From aa1b84ce1cc8b20c3385ccc10b840b1cce68f456 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Sep 2021 21:33:02 +0200 Subject: [PATCH 0001/1848] [AX25] Fixed extension bits and repeater callsigns --- src/protocols/AX25/AX25.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index d5b5520cb3..bf6782de28 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -126,7 +126,7 @@ int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs #ifndef RADIOLIB_STATIC_ONLY this->repeaterCallsigns = new char*[numRepeaters]; for(uint8_t i = 0; i < numRepeaters; i++) { - this->repeaterCallsigns[i] = new char[strlen(repeaterCallsigns[i])]; + this->repeaterCallsigns[i] = new char[strlen(repeaterCallsigns[i]) + 1]; } this->repeaterSSIDs = new uint8_t[numRepeaters]; #endif @@ -135,6 +135,7 @@ int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs this->numRepeaters = numRepeaters; for(uint8_t i = 0; i < numRepeaters; i++) { memcpy(this->repeaterCallsigns[i], repeaterCallsigns[i], strlen(repeaterCallsigns[i])); + this->repeaterCallsigns[i][strlen(repeaterCallsigns[i])] = '\0'; } memcpy(this->repeaterSSIDs, repeaterSSIDs, numRepeaters); @@ -249,7 +250,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { frameBuffPtr += AX25_MAX_CALLSIGN_LEN; // set source SSID - *(frameBuffPtr++) = AX25_SSID_COMMAND_SOURCE | AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_END; + *(frameBuffPtr++) = AX25_SSID_COMMAND_SOURCE | AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE; // set repeater callsigns for(uint16_t i = 0; i < frame->numRepeaters; i++) { @@ -262,7 +263,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // set HDLC extension end bit - *frameBuffPtr |= AX25_SSID_HDLC_EXTENSION_END; + *(frameBuffPtr - 1) |= AX25_SSID_HDLC_EXTENSION_END; // set sequence numbers of the frames that have it uint8_t controlField = frame->control; From 6cd7c8efdc773bf0b5053cd367199a0a311e3a0c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 9 Oct 2021 09:55:36 +0200 Subject: [PATCH 0002/1848] [Hell] Fixed comma bitmap (#384) --- src/protocols/Hellschreiber/Hellschreiber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index f7c634cb9f..0e2e05b9bb 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -27,7 +27,7 @@ static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] RADIOLIB_PROGMEM = { { 0b0010000, 0b0001000, 0b0001000, 0b0001000, 0b0010000 }, // ) { 0b0010100, 0b0001000, 0b0010100, 0b0000000, 0b0000000 }, // * { 0b0001000, 0b0001000, 0b0111110, 0b0001000, 0b0001000 }, // + - { 0b0001000, 0b0010000, 0b0000000, 0b0000000, 0b0000000 }, // ´ + { 0b0000000, 0b0000000, 0b0000000, 0b0010000, 0b0001000 }, // , { 0b0000000, 0b0000000, 0b0111110, 0b0000000, 0b0000000 }, // - { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0001000 }, // . { 0b0000010, 0b0000100, 0b0001000, 0b0010000, 0b0100000 }, // / From 730abc0903bb4048562f2c23c5e62d19dde0cd3a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Oct 2021 09:00:27 +0200 Subject: [PATCH 0003/1848] [Hell] Fixed comma direction (#384) --- src/protocols/Hellschreiber/Hellschreiber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 0e2e05b9bb..9bebbe627d 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -27,7 +27,7 @@ static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] RADIOLIB_PROGMEM = { { 0b0010000, 0b0001000, 0b0001000, 0b0001000, 0b0010000 }, // ) { 0b0010100, 0b0001000, 0b0010100, 0b0000000, 0b0000000 }, // * { 0b0001000, 0b0001000, 0b0111110, 0b0001000, 0b0001000 }, // + - { 0b0000000, 0b0000000, 0b0000000, 0b0010000, 0b0001000 }, // , + { 0b0000000, 0b0000000, 0b0000000, 0b0001000, 0b0010000 }, // , { 0b0000000, 0b0000000, 0b0111110, 0b0000000, 0b0000000 }, // - { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0001000 }, // . { 0b0000010, 0b0000100, 0b0001000, 0b0010000, 0b0100000 }, // / From 9d3807168f0cfed6b2e7e18644b13ee8c549be38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 17 Oct 2021 11:10:52 +0200 Subject: [PATCH 0004/1848] [SX127x] Fixed low-power output on RFO pin (#385) --- src/modules/SX127x/SX1272.cpp | 40 +++++++++++++++----------- src/modules/SX127x/SX1272.h | 6 ++-- src/modules/SX127x/SX1278.cpp | 53 ++++++++++++++++++++++++----------- src/modules/SX127x/SX1278.h | 7 +++-- 4 files changed, 69 insertions(+), 37 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index cab426758d..4dfc647992 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -208,32 +208,40 @@ int16_t SX1272::setCodingRate(uint8_t cr) { return(state); } -int16_t SX1272::setOutputPower(int8_t power) { +int16_t SX1272::setOutputPower(int8_t power, bool useRfo = false) { // check allowed power range - if(!(((power >= -1) && (power <= 17)) || (power == 20))) { - return(ERR_INVALID_OUTPUT_POWER); + if(useRfo) { + RADIOLIB_CHECK_RANGE(power, -1, 14, ERR_INVALID_OUTPUT_POWER); + } else { + RADIOLIB_CHECK_RANGE(power, 2, 20, ERR_INVALID_OUTPUT_POWER); } // set mode to standby int16_t state = SX127x::standby(); - // set output power - if(power < 2) { - // power is less than 2 dBm, enable PA0 on RFIO + if(useRfo) { + // RFO output state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power + 1), 3, 0); state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if(power <= 17) { - // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 2), 3, 0); - state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if(power == 20) { - // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 5), 3, 0); - state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); + + } else { + if(power <= 17) { + // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 2), 3, 0); + state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); + + } else { + // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 5), 3, 0); + state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); + + } + } + return(state); } diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 8f333e35bf..3851960e33 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -198,13 +198,15 @@ class SX1272: public SX127x { int16_t setCodingRate(uint8_t cr); /*! - \brief Sets transmission output power. Allowed values range from 2 to 17 dBm. + \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). \param power Transmission output power in dBm. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. Defaults to PA_BOOST. + \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power, bool useRfo = false); /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 903855d8ac..78cfa3321f 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -222,32 +222,51 @@ int16_t SX1278::setCodingRate(uint8_t cr) { return(state); } -int16_t SX1278::setOutputPower(int8_t power) { +int16_t SX1278::setOutputPower(int8_t power, bool useRfo = false) { // check allowed power range - if(!(((power >= -3) && (power <= 17)) || (power == 20))) { - return(ERR_INVALID_OUTPUT_POWER); + if(useRfo) { + // RFO output + RADIOLIB_CHECK_RANGE(power, -3, 15, ERR_INVALID_OUTPUT_POWER); + } else { + // PA_BOOST output, check high-power operation + if(power != 20) { + RADIOLIB_CHECK_RANGE(power, 2, 17, ERR_INVALID_OUTPUT_POWER); + } } // set mode to standby int16_t state = SX127x::standby(); - // set output power - if(power < 2) { - // power is less than 2 dBm, enable PA on RFO + if(useRfo) { + uint8_t paCfg = 0; + if(power < 0) { + // low power mode RFO output + paCfg = SX1278_LOW_POWER | (power + 3); + } else { + // high power mode RFO output + paCfg = SX1278_MAX_POWER | power; + } + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_LOW_POWER | (power + 3), 6, 0); - state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if(power <= 17) { - // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 2), 6, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, paCfg, 6, 0); state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if(power == 20) { - // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power mode - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 5), 6, 0); - state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); + + } else { + if(power != 20) { + // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 2), 6, 0); + state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); + + } else { + // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | 0x0F, 6, 0); + state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); + + } } + return(state); } diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index d22145cf4d..7e69a398ea 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -206,13 +206,16 @@ class SX1278: public SX127x { int16_t setCodingRate(uint8_t cr); /*! - \brief Sets transmission output power. Allowed values range from 2 to 17 dBm. + \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). + High power +20 dBm operation is also supported, on the PA_BOOST pin. \param power Transmission output power in dBm. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. Defaults to PA_BOOST. + \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power, bool useRfo = false); /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. From 8579b2cb1b9a1b4ba834c278d67e133e33688ff0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 18 Oct 2021 21:30:54 +0200 Subject: [PATCH 0005/1848] [SX127x] Removed redundant default argument --- src/modules/SX127x/SX1272.cpp | 4 ++-- src/modules/SX127x/SX1278.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 4dfc647992..9acac6fb9a 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -208,7 +208,7 @@ int16_t SX1272::setCodingRate(uint8_t cr) { return(state); } -int16_t SX1272::setOutputPower(int8_t power, bool useRfo = false) { +int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { RADIOLIB_CHECK_RANGE(power, -1, 14, ERR_INVALID_OUTPUT_POWER); @@ -241,7 +241,7 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo = false) { } } - + return(state); } diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 78cfa3321f..4acd827ed5 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -222,7 +222,7 @@ int16_t SX1278::setCodingRate(uint8_t cr) { return(state); } -int16_t SX1278::setOutputPower(int8_t power, bool useRfo = false) { +int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { // RFO output From d91c6d07125c0547183836615a0c4fed1e7cde1b Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 18 Oct 2021 21:31:46 +0200 Subject: [PATCH 0006/1848] [SX127x] Only apply errata fix by a macro (#388) --- src/BuildOpt.h | 14 ++++++++++++++ src/modules/SX127x/SX127x.cpp | 8 ++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 05d8d4cb6c..8122f72769 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -410,6 +410,20 @@ */ #define RADIOLIB_CHECK_PARAMS +/* + * Uncomment to enable SX127x errata fix + * Warning: SX127x errata fix has been reported to cause issues with LoRa bandwidths lower than 62.5 kHz. + * It should only be enabled if you really are observing some errata-related issue. + * Note: Disabled by default. + */ +//#define RADIOLIB_FIX_ERRATA_SX127X + +#if defined(RADIOLIB_FIX_ERRATA_SX127X) + #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); } +#else + #define RADIOLIB_ERRATA_SX127X(...) {} +#endif + /* * Uncomment to enable god mode - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code. * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 354b72b47f..b0f1f8abb4 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -324,7 +324,7 @@ int16_t SX127x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // apply fixes to errata - errataFix(false); + RADIOLIB_ERRATA_SX127X(false); // start transmitting return(setMode(SX127X_TX)); @@ -344,7 +344,7 @@ int16_t SX127x::receiveDirect() { RADIOLIB_ASSERT(state); // apply fixes to errata - errataFix(true); + RADIOLIB_ERRATA_SX127X(true); // start receiving return(setMode(SX127X_RX)); @@ -392,7 +392,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { } // apply fixes to errata - errataFix(true); + RADIOLIB_ERRATA_SX127X(true); // clear interrupt flags clearIRQFlags(); @@ -460,7 +460,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6); // apply fixes to errata - errataFix(false); + RADIOLIB_ERRATA_SX127X(false); // clear interrupt flags clearIRQFlags(); From 9824ac32b6311afb07fa94e12037f6a03b623789 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 07:50:06 +0200 Subject: [PATCH 0007/1848] [SX127x] Fixed missing call to FSK config in some derived classes (#395) --- src/modules/SX127x/SX1276.cpp | 4 ++++ src/modules/SX127x/SX1277.cpp | 4 ++++ src/modules/SX127x/SX1279.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 8c97f447ee..a52fa27a02 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -37,6 +37,10 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index a150c4626c..6b4a1a6638 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -37,6 +37,10 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 179b75079b..dff6e85676 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -37,6 +37,10 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); From 6475507274f2d1b1cddec6759a9cfe69409654b3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 19:15:36 +0200 Subject: [PATCH 0008/1848] [SX127x] Fixed missing OOK shaping configuration in some derived classes (#393) --- src/modules/SX127x/SX1276.cpp | 9 +++++++-- src/modules/SX127x/SX1277.cpp | 9 +++++++-- src/modules/SX127x/SX1279.cpp | 9 +++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index a52fa27a02..eb3a229551 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -48,8 +48,13 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setOutputPower(power); RADIOLIB_ASSERT(state); - state = setDataShaping(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } return(state); } diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 6b4a1a6638..b2f7e86b66 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -48,8 +48,13 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setOutputPower(power); RADIOLIB_ASSERT(state); - state = setDataShaping(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } return(state); } diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index dff6e85676..8313a4899e 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -48,8 +48,13 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setOutputPower(power); RADIOLIB_ASSERT(state); - state = setDataShaping(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } return(state); } From 2bdec154ad4145c30bcabe370aff3ac6e069da8b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 21:15:46 +0200 Subject: [PATCH 0009/1848] Added CubeCell support --- src/BuildOpt.h | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/ISerial.cpp | 7 ++++--- src/ISerial.h | 2 ++ src/Module.cpp | 4 ++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 8122f72769..245cd157af 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -19,7 +19,8 @@ * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. * RADIOLIB_PROGMEM - macro to place variable into program storage (usually Flash). - * RADIOLIB_PROGMEM_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). + * RADIOLIB_PROGMEM_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). + * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword. * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial. * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support. * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. @@ -48,6 +49,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // the following must be defined if the Arduino core does not support SoftwareSerial library //#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED @@ -102,6 +104,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #elif defined(ESP8266) // ESP8266 boards @@ -115,6 +118,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // RadioLib has ESP8266 driver, this must be disabled to use ESP8266 as platform #define RADIOLIB_EXCLUDE_ESP8266 @@ -132,6 +136,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -151,6 +156,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -169,6 +175,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -187,6 +194,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -202,6 +210,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 #define RADIOLIB_TONE_UNSUPPORTED @@ -218,6 +227,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #elif defined(ARDUINO_ARC32_TOOLS) // Intel Curie @@ -244,6 +254,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #elif defined(ARDUINO_ARCH_APOLLO3) // Sparkfun Apollo3 boards @@ -257,6 +268,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -278,6 +290,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -296,6 +309,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -314,6 +328,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 @@ -329,6 +344,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico @@ -342,10 +358,36 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 #define RADIOLIB_EXCLUDE_ESP8266 + #elif defined(__ASR6501__) + // CubeCell + #define RADIOLIB_PLATFORM "CubeCell" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE PINMODE + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS IrqModes + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + // CubeCell doesn't seem to define nullptr, let's do something like that now + #define nullptr NULL + + // ... and also defines pinMode() as a macro, which is by far the stupidest thing I have seen on Arduino + #undef pinMode + + // ... and uses an outdated GCC which does not support type aliases + #define RADIOLIB_TYPE_ALIAS(type, alias) typedef class type alias; + + // ... and it also has no tone(). This platform was designed by an idiot. + #define RADIOLIB_TONE_UNSUPPORTED + #else // other platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown" @@ -359,6 +401,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #endif #endif diff --git a/src/ISerial.cpp b/src/ISerial.cpp index 7822e5c27a..786ed00e74 100644 --- a/src/ISerial.cpp +++ b/src/ISerial.cpp @@ -8,10 +8,11 @@ void ISerial::begin(long speed) { _mod->ModuleSerial->begin(speed); } +#if !defined(__ASR6501__) void ISerial::end() { _mod->ModuleSerial->end(); } - +#endif int ISerial::peek() { return(_mod->ModuleSerial->peek()); @@ -33,7 +34,7 @@ void ISerial::flush() { _mod->ModuleSerial->flush(); } -#ifndef ARDUINO_ARCH_MEGAAVR +#if !defined(ARDUINO_ARCH_MEGAAVR) size_t ISerial::print(const __FlashStringHelper *ifsh) { return(_mod->ModuleSerial->print(ifsh)); } @@ -79,7 +80,7 @@ size_t ISerial::print(const Printable& x) { return(_mod->ModuleSerial->print(x)); } -#ifndef ARDUINO_ARCH_MEGAAVR +#if !defined(ARDUINO_ARCH_MEGAAVR) size_t ISerial::println(const __FlashStringHelper *ifsh) { return(_mod->ModuleSerial->println(ifsh)); } diff --git a/src/ISerial.h b/src/ISerial.h index 908c4ee727..52d05bf52f 100644 --- a/src/ISerial.h +++ b/src/ISerial.h @@ -13,7 +13,9 @@ class ISerial { explicit ISerial(Module* mod); void begin(long); + #if !defined(__ASR6501__) void end(); + #endif int peek(); size_t write(uint8_t); int read(); diff --git a/src/Module.cpp b/src/Module.cpp index 0d0dde53d4..121a17a2dd 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -139,9 +139,11 @@ void Module::term(uint8_t interface) { _spi->end(); } + #if !defined(__ASR6501__) if(((interface == RADIOLIB_USE_UART) && ModuleSerial != nullptr)) { ModuleSerial->end(); } + #endif } void Module::ATemptyBuffer() { @@ -374,7 +376,9 @@ void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) { } void Module::yield() { + #if !defined(__ASR6501__) ::yield(); + #endif } void Module::delay(uint32_t ms) { From 20d5e2c422a506f569dc250e7284ab35f15211e2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 21:16:09 +0200 Subject: [PATCH 0010/1848] [RFM2x] Added CubeCell support --- src/modules/RFM2x/RFM22.h | 2 +- src/modules/RFM2x/RFM23.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/RFM2x/RFM22.h b/src/modules/RFM2x/RFM22.h index 3204c7cad9..61387b178e 100644 --- a/src/modules/RFM2x/RFM22.h +++ b/src/modules/RFM2x/RFM22.h @@ -14,7 +14,7 @@ \brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules. */ -using RFM22 = Si4432; +RADIOLIB_TYPE_ALIAS(Si4432, RFM22); #endif diff --git a/src/modules/RFM2x/RFM23.h b/src/modules/RFM2x/RFM23.h index 45a708a269..02afc68ad6 100644 --- a/src/modules/RFM2x/RFM23.h +++ b/src/modules/RFM2x/RFM23.h @@ -14,7 +14,7 @@ \brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules. */ -using RFM23 = Si4431; +RADIOLIB_TYPE_ALIAS(Si4431, RFM23); #endif From f67549ff3678b3de370227f9c9d92b5c025f7e34 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 21:16:15 +0200 Subject: [PATCH 0011/1848] [RFM9x] Added CubeCell support --- src/modules/RFM9x/RFM96.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h index b36f19cc11..31a72cd60e 100644 --- a/src/modules/RFM9x/RFM96.h +++ b/src/modules/RFM9x/RFM96.h @@ -79,7 +79,7 @@ class RFM96: public SX1278 { \brief Only exists as alias for RFM96, since there seems to be no difference between %RFM96 and %RFM98 modules. */ -using RFM98 = RFM96; +RADIOLIB_TYPE_ALIAS(RFM96, RFM98); #endif From 610bb6eaec39e11ac586cf3d548e12292846c7be Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 21:16:40 +0200 Subject: [PATCH 0012/1848] Added CubeCell to supported platforms --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f15e08111..9e2bc8e3aa 100644 --- a/README.md +++ b/README.md @@ -76,10 +76,13 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __Raspberry Pi__ * [__RP2040__](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect +* __Heltec__ + * [__CubeCell__](https://github.com/HelTecAutomation/CubeCell-Arduino) - ASR650X series (CubeCell-Board, CubeCell-Capsule, CubeCell-Module etc.) + The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platforms prior to releasing new version. ### In development: -* __SIM800C__ GSM module +* __AX5243__ FSK module * __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules * __APRS__ protocol for all the modules that can transmit AX.25 * ___and more!___ From 68eebadf1d42099f9407c776d299deb91976a4b2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 21:17:09 +0200 Subject: [PATCH 0013/1848] [CI] Added CubeCell to build matrix (CubeCell:CubeCell:CubeCell-Board) --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1933b5bd70..d2eca1a85a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,6 +31,7 @@ jobs: - stm32duino:STM32F1:mapleMini - MegaCoreX:megaavr:4809 - arduino:mbed_rp2040:pico + - CubeCell:CubeCell:CubeCell-Board runs-on: ubuntu-latest name: ${{ matrix.board }} @@ -127,6 +128,10 @@ jobs: # MegaCoreX echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" + elif [[ "${{ contains(matrix.board, 'CubeCell:CubeCell') }}" == "true" ]]; then + # MegaCoreX + echo "::set-output name=index-url::--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" + fi - name: Install platform From e03b674e1020abe2d1e5037804177d5bcadd617f Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 22:07:00 +0200 Subject: [PATCH 0014/1848] [SX127x] Skip tone() for CubeCell (CubeCell:CubeCell:CubeCell-Board) --- examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index d6294889e4..3239472d87 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -175,8 +175,8 @@ void loop() { Serial.println(state); } - // tone() function is not available on ESP32 and Arduino Due - #if !defined(ESP32) && !defined(_VARIANT_ARDUINO_DUE_X_) + // tone() function is not available on ESP32, Arduino Due and CubeCell + #if !defined(ESP32) && !defined(_VARIANT_ARDUINO_DUE_X_) && !defined(__ASR6501__) // transmit FM tone at 1000 Hz for 1 second // (DIO2 is connected to Arduino pin 4) tone(4, 1000); From 2c3f22335fc965a2c60fa5842c1a4979c8eb195e Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 23:22:14 +0200 Subject: [PATCH 0015/1848] Use Module::tone override in FSK example --- examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index 3239472d87..947e7ce3f7 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -175,16 +175,15 @@ void loop() { Serial.println(state); } - // tone() function is not available on ESP32, Arduino Due and CubeCell - #if !defined(ESP32) && !defined(_VARIANT_ARDUINO_DUE_X_) && !defined(__ASR6501__) // transmit FM tone at 1000 Hz for 1 second // (DIO2 is connected to Arduino pin 4) - tone(4, 1000); + // Note: tone() function is not available on ESP32, Arduino Due and CubeCell + // on these platforms, the following will do nothing + Module::tone(4, 1000); delay(1000); // transmit FM note at 500 Hz for 1 second - tone(4, 500); + Module::tone(4, 500); delay(1000); - #endif // NOTE: after calling transmitDirect(), SX127x will start // transmitting immediately! This signal can jam other From 29446986f3471433945cff78f2d452061d21a17f Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 23:57:43 +0200 Subject: [PATCH 0016/1848] [SX127x] Added ping-pong example --- .../SX127x_PingPong/SX127x_PingPong.ino | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino new file mode 100644 index 0000000000..9231ea586a --- /dev/null +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -0,0 +1,159 @@ +/* + RadioLib SX127x Ping-Pong Example + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// uncomment the following only on one +// of the nodes to initiate the pings +//#define INITIATING_NODE + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// NRST pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// save transmission states between loops +int transmissionState = ERR_NONE; + +// flag to indicate transmission or reception state +bool transmitFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// flag to indicate that a packet was sent or received +volatile bool operationDone = false; + +// this function is called when a complete packet +// is transmitted or received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we sent aor received packet, set the flag + operationDone = true; +} + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setDio0Action(setFlag); + + #if defined(INITIATING_NODE) + // send the first packet on this node + Serial.print(F("[SX1278] Sending first packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + #else + // start listening for LoRa packets on this node + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + #endif +} + +void loop() { + // check if the previous operation finished + if(operationDone) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + operationDone = false; + + if(transmitFlag) { + // the previous operation was transmission, listen for response + // print the result + if (transmissionState == ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // listen for response + radio.startReceive(); + transmitFlag = false; + + } else { + // the previous operation was reception + // print data and send another packet + String str; + int state = radio.readData(str); + + if (state == ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1278] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1278] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1278] Sending another packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + } + + // we're ready to process more packets, + // enable interrupt service routine + enableInterrupt = true; + + } +} From 0fc841331342707a177471f782cbbb8b7ac43128 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Oct 2021 23:58:28 +0200 Subject: [PATCH 0017/1848] Bump version to 4.6.0 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 94f1257ef3..c37f3f6a1e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=4.5.0 +version=4.6.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library for Arduino diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 245cd157af..aa69db9b9e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -513,7 +513,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x04) -#define RADIOLIB_VERSION_MINOR (0x05) +#define RADIOLIB_VERSION_MINOR (0x06) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 98e2a1847d88b7d0addc7227f6f18c43131163e5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 28 Oct 2021 00:11:24 +0200 Subject: [PATCH 0018/1848] Added missing alias macro for Intel Curie --- src/BuildOpt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index aa69db9b9e..039ec43cdc 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -241,6 +241,7 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every From 81e8de832495198436f3b74e503dc5a3169282c9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 28 Oct 2021 00:15:02 +0200 Subject: [PATCH 0019/1848] Drop references to I2C CI_BUILD_ALL --- src/Module.cpp | 2 -- src/TypeDef.h | 5 ----- 2 files changed, 7 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 121a17a2dd..3a57a8a2da 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -124,8 +124,6 @@ void Module::init(uint8_t interface) { #endif } break; - case RADIOLIB_USE_I2C: - break; } } diff --git a/src/TypeDef.h b/src/TypeDef.h index 2d22051de4..dfeb288373 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -19,11 +19,6 @@ */ #define RADIOLIB_USE_UART 0x01 -/*! - \brief Use I2C interface. -*/ -#define RADIOLIB_USE_I2C 0x02 - /*! \} */ From ebc4852fc26d62ff8315fee692f0e63a236b2ee6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 28 Oct 2021 15:44:25 +0200 Subject: [PATCH 0020/1848] [SX127x] Added interrupt-driven CAD (#396) --- ...x_Channel_Activity_Detection_Interrupt.ino | 136 ++++++++++++++++++ keywords.txt | 2 + src/modules/SX127x/SX127x.cpp | 48 ++++--- src/modules/SX127x/SX127x.h | 9 +- 4 files changed, 173 insertions(+), 22 deletions(-) create mode 100644 examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 0000000000..a2c0f75806 --- /dev/null +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,136 @@ +/* + RadioLib SX127x Channel Activity Detection with Interrupts Example + + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// save state between loops +int scanState = ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa preamble is not detected within CAD timeout period + radio.setDio0Action(setFlagTimeout); + + // set the function that will be called + // when LoRa preamble is detected + radio.setDio1Action(setFlagDetected); + + // start scanning the channel + Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a preamble was not detected +volatile bool timeoutFlag = false; + +// flag to indicate that a preamble was detected +volatile bool detectedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when no preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlagTimeout(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we timed out, set the flag + timeoutFlag = true; +} + +// this function is called when LoRa preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlagDetected(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we got a preamble, set the flag + detectedFlag = true; +} + +void loop() { + // check if we got a preamble + if(detectedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + detectedFlag = false; + + // LoRa preamble was detected + Serial.print(F("[SX1278] Preamble detected!")); + + } + + // check if we need to restart channel activity detection + if(detectedFlag || timeoutFlag) { + // start scanning the channel + Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); + + // start scanning current channel + int state = radio.startChannelScan(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + } +} diff --git a/keywords.txt b/keywords.txt index b6ed434d89..8548153eb5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -96,6 +96,8 @@ clearDio1Action KEYWORD2 startTransmit KEYWORD2 startReceive KEYWORD2 readData KEYWORD2 +startChannelScan KEYWORD2 +getChannelScanResult KEYWORD2 setBandwidth KEYWORD2 setSpreadingFactor KEYWORD2 setCodingRate KEYWORD2 diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b0f1f8abb4..81c24eef14 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -247,27 +247,8 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { } int16_t SX127x::scanChannel() { - // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); - } - - // set mode to standby - int16_t state = setMode(SX127X_STANDBY); - RADIOLIB_ASSERT(state); - - // set DIO pin mapping - state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4); - RADIOLIB_ASSERT(state); - - // clear interrupt flags - clearIRQFlags(); - - // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); - - // set mode to CAD - state = setMode(SX127X_CAD); + // start CAD + int16_t state = startChannelScan(); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -566,6 +547,31 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { return(ERR_NONE); } +int16_t SX127x::startChannelScan() { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = setMode(SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set DIO pin mapping + state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + + // set mode to CAD + state = setMode(SX127X_CAD); + return(state); +} + int16_t SX127x::setSyncWord(uint8_t syncWord) { // check active modem if(getActiveModem() != SX127X_LORA) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index dc33ec08cc..bde973ace6 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -734,6 +734,13 @@ class SX127x: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected. + DIO1 will be activated if there's no preamble detected before timeout. + + \returns \ref status_codes + */ + int16_t startChannelScan(); // configuration methods @@ -1085,7 +1092,7 @@ class SX127x: public PhysicalLayer { * \returns bandwidth in manitsa and exponent format */ static uint8_t calculateBWManExp(float bandwidth); - + virtual void errataFix(bool rx) = 0; }; From 3a8360c361ad039da3ce91712dc2794f6ee11cdf Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 28 Oct 2021 15:44:44 +0200 Subject: [PATCH 0021/1848] [SX126x] Added interrupt-driven CAD --- ...x_Channel_Activity_Detection_Interrupt.ino | 123 ++++++++++++++++++ src/modules/SX126x/SX126x.cpp | 82 +++++++----- src/modules/SX126x/SX126x.h | 14 ++ 3 files changed, 186 insertions(+), 33 deletions(-) create mode 100644 examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 0000000000..9d65ab247c --- /dev/null +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,123 @@ +/* + RadioLib SX126x Channel Activity Detection Example + + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[SX1262] Packet detected!")); + + } else if (state == CHANNEL_FREE) { + // channel is free + Serial.println(F("[SX1262] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[SX1262] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // enable interrupt service routine + enableInterrupt = true; + } + +} diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 92cfe2a327..2c8dd3a0bf 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -331,28 +331,8 @@ int16_t SX126x::receiveDirect() { } int16_t SX126x::scanChannel() { - // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); - } - - // set mode to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); - - // set DIO pin mapping - state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE); - RADIOLIB_ASSERT(state); - - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - // set mode to CAD - state = setCad(); + int state = startChannelScan(); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -361,18 +341,7 @@ int16_t SX126x::scanChannel() { } // check CAD result - uint16_t cadResult = getIrqStatus(); - if(cadResult & SX126X_IRQ_CAD_DETECTED) { - // detected some LoRa activity - clearIrqStatus(); - return(LORA_DETECTED); - } else if(cadResult & SX126X_IRQ_CAD_DONE) { - // channel is free - clearIrqStatus(); - return(CHANNEL_FREE); - } - - return(ERR_UNKNOWN); + return(getChannelScanResult()); } int16_t SX126x::sleep(bool retainConfig) { @@ -608,6 +577,53 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { return(state); } +int16_t SX126x::startChannelScan() { + // check active modem + if(getPacketType() != SX126X_PACKET_TYPE_LORA) { + return(ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + + // set DIO pin mapping + state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to CAD + state = setCad(); + return(state); +} + +int16_t SX126x::getChannelScanResult() { + // check active modem + if(getPacketType() != SX126X_PACKET_TYPE_LORA) { + return(ERR_WRONG_MODEM); + } + + // check CAD result + uint16_t cadResult = getIrqStatus(); + if(cadResult & SX126X_IRQ_CAD_DETECTED) { + // detected some LoRa activity + clearIrqStatus(); + return(LORA_DETECTED); + } else if(cadResult & SX126X_IRQ_CAD_DONE) { + // channel is free + clearIrqStatus(); + return(CHANNEL_FREE); + } + + return(ERR_UNKNOWN); +} + int16_t SX126x::setBandwidth(float bw) { // check active modem if(getPacketType() != SX126X_PACKET_TYPE_LORA) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 775aeb9f54..97fb05feb4 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -554,6 +554,20 @@ class SX126x: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected, or upon timeout. + + \returns \ref status_codes + */ + int16_t startChannelScan(); + + /*! + \brief Read the channel scan result + + \returns \ref status_codes + */ + int16_t getChannelScanResult(); + // configuration methods /*! From e3ff5affc63db5f1e53df8dbf7be9722951adecb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 30 Oct 2021 21:22:36 +0200 Subject: [PATCH 0022/1848] Fix possible issues in CubeCell 1.3.0 (#397) --- src/BuildOpt.h | 12 ++++++++++-- src/Module.cpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 039ec43cdc..c5e483d05e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -364,7 +364,7 @@ #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 #define RADIOLIB_EXCLUDE_ESP8266 - #elif defined(__ASR6501__) + #elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) // CubeCell #define RADIOLIB_PLATFORM "CubeCell" #define RADIOLIB_PIN_TYPE uint8_t @@ -376,6 +376,8 @@ #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_PROGMEM PROGMEM #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 // CubeCell doesn't seem to define nullptr, let's do something like that now #define nullptr NULL @@ -389,6 +391,12 @@ // ... and it also has no tone(). This platform was designed by an idiot. #define RADIOLIB_TONE_UNSUPPORTED + // ... AND as the (hopefully) final nail in the coffin, IT F*CKING DEFINES YIELD() AS A MACRO THAT DOES NOTHING!!! + #define RADIOLIB_YIELD_UNSUPPORTED + #if defined(yield) + #undef yield + #endif + #else // other platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown" @@ -415,7 +423,7 @@ * verbose - full transcript of all SPI/UART communication */ -//#define RADIOLIB_DEBUG +#define RADIOLIB_DEBUG //#define RADIOLIB_VERBOSE // set which Serial port should be used for debug output diff --git a/src/Module.cpp b/src/Module.cpp index 3a57a8a2da..98e6af346f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -374,7 +374,7 @@ void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) { } void Module::yield() { - #if !defined(__ASR6501__) + #if !defined(RADIOLIB_YIELD_UNSUPPORTED) ::yield(); #endif } From 6e20c16d3d5d5102c2369a61dbd8766f22e0e823 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 Nov 2021 21:41:12 +0100 Subject: [PATCH 0023/1848] Removed debug output (enabled by mistake) --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index c5e483d05e..c5a015f86e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -423,7 +423,7 @@ * verbose - full transcript of all SPI/UART communication */ -#define RADIOLIB_DEBUG +//#define RADIOLIB_DEBUG //#define RADIOLIB_VERBOSE // set which Serial port should be used for debug output From 5c538f31ea1d9008d37ab6f4942b91c6d2d46410 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 8 Nov 2021 17:45:12 +0100 Subject: [PATCH 0024/1848] [AX.25] Fixed command/response bit --- src/protocols/AX25/AX25.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index bf6782de28..1c1af83578 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -250,7 +250,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { frameBuffPtr += AX25_MAX_CALLSIGN_LEN; // set source SSID - *(frameBuffPtr++) = AX25_SSID_COMMAND_SOURCE | AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE; + *(frameBuffPtr++) = AX25_SSID_RESPONSE_SOURCE | AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE; // set repeater callsigns for(uint16_t i = 0; i < frame->numRepeaters; i++) { From 50055ee52d9b85927fc5f403b9b3b0fa25e280dd Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Mon, 29 Mar 2021 10:25:29 +0200 Subject: [PATCH 0025/1848] new RF69::setOokFixedThreshold() --- keywords.txt | 3 ++- src/modules/RF69/RF69.cpp | 4 ++++ src/modules/RF69/RF69.h | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index 8548153eb5..17bb7acd27 100644 --- a/keywords.txt +++ b/keywords.txt @@ -154,7 +154,8 @@ enableAES KEYWORD2 disableAES KEYWORD2 getTemperature KEYWORD2 setAmbientTemperature KEYWORD2 -setLnaTestBoost KEYWORD2 +setLnaTestBoost KEYWORD2 +setOokFixedThreshold KEYWORD2 # CC1101-specific getLQI KEYWORD2 diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 9b96143a57..3a509772ac 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -388,6 +388,10 @@ int16_t RF69::setOokThresholdType(uint8_t type) { return(_mod->SPIsetRegValue(RF69_REG_OOK_PEAK, type, 7, 3, 5)); } +int16_t RF69::setOokFixedThreshold(uint8_t value) { + return(_mod->SPIsetRegValue(RF69_REG_OOK_FIX, value, 7, 0, 5)); +} + int16_t RF69::setFrequency(float freq) { // check allowed frequency range if(!(((freq > 290.0) && (freq < 340.0)) || diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d2acc5e833..de230933ee 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -757,6 +757,15 @@ class RF69: public PhysicalLayer { */ int16_t setOokThresholdType(uint8_t type); + /*! + \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. + + \param value Fixed threshold value (in dB) in the OOK demodulator. Used when OokThresType = RF69_OOK_THRESH_FIXED. + + \returns \ref status_codes + */ + int16_t setOokFixedThreshold(uint8_t value); + /*! \brief Set modem in fixed packet length mode. From 0eb5578e2209feda743ff89706d1826b779e6206 Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Fri, 16 Apr 2021 16:09:46 +0200 Subject: [PATCH 0026/1848] doc comment fix --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index bde973ace6..1cc5aaa125 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -921,7 +921,7 @@ class SX127x: public PhysicalLayer { /*! \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. - \param value The actual value used by teh data slicer is (128 - value/2). + \param value The actual value is devided by 2 because (0.5db step). ie: value=12 means 6dB \returns \ref status_codes */ From d47c30b18d2c2ebb1490372896f9c645f9638ad1 Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Fri, 16 Apr 2021 16:10:06 +0200 Subject: [PATCH 0027/1848] new RF69::setOokFixedThreshold --- src/modules/RF69/RF69.cpp | 4 ++++ src/modules/RF69/RF69.h | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 3a509772ac..4596ea3ca3 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -392,6 +392,10 @@ int16_t RF69::setOokFixedThreshold(uint8_t value) { return(_mod->SPIsetRegValue(RF69_REG_OOK_FIX, value, 7, 0, 5)); } +int16_t RF69::setOokPeakThresholdDecrement(uint8_t value) { + return(_mod->SPIsetRegValue(RF69_REG_OOK_PEAK, value, 2, 0, 5)); +} + int16_t RF69::setFrequency(float freq) { // check allowed frequency range if(!(((freq > 290.0) && (freq < 340.0)) || diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index de230933ee..08e9c3c049 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -766,6 +766,15 @@ class RF69: public PhysicalLayer { */ int16_t setOokFixedThreshold(uint8_t value); + /*! + \brief Period of decrement of the RSSI threshold in the OOK demodulator. + + \param value Use defines RF69_OOK_PEAK_THRESH_DEC_X_X_CHIP + + \returns \ref status_codes + */ + int16_t setOokPeakThresholdDecrement(uint8_t value); + /*! \brief Set modem in fixed packet length mode. From 0c3b0b32dba2bc942f066dcde9ae7fff70b56b86 Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Fri, 16 Apr 2021 16:40:42 +0200 Subject: [PATCH 0028/1848] new RF69::enableContinuousModeBitSync() --- src/modules/RF69/RF69.cpp | 8 ++++++++ src/modules/RF69/RF69.h | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 4596ea3ca3..74a1a4a321 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -720,6 +720,14 @@ int16_t RF69::disableSyncWordFiltering() { return(state); } +int16_t RF69::enableContinuousModeBitSync() { + return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); +} + +int16_t RF69::disableContinuousModeBitSync() { + return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE, 6, 5)); +} + int16_t RF69::setCrcFiltering(bool crcOn) { if (crcOn == true) { return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_CRC_ON, 4, 4)); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 08e9c3c049..c2f6b04195 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -809,6 +809,20 @@ class RF69: public PhysicalLayer { */ int16_t disableSyncWordFiltering(); + /*! + \brief Enable Bit synchronization in continuous mode. + + \returns \ref status_codes + */ + int16_t enableContinuousModeBitSync(); + + /*! + \brief Disable Bit synchronization in continuous mode. + + \returns \ref status_codes + */ + int16_t disableContinuousModeBitSync(); + /*! \brief Enable CRC filtering and generation. From 29778e0e1d21dad192c9851830322f0e6867eb0a Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Fri, 16 Apr 2021 17:27:12 +0200 Subject: [PATCH 0029/1848] missing keywords --- keywords.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keywords.txt b/keywords.txt index 17bb7acd27..6a83fea256 100644 --- a/keywords.txt +++ b/keywords.txt @@ -156,6 +156,8 @@ getTemperature KEYWORD2 setAmbientTemperature KEYWORD2 setLnaTestBoost KEYWORD2 setOokFixedThreshold KEYWORD2 +enableContinuousModeBitSync KEYWORD2 +disableContinuousModeBitSync KEYWORD2 # CC1101-specific getLQI KEYWORD2 From 7ddf0f81ce088f48efe668dd67663c385f65ccdb Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Fri, 16 Apr 2021 17:34:55 +0200 Subject: [PATCH 0030/1848] SX127X enable/disable BitSync --- keywords.txt | 6 ++++-- src/modules/SX127x/SX127x.cpp | 8 ++++++++ src/modules/SX127x/SX127x.h | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index 6a83fea256..097cf08a38 100644 --- a/keywords.txt +++ b/keywords.txt @@ -147,6 +147,8 @@ setOokFixedOrFloorThreshold KEYWORD2 setDirectSyncWord KEYWORD2 setDirectAction KEYWORD2 readBit KEYWORD2 +enableBitSync KEYWORD2 +disableBitSync KEYWORD2 # RF69-specific setAESKey KEYWORD2 @@ -156,8 +158,8 @@ getTemperature KEYWORD2 setAmbientTemperature KEYWORD2 setLnaTestBoost KEYWORD2 setOokFixedThreshold KEYWORD2 -enableContinuousModeBitSync KEYWORD2 -disableContinuousModeBitSync KEYWORD2 +enableContinuousModeBitSync KEYWORD2 +disableContinuousModeBitSync KEYWORD2 # CC1101-specific getLQI KEYWORD2 diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 81c24eef14..07eae0e77a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -939,6 +939,14 @@ int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { return(_mod->SPIsetRegValue(SX127X_REG_OOK_AVG, value, 7, 5, 5)); } +int16_t SX127x::enableBitSync() { + return(_mod->SPIsetRegValue(SX127X_REG_OOK_PEAK, SX127X_BIT_SYNC_ON, 5, 5, 5)); +} + +int16_t SX127x::disableBitSync() { + return(_mod->SPIsetRegValue(SX127X_REG_OOK_PEAK, SX127X_BIT_SYNC_OFF, 5, 5, 5)); +} + int16_t SX127x::setOOK(bool enableOOK) { // check active modem if(getActiveModem() != SX127X_FSK_OOK) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 1cc5aaa125..95b36d6fd6 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -927,6 +927,20 @@ class SX127x: public PhysicalLayer { */ int16_t setOokFixedOrFloorThreshold(uint8_t value); + /*! + \brief Enable Bit synchronizer. + + \returns \ref status_codes + */ + int16_t enableBitSync(); + + /*! + \brief Disable Bit synchronizer (not allowed in Packet mode). + + \returns \ref status_codes + */ + int16_t disableBitSync(); + /*! \brief Query modem for the packet length of received payload. From 964ee86b3ee6b2044942fe9b74ab9059fd474065 Mon Sep 17 00:00:00 2001 From: Christophe Painchaud Date: Sun, 25 Apr 2021 08:51:18 +0200 Subject: [PATCH 0031/1848] indentation fix --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 95b36d6fd6..50f8a308ae 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -941,7 +941,7 @@ class SX127x: public PhysicalLayer { */ int16_t disableBitSync(); - /*! + /*! \brief Query modem for the packet length of received payload. \param update Update received packet length. Will return cached value when set to false. From 0d9718a6037405c7900d3a07d304f8768dfcd680 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:29:51 +0100 Subject: [PATCH 0032/1848] Dropped support for ESP8266, HC05, JDY08, HTTP and MQTT --- README.md | 8 - examples/HC05/HC05_Basic/HC05_Basic.ino | 43 -- examples/HTTP/HTTP_Get/HTTP_Get.ino | 83 --- examples/HTTP/HTTP_Post/HTTP_Post.ino | 86 ---- examples/JDY08/JDY08_Basic/JDY08_Basic.ino | 42 -- examples/MQTT/MQTT_Publish/MQTT_Publish.ino | 91 ---- .../MQTT/MQTT_Subscribe/MQTT_Subscribe.ino | 128 ----- examples/XBee/XBee_Receive/XBee_Receive.ino | 66 --- examples/XBee/XBee_Transmit/XBee_Transmit.ino | 69 --- .../XBee_Transparent/XBee_Transparent.ino | 77 --- ...er_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin | Bin 4194304 -> 0 bytes ...nker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin | Bin 1048576 -> 0 bytes src/ISerial.cpp | 131 ----- src/ISerial.h | 60 --- src/RadioLib.h | 26 +- src/modules/ESP8266/ESP8266.cpp | 251 --------- src/modules/ESP8266/ESP8266.h | 68 --- src/modules/HC05/HC05.cpp | 14 - src/modules/HC05/HC05.h | 29 -- src/modules/JDY08/JDY08.cpp | 16 - src/modules/JDY08/JDY08.h | 29 -- src/modules/XBee/XBee.cpp | 485 ------------------ src/modules/XBee/XBee.h | 204 -------- src/protocols/HTTP/HTTP.cpp | 219 -------- src/protocols/HTTP/HTTP.h | 73 --- src/protocols/MQTT/MQTT.cpp | 472 ----------------- src/protocols/MQTT/MQTT.h | 147 ------ src/protocols/TransportLayer/TransportLayer.h | 86 ---- 28 files changed, 5 insertions(+), 2998 deletions(-) delete mode 100644 examples/HC05/HC05_Basic/HC05_Basic.ino delete mode 100644 examples/HTTP/HTTP_Get/HTTP_Get.ino delete mode 100644 examples/HTTP/HTTP_Post/HTTP_Post.ino delete mode 100644 examples/JDY08/JDY08_Basic/JDY08_Basic.ino delete mode 100644 examples/MQTT/MQTT_Publish/MQTT_Publish.ino delete mode 100644 examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino delete mode 100644 examples/XBee/XBee_Receive/XBee_Receive.ino delete mode 100644 examples/XBee/XBee_Transmit/XBee_Transmit.ino delete mode 100644 examples/XBee/XBee_Transparent/XBee_Transparent.ino delete mode 100644 extras/bin/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin delete mode 100644 extras/bin/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin delete mode 100644 src/ISerial.cpp delete mode 100644 src/ISerial.h delete mode 100644 src/modules/ESP8266/ESP8266.cpp delete mode 100644 src/modules/ESP8266/ESP8266.h delete mode 100644 src/modules/HC05/HC05.cpp delete mode 100644 src/modules/HC05/HC05.h delete mode 100644 src/modules/JDY08/JDY08.cpp delete mode 100644 src/modules/JDY08/JDY08.h delete mode 100644 src/modules/XBee/XBee.cpp delete mode 100644 src/modules/XBee/XBee.h delete mode 100644 src/protocols/HTTP/HTTP.cpp delete mode 100644 src/protocols/HTTP/HTTP.h delete mode 100644 src/protocols/MQTT/MQTT.cpp delete mode 100644 src/protocols/MQTT/MQTT.h delete mode 100644 src/protocols/TransportLayer/TransportLayer.h diff --git a/README.md b/README.md index 9e2bc8e3aa..493983ae08 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,6 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github ### Supported modules: * __CC1101__ FSK radio module -* __ESP8266__ WiFi module -* __HC05__ Bluetooth module -* __JDY08__ BLE module * __LLCC68__ LoRa module * __nRF24L01__ 2.4 GHz module * __RF69__ FSK/OOK radio module @@ -26,13 +23,8 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) * __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282) * __SX1231__ FSK/OOK radio module -* __XBee__ modules (S2B) ### Supported protocols and digital modes: -* __MQTT__ for modules: -ESP8266 -* __HTTP__ for modules: -ESP8266 * __AX.25__ using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: diff --git a/examples/HC05/HC05_Basic/HC05_Basic.ino b/examples/HC05/HC05_Basic/HC05_Basic.ino deleted file mode 100644 index fc7ad4c7f5..0000000000 --- a/examples/HC05/HC05_Basic/HC05_Basic.ino +++ /dev/null @@ -1,43 +0,0 @@ -/* - RadioLib HC05 Example - - This example sends data using HC05 Bluetooth module. - HC05 works exactly like a Serial line, data are sent to the paired device. - The default pairing code for HC05 is 1234 or 1111. - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// HC05 has the following connections: -// TX pin: 9 -// RX pin: 8 -HC05 bluetooth = new SerialModule(9, 8); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//HC05 bluetooth = RadioShield.ModuleA; - -void setup() { - Serial.begin(9600); - - // initialize HC05 - // baudrate: 9600 baud - bluetooth.begin(9600); -} - -void loop() { - // HC05 supports all methods of the Serial class - // read data incoming from Serial port and write them to Bluetooth - while (Serial.available() > 0) { - bluetooth.write(Serial.read()); - } - - // read data incoming from Bluetooth and write them to Serial port - while (bluetooth.available() > 0) { - Serial.write(bluetooth.read()); - } -} diff --git a/examples/HTTP/HTTP_Get/HTTP_Get.ino b/examples/HTTP/HTTP_Get/HTTP_Get.ino deleted file mode 100644 index cea5ead263..0000000000 --- a/examples/HTTP/HTTP_Get/HTTP_Get.ino +++ /dev/null @@ -1,83 +0,0 @@ -/* - RadioLib HTTP GET Example - - This example sends HTTP GET request using ESP8266 WiFi module. - - Please note that the response will be saved including header. HTTP header size - can easily exceed Arduino resources and cause the program to behave erratically. - - IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running - AT firmware (can be found in the /extras folder of the library)! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// ESP8266 has the following connections: -// TX pin: 9 -// RX pin: 8 -ESP8266 wifi = new SerialModule(9, 8); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//ESP8266 wifi = RadioShield.ModuleA; - -// create HTTP client instance using the wifi module -// the default port used for HTTP is 80 -HTTPClient http(&wifi, 80); - -void setup() { - Serial.begin(9600); - - // initialize ESP8266 - Serial.print(F("[ESP8266] Initializing ... ")); - // baudrate: 9600 baud - int state = wifi.begin(9600); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // join access point - Serial.print(F("[ESP8266] Joining AP ... ")); - // name: SSID - // password: password - state = wifi.join("SSID", "password"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - -} - -void loop() { - // send HTTP GET request to www.httpbin.org/ip - // the response will contain origin IP address of the request - String response; - Serial.print(F("[ESP8266] Sending HTTP GET request ... ")); - // URL: www.httpbin.org/ip - int http_code = http.get("www.httpbin.org/ip", response); - if (http_code > 0) { - Serial.print(F("HTTP code ")); - Serial.println(http_code); - Serial.print(F("[ESP8266] Response is ")); - Serial.print(response.length()); - Serial.println(F(" bytes long.")); - Serial.println(response); - } else { - Serial.print(F("failed, code ")); - Serial.println(http_code); - } - - // wait for a second before sending new request - delay(1000); -} diff --git a/examples/HTTP/HTTP_Post/HTTP_Post.ino b/examples/HTTP/HTTP_Post/HTTP_Post.ino deleted file mode 100644 index 0484e2ffb5..0000000000 --- a/examples/HTTP/HTTP_Post/HTTP_Post.ino +++ /dev/null @@ -1,86 +0,0 @@ -/* - RadioLib HTTP POST Example - - This example sends HTTP POST request using ESP8266 WiFi module. - - Please note that the response will be saved including header. HTTP header size - can easily exceed Arduino resources and cause the program to behave erratically. - - IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running - AT firmware (can be found in the /extras folder of the library)! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ - */ - -// include the library -#include - -// ESP8266 has the following connections: -// TX pin: 9 -// RX pin: 8 -ESP8266 wifi = new SerialModule(9, 8); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//ESP8266 wifi = RadioShield.ModuleA; - -// create HTTP client instance using the wifi module -// the default port used for HTTP is 80 -HTTPClient http(&wifi, 80); - -void setup() { - Serial.begin(9600); - - // initialize ESP8266 - Serial.print(F("[ESP8266] Initializing ... ")); - // baudrate: 9600 baud - int state = wifi.begin(9600); - if(state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // join access point - Serial.print(F("[ESP8266] Joining AP ... ")); - // name: SSID - // password: password - state = wifi.join("SSID", "password"); - if(state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - -} - -void loop() { - // send HTTP POST request to www.httpbin.org/status/404 - // the server doesn't process the posted data, it just returns - // response with the status code 404 - String response; - Serial.print(F("[ESP8266] Sending HTTP POST request ... ")); - // URL: www.httpbin.org/status/404 - // content: str - // content type: text/plain - int http_code = http.post("www.httpbin.org/status/404", "str", response); - if(http_code > 0) { - Serial.print(F("HTTP code ")); - Serial.println(http_code); - Serial.print(F("[ESP8266] Response is ")); - Serial.print(response.length()); - Serial.println(F(" bytes long.")); - Serial.println(response); - } else { - Serial.print(F("failed, code ")); - Serial.println(http_code); - } - - // wait for a second before sending new request - delay(1000); -} diff --git a/examples/JDY08/JDY08_Basic/JDY08_Basic.ino b/examples/JDY08/JDY08_Basic/JDY08_Basic.ino deleted file mode 100644 index c249e37f2e..0000000000 --- a/examples/JDY08/JDY08_Basic/JDY08_Basic.ino +++ /dev/null @@ -1,42 +0,0 @@ -/* - RadioLib JDY08 Example - - This example sends data using JDY08 Bluetooth module. - JDY08 works exactly like a Serial line, data are sent to the paired device. - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// JDY08 has the following connections: -// TX pin: 9 -// RX pin: 8 -JDY08 ble = new SerialModule(9, 8); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//JDY08 ble = RadioShield.ModuleA; - -void setup() { - Serial.begin(9600); - - // initialize JDY08 - // baudrate: 9600 baud - ble.begin(9600); -} - -void loop() { - // JDY08 supports all methods of the Serial class - // read data incoming from Serial port and write them to Bluetooth - while (Serial.available() > 0) { - ble.write(Serial.read()); - } - - // read data incoming from Bluetooth and write them to Serial port - while (ble.available() > 0) { - Serial.write(ble.read()); - } -} diff --git a/examples/MQTT/MQTT_Publish/MQTT_Publish.ino b/examples/MQTT/MQTT_Publish/MQTT_Publish.ino deleted file mode 100644 index faf8817d07..0000000000 --- a/examples/MQTT/MQTT_Publish/MQTT_Publish.ino +++ /dev/null @@ -1,91 +0,0 @@ -/* - RadioLib MQTT Publish Example - - This example publishes MQTT messages using ESP8266 WiFi module. - - The messages are published to https://shiftr.io/try. You can use this namespace - for testing purposes, but remember that it is publicly accessible! - - IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running - AT firmware (can be found in the /extras folder of the library)! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// ESP8266 has the following connections: -// TX pin: 9 -// RX pin: 8 -ESP8266 wifi = new SerialModule(9, 8); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//ESP8266 wifi = RadioShield.ModuleA; - -// create MQTT client instance using the wifi module -// the default port used for MQTT is 1883 -MQTTClient mqtt(&wifi, 1883); - -void setup() { - Serial.begin(9600); - - // initialize ESP8266 - Serial.print(F("[ESP8266] Initializing ... ")); - // baudrate: 9600 baud - int state = wifi.begin(9600); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // join access point - Serial.print(F("[ESP8266] Joining AP ... ")); - // name: SSID - // password: password - state = wifi.join("SSID", "password"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // connect to MQTT server - Serial.print(F("[ESP8266] Connecting to MQTT server ... ")); - // server URL: broker.shiftr.io - // client ID: arduino - // username: try - // password: try - state = mqtt.connect("broker.shiftr.io", "arduino", "try", "try"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } -} - -void loop() { - // publish MQTT message - Serial.print(F("[ESP8266] Publishing MQTT message ... ")); - // topic name: hello - // application message: world - int state = mqtt.publish("hello", "world"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // wait for a second before publishing again - delay(1000); -} diff --git a/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino b/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino deleted file mode 100644 index 093eb02eb2..0000000000 --- a/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino +++ /dev/null @@ -1,128 +0,0 @@ -/* - RadioLib MQTT Subscribe Example - - This example subscribes to MQTT topic using ESP8266 WiFi module. - - The messages are pulled from https://shiftr.io/try. You can use this namespace - for testing purposes, but remember that it is publicly accessible! - - IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running - AT firmware (can be found in the /extras folder of the library)! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// ESP8266 has the following connections: -// TX pin: 9 -// RX pin: 8 -ESP8266 wifi = new SerialModule(9, 8); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//ESP8266 wifi = RadioShield.ModuleA; - -// create MQTT client instance using the wifi module -// the default port used for MQTT is 1883 -MQTTClient mqtt(&wifi, 1883); - -void setup() { - Serial.begin(9600); - - // initialize ESP8266 - Serial.print(F("[ESP8266] Initializing ... ")); - // baudrate: 9600 baud - int state = wifi.begin(9600); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // join access point - Serial.print(F("[ESP8266] Joining AP ... ")); - // name: SSID - // password: password - state = wifi.join("SSID", "password"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // connect to MQTT server - Serial.print(F("[ESP8266] Connecting to MQTT server ... ")); - // server URL: broker.shiftr.io - // client ID: arduino - // username: try - // password: try - state = mqtt.connect("broker.shiftr.io", "arduino", "try", "try"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // subscribe to MQTT topic - // after calling this method, server will send PUBLISH packets - // to this client each time a new message was published at the topic - Serial.print(F("[ESP8266] Subscribing to MQTT topic ... ")); - // topic name: hello - state = mqtt.subscribe("hello"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // unsubscribe from MQTT topic - // after calling this method, server will stop sending PUBLISH packets - Serial.print(F("[ESP8266] Unsubscribing from MQTT topic ... ")); - // topic filter: hello - state = mqtt.unsubscribe("hello"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } -} - -// create a function that will be called when a new PUBLISH packet -// arrives from the server -// -// IMPORTANT: This function MUST have two C-strings as arguments! -void onPublish(const char* topic, const char* message) { - Serial.println(F("[ESP8266] Received packet from MQTT server: ")); - Serial.print(F("[ESP8266] Topic:\t")); - Serial.println(topic); - Serial.print(F("[ESP8266] Message:\t")); - Serial.println(message); -} - -void loop() { - // check for new MQTT packets from server each time the loop() runs - // this will also send a PING packet, restarting the keep alive timer - int state = mqtt.check(onPublish); - Serial.print(F("[ESP8266] MQTT check ")); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // the rest of your loop() code goes here - // make sure that the maximum time the loop() runs is less than 1.5x keep alive, - // otherwise the server will close the network connection -} diff --git a/examples/XBee/XBee_Receive/XBee_Receive.ino b/examples/XBee/XBee_Receive/XBee_Receive.ino deleted file mode 100644 index f5825efb4c..0000000000 --- a/examples/XBee/XBee_Receive/XBee_Receive.ino +++ /dev/null @@ -1,66 +0,0 @@ -/* - RadioLib XBee API Receive Example - - This example receives packets using XBee API mode. - In API mode, many XBee modules can form a mesh network. - - IMPORTANT: Before uploading this example, make sure that the XBee module - is running API ROUTER/ENDPOINT firmware! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// XBee has the following connections: -// TX pin: 9 -// RX pin: 8 -// RESET pin: 3 -XBee bee = new SerialModule(9, 8, 3); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//XBee bee = RadioShield.ModuleA; - -void setup() { - Serial.begin(9600); - - // initialize XBee module with baudrate 9600 - Serial.print(F("[XBee] Initializing ... ")); - int state = bee.begin(9600); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // set PAN ID to 0x0123456789ABCDEF - Serial.print(F("[XBee] Setting PAN ID ... ")); - uint8_t panId[] = {0x01, 0x23, 0x45, 0x67, - 0x89, 0xAB, 0xCD, 0xEF}; - state = bee.setPanId(panId); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } -} - -void loop() { - // check if XBee received some data - if (bee.available() > 0) { - // print source address - Serial.print(F("[XBee] Packet source:\t")); - Serial.println(bee.getPacketSource()); - - // print data - Serial.print(F("[XBee] Packet data:\t")); - Serial.println(bee.getPacketData()); - } -} diff --git a/examples/XBee/XBee_Transmit/XBee_Transmit.ino b/examples/XBee/XBee_Transmit/XBee_Transmit.ino deleted file mode 100644 index cc33faf3d4..0000000000 --- a/examples/XBee/XBee_Transmit/XBee_Transmit.ino +++ /dev/null @@ -1,69 +0,0 @@ -/* - RadioLib XBee API Transmit Example - - This example transmits packets using XBee API mode. - In API mode, many XBee modules can form a mesh network. - - IMPORTANT: Before uploading this example, make sure that the XBee module - is running API COORDINATOR firmware! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// XBee has the following connections: -// TX pin: 9 -// RX pin: 8 -// RESET pin: 3 -XBee bee = new SerialModule(9, 8, 3); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//XBee bee = RadioShield.ModuleA; - -void setup() { - Serial.begin(9600); - - // initialize XBee module with baudrate 9600 - Serial.print(F("[XBee] Initializing ... ")); - int state = bee.begin(9600); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // set PAN ID to 0x0123456789ABCDEF - Serial.print(F("[XBee] Setting PAN ID ... ")); - uint8_t panId[] = {0x01, 0x23, 0x45, 0x67, - 0x89, 0xAB, 0xCD, 0xEF}; - state = bee.setPanId(panId); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } -} - -void loop() { - // transmit data to the destination module - uint8_t dest[] = {0x00, 0x13, 0xA2, 0x00, - 0x40, 0xA5, 0x8A, 0x6B}; - Serial.print(F("[XBee] Transmitting message ... ")); - int state = bee.transmit(dest, "Hello World!"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - delay(1000); -} diff --git a/examples/XBee/XBee_Transparent/XBee_Transparent.ino b/examples/XBee/XBee_Transparent/XBee_Transparent.ino deleted file mode 100644 index b063df8338..0000000000 --- a/examples/XBee/XBee_Transparent/XBee_Transparent.ino +++ /dev/null @@ -1,77 +0,0 @@ -/* - RadioLib XBee Transparent Operation Example - - This example transmits packets using XBee Transparent mode. - In Transparent mode, two XBee modules act like a Serial line. - Both modules must have the same PAN ID, and the destination - addresses have to be set properly. - - IMPORTANT: Before uploading this example, make sure that the XBee modules - are running AT COORDINATOR and AT ROUTER firmware! - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// XBee has the following connections: -// TX pin: 9 -// RX pin: 8 -// RESET pin: 3 -XBeeSerial bee = new SerialModule(9, 8, 3); - -// or using RadioShield -// https://github.com/jgromes/RadioShield -//XBeeSerial bee = RadioShield.ModuleA; - -void setup() { - Serial.begin(9600); - - // initialize XBee module with baudrate 9600 - Serial.print(F("[XBee] Initializing ... ")); - int state = bee.begin(9600); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // set PAN ID to 0123456789ABCDEF - Serial.print(F("[XBee] Setting PAN ID ... ")); - state = bee.setPanId("0123456789ABCDEF"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } - - // set destination address to the address of the second module - Serial.print(F("[XBee] Setting destination address ... ")); - state = bee.setDestinationAddress("0013A200", "40A58A5D"); - if (state == ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true); - } -} - -void loop() { - // XBeeSerial supports all methods of the Serial class - // read data incoming from Serial port and write them to XBee - while (Serial.available() > 0) { - bee.write(Serial.read()); - } - - // read data incoming from XBee and write them to Serial port - while (bee.available() > 0) { - Serial.write(bee.read()); - } -} diff --git a/extras/bin/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin b/extras/bin/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin deleted file mode 100644 index 792594c7cec044745db1ea217def19c5d88f90c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4194304 zcmeFaeSA|z);K+clnOq$+k_H8skXHU z?gQ8sT2Z^ZrTBtc-4u~kmt7HE*2hIni!EihtZj7#T&jSIpnz>DrG=9Dp1ElO_j$gb z-|zRw@4u%XCU@?c_cLeCoH^&r<&1)J@k+f5A-&5LgZ@AN@f#zv%y%MJdn$67mByyy z*;wnwS7;a^4kIyiW^$d9aII>Hem}V`)`@YNBRHF@;gHZvaUaXKu217OHu1V1JJh8a z*1L>NJqHb1e25dS&}@RwuuL|hx=bzHg!X!TiP{K2S{3MTBJQVRvmV}Z5hBJmg9aO$ z^tv8|?0N)4Lg?Lb$c5%3mluNj3UwL6Bqz|R*A^UobY||sU^cYk>N0e7+ig1h57v-` z5lJLsS*QN!6Rwnv&L+M4Je^{7i3Z#%kE&De!${+5uO>EP6y2x>3QQylryGe)da@}S z;jdY~FOETtCs+)saM=v*W3;PNf8^J=o56l&#b2;zHYPbXU2~_tZ52yhk3VNnp@VXr zdQILG0~-oLYE;PIg;4u6#Big5Ou+jJ2y)$=0!=QQAcd~Dke-{3s?SnkkmAiO zt7?#{VcsrMyotSD!?lw`632-!-#LZ~(clt!J_V)|C;$~A9wAhb20v^<5QY~7GlEEN z{vaE|+|`A0ALp$$1ymN}VvD%M;{0V*^KfY|C0xbijaz!?K#I!oYg(g3cE3Arc14aM zE*K6P9>|%W5tqSl@~kUe4r`m3Hr0u}JP zU95DysV{kx<=Gyngx`9x%JqW2(GhG{z&tfTXos*H!etYBo&RKu{tSz!fE3g&Sw-^08CS#QFZBakZmlj0#3 z(O}YtG&341;_RjrixiHSQqv~aB?)9J zpHvpUYPvK*_?Qw+m7Bv~j~4uh;^T6`4=L_u5$I99HMg#AQgE?G#2oI35-cJ!Om!3E zcvIEQPN;CBAVGymqAxsbS_VyAF`2}&@MY5zV}w6a{C8GSb7OSp=)M%&lwrGj-Hap^i%Xd*&)}C##dgI%H8UKhE8IJR9BX-nUwK zlH%7`iiio%DS3NRd*bAis)A5VFmb)Gk>ZzGqR8%&DPukdMDI21$rZQ zML0Jnylw+(mIAt3drJ6}%MRFSoRX3iBzxkHu>qq{3W^?`84UN2!oY@jWb_)n2oi z3ON+#vp02s3KGS4v3PDV6PnS;nodQ$fkIXoDInIXB6kiNsYtmwN%KY*u`FJ z{zeh7H&|N=ga$c?-|)xwNVXTTJu-B(^UR5%-fVoZN&7Y)qKCLJLIq`JXXuQG(V)RD zhGCza*;pVYXJfOH!$88ZCvjXCPN+CgMrDDz>xzv7pK{wB@8fQEcZmjiTRZ$`h{Q=FpGk*e-vPEuO@b`3>i=jw53Of}u)C zDtsVZSXjRNJxpRub8aRxmut;CO+P2PJ7^WzKC!hEV*^y?oh zbqab(Fc8)J6)snKptYy4aC(VntK>J7tk}4+a%ZBK=(K)OFlJ-Ci<*^eRH7E%2?7}a z#*}RTo)l2g^2Q*&G z^R(S=FL(M4YCV%SzPIBC=>i=fB07xa(P03KSw@|Jmramoimf9j4ES{J*E{`2KxQ_E z{AupZ`R3Rve^Q@dnA`Y0jZ-35`Mk!0kH6Avfn>tf`~%oH%u3A*)bx2T%x#(b)L50R^k;oSd%^`M8nBn{TWFd7LMo)DIml|5X>7yFm5Tq?vu8t>vKt&NRE!Ifo? zl=FdyA1>#E{*|ki68B^ug67d|>56kQ<@V*XsqQ$?#a`Lq*YQ z9$i-U$jXNw;&102(`K+Di0ALlo5$Z>vTRuqFaO=nqv`eqbAJV?&ReJ57L7rC1eQ7S zjFwyQaM7}8F{l#d&-=MtXa3I@-oqj}BkwsQ@6j^3tNf3w;O}1ft7W`}U*Io+g77ze zL11NhnsdgjcS=*`-}G4IWH6{GQ%;-Va6+2=3u%s9{|6w{lOY#M`)Ou?kK}jQoztO~ z=mV-5&Hvxva(^Jbd>KqZF$~knqh$}R@ISP4SrnBcum@Hbm+&whWvd@z^DsJf=tlVJ zN0ybbF*+bPAw=h!LFFRBRsQ8xp8fLKY~oQS$RsSVGB^A^M*sKke=+dC82JAU1K%qV zR>Ij|UUOfm(2D0Gvq~WJYv`0I?bpO4B15Z zma0x03Fr8R5+y#x@)9HdmOVWK@huM}GQt~(pQE0Ca(yA}KSzC`_@?h^=l7H&>&1y1VrJlWeV=#zD)@K* z24|=U!{HOS-3iL`{dTcRZ{VwcG;m}CNf^lEf_hz_cZ2XR>Q&$`S-t?NkjUetdT%P% z=Y72DOInpSY5AX(WKNm4BB&W7bW-bV{3*)`ssJb?A7A>4-F?Nb?PSxQFDZA7)}!9O zJGbmj=lWc|oNdP52bAQdlip2jhSQD#7jCzcS$)MbjtGNphAR0u&h!Xv3Ycp+_re^) z1e%;0=UWj$KJm)h0d~H1T%w>LkV1%5;f<^h#00Yo31UiRp~z0I;?hd88=m<;P;OZh z`4>d@ENjkUhu8W^;ZXDhyezzK8vx2Cfo_6TTed6=ztSYoORzemWnr-q;Z>{w&zXeL z`9ui_p$PpYLKK}I!*oH%j|xL>Ek0;C<2b~fQ()*ULfu?1s38Vun0Cg}CZIYVako4X zLy|D`6rm0-9CL>TfZ{Dr9H{!f&2U6G?YNGK-%oOFPvl)4Z%lF>hrq-8Zg|!~D1nd% z!45$Wq388Ut_}#hA=E)AfshBm4nYs02g-Ip2tx=#sDMxi!39B|q<2j>>0QD%)P7oF zYziN&Ji6sfTeo z8-vtV)Cx7IP_7cGEhtw+H8-JLjMNiQt_cZYiVw3!g%3eo)b;$FKmH58Sht?wP6j3E zjgK(Ivg5q@(KS_n16#qqze?^5I6u&FSk5OSejh>flj#42+@tyAk`B;W<-nsfO`yXGgU$tD z_BVlcAml+Pgi!ZXWL6zKVL70+A4X<98V_aQc@GHen>oG9tI@k&*XdoS4SLr%WqSFH z$-{ds(B1J#QJu}Iv3ggUR_{6jK@4eONp<l zlQ|l3LQLkv=4ObUWU1yZh#hCKYyvz&R%o`IBPU*o*y8cO7+h$g+3}udINVH|KB7Qp z>E`q-t+nMI)N%*k^485jaOSN<>0FZJ_$$Squp+9R)cr+-F^1HqVv1BPdlW#Yz(zgq zDe%>Z;|fa(q&%@4v1MJB@7UpH>gNaIF3b^jYFVVhZ z`0Z_!#BTQvZod-^p{hU8-aoOf)Zg;!iWeALtAF^{tV6f_W`xT<{2TlVt5hV&;u~ut zj;CN_tiUfaSav+9v1@4!mSfdVGrECB@c>gF2vra-#TVpw1;op64~sj=pe0e`UPC3& zvn27Ll@UdBQdEc{&W^|PSeEQ~7|sIX+umQj9fz&FV+A1KD&D}_6dt0EhexzxLNP;_ z)AqakRn%_32yw|4$;;8Z=DH#7gLqy!?qW5u+ z#4FglJD>WL_r@%{72ikqTFnDX#>=(8LX1#3$}rgN4rd;!u2!`w5m5*7Sgk(WD|vbS zEK>YRr<)#Yzy++TxIlqL2U;4UFn^5iW)M*C?_EcP*-_A44AhjtVxqXt16f^E@;))>k5MDu~6&Sq*jdJk8mxfq@Y`V_!fZ+ z8aY)4CnVD}uGSdl(7$ap_-58*P_#J=G*c10JKmi@=ccw7=v~r|-@y9S;^^`{DqQ8d6+hd5Vt_h+h#YU% z+X&kf5jw{$Ag)^sKp?UfcGm~JKT<;aJ{hzn{Ot~>0^!9Bf5~2#E2q6&I8E_F`Mo_H z?mzJI7fnYZuxH^s29tKY$b^V&Ks6IB@EHcYE>eV{Um#12*lUIKHVSO%Td^L}KOKSJFRN>t0=jq&B6yhJ%q zkH<31kQ~PoY)BxkfhmSXmR5>85H_$xp@*6;xPcfv_(#^N|36t)qFUTq7GkEP$9BTc z;+kuX5{^v=?`i}2na#6s)S)$WbNC89q=?ynyG;T5OQQ_O=#P_JX4s1XFU@`~9cv9OTjSe})t|?!3gUN_H4V___F;~o zV|w8NJ0JnICNXLydd`bHzIcv|YpA#A#}Y1A))uE>(Y0}1Uz?yY$Ve%$b7BZrKM*f` zO|hPp6i!fQD3&P67_5_PN_2Y1ab!H%k&J-eIq&$GcXh%S6#HdD2myd>cajP2&uMJN ze8p|sUz&?0*JJ8av;xKug1!&J^Jxe$hBFQ=J}MkEG!220k0aVHuf|lN0oK9}GjrnG z%h+>ne1S1WBC+2qq01Kiy%zp1i+z^Gb*m+Ba%~Fw#G-Cq`X?dtrw|kEP@pQwmI1ET7HLfd#UP6-1;MJIfY?HByVg%&!rkL zgAnbB?eth7u=PW1Xc`Q?JMCaANJf=sU3|L){cHI!o)|s%#vh-?ml&}F zklTS|@=VN;hmB0E6AVQN*4>PQ?QgNgpQ zIEr$MeX@m5wPAUaen3X2U1$6W~1Dl0u2m@fG!? zfCw(rti2Q@MmRA}?m~ZM>}k*PuI-IXHmJAOjGP@;)vRj+KwxrLMUV+uf#qF3S=f`T zH6X75L|RqTR*BnX##w4?va_+ejG(i)nP+@Ti#?~1j!QRKoXT`V(5Up}j@KA0b}q=P zfJ{_xCkp)(|BQ`+DKGli+O)}UKf($tk_l#dbktG)6y7z-brxiGamOadRoI1^p%J#} z;bbqW8-#kh~vO%5y;Nu@+KI!P6?^=BAd8O%-rhfvt4(s2uqj*0m_G(gr9uCOpC z(0Zb9($*R^)DGOKw&PSDcZ#2Os)Re0H!T+-uinKQu5mk&Y>-HWlRSQ7%{8El2vz1@ zq+BCzy#Q-8{|NP|)|&_N_?(^2nB_)g-ek9~hZx!X=K&t-Aap?34WR@A6PAR7j-&2F zAShLzqb5!@OhydU?=ZB;W=B(@Hpp}8R1~yxH6jYSIJJP7i$ns;qK-j9v)*%-p5>UR z6f48P4tR>)$0gPJ zKg0`Ws`e`dcFhmV75*;1Qu~Q+atprg%`uy+~JCg z`OnghweB)cRhOr-%2QGAdA!-PA>i34H*m$}DuMg?7r^@O<2U5xO%IOw zju_QLv;_8~0cWfOWWywJ_C=r;qO>Uiy_aDRz6i7ZC(ymX{4#eE4aD^j2!tdEN(gK{ z7^(ql=YcLcbdhkdQ>hI|lAiT??@gN3t^^YH1%C( z^TJ(6ljjIhy$|y;vOj|_1b%{5kcsi1FI!T!oBQV^zU==Og`pHKDVy*TIr$ZqoI6B?gA_j~LteaA zfF#1|tLde}eu|6aw5`{MBB!bU4r?YO1NMQBDAgm3C}<*NV;n5T2{=?v4P^;e9%j= zb|f*>h7Yh!;>7;T#A#+;P|o7z@GBOt@Pmem<(}<(>l27bHrL43QtY}h+q&cMwr5)9 zi1W`wl_IDu-(huZ8ho>w7q{$orY-N1Pw49z#6GrwfiuAVP8W zC5v6D6@q$Y^^tKJLEhXr&+J6ujtJhwh(XATz}!g!!jHl24WUx4~n6X>JsCc`?E5fKdrjqyu3@ceTP!pZjEO62zpgHFkV#n2{)$ks*rt89xxjzvsf za;8-9DPaca0Y1kAzsiG<8joBZUWSW~gN;q0A?=nnF9>CA#K+%k%2JtBsYb)TdDqG2#*WUC7ohOv=>N2w%A*B%qSfz}bQQ#Vt153#8fpK)dA-J97Qi{i8T zxh|Kew~Li9xzVyM3UWhP;diW%D9(ZOijUr|$y3Yot=%$DIM{gf?L%DG{>Z6`ia&fB z*Sy%h(*KwNlpJt`)H>4hXM(KgY^=lHA?ROvDXeAC_RN!CD#?Da@nPOpg+1(@D2})n zm9DLvD})2?DLHUl78{FsYt;h_+Z^}hOi7)y2ZINj%DgG6#l1aiimfgG@E)9;al}tl zSszDzQ)MuYg25{X!2e_fv{BGIEA{+ZvC&J!cQ+4EK%9o5K(hmx5F# z+;dr`dBDTER^F8~e|BL&@AA1_d{W`U&;)UjYB6jvfF=+;NAtL5*WH*&FV@MqjL}?7 zrZ_&+tu-(`1W0sBVxL@L$4416<57QH-c(nf=N;m4NkU#u$mQyvQ>W@E>|ef{Xz?8O z(^1kt=Pw}D)Tq!Arqj~l>1?)%aT_L@FJ7pchuVZA4#pQjl#}OA(IOy=ak|NkM5tHp-@jPBXL-V@{>kAFp?^?kFj1v?J{iBy`lp17N7jejzi7Yk)~g&p z>!86D2K-ica)-FuK+D!-*zjVKfko{emR?K7|77HOh}%^~B(gu9+-b!x4g$pNBeNHf zs4lOz8ID9dAh(GB!E(0@z^RC#=Ue1Cc5Pic-jdhR(!r?ckA!CcN1(WIJU0y88C7L; zGrTs{4>P61j!n{Q`S>k1-HyhgOvNEi7V;ir?GpuP&qt+i&m44;X!hQP$u!GEuu(fI zp)-r|o2)Y$+-5k=mosx>^dv@%(3}=m58j}sBb*HLT)F`Ukf>Zu^aBzmU|~VcTPiZLmkm%56oO7OSW7unQDBFIx#v9&I3-D(t0X+16Lu*!UO)ALo&v!;D) zpiWEnF(N*8C6F#9WXLR5NIKoPR zy%Asa2a(bPG{|Y1=iJgY#|{VEg6s?KAFj;9HHRrsU}BVJdTyW@0ybkNq5OCQOolXU z4+`g0kNMdl*`{)|T){suRDy$MbBq?lL8)W7>gg`nZe*Qt?RMb@is!N% zV28FPWcnAxN9~4?0*7LWrL<~U3Wk)U>=jbFLE$2oQGhZ-E+hLw)b6qAKzlxeCDojw zfZEppwRhovFaSg0Y4>3M2uDWf&4q6+1o=o?d9?A&+XuIt;|?jhm8N$z_>Y4cq_NN0 z&DGotN~@`&`Q!9bp0C31vufbR21#=47$jV#A}@7gX2t>{y3zf*DbtRWdVZwlkBMom z0GTRJ(GiGeXWpwdXW7w@4T{>Id~Xp-e^kJvJRwggrli z?ANyCNaN|ZHI=g50%UpxrW83g55jb1DzsQ8s9!LGay)$H8bx_7T%XvHF&*4;=Iuku zbBbq;z&q#AF z(18O=HkmRF|0m1zZ=HjF!OSz;FEb(?6`(Dy-3fd=4LRmq3Ere?%DpneE_c3$mooZx z6bxQtmo_$tpR&t-nwiztep^tH_;)L~txRG$Yzg4ClEPvVd4s6H&&B6`!=`h#>#a(B zFY8uzf_RAcD)Bw+MLgsuMb2Y5K;8%}D0J?B6W_(amYW#+6@VPx$9Im5<=j-h-;_mBC@Vk)!-(_b_`@YN?IJ{@cP z;Memss;KRZ-Bz!yxOaTOs?^}#eFI&goss)A6B-8qqugR)m zXODOdsK$;sZ1IEnr`=KIFN`X>hg5H)1FL?vuht^oy3dIZf)i840VD4?dnr@V?5dE7 zZT|qY=J@pTHDUw(4p74A1u38=CYfMH3up2d;~~FRIO;y=U>uk0!dI0xMV~7hSF!20 zqLZPbp7WjGpN(2{bXFzzP@ecD7MpYMH*Ah!?1y+6P&CtkzhWTpI?rYqr{!t0@V^)& z(;&9r1`~dmy?{&$ri)ue?;3E3a__qYGI7t3JzUXMNmuy&S?)^(7j6$GO(jKLhy3C( z?DW3jbgdJc-vrg#0aiX+M~cKR6=L%|yq~@2VkCOs5MAqzxKHOV!h`C z3Wkgu)UGXmrEQK8eH}t*9MA<*-iCGvj|?!hgFMb4RCyA5GAEypzMcPHNt}f zK-#NV6x`cHw4NyTik#E6-cdW+T#=0X^6R*7d6$kHwbAa6n60G)q4Lz)A@fS(UuCbBZl}i`XUO{kKf*T+pn_ ztW4YDRm#Ak=v|G1GNqJINc6#^n=%cgC~WPSViUV$R8`6P_e6qt#l}`j8#?CV@RA-$ zx&FTU4?JV={Zrvsdge zIa&_Wnn9q%`$2avuUclIW!sSF0cvW{a?KHwU2EdBK^q8w6ug%l7nx)FY($*Zb0a~{ z1ipiLLsDotcC!g{_g(JFscKDvO*&TuLBV)g`h6XCvZd!ph56}@3Vl~D0sy#}?wX*` z@_Wj*A(Esz1rdi5$~}vx$)rXE?lMtUgJ&YFpCiI`$(J#CxzD(N5Xjl3Y`MC zOqf@Cu5%|K{1iD&b)7ry0{R2nr^u}bD!k2zL0pint~-rlRfyJy+K4*8Gg1~R;@5QE zw`RMlVruY-7xgbLTr;DOaSHY1=Rmw0QG)ZZ&%YZ(XAOfMKabE^&q3X=#<$-NVP}}}Un-^4q0^D7CG1IUJpZJpcCf)3ND1Uy& zOu?#jekwD}!}2P6@nWU`Y=eQ8;7=K7H!%dd!4tsUMSZz{o$r#A6~HR*O-d1-xahe5 zA}gYK43^xk;r+Xed!*pFd}kfebW zyg=dN%h_QV>W}hpPZk}p&Wv*Ki=!O;KL@UJa37;l$I_we9K7Uz;NZf449VL$Gu^@s zr85o=RSdb$Arr48qf`E^?tFL^@-;#ctpSS$G38EFI%A^MQjf z$P)Y*gY0V_S<`K8hR!<%PdmDF%0YK<;zY;Y&_9`@PL(^CbwlTZG`ci^barPMgx-Fu z@^;ZN?xNVG7MqXZ`xvToe}EN3sf=TcPxr&20S=xmQvtvCo3^V!^vfDBi7Ka}pkTj} zh@RMph0DiZ_NTdkr$`-(T)>PaPp1WC?W@Z_M;+7HOiL+OnG2JPxidLat_r3hxFQow zGLX-2+Y9${t3Mp8R=|Ff%fW(&<5cwrY^n_M>8)koSWs~y6t&@l<$Hg>7Pon;MQU25 z#^c$#DCkgu3eFTi(9C zG(A!o!}?aX;;QH182qPxjjNtFG^`Z<(9fJ!TAnniHAqCy7Hq!^x(FS*lgHy2f`nK5 z(_acy*~hgJsT&6BSXbUIW*pYukC04;k=QXb29YCfIH) zqOrCw4cG1we#7eIy5tdyA*#L#BSy7laC#fj_O@JNHWrnP3ZeOu$f;yq1DrgJaK?+X zI5p#o_!V90Lcf z8klQ#Kh~&4$OK{Ys85U5aENQD$8#9FPsdg;?dv=o4BcpPCIICyapjts60aY0|44;4 z=xrM3%t0`Yvuqr%%Hw!+(BA|sVX+#{nxX*L(0Q>L<9c~E{|cTZyF@_PM>yRfyay~a zjRScQ+SE9Ru{O`~4!DTT++7134VU{h;P5@Ue-=HIT)40{?Gs+1fd`H4W`cs zgVnjI`Y=d`{a`)j_%}t)YC$TtIn_JCHP+drmqJON0};5w?+m5l^nPdxW{APD!iSXs ztZFI8fERF9aTYxQ>#fPyzvz4*J}Y^lX-r&Mh?am8QB5q@jk)lA}3tH^!gLZ5eq7#}7TvYgC$SArPB>2J+! zjF}F~o24;M4)`y(WQHYC2O`D~m)vk$d5k=ZKe;fNr|aokHQuWLvCXf?T^FDit>ET7 zjp`jd;JxLo2rwdN6L2zQoh^2QIJg_Pv0T|$!YMwS8o-le@Vlbl;8}v<_91z7=6Q81 zTlXX9CDrL0&PF5WrIu4Sz&?jLia_XxeeAASgi3UDmJ*&90p@y7)>$+8RqHqi&fv1V z_DQ6+-C~TbEpz<6pHmbB_4-kX;+oJ$0!IbaAFl?vaUivw7?47%@Mml$9Ul&*3F7Q> z_2bCD^U{g;`;Q9k3p#gP0^4(x298nO#1J(%zMGRZJx{ao{*(aXU_n`xC%f^bBwGSrz^G|w71vsZ<_d8+1w|KOHa1^!e++)-tT(xx z)CbD15RG{@K0t8HbDHXZP#~?`Sj3US_Bv35WU(rER1WPOT5BD<20Y!AY2Zg~Rcg=U z-?2)v6WE>#bMslc0l&l`RohEo7rU#0^=0fpAs5uEq`N+3Bz4z^9Pvj<%2jsP2Qugb zj;sK(T7aaxK9a~vE~Ek1Af3`Z_X2lUSTxU=JROd!ODF%C%gsPfU4;VzkQPYh+%Gra z9EKamtP9{@0*V0Dfq2O}esAiuHt@H@@vP&gx`aiQa6oGLdBjFC@!a$I8!uU70^K;! zItD+<_=YM!vQ`L=o$t7}e`LeIMJ6!abz$VYh|m|2Lbc9r?A*T_2iOqv%c*qphDVzy{YE;Ky$O>21pjO2&ciofuoo=u=m9 zTunQ@jzD}5n@B)gLH*Z&ZYlo5IeKqXE>8Vh z_9}&Vxp!l#_opOF1)EMT656Rn`=Pb#z{3>w{FTueu-V8ys-Yq*!G2 zwH~@*oq-3!s3nQfD@Z?f zW@%8^5`gC$7$zF}aD4T0`Y*OU{X|bjj7M(`JD#9%q33(mtXovss=@D4Q%j zHY+fx5Cb_-#P$Tra9{T;f^$)`GK2iMTzxlXDH>RD@{xY%ljAO`s(9nByplM0p ziB|@?j$zUI%Z7l4~jJRz{%cjV_RbbEA zXT)xX#OIEKP&GA==#!mcS4c{=fbf_MWy)PCTVtL*6W#m&O>6QE*dhU!%oFyYaK_zq zYu`DpZHedch{ZU0m$b{;`SgV@UBR(GitTf|tf{bfa;s9$#xp0gBD{_DGB<_^q(Bg| ziukm9M7znhaa_kTfVAffg{2Tzy(3W=8|hk=DssEKLio8o!(m;>$y*w}*5X>YZUF^q znHIdgDib?XEMRPzGfs$$Kh7e$>r;xz6N+hE%;kRm(Lb4lGH4gG22zCZDSI zE-rNGyWI)MAMUk`yhd@wO4 ze@=uXfm<@n2{?0|&L2?^H4uw=iN*R$OI9H0eYNv*3fvif9m5wjI#b!uJi`mPVD}(t zhEppZ$CiJ(&a~%}qyJ*FgxvpN*AR>hx>lDyR-;>?KWlQFyXZd1I$>g+X#JFSwoWpiHKuM6pJd= zZj&e3APSskb&@1-r4RKIbzu45eTO5#=}MbQHQi8IGgPHP+i-B)v=NboOv;kZ$2PeavjPW-nMw!E&jc(0Q=sbK`39jd$FOfnKEB`F&-`h2a;Y`o9CZPHdc7uyNkE&8%ihil6s_3P% z5C@Pz>PsVE0xEjR7g7R5OnoUY>at(-5?JgW2WRGyF21)&?z_BRGb4BgSj156@t~39 zKiu~o4yXzUd~c?ZaOyEAdI=Z2(4j)d7ql$prK%7f`99Rrmxu+xzLb~1L5)QKki!~I zc?tZ^SOfr^V`^{pn)t@WeMDP7zreGPbtB3gOn0g*rh8O68oj|#{}#Io-X4B#w!Ns#)$30^8t{a3taZ+y*nw4kQnrUbWiaJL%} zm(JJqyvy#*L5R*HxTQ7waW@!y2E>UCuU7wnc7a8FW=!G4xyE@UQ=DnmIJMRh7n~cF zbV!KrZ~wr@DS~4_t*SMH$9aI`f+jV4sp+Hm6wO34Nt!<0tl?|UQ}}k*4e#HN+Qy-A z=mHaS8#WGzrs}T|9=y=*1-m$0%>s+8gt%Z5b1TrIvuAM^U7=fv7EN5NFSBuFg`DXm zs)Ek0&}8fGT=4Y$)hmINZ|Ed$p|9)SK-(t1pl6m)nXW-Ca=py~aa_aQVEfi_ySi+k z_;!Xfu(}V(5N>rsn+o_mkK@~3*a|QM{-o{#YXlPC>w&}}wr*R&+|T5I5xE`op)H9K z9an4KYXh%XrT`pK|A`<0`*F<4Gd5kzXUOsUo^+w$Wz}4RCH3$;Y)ZXKifm9A>~`mv zZq?Kmy9ftoBnbO^L5B*Lp=Dt6Wm%L z$P*UrXiS-Ak_58b$7@>4up33^Q^> z;3Ecbyx9v{q+kkx+W=kQoa*_jzLi5@LHBg(+3))RtJzQ8V8vy(>Uv?67bCfFAa*qL zinB{~Jq^Bw4B)Xu6;M7Bn2jW5nIs__C`Q&@tYHe2z5A6AQ=$P$=l(5ZbLKoE=9Iyn zzV2I=i^&}9&NAq-0ZpFQ>EW#LaT3WOyTR^$z^==$>Lpy4r@Yy-nw9ChfgEn+YcRLf zFY34u=AArr+sB>v4vLCvS|+2R@r5dLCsmh3qDKZQo7kVf*gd=)Oxp zu?#P4--Z6A0;(q`6@C1_cWoiIF5=p8%?h z#C1K{9O3Nz))93l8l_iNUeXP`Ho9&-zW)JM@c#r`3;VsRFo}%Ya+Q)fCFOc?-iE4q zk5|oGe|(LBam=8h>`%;PbCIHCp+3sU7K87HjC1(V02pP!8ZQik!~=F2>}CWpiZ^%a zKwN-~A&SBo8=W~73>D}t9qgyy^p8xLlsc=;*f71p3||>k0;hN2e(;;XQ&}z76>e{X zek%|3hMIid1s4KjbZQOkX5D3aHU-pN=DV#bIK6#bh@WMv(hnYjV=6DuwfM2MzFY*@ zO)nYYsmKL7`$7nE2lfJ`4^xtXOM0LfFmxqq$Z41~6+WRzd}J^Js798vT%dLX z>TuLtfEs{vRFh%w%dNVgBEy2J2T&DgMESS}5LPv*s${diFzTwhtO_8~q)jC``Vl9} zWt+%sfN|necEmOVF7VVS-dOz)jn=Pb^*?X{G=}Tm5zhWNT7)t88;T&Ivq#47ij&B7 zKl6!62Z=e2OUJ>jB6$@M1zk@U$g61>KmQ}d7lBPKT?Nhy(Y*#f$^&190xcC$SqE2e zSud2S(VF*+Yi1_ofrUP}k}FwQ=WFSx8KUxvLuknnI%_Tj&@G*Ld#LGXOy?L==-O&V=z0B|EA)0~)AdfMM3hHv}Lgv`#`jGaatCobUP#GOg82S9xA z!UZ7kAy}JV``UqQb(~nN3NX;I-*5J3qlyY;#qC>PX1T|++|H5Q6Ml?4|Hp(lx^sf= zK(=a6Jlew&)R*Zwmi49^E7nvpcLf_6Y--zLYyyST~cTmNGHS9;@O z_dLgKrkfAk!O2|?=x}m(L2D$fk)Q(~a;>)`7@YccM39{Fm*-;5381uu1DE;=UGrQF zk$A+{T%p0%7_!NQcsN5?XWaW-j8$C-@QXA{^8{oXUx)bIK5Fe-zGq_Av&(0UBMHm* z*p|H%z&^kS6~~>FG+|8Xnxz z=8u{_)ydtEx8@`z;4j67PF@4+gqMrHm{oz$s^!n<%$wydr)5HanHag^`DYT*7NxmL z25;wTGGHV%(~-GG23VAkPle2z=YXwx{#>`3L*^&vfHoWAZ{Yd!rOzmEw&DaE$&O!- zS`NX2cpbx}{mc3n^>Y-aM*R$hLDbaKIfcI%LDwXu#=+{TnPY)^H0}d;#Kt~Vbp$TI z&Z=Ux6-Q6q%+=J;19$XUwe?UK*xqmF+#axbGL#9bV01S`p!3l30m@7VvOSI z_mk9f9dF>8Ykg#6jgD~@!SjetR2(u|<&F-g=qFb+_J1UuM_ww0Lpp0>#S8br)Xn7pvA*-mk50 zll4S)nTJA-$F{7jTnrl5d4BkMOp|^dzF#@dpcRTy%N5EtV>zS5q5HYoqJRn~FD!VJ zmMKt~2PJ2~%VhWxD!Aits2I|HYMdM_SWV-ClW!$)BIB%ynz-Qd`hI3fwyEVd?Sxq#w3%zGG_#{0_60%Bs%%LhparRpn6K}-*UK5Jr~co{ zc?c_~x^hD~XK0V~+A*@sCpjhGIHxo-YFNprG32v?Uwy&12ETtOphiJcOxoM3pGR=!&}#URsIl`Y=$_IP0*d=v9LWEbA2 zWz5U~#s*Qsf)n!`o}|SmvE_`R8Baba?7?YpYXGOitpPj*ZVlk6aBCn-F8W7`Z)Xur zQ(LD^ce?k;3E4DMtgQJf7?9F@O{rx~d|(<}`9#t*JWrK2EnVS0J2*E9#_^0ijwbw} zJdW=MVH{(G7pQqZj3Y}P$Cm5k`1R;GRJG<-W=>-=Z}eOxiB7(mKbr(Dv|G)>KL^u{ zCZE#5wuB$>+pKf$4shI?1HeQT<@|zqIc!#^{%>`^sf5G<8_9x7&_t%At~gV zAaedS&HhKb{Hss;%lrI~VEM~JE#J7ruHC%V?F=1piG~RoR%P{3S37*dda(0r+T4k= zbz=KWYf|)k+hS-NQFxV81pEyXaah_oNRz++;y4Q8=8IFTPH&|cTHy<=stP^i43*V~9<+Xzr7rXSO7uSE^FEwa~VE&0e`~3-34iI$h2GQvUSPr zo>%ErU2xy&6Hf!qwq?glO^YUos_it;IPQT?i9sg72f{2zG^6^1EB{ew6MFVH<{8`pZ6^5qtCHJQ4b&&B z3hw(R8!VAf>y~J()h|M=)d?fD!q;J7%+Xo_+~9($q1KkyT;TNuRn8u*66$-N2KRjr zRY{HGvg7Bwp@Yv-v2muvMxf8B(2Er<&oBUVwv??_^YG+dlYvCxy_mgE-ZdUlffOf* zj1sYjo$A{qVGdKU!Y6t?uie54Yk;zwg-5%D)hC7WKH-rUqu)dCXKMj;@b#hHK=)n# zboed^*l0qVNI#?fsm=Z=IFpUVF+k1FuxXmk-oSNYy4X~T?Q)V8(7Tn~1O2hFcNhw! zZvuKxW3SH8Rw=Z}2a}T_&&OsqQFI&as@3N3}sVe%dhJbdC+CX%$XlSYE(E zL4f{h6dKQ-h#!SZ*G2U#~5i*3C-UuS4ZFpzXs9 z?)vZWP6p5W@9@7f_`mlR>Sf#avbSNEBg;%;TQTp3zu*bPbxP`0jC zhUEz8D`Dyt`d)x~Z#&-v-?899%KA3uq#Gi>TN=hL%k2D! zYIGbwk@d@mFSGshWaB0cTx(zhPlVU+ntR~Y$zD@fuBC86GZ;9wOdlj@@X z55WqFRcrm0m`3!>tG)$*bV~#1jmH)lAimvt`n$^-i0rYRj)@y!3a}fzQvl;qs1k^Q zsn9xKfV;@i>6jXwfHLStB14zQ4gCnaa^M{%YpUE!P*z7%rO@N7mw}(W{zTK(1Kwx} zpu9PrZkQ=(;pFPR0-rCZ4*BM;n9>*3iE9wY-zF~YgUZr`Ov7Bq{aCdD;YWaoI6l*c z0gg-Lms=s)Qij~{5j7q;UZHXoOf3SXNB)xw1U*V5_mI^@Ezb+HZGt_vkPR`OQQRch zl%N`-yUIELv^MW8^xRU{Bld{R z6H$+$r^kU0vAo;jkz^njbPAWtQJ+59_1Qb8KEOI1>M(S4IQC|lN!8BZ;&oNP_HxJ! zqMq`2Nl7_45`?t~bWS~Td^8PU+u}(D)Uww)Vdt;$x(dh$iRG+d?0P5|E!8nvN=}eV zL782v#E@Se^bBGlw*h$ceT*ias5yQz0O2zW*WoN*%>R@x2J-zosi0Hg$SkNa$~xlV zijxMBO&o7AkAd9a!6b61WA7@HCEiQZOE8)M+!xRO?&q|^n8wq@tFRu?t zJPZpAlBB?4_?!nsIPtI@Mb%t~+0}A8TO?v=6-gmV{9}YHgO-DAJTW)G&)fhX3ves5 z^f(&Miz%N)>5HV2)$sop5atuO^fRaqh(KOoqslk<$N{BaL4P}rR-W0S^{2mmuym-g zNlmYEwSC0MI%fSAPQ)y->f6pk5uo_M=%R(bJwqlz<+^iG>Ut3Rz&cD8k^*3B`7+6^ zVnD{_+|ZkV>nGLrp8u?F+oXb-RFn-$|A(<} zkBh3z|9{S5W*FoQ%phR}=9vR>(ZQI}5?$S9M#0gfU{pd^H)hcB5*o0S*3!2D1+}aN ztkklap|X1lwOzhjyECMuySNKviY5i7h?WY3iVB?H`#EP&cE9__&zFZe=X0Lhd9I)P zr;b0u%kejIkKk<$f5a>W-w-@^)Z`vv{z*?Zt)5S_sW_;`B{R`xKBdw$nwUxP-@k@m zGnf09j4-)l#B zm}Oh_yfbP?YiULU2p=r)^P=- zc%IdoZgS=R+-e~uI(BdAL1VCh{e|QftMyO1oGWgNpo-yvvsl*C=QL4c74c(vS8}%8 zZ*klTCV7ZUSCbPZ=qFH*XbAkn48OgH881!r5pQ8kD8G&5?qTlw&$rQS&|+}S+%aO` z#=aS%o5oO`nR6ECL@NB+p(r6-@T{kvi8!U28#yN_@J$Xze_T2pI6BC3$`L?$O3Nu1 zA*D2XN2a_9yqOZ~2V1zB+W@p6p`fIAxL7W7B)s?*JdW;_!|4mA+)O{4do0l4c5I`8 z#&J__K{rrnd%-1$)7L3zS$>oNBswIWXcu8*=fp~ zXduyouR_OC(($3V2|N^f@=ke{H}4*VqmkqE5R= zm_NX~RrOTA@uq&yVP(fJ;S6hA%9croMmxHWVPtCs1Bsq*zfiS!8IJ7O#dmPJfX~BC3V? z3{54u3Y1bw)HUp({zX&C9(&cgR--VV?Xn!y2bL;Xk01J`S~ zcHw#f*Pn1bgR2~u8`mFkJ&vmo7y4nYgK9a2z)bX7RvSC0VD1^b5aeGuXxt}x88q~! zNSXsOmXuGiB<}Q_uckOU#HMAk3uB1IE0&Rlb)+Jnq^}{WRit4B^=O>#AgYH+!%|YQ zg!(mBWfT8*V)oO@E0Y$^*cbXg*$JF=?`L&;H`aI_U;5M1<4eC;`Z;$hVJ6$)AdbeH zrKkU%q+3ZtE~$8ysJ4*wO|;wwH>oHg6&r}^G15?gh%TgIHMYu`VHx4T-cHdlIYne0 z*A=`ndh@HdXN1oTTgJ4If_m~O0;imS9bO-FJbo0LuMem-9R^so%Xl6|kSUTUF#NU% z_)bgaERRaAaVGV`3xtoC3|39+da2P~U^UH9%(!!gVDh-?_EzPuj=8;P?_anx4}CQy zYq!|6wsMKfqax@Zu=pGBcRER*PAX;+?4K2Jqyhio%{h+1n{z`7sZfHTE8E-nmHH{Q zCiFwa%;1bstc6iAl+Lp-njkA=R4gg85MghvU}0Db3tyuCjbi$HqW_IPgxm3#is^6D zzYTARez%zZCjHw`Bl@2f)4lX>!|S5|f5i0H=--CjqW>u|{T2GRVHe!QiRnAV=Yqac z&s4t}nlY-{!a#(f8RhgimtHNh5T}KK11VI_?)|YO32)PX6ai*EkCwb#gLmJHXmv2! z%+fX=fgJADpr?W~As;GKhoy(~^HPe6L!ya(!Tx-o>Ywzs&ce)hs~YJoyZ6oc(Ri+a z`aMB005u#CHR_om!rs3MDE5X}O{*-yJB>p1H~JJarQrr`h!q{O_a7>-E-j?S!WatD zKNB^fc$hKEgq)vts*r+mg=tl*y-(DR$yMx$VSs^f5aRy)GbYQ1+Ew1vs-&!R$kjRc^2l1I z%HSMBg92l2Nl!^)oPKSxChd^Ooi$#C@@t5{Ca7@zS5vA^icQZ|zP!bQxe!9q?q9NjDJH1k#W|>OE_M*DRKg3Y;vQs`MWsGk0J^mYO`X zo}N^<&KNlMvku%sS#O?ffX^5J5=TZLadzf$%0f{4E&nTKeJ&bT4`eQNcQ0Zv$hBCbaKodh3N^)*W{E$VAFs}ADtClw81J8&r+Pg(Ed zaAK8(@D7@gt7DZ#Zi3)^#wMa;vq^d=vA#s6=7x=gr(=5}qk>4L4n)*Lk)cQ@o3AL5 zk&%o=7U3UZdr^Kn>rgT;4Awh<B@@Sk7Oxj6o4F?3)Qa)%?_{#=&6m#%+5u}U=R?bym9te6xc`Q@2cc}2?pV5ca z39SKNSu0zitObZOq16o@0&Z5e+PUAk#)sCP5dDð#*nK}R687MU#d1KO#ocLbNc zNeU}|=If<=2~BbVILL|7G3Z>`l=ZRbaM0GGiD+mDbD&v-gD9V&a=K9N1U6m_3y!p9 z%)vrBWD=?exzfyh;`C+Ff{1Ry6Z-GCc-pIo-Lmvlr%8_B@))o1`Q{8*7yji zY8Pw&I#3-#m>_={k8&yH6qjYSvxH5ou)3174RrJK$7u?QHK+u?mMIv>qmP zdA4W+%6IF!3R^@+3x(U^if~we#J;Yxgpw6P?CxPqem5sDpZ|i|p&QF5;+KP#ti*Nz zYXXnP`hROTO=Uu(@dk|sUk8%|A7DuPPrxDoXyUu^YkgNV-a%)85Zffzi{VOx41O~@ zAg>A74@KK3?}h0d$RVFy4hDsARBV8VjHCqSZM#TIqYN1djYhqZsCRyOpc+AXA(5!J zP-A(q%fRu-5l^e3Kw1>7PR0>Opvb`^fd7H{{Rf79Ya@9RyGQ_;mVqk~%uvR6M^KXJ zD}3}l!>vd_MNmbP_(3-bU_!5V0ZbW1z=B~RUfbN4p`?d)pYL%4F>y6X^GRN10Acw ztPsSovq+=8aRz5q{!JAi`M5<)|8j4Te+-)yAk~K9ohrW-k7b5dB5M=nw-zZGlU|Yi8EM=|_qw#NRatw)#H@pb zHV3D2rV$Oq+|s7KE(gvlo%G-PT`QQW6A*3 za>Jgz2zJwcP9^MCDF?)5?8L^iyMOV+W^ineVE~5sz2lOdZ=7B^jtzeO4({t2`vq<) z7Zq3_*N`5FIo?0g7~SSt*2;_-^$FS+i8op&JDy@;6DBQ^8t?n8dX05{p{ zDG_2=E}d^J#!Nf_BA$X!K{_h982F-NblMyHZ*&<=LCg9r?jU-Yt5wS!$xBS|+vdk@snO7TzyHyvZt=Y&Vv#Lb+X)l`iUky1^VeC$RaF^&ZqA%fE-d zXO>xn{Xh2y{q=JgM5}P*)&vj&bG9%~+PQ^e!%VSbmdO-i5{}83uE}|?yn|{iU|Lbd*ENg$itD^n@g$r9EBMD1PZGWu zf7XyCBxOMy9ys$A#PVbbUm4SsDO6&-B#S=IN-~SVB;(9!`&MC(ooG|!KC$TuojG$; zZtkYl`o)ZS?j|fPn+|)KeV83>qr|h7KG7}OrXPMspAK3A>b9hPAAHv0YQp8l^`Y`r z@Q3#$HHTzft2*SE)^o1(c;Q@c^U-VheHVg_!IHbVScr6K$H&A`OpgnGw{};DS|jA0 z#_mlw^dM9rqk=DhoiKt^$7#8TIWDoe-Z7f*-hRz*^PBXe=ftwAw@K8j#L&E`^u(gC zhoYt?mVG@K_4$PAuLq(+CIWXIRpZbiC0B;R!dZSwO7F(xa8zQ|kG>KI7t%Ast=>Mo zJHYbOfz{#-$2Pxv&E$o+1cn*>Z80kVOXgzoY_;W`;s-xG#jOoTun@3l*1XG9Gg_-x zA#d%wbY+aruGhM^FzzkJt$HT86FHk-x<)B5DDTpu!?}pm9;;qU?V(pQt97d(v*ChS z{!WR{f%^z`lj%*$fI=UsHU9s-ruNkvuHkvx5Bj%6U#i|xaGr_k1VI1xbylzarba9H zZjTnbyNh{vQ+H@xcfZ0WgUKH)U|s{)_s~iqYJg&?Lnk;QxKmOC?EZ*V9Z!WR-&XGa ztNu?A#o3wBRwlx|h;h$m%r;|Yj*%HWg95$;N)f@VxQ2~MO?WCLfMYc zJVtyfyweA$`zoVuM(UH9sonyzu!*1T0V|P!j|k7Rm8_j?ySOYoL!)1S079dg{q!4s znUT$gYj|8WHhPwsMynj%?$SXFw0La#3Xx?-qYHqg%X>4nx9j9YOLQA-t{8n&bD)t8 z-$9C9ktfdQ(w!g{a=Bi?p>4<&W0V+4i|v{z?sVp4da|3ApQeFkyGr}3C`OzKGQ(3~ zsBk*8>5GtY!~8Kth+%0LiMe*XnRg?e@nh7E!YA_%uVsbk7JHwlN-CUNDtMlD&!U56 zHoY;;(K(t`&5@`zEmxA*{H-wU1x|etC3dIE375aHqh=2F{(BqlOtqt42 z_(tgnF;|+am<4nQ)&5n8)|~KKs4H7-tP|^J(P%6-M|7jRk?|cgn&&XRsg7p-jt*mE*{*8WO?o+c8N-c?5 zK~Lo|J19R3DB+4Gs}9})Ig^?|3UgB&af^M38iR-j_<|_Hu>UoZn}HqE6XH!OoaV4Q zw8#DDnh(`p>!|m(_k7iFb?7=a_qPSx!_+ay8q0SEO>RweNuRkVFUF`Fd$Nmx>;BtKa{0>}lc!;-470VCtB?AU<= z!meNdquR7Fk5fSfHzwwY>BC=6>9GUkC-wNMEbY5IJ41r=m6e_|=%`B1X-}fUvq|Au zpzyq;cxI8OTmhcIF2&1&X9xZ~BY50#ODJ~BrG2Hux%CyhFSFSE37@&B(!Hn>!FC>+ z!e;)N-?y)igqn%FD!A+MI>%^it*j$5^LP7F7P;+?h|lgV^6;M=2p>Y^E)aptjDGG- zHOc8=`QJ#JDXWjH(~m|wV~(KNW2&n{gerASRj9pcl*h9vGjkKqZ>p@^RIp1|Am}m$ z-mZ`E?BazL<<%=HNVJ)3_PPl#?OwiDec4-kI^z04!&HxdQW*aPQbDmd)sY%xD-8bi zj@`?#zizbZ>F)1jmKQOr%9#AE%z@`cO9dskjJE!pV$}^*@-R^GD&=|)A9@?GoGDcj z7&DpiO-Iy(uBX3}#sPjQ4VLP#%)F2o6mtv=jHIBbwVK+s@b;?3h(ML_zYT{?;aM&X zM}=a|BF_rNGcM0o#WS-#oAGDOY)@{Sq!!7gB`dEiWRel0yEr*GWmaYG>`Lc{zW`UC zGnGO!`^chwYZh6@SJ=mwo86l-b2kBf$XvV$-{@YX>wcM8vMc6{{n0yfvn)$??OW;r zT2`V6%tivIx7~?3%agfExwoJ5$)AwD^Vfs5 zt^Tg&{tmTQ3Q7#lxV#r0_aCYa@xo7UFLlFZ7kN!(0j zvVxg)9(@jPww4^d%_u?cqmYcCRavQ)3GwqLucVG>Gc+=*J1NG-tkSJ6L=m}<8dp1{ z43niIs-~6ZIBbOyWRhIOma5d!35oM2Zw?e8x&BsrlMJo?gS8SDYO25{ys0C%nT;Fa z^(1jJneC;+KACP{gHI2NWgn3uuhm#fyTTc}7~vW`s>$N8hCUjyNS!U@~=l>(IuI82N=qv>XjSDt+atovS$q?(GkM%-zw)1OLva(8C;gz^igCUYqQE)e14Z59P*Yhov%mkEHON^XQW7|od1p?A%@}kPs-Z|af2NQj<~Er%$-Q1&gEF72Lgo6 z@&QMuxH@Zhetb-Lydl^%L(5%2XK`OufVH|7CmT1`@lHQDTviWb487`3X6)Oy0nai8 zy=8U4H0nUj5NP{|1HTUvJZ6|z+dX7emJ!ULfl5;lS@Wp!MMdaEW@mqNLx0;3Qbyu0*EA%7iuEJcBZt2FtT##<>_Df+8;i@r_ z_%O%lW*-ix+_j@FaTl)S$KteGU=8Evb}+4{kZUGu4U0|efY(PJ%Y7rux4Y|bs0~C8p?DbjUS@?+^(vAZ-A!@CgA2d3CvUQ`8LlPy=mS8yOOxg#RZFe zuyJxNKd>DsQec~h6PNW6 zIBsk!VAx0)DRfU}{14JGk^M5h3kt zZb{pK(}IPL4!?nQ`4ajbYw~y&_1JRA5@Lku6_{P*U(@`J*0lXB1Gm88%_pvM>wNj1 z(E0Yp>x)b0);b#wt=3;DN#+(L)><{cwQEurdqK{iZ6IeTQ6o>pk14{KXC1*P9~bnR$rn%CXY_` zm!&K^<}k9f9EO7zu}IH3$+Rb*MxRF0E}h_V&LP=DePzT~P0q#No)~|}cuv`}*S%Jw z_levBo4>^zW;frRwkT+%BSPS?s zvX44t4P#bPIHEyLXp;-#ZmWRyH2GgnYpu@E8=&Enps`#j6>Jf<}RjhVO?AEGAEX@G?|i*(L3>139_{ zx{2_hYG+C94Cj7w^Yj~hlYLD>ps6#YrWV|6YWflJQwZKO(L?DKpNc4)Q$m_ZNF3%D zpE(69`j8POrOa{5xh(2Xl<%X4cYIP@w^+$)gEPfSavJW6r?g+JBq4E`7c09j`r0q* z5=9C^*9(#-T@x|L-PwQeQTm;#Gf8}Rc{-SS~3OQ!@0UN3Y z^0ZR@#H;-}A6I#Opf{ZGq>?2w<=%1=%0MHc505OA7YTY08Z+VOq=XMgGaE1Cc#$8k zmC8dtT)J!iyBybF%4v=lUcbm`^rNpb>o50%YVRJXY?+nmgAC2Q|4FZ8Y=P8xrDYxSO~4pnVAMRYbEud(tO3P`QKAs z2|a7+uYAx7chOT;xn>YI(kWa14_2)S9I>b95j*m1y-3g2ztXeyF1mBBgUima18<1Z z(czkZgcd6y)cBPUYW&`PuoM*cL;Nf|Q{!r)npvQ31g zn(%wt0;`9Vf6dCRQGUVNlNFy`Rtp-l$$$HSPedA8pv&LiO#QpbG^YOk%XHTj7V~j` z22Wpa5nB3XO{QV{Ukx1q4;o?r=mYkn4Up1mz;6y74`Hnuf;Sx$p(3bDIGA0ZuuP?; zRmbH7q;Jb}qH89Wd7k;$U8=ACh?KRmZucgnD2iKLxn3JkU0c4`@z@|Y9$-^kPVQvw zFed_-AR(k%6j?V*3iY&PQ$kLe*E8m)yZOpEFM=BFq6o4xVX?=ht#t9jGO@)7Q~|g( z0k|3_J+ZEoi-L)fNM0hj2!f;^k`5bTD@JcR{p{gy7JCri4YD}{)*y$ga6oj{U?xGc zk;>t+#J)Dxf2fa^I(~7%Elc0U+(N+E@i`>iVkX-7%u!VGa|gN&S_aVC7PLgllQU-d z*eliJq6Hz7=+BB)L*gr@18)wE(8ii({Ipsre6$a9Ma@YapK3%DVCzTu32#1X*OH=- zKDhE?r1PT;?hj=QblvbeJ5V{1eAoSJB%p${%6gx%wwwXYnnEUNEczvpu)S^8xWh|Yxg5zR<% z6Upt8>{I+3^$vR$mu9Wg*dp`g}@X&>z=EA<23aehbQ=?W?Cq*I1eRlWlX!2@o zgTtPSzcL|O)|~JbG@$F7m%oGYhUUY(b~p^`it&n0boFx_{90H3OeO@@Z0zNRvEa z3j12URzBy09~hjU9BHe}2v2NI_2<+ojp9iG+6vZJp?fu_h830(>^9%L_5-uL&+j>f zyopUEKS47bcdg!}rs%=$rsCsXSH@-l9KY+^qTl){?lu^UTnF)+V}W|RtLe*6m_1PR zY~@0Bc}b1V<1wasZHNj}8NCo6ZrV=fdf$G7Ne;q0*X(vP9 zEKFfLoy>GZ6E)vdU#0GX=xMBGxP|&rbTylVoRs@4ki@taj4t^O0IM)e={a-K8TzG8 zA*b-~zitRFO1OjY#lGN?p-sqs*w2VTa5O-LBImMX&q~Z+f2D{xCqSHfihMSGw)-M8 zU9d(HYZeh$%C;0NEZ5Rm5{vI5R>h~G1{qhIt1~|!ktKKkgjROxCR~I9lZku|^ascf z5S4FgSmv`HaPOXf`wtp zUswy3b=W&ruo(o$K5$fy1Uq5^HkpuO^Q6Y+f`JVt4$>pUFj zD{0~rtoLu?sMjoi{PlQWjW#LL#eIK{K33kFGu<5!IoZh{3HRs6vs(8dN=C`VwU}? zHYe#53c`)Q`xV=f>FYd~0>2MoXRKnmSpii@f&E6ANAwT= zs%Gh`sHUqT<`lE_G=6XS={Sfn_bns%7iZqJYp(g_UG(2MGi)Fz(D&vkV&)J-z8k;Y z2jS+ik?KM2JJ)=zBdL&biTwBe8scTSx7valQw-0iD+pqb#e9^`5|eKzrp)j>luxNM zQYL}ABX2AdmcTl4YXG$py+L?OhDSFrQnV1^RJV|dEiF}_h zQ~~@aT&fk$p?V#oqqOP}i@=@f<$jb~H7J0x6Ce@tXDsJ z!f#a!{gs4JaL20VT4MeHed`}4ASwY(xEb;^t7rKffoTiM;e?pt9OZS9L(f-fv&@SU2 z^##YXstmbf?~#T~V5ZQ9B{68XNxIXaYuCwN)6XR8m?R37x;dWS86T!!6H9Ly7fsgi zw#Yx|I~K>PQsr(M7by5Hnx>78PYk`om|2({xnRH|DNO1lExj|&qs40IEt4q~`)Bd6 zrXw9;jN$TfK7}NKS(r6Tw9JAs9DQCE1_q~Q(Mdg`aMtpoKz_VY$E z=k`&V3v--8;Bh3A&aFN0UG^B{d{~0@3`4iPM#fDjt%IbUF-l_5H_&a8M3{-$tCv(% ztZ@f0r z#Vfe-iXbfcLGJx!s+8Ytq@=<4Jzr|_73TSsB+^XMycDFMz2khNBy>-Vw)0C3Jgt;e z(i$G~qG_Buvq8?j?+D%<)U(d>lue7{{ivz)=5VgQHJqV7 znNPqh4-Dw{)bh1t<}#5l%sHE}_1^NypJf z;wE5Ii<$1B`yR#FXx;0ss_ch`CAbVBmP1*`9oI_F74~%8==f})`Nzxt13k1i3^@T} zET3|_1;eZ+fu}e5vzUKUWVp`IgfN~>a@gtoCNJFgKy4-ecclj0(xRp)y=l@rfw{8o9sPEZ*-q=LGc1ONS3qYn zf3Y`npz3)FFEcE@g$Cs>E__CGJVW7j!$TuVeh4Btqa>9R3=5%)0wN!21gY2RJZ@I% zwYvNUZXUqZhW(HU(wqGKrB8~5Ptx+7hLg8sEcqv4zHWJ(!cB%lK(Yeu%|E0s5}6_j zuQOziXm7T6omhnfhqm|I5$*l9@ZxF5Y6`a-4vuK=LCXrM@JXkJd*YPdAu?3=6{@4V zZZ-wtnUI<4Mq{ch^C0HDD0y-9%HE@EA)K zl9uC%X1zO*GD5i9X!1O5i50VA#TY0QrCk_=r>}**oXRE^?z?Kg+X#cM#f<$sN!w<% z5pl8#ik)9arKyK@YRbaDfU#%rs>FcomFgrFd0Ihs$$(AVZKybk%4o-+LTp$6mat2v z&#aSna<>KeAnSG-+uHH%f}vENS*?z)LLtAjzw}@hHK$D(mQAHiQ^FvXIZU@y_NK#6 zQ5*-3jGOLNe#clf(_@L zExjZbrbj&(W7lN>7TNZ)2!z$X0+fKUpG0wd&z@3Jac~!2U z%?y0SD(6T4Vim^?!SUMo_>|aqGasKhmQ{RT<{QjTq=-v(>~p!hv<32l%zLgPiDVUZ zbLvn})C6svZy@R);eu~4s_eFE-;JoG+t`o7XVAk>h%Fb&Rh1)=+* z{-LH#ajN6Z`uNPd0_T&9rwleLvd`8Q$ZWH`auvcAC{DPvcR__SnxcF&wTn*eog6X((+zmZuoMz2E^%< z@{j(v{8}mhQ87CgA;$x42$fO{w;`B5H5{hJ#HZXHpK17%kF44(&6X8r71Ywucc=$M zfpk;h5xu4KzGj8F;#INsX?kCW`77Yj6Xi1b4Pm%`{#TJT7P~ zPiFZzE)o?Q4_*@T=IXCeXMJ|zj6IL;$X21#ns+~L@F9yh)r@Zh;jEB1Uk&M~i!Rg2 z$Oyp>_Ypd!dYG(=#^)^Fa88zbwX!gPhZ(t3TH5w+6i=t(3_QKXiy~gEqr2? zOyi=RgJ@@oDiHlSd$ep3KZdcMR3NCDo|GZ@91(ajYJ7a}*J6fC9De!T) z5%SJLq1aq9T(b1-2=rNgiQ48JxONl4A!d?=I>`pfj*WFF4rS^6-}}pHCs>6Y_-hhg z!e0dK#ZXb3b(o#2IYHQguZKlBT9Wn^{De?d5=32r=B8?R_fl$DV^~je(EXFkEsSmc z%DylJJ+%%L{v@uN4`#vY`Q_n5r5$3K`iX6;;K{daNCl)f;y~%pd?gnQUCleVQI@4w z^n=}H+{32&NN9{%Bbj%ZT{Ymm8DeVm(HT>c|d&8fFd4Qb z*CaD9^k0akq4axyCjO5_fqTNlJ!$3sctAbKa%+HK$MZVDL(|xe_T})!EhN&j*v*_8@{Hb%c2XkYE z{HYixzJ+g@U$52kaEzXo%tR%t?c96KcU{VUG1%mxmaVsOQ4j>EHNab;Vg=z;k{&~W zHe%sPZ#lTsPSQz3MZuO1F*SpW08eaMM%p7dknG&oIFNSVCJo?l7MwB_(#eBLte$YY z2Z5tD=m1UBAMg$6cfnt(seZwMdj~V%9_6|~%#+7k!oqiJK6DHuw#>@LnAovq z^FsG*9gs9r&fO@$WmVi|P2=5DC_Aw;k6phU_3*Uh^)Ggym}B^6xqhK8EpE8}Zz=R% z)E$&)N}C`-xkW{6N|DXtWQ|VSAFQm&YJ-ov$tK%lb?lTn+v7FtJvFxVMeMyrwhc~p zs?+v_l})wUo;0y$lkJantfkIYQo~w{*jXOWLic+*&w9Qn=RPMp+i7!K*)*#SfzRjE zvFYGUy8puL``k$BuF1NTzwmWAmKt_$5o?3usCzwAu)zrR(cu!TPIjKtR$*oDU#m2m zr&w)Ut}JKPDx9`0HSGPKH{)t-&lIuu7pzwl*|s?mf+ly0)3$l#Jt>(!cseJ?^)S3R@?g~_7RiqgE}_9&h}vqySB#m zQ4zbY$hOzXKI*jXv$6$NTdj#LG}-Fv*rGby$FeiO0^%m)F-L(bfv#<59c&A>dt*tj z-+H1sCtqf$$)2@{iPZ8)u;bE5nB4aF@=dMFlW+0=^qb4>ivgtkq#i zoCK)?q(Mnse53@YK0uIKay*cLSNg-^PL05Rjtz|GBV7>@a;n+XI4oukwyTC9xj@)c zQ4sa2V)ViO@N*d1=FLmVQdly2;INP7$7RNCpUFyUR`N->pLc-#LUUOVi} zwI65;!%@rn;jJ==yLb5flZ%o%^wyy`Tt0eP1_q;uRt9~Os1x$7@NRWC?eLa-GnIq4 z0)xjP65wf+53$UB*G=RBmelQ@<$-34RK z1#9r}tjl72wY)>;V#tIInMSN2l*t@`if z>W(A2M4VgF!8)3Qbs~xd1CisjX8jF`6{$l<4$u#UyBy==$Ne*C7fJeV=@LeiH+zIB zqTpEpJ3jb_074|;iNVM?420#T>?Vc+^=BZOa7(5~X<2J~EQ@Kernu`e3SwG*9j1-w zjJPua#=-J4$PJUniBPlzQ>+Uw3+G=LiBclYhB1?llMq`W)4rU-04qZwuL4UND@(Gn zp<>|CDB%`2YgHJ@bqFUoC4&FbHpIK{cP&}4{-xfMK66@1R`dzT3Q*|ym$@i2u+De{ zNWrsp#mfO-p>Vw9C>*fpsEiho3`U6kUy;Z(X)eOwQr4;gqnajSV_(UH+CC5?bR^5> zy@GI>fmy^Uvc%(jv8ODUaRw9j7Tq(hvf!YiU=~;(S+9F${gbZDVh{2;SGuET!^5g; ze-o_)`Ff6LE~jsh+ZivvgyK`K`*QA1OZ6P4Yz~{d>M`e>AlLq*h@r5GH^&^|>D$ zb8aJin>u*&!R5Sp-!|SnfGg)Y-u&f1cyr_$-dwVQH@k5OkaZK(HBs728-qk~uc&?m zdiwA)30csgDjIkDnm?qJi!wfP5-qXEw!pT7-sH7NObIr&1quZKBsti;7N8dxhmO-? z;YktEwW~lGpB8IRiT)0;2TSp!hzJ#y<6_n^vHA6197n_?jng^H?u@WHr<l7Bkgf9sjy6Qu{(T(~)xZF77| z7pFb`K{o7>%*4?X26w` zkocmdMg#?q`})L}%#B*osN);?Lzdb?I^U}kcX&_z0B!>A%MxFZ*-TsY{gI z_zB~eV-g+E&4sY=IDBA1{DhQt!%my!p%*B@Uu4*|O1~bVVuRq<7fd_!Ksx4>N=o%g zX69p!nNSYs0dukDzyMG^wQyjFi{@`^^laU@wP#?~?tMtf8eS<1TY<1}Q4hsukB=t_ zzHDcLY;;7jLViLDtKk)B921!$&wqu}ZfIW3GzM>burYQ^&$iDIX~(;@b!W!ghZv5K z_Tt^IfrtR*qHQeuoY^)p(b&iWZZ776%s*|9`hAf8&ljv70*t)eJ-}OeVQr#5?J7|6 zrw2+Gfx03m6Ql0CYi9?}!~%_WTSjm(8o*|#9e<#!6^kjSXLZ)Lv;!ZBP$$s;d5D=sCoW!Dl~U2mUNt#&@TN1Mi&{?tpF? z9l+ON!Vy?u`LF-7ZdC_J!rfQwduiLOhS$*9H~D4xuLWiRs8%-of{UM39sY|m{CZ9J zU|IP2qVRLrYoNqb7Jh>wp}2S9{%5QdvPB1j&Fb(0yoH$%j-5&uUDKur~=P6U^2b-45mg1YMPieYOV4rn(#5JM-bEEpH2K7 z@N}7Sc^dp}$()i$f0q1j>D29#hQCe6dY;C4A7-x<+-2P!7RsBphtJhR4OrIpJaPh4RIP`m z!)S8FGtRmlJiF_r?OLc~3@7=Altedyq(e!3yN){&JY^io^dQkR=oKHLD&phIV)7Wj zln#oc*b|^H#~HWx5i@P^0sSCHq6$<(719hj3kI3!C8S$I%M<@Qdgzi zYax1BGXvx$_)1oU17*1#T=2?$x7p`=h{{LUVlK)#|Me^U{oJVvH7T0^x`|P&4W613 zVP%4rv2*s#YG8<+ArI|ahq*A{!}V@U2XP9*-N`+??Qwz2O#^laj!N%=Q-M(KT21$r zTm{$C&?jDThjY~py5*q4sJLjE(?}IuM(yFO(A;F(=!>tJSdQ$@`-~qDi~@aWNY9(bD&M6?5vS| zE}%wiR>T$V8%(I^P0sP#+F#H?q?wx%3ElYIRThvGYbL|$eY)V<^gS&stoJ@+`+4a2 znPRi(f)I2mLW-u_i8{Cl%lkJRpy^=~-)%g49X5rlLkmqNb z=VsGL3S@qke_q~Q=6v%R8U3=yZMh|tS-u5r*?S-T@VG50(g7$?7%?6>N`ZL~;yxaD z2^Ugp{N?4EeOoKbcB;zek(bLW->uyDUS;&Ino%=rYy^jZYwi!;lYLcvqJ7jw`z#`i zx+KhE>h27#TS#g~>1xtR^)6EV5J5oTP3NH|qv@W2a~Bqnxhgf?dOoQNPU0_-l6?5CR(G~L^J5kEOzfT=}L46EsmvEmi37`!5ao8sAO zX&u97mh3(2LXa8(q)3o5yItM0{Jj3Es16q*U_6qjgi_B%t@$FKd6B+47akx;AUAQnlfCj(*HQP4PYq*3;SQ}B?u-!O zIgCt*MY5Y|TrnL-&DUIOt40*i07)C2`$?9NLO96|XSm6BT~M8lEz>bIy5J(6s#>RX z>J-cy=V-7hxG8qMxBh>(sN0`eRIt7>*Hu~I@)ayPIMY|AwSudNEr*$1vxF|^Ng>lu~F4E@9|RV%*%hf$iC6t zys(#DN|>=fH`bdnNX(xEGF7l>8yJEo!=HLB+KxY-!!0a~YPljfeF(G0V6jd#r&&-D z746)FnCbErVu;Bf!9~J3k7V}4MN(5BSpL8oC}8}9B~av#RNl|9Or*go4|BC|Ty+M4 z%37yq5xLuk@MxAu!5>);OaA|lN}Wt(PA!&L^kd*CqWIiLeFZtj#W39&=gc7X14G&4 z`-U5)JS;Y!Ixjz!*NbWgHRCFaA!W;wsZrOk4FdJ0fJ1{K;21)xXAxpKS2#^SP1iB? z98evE0)&Hw`9ZW3G#sZ6Q|}YJsd$QR`+Geo7I;E)Wpq&!+h~d9q_(s=?w|1&Ls#L! ztd!V~`B)sF*wb~;{>I4AdD3*qajlB#REK0;U|E*TFAJ^<;l|DgGD*Y1X{^33t3`XW zSJ9#VGd<{Ajy$2;$`tvjVHG~U{2s={=w!sh^z}G*EQ4LZWYIxzV6E?R@26T+QOi_R zCk(DxkaUnm8oWKwEgCAJh9;wBb39`OMu&;+7U)YHmO{Nvu;}DRXfC?OYHrpuaWX29 zH{9g6kxfp7>Nt&DAs1}-Ji1otEBV;{4Q)Wec<8`8El}}-C}l(&%DZSA9`<3h%*Ehb>kRpy6gST^Z%rH4Zwu zNz_0=WgR!t6OZF!o^NjJ>Mx}s zrqdoL*Dqr3vb}mOJi&BuMX7!+#q@Pw z0lPiKi-2&`YOl;l%Lr#OyFmE2Pimens7Y!MpQxu^39QovZnQj9XhKGKYAKW6m16S2 z;welX%4t1F1s*u{G74WRwKm-{W}+kQ7qO^{u~!jI@cOqHjgpHbDZ0!AUnbDf6eF3k zk@@r(vat19qSUh)WZUbBJxA^E3ztjxOE%Rn7jxjOXsTkYRU{?OH*d08(4ibiLQ;$= zDB&$yg1ugwxkzu%V75Jd^!Fq)GZ(k4h9vd`CdrJb%!@uK8ltgKM2Ge{A_XM%q~A#r zn{6Ev?wOa1l|erw(U@y9&h1EQcI7{i+5;0>P1i(p1TX0MSw57hyObW`W+Wn&bCDE#3Od2wB2{2oa zAbE~gnvK3izU;KK+-Qu%#j}Y$h-)A)=vizZNCV)xvs@5>lWqYi|GVFDDuYSv5i&?u z7UhL!(zVo%IRTDxJNlQTZ0BKcQtt@qb#RNDR~zT*LrN+84K9y^)$A@EVU*dP+xwd( z+SmWDvoQ*APnFb7t_t-^QqmQiOU(sbdMUEPBs)v z)KhEh;OmL{nG6@1wi+_xfRz|-AoxXMndGLPh5nDfWd%1L!1!TdL87sUnLRUnqNSHH zFAG~6Ufv{$oaGZjDu#;JCGW^t$nyj}VmCPC^7~NG3R;kh0t*9`0w_5_RslF%z|AUy z0pxnE3|pe5qi-_?$AQ!aWf@F8cIImZ3rmO6M1_fX8`CSjmtG2%AjG`@aNETk%eJ>t zFsG4N+V{5oh)_dJC>?ebWn$QrhZOFg=(LPlp+5CBuL2r7n)tdbvVNz-bJqP4Q+w=U z`)&r(+>YmaYb6D`vPnDlZPCIqCEy`z-A+R=cA%U+vTE1jJtYdTu(2gg`V;uuDY81x zx<9cWg>mBmZke=;v}wB~=E}jUmUX-O{giQ{#sO~Dbi4bgjVPp}z5C5-&iyY;xCuCQ z&}3u2n5c0-$hd#6!`ET+$^nhZTNfc-b;S|NKmj&|-SW6zibim(3v_0f|2JpXci$s9 zGXzNsCi^W9+Es_U-r%BCe)1*jg!<#m@}o%FG_#v;DsFke&>jnvsE^yueAfc7 zBd9AU3`m&7F0ww54F2EZFxC5F%&ewlPm@q7)b}zAX@1ouj9vc$-W&=#7UL&d{ZS(x zy{ik@Bx_GA6Pe{*4oBCOFQ;2BBfM_qyvd#*Qjti##i}NgbQ7regT5FN7 z*RG1?NP%)=1vWAjpTZXh*D1?X55_0L8uOq|e?)B6gD3)B7hH!m8Q>L6H#Ph$vMPQ0 zulOr8083Nl!KX0lN$Ry-CBQ!{w?bsNp#NDxpolwjEcl8_k5+kBaPZU9@O;J7C>FYa+VqUs&GQ;yLW6#hhsRpCvoH?*1@ zV|)kG4%`hVGGlr!(a1y(lPlXsmGtt46rPU*_60xGM0rNEH5-BuWYBRNdLo~+11V1S z$rzgOFoW$#!`j0Y!LiIt`23>?^Odw{p4Ff0fUQ9KE;5QGE&8UWT-lCX6+~u+K^8n- z*^L^{b#$CPYtl#U85=HyEsF_w3Qd5n3*4&Qh+3dprYQ`4T+B zLKG!ATVwR~qO78T4W~4}vo5jqLn5m)e4(qklf0`xWULNL2}oEh?rk2VD@*hTvS%^% zbPh9ry|JYyYUiDY{81Tq)_cHf8q`?BmKtWsdopjYbnm84Jfnqn#Bo*5ghi9gD%kNB zb6DxJwq+gd|NH(XgHIl&gg4YhS^^)A>+cQitodWLmXy9M?no^%zIh|&8U8(AjfEHd zyiyGsbr~DB&C2k;Wj_0X+v!dZPKmUIgRaKrXCCjH0GCp}36o6^ESm>+M*^qN|D~Ur zh+8>*)eY>Rlv8qjNdNo|yu^L^r6K0o8(DSzCM_}jKKba6Wd3sM%uAv>R=ydDD41A1 z-6cM`*E-*3VKF0wr68VNP1v@wuw~U@OKIoqVq~vj_-d$mb#HNZ@A6%LuO^MFeqd?Y z1IxJKmQcx!^#uk)HauR-G&hH?Mfx!D}0otJ*tDI*se7rJ)de3?~!4$vam2Q70`a_E z(Pxwc7_uobsUW1ru4{=PhBxRL+r&rU@h9ggigXoR(h=fG2!jTk0JC=1G ziK%AF>5+jzW>?^rmDL4Vb*xFpR8y7=<;RriR8P8I-ZF3UbWAMDhk-vicR^owrLMBF zZ~Zi-+ucMdM|GJUmZ|ISRTjki=raq;@LT?(duHgEUvYKg62%~rVut*r>5zrG9$8$w zTF;F>p4B}5Oo&ld-J2*eG!tw6tw*A)x|n~>51X&y)LaNRs;++Ei&7{=R&Dh%cboxt z6bd}xzqCtnvzW*;5Shu4CJBOXG~$fN{}wm;c2UUx7HX1n>G!H3tb3aFiQ(JLeQMm; zar4*}+&B&2a$|BIRTj8X@Z`Pc42%f45J*HCyp_jMM z;m541+TuO`_=%m6wn5}ykZY`T8@GB_S8b`4rb7rsa=vU^cLQV`EaFO5C3z{MvcIbN z=;?_F)75S5LuYjN>hXb;x!L7aYbIW7m!R#ZBa8Z@{|M>G9W`;oy zI$T6cYUdnq7z}J?yn$)W1rS`UVN!xNcV`A2wP?RES?Ye-8peifb9WKDXyNWaWo>Jv zWOlO}K=2Z{YPHy=8&hwn-e*N4(mL>^()F8l=#d|DqQCO~;`GO0yEP1k7_RGwPYd`pWZD-Bhz|TX7r6Ph(zf=Hu3u z=+fdm*`xRstG0C^#pNfry}NDSYkxb~IG0TL;JtG@x9HMt@?_r~^*}=d#{miw8I+YF z(x05u(8rF$3^iEd!@z1`ESko=AHg#XnzZ6LBu+{7?;G$P)B`k!dXEEfJT{ExpXEeB zv$homO=l;}gWUc>Bsulw=%LX?2l-^f?1s?n^`?AMbWWxi9mo%rrCjVshVO*80SnCL ztqMYaIDkA`vUO>TJ=qYCW|e2arB3;A=2Bs8x;?8x$ndr0`3`>`&i{FF3md@S66Y+?MmX6 zu1`+HE8;A~u-vWsb>zNrPFoGKf-8AOkn5_z`I`tjhPE-$&_WlrxHOHf)ZAktbXUjB z6an>!u9Oxb3A(D^ycW5NUU_NMq2QvnwBvC#g&b+S5r6rF;J@DDlT1S50Z=8eG@_tea|2+><^2o2Cg8Im6D1h|L)HKQ5M?{Jx%p z%_5ER+jSQ{uTaMLKPz7*Q}l`eCi7 zXLQb(vt%evbZJ6g8Rv1@-xw>-&4#uIJMb66)Nr0L%K{gjJOx~iGeHG|$Fb$ccP%p) zO!}p{di6Wo;U4=##p_DDbM*>U%!d#fnm6W(tKS8K!q~zsu9Q~S*uFm-2T*RQ-<3#H zSuy>>SU^S&A<-%%<<(@>$rWhW7j=z+gmUY&FNR)ui^h}cNr|wEJ6bcx95mF?_ZX`! zmx8WPehiBO5?vO-taaKmR+pC+xkMYu66BJG*bC% zdf}Ko6y;)RXbp9+wHZ+!cTi`<8tep*(2 z@-@)VjV_>>f<|<~rf8B|NOW5?4of1R#Dw3(W{#G}9Rp^Yb&yY4I0jTo_|445F?Ktw z*ysgQn|YyiM(Rrn24{s+jDqCfp7;;oN7qIBY?@tbvbCFAN5cTe}m5x z@(W4MW$RI^Z$W6yF?+>&)cz!e*UVB*o8)a{x%B5anlx#$uaCm~FbFo2zQe|dkN~kg zNOuTI2HjL0ijYc7LUQ~RlPkIGtqUT>Es9GG#6%h3JLyOgDZJ!e7q!_jt_ET|PhE8_ zAIw!aRLbfp+6fCBg~~hyf4)`|JDDboj?$fc{ft@!a?^D^8c1uZwmtnVE?6aRbR~i6cV1w!kw4J~!FCxY1&-LYmFXE#`k)*M zKVu*ouDdQ}i4JE-;l5bGF?<;=E7^y4xu zaUAS``)Oj|#?XN^A>R}08=hO=XwmpB7>!KX0hpTa7Z6C%yI41HBk*u41Rx1aDsZS^ z;~vn$Y&MSi(v@}YHkjg0EMI4$nzPC)iOc9J0gFP-FGZ_uLn@?VM9&B*a%Hp~Q9A0+ z{H5_fBSc>BS#1GpR~ZWW{g~ly43m`(*RW_H2@tX7pGMREi)b0?@FT2%Sfujyr!Q%XM!QO;CWO0aI1SWp3e>!Pp_WxE*Rzlf$8fp}NcS`1pWKJ; z^{^3>v>)F9=D_i3=GJ&Rh6T-HBDh9)(s&k(HrXKh;nqB1zyO?aO)?>+h5IoC)`@fG zG8E8tRkAL&7_UnF*vu)A+JyX4WULroMql{)3xOkf2lMtH(bje%xhbb2DxLgbMSU#s zXkxQf&U`JzB0ZRcT%_>kR7A1a2P^oPwsXf=t_SUSiVv2uCuSS2H32K~)(6d)+q7M1 zYiZdTOGdBp26=YU&yO&R#7cPZq&I(xBrIb@694~rAl&s6`7)LjcGF4ARaTNw*)OJF z9VzU3iS4UDli2<*|1YeNVTtXr(JuVEuY9|9b3`5dWK@(*N|} zi+5t7Z-qu1ab>c&u=XV4tP}5tW~L!36mmbiQ&!4yF=PxR@boGVH?efxANBCnCaHAyGRPL(XzB<0sqS1h6W zuQ{^Vqm9J=C#mGQFjx(BB8BG_h>O4YI@$D{kUl+Lp1Nncr)-PxRb!MmrVD z@w=u;!0{Yqlr;-pMZ7mq>au{UZO53UI$-D zNl|IIzBx8@ zC?l=xebE!^x(?J8A7byK6__l0aa;MPYNz1MpLM{nMzd8`NrrtJ|FQ!c65|(mlvh1B zuzlMq&fU5-rTg!AHHmW#hLqGP^8CrIVUdgcEEO6NaYHKy8&Q3P*0tyfnbzeH=R(8J zVOH@R9Lzy(i1UcImVOZym5OiO!Y?9got57GB1*H0bIsz?#Rb zgzF^9m~hOM#Paw(`M4sm)jXx8&s@Qa!(+BsPvd387&=ap1SYt}CUFqIJ5YwNnI1A$ zeCe9`52S4ITwZrss{585SYF+xpDY@BHo*d+MRkIerrR`fnuwlF+hR{NCo!qNM%|{L zG}%3yAj%KjJ;Xb7o32x6++?}*9V;ZgZkR$?hpt$x{a8=zxaAbn+Q$7ur+GwYct~fi z*4ZEA3DR>_m+5Dc@mAUTTJ|RBlOwXVYE$#6<9KPz-V`0;s!esW#SU-wCM+*}@>Xqf zb;!-g-V`M%R&BDhvlzJzZ2rZ{x)C)HQ8B$>3Q--G$P>6H(yUCxMfO&9#e%!wLx!*O z{IM(2LErIn@vJpm&f|nk?QUS@+bM8F-yJPG?s|4~AJPVN*AXbcg}-hyyZrfYm4dF`_)dx&MglI!%twFiB_T zJoXNE%=8_)51HhVtakp$A=X$w;0h>VQ7;R@sG%2$GB3+nvUlen>(yk|D7-cz z;l^RHa5%peq`MAa*E+`%V44UHi>jXCc_kDM|!)9axOUggSOfySB;bV zgvovA8z)+aDXG?iAoLYH<+|dQYHkj8qfDw&;Itt-!w|Wrq~_O!BNPD}C^o zLs{hxN=u%Z)}~7kmriP-Cw(vOb!Zz1G27F3vOdO4z?Y$H4rYkH`JfFVp)6 zBI2chJAnk#r-pPQ=SfN|J4-~ODDx8&+{C7n&f3A+nS8OU=aaf(cC>l*2ZAd!4Usjv z^g!tz)(ESv9*l1G;;HwnO*|&c>a^DZpHEkCdW*1afDx=l8dld&lZ z04~}jc1x+P3Eu8->OBem?#ro{0RxYsZ!v<;wpYJGF2^m_zKHws2duC;j~LS}<>rV* zrU%Mv+03-uQVv&z?B#)SJlFO1G-fr8TXq}Hk!Ds6g7}wSugTD&GK~KFtqJ0DJ#C9LsGsb@uR<;eb6#=C_#DTLz)m43GpN) z8)prH+2KhZWku^3#mC>5IyRokgSra9dhIVHr;ReWZ+Yr#YWd3e5bF#e$;h#74aPWv zv2Lh>Ut)qxKZhh`_>fNhN~WU9aASl`9*Lj)6>vCmy`y+H&5EqX?LYw>vhRR`M#=JV zU+Fzx(OF%v0E3L@iZ;Y$BM%Shu_P4 zMqt0Hq0Ye(C{Nc1-*UrHA|dyOZXjClt^svwk&j(qwF7OFS@B#|alti-9lwFQq=Mf_ zP~;EfO2$cS*@@X!Lxh_Jl~=LzF{xm+M9;#~CjYRU)4Z+dEM8ixEO=V0tj#yGTrE|$ zb)}3e(O8ww7vZnJs!;yU-mS7$vbCxdT673{VMR*T>vUJ$Eq^V;(@}Mg{A7#FT2&!G z@0Fhm<)>4AE|Q;%<)=q}E|H&0<>&qK^8xu;B|jg$?o7ZK;A9LurFhl>k5ydYN5aXr zcGyOCV*kRQVhCm$(^2LyLmEFcBrFX3fa2_wSKBb?cwU8mJ5ShZ|^ z(MFii#ct#f=FG&fF1GR}W(jXiBQ7s0t3v2gXI>c$vjI-yP{udU^}Y93<~9m z1;->$5*N6P2<3UHkdjcgHt?g=h7&kjOBb@qrj}1QQub{FRE>@?$LV*n$j-%z9`4zG zieZNMV3Px8zp%&0^@EZd*#DEaJmFJ`maz27ouuoEM7B>fYckn5_Vv3IoC}^<_6kQ; zJzVOiF|!q`=se{@m2$S?EH^tr_)((Ivj%V34-wo`aD$+x+;7JL+Ckhr9)7oC3dSnv zLo5i~akgTfQj@4v7Afe?y`uJCCheE0=M}p25)eOIC8%i7Nvs+Df+F<@XG!?Pswn$5 zKTx4~_B@9!K#F^dyVN2%lw{nAn{yJ3FjJx6$I_cw9wxrZ)C<5a=F=ed0*jyHEgXs#Y*q;8CF*9~ z>*5ID1>t*%{)PpkdJF|$NW!;LE~OQ68jKvq>_A*iv8AGPmFrA1bH;I$>xnt5+Tl?K zK9vd;r28%9r)b-39>ID-3O<$keyg<#it^HxE{L%taMXbFbi3ko^K3pRfjOjrimSTj zdfQy>ijiG4yw(eDXK`g#l6D>~6}cF(JqVgAh^)gjsI6F&d@Q7Rwf?OQYl31COpGWU zMQUqNthGqxF6X^Pao(a)-lD`+D_22TC=?H5CvwJM|0@~ej)T-#KL0YWVkfl;CUWFJ z0E8fLQb8#xaQz^`SP)~Mg2y(^{c>ODWeL=R^hiSJYeNP;3vnzQXb<19g$WchSHiOL7Z8+t zj)It_CKaiS#P&GmRk$e8i;TS>T!`FTdZ;Op;~i01Fes+saO-ZsQ3B0H8TA&v`6;3C z6hj3tT&8qduqPbo4v!owSQqj+`fnJJ;A5Q$o%_PD=`IG<>JV0e7$oDIN>h-DCuTa8 z)}X>HYRMEu=f6ivuw&iUg5G1^6}}@EKa>akzrQk)G| zuP|$$o-AzYAP zhcQTe?07%FXNR7Ha2uQc80D`dKC7{0k1CURCfUd zCz(luSn(eh)f3m?b-P`1#6YSh#xpjagECqWk_fa@c{O@}@et3(;nHcB=sj%bqczX5 z)+q1b-27f$Dpv?S?i=b-_TnP;>I1{TZGaj7d5e)h3lB=f^@t>@Or_ROwj{CpS~b%# z(WfuV-C-9)@FA2rg$K~?O-=d3ip+OF?1||6EqxaDd^WH->BCLj?*h+2#SDNSA%%yYR=A_!WHJh2mwFV`28Nly3+$rr@~pV-VDK&lD(dk z@ewQ|JrKn*Dw!dqCs|9Cw*sA_PS!hK3}i`XY6=dGRMQy@pXE?qQH^-3FE*?O4GS>D>4MfHlG)(I$H|GiE=WJxJuV`@FBaQs_xbbe;t zb^4y|#siZ>A}VhGOnFFBcayvfT{_g#CJP@(#+`r|E@2xWlS-244{UbXfrmYs6fyIC z*~KOf=XK4Cr~I2qbv1Jc;eX=}^wwL&TV9pNBx8=dDi)n_-0G`Xi@&^B^mK8PSh6Ru zFN~+wx4b(SL-6k~&p`tfaE1!dPSGx&GZ$yT5WlQbc6ev_4kz|cIrdF8{`&B1!0%n0 zao9(UF3+eIJ>0>I;bT>M2f3WlbPels&S=XyDQ!JJ)-<2sPYPYlVg7Ecf%vAy+wq6%D(H;?$%}7+vk0vN+5lcwX}wnf)`Wp z29O@cZaXZcJ>T*xLaSIj>@H$lV3v@%ivkzz)vGBj?*8 zR}Aj@gKvl1UEHCZq_(igsSL`#T`^298 zp^gxDWIPx8EOYA|;Xg1`MyIptO)s7f<%Goc{q+291bGFn+p&5|4eTR*KCBMO3nwGi zDF`_dl>4nMGw3@kDHcw_Hnv`(ce@6#;`me6%}^6(rc5nQVb=3@)n7u#f|yS-ip^)= z7nX=-O6Tj+L4R16U9Kxxpj(^c*?E_`r`I`G>{*1CX;|fY%D>1fYBpY8+QW~nhLyP< z8qeb421D$zXC+b<3yC?&=mKrOuJMVKvM=f$*77MC5RjV3({g!kddQO*y4*zJTG)6k zY;CEck4JkVoH?o0YI>bx=|3gHY2$j@=S^W7A-V|?xO!&zO`#I77%Wf5aDg<<1?lj?Tp8=GDtps&QW58psjF~^{P%84UF z>HT}YZQs*$P`xh%Dfk?prR}7?+bDb&A+Kb0bG)g1XX-$#x@6^j2ehHgw`Xp9bazW| z5wB|GXYxrCJaJX_C;g+8@JBi$G~?Zv->qDA-vM9fm1oB^n3vmswYp+wgLU;Lg|%en z6Vnc2faqInc(Aj!vA-BlYj#q3iI|;yU_t0!5r-7L|EB>)vcIupU>N17>C4faFGl{F zg3DyEFUW#FV|Ed&N2~+6lLa43M;hUt`=3OhVap#dDy9|!TA(~Cpe`}U^;=fs@CYF@ zk8L@U{{xnv3mhWCxgpE%kRP|~f8{^&U-?I~?Mp_;UYM3=88FdyY{o+c7h7 z-L!_aTzEmEzhy7#ZYw`yci-f1x8qnT$?J6{xXwyWr*>I)=RB?+u5W&I5@+M8Zsj~k zdjHf~!2gBUn0Y{nygkvZPlt)J%yF!_*LJqoqb`ErGiNz}n!j6dM8 z7QThK4Qt7CYsn0t1aiAPVv2H$w6;2x%I-jJ6ed@a!? z)_L*Gu<4CEYK}=uyDeYgSgiYd*k6@YvC~m9v!be^q~gAcwbrU+5aE|~J4#IIZhkpx z(y~Dy6_$Gxqt<1dY-rGI>@K+Dy1rFM&Ld&{5Y8hmNI2_Mm{kIjL`Avze;mr~=>0l5 z;E(A(q^G9l3-WSEW8X#;jM+ZXU|bR+Ww9g86?5>>p}0hKPY>7Y%7p zP|Erkln)y?mfxN?-dT`p}N}<1zr@V(0XOzuXmadlUc5OvZ zWYXa|4T*Cp2FIGLX`eUCx==KA+z4#^dzNWs4?i9k+^QbeEerzTm2RDHSx&|5&QEFQ z=k&TGPPgcdSm)n`Z-$Kj8M3~3A6?#s+&Bt}0sYaUKPT`ziC+WY!RlUSw+m<971v(l znbJ7nY>Yt>+8ms3N>;SlhMZFp^L8GI5qgJ=y(sKW>WUWj$!Ib)v^o7|KEX?<8}^Cr zxhGwF%M+e5dX)SDB>K?F^b>_x0Wb)8LwZ7Fx(k_j6d z?^_DRg3CL**S93Z1mE=kjjAXac+3AD&AnManpZ-5>r;7{AeWN6zMnVcCaWpTk!Dp* zB60U!6|+jZ?{p-@VEvea@L?(PHztf~DKTlCpLr7$jS18+Lo;(@b+y7#%bja zl4`}1*8i2=;5mx=0ocbN){^7ak`rAgrPN1H?(S2z@H0}sIZ?1(QavlB{u<)Ed<XqV zn^MlGRMR4x#x=_lNIjhWU!7!40Ftn z5YSeHCasyYapR~br>@FhHosy~UWROwI&z~23=;j*pe}o~qYh|P2Va!60n6bRJ?q85v4h}3y z1h3h-*y3BVIt1jQDL3i<{5cTt&|v$Nq6Y==%`tQBg^+@j{(8`pqyQ#ZKtNCQB$ech zE-*-iDWr21!~SFF7enaGv0Z@r*)X<@Cf(nl$akAszf|Jyd)=xS1~(pVI@Dvw-!Hl& zs>f04jYo{l8LhlWVtb7%wGFOqELbiTo{@4${ZXkO_1*luHDOQLe1$cKAqHah98(Tu zNX}CaJfTHiPQ&y4ianT`;b;iq86l(SJ3vp7EDzLoL?dj{|m-D(bwYF8k&)qs{ zeSBj>qozT>9t2J0=aQInTdMo}5JyxyC81uThvb!&qNmsYe%L_apSE%V-q`0)`)*gbW>+ZOAGl8bKBOz~Dk7uHse5nL!U6${hq=KkP zEHiKiVshpT_O)QX1mB^4tcVj6^iND1C7NO1MVUwHzX5jOFq48@(sfEYgFZytFMJYd zeQFn4)m8`ValKawU0%6uI+YFloe|31}t8zYOWS8~HqgsLAT~+;FtF z|1-GA6Zu)juZ9W~G2QJ9*veD(NzlS0gt$JJVE>8dm}Da<$R>r~B6ijoLbm7NE&&|+ ziH2e4Y%YMAw%M=6(L-rVvW!g9{lcO9mZW~D6w{W@PN19EB>r zofJD&=?E=yR3&lQ$+6Sb-UHOTJKI~8oOU?#U6yLyDQVj&DfT^OOQ@+OlIjDsc!1&Z zVpTF4d*9MMi92#)*FMzgV1!ELEU>wvE5?#@4GqiP6$e^nhR3cn=pWYkIgeSyyGb!c zw>m{hRl>j5-qrf zkTLn1N0X)Qz-rey5{1pzjGIy5)6@_xaJQ4U#!T=2EO0#B)S|p~ctHzI*Nja__!`v> z*US#3w+1m%&?2n=kxhVLlX0O$TpNF6`%_P6JtTvXPqEMl7)gxhuj)Ip89gqmgTa*M z^IG#R&?iHKuN9!Y+YNBxhQ|qKIR4>iD7N!`HS!ya!g-YQ`h4V~)c; zXFfNll$&#R4uHj>L-hZe}%JLRL7d5cSYwWLk`t- zE~3mC6clK(*12ud<7&FCZd)!EsoORKvazP%cnp0(nnHA`k8r~HYsMR{Szj^ImJXDK zJ6jY%Hyp1|$||M%SyWn}sBTS-e}24U{wQPYrP3Qu7Ny|S*DD~n6Jb1NDYkKk>D^51 z{#6B-&s$~p3V&0q`-pK5S1Lv%e^x0x9g%+-H!5f1sAQUYClJMbVd432DFLGi5 z6ce!nMiFF`689C=vdtt+ zzG_^thZA|A(V(g-)iio0@a(LLqe|Gr8opLY`AB|X!ig+9&vjmha5L{mk@79$uL5D+ zWl~IMxZ$o|=d{6eha!*XJY!8_ejcgF(2boZY`$vTeAW624uI%PLRN5X3rM~J@OSW} z!;SGwJkD}0%g}ieg$-AY8DX3T5&KV48p5 z@og=Yo%;x9I~bK0^wT(btwV6F34Ggna+7}fGzCc|dl+C$)m z(Or=?`T{y)+#==LgaHYJAUc6X^A8KIYc-oOR_Zx ztl6w7E*S0sj0#2SW(Ug#@Wd3oee*iskwA|56g1t^^^%MKuBd>Iapr4_3uq^6lJQRx z*s(=63^@8jhuRTGpG3n+aYpwAq4Ah$GXa4WC${l%DQj3}`0-JK8FCc3+Usk3`SE;l zX|2Rhl6O{1LAJU;>>Mv&!`kRITtFX_dz56!zQ)JX8g})XC+C`5%{k0Ys#!EAjdWrw z)|E55mW*x8fvuV!Y+x)Fh{y*A>2Fy{GApj4L(k>$QBItJwfyItxJ4|bnzxj8lx~!2 zN<01!Bktz9yC4dj&3JK{SSf&K3R;Gm=Q4KO-0Z@M!|b>(*_Ms6OH ztl2Z+7s8B=2s=*Z2##j$khyV1JeYBv>(3jzB|UF#&Y(8dp3)PSdB%#1<2}joSQ-lO z;X3zU0UxgK^8e+-70kQ*b3R= z4(vwSLPjf)XG!^uWYkFX#$$RL;ec!_MNBg;pGt*tFe)$OBUl}=k_@0RUffEV7dKGK zNmyQ1Wj0N1FPo~gPt#h{DJm3_+C_0rZVYh7f^&oG=IpBb@*1L7s!K118?$^%C+1GO z-`(H|-M?a$+UW__Bn=J}CVFEDOx3|o)m$d|OlfeB1U= z82c9DE6VOc`Y|i_kT%M)Rn3U7Y*(|If6lVa0m~MV{`5fYnTCj%uFSGc+l>M0yc;Mh z{XyOkV!@q51(${*RdjX^%IsR>$H}R%wfQ2wmyI(! zPD%^gEyu!oXv9TNlr%O*KR;3IEHPcr_ObZJXFq4#j#rn|p4{zBcjAaHIq+y`QYNO3 z=Twvwyv4X}U`m}Xjk2XcvnE=gOsVo%;UcD>ql20bX6Y(_yJGN6DWoDCb#f`wN^pNh+!C!#W0lqg+}NT^wB-SzOQOJB*$hF`_2Z} z|L%#M-dIy}rMx7L!ftRy$&!ZHx_|ES1+-6=H1d<_w zQvbjMTG=)*9?bAbj^fR@_xwbm+y8;sCYtuXd- z=WHT8-bPzkC4#@rsJR?H4*$YpG%HH`; z!C$1p*CqPbt7@{7ETuKiU&SGR{Rxk;Gd>ydTdUXPuIIILr_3-hI;efQDkMRKj{aL- zlw<36N@Qz-z+g!cr<{u_FP!WA;an3Z{5ov>4VK6;svKUHli13s2pcO9-A|>D(I%`` zg7GRJDl+#TSJd`*QDVlzGpTFOM}chb3HHq?DyfIt?A`M1*7 zSY%-gV~H{cSGUs5EaE2`h+r5Jxmyzk9tYg01>AVp&U{w@+j9gTa@`R^>l~g=lxDdi zL(4?ZQAo1?1h4MN)0p2y9vI}7vq6jsUm-b%gmBa{k`O{jGLRt#9|9>I#fp`k46pLt zl&z36nt~5m(%A=Qi5cSYot%|9Sb^7zp9&!;`FOORujP6Uv3g{tlM5scrmx7#No3`q zi0G9S>JHyw0i5V|q)<}|u_~1JPJuzl2uyuNGI7eHmhLG)wV(j!NEj%}kl7(+^O+)A z2F4_U#{!hTDv#X=4qT1#_u&VC8dnXj#6vEQ3FOlOmQMNkP}|=n{^o9z(gq@Jf5~`I znITTct-5v^UX1H<3}y(s1AsX!v~0j+{pT#_tfTO(i$f6T+3;(Aj#aznwc= zD{PQpt7O8_eygfKiPMYl9RJM6s3mju_=D>(U~#p|{X^ZRz$|GCdEcQ?g2I&!7$0ry9oJ=diL&BzJ9+CwV+vH5#qRh;?bsb(mR3>c2kM zhL3;)ME2NTNclou7=#QiRjV+i5p|m3cFWoqSM-$-^P-cF7oHlhId~pA`*!=(?y)!` zO=;r|Q-T9i5=|W@gW&=Wb?dI6wS=hQFaVu5egjcuYx5f5f4{k|PQC*+`3E|~cl4$R z=KE%9%o)bWeoUmW#7y$Cs7Et{KEqDMniPpwH^$Bc&hCi4tzqeEpzPf*W8rTr{kSFg zP|E|I0*?XbtaA7N#!q3e33HR|WrKp-l91rvty$_I6l@>j!W z%j@K|mm5bx8(?|-Mp&1jJ#4?Ku%Q>Tlxiw;K{|61X(c57gH|*6)GV6rVyWPeiQdP8 zxfJ5zxiNF6h%qEy6m2+A;r=d_a<^7l@OPGK)@0m>+nTSuxr zK9K$68PT6kW?z)ghruP%Cn=9es`sTol0O87M@#t`sefCd=`7W&blc<7tE1k34TBXK zsb8?@fSYt}!DfQA?Y=eErHv-FqFfbQsj)v|vD@dHS7@P}3boV-<0_yAt?3mLK4`71C}-(GSo8Gm9e2E|CgB9y zQoVenEnSe->I&bn)hw@B#@#shKp47n39}(zPLy22tnO|cmRfC4&lRXh7gWa6(&#a^ z{^8hCOqgX5@r44S#8NoQqLD>Rm^}frk8=^+{2dM8`g8MUiSuTcC0)Bt#hT%UwZIJ< zuwU(k8nfD}F@F|mM_gig<6fbBY!7E&G|^6`HW_q=#Lb2{K54TPxNkkoMwtpR(&7@p zh2KfW?*Mc@Ku3Rs>T!+3mis9@3ceum-qg%7bO&pezBach;`EGeXJHsmInEkg_xI3- zCTu~lX!X7)mj!l`(n(lVakR{&h#Y#&y70SAY8tmz9slZF!cE;u5=V_vSMMe7#y56r zx3*5*`a$CRuWkGt{fk^rlRinCF)^}v3gf_!y``urZtY6N(gLXWI9F`-X3p6g3wiHu zt=Xb*=5IAEn!|G=u%SnsF2si$A#wQXgpH7=Xtd6L?%hHfh&DMQz{G{=Y8KJL&yIhs zrDQgr1Vfn~(>nqHspr`s&{fg&u*r(h3KjzYtChPQ#Fz=cghZ?1gW%ryi%-LFEN8u4 z_0>;zz{?|;Yu)J~l5Ad6#NXi6-$|A=FNuxGiAxx$-mLYl54J45Q(ShJEO1-%?;)t4 ztenG-cW2%So5AL~D|& zhtnsin{rFkBrgg4wmE&Ha~@P6z)gKrM0=j9TE)(K9b z_PkjO``GQjc(z}))tWfhT)wF6M@9K|t0JT9VMWta-PFV#Q{(utI~K+BO11{46{6UQ z{5X39Hq>%*qnT_BuDPN1Dp}DSTw$nQqj~a%rBGsJ@>YZvv#Ptkme!WgWVt;_*X@OO zon^lYAMPuIdYiVetYyfgEh@7OA!(ePlq#5h9G;g&4}_ctx;3Feb139&@BYQJO0@%j~=drZFxH%7+bNpRXWdK1rwqH)K!(GkV0=ja$7-`ULguFdO%DZUp57% zS@Nu%`!y^bGklljLfRG8bBd@VCEn3F=$Id0lz|=Tdf=mS1=ODH_gN5Yw{JJg>hrF` zE7vh|KupO~fFhE5==+-Y;1Crzs-EV$0)*>&pDpTBP8DDDq^t0h^hC9aU$)WJbzHiH zxO@NR!WBf`R+jzpTUDO~nFgSWfg{q9{!UN0sWGr3++;QVLIu;AnM3^8eyhL$lqK@s zI=?fw`c$Ptujw4Cj)+QJE@jX;05q}(^AmxAm~KL0Y+o$TG2pRwL~{VbT&pAc0yt~q zD8P=x)}=|a6Fym3ks6pnnvy!pp`Bai4_~)B)Co0{KiWOOovP+8Ri}Al%XH&Xdk65I zUU!z6B=C$Eapvul3I`-ELERYqaZBHGnrtW)?Um}Gdcyg?w*5U;b!~d{lO+RbOHpeGz&3y`{`u!WXWys-sG?GITP?sV0$6c7^b& zWoikI;8C8lEb8)hXjTcuM)$7c%cynNqs57EL2}FEPiSj7p6qPU8E(|sN8Qs9>$zER zacV7}bj#DvcZU*CMz3l-1WLZA^B5ndl~c9w9EyDB`C{bflL~*7Jd+QpjU4&?+5u+k z53+npM#}uwkMDXTlYJL+=QK{x(_3cIFe7zz_ancYSp|$uWc!udQ+n8Sx+ZGN@|J9f zX7f{{l%Qm7`g+Jc;BNcdAk!yFVffBg%;`WeM}oMgw&J%4aBl9+f_Ys)#%mH+#_Sau z;|kjw`39e2_lm`_XWUG&3ceUpJHLgZSVqempY49_=GNw0cHc7IxPDMvuif23b9ipO zAl|Kw-9i(1?rs4XB~^c{=dkcWf@nJ~X-Oz{XL8k#7U2`b!71ag+U^T{QrGRIZ0VS2 zExLk}QoOs&GdkNRzIiw^Te(}ysiqSzYR%-jroctVExTXk>WyUGLxYWRDXCw?(;xR? zY%DK-XnLAt(V1KRc{Qf>&BO0(i8pl|ju^3rgnf2k_sgSQO&^*%^wGF7(zfA4>+7%1 zd67Z(_Yv$pD(yr`DkU-R(x$?=>$?)fZSjd-Veya#Z33rARgnCn>vtb|n~1PYf;mWZ z$D#WR{JsqvV*HC`-XLS_q|iToh-}7Jr8dxwpj}6OES$rG^dw6IJi&t3-InBO;IfAc zG-hjX0L<=o7nsa(oGXTz7gq zhc6l@58lFoa?ROPuK6FT6CA30b`L1YWM!&1sdpgu(g0K=*|N!|69;1#$9gr{6IOWb z*`7a7RvIN`MmW{2>YN%*G&2eDCSZhaTj8At2y_raWo2(FQHN}nO`Smglyc-S zDgc&{!{a1Ux(6|Smcyl|U6*Ur&_@H?UVRf#Mw6h{y``9?yk~uy)({f+k2iG;;_{t& zyQyP*XI6NvgDF3DP6}H`Q^#nN$4N}NeJl9@-3gs6?3ze4-9T&jon2faH>pcWRT7T64twbi)|xiL>X z1b7oRx1(68j7Ks^fKHW9?^YDruASSI%`5b4Md#dZujv5A8aFwAS-h6!ur#nv22FAq zm_S?Pyc6ZTFUomKhVzz0^BPRfdB}V7f90j42w4f7&;a;)d75C>Cky6KW*nner=nbA z1Eh#}l55+lO`HI~L&a{ZH52f%qkVjZ*W)`4S(AsOpWN0=hcyG=Jlb!IW5AepHW=)| z;;{ps#F_TnbWYt{69~R)Md21vEJ*Q~kMhLbJl>$)YIPTKA?kGaAg&_k|HfKbVy&F( z|CBcF(KlB9(!a;xubc<@r<%r{*q81lVP!KF4q+Q>;fpqVBE5@;ZOx6eP186SH z?$#Ac?a(<8s7AMsAqA7e-AT%tFo3xN8cuCx>a-AMLm}ED>$x!z_fTSYSi67q?uLVV z5_Jjugak0>bs{}W`tORmdt%@pyMoE1IIpvBm+NbHDPdk2TCmnQBNQHSMSz~u!GyvD zWhN@^TozV0t*OnmTYivYE0b1&&_t>Q#l?(-aZ5(=Vpj^RgRqFQTxIn}McJ7#U=wiJ zab+z;Z`QRdTiQcq|I(}>-Zwj{S89B9iatnsK&G6OH@R-UR5X^!jEvPcy_-}UWB5SB zKLkJN?_00}*p~mS_^m!5)uT`mUGQvnfk^!uN zq*t3Z+*lhAYZmtsS34G5LK$#w{cy1UbXkUL$084Iv8_5b|{{!jnKPN<(-oAs2xc zJ-LaHU3U_)dMd~lI3+AMf{&aG>@^WWC4VI3I4ZKYn2Wc@Ob9qhY7}lw`TP zciT%RYrs-^n4b>1{EbW@UGKL|_uEqZwy}O&YKv`hi;ZuwCA8Q^i#CO5Q;If~Xw$iE zx4Ug=Zre?6+szK!EQf8j!&d09c~*VBs`9-T-%Br!+1RnsR=j#0j)v|0-}xn8+f=V@ zn%8!x*Y;bl?Jr*2X0PoHuWg6d_L0~2Z?Em7*Y=&)cF}7Kx7y~n+7`6hmbcm-Zndp# zwf(Wx_H?W5nO0kOtF5Qi_F1d#bF1w>t8JmxR%^BW-fDZ?Y71CxyR5d(#>&Z!m9t8> zORiR?&wMYx!EY<^+vfRgResxpep|lZR^YcS^4k{sZB2gLCco_^zwKqeZHwRby5F|l zZ+qKs+v&G`=(ip5+m8Be$Njbwe%rTx+gZQug5UO|-!|yC4Yk;^TWmQkwz3x6BQ3T+ zwb-6*vF&fM{Zq7Mh_;EM?bo91QPEZ}+Pd78sgBB<*F7UOR%%K&NUmokcctj4%vkq4 zVhp8ClIwZIOm|e~3QtOwCnRfSiddOuf&9duq~<52mdYE&O1-sGCp;}}W8U7S=06}Z z+gdrZwK7SpynS1}RO6GpmD<+INi|R4Woq63O8(06b*u3-$@2Ih*fjqpwq2<_CUwOV z%TkFi$84M8*Yo3eRl}0i&WY=tE7yDT@AKx@dh_Rt`OC%p5;4C@%+D9|7me%;Y`%#X zO-x}8*WSH8N0~4%0A9n6^cW^()jT9M!a|UGCsc1M-0k7iu2^sTQ0k>P zoi(PmA4F>Zb5DF~oA24d z)gO^^lz&t}*)Uqx+j3cIhc!<1HA@I3haE3-P;!t;&b% zuaAQu!HvSlQs2Px0jZ(CJ$RshHIahntH#%V0>%^SR6+ojUqLvzPSSwm9d%wb-wxv+ z@MyxXFo+EUVgm%oE}AM)CluNbM>7nt)D(K3Y04QB75uO3yQQ?U89M7(1!fD`KfgX5 zF>V9~$172zV|Z9iRTH#g1AJYXs%`{@Qmh&eYdgH5{({6$PCK~-1N1JqH(fi}T-*1A z?=WBa@lDP=lk=XYQ1fvFGc?tz?`tKlpo^7xUjw&h zrpRHTD9mz?CXp0#?G^Gwv$x}F!y2&SeGM9StfCQo#&ePnwgl%W=&xDPDvqfI(qG99 zh|&RFf51`!_3DAbxmJgQK!&n$CtNPV;J{3gUFeXlW&AESFWBjfj@i~DoiXlfZ|BL`n9u=d=&0tv zkQvTv4)y%v*&z;|YZjfWg(ZbrlHeaDiT}8f_J+{tEe_D$ZZbn7PHHBSVE_cX(DK6X z!6%QX(O$MhVcMKAT~J20l%cg|lS1Lxr7{i^#n@VkNYltj3Gz`EHNZCKYPr0`h7q`jp;2>Bb1db zb(fj&v^TwF*yceCUyle!`b*9Q3~F*zzQj+(Uorhhh_wc&IU;6hX`FzWX48wWTpC6Ib_EtXcev_mvMp|q73xJy;ZNT0uUl3w{@ zt6V1Jvs|3}Ir+H(@|u{3$cUHTeynEhW!Lv?mg4BrR4#Mb{e+b~u~7?+?&;@1<=~bq zqdePZ6U1S1HrX(dkZS1ZIWIs)6u)x(%!BydMa)OaHRh7lrI#f4=6rq}RB1p3VO~wo z)Lf~Hvz+@(%2BKtW8G!{L>-s-)S4%01g&Zt-3xEbiw|oZc9QzK;@G(#(2NZU4Gr66 zCC=>#tw{)txWP_9cx6I$^>(vNyIGn5^JS3ULF_U{Q~!$HR)=%SHeFN00=hF>2{&o6 zu#wOb%5Dwm-=lv^w6;6xXDn6u7=HAbK>q@2?aU~KJGFy{ez1HZi{~#6jR4|{=}rII z7RP4s)x~6Z#{af>-95dmU5g{4Tu-v4vU2eO*-qwtHg_jvmR2pc?sD?umcc>5)QUuR zGjY5ECuOYOm1FpaOmh^jJG+nzToTa}q;If#InQ75JolP(-qQlsKi=Ct&8=^;X=%~< zqF#SIz73g(X!Q8k?8aZeXLbJ^C0_bHkK^gk`3@{#E5zaPMM#U6>ll6q!U|-XO!h}U zz&}e^g1CjTLbM$oRV5FI4@=vWPDXd%k(W zxMTn^ocIEeLcG8rwfhB-6u5#EoJ_EusR$&Guy6>8`D=DxPn0ju#|Q)OA&bdfUn`g4 zezG7W1#G1AOQ{n|UYDe87o-{`YXLp^UaPa7XM49X^WTv1V=qhoUH8rxcyVXe{eO(T z3tUuX8b5yCGj}+^4B)6S+RWiL#Ede7CTv>F5fBm+CIu`lX4DaHElieF)DB}H7Hu%L zrA6&PiPs9qylica7^sDXY@6E3hU~8CmZetamGl3;Gw9at@ALot{Coz_`<`>&+j%d~ z<@-Dj_Fj6iqz2e^E;cw-g&YsM60TriqXiQ5vj(39UJy{*A{Z|K?1D?4UNY5}Yc>Yl z5{X?xoD#+Z26L|7DPcXU3FFeB-<5y;6LK8gd*8R>9lPs=PKm5lBK5qd2^o5{x~O%A z&$R)6-L8%JD7nR)Wy2gZyl~Y5 z{vJAZ@T9;uF(Yw`n(8i#)mLg31SC^nhHa1U|mg}5{XYj1PsMS zO=Gs+hoN|nAaD*gVI*mJu7>~V&2z|abv5Fz+tq}>zN98k=qtIJfDelU>(OWxx2(-2=We4Jk3VMf!2zsHaxs1^V%>qgZA;SDH0|=N@q3Mr zE0kf}Z*mEAdi0K0M#u2wdY_E-l+Yop91`!_SXS)sn~U7XA3=NkjS1c*9yld#_xy;+ zKJ6RHGue7i!eBiyl9%hB$xib~^*qAFk!Se3sR)5zLYFDfz&?Hr6B=OWnkw7HcuiYU zWJmSzp78c}{9C^9`}JGDnWiut6!U6sOC(?H4uB9E(Fuv-tzsp7uttNT12I$I0!jvD zI+NGjSVe1!_K14HUzpuqgb;=p#e|w0!hSdyuKvL`cNaDYsxG48D-nA5wLw;MWWn&= z%&`bo|9D@&|Jd0yIE@%kA6P(r(p?s*@7`5kH-8@@ByJuhj6@<~9HLnH@u%QRPju2| zEcPVDu&#Skam^=sDng%lG1hYMW=-&BByCh;O+`>rVqHwV9@9N*P-QcGaisFc{g!pX zu?B)O zda=01vJb`!{B*i4;hzNO`rjO%e#9val^Hx`?aE&gL|Yj{V5XfS?QH2zG@{5`ZL1wlwJ%3JOG$2f}U zXxLqA02-Sv!(1o??ZoU(%vuQ)7vFB@HpMq7sdx6yz2Pov?)!S!(RhDqAX%6(g5Bu?)fo63cu z$y2vJ7aF&`SIK=JXGrDRAPnOMARNpg`IJ6xc||-1y@v6*6p89N(o3^KT|8by*3#w} ziv*54#P&*43dos3r%qNMo#(64AtKFz6OWB?+Qa7wX^nHz+H9~{^&`X;lm`<9H1Q|0C^#DM&?&UM zM;tVP0J5%oa&NHAUd@#~KbzBWvh2OxRp&^t2t^N90cW z78eFiiYIh0@$_xTlUB7cbd@x7Ku@q_;j9pm)Cg z&zXn$#W0Mc>XQXv*#~JCXsF6FmLrdT!bP(FHHX;?{p7-D&D;>bSkJC7Sh;8B6&<)s z**`z~=VsP9Kl?;HugkXj*VINcrA2tbvG^0d;F;+;gB>E2=E#R%_e^ z&w3N}pY*Ps@a}(c@8wEhcA_oA(3lC+pAx2f`RPy6hS{Fzx&eXBezuuc`heLc@{1$g=ZcTA z!Y?f47tZ4s-p4PzpIi!O(5Z1qlogZ5}8S2g)y9{3FPRNWuX6|%Z zK|$1hO$-@3YZohWexzu+<+6Q~ch)Xa0j<4a4t$E{{0t*V*&^AElZRp6fen7zMNxFz zz?8>*vU;Ib5uKBKdm48y-~Th;wUG=4rpT+NGNw#*@2u zVoF}+K|*swxtGLVo=TF74(~3B2I2=nB&c8--}eoGjkr_X(VAg#^}>iH(W%M1$LV>$ zhxbRETM|7kd3TiV_2hTHMHb&5%Xh(>YVcCUcP#;9a_(bVh?Cd1X|-jKHtJXVz0uh| z-mrE(J7b;l6MnVtJ6bK@Px!8?(${B59!y)O^ zO1+@G)v6rtRmOwO-$?Ion8l4R9;@M7{nMg^Ruh@TvS`bb`?y7BhVb+bH$K}v}|s?;Zu>ayO(On zQ#8XIskEK046?nrcMys*noD}RfEso)IwuonXKoRgu~udb%ZyVIQbF$<7XW5C(!kk7 zM(asguww}J->q}4PHV80grV7a3;0Dz#sw^&q-|7KNHHk3p9CXmi&n5(xD`6*AG0OM4uGMH=!qu3xw9`t{J9puiD^7Dv~D74;Bz6w4PiC~QjdIp1e8RW~6JjG+PYOW$0v~QztlU z7r%q$cSw`BUPbbxET6D?(H$&vW|v+Xu1EXLOku#^WpeD`SW{ASJAwxa8h|u|uyeR; zU<*y_ZyL(sOoMN3&9dw{ZigN9oY?*cr&rPp;26|^#wDqL)!=cDGhdvbt2Un3j zblRL}KOFq7vF|(o(BH|>r%w<4Hk|CF`Eb&ilc6A`JB_*_^ERzF{*sWl0OkNfLejjG z?$~?odoX-;0K58w;Z`KRi%Yl8xyQ=X41GGr6_d%u8t&f7N$jkbXV);Jvh-zAs2}*2 zvPo;;&Yj6_A-Pl#Z9CP;jdDsQoTRKwiol`PY{~r-;7uK#OYfnRg^gq@KNNe_Y@{UI zvuk+SAF?`L6i_KT@{!8S?QH!0^5d(!@)olN3C)7!g; ziyw)yyd`o8B$E~i*_LeAFxz5cAF!T2$(v`^?hu{kZC9Rp+{NdPrs?hC$xR}EkGW;# zyM_cR>GS%SJvvUc=atsmJX@D<{q4rz^_GI9U~&n=0?gzW1ruw{RY^BUVu=cI%!IE;mEZ@&l8|niBXALRF0$dDadV-qwHHM0f})JAm0WkcPDc|h?-|d? zE?w2y6*W-!M^`Dim^heFcQ60Z@b`-u&6x(`?nE(gH&(Ay8j>@BLhL^Cld`$x3z1W8 z472FY!@x+dr=$POHE5NoiITDQ`Zbn=YlrKj%f?&Qy#p@-R!Ol?5ao&w102LkdI&}z zyPnJn1l7oK?#CIY>k?WPP<9KB5veNckOhXl`)=)=7I|M{>lY3qGN)!_A%rv9O z%;${Jmh*q+yVS%ZwqyUt?yow3m}UDVEHmMl{Zyf>P0vEJOb03Fj&t-sE&<`rYOh}A z?D*94&+scX+;nIIyMMT5j(FCR}QQ?C1 z?`dZaN4}@40Z|OFSfpeqxHS4YDFpt6%w^PDW31dL>_O%T+fRSSMwIyip85xUYGgB# zJviL$fSEdsvzeegAG9`Bc-nq_^FKJN6)qbRaz2QFOAg&ERtYp$3U^4*^^^BPEZPl9 z`m6O)=;fk<`T(4>pawtgz#h$-Y(}5L8fk6GVE6!8(}8+(rA+k?X=!P{;p2GZlc#8= z?VOmrGsBSIVfFj%yo}3sCMGN;U5gWp_U@Gut3O~6IyjnGAu%9Oi#>x_7bQSIVV6ZK z>sYV?mO&9H(ONGK>Kh13iv6ztJ!~^psk2rBbAj)2sN?cURm<^xXO0X=GNzwpl@cS% z+!NcIO_8QJH{u}>P8!FBWFS!cFVCrlmEAFYHj+d>jFAm;3D8 zPimMM3l2?VW321>DXz>(c225TJOMoMLBBO{E$5HYI))a|FwGp1bK;sg>R`vQeW#CH zI!PT*6$YttFbKMe-m$LPs*ReN1%gAJD?zkjX-WIX8#T^ewbP;AZb~t9Usco`{GiqU zQv`dWGwFF2zBUM%I2Kf#_gErB9`77`u7nGcC*LCs3W=@^Y)w zw5LkYdJS%W62kLPK)UU&}LpH3Fi1Ha({axCp10GIwCO&9n7X!ZA<6Qrdz_Im=w zKXOik#@Q3lx}c~bZjSN#8z98=`s>%eG@EIR^&PriJXY=F#@F4&gsRW??+p|`dyba+ zGA%Wqmf9Tsi+Xc{_1M2N_&$(*r${+p-1Sq>yCMS>zN%9fUi_d`FleT{aMzMDS!=Hz zgV@?TrqmW#7I@aRWD}daUF>v3`y4UuFtp`&YhM~2cN+|Z0EeF#tZ2w*i0L#$qp|hp zJ?k2$l!g1o%x-)oaB3`D*DQ9H&bAs@{?k0cFDJLqrJ((zENOOr>t~mW@BSCXa6U|_ z!v*Xf8^0h-A0A)>*VqN&$=li7=R~6>oG%_4$~bS0i6~AFGe=^=a;s{mOLFT(A2+74 zaZ>JQqB#;9g+Y_Ep6T%fL#sSU3)BmGl;=c{4vn6!-fPYU;l-2xUT@Q_UOR=&eH8D9 zH8x6%RRgUYS+eZ*PJ;&Elml^Q-rtT^6np+=oe-;&m8@ZNmj|n;ohfRqUsjE)8tqgN zum3}c<()IgNadwXOOkJ61cQ9T29uuf0!-j3s4>J`@|a zc^z9fH&|>Qk>!fo*3UaR!umf%NVLuZf;E;gjvp767jrkC5(A?PkPdmaQqtWFwj9F6 zt|OL2vGlw$x-?O#R{YCae%>jE+rxQoAO{%Evzo$7(^dzHXMFZemOVP$Iw66dkZz67 zw0B=HI&0fvdTxi$rU)k<4XV|q{NYyXgml&+(=H@JAkw(duA}eZX}nYWdW<|3k29(w z#lPSHE5l)C=u~c}5=L#8g!fCVx^TqUaYv+Bc61pLH9^pYXT*>{(w!#5BB1k*@ND5; zMb3kWVa6FP_Gkq>DB2aWrik()7z!y)X^cfTR>;e=*y7Ip2&57z1I6llqrO4Xfo5`Zlg4LFPRmGfIuN;N`g#LLLs@B$ltlJR5O^ z64uRqLC*;*LocrQsrsLlb5EF*88()iQy$L-u6ta1XegJ)1Eq^Y6@>5Ydf4-1^0`Mv zCRUlnd>g-mwX(!#M?CA$pOvyP;g@0t z*ewxmbAnlZ>DKx3uFu9?Vc5W!B?)0O+SnerHZ|oXA6u6M9&jMd8YupUieq=(o#=+x2#f*8Von0q zfvugYdgoGGSR{)+5KCTwaZiKL{3%)j9v2rpWC-LGH=p*a(KD?4n^?7MfiPr0z zI>nbZ;FXT&-+sT<=@{cnozFT(@3_oGTMda%6l|aGHjHzAd4jt97%PAIZI7CR&uG&JkyJgwqZ;@5n(ueYG)oC*}5IK`pg=X=$e;l{WzWfOpUqp z4Lzs7^|pRGSbX0oPCYfe)1j-I!??cFa?-9;#p-X_CF8@>;`MgJEozHi_5|rN82SzT zkRkqpA%XY%S%dyI4P4au+hy@qB7m_S?EZdS(_ z=DzLJ5u@9!V>e%Dvzn8vD-)8`uNM0+Pm3~RgS^FV7z;Csx*^!G`IFybdyb1=x3WEd z7ts?TSVPhr7C3DFGb!q!yY=p1Ev-M^bov8j4+V;Q&I4$U;N+2U}OVk#C6=qxDz&2L?o~V8CJ3&rN%#3!nZntO{`yS7}jZ?rqws_IlT)4V{-#Dv7 z$F*@ef?+gMy#8D^EMQKTyur$Mh-j(vGrsFH9n-UZq{;R8wzr`A@a+?MM`EWVX~;3= zg5g$3b_0IaG48@=i5DDkTok^0>M|U5Jud?^$Y|3v;c43SY9a6!?LVXJfj;fOBHV#b zwaF1)|A5C6fLRsCUtdo-<;sAvmY}9vR2J(b?kD>{X?1&L}Z-ft$W)E+Oo5rz* zTgwn6CM$uIw&U}m#-3EzqwHFiDsVC@_8%0Jt^t#5MKRd~=2QRxB57g8DL#cAgBV*V zT~pky2v+UoWNuF4#5=GTcj?`Dr=BputslwCABI=Ih^n=H(x%Ve@}RZOsn-cS?s63E1nCSoyM=fJO>japV$Zn;N=6gFbxC_Tey* z(|hE_w^;ogZ96CID}^i~Rd2OHIw3nvSW?$VT|^U zkJxZx;uP<*IH8(<$43#}KXtF$qZp@uploiSaMGG7oouc`1QTjV;xXZV%CQhV%x_jp zi&qC~mc3P9RZ^}nT~=hWJ=cc;s5IOv7<8@Xq}G)Q-Ia=-OT$=#hPA`i&%&&Z#E`yl zUsy-c)5FD1Vx(Ge*5v7^8P>x9@D75ot6nBIZIlAIK{!{8*{?@D^c0B1Luk53Dq z3s(;d(|X63@wztHtL88O&e)S@YcnAYqoeS7H5tu;d;kR|K}hFVSPmG+mIl6Y!z zIan6ZCPnz(`dpF1=31H7mQ)2czBH!gnCN_o;lmi;n_IL)VM|_5hF#>c>0hiG`yb=V z`OHf<%ql+>$=0_}VULR0?N7j?Vbj0(2sUarY%_oHD4e>#Mjz!3Ovu!-w)(uYnK6`{ z2bKzxp=jLOLgH&MA`F2GEW1Qu@oW9?$}x%d%P{M_W!8BJl}J)BnNJ~zNJ21YrWrL` z#L6wSpVrnA$2PHPoA`C(ovkl1Q(n&K9Lrq1!^+BmjD}s=MK~MFW2|zrYdR~>X4qUt zfZ^xc^)qmSSeUqb?YV@q=1k8-razb2x8nVwQpWL;=xr_WmN5OrOim4T`PY%x-kIv@ z{HptV#O=Dz$8OU9QZ2uP2{v~M>d`7kI3bs6=!c11Cji|LL_|FF z3X)cnN0>;HSWEoul>f5RCN*y=vsk7d`-e4fwODe}vMp5f_rY=hLDcU5cmI6G@LM2= zNp3K&O|-sUfG!vbHE4C6$8a+XgG2n$TfZD)jIY5dl1%!NV}V#%D%O;U=yXp|Fo}_= z`w(+iS{kH#r@=SXn}>=H+EupRsc`u=0p{70IQ7~eN7??iH`C&jMsdkyg;MPw!YUrs zyR)Or3>a2OW#Lh#CV#J2`KI@v2t2LV!H{coP&Sa3yWecw*y!KrZ~c<^juYRZr#EUg z{)zld?;15Zhh$qU*Oqm>{8ndpiDLN#3&89XsJx?%HrMdMUQW#lDLfeV9l?xb@rLDX za6%f=->f|~Y%_o9n0*dJ9XvOowb3}stSctnG-~6i&=?+qI2iT6m2ap$c&W;AVz-g& zZOt&4Ih*bMoa5i8aI$93$mP6(jhVsvV(9uZeDXGVfwGaUZx1*1yp39x za6dr!0CRTSLj5J2XWu+zIQZaMmX3Jt{g@z=xN&RGNzD=RQl{7{wdG^_vmz7EdfKB8bA!|&fFrL@C_XJ~I(epBBF9A{Hb^A#;3 z;{5Rn!1H`GBU^ISa^ZW!p38LU=Fm@rQMTyc68tPD>;B{t0xP|GowQxyCobe78ZOxO ziPIQzJAID$uk`>p5mdg_N6~3;2Fe z)c*N;Sd5&$Ug;N|beaJFDEo0el0|3FiYP zFQ{jxJNa0*-vjE+>5T1>GBtmC)2rN85SBDX>EmOu%lVwKc8Np)E;Gm?3HBAhu67Dv zhV;!6DQ>zYtXue7VPR}pS*%kSunQ*yi99Q7ks$m%_>`Qn{f!>$L)0H6b!(;~0}_^p zqiQ2_@{)+iC|T3>$+1R*umgIVZuM|)|Ix^B!(BV9rpdN<--YjP)-<`nnXHyZfZv{M z1hsI?V5-yQ47$}7#p_R7>;+%_XG~1c*NMNQ%KpJK7HR`Q5jND;sTM9MOtGkt*R8Pr zowdePa|fp=Q!LZ|WovEsxYcXDY;HQ^JaDaY^1reQshi)*pN<0O24=8KwuW61d*1i1 z?Tly{vm=X9BU$2%w8wwqxU*yPBeF7R#8$*EafZ9&KRM^o?_SM%SH$`vm{$M5=8a_L z01enGJ1ce~yw8L`!vZN@roU@_^77GZD`HvhgiUkErIuM7$8rf{4_pTs=Qd5Q`Mp@K zFmsUjlr7XRRdjy?NQo~(a?CJgsjhXxpA8pJ9DO_n9nuG@K5e;ag=JXS5zJQSUKX<$ zJ$fMT!@iyky(Wd=2Yq|ckvS{5&Q|{bA808>EL+3#x2C1FXI8Fuk2WowDqPfy7t@GY zQm{YMaWPAo;^=|2LpIMr)o336D@@KoGUH7wKR!PqXv(vC!Fe)R#hHIHn@7j>Wi8_IOa9p`jRrn zq&l!wy2WweHr17O*h$SE?3#HpuJ>s3wqIMG0KraWGr;{^wq+Jk_~`)4O0e||BsWTC z#-|i@MGR_trCj6%zXzd(*O0*;GzWHTc|}h=F!;bbh4&in%NC?cv?(jAL$PRFn-21X zFWpYX$vD2uvuN#W%5yL3eKSs?oCEx+xbGCN?fx(93?oSw@jPejGpX*0qmlmbfFGkx~Y0^d2d4@R0rynRay8uB0@R?!U@y zqvgi+-YD7RzFBs1^I!1huG`I~>i>FY^(3s zJZ+&nBZO#78rJW1%vV#mco!^y7)p~ku3|a&ovBe39daD6+?TQ4p7cIG_!lgze%vf6 zTs3OSBjL8JgI3eS!4v=C!nRQjo15BpdQA_5uJ^8Zxbhp(%1;(}Ys0pa^+!8R4-dYl z?_BXPciYKR;)yxl@lV1sW5P5i`(1e7(3Xe*`w*4#iVUh-(lt?DK_k)?R#vU zvxsjNOCH~Waf8DO8!Q`?MX-JA8vj(+teDd^frGZLS+NHl$3jRITNkZGr9m)G>_nbU zTbW?Un*BC9Oq`b+V_lqi9EsT*>@O;AxtDccVl$09-^~&(A8jzp@+SS9|e)#&7fgas0Awj9)E6Eryt22D~!nJf#b5 zT2=wTjMguQZ5=C>KvYAAy9j`Ky%h()bo0W2hHL%<9Krk4>9*X}O zWF3+rhrG)nJzfMgfb6VP8%;4hnFej+C^ONm;a;T%I|Zh79J`13x7ZNc zrQ_Qjy0CiU9w$lNu#vd)fG3nxk+O0d)F0fV8AP`>6$PGnz&=iDpUw*7q`xk2$WLsG zPq_=je0tRp(>A-FWXviZRi!Gl2P!;s?A@mUbha0U`;+xs#`{ZCMGw-4EOfOz181F92Qy<(wc{PLq$ca_!RS6xlpM*F|Ph8P$lQ)bj&4<|zylDih9#!dQn&-=+UXrr4?IR$t{fhyrHG z%!J&t9dBjmlrg-2n*ah6>h>2VCjY_Yggx5rNp42+t-{MlPweqAvJ*>N{w)fO!p_J& z*;IVKIaXG53L^6ur!KrI=CPV@T^>c#u{$Xa-JAz5@t>#cN1uGyJh62 zfu`Ubr|Doz5a(yC!HXy(?pIHZrYWig5AI_WGaRA}&r0|%gpkllNeq1=^-jJw7tVx) zf*cY?Gj=@3aydg0By2)kr-B33kVLm z-6898s4nk2-g2fxRdbd#r5%gD5FLJO++oR=;`V8om6_ay&&KrqF0fh;U^#|j{+h>Z zq-85=Fuo>?Q`--ZnO7~$ml=8MIE{6_r2lY2?VRh!3%IaO{{UYgGZk0aASh%Dq}~H3 z*3Dm?#L7Qs`u-T;_y~|^+^7skfuszQn)R5d^qMW}}= zijpr=MN#mTSn4@|zG9Wic&VfxuV70W(DQf&x+R{9=aDqrayj```pVoVCS^9u|NQ^d zvX!BhHOsuxFrQTAp$CB8JO4H~HV;<$e;E+*(orZAM(udF>2F&g(9b8@dH*n4GAgSK z3#85f)nh%8y?ripSzK5i!A!!}>3Ld&^?mZ;ifWm5?co2*P~-%4W}_PZ+HX=9FBlM3 zs8Ng@2)f|Rkjku536C)esVOifznmFUpr$|rwf{P9H))D%kK^UKM@47%{^Fiv!U|1K znP@t?I&qZgScy@Fdp+|-Uw2=z>S+GA^83X8?k|cLd=aiMX1}mXS$hjZoeIpC*4-<% z<(N**W#x9UZL#{)BW%xX6nVM$#lPe?IGeaYe=^&!=w>BOme?VAb_Fe9+5cF;mL=+EL|ZB!zf|-1 zrPa~n)<&l^eLmcBL3}AXVRN*^1Wa*5I`_BE=?v$LIHz4Ba&~??Bd4ff)I;^lRw@!e z+y*BLkSY;SM@aRGI`CbC(15}O{gmi%2fV;JE-i@;TOADtNwk%r5}2qR41NSZ7C#Ao zQv76)oBZF}J*D!3SaU&K9UZ?mdScUgvE@A4ecR^f)Q)rF?whUeM~iQ?eva_#*3&ki z2T;xb-`jswtUN0IZ~L36%>|rz45}P<8>8%RE>zj9jDp808l2%+?|Qu@DOzooft-8s zTm&4EI)bdxH1e$8$q;T*(f8uKA|c1)?76a3)BR5@lyaL=Q&q$UuJALScFQB2atg?R zPzSE;-Y=VHSz4*m6ncJKvL`jemX_%Mh6jr8B-oGgN|y1KS{l?YwKSuMpYBy^;&QSI zR{;)_dtPi)FXUuZHa0L^;qvo6YPUSfDUZBauvUF>Y2`di3Un8RjXy5Q#EBuomy0V} zwWo-?t#xKiorEzOa!!gaUT!Sn(paIUyt33{1bS;Gj~e18rxmX1Ig6?(7c2GAzx$E3^G3^x9gj!oQCB5P3%8> zjg9io?4<+4^0U2h-{HUq;m|g2HW%4{co^DR9=hA!8!h@#rO{6Nxm+_?_~Vkvto%!A znKFQpP;fKcvumKvMEV5ALCTeSXV=W^Mft%Z5#keq-ac{FpDC>klw^5KR}B1ksmQY4 zuHG?ay@9UY(-%!))fa9;R^4(U_lN-Y2JYrbo-jqZxS=Q{8`a?5l@h-{6)q?gB**%S@9#YrcT(%uHcMeJb~gi?j7}-jS#S%6befd!9Ro=Cqx5MEDNV;B?GC2DznOk0nEpm& zr3_mTgJ8zIl;I1aVYXp~pO^v-d<5I2jJ-e&NQG0%I18e32SZJYl>c3PYE`iB==t|; z_%ro}hj$NO2PE}W4^Fm;Kv!!XVtUkcT%h5r z?jIpy5pm?2$jTLLHuWrEmOgts`khT%irIS+cW$Y>1a}_R9@@h@X+EYBP17F!CYb)| zX8QJE`aIr>k)xmTX!!qSHEotDsL zPN;)EK(EhPBx4Pb5A!r3)tZ!o4zcWeCzYB;|MV!NURqA_ON?7Z{VHsMV4G|HC011Y z2vB~-?Q1d(wYLzhTiUfU0b59<%)`L$mcUPJWX|+!)7TyTTyDLA^E7WU`nItCT{gde zPT6~Uf6#BlR@P^>_Nr8ZIikA=>~jR$+m8(mf}qni%A()`si|(`wAKGku~fk=^`4Rp zg@2|RMx`hs?RFbi2P(N-=8jcx2?`iT&+!g}fTnM@meG zVk;-xK#ij7RbYhoE`MBL)dMe6VwLcos>sSA{J%#9ykcR{bH-kk-@h|!o2H|j-l$ihi$JX7vg)NO#X8m6uj%;f z!iP-kjE7=av(=@J00(Y0NNRV(im0wl%uz_SUTCN#Iqa2O8D_K1&{k^U6pz(96WrEr zL^QB2ayN8=N6;HBbuYuO8zL218ro2WZFF14dh4PBh=DL*V=?3AX%1Pa2|;GfnWE#i zvx)&0{yZnC*@%OeYRq!4IbmI83OP92Q$d6RrXtVcT4U9wajw_}Gfi9q5E}&qtLmZ6 znAY2|uVm~a%jq?wD7}=EEvE^r%ic7>oS0uZ(?nf2LDN}4h$HkIeTzImuY+%(fct3z zrk(Ri^R)WPDool&`{+C47CTGs49wNo=Z7o*=!;}7ITTBiy53-pG2Dc{_BnlD*aipm ze(*=Y6Zz+~@3IAM&QzfLPafZN%r+GHRm-qK)x_mEiLTyHCv7pRuFlx`(~8v%D7 z$@!-Q69$tg=c~)mmT_#yA2z{fd;^>6ZUrWUXJM|fLhhj@G90k^X^}qEM(s~tai-UVWdGp?-rSj@yq1Wcgg>ez)DD6Kb8=5z$ zR-c)YreD=P?JB=QQQIfcx2%Ab4rOI<*Q>ig z=L!9D8b9%zC<^{ah(iDx?sCY_G+pjEUUQwrSProV4@;D+%9au1`Hp1744$??l-1l8 z!0b0V&WS;EaB0l4>~H4IixK7nIP4mKi;pmhrLhQ~5zhGMFmjuR(fdJKZqsiK&u;{#^7=h7zWHIoCztYLIzJh9 zqvW-GHk@_9FCEKfOW15Fn=RX5Zq>+JXEGtdredj?pBOvCnViuKhtLZvGIV*=myaNg zryvEv|E2(Wr^%zJL49^mfUvTML3 zges}~TAUWaEjr6`ah*AY@A;O@qC>abVyxsAZRbfoO-&;-MeU7pX)>ePB+HQa{GKHb zhm}_XWC!`5kW0#2v~5w!W~G`_Fw#UggYI)RHm8BR;OsbLgurz;TN&~8#yNpcW@j)? z`TY$pPFYxi^+gS$AS|wgDzC4zu@S=g=?outXIyLR{dYRvdjm10N-G0`MwlC}eNEXf zBLytvBKW@Q~zCC$b( z6bq`FA9qij)wKt|N@>|rT(E`e!Sl**G1`pU;< zs$Dr|NaaIPP$0cbZwLbQz*_n+7eC_>;FB;tN*{$Ipo6zSIHbztu|+GO8~DK<-=nAs#7!c|67?J1x{W~JB~(!0M$ z2HK*%m&y5FxkD3I!8Tf;XvHj>(vBKL$&p7Cns@KKD^lVX8e*+I4TUF(+uA|4zQM^1)u6#9* zS-r??j^M_edD2I+TDd1%vy{x(EO@h8m({%paefXSId<~&dF8&4u#4&001!FT{rMIB zke)TGzy>oqg^?|K{dF#;bS@`#CR*)@vEi<=>1$>zmQ`fyAtOkBBy6=)VUnYjNIBnN zHZPWqT(>Z5oyxBP0SVp;#nbjf#-sKyOke@*(x_G1@qL$1o;h-;L)CH^$QK;`T1LeK zF`A%Tt7?L4yOw#P_mj^reEd0(uI&DE+P+BZ{y}ZJ%HG?j9Tn;I`#lW-?Vedae|uwd zKs)a@`W*r7EwgjO86k$zsxyzNwTCk>@q)9C$%a!R&&&6j$$h2E<^tyM(PCL7=322} zXns@qDmPt;z=Sg@*j&OeIWmwQ<_Or;<-BwiBnM7q*}Nxb0j*+=bVfbt%u?1a7XQnl zjaRN>m5XkJU5r zUUuSr#eeyMqtQQqQKs}24~o<&QKS$mQfi$z`#&$T6Ytlmf0Los?$5l@T=2<5bkvsh(Q3Q_9usq~E6EOqsbHA}(XMNs#)k+u5a&~0FU zfwIBhDUDHscj~*jVcr2t-yA(2L)#nDYu`nQwBhIIV${CC1XrVMjx2@b)hJ_y*f3}) zod#v$91k><_Tuo49h*3H{i{urzN#8yoQ+la*qFRmxkoZ$tL0#bKn-WcQsPa&UP%{6 zdDBhpBooq3GWDTKxFQ?l-QaJgIy&_i1s@@3>JqbzYOM z-eDJ)p7+|robsoHgz*498hmNc8L=Jrda~t1tL-2dv z*AU24k8G_uQ}8j5*C@vcWKJAc6ciklI`Kv{*4kkKQ^RBxnCs^pf43M|8Cr8oM3QE)eqv zCsj}8e;$(UqYriNHjHZ3}F+2OsiH9r z4U``TfyA?88mz8pSwnnK9|6fG!+4YoW2=50Oxop|OpD4!o!%TOIys{iQlZE{AJMf2 zBL-p<>Erz=2DYEDfv4FOlkL(~g7guHzq13UR!Q$zL_ZmfpzdjVS|)rHBp2W$V;;6H zMIEf}u~WBeL-awqb~}U4f<&lT8Y5T`ZoJN{mVVmK^;H*+2kPi{n8u(Qq)^9=C+C?vp)|}wd)9=AEm^oiJLo*beAL24)ioe5{I5*@y->=nAh1xCWRDdodtAQ0)n1nvXo&s zHt@eHti63F`CuUHJxU~P2n$g+xU907@jd2)M5-^^80I~gzEZi4$o@9WniKMxD|Zf* zO3PyrXtTnlMxaf~t?J}up;(+a0;F5ws#(xmoLdjBHI6ej-TKBB8ZgqA;@J~cJ*0n6 zy*I3?dE>Hj1=x+Hio9k{St@mWvlk_zxL*{s`X5qO9nqV%uDXXXkkxeyS5m5L|B6HO zJ8-B(7wLQooD6I#yv>Kpu00$REK^O_I#{~y1?lhg$$ zzQY^u7X1{!<*&a(+5dir`TzSJ=vNT@0elAA&CgKVHC!Er4`FOBvJYgidC_U@b0DjM z#5F&9L$gkbPfca62%N*#kL4mE3E>`x_;KCX%0Iu(CDqdp;ZF8!P*(rjzfrwWS=#(q zc^;(_^JSFvU;PhxLt1dq&r}EH(5omBmWpwgeZXojVBBSUFXet90?++BDl0n!P1%X-tRyXqpD_ZR3^9oT8HZ>lc>AmkrCG@6m!;-V`gIDyppN;zS)NHU^%qn;zDP;Vr7PgO`Mye+Ep~>VQ zE%-u^{z$l|$soNpZ1nTdPx14mh+$?CEzA5Iv%MgH99zI;Jj~CR?fxOpw%G6VW51o_ zv@s2>KI^2NsAfloC+mUTCk&@ zs*v8Hr$k08r_}ATUHl`b@FmOvqtqH=l)~7A5+Pw*@wFHBp)h*$UMMLp|h-;~e zy6V~%Q;N1&s;=O|Qmd=rf?Eo55!(5G&IAzM{qFyHemoD&T+V&YdCz;^%jfmJud_>4 z2;*JhtGeyBd!zisy6T#8Lv@Ll(cYW)QXV7{$t!~ymla_%-;&GN1R!z@=$K_meiSkX zC(IXa|9FL`nT5$-@_?Pm|7GW!{95tm_vljn$gJ%=w!Jdz&ot2*RQ9_peQUy}Wk&zyH2Ov)T;YS5RD- zajr3^)ncuMVeddASZhrXS2G42OmwD0ch@DyXelA)wVjz&X$<&51XyEs)*dO_Jb)hq zGPDJv-8IX~xuwoB`wirPQfciT$iWV^M#TnK@-2PDk0+mmfi+=YX#KbBwlBhku=p8?XCx`3_7R>LUDRkd z-sVbz6nVJh%!F79^kGI8<+ry_Z57DpO1VZw3lA{(#ugu}qSkk8!7t7gNV2O>dKIzOnfXlM`54-Rv7D`Lf);@xDahMFE!$5pdY+ zjYU1!GpYB_RVzA9{d4OpF0 zvF$iBj&Ha*D|Q!R(chO2Y^O@DO5DQXBZbxYDN--Dmi(-X~1|IdF%ume#JRl7Yn z->Y;&(??HFA+0WG4CbeZZ3QHo&L^A%4m@4mz>fgd1Ug|PkT=0}*%r1)Vdy!Ea@X-= zVG}(Sl4F>#BLf`nF)`I-B)w7mJux)~wpvLBeQ=$%WE}c1Z<5qi{K&m|(Ck{KtxFxL zNgb~Q1*@F3&$IYtd@{vFkn-$qA27w0emioTtQGW~IN~Xs59!71r|`xzsj2v0`dk`G zBfij!d!DjxeHv?U_ENl8#+YT*F=bk^;c3>gl(vRMKM1&{bKs(_e|nl%BefzBv{qlw z$`oxA>|O8!x8oNZm2G>uJG=x1QiBzU**AWXo_tsHU7b1IlC;hW8yxjik^J)+RDf7c zu=&Agd_nJk4WRKK1zN%T-uadO`Tpzj`r=hzD9sZ`jgqzr1iJ_vy4dY-|T_@Fi#^K0js-%er=>^Yt{j^%FVm4rMIr z=xuNeW373{rkcSsF|&VPaEEUa62B~|J5#64AYW1E50-y9o$R#;rFXcwj@aoX-w*J% z_m^xOAncRFlYFNOQEyfoHw#;?1m+w3 zuKfMq>AMcA>-cqiY{yIM>Ris?a^^(*iMT=c0UVK=hGXcBv2US27M`NoT{N^!X%{QH zUItQ%^^Rv~r6ZmeHpp37-!nLYWLa%UwU4H1>7X_nUO$^%$tZMQ5TSZYTC&f^y-^fM|8YM5(~ z@zC5cE7ayC7sPNM0Dm`iafHxfHuIZxG4l>_hsi36VUB*YaEh<(Qa;d7oM3GBeC}f+ zT<#~|({CsMIpHk5_;Jj-ur3j=4NKGJQAbs1C#_A7cYX1|w!>FW+)nan^7&_lNpxni z*W&LW`c9;SINv2gJ&K2|2U{-&K4<&60xkA^$5cmY>{TZle!jJHuRDN0Oxp*8yN7*GE;q{_s9UGP{ zwiij@R^soI zfP5A18T8dbq2f5ewCozVYX$6DKU*KL>nbY7H9kr;0)DBUAH1eGU{{x(3fQ@KMsB~O zcIR!Gd}wrHGU7s8LiZ*{gg)VS$62->#X%~cU5q0di)^OWN-Al^8g^&s&EJzsN3DMp zfd0Ls5|g!%Tf$P9)AtEQ$N981#Rx$dN>-u4ljn_Xnp+FXL9!{01DNX6>6(sXcmUezTkvV*o3zCBC9!z9LOvB~7wQctJ+Q=@ObY%{YlK zAmj=9-9V!1WNAl;JWlUCNwxgg@_gauK>(3_UCh-N?+%k_ARSLgi^;n0Pr4j4N#XF+o|Y!W{;6AHI-`q66H!}^kTL>HnN zuTnjTxi8C`M>F>2>L)-S!_A%q7c1@9&w5PVo`Id7#M4~B1J_x<$6&ojCb!Y5+ade~ zh<4)c#^eTT83y7Y$)nHHue9}IXzs?7j_8y8TNqnrV)AR`R{DNwhD|WSY-lW*NN>}& z1rI@u3JCN>PIQgK8hj}OnoR5nmI^fFi zyT)|SO!Cf5HnRlSg@t6ySm!X)38J;OfJgvaU(Ad%i}aP$WU=jIok=F>Q}=XzWvT8; zweUW}5Z}#ae)?T)Eh@(RYjx`Isi`*?`hKnA?YcHzPf92WIKo%H^^X-hp7IX5E0p%z zB;NsDbNO$*GwveA^lh_{&?zK#3jEXbeo5 z8JumgUQJCkq6dhvCf1YC>lxJTF*kb>J3Rvdw|nTBe{_qwUQvDG=H7UQ)jw4wlb(y# zwnptbks&sQHHT8ovr{wUBA;K9cy+JGIN78Iqr8FX6$}?|D($;?llgTmn`tl?XqbfXt+9C}kBrvVx-*j`hD_ctZA=!q?FICx zB%~I`_h)~B33HUHXRd^(%^843+=2m!rtS^A^nSQ15AL~E?wH)70l)u$z5cuG`ExCq z{uHc{M9X4t3t;qynwt@qj;WrF00An7-2Rl`vckM+;O5#oeV%#9z`76m%zsI|bO^|W z>1VhevSROZeXPGVaK+v58O*2}#$=tk)(4dkw;XtI@JoR&|4s5-kzyj|PE)sD8@^C0YfS?&DlFm#`8hIQXDLb^kY8sX7)4`e-m zeb%d4Zr(_Q`=fn(fcC8|BXdQ&*VJ#%my>1pT~2!^ijh zqP{~6OQNZEnzpvq08g+9>v=FL7`-{Pr0P(T+|#qr_lr-VXJFA&CFkv0o^2KqJB5MW zg1J{1#0m+frV99Mee?sOwUSrpz*zsW)iy$H8(}P2$)Lr-6J!;`L>@UQ#cSN*%g}{L zcW8p^Po|n!IFLmuiRP%x_%ZVqmuxyJ)b=TJELZtZ?qmPwEDG+GS1pizhKRP-tISoq zud$@$bF}{H=h23ex+DK*R_;}~<+pU*)qwXyTvWJ7JU*@H&Tu-HG!|lcgw@4{y&3O{ zW%=<%<=oWiqf$wxX7Przc&_jd)jLviwO_Aezn;zdUL64BRz4AGn8^Frg4Uqy%57Uq zC-XzRTnDdBH6w`2fPnK*_T*4*CtOOrTxaSnTxve+OXcU9V(_M5awxB}bh4K_l;ra| z50y@qxI>7=NXehGGoLWNaV#!YPZkS0^gVXai!A(Kgf`AJQQNdG%H8KwUUH;+=nm3~ zxY7WLn-zDlvNOY27!UaJDfG)|J-zddTBaCo6qZh1FsGL~I?Twd+zoWcYS zvjJ^dptaBZ=7>nL38vBK3%R}Uv3i9GwO=+5NvmtWWd6&jYdqZbZK>#cOGA6V`6aX1 z-e(rY)LE==`H?QmLR+(J9-GkFrtWSVEFmEKxfI~UzfF6P8Askyeih`ZM}jZ+@lWJW zW>C=i%sAylfW4J)yZba>;Z#-+)%Deu+{>VJAc%UyVN@{J6r1I5G`}%o1}5PV`B2u@ zK<3{|N=Yaj-=!5c8DjWvUofz~GBqzENE3W;NG+{(>QS^~3%v@KpY)kV>=Cy%jQRV~ zmjJTJl&)tB$B6AC$wTy|^`U2{W@f0#VtSM8wraN)>TM%d*a}nl1mdBREOYa>3SR2= zO7aJqNb>?r)YQ(y6j>U;UQ$>ce5$WA+)A4e{5OH~4*nI`C3Qz?ikg=qpUP7+h>zx^ zJ)BK1ya)UFk)7cW%06A`+(|0qzgB^)77-quuBU=jN>PD}qyFDc;qBEP0qv;5GkWTD0NB$DJ zAm1$RojQ2cA{k$3LWpe{!4!2imMlM-$#-Q7&Q@9T2S70a)&jl_YLZQ}(RPog7qrJ2 zDb6oQvT4-QYJS$L4p};Qh0pB_e`x=Br3Rp{bVw}pT>4m_W){YYjYO0%7pXKmf~SxX z^dgFg_6WBcM$j>L2iL3p4!FImXh?dXk`>}*2TYTK2kH*KBZ4p)1_tFr}LVdJR#*i|DKiBUsb zmM<`H_XGVeT5Ko-E^16%R#hU_a*5U`GQ%NmtDXq0axc~wHE%ev_TqNRc-!frh6yze zE-*4n8y{c1IOVgq_Pp4Xeh5e}ItoyzbZU)$gICFqyOCzE=!*<>L zN6vRUn}0-3eUfeYOs>mJF>n38K_CEPhchXTBes40CHJ3$yaa4Pdhy&jMN~0VP|Q7e zsl>+Re+cJ>219JgcNaDdW#Rso^?=$u`7G43V8&NFN>22=X-r=F1{_nHB1v0> zhvd>^ulR7mz}oYEvC21SC~H}4uKBjqVs?J}`;e^nLB^l)WugUd<#R#h2`j_3KLf`>&LYiuGC^ zFq{8bt~u1d*}Ue(0Oc|E1*TkD+Au zF_fHYy48zvHy+g(5PQP;#$`T`UrASs_`b$HlAuMlNF16JeA1wqC;#lB^9e)CY($?@ zOiQ^v#uX`B`53g^Ur=Ix;Ip)Rv-laR(A=#g;a)LrPu|Mw@IG`K-hWEpe@frqiTY}w zTfklog%PF!D;lA^^;xooH#VoH{)!&&gVnN=2Mr&os0~uKVzpSO{DAeXCWGh=7Wa-5 z%87qCy}hm?vW4{%Hkt9gi=XO|!Yn9&|$X&)%OO4OofNGXHYE9OU`lM&?B8{}J zB@UeK<_{{FaY?v+GaZbeU&fi6ajQu3!WrWfos3_l4Y1QI%EryztoZi7G}bFk4~46| z&4X(;8A1~8S3zo}_Ddyh6+|ZE+|mq5MeO!*l2qEDf=OxpYvUTEJL^q+YM2!PrKa=XnVc6x4_x$+pC4zz5qAhMq1LJsP0$upFcZbp-n zKRq{ z>yF0By9UqV!IL5OjaL{Nu`n%!dHx;Pa_xWa^JZaqr*KoZVCfYEF62C ze$;MumBj1^4El7Y>ko}{cXfJ)>)GMFe|Q{J5rYTK!m5Eg;KAYZ$WkK;_6tct9K^nr zeW!Ldhbd-s$xO}$Qh8P_9vpzP(7lv}C^4zYulu@%p&iCt;W^EB z#x=JOhS>Mk=p2+XQzq_{665%R_OVS^5Wl34TV9h9LSQk*WWT)s1r|HCm}yLPYg28U z8{}vDzoy=76OyBmOtO@Yir;qqt}%K2j1;!zIazpp6V!>rc{fbt6%ZoyLIZo2aL43~ zU+xD!`!?B)?=^jNwaalz%+%|aXX^{B&9giCJ0m&rBp#ZJM4sdPXTivC zKfLEe)5Sy76(6hs@oWOjwi_X_*Ha3}SS-O?War)!u~Nyjb5q;#G27^hfdr`MB0k}J z(VJ@&wuRmT&EYOby0u~7aDPJF(#rbV8oy3qHFrT?^U~SwmN0Y=E=sufqmx9u&h6pmD5;~VC2<%rICSH&L69C z$11Qt(=Gm3^^YL*(=C2m;Cwh#us&Z{jro3Ge( z`q53uVxAV$gFH#mJnmS|7OM&&kK&VUL!Rjr%?MS(McbPG%>;nzB$^Y|Z^5j4Ew>5c zuJoBNe({bjyZE80FWtSw<87wUI=lp6otw8%%JAypg3Bwzlb| z8O#0#b<$lKLAh^Lp)4GKo6a|bW;Uk3a=tc__KiR^w)3#Ofbc;C#>3f-oBRmK)(R95 zMPF{qV6d+r%`L>7nxvNA|BiEfo6ZaGZRGAilr|CSjxcf4?i4b?%(I?fy#ly=*CD^F z!<{h>HVp3h<68a&7-hLnInR?l8@04H14yxG8Mmod3-lCdh@fb20M~+Z+YhomxH1XSakv%5LCkXO*~@*^hhUx8%gX~#SomLUlB5y zlCJ_{&#P(73o8cOk4!O2^QRJtzCg&AWCk%%t^dN_4~vC!oAB_O#R9DW-vM?uUjP?D zVzS*#PHkQ~4hH*QN63U0j^Rv9niay)Y@yknlT(&nfwMa6wP#;vUl{AhP(Y^NpFUg6 z%@%WW6fQnG25s^ZL-hq7nCA=>|G@Q&4nVpg$FgGH#wqsI+PjKYYv*MRDnA~?a)sC6 zv*Yz}INttE?Cw+C2@Kmd(BhD+=wKZ4e;AE|wW~en$-G+rcN2|hV_>xSj<7}JIC^Q=+6wH!7ZwjE{2i!8_v zGar&hN6j5(1-O9rloQAI@)Qj#Rb{J%b211{4s^Pl{`_^76JqW_E$P^#45-MhbaMeq znVN{M>xMFYQkbw?s~UO9D(KxB-!*f zImYwEv!FLO+UZFAi`8H8fRB-m!XaW;@RbYsie{QJ{*galzz$fw4TqDw{zFH%u40(Z z?eQyKmsby7`*%5}oU1uz(Wn?(n*jmZvEvO43J7^Y)goNnwGYP7ws-Y<)Sy8(;sHX@ zoYH@)76Cs|5kE3AtUs6xol1oMp^vy1F3i#w#);eGVX@TK*OCm{#+coNtf#X9G|ggP z2vb&*b7+4)z%|0)zUgU#AL$&@pO#$hcMj~&C#am^2K9@)mhY%;9+fp9GNJ#>uB}+M z4AZ+kUgUMvA;6~(><2N!KeTCJ|15pi?G`F&9_x(s{fBPo6U>owI4=SG+wq4D_$tv) zqRne(ZA_=lStT-u_dHEuXVy@~l~rEd9j2Eecnqe!O9yyz|aM`Vv&3lIYhB|tEf zfU-usx=1367;~r}&p(8#Wsp5SJIx3tGZlXpn%Ra`*uZH2~g9220(aG~Np3;_sDEvr2c4B-{9-ugzfnsiK z0UJ{9C==@UY1R?m}_YF^$o59^4+7+d|0tWw?ViJp)H+o7Vp1i92jhoS1C}g!m0Jj1dNi=;Ff-F$O)f`MK6EsoA6~c4JCLW zwVV1QW|}5=?uImY<*;o;(?xX&`E0#UN<^`uNp+w=s?KXvGvv^EbRY%xee3#z zCR&8E=UNd;(QOIA8^^Q@V^fAPs=|L;*x+bdFT9VS2vw{nso9eZN>Y%AgBp~@I+nWy zYRM9>(Q{UIYnDf&%jPflO;5}u+~RM%q|9g5WfCw5jm5TYPHtf$|2g%37Fcp zl0-@=Afq0((aqL#3U{yQvvg!!sFbqNfRy-L~+7J=@k7@(p8FG`Ld8 z1$vlQf&hJj;yxxEO+_}W*V>zz4n*uYvHO{kD`(-P`S;z_vM`HVetN za1|>g{St@3RLdY>w+0{Vk1!aWSfLqaeNU4+>0I#qu&wg54fwp?xqXrTZ+xadHw!}* zNy2yZHMnlmd2rodL~pKf-6!bnsxFx;VMryKBQl*nTb%U|>-j{<-kF_C&0P*bHBOik z@w{h2f2n5v1;uw7f;R|UG5$sGU9<1HA|EiamZ3mgYK#euCMLQBZ5hKytsBm>{_S?h zIl1_*_1=_WrA|0bc;^h0)axZ@rzVjxzoQO>)uAvGnyC-CP7s-n&Ys)Cbs59!ejiKv zl)?Jzdh|{BQr6b62pjf8-POVqk^rd3+X{K-eR6FbZvtlv4)I!$UJxJ^2QnhA`ay1- zZxJ(w7eh7}W?<(MsgMD34+nH*eRZ%N?SZv9mF+AvdQAr6S&#DJbgr!|32S+;v+@G( z=kO;Gskp$0oD~_^{vhIFPrO> z&2>8Xk3PVXvEp#+%+2N=BH_&a6>&49BuIdcdz6CXwtW_0)NQK)j@y>QtFa+Lg<<|g zSI0hLevq0GyTeSdu&;G31zyYo&_l(o*c#}*Fwl$L{?Qzgr6>iI@SiO;&O;GOUT&6wcjLr& ztt`HrKeE#U0CD3Q!Fjg<@I@Hkfm~i6v?q+Gm4+jsUdg9WImO~fe@yoi5$;D18o@LivT=QYP<&+V_(_&+Gk3$432Cb(%d; zENYe`;>f5;2U_r5<4zXC1PK8gfYAcn_g0(&Ad6xE21{icw;xu92SoLv6m;nCv213Iz%9t z@ai^q+gQX`s~(5p7>NCY8gTGtL{rOz`JKh>(p>E}+DBVP?bOM<{*zXCI-h2DSDbmI zkLP=ihC4G4)@D)}0LJ$WRccgsli&3tQBqrDajMwQ06`?uM_a3G`Z5zgM@svb^tI&E8uS z$=vx=W5uelSbor^Th6mE$e*%Y-&6ZM&((>;D}rGu?I1kEUr3Bsi0|AD|Ds=k!;7Tn z=I%07>TjHK7Z@{eF3f$w{@uQX!AnVb7DyW*Ggal4uJxI+bf zP{nr~4U3rv$-;H$W>Q=Cf`fRkbn-auV)q@(qh>JCKBBBkj_5S~B8iq2xBSqAzFIra zcU%eEesOSAf=wBs{Wagw1|ncuLI)pCYU{Op)LVA2H;$HkVdB4j#y?SmfN8XT5X?Uu zM47Q@_Cogd<*+(pn6N@)FrTh|uPgEq!OH}XvAb8D8BD*|sjztS!Ou(yw3u9441u*a z=f3YCQYo#OJMnY+u{z6!V>S%yv1)2;Py*Yvz?4DSlp@2a`{ zSopD5s~!<*maOx;{vf*UvoH(Wim=*qxqAR#`G>_`OhA9{MG93Kur6$66@&fT>iGK={`$M7Q}vncMI^Q&vD0Oc5Uq#8!v_xloK28_+ZNK5wvDI$Tp`#Q&k zG~k({?3V3)0|@&Zl1iyM|Gn7eEFi5y_Ok`Aaew>a>hWd?&Pm0uU%5IxqRtax zaP6#nWT$9~Yn(Ko^ zTTYs2mdO2JS!_*rgqkz{eyXe8yEn7f(7qFKmWyW)7&r8qlJtTxg z{)F}JKG@WVqK7$mYII>v^3XM4m8sTCckVQ4@dmIq9T}KYa*?3^Ma4Tn>EN<$FgsF7j%|q z9QMH7dtOHGeJQQQCn_&SSp|iD!Yj1t(pnof`wX?tp;e11DZ3kY*SY_!osm4!`%3#< z!%eovv7X=6`ZHDp)b@&sh3B&q3fWmKM1jOvaT&A7mSL+CAqko_ZV7L`?o zA@<-t=&OA16JCY2pmoK}9RzFvoPS-R+d5afYz2p|^P4t%2b-a`**hEXcj_T$J|^`S z!to6##CfJaAK?R-*Ko$R*CIg4BIUclXBVI5h=(FjMXIjw3IA;(22Y;}WDH+Ro(gC+ z5FW2RM%{-4^ZKGHlJm5sSR!xG?wq7Iim?66)yKeiR+BI34f*`Sp(SfWmWLZU`gf<- zS*mMT)TGl%uszTK>4YBXCnGg7;Chx9F%i1mB;qJO0m7+&z z4onG@@x*?mj8EwkitKRpYvWBzwDg0~(jPGQ^rachb$zsaIvmQ{+=jy?LRmtxH)Y!a zfo1AXIyP33F&0v|R$Ig;Ge^S+4_teHbYBkrn~$U5V3~0==9-BvdvUwL`o}BMa}ckS zU9_UpthgW*5Cd^7=O7N`=RCx-(g`s$l{`n^uA+M~<`K29C7IiBYGLZz*^M=1Oc}{q zn_UD5|IV;4H^3HHZ?6~os0`4haRYH`>**Asm33dUm^+PRfHLX*H>XhAA4;LsK@&Xm)n9OoDD zYl(K-F`QoOPyF_IHk*%!woMOTC9e18RBY{C6T>;haAB|hSYhrS+=7zG<=WjQWJqco zBY{7eoY78smw3wl92PR;DGzC)19h>u_ZO*fKVcZg@Xknk5&olY3R-fY7&=as_%Q?> zJ;X~}$7ZHlU+QjT8qHx|Ox6Q%U;-<^kqnW0A?0vmMB!=2Gl=WE20o~yVJ-4NWCOW1 zd4*nwlJ(ok7v?qEy3vezv|0>jSO=o-e|0?H>-^A{=vbVZ|xt;rIy80+F(~cxVe>hN6v* zn8Hsm&g8FCO~cG}#Bm1ZLxe@P5iw;vd@f-zcy)sCEFh1W3XE+H{?{vGjJ-z(F%@J~ z3Wx>HHtp(6ND{2Sd79|x7d%==BgiKwM(md%7$?7_BS<$$?rXVa2^6=)^H@!2n4UGC ztjWq_RCdO)C&oKW_(mqvXi~s3!h8wYCtjwxg57fd@0pTxP4Npg2OKyXwa0%wkk$O2 zNgCN$g@)Rhiajyku&d^RUv6wXw?A~EWe#Jl{UK|j#WqWyg&Gp<%rCZE7zFsgI}77U9Tf`f_QRpD>az5Fh}6@hP<{|t(ZTE(H+Z!auQrkw zl~RH-e-mnl1?vdIpxJ{lV4@uq--uxgrYnQy{7BXe$Drdmd{1vqAzNui>E;wvKZzHo zVO$|OPQ8p*h}jHwawC23y*Y*F00H1G(VN4nw6Z0p-7kolInF0z0RS*bpXLoNixn5- z)OJr|C8W})q|K4qM@D|BZ);W%0&JN%+{3ZGg@dE0%@@~R#cgKbF7lCO|424}3$*fIZ=eVDsJL83e$7vjh@~y7(*aR|2$pVR%Ul zIMTf->gCjAq4JC9Bam7XSoB5;=mJSUV13tD9*w>NyySAKC_;LL-qV(pqOC>vKkfgw z%_S@4pSAg&|J7zzMb=)F=a%WnFHdLu!>U#8v9T9;dYjlm?V+()nHC}z<->0 zv($`T9x-5Nn9f7T;)4fAyogy45KHxaUwQJ1zdNwuH+{J4R zm#^YPF@;qT;{|*oX4PmW-Dqx$v1O#D5%c{q?u?P!SScd~_Mk~~ChsLlfG~8=AL*T+ z;++Dm#7J0EN>kV@afLVqLW(^ZEKqJKO_-u;$VjQn7-_KE>vyfFo1zY6r1)`LV6R%d z!aoH(=16IZ#+ETME8Ah45+i1$LMLaUz*3kbqQG!Haz~*>^f1{1SH>hiT5e1yrDjB` z9q2C^KvC=>Cn&}RJmTQTX*JQEi|=Xq5EHfI(w-@vc@ACWffW=C89~Jmw2h)NWvZNC z%d=qo(8m^dGWiAZ&hO-73Kp`ai1EDCT=~~M4W`&S(|{1Xf_GJ6WJ`4rWJ08ZOTa+y z*x@+$XI!S~;LMGU0GH`HQuZN!71VJ2D&Ww2W_}3NaNOMh4!t}M`e!}tMv}Sm;x)RH z1Zc}a=?9>Z7_7;ElEPJKh31FV0hYK1z_>0Tk+f|~*ov}gK%iiv=o5fgVoUF2Z(?x7 zY#RvTUi|S%?62LwNPW|GA`Vgdy1K?yeP`?fV34iywY9uCS*zV9{OZGthEm2N8;UFx zl&LC;?gVIBrZo4GVdpmfq18i|#dRsz=xc_e=%SK!t10N;MaQzg6&0xgF|<<~1;*5- zZChHdWqS}rg)tOSfqC^WvbRmi&D3vM?i_dSXXwg3*wYM%J25|McTO?O6{WYDOpuRp zTFYsbIjqhkFO3C}oI)pTCJDC5=H3`qOf}cU05p2WmpRKiTXdkdd|oC)>@-nvnp`@v zcHrfS5)VRgCde-K$?V-RNzfs=r#BR1+A`I9j@df_9Ptojq`T-FQz%f{=b9(`%Y3-x;8 z1DRAQ&%0N3%MEda?3e3bRhxhR{ndsJr+f)%mP@2_^Tig3J(=oH1bY_7LJU7_3p0)@ zl$t`z5p0kxtR>x89fER|{GOJnHClWB1tZrO0Bx#ZN&RCl`((g@~ z@dm+(%sUdG$Zl~Y4nTDUY(s&nZ2Ag!0STc9k*?et-wJPm8YMR1w!mKW_KJoAi0Vex z6=*`@NZwSl*%2y;QR+sQHYY3@q7xoeyBSp=TwOF>ZJr*>$3ledjbU=Ez%&blS3kPZ zSQkUW;Y7IVlnfoa9^_#cf8WLXJ7`T%fzVHl2 zT~LUpKV~r85H+9Cy_C{r^wTX7I+b(4;vm!-KaPFnm_nMzh-9Pk5e1Mkqv+DuT--w$ ztsqX=?LdR)S(iF=#dir)j0Ze9u+D(`KQVa&Tq?7Tj|0|TOITM-bjoRqy~d#;$@Uuu z2aIMLNs~y5n^-nGc3R&Q8eDO8uK17(2YjRCGTB@S0av2mWfomSy{^GxTN1(;RxEK; zt#$-l1O2W+Ue}OTPn1AL=w?Few<`5RJC5kb+3=^+lE*Vpd#jcBqCNOYn>|XKE0sKV zLcBmMcNIT19p0qezvXO4LGjxe<<=zv&_bXf z4yCNIP#bKBd@H9JwHPv+D~5IHM3)wFfVa__0a|OTLuof!efKm}r-On*3HnL#opaIn zZ{&wEvq>ROvS~%1XV5d>Ve3O;blao+_(T7Z53W{$wWx{NI2+dsGR{iHmaW7?}F$0xe8$ZuD z;h@cV3B`dTq5tpvH7c7BXv`69Ku5Uu)R;k#&+LJH2xJTn^<=4KiBIAZD#{%-K10o;1`x`M&5K~VR^y{aXwbyXtMYOt z7(fDE4u8Fz(aq5amQj<)DK*g9U*&MX-=U8@e7(SNP>=Vk4g3T)-q7QW3z|u~P|{$^ z42;^;*hwzDOJW`O>NUoQ-@)Q=WCwpNs^K{@B7xgCEe_SGfiJP4ksKVKG$BP+Y(1jB3xn?!!~gl+q| z!^Mo{oY)DknzJNATOiKVYlT+Fb-su>H(0SNfK04UZsm1k_bF}l?jq3;Z!^SEi?efL zQGAIw7wem*<^HKF7$CD_r z18jqsd9k_656swf)td&QVox4THMQ9*aDi$z7=BE6HPB`>40Ybp+S=?OGE zZFjY)5zl`Vq$n~N#l8Zog=KkL<2mzet*?yLSQvy`ky!otInyyphh>eC@m1;FcrdaU zhxm561&}I5h;Z(_m(dJheD-)htLIlOz6C*(xn)c~$M~{L0VGdD8tzF7G=Xw*e^geW zkS%x=lo%X`@H?HsF$GCC2@{ z1#}5@Iuq6_ct-rK(-}iL8lwi+kO8i#@#{5ToOq)4!seH;SHHOkN}R3(hN?DW<1P!f z?k)u>5qu9&{Ooac`k30!-+Z@gjG^j7LL-m0S?bdkA+mJW+Xlq-Xarwb-yCK-TvZ5c zZl0q$pE0($6Jt;`Gh7;+M2eOys=9}C1u6Bw-d$Ac=u)D5VAH*eIFArTFb9ViN)b;u zC_MvBENHYl9Qhx}1&x|EY_JpGry~hQ|A3IGYF7a*xrI&(Ejdti-QK0<+Wdpf4dz63 zH;r~$w}`w&Q}T?i`p2ot9R60ZJD@sHY7J>N4LDpavN^W!1qf_JSB_<*+T5viCl8kD zZk_SkyrT;yDz+ST+sRW;qBMBjNnCn01Xf}uF^i1Tr-d0dubTKi3DerRdD`@0@0eV9 z*2nt2tQPUQVY47~>YaDmCHf` z;>~UiR0=jUg`$VrBrTdYyPun?1@$pl5%n?nSLR9}lTh00T!w;d$%DCvDd&BJu^IU^ z$8}2NT&iBcr=7`mII8Dp$&$O;BiQ&AOKs;tpyjD*7hSa!TC z>Ukcz`meq0*EW4>Xh0^<7V2RX2ip}iByxuue{oF2!(hoz7Q3>JYDI0Jx=Uhs-y^#6 zno`x=4J=H#uJ13lFpp%||EPX8y1NALi|#IY!Foo|rdvw_+|}&_FZhC5&!{Kt*$(U_ zWz*;`VlT(Og1w8z6rmeLC0*qQVAp;lDR$1gMv7f@07UxvA~@sW zpXHRhgy1aPVOQhmZ^o;^nfP(O`LiM6O0Nw`42Fa=(%tD*pz{2myVJVIf3`afr;O2m z>`rw4bVTE+=^$Y?+xXVN7p6a%--*>8O=X5p+$S~;C&9;&RUbF%*N9(6x4W5f5LP7E zX2xkxr7|O;X_noXhB*giXM#seA`Y~Rc{^9+r4H>Oe` zBR1e6ZEtR_-9GM3fG1OuXl!UQJZ?=J_920UMi2JtMCM6m=cE^7xj}01GK3qBpQ+YJ zGJYb%)sG7wTBRmK#Pb!t!w#pD`AL8^kxyCN%>nVIp6^SN-*9zv~0=(9=>i@xO1!<9y^*@_8!EsmTjnrmwjSrrtdopl; zc)j>S$92Z0hO;nD_)6qmK-T?)rCCe6_Mel6&;9v$-F$7lDtnyVmC^)*lW<8Au<%Lvensx z!)RYHQzAof0W$jO*_QKi&bv9MbB^V-Ptr$j!zi8dW4Zef&5Tbg z{BgI`sMCgJ7fS7z-wXKQdoi#BfX$v>FJAj%h5EfU?5e-XnB*;=Qt=N?Zy-Eo6SfI9 z%8>wLPRgm}VZQAS9*+T(S~8mP6LV-rVqt+WAyI3Sc(Zhq@( zTS1T4#Fx609`L*Qd#6jz9-tnX_yTv*Jzh8en>k4zmP$`+4e5;|Ax36xr%Z)uf=ODO)VWzoy@S5#u z$?0o%Pu#qA=k~471gJx~JbCcI7v3`^y*K9H$k)|%Zt_bGApSs~f5v_VxH!Axt-rp) zvjw?gE|Z#Q@TF+@#3>%|W4>_|_RPZ%T3Wff(p+v1girN`=kvNPl`Y5QB|Jh1#^8{! zWRO3Gsi;|aOlQ7mjNNG-YH9$SMXX6|{lRQ9*;?DpA18QQ+srKq{?-r8ZzR;Ueqi2} z(9qgqekwt1jhF)oynfk*t@0RvrkpdM)(ND~I`j$+Y5U6wmQmsKrkp)3ag0~s1467{ zU=Yf8Doj<*!6*=Ca(4m4ykJOLUA4=&W>3|l1gt(JJ&b||j+6RQ%~apKrVjhLy@doa zQv@5H73bvCMrR?PQ z*i|pc+1sPzP62qc&gE>Ma4XyLl5F1hZ7W}pJY}us8CijQhYVKX?k^V86=m1=#LB!b zf1k|H)!@%!zA(Q@MohTXFKahtlb3bjj)icQ-|R8pbtMpq?(mvequ9ng;TYLb)2K5Az3Z(?B8K4H^0m35DW)S7@grqqfPODP9N zJf!BL2d9u4K7aHCRk7Jn1!0=c0C{oM5*nnjYV{(VZoufz-7qfAI!VuU%BSkcuFD~Y z>`u2aiM~5;(ZbFW*ihi}f+9U5e$|f?L~52R)jlP)C?DZL#V~MSVIkx^sG@<;uClhi z*#;$NYS!pf!>CkyN@|hd8}U(^Rb+XecRwhw6_#+*^pP+7HQ%A!;CxwgikAO*zvf$+ zxpOwd1n_4z{>+5VjM7L#FC^#j~7Vy;2VO%!tn^Nc$;!JRwEotw1hc{!A8 z4CM~==bHSvW`FL`Q0@?ac=p<-t=+G^yIey{y6+)}@MR?=z#d`zVfC_$6K|oseX-8b+-!of*ehuQk~$!% z0ut+&V*C=Rleh+nDOF8uDVrWBDqZB3v;`_HQzSI zZ&Rry33kp+jD69R6_R9dOR-GZ!g(IA6vvb&FSQnREm%NWp54rRq zS6s+7)aKHNE}k!gaGrHBtSd3&Rfz4AFVSl%$=5org7rh&bk;_dyvjb!=kfQzF>@5J zUHc*>e3OVyIACSNRqgENA@DZZLIN&TV5ZvdV!STmcERM7BM+=WUq8%%4@w?cOs{Dq zaC&op^k%SfQxUyEGMAbxh~CVHA6&SK%%gX>+@9Thlr*=Ug3skW^wCr+-BZYk{#I&* zHIqKNsv|+uuKVY;QfVln?W`kumOJG1cQiJRelu zAT?3e(hY5J0yJ-Sv<=*+a`4;h4VeD_*nlb58Zhj71N=W}z)!~jhRFP#SL<(=g9l|; z+gu%kVB!B`6Vk3WA(D8l3EaIuX#%r=oySPaF+ER~270 z&xlB0j-_yzU~)V!m=fMF4RD9$8KE)!pjA2s3IQO{1K{o!%$3vhq+V{!_ADvhY@IlI z;@ztq{5ZYVqF&i{!L1=6SmYV4f85s?-E)>evCPxv9SUhwx>v0!_^_rrP5w zuk`z44E!yziz`;G)N2{bLONX__2Y{)@N6@*z&j5RK9J|p$N-AIAV+9tA# zRSWWj`mG~edLv4_*M6Kp4xDzyCWEVqFxFw{mcy~mB7m4vw+O;^q% zi`Psi_}r{7Ay|0D@XHBQ^#5-;)ud0gW%(o?&GVdS1&Y5%O z0nQ9F10GZ!oH-&6#keq74hA)x7(hjnDM#GJf=LkzH<)apy=fQ5K-#8z5jP)N+C?g} zmNui-YO~#u0%gN)bKBBZcgfn)?ldE_G~j&S*BLbJ`}_U=`SnU><~&^II@iPJ`SbpO z!J93%)0y3Jdv(Rq$5ls^HZ^W$Z`8k|MoB(CF=Y3Vgnc#bvDf);HrU+v zH6LagDV^DEQmCiqn@8N`7;{pB3sQ6 z7Nb6M2#ydrah?i84Yv1Ro?E%A;80`1(_63IRd=|1RW}5r$C${U&0xhqW<^!v$g|WW z4QZ+>Y|m+6~bOhh)@jub?Wqqw^T_BdO~ebLSwvaR29Lg(x6 zTESqUB?ZDQ*Jn4Ac-1oOTcfV?Dewf+aSU~yzGfc!_ZdMB|(?06& z1LufrHxpC@iZ$DfmjocuT;D7;VR9L>Z%j0eBhG| z#?c7|t<|*}bnkd4GMr&{xC=2-OcU*o!|AdU_IV{^vmxIhWEfjNRUFQ2?gEU!Uum;J zjW~ysKE=!EE~~NR0Oku3f>`{~WD}aGz#|{t zru23l7Z6@~AQ`G`tKy(IE>95VBJF_FctQQiGUw?}f9e07z6*I{1lap*l?L+0z^0GV ztqhE4Y+E)Fn-snQzrU0O!k8w+(HOHGy0F0PYC~Jd31j%x|7rQh#>QkfgH@B|xG$@O z3Q^5)%b~ouWP_C-4!GtuOmhwv4*s_Qn*x&wK^dn?G7&A)yx#257c>)k(t|}ps0p?X zCRk!y?&6^VwjEQJ))WBmtTF&(l=DFPsS8H@?|;3tBNFOfwe=OY=v~ELOjp1L+AHSc z@mG>xt=yIQOdWbHc@mJ*_x;xXUbZ^OdN<(J(tBOK$;|uX5=j^icxygl{xRNV6|5zd z3zFS+&@(TI;YhJm<)EsAQOJjywjqmNbZQThuDW)?P1@a!IU8TrtYhITBzm*IV}fpZ zjYE*1`1!76VcIj|_FJ<*n_wQLvylDig#1L4fI3323drT}pvNY~eeeq!$;-SrK4dx2 z3@=(2Cm2r)<-&o~8n6Dk;q+KyxbE`~djo{))@sFJ%6=DZbuhoAZ8%NY@8B0gT<$k9 zKc`1PF4W91f3I2?5P9e)v-dp0wtl5t4oX&eB#aI)J%HjJWRGixHw-NQh%Nzy3}XqL z&pcP1Y-Ww9D>F_A$I6J~jFQYN9CGM))OK-@9ax8Poz@j-y%nF9@aN1g#|7)q_Z~EL zC~-ZW$=^*c6$8w`QhWjOK=%4^w!6`wnH-I1JgohmaTOPvZV1#OqczFk-qwgIdhsLO zzMAm^VX;=Xz@A~rH=aaN;G#Lq&D6*<-0w6YhyfXW^jA1=AlW}W4t-z0B;Cw806)qx ztrJ~M_B24#@IFw~><|X;f0;}=aLg|!!hdmMADzu7jDsFgmp%*$95Y)TYijI$?G}5p`saI=9*R6U@ zI{9e04*q#IqaG#)v{Mh-2JOF|0ws|HZETTQ%rgjah884MY;y0Id`|;?vtz!YO=5l` zEwPE0<>?{Y*aj_hy5}ZdY4I=OaRz!nGeM1;0BmwF*(cjPCz1+x$CthF$86BJCCl@h8ZRql%O!p2%gALH{RiBR)u_U9O9T*X2jC#z# zt*9^8uE<+Znp**5-{hsQ(Mz*U6GBLSa)Y34`S)03eY^gly!%VnRxrEiNl2Q8A$Ggf z{?x?48~{+o07c2W^J8fa8Qh|XH)&7C?YceoS^ozgFPfu1d?&q0h<#^x3?PQaqc;vM zdG+?TFBKv6RLfvQIT_QtSZ}mrvX3cj72}}LA)g0;75{r}_BTp~ zrmH7=^*2cKe^`rX64a^y`(azRBg{9SX$1+IG^C!F63RYTO8D@b;V0ahz<@cNQyJ*a z)l%hS1kX7y84!Y+C3VwXXpd5?sN(5Zy#bPy=|hNK(!^-Nxe7 zu6Z&GL^hI?v-~$xk|Y$nu3YcmIe}}EB>&cN8f{EN=mRXY#7L5~Qrl2u3Af=w8d&3B zrr?CXdP3ELKnswNB~@v1?NpCE$a&Z41QVrn0f*SId&f()RW63N|mZJtFvu z2prddD@z(i9C$;#G5kbQp{tZYejA3kDwklZJ|akvMu@*>JSh_jng*vk%kV$&;h9AG zR5wtzvhpH7p$oAI6 z>FtSKXc{EAC>GUvzrxnRVq{_m!|5XCELb%!o1t+sSl(VhIcv& zO6s9{r_nL4sRy?zLOH3zNT#jzVOFwhk-sHBQPpoZFb~kd(6^|(rS&Z(pUv1IJn3YZ zpV8wXl(pVb{q0?y7Dl#k)fZOvprZV5Zg*SCR<&lmLS?t5GtI!)_Pl08pht5K1Mv(Y z9*+9@Zsk?!<(HZJC85w!|A#CnVsA+q*-RB}^@=XKv!h)suP>kF|N84TXeJh}rp)7B z-<)PaW3ksm%elsuRe5f0*&ihT;MYa_>HG_Z9fv3az)?Gubg6Mt5P;Sd`kU=E3<8ID zOg(h$oez#c0O{(k&N8w_jv(y*8IE+UcM6lM= zZNr^`?upsyyYcH4`fHqRQ)@09rg?Z8mdZ}d?Weg_Nd~otL(o#fv?2xuvcaS-ObVv~9|QmL@Q)yN4g?({Q#72y z!M<}r=|Z@&Aha7B57#wD*38qa(?L0K`AB>GXGw1Ngz@NSOzLTNW{LpHk8&^07z z-E#V^Z1tV7Ke#QRimQUSmjO-&5?uH{2WdxylcDQE^r^!3UGmn) ze%MN9w3WklR;*yq3Se{o!hv@kQsnNn%zLz*?{_sJOaBTTA1*DtSk!ipiFXRWV=gND zUVM#ot(XnWr)FRFgjs1m4%4K8_QV`5VJGCqAZ`{@r3b2Zodwd0c)Z50MSR~X=; za&Q^IuTi(Ya{Y!Vh{ED0t};hs{n5BY>Nh-9V6a>$%dHw`?MD^XuCU4%z$P zs7?b^uHz|_UbE~Rv-gTub1hjlpn^Le*30n0&D_7%kNmJT=pT8mQ;>8Bu!HEH0wpy0| zCSjL#&0}$WR&&E|4Q_VhW^T|(V6}DmN5>J));rkyl!FVOP%q^gt!olb&{Go*L-<4p zw{PRNS=UT^TRlcutOG38VGt#y2PYqkd&Rouw=piXy_qXvHzw@Fb@Bwl*i^ba86hQe z5?jXHj&!#<4grxkQg|f$$9Ub(5rAJwU)TXAD|dg9D`lf3c7?iNd>H!$m`}NT6hhAO zA58vj(`oD>^iK9f6-rL<)HrdR<^QdSkLyOAQ&?lV+t^HK#y>dBSK;R!GsCDDF(7KO zytBTt^*gol!KvagWks4szAMq+^c{!@oYUTB4r~B`H7(qMb*_U`yT)?M(6D6Z`!hKxidH%_XVAva zn6EdW4Zkq4Zzwu6d#)Us&*@1FOr5(joP$(2B@HHi#iR z^##*ih)Ug@*k=$o7{uEQ-&%7Sc1CLdjNG%tQk=&eP1y69Z;dT=#+5TA4@7Q^xNhTqT(Kgd^;<6B zj5o5gtCJcZ2qtnFRmTz+8Xb4REl<;y?fC=!FAS>VRDu;Uj%W6G-KSi*!ML{s*Ct`qcHFOsSZo_tO>biJCjKp8UFonlZt}FK~TL~aR+HodDc<; z5i8=4jcEtjHI*?^%KSYc6wYajA-O~F^9o_`)r)v~EPTQQv+k1*fS*#K3}DVKAt;VF30leLE{ru%RI?gs*oI{s(Np(L_X zw7J%Wgk7eUebadW!(D>#T#Ouhtns}*y|soFR<977LbEp~J3LLx!=o)jp>!!NU7p*t zCfz4j2lT5(;jdNg4M^g?G}=DGHy- zVKc?|8PiG$dCk_hIBkH@I!qu{H;3avspL8FLi4;;i9Yx(fT*-sk4c57kbP8P7&_n- zVakbo{sWVmG$C`*_Xz%F|9V`0qBY9#U_b`bGgtsM(7lQY(;E-6dwq^MF4l-(c9=+! z$K+z;B-R8WoJdr3wjr^OX|=&+f2LAvnD%WGki5Ll@d#Uj zQc1%R0dv+mgML>95UTPdSW&f9)i7$rrHc8kbZT^V^Jq`=MzVH4}_BNlXH5 zri~-vTGff;eV&Pu86NI{$!e^ZT~QDj)V)_8$hBgBuI;1zNjbTFUAuKTCV(jPQKg)L0fUEc64Yq2 zP3C`L$`KxcleMl=iLQ;$lKutMilL+vY>D9EY;&K(TU)d zbRw0~i7so)Ut7{$>FM(IpcBDDVcW*eA5e1Rcnb_^g1Jyh_zF$FzB0gs-{D<`OO$8}Z2wDW?>Q^b(u&sY_ zns*QXe^V~~Wy(ca@D(W+2m<;}fwoMAnv)pE>^lLTVf%lgSCzD1pjWPe_u;V~qtvJz z*Jd!c(-Tm)oyHGu#Q{0r#H>)?0a~y8)Xj{a{%E?ITFGcAnyYQh7`9|rB9cqkp< z6LL4*`j>R_1x#-spBZ?bM{r70U)bEHC9wVI*>H!O?2k{x()N3l;Vjh++$0~!zNCTU zSy{G$AM;2POG^!83~HsA8E3uj=_HO)LN(+sq_u?1%L)8 zC0fa|G*P(;SVhTCAmd;7THVLYf78uBxy(m!{@hA4)~c%iGGmIZzk>|#2HQqP2y;O# zCPz?RxHRGNzEoSGnJd&ta-#c-cfc`)jzeTO99TXwrE4^bPwJVn{6@ao8nb5>LTe#N z459>>ixbiVo`k5yr0c-d)Djuz&q5d9DeMydfWb3ZXm;a}{Wz?rAHIjcBm+{_I!2`3 zESpfhC1$w0xt2o2A-hU6bK#Zc))M3LgxYFzS_#XtQ^Id<&ARq+(%ehI;SfFGU}k3} z8JOn16g5uEkv%r>xhV}x-EAj$(H#e{Z7r7!Uk8VfCR~W> zE9H+&8eF?hT(uyaRIgcpiYvlQgPs4EvgI(7eH-%9JF>`b#50y#_RJI(c^a9AE7$54 z@I`cE(?L>g{`9$)y#aT;tV!`{lB4OMK26f4FViOzM456)Z}oTq8elH&(BFNtFbn#` zXWwgzaH92B>DemX;VJ_F8=yA9>37EHO5ig)=4I)eT{L$SI#zcJV*q8H`0UQgWFa2Q|bD@|}3AFhxO=Fr82l53Ncj*w?2 z)O{G$^I$O@f*K5;7gd8l@}fLmXVVF2c8lS|gcHC-t^#e4oD`&pzY$R9q$~yg2ADiX z^hUbFZ032LE>w@xS9}^QU_%8=X8{QqnUzds<*Gn|MmDl?0f&4^R{>9hQRU$r{;$d) zf-o|7CEIqJZO@uto}N$uFb1ep@v%+b<;i!{T+C zigrk8>K}yF`w(dV*(fc6^$R+6e-*2mK2+m?Lj(EZN8}iC%SWQ51TSjUgoR@sFzWBQ z=w)*RM7{U{TH9cYJi**GVH@or%5F9;VR$JrovhL=39(t?y#{eH%E0Wgi4^Baemm#k zJL>BqdwXbd4pd1{TGfGG+v(=dWd;9O>|^&{~7t`NvuB7@2Y!hnVm z1k4!r&7p%fuaObEfMa;C{VnC4mnS3%P)y8Hx<17aKV%h1Nt}TdpM*KOH(oF=*0?qB zl-;Qe0-wXG{RDj8X+lb|_{b=_3`_;Kn~_$LJy}!xe?*Y?Eab-V;}p_Lke_^*Df}gx zMPR^RFtV-Rf$kLTRfW&EqEVIRjRdMt%as5!E4Sci{ZLg#HgfY_$GOZW1X%C*_i5-B zLXL|Z@a5CZ$6Bl)xd;)(j*x~$AeeyP(imTCdk1}%8?j|JZ0T9*59oLJE~(!ORMs&= z{f>K+K^&6l4{11ED0H_l)94RN@Kn{tMJV#h&f8!UB zpL_wO;5(|(%YiZB4Sc!+7llfEvVjZyCc?kZqauM9dBag#SvotTt6$dSCay}ViFePO zEhgCRHD~$F4Ufh)ecQYtYh%BLx`(L^o0JXgrm<@QrsYq+umROV28pMUVo39^LxTTI z+j3UFw5-6tT4`fR_`cb#hUl+L4PcBAHf!<1!ptaNT@pNCo%k)t~< z>>Jv2>IFl~TQ9s?Z)8rh{U+knWR&f{o^4x1_P@+(7ZO83p7H&zDg7oU>CEVGyLiiV zc6gUKGEMk3cB=5aVBEiF!TxzgO{4j7%!&svy|i&W<9+xi=act4lhrdXKJxt;*YF{l zjnKokxyYe^hdwxV_~4r3clZ&q8@(q(sOrJp-BjtH=WZn=g)r8Y-7-tyR7S@ zvcg{+g75;Xj_13Kd|Y@j*~BZyN~)dJ@8)?n5D=Ktc^vc zsXd)MDb{_LZhj)&mQ$Ve$MfTl(&jrHmh+XR}3R`pptZL6$w&*`{UB*89iD^!89U0(N78v$uX@^7P|zCpRT2pFSu2 zJX3-Z6xWeKSm`t{l;p>i;8gJwU+&tGc`~VTtv!UZ&+1=zW=B#-2U(x)VUerkZs~_4 zAKO=|I5knh@!NW8Xh0Z}x^Is{+PDAL7ef{YOVi@JLM|a!cc-Z)vpl)P2&9e5Li6&3 z8-dPHF#!WG>iq?9z8V}cU+})E3 zQ4sVn=g{nyNl}p;Qh6YTld1SZPkJLLNwn0%=~kQCZH?v{6x+gjFgJ)L;dgi0wwc>C zNciY(H*cLf4;;!oo_*7UNZHZ|N#U1RE?0;_cpCY`hVXRg81_>@>mOv2=&HA0_n_mF zvBXJ`yFkbY=JKW}zZk93LM%~bl2c^|*^^cvH=7uj30#~S;>g^&={LtCeHFy+ir_7f zWS5B@HECeu8zGiv#e&$~EX8&f&ThqmFD@&OR4!f4bjga?O6D6E#S6?Qt?Bbs{`qTK zyd6XopQq^JI(w519snfuLS+bcpZ)TP;xfg{CTlccQZ`LSPRb^8^hjfIy4VQ4t@HV@7V?GM%^Wh?FzC9~ zGq#$O8_kZmuH_5r4b1FBDW9OWh@NRVf2L`ur2d$7c&?s0pY&j5y2lxef92Tco`A^^ z82rLtZQN%0Y0I(3tp zulX00mf%>EA>DjkI$}yI*`idE96!%|E1a@%{BMI-n4ec+Bj_+eE>M%&q&b*`c;TWDPVyNzKNJL-1Ut{doFqy zk{vP-FlA?Nv9-4HMQ79tTHhs9`&VUMLqU7XLkv`Bi@`pCal6ExAy*%QQUlc{s@Fh! zbZYh{tSA5wl)c}AFm@4;{lc{6>Pub8bNyfnhi+yLB}YT~nG)VB43c zoMr;NImlZ=yw%6YJN88*mhiU@k+*6*$_i$&N$*p|imNn>{%)+a1gQ!JrR1Bvm0;=@ zQKz;{(8(!WyIr4x%o>kAd6ph?R0)F3er~7LqE8`Ghs#W^C4YNk zcE{I6e^ek0KNp?%L%C%ukf?fpi(ykn!O#vTcaYd z*gUXq-5%QBd64a_HLq=wP^+j^ zD$Pp@0;&zWMguvKmmsw9B-?OCMup~D(tjsV_j4NpRM#)S!lzhR-|OjA!&mY5 zSUwibxEbC`KP(5bTg|G~gDUjsN`Dmt+cL=h-cIBtH&pVi9@x`zb(Lt=n?TA=pVsrb zF0EcL@Nnydn;m4ob()d&`xJbivLCf?*j6J9^plbvM0%o{C`fN#*}qPg^S#~x%LWDy zAs{fw=XLV)*K9R~Skl8XTetCj{0%Qp*O&ADS-`ZLEM`_3wRzK6Y3fy_Vawv*IfqrR znQhLoyS{O-U6P#1xFm8y(iCrIy*k!u^8aOm8HHWDi#SL)=uV!!SyN(MK=fJuLlfa~ zz43_MkW8I7lfA^YSAD$0IVurzYjRz5ipclBCG~gqA5Uk*UpY<(VFb$+th$jDsMu_2 zZgFM8@=AkKSd_;XDj2o~I&1?j{_>Ml{)+)tbG|2Zm9be_W|y41{7$y@qY1cEF=5T> zHPLxc+fQbTN3KEp?l7JZz7x~?%y;UPOqqO^H$VC;9z=@IqYP1U8x92?~w4>GUQ4Tu07R_qyDU_G&tJF$}QUo0#z z%8QLcVsNDn&{il&aVnVZIUMR^se#-2+ z+^FxH1#&slH27nmZy*t}&I)VMCyHY$>dUWXnBQH#?8G^vsb2>2^a&s5#^v+rkWl^wj5BQsmPffRP-v2qNMKgDd&KN?qNV$S0{R!r`*_Dt2~E-m%cp$+SmX-Rl#k zj?|r7z`{d`rpqm^r#?4oGAtQ9p3#uQz*&i6c|INKI2Y_sxZm1A+uGB%Pl2&0mS~^H z7^~taYvqP4x)-y_oe|c`A7tn4o&s0Z!XmkXJ0Osp2r`u5H=dVu%2mNT1Xl$Ywzld} zMP&st5GL2VxEXW9z4sN7t$bETWk<)ktuJY*!j#ovPi6*=q6Rd+}_@ z%5QZiWj!5vh64EFSD%&p)y=Yx|MQD|K5TeY8cL7gFxEq$-<`EQvckINPw(GvZ9`fz z?eq707p5b&XgUG(N3srv$|&|&h0Z_9ofN83=t9W;DRP`XVT%3>ivYwe-JFtco1X4T z#F-kL`HH!To;hez1H541ca*kP{u?JNaq=wVrY9jP6D$V7-*q8cj_>;jiSS{8ODc4* z9?yCZEV^Vk6+|-}a9MSL!}I~l5@{mwQ57`$+ZRYg)%3;T^Dezk|HITq{rimC1r!jq z9o%r0u#9~~qXTG`J9K-*kcgc+@lKr-&#^Eqnr3I+EyQ7(r4)XIM9xYP9bJg-WJe02 z(!)jRvmEB!&oLBIGOsT~e*DF=pN#-R08;8Vn>9y_Lfq^dvFQaGRFoh35Dlj%|VU9KWdoN(NV1tsQB;a!BWK$2wCHhE_5igXf0bLwY#zk2x#%l$W z3hl^>4{%~BhxWtW#aVg}L3hqUl5rYIVFcX&{g)Ug=T5erJ-0Z{!NlZTGl$tvyDX5; zesuPD#CIsZCpV!r~q05U(;ElvK?BiOU68OBQv<23LB3~yne zun+u)O7w@717O8h@Y$}z0V}^IC&s~6=0vawQO_pav*ty;!+On3i3QtNEgE!BAmNM7 z?}9QlKOc^Ty|1$=yza)BBSvy2f?na)-bZwQNgwBtLkOeI-)^MQYo!6*s|MjzdyPNbD>O4d(tuiW3U|e&*)x6O+`dp%@twyGotjT=NzIv4kpE_#kJCvPP zB09pfjCBPZc|uA)8~$C{r%J|+ZhnZ*&BLM|RUC{vukEbj&MW!?eux8hyrS{jvLn!v z@rvK`eS{_BjlchGRe$ID76j-(K)yd*rCR_{*HbM+RncItZRUi6{qPcn5jiBWSdO-b{EMiw;1^Pdy+(KDvzc*_!CMw zS>CC2UzbZ!*~0(PUl(3FyF;UQ8LnGN{AVWsO)l^7G9TZMNxV$bNcLGAUGWHw5~6#< zzVPBhH1*^V-B8#j{emX>P38l7Pxix#@A+n!oGD6eOo?Ve-jL?1twK1=d6wFrLx!qy z>#0pgTZZZ>t^4qT65xrgT=Mk| zdvf+^$J{#{g7?o8{yt5+(Aj;qqut!uJ+gJGb1_|etHC}%*;?asdjsI7Td1GZX*64G z{1yd?J}oCV>8n)f90U9trA?IvoHLI_DQz=0+@i5P*oNF(i$7TI8e|=aY6@^tDZaoEWjcIkEldLa=l!0WPV)@_?q#W58#hCr14nD-LtpI6=RQmk6nQ zWj(Tok&z%JTLQ`Empi8-c|{_$BD<}@*09CkNUjl{?qs)$hDQVlskP(SR^j$-dE4EM zn)|WT{9`fut~s}hKOk)5_LhbS(+BY8cFXQ|Tc6tE#@{AMM1%YoOiG<(Thl4jBsU6A zZ{a%{BI0ZbO;(J*@Zp%Ccf@XksATRTngA|-)>8SbEnqc2y+vqbJJv+RPfXz+ajVG| zvPqK0@0##8Y1*@4q;9ay{#0@R(wfxRu?E~g9k<+-gTt63Om1{KTALvR@IO_wcTj=F z@Vlcwl{4*vrm-w|yE*sv+&{XOWbU0C%$ym1no>1^2T2=*Ik21h$b1L|ev*MHP9LhZ zLlJ9wXlo~{ok4n14gR}yf^q0=_)M}%)59-YXUnF{d8^jRnd#x%9JNjNMqo1g&sQ+z zy#eNxJp()X4(78)?AfDlOLMe`e;N~ZwXRZ*{rV#IejADUZj^rRtD z1H6~dV2b{(1We|6)iFWNC`_drr_lKSK3c7tn1?&XXTA)(cKxxZ*4}5zTzC%mLX4Y zWt0xZwss+sec&s|nW@ltcQR5%YVu4hycmSyhI?Rw(*S(R!L%K~jJ4X>wn2;>hN!9q zLqu3DjCJhn5jnB4P?lo!=|QXL$%<^za0`*77WpL6U9jn5*~M|k^)AuSD8}T3bZn=N z1azpd#YD#qea0B_r5L?IEzwnK3!Gn-a0?CxMT7YCM2JmWN=qrE@zXBZgt0O`;5)(w zl{X%>zjOP29<_cC{W@1UcK$aFpJnV+HI3m~*Yy1v5T`Eg=EeQx| z1R$@aX;(SK96frctuC_V8xl$uufaq`KAFl1X1a8Um^I!M>@#L|3TZvvz#A}w680_5 z>?}~Isl#9L ztPOuDppyQ+=07uacc~EDuTflwx@XNei&II@KHa%=QC?qi?lxz8id35*c(5W2r9pjM z(lbe~^;P6P)BDVDNNDQ!E)*^0hX(`)r{_uE<2v?1tpClBKPV zG_T^spPfSQdYo(kP_-!rY#?l$OMB?54RkF#_!xb$;+kuMnF)@3AP4MBtO#W$His}5 zw+ai&o3@vV1J>xq26<`Ppe-TIJ2-LSM{H(HpOa-H3VAK!|H%og=o{Ihjaae+*AdB> zNkM`~M}#z&kS5%>q7S7b;(N#eaApz9TC zmdPfV1lDM-yN?r}jtzC2H#W0_F4B{k*y)6?BjUdhE5PpDhlki`KyqmszlyQ{*QkTF zr$9qr>@M_N`_fC>L9jo#9t$9 zb8RO`io_)Y4$@;ZcR$IA)8Az?6Z@PR^?m=22B6EVWSBeXO?cQFu_dkrMC*d$Ck8F^ zXdEtom^6h3WlH#x`Q^=Q+f7O^GqEPWt~%ns{(pp;hf1|KD8e;ZhiRx)V8U0x%Jmq zypc9dVXR693HP{N`{Ne?iB#jyQ4ZH?TCzubx?_53xo!IGc|-bvTiK#%3ZuJx>8$TB zeIb2R>W-0WIen}lZzz^8W7|xS{&QVLr4>mJG*(s>uNZ3^Jqdy=nxCc8Brz_M;fb~r0`cVC5@O-@Bca^$aI z;jk6g(zWAy{fBGk>_ko8TG!x7szby4hGZjB6dkPm9Ebl-1;HBr-=OhYg-$>spiZ(#BKB8Ng0}p_ltc8s|Ku|A(TI~abi+=fWp(iJ@B}d~U#sCqb z$2P8>*0?yJGlq0Rl#rgq$|)A8Ojv9@z?7W*~q9M&aq!4$2m(MlR!Ov9v6 zU$P+99#CA=z#olUZ@`W-5*G~V&{SP3wfsLOXl3Fd)DEU9-zD8qi73ic)uyZ3IH*nc zo$)c6TmdRfI8NNH*E?O(^nf)hC{3H+Mv5a_-mQ1!>$dW?TO(U$O}E_}@y|=%mJ*Dz zC6xsOc1Ted!K0n-6VV0mnXVr$z5q9lHGHw9jH=)S~E;B zOLHPoK|brt%7r;LC35kMt0HZ*EA2$Ztg~O)FP=G3k*;?-dWEz=ieW*Sn7)EgvXXb# zQq&)M&#Q5)gX_YB-ww>X2)tS#oMy|2%4hkXu4_jbk%YSYH~+l)@{?dB z7E|XpcW`2c!)e-O>Z!GP&k-E;PfP?JH#nSkNkt!$t0#x8od#+z)lOfhgC@SQN9YaD zr{3vaHZ$Qv&(Fwc@}gTlr4?xY#kB*(A}(XTM`x| zY9QQp-ot8pVc1EPlCO~c+lqEEuFOOsF3T0!8P94xgcZ_eSDNJR?|jLb zzKUx-9)#ee1v0sw4Tk{6{?!E|i@vj>G{A^D}Zm=SK zPti0fIde4mT0C#|O{}(#iHW0+{41c=t{u&sQJyc}u|S@ot+@qbr{#LIJge1)w8lOy z9dYOz&Fu*Rt*-f@&A%$dR)g$-zuoFzQ0vO}`8BqP=z|?ORJBBO z4gP}NMFF2j?o>IyT3ln~QgMy>gs_n<%?ISnM31a?cZTAaQ6A^3P3517cDM1C*k+KL zph{}+&Ks-QklNj+CpyvH?dWbNx_gKWzDwo$`E^^=+55UDb`$fFvO|Y# zhfC9bVB{K^u!;ZD%cb?H%~a6*rwYa7p4ZITUsT3bc;4(i-HVPW}TZajn>)*;lad4 zlxkyK$s$U^!{}Tg@^=%*y2i(4E0-A;F3fli4uN%7&x<}}%sdN$d2uG) z37P<|%4v-l|4&pubq3~eF0D?6$g3`Pq(@%*!bQK34H3~T_D=Dt*|?gqBasd&4H$iC&j zhmL5Qo9;LPaW=05!=v=JqR|PL)(9hdbO5s4od4DX{B|P!6cWLHY_i5B*m6D{7trx8 zoi2!1zeFxBFOd0#gwn4#M`~7o$7d01>S8lcVJl-gQ6CMijAFf2ynASIYgMDU(}bR z?I)-XAi(BDhGE7^i2TpyzrEJC($MzhL`EC}ZPzN=FDCNih;1M9-OnO~Tx8*t&;iRh zJVDvV!xIA0{zYm174?6M(yMsWnp<2mw6d1-X?ZEC7)h2&RpeQ!{)PB+O%8VN&Uhmj zyJH63t#@d>UWkYJrlB~PM%oUe)wW$qbry96L*+3SJw;_JffPMKKU@BCv3;tnH~PSK zRchoZoV#aLM)1w=Mj9-2b?3U??|kYdf&bN0a!f)XW=iG`Kgz%3>Iq_Et7qzg8*Gw1~enLDu2Na z%-=)o;|j|n!i<%nK(no=DiHNxmEW%Bs{qal-oVYV!7lrBzvj}E0fnzTd;** zb&#z#b4|X%SR($NktDlZ#fqJT_e_-7v8rnA(4UfdkPc{1;os;>&o5=qXBpG$VyGrP z*%q}JFeenuOp$7V^+fH%x%Q(whBg^mP%}$@=R2jkBhl{q0tT$D(NN(XtC{)haZg(k zIV`1zpk7!lveoR9VggcPpo&{jwxBAv{vjqGj?McmjzC7XebyJPn_-li5w;Fg<1;mE z_0mrpey=9m?BS!10(aSBW>Hy9RbxG0#DrHmvYR$UjL?*_{|UQQh)JPOq_K)LPLW1+ zP;3c0qF376kKCb-Arv9a?5u?g}m@^Fa3SoUj0UTLoJuFXH{^*)GfmMgp} zO|C&WRo;v~TlHaKZjRNZo0rKwR{P3x+0QBt7xNK)0XXt|IE0ayh#@_Es4;8*R<_7S z?oT)B{5mB!55zP3_wcMr%!l{l>aw6B+e!T?CAdmgvuy3$1F24p#*s!D-!_$mo4HA{j4aYvHJAU0mm7a^aaDdOMwO?%cu zMcNM)SaP$9{;gE?-rLv{vWlJ7)Ss8b<`qaEE9tMSDp>O>v(B(^OUI*;E%%dMxkfF^`lCCrM_u8;LM3p#}K)MTx_ zc~CnBN}H4rh`WPVwZ7AwatvK?zsNmo@*{Vy_pkI+ROw8UU1#p zckRWOrLfw<~8=ul*0#^!?oA6=KhP#yauOcXIUsAx#s+OE@`f-v=^Pp zWAvp6CJ;~&%v^J<{GJNLnMIbr#Hrx{^8&H1$e8$qQI1>?3ylzXTCl}y?&%7)9}9M+ zH&;jM8amE4SQ@U^dDCHP4b|GvS|{QVUOBewo(co>$ERP7HZ{A$Qhu!D9@mZ$h%?16 zMh}XokrOx&*5d!8@#u`f>xkTy;>(<|Mqda~t;6!EFA16}EBo}|IX z2xqXrq3LlZG8oH`wHBJG+s2oYh&8qI-!ka%4vVG>@K&%(EU# z@v|%}WONd*9WXOMqa#Sa@4nc0tmYm$GegRp?aOqmuw@{?^0GGrSn{@;p#v-r|04pd z;SK+uk6xxzT`q?eENK|Fp6r_@7?b**x0TnXGjFElaln=~fkQt$jz z5KGSgQlXI-stv#3i*Ydhgk7t8J%R3D0;5I;u;Jw{^YZJB+YWU+7TK7~KVn$NKR{#d zvQz*JU3i{T*ZRmMcQl@B{}*k;)zvKUjRAqJIaIkOviy3@N-a_}viu`a*bI!ruP)tF z6AR6zRPsdLMa2G-uVsHrAzGt`GyBt{2F4*V&gi?3SrIFdeRkZwV^n^!AIE1$k00xV z&*q$xeQMnPTbwz7Gxq2iF@Snjf=2G%&1BG_I$WBt<6{L@0Ks^;V!lvPZwOwZxRmsU zD$+w0vkq6Jxt?!Ey7AY6N&1_37`0C;QhgOEG6-*J4D5r#Z<+tuS@6WTRGS1-186!- zA=z&$uG*RQx0RAr3yvKwbssK$PO6>F);juXGp>%DFQu~!x#G)9gMjhRMf8Cy5Uu&^ z3P|c&a0SxU&)gtAH%q3WewXK#l@J-Tw>iDz`gC&+WV3Lfbtk45QW+>>>w5}Bpr)_D zI%{n%7-j!~-!lN44*0p+RA223U&RfV7XtO)sPY~>_47Kk?yOw4jU(B2k6+>&^C$TR zHnR*;R;y|KM$wn1cT53pkh*C=VT4&rm#WuMjAD00kOt3D@K`_r72@ur>){l!lLe=l++2g)KJsOfheJs;`)n zrzFBX4P3jvVpIqzsB8y@bU|OSwp+hm{i2JyNcyH&dWs1wZoBpCdy3%)xAb&>0W*Fx zXXz_u7cRiHNHAcFO?}0h%3O1DEEJ}Wn)_(-S#ew?tVG+HtnD_qe~RN(RYxD`EcnTG zRo^jqP@4J~z;#3Si2`V5St%)GIU~};ClemrX~$+tI|wCVg#wUaC2&br3yg?(?~+S;K(or*DZWO44kM2| zJ7nA0-}(|V4~LSqa`(=mY!IDW=%zWy`a>~@uV@|z=}80LUkgxMlWXkdQz}aeXh7!A z%qvPey;c|)1p~Ey71}zz@y*rDHWXR0A=aajsmTsav&dc!h*@>P0#8YS?B$zxt^Y{_ z>}ekODCq$$E(WA{$jf%@S`VN_^`H)xHQ3SUuz2B7q0rL-uh8iwFssq=@iGCgQIFc7 zN9rfbA-lR05I@q>4OiVO7D4;C_7QELY&x2}RuClHwPu@b^KNjR$nIZlwsmZF8Xuz` z*oWZCj|3~U19y*$C%y#Pe^M!WlhQ;i_UKY`RS|>T_0&uJEfDY!oW)@zVF@llQEOmP z5d{As&hv5#H7S?Vy~gzWV$x^n(y!y1ZY@G`%uLyu8|ZGHH#gR0onQ8K{rL^-yg!+O zY+BP-m2jQOX-*Ad$uw<%W5q+e4ezXYVYJF}^vj_SPtbair!~hpA#SuxKb(Uk(&<1c zY`viPty&@Da8>-N9X-kO1DUBkRSDuA3&4X}yJ!FdOmf-drQ}?nJ;7Ho9}IWl%`)g! zMQ-oU^hLc{H7^K>7|_H|rf<4oONbbIpk=F7N9l6)sG7M4Yv;g+N4`8^H;>va`gg4R zDv`dWJ*^GD z)qmI?zs_VdzOQa+at_u6;*0po^f(FTj+85H$R2;3Y~1Y=&vD{@1ah9LHNF{TT*`DC4XcOm$e@J4#wU$YGwY z!y?v}A)l)V%pbxAKoCtroNSL5Vv6%wtq*Ceue=~=TvZ~XQ+C_dXY51g`>GP3sWOz& zH$$hnLsA5^sJM?=$HF4#siRH+h$hOZF)PzHv;M+^x5* zZmwK<&R3PNeC|yy`xKC0f%9c13EB^q@oy^nvc1+md*X9!z%IJ%*5M+lO2ja>S7iX8 zF8+hRBi?fB>+ImLvX0eGCukR;QQpFFSxEDBH%I*x;vE!ljlX#uO@yy^YWaH+YBm^B zI&y8DReGsggGxX%#_4z(8h3oqaKDwc>v6-OL(OR1TQZJFRC_{A{WUqRs)WI30rMbN ziF-$mr0#VZ%GTEVQn*HA%rf6f?%4b86hyWzCi5lt4o0RUQiI%BIfcgsh4M=NxX%Cb zm@id}t8dq?tq)rC!HOHY?r@~$$Ne9|-Uhy@^6Vc!_sM&E(k5w1K?3F+AWbxNZHkgA zb?t$aRN9ROsjX6N0*0~`2N6fv54X0Ef+O2Qi(;A8r9~0_@jOD^6gRfDh4P}QLgy4* z>q>nA6kVx^yp*2b_dY2VefIhP_ZciV0NRjYot zss2HA>4(SLcyn9z)Pe#U6X!Rp-<0f);XAIWk5K;`#jB5{R1r*f_A4&dtFk7oN`KXl zPiJKR%(|fl(5WgS3v%N!)S)=WCYbAl*G%42Up+arILEvPXo47L!{&I8T6?And%K0FKCUFYRUb_NO)5}Ta z@~z8_m7cA@Qq|6akr`2iqPlZjShlL!bM#V*xE`f?+m@0#WO5jD-?g$`@*qII% zU~e|t$~_z~DchqXc+LExX47_32)~*E@9KW;4zJP2B?Leyvdm4a+I(S-ft>@=9S}&p zJpw?Sl`4=oFr6ZP4tA%xmDDCOKttduDiyrdh zY8#_$XH@kR!Ka3}vr>0X+^Iuzrqv>w#4a*mN0@=pidA`2{s7d2O>|`f)x@vYZ+x9C zxC^$~rb(LD94w5iZO)sE#Fm71c%?QcM*6+_*j%4w>V4UO&=)|YnIdfhH$4=MuBm4a zWiZY9O+`)BQ*Cxzy!nM2{D4`%385DN+7t5RbvsXw9-%Eyc2VmAr-nmDn4)$U!z?d5 zMA|@nrO-FQn+sZ6P2y{wbyO?$nH@4C>dBtbLGNg0!(4t--FlP zl9@TT&M1c&RTHCO(VE+h46=1>Hx9{vq1SA=^jPg1WFVfrc>DsLjfoYHa!Lt`T(ZDA}hXf0X(`d zD76Z6hiX$^NULem(vc+(8Do=HRj*aXf8)u4r@x;K1>;M;YPGKEc<*(R%K)@~GWnVw zi%1+~Dqvn>93NUH>GUTRuuEZobx2abgY|nsDqX{mE$7!7<1pfrs~q|LD$dlS_(Ex! z!+}5}{N@OfK(`rIeJxqMUZel3N3>aPo&k|_*=lB2K6xbd1b3Bkz_-* zC8M{?@}Y-PrEvyX(44{yvm8X*Z$_essHGbnqTV7&Qo`z%dJ08K#$Txiig`;ipI{;R-L~;6v ztHXepi+G(rUm$wmH8jae8!6TcbBHj9;T{HGUmnw*M{P{ycjP8v)Xx1Q z)xI0{QUT#+UssL!Q(fJ&kGR#i%d0XgwYv&J37V#a8^%C_sx4t`3^dP$G-=bRT{=yz zEM>;$P@7KGq*KP{(-!o`4nyr$0(BkgXy&fR(3Z8?272{Hf~)A1mHTKi9mGEGSz|?+ zE3-S^o5NHn3qa1ID^xF6)w4fpLZvs=i$9{9J1CfR@5Kr?V>h=&V5g@K&O~#3CBYRA zu?bf@NYqHIFQ&mAT0y)7V^c7Q7?cuMoC^?0a3!&R@0z_%1a(4X!JRN?22Gg<$} zPY(r2KTgv_D8q!w`jf=(t40A@VsCQ5NrS3wk@vJiI=&Dwu{2x>Imh_4FU3~7Jw%>; z1fz2Q;89Z5vY^?}u^l<6bgV&f`^2O0a#UbLz;D*IJgD{v6MFs$yl56P(&MkIFPCE4T95v!t1K>$8{UW&BL}}Jre+EYGbt_QShOej|OZm*> z%;u-oRUdzx`Y^N^XPz_HYR+%ixo#MFZ?#kUexSL#ChNB6nAFdD&4$4!-YR0dd7;cRxr& zZXO*uQgXt7X4R!S8ru(VAKd@Lenscd83`{Zn_GFgOYcKcQqExWfPcC0y~^Q z0tpI8ESM#rSu>DZT57BK&Y7VLMVau_&f8`Sz4MpS7fssVnuk)|2J?>8`RmR5QnV@N z%9Lgmv%SN7)&vOPbVjqy(*Dl=(gzIg=gd1018v@8^m5o6n`a`chT6iQZ;(Yu!RgE+ zs{H(a*QmV8wfvsdhPB3ei*8x7Jr-&y+Q-H2YEUryxOtOx`;4yWz^usxk&zQ)l_AcM zewyfM4ptz~-Sw7)b#Hys%)M?2x-B)l`770$l*P}|fD7)b+{qms>tp-t(*NB&b(8k# ziEP8ojNoUQ5;W~tIJeX6Z|3c2zN{yP^QZpXGJ(e5{PT7iD-(Wj1Uo<)T=U8$)qNu^ zFv^B2M$|hc^BY(8!b&x}Fvp#k1DGbFdCemqZCcmToXZvKS0vjbB|jhT&@u(jAP&D^ zfCl6Li^j*6k06^5dKxQC`H1>S`V&E6C!`()NTxWB@^^6!?_!<|%@=*9gzs>=z`i<= z!y`IAUzgPbV;P{xd5l4f4$Rx45xOQWCzyX3+;ZaCebpMU!c8H(GSa{@#YhR@=F5y= zhZ#>h1|p$ef5NaIcCYeP%l&8f9&JP%G@F4iNS&i3wgI334srLTtRW+bTOXb`vYSPm z*m{U8=ZL)N8ZO9T*s01$2fzyVkHFu6{|$U-by;*^co%t%b_#5=d1_yt23lTRowBn~ z+Nds-r^rM~6L}~@lZ)$ZuILc5J<%?1G6WDfhhPc4p7YXWtXOZ3Xzd)bFPpT@ldf^; zleqUOhj91Yk#%hiFbnyW=&&}x}inTs0URTyr(JB=Rck46)SJ_%rlti6za`bG3(!zu|7^aNnc(x#XWOH4M^z zlYYf8erYss<%MQ7r!Cg)&Y1`J;zaMv(tD)>HRDUwt$FJF{^xfo_y1)7oPCP@iLd`| z@K6HA>$gFAZ0z-{FQsDLs<}S{OKI%mkWUvY^M5wF-Q_?AB>m7jME4i#Xr_q^=G4(y zX?<-d^rmy(nKT$tUI%5L0(vf2DVlUSS+Ui*Z1|$&&N?>;W;p~0VDuw{lf|_-f#nQY ze;-A3K3in4EA(t6ps{G-y;vzZ5Ql_4%D2&u)JAyK#Twv^3x8~B)(jr?Pz@7jy?R+bNC3VDB4ZrY+Tev204XuF8PYy z503>L6W_Cu>qyPCGDTHN+?&#)SZ*q3s|2q?t9fhITejdIGP$`rbxqn@Gx?B~f%GsL zZs%rUb2j;a9=o01jIxDQbC%C7zt_DaXK4W<&aXdk{Cf}d&|@ueR|6qXRs<+?Zh5g- zoSL(Oww1i{m9eqgb67Z|g&Ap)Km{uZX{8~_^)MX!!jd%oP}L1Nid8OK8a7mdEp1kl zN|=@=1k+Zq$c{qWGhU8b!Pq?!Uj=IyVT8=_fcJ3Dcgs+^3l1UAaRJS9JjYRh=i_;f zcZ(%|JKd~Wp^F^#s;!W+t2F^zTB%v8nh@DmrcR%rqld67VNlrxb3kfilj~W12->K; z$E=6S`Z8f;Ln-E*`MztL*cCeS8H93-w5yZb)cPiXtmN%Mn>wlX&xDDGT5PvI{j_qQ zZR2DuEgz<;)6#M{E@Yj`|IFzsHK%GRtx@A*WaB2y#wMlA1zY->>@ibiP*(}Y@qo@B z@o8B{iEYn4>qJDdbcgzaLbVVjAdFObKeQ9GsNy%C24hl5OMMv|`NXXPi+`2XJEO|% zOv3WROLt!S_*H zhG15F#(@M3-m%Y+nSU3Is{V4rOhJhF2(952X;0k0!P2CNib3#IB3(Kq8KF$LyG<=$ zwY&?y%zsHO0Z!C%4vTHiqF_fNrLRQhiyB6qgeVE{ROWIgO@lt=N!CsV7pt&rASWx< zhma_w#1uzE=}Wb~DB}~o0?%|`xm+vI59s3A8+e)R#Kn4XyZP@|(mw`DDLk1eBR*B; zeJ*ZYQ^5tP$`ml)d9h*GB4+&^>fdk4<)2_0!QmoY0>|OGxDH6IYBzpBM2IM2Gx4!% zhW7d2C9?^>Jto-o`M{5?^b@-4$MRiJPCRt3teffx-}4h_WN>02Fplh8ju%;xy?0#B zL`<)>E7pnnA)w2$4*bMA{W$IxmWVX_dM~U89aHOMhBf!`fb#Z+&kxerqPZl^Nri5dRm?gqS1J8|b}} z-ZBAPDv#L?!Yz>VSo|b|b_#d}oS1w4L`2Mi7isL7__ce-uf>m-UO%oK!}Y{R?U^(hooFC`-fgQEA)aMSybj zt;|9!0NmWo0twJ316-<>Ob&vzCs341nY3$1nvHcIOHb%RTq?)LW?>dc$ZIvW=K+U& zn{@(;{oSo))~pXCFGCAXjTg+8o8*G$|HpzCj9`+Z9lo90dosv_pWZOHA)>xNx5L?2 zz8#(4&TU$TQJ%#7Q;rBhw+7|es>vefU$zSMla~ggG)aG1w_0ZWZouOAhn1s)8aJ& zn>|9;BTa6iP3c>S`mmt2)Ef48*eW6H$2&qa-03sqaPZFh987!PQ{u4bOh~EJQyBpfX%jOt^e?Xgf zenV-m!~zZ?OKWt^NU=|#?(Tw~lS)o^%ZaAYQjvL7x5&w)TfIT*Erd5ah7!?|o{_@y_lq!IV`o=guG8foEjj7$QJgTDyY%K~_2wmd^Gv-Xi+$m*^D+Ua!z>fwZ}YR@g2_!* zExHPeU%l}+ET_3_WGAYcC(4=K-}uGu$xK@UBkvH}<}<=X6>#F|nV;0#nbN9jm$EJ; zU-|*sGnuVOXh&w-q$d+~n@xTmeCoeG0t1_|=7d1fZNs z)jd}oNFk#7<<-bAM#^_h64W<)$JJpTd*Iw;k5S4<_EcT9H+IjwiW5m5gXEj4>1TI; zosrZXyvn8280}eAe6MH&R50K(y}4#>eUHBTw6t@Ia-C3c27&-eC;Yo0x=HF@a&=u- z!ABC4cQ5)GlqaBSS6^;Dy6S9WkK&B!5^Hwp%}ILm-#PR1oWpp%vEi>)mggf{DyPJA z_tk#bR%uJCzHR5V_g7Cw96Up{*9(Dp-*4wlXycHUYnsTkY4zK)nzYGORbFF7ATjVV zP$A)Cg;u?mcs9vx+`aKb$KLQkxs5GM>n|j9Verl>^F!)=d(DYz7HwR4zmS-t3EWG4 z#o;wq%xy~hRQFyLez9=Ef!kf#oqg58BOTSUcpJ;qAeUOl$U)G?-8Wx_QMZ^};>)ry zf<{I&lDkW;+V^^qPqxoN`pqVN!)rsIo z5jmHNxJ136!fKwxsuatemo02jvgZ%~w3%+EDcifB=&vzWk+P(fLBq;LhGi2BRF(E@ z>ZfZLesyo`hy1m&gW$}~)9&N;-P%S-+k9O!*X*b#Y<*!u4Of#MAd0}eMDq%z*m}1x zMTx~6M#1~3=nSfC{N@tOO_4siq@;5tI=87yTM$kovilX$B#MXIa z0e$K};4!=WtPbkRZWft)NmviXIh-u<{*M9i=jn>{7wEfwk}p5aUzcJB9~JT-E$}S# zb~&Y>L84r?)F8YU4?K2~kWBgr3@i2Ul_#Ku3lbPmd1}c~laA#JKMqflyl^Xdr)S-C z5}8TDmqw|V3AXNTHI&mEq<&n6buXpDgMCG^$|TZb+Hm|@xa>b&i_2#8p)RNHja{*RCQCG!!{Drl%z8GW?I83h5go+I`dal?g z|24^fQ$iq36dBk=mw`;f$~;r*6IsigrdMj2UHJ=OU=kH=#feSD+6+BgoZxAn>0Tui zCjei-7ANAfQm^*8vJyW7xFuT4sqJ-K8cq8ae(?&fO}eV?mhc_GO938@5AA+srnz?r zKf-BO0eptG^U8-R13tps^cC(mUsb<><#RKw0TLoGnR%f_Cf5U|DyPBr4yc5 zo&V^nH?n%zmw2SP&sUwl0u_5$V>yWI5vnS_CJV#2BqTBck@!TVPgMCtwNKQzQ*w+@ zqd^w~4G|K?WkHTIh(=LVc%GlhDT+x=iIqlPD};G0g?0GU$st$+WM@)Ht;Y|<9KuD- zrQs*MRpkU&g=lT}>-c0yhKYJf%;dVUDnw$gJlBjvc#;6ET$ z*&-Kf%*{4z$TlgSo~W%-mwp;25Je_)xxDLEE!8!tF9gROcJkA7LLsD=&!_Q;dZdo? ziG~|&bx5_uH=Tyqu?NURDn-ofXx1+2q{%z2lpBEoa4g@QzW*&Ky_|!@StqNRnv-++ce1vV}~8Ojw9<23a2`7e@vZg_p{T z8{89dSurjnx<9(o7s60F$-lPVaKZu`_^)Py+KN-1y#l)#Cd8R5nEv=5{KKcOd?$Sj zPGSjj@vP^ZR2rf;d~)T`MJc3bEaqitH(9DSK7F)_)dwdX;BEn8%BN`;xi(P`cB@rY zlAG6R+=_JvHCu&wQy%o`H32;he8jLslB?@K#;6DO|6|^>EDZEWd4=3padWi~cgfHM zpI#aNVgAF{nyuQ5q(UT6SA8UzyDmUPhONw@W0Fr#Vz+ZU1I6%^ne)EdWH{YC0qo!! zo$n`8|cv2EJ=urYLg;+ycSKW2BWTpX3C{p)ZHI|(r$m7 zkJSfQ!?{H|5<7&Mgu#w$^4zf#%aZU-P`WW-4bW0STAGJs8(4hd$ImmU&tV}_4^n## z-PfJWKU>oOzw4=&I#b5#nTC22X5I6J#7?O5{7ebmDAKyNjIN97h)nuh6!|4;o9VV_ zw&v5Cgx{vM^a-rtqL3~Eh--|jwmgdV0+h{&`r&&N-Rkc&HC&?4muCP)Ho^C< zyVCGcTwrv5HhRPfg4lJeMH4xeXqBU|~gvc!{cT}5Xq zD2AP5>AWuI0l_w8TGv}UwgxSUM~v(u&Dhi7M;KR3B0qf$Q^d!!Y!{(3V@znF)E?Gm zMbW9ONt0>45HV=l!L;kSfCCRM1@z($pU5?y_Xww$arauc|8 z9Um^ZqAihIum^X{DVmGQl zU1$uye1&TN<3!`NC4|W@sB*Oe<-w^}jY#!vWq=dj$=%u>n9?5L+XK_u1JmCyz2RyL z+}sqf)CXpS0_lN(qnvdGCc6R|qVM5#U%3K5fbD8!*Ni;qP+}B0EU{di(I7-){o-EmBLlTg?;T;HDVQl2|u(Mh6-?UuEZdfUXVGFhICn6QZ z02J7FJC#_ScggR?S~R|{(6<}4!!1$mpo8==LYEe2T^*Ij zDUU2dIwQ+6C$r{laaZjqYwJ-gd+G=MY^ckymUt^REuPoRV^?P(Pth9piSuL4WPbnC z&w|AB26dA&A%K(aXiKPkps1K@%ESXZQ(T;$#&>Z`KLCICj)qzv|z-?P#R?AIx ztRl6v(3UP#a`J}|ZHaHczq=O&%Q7PlDuL_TZgj7T2<~Y)*p*WIRHV0x-L{RHWlpFv z%@^J)mCdqaz6M#AQb~#wrU1!v`XhsR$JXy|$ssMjv0GxpLd=e2yGu!czL+z_T$`N@ z3TE@{%)2{|aGA%}gP1S=VQ2Ekb^>4%Cm>96aGs?yy!JPO0-FrK144VmA= z3M|uo6&$VGnjjVl=yVilh1 zBDcnbVrKG}llxEq{`3E(qhPNl+f8bJ`SSY125Qe36ChT^r4aZ6i0Y>p%P8<6S%?OyWek;!bpcYq@2nKoCSo;K_IMe3G;!c#cJh?;P z#r_Cm(&H>>^2?#s5X#qgCOOV3VX~i_aE{9wtXG z^L8iE^-Gq$xk(NruxUV19ki%i?hDqdCx_^hHGtiJwk9x-DHukqq9DYG;Agr^`ps=u za>3^Ee>#MY#QG=nq@6wp9o%)w-QrZKI+8!8PC*@zHbxrjE*A{>DO`zhXW>-0rJ8K_CTFO^KZlX-%w(Ek1OL+=e+Ihc>fyIZ zX@mv~cq%?cET6z5`$S66`2(TT;O?|+AjPy|BGb&nO$Ln!I$in;4)?~%+a4zaMAzPgsDwp;9KtQBWyq0 z(t;3@n=cm)R=Z#-;Z)BP*69MpE>x$;sF0yDchOJd6!}BwP}M&a-`fvmP@AZ{ZBv9Z zAXttV!_Pye$!py)^rQDrOkM@mq-_B;TF}K$^Z2<;+`Iv$>x3%MYUC~;WpLC~@3SoFt(H2=hk@A*WQD0bP#MX^thMDC=h`vjD=&NAl zF(HXry}da6qQbE_7u39n#(WQ9o5(bcHTyYonBE3#5B8ubc9P@lgHZ{Lp$KG#!l%E$ZwDL--Y)dCNI*HuoGdwiNJ~OVadVu^$O0^tZZEFA-|75ll21} zy-ix^5!ksoD%<4RK%%z!Rwy2)3h&V@p|vGz#`VhlhTa^H%7xd-O*RXt&#&o8tx?B8 z+q8VAobg^qVm+v^MS1Mqhi~W|oE8eqY{JTB^x0~d{*DhA42fxBoW=rh-SHP{Da>WJOhBF`Rf1DQwN zhAo1dycL_(0$=9$6(=VCJl6K>D4xNtOpZYbLgWj16m1}P&@wnC#_F7J#ZG@OBPs?3 zopUe(U4$|;t`OQ8=E>g(c`MMh(O$o4*q_S!4H>FIe@d4h>Jdo#-&1ML=313`p~@8v z-1q8_hm~rV($6X>qYw~_a0#%=fY|*kd}EY%X69`m1Z_%E>RKJ0F6WZvdxO&^y*P;t zI?VZ>NW{Ns-aGuz{YrBz`Qu=Oc!tLy8kFe#Gx(IgE_B3$@!y1yqjX;P;`3m zmYvMs3~!v*BqP4RvL)r2+aQ(ui0i;(acMWs)O$H<^z*Nr_p@y9Jc{CV}n>-DRe#d z%-!UFsOYb16??9jFMM`lFT!Dx4KMzz3Mf1!U|r&R$fE&ir-?0iUOHrDxZ;A{((6CF zo69YDnFcYhG}>yDT+WKjJCtU{X|dyC>GPkKS$s2Qn!|eg-p#W;zn9e8q^hF8p^K&J zPeRVSO1~LC)F=(DSC(o&O77ZPwD-1GdpAKK~|pluoh}okH~kX7R(^q+&f; zLofGMFGf>wsqXVb)09IxirPN6hcP-vU?vt``Il4asy0~vY(NL0n-Ch(UR^z3cV9w9;jPnN>$8x;6NG|_LQf@10VSaLLax+S)cupQ3W zwb{xOjT!hn;-S^S`hTL4Q_NNZ=PaL~?cwQ?)PI&@&t4ySp1&ZaC>zW4{hf#^O+ZDB zOo$@J-+)TxQz_%WG3v~zvA41{Ti=TlRhv4u`26O8KP^Pp%$r>P34%WrzDq2ZNEJ$E z(D%D|GZsq>Vu2nBop*%uv2NaNQFwx2!I==^)0_&djk7-${F7LIB9t5$MW>A7ULQYc z-31T`D|c9xJ2GI2y~)(MQkJb_as|T9;0gqFz1`{8S8`zGe=AA&KU3AuK!>P}ixX4SfQz5_0dFRg<` z>VdL+?!ho`8Q6G^$X>(h$@Vev-$ou);i2q`~iSI#^F92u0fWA4$ZIrYO@? zq-iSBvi-!>Gu`F4Fhf?M!z%cv48N1gc8sw8$pSyc$6F|}RCP6=x)Sf`fa>z~AD8gM z_YZ;|NAS2DTcnczs^z~LM97j?=;sf=b0NS__VH6fyv5gjA$0gc$ZvtlwCt&tN}H8i z-#tM(@4n{ZCqLuFV$((+;cjZ`C*X%ERJ9d?qQ1Tmz|{IeO%p#g@4XWN_C%x{`4O2pH~vK*}x>G24C$`1Wd=$h`)Nbc4QVo{Ri^ehIy zMd?BZ9N14DrYCZtXHP)29eatN9%m3Jgsn{3-T*&=lu|V?gWi#KZbU2!&{i(;i!W>> z_tAULpB~xxh{Kn0SL~BqIHSZD{)?2*^95k%;yIAW`1s^NtVHO?in2TWIg9XN{|67b zT0!xo;*?ct%uUq;mpA7^sXb%jmS!Z8Jo@;F^FO`K#ivn)Hk;f<&mew`pO}>;xqigi zO<9@vul{oZ)~cEGqQIx2g3y4)gR8`as_@(|UZI%jdfupuNPbx)v8o`yZl(V=FjAnLiZLmnb*b)R^ zGa0qwflDB7%$xaYW;Tz+fu8LO^YA(JW$TFe!Wxo9U!Rej^&F0BNCG`Vrd8-Y$F5@- z&aQ$JfQ3@=kp|i7PI)^yMweAc9DEMqg(w(4{1>TgzdeRMOf91~6r*Xk=FQj|G-+J7 z8GX^Eu{py#&S3ftw_eEmdMm<`gC_09FI0gjj5R@Q%>XGOchVK4pT*CNWU_~T>I$wR zDVG&-LZ6pipMUV0ic@?KXMj2$UF9gz`Dw-u$~3@61M@O@m_$I~1!|dGI-vehNxx73 zoy;0y)F3F-T?a}49X0TXiz08ycR|s{6EXU`LSLL@FLCFu;4(9(tKMWwyRKxw^oYwx zm*H}0?`2Nk@TtTc2@82*G!J2Gam$M?zXyiQyM$gkn#dcpD5|}0UJRXAW9QIxBy5zR zC9rNzsGiLaNk>XlqwKh`MAr7M+kvQ!5L9v;``Wa5oZ;de_Tseaiz{ZoR-A*Cf7VA+ zVF#kyO2nSlH0TYV#c9H8dNvO3K!Mnb3w14vbM zg}3@-QRGRVvtr$+6!BDD5ptS(t8*jEnk}1h5;r}O)8t&zTWtzXLOQqmGB~#SZa95T z?iZX7)7-4&44uW}8ZOnlD`2JP43TWRXftVDGvwDiTwzyjzFp_R_Ui>8OTN7y&6^&{ zc8j)Y2_p3S2~@ocR4fmz6=fSo+}Rk(){3^w1OZA(3XNE$b$90`!U$OGW7W7psMQ0)#W!UO6UEk!nh5J9f zHxzI#fg%>PEm#Fh!th3o*Y(P7Zf?^n{g(M{aD?2$3il}5?;)^^iT9{n_b4$4xHQ|a z(l$sQXPk=7ivyizFBh+tc(5$|B5SD(b;{vfnp`drD-xrdIHZ)*k#e|kI2HB~M~-Vd z-)2<1UJqSK>?-8?ebM+V=HM7G++V7&@mkF62@!UBw;ck-O;mA`Sdx*~ulFn!Pj zB%RIya}(k3d=TmEj}=?dQMt)>lWNN-jmd$Y-VduVh4#Sr0>Xdi1EO_6Q!(elMuh8rouxM=(VLJs3_uv@3cq;>N4X>}5~lQ4!#1&- zY@#Q7tM3|Ll&(r&0;dSb?*DmC;5_@+3ICafx)&HXZi>Irl4>)WcVX4t7*@m@w1Ny-}ZX% z75$c$6rs}!9-8*iZ2_#AIDEDG#US?*hD?cymRmt-#lgmPue=Z$=;|l0hLYe8bU0Q{HZLyE?|xnuSML1qzEO1wgc%c3WPK*5-_Chb>2v1y?p$fq(%lggu3Axw!>dZ zWi62~Jpx-v!@s3~vy1{wa1jR7&#|el`&7CZeUVwY<=1PX8U~=lg4-DNt<0fxrh#XW z=DA=34YGh~3w}G)`Ot?_le1#WHl_IugfOAhze(y3u!N$(V^YKW5_td3F9XGeo*3|MQB2=O74pM52ahCZ5FcLzfA6;a|-y}c6ER^X1zJ;T>%Xt zKR+)oRm{)hW?=r-RCN30iL2T}7jApS7fgb{rG%V!`*w7QJ8B1-Is*M9aA=pETj^Q9 zonX8Ec+#d7Is6mgC{Pt*tSkxM0+F1x|8jn(MC`P_U3^L}pE}4-V0n{lU;}1A&DkM& zeYR;@G~<|#GZ+#~PxvCscA1**Ox(Wx&OpGlyvr9TmvsU>GfRE~s?YT&0)lC+FA{7v z#r3lCHt^pD5YlzS9P2wK2>18ZYZvd{Vl#-Yj#1?N3}#NCy&C?A!k^_)Fo?KzvHJdT z1qBLc>;=38UBlr)F%P{%N&>iUE2y}g!LyL?R3=jC}i{VE=Qy5!1SC} z@<9cf&ED!%c!W{@f&~44gX*IbWsSK+h&Lu^L2 z)--F2!!2@un3tjfhhM-12bHfE!BeXj+?OBwWRt1J&6y{!S?fk8bsHcD@#45~nqioa zpA+)9RJkN-FBX@$#3jZa1f0WU{HU(Ty~I(Svrbkx|1Fix=F}0@^4TCCpjic}&aSFN z$Ut0UrE_P%vMRe~POLz6MZ(s?{Nf0fPs+16Huhi+>Qb{%;Dxk-rPSVx71K$s2xG{#kj`x)ZgvhI%|v<$wio-6&@o zADMQ}ZSj0f@6!zYH&Dg8CWosu=SlwBdiwLr)L1qUrg)V6O9BhJzE zv*H{86offyVUB9uG`2|LDpI<0yR|HMI)$P{Yt>`cm0!#Dq=XO{H;c5NJKY&76T6sM zH;q%7O=_Wtvo_~<)JFqH3{6G)nkk$^vn-7>1&*Y;ye1ahRp2GLsm+^GBh$*VY0Hu) z3%&w|Eg-G}wy8idKiJYPc$2Ir@_W6>9k!14uF>`)xK75imtxB+#|saLeg+P&F`R^o zV<;Q+Y{YA_#R{RAbrmz5;GV6zM$Cdl4~pl7%&Q2_3S2* z)Qc>@v%uEQ7tD{Uxuc-$nCS8(WTFgDVpU6f8&kPqy?6hfeb&6qTldAbG+XyPv9(@g zC~8S0w+bz9Zz5e?reFW&u-lQF1RzqI$XJxOg8h3jreOvLV!NiU(WYX|!W#k?;X|T< zN><1TS9D9Jv7^h+vwkbazp2+Rqy;9-cjgiiU|p5x3u#-E>ZV>ht#&`r1X6KHe=NU4 ze3ys^YgPY}wzVlfkiBi^;9vU@IY{3NJhs^SV?%#OhMv4eSw_R{+E`mEeBg(D4W9lAfN<9CUEFjW%7DW_$IEc0b5OsHwF`?^ThEp zr!JizlZLEc>u3#HCnG;{YccU`B#uVFCf^o!$PtXi0$b(2Pc0U)tX!5*IIFp<2 zevi~NHuI%VU)fZ=FYD=vN=`U*8W^H8Cdqm^y3>q z4F4#s^$*Ynfm5PYY+Fr=;~nHjX39XpQ3(tmK!>!F5_%8E*0hGI0}Tfx&IP54!Cqx} z0i(ozMS*`ImiSmzES*A+URyS+o@JX@MSxW@p!5W>=OzM(ssDmRV?GvHmpx^!XVt-p zh9*`Md&!|}W67;Azm$6DX6AwRS%3b4C40@Qx1hBDT*yb`g{XfTT06JF#Jsj5}<@K&9maRt7I#L|=@Bbj=RhLapVoaywIW)8OoDJgy5TKQ|!EL|3*E<=+0ymdRztqccPfd#=LUagm(#AicfEWjW}2D zHDdd+tqJbBzU%1i8-QOJqL8^1v=j*lLWOlY5}3N{H zo+C}1qK#7ltX_d>d%v>L@^sVgGvoO;L6HL}%oX-R~~(=2z&ue@#jS zbp|W}+{ffFy$< zYKKG#uhP4U^;jG7$sYQfz3o?c06*gV6WThN&V@5Wy*YV4XK!I^NSJf%xZgI zX*&$8eP07-vVEhpokp64SeM|;=cWi4wVDN@Zzrn zofAWy7F9Ou=rpqlHLcu+rk#v^RlC#C*2-|x*yw28=~|z2VeN0MzV6WliuKW5R!#-F zS%~mmdm*0pt%^ReHLuFLvSDj2K%?_X^D4ZkzL2e1=u5JE<8<%UetJscWT4S__D>hwbAoUl&YWF*c4tNTv zeU!YF(zfQsb=VYdJ;&xvTQ84is{Fa=5YdeZIOsS1nhd3*uH}7bjriO^ryf;UN zt9;!LA)qTfjn%WIAr01tNz7dicO5tVu59unT1Re!yUt$nKsM@p4?Xs-sw&AtKAVCH zcZoRXL3;_HJ6#WvIrN&l(O%+I{!<`%^r#r7n6g$dH1fvg{Ox2@iQn>S{gL7)jNN~S zQV|!VV`6ky2?sL$QD3W8a4uZ%pjGG^wLY^R)~`(^3n(!ese%#PSHOzSh0P`6!O_wu zzvk3|Lge2K%u^!25W_H;SknSgM1@#k(Sj|@vZ4GuHEXRs6}M>R%NDImwd(b-Ky_!I zfXT*w-V2M?9B#sxMN5Uv`#+y_M_}gA@qxny4r6&1b|Q!KGO(lHedM?&fKhebs72r6 zPxASbu_x;CWBE*>@m^d&Wgr-49A)reX)CbKh2Y{9dL9z>6)ydQ@O)wDgU=c-2}gmY zQGG0}`{X{;>e7%p;Jm9IL*~ftdcPs^UWOKG`tPnG>o|5F)psHM=M?xvV@u1AhtEr8 z=L5WQf+ZO;QkQ z5Ha|rX zV*DA(2v$ofI3Otm=Z~ow#q%qgC8cEC=Fe5x1dFZS#_4Q>S+-#X1(I^T>06cDfqBz1 z=uz;%rJV=AenQ0w_`cw)pYQy`861pp$OISubLYJ$wyU@l)EEC*n4!x-v%QbUfrpljj0DY(1LEZrshf(LLNuZbJAQB4C&pY=XwttF#TnaURJ;oal?+2GP^9 zI&_^UPaQo@G3l%zx(*nERtJUxJR<98!(%h;ih;R`)WnbMu9zK1kI^HH*Iit*QyU9p zED5n1Azk#B=$fCZ20Su$SdEIO0=gy6TIEA+AeO*;r#L~HX}#y!0~ zqfW*9*`k=l&`o^xMkp5t4K z%7g+hA;b`xbfXIDiej))NM(4C#37aO)eR@R`~>H*zc`!KkA;{O76F1)D+r}DfWh-G z;6}?bV(-SnF6W|=X#r>Hx%bS^D{(-#(kaTaDfc~{oS`gM5r-dD+C7Zhr{qEgRb|xV zB2x^2RrF|uswTH=3RqFlcwj-m7U4|R*uKn{!J7X8qj4$l5G`|9=N#KHrL6<4COXTi za=ULPrEOR0oeMcOIPp+fhIztBle4t+jjL@=kNN(qv}~__tn~9z!)XX5c_XeH_Ui}z z+{wLbPc5%I+M2Tp<19NMOW=Oh7s_GYfcUs~s1)|R1xkFXE+4vufha6ea*j}Rw9UCN z&<3mcFWq(RtiCea(DvqNbnW`gTx%W>A)+24GTRDwa#cwt70bj6QR$isQ{qBzNl@V6 z$C|6yR1)$kVU)OQ`dxQ()5(c)G|&Tg+e^3&5bN*KqpFf2S*UwU+^2@;J{Wn`UQ(P) z1$z&@N@Fd{R^2GdU)n2+a@86t$`P=5rt{Kq8nh@cNEl;XhybW7Ln#o2 zZa!#L=8^^s`2)FSSr|iNSM8A!q3g(k>02=y_R_bF&wCl~3Ttx`M0OlhVePW^E4Wbi z8w@1spdJyL53+g$X;uIS5f`n@m)3!S3vmJKxrdZBwmfzC%QQ^n6we#vy9RrRJh;1I z0;343f}G>s?@QanYc~kYrz=sLQqu^FXmq^-vP?YKQh1(H2s2jb7669X1Z}WhYulp& z`&qD~*?pc%MUhKV5!C||L}S%?PB~cmt{7b2aywQ0JYT}v=Wg`2RwQ{2OWQ&h5#`uv zP#pt`{p%Hg1-XxxokCT$q1g1b#wXx|?EWXn;4c&$kMIApsE~r^lr^>K;E0&(Aj>L& zP*Uxbuu2F~Ej(+;AmW;alq?12X|R&J`dG*z&uh{-=$*bc#%qj!>w>uk*x_(jmGS8y zwaun-6B1^tUZP_6I{XHaGnReMi#YFp(IWq6X}Y&vv%FP}eq>g4gGok08cKtdF2u5qCx zg-fBN(0qAW&FMM(TH(4O(EMy__3w>s*A(^aoUUK);FDo);9VXs@E7X&f9O)B+W z_O`kk^X8@&<_1%K3xCtw8Ibl2{R{|xcO5Vqz;TSwvF}tK{sXH%DY@Q$sF)k<0jV6h zNY7I*eg=`j8sywXS||1bjO4W4kHv)qwwO@(2Vu}_EQjn^{Ix8!p~ZPNjfsnbbSAKa zp)t0%)JI3#oeO7cM2L%3f>OUS+tB{j=$>CwaRKsRB#me;sm!+47cw;^nKY2~260g) ziwi9>GBlUe7s}#dhAb{(w4&qU;wU{T)`KgKgKp}7anG3&sINb&*jM7~LrD6Aab3^X zT@V)#x6`gf?zJ;}#}s%5I;8?%ceb_MzdT>J>hj*BbtfCC@-*Db&YnB`jsXaVSLsVI zzePRb7Ar8tWi2A+D53KlOsaFO@p%rBf+PdTRkZ>;epk;!6-nLiB2R!?$y_E?s9~@H0PAZkogY7EO8-TMdHC{k0o)7!5l*4vLJbbt35DdMA&BK&i5r0zuH znbu2twX5POB>iMv|Oi!nsEq`e1`_EGP4hoOVndlIyho)1-w*G ztn?kny!mB~zM==kq6$>%_=!_v&Tm~^F!g23)B|*;n(3Xco|%}eI5N>AU+kf==~z`q zwDN@XebexzB=5az5repLvh>4REATJC79Tt5r%WbPH-^qfu{B_(fQ>>>kbpuFQqauu zh@B6*gwVkea5Gjit1*7DcxYxB77v0EpH(Pb(a~9kbek3YHyE{EW8}#d7?T-EupadQ zS@JzZ563RgD(B~qfOh1fB+%`?I^Jr`vFWxc8e0ZrF(PqJ{X=rymLFW7Xv@%ww~4k5 zXJ!q2;=Ao`U1N*t87D&S&|w4Ag`#cTX^Qz{(lX}I>jMXLjovJpN_V9Jl$C3d5p9gO zvXE@7oB$|Oasvzl00=E+JS#Uax%L5F-5Qg?>U5j$1KthnN%!20|7r9@+$yL zgr1!bJ^67|0?fOv%6w)*9ugu7twN>fs=S-8k;n#Gpqubt!W&TXD1!9GhwlnJ{9_nK zej#5m@?dCQO4i8lJuP)7F!?``GL)|AMdI{gY?17UB=y#XzoQ31VTN~2LnJyz`FrmZ z*#99ysd-q*Sg~3Do8TwpGQC8mlc}1>+lv9cxERrDbUWSd=l>>4aU2WJJ1>%MfZu{S+^E zP0cX?$p@z?gFQsY9=+|Y+uW_(Qr%RNN#ASVd-)N^gTmXkK?)DZO(M6*&DZMP8{!RQ ziWJ~eDw5A)k9N`+mpYdkm-DQ(t|}i7W1|ik1Z^}c1>#j$QZ6j{soeMS&>?zBuogrD zxKdfreGPYXr(Ul#gYkiWZ$bZ8zaiu;#y>DK;4umv0?iT`9rYdD=d%8kwU%4&U4JKI zu2gdE@Ky1bMge5E>mpn$!jb}h|7N12MgWBA5n6eG3O~noms}`~AN)V!-Uhs> zD%~I5YbQHN+nqM)NBC&L>|JH7)%$#%Xx%WQzd2SyT z*`I5_>s@QT>s{~XYYTW7eUl-23S<;=d;?UqTqJ=JzEUdVjzL9e|BSx#_2@eQWW2ek7V=d+JmSyRdsyry&3=4VH#yP^@Vj;N2 z8n5WW{G5IfSrWJ*M-^HmuOnt#C34Hxhu=mN^8*`ZFBNE$_dg0G9X`%3vzr?IYv3&mM_+TJQ zW>Gj4`>+hLvY%zWtZIao_*sTo34!uxvXdE4D`7R4Pw%h3B(HoL{BD)L>j_*G^_G$h9OTB4{a4ka=f3YgmTs4ip2eCG!?IjFL zW!@+p3IcTeFZGPVcf;lC?*9TGXu$c}Xgfpk zeRj}Am2%XN=6f}jK;&Rw5A!7-#X2uSKD0J(a^CfEH)SQleC5`-U&j4B?y&=VUMtR( z^vq0d;ZxW6^(5FHTe;cvuCHFNs?oDF=;t~!js96>w~S9)(>bzN9t-{frXR*6zM}U# z4o1(dWi>M}x}o|mYVUYInsxoT9JY1_12F=hG&s3|XPO`pZ%4>bBvJ^6dtUOGZq%QR zH){XP);gG-6DROs-yqghUQU+_C+B+1`R2Kk`=9(86}3%MD$=gL$;%_UA+6}jVzbC& z>eZbM8J|E!0<$x1q@uG|D%y9`E)Sw1zj0IlvtRF2q#E5=Ba|8xA0H$p7`%07j$M2| zCh-IU^D*&U-p^qtKcgXKO%OJQKQCyO&)v=<8_}AM+PCEE9$5NI@KpQdghxxi?p@Q= zwoeXB`s14Vw%6n}t+lVp2m-Me1ml0|ljs84Ck9^3njDvi9=ZO<9x;7~jmDi0JtKwB z-29{qF*W?{u_aIE2K8LMo^7E0qGsSwOhd9FxtY28*+HbMfLrks&!jf!we^VHp+u;K zBBrj+Zkg~u^xB3qv-sBbfpa@pxO~DOvqLUA)7nmZEt_q-j%kID0-H6tThD;;zU~ZI z78)T9IUH__KReqvV-MSAVRl|K2_~id?z7?2%5574wkf!HD^oQmh zIgqhwO%tLC1v37&re1RpozT{TPN-F~uC_NYPAmK_!L7w@vZTZ>RdME4Id_w#$;SqC>oxt z>h@g&CkV+mvBNj1(>K}So6zdZfOY))+8k~cG@EBMSpKW%>)kD;kD3rB4h$$R1?ktQ znHr8CqQ}q}fz4L#-LKqBRPI&KW9(Q2GZyJY@*u6Lqh%(xI4v0;{Q*YUnE3aMKCj2| zUG%sBj?>hjaglNZ77;iurN^+zcL)>UrVtbaZ;PS0tyReA5GHjBle>j$SV07fkIhg4zN7=iN;x!D5K)(+jc4?9?S@ankJ|kr9h+!**dG}i%CHvI;Pf@Y& zk{pBxR7e(ulq_GKM-<@iY9tpZ#^I6UXfcBaw^N8%Ax$yoVJu>*r6$eNk!-ceo$f&FRDnyrt5Cal6#ZV7t~9tk(;s?wt>&NPYw0c+${8;@}HQ^?16^W>6e$G)-Wv1tD9I_TR6 z{y)$`OJkK>t%El9{=d;d+Xnuh>Y$g;$Bg*@Q3su|a>nbG{M?$qoZ(Z}Tz6M|gQRMb z)DDTOkr;wT->>B{(KxdV^q0mGXkNPf)OKnH5LZ3e0!<$D3GcI=LUNAU zwcNY&R<=!KKF;sRnHtoecZB5`js^FY&Mg4iP zmF47fk0up*%6y1F32J(NoohY0F5v!Ir~OVZo9GfsI9sQ1v)8Odh1ghc ze^0)vhrE0{s~h938Afl@&)UQzluaPqf@S z&N7FiyX1#q-oy1@Wq%0$VP6c^Sm=AHgY_T!N$?OtwW@0XiCDc(=T&Emho?*GYZ2HA zuep+`<&tmML!HI~CDQGXM>zr>&9Lkm@D%3TZ@XPocQ{nLE#7#`!)#!!8dER7gAT4L zjFXv%MQ1`)Y<3vO%_#WhyUSb7dkz=J`Pl5KR)k=aSSK@-js- z`OM=rf8sZPx-rdS$}Gyx@{n68f~_7q_IzsM8a)ZkS9Y?6^tAdzk8tGfbx3x@79I<- zf@K^uNuncrD)^c_`T);t|LRT%WwNJk`fmF^k(I`8i9;yfH$?Up#+0YYZbeuKX?rTU zjy{}aH?eSS%T^8feJ=8wp#5Mmg7;n-G^^ebomTWuZkyU~?M^60u0u6d-Y&tERxX@%Su=$Du|2fWi!& z;XDo^an;D_M*X`;L~vCU2ZeTdeJZ~X{vKSMZ?2F<@{GI#-l33$ywQsY|HeXu->q=z z5IR#Ve=LWI^wN-$kk9y%>6iw*G)vz6*Gd3yO^ym5y@DD%1O^U;j$=?dWSGJXLHIW+ zcFk+~9-$j{Vy~;t;ULa@k%BvmFKpRxeb)A)`9|_bdLc&-C-7ph>EQT9X2Zp-&nsFW zj@GV58s_xC(oHo2-zvoK9KWDm(C^xmerosDtrsCZPeg@(P~K01Mf2l`e~r4VpU)!D zdlfSfXcAnkRUUvFa8sg|f4uQ6ThpytQcW*zXxCj#KcjtauO#sBq<08pP%}+xGUz$)S_HG7Q+68>I@C#C zbwa0_?^f%X{l+RJEJ4z$AFvg)l`pW>s8x--ZGN?`NzHZrV1wkOTaCW8;mLZnx=J?E zi(5(KR@;E1Ngda9hTdrm*qYSwXJ^^y=A0gDP!m1gYO7m`Qx?hf=;>}-c%3Z)_CL;L zjg_{eE2^3+ZQoSdx++VM$*5w*vha$!-Ql`GxGq0jCx`2P2-mfT>&}Gh_J{W+e5^mr zf0HxEXs=L9+FeHdDD_1QP&!3>nVy70!XmxaG@AR#fR$)GbgD0gQ~{0tlk$*cCs5kP6K} zQW;mrgmp~Gg6a~6wyUayHhmonP#D>UI&4g383&Xpk10q4fo0ICK-X2s7(s<@`3N#l z(bbrswF47n6s9tcVqyWsL~31Mf}v$f<;)dey+sKnyH=Ex_xg+C8j5tt zq3SJ)-{qh^3rL)2E75qgww<>2>~5Rwn-$6h9i}Vhp#iNQ@OCN~Lc(7YYqk`A_@84Z^T(WHWW#E48u&HHU2A1|>DDz09osZnVa(W0$hrO2|jk}yck zI@|WQW1BXVu1~H}#RXOIepLe1=?82)9PzH%kL;zD*9D=uPTvMB~fiK zWAh>)=coa&&G)H{D{+p%mk<7_O|L0*_!%ah0X1~mDxLdQI7?Q97lgz6!(mE+_9c{Y zjr-^*Y7E$%`zmpLUjj0}F57QtoNn94B8h6rew%H-tt>fL#3M^3I#8$E7J2jhpe}hq z*iF4t_blH~u$p02##U8wlPU#+2yJdv85n4*+X=#~;PeftHQd~MsJTg%=2e+k6^#(B zK%UBgk}n{Q3v9oBjRNj1-J{cMHk2+RW!^GY9^2%@^9Ht|?LbGg*p$akL1Gd9# z$uguxUJ+gyUZq8g$~Yjbq^uG``(^F6@^)JgTuw3&SF(~$?K1JOW3?aeEe)at%i~HG z)s(c`-mPyeZ#LDYq%###nb3^84JG)msSK?2_=N@03y zRcLIvm5}Y)+HKCp^Cv@Xf2hs zoE2MAr50>1*gVg>cCZcnyAad6?_)Mfky%WwhQ5Kwrlu0mm4wzXX`RD_Zlu1G+|1EH zgp>eaD$@G%n9zI2uh`6eM|G2jC@()cO_78`7?Q0lxs1?yQg{W_clVTFqC)r7txVt^ zWCNh&U;({~Am3Rk-1-N-HIEg(LvS9v>!J6?v`Tv+FKR}43Z)&z9s@lg@R&oW27$&X z53{~hXhV@=3?{Qi?)s1M%gxq>K0Y~*h2s^@BH8p>WR^}i4%jv(yJzV_*=RNFOv@>0 zW1L0B472wT)H!G-T(Xc#6hRr0nW81NeNG6@rQ;bO&~Xrv8S^|a4e|hW+_en6X?4VP zQPxf^GF7R43vTnwzpdHKcr%|sY=x4N6{Ro4gwv0cEV^}si7CvY$Wlrr&9)wViTwFi z9D{+M!#^HrR=cM#qj8!;QyGW?fm2AV-cY;WI35ug_bbQ8cT26m%1VuR0lXx z7n-cJRzhpt=~NJGC5VrD&Y_PKp0p&VauXSd1Te}bT!9=X+&G4MIWdd@iSe-+h`E}*_jfHA=^2a$OG({IlhC#rny~}?CUoxXf z_!szcDSSo-9u^pvj<9#LnP{gZG3H9nbb?E~0vm_K#kA4i04Bt9!k`(!A?qXU4?{f8 z>6x}fSOikbX`DL3PO^f6I}11!TNZ~Lbh^YdZ6jZK@qX=&ajwgcXr~$(b5F={BBUJ| zP|K>Y!nGLe=VUiWM_tII!z~2P9hpC&$B#$!Cqh>xvAG&Qi|7a4HOK8uvaj)9@xxI3 z7)F_B#O)ucI+CQjYU(qMSKs3j|LGp^`mS)^HRw_HXzYP0RE1ERz!d-H za~LXQp^%w@+^fFoa}V_Bg=CWm_F<(a2uZp$9xKMo?mG);Yg z%;Y7NE7P(d&V9l#{ux8si-u(FepY*cPZ!ezSe45w?3z9~M>9rsV8MdHf;y>>CuKm| zC4{W4&1OP_$YX9{e}aG_|BwT0I`#B)UzA;~ve{8rsOA~x^u~0_XjQ)FbgwB>XS$?)4+g0WLgm)!b8m;sE;UzBF|}#T%z-EBQi42L@{B%rx@o#*T{=4XdPfV()rJ0iXKkGnL$dn1k$S2$Z`T%)#73nEuw zJdUjE#%$#601V{{z9}sO#cF?;Ymqf3bPi(>%#?n)=i#ej3ypikA0ky0hLH~kk~#NZ zWe`$4D1{MQYl6RJ@hnaH0Bl3fCq#tuO=jJO6EJAUd!dAr z?Hx5jN?<%2ia&uEleI{n^NOrda`*}Da;Qxk+A9})2};f3w^M!qZCr)24&^D7eJF=e z&_IxJ(KnICdTTL|_>snzAb<|hjvSZ4kK+)LXuCbH$Px!bKF)$1G9v5=9W7;%%O6on z{SCtNP4vu{+eL422k0$Hm_TzC zsv|p<$KTY_YD+?DdS*X?*Gjy^<0sxAxxJpu-%4u80yrM+P%7A`b^TtJ)Ci2sc@GVj zo``d+KMHseaSDLBFMd>ueG9s7qyK}pSwkkF3)`qsC`_q-~2Vf%$j(f}1 zW3mo&;VAm$G>ZB;totZRA62#bCUpAJyL}lQw6n&WJIruHA^%Z~Msd9-NVhDu4w)Jd zhnbVg(M&UPF^4wcyXHuP_Tn^|O=5)ahfPQ0TEooeqI~pBo%u{-&GjU_4Ynaw4!H5a z$$O60Vb$)-)lDhX`x!pS=o^^CdM3%r{9ood^hm&jJ*8!r1vnWh9l{q7AX z!89}=1-XylddHRPk@d>gpVfjl9=qEK^Jo8SY3c(L|ij6TRDiVPwSnV!;NPTj4Sl30iiz-2#*uo9u*NziAQnSCnH z(?^!WN06MOquwE?&7J0X`fIaEu`;QXpa|mAKDiYZ*O9~UJFq_&leQ0zkh)ry0R_qR zkmo7>MuN$Wk@4BP^`ZMu(ztNgg0#v<=b6C+mY15d$b*0+vh-xzXSj72 z@G&2y7)2S!jUaWb&xr21P=xBi!(z|jDHxUngYYPwk|G-q0^+#@ieN5Tn?v090q>zl zw2}LObg)Q3I=+bY5uRRPyD^;UK8$kk?)zjo3yg8y*nlAK+6IK*jod4b?#~v-uG*i) zhstHTKl6_|f6@KfNZ)n%;OdhQxBUF}cdOx4&TeCUrB}KR9`8ICdR6-`X65$cm>6cf zJ}%289&$~pQFWqm=+MjN1hufZHSuQ(z@nA2jm#()(`b%20x<{nYbVm&oT+7 zsfqUcDQ@G8tH~naQ5GHrdiR2p8tQFf56JTpp*wfaKMAvM^3X`fa-vT&FY($Oa)N$N zM91n2eSF%t`RH2iPg=ZYL9pn1$OrT`n`AVV^aKnJBoc>n?h%?u{2k@J50Z0TW!Z%( zbGZ%E`Fzq!FIG^!;%&wX)6$394$3vnvC=JFSH1YgfA`|vkr$PBUXx9gJpkZFWwaz> zyQ6{k3;KM9j6BF*AHj-zx8^|>(SL6~2}_`5;FA`k)J>LWm*bbA#iYdIgXK!^Fwhi8 zuC(`2w%3Iq(VW+r;4RTesbHuMRAQ4#o}ypp6UYzp_V4BD^TS)>{o^%31JhK({3`IP zty|;E%X^j=f8sCGtlSLB9r~VN%O{+Z$wvC3@THtFN6~$)SL%WHIMiaFQLC0QM&d5; z44~U_q!a@E-9^}^vgY-k4~ADR(;^`OykZVK3DXMSd&ApKRG4@s>@?m|5L7dPaq6I2 z*Zz7snqR4X`fKd?ct-nlqIZpM3f-n++0`g%n^M!o?zP38)_IdpoIz=?LM| zZA&}2+CZ`^9$`rd(D!1{#( z{*;roJR@Wc+oul4A#4dFK)zM1qqZf}Y1e*5LB0ZPiJL-$B`aj6#Kf*G+*Y<{(Se0e zoq+Fgu@2E$%)s|Pw84g7^;yvw{Ze$!|3Y*g#kG$cC_jGm-A$*q$5qn^HF3n$nt0fs zp#on(-l9!JY)gn?$U@o+U`F9tv49@JpB5pm=gyRh4Pr5qmx0M}UUuIxfZuQAP$~U| z)p+RuKgqfVzADuNx{Z74aJUw#;;I20s1R&o!@wy*Z_gv#=;0K^r}*taEn(=Rk+lQD z^~1}%hsn7pe}mV|_?Iw&1#nw-6ccMQKgSy6)(mKp7>U(wn@`!FBMSPGC`-Z#S}^|r z`5oD9)_QpoNK17m$<-f5eIG=FVJ28iItrLz1w)nay6RDRf)hA83%qopL{ai_uKOd# z>GqMa`md}CJk1EHR7S!X?coQ(N-G@YpDBjKmSQ-tU{4n+eczi{w| z^yv;DE-4|9JfZWpgwA_3If>%N85X zXTS#oSaRgBY_?v!7nuz3z}4)F#iov3M7znH_K zMpHKnv8WNz;%O{X2zq>O3-&x@vAT_9MrNoB+f;ZvS(D^t6^5D zp`h?dryqlEnu}@3yr{h}N+Sd@gN*x!SX(jEdcCIfd(vIZbQcpOvWN_6T=`Mo>?pzu z7BGWq?z>nmCg(Ysn!@UdSI_$OD)Kv8Evb$M%?YL2q;-1JzC`QwTN00mmN(dfYhWsg zHAtXnIkpNFNxW)N#>T~d{j~Ief8I3R>6}E|G6jPez}c>ecx4%d-1Z+S}i0(0+Td@+kqIzC<4fq9`a+@aYTmd~nUN!6EL` zSm!+EYK^fCA|Lg!o1*SHS~xT5Gd(>+t_wqhTxULV$vEaA010dVdn|ICw(p$AeInL| z%`VTnoyY;0N%4^hyL~1Xedt6fM_G(gf${)KG0HOZu{i^V6F3f|G@>+rG1a*R$3Zp4;y;&r zT7|q0;l@tk-@1ia0G<_c=`I74196g#K>`${oE_>&y@nf^vB}psj=|wf z9XhL$T8ZiLc#}6C*X<25d7H8c{N(oFc~1sx0u=G8+5VhN_R$;d-cz1z1`agz>8&z( zgCpp;R8j})9(Wl;rF@v({$XvSiy0*_7l8WE`^j!`u(Z`~ZKn0|HX}ZvhF=TaM z7$zvF{n;eE()g#@VlYND;fmr)I5Pl#c;;Oz>xHU2?6X$ zJe`DI;ih#iT}F7F@wZi3tJ)icnR2926WJbv{<~h7S?_0R1hsN^-KtaLD_r46jK5mu zznLv`ZOI7d8*iC=DmB-&&ljFMwYyy5-NxNpJLc*FX-3p#c{4$<%Ar4LBHLnZ z0a+B(EC3aa*D`@LvD2yYiLytOT~p+_M;D!4+U4MqO^+(0>#15xwQ@UJVo`lLxyN@@$*Jb*5v-IBC(l0;s@^OK*S$=^tJ)(*{9n%!a z?x$n5b18xZgSsyn==epcwRe;%XNh+tse>CdHi00qwMTZbd9{SqlZ4R6nK z`^T{i^_t#A@cyGsz(S0RlnZ>lJBwi7E20CCCPA#S2C;V$XOSZ!*+8G<^T+BGTamY$ zgy_{m5>WqyR(lZDlJ!)Fwyo3C60>HwetS9B)sfGjHrIg|1;o)(9?=f8eHXj>GrA6I z5HFehg2d}K9-{Nz8Y^@~R(%9UpPv0O#;t<1$n0LP0q!eYWf@@vXf7v^L`>ql>v(JotHj9*Z;0^OK- zdU|BAA7)$1hsrA+sjy_3lx|$*qKIF%YUQeF6~?7nB$4n??3X|fG=`h2&^Aj!5Cs@O zE~r?sC}7R7uZbx=wCA6CXk{$)&lf7`1<#F_uj*`4NYLhhI*Vd^3B~sH3bt!p_r*N- z#jXMXcy?dxZ>z^Ow1E!A^C?!BGOZ*=wQ;e;PfO32il=$adeN+fsNU>1TV1Bo)Nq6G zXeXXV-NUl8x`s&S)7fbh+>OsBNTc@?sb`?w>2Y^APPF zX=MCd>5~fd$#5YMEWPlHtKgfJbV?-s^tz5B2QgPUz;$ZH#-}iSMSfa>C>Bo(-5D$J z#~9EgK^;1z!MbJoP#F(jM+;rt!YiZWtEjtF`Ti1(#AniGWx7jaZMVmm(3$>OY?gqX zBmQy)&$OZ$nRo0=Stv}7kv#hGtBG@ey#UHAfzVPan|j0*`Bm&kQaUT*#r%(fs@5kV zS&2tTjFBu_MeU9l!toa5QaD2;G0hG1Ao7ML2vETEX13Ysg8Pd@X1V%n;Opo6%fLVDNI55XDYr)xa>mAVfX(1zj-t@Lc6em3Jr?9#5hmu} z+>BYh(R}Q~K|Yae7#!xU%;5(D-h2uB6m*lpp-%{;Oz51K(0MoZDO7aeYajBwKeR|g zJ{ZEg!q>9BDM~(|^thgaIz+6Ni7*r0iU5r4u~9~eYVx>-7Dr7q@=iV2C*yiSqDe9H0RZ!sj;9w^SdS69hc$Ppto#|-?poXC!O;w zf%Ify@*r=xD9~5VC$SO}5n`BiBx5izo$i*tjUm9bjtP{++fxUX9gQZQ2{<#cMUp0^ znhuf9yHnww?=cK6=Lh{^;=h^cypM_GXdpWIEOtI)Od@hsTCh!IuyZa`17OD|;j>#N z@#8OJjU%fjU0$jC+PV@g)*O*XbZdF~1y|q6wwOumPs7TP@VH zJaS`fo8(Rb+iU6&#&sfd5|yl{QJ&Xh9z>`oj;Zb#Sn`67Gt%kDFwE!U2N!NO`1wo+ zZ~LwwqK_4H(aV&fu^7!v71+57Tj`QCX#PSOnh@@PBb#<;5W-r_)d4RgD~Rqitb7S-x!KaQ|Ol0^36_6xp za_Kvi^B5i4h^$GkjIIeg2Qa)>QMmu*`em#ML3+I+V---4iIrB-pZ_Xw>Je{oW_xH; zXpk>lALkwz_B0PD9YEW+a3|Y#M6P{WR@z_^rGs6iPbJLLVK?oh5dSMQnhkQ`m5l$3 z`)id}Jw4j0P#0}gi2N_DdT|-?>S8D#{c0}KPU&c&H` zc-_Vao2Dz~sM^TEE4s*XaGxYVa&q?1e z)9^P}EnK@uQ*b-RoB{JfK9Qf=teFrwv0J{i^^(qXnT-@8~JF;%KfbJRMOsY_M17;Nf_MZ_wW-M5GZv-%mW z(v^4Fe&c1|_x)DF|7=n6B2AteU!23`_q&e|BRoauOKvm<0C!@z`YfGx+dKQ~k>KkW z3<8R2ka2oU-*{~JD!O9>3^P$mP!^*sL)n93yNta)e)pjqMp=Wh4rL1pX0{k^R<`@s zvA%01@SZ+07f}KozMS?s-220jHlm~HhW-(yi?jnXkBfYqL&ymv>xD1m&?zqT-f%4k zn7kld$6%qj7ou~oFX!eIBlj*k@H%{e6|ObIW1ZqtXG&2iq)g}jVYpE6TNtu0G+W2i=;cb~a%5g2j1yperY91~)L$Rjpm31RPhRzKa8tot7UqNo( zks$1qx%WBlufqi&%8(i=Ts(F_Tp%(h`!FlyT-oyOec~BMx~*6Z?975+uOV`prKt|r zF~SQn_b$i1ISfZzx< zOZo#hq=O?0;PhdKYB8oDM)6e3Qp<0oLz$7h{!(vR8Krh~Peyllh4#6a zy?nkx5b4vuv5Jm^nHZ)w6ri@Tx?H~-wEun(0t`A@MLw4f*np#0;-^x=>CAm9eR|$g zBF?ZkHW${nA4>meUj2{fUNPQYPH9Kz1%+O{_9MwqhJ8{$;!d`Ac=@S(>gbL|r^`Tl z9bq-9G@G&8i}3w+m%G`FAZqJZKCE?Z8iXil<6>TGYFcvR6@?OE%Z+RvNW{M^Vv+4D&sG53QC#sz+s$XjZd zsjCcB@PQ2Ax_W2ssK)Co=6etL;ta_42k>jdZ$3&HN*B(1a36HpESVMEI}M(yXm=&h z=au=uTMlW__CvugWu%7IodCOtsGSpez3cTp^xir;vVOZ@)e7=@AI9#MwDzSHT7O%Y zX>&6F%*w6fgwJItxf}ACQw(oipGIU_W1Al2M=jom@Xb>lf&u$2MptEBrt88daGN*S z!+owDeI{?hDK!hx^N3~AMf&QGpLB4#HD3p&FRh4l(ZEiIr4fuxKemVSjdzrlJ-u-= z7~D2F^yrBK#chh%55WL{g8w@%$WN`oyhA*bl~ollV$psP)zVQ|rhB2iIlX-83qPK( zdRqHTdWTzAz%jzUK|1o*bM;EQN4B9lXb=7kOxe}3Tk-ZNUK%)E;KtAS(k+oS-*#;^ zhPN8FMoy`N{8TiH?%Y=`9S5ci=n`&Ag^sVOmPY^u$ztO5^_5w z#pL-u$xOtlS}P)cc9kaUa#KqWYQ;m4f2`@5i-}F0npETtxGWL1~Js%ynQH;$8Fh&dg2B$rv58Fjg#ei$+zzFXx-N%S? z7&5WXUfu`yHAcK$V<};4&5Y13KZ>Zeun+OyoIn;+Z1Qo{3;SM9>f1GbYeM}kx*Ai8p4-QQkf}1FrKQj z1~)n?Sj%gOT1Sl`9!EPLpt|z*Oy@cr8}KXGX;Yy#|A@AMeAY{MI!-dR&u$$MnG(sM zIglLq>C7Az|5K{C{D3MuzVjnh01PF__i`b#rq_Z96O3@pz^G3A5UpqwIFj6l8cg}a z6$a}grY0m$3cP;fs$|Oy&T=ywSXflgBv>YNc;YBIb0_Hf>UM~a51>21&De%DZcbsr5AU8b4KK@`q_@9OUt zF7~2{QnJRH97lBB%D&Teq2J!s@B6k_hs1WU^YfNs;h{KM$4+r>18zq8pLF($jLpHs zm3G9LcEpKhQvFOXa2pJB?fIN*7!mEk{k?p;fBTvKO&fa~?q~dS(RDnZ(xs<0S3+S+L&lnayl0!FN83tVLuwrlR2!p^L9W?+K=HN*XsK`)ZwP$6| zh{>Jj&%K3eFQ;=mK&C=-xQJtTRJsvHyZ53TMmdWjEa`)+hV`+c$WUc=oH5|ggL}^N za88c14;Lge?N7oW-Zl&`Z~Xm>MNR22ENZSFhUG*dA$7fh)Jz~UkfMixgPX~5Il~~C zm^LX6r!I8u@Q?DIs9J(|52FjD>V-41JCAc;JFEmt45TIdnaquCuy^EgIWB8hLnS^4 zK=p&{whrTeRA(Db_4US;_nWV!TVZ=$Vq zfx6pgu>KwPn(&~#yRYK!eobmr17-5IK5LHM+3PwYlk-Yn>IZY|GkaZ!W%3n0A6&EP zLJvQF`NbZv41?MRUbinJa3iD^?$0RR14ZWUpQj%CwnzA?hYb_RHo6~V1oHqlmFpf+ z@SYeRgn)vsDxE@Vw~(d~RqCZt0z5858L^aupbHx*ioKeIE7)64u{TQ(vl23u!UDxF z%-VTPQYi?&pCULEM-e=c(?C4c zIY7lz6S?K;UO!JdZngwWx{hLki*DU;4X@jh5y++OJEpX6ZtC{SJ;HbW9e1QgOk9W3 zrqJPG^5>o=Gh_KTwxgU8cJ|OUfjKoQh`D0w!7xk}+Sh||zDqO3xtODC$k}&&G+x~q z)+9o03$=EMGDP}h7!#3imE+HP_;Hw*6_N9~G4P3iF?$cBM zcxh(pg_3k_dMAu;nxJ`cvc-GKi9X7Y0wux*m~-(?nXk z6#7TBHV(98e*3b>w^0y%{3#49Hb!ZV7G1=Ey_HVbnVJ~+CVKcH;sWbFPo|zl{70v; z8A`)uXh~WD_jPn+GaE2GjA|V%^F@eL!`UnA$6pb6r%_*%NW!p*o#_5DTKk>6Bv}{v zA_^%nzUbXPZxPW6e%^Mhya%oWLaQ9=3`nBedskg7&h>_^~tMQs9w71^YA&@a(WlZ%6cg|CoVLx?=9AP zdfPvschbA|$mDza2$Hs(cI_S=cibmY4R)l~J~N9r)Ou4FEEn)B0u6MIJ-b~dpV1Td z$*ATHn8{<8gOxw4g;70eJ?&_*vBfrSe4q8S#HN1tc&M~b`M}dML=?y9Yu3}edX|2! zh;@d%PcJ}HaT@LrJZy#4UbwZ3?9o|uXYVyGJ$6JanI48sU@LuW-LX|I*3-XTxlUX) zZnZ9C!57lc)U&Bak5)c2>tLik+V(U>gx%0XL7GBB=Dt0!K1AbI(Qh}=I+W8DGWiQV zaUY3l*2}p9pK3z@&thA_4+x#$>CM+>ayy|l-YUD_jkZ#P{RVi-g7EY>%uBi^-Bg#_Hs4o2JJn3gXuLEs?q zI@oEJ_AnR)LC6FG+n$KDL@AZ(k|Q6ext8cigkNe8%IGp`V2guQYkd61)$X^W1&SzT zM6Qa3(fw7_;KxqkC2FgPNTS?gzv8^0`52O{ws9|@#zq5aVUgjF18 zn}N2+MfOE$mN!_Rz8S6kLdK4UNj@gSY{KC~_H9P=kt`w0p5@B&AZd7unM|c=vi}o_-SOM?2et+>6nI zztPu&V}L&cYmIu}tl&GxO$&Ru7or7 z*z3em%&l?-w3D$!7ps-+ej54H^SG+)ct$RS{tfbIh}=1xdW9K&;Re5Jt=CnbE;>Ag zlB+6XPO;jZM$6188f2B#ZY{ojhd zp8=DRu*YNj%QrW)Fy}U*LoI>I;D=p1^2ZqHY8VDjO>${Fa0Zv)!i%2Yk2YlP=Wx+nb-el@ zf>$D4Ft6R2w%qr2w`d{MQdoqLGBCkA_n0-fx+Ryzu08NdKD7aLclWMp+1yH{hxSgn z;+UtYyYTb$Cy<_tqNQq;eRaz(5YmmUAnxFCJQP~1Ue)4zsk{26Zg771P&!k^5JqQT zXnqoE*kG7xr{FKemZg^MlDS^GSr9@*M38cnz7kbMkQAuM~n(ps8JRX9$QEmR|lX;VcBSTjN z1quoLr(7g~L!Tkgo#R$T;`vLJ_f~`5(-+#&J6ef}jk?~GTkh?)K8F4Htqc}fp2Sla z;4A$Y5*iaNJ%JihQ9?qMCH!UVYZ`hBM7lb@d-?osM1tnK`T6$wJwj=Zvd7MXHL8E1 z#$U(~1Z7h8d7B>T!9K4(j@dXD`@F~swJ@*e<#Ex5zsN5okc)I^2!%cNJEPb#exaPX zdq%g6|4>dBMBPi&S0n+vo?-MTiXbPMOz%dH*j6)f{6)5|$s?xZc-Pk#3t{LP113psT&zExVU8GM216#Ass zHL=^F&V>14erBzK2}Iy7-pdx#$tFFZg07qUeJ_k^t!wD3HEP$#0EF5b1FiOiZnBqt z#Ja|=>vq8o0wk;j^av0Xwwg7%BfxCF5@Il;?AFvymM;scGGzxk}G zFAmGGsV*+Sq!|RWLf5%ZL1D->O3PVYs8h~pwV%1@`cfv<6j=Kw7qcEM^=gGzd%4@x zwd0sbq?gUnvSwB+Cm6g%Gp*TKjKgO*VkWET3y?yJ?^83;O681KSs!)GGumJ64gIRu z`lx+xZ{*kX_my7vn%qUv9Ml0@V`1(JK|AI)CNnK35^Vn1VrHJu1JAl~I z<9I{$lf9ds?A`uk?@MR4e!qU0ou{(Ac5|SuF@psoN^Ym0*0cK_&7GNb-OiMs3xAYm zh-G<(wsB10wKTG>*R`&9?wPpnmp{?FdRULRNtz2XsqL)}^{zitJ1Dzel8Vspag!!@b3zg>v;o|Pa!edrl_<7%hbHN0MP)eZeqhK)~EG`vkQ;0Ep%lCIT}W)bWe(EPSYj^%%fG>ET|G6XMGw;&}T=+ zsvH-Z7==3wH!+I+7~Tj?h*F6aFsOM0h18tI zh8flemgJ}YaCRAhO;p&o)yI~kjfT@^HS|Xah19t&o|VFj-A|}J+(j?vF>zmQ5cswHh2)j>_(Oy6oLuESfWgXq!^PlF>Q6%ArC; z@jyyEq*##@d>Y&8E7Vh|8w>JRUGN`rfRTp^vUR|1REOAT8v$BOuP_mU#Sbu0zhDSq z2j%u)h=~@^#ElF&*~OYEUt7AD5ndgL=+%+f5VZ$3YbA3$L}B*s=L-K~qRBGq?xof~Jafq>Ka#Pj1f&nNZ5gzWdy z-@tm_Akz^I(dCw1xCf?6HJY%;yB(w1|+`irQ}S9g&zireK# z`-dPB_#+$Wm3bT#PIptcHTRJZaqd2?iX0h2Aa#b(mVZjtUW5^muvsQ4H#Nh8@W@cx zUiww{k)hfqc^CSS+S%3NJ=QmYJg9Wp@P!}e=O_K{ld90+p;|gWHy(_<14K{w5z+3q z=>%;XY8#}LiY@R~2XB%}w$hK0e_W8v#0#IhG^4eWs!4tpIXHyX&h^!W!c^Lrvrx`v z)flh!PL1F4RK?!(t$b?T+$YzQ&|hgwA|I%@w}&)e$gp7wUDIpwMq)ou~*C7aE>*MfnI55&W! z$%_*bL$A@f>3(f!Bz`rWvi}LJaIX#_6o7)2@=>hZu3%;7g$9A!Vo>bW8{#0e9&cT} zkG1Td$u$jW&d8hoL(noz4(t)YUg|-h0zK{i>%NtfXL~1Y*xLw6tmLd~+=mr%GDntLNLYgD!A+d3y zpZ~LpiyfGH`Oakm(C2B;IJ_km8RM>(+R|awD##gy57$;R2|8$)29Rb6*kp7q@`DQo%cesR3 zIr2R0|A#Q&PM7$FNnnennbN6(WrxcB)R1Ddhd3VY236?Ep*FfQQ7yE0e57s&;wUu# z2sFKj@9-WS!8{8~f-@aDyU84%zRYwo4t<@it`R2Hw^YuGOJ7&xn-pne&S9;B!{Bo& z_wR=aK9&QmBtc|bDx1RDuuDXvye;NCypo$~P*D#i-=xq;{z7 z4Ow_ejy$E}a7_7|5t$rZfc6Y+F@6^Zd6yw$``>44uQfFZljyp5RGUt{;v$<=k(wdR zZrNQkRJ)6!Kn&;F&-~zeMkc?ea|QAJm8p|U9#^KdFrIBO$FVsKNuG_{vsg(OFZ>Sv z>EzRyIIplT-ym227TzA?{|{kb0~b}5{(sLM?l9m50daf*>)tEkU^B*ymS|ElBSTo& z!eoT4w%n1>cD00TwbphK9nuYV6@o=eA03+vXOG4r(F+y;{1f5bpU6!lS^5k<&VkTGCjIs8iXE!e~nr4T?Gns!!MrXX_nkN`UqeHl;ss z@JW(;9gGvAu{90sNRx$%UNAujF@6ER7o3+dALA>SA+(s#Ay$k3*9KZMi?818@FleM zTkO1L{2t1>tjirpVA(n7qFLz`c`(>qk8~9t(#ofwBUvweR9pnUlAk{pddv{|xlSWh zt{U{aq$Gi50#@b?lwa=A5WYcS777jE0N{|!MU7~N~Gk?IV z+-mf19&b$=KYX-x(v;!DtvR<3Pe}hH&RPa*rn!5U4L6YdekCl~le~Fc-1!2?@Zl#& z_YMSqI2pr0_wGPH(091ySi~@3?!96>+1|;y6{v(g; z4D==}IU-k=MEW;@KeAS8pzCYgj~J7~&yF2TJY}tmD}`NqCF<{mKOWL2NW&UUfE~Vu zxF0gK+p-W|fhQT^i%2sPzY7sA#$!U>#@G696Y-mg@MJvXH|sLeB`ipArY$5Jei#SB zse*_L5KrxlSqXm_{7`o27O3}F`1U3Zws6JQ!Gyagl$^&G&5qOAC{JGaQY((*8kg=b zHxG~7DxU|nTl8De22Z|1g`sCIn9CjxDeZs0MF~7&f|YLw_m&SuClOh``4(T`5#NGP zvkYUxSdnK(NWhNeU#7%buJgZas7~SVugsCO?>f^Hjr&|>+$_(LK6sGAzhkf8Qs%bX z0~$&SPJ9whI^d!N?lc~uQO5<_owu2xfj<;qJ0@19Xy?x_{h{uHF`AWmM_b0!c^i2S z+Sf{B@?Hnud``FS|EzES6aV4MoVOXv3RJoITegU1=0f@hC{O+$&Gq0dj=&?1(op9_ z2ASm1lP+*J+}VZCXvKm#bjQMSUvpp4FZ0k>=2s!{wr|wL$?Sd-%@%d!nVv{lQuO3Z ze_NkXVsV1;H4V3;vE$TmxNNTtu*UkvssJai(E@8%tyTT=4B}9cldCnmA1VMDu9#!t zc5x^l(1I-*I?d%bnrB}`!|XXU%EunpFwBY^@30wD+^0J`ajmelG~-zMq*3Y5Cc9>U z&}B7mbh@IzaT2^PAvDd9wb=Z6`jGi%vs|&e-@G>^eNsW$jAz%VWh2MQWg7bjwQT%f zlQzuP{`fy2Z%%B9)(5nj!QPV;6x1T|2a8&k6ffVeg>Eu<#`T8Y`q229CePJ`n+(k# z6AHKgRI{vO#agGEno!wmz1nu z{yJRJmJK%yQ8Ly&*bXl7i_eb#TYFgwZiI%L?EAkxxlWAY&NVWRHsoAq0mtTjiXmp_fnmEY7kGHxnsVzq=~;ZU#65EzA=;Gsm)8|d|3bWvuO7q_csEq!=mx%FG0nH#d~ z@v;RCLzcUiH5gN>)~;(N?>bE1=s1?H_iW~t#YJlXmR-Z|g^ML(ZLk1OO1HwrX&G5NE8SPbG5tEHHl4qxk~B6GX^ala?QV06Qdw|`}8zZfl! z+OoJJk5!-6qNnrC3EH&nF9MR|HRx~V#!sR54Fhdt>3YSZ$WMDtqd9553L3=dbb}D#@_zU#nI|p{fZ6Vm$=3y7dgUS z7om?D{r1RgF*Md-f2}`noidEOBY)<)30CE94wl8dYKVTuUGlXA_jxil5yy30-nwbi zDT(8L&J*Z^EEAxvz|#MEgZ$b#Hk)dfx1Vzal6C(kg%oc7vOhG&aBL;{t;t)bKHb0E z?lp6F+&**N$C%h@w>sv< z=AO{-o%>1S?b}BxwkTA~DV3g)`uFMhe(H(lrhYgZ;)M|gqwX#fSn))I$zR4_QtwBY8ry-$CeQZUD`4`NramEz7rx4)y$9Ox6_=?7}P3r2WwiW}jy zTK7KFoWi}3+`RK*AGp5s)jNcHafH0=52luvQ#f%{vw_?D46EA@AB)gM1Ua0t=62VIo72Iwr*x=|$ppt16}+@l((9lA5%lq)9jEWf>K`~0blJwTgFYC?4FXi*e#{kJ%Y zeM_dCAH)NzlqoUO>&GV)fM+(Gvwj!-`q1f5M^BDzJd*fDTgSmR*hJ+U5Sd^4W90tk zD9#ZmiGKY9cc3hK@}7aTFJqTAu?{B`3sOMNr6%cmGvn*l4f-V-DqwY+3D#)+>H7J5yL+q>hI>9uU_I|>X@i-@6s5B5pH*KRMxRr(;861Rp|qYa>bkUdN7VF;MrL8FF^~iY}H#RejdL!`ADwT3N4a zBh^(KP+yYsM+VkztgLB#bxmdE(kJVA`0POTcPYC&pym&=o`!>b}06iMyrAtpoiICAI6)dghInVgEc|4Tpyl#flyHL71k4o3Q%nI94y5}Ff zfBRtRF3^Ke+5lz>s!=>iKy|OW8-(pWkRT~dX<+MvH8ynvSZp0VHE#baJ=L)sFXNCV zf9wB=9WEt}KVg-!x!GaIl#yZm`j&-ibgEN(G45aX?>`=$GJQAwusn#_|F$iP@ z^eBxJ-ra#puRIQl48G>4OKz6PQRcYNtD3nXCZ)o>Af`$l2WFRe=$Vm2Lu-11vVwwn zS&sPS7zt-9?yX<2E!0X04!pgbr@E*4d(D1C15LX{*}@CI842HX;C0Y%HdCKHEeh_Y z-=yTg5l!KzkXc-8>AB?5#S1fz)3PHV^Xg6PMj94yLuiPs^e$e1to(HQ($hs}Zh!_y%j;ctfe@S- zC;YM}_cg9CK`S0!HvDJiVH2wYkH9mVI;H$)S+(*_VpLp=IXt0Wo|44{wl$jXn9#sk zg9aHHF$N>p3-V3Qf>mDirdeE^p(xPX zyaiU3K6OfkeAB^b^8%%-$%*ztJ0zL8XgFRyY>Q*<)9_}E8lN@-fmRC4g5DR>vB~<7 zk;I=ub_$X5&gzK%S7Is80hHE0u6~l-D9G=n$_XtQ|jMv7-nV zA|t`ug9%=MJyJrbw4*b?u*uV>9fO|&^hucCF@Ev%qH}t#SLjoZ;ufu##>yP#%(DwB z3a^GoS>&uA$VuO82fzQUW6I)ti{68Jg_Hd;lHXnfXHU^S_&vrN5~FHG6C964b& zb5R&}MN0eo!Dg(yCUJvkYEZd)G3Mn&|D2B77vFgJ*OYqIK*{CsS9C+@UMeQinr(u)f6TLFFpo-Kgu6QyES^~Oke=tkfjsx(ORA@^ zW1yD#gE?kXeCQ_~)Ta9f(%zxD3N`;-6c_p#ZxX%o&4-tC$~Se$H!Jd#6Jw%9*tbp< zV|Y=_H9)R0rJ$g(Ab-_C4%%HsyN`Bd$??53OJ0gKheGoJkWBpbw2yKpOkZ+3K!sn`5(Yqb6z!JrvI;9ypLJ-UVzW~Km zf=LQqqN0L5#~?1w?J;Ix5&%mQn>Ph>t~6yj0!i$?$a?`fu)R0(9&!J=fgsE+j{(0m zWim>_In~-2ojf|5w?e3#;F+&k8=;sbxO$p#AGkb*RwLiyBLy~dF4$r)CQ!`~oxvh6 zx;729xuHo2SwPcLcOc3CGbpM}_hk2gS_1&NN{|rBZb?Ih={-MkZ!s`%MhpF2|3htN zw{hh!PXUbcxMm%lqpFx%b%ef7Ga-9GgVK{sLRJq%7sy!OR8S8~aNY2`!N4g2>-axC z4V5c!{StGZwHS)rbi)! z#Ewle_zanEN`^tXy~ik$6h37VIq84O?zy+eBxe=Yw52Buf!AZs44(35)!E=94giyuQs8k*1peMuxQ{1T2o z`SO?heKPYc;ARf@jPGgw24Aw!Mt#d-9evQsE|X0D@jbav{znx7&i**O=(U*}IQzI$ z2;%frZ6J+*VpC4y>2DgwLfe zEQXedr?QQ_PJO3&Zsh&f^?-ZC8qfr;rVZ&l-+m}bOCxI>LE-F&Ex{|t1QrrtXL3Ybgt4*L^bOE7o-VC$ZQnIC%}CICv+=Azzt`w} z2L;fUAWP5&+(4a%4^8$VH5exyo`-@M@8%)_x zLH*#QZr(UG3cABPv-|6#xxb~%T>17iMNr$|KN8+EMJ{h8iUHvnOY~t15Bt5)XdZlD zW$zxxi*2(w_BvHLK#@L;c0Gru5zpqE3C_u=7#78_XoLXV)Kh&OhkrH(rPtEPL}9O7 zz*Kr?`S1tI99(LdVhRa8&BG`uS)rWP{KNQAR1aE7Q|ojGB$(3bM8_K-I=ms~Rc-z> z4J60jM00JTb$^v?<4FVdjg*%_f7GkCXGV&C>>;`dvQB+8m4LsFL%ASp*u+s*1xjpw z1O73r!SNfXWgB5skOmJasx5S#mQrOdj#Jbd%w6Em!9v!tTk)p@76eak*mxS2zS!Jt za6ab>Tmgr0xEVUYAYmJsS%?wx+d$NoAMX>39vsgW(OG?^r4LQ3Sx)#lt_|ytUgF!Z z7F!zRziR#{-v50V2N3{=#J;%+IsCV_LC6mQ3D1YV3maQB`BxhA>J$E$W`B;1l{|Xr zQO*9|Vx23HPvNZvCxM6V;Hux(JmvdekC4OhQ|Gv;|$RAlXeUOuj= ztnV6n8Q($NhE9jC=v3g&TFh}I-g9dk{G7;t=@ScL6#vOEIwN;$o^Iwp75))sk0ZTf zYl051m5O>BuR4LGStoUkfOV0so14f|sm*NvWd}zp8fDPG_;)xr6;0*pfYr%-S9p?! z3HSm3A~Cc%t!``Sy1JZLDhD;x%Gu>(PxxT}EZ^pBPV_a~0k2Eo&^(Q+U>C^wczA81 zgLO}p$(!hx?Z^^3!-T_O-G`i02Tp>`=PwVyCe9Ou_0aRvyB0ZbD1r0(I)?)9RKi~R zmKIU>hWY%VurUQKfu<_Is$Q1UgUEv9CVmnO?SF*<;wYR7IUcfx9;YfCv!tq znNNy!lWOHjU$2e#?+xR`E$j`$+#ZEM+Q{oIt4D#mkH7uLR5XWN(M>%7>8WrgT$~8s zAVv!(>|Ba8@E3l`C;VQ@Hu>KxMpZ zUmfph3|GTbCcx?aaPFJ*V&&NyBAQ$?E`zIF1MS%oVN;u;P99ugCH_rxg!W>C0W6wm z+I;e4^VjgB6oy8)@NU?+O)v59;pPCnWZ7RBcKz3Pr#f8w(IYs9FuBZJcNw(n|EYQY z7Os9qPyKc{m&`2)_QpllRu1R+Qd5=7*T5e40_}5^N?-?;SWwOAP$zV%H()vOs)Y@s z#<2cg+E5cr{)RAg8}ZMxu}y-%@vf+2#g{9@p*}I*3)>J;Y!IW~VfCW$a$>D$+#*+r z(QEDS#W2;Sh%rF;8HFg;^D00<^6$c7Jv-k0+$W!lY%-zegKtR~qCXs>z#DL?)VMJ;@&$_xQ8>73Rcd847D)S*Z4}rGjL)oQMpAoC{B&9S8EA zEEE8CiYTPgn8qY-??_L&IbBJFHYq&MihQQDYQUq0c_Z(+*s7>}=yIz`mZSut04{0U zhlRRYjrsw+?mJI!D{&g2Y%f2)zi?SOZP!gzHE)E^^s z7nDV|gqugB4zS0zzIHEHh*v}EbRdSM$ z4yWen-0(VyM8B#2Lv0opelyCU$8oeRYir%zu4TOhFH50rfSK~7_lMSmb3vZ|Hrx!A zFq#8S*6KyL?tOJ7Ki^)JWzjOdo>3xjh9 zM5fa0o8+>DWQRP;OGJ37H}tXj&G^uxVQB6ZRl=o>5uTm{5|QC0*eKC^c6Vd}L6HMG z0HLS*UufW~e+JbH-grOlGoI(qW)#Aw=*J_>_0TfrT~03wkJ#!YdX~^6Vc7f+hmAB( zz-7X6SB0ABQYM%cC`u%!^VH;4Ol>E z8EG(FoFt{Z4oy7l7wf{N#1|574m}XgeH|JYXic2|9keFeUm9+H4e9NNdO&8Gw?*Jf zoSWnC?-SH;^NUm#fb@j~6^b9xX+On~;w*$w^#!a8h710ZaPzZd5QDkFfMRkW66CHP zN>63~*A2E8k|rRLu;FZmE1kD*??f>;7-44Iuz{LWG6rMOfcp{-g3&@$DvBF1tumI}*KsTqX znw}$^>?0jJ1WMU1!n@!o5SSNuUTJHojTE|Ku+U@w#~mo4JStqck9lTdWnWR|Yt#9m zl{{2#)G;lO;A4c6*D(vQp^0sy8fhK^PUef$B4I+jP<4V*l78FH7(e_+j#vf?+Y<)& z75Ykpd_+QbIRMg1K5~l)l>_sb#r-&1``zJY-I!1Q7uuZcW5c{G$<09BCDgLvTNpb| zwLz&Y05!LSX#pr7-22Dq6b>3=WhLKUD!EPMrb!UbxA+F)&R;6QHpd}x=-D>nPficR zrb?dLgGAPo?DoI!qszqUZ3mrylMtC;ea>c>bZ8ZZyfqWgL9+L`?$!wC+Ks1)y+zw zyvSVp(`l};l&UaE;2FnZu07*WpIKKF)fcGZq*3?ZrBC-*9U*gcQ9uQo?PGU)Asl9f z4pu-n3Nf}YGTm6$nDJ@rp^0!WG!g!P)6I}R^c$LP|Cn&|zcl$D;lb%fPfXT5{SuPjHbREz6QpN0pm;X)Zo$O_oD7K zFcnugfsR9m*{6{iqBF!M8dbJ3jLmO*C9x`YTcdz(*8?fFVD7=Ct`Bi9HjJbDb*3`= z=TPg%3Xp^pR>4O5*eEX>nI|eNg)Rre)+z}m{qrc6Csr`Cj}7;-WCt68FUb9YCK&0n zX9Nq%sUBkld{cDNkxMu@&MD!^#G`AwjnLOpNC+DXFti*>qBpTwCzy-4@|z}M!YWyPa*P(y9PHCNw(knUS&n z3*EdtLIMl$yR{9`VE~1BW>jc~21i?pt9bezY!UvoKpFW+ zjp3Xe8C+}@d1L?>3C(sigz{+xdaCbj9Rolc zTYy$|EVYik-A!-;PTyQ{cWRD*IpAaj!O41@2XWPB2%?WM^2OQ>L8A1m~-0u~>Ek-Gy{LeWdph2>Bq=+yMyL8wm|S$ZiV#7le4u_W?pqn9U7l{USTh=r&9r zN00*k*XPOR`s8Z>W%Tdq1|NR_-hM#F z#1^+_cQ>4e$?seXR;OtsY`w{ij;( zV=t>}=RDpm!&}ba(K)moQylsS=lKhUA~7j)5f^0Qyvp+dKn15u{0oJ@bc0W?==bP? zRww7q!bjc2U5RgLFtIvkdO}j@mF~z{)bmRBpn(z$7``IHU3j@$H@phHKsaZ`i;$~g zJ^u}li1#!+nRuLdO7MJ)_$659b$DNj-|hIV3aqcBb09?Za)+t_+%rFt^o^mCb!4K4 z=0&kXL}naygvJ@KY&R-BNfXU>g-UI_*|P6C;Slu<$0BYxW4e9By6GZE1dsat1T|Hv$e%7 z!|?iL&U3uANC}gD!Al&jXymwbc)|FmCPO~-A{TLyK)%lQYs^LS0`DVGySMMv*sT<7 z{)869>RDr*`uQ><%i$yTl#t~3pYDbXe(-FmyV(AFcUh7kZ0v>`78A=WB!fTR7%})u zGQy}Z(<~|jO5wxl;I@8nZbHBBj##}5Ct_QC!tc9{WOxJSzW>!&_VXVghw%oO*O}^n zs=K<2RFUvn)7?yRt4hp?5+EfhUS+~pvA6*Cscwjv;FT}*Vyxtla3Cg8L=1Jwf;;whxVDd9I0Po!@D_XpFH#-QE8I!^dCwG%~nYB>L|&`z|E+Ua>8_9LFRq20K&B>)|D z&u=-;ue#xU78i62AMjuz6*X{>R)p4Yp~t$xJ@W77fijCG^IMTn&cSSfA%1`Hl3Q7o-`EB!a}RL(4&J>6)}SF$^uLbb=FX!=TF_s6W0`;xi@kq z+I*b}%s<8RCbjM_ytIC4(K}I~G(44@r@XuRtR|FGy%>U`OeVa}OM#__e~VS``8DTx zxEq>gP?PsR!TBHR);;FHw1k$*3NG}E?p$5YNN!Pg@zRc^MelNQgBE(6KEdg&|4kZ- zq8*(4n&y9u^Z&dX+yePUEwr3;ts>*fKD*?WOkOU{{07^ulnsxuMfp!%aCKbDTaCBn z7sQ0Z4=?eav>)XJWy7OvQJxbQVA-pm<#uIq+>RLdvioiSZ9I76f5ZEGcp@+oRE-^K zbo+akVhZ`VG^NmF&Wy=hSN@&0CT+!cjy!Q;+G8e1Zd`Gi!xNvEX8DUFXDIsv;pBt7 zL|;=v-aoSbQur@z4r~lWK{R^a zi%(Y)pqc`oNFW%`5DFqOugwH)Nq3^j^Y8`IItgELeFFbq^mU*5dHH~QDURbh(0+!# ze2L#_Fy9QQP@F!v=rL+U2=Vj`)#O}Tv)IqCd%0%Y^YHla zl;PQ2NVqS;=uYcU$91ad4mAVd)uoQ-)v;Xxu1m##+zdjMfm$LeKSP(1JQracWC*2w zXL%4Zw~sO>jj|rBk~4Gx$#W^2i7Zw#J{vhwaDu){>yXEF%IRJ5c%6?umUabF0SFX8 zD(L@NANH6O#auPoJa@F?N*Oc2cygnRVM6GZZsR#E0-Ky93BGO%e6(Z~xf7AZ1mVhe zMH>?~Nh4gp_#miC@c&yqhigi{WU6UjdTBfCdulr16Y6b^&C^G%CM+TNh6aPAITR7D zv23qtK-5l+-J?frx9rj*aFGcB7tTm$_4*Br?mQB(vf>WXZA} ztB_^t;W*1Kc&TDG3fOrP!t}z3p%bRS6A;qWmQ|)GQ)(~RqFoQ`W0bzu85y9mwc-s(P@leP$1BvB`m$B9 z4%OYka&5i@XEu>sF|4c>$20LG)=TQec-sa&U%Y|pgEb_?ZAt8V3SVg&(N?6*PFLQt z&uE=zi<0xAIDAEyCzrdT%?>!erz>MDbYoq2cOgq&S`4enX^i4X_SQS7B)X<}tkast zIp^tZfqx%12d*OKz>An>zgM%c3>d71KG7gieb0uPpk&W3>aD@y0{X68Wg6pTO|z2= zWAw#;rC<*J`>|&PKwFl=U|s)8AlKfb9poKxQKFI=+;~{DK-K+n5c(~woYn=%-ZHD~ zw(&*Jk)K~b?6Vg0bxFc+FSpcNY<}2P3v+C_9JfE4CTw6xDw1M-Nt`%xnK^20Hpt%n z*+Mk8--b+3Jw-d#qYbD(h%=DNunU9|4_->;$4`f=5gaw)SEd`fq+dnA8VvUg7WBdl zkM!V14?1PD_l;h_Az$T>0hz6@zsyq^3TW_~1$ln=m$OWkxpInw7|k=(?GOFvrMR35&LA zj-K;f^J1rF&y?$aeOhAGdKte!8NM-`-t@dNGgqFJPY;%mZDbxQA#Y_*{2hw%1Fh~^ zy~E4(jB}9@wdxs*$IMyz!If;$Y|213@eT#fbK0<8)|VzYpWs(~N;VLKwi*U@r*=&YO zvBl2MCdIeBIV%pP4JQbWU|3>qG468$*bdhz2b10PXV^??ubK%s$;gFT$e|>d6QSUW zw9B7OkxltE1qV5kv#3(jlV4)llsqHlmyriMf2gP?D$!6hpd~K(vqApy*8g? zQz(^%`4hQg9>Rb-=i54NSbOvcA*POBtQD>Jt-oPaV+2$EV%0UCyWm}uttI%!DF982 zjQ~5#zTh)PEtj?%YZllHjnQOIS)5t(rp=HY1+yx`Gv5s28S{8ePmw@CdA%|C%QvF~WZ|C5!zU(iIQ zt!aEq~Z=@k-W!iHEri5??{WSEUWz)&uL^P=D6lnbQL%T;UXB zXi4z=`Sg|4uJ`)$W{U==I}q`6Z9m-a-gf4w0^|Xuh788`(%jhJ=+9#rcSC~NMk76d zS~5$P7Is_9yRFha?T_Dcv@CJO6ik$R+?pjh2_-o+dF}_+U_dF|Icxd3NV>+d#EQRu z_`fC8wCMhFO)LD$s(wXje|`^A`A}RLtz+K20kwINO`yO)|8_*q>mb8^ z??hH!%B|XptmF8`Uh`2?#cLn3zgY|4u}WO~eVn|`8a@A3r1C1Om)w(3c@I?vM8rLp zxbt~JRJGFD9a|DWKhS&0TJ>QUC6LyZL{gTl&5hzV+)9x?Y3=$*k4x5$m_G?I4y9_z zq=d@I&h4w(Ii7%|URpD-b(gHk#YP9+rZs~ry6~NaNO3h8(oCmYn;krmqx%zyw47Ra zNDjM>@ZE*%x76pRxmI>d|5@I?$||q6wtdt-;RuRQY)@u!lJscHB+)?Jlwq-sVVrYP zV+&vR63b42KAZ%`Xo*!lEK0EFaYvbf!UUVfV@< z(jS&x*eXxjyIr(+CCp4=sZ}kFOujsy;NCIr$tgV1O}=qYj<3E%lUH8;8`pi-!uzaJ zPWyd1^eJtS0xMlpSlCCo($*A2uwQ9pzH$65am}(8_G^QgBI~^{&#LBKS#0ics|HsW z$f3y(4%{72&Xtbzu_JwGGVyA9Ahn_Q0f;+_bt1KnbDqR67i56d%Ak5(hk8A)j`3VR zzz4GJpL}cf@!+2EfiZNd4fdPgxRG3!+;gKZc-eeuVnwjm{KLemV2^q8L~t7UyJ5H? zu7VRL@BmM0Y)U6;GuPvy*MR-s+T1p~JKJ~cNN9UkdZ!M2h-QrqpMsJ_UCABpu(Sap+AZNmYw#l2 z0cr^DT~k_0^m`zJ)DYx+Q)9+RPOx^^PYAcn;_W-gg6%!ZQqzD$aCF>vGXmn6vN16* zxS>u8CwlSa1xR+EV%w=OVh{&R5b%3Cdo6`c<%h>_=bIlOwUpda&i<_CpNm!KU?cr+ z>c69KHly(9&@TNK=6Iz-P!s;qf)kCy)7c_Ag#9f_Q>w18aHLm61*yS+HX#!y?7bVW zlH;a|oF3USU#D`)N+7nUOR=G@Te`}qR1)fPl-m!t|5F2_5>2q|Irq*8Y;p>hTp12f!6U2}3{xYmW zPO4Cc`&6@k z|NdUQ38!FvbzO&iy{KhDC4q#2~xfup^u z!KX%5fLp6#>cFZM9geLR0qeq574fEQm=U`JAG3ETsyQAs(k#V#7jROtdr_fd zZlFfb^)=f`-^D5_;skqTApc?TohbV$_Okw2G@3ZvuOqHz`M;y&e($26h@Wm2S2k+P zQ>*4ITJrVAQ`1eZ&v6boS-!7OAF9xLCIMUF&OYm1g5g8pTyZ1&=>%kl&OKVPnr)!6 z<((RC_U)p0nDTQv-2ghQ=>;ul<$_i|2J7r*Vfb*xIwh2hzgZsoJ4>LycL58zw`Q

y*WBr7@6GY%l+uI1ja*7vjYG1f% zd_%_MxCvgT3PuM6%X<P5^Xp;dN` zqngX9P!jIYbqD+oMTWYpn$XQ4qGlngN z$ttR_E`=p|a({JF6Xf^vyMO<(v3XECt<@A^eB!qP8 z3(Gy5=?`Oio?F@aqPq_}ZyfbG8hv!UdOVSi=VA4e%i`amepNy zI11OeesQnnI=6>Ys)uIy$oDcgDUjvq1O(GrH?^~F8rMI@h+VYIX*Z2gtS*?CSc&F7 zLw0r??0Q9JIHL<7d_nhhpj)KM0S@M)ehv3AO)Z-wb!!e)6 z^(#`QT<`mW>iR*qG$sCe>M_V4awDXS&aEC$1^?{><~;MnPki$DmOiS9B=@Anj-j-o zR!lhgFepr5nAbCZ+qd>NiB?QmSVDeW@;THdMdgkit?6LU5!KnXmLl$`=!Cz`@aP#S zD7JzE<}@H*S3C)S*^p;5$5V!Xyu1E*keo^r>ZndvZm;NcpF!j2Gnljf27oh#5##!; z1!3AwXFmcf_E|6k$$r&OHyWZX<4H3s zDXKCwHN}yYiuQUqIErhG-uynth{*JJmB@-33d;ys~_jmkoJ0=dZa8=eRTh zuD#3E*ZV$og6=WU?Ov|B4%;D!P73V+T(xjL1J`yffqZhvE9dGe=FuBxmtG;q7G0Tq zz`Xw+)sewJ)6;koM#;xRpG|XLz!xp@@mD4XeR=56B`}wc;`qi}*)`PXgkx=)6H$!T z;(X`vDTdQdid3f^2#nak3u!5R;c&rdga&8vH8u=lZqZCj&!OD;mjrZ=!iWj zlbn4KupCWp>>`j?vh^)Svqf>-MLgV_hi!P=r= zh5Es})PI@6WY7nxzsv7|gDrTZzA2`mQh!;ruQtkQ*zQd6xxU|gbkUimS5`@Lc(GuH zeEMGIUix5j*YS?78&Z|=FEF03dvI)qR_bTCGyt3;R0(W^Kb;<#Zb(#5(6D`xFn;4@ zzkBS|scat{-cE=)_(ogzgalTiCKKMJW5MN;4dL*p7qdZDpePSF^^Pr9!q%*frDbnF zEH7E3*ubpR2EDWO!LhR=Hpp}b{JJ)5?=B$rao+XB`$`z{st4F?8<6eK9P>`QQ}pJFzV9DO9(}@p`1=9D8$ZZGdTdw!f#3HcrD6 z;mmsaa1JzuY(mO3MS4p{N@NT3Pa5+@gU<5#QiXS^ZGP$x&ZAH9^JH?^=im}Ln19ko zUygEZrG>h#%hx#*&UcSE0_rWh!}Kd7)U@uSH6Py&vz`a>i-m`&xHGQxHd0P>qT?adXlZycjl}0ng`YT0?SLS+GbbB5q&DrHJW~abDBquVrK=%$PR)zzk+DeF!?a zFbf*&rwq83p0)3J2}Cuk@1!#$I)C1kz7tN>+pw^Zfu^3ON&6P;tnFL=`8DY35|D4- zq;}g~b{oO2zxU`h*aiT05T{Ml;!8Ha`$zfw#>~Etp|)q)OGOkWhD){niL59_Q} zc-vpX$#UJD<5?fy2xG%$-RQuYf;!DgM^mw)Cf$%Y6{JIp(Rb-%=Zne>O?;ErG@r2; zM>WyvTLB9PXd`Hp>eCHIqZj{I#{c!6*6&#)TJ@E4tqI0EWh{IDcx8q6PWkKs<#m}Z z$}b`-zgPsj$tjm#g;(P%D~9Lrskfe(w?TZJstDKMMam$N`qy-h&B2(8x_%> z%pWOUI8sw?lFKY|FL~L9EN+cKJsZNe;nt_rr61xr2%Y z+^g4Jf-w5;%OJIksIE(bEi6ns9nWCEI+zKn0_Rc0LD$+WN znp&co1558-auk&Is20fCR8i3af8{J&v8;C*ow^5IM^tl~%?DOcrub5AFbw7|yH(QM zang;5)5p%`-qh)BaT=|Ly>dw)4#0q(NG|GCUzd!djv#U?tkhC$9JUmzuJ2edhE0zh7-3pO?*hdBJyayjyRy`uJ=Dpu9lAeJr z+>g+P8E6~39;3A5#GrN2cI6K^>z9Q^t!>-n{>yJTb#f-CKR@KwqGm$;KR6EKzAWAE zB0gp~0Ebl`WY2l*>fY6|tE9jmGEanhVKSH81M7D`i;K(hVM5M8mH}xxBI-);#OTPV zL3K~BjJc+ULzN?=4#7C{{j!ncr!b&xG!rJk^%O|r5zLj~S!({l6i>z!EK7%{Bcr~J zJHzPndQA7r^jSR_3dYOzM0!+&;?@Hq=FojT5Y#neMpPn^KnXes=UzgdTDERz=Erc( zFQl6_Gt3k?+nv>M9>=u(ufo_YtSwHFUQbOVrK5d$=CJ;Sq@igV>$OkaZ_ib%`yT{q-KE4xP z`5b!XC)5n9_R#s0<6IAHCgtWd!P=yZ>4`IRkTv+;wyQ2{hj*97YW=?FGbC}X9jsDV_%!KJ{^(nCb zkTt@hl#r%mx)3Dgn`ZgcGgXiVrUyIvSn-m<`%uFL-ot!O3_1<|G}#q)vsf8(6&4^KiDvh7k@V<~X2Lu* ztWcMZkBHWdCqe4SXj$yk4#q1QBC)5Rfe0}V&`9K)U;-14;m$F2IYBze$XR~y+Tm14 z!M@+@Jm@Pq?3^L&=`QW?19yLe>@3HD!$x`eF1-BQRvY{KesQL+U^4^hqsrZ5x^X zZYZq}==hC%v>=vA8CV45o-=dXB?*h8sGSGV{7BO4j79<#|ieQ4P4zB~M`6sGyo zl?fq#mS{9B;t_|F|8lsz%tX`oUxdp`N_?6&+!5|C`8`??kbjYDi13k+|1#X?htvDi z9pM5$;e6(3kAoh|e}epw9vs2!S1rFjynUYha@?M9^ByLB>s>Us?fwfUmBVo>{vX7x zGuAmX%BH4yk**O@-EbaL9EE+_URt5w%IPoBy%oYK^io*we^khF&}_X%)6R%totbNv z3pUBT&YPvcAcD(GyJ8?wt!5c{2+S};zSp+6^euv((~r6Fn)&g8CD+!lnkI+#v4N%r zMNI=oy8!OLT^X9hclGc4l|4PCW`U;bZB1g{mOQ^Qu^#%$1Req*LN4h{S}{5xsC42K zy9ep?T=C)$bPW>NuXxT=xCfr2l3vZbny%TJ#P@mcde`{RR(CDXBxXPjQzkmmH$WGx zDW4ZE^Va;P6@y5-Ux$@dj_>|}rMG5_WGS45AoZy5$!8B#7Q@GN^F zG(6*zocjj6m~v0pWgyWkEG4CWQl{+bKh3V6y)kHI$AKG{GycX!bZHX0ju*h5rJlZ{ zPBL*qVwzDz)GUE8^y(g(PKZD4Y15NDHoq$V*4f$oC9Gjq?_pBTI`iS+FPPk?H31)~ z+jh&qw*mI3m?J8db?r7LWNFX<{m{UnV>w>hNL7a7>LNO2dC=o4|ACw0t8dAdACZ%9 z;m|M;+@>DCD4*8Is1N>ak?(-g-&Zb*+BWqSF*tzQG-K60pHM&mO$ z9rg~6%b$EneejU{P435*zJpE(Q9e4Tf7&X^epn9(GFwBMpX~nDGCy(tn-^en$Pqac zJZe&Z>W5C@ED-+i^aI~{F)(?V@~yi`ATZ#^sSKM>bY0YUe{_Z1rH8JXd~Das9uUI@ z;Q%VFp);iG2e)19I{CP+wLPt4NzG)jpPG@xk--*4|4PIBZ(yTutA>!W4<$7%iZ*Gq zN6iyr@SGU*+=Qi)iDa-@k-u_iQPwv#AzW%W}OhC_D6nm(=p-xk5u*n0Io}O4xN$q+Sa4Fz%>d*<J#jOP{TV|E3{MY&)N3#Z&LN@w$p$gyNXwD%UOLr3e=nn4 z{`(ASTv67PeJD2kbdrA(;46>b6zU%HTmkH-Wl5)9V9#DwCR~I4%ICWq=5d z!RcCO03Z4;Q&v1FHF;=VR~L|K)A67_mD~v02>kO~ue;oS=M+fr)uoyHuFRILIFL=+#}*_I(4Z%fTzT$3!15`Da@s zs!LAj0>W7_(}G8=0VjN%+diIEYw;jKv6d7Plvf{e(Pwan<1BAt-0K8GQ!f)}4c$@l z37FYEm`Sm)))tKIDX`(PkA-YSI1}f2;y~bu&-D(2JYhwPrE_1;3Ps||a*u}5HgS1K zV?aZ!Ell^JUt_$f*KbA0si`I2)b8n6o47IH>AVRirGX~{JWr}2LggN_!E|PPykv_-3>_G897FvRPIgMOYU06FjhE**RY4og8Ql-?8kt zjwS)fNhHurL&vCAQ4`A%{x6U3FM%hH0=~|`o-)P4(rMyp0n@^!QCwwV7p9hosR4j0 z@t8*0l!$omJWE&z1J=NOJ(@-l>fQftf2@2=xY{%Ph$#FbY((TGa2QS=AqQ8o(2VXn z(%nV2dO%~{Iq9K^(C|OzT|bTsTAA2j_aylfoIx9T)BIyM6L)U)CUV)9iL}q7oDVyM zYv>`2!dQ}#h2y0+FN5(v2~49rR0|J3w4pN%goL2d`n$dlT08N{t#FvAq-~SrigRKl zj6!&jwov-4&){P$rz+BDi*|%)vM=iOKj_om4us~OZrqDqH&w?%bpUMwylWFPt+I8J77c`Gh1g-Q)>U2cA-Irw`w!gHFTi zs7(~u+^+X#=|3Wdty{v+gLn`b{PTu?p70MgO1Z7*9S#o`+}lBdVSNO(mF_U}64dt- z81wWM)CKSb6;>vwP4Mk`b`+?+#on_C;Z;UOQ7GCoH=>NNC?_rffdVxb`abbT#phxKT{ zPXrhJNe`*?Bd=YccVF;*o=pwlhL*1ZG5mpts>Z>40p)hMXvUiX*Zm9wc^l5afQ#DE zA1xOQ{9(w0qeqVx$_qWSItI*Da5gt}^I9w1SHO2L;G+8f^b1}4-?{rw{`}wAyXzC* z*n^wm{3}ll{6h={4}VAi3H)ye?1cGa`aG>KG|vd_r5^4*)R6veYt;m!e`g-Lb7*E9 zT;=dh9a;~K{2iSG-_7|2bG;!{-vH)bBOJ?9L-ka<><)8k)~^rMw}bh}sCCX0+;`q# zzGQ)5zTpmk4!O*?-{D@rP;lP^=6A-w9qjglxetwm>nC@Gdlby&ZbR373D}(hbIAzv zWMDwGgJ3=~z0~ZADO7*s4)aUDf-vEd!d{7y>80+s+#jkRbBFmQFr#)Hn7hO>s^x!< z2SW8xV18$~Yi7dtj_&Y>KClbSJ>cF%HUEnr<&v;X$Y;}C_hi>S6Ydptq536o53Uc@ z?}9rA-(ETiclr$`(RP?u<2XGBca4hEPlr2vOkH0AcljgmttPnBZ#L0(t{v9L6lvgy z!kGA&xCo2cY&BagmPk@+P0&QgCd4L0Yb{f>(K_8!bF?*1S1crnGeQcJTxx?z>L)J& z%^0bkeCbKDFT&6lwWD$-Z8u+oIX?Q`Z#vgU&FRl=C+G;Q6K=Y4;N{uhypdOMuJD1P zWp4W~#o!+lw0s?nAR(Ll{rP8U0C(kw>Zik14%e^YdLOP6aD6iWmoG0cp8{7gTBcHhJ05B5{wS_s!N`1Vy1T%~YTz-5Q40j|g4 z>ZlFX{}!${;p&0w6S%&EOXLXEhrpE#*TZnV2$!1$f9Kr42>NqtZrxY<-To5||6Jw< z{wMS;ZvQJdF!De47k<>9yDc*Re>CoTmWEFA>d2pvKb+13qdxCemG6n$+h=*Y>5JgQ zk?b7lQ)T@Q)_eCG_l|y9oij_?_-vf$%kwXc+jcN9DM&L(R(Y{-%+$GG#aCA5>`6Jf z{O!e-2OsadlxaNs#?*5UdpqynaY^#dx$hGmzP|9u-@g8b--ard%)aMTMnq}Oz{y|D z*h7}=Tvz-j@tV)mrv&Hy?IoLX=7yW0e=TgWJ`nQ7tG{0zZ22LdTW)&)H=jg$)~sG# zStgI4Gi%ox(FI3^^rMj43GR5Wnf#P-Rr1tDf4$!G_UnIt`|Pjw7C#DYKl;C;L=ZPofua*98a zlto64SuT5LLV_wN=0;^y)@YxE+-(~Y7RMaevvhfsy<^>(KXuP8y=z0w)3f)y znp3fF+?kHUp^~+qE|2%URMYj4pYns(#z`xt-kn*WKH=?MTjI9KgQv~fcy!L(k2-(# zLv>8~_szd{R2RSAFs5PuGAX;S?V59U`*#)Dul@Au)!i2x7WIAc4xGsam;0R_-vMgS zN5GW~R}oxIaJ>ds4_qHp`w_pU5$gYmaO;`+fOw>51A?+Wqvb=gCED00i^)Tqg2 z{y)8`{}AyR%~J=h=R;_|ntX580L@#w{{G}rn!gg>PXB@Cv2lmQJ7_+8dG5G3X~Wmt z<(evA8O_f(CLc+qc{=<+`293rpPRUMA`72sJiWeT}rDf#LPZ_?Z<)rrO z;(A(EUfsF%Q(9hbY(4(~Ei*-v1CwaEv2Pk&N6XH@w354M`H8r@IE0p=vwv*<2Q5bd zjeT2bS(=n<|C*MkPILITf4OhMN1l6nRQq5EOhr&y@aTB&MM29R6NUU(|M!UJLigz(-Sm-e*X{!W zvfaO#p6TP)xwmY5(hlQ&f8PCZZ|20utv5O&pI9((?bF0f)qgGwEJ&NxHZHm1f17{* zr}^If9K(VX!s(lWrc@l=l=af&2X__sy%_({$J-veb{@WFPl}h+KYH=u>Rt^~HfiXy zO^ZKjKJeJJ1!;r7|G4|j&e!Zc@7#PYe9Fw9`r}^z=E9<*+5pkMkPpYM7Qf`_-*n=; z30v#DTB7a>s#@4(y7$vYD({W6Wdp&e!p|f zKOXe{`*B^OEJG4{|DL~Xwyb*LWaH`mQ!AhOWX|s@@-KaBedG_)_Zq@tg5TKQcjimS zJ+uG#^iwtWyY0WQBcCLtfHYs`UKhFMn-lNa!-q;f| zt6=9pQ>HG*`YrD`}pN2u1-A@T=&navP24xA)<{Jr{5!@shPDb7>LAM=oTlf3Z?GRfD2g&8hV)SAv%Jw&X# z4tDF^a)w(^WqJCW*qYw@lMmx|PUgLLdwb+=*Z+(Aec)zhT>O-&3DXkqojwC}LvX=} zlZQww@sxVWyyZT=qx=;9qsIg&1ILaNyu2$Yc>LY>a4L03Xju4!h{%bPqM~Ca!*_UM zdHc1E%?sCkcdY7*T|vM8^aIOBGFCE1;u%1~YPqmF=+so2ZNy=#Bq@nmTv&;Wgf(#H z3cJ-@(#VzCtyVB0;FezWFO0d$cuOB@?jy5REjCx!NQ#@5S)uJgbjnl+W zjWt`R#apK8VoR-4roc!YeA3&tz+7XiDx>Q3I&)Q-sm?~#xs_(S!&p~QVyd>-s;IvP zTlBngTh+r>J2%f-TwYaOQC-%^B~{08nU0be8u)*5LDNSgJgcsX)5dae*2NT})h6nu zCF-D8L&&70^pwoZxp2>2keiV#+;dY>l6gBYOHVOm^XiPbMnfJo1~(aVv*sqJxYhGb z8S|)ynwwG#!)^@8NnkcVH_Kp}mpc#s@NV4txzt;*Pff~#C*aw<>|}$>pUmW2?y1`C z7St(oT>fV!=gl!@P~D_V!<=FFyjpOdlAB!^rqLC+FB+a9BYIwX#+=zHrrWJ5&Bdgq z5ReZxv+@cAzf(;4DXuh)$WxGB znkOM`nHl+Re~o#mrj*oY5iO&0XVaJFBTF%v z=9+}}XUY}gn3e@813%MpGx;)`kfp$$XiZ z&m(~{MDMP5C#Z#YH-8o_oL~=k_q*fOd}P5q(`66$x!JDrm*X%ac7R=o5eST&J zpZDe`rzd68FzDSK2VU)p16Ah=KJal7^a3vWoFQ-C+@!g4=1?_XO!*3drjzRDX1le+ z_Q@H!NptyJG3;j8Xwv*_`kKIPMry7r-w0)eki05uLyfiAVJ+dJYi(s!DsY!?wKsBA zb(LJL!%nZdVn?0bI+J8%bHgtT%Az4VBRh)vt9BP_DBo&$o4g$qHEOAbilia&U;Ux3 zY5R}}(Gffo)WX9;<`c?1n1_`_siF9&qizc?3XJ*xyjMaU5v87&l>J}1%S-;x?jqEV z#u_UuO^;C9YB+OAiQQUTOSLuCb_cD)AZ{bvlvG2zSjAPDEBR;Kj)ZhZ*h(Ttxc%4u zQHQs}{nvi_$e?5-4?`HPVZkI3f`l@5%l=Nwk#^MaupTs&H*EvwnP_bQCubTm`MQdt zu8X2I6qjnq$Q0h+9R@zK5w3)y4t~2IbC-SI4_@OauHlL+Y}P6VS6p3H1-a4nE=!_l z8AwT*C+O!v#SbC?XSaeg${p-!6`Bm{VFkps#8!KoKTu0?sb*UR^@Tno_<1Y-Rn?rW z1}rm@Z{_bykRUkv-ftNZ$W#O}41r8YQs&GvEf`^!Wvi{_YRq>uClJy!Btmr;5YvuH3KQBxSXprH-L#QK0ao|MR@nc71gy?jykP?X!6fN z+c1N+gn4sl9m^XLYNiEcy;TSX@~s1;CEoHrjzD>)RV43(P>(oUEmu|T;M{Uqt+lFz ztE?`ua#p*&+Ri`csIKNJs;kPV26FGP1u&#Jop(bOw`>UE^?aj!%M{!@T(5*cJCmAX z;!^W6h5W=fLASI7a!yzs`0OJyS&J8gsL5Fx9acdopz$t*WI3!f_J(<=x>dPt1-&2PCN$UO7Bn zXl<|wX`eJ{5-Bk|%p4ETkBfD>yv8B#dQ6faa^$vvhW3h6)Fau3*F5kr8ZcLJd z!U3`r2jSH^D1kDogM;#u#224L9zOxLLMlN!uec`HY6lUFF9A@EgBkb_S%Wjf+x=HT z(elrG26tNtAcy*d*Uy3cQ43*0e&rsvTA@Cyuq~#Z!jEQ1nty8RYUnHHQz+B~Vf@RY z?~y9__erY}_lt#R=Vzp5+*VlJX187?9|&zIxp^5`DRcAqT7iEqZSFiSLnuGhHGGDx zwAEIc9Z-tu%dJ&hWl0qc7xJsC({YH3uTAc_bMhFw?HM0dQUCH^Gz1y71Zi1{fQsx%k zkzw8>khI)t*yin^d2_z4qJk@}wijDDM>W(xd_AF3sRVaEGD}@;BUcj>!*`#+JzsYx znX8Je6|Q{ja#QPeL)%1cbS!Ni$t36`TC3~$0y2p&$-ImL@>OC4BpK>tIQtF$sKaX2 zR1Xb2ulNtL19kUrg$wFeX@$A$R;>eTcHwfa8c3{@;-i(nqoL?K~93kx$-I3-;8Ftp;%1vKW@z%An${H#h#= z5}v8DIwc`JkYSpgk(&!vKex-9Gkeb5 z`E#h9z@5JBdRwUt%6(}yHHJFMRsxa@udXrI*49_shxH@FqVMU>_cPMo{jS{a=ojoj zq^4o>K?!l?>dmfZ!lf^@K^;u%>MAQQoe)xAQw#NHaWROPQLZqk$YZYIgpx(=-C_P> zT?Y+{#B>a8q65cH-8%iaqaVadl-SZA{$4 zK&mOL5IPF{^QHoBZhopzkyz?Vxzf6d3aD6QbnYIy8`XBGaVx6piyig~zFpz#>*6{) zZB;o-HMAzQJ{K55_eKYg5x8sVJxr58voNf86@F9=@e{;>8Ff{{`-3(QMxt(+k2DqB zn`=M>aMaZlR#X>1Y%Q6g75IT+1>Z9&v|G!dxwV_^ycO>kjC0tEt%dF^RA?)i!HKh3AIB^s7`M{J#!)UdASw6-ZEdO{I@eZNQ(;ZwYoO?qDtmQBh1D9ZjiznT zd|Py?jY}~@oljqDt`**gm78sCUR78g3IAGX5K9I=6*G*VC1U}m+Knv1Pq|FE^O#td(CvCZzNGglNsdskCo zZX`A3jkUJo5eDGa?WU%#w!F|%=WtY4-Eue55ZnUeygK@VYGt6z7HB8)FL0iVHJA$q zb6lXoAj@1;2Qj04U%TtsEXa!$Bc1U2x=PEi3lO$!=88GPMi4yYQyskTTNh9hH2+57 zcH+KMe`<>hYpZOfrB-_kzh(mTW}E$C=y?q5;k7%e>x#?4;8C^kzB8ceQzyE0G{I`v zB^KqjEup%{9{cysVdMWu_cTqliSv_T6G9cOVg%99ZI&#EDT1NPT~dV=1m#=q!b*(8 zB0POADLn%kPsmL7re+#)(*@=1lm$>#-^&;Nf8~Z+PMkQAgEs?pEmXOdMh^7+GwyL> zs+qpHx}LVe`ZDO9SHwV-bsz7>J+92Vd8n~Q3uoTn=?46}^T$6+|n(o*Je zlg*CF_Ug*Xi?x$y+G-0yrUE&%u$C`vGhisi%B9bnmpvJTJs(**$ef8>wZj}^wnaOH zF>4w#9~qQO+6|_oro5CL?UJ&Spkru_23rRd*hCPvql>ADk1P-5%xFUyRGNu^;t>$% z%#-6|G+e}dXkj4b+?;t_e2g}dGt@w_pKrCywmBxp$4-rjox(-TPM?>R83ldGhpk+i zwfN!cNG_=y5@DSjtBKLXXyd0%i_vPdT&}s)Y`3`|gOPS5AE}6txJ6;Ybd8cYX+pXs-oIlQV7uxcgfaJcEd|;6;@Xr>V5&xGsYM2vljr9 z9r2nt?KEwiHa0%~w)YWt$NQl}3*_gy7i2FwdBNr8B_*Zsf?6(2lF;#`Y(sAD{JADx zJ!6FI3gRdAiev~gLR?yQ#$0NkO-#>7qe3A3G>MsW=YtZ)sFE`2co%pG!yt7fca$CK zmMpZe$ID-2NVIl%ZjCqpZ~koGD++_!H6kjK?~8y;lUQ2G4`=Z4pnBTJZLF>XX$~4M zkl!jnz5w@RakY(?M`B{2?E`oGa1fP>;K}HbKahf|`1}fG4u*e5T17|8Zg+dT<()b{ zPInsqYrTw6$s?g5k)!g(zjpTvHnLJkCzlTuLM+EUVz04QmC;(KBvHmehcrUdpwU2{ z(Isf2xOlBDiql3?3u`4vR<~JBiRT^gw&n_uxFWO~T^!ZYIl~c7BW1r3i+^ndB!-#8 zFcyqn^Wb?=E1>~0%)P_!uePz)VXdU^O>k2I1D$kOmu8Q0Yefyc(|1YJ1@Z|$Xp27vtg=j*^aR>uiZD};VaA;nQx zZl%I01i^a@;r!fPak;Gq#7~z4K1i1@u714xQ6Wtu>_GS)wxhADErkTvK`dzW|3idb z?(2E?^>&*BrhVx{bqU;uxbTcZ%I@6;*WNV&P9l=j=Gn%+6HgA?*K2lm z53aVu*c8kRq>Sim6b@@*3SlfVhW4YVZ-rqH3N>))b-Fk{0lIiC$mC|)9jt~nn)d%l zvDNMX0j?N?1p@sc=ww(6p+6whQO1-sI`7CAeqPO)at#o(jC`2<=0Hs3ZARLs%t{qoJOSPBPL7w%g5h@l#yp+4kzMASv7zZ{Z{mX~GSZO0z#7Da0 zNIS794Z`R+SWMylN_D|-8>GftI7CnI4Udt3}`zq`$E$hXvQ*H8_NYJhz~ zyk;6d0ABqtfpJ8T_JJkH2as$!IbmK5JrCMlqI`@{xaoYWnRYK-e!J&i8exovpM!Cm z(|HSc2{!0K(PwEIsaqJIDCH+@!8oa$PCA02dxSdz`US-gb5K3P>x8<8#-cV7=6i=n z=eZJF8N9?>a+j;zL64&m-0_JgJc~pw)yhZo_Thb6F+snpuA;7%WY<|LY{hht0OUNO z{PG$>s)sm3p9Oj+(U~AOILhzTCvr4hAk!0AI+IM*bZ$ZD_3(0DEoJnmYG#b)F<2uD z>!hy0St`_>>({sS+CN!g%?bWR0!RP}AOR$R1dsp{Kmter2_OL^fCP{L58(aHQ;b$Kj{pGz1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ;79^} zQ?>n5F|=j>S+_;i)kA%*&c!gaWA{;xN4mwX1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfWR>Y zV#w1NV|uSKZt?TI&htD?)Ah8jOIViox7W*a6GD=tSss(Hz4Vc{bUp2D^7XQ}f7C4e z{;-c6Q_a={2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk e1PBlyK!5-N0t5&UAV7cs0RjXF5FkL{e+6#vKZ2eB diff --git a/extras/bin/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin b/extras/bin/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin deleted file mode 100644 index ebfe5d9cd4400a9c4bfd8eab0fc16d4373758a89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1048576 zcmeFaeSA|z);K+clnOq$+k_H8skXHU z?gQ8sT2Z^ZrTBtc-4u~kmt7HE*2hIni!EihtZj7#T&jSIpnz>DrG=9Dp1ElO_j$gb z-|zRw@4u%XCU@?c_cLeCoH^&r<&1*kd8OWkkly8rLI0os_>GZS<~xzAJr%jkN@LUU zY^-(TD>RG{hmjaMGr3MlxK=epzn@$e>%=(C5uDA{a7gH-xR2#q*QaqCn|NK19qQ5y z>s`jCo`VK0KEw%EXg0xTSSA}$U8WXpLVG>FL~R5htqSxv5%*KESr2cy2oYnOL4%D= zdR-4fc0Gb2A@uGze zh$IrRtW$sV30KNSXOrH2o=&m4L<4S>N7bqKVWe@jR}&jCif&W`1tt=O(~ZO?J=v6v z@YgKg7ssH+6D$T*xNHXZG1}FsKk{qb&0s&X;xE`U80%GwOiGBI4ShG&sLn0VGb2Qf(u7v|{m zau`$sXd*m0F>FT+zy-p>S&GlHwpxd2Cg6Pq1i5ZbfhHGDkV02nNYBki)n}tAF%|r*P}K(E@w%$uS5(&{oTN49sPGk4!(fin zn(yWK8Hyr5&LU~T>s0#FC-T^xjmR3~zs#!fS)Qs`$m;b4pW=2g$R4o*{Z-E*feQHD zE>^nU)R(-;@@x-O!f(A;<$6J1@&bd@2ddz=O5Et$tS^!KR~6U@kbt( z6a4zbr(6s5_GnvyrvSot@d`yX^%FW@gM+<&L@o~A}hZJ|S2=u7lnp;;lDY#f8Vh(pi2^NtVrn-r7 zys7GDCsepmkf6dO(H9;zErTYmm`q|>__FDVF~T1y{yVFvIkfI+2gz|+4Puuaw=j@| zHHKjmk63~a>+Xl)OEuJ#q3$RY52wn7CfpNb$=oQD}-(|A7XLYgwb7W?GYsj!E|x8h;Q} zEwq~xens(CmQSrlXu12Cr3{mjGNtMFv0{@!wI6cSq$8n>X6x`%ESpVNy%TDi0=<#D zBA_SS$KGRgSMOsBGnmL(^v-s)>r){}@p@LI&3~j+lP~jiAwcn32Frb(3WXG}X7T1% zhg)B#-9%VIaVZ06fRE0o4__Ua7b`5H$2$yDy1Q(T-)Z9oH!xqZOJDs8bm8~%fc{K# zzoS10p7+>T?xMJmRiOTq3SNrums{FGh4~cU$Ko{)QeiH|_p*5Fqg2SH_#PI|YOmQ$ zg&d0W*_%2*1&QLjSUk6w3NDK8Wbx+EaO(ytWK%px&IV-qGm3NMq{d|(Dq zf1?Q48>}q_LW3N{Z}?+-B-@MF9vM2?dFI4WZ#F*Iq~`zY%GwHv$0vpVIbkylQ^ymCsdp_RCF8o^Sp?)5SJtI5JBg8zMJPT5wVVC=;q-U zb@TWn72DbVSWsme+H%sLD7N#OM$vCHEe?$tc`x4~NT_zx;i!4(+qpP+`4$ z=lFD%M@qn4g2I`A!pPp7z_~K)_I5jJXW2CgTJBDIr}+HKhjpCk`SFEmVLsI@`t^^M zIt9HX7>H{A3YV)q(Ara2IK9NPRq`83R%~2ZxiisAbXvbC7_%|nMa@b!Dp3pX1c3|y zV@kGv&x;(gqw;9ag1gVA`62W6Xy)W@4V2b%VZGLWxPEVDsn*}{PPDph(Ht6ofl&#N zt2kQWib|5fu&|L+-+^|TO#heRXEvH+gNfrMoDj|ln?8;ML8R$O=jjuJy_&a;O@+E1 zPB6r((HG&4j`F>~&aF>SI}^C7gcvbFQL&lrn0AqEV$K8%@%jW60O1vY^$ALd0~)X8 zdD?EbmplCiwVp{E-`nwnbb$^K5go?z=rDlAETc}q%O=P(#nzD%27EgA>z#fhATt|7 z{xtXId~deFmOk_KyG7>xuBPYBD(${sG`i~Y-2E)`-Sjd$^r*2c!7;L5T` z%K5;<50~>n|H@U%imZIuGWoUqVZOZVF+Sj5`rzskKCtp3$c@nG>-7TDWO%Iep`vIt zk1i{FWaYyT@wfAiX){<6#PfIO&ExMbS+=Z*m;Y|((RBNQxxa!`=dIIji^d>60?QnE zM$0XDxM*3l7*vV!=lxu+Gymrc?_rUgk@uXD_h^~iRsKg-@OQ8L)iU0~FYuQ@LHL`# zAh5DL%{k-NJEf`eZ+a|pG8j~pDW}bFI3Z2`g*3;l{{s-}$&d@B{WLScNAf%D&goD~ z^a0h3=KpVSxj&Fzz6_?I7=~%((XxkD_#axjEQ-nz*aNGJOL&-$vegfcnxL*K{^gon}-ChHN5y zOI4?hgmZjDi4vb;d5IB!%buQr_?Cwfn!0HVRoaMW?SwXi>Jj7U;j>6fXLaq1%-R9Z zC2@3C;r9rkI*h{bJ_ut-fv5Q-a-E)nTp)|Hvy0)VaK>?>k7_aZB^6QKko&fJB}tWB zbt>4Y&r#1mxxNtgpQFA|eAD-|^LxsX_2R@0F*9(xzR$aU@~x_}(9+4bX~a-b75uw@ zgELfw;qVFE?gZuee!EzuH}KUz8aT3nBn;$nLA|ceyFvID^(yd}EMI_BNaS%+y*HKX z^FChnC9O)EwEWLXGN;U25!8$kI;nLw{*>heRR9!{k1u`2?!IEzcCu;Dmy|n3>rrpt zom=*%bA7H}&NgH314?q!N$;jM!)eEW3%A?JtiIwIM}$E)LzR3SXL^J-1bh^R0*=pLk{M06X70E>TbrNFhY3@J7}LVuIO)1Tm$uP-G`pacL#l4bS`^D7UPM z{0pLcmNjRw!)yJda432LUKU=r4FF}6KsUjvEn60bUuhEPC0HHOvar~Q@G91T=S;%r ze4+$|P=x*xA&O3qVY;B>M};A`79TX6aU9~#DKK;vp>D1h)DQzSOgm#~6HpzGxLclx zAxRi|ickj^j=4hvK=GC*4pe>LW;i08c3j8A?C7hdwnE$4vqy3K9Yx1^ML4VgRTlI-t;zh&oIOSUBb4{mJ+LsO zLh5vsyByUlMXkR?>Ln<55vsWdUw_8AO8hktXofTCxepo z#zz=p*>T?d@!HPKP4y3WU%*3-Gw!4L2mMbP9usgI%h>WhTk^u6DBjOrYkr`@E{el) z{4^Ebr1%3l{w)Pv3w~dYpQOT0ivJ?VzoNnpirCOWvZ_%(5bcqU)l{J{JIhY14n0nDY}lqJBmkz_MMYlNeAexa^O*#CeY!8LFWQ6 z`-4VE2EFT>GQE7p zy#E!FAHUSPfqkrS^(Z1MPC3@$X$?0C;J9B!sfA5oyQ zbaQ%^*4lCpYPo}NdFy5%IP+GbbS_D9{FUNQSP|7u>i#0a7(?n)F-5ADJqn;xV56S* z6!>byafKxXQl40j*s?B5c_QYCfleR|P_o(PJRt+?ZF6Ft91yqnJKmtutDR9oYy3TZ zJ@ybcczfD}?1ZRhBAZCt`^DyA{+24dhcyjkLX?v0UMDFb3-dDc!9*o71zh*ymuTNH z{Ps3VVz+w-x8I3|P}QGk@1Iy#>TmgV#S4tB)j#}e)}dQ|Gs5K_{tbSGRVor>@r|_+ z$5XH|R^S&IEIS_5*tN6<%dzUG8Qnmmcz~%7ger)a;tO)T0^()3hsB*_(2}Teub~p? zS(13r%7`L5DJnz}XUF4tEK7Dg3}*rHZSSw%j>A^ou>ufq6>nf|3J+1o!y{TTp_n1e zY5QINDr&c1gt%mj%Fxx-~v`vT%f?B11$|vm_NpMGYF{n_pT$t>?r6i25QP+a>emGc*ygnJZ@r( zmv(q@4ofA*YFODG7Cm91K#8+i6jU2YO*d0A#%WH%E(WOzJp#>FJ={XZmU&&xx(XX< zdCX`rbHOZ5^}%?HRTaz{7qsf@bp^rnSg3VuQY%LAN4OSKQqZgw-oKhArE%3we2c&Z zjhrfj6Ow5fS8EJ&=-;*)d^2k@DB2tbnyCoh9q&${b5q-k@^y64LQ_kh5EmVviDfI* zP!e1jliNbEfxWBuQ#1_g{ykX#??YHb^e$<~Z(#juadi0}6|QpKil6O2F+d$ZM2@%X zZG>%#2%X~=5Z5gRAP`v#yX%AAA1NVypA6a({&t5`f$(C6zhtk=mD64>oThl8{N5f8 z_aAuqi>4zH*t2jRgGoDHWI{wXpqhym_zVMH7b(KfFOVfh>@~v_&t~a1;@q*xbCD)n z;n~tpr&`VXL2ThK)6x%loeGr+o?RGfFf~;B&{ILR_-^9qW zL{#`=@&pF+15ipo?S20$(1Yf8@N;rnMQ1NvccE>f$*fK@ugF4D_*Bx*)2s(=E3+4o z#S>?ehGxiDc?tx!3a~dE-yDA8FKMx2x_OjKMtP+sE6oeFn_Okx1OPy<|!$; z{j}DLkFkVNTER!y+jX3dj2T2Y4sdr(GC~!=zn@9wU3wT_hYq>OcF5_t3>+LbUZR|* z$7300NRHzPHY5<&z!bwGODn}42pd?U&_m4^+&~N-{3C1C|DP-?Q7vvQ3o%pDV>{tz zam}?x3CE^`ceR21%;s4*>d+dxIedj4QpD`P-KGHjB~%mVG^44aJ>?xTn->MU7y>bP zvK{n^KsV6S{&_e`afft^Fj0Q7Q1T#+!A6ca+JvaV&JJS|C{3$^=2(l2J_bLcBXVl> zCF&oh?n|`vGA%2LFA0WCP9+!8lMBv!;<$SVcTeoE?q1i&r`Yp+`o+%_iu&}=P$0Z= z(|sZm!|CM&X>+tYw4Bzsa!k5PtJEfq43JciN1|2ao~Nsz4-QJx70>|<=y4%VlK9lE z;%vD~2q;kGAX*OjG&k`s^v6jqGwj8Hmu5egjd)g<1@XJeng(cd`!Gk) zF}-ks9gu)plNhxUJ?BLpUpz;~HPl=5V+oflYm3vc=-RlhuT9VxWTX_>IWdH*ABY#e zrdZEP3MZ&D6ibw34A#jtB|5$1I5M8>NJc>KoOgW8yE@?uiv2PngaAOcJIMt1=QK8B zzT&p+FU`f0>oN5yS^;ASLEi`A`7{I=!x@Jb9~BN7nub8h#}RFpS7WNs0Bd1~nK|+8 zW$ZaOzQ7nGk=XB*&}EDMUJHMh#Xig8y48|5IanA6W<@9YMs)`VS)hvK9MC+*MZ2aA zK66W#H&z`7TjL{6QeG|K){9g%7Qu=D+Z^n7Ex*ILy;SujZvBzAoWd|8k~g-X=TZ%r zL5TLmc6zK3*!m$hG!2H{op!JlB%{i+F1}rY{>AW8$%bfUk{}^QvtP!5A3+S8{t14CavuNM+lsl*T%Av&7<8qOc1`iwTM8xC@bu&K)&ksYAmFtw^ibtDdu!9;&t z97VasKH0*j+OWJyKOm!1ay&Q;+07q|OTFnB%zhl+KMW|cVbvhW32+{6Nuk8(_=80I~U|t zKqjiU6NP??f5yhZlox$$ZQA6wA7Oes?se+S zJuyZN8P$*oV7>nZn-b9JU#27UbCtTEydtG;Sl8oPpyZWXZSwBJcF+r;R#K{ zR0~Rs^&(k^V%*2-CI=Raq*5XqourD{`ZEl!3}&Z*Lnv%i>9~bQ$He>|8X)TlS6G-6 zXgyIlX={xdY6tFA+i@z7JH<~sRl=Rho0f}^SMTBt*SMWXHb|txNgltk<{HpNger3{ zQmzrVUVt^4e}wu}>&*jse9lg1%yOeLZ?aq0LyTMRKaBSQLP+OFk2@a0*knu?UCV*!i(W;?r_D$ z{AX#$T6dYJs>@SZ<*BImJl^ct5b$i28@S?f6+r`%YF(xR+9J82c9A^m!St`iRPMEk{A7XRbT3C_i%9A}WEb>cP}BU7ECEof>Ma;ZPVQvA0%MztL3! zmYNOM2pEm1mn|vV&HZx{U-tit!cYnq^1i|id3@63Z-M>T zg~JrDliT{k<=i;LAfJL!T!!qFTi*|@L(|}DAo4ZcludYvocsz)&K;t{L5d%gAunDl zKoVi~)$~$fKgC6I+SY4Bk<-+Fhc%Ot0sFv5lXr!6kebfZmmyPC zv8xgE1;EX1E^u#Pkz!X?3_N`{SII)g@O{NDk^@hvINt&40;srnHWOODVDXbSAAepC z_G}g}_U-u-+8(Nac)iWH`vq{AVDS24AN*Dovr5WrbIK0mvI9(bEh}c{*g$b^KIo-b zJCYb`!w1+Vabo{v;xscaC};6<_!Wy+_(4O(a?kd?^$A2In`>liDR$kMZQXHr+cT|l z#QEo;N)gnS@31<_$yEr_s-{(-&3ZoS5Q3%lFnNulpL1BJ$O+Bv_=d+NO$1UNte$`Ov-f6KyJDf+UHr9?>Qj zR>MkXb7EwyVwAH$G+H;*e3d2heED_UG9H0d5xNA$)EgaN12K!U2gOiGb&2ubpH#z; z05ZiD*o{Il^<(joh=>M*#`q;1c>cKt;bi-7CGvZQL8s)wVrY{?Wa}dRRklST$08;# zIa4b5lrRJI0H5Q5U*$najYqByFT+L0!N#W0kakO(7lg7l;^S{NWvNUm)mrlkZku(@ zb8(v$&u>$|m-V{xFB5)dZFU^FD(%qW2;*1jmAk4mSqr#DW|A?JTWn0Trl)GBn|=5+ z8-HzcTBYL<-@Z+}5bs5|!xS3|0yH&qBZr(}Oa7 zK?TG^5Kx%T3d2(vV#mV#i%h5oO{OaEo-hV{1My#^`4_1B0*%5Z%CKIV|MeC3i7Qdq zI2m@Hy3bL6(J&Y@vektP!`R5cqf`>5YmbTEK(l+-TVr1-YTD@H3_@sN)9+eY8~nMGeK5#Hr8S95cDs-6xK3md*;b6m1Muz_%Ls)!XEZc6i3{P zO4nA-6~Y1clpHuNi;cy+wd#R|ZI1hLrliiu$`X7whC)#%L}k zQyib^)*6@|0wg*mu}`kBlTL^A7R2Bq1*+xD6A{7cW%JLv6wl2jhz%%E|MmXc3UbINfAa;4zmu zRB*NeRDxf_Vd+W(=wZ3`E&~2Y)fcf1dmcCAzAL~)T%5)s4+^9wroW5QfoCGrGtIPz z!wR_`o)}eMaro4g+U-zJ(5PyuG~<&{o^g~>1}4`abYBrU(8EOQX&HwsqQ@jEaqkfH zr=U&&Ji7V|4s2haUa75jB1QXbA2&1R+c?RkxONN(gis)W0|9QO(_=`+ZC6N=sp~3e z9xll;A24`NBGfDQ?_aFmvpnHc|K#w8&_Ad%n5a@cpN!vU{Zm54BkM!%U$kF%>s5}Q zb0ng!N5V6JBT(Epo*RbljH)ua z8D5*}hndo0$0q5ueEb%hZb#!#rs5DM3we*R_K5fP1YF=ZZjO`%b7VbdJ-c>Xikf(2XD~R5l)7AF5LhFNK~#S`T+?Ou&|)!trjzG z2PHdFwHYl|uE2^^OUBsJ2Z_Nf6=ZDrlQC$H6($UdqB4#1EWY`g zxShmwIpePB%LXV23PGnCtfd^PD6qr9-18m>oRTEYRT7@h3A+>iJU!H6RH=FZ%;SrfI9_Qg!6J`T zc{g7pI^lbYKa%mw&Yqrg)FP@{&O(Xv_{=3uo~baBhExk~R>Q&WW7r3Kz%~YUvIN!- z!%@dUp&KS?K+@pb7(trq;(%PIu!(e-VMZ?CEH;2V7733#8F;YbG3h)VyLp!Q6B z?NC-d4msYx)I1vnC+gC$WB7`+GX_s$L~+d8GN=n0bwsT8=&JA637^oGGdl1B9APEE z-iWXIgGlKC8ss$1b8hLHV~2xnLG}gr4_D^ln!^+*FfmFqJvYz{0h=+CP=34tCPNyw za-koII=SEh2?ml^*pHNUIAAZ|dbS2sWuYH$m{`qQlUxXb5<(%^2%mxQ8Tg^DXLmJ* z@}->_4Ap1c2ZeL0$NcP&Y*RT}uHYXSD#1asIYx`&pwuy3^>i0(H?q#ScDwKc#dBE> zutVDtGW`qUqjp0`fkUyxQd+ev1w+bF_6jN8pm34PC_tGZmyvxTYWLW5pgo_#l4?#- zK<#UQ+Pm;S7=WShw0kgrgd-#L=E64@f_$W{Jlc5X?Sos+afcM$O4B5~Ti!cg*>lI2@h3iD<-F{pC%86jt)+H;zkTO^De^@IAHP^KdN9-9s-!k!;M z_G{a6r1A9Ino3!20W!S;Q;Hm$2VuH06OBsDT z3I?ySOB)-+PuXQZ&CKd+zb&Xp{JRz0Rwl6=wgm86NntUGyg^jp=i>9eVbeL=^;RXm zmvt*UK|I8JmG~a^A|CRSBIhw2Aa4W~6gv06iSJ@y%T0{^3P29;<2y&j@^7vjBkQK6 z?>Z`>d-5u&?!5u_I`{$YhVU-<2$fz1Y4P|`$51|_`^WrcF%?>a=`R`|`05i9pN=(t z@auURRn&IIZmZW;+&eyCRcdhWzJadL@{TV%FAv6c!&tsjIQM7a)M)=p&qggeI;)aYxz1~|Slh?3GUQ1-*D8sWhK zAnjEw3hr$pT2B;vMb7D3@2DMZu1Lmx`E}g4yh}%p+GzJj%+}HY(!TqQf2j0m{#Aw6 z;q1cP{;*S#)eR0#rW7p!Nww+|fBh%?3zbhAV5NkLtV-V6ImMQ~MeLIC{#&MYE@)O| zR;F$7DrI0%^sYuhnNmt9B>G^|O_>H#6t?zEv58$Ws;XrDdm=%+Vq+_%4IOiFcu9|> zTz}vF2c9wb{;BY_wE0vO!7=%PghGqyPMIDL+{D#{*?+XHUs+ zDk@?UXGAl-@?FzGDiJj26(z`rURd5X-6BEt1??gzxx34Y+T2I-Px}W;nP_a+^(-LK z94&`w%^*vSpkTZ#{k{%6+0t{Q!u)hcg}y5n0RUV~cTG@e z`8{RZ5J^&hI72amVATG#O*PTYODn#o;ZA6{l87T`D@oPHo zTeDqNF*W$ai~1KAu9?xtIE8xhb0FT0D8YHy=iiN?vxY&BpGWAd=b&y_<66fVKR9i< zJ3ovZ;!f%+s_y|=jMUbDw=V{NH2~68Z3p3^Q^Y0+4nMYdu;7@gBK|$BJ-Z}hdR*{ECEhbd+2}QpG-zu0J&aV*t2)iyi{aEAD z3N3EHRoX6Jnt-1fXgKLa1;@660ArBC{eCd&s(b}V_03oidT%`R?Sg#nQq~R z(isPbDu&$Wkcn3kazEGCqW87jwm3gK!K&;e7r9UoBAv0_VmI)EEWCjkmX2|m`M^OK zWC?zZLH0F|tm(EkL+2fXryX57<)Aw_aiZgH=%36{r^=nnx}kGH8eJMdI=izBLT|rS zdAsNscTwz8i_ORIeGJvPKfsEiRK_vJr~Bd100+;Oses@6P1{u<`ehB6M3qxfP_SP~ zL{DtQ!sX*H`_o*&Q>2bXE?~xzr_+M6_SNN|qmF58rlpjt%!SFt+?kvyR|V4$T#*ST z8OZ0i?S*@})gO*kD`3CL&h1!~VVhLBgy3 zX_DAH4kxiUN2uSKqI9NAfBu3Iyt-7M!7^vXiHfLIuYqgQwe390hYWZtGz5oH6KppY z(OBD;hHLi-zhQN9UGj*<5LI7=5u@5NIK7Q%ds{9s8;eRth0uISI--~fIOZXS>^%OMp&Fj)8+# z4a_yWA8XViWP-4H)Tc#jIK(y7<2j7or(-La_H`Z(hHkVt6M%AM{F@?YwICJSoa&w68tZJ*OQ9ssfe2jTcZO1NdOtJ;GsNIn;ls)R zR<)F4zzaC5IEx;D_10u;a>=^D2LSJ{Lohb&j^2V~cOVbRClI(}=eG>bYy?$P=cK`! zIFzl1EgYx;OEUhZU%a+|$FUZFx_?ilB;n+twOss%V(7EId0g%^1UHRm$8oF1OWj!d z_%q3`UvxeYpOw7OG$yVrL`%Sls3w-{#$5Pa8?h>34jl}oa0?MGNrIqiV{e-CRxU>5 zPU%&B-a>Y|_7-ySACRwOGH|=>$m8eYKN{fiRpdT#q0hTQj1Q9vSx)A>D?yCm^tWa< z#!Lt0&C(br2mF^?GQ*On0}3uV4uSrMIiLUK6Y0uLM1vnO9{`50CT-3>#Ujls&yO$XK-0w z`y^7^ZZXEzmO1|3&nXImdi|(GaZTtWfun-zk5_}-IFQ;-3`n6>_%k+>jt_^@1aWq` z`f=pndFjOa{YQoN1)V!Cf$cd;1IH+CVu+d>-_6OIo~PM(e@Xyxu%N8Ulim2_Ki;*) zpTW45X@&dRd6SsTS;rG&dgWezk}Ux*VAQm;ifb)HbA`B^f})Es8=Eh=KL)>Z)|=c; z>I3Chh{ik{A0Rm9IZgFHD3DfeEaFIEdmX4jvRD;7Du?zCt+kF_1DI z4#SOO)&=k{0Y!l7K)hrfzc+PS8~EGdc-HY#UBaSDI3TtBJYpl6c<%Z9jhC!3fo>dV z9fO}_d_$EVSt|s`&Uf6~KeFN9A`_VIx-jxxMCgl1p;~7*cJAMe18j)-Q(^r@>l zuBM${Mw-o>39KE-_+`_N5*jHOzWhC~E%9_oz=N2A+&WPkx7pML$ zdzC`G+`BQ=`%{vof=wqE32_SxR(}rDO)k0Ns`#y}V>JtDS^Nh9;$QO|UmqW?A}gQY zHg-?^N88DYzq}ZK(mX@#=EUX_(YRsqO*+`3Dr<_tIy$ei^+77vSKSZw4Gy?xQY^Ci zS`Xc@&cFj<)RM&L6(k?9BDUWEW9M)8P=3^}5*(yDU+v@2?j!dtQLE9k0-DVeQI- zBD+lk*Pov3)8f;=P(2edeW?K-=2iijB#mQZU+?1)@ZtJZM11(>zE9SPXm{Vz!smP{ zVm^K>HDKJiY`X|q5Vk264iX&=#)*(^^cluec% zn-!Q;h=Y+Kb>Ff=s1f>I5B+}L`UhcopD6zF-+bJn8`I8cf0og{)PD+3{|0=4xgQ!&&m*s)Mo1GIx^~M%=cfWm9C|DzNA5 zGh#PG;&aDAsG6Eb^vTY!D|LV<_UXHIOA@* zweK9)w#4&z#A2MhOWI}aeELF{uHe`o#rC;f)>PO#xmBrW2R43dwzs+{2=35{DcklvHNXi0Yls=BY*hbDGveW7# z5itIP%{(d;lS#r&m)-YW5IMvt3)<^5v0b&5%PGiJp#V@xF1GN*ms0?1H_HH~uu1R( zK9!~t&<^0T5Gu4Fb?w8BuZO@LKA0Gj zKPN(xz%3c(1f01}=Z~m|8i>Wb#A5xWB`Xm0zS{XY1?~*Lj^T?MovCbSp5X;tuzQd+ z!>JXIW6M8XXWDbg(SNa7LhgUCYY0XLU8_qUtI@5{pEWtoU34F0oiMRZw0=rETPfU_ zf?qYr7rYG}Q$1-FZ(sT>r(~LM)e$$~*GmBKo<>Te;R0@KBDV=XIux2qSr<@n&@wXHz)M8vTriba)b zx5<-i5CzV&I!O|^(uaD9I0!TaNMZ1r=jXMC;r zhyzF<^`((70TsRE3n>92roNOHb=fa^2`qMxgER9;7vEbX_g!AEnGrk#EMlnkc+g1l zAMSe(2UG?A*OT+?TU&>41pvEEq$YBkq zyaaw{ECK+|F}1gPO?>0xKBBFkU*Ortx)Eg#raM&@(>*F3jox6We~aCPayL|fDt@|@PoiMfx25=U=BuIVW1TPh+{wvJ3xfN*9*|WHduF$PSizY7Cm)W?oLe6v& zRY7N0XtH&8E_nL>>XkssH*^xW(ARZupluUh&@)S@OxK_mx!&f0IIiJtuzl;eU0pU% zd^^J#SltI?2)8<+O$B_O$MJ11Yz3GBe^PgWH3Et6^+4hfTeq!X?q_nqh};hP(3ZrA zj;l5AwSiYGQvi;r|3r|0{W#|28Jn)vTClul6rU^Hl( zU-vD`#bge4XBl+afF{rD^l;YrIEiGC-C%b=VAthW^%AbjQ{L=Z&C2xMKn^$ZHJID# z7j;|+^G+VRZRaYbg^?(p<26gMtN)#7GjbPXN_L z;<}z}j&OE<>xjA&jnbODx zbvSA+Kn=h-s>v|;l#qI}!~2&;`@M(bCz`X9Ie8pCz(2xosBEy9@l4MmX9*(2k3#YyD4 zpZUb3gT$Q1rQ_gMk-Q3sg080vtb;4K ztQX4EXw7@ZH8T_Pz(OBf$(1au^R;x;3{iQ-A++QOoi!H%=$6jBJ=Aox@!*z~rP|7p zpb{>r$*v7brgMxbbZs>w^t^t~@|bnsm1OAAR{c!B6^&gA4vwEY6L`MRdgRH@T#R1G zhqGm8R&0BK+`Qe5zttLdoX~PF`8mX--TlJ?-xi!?*orLS|=e#!e%S6BlrC;?AVl10X(l z;Q|o&5UkCweeFQDI!-KB1sLeq?>GCiQALHa;`XgCv)toZZs$nu2|vc2|6@WN-8n&b zAX~L39_?WX>dW*T%X-s|6>BP)yMm1jHnnXrHi5!v@=~?+otd4v@O>vW*4B6yDJe(n{GwyvZ#;Ps^_(htfc>*$xuS0xpAGP)^-!n1m+2u3Fk%Z-Y zY|Cd%N$&2Up+Z{M_elrz3&w8UKKVIga<{p9LF}Dx{{A&ieJ`5pP%lF3z}&lHj;X9F zwCV}dDx$PM7dAbau%v3T=}}+n%cf@&szOCinC`C+t$f~euh_c9v}cU3wa)bH*s9iF zn+B8XL#v-R%@IRuC!6j{CI{|N!6ZO~hmdKnm<->Z-~uj`8>ZY{NRxl0^mHX}4G(T< z^G8je>f~<7TXT{U@RwpkC$E8Z!plWp%&I_W)$(U_=FM`K(=wsIOpILd{4Bw9o11w6&r$XkZ zEr(!1ypCbg{$>4(`Z)?yqke|MAZqIAoWfs>plgy+<6!mF%&|Z{8ux)aVq>4GIs%tp zXH_xUile7)=4xu_fjj!F+IlDqZ11;oZjsxZf4T1~+IPz=80qJ4p`M;X^T_zrjTC6~ z=9doKp|mnfu}tY8PdCw#cILXHy-nKi21c6<6%~%Uxm!U4x**nEedn9O1TFb3F-CFq z`$_7#jyG`4wLY@3M#s1auSfGeW>s|DEg#-E-us}bDAF{nxK;oQkyf~dx;Jnd-XhWY zqSyrordfRYM$qB882^uAY_4Ga%bcQHb{fYJrN)q)1JmzA$j63~jONszD~3h5T;y_H zfEcA!BclpP@nrx%zrBsY*dj=7Z@o<8x?69hFSF}-TD-V)fnsIlx(hG(i&bkY@7Gqh z$$BEY%tIl^V_Q~ME(VS3JU@Irrb#~!->;l!&K?=~;E@5_PvodrgEUG5m^r`EB!l!Sdv`o*|dwHSK2 z9##K!w3o0GjQB!ws#}nTWOK(V+RU|8n%U70`+}fmRkkD$(1KJ)%-8qa>*b8qQ~z(} zJcN}~UAdv0Gqgu~?HF0+lbn)ooKu<^HLs%(?78bqqHD=&!Id+OckNolyS^DOy1s#D zEZB*5LwW}Uw0n}P9AID>IeOw?=b2t@(>W!`8HYHVB9o-QeQc>$l0v@)1HxFg8+UW* z1U#yA;KqaR81h-cufE`0gWo?CP@|wJChcw2&m%ZyoMiQT`t`ZP7hEXYVm(Wp}Lj0m{e~wmwrggVvuR9$`;fsFpe?83)H+H#*rnDW6Sk%{Cad8s#I&d(!a$fQRub3=9)Ru2V47JoQ|AAT8$@c--lFg2uSCduqir=DYzx*TZ69 z_k-^q9D{Hg!jV5jW<3MXZ4g2bc0pKDu6J1<(Yx~WdRN^|dRKkp@j63T3>|TXkQ8!F z5IO&vX8)sI{?#Y_<$eA~u>57AmTz2Q*KXeGc7~3)M8kv(tFrp2s~tXJJ=pm*ZSKU` zIIoc^}TI@`ct`d28WoSyiFZ zvd}W8_qRk*yF%%HJk7kwmyqlcfYNvNCIHY+_4jb?_nn2?N>$&^M1OD3`^W88m z54Z|pmD$CH7-HFYiFYe$FK_!?ilFMok=5 z1^0cE4VFl#bxX9?>KCEb>V%P6;p;Fk=4h<|Zg4@>P;1L;F7Wz-Drb*Y3H3csgZsXR zs-(to+41w;(7|V^*f>*SBhcqm=*5bbXBYrFTgq0ed3f@!$v~p;Ud-Mn?-~!OK#CJY zMv2(NPWA1QFo!8v;S;@{*KXm2H9*XSlwpYX_w(eI)6v$X&^`1;Upp!+U= zI(!!dY&4-wq@U6L)Moz_oXN)G7@+27*fdRNZ{RvHU2H1Fb~(uk=-o>0f&SRoI}8QV zHvzq;u~%nks}$PggUQK|=VLRQ@~gApzDO!dUI15e;ljsLGTO_lw*rF1rt-f@jwJS# z9zc6?d&?%k&>2pc3cYL=rgRDEa_@7tMP@C65be7SN4r~Xfvb77w}Tr1csRiK*ChN~ zAFd1FEn?FuPX)B?Y+6Nj;NeTq_93o7Qbto9=U7h2quL-FKW!LqI>!dnv1ja&CEFzs3fm^?U;t?0w*P(J7(Dq>l zcl~#GCxhqxclh5K{NMWu^|UZ}$&LBjVC>8@?>M_F-U;{K1&t0|VR;|O;C|g%6 z!*T@l6_5e$Cb62FBt@fx`wEQ*z=sKnhVxQ878&3j247?KNcw+FkEVz3Q$l0c zGTv|j9U;V_Lip977v(3&E$|IJb|r>+eJ?=0x1Dc-?^y64WqliS(hU*cEe&IrWp;i< zH9C%;$ol2Om)U-LvT>6Jt~IcMC&KG@%{}nyWUnbK*HXBk84MiT@-3~Dul$y!Np;cx zhhT-oscRo?B~aUFDpA+65o?u#3B$p|9}~CQcxqf%NN?d3g?-E^pF1r}n@ncATM4dTy!f5qreu ziKxfW)8oL0Sl(^%NHUNMI)%&Ss865l`s|%kA7Gshbr?E29DB3Oq-y7H@wzHtdpTqV zQBQfiq@)}i3Bp#Bx?Jc0Ck~mg*QSB`3(G zpvu{DY=6}i;1Nr`)RM4q#WERvIWgYQw z#Yuz6CXTn5$3SlIU=lgha-+Ws?AS2xk29s67MH#CmGEEZVTuCcXC={(jRZc+m)D0R z9)<-5NmAf2e9i+RoOsxdqH3}t84EfO)bilh)F{xL$9LCZllo|qfpXKsLx1-O-2 zdK?Ys#gxyY^hHw1YWV*P2=fVC`WaLQL?AD)QRN$a&2vB@rbkRcJo*|Qzn4Ndd66e3|4{ zF(Bh|Zs<+Gbr%n-Daxb7(1UUntD(|I+1S_^MuC$6C{N%G111XrSTLHCq*iuN_?BHE z!*LmZc*GD@c-a4UhEX4XxNsrEsITxa{5tv1?3t@?|HIg~ z$3<1<|3Bw2GYoPDW{|J~^UMLc=wQrfiLP!lqu^*#Fe;&|8#Cy52@P0EYw6p7f?C!B zR%%(zP}x0&+AiO%-5FBSUEBpSMUw(kL`wxiMFr09{hTu>yWjoe=gY&K^EuD$JlD_t zQ^z0S<@g)9NAR|WKVp`GZwQ_{YI2V-|D-3IR?nx|R2Q>$n0^ zJkM%PH@R|uZncmS9lN*mpfOm${z7t#)%qu0&K0*sP{r`TSuE@6bDF5Jiukd-D>+;4 zw>WMElRU(wtI3HH^b@E@Gz9)(hTq=9jF%?*h_^5%l;1{j_b_+;=iBHuXfe2E?ijIe zW8VzXO=GCe%sC5mA{Bn^P?QiZc-B+TM4VF1jhvGd_$CLVKQ5gP935miwUN$Md@?*~ zG>~Y)SD|Am>G)9G1Re@Kd8a(fn|BYw(a3Rnh{?og(HJ{z1%34-@k*kAjXagpWW!G4J0` z%pc(0s(Py5cvHXUu(IP9aoe|4(i^Mp_?Z$Y9gt{q;%B=4zNaPXy&%^+nG zI*BpKgV?|Dvg6kG*PLt5KNGc3BSU151^x$mh+Ugb?yIe#_VL=6u}0f$KF~ zyKudL>rc3z!BvjSjq8uN9>-OP3;i(HLA9JhU?zGktBoC0F!u~z2=cESH13nU3>tb< zB+UUCOUkEM5_fveS5q7vV$(9&g)zk970XD&I#Q8O($^5xD$=lmdNfXV5Y@w^VJWFt zLj4-6vWfpYG5cxdl}QU{>;%rb_p`da8*4m|Fa2rh@ulA^{hT|MFq3U?5J%(9 z($jxW(ygQ+msC7UR9i^;CR%QTn^csLiVZ~d7-=X#L>JPq8e8Seu#9kEZ>MOOoFcN0 z>k3{Oz4_JKGs0(vEn`|pK|OgCfm2Sv4zCY79zTlB*9X*^4g)OPWjv1}$P~#F7=Bv> ze5WOImPaMmIFowe1;WQm2CJrZz0_zgu$pElX52YLFnL^cd#mzS$J}1D_b=R;hrXJU zwOedjTe-yLQ4#bHSo{t6JDsFYClxaZ_Roqq(t!W)<{U@h&AB0kR475vmF;c(O8t~t z6Z)ZIW^l$R*21V5O6OS^O^_8bDwdR4h_JU-urREJg)dS6Mlt<8(f>vt!tMA=#q_u7 z--fqDzgtXylm2a}5&ch#>0bJ`;dRmfKVtf8^l!s%(f^c~{tEruunTVD#Pprwb3tFJ zXR2Qf%@|c}VIacLjB_WFu*`K2yuV@8Ixs0?J93-RZ>m`8C8}6I8hVt0`3{#ir*fU*6)uTnHiQcasXp zlzvN8Gf2ZUQZbdJ-$PWBrFk)lq#KB80%=Gf^`14sYZl8#1x^-DRr(K+nLDr{OHH0x zPfw~_XAB(sSqE;RtT#_Kz-J5qi6bMBI6Lz=Wg)2jmj4yAJ{OIv2QrtsyB9H-@j`4G z&+pF^co~@$^3uSOo=MVXu;qp9!NS&3H869trn|nTqoP%;_cW`H;qO4jcVfLa0rQ~V zyP%>4fB#3-jKA-}5UbvM6eC{`5mzJrPJ$1s`kEz}7WFloRR{6+lZpnh9k>*Zr>ysJ zII+q?cn3|$)v?MVH$iYdV-wM_*(5!bSYIMjbHhf$)3H5~Q9&eA2O{dB$WWw{%~zDj z$VkQ_i|~)Iy(qt(btst^2J0Qbalv@mQ2_a5`Jf6b?!ZJQ$$}wPIJOPKK90NHxMeWw zd)Rw1_7}-kCha7)h64g?DIc^c{AGhXiaB_^2vSA_E9WXO4+OoUJeH~1J5>1c&*;PI zgw}wstd*@$)&j(t(CP*c0XHjK?cDEN<3npthIbA4s0vj)e1xMO4 z=3pTmG6~fK-63AZYG8x>)HlP^L%2@?tR25G`281twYa#_XL<|IpOq*oiW#0WHlIG* z@xu-OdpD$ysTls43b@$;#5(CZ7#j3u-E|{86JZ)9&z8>-N}3pe5(#T(gN744YkY)M zwTrcX9jFc=%#Y&k5Tve|be+7X-6s(MHS4b9h%_?i0k2D*9dIhScDDDZScO9pS`U-D zJX^E@<-2uVg)O3^g~IJ{ML4WKVqe!;LdgmtcK0wQznc@7&woMf(2eC2@ykI=R$@DV zHGxNC{lB%FrZSmqHkVw>9 zsIk1*W#D+^h^N(1AT5ekC*z1CP~_kd!2iJf{sY6lwUNAuT_k`^%fOWgW+>ykBPdDq z6+Zf&;Z`J|BB-KC{GgizFd^fHL`U5~%(K<1rG>T|?p;jfPGjW@zAs@=mGXwp*e@11 zJ?O`>cz;R`#@d&;gm=4(-HYg2u)F-x027`U3w8ZJsfsWN- zRtRF)S)|e4ID@k)|E3C%eB2_Y|2jxz!i_;M9irr5)}h0=CR>q;dLn0^ULy&Fk|Ud1F+6;q{b7x@AJn# z8%3#L)^LQV$7iQdM*R{cbM!i_{}gMP={z`PzUo+Vn6F|A}1|C!x8QeX4_+Pf@p0wo2)-g z7jB*5Sb*lvKZeZ;kZQy5PLp-ei?bwj0Y=q1>*@N*DD%-Cz!#6WDyodJpQ5<=;c! zGs`T({-67U{`xr#qE$F@YXS&?Ia`<~?cBn#VW!wI%VY{M3CCni*W^4_CrybOp>^MT zbSl+2TcPbtXNAxj*lnG3RzQ)oalLf>)u`b0d-#|ol$Ss+e!K5CTPwGI>@L$sZ`r-Y zn0l7q;F&%J1=;8-vF5q&7w(_DzWPFYq9g#~H~N0F!M)+*f+BtN`rU7P4QI_eJnv0; zZ!Qwo#k%qL3-zYM=#dY4PcoNQl75w9hCkbDS zKWoSmlCmHU51jc5VtKNJuZ(HR6e=-Zl0_e9C7H!wl5ys=eXFp?PP8dnnSX#RUL9n>p53?yl}3!`RKL$z6-&|V9DKFEJV7r<746|rpE=pTf3`6tr7B0 zWA~;TdJw9RQNb6$P8h+dcdcwwM)wC37)(w%YPe@q-_p;?{;ESO{1&Yu;t58Lic; zkhk_-x-v#**K6Hd821+ARy~v4iJZ+ZU858jly_;-;ao&&k5#Xw_Ry=D)wJ%u zf2YLfz3FI8_TIL}0N0-%5UI;+=yQ==7p zw?~WJ-Nih-sXMf;yI*0G!Q_t?Ft35@duXK)H9)b{p%WYt+$pI6c7MdGj;F$uZ!35I zRsSc5;_S?5D-+>f#JFcOW}7iH$H)wxK>=R^rHEiwT*JnsCOnmr@yR~GJB8Z?W;FBg z$QO6h7kdOF0yzqLT?-S@%Z!$o9d40vw=qqv#_oROguAEDL|8`{ddAOZE4~L+l#Y(k z=8w)chqUM;VEQ?+Z6eS&eN&5G&QucN?q-lv!zLs{8o>2F#dhw4u9POoeT)`5^=?KJ z9wR;#-suC>eU(u+BlXG5RBr)U*u>BFfR#wVM}+6uO4d%cU0fEPq0uiu0HM*$e)^5R z%*bZLH9W2w8$HWRqg9S>cj+JoT0Ay=g~&3a(FMTL<-Hl(+jVlHCAtkZSB$=?Inc<4 z?;ypl$P?#t=}r&}xm>T{&^F|XF-nZ2#dggUcRF)2J=smmPt!oNU8Vh16eG?Anc*og zR5%^l^hLvl1TwYjT| z2_H`O6cjhUU8cc|rIU7ZywK{6CLX?c0<=$xN43d$QOK?AANfN3G0(g`N#p!y7dM2W zP*BAv8nq;kS=xo()UaG$au@=%ad(l6-ca}q>XSJ>YQNh_Q~NxMJ=qE_y8I&A^W73GpTsPIK5D z+T;Fn&4+5Qb<}&?d%o(oI&>YI``d!;Vd|J;jpaLora3ArmD$&LM0YoS(vPWhQ`|=- zeb_I+O--zS^iDKJ#)ab`tCDz-D%!rFm`#%WBrK^^lAo*}0px^$msxE7gwI@5>0VTcU^@>@ zVKe{C@7vc$Le0co72NfBonth%R@M=j`MZ57i`;fc#Ao*wdH7EbgbyKd7l=S+MnCta zn&kAb{BNYql+{Pp=|`iTF-OqsG1XNeLY2CvD%4&z%H!FTnYoGQH&s?{D%hnf5OkRW zZ`Vh7cJacB^6C{8B-%_id)PQW;6$bx$ z$L{6WUpHFyboX~M%Zr#*Wla87=D_o!rGgS%MqB?)vFe5@c^Ig8m2$m@54{ao&Xg(% zjG4^%rXy-X*VA7~;{d;u21|8VW?o1Pia7=bMp97JT21X*cze}iM4(Fe--g4c@GO^x zqe8J}k!OYC8JB0P;+ff=&G@rswkJ1EQj6r$l9g8$GRX+hU7Q@8GOIFocBS*fUx2I6 znM$FVePq$THH)m{E9~RT&F)Q^xtoAKWG>!>Z*(uxb-&Ck*%fof{^*^#S(YWc_AT`Q zu5~e<+02^RPQ7lIGB>Z%8AVdI=yG%4bh|ujW+Q>q+wR1i<;h&7+}qFjj zR)1G>e}~#D1tkV&T;2_&Ai?a~XB94AwY)+j(j zLokg=7a>kqj z-lPg9c(NzE&5L{w{q<`s4LmxN-NfZv`PZYc=#tF40}N$S^~w$7R@%U_SZjcy%(H@e zr!CGIZf;HqZGshTmH8}rIe1L^n0_Z%I-=zXT0r6BR}(*>`QogBe9Nu)Oh8gUk&X4H zeG;%2CCt>TEWU}?nLKW^U-?hCp}2|4lYY={#W-IHQQ#c#fue44sHv=)+24Q7n@X&{ z?i7{5X12NC*|#fxWNttM_kq*=1!zh=W;C40|CNj z`GBKST%EN$KRzZr-Vp4Xq2(^1v$(G+z*=34lZ_kec&8s6E~|$zhF*0iGxqJk$|+xRUN%5hhmX5MbrTg^iDx~oj@75Wi$S79zmw{&A+E=ad``=zjlaMhSd ze3)Z&vk!+;?%Gk8xC>YEV{zIou!iw-JDAo}$TgF-hQ%g!!0RIqa(!~ybfF@WaBqEc zkH9Su8gE#`;_YFvi<>DeFO)HhI+0~nGqbjTjR1r}2umvRaNkVT`?h&ZVeuvhS9b89 zkp1$BWhPG)Gnb~`>1Q1MFAJec6L9mK1m-FDe4FQt-ZXE4T}j;L;(|p! z*f_bCpVxHffj>D4mlhWxgqO$0aUVQmHl6c^6dtcSRBC@|6SdAkO(xZgbEzvKPNCc~ zWIS|TVofUV7{VcKRXp9e+?5X_OXaK}Na0*#rvMXIE_NWoPxl5Q+B80~4Q4tzz<7HqRDX`7MiOYHj z95*`miXBn?P3GdJOuAiQp8#W}y}h#K_bRf;o4Y8b8ByoxW+2|&3}CbvbD0Y+^QH=U zBJowuhxVPeyHV%VfFt~b4%i*^se!URS#sbR1(SEhNoEPeYVv8P&#(ri+Jk213O=|| z2%0vMaBxqCm$Py943d&+G*9+TtqIBcNVFkT0YBG#u(Y*GUFdvG)#crj9bEdBh>&(R zx1?>rX~9BAhu^@udlSe1} z%Tg8{a~N4#4#UBVSfuBiWZIKYqfeu0mrigw=aB57zB1ygCgt3tT z`$TSm&EH}UvzzZuTNE_X5h3u_8uHmG@|TlKKApi<%t2TkxWAgt-R5qgv=HJ@ee+vK z&kI*u$QRe!S~RJ>r$SOPf4l21YNj79-a* z*+-qShA}HC9MK>rw8;f=w^cxUn*1*(@}lpmVP4M@sO)oE**w$D%0{>L5vlhI2o;dHM~$$-X8b(9{`HQwwf3HT{VADFpAC=%MtAPel~YDIrZHBo6b7 z&zyo4eaHxtQs%hjTo!dG%J)&jJ3c9{TdZWY!I@$uISqHkQ`#?9l90H}iK#8Qpu8;a&Nf_WuOt!hesC5iv&FgjhS$CQo@I$nT?lmyvUE& zO64IRF5NZ%U5@K78R zgr2qZS3YQkyXYyaTr-Fp>69)12dmZuj@VQ5h#h&hUZiL1U+LL;7u`A6!DVOIfj30y z=y1(HLW`9UYWzwFHGc0tSc(dbt2z@iIE6K1tu-Uxx-7+-u^Wuaq>PyeVeqU)*(SnL zP53=+fz?CGzh>puD8FFs$%@Y|s|AhOP!ZH69L%mySfimaO@g?d`DDIurK>lyRY-F#)77eS47Q3TnUu-N0$R=W6Mnb=|kssP-Y z09*}|o>*7PMZv^KBrlO%1VPddNr#QF6{9zue)jM;i#>?%2HBheYmmcLI3PM}Fq5F! zNab)@VqY8UKh#G{9lyBXmZk4vZXsao_#6^$F%xZk<|r!pxdYt>Edyw63tA%O$r-bJ z?3LlY>_#Fv-yPqT^8bt?1klQ5JkWVUHs>y>gyltsjaO%yA!szeJp% zYmCl^BBE?4y<}z0JrmNSv2c}= zta2_L$KBR&SzKB3v9+OlPEEAX& ziR5-k_9_02`Y`l`WF0R&S4w%Zy&r%fc<4e6!(Pl_7yN{mrZ>2)`cZ->%sjd!wSm?cAIZr`+-^B=l7gK z-o&PopP(6zyH;;fQ}keWQ}J=HD`PVNj^Fid(Qo|}cN>gFu7mi^u|U1u)%4{j%pNFu zwsIl6yrf3w@fcIRHbjM~j9!QjH*F_#y>Gw4BnRQ0Yj(RavQHg^5f>JW!%*XN$kO&% zKPs^<8s`nUypt*9`nH5PcZ~CF;kSl3ADRM10O8ef7zNZQkM<+9-!9m zOD?vz(e@svk98AsM)DNpedjvxD6Fb_M-aU5@%21x^h5Ll8}SLvI2xcrk#kwHXC>yZzfwe;6Ch4KMLwH8+kKIl zE?6UpHH!!=Wm^gsmTT!OiN$vjtK!p8gN&=q)tMiV$dbE%LMyv;6D~r5$wWQ}`UB(# zh{`uLEOfMhZ1b@cO&L#bsi4% zl{E1Q*84Yc)N7VM|5{mDoGb0lWpO8NDGMw=A(7Rqpc&4iM^_(_i0afM0owS;zqyL4 zIXsv>?=rI%?f+70|5sA`|El^IMHCx{Xsu@{rB~4*(nqN$ev$xRisK|4y_wfu{fh0#^z|dtg#)(1M7`xu2Oa3R-D8#~f!~L)Ggh(Otbi({z<#65Bl-t_ zRkL(eRMS-vbBft|8o#&vbR5K(`<4;>i!<-qHP`&|F8c4B88#3U=zH@NF>{C^-;Lky zgK+cMNcAB1ool|zME-k!4e_$vTWvv&DTe3M6$G)zVm?Y|iODwE?Aw4onXI0bl0}W26K%G(j{=hLgaLEPQi0Oq^ff zPDjP6r)BkWz*}__#HfdZlY>guHC-%g68tHXJ>8RaNj(sMAhP=?S|zKGu=T)OXTt)L ztN?HuEtz@tGX5s%;rVeZy&Gf`vtR&(JE&2HGo=&;?MyxM6us;DOiT@Do}{;oM7~cL zssR2IF4YR>P`!@PQCf9~Mc~f#azDzg8W%h>yovWiL_wN7-EBJN>@{Qu3-K5*5zO<6_DO@eq z;kPP={z^h9xMNjwEir$9zV#0i5S4%?+zfe|)w6t#z_bPBa6(LRj&j1qQ5TcLd`h%R zms;qIafD7LLFU}t+F%!(z4tb2Od%f4=Gx%pY-^h6_9BX#eMSXqWMi z`hw$GRfgQL_eet~FjHv5k{GnxB;D!Iwd>@s>1PskOcI4k-5gKvj1SYViKVxUizaJ$ zTjU?~9gAaCsd6`s3lw}8P18olCx+f(%q&cfTrgmf6ee|&mfjiX(PB09mdTWg{j+#j z(~*ua#&CH#pF)zrEX)k`X> zR_C9cjdyWM=v>XoaeIARY2q@cH(nd* z;uTzZMG%(!Aou<odK zX$_Bg(KJq-S)})E*p4*$cNRHoN*DEh^S<`zNfL9ea(5-UgC?Ve1ee@_Bt@&f{^mXH zjt?|5zD}7@iSThFt5{VZXq6eQvZGZCGna4FsAz62ZIvoFzmk5lc|@x&{YRTJ@%cLeVa>RIP`%BIEfe$>=?b2wMu8qQFk z%qL)$2L|+eYWZ5SacYeY<5?+kDV=3(`tu^ktDeI{$!VZi70=)?eJe<98M9}Cdrt~6 zw1Z9jX|pT{%{{GB5QL>bQcZ-B)$sYL_ z5f|p9B4c=WC*ecy>lS}BbD)!vjF8a;&!QVPF!(nR#|#DGcONc=2&W)8mr&o|q~mBK zaTBnq#Z33meUIX7wC;6RRrW)}5?qE5%b~2}j%%go3VS+kbbL0@{NrW+fgai$hMWK~ zmQT6ef?-yZz|))jSc&AX$O-<{#1*iA)iN z*BP=$v^U$kPOQR#L)-i9i1vP4c=5DjHHF&^2S>E`pk;+r_@q^Q^TfcJq@g!)}yX&C08Ze0UZlWnnc#NeA zNz3s>v)&y@86n(lG zh&WjV#m=vz($qscHD%#nz}Pc*RboK)N_CQoJgp$RWWXlwHdGu%Wwc{ZA-1c3OV}mT zXVytOx!VGKkaataZSDAW!B8sCtX4-?p^#tNUwSZ$n$xBX%cjz%DPfSx9Hv_;d(+{k zD2@Y1#!dICapHaLPy!i;{e@tkd7so?6Ty%%{<)hLAKST4(0b&#o7V|Qb?n(&!G`nB zmR=GIQzfUCv1e}0*1R)W=S7R8&WsXnN&$qt&e~4Vdsdo0v0Wp|=_-wBFY*$U?~Lso zQBJRYuX}#6+>nvQNc;7&uzyee1F zW(K}umGh&2v5Mn{;CO9(d`fJ*nUBvL%PPJv^9^PvQpBY?_PN|$+5&k&<~>)DM6!yy zId!NfYJ#@THxTuYaKSeiRd!po??zP8ZR|(kGw9(b#Fmj;m6QQe7rPN#YNouU=54G| zocMG?Jm6)q<+)q51+sEzUO6Ck)Od3S=RF7N48R&BdrzAwD{@Q84IMg3x_Y z|4`GWIMwlHeSGF!f%D15QwEzA*=K7DWVTsexeDP56enETyP!fa8kTrU#y}BDjv6^{ z!c!uBYPcw7yQMgrQi@n91yl~C6g+)O@05x`EO?&8XFmNYzozsxX?d?OH+(r<1LAZ_ z`A7d-eyx=MsFM^e`MYQ{H$a8}5huZDEgMVIMh zWQ1S`d_SZqJb$S!;Vdr?^vbi|7k>hEy&7REMz zWnUPAo>~VAe-c;C2eV-H{POUj(hjjq{lvCa@Z?)Iqyo|#aiDZ)zLE=uuI3%wD9h3- z`oZop?qO4XBs9jXk<7cyE*%ud$_|c`HOSnnKF-Z8F8`6K=G5D!an1ur2htve*Epu3 z4Xv)@abWSdK}gm=a0{~=duh;5%I7UxPW}=eScJ96AyDnwF7;N%T%hubtCEuBrR!_Ly zgTPT6bbu!65BLW3yWlU?RKMWBy@MHWk8<6b9|3;%J%b}WB2XewjG!lF9#UrBnRXh(i=am3-vkX8T!3* zd7*o@4oI3Q=WZ0>vMTPfrt$76l%3d_$F5(FdU#s$`WHJ;%rShkT)$A47B^h~w-kCW z>JCaYrA?5a+@c~jrO0M+vPP%v4_4M>wZX^TWRvZ&I(AB(?eQA+o*LWwBKF=Q+Xg2) z)oFXe%BEUvPnuY>$@a%O)>3CHsbQ@}>@1IGq5D0ZXFXq(bDxu)?XBeQu<5*JNGFU--HlOAR}>h_yj+)V-c5*kFYE=x_;ECp*t+tFW^7uT`4O zQ>?ZvSC%tt6;9ih8uotAn{hR^XNuVS3)U-&Y}=d&L6bYhY1_Q=9%h-!Zre-&%j2B3 ztyXrvd5*$rd)CBeq@+wS*`BXsGxmLg?|QC=eW1qnry};jB3q@C&2-wTtZbImR&8SK zCfoKpc0rx(g&KBYjqSxEc2SY-B`2HhwC%964_R$HO>Bl| zUA67iBHL~!yUb~O&C34XYJ1(pK5Vji>e$>mo41B_)Yxi@SZ9JVuDw7qF%ms@Rb znb;L3+nzesRcCvd#8w9Rb+b?VX2+A_pIz1tL=Rg`-sW*K^>c4XZx^*U0Y-O zsEA!xWZUaxA9dRHS=j=st=7aAnrwA-Y*C%l`y|JX% zZ#~f*auLf13LZcK)EXgwF3uU*t_<*b?(+A(-F*OVg;!@-y*UmY-E}7Qarznqfk4 z4Ib?V^I`@e1aNE3H&d+QKzNWh`A2HIjkC~zm0`nixJ&2Kq5>E@0pE?Jhni;#*6J`M zPJ&bc(x4wDJ&U1aM;K4<1*v6&txSvEBPeb51UWTNOOLAyzT!FuN`*g z+7Gma;izT(@Kzbb-8+2#$wf&Wdh1XeE+4%t1A|dSD}%mC)Cu`kc(=Nnc6dv^naaUi zfx+Vt3Gg(^hgjym>n8F5OX_yda%t7&KZz>J9w3dm@ezt`5#^_b&-KXZ#QbI|1SwEz2#tNcM^KBqFYYCb*T2})Si@adip z$Gav(*M5E+k98BbY<>im1+uX|elgtGXPJP^n87~<{f8giFyhysDAd4MWH3{>?t-!A zf;ISf)@3n1a#j4474ZBVKf5q~;W}&Z_pUfZ#-npZ$ZN%4XWsF2Fwv)kSuRL(N&?#R zj(a!K30oa&4&YXK=28Ty?xbm)vDOikgH;kkFMdNq$ryWHYpsNW)#V+BD|@N@R{i&K zb;l81BF-)8U>(iDIuXT!fyi-Mv;Ky}iqxSa2k3{wU5@ebkcN*i#nFID?6Mi|!d$S#VHMFbk}Ytk*rW{z+G6u?P8_E8Wqv;bGOa zzlm0Yd_BiAm(w@M?TnXSLh&ireK~ihrFsriHiyk!^_X)`kZb=@#86npn`4gf=J_qW zIkyqMO&z@X;Bwx)ZyRqOz?JhHZ~pQhyg70WZ!X!uo87ns$hryYnken1jX|QgS5!X& zJ$?9@ge>S#6^*-n%^ys#;@y zw{X~usQfFjyg{t}J9WU_7_H>Q15-sfM1{KN$p!YX)!hDv6k*P=HL`dXF5H~UwmCkf zi_;$eARG2bW@a(vcx%}Q9^r1!%-om>Z_T%DONrMqoU+}rC*Owu|e?b3#J`=OehERfVo(6U;wC|S~xJoMe{c{dbV!d+A}a~_dcX#4X+f1tw30~sE6XS$H$Wd zU$!$rHaa3%AwMC7)$j^5j)_c>=fA>fH#Dzi8iThz*ciK|XWQq9wBy~{x-;YLLkveq zd-3kqKtzCY(KeQS&TN~QXl!HwHy3k3=AX7l{XR(l=L=R30Y+Z#9^kFKur^Vjb`>c3 z(*vc8KwXiOiBb36wX*}_+ihEG3$MSE0siZ|864U6TP~uT-QM%o1tA%_ii0?ZXZ^|K zc`7XfVu41xEhD%X4PZ0Wjz7@Vip7-EvpQ>A+JTQms1xY_JjBeR6Bn;aA30I2SC%EZ zi!^H36_>4jFe-sTNzK2ZA&rv9rr8L0M|H*vUZYquin#9NJ`exwh9yy_9JrAlMp}CY zGK|S0qIW6E3kNb-;n6t#ZTNulf&rABXc6*v;upb}^lbjF1Ai7R$4;e-uIbgmC?@OT&#*Ui zrQBH)e$M=!4&dtXi&J)K1BcU!#k4AO(kZ;XNZ+>LZJV}T=8Ugc?EhmQfOX?f_+-|> ziW6-3B^Mv6-*d^hhf?A~o;$JdU={U9-|x4TI({7DZnLLL=E9kpZWxAT2pjU4Esh~E>$9IziV&kJ z)9OL}rZ_*g^OULdgH6k2OYzOsr!?KCF%uC)k8bUH_U+(=eM&eQP57AABZz77&nEs3 zc)CovJPrP~WKPMWKTH0%bn13V!{4T3Jx}wqeZt<-?%6s5a>i_&INNO1%eS4U;i4pg zr)p_>S)nO_Vo>~*#%gX0GA{W!#K;Dj53^Sa?y_zV3*}AQ!{_Ru1}tlP9yx(2s@6l( zVKlko8E4%Np51lRb}iH~hLik5N}`)U(xD{2UB?{>o-&SPdXQ)u^okEr74h+9F?oz% zN(aSJ>+wAi_MCBuFF&E{W|N0gFe(qF-niS1{-NY!?22V|i zurfi**g5-VH88}^kcalI!(5o};d-~FgE$4@?&Kcc_PD_1rU5$yN2T|`sX!=qt)}}* zu7Yc6=o7EF!@25)Ua<_yANOqD$ARI;y&F6&oU5<6Al5L<+xy<&##fvZx$lF2qu|QY zyTq8$Q&V;)2RED%mjz3qSBX;orVu^o>6wgR9u!DW`NTmQ6$~{IvNiCYInX9jcGgHf z7f>TME8+_G4JK6dCg=EV?Jwvc(#%bXgl>H9Dho)8HIrfWK3#Ba`kodR)_b3^{XBI1 zOtD#XK?u4OAw|>eL>*j&<^3BD(Dbm0?=~Ji4_92X?CEZtupzS!EFHXwmxku;2J`1R zmVe2UqrQL3laKA#d4+E8!F;SoXc;Q`HDzkbwoe4%X)cnEc^vQ?lk;gAxsh-eqxzD* z_dIH6h3mtNjO#FD?f)KgtlHC4^a08Gg}&eN9YTo6=G|Mrb9%Y~vVC_`vvBTr$n!JJ zbF*nA1u{R&KQHetbH4eEjDFeUw%n4+EZ>5*?7feEc-)p0=>QZcj2Mp`rNF!gaUT!7 zgbS%P{_=9ozO9vIJ5^=#$jjxG?^f=6uQGa9&8V3*HiARIHTMVa$-b&S(LU;;eHIZ$ zT@q$7b$15WEhIIgbT#RudKamFh#(;Frt?sf(R5Ehxml&>EkmOH#cg&wvA#g83-CVP z8W~>~5)(T$LK`!CPDBtF0d|*3_S4M?n(l4Ah@TuUz|@JTpi0z{rXe5$ zFpDFIGKi>QxILk{m7Z>iTobf%xsjHflpqtS5-Y_5eUQ~w>q-a2!bi^6-VnV5GOa*e z$sX5pB<8t-OuB(u$NSy0wUzRbzrs&oRt;(ao^XN)&??zr06O}J*2SOE?MtWhV7*Yf zuTg7m!|z2r-reiaEDe5cSeZt z97ZO@BH7I}u9%La=4-CCRU-;$fTWGi{Ul3BA)I7~Gu&jmE~rk&mg$%pU2u_3RjpGx zbqeN#8hp`3e>_kwrQJyYXBj{4~MUZEpIJq>P2>f}9rfdB)e&*r@87_joCF=H7nJQSc4Gh7P;ZMC5ZO0$a;T9G~wOkRLK7?6guvjOW(=4cn zigs>7%yjt*F~sDL;3DCiM>6~2BB?15EPr4P6fpk55-9RVD(`1lCemP)hq>A}t~!H2 zWv$b*h}`W%cr;6-;EybaCIA0NrA{U?rxr^r`Y~`6QGD*BzJeU%VwmoXb7m0xfuZd2 zeZvh?9u}KVotK}=>qWJLnsJrIkg{dT)TnFN27&rgz@b4Aa10^Uvk0-AE1agErt6q` z4yX=70m8w;{24Vszb6auq;dFmj%~_aARi#nWW+1G*(}i)uO%G ztLRYwnI7~lN1o7aWs3aNunHeveh*_}bTZ;$`g)u@mccGyvgjZ+3Wzl&P z`+!xEBCr|Ml1oy$#pWr0W@qv7WJFz)#t{Bk9jgnIn7O6bvW^?+iN|p<&o{Sq^_S8R z(`k>B>lj-25Rj++m2HZ7X3$wVg&E4=w-Du;-AkHgc+BqHj4)aBwRsYgp*CmAQgQzX znX_NAJ~_Ml?UARJ^a+?v23+*;61%I0#N09l$3u~qq^$R?)-7fZ!5;ZA%anIzect7` zEP?{hU9ZbsP7fJj{KZN^>lXL|fzOpB=-eA>BCNQ`@-dv%2UF>#I$wc;i`v3~=F1@k z=^LShE>h&dtdjr|k`klIiMqx3gJFv$ikdqM} zg+l+E#P<9M#)8z6kTS5FB52Kijhp& z$b5PXS=f3lQR>+YvhDT6o}+g7h0CS;C7bG(i#c#sG*vOyDv}cCn>X1k=ui$MAt}Zb zl<*cU!CtS;T%@;WFx#F!`g@X@nTuOiLlS!elVnCz=0zVA4bfOAqC@)}kphx>((fdR z&9;sS_sq-1%Ag;TXw0=4=XNADyYe4M?STocrfVWPf*17sEFV=+Pc=^KNo`gW1kp3; zrxm7L^vUI+4W0HdhQV;DNn#-$_t-h(PSLVcObo(UCI#hG?S4`Jl4#X1CJh<61emQy zkUYmL%|_oMUv}DAZZt;X;@QL=#5E8Y^enayqyg~USuO~`NwZvt$@byIfOooe0TMZd;z)B1^5d0#sOmb7tLjT9#vVt2AVEnMKAkkRF%$^xO(bCJ9 zmxZkjFK?1W&hiN%6+^}Al6T}R;AWM< z0CK%nhAq+3(YG0c<3MVIvJ9pkJM*=Ig{4DjqQXSHjp>!%OD_dW5aM0{xb0$&W!qaR znA1os?R(pPM5rMqlny(JGBIq*Lkjm#bXrEOP@npmR{@P3O?+JzS-;caIqUw2sXcbF zeK!MXZpZVzwUPo|*`%HOwrF9Q67Z0l z8G@t*ll_(l?W)6F?{Gp0Q!^nUszo6uq3%Z0q1rWyK%coK%m4)nXjQ~XuD4Yf!KbKl zdQn)ir1Sxe4^H-^t^)MmF#D0EC7?7!0z%+aDDxl(El1KGlM^k!Sva>D#SG{CFDa+o zl2(ivk@6mtDao{g{~J(Fxty8Wdh_iaSzH0&4 z5!96v1|&>k7g--j2LEqynCg8oW>!U)`mG{5Q+#;*SWZw>_=i}91K{-_a; z-qi(clC`ImiOljYhokGtm(wkm5ni`)-egY@sYs;WVpWq#x`|Ybr=EsYDb&ZTDw#A) zklyMkJUy1E^rYb~a$<(*Td<6~u`6BK7HU;FvK2~fi5O{lvyRt};p!5!7VgL#t+mM4 zYgff`q(Hf`0vnl%PvMJ$>y%}x2jdfAjd@U~KO(m3K@@?m3$DYO4Dbr3n;L!=S(QHh zSNs(kfTgMO;8Pg&q<7#i+wdd)Di9>tq)|bu-lSpD;c`_I)NmYsmC&j;shkZ*#fi(y zwnL@Z?5?Z@!xp;V&y@P8(K|{ zF}{Oo2kwRwnK3<=Xk?;?$(3!RN_u%i3eU#@`+^^8qC6wonhik+GU&JsJ&{k^ffOhE zWDHGsn89|WVeR3H;8_&~}Iy%mtHR+@Fj13pUmc;}-g(g7P1#VStL@iJ)(-eg*v%b!hg)LpxVbb5`d zI)|CR-q_L;we!wH{-}&Q>pkE#4Qi}mOAWK+J(;&xx_472p3y=(;=K|9yXx!6y$>!W-%$ErAcm_4kH$*8H(rOG;lBccc~>-@Fm?4F8_5#=;AJ zUa1C+x{M9mW@UKaGN1jx?R2LHr$pMqL04n*GmrO8fJ-Uggvq7{md%5^BY{)s|I$xQ z#I2mZ>IQaD$|<=%q<{VfUgEy|(h&3PjjXzUla`o%pM3O3GJiRB<|WY`E8mPn6ilq1 z?h>EeYn^Yiu$U3TQV`FsCTv?-*s|)drL=Q)F|yY%d^Oa(y0^HycloZrSCht7Kd`jy zfo0`qZXEcD=rujoNpX-6T)bYbkBZu=f`&2%Yj~tAOQ__=`T~O?8y>G^nw!H_%XGfu zXD7DyJbXi5m?65}apYa&HGMrstdY_nhb;Tvqa#)`!7n%G-7IDi9kF`2nbSv{(vR-d zBSf=S_7cSU;I$3PRqdT6oyK+4(ol#!hLefjF;2T==@fH}tMtlxQLhkLRuMBLc*>~gOuJQqz000S(z-?c z=(Eg*GXlGf{4`tC!A?J3g;9%3;d@}Fror+jBn4K$8&(BQE+?z_^%&0Hwdu7@wET&DRj6s;D`&uSijCd4SK?oE^!nu)dk)+13?UCh7cht1b;YA%EuRaZaoMJW^_tG0TXJI;VR z3I!hUU)rU(Sxn>^h|FY2lLWyx8gWMCe~TM^yC~#;3pL5P^n2A1);&%8#PIFrJ~eLa zxOwafZk&d1xiPtqDhpgGc=FzJ21W#22qdfS9UFJYKNoc3N7-x4u~_CgO`AGBh;%3W zIE}nT^DQ6SN_Qtc7j*s-xu|PzH=aeRunSVENj@$tkm}UO&VLPcXX&FCapMA<(97HB z@MBh0ZSkIe{KQU3+aU5U$Te2Fja$8|tG3ii(;);RIbXJ|y8$u|7I7u3lDw2r*FT!jp)JxJXYt^Uy zHgeuZo6fI$PU?G))rVKnrsGforCEtt0_HiE8TCwJedYP7ZmL{0xRRol9d;_{Q*-rctEwZ9!~oJ%Hr@ZPzdTXbnRd9v@0dZ3|!;{XMT49dz7 z=}*pS=wruWh8isKVPLf|7ENQ`kKmaGOH(TVy~lw#9vepU&vK%m zS=$POrn3{~L2myblAL;T^w8*{gM6}Kc0*|PdQ(0rIww<%4&;Z*QZDu*!*{~lfCXmr zRt2Fy96+8e*}AmFo@|Imv&u8zQm6blbE&iPAZo^eha~kdp)lMuT6!F~)Ae8V5h_W% znAKM1I7^Gs%3*@s^{VZ_IESm4M(_CVLb}f4+;?IQ0rw2ceXMd7m*yRdtE)KZb|vvj z*C!|96>%0~SngK+I&$AQr>zEA!IeBC$aPiV{7nQML)(~WXrYT*T$)B#YVI)+x~pSm zihz1VS4xYJ1YOl{UW;5sue>zsP;gOO+VQxWLXNcEh`)S7@LzB7NhTrj0H~5!8c|cP z{79>ng9HiPh293E9U8n@vwZpbic-g_H;R-;ee|DMJlT2(4#R)}40p z7gi6i(%0ycX72R*<}oC)JLTCUTmpY`)=jl1?#UkiP16L4oMC50#Ab~99~a9`eqYbQ zW|7d)6ng$Ig_oqu=k%_34{}2C)(=C6pzBL~e`j_^Tg{~EsdrveRIP0{llTNS)Q63S zT*MAcasmT2c0O~k8eVp4hW2|4$-3X1XpH;y zmNU7Q&B>GWF4w{nD@%ED{|bMs@&1O!IFnWR7+~f<50tP1u^$>F4 zGdgF?SuzwSx-_A$jPp3{Z;Tb^W<%S99rz1jYB@@lf`sCKZZpCi7ty^);jGOtIJD^T%wI+335q8Yzaq7KN{1+$t|ImS>()wN!hz$(vZv> zy>QGPigK|uw1zs^+KecVJE${a4R(UZ=@Oj8c|f(AE1_E!gJgk0HU96{MTtH;Gu#EV z$drDiNH7?-Mc{Dy&wrqX>kaK-MhQf42$5-%t7?i%vDY20#JD;P_mwtAf!e!{Q6~>h z`5I{GMi@Ii90MvP{AOn37`q)- zZ1jSuO_Oy_J2?vCqaCKUL|(CQOvG2+?KwQ6K)8b^PBkRq5y0f+x*Rmok9w$vzrp7T z`Gq9svh}Fdw;;6Un7v{>YJZZ#Yi22@P4c#}T>5hyO`0^>*GFM~7zCS1-(h1!NPyTL zq&oy9gKnx0MMxzkAvu1E$(3C8)&-H`7R99oVxkQ2opdCL6khVKi`wiMR|Bz~r>?q| z59TTyDrNN)?Suu6LS>$UKVPefolFx(N9j(!enu?$6yU3a+oa$9bVD5Uh;NV}Ds-nM6*OflS~e4SB{zc_a0+^RZ|{FLWi znz**TIG&TUN{bl{4Wu(*Ikz~a)~3dc_b2nnql+Y{T9t3OXAvpKsK`tu1yQj9n|`Nh;@v{a%Nj3`f-_- zI1YBe{WP&}W9Yz|knf504bQD_v}pVmj7FyH08GvI3kam>U920p5qLNi0+0kI6*yF| zaSv!=HXBEM>B>5H8%%L0maj8W%~|D@#AS4qfJLF^m!j3SAr(?FqGyB@xiZ?0C>`}@ z{?hoL5hAbmthRu)s|*GGe#~$;hRI5YYgjap1c+GkPoru7MYN1`_z_k>EK>fT!C{dw z?;xN@8W~b%UeiyXGr<_RpaHcVi&30MnG1DBJeKJ{rM`ab_(+Y9J0>1>9simZ_q$bh z!;G@s2@n)AvN#7KxT_O}8aq!z#*x)SW#$CI^23T6;A7(G86%?y9#ypE_Mhc2j|@!H zrEMQ>Df%-X5q7>siQ#V>sOfr2851Pwqqa zdf13b+K+DlbKv+ib89>u!-8fp5nLlYX*>%?n`{vMaBH40U;xgzCYg}Z!u=Qm>%=*8 z84BpSDp?m>j8`RoY~~b5Z9;x2GFA*Pqc42@g}{-#gL(UpXlpx>+>}!hl}>)JqCS>* zG_lz#XTBCd`NDx%ozgB5&C+qq*b*MoLE#Rp5-6SEE1nt&B~>w{*@ZQ3rh zwY2PvC8O7PgFHLw=SP@DVkJCy(wjd;5|%L{iT{5*5bpYkd>P9MyXmCmDl5sT>=)Co zjudvi#P-#nNo@a@{})!su*CLaOor#DB^Z(IW<>pwbt!l+uzo$5e?9g|i2uz{>3@3g z#XGUkw?dSbGw2)`|B+Gt&?i3b~)%DJx~U7%~PDczTtGn^?N;kY!L3j<6!2 zh=*Z^Nh4447*?0~3}_5m{li%*Sr8j4dGPH;2(besk=IDznxqqDr%IMj0Flh`gyqftPPoa5uJB0yOLBgk8&Kg@ekJE0Kb)V%o{$1Z<@_x0 z*Z$5UBl%}(W5^;OA8CgYDpara=#moG_Cqd^HQi~8Rs=`htY=Oen$G&4sD%xY-1Buo z)?v54UU>FcM7u;33u~@OncmV;=sZg!&$KT=e__A&oxnR!?vdlmRy2N$7x&V7nXqY}YObDdaHfPjP*`H7 z_+8T^;CPNQ%9;hQqTxFzeo!N2tW(J{naTOY3GNiSjFx5|qRZtO(ne<}FHx5iuY)h7 zq^LAp;Jjpcpr`ITiT;9#ss`LOzU!pbD`nq zFspbD4(1>?#CgP9OTP$Qsr(M93}9#e#4bV9jGz z!gZ2lOgQFBVtM?Yd|VOOYM#>4XRhGI;W1mRr|~jk3>_y)0u$U~lQ@Xq9Vo-sOb;0= zzI4s}2U50pF0Z>R)qTqjEU#|UPZkY5n_z*^qB_A!(`_0#O+?S8ZLueslbF$UxJft&M z>+BEm1nIe|%k(qJc&luEEqfF6$r0IFwW;~kalABUZ;B3a)uuYxVuv?-6P6b~d8;t2SBMS&ZBUHveK}-G~~9sF+?bg{Y28VTA;Z^s z{@4}ipzrv(c-9&&=W#-&b~mtcZoQz*p4!9#*?fy7oXs=d?}Zs3$xeH&_g#+8;#@{= zW2RZ(KySzB47|=9r?ab~2g59tu&EnGI>dl^!~vN*!0HqK7*U?!+5NoU-a0QgGsF#Ic)Xa$g7lUEzCuh2Lnr@NE2(yIL<=#01(*}LUrJ@6iz9u>`&nP6%YFG& ziWW26VZ+Z7<*<-ypHyZ)KQeB5ImPg}Ww20vn?yPxlVJ+7BfZ^4ITxJ$L0j#UtH#NF z!sI^mjT5cIlvHa$5c&$bl5rNWsq%>@P1*S@QyS1^bDp)F@_A@lf5WG{7BV12)CGRx z;(7w~xBo$8t1b{-;+{bBIJQ_Db%Cffy(dsNMyiQnTlBxSR^VTfvO@}dCVAGDl|FdP zp{#NTr6tcyYg4fHIkHdisW{p3%DZXzSCCI5dwoKaJs}Nn-6osK$=DPH z02gf%yQS3D1aEgZ^_~QO_vO^ffPqKRw-~`^+pAw8m*W;|U&MX+16J6aM~vx~a&yEY z(*xzTY-U<+DTk{<_VPeEp6hyh8nc?lExQfpNHZ&_HF&OZ3&EF~r@wl&w_(_;;oo}w zvTXIz-Ug2biW*3;tQUEnW_dbq7~1xhloemlAt_&z_|f0aK4=*_l%PEFAx#L2gm{vY zjkAWp?C>OyvZD2i;^Xg29UIT&L0tu4z4jN9(?%KGw>^xeqh$HG zuk@a;av>=%^Ti9EALLu;Le{sMcl(yc_IWhRVhcA*{bo|r+E*7h*sY7rc$yaHW5r>E!|&xi zBd}l9Q0L$Xl&9;1Z@FP8k&ydCHxMm&*MK^;$j2_Q+JUyotaz@fxZs+^j^DstQo(N| zDDnq#CF3Nv?8I!VA;Qgq%B$G zx>ClKXspWTi}2T9RVaUF?^anW*;-W!Ejk3fup%Yvb-JtWmcN$a>8QF#ezHYot*Vfp z_sY+O^3y3l7s=1X^3x+fm&nhh^7DTA`GEYalAjM=cP3yAa54s-QatN`$0{!HBjIFQ zJ8UC6v47!DF$6P>=`36dZBlpQ{R{FYS_^nYnDHI?9qe%B+Fdcl6b?szkU}Mib47j; zJ@g4?o=FN8B^JOaX);MO10;dSoRUP`1A;p&7LbDRm+&&Igc0HA5zcJTuG4B2tXej| zXd_JMVmERKb7o>#7h8D~vxGOb+4`nro?@^Zl?(Dqk!j7mQ1S+B(b6+9rA(S z*)4?}iTCE`X7HRYIo7M-p|hu3jU)*J#?DATMJ_?E)7Ul~9xaD0FdWJ9n(`yxEua8K z!jbRBw};cSkr`?8?>}Kz52@C+YrAov0>OcYh#0I$2&@vNh|^`3)*1x59N4WGS)>PK z`uxbHB@Du&6Ybv@0&Kv|h6mElT?%CX4tCwTz4Ut~$I`itMsxQe?*M-Jn49dAS~KG( z8Y_gomSu@OT#mw%o{AG5#qDRsVRD3`L?~f*fdS^i!Ey`JWS*s^UD2;JupL!l28Hs( zf@6{=i3?mtgz~&pNJ%JL8~9Ob!wHzzkB-V_6L6Lfdvm|_CRg`_3 zAE;0~d!9oVAjQ4KU22gWN;2-m%{d81n5j_kW9iK-4-;Qy>IGmI^Jx%!fyK{p@({d1 z3NK4UgFcPNPmQ0vrYUsC9WIjkOw7C(sPl^juP9VJ@uZA1*tA-c77j%VHYA?9t2GlMAl&%)K;uXJ{D5ETL0FDH9@fmCPtKw zBDJ+B)>@=;m-F7DIB(G?Z&Bi^m8+mE6p9D36FFnB|CNk!$3bc=pMRNGv6I>a6FG7q z074Krsi2e;xPFjeEQqmB!DE}|ez~vnvIJ^DdL$wAwIPF_&d-;NxFiX%RkGS-g<{EQ zKDqN>F@Z6|yKqt*G~GY_kG1(X{4?$r;%z2%*CZpXe!kaeOK7z5{=3!wyJJ@+FH3ja zJ<59bXz}hb^1g?-{FKmm zilG7+E>k)!*b@$PhewVTtPA-Z{WlCq@UhN>&V6CnbQgnabqK3K43cq9r76h76EmGk zYfxbpwPcE-^WP&S*s*SFLGLl|3g3~7AIgJ%;65o%;IeaJUV6|cwp_3_kE5k*Db5C~ zSD3X=&zY)nb4_`P`XrjX7xAX{L4BgN1zt}5ShaIlQe?MG-B)@>s+qFSeSo@`5H3it z!x$t!cD$e8vqR58xQ$JJjPh3!pVe5hN0muD6K}u?NWORcy4@~0Vjxu$;~5*zK^ZLwNd(%dyc)f~c!+1?aOt#5^d7eJ(VFL2 zYm|3zZho&Wl`DiE_YHL^dvOta^?_mFHo%Pkyv4|$g$E_#dPEXcrc&!CTaws)t(xhW z=+l?w?y!p?_z=pR!UJgcrl$O1Mdmvo_C)mkmOcx6J{#Da^x-D%cY$Z1Vg|sEa)BdK zn+qLG%1whTn(~$KxoigQ^xx_;HD_l|;R^F$gn%Dw{C*E&-RS|RQ{gOFZ-(GX$zD&& z_z0Gf9*ANYmCO**ldPr6TY*kdC+i(A2C}3xH3f%8s_6`d&vGcQs7AcimzxIj3xU6e z9oe}@xxoMyiSa>b!L`ucY(328EN|`2qI$(o>jV_9|6V5_vZR!-F|{65IQ}g;IzO}S zI(^S}|zs#^Sb86Q~u4Qx|%tJ@V{{fdh4y?Ew9RBk}=0!6^qU|ZuM2H#a~`5db+qtEZGy- z7sgZTTi%_EA^3Ng=b(WKI70RXSC&xRErDNVc$GmR( zCF@_|ID%uKF`>Ke6ikMB)xpk@M}4 zD+YJ{!MDThF78lHQd`}=1BXHw^7d@sEN$=B64mbrC~@E;f|qtjXSrWa3#azbMJetLd4g1iFP?N~jf2KJFYA6AFtg_9BM z6oecJ%Kg@s8T1{N6bq+d8(S~YyIliVar`OkW~hlXQ>K=uFzb1{>Mx;VLChx^#pbi` z3rj>ZrSo;^pg*k3F4vVT(5=n!?7U0e)9aio_AElnG^}zxbb+>C*Z4$A*%x&WYx$H62uRK2X}LT%J>@KWna~rLkYxe{AE}eVpk5XvWT&n!m#ncNp(B)jZH5R&{yKxhi{;%m}AgC<-`%8 z^!`2Hw(n^=sNNTX6nu`)(sokcZ4|zXkXN$0Io?#hGj$+VU9$4N1KLpL+cUR4y1ON~ zh*vf8Gx?+mp13Oelm1ak_#>SWn(=PT?^dq5?|?7#%Cln{%**Y+T3xZT!Mb{r!df!( ziD?HhK=ds(JlI*=*k25&H9M)iM9fY;upo4=h(n6r|I+{?+22?)FpP54^yO&I7bAa7 z!DTYo7i7VoF}n!XBi4c3$%2oiBaLv+{ZAs$u;mXJ6;lfVEl?g6P?s3w`Yo$*c!ZFd z$F>~F{{hR-1r8D6+>qsW$d6n0zw#gXul%Fg_9Y`^FHFm`447y;He_7ht?m}P?UEmW1bu^Un0!dB9)()ze7VBMB9Z^+9KzLsbc z>%918*!0F7HOHi--IlL#EY|%!?5|3y*y$*lSy5F{QgL6!T5DA@i15q09VI4pH@_S; zY1tr<3d=o;QR^~JHZ*89b{E`nUEiuB=aH~}2ont6) zC}n*N%7+ac%Wuz{a(Lk@;I-Pk9;#x63g1aZJveP~rO@BVQ{F?0Gs@;GOIJ&FySAby zGU@P~hQzrPgJVtBw9lJmT_~D5ZUi>|J|2=clyu zb9&tor(5(!tn=@}H$%q%3|U{ik1p>*ZXAWgfc|LFpA-0<#IFJHV0ACE+l4dlifga& zOlh2OHpZX`Z4S;iB`ex&L(VCQc{`892)#qbUKI8wbwvyNWHgx?+MIqfpWr3b4f{m* z+>@@osu0Hf^Yi&Mpcvyyybt7=H9Fy%`2h3^{G5ekW0y3-_M(JlhqXFNVBRY zk+}P=idiMycRCVcuzpNI_^=fD8xuygl$f;6&%6nW#sq4Zp_#d{x?15anbf#<5EcrW z{;6I4(u~~HC-RcD&J4rC(7ojjrIM)3b~~6Y6xx2jAfR=W+|oURS7|S<9_U+MvsEI# zzD7lSfWu&&KAmXMIi{WKbXI-Xq{Exr=YHIG8#`Y^^Uz{#`;KAb@Ek?`0PJHBYsqnI$%(F$QtG28clRk<_!+6+oG92Xsh*Wme+_Y7K8CIc zhX{GMd+Sa`>TSmZty1BirPMdRhJm2>N&Q-+Qs8zi`~!OtR)*;>*-RepK5#^ly6{-w zO{r@&?3SLenn^0B5DArgxaB-Vv&}TnMM|AOzQqNk@Tj!AFQxNUNwrcUu$9$yx$Kdn z1-HR8O?&imW)Vpjq9m_t^#|BmLgr#P8`xq7_{B96ektin9PdX8d z!X}9{PEP;OV7qyWK4iIeT+8nHL_s-ZR1H~Q`h@9M=r3Twjjrm4N|MB(J1@zkL8r8BfTTDSJsin6!kwEv?hD~kgz)Om@5MpP)0 zV_;k5@ctm2WL7sQ8cwf|T@o8GNoTp#L&}zfeY`gQwX#w1FlM1g%vfGq_b*5-2M3lU zg4gU^Z1F8w9Rl*ul$&&a{u~H+Xs~@s(Sri`=9szmLP$YMe?90)QUDVyAfP9Dl1g$$ z7Z{|%6w3+ugBuSw9qO^;?-$(> z)#E7j#v{h&j8@(wvAxEX+6LD)7A%(v&qz6>{;1TC`fh&Sny{yAzQUTr5CbuLjwy#S zBQoX@;FJKen(QBLw_Uw3UevkX6 zUMH}OA+uR)t>ioRQ_ycpe{tS;-z zZ_xkj3dt){xNp$75Hau2lhK&YBx$WxxsX|ZlxL@g&5jaQiiZW1ig1^l#_!GPpxJR~ zAzPIYzKDavHCot()Cad-)6=3Jo;Sy3>~yxzo6$aRy1tSA0BYhGSJ7Tw(q#I3CUIj* z$Sdmcq^sNKX-3`X{E163wvhqRb=p-vB#sm`On{={hByK_8;+7e0x! zKD7(2YO8~Fa&>n(g_q1!pTYuvNQ5iNdgA8u z{AuGosj+;lwirjfHm^5O~1hf+4UxxJEjeMR#)MRygZaCW8 z{~285iTo_%S3?DgnC^B4Y~?BYBxvCgLR_Cqu>Zt!OtO&_WRt>g5j$%PA=`6smjDj^ zM8mLiHW$E5+w9lk=%KVFSw<%5e&Nu4OHw~nifKz{C(uo7l5>qr*D;uB&~n*H@a^mR zPKuqXbc7Z;s*IEB#2q=YYai-#FhZqr7T8?T6=TV{hKA+tiUX}O!(&$(^bhO&oX0HU-K3bJ zTb-gaCkpRhGk$Q*x;a4eqw5gnx_?4uEL-;)C$M7TsJ??1Ujy2~5t7vbLuSe%i56T# z$e4W1qsdZtV72QUiNfY<#?2`3X=;cTxZBBFW2Se17C0VmYEj-gyr6}qYsMxde2wac zYi5ViTZ0%WXc5-`$RR0L*qrzKZrZ1uI;To%@+%q5w8DY>_L2YsQ75K~mq$uA1%v{UFupS;TzI-*VnJ3nm8F7{)%iS@#Ys(gL@SYq)yvgIi^LfmY zxAM^^?WIzrtBAs$)f{KaW&mmw=EZo)NPvq*;rF>Jchm?O(D9}M>t{pHRBD}tgjepO9#rr zoh^!>8;;i}WtGzXEGjKfRJW$aKR@0vf0QxyQt6E+i&Ajv>lF~(i7+0s6x+DN^lm10 z|EdDa=dH4Pg}*7*eZ;tjD-|P>KdTg_J0;iqEH+m$V$&3o%W$$C&aEqfXvu?I-Is&H z?>m04)?1&XofWa=bwXxW?lZ{3KTu0tuS-SAqUg)2gtT9A@~h9}uG?^9Q4Nvhv^L(j z@|oH%*2FfyB>9~4ef1XTRt48Evx9X-SC_^5)w39H+ou?i)vwvRhc>l@Zupw?;^@40dB>@w&cQgto&u3f)R#biiy|(qX;reiTjFb*=72jbaZPi7Wl)3eQ;=i0o{TM}VHV!Y>ld zv&7JBTEqJM(|AO_AH9+r>a9%V7nxWJMnmg1!BZ6mhXB$VPThwyB$EE%mA#1^nbyPY z1kNGv&MVTSY>p#q8|Wq$2IW&pCK$jZ<#6&ZENNE1)EJ#Dh6XvHc}FgLNJx@3kh-XS>1$--Qdmlk5drv)P9#0Ia_&TiWmxRVE7zV6Ak((8Gic9r#B8TmJqmQFd zHHdvtaUWM0L(*bmUmOF)yg5mLgoDvB6oUixgKU1kMc;i`i$VNC_#MCxg);dAFwMX3 z__mhH&V7Wl9gNBg`e~fJ)*-`p4zB-9`ID)Ot)0R&!Z?7xX79Q*&Xesn!st-Uw1Zw{pM)UK>I;;I7FD1D1V^)}4=K%V^zUdF2Y7lHRJ#k(u`p z+~bq*UCCDQRL(qcePplufQKkR3-61J12*S7lG@zsbjsl2nX9M@jB0rlr=0f{P-xr3^@v1?e(?2{CK{& zv{vFL$vdm1AX{A^c8-^?VQuspE})OeJxa1&h8jOU5?lz*fxh_gdHby1V^)W$lSOh9?ZDT_2-S2O+`kwr&eV=u@4s1b z2X-TEA)^(@v!wh+GHN7x<1xLBa6q<|BBmLaPo+XR7?qdt5v-0_Ne0juFK(sGiyJ8A zBrGqhGMlEhmrYgLr)jO}6cq|d?V>m*HwHLk!MVY8b9U8zc@5Dk)uk81jaj~>6LY8C z?{4sf?q9J=?eqj|k_HC~6TPtnrs`m)YA%y}rnEiJhm!FsYUlDgZ7}7?C{W2DdSPu| zOxLub3xG6Y-7@;9W$0rUB~BBRP7J#B@sDd;6e|n(;_6iy!L0Q@-D+KCqHs_$9zyPF zx-yy@mM4Tg?eqkjCZVg{IR8rYxagN->{kM7iLf^;iu~FnV4EY$GI|fShp{zqHfs|Z zJMIG%?W3+}(Y&7x>-*u{j94M^c6}G7AF}3%K_4t|{HzV_F51={#uRYbidbh{;LAaE3Gc^kBL2VF-QOdH zeAg!mf0D4@t<7z8TC~aQHukl=1e2sp9=7F;J0QW_Sfz0NwGC6?*Uj-)(VEXY@b1m@ ztzy%{i%XwfHcKqYR;q{a)CQM#&jdL;ZD{01#Fck}0XKbcY;mSEN?@YlV^^hbzHNIb zjC~976=nAz{g{<|NE>C@s%Au3wyRmqKWEwIfMttFe|n(yOhZIWS7zC!?ZyCg-VKzM z{vdA%vEa_3f=fe@Dmps{Wp=IbGB&3#mp=ef#;!r*nQ(3lIJPgc+I*4T%f^`< zC#8k$mSbT(G~%KsN*WuZpPwjpmYA+*`&fMAv!AnV$E!BP_#o_SwQCkGxC-SeP&>z%QIk|IX53%PC)BJ@|=V$aAjvKJQD! z>C`X=Up|us3d19&9eB28M+6QKK!5us8>zM*hssNO7c1>q8BjnG&W4R=!NMz|Pe%(6 z%#)f-!l^Kukd|Wlr)V@G5EoXQI^n!@Vjdf}yR^aG#mH*QLL>AE`sf~E-&Zvql4CQ8eP@H~ zfA_>rZ>*`gQeF~AVK=y&r6E(Xk}E?|%Z)=SwH3SknB zo+|fBv~S2~Wy;)Wt!HAaoIH=*_*Hp{xj=&{KuhiUT5FZU4Mu3HRv3G^ zb2bqkZ=)@&62aeQ)Lf1phks!)@{#nxWxVOTQ{88A9;&uSh>>rz$eIpFyps48W$*l_ z;4f0)>k|FzRW;d3meQK%ui}uu{)ETa8J~>!t<`IC*Yn!BQ)ZYL9n`*D6_OxANB=D^ z%CYr3C9*X^V6dc!Q_e+|7tVG5aIT3HejPUc2211^RSqx9No?g*gpC!5?x)hnXcJZ| z!FZJq6`6aFD{A|@C^2K#yvV6hI4zDWVIRW&LFnix*HI>sDRy zQ1jhitt@J6ArW!yRYg1pN*OQ-tZg%X_Q)E~qH$nJOY}|F9`N388|pqUKp+dm{9Ea3 zEV3|$u|%1Jt6S-27V#4eL@*4A+^q=%j{|Ph0&YBPXTB?d?Ky%Ex$X#|bq-G_O0!&% zp=F}yC?wf`f>-zCY0U2;4-9h4*&s%RuaKNWLO5y}NeCe%8ORWW4}p}9V#Uf%hFAG+ z%2vo3O~HpO>Ffiu#0>HHPR`04tibEVPlXVad^}pu*K$3FSUob+$psPz(^q8WB(ic) zMD)rEb%*b;08Vr}Qm83~SQW~9r@$a&1g5?snK)%pOZOC@T2O#8W`|txmjjIM%;vpBu1oG(sOQ-yNsO|3(e{;7~{-JJDV3xE6zJtUPEfh_@s1+F9 zhabBqarS6t#+dFK?f{ddA#6nU1UoYLfOX0BrAV|DVdY~s1#dhEIWMgKv-U*ud{Z# zIqO*Z3QH{fO|rNlVaY^r0D;mM<;FqG6QUp_ALAZbQ1`lDjs^lRO@-8jV(D#JV)+I?OC1^fDZzm$iKY&d!EgbGx^-93T0+!t7=X?jzk#T-wRsKjzu#O}C*J{^`~#igJ9<+D z^L;Zl<_u$GKPFOGVkUW6)T5a}pJAtBO^U>;8)IhzXLrQj*06LnQ1yV*f0*(1ud*mK4DAIC_vZ%{q&|goB{R1Og-N6^mK0Wy z!qKE2_Uas@>n>7XK)Pm;!b}2NqACrckFc`V&~?4i8ujyQAP^P5f(b);<%2p&`K#fx z<#qDf%Z;O;4X`|ZBdp8N9=2aq*wBkvN;MU_Ae}jhv=S2kL8}>jY8Fj*u~cx#MDJt4 zTnh2<+?csj#26AUiZ&dma;ld<;g>h zPbNfolCo;{hW{Ukd{@eUC(Mix%1RbK1!a`Fp2Cr?3~d0A&=(ts~VQ zAISdkjOb4%voFf$!{8F>laxm!)%(&P$sYp4qow?e)W0p!be8H>y6ti4)lu)ihQW%A z)Gt_cz)iZgU^7A5cHbK7(ngb7QLc)u)Yu=f*zNPpE3{Bfg<5Kbsu4=0!GYj=n(9>= z&r|vKhWY#->}8hV0&NiXkt>iw*Q;y|hTeHD*>0F$^T(_B2)KZKyc-|wg_g|a{HsZg zFTHuBa z*su0NjahBgm_LiOBQCMLaj#H5wuiGXnrJ6en+!Tb;$}k}pS0Nt+_xTPqfCVuX>keQ z!tW&GcK|vcprb!R^|;1i%l#A{1z(VOZ))Zkx`Q=KUz^($ae79#voMUO9A}NL`+I0Z z6Sg2&w0hr@%K|$|=_IVGI9g^>L=L@XUHIK5HH}-Vj(>G7;ihgSiK9lTtM`(3;~TrR zTU)1Y{UGuE*Ear+{za~*NuQ+6m>AhSg>m4=-cr;Qw|1psX#v!GoGZ3^Gw1A$g}isS z)@)HY^S7E7&EdHb*w7kT`sG!bZqbG+Jjr_iiB#M4KEDVB*4bHH&EBXUD(R zQZk!Qf}u>0=^X)p)bnf*=&ERX*kna$1q*@y)ymxtV$6hJLZa31L2z&U#iwC7mb2cj z`s$}U;N=m_weIu~Nj9%3;&1Tk?qN+>-Nf0I@19)X`qBTj? z!|9XMO}Qm%l9vR2+nl~px!Dn+Z`gc_pNeysUSOTD!eO^^Hdi6)(?Ae6UxjbAz zd)};teeCvMJln6@YE7JLE?-pkqoRDfRgqElu%cQYf)9c`HJTS=C)%OKVGLvfQ4e>-NIC z&az*H5BHTpy-izK)-q($7M0nCkTgzC$`xLahZ;08NTD|%xvd~euMh8IFPj3> zEP2+>{Th~z8NSPMA?=FlIYrcw67T37bj*)0%D|3vJ@8Sv0&36p`z(mH+qau#^?6s} zmFt)}Ag1IgKoLnj^nJ~HaEOW(Zpz37;&iNDWLOO-Y^Q(9SLMhp$^5>V%rfAMGCCPE~W4s?)r&Wx8>xy#shp zuRF_35_raoIP>;Ng#!|opl%HQxTWtoO*WK@_Dc0oz2Sl9K^hy{OpYMz1S*8Kov_8G zcSI~Cb@p=@iJv~cFMqT~J}SG^sxL8)zKA^i-csf+;S1MU)lsEc89Eu{RFlXjyFz%? zGPMLp@F>q&7Ik?$G^>PSqkGr!Wz@Rs(c(n7Ai3r7C$zO3Pj)uw3^(fRqwZ;l_1vtu zIJK5fy5;HTyF&>mqgOQ^0wv$md5jO!%Bfm-4n@B6d@=I#NrgX3p2>&QMvnY`?Etg& z2U$KPBV~T;$9KJv$-axZa~db;=`FKpn2|cV`;lMHtOCX+vi-{KDLw2uT@$rsc}q4# zv-zn}N>H*keLdtJaJT(!km-}8Fnnh#=5(N#BSG9#Tk%^2I5+oZ!MrXY<28vZWA+M- zafR)Te1lK1d&T0|Gj66>1z!xQo!>%HETiR(&vw6db8GW0yKfn9Tt6tT*Y0kiIXt&s z5bxH;ZlMW0ceenHlBz$}b6EHwL9`v0v?LU}Gr8(Vi|`5J;FNJ#ZTAH}sq1!9wscIi z7G1$fDc)V?8J+DD-#na|t=z5URMUwUwPtc%Q{bZGmff#%^+vMpp~1$ul+-Wc>5uy` zHkOw^G(AnS=*%tuyc*N`=HYj?#G5(}M~v7*!ah5&`{mKDrVmXW`eem6DiuX;Wd`^<4?#w)jM^uy{y=Hi1*5DoFm(^}7$fO+?rx!5k#I z8dXl99o?yZ2ZcFksaM{BJ z8nZPx0A_c)3ryxX&K1MVaeh(C|Kn)P=_KRy!P7T$F)9&0F9;ntuK}Y9O!}<4&6Ldbr82Usn!AMAQE9_WY1_*C1}Xxp!K3jSt*A zbTKg#S-Ng^Le?V`nwf-n6EH%zt?XgNWrHS?vVIw)!UL>pg=#& z6GZNwxI`$grk+2iUpH^G!5MPwA3r<6-8Bg7tM~ub-8DY&i4^ZIQxE9Z1s(;h5LT|) z`I&gpKbh{irZ#UiCC(%q$;_iiLe$32U!nb4F4e>PgWjDbPz#Gv3v7nS+Unef+?XdG z0=x;E+fl4k#v>UdK&Q&5cPk2Q*UoLq<`w$2qH}Jy*K~kljhmdmEM7}(LTPy>+zk2tjWXCPi||b!44>EC1USI&d{Q%&Pe>`V8Ou(Fv7hp>&c@I{+Fk>135CBzLH|A8Gzo7lD% zUb$xML1^1=u9e0dq!s5J%KMx5NXd=~u;$lX^xFw@_u`31EL0CjtuCjWgqU_8VunD;A zxUv?aH|yG!E$yMQe`(eb@0%UfD>c44MIR(RAX84tn_M?vDjLgVM#k!!-c72FF?^um zAA+Cs_mbEJ6uo@>0$28GjPm?YYJ0pRJ8r4c`eui@P~&td`aFq@*Q(Sv8DXR#$pF?s z(yL7yZmf-mH4FZKVI*kdja}bLf$xUOk|?s4D`z|m?5Oj{A#9;j5?#d(9aDBJKAB=3 z5hs%Jv06c4H&3Hb6b zj(4EnC5^c(?{BJZEcdDntx54jJ@uk_6qGsGHYaQ!n@4@n>WFXt&j%|-tjIO7>-Jq_ zMvK>4My>Jrwwu?m`(tS=6Rq)R@mkbaq*xaF#B$ZQ1?anql+OE?wS2jn0sai>hMKSTSgUBKFGnF-Slv zEuZgPnq*3fUz$31ishp(^eTg4dqg?Ma`@j+o6J&a$@X9R9LnVeljezuYN8C`R*}yo zVqXN%6^0-f%UY#kV`ImjnEXB=;}#MUf}G)NuMx7lhL8md2>Ch};Ypwtr6D|)kc+^J zp4>#pt~&`?Jr(2&oD!BB!ADL8_L>Nxl0Oo192Hq_#a)mNbfUWxz%=`)wa-TtF_vGZ?!#cwFRuUT~=FXW98(=%2}n` zC08rcXTF!;;J20dZS(xLD!=VPzb)TyEAZPE`E85+wkE%Ali&7|-}bWKw#9FI-EZ6O zx4rGR?eyC|^xKa3ZAbmK<9^!-zwKMU?X2H+!EgJ~ZyWU6hFWadEw-E%TUm?kkrvyZ zT5Qj@*!H*B{wdlrMB7Bs_G{7hsA#JfZC&olR7d5_>zbDXB-gW&yHa#iW~_T2 zF^1A6$@M&9raLNgg(oG;6Oy$uMXXG-Kz`y+Qu7m1OXZDXrQTYp6P}i~F>miu^B)kI zZLOTyTA3tP-oC9~s_{wQN^NW9q?#x2GPUl1C4c4ky484^WO;lLY?^-)+pbg|le*%G zWvRrMW42B4>-llKs$t1$=fw5SmFvCv_j&Vcz4`OS{N-YPiI`s{=I4v~i$-<^Hs8dH zCZ?`!U%s~TmT924Ywup4qf8hW0Iy+3dJL1YY95jrVIfGp6RNir?)GqMSFE>vDD_gD z&KgtO4$3FR)0*d=N#Lgi z(;NI&;;>RswC79W@e{%0DWgY#1%;ZMiJ9!y2dhnk9si!;Y6ZC^^U_s#RBp6Fw{_+8uEQ)L3@Ggg zaP@m433(*MDYo`gppw>6pNOzH>s-EMJ^D>9*g)I$hwpeCf2-@lckIHCAe@n}F}tqd zSnG?UChJ&6Lu0-X&%GrbyC5CK?E__ej>{hB-G3z2K3b=l?X9{|EP?#7(ps|8T{WS< zYJ3iV*>b34Re#kDGR^-#?C#@&k8vf0E1_Ho$CboH80EO&kQJD?;~!f7)taLczpAlh zrMGIrfhX7dOOyx7Ry(S0-25V^G7|ocwX=8piSm!mW_M*lztqC72(~nc+2aOYYk)pD zsB^E}K52FWEC;soE4H>a41Cbg8c$DskSX%_%}yxzO6uoV^z}CkeAm!FnyM6Jc7pQX z*T+GS;6~wNsc&HUfYi|69z4*$nn=O(RpaYF0pkgEDj@*NuOOUUCuzX(jyf-zZ-?;@ zcr@Wx7{rDFu>k^P7fqF@6AJBzqZtNRY6`v2H06wm3jWvi-BMcF44w6?0<(qepI@Jj z7&iigzoQ6vP_t>hGnyhLJO7rS^0U?p6i zIQ3)uxOxG!cz)5LU~TB=!GHCNJvV06(7ZM*tg?2Mr98{&_3f=RKmYVP&sO^e)uU3G9NL%>!nn z|N996Dl zMCpL8KVYeVdi6lzT&qJtAVXQbz~Cs9W${oO7{nBGPtFIRR0Q=t2sW=LNhqg6BQt4Y z4c6KXPT<^zAIt`W6D}8FaA2m$E_BG&GJY4E7wmLK$8777&KUQ#xAWv|Oz40!bX0R- z$PDK-hkAbT><|afHH*&G!jeKQN$`)7#DCmKdqZgS76)i=H<_UkCp8nvFaUyGXnEoH z;FCwxXfIo$Fm2A5E+`{g%FtS~NuhA;(ioW4pE%5lHvQnFi4n^O!krAXV!h!Mf%WG( z0kmh0r3j!rwZfPR2j(eSUwb~%dIBZw$9+MC`oZ1bRnuSbL<{UzrD1~oYhiWW-BvKUOpMvg>;`OL25*DwnzJe!@zg*r^YR!{0f>yPS?u9qz#fP;HJ4tdb?Ss-7HOj`7%iFAa)s}sei?8tHU{Eo35#00o|FcgqyTj z*hpvzWw(a(@6o>{THBrUGnT4+3_tozpnn0ic4idAo!Y@eKUhAI#q$@3MgZ}}^rnAp zi(|9+>S8iH<9}Pc?w(%OuEh~it|!@2S-JRtY$x+Ro4XS-ORE-JcRBfS%ithjYDJ>E znK)j7lQLHC$}#*yra21Non6QUE{W&~(l=PWoae82o_kF??`Z++AMfp+=GHgaw6y4a zQLjH9--b*?G%#0omrLbv!rWPIK37pi__S;QBHJ>R@w zTrz+dPJ97KAzomR+Wi7Z3S2=7P9|8-R0NVoSU7~l{589;C(4)SV}ybCkj3P#ua(Pi zKUolx0yfh5rPK)}uS?Rl3sQ}ewSb;{uhm)4v%TAx`ESVhv6m(Pu6ySTytp&#{y)av z1um*GjUPYnnL8X{25{6EZRT(rVn&%k6E-d82ndM@lLD3&GwO)97A8w7YKJipi#8bB z(xP^t#A^j)UbePI4AjCxwoPqiLw476%Tg=z%K3la8FXv+_xb;Rem;Zeea|`X?Yx)g z@_n8MdoR6MQUmNd7aN?aLXHPr30E+%(EelW6+MJ!10+oOK6NbvsxK|r3$0MCdO@$#hu&$;~iNq%%0)}Fv zrZHRZ!%)0O5I6^$Fp{)9SHu7G<~iiIx*GAV?_#`p`;}vW|u+C?LHT*tU!}IvdCq3^8ZSk(>gX3k} zDHhG&+i(H*tcgt^U+Bf+Q0;u;^I(qYTZ=;vM_;&$kzcq=8GGR_N+?6KjM^z%8#)%RaSl20tZ^7Y~cv&axPCw$$eReI9#-O zPhPMj*BT=I3rg}OwvK%H#jQv>Z}X%D4?pKJ53T1mPkU&w2b1h=HEBVC6T6H~9N%p< zH{8$Cq<3*}|5;4;AMfJe+FJZPM>kv{vF=8@>tGg$9F{*4+TmH}5yR7a$gKA;r>eik z9mi99>`9w|2*I`8wduy!4W1!z<}=3d0&TyWe`SOy!ugOyALU;ep^1=@jSQS2S)sNf zgRO15iTBWJ~ZILq>x%Ovav0vL)w~JqYrK4%WIlIWYFfcf*_<9<*oMpV;n_v zH0-W50F6zTVJ;Mcc4BrXW~~H@aqzfBr8#7hkH2dm^Y&QleD-#lu=m$`ukB3-nY`f(|lYibVAs>7`krE*>u;YiV|i2T z!Dpm^CTN5tp{0-H(?ne~2J}V+Gic6{dqwgzEwpOdV-1IC3L_8Eq#Q64MlTibs=yiv z5b-X*oZ=ZE*t%?^N6&G?kiYE6C2=3H%C}yaFF)Q~H0mcaSGtLdxer>(A4^BgE6CU7 zo4QYnUA@Ns!}_65e>^q*uiWp?16T~0t=aj$rTo0+yLOapWy5 z;TM+j3+M3*@8cKV&o7)G90$A!zma@B0S8M%*dxXw9&=dSS$p=+xxh>-AoqHBU~qsdm0A(%;LrukJa$4{%KJ{tBFi_7nu=k$}BA(!?&oXMR8%RW!62j zgjQ?oat%qMw@=UFA4)XNV);aES+wQJecU25LwI_J8=q@ofKDe~S~fS{@To}I-Ags( zDVkx9RN78g2H9TRI|#)Y%_TiuKn=SYos)^PGq(uLSSvGzWyYxpsi60b3jnhmY2a)k zqxGaL*f9kA@7B3ir#0A0!qDuz1^l8U;{ujX(l#nAC8360qh(MoArjFEdcG8mv$W2O zJfBGW>mnEFUG$POqKiw&1)4lGOMXOj=}?lk>j$1sqE8Cso6wWS1w!j|a+)SM*}MgH zJ)&WQNOEbq4sz#6`FX@g6k6{mUj-kDM6kvMJ%ho#4D#hjp5n1t@~^RtGIX-gsS}*F zi{HWWJEX~5uOfL;mQPr{=nj@Svr8`x*Q5PrrZC{|GC6i|tSPCv9l-+y4M3Vf*g4!a zu!W}eHx1=*ra?drA?a!P1u9Ci$AqgiY)n{X!8`Xcy8_no7>Jhm1g~7WEJ0B&!258C zQ>`zKy$|};f7|_HNux|I!S$JnGQTs)v6S>eD+rG&Y*Lc4&@4w^XR(m(LR`3h1Vcfq z!ojf962fhQUP>W{C3nYj(+Svm`aIjhB)3bsgP;LV86 zh{+?rnVKm*Xb1|!4q{JS03204aAi!pl=)F5-qi;kv4`Rt<%sw;L?e;M^dl_a`7Vcg z--Zv#%AGvN9Eo|y6+P3aa~3cez6?oPwoE&R=cd;^1HH2=+Imv@;ZWq8L!XL+gR96M zI&IFg9}a%k*!P`(=zaMmePtPEuATMc`0tw&eZ^@TLyWrT5Uu!bY-{ABw$dHc}Gq z@!rG2B#MjHj*jIEBG^c&p3$@SNLllo_p`7$`^8kfV4EcDo0M~jJ!${YPA2i6>FwRa z#g9Z;-V(V4l1Yn%Y)iIlm~An!4_Hs1E9v!FJ^GfS&o~_Hb{&wT^6ngsz&R0E(*b4c|Bhc)$G67(8L#aN1qKRqcDsl$6BQwhY%k z{~h`Coz|}F#m^k)&A>9ToxEmOY6|aXY}JkKP%IEFSuFSo_v_S<5hW zT)sjj{|LCIo)U2<=C$l0(4`X2RE_O7H_>Nk})%5x59D7uoR7xVg~Q+6y9gK~cumO0GLzr=y9M_l##` zm#%8?3;4apfmA$FhnN!i@;g~+Kk zhFNsyVPK@!)6swC8nnvPM9Elt{Tj=`wZrw%W#cXD-hmeZtE5;ch;qe;0S;m%Jp`kV zT~B5Of@Ci)|8&2?j52zE*wK%nwOi!6m-#?W#n<19$>!}rbY6mbfIM>d|E$7^G4DSkw<6> zlVL@Aos~I1v6GE@%B7cZqvo+3?@E&*nG)g3l5kTVi{MvEQpTmc$-ORoB?<|5W|~oC z=5xkq%lSX^U25W_B^5xGV@FM2iKV0POn$e}QcFtd9j7V1TzmeO&XkMhC~}rgYPTtU z7F#uXT9ol;Vh=VW4Nj)HTTrael+-txhvrFsE}x?7Ech@)#}} zb92@?GeN9qY0glLm3Hohl!enGA#Km1W&M}qM}}EJ=Ty)))yEwwa&SHeQ`dA9DVSod zrX=vo!irc`ywn)3mPq-idqe?|H) zcoc?d%r#`~oKEdH+p+&+_g9@i%(DFwmYHzOeyUK`re~p9rh}Ao$2s~Rmw<3*wO225 zc6{pjXZV#GZaTDq-9KD2M?7oEaY$i}QPoql_1)%w50vxjT&dK+UZblH>DW5uPSN|e$eXw zDS|!Gne;phUma#;?G>D5S27IzLkS>vBWu5rKy~_{q<{Kn$0xE`VL($9;^0o_cZQ>2_P?)s_cU6FwbU)8A#FMd!e7&KE}xNAw7thHB< zL2T_EQ)&w=3q0#uvWd;zE_OPieU2D+7~1l?wJ(j1yA1|HfWuD=Ry5=@#B>^>(b)R) zo^_2=%EEnPW;ebPI5n27YZg08XIl*{|7o7!my=uQQqcZUmNYxR^|MRGcmIoGI3K3e z;R1G#jb9L^4-c?`YwUvXlonIkb_xmC5(CAoE?j~mn2 zI4Sot(Hx15!l21n&-8eLp;aEF1?mMo%5x$}hel6V?=|Ow@Z!mTuea$|ubsl?K8p9l z8XKj>s)1IHELnDYr$Ga7%7HjD?{7ydiamd`PKedXO4hKs%Y#+a&J?xQFRR8?jdm)C z*Z(2J^3EA#r1H|H@|x~srmjr1I~cDaN++o|VnEXBp@UbijZqlS*WM>Z#*(r`ABqjz zypFA#8!R@D$Z|z(>*t*uVf`N>BwA+y!5YgL$Bzrki@BRmiGk4tNQXRIDd}zoTMpr3 z*AYviSbAO=U7Dy=EB<9IKkt;o?cqE(kOK_oSxw=kX{!UpGd}w!%N`wWoshs!NVmpk z+Pg0powaQ-J-5SWQ-l+b2Gwd){&1^xLOSb^X%`Y95NTX!*U@+IG~TIwJw~32#~D?T z;$LupmEkZmbSk$~38S`4!uuswT{vRwxFb?5JGzXBnjq-HGh)ae=}wbj5zu)@c(!n_ zBIiNGFyo9Cd$a-`6zvLGQ$%?Y422Y@G{&MEE97NbY;os)1X78VfnxQ_BSmJ<-E^NH z1m|mE**S+_UZY0#7A~~>^$d;ChSl;2eH&MjAoCuO8Kp*B@bX*=ArA*{63bU&o{hLd z3G3#*pyz~@p%+*DRQ=D&xhG7@3>(YMDUW9Z*F7#hG?Yu@fzrjH3c~kxJ?wch`P`!- z6RXT(zK!3(T3O<_F1E$Q>dJ3>*vhhLX^W;9!>1H0t@JlfR z?3M_(Il(NybnAS1*Jop{Fl=DVl7z4sZEO$bLTpblbLu0uZU$qL%}8YBGniAKv+@$A zK#m9Ga}n`Z<34b;cz5i%#(-|aOK@tmjtLY7xJbcp3&(E%ElyR(c&8(gcO-Fg;UmA` z7>AVwZY=fj)qvP#Gg>}8+^ek*o0{^HkF84r4>*u!4HW-F#j(5YPINqE8ERsbZh$Sz;xTitra*Xe}1z#JlSUH)GlX&q8^pW*?A6`kP`n)u#MCkdRspoEWU3Pr=A+#>Cn~9VO-y7IcZm_V)eJ|lJVhb@p`-A7PUn$dxCTs4E+Xv z$PjtU-U91}^IS?K38ne*Fd=CEhW1C{)h_M{d@0gw|8cUPH43OrWi7H>+a| zbKiFAh|%rVv70ZnSzJ;%kbTiKq! zi|C0EtRZO*3mi88nH2TV-FkPhme!x_sAX>8R3Zy60N9DFhFfc!6m@Vr>hDXQphY3D zsSXtA&)r4$sRal^r^r1dI{ksNhXTbt=K(ZFaPmk_!706t@oqhrcPt?BnoggPBW=1<(w_7xfeUE3~#wp+)TfAs&E?nKfZ=BVk zWiR31s3(6R{YsbKuv`av%%39AhxTsmqr2VsNn@dOF0qNlf#P?$m8q zU|BeEj`s6CtmUmg5hI;DbV;?pRqQ=tO;zlESccE4{iv_#vtg$>sZ{1%nV_93HFa5P zuGxBriJDdje~J9|ySPPee6mNEvhD-^$D*I*2}keg?A*h%IC6=yO$}Y3K_9+m`*4`Z z={@q|TdaPLww)99l|mMgs<+x8osgX-EGccMNK(rL!+34%A~lfz4al+-R}WFh+aF zM{GDTafEU80F;cBKYw~o|4C`S4c!$gyB~|=G8|vT7BEIv@4%QkaNFI4~7!EEEUm|$CtX2xfJ7N%L8@!SU+ukb_ig-u@A1sF-=!F5x(@Ly{wt zH#kAqGuOb=wA}I*7je9y^ENk(>kozdmbrhy9D;%2R>@k}TpF9D8RugeWQb1uHUOU< zfSh3vzmJe#g}gpopTiHZT`GA%(7cer^vT2TU+DUrjY`?Kqg~s03n_VV z94rfHlOlX?eXdAhbFEBkOR54JUmDYLOmx1)@L`Pa%`MuYuqCf2!!B~!^e1UBq5kH(~O!e zV&xXvPit$5W1HBtP5ip?&eoThDKBSqj%6<1VP)k&M#HY`BAkuoF;+R*HJz1bGi)v+ z!0_|!`WZMuEKJCu|TXW6>CaFbh;-fn8e7` zeTca$Ee+DW)8L!x%|k^8?J8UERJeSb0Q2lgoOu!2-ETH-Z1ivRw|+@{$BFOI(;GD# z|3rSKca55yL$WQFYs)%beycOQM6rB=1z`3GRNm1>n``)BFQ;aO6dnxwj$lTzc*F8G zI3W$`Z`Pg~wwb?l%svOA4xXFP+Gw0*))kX(8ny9MXbcZQ9E|$k$~V*=yi{d5vD?V? zwq_X2oXz%r&hhV4I9W4i`-SF?4+yK6#tGK-tLFw}+d0-p04{rfh=c7rj`z zDQEi?*z3J}CC7QS_V%-#5XRpBJ&Ae~z7e(U46oPh;$^I#>DhzW)gUhFu^)_steM9T zxE~;VfH^yEq5cxivu_?U9DMLBOGiBSeoT-_+_<&pq~-{DDN}5fTN2;QBvy&%jN?U# zlpA-(5jg8-CqV0jZI3dk*%wR+?23f$(qKBkCCKR2g%t_b2}#}8<&daIJaGf5)8Qg& zhPi9VAU}U@OUk7J#A5k!m;rDNoQrcm|GqkrXzo~BojU6Blw34HspjKy7vqd>s~JtWmGFp-_q=c^&B&!Lds3g1$;j! zYX5vaEJjXWuk?#fI!%E8ablXl7vO2ze;g(-N-3uSPwz5hy@8+A&p57$HCIG;zXWHL zyLu*o6~%`wtW&hwA3$=lu2pekaR0|grrdU+S>sDC* z&RS!txr0-bDVAyfvbDB*-0HPnHaDGd9=KLH`CnOu)Xi_@Pe*}s12b4ATf?r1J@0$h zc1E;}*^$Mlkt}gW+T%ZQ+}W}D5m^~DVk=^oIK$oXpPcjPcdur>D`I^SOsjuj^F}gr zfCg-pofSI~-e z9zBrvVPDUNUXw!bgT6iJ$efj2XRCjJ544mbmaXCWThr3oGb>lSN1GN-6)x(EVch%_=MFP`Di+pjH8fMBPx8Q^{{+cJwN{B(e2CD?ifk{cy6 z<5P;dA_ld+QZDj>--FP?Ysg>^nghGFyrL%_7<}NJ!g~$(WeZXz+LV>mp;$DoO$T|x zmu{!xWE@}SS+w>w<+&I2z8NP`&H?^Z+;@uCcK;W4h7xX=SrmVC#saX;Sqa-Ob23w` zfj!RIeJpc(W)VC4$c4`eIdz*hox=vpt$E@^;KVz9e=&Udck(`MkQHYDu(xU^tA!p_ zvlwTTC$6_INt0~)EThOCKaQVx>)J;&OWcvpNGXFgdXE%2cu4<(I*U;>{{`=$Dll)jpu@H#dbBX{RxUl99b_~Bp{`z~(y^GhxtLUH_8yoR zp0?1P5kfR34eR$h=Bp`OybBgU45djNSFxP?&eW)i4mplj?#tM2PkJ98{0o*&3 zt{OGvk#JkqL96NE;EDfmVcV#N%}s4Py{3mj*LznyT=|V?!& zcdmGtyY1vD@x&bO_$OhRF=3jM{j#uBrv0nZ4^Or{WzE?aDQ}{hNPM z+P=iHQiGE)DJmHK?nmZ~E-NZfdJvgIqg$nKj2&##?9p`2V$!y$?=W+c6dQKY_C2=F zS;RMsC6DjGxWQqC4VDecBG|rljen|ZR?O*|z(HHrtk{E&Vt%PYmAmsQr=`we81-q-JDIItBB4o2n;KbR30d~8z)u4 zNA|ZHIl1m@@7n`-PDQ)|;}(chVC{lrYMLNOSwXg(@BXz<=fTTGl&V2AaEVpIoUygV z*oOR1aa;=dvOqw{0sW%Yi*8Gvkj$;QM4n*v>^qFa5GInJyD>Ug57AjX=<2lKjG9fC zNnGy~(?|bvLK`tx1V43IfwK+=3pRQQ(6SO@prg#2C+D?V^#eJocCx&4(H(u z2yPhJ(QZKBFb84AYBf*hvf<`COP^*L)es{TkmV-p0I^35*b7+e{=s7g#G~PRwKsil zzySs;KPx7?_rclQcfil@J2#b%U)hcEtG)O?~_WI_>*pl2#}7Jfc9u;+~U<1S)luVSu`xPAa4AQ%i`55<2C zvJT0RL*C_(9xs9#Kz3HDjiwl$OoO&@l$q$(a4+N>ydJ@7`Ph0=Wq_NlQWCd#DH+Nk z8H69l#7)m9{B&H$#lzd=c&&XLu}>$$I8qAFzBVC;z#$T!LORE>odVN3j@?82TWkpJ z((&yMU06MFkCUWs*ht)Yz!OTUNLjfJ>JRSG45C|`iULnOU>_&7PiKX3(qET1*Is!|o&0~MY*_U_XFI@=4w{mJ?*WBsr^sn=(1Q*Rwx+PF@Y zH>z4uk*x+-nm;NKAJ9)&f4UI_X7!i)Mk#o}jL4u-Y-VJAyH8yMOr7F$p)8RP}UCYy?tjc?#2dWIsyb5TZoDol24aAwP6#RXNDA{F@QinGq z8U(}ZA~~{+E`ey6q6g_i7P?xVfwNAlgPAd?+VPHA(mm=b?2oAqBqkhWcI{BO-2f;- z`KVcJxprxEifo>s>moC$jA}$t>iGd2^Av^&l?i7=VXQ-?@6vxGQ|wf9tFLk#L;ks{}u&CVQ1u? zY$`tA94jk21(A7-Qx{$p^H|L{F86^8kHt9WhszaAR=urdQ1t1-I|Ent*6fYhw(%Q; zfD9M1GgdC=-|5zZoEvn?&Bd$_ zt|RDmpgmG)PVj(#!kSoUnN9vp-%}F4Y_w9tQU6{cW6Z(}Qs`bJOk+Vhev_j21q6rO z?vQmkRG0T1Z#mPUsyWM=(vC%6hz>tC?y%%bar?B)%1rLUXJh()7g((aupC1%f6Zey z(y|pb7+({{sqKfy%&QjW%Z$8roW?p|(tkLicFy(V1zcFCe}FHLnTo4y5EQZnQtyEi z>*lXcV&$JReSZvad<4idZd8V&@{eymrb(N;-h0r$&XC5ghgvLx%!)|WCvRnY4lwoz z#w0n_&DOOuC9i9yCPA!S=VzuSmn6sLzt1ADRA1@<$~%>E5Z-y^e`a>${vVi<)Ki>n zS5~4kLS~JS@DVqJ(GgOQiwdL5Lc-_=E>H1+Z*N$fe*#4z1R7o{OZ7@+ZmGm6y&;X3 z{#qJszr6ZIg;y$fjlrweMg?EtrLumh#D`Y~G<_TO{dfhk^8t;1K#$~+oXbZyDy*zYK_Y=_r&5qjtR8^tUY#=;ssdynh%i8I@Ir z1yW~#>am{4-aZ$)EG{gMU?$<~^gJ!X`abz^MYT-3cJTjYC~|^2vr!Fy?Ki257Yqn1 z)F?&{1YK}uNM%;3gvXeK)D#$#U(SpvP*b3R+J7Cln>59>$MJIAqoT8We{s(-VTGor zOf(%`ojA&Lti&k8y`K4^ue+~Ubu|B5`F&!4_ZP(rz6jSBvtL-Hti6SyP6g&m>+TiX za!jY@vU0oFwpe}Y5w>SGio9I>;$QL`atlOv_toOB`|Iz?U*UN!;4R?lW{7R0w5JlK z`8#^DQU3K})sg-Pw!c6sw~56$efiDuy8sHRGcXxD^4{0}LpdZNyFOrZv1zl->CLfr zDXdKiCzgqUlDDPYj0#@QJ)P0q&&e7V!u-;td}$Ax#p@O0q^8J0UaxG>z0pv1fgu;~ zB3m0+lUjGGS#M>C8-NCB`|3bN@tTr%*j9|9NuyiZ%=9yimm%!~fxZ{kprqCnnuATp zT26Od+NZ3E-j@ZPFAs$boK0MyKbdV{0;aejo%>tobcSY@5&D-{VK zZiABrNR176@9mzG3_t&WC+B-+YQ2~5-u20wxyi=PBP zDSk4@P5y7~o>F;1thperj*ed&J+bM$*m552zHM`KYR5To_s!P#qs2E`KS%g=>uDR% z1E}Wz@9jS-Rvs1qxBbo3<^oPU22~EbjZyYD7piPlM#1A04bE_^cfH<{6sHa4cO1Vv`sVZUvSNIuEyX6s1IR#`u zr~_Aa@0ZQ9EUi>&3OzqA*^`=KOH1^B!vn>466{BLCChkAEe&dyTAESBPxmS{aXDFq zs{n_|JukMY7jm*H8ygs|aQXQjwObzLlt5pkgqXn2ALm|+x5*pSB7FkmAmvKEvukGdqWoZy2=NI)Z=bm8&y>~%O0qnrD+YeNRAgCi zSMQjz-auFH>5HbY>I*j^t8O_F{J&eW6t!N6Di)z>gRCL?++q4qumc3B;)q$ zjWs3-C(S4MaI%_j%P-1zWNK3J2_XpW&IgmBd$%(Co$?yzl305&qihONYr1}fM>9<# zJGP+NDK*9HRqApyil(YB(1-#U8_OM=sZT;aeh#~E4h;AQ!~!XKgFaHU`<k}M5i)r^ZE}QE|>~D^`rq7+oen>p5N zoYV5cJE`?+o24)qyPJVcMyHhNEVu)p%J2ozFx#-gPfURZK7#F1#$KQXq{1m>oCQ(2gP|rx%Kt7twJO+m^!)oa ze4CYQZ(6A5o$tSZo)=vb)8ZTN#q7O^JGazbf;$gu5AETdG#^umrfCm<6HNbf zGktq7eI9Sc$k9)EH2nXva*g~n{;KOv;cpZ$j!O15(Q**rXm|IoEnl+HkL6_zU)7~2f&c?Z<`&LD1ZKZLM|G*593q-D0+1GZUV)kSFIBg!r1FP6*8mPm_T z92{WPK6w@B5rc#rKG-=rymfRKzeLf#&9h;2$4=_Gqh7_-tJ~}KxLl`lNP2AT)ZtHt zsw`a%nI0}PRb=H5{@IfIb*NN@86lVP18|MZ`7;MMIhF3S@lwtVx4O3*L3`K z;X@{N#zQfz+3He9fCIN0B(=L?MO4=&<|w3EFErGW9QI1C471s0Xe+gFipOf532tjQ zA{tm1xf{B`Bj}Bmx|iYC4Uvj04Q;5xHo7fiy>(Fm#6TFZv6yl5G>0tIgdnr#Own=M zS;YVgf1Z=nY{bD!HDZe*RrSzj zOzZ8~S2FgI<@6d-lwQiomeT~*WpA2bPRy^IX`-&1py@0i#1VRqzC|9O*TFYX!2L7< z)6V&%d0KsC6(((?ee|7ii=8ER2Igw)^TU;Y^hGk49Ezn$U2ibQ7;Zve`<%WnY=Z-O zKlmfyiTrcgci93rXDZPBCy#GBW*drpawtm~3jGC9d~XJCPE4uv6_AX5=*%KA?H4Wj z%}9%Ad&v}z+z&cV)@@Ya~H4KaV(7NAqW zldc9~j>}9{M|F42ZFFLks@mtOJ#%U9JeB3^llXs+3Z6{y|IJx3M00;JE7qx;J?W(d zR^B?#*8BQn1mRC*IsX))nJ9ApY#ki|*sZ%OZ)q^Udq^yAuD6xT3sg&7O1F~0jet9k z}m`o%)QrL$M_ojsk1H`rrBrX}t=z#lbzGym{}^QhD{U&};ML!ng=?l=h#J4b2-= ztIteH)355Dc9mbDsO^(z-JpePKe-Gz4F)fF)8&T#(9lKDp{qI8bh_nIhq5xb>(yPL z^Mw96jh}c<6a{}I#329;cRA!|nl5)7uer`*EQi>Ghb2l@Wy^^1d`B{322Wcc%4%*4 zVD=jw=fog7xHM*2_BV6q#R&5O9CnSr#YY&$(pZGg2xt6r7`e^E==~rqx9PWr=eGdx zw@tUstqV7rpItrL8CKd{D&w?k|3#LzaJSq2+xE2ZZ*OaVdHtRk-~2G)lS}zAou3T5 zQSw?o8_qi5myTt#C2Y2o&6aI2w`%0AGntTJQ?b;{PmG=6OwMSAL+FJS8M-{`%SVt# za_p3UK46ZT#&x@{LBPD0GiK-@H#9>W$2+(d;1+e^&UoM^#`rgS>^-OFRn9~0;qwaI zISf0Oy#HFtzVNrSkH<93$DtLIa|Kd8Wzn&k(@k*U*l`dn1Xw*d<~=u24{&#F*)?Di zLY35gEl!Kz7M*3exXv8H_k2rc(V<&zF;;Smw(}&Prlt{^qV`6)G?~$Cl4VGIe$SGJ z!^$fGvV;6j$R*`1+O{ZVvr^3|7-=G$LHD^Do72EuaCRIrLf|@_t&DhkApszp3mZh2}#DZJSki(XJt)-#F8Fr zX;sa3d9{6pvTmn%+U5=R9#%Vx2uC|<{WN`K2vjtAdS7Tr=paaGM$ex`v$77Vl4fHX ziUn28kGm(%YF%(o&tF8_eLsMF;WDdYd^Xl+lW_4?8*wTkyb9=aX(VoLjMv7@co7ck z<%HS7kN&sZ3}Ase;+(54)~<*woNL?hhos5LyC&Z{O}T3^P)Z9(Qu^Q07B=c#jWDCr zUc7c+I&>=ti8oCJ6B908PQwFGS~(bB>fk07*y~j+`^a%a785w-k;e7Wv;DcYak_q- zHKXhW4DP3zelsa9eO3hN+k_sau3XluBxdfI;if`8NQ1%JXXhrBCR83uYx5YUCJBMd z`8dmnvw*P&3!3~&I{APWQ$fr1BvtD3D&JHw1xtU@d)^i=Xib@JW~+C67qCT+lmKfxQFFc&J?JeCW90Frr|l zrVBdwyr2d02&+ZDiNcE9=8^G%tF!?uLc4|6F-&I+5Jq;^REl&Y(nB%K@eVC> zONJWpRkdrzZU@qQjL#9~HqFuB=lS#B~x2qy|{e9VYXLV1yHo%_np>z}x z+<;>k!%@ip-$3Ib|1V-Pigau9ID}KW z18vdX%jA47@(!ujG)J4qGIS8%ga-k$XZX&v>deEu-Rr z7){WvRW-r2UCTVt`^o1QKK>j?S9bq7ZC|8y|DZNqW$*3Nj*9g9{ho$^cF!!IzrC?J zpq=*{{f>b4mf5-Cj1a?U)tSfC+QS)`c)?l6WWy7RPsm|hx$Lg7Q zFFWzR;=laB(deJQC{y~12Sw_XC{hR&DYZ_V{ht@viT7*OzsXQ*_h;Vd@ls8g{q8*U z7kw?x5wE7yz+Nf(ydn8*-5TqHFrIxA9(T{d$wpTd#8FC;r{N13p^(hfr;y%7rA_ux z5%xmXa%q^VA~P$yw~Hw_gmT)&S*)@tg(&s-RC-2jmb&`Jnx$axBB*=Y$Xfky=r*vw zK-u8$l*XvRJN4b%FzQUsa7U&c>>IY)sy(+#?yW)p9UIpoTMJDeQPk_l-infh1vmi<~gsf|#+s=at}3*+A`Eq?rD_ZwGIo>ab?`?R>{cibqQIY)+S zsEM@$W)^9+lbIMmS8r5C6OPcSbR#p8<;coAZ~4ueLV^~MgcQ={&{$p@&aBM&gSe8d zI-f$^$=@Gln@j4?dyVH@VCq_U|8!N6GTmq5dv4VAB_glo>3`V4->X7gT|gX zm_nvJ66Kx{>+}a!%jNi*-(LsEE+H}0kdL+nPaLRqR7E$a*r^d7kyK@IV| z`@y1)F1O`rboKaHSy>h%DO$k+g;<5E(-PXA753iPvQ@)xp%9ecHy8m?MsLWZ~e$E*Uwzi%reb7@e zXK-%7Q)h$bh(hFP6p7xP5zt^3XXQaw(HQBlI-C>|VW*_YXVVcFBXWy`!tkD%A~pqW z;AgxWgQlv9-`RmvtE6`F%Mgp zq7GK~*s0sKA^IR)yPZL2K_XPF@|1qZNtexie6HI(CrBLJorQhua|EZV@9w;Moh|l- zK^m6;fSt(2Foi$X%4FDG1XFtRM|q2^39-%h3JIe~868fT${U>!81SRuFPi{82{$BZ ziOsL)S(0M4PE)MiA6O!bn8wNWU7rRdPVMJ(KAY)$UXJ;U`n4rY_d&XOq1nHf+qEjp z?TD!QTXpN|$M_x$^LPW^gQvX@hTm{1ii1NCpV%k*jeX@c?S4@6cXUbr6fC%%k&AL zCOK`~+I0lbk5XdP#Lb;Yy2}x12YMPKi9=7Zc;|{_%qgW(6iS6ZE9%L5fLv3%gz+X;-9Woy<@iNGK4pttkp;{LR zH!36kTBHAnjSlaO4%-qPM#0AAVL)XnT$}>2f&j#7`?kgi-At(*72`y)S^$mV00j=ErdCdp=|BqkcN$LU= z-{FmSi+&2=^4H&??0>(*{Qvz9^eYJd06v55=4Ytw8mBZGENy)OX)1rDxrl3Y)9Lpx?r)~Yf=oy9cJl(^!z6OVaZwe!7F;)&qn=uYBpFdW)-}V6f%BQ3)@FeBUKao&}8zD z7JMN{ePixrl z{Wlw5?v)dUEr|H07etmN`I^-ssr`9a-=*Ku(vdRUdYd6dv-|GR+*H7vqWLV+mBkpF zy1A%)g(>5^fQ{WMHoY{5~9qkxO)Eu<$wk0|mhIh>rp z)~FgkIbe%xi95IRlaa|Q~Y z?t<&nB2%8rDZ74{wZ-}|e5WfL{s}GboM8*MLx{@A@u5(q?NUv-p?-l~8&;(S2j^W7 zQ8oIQr7bY6i&`;H$`bquhiq{WPNPK6RFE!a^{ zRY>p9QzE04Q|flvF8+~I_!8!TQECk_N?~k5iIA|Z@zM4FA7}3Z-b9uDkI$K8(u7Xh zBrW06f|;R|7FxFnAnh)!$+Rg&Qf(uYy25S~FccTuHiCe{T7p5)>XvZFqM>*}#I;mK zU3G1XDMec>RabCfsnu0*!7T;32<`koX99@se)s=8Kc0tXF6Tbyyyrdd<@0*q*V&~i zgz>KMRo!;my-|K*U3E>lp}NG&Xz$H?DGw5fZ^>nB0uVU{bj-3OKMI+H z6XpxIf4sue%)(?ZdBD!(|FZK#lthFYHs~H0hCOXrhyX%r;w3HC@+Rn_XGzR=20<1ARYmby|9>9+Q z8QKET?wV!g+)`(m{RVPCskC+v*HLkI&+r!p3J}UA(5%=#`dx zr9Zl*hwZ9$thDU9=^rCJ@r)>b#3z7#9I+0JW<6w3jrhO*t&w(XAB+HV6zLj`XD^07 zA*aF^0xhcW8D?0|L)!fb`IbK7$CFROz?!fxwEkOm+ZW+NSp1B{Gm?~1`v}jBE^4$J zZ*wIc$1rngBp-`ISH$q6j2ZuX6nd|7VacwZv$qJYbW2srHZ z#-bkVnbiB|s+FgzSsZ(sZA;F#FufVtl3{FQG7HaMJ|bPrH!;O2SV~K)y(9e+7(k75 z4{T@{-!Oxi!Em?hK-3^l5B`9t&!G%mC|!dIwc`El5J}anZu~5JJpAXTDsARg{?L2h z*mj&5$2Z)Z6}trT3NH=4|2h|L4CW*nudAs@)!( z?^QaX>7%EokX9Eo2J=(IwgQq(=Mzo>2cE8O;70&!0-Z1t$eUogYzteYF!UTnx$F3` zu!)`u$uUgWkpT|(n3!rZlHMr(o|qZ~TdgF6KDf?WG7f#1H%aO$e&pUfXm%~r)}@Zr zq>fjDf>qAi=UMzRKAGYoNO^X*518Ugza6ky;T5TC1;T zWs0^5_AdB=+wqHy%C^1S9bSS0slf`w>>IyGPrj@9uFjlpNm^%x4UT%MNdEZ@DnKkJ z*!*BLzMyx&2GIDA0ia&!=qva8Kwmc_}p zmTna6J#P#4dVKd*{Lk7d*cg_+w&UvC2{ zL*Ih6%w>Y_oOfP4Um`M*UtTzq`*hkJHnxK|_!6`dpC2=aWnH_``Ffh%`iY!&hcXs* z^fow#vDQ3eQ_bL+nAyKCxWhLIiC>n~ovG7ikguro2g|>lPWD=a(mUK-N9^>H?+19> z`%5+s5cbLbS6u#?GsuOfkqlNpu~j9j2MB+aNiTiC>q0YU)bTGT?W%LVOrr$PfKzp( z<}}Yl>qzDtU+%_)P@*2w*<_pZ6c9+PuYjyF&TisGz&Ug8NxsvCs5h&Pn}sb`0`m=i zSN{I*^j(M5b^JO$w&SIBbuMRcIddZZMBJeJ0FKB_!!h*6*tgIh3r|t)E*jdVw2Kv8 zF9RvXddD-g(h*M!8|194?-`sxvaB|w+DB8hbWocaosp=&5E0|sJBW%n$?xcpr9rqw zKLwdZ@2-=N=v)ro%2Z1c!mJ`_2S6-_{5W4OZWiq0wp_C-`mSpMyf%vuZ~La(Sn4e3 zaE~-*H@YL2;j@^}Fxg#YsTKq*Ej|Ze-TXjUOTA0%`N6-DYo4bV;1qZGg6C+LGD&Tk ze61#WY_{d+f77L3!fyIT%RHeD#LA3No9nb< z_ySJZtSf(18Bl!y+W?EMp^R`=uH8Wd+E*!j*@nPBtewJG=7W^O_Q}LxlWcl^+oNSA zWDrf{{09++A|TapWsDN(BVJ$prF<6=Gb(FC9U63u3qrfWMo%I6`PKoB7SUn0be|!(xIK|g?DIaJkPB1omKKC&Z zF87n~={FRBoN$(2{5WP^SeJ;`hNWrqsG};hlh&rkyS{i}+upweJ9dEobM8$9>_R9xG@ImDLkME+^&4`InBar*Ie=6Z1l}AI%aR<#R724Qc9Om0ocWI^Nx3}%3Xny^mA+OK}*k5hoIjD&Oh`vsr zaMDSi%}jc!g9LZm50&Fz^vArs*hCjf}AgdAatk&Nr| z4NRNFSj74)F+53a^O`bLVzUeDY3eqV47s;ZU?c%r3rX)9;Ofk)p)2_6QJOh#GvUN0 zc3GtQqP*~L+%{*8Z4UNKk8T^S&T*i)DXFVGpXEd4n)4RZ2NnL9nvzE~3TOrE3L%~{ zuQH!iH)d7YR5is-yL=FnJN#XYAoBFq(&}@HtU*kbT_|FE*cLv5% zQz3@kqVSlAnB;@*QP=+EjnI&2ukxLnYW_jFw8KKw-xEuwI{C9uSM~5s|NMJWmM!0@ zp)N|WS*m=mcG=(fe5TCD@ifXI zIG(P}UMR%ZeKT8a8DU6YNZ<7+dnDE{fyE%83J^u6`GR9zZE>hwyYOhIRb3~*z%6m_{`?AhMmewAqEU>q$Ao!jCJqV|5P9n<;hNc(ib4zSmEktT$^z)}AsYA}Ll~S_d zSfCT;t~ZPso5_gHUy1JWo%6a5da#Ab*P{EAjV9 zK)wq14EpMzP;ne!T6PWGwE}jnpREtrbrluk8Xu(^0l!qw4_;Fou&YZ?1?=2ABe&mC zyYse8J~TQp8F8U4p?eb}LZ9%v<1AZ`;vkjJF2)g!MK)7wC6%;d4ZAb+=I=?Rqt-tP zK>yxRiOE{XEnz9l>HCDD<9ynhVuTPvzgfQi(!x5T|h8|bR^^&9dKp% zU1PduCV6Kjn^^+v!a_1;taF&@1kqYsKqP>zFJ{J>Mfyr=ve@>q&Lk7`se8JP#ucoFN(F4R-6YELn^$hCvn43L`ot}Y!+dcHmKe|O-uc$t8b8kGu>Yu8TNzX-V zTcdWJ$PgRDnnS7P*{PXvkz8oNQ8qQQpAx3Wkd}mG)h{$^5#O%`}*cv@iW4 z{R`)DxuhXR)PvDmgA}`?J5mggHvpGgm^?<_th1ZovRVQ}+g5dOuv12lrencT8^4fZzYWUjJS8{JEA) ze+t$}qGhqS1u%L;&CQ5Q$5hWofB+RkZhy*eSz+EZaC2>)KF>U4VBH6O=D#FfIt1jx z^fO!!S+V!IKGxqFxZ-a33}#dfW3tg$z@bfkDqi^Wb7=Cbw26LUaIM6~EH^VoVb^on zXVCPQ>GKlSAPQ7+FPH$^2^Zvo+DsCiR(W(<;SgKP3P!I664J1)X{ZmlKqa?wX=lLf z^|7|?26ER^G}%fqPRpl2RGr-<-mdNb!|=@bh=$FKr)QT)9KE;`7m2t4c{mg_D;KEL zIRsb1e-TLFkqL%%u;XPo70oc4Pvm0h1#&u#tag5N7`jh4!@BPnA>AQHjqqr@2eO{O zKI_#iH*X}u{n5TXK>OAf@&iMvfYR2&{LT6o<_)OB{ZvG!sVmH9<28^`f_~ni;p2OL zQQskkCDBwnOep^Jqg!-I4z@EBC70@>{y@YQXy;E-G9k9-mfpXE>cp8Vj*J!s=qf-i&v} zvi$g>a&GGMQK=+Tvv|WK&=M+OOBKU(aTJuMPlmE1w88OyvD*L2FQU<+iP* zlldWDu7lU6ni0fhK)`t@dvYkZ6D}oQt~2!(E;XO^rSfx4F?drjIh5B~I@!w|O7eM~ zhe{_)+#$qbq~y=pnNJwsI2ISHCyNCg`W`#zMHc=qLK|nAsBKyoIuB8PTj2Z$d*IrjuE<{*8OyFcF0b}pAh1_2FSiQo8+Ao`jq}8=wGXG`NH6HHzwp8@JrJ=pw{E}I0 z?=y>H>MYi`{79E&p{-dqk4@-oQ+KxwmJpErTncdF-=;mtj3aL;zY22IBf*#Z_$Trw zGbreMW}I>&z}`x@-F=#`a4M^Z>iTL+?qyIq5JbJ#{B*0 zO8{B_%VnHP)+kNWUxOF}ury@|vWp`Z$e~H!9@d-R{dY$5qxW^m&63Lj5+43lEYs{TR)uKLDRwY#vEm^o`Z^?9`jlbY;>33^QT-ku8OBb)#3*-JTK^(V0!h(R2hoNGEohBYz29 zkZ%_EP93~zk&G`iA;h+fV2U~$OO_wai&UB&!BfZx zdJ#oLdxTq!ack4;iDsk6*~qHC{5#;F2hjUfeJw89TAH>V_rbo-`9@8F%urnUvH?+B z(Y2ShQ_Fz^l`t`P9fR;=5@-2sVw=-qc^&+Gn!%FhAg8ywnG)YXwk4G@KcVXm%e|Q? z7R$Nw0OJ%HZL-$jhHGtEVo6I(DBLl{ngfNHmmziG9{yn0KMmpM3_#AB=h*!_VbjqU zn?yEWM`F5%AUx2Vmn`J$cJxL|b~Yhvwe8B&o3>7HhpWBe)!BlruyNFV?5Yur#Hb-I z%NH29`+@!!EjE+^7d0j>t11y|xkPIenc)z(RZoOgxfkn;nm3$SdvQBuyzTT*!-N_K z7Z{nPjgK#0obuUQdtPixKLn%~9R}>-$(wIVO1HjEvDZ7UwFT9q5w%jxF%|9ZiKFPLxCf8-An74l4AP@kt!71CFUpa^V1)v(#EH z1Sc`@ofnzG7R$I6*v=LgB*ShY(Nc8oH)C@W>Fg31Ng$=g&i2b|7jK=!f)kcbk)$oc zLvm@dSA4i&VC{LoSmhful(j52*L+)QF+0EgeM%r9_Fvu;t}&+`KlIJ!|5Ebv$568S z7)nkx-RecT8;@!Xh&|za<1!z}ucWI*d|%@pNzfu&Bo0jqK55X*lYjQm`GlcmHlj}{ zrls5-o6Pv$#ZUD}VHOlXa#n$BbN0cd(YzR^-YB(@of?$BUnyO$lx~fd z&iu6W7a)kze(#GD7!+qkh%od0eVJH`QXV%P{&zTZKiN;Zl*}TqZ*hgw8nMx@>Ns z2Cf-{uAZ-=wHAO{*C*w16Z%@MRBwXgHm^;ZGh^@IIyJFxXdJWah4kGGYG#(U;lrN# zX;hdyOUoJ!U)y7!w`k4WB^yV4Up^+G(v){}1hP zpP#s?_omnr!)L~RD+5O5jf?^0rp^1u+`%VmC#w!esSeO>VJpT@Cx%NNzd9yIQQ@E*Hu=EOo7_MQ3VH9IM`6)46 zKWaC-N@Df{27Nly^@ql}yE?tY_3UuoKRgbqh{1zqVb#DL@Zj)yWT_Da`-P++4r1TR zzEeA!!xS^RWF}_=sXVI|4-UXt=w8Y~l$g}y*L~f>&=7-YV&U4QnQ_4)nSJHsn7R=N zpS1ZqVM1T8MBwEp2@pC@p1cFFea=nad8~bK1<8j~S!Aj#3ZkvaP{;!+KDhaEN#JZD zAAJ-w$+X7%d#?iWe{&|F(o_Z1=F&6UKiw1x&)#_(n-JG~n?2?&ZcpE)n76s+@SNs5 zdfXAGPFxE#nd23jwd6m;_=Lc{q?8qV83#S+PrVM2`pQ9ew+rGtZmXGzP$ zGQ+$KyZ^?MO_vVo)*je?1lAnQ2!p_twCUi|4#8mtYkQ@SS|eoa{^Rc7IRcxcln*B? z9G0mM{`CjixWf3z$3M_kO;iWJ`hil?NY4+49^7P0j+dUL5xFw;+=zZQW4IP#^Tru= ztq6k{JF9t`u_YU_tZMVwRNEa>kiVs$Rcs2oM+l`Re>nR0fESBIcvUBf=SgB;%xvA~=m~C{$Kmycr5ufnA z=*=|>+d^-F=5UuI-P*8kxIZCoX=VLwjbEp*n!6ycdFgC-OBgzb6}$#|#bN;D$BVHf z6w8dUO~9vmOOBmle%9nZ@Ui)OqyNA`^JHV-z&`V4Sk@oQ%4sY~F!JiX(#Sw8=Z{sn zV-?t+=@x&i`bQA@>6XfA-z?rh_{8dQZ>?yVz^u*K6iWYa|5Bfl)gQ~bV^ua}1?b3F ziyK)NUyJuJ)>6FV^o(^hYhKsCR<@);3XR%Av0NZlL7t>&9(OEfi&ce?NAbzFAD7LPm+3g%i3{adF2uzZCAEZ=fB zwZ+A5lkt7<_RDpd<~J*~4t8dI!%ThKR>4iZz0*SC0<%rfn%8}T4JNol-pJAmTif)~ zjAeg=I_a*Apxn2rP!^8AP3N0IGaJ)iIbRz|`$ixd+j&@CK=>d6yY2o z;m#Nb8wU6MaV`G>jI!LPoaf1&japip0i;;8jN8dWP#v1~)%Rx~GtU3V>2rA+HCZ4eYdZd%UjU;xgVhB#ruLzk; z$yWif=hZakg%yMCN2VC1`BRBRUm)a5GJ_bX)_-B|hsDCVO?Y_CVu4nG?*KcSFMx|6 zG1+b=r#3Gg2ZQ~uBV(z*(L3+Ow~-FO2nLC?M1CPoFL3 zW{bHw3Kt(8gEo1Iq51+3%yR~cf8hE>2O!;$V_7k8;}rX9?OjEywezwDl^+jcxx#Dk zS@a!wDPH5DcV(TiwNN_=Jv2RsHcw*Hh5is!M#D6{f^!vlpY{|d)l7xyYNB^Hsz{gZqpdWO9WXhcU>FAXR(FmtRYWn1XfdTi zbx^3qq)fAclfF7hc&gRY5$Bcb+M26!aI#iTGt`=>Zo@*JqgCNFd`TwNa%mY%WpdLh zXd%)5GfJKV#-_B5It2cjN|a2IS+i?zA4uf1#8MyhXaH2Mh)hbD2R(U{7VeW`m2F~1?@%@ z%X)|?PUV(e6rm4(gEq$b&_&n+60Oma*N90A0CUA`jOoJndDbZ3S`M2H+m15iMHXa- znGZ>$qvj5?0$f0Q%8BE9d5VUWsIT-{e2RdC&fBw442{Ct|mUL`V22|u$y19U* zOijas4zwdqD9S20ZI z_V^XA%c}>k{kt4f&ea^VXjF`?&42*y*zpDi1%$kyY7s8(+6QB3+q-%_YS5q?@c^M{ zPU$~Yi-4b~h#wgl)*noUP9;MB&_~=07iQ@T{PfM=$I|ugX6I9M{gZf2Y%Xd^akIEVlnb3b`*H$cB zhUwiNFY>zT5a81X_Jf$=AKEmqf0n-Mb_k99`+{zEtP3FgQ-oRWN7IcUU{#6iveo7@)$+yHZO*Y>vx=% zt9RohH3Corf9+dE0R4jK8aJGw-o$*gQn!3M17O&PQ6$r4Ui6mzBeF-X1&D!$5+ImK zKv^SRT_ll3j5*YgXP_AfmcgS8d;>W36KMnd`T?5{%UMR}AiY#{3=Sv8WLN;3X3T7! z%VdIkai#@(5G>VsP303CvmO4JM-U)v9>i(SL>yOc#9%@10=;V1BPif0R6n>;1J2Ac}4^W)VKruHq z0oROSU4LxO$Z-Bejyx|{FUuxc%r&(8`UY14`R>tZKCD=x+aO$q(3Va(^0y60m7u%Xe74>vC8Ai-@_;R`q&iR_Rp<8FFYnI*Qsy)3G6@(2M_KT_Z&q}EwOVU#@ko^9(3`Gzqo8eA#l z0zJ$tL4ZC%aUTh+SdQQI;o&C~~6Cx}c(XU}cnx{TpR&2`e|`qt+9m(6v` z<~kkxM;~CxSaG;@=4Nvbk#Oezintk45+p#!JxalG+dd00>bBJY$8F2u)!2}r!Z3fL zt79KAKS<4p-C-tJ*w?z20xxC(=%M0PYz=f@80f`r|7Z@$@$h%QWqeDR#0NbFx-}}# z5vS12m+2ri&OvNBwC;BXK2LI;1dxuq@nVVdycp(`Qj`Kp_|KLa=b;ECFE`7;yK&;X zRu*5*AKB>vfVgpu;Jn)a_#%w&KrXKj+7rgpO2d&*Foly=Skh>gUvil1fuavx`SCtp zb!PpxoMQ2#Kc;(__OKMcygB1w_4{cals<<{q5Q&bDU)|X?fXfe=k@-iW2646I?Wy^ z7B$Neab(n_11kVP?oack{!b5$|-43*eQFMD5A9@Rh( zx+fX1kY(l8vb;k${tUV&R=W0zP7?K~dvw)v{Oljb%mJ#xgnP6hc45yW#+rh4Q9pci zhIZtVgChO%dY(V?a^JEZK!R;IF#1CS;vt;(|DyA#Ut|#4dO%xm+s6_U+xCc?;oHW0 z8GUWb<6Ykjf-5|CUS3`NXoIRfF14+ zcy*h*Z7kxeRgc4P48;CH4LEo+qN!!V{LbQbX|8q~?V~NDcIsqa|4A!6olmp7E6zO9 z$MZc$!=0H2Ycr_~0ONaxDmALR$?y7+D5$unt_qjUvyBI3p$c3X7qct z%iY>PR{HzqzCJj~Surv!iU)z}=q~u9O&p%B+B91|cf;4z1bVHj->X|*S>E@qX74SE zWbS;bv0_zNEI(+|E$3MnMc9i8%ImNF!5hM^wPiolFmxw``{St0%pRrLspYOQZ*ta=g1>DKzUYkJ-`hIfVQchy{e zEd1E3RgVZYOV;^ae-K^wS(t@wMOf{*+&zG={KH}|rX#T`+bQq1IA`yq^0|T6p_H)eVyY% z8t_a}cFXp@0fc=HNu^Ys|6Xi!7LZmU``LomxWD~y^?0)c=cMA-uUwrTQRfdn4#8#; zxOUb(vQsq0HBN8j6N^?|NsQ(zZw*Prk za_!R);B;NJ+aVN{efrG#@2YoTmZ#cBq!w9HD~4qs!(FYa z0j7LU#dpKi?$_}mpbI+V_&6xyyH(JZj_f|j0*Vx80P+=`V%;u?qYYA~v37QC9{Y=~ z2^H}|WvE1;2A~Q4%2m}FfJS(S0|~H-Q-nz(5Xh0b?APd zEhkMhOXPmAEViaQLd_X}KULdwd#Kf=FfZ@XmtbDLJPYQfA$oI-d3lT8Mi(OGMX?y7 z9UVgpTJzRMp zIfpOlau8*wxfe3kZZ4qDnNSW=>O4;%N+m2FE+V~7vPx}&+fpp_efRrnO6)$ zZbeUg!S~M}GF;(Prs!E-GpH;vlV7%uha-MpQ4!3rHIY`idBMlv%^GB_W7#*o3p&d) z4twD4Jujp8zLeJD6O|XEtb#&6;T76+X{`;LeTG`+(5l6hl--TH>)e0V&PX2VeWiV_ z;U-(-SkLcj{TV9)YI{Y+!t>b)h3qUAqCn!TxQtn3%d@XiF~xs=CIn8+qwrAoT`q9h z)OOJNJbRi;Y#vPRRQkOA92MZCxmt_qvpeXss}UlYdhqI3S_Qj6!z^JLlV|Ca7CP5v z!)#5;wWmo|gjqta2{f1U`Vr!NNFR)ATcHRORqT&smjJSkqr7qlfaxWG9XMGat)&oBBx~yjYGtcA@r6)$o`Qwi^?j) z5PNVR^i{t139rIh(7Iyg4g$6S&cCkEZJn!Kwt_>~`AwU>gUwLe?41qxJN1w=ACvkE z;rIp=;ylxzkMIG^YdB-uYZ0Jik@8*Ovx`r2#6uCNB2`!Tg#R`XgQw2~GKQ}uPX)9Z z2#?nuqwd3jd3{k8$$8pRERi>8cTUn9Mc97k>SJI$tI3!2hJ1eE(2}(w%fk&F{kzla zELFat!;tSN54cb>N}i){SJ6Eg^N3p5lFV&5wJ`PV?8X{0ri^5* z%`O6je`i?AOidE^CmJl4g`+lpN2$!!^DdUS*vvZX&x;v3k&j}f=Qb6OSWDOatSd#) zb^ipd1p8ycieYR0{0UxDwK(jZ>j^%11>-Rd?c7Qpp-JE`v>+82aA*q{XUb_(j`NH7 zwM4t^7*4PCCw}`po6W~V+op%F64!fkDz^5niQ$}LxUg4$tT1;EZb3=pa_w#tG9($x1uZ#H3>~LR{1}3c z9^$2~V>45&FLgIEjpi^fChGw>Fo6}|NQTJ0kaD;&qVTli8N~Hn10PhazY_;79lTFBTrT)2EZns0^a)IaW*6!klJyOR z10V>*6C9ZJRxR>$lWdwIa=SvPZzR*RG$7Qb;M-?-?J}UyZf~psJZ)&`NruT|40h)2 z?HzAtQQ_2YP6lS`fk)9L-!MCw?3Ml0_78_{5staJu;LW+aD0Skfk;_gJhX)`L(xV@ zOyMUOXY$vnreWqf;y45IA;Kcth?p`SK9{fjFaEe5u_U=_qE)z1d3bYd8{ThOwXE6 z)@0=|Dm!D@6XP8wd?S--G$~*iVZMay6ED+T!EQPK_e@E;ruc=L0}h;x+T*_-$ZCGi zB#msWLPPCL#h#dN*j01EFE=)x+aEg7GKaC&{*X1%Vw&7jD;;Z>6~x{ ziWD55XYm+pHE#k!x3SexsCPbl22B$7%b1>$9x;ztuU-X9>=nbh>-1dJ8pDfZjge%~ z_VE&VPF}mb%Lbn&UC&sHd1*{W^UI9%{A0G;;O}^uyhBsn|?(&k9*BO|}mw>2vW0k+H>?%~+p!ogA0=8J2u;x;pI7x~DteG~d;^8AR4 z!uN9i4|2)behB#CE~D)b?3n+`KFr;qAWQ^^>S*mQ29ml5lF2GEP5jabb+KFu)gank49esUUE5A6d}Dr?`ca)(bgjTpZ5RT z=8~22&)WRX|7tUL8A*-M#R zc^rH#dh}zv@qD@NsG;&m^hL`>x$;GM$=sInGR2ZFQ|xT%*`wFdCl{!zAA!*FC#xRD z*YM$m{8w?mO;<%_308<>+4QL1gW3nqK{?ibSj8y=jr}M5a68LNOp-|YYA~lf;6F~h zS!%{Ej~K8sOy{BbNH_C&u+;pXzJEM}Qg&sa>E5BUP7#h2A8;Jw+BN2UJ)4?p?&7tE z%U5xtn8K=v@d7>(vuZSxZZx;W*fLVni242)cgDzVtdx-gd(fmgllPJ&Kp48`kMzz@ z@lJtOVkE37r73KdxI&x)A;q2y7AUurCQMN^WTez(j5OHo^}ANoO;HCjQvA3ruvaZ! z;hzE?bEGsyW6KzsmF=)ii4ikWp_4OFU@1%zQDC?pxueh`dYEj1D`S!$EjOl6;9Y0nhTJcq9GzzPb6jG$r&+D1{CGF8s6 z~Ng>GcMC~aOTEFfXj3pDf#W1Gd~1sIPPu$hh82B{j(l+BgtHO@fzJp z0<`6z^aIdH4A$g7N#UxrLi5Aw083m0U|biFNZPg~Y(?2LAW$$-^a(&Lv88viH!(P3 zwhaVvFaG!>_Sf!Tq`ql85r-&!U0vg}dwXotPiBJExfCiqcz6CdkJ) zt>v`J99CzNm&SrfPN5SvlLXsjb8ieQrkZPF02)2x%baDMEjmzJJ};9YcABU-O)ec- zJMi*EiH9g&(TZQT+ZRF$3sV#8VMi1*9CM-65Q3nd$GMm*w*+_si%4o=v5UZ}A^>hn z37S+@buPrKKZvZcF^IE2V2sX$T){<_l4nes}eoxEP8m+y5a%_GQBBD7DigO+kb1QyyQ@&0&zJYIR`iQG^ z<16S4(?=*WPOMRWfLl!QCd6(|sARv%h^>FkvSiTeArJa0RyVF0lC;QsXRJ*e>G!70 zc!S_X<{b%8WVbjH2cWtFwxK{(HhqP=fP_$lNLOx+Z-uu&jS?GhTVOAGdqqP5M0F$U z3N#^cByXzO>vnUP|dQ`stPkoys|2aS&>aAIH9OOd-u zRuCubcA&xYtVE|uBF#{p}vC9EqZI_0#*UgJ=aWc!VS z14grrq)8;jO)Q%oJFRaD4X(I4SA58Y1HMsmnQX3vfGg4OGK;REUe{o;EeT-^E0#E_ zRyzW&fqvH@uWLxFCrThAbTgs#Tb25u9Y^%zZ1~e@$>SNQz12#5(H{Jy%^s!Al}esF zAzmPsyNaKh4sTNK-*UF2p!n^Ka_bTSXaw-9iwU^2ewWVc8qiuv?oy9s0}tmzLnFAS`3-Z6~nr8qDu=oz}sle0Ijvvp|l&VzIz&~(?LO@1pTD=&bes( zH}XT7*`$ys*|eh1Gw7M`u=OD^y6sVZ{GtEI2iK|KmvVEV_9-PRukjYfkhB}~KlNk& zE}ij!aME!E<8=%+yvI(f+c`e*aoTry$7Pd;GGVqpgl4X8tN!z(xR)}~n1M>Kjh|b-UBjkgYR5_ffs`mIZ;FxI&j8F&#gy#m$7h3UX)>SYQoP@L zva-%an$!#QY023x$Dd`_c9UO(MT~!nXa~ z;bO*ePV9tN%~=wmEf8nwwL+`oI$y+`8?4wBKql5FxAHo&`;@kNcadm_w;AH7#o0Nr zD89|BD3c(niG_39Ia^U&8zjw66Vu9xdc}mXk6{9$tZy-kTKOY_`KbDk<4Kg* z0k%QRyjWd_Un%pVjnPkjRTK^Sy<$wP+g+sBsGz&n#iAl_k>1JDl9y50H5CWE^aL87 zw!7NYi03~FQWP1CVqbyP!m_-r@tk?K)>p=AEDXY}NUZ++oaq>)!?MQ6_^R}7JQ!Jw zLwvj30!Wo2L^yZe%V-8LK6|{M)$^+s--4jY+%hJgV|-br0FtL64fiAknm{?ZKPoFw z$QC>bN(_!e_?^z+n1ZC6@zCj@k}0IOGa8(-FdjMrlXHeoHE^jltgndWX8*V({_FdN zH@vTk@<;~+D&IO}mbC$F>GkPh#H>8&s2)+Ud`hERuQq?r7d$bg1F5L&AjZuSZ$N<;W`1P7EPCQY2Ve`w_tKVD%B~I4?LsgrxahC;K zcb9^c2)+j>e)hOJeN64=Z@$|##!&Skp^?YhEcI!N5LvqGZ3E(ZG=i_JZw@mZt||mJ zH_uU>&lp?Wi7_ae87>V@B1KCURoz3nf|Pn-?=C8JbSY6ju<71KoJWWvn1e$MrHCgS zl%9bm7Bt!&j{Fbgf<{dnHrR>p(~$(De?Z7owX1-Z+(M^?mK>tp?1R*QJuuvw6_+%&B<*q=7cHIBPmn>Gw0w#9v+^vP#39WV|trpiSoewkG>gtL#L$xja%&Hj1S*8^| z@n*LMDg_&wLeWEQk`_&y-Oo+cg8CS&i24}(D|01~Nhs}gE<-`K$n!)6Qf&9M%1<@lG2WzWCeq%si+DqRn}-UM#A9$EIZy6 z^*j$<{nuXhYnwhbG$4~_3-vIHgY60$61hW-zc?o1VX)*Ui(OeqwW2mq-6b)+?-5;j zO{r?`1{S7V*Y_7&m`5_~e^fsk-CctBMR%9HU_GN})2$@|?&@}e7kojjXVeq+YzOv| zvT1Y|v6o|C!QMq_a$Hb{Sx z&vMFLLU0!Du&Z(OH{;ddO#C?C{MnFjrPqce21CLb>F)F@PE^bdWHcZG3Cs3)7#>@5E}4rZU4P?h_k_li=gXs*fA>Ys4?3+uh7K2rCk7 zGvlV%w5^_pnTs?t9-Aeb9Pdt!^Yd{r;{lBewr^&fd4@*28&fHe z5gYK3wl_D|ZXfq1z>_ISG&VFD9=E0q`;b6FqX&C+BJ(7(bJB~k+#of08Nv<6&s1w9 z89$NX>c@o-tx}UA;`s{SVTaSn{3O7d$fqps=74z9@}*4fua?5^je3o3>5}zvtBzx_ zTW$yGy7Ol|6X&?fGdWk@IB&4!DDx(m%V^)#k$0F($ZJU4Pi9W=*Z(ESPoUcr{Z( zdVQqALb(YzO@%o&O z*K%dNcAWUn@p`lIXXEAk@8e|)s}#D4z4eGSN;kQrt0RVG4`6dY>^11l5E+VA+3M`U zVYDxpDUl(#02%%C@&7?aBgsg_E&5qsB8k`f^1~I^_((hY60Gd^KpRQ~4tyGr@_LIn*7 z&vmQPQ1D^v)q<%H7gXvxbcA1suxn4`Y|D8$=iQvsImdF^C+Q=%VU$k!vD|%#X2z!# z{-A3#E3LjB$vcGcfxO!AgbsrUz{HxM4P3EKo4 zCvIN5bNkk30@R^go;-Nq3-6hd-W&687>H~A$85PzW0KV!cFT%6tU)?Z)Y z*@9d#mq|@D_);`{;uH_~G2b`}d*Ev;N#X)ZSh!l!z}^LgEt%9dmD5*{H0V{k}V zGRPmpRMadyrZZnO#_lu^H8lXvBGx3f{$MtlY_09)j}yGDZRVB)f9r?lHxlYvKQQk~ zXlQLQKb0W1M$CZ(Uccjctg9eRa^wEg7-%cyXAQ_h~2IL0gR0U_2e zFbL&46{afZU=)Zmxx0X2UN9uBuG(c>v#07&0#+ZA9!5a}$4PyuW~y&qQ-}TB-a-PI zDS{2pigR*m^37xX!1J?qr8S+{Beh>yLc9QN+q?+*Q5cH)St<4h)-5IO+Zl}BQg-rt z?5Y>!?CsHUrvSWJ=W@1BxRq^rNjC5Mwv{hPp0ZZ+jI6-DLk6pG_ZN%lin8l_Vr5>J zzfb1pYVc<PVZWxzlouubFhtf&PAHIzOb6r2)g@@X@ZIuP$j>giz4O{nR? z_5g8URlRMj3PX8g!F4ECP36(b4 z0g3fXF@A~ENnC@(l&U7SluZv5l`e8i+5(l9Da#Ak?cYn1ZnJ9QoU$ze`thUzr7FLq zx2e>U1Uu&@#=dCE3Q01!rC6qH;XIF5iepL_-c{+A;u-BCL@bbuF|(zq0>6(eUX8tm zH%+w$5C2oUwqQkRWw~eBMScKc659|%-9vd_}E|uG*lU!=aH6Y-MZEzVIsCb?DUGNw+*SSn}u0eIK!F8@7tcy#oOWwz)hg|xQ zD=y?3YIA8s7tfbLIM2Em)|Hs?D#Z55m*_Q>abzDYzU9I&$Cs&;ns5O^DHApw^vFjMV!F2PKazrq?tQ zIK8<)dNWwLsfgYnnM+L;L~rK94=!9q=FvM`ZqIH$N}AhF!RPWG`e>?^?kVI%e=D`Z znn@pB)sdiS*ZuR_sY?$(LOe>Xgq*3AJIK z8Bj7>!Inp_A&Qio2s+0x%(=-~|Fn%@N@n+UOtLuU$u4JF%7=N}$QbvqnCkH$o)4;S zkeVoK>4r8q0h%{E+6L}ZIr#1M22B5dY`~Oj4H$O40sfyf;HP5%LuCHWtM#|b!Gkia zZLW?%u<-w}329fG5J|k&1n%CSG=W*b@&%*U;apTXOx6k7K{~RjVb;XECyoZ7tBNn0 zXGEkg$5J>a~nzA)PLe`td~?c(xf@;GG8uAIS4)WB^59kR!CSkmpfv=;l+T zjW(jB0b1e@C!$U7(M3Foh;7N~MrS$f0`#oo%l_yf>k^|#)reLJ2~e@mYiv5!54cVE z!Bczh;sOG8nwolGi*j6p&}AB z#cQS$d~Vj45G=f6_~isD`v13_YSO3LvV0N`=!K7|uN@}&2mc>wZyy&`nfH%h=gc|t z0B44o0S_t<&KwbkVq6$32ZI_;44|UPlq2q9!K8?V8%(y)-n0v2AZ^pVh?@^B?IM*~ zOPf(^wb|}SfwEz@xov5yyJT%?cbbt|8gRbv>kOLq{r!Ib{CXuba~`g9o$KNA{CR)C z;LR3W>mt}7fKe{@^f14qy}DxQH|pO}qa+`n7_$3F!oHgJ*z5c^8*J|T znh!ILm64FyR#Ff_C3QG?YVK=3ZfoAkL^hf|$89JZGb!~n7DO7%QP0ns{27gPk*#J3 zi&39B1V@ORI8TM42HX2D&#l~5aHz51>8;o9syp1hsv82*V@%}FX0T!)v!W_-ST(c1au#4$@o^(8J?)%%FyI-|6Kg{fIETH`V875*dH>-t~X&?3X zfpbK*n+Ylc#hQ1&avwd_ZriQ)z2&wE+_Jsq{>CenK&%PJSE}9kaFu3Ab=3)0KJZBf zA@l))C5}x z6D+YUck$2w+m0zqYYKpORv7>?%6TCD)CD8{_rG4+5eap#+WHDx^sZtrrYm3r?G^L! z_$$e;R_@AtrVhQ9JPF9@`+jSGFIydCy&Ldq>AkMrWaj;Gi6jgMyfq&&{}}JG3f7X! z1olZO)!trS;+o$LVlu2Kpml11?2K~&|{P0KKKQV>1 zh8L}i6O5;Ya^XN~jaPr&aC$5;T=#j0y#c~?YqjDqWxtEII+$P5Hk_vHckl}#F87<5 zpVK2C7i#91zgH~`h&=R@*?S&gTfb5+2PLaK5=IA@9zgL9vd1;U8wQqtM3(?UhOq?B zXP&E0HnT?5l^G|5V`ao~MoH!s4mtEYYP&ed4y?ntPU{M^-il94_;co$mA zl(-(xt(VAp%Z)?O9z4(!C zU(NV|uvn{GV9&7R8&4uBaM2v*W@_Xa?su9H#DI)G`YRkbknA5GhrX|0l5XZ4fFI?U z)`_krdm5l=cpoTgb_j#_zf2|_IOdlV;lDVskIv>3#zBv$OCN>=j+w2FH8u9W@$prK z%!K&d+l#(d$_lYY4h?0WD!Wi+upceZuRgAUBk;cAQLq^`8tL0A%JZ^})T_0l>sGxc zoqRN02md^qQ4f;?+NlR^gZ5uffs)99Hnzwt<{5-ILkp5BHo139zNdk{*)iYHCNV#e zme|D0^7N2xY=ag$-E$MKwD=eCI0L<(nV`l^05&<8?2~P_llL{t3?j2Z`LNZnz2N(@ zow1QKwxlyzbIi>q)!9dEBaZt6#D(N?JZ@0n_w~~c5SNqZcKd4ApTM~5GSywg{NoC zIZ_dO+;2SNW6ECoWjE+t6lZ%+4HgtJWrh5mX!3OB}s?W!YSdvlC4vYvhMm=WW zR@9ekSL7`y&8>j3Z}QUD=%v}F2_Ymuxk1pj{CljizFq%N-ujs%0>uoQ&yRtT);_C)}G1Ca+U*Z_?M>_l*g04)((B88;f1*dLzoI+UXS zDDIZn9RIyYE<_Y=GI|%p>I&1g53;A(@JhYWz``m}(ozi+a>l@xTXfg4gF|#}{u7x# zO-w7j7QnUH@8f49(?Wj^u7$vK2t4D^&Hwt>-U*dQ*~b*Nig8frkk13aivPVf`x_-g z)76u``WvMAKdePG32Ie<{jjau5$2oEw1Nap8dA?o31y!vC4BhJ@DpxLV89&CsSI@I zYN_%ug6Eu<3hxJes86bb6S<(~9IFQe|P=|0)4nAzbZ)g61uoZ1YC6n07=cs%L?pi<{oc z5@yjO4DR-MNbAQ6@G|jSi7;&>IRSsyw&0><^NE@av-ebp8dyjzbgy;HaHSy3{x+2tex!{mph727$vn zrXD)>&Id;zfOK_NXBk-|M-X=Z3`aWFJB7*Bae8Ff%SL+nVO&0HBy#4OJyhKcN529rpo7fvwBmyMsqEocPp5#RZK6v z;geBn58cM3v#}Xq^+g)eB!k++A!sRKS`h;S*s2Z9cfDH=}U zVBfi*bRk?>5ZaB6hwB<6YvyUz>7X3A{3j+b68)%8T0w&2`>B_G#Ud{`zjt}PCkgfgR~>U$qrGJHv50@5RENZ*Q#5;xGF&CA6 zFFr`tb=PQXw7u_@7gaxMR0&kX2A90DF)=B98K1tI{qzTixtivhwS}t zRHp$d*Kw0C)qLQ_vxtYEySeL$)2L7jQHAAq!`q*|1#kHW=5hL#pxLJZ1uMk+_l~)% z?1M_u&7Q3FxmDFS@4C_z0$RSQO)1!@1g(0Xm8)^Nq$%yb&)*Pt@nQq-;KTqgTP@3f zld#LW=CQawtGVH~1~mBTU%E5(CsF!k$)-{PI=&1>ZA$%f) z+qZGstZSydtsbK+)&UmlFo=@UgOiWNy<%PS+ZY$x-prM-8xwZoI(Y(NY${!zjF6H! zi7jJpN4nb_hk!^NDLj(>W4!L?2*9tTFYEx5mAk*lm9kM1yFy(sK8*bW%%|Kv3L$6t z4<`S%=`{8bdMA6L3MD6aYMeOE^8Z%E$91F5DXcNwZEPkq;~yO6tMK!VnPF6n7!b8s z-dSJS`kh+&;8gJ#v!Du-P<5a*-{eixLjSoAAURW+8|c&gc@z6S0Z<%_lVc(LhWGm5 z+~h(ghn@`oTmPeQNBPq5GH0BdL81VxD_>4Vp+)^vm>fcg=TbkJ6IB`@cG1Mo<814@ ziuj1hZA4GSH}v5z(7XPUAB7)u#es~ES3Pb9ETq>TJa7*rc#d|043@$cP4B~BuZ>_luJ0rD!M($Z+Db8aKa{Iek5;-S1<7Wq~040Nkg(7lI z8Q9Gk*)|QW8G%EK!S7q2$B}BHkL)X`ChYmlx5kz_8{T(@yQu2_-K`Yji5 z#v9q$)k%#H1QWT8s$+?ZjmbTTBcB>tT*7RnW;K14Qw0+|S#Wu2ARbS(Q!b|A6ExnC zm8Q6@VNdHV1S@m^_e3S&-{>WeI#$FL0BfUpy2m-BaB7gkso__1!|ULx``MxN26tPeumBT#%=JiyTAhOVPTQ*=Eqe_7% z+6MM3nz8lU;EqBn8&u#g)OL`l5{b4ms3)wQprLB(R3Or!zJ+9CT;^;6IhpbMxqKF-rx?M_5v4EVUNCe~Q#O6GYh<}iLEWm9O21GW4K}^R52FcvZ7HhgTIE*W- z<*rjH;p^NM?E9J})kS=}QJ8oCREH&d)`Z-%oynw)4F7((NkzfoAgErgxPvsPJnN|a zh!ye2#1oUZntUBd7Y<2|i+yCt?B6m? ze}6!OKwumSI4=6gk~LFad_V&wgOG$6$y0~*x9!hY`>$cDI>`Co)d}W6ytz>minr`y zh1~7aACm6(t;K80a=K5$`D8)X@G|ufYF)A^-y|7z?2-~`2?aOKq>THd!aM2b6ot>^ zu$kifjA^BWyk_fLoHoE{9VU>fo5S&-RPvm7p?Th_L?8SXKvY_+$D~43$Udqt3>|Qa zFy%x(|A9$Onvl8Zdj$Woe?2Zg(HiA=Fd&2J87zPr=w8Ky>5T{3y*|er7i&Z?J4~d= zV{)-^5^I7GP9!Qi+mKktwA$dZKh_6{>c7z1qfAKMa-&g^f^JkSO#8M8NM7FOc!VuM zsifhEfH`ZOK|ia%ItA3Nk~xTSteqk!uq#rJCVRJnSLHKh?<*znc$cIFO3UN~GVr2C zDoqb`kJ*;4U-RhW_6-xTkv+>xDQ12hwMP5|&)>rY)aUnW5v=&R@c%*QT1A!4d7Csv zI;w~PX^@6XQbIT7`w#CUm+0MTr8S;wi^b9;{&m>B>J16%m0oM~2J6*y&$$tU_ye(y z(iI=2SDI5*H0R_X1}{ogyvD1j3jh17sEW(Z`s1}?SSvqi0AYb~>-8ild&W2;(btXA z78K9}QF({Suz+X3$dp?SFpK%FryNGXzjl(ktS3=em}WHr{yt|*8M>fS34XR1|j}vYAD6>&>SEg1eXX%*$6B#`ixrN5|eDyxt5g3OXA+T(E zTN3jSy)j<^J<5G0vnR#!OzigLfodKd->)D<5uY;^{zLltrh*hH1TBJc^{bR?*w()| z&AW&HzbTjgGUcKy_==PZ1Oa`gKwG9l%}I=7_MHIFu>C*Lt4i80&@0!#`|wzgQEF6< zYcrVJ=?SRYPUDBS;((lQVpgc{0IgSk>So4Ie>7c9t>iguwr3QiXkdv(jk5%tq((vn zWavBlLfGX8DtQNUN|0)&I+UHQ@o}4}*44Jd_Ub z3AvkY{YyIe0;V^R&kQ`zBRHk0FKlkp64-w9Y`DWs_Qxk;Y5P6OaF*%@ZjujVU(&$w ztSsBWk9nja$(d6YSloqjf|=RajF&(br`6n=j08pRk2Kj+$6&vCYAw`^RQiVc0ziY4 z60PJ}nyB0atfJ&6knt~kt?pyyzv^Q0G~?z1*xmbyn~cdUl8kN{v1VJ5Rd zv7P83XLh@mBs@IFZD%^@W8o$=xt2`nJ?uM}vx4cDnCwrW#VP@b1b#}Gc6td-lPqD% z?cT4zefd(xVeQEgr4kM~Jnwgc zmGVa>4X#}$u38XIs@E()#T8+u!Os6n*>af4z72Wl9a&^I;u*^=du9rYJdMo5m1}hi z_#(Qo=^&{#fBIa@-hew^)};6}$90iMRgdc4t{VomL++|odHg$GTAPwJB)Qif1o4Sgb zPQTxsseVtS-vyT|g#)KSIeRvYWy0Ug0GNfHqlL7F(^%tk01?+Zhlv6v=<8J*F2Nc2 z?p(vkxdjYQ+d<$Oex~Qz8HWCB>Ytrjs!tW`I02I)Xb3e;ZOF|=+eqyS+BFCinD`y)z9;7}(pxLzn*bJ#sD$EsKKhYdH<{uND zHz{QT2|dnM+otDc%V?zgqvAdY(Tnn0uP5$oIE=6Jl_ofi4_C+sbLe71$+byJN60f1 z>OPF>d9aucK@En_i>kpNc~Ks(v*`phyT$Nf!Ue^2D9|TgS?_O}GZm!Y|f6 zMLVQ4^$)`8eF(JwY?PM3`URc3zlv2&AF6S{p@DqyBXSJ6nQJhetoz!U|TX&AvJa4s{~`Vn}3R|w=SkwN7HVL-zO z0%i>R=FmZ#*T{%nz%jhn{+9C2%M+3WC?;kpU7uozAF>LhB+kH!Pr@AC8!wm_Yup-m z%I;JKfzM&pegZ!4G$Ex}d}I_|2Brer%}A@ro~)_;KO)F`7INeGaSCZA$WK1Z6#f#; zA~4`D7}?hEKzEAvs={Yn(WpxEMgmo+tX^bzny@Ni>jo309w)8CZ2lP99m(=eCD(je` ze#gDZAP&j&hcuin6uMiOY4nFaTew-;3FoBHDu}@yM5qasT0^DAV5uok8s{rD%cTH? z5D@rD*-gF?w@}aDz-iC~nk_~_oua(wU96c!fr5&M>&F#ee-7AmE@LRj=LNIDLeb6( zCNEU!KHa&{k69#A2qUw1XE>5s)`*z#=)O;Hp6S}DpVwiPjk(KL35yY2<~o=&uuFmQ z0&Dvd(xxZ)&!@>$k81a z_6==1^@5@0truRcH!`Q$eiLzOGRpQ}&$cZh`(I|Y3yGm1&-i}VlztPFbY^t8UA$#F zJG@IAnI`-iJ5_jIFz(;8VE??LrqTR3X2k=TUfMXG@jm>M^U3?2$?BOGANl@_Yxoe& zM(APNT;$NdLmwPFeDF}x89ch}b0z(+Y>|!Z-^1>I*}DG~Bo9{a-)$&m_xG(Uy>ov~ z&Hh(_CiL_Db9KJ%sufj(gp^L(UZp-@{*{k*1>f&XQ4c?Q>AAbA(5LR+$RD2V?q2`2 zR2Fes_P-L_hsJKeQ>ySTrDl>B`NQ9B$8CfER5Cv zsZAfgBfYmGy=#T=!PCjN3BP?g`4-_XpC&Jagl;5X=KkXSo6hN(^Jl+kwlQeSUDowc zS>Z1Z!TY$5dLQ8)Jyd=ll5m?r#onw<6JbT7Af*1Hu zNsfzld8@J~g)KS)R<-9WTl5};`aPpGrmT4>Lu3n021Y@T_b7=u1iS>)ok*q*D;Q%g z%kk?VD;=U1hEr7wHci`++j61aki8a}C_3GAh`2s@bWEvo-{sjHA2_Nc&m>;2dagRD>Yu*g+%xAa4j zkL@c}oSLZM_-#EkG$0H~-M2>}?c4wBiy@1HrD^e9A(xP=yVF#YS)N>C1ky%jp?P`2 zjX-Cpn1BHo_5K1lUk#3!FL>Wnh64i2zw^<4Ycj5Y=Vir%0#dUCW4KEaa&0!wc4$M` zCbgND6wnlReifv&%m>a~B@VmQg+sy46 zBz$zYo3~D#2M%Q(&%WtFq-<$~r0`2Dmn*~|JdONeLwGuL4Ergd^$#*hbk*Chd(d&o zSmGqeT_9uxb9qygUyN31A(p5z$*Hn~>`5z-n@x<%1TIbuab)h?^qb?6z6xS@Mer6# zvdhGdnl!NSjSx$-VnOU~mSQ^#XSZU(7nhYsDwi&2x@1LcCG(Ao;sxfD*7W%*|NJ#A z-VP#)&r@`9oxRBh4*-&Sp)v%!&whDCahc*}lQkMJDVruECuNg4dL%avSSGS5&S#pG zdwnKjQ~>swgy@$AGiGm21cCPybK;ZnP$A-4|C<*9U2KHj*7^Kc3;9CsW)2x`7;Qa*|d{SYyE0Rg)GHDTr0PE*$0XQXHY{VK$x6tF-B-$YCr?)pZfJr_L; z$qpF^n6k6C*jiipqBH6Rt?v@5{j0LBp`g9xAqJ|m#b6)6xLsn;kgE?tsex(})oY+V zIyHL}RuljT%HD557`q6_eq+J-12^O$mL<1Jej~x-Ik%vUz%ZPZ-MX5Ht|?6?uYZIf>Z^AQu58-N-*_{ zs8d@e=;Rcx-L6kTW{pQ5@)$f01PW<`9$jUipxJH7$_4f>jdPiw*JuiQ%*}67M36eq zxw^`)5deNy;liAt$5Q1`@FVE4N}?WLlH{N#UiRy4CF`rIdoiU54Q}>YBo9XkeEE71 zS=mE81xx1GAxFYC@TUz-w;&bj=hR?f}HJz_qmgV!r(9kYV zY}=m{_dAZ1#RBsON|j5hiual#g%L-Jp!u7`JWG!`sszDiKey9r(Welp!(}GdlE1w% zyW{JkKPnK0pNr1>q1>_+NL0PQ#jq)(U}%SvJIL|RDiAsQ(Zj{i6w9k>>NA+e7DoXJ zY#!J_OCYKwm{2-A2D*gUF2MjEb3X)>A-ld{yLG#?-PI}QZVzqmJjiy|n%6c-s8v)d zmF6V{0o8_Gqk$ab6wt}AOAy+4l5IF6qe62n>Aw@G`?(DPs_PeE;ZrQE@AY)5;j8$2 zEFX(z+zfA}AC?2zt!CBgK^1y*rN4@SZ5d>LZzuAS8!Gu$5A12Vx=J+bO(12bPwRPI zmsT$rc(`@K%?`5PI?c%XeG0x$*^k;cY^xCl`bkL-B0W(}6r{JW>|dwL`Ce~;WdnnU z5D*yT^E&zYYqpv~Ea_pHt=srM{)U&Q>&tonEMVGA7Bef2+PrD3H1(>|ux0V@oWrWu z%r@uPUEes^E=kU0ToO4UX^JT>J?I*LvBiEpPcNk9y--+pc<~wytrc6G|n;(4^4Y9Gb6)nHIFD!t3JKL!dm__jG==|o#B}Ttr-@(A9z+gXBHk5rD9y>9hO}EyhOS*JdxjQ;5tk$qPz#KCk%d~tYvPPBM&AbF`-#9FO=jRKV^1Z zZq)b90=b-N8vL=(H;@QfXN9%s6UDI=_2t(x%% zN9xWkVBw)e)8!V|Q=c0(8I}wl&uGYD;H*TkJfDtqoD23R+;8omZS85>r@&YgOSI2p zj8$=zwQ@ri-HX}e&IoJe53=)iPl2myVUb+H9S}%P1Q|;38_&x+<*MKvf~$fHTU&Lg zqOt-R2$Snw+>E*5-usHkRz9nvvZLeN)|a$YVan<_7hr`(>t28Q^*QP3Y_)juy?8cc z<+r+%vYw7SLjip8tIx{)>So!;|M|r}A2vKH4W&nL80#U>@6K8tSz%rCr}yu-wjnK< z_WAq03)2x>G@StYBUuMSWfXg?LgydlP72j1bRlH_6gf_xFh&1`MF8TKZca(JO;7hE z;!F+Be8t>E&m1(V0bVfhJ4#zC|BaKCIC++F(~}UD2^NFk@465z$M=1NMEJ14B^5eY zk7qpy7F{x&3ZfYfxU4$BVfp}Ni8PV;a<+>PSUEYKyQ@(4aZVm2=^qmzD;JFCa@k)s z1by74eWZHuHLYWi@D5nK-$CB_p5{g=))BmD*8{ATcUd`1k835z`nVyQ{(VO60t$%Q z4sN(gSjIl0(E&8e9lAYYNW@N^c&AQ^=UA8)O|!G^7UD3?QVKspB4?$DjxI!ZvLl61 z>EWXESq^jV=NJkpnb(&gKmOv`&qjbD04epG&6*=dA#V1K*z|%ayjM=<5phv26mMoe zUmboun8F7j6&M?~FvlAGy%#WButCXD5^yuB+A%xN9Z#U9t@(W5y+20Cfj?Df| zDs`ot+yDEIpln0&8EpE&Bqe2H0O93(1Ul;ojklWg^8mo|G>eh?ahm5Wh0>U9o3{KW z@gZg4&-=aJEtHV(6M#Z-=baV~Y7kh~SOE~NPaU=N9m-BC z5glP##<~KIJRv2Y4gap}Qzhd@H$TMZ=3!BfDh|e-*LGHM=M{YcKg0n$UeWk%*%4^T zc*XDeKEjgm#^3+8s=sr63j%Z?Am1OZ(k%d}>#3HZs%WrR^34zeyE>z#JqP|90MlZh zmQCimmSWlLr8Sfz$EY^pdj9j)rxj2>$OCmu6Tq-3DLb_ zUwH8$ntF1GZYXS%enFG`Ci4NkC;MT=_k1%<&J?9KrbM$KZ%A|1Rv{ebJWK7*AwyNU z_0*=LEkpH`)_r(E3GhVbnH5yug_#d=_ak$m5LGTM>|T%>)r|%=EB?cpp&h{#F8TU~ zJvsZdW9}Ue!TaY4f1jpZ=Y_0LRy#eskE!0oyG@30o zev5)cpO%xG^i`^KjsgCS(xys-@*IYGsyQR_;G(K{*4()xR5h!dRL~w)%6v+}r{9Iq zrgxJv__?A_1&B#OCy8+pA%vtD;6M|dM2x^(q>=VWi)^sbARqT_b?xhIH3c}bHrutt zEQmHo0{lie9rTb8VROrD>6_!FOPKY28bBhZTi zM58K5ar9I*u0$q+jh;n*OEtx0q{lOvfQN0l^L}6i2RxeQJZfYJkXZC70xN5^rK8#w zIe-^1&|8MhS;O?MA*LVBk!st}oKB+030%?d;c=k(dIsMsUn!`gS|ro_nz`SjZEiEG z7w9T$?t_V-ImcG{nk@_Pk(NG>{?!|^z2^Wbc|g2drL!v=>vFkyJdH~txs)n<8PBBqCtKPCZ$fYt?3kMk{gAm zx9}Ye5plMJCM(8Y_;5_nJ7Tv%R5JGvO#l}^YpHzJ7OEV~Hvt?7}yjAPu%=GYWj@qVsBQTl$=PQ`< z-T?E;o`D^G2lH7Y_UzHOr8(NeKaB~yT30DYf7<%Z={*uVI1k>TfjnjKI&@Odi+x{) z+fTYqxevq+xiVtCX6&MYDy3)+eFeNtmC|-C{aU=r$qH%3BPKjnd=Pa4w65pR(z31gQG2*+N56!JMdeRW7 z0p81JFhze?0w(jk>X;yB6sFRRQ)v8uAFb9+%)_1HGhc>XyZ+cyYwt5n&9 zOW=P^BX#{U#T7lR>~KzO+BM;}ys+%aA9y zGD?SHTe}d+KJXRf%v5N+I~l1WHF+i$UJOEU!#yy;X#hUuVA>8~##(J`+aN{`LsZp* zAtJ06#yWQPh@4niC`&Q=^q^JrWJR`UxP?eki+qykF4%Oj?BclNdY5Qu6k~EiI<`|s z0y5T3Hugj zc9y0Mo>62Wt&I7q_+w2uzv39iOB*PCZs1>}X+weUVqGEG`!96xV0`YLjt>3wE6q&LNG@2sT@jdrCXi{Aj7DVB^Y`C6OYeYVgdS7ah-c0=-6$r9E`j2D+9Ve2l(Wam_Ws%mhb1kOOumR)jJWn?sn3 zTZIMXP1{Sw0c&()gS<3t(3X(q9h|uEBQ`Up&&je8g}fH=|KtQ#^o?xMMl9KZ>xg8` zq#(hgBSM->NE7Z`Q3_B4S7}<&FO`6k1(Ytj)u|^zJyV&}9MEf`D>9^?B=KGl(De#6 z%VZNw0&6ta-N%Vf$A-Gi8=Kid7wO4N>~zA{5%FJ$6<~Mn!$WK|Ah|S+U&Yw}Yt+Ho z@*@73VnO4m+m*|;{e)%(@R`JC%%lYtR=F=_ciG5Cu`o4ch1JGqwGRz(HCOqto*b>(QqIE&>6N8p{ zG!Bzzp2O-^I@rT)y~K|wE1vFN^2J5%S;PDb$MD;YTMMh-1_S) z-bkCKFjgglgnQhs{qYNcM5^)UD2Hn`E!m?z-7!72+&2C8ydnL-t!&XWh0$HUbk_Hm zzK}jDb;n4xoIci&Hx$d4v27+u|GBQB(@II+0$0&_rR>5)1|L4GckMUdUUh!LNeo&) zp^vFg9PR9m>8$12br0nY>AZ{CHU;qQJ;~QTlieB*U|F{#JDe4}yRX8{Ca0nzIr3Mq zaM+4#>DqC<{=>C%cA_S4t!wZk)uCa2L$VRbVN{iJ$Oko7y6-o_ny6__rXd)aWON7l z&^7K9#0qW69DS)PMH?VmAJHw$fd@cN*22afAgGr?t@Z)JMZf&G(32C{lB4kvV}JzyuXdcc|$l%~yZBgK&|@76o=bz6Dct&uIWrrYj~_~#{WO9@8V zlF9-au4f1DCWEU8n`y?vMvzobCWuz#z0Wj(Zj!z0%M)F*g2`gunV$zLDWzU}XM4;euc)v)&)RxC0w{Ek$GGkBkipn#n2dsJ zZZ8O~H0SFQYjm*`b;z~SEIGBUf1bdzLQaD)EvPq!^g@(G*R`XJNJ8EHn}1$?`AIMm zi>dRQJ2)}J;WX_s_0-zD=LnAaCnf@q8ywENq@oYW)sw^4P6M@Due*C zGlA6_8OMyqxM1xJ{-p^}nl8__TdthZjWt|scTa`eF@x`$=u4h&doALO>#La0|C1EG zuZ&i>M>A8wL&aO(W@l*Kw+N!F;er~zljgM>LmEmDnyG6p!KKlm^wWeN2%S6HTX%baUdb?0wx6yNUTo*`Y(W z!=-6IFmjDd*u;P7F*2yCOJ~a7yx@)Lsv_tie;vMlFzEY4wIkJTVIWzk3 z_JuU=W8T@c#1pgK5>HIKVe%(B)Pz|2O?5+w;9@8*R$u9XH< z&x{**gMdm5exT@`=*%@X@fMx@BhJO?e4G~JxKtfYAIHla7yV90mX6tCpVI(h6y1$7 zZ}jn#-P*cJ?|MUt9(Szcnyf~BY^0z@@g&cKe z7wQJ@LAWjGtt0_gSt?8swjxD{=_z$<$0yhnb6=`fcLUqzRJ>h8WZ&}N zLr1jDO?RAtIGfjj;Zb^9(ddLrYlIO!IsjR2&VTCxemjwV3W;DpHd*5mY&oBf3+Q;4 zP8Y}x2f^wD`gS9 z?Z)b9E$7GcPIWx00`In&JFqN^K~W1r#m3G#g!DvuZq>S`X{8LNb;(5E93srnFX~Iu z_7hYG5Mc8n!!TndME+;<-(KrmX=wX$A|nogwrdsb7Zdq$#I}$5?q?A~F0yb+=zwJ$ zo}ldG;R%6g|Dv@1iu%7r=~cXG%`L7OT3O5aw7e8mj3i5?D)KB<|3dt^CI`EBXS@-N z-7$mi);qLbFT}%q(@-2tBW;J#YTGWQI*Yo3q4JoEo}#jqK#HEApDlm6*gjR(8+~BA zDmC&H&fT*rBlzZbBMp|ix^rFccRux!!2jwgIVK?xGbQ|SdcyqlwAgUnXt?e_ z@V*sYT=b`xXMf!nBL-p;DefLvOXayWxy*2p{M1WW28*?emdU==U=xhCIWED`_CNRnNyV#Q9vdnQWkSXH%l=ugQ!NC&j1@Ne{`=a;hQvyAC=F;tVD zY>Qe9m=g+SrbxBGdZPB>T>H@-Lz@gOsF@|d^PN)Nk!W{)0Rz_7XsGax)y(|$xTh_N z9G22UP%o?&*=qJlF##ztP{pk%TTqo-{}7W8$L9SOM<65HKI@Ct%`i&M2wMlL@tGR7 zdg-SPzgLrO_V7_hfxB!mv#6}5sgi$xR|x)ei7<7>sdWnBy}~r%;w_F zroG*6viHutrH#T~T|@jFge@$c*x31j*aZ0&c{s#iEc>-0uQb}M5+i}{GY037)}9KuLU#E>37)R?t@D_dkE z_oo|mew~t=2jZFidw5nQ=EHk&by-l6?WF#c5?rOLS+;iWf@Q5u%vCP13?`Ipenp^~ zpk5XdYHD4;*qyRMcF8eo1G1b@Ri!{Ve3gWjnkB)2xFgA95F0P(i;&OI6!CBTrakMS zBJGC?EV)@l|5mDc?``Y}S;bCk>d(tz^9rPomGoCu6|8xcS!Yr0({7ePuP zJf=NYAiRiQO-NOYTw#IU;i_fAnI*z8Zc(Op%{UDeLh*5*#Q16n?A(DWGW;_JJPV%N z3iH4{U{wH+i0$jEP3o&nc&InuSigq$xo7rRPX#qwcFrE_tVn!l7+bWV3}hpGFuNJE`F>NKoi2O5@tnd*T?#s1sy_qYO>be zJg6atnc;3n)_!YB#!RdZmvVnzXeJY?)eOZCtc2Ot`!TGZZTq7$M01ZSu}ABo`;=n# z(TLbDPfi>y)8BJs1`xgP5sfni(?O$tvCFum+Ga*qcU*sO&ovjG-pmOpZDxW4FSzdQ zyY}MC@n>YAS9~ef^`>$-^BVhS%He~|;o56jbN|I=UV~G!vn-U5TyuUsmo(Q^+KbNQ zG5S&j69}jXX0AC_eoqDB%p%KQ;?(efd4X70WK4X*C`T@cg+>TGE!g5U_jCo@j|IEZ zo2w&r4IO72EDhJ|yy-BthH7nStrKwwuN>QTPlW;cnIUD)_GLO&STa!7C=FbY;c>fMZbw)@m@>(t3_uaw=?qX&(^`dD)u*toUc8#v^$k%lF~QpEEDhC*x)uKLXFN|M+)5 z41fkbp!9g(O%teImwYN)4D$lK6!s%|y{oA0|9fYP7NP`89WMh$GAy5fpM@c8zn;9k zK^#L-zBFCsG^v}l*=$m28t6tJ0f&>j$6!SVi#uraKXNgut$go4o#d6_&;gc*{}BP! z@P>cSM=#TV78KZk+T#e%T-U$>?@kDzugo z>w~ngu>j{TAX4P+1O^sSjB_T#zk^nh+gt^{tN7n+#&O&Sw%sdxS< zh$ZKLsnEy^)rMd2#WS`AF#(==q9I9LsS$@4{r4}g~S^kkIYzD^RSC{Uo ziG^lUDtRLBB4Yo^*RsE*5Uo+enf>We1LKewXY}32tcaD!K09vTF)BaVkK?nW$B%Ww zXLC-;J~eLtEzTUk8GH1M7(hKMK_hqXW-{nd9WG7S@v#CcfM7gaF<&UDHv}(HTuORF z73rahS%)jqT+cTn-T3RkB>hc1jM}FaslJL78HBeq2KGVWx6J?SEO=sEs!f8a0W=+^ zknFb=SM5yu+e*o*1;-ATx(}B=C)LhoYaM;H8COTnm(tmVT=C_lLBROuBKp7;h}Qgd z1tfJXxB}_wXKs+5njI#g0?-_ti2mD-Zs;_p2ui}Qw3xWD?RCy1c`gt8%cUCUj#*ys1$1m}X`ICGD zn^^`atJSoAqv%W1JEj0PNZmA`Fv6^*OI2?AO9budnYE>pX#$OT_h)IpR7f3a2^1_J zFPp&dIQWH<*rR0dc)QE*1Nj`qyuTXjaSb>&L|&q3ZYbuUN{NMr5zC#a6c1!WNr*rkJ-q)mO~P zQxf5x2CiLSF)D-{x}dLE+pS-(e$ho;Bz;pXJ;ekTx83^nJ;m^YTY9>`fEmA; zv-B0S3m4#8Bp9&8roLiLWv)3n779~G&3!catT?U`R-)}p)^;1*KgIE?s-ur|7W`zp zs_z&)C{6tg;JTsv!~jqm{uVs5W7~T5NG!Fr7YnpJLa}kdz-1qzx<_Rx6<{u$o(nHs zOc2K3tdtb8oDu2alL-&*v|}@+9fXpwLIKFI61XI*1x7@?cgZC^pjqYZ6kj7ihml8~ z9kT80Z+!`wheOF)xqIhOHi*tGbkiJU{h=7dS2T}<^rQjruLY>B$u;)!DU~G!G$8Y5 z<`t!#UMmcYf`MAU3T>U<_~vS68;Y#h5bM#%)MSUIS!6E<#H_ktfv2QE_VUfU*8ijd z_B0QCl=OfW7Xwl}fzc{jLDWcRN&+d4KojgL_e z>_c$nM}igFfxE}W6JLVtKdBVGNogV$dvvL}s))hvdg>+q76^C<&f+kVumqQ&s5P*t z2!j6*=Xp7Wnv~1wUSs-wG3m2(>DO^hw-zBeW~OY-4Rklpn;Yx0&M*7A{`>}Z-k(fC zHm&KaO1RGCG^Yl!WSTa>vErfKhIdxHFj{3f`sL7vCuqIM)0*R)5I0(;AI?D%>2#nJ zwq8*DR;`e6xGMhCj-KTCfy~sNsswS51>nJ~T{M6JCb{hKQgW`(p5UvP4~Dz&W*PLV zBDeQv`l8;fniqsb3~1sf(>L9)B}9xp(6ZI4qjb4?RL$IjwR7OZBVV4dn@8;y{X5ou zl}O*xp4Ntar&$LUh9WEs0^EoiZf_6<`%I>laUBnvoBec@r852Qi<>Vl`|)xJSO^d7 z>OX9cUuQBJ-&eOZIR|S3@kM-PdYlAvN6M8pWRE{iHtzO`=Qwdc0y$6B8_Gycr11qc z8lVnywXd#@E8fXCwYH9P;_@l^kbxf13ohS2^EyG8{tN>|lyO!JraG+d9VIOv5Ac!U*PPWGjF~#|;)`v9KS6&b_t|}4HDZ6d!GxnkLeN~CiR2j99>>u`}&C1M!ct1BT<3pz z%$KUg)wgTc)(0*6V8snxcQ{h>{dG?Q=`{cbnX_K_1AOUj@kS3bCHbqI5 zy7oXyD(yyt)K;lB0Ylk}gNUQ-hg(}n!IABuMX}84(xQm|cpjl{iW}S7LV3|tp>qnZ zb)~)limp^dUP{mJd!LkwKKuOt`;40NcAxv)FV}tD*Y&-=7i!%-=UUTLb^XoCs#U++ zRR5s5^uyzAyt%DwiSwJ)Z%X#Y@EzCGN2vde;?>7estBe#`xO`KRaui(rN8RO zr!%sDX5CN&=u{Pv1-Wq<>QEeGl!3)}#U^N0B!?_H_0GwOYbI~1ubv!QoMYaDw64>e zqBPw>ebID5AYu14OgN6Y1s;Vv>9!EcP23pE)zy z`PSveO3zkcscL7z$c!jaPzoemiwqX)(W|*^74{zCol>l~jho&ct;MR)2CwwH5~p@K zr`Vs> zus54+q;vuQgigkQ~ocXdB^hu7%i5&|F;S>`5IZN4zaz|H~b4hW>) z9swZEN)^Z(m`)Kt2fNeUN@^1spds)Sl?vW!M806*ureLysBmik&sa;QV7k@ePv1jy zv=@4vQ`43%F#p9_<_}C!?<=l%rZy!i+Y(iwL`{358eg!7W^*t`<-c&Ftlae&a#{?$ zK9+$3=KFy)23*A@$nIYRm;I3~_&o#XP2~65ZE=$` zwT)4>Gpc%u;8R1~S*bfG?$n_<(`u1TViy^(Bh0{P#j3n1e*o&iCb}|#YU0=HH@?mm z+y&cg(}+UvG`WOt~2lngASxpLt#0j4nS@4@SC z$;_PF@!oXUG15LYus~3V&YPF(OJ{1Y>3gehZYV$m()3s{CWrZ1m5By3YjIl|ps@E#xzwzY2)8EgAg7GC^wOZG7y!SfEWdK?~nS4!; zMI;U~6)-O`jt?!9bo!GD*rl+)IwYyz!TP-*m9F8(mh)?kaTxK*RgV0A6=&*Ee4(_= z;Xt4fescs#pxX?qzLqRruhIY2BibxC&w$9eY&EkhA3a$4vH=o+`epWzyt37mNU|Z@ zlF{2``OrhD(l~=GXwF}teXLT>hJr8_bg$N;BQRvw=jq|+a^*2%9^00uwL+)NQ$m}C zUL_++38M4b@^n;-%2UaHq1Wi-I4Pzid)s`?e2AbzWnzZTEE}f=U zmNMgWs7Wfw~TLG;`NuXv^Ac1HJkp!Buq1%6&AM4q~78tg)iZ zmDwHd&0#8(1t4e96{?r3>e(MPq0*b`#UIhl9TZHu_hN;cv76f>u+!5AXQDa2lHdx5 z*o3f5-{TZ4QyGHf#{dOw8S)wLizbGnCb!7{O*nnxatZXoj)W^B4pqmU1a6VD+|_prT|zEb*svF$z--^8&681WPN?|7#O1N zJ!#7tESJ{Mk7bAOkM(LT6QHIQQn|7gfkV{6Ez8RV_kt!q3g1k3&j<|!M+*g}D(CkV z>$`8gqZl$;ZXIr!@MD7&dzBv>Gm=yfj8Lzp+%{)Q;yFVQhTwW9RmdPs&YM|*luo*g zSKa7i#d`)88Sx&^;Su#G(!E$)FI5P67$Yq5tprBN=V$n{XRxjc0uvjEb>&kEft>3U z976PQ#NdH6Fqw&?-SHga0=|^8K0IS*+={+HY+?S%GhSunU3%+T+zLZJ6Gno>xPNHr zgV*2Xd0>>@GJ>rj6HdT>0{uy&Nugej-=oUD%Kz7M@q0WnaqRVbqJBf(G5ouPf7XB@ zk8gM`3;E*4s29K+qa-h{fGFW>t7%X|1AE)UdlwrbT{Ym2YRigkcu{Sy3q(RlT$a~r$9bbr;SQ@T`oMU|2mtw2k9wN^^ zf>F7D@TjQ_%(z}-p)3C-DTj4WFBf9jj_C!!#inTXCpxBgRCds$ifV8_rf3x_V;x6L zEnqCzI9s2~ltz&xZ)}ejSnYc0!6f0CUw zLBE2kA_IU;$+dI?=N7voCmnivjv8^S0q`W4ei2-5qBQHRKLaE8x)rEu!&g*~rF`ab zX7f|)s*gWTeHhw|GtZf8HRm_%TsMrox7sOvKhWG=lXcs3%xxVcs~V5?u=pI!-3C{y zo1SxyorBG=)orzA-g4Vy7|!A+?HO8=X149@luJU^9*K!{l(9ewlJX3(wT;|Q>k;{( zopb;$YoNLeQ`#}|z2!M8`MK+5n&M^Bw53dzPvRHQ{-M2tQBx`VCXaPdt|ahBoi^^ft;%Q@HhPGC_JrtZR9U6$)i$W^|SS#)E;(Z^JTFp%HTzqTM|;BLxsH*qZaq z$m)_`{<};Shz? zH;;}SDLLUkv+7bEjqQiG5AOeAzoK*bzkL~`ywT2eH(dq8LCHJAyBdq;vI$HmfgMgD zfdmC47R(aRtQp8HEwxpA=giQBqD**d=WVlv-uX-Eize-F%|oefgLy~l{PpI2DcTfs zWlFP(+1_D3YXSstI-}WUX@6&b=>rD$bLJh0fi~|kdO7Tk%`=fzLv3NuH^?HS;B@8@ zRet`zYgAt4T7J)J!&+m#MYpWk9t*V;?c-v1H7J;U+`P%UeMVPwVAf=U$jFJY$`EHr zKTY&B2P=^0?s`kYy0^Y*=3ci1-If~O{FQ1=%Hn5fzy)_z?&OY+^|AeR>Hlt?x=H)= zM7H5(M({ID37U2+oZD&kH}iHhU)B@D`BVRGnLy)j{&_o%l?gvMf*l|Yu6gB>>b{W{ z7-hp1BkG-!`Hd@kVWpZ~nBz{&0ZbFoyylUQHmz%E&gF{rE0XPzlAjNEXqkd%5Qkqd zK!frBMdM@3N07}2J&hHnd_?^u{fVHk6H<=?BvTwm`MbD=cQH?f=8Ha4!gn}bU|$`` z;Sn95ugmIzu?$e;JjNhK2j*?j2wfAG6U@I1ZaMMnzG@9v;ieE?8EIgdVx$Cc^JPY` z!;GgL1Cda#KVjGpyI1+D<^HpKk2WF>n$18Mq|Q+i+W=4ihq(Jv){v3Jtq;!|+07zO zY&}Glb41>B4Hx7v>{Ml>17L;wN8oS3{{}v^x-2>{yoI|Vk`Jhd-R11&GEPT5%~ zZB&=aQ)D8gi9D2{$;I_HS9A#3o@f_083G8LL$HKi&w1%GR;)Kiv~~{JmrdH{N!Pga zN!`D_aM4m>8_63Yb7UvDpY z@eyynb;f#Ot{MyuuDKdq5_uJNhFI!q{2BVS#FFOex!S|V-*7i{xbM;YT=LJC8U|^< zNxxzkzciY+@Ag~cn(?LT);x87|MR<)`+u^3&OXKd#Mgf} zcqjqm_1hplHuiefmr}8A)!d(fr8M?&$ft{y`9B-o?s6all746%qWg<=G}FWdbL!}< zw7xbJdeb@YOd5(i6ivFEtk~*YHhfWXXPp}avmAm0F#3_f$>Lg^z;cGH zzmFn1pDi-j6?!%j&{(waUaXWHh(p32<=bdSY9qYrVhwOantZ+l>L(K8>ts%-u%0fM z(Xn-jkiUY1_x~?GZ$~Q``Dq7g5??ORb~HY3#~yy^IeY|F6zwK*HZE!-gPg)SmwZL< zhsOeriSOCSb);rmnW8Es?oH`YEH{<2Rf1Qc)x0(9EnDypncQ5Rx+ZO{nS4mgKzf)A zw{x?wIh%YykKImhM%luuIm_pk-|JqIv$Oya=hq)N{=El!=&_c#tAP+GD*_Zcx4c*^ zPR&_C+e%*f%GlWLIV_yf!i=;?pn?^Iw9=5|dKivRbR(L>mkFsST;IUu#M$@Q#01Z`B_ zW7b1ueVH(_p%in@eBZTA>|Z+SSQzYJC$xR`T|sO`TNxXTrooEw)>qep7UW0O+mf-QYb_L!+MsH+6yctGcm z__VB}#J1<2bs{2Jx zrY=jJP21fEAUw=!Vb>KJAqlNih#KJ15&X(-o+-;u|D)NnqAzG_lT(X{A6Ajlomaqs zazR>W0^BJ4)4rhVcg-c7so9ZBLOQNqm(--wqe-wp#P`hDX0Ods{qVzmWLFj(CvPBo zcZc~W7d;F5t<37+f+Sk7D)&PW2^qcyX5P$Pp>$&Qtb%`1c@77MNy`R1GRUIS;QOd8 zLoh2o<3Iui@7QO^%)bjpRe!l*rXWOogx2tiv?uQ0U};iB#US`9kuIH*j8G=r-KLhW zTHXa;=D(zt04HiWhsCyMQLrPC(pMt$MGd1)LX-q}Ds#D$ra_W zL;L*ilGy~`9uw^PeBeh``U&0jWBD#9CmuRi)=hPU@A(NdGB`017)N$4$BV4U-a9U5 zBBs~c73)O(5YS~=2YzCmejIlTOGfBC5MKC$JWlz)&>{pu!jtsG_%m6r$rqN$vxZ^# zSL63xxqhFEJCOdWTzdX)`O?xWv|RqB_`#@KqA8PTr*^=H*Z3mLdCPbd9 zQl*=9z8Pty9*NdhP%VhJJ$N2W`A^cv#OczkndUOq-~FkrJE_VX*;b=YPaB)q^ch#d z0=e8SZo{mZ6a9bwv`XEgu2Dypr9Z8#VQsI=x4t(TzcrKI%8c<$i2sXcLd+5A4fNhf zZ4%?ol%-+$sI+bIB0xF% zR%Rg<0B-JPfduH20WMWbCI`XV6DUfhOxm?0&BnTqr6+VDE|p_rvoH%J)8W|6{=mMli|I4&To0JsIS|Pj8sp5K-Ts+u`gh z-;U02=Qb_FC{N_Ji_`5nd@vOmp+Rri(vIba&xs;zP|1*jPql`~7B7>YdM?fpzD}gG z0ZTJ|o~O@8y4M2J&(NfqJeFyzKQ8CA9uQJ7F>ES)=AHX-=%zt**b zmO%cF@0a2EozxdVi(#Y6!}vl}zq<@Kz*s?EqZjn$!KEL80wUfHGH;VCkXpo+Y4MtX z%^soaktR3Mru3~ueOS<1Y7P54Y?To9;~gOy?(`XQxcY!KttJ{;Vp#r_uyBfR;p9A_ zLs)3B%tflC12f54I>X_rJP*5M){~zgb<)T53>Hot|A`(C#P0xu-3@KxWpj+dKcG!K zzoE2OVgUz{r8T-{q}V4=clX07X_d*qjTR}fy#jJnOIT|Pw|-Wo*2iiyfv1B+9dEw> zRBrc1xm+q_FF=|aSs^74t`Nq+22$*%Spx3yGC8L&cv%y!tMswCl=3eZ*MQh5erJraGEmLe$(rp0Q%5?b2Yq(IQ10M5lBv20QIJ0F_eSM`J-6oH_v5W-&@m-!@eD7Uz9 z)^h2&tkA1WH=NND$BpEUh<`>Ez#f}7)2c&$j0%lPe|c;|%5`HrZ(NGog=+D7xi3h> z=M^KV0FHe-b1AGwCj&O`Pb1O zJ`QWqv9qf#*Xi<)mYnqWC{CEnU3&Agdh-&!d8Xcx#lG;@d6|IIVU~&TxA|Fc!Q>{Z z7F~tKuip3@meX7|vJ+L!6XneAZ~S8SWTq{Fk#`7f^BG~H3OMof%unj=Olj4%OIeqa zFZ}@Rnaoxsv?H@^aYl3(q!3a4@@ixlBjvj$3F@1@_#6aHNg-6VA{xw@{a z;3J92yBGZo$`eqvt1q`6U3IpxM{&kQ7-4xXXf>xIC)@3-?Nv~ftwHBDsNwEFE?P1bSIXDsAgeXO}CP zh@4ABT%ul3VKq-;Rf^@#%NDjM+4F~g+DtdolsaZfzr^ZN9FVYj)HVw!Sc-hO0>r5Jg~KqIrc(x98Q*a|Hpv%^K?b}3-nz-$(NtzuS>Cmj|zE^7I+qV zyPQ(cAW<$`Y7pLw2Oc{~NG5#*hLw8w$`jDS1qlqOJhkMgNyqYqABQJNUbvOK)3a_m ziOeM7OQY1w1Y38v8p`PnQa>)kx|dSn!M-9{WfJKzZ8&}{T=t)?#bq=4P?uA8a_`aB z6Q&;4r6;0(%;X4z<3KiWL6q$?XVo~bOpd>M##IoWBJe_Md2Q~UkQL@3qtJ1ww8_X9 zeFmcrj6TtUOqU@qyMs&3oVhip#9bG@=L!ZeW6j)Jx&xqfkNxT)iZP{-i1e#RT2Jg9 z)stV;IX<&nHfigNxd5x6sHUktJc946OjLd6CeJy&d$ z|C;2#DIt(1iVSR`%Rr`KWu7VZiL7N#(<`;iuKWcsFo}w`;>4z6ZHAsLPVltPbgvSM z6M!#Zixcr#saN}4S&5$k+!C$j)b=_qji!AIzjy`LCS6r`OZX1pr2vn{hjza*)7(3R zAK|pC06s(8dF4Zu0Uu#*`U>}(ud3g`^0}GT00|M8%)Hg;PA>aK`ylqwe^LCm(g{zj z&VO{(8(BTq>u^dG92vrqdlZD}15)zq!NPMEwC#rm++9ztb#7ZNt6~a80!a98FJgbEH6oLx8#pVg$miOj%6I*CI_Oh z$h*)o9B>*~7^9{^hET7lA<}@c5C2JOhZ^Dm7A|D)xeotjz=<8-C)3oul+TZRA{{jz zv3|ks-w*O@%L(rER;Sl`_(^io8o136Nj{kz`FTdt=Gn;RqNZ9TEK{upvVb-Md5@Bq zT;l+dF2fM8M35*7E)qH9(^aJwF6(Tj@EOk#byV@E?$> zY>|sK=4KlBFIAMVe{8uwUZN;h1UV+^V6XMJjOn>|j{^8SCzLP!% zC$WUNc-C`HDh<&aKDlz}q7>3I7W1;Sn=DlupFY~e>VuOGaJK+4<+wfns>d%z0mJGMsLn0CsSV z&iLXa4tHfRs;SuatP(->S~_%124bQeY0Q(HVngu-t5qO-2n^tI0ue52meiSh!VU66 z&DNB4ZFG>g#obhNS%Lk-+&8+e4Rq*hmLx<*wMmgZUW+DGgHhK)Gv!h)>h2FfX}7=4 z$La&D;oKq}i5ohf7WOhY{hv+nsqVkgvjex`(O6lq;sM%P7kL?-<$iu@9_&2(Ed zTk~m6!f(@B`UKW+QAig7#5G1%TOLJw0m^1XeQ_MGF`b^sZuNJX8ZOc2%QJu?o8Wub zU1|6zE-*Sj8$IF#LF_u#qKOj2!uA(y) z6vNK3bY7S9fM6Rkt?R8FTZ5LwBSvDdOW`H(U!<9SOa;9B^@`%-Hj*xB<+35K?l`!J$RQ%cheQKOJ{l1Vf30T%j{DMsf;IU zz;tikT(K#mey$QLT{&MrS4CI6xd4gbuO?8;!LK^2WoqLYX;((uTneSx&bQ5#p)+$S zXr>L3yV!9jzQM1tu(Mj6uBcYvvBU2YA&ChqVu4hI#hG5-omDnPn8Q+R_8dhnu^UyO zE;NQ;zCyMCaia0s62jycRJmG#^5E2~Mx^?-GQbJ%H{-Ef%HJYQO>#olU;!f(f9DWuUvs2z;?B=YepV)C^3p0mRK%M@|{;9;eagb ze;ECe%k@L`Xb_??a*`echmyPBq`D*>)z9t_q7rvNj4tISth>0pczH#6hOc;{SfO@R z2#y|IKjIqDO=Bj0xCK9fVd~f9Em{l~h(R1}CWq+}r-!|hTPjO#@)mVqjExX(3C=lq zT^17E*Du9+JCCG(OG%e}PnK-6AqmLc@D7BnFg9{}*x4-kZ(6QnH>?!Hu!Y+96OjsH z01E88ol30EyX5y`EgD}}=-Z9j;g+a&&_Vhbq011yBE3f`whCZsA=&}XQUOS~1E7SC(uv8%I?r)Z7)#QCviGQa=n zXF=k5gSyF?5Wq=yv?WwNP*lt{W#WOIDK1V=cA;};I=I=tK}v; zR*_m-XiFC=Ir&3~w#2vJ-`$IXWtkBNmB4jvH@a6v1oyNY>`JM9D$-lUZrjGpGAC4- z<_qtY%4XRyUxO@5sU$@TQ-I_-{gJ`EW9xUfutN1l#%Uli`u?kOh zky~RzF*Etg$^EB)|M~yYQLtB&?IyLqe0lw01GQ(22@osdQV9Ga8QkV9Zf>3KVgDtm zgO6+9w%ZqE8 zZp%%w^7)vg4kLDef2Xzkf^7+5wMp_CRi8^pc9A5{;{PJ=(W-Dsut`$0#b*me50j&p zdApP7`X$TW+$0AQ*fgN14q8+$_XX?KlSA~$8o=&9TN9Ya6bvI)Q4nH8@H5>d{pPkS zxnOhoKOI6xV*L|((oP?Q4(___CV2LB`s^3nE6{ic9lAM$g(eh?QX>rVA3SryZ- z(p08qsBXPDG_bmR&4nRmbt2ZMvv8{0QcbpdlQUG|pTkIZW-?8&f&XcbKLg!z_3+!I zG(v*~JQbfJmQUc3eIh03{DIJEaCcfZkYd^_LZ{W;$!%~Qm`Doa$M*QKfq3X~0ldHT ze#Bmoe0t(og%z$#K+;#xcnmDvVx)7phZaRLD@7yXdEJiu@sTsOlez@9l>&s7+Mfwkg6H z5G+TG;pZXKDI;SGHVCQP`dHh@^?mvn96-a^V>Rez^s+N5qbmFYoxxm+Hu-HQU6sPtH z5;{Dcd`v-`+uHHHu4paGPrB1cg)qFSXp5|$NO?=Gs4uKCV(Z2+!_0CbMBgPn^i?qO zn2^M*-d-GjQQ=se3u<0OW4?#5O=OzJn*AI(Om73W2Yb*IJIQhO!Kehr&@Ip%fTUCw zI#pYU7MtV~NC+yof!O-j%q7;i1-i=*ZND!Jhx<3e_gT`9RkBQL*hw@*sV$;PhvGfy1ZB{q!*FGmxH$ZQG6*NvZr*@iB_>uz3(z zp@N%}R;kU*w7LQn4Y1%}9v5}Ufs4jY6$53iz+JQw^qK3v8telyb;Ry$k!KILfy|?B z!xq6!-ipm?fiLs>iW3um9&7t`6whE+CdZ%zA@YShiZ+ltXc-(6V|C8AVyC~C5fy`i z&N&!?E`!I=h78r9Kc&kL^#~;W@2RwAbFIp}Q00mS z?tAse!%DSF>1UOcQ3!}dxCB^bKGxIhOf;J^7b*+w0mvhPTy}@adUYx`R z9p?N`B;wyR?;U>Vex*5_#;s^bU|yVbri(ZB@}@yPWtdN8d4n8aH?%@&er*C*p+>x# zW>YISrS|=;wp>l5*fxa?X3PjUm)aWG;CmQb-G7uK;?S1q!JOBip z?mi`-aXOB7e=M0pHg}Qhz{S$9W(cur*V{&?lJwE%&4bhJ$K9tyXGM{UqR*=<@Vxn2 zLgEVZ9r{qusQK_jTdwxvGhx8 z&E*!nOoNzL8f~>nE@wsN9ZIv}wAgX6^!ZQAEWQ~t&0)QL@8;Q_-%ILkQdLpl(8W^q zCn4uurQZx6YLtf7D@(PXavAFF68FT@$uv>(F-Z-McQvWJ!z#SJq?mNKkeIM*RqP7? zvr*U)l%Ca!3}n<&Jp;JL1IJSl=6@84Hfw3^0o&*lpMR4)N+;QgPNDh%v-n|dQn8+_ zp_hBB7o(}TRQLIzY04oTMQxwk!x$YSFcS-}{L86yRU52-HlTyhO$ZHXudX1=>4O*) zKO_Y~scLazu+(;v);{fYK|n(NTzrBd-x_Wr+uGj8&OElLj8qx1!$7RAb4k#iRPTJ4 zGuTcjZAYLy#WLZugmj34b<1yFj}W1NCre@W4GMfBn&>xDL9ujwEIArI-4feJ*bZmx z+HB>C#teKO@zCmE{XfyjDP}8ybCyrg_V9E`>OV`dXRnVu&tH&Il#ONj{!T=dCZM85 zCPWeAZ$PE;sg&{G7qEkk3uaBR! z?g9vel{>7;9T~91-el@rDa+O|xdLHla0P<8-tP44D><<8zm+8XpQ-9+phMKg#f#v- zxx6vppSrdVG6q5i!lqy0;-`I~G`~6v2v-QP*+)CY*eF*!%mb2q6Z4><{FM3mY$0~d zEFzmx&T;XDoU9Gkgm;!W&XaR~RIiOke1+MR$=Q6-(S4oGe-e3tedi(0U0(!O@oGe6 zLRK{uK}K2GB5ZZ@*&+p-v1HGe)=n`vua&D-vJlKm)5}| z^*~v^_mr;7v1y}^a5pve6Y#?ns@e)cQD0vOU}}A#riq^#c_UXR#HgrirZ?_u zjQlw_QHbT^$tURvZCzO%80UENIg=1uBJwxoGUT`Pf{VY&RTQ8g-6H>?nLwzU&F^yN z7r5MH#NLW8JWT57UDwzc)l5>ai7zaRpDFO+Q7sB0>*x&uUT@yX)blrmUg`h!e<49w zb0-_!-*j};T$r}2v+d1m<~Pk2CE{sgS&mkU^mv3mWruz!bWQhYBzJ2Du_(!MdKQD< zqI97H4(uln(-XPSvnQb1j=jWBk244q!d9kiZ-AdbN~s!{LGQ>qHzF1VXe$@_#TPb` z`{=#rPmgST#No@hEA~k)oKfNn|3ymZ`2w(W@f=8Ge0*{sRwDFcMcEzxoJIJs|AU8I zt)O^Pamp$+=BDa_%bRnd)SfYMOEZ#49)0}8`JdkA;?t-?n@#SbXAnQePt3}aTtDLM zrmRf-SO2*HYt>A8QQ*^1L1@6@!ByfyRe0`~@yh&;WYEhuuBQT3W(~JMnf394*%K4^ zo4EDlbDG&=7(Z*ROb7S?9LH~wHcJJ!z){Sjo`{y%2`|oMl-v%HdrKIYzcy| znT%TTz$K73=FNOHGn+@^K+krCdH5XqvUNm!VGT*5ug^%%dJac5B!M0w(<=0yW7jbZ zXIH@qz(T3`NP}#3r@WmUqsuBJ4n7C*LKF-i{)<$$-yXvrrk2qgiqW)N^JZ)fnl!H4 zjK1j7*qq@VXE6PSTQB5&y%k}}L6dgl7pg!M#+o3uW`LBCJLwA2&*EoBGTB2vbp=(Mq~E9i zPG$`;Y7i9at^*~2jv9ExMUl7UyP#;}i5UG|p)XFdm$>s+aG9CYRd2GTT~{(-dc@_U z%W%20_cEt%_*7z!goQjYnuoBpxaCEc-vdMDT|zG%P2>$)6xH50FNV&mv2$oT5;jWE z5?D7URL|yzq$4G&QFh!|B5Qls?LgE<2r4;_eQnx2&Tw%KdvRLz#TBz(E6%~nKkK8Z zu!GfGr&)E?LUjdJ^0ye9sf4Ppg^`?USQ30rQ>44bQZ*|vxO^6rX14l%T??luQc^`k z6RN(8R|v?&B+X6+DNT8+=c?b%@F1Ou+s0t-g^z4p4JsS)FDVBO%m;0i>$B z!drc^DDtGwS+VX@ig>E72sur?)wz*n&6Z6$iJP9tX>u;L|>hR)(~4VUWO6|mBChDf$uw3)Q78S-l$uCS{%->&mu`}G2lCEwnU=1q@e zyG7fy1QGiE1ghQzDwc=Vin5I(?re-?YeidTf&ir?g+?q_S8xj27BdTr&=f^VQcN2I zeiE?F+*KYqVvKL3P#4-GI?~Uw)3SRMeaE;Is@=_WRcBKzK5W1w1VUgNOh<_I*>z(J z%FlvvkCoq@mxy-*Wfy-r;IA$x;pP?=fgwnU6*(22v!juEJGXguSRrA?0G{7czJGj+ zgm1i0{>Ftjeq$g|Nk5X2_Zl~RXXSU^#qWI36;->cm3AMe6ol-}v+btv%cGIOT-Hg) zgU}Tr3G!$~Se{s2dHvg4^DuxPLo~_J+qBD_=GHi93u5a?(!u_A# z8wxm=KoJYt7Oa9LVR)m)>w0B3H@E4Pe#`teI704Wg?kk3_Yhdd#Cue(dz2UiT$*iI zX&WSuGfu_k#eq(@9Q)|x`Vc%QtT*`kV)gKwHRc*z_N##EYdFwrI zKNUbVQfwEMwoegn7m5`HV%23F4b98R@^zOv70Zd(Y1mwS${T~AO6d|04=iD zKWW%Mnf0f2`6mwgZ=yMm$0m1^c3g(U2NUX?Baft=Na$EZwE-wG%V?#voZwtCY)$R8 zP6(PNR~gcRW-*!EI`{qOlYGg{Z1u9Iz+l^pGyQ{pQ&6}YGW-#j)wE~O_}RyUZ+pG> zihfH=iqL5V4^8{%wg6Ua(_p979smakmx9jaCiwg*qCXXScmv`_l0py_NHB^ZV(@jO zw)xFXeoMW70#YZ0{3!r)fa|7vNXmNqO8!BKtSKbMZbaRqcL@@TJz zk#WZnvGqtBKcSsBKg$kn@33=k7+>OR=WX3i9#2+g5m;()m>zeeZpVYxlr6e?Rakgd*&W3mX>6^YKfu|%CSe~i((R8@nB4gA;h z80)3$in@Xg^$|N4Ivgt}n-`bocRw$SD|dc)->5nT!i)(_)Am-+ZYkjJ94+R;TR;<& zKWns%Tfy1Gsx9*PdxY*wI40y=(pXm!OjBVoXrQC5yt%x|F@2MREu464ll2J)U9iWn zZm<1L$QzTR+5luw2Xwo6`ISLYPqM-z4=1SVB?YF{$Bw3B3R2mx1EKaZGCX zyR`3|`7RCXG?X4w+eZM1r&m1tC3TO)-(7+E?uuzK-^D0{312d5_Q9BkZTBt-d7$M& zek&DpVGsUrd~0X!{Wm=uj!K92%hx^IrGh`je}$z(ugkx}cm_F!_wQVY;C$TtYpG$c zot@Nzl zPOx2nJZaO49R3M#6sQU@R+a>Bfk@8Ue>uNXB6eEeE$W)8=224FAPQ>XQKfWe&`Mu5E=f!uk`Bb~@^M6tekwm!r{jV0um~ z`Je*LW^Z*WJi;h{L4y9jLG{szvc_B@#Jn|&y>(U9&?fc-jX$Xl9P%FNRGk@JcadYP zYS>1!du8pRNRIYL3T#TyC&a2?jjndNs*U6@EgN=!E1d1sx^)1+@W>!J?vq2?AvPmh zYnrvi;TE|+%uCUL!!KZhgUZ*7;HlLM?#qvTvdL8A=FF4VtaYQ4x($$ncyZh~%`nWz z&k1>4s$3Ga7mG_=;u2#I0?uJFepFZFUgD_EStl!;|CY*TbLxm{`D~C6(5!+~XIE7s zWFW4w(z!F>@+-UiYG6-#5N_z1%$9tvL^)Mu@Iu{P zk4!t~ws^j#_h|nJklfzY-bEN_F4(y??;V^>O^}W)MS|H?rf`b+#YTGx55$9<7 zS#b^k3c?(5so$d^kiCxUB zo5rckCbdw+S)21a>Z5@phNdEY%@od|S(e6`0!LC^UK0!MD)5rr)aFg8k!fYwv}MVY z1z!Qf77$kf+f<;KA8ctCyh+v*`Muuc4qHci*JyhYTqon%OR?pZtGP$|~cSl*hUSvG-75xNa5XEidUlgY z>O~gdSzv4D3+6}F+)+?=Omuk?GEs&nv8tuLjj7zQ-n)O#K5O3Qt@~nInyq`D*jg_# z6tyIhTZNXlH<7L`)31MX*zL$o0uZT9WGu>C!T!A%(=dYrv0YQwXj3s};SGU{@FCGa zB`f5FE4n4q*wN+ZS-%zI-_+|D(gG9aJ9CK$u&&DUg|w|nbyKgMR=b~Q0;#y9KbGGi zzDvY|wW@zf+u9T#$lkVd@UQ)d9Hj3B9$Revv7x^sLr-3#@&F{N@*Z6Q9U3a$pXg1! z)e|_ji|2cJ0hM5RD|JiK`54ckOfjq1)G~Ztlc9jIECda=NR_MnAW80v#{xyHuShYU zu~IXZk}V>|Nk4Ux9kl45{`S|gGg*;$sObo=dyby_Af_cJcqGNmr(3qMxXF&o=XHBe z9zT2PXeV_C^|Rmu|4Yl(mV+%XluhA&5Ksal6F79NGI_lwd=uB!fUPFR8-oecdE)q) zQCuoKg%UfVqWWXWUZ<(lP>0FG(5Hs0AJ!U! z!lLG9nI{Yy-BPZ0)){pXv+NAfC$rT{T}jMr<-8Qa-3)KvaP^W%psLm93@rO&`tc1Q zhJO^+`Uhx(z$wuxwyh?`@ecAMGi9LQs04-&phH?o3B8A7Yg$9qfrbMT=YmqjV6QT~ zfKg(FCJz4HO1I$K7TBIPwNyUT9H@4CP59LhwzrDR$nray9~oKI4a_O02oa&P};%j7cS(HSC#Jy+rFxJb|UC??N&f94@5#izHxMx3kn z8nJ!Z)&zH5-*xo%4Ztr9QOH~hT8ab&p~5;H3C!iHGV#4Mf_f4HevRl?>FQ+K3bsd8 z&yglh(Z;C&RtzZ=rqIXCZ)ffi z81I5VTk`~KX1~?iZ#@PYvOTL~|Kyf-brhh+u>U=Prl>l8qBC;H?su1X^DFe-zb2)E zIs=vf?qhP8UWavuLd-ho@1OFp{Ngn0k{1Uycb7I@UiA$KUJazyK2h_ zwL_wWSLt2FdaMokWDot#-u5dzfFE)G32mKB=fatx-kdz2v$wD{B+NN_N_QL`X0^Sq zv>gW4zOR8Z*}hTQP9x1itV?j_b5n$_OV(rS>Ez9Yx(lC?>@Y1LPt$i`hsuFsc=6YP z&WWK;iz=ISbeh?OnpSQ@(@w^|s@>^mYh}1;Y;?5lbgj?1u=Y1rU-#$&#ro(jE2je8 zEJXOOy%5j)Rz;uKnpb6A*|4=1pwaoHc@|51b*EavbjmtIKRcuEwtufle6`L+Ikot>Xwfh}J2RsGT zK1$w7X&XfJUp|0$3>dQ=QkOj#=!8hK-L{&upd#BX`E{z&l?#_qpE zsfY{GF)_NUgaeuWsIOHkI2SH>&?({1|1(cYKRKbYtD_}+E!sZh3;ArWS zUvug}A@c7A<|&b1h+&vatZ9KLqC%{&Xu+0c*-(C-nzh!Rid(euWsBCOTJ?HZpt`e9 zz+_`T?}bHc4mV-UqNT#-{hv>|BQSI5_`u-;hp{{hJCVbA8Q9V9K62a>z^J-z)S_?k zC;9xz*b{a6v3#b`crPxXG7tbnsBa|(Q-v8Cn5!{?>4 z^8wyatlxD!vz#)q{~?O>~K$>81~FBw6F&}aH*?wI*9Mn1S7^(m0ICMgIt z@@TONn|k>amdCJB`M`A>me{PiV6B_WwlIen z#);Vhwp=q;&)pm9V?&2)#p=f~PWi$tHa1s;;gs4=mx>1qbf^#mz$*rs7W>d2o1dZx zG5!o?1gj+#9FP=(^T*VT;`tTLl2S5m^XIB;g2h&E<8-#cEZeYx0!g{v^sP$nz`SW0 z^eA}X($0flKcV6Td|&X@&v*Xe3=YOPWP%I-x%1u=+f`f&>Wlv@%+Tc^+Jx=_hQI(V z`U${DIv#SQ$#Vf6wjRx7H|}QL=pJq+HzE8D5im>)HbGVUT?Y(7s{=y;9+7pl;jx)^#lT!eYT`$BSImy1$LJBp>n^U@sf`6P z^2=t2pi%cj%PJ5K@Aj>DJaqWTiBmx{_?gPHICG9s$LA(=zsbB8Akb=+OqGRRh@bWx zWwzBLoaP2wZv~s7h%9l<$hSc=z=B8hEE%tJ7M)3bLh#$q6?$2KrX7SVqP2M~N=qA2;Bb18_F4Lt1;`Y|Nh3YVTd3|`sN<8$5Vo-{1fgo^-Rm9iF`no3q zWkP|M5Ml^Tx={snMKRbYq%u56;*iSt>V}hDeuDGZU!2YA$3n~sivYo@6@*e6z~K28 zaHC}zv3Fx(mvhm`w1Bhp+44e&QKPsh{KO6?H~b$9(@)TDDg|R{D9V;WUJjyb;$8`}Ko< z?&RLJrEuK?8t8$$?Iqj>i1l~rQB}#1EY!Uv?o-2aAB?+~g|#^eB0CPMuy$Gd6%@B2U$IWG%J9Eh>KR{OY6YEg}8wA+(XJ5Tb?@nWf~@OisudTU4uPD9^Bn9 zfl&liLC*2+_oZ#(wHpNH)0L=AscD2oG`d~^StcHADLhXpgc&Pz3jo7xf;L#Mwe3-X z{Vdqg>^{$>qR1twi0Xj}qOs~cryMMOR}3z1xt%J0o-bkTb2oZhE0R2irEQ^$h;r;S zsEz@}{`CsLg51Z;PNAyWP;B~I;}h^fcK;J(@D~b>$M^qPR7k;d%9`4Aa74^?kY$xX zD5-WzSS5t07M?X^5OGaIN|pliG+4=9eJtdV=QZgZ^iE$J<2A;=b-`Q%>~OfN%J_7U z+GbO^2??`RFHy039sZ1v0}2$y820&ftUsaG&mG;{4{6e)&Q%tZ@JymDu{TBxhX<7y zu_=ssr6gpCn-_ciD>y9Cg|S?v=XunA6ncV!N|D0ZE?^t=5F+8%B!|W8cdBsTyxTk6 zB|^+_Yc_Gw&WHJibpMr(s=X&VwXO1qGCWCfHXXXXm(QO)b@KSpPN02zAR&r1*SJuU z!lh7BXuiCx=JXtXt#I8CXnr;|a%+S3uMR&k8jTvFAc{o6(?`5u-C273xXKlCYAaw zdt2R&d2>?>bAu_rg}>?T3`l#1eg*`;yABu);5bI;*mo)q|AAGXlw5B=RLl+bfK-lL zr01y@KZD3%4RY=xtrL3zMsnKj$KpZ)TTCeYgD~hdmP2+d{#q8=(BeFs#>7QIIuqEz z&=}iW>Z7CW&V{ozBE-ciL8)JvZD@aMbkDD;xBz)Dl14O_RAyW23z?ddOd7~~gSaS@ z#f26b8JbJ#3uSRJLlze?TG4TFag-hv>%kSrK{xfkxaUj>)Yl(X>?`s0Ate35xUT2x zE{F?=+i6!K_u84gV+uS2ol=3XJKI|BU!Jd9b$Rd6x|5Amc^d9zXU`pe#{h)GtMnz9 z-=ZFIixrsSvKA3@l+bw&Ce^vt_&kS5L6QOFs#<{^zpLk=ilpv$ktaZ{WG<5`)G$|H zkyMipfb}(&&X1onrT-$sJbd}N0PcnV2&YhSaz#>ANd`Aqy1)C36!B3>5&k(jQg@>9 zOzWk++EwwCabr2-_@h~@u%!np!oB!fj`dAwD~DA02D-Py*s}8aj6?RFSX-5`#mqG! zZC?Q#Wv20Y6`zP?d?JRa2yGaPD?R3;ihCk#k|$Rk^%pjt#TcSn(%u8bKv(F=a@sC} z^OoI%6k>HD0jgSD&eKiVYNpCKsC6V!kagcIrJpD z+J9oznL27B&D0OM^Mx1~WvF@>sCM|OZy`DIU8aIQ#7y0wFA0hYR`KANV9jtqu$GD{ zAk~eGZ8{sAd4YRWv;N;g&rDaxC0}fr7<;I&wR~?*W9G37nb`-)CF(IN9UQT@0$!>o zR{D-(-u$vgU(thNQ3Wb>{KTm-=eMpdnEEni>H#`a&Gb%J&rD2K9GU2mFZR&bbgZf) zT6seHzG?VUlK0-Vh(TOAS^8nE75Eomi;tc3QzjFt8$;)#*cvcXz(ye`NI;<rOpu|%I2XM)#77VC3m?GGL_Z-5%V;1R$Oe&V1fqr zLeI{Jp8Pl}0p?v-Wj-?@4+#;4R-saKRo>0lNMr*o&`tO+;SDHx6hZpp!*>N9{xJ+A zzmTsOc`!6DC2QpOo|d{3nEane8A{jmB5`^#wn%nFl6vdH-_e7hFvGj1Arc*<{Jr-H z?Ees<)I6+Ytk^97P4E+PnO-7ON_8aIn`j5lF_-Z~M&P9H*1a$Aq>5xMt}OY<{rTq> zIW^++I}bZOPx!N%X!vXSCx;4u~CN%f;O6!0`V#=DHoRfRPK9u=n%amSPLQn zT&XPRzJ@!xQ?FN=!T3PGx1j&4-w^T^;~$tA@EC;-fo6$}j`|Mnb6J1NTFb5XuD_Ep zS1P%7_^S9zqkugryZ2fhBLKqm2(3Iog`Z=)OD>eg5B?uIfA?6h^Fy;;59;Pnu@`e`~i?X3jbH+ zo{p(+D8B$d3{ts3=iK9Tn2mwkudyGGu~X)kv6k|9%d&J!RUVXXhK0Op;~e2{u@Ky1 zjaPJGeonuLED79@qY5pO*AcU=61nB;!*3&sdazIryMPAzz{+1-g9rWq$v_i>47!z# zjfMi`>#P(~w4I^& zK0D~5N;&FB^Szo%Aaby;hxw9^Vx1QuA6lC?Iq&+oo3avNzH)2aFXMh5_t=3wuNCJ? zdS)iK@TqJ3dJ=4pt=w#S*H^Ds)#zCo^mCn=M*pm`TgIoY=^WWBj|Kk#(+^`3U(x#= z2czfKvYHtf-B5iOwRgN9&AR?v4qH2eff#{L8l2p~Gfj|)wT}}*pjDngL>$!rz^(X+XHpyV+ImFpP$JYq z5mQ%Zw@mmSdTqm*S$u2zz_}ePTs~ot*&!F5X>F&ymd&|Hs0rS$yi#!Ye_|?wrheqnT z>A%)j929pw_7eSy`-wMpX2j83-NYnEn`a|=M z9LU(TrU}u60vUf>Q?EIQPH1aEC)6rgSKAvHrxkve;MU?cSyJMbR$Hc|VC)hmLp7Ql zdy~SfW~d${q*vJ%b`D#s72D|FD_zCXz6`5EO=$IHz&ieYZ4NgJn$0sBEdN#X_3jqaM@l6`9ar>NL> zNe)5;DkO_SN|rCrBMR_$HIfSykfxaPFcvY@Qj=!sNVasQNF6f& z;i!@$8*)`q19$D4cY%>!*+vi9D0 zJ-5f~t7C27W0_<40e*cDCIA{#&Zqe$2C8{JKPa(?7gZ!;({;CI$-PPG3+g4+$W7cT z68Wrg|MjBwUOisMeLU!wROt(H5E*)n^)4-+^<(uxT0JZWeyskgns5`hibT{ja(H!3 zaL4#lY<9_(*lfCML4dkN2vny;(P!JIW9N~~+}NEZ@XUeCGt6AL<3cYM6c}`w>yqph zNb?0mx&LH=mt$!1m2s!wQ~Y&orgOR0-L^ISQa7;+rm1ItEU!Y2E;~#W8c{GSTz549rW!3 z{~zd}rLjt`)AM$$D%aZOTun}!KwYWYmBlmL^{K=0(SJNyD%b4YxR zq_;diH83@U&w>e9;48z}6L+gXZ!NE7DtevNf#-DflCefgY><+gB!uBlu8~qKrnrFR zQ+^7j*en2$+90JhNv4c|LmKCoNJb6je8$2VuP<-FE88YAALn=EObzPKJHqmeacp3mevuDOK`v+p=AEx)nbEUxI6Hb%RdCL?qW-+t z%5w6#N0SOYWj@581T{Us&b6Lg7jXZq(|)HHPau$uDEhwh+y5>jbi-X!$(wYbUYw6$ zTj#r&uvqTvz`>btM~<(37UHO$Vbf!6Niz)X(p-i=5_mJBv<*WXCag#wt=F=mHZuzEppL{SZ>tSoot+ba~t5pKqf z5tY>YtT5S&BqCB|$3NhS$WN&%hTm56VJe4ofA#&9SJ01Ljt)@8SBdvOk3WurCH{EcCt9!TJyVBzOp+TGcgxM66z?^QyDO!_y`8wFqp5 z*Idcea>+OBp-y9g66toxqZ|Q`W>|I&cnb6Fx7{wPI~=Or7H_=eVK%TvdXqBEf?Ham>tW)yt$-Q_LkJ%@|qd~EhqtJ!Q;mo^v$ul#IwZSc3y%d^ z!7>h-B+-#Q6?{z|eSl}Se|0B>GTBo%eYbs|$V%h4#32;#8zOrPW6INHw<0Wrv^|wv zM<33zn^?HEWvh|c$yFqhETx9U_BTCNyJJc3sPy7hfg73aZM$ba4D4v*BXa=M^mw zM{8Fj4Rd;6>82WiZx!Nqj$cqO=yz>OKec=7){BsyC!)eXDDNl1qWN*ezeZiw&u0G3t?5=RsiqefKLp;PSY=yWkIjGh)sF@};8T6cYErQw4DZ7mb9qJ^n zI-yg|cdPZxeq$99mLO@>57-LY$`{yb)T+kaHosceq~^MQut9Rttw!J4@MOJOT_qdo z#jT`qt8Kv1q>k%4L+>;OY)$I;v$Je;b54&nsEHnLwbiY}DU0NK^mMl^yv~*Y`yc1B z#!B1K6;;iZwr?tJU6m!sWK^+YS$IX=?r>coT$dlNlf!jCgzMVFb!WnL`@{PZKGq-R zzeyZODulQ2u6SGSitz60y6NFuRXAWnvPoxtHL`{q3Z3QoHdL}JzNCCbms~y9hmTb` zSD?~$QiTQ;7pltx)m`i8J7<5WMi#n4XLEZso;rGF^fD^O#m4>gBC16M`elVHlsEAX zs$W)7>HNXA%3J71treQad|UHM+gV^QP+f9(1zxoUYykW)pBp^dZfi!P^KB*JN(Cxd zJD~dTbX)m!o2lF|f(ZaVh74!<3gJ})707k}e0R&NW?1~>jNQGt~ zsf?>*!aAm8L3Ig3+f`LUo4$?(D2!}F9X6)2j04J)#}uT2z%uAmpzA7RjG#idd;}S& z=xR*R+JT8O3R4+JF|mMRq6C;oE)z#EvEWBcI2BANXaG7!@vy+=9K}PfV+;+NU(5T* z#Yqc4X2~0#W#!1Ry8@a6+u2Ht4%+`{Ik2FN3)=H#+&78L0>jyFDj}vgd&c(pHzi%W z4QB%ej01pFa>mwCq&ix$;%G^)w}|+Q7=XO2ypoQp1>vJG?k-|?C6{rBdFRm;7+W9f zn-5n)8`!nLfSx*g#$Y>4zj~NQMNGS41n`C;ZTRCA;pX1fBCexIjkZ-OFXKTP+_6Yg zCRS(=0Z$pfyW*?bjpY@U0H&+mP*qWRb~mkB!O$|La^?!K-lBw(T`Nk;d;LXm4MjTS zQ1uqY?{d(d1tiY1m1sO#+fG}1cDK#;%?jm$4$~F$(16wtc)oF6fidX{jQWlup3+wZ zw!~ygA>pryHCqZl{LitIday!_#!kAE5*-B8t}jI51<<~Th8c;|)Qv!mtH|ASjY3j2 z?6V)3d3E5TyQwe7JXIWVh%>KFw8}%%(L)y!NW9-?Nr|$?A$c2*Adv7xo=eZK5b3U? z3f+pcH>eO1w@Jmes>levXi`BwVnn8-=KVI1kC)g66<4p))Tp$IXwg=$Qe;_MNf@MN zoo)Nuu}vFF*C*Gg;)1Gpzbb+1^aHk_N=IdoD=Ce`Y4tUp<#&`U75yr`SCz=BlBhPA zv3U`YbJPIX=KEB}l{iP>%Lo6|rq>iY{0x)MfEqe&mCk)DoFyy53&P?3;V`8@`x45y z#(i`YH3n?XeU-SrF9Dffm+dz+PPgr2kwmp*zs@gf_RT3=Fi@?F3;~aQcSS8g6br)ZC;>^Qug&ibjZ5 zAWvmL$rq5u1-4(mMgjMh?$PNr8%h_EGVdaxAc%o<$9~US`Z| zT4-33&K#C(<&{XdO#7LV`7#c38a3fTTRBqu(yvx%l==~GAJ)iq_yjsBV9WI$_S5QG zffm$=i+LUIb~^E~Zjk@dbC+Pv=F-`fdC7OeK!$JCC^0r>Oz6GiS8V3Kqq@mMl$Rf!rbt2|49QlOTt;X;DZB#eyL(D7QK5V4Rwi%{ zvH?(Xuz+4gknb!NZvBJan#T&?Avh1-_0W4`TBW^^7d4|ih0=~Lc+4SGgFs`H zhgn}Lw4q2b29sGMcm2osKrr^E?Gz=ilB_hOwp3sJ|_g{((w!s=s1YTjCmfI26=!w?pg-kv^wIt zC~Kz{nX1&j1-E(T-_~qqyqQlRwn9nCiqaQi!s*9J7Tr3+#1v*xWGSVRW?K)wME-m$ zj={js;UAAQtKCzW(KyYasSHGcz$qkFZ>ZgG9FGW$`<3Hky!BZ?$A%g7Mx3$z-aJo8 zVA^yr_DKbRMJ@_p=w{}0O)l9yhalcH5{2#f#wONq87HoMU^4vx+KtBkOI?u+sskLU z3r$v9E1|XSbSen862wP6=g>zAPg;^wxrq!!0vKfzu0W0xZX83soEXM{ad8&?l}+tz zvZ~`Y!2)kPZE>XFBvuUsI=!1Mtj;0M{JQe|#zM6_`QscCnxcy&!ysVP-sQi6FPYIK z{0n@!6h0#Z4-1S-N7%dBOte#y7;`0OI>9AgfsI4rV%q3$02AUlVbF}=koA%Fhan#4 z^h{eKECQ+JG)^61Cs{$kodukVEsH}AI$h$Kwvn&Ac)xbXIM?Mzv{Q|YxhG^e5z>wf zsAW}H;aUv#bF!PGqb_99;T8htj?ACXFcECfGxF8WZJarhU zoFva)g+jk!q#D6f0!(RP%-gv8>P_lS4i8^2}2+w`C9U9|sX&nx;NL zX7ZBCm1$WJ=RRQ=|BNB+MMJW7KdU{!r;F(UtjgsTc1@q0qZy+*uwcPpL7mjclQJOf z5<=G2W;3Bdpf=xwpe*mzpc6nA$XE=D-tmDM6krc}AZ*-85Y@a-#q- z6HczIn^4b_C$^?E@a&Rj^|@0_JJh4^X_@RH?SA#l=d^F>RvNg_S?c*)HfLMfES^5W zfs~H9AV%OnJ|u_!PJQq>91qBmGt}eLeMYW@gJmt&3p;FESaA+R31bENQ91VvQWFw4 zlLci3L;ncDxKoagzL)9z>9*MHzN?tG=60Z$I~R$tt}= z%d9y!qfs{_k8>P6+D4eF9nEVlg>QIrr^*pfO%5O@NfPok2%pIIPh}#~`9y1)xpkGk zfMxb2HtrAG_Se0Um_98_-*#ROY)ch7WP689#?eO$2|p!I-F6&WJRP!mCuec6mMr~A zFBG7qH}tF{{EXGQg7=YY2W{=b+E+>OHH`J>7)A=jB%Ub5IgAJr;X?wuCxL#^4KbvV zJWFd|j>TvRX-^K79v3dkB0^8wbixICz+D{R9g$xA$6XrWy%EQWE1az|u2Ea41(7Q- z9!J)7V>a@30ETh}-;|btVzocawa6M1I)^a`W=g-@^YB%%g~mPN50NSg!^npN$(;MI zG6*Ril){LuHNoGqc$Ox8f!8;|{daYMWot7SQ@184On_{P|M-b<@$UTq01M_aNJEkx zElBEnGKX;AUxKd9!p=7(b1=p*7gm}}R>0L(I3<&V^y87#6Cy(SCbMqC2^h5Fy->o* z_Kq4MB`}^1#h*Zo$y%h(c}3PJIsAlnIn<^N?Uf6@1f}Ni+bKVQHm*Whhw>E4K9oZ! zXduYA=$lAmy|oxf{77R<5I~1$M~=(j$8m^AwB4RpWQl_zA7?=h84>n`j+U~><&P+( z{s!UsCVJ+_un?8xH%h(89}x_&Q9Y6M2+yoZKM zPsF*^9|gRKI0eAm7eA`Sz6D)3(gGuG0j;w|0X6GKP^GC%vtm_wWJU2~*CdvTh~CNaYI!=|HgtzqVKQ9gR6&U~h^=6Vv|2HTJ-2i$nz zZTOx{R|&u^bJg6J(FZ*a#cD*;FVm5PPJ{$OJu9@4VV3-Oj81&e)oox zU>X{bg4{=Nz2nOD$a>}L&uYONkKJt_yZZ#a%Wc&Hu=Muk=1T1W7P)0xg$W(P#7-f- zTgV92LTymR3gZ<`HRuY{d1$Eg`fh$I0+s@Q^MRXHC}EVtD8=BB8sS_37lZd%@JS0P zZiK%KldogV?RAK$Xl`#T*{m-e?}UY}Zg-zoYyQch)IC+)$x*A2k(2`_2`j$MjvDnMFtUvOi$@Br|#BENi0MM;Ibb@Scy>ZB&RjF9oV0XN!tfUNL?+aP>)uTYi4~yVY_dxcR>gP+lfOk9wOXPE@k z)I|IJ6t{84)nt+IC<~7Qy?en)4fVFL2jqE)(4D*IpM=>rd1$0#Ink$?mw0UsIYB=s zqGR=iK0fW+d~_}MCoNvHAXxN0L$yx%kj(5Vp3x9!E&W{7-$M4 zSK9k1+v`G*XwK_Q@Rn$#R4`NrDzQl=PtmXQ3FHTP`}cD7`Qa_`{_&cifoUpXeiiuD z)~)g7F5w3(mp8ctuZXiqxVj*xBJ}*X2RUe^ZS{ zXWg^QlPo)NN!?Nf*25VnL7Am1w1QQMN~v}?bjAYTEt#7&{Wk`*#jVq(`8ZY$ff=)l6K zPQdrLScm8=X5f1t+F--4`mE@TeknTVe<3=L;@ZazlpjC(?xs`Q!{l6)zrkx}{7aa?0=O+ZiitIupJNSjYX&q)jKu1;&8O_o5e0oolqKN=Etr3R z{EqB4YrQ-Pq@}u(-WPJGrXjcWs42x zGvI>(EID#mHd`;=i%bT1;A-~bN8SQFHEc#neKe4o;mszU#fCsyLT54Qyq6K3496hk zrTedprb`YYlt_{;ePs|&m<$+-Z&O@yLmy$y#2+pkklmL*!VpW)*6;@MPSmukU(8`q zqp6#bcI<#8?*ZCU(h@zNlcSe*yof6m^vd})oy82StL-qbZli6fPs&W#T31(De_Lkz z`p(-dFRvcvZ+R)916JS9br!4Gq-n?sa@#aaq+CoStlbxga*e1Jt zQQzHBZdI;>LIDHOaeGvm=`CFr}U_*EDd4rlmQ+WB=7dsh(mK6qU!wK;Er~}&%NuOLH87RL z8YED(99xBoBwn>BW8-4Kep-6KKX01ubWS2}nSx1!89@0_WjuER>s*hAI9ljeKK37K=Uf}o#`PC_8L^_2$(d~00@5Ru`VE?gV zkO$`iH)2aU@|uue&|_g@6r1@#vN1I6gvFa6yeo%3(uCfL!5gbPoZWJ1ND^G^G1yM1 zr9&|E)=55>>2@_3ts|}+#{FF^*M2T#;Bxw`V3O;07b55@{c%nw^* ztwLUhaAT+NZ{5Ny0M81!beDn2fjG&_KOMq`eWjQn{7H`dO%r)LR!b$|*yL**$KY_L z4xLp=t;F-GkjyiM5zesX*8ye9)T0g8ClY=2HB`{<2!?Gy$&@cUf-X*zCStl+p@`w8AGm%`4-$EtM6 zRB1FxMm!8O6fr+OJWW_DM-FNtdt zyQJpQo(af4p6)~sY_K13g^r`La|X6;AxS7PotW?56RUke4m90}*TiE4N-VKe-T%xr zj%LJ`=ewq%6!jknA_m743?=L=6a-kA5s+Fh>jZsYE)9dmVoG$ZP=yqO?a<oWbjS$gkm>6agR`M5yZEWf~+9#KV}j%kWy z_tUZ3xfDTyL0+CDuRhxLgIv>ksdURf;EXr70h_bS-wFwGWVge z2Wj^<3CMg5-Yb6pzF+4GS=XJO?lukNQgorYw%mtvr(~rRFic)DMoHo3Kva^6Gb6GP`)g9hbKPzmERU?Iju$_2jOokg(k7104mlOR@EgV?)>v&a#VY@ko_`D1m8t;pL= zLiB1O38;TUt38Nn$$F|o+t%r6iCHsTzrCF6>d0qMo9jS~0^(>Xk7x(lzKdP`8C{1p zh?h)$LE?2A57GHwQ|+83gc2Ol1O+c_Di4#8pF+1Xq%-Vhyn~C z7gVfR6tHI4*Tj?_+Vf96v@#a@=L?neg6GD|S9LZiBxrL$okg*|gkt-81=}^Q`(mE^ zVpjnGJi9OUx7Fhs+CYcm`4p>5nN|{`+PGNar={mh#nZfIy=c}#RB!g1tu9k(YPiAp z@}$e_GCGTx-Mdar+~NxIy6{%xv+Ftv$;NkRXS56#y4?4C)Hc#Jc`*ze_s^Byd5HFo zG%|j!^hpK!WVjFrmR|V9Rq)M9Iwg{RdR<46gP5xv;5xNp<5QTvB0nub6pN>Y?u-@q zV+?4Lpbj0eqIO3N;dl#jDV(8_nC1q05P3rr1Snv7Gu!O+Lat}?6lUl2!|q#SwK=%( zCHMm@oDj)Cv@w+W349KB7G@+sxL@lAYu~FqIsu|G*V-Zr+qswB2 z#xl>&RF0b)gA(Zq(dPDgAfHG!3=Z>F=I{dnZ@z?m3cAVQ&?f{^CUnkA=)4>I6e>FKwGVmTA6ld# z9}MAL;cMC66eS~M8W&^Lnc41!T#%G(r>+WxwHw}9T(?jvq+Xq=Fs&ow7jDb}-%|@-v{W&DuW&Fi& zpe8DuVfs*GNqw+vWf|1@CU2z66f#O$?C9)O(a?4D`!hAUlP*v1oPz`>mqlHtLjJ6i z?CSpekQc_$wgV>e%tb-$4n)B+=)L2lT`Q4K3j?3_C&|9{~Z`;+xlg@dT zKzgz;d5||;6zD7GlURv~2rhO&N zn>@ltpE8n$0#xDUc3U|s0PbzJKm|qS}(S%ZC*Z@=4trqH8 z9=S2LO>(Dz?KO1><2sQ!iAvVfD9`IL4q9=w-^#Sd3<-3hZ2kt#nBmG=HHCO$hhDkxe@^2w^Q|>!A~o!c6Ga{vbA= zyhV4K*GNq2QsP|rq_^0zGj*0Eq>5&?{DwNQm3K}LI}Ylw%X)#1SL^9qg1ffqQ2B-n z#oUxUb>!#$6-0L$R=xza+-zy_TpFMRLbH^dOQSx7SQac`vH(({&GdDA?y_7};1yd! zzUldR*R}!V<{K9*wgjEfTbdkZDyfQ=6X2ptKq8zf1-+! zc$=veoEXG%TsPL@(mn}u73{9(pFhl%`v z^Z?`vS<8@KECUDXp}l^&0H3$tHekiYJHRG!i$u~(uQ||w42bB_rozwxr~`+h6of3_%jktR=#FV5le``yQf5uPISB{v!afIBf;&-^}-i&=oA-vZ@88N zOkNPKW3W)%3(>jPmveK9k$V>%cpW~#3fG$9u}<-+Go`2$Ql@kNFkC2jF7=;Fy&DuD zmn__|z$9{hAt$>z{SoX2gT5TCDK2to7%m!MZ3t!m=NO%0RXuzV`P}xGghO)Z7#C?B zMv!%p)xlb`q|81oZTvQ`@V3ky<+zsN0;;$QH4hh@p;%M)%DNFCL+6GIjrNc4uOK(? zND%hQ-1{8&*WrQ>Wk?MbE*?7|E)bcMeV7$;u55YtKJknr-Bzpyc4on^*AO|)(o~1* z7~ut(dza(h9EPJaE2yw@*3>humkYJevu%ICPBjND^oR9J(h`tv(cQ+mUmpgM^7FZ_ zCH;XL(!mi0@!7SosI3AEuMNJ_Wm=fRy*ga*7dh7mIxPxtyJWoij95Gs+;Y6QCAcNd zaaU^K-FpBA`Harv2U#lt^`v)AwHQ+nqj;)ispU7)q0C5Lf2lXEj8Z$gC!@Q&Li=3I zUOrzTi1g{-SVhOdObpW-3Q*fvU9R5^+J8R?0R|ndBA-hKY`{@0@lz?`bml&lK0WU# z5og#Nn+xmP52gP!ul~n#uNZGHr?eyVfp4SxT!N2aS>8zFebZoIB(B6yXNhy@&I${ff+! zdv3VxRyk{{lH@-~<3 zy4Z)LnfXj)%W%O>6pHM&k#XduqLaN#()7Y)Ir0J***siu1MVw=6dlIZ5qspou&Mr2 zVVoSdhxDUE)mduLood!=;w7U}M z^U8eSEr+yd`=MZ$GEzh9PJmrR)Xs^#-t~GPdT$*aS-)MdY6W?{4`X*rTKm!pt-r0y zv^kl7X64p#!sjxS+zt86DTcSMPa`s|u}u&1qZaQ&_~xk&!GQf1qpPwm({hhP9e!T%i>6XZvZ@ab{ z!&?noBd63sekz(pckZi}jssH$^a#(%5H+4+$m_I~wGpf>kk_^wrZ|Nd*v&?C3Avq; zV)A^SWG3QNtrZbJyGoOFxv8ZGwc;VjKi2fj#l$A_sOmE+6$vzX8p)?G6$!;EDGXT$ zTO>dqge#^R&h_idMRxJfaci>YoD307e_xw{ac%6ArV@6l)?sG7YU7@iK$@QG?sL`l z6{hMcE6iD@vg0`ncIfTF<<)(w#_^`5;{*h_3NNN%3rRNp8at-suVbb-F>ZzT5uu1T zuu>`!=>rf5L)8lPPnvQT8GAj0o{x^(D8}Xk7^8)LgVUbThwY-LV!*X@V1)OU?qkF` z44K$xFYkl<8YAAWv6Qg2W=80iA4Sw!*oXLUP9TdZHu<>fg?%q4_3awJHKG0%U5&0J zFkTdP$s>c&Rnn(RMb7MHj{MAx4P|WLRXFLjn?mU@|8q}@xeEKBh|4b#PUeFWiDFc2 zT}(cu!e7rsdc~W$-gp1N%HB9EUF|pEm4~@8RWoD1vCos+hlQ~$4dF{Dsmzoh7*Ew% zgBu+ctmQRCt)s>ekE5LrP+fU@rgI&R4fqx8w5d>=e?;3rKI^4B9VeOEXSWWBOo?RB z97qoQbY_l<|0z{men6ES-}#X$0EQCed%2KV(`!M52}ZbPU{oi5h*mTT97*m&4W|6z z3WN0#QxlRW1zx{#RkCFUXStaTEG(*L5-bxsJaLqqxf67K_JjevZ0a5oPRh{2E@%6o zcLjnIXq|0vFn?z}9%AW38$0Yny}}2wBSk~h^tR`6ziX(!x{rp5F4N5AAPQ%|clGxR z7kkk}DOqDpjw8BmW#8$#&~NYR_kG)|Lt;DF`FTsR@K7ABW2ZQ`0XHN4Pda-=#^zw+ zN;~3AJK{t$seYyxxDAH6_I%DYjEMH&{$4)azx_=Arj5M~_cQ*v=soRfT^Z{y(F9&q z^K&9Q`-GGIgHx)T-N7fq{!~$TH$$6zO^@BO~nZ2&VGWm+053bpC zp@$#8{9+GShCyuuuiKXqxDiqd_h%IEfg*GF&r^?m+ar9{!-ffD8{H2wf_Z?O%5{$@ zcux!uLO?-Rl};hGTS!xgD)rJR0Unp3j9AJ+(1nc@#a>Oq73{62*qfz?SqYg+VS(Zo zX6?MbqnJ6hhFqf{G~bupYd_J;YII&rrd6eEY`q1UB~#aCsT2g?PZ1o7qX?eJX&|2J z9H8QQt#9T4;U>K$f?d!of-=&%2T+Gomjt(*HG?1&38-81@1 zYp9*b`*H|}9sM{wB1dp2(!p+vuH)zq!qt8t2lJV>W7y;NbA*Gq0XWma#w8(vVN&s%hTo^OQ=Aj< zI}yc8vjiNd!B5*z%cq{V8$^8AM6H3xlU+U607aX(Fv% z3jHHm8wXl4zkONc+bD=W{uBll8>2Kwi!Nfo-byFzOihe@6Fqzpae;N8CsWTN{-e{_ z45eW+v?Q&7`#L(ZnGF~oMzxNX`69%r;p~<5$de`sCFtR4?81dH9@cIlYTyWxbS~6BnA;_ZDkC zz3m^+JLz3}Wb!?I1W8*?yLOL`JMNRH20Kz~pP5A*YQ3oomJ4_mfd)Fqp4~2!&*+K! zWK{D8%;d4l!OEZ2!l<6Ko_4g@*kT(uzR!AEVpG3+JXG4JeBfyrB8p@5HS1|!Jxf1V z#5zOXrxzfpI1P6Q9=5`2FWlNi_UNp-v-cX89y=nIOb^2*u$4Zx?%1jp>*?RFTqmv? zw^|pn;0x(z>e*ZX5PqiU{XR)o|2ZT=W^yX_bxt-7&ZYGS<2S z-J@$=_a(a4#f1*iA$?rU9g2>wbykdDF^r*k7V8_-5%1cmLIUn*2cvCqOv{&-AaIa) z9qcqqdl-y@AY=l8ZBIm6qLfN?$&nA#TuXE$!Y{Q4Wpo)eu*JcuH9mghYWLgG0!5TE zB3H%2=>95d@-mUPq6OX1oipdAT)+7h7#tDFto1X-jbE0j1CjWRj|5V<(Eexv!YYol z%|P4ZBKx8=%Nwju-;CCNA!A3wBp;JuHsSCg`!*x`NS2Ug&vIpXkTkr-Or}yaz;dcs zMFe_?05Hn_G+iWjQrtq=z`~HBwWr<5y&BbM#-`RRfXaOu#nd7@Q{&yQL}BTWe2nP3 zOlP@(VRCkxSD3|8Yl@!q6_{c{->fBR_eC0`1vFC_<8F*1W+VxMrVhXEC88=ps`qpYAt3!s8-$x+}{Cg0U;Afe#62c8k+~Pd^Ftqn+(R?!{=q z-{|YXF~FaJwMM;fR`8wUriH!S3(*3_Jlr9uB!Ptl~-QO=2p1^+R0d=i`B|@KaKq9d0bU?JR=uE{|0$9MD83;y}}H?aD(5q*6XTI7ag8L z$yJpxr&#UIBawfP7VMI_=c33Z3Ft!GqP5S{157e#$ zFxyl5iH)|bv`NFK0Aacs-;4qkv&C4tRF5E}@eRHi87z?NKSr7u#^2V{bmVyH{%=L! z&w$fF)8ZTr6nsT40$n$Kjm^=#>~FYrNpb_5o5G+;qTm-c*K zZZSJrcqkeaAl!S$fH*f^ub7u?iq6qyu?3IH?hR4RJ#yr?(b~HyZrs0(7Tk&b+g0=Z z7f#>;^F478^S$}v=zQ<*E>xGL!R-&z{b@B9x-#8?-O;&DzVC)05?uXUW4j;B>*LW; zHkNxl`rom!k(Z(yC3j5}>=fp$YhT}tslw(j2szX3HIo@>3A|c3)tzUsc5ol|a*stv z*;w~)q9Z<^#h^3uQ5K^p@WZYh`C|-pH4KBNCb_g7ID<=Y;YH8yM;kKtbGT@(I$nJc z!7Gt2nAh%1Tkd@yUHEzW6G+cR(NeX_zPjZX2L&H@qwOl)&EEQlc@B1XAO<3%zBNsH8C~P51X49uGm>s5bxf$-K$Jk)bPs z0)+(rQ!bLgq0bQL&T*?E@%*LAd#l0j=?m@X9j(N~MqTg8E%$a?AH#n9RtAeKPvR*I z@RfcH35|)CoL3e<-I5qV6T?E0O?S&oFuvMUazBrgtMpY^#|#{vun~-zu%wjmmS5(%P@cbH2q9`8lP5rVh@!rpWHn^m!g03VqV+ zn%M17XTtn2KeN`r1R`)3?`4bWWRo6HLD$Xwz86Nd);09i8nx?V07C7JfmVA$H`z-+ zVqIg`b-Uma*htS>so^+ceZzSJj~dF9vHj``y3@Fa(2*lOoZ*XJ1n;Zxy=~Y6{se9Q zIm)dgZ6Dd{VdqCKU3{PY*nq6T$YagI*e)R-LHk8#T!L7doZ#gl7-UOB@qtFp-+b28 z7l-B8R2LUu(hP!Gq3hhIpfKbbrRA(H)G24Q+Rt2ceJPV_3atH;i&>ABdbPrnbzzq#^Ey@F_TsF1xO*q_oa=I+W3s8^`gX4qZRiweEpxre?cV6q%J1jdF(0wQp9+h9YAd9 zalE1W$=*#*_HKW&_oXvizh6Jh&Qn=lyE)L-n8AV(CAZU0>)Cye=FZHzZfDBRg+EF& z#Iig?+c+lhS{hl`>sr@4_e|XP%b)07J*-FEB+Uhx)b>_~de@(+9h6-!%JmsKtPROq ze+OQ6_SLnWOJQsODhnH=84WCAx91r&e}%!_k0{~uc{VpYj}hk?i)N0X#qm#Q`3XHM z%%1xo;=nVYij-zIJA8WN!x)JV@KZ2oS3)k^X7LvFvx!YauaPe{3aOCM{8FneNngxid$JbCG=>i4!74(OhyaWiFyA z=!|$RPy)YV_;&@$^}GSfr;r$JQ&if4Woq7BfM|eKH?d(A>(hF}*@eeg7oWZuDuboR z7Gg_s4Q1Ed*F+VUN``(Q;#R7kb)W&691SB?x+g_7r)d)d=Fuu`7F3Ckvp$U^=(8hZ zRgMcyjKUp;n;6A@3~z)cM5#|K2of`oI9&Q7dt|oK{2LB9bVfw{GJ`1y7}UIhLTb)p z!wl;KOY&2HIJ*qMCMxXP>SIgN#zj)2wQtHHh#KCY6>_OjgfqqgG+Dr}`^G31yq#c3 zlcQ~o$m)x_8OWzc>c%(5K=&)yPy=q(l>|)iCl&r0FN?kCh9?xL6Tn7FSt2>e?9ac(E0*(7uE(b_)% zI1p0TFyxik)8~8OP3^nf#gE9qyagWc;Z;~?M`d?CUH0xS7R{MLv`r~t$>^M3|)K7uPxon2(J!A^y)}#h}r|2wURj=BDCB(OA{9w9;*F8zBxt5 z4G$H3N8h8WxAJ&zdEBDLMa|shp*F=+4kQ%Isvl7%5Mxas&0TW|z?y3eBqs>Z4RAU& zH#kHYmxn_GLj?v@!_*vvGTT%%&Nmvu07eh4m}N?+H|zP3RV#ihqQxn1P3t}B|T8~z7P6l4+@ z17VbPknbooq;AAz8~dd!V-}PYU}?xFvzh_#FS;O;gky0aB|*4(Ak>Xa-b0#H%z(x1 zmE0FY1xDIR{~-c#q~ABel%|I80CS_r?$$+Dk?K3U&W$tIK)`8y;`#BL=aYJ2LiT&< zZ(u!d@=bVg!nnxa73}_fh!s+=c=KXMZiE;EwII#~r>2t(0AQYRr-!ha8l68n?$e<* z8nBXqQMx1$KRCZiD4?pmkb2DMw*n6PlV z&i&y~K?i*m7Z)~?gz1~ta_0^%U{ucKle%mY0EiZ{Y6ygtGh@U#qDyW z{X-B5{E-dx$~+DVr@N`!n)}FyICq~`MUD(1kUGO?%ReP+FT#jO*esKjo0?%kcx0$; zFa4_f$WU#QybFCu?dktI7^>KJO92jcTGUV_DiHXA)qayDY`nmU1?)^gw z&9S5zfZt+jypRP6x7vkUN|={1H+INxF^CXn;DEl0b`K= zG+5ZGqxL1b|3P8b1`6yOySFp14LW960Fgo@DL+Se)i=KRmxc2}@=FnTJ z$ey7BXlY=YtM7$kC-mo`S}I6f1ON3e(Z5GgdQc9ajL_{p-6V7Yv(nWsTT-T4SyM;6 zCE4O_9X9<;7m!k*dE@q}LeXQ~rDGa+N3xNdR6mk%KV1Ax@dDzMj)Uwn^s34|>Da~w zZql(p@^LrUVe$UW_sa{|QfV01{TEDJv@kWi%=oMP8jOPR7%|2>A+OwLfZ!gU&w;cK$k^N*78lN*PKe%2Oz26ccE99q86x93P_BaIUNc zRbopeCIR-Y5;dYpp93R4Dr~`^D}y+6zV1j(}lYNPoJ6uAi z9C;r0|3jE>r%U|8B(O!(OzBj?vP0#5YDh8KLmUrxgDUjoP#ayDs218gK2kRXaTJ<= z1e#vNcX*GEV4j5~!I=)7-DHkWUuHTPhrZ5M*9ep9TPkP8rLU{;O^P%!=df16VemPX z`}acyAIpJOk|44zl}+Jn*d?M--WKy6UdhcgsHg{%Z_?`%69o9hJ*#qW7%FIokijX1 z%}8mpN2%#GIkZI;SwGZf$C+H+r!6KnkK*{C-k%`QajZ4 zhAg}!N1jq~IHvr~h)fPHKzoL^7{7~yyvvZW{qM82*P5DyNpxL2s!gX}agj}`NX?LD zx9qMNs@+9VAck}8XMS)!Ba>g#xq|rq%GAjvk1Nw!7|*tt zVKTy2Tkc3`yIMlFT5G$A4(W!wimmA`+i%3)b6cgiZF37o2Q`s^UM<~Ka`PoMB{K$u z`~N<7z;yTb`~3ZQnS0JX@8>+vdCv28YMY!}lGeH(^FHV(h8u_|e>OzLBkj%ST&p$q z5EYiYRpU(0K?e7$bA`V==MFIaP?vzw;=wlHTeiugyZlcYLd$!N(VQDPQ3mES@D&CF z&Mx*Y&A;>`2>1L3;Zb13$Y~u%Eom%9)T!)7VYDTR21OkO)hFzRv-J)%B|!TKo6;XR z_$0}_4#o-5*qR1*q{%`>FPI>N7{7qu3(m`!kMR}E5L!&=5Ua)iYXhyB#aHik_!8Rs zEq2~Aeh+0`*5wW)u=eIs*Re(iv}2y zdIJHJBc!&2E0CDSCfG7$W};TqRUt-(yz?^6IHY6k;KS=_#de5cjw4jcF3~sgnLprF zZZ-NhkGCd`A3oYTY0B{7)|}giC!~K8XDx#@)7-twh8swJzY>=0N!~mz?tB4c`0x{? zdk2C)oQz?hdv~B8=sW0Fc-?m%-XZ__1A8xOdy2JD|#dMWh*t--QSl<1ry`<7@r5iTKS#crqUHn{^rK5*8#l(-x8qKa2z6 zR6)cAh^KbOtb{)dekeP13)Fioe0!4yTe#xuV8UG#O3vepX2!OAy;d&`HSlZY(ee2Xveh;Kot zS%xuTtjMz?Bw)w#FH>SI*ZE&IRHtzGSLR6Ccb(~p#(l0bZkFdrA3R9m-?7(kDRbNH z0SzSuCq4-$9dJ=6diJN8k}hX{d7| zgG}=1Nf$U9?(D*6v|_;=x?^Fvueq=2mwD(b^Q(|}+c#?BWOhG^W{W!VOi!dNDSC3I zzpc+Gu{go_nugoa*l}t&T(;K+SYv%-Re+P%Xo0n>)~fz_263p!$<>zNnsF?B(x~)jlU*}F z=(3tOI$crVI0;^t5SnJlT5NtjeaL*XS+3aKZ{C}dKB=H=#jPTNVDCu^3Tlz~gGDV%ikI)#LN^&a<9b7HeQ5klljmx}O@`)= z35DB#s#(^tVy)B7@!%O6pcOWabA$3qTj;uui0|pKC!W6EvTk8}aeK<9^_5YTOG?%+ ze;qDq%Z3|iS>YzLS4#b?L=t-UM-H$uZr_Wj?UTqj0x=Ng$u8*;9*fMfH%MN36@ z#^UC;wY+vw7*dLR^-4Uez_4AH3p~7TO}X`*^enzv;-0yV5N%5R%j=4!eg*%iq|jr1H5xXYl6t1D7VuDQ$k_9fsNJdV=0|u zEG5n4DvJ}uO$+`Ik6VWlSn8D$9Gt0W)p6*P;dHPbx+pWti`!MRmOebO-1@E0%ne!g zc-ex6A%xAz%YnIi@3w``F?ggCHnya z?+g9@(S}e=ujfx6=02!FHKX4@$^iRF4%GUEeqQ1fS?F|fWzSAVi^y_@@zfsI>3&hj zijrUJ_s(D`lN6p!je=*f#WimEc)w@3fpzwqIINQKnFgr(E>7WGNBU!;nhP}8OUp<4 z-2vXqGq0QLbTjsh8wHxXnEY8kEC%t3)ly7Nhp+Wgk-1&|xZjgtFuGyK+rP54UyK$< zZCPBA$Er_j(bM_n1Z~>(7Xiuf8uT}FWC%*qyH70+mcV@&L{TOIRa zb5Cga&i$nE_U$7TTNJA0luFM?{rhx$KlMa&Q$L&y@xlm$QFoUKtazfq0@viZhCn^N;8y7Sgf~`~_&ZzSr^v|F1g8G5;_Z{tWj&-XZ+@s)NZox_y#- z8yK($pI6_|b2UE+-DV#W}*}(06hSlwdk45Mrf*ej+bG!0c z^}n?k19TQ@-KY`)&{%m~?okcY4&51W$`zA%mfv2reg0I&9-z%7H6glov?z+W{#%^H zz9m!658{DU%9NPt_2Ux?z%v`pS-*>ZedzS3qbJ8U9!dP7t>a)DY@+fFh|DkjF>-%% z6z2$(M8E!lJ5UxqdCx%Fm$A#5Sceme1t}osQj>JOnelb&2K^EaIJo3yFCu#2=ze$u zIHiWmW9&8V<$O)_;oZ0o4D9@*EZk=pHXPDPsgr7V`2ac97afF?#`Al3d^Ua4-kUq7 zCT6hdQMcC(4@R?;AG|GV%n!u*T3#|667(5e0CuFyOiA>Q1gdb&qLbPXiLnT-uUWA(h;fp zOD#2CZ&LFI8dn3_>Kb|JbyOEffF2F<(xs;(@=`d{+t~qs5xaR$L(df(#{{f*vX6}9 zSLh0c7|225s07@fhQ&~`M96593YJ#$oM(L7JRVAPUN=MOT_|0hN2TjtW`*r2-SZFL zzkRTD7wADKZ2&U`)hM1Mpt@Jx4Z`*wNRX7KG_du-8k@QSEVhoG8n^$Ip6XbRmvKmw zzjj`y1SF7o%udHI`&sg%WM0K!q&K52Lx!qQ=*6ChuVy&Q;Lu$W=MiB>o8(+N6Py@{ zy_SW1UYR$)$*Ij+FqaA2dLTjaJl8{)!vI3z^H1k3&)|gfS|RQvj|kU5KB7RPmD?iU zak&3ZQ*m4GAn%#JZ^oEEhX-pGr?8+3L&&Iu256DJPt|UR%sy2KXyezLpfeYGmG1s^ zTN$0#zSI0$Fi`$ia7Dzxy)TUsdOoN!pqx3;mCbln8{qFS2 zbEhHo5diRWaK{!<$V<~Vi!W|53D5LYU(zrNp{ILr4Gvx+IMQ6pIecs;KSv3z8F>Zi zL5a~9;GAg^62&mrq0{W}>6ThBF&^anwLNfFTQru3w>bCK2G&e1kUu$%*>in(8ahUf z9Gpmn^*z{4vJ82Au>!{UV8MrNW1VRe$2!;J!I?@o22yxccBtc89tqX-RO_0f7zDBc zdX&Zq@9sdQR~`pN24C~jB{xgtD05usRn6QGlTu+`5K|?O1G7s!^vuYip*1~0SwX?P zEJyrujD)il_tr1i7HXvg2i{)JQ{B`2y=Fh6fu`M}Y~h99jD&AG@H*%>o2k#976o_H zZ&GsLh^FvU$Sf|lbl_TVSt4a~{~4|NYpvq1y~~oG-mvj>Re(X&(zCJ$Qe-f{+*`X? z71aa_RH3pbBGg%f^W4*$U>}9G@Hae-c=qAhg{KYAc|1D+UsZvlm5GfVs-sh#)TK^V z)SG!VGpO33;)NNFJ^~H$a1<<@K(+KnTu^ z6Mor~`x;l6pcM}<8~!u%u!&WHN8p)Fol^d@tXladF)A*`9G*}wPs!o}+ZxSxOlaV& zL4y_U`r)3vai4w1-|Tx|O>W6?s5b#IPK}ynuoyD97=sb)1^Fgt!78tM(=0B|P!#BG z-U6#ipE{*NzUg4Jd4bZ^`XtQn7{7RW(K$WWEA**Haf?<=V`UC==Gg@m zg;&F)EOOQl~BBlNPU^7-;lej@NHK<&@81r(Xe@@5ki*G#qYf8OppyYD+E4m?cFBKE%%@c#g zJVakSMIHAp&Mf+!-kVP=EF-m<(oR>n-zJ=i80Y4>|3Xb zF}x_|8X(u0Qc%!XkiY662kow+T}RsYo;nshC0_5plaK}e5!Wccht{w0!MLDo?~omx z@}w>q1pZN8&LoiL)hQr`v3{!-gf_=C$TvlA;d523=-m!jV2NT-oze^)AqZxGUx4B& z!6XGQQBlF3V-OeT_82oT34kSu&6|QbSDG>%fh2ZcIznHknUFo8LFq{*A*%6 zhRPMVeu_FKo8dO5x!5|ykD|vWZ%Sais|0BYdrj_X*0t^YlX|KTYst@pw}VF?)1weV zV#g*Ke1^<7CBvZH-eVL=3ZF8Gob*3s_uSiKlCuhH+R_t-!0WMaD=*yGgC&5};7(dY z_a=+N#GU~PjrvE;5$?33IV##eME1NysZcyQNTJokVJ_QKtHPggXszsJ%^8JLU32X4cw(lC6W+Z66*?3l<-)r=~ zg92zvkR@mXZlF%XhbH@w8jO<;&qG0scXR$FZMYGFEAP@kS(VKm1-9btoF~4=_2Eg; zpnh;tH*cI81>NDD+5Pp=+}~1Wu6%o%BB*Wf9|`Z7BA2%k#endPCHgRhhy7k?G!MS7 zvUiW;#kN@-d!4Erph%xayPm_-h-dT71m|Q_42xn|G(rGw>Z!ht!#^8?(ramCqOeyk zU@E<{eE0)p4lcD!F@=Pl=3$hStWZvC{$YG5st2v4sdc&o5=?1zqT>w^9o`W0sy2U` z29jfMqPaHFy1z=c@uUI!M#@W|Kk8N6Gb2Sm_7L3!S*JdlO2A*op0+zcIHkg$!+EW`-;Z6IpPkN1g14~}Px=&Zid(ubziEGPUN*M{{+FY#?y zi!BZEUp0Re@BcoGg9v~_V&B|^9R6F|AmoRDgy%!wg^ewm{40%l^$CAWvp+}1N*+D* zsAhj}vCb99r|{N-lfXlFaMkZ?p7UX7`k+~%Z^O+b+2uUnhO6Jf8S}g=Dzf%KFCW)b z)^`oPjPD?BL#M-6bSiLXE#^29@42-Neoo}S^oa#AivMI7osqjWPdD?Q3jYYR$C2K# zH9?2hN=3bmSDir8tdqJ%z`97+%}r#f)MmE-vV$WPjWXz8{5zbRil%aP!0KeaD?CZV z1pI)1kr>*XR=2fuU0qHrm4g~;QpEJg<8W9M);q*4Zd9f7zhFY>t-4m!-PraN7@a^-wDi#b<X*x#lerADw;#C=%yZk^i((#E>47R z5Tk_?_Jo_8H8I!c+7ISRRlxe>GcxU)?JOmeCLnm+0TS|5I4cp2%9S{wDct;bpfcXI zua5ULhO6Nz6X5iIIQLC@vGQyU5lyZcm%&x8f%a^Pu>^Cl9W$68|PTLVK~n02WO& zZ9aLj`D^%53PU4YcsFd^rkD8laC3lOvg|JmyZ-CDQys4T=n))4m|SMAyA0a(|I|Ex z3s*m*r+zz}OXd~?d*dQ&D~I!Zsj154YhaIif%dsdC9nfaEU0F5s1rKX8?c;s)xw5R zV_1JLZKw$*e?u6$jrix;*e1c>cvsZ1;>#7{P@fp@g>8r^Hi%L0uzFE=Ik8qWZjr0R z=(TqEVwmbu#26s_j6xLac@-ca`FG*4o*nOg?vu|&Hkr`#!MGw@um6>BP|oO(Cv=iS zhaJ3Z8HA6Z%77v~(H{;`;0-ucYTOta`5`Vu6(z1kg3tk1o8c5Zuz_3kJ~<&NRn$aY zO-hg@c62gzd;Hn`3Ugw!423nYEL8i~QbDp?PDF-5&V?t?jsy8l z77746MHEtLOk)zaccdrXoUSB7n-rdBMLttnHQ-Uhypi`@Y*kb~bh*_eOHu++0GG7w z!$MuHM*RR@_noJ=l{gJhw!4IsTu5sL?!)Qa^L=YBku#jXztu?McECGCVZ1s7>W>k+ z3(6u}!p)=62N6acq#J!A0_q@bH3;UviiA>iDg99jWV5GS#qGYP$+-NIK?-xvoOat>g&v0zG?F2_5r1(ciLYZmE_+T1{n+7Cu|IxcIpa~5!V(rPIxB_ zj?9KI{8O3|>oU_55<~05=pyxJeYjcI2~!x1FqgtWSW#m`UulX<9MPE$?B@vJDmh6= zhg0)(Zg`zUqTf{ip*D*PzZvDw<2c%uwYBbU*Ro!Mm!(iQz)X44`$KEOxgbw}8*YY5 z7|nsbxOb38b4)9|r}rA1N$Y+=E_nLJ-SzjY<*e`h1&OEd(6gAUaX~gOj zchAiUrSw-L4nmsttfr|OGPZ&_Q^CghSenAp-EwB(3;&J~WE2Y6wk)TBsMV1 zJ90hCc-dadCTww4u^ZMF3M;VYot|~fzXG_kjhF4Tto=`Y1D2Z7WDPz1O?uKZ_-2Hu zkP~)t`kb%F-6D|94jptl3Sr7tAM`j=yUMs&;cg~7Q4 zB2#JhO>$X6vO^x_B_h1k8~WJ%W_;+;Ff{jyD&f+`2v5%eiOBF0Y?SCdyF0RgpvVCo zfY8(ZFEsGgKZEK8Z@i!O8PD@)GYa8T^y3lcdT1H*E~giTM{IQxJxgekFl_#Z!$z7X z;4)#kt3plmsY#v#SnIf!WJsvF737V7aTvN~M3@wOb6C+YClP3?ZEOwwBHT>MLA=bD zC5%>NgYd{VMZ8dp`%6ag{`Xo#4~Cm}Q{hERm}luXMP5TaK8@x>yIO^XVdFpa1}q@7 zj5HW7PLfhyhbA8Oi*;dB;tL5khaL#$z77oxv?k8~4q6lKFAX=phV=GBJs`8p+amBK z&du@n_X%pa`9&%VK>9+03dN7;w4Y)~aTda;`U2Jk!v%jyxcON!h{4=oKruNG3368t zrKht0>jv8kNfVGr*l;$(mCoC@ccK^^j4(59*g#D_AE!vacxfwdwrO zN**dV>X?>C@G(Nk>zD=D(8RV;jWiDdC-X&WkuV`%s5(I@NxyApj353ZM=S${?FobX z3Vo$PJ|dyJ8~|x0AGt+@%7J;z;(i>h{qAtHZp_})ZmqS@QI&`Bx9WGYb6aI0ot$RHCf1GRA;9TqX@jP{9uGwIr zW&g)q3lpet&n?V9;p(|Qug~>*UNr-naKM{z^;|pIHx7NG!MV}reOzST6ZE;h>Sm=- zUSzKQ=``0^N>!L7@QmXy*Pd~x&#Wto>I+nH(y06I(x-c@j*vOJD4>GP_OZLY5Dv3K z2P>c(g&12HnQp9W%=onR&_uWwnh5{D>1IeD`VCFDe@wXfUz+@n@ZfZ#CnoD2|J!}S z=y2{K&7Tr({)`}<=KIg#!MzUi{m1Zs!T9#b_Z%*CMpIu7UjyUCfbk`GYVhdtdr|iq zn2IZ$K*yoO?9<2$(HUYBjVfCi#^$%Zl2{eHtx>|OeSn8_jRF5$Nz9~BC$R!*c=aled;?cF;M(ArPB!rCx7+Mab9wCb2$XashMAODdgYzTw z)bAsqVhZK38VcE%6^77Ptuens2d5EcbLVjIF(#c=)C8~wJz973&D=FNbm8KGFQ_Uk zL#3${E3r0UeP*+j?ArA`BO8t~Lu2~M;Ip^8dOT<58CobzM2Sh*bB`yQ8xp;863d^| z^1UJ_)YO-E-Ou@OC#>XCljLU2!SdW}rkCB}V|TK~YihFYe`fQ@luYdE*a%ULXGDLB zyQp-C@O?K7X}oe`(VN(;6U;?i`Aw6sVauZ3{cv-HG-OjdCX;lCp6B-@&%*a^( zg>GIRp#x9o?pA^yr{HOWqV=rS(6`;W-P(reFo425Gb%JggQG3QRXlwUwg~@Ppp1N^ z#&AxK3@$c{JTd@`gl0RMauBjbLiw};J=J}olikp|6;5|I>$>dbhKnG~Q!y}!Mf^p4 z)MYLn{ObN*2xi*42hY@PTH(R&|ALu+MZRNS{HLZK?!E?QA~-Urrts?M0U-I%jsc*J zEkLU}mRiT&?j|?^r*E#fJ2l6@9B?v%;AB0{gShHaH8=D00;NtxHDl7@qO%&CAt6Z5 zgtnFj+6+mX_EKd1B~&o4j}>}Z0gI2o$lZf5GE@tFhI$f0C&5^_&&TF?Suw%LPwg=} zj3k6U(LaC95sVc1*gal0+rjQd7QhJ8LLbp*;oqF++@uDeeyMc@`c6{s37=wsg)CI)ud408SzVuU^eei6YFUrO5Ywm-x`(8rxbWq zxVZJ4?jv^mzHXyD05<-fGXyq1voXQkF*E{l6+r&DSZ~5rfDrncGWz#)gO5J|Z$BVo zVvF0eyBp5K$dB(=hm zO(?Oo@K$n6YW76=6R!pl&%Hl_$S)$JI{+dJBcTBhDUE~xBB?pT>^}cn1Hch_yStj4 z5^|omy9em;x4LzDoZuq%3S6{nh0*^F7o!H@Lim@any-b6e1m?hPT=(`xnil;{!^{? zv6oe~a~|)O;VozI=p5RPDGvRE^ZW%vk(d;@hzl}tUgh}!pn}sS{)NI{y1}Pc^m}wc ztCMqQ;iGQiuEe)Am{^@NJs~OdN_XTe>UpJm&_D?W3||r9F1*~W8(xK8Ae^(}MaWgL zp8tkN#CsZ^Ogv6JC3rqY{1UA5I=nB%?{@rF1=d&6IS`_HxkFU|?wKD+`o>VnIx^8i z^P<=xA~fRCt>e?DXO-p0<9ZU$4h~Hsam8O@ttxlOif)}DMYbKz{O5jCTv4L{;vw{x z0f~)yUZ4HdAHXD^k&0yvb#^F9e6G!k6aI*S^1MnxTwi!l61GtI70!RI)fN}p+1lck zVR-#A=Q-Y5q=d=7;3W=MG;&-zykPuOlOZ2^k&C!UAYW(uHRhsuf%g%p-P`wS>{bdk ze?kjl^{lZ@{d^gb}ei;3kGlEEKuj2QeS z8DUhIX%>|MrSRc&a9ck(H=*BmN37n36R|Bm;rHD}GQ0tE-~VbX`}q%$!*~PC>rC}O z)m`01sz`XP>24;uRVC&`36PQ$uQK7QSX==6R5wIS@X8l@F;;R&I1rO4B8IwT!JU0S zkghI#N2P|UyTKZE2RJw0pTv?Qc}^v|O!O00o9B&Ka|b8i`2$e1I~BJef$!t-cMq_T zk7FI|!Gp9htd9TMG4_Qd37X}h4RrS~{?W-GM4}?0r4@P`L_Dq^R5r)w^T?a?64o4^ z^*&IvKYNf|n@&wkPZ|nmVWHJr=+VKciWot7WdSCJI%}xV^QZ3RiE9ea+#5L) zZNAO~=AYtulUnx|URuAj=$$A~8lFndQ{G*DRujspUJOA|CKF!grNGj|zs0Ke{F?JT z+zm}LsLA`E;QSAD>mGApT0%=@1sD27cdjmHB)6!$cxlJdqIWsDK?^-jpWyV?|0WGZ z(GE_2P4hp-`G4LGZh`!w7FtfaR*`XKpIvfGCNGy}euHgS%7(|-qWq^WxH>N7t;XB( z3t~dyhnILy+K+OAvf)v-D9?!tuTjA zy8XRNF@=0wno?*oXU62MEB{VgleXeJN1nJa?J<)hH?BC%;fc>nv;4)8GnD;-aPmRk z@(;F=-t0qvm|%6Cz-^la$S+A3**RLe2YDF6!?o=bqOU0-?;lxzDg2i<2Q~(xAR0aI z#iuI?P)&hPBoK^e2nCUt*JgsYq&v~%dH4cporEvBK7s!)`npg3ynMjD6vuHLXg@<= zzQpe_JYaM~mKReF^9M&^vMZ!{UX35(gQke9=&e|}`VtPHma5RE3u2DE>QdpmnxzVt z72v8r-JNg?l`lVW$x_dLM*Yc9<;O2s8rWP4Wb+mkX7JM#^v?dtC8aQ#I`|fKFr(1i z8HIJQyik2vvoF5nZL;LOp0#ZbdoYpuDD0pKo;VJcwb>4^Hd3bzy z%J6J1B-|HabfQcw^>e#LT*QMe=ZU&*sKrIoKpP|c0o{KOJGKA8; zvpfiy+eev`Mp+M5$r-wU8+VpN$+TI6+^fb;#p7<@7Fjyw1lSOS=N800ask z74-kC4|`0CVy+r(o;%ucrHmP1Jh@TEFd=kHxAB}7flW@51YfrWK3X!0+=)nHf^g-# zqKyfgq!F%Pd=OM6`2Ve*!!;#eGS##%y|f+nJvANh3H7$d=INtW6P6HsLxVxm9Eu3n zShm+RAZn+^?$IN*TXyLYxJ#^1kJvTf)(UQ?@+cys#>~g1LTd+h|15`MOf?yjxhe)R z+q9I4imI?IecHF1lS~kl$qI8(GHCY5lIu@eilV48yHQWF%iJkY5}9RDl3DQ`vSitg zRmd{+aGYfqyi_q81?<1mTqCrFHP&dGF>EeQf6O>@xbWZwVQp)fcLnV2-q#@X4OzN# z>j?#UEZs(3MuL0s28ZF-8cU^;Op#$&LBlYDBCZU>a+sa!5!)5(5bP1;s%xpn;`O*) z!q{#&P4_F^)jA_iP`Y#JsvyD;{ zWX4lLq15i&$29IStiu&}R^svFk!KMq+Ybk5r|dA=xkUM)``n;41-?JVE?H{Cxb3`2 zsX3n=@47%uKSe1lHHQ>LoCEk%@K9tz<6WmUc1(|mOlUmt4m+$z>s*G-5_h(-?!i$RMmJ96l8y(NT(I#D-Qk&Q) zac=3ddrv97l=S8rIJ|hJ%lCQdx1^VU?Zfua#IjVgH5w5<+wb5i00&fhU;Ml3F`Vdy z5s#}=WBC)&cK2U@gD&dRbhJzg4zsl)|l{n5xCq<*&N&QZYVP*~%?hGA{jI z2Z9dUYHm`3G>Hm!EMASj4Yn%o-2~}fifLF}g}?Q-D(5RyNd4lf_GV2k{a02Tn@iP7 znHQl&JAq#1Jrn7sVPU*2g6@a_x<;Bp%(8xMPhJ*dk5f)~}%wt4h|Cx30vC zPg*n3osu<$4P@}+mev&HP&Mw7HHTYVujz3mYaLrnh*P9hnFLqdD4?P9 zmaJVFwBx0!WOeEY{Q9I-k#gzgcwfn?E1Q;DHxZvJ(w|(im~JKylsP?FWx})!5R|cwj}mFg|9S?Xe-iYrz>yS zXSB|Er!+PG)8eGd+Qxk5?xa~)@e=S zob&Xyz`qZh16L7q;6+Tc->X?z1`O6hpJljTPU`|>Z<$qg z+xVjA$j`4I_F0Shx+LMZms{#BHb3mDg*modj@zG26E-j;6-lwaBu*T;%pA2g8)WbP zY$2N4Z$l=io}wM=(FW8X#2H9s*abp~2QQ`a%}O4*9YTD<-Hs2|??W zU2L6L*?6(&J)`+DwEXa)L#foco_jMdKojBfw3lpI*`_fSW4Nv{v9aUNKhwB={YBi$ z3d-Qgci6fZWS%l@LES`K{49~ZK}~4iqJ54$NdCdt9+96Hd+cc~Bm3m7W!K#ZRQPWV zj`(0b!^Pf(%2GIoQVB(4FxB^Fp7CyFi1Yf$K&I;giZaOHZl*DkhiiY{tm_XfmZjd z-r?nX#<|FdTJ?;@W9F><;7Yb=Hf122c!vV#Ic-=k>q`@yPw*=~B^!uATMYxdQ#%rM zP;kwfSokzek7L}bl1YSv91pCraF4OW7;#SaOjMNK(B~R+YA*N049?tYGS`~Si%pKC z*kb2rlj2+6oD~Pth7$xwFf1{*8232=Y=`TVgURmtGi)ZcSIq>RWaL6E{E6H#4`INa^KBhBtUY>!5L3r5){0jA*59zIF@mXnvFaMnUGT2S))M^V6o971 zMu44VU+@{DmP^}>H4AKp#%MC9EY7TX(`Lwyf>{;enQsR1jCs7KC&}&ANL`-`R5NZf z_QJ|}V+l56a6R}T`5=D;KJM5kB6HdKeuaxV<1R~8;Kk;m=AS^D*mtzy|H(?EJ zgm4r#VP3^S!SC*==?c}ImOt#bcqMDV#KT+$iLW5xtI~#U>w)!ds6XrO%;^CWu5gMm zv?O@`eELdi*L(eWvqgi`9fROq^yjgRyCK1Bqmdp! zEtw@t3%jl5-B#(I_Q&rzT9&wC3MR@uZq1UMgpwSZJof`@Frbv~oVEO1Bwb@!V#QxS z{NEC4T6BN8rWJl=RllONKfed5d?>Dr*0Jw_HIYo2R~5~z2&tc0%RjS9W$llr(|2WX z>-DWkA3IF6Ag)4LletW)Tt+Rb@KK8*I3L}UOOLR*G}<`1fZDvsCQx9Ye>)=Qb&z4d zcOok<il2SS7CgK2Ba|jh=riQhAltOYTXiyoV|SBI2G) z-1$5qs#aN+2MT4<@Ag7nyLMB_V{l!3e^|0RIB) zI3;_^D()7eLf`f(EmrG{)Ep1JC5tn}J^pjOV$xG~e|>9>Z?pX+*UO8xtWa7caYkxX z=uEGvCLJDVkG9V%-uZ_0o$WhzB(%LNy;BE1M63mny_UkJ^26h|^UV*CT1svyXMa}n&&4Wqu#x^Z z_1{rAn^AalXqWyAbG%X^s0sgQ!HLG<>1+`l!u}SeDOFckIMOSkg4AF@n~;eU_TG(G z$#GLfPLFJvuTwc?B@o-wrPxqc@@#7buTnIGo&~!;jpS7R&wEW9(z!8p0g;EIV@+#a zQr1?>&b$pX&4w_bvzqL-u0?#BN@7O?fhz&i3^f|gpQ)@5y@O4KEPh5(=3F1e1e;HOG zCsnA!eX7|%@)WKZkP|)APmwSSDpzpA8a^-y!u<0mD z6m~faBsa$fH#Cr-b0B0swPAnxp_Nk$j~GS6LH;Zpv5UuK>bIC}qu>}ate zpitnOIK^r^nzyv_R`@NG9EHY{NxWBRxphSsMAWwUY${;{C7c!a&BQDhOQv^Z5q`iT z*;oGg%99&Rs!lheWkhSmBp!*bP;7S!%SXf*zlnzHJ09kV!M#b2+lR)mg3U`S{fYJb zlKR`@aY(GXJ)v@qtLpZ|nvb)iY~n0|UA_V3(p?x-4vYA@8$!E@{+A!k!$r1m~Je;G%Be zqBS6k&*RsLuu{L-9e4+>OK1bYCEBOT+rQUhT%X6WkEs!0Kl+BS1rtt=ImL_diu8q; z@Rm159R607Q51-76IyOMm5P^`)KjTSOQyp%0%N?NvN{fyC@l%8Q7l9uxoAQ=`~WLo zh?QlErE_jTtj&&d2RisgKVg5T1j?ejig;5t%!u8AkJ&pE)f^8RX_jKW3pgp+y{OPJ zH&CPJ`kL*e?_w1dae}=vkpD3FPL%x=ds+W18ciJT*AZ8<{NGV>zjx73#7{SiD;u@t zsa10pE%|!msp%%y=QszPEZIt%{EZk z@=gsm`*u-0O!+yTZU7zD^nw<&azQH}gLQVZFnqXTof1mM-z*RPoh8uUyMTqmKhvA^;sBoHtZ5ev7^~QaPY&m@%TgFn@44X_sp_I&nnZVpnHyK|KEKGcO5FeJXeEkDYG=*D9+qD$e9PAqF zRubwa`=U5+6ss&t1X;t;ozC`j&nQbnox2K`qwuV94K6*BsC*~uyP6pW8uK9Zz}Vr5q;{Pv@f758^$C#6b*L+O^*2GavQw>c?vXOTl3ZaZ zSef`_o-gF{qGmGxQq!icsA7AIzh==>a_D=l86Ya>?AoQs9_Tb3%|N%dcZxXY018W) zJxbRH`Bnw6&3i96O$sc z1NXM`PEwlg<<%Y-YC<6z9NW+@Oq+aB<{BUXM?3G>eKGWN)24a@_7@qqPi?L7d111i zToAQU6U=TslfyMt1ljd5-80~fDQtskwuFY>;E_z9FYI5&cuE4 zl{!BftW!8fb*50AA4cLlO?sW;q|ggj)#=$CsWbG&K%GE=5ajq&zCtz3Oq|1F3J;ZM zxQ-Z)Xs*5hFC*owx4gPJ>MO`N9s{e)P zBCp972ge(KWkn6q^yc}9!MnA{3mh zO{cuhQSapC-x2^cQqDBiFN1`X6lFs9*>gAWI((zPR<8-^N7P44<1?AQ0hk$#7|22RN?(e42+Vcsr>eAD(- zA~(0YLY^EuFLqf)H27DS_6k)VVn|eY$eQ(;%wxcRI6%D*@`!V7*4pMtoUO7`UPE$f zuJN2+ZRlsMb|dU-e&^nX^}$XMj^gFtb;xTr9sTBn#KURR2aUWOYv#V8K0f(lACKND z{Wu;!#dw@V;~_2iAZUbZIj#h_U>6=G5Cxe${MZ;>-}C`O_uFISyr>76BW;9xPf6$i z7(m;-HkOqd`h9Yd12^v!vpIN@gL-CiIp)=ZVStQK6T znRa(xDkY-|aDmX~(B-$uO`qc*{~8IXDU}V2dan65*ST zxufQ=QoS2Y*wCWR%76o{+#=6`mU?+ig&0+FNB@Qe_LVsq>m!_yg?%#ai+YzzZ*ph& z-){kb|CWaQB9QK|0OI9Tf;smdtthR_VI79Eta;-FxD!-%8y%s`q2Hi$qy5XZqAKiU zqeH7Svm**Gp4G|dkkmxb_s1V{nVjvpeJ1Yn zIMWh$oRyc-ViMtw{2}R8n@N8V) zpA-`p!#odT%Rq@;U`u1AJK~}hg*QLT%@RZ3@)_{}=2^PCk#Bk3?TDu$8Al6H`zKvQ zRuR=cVG0bH*N#UWhYDlt`(3BhV$WH=SZIptD}HpJ=pC2VGJS=Q?5gdO7v!Cl_mAg~ z@Mk*2`06OE*(}+$uX16c-=?i-meMyKW=*le62+e~;+S$jm!_MVHCB-)`cX4qY}a*(d5V){+Vi5m64V@8K+E zF))okGcq%sI3Lkw>e^U|>nJ4c3cM3-3|`#c%O-3^EeXJwFw+_&oCAQ-qj(ze=*Ipj zK{d5$*X0g%%s%mm0Rz~VTgY8n%~$7eJQlIR;4tu&N+LvYm)A>KOQBj)NzTzE$DYg4 zlPqsJ$0>29^rSRLpnpnI)QUc|R*8crhs#n@a1AlRE?8c*Ace ziI%DdQ`m9>i#u_Io$40nuyP8K@0*r#x44rnjszcYfE!oJ9*iUn6|}I5%zCkZ=Uoz)oYpIS_nR$qcr7C zg%w|w{~mgGSZ}SFBqjk$c{v4&)wVcbi4J)TVToA`{dY9>{>dgBghNT-^zYJ@xO8_C zM#j^DVaa_*OLt=!bKllvxJmtUWaye-*Y>;$p4ltVlfsjXClwEYdtr?0RQa*|%ZJpH z@$LDSi|&uHOkdHj9}Az4Wj9cREcub3$SitrZX_7b()6G;5=>x{9$XX&Cb3is+TyF@ zICs3w8$Zz(e`7^_rXwD=PjmLe8XxZfmJn z;E%_2U9d4H_|S-!d__ub{!}BKh!x|+oVmt|K&3bmrqIrkTBonpSytuTT;;@(WkE&3 zET40}+xdXkS?Yf77`sS=kue=8T6T zfrloHyprH7J03|O=m}b@-_q=_X@dDmg6|>=O z=TOIM&Cdh(>aZ4(d+4}r7-w;`pYDweqRb9Zmca=a%l7KQfe9GL_UOTZ2^h~B_29q+ zWUyTn#4!FSB;^M9@vN&S~FQxASWJVl?>p7 zAoA5zx+VI|(`OI_BmqVnv7WkrIo6rEY^?L*<71thAIAHy#yWEz8S6~NqrTA#_EJQz zi&q7c@zlzqqlwB^?$~R+?&rM_h1F0S4&nks`^&xT`t%GqVoLx&Vk^hiMLLqrLh}wP zEjIo5xSHZ{$4=_UVv>@-#GP+FU}e9d$PPFh*g6?TuFtD%8AUKLJtNhOn>yN|zL;KA zF~tAxeiogcVKoP19g-I+mBx4`&^zKjG$Aw)$?VZgI?t;75{)SzQQ^qEBex#x1 zq3-7!m`s`Nuh~21Cn*!DJ&1jqrBW<=$=*>ijGwq{J8p;ePF!|qxO?KV?4gI!l!?pS z&o>=%;Fl#*%8rMYMMjt8_fRJ0%vQ$5S``2d;Dz)wZ+#bfh|z zy3ks4v;Rx#=Jf2Lax%Jk$ilN9=%YQM_mCk18dnKLTtj;EqH1OFdfplf4f7*eX z+L{&Yv2=wi(tQD6IU~F^HwLWI8W3lI3y~|5`qLc~p{>jQJr0G+N#jH===*~Aed&1z zdKa$vakRgF;VAtQ`h4mG>EcbG&>{BKZM>b4y0QKEC!yMT!lVP{3W5EUYE4hN3zRk- zG=pXYW`nvgYoQw0>K=PI4ZIy?{ujK2zhCkkI6s`{pk|+yPP*kqo*^yjgA?;uVQ%`M zRJO1A3>e&`rdu*tC+D%E&iK#`2f#F9x2E&xDJghY$8zjgT4YMio&80x_q%$m(DF8? z^~0YJdzBg?cCh!#==U1`(TdK745g#kWPkdBnobMze1t0ou5<#NKHZ_GR4c(0tBXuH z1vgv@3Ukz;Ivi#)o$81V)m*ENK4Lr@eJ2z1_pgj`wJl4ma2bxyyLj}0M}02N>tah_ zQ0#(7R06zF<@GTpQlAP7pEO4Eht)*mps!o zhq>WTs!8%J!s*&3{AHNZB%vFV=P{@cS2Q_OxvG|2@xl6*%!Zbm-(fE&ZYf+VlckX+l$B>iru;+^M8YVjofr8GloZ5=?gNPGleG z(+>XRjc772Pb4Bx#{%9x*m@fiR4Hcb{+*}V4>c7Oy5?*+5_J}c$!Y+=&5DP|jEt2Y zZ?e)-l+7SFc$>16Mxtl^up|7gq!s-5)I?hxxN^@9bF?JnC9*$L zDZqj(&vsy*)3XY#xl<_~BfL9odjsga&BMevoC?8rHF$Y$h!XvWDJhettncDV8y_5F zl5KJO>;nfvw~Z+_-f>Wr#;&?U;XB~^QbYPTcH?yP^f2haqqL2~stKr5JGlsc)3GzZ zt3niQapE@iKauuF7Mg(Pwt+d>~Ev`{?MNc7mEhRcLpL=d6d*arGe zw3E0^8r#U$QE&h!iraum>9)OtJnN*ao^IenlqBwx*(yp19aLyYHeT(Wg5$W#O`8dK zgT(*?c8~qM-*J8xpT#VY3S?#~nNUGvk5KLm+4G%dvKPxhK?U~&q;c!x&ci?b57RgM zaJTN;(F?MoQtrvUtknST#GRKsjbc)Ijxl{TcC@(jm^fGpO}#Ml*qrttx#39Ql{>*i zDuC$DFg=G&qsif|cV->4wC7!z$&^BaqY!7^d~w(;hEG8`5zIZ^Y6xxhDR)9+uv$^_ z#j#>kqj7Ku^g52sL=6cs7xW71&JR=|Qw6iwKouEKC#1qj=p4jV!56OBBVAqgjQ=S6 z>Th>n^UbRJq$SynPBa_9AkcLtC6mh*$3w@dnXK+uIO}m5)00eFx{nUM&H#m^1a9^No?5Gc`)TfFd!dCMjydL2@RK zdZn|2sMoylp8pjB*4GUD1;>1E1KXhac*=;$z-x$ z%{LYl%=QH;AxZM)n}P$*R!lO;PxN^Wo;Ez|@dWVfz;h8#Bc6SDOcH!X(XSJ>9QfsM z&is7BHL%#?ZaSkiyEyw9Euz&5Pcl~fX-#Teg#p*~TE!We(2yfeVqioNohYtw^Hh@x-C~=yA%jq zls=&7eH6WOw+8Zm$1Z8dj*HR(iVjjVUtbB*pA#i`2Zy&DMDL<#$8(iedT3%c@pE}! zguob-2l2|blORZNJ?*q%U~}PWbBKTj#W9`<#-e&+qB{a{5LO<>4i7=bt;WM%dcmsu zQScL*U^F`}gTLw?hHIO3S`joB7A%(S5vn9Knab}F;kf6jW_Z$!MHL3UhIr3S#xuav z5Ts-o&nWZ~LY=kXWE|lg!zPD@UsauuW;DB@G2*{vSVV3sC!pitYmfZ7uG2#&h*S3c z@NtbLYoH~o>or?$72|4Z*~^3~j?g7=Hn9y#VO=y-S+_!juS3E~dt}XugThyiTBTYa^3$|xo_*`KBSks;6KXUp||&;tIFN}pY5F;DVJ0S_scfJK?B?qvwBK}-D?&5 zA3gnQ@b{qc;MkqY>IMpktU8XnXRuunjb)zC2lH;nHQWNs7gVy>QAUTDZ;NXq!SzM9 zMy~{Zr}7;wX>B=)%uf;3PzwF|K%4X#hbE`th_HQW!SNlCXNNWRxSo$1w>tj|Y#!jVgSre}syLl9I^_*b+#IOjR zaM0lYM7zw>BKLoxox%Qqmw#!8JN5N{T#JbPJh)^ph=W-i^i^6M5LyB^c3sO?u|?Vn z5C%CORQbUv$)?INB{SGGdNVP5@jbkhY!fpZq5tI>GR%}1bQ_3J2DuDc+0D7#%;5&- zS_Jil69~s~Gg0^eWL@>0Z90B%@TqDgkRF`|R*)5r72b8%yB`^5stWHzq92;-GTp}|0OsxNpT6zVsSt}aG;K; zgZx=T-B(!x#rHpz4zQR=iYnnx$kqXOZI#Tn8X zzn1IA^rCE@skhnFsg--aKAYq$8(FSVD;F5B|Bc=dOqI&!`Rt1ty{%fgm$2}V0lk$Y z%l%XXQ&#@3;B$yV>4h?GB8qmCVG5~ULNX> z8vhfjoSfxW+_~Nl)qov4^s;-p;{IXuBeh?qi#)~ciTqpb4bg?HxMz4jQ!y)9^J9@S zYB##D?4GH(&xh*#U0oC;oT^38a$YeQ!Ui1Fh2y#y=GL_83JokX*9lb!t9B)nk;_x3 zqxWfl81JJ;F4k^>R$ckSjCz1`W$iZ9$&odm<>X3kgTv48Yd(`!8zi?8Y46XFHcDBtR8^ODT0Ck{Q8sT!l{D26lz2DyVS$SC zuv6HJ=*zkaVAI>YLjb~`okchH7q}MEttdM~yIkm6MwhR%Kh!Rlxhm;$7bey7v>TNa zxi7A6GE61LmiqYkGCZdg9cI6#mob1{qjxi5MPg3L(|a1eWMWR4tB)r%qnI(@=QI07 z?4S^Kb)OTe1)ZBQayCb={;V;ajMYBiV2%@GV9mt|Uwta8&DgnCw?Xe{l#0G!&$&~M1*ng>&V2EPE$ z0p}^SMjzq>vYu+fbATL>=TSb;X99A}%CF!9e!zJOtuSW?T6q^zQv2LUjT-1NCN4H< zLk6CBk*~@C0y3MUEBW4b5M_v5$M?#KHzR5{W_dEq2t2=zhfA4Wp7)n(T^OsxU)!rqdllYmQ5q^UQ`(xtHfK5tZ{AA3I@1fL>z5T9BM(Vy|XeJK8>Xf=)2(%lt2u-Mkf-Ke&fW$;hPv!Lb?YeA9`j5xZd>TynL z?u@L{YBP~Kf2$qpd>$DDG{mX zyZh+TB5ULU9%RK~V?aBCEZp~A!PoU+W17F+j=~}v?1Iq2(N1-Ay`5|3xf=}BS#yP> zp7=V(8<)i)y$aeRr19T0ljUPuPfmBTAJavyP@*aK@=m8R)y5v8dqcAU!x$3fVAFxy zFScjiaKNy%(&!dCcxGIsQE+z{m?Zqo#NgZ}8HFNkkwxA9Evv(Q`REF%(>`EgtTI!qwhtcPAt%`FldzbzmMrYkSB(4xaI1b^I zzd;gC*tG(jmWm!x1EB#;o_p0mdq3^eBAR&sQEfRben>(_0fOa@c_e8r5W8I%N=`-> z*^hG$+3XT@`0EEoRWGibbLR_tr5iZUS&lKvD8n_PJZMj&mnho$Y?-Pv`MX7bW2_UW5F}VE5 zE>$iX9#epYk=#Ih!GnbdxzT|^SVZ&Czv-fX(Ank0f%0ckYJ0IP=N|#800R@2_%98ez?8mA$kIKEFWj>CCyDGvK-A!B}lIR&wkAukqo zNH6rkJmot(awO26HyJP&;gPl-IHc7jOmf=XIa~&rxXvF{Mm5$C%;0AiH{-7@!&YSc zp=OtY4%ZVjXd@~)8y+`0vP_PXhF9?7m@UJSqU65IF9ced#k zVJCJSRT%jveN(!IQaN_{Y+4j*vC3Cv%89;V!YJN4%>~jL0ocPP~)$d*sp= z*Z26oQe~!7D=mTuf*8IO=OvEE`%hf#l$;AgyNy+U@2{%7IaGNIU>SlrTzPZ2@)px4 zni~qne;P^57?{o2d+x7x+-!s%Z5%M=-Q0Xz5J$h1U74Djl5Z^$aOzg9>YlPm_uN}% zVwv^Fe$y~{LF~!kf&;&Q`2APP>TqB%&8Z{y%psIt!_3HpnwyuWwJAZdD>$`1n8gJp zPGZ0`&dD6$9ed312WGvG^Y7Z(^?mJPRu@3|bZC@B4V1R8$%lggF=?E}Bzxdj1L4h; zTv|F#A*l`s(zxZFez0uGid2i*zI|QdjaXW3uGU zf{SVDGv`Uo@6?^hc3SbJxwdzNKB@GLT7hv2)v|Mf14<8Uxw#i8xwE1#sogD5k8;yX z*a)<*9w@h(^NKe`6{b25*U&ERv4VY`PVs25U3Wgh#^0_F_kV8Ld%$3pcXQb`n}97K zOToU+J3ln<)i&>3oFpx9w3y?2GV@7J%Xf!z&o@6)l{>R;j{<8gp5}W}RfagsE&=;M(gJXucwUWRpYgZYN^!PJa6=Edm)zbSyrU~v zJ;d9*W%)C`&EPFK3YIA125*2ATDr=JJPY;TK*_QEb7ZtbDqqQ+9XTHW?eJDEe=>;SKWNn8!C( zL6efju!4Z5OZZp=U5xi`RUHjyskq%~WK{ppZ74+>`1?n;fxjft294ZviQL!x!{kPJ zr}>gJay!z{!(}Jq*ue-p(7`$90&IhUi8ly#y$Qz(zN-Zn@r_}YgiC7z zKR@1t3ErnvhyQC-5p7GWrF{Xt4SnIYHXGZRZ zvb6~QJNO#WLcY75E_E2HtLjLlX4Cmx(x(hK~W|tuc(R4Wosa2^A4r5;*N@ znJ`Y-%dVPCtB0K>%U5oKcGzvlTiEX|pDZ{^1Dm`rtB&^5xhdY(G~fFw0B)lZKX3?R?Gi9j3OoGKN@eWr{;_xPKN!>kP{wJm zC?XBAqLk~HLd&^Go1sxU5ig7Hh?ljhAk=X(Q1OLcR?SdZ-id>zP8#hsy7=tn`PpmE zM=AW>wgB>rag5vv&N?Lidq0xR61mKfeih8J3|5mkjh7;kHZFSgGiD70nd?JfR$7O?3j5JAYJ3ml0fX|sV zpnp!ySt_9PmlRao|2LOV&N(7ydHbNi2`^n+&@SFSwh_|%5Qyle( zPJy})QQdE&BC5NKM%qAMKk9z0U$0xUM+E?#{M@nTtirH{RHoHK3~j2Z?z3=FPs(ytM?FUk!H9oH7%oG{$pq~DIPgC=e6)%!A-1a9el z87e&a6zz2OX5|_Y*Yj&*ca>Re%HuGCbWN)_3e!7SMrrF4W)vN&srzI0l(OvUKgj-( zyW-NR+BU~-6|L2~u_mV*NKWHP>_PepV*`jXh>{amH&2#xOh zOiS^dDiBa@(7!z@{3w2^twzblvVq?}@7h&)Uy;GfCU^=REbpDVXto?c=Xa2TS6 zv)D&O7D7q-s@esEOeZ&Oa&ojEMOlST;l27VMwwA{-B`!iHpzRtLCC!%tDORS^bCEi z?!j-qe^9rn(fPb*%8ncQ+E;XSv0b~vyHk-d1)%V9`pjF~uaCXg)Vq&u-@U$T_bpT= z9%X!mM_s$WZjXKaWz)a0o=C;bRJy5qBYagx22=7!fPSH`@AL=}1BRaV6@pL*RSY?b zsD`@Gq*%qW-VTAuUY6Ihd;O7xQxL&>PprNxwxT_D9j!3&>Q`Ul)$3!|V;8L#c@4O= zi1g%dsA|NAVPkSr*N4AV+q#|YSPAYndLJ63l@INvJf`uaK;y~K5@eW%UDCMShNj7d z!UFRCb`X_K+&*hyH#*Y@Hs%t5fngY>8Hb{tz11TrYEKv8 z>6as(8sQ!cTRgj3dwOM^;ypFuDX(lk7uI?9r}Xrw$F+K&i2PsZZ{%oZa($=kN$f@8 zo9z?4VDqQPJCE=8Z0#3Nj3$7uko6|k z{7o*0nEr|!2wqaYj13y=vF*V5OxK-hrSh@wz>*a7D)JZ*AW4A z&lFmpcB6=ubaep!ASKuua~;kRb{)2?pIwKDLS5zS{n2$v=cH@J3+gCbK1>=oIWoFS ztv#cz^H@HnV51cDGA-vu;?SA0U1Dd?fYI?nhpj4h=zXj=wu({LaGV70E@6)dCRb63#V6U4cS+%C_V;BIaJ zfe!e6#{o{6(%F0BV9jd_1*>a)KEBnuSyE2j?x)>P7lPuSP{mDh-CMb-PZ!`ipb^4N z`gBis4Y>bWKdfoMuYDCXi$|uj0(Z1b>+FZIkJ0(9{gvm>4DGL^>-#HlYd_4ZT8OnF zYyVQ+mZBEmv z5cX!?8!G4@Ln&I!S7M(2J z`8>N_D~$}Zf1?!55IQIZ(*=zyz^X`g3%d%#{BnL%-N~?&-XJ-ufuKryzM_bY&BkiY zz&wd9b@>e&&4ow6oy6XAxTQK|XW#=uP$oZ9^?3E&JNRlXed`Whzj?RMe5;RNQ|k=- z8T$Bls0?#ioF96u2?Ozj)0#0HAHrqN7vMD|r&pG}bf##I4WR~=GOXay9lugJcSa+O zL1jR!;vDP*C<1M))mtm4F>DPbeg9U?sH=F(8I66p23k&<`P~N2R*BiKh_L}Kx%#`*ab~UJ_p_#pv&7e#0eoO^FD!wT1(os2CfT>&aj0Az*u3J z2FB3B@Cc;kXSim`S-->y@EIu|dXH+jp1Hna(yg}{R=)ao7n|73Q(89aa5rEXq-F#I z0Nn=+*Rme#Ap2JmdF+3*o6H;XuPj+qUbrfE-Q;_$4ehQc*{8UNS{`b>SH4ZT)_-|u ze%0)-YjsYO>sOZkriT27`7dlzr7hM6NXXX%O3PEMnR+NTX3c+bJ@d+L1oy2>mn$<` zD;-j08do_M-qklVb$(bMu@?(K6d+4j3CBPF3(sT~EsJTmc3AUBt$0lq&qDEtUhxUA z>9mXSi4=2rH>j@O$Q_74VdFoy0h-|bKWGY`f1>`q>`@x_M)VWnAe-O9wYz57QcA8V z-&B#oCH*ux-!QBGL|p2ksf-?FyAEeaKMY(Ryr`6xQYWpuBel}^+Pba3y!E!N z4_4OAhEj%r-(!SH(r#D&GqVNrGdY>NY`dQMQ|?of>wZmBe`JjcoexmccG4+s$wX2^!~{enjlW-5Y=AzK#mFnnVW z9~!|6Ss=5qtG5QUpL$gIZPRDZGemwt=U4M6V8fHz-GH-G{ zHg0*knN5-`Ne#&*X|CtzwHR|#BB$}Wuf+7X^x^lZz@ufu8kwo=DNBs=Ckwap>wf^$YNB&#w1r|cX+q8(7Mk$>(TuH`e^0RfUb?? z05+#ZJ|kE^1y?6#q|rQgtaz6=qWtkWY+=fMG_mfcVw+H)6$K_edK3j}Q~r=1NJwb_ z8}tH6nmqf9=L0r-tc(~C{Z#Fw=D$99oVhZ#=RSSje1!^iH1M6m>koe{Fx_i9|M>c3 z!Bv@U_hd`c>24pz%mK{WRWGC`^?b1^t-ShjQ%SvRP2ODR{Q6NmqM3M7)oqoKz@L&p zSp|gnvkDz_4xZLNn#p&G2f#gGdtRS{a1i&o3$18dqt-SF^*z#?XjfdjHCMWtD)JDg z7>zrw!hE^@P@ZJVX#!CckW*M8(5|z-<2+lMZP(1&&FrJJ3V^`psQjgn5I_TZ*~Dm% z_tDRxNMcFoLXceSM|Gxohog<+IUeE_Y}JruzdIeeu+e)bHg;V?G=Bj8OBv)`bY>Sun_z&#>Ep8_ou)6V>Rqw?lriWSa$RLIj$0vIa;V*WH$9}R1 z+P?V2@4ePfXd)eoLpqX1aUWjh)3Go{GfoV-(9)cT15y}^#Q$qV+YpNgz+&jh0Q4Oz z2E@r|wgcZ)Bp9RDfe7!{x@X!e(M89J_nH>Dg*|f;wALbe&DZKaPu=b4$pQ?CdsH$P z4zDxfd_%Y!?Elq!KS5^^w+(tNpTH$%l%n909DUgELo644uZoYUI1rj)n1o&YPA*u} z9=xkdvxvilQZ&^m<9L${V`GMVK)ZNXml%=A zEMG%m#kGCebuxCbW})jM;!8tY(x~<8DnFp}7vT0VYF^88PYCz(aUZkZkRG!dxEDx; z*@ychmcalZ(S4{4>#BBh{xasZm-8jFed|r-ocQ+v|Jcgn`Y)a5AdG}ff@-p@kjHp= zgSu{gzT2GXPa|I`v)$Ds_yi;4+XVVL#rOp8!dPy;p4Kyaj@`K{xc^2=nOVWEECvl& zhRmFRH~}sR-K@>%2r&p5v0&~cv03%KnsK^5vc`6t3vedPMd{jx>TeCs9w&CeehYYx zzmht}Fv0ER&YIJSzBlSK{m4my-bg!Z6GA?8?h31%aY+bH!pGR1$BkRzgXcqcR z9qsZ+w(ygYYi;QA0WuLr*V=Fn5zGx_4O*k-6l3f!Hw0vp3t@&3bRf{cQ_8zY4fIiz zmy}4U8t`i=ez9ghrl-qQ03s+uIn0|4xsJN0C=*a6{Lcme55XF`q_~{r0|vlD^aqg} z2Y}N^;aB5)fJmjSqm9fT(NaUeZowNuL{S4(W-aAa16^7~8h$=tFM4d6g`f-G1<*{& zK^KhMea(oi`d#=B&oU!q+6GPSos2APk=pF~y+ zbcaidsgIVk(FKNBYa+|a0Y}#nvd4yOAdnB)e2rvKjRdvJpslt+WhiEu=Xdajye=+V zw7UTy87oPbvX9d^$hph9Dle_8M(i>noWuGI3;;c3&3D@&m`-z+gxEUwqnT7wGx1^ejoFV94`P8u^CCHj*+O7lhHla|+Rl^|$58 zHugeFYUAy%XclGPCvAB|=D38;#>9n#H`wX%da_uzp3?B`>2}sdmm`QBna}Vg>m15A zWn{i|cH(#B8>Th&OV+NxFHgRJO{Ju~I|mla+({a>&yJ#YWSxEcS%aPvC>>U-WJP>! zzhe!%Ii7C_qce<0j~+|l(R<@~^eAwyJv0nN`r>%>$f-CUJ^Iymf?XMgNx`?8sg3WL z`*Cy^qs3IjQm!+aVS`bpC7)KYbz#i)Kd@o@c?|6a5RB?wf>0nWXL9V@@iaV@fqkGZ z$xkNX9MOaO?`MjX<~@kV))o9A7tA$t?ZN40)ZjXCzz_(VWcOxGQ&}bj-Hw_h?3}Z) zJ`@E)yn>C6{_VkH#*H@8$(v$c)B$QbQZ;ID{75TNAd7iK5P;)9}dik!~{! zW}ED^)m;P2!VX>V+r{Z!(~NwnI;>1}WV#Rd}KXHO9=Zbq0VWDDcV z1toKf{~VjY^6I54k`^(_vMnYPQ?$|OxHc`cY|A23EyonK7#(k%s=`&0vaBt8r#*XW zs*?Fc(Q`(}f)rt@)dW)ou7&ENETcotScHKyk6ZSHvTVCHbH-o~W$UQY5cc=7xr+3w z%1w?3_;rq|X=#CRn7%U&-qzm6hR;0m*OGg&vgOz8#iR|<1Erf)b}nWgqZSr&QsrWY zbX;*SDR?h=u2Q+=TqD<3z4fr4x#QLca*`SCp6{$$sbn7~xxxB|={g3vh0tyKr50(ehRCWvrB+~L^j!lZE3$3~z1{S&h zPW^_-LdV*Y1{wBY-e;7IH z-NBJ}B?hUNIT}^G{{){*93y-IIK}Fw*@b|g4ST(5b3PVoSgv8Mb_|w;o-VFu%1i>Z zz5zZUGN1rkZsr;b@{Pioa=AFz13Tk}IzOW1oIH5A26er{5i5XEkL=U~c{LSV;z|-V z|IfMrrg%G2YsWLuKM+wE{e+t6s~jn^v_knSrvV|5T0@E~G-vPaaZqHmi%Wna`F-3l zDAM~BeII0wJj`jJNN-yzisjo<0e9AS@c)*|HN)lxlj3ODv)*4u;g7e0NJoo?KYkXU zOT!<(no9WNNAW2%{PAPaZ5ow?KYpGAm4F>bZzU=Tf80q_>iA=PZH0tP17tr+R1*Gp z6R0HmUP?vpio8g|WTZ(U`U0p-2hKpcAz=B@H-tmyu_jSEdl8#8`ULT|!3^H=PsDi} z*_PTdnc*Mc5GRs&yMx~Xxq(^^i1bsC8=!d1Ow8$W*R>OKqZ=VN2D%s618)tTktql? zfyU6|SBF?0Z5zq*hB(W;wb(=fAmOQ0bkQe=8UAFd+&otPHp5|ap&daze*AGAenHj zea#eW9+Ud(gxM@QlLE{pdee{8cUw7#Z4`HF3Hj-LM|+MfU%dOTp}WVlyR|qSNr<%4 z-P78d$gh{q2|w&WBwx~rhB2CitcabUu|1(4YR?JhNt@>enx6j~&XYnQzdEW6^3{QK z2s~VR6oUpzn(I{j&E&K*RDZ_^?Bv!_*@tNye&;3jv2VV!?LT8D50Z{I3Oo5e-EsdX z>}2#Dn>+$Lxr5BR8g|k!jGgpa`iIbgL!S9GmVh2R7ff>k%lUkghUFZEoqX+E^t}Av z>B$^H&r9s1L=P9UA%;Lx7u+Nmtn{86Q~>JCatZR{ndq}qz3N$zXCkx$jA;Rvy^x8% zHi*Zf4R8Muo5JuYhtql7?O*400uQg@e__LE&x6&?M+~R^Y>6hugRG)|fYG+K#Dt-H z6dy2dO>a6WNwXq1rP3OLU!5x5FsrUhx5y1`UV}hwFS_ZF-@uk|BqbR)#DjCrwE=^n z__x$e)nfkikzHrxd#gvk_r%Eepjq_gP2EIUm{`_&^nDn=wU8T}S;i(?+ZTa7mi%iXZ^4X#IZnQF!5c2nL-53h`BOS1E&mxWQm~mLm)(0B<_JRqa+s6G-`(Ha z=Ss^zz}NTphLG)e^rTAeD{`(avPe_g8}kvTbT9_KQf zGgqJ9mf2LFZ5x;E%*ZZHt0+nWd_O%uJ$Bjt0>R$#g<4Ux(giILN-_`7(q5o607ii-B1rR%72ZYYseHOBYLlp$xyZ7uWVU+_0x{C3> zV=9bSC~J{bmsD@^AdV-kEE5jTFF-^qvSW+8JjcrR7aunYyLV$Z5e}hW%(B^tq*3PZ z9F~Kk?Jncm_BB0DWJ=O_OIlqYhQyE5SU5jze?iw}o!Go2y>GfP`aIZ<@lu{n5Y9I_ zipDHYcX(e>W3BS^agfSCtC>dUJ2m?YIu5G|tWG?zHiB#qlarY~%jO_*z9RrOfKkI# z?Tk|eI9n5H_I9hW23fpaqpMcK-GeUgAJpzvjV$2N_;xPVLl^nV^x58)vr@1oChsrs z9aiP(tkTTp&D<2NV&A1DSWWatsUY!N9Nz1_@*oR`#X z0lHDw)koP$-Pl)4SPihp#9sUvMh7|5E@h^d)Nz7~TjZMmE9uH~`AWOAJ4cS?EHttg z&^u<<@1Epet*y`F`-D`IXvQ|b8M~I4)}^`zj1V3YSU6Z?KUG^;EmMMQ(M%`*Pqf!4 zyC1H*2Kzi;s@VLN$XSAoz+na!wE~2C+3IIkkg_jT-kgu>9tFI(@|LD0lDj!Stqof) zY~!xDjr1r~OMILw%3o1lvW z0R{n8?Td#**I|Rf4SkxN_Pw>QX$38TIp_GgJ(!GNRbwH@!quHV#0}SEG;*(wGM=tM zYB$4oB_RuuJI@XPs{&E@NN*=R-(vo9w_q%tS(BSuGDUC{`8Ii1vhOx9xvBhQ5{-YV zCw{2eU+?D{dmtJJ_6E3Y3r9PZh>`1U1cn@US?^J`t|2!yIw2LE1!E-gPe{#Nq~TBh z10M7LI1P^pBLKjc%|;!3=@T^V?=;gW(`O*TL=4;D2H+_x?1*-^2*3b79SRTrMp8-V z`EH~ouzK0b3ywo)0M}ERZR`=UR0jIKl0;6}Bw@YsLbmcic2(gl`_1$09PoBn#g(#+ zJ*Uwi0(c(Q(T&FPf{G`ws{|w-P2Qi{E-Ie(Q#_9bI$_k-nJ+@Kajq zVZUk*Zsvl`)IP}|HIJQU;}!Ss950L`hVm6$qkWuNbhN>To5?TsM?VjYbvO=<)j^+2 zv=(q<(WvJUZi}?sQteh(x=T^;u1o^2Sd^&mrEFDrG@&z2pDI{IP=?6#ceA4B#oJ1mri(n4qk?w3^ zcTfvxGgk6(3{NlfOW}LcE^d}v>N&BQEPC2{TGs~=kCEGL%+5MLd&c7IITaO`&CE6O z3ftI@(*V$adw|fZkkVaN7$Z9T2Uun73)dC`XX{-A*mf<#08bFgvSDMkwh6T2%E8+ttAF(K$*dvKBxoZt_R=YkWx*U&M@ z4!;QoLHAu6$LpdiSvXxtF>K}*WiIxXoh|-c&0inQ&bj+_P-W znwsi+Ynq>~L4>@#nKi39oOLUS6P{x4O`GkxT!g!Xe>;4?I~)D*VjKUu3EzhMTp&bCOKlb2xF^qL>0G+qJ#EbzTg5bT=BajuFSDCDKa_+Qp(J2p zjWZYqVt7bG=T_=!Nb8n4rsDZix~@Iq-b*{aeed*~|8Q@sp}5FZB-`e3+^o=qSo*A< z4F49URJJYUxLZT!So*C!L#L@|?T9rr?L^RReWOF+7>U!)cp+TXN&c+rAb@%8m%|$- zk$$zYimB`81oqbDVqezQ=FI73WWO6TJchdd#Uw^UIfv1 zlHRG?bfKcWqbf$#aTqNmvHt(#SxubY(^-jcI;UzyG@*6oHREXxGNh3Fd(Uf?J(vV=>x@-rpMy^8v4HSvu${9 zR`|%$&>>{n{})=XjObXD|A@<0>gEH1w-;bvX1qPR>eU_H&xMxD!7WRSkhzJsPpda z_;+2uV^;W!q>%Qx|JS~gMS0`$@qOvV^v+Aqf2Gm;ANt|<<^P`hO|SysaG@G?sPnuN z?>ygM$7?vx*?OYsyN-K0$1dDG>t*Zdx5r!<4)0ULX4Nr%V4-E!>{x>C8p?~YaY&|> z78~>&E?Dhofx(ECw0%MHTjlq$ja4Q|l!Wx?mvHarC9zNze?yl7$f-&(6cmn9*T#&lf;KW8c7n*aCPre5!-TG#{NipzAssEVK}a zv5lOC6Iob=8EzAlR1Opfbwx760Gte%WxDrafHKfPJCc9JavjNOf`R`VKpSZ5RGcJ; zWII}CgXtM=hIZp3!S$RhZooPB{faAycekj$t**Uz^Y?16#DKHgHIS<_Mfn{T8Cx%0EsfA(%d%!&U%p_asSTHuhp*xR#TEm>0ai zB?JoXdy2V>1n*-MNJSE-%i<4lh0KV{Am+)UXOX}^K_($dlx1-SuC`!)jEIE6f_^3i*fGoe*}Gy_V4g2LZ8-s zuD}`unxXIcEZZohV7=Tf;?uS5*aQS$z;2bqbMW;L^(90V3ql4e3bZ7<$^@HWz%fm( zVDvsTa*V62JSZU2FV?RS+z4A-+acCS^_W4YmQu{F50SzST1%4aa|r9N!Bnu!h6?@< zOf{h$g7+6XlXRBx^*WPumhl_a{=OlOHK_g4B5W!Xb0YVvy?#kN7lQHtm?VoU1*5bV zirrcs%VJGJZci+ebP3Vg4`J3EMyw1Nz(2~us|pN&Obh9Zfkc|W5%mvfJm7DF1P^E; zNO!9cf+Hbw-!9Ah+i#cUt<=lPMpypXP+4^MyUKEe(nwezz?#%Hnx^PVm=sf8B3KDo zZAn2tNsoXy4j&IU`AuM@)#brWq+lf!FObDqLWcK#RG;j+5%(J*pUJK}!S*KY(``gi zn<0M|*JgAuj6c_cJcu~@Z8S^>D_w$7#;tfCUyMEnLJ8q`oK{FTNieRk&DRC#CJBa= z;Hu9^G7z~Q^gzz(GvTeDtNm4)KwO70Op}M}wND2j;D3fsM}iTlRJ$cfOhfe#!Stu` zJbF1`6IdqK_2@y(=v(t3hvfU4-vLL-()SGG8+?Oz1V#&|5byXqAetJRc*wb8brpjh zNVNzM?R4+e;O7wQBGurB#yVn0cnq;Fau4!bTwooEv65h2bjc`wtr*3xpN`^J#VCH^ zD$Xxp)kg4ZWrANz6Z`^r&aZW!pQzpKTJMQmF~qOhA%6M3!LM|1Gx9zB3ef<-{|vH* z{ys|ni_tbg;}_%<-QI)t-T>YtYy3hggq{z6EyO@>A>qQ_C}c+yu3Nw>v&NzIG&aVC zD>?_m3S@{nIOM?(S%eJ5CF(M?9Wta#R1{ZLkes+gEmr#*NT9qvKy`-XX^Dy;Q+rXb z7q&J{o_ugk*7#EbUT9Jjxp@>Xba|TjJ-q1S!3*zIY-0$7jO2wk5A!dv!h3}Zb3Mt+ zRfvlxi4LvR^ex7LJ2&E6Xf;HpYxRTg-W$|98L~UH$2KIe7=vj-?J^Pnm$HotSTV9r zJ_j5&YWzp@+ll?&03!2AVg{;0&uNgvvAB1=+TACK`LZ}0EX75fg6sqZe8u-skQloV z8^BS;fsE*-u)DF6I38yUcvoo!WJ27pLjf2;HF!IDLku;6<`HT`nD`dGgl+7@CmY#@ zXeLc&;2R*my zt-L)>D_=;o61y)RL2G15g4U=lK`W51{}Zj=**dKgKx^c(1g-p%|3<4svf(|SZEX0a zJSM6At(rW_m#fv1UUCpdubQaYpWD~xSp3v9@d&Gvwx#+KwI2p;PN7Gjk6l8;U z7Wyk`wg$cgaU>(cH(hw3s{1u6VzT#K`;fIyq6VtX@^tZQPNgg6Y(Xa zL8C)KFT*)MTEj;uwuye$LdULpGcdP(qn~+?3}Psx@hOdlLdb3;orXf{aOtQ)85T;d?d6nH+ljr)yLNlzOSPAc%ii; zn)K~1@D)G-Cd-S@?C?prlJMMA}qeKS?Vgo$2>4t$HfYUz7zTFV|>)C z{y3L$%Qt7fR3s{#LFTyXshX_^N3%KC>Ib#uvkPX-lDTQya4ZR# z5Qa}C#<$si5C^%6v(v~+iK5;kIzh0Hrz*)lFm?|#0T8lXo=FH4PY1Q|zI1?PlAFrus3)G%|Q+kqZXgm4P zm|C2chX6IraHt>`Yk!ct7EV_CgO*}6qJ7V_nscY-c=&6qyE&W`i{p50gzKYe)EaIc z6lR3!P+spE#JKEIxIGUR?`b~OqA(2#_P?SxSYKgV6~neYr?#1I#^Iq|3cKx<;#P&j zp#;LdU}u?~{Qc!-qqov3i-vNsBn?rX{R)$ZBhzPSN2V)WUVgEx7y`fg3Sg-8=(W~W zY)D}`C|1jxa*5=!7tN`8NlA0AT3hX>Q=k2Fxzh4t|6D^H<6^d-F2eT$phx#Rg_UQN zJsQtT>lUQj4ZjeKw{ z5E_&PtNWdKn?Cr&eLe1Z4;;gC#4p(0@2-5{4Jnp>A8zv9#{ykvtAugxeRu!nMJYD^ z=|W*e7m4$Dqt6_fXT1{VAYrer@&ZMg zq2S1w&rnc_AZOvy{&3ju%X%G2;;rJV_ z@&fNJtN5nM7WU%%d!t>UX0|N97lG=Ob0W*Ew(#Bglki;$mevWdL?DvR(H@w{4KTtHLe zd9@(J-{TAL@Cmjqo-d32<#3(fjEp-E^*#P=dN=4f;BldKB8t12X~d~7r|ABODo4@k zIl=yHsLs_R>b!1rF3Y#u7#zxX^@x1SM(5*^uUw1^sI^Augxc2G#IlM&usBn za2L=y@bs8-l+B9g&*CRoF+k4%u3@~D{lA`qwE&ta6eXWifPG=FAF4+?6(CoDKTieS zD;JxhkgOSOXy}dQLn-Y{0LLH~64|Ydn*3c(&+_45o;RcZ#0<;~B!!x{5rKT+!?Zr0 z*}&TnXmpR#b~Fe_ke!2_#YH8>$|5F`Vl{jA_}l!^LH{D`dhOFkeFj7Ax4-Kr=Lh?x)nS-_Hf#@{gMRUHM}}`L*D@zmSM_Y|dv z^I5;0uQ~p9x*iypxQ2YkN9P+!WAA=;Q#?-=yD^?3=}UyhjngJj`S)FV!+?1p%0HS8}aRfzsC+|{|6Jw;b&#YXL*MuuU= zYh`1;FiJrd>c;*cj>CW(Vo64(p{QtP(Tuj)9`7eYiKo!WhCV@Nl>ddw{*=nep9~z$ z4jUb|5!CC;G(?UHIU@elA8TxY*u(n!u>coyki}lEH1vfwr2VIRV~tb=O3Dt>#7>0^^+cI z2(8CfFvnapL)ke1#3_K6@t%Sqnl`grd$Wo{&6-0d%e{RfnOT{~)n3K~5#TGY{<;~> zIJ5h6#`h^x`)|hdG2=VL_~5;>fbo66bo`U?&1Y&$n2vdj?;lLZn~bTGsolxcDvYU( z{$Kkl)A2H6dV%q6V|>prrXMk;rUg#R96YG*UGk1(~rV|))Xz6Tgz17kX$ zG5wk`-N)44&6s4y=V5B|7~kzo?avwCbfz|!>2Nb9H&eTosXdqJ$YD%5jL*f?PGdT< znc7OmbS+c+Q^pr!YOi8Ce!`fRGQP{0jvq4}pm_?BTI*$enT)TP=_q76Q2QhXz78GZ znA(|)&%xA=WuSSQG8kVvW17zR&SQM%Fwnc z<*KzawI-&6XW+WyGm>``G%0ArCKIECX8J?t4~;X)H#_FJpa7m#D zblcP;leQ_Lx&DyXcLYT~KEEB%%8GNE=C}HKkgdocDmEPiVq_7|zpuU<`Vz3E>=(I? z57ha7(?3-%dLqDlIX~ok5AR;+4_##XhnjqT;O$dN$nNXHJ=q_cVcMf6|1{8eQVC7< z?N+Oh<-ISI&;;KbY8dJ9NRRiut~Nvu1}^VYLSub9)fS|G`#FxZ@NHLXghbPCK*(1C-w`F0X}Vu)+w^~0V@nPzp-HAXH1d{KwG|CdM%rPj0dEHb zMIS05o2eT03;S?!I~%CEcUH<*5gvIheTy65-#Dz&2P-=E)7do4=-DsbqZN+`XyLMuA^pYy9a zu0aC^1Gny1LX$g|gYdz?EBog6n63idg8|DvC3K$Y3Uxl$aXI?GviT&|r8Fp$D=2wH zA?}w!FtG0*!vJfZ+?o4kZd-fJ8++b+t)R`?wxwvE+}1A%T%TaTqTQ)FPnZuXDb+V$Hgm+gK=werZwuRDC|oyP&3g?0v!6X_t#`!Q8Bs~NKbK_^!} zfEaJ9S%2F}y`o4q3IyQkE_S_Eo*XxGbZ#`?sZF&b@$}j_9rrCTl5c^}!dwCbeYM+I zw^d^9NQQ4oatuVgJ`-+riv;%E!=Q23uXL6qG#60)-TowY@+bM8XX*5;ZjJ)i0-)7( zEJfU>7y4}XO`P2>+0!d*=TzA7(MBN478>81d0cAGS!88RL`_%aB-59K8^-*lwMX-j zz)ouW8u&;I9KtI@gBaB_@>ln^AN9ilM#J_f{vvwFK(_35ch)>Zx?h?k)GmD~`Sd@` z=iXeEgz>L#8ofd z1#&Go530x)Fok0INFGRdK7wa(BK`)s=qG8^PpAl@*849yGzb@y`9tvvr+9IiS0CL& z)JpQBMv5rK1yv}b!eb*U>>XJlc(~TBUToWQPLUJ8gBqp|Ist;Wl`y?0mnjJ3wQwf; z6^SU8f`TE3kwY0JO!r*zqzbih;a%+Vqj)B8JSHYO&}&H8w1(_T+kRBt4-0utW|M#K z5p~%~PRb~>S~A(9kC4rk8E6H#aGxk}Ihi>KCS%tR1}g$BT7Ld2MjTMtc~l1uJalEr zhVkBo3Ah|n585BB8N7H|u6ps~NV_byqJ8)wMi#P@GwLyq))*r3_=izdu(hWMLf7l^ z`Ti+Mj8IgX_gvDUF_U6#ZEN3a`qXD8%NQ49xl09pSyaTiw#~bNZ5PJs2Q&({_nOAz z8S)C5l-v1SQqS5%?&1$r@qoHdba6*L*lsb(+ysRiUy**v>-W#&l!=(;%idD~>2~oU zZekTTp~8{(`fqYMWfGijE2OC|W0;%JfDGf!uRr8K1~`7X_!e$rD_)(*zy3Q8uMXjg zKxbEs?YdNmltsnA4%3O~9cZe})U9IZRhR30B~M`Hlf1lfPHX-0ZIq{aZWyPkl4guWE`TV z!baYpXIUC=5%c%ZM{?%)f@!l}P8R>Avim*;NxqYqj2MTL&9+UfaANuDy_$nyp2M0x zC4}cyoC!xslbG{US$MqY$y*HYG-yK`n(>Wor?ZNTr?QF;(lvh7_$@T+aVznmX?kHd zsK-1UWBhP|T4A#Y4yfl>C50{(!YQ`odmQ_w1UCHu-knOSko>2zcI$bZ)$PbM^*#G^ zH3KlKC+XQG;%XJv!wUOPAov#{v?RQ+N%G;o?4Pm#c0Tr<9$ZSX=}#9TB_z!gaIj|kH5t36D3CCC>s^(E7@`ATu>lp7Ap(snWx+tZl#w%~X=`q( z7UlFTb?~}|T~pfK8G)w3T0rXDMo=&j6y&oL;uN%JXcRm@l7ej-1sR<6Jc0KEYP;~q z`BUbXX|Fc8VM^#f6<7rgE zq+b$M_oRef8R5!|bt&yDGZ0g-+bP(=ByLL59>$52G`Xvipuft@k7ey9&KbXSV%@>y zyh#!gc?^g?88|U0rC`G+DsbN1s93FfFNzBGh&#HSgUqnJZnp6J0*>(b@){Z5HWgvz zrwayL>A0&QZ9uG2+4G6mh=IXMO8gm4IYkRDWb^bEL|;*B`&98d)$>=}PG`^6Z%1BM z5$Kn}egotWg9;Zku+I;2j14^_I(sL!I}nJQ4&5rY$i;|CkHZS1<9C`p`bf6-oT5DZ zO7UAmX~ZTv@fyafGgQ_d?X+@}KbUmwowse&q0?4_w0-I>$Z}-qjzTWmE{Zs*BZ)}y zTES)@$Kkm{oWu#LgoZ}UPd=MLK&c}tJ8%TAnNF+Tg*yUaMm&TgN$HOGp;~$rWKOc;qx08PqIQl^| zPPERpNfplI$Pt#GNkO^zBdmyU*f`?7=d>78qmy?)*~e|Hs3>;aDvZbDr>htD<8LK? zNAcT=@%c&oN|1Krw+-of@ML5CVDQ(2;Ha2Yt>8}8>-$)IU6mxb z$upjuL8T>~y-Oo-2N9S>1p2>&z)~&yf7~*&*~?dn2)J@N6*Yt!uCTu$GieHAuSnmXoe}Ue6U6jE zN5n|%3vrWWZc2sY8TJ+xk%bZW?I@z3+hv-o+*{|cmALD&nVD(ZSSy~cZ9?xGgJAW6 z(3gU2`dAgD4t#oh?O}?(en@4+Y*o__+d%s^%pICCKw&hYgw?e}J78t4nH=Uc1c((* zBo(k$0S6Gw!Ke{$`a$Gny0o^(BN}`b&zlv`Yh;@0vNIjo?sO3+lups^+K2M9{~XxG zn9izBl#z#DDSju0^s9FU%uIKln?vmj*Rstt19;vV$e~FVniZQ&g^6ztND>o}S@Cn# z^ErZh!`n)$gabZk=mUxE185!v3vc2)AF0dUVUN-HTm0Gp2Bx8%Fa(oB{muC4-|~e4 zv#q-nXL)$`q2LPk4vm6m2XfMVpx_kFHzWN_e0soT$7tWDdiLVAO7O3%g1y`@w;nta#aPYh~X*;F9#R|BTnxvwt5d8+euBvc+F& z?Snb5$?kauZ{E#5r#0{{YGB6Di(<9*o}|5p<#}^G`+M!ZpVNC&hu*7dt_wGldT2qU z!epFJzxHnUGVu!Sl`+OVNEZ_?%aQ4F1xpM zU{^5TYAI_s*yJ5))iJiM)5E@U5d1E;e)y5<=f^22!sW#k8RsFyVUNm&HFgQ&L3Lt* zY+%^i=~~l8D=LqP7~FnNH~0_L&dIU$;y#tVg|4q~7qW;@=~!1>wa^$^I3D5Jn2>i0 zx5UUkOm)5L_Pj-N_(OCdK#7u4tl<=)NlCtEQbWU~)}ODD!C)^15RPP(VMdTqt5OZ*!d zc_S-ra+!^|-*;&H+!}HRUvad0&e`4vTX^Qqr(Tu%$@?QN7Wyhdn=eYAObKE>m z+VQo+KJNNCj-8H440>I59%uTOYFfg8nwDi_T9#Q_mYLCJ&^POET*pooahaq{vz%#3 zvcEsewol3&qhuyev%NJB!H1WbrDc{vqwh_1W%I<~ZT;anwg*jB4;kxkt*`oxv1~HlP!l_9smQ$Xk_kSqfq_Pjt z?cnEwp2htFlW)KRU6OqD66>UGue z`>|n@HBd5EYG$Hos%LJ0zM;i1apMPr*%O_?qJCjq)trfXt0pKGp&}z$ELYieRN=;d z3_?Bxu+Xe=5s73lk|d{gtLpKfBxMsEY=A*2D)K0o8KunRyt(z&Qd_blEjDtSj9Z+4 z@ozFIoA}bXZGjiYNITMm6*$mf_Ysut5&OedG^TnLTV=2oQixfzYdw;`dsaf5DERC!XtxU=W z64KHFdWa@npi(p+NQ6)3{J;AQsNMU!pa19c|NQxUHgnG2>+HwcYwx}GT5GRO-%UW0 zw~Dp%WfD4+{CI2tNTl|Ut3Z9?3pnOMe@r42(d01nHc=4?-n9(lxE{fU&_>2ILO;SK z1nPT?a|An{ixD7O>@fQdnEjj0KECFrcdwqRIl!JJW4$7Ge;4y=!NAw5kxgFt2^4gF zAg}GL?yI@9)5k0+nagh-e>6L^%FX)2k+qU>iu@|K?19b+fj z#!j$rFf5-eFn5JnDZ!OHpe!t0VYQxVYa0|=Uk$afI_Fa>cQKWBP(w!;C>Shi?~Qjc zircBMWPPeDcZt7At+1%&)o?-)s#?8JF1zxZLh5KfJQ`;(LT;Q zVksHz8^biV_Tp9TqiKtA=i0cuh^0AeY9q⋙`0>?|MP8nnLk#h*lskFCeu7E>NX) zpE8v$G5G`0;#|@SPFn3{QOi~af4g*CTe(`kZrqnTwPMD&{fp5EFMOvsEb?VnqZpHe z3d^A&B+Sy9Oz>8x;BxHsi7t4I%b|1*>ck|bGM_R!7@dQLo-%j+#FiCew(V-(PN5cX+o9ejrZ}bwNq4`z4jFf?DZyJc4GN`RBh@lShsA>s+BK~frpNH zA;y4kAz(5L!t??sEb@=j!i0LsB7r{e6EaH(ByWuZ-9p~zf#J9&HaOagp_IABfxK1B zJ~xc3BPSb^l=R=FErLa)Umy=fP0LCiwk|VZQn_DRMJq{cN=cppt0?A^6a0N}!8r=4 zYIRS-gC*AIv3(P)9q1P3-FSPqu5C49fRj?~cKn)~5l z@Qj#Kg+Y&fL4Gw61>>q(@)Ag`@aqV}J|gsmF!M@=R5ul_Xj`I%kj^Oc!y+WT0sP&SuiU#MB4ri6k zDHi6!4l2wFf+`<7Q8#u%*|P@cG?!-)^GhgDMVneKBC$M9UOgN+VC-g$OjLc+8zFtppxhn4y-~Q$0T?$66T32rg%UZZ8 z-RSHuFHkY+aFaShR}jGzOe$ATE-wf-6-+L(59&9otRD-MeUM6=etZM2q)4Sr&VJnG zVBOEg%kiy#j%wis`pjiCs8vQG0|fwsZ(EI7^H4Ul^23MT0a!gU3ck#jPv`M3~`etI6wj>*cJ z?(zug(*??8IMhsaV0N(-#C8<;wnE@v5TGlF4f`IGmj6?>0$=l#VFpyGQt_{eI&}bj zh;Z%f7<1I{TeplA)PXE4w)Ef#=G2h!RS%El@3E6|fAT4#ZIUXP=PdhL=lxwWrKSvkw~DXI(k$)v4?a9^Ww~B=o0% za`Zjra4xBJR#}`PmE~mp!zlEUAMkX(NIJj&kM(+y%YDH6#Lu?3zJ07gtyrD2VPYh|v|?jy~?k^&^R@0{OxX5$I+(1lO-rS&vM#Is3b_ z28(l4HfQ0=m;8;+;$Fo3teShP4h@6a7+)hBWQLp&gN#qsGnifv7&^22%$G`t)CxoZ znos^(WXIHV)B8aNLQo7up7$~Zkx8*Y`0Yk@j7BpZrXH@uptNZ-94R(wlrT>p`<$0zH2|cCNWrQIF)}zG@^eOkpAM~ic=j)XOm|@v8jYRQMLVZ z{brW+M-3ZDJ!2XQZdY`Qu-L8qLG&N$dE;7t|BBuK_A+n1)sKHpObDd)B!kdT+1^8w z8rem$(YU{8;P6yjU|LDI`8XVNapgYlhxc;w&S_S_Ys+n-krg6Ch@T21NY+mo47r?& z-b}cGP@6X%rRz#EFty-W60-udgyb;-n%#wGjPK+1FkmLPV?9s4JwA}V`kG13MvNuQ zHrQ;dDj*8REJ!bx@~-vIwh;j9SU=3)V4+l`0Twnf%xXzb1o7pb{awcltB|f`Hxv->v`{EVFaMy1Tmv z{eQwZ!@%>{KVj^_cT_IpqyN6TVKDD%N-YtsW3T(8am3fCQ~*{!84d-BNZ0OMY(ce$6BBg)MlId zfm*etL4ChbU1U-(y{{xy`?0y9VDa0ARoUeQMUDcCv0!O!f!S7Yze8;;R~MESJRlSl znhLDN@Y%0^s6oA?q2NJB!9%qLONLG|ibN`9ZJv21pz;q-o z+oBHCXqHf3`ohAU%Xo|0H-%q1jcL7`n%Se*%R&>CIs;tivh&N;50o2do4U|uU@U60 z#o%R9TTBL7#RWI#Tmq-Z4)tO<|FPSbY@4vq-05j1uPLlhsmx z+NcgZ6wc<{$D+g0|LA-asrXs+;k^rgW7Gkm#h3i`q2Yce+)r5%WYrugqXyR%wsZQy zbxXd=GXQz(9{Rir^H*8fAZA~GE^^auqswjQ2Io57DR&J!0q|07t?OF7eQ?|6%?z99 zU!U6;DX5j4V2A{VyoHj`X;D95G0-M;p~=7))n=o?OQ*Kz3^I0p#c{Vyy_hRoQe3>G zY^5u7W5n9BtC-mQt8(|8;|&o1Nf`Y|Ec20t7XR+#2JNVaUJoYSF;MPu*Jllu<+yUc zzd*{i=PnDVRV$sfhHZB-t#^{Lb?OIn23(z7$j%oGxEqF1n;C;w1IW!FYx&M?MA=zO z^!g>(e}(R5v&~mAhxq5@{&9kzB+?=g*0gSt%C7&7OOb^x_|2!po+aU;jFg*m8t6c! zr23o!Mn>z?=c!Ms@_KzRZ~fou^VOg0Gw7e4Fj}83o)YOFrTVN8BUF(f(Mdp=&49fK z!L9s&yBuw?FDWZqVy|*RoTO9V4?;J@UIjNfv&S0Z!}q)CuO#skz6q@AVaIjn1ySSm z)XJJQm&#UZimfWkf2X6|tv?b%YJCKyPeJL^ip!Ri8!)6Fuo-BJy3k@^T0V1QP+)Xm zP&hZca+d{;)WQEo9opP<-T!+XmV7JKVV-Cny5iwyt%vwe-SkT&%gU*!ng&&yQw#>f zKsnS8I1DtIE)0wfvy8#3UKzjuF7i!J(h!b0zNbhP8fk=%Q&@3_l}FTCU(04y&*^I)im^uN1=! zV@PqKwh$dg`mPWoZlWCwF}bdV-Z}OZZOv-HLfNZUT0_+xhbF<;^6$gQ27E*Y^W`M? zdTd@qKl~$NSTFv22!NN;&7|r^@EPBVuP$JfehJ571tveNOPKQ_R#7aB3lmQBhei4h z0*8EFUC%0^$2kUpYCat^@^M%f0Ouy0;P;F4WD;k=0&Fd88$9{xLYGYJcVMK8Mo zC9DsHOHR;fPF#lr_ue|O^)=}U2Pu=cc;eQHm@r6cMWvYhGCKFhmWiPl=)?t@i_%6q zwGnSjjrbW%-}v}RbEi!b4ym-sSI~p^lK!IKxJYbk<5WrAVkI$WiQ`)Sb<^JJ3}{8= zp$lI#J?#oK;0H@0RFAL>eCR#!c}q#N)$~9V9a<}AZQ2hn8{f3ii^(<)3U@}%_lpU% zAOu5FBhY^wlaK&2efh(mhsA17K}fChnypKx5JjIOsr>0n5Sgy15PpTlaV;`iO>aAn z_yZ+G%mThv`x+wG(6uCzKPJ*U|Ahy5F`^(N7Kx51+y4sGkBnTVbKVl6N@fIwk@_|) zQLkTN)PFm7*PVR(CCR8j|E(nnw`vk6vi#vo73+T0uDc99t?|w3s1Evhl0EHxg*BoV zyzo4-(d2-KYrsc5bii@r!u1zlhNxQD@o2uLOE4K~vG$?C9zDDViS*ZhHL^w7?*nyMVD4zh9d+{(tFGG{8+E0=2_E+m7FQ1c@G-d@thaAeO%*9#<7K zL$_`OPa_#&M6<0pON8CMo}dCA*>Y_(`ap|ra4x6sks_T`MdNU*ii%SopRYYBsu`oR zgl-{(8?9z#sX7=S@V{X66JQ)d$}Og$E7$%DIh4{dqd9yuoJ>)^vDXC#s2920w&~{~ zV%OB(4iEYXN~806nk5|%D+?CqO=4da;&evmhMBSOnJ*^^QL&?@PO{Y4RP}XJCyMIC zTt!zWLS2Y;k+={=XNtfO`i5+)aOllBdNBwb!g2W(bLY96OG&lh<}%+NIhYH z@$NA2K~_&t$5kR~8X-HAF{@JYDaL;^gsMmBB>mV{eCwkBMWz_T&LQZ>rjLq4C=KeP zM@T`)LMTSCBRCPZBh(|bArN_qbo*S7bLgP0bgUw87DTniq=`|pAg^Ui0SDr9)2{*9tk;F;%dpb1hD7tn zMUNPbWuemYD7yBO)?HV0{UFkxkqFHAEXAsuGnKw~(2XP}ZWf(7)G@~=YSuxoX5+X6 z6vVRE)k?P#b}iHvNE9nO-27jL=#nACK$nzst=Tx$tG(l5bK-cSQF@rfLx-fgjPdY` z=f&{wCEXi+MtJ5P3uOl4A0+W6RCz4XEbYP(E~!p%Cb)?_bkPrAVA;G`MkNK)q9otA zS^N(1ZmcrCw4J1f9SZBZ_}WkWc9Gn#O20tjn))tjn}?!iu}iKB^oK_gqhnd?7$v^_ zCuDa%bUA_YnU$hCvw%NyNk@&>=_hDUU-DsC0SQI`hY;YGB;dai-~-z0w+A+}nXOG? zH~O&;A?qmgSqOy)MF_KJ6;2pR-ELKZ?ELLovKLK|TEk*5m3 z8U#K02B8cAzP)?R{sU&V+3XE@dCwn5AupG7V--I)Yb%G?>CxKW!zygKKO~D@22-TH z;5$@Uydo;__;9vvz*DgJrFf%*a(0#A7Ezur!4%KgCuRQ^M7RoG=gK-z-_*FM4@cW*12}x>EBNIwtKQ6 z`=p%s+u@EW-srj#y7iuivqE$3@hIxzDk`7A-d_bXmV!V>0jV3Xfr@S1$5ieUTX&10 z>{+NFlW8(wLep{awxo$P5p=>A3_;!H(?FbprB3k>jfGLzl=qIEP&;;_NiHGmSO0RQ z%DYbvoJk17mW<%+_8{QwWCPh)17|0vF$z6!77Cmx5-1#!^`LEf2%{crQiqhQ$CMWY zn+nGC7K~*ILaM_r)fT`l7HgfLTh+7d0=xX}_PBOFQ_{Do=zT;SlhW={2(??c{+tlN zr;7B)B)aHAX-}_u>FjjuDwKZ(Gt_v;MI0fAdoL$O_~{`#VX)up@}TL6MD*6;21 zl=iql{;J!f{#;68^V-86D$H7OU%NG@haYm&781!1y6Hmcn{BH|cMP~a>d!?aE~R}` z{n<{`pJ&{34vAJXS{ZD%_R_tCqHu*p?;M+wEq7L}+c<^|YcTrMD#IPh$z^px&dr>| zB%cxxhkLPM6G5-�RVl7ftxq`l)K~Ra6CTZntfcrOqnzsCDo4F1jNx@YG$W?l9)a z8hEAPq?oU0*FAP&zLKh6@o~HLo<4))BG%SkbC5M8K^LIlzi^Kz45v!%kfoA#eC~#Z z3q}>uo_36q)smmFi^He%Boc4qgKXXk3zW4h>EcrD%C{JtSX#UKV!2NM%uRjniVAcv z6Cx(uQuD+`R>c@6^abwGHrzYD){nJL^x=27=^&{@Mt+{1}a0C^;9aOq3n#EVvIfwO4j16TDoQ2_Sx(NN7}^F+2zV`6Yvku1CTH-4B+1y zWbU9EoK!;=MQobkN(5M4v!dHIkw`68CXiGPqcddN^S^yhVQ zGXcxiUX&!D{`{jjai2+lL#oC~SMxuXKh9k8RIfbueJxk+YG zkL9ZD=u68FZcCm_=a5;)Oo-#bJ{XNEe7i(w4x)D+kupMJcGr-E&@tQ`yK#ez=iKya zPbo+wO3$UD#i1}cU9LOVW#_C6}Gtcr$jqOvNjhnUxG3mFC5 zNXpqB=ulFQG}X@Lp$31}zcKg8&v|b*Z6?LA0jE6kg=}QLSVUrP%oh*!#03)7{P6I| zNSja6lZV}g_a)@WMvyZ!OlNqiO^}04Ux$>tVp)4>JL?;^&b7_%$PX?nUa_j(I`_9q zKQ}h73&lzwH-Bnad*Pa~=2JRB`ht;PyVlCMDasCh#EH<4!2Jkb1fdY24EsF|!ixyS zcz5Er48L~rjIbS{4d2uwz@Fz|_EB>~@OWRt<+b$g-%piX!mKrLM@Z<^u`FwHE@|)n z9kZ9CrU=Y`(DnpZyt8|noiM0_Ha{PW*ImXj6Le!HLOZCLZZPieq$Dc~?-TxT2?lwm z_X&xsP-PXnLf5I70Ct`IHoHoy7SasCZ{5e+}m-tRCtEy);Y-NYc{L`a=SbUXTK90Y;F#2{uOuJh@KO*R)k zot?x{+!SJ};;WT&B3h58r)bf5C{&W8DI-l=oJDgXOpl;SW(+}&6fus(>)`VG`MG-u z`9Tdte@k{Ao{#ZqGEb@tDRjQ7AwRI;*72zMN1rgsJ4DYl-IvymT0H4XixN;oVWM4- zt%9j|;;QWlI<#fXB(&wjMYpheHaI27S!lN?R)tZhCHC%x#%EH4ytn+C8dMr|Xoml; z(67d#2w086Sck6vQ$@BXFn;r)=tU8^TLXy6TrqYV58MWH~3|zdw=v1 zqbR29r@LYuGisUSM`_Fci%V~36c5w3&o8p$%hTqA`B=s0zCUk!g2Qj#p;X4t1eG=8 zm%RlB-G4A?@Qch^gKteq;OB`tnaL>2rprhZ;u822F#7Z8HUHiqng;Hjl-)?J5~$M9 zt-sB1c!y2b=~q?OiywwFiubY4H|kfFCRk{!9(H4LX>uJ790v+CC8TBhBw$I_=Tv?s zTEhb^G-XMPOi6$WDKWQouV~vpoV)Ox1Q_K3TnLj5WS16Ax@BJI=W^71%@f{l3M?Cu zKE~n~?ObEGd6yPjH5LMc)UZQa%5eH-UF=W2ekSUi>#f)CW!YZ8=(=kIfieB(G`$2a z><}OaApUo)phVZeHy1C){s{YHAm`P7DQ5;b$Jzy^l%q6^CuftiMf8sE9`Gwee*NcM zq4%n2#~)CJ5Ou|{o7NIkZBG#VRt*W!q}B_n5{xPHOB0N937I9Y%1eOL`lNYL39*5k}>L%*i#M4Wh3+yI&X;`8ud8y6| zN5xlcnKmQ5#{x33h6-QC&=W5q?+hj`VM?Ix^BDT__oQ4O3jIpOyY8Na&J8;x%$bXk zg_7rf;scT}x}v|>+Qk;&ra9JLln}P2u)x0j5tLHwS`lM4B|qi;YF}wW`4QUYZL+0g z5rUhSTP(jYXW&vGnZW-h69O|CzwwdwJB4qi(w8ry$TPMnf$W1x9d1IxQIYGz63BXc z49*0y>F-FLQWA8sd12FZi5R2EB=`NR$o0a*?pKTXN8D_P?ij9T%r+Vq2+cWIWWOMv z@Jrp=r4auU?D1AN^wtjYXgEJ8Eq&3v#ZCW%#6ZkZ=spd>z)t#k@_t>+vB*tVk_d3L z71x^h9lz5_19;`P|4z>#54BUga3sLjuU8o!`i~t_b<TCwk_7o)1_M$&HR#-plRn%zDL3>C>yu3RnvNxMl>TtWsTd>#{5O}CTv zHME@Fo?!GF7ZGwdK~=?PK$Quo8k!GOM}Vu z*xDm*iD4gXX~d^Ce7Z4+E$HGym4^E+$n))-Grv@B;V&H80GWA5;3rozZFe^Q*)mf zB$N9%Yv}kbq(MvQjS?3zp7rKRp9$Sa4%=S!Bvg}xRvZ}cb?ChgBskJ@_ar#xW(%vQj%3UVEiv>zNzs3*qk+^hxx!6au*d^kM1Wgk=nW(7%<)8* zl6HO(Lr?#Yc50+{E*`8(fca<2Jdds^;#I5$?ZeU_B66eTN5BeE_26k-2;B(O@yYtC z-lo8^O=?wfT?D1ih^^2XRmsDY0RE{fjGTYX+V(DwYu}apj{xxU$ zX4RVgWo0f8lY1iNp>C8DQFT~=i%Ule6yDGw8DTNHhuq;oBi z8Nu8dqJN5riC`cZW_4_)h`3;aOv=ide2NWyGm+G<8}V|M*l@%@XHcueTo(m z-Lz?8UK+1m6wNbv5w&44^{}Iy7*m@Uxn1qtCwG?0ov)7V-W=py8C1WSbABwZZwzw2 zBX6sNWd`S5$=O$On6is>a0QnjquOiN`*~0NO20?0cgyw1$98uG^>=a3#vuJ= zdA%6a-^l5&%8l}@HtCtYt*w!RsoO^(au~-g-LRgS4_Ad0s~j0M^Zm1?z-F0o++lP~ zHJV}>(-e$B>r;KE^~{Msm`Z4t5=!H{rvw#0<+N>#VfAlaWH1#+2l>|I#dq6-vN&hC zBX+a)#HFNKXTR@i&Zbf=SSMqs4K)p4*>oI+y?p&Gdc1NF9{ zBG;W_@TrLm2@cE3f_X{tHh(e)il7gM!(mI&LsMv zmqq#=@?53Oi!TbYy)+G%X60M+tI9V`vAlfy>cr=*%My2LhC08@&&L>(&5)M zJQX+JHO2_8!rdQ3$b%k%9GuD;v4)UBez5%zL~^lFh23nle=Q* zpU4VB?rz2UJ;$9Fuaiebj`0C8<-UF;xsWC+)`wC~M$Q!LrE^jw<{Uu`@_OHsR}skz ztJOcgMRYZ1VAEyj!eIo8s3t3^yX{UhCGBc%C2KI%!D?zPeS~ zI!*Bu#?W*YWf!PbAdwdbj8v%xcD>*EhnY;+Gr@>bUs@G!qiKj7E#9kOwl{Z`)Z5mO zNjiDN(0m4-h_DT1aKI<)#y+(0j%U2r|CWsT9=Gte`me}6(gG$TDLOB{Ts|+f&kx;nz$zm$#x%&Iv(DOk14_FaH4Ov?sbO7PI8brql%IMb`aS150da05#$2yFI$z09 zF%-5+1Qf;%@@z(K0xXy~#&ywq%8!a$s1F6E@(K?63i?$k@j4pj?{;BMX=@vHdP*Bj z*^;u0;s=s*6xrD4DIGNBNQ$hAA4thG=zTp-zb?RV4P9`VqJd}Qa9w4f@U?7ZU1 z&MThmyy87OuXxYSE6dX}4*AH=D=FtX{AvRK3=ZypnRS!>=LmPyHKw+$j9W z&MRr*b@-F>&|ZZ-ora8M&VFMa8r`1()D&Wntz2nicA5{_5C;`T9BH3waW`zG@1EF0UN5=7I zL<)9)wn&rAXfo!+Vk?oe;)ZM*e?mi#ngzeTzY`5+= zVY{`VG(PMf#ecD{ei}uUb+5=@X_@=f+}Hc6;vJoIxsRzlHH*;gyj)JvbMjnY0H&7E z`{lydQ)wqD{aP=XdRndyd#0ZCnuGw%9^Xs5tktAGWK7M|Zo42c>NrtFG@tSO3qid4p{S?m&Cc~!b>GkZYVdC|*ACVZ@0>wA@+LE!lqx0bm|PbbfY>I>3j zaA#h;Nj~q)_k6gUo=OtffD3}VZB`ksfh2pdXsMvDX<)$mmy^8OO@~WROj39gKd+zu z{i9zZ0V@7Mu0JT$OMYD!wg?G#;cLHo;qju^eviF{ zrG$W~zB`ZOdU0U%ga@NOJ0sV7cLZcg?5Q-Z4=WnTDSOXZW}Mu=$;Jm)e9-Tov%Yah zoZ2vO?xV-Y;N*Y?d{+xRg1~H%I66*M$7y`Vgcd3yR1aG@b@Z5MuVgtqeFWQJ7!b8*vr zydqR#R&GBVo;oJg3%-GgRSI#ufD9iKaosi!Z)|h7_JNlw22TXr1K1PYc0sZyvZ|Qm z+d#Z9DVo?+5$m#=ieXaJpkN!c%P$(=dV)?NYaL9Af))H<&k>WN7)iR^(~fACAtpr; zO<}RwkDbF~-kt0c)AzJVo@Gj>=uQIiBsnshNPkbB`LE7H8M-^^crRE@6LNprv-;hz zG0H$>8T}kt0AZ3qZ~6fbl8sR;{2{bK&Wt`Fb{_rx2Gco#l3BvNB7%!8KhP${y`~o0 zlzeZ>bmMolQFd?a<8yZ{)TW+e6LphfU<~!uGS&R`WbNH@M{ zv&?MkGCh-<;|Ggl!5R344)Pk{cYNpZrX2!paW~y$9GvllZ#=Of1>siZ5ao`)(Q;5dthU06ybOk&K=~Lf+be7YLyWzL`A}^6R9f13oq}ybnCQ82c6uwC+KQ-zq zhEOR0e6>mQWiJ}#f0L5SZX`bfdRA4zcgzZv-g$>4yMbp{)+<)VxmKunjxqat{2_a8 z<%16g*C9K1s6K^-?}#b1d{qv{!JTGC+kZ$+` zxnIuO#wkoAL_rr3yD7ztOxTEg zhVsWqhRR*%VU*-0F!we0y!py8@ys>7c#o753vp8^~^=@sN0qv6K5ZoT5NfSRHU>R6B z^U!Mx8KZMknjt|pg*KYk$O{=GzlIHbRCXm9>6$z2u#&^1U@@-=6I-&HEc_blXFqFS z6NQ?5V^dxXUy<2_T}iq{aCQ<5P88@AlDm8*BXrbru?C&9Q!fNfoE9r#qjjqb6E9 zLuN{^_jFqZ`mt%G+cJF7ZRtB58Q$gT4aN+{lK!bN{e4sVXSNIaFQw*dh5{O$MDf zEVF*{OS@JCmSN-Cls8eRnBHWm8Na*p zG~&>kF;d-}n=+V*(-1u!XIoHGMFLZDn}`cqn)33Epb*z&dqSYe{FKeSCTVIDZmO~I zYr=A@AN(X`+>zkz$+{wzG^l1I>oI@Ix?-v)>y{Z<)KNtKoSX8MN0UrRj=vyBW6k&k zWtsu4iEI*TW*R+hnJBbGkXKZCXn6d`i;i|hbU3S<@_+~uo<(bMbyU~x3jD?!< zx|;s5Loxi_+E`h$c}>OL=REfRP4(`GW~Oxxoxoxz{>>_Sw*-HE&@J}7c9LWavv z_AOMhT^eSR3v}%pcyE>7-z4dy!%lK?g%OweF-BbGD`doFzB)SMGCvuaC^PF!nR`u{ zTXdN_gv{4Wnfp9r&4GzBvtF0kfQhnpWTMP`N67rtl=)9-#5poQvt{mdcqYosX4cD* z>8#CkIWlXEnT?jrca52^n=;?GWi}Zz->_uv(q(=wWWFb4)(V+hh0NV##AUuoMqK7w z7;%{&=rTXlWo{QTw^bzU>tZ~P!*n%u#+r{UHLqaMNkdMWD3cgM{wt+H_b_R%H0ZEE zSICGtcT786o6{9ah7C9^jk&4Pm|N%$JJ;fNS@)gl$#sK769PQLZP>+%1j!jJ>yNml+1D87;oBp+-;NXCiBxa z^HWI|T_*l%n`d}*Nm;i_0}h#2{DI6XmXBmUgEVI(b3|YC zvdr*yWY#+}cVddi%&yDuwPb!`%zO_tY|Pwc$!rF-3YiVPnCn4spg%%$A4oL!A)&eb zy_qdS=10Amdy+!;3FfEiA4vUyR2?C@x~G^7<=xulX0$BnNA!|BOCq_i3DC$q-%;~Q zQWt%!9rL`h;skv&y)_Pl-i}E0ws%-Uu7}=!a9L{dZl<^IUE19Qz*KW=gxd(JS7YQTw}QdacS5}z^HGDPEm zM*F?P5WNv{BaCV^+~RqXZ)QXK>D*pmL}FJ|LK&?lwUnRvPrz>aki@TyOr2H&2TYFe zD*@y+fi*gL;hQ}Ae)6Wx8y+R(eCa(0@1B`7m%NY8oRX8P=9<Bx zgkdqION5**2c3eJL8mv9GYA%>dSm(&(q)eH5xP$I1zodV(gf)uWbJ&YHhq+u(-~X3 zk1pNsf2HRCLdv?#7G35ZP;HtluKUh#-ZzyDFm zH^vmN*h#)6N3%~En$3y_ zFZDr~+?K)VzNTsK!-!>>W5RtD2HNtcRJwhG=_LZ^NW3XPnJK;T`nw~`(1{c)mycY=7{Ig#>Ad)5Tc~{foYaP-6 zKFT7Z<+Xn8S%9@v0Su%1DBJRCKMoKgX5DB^#g=~U3B*)XUXOXDU)xJ!Dn?_HHuqOl z^pVYTC(gdZAi#sO&aTP&XQxSWy@UMGAYVARmsj*fO=-F;hSo|095P_i+9`1O4vAJd zc_!{L9YiM9enE^@iX*n`b6-aqQ;!TBgzLV!?9(X#JR zjJ6;Cpet6o&=-y8@XkRVgVUfb|LB>53r5#Elbk(X6f?*LE}Ntm^buNzm_lurZ3WW052tEK^hWGvNxo7VO9tuxW)OUF9MmU3zSWoDrTj!*V zPMk4M>2Yml_i3%BoKR7c= zn)0bNn8l4|Ala>SGRa4nLTP`1S6F|;527lYYk9ymO8vp)cq+cz4xHLY@#?ER8g!Tu z7=<-B7(GlY2+}GR_a)u&se;I+;B%BFQS$ry+V2;ISpT*J&gi7*)6$TWrGA2rRMIEN z+fAsZ%8>s82~Py)9prwhE+$H7%D@G_5)~dJUyvtgdXJE29@qDrXd@5FaQ51AD&&x< zCAY7VM#MQ$Uey0*QeA?)9|4`5$qd(*BA`Fe6O7qgzn?oaKWTm+ZaN{ApGhYz>4%gm zj*en*53JV?TrXg4;G$xsqpFv`LU}mM2@?265BvaQqxnCeOu4D&y0DXik{;!(KzVkI z3((Lhx+hHPQFSvJ4@ZOOG}1rqLm>5NB`Z@isp^D)Xf~Fi=SUqF8>KuT$lH3N)ltd< zS)7o4PE7TJ?Ap*KCUx}unfN=ObIRYb}op*$BZfg*rLMO>IlQ?QAW1Uy zJ3U1v-Sy{jiMFAbdUpQ(^DlN*9!kwz{F(_>5Rau&KXOmN^l*r5x8&(u9$$# zxDAWl=c}@5Jpn1r-q8>y&}u22TTz<*p;6ru*@ruMo?=)v`;TNGgghk^oKu{Q(;gHB zGnElIMcI8n_b8hrxS|XR%9hK&`CK^A)7cJZDLW-sDS)2cPh+B8q4r{#xzlhdZZ=Nl z!a>TM8n|=PPg;)}V;bN9s7ENHs6^;Dru$HZ;}PNzLJ;B+^awHp9|RTwu8|Ad(uo|m z8`=AoXgHKHcNddfLdK9L(HSRm!qf3t(fHmsE{@9c(kGF74pY6@F&dplqmkisw>jA45f^dhE_M@A@q>?>tmK&bDjMh9Vm-2*k zv6Z8UXW<*T`4jM~;tgO8>N%Fu!oBc+0j|CYm;;{tDDCF|3cT(nV3iO={}17-$lMNk zN?J?_Jk?SNU);%rDex&7StP1J6a7+OLstNbQF{@?p+%JTil`BsQLqB0;AvDR)h~t7 zOeY;Zlc9end2^ghkxlWB+?*UQ!$A)Z%xMXRmnl*(Loc}*$de8=0P+xI3O&UyzB&1( zJfzESxk)m`4CIk>Gms~bb}5f=nc@zl-}|5G2c`7MGDRd5>o+IgREDGj;9_NpTPc3_ ze}VZ(%4dp9F_z+I{1=$_B$%l(*oE?U{1=!vC73&8=$4jLsv?6T{0Qj}Fsv%FXp^w! zpP1iA=k~DAr?9?Sn*CBj_=*;nxI@65ESQ3#$hPN@5e~jvWza*?UIZkm`(!KGauS|I z{`>i)o|B&SbaV;9oO(1U?As~IgFIo4h7RHzq77k_8pTh7rzkN?221&x_@Bg9Ox_SW z(q{>j(Mf|ozzlKI*JJ72C$=0t32hbB(iLaUw;UTOr!&Y?QXA@j+|!1zNmw#SVLx6k ztYWwLY6BMGPTXK3$Esb4`VNZnzVj8|jaJ_!CY?N=^!?4%zxJxcw?hR~G4~VPu$TdU zEUE1?aMiz@Z)rQ}gNae%qhG{2Zbxt+?08-J=3ouH^X)uZeQNDu=20&;u<4RmsiOFV z*P+gPvE#~QcFcYBvY@1yR8deKjm0X8d9mTjoi;TE-R^2ZXQcRo%eoPDlc1);GQ$LY z|DaGnb+J7s#HH`UZ!jg?N<~h4M|UeF+(OOJMFM|LH|K*Hl3(&Xr5{9Hyed-qpZ*62>;=8kpfev|xume{ak_`(Tav6OAww!3F zDqLuM%XjC=UI4E6Z{AGwBai36SNBF@4O$eg=dX#tnBkg;MFKQ{<5o+(UNlyGdJ?E_ z*?00f{h^9faFesy9BOpxamN*QJVd}duERW*{^Jsg4m(6dfckV-m6OuW$rr0;Rxssy!Kg0c~)PEp}aXpF$jm*}IJ^8ghS zAVg=kf$2?9y3)CpMP4tOk{V7DJXY)iWsGa)L!pKaZYq@cU9#sy+dyqieN&oR)3zDHVJ@%|0kDnpLg2jqwAW1UhS!sj&Ed>!O_VO%kV)Jyva z7@R@Fa#5I1v2uT*%geL?GvJ`^&6SbU;^c3i)LO)*e~D3EXT7d()WS%ypazK%-b=Xa z=m1=;QE~4X{7?G$JZd4|Hc|`h%|YuGQ`p4-_71|M2AmA<|-TR+l zBE-a;sKVl#NM_zt2L4Uf{DP-EW@KSzFt|Km(>-&uvcCx5ga2IfD~b2QOip+Pqx3y) z%EoX!aU<{PDmG+vR)rkoB&G>?p9vES>097~u-~Voy@jTG@Gt`| zSqC#|Mt&8_rM6fX`r)MR%%3@IN&ih)YfNv}SN+&;0e(qLra=fDk!l4jd|3HKiN_tC z8|g_&OP_n^@Ok&~y_^2JKnJI!GntveSP5qeG%5QRdx36?)h zBW)Q=Ta1iF?lmvRV)U9PXdZISz3Vt>0GJ`%(Cr0()=XJd5b>TTG!1TldRcJzmz=Oxv6Z~ z`xg^m*ttj)_Z=yCP6)C;yuM`9@IU6PdW-kjoobnU>yUnz-j$tye?;9EAD&vQy5ooW zA&Jb|6E&R&u6}#+#Ni(P2k#l5uTy?Mcs3+INq*|*w=cbM{@PLIv8B(a$Nb$m^NP53 zsAQdBe(g~)pV{?Ai`=f(EL&sJnUz5TK7 z6S3})IrJMfK|c4EKRy5Aodb7&+SqX=*;t&W^-DHIrT8p8Qg1588FZ7 z6E5k}F$Xf{c_y==;xsmUxJ}!{8)7D{`90s%Hc8WVuc}{A=>@JRC??17zNkvoXXUIt zmXnrzWiV@wrfssSJ5j|Ya;1D)CfuW_67~ATwfTuLk*9n0lQb}=X%mPoO_ergYDtYq zW$HO$ZJMyU^w<&ZagE-h%37%^T*+-RtbWS8MWoX7#VgmwtX#e>~Jx7J*Cz3gHn|0Un5uTtT5)vP=&Klf6#dDV@wAIo}1 z!&Rx$l8YaLFLiEtVpWaVcD?N7MJWAGWpCPPe)vY&KWmmRL)qt~vd?j+Pn0&9A0lOU zpIaMqt{Y`9^^|?Tr|j+R=KDv=KAnS-(R3?H?@og85|@@-)ni_Gy=?t1&GMq|cT_P} z((V|vyFFVhx-g1!?hVbcA5OoPbxfu2Rdt``PH#rB_M>b2f~r%*n66jO<==Jc6&CW@+gp3dI8FKwRlT^09%%J~krX=hzx%`8zhm-KYq+vw|)uHdjvdQ-LzC5@a&9Hbec5$gJ2fJeu5asF8`HISpZ*O^{vv0s zO8=?K*~o3G+516uG%2{gac%y6#~Ra;xcM6H9a!S3vhun71vQgM$sobKIdyNf&C$ff z=;x{0-c;%9xIRN&Ew3geJL}fQOwF%5)=@u6Q=g{dCgU&y7t_Uuj+T2zUDw`*EYN2L z5JeIVDlz8vv=o$!S|1bg7dYo=oWMqgNPpDmKu{&w-qI~eSqnmB&XHw zS!-ZM%1xVxa=+u|Xt=#9tQ90VW9Kz@XFFO9eC_?TE-~iztX-O{?^N}BRrQ~8ef(Zw z=O1oQ$w0IKZ0yoFJ5=?%N%E$Wy*WG2xkuXkG0J`i{jC39g}y@a-nyNAZcmH%ew1IA zHjmq-;f|^5Kadg=JF|E8xc^l0UX8v{)3+979(SwKNoz;S+^yjnHJf&#v?Fd+l7wMT zX$_jJMh(j8aI5qLvwQbQ<$R!VHflP9_9pH;?50w0YMZA7!`=pX?m!9X$C#;Ujrk^L zxTapvY$}P#;hRTFh>1oo*6MH9WC@zinwXfHPe~bsZr;ro($ebR)Npm0zIM>to{=)@ z-it}xyEm&=qp#C!qU#!K8b->fdmClsb6Yj_b(&6XT~5urBW2XRyEg|!@{T48S()pE zn(d=yymzCFx~+ycNC{|OT4qe$-rZS7jWbb`HgD(aB!ALzAJrx1FXE)e0Y|Tl;^@P) zoS564y9tgq@o4h~k~?X0bbce6Hkq`!lSb42hvZMtE!4f1^{u9@gRAe-q@^B9>?^5$ z&aFx#g~TM*zoB{Mb>~(N?asfiE~olgw51 zFll`LIsJN#eG8YhSrZfWim&=XBPTJaVHnq&-zu!Rf0sdp~-HJo6OuwO@6L9$Bl`6*=Xzbe#kwj zDSU|2TQ%F;mp7U-M@n11Jijp}LXWhExh$)u)397Hr;fC4`J;OUX(1@IaP?MA-_GTU z<~bv+TmF}r#QfZPe7A(-teR3D3rNC9>y|G~%ekq%<&7RRn(uPwH^L3>^2apya9Ptd zF%fqQajd6dX>(H96g9)oOPd!H4q;?07Sz2BQSl$g=9}(|@8DCL`Ltd>Wq_YctU3sv zgj<8o%2JriCBt5Avw{xR9A@;B7NpG~`;T;GD$8}bX6%;7sl%qtRHvxB6DHq1eWv=z ztoWGN{@ENFBs>JX5U-ZW9}@p89q$VwdZ{*DlS(ba zK8%4JDTWsQgC}Oe)2|kXQ+*DNzygs#>L(_B11U@8OjFiH7SaS z>#=91I0QXH83F}$2fmSC7V!o2C_}cXhTlc~sBqhnj{(bDx+8`M}YjWn<~DNCUc<18mDB@U_wEDN3Sl z@o={=Jy>^`a(1}+-TR8(RL*P5&zb%!t3Ac6%B8SaS|?!4?ZImHUec-28v#2Q=S@Wh1eBE?!DdLI?y zX-E4O`}vBaf5N3ib1m(JPPr#W=*DL!+1nEOZ4iZIw=0{6}AmEX^|epR$XMx)EMsneeQq{)&BSU zeZBtw*X#d#z5cx#x#!$-&*SHu^LhT91NBTOC_;O&R?JY!Tf@P6U=vf`iUA}y2jWuF zndSg>eCj!3Fp(D<(a-B-PWc2Q&Fz_9(P}i0GX$H>X?plOpr2M|PH(WAyYkKSLnO7v z`crd216B5tw)funG74>`nMdqSRI{XoR9^5bx@OooXnnxoC{Qcv&4kX zkZ%bHD9gyQAJ!#8jDW5q8x@Ly3i{WiMs~P)@2X(1Ob0dWA;?td#z;MGsCzdLka~(q zX^iy4x{=UDkKsw4^q*>YXeQyE6WIkFCS@ST!NyQPoH7@TV9DgpczT3QbeWUDVzt>u z;DAY`r`n z?u~|(8Ezb2N6vZ=%HED&;-dr8%=q1n=N0%>;8%m+YWz0fXKfsqwjX~l;FpAF8-6`F z=cu;^rj5Wa3BP{mju-vT;Jh1hel_I$If#Q%S8qT++9ekwO>dUOZpqmvP3vT`!8q#V z^;B~6cS4ha4^&JT$G(k#Nej+levW?zp)$mur<4h06aNm<+Sg=QkQGRUjM>C{rJvJZ zk$0w6FZXjSS4BVFn`56bo|)qdujotI5DVX+#W$#`!6fc+S*wItidZ;IqGJA9+GJR4 z#T*L^WvxSI%S0;qCLLlBFxI5%c*-;}r!bQtY)-F=Dh_E)=`Glo01H7%VpVx6dOvBF zm&UiOpr{#Zk7ysDsvtAIEl{NKYN#1ct4)A}G84Sfmwh+x%S>hi5C5=KW0PT<7|6j( zAqy;`vhVm)Y%ESvjNCR6ogp=YU;Cyqq%&fZ!Ffx7|CJeLT;EMR+AJlt`0$nb7}FQ1 zK>t}7rC$23WiI*!;|yL(0(bt{uPq3?OU;0>Z$7wZpFFNI``4!FT0BbIxT3z%k`ic?ikNrhz#2187k_pL)L~nnn~SwB3kR8Jrn(#xxs2K-iIpOhV+7Og20c@l4A{a`k5U!&jKOMSvN?JeEt9gA2;c z8QUDHJVfHdM55pHWYXO*bDWnWT}^1nFtrwEv{ipe;lJQb+boQARiBj3O9E~G4rOBm zY@3*LoC;8V+xH!tV4kz805&!a1JDO{Ca;@-S7HA@I)FXP4G}r2STo$-?wvOCHJ!n(ofiV)-V&OXsOz;+Yl& zVSfzia2{ilH!!^wWsRJ@O0vDTovHprZegG~X!CLQd){GMc2Hzy&J1YZrm(c;Wc!4a zi;O9c|0`W^vl+|gJX99ZZpI>onTj-e&hNrzi@lit`C*s6d%)C*sXI$#rLCf+Fgprr zK`)b>^T@&ZJZ+V&w=A2b1U*%}mp65$yl{?)O5rW2$>4r(0LKr`v6PHXB<=4FwEP|#0q>EjpfBN{F<4vZ z?SX@FXI~wtj-tBeZ4<}S_BRH+<4Nmo_fTE_My0Me)O8duGWFWK(Qi`gD+AdQ#WujV zX$!<_4FgqNy7^4N5qrpDgxs~MZeW7d5+7uUS?`2aM+QN~V{y1hrK5zvKz6%dW}wajC&5N_!G7YJT{ll$!v9 zC@q3nlG=FgMzokpE5*H{GWsczcp#nT-#p_gKm6b*>uP&DT*PkfHb7?4(%0-G_ zt}=Vy|4mt*n}~v`cBLW#9d1q1_6#uGbli%~oY>B}x;bYbH!X4%Q^B`!$KrPgzr*;|1%k@mnbs%W z$VsWwLy;Oy59~yu?B8 zDvtieS4x8C1H-zZ#P;L>&v9%V;x9_$s+}0exRjSPJja`x*V;dqMa~Q{k_jUv_`)Lt z$!W&qyy)by4C2cJ`^4$fV!}VwMoM|sQg`M*`_D)QMhP=G~>CE;zSa`ZK0rycxH(C?)%(@u7+VflKmn<3%o6*h|kC*Mz2%qL%4WQ!|JsNIPSULYoSV$sihyAY+&#bw)r&ATOnT5`hLz9= zs89hh+TexxE;Lxr?ZF|8k-DXUpt-E&msCvVyW?2#U_Xpfg|)1h@V5ka+dbpZWw z1oX`SeGctvPLU2^KIZ;UVLx7h+424!WrU&GfZ6dsg#BTWGVZUHGXC3!%3KZmOr(tF z%gA~Z4wWIWueqJTKEC@eus>duQhZXfrVxW3@8gnj!d?aYDgIf2{S<-Y2>7Q1CzZHc z&yZQ+%s2s3US_Iy$o3gBd=x-XdS)-?kY#>)Q^Yp~%>{4IH6Cdze7_f3enx0t%?@6C zljvMcp$mG?9aPVl#y~E9JYD7<|5(xcTuGD?Qn@0I6%w9~o^bPu=0nF^pb1m$&eKNR z*4_Zs{kg#_(GI)owcfN?ci+HDW=^x_kolaSk?|O>vCu_!vpWc47)S@)%0dC5q9DDZ zbUH-KMRb7xWC!NLU!a2Zs37z`Dmd2oUE*~RmMlc?KQDEgcz2@DJyvjwrEad>JzaF25?yC`S1<4Cdj?=Kl5h6mn@^!C&;NxOx^|GFRfGs%H^D+|KZ&c;iSLHX9=6@jOZ}jEACFD2p`G4l~U*_{);qw*CyZlXL zQS)Dg6;%E^LjJo#{%d^x=1^$oX@-89^c|B7<2y{r)Jd3LvHm?@{qrlCTiuIF=Eq_= z-H(!`)yQG8w2zVxhL+a78lLALz{^{^Gh^LP543$dz{XvIA&Ih@HxWY;*8uot| z210jlq+P5MpzI-nnxYlW69Y>+(PULq$)y~ElKp+4>!#XLK#&~zhm;R6V006@4>(HJKdPO#DAxZV_Gr@ zq0<*Qe5nuaS#kdSnYpA!v|380_5_p&3vqsk;S`S<74mQU0e9rU-GU$ z@v-xG*H%7uKJR*+kG+$3{h5#b1@C$Tq=0K1S#Oq96oGUD{SGmSaX0MDWBAxleX*aE z#{M17A7VSmMwjT`Uz#x}_dR>K(t#dAG|`xC1=#DQmAM z7l4?uHsR4@Ya;qKMH^z@BZ%^$vkrpnUOKW$n=a8dIEN#L`=wOz1VDm%>#8jp?P z8EI*=^!s+HyidBHew6gp|M1|6aK-N3y@DJHt_y852jG%m$ojpVl*WlbMheT@Kak{* z_4~&pVRr!;d2WIgoBu;4eGAfSl=NPbj!aPzeJ@GiFz{3p!}mqxF!0 zJx$+`0^a)P?kvoN**)x8MYQUFkL2P){*BVTA=`I<)_`J*8_K)d5cls9`^9@T)38zR z9kQ48*00HA2kk90QKh?au*x~tROy};snVY_aK(_!9t^{l3iyJG-IP9{n8bJuaqPhvPFjkuJH*pj_VvXG%22aICK=v@q$>B*!6b9_;4uY^nV zDbFmn=g4{5#Acs#FMZ}iyz+7PhGA@B7iBAx8keU9a@0feQ*W~9TVLGIyLWt^s_4%1 zJaaN$vA@{;jCV+`s$Wq7OMgXX6Ruj9|J;v6Y&+ z-?ww+-CS88cYlNc0*fAUs0YJGj24KLSbazQ1kIm6x3CtzBR zAxeffkR(wuWXD3DaFy)s&%h(!#&17<8}TE1cr*TfiC+(X0sM~Pr?g3=E&i=E987iV zAOuvHq!0trox~kBlzQo-Eyx3Dqw#$wvJhqfjh)XY_FHZPkbo*bfho*g=CQUz=o?E$m2`v%W z5dLBcGgE!@y!NS*m-x`B`dy1hvp*s^Vv9@RpyYqo8i5-l+jc%(5^Il87*G%Ow^UPJYB$>okeBhtl{2S zBb){05TS^(5|p+_iL*vW+V;*G$Oaxk zugQwXB}`ug27F$e)z>F2p}%ek665}PUi&X)aOtf;@o4^y0H3eohf{s|j7jA4m9@>+ zvV32@n$M3GZ=>AFJI#(VK7W{yAJcXO787K3aS`(Q2pS~hvwVJhrrtWDFF&>~Kdvv| z(3fu{K6!=_=2~W4#Pa_w!gU~b+_gS=E_>v$-iE6!;*jTRZ#+XZOokTzdf^^YI;!v`t<|8-d8%C2?F^Dvz9lmXrC*zM!Wh*O?bglxfGH-Xc9x*PbE$9EY~ ziSTVg;qVWg^7#A03UWf00B(8ct)v&Ya|Y3p*(4cxH=2HhB<#NdO|lEl8mx4^k}g5I zQAxi*(nDxTHc5~rdzGLik11%$*$ z;Awz)yF!H$H%iaLt&i7JtDq$fp4Uq~^|=JUKDdY<%p zUMlsxA$p$jd0rMgZ}OfOdCywj^EB_-sGud!C}_#E1TA?*@N5!1>v_*Q|Mxp!-hMCX zyHNj}SpTZ8{;_MkgZP7F#cozs>{q1N(26yOL73bMR}J8sg+30malLsJ-lih^SQ!UL z!A-Rw5O(h_{-EdV7~*Va5GV2P+6|Iq(G{G;zjL>JBq`vn-xWb0{5#N~dm=#}3~*MU zOzTzl?YqJe{~-IqOQNpw$77cxZam6Mr84(By8(WsTp2-5I+eN`FZ*kFiwwsyh@9M{ zjQcXa^G>90AYoVeYdASrv1S{obqL?NjH3Aey!&bt#s4}(ldlNgJ&CyiX_Y zJrE=TfyxASK3druY2}7U>GM7fzxOpTh`oESG_sd80;YJrSzzzF(g>5S{U5aP%l~B? zoWL&l-?kzBFWca)=^(c5AG`}AH{rbbeEv9l1H_IlK0k?7x95-dG}CiJSlGfBusc#U z-uiuc%$UGoA38t6{%n|4TU6}`Fvu-Y?!q-;B*1Fk_&)ja$uRe1*#3Sv zM`K}xag^8CE$s=rN6`%TAg;G&?vL%<%5H8&ANN26r>ua!1$d|@n~wi6e5B118-4b` z@r!Q~+>*(jPpw%QwnT$jSA8c{xjbyq;j!fo3Vu&4QG|szo3fXN^Yn?`%a=SN)k*4h ziK3Iq0205N_sfHfSETzys$FF4&xgq^=uxpa?bNsmaSwWwd(flh{vqQElnHLMi&tb2X6M)o2hhT zZ92hl>KIJ}qqb$41z4$`a1BP<6+H<8 z@k=)*@huWE^^R-Sj`x`C>15^d^tkN$JYzGO=@a`f@OBUWA6rzI$7E_!W9P#mg#WV< zme@Q!CSnkG86UMY=5<>W8wN?kq6%AK2Bt4xE-+ljPhw zgp)TJKnFw|5`0g*B)7$efoJ#GV{tE1G)F4O1$Q6SrU^q#{qDHm0Z%VZ*9n-gy|f^b z8GjcMREaw{mT^PaI-GQ>hg3!UL=a~U(h-t)^7cXB2HoUcQ<=;P_=abx_5d@dfzlk4 zG3XW?6BKs@C^-_SJ#-YBUsp8!C~77tv$U;N8X5~ovkugp&;-Ts%X9Y*xt=$%TxPoN|c>7?JntA~h32CNUDKl)_(AL$srUgoAi;@(nrL%gv`0hRv{U2X1SAe2ySWegS@jX7ZAU*_m8qwH zM^@Ory+2ijMp8Z}JynC9#?uRx7jNQ4FvCorBq|Er=ly*?iatS}?Z^6IpvAom(Gi*W z0EK?*mZXsY2G{rn!9Hx4^xYCWxCvuBRnCHQC)P6A3#b!MGc9*fmFxR0x)a!W^C(Qt zyxZpe5;s6g5fxMZhn00vRLXV4^Qryu{xnTq>?2FoOLJYz3s2Iti}bHM4~E|dneG`> zkqfF#nml$sy}Z!>-iUQl9eLF^gX;4@J9dIKh6jW?0K3B8@YG}e6r-T0MLh+_udukP z5OI{BGh5CPo&VDQnk8X15g1IOEC_f!2ICXh>jV+vgVBP>2<#|9R0(W?AgTp+q#$Yp zgbxz60-1>@9)x5dFgac)1h!0$FKYoI&cZQha{Lr6hsWsFX8W9eHVF&vJ|<@;!q~Q- zb}9=!yWgVfR3&t4h_4m8I07`OdcZLEGq~U+lma)SpG-CzUCcW`Wn;Qd^}$?}K+oO* zK#%`p5>pqwg{rNbvUUWQ)t|$x-shnCR+F%|8}b`yD?p=?G>}gk_@OigHvgCDg-QJ& z6)bFoSODp;fw5ZwI`lO1VN+T^p}@Ht`!B$H41|RCW4bM+-=PN~k-eX`kL!=n6d{@` z=vQcpy^HOM{X;ZG8xaQ)nnEEc>@)j8Q>Qm~~wD2N}^6%nFBBPl1TLR1W%q=cLR zEn(4vrns7z@G`WIp+p86X)1W;T`=2>0DhnjE7EB%qwz7sd|JdgI-8uMSKji_gEZT6 z%7pykV*Uu5v)twYS3RL^b3YDLg?t$$-hXJ5ls0``m=8^sv+X#A(9}N z@c%=^%OC>$|0?aG$=yL{mo230|ABT1#Q}8;J=9MaboHd%ASSGd{{ih18uMe?rKn$_ zUHmaaw9D=NL$r%~*bix!bW*!U_z~?AO1_qMSxL$Pza6Aql1XxicKJO?*faWvXqQqY zJq76q?ebfa9->`Fkpx+>|D$M^&`pGP$s~RMY1$=pZWmT;p|WC=NU@<6`>y{A?V_Qs z&@N}bAEI3}XLk|W<)7bUdWZO_|Jrpe?Gie(%l6Zp1 zwcAIG&^BD1^vPy zM*=9+F41j$GSuRs;djSx?RT(S-*Q;D-tS18? zlRMBki$2Hd;Ag5F8DgT&|Ix9lv0Ky|ZBJ9LzJK-Y4%L(q{)@mg;|F!?39oU;C-;z# zZsMDp@Y@X={s%I%J;a%p`;-13vZXW!`dby5*$Me7nVE*{Eo}F}1O9dL@sP}HfF$6+ zYe;5xNl70?IwCVWPtrpN{7WQ34*370WM-kZ?U0#;NZ)^2W)^yeoVPK`0l%9RGY`qk zLhH!=Iw&&>)%UkOCI3if7OLAtWM)qi_R|o5YR#@|WoG``T}?Hlz*RCc_mgPVtsXpw zUsSp`bPl`MM9yLVb2x{ADJagO?d7s^z~38s4CnAq$;>p5qDqZSE)yK>k6crwW_6@W z_tWs_h@)L`zGz<{D>5^GHO6p_%*^k<=1})PM3SiV3<)X{k(pVC_)#ZG9?tX@NYO3} z&8%vA5$V9323?y;zMv<(ax(?}t-QFzW}0iltNVz+Y&sE`Y2ikS^+A?qBKeS|*)wIn zn8}Od1Ec8#k_SB~7?$ZSO-{IT}uYrrrUZ2E3Juh|+%UzIco~HDF;n;)mHs!?_<_uoD#%=^BJ-BZ#cX6Uji* zK$1Bm`BSpBPv9%37JD1#0*tvj1`crh^~9WO;XLVY1Bf@nMwMt&+2x5-tTQvb^K_^6 zOA~TSl9wiAFO7HI7qxWwElWrIeCbGsrlEs)ZF9sItIQV0{*9cdreFI2ZEj$S^sXM6 zA5RG(wMPAEHe?-^SWTnMCS;SThD=O*wNt}$TAY!xOyxL>%9rd|_G&qtbLo2<`SHs} z)eQFyk0~1chvLPvgL6mwZi^B4B&&A8Mzd{KWuu##_ix+J4GRz@+fCQ;NeymQotvrR zlS=vV2B))PX=SNf?c_)wgNHll6@k zeMxLQvG24YRt)B6*>LHwTr(<~dsOYER3*PJn5|Bj%`RA^nR7nIM=?|EUXWQjsv)pC zu-?!RsCjk0u~A2F+cu){gI(jD7r)6!Dk_=@)`8)q_@OCQ!e#~CQD^v$I4op&ZB&Qzrl z=O|u2xn?*&JZ9PGl95H@7d^FT_H#>@k1pVYJnF)XW3Cyv+}ef9ltPy(DEv2=xBJI= z{`Y^Jr}>F;q2?c#bMO0co~HH3dG5VG&eLrAiM+pEo#zDHz(-6f8FQ(MstN>6>GwrF zJmdNelSN27Rg@|Hj;BVN_?Ti?j?CFKfHEe24w$BZcrp)3@4{Y;iZx($@E>i3!}zkHW;(H< zga(6u?BOu8yN*@uk7xIRMfBP3AU5Wk%o`6e9uk0sZj*TrMQ|n$T|6=QNIg4Ttfxc| zWN%TfqcZ&Ot>}l%U)$m1J!ktkgRV)jT=o7X+?7*SaSLI-%qbtAV-P&rBlRSBl_$!2 zn$>;W8k1#0m;zI4sha8-rCu*!ckvEoZq^jzvHM`{X#wr(8RY;c>su8B$Mbm}vq5EvspX~b)+F1TmtIo_!2O9)# z4VmdQ{xZ`UOqZ70>ztI%|gfz|z&QC0;gubL9~(R2J^ zSB=avgF{Weg}7Q23n@qaalgEzQpRX8%H>9|%;igHAT8EjA%{lovM+>Pwqv+v)GoZa ziF7QJzEOlE9DP&RAtLD(%_?Kn{i#*DA6(KrEtzKqzKsil3E##f1Y=A!%;4l-l&hSi zL#$5E&Pjpl_h65X&ypu(o-Z#=xZne)o@djx}C(bw`j85~c|7ajaW z%9SVYmkRUbOxFFuXYh_T@-W=x9`CTkx@O3kafR7(XwPThe8%~QAFh^g;b|8RK}($i zEpz)87P7jWdPG|HP?-HzJv(y=8SYQQnG<`F3bJM_0wB#F#yZ;i;>Y7{Q za|*FVvP@@`)#@E)z*WdFKO4(M3| z-b&4f?g%Ehk0p#ccDe4Bi!#+k&MBNn|G?h@oKp*M9^H#y5P7vo2l2z11Qv3)Gz_k2 z4^&=+YdM$#srHkj2@v+Tj)cDHtcu;2db|fgb}^Z65tsp9@$p~8ja0=-qxX%6*lb^Z zlsBI#&8NhCEut-#=F`WIL+Js<)5&^SPrLph&ulVfu~CoX$N}Vc81$k&kxq=j0$mtcdv@c` z>uNWbnXHiAKyXu6sHP{9+1k~b^WU0oK+{{oInq@S7n5~kE9tNv9j-!$N9$K_HZ85X zd`6Z!$%rn6H;)1)bFE#JwOLfRA=nXZl9IE*pjUMK^g znkn;*RtBRx{|>%d^Qf#V#BuJt50HwEnp!tl*r>stD(N{onIINXfOH-`_J-M5rQO|i z=U<$B9~&e7_wVjwBOrbo!Xu!Iu(8XG78~AAqv)r|$#&uRaVWMB=y>lUlK*wO8FV8M z<|Yl;t-O)@EDvsbzhkN!{fh&ElQ%^X&DD_u2O-FPciv91gVUTuxJ zsxXS)L<*CA{@(y30-MnNZ3s{}qHwmETIm&ooePIG?~%?i1O9gr9sqYm-A1aRz9Ld< z+JAz0k!r*|{3*=0VjOMXgaPz8<{AoVKyD_y_R)VNz1s!H&uxdo(7f$Q>z+<^^|-pH z)5^b$@~?_6BgGuJ8f+QC?_t4x&j05QY~2&k1ZCs>CwAg;NZNk9BU~)Z^ILI0%t^@5 zBJu_P}$LSi`f+lb6dlO z`@$B+J^wSvr{C&G)4Lz+IQ~Hx*TV;4?v-#}tcCIaLb)Y0Z+29}`N!7-bfQuf!Bi>_ zuj#43@FsD0-~>KqxJkk3n9yk3g-!6k_zbSNk)JMVV-C`~D)MhL;h#pVSiWm~`I)`mZ}O`$cCTv-`j$yi3W zz6z%cYL?gBLwu179OeF{Jf{?fRPdZ1dP9a^OL!G&py&rkKhaCO`<0GCJe=UXUCk2R zE-~Gb>iB)(i!O+~>4ZM5?yiJ@HdOu@%UbSYk42G}^adLWvnk6b_*l23dtY1UN zDm8@5(+*OmIDVKApp-J2lB>#a_OSi_0gma*KbFv_c#JRGf%aiK>p%NmvM>gI>NR-a zjjpr(xQw!{)43uOPS|8LynbjxJ3i*@Ot^@iYj?kWEWsOwn@Rdtq>}7&GG#`a1xmZU z=y_M9*%04DHx#<=l7a6G;!tI0Oqh3ec6Uz5WgJM(}ln0 zr#F$}IrCCSSjN(Kkr#PP(LBdk%SiebQk;$L`mOQMK)^C<;hNo0c8RoPZw-qZ zljw>4{)&3kld>I@44rVo8@S>u>BVZ248(?}i4wN?D$JC=Dmp*6tmmgx)Ik(~{Z zF;7KXL+!FkzepjjQFbKKr^sW@JRDE+RL)6jg?U=d)X!2O zq*lBC@?P76{mFtRbnw06_-yV~8DWKLj_qzlKv4Q~@)?mCW0qL^zL~Dy_p@W$J=cZ! z&k`Cn+>0{(DJikP@UYag<%0nobGcQdKwMP0p zNx;3r%RO*(K9XKalGVp#ssM1&16>Ee#DO)@l?NG%sAEmM&X(%II*GL;stV*M; zD*9WZuApOA{9AA(f_Y)fq>TbZV7Y6rebAdX$QEsmPRy zDxXMsMYV751?&XTqhaDHmv}GG9qQbSS{gJruIvgUZy}GCOiliKxY6OU zOEOe(#x%NW|AkVWs!qoMk*Qs3#=mtsgbSx4&rq~pPHP_d6#j&R6{=H-(qt z`wyTVt9m{{q8PakWuHE(RIeSp2$z)&J}fv#XDCoH60FB&ZUkHnL&aI~Hq1Afv4noo zD<5an>8&usE9K&suMu1sGn<4aa~kE-K{I8k6Y3rGLuAzU`{dN&7TSMf$B?w-%XgBTPONP$ zeu^#(0-VG|*B@kbzQarmWf_}FN8g(ejH2Ve!}qBfnY1M_bYA9P?tw3>Jl0=(G>^5c zKq!sSlSixLu}W$I<{VBkA&z;hCdX5{*4w{_2)wieVbM4Rr+5hI@CSARPq?OpSAPaNBGn-A?dn?FpIEy*;S=6pd&ntuU<3hPNa{nON4r-%I1>gZ;U`q{EVE zepBoAk4f9s9p2N}{;UYVd zL;xZ5T_>}xbHuaM&{m}mVIBABiH;TSx+C04 z`vK!=W%M-l6fH3k$5zH3hX!{$kpH&(%6sFy@5qETtXAq z6mxw2V3VAeDL~+1AX1NBKEqJYd4e+PXl0F1Au5VsVHB{bm&h=b|N&KC$ymxfR(N9@tYPStukbOAmFR#)Ze9W;$)M^n(?I}AO! zNGnQDj&RX5?AYTG>jY)nbH+N-KGxf8tLT3!A3!VXFgMt(%RS%F0Q=^R7|bX1I0CtV z<9ek2PTxRMmvJ!<`b2!KVJ!}zKai9u?gbHmo7E*oyN)_%CeC|hC{z^_YZs@kq zaQbL5;!6HE*j4by7K_h1{KdL3;4M==sshIREod7+T=bf*2Fp=eE-{*D*-!N}&089vf5z*eGFdf9}#EbqVI7ccFTF!CdF&5j#e#Tku*zP15?LlEsfKD4Miz(%i-3 zKEvdcwoUv>c2xcMt13^z;fMijo~2?d>4k%WT*`)s_uI>C>&gS`1A$$Ez-%~5+a9wn z+GZ=SU01ekdl~4?KssE8Rm=`l>TIm!xVS5}ZW5O%>KEgaNB_+m@1 zw5_+n8|->2mzq)gyq;ZJ_r&EbMs?xL^W1%(Y9-nG2kd-+_$!R&mKzt+bmm)_pM%VX zsvH~_hq8?Rf61T5V?)D5sON2Z5_!wA)c}HfGtyWcN8mT&pzrTwzJdq1Ms-XHQxjjR zjsg>-K~0}@9kI`)qm35}bwZyy&Z}0nt99M#XljeGVm(crF;;ZKiMwsVY+IFD?NhUq zYzwTn*=Vjot?BBtAqsrAdKetNqkN#oR&mCN%m%f-hbI}uc#Q4ZWvfu07feG^dv=XX zk|?_rN#;Ex1Ze}Q=&br?}>%8{obrV*O|(b66PHKtrvHdVF~ehPi&4F z`DkN7ab;vZ@FLhsaw=*nE4J8>S-ZZ{R#T3Aj1q0w0%bM2#g1~cwRu=CSx9&%CN+Sw zvdiYos$5(GZ-LHb-U3HC-1MS*IZ}yMDHz186<2OsYC~m!^on9zj?dOTo4EmKBusK$o2YtwD0I$?o<^hueC$TUY2(+ zETC-47%_Tkmu*>mg{~a)g07TkQE8;jtV+xPhL5qM*&H5|Q9zN&C}OBio2}TUTjCHR z)6g~BRxvaUv#(5p_5r!#LRke>X6q@p9U@=>Tf)V)QWK3=DfQWh>QDHE&idr5C5$_A@rhMzz|4wr_QGa9Me&lWKOV1ScKb?`n23 z?Ru&^mJ(v9zBp=o+x~d?WCIO=-GT*nH1(dbVHX@~wKY4Vf<5KIL*KSLHQi42VSA5D z`Chx9TgC&QZ;YWDhEa9VRK*sWT5p7$0uGx2c(uyzD0RjxuK0HGy7D@wuF4rrIO)z| z7X+V{L~j8u4?roAyc!A_)NCVmA~q>pCfj6NpEIu4_HA!bx!1`GI4v)@`kb*B3JIcz z)O_NoGfx#w3w(zEeO#l1X9RJi3!k-vP$6lxVS^*}md4Z>*zPOT}2Q!LH?C5J0@l0t&gN&qKEMh+yXLBbB(vL0KkjR40_G6Q-*zS*U*=yv-z3 zsnYax3#mV~@bFl0viFi_Ceqf&vm7@SU2mJT3fz*yDLA7+LN1^_t;1#NzZ=p?3=xK{ z7$RImHEC`twd}?OeXePMN*GBtV zg74nVWKW?=C5tGfbqAc2-;dAKvhnljJj$O)#Y;A;3RQqMB${3H&j?%yoK56N7Jc{) zBtYn8%_#M3rtCHjVGc=mS!Z#uSk>EUEAbt(xiv7s^+zbAW79|3ZRdsfcl)M z>xIcPBbh~MG+aWVGOu(U>P3~1qlV&OzcitpyRn5RbL(DzsKoGRUexE#Sc`B{I_3cIk#@>H2QTd{BKF+X@P8 zW2p_d96A$7qaFGjR%51)iMg%0ohM#64b+TF45dcs6e0j<=B{t&Zs_I^FtC>4#!gjc z@QHzG_c3C<(@CtKXSPeXc1yW^l82FUcqyN0#w_INX`ai=NuEjN7Uxna&z$wO4diNl zEm@^1Rh5dVQ_)}Eqw>HAdKl+>F7-|4(X85wm4{hMbmq3!o~%T!A=`PBzm-Qkk4MFsF5CgNkD6=0 zF;qNe=&CUvt$CF1j5@L;m0qcRJmwMma_K(Jo?-LVJGj@Q7Z$$2yk?y9#dms|uw-Vo zbGLSLxqX~RW1qMcKrgnF0Qa#_`NJ$l$TsU2poCMIk_GIiDPy&?1%)Hd|-Xy4S<( zDd)S#c;e(((AEg`H{TFAEzPUBX|DCy`kv37$V^j6;o9Mx59Q?464l|jtd2vV0 ze6yAQ=+A)FOJ^Lf!;{&i^eL|w|7~m2f$rJpJp^QnDq^< z8(!b=#0Fm)>oDffnmYQKMo?l7dk*JbLx1X{R`f@Y(QX8ruR=3C@~NB;IhMA+amp*u@)b zrcNj-(&X|}Z?4^II1nj2qwbq2kX+kN#37szkk6 zmz$Ma6DSVaeimGe9y7LS=uy;$ZoSfDu&g=)BT2#BtZPfWa8eh`s-6w#ra(6UU#ve5 zw}W?G?&D<^4D?yXJ8>q6^?$gG?19s_iCi728Q?Q?L-GaTD8>4R2{To>RB`b9Om?P~ zW#%ScCQ>hdX%UWaTN}U@)Ne8v=IhBA?i7!x9c=FG$>u(I`V{Lo&`*%Mk7OKSk0c(k zUd0niW%?^EbzpiIuX!!Qm$qI zzHlZKdvRi@NB+T?fEAdj%s=55b}~Jv@1W|0A?jq3`-t2UO@+ol=Pa4gD>YCj&HgWC zumWMj3is(<<5s1b3H!?Zg~G(_v0s@tb`(Y(ZCs}+Vrs@6;7a&|kTD0Jn{ArC;GVS$ z>Ch!=GpnP&9s?OgwDk&GmEeL?*36XVE=jG7u7?tLk9mZ*mCE)BvI#*ro))-`R9s0;{c2En^;@Y+UMyM?Nx5#rLfL z<_B$%-Kao=`m{bjF@^>FBKn zQ!8XYtMcd)J4g+!FAv^sLktDJGy~^UnvdmdBK@|w{9B3R*pFmfT7~hjH@#d<~kPK(Q2#!t!b85H%4?T27zJ2e2at) zL%Z`qY7k%u?FCe2pO=vx>ju>pfskfEi1w_Uxb4G$A&pJkO9wl!bup+|w4!8O`U^64 zH#=f;Zi!Jj)5$VC(*%w^tt>U=5r2qioV3U5K_gfPAp}QY#KhjhA9yq z9;ZR1#cDmZ;QoMZU624Hs?LeZT{=@+!{int?^*L{rS^vdanQn|mMi%Wo6q6ZdS-~0 zP6R#P7414A9VjFxU>dyF(MiY1v;(V8R3DaTGf83B+R5!blbwvrR&5hESKo$12gWMSMiZ>YcZwwSD$O!Y;%6@DRRDjNxXACm0o;yYE716gS*b`@Ps z7S#2?fcKSn@WwqVONK2o5K*-vmqAMuZUyn6L6->De!$3TyKF`iHMMkMR8eAX`W@!J zAI=ZiYX{+0L?8NEUR`?m#(*#7r5Y;oE^?)_3E@rZ_5#HMH*g;Z!bHHYa}%Dc#vBs5<-%sMhQ zjeTaxr(xWN3WSeNJYZfQq-yG8YN%-Ec9kh>TVM@9pW0QwZJRluGc4X^*r7Vi=B9Tf zb!KIse15p3QCjaH57$%15ERM;|xL z8Y!g@(2{_#*{q~bJGY(Ph% zAlvuoV}~k6bfhcuOt3v=UnnvmK=7vFGqLyLKT5~$LoDR}W{3Wx^eOrnl_j&wV>G7+ ze0%#LJjLnop*cRr8iP>lc=omQ&rOJ`>$PNJvf-9ZL1H$XzXrSz687HdfM`e&iv(v< zZ$VZ-{6rR$rrG$w>bp(6)8(2|CJ*+Wh$0US_L(19<}+eI0p#zkeS zL%U@R4j{E#UR_7fh(W-^zQfUX5KxdxC+-E0=8vD^nH|0oo7Tcos4=ISsV;psLljq8%>b-L-Ntqu-r|W0IKWAl%F_oRtDRlQx;XO*U4m zIVx}UBACRuwawhfb}pft8^v%V6iGg-7rEi9CqbJ5H;NvYJ^+e^nnS#1KQt-*|3q!r z1OJpWY4d#W1RzNBN(Rk7WY6)kaN7WnpL`+a7l+a`b8zhejEl|>0U|Rrk)a$P!8H^^9 zK`LH@j0E2$Z5$j-5AT_{-^yOs)fx;QSi8ZJrW2ZM7!uD7cQ7nv3$8lAi(LGM5kRhK z_n#0oHGY|f)h_;e)yeVKOcexf*?VNl@L7`c00P5&awN%F)c`#bh`3(xN>BTwwT!gB zU3$J*dahgAFvt~AbxTi$4#OS%qnoN2t&_sU6nuRjt=D%_eeiu6=g*bri28Qv@jhuy zvsB9(V$yi2jvNQ(dR}_*G((MbQdB)7)kHNg)dJNrl`2k_HW}_>V;SiYzK!9V4VjEz zpfCZYU{=ermWt%-bsDY^qwbV|JTi({gfd&G3+ z#M7?`+|!Yg?&oAyA9)OA$#`(%Uv7;i3yzv=1n$KdFOLYGGY0n>$FzFFCNMk!$ z_f)yxXF3BB;CCC&koKmK#cjACaBJt>uSEvB9J-kdkNNKG3$pe)N(ih@8JEK5AwrGF zy~s1{fsPN8o63cGHIu(_pBcuKSkz>TZ0utp7<}++0E4@>Z$9URA>FsCIn4h zq4X5~X&>KY9uI*ki@fWUg*YX)VY8ru!G-y!m#ZW5{29Z&=;LZk)IEWW;LnV~E^L(E zF@KqGW-8B1kEO+8!SYyt2C0|txwa1e1jgp&9_#*#;f@zS!Mp$x{K=$b)mQBBNZS24 z%tvt+YT@sMdldEq(z6bgD6NYDALyB`bfX|WS<0;=J8#{ohpV_}Of?Dr7h!J$7gd%2 zkKc3WfdTKp4B%veHus7!Ltrz5>y%S=XEx*^-|tNCSj0fWe>5ZltC zZ6GysT|#v}by z)4g-GRA+X(-o$|X_QxR^N*iuJ`qKf%^3NfS{g<16GwT>8+6z$0`hQ;L78|pqxg?;U z-%z}Hd?FVftb00(!vL~J_Wu+FEq{oXgkZN18NG9~v(0FE9;-;CZMPi!MQ-7M)B`%D zU*zIDcT4nPkiPIgi2WbOEbR>{ims>KvkJy|Awiy|Rt!|*cmn!zJm_3X506p9pb1|W zaqi-*8F^$O=a?-TT?o2`BUu4RWS%}%U&9C>d7R?HD4trb;z{k8F2=KM^bTq?M1UT*emSC2J5sLfiKxjng#{4^7eR!=u7c0&1eZ#SPF0IA+0XC4`WV_C0`;%Vdpp2G3POIfzIAGiRO zbDY2{oqaUxfXECVrMiqB+S1Ea#^%)R3p(}{gl2Tf*=BLR{#F&6BMaF`)bbO<_{@f8 z>-M4!$PJXy=mBeoBLRMW<*H^whmoilpDXf&CL1I&Y&e*lwbqWJV}@ff^Ae{{Zy}+a zwP(Sx+?3Rw>~&@zABmH{1Bzl8C^nq&{NId%viXU^MG1snGEP32uU)WqR!=J6EZ(l_ zz){hq(KFu1s7wROfts8ieC+Mk=KgeR%Iv`G6sv6Wgeoi&;i>1i2w3`_gEAxh(4ts0 zc6H*Hv7 zdj0k@D&^lr#-?HzmnfEKy)8Ye%a6~xZQqR0#KW^sJv1N#sS@3#nC}TqS0u|7GsHq? zluBI}-rl3yxAVC_ht++yg*>-Y=usKkPr$)c62rj_(zwdK_ijlaLYCjZ^Wt-Vy7eEk zzMw0H%F?59F2sO&we{-^fVTMrnIGbvuL*Q46l{kg})coRG%^f=z; z9C!DqHbJYWY3xOt ztA?&PdsK}8@=4Lb#rrB>)I6sg{H`iy-h#u!*Y3(KU9xX}G^;!;0s{r6S^Qxgvjobl zuiVYX+>OLrJ5&2KDIPlj>;a&~@+C}e<}80MGyUb$ASjUowdyPHQLQ}m?Ay_BoY|vF zWq@w|;anzW!-gZTuK!j*eIgxkAWC84$o8m4dQ?L_s@@)zuSc~vtv~PNuP!~Q($h`% zyHM%OG^TS!Pl)u`Hi5>ZF{`iY1Kx~_;v80=d47s+D2(C2~}=;TLo@j8ZRGg=QGfjjaGOZqi?|FjC&QCvM4(>> zUC;8`{lznuCH{UmTVp-P%=1`NVz^m~esfO8-t9DZPV23NGr(Dk=^XaFD-`2c?tgn7V zI317|&K*73(Z%GRJ=IZo&qyz?!AchjObV>l+;R~Fs!0K7vCuAGd`@-DiimlO+7lY95_*YY?{G!i zb3s~!W;|Cgf4$YmM`8US!S&-BSVsQ0Dej+$e6fBM^?+@w94ym5y?sdm`|0P80@n8vQQ)Sc@D7(a1*8Iqoq>b2?=+;eI+W=2e zV&yvJjN{eO`d;WSJ$xnUIFZxw3q~f`sC$DPfU!d0Zw>j^LnL7?xRQ39TzLoiZf^b3 ze&^UZdV><6JOeY8mm>l$R`oM1g5V9X_1jcjLK~bWKxBk?q~Xw5*fUzliuK%Ks_rR? zmFVg3#@-BGsAJbCC$AWWiYqo(B5@>wxZeED&dcowtniAHFl`%*zrGP2-uFu_M^_eb zkt-9@i8F+AhlH1hsF_koZmDx{@c1e*^348qA5y_8%r7^PS10`0vFQUn^HgbmI1Q<* zX#8*sDSZ5L?H8i1>|&*!=nZDXUzFB4)f(;rd zj%vU|;6Uk{)>~9;e48Ao5ME+FxiOXwKriKj-MG!2@yJo<+v4p1;=RF)Ec)V4rNoPxE)-nB{a2$-o@eJXSi-}@^OlcgS1x8 zOytL3qv#__=n_nbDG*P8>{T-%;3zRn}Kk8*dJ0Uwu+qevZK7>+;Wkac2 z=F_xV!8Hv$nmO3Nah2kTcli zgRhpa#Ns&OrP)wsNG#68Fz3iFns9UFqy01(s!f%&I3Yiicd;kIAWtobnMySKkkgu^ zDuCTeX{3S+Kb3YWY0&1){!4@vJS<5O{?umV!Th=o>4PB+s_z1k(PG9l6{?l2KAF*P z4z7q}cqm7WMyx+649Kw=$HH;xg}o>+Xz@<}ON4<~0e8l|Ha==5s>-uL-CsPA&|`> zi4>zMInbI@(gXt)ubiosF-7_He@s^YcbvatUyw<2vZ;mqa9~DUfpCmb!f=JFucx)uUJxs> zX27iwW5c}K1zV84xbo>*f(yL!UKdz!h{C9#o4K(HoYB=>q~b-KJ+dHmjN&-K@d6%{ zguy>9+}`~AbGL|tQ?fljWHXGL3o1Y(zH0WUiG_y4GR%g=qqkeESad4+SR$p!vtiP>~^2&Z(JuyovnA)qLsr}nvw*}^R z)+Nf9$Mc`@T(eK4*1OUgi+uy*5Th};$exjH8`<{xw)X`=$8LmmI+z8pPHbv7pi)iF z^za-4V;HyJ#9E0d*((%Bo=!=v{~3viHc+`1mAQ1WXJortcCFsEh>c7YVkd>XPr-Gc zA7-_OJS=WtXAg5mMCQTwd7!V9Rdx4dfVXiW`Ky2h)qbPzXR8Cl6rYW=#f4KI2ldwk zBXz7tFtw5O3c54wwmiec`bfn@Xv^X!iZvwHtOw`GJbTpMvXI2luICu`H@cpV>xO0Z zL*`7RKSCx+=`vV%Q7%jv))Gb8L1AuuKd-kvRsS+}s4qpost0%LDLIdt*ZfVa_J$ zEK7;5Vbr20IvE>kwyz5@W|YS1Xe6N!I$+U~vm%%2Cw(fjA;ZaNO2_Z2o;b;>v1>xh zqi##g9In&Ce;3GEdw%G{E3#h|?6Hwxtv+y@Ge7j(J>1>gEe5XKrnTCaMCzh0VYqaD zAyzhe3m063zSMiRx4pAdJhtkqD(e>;VjVMNh3-)yiTG1xg_e*;PE&a6I6PXgYD{8bxwuv|#6l9o|3l<% zYnh`V@6#ieAyyEg{NeH(0JJQMQoQ*d-Ai!D9KT-8S>55Pa?i!GQq6O>o|@>Mt8&iK zI!+%1D@L%+lxAAaT>GADh10&bzhMMbjla%!ch8Sjxc9^so;WA)tl|M#HP4p6%RKwG zqS3=NE;Qz;V;j@nBl&cE)P5@Re-_DFT9Ku*TNWB?|0$lDh|>$}QDCuKKysjk9UASw z0FIHB82N2c26d68=>x`g9y{jBx#gc-D_rpnt>|;Nw!|t6XIxVbh?_NR?Z3pn?oqgw zBL7Q4+uz;Yj{ggdormaT4`)g+2C=`6xa2qG&T!-&aw#&0E&Rz7)PGoWG)E!Fi5Uz6t0Z;@U|@}zXdf@Kx8kNqiDb$`VJ^~3ye zFX~Zca(TquXKw+=^o%S^ z#vrLhxY8Ig_w5a&;*0d~tTWV7wpX~)9x?Y&%sc7f2zSn4J-|vp=^5G4M(~hiinN2l zY3l#SK|0UIHfYt%QrmZ|pu;>%+hf(J+UqBS57D08a3q~udKdPqcBj***db<(h|Kyk zaW;mDV;Cl$(R?|@X2XU4!(w^4AXFm8%A>ShvZsXs_AqhFKSXZzAhxx{4s0V2Q5D$A44^(U);* zlTh>IdmMD{Eps(olwub#h8J3th;OZB*oZhoI9%|MAqJ&_!yq*y1kaT#DSgkzuNCfXyCbT3~7)%K*s`@X<$70ExP zd?ztR@f~sC9b$#?*2sXZrdh;@aYWqUP{7|N*3sf~(ptLD9LkfouOH4}895MY6u)Ok zZ>E*0&;({?-OA`DD}~8A%j8>h7BMT5;s2hAmMdl)5_p0e$Da=xwB~O`#kPay4XFk# z_$1?VlEGSDI^G`5E|_SHRm34j4pk$IEBI2hM>BrgK@L$k;(sQP5Il>_?bqxZXOlbW z*ULbYH+AXaRtEp%Y2P zCV;3I?mQtfi++%7qW`Zw&fglGpBw4?Or-O3EnrlVCn$vA9;c#lBZkb+BfXY9Dy7R( zq5OxQe;p&wPkz3~9T#g}J9uM{bG$Y-c@#7&N^Cgzvpw#1$~ODi9# z<2~$LSnHhOD!1oi$vn+-kyfF6j@CNUIagKx9yYRCD2A!6FDQOHHX=`EjIq0N2pbz} ziM*|R(xit|hQY%rJ3pHNJ;N4!^EPL3XyE~v!&vRlMe5$W3V>K-R=nI^ z)XvQGCd2IReArzz<)ZSW*noDn1=||j2M-tQ%Q)o%og>Hc*|bR72OSeIQVbJAcLj!^ zj&SGaO6-K=p$-IU&C+CSdLTKRdb*hU%Y9HtW-U_*wm*kPbWRNJgwj5^Q0chi^W`sJ z<>Ki+IMMNUHqdw~wpPb9PE_hbS?qHHn71!uCD65x@`prnm69||XJTh5rn?i6p5l9X zcIe&RUq>m}caMjxTMZ8x{*wr<#~f;b@wlbfNEc;nPw!kuQSATNi`*VXwTF3*tmF(6 zm)xRw@y1>>)4*Xb`YN~=ZJFD$|61XU@1Z4o&nFsTqO#C(4ftxm6i;X_(7ot=k@VB* zSl-|3Y(=oN2G{>+J6*H=g9n0ZcFk|4HT$NWJv&)mYMX39XgeVc+KPXj z-uUleM#b`jRMQpY_FtiOt{f3flj-V)9&tQ*ke)Va7>jSEb>%P%sdyc22dF6N# z^U8mI6!U85Rr{tI^2d#6L2%!*V4PrHeSq}m$xBkYVu70Odz0wC*QDX&N8?SVc$*FT zUfEpk)fEl@vGd(eJ2^<%-c)_Zp4KQ_u8x@d>V%){eC@)OmWa6@z4nuxj}@-;M$8SF zIJWaKO!UP#TQ|n!%JXryjTfY~@h5wfq;`kSg^Q?Sy5pP|{rH8wG;Dy<4zcR!bE8*E zHS&tc&H_fblR5VLtAzp)ZfCLC*f;f&E0ppyMr<3xO2Tn) z_ZJ>K`YZGDtA+^sra_V`^@w~{M8!yLI>Y~FCg9Wz^;!PG_5Nmj?{AoWld5C2+&ddu zpPO3F$;;<*ZcgEzt9Eiq=iG2R7h<0qVMvzzia*^#`&{@qxg}Qn&bXS7!RL0wy~hq% zF?|!--ZVdWHP&w5bcyuPstmBgZ*;oGOZ+Q9QrQ&c!V$hdxZE-aaR;W)|(X zrqP-l`nyHsXbJ$sEp|Rxqx6qi{TbZ0B^EcD6 zQTabPfQ{ZGDmo4r$+n?=;lgjmr*l;`*D;#7DXxEC<=(C~h}CoRpKd)BzaSPw5%_ik zq9Yv*$WqZ0g$$4v;7A@zj#AjbHG0Lq`5|(cK2?nT>|lpxp!Pn=e;IZ<%A3})3ObS; z6AlSnbiJjbJxjyzzN@Uj>Plo*=CgI?E=JIgH)@4QP0h322Cd_@1LhM~j2ZUL{|ir9 zf1_A3KD^4wR2ivp0aG#q8ll3z*G$bPY0vHYCeGFXK1#QmvGLc%*mW7#MD7QPN(g#q z;5T38G^|}dM&Au%9++N&Puk;CY-6?;V|obkz#@+8ZT%jO69kXSd;tz1a;sg6r?m?R zvC&V^#nPpuzd&(LWsE%$8AtO%n4-37^SC0S2*Vho-qLE+NK^6s8Bzto$~16R8M)F7 z2s-vUKO~Z-&A7i&uI4_JgVr%4_1zM4Xhy1b7EdLSMlzt_syjYMMV^L>hTCZ!(qWIf zidKZIqCI2etbCrDd_;jCjs**nR>kZf!KxHM7adi}pgIY(ucTgyj~W+0IW9g$C$yf; zViEB(Cz@_H_uSz6r^^*CqP#}yV~Jzzal}892p$H)5?X$YN817(?O#x@_sD!{P;ln0 zczT~aK%Z{X(hU09-O>j6IqTYNacy$CHuk!<_*`#e$&u?a<;ilgX*UY&YBWQ;Ty4d% zv4ynJwg|4bb~Oro3weXSxASjt>e)hP6avL;wD6m96#5iz?mWjymCmlBCV6l7@>?t| zZ7jbzXcWenk5PD07FRQAqVV!q_$3qgX1nVhQWpgI4mWYOpeBt_C}iPfw%bP9G2JeK9GN=_Q(iq+EWJs;KlfJWbl*P(xOtj!5KPl*t zUebcl(nl!)7NLT}%H$CrzY*(H#~%crw)^vS3t{$H=6F~cOz@X0i{Jt#_>eBIS*OGl z{+ND8J-&km7x(e#eG_njw|IE@sjAQd=zh2^ukB*5%TJ7FJMU(e5H4>jRdNKl$vq^C_Nwt%{ScnRQ_aLKJvV>rj2Xy1yJdTB z;O(XZCy!Acf6Y;m91}n8sP<}fXG6M}6EPpvPGt1odG~f0dQJ!Sb(}m#;%MW|w}LyH zd3xwlGgnO((bFm7RN9-fyVya|i&(Y4rb(A$^AHNE@VXr9P(UPc6s>Lq-c`-}MZ(jk zU6BxPg3AlVrhc)nT*kJZ56uAiC$ye7W=Iu+=pzH6!(d!+X|1Y2vI@_EPL6(LDP=$8 z7W;jw!t!hNT_@7n6BFl^rth-y^k9-=kmflE24hB{`)a@WQZuIE4?f^T#CtUvp?9hd z=&OWw7&^Gmq4-hzH<68i576lvMSKIR+$F|{P)zT@T;gWdena)ALd~h#ebkPPAl!jL z-X*ujW*iy?2@^}mS-^ucGMSMp(k_m5`bQskyZb}~v1Ez)(^fC$bKrJmZwAQ5F*XT9 zV`8ktT3CVWDO{MZKl0g5veaAIK3d7mkcJ`@8X!%*Gp=nn1s>sklN+Q zb#V&%z5vW5Ws#!hL#R>mr$n-YmaQMbtEh~xs2|F0C<&H#!f14c?Q)L1>3#YNvO8Kz z@m|nHjrydyA4@g(Tou=;wW9gWLm6)zDtP^nYr`S%Hl0t~m#_;WXF*^@dHaL=_#*qM zj8N??*J1PJf;sBz>|&S7S#oAdvOItHgWdrz+ZN~ev+hMK{`s>q!r+$4XJ|mUn zsrTP0_$H92Jg8)Hgyo+T9AS*rHRSn&_pEn%>x8{ze;53)aDEjGuWi17P33~QX2{gj zR>E=g^FrP;BR$6@LD|b+D(KGi_M1rw1$RR-ZliPP8R@I-%P@ke2qoLy8viQBIw!5n zl=9$oQ$kv$$>s$W@PnxMo@!rV4%dvp<|v(umE&8jgcwd*i&@Xg&N2RK!;ou2uj`f( z*R4>6hC*~sWDyH>WV;JyAamqCmrj*t5TMv3xS&O)SixLcUZ;hjZVMcolX5-^3cyZY zTXD^M&}92S(|t(Oy;I+_=+KU~BRh9&g<@<|!uI zR~mhSMt@d+dgrk_Ddy9`R{tkn~6!v3JyM=MNnd4j~6^ z_|Mz?@pe>Y&GV=0*33KEQP&g1eV55LMPr(-K`hL~vwSqgop|;%?eQS)L{t80jXqAQ zTir4BAzpn50BEz(-_uQHr#1Pjsb%!ZW2nrU7ZYzH-a{MgNzzmb`nq#KoLI**hioYt zi|5`$mcmZ;GO^!w{N&i84uZTo{LD=xt> zywY!4wW@52#=D>9;Lr5!|9fJfGSRf3wivz0%)z&|?blRJGtu`a`u2PAKEbqq9+09X zLA-vA=`N}Kzx(!gB?k6Wtb3ccZUSD~6#@PT#fuj!DyNwCp3^64q$UG@*KZ8i-MCTDG$>R$ zKWTw8*aCAw-`F?++_4_QxHISVNhoG#quygZgl}izby6o`xIgrueu|z}li_FfX)ym7 zLsS_34wZ7#)=f;9o>7>>M3UYIhX-LIOir#y-~9(nuHlRN;VY&qXV2Z;2d4~I&W`Z6 zo~G@oJZ+ktJ$PI{__gWuz%f%FTq>L%sQlV=gnpO)j)xu`{7OG~oW4t>81e47=?F#H zZ{E6T@U(vLEBY>uV#K?zOh+ij{^nJy2EW!1o~G|6QG|GR+H`~>?AQJT--KV_!^`FJK4>};=;0{BBZ10;ru`J*Ue~Hs-G}tuN9a2xMTmDtg3HI= zp4r*m2lU;C=sSiY#JfYmrDJc#Ll1Tz)OR1C@2(s~1CIpyWzxb?xre%q*t%)!fOo&% z>o*;i?cdokaE>72doWqnymovhl9%hmMdi6bqFQ4?J-rBG|FUd8N#KIH4h*sn1rQz z_y+@RnVZ5$PD+umgr!9eP$beBn93S1XGnIpiZh_F6{~T8Ow+UWaZPs$lO`m|>e~;! z2Tq0py8K+0j8TDBj+NVN`dJ*TLRExHJ(9Ug8GE%7!H^yy1oCmzOZyWDlHNICV5e0> zVi3yJo&z0u)3#AJIiz$ltGu1z+CtVzzr6|T*jgO+PdpYC9hL2S9H8zW zC!ODj{!#*lu^c&TDUY6UMB}#eE79VcE)Kb=A9(=unB60DdI)l(yJ=_R_!8d5_6K5p ze@=JiA!sid%46+$a+Vu6l&2iZ3mM8&4dsP0%rrJn;lCErX9p9bmS>(wHxwtygKa)K`bTXQO>BurBIP+mMY z;fQm{!Q3IR4gyK<5od0RzFdzK!N)c-OrryShsYiC9&0$6J3sc3BP}%E@(}#-&t~BA z!vBvkp5IM98*qZC7ZU1?#2I-T#*Z+Pq&XQFxqX5qT+W6oyeZll=-H=2+6`*@cp_rXBPHM>n(nf3B8y=s;9BP{)v|fbLn4KG!Cd*Fg7FsXY;-uYr?H9}_fme?F zBS9y~ymR!HB+bGI>*qE31mkZhyoKfp;oS}VAXv4~N<;5Y7O{wJAOT|N7i9^3`svQtxXIh|9 z35_NOXMW10)ks<}5urW%j&XW?RUc=u$Gb!A7A92-;_O>a0=?R z3*|hR`d&?jK3#F@+~H&UdO|y3={npiXiob2lbv%3JC~_h%QP*d+|{JaCw|50YAh-> z8*mG)-*-}*UbLE>t8jXuImTPOtYxlDm@79~VVrN7%f>$9-^K)^8>u>O)Kw2YmfiCg zy<3kt;B&EQ)j?;eO9<6GY@}ixcuZ_pkxb|dubotMheYZiBuR+XQ0Acj5+p4ecAZc^tgd@HBfcHe~F$4L<^fZzz>huTSB9%Yo zqFNTA<^eb?frJUsv5n+}Da^XG{(%_g`9Rh+G2Y~cu7RaPo<|gWh;eygyF4d+{!>Z= zVm&A$WELw@V$k)Z=Pg4kv1L9-7vB9)QXQuz-M(?W%GXvix<>B zo{b6QklX>=S?`HSR2=jZbt-T>E8LXb0H5|z^&?FW#7Er{KY2oY%B}G;Z;O8b-f^H+ zBH#ko!C=Sb#6{DnDkUw`WH-2*;ASBb2HQE<+3Pc>H(mf2i55hXfrd|GREV7_%{sc* zgWv7AfL%Ph1hY)>vIy-Ky2QXdg>yKTqagN^Xj_Ut6{?hD@Tg8+n6vT2SM*Hj?4;d)*rTj}Te1ENd#& zE3ItmE_$a?s@$Qw@S#+@lDUfW-1wE`;gYA9F5v9NswIJ%Z>HhJ;Pp<9z2Emh11*|XjPPpe~5V|1Bv0Y(r{hnijt`4#Jg1hs-&T)c8u|5Va z7@x8@)(29?%}e;>nH%Yzv2@SPblBX1@1=d34>eOgq07r>k?Tr(%ipL&Hlgzt^ZrrN zK{t^uHh!WzKK<90FTiVA4+hgSKBnM6ai((nAF1(d=I>h+rJ?8Jiu3O;2jruP4=B&bmXUPD z2%oeNKFa(RA(T7K8|{1|d6RZ)GRccr2%Fx-WoodzEUr6hR)xgMKifE6a#uVIzsxe4 z!3|Dzsp4rkOo)|RaGydNf~76|9rXP&wPFP=7x$TupVG_65Ag{jyg~4ISw8NDpT2IX zuGAZ&(=~O(l{DnKqt}(_a~a{x@#l3l(YiV+QCHXqC)@d{*9Sb!Q#?)vF0lnR7Cf0e7t}0R?xPV&oP58ktEtkp(FWb z(gczqCGq++Sss~lFfC+pv5yzreQ=Js*MCkFsG~!kB6?85<3XG4F2U)V>~_VmbO`C; zYciQS;wM+W0B{S>|BFwO6DcOeOA1*U>@PLrpq>M-MG~xD^7KtuFjY2Y_;<(`lf4=BcVqkM1uP|1YhcPfbO*tb z0ac2ec1Xb^Z?j}F<(b5-9(T%IQZmh*$vP+Ac1D(ufS8#w%S61EtCsE4`ZTGmX41pL zFr!UKf~x&z9@52F|LV1!=M;uzj@Ld{v!!fUOqw_CJyQoC&l-I^Da;4?qx66Ixr)R- zRix&0RFz4cJxPw!+rry!I;%gC^kL`s5)IQ$*VR+o_pLpnfKXG$HmNGUoZg@qdY8$9 zLsM6XZVx?h8UlF=@_YIX2EtWbteeS@>lSf?bv!pQHf-^7F10a(xHA}!M+3dMavbzB z61MFAKw!W-1G@P~e1^Qx$-?`0HF5eqFi z^2IhAs5pjH?E)@qfqtgf5STH|HgokXb7JziY2>3fk)C5d0xc9rBMQ24lp6ooU2K-X z2n?&UsO%dT8Z*o>*AtVCJkiqc196qhkYNqX7I1jaqiw*G%P~F#qN$2e5dB5V6aE-c z6mX-8|1(y_W*m@vi*K_oho1unpf~aYAaZ}DuJaQoLYd2oTH{Bk%n64I%62bQj zQH*6sCPxm~!|7~hf+uN~=W81PqB@+|!`UPKO-~6OHY8r8iAWJT@{dd--_s}a zj%zLa#Pv;vZT5{jJjQk8FSPzS#pJJ|{QxTdvF_KHB38!#F`PL})crqGqa@)%cV>6nV+Cn8m#<#7H0XQn-tWn*QQ*qAVOhQ(4G zBPp@TK5ENL4$lf_+-jLqO~b;0CzgL6wm$Bt@N${S62*>NQFixggzvHJzB+$0n+4f( z>(!y+m_8@7Qd=K#DkP|ieQEia1tJdo?2xqBKQOrOqs~(?MPx7wm$z7InvFD-h~kcp3|p? z=c)B381U3A7O%6fRKv4D%|jxK;2QP>O;+p!(>3#B7iDW!I=!a~YkpX))hSiwO{&7T zLy{v7E04T1l*1?yK1OY8fgLk9O&U{MNEsat?P{id4xE)L_ldntAqj7Uf{+BeMeJ*l zg8@>zTO3g{teTYGt~+X?uN<+U~YgP_|6FS~-8CZ`H;R+IIHGesO5E=!hM zWY90T1{dlxm{^(VE=@?B)<~+GLPE8NCgfy4D(4PlPn>~jVi!SF3G8KqbM*@&YMNlj zHUHhnz=##jGE5FHV4P0LO>tZnsRHWBf=jM39T}%5eE#}RM|k4)MC6Ji#kV~+F+6p7 z{TmqJl-7Glv@X}pydtfM@OY}&IZE}VyKy#&otZHza^tao+;E-d-w2WKD?UsPF3P_{ zWLvN4yWdjPb8+=v17{QTMy}puv*3(FyF%&)51gkjp?v^F6!0`9l5`NTVMi#rev_O} zz&M<|y%(9x2S;-_LzGo!%aq$J7zw!@BEy4X(|Cr_YMxsCuZDZB*^!vl|qcCdybacfQMiz^mI7;%+_n zSk#l{t>3SRT2$S7{@JMCG`3!xZdA0iUU>U0XM5}AkD?a)TCaQ-m5XLh*W<`@HT$jm zo$oU9qvq)*E0R3!R%ZHU!g)9@_5qL(Q`ii`P2du|;B93vibj#Um1Die)i)iwB@Ne} z7h`Q%-;1ngQRg`^$x}NlCRKv_0;|Z9+A|^-%Q0D4u&In0_1?!HHg~bHY6Ir=ZQZ>Z zo1ih03zUs_4GN?6$trTqL)oG#swB`oZ8cb<^b9;^z?Yk1DCYJ^EAz+X8@h4T+lAJ1 zFgq*EyJjVYpTnt(|Cm_Vi(kdpBJ^1q?n63C!QG);o=~#V2ZhFLIh#$~*^Cp&U4laX zbiwAxOqhsO48R;}alsMC$esz0FRjjERz7u4d>PI(S)}MGXBKN+l=Bo>OFzx?@U>Co zs=M7eMRQMGxkA1suwv?NkY!v&>?52!sNBDhGq|b)*H#v|1DD;|%Ia)c$zr~;j<3#U z-PsDC^EQ|t{!a2oKBmXSLYH4q7|GE=p*hWbA9U2}$srH0!5HF!n#

#Nfm+$R83i z)*a|ks=K6ecCp*MW(x{zfIN{T(ESA+1ykKL@;7=OG~aR6P;B4)I?>ZtP+=?n@x0zj z12sWMfu6-@xgKik>(~$jyLrNN8vmtc9FrS} z894N(Ar59^cXP4{Qn(eDjIsDjK2`J|Z`tb@! zu4Y9t*O}ZqF|{&7Vc_T`c7z>}1V8EvuQ(C97|+Lu=}pVFB&U_+T_5Y;lQmyT|msTg2p0533{3T42=94OYbP$z)5QhT~y$a z^zz!!f+AngFX;daZmz+pQVWqyHb(Q1;A9meEREszkhu8|39~X%LA-B%Ny$|hwYAY0 zm((@%XOqL5qKnkG{Gf)8@Ffw4cuYGeyKw9lo;$U2VO<8e!k*{WRWA&Ad@0z#KUF9K zJKJFiN!^~3sJGt%kJK_F+Td<__z$NJt5j2ztO>c zK0P{%`)Yo4Hh1B%=$!cXbC;hIVN+7Q=iAEZtND{K|DnX`7>fWpir^`lVb+B}qVNZN zQG`WX=MVHRi~wPO-8n-4W}OqESJ(L+{hM_*I4-1b!8}%`fL^uVtNfAYfO#SFHKa2A^XLUq&q&-r}I!v zOQngmIO%cxVUgTLpZI=}q|lq2W0q|_7m_sjGkreaE0QD$%mupng(Ss)rhfotV>Fg|4k(0 zrSvaE9D}y8os*f(SX%l;{u7Zz&^K9#xYl~sHpg3d;5`32d{^%mYe!v94iBBg(8_lo7M!(|oT!mo$yaYYlApF#uhLPL|caMoGgBa-iEV&}(V%TZF8c!qC6_%^BR`xpjHKmBGW@SSjZ z=r5i%_%-3O;bL%=;Ht#cfNL1<@hzqG7`pw_%jWanA^0Z+2$#n3O-n%U#g-+lo*ug* zX=8Tm?~{I*-$Yl~wD`yH%QI=ySKwD*<}7{|zmu6p&!SgjWAO$5jqslo3O^u{-Sp<> z7vztKA4vD#iS$FaOZVT3e78v6mF`bb6G5^~ zx<4WEP(XY~x`!iIs2^^Y?gvGFuSnjK?g!v+3$zX|ij=ub*GCNAnwC-4Ls%!c4@d#) z6o298HKu@RBizV{&)u26Y3UHqWDTj0Hiz0%hqNLp=bGqb? zX^ho8z~*G&%_pO^U*r7Zj{_d%SNPEVXbb8Zq+;!nx6J}upx>7!Sk!V>eNz_6&Vd!% zxRCZZVa~XpNmXBX1z#jdW>?40(q_Mv18HQZnn_cH+|>_Jq;edyIXZsr*D!c)*>_DH zcE<`gn^?^n?+_{>YAdZq+*;;YUGA$5=d%+Ah1Ls{#vP+?8$Arqc!D`E7 zH6)jg8ga1}`_7SgC!1hr4Rp27ECNf*_}HdDQVQxjv3gD@P6VKPZmuhETcBXRjZ|^d zOX5Kl<%>tr&yIOiFj*Xu#e(d0L^82*I|!{CJbd(A%~DWNqs}BI45^65yW zB%kh_f>?7m<x)QA1NFX0F>Lf@v<1I8gYL+Z(KQ4_{&(THhl$N)`N}OXSh@AZCX=H2)~2wnTkE)CQ`@@s;*jbEFoLY^ zy5uyz3tgGHy4I2Il_yoR(j=eC(4*!pstsbVP zZ4?eWHM~A4ldzPEgJfkP1bO*!>teGodVKr~mKGb!*VF1kw2bOnk`(1hoF%G>Q?5#R zB1LhxGAT1VavNmGwN$8Ul4`{6gJy9T>P?L>9AWZT+HpQgCuws3IC)^iK&aQP{X$TL z5pM^BE=$g!M(9a}Om5+cQD(sVAU~3>QNviboo~ZIpSQ6mq<4wgzT~c_A@MKMUN+;A&i!T2rx@dCnVYwhdhCnAheomvOb@p;#y}2 z)c}CBGfi$pTOHSBh1E2U2MRjMnw|=>Ut;Gy;pUMVx8U}bU)ng_MX>$ zIGH=NqG38DFMc_-5pec|IHyd@;rHK_pXpW1lv!X2&?6IkgEg}eipql9o)AHpYS}$l z6Q(eB2|VMqR9a+EB6!P|;w_YYhwg~6&q81Lzk&xB`26}`IbaHp8lak<^*)-wWm@2V zaJR>CQbx7a-$hay0MjJJ*EFefE4=fCuzCZ^h1u+T9ZZ!^qMkOKEa4 zhnF$7U@`lnhW(k;E45s-KYEAb3z?cl)^cEd%;=84quf)y;+5YSmSrr(@^IMF6JnX1 zOtObCOpMFSkHJST8f3J4{sm7pKDzdBij~XkJt6kEB;=jF!Wgo6nPswJcIg70VcGta z*>FK3y~VNkWhpmaBR6UsXB1Foa&lrR0tYREe#&B{uqY|4)S1ONdqUg@hCU@ROvyfK z$o8p1&TsIK z$UEPZs_tv^>yK`!dGBi4VCs!@qR%U>5eUqKO*OOfOUbQrLAS~Gczo?@$70`)8 zf}1o>aZG{9CLuHQA0_wEWcaJSFcy#GrZFU~>xe5P)I8>9LVgC^>~v+aLKg_p{V7EE zXhoD;?r3!d}xjhi$#?Jd_8s{eRW2T zq(9%u{&Nkt@ybG{zcMB>MsPEgF-*N~zW$u;cizpnP)`hwcSK#UOmETKc}f`c!p0n@ zL@cCArq@H)QiWR%A3#`r4LTWD2`(?LN?cpYH8x56Nj2gM zLlnSMYxgaOuvey&DU)S?PjQ&#N2}pHjD&7Lvo7u8B8?gSZ>l0fw_my)aw|>^hodsA zZ5gTCVWbdhi)YF z?-ndO@p2Vk)S+{S!tv+4&I=;8TkG~3m)vNE|5~-eCAT)&W22X`MP{tUL*V%~Ra*m1 zGiz>DRKVU|zi%DCOC;SC1^7i3M|CeTFw>!i$@Arf+kV(mpnK>C#6}KtoS{)%dMOoa z*~``3F4sY+uSxk2@lwI1zi~|en}!G@`lWF2qAEkzaIs=r)@SfI0In~;NhF_8@R#^Y z5y+~!k+pUgJ=b6(g|7i;eTt#i0iSv|<>@6jd(VNbjTKiMu4{NciR%EaUAVU4s>fA{ ztKzrQBP|urWJjh{{BeHdw2IA-Mc!5M(Td2sEA~DcIlbcWtC7}<({D$n#FV5!~C+PVce?eTr76<2Z{Kfek?5o|! zGdhkJ{O!2wug90~I$pKo_}Y(;H-C5>@y^&!BL6em+4?)z*ww{Ad z`wCOfY0oX#SbbmP!C%GxdHvRqe)90@$WLp`al3!V&3kI$r{$yDzo>j$dGz(C&b{8z zvE=pRwb`G3*ZD?AM4*|Adot-%^44dbntk-0w&Ejom;c9EaPRtMo#rij6J%|l{b9l1 zz8^Q(nZ5Syg9VT5S3YJmM%RRWlwjp!re0f?lozG8KJegg!yerk_W1uy-RG;SNh)t_ zKKZwn+|t{&ls%v8d#hmSXSbeg?1@uu=&QLa{Ct_`agDBHA#OIp&a&lfcs15QHlB5*_PXxzxn_*G(uZ7W7T0}4Y?OtS zjj)kER@uvjv8(_`k2t4*Oa*VJl0n>HZDl}PDQcnc1KnUddwV&1%kWvfcdLGco$O=B z!3?;Xy{$W-XK+{>cPBe;DlHD@k&L#Qox}|2>0>7HB(UQw4R!iPHc?>j0G0+p-#9J> z*_aJ_cHG_VOhE5* z-HULpK7iV)_mt{cPGjNVBe0zt@8%}7aM1vR5(w9d>?nl17LI4mN`N_iJ2&N&*0VzY zG~dGAimXFi67takX9-2IRcql40E4TeYYzfB`(qSz(TZ ztV4We3m12|sszD|G62cV8GE^O8gh0(i#o#NMmuNr)agr7^evpp%}s-u$#X6XKeL*< z3%HHT0ZiahQGn*I)3);tAD0GWBxp@Bg0_Xf4_eq8)}nZ7b0dFWWq_apr?%tEZh5@L zrRnAG8{+Tt?$ob0Zs_sx_kGgg39H&ZSwwWjlYi=eq1P2T2!O@~Ww-d}XN#PE4!$`?~QywF*&isofD1cDAml+7)%W zZbx0Es;Zs85AZ7uRUh92sGl6GTugzM1c5%G2^(Pf`x@?mqq@*@dcCGZfIWt1sR>q0 z*GDT$HHl{h-sUYeC6*p39sHsS*az>e>IR}L+u&jS;M6MAuKQn_!BmZDK%Y2pq%W+L zd^d_}gbjq1mME)$x+J~|h)eFKS%JB725nAQpdJ~ z)m4LCdO$%=?>^07GPN-Z3+&%b4v+3g2}?1(R}~fjXp@YBHchTVJ_-WC5Pf-;t$Ul^)2i|8)Q9cd(N6Y^z9xiWK2?S7 z1Y~^+g{)_31Zdh_G8&BdwK_ecS+6Z&Os_F*uUDoU!>hJ*h(P}hL1ruu_i9%+Do^2XTi#01&l|9Zpz9MX3kTrELtLkPnv=`9C z7pfitA!h6T3;ob2g<z$RNu|+lQfN+Z&39BCbB&f{QqcKRXeQL!uq)u7)~I z!>KB79fiEL4v|R#xxrW!3|flVq^Ad%!Kx#5s5aAGh0vsc$&^%eqf2Jln1lN6&o$kd z`kt)O$1`W=v@J0msXLOnW<}j{xc4eMRMm#2XW7=2mVHgZmR+R5PSF>(I0^|KrR{M4 zQnkO7IiT;jd$jwY23P^#c3cXI3i#(W!vlImOzqo0upf~aZONL3$4sW(RZ!3b+=fz< z=}QXO^!*s%OI3pb)BnfU_kcxJrT^c1hvDx9?;uh-sQ2DXXGrWaQ#lam%m|901sH~W zb(>2q{zJ9``K2T0d21`lF zm?Y(U51{0_lC32?ro^vF$&KH*oodOY7q2&dFkUkM4Ienq1t2-Uk~(Ya_H3=i8J!I4 zBW~*uDcQQwoeS3HSgr4oaf}S=Xu>+PXN!ByVHCM;D0K)j4++Y_3NmGmxh1d#6C{O~ zOq^8Cca|sjUElhf)SvHY>_E30B8Z zcjOR~^Fj_vW*fE0O8F(nIvXR{AW<7i>IG|?U?s=lAfWteBO4?LL~EDi{3Ex{%=_O{-m)2hu>8b%D)snj{7W8$j5AD(c~173Q@G^ITOwAq-L^L+Wmm zyp`O#j7C3)lJ~+gH@-tUf;QEunMHr zde`udpL1tu{sYP5=b%k^bQ{#ledP1Nmo}Ak^FVLv5G4^JDXW_da2Eeby$VqGA&gXbba;<%Ix$0DNP}4-gPU+J$() zK@3sC&40SB**0*7bjop30_ej?>Yza(Bn8L|4oM&Yy3lo+>m!2mL^T;4P)7@`*-IVY zyG_Ea_!@2KG`m81Dw4}Ko8%0jh>@Yj2+2utp371rC8bh0kT~o5U?7o79E#Ky3fQkj z@nj%+keXQ{ECJilP*4xG+brfTut6H2!4L(Q{*4*Z5nZCvoY5rQ0?Nk*2&6FjqOsWq zLeVdH4Fq-^7*p~fu=$yL>Y-XaX36Q5YJ`j;bFhJPHc0tG zMq+~~WO(Xqyhw&G4)1}kT;P^ksqir5ZCwG#L!Li*vh{g);4TjLL8SEo;H1f@$WtIC zHUysMJtds*uWPDqOHEB|NW=$=8V*@(pce`YG)TLN2Coq^QHiIP&_gO*Z1onoQ6yU6 zT}N5~T*j+vFUU(o?L8woDCWw z^_&G#nJ^hN;uIukB(oF3?hZGOID$sN5YX7z;%-E-ORY^pwoAmJ)!&fl73E2bB!uaFl5YJvjbOng8M;oR#L8SM*BAS}j6z}?_&HgF5H z*NKijq)Q1ttd$&*HV*~<$Aj+3+By)E;C)eY)pFii39T8dg+@%Q1z|vY0d=Mj6{(88 zTn$f!ak*xWGV_DxQ){lJrVQ2&qKD_C4n_)OP>_;_g@flEUFP2yZlVlENRp^%|Ns(%jHc z(5wJOf=XZw;O8b`Dma2c23`e*$oRvE2|!G!+6aVVxPVabFkl9Ci>+TnP~{GB)*-3e zY{UGoGh-hnW}3IbhT?+%a09W~t##8V2y5x5D3xzI{q{UP`=WT6dJU=&FI;Ojy0 ze6F#X1G#nPCc&CIFLEf-JlFylN&5Ijb@+dy>M}?ZO3J2u``o?-HW2SSrxJ|Y84`wT zUj`cC>a)4_5@J27M6MAgJ8_b_wsDAa4oT9-?z#-S%#%JI${s?ucdHW@ogMs`N8vRp zW!<%0@MF%?&qwytT|e}F0fPDm8!)CokhhKyL`D`w$Rg{R!}w||wfFGm!%%T#2BYUy zS>pk&8A5^6%Y^BjL%7!_Ob30=t+sJU0J6)a+z%vaKex5S>qnpmsrzyFI*cNL&QOifxu4$!T`JrxKWGyTx$dv_{b{(yRFYnqMCFFI~ zXI*Eb{1Px%_+fNzq#ttyyr)#qg^^z-ELcYs3kxFsZL)}u7-0b!oro9$MS~dv83a=! zN`+_z5LS2<#5tg@*18+jISUFqsUoTyNNoi%8$e?BTHf(6=P2ik%8P|bc~AVX)mc2n_IrOMI(GN;7HAKiU2;vfnzYV^VNq7-< zP$EGpok&7A1GXw|foebud<(8Y+;%pAASh-~gL?pcs1n-T2l{LTVWVX7ZX|S8JmtsC zx}~!UTyKLETBIUJ^&aUj4e7;Bu}xU86LNH>Z-PW=IC86@)%Zih|8_Ps^us&^F$50- z2}i5*6}X*9lLgLpZYSleRIN2XzmA0S*y#?wD|Pz`$Djs-s^Q^+I{-)&P!MCC3?DrE zIqz7_IjVSQg9o3kV^#A_pcpAGf{?)J*J z1LneiIp)X&sBMyS&<0>x;@}hvj4%Z}LTh-t+K7dK6t~03u|kE|tyIw6+zHmf=tDJV zSod`@MZ5dePF>;-0%XG@@)}_u8Xp| zczYC;x< zs6%y~$aju7!`xO?;s+P;)*Ps2K61z|7ze*vSAf_VM6E0WQAPR1f>9KVAP#c_A6rGq zE=(nie8g>4r7}3`Q7!)(VJ1jVtc|S2h^zzpxC3} zDu;-V4wkn_N}?bO;M6etAVc7Z$fyw(d2g4T5xnzlj+(&1XUz!n5EKd)Ut*ImixSBY z^NOlXcG}(70>YZ1_-AK}j!%iDm@0y@KplLT1U&U3c~T3!i65%=v&||BiyT8-W7D{+=53gy z4YeSn0iS09{|2By7GV;BJpeb+>fHLO`_uj-dIt5%~?h=_-7|q!Slf zdxbd=O_;hRs1lHq5#}@rA{6RRha16_0K_eBj44z=OchANI;6wFjHQpttd zB`!6!AS3j&IvcYP_Y5OLqSCk~VKMbN-`&DFdnEwa2D77|b7FW6!JMw^AL%Eo8|B~` z1~niMucNbpm(g(FpLueWP2p3Odf~R@jH@HpQ~Ohuz7|LZoWKQ*5NF*DQm=3uTGRcp zP5pgmLjiKU*bmKYU6NCkxH<%$zi_B}vp7o|EJWXz~=1+f*)b$r6Wcg>0g{gwOEKq8fCn<1+~z z3`aA#2A6few3Bcwu^$*NSDghxfVWrNJZQ36g8*-H2zYBK5PrAvk}ZNTQ8r^-fh^w=w-xj* zwKiG_w;D=(8C>okiIz;v09orYAo9E_w1gKg_Y*=d3UUG=0gpHEeGT%bR~r7XE@NFo z_7LDKiY5yySQ5C83_uhOA#WFE!JBZz4G;q2p%XB2;aq?z+k}a>$l6>5@zpELBDNT; zvwqTfcm*_|SvxZT+p?hr?gBZ~5-E_uQ5n*@jJ^!06_-jG!EViNhbq%e6hi3i`=!ePZKpi&mu(%Aw{fcu29nH;>P#Jvab@F^l+ zaor-{DMFgH{`^Yf9q^AAbc)u$5}gj=i>ARDNT`6{^lz{yNk8qj0e9mGloLnj-f~qw*?DUg zXKf*&5A9c)-x>4|wsbZ)+a*8;7>%d^o?0ggfDo-Corv%8<;W16s8;u|U6_W_JH z$+};3N!t$O5zz;2({26{_+~kt&2-YZ1Yf zt{ohjIru(4EfenOUIyRCefT0@umoD9LS%C5c zv!R0qgk03?YmfqG`8Hu`_2A`zpYv7m144d76-3a^XX>gzQXSSxpjn|r(HL~7^Y=E; zjmx_IkQAU61|tdqweY-xTCj{vVAx?L7{kkQJ8kR4?h{xHFtX2*~O z2Zc$t;Rh_A)S*PO91Ni0P#rtP!ZJ)F3Dd}CH3_*6INIUQAJnDE<9ZMyg zcZARm1_x>-m;rU=AgM;k$5IPn8O&|s-LSf@^JGP+dp~iAfB^%b^>HpZgg!|MlmnCu z2)63Im$&|^t{lM6Tqe(hrHty}{D%Du7QqQaMy*Oz;3YU1h+qU>#IglS#QhrKZo>Hz zU~n>Gzg0aiAPfj%NLq(+j&?K-O6x>v2#h62rxB10YGkN$2%>HmaKhPHrc`c8*_S2rly0N_Z<#DH8zU?g`X##JVsO{8c7o!q`(rYC&By@smMR zktq)`2HMS#AoD;_<1D_hoP)c8c3Pu3=hC^xddfHmfy$(>Hv4=kvU``Ju9i}g+N!$#7hAi7>isW1GgK0BjHrC z35IjI1UQ~eWHL%@D3{uJsh;y4<*>u0x#95bmm6MbF5lYU+yE#6Qiw7rC*u#qITf^1 zDpE+>(86UlthRx7D5kMMsw*f`;6fnN93G4Pgp0%x31|vq=!gWUSmXz&!q^O`;(7$) z8eV(cCw!{oyq)e`bv1@B;&Yb)U-O-{t(wbqFLt(c);5A{xbeD-JO)XQRqDECl~llW7f7D>xaI=1WhYrL zu|7ps2tW`_0+(8a=P4e+d|iHi(C_~H_XC2pvwf$3XF-KvE)p>)P%UIBs0J%sPud)> zOK2Sr9f@K1w7Wh{8(VL=C@0te(4g7`!Q2n+!? zKt9yV)n7rYK+`~Ab(6grP$_#)?R;iu!B#~5-CEFDTYJxnnKc3jZPQR&TS7u~V4vt! z`D|Wjof4cDEZ zz1W7-@7vYC6d}RJ%KMO%_h09-;VMO3_NCb7889LY(wd3KY@0P*n(n7{&ixmif811W z3#qYbD{NuT5_hppd`IF(gu@jk0JEd|G;7ZX*+Fr_x-K8h`q% zf@m^i|2bmFf2$Z~hYP%6lW3)m%x-MF)MTX(&GsI$;atJq*)>*8Rhp}6Q-w8TbDGn6 zsm!WflSblVT0;xd@~vT6ORQO&?ACD05=pvbvPKw|@CKV`jXbiX$r^QNrT5ULdMl1w zcs!SCtkG2~34PX>%`3~S6V|LJ1X{Vm^|`s1@~yh8_0}w#-5P6IZ?aA_Y*Pt}JF-nB zXwso=Dnapkx7Ap0soJFybnE6_DnXOi>{1DuQn)MMs?XY|5|m)srxG;Puummu+L3)7 zwkGTJ@h}Alu&r+5T(!UDgA*@lTN90S#bKXpyQhd=QGH9lQ#x_(&PgdNVlJ@(I4&~`MV9rATKF-!-^bKO21Xy=auSj6gKkk z1?BDH`r^j=;@9hon`&csFk4J(#TEG}WsB_ytp`6MqNmH}mC|n%_gMwUnrbU{G;OJ0 z+qt(fdS>!8l0+7_n0y`K9Wf>>S-_+ZjpVbxQBo(Z8E~_bs<_=We&CLPw9w( zmli_bs}3audb+tGHT>8+-`)F4=TmoFd4BZ5JyRd*sW|Fej+@#x=dKWq_xGtq{_ zohf~JbNl4)mD0QW+!vKHpsbsW0zaMV`}FdR}qg(N{hA-)*?PZ@dk;7{^N) zlh=z=FDK=~kYjmk;*4~JZSxuZ#hE9j#jqGyfbF z|D0vHSS;Vt@j$+O>xmhK@Ab;MHkn)VPpt1I&R~2U2pd;z`M2RNlRQO~#pK_=2)2;|n)QFu^i-S3ZrcUoKGx>kpSA|FYfjGM}}HFSJ1vS_{a=kgRINR&a@Uk;hy4 zj+aCMUWnVCp%!^wS$iNlM3iG!BtzUS(IAddg&-93E<5jO)sPvGXdN9$@9HPia?S#Q&N;+I&rItrGsP`CA!w{WA_@p75trDv$+N4^i&wZ5XP zWDu}8c%S=F@{t33TLbgmz3?U92ix2o{DlgCeoG8JfR(^=?hP@i{a7S62~(UIQq|$d zCpZc@=UFcMySe|M_5E4ww(k%HTDq5$5I6n&w(m|PNcSL|Gba`BCjRB3hc3TC>xYK< zms0yjE-oTpRLHYHf3bW!Vu+z9%H)}SLs=K>^0bjp%7j})Ar=d`W%Bf4fg6^m@)NKF zihuBLD5Lg3y*#B!o{RwX!OI+WZRS40<;!|>RK9TQ3c-1|I~TsmOwN(PBOJB!c6aV- z;&{k?+U*i0=O(ho1)H!!n1vqOk&L!Q0yNEp*KtUTt9G2st zT&|ol$&>8DBumf8XwlD7)3cY_Wo&AV9}wb?lNX=yKSM={76HsO$vTrT-6Y4F1bxZ{ zlaOGN0d1zG^q7RHDW^;VKD+h!UugtEly3p!mz$76L7zn4y&umdw@-=|`!Q2ien)Z91Cg2t``ktpg`&gDR^;ak(^9FTmG6Vm zR7BZ|;_#ZRiV3|ux>z0tIyKD^h`R!8j|yU~$%LOxS^#T@~0 z5y*-yB{s5N^YnDK$D36bm_3dewF|`J{lrdLh>}2jiA8Vx#DFbwyL6?|2hV zaHdaK$`0~ko0Y!3$_J%4=k-nni55(AnwU9_scATc^^3;$!8%d=#p|YDG?fIRl47*2 z*g%g%fxjR{ot}F5zfS>DRCf(>8HZ8`sH0{~An~zI+Ro;YNM5GfUKf*^=quzzLJDov zF-a)pv9Km4RHBN#PDG@{M)rk1?M38pX{~;9GrdNKvql?|@;A(e4s=>+no2~9kLu=5)cCMX2k`61hLcaP3@;*Ufr zKpY7YLxRKwHCDg&yOK$_vd^*Sjn&)35m+H1MC@h6wtv(AAT|6nvID{ku=lfnGE_5v z4(ZLOhV$uz)9;UL&~Wfmo`40@51i44p0g`c5YFGsReKbR%9X z|B*M+pCS*;egdJgCeUxb3hI`dLIP_x1#&k9vNmp(1JXt&jMA5Hkx#WN*m9kHA12~F zlZMLIQuYwaRX|hNByZMXH{0AL77R!~1MLdeQ0Hr&f%PbTq+f^m+vLatn4t%FXQ5J^F zvgW?aNylxeuUlbv^kW;G&jANOi5Y{j@VFaci)@X^flFX-@>YaKVM~7X= z3-Y6 zgoF@!8Yy`ABT{C5E6=n_o3(2~atd-XoO?I9o~C`Ta2Qb7NAKKh!@R@Nm#Z8nAEdQZ z4t4zbUQw8AYLzOn{jHV5xB0EsDm>T`LZ;s#^~+j5C&P7U6Q&*}9m*loO`B72{P|Ck zVoa@8P;h-aC}Qf7E z7`YpJy%IaE%@@!x%dy$ax8`wR+{ zp%9di-_U9KvxFmyAj*^vj+ zaz$uP$*eu!>}@?gnK`)3J8y9rO1sriwiB~H3 zN)29$kCQ|%BgZ$%aljEZ@}$jShawG3aVW*}n|7AKuyJnQxOH>GA>3JexIU693!}F5 z)XTcWDo7*4g&n76{cjm!dO8`2dQ)nWxpuE&>B$#3yP(U>mkg)iKv--8(93*Tu^h(z ztW)H654n8`x7+uR-|oR}5#Qi`4|#o`!U*x3d#X;=2$K%knuIuj8@s@*Ic&vF$Py{4 z7V$ub^oqXUl}J-rI@g0b_oJh^%Xx74|27kdcLj^K=3v)~clp_1cpl)|1`RlKXBD-X z#USxR_-s+Rcpk?F=jmG_^7gi}=zQPulizfdl7oO(4us3Gtqx+aIG;zX(T_*%UQgMd zxvdZ5*wl?q!W`L=7a^~0g+z_$@liUQi}J-q*!Je35i_4a)Vfz~ha!uQUISFFFLAxF z=c^+u#ZvBI7Sv~WFEa2bb%Su zyU}&!-pyfXkyPbHkFE)=3Ktp5xp@=tTZ6cDtIM^?v1a4Cbvt*W)9^%;Czr{3bQ}5- z`!shPo@->bTPfEp$#@EpBJzbPS%-}m&;xdvOA66GrHBL@P8NkJq(h#>B|suB_2jYw zm*^0kU7l*VAj)y*7NjN@=aGXe5M~3AB{V5CI(TsM_iQK|p7@Hs z3IIWaSp@>tt$Vum-1f_etrbK(BTZs1fWm`uA&5muQ+mf*P5ad!4_~T!o4nPfK{#Cv zH5cy%QCm8zw=QNgFDr#COC=VpK$L9+P98h58Nhkk4G2aNI3}<&NIr#=$t2A5TDtuT z4vy~0*BlgM!lMUCasCBSZ72xmfYku`%`{K+UKVYMHiitEm$LNAN?aF4cNVOOhNmYv zi9KWM5Y$LV&;j1CVlS+B7b7RM$y1BvxMF!?u^d}0>xyNrSe~%<)Y_gdW<_ffY)(DH zQV2J}F-K?O_;CBjIHnI3X>YwN^OAxeqCCaknuc@57ssw9+gmL-octXOpeYr?StHwXHB37^Z;Us%&21*Q$UEN}DMc!)d_*J~UbqTJ%9eXy--kOUlh7@eY z#rC^;VH%?MV}JNTefYu2+JjS=)3G7j%C_HuT`)2E!UU5L-6Y)lHeDfbJ9H63v7lR< z9APUKCfkMB#d)=|U6{fM6JK>ll(q?R#skNyF<~+<(xSk%zKp;WLB#I;U_00cVV90P zmKW%bv8z~eHB7%Zb~TY)eMh&BUB!{Bi}c^fm7#}RjL^;M#VK;}1N|1cK(_Gbxu_SbS9AC4HV`2$KmbhePVwQJ46kf&K#Xiow4`EMh<*98VFqU|2C@sgCYFr z?!HJ8ranU7@f3cwt5aKBDI7=FHODeEjoKcZ2rXsq=PYef&q8jg1 zFb5hVF2D-{UkJRFOgQ308V~mo{F|_G(cUdd(Rxp^a1~dJ3@0 z^QWNURN5VVqKTmpXG}7Ct!9tu<58UNPsy8mM~MC1M;7N5lXI;aM~T;2;wk=gwD{<^ zYi-4hHXpG!=-dLYqrekcup(J|UfFy&yvG<;#j;Ff)eiRPEmXpe7xosSdhe^6cHda_ ztw-3mN%a?Ykm_IAVCzDgL>8j7%|Yc8+H z`SiHOd5e=%Y)5(IU}+P$UO^XrA+|L)I(Xu6)5lkvK6w7^ym}_2iP3r+yp0W>`o7Wn z&Tn6})i9wrrR%BndTTv3Cr4|J1#6QlnD81V!d2zi)L@kNLeIhQt%tmETtj5AdYf4N)-@|%M1ZxkaRu(+?{KPx(yDXG0Srl>alRH>3 zl-bTuku|mG8B#Fw6H@_WoMeh2R%L|ld`Lo|pD{pA_6-kDpc2e;r;9WHGCg6z-04#g zMRoe5u<5bef;a3+$V#0m#UMxXSAhJ=dL_AO)JP|sUj1@Df+jF}(K_RGUJ&dD{%DjD zpQDcmLW^vSIXInXsWmZ$tlmjEUym$smI`-JTT6;o8=>4ZKr9YW@r1%ZihqMf3C`8(Lk_(QvhojjHm@)*E3 z;ktIevZp5O!euxK(%G~)?LKACaH#q_B=bdO&w!Tvt~`t2#(PBkW<%21#WaHaoLBbP zHJfE&P{~JRb@9QMG;6~4?a3*>Tr-3S2-FYAf4mV98@{5wgtDUuNX1prJHoajG~O>p z4M=p_L)Vcfhy7zFY>Sgm%E$7?=p^xXB6OKG%AN{ljJ)>U%I9t5Cwo`B z2i>j?okB!j(L-%jKBs(2QW7oHQ3!N^(BGVm*FLWxz_*ZNL$~Z!vV;wcg*GG?>cqC$ znXkYf)tWVGuh&AlZX|?37V7Nvp|q1+V0^$=G#(ID)tzVI3nJND!ZqhZ^t@5iM==PI zt|^i3MVyT%6?^>@3yU=BKa0}?xnE3SlciDmAySm_B@1hx7KdJX@kw0fPm9aK7%a+I zOwwl}5%hl!aCLP1%lu{pu+vbxYIgmSet8u>QzygtGytz|`ngG3ne)tR`G{M=_A{r` zCLj?=efyg~T#Y8#Ktg{|km5B4&0IjI5@N<``!O5{6@-pg>m=>NoI*H|4+ex0#lmJq z(^lfxLR8D>%I}rW?K%B9{;&59j7^=JbCQi+_yfk=-+&Xk&*r6tLqleS~Y{n{?% zYI$3y{grYs_Wm>MNqUfpD1{x#j(nkyiC}x9srJW|a5gcJ#?0D33%9$$R-|*mgUnwj zB^%-_^sLFcz#Ao}EG(T#Y4MMX(17shu$X zZHmI)O$HX7lE<{hrBjucl<+(@gb#Ug4C5g7+h)Aih(G=eVu|1{3x6(Ld+_JQA3pyv zvMVBrYr53lA0)lsuVH*6%c=0Bn9PSUF-!7)Eu2#<(d+|*W_lGNcX>@Hn+uyQnpu*F zuIMYh!)H(7v-`-~Y|X5fJqWNk z{*qaJ$;A4Oexlevy1YE&vhePWXS3B7h~Kl_+u@kY1z(oflShF^9#!W<1Whk~22~(S zQa*cIWj|${{dp|lAIbk+M!!r15)yA{U|CvB2&kfonAjc#z;-hU8Kth*j79G=h*}oU zEVJ9Asqk~3b3kDLTJf(T|ghuIT0GuUl-8DBnd){Bgda_bIBOKzU-kJzb1;fC`^2{GjNiSsa}* z`=`|2e5d_ic&CI55iTgk**{YC_(lnzJ_q@8Ym4}Aie^a-`=oF(19pE0BbGIaE|3UJ~-QY%p#7>w>D4e0|_FC!SxT3dS$ z0tZ$0P|SX&?IkAcHDoVHiqWTKzKz@ItoCgxd|p<%!3GpEWiM3)=TTi%>SlK0({pJy zatjsZ&!JvGbX$$r%(GLLzjHkWJ(nJRLI99XiaC><=~s;lmG!F3N3`a#3`fY?9+IRv zueq*m+s#xSBhib<|BxH%FsiIdXG7RYd&3P>PL-#|XHD_3aW9yVK`ceBa&8LEhQN)@ zPFlY2dI!C0!eYe9scc77Q(*ry3ena{F<0`=*fQU{p|I6)@WZQ%#{MiD31%~DrbHpUPgaoB?25v_Fj z3G%dc^WoIrCcbPU)Sur5Fk15Dwmq|{z+8W_Lc>oqT$)nSyJrC~m?q-lQe$Dnb z(Lt4OQtxbo$4^MetVJ5Er1TiL4%<&CqL2VJg5P+eC6|-5f2BIANlJt(t-$)>YB)bU zhmcD?1~WUZP0;Jjm0p#LHB1+io8e`(Bxc!+ z`7EQ)pnJ%|1gj|)CY@*Odlh2;UU?Zo zl+szeurvl4Uam8s*^(^QFmr3d^k!VNS5s$oc0tdwC@=>*C8rqD?LtDnpf^3wWZji( z_W8^{tJ!OM_ZloIy46j3VZJ3@+|LZW%)sXhe+M<>6?@^(x^>`-QBiyX$FT?IJTdE~ zkZq$2XMtwBa4S2>KI1obIhGBfy;o7fSvjAq&*>6xf3S(xn-O$aOV^SX77MqWXAaI> zT_(hr&H7E5%*DT@Whb#ACP4=mQ4LB8-*KwO_;{*lk!yPb<_bylu^RdrQfOgM_^HIq zR4Sr$@r4KfN-}Ym!peg$^vrQQ-FqRcl%*D#!{$EEU~!Y>qJBnwwLAXLp-B_42$Rk% zC7oLNPlW1U%B+HUIJx};#3F^4tMUnS@g!Ib29uBS@szi$TNzkAe+?bKFvQ+HYMSvx z(u63)b9*B5u(Fg%kH)83pORn0L>1)cGxnF6ekLlz{t&ZJOH~My*wC`QOqIn~?sJuU z%Z@9>tLJ0%paaC+jKypfec-ZB^nt5l+cir%{d2-__+#|`_itww?ge=$zeCU-R?;UB zf*X~1|8e}lXAOgeAk|{&(ikI&)hE;E$(=5yx9i%cf4gSL zyP;_-pZZbope9lesfEOByUw)LFlS7X-xv7U+wO+OI-M{%X~LQLZ1l+(@;&nqb0+yF zW{UEMM@Pf}3=N%57`EgwFEdFvJLWrj5jIdDLPxBKW5Rh2$^=*a?c1o+(_+GP9YPW^ zrJqPvjRn(w2kwQ;mLZV{1yuSBd|0jwuB7^?$a64F>KasM{^dc`KySW zCMfNENWbRZj7R5L?|L1+?e?FewZvRH%25WBeIEl^g?U#*zKe=ME;yE9LpP^IKHFWR zivn<`CRptCN!9Z%2k*{U5uR!KvMa=r1C- zySG!6>D^;dRACx*t94yLmX><*z|M@t+LDTKV!Hk#r5ZAO-9h9c)@4bYy|c*?^m$FZ zS5F6>Y{TB8YhejfsRXNK9(DhLKC=ag#A?N6 zPpSIN-5;CYof~>l!C1-4OYlc!EY2$ldFRH6Az=Hz^c3k^BTXc6KlD^oyY?Y!>4YSN zBd13RxQ5C!&<8mSRF$^Es|=>GP)H~S9)~&&R61HOP{<)yOC^Zip~;F&@h~g`?bHswPkkYHpQab zb`jo=%zr9b=?LnFY%bcpigAOsRQZYdgZklL9J9FjcfE!*JWh(Xq@ftY`b;PJy*{%{ zG3={+OtI`6%aEH{`lIU+-+M{FLCcn|xUjaBz;V)t!_PAVyCI*ss|QAg(ql4HFpy7_ z8uG%^PNX9qpXq9~b}?lrZO@|G?*DxcgsT--lkq1jv2)+aL+V%Jdq$c@ z_&!66<@kI#)-EH723`3n=}jRX3kmhY#4;f^wIT7X@)la(pdZTVZ=m!_^Q*72O#+wW ze*rsDsJHHXwc{{~j$qFmIMFjK==A+a7$WOV_I&*(X5mQ%DnC!_zy{4YqWmi#0{biP z9iM4qa>YTgs5;k(8aC2h>KFsM0Ti}S$U3QILzj|7bwDy&z)LtCNOW1WEe@Wqv0#o@ zOO5W7>WE}uz?2@+t1~bw3#&0JjRIz+!Blwnio?bO^fJOimaXbJba?N9TKd%so+FKj zuXV`#>M2i^cZZIRwp_SETQpZDV7}W4E7s_;dcx_{^NCNe(Oam?*k&`N-?nHLvoM(| zlP7k*f90^@K=87c_Y>w$FfjC8FId48xX~l!PeJcx`!5 zL+sni%SvbjmB5_(6_Q@91D@dtCV&a{heyvdNRCS~e!_+~h7Yc3PnF;U_d`8OXd#>zD#1n{=|UeCxjnONzfdKNWNM+9->t_v>zA(#aR=geW3 zBu&t20b$A0PV*SgD_>LJsXV7-b#-PKLo&5WVP1~^!F|239w&6@uGliem9zb0nc-C; z;i)>AjQvAyvZe*B2ES-h2#h7Pej*qffy$22X!a>g`1XL(6^$(5-l+%`D_i6wR&P#` z*=6+8uY&3>gcP1Na+MrOkt8+}S01b~4o;>k^iE=5_Np^$}G=0mxv z4UrV1?Zd68{!gF1wE2sJxA4d+9c}oq6Ct77zZLyg}#4L(m)4o z_%PXp?)p8QNO}tW6qEVgC>rZ-A08#h7RL1if>>fnLRbub!r#(}ytD3O@_E3*bZt^d z{JF6BzlX&?6&7C*h6uy9%+E&q8H+9R;wWH82zr=63SfZm;5tXL=v)QFltOj%C6|jZ${yk)>QrqU$lRQNXR5xbmkyJmRoFRk}J=SlJS{&76gvvmI)uD z3vPenrvz<_=@q)Q!j@#R03RXuYgn#}VeGI#GXDi?ve5JG{YsY3Xk%|Pks!xFWuGe+ zTfaJaD$k7?^HA~Uqn12mAHeLW{EmFpn#5xH8;zNiPrhk?myA*@b5>TU78huAca*lD z86_J62$vl2r(v$N$;_~Zf)+(YSUwA{S$SJh#DIXcXpw$sJ3c{X2h&u}2m|{PUO^Hq z(or}5_q6Eh?R5pA+=my2QwI|g*yxe- zObq4k=5&1f(;tcVVGqd0cm{hcj_>>T|8aAoEOq{MkNH(^?65qhJ3WyJ<*A+#Wx%Tp zdq>$cHiC^}Be5V&7VuoIM|M7ofA!SYw`N@48-bj`vqRYM?G#m#ma1>?VprQmr7MlIPSVYmcpu~tZ+P7wE!*>5MRD09+e$%qU z^Qh%pM_J}=EtV}Ps=^y|k-VxFlYGyBe6J|aZ6hIVQ@cX@wMj4oScH?ODdN-@TdnHF zHR5C=o12zK(=R`c-%By5@sQp}E>_XStyZShy0SBEZLe_8fG}6oQYMP>h$NPs$x4Zt zXr#Vi_3uurIa@2Om(%GbA!EO7m&eLNF4uM|!sV-}cPq0mt53D_E@QLO_^aCam(y8n zgCuERGv{6I6;cO;d&fU$6H+o4T^7ATMzE;65Mp~2Mou-!mH|0klvCQ|dwb=y|7hU* zq)j&(_})(%xca9JeB}Q&&@v#T{Qn!6X+x&iajM(xpXwFT288sR4ZOE<0kC^&Y!6Mw_m4U^tcwA5=)iP7u@8A#qT3_kz(rCS zOI{Wn)|Pi!FmtUBL`PLD`Vp%?4U$}6CG49wcnU9nm% zrQJE2d|Bb!c)Rx@(QBZ~2uQbJy~!Apr8`r4tY&cqgoy%CW5k*qeoj+}1H>X^j*fQN zj8o6ZC-N$PH#&ZbLv8oiL5K)!RgSL+JyBzb#dDCEQ2D~BVIKsji1RJ+O`6Q-$=%u7 zJ)?$|mAgrk@V{;CHRSHfcJ<-*Vbb7wxePPWG($W^3{3f{lBC@szgv>36~F6 zUZniKg9#A^8aqe2w&6KevHpTOKB9M!w@Jd^A5%3#oQeV!yq`CDsVk+lo(xgI8P>2L z!aAMV^&F@SgU1QGV$h8&eu+sDf%|yhN`cg!1H&mu5; zjaPyD@ne#!T#qU0TW_``T@lWEdv z`-;_NxXR$Da8}GNxhbA0zL>~v2yXjK+E9bUgLbR7>?h+6`mPuc zWqMc+KU+HPM$iK3P)V9I&oY_R9d{cA>!|N)^6*F3<9~%9`Aa9T6HS@43E8WT5!7x- z?!2GXm@=47Z2!+fR!Y(zhW+Vqz*T-aS_n|Ns}hsu0+e4ULl$4#zgKV`g7AM;Oy;>! z!~XV1M#F8yp#UGe`%I~-01@H8*vk}W((Sd#CVF+?FA5SgQ`rA~s`p*wxU@a|dY=5c z{Lt&AKYJbi)chUA75On+n6G&3g2G&M%QpwDby6(h2g zxL{iNs^Y0|vP7)%TMIW}nRr79vPEP5V*M=iyYbuzKk`zQ6>5p_vm|NSc}nb>rpop0 zgb~}mOR&Swzbaybl#5e~LU)EYH#bgCbrD(gARi6(ucD+0{NvGY)qQdZ4isw*8hh;D_$W8X z_1^JxZh+5e!CCm=5Z}=6yzCws`oEvP@Zv{TlJO~$P^^p@5LSX%5QTHG^~R?i-JrMo z6KSNOuVq76b5lQ+q-}0kMg1*|kQ(`PEq0ndU=o%O3x#%}fW-BTG&dA5!ip8_;)Imh zSC@#wgTunAKGB%gEBudmz||%c5k+}(Y@AJIqtku^#F!8x{>2sc_jJ8vS{c(xiPmYj z^?mn*POCmQe`QQ>2DyH-`&$6RfP$Z4^Gux%y|WCD7LrF{2>u^Nb-MJPnw2qPmU?U6 zgif!%u?eqakH2zarD46eWJT|iRo&s6x&xPZ=@PaH+m|diEqQQY$^S4*iq0fszcz2M ziAxH5m#idU7)d`*-Vg!OnBIwiU;3DE76|S<&T_`T8yWw6WLg{&Nh14vpGbd7K#XyT zosDcsOQGq~U*poUL}VkEMyHA}=hu@PINixcT9)*E(QS=GS}be751YQQt>Ne7p*;b~ zjZFzmACqminssv<4S82yrC8hXyTgkULc-!1W@U(F31Ct78+hAa1Lx4RzVa<(4+I;N z{HbDCvho2smVgNOQ^R*G8N;>XKG5+!261L({!*+H1k)Mex)MPfn9SiD?SzapFk-A` zT<1fELj6H3YX5$y6)$0Lgg=mAPkskVWZT$A3?nNdjnuhA-PFdJe9lZMYo;}GX6{`x z9m&03n}tnl5|?QzPalGZh-Krtofp~g69WI#ldeU(tqY9;NFG3A&19J~l=PeJy~rjL;ilmCW21jgHbst0ajoyx$WnXwFZXx=QA zV4(4GE8sOS%ufC_XsDpyREye-vhCin!kg4P2miZpE5^`l@E+xWuV88ygGF-s$P*x? z^5h|!Xu~rzMPm}l3T0lrz`h`k-uMC@;sEBShp=~q4bAcwFA05ZMiT1_p^k=96wlL- zk~i8fDrH{UKASCD61wXy^|7!Wg4rNuuIjqcf?RbB6D8N4@+wq|a803WN#%@s_LDT7 za^jufi?_qIuhNOVe0UuSlzxu9NS7)M&&2yQ+NZnZU%(FDi>CY3Fwd-zjt! zAx5~M*j6jaZ##vGe@SO9gtZ!L%aJe z18s<<_x%;$h)byU=ikDU)?9_2sw{sh1Xe9h&NwU+={1D3yz`1li=DE1#4O!t%A~SF z7MTl}*<6wq50g1XoUOBa&(S$**9@R*#PvFH0Ts$3`JC>xKU!$v3k78rkg}3P#$LZf z&nK_5A>p&_>vg+w4Gv(;e`96gh8K&X;`ZKdO}>f^TVd!`96HsBuej(>2y~)nDi+%0 z;6#UR*Fb`KDUNufD%gNBcSe~mLZ_VvP%5*kV& zXJ%$l5zb>BShuT2_+~Vn6=NCf5WYE`fY~5CkZ^EV4jG#`@urZbQYj7FUcoU`eN zu;KN!IX!(xSr)6U;&hzh{iSI`d#6ZGCw)%Zu<`4(FNthpd#5wLepl~9Oy5 zV{kYbc|h;nimH3w8jWuvyRgqG^d00zd@qYDWPCM{E0_ZLG09&mVjE|4)3=dZ#_ITi z=p^jeKu*J@gkctUR&^5X%RplEAU(7NcYsg+LjHyAv6N(cZ6=i#E^WPCIrnn__$_E#ll_V|vJ1(E=ndp15I871xs3kmKR#GZt_({n zPr+l!#uqP*Td}m`@ChvKgdd1)#SRIfMWO2m0b){YylIsFl4J~B%9xUn#SsYwGEevy zen)_$(4^2F^4@l2C2dsbXVu@x5)OC282q z^#|Fx>-S;>i;*W{8LC&FguMe5Hmb}<7u%S8n?{sl&xiC3jItqZUH=SEv)e+JyCRdH zQRoi{%i?Pyuqhz9N})T{%ldF~xm}^(BbV4-5I-E3jB^s`j~@CT%&^cqq%_-bh#^GR8jV4q$qCX#jyRT3M*itWETWS9;0mX@-_v?R_@jE$zC zYv_0Q3@258uV9~r+STyojfvPZdBd`xS0=}#XH&+X)Bh{Uyyf_ zQ*Jct!T)I13GxsMS9n&Tb>q!RHY)U5LTX_eL$-5pJmrIei5wdE@ERs@(a%<-(V=7S zayg>$Li}h1Ns~x#aN(Qy0gd6p9m%*{ODGMlT1G_UgjeTeR{miSJX1;8)Z)ak21Y#nQtkE z3kaO?m=d~25gvp9AfFz64*;W^>}J3Ut9)av7G7;FttZpNSZye!Z&iQgu@jI+6T6ia zpWU|@-VXZGX1oE%b#=JABd@O;cP@}ShU!6oUoSiirSxRN!1K)VvTJ9OiI<+pX8OZ- za5HH_IDG|X?3mxz2l@3L{`~kmfxl$=y1gD7Fvm}f_A_EVMW+!{D!J%7whPqXLvG9^ zH*7E;qw_An1rOitcf=RW+J;Ch2q3)V`;isaUZ2vTqjwOAl@v{U`8O7e&LRIB=I=iI zsrUptxByR}_&tO(!nNyk9$_3r&G(A7&5wUCDV6W|g$>t5F*d#_1bae_w6ONNiHXCF zeZQnXti$U|ndC=MD+G$^wpi_MKaLjD9pnLT#{olfE7fU0#?xe=@3xt_X@3g(Lhsc*7a~20Y@5{^|9@L^#i3{ zP%_`}YnLf(tk#aXq}}WnI7zD{rcGM3X{u?G5~GR#V7}j(*@cB9&GWv``+nayFgtV4J@?#m|DAj9xo7T8SjI`B z#_lh-O0C?HMude1mpZOd6)>|RE%~^W{N*sNf|^RV7{koy{(g+Rxtl4cVXr)k8K(}V zNZjA9z3oiuv3EU_0aZ2Caa}`Kp|n zspJ>eLF{0eaW?Dkp<&Dr4X2vVBm0C%#|30{Y-D01E3hSIMwaSIbtYt3tgd3q2T@qe zz=z16{dFY!_Pks0o_tGvj?SrJ*jz)LNuRY_q2c2b=jBVL#+~oQ4*J2v0PXn^%OCMklS%P0 z7!eUH$Bgf%V8!RJ=zdmCH{!_jbD9(^Msbf(BqRgu{teuIazM);+*N_}Sr7z*&^(-D z`1mmyyF$TI<)Nz>A7#XKrF$RW6L1(be=3{IrI_m8M*)isIh+uWPv>Aog#!!CLD^CYz0CmR*ag&+ zj!v7vAA#{*CXujY;tl!tb$H)!LO)EdD|4tupfjA5qAp z*yIFhvgCg*V?wI-dWpM0(b;2@0kOP36M%=Q$rbuf-d z;`ROO-}CstlXPio0y__#)_)D4{>-}h7NI_Eg58l`=veG@Eb=(M(dt;jbv{D0jEg;O7JO=gHtaP2!^DWFzV9e3Kd~W9%|8wu3 zHotK3_ldWR{$C4<9M z5ifRVb@9dl7{qyOO{d2n!WU|`^Mv@Bm@mo62qyd~3`4$;H$8m*2~Lh;Hk z{hU^$H@$H?m(k-ZE_^I71|z%5Q`6}1xWrW}^VW&=4Q_Xx$6GIEt~4uR93Oc6c4tqN}OQ<@Q$9)r!gGW5~0V-0EuA21j*nZN1miP)0b*91ZoZ z*^5;IDXTZvmpQ7d#{k1fq=W@5ba~4vvpk+U&nR|EUY(sm5o9XpVzg)<;kqtR8{V>Z@%5-sT=jh5GdaRA0)|D9u6Mi zc$6Pob=8L28dvSuDAn}j=VoUjR!2M6<0Vmi{^!*#bmx&G%s3g znYVbse2U0jxjBelo+`TCq4&AT<5Gva#VQ`T7maf-9OqupqySP!Ln%=!KNNn!=EceG)MQ1Z zDDH9LZyx9N09`C|idFSuZ9{eS7>1Dqb1I1=uwCP55{aI;$x+?lQqkaV`FH+=ZwiYK z`18IB-yDWd;Vt9b^TxU7hq+Oz$qnF?q!8Z5q=hmlyV_A-Nhx(ydt8q4&0<0Bs&JVM zrZzcEF+mi2N~%aYRyfLBptBE>{*3k?rPDVyL>s`igIi#MYCx%Srrbd zz>CGvdiBi=RIPa-jPknLS>8}TgfdikNB+3ysu&&@lHl=*-Z~Mi)9n$RRkdgl$!JaZ z#t;4@dF6K0*SpGtAys}oE~PRDgDcqK!P)ruy_?;xZ~|k(gQOXeT7oydhumsxj8(Z8 zCzqr3ssE`pj{3XD05&v+JE>icy~@!|h>#W#K~3U!lt-#q?W%=5C?{M`9btUAzq7tx z{CD9iT@LrZ^G8jo^Qhv%g-SA>J$6Udo$QX=a2MXGFkbIMHEtS}BxMaA5Bk6oPhA6o zmsFKgT~=9F@IimE=tZuGZckO6xFp<<5JvqsHnk-=f5=_$LfJKyY`~CpvFNGr0v#Qpr^3^eff|YUyj~?XZ9BjGlTC+mx*_8c^T?@YFObT5mmM2t|qF?s*ny=WTm!`{DgR+G>5;F+kUG`6J+V1 z!i+)jHjRz7+(`{G6?GIhJx6XeSn@p3nOFV|k%;5+QvOovgQxd_#j)-<0YI&yg%q+6R>n8UqB)Xzf?ZJ&m${ z#O9H<)+u*Yi&Yh)b+oKXoT%7qq$EsE35U26nR6f`sQsCX+EWtydu3v zI8&03`ZdDs@oQepGUwYai|!vC(n2s{umK zOK7NRH2n&79~gg%Wz}`{u2dRHQ2~^A8$1+I@cO)eg`>KD6an;=@Jiwl2JSkyt5#(T zt$H*kRf4s3MY$`&W|h@d_1==OQCxj+IM)z-ao3bo)Okvfy(M+E)tgId>dMEAQs7zU z66>qO^C-kSJxBdV^DNx|tMacREP+(80M1$Of?5RI$Xv&M4QCgRLhUs2+0pq^E|s$4Ety2)ZT z2O)~KLCYBB0fsS*ikdLd_bLHWXhMSV@E8BgX5vkvf>&Qx;kD&s{`qC73Jshdq+pN! zjPO%Zi9rH}ks(HdD3l+zartAz06mmHiho#sDQ*ntL;kgOB9bqnnn6S<8juRiq(;kg zH2$hucY}9)^la3>#)U!p#)hi0yTg&b$RFeNDzAu`YcO*gm*6md+@3lo>RpwK#*3kb zI7$yQMMQ+6`NFGt3WH|qd)!~ycNPCjbKurI%>9uyDDJZwdbF~|++wAOk43_t+rsf& zm*W5b<&W?skq6Vnk4uy0zmq0Pqw?a%ar<>F^H(MW}MZWvqPa%(ZU zMjv=vR=#+*YcsSIWBncO5_B)4z%c&24%9!iNw3lyiD}O8!?WqZ5nM6 z7){mH)?!E%j0W``Q|OAihFWxOBc7t80<#U#JQ{B(J=Bq4j*ekSDp*sRNJ+h`R+$-l zKy(aHtiv>c$YOfYSXEI)GX|PILx_{yuCK2v8=G21u8|Z#|N12&O_5V*k&aDho3`9c zF(cG86&6Wn5lkV-gwOQV6nvFG1{x#NUxmRcS9v%UO2L1Fzq{(HYQKm*wl-^J=Bh%` zwyY?3)yl<+WKqU8q5S~#Hp;xT3445Ug#ox zbvmeqQrx5_@pw~aFGf)`RF^~4dc``Y7qbA-UFKAZyu7wv3E--CQ*o7egV7d(<(xX2 zTG=;??x1gK1qQcDv6j@-Zy3`*|F7ax`GO7V%tG}9T9TCH`e3UGn8fJHim{ga{+3uERvdFHfnHJbg? zZ^Zs4_nPi~+Sg*Vygb}7h26Af&g}Q5pC3#&m~IY0k_-I)Njf{W>9(;#1MDs1<|K>O z3$WF_1!v=2q*G^oc7vGiwaydW(|2OkNU>Rjof+B8sTSvH5edy&Ay$~M$d+5M&QY~7 zCCQSc!+=|VFB-OKjves&N-x4_99tf{-531+3j=@J=@T!UHQy!q+6bqE4df|Q?Lv@!Vx-W>O7w62x9)zVA?~2m8BTPt(n2pUJsvbm&5>{yWBwgf-Tx@Jg5*xgL4@=Lk*EODYgirg^OH*7$9&U#_|ed$2}2U&m(dM`g1@gY8zpk?MuEh%Q-O2dGXlPP@8 zgIIyJ{%t2RI)_89E|#pt-gM)fxxP$%GlTtrV5CuONY~JQ%J~VlDgPqE&{m3z zCAEm=Ouq%DmlqdHINc$XGR0N{b`yVr6>ak;D9;fe#XcZZW=EWq(MmzJ{rSINP+PwouuG)I)Tj^?a zJ4!I?s0>wjlEN1-n4$3-jU(s|zjA44xeVPYUC!we4`^u`Tpo65|+vA-(H(Z^|$|_yxSvJ=-DC$6ORhd}j4(~4=uKF}ZJ&t)< znya=fl#j#W)F5r~6;a5BS2FJl40xiP1 z7Dm76q-6a7@KQXrKOSC+p+756oo?NS`|MkkNlOH}_#z(f3K7mvcdVQ|8q0Y9SU3!_7By0(DUHoz(0=qk>bZY^G_ z;qpczIVM%qrw}7@d$`Ip7xnr~W>4xmT-n^m~SvP7DD<&$ZL7(*O^z=j-#QTL(Z# z1f0r!_n##zp&!Qc;M8P!tH5{D~m`j89d!70>mTCF^0pNj~hkqQc+B)32FseFbphGX&o~tok1d z(t#ICIxSf%aWhlWPPe=Us8{E5@8 zZrlXdLN0~M_d*ax@HoIj?SkCmG{~W;C{Msc`9Sa)*Qs<;$Kh87;Y$Dy)i=Tq!SetQ z)gOYtojBc^f_pvSp>ia6lc>_K1Uy`BUzn@H-Q(b?H>mKYaqx8TPV{_$htf;#5PZit z_>3tk{%*j-`A-*AIEAGP{a2MctoKT;$J!L`&=p#_#QJ3{r7N^j4Wod~m|KvlQGti> ztE+17R#us5g#s+Azs)FpWIOJD2tewlB!h` zb_#iUYM4;|g$lv##r#^eD^d9kYYT*9!OQ>p^StE zugnD-2X}*$W+=)KKZHwBjPqBM5{5wZRDF}jK?I!*RZ#eVS~aEuUqJD5{^KatmzC7l zR#jBE6z-r8EL$8DnW#C7F+0JeB)s3iN{h#fMvWPrqGyC_tbf^JH*{YvXnSf&;)SuU zLME{ z2}@S2%FH6pm1KwEW8tKJ^B883qSeb52UV1!GIgu>)`d(>mGrJ&MkZ}E2Zj6$lXHqE zekwdJmqO98r?enYn`Csv;P6llN%RHp245k-a%_`5`u(nj2J<7{% zyLEX3+Til)I;YZXl;zK0r5Nx3Zz~VdOZY^c(yS^f!>K9$)GA?=Kr5422O1^#1*QFe zo}Q;_1MC_+_4QRK5D{YwQj3G{P(5~+DBQ19L^6Oy&6!nD`+61Kuj_NwofWOi&sq$< zdEu?Ot5+k7i<)iu;tJa`qDhxX5#Sl3U(}pK8Iy;U(}-exbwl`Ia~09CmQ{YPg%vfE z-Ogx>g*_EkJJ1}Uqew;KDwS1SC2Hj-l)ex|3?@CqPnBIE@VR`TMMMe{3O|CstWw07 z=I)StJU^e$zakHGG{NjkEvp>YU_YOK`8lgrW{qTFDE~tIM~5<4gq0Y8A^%X8{BPuM zD5w%eQ8RjQQmoSur@A^1lY*d94gDij?%ukFGF2r>@++(8-^;^r|55Sv1)VAQBYMkn@*wM!c5hTI zgh$)&IRCFA_urSVMXS~<%PCQ0`Y6%Qi`cJ{hsa+=!oluVp%|XGl>c8Xul}dME z@>1WuhU9BV9+B)+{R2SsQ|4=@nJjZ4C z*!Ekmth0W3|5No9^7VgS9{;!H>)7%tYECYPRoh6lfxB$1TakBTg5gF1$eG*t)-1UjKBTj?)H3gj!xCm7$C_J7&UW6LL)o{{oV z-J?m$ZqBB)ZaXC)C?Z0vDbMV2<%irIQ-0ZM|NW)qw|d!VbEh&L)z_#ad&~{1%3LK4 z?hPJCxvNC|+yGwV;Pnkzo!Foy@xE_&EIjH8J{LUHHS8;QAr}co)n!u5+8P>^<&al>m3@hMA7r9F?poQ%)G-vM3Rka(){HE50 z6>G)tPWhf>RDdY>szDEo{81IYA{0JeDOr)VLJU#BWKo1IK#5|YQ&K}8pl!f+gNin9 ztR;=gAJi#?PWCcih)w*2zBdT_iYH{^0`*S#Y9s81{~a;Pk9z2nD(Yb4Lmv#O)jPy{ zD8I0TNdqvGo8D%N1N7vtA38!9Dy2nj-74M1k!_=sh5 zH9iica6}A26$;_Gr>rjrEmzch7_W@F5x=2LKnVsfo;#MrJ{k_J1(b{? zy93fRD$JIRG9I4e;rO0l+P?%>i3XB=trxe_rWK6Vm>4ZxyIsqtLsDN&@5yhnMLgryp2-nv;HjLO)g#2MPu7n7=gG#j#`t=A#h90o5 zEUR)?s>UE=`GH-hmpRd(!pdtTJXEI&eN{aQF&B&|$mYm{=#SP6q*1BtBi<}nAMp*D zYeOBB%ZiD0NI|aX$47DLZI${N`j=viv?tL~FK)&dDh(MOMj}+uwrX&N@=-r-0J*9P zB|+o!Ykc|}YGEV;{S{I?F6Y%q2p=+y^aV;0jFh7y%g20rp#-Q>Kc64{0xyhLdWA?L z%X&rJ2i=~{ZbboEM+Q8|-!XYdIN_Ir(uqt+X{f!swyu%v#Ak>5hw>u?qx#>pz_chN z*&L9+)fH*=SYkku!;2DzhFB2@Eewd%P?p&sj<6CDM%3wo={)9>4G`;_F#e*CVDVL% zV!lhC!&cYT-K|>Ji`YK^8ca2k5eoDXXpnSxZshR%tVbI38|(?wf`Xs zqv&-b+BWomNUx*5cBK7cT*xz6wfi}Af)gSIy<&Funjw}KgdRKVv2!(o)5>GB z@QR90FUInPj8FX8;$0n4>>lC%w)?mHeBL>g9T9wol`qT&+VaP_d!nCfKRLPqPAktm zJhy+!yjy;nxQ);c7sl|nH@e;4IlG)uyz^GRFqgMz*2Be4fwzXA4OW`s}}VtCB%+3 zWpvBbn~WlZ-drLYb^*V{NebH_!{P4W*Pvs{25#~9L#$=e24vMB?cF}M`X zsQtR)5A{-`{dO=rnfmQ~nWu~hG>l9WLf#|wHP}yM@;I7TgcPdJLH|%S9tj^T56DSc zlg4;l*^gml{;DKAoFX_0iC%?9a5hW~dTIT1e1V7gf6;Vl-2MP#h8_z2vHJ&n-oL75 z1LTvMJ1U>uftGG7$GsfT_;_0n*B6NJMcR%sU3YKGD^@Mn9}s-8w%6Ij?*D4}y>$YM z?*47d@2oN0Yk?>q40^d!foZ<$Y;Uo|?mxHu$$CAzq5Cf_f3@Doy%YGFFUj^co80|I z%O9;%xRZgYz69Hw+=)QEZ<6f~%+P(j<(M^&8w{9yX4}VXUiT+0=dBiYbN8n$pIH}j z7Xu4?^KBQ{lJ09QL)HvV4lMP3(>Baq2`u(~!*-P|>b~4^3H$7%bf0ZGXPwRcGjNk{ zj_rN!qrhC>*KPk|Y26>Td|*xG-VMy~CENbaW_ACgyRJc2D<E7uyZ`C$a&J<{WqYtQ?4C zm$*UAq$NRkPIvL~%F|6Bw;JO*jD{{_{2}9{k&P|S8>gn2({18YlT2qPr4)!CO-gr| zj!)9Jm^2#cQ8^%SCe0+_lSO<=XZlmq9*moZR0rgx?6?L;b<8eU60eeTS- z(o7NW=F76(<(sX+#{m(nv|20tO^xF`Ar^{0>zX*z8bT~A_2E|%eUWG0#a^}PnjMn@ z8tfpZ&zc$O{N-@Lph{U&ni&VY+yx{1_Gu>s`OcclP^Ofs5!M3xu?IA6HO@b(aqdER zr}!{_?cxvd%Zm?v_MRTw1803GN62!2d%qW(>EZM!I9OAIb(`(zdp9h}O4{1|H;bKf z(nv>Vw`*JNnnHVMPsIG)wtWA^E<5Y6bJ?HCjAy0vL5%z_kQkI@$8)mns$B4r{GODx z5hWn9^cn7Xlo z6xMQ1j?qG&3} z$Ei^7_yzHzL`gtI`P3T(IWXhk<8h)A<6|>WbdsOh{YmX-u@PY)gNr)udrI@j#_cWc zLz>MGmOibi>dgO0v+gMt&_s2&;X{upjy5HYEh!J?Y}9ui=sx^ZVMX3L?)iep98tDh z!))xuC-50u(knV6r$4UN!O2JErQV6mx+9ZW%O{D!GP_CziY+Cv)1OjvdvU_~rLl#~ zAW(+o68~0?;rkivr+LDmIpfe?E}%`Uvl6%={`hBd_h&NizvuL4@>UI_qlqSSa1Kg= zS>H@RdM&B<9itOK8y1>Q!rW566zWnQF$}PsT z^64_l^Paicfj}~c)zJIXqXc~ipT6KJ@VVcy9LI61?LsDZX&5*{R0}5`@09uD zT3(z{u^#*MM!-@veZhP4v^P!9=2_v(9}ANODSyVj=3{bkEE5(y;f^Uy*fh-(7*5zV z)zL3^1%?t9Pu=)C`B30m!tbW`1g<7rORxv7Bs`O_Xi7&8(;bsjVqdkS#ACO}-w|Ic zc<>M-iK(rYmv{HPGL-ZR_eX`7DJii?mqoif#bR2p(~`M+@e=#KEhecogX8)M!*X1E ziUX_CaqLvMn`gU^oyruMKP6u(OVgXuIKFJI?rbnE;B;m_Us0Oy=?cEj%$|Ln&o(i0 z@31f#hxbX#7)~SR4k)$j5t-XZF9knVgU-6G-I&H9t`qoAOS4R$%l#+$pNvny=GJ@Z z6~b^P)6>q?$_dcCku4lB>mFtn|6c4-v9Kc<$8T4}-?(ubl}Y7Xwarz{El}D;&Rn%L za_1UbA(W9sZaWdh_LTTV`67j9l-PSv%BiLkY34I?Exh=3I(EXiN$%|;(d1~5Ga~x- z%Vw{f{Zsj#h|N>_a7tffb{F-pFAgsqr26!8MfULy2JzqH;2_t<9&tx08Wc`$Kgzft z4}(8Rj1p4=@5LwK9ed37h*3C~x2Hcp;ZfQeJws@Fg>mhK_*!6ey2zraA64mNV{}A; z9nxRJ7Kz8V66&eF>-jT3W!Peudq)O2#B4gV6ES~61YctBr-?$~y|{#9O9Jmr(zRWb z`!wwRRH?_RyC_HCSRSG6!no5|7Flxb%@^?zS$vhW4lPPV+*aKAxJz+YVsB0_ZpZ*I zV{z!f6&(%y@r&|nhF5QVhkqhTm>^ALJ6esjwQx?7?m3p8WXcHapCo)Jyeh0s8s5s- z8A!T`ETNn;o|AECm(cqRD?}KV@jZmWN$HgZuSL9-u;W|E?+MsCzVuZLLbS8anAICm{Z2*eq_J~>E=IS%jdsvNmPeXbeC`}9d%M7$ps%|9{MMB zTY2s!LMdpM^-~0X&tPQIjcE`WYx6P2Xg)t%h)Ttl$I3az!9Gsl6HLQ;w!;#|Z~at` znv#$|loE$C)3M|E4D^dh=h0!)hm1)6mf#`2;!(j?jdTW;m1v(7_le%(L)CO_CCn6>7+OY zK1}_scGR76BhEb+vf9}bZx=p#`_W%b4h&2l_{bmVu?7151O5K&KM}t1G1>f>Osu!6 ztZ#io7KH3S$R@Pqjk25`pR>FsvN&SauOfCVsL}OZlh@&3l|{>EN1zf}QBDW319fVW zXzia%_32=b!_fUP&Y+0nlcG;J;-5XZflDF6#+k$DOJ~t5^@F8yx^VoFp@ivLYU*54 zCif8~FI|wj#q{ai2js}$i-j~UXF>54u6hV=>1W5d_s9d8_p0FW*H;Rjn%=d2SGg4g z?J*io7~^?kTzq#vc-wePR`{M08{~V|6ixH_*g+(SPg$NDVUhx~m#bYQbM(sgglJ1b z%$ynG>bO~&NKb;0-x&C|1Uf~?hbFXdKhlW$ch0fM7-go@({Kj1miw3(JN+wJ|DAp- z_ZhMAL=p~NydvY+tk#qV^go$(B!1(+0z_UnG2DJ}|!GrOIEb*$=vXAeh3aodbdhRvq!VhWe_H#y>Oh_vst%zTQhQqQ90 zj~wE*%6wcj;{#}_zabug{ek@E3EIyYCs)K02r|;vET?eAThilipSNg>E{1V~RFYxa zjI(_hC)|U9nnF24>y}zq=w@@hA0Q`ov^Bz70S zHs-9Dfw#<2hDF@vg4c|>j&rsZx({`)^OqcH8XOq=4{XrB$Fe6WLjd8E#3YV`oro>l zal{VjpS9sA*n;38_h{okkd+!-qbt_UT5zc;;jV=XJ0f%9(;~i|nVZlQKj*&temJpZ znY^v(zA16LrxfeH{m3Kn>-Y`v998o>_1V{CCd)&z^A|F9SuZ$!4K>i7e6Knuu)FSs zQ<}bXhX+s3^rdSz$PYqTifr5T_H8u2-9DWJF8U(0C-aGGjs$A{#WUS&Xl%4@rd=6p zOVjVQN(7L~?j>{+W837H>V}u$-NdNpCLew)o%kuHLAvD^at?9YdXvwju-AIG4_iJ1vdv>srU2VL z%})oN3i}@OUleai#osQO|4i;hMDnrt77~tZdx!aCh(<7wGNd1+X+9qEr&MnDn13H~ z2k{{*L9`V=T}}dZDHD@zygD!0&I6Rr&#I5aa~nVF(r1Js#dTSk-*nNxt)bPbu~>Qk z0b7@qgO^1zSgcx;@1kjULx(l8)f!<+w^^(-EcM(?IkJv2ql(gy>oE>rL-xtn0yszL z@7U))xNSXcQ!uz(=_k=Vlu4fP0%2YxOhL!(qYN%Ajk94m209Es>1;nK zJ$l4AOp81YuFW7zMh=6vVD)FOE>mbL6NW#@#&@oz<0vV0!ZF*Zdk5!xkM5tp#9*{8 z!5oF*Mk}K*7+ev!;+g!-C_vBbo82N)}UJ#@2QX8($`jR|vWH zO&R;ct0(DzW*TVfK9l=9^xTeo>|cFZ?gt6#%R)#D*DY%NhA3n2H3gwh$2imhY%BeH zImMt(lV)?e@~dtIZu%(({^3 z2h68%oWk+zd|N+GhN4MPkW=N*aaIkvtc);d*8-dguBDS``sWEr*)eS6Ww|Nx?b~#{ zGL9<6DZ$*IuYx@syLptxdv|JAXmI2~E3zRF2`C-nkS3fpzp7>gl30pGHoZV(o^S39kb7IR8twMxjRT=r z$$wGvQ_qwC^E>d97u{7&z->aX*$Qwp39}lh*&Y^VU8QDQSVIkPb}D{yiIr;>qLtmqtgZfoK0~0#al;A6jb|L9Y&EYoz6gRTt%y+^*OhXtOd z`fEh}#eq?YsgmP*-G88W;!YC^_qKfUko_GlPb=Wim&Bv|TEl^EjsFL=-1f&g398X()5U3FD1tjH2W}$Q!>#^DoJGz1?4pLo3=EW$}dA>SwKv zM6icrE(3WYm!P!$fQ+&48OIc7cmAJt2$3DeB;l4WM?!~VvL}ZHBRE1495N=Z{oZ99 zU+@ej2>+q`uDtaO4F-Ks5EzeKRhkuQ;0x4hxB&I^)n4-qs{8IC=KEz(@Aj-k zz~OwtJREw6BSEz6CJ9qy?i6JdPJLLra~NViq_La8N(=oj%~~*d&m>`?sdRGx{(%ld z>!YlFTVVMC4UH0)M@9=-R=X`f(~rG8tgW^^XE&b5`5U)5O+|ipg&!;wQ{Pfp5lGCm zTD|wpf0xuSjQwxWeVgbOn#%p|HAJ^CIe_1F5o75d#yIY6+-Gs0`uXtEhw$8uoB1cQ z$x*CyFiBpj-8H;41$RE~^|<4<;ar?ML~Ht8GpxI-W?0kFJ`UU_TCaU;hV|VIGpxSK z8P>ySH%GoDTK56Rjr$D|x}e$9tx0H8O(mjruo(LuU{8olz=|;T@947PJPOHw%0kLI zD-K@Z9Y5%CJaEGC{WFdo=N;ec?bmS_UN9z|I4GvtEdEnC{p0$1IOXfF1nrNPY?n^= z%RR?&T6OAVslT}QS)JtHO~;+iG3s8^snBUzztXk5B1@fv>H0awoN0@Ai(a1_Z?Wsm zF9G^@;h{OkR!5ueX&nWWx{I@VbyDZ4IUnc6ORLzD4k_<>$?ul(UO3VD+Ist+j;F3J z^jAr%G?Kr;vVs+^;xM1E;E1_ZI?IX(%L;vA-mj&+BZdBI$zR#wueJC+UH-dM-&hji zS;0xGv>mG=mb7;GH+oh?T2@7Q{4POLnD?7Pe^b}0$d0_1I`RVcRlIYBrf`MMvr6w= z5oK8wZO?nrp4TI-&`K+!rMzw_?`6rqNy>Xg@;jxx-X)&G6)~0-f+g>$l-H-~cO=J_ ztR}h8xW(D|{5?3kWW~h097r0slQIs<^bRFkyNi3*k#eiM7@!9TWbfR4%W-r~kOtiM z2p~*6_Mv!XB~VOXZ?|iixn53`xfb%Octtfg5}2SlkB&vkb0!ul-iyVo7m4qljn!A z6-WO5@#SHpKUBP0f;&5RhZnC*R%#_HhDN9Qg;xqRMAXwAy@h@XPO1f~V~M-E)kCOU1ZMAJ<2)6aM<{ z=Z7OW26_6H!2L$SBdK(OdxhTD77lkmHH=Y)GjAG}Ixmxa%yQ_=UN{DeH933#vJ=7*A`|j5C@d{2nP(+u zS;<3W7Ut=ev_e8cbXrzMknCI;X<4a^nXg5->rRz@q5Ge(h|g5+OVxH9I%O5sG_1St;(`%(_Q!{gNZd-ywJYXk_Z ziAWijMR4S9COrYb;36nB&vZV|Sqb|7=`{30+&AeRnR0y2@ay`a3E3$)n&$`T=z5F~ zoG^a>jB&?#t+t%HjLaA2Z)~Ej`!le!1X+ z?C@OPctMUlqnmn0=!;;j8g1gdC(^M-cGJ9Vnhp9njoTu>F;AQxz`$YKq+91L*GJ!` zkKLe;Z`}5;5IiyHe^c-ocxiZPW~pcuNcVClj`qc@P>5egn)kry=nT#KQ(0LKRR(vM zTIrcS4hSRXgBhP7tptWqi2D`LgmG9YX+2)WyRus!6qD5fdjG2|%xw8g7N*kiVCHi+ ztav#VZG6obWxyztJ0e5>_bd)B)Ry|Zpjept#ySqq^QnKtuP@zTdtW}2`XNjEzvzrXQ1AgBNhB+_%`tg{@0q#isBYPyy{|KRURR7V}b>8t<@*t^rXJwZfaKpz8$!izOms<{RJojM2 z9nnJUdB1#GnftV+zR~=as_kj5egoLf)Hj4#?h4|=S^b6(&mF!((Xi$#fEen-9|AbZr9hjd!pvd!d`8Ol4vyM&%IY#&C)j>JLX;ZBA|nCqn$xgcLrkI=^NW+$E|8z{5qekZ zNp+6dReiGg900AUr$Wg;1*a$Vl&DN5Pnpl!E){sHPYDsP8l6_w~VhD3eFE> z6>H)pVA#{v=PULG_L}vUPHH`tnmdf=XwuE6-61lnRX9YEuepPhs9M44Ok4l(R(kQI zt$!0|N1vmZxXD-*SL^?!$TW?bY`pk{Halr#1up5{>_HNHHveaP;+r=imckiZOV?2QDlFfM zQ}+~Y=!~twc1^71bxBH8nT( z+@icOU{P7$j^nK95N-1n%vV3;DnA3`SkS^u+~U{t8a3&hv@A~O%DP??)DZ>O%rObq zx9{Z<_Mfu(p9p)2TNf5KDo%F;W&qJyiJDN&fNl<}R&Cr!Rgq;4Qp-5xO58I>qgBuy z^7~+q5aoDn<6A9Q1ke~?mHX%E=>U0shet3}S}k!g+uEhL=-ql`o_HaBTKj(6!C%Lj z7Pg(N(jGkrLxnvXW-gpObC$u_E1Uadd*>8xUXU#za-CteO_-cpu;JTrLj1ON%UbS$ zUYO+HZ|h6IX?ZdIcDoRp@J33S#y(Bgu_xxxp6Jd4GFxpp@OXZ{`M{6bUkDty{?Pj9 zjy=)-pS3-nX__Bk^9&}F*|I*yv?#DJSud^SJb40&8Kk$h3mTB;K|Ud#w>Y9aj_9hV zqPp+9YqF%*x4p^fyDOjC*51^4K%f2~ko0kf_VLf%ALE~?OE@#lzf8Aw%QS({=9zz| zE~P+7ZcpA>@Qi%e){(%8;tZd}IS$I~5yQcQ&y<$Nag(kktVq~(7Y8+6EaE?&cjZ3C z5e-LY@>R>8==UZGIR;Fh`!jp=`e%=51r5B+CqDDPE|$V@rAIXNiy1V}?kRl^za6E& zF4PO)l&vv{$L3q#F&z7|_~{`oBQk%PXnlv;$%)d#@VEHy`}7bWF`p%E5!z}Zck5rZ zb@dGT{WE<1hW0(WcGu3pG{dQ=qK=UX2!wEtKP zc4!sn;r;BPB}w<60KxAG_vYwpBCUBkYuV0YFC34K0nDmtOzrulb0>vJk!XIax{)66}$vP_1GVT4hHHTf{|Pp3``4*5*#CPe(WF z)t6nHr?gA+(>Z&Rp!*5e)T!1lRLLA})-w}5>tm$#(ZvOYd4doh!7Co|Dnm2WE4N3{|1^WF1!YhCW4LeF4tXJvl5&2ThXyggr9dV6p2g zd_<33zi^563}53S1h=QBrl2CeqULDMX0v<>4p;uVr`gru=*JnfFVV1{g=!GKx{*jY*5jmYenS$eo-{y@^4x4|0FitKp z7^YzFu>Pm%Km5S@#M8$8!{+_)tl}mIJ@Z}KgzRXKR_pfK_Rr!YW{$4#&HialhoIMM zw+lxH&&}pKgcuZg|MOjYqW51PAtWBki`8or&TA|}j9n0RX!_?D3b9XIWYT=yWX^76 z_8C$947TSCTWgCP+|@YnP{Dr;3zKI55No9epxw9l-_Ui+eSecrmhLz@upPmA(H|ddD5Z`u$P_L(kwEHoM^WGwwvt&(dd73*N#TW==O4*AJWT z1i}ICw?PDbyAYYq?E84rR@?Gzx}){0cYTuYu}69A(LMg}7V?pW_J|&9lzzXyy@?ga zJ-1?^W`kG$`! z-eQjc<*iUfD=&y*>sh36Ad0(e3-11_p|y`8UHStldlKg@dO**guunW$DjXe%N)rT4 z))}^yqiLqldm0C=NAV&%Svuk9KnyZD3szt~;#$i!I!ODh`I3!#K~!S%b-}8S`h2Id zA$2DD#1T_7R)aH2(MzUjgt!cC@ur-P#5LHPUOVHad?+hv%;(}^p1x+_p23mi`t~S3%gcnP!%>(pztH~>W?knt(vi%UTi$XA6OTUz zbY3u|Y0!v1I3(O41+J_;AEkfte4Zia$rNGjjO%w;iuWe8r5PU|GCw|Ke{>BuEm#OM z#mO_{490y!=6!(oaq*!F{$$hMx2=?1;bv!^q4#bax-R7NdGUQ;V+luj$oSS2*h=}f z>wF7#W>v{4d$XXGBJ@QEo_tK`$TPH6QjpT@^YUQ~%p;B88#3=e6o2F{Ur-xhMgDbQ zQ2*rG0ljg{ka-I{+qm;VPor;ojgeHerY69iVgSJ+~SWtX3ngxG=k_p*|E*X@Pw zHsM69(K}@J0{=tqbPzwKy^=q=XpDIZE@YyYW}#3)pr*}4SJq%`g(^R2e;73ltx*FRZo z)VJptDw)N=m7=2Gty{Zxf)LUBJJz?D}JPWnIZkA&XZ-4hwAF=g4nN=2b2nJ!Ap!3AW zwin;qcymm;8O+RRdsgoIi+m_nV81AOZt=Gi;QXv#k+60$ZE3kJ5&O1#buY4Y`eXqz0`OK_e%6;APY{Z}SGL8w~ z`a8L)Jxyqe{E)df>)Z==wk?%Yev-nUbP7k$pft0POB1qtkaxP*fUX?Vjo1R1htXU^ zSyLaPT*o}aSV{T-UfOF?rdzyoFE@`^O_jJ_dUBr-;>Nw7rQk4h+xp8QJAMm82&edQ z(A2r~QJ>KYO?gmTUw(%WyLqg?H+W|S^0<21}>HP`5 zYx;Hzug!@|Vb;v#tYM@Np}D6ql@i+{9faL{An+@^^BDRtVw!gz zd}5DqL$iz#*fG)D_MyzaW@QsP2VtSo9~U@Q8h9t}*pT(uvCL*u#<%u^>I zYawHMKVf{(^Z{{0?!s^rwvv}^QJiiG|2lu9P`EK7k{uiH4$KvM(|P=6X;||hMfdei z1}(_vql+DCTf~o#F*x^ow$)&)y=JbxX5Y7%`|~HrL9$+TQvR1p{&fCrjj`gIxdPrx zxHp2{N~su(rPs`*fM;;O55kLgc1((aZuC)>zt+~+Hnnw9w5RWwXKLh+w%zx$DBY}3 zw@< z9S!)hUPBQ3zIEI$g7I@-zvkhiBo>vH&`7bYi`75;K!{%vukrSk(72F!KV#i#7G2p9-Wo;k^2yzZL$dT@3ZcVCdR zw(oPC{@U7B&Y2eFoXL4uY-wdtZoO&M;v|Wrn_oL(#|H+O7{a!sgIymvUK_PvGq~U}uFpiRzaS#-f+I}Ese+=1R zm^sB@ym-}o@v42__qnnlLnKOsZ1h@L5Lf@8F+M6E$4l%rV`V$W#SwzG@w^ce=_6$c zCn6!y+hTeA3X=q_1>#hri^N&&sOz}`bq{Wk!x*Bi4!!+|wOc}muJmS65+j=u3M2IE zICo3wdi`f0-?nhcak`G+x zjAg$2l3?vInnQrV_I7xYV`a7v}ja& zFxm)?93H-Eei*rbn$rYxUrLL{=tft~t+j9|Po{UIPqN1frf(K4e_9KxjwhUj$mt4u zEJOL+_K;c`Ji*GaKD;uZ(s*LoeY@eg~Rr)7*6>9vByQsfT$Yi>g2xj zGVy{TO#M}}7mR$yoj$KNbis~wwmbtmyuZp3nCdanauC^Ob6$<&tkeBGZ@_m(iV$#J zHM_3be;Ui32nC&t-gK-!NcYBYf?eDDhhfYm)?GEP1OAO%Ul8Axb5+u^^nLbMO!}RW zE_!B_{QoG86Et={(r%Bi*rR&ir9=watnLxQ=5Jh;mND3qKNGZ9P)}cZN0asXaDpd7 z_d3P(&8y~bBCaLe&x3JsX;*p1BEM!ZF1%`92(Jw8r$MioNog~e%t?wrD)H|fu~__p zg-NNfEQP`Su_5D4SIw!w&gUKpVxv6MV%t6n&vT*NoOqRqH08x41TA5my!A8Ls`97W ziMPExoWSd{UMAkAUNuhz$ue%s2m|wGE-@v=9TmaAe97N^RMHU}Po${k{6~k3(O1pU z2(y`M9A%^T9GD1Zx1cGwctt3ebgZzKCSmysD{c8QtjxhNEU`3f!g=bei68D?S4=M- zgy9V;!Jg8YrpYs{bBrHfF@Jo;zJCT+5@O3bWw!7^m+_xh%>RT(DpwrzNEgI;frR>K z2AbAI0PAS!a*UHI7TJmu^7qZ(zj%?&Ae;O}zJp@^?jrFK zgZ~8sluXvFxb{rZ|E%r7?+l|2x?hOPO~~m`{T_=rJh}aaxaTJ;V&d?yty}g85kdl+ zYGrFXmE{fyE{mYE&oH1pL1PTdlvfS97r0R6g&;vzsZ*TS`K)J#AsV#;ItwkIXL!}n zc6bC+=`$C>Ixh;JQe-8w^gVjbuF}Y(gW8nlte2Qz*EOM!+k+DlXh@x$wQqPwYw*2y z!l;%2WrPUP*=Nl_$FFPihB`*Z?EY;@Ta*5dZ~ZMiYxVE&&5LupCwq<#x!3MozLUFY zO_~lfGPKiIhL>)^Hy#&m6s@q|@zKX$SQ&_PKc(Sf&zBz3~z zaDNB)bCQD1=d)qmCA8guHAukrE3h-LO5`ONj?4cKd*>b(Rhd8j=Nx8+VHl7>88ooY z3>QHGX9iFt&6(k@pfCucTfqzrFvZPb5GX4IMJsBN%Cu+~>7uLdW@={Tx@3ad;;y<~ zw5?q;^HP{-W?q@!=Q(Ev(b~)J`+dEBzkfcXhx6Rdb9tZV@_DWY`ro<`(PuTI)FB1N zkOe_%?_^`~0(Ef#^D=b_%N2dZM`&vUU2^w(yxcs=@V+xWd5cN0Fj*&>5K;2QbDbRp z9R=d@<`q9GY$bAO{}lV)v5k%=n^R#KaH;NMdoK=|qC_0aeV%6# ztK{G*9LZ9AmUNF3F=)}(te`>k@K>>Mg@vsr;@@7TsVXpz|pX|KhpRNtH- zk6@rJ{(dNDzOx|Z^Sss{XuSkE^ni*^gwhr3F!St7n7K~*JyQMga|&5B$?8fUqh`kp z+$5}CuUX|;ETbU}h~(n)&iroCl8aPO9<`1Gx%_*-K3IT$yJ)`poCmmt zwf+4U1)2K%I`X~dc)yeE*HTD-#SUg1+$i@Ew9QSJHL-j1AOM*8q-O*ejRN zA=hUlu}P!Ezjw-wFs$#c{|9^dxlo~XWHLH(sw#H}T@e}%+A7wjskQCv);V*g#9d{Fyr0&-DEWOkoKQ4PR)e zq3MOLA9>L(QxmD!mq@Yv%Fg`?b%9tIT_$9QY4na}uc+k9TRnr5q3JPp z6-A3+?RHm>&tUdGehyrt-lAryqywiX@M^FpT_EphuTZ`ArW33+>UOn1^bMe0nZ{%& zc!sR_nlsXn09~J6F_9V)6!O<5hU{o#f<^nav$7Ye`S~Z9ZFaSf^ce>Bd~GJ|7Bvxj zF*}->V0rJ4&PYWB6XgMcq%b5wAyp+#->>DTsa=UUl%&Y{#HrU@G8nF8o3<2)cQnJs zZ6%~w6W(Nq+jvTN4d1xvy)V z72D-OQkA524C(VHeNrNkl2!%j8%1E_NU9HkRhE5T)G*b9w2J9wGgwif?s5u3iQEEr zBV1~@>~NXj(!oUsP^jS20arH!y4gS6KQLT9HeBZuZt@Mcj0(4lZuvr=rcc0=@RqrC zo&?q-nABro#6HD4qdTJ`^iD) zO*0VEu8z8kp7ucGZ}2fQs>e#Zjj()_OpTkA-r?0f%Oi+*bzClvyd3K#hh?`gA4Nl9 zC7wHAphFB3A~4V6=QAj{okU>J5G-jQ-@zIseDR@W$BR*Rd$Q`WO1)=#t;u7Q=kpci zCxS|CCrSezXfQQ*Ju%^Q2J7J^_iQR+ipsSsl=pV9gf)^TFQ((bQm8a!62hq3JzKyY z(Fc#x)4MxUTnc8dyV1U$bn+F5qRi=GxE40b@7hI>;P4e6ocBD1QglqzRP?5xMn zLyptOZPUc5bVj-|2Wmz5Q?eA+$HUdLBTOIK3~S(|961ho!2B2;auK?~(H@<_Y}DAc zo&*o*<<%EI$VQC=Q8R&sbt<04k9yf5`pkJJYw=W@+58@&I_DH0y%C`@S2z>cw$AkX z%SyyA7PGBTyGrbuMIzz}&Fd;pt1m05-LGJcQdg>_cBtE-b%<2GSgeOaKbe?+1slR3 z=yW#6^SsdIgubV%%LxmGohHd5=7_U2z_OI5`|%~cD2$AoPj(U3WO2BQKeyu+4th@gq}fC>J8s`nh%glvPwcAUB$hT2*$Id^op z?5{(QnrL#SBI@7N1Z#mg^*J}0m~oNdoB-K_8oEti-w;) z2-bt@Jr{(mdN@{?|B$!@T|sNVC#uyyOZ!y)(WxHII` ztxox{*OE8E`m%b@Pq&`kNZFYwhIFU45{UEA;#^8?h2M`D^1 zjzDL5jWeN>?J8ClE7J#ZE;`dRu*H{^bx^zbGmQ4S`n0-;maKOz6WZ5 z&cVt9)tO4=7EhTep+DLOBwABuAPh^NkOxLGx~Q>gIaEia_b3#Tv7E}GBVL)}{=eP- z8kgK7_dgvs88U*5OpPC9>4GzcsnL{R5aq-~F0pr2fgpeS9WSn>XVS{kI~lpMh;zvA zR;qnAFdb3K_0#C7AU?j5G?nwD(W-Qrfvz^Ch%QEk z#>E&l)+Dbtie%X)XaE8S^V&^fnwI%-@yvYc2K=+oR!LT5X&)?Yw@4Vz9Z@b%=I{>W z_0TE}@~sk#a5EWq7{atR;T+R8PwSjEpo_W-GB*qbsw>9c(d|=5`6qnQ+vJ4OY9!vC zCuKRSodx3T>@oRoU!ve(h@}^19|I}7r4Fbe)Wo|9IxTM~JuSX$lycS6PS0uL!7fF2 zg;LJ-K@Di}eJcnSdJJiFemcGPRxpNBpkPvO`EsY>?jb(ai-{Qeb*nr}5?v{}OTbbO zveF=kODrwQ#-5>k$3V1C!mi%M&YW@ILq_O>4TUgR+}q+z-9+baDI_8*)3L4VogF=w zn!UU`D#jjP$u(!tRj!L3x@e!!)YzZe1g&T{>pmU-k_T+{_wM$Wb-a4!y^ZT5hfQHL5%q*OU-Wju^}tO;2Q28|IgMyAeVy7NeR-p-VF!y;2` z@sWA($?np-M8@8+8R3y3i(-B(4+C_TvgVEera6G9X8rim%2N^CTY(qBST|`SCro}m zOc!)_Puj%sdsDj~-UMUc9UK(xJ!TNpq&7t(|M@+O~^Fo z_ktuNEbxGJFRSgDGMQ41yRA*w28P42&KzsD=gY2Qdi;pqli?FK* z#>xhr+Cf+y`Utam0LnM?aE{z9(Vl~LQNqTs92W-*kYSRRBOF`BE|0y*b#rhU!YSv# z_BFm+y9V2%#QUy_+aC}s#j-<9amu4|%l;e6aG&3;vhTm5EK@XdAwesfi$dg5*ij7| zYW+L7d*ow-)^-%#^Oge!K6iQ>N!O7eW@`}fPX7G;Qz1}>qvZ)p zd%tr^e294pMPDF?RlwQz8@>?3X(rk|PGffh^SCSCS@P&n2~5G#as_!rQB$K$Iqn>J zk_jvbKYf+`sqsM?%?*<9be|50;WV$U5X1Mkx?)H>XY#Q}I91S>M~YOfpE|dk^9%oe zF-(dbc5aFGD?P!c-U9==?HXN=@E?-}hW7%U{7@l22!G;HZM_^U46 zt}38SCmX&MG7WFOl^HrmJrg8 z^7H}2S@YFJUfO9(kL4UT&;V3pFYHmTRCdzk^Q?Lu{M}=DvS&b?|A)K0RPQVSL8|wv zb3NSsQ(#5Cp2+>CR`|({6WY8}mXZ_e$ngO`iO8jBtGT$2{M5#Z?L_%3O&OzbYW*%j zr&brTLU|+*ObkAkE`}}#MNY$2Q`nzCVGM0mKEahwR_2F*u3^+67#@5)pfs>3g4?A# z$AZ~P_7DuqJsZ$}=1dG|*Z3Y<>(~C90Oi#o@v{UDDeLAI1a0gtT5$RvQAA9B_l>vq zIQMzWB2-*d92{UHP9B;w90o9vM&2&FF7hoFmgW{>mclqbgN;N-KGyNqz!*~fR8damdHI7&QaXwh$-HIH|d?~{Uv zZrexu9?uQ{P9=eJCZJ5m?Py|4+tZ@S^8A~hEn&r{Z>B8~(*t-;-+Zw`rv1~9I>Z{J zRu@})riztGCv)B#GKQ4~B^#}!tS7-sQx^p?FW-jm=!J)NPo`n zf4CS%=`-W5vK*yv3TsuKmq$!isuf?o0SjTz#K=c??gk5~?;+wxd;|KM&cp=KWqz$! zoozAcF&RsDgvgY>qG;dVH=M9BD%v+)alE<*CgsINxh=~#JC{B`WRF-7RBta|aQxRj zO6ln{OH;pfsx}O1H$Zg$!W7?%&YDrKH~H?#=uy3}sR5{+9B;) zFxkfBxlDxS;mRV~KtO$@S~a9y1rG9=EcYXAL)vG+WHFQOG8xo3Ai@PVCBLBpYlLcs zFUQr1Lxvp^Ux?ogbzaogRma*=dK^06J0kwJy$8D!!8;ZWu2J%KBTVR_P zwJYAj*J4D!M9S5~<&2`XmaxrDrGBoBQr68Cdm*liG#3}r=vqS0y5n~iBzrK?g`Umk z&#%;#oCUus_T~(o7t(+4_ik$%lwb|4FV5svh&cNg*eSO3h7)?QFq->Rz40@-oUYEX zerX}bLu#|;UA(UGMEw9g@ za}+%Ql4SG30391T3+I}g135z3Es@K#KYVYvdBHq%VNt;MOMir8)ZqCwY|&ajJ-?T2 zEv2hnH(iJ!2Py!{Vz_f4>HOdUn32Fb4{=jRZv>xQ+kGlGe)T?mQG22{!RoN%{WLLqDmT$NkuzGRm~Xd) zrbOq*91H#E!`5$rA~2lBcq!=-ok+<*}Vj3m3fz@yH6Si*rP9U6}y zz9D0B+yt*v1)~FkWejsGO%1A^7%z{IoCm+=s^&)1H&?>ve zQO)JlaYy)Q@GqO1wm0WewLSdvMiJaC;m2%zQ6|TsEj8OOT!_J;h0b3 z`V}ctuJ?UGb^V}Qni79K^%&$2xe-!E=T;A>g8%jbbDnwPCq8+6OCQxll6%r($52{P zD<+(L7!)Qj%G-d%q@NKT~*byTM-w^ww!&!F-18O&LK1HhTWh;jYa zf-r5Tvmjsr(;IvpY6J_Mzytt)Phq9RQGi!(Xs_Kcu78(#`z)A&WWVaC8x7Hx@uZoR z6jd3Tn&QYxMSDFQ9K|(8Z+@d;d=20`&A!pZo$48{?t&#^URgfN%Z9w0^VeL4b6lDL z*WTso>wTX(LH8Kwb}v_5hwTtVCxvzZu3EUBfor>#Kt4I-m2-6!^XQGUORtb)i>^#Q zVBUX^>d4@q>1jL(qvYeE&!)LA;ENXd_$!lxzC3j35|~RzaeU*g>>BEG!m+l@i6};E zalZ5T6vJt!#muPXUO5|Kd1V)zN1+;2E7W^*z4Ghl*!*VbNkxwmM>fvS)}|JhW(oipE#F$!BeR$nZCzx#JOAwn*QCq4`I$!I!H~* z4azr^(Y`a_@g}B#Qk9Qwe(*l2oIF0JKaG&LC9r=l7-mV>2WNsb!7FwB!R&+MU~N&b zLjB-f>c323GU$WU-{tqf!4^DH-xSkOslP1RR~zLtYv%`k4XMib7Z}giJvcT)EA=y68URiassuK|pH7cVHzcYjXxP3;7{Bqd z-#vEfRJIQeZzseYe50*eV2;+h64ja3KA4t_9ZygPcfTF4#7#HfWz0Rx&$Zq z&==L~=SBI-e0_pq4iuk zaArMyI0u?SHX&u2BE2OeC9;M2Cyn`{L1+1VslvO|Hb3aC@Sld19C=G|jO3 z-N)GVx_Izf{`4WCL2}D33FDkI^?wS}XTp6tT$>lD^`bdyJ;_$e9V1plq%=^IXD1{ioQ2=!OHogC&Cb2!saab?E5Xje)eDm z^Bs)?oZ|~i!lAP_UQYHsZ!eFtjZfu>a-NsBL%Ckoymv?`m3QpDskHfY@4ca%{Cu$gX2i#ZEgLP z@FX0$2Z8#~)Vk7|5#8^ALF~xrELbEI5x1}7QpEJgIIrpQ*D^8_W=xxYU=oj>nN-wCJcZCF^yKvPfCqU2SP`@jsyW;F=Q-iw9pIM{9pQ$h>|Y)H#=(uv;8V*jJqsG-CA;5vZRL ztMf^Nw83-s%C;9f0{te8>us2tpXS`R=IrpALx>eC5^v9j_nzGorY{On>&M>Bhjmsf zyzMXHWV!Cn@vM(;gt1|>ZggNxL7ir$qp4U?lWs_y3eus)=)3f>^F`%`CcepQn$K8_ zqnc>-t$>9Cv=KB)_2~wq(To2p-Q`Yt@_Hj)&%37GM2r6yt2Z3r+oH+^14hH z zY^v}xRw!o3vwR!I%dH)OVoRWCWng4rQ*%#KX;0JIo{stAqM}P=rNJ^^#2WpYjf!Yb z=8qIF9H}Wc$z>L~m%MC47PrQrp5@muOA#@id52oxR)%H|z%eyjsWB{{(hcqOe^;LR z7y8DFppxh^`|16@Q0cpVQt7!u*L#HVHgGNcRb6&!VV*=JlvH=IB!}R+`{6mh+(E?x z?$zrq!I%iRfIrZJ;t{}=e zbKb%b8ZN)i^ah;cPHT2k)Qt&mGY_!Y8rmL45M9M}SQZTHM2-GLK6?K1QWeeXE=y-@qlhce~td6>VtBND4zta%a z>g!O)nXPB+U5^>=IiFK}hIV&C!N#OsLC4#&>*h}#1g*}}BC9uO*oJD%oL=r&lOi|5pZiN+0duNjr6=@ws zO)XK)fu(mZISNX9R14&6s;FpzzjBtXSk^m@PThm9BdR&g<^wAzQ+%m57zXo~-70DB zIO#^j>0{?|Z|d~6IE_}rUb!R?2Vg)?Bp3CnuS>>JM-aIcR%$6W4qJ*<*ZUOIl8@tr zjyLH!Ce2YT?&Bz0cwfY@YVU6Tbh(M$70ZOkZiUD`?4yEq-h+=Us~!6pC58-Q8OX_9~_5qUzYB7 z5g#)gfWs;evgbT@b?<7~RZ`#&nI}TMFqup4f%Ute#l>a$Fd=6k%YZZ;5p^YaVsvEG zpt`45##~dwp~{g_hhUufe%Z+JQy9=Tnh6u&dI}`*2@y%7)?H`)AUdKi3CmOcp{ zS)!U?_S%w6$^+8F>;dozv5c^X>g%8P$dcH?JYV^Y#w@%?ohM7V#(Vik>ZPuW2!2A6 zz#P1hv!->72{L^Utce;vl~nNG-sSWLaoJJ-3LTGtvaybV;vpVKV2+sPgF)J+xL5is zjpALoIn}47I&;MLau$vdSeV>QNKpIQ>F{uKNt1N?ncyHb7#Kv2An*warN5L;CixT7n@yVd9vGXWb9URt!GZY9t|4$}iEfccxJE)M zTT(rVay?T68+9)_neEix9^KO1#X^ULsw-Re>m$gnwuC6~bZSDlMt^BdX2SHf`V`oI z$Qof$N=Q>OT?mr$%{34pK64shEnJ>|ZG@mwV1(JR(trVrKdE1RYRNJ1wK>{ds4H8T zHFW-uc>xX`J3tF>H^gp|>(qwI7RfoM;p1~TV^8ygL#98__~}Ah+=F8+P^TLD&*k{J z?AI}Fdm4FN3AH~C+@RdjcSX0TF^>+N1=$)#c-ney!im;x#fKLU9gWU^Oawa$<>YWJ zMC52REET>uUZ(4E9(VR!d_cxLLC4mWYR2>?F{S`f>m3@ie2&zZUHl7z)k)XsxwekAF2Mk9d_+t6Mbe9y);!^W2pR|$cA z?VTPoM9gX0e$s<{nJ-U)YD6AM9}y3CI3dj6g_aza6!Cr!$K;p%J~Zri-yMEe3e$Y) z%7lq%UW}@l)FT&*|B|c3X?g;mn{2na`$iK)nMEFR^e;Mxc!|8qM zj&OmWa6WUi$3c(fKS6#-4~}5=tCn9M-ab!$Ic`t5c@LAm^)4FRcK-#F%Hg;b{}1BU z8S9)GWmD60}|FRjpT<@A^6-U{IqdMT{;KPqH7XtrLXX=lW+&dfE- z1)F4E=gm@J5W!`pT``cTRBro7&HVVll51;NO_M|W*g#W* zqNahPT>$srt_)4$yZZP2%AOumvq01Jwk9!eOP*huSPy+=0uO-@A(wO}tr#5;R622r z-Gg*`u6XeWx&{gCS3Kt_+yl>1Nw4NzP1kHq;`_XJy=(kutGgCx5;LHNDHEOO8=wo; zl+TMaCJq*6D3^=uT?7{AHG7cFdsnQTs9(l~kBypGW|5Gf`pw}r%X*Y+JQH7>xV~FP z;M<++#~p8<*dq*NHbn{wIn)m{-E!%U+Ed)64o%Q_b@4Eo%wL^7fkNcnt+eg zZM$XQ+W>o1%n=pKx^^2AvNULberVv(u^caLq$)#kbrGGiJm~S2|G-W0)wkr!kI2cl zaA+6^Zc~q6luv79)Cd2z$ag^L?<*HYZJYXv7#u)tnz3rbD&?ErmcI@vQ@!P4Iq7P6 zu5szN&ooP!3FYD=2M_gmkQH7zO`K@@qxV0;ZF;Wj%buTpZ}3{TI)#l`I%5>`yKj1+ zld(=d%~Lnpvm=N%yG%#wso7`UvL!!4KtcVj-#UprfQ)LE`AA@vm5|kSZ2BsqDT+|& zJ)YZarwbXbENW1!WTJ_81!QJJc6p1 z4tod37P8gWE24oqSx^+Md?2q-L_%Pt8c;$Y6`2f2CpmH?YySRYOSGhmx8WMVmC* zqvi=Qcuov@Zo*Q@L^9Z{$X_|MDC?V=5H2+w^2u@fH4ZuhZGQbbja^e_++LP+j9XEs zd9hB}a9Qbf<)xMDe9jc9xh}O|Q7qRL>&NMT)MWpdZTUd6{R6qzd!_H}V1i(3Mqjjc zsb=d3un)y$lpXrPOKSP^T%n;Y%sV+~CG0vWQZEI27@ju?rR|*j>0)Sh2TK*o z9ZdU5<|#Eq*RP(bQFCti!h#ck1F3+0jH_3|*rBsMf`PS-uqWgd7@yQ%-ai`7WaYS3 za;fszHTk&qQjWI&E;g{`p12vt{*0jnhNlNX>NOYy=aA6;WP_M;q~%C>FP-Y2zn4)i z|9u8Et|)8DJ`@{%I>|o?@Rdhz3U!Zpt^oGavZT{4uxBqT6RyF2=5_C!9!YjWtOx@1 zUa3*{z+HY7sfDe6_DJ!0onmn|ws|!fA>3C3|N^S&g1pfK0*IjPEa|$H*>e9@8S7uamX?4cE z&8PNqZ;Xj7vU5%I74R-$-EB5kR1>z1cUWUow1Jeo%0pYBeX~84bfD=B>Z6D97wRn)ASW5~C%Bv5#=rg#(ah5kR?sbBpsh0_~hVCf& z1kCIn%%oUYYYWEq6xeXt$3nIuoQd;1aUk%-=X!@hp0J|D(z&l^g(7ifxktljo47or zF`yyV7N+~quQA@#>$f80)YKAhYWH-kP23ppbl!xM(!i4eo+s51p>mJeU^+W5@TAD| zBph0A8BHd|TJp%GJkOJWlCIx|z>RK2P7bt&?^t$R zN0R{LBob(*p<`65sEOqW|Ch)2m%tN80bgfePnlw2=```QfN5dVD6X=w3sXzP)Br%0 zcub>gN<_SOo+T`V0c+sC9!;YN_3nSSKUO{_TFy$1J)p7fob=E{X!sxVt{=w*txRmNdy@PK&Y+FFY5uXBi95G?6S-{5MB3+3&W9bs zHS`chVJykW!tv6Zm%;d-1g23Qs)dIi+R&K>LPAh!{axP&t)2MfRya&l(zZ!*#W^t& zMj<>%TPS_jXYetWQx$2nMLR+?*%$TtAM|N&2SRgCH}1u*o2p}>I)F9-a%sNEDQG{P z0R7w|3Zp+4fFx(+YlLXPrwR3^_Ihz4OEsFesJ(`JOEXh@d)eHPJcY}p!p^`aa@jMi zrj~m}w9~U(8np49)k^z5(QHBX_>Oz3OY=zA@s||s&-cvmjFx7>{)JA_#1|7+G{X)k zFOY{;td*p_$jewD`|$6Ez#f2QGMZ6fUlCjk|ARYka_dhX8T3fEbNbL_oIZFFd=qP1 zn0}y$=nuhlrkm661^q48yh=nk5(-0!QLt?@j_64dDIw+XH_$J3M&)TCiwO|I||g^V(;06@G7cKAVi1*sP+F_|Gil;O^eHaUd{UtDrye? zOQ;K~o(5}{smi71Ra8wAIpXID3om(p^#9$n_pnMKy}&1s4H#A{*)hZF0Cu#XE+S+M z>o2JD2pR2GL;U?&g7Sm1*l!|;nffyy1tgQ!+JE} zCxVOqq=!`ck=HKJyD#`Y&!z@&L(A8I82-RRRpa2jfO0!rG~>;H>wboTybWhyz(wuo zkCqDt{xIah(W6HT<%OPE9RubnIGdZgd94-hE8sgAa8dn#`h~9j@7(<-fBtXm-SvrY z?7>ZO{*|W&{vn2fhd(5M1pYS!cEbEIeV*1AnrDReQV;hYYDj;#wQ7RVzcUZrIW#j4 zu5$RM4y}hq{*KOp@8(__s+rfNf)H>%0?mO== zU$Q_j-*AUNhg{~{?{KeQD7fzd^E>0;4tD#&+=oWO^^?28JqqS>x1sC41nka$xnzWS zGBBXpK`n*YU*a!J@GtVQFgv-r>zjN+i1pT=+x9%(bZvTmfe=c(a z{}cKaxBnF!82KOj3qNYl-4>buKN@#EOGBr5b>vUTA5Q0iQJ;6K%J;%IGpdq=;l&Y2}`d^S$><@p!JZ9ABl6r`CXtGrk^X6oFp;wvk2_N1I# z{`O+agOB%J$~2yRW9qqwy`A^(xFmV!-1i9&Utjp-Z(skzZ$lMJX5VuvBce2C;N-7n z>>*2bt}FhNc+KbOQ-bsU_L5CGbHmNhzZSMw9|-y4)!(lUw)~LKEjPXYn@=J=YgVtW zER)C2nYC+;=z^m{`cX*j1b4jGOn%C^DtYRnzh3Wo`}M!SefC#-@~2%;Tv+g0^URJ< z9t_^JW~1j(=2tELyO(Q2KYUD{=XhYZedw)!G_99>@v`H>%O8ATd--H*+V1mxuY547 zf1NzEI_hln#$}FKU;J*%{hzPAy4aL+-7?z~!=^?lhxi(?M#S-L#R-m&h?pSow4-nF6T>DhZ; z&8gTo?o7wwP|4a)m&f~Fs_A;jPx--Xh6mTi~7EJ2hQYz%l%G|?*KLE zBj8Ggs|cu=Bb0$^C2`}O};m4faa}Te}8f*&0h&`r~g3n*tkRD9WM@Ox5)@H1D4DJ-?gg-#x$HFoWjdu=TR%Xg;oP_Bc-S za!r-5jOOPXlaHj*JRN=@{C=9R&rRIBkml`wZhPSsn!o>1{N~d%k8jvoKb_|DQ-3&@ zM)Uf;@y%mselPL3kV*4AqcQHH`F_=lR}Rs(n8Swj^HIJ5qiQJ<3 zv@GmA{JxHshy90+?4)HPcatH9mW#FDJ^N2uHa4Wc{1q)9#S0Jg(lYYrrwm`ya#H(s zaXl?7ukPIXDJ?HIww`~0mYJf-fl0L7*f$NXqh)7cTFG6s{6ySc974;`**`Y_gO;O! z#=fnzEKSO_e@)9%r#bxFzuY(BBhNiOs(m|K58wUW@q?c}_W8FBhpWDSV(w!S+ z-&i&%d1KA~?%v0WWqw2X@~K?KkxpyH*@0S)*GFXPb?U?_G#j#>OU6-7NpH;8<$-1zs6&< zro|sMA9(EAg0#Wkf870M=WF(!cWyoxK4s=l{c*2A&5O^Q!*W9j_$(xNFDfDnI8BM-IwI4-~$b9JqJ=<1zu!6L z9}jx}{kSesmLUnff6w1GTUNbrvhno(sg=)sGUs;{`Io-6KJo|YdktYR!EbEuJM*RE zp4oqV`l*`x-Y!k|xa@0=pZ{*_2jhS9)s;00+p%Y#fBEheXaABH@z1t(Px}1nl(F2f zHhR>SdG9MtUJreuneuwVpY*T(X6X-~U0?F`wC0y5J6FU#o0PowA7}qO@6qRVZ|n(~ z@qOkC-o|Sm&XLBfD~&i7x^?ldx-%-DJ{)Gha=E0ne2wzs*Y59sz`CQOq9#52=DBx2 ze=s0*{`zNLS=N4Z6KUJ^H`z}o3&cCOrAQ7%-Tmv2W{zS%c=L}Q%;={cPF$rh%q{!k z+ZQkX^)G|lPt~s8>`;J|5K5#QLE`G|?glUQQPM-m~A-G_~ z$wMTTcuKuw-f|z`QGN>l(PILXfn&!BUfvZHJpS%`IF&jiG%S2VMC8OtQPDAz;X6FB zy#3n7=7sCNJ683@uApCk`hn#m87mnh@eCkgwOm*obZRQiHsY{Vl9a?OF04dG!WuYp zh23f{Y2-@nRx6kga7!=x7sgy=yrmB{_mSDE7Mm+dlB#34Oh-u!4g5d3py{I#o>f=HX=6D!>tYJgY7=$S z5_Qn4A!JfgdP-*IT)5{h$jwL=?zt%`$-EtyrKcFOd3DBIqalwPgPV-GS#y(9-0JzJ zjCoW;%}ptWVK;{4Bruzwn`JP~%bf>*csFkSTcsBTiGVa~97UM;v!$;~bd)94D^7Y)yl5j`(GW6tap)9qH3=3-J) z37@xwKQ%Rkj2((2CDz3x3UaiN!Qk0>++wS})>d7W7*-PF{vW|3j)a$yWp3oOS{LJl zM9s9s_$f5Z+~nD}9<1fF4CEv51C(}n{nkY7G>zu*SlFSs~3#kj?dAC2e!ZT#^*6!!#<>d~?!}T5^ zj=7n+84FW*H%Xaub6t5L`_?-GH}JkvU@n4&lbkUpb*?MUS$PG5-zld26jz!?!bMjL1;9=?yxC0D)GI)LR z+$=-J9I(sIn3G2R%SxUDNrZ_9U9W+-z6*%W;|I-ntJz3uf;3K0h;q z&wKNe)047k81(Lr1Fv?)fvR%_ANaTkdI1-G&X6~6ZqnR2bEujxrhJ7!(@FJnv)$TZ z`{az=q`7>q7P2LWQ8nskIMbeP?ul`Wi zw0%f~=m?$(YT;oa^9f}h%)?5e)KGlXQMZK`1;+e;-YcPwh*Hl>%Koq13cRI{yu`a+)({Ja(as%p+w z1C|-dxAJ!;NDv%-@3)KyWGVs~hCn7HDRbtT7L2gVvenjdHD>7< zRaTc+Ijh}XZRekJR9ABq)m3Fw1G#tD0vOVq&by(CTQ-F7dcM)VWeV;cu2({!ok>kG zajAKkLVn_#pj%o3IVY?ReD;xf>_` z4<6nJpT2T)EmvGlr3WfT5NmA>%_oJBP6t;i#OAiV>&oG`^6qe!CuT>X1Cmq=uN4Hzr9! z;Q(2RgYaq{lt7u)!9n>+;)_orkDmZrA(fz=S6q{8wSx%8mjI~7!3_L|tihS#?f$Ev zX!++ogS)K+kVAdK>*qlJsD&^gzj6;-txz9U*cMYy;YTwh%|EquHT0G9DHLjgF#cuH z_ed4|`=r%~`^Cbu^D|O2ZYwNqvs<9+`Npel(~6)t-wE*Hg_JEA(Wr$8a~5T z+G;D!4k$(S<<=^$vZRWJ3;EU6>A209XINfc>!4LOpAT-gCc}1oZol1<@~`Cq|MJr# z?0(^CLR`WzH-pp0XdulH`??A%XbtlStxkjzBZLX{n%M%DuH^j8-fd20H$he#DRT?& z$S`jbNLp?+Z1Z-|ygA=iQNfi~+l#H7qZ;ZTzMfF2RDwGnnWe6_k*kS`;k!@Zp0B%; z%vHtK3RgaMxv6!#p>3izI+iw%WD;}|t<`mW0hz>?WL`!A`6@92k_>e+oc#uW)M2%1 zs)q)iSNsRrfx7#*!UgrKw8C6=tJZ-vyYRj$&9x7YG^;H(SGmjooNCTMa}va##^OH( zAvC<;9^^8RCk0u>M|P{8;QOZ_L_xi4g=7+1c4&1)3o%qarM5D6$S|HHl<#4CckKbf z=dhz&@q)7&^Bb{-1i$R}^91$*koRs%S0Sq#f$$jt?-pWEflnLTIj z{5jN4;7;Fmy{*&+<-W9<8bcjrD*?%dSJ#+pYwN4+!}^h7(f4%c`x$BPepl{y^b2+% zQq!>cpoF+`^=4Ny;nJ7dpbn;Wb(NKuP6(;5sfGHpxEMstC|4L%6Ib{`Zsj8`xT&sjJ8|n>#h&-GxVo~EHYRRi zAk~yr2pt9fc~b#5H$PRVNGx@wTxnfJ1yn3DI(HA&fWb#a}Y zwyK<^8d?)tp9>73d!vKL2;8;w9;Qj4Ss2#43O}lb_zB{`jJhh}{Xv@tBT=`^N16)m z%{3qbIO=K&E2@hhwwBD$3jDyZg6|m>+O1{K+}h1{-ir4N#yM=o)ueoolPCsjw#THBfX)mA$&6!fK7yM$-V^Z82YYQ9r}#qTv-3M2FQuc#d+b9ZEbkuP|Gz z6>zsUI0~yuiwhmq4_jeqj@Up@8mXshFtgfA&Ba!*f7sesV}>`n*k*UsnJWsRy{oA( zHkxqDhU8QB%1qfR@>4I{0$^xjW@8t{szj8w@Cr+Hm!JC1)7OGrJBL{l^8TU9b z)l6SpT~AwKeHrx5D`KF^x{r6`9#`hwJk(gDg){H(bOZj~`Qx9Za+WXvo2a7(X({u# z$!5o7dv)dH#oEa;ZMB6UQ-K^>Sj(5T88DP$< z=E?Cf8ZKf!v@nozZq7U|K1LhK8ET-|&$n7;+Z>bQW2eT%PT?YEr_amEjDo)8!&WZM zTKsTzB$reUiLg$N)x>CGwDHrX#b`BJF4tUYw%go~!ALtaQ#BCa#L2*0&_GpE3~!>U zERidF#8wkkVg&)r0TFarXF}(z&J3fs+#}`DNpqsCmgv0Pdl${n#3cC0D8msg+xv*Sx5k_QH-EP86@@|V8W9!A_eDUaNi418hcoziP(AJAHdfbxGzX0r z$ZwS(Ux0hExZ1|cBQY`1_JKQoIEYF`@MQGJA4ow}e13&82g5%jt)io4x4XUF@=hHe zr#lV*wO&T3AR%q0{Mg=@{NKn z1muDWYh__^m1Bgi*7k@sl9z43!Gxrx*_Z4`G)13>=$^L1bytK)>I6+*wIkm4vT zw^HF0g5W)daDMKtxZG9);-||2AEe6{S3lnUsF0=+b|8EY+tJw7mO_H-AQm+G{~^LI z_w~H{db`a5)4uefx&&@w4G8+60*~M|49B?;x)~K_kk)F=rB*(LG+l*sD9;rO+Wyme zf&-xkroZSt&UH_qcj^>wq}*IlO8ae8P4Ar9!3p`AgZxADcO<8p!Tk#>+3@psJ{KoE z=l1>=tYv&0?zGSe&(Y}pf)$LxK_ywiRhQC{OF9?M)muTH27#HY1!+@8pp;a@j0>M% zYin!*COQht=T8-%Z%x^miE7#!!#@zlG_-OuWzPdMn&1Lz)F6ykjOe9DsVi({s-$C}T<*opsgfYT@I`i?1p}YL0_Wvey-Y4qjXCaSx{%0Y>R>PFp z(NvO8gRXe7o$t)SJAlFF8W`yY@e1-lx)thd&SYIw2ZMxA+@N?9Vepv~tRl43 zh~x_4xXg6CS<JCF_Er0H_qXg~f9`*Bb(Ix-j02mI{^dhoth5m<;v?O0 zq@CE524Qp@ET-^&rMh6a4N~ZA2N#i7^>7u4laa8FJuU{e-`(anqjo(JtNQ9ec}+;qOxOuLsZzuogMjW9;T&%wCO z>AVHJ1RM0A=(9A9)Gdrpl=73dV4PG=Cmq4iJ;EIU{et3$IjA1tbwb@kV^JFk^S#5P z^IVCo3|`_bxyx1VpvTb&?)bzLo<$;;YULw(`|v)kn4sTPS5a3>vg<4rwqiO+0CJvC zetC@`)kB=2&jP)Z=uD6s9OZZF6FHhLkm(65ok^x@I=3M7dU!dnmNI%&H8V!@7_5RZAFAl9d#LxFUj^i*4*TXzdVVd6GUeC{`5RxR#@|c9>rH{O% z>tSt^ua~v`r)J^zhjnDH?(QZ)fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 p2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009Dj1#YN|wIKii diff --git a/src/ISerial.cpp b/src/ISerial.cpp deleted file mode 100644 index 786ed00e74..0000000000 --- a/src/ISerial.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "ISerial.h" - -ISerial::ISerial(Module* mod) { - _mod = mod; -} - -void ISerial::begin(long speed) { - _mod->ModuleSerial->begin(speed); -} - -#if !defined(__ASR6501__) -void ISerial::end() { - _mod->ModuleSerial->end(); -} -#endif - -int ISerial::peek() { - return(_mod->ModuleSerial->peek()); -} - -size_t ISerial::write(uint8_t b) { - return(_mod->ModuleSerial->write(b)); -} - -int ISerial::read() { - return(_mod->ModuleSerial->read()); -} - -int ISerial::available() { - return(_mod->ModuleSerial->available()); -} - -void ISerial::flush() { - _mod->ModuleSerial->flush(); -} - -#if !defined(ARDUINO_ARCH_MEGAAVR) -size_t ISerial::print(const __FlashStringHelper *ifsh) { - return(_mod->ModuleSerial->print(ifsh)); -} -#endif - -size_t ISerial::print(const String &s) { - return(_mod->ModuleSerial->print(s)); -} - -size_t ISerial::print(const char str[]) { - return(_mod->ModuleSerial->print(str)); -} - -size_t ISerial::print(char c) { - return(_mod->ModuleSerial->print(c)); -} - -size_t ISerial::print(unsigned char b, int base) { - return(_mod->ModuleSerial->print(b, base)); -} - -size_t ISerial::print(int n, int base) { - return(_mod->ModuleSerial->print(n, base)); -} - -size_t ISerial::print(unsigned int n, int base) { - return(_mod->ModuleSerial->print(n, base)); -} - -size_t ISerial::print(long n, int base) { - return(_mod->ModuleSerial->print(n, base)); -} - -size_t ISerial::print(unsigned long n, int base) { - return(_mod->ModuleSerial->print(n, base)); -} - -size_t ISerial::print(double n, int digits) { - return(_mod->ModuleSerial->print(n, digits)); -} - -size_t ISerial::print(const Printable& x) { - return(_mod->ModuleSerial->print(x)); -} - -#if !defined(ARDUINO_ARCH_MEGAAVR) -size_t ISerial::println(const __FlashStringHelper *ifsh) { - return(_mod->ModuleSerial->println(ifsh)); -} -#endif - -size_t ISerial::println(const String &s) { - return(_mod->ModuleSerial->println(s)); -} - -size_t ISerial::println(const char str[]) { - return(_mod->ModuleSerial->println(str)); -} - -size_t ISerial::println(char c) { - return(_mod->ModuleSerial->println(c)); -} - -size_t ISerial::println(unsigned char b, int base) { - return(_mod->ModuleSerial->println(b, base)); -} - -size_t ISerial::println(int n, int base) { - return(_mod->ModuleSerial->println(n, base)); -} - -size_t ISerial::println(unsigned int n, int base) { - return(_mod->ModuleSerial->println(n, base)); -} - -size_t ISerial::println(long n, int base) { - return(_mod->ModuleSerial->println(n, base)); -} - -size_t ISerial::println(unsigned long n, int base) { - return(_mod->ModuleSerial->println(n, base)); -} - -size_t ISerial::println(double n, int digits) { - return(_mod->ModuleSerial->println(n, digits)); -} - -size_t ISerial::println(const Printable& x) { - return(_mod->ModuleSerial->println(x)); -} - -size_t ISerial::println(void) { - return(_mod->ModuleSerial->println()); -} diff --git a/src/ISerial.h b/src/ISerial.h deleted file mode 100644 index 52d05bf52f..0000000000 --- a/src/ISerial.h +++ /dev/null @@ -1,60 +0,0 @@ -#if !defined(_RADIOLIB_ISERIAL_H) -#define _RADIOLIB_ISERIAL_H - -#include "Module.h" - -/*! - \class ISerial - - \brief Interface class for Arduino Serial. Only calls the appropriate methods for the active UART interface. -*/ -class ISerial { - public: - explicit ISerial(Module* mod); - - void begin(long); - #if !defined(__ASR6501__) - void end(); - #endif - int peek(); - size_t write(uint8_t); - int read(); - int available(); - void flush(); - - #if !defined(ARDUINO_ARCH_MEGAAVR) - size_t print(const __FlashStringHelper *); - #endif - size_t print(const String &); - size_t print(const char[]); - size_t print(char); - size_t print(unsigned char, int = DEC); - size_t print(int, int = DEC); - size_t print(unsigned int, int = DEC); - size_t print(long, int = DEC); - size_t print(unsigned long, int = DEC); - size_t print(double, int = 2); - size_t print(const Printable&); - - #if !defined(ARDUINO_ARCH_MEGAAVR) - size_t println(const __FlashStringHelper *); - #endif - size_t println(const String &s); - size_t println(const char[]); - size_t println(char); - size_t println(unsigned char, int = DEC); - size_t println(int, int = DEC); - size_t println(unsigned int, int = DEC); - size_t println(long, int = DEC); - size_t println(unsigned long, int = DEC); - size_t println(double, int = 2); - size_t println(const Printable&); - size_t println(void); - -#if !(defined(RADIOLIB_LOW_LEVEL) || defined(RADIOLIB_GODMODE)) - protected: -#endif - Module* _mod; -}; - -#endif diff --git a/src/RadioLib.h b/src/RadioLib.h index d7717c8d9c..b7bca87c41 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -8,15 +8,12 @@ \par Currently Supported Wireless Modules and Protocols - CC1101 FSK module - - HC05 Bluetooth module - - JDY08 BLE module - RF69 FSK module - Si443x FSK module - SX126x LoRa/FSK module - SX127x LoRa/FSK module - SX128x LoRa/GFSK/BLE/FLRC module - SX1231 FSK module - - XBee module (S2B) - PhysicalLayer protocols - RTTY (RTTYClient) - Morse Code (MorseClient) @@ -24,9 +21,6 @@ - SSTV (SSTVClient) - Hellschreiber (HellClient) - 4-FSK (FSK4Client) - - TransportLayer protocols - - HTTP (HTTPClient) - - MQTT (MQTTClient) \par Quick Links Documentation for most common methods can be found in its reference page (see the list above).\n @@ -34,7 +28,6 @@ \ref status_codes have their own page.\n Some modules implement methods of one or more compatibility layers, loosely based on the ISO/OSI model: - PhysicalLayer - FSK and LoRa radio modules - - TransportLayer - Modules with Internet connectivity \see https://github.com/jgromes/RadioLib @@ -47,24 +40,21 @@ // warnings are printed in this file since BuildOpt.h is compiled in multiple places // check God mode -#ifdef RADIOLIB_GODMODE +#if defined(RADIOLIB_GODMODE) #warning "God mode active, I hope it was intentional. Buckle up, lads." #endif // print debug info -#ifdef RADIOLIB_DEBUG +#if defined(RADIOLIB_DEBUG) #pragma message "RADIOLIB_PLATFORM: " RADIOLIB_PLATFORM #endif // check unknown/unsupported platform -#ifdef RADIOLIB_UNKNOWN_PLATFORM +#if defined(RADIOLIB_UNKNOWN_PLATFORM) #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" #endif #include "modules/CC1101/CC1101.h" -#include "modules/ESP8266/ESP8266.h" -#include "modules/HC05/HC05.h" -#include "modules/JDY08/JDY08.h" #include "modules/LLCC68/LLCC68.h" #include "modules/nRF24/nRF24.h" #include "modules/RF69/RF69.h" @@ -89,7 +79,6 @@ #include "modules/SX128x/SX1280.h" #include "modules/SX128x/SX1281.h" #include "modules/SX128x/SX1282.h" -#include "modules/XBee/XBee.h" // physical layer protocols #include "protocols/PhysicalLayer/PhysicalLayer.h" @@ -101,13 +90,8 @@ #include "protocols/SSTV/SSTV.h" #include "protocols/FSK4/FSK4.h" -// transport layer protocols -#include "protocols/TransportLayer/TransportLayer.h" -#include "protocols/HTTP/HTTP.h" -#include "protocols/MQTT/MQTT.h" - // only create Radio class when using RadioShield -#ifdef RADIOLIB_RADIOSHIELD +#if defined(RADIOLIB_RADIOSHIELD) // RadioShield pin definitions #define RADIOSHIELD_CS_A 10 @@ -139,7 +123,7 @@ class Radio { ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_B, RADIOSHIELD_TX_B, SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), nullptr); } -#ifndef RADIOLIB_GODMODE +#if defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/ESP8266/ESP8266.cpp b/src/modules/ESP8266/ESP8266.cpp deleted file mode 100644 index fe62cc8e1b..0000000000 --- a/src/modules/ESP8266/ESP8266.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include "ESP8266.h" -#if !defined(RADIOLIB_EXCLUDE_ESP8266) && !defined(ESP8266) - -ESP8266::ESP8266(Module* module) { - _mod = module; -} - -int16_t ESP8266::begin(long speed) { - // set module properties - char lf[3] = "\r\n"; - memcpy(_mod->AtLineFeed, lf, strlen(lf)); - _mod->baudrate = speed; - _mod->init(RADIOLIB_USE_UART); - - // empty UART buffer (garbage data) - _mod->ATemptyBuffer(); - - // test AT setup - if(!_mod->ATsendCommand("AT")) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -int16_t ESP8266::reset() { - // send the reset command - if(!_mod->ATsendCommand("AT+RST")) { - return(ERR_AT_FAILED); - } - - // wait for the module to start - Module::delay(2000); - - // test AT setup - uint32_t start = Module::millis(); - while (Module::millis() - start < 3000) { - if(!_mod->ATsendCommand("AT")) { - Module::delay(100); - } else { - return(ERR_NONE); - } - } - - return(ERR_AT_FAILED); -} - -int16_t ESP8266::join(const char* ssid, const char* password) { - // set mode to station + soft AP - if(!_mod->ATsendCommand("AT+CWMODE_CUR=3")) { - return(ERR_AT_FAILED); - } - - // build AT command - const char* atStr = "AT+CWJAP_CUR=\""; - #ifdef RADIOLIB_STATIC_ONLY - char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4; - char* cmd = new char[cmdLen + 1]; - #endif - strcpy(cmd, atStr); - strcat(cmd, ssid); - strcat(cmd, "\",\""); - strcat(cmd, password); - strcat(cmd, "\""); - - // send command - bool res = _mod->ATsendCommand(cmd); - #ifndef RADIOLIB_STATIC_ONLY - delete[] cmd; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - // disable multiple connection mode - if(!_mod->ATsendCommand("AT+CIPMUX=0")) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -int16_t ESP8266::openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive) { - char portStr[6]; - sprintf(portStr, "%u", port); - char tcpKeepAliveStr[6]; - sprintf(tcpKeepAliveStr, "%u", tcpKeepAlive); - - // build AT command - const char* atStr = "AT+CIPSTART=\""; - #ifdef RADIOLIB_STATIC_ONLY - char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t cmdLen = strlen(atStr) + strlen(protocol) + strlen(host) + strlen(portStr) + 5; - if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) { - cmdLen += strlen(tcpKeepAliveStr) + 1; - } - char* cmd = new char[cmdLen + 1]; - #endif - strcpy(cmd, atStr); - strcat(cmd, protocol); - strcat(cmd, "\",\""); - strcat(cmd, host); - strcat(cmd, "\","); - strcat(cmd, portStr); - if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) { - strcat(cmd, ","); - strcat(cmd, tcpKeepAliveStr); - } - - // send command - bool res = _mod->ATsendCommand(cmd); - #ifndef RADIOLIB_STATIC_ONLY - delete[] cmd; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -int16_t ESP8266::closeTransportConnection() { - // send AT command - if(!_mod->ATsendCommand("AT+CIPCLOSE")) { - return(ERR_AT_FAILED); - } - return(ERR_NONE); -} - -int16_t ESP8266::send(const char* data) { - // build AT command - char lenStr[12]; - sprintf(lenStr, "%u", (uint16_t)strlen(data)); - const char* atStr = "AT+CIPSEND="; - #ifdef RADIOLIB_STATIC_ONLY - char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1]; - #endif - strcpy(cmd, atStr); - strcat(cmd, lenStr); - - // send command - bool res = _mod->ATsendCommand(cmd); - #ifndef RADIOLIB_STATIC_ONLY - delete[] cmd; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - // send data - if(!_mod->ATsendCommand(data)) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -int16_t ESP8266::send(uint8_t* data, size_t len) { - // build AT command - char lenStr[8]; - sprintf(lenStr, "%u", (uint16_t)len); - const char atStr[] = "AT+CIPSEND="; - #ifdef RADIOLIB_STATIC_ONLY - char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1]; - #endif - strcpy(cmd, atStr); - strcat(cmd, lenStr); - - // send command - bool res = _mod->ATsendCommand(cmd); - #ifndef RADIOLIB_STATIC_ONLY - delete[] cmd; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - // send data - if(!_mod->ATsendData(data, len)) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) { - size_t i = 0; - uint32_t start = Module::millis(); - - // wait until the required number of bytes is received or until timeout - while((Module::millis() - start < timeout) && (i < len)) { - Module::yield(); - while(_mod->ModuleSerial->available() > 0) { - uint8_t b = _mod->ModuleSerial->read(); - RADIOLIB_DEBUG_PRINT(b); - data[i] = b; - i++; - } - } - return(i); -} - -size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) { - // wait for available data - uint32_t start = Module::millis(); - while(_mod->ModuleSerial->available() < (int16_t)minBytes) { - Module::yield(); - if(Module::millis() - start >= timeout) { - return(0); - } - } - - // read response - char rawStr[20]; - uint8_t i = 0; - start = Module::millis(); - while(_mod->ModuleSerial->available() > 0) { - Module::yield(); - char c = _mod->ModuleSerial->read(); - rawStr[i++] = c; - if(c == ':') { - rawStr[i++] = 0; - break; - } - if(Module::millis() - start >= timeout) { - rawStr[i++] = 0; - break; - } - } - - // get the number of bytes in response - char* pch = strtok(rawStr, ",:"); - if(pch == NULL) { - return(0); - } - - pch = strtok(NULL, ",:"); - if(pch == NULL) { - return(0); - } - - return(atoi(pch)); -} -#endif diff --git a/src/modules/ESP8266/ESP8266.h b/src/modules/ESP8266/ESP8266.h deleted file mode 100644 index f0a613057c..0000000000 --- a/src/modules/ESP8266/ESP8266.h +++ /dev/null @@ -1,68 +0,0 @@ -#if !defined(_RADIOLIB_ESP8266_H) && !defined(RADIOLIB_EXCLUDE_ESP8266) && !defined(ESP8266) -#define _RADIOLIB_ESP8266_H - -#include "../../TypeDef.h" -#include "../../Module.h" - -#include "../../protocols/TransportLayer/TransportLayer.h" - -/*! - \class ESP8266 - - \brief Control class for %ESP8266 module. Implements TransportLayer methods. -*/ -class ESP8266: public TransportLayer { - public: - /*! - \brief Default constructor. - - \param mod Instance of Module that will be used to communicate with the radio. - */ - ESP8266(Module* module); - - // basic methods - - /*! - \brief Initialization method. - - \param speed Baud rate to use for UART interface. - - \returns \ref status_codes - */ - int16_t begin(long speed); - - /*! - \brief Resets module using AT command. - - \returns \ref status_codes - */ - int16_t reset(); - - /*! - \brief Joins access point. - - \param ssid Access point SSID. - - \param password Access point password. - */ - int16_t join(const char* ssid, const char* password); - - // transport layer methods (implementations of purely virtual methods in TransportLayer class) - int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0) override; - int16_t closeTransportConnection() override; - int16_t send(const char* data) override; - int16_t send(uint8_t* data, size_t len) override; - size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000) override; - size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10) override; - -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) - protected: -#endif - Module* _mod; - -#if !defined(RADIOLIB_GODMODE) - protected: -#endif -}; - -#endif diff --git a/src/modules/HC05/HC05.cpp b/src/modules/HC05/HC05.cpp deleted file mode 100644 index 7a35ce7141..0000000000 --- a/src/modules/HC05/HC05.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "HC05.h" -#if !defined(RADIOLIB_EXCLUDE_HC05) - -HC05::HC05(Module* mod) : ISerial(mod) { - -} - -void HC05::begin(long speed) { - // set module properties - _mod->baudrate = speed; - _mod->init(RADIOLIB_USE_UART); -} - -#endif diff --git a/src/modules/HC05/HC05.h b/src/modules/HC05/HC05.h deleted file mode 100644 index 7721a50a5e..0000000000 --- a/src/modules/HC05/HC05.h +++ /dev/null @@ -1,29 +0,0 @@ -#if !defined(_RADIOLIB_HC05_H) && !defined(RADIOLIB_EXCLUDE_HC05) -#define _RADIOLIB_HC05_H - -#include "../../ISerial.h" - -/*! - \class HC05 - - \brief Control class for %HC05 module. - Most methods supported by this module are implemented in ISerial interface. -*/ -class HC05: public ISerial { - public: - /*! - \brief Default constructor. - - \param mod Instance of Module that will be used to communicate with the radio. - */ - HC05(Module* mod); - - /*! - \brief Initialization method. - - \param speed Baud rate to use for UART interface. - */ - void begin(long speed); -}; - -#endif diff --git a/src/modules/JDY08/JDY08.cpp b/src/modules/JDY08/JDY08.cpp deleted file mode 100644 index 0179a1424d..0000000000 --- a/src/modules/JDY08/JDY08.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#if !defined(_RADIOLIB_JDY08_H) && !defined(RADIOLIB_EXCLUDE_JDY08) -#include "JDY08.h" - -JDY08::JDY08(Module* mod) : ISerial(mod) { - -} - -void JDY08::begin(long speed) { - // set module properties - char lf[3] = ""; - memcpy(_mod->AtLineFeed, lf, strlen(lf)); - _mod->baudrate = speed; - _mod->init(RADIOLIB_USE_UART); -} - -#endif diff --git a/src/modules/JDY08/JDY08.h b/src/modules/JDY08/JDY08.h deleted file mode 100644 index 7bb6401104..0000000000 --- a/src/modules/JDY08/JDY08.h +++ /dev/null @@ -1,29 +0,0 @@ -#if !defined(_RADIOLIB_JDY08_H) && !defined(RADIOLIB_EXCLUDE_JDY08) -#define _RADIOLIB_JDY08_H - -#include "../../ISerial.h" - -/*! - \class JDY08 - - \brief Control class for %JDY08 module. - Most methods supported by this module are implemented in ISerial interface. -*/ -class JDY08: public ISerial { - public: - /*! - \brief Default constructor. - - \param mod Instance of Module that will be used to communicate with the radio. - */ - JDY08(Module* mod); - - /*! - \brief Initialization method. - - \param speed Baud rate to use for UART interface. - */ - void begin(long speed); -}; - -#endif diff --git a/src/modules/XBee/XBee.cpp b/src/modules/XBee/XBee.cpp deleted file mode 100644 index 73bb934eb2..0000000000 --- a/src/modules/XBee/XBee.cpp +++ /dev/null @@ -1,485 +0,0 @@ -#include "XBee.h" -#if !defined(RADIOLIB_EXCLUDE_XBEE) - -XBee::XBee(Module* mod) { - _mod = mod; - _packetData[0] = '\0'; -} - -int16_t XBee::begin(long speed) { - // set module properties - _mod->baudrate = speed; - _mod->init(RADIOLIB_USE_UART); - - // reset module - reset(); - - // empty UART buffer (garbage data) - _mod->ATemptyBuffer(); - - // try to find the XBee - bool flagFound = false; - uint8_t i = 0; - while((i < 10) && !flagFound) { - // hardware reset should return 2 modem status frames - 1st status 0x00, second status 0x06 - int16_t state = readApiFrame(0x00, 1, 2000); - readApiFrame(0x00, 1, 2000); - - if(state == ERR_NONE) { - flagFound = true; - } else { - RADIOLIB_DEBUG_PRINT(F("XBee not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) STATE == ")); - RADIOLIB_DEBUG_PRINTLN(state); - RADIOLIB_DEBUG_PRINTLN(F("Resetting ...")); - reset(); - Module::delay(10); - _mod->ATemptyBuffer(); - i++; - } - } - - if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN(F("No XBee found!")); - return(ERR_CMD_MODE_FAILED); - } else { - RADIOLIB_DEBUG_PRINTLN(F("Found XBee!")); - } - - return(ERR_NONE); -} - -void XBee::reset() { - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), HIGH); -} - -int16_t XBee::transmit(uint8_t* dest, const char* payload, uint8_t radius) { - uint8_t destNetwork[] = {0xFF, 0xFE}; - return(transmit(dest, destNetwork, payload, radius)); -} - -int16_t XBee::transmit(uint8_t* dest, uint8_t* destNetwork, const char* payload, uint8_t radius) { - // build the frame - size_t payloadLen = strlen(payload); - size_t dataLen = 8 + 2 + 1 + 1 + payloadLen; - #ifdef RADIOLIB_STATIC_ONLY - uint8_t cmd[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* cmd = new uint8_t[dataLen]; - #endif - memcpy(cmd, dest, 8); - memcpy(cmd + 8, destNetwork, 2); - cmd[10] = radius; - cmd[11] = 0x01; // options: no retries - memcpy(cmd + 12, payload, payloadLen); - - // send frame - uint8_t frameID = _frameID++; - sendApiFrame(XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST, frameID, cmd, dataLen); - #ifndef RADIOLIB_STATIC_ONLY - delete[] cmd; - #endif - - // get response code - return(readApiFrame(frameID, 5)); -} - -size_t XBee::available() { - // check if there are data available in the buffer - size_t serialBytes = _mod->ModuleSerial->available(); - if(serialBytes < 3) { - return(0); - } - - if(!_frameHeaderProcessed) { - // read frame header - uint8_t header[3]; - for(uint8_t i = 0; i < 3; i++) { - header[i] = _mod->ModuleSerial->read(); - } - - // check if we received API frame - if(header[0] != XBEE_API_START) { - return(0); - } - - // get expected frame length - _frameLength = ((header[1] << 8) | header[2]) + 1; - _frameHeaderProcessed = true; - } - - // check if the header is complete - if(serialBytes < _frameLength) { - return(0); - } - - #ifdef RADIOLIB_STATIC_ONLY - char frame[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* frame = new uint8_t[_frameLength]; - #endif - for(size_t i = 0; i < _frameLength; i++) { - frame[i] = _mod->ModuleSerial->read(); - } - - // save packet source and data - size_t payloadLength = _frameLength - 12; - #ifndef RADIOLIB_STATIC_ONLY - delete[] _packetData; - _packetData = new char[payloadLength]; - #endif - memcpy(_packetData, frame + 12, payloadLength - 1); - _packetData[payloadLength - 1] = '\0'; - memcpy(_packetSource, frame + 1, 8); - - #ifndef RADIOLIB_STATIC_ONLY - delete[] frame; - #endif - _frameLength = 0; - _frameHeaderProcessed = false; - - // return number of bytes in payload - return(payloadLength); -} - -String XBee::getPacketSource() { - char buff[17]; - sprintf(buff, "%02X%02X%02X%02X%02X%02X%02X%02X", _packetSource[0], _packetSource[1], _packetSource[2], _packetSource[3], - _packetSource[4], _packetSource[5], _packetSource[6], _packetSource[7]); - String str(buff); - return(str); -} - -String XBee::getPacketData() { - String str(_packetData); - return(str); -} - -int16_t XBee::setPanId(uint8_t* panId) { - // build AT command - uint8_t cmd[10]; - memcpy(cmd, "ID", 2); - memcpy(cmd + 2, panId, 8); - - // send frame - uint8_t frameID = _frameID++; - sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, cmd, 10); - - // get response code - int16_t state = readApiFrame(frameID, 4); - RADIOLIB_ASSERT(state); - - // confirm changes - return(confirmChanges()); -} - -XBeeSerial::XBeeSerial(Module* mod) : ISerial(mod) { - -} - -int16_t XBeeSerial::begin(long speed) { - // set module properties - char lf[3] = "\r"; - memcpy(_mod->AtLineFeed, lf, strlen(lf)); - _mod->baudrate = speed; - _mod->init(RADIOLIB_USE_UART); - - // reset module - reset(); - - // empty UART buffer (garbage data) - _mod->ATemptyBuffer(); - - // enter command mode - RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ...")); - if(!enterCmdMode()) { - return(ERR_CMD_MODE_FAILED); - } - - // test AT setup - RADIOLIB_DEBUG_PRINTLN(F("Sending test command ...")); - if(!_mod->ATsendCommand("AT")) { - return(ERR_AT_FAILED); - } - - // exit command mode - RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ...")); - if(!_mod->ATsendCommand("ATCN")) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -void XBeeSerial::reset() { - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), HIGH); - Module::pinMode(_mod->getRst(), INPUT); -} - -int16_t XBeeSerial::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) { - // enter command mode - RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ...")); - if(!enterCmdMode()) { - return(ERR_CMD_MODE_FAILED); - } - - // set higher address bytes - RADIOLIB_DEBUG_PRINTLN(F("Setting address (high) ...")); - #ifdef RADIOLIB_STATIC_ONLY - char addressHigh[13]; - #else - char* addressHigh = new char[strlen(destinationAddressHigh) + 4]; - #endif - strcpy(addressHigh, "ATDH"); - strcat(addressHigh, destinationAddressHigh); - bool res = _mod->ATsendCommand(addressHigh); - #ifndef RADIOLIB_STATIC_ONLY - delete[] addressHigh; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - // set lower address bytes - RADIOLIB_DEBUG_PRINTLN(F("Setting address (low) ...")); - #ifdef RADIOLIB_STATIC_ONLY - char addressLow[13]; - #else - char* addressLow = new char[strlen(destinationAddressLow) + 4]; - #endif - strcpy(addressLow, "ATDL"); - strcat(addressLow, destinationAddressLow); - res = _mod->ATsendCommand(addressLow); - #ifndef RADIOLIB_STATIC_ONLY - delete[] addressLow; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - // exit command mode - RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ...")); - if(!_mod->ATsendCommand("ATCN")) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -int16_t XBeeSerial::setPanId(const char* panId) { - // enter command mode - RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ...")); - if(!enterCmdMode()) { - return(ERR_CMD_MODE_FAILED); - } - - // set PAN ID - RADIOLIB_DEBUG_PRINTLN(F("Setting PAN ID ...")); - #ifdef RADIOLIB_STATIC_ONLY - char cmd[21]; - #else - char* cmd = new char[strlen(panId) + 4]; - #endif - strcpy(cmd, "ATID"); - strcat(cmd, panId); - bool res = _mod->ATsendCommand(cmd); - #ifndef RADIOLIB_STATIC_ONLY - delete[] cmd; - #endif - if(!res) { - return(ERR_AT_FAILED); - } - - // exit command mode - RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ...")); - if(!_mod->ATsendCommand("ATCN")) { - return(ERR_AT_FAILED); - } - - return(ERR_NONE); -} - -bool XBeeSerial::enterCmdMode() { - for(uint8_t i = 0; i < 10; i++) { - Module::delay(1000); - - _mod->ModuleSerial->write('+'); - _mod->ModuleSerial->write('+'); - _mod->ModuleSerial->write('+'); - - Module::delay(1000); - - if(_mod->ATgetResponse()) { - return(true); - } else { - RADIOLIB_DEBUG_PRINT(F("Unable to enter command mode! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries)")); - - reset(); - - _mod->ATsendCommand("ATCN"); - } - } - - RADIOLIB_DEBUG_PRINTLN(F("Terminated, check your wiring. Is AT FW uploaded?")); - return(false); -} - -int16_t XBee::confirmChanges() { - // save changes to non-volatile memory - uint8_t frameID = _frameID++; - sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, "WR"); - - // get response code - int16_t state = readApiFrame(frameID, 4); - RADIOLIB_ASSERT(state); - - // apply changes - frameID = _frameID++; - sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, "AC"); - - // get response code - state = readApiFrame(frameID, 4); - - return(state); -} - -void XBee::sendApiFrame(uint8_t type, uint8_t id, const char* data) { - sendApiFrame(type, id, (uint8_t*)data, strlen(data)); -} - -void XBee::sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length) { - // build the API frame - size_t frameLength = 1 + 2 + length + 1 + 2; - #ifdef RADIOLIB_STATIC_ONLY - uint8_t frame[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* frame = new uint8_t[frameLength]; - #endif - - frame[0] = 0x7E; // start delimiter - frame[1] = ((length + 2) & 0xFF00) >> 8; // length MSB - frame[2] = (length + 2) & 0x00FF; // length LSB - frame[3] = type; // frame type - frame[4] = id; // frame ID - memcpy(frame + 5, data, length); // data - - // calculate the checksum - uint8_t checksum = 0; - for(size_t i = 3; i < frameLength - 1; i++) { - checksum += frame[i]; - } - frame[5 + length] = 0xFF - checksum; - - // send the frame - for(size_t i = 0; i < frameLength; i++) { - _mod->ModuleSerial->write(frame[i]); - } - - // deallocate memory - #ifndef RADIOLIB_STATIC_ONLY - delete[] frame; - #endif -} - -int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) { - /// \todo modemStatus frames may be sent at any time, interfering with frame parsing. Add check to make sure this does not happen. - - // get number of bytes in response (must be enough to read the length field - uint16_t numBytes = getNumBytes(timeout/2, 3); - if(numBytes == 0) { - return(ERR_FRAME_NO_RESPONSE); - } - - // checksum byte is not included in length field - numBytes++; - - // wait until all response bytes are available (5s timeout) - uint32_t start = Module::millis(); - while(_mod->ModuleSerial->available() < (int16_t)numBytes) { - Module::yield(); - if(Module::millis() - start >= timeout/2) { - return(ERR_FRAME_MALFORMED); - } - } - RADIOLIB_DEBUG_PRINT(F("frame data field length: ")); - RADIOLIB_DEBUG_PRINTLN(numBytes); - - // read the response - #ifdef RADIOLIB_STATIC_ONLY - uint8_t resp[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* resp = new uint8_t[numBytes]; - #endif - for(uint16_t i = 0; i < numBytes; i++) { - resp[i] = _mod->ModuleSerial->read(); - } - - // verify checksum - uint8_t checksum = 0; - for(uint16_t i = 0; i < numBytes; i++) { - RADIOLIB_DEBUG_PRINT(resp[i], HEX); - RADIOLIB_DEBUG_PRINT('\t'); - checksum += resp[i]; - } - RADIOLIB_DEBUG_PRINTLN(); - if(checksum != 0xFF) { - RADIOLIB_DEBUG_PRINTLN(checksum, HEX); - return(ERR_FRAME_INCORRECT_CHECKSUM); - } - - // check frame ID - if(resp[1] != frameID) { - RADIOLIB_DEBUG_PRINT(F("received frame ID: ")); - RADIOLIB_DEBUG_PRINTLN(resp[1]); - RADIOLIB_DEBUG_PRINT(F("expected frame ID: ")); - RADIOLIB_DEBUG_PRINTLN(frameID); - return(ERR_FRAME_UNEXPECTED_ID); - } - - // codePos does not include start delimiter and frame ID - uint8_t code = resp[codePos]; - #ifndef RADIOLIB_STATIC_ONLY - delete[] resp; - #endif - return(code); -} - -uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) { - // wait for available data - uint32_t start = Module::millis(); - while((size_t)_mod->ModuleSerial->available() < minBytes) { - Module::yield(); - if(Module::millis() - start >= timeout) { - return(0); - } - } - - // read response - uint8_t resp[3]; - uint8_t i = 0; - RADIOLIB_DEBUG_PRINT(F("reading frame length: ")); - while(_mod->ModuleSerial->available() > 0) { - Module::yield(); - uint8_t b = _mod->ModuleSerial->read(); - RADIOLIB_DEBUG_PRINT(b, HEX); - RADIOLIB_DEBUG_PRINT('\t'); - resp[i++] = b; - if(i == 3) { - break; - } - } - RADIOLIB_DEBUG_PRINTLN(); - - return((resp[1] << 8) | resp[2]); -} - -#endif diff --git a/src/modules/XBee/XBee.h b/src/modules/XBee/XBee.h deleted file mode 100644 index 920ad3759c..0000000000 --- a/src/modules/XBee/XBee.h +++ /dev/null @@ -1,204 +0,0 @@ -#if !defined(_RADIOLIB_XBEE_H) && !defined(RADIOLIB_EXCLUDE_XBEE) -#define _RADIOLIB_XBEE_H - -#include "../../ISerial.h" -#include "../../TypeDef.h" - -// API reserved characters -#define XBEE_API_START 0x7E -#define XBEE_API_ESCAPE 0x7D -#define XBEE_API_XON 0x11 -#define XBEE_API_XOFF 0x13 - -// API frame IDs -#define XBEE_API_FRAME_AT_COMMAND 0x08 -#define XBEE_API_FRAME_AT_COMMAND_QUEUE 0x09 -#define XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST 0x10 -#define XBEE_API_FRAME_ZIGBEE_ADDRESS_EXPLICIT 0x11 -#define XBEE_API_FRAME_REMOTE_COMMAND 0x17 -#define XBEE_API_FRAME_CREATE_SOURCE_ROUTE 0x21 -#define XBEE_API_FRAME_AT_COMMAND_RESPONSE 0x88 -#define XBEE_API_FRAME_MODEM_STATUS 0x8A -#define XBEE_API_FRAME_ZIGBEE_TRANSMIT_STATUS 0x8B -#define XBEE_API_FRAME_ZIGBEE_RECEIVE_PACKET 0x90 -#define XBEE_API_FRAME_ZIGBEE_EXPLICIT_RX 0x91 -#define XBEE_API_FRAME_ZIGBEE_IO_DATA_SAMPLE_RX 0x92 -#define XBEE_API_FRAME_SENSOR_READ 0x94 -#define XBEE_API_FRAME_NODE_ID 0x95 -#define XBEE_API_FRAME_REMOTE_COMMAND_RESPONSE 0x97 -#define XBEE_API_FRAME_EXTENDED_MODEM_STATUS 0x98 -#define XBEE_API_FRAME_OTA_FW_UPDATE_STATUS 0xA0 -#define XBEE_API_FRAME_ROUTE_RECORD 0xA1 -#define XBEE_API_FRAME_MANY_TO_ONE_ROUTE_REQUEST 0xA3 - -/*! - \class XBeeSerial - - \brief %XBee Serial interface. This class is used for XBees in transparent mode, i.e. when two XBees act as a "wireless UART". -*/ -class XBeeSerial: public ISerial { - public: - /*! - \brief Default constructor. - - \param mod Instance of Module that will be used to communicate with the radio. - */ - XBeeSerial(Module* mod); - - // basic methods - - /*! - \brief Initialization method. - - \param speed Baud rate to use for UART interface. - - \returns \ref status_codes - */ - int16_t begin(long speed); - - /*! - \brief Resets module using interrupt/GPIO pin 1. - */ - void reset(); - - // configuration methods - - /*! - \brief Sets destination XBee address. - - \param destinationAddressHigh Higher 4 bytes of the destination XBee module, in the form of uppercase hexadecimal string (i.e. 8 characters). - - \param destinationAddressLow Lower 4 bytes of the destination XBee module, in the form of uppercase hexadecimal string (i.e. 8 characters). - - \returns \ref status_codes - */ - int16_t setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow); - - /*! - \brief Sets PAN (Personal Area Network) ID. Both XBees must be in the same PAN in order to use transparent mode. - - \param panId 8-byte PAN ID to be used, in the form of uppercase hexadecimal string (i.e. 16 characters). - */ - int16_t setPanId(const char* panId); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - bool enterCmdMode(); - -}; - -/*! - \class XBee - - \brief Control class for %XBee modules. -*/ -class XBee { - public: - /*! - \brief Default constructor. - - \param mod Instance of Module that will be used to communicate with the radio. - */ - XBee(Module* mod); - - // basic methods - - /*! - \brief Initialization method. - - \param speed Baud rate to use for UART interface. - - \returns \ref status_codes - */ - int16_t begin(long speed); - - /*! - \brief Resets module using interrupt/GPIO pin 1. - */ - void reset(); - - /*! - \brief Sends data to the destination 64-bit (global) address, when destination 16-bit (local) address is unknown. - - \param dest Destination 64-bit address, in the form of 8-byte array. - - \param payload String of payload bytes. - - \param radius Number of maximum "hops" for a broadcast transmission. Defaults to 1, set to 0 for unlimited number of hops. - */ - int16_t transmit(uint8_t* dest, const char* payload, uint8_t radius = 1); - - /*! - \brief Sends data to the destination 64-bit (global) address, when destination 16-bit (local) address is known. - - \param dest Destination 64-bit address, in the form of 8-byte array. - - \param destNetwork Destination 16-bit address, in the form of 2-byte array. - - \param payload String of payload bytes. - - \param radius Number of maximum "hops" for a broadcast transmission. Defaults to 1, set to 0 for unlimited number of hops. - */ - int16_t transmit(uint8_t* dest, uint8_t* destNetwork, const char* payload, uint8_t radius = 1); - - /*! - \brief Gets the number of payload bytes received. - - \returns Number of available payload bytes, or 0 if nothing was received. - */ - size_t available(); - - /*! - \brief Gets packet source 64-bit address. - - \returns Packet source address, in the form of uppercase hexadecimal Arduino String (i.e. 16 characters). - */ - String getPacketSource(); - - /*! - \brief Gets packet payload. - - \returns Packet payload, in the form of Arduino String. - */ - String getPacketData(); - - // configuration methods - - /*! - \brief Sets PAN (Personal Area Network) ID. All XBees must be in the same PAN in order to communicate. - - \param panId 8-byte PAN ID to be used, in the form of uppercase hexadecimal string (i.e. 16 characters). - */ - int16_t setPanId(uint8_t* panId); - -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) - protected: -#endif - Module* _mod; - -#if !defined(RADIOLIB_GODMODE) - protected: -#endif - - uint8_t _frameID = 0x01; - size_t _frameLength = 0; - bool _frameHeaderProcessed = false; - - #ifdef RADIOLIB_STATIC_ONLY - char _packetData[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - char* _packetData = new char[0]; - #endif - uint8_t _packetSource[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - int16_t confirmChanges(); - - void sendApiFrame(uint8_t type, uint8_t id, const char* data); - void sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length); - int16_t readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout = 5000); - - uint16_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10); -}; - -#endif diff --git a/src/protocols/HTTP/HTTP.cpp b/src/protocols/HTTP/HTTP.cpp deleted file mode 100644 index fae9d8ae04..0000000000 --- a/src/protocols/HTTP/HTTP.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "HTTP.h" -#if !defined(RADIOLIB_EXCLUDE_HTTP) - -HTTPClient::HTTPClient(TransportLayer* tl, uint16_t port) { - _tl = tl; - _port = port; -} - -int16_t HTTPClient::get(String& url, String& response) { - return(HTTPClient::get(url.c_str(), response)); -} - -int16_t HTTPClient::get(const char* url, String& response) { - // get the host address and endpoint - char* httpPrefix = strstr(url, "http://"); - char* endpoint; - char* host; - if(httpPrefix != NULL) { - // find the host string - char* hostStart = strchr(url, '/'); - hostStart = strchr(hostStart + 1, '/'); - char* hostEnd = strchr(hostStart + 1, '/'); - host = new char[hostEnd - hostStart]; - strncpy(host, hostStart + 1, hostEnd - hostStart - 1); - host[hostEnd - hostStart - 1] = '\0'; - - // find the endpoint string - endpoint = new char[url + strlen(url) - hostEnd + 1]; - strcpy(endpoint, hostEnd); - } else { - // find the host string - char* hostEnd = strchr(url, '/'); - host = new char[hostEnd - url + 1]; - strncpy(host, url, hostEnd - url); - host[hostEnd - url] = '\0'; - - // find the endpoint string - endpoint = new char[url + strlen(url) - hostEnd + 1]; - strcpy(endpoint, hostEnd); - } - - // build the GET request - char* request = new char[strlen(endpoint) + strlen(host) + 25 + 1]; - strcpy(request, "GET "); - strcat(request, endpoint); - strcat(request, " HTTP/1.1\r\nHost: "); - strcat(request, host); - strcat(request, "\r\n\r\n"); - - delete[] endpoint; - - // create TCP connection - int16_t state = _tl->openTransportConnection(host, "TCP", _port); - delete[] host; - if(state != ERR_NONE) { - delete[] request; - return(state); - } - - // send the GET request - state = _tl->send(request); - delete[] request; - if(state != ERR_NONE) { - return(state); - } - - // get the response length - size_t numBytes = _tl->getNumBytes(); - if(numBytes == 0) { - return(ERR_RESPONSE_MALFORMED_AT); - } - - // read the response - char* raw = new char[numBytes + 1]; - size_t rawLength = _tl->receive((uint8_t*)raw, numBytes); - if(rawLength == 0) { - delete[] raw; - return(ERR_RESPONSE_MALFORMED); - } - - // close the tl connection - state = _tl->closeTransportConnection(); - if(state != ERR_NONE) { - delete[] raw; - return(state); - } - - // get the response body - char* responseStart = strstr(raw, "\r\n"); - if(responseStart == NULL) { - delete[] raw; - return(ERR_RESPONSE_MALFORMED); - } - char* responseStr = new char[raw + rawLength - responseStart - 1 + 1]; - strncpy(responseStr, responseStart + 2, raw + rawLength - responseStart - 1); - responseStr[raw + rawLength - responseStart - 2] = '\0'; - response = String(responseStr); - delete[] responseStr; - - // return the HTTP status code - char* statusStart = strchr(raw, ' '); - delete[] raw; - if(statusStart == NULL) { - return(ERR_RESPONSE_MALFORMED); - } - char statusStr[4]; - strncpy(statusStr, statusStart + 1, 3); - statusStr[3] = 0x00; - return(atoi(statusStr)); -} - -int16_t HTTPClient::post(const char* url, const char* content, String& response, const char* contentType) { - // get the host address and endpoint - char* httpPrefix = strstr(url, "http://"); - char* endpoint; - char* host; - if(httpPrefix != NULL) { - // find the host string - char* hostStart = strchr(url, '/'); - hostStart = strchr(hostStart + 1, '/'); - char* hostEnd = strchr(hostStart + 1, '/'); - host = new char[hostEnd - hostStart]; - strncpy(host, hostStart + 1, hostEnd - hostStart - 1); - host[hostEnd - hostStart - 1] = '\0'; - - // find the endpoint string - endpoint = new char[url + strlen(url) - hostEnd + 1]; - strcpy(endpoint, hostEnd); - } else { - // find the host string - char* hostEnd = strchr(url, '/'); - host = new char[hostEnd - url + 1]; - strncpy(host, url, hostEnd - url); - host[hostEnd - url] = '\0'; - - // find the endpoint string - endpoint = new char[url + strlen(url) - hostEnd + 1]; - strcpy(endpoint, hostEnd); - } - - // build the POST request - char contentLengthStr[12]; - sprintf(contentLengthStr, "%u", (uint16_t)strlen(content)); - char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64 + 1]; - strcpy(request, "POST "); - strcat(request, endpoint); - strcat(request, " HTTP/1.1\r\nHost: "); - strcat(request, host); - strcat(request, "\r\nContent-Type: "); - strcat(request, contentType); - strcat(request, "\r\nContent-length: "); - strcat(request, contentLengthStr); - strcat(request, "\r\n\r\n"); - strcat(request, content); - strcat(request, "\r\n\r\n"); - - delete[] endpoint; - - // create TCP connection - int16_t state = _tl->openTransportConnection(host, "TCP", _port); - delete[] host; - if(state != ERR_NONE) { - delete[] request; - return(state); - } - - // send the POST request - state = _tl->send(request); - delete[] request; - if(state != ERR_NONE) { - return(state); - } - - // get the response length - size_t numBytes = _tl->getNumBytes(); - if(numBytes == 0) { - return(ERR_RESPONSE_MALFORMED_AT); - } - - // read the response - char* raw = new char[numBytes]; - size_t rawLength = _tl->receive((uint8_t*)raw, numBytes); - if(rawLength == 0) { - delete[] raw; - return(ERR_RESPONSE_MALFORMED); - } - - // close the tl connection - state = _tl->closeTransportConnection(); - if(state != ERR_NONE) { - delete[] raw; - return(state); - } - - // get the response body - char* responseStart = strstr(raw, "\r\n"); - if(responseStart == NULL) { - delete[] raw; - return(ERR_RESPONSE_MALFORMED); - } - char* responseStr = new char[raw + rawLength - responseStart - 1]; - strncpy(responseStr, responseStart + 2, raw + rawLength - responseStart - 1); - responseStr[raw + rawLength - responseStart - 2] = 0x00; - response = String(responseStr); - delete[] responseStr; - - // return the HTTP status code - char* statusStart = strchr(raw, ' '); - delete[] raw; - if(statusStart == NULL) { - return(ERR_RESPONSE_MALFORMED); - } - char statusStr[4]; - strncpy(statusStr, statusStart + 1, 3); - statusStr[3] = 0x00; - return(atoi(statusStr)); -} - -#endif diff --git a/src/protocols/HTTP/HTTP.h b/src/protocols/HTTP/HTTP.h deleted file mode 100644 index 0f30a43e6b..0000000000 --- a/src/protocols/HTTP/HTTP.h +++ /dev/null @@ -1,73 +0,0 @@ -#if !defined(_RADIOLIB_HTTP_H) -#define _RADIOLIB_HTTP_H - -#include "../../TypeDef.h" - -#if !defined(RADIOLIB_EXCLUDE_HTTP) - -#include "../TransportLayer/TransportLayer.h" - -/*! - \class HTTPClient - - \brief Client for simple HTTP communication. -*/ -class HTTPClient { - public: - /*! - \brief Default constructor. - - \param tl Pointer to the wireless module providing TransportLayer communication. - - \param port Port to be used for HTTP. Defaults to 80. - */ - explicit HTTPClient(TransportLayer* tl, uint16_t port = 80); - - /*! - \brief Sends HTTP GET request. - - \param url URL to send the request to. - - \param response Arduino String object that will save the response. - - \returns \ref status_codes - */ - int16_t get(String& url, String& response); - - /*! - \brief Sends HTTP GET request. - - \param url URL to send the request to. - - \param response Arduino String object that will save the response. - - \returns \ref status_codes - */ - int16_t get(const char* url, String& response); - - /*! - \brief Sends HTTP POST request. - - \param url URL to send the request to. - - \param content Request content. - - \param response Arduino String object that will save the response. - - \param contentType MIME type of request content. Defaults to "text/plain". - - \returns \ref status_codes - */ - int16_t post(const char* url, const char* content, String& response, const char* contentType = "text/plain"); - -#ifndef RADIOLIB_GODMODE - private: -#endif - TransportLayer* _tl; - - uint16_t _port; -}; - -#endif - -#endif diff --git a/src/protocols/MQTT/MQTT.cpp b/src/protocols/MQTT/MQTT.cpp deleted file mode 100644 index b86b548f34..0000000000 --- a/src/protocols/MQTT/MQTT.cpp +++ /dev/null @@ -1,472 +0,0 @@ -#include "MQTT.h" -#if !defined(RADIOLIB_EXCLUDE_MQTT) - -MQTTClient::MQTTClient(TransportLayer* tl, uint16_t port) { - _tl = tl; - _port = port; - _packetId = 1; -} - -int16_t MQTTClient::connect(const char* host, const char* clientId, const char* userName, const char* password, uint16_t keepAlive, bool cleanSession, const char* willTopic, const char* willMessage) { - // encode packet length - size_t clientIdLen = strlen(clientId); - size_t userNameLen = strlen(userName); - size_t passwordLen = strlen(password); - size_t willTopicLen = strlen(willTopic); - size_t willMessageLen = strlen(willMessage); - uint32_t remainingLength = 10 + (2 + clientIdLen); - if(userNameLen > 0) { - remainingLength += (2 + userNameLen); - } - if(passwordLen > 0) { - remainingLength += (2 + passwordLen); - } - if((willTopicLen > 0) && (willMessageLen > 0)) { - remainingLength += (2 + willTopicLen) + (2 + willMessageLen); - } - uint8_t encoded[] = {0, 0, 0, 0}; - size_t encodedBytes = encodeLength(remainingLength, encoded); - - // build the CONNECT packet - #ifdef RADIOLIB_STATIC_ONLY - uint8_t packet[256]; - #else - uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength]; - #endif - - // fixed header - packet[0] = (MQTT_CONNECT << 4) | 0b0000; - memcpy(packet + 1, encoded, encodedBytes); - - // variable header - // protocol name - size_t pos = encodedBytes + 1; - packet[pos++] = 0x00; - packet[pos++] = 0x04; - memcpy(packet + pos, "MQTT", 4); - pos += 4; - - // protocol level - packet[pos++] = 0x04; - - // flags - packet[pos++] = 0x00; - if(cleanSession) { - packet[encodedBytes + 8] |= MQTT_CONNECT_CLEAN_SESSION; - } - - // keep alive interval in seconds - packet[pos++] = (keepAlive & 0xFF00) >> 8; - packet[pos++] = keepAlive & 0x00FF; - - // payload - // clientId - packet[pos++] = (clientIdLen & 0xFF00) >> 8; - packet[pos++] = clientIdLen & 0x00FF; - memcpy(packet + pos, clientId, clientIdLen); - pos += clientIdLen; - - // will topic and message - if((willTopicLen > 0) && (willMessageLen > 0)) { - packet[encodedBytes + 8] |= MQTT_CONNECT_WILL_FLAG; - - packet[pos++] = (willTopicLen & 0xFF00) >> 8; - packet[pos++] = willTopicLen & 0x00FF; - memcpy(packet + pos, willTopic, willTopicLen); - pos += willTopicLen; - - packet[pos++] = (willMessageLen & 0xFF00) >> 8; - packet[pos++] = willMessageLen & 0x00FF; - memcpy(packet + pos, willMessage, willMessageLen); - pos += willMessageLen; - } - - // user name - if(userNameLen > 0) { - packet[encodedBytes + 8] |= MQTT_CONNECT_USER_NAME_FLAG; - packet[pos++] = (userNameLen & 0xFF00) >> 8; - packet[pos++] = userNameLen & 0x00FF; - memcpy(packet + pos, userName, userNameLen); - pos += userNameLen; - } - - // password - if(passwordLen > 0) { - packet[encodedBytes + 8] |= MQTT_CONNECT_PASSWORD_FLAG; - packet[pos++] = (passwordLen & 0xFF00) >> 8;; - packet[pos++] = passwordLen & 0x00FF; - memcpy(packet + pos, password, passwordLen); - } - - // create TCP connection - int16_t state = _tl->openTransportConnection(host, "TCP", _port, keepAlive); - if(state != ERR_NONE) { - #ifndef RADIOLIB_STATIC_ONLY - delete[] packet; - #endif - return(state); - } - - // send MQTT packet - state = _tl->send(packet, 1 + encodedBytes + remainingLength); - #ifndef RADIOLIB_STATIC_ONLY - delete[] packet; - #endif - if(state != ERR_NONE) { - return(state); - } - - // get the response length (MQTT CONNACK response has to be 4 bytes long) - size_t numBytes = _tl->getNumBytes(); - if(numBytes != 4) { - return(ERR_RESPONSE_MALFORMED_AT); - } - - // read the response - #ifdef RADIOLIB_STATIC_ONLY - uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* response = new uint8_t[numBytes]; - #endif - _tl->receive(response, numBytes); - if((response[0] == MQTT_CONNACK << 4) && (response[1] == 2)) { - uint8_t returnCode = response[3]; - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - return(returnCode); - } - - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - return(ERR_RESPONSE_MALFORMED); -} - -int16_t MQTTClient::disconnect() { - // build the DISCONNECT packet - uint8_t packet[2]; - - // fixed header - packet[0] = (MQTT_DISCONNECT << 4) | 0b0000; - packet[1] = 0x00; - - // send MQTT packet - int16_t state = _tl->send(packet, 2); - if(state != ERR_NONE) { - return(state); - } - - // close tl connection - return(_tl->closeTransportConnection()); -} - -int16_t MQTTClient::publish(String& topic, String& message) { - return(MQTTClient::publish(topic.c_str(), message.c_str())); -} - -int16_t MQTTClient::publish(const char* topic, const char* message) { - // encode packet length - size_t topicLen = strlen(topic); - size_t messageLen = strlen(message); - uint32_t remainingLength = (2 + topicLen) + messageLen; - uint8_t encoded[] = {0, 0, 0, 0}; - size_t encodedBytes = encodeLength(remainingLength, encoded); - - // build the PUBLISH packet - #ifdef RADIOLIB_STATIC_ONLY - uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength]; - #endif - - // fixed header - packet[0] = (MQTT_PUBLISH << 4) | 0b0000; - memcpy(packet + 1, encoded, encodedBytes); - - // variable header - // topic name - size_t pos = encodedBytes + 1; - packet[pos++] = (topicLen & 0xFF00) >> 8; - packet[pos++] = topicLen & 0x00FF; - memcpy(packet + pos, topic, topicLen); - pos += topicLen; - - // packet ID - - // payload - // message - memcpy(packet + pos, message, messageLen); - - // send MQTT packet - int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength); - #ifndef RADIOLIB_STATIC_ONLY - delete[] packet; - #endif - return(state); - - /// \todo implement QoS > 0 and PUBACK response checking -} - -int16_t MQTTClient::subscribe(const char* topicFilter) { - // encode packet length - size_t topicFilterLen = strlen(topicFilter); - uint32_t remainingLength = 2 + (2 + topicFilterLen + 1); - uint8_t encoded[] = {0, 0, 0, 0}; - size_t encodedBytes = encodeLength(remainingLength, encoded); - - // build the SUBSCRIBE packet - #ifdef RADIOLIB_STATIC_ONLY - uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength]; - #endif - - // fixed header - packet[0] = (MQTT_SUBSCRIBE << 4) | 0b0010; - memcpy(packet + 1, encoded, encodedBytes); - - // variable header - // packet ID - size_t pos = encodedBytes + 1; - uint16_t packetId = _packetId++; - packet[pos++] = (packetId & 0xFF00) >> 8; - packet[pos++] = packetId & 0x00FF; - - // payload - // topic filter - packet[pos++] = (topicFilterLen & 0xFF00) >> 8;; - packet[pos++] = topicFilterLen & 0x00FF; - memcpy(packet + pos, topicFilter, topicFilterLen); - pos += topicFilterLen; - packet[pos++] = 0x00; // QoS 0 - - // send MQTT packet - int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength); - #ifndef RADIOLIB_STATIC_ONLY - delete[] packet; - #endif - if(state != ERR_NONE) { - return(state); - } - - // get the response length (MQTT SUBACK response has to be 5 bytes long for single subscription) - size_t numBytes = _tl->getNumBytes(); - if(numBytes != 5) { - return(ERR_RESPONSE_MALFORMED_AT); - } - - // read the response - #ifdef RADIOLIB_STATIC_ONLY - uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* response = new uint8_t[numBytes]; - #endif - _tl->receive(response, numBytes); - if((response[0] == MQTT_SUBACK << 4) && (response[1] == 3)) { - // check packet ID - uint16_t receivedId = response[3] | response[2] << 8; - int16_t returnCode = response[4]; - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - if(receivedId != packetId) { - return(ERR_MQTT_UNEXPECTED_PACKET_ID); - } - return(returnCode); - } - - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - return(ERR_RESPONSE_MALFORMED); -} - -int16_t MQTTClient::unsubscribe(const char* topicFilter) { - // encode packet length - size_t topicFilterLen = strlen(topicFilter); - uint32_t remainingLength = 2 + (2 + topicFilterLen); - uint8_t encoded[] = {0, 0, 0, 0}; - size_t encodedBytes = encodeLength(remainingLength, encoded); - - // build the UNSUBSCRIBE packet - #ifdef RADIOLIB_STATIC_ONLY - uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength]; - #endif - - // fixed header - packet[0] = (MQTT_UNSUBSCRIBE << 4) | 0b0010; - memcpy(packet + 1, encoded, encodedBytes); - - // variable header - // packet ID - size_t pos = encodedBytes + 1; - uint16_t packetId = _packetId++; - packet[pos++] = (packetId & 0xFF00) >> 8; - packet[pos++] = packetId & 0x00FF; - - // payload - // topic filter - packet[pos++] = (topicFilterLen & 0xFF00) >> 8;; - packet[pos++] = topicFilterLen & 0x00FF; - memcpy(packet + pos, topicFilter, topicFilterLen); - - // send MQTT packet - int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength); - #ifndef RADIOLIB_STATIC_ONLY - delete[] packet; - #endif - if(state != ERR_NONE) { - return(state); - } - - // get the response length (MQTT UNSUBACK response has to be 4 bytes long) - size_t numBytes = _tl->getNumBytes(); - if(numBytes != 4) { - return(ERR_RESPONSE_MALFORMED_AT); - } - - // read the response - #ifdef RADIOLIB_STATIC_ONLY - uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* response = new uint8_t[numBytes]; - #endif - _tl->receive(response, numBytes); - if((response[0] == MQTT_UNSUBACK << 4) && (response[1] == 2)) { - // check packet ID - uint16_t receivedId = response[3] | response[2] << 8; - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - if(receivedId != packetId) { - return(ERR_MQTT_UNEXPECTED_PACKET_ID); - } - return(ERR_NONE); - } - - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - return(ERR_RESPONSE_MALFORMED); -} - -int16_t MQTTClient::ping() { - // build the PINGREQ packet - uint8_t packet[2]; - - // fixed header - packet[0] = (MQTT_PINGREQ << 4) | 0b0000; - packet[1] = 0x00; - - // send MQTT packet - int16_t state = _tl->send(packet, 2); - if(state != ERR_NONE) { - return(state); - } - - // get the response length (MQTT PINGRESP response has to be 2 bytes long) - size_t numBytes = _tl->getNumBytes(); - if(numBytes != 2) { - return(ERR_RESPONSE_MALFORMED_AT); - } - - // read the response - #ifdef RADIOLIB_STATIC_ONLY - uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* response = new uint8_t[numBytes]; - #endif - _tl->receive(response, numBytes); - if((response[0] == MQTT_PINGRESP << 4) && (response[1] == 0)) { - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - return(ERR_NONE); - } - - #ifndef RADIOLIB_STATIC_ONLY - delete[] response; - #endif - return(ERR_RESPONSE_MALFORMED); -} - -int16_t MQTTClient::check(void (*func)(const char*, const char*)) { - // ping the server - int16_t state = ping(); - if(state != ERR_NONE) { - return(state); - } - - // check new data - size_t numBytes = _tl->getNumBytes(); - if(numBytes == 0) { - return(ERR_MQTT_NO_NEW_PACKET_AVAILABLE); - } - - // read the PUBLISH packet from server - uint8_t* dataIn = new uint8_t[numBytes]; - _tl->receive(dataIn, numBytes); - if(dataIn[0] == MQTT_PUBLISH << 4) { - uint8_t remLenFieldLen = 0; - uint32_t remainingLength = decodeLength(dataIn + 1, remLenFieldLen); - - // get the topic - size_t topicLength = dataIn[remLenFieldLen + 2] | dataIn[remLenFieldLen + 1] << 8; - char* topic = new char[topicLength + 1]; - memcpy(topic, dataIn + 4, topicLength); - topic[topicLength] = 0x00; - - // get the message - size_t messageLength = remainingLength - topicLength - 2; - char* message = new char[messageLength + 1]; - memcpy(message, dataIn + remLenFieldLen + 3 + topicLength, messageLength); - message[messageLength] = 0x00; - - // execute the callback function provided by user - func(topic, message); - - delete[] topic; - delete[] message; - delete[] dataIn; - return(ERR_NONE); - } - delete[] dataIn; - - return(ERR_MQTT_NO_NEW_PACKET_AVAILABLE); -} - -size_t MQTTClient::encodeLength(uint32_t len, uint8_t* encoded) { - // algorithm to encode packet length as per MQTT specification 3.1.1 - size_t i = 0; - do { - encoded[i] = len % 128; - len /= 128; - if(len > 0) { - encoded[i] |= 128; - } - i++; - } while(len > 0); - return(i); -} - -uint32_t MQTTClient::decodeLength(uint8_t* encoded, uint8_t& numBytes) { - // algorithm to decode packet length as per MQTT specification 3.1.1 - uint32_t mult = 1; - uint32_t len = 0; - uint8_t i = 0; - do { - len += (encoded[i] & 127) * mult; - mult *= 128; - if(mult > 2097152) { - // malformed remaining length - return(0); - } - } while((encoded[i++] & 128) != 0); - numBytes = i; - return len; -} - -#endif diff --git a/src/protocols/MQTT/MQTT.h b/src/protocols/MQTT/MQTT.h deleted file mode 100644 index 6f21f585ee..0000000000 --- a/src/protocols/MQTT/MQTT.h +++ /dev/null @@ -1,147 +0,0 @@ -#if !defined(_RADIOLIB_MQTT_H) -#define _RADIOLIB_MQTT_H - -#include "../../TypeDef.h" - -#if !defined(RADIOLIB_EXCLUDE_MQTT) - -#include "../TransportLayer/TransportLayer.h" - -// MQTT packet types -#define MQTT_CONNECT 0x01 -#define MQTT_CONNACK 0x02 -#define MQTT_PUBLISH 0x03 -#define MQTT_PUBACK 0x04 -#define MQTT_PUBREC 0x05 -#define MQTT_PUBREL 0x06 -#define MQTT_PUBCOMP 0x07 -#define MQTT_SUBSCRIBE 0x08 -#define MQTT_SUBACK 0x09 -#define MQTT_UNSUBSCRIBE 0x0A -#define MQTT_UNSUBACK 0x0B -#define MQTT_PINGREQ 0x0C -#define MQTT_PINGRESP 0x0D -#define MQTT_DISCONNECT 0x0E - -// MQTT CONNECT flags -#define MQTT_CONNECT_USER_NAME_FLAG 0b10000000 -#define MQTT_CONNECT_PASSWORD_FLAG 0b01000000 -#define MQTT_CONNECT_WILL_RETAIN 0b00100000 -#define MQTT_CONNECT_WILL_FLAG 0b00000100 -#define MQTT_CONNECT_CLEAN_SESSION 0b00000010 - -/*! - \class MQTTClient - - \brief Client for simple MQTT communication. -*/ -class MQTTClient { - public: - /*! - \brief Default constructor. - - \param tl Pointer to the wireless module providing TransportLayer communication. - */ - explicit MQTTClient(TransportLayer* tl, uint16_t port = 1883); - - // basic methods - - /*! - \brief Connects to MQTT broker (/server). - - \param host URL of the MQTT broker. - - \param clientId ID of the client. - - \param username Username to be used in the connection. Defaults to empty string (no username). - - \param password Password to be used in the connection. Defaults to empty string (no password). - - \param keepAlive Connection keep-alive period in seconds. Defaults to 60. - - \param cleanSession MQTT CleanSession flag. Defaults to true. - - \param willTopic MQTT will topic. Defaults to empty string (no will topic). - - \param willMessage MQTT will message. Defaults to empty string (no will message). - - \returns \ref status_codes - */ - int16_t connect(const char* host, const char* clientId, const char* userName = "", const char* password = "", uint16_t keepAlive = 60, bool cleanSession = true, const char* willTopic = "", const char* willMessage = ""); - - /*! - \brief Disconnect from MQTT broker. - - \returns \ref status_codes - */ - int16_t disconnect(); - - /*! - \brief Publish MQTT message. - - \param topic MQTT topic to which the message will be published. - - \param message Message to be published. - - \returns \ref status_codes - */ - int16_t publish(String& topic, String& message); - - /*! - \brief Publish MQTT message. - - \param topic MQTT topic to which the message will be published. - - \param message Message to be published. - - \returns \ref status_codes - */ - int16_t publish(const char* topic, const char* message); - - /*! - \brief Subscribe to MQTT topic. - - \param topicFilter Topic to subscribe to. - - \returns \ref status_codes - */ - int16_t subscribe(const char* topicFilter); - - /*! - \brief Unsubscribe from MQTT topic. - - \param topicFilter Topic to unsubscribe from. - - \returns \ref status_codes - */ - int16_t unsubscribe(const char* topicFilter); - - /*! - \brief Ping MQTT broker. This method can be used to keep connection open. - - \returns \ref status_codes - */ - int16_t ping(); - - /*! - \brief Set function to be called when checking new messages in subscribed topics. - - \returns \ref status_codes - */ - int16_t check(void (*func)(const char*, const char*)); - -#ifndef RADIOLIB_GODMODE - private: -#endif - TransportLayer* _tl; - - uint16_t _port; - uint16_t _packetId; - - static size_t encodeLength(uint32_t len, uint8_t* encoded); - static uint32_t decodeLength(uint8_t* encoded, uint8_t& numBytes); -}; - -#endif - -#endif diff --git a/src/protocols/TransportLayer/TransportLayer.h b/src/protocols/TransportLayer/TransportLayer.h deleted file mode 100644 index eb23bd8e6b..0000000000 --- a/src/protocols/TransportLayer/TransportLayer.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef _RADIOLIB_TRANSPORT_LAYER_H -#define _RADIOLIB_TRANSPORT_LAYER_H - -#include "../../TypeDef.h" - -/*! - \class TransportLayer - - \brief Provides common interface for protocols that run on modules with Internet connectivity, such as HTTP or MQTT. - Because this class is used mainly as interface, all of its virtual members must be implemented in the module class. -*/ -class TransportLayer { - public: - // constructor - // this class is purely virtual and does not require explicit constructor - - // basic methods - - /*! - \brief Open transport layer connection. - - \param host Host to connect to. - - \param protocol Transport protocol to use. Usually "TCP" or "UDP". - - \param port to be used for the connection. - - \param tcpKeepAlive TCP keep alive interval. Defaults to 0. - - \returns \ref status_codes - */ - virtual int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0) = 0; - - /*! - \brief Close transport layer connection. - - \returns \ref status_codes - */ - virtual int16_t closeTransportConnection() = 0; - - /*! - \brief Send string-based data. - - \param string String data to be sent. - - \returns \ref status_codes - */ - virtual int16_t send(const char* data) = 0; - - /*! - \brief Send arbitrary binary data. - - \param data Data to be sent. - - \param len Number of bytes to send. - - \returns \ref status_codes - */ - virtual int16_t send(uint8_t* data, size_t len) = 0; - - /*! - \brief Receive data. - - \param data Pointer to array to save the received data. - - \param len Number of bytes to read. - - \param timeout Reception timeout in ms. Defaults to 10000. - - \returns \ref status_codes - */ - virtual size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000) = 0; - - /*! - \brief Get number of received bytes. - - \param timeout Reception timeout in ms. Defaults to 10000. - - \param minBytes Minimum required number of bytes that must be received. - - \returns Number of received bytes, or 0 on timeout. - */ - virtual size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10) = 0; -}; - -#endif From 8111bc058fe5818082c347370a7af00bf1ff286f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:33:35 +0100 Subject: [PATCH 0033/1848] Added HAL --- src/BuildOpt.h | 636 +++++++++++++++++++++++++++++++++++++++---------- src/Module.cpp | 383 +++++++++++++++-------------- src/Module.h | 290 ++++++++-------------- 3 files changed, 809 insertions(+), 500 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index c5a015f86e..0d8b628cb5 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -2,11 +2,16 @@ #define _RADIOLIB_BUILD_OPTIONS_H #if ARDUINO >= 100 + // Arduino build #include "Arduino.h" + #define RADIOLIB_BUILD_ARDUINO #else - #error "Unsupported Arduino version (< 1.0.0)" + // generic build + #define RADIOLIB_BUILD_GENERIC #endif +#if defined(RADIOLIB_BUILD_ARDUINO) + /* * Platform-specific configuration. * @@ -18,24 +23,22 @@ * RADIOLIB_DIGITAL_PIN_TO_INTERRUPT - function/macro to be used to convert digital pin number to interrupt pin number. * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. - * RADIOLIB_PROGMEM - macro to place variable into program storage (usually Flash). - * RADIOLIB_PROGMEM_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). + * RADIOLIB_NONVOLATILE - macro to place variable into program storage (usually Flash). + * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword. - * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial. - * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support. * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. * * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). * - * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_PLATFORM, + * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_ARDUINO, * and then specifying all platform parameters in the section below. This will override automatic * platform detection. */ // uncomment to enable custom platform definition -//#define RADIOLIB_CUSTOM_PLATFORM +//#define RADIOLIB_CUSTOM_ARDUINO -#if defined(RADIOLIB_CUSTOM_PLATFORM) +#if defined(RADIOLIB_CUSTOM_ARDUINO) // name for your platform #define RADIOLIB_PLATFORM "Custom" @@ -47,14 +50,11 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - // the following must be defined if the Arduino core does not support SoftwareSerial library - //#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - //#define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - // the following must be defined if the Arduino core does not support tone function //#define RADIOLIB_TONE_UNSUPPORTED @@ -69,9 +69,6 @@ // while keeping SX1231 (because RF69 is the base class for SX1231). The dependency is always uni-directional, // so excluding SX1231 and keeping RF69 is valid. //#define RADIOLIB_EXCLUDE_CC1101 - //#define RADIOLIB_EXCLUDE_ESP8266 - //#define RADIOLIB_EXCLUDE_HC05 - //#define RADIOLIB_EXCLUDE_JDY08 //#define RADIOLIB_EXCLUDE_NRF24 //#define RADIOLIB_EXCLUDE_RF69 //#define RADIOLIB_EXCLUDE_SX1231 // dependent on RADIOLIB_EXCLUDE_RF69 @@ -81,13 +78,10 @@ //#define RADIOLIB_EXCLUDE_RFM9X // dependent on RADIOLIB_EXCLUDE_SX127X //#define RADIOLIB_EXCLUDE_SX126X //#define RADIOLIB_EXCLUDE_SX128X - //#define RADIOLIB_EXCLUDE_XBEE //#define RADIOLIB_EXCLUDE_AFSK //#define RADIOLIB_EXCLUDE_AX25 //#define RADIOLIB_EXCLUDE_HELLSCHREIBER - //#define RADIOLIB_EXCLUDE_HTTP //#define RADIOLIB_EXCLUDE_MORSE - //#define RADIOLIB_EXCLUDE_MQTT //#define RADIOLIB_EXCLUDE_RTTY //#define RADIOLIB_EXCLUDE_SSTV @@ -102,10 +96,30 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ESP8266) // ESP8266 boards #define RADIOLIB_PLATFORM "ESP8266" @@ -116,13 +130,29 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - // RadioLib has ESP8266 driver, this must be disabled to use ESP8266 as platform - #define RADIOLIB_EXCLUDE_ESP8266 - #define RADIOLIB_EXCLUDE_HTTP + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) #elif defined(ESP32) // ESP32 boards @@ -134,16 +164,34 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_TONE_ESP32_CHANNEL (1) + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, void) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, void) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARCH_STM32) // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32) #define RADIOLIB_PLATFORM "Arduino STM32 (official)" @@ -151,18 +199,36 @@ #define RADIOLIB_PIN_MODE uint32_t #define RADIOLIB_PIN_STATUS uint32_t #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt((PinName)p) #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 // slow down SX126x/8x SPI on this platform #define RADIOLIB_SPI_SLOWDOWN + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin, bool destruct) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) + #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(SAMD_SERIES) // Adafruit SAMD boards (M0 and M4) #define RADIOLIB_PLATFORM "Adafruit SAMD" @@ -173,15 +239,33 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 // slow down SX126x/8x SPI on this platform #define RADIOLIB_SPI_SLOWDOWN + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint32_t _pin, uint32_t frequency, uint32_t duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint32_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, voidFuncPtr callback, uint32_t mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long dwMs) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARCH_SAMD) // Arduino SAMD (Zero, MKR, etc.) #define RADIOLIB_PLATFORM "Arduino SAMD" @@ -192,11 +276,29 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pinNumber, PinMode pinMode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pinNumber, PinStatus status) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, pin_size_t pinNumber) + #define RADIOLIB_CB_ARGS_TONE (void, tone, unsigned char outputPin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t outputPin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t pin, voidFuncPtr callback, PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) #elif defined(__SAM3X8E__) // Arduino Due @@ -208,13 +310,31 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 #define RADIOLIB_TONE_UNSUPPORTED + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, void) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, void) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t dwMs) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) + #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) // Adafruit nRF52 boards #define RADIOLIB_PLATFORM "Adafruit nRF52" @@ -225,10 +345,30 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (int, attachInterrupt, uint32_t pin, voidFuncPtr callback, uint32_t mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t dwMs) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) + #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARC32_TOOLS) // Intel Curie #define RADIOLIB_PLATFORM "Intel Curie" @@ -239,10 +379,30 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint32_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint32_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t dwMs) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t dwUs) + #define RADIOLIB_CB_ARGS_MILLIS (uint64_t, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (uint64_t, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every #define RADIOLIB_PLATFORM "Arduino megaAVR" @@ -253,10 +413,30 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, PinMode mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, PinStatus val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*userFunc)(void), PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARCH_APOLLO3) // Sparkfun Apollo3 boards #define RADIOLIB_PLATFORM "Sparkfun Apollo3" @@ -267,18 +447,33 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - - // Apollo3 uses mbed libraries, which already contain ESP8266 driver - #define RADIOLIB_EXCLUDE_ESP8266 // slow down SX126x/8x SPI on this platform #define RADIOLIB_SPI_SLOWDOWN + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pinName, Arduino_PinMode pinMode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pinName, PinStatus val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pinName) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNumber) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARDUINO_NANO33BLE) // Arduino Nano 33 BLE #define RADIOLIB_PLATFORM "Arduino Nano 33 BLE" @@ -289,14 +484,29 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver - #define RADIOLIB_EXCLUDE_ESP8266 + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) // Arduino Portenta H7 @@ -308,14 +518,29 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - // Arduino Portenta H7 uses mbed libraries, which already contain ESP8266 driver - #define RADIOLIB_EXCLUDE_ESP8266 + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) #elif defined(__STM32F4__) || defined(__STM32F1__) // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) @@ -327,11 +552,29 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8 pin, WiringPinMode mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8 pin, uint8 val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint32_t, digitalRead, uint8 pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint32_t _pin, uint32_t frequency, uint32_t duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint32_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8 pin) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32 us) + #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) #elif defined(ARDUINO_ARCH_MEGAAVR) // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX) @@ -343,10 +586,30 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint8_t, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*userFunc)(void), uint8_t mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico #define RADIOLIB_PLATFORM "Raspberry Pi Pico" @@ -357,12 +620,29 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - #define RADIOLIB_EXCLUDE_ESP8266 + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) #elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) // CubeCell @@ -374,10 +654,28 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, PINMODE mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin_name, uint8_t level) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint8_t, digitalRead, uint8_t pin_name) + #define RADIOLIB_CB_ARGS_TONE (void, tone, void) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, void) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin_name, GpioIrqHandler GpioIrqHandlerCallback, IrqModes interrupt_mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t pin_name) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t milliseconds) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint16 microseconds) + #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) // CubeCell doesn't seem to define nullptr, let's do something like that now #define nullptr NULL @@ -398,8 +696,8 @@ #endif #else - // other platforms not covered by the above list - this may or may not work - #define RADIOLIB_PLATFORM "Unknown" + // other Arduino platforms not covered by the above list - this may or may not work + #define RADIOLIB_PLATFORM "Unknown Arduino" #define RADIOLIB_UNKNOWN_PLATFORM #define RADIOLIB_PIN_TYPE uint8_t #define RADIOLIB_PIN_MODE uint8_t @@ -408,13 +706,49 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_PROGMEM PROGMEM - #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #endif #endif +#else + // generic non-Arduino platform + #define RADIOLIB_PLATFORM "Generic" + #define RADIOLIB_PIN_TYPE int + #define RADIOLIB_PIN_MODE int + #define RADIOLIB_PIN_STATUS int + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) (p) + #define RADIOLIB_NC (-1) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + +#endif + /* * Uncomment to enable debug output. * Warning: Debug output will slow down the whole system significantly. @@ -422,27 +756,17 @@ * Levels: debug - only main info * verbose - full transcript of all SPI/UART communication */ - -//#define RADIOLIB_DEBUG -//#define RADIOLIB_VERBOSE - -// set which Serial port should be used for debug output -#define RADIOLIB_DEBUG_PORT Serial - -#if defined(RADIOLIB_DEBUG) - #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } - #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } -#else - #define RADIOLIB_DEBUG_PRINT(...) {} - #define RADIOLIB_DEBUG_PRINTLN(...) {} +#if !defined(RADIOLIB_DEBUG) + //#define RADIOLIB_DEBUG +#endif +#if !defined(RADIOLIB_VERBOSE) + //#define RADIOLIB_VERBOSE #endif -#if defined(RADIOLIB_VERBOSE) - #define RADIOLIB_VERBOSE_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } - #define RADIOLIB_VERBOSE_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } -#else - #define RADIOLIB_VERBOSE_PRINT(...) {} - #define RADIOLIB_VERBOSE_PRINTLN(...) {} +// set which output port should be used for debug output +// may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) +#if !defined(RADIOLIB_DEBUG_PORT) + #define RADIOLIB_DEBUG_PORT Serial #endif /* @@ -451,7 +775,9 @@ * This improves reliablility, but slightly slows down communication. * Note: Enabled by default. */ -#define RADIOLIB_SPI_PARANOID +#if !defined(RADIOLIB_SPI_PARANOID) + #define RADIOLIB_SPI_PARANOID +#endif /* * Uncomment to enable parameter range checking @@ -460,7 +786,9 @@ * possibly leading to bricked module and/or program crashing. * Note: Enabled by default. */ -#define RADIOLIB_CHECK_PARAMS +#if !defined(RADIOLIB_CHECK_PARAMS) + #define RADIOLIB_CHECK_PARAMS +#endif /* * Uncomment to enable SX127x errata fix @@ -468,12 +796,8 @@ * It should only be enabled if you really are observing some errata-related issue. * Note: Disabled by default. */ -//#define RADIOLIB_FIX_ERRATA_SX127X - -#if defined(RADIOLIB_FIX_ERRATA_SX127X) - #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); } -#else - #define RADIOLIB_ERRATA_SX127X(...) {} +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + //#define RADIOLIB_FIX_ERRATA_SX127X #endif /* @@ -481,43 +805,101 @@ * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. * Failure to heed the above warning may result in bricked module. */ -//#define RADIOLIB_GODMODE +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + //#define RADIOLIB_GODMODE +#endif /* * Uncomment to enable low-level hardware access * This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite" * Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this. */ -//#define RADIOLIB_LOW_LEVEL +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + //#define RADIOLIB_LOW_LEVEL +#endif /* * Uncomment to enable pre-defined modules when using RadioShield. */ -//#define RADIOLIB_RADIOSHIELD +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + //#define RADIOLIB_RADIOSHIELD +#endif /* * Uncomment to enable static-only memory management: no dynamic allocation will be performed. * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. */ -//#define RADIOLIB_STATIC_ONLY +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + //#define RADIOLIB_STATIC_ONLY +#endif // set the size of static arrays to use #if !defined(RADIOLIB_STATIC_ARRAY_SIZE) -#define RADIOLIB_STATIC_ARRAY_SIZE 256 + #define RADIOLIB_STATIC_ARRAY_SIZE (256) +#endif + +#if defined(RADIOLIB_DEBUG) + #if defined(RADIOLIB_BUILD_ARDUINO) + #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } + #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } + #else + #if !defined(RADIOLIB_DEBUG_PRINT) + #define RADIOLIB_DEBUG_PRINT(...) { frintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__); } + #endif + #if !defined(RADIOLIB_DEBUG_PRINTLN) + #define RADIOLIB_DEBUG_PRINTLN(...) { printf(RADIOLIB_DEBUG_PORT, __VA_ARGS__ "\n"); } + #endif + #endif +#else + #define RADIOLIB_DEBUG_PRINT(...) {} + #define RADIOLIB_DEBUG_PRINTLN(...) {} +#endif + +#if defined(RADIOLIB_VERBOSE) + #define RADIOLIB_VERBOSE_PRINT(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) + #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) +#else + #define RADIOLIB_VERBOSE_PRINT(...) {} + #define RADIOLIB_VERBOSE_PRINTLN(...) {} #endif /*! \brief A simple assert macro, will return on error. */ -#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != ERR_NONE) { return(STATEVAR); } } +#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } } + +/* + * Macros that create callback for the hardware abstraction layer. + * + * This is the most evil thing I have ever created. I am deeply sorry to anyone currently reading this text. + * Come one, come all and witness the horror: + * Variadics, forced expansions, inlined function, string concatenation, and it even messes up access specifiers. + */ +#define FIRST(arg, ...) arg +#define REST(arg, ...) __VA_ARGS__ +#define EXP(...) __VA_ARGS__ + +#define RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, FUNC, ...) public: typedef RET (*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC; +#define RADIOLIB_GENERATE_CALLBACK_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, __VA_ARGS__) +#define RADIOLIB_GENERATE_CALLBACK(CB) RADIOLIB_GENERATE_CALLBACK_RET(EXP(FIRST CB), EXP(REST CB)) + +#define RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, FUNC, ...) public: typedef RET (Module::*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC; +#define RADIOLIB_GENERATE_CALLBACK_SPI_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, __VA_ARGS__) +#define RADIOLIB_GENERATE_CALLBACK_SPI(CB) RADIOLIB_GENERATE_CALLBACK_SPI_RET(EXP(FIRST CB), EXP(REST CB)) /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled */ #if defined(RADIOLIB_CHECK_PARAMS) -#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } + #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } #else -#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {} + #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {} +#endif + +#if defined(RADIOLIB_FIX_ERRATA_SX127X) + #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); } +#else + #define RADIOLIB_ERRATA_SX127X(...) {} #endif // version definitions diff --git a/src/Module.cpp b/src/Module.cpp index 98e6af346f..9ff2921394 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,199 +1,122 @@ #include "Module.h" -SerialModule::SerialModule(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rst, HardwareSerial* serial): - Module(RADIOLIB_NC, RADIOLIB_NC, (RADIOLIB_PIN_TYPE)rst, (RADIOLIB_PIN_TYPE)rx, (RADIOLIB_PIN_TYPE)tx, RADIOLIB_DEFAULT_SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), NULL) -{ - _initInterface = true; - -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - ModuleSerial = serial; -#else - ModuleSerial = new SoftwareSerial(rx, tx); - (void)serial; -#endif -} - -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst): - _cs(cs), - _irq(irq), - _rst(rst), - _rx(RADIOLIB_NC), - _tx(RADIOLIB_NC), - _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0)) -{ - _spi = &RADIOLIB_DEFAULT_SPI; - _initInterface = true; - ModuleSerial = NULL; -} - +#if defined(RADIOLIB_BUILD_ARDUINO) Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), _rst(rst), - _rx(gpio), - _tx(RADIOLIB_NC), - _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0)) + _gpio(gpio) { _spi = &RADIOLIB_DEFAULT_SPI; _initInterface = true; - ModuleSerial = NULL; -} -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings): - _cs(cs), - _irq(irq), - _rst(rst), - _rx(RADIOLIB_NC), - _tx(RADIOLIB_NC), - _spiSettings(spiSettings) -{ - _spi = &spi; - _initInterface = false; - ModuleSerial = NULL; + // this is Arduino build, pre-set callbacks + setCb_pinMode(::pinMode); + setCb_digitalRead(::digitalRead); + setCb_digitalWrite(::digitalWrite); + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + setCb_tone(::tone); + setCb_noTone(::noTone); + #endif + setCb_attachInterrupt(::attachInterrupt); + setCb_detachInterrupt(::detachInterrupt); + #if !defined(RADIOLIB_YIELD_UNSUPPORTED) + setCb_yield(::yield); + #endif + setCb_delay(::delay); + setCb_delayMicroseconds(::delayMicroseconds); + setCb_millis(::millis); + setCb_micros(::micros); + setCb_SPIbegin(&Module::SPIbegin); + setCb_SPIbeginTransaction(&Module::beginTransaction); + setCb_SPItransfer(&Module::transfer); + setCb_SPIendTransaction(&Module::endTransaction); + setCb_SPIend(&Module::end); } Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings): _cs(cs), _irq(irq), _rst(rst), - _rx(gpio), - _tx(RADIOLIB_NC), + _gpio(gpio), _spiSettings(spiSettings) { _spi = &spi; _initInterface = false; - ModuleSerial = NULL; + + // this is Arduino build, pre-set callbacks + setCb_pinMode(::pinMode); + setCb_digitalRead(::digitalRead); + setCb_digitalWrite(::digitalWrite); + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + setCb_tone(::tone); + setCb_noTone(::noTone); + #endif + setCb_attachInterrupt(::attachInterrupt); + setCb_detachInterrupt(::detachInterrupt); + #if !defined(RADIOLIB_YIELD_UNSUPPORTED) + setCb_yield(::yield); + #endif + setCb_delay(::delay); + setCb_delayMicroseconds(::delayMicroseconds); + setCb_millis(::millis); + setCb_micros(::micros); + setCb_SPIbegin(&Module::SPIbegin); + setCb_SPIbeginTransaction(&Module::beginTransaction); + setCb_SPItransfer(&Module::transfer); + setCb_SPIendTransaction(&Module::endTransaction); + setCb_SPIend(&Module::end); } +#else -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* serial): +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), _rst(rst), - _rx(rx), - _tx(tx), - _spiSettings(spiSettings) + _gpio(gpio) { - _spi = &spi; - _initInterface = false; + // not an Arduino build, it's up to the user to set all callbacks +} -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - ModuleSerial = serial; -#else - ModuleSerial = new SoftwareSerial(_rx, _tx); - (void)serial; #endif -} Module::Module(const Module& mod) { *this = mod; } Module& Module::operator=(const Module& mod) { - this->ModuleSerial = mod.ModuleSerial; - this->baudrate = mod.baudrate; - memcpy(this->AtLineFeed, mod.AtLineFeed, strlen(mod.AtLineFeed)); this->SPIreadCommand = mod.SPIreadCommand; this->SPIwriteCommand = mod.SPIwriteCommand; this->_cs = mod.getCs(); this->_irq = mod.getIrq(); this->_rst = mod.getRst(); - this->_rx = mod.getRx(); - this->_tx = mod.getTx(); - this->_spiSettings = mod.getSpiSettings(); - this->_spi = mod.getSpi(); + this->_gpio = mod.getGpio(); return(*this); } -void Module::init(uint8_t interface) { - // select interface - switch(interface) { - case RADIOLIB_USE_SPI: - Module::pinMode(_cs, OUTPUT); - Module::digitalWrite(_cs, HIGH); - if(_initInterface) { - _spi->begin(); - } - break; - case RADIOLIB_USE_UART: - if(_initInterface) { -#if defined(ESP32) - ModuleSerial->begin(baudrate, SERIAL_8N1, _rx, _tx); -#else - ModuleSerial->begin(baudrate); -#endif - } - break; +void Module::init() { + this->pinMode(_cs, OUTPUT); + this->digitalWrite(_cs, HIGH); + if(_initInterface) { + (this->*cb_SPIbegin)(); } } -void Module::term(uint8_t interface) { +void Module::term() { // stop hardware interfaces (if they were initialized by the library) if(!_initInterface) { return; } - if((interface == RADIOLIB_USE_SPI) && (_spi != nullptr)) { - _spi->end(); - } - - #if !defined(__ASR6501__) - if(((interface == RADIOLIB_USE_UART) && ModuleSerial != nullptr)) { - ModuleSerial->end(); - } - #endif -} - -void Module::ATemptyBuffer() { - while(ModuleSerial->available() > 0) { - ModuleSerial->read(); - } -} - -bool Module::ATsendCommand(const char* cmd) { - ATemptyBuffer(); - ModuleSerial->print(cmd); - ModuleSerial->print(AtLineFeed); - return(ATgetResponse()); -} - -bool Module::ATsendData(uint8_t* data, uint32_t len) { - ATemptyBuffer(); - for(uint32_t i = 0; i < len; i++) { - ModuleSerial->write(data[i]); - } - - ModuleSerial->print(AtLineFeed); - return(ATgetResponse()); -} - -bool Module::ATgetResponse() { - char data[128]; - char* dataPtr = data; - uint32_t start = Module::millis(); - while(Module::millis() - start < _ATtimeout) { - while(ModuleSerial->available() > 0) { - char c = ModuleSerial->read(); - RADIOLIB_VERBOSE_PRINT(c); - *dataPtr++ = c; - } - - if(strstr(data, "OK") == 0) { - RADIOLIB_VERBOSE_PRINTLN(); - return(true); - } else if(strstr(data, "ERROR") == 0) { - RADIOLIB_VERBOSE_PRINTLN(); - return(false); - } - + if(_spi != nullptr) { + this->SPIend(); } - RADIOLIB_VERBOSE_PRINTLN(); - return(false); } int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { - return(ERR_INVALID_BIT_RANGE); + return(RADIOLIB_ERR_INVALID_BIT_RANGE); } uint8_t rawValue = SPIreadRegister(reg); @@ -203,7 +126,7 @@ int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { - return(ERR_INVALID_BIT_RANGE); + return(RADIOLIB_ERR_INVALID_BIT_RANGE); } uint8_t currentValue = SPIreadRegister(reg); @@ -214,13 +137,13 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t #if defined(RADIOLIB_SPI_PARANOID) // check register value each millisecond until check interval is reached // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) - uint32_t start = Module::micros(); + uint32_t start = this->micros(); uint8_t readValue = 0x00; - while(Module::micros() - start < (checkInterval * 1000)) { + while(this->micros() - start < (checkInterval * 1000)) { readValue = SPIreadRegister(reg); if((readValue & checkMask) == (newValue & checkMask)) { // check passed, we can stop the loop - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } } @@ -244,9 +167,9 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t RADIOLIB_DEBUG_PRINTLN(readValue, BIN); RADIOLIB_DEBUG_PRINTLN(); - return(ERR_SPI_WRITE_FAILED); + return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); #endif } @@ -270,14 +193,14 @@ void Module::SPIwriteRegister(uint8_t reg, uint8_t data) { void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // start SPI transaction - _spi->beginTransaction(_spiSettings); + this->SPIbeginTransaction(); // pull CS low - Module::digitalWrite(_cs, LOW); + this->digitalWrite(_cs, LOW); // send SPI register address with access command - _spi->transfer(reg | cmd); - #ifdef RADIOLIB_VERBOSE + this->SPItransfer(reg | cmd); + #if defined(RADIOLIB_VERBOSE) if(cmd == SPIwriteCommand) { RADIOLIB_VERBOSE_PRINT('W'); } else if(cmd == SPIreadCommand) { @@ -292,7 +215,7 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da if(cmd == SPIwriteCommand) { if(dataOut != NULL) { for(size_t n = 0; n < numBytes; n++) { - _spi->transfer(dataOut[n]); + this->SPItransfer(dataOut[n]); RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); } @@ -300,7 +223,7 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da } else if (cmd == SPIreadCommand) { if(dataIn != NULL) { for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = _spi->transfer(0x00); + dataIn[n] = this->SPItransfer(0x00); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); } @@ -309,92 +232,184 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da RADIOLIB_VERBOSE_PRINTLN(); // release CS - Module::digitalWrite(_cs, HIGH); + this->digitalWrite(_cs, HIGH); // end SPI transaction - _spi->endTransaction(); + this->SPIendTransaction(); } void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) { - if(pin != RADIOLIB_NC) { - ::pinMode(pin, mode); + if((pin == RADIOLIB_NC) || (cb_pinMode == nullptr)) { + return; } + cb_pinMode(pin, mode); } void Module::digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value) { - if(pin != RADIOLIB_NC) { - ::digitalWrite(pin, value); + if((pin == RADIOLIB_NC) || (cb_digitalWrite == nullptr)) { + return; } + cb_digitalWrite(pin, value); } RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) { - if(pin != RADIOLIB_NC) { - return(::digitalRead(pin)); + if((pin == RADIOLIB_NC) || (cb_digitalRead == nullptr)) { + return((RADIOLIB_PIN_STATUS)0); } - return(LOW); + return(cb_digitalRead(pin)); } -void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value) { - if(pin == RADIOLIB_NC) { +void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) { + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + if((pin == RADIOLIB_NC) || (cb_tone == nullptr)) { return; } - - #if !defined(RADIOLIB_TONE_UNSUPPORTED) - ::tone(pin, value); + cb_tone(pin, value, duration); #else + if(pin == RADIOLIB_NC) { + return; + } #if defined(ESP32) // ESP32 tone() emulation ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); + #else + (void)value; + (void)duration; #endif #endif } void Module::noTone(RADIOLIB_PIN_TYPE pin) { - if(pin == RADIOLIB_NC) { + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + if((pin == RADIOLIB_NC) || (cb_noTone == nullptr)) { return; } - - #if !defined(RADIOLIB_TONE_UNSUPPORTED) - ::noTone(pin); + #if defined(ARDUINO_ARCH_STM32) + cb_noTone(pin, false); #else - #if defined(ESP32) - ledcDetachPin(pin); - ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + cb_noTone(pin); #endif + #else + if(pin == RADIOLIB_NC) { + return; + } + #if defined(ESP32) + // ESP32 tone() emulation + ledcDetachPin(pin); + ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + #endif #endif } void Module::attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode) { - ::attachInterrupt(interruptNum, userFunc, mode); + if((interruptNum == RADIOLIB_NC) || (cb_attachInterrupt == nullptr)) { + return; + } + cb_attachInterrupt(interruptNum, userFunc, mode); } void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) { - ::detachInterrupt(interruptNum); + if((interruptNum == RADIOLIB_NC) || (cb_detachInterrupt == nullptr)) { + return; + } + cb_detachInterrupt(interruptNum); } void Module::yield() { + if(cb_yield == nullptr) { + return; + } #if !defined(RADIOLIB_YIELD_UNSUPPORTED) - ::yield(); + cb_yield(); #endif } void Module::delay(uint32_t ms) { - ::delay(ms); + if(cb_delay == nullptr) { + return; + } + cb_delay(ms); } void Module::delayMicroseconds(uint32_t us) { - ::delayMicroseconds(us); + if(cb_delayMicroseconds == nullptr) { + return; + } + cb_delayMicroseconds(us); } uint32_t Module::millis() { - return(::millis()); + if(cb_millis == nullptr) { + return(0); + } + return(cb_millis()); } uint32_t Module::micros() { - return(::micros()); + if(cb_micros == nullptr) { + return(0); + } + return(cb_micros()); } +void Module::begin() { + if(cb_SPIbegin == nullptr) { + return; + } + (this->*cb_SPIbegin)(); +} + +void Module::beginTransaction() { + if(cb_SPIbeginTransaction == nullptr) { + return; + } + (this->*cb_SPIbeginTransaction)(); +} + +uint8_t Module::transfer(uint8_t b) { + if(cb_SPItransfer == nullptr) { + return(0xFF); + } + return((this->*cb_SPItransfer)(b)); +} + +void Module::endTransaction() { + if(cb_SPIendTransaction == nullptr) { + return; + } + (this->*cb_SPIendTransaction)(); +} + +void Module::end() { + if(cb_SPIend == nullptr) { + return; + } + (this->*cb_SPIend)(); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +void Module::SPIbegin() { + _spi->begin(); +} + +void Module::SPIbeginTransaction() { + _spi->beginTransaction(_spiSettings); +} + +uint8_t Module::SPItransfer(uint8_t b) { + return(_spi->transfer(b)); +} + +void Module::SPIendTransaction() { + _spi->endTransaction(); +} + +void Module::SPIend() { + _spi->end(); +} +#endif + uint8_t Module::flipBits(uint8_t b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xCC) >> 2 | (b & 0x33) << 2; @@ -414,8 +429,8 @@ void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _useRfSwitch = true; _rxEn = rxEn; _txEn = txEn; - Module::pinMode(rxEn, OUTPUT); - Module::pinMode(txEn, OUTPUT); + this->pinMode(rxEn, OUTPUT); + this->pinMode(txEn, OUTPUT); } void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) { @@ -425,6 +440,6 @@ void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATU } // set pins - Module::digitalWrite(_rxEn, rxPinState); - Module::digitalWrite(_txEn, txPinState); + this->digitalWrite(_rxEn, rxPinState); + this->digitalWrite(_txEn, txPinState); } diff --git a/src/Module.h b/src/Module.h index 324c4e308a..a824d1737d 100644 --- a/src/Module.h +++ b/src/Module.h @@ -1,12 +1,9 @@ -#ifndef _RADIOLIB_MODULE_H +#if !defined(_RADIOLIB_MODULE_H) #define _RADIOLIB_MODULE_H #include "TypeDef.h" #include -#ifndef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED -#include -#endif /*! \class Module @@ -16,19 +13,11 @@ */ class Module { public: - /*! - \brief SPI-based module constructor. Will use the default SPI interface automatically initialize it. - - \param cs Arduino pin to be used as chip select. - \param irq Arduino pin to be used as interrupt/GPIO. - - \param rst Arduino pin to be used as hardware reset for the module. - */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! - \brief Extended SPI-based module constructor. Will use the default SPI interface automatically initialize it. + \brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it \param cs Arduino pin to be used as chip select. @@ -38,25 +27,10 @@ class Module { \param gpio Arduino pin to be used as additional interrupt/GPIO. */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio); - - /*! - \brief SPI-based module constructor. - - \param cs Arduino pin to be used as chip select. - - \param irq Arduino pin to be used as interrupt/GPIO. - - \param rst Arduino pin to be used as hardware reset for the module. - - \param spi SPI interface to be used, can also use software SPI implementations. - - \param spiSettings SPI interface settings. - */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC); /*! - \brief Extended SPI-based module constructor. + \brief Arduino Module constructor. Will not attempt SPI interface initialization. \param cs Arduino pin to be used as chip select. @@ -68,34 +42,26 @@ class Module { \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0. + \param spiSettings SPI interface settings. */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0)); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings); - /*! - \brief Generic module constructor. - - \param cs Arduino pin to be used as chip select. - - \param irq Arduino pin to be used as interrupt/GPIO. - - \param rst Arduino pin to be used as hardware reset for the module. + #else - \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication. + /*! + \brief Default constructor. - \param rx Arduino pin to be used as Rx pin for SoftwareSerial communication. + \param cs Pin to be used as chip select. - \param spi SPI interface to be used. Defaults to Arduino hardware SPI interface, can also use software SPI implementations. + \param irq Pin to be used as interrupt/GPIO. - \param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0. + \param rst Pin to be used as hardware reset for the module. - \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1 + \param gpio Pin to be used as additional interrupt/GPIO. */ -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = RADIOLIB_DEFAULT_SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT); -#else - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = RADIOLIB_DEFAULT_SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr); -#endif + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC); + + #endif /*! \brief Copy constructor. @@ -113,25 +79,6 @@ class Module { // public member variables - /*! - \brief Internal SoftwareSerial instance. - */ -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - HardwareSerial* ModuleSerial; -#else - SoftwareSerial* ModuleSerial; -#endif - - /*! - \brief Baud rate of SoftwareSerial UART communication. Defaults to 9600 baud. - */ - uint32_t baudrate = 9600; - - /*! - \brief Line feed to be used when sending AT commands. Defaults to CR+LF. - */ - char AtLineFeed[3] = {'\r', '\n'}; - /*! \brief Basic SPI read command. Defaults to 0x00. */ @@ -146,51 +93,13 @@ class Module { /*! \brief Initialize low-level module control. - - \param interface Interface to be used on the module. See \ref shield_config for details. */ - void init(uint8_t interface); + void init(); /*! \brief Terminate low-level module control. - - \param interface Interface to be terminated. See \ref shield_config for details. - */ - void term(uint8_t interface); - - // AT methods - - /*! - \brief Empty internal AT buffer. - */ - void ATemptyBuffer(); - - /*! - \brief Get response after sending AT command. - - \returns True if AT response contains the string "OK", false otherwise. - */ - bool ATgetResponse(); - - /*! - \brief Send AT command. Will also call ATgetResponse. - - \param cmd AT command to be sent. Line feed characters are added automatically. - - \returns True if AT response contains the string "OK", false otherwise. - */ - bool ATsendCommand(const char* cmd); - - /*! - \brief Send raw AT data. Will also call ATgetResponse. - - \param data Data to be sent. - - \param len Number of bytes to send. - - \returns True if AT response contains the string "OK", false otherwise. */ - bool ATsendData(uint8_t* data, uint32_t len); + void term(); // SPI methods @@ -309,35 +218,7 @@ class Module { \returns Pin number of second interrupt/GPIO configured in the constructor. */ - RADIOLIB_PIN_TYPE getGpio() const { return(_rx); } - - /*! - \brief Access method to get the pin number of UART Rx. - - \returns Pin number of UART Rx configured in the constructor. - */ - RADIOLIB_PIN_TYPE getRx() const { return(_rx); } - - /*! - \brief Access method to get the pin number of UART Rx. - - \returns Pin number of UART Rx configured in the constructor. - */ - RADIOLIB_PIN_TYPE getTx() const { return(_tx); } - - /*! - \brief Access method to get the SPI interface. - - \returns SPI interface configured in the constructor. - */ - SPIClass* getSpi() const { return(_spi); } - - /*! - \brief Access method to get the SPI interface settings. - - \returns SPI interface settings configured in the constructor. - */ - SPISettings getSpiSettings() const { return(_spiSettings); } + RADIOLIB_PIN_TYPE getGpio() const { return(_gpio); } /*! \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. @@ -367,7 +248,7 @@ class Module { \param mode Which mode to set. */ - static void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode); + void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode); /*! \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin. @@ -376,7 +257,7 @@ class Module { \param value Whether to set the pin high or low. */ - static void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value); + void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value); /*! \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin. @@ -385,7 +266,7 @@ class Module { \returns Pin value. */ - static RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin); + RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin); /*! \brief Arduino core tone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone. @@ -394,14 +275,14 @@ class Module { \param value Frequency to output. */ - static void tone(RADIOLIB_PIN_TYPE pin, uint16_t value); + void tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration = 0); /*! \brief Arduino core noTone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone. \param pin Pin to write to. */ - static void noTone(RADIOLIB_PIN_TYPE pin); + void noTone(RADIOLIB_PIN_TYPE pin); /*! \brief Arduino core attachInterrupt override. @@ -412,43 +293,77 @@ class Module { \param mode Pin hcange direction. */ - static void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode); + void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode); /*! \brief Arduino core detachInterrupt override. \param interruptNum Interrupt number. */ - static void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum); + void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum); /*! \brief Arduino core yield override. */ - static void yield(); + void yield(); /*! \brief Arduino core delay override. \param ms Delay length in milliseconds. */ - static void delay(uint32_t ms); + void delay(uint32_t ms); /*! \brief Arduino core delayMicroseconds override. \param us Delay length in microseconds. */ - static void delayMicroseconds(uint32_t us); + void delayMicroseconds(uint32_t us); /*! \brief Arduino core millis override. */ - static uint32_t millis(); + uint32_t millis(); /*! \brief Arduino core micros override. */ - static uint32_t micros(); + uint32_t micros(); + + /*! + \brief Arduino core SPI begin override. + */ + void begin(); + + /*! + \brief Arduino core SPI beginTransaction override. + */ + void beginTransaction(); + + /*! + \brief Arduino core SPI transfer override. + */ + uint8_t transfer(uint8_t b); + + /*! + \brief Arduino core SPI endTransaction override. + */ + void endTransaction(); + + /*! + \brief Arduino core SPI end override. + */ + void end(); + + // helper functions to set up SPI overrides on Arduino + #if defined(RADIOLIB_BUILD_ARDUINO) + void SPIbegin(); + void SPIbeginTransaction(); + uint8_t SPItransfer(uint8_t b); + void SPIendTransaction(); + void SPIend(); + #endif /*! \brief Function to reflect bits within a byte. @@ -460,58 +375,55 @@ class Module { */ static uint16_t flipBits16(uint16_t i); -#ifndef RADIOLIB_GODMODE + // hardware abstraction layer callbacks + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_READ); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_TONE); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_NO_TONE); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_ATTACH_INTERRUPT); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DETACH_INTERRUPT); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_YIELD); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY_MICROSECONDS); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MILLIS); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MICROS); + + #if defined(RADIOLIB_BUILD_ARDUINO) + RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN); + RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION); + RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_TRANSFER); + RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION); + RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END); + #else + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_TRANSFER); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END); + #endif + +#if !defined(RADIOLIB_GODMODE) private: #endif - // allow SerialModule class to access private members - friend class SerialModule; - - // whether RadioLib should automatically initalize selected SPI or UART interface - bool _initInterface = false; // pins RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC; RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC; RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _rx = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _tx = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _gpio = RADIOLIB_NC; - // SPI settings - SPISettings _spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0); + // SPI interface (Arduino only) + #if defined(RADIOLIB_BUILD_ARDUINO) SPIClass* _spi = NULL; + SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; + bool _initInterface = false; + #endif // RF switch presence and pins bool _useRfSwitch = false; RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC; RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC; - - // AT command timeout in milliseconds - uint32_t _ATtimeout = 15000; -}; - -/*! - \class SerialModule - - \brief Extension of Module class for UART-based modules, only exists to distinguish the UART constructor. -*/ -class SerialModule: public Module { - public: - /*! - \brief UART-based module constructor. - - \param rx Arduino pin to be used as Rx pin for SoftwareSerial communication. - - \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication. - - \param rst Arduino pin to be used as hardware reset for the module. Defaults to NC (unused). - - \param serial HardwareSerial to be used on platforms that do not support SoftwareSerial. Defaults to Serial1. - */ - #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - SerialModule(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC, HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT); - #else - SerialModule(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC, HardwareSerial* serial = nullptr); - #endif }; #endif From c6eb3ee94fbbbde037384321133c0fc25c78488d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:34:13 +0100 Subject: [PATCH 0034/1848] Removed reference to AT commands --- extras/decoder/DebugDecoder.py | 1 - extras/template/ModuleTemplate.cpp | 2 +- extras/template/ModuleTemplate.h | 30 +++++++++--------------------- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/extras/decoder/DebugDecoder.py b/extras/decoder/DebugDecoder.py index 330326f61f..c5c9b37130 100644 --- a/extras/decoder/DebugDecoder.py +++ b/extras/decoder/DebugDecoder.py @@ -8,7 +8,6 @@ 1. Parse macro values (the names of bits in all registers in header file) 2. Failed SPI write handling 3. SX126x/SX128x handling - 4. AT handling ''' diff --git a/extras/template/ModuleTemplate.cpp b/extras/template/ModuleTemplate.cpp index 07267305af..1efb1fc069 100644 --- a/extras/template/ModuleTemplate.cpp +++ b/extras/template/ModuleTemplate.cpp @@ -17,6 +17,6 @@ int16_t ::begin() { /* "begin" method SHOULD implement some sort of mechanism to verify the connection between Arduino and the module. - For example, sending AT command for UART modules, or reading a version register for SPI/I2C modules + For example, reading a version register */ } diff --git a/extras/template/ModuleTemplate.h b/extras/template/ModuleTemplate.h index 4d957cb0ee..ee121942ff 100644 --- a/extras/template/ModuleTemplate.h +++ b/extras/template/ModuleTemplate.h @@ -13,7 +13,7 @@ */ #if !defined(_RADIOLIB__H) && !defined(RADIOLIB_EXCLUDE_) -#ifndef _RADIOLIB__H +#if !defined(_RADIOLIB__H) #define _RADIOLIB__H /* @@ -23,16 +23,6 @@ #include "../../Module.h" #include "../../TypeDef.h" -/* - Only use the following include if the module implements methods for OSI transport layer control. - This concerns only modules similar to e.g. ESP8266. - - In this case, your class MUST implement all virtual methods of TransportLayer class. - You also MUST provide crystal oscillator frequency and frequency configuration divisor step resolution - to the TransportLayer constructor. -*/ -//#include "../../protocols/PhysicalLayer/TransportLayer.h" - /* Only use the following include if the module implements methods for OSI physical layer control. This concerns only modules similar to SX127x/RF69/CC1101 etc. @@ -43,7 +33,7 @@ /* Register map - Definition of SPI/I2C register map SHOULD be placed here. The register map SHOULD have two parts: + Definition of SPI register map SHOULD be placed here. The register map SHOULD have two parts: 1 - Address map: only defines register names and addresses. Register names MUST match names in official documentation (datasheets etc.). @@ -52,11 +42,11 @@ See RF69 and SX127x header files for examples of register maps. */ -// register map | spaces up to this point -#define _REG_ 0x00 +// register map | spaces up to this point +#define RADIOLIB__REG_ 0x00 -// _REG_ MSB LSB DESCRIPTION -#define _ 0b00000000 // 7 0 +// _REG_ MSB LSB DESCRIPTION +#define RADIOLIB__ 0b00000000 // 7 0 /* @@ -64,10 +54,8 @@ The module class MAY inherit from the following classes: - 1 - ISerial: Interface for Arduino Serial class, intended as a thin wrapper for modules that directly take - Serial input (e.g. HC-05). - 2 - TransportLayer: In case the module implements methods for OSI transport layer control (e.g. ESP8266). - 3 - PhysicalLayer: In case the module implements methods for OSI physical layer control (e.g. SX127x). + 1 - PhysicalLayer: In case the module implements methods for OSI physical layer control (e.g. SX127x). + 2 - Common class: In case the module further specifies some more generic class (e.g. SX127x/SX1278) */ class { public: @@ -90,7 +78,7 @@ class { All implemented methods SHOULD return the status as int16_t type. */ -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif /* From 10ec10d233ade71d3fa961f18faeb321eaf6938d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:35:32 +0100 Subject: [PATCH 0035/1848] Removerd reference to UART --- src/BuildOpt.h | 2 +- src/Module.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 0d8b628cb5..ba163c1d9d 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -754,7 +754,7 @@ * Warning: Debug output will slow down the whole system significantly. * Also, it will result in larger compiled binary. * Levels: debug - only main info - * verbose - full transcript of all SPI/UART communication + * verbose - full transcript of all SPI communication */ #if !defined(RADIOLIB_DEBUG) //#define RADIOLIB_DEBUG diff --git a/src/Module.h b/src/Module.h index a824d1737d..6c44033bd5 100644 --- a/src/Module.h +++ b/src/Module.h @@ -8,7 +8,7 @@ /*! \class Module - \brief Implements all common low-level SPI/UART methods to control the wireless module. + \brief Implements all common low-level methods to control the wireless module. Every module class contains one private instance of this class. */ class Module { From 70d86f7eb6f8da08f049a3a0a20cf6cf3bda8e16 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:36:06 +0100 Subject: [PATCH 0036/1848] Updated macro names --- keywords.txt | 189 ++++++++++--------------------- src/TypeDef.h | 306 ++++++++++---------------------------------------- 2 files changed, 123 insertions(+), 372 deletions(-) diff --git a/keywords.txt b/keywords.txt index 8548153eb5..00db446d65 100644 --- a/keywords.txt +++ b/keywords.txt @@ -13,9 +13,6 @@ SerialModule KEYWORD1 # modules CC1101 KEYWORD1 -ESP8266 KEYWORD1 -HC05 KEYWORD1 -JDY08 KEYWORD1 LLCC68 KEYWORD1 nRF24 KEYWORD1 RF69 KEYWORD1 @@ -42,12 +39,8 @@ SX1279 KEYWORD1 SX1280 KEYWORD1 SX1281 KEYWORD1 SX1282 KEYWORD1 -XBee KEYWORD1 -XBeeSerial KEYWORD1 # protocols -MQTTClient KEYWORD1 -HTTPClient KEYWORD1 RTTYClient KEYWORD1 MorseClient KEYWORD1 PagerClient KEYWORD1 @@ -177,17 +170,6 @@ startReceiveDutyCycleAuto KEYWORD2 setRegulatorLDO KEYWORD2 setRegulatorDCDC KEYWORD2 getCurrentLimit KEYWORD2 - -# ESP8266 -join KEYWORD2 -reset KEYWORD2 - -# XBee -setDestinationAddress KEYWORD2 -setPanId KEYWORD2 -getPacketSource KEYWORD2 -getPacketData KEYWORD2 - # nRF24 setIrqAction KEYWORD2 setAddressWidth KEYWORD2 @@ -197,19 +179,6 @@ disablePipe KEYWORD2 getStatus KEYWORD2 setAutoAck KEYWORD2 -# HTTP -get KEYWORD2 -post KEYWORD2 - -# MQTT -connect KEYWORD2 -disconnect KEYWORD2 -publish KEYWORD2 -subscribe KEYWORD2 -unsubscribe KEYWORD2 -ping KEYWORD2 -check KEYWORD2 - # RTTY idle KEYWORD2 byteArr KEYWORD2 @@ -217,17 +186,6 @@ byteArr KEYWORD2 # Morse startSignal KEYWORD2 -# TransportLayer -openTransportConnection KEYWORD2 -closeTransportConnection KEYWORD2 -send KEYWORD2 -receive KEYWORD2 -getNumBytes KEYWORD2 - -# SIM800 -sendSMS KEYWORD2 -shutdown KEYWORD2 - # AX.25 setRepeaters KEYWORD2 setRecvSequence KEYWORD2 @@ -273,88 +231,65 @@ RADIOLIB_ENCODING_NRZ LITERAL1 RADIOLIB_ENCODING_MANCHESTER LITERAL1 RADIOLIB_ENCODING_WHITENING LITERAL1 -ERR_NONE LITERAL1 -ERR_UNKNOWN LITERAL1 - -ERR_CHIP_NOT_FOUND LITERAL1 -ERR_MEMORY_ALLOCATION_FAILED LITERAL1 -ERR_PACKET_TOO_LONG LITERAL1 -ERR_TX_TIMEOUT LITERAL1 -ERR_RX_TIMEOUT LITERAL1 -ERR_CRC_MISMATCH LITERAL1 -ERR_INVALID_BANDWIDTH LITERAL1 -ERR_INVALID_SPREADING_FACTOR LITERAL1 -ERR_INVALID_CODING_RATE LITERAL1 -ERR_INVALID_BIT_RANGE LITERAL1 -ERR_INVALID_FREQUENCY LITERAL1 -ERR_INVALID_OUTPUT_POWER LITERAL1 -PREAMBLE_DETECTED LITERAL1 -CHANNEL_FREE LITERAL1 -ERR_SPI_WRITE_FAILED LITERAL1 -ERR_INVALID_CURRENT_LIMIT LITERAL1 -ERR_INVALID_PREAMBLE_LENGTH LITERAL1 -ERR_INVALID_GAIN LITERAL1 -ERR_WRONG_MODEM LITERAL1 -ERR_INVALID_NUM_SAMPLES LITERAL1 -ERR_INVALID_RSSI_OFFSET LITERAL1 -ERR_INVALID_ENCODING LITERAL1 - -ERR_INVALID_BIT_RATE LITERAL1 -ERR_INVALID_FREQUENCY_DEVIATION LITERAL1 -ERR_INVALID_BIT_RATE_BW_RATIO LITERAL1 -ERR_INVALID_RX_BANDWIDTH LITERAL1 -ERR_INVALID_SYNC_WORD LITERAL1 -ERR_INVALID_DATA_SHAPING LITERAL1 -ERR_INVALID_MODULATION LITERAL1 - -ERR_AT_FAILED LITERAL1 -ERR_URL_MALFORMED LITERAL1 -ERR_RESPONSE_MALFORMED_AT LITERAL1 -ERR_RESPONSE_MALFORMED LITERAL1 -ERR_MQTT_CONN_VERSION_REJECTED LITERAL1 -ERR_MQTT_CONN_ID_REJECTED LITERAL1 -ERR_MQTT_CONN_SERVER_UNAVAILABLE LITERAL1 -ERR_MQTT_CONN_BAD_USERNAME_PASSWORD LITERAL1 -ERR_MQTT_CONN_NOT_AUTHORIZED LITERAL1 -ERR_MQTT_UNEXPECTED_PACKET_ID LITERAL1 -ERR_MQTT_NO_NEW_PACKET_AVAILABLE LITERAL1 -MQTT_SUBS_SUCCESS_QOS_0 LITERAL1 -MQTT_SUBS_SUCCESS_QOS_1 LITERAL1 -MQTT_SUBS_SUCCESS_QOS_2 LITERAL1 -ERR_MQTT_SUBS_FAILED LITERAL1 - -ERR_CMD_MODE_FAILED LITERAL1 -ERR_FRAME_MALFORMED LITERAL1 -ERR_FRAME_INCORRECT_CHECKSUM LITERAL1 -ERR_FRAME_UNEXPECTED_ID LITERAL1 -ERR_FRAME_NO_RESPONSE LITERAL1 - -ASCII LITERAL1 -ASCII_EXTENDED LITERAL1 -ITA2 LITERAL1 -BCD LITERAL1 -ERR_INVALID_RTTY_SHIFT LITERAL1 -ERR_UNSUPPORTED_ENCODING LITERAL1 - -ERR_INVALID_DATA_RATE LITERAL1 -ERR_INVALID_ADDRESS_WIDTH LITERAL1 -ERR_INVALID_PIPE_NUMBER LITERAL1 -ERR_ACK_NOT_RECEIVED LITERAL1 - -ERR_INVALID_NUM_BROAD_ADDRS LITERAL1 - -ERR_INVALID_CRC_CONFIGURATION LITERAL1 -LORA_DETECTED LITERAL1 -ERR_INVALID_TCXO_VOLTAGE LITERAL1 -ERR_INVALID_MODULATION_PARAMETERS LITERAL1 -ERR_SPI_CMD_TIMEOUT LITERAL1 -ERR_SPI_CMD_INVALID LITERAL1 -ERR_SPI_CMD_FAILED LITERAL1 -ERR_INVALID_SLEEP_PERIOD LITERAL1 -ERR_INVALID_RX_PERIOD LITERAL1 - -ERR_INVALID_CALLSIGN LITERAL1 -ERR_INVALID_NUM_REPEATERS LITERAL1 -ERR_INVALID_REPEATER_CALLSIGN LITERAL1 - -ERR_RANGING_TIMEOUT LITERAL1 +RADIOLIB_ERR_NONE LITERAL1 +RADIOLIB_ERR_UNKNOWN LITERAL1 + +RADIOLIB_ERR_CHIP_NOT_FOUND LITERAL1 +RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED LITERAL1 +RADIOLIB_ERR_PACKET_TOO_LONG LITERAL1 +RADIOLIB_ERR_TX_TIMEOUT LITERAL1 +RADIOLIB_ERR_RX_TIMEOUT LITERAL1 +RADIOLIB_ERR_CRC_MISMATCH LITERAL1 +RADIOLIB_ERR_INVALID_BANDWIDTH LITERAL1 +RADIOLIB_ERR_INVALID_SPREADING_FACTOR LITERAL1 +RADIOLIB_ERR_INVALID_CODING_RATE LITERAL1 +RADIOLIB_ERR_INVALID_BIT_RANGE LITERAL1 +RADIOLIB_ERR_INVALID_FREQUENCY LITERAL1 +RADIOLIB_ERR_INVALID_OUTPUT_POWER LITERAL1 +RADIOLIB_PREAMBLE_DETECTED LITERAL1 +RADIOLIB_CHANNEL_FREE LITERAL1 +RADIOLIB_ERR_SPI_WRITE_FAILED LITERAL1 +RADIOLIB_ERR_INVALID_CURRENT_LIMIT LITERAL1 +RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH LITERAL1 +RADIOLIB_ERR_INVALID_GAIN LITERAL1 +RADIOLIB_ERR_WRONG_MODEM LITERAL1 +RADIOLIB_ERR_INVALID_NUM_SAMPLES LITERAL1 +RADIOLIB_ERR_INVALID_RSSI_OFFSET LITERAL1 +RADIOLIB_ERR_INVALID_ENCODING LITERAL1 + +RADIOLIB_ERR_INVALID_BIT_RATE LITERAL1 +RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION LITERAL1 +RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO LITERAL1 +RADIOLIB_ERR_INVALID_RX_BANDWIDTH LITERAL1 +RADIOLIB_ERR_INVALID_SYNC_WORD LITERAL1 +RADIOLIB_ERR_INVALID_DATA_SHAPING LITERAL1 +RADIOLIB_ERR_INVALID_MODULATION LITERAL1 + +RADIOLIB_ASCII LITERAL1 +RADIOLIB_ASCII_EXTENDED LITERAL1 +RADIOLIB_ITA2 LITERAL1 +RADIOLIB_ERR_INVALID_RTTY_SHIFT LITERAL1 +RADIOLIB_ERR_UNSUPPORTED_ENCODING LITERAL1 + +RADIOLIB_ERR_INVALID_DATA_RATE LITERAL1 +RADIOLIB_ERR_INVALID_ADDRESS_WIDTH LITERAL1 +RADIOLIB_ERR_INVALID_PIPE_NUMBER LITERAL1 +RADIOLIB_ERR_ACK_NOT_RECEIVED LITERAL1 + +RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS LITERAL1 + +RADIOLIB_ERR_INVALID_CRC_CONFIGURATION LITERAL1 +RADIOLIB_LORA_DETECTED LITERAL1 +RADIOLIB_ERR_INVALID_TCXO_VOLTAGE LITERAL1 +RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS LITERAL1 +RADIOLIB_ERR_SPI_CMD_TIMEOUT LITERAL1 +RADIOLIB_ERR_SPI_CMD_INVALID LITERAL1 +RADIOLIB_ERR_SPI_CMD_FAILED LITERAL1 +RADIOLIB_ERR_INVALID_SLEEP_PERIOD LITERAL1 +RADIOLIB_ERR_INVALID_RX_PERIOD LITERAL1 + +RADIOLIB_ERR_INVALID_CALLSIGN LITERAL1 +RADIOLIB_ERR_INVALID_NUM_REPEATERS LITERAL1 +RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN LITERAL1 + +RADIOLIB_ERR_RANGING_TIMEOUT LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index dfeb288373..27751dc258 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -3,86 +3,6 @@ #include "BuildOpt.h" -/*! - \defgroup shield_config Shield Configuration - - \{ -*/ - -/*! - \brief Use SPI interface. -*/ -#define RADIOLIB_USE_SPI 0x00 - -/*! - \brief Use UART interface. -*/ -#define RADIOLIB_USE_UART 0x01 - -/*! - \} -*/ - -/*! - \defgroup uart_config UART Configuration - - \{ -*/ - -/*! - \brief Use 1 bit stop. -*/ -#define RADIOLIB_UART_STOPBIT_1 0x01 - -/*! - \brief Use 1.5 bit stop. -*/ -#define RADIOLIB_UART_STOPBIT_1_5 0x02 - -/*! - \brief Use 2 bit stop. -*/ -#define RADIOLIB_UART_STOPBIT_2 0x03 - -/*! - \brief No parity. -*/ -#define RADIOLIB_UART_PARITY_NONE 0x00 - -/*! - \brief Odd parity. -*/ -#define RADIOLIB_UART_PARITY_ODD 0x01 - -/*! - \brief Even parity. -*/ -#define RADIOLIB_UART_PARITY_EVEN 0x02 - -/*! - \brief No flow control. -*/ -#define RADIOLIB_UART_FLOW_NONE 0x00 - -/*! - \brief RTS only. -*/ -#define RADIOLIB_UART_FLOW_RTS 0x01 - -/*! - \brief CTS only. -*/ -#define RADIOLIB_UART_FLOW_CTS 0x02 - -/*! - \brief Both RTS and CTS. -*/ -#define RADIOLIB_UART_FLOW_BOTH 0x03 - -/*! - \} -*/ - /*! \defgroup config_shaping Data shaping filter values aliases. @@ -92,27 +12,27 @@ /*! \brief No shaping. */ -#define RADIOLIB_SHAPING_NONE 0x00 +#define RADIOLIB_SHAPING_NONE (0x00) /*! \brief Gaussin shaping filter, BT = 0.3 */ -#define RADIOLIB_SHAPING_0_3 0x01 +#define RADIOLIB_SHAPING_0_3 (0x01) /*! \brief Gaussin shaping filter, BT = 0.5 */ -#define RADIOLIB_SHAPING_0_5 0x02 +#define RADIOLIB_SHAPING_0_5 (0x02) /*! \brief Gaussin shaping filter, BT = 0.7 */ -#define RADIOLIB_SHAPING_0_7 0x03 +#define RADIOLIB_SHAPING_0_7 (0x03) /*! \brief Gaussin shaping filter, BT = 1.0 */ -#define RADIOLIB_SHAPING_1_0 0x04 +#define RADIOLIB_SHAPING_1_0 (0x04) /*! \} @@ -127,17 +47,17 @@ /*! \brief Non-return to zero - no encoding. */ -#define RADIOLIB_ENCODING_NRZ 0x00 +#define RADIOLIB_ENCODING_NRZ (0x00) /*! \brief Manchester encoding. */ -#define RADIOLIB_ENCODING_MANCHESTER 0x01 +#define RADIOLIB_ENCODING_MANCHESTER (0x01) /*! \brief Whitening. */ -#define RADIOLIB_ENCODING_WHITENING 0x02 +#define RADIOLIB_ENCODING_WHITENING (0x02) /*! \} @@ -154,13 +74,13 @@ /*! \brief No error, method executed successfully. */ -#define ERR_NONE 0 +#define RADIOLIB_ERR_NONE (0) /*! \brief There was an unexpected, unknown error. If you see this, something went incredibly wrong. Your Arduino may be possessed, contact your local exorcist to resolve this error. */ -#define ERR_UNKNOWN -1 +#define RADIOLIB_ERR_UNKNOWN (-1) // SX127x/RFM9x status codes @@ -168,344 +88,240 @@ \brief Radio chip was not found during initialization. This can be caused by specifying wrong chip type in the constructor (i.e. calling SX1272 constructor for SX1278 chip) or by a fault in your wiring (incorrect slave select pin). */ -#define ERR_CHIP_NOT_FOUND -2 +#define RADIOLIB_ERR_CHIP_NOT_FOUND (-2) /*! \brief Failed to allocate memory for temporary buffer. This can be cause by not enough RAM or by passing invalid pointer. */ -#define ERR_MEMORY_ALLOCATION_FAILED -3 +#define RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED (-3) /*! \brief Packet supplied to transmission method was longer than limit. */ -#define ERR_PACKET_TOO_LONG -4 +#define RADIOLIB_ERR_PACKET_TOO_LONG (-4) /*! \brief Timed out waiting for transmission finish. */ -#define ERR_TX_TIMEOUT -5 +#define RADIOLIB_ERR_TX_TIMEOUT (-5) /*! \brief Timed out waiting for incoming transmission. */ -#define ERR_RX_TIMEOUT -6 +#define RADIOLIB_ERR_RX_TIMEOUT (-6) /*! \brief The calculated and expected CRCs of received packet do not match. This means that the packet was damaged during transmission and should be sent again. */ -#define ERR_CRC_MISMATCH -7 +#define RADIOLIB_ERR_CRC_MISMATCH (-7) /*! \brief The supplied bandwidth value is invalid for this module. */ -#define ERR_INVALID_BANDWIDTH -8 +#define RADIOLIB_ERR_INVALID_BANDWIDTH (-8) /*! \brief The supplied spreading factor value is invalid for this module. */ -#define ERR_INVALID_SPREADING_FACTOR -9 +#define RADIOLIB_ERR_INVALID_SPREADING_FACTOR (-9) /*! \brief The supplied coding rate value is invalid for this module. */ -#define ERR_INVALID_CODING_RATE -10 +#define RADIOLIB_ERR_INVALID_CODING_RATE (-10) /*! \brief Internal only. */ -#define ERR_INVALID_BIT_RANGE -11 +#define RADIOLIB_ERR_INVALID_BIT_RANGE (-11) /*! \brief The supplied frequency value is invalid for this module. */ -#define ERR_INVALID_FREQUENCY -12 +#define RADIOLIB_ERR_INVALID_FREQUENCY (-12) /*! \brief The supplied output power value is invalid for this module. */ -#define ERR_INVALID_OUTPUT_POWER -13 +#define RADIOLIB_ERR_INVALID_OUTPUT_POWER (-13) /*! \brief LoRa preamble was detected during channel activity detection. This means that there is some LoRa device currently transmitting in your channel. */ -#define PREAMBLE_DETECTED -14 +#define RADIOLIB_PREAMBLE_DETECTED (-14) /*! \brief No LoRa preambles were detected during channel activity detection. Your channel is free. */ -#define CHANNEL_FREE -15 +#define RADIOLIB_CHANNEL_FREE (-15) /*! \brief Real value in SPI register does not match the expected one. This can be caused by faulty SPI wiring. */ -#define ERR_SPI_WRITE_FAILED -16 +#define RADIOLIB_ERR_SPI_WRITE_FAILED (-16) /*! \brief The supplied current limit value is invalid. */ -#define ERR_INVALID_CURRENT_LIMIT -17 +#define RADIOLIB_ERR_INVALID_CURRENT_LIMIT (-17) /*! \brief The supplied preamble length is invalid. */ -#define ERR_INVALID_PREAMBLE_LENGTH -18 +#define RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH (-18) /*! \brief The supplied gain value is invalid. */ -#define ERR_INVALID_GAIN -19 +#define RADIOLIB_ERR_INVALID_GAIN (-19) /*! \brief User tried to execute modem-exclusive method on a wrong modem. For example, this can happen when you try to change LoRa configuration when FSK modem is active. */ -#define ERR_WRONG_MODEM -20 +#define RADIOLIB_ERR_WRONG_MODEM (-20) /*! \brief The supplied number of RSSI samples is invalid. */ -#define ERR_INVALID_NUM_SAMPLES -21 +#define RADIOLIB_ERR_INVALID_NUM_SAMPLES (-21) /*! \brief The supplied RSSI offset is invalid. */ -#define ERR_INVALID_RSSI_OFFSET -22 +#define RADIOLIB_ERR_INVALID_RSSI_OFFSET (-22) /*! \brief The supplied encoding is invalid. */ -#define ERR_INVALID_ENCODING -23 +#define RADIOLIB_ERR_INVALID_ENCODING (-23) /*! \brief LoRa packet header has been damaged. */ -#define ERR_LORA_HEADER_DAMAGED -24 +#define RADIOLIB_ERR_LORA_HEADER_DAMAGED (-24) // RF69-specific status codes /*! \brief The supplied bit rate value is invalid. */ -#define ERR_INVALID_BIT_RATE -101 +#define RADIOLIB_ERR_INVALID_BIT_RATE (-101) /*! \brief The supplied frequency deviation value is invalid. */ -#define ERR_INVALID_FREQUENCY_DEVIATION -102 +#define RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION (-102) /*! \brief The supplied bit rate to bandwidth ratio is invalid. See the module datasheet for more information. */ -#define ERR_INVALID_BIT_RATE_BW_RATIO -103 +#define RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO (-103) /*! \brief The supplied receiver bandwidth value is invalid. */ -#define ERR_INVALID_RX_BANDWIDTH -104 +#define RADIOLIB_ERR_INVALID_RX_BANDWIDTH (-104) /*! \brief The supplied FSK sync word is invalid. */ -#define ERR_INVALID_SYNC_WORD -105 +#define RADIOLIB_ERR_INVALID_SYNC_WORD (-105) /*! \brief The supplied FSK data shaping option is invalid. */ -#define ERR_INVALID_DATA_SHAPING -106 +#define RADIOLIB_ERR_INVALID_DATA_SHAPING (-106) /*! \brief The current modulation is invalid for the requested operation. */ -#define ERR_INVALID_MODULATION -107 +#define RADIOLIB_ERR_INVALID_MODULATION (-107) /*! \brief Supplied Peak type is invalid. */ -#define ERR_INVALID_OOK_RSSI_PEAK_TYPE -108 - -// ESP8266 status codes - -/*! - \brief AT command failed to execute, or timed out. -*/ -#define ERR_AT_FAILED -201 - -/*! - \brief Supplied URL is malformed or invalid. -*/ -#define ERR_URL_MALFORMED -202 - -/*! - \brief AT command response was malformed. -*/ -#define ERR_RESPONSE_MALFORMED_AT -203 - -/*! - \brief Data response was malformed. -*/ -#define ERR_RESPONSE_MALFORMED -204 - -/*! - \brief MQTT broker rejected connection due to version mismatch. -*/ -#define ERR_MQTT_CONN_VERSION_REJECTED -205 - -/*! - \brief MQTT broker rejected connection due to unknown ID. -*/ -#define ERR_MQTT_CONN_ID_REJECTED -206 - -/*! - \brief Failed to establish connection with MQTT broker. -*/ -#define ERR_MQTT_CONN_SERVER_UNAVAILABLE -207 - -/*! - \brief Supplied username/password combination is incorrect. -*/ -#define ERR_MQTT_CONN_BAD_USERNAME_PASSWORD -208 - -/*! - \brief Unauthorized connection to MQTT broker. -*/ -#define ERR_MQTT_CONN_NOT_AUTHORIZED -208 - -/*! - \brief Received packet ID does not match the expected ID. -*/ -#define ERR_MQTT_UNEXPECTED_PACKET_ID -209 - -/*! - \brief No new packet was received since the last check. -*/ -#define ERR_MQTT_NO_NEW_PACKET_AVAILABLE -210 - -/*! - \brief Successfully subscribed to MQTT topic with QoS 0. -*/ -#define MQTT_SUBS_SUCCESS_QOS_0 0x00 - -/*! - \brief Successfully subscribed to MQTT topic with QoS 1. -*/ -#define MQTT_SUBS_SUCCESS_QOS_1 0x01 - -/*! - \brief Successfully subscribed to MQTT topic with QoS 2. -*/ -#define MQTT_SUBS_SUCCESS_QOS_2 0x02 - -/*! - \brief Failed to subscribe to MQTT topic. -*/ -#define ERR_MQTT_SUBS_FAILED 0x80 - -// XBee status codes - -/*! - \brief Failed to enter command mode. -*/ -#define ERR_CMD_MODE_FAILED -301 - -/*! - \brief Received ZigBee frame is malformed. -*/ -#define ERR_FRAME_MALFORMED -302 - -/*! - \brief Received ZigBee frame checksum does not match the calculated. -*/ -#define ERR_FRAME_INCORRECT_CHECKSUM -303 - -/*! - \brief Received ZigBee frame with unexpected ID. -*/ -#define ERR_FRAME_UNEXPECTED_ID -304 - -/*! - \brief Timed out waiting for response to ZigBee frame. -*/ -#define ERR_FRAME_NO_RESPONSE -305 +#define RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE (-108) // RTTY status codes /*! \brief Supplied RTTY frequency shift is invalid for this module. */ -#define ERR_INVALID_RTTY_SHIFT -401 +#define RADIOLIB_ERR_INVALID_RTTY_SHIFT (-401) /*! \brief Supplied RTTY encoding is invalid. */ -#define ERR_UNSUPPORTED_ENCODING -402 +#define RADIOLIB_ERR_UNSUPPORTED_ENCODING (-402) // nRF24-specific status codes /*! \brief Supplied data rate is invalid. */ -#define ERR_INVALID_DATA_RATE -501 +#define RADIOLIB_ERR_INVALID_DATA_RATE (-501) /*! \brief Supplied address width is invalid. */ -#define ERR_INVALID_ADDRESS_WIDTH -502 +#define RADIOLIB_ERR_INVALID_ADDRESS_WIDTH (-502) /*! \brief Supplied data pipe number is invalid. */ -#define ERR_INVALID_PIPE_NUMBER -503 +#define RADIOLIB_ERR_INVALID_PIPE_NUMBER (-503) /*! \brief ACK packet from destination module was not received within 15 retries. */ -#define ERR_ACK_NOT_RECEIVED -504 +#define RADIOLIB_ERR_ACK_NOT_RECEIVED (-504) // CC1101-specific status codes /*! \brief Supplied number of broadcast addresses is invalid. */ -#define ERR_INVALID_NUM_BROAD_ADDRS -601 +#define RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS (-601) // SX126x-specific status codes /*! \brief Supplied CRC configuration is invalid. */ -#define ERR_INVALID_CRC_CONFIGURATION -701 +#define RADIOLIB_ERR_INVALID_CRC_CONFIGURATION (-701) /*! \brief Detected LoRa transmission while scanning channel. */ -#define LORA_DETECTED -702 +#define RADIOLIB_LORA_DETECTED (-702) /*! \brief Supplied TCXO reference voltage is invalid. */ -#define ERR_INVALID_TCXO_VOLTAGE -703 +#define RADIOLIB_ERR_INVALID_TCXO_VOLTAGE (-703) /*! \brief Bit rate / bandwidth / frequency deviation ratio is invalid. See SX126x datasheet for details. */ -#define ERR_INVALID_MODULATION_PARAMETERS -704 +#define RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS (-704) /*! \brief SX126x timed out while waiting for complete SPI command. */ -#define ERR_SPI_CMD_TIMEOUT -705 +#define RADIOLIB_ERR_SPI_CMD_TIMEOUT (-705) /*! \brief SX126x received invalid SPI command. */ -#define ERR_SPI_CMD_INVALID -706 +#define RADIOLIB_ERR_SPI_CMD_INVALID (-706) /*! \brief SX126x failed to execute SPI command. */ -#define ERR_SPI_CMD_FAILED -707 +#define RADIOLIB_ERR_SPI_CMD_FAILED (-707) /*! \brief The supplied sleep period is invalid. @@ -513,14 +329,14 @@ The specified sleep period is shorter than the time necessary to sleep and wake the hardware including TCXO delay, or longer than the maximum possible */ -#define ERR_INVALID_SLEEP_PERIOD -708 +#define RADIOLIB_ERR_INVALID_SLEEP_PERIOD (-708) /*! \brief The supplied Rx period is invalid. The specified Rx period is shorter or longer than the hardware can handle. */ -#define ERR_INVALID_RX_PERIOD -709 +#define RADIOLIB_ERR_INVALID_RX_PERIOD (-709) // AX.25-specific status codes @@ -529,28 +345,28 @@ The specified callsign is longer than 6 ASCII characters. */ -#define ERR_INVALID_CALLSIGN -801 +#define RADIOLIB_ERR_INVALID_CALLSIGN (-801) /*! \brief The provided repeater configuration is invalid. The specified number of repeaters does not match number of repeater IDs or their callsigns. */ -#define ERR_INVALID_NUM_REPEATERS -802 +#define RADIOLIB_ERR_INVALID_NUM_REPEATERS (-802) /*! \brief One of the provided repeater callsigns is invalid. The specified callsign is longer than 6 ASCII characters. */ -#define ERR_INVALID_REPEATER_CALLSIGN -803 +#define RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN (-803) // SX128x-specific status codes /*! \brief Timed out waiting for ranging exchange finish. */ -#define ERR_RANGING_TIMEOUT -901 +#define RADIOLIB_ERR_RANGING_TIMEOUT (-901) /*! \} From fbdb3eb6a2f4f4a1f794f36bd4c2c775eed06c85 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:37:49 +0100 Subject: [PATCH 0037/1848] [AFSK] Update to 5.0.0 --- .../AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino | 4 ++-- examples/AFSK/AFSK_Tone/AFSK_Tone.ino | 4 ++-- examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino | 6 +++--- src/protocols/AFSK/AFSK.cpp | 10 ++++++---- src/protocols/AFSK/AFSK.h | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino index ebe8b1a91f..b749bb6e49 100644 --- a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino +++ b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -51,7 +51,7 @@ void setup() { // (RF69, CC1101,, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -62,7 +62,7 @@ void setup() { // initialize AFSK client Serial.print(F("[AFSK] Initializing ... ")); state = audio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino index 113576b3f6..e5dd0ab42f 100644 --- a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino +++ b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -49,7 +49,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -60,7 +60,7 @@ void setup() { // initialize AFSK client Serial.print(F("[AFSK] Initializing ... ")); state = audio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino b/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino index 7d780f42ca..9394d9ab27 100644 --- a/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino +++ b/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino @@ -46,7 +46,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -57,7 +57,7 @@ void setup() { // initialize AFSK client Serial.print(F("[AFSK] Initializing ... ")); state = audio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -68,7 +68,7 @@ void setup() { // after that, set mode to OOK Serial.print(F("[SX1278] Switching to OOK ... ")); state = radio.setOOK(true); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index ee3c7a0a3c..53ffe7d960 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -11,7 +11,7 @@ int16_t AFSKClient::begin() { int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { if(freq == 0) { - return(ERR_INVALID_FREQUENCY); + return(RADIOLIB_ERR_INVALID_FREQUENCY); } if(autoStart) { @@ -19,12 +19,14 @@ int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { RADIOLIB_ASSERT(state); } - Module::tone(_pin, freq); - return(ERR_NONE); + Module* mod = _phy->getMod(); + mod->tone(_pin, freq); + return(RADIOLIB_ERR_NONE); } int16_t AFSKClient::noTone() { - Module::noTone(_pin); + Module* mod = _phy->getMod(); + mod->noTone(_pin); return(_phy->standby()); } diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index 79183d5cd9..9df3cb41be 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -50,7 +50,7 @@ class AFSKClient { */ int16_t noTone(); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; From ba1568669fff7a9a6ae0952ddf14fad117e7685c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:38:05 +0100 Subject: [PATCH 0038/1848] [AX25] Update to 5.0.0 --- examples/AX25/AX25_Frames/AX25_Frames.ino | 10 +- examples/AX25/AX25_Transmit/AX25_Transmit.ino | 6 +- .../AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino | 8 +- src/protocols/AX25/AX25.cpp | 95 ++++++------- src/protocols/AX25/AX25.h | 126 +++++++++--------- 5 files changed, 123 insertions(+), 122 deletions(-) diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index 0167214c4a..232d05e228 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -58,7 +58,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -72,7 +72,7 @@ void setup() { // source station SSID: 0 // preamble length: 8 bytes state = ax25.begin("N7LEM"); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -97,7 +97,7 @@ void loop() { // send the frame Serial.print(F("[AX.25] Sending UI frame ... ")); int state = ax25.sendFrame(&frameUI); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); @@ -125,7 +125,7 @@ void loop() { // send the frame Serial.print(F("[AX.25] Sending RR frame ... ")); state = ax25.sendFrame(&frameRR); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); @@ -159,7 +159,7 @@ void loop() { // send the frame Serial.print(F("[AX.25] Sending I frame ... ")); state = ax25.sendFrame(&frameI); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index fa61383010..98236d108c 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -50,7 +50,7 @@ void setup() { // (RF69, CC1101,, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -64,7 +64,7 @@ void setup() { // source station SSID: 0 // preamble length: 8 bytes state = ax25.begin("N7LEM"); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -79,7 +79,7 @@ void loop() { // destination station callsign: "NJ7P" // destination station SSID: 0 int state = ax25.transmit("Hello World!", "NJ7P"); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); diff --git a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino index a44d1ed992..540dc08d14 100644 --- a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino +++ b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -53,7 +53,7 @@ void setup() { // (RF69, CC1101,, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -67,7 +67,7 @@ void setup() { // source station SSID: 0 // preamble length: 8 bytes state = ax25.begin("N7LEM"); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -82,7 +82,7 @@ void setup() { /* Serial.print(F("[AX.25] Setting correction ... ")); state = ax25.setCorrection(100, -100); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -98,7 +98,7 @@ void loop() { // destination station callsign: "NJ7P" // destination station SSID: 0 int state = ax25.transmit("Hello World!", "NJ7P"); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 1c1af83578..790582fb3e 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -24,7 +24,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src // set repeaters this->numRepeaters = 0; - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) this->repeaterCallsigns = NULL; this->repeaterSSIDs = NULL; #endif @@ -42,7 +42,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src // info field this->infoLen = infoLen; if(infoLen > 0) { - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) this->info = new uint8_t[infoLen]; #endif memcpy(this->info, info, infoLen); @@ -54,7 +54,7 @@ AX25Frame::AX25Frame(const AX25Frame& frame) { } AX25Frame::~AX25Frame() { - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) // deallocate info field if(infoLen > 0) { delete[] this->info; @@ -109,21 +109,21 @@ AX25Frame& AX25Frame::operator=(const AX25Frame& frame) { int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) { // check number of repeaters if((numRepeaters < 1) || (numRepeaters > 8)) { - return(ERR_INVALID_NUM_REPEATERS); + return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); } // check repeater configuration if((repeaterCallsigns == NULL) || (repeaterSSIDs == NULL)) { - return(ERR_INVALID_NUM_REPEATERS); + return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); } for(uint16_t i = 0; i < numRepeaters; i++) { - if(strlen(repeaterCallsigns[i]) > AX25_MAX_CALLSIGN_LEN) { - return(ERR_INVALID_REPEATER_CALLSIGN); + if(strlen(repeaterCallsigns[i]) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN); } } // create buffers - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) this->repeaterCallsigns = new char*[numRepeaters]; for(uint8_t i = 0; i < numRepeaters; i++) { this->repeaterCallsigns[i] = new char[strlen(repeaterCallsigns[i]) + 1]; @@ -139,7 +139,7 @@ int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs } memcpy(this->repeaterSSIDs, repeaterSSIDs, numRepeaters); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } void AX25Frame::setRecvSequence(uint8_t seqNumber) { @@ -161,14 +161,14 @@ AX25Client::AX25Client(PhysicalLayer* phy) { AX25Client::AX25Client(AFSKClient* audio) { _phy = audio->_phy; _audio = audio; - _afskMark = AX25_AFSK_MARK; - _afskSpace = AX25_AFSK_SPACE; + _afskMark = RADIOLIB_AX25_AFSK_MARK; + _afskSpace = RADIOLIB_AX25_AFSK_SPACE; } int16_t AX25Client::setCorrection(int16_t mark, int16_t space) { - _afskMark = AX25_AFSK_MARK + mark; - _afskSpace = AX25_AFSK_SPACE + space; - return(ERR_NONE); + _afskMark = RADIOLIB_AX25_AFSK_MARK + mark; + _afskSpace = RADIOLIB_AX25_AFSK_SPACE + space; + return(RADIOLIB_ERR_NONE); } #endif @@ -177,8 +177,8 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea _srcSSID = srcSSID; // check source callsign length (6 characters max) - if(strlen(srcCallsign) > AX25_MAX_CALLSIGN_LEN) { - return(ERR_INVALID_CALLSIGN); + if(strlen(srcCallsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); } // copy callsign @@ -194,10 +194,10 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) { // create control field - uint8_t controlField = AX25_CONTROL_U_UNNUMBERED_INFORMATION | AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_UNNUMBERED_FRAME; + uint8_t controlField = RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME; // build the frame - AX25Frame frame(destCallsign, destSSID, _srcCallsign, _srcSSID, controlField, AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str)); + AX25Frame frame(destCallsign, destSSID, _srcCallsign, _srcSSID, controlField, RADIOLIB_AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str)); // send Unnumbered Information frame return(sendFrame(&frame)); @@ -205,27 +205,27 @@ int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t int16_t AX25Client::sendFrame(AX25Frame* frame) { // check destination callsign length (6 characters max) - if(strlen(frame->destCallsign) > AX25_MAX_CALLSIGN_LEN) { - return(ERR_INVALID_CALLSIGN); + if(strlen(frame->destCallsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); } // check repeater configuration - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) if(!(((frame->repeaterCallsigns == NULL) && (frame->repeaterSSIDs == NULL) && (frame->numRepeaters == 0)) || ((frame->repeaterCallsigns != NULL) && (frame->repeaterSSIDs != NULL) && (frame->numRepeaters != 0)))) { - return(ERR_INVALID_NUM_REPEATERS); + return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); } for(uint16_t i = 0; i < frame->numRepeaters; i++) { - if(strlen(frame->repeaterCallsigns[i]) > AX25_MAX_CALLSIGN_LEN) { - return(ERR_INVALID_REPEATER_CALLSIGN); + if(strlen(frame->repeaterCallsigns[i]) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN); } } #endif // calculate frame length without FCS (destination address, source address, repeater addresses, control, PID, info) - size_t frameBuffLen = ((2 + frame->numRepeaters)*(AX25_MAX_CALLSIGN_LEN + 1)) + 1 + 1 + frame->infoLen; + size_t frameBuffLen = ((2 + frame->numRepeaters)*(RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1)) + 1 + 1 + frame->infoLen; // create frame buffer without preamble, start or stop flags - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) uint8_t* frameBuff = new uint8_t[frameBuffLen + 2]; #else uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -233,37 +233,37 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { uint8_t* frameBuffPtr = frameBuff; // set destination callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit - memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN); + memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); for(size_t i = 0; i < strlen(frame->destCallsign); i++) { *(frameBuffPtr + i) = frame->destCallsign[i] << 1; } - frameBuffPtr += AX25_MAX_CALLSIGN_LEN; + frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; // set destination SSID - *(frameBuffPtr++) = AX25_SSID_COMMAND_DEST | AX25_SSID_RESERVED_BITS | (frame->destSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE; + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_COMMAND_DEST | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->destSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; // set source callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit - memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN); + memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); for(size_t i = 0; i < strlen(frame->srcCallsign); i++) { *(frameBuffPtr + i) = frame->srcCallsign[i] << 1; } - frameBuffPtr += AX25_MAX_CALLSIGN_LEN; + frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; // set source SSID - *(frameBuffPtr++) = AX25_SSID_RESPONSE_SOURCE | AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE; + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_RESPONSE_SOURCE | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; // set repeater callsigns for(uint16_t i = 0; i < frame->numRepeaters; i++) { - memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN); + memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); for(size_t j = 0; j < strlen(frame->repeaterCallsigns[i]); j++) { *(frameBuffPtr + j) = frame->repeaterCallsigns[i][j] << 1; } - frameBuffPtr += AX25_MAX_CALLSIGN_LEN; - *(frameBuffPtr++) = AX25_SSID_HAS_NOT_BEEN_REPEATED | AX25_SSID_RESERVED_BITS | (frame->repeaterSSIDs[i] & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE; + frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_HAS_NOT_BEEN_REPEATED | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->repeaterSSIDs[i] & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; } // set HDLC extension end bit - *(frameBuffPtr - 1) |= AX25_SSID_HDLC_EXTENSION_END; + *(frameBuffPtr - 1) |= RADIOLIB_AX25_SSID_HDLC_EXTENSION_END; // set sequence numbers of the frames that have it uint8_t controlField = frame->control; @@ -301,7 +301,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { *(frameBuffPtr++) = (uint8_t)(fcs & 0xFF); // prepare buffer for the final frame (stuffed, with added preamble + flags and NRZI-encoded) - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) // worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags uint8_t* stuffedFrameBuff = new uint8_t[_preambleLen + 1 + (6*frameBuffLen)/5 + 2]; #else @@ -345,13 +345,13 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // deallocate memory - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] frameBuff; #endif // set preamble bytes and start flag field for(uint16_t i = 0; i < _preambleLen + 1; i++) { - stuffedFrameBuff[i] = AX25_FLAG; + stuffedFrameBuff[i] = RADIOLIB_AX25_FLAG; } // get stuffed frame length in bytes @@ -361,10 +361,10 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // set end flag field (may be split into two bytes due to misalignment caused by extra stuffing bits) if(trailingLen != 0) { stuffedFrameBuffLen++; - stuffedFrameBuff[stuffedFrameBuffLen - 2] = AX25_FLAG >> trailingLen; - stuffedFrameBuff[stuffedFrameBuffLen - 1] = AX25_FLAG << (8 - trailingLen); + stuffedFrameBuff[stuffedFrameBuffLen - 2] = RADIOLIB_AX25_FLAG >> trailingLen; + stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG << (8 - trailingLen); } else { - stuffedFrameBuff[stuffedFrameBuffLen - 1] = AX25_FLAG; + stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG; } // convert to NRZI @@ -390,9 +390,10 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // transmit - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { + Module* mod = _phy->getMod(); _phy->transmitDirect(); // iterate over all bytes in the buffer @@ -400,14 +401,14 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // check each bit for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { - uint32_t start = Module::micros(); + uint32_t start = mod->micros(); if(stuffedFrameBuff[i] & mask) { _audio->tone(_afskMark, false); } else { _audio->tone(_afskSpace, false); } - while(Module::micros() - start < AX25_AFSK_TONE_DURATION) { - Module::yield(); + while(mod->micros() - start < RADIOLIB_AX25_AFSK_TONE_DURATION) { + mod->yield(); } } @@ -423,7 +424,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { #endif // deallocate memory - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] stuffedFrameBuff; #endif diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 6b9dbbf92d..d924840a99 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -1,5 +1,5 @@ -#if !defined(_RADIOLIB_AX25_H) -#define _RADIOLIB_AX25_H +#if !defined(_RADIOLIB_RADIOLIB_AX25_H) +#define _RADIOLIB_RADIOLIB_AX25_H #include "../../TypeDef.h" @@ -9,76 +9,76 @@ #include "../AFSK/AFSK.h" // macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html -#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) -#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) ) -#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) -#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) +#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) +#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) ) +#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) +#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) // CRC-CCITT calculation macros -#define XOR(A, B) ( ((A) || (B)) && !((A) && (B)) ) -#define CRC_CCITT_POLY 0x1021 // generator polynomial -#define CRC_CCITT_POLY_REVERSED 0x8408 // CRC_CCITT_POLY in reversed bit order -#define CRC_CCITT_INIT 0xFFFF // initial value +#define XOR(A, B) ( ((A) || (B)) && !((A) && (B)) ) +#define CRC_CCITT_POLY 0x1021 // generator polynomial +#define CRC_CCITT_POLY_REVERSED 0x8408 // CRC_CCITT_POLY in reversed bit order +#define CRC_CCITT_INIT 0xFFFF // initial value // maximum callsign length in bytes -#define AX25_MAX_CALLSIGN_LEN 6 +#define RADIOLIB_AX25_MAX_CALLSIGN_LEN 6 // flag field MSB LSB DESCRIPTION -#define AX25_FLAG 0b01111110 // 7 0 AX.25 frame start/end flag +#define RADIOLIB_AX25_FLAG 0b01111110 // 7 0 AX.25 frame start/end flag // address field -#define AX25_SSID_COMMAND_DEST 0b10000000 // 7 7 frame type: command (set in destination SSID) -#define AX25_SSID_COMMAND_SOURCE 0b00000000 // 7 7 command (set in source SSID) -#define AX25_SSID_RESPONSE_DEST 0b00000000 // 7 7 response (set in destination SSID) -#define AX25_SSID_RESPONSE_SOURCE 0b10000000 // 7 7 response (set in source SSID) -#define AX25_SSID_HAS_NOT_BEEN_REPEATED 0b00000000 // 7 7 not repeated yet (set in repeater SSID) -#define AX25_SSID_HAS_BEEN_REPEATED 0b10000000 // 7 7 repeated (set in repeater SSID) -#define AX25_SSID_RESERVED_BITS 0b01100000 // 6 5 reserved bits in SSID -#define AX25_SSID_HDLC_EXTENSION_CONTINUE 0b00000000 // 0 0 HDLC extension bit: next octet contains more address information -#define AX25_SSID_HDLC_EXTENSION_END 0b00000001 // 0 0 address field end +#define RADIOLIB_AX25_SSID_COMMAND_DEST 0b10000000 // 7 7 frame type: command (set in destination SSID) +#define RADIOLIB_AX25_SSID_COMMAND_SOURCE 0b00000000 // 7 7 command (set in source SSID) +#define RADIOLIB_AX25_SSID_RESPONSE_DEST 0b00000000 // 7 7 response (set in destination SSID) +#define RADIOLIB_AX25_SSID_RESPONSE_SOURCE 0b10000000 // 7 7 response (set in source SSID) +#define RADIOLIB_AX25_SSID_HAS_NOT_BEEN_REPEATED 0b00000000 // 7 7 not repeated yet (set in repeater SSID) +#define RADIOLIB_AX25_SSID_HAS_BEEN_REPEATED 0b10000000 // 7 7 repeated (set in repeater SSID) +#define RADIOLIB_AX25_SSID_RESERVED_BITS 0b01100000 // 6 5 reserved bits in SSID +#define RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE 0b00000000 // 0 0 HDLC extension bit: next octet contains more address information +#define RADIOLIB_AX25_SSID_HDLC_EXTENSION_END 0b00000001 // 0 0 address field end // control field -#define AX25_CONTROL_U_SET_ASYNC_BAL_MODE 0b01101100 // 7 2 U frame type: set asynchronous balanced mode (connect request) -#define AX25_CONTROL_U_SET_ASYNC_BAL_MODE_EXT 0b00101100 // 7 2 set asynchronous balanced mode extended (connect request with module 128) -#define AX25_CONTROL_U_DISCONNECT 0b01000000 // 7 2 disconnect request -#define AX25_CONTROL_U_DISCONNECT_MODE 0b00001100 // 7 2 disconnect mode (system busy or disconnected) -#define AX25_CONTROL_U_UNNUMBERED_ACK 0b01100000 // 7 2 unnumbered acknowledge -#define AX25_CONTROL_U_FRAME_REJECT 0b10000100 // 7 2 frame reject -#define AX25_CONTROL_U_UNNUMBERED_INFORMATION 0b00000000 // 7 2 unnumbered information -#define AX25_CONTROL_U_EXHANGE_IDENTIFICATION 0b10101100 // 7 2 exchange ID -#define AX25_CONTROL_U_TEST 0b11100000 // 7 2 test -#define AX25_CONTROL_POLL_FINAL_ENABLED 0b00010000 // 4 4 control field poll/final bit: enabled -#define AX25_CONTROL_POLL_FINAL_DISABLED 0b00000000 // 4 4 disabled -#define AX25_CONTROL_S_RECEIVE_READY 0b00000000 // 3 2 S frame type: receive ready (system ready to receive) -#define AX25_CONTROL_S_RECEIVE_NOT_READY 0b00000100 // 3 2 receive not ready (TNC buffer full) -#define AX25_CONTROL_S_REJECT 0b00001000 // 3 2 reject (out of sequence or duplicate) -#define AX25_CONTROL_S_SELECTIVE_REJECT 0b00001100 // 3 2 selective reject (single frame repeat request) -#define AX25_CONTROL_INFORMATION_FRAME 0b00000000 // 0 0 frame type: information (I frame) -#define AX25_CONTROL_SUPERVISORY_FRAME 0b00000001 // 1 0 supervisory (S frame) -#define AX25_CONTROL_UNNUMBERED_FRAME 0b00000011 // 1 0 unnumbered (U frame) +#define RADIOLIB_AX25_CONTROL_U_SET_ASYNC_BAL_MODE 0b01101100 // 7 2 U frame type: set asynchronous balanced mode (connect request) +#define RADIOLIB_AX25_CONTROL_U_SET_ASYNC_BAL_MODE_EXT 0b00101100 // 7 2 set asynchronous balanced mode extended (connect request with module 128) +#define RADIOLIB_AX25_CONTROL_U_DISCONNECT 0b01000000 // 7 2 disconnect request +#define RADIOLIB_AX25_CONTROL_U_DISCONNECT_MODE 0b00001100 // 7 2 disconnect mode (system busy or disconnected) +#define RADIOLIB_AX25_CONTROL_U_UNNUMBERED_ACK 0b01100000 // 7 2 unnumbered acknowledge +#define RADIOLIB_AX25_CONTROL_U_FRAME_REJECT 0b10000100 // 7 2 frame reject +#define RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION 0b00000000 // 7 2 unnumbered information +#define RADIOLIB_AX25_CONTROL_U_EXHANGE_IDENTIFICATION 0b10101100 // 7 2 exchange ID +#define RADIOLIB_AX25_CONTROL_U_TEST 0b11100000 // 7 2 test +#define RADIOLIB_AX25_CONTROL_POLL_FINAL_ENABLED 0b00010000 // 4 4 control field poll/final bit: enabled +#define RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED 0b00000000 // 4 4 disabled +#define RADIOLIB_AX25_CONTROL_S_RECEIVE_READY 0b00000000 // 3 2 S frame type: receive ready (system ready to receive) +#define RADIOLIB_AX25_CONTROL_S_RECEIVE_NOT_READY 0b00000100 // 3 2 receive not ready (TNC buffer full) +#define RADIOLIB_AX25_CONTROL_S_REJECT 0b00001000 // 3 2 reject (out of sequence or duplicate) +#define RADIOLIB_AX25_CONTROL_S_SELECTIVE_REJECT 0b00001100 // 3 2 selective reject (single frame repeat request) +#define RADIOLIB_AX25_CONTROL_INFORMATION_FRAME 0b00000000 // 0 0 frame type: information (I frame) +#define RADIOLIB_AX25_CONTROL_SUPERVISORY_FRAME 0b00000001 // 1 0 supervisory (S frame) +#define RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME 0b00000011 // 1 0 unnumbered (U frame) // protocol identifier field -#define AX25_PID_ISO_8208 0x01 -#define AX25_PID_TCP_IP_COMPRESSED 0x06 -#define AX25_PID_TCP_IP_UNCOMPRESSED 0x07 -#define AX25_PID_SEGMENTATION_FRAGMENT 0x08 -#define AX25_PID_TEXNET_DATAGRAM_PROTOCOL 0xC3 -#define AX25_PID_LINK_QUALITY_PROTOCOL 0xC4 -#define AX25_PID_APPLETALK 0xCA -#define AX25_PID_APPLETALK_ARP 0xCB -#define AX25_PID_ARPA_INTERNET_PROTOCOL 0xCC -#define AX25_PID_ARPA_ADDRESS_RESOLUTION 0xCD -#define AX25_PID_FLEXNET 0xCE -#define AX25_PID_NET_ROM 0xCF -#define AX25_PID_NO_LAYER_3 0xF0 -#define AX25_PID_ESCAPE_CHARACTER 0xFF +#define RADIOLIB_AX25_PID_ISO_8208 0x01 +#define RADIOLIB_AX25_PID_TCP_IP_COMPRESSED 0x06 +#define RADIOLIB_AX25_PID_TCP_IP_UNCOMPRESSED 0x07 +#define RADIOLIB_AX25_PID_SEGMENTATION_FRAGMENT 0x08 +#define RADIOLIB_AX25_PID_TEXNET_DATAGRAM_PROTOCOL 0xC3 +#define RADIOLIB_AX25_PID_LINK_QUALITY_PROTOCOL 0xC4 +#define RADIOLIB_AX25_PID_APPLETALK 0xCA +#define RADIOLIB_AX25_PID_APPLETALK_ARP 0xCB +#define RADIOLIB_AX25_PID_ARPA_INTERNET_PROTOCOL 0xCC +#define RADIOLIB_AX25_PID_ARPA_ADDRESS_RESOLUTION 0xCD +#define RADIOLIB_AX25_PID_FLEXNET 0xCE +#define RADIOLIB_AX25_PID_NET_ROM 0xCF +#define RADIOLIB_AX25_PID_NO_LAYER_3 0xF0 +#define RADIOLIB_AX25_PID_ESCAPE_CHARACTER 0xFF // AFSK tones in Hz -#define AX25_AFSK_MARK 1200 -#define AX25_AFSK_SPACE 2200 +#define RADIOLIB_AX25_AFSK_MARK 1200 +#define RADIOLIB_AX25_AFSK_SPACE 2200 // tone duration in us (for 1200 baud AFSK) -#define AX25_AFSK_TONE_DURATION 833 +#define RADIOLIB_AX25_AFSK_TONE_DURATION 833 /*! \class AX25Frame @@ -90,7 +90,7 @@ class AX25Frame { /*! \brief Callsign of the destination station. */ - char destCallsign[AX25_MAX_CALLSIGN_LEN + 1]; + char destCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; /*! \brief SSID of the destination station. @@ -100,7 +100,7 @@ class AX25Frame { /*! \brief Callsign of the source station. */ - char srcCallsign[AX25_MAX_CALLSIGN_LEN + 1]; + char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; /*! \brief SSID of the source station. @@ -137,7 +137,7 @@ class AX25Frame { */ uint16_t sendSeqNumber; - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) /*! \brief The info field. */ @@ -161,7 +161,7 @@ class AX25Frame { /*! \brief Array of repeater callsigns. */ - char repeaterCallsigns[8][AX25_MAX_CALLSIGN_LEN + 1]; + char repeaterCallsigns[8][RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; /*! \brief Array of repeater SSIDs. @@ -314,7 +314,7 @@ class AX25Client { \param srcSSID 4-bit SSID of the source station (in case there are more stations with the same callsign). Defaults to 0. - \param preambleLen Number of "preamble" bytes (AX25_FLAG) sent ahead of the actual AX.25 frame. Does not include the first AX25_FLAG byte, which is considered part of the frame. Defaults to 8. + \param preambleLen Number of "preamble" bytes (RADIOLIB_AX25_FLAG) sent ahead of the actual AX.25 frame. Does not include the first RADIOLIB_AX25_FLAG byte, which is considered part of the frame. Defaults to 8. \returns \ref status_codes */ @@ -342,7 +342,7 @@ class AX25Client { */ int16_t sendFrame(AX25Frame* frame); -#ifndef RADIOLIB_GODMODE +#if !defined(ADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; @@ -352,7 +352,7 @@ class AX25Client { uint32_t _afskSpace; #endif - char _srcCallsign[AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; + char _srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; uint8_t _srcSSID = 0; uint16_t _preambleLen = 0; From e82049587b8721747e7ef8d89088cd7092ceb845 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:38:31 +0100 Subject: [PATCH 0039/1848] [CC1101] Update to 5.0.0 --- .../CC1101/CC1101_Receive/CC1101_Receive.ino | 8 +- .../CC1101_Receive_Address.ino | 10 +- .../CC1101_Receive_Interrupt.ino | 8 +- .../CC1101_Settings/CC1101_Settings.ino | 18 +- .../CC1101_Transmit/CC1101_Transmit.ino | 6 +- .../CC1101_Transmit_Address.ino | 10 +- .../CC1101_Transmit_Interrupt.ino | 6 +- src/modules/CC1101/CC1101.cpp | 398 ++++----- src/modules/CC1101/CC1101.h | 800 +++++++++--------- 9 files changed, 633 insertions(+), 631 deletions(-) diff --git a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino index 4ff6235915..e79ba1f0db 100644 --- a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino +++ b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino @@ -36,7 +36,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -58,7 +58,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -77,11 +77,11 @@ void loop() { Serial.print(F("[CC1101] LQI:\t\t")); Serial.println(radio.getLQI()); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino index 81eac67c8c..2f912f081f 100644 --- a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino +++ b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino @@ -34,7 +34,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -51,7 +51,7 @@ void setup() { // 0xFF will be used. Serial.print(F("[CC1101] Setting node address ... ")); state = radio.setNodeAddress(0x01, 1); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void setup() { /* Serial.print(F("[CC1101] Disabling address filtering ... ")); state == radio.disableAddressFiltering(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -88,7 +88,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -107,7 +107,7 @@ void loop() { Serial.print(F("[CC1101] LQI:\t\t")); Serial.println(radio.getLQI()); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index a7228de4af..e52630a557 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -39,7 +39,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -54,7 +54,7 @@ void setup() { // start listening for packets Serial.print(F("[CC1101] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -112,7 +112,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[CC1101] Received packet!")); @@ -131,7 +131,7 @@ void loop() { Serial.print(F("[CC1101] LQI:\t\t")); Serial.println(radio.getLQI()); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino index e724f7b625..b8f8fb2fd9 100644 --- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino +++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -45,7 +45,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio1.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -62,7 +62,7 @@ void setup() { // output power: 7 dBm // preamble length: 32 bits state = radio2.begin(434.0, 32.0, 60.0, 250.0, 7, 32); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -74,42 +74,42 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("[CC1101] Selected frequency is invalid for this module!")); while (true); } // set bit rate to 100.0 kbps state = radio1.setBitRate(100.0); - if (state == ERR_INVALID_BIT_RATE) { + if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { Serial.println(F("[CC1101] Selected bit rate is invalid for this module!")); while (true); - } else if (state == ERR_INVALID_BIT_RATE_BW_RATIO) { + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[CC1101] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[CC1101] Increase receiver bandwidth to set this bit rate.")); while (true); } // set receiver bandwidth to 250.0 kHz - if (radio1.setRxBandwidth(250.0) == ERR_INVALID_RX_BANDWIDTH) { + if (radio1.setRxBandwidth(250.0) == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[CC1101] Selected receiver bandwidth is invalid for this module!")); while (true); } // set allowed frequency deviation to 10.0 kHz - if (radio1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[CC1101] Selected frequency deviation is invalid for this module!")); while (true); } // set output power to 5 dBm - if (radio1.setOutputPower(5) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(5) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[CC1101] Selected output power is invalid for this module!")); while (true); } // 2 bytes can be set as sync word - if (radio1.setSyncWord(0x01, 0x23) == ERR_INVALID_SYNC_WORD) { + if (radio1.setSyncWord(0x01, 0x23) == RADIOLIB_ERR_INVALID_SYNC_WORD) { Serial.println(F("[CC1101] Selected sync word is invalid for this module!")); while (true); } diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino index 3463c6f14f..634dc6b624 100644 --- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino +++ b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino @@ -34,7 +34,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -55,11 +55,11 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 64 bytes Serial.println(F("too long!")); diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index 430eafd864..4aa219d335 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -34,7 +34,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -51,7 +51,7 @@ void setup() { // 0xFF will be used. Serial.print(F("[CC1101] Setting node address ... ")); state = radio.setNodeAddress(0x01, 1); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void setup() { /* Serial.print(F("[CC1101] Disabling address filtering ... ")); state == radio.disableAddressFiltering(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -87,11 +87,11 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 255 bytes Serial.println(F("too long!")); diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index c15652b670..29719ade4d 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -30,7 +30,7 @@ CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); //CC1101 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -38,7 +38,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -95,7 +95,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 0c4a927667..5b6f441f4b 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1,29 +1,33 @@ #include "CC1101.h" #if !defined(RADIOLIB_EXCLUDE_CC1101) -CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_FREQUENCY_STEP_SIZE, CC1101_MAX_PACKET_LENGTH) { +CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) { _mod = module; } +Module* CC1101::getMod() { + return(_mod); +} + int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLength) { // set module properties - _mod->SPIreadCommand = CC1101_CMD_READ; - _mod->SPIwriteCommand = CC1101_CMD_WRITE; - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); + _mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; + _mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); // try to find the CC1101 chip uint8_t i = 0; bool flagFound = false; while((i < 10) && !flagFound) { int16_t version = getChipVersion(); - if((version == CC1101_VERSION_CURRENT) || (version == CC1101_VERSION_LEGACY) || (version == CC1101_VERSION_CLONE)) { + if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { flagFound = true; } else { - #ifdef RADIOLIB_DEBUG + #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINT(F("CC1101 not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) CC1101_REG_VERSION == ")); + RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_CC1101_REG_VERSION == ")); char buffHex[7]; sprintf(buffHex, "0x%04X", version); @@ -31,15 +35,15 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_DEBUG_PRINT(F(", expected 0x0004/0x0014")); RADIOLIB_DEBUG_PRINTLN(); #endif - Module::delay(10); + _mod->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN(F("No CC1101 found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { RADIOLIB_DEBUG_PRINTLN(F("M\tCC1101")); } @@ -89,8 +93,8 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // flush FIFOs - SPIsendCommand(CC1101_CMD_FLUSH_RX); - SPIsendCommand(CC1101_CMD_FLUSH_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); return(state); } @@ -104,26 +108,26 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission start or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); - if(Module::micros() - start > timeout) { + if(_mod->micros() - start > timeout) { standby(); - SPIsendCommand(CC1101_CMD_FLUSH_TX); - return(ERR_TX_TIMEOUT); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + return(RADIOLIB_ERR_TX_TIMEOUT); } } // wait for transmission end or timeout - start = Module::micros(); - while(Module::digitalRead(_mod->getIrq())) { - Module::yield(); + start = _mod->micros(); + while(_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); - if(Module::micros() - start > timeout) { + if(_mod->micros() - start > timeout) { standby(); - SPIsendCommand(CC1101_CMD_FLUSH_TX); - return(ERR_TX_TIMEOUT); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -131,28 +135,28 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { standby(); // flush Tx FIFO - SPIsendCommand(CC1101_CMD_FLUSH_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); return(state); } int16_t CC1101::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full max-length packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(CC1101_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); - if(Module::micros() - start > timeout) { + if(_mod->micros() - start > timeout) { standby(); - SPIsendCommand(CC1101_CMD_FLUSH_TX); - return(ERR_RX_TIMEOUT); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -162,11 +166,11 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { int16_t CC1101::standby() { // set idle mode - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // set RF switch (if present) _mod->setRfSwitchState(LOW, LOW); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t CC1101::transmitDirect(uint32_t frf) { @@ -175,11 +179,11 @@ int16_t CC1101::transmitDirect(uint32_t frf) { // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { - SPIwriteRegister(CC1101_REG_FREQ2, (frf & 0xFF0000) >> 16); - SPIwriteRegister(CC1101_REG_FREQ1, (frf & 0x00FF00) >> 8); - SPIwriteRegister(CC1101_REG_FREQ0, frf & 0x0000FF); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ2, (frf & 0xFF0000) >> 16); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ1, (frf & 0x00FF00) >> 8); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ0, frf & 0x0000FF); - SPIsendCommand(CC1101_CMD_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); } // activate direct mode @@ -187,7 +191,7 @@ int16_t CC1101::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - SPIsendCommand(CC1101_CMD_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); return(state); } @@ -200,98 +204,98 @@ int16_t CC1101::receiveDirect() { RADIOLIB_ASSERT(state); // start receiving - SPIsendCommand(CC1101_CMD_RX); - return(ERR_NONE); + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); + return(RADIOLIB_ERR_NONE); } int16_t CC1101::packetMode() { - int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_CRC_AUTOFLUSH_OFF | CC1101_APPEND_STATUS_ON | CC1101_ADR_CHK_NONE, 3, 0); - state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF | CC1101_PKT_FORMAT_NORMAL, 6, 4); - state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON | _packetLengthConfig, 2, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF | RADIOLIB_CC1101_APPEND_STATUS_ON | RADIOLIB_CC1101_ADR_CHK_NONE, 3, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF | RADIOLIB_CC1101_PKT_FORMAT_NORMAL, 6, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON | _packetLengthConfig, 2, 0); return(state); } void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); } void CC1101::clearGdo0Action() { - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { if(_mod->getGpio() != RADIOLIB_NC) { return; } - Module::pinMode(_mod->getGpio(), INPUT); - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir); + _mod->pinMode(_mod->getGpio(), INPUT); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir); } void CC1101::clearGdo2Action() { if(_mod->getGpio() != RADIOLIB_NC) { return; } - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length - if(len > CC1101_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set mode to standby standby(); // flush Tx FIFO - SPIsendCommand(CC1101_CMD_FLUSH_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); // set GDO0 mapping - int16_t state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED); RADIOLIB_ASSERT(state); // data put on FIFO. uint8_t dataSent = 0; // optionally write packet length - if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) { + if (_packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { // enforce variable len limit. - if (len > CC1101_MAX_PACKET_LENGTH - 1) { - return (ERR_PACKET_TOO_LONG); + if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { + return (RADIOLIB_ERR_PACKET_TOO_LONG); } - SPIwriteRegister(CC1101_REG_FIFO, len); + SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len); dataSent += 1; } // check address filtering - uint8_t filter = SPIgetRegValue(CC1101_REG_PKTCTRL1, 1, 0); - if(filter != CC1101_ADR_CHK_NONE) { - SPIwriteRegister(CC1101_REG_FIFO, addr); + uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); + if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { + SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr); dataSent += 1; } // fill the FIFO. - uint8_t initialWrite = min((uint8_t)len, (uint8_t)(CC1101_FIFO_SIZE - dataSent)); - SPIwriteRegisterBurst(CC1101_REG_FIFO, data, initialWrite); + uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); dataSent += initialWrite; // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); // set mode to transmit - SPIsendCommand(CC1101_CMD_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); // keep feeding the FIFO until the packet is over. while (dataSent < len) { // get number of bytes in FIFO. - uint8_t bytesInFIFO = SPIgetRegValue(CC1101_REG_TXBYTES, 6, 0); + uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); // if there's room then put other data. - if (bytesInFIFO < CC1101_FIFO_SIZE) { - uint8_t bytesToWrite = min((uint8_t)(CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent)); - SPIwriteRegisterBurst(CC1101_REG_FIFO, &data[dataSent], bytesToWrite); + if (bytesInFIFO < RADIOLIB_CC1101_FIFO_SIZE) { + uint8_t bytesToWrite = min((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent)); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, &data[dataSent], bytesToWrite); dataSent += bytesToWrite; } else { // wait for radio to send some data. @@ -313,18 +317,18 @@ int16_t CC1101::startReceive() { standby(); // flush Rx FIFO - SPIsendCommand(CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); // set GDO0 mapping: Asserted when RX FIFO > 4 bytes. - int16_t state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END); - state |= SPIsetRegValue(CC1101_REG_FIFOTHR, CC1101_FIFO_THR_TX_61_RX_4, 3, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4, 3, 0); RADIOLIB_ASSERT(state); // set RF switch (if present) _mod->setRfSwitchState(HIGH, LOW); // set mode to receive - SPIsendCommand(CC1101_CMD_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); return(state); } @@ -332,17 +336,17 @@ int16_t CC1101::startReceive() { int16_t CC1101::readData(uint8_t* data, size_t len) { // get packet length size_t length = len; - if (len == CC1101_MAX_PACKET_LENGTH) { + if (len == RADIOLIB_CC1101_MAX_PACKET_LENGTH) { length = getPacketLength(true); } // check address filtering - uint8_t filter = SPIgetRegValue(CC1101_REG_PKTCTRL1, 1, 0); - if(filter != CC1101_ADR_CHK_NONE) { - SPIreadRegister(CC1101_REG_FIFO); + uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); + if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { + SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); } - uint8_t bytesInFIFO = SPIgetRegValue(CC1101_REG_RXBYTES, 6, 0); + uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); size_t readBytes = 0; uint32_t lastPop = millis(); @@ -361,53 +365,53 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { * TODO: drop this delay(1) or come up with a better solution: */ delay(1); - bytesInFIFO = SPIgetRegValue(CC1101_REG_RXBYTES, 6, 0); + bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); continue; } } // read the minimum between "remaining length" and bytesInFifo uint8_t bytesToRead = min((uint8_t)(length - readBytes), bytesInFIFO); - SPIreadRegisterBurst(CC1101_REG_FIFO, bytesToRead, &(data[readBytes])); + SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, bytesToRead, &(data[readBytes])); readBytes += bytesToRead; lastPop = millis(); // Get how many bytes are left in FIFO. - bytesInFIFO = SPIgetRegValue(CC1101_REG_RXBYTES, 6, 0); + bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); } - // check if status bytes are enabled (default: CC1101_APPEND_STATUS_ON) - bool isAppendStatus = SPIgetRegValue(CC1101_REG_PKTCTRL1, 2, 2) == CC1101_APPEND_STATUS_ON; + // check if status bytes are enabled (default: RADIOLIB_CC1101_APPEND_STATUS_ON) + bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. if (bytesInFIFO >= 2 && isAppendStatus) { // read RSSI byte - _rawRSSI = SPIgetRegValue(CC1101_REG_FIFO); + _rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); // read LQI and CRC byte - uint8_t val = SPIgetRegValue(CC1101_REG_FIFO); + uint8_t val = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); _rawLQI = val & 0x7F; // check CRC - if (_crcOn && (val & CC1101_CRC_OK) == CC1101_CRC_ERROR) { - return (ERR_CRC_MISMATCH); + if (_crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { + return (RADIOLIB_ERR_CRC_MISMATCH); } } // clear internal flag so getPacketLength can return the new packet length _packetLengthQueried = false; - // Flush then standby according to RXOFF_MODE (default: CC1101_RXOFF_IDLE) - if (SPIgetRegValue(CC1101_REG_MCSM1, 3, 2) == CC1101_RXOFF_IDLE) { + // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) + if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { // flush Rx FIFO - SPIsendCommand(CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); // set mode to standby standby(); } - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t CC1101::setFrequency(float freq) { @@ -415,20 +419,20 @@ int16_t CC1101::setFrequency(float freq) { if(!(((freq > 300.0) && (freq < 348.0)) || ((freq > 387.0) && (freq < 464.0)) || ((freq > 779.0) && (freq < 928.0)))) { - return(ERR_INVALID_FREQUENCY); + return(RADIOLIB_ERR_INVALID_FREQUENCY); } // set mode to standby - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); //set carrier frequency uint32_t base = 1; uint32_t FRF = (freq * (base << 16)) / 26.0; - int16_t state = SPIsetRegValue(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0); - state |= SPIsetRegValue(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0); - state |= SPIsetRegValue(CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { _freq = freq; } @@ -437,10 +441,10 @@ int16_t CC1101::setFrequency(float freq) { } int16_t CC1101::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 0.025, 600.0, ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.025, 600.0, RADIOLIB_ERR_INVALID_BIT_RATE); // set mode to standby - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // calculate exponent and mantissa values uint8_t e = 0; @@ -448,32 +452,32 @@ int16_t CC1101::setBitRate(float br) { getExpMant(br * 1000.0, 256, 28, 14, e, m); // set bit rate value - int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG4, e, 3, 0); - state |= SPIsetRegValue(CC1101_REG_MDMCFG3, m); - if(state == ERR_NONE) { + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG3, m); + if(state == RADIOLIB_ERR_NONE) { CC1101::_br = br; } return(state); } int16_t CC1101::setRxBandwidth(float rxBw) { - RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // set mode to standby - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // calculate exponent and mantissa values for(int8_t e = 3; e >= 0; e--) { for(int8_t m = 3; m >= 0; m --) { - float point = (CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); + float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); if((fabs(rxBw * 1000.0) - point) <= 1000) { // set Rx channel filter bandwidth - return(SPIsetRegValue(CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); } } } - return(ERR_INVALID_RX_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } int16_t CC1101::setFrequencyDeviation(float freqDev) { @@ -483,10 +487,10 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { newFreqDev = 1.587; } - RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // set mode to standby - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // calculate exponent and mantissa values uint8_t e = 0; @@ -494,8 +498,8 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { getExpMant(newFreqDev * 1000.0, 8, 17, 7, e, m); // set frequency deviation value - int16_t state = SPIsetRegValue(CC1101_REG_DEVIATN, (e << 4), 6, 4); - state |= SPIsetRegValue(CC1101_REG_DEVIATN, m, 2, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, (e << 4), 6, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, m, 2, 0); return(state); } @@ -553,37 +557,37 @@ int16_t CC1101::setOutputPower(int8_t power) { powerRaw = paTable[7][f]; break; default: - return(ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } // store the value _power = power; - if(_modulation == CC1101_MOD_FORMAT_ASK_OOK){ + if(_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ // Amplitude modulation: // PA_TABLE[0] is the power to be used when transmitting a 0 (no power) // PA_TABLE[1] is the power to be used when transmitting a 1 (full power) uint8_t paValues[2] = {0x00, powerRaw}; - SPIwriteRegisterBurst(CC1101_REG_PATABLE, paValues, 2); - return(ERR_NONE); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2); + return(RADIOLIB_ERR_NONE); } else { // Freq modulation: // PA_TABLE[0] is the power to be used when transmitting. - return(SPIsetRegValue(CC1101_REG_PATABLE, powerRaw)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PATABLE, powerRaw)); } } int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { if((maxErrBits > 1) || (len != 2)) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } // sync word must not contain value 0x00 for(uint8_t i = 0; i < len; i++) { if(syncWord[i] == 0x00) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } } @@ -594,8 +598,8 @@ int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, RADIOLIB_ASSERT(state); // set sync word register - state = SPIsetRegValue(CC1101_REG_SYNC1, syncWord[0]); - state |= SPIsetRegValue(CC1101_REG_SYNC0, syncWord[1]); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_SYNC1, syncWord[0]); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_SYNC0, syncWord[1]); return(state); } @@ -610,82 +614,82 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) { uint8_t value; switch(preambleLength){ case 16: - value = CC1101_NUM_PREAMBLE_2; + value = RADIOLIB_CC1101_NUM_PREAMBLE_2; break; case 24: - value = CC1101_NUM_PREAMBLE_3; + value = RADIOLIB_CC1101_NUM_PREAMBLE_3; break; case 32: - value = CC1101_NUM_PREAMBLE_4; + value = RADIOLIB_CC1101_NUM_PREAMBLE_4; break; case 48: - value = CC1101_NUM_PREAMBLE_6; + value = RADIOLIB_CC1101_NUM_PREAMBLE_6; break; case 64: - value = CC1101_NUM_PREAMBLE_8; + value = RADIOLIB_CC1101_NUM_PREAMBLE_8; break; case 96: - value = CC1101_NUM_PREAMBLE_12; + value = RADIOLIB_CC1101_NUM_PREAMBLE_12; break; case 128: - value = CC1101_NUM_PREAMBLE_16; + value = RADIOLIB_CC1101_NUM_PREAMBLE_16; break; case 192: - value = CC1101_NUM_PREAMBLE_24; + value = RADIOLIB_CC1101_NUM_PREAMBLE_24; break; default: - return(ERR_INVALID_PREAMBLE_LENGTH); + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } - return SPIsetRegValue(CC1101_REG_MDMCFG1, value, 6, 4); + return SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4); } int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { - RADIOLIB_CHECK_RANGE(numBroadcastAddrs, 1, 2, ERR_INVALID_NUM_BROAD_ADDRS); + RADIOLIB_CHECK_RANGE(numBroadcastAddrs, 1, 2, RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS); // enable address filtering - int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, numBroadcastAddrs + 0x01, 1, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, numBroadcastAddrs + 0x01, 1, 0); RADIOLIB_ASSERT(state); // set node address - return(SPIsetRegValue(CC1101_REG_ADDR, nodeAddr)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_ADDR, nodeAddr)); } int16_t CC1101::disableAddressFiltering() { // disable address filtering - int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_ADR_CHK_NONE, 1, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_ADR_CHK_NONE, 1, 0); RADIOLIB_ASSERT(state); // set node address to default (0x00) - return(SPIsetRegValue(CC1101_REG_ADDR, 0x00)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_ADDR, 0x00)); } int16_t CC1101::setOOK(bool enableOOK) { // Change modulation if(enableOOK) { - int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_ASK_OOK, 6, 4); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK, 6, 4); RADIOLIB_ASSERT(state); // PA_TABLE[0] is (by default) the power value used when transmitting a "0". // Set PA_TABLE[1] to be used when transmitting a "1". - state = SPIsetRegValue(CC1101_REG_FREND0, 1, 2, 0); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREND0, 1, 2, 0); RADIOLIB_ASSERT(state); // update current modulation - _modulation = CC1101_MOD_FORMAT_ASK_OOK; + _modulation = RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK; } else { - int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4); RADIOLIB_ASSERT(state); // Reset FREND0 to default value. - state = SPIsetRegValue(CC1101_REG_FREND0, 0, 2, 0); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREND0, 0, 2, 0); RADIOLIB_ASSERT(state); // update current modulation - _modulation = CC1101_MOD_FORMAT_2_FSK; + _modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; } // Update PA_TABLE values according to the new _modulation. @@ -708,10 +712,10 @@ uint8_t CC1101::getLQI() const { size_t CC1101::getPacketLength(bool update) { if(!_packetLengthQueried && update) { - if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) { - _packetLength = SPIreadRegister(CC1101_REG_FIFO); + if (_packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + _packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); } else { - _packetLength = SPIreadRegister(CC1101_REG_PKTLEN); + _packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN); } _packetLengthQueried = true; @@ -721,42 +725,42 @@ size_t CC1101::getPacketLength(bool update) { } int16_t CC1101::fixedPacketLengthMode(uint8_t len) { - return(setPacketMode(CC1101_LENGTH_CONFIG_FIXED, len)); + return(setPacketMode(RADIOLIB_CC1101_LENGTH_CONFIG_FIXED, len)); } int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) { - return(setPacketMode(CC1101_LENGTH_CONFIG_VARIABLE, maxLen)); + return(setPacketMode(RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE, maxLen)); } int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) { switch(maxErrBits){ case 0: // in 16 bit sync word, expect all 16 bits - return(SPIsetRegValue(CC1101_REG_MDMCFG2, (requireCarrierSense ? CC1101_SYNC_MODE_16_16_THR : CC1101_SYNC_MODE_16_16), 2, 0)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_16_16_THR : RADIOLIB_CC1101_SYNC_MODE_16_16), 2, 0)); case 1: // in 16 bit sync word, expect at least 15 bits - return(SPIsetRegValue(CC1101_REG_MDMCFG2, (requireCarrierSense ? CC1101_SYNC_MODE_15_16_THR : CC1101_SYNC_MODE_15_16), 2, 0)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_15_16_THR : RADIOLIB_CC1101_SYNC_MODE_15_16), 2, 0)); default: - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } } int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) { - return(SPIsetRegValue(CC1101_REG_MDMCFG2, (requireCarrierSense ? CC1101_SYNC_MODE_NONE_THR : CC1101_SYNC_MODE_NONE), 2, 0)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_NONE_THR : RADIOLIB_CC1101_SYNC_MODE_NONE), 2, 0)); } int16_t CC1101::setCrcFiltering(bool crcOn) { _crcOn = crcOn; if (crcOn == true) { - return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON, 2, 2)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON, 2, 2)); } else { - return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_OFF, 2, 2)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_OFF, 2, 2)); } } int16_t CC1101::setPromiscuousMode(bool promiscuous) { - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if (_promiscuous == promiscuous) { return(state); @@ -795,13 +799,13 @@ int16_t CC1101::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4); break; case RADIOLIB_SHAPING_0_5: - state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_GFSK, 6, 4); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_GFSK, 6, 4); break; default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } return(state); } @@ -814,19 +818,19 @@ int16_t CC1101::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { case RADIOLIB_ENCODING_NRZ: - state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MANCHESTER_EN_OFF, 3, 3); RADIOLIB_ASSERT(state); - return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF, 6, 6)); case RADIOLIB_ENCODING_MANCHESTER: - state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_ON, 3, 3); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MANCHESTER_EN_ON, 3, 3); RADIOLIB_ASSERT(state); - return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF, 6, 6)); case RADIOLIB_ENCODING_WHITENING: - state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MANCHESTER_EN_OFF, 3, 3); RADIOLIB_ASSERT(state); - return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_ON, 6, 6)); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_ON, 6, 6)); default: - return(ERR_INVALID_ENCODING); + return(RADIOLIB_ERR_INVALID_ENCODING); } } @@ -836,26 +840,26 @@ void CC1101::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { uint8_t CC1101::randomByte() { // set mode to Rx - SPIsendCommand(CC1101_CMD_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); RADIOLIB_DEBUG_PRINTLN("random"); // wait a bit for the RSSI reading to stabilise - Module::delay(10); + _mod->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { - randByte |= ((SPIreadRegister(CC1101_REG_RSSI) & 0x01) << i); + randByte |= ((SPIreadRegister(RADIOLIB_CC1101_REG_RSSI) & 0x01) << i); } // set mode to standby - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); return(randByte); } int16_t CC1101::getChipVersion() { - return(SPIgetRegValue(CC1101_REG_VERSION)); + return(SPIgetRegValue(RADIOLIB_CC1101_REG_VERSION)); } void CC1101::setDirectAction(void (*func)(void)) { @@ -868,13 +872,13 @@ void CC1101::readBit(RADIOLIB_PIN_TYPE pin) { int16_t CC1101::config() { // Reset the radio. Registers may be dirty from previous usage. - SPIsendCommand(CC1101_CMD_RESET); + SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); // Wait a ridiculous amount of time to be sure radio is ready. - Module::delay(150); + _mod->delay(150); // enable automatic frequency synthesizer calibration - int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); RADIOLIB_ASSERT(state); // set packet mode @@ -885,21 +889,21 @@ int16_t CC1101::config() { int16_t CC1101::directMode() { // set mode to standby - SPIsendCommand(CC1101_CMD_IDLE); + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // set GDO0 and GDO2 mapping - int16_t state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SERIAL_CLOCK , 5, 0); - state |= SPIsetRegValue(CC1101_REG_IOCFG2, CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); // set continuous mode - state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); - state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_LENGTH_CONFIG_INFINITE, 1, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); return(state); } void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant) { // get table origin point (exp = 0, mant = 0) - float origin = (mantOffset * CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp); + float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp); // iterate over possible exponent values for(int8_t e = expMax; e >= 0; e--) { @@ -925,16 +929,16 @@ void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8 int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { // check length - if (len > CC1101_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set PKTCTRL0.LENGTH_CONFIG - int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 1, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, mode, 1, 0); RADIOLIB_ASSERT(state); // set length to register - state = SPIsetRegValue(CC1101_REG_PKTLEN, len); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTLEN, len); RADIOLIB_ASSERT(state); // update the cached value @@ -945,8 +949,8 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { // status registers require special command - if(reg > CC1101_REG_TEST0) { - reg |= CC1101_CMD_ACCESS_STATUS_REG; + if(reg > RADIOLIB_CC1101_REG_TEST0) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } return(_mod->SPIgetRegValue(reg, msb, lsb)); @@ -954,21 +958,21 @@ int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval) { // status registers require special command - if(reg > CC1101_REG_TEST0) { - reg |= CC1101_CMD_ACCESS_STATUS_REG; + if(reg > RADIOLIB_CC1101_REG_TEST0) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } return(_mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval)); } void CC1101::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) { - _mod->SPIreadRegisterBurst(reg | CC1101_CMD_BURST, numBytes, inBytes); + _mod->SPIreadRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, numBytes, inBytes); } uint8_t CC1101::SPIreadRegister(uint8_t reg) { // status registers require special command - if(reg > CC1101_REG_TEST0) { - reg |= CC1101_CMD_ACCESS_STATUS_REG; + if(reg > RADIOLIB_CC1101_REG_TEST0) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } return(_mod->SPIreadRegister(reg)); @@ -976,34 +980,30 @@ uint8_t CC1101::SPIreadRegister(uint8_t reg) { void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) { // status registers require special command - if(reg > CC1101_REG_TEST0) { - reg |= CC1101_CMD_ACCESS_STATUS_REG; + if(reg > RADIOLIB_CC1101_REG_TEST0) { + reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } return(_mod->SPIwriteRegister(reg, data)); } void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { - _mod->SPIwriteRegisterBurst(reg | CC1101_CMD_BURST, data, len); + _mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len); } void CC1101::SPIsendCommand(uint8_t cmd) { - // get pointer to used SPI interface and the settings - SPIClass* spi = _mod->getSpi(); - SPISettings spiSettings = _mod->getSpiSettings(); - // pull NSS low - Module::digitalWrite(_mod->getCs(), LOW); + _mod->digitalWrite(_mod->getCs(), LOW); // start transfer - spi->beginTransaction(spiSettings); + _mod->SPIbeginTransaction(); // send the command byte - spi->transfer(cmd); + _mod->SPItransfer(cmd); // stop transfer - spi->endTransaction(); - Module::digitalWrite(_mod->getCs(), HIGH); + _mod->SPIendTransaction(); + _mod->digitalWrite(_mod->getCs(), HIGH); } #endif diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 40c7079143..90c439abbe 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -7,497 +7,497 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // CC1101 physical layer properties -#define CC1101_FREQUENCY_STEP_SIZE 396.7285156 -#define CC1101_MAX_PACKET_LENGTH 255 -#define CC1101_CRYSTAL_FREQ 26.0 -#define CC1101_DIV_EXPONENT 16 -#define CC1101_FIFO_SIZE 64 +#define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 +#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 255 +#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 +#define RADIOLIB_CC1101_DIV_EXPONENT 16 +#define RADIOLIB_CC1101_FIFO_SIZE 64 // CC1101 SPI commands -#define CC1101_CMD_READ 0b10000000 -#define CC1101_CMD_WRITE 0b00000000 -#define CC1101_CMD_BURST 0b01000000 -#define CC1101_CMD_ACCESS_STATUS_REG 0b01000000 -#define CC1101_CMD_FIFO_RX 0b10000000 -#define CC1101_CMD_FIFO_TX 0b00000000 -#define CC1101_CMD_RESET 0x30 -#define CC1101_CMD_FSTXON 0x31 -#define CC1101_CMD_XOFF 0x32 -#define CC1101_CMD_CAL 0x33 -#define CC1101_CMD_RX 0x34 -#define CC1101_CMD_TX 0x35 -#define CC1101_CMD_IDLE 0x36 -#define CC1101_CMD_WOR 0x38 -#define CC1101_CMD_POWER_DOWN 0x39 -#define CC1101_CMD_FLUSH_RX 0x3A -#define CC1101_CMD_FLUSH_TX 0x3B -#define CC1101_CMD_WOR_RESET 0x3C -#define CC1101_CMD_NOP 0x3D +#define RADIOLIB_CC1101_CMD_READ 0b10000000 +#define RADIOLIB_CC1101_CMD_WRITE 0b00000000 +#define RADIOLIB_CC1101_CMD_BURST 0b01000000 +#define RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG 0b01000000 +#define RADIOLIB_CC1101_CMD_FIFO_RX 0b10000000 +#define RADIOLIB_CC1101_CMD_FIFO_TX 0b00000000 +#define RADIOLIB_CC1101_CMD_RESET 0x30 +#define RADIOLIB_CC1101_CMD_FSTXON 0x31 +#define RADIOLIB_CC1101_CMD_XOFF 0x32 +#define RADIOLIB_CC1101_CMD_CAL 0x33 +#define RADIOLIB_CC1101_CMD_RX 0x34 +#define RADIOLIB_CC1101_CMD_TX 0x35 +#define RADIOLIB_CC1101_CMD_IDLE 0x36 +#define RADIOLIB_CC1101_CMD_WOR 0x38 +#define RADIOLIB_CC1101_CMD_POWER_DOWN 0x39 +#define RADIOLIB_CC1101_CMD_FLUSH_RX 0x3A +#define RADIOLIB_CC1101_CMD_FLUSH_TX 0x3B +#define RADIOLIB_CC1101_CMD_WOR_RESET 0x3C +#define RADIOLIB_CC1101_CMD_NOP 0x3D // CC1101 register map -#define CC1101_REG_IOCFG2 0x00 -#define CC1101_REG_IOCFG1 0x01 -#define CC1101_REG_IOCFG0 0x02 -#define CC1101_REG_FIFOTHR 0x03 -#define CC1101_REG_SYNC1 0x04 -#define CC1101_REG_SYNC0 0x05 -#define CC1101_REG_PKTLEN 0x06 -#define CC1101_REG_PKTCTRL1 0x07 -#define CC1101_REG_PKTCTRL0 0x08 -#define CC1101_REG_ADDR 0x09 -#define CC1101_REG_CHANNR 0x0A -#define CC1101_REG_FSCTRL1 0x0B -#define CC1101_REG_FSCTRL0 0x0C -#define CC1101_REG_FREQ2 0x0D -#define CC1101_REG_FREQ1 0x0E -#define CC1101_REG_FREQ0 0x0F -#define CC1101_REG_MDMCFG4 0x10 -#define CC1101_REG_MDMCFG3 0x11 -#define CC1101_REG_MDMCFG2 0x12 -#define CC1101_REG_MDMCFG1 0x13 -#define CC1101_REG_MDMCFG0 0x14 -#define CC1101_REG_DEVIATN 0x15 -#define CC1101_REG_MCSM2 0x16 -#define CC1101_REG_MCSM1 0x17 -#define CC1101_REG_MCSM0 0x18 -#define CC1101_REG_FOCCFG 0x19 -#define CC1101_REG_BSCFG 0x1A -#define CC1101_REG_AGCCTRL2 0x1B -#define CC1101_REG_AGCCTRL1 0x1C -#define CC1101_REG_AGCCTRL0 0x1D -#define CC1101_REG_WOREVT1 0x1E -#define CC1101_REG_WOREVT0 0x1F -#define CC1101_REG_WORCTRL 0x20 -#define CC1101_REG_FREND1 0x21 -#define CC1101_REG_FREND0 0x22 -#define CC1101_REG_FSCAL3 0x23 -#define CC1101_REG_FSCAL2 0x24 -#define CC1101_REG_FSCAL1 0x25 -#define CC1101_REG_FSCAL0 0x26 -#define CC1101_REG_RCCTRL1 0x27 -#define CC1101_REG_RCCTRL0 0x28 -#define CC1101_REG_FSTEST 0x29 -#define CC1101_REG_PTEST 0x2A -#define CC1101_REG_AGCTEST 0x2B -#define CC1101_REG_TEST2 0x2C -#define CC1101_REG_TEST1 0x2D -#define CC1101_REG_TEST0 0x2E -#define CC1101_REG_PARTNUM 0x30 -#define CC1101_REG_VERSION 0x31 -#define CC1101_REG_FREQEST 0x32 -#define CC1101_REG_LQI 0x33 -#define CC1101_REG_RSSI 0x34 -#define CC1101_REG_MARCSTATE 0x35 -#define CC1101_REG_WORTIME1 0x36 -#define CC1101_REG_WORTIME0 0x37 -#define CC1101_REG_PKTSTATUS 0x38 -#define CC1101_REG_VCO_VC_DAC 0x39 -#define CC1101_REG_TXBYTES 0x3A -#define CC1101_REG_RXBYTES 0x3B -#define CC1101_REG_RCCTRL1_STATUS 0x3C -#define CC1101_REG_RCCTRL0_STATUS 0x3D -#define CC1101_REG_PATABLE 0x3E -#define CC1101_REG_FIFO 0x3F +#define RADIOLIB_CC1101_REG_IOCFG2 0x00 +#define RADIOLIB_CC1101_REG_IOCFG1 0x01 +#define RADIOLIB_CC1101_REG_IOCFG0 0x02 +#define RADIOLIB_CC1101_REG_FIFOTHR 0x03 +#define RADIOLIB_CC1101_REG_SYNC1 0x04 +#define RADIOLIB_CC1101_REG_SYNC0 0x05 +#define RADIOLIB_CC1101_REG_PKTLEN 0x06 +#define RADIOLIB_CC1101_REG_PKTCTRL1 0x07 +#define RADIOLIB_CC1101_REG_PKTCTRL0 0x08 +#define RADIOLIB_CC1101_REG_ADDR 0x09 +#define RADIOLIB_CC1101_REG_CHANNR 0x0A +#define RADIOLIB_CC1101_REG_FSCTRL1 0x0B +#define RADIOLIB_CC1101_REG_FSCTRL0 0x0C +#define RADIOLIB_CC1101_REG_FREQ2 0x0D +#define RADIOLIB_CC1101_REG_FREQ1 0x0E +#define RADIOLIB_CC1101_REG_FREQ0 0x0F +#define RADIOLIB_CC1101_REG_MDMCFG4 0x10 +#define RADIOLIB_CC1101_REG_MDMCFG3 0x11 +#define RADIOLIB_CC1101_REG_MDMCFG2 0x12 +#define RADIOLIB_CC1101_REG_MDMCFG1 0x13 +#define RADIOLIB_CC1101_REG_MDMCFG0 0x14 +#define RADIOLIB_CC1101_REG_DEVIATN 0x15 +#define RADIOLIB_CC1101_REG_MCSM2 0x16 +#define RADIOLIB_CC1101_REG_MCSM1 0x17 +#define RADIOLIB_CC1101_REG_MCSM0 0x18 +#define RADIOLIB_CC1101_REG_FOCCFG 0x19 +#define RADIOLIB_CC1101_REG_BSCFG 0x1A +#define RADIOLIB_CC1101_REG_AGCCTRL2 0x1B +#define RADIOLIB_CC1101_REG_AGCCTRL1 0x1C +#define RADIOLIB_CC1101_REG_AGCCTRL0 0x1D +#define RADIOLIB_CC1101_REG_WOREVT1 0x1E +#define RADIOLIB_CC1101_REG_WOREVT0 0x1F +#define RADIOLIB_CC1101_REG_WORCTRL 0x20 +#define RADIOLIB_CC1101_REG_FREND1 0x21 +#define RADIOLIB_CC1101_REG_FREND0 0x22 +#define RADIOLIB_CC1101_REG_FSCAL3 0x23 +#define RADIOLIB_CC1101_REG_FSCAL2 0x24 +#define RADIOLIB_CC1101_REG_FSCAL1 0x25 +#define RADIOLIB_CC1101_REG_FSCAL0 0x26 +#define RADIOLIB_CC1101_REG_RCCTRL1 0x27 +#define RADIOLIB_CC1101_REG_RCCTRL0 0x28 +#define RADIOLIB_CC1101_REG_FSTEST 0x29 +#define RADIOLIB_CC1101_REG_PTEST 0x2A +#define RADIOLIB_CC1101_REG_AGCTEST 0x2B +#define RADIOLIB_CC1101_REG_TEST2 0x2C +#define RADIOLIB_CC1101_REG_TEST1 0x2D +#define RADIOLIB_CC1101_REG_TEST0 0x2E +#define RADIOLIB_CC1101_REG_PARTNUM 0x30 +#define RADIOLIB_CC1101_REG_VERSION 0x31 +#define RADIOLIB_CC1101_REG_FREQEST 0x32 +#define RADIOLIB_CC1101_REG_LQI 0x33 +#define RADIOLIB_CC1101_REG_RSSI 0x34 +#define RADIOLIB_CC1101_REG_MARCSTATE 0x35 +#define RADIOLIB_CC1101_REG_WORTIME1 0x36 +#define RADIOLIB_CC1101_REG_WORTIME0 0x37 +#define RADIOLIB_CC1101_REG_PKTSTATUS 0x38 +#define RADIOLIB_CC1101_REG_VCO_VC_DAC 0x39 +#define RADIOLIB_CC1101_REG_TXBYTES 0x3A +#define RADIOLIB_CC1101_REG_RXBYTES 0x3B +#define RADIOLIB_CC1101_REG_RCCTRL1_STATUS 0x3C +#define RADIOLIB_CC1101_REG_RCCTRL0_STATUS 0x3D +#define RADIOLIB_CC1101_REG_PATABLE 0x3E +#define RADIOLIB_CC1101_REG_FIFO 0x3F // CC1101_REG_IOCFG2 MSB LSB DESCRIPTION -#define CC1101_GDO2_NORM 0b00000000 // 6 6 GDO2 output: active high (default) -#define CC1101_GDO2_INV 0b01000000 // 6 6 active low +#define RADIOLIB_CC1101_GDO2_NORM 0b00000000 // 6 6 GDO2 output: active high (default) +#define RADIOLIB_CC1101_GDO2_INV 0b01000000 // 6 6 active low // CC1101_REG_IOCFG1 -#define CC1101_GDO1_DS_LOW 0b00000000 // 7 7 GDO1 output drive strength: low (default) -#define CC1101_GDO1_DS_HIGH 0b10000000 // 7 7 high -#define CC1101_GDO1_NORM 0b00000000 // 6 6 GDO1 output: active high (default) -#define CC1101_GDO1_INV 0b01000000 // 6 6 active low +#define RADIOLIB_CC1101_GDO1_DS_LOW 0b00000000 // 7 7 GDO1 output drive strength: low (default) +#define RADIOLIB_CC1101_GDO1_DS_HIGH 0b10000000 // 7 7 high +#define RADIOLIB_CC1101_GDO1_NORM 0b00000000 // 6 6 GDO1 output: active high (default) +#define RADIOLIB_CC1101_GDO1_INV 0b01000000 // 6 6 active low // CC1101_REG_IOCFG0 -#define CC1101_GDO0_TEMP_SENSOR_OFF 0b00000000 // 7 7 analog temperature sensor output: disabled (default) -#define CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 0 enabled -#define CC1101_GDO0_NORM 0b00000000 // 6 6 GDO0 output: active high (default) -#define CC1101_GDO0_INV 0b01000000 // 6 6 active low +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_OFF 0b00000000 // 7 7 analog temperature sensor output: disabled (default) +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 0 enabled +#define RADIOLIB_CC1101_GDO0_NORM 0b00000000 // 6 6 GDO0 output: active high (default) +#define RADIOLIB_CC1101_GDO0_INV 0b01000000 // 6 6 active low // CC1101_REG_IOCFG2 + REG_IOCFG1 + REG_IOCFG0 -#define CC1101_GDOX_RX_FIFO_FULL 0x00 // 5 0 Rx FIFO full or above threshold -#define CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END 0x01 // 5 0 Rx FIFO full or above threshold or reached packet end -#define CC1101_GDOX_TX_FIFO_ABOVE_THR 0x02 // 5 0 Tx FIFO above threshold -#define CC1101_GDOX_TX_FIFO_FULL 0x03 // 5 0 Tx FIFO full -#define CC1101_GDOX_RX_FIFO_OVERFLOW 0x04 // 5 0 Rx FIFO overflowed -#define CC1101_GDOX_TX_FIFO_UNDERFLOW 0x05 // 5 0 Tx FIFO underflowed -#define CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED 0x06 // 5 0 sync word was sent or received -#define CC1101_GDOX_PKT_RECEIVED_CRC_OK 0x07 // 5 0 packet received and CRC check passed -#define CC1101_GDOX_PREAMBLE_QUALITY_REACHED 0x08 // 5 0 received preamble quality is above threshold -#define CC1101_GDOX_CHANNEL_CLEAR 0x09 // 5 0 RSSI level below threshold (channel is clear) -#define CC1101_GDOX_PLL_LOCKED 0x0A // 5 0 PLL is locked -#define CC1101_GDOX_SERIAL_CLOCK 0x0B // 5 0 serial data clock -#define CC1101_GDOX_SERIAL_DATA_SYNC 0x0C // 5 0 serial data output in: synchronous mode -#define CC1101_GDOX_SERIAL_DATA_ASYNC 0x0D // 5 0 asynchronous mode -#define CC1101_GDOX_CARRIER_SENSE 0x0E // 5 0 RSSI above threshold -#define CC1101_GDOX_CRC_OK 0x0F // 5 0 CRC check passed -#define CC1101_GDOX_RX_HARD_DATA1 0x16 // 5 0 direct access to demodulated data -#define CC1101_GDOX_RX_HARD_DATA0 0x17 // 5 0 direct access to demodulated data -#define CC1101_GDOX_PA_PD 0x1B // 5 0 power amplifier circuit is powered down -#define CC1101_GDOX_LNA_PD 0x1C // 5 0 low-noise amplifier circuit is powered down -#define CC1101_GDOX_RX_SYMBOL_TICK 0x1D // 5 0 direct access to symbol tick of received data -#define CC1101_GDOX_WOR_EVNT0 0x24 // 5 0 wake-on-radio event 0 -#define CC1101_GDOX_WOR_EVNT1 0x25 // 5 0 wake-on-radio event 1 -#define CC1101_GDOX_CLK_256 0x26 // 5 0 256 Hz clock -#define CC1101_GDOX_CLK_32K 0x27 // 5 0 32 kHz clock -#define CC1101_GDOX_CHIP_RDYN 0x29 // 5 0 (default for GDO2) -#define CC1101_GDOX_XOSC_STABLE 0x2B // 5 0 -#define CC1101_GDOX_HIGH_Z 0x2E // 5 0 high impedance state (default for GDO1) -#define CC1101_GDOX_HW_TO_0 0x2F // 5 0 -#define CC1101_GDOX_CLOCK_XOSC_1 0x30 // 5 0 crystal oscillator clock: f = f(XOSC)/1 -#define CC1101_GDOX_CLOCK_XOSC_1_5 0x31 // 5 0 f = f(XOSC)/1.5 -#define CC1101_GDOX_CLOCK_XOSC_2 0x32 // 5 0 f = f(XOSC)/2 -#define CC1101_GDOX_CLOCK_XOSC_3 0x33 // 5 0 f = f(XOSC)/3 -#define CC1101_GDOX_CLOCK_XOSC_4 0x34 // 5 0 f = f(XOSC)/4 -#define CC1101_GDOX_CLOCK_XOSC_6 0x35 // 5 0 f = f(XOSC)/6 -#define CC1101_GDOX_CLOCK_XOSC_8 0x36 // 5 0 f = f(XOSC)/8 -#define CC1101_GDOX_CLOCK_XOSC_12 0x37 // 5 0 f = f(XOSC)/12 -#define CC1101_GDOX_CLOCK_XOSC_16 0x38 // 5 0 f = f(XOSC)/16 -#define CC1101_GDOX_CLOCK_XOSC_24 0x39 // 5 0 f = f(XOSC)/24 -#define CC1101_GDOX_CLOCK_XOSC_32 0x3A // 5 0 f = f(XOSC)/32 -#define CC1101_GDOX_CLOCK_XOSC_48 0x3B // 5 0 f = f(XOSC)/48 -#define CC1101_GDOX_CLOCK_XOSC_64 0x3C // 5 0 f = f(XOSC)/64 -#define CC1101_GDOX_CLOCK_XOSC_96 0x3D // 5 0 f = f(XOSC)/96 -#define CC1101_GDOX_CLOCK_XOSC_128 0x3E // 5 0 f = f(XOSC)/128 -#define CC1101_GDOX_CLOCK_XOSC_192 0x3F // 5 0 f = f(XOSC)/192 (default for GDO0) +#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL 0x00 // 5 0 Rx FIFO full or above threshold +#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END 0x01 // 5 0 Rx FIFO full or above threshold or reached packet end +#define RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR 0x02 // 5 0 Tx FIFO above threshold +#define RADIOLIB_CC1101_GDOX_TX_FIFO_FULL 0x03 // 5 0 Tx FIFO full +#define RADIOLIB_CC1101_GDOX_RX_FIFO_OVERFLOW 0x04 // 5 0 Rx FIFO overflowed +#define RADIOLIB_CC1101_GDOX_TX_FIFO_UNDERFLOW 0x05 // 5 0 Tx FIFO underflowed +#define RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED 0x06 // 5 0 sync word was sent or received +#define RADIOLIB_CC1101_GDOX_PKT_RECEIVED_CRC_OK 0x07 // 5 0 packet received and CRC check passed +#define RADIOLIB_CC1101_GDOX_PREAMBLE_QUALITY_REACHED 0x08 // 5 0 received preamble quality is above threshold +#define RADIOLIB_CC1101_GDOX_CHANNEL_CLEAR 0x09 // 5 0 RSSI level below threshold (channel is clear) +#define RADIOLIB_CC1101_GDOX_PLL_LOCKED 0x0A // 5 0 PLL is locked +#define RADIOLIB_CC1101_GDOX_SERIAL_CLOCK 0x0B // 5 0 serial data clock +#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC 0x0C // 5 0 serial data output in: synchronous mode +#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC 0x0D // 5 0 asynchronous mode +#define RADIOLIB_CC1101_GDOX_CARRIER_SENSE 0x0E // 5 0 RSSI above threshold +#define RADIOLIB_CC1101_GDOX_CRC_OK 0x0F // 5 0 CRC check passed +#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA1 0x16 // 5 0 direct access to demodulated data +#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA0 0x17 // 5 0 direct access to demodulated data +#define RADIOLIB_CC1101_GDOX_PA_PD 0x1B // 5 0 power amplifier circuit is powered down +#define RADIOLIB_CC1101_GDOX_LNA_PD 0x1C // 5 0 low-noise amplifier circuit is powered down +#define RADIOLIB_CC1101_GDOX_RX_SYMBOL_TICK 0x1D // 5 0 direct access to symbol tick of received data +#define RADIOLIB_CC1101_GDOX_WOR_EVNT0 0x24 // 5 0 wake-on-radio event 0 +#define RADIOLIB_CC1101_GDOX_WOR_EVNT1 0x25 // 5 0 wake-on-radio event 1 +#define RADIOLIB_CC1101_GDOX_CLK_256 0x26 // 5 0 256 Hz clock +#define RADIOLIB_CC1101_GDOX_CLK_32K 0x27 // 5 0 32 kHz clock +#define RADIOLIB_CC1101_GDOX_CHIP_RDYN 0x29 // 5 0 (default for GDO2) +#define RADIOLIB_CC1101_GDOX_XOSC_STABLE 0x2B // 5 0 +#define RADIOLIB_CC1101_GDOX_HIGH_Z 0x2E // 5 0 high impedance state (default for GDO1) +#define RADIOLIB_CC1101_GDOX_HW_TO_0 0x2F // 5 0 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1 0x30 // 5 0 crystal oscillator clock: f = f(XOSC)/1 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1_5 0x31 // 5 0 f = f(XOSC)/1.5 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_2 0x32 // 5 0 f = f(XOSC)/2 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_3 0x33 // 5 0 f = f(XOSC)/3 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_4 0x34 // 5 0 f = f(XOSC)/4 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_6 0x35 // 5 0 f = f(XOSC)/6 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_8 0x36 // 5 0 f = f(XOSC)/8 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_12 0x37 // 5 0 f = f(XOSC)/12 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_16 0x38 // 5 0 f = f(XOSC)/16 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_24 0x39 // 5 0 f = f(XOSC)/24 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_32 0x3A // 5 0 f = f(XOSC)/32 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_48 0x3B // 5 0 f = f(XOSC)/48 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_64 0x3C // 5 0 f = f(XOSC)/64 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_96 0x3D // 5 0 f = f(XOSC)/96 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_128 0x3E // 5 0 f = f(XOSC)/128 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_192 0x3F // 5 0 f = f(XOSC)/192 (default for GDO0) // CC1101_REG_FIFOTHR -#define CC1101_ADC_RETENTION_OFF 0b00000000 // 6 6 do not retain ADC settings in sleep mode (default) -#define CC1101_ADC_RETENTION_ON 0b01000000 // 6 6 retain ADC settings in sleep mode -#define CC1101_RX_ATTEN_0_DB 0b00000000 // 5 4 Rx attenuation: 0 dB (default) -#define CC1101_RX_ATTEN_6_DB 0b00010000 // 5 4 6 dB -#define CC1101_RX_ATTEN_12_DB 0b00100000 // 5 4 12 dB -#define CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB -#define CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4 +#define RADIOLIB_CC1101_ADC_RETENTION_OFF 0b00000000 // 6 6 do not retain ADC settings in sleep mode (default) +#define RADIOLIB_CC1101_ADC_RETENTION_ON 0b01000000 // 6 6 retain ADC settings in sleep mode +#define RADIOLIB_CC1101_RX_ATTEN_0_DB 0b00000000 // 5 4 Rx attenuation: 0 dB (default) +#define RADIOLIB_CC1101_RX_ATTEN_6_DB 0b00010000 // 5 4 6 dB +#define RADIOLIB_CC1101_RX_ATTEN_12_DB 0b00100000 // 5 4 12 dB +#define RADIOLIB_CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB +#define RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4 // CC1101_REG_SYNC1 -#define CC1101_SYNC_WORD_MSB 0xD3 // 7 0 sync word MSB +#define RADIOLIB_CC1101_SYNC_WORD_MSB 0xD3 // 7 0 sync word MSB // CC1101_REG_SYNC0 -#define CC1101_SYNC_WORD_LSB 0x91 // 7 0 sync word LSB +#define RADIOLIB_CC1101_SYNC_WORD_LSB 0x91 // 7 0 sync word LSB // CC1101_REG_PKTLEN -#define CC1101_PACKET_LENGTH 0xFF // 7 0 packet length in bytes +#define RADIOLIB_CC1101_PACKET_LENGTH 0xFF // 7 0 packet length in bytes // CC1101_REG_PKTCTRL1 -#define CC1101_PQT 0x00 // 7 5 preamble quality threshold -#define CC1101_CRC_AUTOFLUSH_OFF 0b00000000 // 3 3 automatic Rx FIFO flush on CRC check fail: disabled (default) -#define CC1101_CRC_AUTOFLUSH_ON 0b00001000 // 3 3 enabled -#define CC1101_APPEND_STATUS_OFF 0b00000000 // 2 2 append 2 status bytes to packet: disabled -#define CC1101_APPEND_STATUS_ON 0b00000100 // 2 2 enabled (default) -#define CC1101_ADR_CHK_NONE 0b00000000 // 1 0 address check: none (default) -#define CC1101_ADR_CHK_NO_BROADCAST 0b00000001 // 1 0 without broadcast -#define CC1101_ADR_CHK_SINGLE_BROADCAST 0b00000010 // 1 0 broadcast address 0x00 -#define CC1101_ADR_CHK_DOUBLE_BROADCAST 0b00000011 // 1 0 broadcast addresses 0x00 and 0xFF +#define RADIOLIB_CC1101_PQT 0x00 // 7 5 preamble quality threshold +#define RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF 0b00000000 // 3 3 automatic Rx FIFO flush on CRC check fail: disabled (default) +#define RADIOLIB_CC1101_CRC_AUTOFLUSH_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_CC1101_APPEND_STATUS_OFF 0b00000000 // 2 2 append 2 status bytes to packet: disabled +#define RADIOLIB_CC1101_APPEND_STATUS_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_CC1101_ADR_CHK_NONE 0b00000000 // 1 0 address check: none (default) +#define RADIOLIB_CC1101_ADR_CHK_NO_BROADCAST 0b00000001 // 1 0 without broadcast +#define RADIOLIB_CC1101_ADR_CHK_SINGLE_BROADCAST 0b00000010 // 1 0 broadcast address 0x00 +#define RADIOLIB_CC1101_ADR_CHK_DOUBLE_BROADCAST 0b00000011 // 1 0 broadcast addresses 0x00 and 0xFF // CC1101_REG_PKTCTRL0 -#define CC1101_WHITE_DATA_OFF 0b00000000 // 6 6 data whitening: disabled -#define CC1101_WHITE_DATA_ON 0b01000000 // 6 6 enabled (default) -#define CC1101_PKT_FORMAT_NORMAL 0b00000000 // 5 4 packet format: normal (FIFOs) -#define CC1101_PKT_FORMAT_SYNCHRONOUS 0b00010000 // 5 4 synchronous serial -#define CC1101_PKT_FORMAT_RANDOM 0b00100000 // 5 4 random transmissions -#define CC1101_PKT_FORMAT_ASYNCHRONOUS 0b00110000 // 5 4 asynchronous serial -#define CC1101_CRC_OFF 0b00000000 // 2 2 CRC disabled -#define CC1101_CRC_ON 0b00000100 // 2 2 CRC enabled (default) -#define CC1101_LENGTH_CONFIG_FIXED 0b00000000 // 1 0 packet length: fixed -#define CC1101_LENGTH_CONFIG_VARIABLE 0b00000001 // 1 0 variable (default) -#define CC1101_LENGTH_CONFIG_INFINITE 0b00000010 // 1 0 infinite +#define RADIOLIB_CC1101_WHITE_DATA_OFF 0b00000000 // 6 6 data whitening: disabled +#define RADIOLIB_CC1101_WHITE_DATA_ON 0b01000000 // 6 6 enabled (default) +#define RADIOLIB_CC1101_PKT_FORMAT_NORMAL 0b00000000 // 5 4 packet format: normal (FIFOs) +#define RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS 0b00010000 // 5 4 synchronous serial +#define RADIOLIB_CC1101_PKT_FORMAT_RANDOM 0b00100000 // 5 4 random transmissions +#define RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS 0b00110000 // 5 4 asynchronous serial +#define RADIOLIB_CC1101_CRC_OFF 0b00000000 // 2 2 CRC disabled +#define RADIOLIB_CC1101_CRC_ON 0b00000100 // 2 2 CRC enabled (default) +#define RADIOLIB_CC1101_LENGTH_CONFIG_FIXED 0b00000000 // 1 0 packet length: fixed +#define RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE 0b00000001 // 1 0 variable (default) +#define RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE 0b00000010 // 1 0 infinite // CC1101_REG_ADDR -#define CC1101_DEVICE_ADDR 0x00 // 7 0 device address +#define RADIOLIB_CC1101_DEVICE_ADDR 0x00 // 7 0 device address // CC1101_REG_CHANNR -#define CC1101_CHAN 0x00 // 7 0 channel number +#define RADIOLIB_CC1101_CHAN 0x00 // 7 0 channel number // CC1101_REG_FSCTRL1 -#define CC1101_FREQ_IF 0x0F // 4 0 IF frequency setting; f_IF = (f(XOSC) / 2^10) * CC1101_FREQ_IF +#define RADIOLIB_CC1101_FREQ_IF 0x0F // 4 0 IF frequency setting; f_IF = (f(XOSC) / 2^10) * CC1101_FREQ_IF // CC1101_REG_FSCTRL0 -#define CC1101_FREQOFF 0x00 // 7 0 base frequency offset (2s-compliment) +#define RADIOLIB_CC1101_FREQOFF 0x00 // 7 0 base frequency offset (2s-compliment) // CC1101_REG_FREQ2 + REG_FREQ1 + REG_FREQ0 -#define CC1101_FREQ_MSB 0x1E // 5 0 base frequency setting: f_carrier = (f(XOSC) / 2^16) * FREQ -#define CC1101_FREQ_MID 0xC4 // 7 0 where f(XOSC) = 26 MHz -#define CC1101_FREQ_LSB 0xEC // 7 0 FREQ = 3-byte value of FREQ registers +#define RADIOLIB_CC1101_FREQ_MSB 0x1E // 5 0 base frequency setting: f_carrier = (f(XOSC) / 2^16) * FREQ +#define RADIOLIB_CC1101_FREQ_MID 0xC4 // 7 0 where f(XOSC) = 26 MHz +#define RADIOLIB_CC1101_FREQ_LSB 0xEC // 7 0 FREQ = 3-byte value of FREQ registers // CC1101_REG_MDMCFG4 -#define CC1101_CHANBW_E 0b10000000 // 7 6 channel bandwidth: BW_channel = f(XOSC) / (8 * (4 + CHANBW_M)*2^CHANBW_E) [Hz] -#define CC1101_CHANBW_M 0b00000000 // 5 4 default value for 26 MHz crystal: 203 125 Hz -#define CC1101_DRATE_E 0x0C // 3 0 symbol rate: R_data = (((256 + DRATE_M) * 2^DRATE_E) / 2^28) * f(XOSC) [Baud] +#define RADIOLIB_CC1101_CHANBW_E 0b10000000 // 7 6 channel bandwidth: BW_channel = f(XOSC) / (8 * (4 + CHANBW_M)*2^CHANBW_E) [Hz] +#define RADIOLIB_CC1101_CHANBW_M 0b00000000 // 5 4 default value for 26 MHz crystal: 203 125 Hz +#define RADIOLIB_CC1101_DRATE_E 0x0C // 3 0 symbol rate: R_data = (((256 + DRATE_M) * 2^DRATE_E) / 2^28) * f(XOSC) [Baud] // CC1101_REG_MDMCFG3 -#define CC1101_DRATE_M 0x22 // 7 0 default value for 26 MHz crystal: 115 051 Baud +#define RADIOLIB_CC1101_DRATE_M 0x22 // 7 0 default value for 26 MHz crystal: 115 051 Baud // CC1101_REG_MDMCFG2 -#define CC1101_DEM_DCFILT_OFF 0b10000000 // 7 7 digital DC filter: disabled -#define CC1101_DEM_DCFILT_ON 0b00000000 // 7 7 enabled - only for data rates above 250 kBaud (default) -#define CC1101_MOD_FORMAT_2_FSK 0b00000000 // 6 4 modulation format: 2-FSK (default) -#define CC1101_MOD_FORMAT_GFSK 0b00010000 // 6 4 GFSK -#define CC1101_MOD_FORMAT_ASK_OOK 0b00110000 // 6 4 ASK/OOK -#define CC1101_MOD_FORMAT_4_FSK 0b01000000 // 6 4 4-FSK -#define CC1101_MOD_FORMAT_MFSK 0b01110000 // 6 4 MFSK - only for data rates above 26 kBaud -#define CC1101_MANCHESTER_EN_OFF 0b00000000 // 3 3 Manchester encoding: disabled (default) -#define CC1101_MANCHESTER_EN_ON 0b00001000 // 3 3 enabled -#define CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble/sync -#define CC1101_SYNC_MODE_15_16 0b00000001 // 2 0 15/16 sync word bits -#define CC1101_SYNC_MODE_16_16 0b00000010 // 2 0 16/16 sync word bits (default) -#define CC1101_SYNC_MODE_30_32 0b00000011 // 2 0 30/32 sync word bits -#define CC1101_SYNC_MODE_NONE_THR 0b00000100 // 2 0 no preamble sync, carrier sense above threshold -#define CC1101_SYNC_MODE_15_16_THR 0b00000101 // 2 0 15/16 sync word bits, carrier sense above threshold -#define CC1101_SYNC_MODE_16_16_THR 0b00000110 // 2 0 16/16 sync word bits, carrier sense above threshold -#define CC1101_SYNC_MODE_30_32_THR 0b00000111 // 2 0 30/32 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_DEM_DCFILT_OFF 0b10000000 // 7 7 digital DC filter: disabled +#define RADIOLIB_CC1101_DEM_DCFILT_ON 0b00000000 // 7 7 enabled - only for data rates above 250 kBaud (default) +#define RADIOLIB_CC1101_MOD_FORMAT_2_FSK 0b00000000 // 6 4 modulation format: 2-FSK (default) +#define RADIOLIB_CC1101_MOD_FORMAT_GFSK 0b00010000 // 6 4 GFSK +#define RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK 0b00110000 // 6 4 ASK/OOK +#define RADIOLIB_CC1101_MOD_FORMAT_4_FSK 0b01000000 // 6 4 4-FSK +#define RADIOLIB_CC1101_MOD_FORMAT_MFSK 0b01110000 // 6 4 MFSK - only for data rates above 26 kBaud +#define RADIOLIB_CC1101_MANCHESTER_EN_OFF 0b00000000 // 3 3 Manchester encoding: disabled (default) +#define RADIOLIB_CC1101_MANCHESTER_EN_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble/sync +#define RADIOLIB_CC1101_SYNC_MODE_15_16 0b00000001 // 2 0 15/16 sync word bits +#define RADIOLIB_CC1101_SYNC_MODE_16_16 0b00000010 // 2 0 16/16 sync word bits (default) +#define RADIOLIB_CC1101_SYNC_MODE_30_32 0b00000011 // 2 0 30/32 sync word bits +#define RADIOLIB_CC1101_SYNC_MODE_NONE_THR 0b00000100 // 2 0 no preamble sync, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_15_16_THR 0b00000101 // 2 0 15/16 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_16_16_THR 0b00000110 // 2 0 16/16 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_30_32_THR 0b00000111 // 2 0 30/32 sync word bits, carrier sense above threshold // CC1101_REG_MDMCFG1 -#define CC1101_FEC_OFF 0b00000000 // 7 7 forward error correction: disabled (default) -#define CC1101_FEC_ON 0b10000000 // 7 7 enabled - only for fixed packet length -#define CC1101_NUM_PREAMBLE_2 0b00000000 // 6 4 number of preamble bytes: 2 -#define CC1101_NUM_PREAMBLE_3 0b00010000 // 6 4 3 -#define CC1101_NUM_PREAMBLE_4 0b00100000 // 6 4 4 (default) -#define CC1101_NUM_PREAMBLE_6 0b00110000 // 6 4 6 -#define CC1101_NUM_PREAMBLE_8 0b01000000 // 6 4 8 -#define CC1101_NUM_PREAMBLE_12 0b01010000 // 6 4 12 -#define CC1101_NUM_PREAMBLE_16 0b01100000 // 6 4 16 -#define CC1101_NUM_PREAMBLE_24 0b01110000 // 6 4 24 -#define CC1101_CHANSPC_E 0x02 // 1 0 channel spacing: df_channel = (f(XOSC) / 2^18) * (256 + CHANSPC_M) * 2^CHANSPC_E [Hz] +#define RADIOLIB_CC1101_FEC_OFF 0b00000000 // 7 7 forward error correction: disabled (default) +#define RADIOLIB_CC1101_FEC_ON 0b10000000 // 7 7 enabled - only for fixed packet length +#define RADIOLIB_CC1101_NUM_PREAMBLE_2 0b00000000 // 6 4 number of preamble bytes: 2 +#define RADIOLIB_CC1101_NUM_PREAMBLE_3 0b00010000 // 6 4 3 +#define RADIOLIB_CC1101_NUM_PREAMBLE_4 0b00100000 // 6 4 4 (default) +#define RADIOLIB_CC1101_NUM_PREAMBLE_6 0b00110000 // 6 4 6 +#define RADIOLIB_CC1101_NUM_PREAMBLE_8 0b01000000 // 6 4 8 +#define RADIOLIB_CC1101_NUM_PREAMBLE_12 0b01010000 // 6 4 12 +#define RADIOLIB_CC1101_NUM_PREAMBLE_16 0b01100000 // 6 4 16 +#define RADIOLIB_CC1101_NUM_PREAMBLE_24 0b01110000 // 6 4 24 +#define RADIOLIB_CC1101_CHANSPC_E 0x02 // 1 0 channel spacing: df_channel = (f(XOSC) / 2^18) * (256 + CHANSPC_M) * 2^CHANSPC_E [Hz] // CC1101_REG_MDMCFG0 -#define CC1101_CHANSPC_M 0xF8 // 7 0 default value for 26 MHz crystal: 199 951 kHz +#define RADIOLIB_CC1101_CHANSPC_M 0xF8 // 7 0 default value for 26 MHz crystal: 199 951 kHz // CC1101_REG_DEVIATN -#define CC1101_DEVIATION_E 0b01000000 // 6 4 frequency deviation: f_dev = (f(XOSC) / 2^17) * (8 + DEVIATION_M) * 2^DEVIATION_E [Hz] -#define CC1101_DEVIATION_M 0b00000111 // 2 0 default value for 26 MHz crystal: +- 47 607 Hz -#define CC1101_MSK_PHASE_CHANGE_PERIOD 0x07 // 2 0 phase change symbol period fraction: 1 / (MSK_PHASE_CHANGE_PERIOD + 1) +#define RADIOLIB_CC1101_DEVIATION_E 0b01000000 // 6 4 frequency deviation: f_dev = (f(XOSC) / 2^17) * (8 + DEVIATION_M) * 2^DEVIATION_E [Hz] +#define RADIOLIB_CC1101_DEVIATION_M 0b00000111 // 2 0 default value for 26 MHz crystal: +- 47 607 Hz +#define RADIOLIB_CC1101_MSK_PHASE_CHANGE_PERIOD 0x07 // 2 0 phase change symbol period fraction: 1 / (MSK_PHASE_CHANGE_PERIOD + 1) // CC1101_REG_MCSM2 -#define CC1101_RX_TIMEOUT_RSSI_OFF 0b00000000 // 4 4 Rx timeout based on RSSI value: disabled (default) -#define CC1101_RX_TIMEOUT_RSSI_ON 0b00010000 // 4 4 enabled -#define CC1101_RX_TIMEOUT_QUAL_OFF 0b00000000 // 3 3 check for sync word on Rx timeout -#define CC1101_RX_TIMEOUT_QUAL_ON 0b00001000 // 3 3 check for PQI set on Rx timeout -#define CC1101_RX_TIMEOUT_OFF 0b00000111 // 2 0 Rx timeout: disabled (default) -#define CC1101_RX_TIMEOUT_MAX 0b00000000 // 2 0 max value (actual value depends on WOR_RES, EVENT0 and f(XOSC)) +#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_OFF 0b00000000 // 4 4 Rx timeout based on RSSI value: disabled (default) +#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_OFF 0b00000000 // 3 3 check for sync word on Rx timeout +#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_ON 0b00001000 // 3 3 check for PQI set on Rx timeout +#define RADIOLIB_CC1101_RX_TIMEOUT_OFF 0b00000111 // 2 0 Rx timeout: disabled (default) +#define RADIOLIB_CC1101_RX_TIMEOUT_MAX 0b00000000 // 2 0 max value (actual value depends on WOR_RES, EVENT0 and f(XOSC)) // CC1101_REG_MCSM1 -#define CC1101_CCA_MODE_ALWAYS 0b00000000 // 5 4 clear channel indication: always -#define CC1101_CCA_MODE_RSSI_THR 0b00010000 // 5 4 RSSI below threshold -#define CC1101_CCA_MODE_RX_PKT 0b00100000 // 5 4 unless receiving packet -#define CC1101_CCA_MODE_RSSI_THR_RX_PKT 0b00110000 // 5 4 RSSI below threshold unless receiving packet (default) -#define CC1101_RXOFF_IDLE 0b00000000 // 3 2 next mode after packet reception: idle (default) -#define CC1101_RXOFF_FSTXON 0b00000100 // 3 2 FSTxOn -#define CC1101_RXOFF_TX 0b00001000 // 3 2 Tx -#define CC1101_RXOFF_RX 0b00001100 // 3 2 Rx -#define CC1101_TXOFF_IDLE 0b00000000 // 1 0 next mode after packet transmission: idle (default) -#define CC1101_TXOFF_FSTXON 0b00000001 // 1 0 FSTxOn -#define CC1101_TXOFF_TX 0b00000010 // 1 0 Tx -#define CC1101_TXOFF_RX 0b00000011 // 1 0 Rx +#define RADIOLIB_CC1101_CCA_MODE_ALWAYS 0b00000000 // 5 4 clear channel indication: always +#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR 0b00010000 // 5 4 RSSI below threshold +#define RADIOLIB_CC1101_CCA_MODE_RX_PKT 0b00100000 // 5 4 unless receiving packet +#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR_RX_PKT 0b00110000 // 5 4 RSSI below threshold unless receiving packet (default) +#define RADIOLIB_CC1101_RXOFF_IDLE 0b00000000 // 3 2 next mode after packet reception: idle (default) +#define RADIOLIB_CC1101_RXOFF_FSTXON 0b00000100 // 3 2 FSTxOn +#define RADIOLIB_CC1101_RXOFF_TX 0b00001000 // 3 2 Tx +#define RADIOLIB_CC1101_RXOFF_RX 0b00001100 // 3 2 Rx +#define RADIOLIB_CC1101_TXOFF_IDLE 0b00000000 // 1 0 next mode after packet transmission: idle (default) +#define RADIOLIB_CC1101_TXOFF_FSTXON 0b00000001 // 1 0 FSTxOn +#define RADIOLIB_CC1101_TXOFF_TX 0b00000010 // 1 0 Tx +#define RADIOLIB_CC1101_TXOFF_RX 0b00000011 // 1 0 Rx // CC1101_REG_MCSM0 -#define CC1101_FS_AUTOCAL_NEVER 0b00000000 // 5 4 automatic calibration: never (default) -#define CC1101_FS_AUTOCAL_IDLE_TO_RXTX 0b00010000 // 5 4 every transition from idle to Rx/Tx -#define CC1101_FS_AUTOCAL_RXTX_TO_IDLE 0b00100000 // 5 4 every transition from Rx/Tx to idle -#define CC1101_FS_AUTOCAL_RXTX_TO_IDLE_4TH 0b00110000 // 5 4 every 4th transition from Rx/Tx to idle -#define CC1101_PO_TIMEOUT_COUNT_1 0b00000000 // 3 2 number of counter expirations before CHP_RDYN goes low: 1 (default) -#define CC1101_PO_TIMEOUT_COUNT_16 0b00000100 // 3 2 16 -#define CC1101_PO_TIMEOUT_COUNT_64 0b00001000 // 3 2 64 -#define CC1101_PO_TIMEOUT_COUNT_256 0b00001100 // 3 2 256 -#define CC1101_PIN_CTRL_OFF 0b00000000 // 1 1 pin radio control: disabled (default) -#define CC1101_PIN_CTRL_ON 0b00000010 // 1 1 enabled -#define CC1101_XOSC_FORCE_OFF 0b00000000 // 0 0 do not force XOSC to remain on in sleep (default) -#define CC1101_XOSC_FORCE_ON 0b00000001 // 0 0 force XOSC to remain on in sleep +#define RADIOLIB_CC1101_FS_AUTOCAL_NEVER 0b00000000 // 5 4 automatic calibration: never (default) +#define RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX 0b00010000 // 5 4 every transition from idle to Rx/Tx +#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE 0b00100000 // 5 4 every transition from Rx/Tx to idle +#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE_4TH 0b00110000 // 5 4 every 4th transition from Rx/Tx to idle +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_1 0b00000000 // 3 2 number of counter expirations before CHP_RDYN goes low: 1 (default) +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_16 0b00000100 // 3 2 16 +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_64 0b00001000 // 3 2 64 +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_256 0b00001100 // 3 2 256 +#define RADIOLIB_CC1101_PIN_CTRL_OFF 0b00000000 // 1 1 pin radio control: disabled (default) +#define RADIOLIB_CC1101_PIN_CTRL_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_CC1101_XOSC_FORCE_OFF 0b00000000 // 0 0 do not force XOSC to remain on in sleep (default) +#define RADIOLIB_CC1101_XOSC_FORCE_ON 0b00000001 // 0 0 force XOSC to remain on in sleep // CC1101_REG_FOCCFG -#define CC1101_FOC_BS_CS_GATE_OFF 0b00000000 // 5 5 do not freeze frequency compensation until CS goes high -#define CC1101_FOC_BS_CS_GATE_ON 0b00100000 // 5 5 freeze frequency compensation until CS goes high (default) -#define CC1101_FOC_PRE_K 0b00000000 // 4 3 frequency compensation loop gain before sync word: K -#define CC1101_FOC_PRE_2K 0b00001000 // 4 3 2K -#define CC1101_FOC_PRE_3K 0b00010000 // 4 3 3K (default) -#define CC1101_FOC_PRE_4K 0b00011000 // 4 3 4K -#define CC1101_FOC_POST_K 0b00000000 // 2 2 frequency compensation loop gain after sync word: same as FOC_PRE -#define CC1101_FOC_POST_K_2 0b00000100 // 2 2 K/2 (default) -#define CC1101_FOC_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 frequency compensation saturation point: no compensation - required for ASK/OOK -#define CC1101_FOC_LIMIT_BW_CHAN_8 0b00000001 // 1 0 +- BW_chan/8 -#define CC1101_FOC_LIMIT_BW_CHAN_4 0b00000010 // 1 0 +- BW_chan/4 (default) -#define CC1101_FOC_LIMIT_BW_CHAN_2 0b00000011 // 1 0 +- BW_chan/2 +#define RADIOLIB_CC1101_FOC_BS_CS_GATE_OFF 0b00000000 // 5 5 do not freeze frequency compensation until CS goes high +#define RADIOLIB_CC1101_FOC_BS_CS_GATE_ON 0b00100000 // 5 5 freeze frequency compensation until CS goes high (default) +#define RADIOLIB_CC1101_FOC_PRE_K 0b00000000 // 4 3 frequency compensation loop gain before sync word: K +#define RADIOLIB_CC1101_FOC_PRE_2K 0b00001000 // 4 3 2K +#define RADIOLIB_CC1101_FOC_PRE_3K 0b00010000 // 4 3 3K (default) +#define RADIOLIB_CC1101_FOC_PRE_4K 0b00011000 // 4 3 4K +#define RADIOLIB_CC1101_FOC_POST_K 0b00000000 // 2 2 frequency compensation loop gain after sync word: same as FOC_PRE +#define RADIOLIB_CC1101_FOC_POST_K_2 0b00000100 // 2 2 K/2 (default) +#define RADIOLIB_CC1101_FOC_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 frequency compensation saturation point: no compensation - required for ASK/OOK +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_8 0b00000001 // 1 0 +- BW_chan/8 +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_4 0b00000010 // 1 0 +- BW_chan/4 (default) +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_2 0b00000011 // 1 0 +- BW_chan/2 // CC1101_REG_BSCFG -#define CC1101_BS_PRE_KI 0b00000000 // 7 6 clock recovery integral gain before sync word: Ki -#define CC1101_BS_PRE_2KI 0b01000000 // 7 6 2Ki (default) -#define CC1101_BS_PRE_3KI 0b10000000 // 7 6 3Ki -#define CC1101_BS_PRE_4KI 0b11000000 // 7 6 4Ki -#define CC1101_BS_PRE_KP 0b00000000 // 5 4 clock recovery proportional gain before sync word: Kp -#define CC1101_BS_PRE_2KP 0b00010000 // 5 4 2Kp -#define CC1101_BS_PRE_3KP 0b00100000 // 5 4 3Kp (default) -#define CC1101_BS_PRE_4KP 0b00110000 // 5 4 4Kp -#define CC1101_BS_POST_KI 0b00000000 // 3 3 clock recovery integral gain after sync word: same as BS_PRE -#define CC1101_BS_POST_KI_2 0b00001000 // 3 3 Ki/2 (default) -#define CC1101_BS_POST_KP 0b00000000 // 2 2 clock recovery proportional gain after sync word: same as BS_PRE -#define CC1101_BS_POST_KP_1 0b00000100 // 2 2 Kp (default) -#define CC1101_BS_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 data rate compensation saturation point: no compensation -#define CC1101_BS_LIMIT_3_125 0b00000001 // 1 0 +- 3.125 % -#define CC1101_BS_LIMIT_6_25 0b00000010 // 1 0 +- 6.25 % -#define CC1101_BS_LIMIT_12_5 0b00000011 // 1 0 +- 12.5 % +#define RADIOLIB_CC1101_BS_PRE_KI 0b00000000 // 7 6 clock recovery integral gain before sync word: Ki +#define RADIOLIB_CC1101_BS_PRE_2KI 0b01000000 // 7 6 2Ki (default) +#define RADIOLIB_CC1101_BS_PRE_3KI 0b10000000 // 7 6 3Ki +#define RADIOLIB_CC1101_BS_PRE_4KI 0b11000000 // 7 6 4Ki +#define RADIOLIB_CC1101_BS_PRE_KP 0b00000000 // 5 4 clock recovery proportional gain before sync word: Kp +#define RADIOLIB_CC1101_BS_PRE_2KP 0b00010000 // 5 4 2Kp +#define RADIOLIB_CC1101_BS_PRE_3KP 0b00100000 // 5 4 3Kp (default) +#define RADIOLIB_CC1101_BS_PRE_4KP 0b00110000 // 5 4 4Kp +#define RADIOLIB_CC1101_BS_POST_KI 0b00000000 // 3 3 clock recovery integral gain after sync word: same as BS_PRE +#define RADIOLIB_CC1101_BS_POST_KI_2 0b00001000 // 3 3 Ki/2 (default) +#define RADIOLIB_CC1101_BS_POST_KP 0b00000000 // 2 2 clock recovery proportional gain after sync word: same as BS_PRE +#define RADIOLIB_CC1101_BS_POST_KP_1 0b00000100 // 2 2 Kp (default) +#define RADIOLIB_CC1101_BS_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 data rate compensation saturation point: no compensation +#define RADIOLIB_CC1101_BS_LIMIT_3_125 0b00000001 // 1 0 +- 3.125 % +#define RADIOLIB_CC1101_BS_LIMIT_6_25 0b00000010 // 1 0 +- 6.25 % +#define RADIOLIB_CC1101_BS_LIMIT_12_5 0b00000011 // 1 0 +- 12.5 % // CC1101_REG_AGCCTRL2 -#define CC1101_MAX_DVGA_GAIN_0 0b00000000 // 7 6 reduce maximum available DVGA gain: no reduction (default) -#define CC1101_MAX_DVGA_GAIN_1 0b01000000 // 7 6 disable top gain setting -#define CC1101_MAX_DVGA_GAIN_2 0b10000000 // 7 6 disable top two gain setting -#define CC1101_MAX_DVGA_GAIN_3 0b11000000 // 7 6 disable top three gain setting -#define CC1101_LNA_GAIN_REDUCE_0_DB 0b00000000 // 5 3 reduce maximum LNA gain by: 0 dB (default) -#define CC1101_LNA_GAIN_REDUCE_2_6_DB 0b00001000 // 5 3 2.6 dB -#define CC1101_LNA_GAIN_REDUCE_6_1_DB 0b00010000 // 5 3 6.1 dB -#define CC1101_LNA_GAIN_REDUCE_7_4_DB 0b00011000 // 5 3 7.4 dB -#define CC1101_LNA_GAIN_REDUCE_9_2_DB 0b00100000 // 5 3 9.2 dB -#define CC1101_LNA_GAIN_REDUCE_11_5_DB 0b00101000 // 5 3 11.5 dB -#define CC1101_LNA_GAIN_REDUCE_14_6_DB 0b00110000 // 5 3 14.6 dB -#define CC1101_LNA_GAIN_REDUCE_17_1_DB 0b00111000 // 5 3 17.1 dB -#define CC1101_MAGN_TARGET_24_DB 0b00000000 // 2 0 average amplitude target for filter: 24 dB -#define CC1101_MAGN_TARGET_27_DB 0b00000001 // 2 0 27 dB -#define CC1101_MAGN_TARGET_30_DB 0b00000010 // 2 0 30 dB -#define CC1101_MAGN_TARGET_33_DB 0b00000011 // 2 0 33 dB (default) -#define CC1101_MAGN_TARGET_36_DB 0b00000100 // 2 0 36 dB -#define CC1101_MAGN_TARGET_38_DB 0b00000101 // 2 0 38 dB -#define CC1101_MAGN_TARGET_40_DB 0b00000110 // 2 0 40 dB -#define CC1101_MAGN_TARGET_42_DB 0b00000111 // 2 0 42 dB +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_0 0b00000000 // 7 6 reduce maximum available DVGA gain: no reduction (default) +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_1 0b01000000 // 7 6 disable top gain setting +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_2 0b10000000 // 7 6 disable top two gain setting +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_3 0b11000000 // 7 6 disable top three gain setting +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_0_DB 0b00000000 // 5 3 reduce maximum LNA gain by: 0 dB (default) +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_2_6_DB 0b00001000 // 5 3 2.6 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_6_1_DB 0b00010000 // 5 3 6.1 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_7_4_DB 0b00011000 // 5 3 7.4 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_9_2_DB 0b00100000 // 5 3 9.2 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_11_5_DB 0b00101000 // 5 3 11.5 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_14_6_DB 0b00110000 // 5 3 14.6 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_17_1_DB 0b00111000 // 5 3 17.1 dB +#define RADIOLIB_CC1101_MAGN_TARGET_24_DB 0b00000000 // 2 0 average amplitude target for filter: 24 dB +#define RADIOLIB_CC1101_MAGN_TARGET_27_DB 0b00000001 // 2 0 27 dB +#define RADIOLIB_CC1101_MAGN_TARGET_30_DB 0b00000010 // 2 0 30 dB +#define RADIOLIB_CC1101_MAGN_TARGET_33_DB 0b00000011 // 2 0 33 dB (default) +#define RADIOLIB_CC1101_MAGN_TARGET_36_DB 0b00000100 // 2 0 36 dB +#define RADIOLIB_CC1101_MAGN_TARGET_38_DB 0b00000101 // 2 0 38 dB +#define RADIOLIB_CC1101_MAGN_TARGET_40_DB 0b00000110 // 2 0 40 dB +#define RADIOLIB_CC1101_MAGN_TARGET_42_DB 0b00000111 // 2 0 42 dB // CC1101_REG_AGCCTRL1 -#define CC1101_AGC_LNA_PRIORITY_LNA2 0b00000000 // 6 6 LNA priority setting: LNA2 first -#define CC1101_AGC_LNA_PRIORITY_LNA 0b01000000 // 6 6 LNA first (default) -#define CC1101_CARRIER_SENSE_REL_THR_OFF 0b00000000 // 5 4 RSSI relative change to assert carrier sense: disabled (default) -#define CC1101_CARRIER_SENSE_REL_THR_6_DB 0b00010000 // 5 4 6 dB -#define CC1101_CARRIER_SENSE_REL_THR_10_DB 0b00100000 // 5 4 10 dB -#define CC1101_CARRIER_SENSE_REL_THR_14_DB 0b00110000 // 5 4 14 dB -#define CC1101_CARRIER_SENSE_ABS_THR 0x00 // 3 0 RSSI threshold to assert carrier sense in 2s compliment, Thr = MAGN_TARGET + CARRIER_SENSE_ABS_TH [dB] +#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA2 0b00000000 // 6 6 LNA priority setting: LNA2 first +#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA 0b01000000 // 6 6 LNA first (default) +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_OFF 0b00000000 // 5 4 RSSI relative change to assert carrier sense: disabled (default) +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_6_DB 0b00010000 // 5 4 6 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_10_DB 0b00100000 // 5 4 10 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_14_DB 0b00110000 // 5 4 14 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_ABS_THR 0x00 // 3 0 RSSI threshold to assert carrier sense in 2s compliment, Thr = MAGN_TARGET + CARRIER_SENSE_ABS_TH [dB] // CC1101_REG_AGCCTRL0 -#define CC1101_HYST_LEVEL_NONE 0b00000000 // 7 6 AGC hysteresis level: none -#define CC1101_HYST_LEVEL_LOW 0b01000000 // 7 6 low -#define CC1101_HYST_LEVEL_MEDIUM 0b10000000 // 7 6 medium (default) -#define CC1101_HYST_LEVEL_HIGH 0b11000000 // 7 6 high -#define CC1101_WAIT_TIME_8_SAMPLES 0b00000000 // 5 4 AGC wait time: 8 samples -#define CC1101_WAIT_TIME_16_SAMPLES 0b00010000 // 5 4 16 samples (default) -#define CC1101_WAIT_TIME_24_SAMPLES 0b00100000 // 5 4 24 samples -#define CC1101_WAIT_TIME_32_SAMPLES 0b00110000 // 5 4 32 samples -#define CC1101_AGC_FREEZE_NEVER 0b00000000 // 3 2 freeze AGC gain: never (default) -#define CC1101_AGC_FREEZE_SYNC_WORD 0b00000100 // 3 2 when sync word is found -#define CC1101_AGC_FREEZE_MANUAL_A 0b00001000 // 3 2 manually freeze analog control -#define CC1101_AGC_FREEZE_MANUAL_AD 0b00001100 // 3 2 manually freeze analog and digital control -#define CC1101_FILTER_LENGTH_8 0b00000000 // 1 0 averaging length for channel filter: 8 samples -#define CC1101_FILTER_LENGTH_16 0b00000001 // 1 0 16 samples (default) -#define CC1101_FILTER_LENGTH_32 0b00000010 // 1 0 32 samples -#define CC1101_FILTER_LENGTH_64 0b00000011 // 1 0 64 samples -#define CC1101_ASK_OOK_BOUNDARY_4_DB 0b00000000 // 1 0 ASK/OOK decision boundary: 4 dB -#define CC1101_ASK_OOK_BOUNDARY_8_DB 0b00000001 // 1 0 8 dB (default) -#define CC1101_ASK_OOK_BOUNDARY_12_DB 0b00000010 // 1 0 12 dB -#define CC1101_ASK_OOK_BOUNDARY_16_DB 0b00000011 // 1 0 16 dB +#define RADIOLIB_CC1101_HYST_LEVEL_NONE 0b00000000 // 7 6 AGC hysteresis level: none +#define RADIOLIB_CC1101_HYST_LEVEL_LOW 0b01000000 // 7 6 low +#define RADIOLIB_CC1101_HYST_LEVEL_MEDIUM 0b10000000 // 7 6 medium (default) +#define RADIOLIB_CC1101_HYST_LEVEL_HIGH 0b11000000 // 7 6 high +#define RADIOLIB_CC1101_WAIT_TIME_8_SAMPLES 0b00000000 // 5 4 AGC wait time: 8 samples +#define RADIOLIB_CC1101_WAIT_TIME_16_SAMPLES 0b00010000 // 5 4 16 samples (default) +#define RADIOLIB_CC1101_WAIT_TIME_24_SAMPLES 0b00100000 // 5 4 24 samples +#define RADIOLIB_CC1101_WAIT_TIME_32_SAMPLES 0b00110000 // 5 4 32 samples +#define RADIOLIB_CC1101_AGC_FREEZE_NEVER 0b00000000 // 3 2 freeze AGC gain: never (default) +#define RADIOLIB_CC1101_AGC_FREEZE_SYNC_WORD 0b00000100 // 3 2 when sync word is found +#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_A 0b00001000 // 3 2 manually freeze analog control +#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_AD 0b00001100 // 3 2 manually freeze analog and digital control +#define RADIOLIB_CC1101_FILTER_LENGTH_8 0b00000000 // 1 0 averaging length for channel filter: 8 samples +#define RADIOLIB_CC1101_FILTER_LENGTH_16 0b00000001 // 1 0 16 samples (default) +#define RADIOLIB_CC1101_FILTER_LENGTH_32 0b00000010 // 1 0 32 samples +#define RADIOLIB_CC1101_FILTER_LENGTH_64 0b00000011 // 1 0 64 samples +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_4_DB 0b00000000 // 1 0 ASK/OOK decision boundary: 4 dB +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_8_DB 0b00000001 // 1 0 8 dB (default) +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_12_DB 0b00000010 // 1 0 12 dB +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_16_DB 0b00000011 // 1 0 16 dB // CC1101_REG_WOREVT1 + REG_WOREVT0 -#define CC1101_EVENT0_TIMEOUT_MSB 0x87 // 7 0 EVENT0 timeout: t_event0 = (750 / f(XOSC)) * EVENT0_TIMEOUT * 2^(5 * WOR_RES) [s] -#define CC1101_EVENT0_TIMEOUT_LSB 0x6B // 7 0 default value for 26 MHz crystal: 1.0 s +#define RADIOLIB_CC1101_EVENT0_TIMEOUT_MSB 0x87 // 7 0 EVENT0 timeout: t_event0 = (750 / f(XOSC)) * EVENT0_TIMEOUT * 2^(5 * WOR_RES) [s] +#define RADIOLIB_CC1101_EVENT0_TIMEOUT_LSB 0x6B // 7 0 default value for 26 MHz crystal: 1.0 s // CC1101_REG_WORCTRL -#define CC1101_RC_POWER_UP 0b00000000 // 7 7 power up RC oscillator -#define CC1101_RC_POWER_DOWN 0b10000000 // 7 7 power down RC oscillator -#define CC1101_EVENT1_TIMEOUT_4 0b00000000 // 6 4 EVENT1 timeout: 4 RC periods -#define CC1101_EVENT1_TIMEOUT_6 0b00010000 // 6 4 6 RC periods -#define CC1101_EVENT1_TIMEOUT_8 0b00100000 // 6 4 8 RC periods -#define CC1101_EVENT1_TIMEOUT_12 0b00110000 // 6 4 12 RC periods -#define CC1101_EVENT1_TIMEOUT_16 0b01000000 // 6 4 16 RC periods -#define CC1101_EVENT1_TIMEOUT_24 0b01010000 // 6 4 24 RC periods -#define CC1101_EVENT1_TIMEOUT_32 0b01100000 // 6 4 32 RC periods -#define CC1101_EVENT1_TIMEOUT_48 0b01110000 // 6 4 48 RC periods (default) -#define CC1101_RC_CAL_OFF 0b00000000 // 3 3 disable RC oscillator calibration -#define CC1101_RC_CAL_ON 0b00001000 // 3 3 enable RC oscillator calibration (default) -#define CC1101_WOR_RES_1 0b00000000 // 1 0 EVENT0 resolution: 1 period (default) -#define CC1101_WOR_RES_2_5 0b00000001 // 1 0 2^5 periods -#define CC1101_WOR_RES_2_10 0b00000010 // 1 0 2^10 periods -#define CC1101_WOR_RES_2_15 0b00000011 // 1 0 2^15 periods +#define RADIOLIB_CC1101_RC_POWER_UP 0b00000000 // 7 7 power up RC oscillator +#define RADIOLIB_CC1101_RC_POWER_DOWN 0b10000000 // 7 7 power down RC oscillator +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_4 0b00000000 // 6 4 EVENT1 timeout: 4 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_6 0b00010000 // 6 4 6 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_8 0b00100000 // 6 4 8 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_12 0b00110000 // 6 4 12 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_16 0b01000000 // 6 4 16 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_24 0b01010000 // 6 4 24 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_32 0b01100000 // 6 4 32 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_48 0b01110000 // 6 4 48 RC periods (default) +#define RADIOLIB_CC1101_RC_CAL_OFF 0b00000000 // 3 3 disable RC oscillator calibration +#define RADIOLIB_CC1101_RC_CAL_ON 0b00001000 // 3 3 enable RC oscillator calibration (default) +#define RADIOLIB_CC1101_WOR_RES_1 0b00000000 // 1 0 EVENT0 resolution: 1 period (default) +#define RADIOLIB_CC1101_WOR_RES_2_5 0b00000001 // 1 0 2^5 periods +#define RADIOLIB_CC1101_WOR_RES_2_10 0b00000010 // 1 0 2^10 periods +#define RADIOLIB_CC1101_WOR_RES_2_15 0b00000011 // 1 0 2^15 periods // CC1101_REG_FREND1 -#define CC1101_LNA_CURRENT 0x01 // 7 6 front-end LNA PTAT current output adjustment -#define CC1101_LNA2MIX_CURRENT 0x01 // 5 4 front-end PTAT output adjustment -#define CC1101_LODIV_BUF_CURRENT_RX 0x01 // 3 2 Rx LO buffer current adjustment -#define CC1101_MIX_CURRENT 0x02 // 1 0 mixer current adjustment +#define RADIOLIB_CC1101_LNA_CURRENT 0x01 // 7 6 front-end LNA PTAT current output adjustment +#define RADIOLIB_CC1101_LNA2MIX_CURRENT 0x01 // 5 4 front-end PTAT output adjustment +#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_RX 0x01 // 3 2 Rx LO buffer current adjustment +#define RADIOLIB_CC1101_MIX_CURRENT 0x02 // 1 0 mixer current adjustment // CC1101_REG_FREND0 -#define CC1101_LODIV_BUF_CURRENT_TX 0x01 // 5 4 Tx LO buffer current adjustment -#define CC1101_PA_POWER 0x00 // 2 0 set power amplifier power according to PATABLE +#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_TX 0x01 // 5 4 Tx LO buffer current adjustment +#define RADIOLIB_CC1101_PA_POWER 0x00 // 2 0 set power amplifier power according to PATABLE // CC1101_REG_FSCAL3 -#define CC1101_CHP_CURR_CAL_OFF 0b00000000 // 5 4 disable charge pump calibration -#define CC1101_CHP_CURR_CAL_ON 0b00100000 // 5 4 enable charge pump calibration (default) -#define CC1101_FSCAL3 0x09 // 3 0 charge pump output current: I_out = I_0 * 2^(FSCAL3/4) [A] +#define RADIOLIB_CC1101_CHP_CURR_CAL_OFF 0b00000000 // 5 4 disable charge pump calibration +#define RADIOLIB_CC1101_CHP_CURR_CAL_ON 0b00100000 // 5 4 enable charge pump calibration (default) +#define RADIOLIB_CC1101_FSCAL3 0x09 // 3 0 charge pump output current: I_out = I_0 * 2^(FSCAL3/4) [A] // CC1101_REG_FSCAL2 -#define CC1101_VCO_CORE_LOW 0b00000000 // 5 5 VCO: low (default) -#define CC1101_VCO_CORE_HIGH 0b00100000 // 5 5 high -#define CC1101_FSCAL2 0x0A // 4 0 VCO current result/override +#define RADIOLIB_CC1101_VCO_CORE_LOW 0b00000000 // 5 5 VCO: low (default) +#define RADIOLIB_CC1101_VCO_CORE_HIGH 0b00100000 // 5 5 high +#define RADIOLIB_CC1101_FSCAL2 0x0A // 4 0 VCO current result/override // CC1101_REG_FSCAL1 -#define CC1101_FSCAL1 0x20 // 5 0 capacitor array setting for coarse VCO tuning +#define RADIOLIB_CC1101_FSCAL1 0x20 // 5 0 capacitor array setting for coarse VCO tuning // CC1101_REG_FSCAL0 -#define CC1101_FSCAL0 0x0D // 6 0 frequency synthesizer calibration setting +#define RADIOLIB_CC1101_FSCAL0 0x0D // 6 0 frequency synthesizer calibration setting // CC1101_REG_RCCTRL1 -#define CC1101_RCCTRL1 0x41 // 6 0 RC oscillator configuration +#define RADIOLIB_CC1101_RCCTRL1 0x41 // 6 0 RC oscillator configuration // CC1101_REG_RCCTRL0 -#define CC1101_RCCTRL0 0x00 // 6 0 RC oscillator configuration +#define RADIOLIB_CC1101_RCCTRL0 0x00 // 6 0 RC oscillator configuration // CC1101_REG_PTEST -#define CC1101_TEMP_SENS_IDLE_OFF 0x7F // 7 0 temperature sensor will not be available in idle mode (default) -#define CC1101_TEMP_SENS_IDLE_ON 0xBF // 7 0 temperature sensor will be available in idle mode +#define RADIOLIB_CC1101_TEMP_SENS_IDLE_OFF 0x7F // 7 0 temperature sensor will not be available in idle mode (default) +#define RADIOLIB_CC1101_TEMP_SENS_IDLE_ON 0xBF // 7 0 temperature sensor will be available in idle mode // CC1101_REG_TEST0 -#define CC1101_VCO_SEL_CAL_OFF 0b00000000 // 1 1 disable VCO selection calibration stage -#define CC1101_VCO_SEL_CAL_ON 0b00000010 // 1 1 enable VCO selection calibration stage +#define RADIOLIB_CC1101_VCO_SEL_CAL_OFF 0b00000000 // 1 1 disable VCO selection calibration stage +#define RADIOLIB_CC1101_VCO_SEL_CAL_ON 0b00000010 // 1 1 enable VCO selection calibration stage // CC1101_REG_PARTNUM -#define CC1101_PARTNUM 0x00 +#define RADIOLIB_CC1101_PARTNUM 0x00 // CC1101_REG_VERSION -#define CC1101_VERSION_CURRENT 0x14 -#define CC1101_VERSION_LEGACY 0x04 -#define CC1101_VERSION_CLONE 0x17 +#define RADIOLIB_CC1101_VERSION_CURRENT 0x14 +#define RADIOLIB_CC1101_VERSION_LEGACY 0x04 +#define RADIOLIB_CC1101_VERSION_CLONE 0x17 // CC1101_REG_MARCSTATE -#define CC1101_MARC_STATE_SLEEP 0x00 // 4 0 main radio control state: sleep -#define CC1101_MARC_STATE_IDLE 0x01 // 4 0 idle -#define CC1101_MARC_STATE_XOFF 0x02 // 4 0 XOFF -#define CC1101_MARC_STATE_VCOON_MC 0x03 // 4 0 VCOON_MC -#define CC1101_MARC_STATE_REGON_MC 0x04 // 4 0 REGON_MC -#define CC1101_MARC_STATE_MANCAL 0x05 // 4 0 MANCAL -#define CC1101_MARC_STATE_VCOON 0x06 // 4 0 VCOON -#define CC1101_MARC_STATE_REGON 0x07 // 4 0 REGON -#define CC1101_MARC_STATE_STARTCAL 0x08 // 4 0 STARTCAL -#define CC1101_MARC_STATE_BWBOOST 0x09 // 4 0 BWBOOST -#define CC1101_MARC_STATE_FS_LOCK 0x0A // 4 0 FS_LOCK -#define CC1101_MARC_STATE_IFADCON 0x0B // 4 0 IFADCON -#define CC1101_MARC_STATE_ENDCAL 0x0C // 4 0 ENDCAL -#define CC1101_MARC_STATE_RX 0x0D // 4 0 RX -#define CC1101_MARC_STATE_RX_END 0x0E // 4 0 RX_END -#define CC1101_MARC_STATE_RX_RST 0x0F // 4 0 RX_RST -#define CC1101_MARC_STATE_TXRX_SWITCH 0x10 // 4 0 TXRX_SWITCH -#define CC1101_MARC_STATE_RXFIFO_OVERFLOW 0x11 // 4 0 RXFIFO_OVERFLOW -#define CC1101_MARC_STATE_FSTXON 0x12 // 4 0 FSTXON -#define CC1101_MARC_STATE_TX 0x13 // 4 0 TX -#define CC1101_MARC_STATE_TX_END 0x14 // 4 0 TX_END -#define CC1101_MARC_STATE_RXTX_SWITCH 0x15 // 4 0 RXTX_SWITCH -#define CC1101_MARC_STATE_TXFIFO_UNDERFLOW 0x16 // 4 0 TXFIFO_UNDERFLOW +#define RADIOLIB_CC1101_MARC_STATE_SLEEP 0x00 // 4 0 main radio control state: sleep +#define RADIOLIB_CC1101_MARC_STATE_IDLE 0x01 // 4 0 idle +#define RADIOLIB_CC1101_MARC_STATE_XOFF 0x02 // 4 0 XOFF +#define RADIOLIB_CC1101_MARC_STATE_VCOON_MC 0x03 // 4 0 VCOON_MC +#define RADIOLIB_CC1101_MARC_STATE_REGON_MC 0x04 // 4 0 REGON_MC +#define RADIOLIB_CC1101_MARC_STATE_MANCAL 0x05 // 4 0 MANCAL +#define RADIOLIB_CC1101_MARC_STATE_VCOON 0x06 // 4 0 VCOON +#define RADIOLIB_CC1101_MARC_STATE_REGON 0x07 // 4 0 REGON +#define RADIOLIB_CC1101_MARC_STATE_STARTCAL 0x08 // 4 0 STARTCAL +#define RADIOLIB_CC1101_MARC_STATE_BWBOOST 0x09 // 4 0 BWBOOST +#define RADIOLIB_CC1101_MARC_STATE_FS_LOCK 0x0A // 4 0 FS_LOCK +#define RADIOLIB_CC1101_MARC_STATE_IFADCON 0x0B // 4 0 IFADCON +#define RADIOLIB_CC1101_MARC_STATE_ENDCAL 0x0C // 4 0 ENDCAL +#define RADIOLIB_CC1101_MARC_STATE_RX 0x0D // 4 0 RX +#define RADIOLIB_CC1101_MARC_STATE_RX_END 0x0E // 4 0 RX_END +#define RADIOLIB_CC1101_MARC_STATE_RX_RST 0x0F // 4 0 RX_RST +#define RADIOLIB_CC1101_MARC_STATE_TXRX_SWITCH 0x10 // 4 0 TXRX_SWITCH +#define RADIOLIB_CC1101_MARC_STATE_RXFIFO_OVERFLOW 0x11 // 4 0 RXFIFO_OVERFLOW +#define RADIOLIB_CC1101_MARC_STATE_FSTXON 0x12 // 4 0 FSTXON +#define RADIOLIB_CC1101_MARC_STATE_TX 0x13 // 4 0 TX +#define RADIOLIB_CC1101_MARC_STATE_TX_END 0x14 // 4 0 TX_END +#define RADIOLIB_CC1101_MARC_STATE_RXTX_SWITCH 0x15 // 4 0 RXTX_SWITCH +#define RADIOLIB_CC1101_MARC_STATE_TXFIFO_UNDERFLOW 0x16 // 4 0 TXFIFO_UNDERFLOW // CC1101_REG_WORTIME1 + REG_WORTIME0 -#define CC1101_WORTIME_MSB 0x00 // 7 0 WOR timer value -#define CC1101_WORTIME_LSB 0x00 // 7 0 +#define RADIOLIB_CC1101_WORTIME_MSB 0x00 // 7 0 WOR timer value +#define RADIOLIB_CC1101_WORTIME_LSB 0x00 // 7 0 // CC1101_REG_PKTSTATUS -#define CC1101_CRC_OK 0b10000000 // 7 7 CRC check passed -#define CC1101_CRC_ERROR 0b00000000 // 7 7 CRC check failed -#define CC1101_CS 0b01000000 // 6 6 carrier sense -#define CC1101_PQT_REACHED 0b00100000 // 5 5 preamble quality reached -#define CC1101_CCA 0b00010000 // 4 4 channel clear -#define CC1101_SFD 0b00001000 // 3 3 start of frame delimiter - sync word received -#define CC1101_GDO2_ACTIVE 0b00000100 // 2 2 GDO2 is active/asserted -#define CC1101_GDO0_ACTIVE 0b00000001 // 0 0 GDO0 is active/asserted +#define RADIOLIB_CC1101_CRC_OK 0b10000000 // 7 7 CRC check passed +#define RADIOLIB_CC1101_CRC_ERROR 0b00000000 // 7 7 CRC check failed +#define RADIOLIB_CC1101_CS 0b01000000 // 6 6 carrier sense +#define RADIOLIB_CC1101_PQT_REACHED 0b00100000 // 5 5 preamble quality reached +#define RADIOLIB_CC1101_CCA 0b00010000 // 4 4 channel clear +#define RADIOLIB_CC1101_SFD 0b00001000 // 3 3 start of frame delimiter - sync word received +#define RADIOLIB_CC1101_GDO2_ACTIVE 0b00000100 // 2 2 GDO2 is active/asserted +#define RADIOLIB_CC1101_GDO0_ACTIVE 0b00000001 // 0 0 GDO0 is active/asserted /*! \class CC1101 @@ -519,6 +519,8 @@ class CC1101: public PhysicalLayer { */ CC1101(Module* module); + Module* getMod(); + // basic methods /*! @@ -799,7 +801,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t fixedPacketLengthMode(uint8_t len = CC1101_MAX_PACKET_LENGTH); + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_CC1101_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. @@ -808,7 +810,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t variablePacketLengthMode(uint8_t maxLen = CC1101_MAX_PACKET_LENGTH); + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_CC1101_MAX_PACKET_LENGTH); /*! \brief Enable sync word filtering and generation. @@ -935,11 +937,11 @@ class CC1101: public PhysicalLayer { float _br = 0; uint8_t _rawRSSI = 0; uint8_t _rawLQI = 0; - uint8_t _modulation = CC1101_MOD_FORMAT_2_FSK; + uint8_t _modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; size_t _packetLength = 0; bool _packetLengthQueried = false; - uint8_t _packetLengthConfig = CC1101_LENGTH_CONFIG_VARIABLE; + uint8_t _packetLengthConfig = RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE; bool _promiscuous = false; bool _crcOn = true; From 727e4b47034012d1ffd8e19bf77bf08b8b157156 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:39:17 +0100 Subject: [PATCH 0040/1848] [FSK4] Update to 5.0.0 --- examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino | 4 ++-- .../FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino | 4 ++-- src/protocols/FSK4/FSK4.cpp | 11 ++++++----- src/protocols/FSK4/FSK4.h | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino index 4f7319bcad..9cd4d40c77 100644 --- a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino +++ b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino @@ -68,7 +68,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -92,7 +92,7 @@ void setup() { // frequency shift: 270 Hz // baud rate: 100 baud state = fsk4.begin(434.0, 270, 100); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino index d3e4007472..f4b4cceacb 100644 --- a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino +++ b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -69,7 +69,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -85,7 +85,7 @@ void setup() { // frequency shift: 270 Hz // baud rate: 100 baud state = fsk4.begin(400, 270, 100); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index d1d4eb8423..5e34c01450 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -28,7 +28,7 @@ int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { // check minimum shift value if(shift < step / 2) { - return(ERR_INVALID_RTTY_SHIFT); + return(RADIOLIB_ERR_INVALID_RTTY_SHIFT); } // round shift to multiples of frequency step size @@ -78,7 +78,7 @@ size_t FSK4Client::write(uint8_t b) { // Modulate FSK4Client::tone(symbol); - + // Shift to next symbol b = b << 2; } @@ -87,10 +87,11 @@ size_t FSK4Client::write(uint8_t b) { } void FSK4Client::tone(uint8_t i) { - uint32_t start = Module::micros(); + Module* mod = _phy->getMod(); + uint32_t start = mod->micros(); transmitDirect(_base + _tones[i], _baseHz + _tonesHz[i]); - while(Module::micros() - start < _bitDuration) { - Module::yield(); + while(mod->micros() - start < _bitDuration) { + mod->yield(); } } diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index 4bd703b1ad..049453bced 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -56,7 +56,7 @@ class FSK4Client { size_t write(uint8_t b); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; From d7701c3ec7d69d1577cffc2296aec2f9f55114a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:39:33 +0100 Subject: [PATCH 0041/1848] [Hell] Update to 5.0.0 --- .../Hellschreiber_Transmit.ino | 4 ++-- .../Hellschreiber_Transmit_AFSK.ino | 4 ++-- src/protocols/Hellschreiber/Hellschreiber.cpp | 17 +++++++++-------- src/protocols/Hellschreiber/Hellschreiber.h | 8 ++++---- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino index edadc5d684..8374da597d 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -49,7 +49,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -62,7 +62,7 @@ void setup() { // base frequency: 434.0 MHz // speed: 122.5 Baud ("Feld Hell") state = hell.begin(434.0); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino index 1938f34ccb..79908b7d37 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -52,7 +52,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void setup() { // AFSK tone frequency: 400 Hz // speed: 122.5 Baud ("Feld Hell") state = hell.begin(400); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 298a44011b..a284eb60c3 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -30,15 +30,16 @@ int16_t HellClient::begin(float base, float rate) { size_t HellClient::printGlyph(uint8_t* buff) { // print the character + Module* mod = _phy->getMod(); for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { - for(int8_t i = HELL_FONT_HEIGHT - 1; i >= 0; i--) { - uint32_t start = Module::micros(); + for(int8_t i = RADIOLIB_HELL_FONT_HEIGHT - 1; i >= 0; i--) { + uint32_t start = mod->micros(); if(buff[i] & mask) { transmitDirect(_base, _baseHz); } else { standby(); } - while(Module::micros() - start < _pixelDuration); + while(mod->micros() - start < _pixelDuration); } } @@ -75,12 +76,12 @@ size_t HellClient::write(uint8_t b) { } // fetch character from flash - uint8_t buff[HELL_FONT_WIDTH]; + uint8_t buff[RADIOLIB_HELL_FONT_WIDTH]; buff[0] = 0x00; - for(uint8_t i = 0; i < HELL_FONT_WIDTH - 2; i++) { - buff[i + 1] = RADIOLIB_PROGMEM_READ_BYTE(&HellFont[pos][i]); + for(uint8_t i = 0; i < RADIOLIB_HELL_FONT_WIDTH - 2; i++) { + buff[i + 1] = RADIOLIB_NONVOLATILE_READ_BYTE(&HellFont[pos][i]); } - buff[HELL_FONT_WIDTH - 1] = 0x00; + buff[RADIOLIB_HELL_FONT_WIDTH - 1] = 0x00; // print the character return(printGlyph(buff)); @@ -90,7 +91,7 @@ size_t HellClient::print(__FlashStringHelper* fstr) { PGM_P p = reinterpret_cast(fstr); size_t n = 0; while(true) { - char c = RADIOLIB_PROGMEM_READ_BYTE(p++); + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); if(c == '\0') { break; } diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 9bebbe627d..9e6913d9ad 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -8,13 +8,13 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" -#define HELL_FONT_WIDTH 7 -#define HELL_FONT_HEIGHT 7 +#define RADIOLIB_HELL_FONT_WIDTH 7 +#define RADIOLIB_HELL_FONT_HEIGHT 7 // font definition: characters are stored in rows, // least significant byte of each character is the first row // Hellschreiber use 7x7 characters, but this simplified font uses only 5x5 - the extra bytes aren't stored -static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] RADIOLIB_PROGMEM = { +static const uint8_t HellFont[64][RADIOLIB_HELL_FONT_WIDTH - 2] RADIOLIB_NONVOLATILE = { { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0000000 }, // space { 0b0001000, 0b0001000, 0b0001000, 0b0000000, 0b0001000 }, // ! { 0b0010100, 0b0010100, 0b0000000, 0b0000000, 0b0000000 }, // " @@ -149,7 +149,7 @@ class HellClient { size_t println(unsigned long, int = DEC); size_t println(double, int = 2); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; From d0670fd9977135f9a35366be48a7137bb7497085 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:39:51 +0100 Subject: [PATCH 0042/1848] [Morse] Update to 5.0.0 --- .../Morse/Morse_Transmit/Morse_Transmit.ino | 4 +- .../Morse_Transmit_AFSK.ino | 4 +- src/protocols/Morse/Morse.cpp | 22 +-- src/protocols/Morse/Morse.h | 148 +++++++++--------- 4 files changed, 90 insertions(+), 88 deletions(-) diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino index 9c39a3b7dd..764fcd55ed 100644 --- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino +++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino @@ -49,7 +49,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -62,7 +62,7 @@ void setup() { // base frequency: 434.0 MHz // speed: 20 words per minute state = morse.begin(434.0); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino b/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino index ad89cb49a5..ac5d284be8 100644 --- a/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino +++ b/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino @@ -52,7 +52,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void setup() { // AFSK tone frequency: 400 MHz // speed: 20 words per minute state = morse.begin(400); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index e23f682e9c..2395562e2a 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -48,6 +48,8 @@ size_t MorseClient::write(uint8_t* buff, size_t len) { } size_t MorseClient::write(uint8_t b) { + Module* mod = _phy->getMod(); + // check unprintable ASCII characters and boundaries if((b < ' ') || (b == 0x60) || (b > 'z')) { return(0); @@ -57,35 +59,35 @@ size_t MorseClient::write(uint8_t b) { if(b == ' ') { RADIOLIB_DEBUG_PRINTLN(F("space")); standby(); - Module::delay(4 * _dotLength); + mod->delay(4 * _dotLength); return(1); } // get morse code from lookup table - uint8_t code = RADIOLIB_PROGMEM_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - 32)]); + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - 32)]); // check unsupported characters - if(code == MORSE_UNSUPORTED) { + if(code == RADIOLIB_MORSE_UNSUPORTED) { return(0); } // iterate through codeword until guard bit is reached - while(code > MORSE_GUARDBIT) { + while(code > RADIOLIB_MORSE_GUARDBIT) { // send dot or dash - if (code & MORSE_DASH) { + if (code & RADIOLIB_MORSE_DASH) { RADIOLIB_DEBUG_PRINT('-'); transmitDirect(_base, _baseHz); - Module::delay(3 * _dotLength); + mod->delay(3 * _dotLength); } else { RADIOLIB_DEBUG_PRINT('.'); transmitDirect(_base, _baseHz); - Module::delay(_dotLength); + mod->delay(_dotLength); } // symbol space standby(); - Module::delay(_dotLength); + mod->delay(_dotLength); // move onto the next bit code >>= 1; @@ -93,7 +95,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); - Module::delay(2 * _dotLength); + mod->delay(2 * _dotLength); RADIOLIB_DEBUG_PRINTLN(); return(1); @@ -103,7 +105,7 @@ size_t MorseClient::print(__FlashStringHelper* fstr) { PGM_P p = reinterpret_cast(fstr); size_t n = 0; while(true) { - char c = RADIOLIB_PROGMEM_READ_BYTE(p++); + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); if(c == '\0') { break; } diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index caeec47ee8..66ead3b910 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -1,84 +1,84 @@ -#if !defined(_RADIOLIB_MORSE_H) && !defined(RADIOLIB_EXCLUDE_MORSE) -#define _RADIOLIB_MORSE_H +#if !defined(_RADIOLIB_RADIOLIB_MORSE_H) && !defined(RADIOLIB_EXCLUDE_MORSE) +#define _RADIOLIB_RADIOLIB_MORSE_H #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" -#define MORSE_DOT 0b0 -#define MORSE_DASH 0b1 -#define MORSE_GUARDBIT 0b1 -#define MORSE_UNSUPORTED 0xFF +#define RADIOLIB_MORSE_DOT 0b0 +#define RADIOLIB_MORSE_DASH 0b1 +#define RADIOLIB_MORSE_GUARDBIT 0b1 +#define RADIOLIB_MORSE_UNSUPORTED 0xFF // Morse character table: - using codes defined in ITU-R M.1677-1 // - Morse code representation is saved LSb first, using additional bit as guard -// - position in array corresponds ASCII code minus MORSE_ASCII_OFFSET -// - ASCII characters marked MORSE_UNSUPORTED do not have ITU-R M.1677-1 equivalent -static const uint8_t MorseTable[] RADIOLIB_PROGMEM = { - 0b00, // space - 0b110101, // ! (unsupported) - 0b1010010, // " - MORSE_UNSUPORTED, // # (unsupported) - MORSE_UNSUPORTED, // $ (unsupported) - MORSE_UNSUPORTED, // % (unsupported) - MORSE_UNSUPORTED, // & (unsupported) - 0b1011110, // ' - 0b101101, // ( - 0b1101101, // ) - MORSE_UNSUPORTED, // * (unsupported) - 0b101010, // + - 0b1110011, // , - 0b1100001, // - - 0b1101010, // . - 0b101001, // / - 0b111111, // 0 - 0b111110, // 1 - 0b111100, // 2 - 0b111000, // 3 - 0b110000, // 4 - 0b100000, // 5 - 0b100001, // 6 - 0b100011, // 7 - 0b100111, // 8 - 0b101111, // 9 - 0b1000111, // : - MORSE_UNSUPORTED, // ; (unsupported) - MORSE_UNSUPORTED, // < (unsupported) - 0b110001, // = - MORSE_UNSUPORTED, // > (unsupported) - 0b1001100, // ? - 0b1010110, // @ - 0b110, // A - 0b10001, // B - 0b10101, // C - 0b1001, // D - 0b10, // E - 0b10100, // F - 0b1011, // G - 0b10000, // H - 0b100, // I - 0b11110, // J - 0b1101, // K - 0b10010, // L - 0b111, // M - 0b101, // N - 0b1111, // O - 0b10110, // P - 0b11011, // Q - 0b1010, // R - 0b1000, // S - 0b11, // T - 0b1100, // U - 0b11000, // V - 0b1110, // W - 0b11001, // X - 0b11101, // Y - 0b10011, // Z - MORSE_UNSUPORTED, // [ (unsupported) - MORSE_UNSUPORTED, // \ (unsupported) - MORSE_UNSUPORTED, // ] (unsupported) - 0b1101000, // ^ (unsupported, used as alias for end of work) - 0b110101 // _ (unsupported, used as alias for starting signal) +// - position in array corresponds ASCII code minus RADIOLIB_MORSE_ASCII_OFFSET +// - ASCII characters marked RADIOLIB_MORSE_UNSUPORTED do not have ITU-R M.1677-1 equivalent +static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { + 0b00, // space + 0b110101, // ! (unsupported) + 0b1010010, // " + RADIOLIB_MORSE_UNSUPORTED, // # (unsupported) + RADIOLIB_MORSE_UNSUPORTED, // $ (unsupported) + RADIOLIB_MORSE_UNSUPORTED, // % (unsupported) + RADIOLIB_MORSE_UNSUPORTED, // & (unsupported) + 0b1011110, // ' + 0b101101, // ( + 0b1101101, // ) + RADIOLIB_MORSE_UNSUPORTED, // * (unsupported) + 0b101010, // + + 0b1110011, // , + 0b1100001, // - + 0b1101010, // . + 0b101001, // / + 0b111111, // 0 + 0b111110, // 1 + 0b111100, // 2 + 0b111000, // 3 + 0b110000, // 4 + 0b100000, // 5 + 0b100001, // 6 + 0b100011, // 7 + 0b100111, // 8 + 0b101111, // 9 + 0b1000111, // : + RADIOLIB_MORSE_UNSUPORTED, // ; (unsupported) + RADIOLIB_MORSE_UNSUPORTED, // < (unsupported) + 0b110001, // = + RADIOLIB_MORSE_UNSUPORTED, // > (unsupported) + 0b1001100, // ? + 0b1010110, // @ + 0b110, // A + 0b10001, // B + 0b10101, // C + 0b1001, // D + 0b10, // E + 0b10100, // F + 0b1011, // G + 0b10000, // H + 0b100, // I + 0b11110, // J + 0b1101, // K + 0b10010, // L + 0b111, // M + 0b101, // N + 0b1111, // O + 0b10110, // P + 0b11011, // Q + 0b1010, // R + 0b1000, // S + 0b11, // T + 0b1100, // U + 0b11000, // V + 0b1110, // W + 0b11001, // X + 0b11101, // Y + 0b10011, // Z + RADIOLIB_MORSE_UNSUPORTED, // [ (unsupported) + RADIOLIB_MORSE_UNSUPORTED, // \ (unsupported) + RADIOLIB_MORSE_UNSUPORTED, // ] (unsupported) + 0b1101000, // ^ (unsupported, used as alias for end of work) + 0b110101 // _ (unsupported, used as alias for starting signal) }; /*! @@ -151,7 +151,7 @@ class MorseClient { size_t println(unsigned long, int = DEC); size_t println(double, int = 2); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; From e775bfc22e788239cc0e7c78101f1169d2977bf5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:40:06 +0100 Subject: [PATCH 0043/1848] [PHY] Update to 5.0.0 --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 32 +++++++++---------- src/protocols/PhysicalLayer/PhysicalLayer.h | 6 ++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 95a399016a..d6aec9f053 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -12,7 +12,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { size_t len = 0; PGM_P p = reinterpret_cast(fstr); while(true) { - char c = RADIOLIB_PROGMEM_READ_BYTE(p++); + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); len++; if(c == '\0') { break; @@ -20,7 +20,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { } // dynamically allocate memory - #ifdef RADIOLIB_STATIC_ONLY + #if defined(RADIOLIB_STATIC_ONLY) char str[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* str = new char[len]; @@ -29,12 +29,12 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { // copy string from flash p = reinterpret_cast(fstr); for(size_t i = 0; i < len; i++) { - str[i] = RADIOLIB_PROGMEM_READ_BYTE(p + i); + str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); } // transmit string int16_t state = transmit(str, addr); - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] str; #endif return(state); @@ -57,7 +57,7 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { } int16_t PhysicalLayer::readData(String& str, size_t len) { - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; // read the number of actually received bytes size_t length = getPacketLength(); @@ -69,19 +69,19 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { } // build a temporary buffer - #ifdef RADIOLIB_STATIC_ONLY + #if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; if(!data) { - return(ERR_MEMORY_ALLOCATION_FAILED); + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } #endif // read the received data state = readData(data, length); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { // add null terminator data[length] = 0; @@ -90,7 +90,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { } // deallocate temporary buffer - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] data; #endif @@ -98,7 +98,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { } int16_t PhysicalLayer::receive(String& str, size_t len) { - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; // user can override the length of data to read size_t length = len; @@ -109,19 +109,19 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { } // build a temporary buffer - #ifdef RADIOLIB_STATIC_ONLY + #if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; if(!data) { - return(ERR_MEMORY_ALLOCATION_FAILED); + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } #endif // attempt packet reception state = receive(data, length); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { // read the number of actually received bytes (for unknown packets) if(len == 0) { length = getPacketLength(false); @@ -135,7 +135,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { } // deallocate temporary buffer - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] data; #endif @@ -203,7 +203,7 @@ uint8_t PhysicalLayer::read() { int16_t PhysicalLayer::setDirectSyncWord(uint32_t syncWord, uint8_t len) { if(len > 32) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } _directSyncWordMask = 0xFFFFFFFF >> (32 - len); _directSyncWordLen = len; @@ -214,7 +214,7 @@ int16_t PhysicalLayer::setDirectSyncWord(uint32_t syncWord, uint8_t len) { _gotSync = true; } - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } void PhysicalLayer::updateDirectBuffer(uint8_t bit) { diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 8b91d53052..0245b8f450 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -1,4 +1,4 @@ -#ifndef _RADIOLIB_PHYSICAL_LAYER_H +#if !defined(_RADIOLIB_PHYSICAL_LAYER_H) #define _RADIOLIB_PHYSICAL_LAYER_H #include "../../TypeDef.h" @@ -298,10 +298,12 @@ class PhysicalLayer { */ uint8_t read(); + virtual Module* getMod() = 0; + protected: void updateDirectBuffer(uint8_t bit); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif float _freqStep; From 008187b0b1bf2c75cdaf407d2a1c77aa6d530013 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:40:31 +0100 Subject: [PATCH 0044/1848] [RF69] Update to 5.0.0 --- examples/RF69/RF69_Receive/RF69_Receive.ino | 8 +- .../RF69_Receive_AES/RF69_Receive_AES.ino | 8 +- .../RF69_Receive_Address.ino | 14 +- .../RF69_Receive_Interrupt.ino | 8 +- examples/RF69/RF69_Settings/RF69_Settings.ino | 20 +- examples/RF69/RF69_Transmit/RF69_Transmit.ino | 8 +- .../RF69_Transmit_AES/RF69_Transmit_AES.ino | 6 +- .../RF69_Transmit_Address.ino | 12 +- .../RF69_Transmit_Interrupt.ino | 8 +- src/modules/RF69/RF69.cpp | 418 +++++------ src/modules/RF69/RF69.h | 676 +++++++++--------- 11 files changed, 596 insertions(+), 590 deletions(-) diff --git a/examples/RF69/RF69_Receive/RF69_Receive.ino b/examples/RF69/RF69_Receive/RF69_Receive.ino index fd9247557b..f38dcc44fb 100644 --- a/examples/RF69/RF69_Receive/RF69_Receive.ino +++ b/examples/RF69/RF69_Receive/RF69_Receive.ino @@ -35,7 +35,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -57,7 +57,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -71,11 +71,11 @@ void loop() { Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino index c1fa2816b0..8ca312129b 100644 --- a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino +++ b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino @@ -31,7 +31,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -67,7 +67,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -75,11 +75,11 @@ void loop() { Serial.print(F("[RF69] Data:\t\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino index df20200c8d..c6127995b4 100644 --- a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino +++ b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino @@ -33,7 +33,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -46,7 +46,7 @@ void setup() { // address filtering (node address only) Serial.print(F("[RF69] Setting node address ... ")); state = radio.setNodeAddress(0x02); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -59,7 +59,7 @@ void setup() { // address filtering (node or broadcast address) Serial.print(F("[RF69] Setting broadcast address ... ")); state = radio.setBroadcastAddress(0xFF); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -73,7 +73,7 @@ void setup() { /* Serial.print(F("[RF69] Disabling address filtering ... ")); state == radio.disableAddressFiltering(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -96,7 +96,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -104,11 +104,11 @@ void loop() { Serial.print(F("[RF69] Data:\t\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 2a512783a4..12d5de5db8 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -31,7 +31,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -46,7 +46,7 @@ void setup() { // start listening for packets Serial.print(F("[RF69] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -104,7 +104,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[RF69] Received packet!")); @@ -118,7 +118,7 @@ void loop() { Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/RF69/RF69_Settings/RF69_Settings.ino b/examples/RF69/RF69_Settings/RF69_Settings.ino index f936ee2e68..23626c2df9 100644 --- a/examples/RF69/RF69_Settings/RF69_Settings.ino +++ b/examples/RF69/RF69_Settings/RF69_Settings.ino @@ -43,7 +43,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio1.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -60,7 +60,7 @@ void setup() { // output power: 17 dBm // preamble length: 32 bits state = radio2.begin(868.0, 300.0, 60.0, 250.0, 17, 32); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -72,17 +72,17 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("[RF69] Selected frequency is invalid for this module!")); while (true); } // set bit rate to 100.0 kbps state = radio1.setBitRate(100.0); - if (state == ERR_INVALID_BIT_RATE) { + if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { Serial.println(F("[RF69] Selected bit rate is invalid for this module!")); while (true); - } else if (state == ERR_INVALID_BIT_RATE_BW_RATIO) { + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[RF69] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[RF69] Increase receiver bandwidth to set this bit rate.")); while (true); @@ -90,23 +90,23 @@ void setup() { // set receiver bandwidth to 250.0 kHz state = radio1.setRxBandwidth(250.0); - if (state == ERR_INVALID_RX_BANDWIDTH) { + if (state == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[RF69] Selected receiver bandwidth is invalid for this module!")); while (true); - } else if (state == ERR_INVALID_BIT_RATE_BW_RATIO) { + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[RF69] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[RF69] Decrease bit rate to set this receiver bandwidth.")); while (true); } // set allowed frequency deviation to 10.0 kHz - if (radio1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[RF69] Selected frequency deviation is invalid for this module!")); while (true); } // set output power to 2 dBm - if (radio1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[RF69] Selected output power is invalid for this module!")); while (true); } @@ -115,7 +115,7 @@ void setup() { // NOTE: sync word must not contain any zero bytes // set sync word to 0x0123456789ABCDEF uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - if (radio1.setSyncWord(syncWord, 8) == ERR_INVALID_SYNC_WORD) { + if (radio1.setSyncWord(syncWord, 8) == RADIOLIB_ERR_INVALID_SYNC_WORD) { Serial.println(F("[RF69] Selected sync word is invalid for this module!")); while (true); } diff --git a/examples/RF69/RF69_Transmit/RF69_Transmit.ino b/examples/RF69/RF69_Transmit/RF69_Transmit.ino index c57122b2f8..8c6866d662 100644 --- a/examples/RF69/RF69_Transmit/RF69_Transmit.ino +++ b/examples/RF69/RF69_Transmit/RF69_Transmit.ino @@ -33,7 +33,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -49,7 +49,7 @@ void setup() { /* Serial.print(F("[RF69] Setting high power module ... ")); state = radio.setOutputPower(20, true); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -71,11 +71,11 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 64 bytes Serial.println(F("too long!")); diff --git a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino index d5bc2de27e..48c9057761 100644 --- a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino +++ b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino @@ -31,7 +31,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -66,11 +66,11 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 64 bytes Serial.println(F("too long!")); diff --git a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino index 5f91e1f621..e9b1fba163 100644 --- a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino +++ b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino @@ -33,7 +33,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -46,7 +46,7 @@ void setup() { // address filtering (node address only) Serial.print(F("[RF69] Setting node address ... ")); state = radio.setNodeAddress(0x01); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -59,7 +59,7 @@ void setup() { // address filtering (node or broadcast address) Serial.print(F("[RF69] Setting broadcast address ... ")); state = radio.setBroadcastAddress(0xFF); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -73,7 +73,7 @@ void setup() { /* Serial.print(F("[RF69] Disabling address filtering ... ")); state = radio.disableAddressFiltering(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -106,11 +106,11 @@ void loop() { int state = radio.transmit(byteArr, 8, 0xFF); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 64 bytes Serial.println(F("too long!")); diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 0f03dad12d..eb54a54141 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -29,7 +29,7 @@ RF69 radio = new Module(10, 2, 3); //RF69 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -37,7 +37,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -57,7 +57,7 @@ void setup() { /* Serial.print(F("[RF69] Setting high power module ... ")); state = radio.setOutputPower(20, true); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -111,7 +111,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 9b96143a57..d8bf3ce8dc 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -1,14 +1,18 @@ #include "RF69.h" #if !defined(RADIOLIB_EXCLUDE_RF69) -RF69::RF69(Module* module) : PhysicalLayer(RF69_FREQUENCY_STEP_SIZE, RF69_MAX_PACKET_LENGTH) { +RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) { _mod = module; } +Module* RF69::getMod() { + return(_mod); +} + int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); // try to find the RF69 chip uint8_t i = 0; @@ -19,13 +23,13 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe // check version register int16_t version = getChipVersion(); - if(version == RF69_CHIP_VERSION) { + if(version == RADIOLIB_RF69_CHIP_VERSION) { flagFound = true; } else { - #ifdef RADIOLIB_DEBUG + #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINT(F("RF69 not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RF69_REG_VERSION == ")); + RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_RF69_REG_VERSION == ")); char buffHex[7]; sprintf(buffHex, "0x%04X", version); @@ -33,15 +37,15 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_DEBUG_PRINT(F(", expected 0x0024")); RADIOLIB_DEBUG_PRINTLN(); #endif - Module::delay(10); + _mod->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN(F("No RF69 found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { RADIOLIB_DEBUG_PRINTLN(F("M\tRF69")); } @@ -100,11 +104,11 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe } void RF69::reset() { - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), HIGH); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(10); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), LOW); + _mod->delay(10); } int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -116,14 +120,14 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); - if(Module::micros() - start > timeout) { + if(_mod->micros() - start > timeout) { standby(); clearIRQFlags(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -133,26 +137,26 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { // clear interrupt flags clearIRQFlags(); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t RF69::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RF69_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); - if(Module::micros() - start > timeout) { + if(_mod->micros() - start > timeout) { standby(); clearIRQFlags(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -165,7 +169,7 @@ int16_t RF69::sleep() { _mod->setRfSwitchState(LOW, LOW); // set module to sleep - return(setMode(RF69_SLEEP)); + return(setMode(RADIOLIB_RF69_SLEEP)); } int16_t RF69::standby() { @@ -173,7 +177,7 @@ int16_t RF69::standby() { _mod->setRfSwitchState(LOW, LOW); // set module to standby - return(setMode(RF69_STANDBY)); + return(setMode(RADIOLIB_RF69_STANDBY)); } int16_t RF69::transmitDirect(uint32_t frf) { @@ -182,11 +186,11 @@ int16_t RF69::transmitDirect(uint32_t frf) { // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { - _mod->SPIwriteRegister(RF69_REG_FRF_MSB, (frf & 0xFF0000) >> 16); - _mod->SPIwriteRegister(RF69_REG_FRF_MID, (frf & 0x00FF00) >> 8); - _mod->SPIwriteRegister(RF69_REG_FRF_LSB, frf & 0x0000FF); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (frf & 0x00FF00) >> 8); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, frf & 0x0000FF); - return(setMode(RF69_TX)); + return(setMode(RADIOLIB_RF69_TX)); } // activate direct mode @@ -194,7 +198,7 @@ int16_t RF69::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - return(setMode(RF69_TX)); + return(setMode(RADIOLIB_RF69_TX)); } int16_t RF69::receiveDirect() { @@ -206,47 +210,47 @@ int16_t RF69::receiveDirect() { RADIOLIB_ASSERT(state); // start receiving - return(setMode(RF69_RX)); + return(setMode(RADIOLIB_RF69_RX)); } int16_t RF69::directMode() { // set mode to standby - int16_t state = setMode(RF69_STANDBY); + int16_t state = setMode(RADIOLIB_RF69_STANDBY); RADIOLIB_ASSERT(state); // set DIO mapping - state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO1_CONT_DCLK | RF69_DIO2_CONT_DATA, 5, 2); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_CONT_DCLK | RADIOLIB_RF69_DIO2_CONT_DATA, 5, 2); RADIOLIB_ASSERT(state); // set continuous mode - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); } int16_t RF69::packetMode() { - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_PACKET_MODE, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE, 6, 5)); } void RF69::setAESKey(uint8_t* key) { - _mod->SPIwriteRegisterBurst(RF69_REG_AES_KEY_1, key, 16); + _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_AES_KEY_1, key, 16); } int16_t RF69::enableAES() { - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AES_ON, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_ON, 0, 0)); } int16_t RF69::disableAES() { - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AES_OFF, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_OFF, 0, 0)); } int16_t RF69::startReceive() { // set mode to standby - int16_t state = setMode(RF69_STANDBY); + int16_t state = setMode(RADIOLIB_RF69_STANDBY); RADIOLIB_ASSERT(state); // set RX timeouts and DIO pin mapping - state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 7, 4); - state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START); - state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY, 7, 4); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -256,75 +260,75 @@ int16_t RF69::startReceive() { _mod->setRfSwitchState(HIGH, LOW); // set mode to receive - state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_ON | RF69_OCP_TRIM); - state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL); - state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_NORMAL); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_NORMAL); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_NORMAL); RADIOLIB_ASSERT(state); - state = setMode(RF69_RX); + state = setMode(RADIOLIB_RF69_RX); return(state); } void RF69::setDio0Action(void (*func)(void)) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void RF69::clearDio0Action() { - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } void RF69::setDio1Action(void (*func)(void)) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - Module::pinMode(_mod->getGpio(), INPUT); - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); + _mod->pinMode(_mod->getGpio(), INPUT); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); } void RF69::clearDio1Action() { if(_mod->getGpio() == RADIOLIB_NC) { return; } - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length - if(len > RF69_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set mode to standby - int16_t state = setMode(RF69_STANDBY); + int16_t state = setMode(RADIOLIB_RF69_STANDBY); RADIOLIB_ASSERT(state); // set DIO pin mapping - state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PACKET_SENT, 7, 6); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PACKET_SENT, 7, 6); RADIOLIB_ASSERT(state); // clear interrupt flags clearIRQFlags(); // optionally write packet length - if (_packetLengthConfig == RF69_PACKET_FORMAT_VARIABLE) { - _mod->SPIwriteRegister(RF69_REG_FIFO, len); + if (_packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, len); } // check address filtering - uint8_t filter = _mod->SPIgetRegValue(RF69_REG_PACKET_CONFIG_1, 2, 1); - if((filter == RF69_ADDRESS_FILTERING_NODE) || (filter == RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIwriteRegister(RF69_REG_FIFO, addr); + uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, addr); } // write packet to FIFO - _mod->SPIwriteRegisterBurst(RF69_REG_FIFO, data, len); + _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, len); // enable +20 dBm operation if(_power > 17) { - state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_OFF | 0x0F); - state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_20_DBM); - state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_20_DBM); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_OFF | 0x0F); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_20_DBM); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_20_DBM); RADIOLIB_ASSERT(state); } @@ -332,7 +336,7 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->setRfSwitchState(LOW, HIGH); // set mode to transmit - state = setMode(RF69_TX); + state = setMode(RADIOLIB_RF69_TX); return(state); } @@ -344,18 +348,18 @@ int16_t RF69::readData(uint8_t* data, size_t len) { // get packet length size_t length = len; - if(len == RF69_MAX_PACKET_LENGTH) { + if(len == RADIOLIB_RF69_MAX_PACKET_LENGTH) { length = getPacketLength(); } // check address filtering - uint8_t filter = _mod->SPIgetRegValue(RF69_REG_PACKET_CONFIG_1, 2, 1); - if((filter == RF69_ADDRESS_FILTERING_NODE) || (filter == RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIreadRegister(RF69_REG_FIFO); + uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { + _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); } // read packet data - _mod->SPIreadRegisterBurst(RF69_REG_FIFO, length, data); + _mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, length, data); // clear internal flag so getPacketLength can return the new packet length _packetLengthQueried = false; @@ -363,18 +367,18 @@ int16_t RF69::readData(uint8_t* data, size_t len) { // clear interrupt flags clearIRQFlags(); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t RF69::setOOK(bool enableOOK) { // set OOK and if successful, save the new setting - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(enableOOK) { - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_OOK, 4, 3, 5); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_OOK, 4, 3, 5); } else { - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK, 4, 3, 5); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK, 4, 3, 5); } - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { _ook = enableOOK; } @@ -382,10 +386,10 @@ int16_t RF69::setOOK(bool enableOOK) { } int16_t RF69::setOokThresholdType(uint8_t type) { - if((type != RF69_OOK_THRESH_FIXED) && (type != RF69_OOK_THRESH_PEAK) && (type != RF69_OOK_THRESH_AVERAGE)) { - return(ERR_INVALID_OOK_RSSI_PEAK_TYPE); + if((type != RADIOLIB_RF69_OOK_THRESH_FIXED) && (type != RADIOLIB_RF69_OOK_THRESH_PEAK) && (type != RADIOLIB_RF69_OOK_THRESH_AVERAGE)) { + return(RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE); } - return(_mod->SPIsetRegValue(RF69_REG_OOK_PEAK, type, 7, 3, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, type, 7, 3, 5)); } int16_t RF69::setFrequency(float freq) { @@ -393,39 +397,39 @@ int16_t RF69::setFrequency(float freq) { if(!(((freq > 290.0) && (freq < 340.0)) || ((freq > 431.0) && (freq < 510.0)) || ((freq > 862.0) && (freq < 1020.0)))) { - return(ERR_INVALID_FREQUENCY); + return(RADIOLIB_ERR_INVALID_FREQUENCY); } // set mode to standby - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); //set carrier frequency - uint32_t FRF = (freq * (uint32_t(1) << RF69_DIV_EXPONENT)) / RF69_CRYSTAL_FREQ; - _mod->SPIwriteRegister(RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); - _mod->SPIwriteRegister(RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); - _mod->SPIwriteRegister(RF69_REG_FRF_LSB, FRF & 0x0000FF); + uint32_t FRF = (freq * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / RADIOLIB_RF69_CRYSTAL_FREQ; + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, FRF & 0x0000FF); _freq = freq; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t RF69::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); // check bitrate-bandwidth ratio if(!(br < 2000 * _rxBw)) { - return(ERR_INVALID_BIT_RATE_BW_RATIO); + return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); } // set mode to standby - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); // set bit rate uint16_t bitRate = 32000 / br; - int16_t state = _mod->SPIsetRegValue(RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= _mod->SPIsetRegValue(RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); - if(state == ERR_NONE) { + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + if(state == RADIOLIB_ERR_NONE) { RF69::_br = br; } return(state); @@ -434,93 +438,93 @@ int16_t RF69::setBitRate(float br) { int16_t RF69::setRxBandwidth(float rxBw) { // check bitrate-bandwidth ratio if(!(_br < 2000 * rxBw)) { - return(ERR_INVALID_BIT_RATE_BW_RATIO); + return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); } // check allowed bandwidth values uint8_t bwMant, bwExp; if(rxBw == 2.6) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 7; } else if(rxBw == 3.1) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 7; } else if(rxBw == 3.9) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 7; } else if(rxBw == 5.2) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 6; } else if(rxBw == 6.3) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 6; } else if(rxBw == 7.8) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 6; } else if(rxBw == 10.4) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 5; } else if(rxBw == 12.5) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 5; } else if(rxBw == 15.6) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 5; } else if(rxBw == 20.8) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 4; } else if(rxBw == 25.0) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 4; } else if(rxBw == 31.3) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 4; } else if(rxBw == 41.7) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 3; } else if(rxBw == 50.0) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 3; } else if(rxBw == 62.5) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 3; } else if(rxBw == 83.3) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 2; } else if(rxBw == 100.0) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 2; } else if(rxBw == 125.0) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 2; } else if(rxBw == 166.7) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 1; } else if(rxBw == 200.0) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 1; } else if(rxBw == 250.0) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 1; } else if(rxBw == 333.3) { - bwMant = RF69_RX_BW_MANT_24; + bwMant = RADIOLIB_RF69_RX_BW_MANT_24; bwExp = 0; } else if(rxBw == 400.0) { - bwMant = RF69_RX_BW_MANT_20; + bwMant = RADIOLIB_RF69_RX_BW_MANT_20; bwExp = 0; } else if(rxBw == 500.0) { - bwMant = RF69_RX_BW_MANT_16; + bwMant = RADIOLIB_RF69_RX_BW_MANT_16; bwExp = 0; } else { - return(ERR_INVALID_RX_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } // set mode to standby - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); // set Rx bandwidth - int16_t state = _mod->SPIsetRegValue(RF69_REG_RX_BW, RF69_DCC_FREQ | bwMant | bwExp, 7, 0); - if(state == ERR_NONE) { + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, RADIOLIB_RF69_DCC_FREQ | bwMant | bwExp, 7, 0); + if(state == RADIOLIB_ERR_NONE) { RF69::_rxBw = rxBw; } return(state); @@ -535,30 +539,30 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { // check frequency deviation range if(!((newFreqDev + _br/2 <= 500))) { - return(ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } // set mode to standby - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); // set frequency deviation from carrier frequency uint32_t base = 1; uint32_t fdev = (newFreqDev * (base << 19)) / 32000; - int16_t state = _mod->SPIsetRegValue(RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); - state |= _mod->SPIsetRegValue(RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); return(state); } int16_t RF69::setOutputPower(int8_t power, bool highPower) { if(highPower) { - RADIOLIB_CHECK_RANGE(power, -2, 20, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } else { - RADIOLIB_CHECK_RANGE(power, -18, 13, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } // set mode to standby - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); // set output power int16_t state; @@ -566,22 +570,22 @@ int16_t RF69::setOutputPower(int8_t power, bool highPower) { // check if both PA1 and PA2 are needed if(power <= 10) { // -2 to 13 dBm, PA1 is enough - state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_OFF | (power + 18), 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); } else if(power <= 17) { // 13 to 17 dBm, both PAs required - state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_ON | (power + 14), 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 14), 7, 0); } else { // 18 - 20 dBm, both PAs and hig power settings required - state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_ON | (power + 11), 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 11), 7, 0); } } else { // low power module, use only PA0 - state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_ON | RF69_PA1_OFF | RF69_PA2_OFF | (power + 18), 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_ON | RADIOLIB_RF69_PA1_OFF | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); } // cache the power value - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { _power = power; } @@ -591,13 +595,13 @@ int16_t RF69::setOutputPower(int8_t power, bool highPower) { int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { // check constraints if((maxErrBits > 7) || (len > 8)) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } // sync word must not contain value 0x00 for(uint8_t i = 0; i < len; i++) { if(syncWord[i] == 0x00) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } } @@ -607,50 +611,50 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { RADIOLIB_ASSERT(state); // set sync word register - _mod->SPIwriteRegisterBurst(RF69_REG_SYNC_VALUE_1, syncWord, len); - return(ERR_NONE); + _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); + return(RADIOLIB_ERR_NONE); } int16_t RF69::setPreambleLength(uint8_t preambleLen) { // RF69 configures preamble length in bytes if(preambleLen % 8 != 0) { - return(ERR_INVALID_PREAMBLE_LENGTH); + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } uint8_t preLenBytes = preambleLen / 8; - _mod->SPIwriteRegister(RF69_REG_PREAMBLE_MSB, 0x00); - return(_mod->SPIsetRegValue(RF69_REG_PREAMBLE_LSB, preLenBytes)); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0x00); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes)); } int16_t RF69::setNodeAddress(uint8_t nodeAddr) { // enable address filtering (node only) - int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_NODE, 2, 1); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE, 2, 1); RADIOLIB_ASSERT(state); // set node address - return(_mod->SPIsetRegValue(RF69_REG_NODE_ADRS, nodeAddr)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, nodeAddr)); } int16_t RF69::setBroadcastAddress(uint8_t broadAddr) { // enable address filtering (node + broadcast) - int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); RADIOLIB_ASSERT(state); // set broadcast address - return(_mod->SPIsetRegValue(RF69_REG_BROADCAST_ADRS, broadAddr)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, broadAddr)); } int16_t RF69::disableAddressFiltering() { // disable address filtering - int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_OFF, 2, 1); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 2, 1); RADIOLIB_ASSERT(state); // set node address to default (0x00) - state = _mod->SPIsetRegValue(RF69_REG_NODE_ADRS, 0x00); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, 0x00); RADIOLIB_ASSERT(state); // set broadcast address to default (0x00) - return(_mod->SPIsetRegValue(RF69_REG_BROADCAST_ADRS, 0x00)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, 0x00)); } void RF69::setAmbientTemperature(int16_t tempAmbient) { @@ -659,27 +663,27 @@ void RF69::setAmbientTemperature(int16_t tempAmbient) { int16_t RF69::getTemperature() { // set mode to STANDBY - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); // start temperature measurement - _mod->SPIsetRegValue(RF69_REG_TEMP_1, RF69_TEMP_MEAS_START, 3, 3); + _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEMP_1, RADIOLIB_RF69_TEMP_MEAS_START, 3, 3); // wait until measurement is finished - while(_mod->SPIgetRegValue(RF69_REG_TEMP_1, 2, 2) == RF69_TEMP_MEAS_RUNNING) { + while(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_1, 2, 2) == RADIOLIB_RF69_TEMP_MEAS_RUNNING) { // check every 10 us - Module::delay(10); + _mod->delay(10); } - int8_t rawTemp = _mod->SPIgetRegValue(RF69_REG_TEMP_2); + int8_t rawTemp = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_2); return(0 - (rawTemp + _tempOffset)); } size_t RF69::getPacketLength(bool update) { if(!_packetLengthQueried && update) { - if (_packetLengthConfig == RF69_PACKET_FORMAT_VARIABLE) { - _packetLength = _mod->SPIreadRegister(RF69_REG_FIFO); + if (_packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { + _packetLength = _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); } else { - _packetLength = _mod->SPIreadRegister(RF69_REG_PAYLOAD_LENGTH); + _packetLength = _mod->SPIreadRegister(RADIOLIB_RF69_REG_PAYLOAD_LENGTH); } _packetLengthQueried = true; } @@ -688,40 +692,40 @@ size_t RF69::getPacketLength(bool update) { } int16_t RF69::fixedPacketLengthMode(uint8_t len) { - return(setPacketMode(RF69_PACKET_FORMAT_FIXED, len)); + return(setPacketMode(RADIOLIB_RF69_PACKET_FORMAT_FIXED, len)); } int16_t RF69::variablePacketLengthMode(uint8_t maxLen) { - return(setPacketMode(RF69_PACKET_FORMAT_VARIABLE, maxLen)); + return(setPacketMode(RADIOLIB_RF69_PACKET_FORMAT_VARIABLE, maxLen)); } int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) { // enable sync word recognition - return(_mod->SPIsetRegValue(RF69_REG_SYNC_CONFIG, RF69_SYNC_ON | RF69_FIFO_FILL_CONDITION_SYNC | (_syncWordLength - 1) << 3 | maxErrBits, 7, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC | (_syncWordLength - 1) << 3 | maxErrBits, 7, 0)); } int16_t RF69::disableSyncWordFiltering() { // disable preamble detection and generation - int16_t state = _mod->SPIsetRegValue(RF69_REG_PREAMBLE_LSB, 0, 7, 0); - state |= _mod->SPIsetRegValue(RF69_REG_PREAMBLE_MSB, 0, 7, 0); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, 0, 7, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0, 7, 0); RADIOLIB_ASSERT(state); // disable sync word detection and generation - state = _mod->SPIsetRegValue(RF69_REG_SYNC_CONFIG, RF69_SYNC_OFF | RF69_FIFO_FILL_CONDITION, 7, 6); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_OFF | RADIOLIB_RF69_FIFO_FILL_CONDITION, 7, 6); return(state); } int16_t RF69::setCrcFiltering(bool crcOn) { if (crcOn == true) { - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_CRC_ON, 4, 4)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_ON, 4, 4)); } else { - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_CRC_OFF, 4, 4)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_OFF, 4, 4)); } } int16_t RF69::setPromiscuousMode(bool promiscuous) { - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if (_promiscuous == promiscuous) { return(state); @@ -754,15 +758,15 @@ int16_t RF69::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_NO_SHAPING, 1, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_NO_SHAPING, 1, 0)); case RADIOLIB_SHAPING_0_3: - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_3, 1, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0)); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_5, 1, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_5, 1, 0)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_1_0, 1, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_1_0, 1, 0)); default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } } @@ -774,26 +778,26 @@ int16_t RF69::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_NONE, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_NONE, 6, 5)); case RADIOLIB_ENCODING_MANCHESTER: - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_MANCHESTER, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_MANCHESTER, 6, 5)); case RADIOLIB_ENCODING_WHITENING: - return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_WHITENING, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_WHITENING, 6, 5)); default: - return(ERR_INVALID_ENCODING); + return(RADIOLIB_ERR_INVALID_ENCODING); } } int16_t RF69::setLnaTestBoost(bool value) { if(value) { - return (_mod->SPIsetRegValue(RF69_REG_TEST_LNA, RF69_TEST_LNA_BOOST_HIGH, 7, 0)); + return (_mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_LNA, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); } - return(_mod->SPIsetRegValue(RF69_TEST_LNA_BOOST_NORMAL, RF69_TEST_LNA_BOOST_HIGH, 7, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); } float RF69::getRSSI() { - return(-1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0)); + return(-1.0 * (_mod->SPIgetRegValue(RADIOLIB_RF69_REG_RSSI_VALUE)/2.0)); } void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { @@ -802,19 +806,19 @@ void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { uint8_t RF69::randomByte() { // set mode to Rx - setMode(RF69_RX); + setMode(RADIOLIB_RF69_RX); // wait a bit for the RSSI reading to stabilise - Module::delay(10); + _mod->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { - randByte |= ((_mod->SPIreadRegister(RF69_REG_RSSI_VALUE) & 0x01) << i); + randByte |= ((_mod->SPIreadRegister(RADIOLIB_RF69_REG_RSSI_VALUE) & 0x01) << i); } // set mode to standby - setMode(RF69_STANDBY); + setMode(RADIOLIB_RF69_STANDBY); return(randByte); } @@ -828,77 +832,77 @@ void RF69::readBit(RADIOLIB_PIN_TYPE pin) { } int16_t RF69::getChipVersion() { - return(_mod->SPIgetRegValue(RF69_REG_VERSION)); + return(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_VERSION)); } int16_t RF69::config() { - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; // set mode to STANDBY - state = setMode(RF69_STANDBY); + state = setMode(RADIOLIB_RF69_STANDBY); RADIOLIB_ASSERT(state); // set operation modes - state = _mod->SPIsetRegValue(RF69_REG_OP_MODE, RF69_SEQUENCER_ON | RF69_LISTEN_OFF, 7, 6); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, RADIOLIB_RF69_SEQUENCER_ON | RADIOLIB_RF69_LISTEN_OFF, 7, 6); RADIOLIB_ASSERT(state); // enable over-current protection - state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_ON, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON, 4, 4); RADIOLIB_ASSERT(state); // set data mode, modulation type and shaping - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_PACKET_MODE | RF69_FSK, 6, 3); - state |= _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_3, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE | RADIOLIB_RF69_FSK, 6, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0); RADIOLIB_ASSERT(state); // set RSSI threshold - state = _mod->SPIsetRegValue(RF69_REG_RSSI_THRESH, RF69_RSSI_THRESHOLD, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, RADIOLIB_RF69_RSSI_THRESHOLD, 7, 0); RADIOLIB_ASSERT(state); // reset FIFO flag - _mod->SPIwriteRegister(RF69_REG_IRQ_FLAGS_2, RF69_IRQ_FIFO_OVERRUN); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, RADIOLIB_RF69_IRQ_FIFO_OVERRUN); // disable ClkOut on DIO5 - state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_2, RF69_CLK_OUT_OFF, 2, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, RADIOLIB_RF69_CLK_OUT_OFF, 2, 0); RADIOLIB_ASSERT(state); // set packet configuration and disable encryption - state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_PACKET_FORMAT_VARIABLE | RF69_DC_FREE_NONE | RF69_CRC_ON | RF69_CRC_AUTOCLEAR_ON | RF69_ADDRESS_FILTERING_OFF, 7, 1); - state |= _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_INTER_PACKET_RX_DELAY, 7, 4); - state |= _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AUTO_RX_RESTART_ON | RF69_AES_OFF, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_PACKET_FORMAT_VARIABLE | RADIOLIB_RF69_DC_FREE_NONE | RADIOLIB_RF69_CRC_ON | RADIOLIB_RF69_CRC_AUTOCLEAR_ON | RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 7, 1); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_INTER_PACKET_RX_DELAY, 7, 4); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AUTO_RX_RESTART_ON | RADIOLIB_RF69_AES_OFF, 1, 0); RADIOLIB_ASSERT(state); // set payload length - state = _mod->SPIsetRegValue(RF69_REG_PAYLOAD_LENGTH, RF69_PAYLOAD_LENGTH, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, RADIOLIB_RF69_PAYLOAD_LENGTH, 7, 0); RADIOLIB_ASSERT(state); // set FIFO threshold - state = _mod->SPIsetRegValue(RF69_REG_FIFO_THRESH, RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RF69_FIFO_THRESHOLD, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RADIOLIB_RF69_FIFO_THRESHOLD, 7, 0); RADIOLIB_ASSERT(state); // set Rx timeouts - state = _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START, 7, 0); - state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START, 7, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH, 7, 0); RADIOLIB_ASSERT(state); // enable improved fading margin - state = _mod->SPIsetRegValue(RF69_REG_TEST_DAGC, RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_DAGC, RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0); return(state); } int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) { // check length - if (len > RF69_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if (len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set to fixed packet length - int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, mode, 7, 7); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, mode, 7, 7); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(RF69_REG_PAYLOAD_LENGTH, len); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update the cached value @@ -907,12 +911,12 @@ int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) { } int16_t RF69::setMode(uint8_t mode) { - return(_mod->SPIsetRegValue(RF69_REG_OP_MODE, mode, 4, 2)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, mode, 4, 2)); } void RF69::clearIRQFlags() { - _mod->SPIwriteRegister(RF69_REG_IRQ_FLAGS_1, 0b11111111); - _mod->SPIwriteRegister(RF69_REG_IRQ_FLAGS_2, 0b11111111); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_1, 0b11111111); + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, 0b11111111); } #endif diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d2acc5e833..a334e2f715 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -10,427 +10,427 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // RF69 physical layer properties -#define RF69_FREQUENCY_STEP_SIZE 61.03515625 -#define RF69_MAX_PACKET_LENGTH 64 -#define RF69_CRYSTAL_FREQ 32.0 -#define RF69_DIV_EXPONENT 19 +#define RADIOLIB_RF69_FREQUENCY_STEP_SIZE 61.03515625 +#define RADIOLIB_RF69_MAX_PACKET_LENGTH 64 +#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0 +#define RADIOLIB_RF69_DIV_EXPONENT 19 // RF69 register map -#define RF69_REG_FIFO 0x00 -#define RF69_REG_OP_MODE 0x01 -#define RF69_REG_DATA_MODUL 0x02 -#define RF69_REG_BITRATE_MSB 0x03 -#define RF69_REG_BITRATE_LSB 0x04 -#define RF69_REG_FDEV_MSB 0x05 -#define RF69_REG_FDEV_LSB 0x06 -#define RF69_REG_FRF_MSB 0x07 -#define RF69_REG_FRF_MID 0x08 -#define RF69_REG_FRF_LSB 0x09 -#define RF69_REG_OSC_1 0x0A -#define RF69_REG_AFC_CTRL 0x0B -#define RF69_REG_LISTEN_1 0x0D -#define RF69_REG_LISTEN_2 0x0E -#define RF69_REG_LISTEN_3 0x0F -#define RF69_REG_VERSION 0x10 -#define RF69_REG_PA_LEVEL 0x11 -#define RF69_REG_PA_RAMP 0x12 -#define RF69_REG_OCP 0x13 -#define RF69_REG_LNA 0x18 -#define RF69_REG_RX_BW 0x19 -#define RF69_REG_AFC_BW 0x1A -#define RF69_REG_OOK_PEAK 0x1B -#define RF69_REG_OOK_AVG 0x1C -#define RF69_REG_OOK_FIX 0x1D -#define RF69_REG_AFC_FEI 0x1E -#define RF69_REG_AFC_MSB 0x1F -#define RF69_REG_AFC_LSB 0x20 -#define RF69_REG_FEI_MSB 0x21 -#define RF69_REG_FEI_LSB 0x22 -#define RF69_REG_RSSI_CONFIG 0x23 -#define RF69_REG_RSSI_VALUE 0x24 -#define RF69_REG_DIO_MAPPING_1 0x25 -#define RF69_REG_DIO_MAPPING_2 0x26 -#define RF69_REG_IRQ_FLAGS_1 0x27 -#define RF69_REG_IRQ_FLAGS_2 0x28 -#define RF69_REG_RSSI_THRESH 0x29 -#define RF69_REG_RX_TIMEOUT_1 0x2A -#define RF69_REG_RX_TIMEOUT_2 0x2B -#define RF69_REG_PREAMBLE_MSB 0x2C -#define RF69_REG_PREAMBLE_LSB 0x2D -#define RF69_REG_SYNC_CONFIG 0x2E -#define RF69_REG_SYNC_VALUE_1 0x2F -#define RF69_REG_SYNC_VALUE_2 0x30 -#define RF69_REG_SYNC_VALUE_3 0x31 -#define RF69_REG_SYNC_VALUE_4 0x32 -#define RF69_REG_SYNC_VALUE_5 0x33 -#define RF69_REG_SYNC_VALUE_6 0x34 -#define RF69_REG_SYNC_VALUE_7 0x35 -#define RF69_REG_SYNC_VALUE_8 0x36 -#define RF69_REG_PACKET_CONFIG_1 0x37 -#define RF69_REG_PAYLOAD_LENGTH 0x38 -#define RF69_REG_NODE_ADRS 0x39 -#define RF69_REG_BROADCAST_ADRS 0x3A -#define RF69_REG_AUTO_MODES 0x3B -#define RF69_REG_FIFO_THRESH 0x3C -#define RF69_REG_PACKET_CONFIG_2 0x3D -#define RF69_REG_AES_KEY_1 0x3E -#define RF69_REG_AES_KEY_2 0x3F -#define RF69_REG_AES_KEY_3 0x40 -#define RF69_REG_AES_KEY_4 0x41 -#define RF69_REG_AES_KEY_5 0x42 -#define RF69_REG_AES_KEY_6 0x43 -#define RF69_REG_AES_KEY_7 0x44 -#define RF69_REG_AES_KEY_8 0x45 -#define RF69_REG_AES_KEY_9 0x46 -#define RF69_REG_AES_KEY_10 0x47 -#define RF69_REG_AES_KEY_11 0x48 -#define RF69_REG_AES_KEY_12 0x49 -#define RF69_REG_AES_KEY_13 0x4A -#define RF69_REG_AES_KEY_14 0x4B -#define RF69_REG_AES_KEY_15 0x4C -#define RF69_REG_AES_KEY_16 0x4D -#define RF69_REG_TEMP_1 0x4E -#define RF69_REG_TEMP_2 0x4F -#define RF69_REG_TEST_LNA 0x58 -#define RF69_REG_TEST_PA1 0x5A -#define RF69_REG_TEST_PA2 0x5C -#define RF69_REG_TEST_DAGC 0x6F +#define RADIOLIB_RF69_REG_FIFO 0x00 +#define RADIOLIB_RF69_REG_OP_MODE 0x01 +#define RADIOLIB_RF69_REG_DATA_MODUL 0x02 +#define RADIOLIB_RF69_REG_BITRATE_MSB 0x03 +#define RADIOLIB_RF69_REG_BITRATE_LSB 0x04 +#define RADIOLIB_RF69_REG_FDEV_MSB 0x05 +#define RADIOLIB_RF69_REG_FDEV_LSB 0x06 +#define RADIOLIB_RF69_REG_FRF_MSB 0x07 +#define RADIOLIB_RF69_REG_FRF_MID 0x08 +#define RADIOLIB_RF69_REG_FRF_LSB 0x09 +#define RADIOLIB_RF69_REG_OSC_1 0x0A +#define RADIOLIB_RF69_REG_AFC_CTRL 0x0B +#define RADIOLIB_RF69_REG_LISTEN_1 0x0D +#define RADIOLIB_RF69_REG_LISTEN_2 0x0E +#define RADIOLIB_RF69_REG_LISTEN_3 0x0F +#define RADIOLIB_RF69_REG_VERSION 0x10 +#define RADIOLIB_RF69_REG_PA_LEVEL 0x11 +#define RADIOLIB_RF69_REG_PA_RAMP 0x12 +#define RADIOLIB_RF69_REG_OCP 0x13 +#define RADIOLIB_RF69_REG_LNA 0x18 +#define RADIOLIB_RF69_REG_RX_BW 0x19 +#define RADIOLIB_RF69_REG_AFC_BW 0x1A +#define RADIOLIB_RF69_REG_OOK_PEAK 0x1B +#define RADIOLIB_RF69_REG_OOK_AVG 0x1C +#define RADIOLIB_RF69_REG_OOK_FIX 0x1D +#define RADIOLIB_RF69_REG_AFC_FEI 0x1E +#define RADIOLIB_RF69_REG_AFC_MSB 0x1F +#define RADIOLIB_RF69_REG_AFC_LSB 0x20 +#define RADIOLIB_RF69_REG_FEI_MSB 0x21 +#define RADIOLIB_RF69_REG_FEI_LSB 0x22 +#define RADIOLIB_RF69_REG_RSSI_CONFIG 0x23 +#define RADIOLIB_RF69_REG_RSSI_VALUE 0x24 +#define RADIOLIB_RF69_REG_DIO_MAPPING_1 0x25 +#define RADIOLIB_RF69_REG_DIO_MAPPING_2 0x26 +#define RADIOLIB_RF69_REG_IRQ_FLAGS_1 0x27 +#define RADIOLIB_RF69_REG_IRQ_FLAGS_2 0x28 +#define RADIOLIB_RF69_REG_RSSI_THRESH 0x29 +#define RADIOLIB_RF69_REG_RX_TIMEOUT_1 0x2A +#define RADIOLIB_RF69_REG_RX_TIMEOUT_2 0x2B +#define RADIOLIB_RF69_REG_PREAMBLE_MSB 0x2C +#define RADIOLIB_RF69_REG_PREAMBLE_LSB 0x2D +#define RADIOLIB_RF69_REG_SYNC_CONFIG 0x2E +#define RADIOLIB_RF69_REG_SYNC_VALUE_1 0x2F +#define RADIOLIB_RF69_REG_SYNC_VALUE_2 0x30 +#define RADIOLIB_RF69_REG_SYNC_VALUE_3 0x31 +#define RADIOLIB_RF69_REG_SYNC_VALUE_4 0x32 +#define RADIOLIB_RF69_REG_SYNC_VALUE_5 0x33 +#define RADIOLIB_RF69_REG_SYNC_VALUE_6 0x34 +#define RADIOLIB_RF69_REG_SYNC_VALUE_7 0x35 +#define RADIOLIB_RF69_REG_SYNC_VALUE_8 0x36 +#define RADIOLIB_RF69_REG_PACKET_CONFIG_1 0x37 +#define RADIOLIB_RF69_REG_PAYLOAD_LENGTH 0x38 +#define RADIOLIB_RF69_REG_NODE_ADRS 0x39 +#define RADIOLIB_RF69_REG_BROADCAST_ADRS 0x3A +#define RADIOLIB_RF69_REG_AUTO_MODES 0x3B +#define RADIOLIB_RF69_REG_FIFO_THRESH 0x3C +#define RADIOLIB_RF69_REG_PACKET_CONFIG_2 0x3D +#define RADIOLIB_RF69_REG_AES_KEY_1 0x3E +#define RADIOLIB_RF69_REG_AES_KEY_2 0x3F +#define RADIOLIB_RF69_REG_AES_KEY_3 0x40 +#define RADIOLIB_RF69_REG_AES_KEY_4 0x41 +#define RADIOLIB_RF69_REG_AES_KEY_5 0x42 +#define RADIOLIB_RF69_REG_AES_KEY_6 0x43 +#define RADIOLIB_RF69_REG_AES_KEY_7 0x44 +#define RADIOLIB_RF69_REG_AES_KEY_8 0x45 +#define RADIOLIB_RF69_REG_AES_KEY_9 0x46 +#define RADIOLIB_RF69_REG_AES_KEY_10 0x47 +#define RADIOLIB_RF69_REG_AES_KEY_11 0x48 +#define RADIOLIB_RF69_REG_AES_KEY_12 0x49 +#define RADIOLIB_RF69_REG_AES_KEY_13 0x4A +#define RADIOLIB_RF69_REG_AES_KEY_14 0x4B +#define RADIOLIB_RF69_REG_AES_KEY_15 0x4C +#define RADIOLIB_RF69_REG_AES_KEY_16 0x4D +#define RADIOLIB_RF69_REG_TEMP_1 0x4E +#define RADIOLIB_RF69_REG_TEMP_2 0x4F +#define RADIOLIB_RF69_REG_TEST_LNA 0x58 +#define RADIOLIB_RF69_REG_TEST_PA1 0x5A +#define RADIOLIB_RF69_REG_TEST_PA2 0x5C +#define RADIOLIB_RF69_REG_TEST_DAGC 0x6F // RF69 modem settings // RF69_REG_OP_MODE MSB LSB DESCRIPTION -#define RF69_SEQUENCER_OFF 0b00000000 // 7 7 disable automatic sequencer -#define RF69_SEQUENCER_ON 0b10000000 // 7 7 enable automatic sequencer -#define RF69_LISTEN_OFF 0b00000000 // 6 6 disable Listen mode -#define RF69_LISTEN_ON 0b01000000 // 6 6 enable Listen mode -#define RF69_LISTEN_ABORT 0b00100000 // 5 5 abort Listen mode (has to be set together with RF69_LISTEN_OFF) -#define RF69_SLEEP 0b00000000 // 4 2 sleep -#define RF69_STANDBY 0b00000100 // 4 2 standby -#define RF69_FS 0b00001000 // 4 2 frequency synthesis -#define RF69_TX 0b00001100 // 4 2 transmit -#define RF69_RX 0b00010000 // 4 2 receive +#define RADIOLIB_RF69_SEQUENCER_OFF 0b00000000 // 7 7 disable automatic sequencer +#define RADIOLIB_RF69_SEQUENCER_ON 0b10000000 // 7 7 enable automatic sequencer +#define RADIOLIB_RF69_LISTEN_OFF 0b00000000 // 6 6 disable Listen mode +#define RADIOLIB_RF69_LISTEN_ON 0b01000000 // 6 6 enable Listen mode +#define RADIOLIB_RF69_LISTEN_ABORT 0b00100000 // 5 5 abort Listen mode (has to be set together with RF69_LISTEN_OFF) +#define RADIOLIB_RF69_SLEEP 0b00000000 // 4 2 sleep +#define RADIOLIB_RF69_STANDBY 0b00000100 // 4 2 standby +#define RADIOLIB_RF69_FS 0b00001000 // 4 2 frequency synthesis +#define RADIOLIB_RF69_TX 0b00001100 // 4 2 transmit +#define RADIOLIB_RF69_RX 0b00010000 // 4 2 receive // RF69_REG_DATA_MODUL -#define RF69_PACKET_MODE 0b00000000 // 6 5 packet mode (default) -#define RF69_CONTINUOUS_MODE_WITH_SYNC 0b01000000 // 6 5 continuous mode with bit synchronizer -#define RF69_CONTINUOUS_MODE 0b01100000 // 6 5 continuous mode without bit synchronizer -#define RF69_FSK 0b00000000 // 4 3 modulation: FSK (default) -#define RF69_OOK 0b00001000 // 4 3 OOK -#define RF69_NO_SHAPING 0b00000000 // 1 0 modulation shaping: no shaping (default) -#define RF69_FSK_GAUSSIAN_1_0 0b00000001 // 1 0 FSK modulation Gaussian filter, BT = 1.0 -#define RF69_FSK_GAUSSIAN_0_5 0b00000010 // 1 0 FSK modulation Gaussian filter, BT = 0.5 -#define RF69_FSK_GAUSSIAN_0_3 0b00000011 // 1 0 FSK modulation Gaussian filter, BT = 0.3 -#define RF69_OOK_FILTER_BR 0b00000001 // 1 0 OOK modulation filter, f_cutoff = BR -#define RF69_OOK_FILTER_2BR 0b00000010 // 1 0 OOK modulation filter, f_cutoff = 2*BR +#define RADIOLIB_RF69_PACKET_MODE 0b00000000 // 6 5 packet mode (default) +#define RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC 0b01000000 // 6 5 continuous mode with bit synchronizer +#define RADIOLIB_RF69_CONTINUOUS_MODE 0b01100000 // 6 5 continuous mode without bit synchronizer +#define RADIOLIB_RF69_FSK 0b00000000 // 4 3 modulation: FSK (default) +#define RADIOLIB_RF69_OOK 0b00001000 // 4 3 OOK +#define RADIOLIB_RF69_NO_SHAPING 0b00000000 // 1 0 modulation shaping: no shaping (default) +#define RADIOLIB_RF69_FSK_GAUSSIAN_1_0 0b00000001 // 1 0 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_RF69_FSK_GAUSSIAN_0_5 0b00000010 // 1 0 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_RF69_FSK_GAUSSIAN_0_3 0b00000011 // 1 0 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_RF69_OOK_FILTER_BR 0b00000001 // 1 0 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_RF69_OOK_FILTER_2BR 0b00000010 // 1 0 OOK modulation filter, f_cutoff = 2*BR // RF69_REG_BITRATE_MSB + REG_BITRATE_LSB -#define RF69_BITRATE_MSB 0x1A // 7 0 bit rate setting: rate = F(XOSC) / BITRATE -#define RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps 0x40 // 7 0 +#define RADIOLIB_RF69_BITRATE_MSB 0x1A // 7 0 bit rate setting: rate = F(XOSC) / BITRATE +#define RADIOLIB_RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps 0x40 // 7 0 // RF69_REG_FDEV_MSB + REG_FDEV_LSB -#define RF69_FDEV_MSB 0x00 // 5 0 frequency deviation: f_dev = f_step * FDEV -#define RF69_FDEV_LSB 0x52 // 7 0 default value: 5 kHz +#define RADIOLIB_RF69_FDEV_MSB 0x00 // 5 0 frequency deviation: f_dev = f_step * FDEV +#define RADIOLIB_RF69_FDEV_LSB 0x52 // 7 0 default value: 5 kHz // RF69_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB -#define RF69_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 -#define RF69_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz -#define RF69_FRF_LSB 0x00 // 7 0 default value: 915 MHz +#define RADIOLIB_RF69_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_RF69_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_RF69_FRF_LSB 0x00 // 7 0 default value: 915 MHz // RF69_REG_OSC_1 -#define RF69_RC_CAL_START 0b10000000 // 7 7 force RC oscillator calibration -#define RF69_RC_CAL_RUNNING 0b00000000 // 6 6 RC oscillator calibration is still running -#define RF69_RC_CAL_DONE 0b00000000 // 5 5 RC oscillator calibration has finished +#define RADIOLIB_RF69_RC_CAL_START 0b10000000 // 7 7 force RC oscillator calibration +#define RADIOLIB_RF69_RC_CAL_RUNNING 0b00000000 // 6 6 RC oscillator calibration is still running +#define RADIOLIB_RF69_RC_CAL_DONE 0b00000000 // 5 5 RC oscillator calibration has finished // RF69_REG_AFC_CTRL -#define RF69_AFC_LOW_BETA_OFF 0b00000000 // 5 5 standard AFC routine -#define RF69_AFC_LOW_BETA_ON 0b00100000 // 5 5 improved AFC routine for signals with modulation index less than 2 +#define RADIOLIB_RF69_AFC_LOW_BETA_OFF 0b00000000 // 5 5 standard AFC routine +#define RADIOLIB_RF69_AFC_LOW_BETA_ON 0b00100000 // 5 5 improved AFC routine for signals with modulation index less than 2 // RF69_REG_LISTEN_1 -#define RF69_LISTEN_RES_IDLE_64_US 0b01000000 // 7 6 resolution of Listen mode idle time: 64 us -#define RF69_LISTEN_RES_IDLE_4_1_MS 0b10000000 // 7 6 4.1 ms (default) -#define RF69_LISTEN_RES_IDLE_262_MS 0b11000000 // 7 6 262 ms -#define RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode rx time: 64 us (default) -#define RF69_LISTEN_RES_RX_4_1_MS 0b00100000 // 5 4 4.1 ms -#define RF69_LISTEN_RES_RX_262_MS 0b00110000 // 5 4 262 ms -#define RF69_LISTEN_ACCEPT_ABOVE_RSSI_THRESH 0b00000000 // 3 3 packet acceptance criteria: RSSI above threshold -#define RF69_LISTEN_ACCEPT_MATCH_SYNC_ADDRESS 0b00001000 // 3 3 RSSI above threshold AND sync address matched -#define RF69_LISTEN_END_KEEP_RX 0b00000000 // 2 1 action after packet acceptance: stay in Rx mode -#define RF69_LISTEN_END_KEEP_RX_TIMEOUT 0b00000010 // 2 1 stay in Rx mode until timeout (default) -#define RF69_LISTEN_END_KEEP_RX_TIMEOUT_RESUME 0b00000100 // 2 1 stay in Rx mode until timeout, Listen mode will resume +#define RADIOLIB_RF69_LISTEN_RES_IDLE_64_US 0b01000000 // 7 6 resolution of Listen mode idle time: 64 us +#define RADIOLIB_RF69_LISTEN_RES_IDLE_4_1_MS 0b10000000 // 7 6 4.1 ms (default) +#define RADIOLIB_RF69_LISTEN_RES_IDLE_262_MS 0b11000000 // 7 6 262 ms +#define RADIOLIB_RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode rx time: 64 us (default) +#define RADIOLIB_RF69_LISTEN_RES_RX_4_1_MS 0b00100000 // 5 4 4.1 ms +#define RADIOLIB_RF69_LISTEN_RES_RX_262_MS 0b00110000 // 5 4 262 ms +#define RADIOLIB_RF69_LISTEN_ACCEPT_ABOVE_RSSI_THRESH 0b00000000 // 3 3 packet acceptance criteria: RSSI above threshold +#define RADIOLIB_RF69_LISTEN_ACCEPT_MATCH_SYNC_ADDRESS 0b00001000 // 3 3 RSSI above threshold AND sync address matched +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX 0b00000000 // 2 1 action after packet acceptance: stay in Rx mode +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT 0b00000010 // 2 1 stay in Rx mode until timeout (default) +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT_RESUME 0b00000100 // 2 1 stay in Rx mode until timeout, Listen mode will resume // RF69_REG_LISTEN_2 -#define RF69_LISTEN_COEF_IDLE 0xF5 // 7 0 duration of idle phase in Listen mode +#define RADIOLIB_RF69_LISTEN_COEF_IDLE 0xF5 // 7 0 duration of idle phase in Listen mode // RF69_REG_LISTEN_3 -#define RF69_LISTEN_COEF_RX 0x20 // 7 0 duration of Rx phase in Listen mode +#define RADIOLIB_RF69_LISTEN_COEF_RX 0x20 // 7 0 duration of Rx phase in Listen mode // RF69_REG_VERSION -#define RF69_CHIP_VERSION 0x24 // 7 0 +#define RADIOLIB_RF69_CHIP_VERSION 0x24 // 7 0 // RF69_REG_PA_LEVEL -#define RF69_PA0_OFF 0b00000000 // 7 7 PA0 disabled -#define RF69_PA0_ON 0b10000000 // 7 7 PA0 enabled (default) -#define RF69_PA1_OFF 0b00000000 // 6 6 PA1 disabled (default) -#define RF69_PA1_ON 0b01000000 // 6 6 PA1 enabled -#define RF69_PA2_OFF 0b00000000 // 5 5 PA2 disabled (default) -#define RF69_PA2_ON 0b00100000 // 5 5 PA2 enabled -#define RF69_OUTPUT_POWER 0b00011111 // 4 0 output power: P_out = -18 + OUTPUT_POWER +#define RADIOLIB_RF69_PA0_OFF 0b00000000 // 7 7 PA0 disabled +#define RADIOLIB_RF69_PA0_ON 0b10000000 // 7 7 PA0 enabled (default) +#define RADIOLIB_RF69_PA1_OFF 0b00000000 // 6 6 PA1 disabled (default) +#define RADIOLIB_RF69_PA1_ON 0b01000000 // 6 6 PA1 enabled +#define RADIOLIB_RF69_PA2_OFF 0b00000000 // 5 5 PA2 disabled (default) +#define RADIOLIB_RF69_PA2_ON 0b00100000 // 5 5 PA2 enabled +#define RADIOLIB_RF69_OUTPUT_POWER 0b00011111 // 4 0 output power: P_out = -18 + OUTPUT_POWER // RF69_REG_PA_RAMP -#define RF69_PA_RAMP_3_4_MS 0b00000000 // 3 0 PA ramp rise/fall time: 3.4 ms -#define RF69_PA_RAMP_2_MS 0b00000001 // 3 0 2 ms -#define RF69_PA_RAMP_1_MS 0b00000010 // 3 0 1 ms -#define RF69_PA_RAMP_500_US 0b00000011 // 3 0 500 us -#define RF69_PA_RAMP_250_US 0b00000100 // 3 0 250 us -#define RF69_PA_RAMP_125_US 0b00000101 // 3 0 125 us -#define RF69_PA_RAMP_100_US 0b00000110 // 3 0 100 us -#define RF69_PA_RAMP_62_US 0b00000111 // 3 0 62 us -#define RF69_PA_RAMP_50_US 0b00001000 // 3 0 50 us -#define RF69_PA_RAMP_40_US 0b00001001 // 3 0 40 us (default) -#define RF69_PA_RAMP_31_US 0b00001010 // 3 0 31 us -#define RF69_PA_RAMP_25_US 0b00001011 // 3 0 25 us -#define RF69_PA_RAMP_20_US 0b00001100 // 3 0 20 us -#define RF69_PA_RAMP_15_US 0b00001101 // 3 0 15 us -#define RF69_PA_RAMP_12_US 0b00001110 // 3 0 12 us -#define RF69_PA_RAMP_10_US 0b00001111 // 3 0 10 us +#define RADIOLIB_RF69_PA_RAMP_3_4_MS 0b00000000 // 3 0 PA ramp rise/fall time: 3.4 ms +#define RADIOLIB_RF69_PA_RAMP_2_MS 0b00000001 // 3 0 2 ms +#define RADIOLIB_RF69_PA_RAMP_1_MS 0b00000010 // 3 0 1 ms +#define RADIOLIB_RF69_PA_RAMP_500_US 0b00000011 // 3 0 500 us +#define RADIOLIB_RF69_PA_RAMP_250_US 0b00000100 // 3 0 250 us +#define RADIOLIB_RF69_PA_RAMP_125_US 0b00000101 // 3 0 125 us +#define RADIOLIB_RF69_PA_RAMP_100_US 0b00000110 // 3 0 100 us +#define RADIOLIB_RF69_PA_RAMP_62_US 0b00000111 // 3 0 62 us +#define RADIOLIB_RF69_PA_RAMP_50_US 0b00001000 // 3 0 50 us +#define RADIOLIB_RF69_PA_RAMP_40_US 0b00001001 // 3 0 40 us (default) +#define RADIOLIB_RF69_PA_RAMP_31_US 0b00001010 // 3 0 31 us +#define RADIOLIB_RF69_PA_RAMP_25_US 0b00001011 // 3 0 25 us +#define RADIOLIB_RF69_PA_RAMP_20_US 0b00001100 // 3 0 20 us +#define RADIOLIB_RF69_PA_RAMP_15_US 0b00001101 // 3 0 15 us +#define RADIOLIB_RF69_PA_RAMP_12_US 0b00001110 // 3 0 12 us +#define RADIOLIB_RF69_PA_RAMP_10_US 0b00001111 // 3 0 10 us // RF69_REG_OCP -#define RF69_OCP_OFF 0b00000000 // 4 4 PA overload current protection disabled -#define RF69_OCP_ON 0b00010000 // 4 4 PA overload current protection enabled -#define RF69_OCP_TRIM 0b00001010 // 3 0 OCP current: I_max(OCP_TRIM = 0b1010) = 95 mA +#define RADIOLIB_RF69_OCP_OFF 0b00000000 // 4 4 PA overload current protection disabled +#define RADIOLIB_RF69_OCP_ON 0b00010000 // 4 4 PA overload current protection enabled +#define RADIOLIB_RF69_OCP_TRIM 0b00001010 // 3 0 OCP current: I_max(OCP_TRIM = 0b1010) = 95 mA // RF69_REG_LNA -#define RF69_LNA_Z_IN_50_OHM 0b00000000 // 7 7 LNA input impedance: 50 ohm -#define RF69_LNA_Z_IN_200_OHM 0b10000000 // 7 7 200 ohm -#define RF69_LNA_CURRENT_GAIN 0b00001000 // 5 3 manually set LNA current gain -#define RF69_LNA_GAIN_AUTO 0b00000000 // 2 0 LNA gain setting: set automatically by AGC -#define RF69_LNA_GAIN_MAX 0b00000001 // 2 0 max gain -#define RF69_LNA_GAIN_MAX_6_DB 0b00000010 // 2 0 max gain - 6 dB -#define RF69_LNA_GAIN_MAX_12_DB 0b00000011 // 2 0 max gain - 12 dB -#define RF69_LNA_GAIN_MAX_24_DB 0b00000100 // 2 0 max gain - 24 dB -#define RF69_LNA_GAIN_MAX_36_DB 0b00000101 // 2 0 max gain - 36 dB -#define RF69_LNA_GAIN_MAX_48_DB 0b00000110 // 2 0 max gain - 48 dB +#define RADIOLIB_RF69_LNA_Z_IN_50_OHM 0b00000000 // 7 7 LNA input impedance: 50 ohm +#define RADIOLIB_RF69_LNA_Z_IN_200_OHM 0b10000000 // 7 7 200 ohm +#define RADIOLIB_RF69_LNA_CURRENT_GAIN 0b00001000 // 5 3 manually set LNA current gain +#define RADIOLIB_RF69_LNA_GAIN_AUTO 0b00000000 // 2 0 LNA gain setting: set automatically by AGC +#define RADIOLIB_RF69_LNA_GAIN_MAX 0b00000001 // 2 0 max gain +#define RADIOLIB_RF69_LNA_GAIN_MAX_6_DB 0b00000010 // 2 0 max gain - 6 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_12_DB 0b00000011 // 2 0 max gain - 12 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_24_DB 0b00000100 // 2 0 max gain - 24 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_36_DB 0b00000101 // 2 0 max gain - 36 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_48_DB 0b00000110 // 2 0 max gain - 48 dB // RF69_REG_RX_BW -#define RF69_DCC_FREQ 0b01000000 // 7 5 DC offset canceller cutoff frequency (4% Rx BW by default) -#define RF69_RX_BW_MANT_16 0b00000000 // 4 3 Channel filter bandwidth FSK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 2)) -#define RF69_RX_BW_MANT_20 0b00001000 // 4 3 OOK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 3)) -#define RF69_RX_BW_MANT_24 0b00010000 // 4 3 -#define RF69_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp value = 5 +#define RADIOLIB_RF69_DCC_FREQ 0b01000000 // 7 5 DC offset canceller cutoff frequency (4% Rx BW by default) +#define RADIOLIB_RF69_RX_BW_MANT_16 0b00000000 // 4 3 Channel filter bandwidth FSK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 2)) +#define RADIOLIB_RF69_RX_BW_MANT_20 0b00001000 // 4 3 OOK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 3)) +#define RADIOLIB_RF69_RX_BW_MANT_24 0b00010000 // 4 3 +#define RADIOLIB_RF69_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp value = 5 // RF69_REG_AFC_BW -#define RF69_DCC_FREQ_AFC 0b10000000 // 7 5 default DccFreq parameter for AFC -#define RF69_DCC_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter for AFC -#define RF69_DCC_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter for AFC +#define RADIOLIB_RF69_DCC_FREQ_AFC 0b10000000 // 7 5 default DccFreq parameter for AFC +#define RADIOLIB_RF69_DCC_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter for AFC +#define RADIOLIB_RF69_DCC_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter for AFC // RF69_REG_OOK_PEAK -#define RF69_OOK_THRESH_FIXED 0b00000000 // 7 6 OOK threshold type: fixed -#define RF69_OOK_THRESH_PEAK 0b01000000 // 7 6 peak (default) -#define RF69_OOK_THRESH_AVERAGE 0b10000000 // 7 6 average -#define RF69_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 5 3 OOK demodulator step size: 0.5 dB (default) -#define RF69_OOK_PEAK_THRESH_STEP_1_0_DB 0b00001000 // 5 3 1.0 dB -#define RF69_OOK_PEAK_THRESH_STEP_1_5_DB 0b00010000 // 5 3 1.5 dB -#define RF69_OOK_PEAK_THRESH_STEP_2_0_DB 0b00011000 // 5 3 2.0 dB -#define RF69_OOK_PEAK_THRESH_STEP_3_0_DB 0b00100000 // 5 3 3.0 dB -#define RF69_OOK_PEAK_THRESH_STEP_4_0_DB 0b00101000 // 5 3 4.0 dB -#define RF69_OOK_PEAK_THRESH_STEP_5_0_DB 0b00110000 // 5 3 5.0 dB -#define RF69_OOK_PEAK_THRESH_STEP_6_0_DB 0b00111000 // 5 3 6.0 dB -#define RF69_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 2 0 OOK demodulator step period: once per chip (default) -#define RF69_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00000001 // 2 0 once every 2 chips -#define RF69_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b00000010 // 2 0 once every 4 chips -#define RF69_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b00000011 // 2 0 once every 8 chips -#define RF69_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b00000100 // 2 0 2 times per chip -#define RF69_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b00000101 // 2 0 4 times per chip -#define RF69_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b00000110 // 2 0 8 times per chip -#define RF69_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b00000111 // 2 0 16 times per chip +#define RADIOLIB_RF69_OOK_THRESH_FIXED 0b00000000 // 7 6 OOK threshold type: fixed +#define RADIOLIB_RF69_OOK_THRESH_PEAK 0b01000000 // 7 6 peak (default) +#define RADIOLIB_RF69_OOK_THRESH_AVERAGE 0b10000000 // 7 6 average +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 5 3 OOK demodulator step size: 0.5 dB (default) +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_0_DB 0b00001000 // 5 3 1.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_5_DB 0b00010000 // 5 3 1.5 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_2_0_DB 0b00011000 // 5 3 2.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_3_0_DB 0b00100000 // 5 3 3.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_4_0_DB 0b00101000 // 5 3 4.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_5_0_DB 0b00110000 // 5 3 5.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_6_0_DB 0b00111000 // 5 3 6.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 2 0 OOK demodulator step period: once per chip (default) +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00000001 // 2 0 once every 2 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b00000010 // 2 0 once every 4 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b00000011 // 2 0 once every 8 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b00000100 // 2 0 2 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b00000101 // 2 0 4 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b00000110 // 2 0 8 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b00000111 // 2 0 16 times per chip // RF69_REG_OOK_AVG -#define RF69_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 7 6 OOK average filter coefficient: chip rate / 32*pi -#define RF69_OOK_AVG_THRESH_FILT_8_PI 0b01000000 // 7 6 chip rate / 8*pi -#define RF69_OOK_AVG_THRESH_FILT_4_PI 0b10000000 // 7 6 chip rate / 4*pi (default) -#define RF69_OOK_AVG_THRESH_FILT_2_PI 0b11000000 // 7 6 chip rate / 2*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 7 6 OOK average filter coefficient: chip rate / 32*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_8_PI 0b01000000 // 7 6 chip rate / 8*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_4_PI 0b10000000 // 7 6 chip rate / 4*pi (default) +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_2_PI 0b11000000 // 7 6 chip rate / 2*pi // RF69_REG_OOK_FIX -#define RF69_OOK_FIXED_THRESH 0b00000110 // 7 0 default OOK fixed threshold (6 dB) +#define RADIOLIB_RF69_OOK_FIXED_THRESH 0b00000110 // 7 0 default OOK fixed threshold (6 dB) // RF69_REG_AFC_FEI -#define RF69_FEI_RUNNING 0b00000000 // 6 6 FEI status: on-going -#define RF69_FEI_DONE 0b01000000 // 6 6 done -#define RF69_FEI_START 0b00100000 // 5 5 force new FEI measurement -#define RF69_AFC_RUNNING 0b00000000 // 4 4 AFC status: on-going -#define RF69_AFC_DONE 0b00010000 // 4 4 done -#define RF69_AFC_AUTOCLEAR_OFF 0b00000000 // 3 3 AFC register autoclear disabled -#define RF69_AFC_AUTOCLEAR_ON 0b00001000 // 3 3 AFC register autoclear enabled -#define RF69_AFC_AUTO_OFF 0b00000000 // 2 2 perform AFC only manually -#define RF69_AFC_AUTO_ON 0b00000100 // 2 2 perform AFC each time Rx mode is started -#define RF69_AFC_CLEAR 0b00000010 // 1 1 clear AFC register -#define RF69_AFC_START 0b00000001 // 0 0 start AFC +#define RADIOLIB_RF69_FEI_RUNNING 0b00000000 // 6 6 FEI status: on-going +#define RADIOLIB_RF69_FEI_DONE 0b01000000 // 6 6 done +#define RADIOLIB_RF69_FEI_START 0b00100000 // 5 5 force new FEI measurement +#define RADIOLIB_RF69_AFC_RUNNING 0b00000000 // 4 4 AFC status: on-going +#define RADIOLIB_RF69_AFC_DONE 0b00010000 // 4 4 done +#define RADIOLIB_RF69_AFC_AUTOCLEAR_OFF 0b00000000 // 3 3 AFC register autoclear disabled +#define RADIOLIB_RF69_AFC_AUTOCLEAR_ON 0b00001000 // 3 3 AFC register autoclear enabled +#define RADIOLIB_RF69_AFC_AUTO_OFF 0b00000000 // 2 2 perform AFC only manually +#define RADIOLIB_RF69_AFC_AUTO_ON 0b00000100 // 2 2 perform AFC each time Rx mode is started +#define RADIOLIB_RF69_AFC_CLEAR 0b00000010 // 1 1 clear AFC register +#define RADIOLIB_RF69_AFC_START 0b00000001 // 0 0 start AFC // RF69_REG_RSSI_CONFIG -#define RF69_RSSI_RUNNING 0b00000000 // 1 1 RSSI status: on-going -#define RF69_RSSI_DONE 0b00000010 // 1 1 done -#define RF69_RSSI_START 0b00000001 // 0 0 start RSSI measurement +#define RADIOLIB_RF69_RSSI_RUNNING 0b00000000 // 1 1 RSSI status: on-going +#define RADIOLIB_RF69_RSSI_DONE 0b00000010 // 1 1 done +#define RADIOLIB_RF69_RSSI_START 0b00000001 // 0 0 start RSSI measurement // RF69_REG_DIO_MAPPING_1 -#define RF69_DIO0_CONT_MODE_READY 0b11000000 // 7 6 -#define RF69_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 -#define RF69_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define RF69_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 -#define RF69_DIO0_CONT_RSSI 0b10000000 // 7 6 -#define RF69_DIO0_CONT_TX_READY 0b01000000 // 7 6 -#define RF69_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 -#define RF69_DIO0_PACK_CRC_OK 0b00000000 // 7 6 -#define RF69_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 -#define RF69_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 -#define RF69_DIO0_PACK_RSSI 0b11000000 // 7 6 -#define RF69_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 -#define RF69_DIO0_PACK_TX_READY 0b01000000 // 7 6 -#define RF69_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 -#define RF69_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define RF69_DIO1_CONT_RX_READY 0b00010000 // 5 4 -#define RF69_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 -#define RF69_DIO1_CONT_TX_READY 0b00010000 // 5 4 -#define RF69_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 -#define RF69_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 -#define RF69_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 -#define RF69_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 -#define RF69_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 -#define RF69_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_RSSI 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_CRC_OK 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_RSSI 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_RX_READY 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_TX_READY 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO2_CONT_DATA 0b00000000 // 3 2 // RF69_REG_DIO_MAPPING_2 -#define RF69_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) -#define RF69_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 -#define RF69_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 -#define RF69_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 -#define RF69_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 -#define RF69_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 31 -#define RF69_CLK_OUT_RC 0b00000110 // 2 0 RC -#define RF69_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) +#define RADIOLIB_RF69_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define RADIOLIB_RF69_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 31 +#define RADIOLIB_RF69_CLK_OUT_RC 0b00000110 // 2 0 RC +#define RADIOLIB_RF69_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) // RF69_REG_IRQ_FLAGS_1 -#define RF69_IRQ_MODE_READY 0b10000000 // 7 7 requested mode was set -#define RF69_IRQ_RX_READY 0b01000000 // 6 6 Rx mode ready -#define RF69_IRQ_TX_READY 0b00100000 // 5 5 Tx mode ready -#define RF69_IRQ_PLL_LOCK 0b00010000 // 4 4 PLL is locked -#define RF69_IRQ_RSSI 0b00001000 // 3 3 RSSI value exceeded RssiThreshold -#define RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occurred -#define RF69_IRQ_AUTO_MODE 0b00000010 // 1 1 entered intermediate mode -#define RF69_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address detected +#define RADIOLIB_RF69_IRQ_MODE_READY 0b10000000 // 7 7 requested mode was set +#define RADIOLIB_RF69_IRQ_RX_READY 0b01000000 // 6 6 Rx mode ready +#define RADIOLIB_RF69_IRQ_TX_READY 0b00100000 // 5 5 Tx mode ready +#define RADIOLIB_RF69_IRQ_PLL_LOCK 0b00010000 // 4 4 PLL is locked +#define RADIOLIB_RF69_IRQ_RSSI 0b00001000 // 3 3 RSSI value exceeded RssiThreshold +#define RADIOLIB_RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occurred +#define RADIOLIB_RF69_IRQ_AUTO_MODE 0b00000010 // 1 1 entered intermediate mode +#define RADIOLIB_RF69_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address detected // RF69_REG_IRQ_FLAGS_2 -#define RF69_IRQ_FIFO_FULL 0b10000000 // 7 7 FIFO is full -#define RF69_IRQ_FIFO_NOT_EMPTY 0b01000000 // 6 6 FIFO contains at least 1 byte -#define RF69_IRQ_FIFO_LEVEL 0b00100000 // 5 5 FIFO contains more than FifoThreshold bytes -#define RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred -#define RF69_IRQ_PACKET_SENT 0b00001000 // 3 3 packet was sent -#define RF69_IRQ_PAYLOAD_READY 0b00000100 // 2 2 last payload byte received and CRC check passed -#define RF69_IRQ_CRC_OK 0b00000010 // 1 1 CRC check passed +#define RADIOLIB_RF69_IRQ_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define RADIOLIB_RF69_IRQ_FIFO_NOT_EMPTY 0b01000000 // 6 6 FIFO contains at least 1 byte +#define RADIOLIB_RF69_IRQ_FIFO_LEVEL 0b00100000 // 5 5 FIFO contains more than FifoThreshold bytes +#define RADIOLIB_RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred +#define RADIOLIB_RF69_IRQ_PACKET_SENT 0b00001000 // 3 3 packet was sent +#define RADIOLIB_RF69_IRQ_PAYLOAD_READY 0b00000100 // 2 2 last payload byte received and CRC check passed +#define RADIOLIB_RF69_IRQ_CRC_OK 0b00000010 // 1 1 CRC check passed // RF69_REG_RSSI_THRESH -#define RF69_RSSI_THRESHOLD 0xE4 // 7 0 RSSI threshold level (2 dB by default) +#define RADIOLIB_RF69_RSSI_THRESHOLD 0xE4 // 7 0 RSSI threshold level (2 dB by default) // RF69_REG_RX_TIMEOUT_1 -#define RF69_TIMEOUT_RX_START_OFF 0x00 // 7 0 RSSI interrupt timeout disabled (default) -#define RF69_TIMEOUT_RX_START 0xFF // 7 0 timeout will occur if RSSI interrupt is not received +#define RADIOLIB_RF69_TIMEOUT_RX_START_OFF 0x00 // 7 0 RSSI interrupt timeout disabled (default) +#define RADIOLIB_RF69_TIMEOUT_RX_START 0xFF // 7 0 timeout will occur if RSSI interrupt is not received // RF69_REG_RX_TIMEOUT_2 -#define RF69_TIMEOUT_RSSI_THRESH_OFF 0x00 // 7 0 PayloadReady interrupt timeout disabled (default) -#define RF69_TIMEOUT_RSSI_THRESH 0xFF // 7 0 timeout will occur if PayloadReady interrupt is not received +#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH_OFF 0x00 // 7 0 PayloadReady interrupt timeout disabled (default) +#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH 0xFF // 7 0 timeout will occur if PayloadReady interrupt is not received // RF69_REG_PREAMBLE_MSB + REG_PREAMBLE_MSB -#define RF69_PREAMBLE_MSB 0x00 // 7 0 2-byte preamble size value -#define RF69_PREAMBLE_LSB 0x03 // 7 0 +#define RADIOLIB_RF69_PREAMBLE_MSB 0x00 // 7 0 2-byte preamble size value +#define RADIOLIB_RF69_PREAMBLE_LSB 0x03 // 7 0 // RF69_REG_SYNC_CONFIG -#define RF69_SYNC_OFF 0b00000000 // 7 7 sync word detection off -#define RF69_SYNC_ON 0b10000000 // 7 7 sync word detection on (default) -#define RF69_FIFO_FILL_CONDITION_SYNC 0b00000000 // 6 6 FIFO fill condition: on SyncAddress interrupt (default) -#define RF69_FIFO_FILL_CONDITION 0b01000000 // 6 6 as long as the bit is set -#define RF69_SYNC_SIZE 0b00001000 // 5 3 size of sync word: SyncSize + 1 bytes -#define RF69_SYNC_TOL 0b00000000 // 2 0 number of tolerated errors in sync word +#define RADIOLIB_RF69_SYNC_OFF 0b00000000 // 7 7 sync word detection off +#define RADIOLIB_RF69_SYNC_ON 0b10000000 // 7 7 sync word detection on (default) +#define RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC 0b00000000 // 6 6 FIFO fill condition: on SyncAddress interrupt (default) +#define RADIOLIB_RF69_FIFO_FILL_CONDITION 0b01000000 // 6 6 as long as the bit is set +#define RADIOLIB_RF69_SYNC_SIZE 0b00001000 // 5 3 size of sync word: SyncSize + 1 bytes +#define RADIOLIB_RF69_SYNC_TOL 0b00000000 // 2 0 number of tolerated errors in sync word // RF69_REG_SYNC_VALUE_1 - SYNC_VALUE_8 -#define RF69_SYNC_BYTE_1 0x01 // 7 0 sync word: 1st byte (MSB) -#define RF69_SYNC_BYTE_2 0x01 // 7 0 2nd byte -#define RF69_SYNC_BYTE_3 0x01 // 7 0 3rd byte -#define RF69_SYNC_BYTE_4 0x01 // 7 0 4th byte -#define RF69_SYNC_BYTE_5 0x01 // 7 0 5th byte -#define RF69_SYNC_BYTE_6 0x01 // 7 0 6th byte -#define RF69_SYNC_BYTE_7 0x01 // 7 0 7th byte -#define RF69_SYNC_BYTE_8 0x01 // 7 0 8th byte (LSB) +#define RADIOLIB_RF69_SYNC_BYTE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define RADIOLIB_RF69_SYNC_BYTE_2 0x01 // 7 0 2nd byte +#define RADIOLIB_RF69_SYNC_BYTE_3 0x01 // 7 0 3rd byte +#define RADIOLIB_RF69_SYNC_BYTE_4 0x01 // 7 0 4th byte +#define RADIOLIB_RF69_SYNC_BYTE_5 0x01 // 7 0 5th byte +#define RADIOLIB_RF69_SYNC_BYTE_6 0x01 // 7 0 6th byte +#define RADIOLIB_RF69_SYNC_BYTE_7 0x01 // 7 0 7th byte +#define RADIOLIB_RF69_SYNC_BYTE_8 0x01 // 7 0 8th byte (LSB) // RF69_REG_PACKET_CONFIG_1 -#define RF69_PACKET_FORMAT_FIXED 0b00000000 // 7 7 fixed packet length (default) -#define RF69_PACKET_FORMAT_VARIABLE 0b10000000 // 7 7 variable packet length -#define RF69_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: none (default) -#define RF69_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester -#define RF69_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening -#define RF69_CRC_OFF 0b00000000 // 4 4 CRC disabled -#define RF69_CRC_ON 0b00010000 // 4 4 CRC enabled (default) -#define RF69_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 discard packet when CRC check fails (default) -#define RF69_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep packet when CRC check fails -#define RF69_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) -#define RF69_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node -#define RF69_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast +#define RADIOLIB_RF69_PACKET_FORMAT_FIXED 0b00000000 // 7 7 fixed packet length (default) +#define RADIOLIB_RF69_PACKET_FORMAT_VARIABLE 0b10000000 // 7 7 variable packet length +#define RADIOLIB_RF69_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: none (default) +#define RADIOLIB_RF69_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define RADIOLIB_RF69_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define RADIOLIB_RF69_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define RADIOLIB_RF69_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define RADIOLIB_RF69_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 discard packet when CRC check fails (default) +#define RADIOLIB_RF69_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep packet when CRC check fails +#define RADIOLIB_RF69_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast // RF69_REG_PAYLOAD_LENGTH -#define RF69_PAYLOAD_LENGTH 0xFF // 7 0 payload length +#define RADIOLIB_RF69_PAYLOAD_LENGTH 0xFF // 7 0 payload length // RF69_REG_AUTO_MODES -#define RF69_ENTER_COND_NONE 0b00000000 // 7 5 condition for entering intermediate mode: none, AutoModes disabled (default) -#define RF69_ENTER_COND_FIFO_NOT_EMPTY 0b00100000 // 7 5 FifoNotEmpty rising edge -#define RF69_ENTER_COND_FIFO_LEVEL 0b01000000 // 7 5 FifoLevel rising edge -#define RF69_ENTER_COND_CRC_OK 0b01100000 // 7 5 CrcOk rising edge -#define RF69_ENTER_COND_PAYLOAD_READY 0b10000000 // 7 5 PayloadReady rising edge -#define RF69_ENTER_COND_SYNC_ADDRESS 0b10100000 // 7 5 SyncAddress rising edge -#define RF69_ENTER_COND_PACKET_SENT 0b11000000 // 7 5 PacketSent rising edge -#define RF69_ENTER_COND_FIFO_EMPTY 0b11100000 // 7 5 FifoNotEmpty falling edge -#define RF69_EXIT_COND_NONE 0b00000000 // 4 2 condition for exiting intermediate mode: none, AutoModes disabled (default) -#define RF69_EXIT_COND_FIFO_EMPTY 0b00100000 // 4 2 FifoNotEmpty falling edge -#define RF69_EXIT_COND_FIFO_LEVEL 0b01000000 // 4 2 FifoLevel rising edge -#define RF69_EXIT_COND_CRC_OK 0b01100000 // 4 2 CrcOk rising edge -#define RF69_EXIT_COND_PAYLOAD_READY 0b10000000 // 4 2 PayloadReady rising edge -#define RF69_EXIT_COND_SYNC_ADDRESS 0b10100000 // 4 2 SyncAddress rising edge -#define RF69_EXIT_COND_PACKET_SENT 0b11000000 // 4 2 PacketSent rising edge -#define RF69_EXIT_COND_TIMEOUT 0b11100000 // 4 2 timeout rising edge -#define RF69_INTER_MODE_SLEEP 0b00000000 // 1 0 intermediate mode: sleep (default) -#define RF69_INTER_MODE_STANDBY 0b00000001 // 1 0 standby -#define RF69_INTER_MODE_RX 0b00000010 // 1 0 Rx -#define RF69_INTER_MODE_TX 0b00000011 // 1 0 Tx +#define RADIOLIB_RF69_ENTER_COND_NONE 0b00000000 // 7 5 condition for entering intermediate mode: none, AutoModes disabled (default) +#define RADIOLIB_RF69_ENTER_COND_FIFO_NOT_EMPTY 0b00100000 // 7 5 FifoNotEmpty rising edge +#define RADIOLIB_RF69_ENTER_COND_FIFO_LEVEL 0b01000000 // 7 5 FifoLevel rising edge +#define RADIOLIB_RF69_ENTER_COND_CRC_OK 0b01100000 // 7 5 CrcOk rising edge +#define RADIOLIB_RF69_ENTER_COND_PAYLOAD_READY 0b10000000 // 7 5 PayloadReady rising edge +#define RADIOLIB_RF69_ENTER_COND_SYNC_ADDRESS 0b10100000 // 7 5 SyncAddress rising edge +#define RADIOLIB_RF69_ENTER_COND_PACKET_SENT 0b11000000 // 7 5 PacketSent rising edge +#define RADIOLIB_RF69_ENTER_COND_FIFO_EMPTY 0b11100000 // 7 5 FifoNotEmpty falling edge +#define RADIOLIB_RF69_EXIT_COND_NONE 0b00000000 // 4 2 condition for exiting intermediate mode: none, AutoModes disabled (default) +#define RADIOLIB_RF69_EXIT_COND_FIFO_EMPTY 0b00100000 // 4 2 FifoNotEmpty falling edge +#define RADIOLIB_RF69_EXIT_COND_FIFO_LEVEL 0b01000000 // 4 2 FifoLevel rising edge +#define RADIOLIB_RF69_EXIT_COND_CRC_OK 0b01100000 // 4 2 CrcOk rising edge +#define RADIOLIB_RF69_EXIT_COND_PAYLOAD_READY 0b10000000 // 4 2 PayloadReady rising edge +#define RADIOLIB_RF69_EXIT_COND_SYNC_ADDRESS 0b10100000 // 4 2 SyncAddress rising edge +#define RADIOLIB_RF69_EXIT_COND_PACKET_SENT 0b11000000 // 4 2 PacketSent rising edge +#define RADIOLIB_RF69_EXIT_COND_TIMEOUT 0b11100000 // 4 2 timeout rising edge +#define RADIOLIB_RF69_INTER_MODE_SLEEP 0b00000000 // 1 0 intermediate mode: sleep (default) +#define RADIOLIB_RF69_INTER_MODE_STANDBY 0b00000001 // 1 0 standby +#define RADIOLIB_RF69_INTER_MODE_RX 0b00000010 // 1 0 Rx +#define RADIOLIB_RF69_INTER_MODE_TX 0b00000011 // 1 0 Tx // RF69_REG_FIFO_THRESH -#define RF69_TX_START_CONDITION_FIFO_LEVEL 0b00000000 // 7 7 packet transmission start condition: FifoLevel -#define RF69_TX_START_CONDITION_FIFO_NOT_EMPTY 0b10000000 // 7 7 FifoNotEmpty (default) -#define RF69_FIFO_THRESHOLD 0b00001111 // 6 0 default threshold to trigger FifoLevel interrupt +#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_LEVEL 0b00000000 // 7 7 packet transmission start condition: FifoLevel +#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY 0b10000000 // 7 7 FifoNotEmpty (default) +#define RADIOLIB_RF69_FIFO_THRESHOLD 0b00001111 // 6 0 default threshold to trigger FifoLevel interrupt // RF69_REG_PACKET_CONFIG_2 -#define RF69_INTER_PACKET_RX_DELAY 0b00000000 // 7 4 delay between FIFO empty and start of new RSSI phase -#define RF69_RESTART_RX 0b00000100 // 2 2 force receiver into wait mode -#define RF69_AUTO_RX_RESTART_OFF 0b00000000 // 1 1 auto Rx restart disabled -#define RF69_AUTO_RX_RESTART_ON 0b00000010 // 1 1 auto Rx restart enabled (default) -#define RF69_AES_OFF 0b00000000 // 0 0 AES encryption disabled (default) -#define RF69_AES_ON 0b00000001 // 0 0 AES encryption enabled, payload size limited to 66 bytes +#define RADIOLIB_RF69_INTER_PACKET_RX_DELAY 0b00000000 // 7 4 delay between FIFO empty and start of new RSSI phase +#define RADIOLIB_RF69_RESTART_RX 0b00000100 // 2 2 force receiver into wait mode +#define RADIOLIB_RF69_AUTO_RX_RESTART_OFF 0b00000000 // 1 1 auto Rx restart disabled +#define RADIOLIB_RF69_AUTO_RX_RESTART_ON 0b00000010 // 1 1 auto Rx restart enabled (default) +#define RADIOLIB_RF69_AES_OFF 0b00000000 // 0 0 AES encryption disabled (default) +#define RADIOLIB_RF69_AES_ON 0b00000001 // 0 0 AES encryption enabled, payload size limited to 66 bytes // RF69_REG_TEST_LNA -#define RF69_TEST_LNA_BOOST_NORMAL 0x1B // 7 0 -#define RF69_TEST_LNA_BOOST_HIGH 0x2D // 7 0 +#define RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL 0x1B // 7 0 +#define RADIOLIB_RF69_TEST_LNA_BOOST_HIGH 0x2D // 7 0 // RF69_REG_TEMP_1 -#define RF69_TEMP_MEAS_START 0b00001000 // 3 3 trigger temperature measurement -#define RF69_TEMP_MEAS_RUNNING 0b00000100 // 2 2 temperature measurement status: on-going -#define RF69_TEMP_MEAS_DONE 0b00000000 // 2 2 done +#define RADIOLIB_RF69_TEMP_MEAS_START 0b00001000 // 3 3 trigger temperature measurement +#define RADIOLIB_RF69_TEMP_MEAS_RUNNING 0b00000100 // 2 2 temperature measurement status: on-going +#define RADIOLIB_RF69_TEMP_MEAS_DONE 0b00000000 // 2 2 done // RF69_REG_TEST_DAGC -#define RF69_CONTINUOUS_DAGC_NORMAL 0x00 // 7 0 fading margin improvement: normal mode -#define RF69_CONTINUOUS_DAGC_LOW_BETA_ON 0x20 // 7 0 improved mode for AfcLowBetaOn -#define RF69_CONTINUOUS_DAGC_LOW_BETA_OFF 0x30 // 7 0 improved mode for AfcLowBetaOff (default) +#define RADIOLIB_RF69_CONTINUOUS_DAGC_NORMAL 0x00 // 7 0 fading margin improvement: normal mode +#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_ON 0x20 // 7 0 improved mode for AfcLowBetaOn +#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF 0x30 // 7 0 improved mode for AfcLowBetaOff (default) // RF69_REG_TEST_PA1 -#define RF69_PA1_NORMAL 0x55 // 7 0 PA_BOOST: none -#define RF69_PA1_20_DBM 0x5D // 7 0 +20 dBm +#define RADIOLIB_RF69_PA1_NORMAL 0x55 // 7 0 PA_BOOST: none +#define RADIOLIB_RF69_PA1_20_DBM 0x5D // 7 0 +20 dBm // RF69_REG_TEST_PA2 -#define RF69_PA2_NORMAL 0x70 // 7 0 PA_BOOST: none -#define RF69_PA2_20_DBM 0x7C // 7 0 +20 dBm +#define RADIOLIB_RF69_PA2_NORMAL 0x70 // 7 0 PA_BOOST: none +#define RADIOLIB_RF69_PA2_20_DBM 0x7C // 7 0 +20 dBm /*! \class RF69 @@ -452,6 +452,8 @@ class RF69: public PhysicalLayer { */ RF69(Module* module); + Module* getMod(); + // basic methods /*! @@ -764,7 +766,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t fixedPacketLengthMode(uint8_t len = RF69_MAX_PACKET_LENGTH); + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_RF69_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. @@ -773,7 +775,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t variablePacketLengthMode(uint8_t maxLen = RF69_MAX_PACKET_LENGTH); + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_RF69_MAX_PACKET_LENGTH); /*! \brief Enable sync word filtering and generation. @@ -901,7 +903,7 @@ class RF69: public PhysicalLayer { size_t _packetLength = 0; bool _packetLengthQueried = false; - uint8_t _packetLengthConfig = RF69_PACKET_FORMAT_VARIABLE; + uint8_t _packetLengthConfig = RADIOLIB_RF69_PACKET_FORMAT_VARIABLE; bool _promiscuous = false; From 7f3ef0bff5a72069cf35180783f394b5f43aea01 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:40:52 +0100 Subject: [PATCH 0045/1848] [RTTY] Update to 5.0.0 --- examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 4 +- .../RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino | 4 +- src/protocols/RTTY/RTTY.cpp | 94 ++++++++++--------- src/protocols/RTTY/RTTY.h | 30 +++--- 4 files changed, 67 insertions(+), 65 deletions(-) diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index f6d22a02f7..e02ad3ca97 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -49,7 +49,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -75,7 +75,7 @@ void setup() { // encoding: ASCII (7-bit) // stop bits: 1 state = rtty.begin(434.0, 183, 45); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino index 243c3488d8..58e6d8c083 100644 --- a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -50,7 +50,7 @@ void setup() { // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -68,7 +68,7 @@ void setup() { // encoding: ASCII (7-bit) // stop bits: 1 state = rtty.begin(400, 170, 45); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 15fc7a72bb..432a645378 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -16,7 +16,7 @@ ITA2String::ITA2String(const char* str) { } ITA2String::~ITA2String() { - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] _str; #endif } @@ -35,7 +35,7 @@ size_t ITA2String::length() { uint8_t* ITA2String::byteArr() { // create temporary array 2x the string length (figures may be 3 bytes) - #ifdef RADIOLIB_STATIC_ONLY + #if defined(RADIOLIB_STATIC_ONLY) uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; #else uint8_t* temp = new uint8_t[_len*2 + 1]; @@ -48,11 +48,11 @@ uint8_t* ITA2String::byteArr() { uint8_t shift = (code >> 5) & 0b11111; uint8_t character = code & 0b11111; // check if the code is letter or figure - if(shift == ITA2_FIGS) { + if(shift == RADIOLIB_ITA2_FIGS) { // check if this is the first figure in sequence if(!flagFigure) { flagFigure = true; - temp[arrayLen++] = ITA2_FIGS; + temp[arrayLen++] = RADIOLIB_ITA2_FIGS; } // add the character code @@ -62,14 +62,14 @@ uint8_t* ITA2String::byteArr() { if(i < (_len - 1)) { uint16_t nextCode = getBits(_str[i+1]); uint8_t nextShift = (nextCode >> 5) & 0b11111; - if(nextShift == ITA2_LTRS) { + if(nextShift == RADIOLIB_ITA2_LTRS) { // next character is a letter, terminate figure shift - temp[arrayLen++] = ITA2_LTRS; + temp[arrayLen++] = RADIOLIB_ITA2_LTRS; flagFigure = false; } } else { // reached the end of the message, terminate figure shift - temp[arrayLen++] = ITA2_LTRS; + temp[arrayLen++] = RADIOLIB_ITA2_LTRS; flagFigure = false; } } else { @@ -82,7 +82,7 @@ uint8_t* ITA2String::byteArr() { uint8_t* arr = new uint8_t[arrayLen]; memcpy(arr, temp, arrayLen); - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] temp; #endif @@ -92,14 +92,14 @@ uint8_t* ITA2String::byteArr() { uint16_t ITA2String::getBits(char c) { // search ITA2 table uint16_t code = 0x0000; - for(uint8_t i = 0; i < ITA2_LENGTH; i++) { - if(RADIOLIB_PROGMEM_READ_BYTE(&ITA2Table[i][0]) == c) { + for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { + if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { // character is in letter shift - code = (ITA2_LTRS << 5) | i; + code = (RADIOLIB_ITA2_LTRS << 5) | i; break; - } else if(RADIOLIB_PROGMEM_READ_BYTE(&ITA2Table[i][1]) == c) { + } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { // character is in figures shift - code = (ITA2_FIGS << 5) | i; + code = (RADIOLIB_ITA2_FIGS << 5) | i; break; } } @@ -129,17 +129,17 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc _shiftHz = shift; switch(encoding) { - case ASCII: + case RADIOLIB_ASCII: _dataBits = 7; break; - case ASCII_EXTENDED: + case RADIOLIB_ASCII_EXTENDED: _dataBits = 8; break; - case ITA2: + case RADIOLIB_ITA2: _dataBits = 5; break; default: - return(ERR_UNSUPPORTED_ENCODING); + return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); } // calculate duration of 1 bit @@ -150,7 +150,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc // check minimum shift value if(shift < step / 2) { - return(ERR_INVALID_RTTY_SHIFT); + return(RADIOLIB_ERR_INVALID_RTTY_SHIFT); } // round shift to multiples of frequency step size @@ -210,7 +210,7 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { size_t len = 0; PGM_P p = reinterpret_cast(fstr); while(true) { - char c = RADIOLIB_PROGMEM_READ_BYTE(p++); + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); len++; if(c == '\0') { break; @@ -218,7 +218,7 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { } // dynamically allocate memory - #ifdef RADIOLIB_STATIC_ONLY + #if defined(RADIOLIB_STATIC_ONLY) char str[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* str = new char[len]; @@ -227,17 +227,17 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { // copy string from flash p = reinterpret_cast(fstr); for(size_t i = 0; i < len; i++) { - str[i] = RADIOLIB_PROGMEM_READ_BYTE(p + i); + str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); } size_t n = 0; - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str); n = RTTYClient::print(ita2); - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, len); } - #ifndef RADIOLIB_STATIC_ONLY + #if !defined(RADIOLIB_STATIC_ONLY) delete[] str; #endif return(n); @@ -252,10 +252,10 @@ size_t RTTYClient::print(ITA2String& ita2) { size_t RTTYClient::print(const String& str) { size_t n = 0; - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str.c_str()); n = RTTYClient::print(ita2); - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); } return(n); @@ -263,10 +263,10 @@ size_t RTTYClient::print(const String& str) { size_t RTTYClient::print(const char str[]) { size_t n = 0; - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str); n = RTTYClient::print(ita2); - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, strlen(str)); } return(n); @@ -274,10 +274,10 @@ size_t RTTYClient::print(const char str[]) { size_t RTTYClient::print(char c) { size_t n = 0; - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(c); n = RTTYClient::print(ita2); - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write(c); } return(n); @@ -324,10 +324,10 @@ size_t RTTYClient::print(double n, int digits) { size_t RTTYClient::println(void) { size_t n = 0; - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String lf = ITA2String("\r\n"); n = RTTYClient::print(lf); - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write("\r\n"); } return(n); @@ -400,18 +400,20 @@ size_t RTTYClient::println(double d, int digits) { } void RTTYClient::mark() { - uint32_t start = Module::micros(); + Module* mod = _phy->getMod(); + uint32_t start = mod->micros(); transmitDirect(_base + _shift, _baseHz + _shiftHz); - while(Module::micros() - start < _bitDuration) { - Module::yield(); + while(mod->micros() - start < _bitDuration) { + mod->yield(); } } void RTTYClient::space() { - uint32_t start = Module::micros(); + Module* mod = _phy->getMod(); + uint32_t start = mod->micros(); transmitDirect(_base, _baseHz); - while(Module::micros() - start < _bitDuration) { - Module::yield(); + while(mod->micros() - start < _bitDuration) { + mod->yield(); } } @@ -433,12 +435,12 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { } while(n); size_t l = 0; - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str); uint8_t* arr = ita2.byteArr(); l = RTTYClient::write(arr, ita2.length()); delete[] arr; - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { l = RTTYClient::write(str); } @@ -456,25 +458,25 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically if(code[0] != 0x00) { - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(code); uint8_t* arr = ita2.byteArr(); n = RTTYClient::write(arr, ita2.length()); delete[] arr; return(n); - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { return(RTTYClient::write(code)); } } // Handle negative numbers if (number < 0.0) { - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String("-"); uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n += RTTYClient::print('-'); } number = -number; @@ -494,12 +496,12 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { // Print the decimal point, but only if there are digits beyond if(digits > 0) { - if(_encoding == ITA2) { + if(_encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String("."); uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; - } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { + } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { n += RTTYClient::print('.'); } } diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index 7bae73279d..a26b144b1d 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -8,17 +8,17 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" -#define ITA2_FIGS 0x1B -#define ITA2_LTRS 0x1F -#define ITA2_LENGTH 32 +#define RADIOLIB_ITA2_FIGS 0x1B +#define RADIOLIB_ITA2_LTRS 0x1F +#define RADIOLIB_ITA2_LENGTH 32 // ITA2 character table: - position in array corresponds to 5-bit ITA2 code // - characters to the left are in letters shift, characters to the right in figures shift // - characters marked 0x7F do not have ASCII equivalent -static const char ITA2Table[ITA2_LENGTH][2] RADIOLIB_PROGMEM = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, - {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, - {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, - {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}}; +static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, + {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, + {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, + {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}}; /*! \class ITA2String @@ -61,10 +61,10 @@ class ITA2String { */ uint8_t* byteArr(); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif - #ifdef RADIOLIB_STATIC_ONLY + #if defined(RADIOLIB_STATIC_ONLY) char _str[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* _str; @@ -76,9 +76,9 @@ class ITA2String { }; // supported encoding schemes -#define ASCII 0 -#define ASCII_EXTENDED 1 -#define ITA2 2 +#define RADIOLIB_ASCII 0 +#define RADIOLIB_ASCII_EXTENDED 1 +#define RADIOLIB_ITA2 2 /*! \class RTTYClient @@ -120,7 +120,7 @@ class RTTYClient { \returns \ref status_codes */ - int16_t begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding = ASCII, uint8_t stopBits = 1); + int16_t begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding = RADIOLIB_ASCII, uint8_t stopBits = 1); /*! \brief Send out idle condition (RF tone at mark frequency). @@ -163,7 +163,7 @@ class RTTYClient { size_t println(unsigned long, int = DEC); size_t println(double, int = 2); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; @@ -171,7 +171,7 @@ class RTTYClient { AFSKClient* _audio; #endif - uint8_t _encoding = ASCII; + uint8_t _encoding = RADIOLIB_ASCII; uint32_t _base = 0, _baseHz = 0; uint32_t _shift = 0, _shiftHz = 0; uint32_t _bitDuration = 0; From 9504bc24ab9b888fc5e59c4e072c8228519c6d3c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:41:09 +0100 Subject: [PATCH 0046/1848] [SSTV] Update to 5.0.0 --- examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino | 4 +- .../SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino | 4 +- src/protocols/SSTV/SSTV.cpp | 53 ++++++++++--------- src/protocols/SSTV/SSTV.h | 42 +++++++-------- 4 files changed, 52 insertions(+), 51 deletions(-) diff --git a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino index 6b06bae37d..3a189c980b 100644 --- a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino +++ b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -91,7 +91,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.beginFSK(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -117,7 +117,7 @@ void setup() { // (lower number = shorter pulses). // The value is usually around 0.95 (95%). state = sstv.begin(434.0, Wrasse, 0.95); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino index e27bf67e38..8678fa7163 100644 --- a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -90,7 +90,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.beginFSK(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -115,7 +115,7 @@ void setup() { // (lower number = shorter pulses). // The value is usually around 0.95 (95%). state = sstv.begin(Wrasse, 0.95); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 51e8b950c7..ec5957c5c6 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SSTV) const SSTVMode_t Scottie1 { - .visCode = SSTV_SCOTTIE_1, + .visCode = RADIOLIB_SSTV_SCOTTIE_1, .width = 320, .height = 256, .scanPixelLen = 432, @@ -19,7 +19,7 @@ const SSTVMode_t Scottie1 { }; const SSTVMode_t Scottie2 { - .visCode = SSTV_SCOTTIE_2, + .visCode = RADIOLIB_SSTV_SCOTTIE_2, .width = 320, .height = 256, .scanPixelLen = 275, @@ -36,7 +36,7 @@ const SSTVMode_t Scottie2 { }; const SSTVMode_t ScottieDX { - .visCode = SSTV_SCOTTIE_DX, + .visCode = RADIOLIB_SSTV_SCOTTIE_DX, .width = 320, .height = 256, .scanPixelLen = 1080, @@ -53,7 +53,7 @@ const SSTVMode_t ScottieDX { }; const SSTVMode_t Martin1 { - .visCode = SSTV_MARTIN_1, + .visCode = RADIOLIB_SSTV_MARTIN_1, .width = 320, .height = 256, .scanPixelLen = 458, @@ -71,7 +71,7 @@ const SSTVMode_t Martin1 { }; const SSTVMode_t Martin2 { - .visCode = SSTV_MARTIN_2, + .visCode = RADIOLIB_SSTV_MARTIN_2, .width = 320, .height = 256, .scanPixelLen = 229, @@ -89,7 +89,7 @@ const SSTVMode_t Martin2 { }; const SSTVMode_t Wrasse { - .visCode = SSTV_WRASSE_SC2_180, + .visCode = RADIOLIB_SSTV_WRASSE_SC2_180, .width = 320, .height = 256, .scanPixelLen = 734, @@ -104,7 +104,7 @@ const SSTVMode_t Wrasse { }; const SSTVMode_t PasokonP3 { - .visCode = SSTV_PASOKON_P3, + .visCode = RADIOLIB_SSTV_PASOKON_P3, .width = 640, .height = 496, .scanPixelLen = 208, @@ -121,7 +121,7 @@ const SSTVMode_t PasokonP3 { }; const SSTVMode_t PasokonP5 { - .visCode = SSTV_PASOKON_P5, + .visCode = RADIOLIB_SSTV_PASOKON_P5, .width = 640, .height = 496, .scanPixelLen = 312, @@ -138,7 +138,7 @@ const SSTVMode_t PasokonP5 { }; const SSTVMode_t PasokonP7 { - .visCode = SSTV_PASOKON_P7, + .visCode = RADIOLIB_SSTV_PASOKON_P7, .width = 640, .height = 496, .scanPixelLen = 417, @@ -172,7 +172,7 @@ SSTVClient::SSTVClient(AFSKClient* audio) { int16_t SSTVClient::begin(const SSTVMode_t& mode, float correction) { if(_audio == nullptr) { // this initialization method can only be used in AFSK mode - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } return(begin(0, mode, correction)); @@ -198,7 +198,7 @@ int16_t SSTVClient::begin(float base, const SSTVMode_t& mode, float correction) void SSTVClient::idle() { _phy->transmitDirect(); - this->tone(SSTV_TONE_LEADER); + this->tone(RADIOLIB_SSTV_TONE_LEADER); } void SSTVClient::sendHeader() { @@ -207,44 +207,44 @@ void SSTVClient::sendHeader() { _phy->transmitDirect(); // send the first part of header (leader-break-leader) - this->tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); - this->tone(SSTV_TONE_BREAK, SSTV_HEADER_BREAK_LENGTH); - this->tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_LEADER, RADIOLIB_SSTV_HEADER_LEADER_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BREAK_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_LEADER, RADIOLIB_SSTV_HEADER_LEADER_LENGTH); // VIS start bit - this->tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BIT_LENGTH); // VIS code uint8_t parityCount = 0; for(uint8_t mask = 0x01; mask < 0x80; mask <<= 1) { if(_mode.visCode & mask) { - this->tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_VIS_1, RADIOLIB_SSTV_HEADER_BIT_LENGTH); parityCount++; } else { - this->tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_VIS_0, RADIOLIB_SSTV_HEADER_BIT_LENGTH); } } // VIS parity if(parityCount % 2 == 0) { // even parity - this->tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_VIS_0, RADIOLIB_SSTV_HEADER_BIT_LENGTH); } else { // odd parity - this->tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_VIS_1, RADIOLIB_SSTV_HEADER_BIT_LENGTH); } // VIS stop bit - this->tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); + this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BIT_LENGTH); } void SSTVClient::sendLine(uint32_t* imgLine) { // check first line flag in Scottie modes - if(_firstLine && ((_mode.visCode == SSTV_SCOTTIE_1) || (_mode.visCode == SSTV_SCOTTIE_2) || (_mode.visCode == SSTV_SCOTTIE_DX))) { + if(_firstLine && ((_mode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (_mode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (_mode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { _firstLine = false; // send start sync tone - this->tone(SSTV_TONE_BREAK, 9000); + this->tone(RADIOLIB_SSTV_TONE_BREAK, 9000); } // send all tones in sequence @@ -271,7 +271,7 @@ void SSTVClient::sendLine(uint32_t* imgLine) { case(tone_t::GENERIC): break; } - this->tone(SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen); + this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen); } } } @@ -282,7 +282,8 @@ uint16_t SSTVClient::getPictureHeight() const { } void SSTVClient::tone(float freq, uint32_t len) { - uint32_t start = Module::micros(); + Module* mod = _phy->getMod(); + uint32_t start = mod->micros(); #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { _audio->tone(freq, false); @@ -292,8 +293,8 @@ void SSTVClient::tone(float freq, uint32_t len) { #else _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); #endif - while(Module::micros() - start < len) { - Module::yield(); + while(mod->micros() - start < len) { + mod->yield(); } } diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index fb8fc27aa7..f24053e439 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -1,5 +1,5 @@ -#if !defined(_RADIOLIB_SSTV_H) -#define _RADIOLIB_SSTV_H +#if !defined(_RADIOLIB_RADIOLIB_SSTV_H) +#define _RADIOLIB_RADIOLIB_SSTV_H #include "../../TypeDef.h" @@ -12,28 +12,28 @@ // http://www.barberdsp.com/downloads/Dayton%20Paper.pdf // VIS codes -#define SSTV_SCOTTIE_1 60 -#define SSTV_SCOTTIE_2 56 -#define SSTV_SCOTTIE_DX 76 -#define SSTV_MARTIN_1 44 -#define SSTV_MARTIN_2 40 -#define SSTV_WRASSE_SC2_180 55 -#define SSTV_PASOKON_P3 113 -#define SSTV_PASOKON_P5 114 -#define SSTV_PASOKON_P7 115 +#define RADIOLIB_SSTV_SCOTTIE_1 60 +#define RADIOLIB_SSTV_SCOTTIE_2 56 +#define RADIOLIB_SSTV_SCOTTIE_DX 76 +#define RADIOLIB_SSTV_MARTIN_1 44 +#define RADIOLIB_SSTV_MARTIN_2 40 +#define RADIOLIB_SSTV_WRASSE_SC2_180 55 +#define RADIOLIB_SSTV_PASOKON_P3 113 +#define RADIOLIB_SSTV_PASOKON_P5 114 +#define RADIOLIB_SSTV_PASOKON_P7 115 // SSTV tones in Hz -#define SSTV_TONE_LEADER 1900 -#define SSTV_TONE_BREAK 1200 -#define SSTV_TONE_VIS_1 1100 -#define SSTV_TONE_VIS_0 1300 -#define SSTV_TONE_BRIGHTNESS_MIN 1500 -#define SSTV_TONE_BRIGHTNESS_MAX 2300 +#define RADIOLIB_SSTV_TONE_LEADER 1900 +#define RADIOLIB_SSTV_TONE_BREAK 1200 +#define RADIOLIB_SSTV_TONE_VIS_1 1100 +#define RADIOLIB_SSTV_TONE_VIS_0 1300 +#define RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN 1500 +#define RADIOLIB_SSTV_TONE_BRIGHTNESS_MAX 2300 // calibration header timing in us -#define SSTV_HEADER_LEADER_LENGTH 300000 -#define SSTV_HEADER_BREAK_LENGTH 10000 -#define SSTV_HEADER_BIT_LENGTH 30000 +#define RADIOLIB_SSTV_HEADER_LEADER_LENGTH 300000 +#define RADIOLIB_SSTV_HEADER_BREAK_LENGTH 10000 +#define RADIOLIB_SSTV_HEADER_BIT_LENGTH 30000 /*! \struct tone_t @@ -187,7 +187,7 @@ class SSTVClient { */ uint16_t getPictureHeight() const; -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; From bd5d824d7337e3d59d4aeae9061a4a88be7d6d15 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:41:27 +0100 Subject: [PATCH 0047/1848] [SX1231] Update to 5.0.0 --- .../SX1231/SX1231_Receive/SX1231_Receive.ino | 8 +++---- .../SX1231_Transmit/SX1231_Transmit.ino | 6 ++--- src/modules/SX1231/SX1231.cpp | 24 +++++++++---------- src/modules/SX1231/SX1231.h | 10 ++++---- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino index 18d0354c8b..cd3efea455 100644 --- a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino +++ b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino @@ -33,7 +33,7 @@ void setup() { // initialize SX1231 with default settings Serial.print(F("[SX1231] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -55,7 +55,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -63,11 +63,11 @@ void loop() { Serial.print(F("[SX1231] Data:\t\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino index 0f8cd14bcd..44db4556d7 100644 --- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino +++ b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino @@ -33,7 +33,7 @@ void setup() { // initialize SX1231 with default settings Serial.print(F("[SX1231] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -54,11 +54,11 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index 3148556f7f..1681d6bf50 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -7,9 +7,9 @@ SX1231::SX1231(Module* mod) : RF69(mod) { int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t preambleLen) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getRst(), OUTPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getRst(), OUTPUT); // try to find the SX1231 chip uint8_t i = 0; @@ -20,7 +20,7 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po flagFound = true; _chipRevision = version; } else { - #ifdef RADIOLIB_DEBUG + #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINT(F("SX1231 not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RF69_REG_VERSION == ")); @@ -31,15 +31,15 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po RADIOLIB_DEBUG_PRINT(F(", expected 0x0021 / 0x0022 / 0x0023")); RADIOLIB_DEBUG_PRINTLN(); #endif - Module::delay(10); + _mod->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN(F("M\tSX1231")); @@ -80,22 +80,22 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po // set default packet length mode state = variablePacketLengthMode(); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { return(state); } // SX1231 V2a only - if(_chipRevision == SX1231_CHIP_REVISION_2_A) { + if(_chipRevision == RADIOLIB_SX1231_CHIP_REVISION_2_A) { // modify default OOK threshold value - state = _mod->SPIsetRegValue(SX1231_REG_TEST_OOK, SX1231_OOK_DELTA_THRESHOLD); + state = _mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); RADIOLIB_ASSERT(state); // enable OCP with 95 mA limit - state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_ON | RF69_OCP_TRIM, 4, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); RADIOLIB_ASSERT(state); } - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } #endif diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX1231/SX1231.h index 5ad6ac9451..ada7dbb9b3 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX1231/SX1231.h @@ -8,15 +8,15 @@ #include "../../Module.h" #include "../RF69/RF69.h" -#define SX1231_CHIP_REVISION_2_A 0x21 -#define SX1231_CHIP_REVISION_2_B 0x22 -#define SX1231_CHIP_REVISION_2_C 0x23 +#define RADIOLIB_SX1231_CHIP_REVISION_2_A 0x21 +#define RADIOLIB_SX1231_CHIP_REVISION_2_B 0x22 +#define RADIOLIB_SX1231_CHIP_REVISION_2_C 0x23 //SX1231 specific register map -#define SX1231_REG_TEST_OOK 0x6E +#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E //SX1231_REG_TEST_OOK -#define SX1231_OOK_DELTA_THRESHOLD 0x0C +#define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C /*! \class SX1231 From 6f744a8f138dbce1586f31589753da4556204a4c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:41:53 +0100 Subject: [PATCH 0048/1848] [SX126x] Update to 5.0.0 --- .../SX126x_Channel_Activity_Detection.ino | 6 +- ...x_Channel_Activity_Detection_Interrupt.ino | 10 +- .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 18 +- .../SX126x_PingPong/SX126x_PingPong.ino | 10 +- .../SX126x/SX126x_Receive/SX126x_Receive.ino | 8 +- .../SX126x_Receive_Interrupt.ino | 8 +- .../SX126x_Settings/SX126x_Settings.ino | 26 +- .../SX126x_Transmit/SX126x_Transmit.ino | 8 +- .../SX126x_Transmit_Interrupt.ino | 6 +- src/modules/SX126x/SX1261.cpp | 8 +- src/modules/SX126x/SX1261.h | 4 +- src/modules/SX126x/SX1262.cpp | 30 +- src/modules/SX126x/SX1262.h | 8 +- src/modules/SX126x/SX1268.cpp | 22 +- src/modules/SX126x/SX1268.h | 8 +- src/modules/SX126x/SX126x.cpp | 700 +++++++++--------- src/modules/SX126x/SX126x.h | 626 ++++++++-------- 17 files changed, 754 insertions(+), 752 deletions(-) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino index b888a95d39..8a5b6e163f 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino @@ -35,7 +35,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -50,11 +50,11 @@ void loop() { // start scanning current channel int state = radio.scanChannel(); - if (state == LORA_DETECTED) { + if (state == RADIOLIB_LORA_DETECTED) { // LoRa preamble was detected Serial.println(F("detected!")); - } else if (state == CHANNEL_FREE) { + } else if (state == RADIOLIB_CHANNEL_FREE) { // no preamble was detected, channel is free Serial.println(F("channel is free!")); diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index 9d65ab247c..2598e68c43 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -35,7 +35,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -50,7 +50,7 @@ void setup() { // start scanning the channel Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); state = radio.startChannelScan(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -91,11 +91,11 @@ void loop() { // check CAD result int state = radio.getChannelScanResult(); - if (state == LORA_DETECTED) { + if (state == RADIOLIB_LORA_DETECTED) { // LoRa packet was detected Serial.println(F("[SX1262] Packet detected!")); - } else if (state == CHANNEL_FREE) { + } else if (state == RADIOLIB_CHANNEL_FREE) { // channel is free Serial.println(F("[SX1262] Channel is free!")); @@ -109,7 +109,7 @@ void loop() { // start scanning the channel again Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); state = radio.startChannelScan(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index d450f9c618..7231da009d 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -36,7 +36,7 @@ void setup() { // initialize SX1262 FSK modem with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.beginFSK(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -61,7 +61,7 @@ void setup() { uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; state = radio.setSyncWord(syncWord, 8); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); while (true); @@ -94,11 +94,11 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1262] Packet transmitted successfully!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { Serial.println(F("[SX1262] Packet too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { Serial.println(F("[SX1262] Timed out while transmitting!")); } else { Serial.println(F("[SX1262] Failed to transmit packet, code ")); @@ -112,11 +112,11 @@ void loop() { byte byteArr[8]; int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1262] Received packet!")); Serial.print(F("[SX1262] Data:\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("[SX1262] Timed out while waiting for packet!")); } else { Serial.println(F("[SX1262] Failed to receive packet, code ")); @@ -137,7 +137,7 @@ void loop() { state = radio.setNodeAddress(0x02); // set broadcast address to 0xFF state = radio.setBroadcastAddress(0xFF); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("[SX1262] Unable to set address filter, code ")); Serial.println(state); } @@ -147,7 +147,7 @@ void loop() { // node and broadcast address /* state = radio.disableAddressFiltering(); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("Unable to remove address filter, code ")); } */ diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index 946a175c69..1f0f8688fb 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -27,7 +27,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // save transmission states between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; // flag to indicate transmission or reception state bool transmitFlag = false; @@ -58,7 +58,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -79,7 +79,7 @@ void setup() { // start listening for LoRa packets on this node Serial.print(F("[SX1262] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -102,7 +102,7 @@ void loop() { if(transmitFlag) { // the previous operation was transmission, listen for response // print the result - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); @@ -122,7 +122,7 @@ void loop() { String str; int state = radio.readData(str); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1262] Received packet!")); diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino index 23969cb192..0c862e69f4 100644 --- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino +++ b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino @@ -40,7 +40,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -85,11 +85,11 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 3932f7b021..2a732d91b3 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -41,7 +41,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -56,7 +56,7 @@ void setup() { // start listening for LoRa packets Serial.print(F("[SX1262] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -115,7 +115,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1262] Received packet!")); @@ -133,7 +133,7 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index f485284f79..f33c9aa04a 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -51,7 +51,7 @@ void setup() { // initialize SX1268 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio1.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -72,7 +72,7 @@ void setup() { // output power: 2 dBm // preamble length: 20 symbols state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 20); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -84,56 +84,56 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); while (true); } // set bandwidth to 250 kHz - if (radio1.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) { + if (radio1.setBandwidth(250.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); while (true); } // set spreading factor to 10 - if (radio1.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); while (true); } // set coding rate to 6 - if (radio1.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); while (true); } // set LoRa sync word to 0xAB - if (radio1.setSyncWord(0xAB) != ERR_NONE) { + if (radio1.setSyncWord(0xAB) != RADIOLIB_ERR_NONE) { Serial.println(F("Unable to set sync word!")); while (true); } // set output power to 10 dBm (accepted range is -17 - 22 dBm) - if (radio1.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(10) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); while (true); } // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) // NOTE: set value to 0 to disable overcurrent protection - if (radio1.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) { + if (radio1.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { Serial.println(F("Selected current limit is invalid for this module!")); while (true); } // set LoRa preamble length to 15 symbols (accepted range is 0 - 65535) - if (radio1.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) { + if (radio1.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); while (true); } // disable CRC - if (radio1.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { + if (radio1.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { Serial.println(F("Selected CRC is invalid for this module!")); while (true); } @@ -141,7 +141,7 @@ void setup() { // Some SX126x modules have TCXO (temperature compensated crystal // oscillator). To configure TCXO reference voltage, // the following method can be used. - if (radio1.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) { + if (radio1.setTCXO(2.4) == RADIOLIB_ERR_INVALID_TCXO_VOLTAGE) { Serial.println(F("Selected TCXO voltage is invalid for this module!")); while (true); } @@ -150,7 +150,7 @@ void setup() { // this feature, the following method can be used. // NOTE: As long as DIO2 is configured to control RF switch, // it can't be used as interrupt pin! - if (radio1.setDio2AsRfSwitch() != ERR_NONE) { + if (radio1.setDio2AsRfSwitch() != RADIOLIB_ERR_NONE) { Serial.println(F("Failed to set DIO2 as RF switch!")); while (true); } diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino index 541645eef8..5b4c5d0d33 100644 --- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino +++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino @@ -36,7 +36,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -71,7 +71,7 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); @@ -80,11 +80,11 @@ void loop() { Serial.print(radio.getDataRate()); Serial.println(F(" bps")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { // timeout occured while transmitting packet Serial.println(F("timeout!")); diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 20600a1161..0ec70f65ee 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -32,7 +32,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -40,7 +40,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -97,7 +97,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index 1e0356512b..b3424f6fc2 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -6,15 +6,15 @@ SX1261::SX1261(Module* mod): SX1262(mod) { } int16_t SX1261::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -17, 14, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; - int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); // set PA config - state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261, 0x00); + state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1261, 0x00); RADIOLIB_ASSERT(state); // set output power @@ -23,7 +23,7 @@ int16_t SX1261::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // restore OCP configuration - return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } #endif diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 0f5262fdd5..1dcd6d1980 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -9,8 +9,8 @@ #include "SX126x.h" #include "SX1262.h" -//SX126X_CMD_SET_PA_CONFIG -#define SX126X_PA_CONFIG_SX1261 0x01 +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01 /*! \class SX1261 diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 0d78eea5c3..33422125ec 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -42,26 +42,26 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1262::setFrequency(float freq, bool calibrate) { - RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); // calibrate image if(calibrate) { uint8_t data[2]; if(freq > 900.0) { - data[0] = SX126X_CAL_IMG_902_MHZ_1; - data[1] = SX126X_CAL_IMG_902_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2; } else if(freq > 850.0) { - data[0] = SX126X_CAL_IMG_863_MHZ_1; - data[1] = SX126X_CAL_IMG_863_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; } else if(freq > 770.0) { - data[0] = SX126X_CAL_IMG_779_MHZ_1; - data[1] = SX126X_CAL_IMG_779_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; } else if(freq > 460.0) { - data[0] = SX126X_CAL_IMG_470_MHZ_1; - data[1] = SX126X_CAL_IMG_470_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; } else { - data[0] = SX126X_CAL_IMG_430_MHZ_1; - data[1] = SX126X_CAL_IMG_430_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; } int16_t state = SX126x::calibrateImage(data); RADIOLIB_ASSERT(state); @@ -72,15 +72,15 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) { } int16_t SX1262::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -17, 22, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -17, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; - int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); // set PA config - state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262); + state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1262); RADIOLIB_ASSERT(state); // set output power @@ -89,7 +89,7 @@ int16_t SX1262::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // restore OCP configuration - return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } #endif diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 3f5afd6cc5..f259065f5c 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -8,8 +8,8 @@ #include "../../Module.h" #include "SX126x.h" -//SX126X_CMD_SET_PA_CONFIG -#define SX126X_PA_CONFIG_SX1262 0x00 +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_SX1262 0x00 /*! \class SX1262 @@ -38,7 +38,7 @@ class SX1262: public SX126x { \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x12). + \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. @@ -48,7 +48,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 0addddf8cc..dfa65430a4 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -43,20 +43,20 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t /// \todo integers only (all modules - frequency, data rate, bandwidth etc.) int16_t SX1268::setFrequency(float freq, bool calibrate) { - RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); // calibrate image if(calibrate) { uint8_t data[2]; if(freq > 770.0) { - data[0] = SX126X_CAL_IMG_779_MHZ_1; - data[1] = SX126X_CAL_IMG_779_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; } else if(freq > 460.0) { - data[0] = SX126X_CAL_IMG_470_MHZ_1; - data[1] = SX126X_CAL_IMG_470_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; } else { - data[0] = SX126X_CAL_IMG_430_MHZ_1; - data[1] = SX126X_CAL_IMG_430_MHZ_2; + data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; } int16_t state = SX126x::calibrateImage(data); RADIOLIB_ASSERT(state); @@ -67,15 +67,15 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) { } int16_t SX1268::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -9, 22, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; - int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); // set PA config - state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268); + state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1268); RADIOLIB_ASSERT(state); // set output power @@ -84,7 +84,7 @@ int16_t SX1268::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // restore OCP configuration - return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } #endif diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 3803ec05a8..4b575342bf 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -8,8 +8,8 @@ #include "../../Module.h" #include "SX126x.h" -//SX126X_CMD_SET_PA_CONFIG -#define SX126X_PA_CONFIG_SX1268 0x00 +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_SX1268 0x00 /*! \class SX1268 @@ -38,7 +38,7 @@ class SX1268: public SX126x { \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x12). + \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. @@ -48,7 +48,7 @@ class SX1268: public SX126x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2c8dd3a0bf..2a308f1a8b 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1,15 +1,19 @@ #include "SX126x.h" #if !defined(RADIOLIB_EXCLUDE_SX126X) -SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_FREQUENCY_STEP_SIZE, SX126X_MAX_PACKET_LENGTH) { +SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { _mod = mod; } +Module* SX126x::getMod() { + return(_mod); +} + int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams @@ -17,13 +21,13 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 _sf = sf; // initialize configuration variables (will be overwritten during public settings configuration) - _bw = SX126X_LORA_BW_125_0; - _cr = SX126X_LORA_CR_4_7; + _bw = RADIOLIB_SX126X_LORA_BW_125_0; + _cr = RADIOLIB_SX126X_LORA_CR_4_7; _ldro = 0x00; - _crcType = SX126X_LORA_CRC_ON; + _crcType = RADIOLIB_SX126X_LORA_CRC_ON; _preambleLength = preambleLength; _tcxoDelay = 0; - _headerType = SX126X_LORA_HEADER_EXPLICIT; + _headerType = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT; _implicitLen = 0xFF; // reset the module and verify startup @@ -35,7 +39,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 RADIOLIB_ASSERT(state); // configure settings not accessible by API - state = config(SX126X_PACKET_TYPE_LORA); + state = config(RADIOLIB_SX126X_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // set TCXO control, if requested @@ -78,20 +82,20 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // initialize configuration variables (will be overwritten during public settings configuration) _br = 21333; // 48.0 kbps _freqDev = 52428; // 50.0 kHz - _rxBw = SX126X_GFSK_RX_BW_156_2; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_156_2; _rxBwKhz = 156.2; - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5; - _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration + _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; + _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration _preambleLengthFSK = preambleLength; - _addrComp = SX126X_GFSK_ADDRESS_FILT_OFF; + _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; // reset the module and verify startup int16_t state = reset(); @@ -102,7 +106,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL RADIOLIB_ASSERT(state); // configure settings not accessible by API - state = config(SX126X_PACKET_TYPE_GFSK); + state = config(RADIOLIB_SX126X_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); // set TCXO control, if requested @@ -145,7 +149,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL state = setEncoding(RADIOLIB_ENCODING_NRZ); RADIOLIB_ASSERT(state); - state = variablePacketLengthMode(SX126X_MAX_PACKET_LENGTH); + state = variablePacketLengthMode(RADIOLIB_SX126X_MAX_PACKET_LENGTH); RADIOLIB_ASSERT(state); state = setCRC(2); @@ -159,34 +163,34 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL int16_t SX126x::reset(bool verify) { // run the reset sequence - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), HIGH); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), LOW); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), HIGH); // return immediately when verification is disabled if(!verify) { - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } // set mode to standby - SX126x often refuses first few commands after reset - uint32_t start = Module::millis(); + uint32_t start = _mod->millis(); while(true) { // try to set mode to standby int16_t state = standby(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { // standby command successful - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } // standby command failed, check timeout and try again - if(Module::millis() - start >= 3000) { + if(_mod->millis() - start >= 3000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - Module::delay(10); + _mod->delay(10); } } @@ -196,24 +200,24 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // check packet length - if(len > SX126X_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } uint32_t timeout = 0; // get currently active modem uint8_t modem = getPacketType(); - if(modem == SX126X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // calculate timeout (150% of expected time-on-air) timeout = (getTimeOnAir(len) * 3) / 2; - } else if(modem == SX126X_PACKET_TYPE_GFSK) { + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // calculate timeout (500% of expected time-on-air) timeout = getTimeOnAir(len) * 5; } else { - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } RADIOLIB_DEBUG_PRINT(F("Timeout in ")); @@ -225,16 +229,16 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { clearIrqStatus(); standby(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } - uint32_t elapsed = Module::micros() - start; + uint32_t elapsed = _mod->micros() - start; // update data rate _dataRate = (len*8.0)/((float)elapsed/1000000.0); @@ -258,21 +262,21 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { // get currently active modem uint8_t modem = getPacketType(); - if(modem == SX126X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz; timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); - } else if(modem == SX126X_PACKET_TYPE_GFSK) { + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) size_t maxLen = len; if(len == 0) { maxLen = 0xFF; } - float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br; + float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br; timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0); } else { - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } RADIOLIB_DEBUG_PRINT(F("Timeout in ")); @@ -285,19 +289,19 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { fixImplicitTimeout(); clearIrqStatus(); standby(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } // fix timeout in implicit LoRa mode - if(((_headerType == SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == SX126X_PACKET_TYPE_LORA))) { + if(((_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { state = fixImplicitTimeout(); RADIOLIB_ASSERT(state); } @@ -311,15 +315,15 @@ int16_t SX126x::transmitDirect(uint32_t frf) { _mod->setRfSwitchState(LOW, HIGH); // user requested to start transmitting immediately (required for RTTY) - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(frf != 0) { state = setRfFrequency(frf); } RADIOLIB_ASSERT(state); // start transmitting - uint8_t data[] = {SX126X_CMD_NOP}; - return(SPIwriteCommand(SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); + uint8_t data[] = {RADIOLIB_SX126X_CMD_NOP}; + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); } int16_t SX126x::receiveDirect() { @@ -327,7 +331,7 @@ int16_t SX126x::receiveDirect() { _mod->setRfSwitchState(HIGH, LOW); // SX126x is unable to output received data directly - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX126x::scanChannel() { @@ -336,8 +340,8 @@ int16_t SX126x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); } // check CAD result @@ -348,20 +352,20 @@ int16_t SX126x::sleep(bool retainConfig) { // set RF switch (if present) _mod->setRfSwitchState(LOW, LOW); - uint8_t sleepMode = SX126X_SLEEP_START_WARM | SX126X_SLEEP_RTC_OFF; + uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF; if(!retainConfig) { - sleepMode = SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF; + sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; } - int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); + int16_t state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); // wait for SX126x to safely enter sleep mode - Module::delay(1); + _mod->delay(1); return(state); } int16_t SX126x::standby() { - return(SX126x::standby(SX126X_STANDBY_RC)); + return(SX126x::standby(RADIOLIB_SX126X_STANDBY_RC)); } int16_t SX126x::standby(uint8_t mode) { @@ -369,15 +373,15 @@ int16_t SX126x::standby(uint8_t mode) { _mod->setRfSwitchState(LOW, LOW); uint8_t data[] = {mode}; - return(SPIwriteCommand(SX126X_CMD_SET_STANDBY, data, 1)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } void SX126x::setDio1Action(void (*func)(void)) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void SX126x::clearDio1Action() { - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -385,29 +389,29 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { (void)addr; // check packet length - if(len > SX126X_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // maximum packet length is decreased by 1 when address filtering is active - if((_addrComp != SX126X_GFSK_ADDRESS_FILT_OFF) && (len > SX126X_MAX_PACKET_LENGTH - 1)) { - return(ERR_PACKET_TOO_LONG); + if((_addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set packet Length - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = getPacketType(); - if(modem == SX126X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { state = setPacketParams(_preambleLength, _crcType, len, _headerType); - } else if(modem == SX126X_PACKET_TYPE_GFSK) { + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType, len); } else { - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } RADIOLIB_ASSERT(state); // set DIO mapping - state = setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE); + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE); RADIOLIB_ASSERT(state); // set buffer pointers @@ -430,12 +434,12 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->setRfSwitchState(LOW, HIGH); // start transmission - state = setTx(SX126X_TX_TIMEOUT_NONE); + state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); } return(state); @@ -465,12 +469,12 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) { // check 24 bit limit and zero value (likely not intended) if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) { - return(ERR_INVALID_RX_PERIOD); + return(RADIOLIB_ERR_INVALID_RX_PERIOD); } // this check of the high byte also catches underflow when we subtracted transitionTime if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) { - return(ERR_INVALID_SLEEP_PERIOD); + return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD); } int16_t state = startReceiveCommon(); @@ -478,7 +482,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) { uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), (uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)}; - return(SPIwriteCommand(SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); } int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols) { @@ -523,7 +527,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ int16_t SX126x::startReceiveCommon() { // set DIO mapping - int16_t state = setDioIrqParams(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR | SX126X_IRQ_HEADER_ERR, SX126X_IRQ_RX_DONE); + int16_t state = setDioIrqParams(RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT | RADIOLIB_SX126X_IRQ_CRC_ERR | RADIOLIB_SX126X_IRQ_HEADER_ERR, RADIOLIB_SX126X_IRQ_RX_DONE); RADIOLIB_ASSERT(state); // set buffer pointers @@ -535,12 +539,12 @@ int16_t SX126x::startReceiveCommon() { // restore original packet length uint8_t modem = getPacketType(); - if(modem == SX126X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { state = setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType); - } else if(modem == SX126X_PACKET_TYPE_GFSK) { + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); } else { - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } return(state); @@ -553,14 +557,14 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { // check integrity CRC uint16_t irq = getIrqStatus(); - int16_t crcState = ERR_NONE; - if((irq & SX126X_IRQ_CRC_ERR) || (irq & SX126X_IRQ_HEADER_ERR)) { - crcState = ERR_CRC_MISMATCH; + int16_t crcState = RADIOLIB_ERR_NONE; + if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || (irq & RADIOLIB_SX126X_IRQ_HEADER_ERR)) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; } // get packet length size_t length = len; - if(len == SX126X_MAX_PACKET_LENGTH) { + if(len == RADIOLIB_SX126X_MAX_PACKET_LENGTH) { length = getPacketLength(); } @@ -579,8 +583,8 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { int16_t SX126x::startChannelScan() { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -591,7 +595,7 @@ int16_t SX126x::startChannelScan() { _mod->setRfSwitchState(HIGH, LOW); // set DIO pin mapping - state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE); + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE, RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -605,69 +609,69 @@ int16_t SX126x::startChannelScan() { int16_t SX126x::getChannelScanResult() { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check CAD result uint16_t cadResult = getIrqStatus(); - if(cadResult & SX126X_IRQ_CAD_DETECTED) { + if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DETECTED) { // detected some LoRa activity clearIrqStatus(); - return(LORA_DETECTED); - } else if(cadResult & SX126X_IRQ_CAD_DONE) { + return(RADIOLIB_LORA_DETECTED); + } else if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DONE) { // channel is free clearIrqStatus(); - return(CHANNEL_FREE); + return(RADIOLIB_CHANNEL_FREE); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX126x::setBandwidth(float bw) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // ensure byte conversion doesn't overflow - RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); // check allowed bandwidth values uint8_t bw_div2 = bw / 2 + 0.01; switch (bw_div2) { case 3: // 7.8: - _bw = SX126X_LORA_BW_7_8; + _bw = RADIOLIB_SX126X_LORA_BW_7_8; break; case 5: // 10.4: - _bw = SX126X_LORA_BW_10_4; + _bw = RADIOLIB_SX126X_LORA_BW_10_4; break; case 7: // 15.6: - _bw = SX126X_LORA_BW_15_6; + _bw = RADIOLIB_SX126X_LORA_BW_15_6; break; case 10: // 20.8: - _bw = SX126X_LORA_BW_20_8; + _bw = RADIOLIB_SX126X_LORA_BW_20_8; break; case 15: // 31.25: - _bw = SX126X_LORA_BW_31_25; + _bw = RADIOLIB_SX126X_LORA_BW_31_25; break; case 20: // 41.7: - _bw = SX126X_LORA_BW_41_7; + _bw = RADIOLIB_SX126X_LORA_BW_41_7; break; case 31: // 62.5: - _bw = SX126X_LORA_BW_62_5; + _bw = RADIOLIB_SX126X_LORA_BW_62_5; break; case 62: // 125.0: - _bw = SX126X_LORA_BW_125_0; + _bw = RADIOLIB_SX126X_LORA_BW_125_0; break; case 125: // 250.0 - _bw = SX126X_LORA_BW_250_0; + _bw = RADIOLIB_SX126X_LORA_BW_250_0; break; case 250: // 500.0 - _bw = SX126X_LORA_BW_500_0; + _bw = RADIOLIB_SX126X_LORA_BW_500_0; break; default: - return(ERR_INVALID_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // update modulation parameters @@ -677,11 +681,11 @@ int16_t SX126x::setBandwidth(float bw) { int16_t SX126x::setSpreadingFactor(uint8_t sf) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(sf, 5, 12, ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); // update modulation parameters _sf = sf; @@ -690,11 +694,11 @@ int16_t SX126x::setSpreadingFactor(uint8_t sf) { int16_t SX126x::setCodingRate(uint8_t cr) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters _cr = cr - 4; @@ -703,32 +707,32 @@ int16_t SX126x::setCodingRate(uint8_t cr) { int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // update register uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; - return(writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)); + return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)); } int16_t SX126x::setCurrentLimit(float currentLimit) { // check allowed range if(!((currentLimit >= 0) && (currentLimit <= 140))) { - return(ERR_INVALID_CURRENT_LIMIT); + return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT); } // calculate raw value uint8_t rawLimit = (uint8_t)(currentLimit / 2.5); // update register - return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1)); } float SX126x::getCurrentLimit() { // get the raw value uint8_t ocp = 0; - readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); // return the actual value return((float)ocp * 2.5); @@ -736,21 +740,21 @@ float SX126x::getCurrentLimit() { int16_t SX126x::setPreambleLength(uint16_t preambleLength) { uint8_t modem = getPacketType(); - if(modem == SX126X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { _preambleLength = preambleLength; return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType)); - } else if(modem == SX126X_PACKET_TYPE_GFSK) { + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { _preambleLengthFSK = preambleLength; return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType)); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX126x::setFrequencyDeviation(float freqDev) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set frequency deviation to lowest available setting (required for digimodes) @@ -759,14 +763,14 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { newFreqDev = 0.6; } - RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // calculate raw frequency deviation value - uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0)); + uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0)); // check modulation parameters /*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) { - return(ERR_INVALID_MODULATION_PARAMETERS); + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); }*/ _freqDev = freqDevRaw; @@ -776,18 +780,18 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { int16_t SX126x::setBitRate(float br) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); // calculate raw bit rate value - uint32_t brRaw = (uint32_t)((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); + uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); // check modulation parameters /*if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) { - return(ERR_INVALID_MODULATION_PARAMETERS); + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); }*/ _br = brRaw; @@ -797,61 +801,61 @@ int16_t SX126x::setBitRate(float br) { int16_t SX126x::setRxBandwidth(float rxBw) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation parameters /*if(2 * _freqDev + _br > rxBw * 1000.0) { - return(ERR_INVALID_MODULATION_PARAMETERS); + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); }*/ _rxBwKhz = rxBw; // check allowed receiver bandwidth values if(fabs(rxBw - 4.8) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_4_8; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_4_8; } else if(fabs(rxBw - 5.8) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_5_8; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_5_8; } else if(fabs(rxBw - 7.3) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_7_3; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_7_3; } else if(fabs(rxBw - 9.7) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_9_7; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_9_7; } else if(fabs(rxBw - 11.7) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_11_7; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_11_7; } else if(fabs(rxBw - 14.6) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_14_6; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_14_6; } else if(fabs(rxBw - 19.5) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_19_5; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_19_5; } else if(fabs(rxBw - 23.4) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_23_4; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_23_4; } else if(fabs(rxBw - 29.3) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_29_3; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_29_3; } else if(fabs(rxBw - 39.0) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_39_0; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_39_0; } else if(fabs(rxBw - 46.9) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_46_9; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_46_9; } else if(fabs(rxBw - 58.6) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_58_6; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_58_6; } else if(fabs(rxBw - 78.2) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_78_2; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_78_2; } else if(fabs(rxBw - 93.8) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_93_8; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_93_8; } else if(fabs(rxBw - 117.3) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_117_3; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_117_3; } else if(fabs(rxBw - 156.2) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_156_2; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_156_2; } else if(fabs(rxBw - 187.2) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_187_2; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_187_2; } else if(fabs(rxBw - 234.3) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_234_3; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_234_3; } else if(fabs(rxBw - 312.0) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_312_0; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_312_0; } else if(fabs(rxBw - 373.6) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_373_6; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_373_6; } else if(fabs(rxBw - 467.0) <= 0.001) { - _rxBw = SX126X_GFSK_RX_BW_467_0; + _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_467_0; } else { - return(ERR_INVALID_RX_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } // update modulation parameters @@ -860,29 +864,29 @@ int16_t SX126x::setRxBandwidth(float rxBw) { int16_t SX126x::setDataShaping(uint8_t sh) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - _pulseShape = SX126X_GFSK_FILTER_NONE; + _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE; break; case RADIOLIB_SHAPING_0_3: - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_3; + _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3; break; case RADIOLIB_SHAPING_0_5: - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5; + _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; break; case RADIOLIB_SHAPING_0_7: - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_7; + _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7; break; case RADIOLIB_SHAPING_1_0: - _pulseShape = SX126X_GFSK_FILTER_GAUSS_1; + _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; break; default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } // update modulation parameters @@ -891,17 +895,17 @@ int16_t SX126x::setDataShaping(uint8_t sh) { int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check sync word Length if(len > 8) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } // write sync word - int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, len); + int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len); RADIOLIB_ASSERT(state); // update packet parameters @@ -913,13 +917,13 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) { int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check sync word Length if(bitsLen > 0x40) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } uint8_t bytesLen = bitsLen / 8; @@ -928,7 +932,7 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { } // write sync word - int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, bytesLen); + int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, bytesLen); RADIOLIB_ASSERT(state); // update packet parameters @@ -940,46 +944,46 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { int16_t SX126x::setNodeAddress(uint8_t nodeAddr) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // enable address filtering (node only) - _addrComp = SX126X_GFSK_ADDRESS_FILT_NODE; + _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE; int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); RADIOLIB_ASSERT(state); // set node address - state = writeRegister(SX126X_REG_NODE_ADDRESS, &nodeAddr, 1); + state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &nodeAddr, 1); return(state); } int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // enable address filtering (node and broadcast) - _addrComp = SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; + _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); RADIOLIB_ASSERT(state); // set broadcast address - state = writeRegister(SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1); + state = writeRegister(RADIOLIB_SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1); return(state); } int16_t SX126x::disableAddressFiltering() { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // disable address filtering - _addrComp = SX126X_GFSK_ADDRESS_FILT_OFF; + _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening)); } @@ -987,28 +991,28 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool // check active modem uint8_t modem = getPacketType(); - if(modem == SX126X_PACKET_TYPE_GFSK) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // update packet parameters switch(len) { case 0: - _crcTypeFSK = SX126X_GFSK_CRC_OFF; + _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF; break; case 1: if(inverted) { - _crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV; + _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV; } else { - _crcTypeFSK = SX126X_GFSK_CRC_1_BYTE; + _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE; } break; case 2: if(inverted) { - _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV; + _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; } else { - _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE; + _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE; } break; default: - return(ERR_INVALID_CRC_CONFIGURATION); + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); @@ -1016,61 +1020,61 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool // write initial CRC value uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)}; - state = writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2); + state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2); RADIOLIB_ASSERT(state); // write CRC polynomial value data[0] = (uint8_t)((polynomial >> 8) & 0xFF); data[1] = (uint8_t)(polynomial & 0xFF); - state = writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2); + state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2); return(state); - } else if(modem == SX126X_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion // update packet parameters if(len) { - _crcType = SX126X_LORA_CRC_ON; + _crcType = RADIOLIB_SX126X_LORA_CRC_ON; } else { - _crcType = SX126X_LORA_CRC_OFF; + _crcType = RADIOLIB_SX126X_LORA_CRC_OFF; } return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType)); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(!enabled) { // disable whitening - _whitening = SX126X_GFSK_WHITENING_OFF; + _whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); RADIOLIB_ASSERT(state); } else { // enable whitening - _whitening = SX126X_GFSK_WHITENING_ON; + _whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON; // write initial whitening value // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register" uint8_t data[2]; // first read the actual value and mask 7 MSB which we can not change // if different value is written in 7 MSB, the Rx won't even work (tested on HW) - state = readRegister(SX126X_REG_WHITENING_INITIAL_MSB, data, 1); + state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1); RADIOLIB_ASSERT(state); data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01); data[1] = (uint8_t)(initial & 0xFF); - state = writeRegister(SX126X_REG_WHITENING_INITIAL_MSB, data, 2); + state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); RADIOLIB_ASSERT(state); state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); @@ -1092,8 +1096,8 @@ float SX126x::getRSSI() { float SX126x::getSNR() { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // get last packet SNR from packet status @@ -1109,22 +1113,22 @@ float SX126x::getSNR() { size_t SX126x::getPacketLength(bool update) { (void)update; uint8_t rxBufStatus[2] = {0, 0}; - SPIreadCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } int16_t SX126x::fixedPacketLengthMode(uint8_t len) { - return(setPacketMode(SX126X_GFSK_PACKET_FIXED, len)); + return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len)); } int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { - return(setPacketMode(SX126X_GFSK_PACKET_VARIABLE, maxLen)); + return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen)); } uint32_t SX126x::getTimeOnAir(size_t len) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact - if(getPacketType() == SX126X_PACKET_TYPE_LORA) { + if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) { uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << _sf) / (_bwKhz * 10) ; uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) uint8_t sfCoeff2 = 8; @@ -1137,7 +1141,7 @@ uint32_t SX126x::getTimeOnAir(size_t len) { sfDivisor = 4*(_sf - 2); } const int8_t bitsPerCrc = 16; - const int8_t N_symbol_header = _headerType == SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; + const int8_t N_symbol_header = _headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) int16_t bitCount = (int16_t) 8 * len + _crcType * bitsPerCrc - 4 * _sf + sfCoeff2 + N_symbol_header; @@ -1152,31 +1156,31 @@ uint32_t SX126x::getTimeOnAir(size_t len) { return((symbolLength_us * nSymbol_x4) / 4); } else { - return((len * 8 * _br) / (SX126X_CRYSTAL_FREQ * 32)); + return((len * 8 * _br) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); } } float SX126x::getRSSIInst() { uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU - SPIreadCommand(SX126X_CMD_GET_RSSI_INST, data, 3); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); return (float)data[0] / (-2.0); } int16_t SX126x::implicitHeader(size_t len) { - return(setHeaderType(SX126X_LORA_HEADER_IMPLICIT, len)); + return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len)); } int16_t SX126x::explicitHeader() { - return(setHeaderType(SX126X_LORA_HEADER_EXPLICIT)); + return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT)); } int16_t SX126x::setRegulatorLDO() { - return(setRegulatorMode(SX126X_REGULATOR_LDO)); + return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO)); } int16_t SX126x::setRegulatorDCDC() { - return(setRegulatorMode(SX126X_REGULATOR_DC_DC)); + return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC)); } int16_t SX126x::setEncoding(uint8_t encoding) { @@ -1189,8 +1193,8 @@ void SX126x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { int16_t SX126x::forceLDRO(bool enable) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // update modulation parameters @@ -1200,26 +1204,26 @@ int16_t SX126x::forceLDRO(bool enable) { } int16_t SX126x::autoLDRO() { - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } _ldroAuto = true; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } uint8_t SX126x::randomByte() { // set mode to Rx - setRx(SX126X_RX_TIMEOUT_INF); + setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); // wait a bit for the RSSI reading to stabilise - Module::delay(10); + _mod->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { uint8_t val = 0x00; - readRegister(SX126X_REG_RANDOM_NUMBER_0, &val, sizeof(uint8_t)); + readRegister(RADIOLIB_SX126X_REG_RANDOM_NUMBER_0, &val, sizeof(uint8_t)); randByte |= ((val & 0x01) << i); } @@ -1245,8 +1249,8 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { // set mode to standby standby(); - // check SX126X_XOSC_START_ERR flag and clear it - if(getDeviceErrors() & SX126X_XOSC_START_ERR) { + // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it + if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) { clearDeviceErrors(); } @@ -1258,23 +1262,23 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { // check alowed voltage values uint8_t data[4]; if(fabs(voltage - 1.6) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_1_6; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6; } else if(fabs(voltage - 1.7) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_1_7; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7; } else if(fabs(voltage - 1.8) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_1_8; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8; } else if(fabs(voltage - 2.2) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_2_2; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2; } else if(fabs(voltage - 2.4) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_2_4; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4; } else if(fabs(voltage - 2.7) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_2_7; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7; } else if(fabs(voltage - 3.0) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_3_0; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0; } else if(fabs(voltage - 3.3) <= 0.001) { - data[0] = SX126X_DIO3_OUTPUT_3_3; + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3; } else { - return(ERR_INVALID_TCXO_VOLTAGE); + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); } // calculate delay @@ -1286,55 +1290,55 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { _tcxoDelay = delay; // enable TCXO control on DIO3 - return(SPIwriteCommand(SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); } int16_t SX126x::setDio2AsRfSwitch(bool enable) { uint8_t data = 0; if(enable) { - data = SX126X_DIO2_AS_RF_SWITCH; + data = RADIOLIB_SX126X_DIO2_AS_RF_SWITCH; } else { - data = SX126X_DIO2_AS_IRQ; + data = RADIOLIB_SX126X_DIO2_AS_IRQ; } - return(SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } int16_t SX126x::setTx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; - return(SPIwriteCommand(SX126X_CMD_SET_TX, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); } int16_t SX126x::setRx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; - return(SPIwriteCommand(SX126X_CMD_SET_RX, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX, data, 3)); } int16_t SX126x::setCad() { - return(SPIwriteCommand(SX126X_CMD_SET_CAD, NULL, 0)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); } int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; - return(SPIwriteCommand(SX126X_CMD_SET_PA_CONFIG, data, 4)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); } int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; return(SPIwriteCommand(cmd, 3, data, numBytes)); } int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; return(SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true)); } int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - uint8_t cmd[] = { SX126X_CMD_WRITE_BUFFER, offset }; + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; return(SPIwriteCommand(cmd, 2, data, numBytes)); } int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { SX126X_CMD_READ_BUFFER, SX126X_CMD_NOP }; + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, RADIOLIB_SX126X_CMD_NOP }; return(SPIreadCommand(cmd, 2, data, numBytes)); } @@ -1343,44 +1347,44 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; - return(SPIwriteCommand(SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } uint16_t SX126x::getIrqStatus() { uint8_t data[] = { 0x00, 0x00 }; - SPIreadCommand(SX126X_CMD_GET_IRQ_STATUS, data, 2); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(SPIwriteCommand(SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX126x::setRfFrequency(uint32_t frf) { uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(SPIwriteCommand(SX126X_CMD_SET_RF_FREQUENCY, data, 4)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } int16_t SX126x::calibrateImage(uint8_t* data) { - return(SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2)); } uint8_t SX126x::getPacketType() { uint8_t data = 0xFF; - SPIreadCommand(SX126X_CMD_GET_PACKET_TYPE, &data, 1); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); return(data); } int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) { uint8_t data[] = { power, rampTime }; - return(SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set requested packet mode @@ -1394,8 +1398,8 @@ int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { int16_t SX126x::setHeaderType(uint8_t headerType, size_t len) { // check active modem - if(getPacketType() != SX126X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set requested packet mode @@ -1417,76 +1421,76 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t RADIOLIB_DEBUG_PRINT(symbolLength); RADIOLIB_DEBUG_PRINTLN(" ms"); if(symbolLength >= 16.0) { - _ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; + _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; } else { - _ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; + _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; } } else { _ldro = ldro; } uint8_t data[4] = {sf, bw, cr, _ldro}; - return(SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); } int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), pulseShape, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; - return(SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); } int16_t SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) { int16_t state = fixInvertedIQ(invertIQ); RADIOLIB_ASSERT(state); uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ}; - return(SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 6)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); } int16_t SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType, uint8_t payloadLength, uint8_t preambleDetectorLength) { uint8_t data[9] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), preambleDetectorLength, syncWordLength, addrComp, packetType, payloadLength, crcType, whitening}; - return(SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 9)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); } int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { uint8_t data[2] = {txBaseAddress, rxBaseAddress}; - return(SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX126x::setRegulatorMode(uint8_t mode) { uint8_t data[1] = {mode}; - return(SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); } uint8_t SX126x::getStatus() { uint8_t data = 0; - SPIreadCommand(SX126X_CMD_GET_STATUS, &data, 1); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1); return(data); } uint32_t SX126x::getPacketStatus() { uint8_t data[3] = {0, 0, 0}; - SPIreadCommand(SX126X_CMD_GET_PACKET_STATUS, data, 3); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]); } uint16_t SX126x::getDeviceErrors() { uint8_t data[2] = {0, 0}; - SPIreadCommand(SX126X_CMD_GET_DEVICE_ERRORS, data, 2); + SPIreadCommand(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) & ((uint16_t)data[1]); return(opError); } int16_t SX126x::clearDeviceErrors() { - uint8_t data[2] = {SX126X_CMD_NOP, SX126X_CMD_NOP}; - return(SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); + uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); } int16_t SX126x::setFrequencyRaw(float freq) { // calculate raw value - uint32_t frf = (freq * (uint32_t(1) << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ; + uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; return(setRfFrequency(frf)); } @@ -1496,16 +1500,16 @@ int16_t SX126x::fixSensitivity() { // read current sensitivity configuration uint8_t sensitivityConfig = 0; - int16_t state = readRegister(SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1); RADIOLIB_ASSERT(state); // fix the value for LoRa with 500 kHz bandwidth - if((getPacketType() == SX126X_PACKET_TYPE_LORA) && (fabs(_bwKhz - 500.0) <= 0.001)) { + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabs(_bwKhz - 500.0) <= 0.001)) { sensitivityConfig &= 0xFB; } else { sensitivityConfig |= 0x04; } - return(writeRegister(SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1)); } int16_t SX126x::fixPaClamping() { @@ -1514,12 +1518,12 @@ int16_t SX126x::fixPaClamping() { // read current clamping configuration uint8_t clampConfig = 0; - int16_t state = readRegister(SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1); RADIOLIB_ASSERT(state); // update with the new value clampConfig |= 0x1E; - return(writeRegister(SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1)); } int16_t SX126x::fixImplicitTimeout() { @@ -1527,23 +1531,23 @@ int16_t SX126x::fixImplicitTimeout() { // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.3 for details //check if we're in implicit LoRa mode - if(!((_headerType == SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == SX126X_PACKET_TYPE_LORA))) { - return(ERR_WRONG_MODEM); + if(!((_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { + return(RADIOLIB_ERR_WRONG_MODEM); } // stop RTC counter uint8_t rtcStop = 0x00; - int16_t state = writeRegister(SX126X_REG_RTC_STOP, &rtcStop, 1); + int16_t state = writeRegister(RADIOLIB_SX126X_REG_RTC_STOP, &rtcStop, 1); RADIOLIB_ASSERT(state); // read currently active event uint8_t rtcEvent = 0; - state = readRegister(SX126X_REG_RTC_EVENT, &rtcEvent, 1); + state = readRegister(RADIOLIB_SX126X_REG_RTC_EVENT, &rtcEvent, 1); RADIOLIB_ASSERT(state); // clear events rtcEvent |= 0x02; - return(writeRegister(SX126X_REG_RTC_EVENT, &rtcEvent, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_RTC_EVENT, &rtcEvent, 1)); } int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { @@ -1552,18 +1556,18 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { // read current IQ configuration uint8_t iqConfigCurrent = 0; - int16_t state = readRegister(SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1); RADIOLIB_ASSERT(state); // set correct IQ configuration - if(iqConfig == SX126X_LORA_IQ_STANDARD) { + if(iqConfig == RADIOLIB_SX126X_LORA_IQ_STANDARD) { iqConfigCurrent &= 0xFB; } else { iqConfigCurrent |= 0x04; } // update with the new value - return(writeRegister(SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1)); } int16_t SX126x::config(uint8_t modem) { @@ -1574,42 +1578,42 @@ int16_t SX126x::config(uint8_t modem) { // set modem uint8_t data[7]; data[0] = modem; - state = SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1); + state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); RADIOLIB_ASSERT(state); // set Rx/Tx fallback mode to STDBY_RC - data[0] = SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; - state = SPIwriteCommand(SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); + data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; + state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); // set CAD parameters - data[0] = SX126X_CAD_ON_8_SYMB; + data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; data[1] = _sf + 13; data[2] = 10; - data[3] = SX126X_CAD_GOTO_STDBY; + data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[4] = 0x00; data[5] = 0x00; data[6] = 0x00; - state = SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7); + state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); // clear IRQ state = clearIrqStatus(); - state |= setDioIrqParams(SX126X_IRQ_NONE, SX126X_IRQ_NONE); + state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); RADIOLIB_ASSERT(state); // calibrate all blocks - data[0] = SX126X_CALIBRATE_ALL; - state = SPIwriteCommand(SX126X_CMD_CALIBRATE, data, 1); + data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; + state = SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1); RADIOLIB_ASSERT(state); // wait for calibration completion - Module::delay(5); - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); + _mod->delay(5); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); } - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { @@ -1629,33 +1633,29 @@ int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, boo } int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { - // get pointer to used SPI interface and the settings - SPIClass* spi = _mod->getSpi(); - SPISettings spiSettings = _mod->getSpiSettings(); - - #ifdef RADIOLIB_VERBOSE + #if defined(RADIOLIB_VERBOSE) uint8_t debugBuff[256]; #endif // pull NSS low - Module::digitalWrite(_mod->getCs(), LOW); + _mod->digitalWrite(_mod->getCs(), LOW); // ensure BUSY is low (state machine ready) - uint32_t start = Module::millis(); - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); - if(Module::millis() - start >= timeout) { - Module::digitalWrite(_mod->getCs(), HIGH); - return(ERR_SPI_CMD_TIMEOUT); + uint32_t start = _mod->millis(); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); + if(_mod->millis() - start >= timeout) { + _mod->digitalWrite(_mod->getCs(), HIGH); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } // start transfer - spi->beginTransaction(spiSettings); + _mod->SPIbeginTransaction(); // send command byte(s) for(uint8_t n = 0; n < cmdLen; n++) { - spi->transfer(cmd[n]); + _mod->SPItransfer(cmd[n]); } // variable to save error during SPI transfer @@ -1665,63 +1665,63 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d if(write) { for(uint8_t n = 0; n < numBytes; n++) { // send byte - uint8_t in = spi->transfer(dataOut[n]); - #ifdef RADIOLIB_VERBOSE + uint8_t in = _mod->SPItransfer(dataOut[n]); + #if defined(RADIOLIB_VERBOSE) debugBuff[n] = in; #endif // check status - if(((in & 0b00001110) == SX126X_STATUS_CMD_TIMEOUT) || - ((in & 0b00001110) == SX126X_STATUS_CMD_INVALID) || - ((in & 0b00001110) == SX126X_STATUS_CMD_FAILED)) { + if(((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) || + ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) || + ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED)) { status = in & 0b00001110; break; } else if(in == 0x00 || in == 0xFF) { - status = SX126X_STATUS_SPI_FAILED; + status = RADIOLIB_SX126X_STATUS_SPI_FAILED; break; } } } else { // skip the first byte for read-type commands (status-only) - uint8_t in = spi->transfer(SX126X_CMD_NOP); - #ifdef RADIOLIB_VERBOSE + uint8_t in = _mod->SPItransfer(RADIOLIB_SX126X_CMD_NOP); + #if defined(RADIOLIB_VERBOSE) debugBuff[0] = in; #endif // check status - if(((in & 0b00001110) == SX126X_STATUS_CMD_TIMEOUT) || - ((in & 0b00001110) == SX126X_STATUS_CMD_INVALID) || - ((in & 0b00001110) == SX126X_STATUS_CMD_FAILED)) { + if(((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) || + ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) || + ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED)) { status = in & 0b00001110; } else if(in == 0x00 || in == 0xFF) { - status = SX126X_STATUS_SPI_FAILED; + status = RADIOLIB_SX126X_STATUS_SPI_FAILED; } else { for(uint8_t n = 0; n < numBytes; n++) { - dataIn[n] = spi->transfer(SX126X_CMD_NOP); + dataIn[n] = _mod->SPItransfer(RADIOLIB_SX126X_CMD_NOP); } } } // stop transfer - spi->endTransaction(); - Module::digitalWrite(_mod->getCs(), HIGH); + _mod->SPIendTransaction(); + _mod->digitalWrite(_mod->getCs(), HIGH); // wait for BUSY to go high and then low if(waitForBusy) { - Module::delayMicroseconds(1); - start = Module::millis(); - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); - if(Module::millis() - start >= timeout) { - status = SX126X_STATUS_CMD_TIMEOUT; + _mod->delayMicroseconds(1); + start = _mod->millis(); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); + if(_mod->millis() - start >= timeout) { + status = RADIOLIB_SX126X_STATUS_CMD_TIMEOUT; break; } } } // print debug output - #ifdef RADIOLIB_VERBOSE + #if defined(RADIOLIB_VERBOSE) // print command byte(s) RADIOLIB_VERBOSE_PRINT("CMD\t"); for(uint8_t n = 0; n < cmdLen; n++) { @@ -1744,13 +1744,13 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d } else { RADIOLIB_VERBOSE_PRINT("R\t"); // skip the first byte for read-type commands (status-only) - RADIOLIB_VERBOSE_PRINT(SX126X_CMD_NOP, HEX); + RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX126X_CMD_NOP, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); RADIOLIB_VERBOSE_PRINT('\t') for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(SX126X_CMD_NOP, HEX); + RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX126X_CMD_NOP, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); @@ -1763,22 +1763,22 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // not sure why, but it seems that long enough SPI transaction // (e.g. setPacketParams for GFSK) will fail without it #if defined(RADIOLIB_SPI_SLOWDOWN) - Module::delay(1); + _mod->delay(1); #endif #endif // parse status switch(status) { - case SX126X_STATUS_CMD_TIMEOUT: - return(ERR_SPI_CMD_TIMEOUT); - case SX126X_STATUS_CMD_INVALID: - return(ERR_SPI_CMD_INVALID); - case SX126X_STATUS_CMD_FAILED: - return(ERR_SPI_CMD_FAILED); - case SX126X_STATUS_SPI_FAILED: - return(ERR_CHIP_NOT_FOUND); + case RADIOLIB_SX126X_STATUS_CMD_TIMEOUT: + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + case RADIOLIB_SX126X_STATUS_CMD_INVALID: + return(RADIOLIB_ERR_SPI_CMD_INVALID); + case RADIOLIB_SX126X_STATUS_CMD_FAILED: + return(RADIOLIB_ERR_SPI_CMD_FAILED); + case RADIOLIB_SX126X_STATUS_SPI_FAILED: + return(RADIOLIB_ERR_CHIP_NOT_FOUND); default: - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 97fb05feb4..79564f2fef 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -10,327 +10,327 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // SX126X physical layer properties -#define SX126X_FREQUENCY_STEP_SIZE 0.9536743164 -#define SX126X_MAX_PACKET_LENGTH 255 -#define SX126X_CRYSTAL_FREQ 32.0 -#define SX126X_DIV_EXPONENT 25 +#define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 +#define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX126X_DIV_EXPONENT 25 // SX126X SPI commands // operational modes commands -#define SX126X_CMD_NOP 0x00 -#define SX126X_CMD_SET_SLEEP 0x84 -#define SX126X_CMD_SET_STANDBY 0x80 -#define SX126X_CMD_SET_FS 0xC1 -#define SX126X_CMD_SET_TX 0x83 -#define SX126X_CMD_SET_RX 0x82 -#define SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F -#define SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 -#define SX126X_CMD_SET_CAD 0xC5 -#define SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 -#define SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 -#define SX126X_CMD_SET_REGULATOR_MODE 0x96 -#define SX126X_CMD_CALIBRATE 0x89 -#define SX126X_CMD_CALIBRATE_IMAGE 0x98 -#define SX126X_CMD_SET_PA_CONFIG 0x95 -#define SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 +#define RADIOLIB_SX126X_CMD_NOP 0x00 +#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX126X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX126X_CMD_SET_TX 0x83 +#define RADIOLIB_SX126X_CMD_SET_RX 0x82 +#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F +#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 +#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89 +#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98 +#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95 +#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 // register and buffer access commands -#define SX126X_CMD_WRITE_REGISTER 0x0D -#define SX126X_CMD_READ_REGISTER 0x1D -#define SX126X_CMD_WRITE_BUFFER 0x0E -#define SX126X_CMD_READ_BUFFER 0x1E +#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D +#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D +#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E +#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E // DIO and IRQ control -#define SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 -#define SX126X_CMD_GET_IRQ_STATUS 0x12 -#define SX126X_CMD_CLEAR_IRQ_STATUS 0x02 -#define SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D -#define SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 +#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 +#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12 +#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02 +#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D +#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 // RF, modulation and packet commands -#define SX126X_CMD_SET_RF_FREQUENCY 0x86 -#define SX126X_CMD_SET_PACKET_TYPE 0x8A -#define SX126X_CMD_GET_PACKET_TYPE 0x11 -#define SX126X_CMD_SET_TX_PARAMS 0x8E -#define SX126X_CMD_SET_MODULATION_PARAMS 0x8B -#define SX126X_CMD_SET_PACKET_PARAMS 0x8C -#define SX126X_CMD_SET_CAD_PARAMS 0x88 -#define SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F -#define SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A +#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11 +#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A // status commands -#define SX126X_CMD_GET_STATUS 0xC0 -#define SX126X_CMD_GET_RSSI_INST 0x15 -#define SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 -#define SX126X_CMD_GET_PACKET_STATUS 0x14 -#define SX126X_CMD_GET_DEVICE_ERRORS 0x17 -#define SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 -#define SX126X_CMD_GET_STATS 0x10 -#define SX126X_CMD_RESET_STATS 0x00 +#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15 +#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 +#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14 +#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17 +#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 +#define RADIOLIB_SX126X_CMD_GET_STATS 0x10 +#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 // SX126X register map -#define SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 -#define SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 -#define SX126X_REG_CRC_INITIAL_MSB 0x06BC -#define SX126X_REG_CRC_INITIAL_LSB 0x06BD -#define SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE -#define SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF -#define SX126X_REG_SYNC_WORD_0 0x06C0 -#define SX126X_REG_SYNC_WORD_1 0x06C1 -#define SX126X_REG_SYNC_WORD_2 0x06C2 -#define SX126X_REG_SYNC_WORD_3 0x06C3 -#define SX126X_REG_SYNC_WORD_4 0x06C4 -#define SX126X_REG_SYNC_WORD_5 0x06C5 -#define SX126X_REG_SYNC_WORD_6 0x06C6 -#define SX126X_REG_SYNC_WORD_7 0x06C7 -#define SX126X_REG_NODE_ADDRESS 0x06CD -#define SX126X_REG_BROADCAST_ADDRESS 0x06CE -#define SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 -#define SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 -#define SX126X_REG_RANDOM_NUMBER_0 0x0819 -#define SX126X_REG_RANDOM_NUMBER_1 0x081A -#define SX126X_REG_RANDOM_NUMBER_2 0x081B -#define SX126X_REG_RANDOM_NUMBER_3 0x081C -#define SX126X_REG_RX_GAIN 0x08AC -#define SX126X_REG_OCP_CONFIGURATION 0x08E7 -#define SX126X_REG_XTA_TRIM 0x0911 -#define SX126X_REG_XTB_TRIM 0x0912 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 +#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC +#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF +#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0 +#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1 +#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2 +#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3 +#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4 +#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5 +#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6 +#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 +#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD +#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C +#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC +#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 +#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 +#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 // undocumented registers -#define SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 -#define SX126X_REG_TX_CLAMP_CONFIG 0x08D8 // SX1268 datasheet v1.1, section 15.2 -#define SX126X_REG_RTC_STOP 0x0920 // SX1268 datasheet v1.1, section 15.3 -#define SX126X_REG_RTC_EVENT 0x0944 // SX1268 datasheet v1.1, section 15.3 -#define SX126X_REG_IQ_CONFIG 0x0736 // SX1268 datasheet v1.1, section 15.4 -#define SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 -#define SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 -#define SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 +#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 // SX1268 datasheet v1.1, section 15.2 +#define RADIOLIB_SX126X_REG_RTC_STOP 0x0920 // SX1268 datasheet v1.1, section 15.3 +#define RADIOLIB_SX126X_REG_RTC_EVENT 0x0944 // SX1268 datasheet v1.1, section 15.3 +#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 // SX1268 datasheet v1.1, section 15.4 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 // SX126X SPI command variables -//SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION -#define SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) -#define SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained -#define SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled -#define SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled - -//SX126X_CMD_SET_STANDBY -#define SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator -#define SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator - -//SX126X_CMD_SET_RX -#define SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) -#define SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) - -//SX126X_CMD_SET_TX -#define SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) - -//SX126X_CMD_STOP_TIMER_ON_PREAMBLE -#define SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) -#define SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection - -//SX126X_CMD_SET_REGULATOR_MODE -#define SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) -#define SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC - -//SX126X_CMD_CALIBRATE -#define SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled -#define SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled -#define SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled -#define SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled -#define SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled -#define SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled -#define SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled -#define SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled -#define SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled -#define SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled -#define SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled -#define SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled -#define SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled -#define SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled -#define SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks - -//SX126X_CMD_CALIBRATE_IMAGE -#define SX126X_CAL_IMG_430_MHZ_1 0x6B -#define SX126X_CAL_IMG_430_MHZ_2 0x6F -#define SX126X_CAL_IMG_470_MHZ_1 0x75 -#define SX126X_CAL_IMG_470_MHZ_2 0x81 -#define SX126X_CAL_IMG_779_MHZ_1 0xC1 -#define SX126X_CAL_IMG_779_MHZ_2 0xC5 -#define SX126X_CAL_IMG_863_MHZ_1 0xD7 -#define SX126X_CAL_IMG_863_MHZ_2 0xDB -#define SX126X_CAL_IMG_902_MHZ_1 0xE1 -#define SX126X_CAL_IMG_902_MHZ_2 0xE9 - -//SX126X_CMD_SET_PA_CONFIG -#define SX126X_PA_CONFIG_HP_MAX 0x07 -#define SX126X_PA_CONFIG_PA_LUT 0x01 -#define SX126X_PA_CONFIG_SX1262_8 0x00 - -//SX126X_CMD_SET_RX_TX_FALLBACK_MODE -#define SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode -#define SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator -#define SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) - -//SX126X_CMD_SET_DIO_IRQ_PARAMS -#define SX126X_IRQ_TIMEOUT 0b1000000000 // 9 9 Rx or Tx timeout -#define SX126X_IRQ_CAD_DETECTED 0b0100000000 // 8 8 channel activity detected -#define SX126X_IRQ_CAD_DONE 0b0010000000 // 7 7 channel activity detection finished -#define SX126X_IRQ_CRC_ERR 0b0001000000 // 6 6 wrong CRC received -#define SX126X_IRQ_HEADER_ERR 0b0000100000 // 5 5 LoRa header CRC error -#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received -#define SX126X_IRQ_SYNC_WORD_VALID 0b0000001000 // 3 3 valid sync word detected -#define SX126X_IRQ_PREAMBLE_DETECTED 0b0000000100 // 2 2 preamble detected -#define SX126X_IRQ_RX_DONE 0b0000000010 // 1 1 packet received -#define SX126X_IRQ_TX_DONE 0b0000000001 // 0 0 packet transmission completed -#define SX126X_IRQ_ALL 0b1111111111 // 9 0 all interrupts -#define SX126X_IRQ_NONE 0b0000000000 // 9 0 no interrupts - -//SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL -#define SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ -#define SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control - -//SX126X_CMD_SET_DIO3_AS_TCXO_CTRL -#define SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V -#define SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V -#define SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V -#define SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V -#define SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V -#define SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V -#define SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V -#define SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V - -//SX126X_CMD_SET_PACKET_TYPE -#define SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK -#define SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa - -//SX126X_CMD_SET_TX_PARAMS -#define SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us -#define SX126X_PA_RAMP_20U 0x01 // 7 0 20 us -#define SX126X_PA_RAMP_40U 0x02 // 7 0 40 us -#define SX126X_PA_RAMP_80U 0x03 // 7 0 80 us -#define SX126X_PA_RAMP_200U 0x04 // 7 0 200 us -#define SX126X_PA_RAMP_800U 0x05 // 7 0 800 us -#define SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us -#define SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us - -//SX126X_CMD_SET_MODULATION_PARAMS -#define SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none -#define SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 -#define SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 -#define SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 -#define SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 -#define SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz -#define SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz -#define SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz -#define SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz -#define SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz -#define SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz -#define SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz -#define SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz -#define SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz -#define SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz -#define SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz -#define SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz -#define SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz -#define SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz -#define SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz -#define SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz -#define SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz -#define SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz -#define SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz -#define SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz -#define SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz -#define SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz -#define SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz -#define SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz -#define SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz -#define SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz -#define SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz -#define SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz -#define SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz -#define SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz -#define SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz -#define SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 -#define SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 -#define SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 -#define SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 -#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled -#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled - -//SX126X_CMD_SET_PACKET_PARAMS -#define SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled -#define SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits -#define SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits -#define SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits -#define SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits -#define SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled -#define SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only -#define SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast -#define SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) -#define SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) -#define SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled -#define SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte -#define SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte -#define SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted -#define SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted -#define SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled -#define SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled -#define SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit -#define SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit -#define SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled -#define SX126X_LORA_CRC_ON 0x01 // 7 0 enabled -#define SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard -#define SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted - -//SX126X_CMD_SET_CAD_PARAMS -#define SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 -#define SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 -#define SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 -#define SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 -#define SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 -#define SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode -#define SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected - -//SX126X_CMD_GET_STATUS -#define SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC -#define SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC -#define SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS -#define SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX -#define SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX -#define SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved -#define SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out -#define SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command -#define SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute -#define SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done -#define SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed - -//SX126X_CMD_GET_PACKET_STATUS -#define SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error -#define SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error -#define SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error -#define SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error -#define SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error -#define SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error -#define SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received -#define SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent - -//SX126X_CMD_GET_DEVICE_ERRORS -#define SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed -#define SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock -#define SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start -#define SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed -#define SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed -#define SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed -#define SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed -#define SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed +//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION +#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) +#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained +#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled +#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled + +//RADIOLIB_SX126X_CMD_SET_STANDBY +#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator + +//RADIOLIB_SX126X_CMD_SET_RX +#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) + +//RADIOLIB_SX126X_CMD_SET_TX +#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) + +//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection + +//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE +#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + +//RADIOLIB_SX126X_CMD_CALIBRATE +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks + +//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 +#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 +#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 + +//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) + +//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b1000000000 // 9 9 Rx or Tx timeout +#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0100000000 // 8 8 channel activity detected +#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0010000000 // 7 7 channel activity detection finished +#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0001000000 // 6 6 wrong CRC received +#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000100000 // 5 5 LoRa header CRC error +#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received +#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000001000 // 3 3 valid sync word detected +#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000010 // 1 1 packet received +#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_ALL 0b1111111111 // 9 0 all interrupts +#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000 // 9 0 no interrupts + +//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL +#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ +#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control + +//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V + +//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE +#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK +#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa + +//RADIOLIB_SX126X_CMD_SET_TX_PARAMS +#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us +#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us +#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us +#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us +#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us +#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us +#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us +#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us + +//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 +#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz +#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz +#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz +#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz +#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz +#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz +#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz +#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz +#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz +#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz +#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz +#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled + +//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast +#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) +#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) +#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted +#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled +#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit +#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled +#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard +#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted + +//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS +#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 +#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 +#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 +#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 +#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode +#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected + +//RADIOLIB_SX126X_CMD_GET_STATUS +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC +#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS +#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX +#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX +#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved +#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out +#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command +#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute +#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done +#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent + +//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS +#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed +#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock +#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start +#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed +#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed +#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed +#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed +#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed // SX126X SPI register variables -//SX126X_REG_LORA_SYNC_WORD_MSB + LSB -#define SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. -#define SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. +//RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB +#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. +#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. /*! @@ -354,6 +354,8 @@ class SX126x: public PhysicalLayer { */ SX126x(Module* mod); + Module* getMod(); + // basic methods /*! @@ -443,7 +445,7 @@ class SX126x: public PhysicalLayer { /*! \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX126x series does not support direct mode reception. - Will always return ERR_UNKNOWN. + Will always return RADIOLIB_ERR_UNKNOWN. \returns \ref status_codes */ @@ -475,7 +477,7 @@ class SX126x: public PhysicalLayer { /*! \brief Sets the module to standby mode. - \param mode Oscillator to be used in standby mode. Can be set to SX126X_STANDBY_RC (13 MHz RC oscillator) or SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). \returns \ref status_codes */ @@ -512,11 +514,11 @@ class SX126x: public PhysicalLayer { /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to SX126X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to SX126X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX126X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX126X_RX_TIMEOUT_NONE for no timeout (Rx single mode). \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout = SX126X_RX_TIMEOUT_INF); + int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. @@ -800,7 +802,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t fixedPacketLengthMode(uint8_t len = SX126X_MAX_PACKET_LENGTH); + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX126X_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. Available in FSK mode only. @@ -809,7 +811,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t variablePacketLengthMode(uint8_t maxLen = SX126X_MAX_PACKET_LENGTH); + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); /*! \brief Get expected time-on-air for a given size of payload @@ -915,29 +917,29 @@ class SX126x: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); -#ifndef RADIOLIB_GODMODE +#if !defined(RADIOLIB_GODMODE) protected: #endif // SX126x SPI command implementations int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); int16_t setCad(); - int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT); + int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t readBuffer(uint8_t* data, uint8_t numBytes); - int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX126X_IRQ_NONE, uint16_t dio3Mask = SX126X_IRQ_NONE); + int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); uint16_t getIrqStatus(); - int16_t clearIrqStatus(uint16_t clearIrqParams = SX126X_IRQ_ALL); + int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); int16_t calibrateImage(uint8_t* data); uint8_t getPacketType(); - int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U); + int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); - int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD); - int16_t setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType = SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLength = 0xFF, uint8_t preambleDetectorLength = SX126X_GFSK_PREAMBLE_DETECT_16); + int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ = RADIOLIB_SX126X_LORA_IQ_STANDARD); + int16_t setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLength = 0xFF, uint8_t preambleDetectorLength = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setRegulatorMode(uint8_t mode); uint8_t getStatus(); From 8c7b8a1b63bfd9f934700fc24e1d3365a5c16805 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:42:12 +0100 Subject: [PATCH 0049/1848] [SX127x] Update to 5.0.0 --- .../SX127x_Channel_Activity_Detection.ino | 6 +- ...x_Channel_Activity_Detection_Interrupt.ino | 8 +- .../SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 26 +- .../SX127x_PingPong/SX127x_PingPong.ino | 10 +- .../SX127x/SX127x_Receive/SX127x_Receive.ino | 8 +- .../SX127x_Receive_Direct.ino | 2 +- .../SX127x_Receive_Interrupt.ino | 8 +- .../SX127x_Settings/SX127x_Settings.ino | 22 +- .../SX127x_Transmit/SX127x_Transmit.ino | 10 +- .../SX127x_Transmit_Interrupt.ino | 6 +- src/modules/SX127x/SX1272.cpp | 220 ++--- src/modules/SX127x/SX1272.h | 148 ++-- src/modules/SX127x/SX1273.cpp | 14 +- src/modules/SX127x/SX1273.h | 2 +- src/modules/SX127x/SX1276.cpp | 8 +- src/modules/SX127x/SX1276.h | 2 +- src/modules/SX127x/SX1277.cpp | 20 +- src/modules/SX127x/SX1277.h | 2 +- src/modules/SX127x/SX1278.cpp | 242 ++--- src/modules/SX127x/SX1278.h | 142 +-- src/modules/SX127x/SX1279.cpp | 8 +- src/modules/SX127x/SX1279.h | 2 +- src/modules/SX127x/SX127x.cpp | 630 ++++++------- src/modules/SX127x/SX127x.h | 824 +++++++++--------- 24 files changed, 1188 insertions(+), 1182 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino index ececb74716..ad7126d434 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino @@ -36,7 +36,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -51,11 +51,11 @@ void loop() { // start scanning current channel int state = radio.scanChannel(); - if (state == PREAMBLE_DETECTED) { + if (state == RADIOLIB_PREAMBLE_DETECTED) { // LoRa preamble was detected Serial.println(F("detected preamble!")); - } else if (state == CHANNEL_FREE) { + } else if (state == RADIOLIB_CHANNEL_FREE) { // no preamble was detected, channel is free Serial.println(F("channel is free!")); diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index a2c0f75806..30f945e47b 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -31,7 +31,7 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // save state between loops -int scanState = ERR_NONE; +int scanState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -39,7 +39,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -58,7 +58,7 @@ void setup() { // start scanning the channel Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); state = radio.startChannelScan(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -125,7 +125,7 @@ void loop() { // start scanning current channel int state = radio.startChannelScan(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index 947e7ce3f7..f632817257 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -36,7 +36,7 @@ void setup() { // initialize SX1278 FSK modem with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.beginFSK(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -61,7 +61,7 @@ void setup() { uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; state = radio.setSyncWord(syncWord, 8); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); while (true); @@ -74,7 +74,7 @@ void setup() { // setDataShapingOOK() to set the correct shaping! state = radio.setOOK(true); state = radio.setDataShapingOOK(1); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to change modulation, code ")); Serial.println(state); while (true); @@ -95,11 +95,11 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1278] Packet transmitted successfully!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { Serial.println(F("[SX1278] Packet too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { Serial.println(F("[SX1278] Timed out while transmitting!")); } else { Serial.println(F("[SX1278] Failed to transmit packet, code ")); @@ -113,11 +113,11 @@ void loop() { byte byteArr[8]; int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1278] Received packet!")); Serial.print(F("[SX1278] Data:\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("[SX1278] Timed out while waiting for packet!")); } else { Serial.println(F("[SX1278] Failed to receive packet, code ")); @@ -138,7 +138,7 @@ void loop() { state = radio.setNodeAddress(0x02); // set broadcast address to 0xFF state = radio.setBroadcastAddress(0xFF); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("[SX1278] Unable to set address filter, code ")); Serial.println(state); } @@ -148,7 +148,7 @@ void loop() { // node and broadcast address /* state = radio.disableAddressFiltering(); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("Unable to remove address filter, code ")); } */ @@ -159,7 +159,7 @@ void loop() { // activate direct mode transmitter state = radio.transmitDirect(); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("[SX1278] Unable to start direct transmission mode, code ")); Serial.println(state); } @@ -170,7 +170,7 @@ void loop() { // it is recommended to set data shaping to 0 // (no shaping) when transmitting audio state = radio.setDataShaping(0.0); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("[SX1278] Unable to set data shaping, code ")); Serial.println(state); } @@ -193,7 +193,7 @@ void loop() { // direct mode transmissions can also be received // as bit stream on DIO1 (data) and DIO2 (clock) state = radio.receiveDirect(); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.println(F("[SX1278] Unable to start direct reception mode, code ")); Serial.println(state); } diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index 9231ea586a..cd505a0672 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -27,7 +27,7 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // save transmission states between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; // flag to indicate transmission or reception state bool transmitFlag = false; @@ -58,7 +58,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -79,7 +79,7 @@ void setup() { // start listening for LoRa packets on this node Serial.print(F("[SX1278] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -102,7 +102,7 @@ void loop() { if(transmitFlag) { // the previous operation was transmission, listen for response // print the result - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); @@ -122,7 +122,7 @@ void loop() { String str; int state = radio.readData(str); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1278] Received packet!")); diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino index 0f839eec94..e67fbc82b4 100644 --- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino +++ b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino @@ -40,7 +40,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -91,11 +91,11 @@ void loop() { Serial.print(radio.getFrequencyError()); Serial.println(F(" Hz")); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino index 439dc1bd5d..dee4214f5d 100644 --- a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino +++ b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino @@ -34,7 +34,7 @@ void setup() { // initialize SX1278 with FSK modem at 9600 bps Serial.print(F("[SX1278] Initializing ... ")); int state = radio.beginFSK(434.0, 9.6, 20.0); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 8a755bb886..9db3eaf3c7 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -41,7 +41,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -56,7 +56,7 @@ void setup() { // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -115,7 +115,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1278] Received packet!")); @@ -138,7 +138,7 @@ void loop() { Serial.print(radio.getFrequencyError()); Serial.println(F(" Hz")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("[SX1278] CRC error!")); diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino index 84f31fac61..834a6cc8a1 100644 --- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino +++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -47,7 +47,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio1.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -73,7 +73,7 @@ void setup() { // preamble length: 20 symbols // amplifier gain: 1 (maximum gain) state = radio2.begin(915.0, 500.0, 6, 5, 0x14, 2, 20, 1); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -85,32 +85,32 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); while (true); } // set bandwidth to 250 kHz - if (radio1.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) { + if (radio1.setBandwidth(250.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); while (true); } // set spreading factor to 10 - if (radio1.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); while (true); } // set coding rate to 6 - if (radio1.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); while (true); } // set LoRa sync word to 0x14 // NOTE: value 0x34 is reserved for LoRaWAN networks and should not be used - if (radio1.setSyncWord(0x14) != ERR_NONE) { + if (radio1.setSyncWord(0x14) != RADIOLIB_ERR_NONE) { Serial.println(F("Unable to set sync word!")); while (true); } @@ -118,20 +118,20 @@ void setup() { // set output power to 10 dBm (accepted range is -3 - 17 dBm) // NOTE: 20 dBm value allows high power operation, but transmission // duty cycle MUST NOT exceed 1% - if (radio1.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(10) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); while (true); } // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) // NOTE: set value to 0 to disable overcurrent protection - if (radio1.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) { + if (radio1.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { Serial.println(F("Selected current limit is invalid for this module!")); while (true); } // set LoRa preamble length to 15 symbols (accepted range is 6 - 65535) - if (radio1.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) { + if (radio1.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); while (true); } @@ -139,7 +139,7 @@ void setup() { // set amplifier gain to 1 (accepted range is 1 - 6, where 1 is maximum gain) // NOTE: set value to 0 to enable automatic gain control // leave at 0 unless you know what you're doing - if (radio1.setGain(1) == ERR_INVALID_GAIN) { + if (radio1.setGain(1) == RADIOLIB_ERR_INVALID_GAIN) { Serial.println(F("Selected gain is invalid for this module!")); while (true); } diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino index 6113046b57..3eeabf57a2 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino @@ -24,7 +24,7 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 radio = new Module(10, 2, 9, 3); +SX1278 radio = new Module(5, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield @@ -36,7 +36,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -71,7 +71,7 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F(" success!")); @@ -80,11 +80,11 @@ void loop() { Serial.print(radio.getDataRate()); Serial.println(F(" bps")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { // timeout occurred while transmitting packet Serial.println(F("timeout!")); diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 5e5578520a..b218a0a7cc 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -32,7 +32,7 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -40,7 +40,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -97,7 +97,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 9acac6fb9a..40dbbf9d44 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -7,7 +7,7 @@ SX1272::SX1272(Module* mod) : SX127x(mod) { int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, preambleLength); + int16_t state = SX127x::begin(RADIOLIB_SX1272_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -34,7 +34,7 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1272_CHIP_VERSION, br, rxBw, freqDev, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -60,19 +60,19 @@ int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t } void SX1272::reset() { - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), HIGH); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(5); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), LOW); + _mod->delay(5); } int16_t SX1272::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 860.0, 1020.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 860.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); @@ -80,26 +80,26 @@ int16_t SX1272::setFrequency(float freq) { int16_t SX1272::setBandwidth(float bw) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newBandwidth; // check allowed bandwidth values if(fabs(bw - 125.0) <= 0.001) { - newBandwidth = SX1272_BW_125_00_KHZ; + newBandwidth = RADIOLIB_SX1272_BW_125_00_KHZ; } else if(fabs(bw - 250.0) <= 0.001) { - newBandwidth = SX1272_BW_250_00_KHZ; + newBandwidth = RADIOLIB_SX1272_BW_250_00_KHZ; } else if(fabs(bw - 500.0) <= 0.001) { - newBandwidth = SX1272_BW_500_00_KHZ; + newBandwidth = RADIOLIB_SX1272_BW_500_00_KHZ; } else { - return(ERR_INVALID_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // set bandwidth and if successful, save the new setting int16_t state = SX1272::setBandwidthRaw(newBandwidth); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_bw = bw; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled @@ -109,9 +109,9 @@ int16_t SX1272::setBandwidth(float bw) { RADIOLIB_DEBUG_PRINT(symbolLength); RADIOLIB_DEBUG_PRINTLN(" ms"); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } @@ -120,8 +120,8 @@ int16_t SX1272::setBandwidth(float bw) { int16_t SX1272::setSpreadingFactor(uint8_t sf) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newSpreadingFactor; @@ -129,33 +129,33 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { // check allowed spreading factor values switch(sf) { case 6: - newSpreadingFactor = SX127X_SF_6; + newSpreadingFactor = RADIOLIB_SX127X_SF_6; break; case 7: - newSpreadingFactor = SX127X_SF_7; + newSpreadingFactor = RADIOLIB_SX127X_SF_7; break; case 8: - newSpreadingFactor = SX127X_SF_8; + newSpreadingFactor = RADIOLIB_SX127X_SF_8; break; case 9: - newSpreadingFactor = SX127X_SF_9; + newSpreadingFactor = RADIOLIB_SX127X_SF_9; break; case 10: - newSpreadingFactor = SX127X_SF_10; + newSpreadingFactor = RADIOLIB_SX127X_SF_10; break; case 11: - newSpreadingFactor = SX127X_SF_11; + newSpreadingFactor = RADIOLIB_SX127X_SF_11; break; case 12: - newSpreadingFactor = SX127X_SF_12; + newSpreadingFactor = RADIOLIB_SX127X_SF_12; break; default: - return(ERR_INVALID_SPREADING_FACTOR); + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } // set spreading factor and if successful, save the new setting int16_t state = SX1272::setSpreadingFactorRaw(newSpreadingFactor); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_sf = sf; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled @@ -165,9 +165,9 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { RADIOLIB_DEBUG_PRINT(symbolLength); RADIOLIB_DEBUG_PRINTLN(" ms"); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } @@ -176,8 +176,8 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { int16_t SX1272::setCodingRate(uint8_t cr) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newCodingRate; @@ -185,24 +185,24 @@ int16_t SX1272::setCodingRate(uint8_t cr) { // check allowed coding rate values switch(cr) { case 5: - newCodingRate = SX1272_CR_4_5; + newCodingRate = RADIOLIB_SX1272_CR_4_5; break; case 6: - newCodingRate = SX1272_CR_4_6; + newCodingRate = RADIOLIB_SX1272_CR_4_6; break; case 7: - newCodingRate = SX1272_CR_4_7; + newCodingRate = RADIOLIB_SX1272_CR_4_7; break; case 8: - newCodingRate = SX1272_CR_4_8; + newCodingRate = RADIOLIB_SX1272_CR_4_8; break; default: - return(ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_INVALID_CODING_RATE); } // set coding rate and if successful, save the new setting int16_t state = SX1272::setCodingRateRaw(newCodingRate); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_cr = cr; } return(state); @@ -211,9 +211,9 @@ int16_t SX1272::setCodingRate(uint8_t cr) { int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { - RADIOLIB_CHECK_RANGE(power, -1, 14, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } else { - RADIOLIB_CHECK_RANGE(power, 2, 20, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } // set mode to standby @@ -221,22 +221,22 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { if(useRfo) { // RFO output - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power + 1), 3, 0); - state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power <= 17) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 2), 3, 0); - state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 5), 3, 0); - state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } @@ -248,7 +248,7 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { int16_t SX1272::setGain(uint8_t gain) { // check allowed range if(gain > 6) { - return(ERR_INVALID_GAIN); + return(RADIOLIB_ERR_INVALID_GAIN); } // set mode to standby @@ -256,24 +256,24 @@ int16_t SX1272::setGain(uint8_t gain) { // get modem int16_t modem = getActiveModem(); - if(modem == SX127X_LORA){ + if(modem == RADIOLIB_SX127X_LORA){ // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_ON, 2, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); } else { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_OFF, 2, 2); - state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3); - state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } @@ -283,13 +283,13 @@ int16_t SX1272::setGain(uint8_t gain) { int16_t SX1272::setDataShaping(uint8_t sh) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation if(SX127x::_ook) { - return(ERR_INVALID_MODULATION); + return(RADIOLIB_ERR_INVALID_MODULATION); } // set mode to standby @@ -299,27 +299,27 @@ int16_t SX1272::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); case RADIOLIB_SHAPING_0_3: - return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_3, 4, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_1_0, 4, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } } int16_t SX1272::setDataShapingOOK(uint8_t sh) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation if(!SX127x::_ook) { - return(ERR_INVALID_MODULATION); + return(RADIOLIB_ERR_INVALID_MODULATION); } // set mode to standby @@ -328,16 +328,16 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { // set data shaping switch(sh) { case 0: - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); break; case 1: - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_OOK_FILTER_BR, 4, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); break; case 2: - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_OOK_FILTER_2BR, 4, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); break; default: - state = ERR_INVALID_DATA_SHAPING; + state = RADIOLIB_ERR_INVALID_DATA_SHAPING; break; } @@ -345,9 +345,9 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { } float SX1272::getRSSI(bool skipReceive) { - if(getActiveModem() == SX127X_LORA) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { // RSSI calculation uses different constant for low-frequency and high-frequency ports - float lastPacketRSSI = -139 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); + float lastPacketRSSI = -139 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); // spread-spectrum modulation signal can be received below noise floor // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value @@ -365,7 +365,7 @@ float SX1272::getRSSI(bool skipReceive) { } // read the value for FSK - float rssi = (float)_mod->SPIgetRegValue(SX127X_REG_RSSI_VALUE_FSK) / -2.0; + float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; // set mode back to standby if(!skipReceive) { @@ -378,61 +378,61 @@ float SX1272::getRSSI(bool skipReceive) { } int16_t SX1272::setCRC(bool enable, bool mode) { - if(getActiveModem() == SX127X_LORA) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC SX127x::_crcEnabled = enable; if(enable) { - return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_ON, 2, 2)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_ON, 2, 2)); } else { - return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_OFF, 2, 2)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 2, 2)); } } else { // set FSK CRC - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(enable) { - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } int16_t SX1272::forceLDRO(bool enable) { - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } _ldroAuto = false; if(enable) { - return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); } else { - return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); } } int16_t SX1272::autoLDRO() { - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } _ldroAuto = true; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t SX1272::implicitHeader(size_t len) { - return(setHeaderType(SX1272_HEADER_IMPL_MODE, len)); + return(setHeaderType(RADIOLIB_SX1272_HEADER_IMPL_MODE, len)); } int16_t SX1272::explicitHeader() { - return(setHeaderType(SX1272_HEADER_EXPL_MODE)); + return(setHeaderType(RADIOLIB_SX1272_HEADER_EXPL_MODE)); } int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { @@ -440,7 +440,7 @@ int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); return(state); } @@ -449,16 +449,16 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { int16_t state = SX127x::standby(); // write registers - if(newSpreadingFactor == SX127X_SF_6) { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | (SX127x::_crcEnabled ? SX1272_RX_CRC_MODE_ON : SX1272_RX_CRC_MODE_OFF), 2, 1); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE, 7, 3); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6); + if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::_crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_EXPL_MODE | (SX127x::_crcEnabled ? SX1272_RX_CRC_MODE_ON : SX1272_RX_CRC_MODE_OFF), 2, 1); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE, 7, 3); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::_crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } @@ -468,22 +468,22 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); return(state); } int16_t SX1272::setHeaderType(uint8_t headerType, size_t len) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set requested packet mode - int16_t state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value @@ -498,7 +498,7 @@ int16_t SX1272::configFSK() { RADIOLIB_ASSERT(state); // set fast PLL hop - state = _mod->SPIsetRegValue(SX1272_REG_PLL_HOP, SX127X_FAST_HOP_ON, 7, 7); + state = _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 3851960e33..3e0aa8cb3c 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -9,82 +9,82 @@ #include "SX127x.h" // SX1272 specific register map -#define SX1272_REG_AGC_REF 0x43 -#define SX1272_REG_AGC_THRESH_1 0x44 -#define SX1272_REG_AGC_THRESH_2 0x45 -#define SX1272_REG_AGC_THRESH_3 0x46 -#define SX1272_REG_PLL_HOP 0x4B -#define SX1272_REG_TCXO 0x58 -#define SX1272_REG_PA_DAC 0x5A -#define SX1272_REG_PLL 0x5C -#define SX1272_REG_PLL_LOW_PN 0x5E -#define SX1272_REG_FORMER_TEMP 0x6C -#define SX1272_REG_BIT_RATE_FRAC 0x70 +#define RADIOLIB_SX1272_REG_AGC_REF 0x43 +#define RADIOLIB_SX1272_REG_AGC_THRESH_1 0x44 +#define RADIOLIB_SX1272_REG_AGC_THRESH_2 0x45 +#define RADIOLIB_SX1272_REG_AGC_THRESH_3 0x46 +#define RADIOLIB_SX1272_REG_PLL_HOP 0x4B +#define RADIOLIB_SX1272_REG_TCXO 0x58 +#define RADIOLIB_SX1272_REG_PA_DAC 0x5A +#define RADIOLIB_SX1272_REG_PLL 0x5C +#define RADIOLIB_SX1272_REG_PLL_LOW_PN 0x5E +#define RADIOLIB_SX1272_REG_FORMER_TEMP 0x6C +#define RADIOLIB_SX1272_REG_BIT_RATE_FRAC 0x70 // SX1272 LoRa modem settings -// SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB -#define SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 -#define SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz -#define SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers - -// SX127X_REG_MODEM_CONFIG_1 -#define SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz -#define SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz -#define SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz -#define SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5 -#define SX1272_CR_4_6 0b00010000 // 5 3 4/6 -#define SX1272_CR_4_7 0b00011000 // 5 3 4/7 -#define SX1272_CR_4_8 0b00100000 // 5 3 4/8 -#define SX1272_HEADER_EXPL_MODE 0b00000000 // 2 2 explicit header mode -#define SX1272_HEADER_IMPL_MODE 0b00000100 // 2 2 implicit header mode -#define SX1272_RX_CRC_MODE_OFF 0b00000000 // 1 1 CRC disabled -#define SX1272_RX_CRC_MODE_ON 0b00000010 // 1 1 CRC enabled -#define SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled -#define SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz - -// SX127X_REG_MODEM_CONFIG_2 -#define SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA -#define SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop - -// SX127X_REG_VERSION -#define SX1272_CHIP_VERSION 0x22 +// RADIOLIB_SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +#define RADIOLIB_SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers + +// RADIOLIB_SX127X_REG_MODEM_CONFIG_1 +#define RADIOLIB_SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz +#define RADIOLIB_SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz +#define RADIOLIB_SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz +#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5 +#define RADIOLIB_SX1272_CR_4_6 0b00010000 // 5 3 4/6 +#define RADIOLIB_SX1272_CR_4_7 0b00011000 // 5 3 4/7 +#define RADIOLIB_SX1272_CR_4_8 0b00100000 // 5 3 4/8 +#define RADIOLIB_SX1272_HEADER_EXPL_MODE 0b00000000 // 2 2 explicit header mode +#define RADIOLIB_SX1272_HEADER_IMPL_MODE 0b00000100 // 2 2 implicit header mode +#define RADIOLIB_SX1272_RX_CRC_MODE_OFF 0b00000000 // 1 1 CRC disabled +#define RADIOLIB_SX1272_RX_CRC_MODE_ON 0b00000010 // 1 1 CRC enabled +#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled +#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz + +// RADIOLIB_SX127X_REG_MODEM_CONFIG_2 +#define RADIOLIB_SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA +#define RADIOLIB_SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop + +// RADIOLIB_SX127X_REG_VERSION +#define RADIOLIB_SX1272_CHIP_VERSION 0x22 // SX1272 FSK modem settings -// SX127X_REG_OP_MODE -#define SX1272_NO_SHAPING 0b00000000 // 4 3 data shaping: no shaping (default) -#define SX1272_FSK_GAUSSIAN_1_0 0b00001000 // 4 3 FSK modulation Gaussian filter, BT = 1.0 -#define SX1272_FSK_GAUSSIAN_0_5 0b00010000 // 4 3 FSK modulation Gaussian filter, BT = 0.5 -#define SX1272_FSK_GAUSSIAN_0_3 0b00011000 // 4 3 FSK modulation Gaussian filter, BT = 0.3 -#define SX1272_OOK_FILTER_BR 0b00001000 // 4 3 OOK modulation filter, f_cutoff = BR -#define SX1272_OOK_FILTER_2BR 0b00010000 // 4 3 OOK modulation filter, f_cutoff = 2*BR - -// SX127X_REG_PA_RAMP -#define SX1272_LOW_PN_TX_PLL_OFF 0b00010000 // 4 4 use standard PLL in transmit mode (default) -#define SX1272_LOW_PN_TX_PLL_ON 0b00000000 // 4 4 use lower phase noise PLL in transmit mode - -// SX127X_REG_SYNC_CONFIG -#define SX1272_FIFO_FILL_CONDITION_SYNC_ADDRESS 0b00000000 // 3 3 FIFO will be filled when sync address interrupt occurs (default) -#define SX1272_FIFO_FILL_CONDITION_ALWAYS 0b00001000 // 3 3 FIFO will be filled as long as this bit is set - -// SX1272_REG_AGC_REF -#define SX1272_AGC_REFERENCE_LEVEL 0x13 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm] - -// SX1272_REG_AGC_THRESH_1 -#define SX1272_AGC_STEP_1 0x0E // 4 0 1st AGC threshold - -// SX1272_REG_AGC_THRESH_2 -#define SX1272_AGC_STEP_2 0x50 // 7 4 2nd AGC threshold -#define SX1272_AGC_STEP_3 0x0B // 4 0 3rd AGC threshold - -// SX1272_REG_AGC_THRESH_3 -#define SX1272_AGC_STEP_4 0xD0 // 7 4 4th AGC threshold -#define SX1272_AGC_STEP_5 0x0B // 4 0 5th AGC threshold - -// SX1272_REG_PLL_LOW_PN -#define SX1272_PLL_LOW_PN_BANDWIDTH_75_KHZ 0b00000000 // 7 6 low phase noise PLL bandwidth: 75 kHz -#define SX1272_PLL_LOW_PN_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz -#define SX1272_PLL_LOW_PN_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz -#define SX1272_PLL_LOW_PN_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) +// RADIOLIB_SX127X_REG_OP_MODE +#define RADIOLIB_SX1272_NO_SHAPING 0b00000000 // 4 3 data shaping: no shaping (default) +#define RADIOLIB_SX1272_FSK_GAUSSIAN_1_0 0b00001000 // 4 3 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_5 0b00010000 // 4 3 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_3 0b00011000 // 4 3 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_SX1272_OOK_FILTER_BR 0b00001000 // 4 3 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_SX1272_OOK_FILTER_2BR 0b00010000 // 4 3 OOK modulation filter, f_cutoff = 2*BR + +// RADIOLIB_SX127X_REG_PA_RAMP +#define RADIOLIB_SX1272_LOW_PN_TX_PLL_OFF 0b00010000 // 4 4 use standard PLL in transmit mode (default) +#define RADIOLIB_SX1272_LOW_PN_TX_PLL_ON 0b00000000 // 4 4 use lower phase noise PLL in transmit mode + +// RADIOLIB_SX127X_REG_SYNC_CONFIG +#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_SYNC_ADDRESS 0b00000000 // 3 3 FIFO will be filled when sync address interrupt occurs (default) +#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_ALWAYS 0b00001000 // 3 3 FIFO will be filled as long as this bit is set + +// RADIOLIB_SX1272_REG_AGC_REF +#define RADIOLIB_SX1272_AGC_REFERENCE_LEVEL 0x13 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm] + +// RADIOLIB_SX1272_REG_AGC_THRESH_1 +#define RADIOLIB_SX1272_AGC_STEP_1 0x0E // 4 0 1st AGC threshold + +// RADIOLIB_SX1272_REG_AGC_THRESH_2 +#define RADIOLIB_SX1272_AGC_STEP_2 0x50 // 7 4 2nd AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_3 0x0B // 4 0 3rd AGC threshold + +// RADIOLIB_SX1272_REG_AGC_THRESH_3 +#define RADIOLIB_SX1272_AGC_STEP_4 0xD0 // 7 4 4th AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_5 0x0B // 4 0 5th AGC threshold + +// RADIOLIB_SX1272_REG_PLL_LOW_PN +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_75_KHZ 0b00000000 // 7 6 low phase noise PLL bandwidth: 75 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) /*! \class SX1272 @@ -130,7 +130,7 @@ class SX1272: public SX127x { \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -253,7 +253,7 @@ class SX1272: public SX127x { \param enable Enable (true) or disable (false) CRC. - \param mode Set CRC mode to SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) or SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. + \param mode Set CRC mode to RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) or RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 46aa680cdc..9856e3d269 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -7,7 +7,7 @@ SX1273::SX1273(Module* mod) : SX1272(mod) { int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, preambleLength); + int16_t state = SX127x::begin(RADIOLIB_SX1272_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -38,24 +38,24 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) { // check allowed spreading factor values switch(sf) { case 6: - newSpreadingFactor = SX127X_SF_6; + newSpreadingFactor = RADIOLIB_SX127X_SF_6; break; case 7: - newSpreadingFactor = SX127X_SF_7; + newSpreadingFactor = RADIOLIB_SX127X_SF_7; break; case 8: - newSpreadingFactor = SX127X_SF_8; + newSpreadingFactor = RADIOLIB_SX127X_SF_8; break; case 9: - newSpreadingFactor = SX127X_SF_9; + newSpreadingFactor = RADIOLIB_SX127X_SF_9; break; default: - return(ERR_INVALID_SPREADING_FACTOR); + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } // set spreading factor and if successful, save the new setting int16_t state = setSpreadingFactorRaw(newSpreadingFactor); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_sf = sf; } diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 6711a84dee..46127ba5af 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -49,7 +49,7 @@ class SX1273: public SX1272 { \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); // configuration methods diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index eb3a229551..c4c32f9c92 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -7,7 +7,7 @@ SX1276::SX1276(Module* mod) : SX1278(mod) { int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); + int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -34,7 +34,7 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -60,11 +60,11 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1276::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 9ba7433c49..acb5c78610 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -49,7 +49,7 @@ class SX1276: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index b2f7e86b66..59250e45ed 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -7,7 +7,7 @@ SX1277::SX1277(Module* mod) : SX1278(mod) { int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); + int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -34,7 +34,7 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -60,11 +60,11 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1277::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); @@ -76,24 +76,24 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { // check allowed spreading factor values switch(sf) { case 6: - newSpreadingFactor = SX127X_SF_6; + newSpreadingFactor = RADIOLIB_SX127X_SF_6; break; case 7: - newSpreadingFactor = SX127X_SF_7; + newSpreadingFactor = RADIOLIB_SX127X_SF_7; break; case 8: - newSpreadingFactor = SX127X_SF_8; + newSpreadingFactor = RADIOLIB_SX127X_SF_8; break; case 9: - newSpreadingFactor = SX127X_SF_9; + newSpreadingFactor = RADIOLIB_SX127X_SF_9; break; default: - return(ERR_INVALID_SPREADING_FACTOR); + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } // set spreading factor and if successful, save the new setting int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_sf = sf; } diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 4b80b63fe8..f2375fdeb8 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -49,7 +49,7 @@ class SX1277: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 4acd827ed5..317c38ee8b 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -7,7 +7,7 @@ SX1278::SX1278(Module* mod) : SX127x(mod) { int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); + int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -34,7 +34,7 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -60,19 +60,19 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1278::reset() { - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), HIGH); - Module::delay(5); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), LOW); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->delay(5); } int16_t SX1278::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); @@ -80,40 +80,40 @@ int16_t SX1278::setFrequency(float freq) { int16_t SX1278::setBandwidth(float bw) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newBandwidth; // check allowed bandwidth values if(fabs(bw - 7.8) <= 0.001) { - newBandwidth = SX1278_BW_7_80_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ; } else if(fabs(bw - 10.4) <= 0.001) { - newBandwidth = SX1278_BW_10_40_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ; } else if(fabs(bw - 15.6) <= 0.001) { - newBandwidth = SX1278_BW_15_60_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ; } else if(fabs(bw - 20.8) <= 0.001) { - newBandwidth = SX1278_BW_20_80_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ; } else if(fabs(bw - 31.25) <= 0.001) { - newBandwidth = SX1278_BW_31_25_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ; } else if(fabs(bw - 41.7) <= 0.001) { - newBandwidth = SX1278_BW_41_70_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ; } else if(fabs(bw - 62.5) <= 0.001) { - newBandwidth = SX1278_BW_62_50_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ; } else if(fabs(bw - 125.0) <= 0.001) { - newBandwidth = SX1278_BW_125_00_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ; } else if(fabs(bw - 250.0) <= 0.001) { - newBandwidth = SX1278_BW_250_00_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ; } else if(fabs(bw - 500.0) <= 0.001) { - newBandwidth = SX1278_BW_500_00_KHZ; + newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ; } else { - return(ERR_INVALID_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // set bandwidth and if successful, save the new setting int16_t state = SX1278::setBandwidthRaw(newBandwidth); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_bw = bw; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled @@ -123,9 +123,9 @@ int16_t SX1278::setBandwidth(float bw) { RADIOLIB_DEBUG_PRINT(symbolLength); RADIOLIB_DEBUG_PRINTLN(" ms"); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } } @@ -134,8 +134,8 @@ int16_t SX1278::setBandwidth(float bw) { int16_t SX1278::setSpreadingFactor(uint8_t sf) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newSpreadingFactor; @@ -143,33 +143,33 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { // check allowed spreading factor values switch(sf) { case 6: - newSpreadingFactor = SX127X_SF_6; + newSpreadingFactor = RADIOLIB_SX127X_SF_6; break; case 7: - newSpreadingFactor = SX127X_SF_7; + newSpreadingFactor = RADIOLIB_SX127X_SF_7; break; case 8: - newSpreadingFactor = SX127X_SF_8; + newSpreadingFactor = RADIOLIB_SX127X_SF_8; break; case 9: - newSpreadingFactor = SX127X_SF_9; + newSpreadingFactor = RADIOLIB_SX127X_SF_9; break; case 10: - newSpreadingFactor = SX127X_SF_10; + newSpreadingFactor = RADIOLIB_SX127X_SF_10; break; case 11: - newSpreadingFactor = SX127X_SF_11; + newSpreadingFactor = RADIOLIB_SX127X_SF_11; break; case 12: - newSpreadingFactor = SX127X_SF_12; + newSpreadingFactor = RADIOLIB_SX127X_SF_12; break; default: - return(ERR_INVALID_SPREADING_FACTOR); + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } // set spreading factor and if successful, save the new setting int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_sf = sf; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled @@ -179,9 +179,9 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { RADIOLIB_DEBUG_PRINT(symbolLength); RADIOLIB_DEBUG_PRINTLN(" ms"); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } } @@ -190,8 +190,8 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { int16_t SX1278::setCodingRate(uint8_t cr) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newCodingRate; @@ -199,24 +199,24 @@ int16_t SX1278::setCodingRate(uint8_t cr) { // check allowed coding rate values switch(cr) { case 5: - newCodingRate = SX1278_CR_4_5; + newCodingRate = RADIOLIB_SX1278_CR_4_5; break; case 6: - newCodingRate = SX1278_CR_4_6; + newCodingRate = RADIOLIB_SX1278_CR_4_6; break; case 7: - newCodingRate = SX1278_CR_4_7; + newCodingRate = RADIOLIB_SX1278_CR_4_7; break; case 8: - newCodingRate = SX1278_CR_4_8; + newCodingRate = RADIOLIB_SX1278_CR_4_8; break; default: - return(ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_INVALID_CODING_RATE); } // set coding rate and if successful, save the new setting int16_t state = SX1278::setCodingRateRaw(newCodingRate); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_cr = cr; } return(state); @@ -226,11 +226,11 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { // RFO output - RADIOLIB_CHECK_RANGE(power, -3, 15, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } else { // PA_BOOST output, check high-power operation if(power != 20) { - RADIOLIB_CHECK_RANGE(power, 2, 17, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } } @@ -241,28 +241,28 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { uint8_t paCfg = 0; if(power < 0) { // low power mode RFO output - paCfg = SX1278_LOW_POWER | (power + 3); + paCfg = RADIOLIB_SX1278_LOW_POWER | (power + 3); } else { // high power mode RFO output - paCfg = SX1278_MAX_POWER | power; + paCfg = RADIOLIB_SX1278_MAX_POWER | power; } - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, paCfg, 6, 0); - state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power != 20) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 2), 6, 0); - state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | 0x0F, 6, 0); - state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } } @@ -273,7 +273,7 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { int16_t SX1278::setGain(uint8_t gain) { // check allowed range if(gain > 6) { - return(ERR_INVALID_GAIN); + return(RADIOLIB_ERR_INVALID_GAIN); } // set mode to standby @@ -281,24 +281,24 @@ int16_t SX1278::setGain(uint8_t gain) { // get modem int16_t modem = getActiveModem(); - if(modem == SX127X_LORA){ + if(modem == RADIOLIB_SX127X_LORA){ // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_ON, 2, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); } else { - state |= _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_OFF, 2, 2); - state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON); + state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3); - state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } @@ -308,13 +308,13 @@ int16_t SX1278::setGain(uint8_t gain) { int16_t SX1278::setDataShaping(uint8_t sh) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation if(SX127x::_ook) { - return(ERR_INVALID_MODULATION); + return(RADIOLIB_ERR_INVALID_MODULATION); } // set mode to standby @@ -324,27 +324,27 @@ int16_t SX1278::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5)); case RADIOLIB_SHAPING_0_3: - return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5)); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5)); default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } } int16_t SX1278::setDataShapingOOK(uint8_t sh) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation if(!SX127x::_ook) { - return(ERR_INVALID_MODULATION); + return(RADIOLIB_ERR_INVALID_MODULATION); } // set mode to standby @@ -353,31 +353,31 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { // set data shaping switch(sh) { case 0: - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5); break; case 1: - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_OOK_FILTER_BR, 6, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5); break; case 2: - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_OOK_FILTER_2BR, 6, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5); break; default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } return(state); } float SX1278::getRSSI(bool skipReceive) { - if(getActiveModem() == SX127X_LORA) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { // for LoRa, get RSSI of the last packet float lastPacketRSSI; // RSSI calculation uses different constant for low-frequency and high-frequency ports if(_freq < 868.0) { - lastPacketRSSI = -164 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); + lastPacketRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); } else { - lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); + lastPacketRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); } // spread-spectrum modulation signal can be received below noise floor @@ -396,7 +396,7 @@ float SX1278::getRSSI(bool skipReceive) { } // read the value for FSK - float rssi = (float)_mod->SPIgetRegValue(SX127X_REG_RSSI_VALUE_FSK) / -2.0; + float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; // set mode back to standby if(!skipReceive) { @@ -409,61 +409,61 @@ float SX1278::getRSSI(bool skipReceive) { } int16_t SX1278::setCRC(bool enable, bool mode) { - if(getActiveModem() == SX127X_LORA) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC SX127x::_crcEnabled = enable; if(enable) { - return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2)); } else { - return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2)); } } else { // set FSK CRC - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(enable) { - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } int16_t SX1278::forceLDRO(bool enable) { - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } _ldroAuto = false; if(enable) { - return(_mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); } else { - return(_mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); } } int16_t SX1278::autoLDRO() { - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } _ldroAuto = true; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t SX1278::implicitHeader(size_t len) { - return(setHeaderType(SX1278_HEADER_IMPL_MODE, len)); + return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, len)); } int16_t SX1278::explicitHeader() { - return(setHeaderType(SX1278_HEADER_EXPL_MODE)); + return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE)); } int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { @@ -471,7 +471,7 @@ int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); return(state); } @@ -480,16 +480,16 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { int16_t state = SX127x::standby(); // write registers - if(newSpreadingFactor == SX127X_SF_6) { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_IMPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? SX1278_RX_CRC_MODE_ON : SX1278_RX_CRC_MODE_OFF), 7, 2); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6); + if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? RADIOLIB_SX1278_RX_CRC_MODE_ON : RADIOLIB_SX1278_RX_CRC_MODE_OFF), 7, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_EXPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? SX1278_RX_CRC_MODE_ON : SX1278_RX_CRC_MODE_OFF), 7, 2); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? RADIOLIB_SX1278_RX_CRC_MODE_ON : RADIOLIB_SX1278_RX_CRC_MODE_OFF), 7, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } @@ -499,22 +499,22 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); return(state); } int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set requested packet mode - int16_t state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value @@ -529,13 +529,13 @@ int16_t SX1278::configFSK() { RADIOLIB_ASSERT(state); // set fast PLL hop - state = _mod->SPIsetRegValue(SX1278_REG_PLL_HOP, SX127X_FAST_HOP_ON, 7, 7); + state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } void SX1278::errataFix(bool rx) { // only apply in LoRa mode - if(getActiveModem() != SX127X_LORA) { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { return; } diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 7e69a398ea..dd89f32b66 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -9,91 +9,91 @@ #include "SX127x.h" // SX1278 specific register map -#define SX1278_REG_MODEM_CONFIG_3 0x26 -#define SX1278_REG_PLL_HOP 0x44 -#define SX1278_REG_TCXO 0x4B -#define SX1278_REG_PA_DAC 0x4D -#define SX1278_REG_FORMER_TEMP 0x5B -#define SX1278_REG_REG_BIT_RATE_FRAC 0x5D -#define SX1278_REG_AGC_REF 0x61 -#define SX1278_REG_AGC_THRESH_1 0x62 -#define SX1278_REG_AGC_THRESH_2 0x63 -#define SX1278_REG_AGC_THRESH_3 0x64 -#define SX1278_REG_PLL 0x70 +#define RADIOLIB_SX1278_REG_MODEM_CONFIG_3 0x26 +#define RADIOLIB_SX1278_REG_PLL_HOP 0x44 +#define RADIOLIB_SX1278_REG_TCXO 0x4B +#define RADIOLIB_SX1278_REG_PA_DAC 0x4D +#define RADIOLIB_SX1278_REG_FORMER_TEMP 0x5B +#define RADIOLIB_SX1278_REG_REG_BIT_RATE_FRAC 0x5D +#define RADIOLIB_SX1278_REG_AGC_REF 0x61 +#define RADIOLIB_SX1278_REG_AGC_THRESH_1 0x62 +#define RADIOLIB_SX1278_REG_AGC_THRESH_2 0x63 +#define RADIOLIB_SX1278_REG_AGC_THRESH_3 0x64 +#define RADIOLIB_SX1278_REG_PLL 0x70 // SX1278 LoRa modem settings -// SX1278_REG_OP_MODE MSB LSB DESCRIPTION -#define SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers -#define SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers +// RADIOLIB_SX1278_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers +#define RADIOLIB_SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers -// SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB -#define SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 -#define SX1278_FRF_MID 0x80 // 7 0 where F(XOSC) = 32 MHz -#define SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers +// RADIOLIB_SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +#define RADIOLIB_SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_SX1278_FRF_MID 0x80 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers -// SX1278_REG_PA_CONFIG -#define SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm -#define SX1278_LOW_POWER 0b00100000 // 6 4 +// RADIOLIB_SX1278_REG_PA_CONFIG +#define RADIOLIB_SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm +#define RADIOLIB_SX1278_LOW_POWER 0b00100000 // 6 4 -// SX1278_REG_LNA -#define SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current +// RADIOLIB_SX1278_REG_LNA +#define RADIOLIB_SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current // SX127X_REG_MODEM_CONFIG_1 -#define SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz -#define SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz -#define SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz -#define SX1278_BW_20_80_KHZ 0b00110000 // 7 4 20.80 kHz -#define SX1278_BW_31_25_KHZ 0b01000000 // 7 4 31.25 kHz -#define SX1278_BW_41_70_KHZ 0b01010000 // 7 4 41.70 kHz -#define SX1278_BW_62_50_KHZ 0b01100000 // 7 4 62.50 kHz -#define SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz -#define SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz -#define SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz -#define SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5 -#define SX1278_CR_4_6 0b00000100 // 3 1 4/6 -#define SX1278_CR_4_7 0b00000110 // 3 1 4/7 -#define SX1278_CR_4_8 0b00001000 // 3 1 4/8 -#define SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode -#define SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode +#define RADIOLIB_SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz +#define RADIOLIB_SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz +#define RADIOLIB_SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz +#define RADIOLIB_SX1278_BW_20_80_KHZ 0b00110000 // 7 4 20.80 kHz +#define RADIOLIB_SX1278_BW_31_25_KHZ 0b01000000 // 7 4 31.25 kHz +#define RADIOLIB_SX1278_BW_41_70_KHZ 0b01010000 // 7 4 41.70 kHz +#define RADIOLIB_SX1278_BW_62_50_KHZ 0b01100000 // 7 4 62.50 kHz +#define RADIOLIB_SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz +#define RADIOLIB_SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz +#define RADIOLIB_SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz +#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5 +#define RADIOLIB_SX1278_CR_4_6 0b00000100 // 3 1 4/6 +#define RADIOLIB_SX1278_CR_4_7 0b00000110 // 3 1 4/7 +#define RADIOLIB_SX1278_CR_4_8 0b00001000 // 3 1 4/8 +#define RADIOLIB_SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode +#define RADIOLIB_SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode // SX127X_REG_MODEM_CONFIG_2 -#define SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled -#define SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled +#define RADIOLIB_SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled +#define RADIOLIB_SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled -// SX1278_REG_MODEM_CONFIG_3 -#define SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled -#define SX1278_LOW_DATA_RATE_OPT_ON 0b00001000 // 3 3 low data rate optimization enabled -#define SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA -#define SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop +// RADIOLIB_SX1278_REG_MODEM_CONFIG_3 +#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled +#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON 0b00001000 // 3 3 low data rate optimization enabled +#define RADIOLIB_SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA +#define RADIOLIB_SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop // SX127X_REG_VERSION -#define SX1278_CHIP_VERSION 0x12 +#define RADIOLIB_SX1278_CHIP_VERSION 0x12 // SX1278 FSK modem settings // SX127X_REG_PA_RAMP -#define SX1278_NO_SHAPING 0b00000000 // 6 5 data shaping: no shaping (default) -#define SX1278_FSK_GAUSSIAN_1_0 0b00100000 // 6 5 FSK modulation Gaussian filter, BT = 1.0 -#define SX1278_FSK_GAUSSIAN_0_5 0b01000000 // 6 5 FSK modulation Gaussian filter, BT = 0.5 -#define SX1278_FSK_GAUSSIAN_0_3 0b01100000 // 6 5 FSK modulation Gaussian filter, BT = 0.3 -#define SX1278_OOK_FILTER_BR 0b00100000 // 6 5 OOK modulation filter, f_cutoff = BR -#define SX1278_OOK_FILTER_2BR 0b01000000 // 6 5 OOK modulation filter, f_cutoff = 2*BR - -// SX1278_REG_AGC_REF -#define SX1278_AGC_REFERENCE_LEVEL_LF 0x19 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm]: below 525 MHz -#define SX1278_AGC_REFERENCE_LEVEL_HF 0x1C // 5 0 above 779 MHz - -// SX1278_REG_AGC_THRESH_1 -#define SX1278_AGC_STEP_1_LF 0x0C // 4 0 1st AGC threshold: below 525 MHz -#define SX1278_AGC_STEP_1_HF 0x0E // 4 0 above 779 MHz - -// SX1278_REG_AGC_THRESH_2 -#define SX1278_AGC_STEP_2_LF 0x40 // 7 4 2nd AGC threshold: below 525 MHz -#define SX1278_AGC_STEP_2_HF 0x50 // 7 4 above 779 MHz -#define SX1278_AGC_STEP_3 0x0B // 3 0 3rd AGC threshold - -// SX1278_REG_AGC_THRESH_3 -#define SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold -#define SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold +#define RADIOLIB_SX1278_NO_SHAPING 0b00000000 // 6 5 data shaping: no shaping (default) +#define RADIOLIB_SX1278_FSK_GAUSSIAN_1_0 0b00100000 // 6 5 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_5 0b01000000 // 6 5 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_3 0b01100000 // 6 5 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_SX1278_OOK_FILTER_BR 0b00100000 // 6 5 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_SX1278_OOK_FILTER_2BR 0b01000000 // 6 5 OOK modulation filter, f_cutoff = 2*BR + +// RADIOLIB_SX1278_REG_AGC_REF +#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_LF 0x19 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm]: below 525 MHz +#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_HF 0x1C // 5 0 above 779 MHz + +// RADIOLIB_SX1278_REG_AGC_THRESH_1 +#define RADIOLIB_SX1278_AGC_STEP_1_LF 0x0C // 4 0 1st AGC threshold: below 525 MHz +#define RADIOLIB_SX1278_AGC_STEP_1_HF 0x0E // 4 0 above 779 MHz + +// RADIOLIB_SX1278_REG_AGC_THRESH_2 +#define RADIOLIB_SX1278_AGC_STEP_2_LF 0x40 // 7 4 2nd AGC threshold: below 525 MHz +#define RADIOLIB_SX1278_AGC_STEP_2_HF 0x50 // 7 4 above 779 MHz +#define RADIOLIB_SX1278_AGC_STEP_3 0x0B // 3 0 3rd AGC threshold + +// RADIOLIB_SX1278_REG_AGC_THRESH_3 +#define RADIOLIB_SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold +#define RADIOLIB_SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold /*! \class SX1278 @@ -138,7 +138,7 @@ class SX1278: public SX127x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 8313a4899e..1eac9dc9ae 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -7,7 +7,7 @@ SX1279::SX1279(Module* mod) : SX1278(mod) { int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); + int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -34,7 +34,7 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -60,11 +60,11 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1279::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 3a8336d693..bfab291b34 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -49,7 +49,7 @@ class SX1279: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 81c24eef14..c8849f9692 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1,21 +1,25 @@ #include "SX127x.h" #if !defined(RADIOLIB_EXCLUDE_SX127X) -SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_FREQUENCY_STEP_SIZE, SX127X_MAX_PACKET_LENGTH) { +SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) { _mod = mod; } +Module* SX127x::getMod() { + return(_mod); +} + int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN(F("M\tSX127x")); @@ -28,9 +32,9 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe RADIOLIB_ASSERT(state); // check active modem - if(getActiveModem() != SX127X_LORA) { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { // set LoRa mode - state = setActiveModem(SX127X_LORA); + state = setActiveModem(RADIOLIB_SX127X_LORA); RADIOLIB_ASSERT(state); } @@ -54,14 +58,14 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN(F("M\tSX127x")); @@ -70,9 +74,9 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB RADIOLIB_ASSERT(state); // check currently active modem - if(getActiveModem() != SX127X_FSK_OOK) { + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { // set FSK mode - state = setActiveModem(SX127X_FSK_OOK); + state = setActiveModem(RADIOLIB_SX127X_FSK_OOK); RADIOLIB_ASSERT(state); } @@ -93,7 +97,7 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB RADIOLIB_ASSERT(state); // sets AFC&AGC trigger to RSSI and preamble detect - state = SX127x::setAFCAGCTrigger(SX127X_RX_TRIGGER_BOTH); + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); RADIOLIB_ASSERT(state); state = SX127x::setAFC(true); @@ -136,21 +140,21 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); uint32_t start = 0; - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // calculate timeout (150 % of expected time-one-air) float symbolLength = (float)(uint32_t(1) <<_sf) / (float)_bw; float de = 0; if(symbolLength >= 16.0) { de = 1; } - float ih = (float)_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_1, 0, 0); - float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); - float n_pre = (float)((_mod->SPIgetRegValue(SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(SX127X_REG_PREAMBLE_LSB)); + float ih = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + float crc = (float)(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + float n_pre = (float)((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); float n_pay = 8.0 + max(ceil((8.0 * (float)len - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0.0); uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1500.0); @@ -159,16 +163,16 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { clearIRQFlags(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // calculate timeout (5ms + 500 % of expected time-on-air) uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); @@ -177,21 +181,21 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { clearIRQFlags(); standby(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } } else { - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } // update data rate - uint32_t elapsed = Module::micros() - start; + uint32_t elapsed = _mod->micros() - start; _dataRate = (len*8.0)/((float)elapsed/1000000.0); // clear interrupt flags @@ -203,39 +207,39 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX127x::receive(uint8_t* data, size_t len) { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // set mode to receive - state = startReceive(len, SX127X_RXSINGLE); + state = startReceive(len, RADIOLIB_SX127X_RXSINGLE); RADIOLIB_ASSERT(state); // wait for packet reception or timeout (100 LoRa symbols) - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::digitalRead(_mod->getGpio())) { + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->digitalRead(_mod->getGpio())) { clearIRQFlags(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // calculate timeout (500 % of expected time-one-air) uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); // set mode to receive - state = startReceive(len, SX127X_RX); + state = startReceive(len, RADIOLIB_SX127X_RX); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { clearIRQFlags(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } } @@ -252,18 +256,18 @@ int16_t SX127x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::digitalRead(_mod->getGpio())) { + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->digitalRead(_mod->getGpio())) { clearIRQFlags(); - return(PREAMBLE_DETECTED); + return(RADIOLIB_PREAMBLE_DETECTED); } } // clear interrupt flags clearIRQFlags(); - return(CHANNEL_FREE); + return(RADIOLIB_CHANNEL_FREE); } int16_t SX127x::sleep() { @@ -271,7 +275,7 @@ int16_t SX127x::sleep() { _mod->setRfSwitchState(LOW, LOW); // set mode to sleep - return(setMode(SX127X_SLEEP)); + return(setMode(RADIOLIB_SX127X_SLEEP)); } int16_t SX127x::standby() { @@ -279,13 +283,13 @@ int16_t SX127x::standby() { _mod->setRfSwitchState(LOW, LOW); // set mode to standby - return(setMode(SX127X_STANDBY)); + return(setMode(RADIOLIB_SX127X_STANDBY)); } int16_t SX127x::transmitDirect(uint32_t frf) { // check modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set RF switch (if present) @@ -293,11 +297,11 @@ int16_t SX127x::transmitDirect(uint32_t frf) { // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { - _mod->SPIwriteRegister(SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16); - _mod->SPIwriteRegister(SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8); - _mod->SPIwriteRegister(SX127X_REG_FRF_LSB, frf & 0x0000FF); + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8); + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_LSB, frf & 0x0000FF); - return(setMode(SX127X_TX)); + return(setMode(RADIOLIB_SX127X_TX)); } // activate direct mode @@ -308,13 +312,13 @@ int16_t SX127x::transmitDirect(uint32_t frf) { RADIOLIB_ERRATA_SX127X(false); // start transmitting - return(setMode(SX127X_TX)); + return(setMode(RADIOLIB_SX127X_TX)); } int16_t SX127x::receiveDirect() { // check modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set RF switch (if present) @@ -328,48 +332,48 @@ int16_t SX127x::receiveDirect() { RADIOLIB_ERRATA_SX127X(true); // start receiving - return(setMode(SX127X_RX)); + return(setMode(RADIOLIB_SX127X_RX)); } int16_t SX127x::directMode() { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // set DIO mapping - state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO1_CONT_DCLK | SX127X_DIO2_CONT_DATA, 5, 2); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_CONT_DCLK | RADIOLIB_SX127X_DIO2_CONT_DATA, 5, 2); RADIOLIB_ASSERT(state); // enable receiver startup without preamble or RSSI - state = SX127x::setAFCAGCTrigger(SX127X_RX_TRIGGER_NONE); + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_NONE); RADIOLIB_ASSERT(state); // set continuous mode - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_CONTINUOUS, 6, 6)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_CONTINUOUS, 6, 6)); } int16_t SX127x::packetMode() { // check modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET, 6, 6)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6)); } int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping - state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); // set expected packet length for SF6 if(_sf == 6) { - state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); } // apply fixes to errata @@ -379,21 +383,21 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { clearIRQFlags(); // set FIFO pointers - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX); - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); RADIOLIB_ASSERT(state); - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set DIO pin mapping - state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); RADIOLIB_ASSERT(state); // clear interrupt flags clearIRQFlags(); // FSK modem does not distinguish between Rx single and continuous - if(mode == SX127X_RXCONTINUOUS) { - return(setMode(SX127X_RX)); + if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { + return(setMode(RADIOLIB_SX127X_RX)); } } @@ -405,40 +409,40 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { } void SX127x::setDio0Action(void (*func)(void)) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void SX127x::clearDio0Action() { - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } void SX127x::setDio1Action(void (*func)(void)) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); } void SX127x::clearDio1Action() { if(_mod->getGpio() == RADIOLIB_NC) { return; } - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); int16_t modem = getActiveModem(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // check packet length - if(len >= SX127X_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len >= RADIOLIB_SX127X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set DIO mapping - _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); // apply fixes to errata RADIOLIB_ERRATA_SX127X(false); @@ -447,47 +451,47 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { clearIRQFlags(); // set packet length - state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); // set FIFO pointers - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX); - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // check packet length - if(len >= SX127X_MAX_PACKET_LENGTH_FSK) { - return(ERR_PACKET_TOO_LONG); + if(len >= RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set DIO mapping - _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); // clear interrupt flags clearIRQFlags(); // set packet length - if (_packetLengthConfig == SX127X_PACKET_VARIABLE) { - _mod->SPIwriteRegister(SX127X_REG_FIFO, len); + if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); } // check address filtering - uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); - if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIwriteRegister(SX127X_REG_FIFO, addr); + uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); } } // write packet to FIFO - _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); + _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, len); // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); // start transmission - state |= setMode(SX127X_TX); + state |= setMode(RADIOLIB_SX127X_TX); RADIOLIB_ASSERT(state); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t SX127x::readData(uint8_t* data, size_t len) { @@ -497,40 +501,40 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // put module to standby standby(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // len set to maximum indicates unknown packet length, read the number of actually received bytes - if(len == SX127X_MAX_PACKET_LENGTH) { + if(len == RADIOLIB_SX127X_MAX_PACKET_LENGTH) { length = getPacketLength(); } // check packet header integrity - if(_crcEnabled && (_mod->SPIgetRegValue(SX127X_REG_HOP_CHANNEL, 6, 6)) == 0) { + if(_crcEnabled && (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6)) == 0) { // CRC is disabled according to packet header and enabled according to user // most likely damaged packet header clearIRQFlags(); - return(ERR_LORA_HEADER_DAMAGED); + return(RADIOLIB_ERR_LORA_HEADER_DAMAGED); } // check payload CRC - if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { // clear interrupt flags clearIRQFlags(); - return(ERR_CRC_MISMATCH); + return(RADIOLIB_ERR_CRC_MISMATCH); } - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // read packet length (always required in FSK) length = getPacketLength(); // check address filtering - uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); - if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIreadRegister(SX127X_REG_FIFO); + uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); } } // read packet data - _mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data); + _mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data); // dump bytes that weren't requested size_t packetLength = getPacketLength(); @@ -544,21 +548,21 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // clear interrupt flags clearIRQFlags(); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t SX127x::startChannelScan() { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // set DIO pin mapping - state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_CAD_DONE | RADIOLIB_SX127X_DIO1_CAD_DETECTED, 7, 4); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -568,83 +572,83 @@ int16_t SX127x::startChannelScan() { _mod->setRfSwitchState(HIGH, LOW); // set mode to CAD - state = setMode(SX127X_CAD); + state = setMode(RADIOLIB_SX127X_CAD); return(state); } int16_t SX127x::setSyncWord(uint8_t syncWord) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby - setMode(SX127X_STANDBY); + setMode(RADIOLIB_SX127X_STANDBY); // write register - return(_mod->SPIsetRegValue(SX127X_REG_SYNC_WORD, syncWord)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_WORD, syncWord)); } int16_t SX127x::setCurrentLimit(uint8_t currentLimit) { // check allowed range if(!(((currentLimit >= 45) && (currentLimit <= 240)) || (currentLimit == 0))) { - return(ERR_INVALID_CURRENT_LIMIT); + return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT); } // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); // set OCP limit uint8_t raw; if(currentLimit == 0) { // limit set to 0, disable OCP - state |= _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_OFF, 5, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_OFF, 5, 5); } else if(currentLimit <= 120) { raw = (currentLimit - 45) / 5; - state |= _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_ON | raw, 5, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); } else if(currentLimit <= 240) { raw = (currentLimit + 30) / 10; - state |= _mod->SPIsetRegValue(SX127X_REG_OCP, SX127X_OCP_ON | raw, 5, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); } return(state); } int16_t SX127x::setPreambleLength(uint16_t preambleLength) { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // check active modem uint8_t modem = getActiveModem(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // check allowed range if(preambleLength < 6) { - return(ERR_INVALID_PREAMBLE_LENGTH); + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } // set preamble length - state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF)); - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF)); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF)); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF)); return(state); - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set preamble length (in bytes) uint16_t numBytes = preambleLength / 8; - state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF)); - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF)); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF)); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF)); return(state); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } float SX127x::getFrequencyError(bool autoCorrect) { int16_t modem = getActiveModem(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { // get raw frequency error - uint32_t raw = (uint32_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB, 3, 0) << 16; - raw |= (uint16_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8; - raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB); + uint32_t raw = (uint32_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB, 3, 0) << 16; + raw |= (uint16_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MID) << 8; + raw |= _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB); uint32_t base = (uint32_t)2 << 23; float error; @@ -667,10 +671,10 @@ float SX127x::getFrequencyError(bool autoCorrect) { return(error); - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // get raw frequency error - uint16_t raw = (uint16_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8; - raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB_FSK); + uint16_t raw = (uint16_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB_FSK) << 8; + raw |= _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB_FSK); uint32_t base = 1; float error; @@ -688,20 +692,20 @@ float SX127x::getFrequencyError(bool autoCorrect) { return(error); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } float SX127x::getAFCError() { // check active modem int16_t modem = getActiveModem(); - if(modem != SX127X_FSK_OOK) { + if(modem != RADIOLIB_SX127X_FSK_OOK) { return 0; } // get raw frequency error - int16_t raw = (uint16_t)_mod->SPIreadRegister(SX127X_REG_AFC_MSB) << 8; - raw |= _mod->SPIreadRegister(SX127X_REG_AFC_LSB); + int16_t raw = (uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_MSB) << 8; + raw |= _mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB); uint32_t base = 1; return raw * (32000000.0 / (float)(base << 19)); @@ -709,12 +713,12 @@ float SX127x::getAFCError() float SX127x::getSNR() { // check active modem - if(getActiveModem() != SX127X_LORA) { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(0); } // get SNR value - int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); + int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_SNR_VALUE); return(rawSNR / 4.0); } @@ -724,28 +728,28 @@ float SX127x::getDataRate() const { int16_t SX127x::setBitRate(float br) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // check allowed bit rate if(_ook) { - RADIOLIB_CHECK_RANGE(br, 1.2, 32.768, ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 1.2, 32.768, RADIOLIB_ERR_INVALID_BIT_RATE); } else { - RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); } // set mode to STANDBY - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // set bit rate - uint16_t bitRate = (SX127X_CRYSTAL_FREQ * 1000.0) / br; - state = _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + uint16_t bitRate = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br; + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); /// \todo fractional part of bit rate setting (not in OOK) - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_br = br; } return(state); @@ -753,8 +757,8 @@ int16_t SX127x::setBitRate(float br) { int16_t SX127x::setFrequencyDeviation(float freqDev) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set frequency deviation to lowest available setting (required for digimodes) @@ -765,18 +769,18 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) { // check frequency deviation range if(!((newFreqDev + _br/2.0 <= 250.0) && (freqDev <= 200.0))) { - return(ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } // set mode to STANDBY - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // set allowed frequency deviation uint32_t base = 1; uint32_t FDEV = (newFreqDev * (base << 19)) / 32000; - state = _mod->SPIsetRegValue(SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0); return(state); } @@ -784,7 +788,7 @@ uint8_t SX127x::calculateBWManExp(float bandwidth) { for(uint8_t e = 7; e >= 1; e--) { for(int8_t m = 2; m >= 0; m--) { - float point = (SX127X_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); + float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); if(fabs(bandwidth - ((point / 1000.0) + 0.05)) <= 0.5) { return((m << 3) | e); } @@ -795,164 +799,164 @@ uint8_t SX127x::calculateBWManExp(float bandwidth) int16_t SX127x::setRxBandwidth(float rxBw) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // set mode to STANDBY - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // set Rx bandwidth - return(_mod->SPIsetRegValue(SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0)); } int16_t SX127x::setAFCBandwidth(float rxBw){ // check active modem - if(getActiveModem() != SX127X_FSK_OOK){ - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK){ + return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // set mode to STANDBY - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); // set AFC bandwidth - return(_mod->SPIsetRegValue(SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0)); } int16_t SX127x::setAFC(bool isEnabled){ // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } //set AFC auto on/off - return(_mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, isEnabled ? SX127X_AFC_AUTO_ON : SX127X_AFC_AUTO_OFF, 4, 4)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4)); } int16_t SX127x::setAFCAGCTrigger(uint8_t trigger){ - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } //set AFC&AGC trigger - return(_mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, trigger, 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0)); } int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(len, 1, 8, ERR_INVALID_SYNC_WORD); + RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD); // sync word must not contain value 0x00 for(size_t i = 0; i < len; i++) { if(syncWord[i] == 0x00) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } } // enable sync word recognition - int16_t state = _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_SYNC_ON, 4, 4); - state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); RADIOLIB_ASSERT(state); // set sync word - _mod->SPIwriteRegisterBurst(SX127X_REG_SYNC_VALUE_1, syncWord, len); - return(ERR_NONE); + _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len); + return(RADIOLIB_ERR_NONE); } int16_t SX127x::setNodeAddress(uint8_t nodeAddr) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // enable address filtering (node only) - int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE, 2, 1); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1); RADIOLIB_ASSERT(state); // set node address - return(_mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, nodeAddr)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr)); } int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // enable address filtering (node + broadcast) - int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); RADIOLIB_ASSERT(state); // set broadcast address - return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, broadAddr)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr)); } int16_t SX127x::disableAddressFiltering() { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // disable address filtering - int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_OFF, 2, 1); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1); RADIOLIB_ASSERT(state); // set node address to default (0x00) - state = _mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, 0x00); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00); RADIOLIB_ASSERT(state); // set broadcast address to default (0x00) - return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00)); } int16_t SX127x::setOokThresholdType(uint8_t type) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(SX127X_REG_OOK_PEAK, type, 4, 3, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5)); } int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(SX127X_REG_OOK_FIX, value, 7, 0, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5)); } int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(SX127X_REG_OOK_AVG, value, 7, 5, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5)); } int16_t SX127x::setOOK(bool enableOOK) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set OOK and if successful, save the new setting - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(enableOOK) { - state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_OOK, 6, 5, 5); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5); } else { - state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5, 5); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5); } - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { _ook = enableOOK; } @@ -961,38 +965,38 @@ int16_t SX127x::setOOK(bool enableOOK) { int16_t SX127x::setFrequencyRaw(float newFreq) { // set mode to standby - int16_t state = setMode(SX127X_STANDBY); + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); // calculate register values - uint32_t FRF = (newFreq * (uint32_t(1) << SX127X_DIV_EXPONENT)) / SX127X_CRYSTAL_FREQ; + uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; // write registers - state |= _mod->SPIsetRegValue(SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); - state |= _mod->SPIsetRegValue(SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); - state |= _mod->SPIsetRegValue(SX127X_REG_FRF_LSB, FRF & 0x0000FF); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF); return(state); } size_t SX127x::getPacketLength(bool update) { int16_t modem = getActiveModem(); - if(modem == SX127X_LORA) { + if(modem == RADIOLIB_SX127X_LORA) { if(_sf != 6) { // get packet length for SF7 - SF12 - return(_mod->SPIreadRegister(SX127X_REG_RX_NB_BYTES)); + return(_mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES)); } else { // return the cached value for SF6 return(_packetLength); } - } else if(modem == SX127X_FSK_OOK) { + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // get packet length if(!_packetLengthQueried && update) { - if (_packetLengthConfig == SX127X_PACKET_VARIABLE) { - _packetLength = _mod->SPIreadRegister(SX127X_REG_FIFO); + if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + _packetLength = _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); } else { - _packetLength = _mod->SPIreadRegister(SX127X_REG_PAYLOAD_LENGTH_FSK); + _packetLength = _mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); } _packetLengthQueried = true; } @@ -1002,17 +1006,17 @@ size_t SX127x::getPacketLength(bool update) { } int16_t SX127x::fixedPacketLengthMode(uint8_t len) { - return(SX127x::setPacketMode(SX127X_PACKET_FIXED, len)); + return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len)); } int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { - return(SX127x::setPacketMode(SX127X_PACKET_VARIABLE, maxLen)); + return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen)); } int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -1021,46 +1025,46 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { // check provided values if(!(smoothingSamples <= 7)) { - return(ERR_INVALID_NUM_SAMPLES); + return(RADIOLIB_ERR_INVALID_NUM_SAMPLES); } - RADIOLIB_CHECK_RANGE(offset, -16, 15, ERR_INVALID_RSSI_OFFSET); + RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET); // set new register values - state = _mod->SPIsetRegValue(SX127X_REG_RSSI_CONFIG, offset, 7, 3); - state |= _mod->SPIsetRegValue(SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset, 7, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); return(state); } int16_t SX127x::setEncoding(uint8_t encoding) { // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set encoding switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_NONE, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5)); case RADIOLIB_ENCODING_MANCHESTER: - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_MANCHESTER, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5)); case RADIOLIB_ENCODING_WHITENING: - return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_WHITENING, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5)); default: - return(ERR_INVALID_ENCODING); + return(RADIOLIB_ERR_INVALID_ENCODING); } } uint16_t SX127x::getIRQFlags() { // check active modem - if(getActiveModem() == SX127X_LORA) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { // LoRa, just 8-bit value - return((uint16_t)_mod->SPIreadRegister(SX127X_REG_IRQ_FLAGS)); + return((uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS)); } else { // FSK, the IRQ flags are 16 bits in total - uint16_t flags = ((uint16_t)_mod->SPIreadRegister(SX127X_REG_IRQ_FLAGS_2)) << 8; - flags |= (uint16_t)_mod->SPIreadRegister(SX127X_REG_IRQ_FLAGS_1); + uint16_t flags = ((uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8; + flags |= (uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1); return(flags); } @@ -1068,12 +1072,12 @@ uint16_t SX127x::getIRQFlags() { uint8_t SX127x::getModemStatus() { // check active modem - if(getActiveModem() != SX127X_LORA) { + if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(0x00); } // read the register - return(_mod->SPIreadRegister(SX127X_REG_MODEM_STAT)); + return(_mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT)); } void SX127x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { @@ -1082,16 +1086,16 @@ void SX127x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { uint8_t SX127x::randomByte() { // check active modem - uint8_t rssiValueReg = SX127X_REG_RSSI_WIDEBAND; - if(getActiveModem() == SX127X_FSK_OOK) { - rssiValueReg = SX127X_REG_RSSI_VALUE_FSK; + uint8_t rssiValueReg = RADIOLIB_SX127X_REG_RSSI_WIDEBAND; + if(getActiveModem() == RADIOLIB_SX127X_FSK_OOK) { + rssiValueReg = RADIOLIB_SX127X_REG_RSSI_VALUE_FSK; } // set mode to Rx - setMode(SX127X_RX); + setMode(RADIOLIB_SX127X_RX); // wait a bit for the RSSI reading to stabilise - Module::delay(10); + _mod->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -1100,13 +1104,13 @@ uint8_t SX127x::randomByte() { } // set mode to standby - setMode(SX127X_STANDBY); + setMode(RADIOLIB_SX127X_STANDBY); return(randByte); } int16_t SX127x::getChipVersion() { - return(_mod->SPIgetRegValue(SX127X_REG_VERSION)); + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION)); } int8_t SX127x::getTempRaw() { @@ -1115,33 +1119,33 @@ int8_t SX127x::getTempRaw() { uint8_t ival; // save current Op Mode - previousOpMode = _mod->SPIgetRegValue(SX127X_REG_OP_MODE); + previousOpMode = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE); // check if we need to step out of LoRa mode first - if ((previousOpMode & SX127X_LORA) == SX127X_LORA) { - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_LORA | SX127X_SLEEP)); + if ((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); } // put device in FSK sleep - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_FSK_OOK | SX127X_SLEEP)); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); // put device in FSK RxSynth - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_FSK_OOK | SX127X_FSRX)); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX)); // enable temperature reading - _mod->SPIsetRegValue(SX127X_REG_IMAGE_CAL, SX127X_TEMP_MONITOR_ON, 0, 0); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0); // wait - Module::delayMicroseconds(200); + _mod->delayMicroseconds(200); // disable temperature reading - _mod->SPIsetRegValue(SX127X_REG_IMAGE_CAL, SX127X_TEMP_MONITOR_OFF, 0, 0); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0); // put device in FSK sleep - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_FSK_OOK | SX127X_SLEEP)); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); // read temperature - ival = _mod->SPIgetRegValue(SX127X_REG_TEMP); + ival = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP); // convert very raw value if ((ival & 0x80) == 0x80) { @@ -1151,73 +1155,73 @@ int8_t SX127x::getTempRaw() { } // check if we need to step back into LoRa mode - if ((previousOpMode & SX127X_LORA) == SX127X_LORA) { - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_LORA | SX127X_SLEEP)); + if ((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); } // reload previous Op Mode - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, previousOpMode); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode); return(temp); } int16_t SX127x::config() { // turn off frequency hopping - int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF); return(state); } int16_t SX127x::configFSK() { // set RSSI threshold - int16_t state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD); RADIOLIB_ASSERT(state); // reset FIFO flag - _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN); + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN); // set packet configuration - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_NONE | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON | SX127X_ADDRESS_FILTERING_OFF | SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 5); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_PACKET_VARIABLE | RADIOLIB_SX127X_DC_FREE_NONE | RADIOLIB_SX127X_CRC_ON | RADIOLIB_SX127X_CRC_AUTOCLEAR_ON | RADIOLIB_SX127X_ADDRESS_FILTERING_OFF | RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5); RADIOLIB_ASSERT(state); // set preamble polarity - state =_mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_PREAMBLE_POLARITY_55, 5, 5); + state =_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_PREAMBLE_POLARITY_55, 5, 5); RADIOLIB_ASSERT(state); // set FIFO threshold - state = _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_FIFO_THRESH, 5, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); RADIOLIB_ASSERT(state); // disable Rx timeouts - state = _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_1, SX127X_TIMEOUT_RX_RSSI_OFF); - state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_2, SX127X_TIMEOUT_RX_PREAMBLE_OFF); - state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_3, SX127X_TIMEOUT_SIGNAL_SYNC_OFF); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF); RADIOLIB_ASSERT(state); // enable preamble detector - state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_2_BYTE | SX127X_PREAMBLE_DETECTOR_TOL); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_DETECT, RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON | RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE | RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL); return(state); } int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) { // check packet length - if (len > SX127X_MAX_PACKET_LENGTH_FSK) { - return(ERR_PACKET_TOO_LONG); + if (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // check active modem - if(getActiveModem() != SX127X_FSK_OOK) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set to fixed packet length - int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, mode, 7, 7); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH_FSK, len); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len); RADIOLIB_ASSERT(state); // update cached value @@ -1237,10 +1241,10 @@ bool SX127x::findChip(uint8_t ver) { if(version == ver) { flagFound = true; } else { - #ifdef RADIOLIB_DEBUG + #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINT(F("SX127x not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SX127X_REG_VERSION == ")); + RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_SX127X_REG_VERSION == ")); char buffHex[12]; sprintf(buffHex, "0x%04X", version); @@ -1248,7 +1252,7 @@ bool SX127x::findChip(uint8_t ver) { RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); RADIOLIB_DEBUG_PRINTLN(ver, HEX); #endif - Module::delay(10); + _mod->delay(10); i++; } } @@ -1258,61 +1262,61 @@ bool SX127x::findChip(uint8_t ver) { int16_t SX127x::setMode(uint8_t mode) { uint8_t checkMask = 0xFF; - if((getActiveModem() == SX127X_FSK_OOK) && (mode == SX127X_RX)) { + if((getActiveModem() == RADIOLIB_SX127X_FSK_OOK) && (mode == RADIOLIB_SX127X_RX)) { // disable checking of RX bit in FSK RX mode, as it sometimes seem to fail (#276) checkMask = 0xFE; } - return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask)); } int16_t SX127x::getActiveModem() { - return(_mod->SPIgetRegValue(SX127X_REG_OP_MODE, 7, 7)); + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7)); } int16_t SX127x::setActiveModem(uint8_t modem) { // set mode to SLEEP - int16_t state = setMode(SX127X_SLEEP); + int16_t state = setMode(RADIOLIB_SX127X_SLEEP); // set modem - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, modem, 7, 7, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5); // set mode to STANDBY - state |= setMode(SX127X_STANDBY); + state |= setMode(RADIOLIB_SX127X_STANDBY); return(state); } void SX127x::clearIRQFlags() { int16_t modem = getActiveModem(); - if(modem == SX127X_LORA) { - _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS, 0b11111111); - } else if(modem == SX127X_FSK_OOK) { - _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_1, 0b11111111); - _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, 0b11111111); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, 0b11111111); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, 0b11111111); + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, 0b11111111); } } void SX127x::clearFIFO(size_t count) { while(count) { - _mod->SPIreadRegister(SX127X_REG_FIFO); + _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); count--; } } int16_t SX127x::invertIQ(bool invertIQ) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t state; if(invertIQ) { - state = _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_RXPATH_ON, 6, 6); - state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_TXPATH_ON, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ2, SX127X_IQ2_ENABLE); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE); } else { - state = _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_RXPATH_OFF, 6, 6); - state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ2, SX127X_IQ2_DISABLE); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE); } return(state); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index bde973ace6..c4c7253f8a 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -10,533 +10,533 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // SX127x physical layer properties -#define SX127X_FREQUENCY_STEP_SIZE 61.03515625 -#define SX127X_MAX_PACKET_LENGTH 255 -#define SX127X_MAX_PACKET_LENGTH_FSK 64 -#define SX127X_CRYSTAL_FREQ 32.0 -#define SX127X_DIV_EXPONENT 19 +#define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 +#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX127X_DIV_EXPONENT 19 // SX127x series common LoRa registers -#define SX127X_REG_FIFO 0x00 -#define SX127X_REG_OP_MODE 0x01 -#define SX127X_REG_FRF_MSB 0x06 -#define SX127X_REG_FRF_MID 0x07 -#define SX127X_REG_FRF_LSB 0x08 -#define SX127X_REG_PA_CONFIG 0x09 -#define SX127X_REG_PA_RAMP 0x0A -#define SX127X_REG_OCP 0x0B -#define SX127X_REG_LNA 0x0C -#define SX127X_REG_FIFO_ADDR_PTR 0x0D -#define SX127X_REG_FIFO_TX_BASE_ADDR 0x0E -#define SX127X_REG_FIFO_RX_BASE_ADDR 0x0F -#define SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 -#define SX127X_REG_IRQ_FLAGS_MASK 0x11 -#define SX127X_REG_IRQ_FLAGS 0x12 -#define SX127X_REG_RX_NB_BYTES 0x13 -#define SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 -#define SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 -#define SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 -#define SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 -#define SX127X_REG_MODEM_STAT 0x18 -#define SX127X_REG_PKT_SNR_VALUE 0x19 -#define SX127X_REG_PKT_RSSI_VALUE 0x1A -#define SX127X_REG_RSSI_VALUE 0x1B -#define SX127X_REG_HOP_CHANNEL 0x1C -#define SX127X_REG_MODEM_CONFIG_1 0x1D -#define SX127X_REG_MODEM_CONFIG_2 0x1E -#define SX127X_REG_SYMB_TIMEOUT_LSB 0x1F -#define SX127X_REG_PREAMBLE_MSB 0x20 -#define SX127X_REG_PREAMBLE_LSB 0x21 -#define SX127X_REG_PAYLOAD_LENGTH 0x22 -#define SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 -#define SX127X_REG_HOP_PERIOD 0x24 -#define SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 -#define SX127X_REG_FEI_MSB 0x28 -#define SX127X_REG_FEI_MID 0x29 -#define SX127X_REG_FEI_LSB 0x2A -#define SX127X_REG_RSSI_WIDEBAND 0x2C -#define SX127X_REG_DETECT_OPTIMIZE 0x31 -#define SX127X_REG_INVERT_IQ 0x33 -#define SX127X_REG_DETECTION_THRESHOLD 0x37 -#define SX127X_REG_SYNC_WORD 0x39 -#define SX127X_REG_INVERT_IQ2 0x3B -#define SX127X_REG_DIO_MAPPING_1 0x40 -#define SX127X_REG_DIO_MAPPING_2 0x41 -#define SX127X_REG_VERSION 0x42 +#define RADIOLIB_SX127X_REG_FIFO 0x00 +#define RADIOLIB_SX127X_REG_OP_MODE 0x01 +#define RADIOLIB_SX127X_REG_FRF_MSB 0x06 +#define RADIOLIB_SX127X_REG_FRF_MID 0x07 +#define RADIOLIB_SX127X_REG_FRF_LSB 0x08 +#define RADIOLIB_SX127X_REG_PA_CONFIG 0x09 +#define RADIOLIB_SX127X_REG_PA_RAMP 0x0A +#define RADIOLIB_SX127X_REG_OCP 0x0B +#define RADIOLIB_SX127X_REG_LNA 0x0C +#define RADIOLIB_SX127X_REG_FIFO_ADDR_PTR 0x0D +#define RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR 0x0E +#define RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR 0x0F +#define RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_MASK 0x11 +#define RADIOLIB_SX127X_REG_IRQ_FLAGS 0x12 +#define RADIOLIB_SX127X_REG_RX_NB_BYTES 0x13 +#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 +#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 +#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 +#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 +#define RADIOLIB_SX127X_REG_MODEM_STAT 0x18 +#define RADIOLIB_SX127X_REG_PKT_SNR_VALUE 0x19 +#define RADIOLIB_SX127X_REG_PKT_RSSI_VALUE 0x1A +#define RADIOLIB_SX127X_REG_RSSI_VALUE 0x1B +#define RADIOLIB_SX127X_REG_HOP_CHANNEL 0x1C +#define RADIOLIB_SX127X_REG_MODEM_CONFIG_1 0x1D +#define RADIOLIB_SX127X_REG_MODEM_CONFIG_2 0x1E +#define RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB 0x1F +#define RADIOLIB_SX127X_REG_PREAMBLE_MSB 0x20 +#define RADIOLIB_SX127X_REG_PREAMBLE_LSB 0x21 +#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH 0x22 +#define RADIOLIB_SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 +#define RADIOLIB_SX127X_REG_HOP_PERIOD 0x24 +#define RADIOLIB_SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 +#define RADIOLIB_SX127X_REG_FEI_MSB 0x28 +#define RADIOLIB_SX127X_REG_FEI_MID 0x29 +#define RADIOLIB_SX127X_REG_FEI_LSB 0x2A +#define RADIOLIB_SX127X_REG_RSSI_WIDEBAND 0x2C +#define RADIOLIB_SX127X_REG_DETECT_OPTIMIZE 0x31 +#define RADIOLIB_SX127X_REG_INVERT_IQ 0x33 +#define RADIOLIB_SX127X_REG_DETECTION_THRESHOLD 0x37 +#define RADIOLIB_SX127X_REG_SYNC_WORD 0x39 +#define RADIOLIB_SX127X_REG_INVERT_IQ2 0x3B +#define RADIOLIB_SX127X_REG_DIO_MAPPING_1 0x40 +#define RADIOLIB_SX127X_REG_DIO_MAPPING_2 0x41 +#define RADIOLIB_SX127X_REG_VERSION 0x42 // SX127x common LoRa modem settings // SX127X_REG_OP_MODE MSB LSB DESCRIPTION -#define SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode -#define SX127X_LORA 0b10000000 // 7 7 LoRa mode -#define SX127X_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode -#define SX127X_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode -#define SX127X_SLEEP 0b00000000 // 2 0 sleep -#define SX127X_STANDBY 0b00000001 // 2 0 standby -#define SX127X_FSTX 0b00000010 // 2 0 frequency synthesis TX -#define SX127X_TX 0b00000011 // 2 0 transmit -#define SX127X_FSRX 0b00000100 // 2 0 frequency synthesis RX -#define SX127X_RXCONTINUOUS 0b00000101 // 2 0 receive continuous -#define SX127X_RXSINGLE 0b00000110 // 2 0 receive single -#define SX127X_CAD 0b00000111 // 2 0 channel activity detection +#define RADIOLIB_SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode +#define RADIOLIB_SX127X_LORA 0b10000000 // 7 7 LoRa mode +#define RADIOLIB_SX127X_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode +#define RADIOLIB_SX127X_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode +#define RADIOLIB_SX127X_SLEEP 0b00000000 // 2 0 sleep +#define RADIOLIB_SX127X_STANDBY 0b00000001 // 2 0 standby +#define RADIOLIB_SX127X_FSTX 0b00000010 // 2 0 frequency synthesis TX +#define RADIOLIB_SX127X_TX 0b00000011 // 2 0 transmit +#define RADIOLIB_SX127X_FSRX 0b00000100 // 2 0 frequency synthesis RX +#define RADIOLIB_SX127X_RXCONTINUOUS 0b00000101 // 2 0 receive continuous +#define RADIOLIB_SX127X_RXSINGLE 0b00000110 // 2 0 receive single +#define RADIOLIB_SX127X_CAD 0b00000111 // 2 0 channel activity detection // SX127X_REG_PA_CONFIG -#define SX127X_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm -#define SX127X_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm -#define SX127X_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST +#define RADIOLIB_SX127X_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm +#define RADIOLIB_SX127X_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm +#define RADIOLIB_SX127X_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST // P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_RFO // SX127X_REG_OCP -#define SX127X_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled -#define SX127X_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled -#define SX127X_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA +#define RADIOLIB_SX127X_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled +#define RADIOLIB_SX127X_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled +#define RADIOLIB_SX127X_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA // SX127X_REG_LNA -#define SX127X_LNA_GAIN_1 0b00100000 // 7 5 LNA gain setting: max gain -#define SX127X_LNA_GAIN_2 0b01000000 // 7 5 . -#define SX127X_LNA_GAIN_3 0b01100000 // 7 5 . -#define SX127X_LNA_GAIN_4 0b10000000 // 7 5 . -#define SX127X_LNA_GAIN_5 0b10100000 // 7 5 . -#define SX127X_LNA_GAIN_6 0b11000000 // 7 5 min gain -#define SX127X_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current -#define SX127X_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current +#define RADIOLIB_SX127X_LNA_GAIN_1 0b00100000 // 7 5 LNA gain setting: max gain +#define RADIOLIB_SX127X_LNA_GAIN_2 0b01000000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_3 0b01100000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_4 0b10000000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_5 0b10100000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_6 0b11000000 // 7 5 min gain +#define RADIOLIB_SX127X_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current +#define RADIOLIB_SX127X_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current // SX127X_REG_MODEM_CONFIG_2 -#define SX127X_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit -#define SX127X_SF_7 0b01110000 // 7 4 128 chips/bit -#define SX127X_SF_8 0b10000000 // 7 4 256 chips/bit -#define SX127X_SF_9 0b10010000 // 7 4 512 chips/bit -#define SX127X_SF_10 0b10100000 // 7 4 1024 chips/bit -#define SX127X_SF_11 0b10110000 // 7 4 2048 chips/bit -#define SX127X_SF_12 0b11000000 // 7 4 4096 chips/bit -#define SX127X_TX_MODE_SINGLE 0b00000000 // 3 3 single TX -#define SX127X_TX_MODE_CONT 0b00001000 // 3 3 continuous TX -#define SX127X_RX_TIMEOUT_MSB 0b00000000 // 1 0 +#define RADIOLIB_SX127X_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit +#define RADIOLIB_SX127X_SF_7 0b01110000 // 7 4 128 chips/bit +#define RADIOLIB_SX127X_SF_8 0b10000000 // 7 4 256 chips/bit +#define RADIOLIB_SX127X_SF_9 0b10010000 // 7 4 512 chips/bit +#define RADIOLIB_SX127X_SF_10 0b10100000 // 7 4 1024 chips/bit +#define RADIOLIB_SX127X_SF_11 0b10110000 // 7 4 2048 chips/bit +#define RADIOLIB_SX127X_SF_12 0b11000000 // 7 4 4096 chips/bit +#define RADIOLIB_SX127X_TX_MODE_SINGLE 0b00000000 // 3 3 single TX +#define RADIOLIB_SX127X_TX_MODE_CONT 0b00001000 // 3 3 continuous TX +#define RADIOLIB_SX127X_RX_TIMEOUT_MSB 0b00000000 // 1 0 // SX127X_REG_SYMB_TIMEOUT_LSB -#define SX127X_RX_TIMEOUT_LSB 0b01100100 // 7 0 10 bit RX operation timeout +#define RADIOLIB_SX127X_RX_TIMEOUT_LSB 0b01100100 // 7 0 10 bit RX operation timeout // SX127X_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB -#define SX127X_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25 -#define SX127X_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length +#define RADIOLIB_SX127X_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25 +#define RADIOLIB_SX127X_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length // SX127X_REG_DETECT_OPTIMIZE -#define SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization -#define SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization +#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization +#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization // SX127X_REG_INVERT_IQ -#define SX127X_INVERT_IQ_RXPATH_ON 0b01000000 // 6 6 I and Q signals are inverted -#define SX127X_INVERT_IQ_RXPATH_OFF 0b00000000 // 6 6 normal mode -#define SX127X_INVERT_IQ_TXPATH_ON 0b00000001 // 0 0 I and Q signals are inverted -#define SX127X_INVERT_IQ_TXPATH_OFF 0b00000000 // 0 0 normal mode +#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON 0b01000000 // 6 6 I and Q signals are inverted +#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF 0b00000000 // 6 6 normal mode +#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON 0b00000001 // 0 0 I and Q signals are inverted +#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF 0b00000000 // 0 0 normal mode // SX127X_REG_DETECTION_THRESHOLD -#define SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold -#define SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold +#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold +#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold // SX127X_REG_PA_DAC -#define SX127X_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled -#define SX127X_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111 +#define RADIOLIB_SX127X_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled +#define RADIOLIB_SX127X_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111 // SX127X_REG_HOP_PERIOD -#define SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled -#define SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0 +#define RADIOLIB_SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled +#define RADIOLIB_SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0 // SX127X_REG_DIO_MAPPING_1 -#define SX127X_DIO0_RX_DONE 0b00000000 // 7 6 -#define SX127X_DIO0_TX_DONE 0b01000000 // 7 6 -#define SX127X_DIO0_CAD_DONE 0b10000000 // 7 6 -#define SX127X_DIO1_RX_TIMEOUT 0b00000000 // 5 4 -#define SX127X_DIO1_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 -#define SX127X_DIO1_CAD_DETECTED 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO0_RX_DONE 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_TX_DONE 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CAD_DONE 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO1_RX_TIMEOUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CAD_DETECTED 0b00100000 // 5 4 // SX127X_REG_IRQ_FLAGS -#define SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout -#define SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete -#define SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error -#define SX127X_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received -#define SX127X_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete -#define SX127X_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete -#define SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel -#define SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation // SX127X_REG_IRQ_FLAGS_MASK -#define SX127X_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout -#define SX127X_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete -#define SX127X_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error -#define SX127X_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received -#define SX127X_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete -#define SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete -#define SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel -#define SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation // SX127X_REG_FIFO_TX_BASE_ADDR -#define SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only +#define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only // SX127X_REG_FIFO_RX_BASE_ADDR -#define SX127X_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only +#define RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only // SX127X_REG_SYNC_WORD -#define SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word -#define SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks +#define RADIOLIB_SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word +#define RADIOLIB_SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks // SX127X_REG_INVERT_IQ2 -#define SX127X_IQ2_ENABLE 0x19 // 7 0 enable optimize for inverted IQ -#define SX127X_IQ2_DISABLE 0x1D // 7 0 reset optimize for inverted IQ +#define RADIOLIB_SX127X_IQ2_ENABLE 0x19 // 7 0 enable optimize for inverted IQ +#define RADIOLIB_SX127X_IQ2_DISABLE 0x1D // 7 0 reset optimize for inverted IQ // SX127x series common FSK registers // NOTE: FSK register names that are conflicting with LoRa registers are marked with "_FSK" suffix -#define SX127X_REG_BITRATE_MSB 0x02 -#define SX127X_REG_BITRATE_LSB 0x03 -#define SX127X_REG_FDEV_MSB 0x04 -#define SX127X_REG_FDEV_LSB 0x05 -#define SX127X_REG_RX_CONFIG 0x0D -#define SX127X_REG_RSSI_CONFIG 0x0E -#define SX127X_REG_RSSI_COLLISION 0x0F -#define SX127X_REG_RSSI_THRESH 0x10 -#define SX127X_REG_RSSI_VALUE_FSK 0x11 -#define SX127X_REG_RX_BW 0x12 -#define SX127X_REG_AFC_BW 0x13 -#define SX127X_REG_OOK_PEAK 0x14 -#define SX127X_REG_OOK_FIX 0x15 -#define SX127X_REG_OOK_AVG 0x16 -#define SX127X_REG_AFC_FEI 0x1A -#define SX127X_REG_AFC_MSB 0x1B -#define SX127X_REG_AFC_LSB 0x1C -#define SX127X_REG_FEI_MSB_FSK 0x1D -#define SX127X_REG_FEI_LSB_FSK 0x1E -#define SX127X_REG_PREAMBLE_DETECT 0x1F -#define SX127X_REG_RX_TIMEOUT_1 0x20 -#define SX127X_REG_RX_TIMEOUT_2 0x21 -#define SX127X_REG_RX_TIMEOUT_3 0x22 -#define SX127X_REG_RX_DELAY 0x23 -#define SX127X_REG_OSC 0x24 -#define SX127X_REG_PREAMBLE_MSB_FSK 0x25 -#define SX127X_REG_PREAMBLE_LSB_FSK 0x26 -#define SX127X_REG_SYNC_CONFIG 0x27 -#define SX127X_REG_SYNC_VALUE_1 0x28 -#define SX127X_REG_SYNC_VALUE_2 0x29 -#define SX127X_REG_SYNC_VALUE_3 0x2A -#define SX127X_REG_SYNC_VALUE_4 0x2B -#define SX127X_REG_SYNC_VALUE_5 0x2C -#define SX127X_REG_SYNC_VALUE_6 0x2D -#define SX127X_REG_SYNC_VALUE_7 0x2E -#define SX127X_REG_SYNC_VALUE_8 0x2F -#define SX127X_REG_PACKET_CONFIG_1 0x30 -#define SX127X_REG_PACKET_CONFIG_2 0x31 -#define SX127X_REG_PAYLOAD_LENGTH_FSK 0x32 -#define SX127X_REG_NODE_ADRS 0x33 -#define SX127X_REG_BROADCAST_ADRS 0x34 -#define SX127X_REG_FIFO_THRESH 0x35 -#define SX127X_REG_SEQ_CONFIG_1 0x36 -#define SX127X_REG_SEQ_CONFIG_2 0x37 -#define SX127X_REG_TIMER_RESOL 0x38 -#define SX127X_REG_TIMER1_COEF 0x39 -#define SX127X_REG_TIMER2_COEF 0x3A -#define SX127X_REG_IMAGE_CAL 0x3B -#define SX127X_REG_TEMP 0x3C -#define SX127X_REG_LOW_BAT 0x3D -#define SX127X_REG_IRQ_FLAGS_1 0x3E -#define SX127X_REG_IRQ_FLAGS_2 0x3F +#define RADIOLIB_SX127X_REG_BITRATE_MSB 0x02 +#define RADIOLIB_SX127X_REG_BITRATE_LSB 0x03 +#define RADIOLIB_SX127X_REG_FDEV_MSB 0x04 +#define RADIOLIB_SX127X_REG_FDEV_LSB 0x05 +#define RADIOLIB_SX127X_REG_RX_CONFIG 0x0D +#define RADIOLIB_SX127X_REG_RSSI_CONFIG 0x0E +#define RADIOLIB_SX127X_REG_RSSI_COLLISION 0x0F +#define RADIOLIB_SX127X_REG_RSSI_THRESH 0x10 +#define RADIOLIB_SX127X_REG_RSSI_VALUE_FSK 0x11 +#define RADIOLIB_SX127X_REG_RX_BW 0x12 +#define RADIOLIB_SX127X_REG_AFC_BW 0x13 +#define RADIOLIB_SX127X_REG_OOK_PEAK 0x14 +#define RADIOLIB_SX127X_REG_OOK_FIX 0x15 +#define RADIOLIB_SX127X_REG_OOK_AVG 0x16 +#define RADIOLIB_SX127X_REG_AFC_FEI 0x1A +#define RADIOLIB_SX127X_REG_AFC_MSB 0x1B +#define RADIOLIB_SX127X_REG_AFC_LSB 0x1C +#define RADIOLIB_SX127X_REG_FEI_MSB_FSK 0x1D +#define RADIOLIB_SX127X_REG_FEI_LSB_FSK 0x1E +#define RADIOLIB_SX127X_REG_PREAMBLE_DETECT 0x1F +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_1 0x20 +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_2 0x21 +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_3 0x22 +#define RADIOLIB_SX127X_REG_RX_DELAY 0x23 +#define RADIOLIB_SX127X_REG_OSC 0x24 +#define RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK 0x25 +#define RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK 0x26 +#define RADIOLIB_SX127X_REG_SYNC_CONFIG 0x27 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_1 0x28 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_2 0x29 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_3 0x2A +#define RADIOLIB_SX127X_REG_SYNC_VALUE_4 0x2B +#define RADIOLIB_SX127X_REG_SYNC_VALUE_5 0x2C +#define RADIOLIB_SX127X_REG_SYNC_VALUE_6 0x2D +#define RADIOLIB_SX127X_REG_SYNC_VALUE_7 0x2E +#define RADIOLIB_SX127X_REG_SYNC_VALUE_8 0x2F +#define RADIOLIB_SX127X_REG_PACKET_CONFIG_1 0x30 +#define RADIOLIB_SX127X_REG_PACKET_CONFIG_2 0x31 +#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK 0x32 +#define RADIOLIB_SX127X_REG_NODE_ADRS 0x33 +#define RADIOLIB_SX127X_REG_BROADCAST_ADRS 0x34 +#define RADIOLIB_SX127X_REG_FIFO_THRESH 0x35 +#define RADIOLIB_SX127X_REG_SEQ_CONFIG_1 0x36 +#define RADIOLIB_SX127X_REG_SEQ_CONFIG_2 0x37 +#define RADIOLIB_SX127X_REG_TIMER_RESOL 0x38 +#define RADIOLIB_SX127X_REG_TIMER1_COEF 0x39 +#define RADIOLIB_SX127X_REG_TIMER2_COEF 0x3A +#define RADIOLIB_SX127X_REG_IMAGE_CAL 0x3B +#define RADIOLIB_SX127X_REG_TEMP 0x3C +#define RADIOLIB_SX127X_REG_LOW_BAT 0x3D +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_1 0x3E +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_2 0x3F // SX127x common FSK modem settings // SX127X_REG_OP_MODE -#define SX127X_MODULATION_FSK 0b00000000 // 6 5 FSK modulation scheme -#define SX127X_MODULATION_OOK 0b00100000 // 6 5 OOK modulation scheme -#define SX127X_RX 0b00000101 // 2 0 receiver mode +#define RADIOLIB_SX127X_MODULATION_FSK 0b00000000 // 6 5 FSK modulation scheme +#define RADIOLIB_SX127X_MODULATION_OOK 0b00100000 // 6 5 OOK modulation scheme +#define RADIOLIB_SX127X_RX 0b00000101 // 2 0 receiver mode // SX127X_REG_BITRATE_MSB + SX127X_REG_BITRATE_LSB -#define SX127X_BITRATE_MSB 0x1A // 7 0 bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16) -#define SX127X_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps +#define RADIOLIB_SX127X_BITRATE_MSB 0x1A // 7 0 bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16) +#define RADIOLIB_SX127X_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps // SX127X_REG_FDEV_MSB + SX127X_REG_FDEV_LSB -#define SX127X_FDEV_MSB 0x00 // 5 0 frequency deviation: Fdev = Fstep * FDEV -#define SX127X_FDEV_LSB 0x52 // 7 0 default value: 5 kHz +#define RADIOLIB_SX127X_FDEV_MSB 0x00 // 5 0 frequency deviation: Fdev = Fstep * FDEV +#define RADIOLIB_SX127X_FDEV_LSB 0x52 // 7 0 default value: 5 kHz // SX127X_REG_RX_CONFIG -#define SX127X_RESTART_RX_ON_COLLISION_OFF 0b00000000 // 7 7 automatic receiver restart disabled (default) -#define SX127X_RESTART_RX_ON_COLLISION_ON 0b10000000 // 7 7 automatically restart receiver if it gets saturated or on packet collision -#define SX127X_RESTART_RX_WITHOUT_PLL_LOCK 0b01000000 // 6 6 manually restart receiver without frequency change -#define SX127X_RESTART_RX_WITH_PLL_LOCK 0b00100000 // 5 5 manually restart receiver with frequency change -#define SX127X_AFC_AUTO_OFF 0b00000000 // 4 4 no AFC performed (default) -#define SX127X_AFC_AUTO_ON 0b00010000 // 4 4 AFC performed at each receiver startup -#define SX127X_AGC_AUTO_OFF 0b00000000 // 3 3 LNA gain set manually by register -#define SX127X_AGC_AUTO_ON 0b00001000 // 3 3 LNA gain controlled by AGC -#define SX127X_RX_TRIGGER_NONE 0b00000000 // 2 0 receiver startup at: none -#define SX127X_RX_TRIGGER_RSSI_INTERRUPT 0b00000001 // 2 0 RSSI interrupt -#define SX127X_RX_TRIGGER_PREAMBLE_DETECT 0b00000110 // 2 0 preamble detected -#define SX127X_RX_TRIGGER_BOTH 0b00000111 // 2 0 RSSI interrupt and preamble detected +#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_OFF 0b00000000 // 7 7 automatic receiver restart disabled (default) +#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_ON 0b10000000 // 7 7 automatically restart receiver if it gets saturated or on packet collision +#define RADIOLIB_SX127X_RESTART_RX_WITHOUT_PLL_LOCK 0b01000000 // 6 6 manually restart receiver without frequency change +#define RADIOLIB_SX127X_RESTART_RX_WITH_PLL_LOCK 0b00100000 // 5 5 manually restart receiver with frequency change +#define RADIOLIB_SX127X_AFC_AUTO_OFF 0b00000000 // 4 4 no AFC performed (default) +#define RADIOLIB_SX127X_AFC_AUTO_ON 0b00010000 // 4 4 AFC performed at each receiver startup +#define RADIOLIB_SX127X_AGC_AUTO_OFF 0b00000000 // 3 3 LNA gain set manually by register +#define RADIOLIB_SX127X_AGC_AUTO_ON 0b00001000 // 3 3 LNA gain controlled by AGC +#define RADIOLIB_SX127X_RX_TRIGGER_NONE 0b00000000 // 2 0 receiver startup at: none +#define RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT 0b00000001 // 2 0 RSSI interrupt +#define RADIOLIB_SX127X_RX_TRIGGER_PREAMBLE_DETECT 0b00000110 // 2 0 preamble detected +#define RADIOLIB_SX127X_RX_TRIGGER_BOTH 0b00000111 // 2 0 RSSI interrupt and preamble detected // SX127X_REG_RSSI_CONFIG -#define SX127X_RSSI_SMOOTHING_SAMPLES_2 0b00000000 // 2 0 number of samples for RSSI average: 2 -#define SX127X_RSSI_SMOOTHING_SAMPLES_4 0b00000001 // 2 0 4 -#define SX127X_RSSI_SMOOTHING_SAMPLES_8 0b00000010 // 2 0 8 (default) -#define SX127X_RSSI_SMOOTHING_SAMPLES_16 0b00000011 // 2 0 16 -#define SX127X_RSSI_SMOOTHING_SAMPLES_32 0b00000100 // 2 0 32 -#define SX127X_RSSI_SMOOTHING_SAMPLES_64 0b00000101 // 2 0 64 -#define SX127X_RSSI_SMOOTHING_SAMPLES_128 0b00000110 // 2 0 128 -#define SX127X_RSSI_SMOOTHING_SAMPLES_256 0b00000111 // 2 0 256 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_2 0b00000000 // 2 0 number of samples for RSSI average: 2 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_4 0b00000001 // 2 0 4 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_8 0b00000010 // 2 0 8 (default) +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_16 0b00000011 // 2 0 16 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_32 0b00000100 // 2 0 32 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_64 0b00000101 // 2 0 64 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_128 0b00000110 // 2 0 128 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_256 0b00000111 // 2 0 256 // SX127X_REG_RSSI_COLLISION -#define SX127X_RSSI_COLLISION_THRESHOLD 0x0A // 7 0 RSSI threshold in dB that will be considered a collision, default value: 10 dB +#define RADIOLIB_SX127X_RSSI_COLLISION_THRESHOLD 0x0A // 7 0 RSSI threshold in dB that will be considered a collision, default value: 10 dB // SX127X_REG_RSSI_THRESH -#define SX127X_RSSI_THRESHOLD 0xFF // 7 0 RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm] +#define RADIOLIB_SX127X_RSSI_THRESHOLD 0xFF // 7 0 RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm] // SX127X_REG_RX_BW -#define SX127X_RX_BW_MANT_16 0b00000000 // 4 3 channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz] -#define SX127X_RX_BW_MANT_20 0b00001000 // 4 3 -#define SX127X_RX_BW_MANT_24 0b00010000 // 4 3 default RxBwMant parameter -#define SX127X_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp parameter +#define RADIOLIB_SX127X_RX_BW_MANT_16 0b00000000 // 4 3 channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz] +#define RADIOLIB_SX127X_RX_BW_MANT_20 0b00001000 // 4 3 +#define RADIOLIB_SX127X_RX_BW_MANT_24 0b00010000 // 4 3 default RxBwMant parameter +#define RADIOLIB_SX127X_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp parameter // SX127X_REG_AFC_BW -#define SX127X_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter used during AFC -#define SX127X_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter used during AFC +#define RADIOLIB_SX127X_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter used during AFC +#define RADIOLIB_SX127X_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter used during AFC // SX127X_REG_OOK_PEAK -#define SX127X_BIT_SYNC_OFF 0b00000000 // 5 5 bit synchronizer disabled (not allowed in packet mode) -#define SX127X_BIT_SYNC_ON 0b00100000 // 5 5 bit synchronizer enabled (default) -#define SX127X_OOK_THRESH_FIXED 0b00000000 // 4 3 OOK threshold type: fixed value -#define SX127X_OOK_THRESH_PEAK 0b00001000 // 4 3 peak mode (default) -#define SX127X_OOK_THRESH_AVERAGE 0b00010000 // 4 3 average mode -#define SX127X_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 2 0 OOK demodulator step size: 0.5 dB (default) -#define SX127X_OOK_PEAK_THRESH_STEP_1_0_DB 0b00000001 // 2 0 1.0 dB -#define SX127X_OOK_PEAK_THRESH_STEP_1_5_DB 0b00000010 // 2 0 1.5 dB -#define SX127X_OOK_PEAK_THRESH_STEP_2_0_DB 0b00000011 // 2 0 2.0 dB -#define SX127X_OOK_PEAK_THRESH_STEP_3_0_DB 0b00000100 // 2 0 3.0 dB -#define SX127X_OOK_PEAK_THRESH_STEP_4_0_DB 0b00000101 // 2 0 4.0 dB -#define SX127X_OOK_PEAK_THRESH_STEP_5_0_DB 0b00000110 // 2 0 5.0 dB -#define SX127X_OOK_PEAK_THRESH_STEP_6_0_DB 0b00000111 // 2 0 6.0 dB +#define RADIOLIB_SX127X_BIT_SYNC_OFF 0b00000000 // 5 5 bit synchronizer disabled (not allowed in packet mode) +#define RADIOLIB_SX127X_BIT_SYNC_ON 0b00100000 // 5 5 bit synchronizer enabled (default) +#define RADIOLIB_SX127X_OOK_THRESH_FIXED 0b00000000 // 4 3 OOK threshold type: fixed value +#define RADIOLIB_SX127X_OOK_THRESH_PEAK 0b00001000 // 4 3 peak mode (default) +#define RADIOLIB_SX127X_OOK_THRESH_AVERAGE 0b00010000 // 4 3 average mode +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 2 0 OOK demodulator step size: 0.5 dB (default) +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB 0b00000001 // 2 0 1.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB 0b00000010 // 2 0 1.5 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB 0b00000011 // 2 0 2.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB 0b00000100 // 2 0 3.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB 0b00000101 // 2 0 4.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB 0b00000110 // 2 0 5.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB 0b00000111 // 2 0 6.0 dB // SX127X_REG_OOK_FIX -#define SX127X_OOK_FIXED_THRESHOLD 0x0C // 7 0 default fixed threshold for OOK data slicer +#define RADIOLIB_SX127X_OOK_FIXED_THRESHOLD 0x0C // 7 0 default fixed threshold for OOK data slicer // SX127X_REG_OOK_AVG -#define SX127X_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 7 5 OOK demodulator step period: once per chip (default) -#define SX127X_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00100000 // 7 5 once every 2 chips -#define SX127X_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b01000000 // 7 5 once every 4 chips -#define SX127X_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b01100000 // 7 5 once every 8 chips -#define SX127X_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b10000000 // 7 5 2 times per chip -#define SX127X_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b10100000 // 7 5 4 times per chip -#define SX127X_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b11000000 // 7 5 8 times per chip -#define SX127X_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b11100000 // 7 5 16 times per chip -#define SX127X_OOK_AVERAGE_OFFSET_0_DB 0b00000000 // 3 2 OOK average threshold offset: 0.0 dB (default) -#define SX127X_OOK_AVERAGE_OFFSET_2_DB 0b00000100 // 3 2 2.0 dB -#define SX127X_OOK_AVERAGE_OFFSET_4_DB 0b00001000 // 3 2 4.0 dB -#define SX127X_OOK_AVERAGE_OFFSET_6_DB 0b00001100 // 3 2 6.0 dB -#define SX127X_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 1 0 OOK average filter coefficient: chip rate / 32*pi -#define SX127X_OOK_AVG_THRESH_FILT_8_PI 0b00000001 // 1 0 chip rate / 8*pi -#define SX127X_OOK_AVG_THRESH_FILT_4_PI 0b00000010 // 1 0 chip rate / 4*pi (default) -#define SX127X_OOK_AVG_THRESH_FILT_2_PI 0b00000011 // 1 0 chip rate / 2*pi +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 7 5 OOK demodulator step period: once per chip (default) +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00100000 // 7 5 once every 2 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b01000000 // 7 5 once every 4 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b01100000 // 7 5 once every 8 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b10000000 // 7 5 2 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b10100000 // 7 5 4 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b11000000 // 7 5 8 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b11100000 // 7 5 16 times per chip +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_0_DB 0b00000000 // 3 2 OOK average threshold offset: 0.0 dB (default) +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_2_DB 0b00000100 // 3 2 2.0 dB +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_4_DB 0b00001000 // 3 2 4.0 dB +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_6_DB 0b00001100 // 3 2 6.0 dB +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 1 0 OOK average filter coefficient: chip rate / 32*pi +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_8_PI 0b00000001 // 1 0 chip rate / 8*pi +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_4_PI 0b00000010 // 1 0 chip rate / 4*pi (default) +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_2_PI 0b00000011 // 1 0 chip rate / 2*pi // SX127X_REG_AFC_FEI -#define SX127X_AGC_START 0b00010000 // 4 4 manually start AGC sequence -#define SX127X_AFC_CLEAR 0b00000010 // 1 1 manually clear AFC register -#define SX127X_AFC_AUTO_CLEAR_OFF 0b00000000 // 0 0 AFC register will not be cleared at the start of AFC (default) -#define SX127X_AFC_AUTO_CLEAR_ON 0b00000001 // 0 0 AFC register will be cleared at the start of AFC +#define RADIOLIB_SX127X_AGC_START 0b00010000 // 4 4 manually start AGC sequence +#define RADIOLIB_SX127X_AFC_CLEAR 0b00000010 // 1 1 manually clear AFC register +#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_OFF 0b00000000 // 0 0 AFC register will not be cleared at the start of AFC (default) +#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_ON 0b00000001 // 0 0 AFC register will be cleared at the start of AFC // SX127X_REG_PREAMBLE_DETECT -#define SX127X_PREAMBLE_DETECTOR_OFF 0b00000000 // 7 7 preamble detection disabled -#define SX127X_PREAMBLE_DETECTOR_ON 0b10000000 // 7 7 preamble detection enabled (default) -#define SX127X_PREAMBLE_DETECTOR_1_BYTE 0b00000000 // 6 5 preamble detection size: 1 byte (default) -#define SX127X_PREAMBLE_DETECTOR_2_BYTE 0b00100000 // 6 5 2 bytes -#define SX127X_PREAMBLE_DETECTOR_3_BYTE 0b01000000 // 6 5 3 bytes -#define SX127X_PREAMBLE_DETECTOR_TOL 0x0A // 4 0 default number of tolerated errors per chip (4 chips per bit) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_OFF 0b00000000 // 7 7 preamble detection disabled +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON 0b10000000 // 7 7 preamble detection enabled (default) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_1_BYTE 0b00000000 // 6 5 preamble detection size: 1 byte (default) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE 0b00100000 // 6 5 2 bytes +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_3_BYTE 0b01000000 // 6 5 3 bytes +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL 0x0A // 4 0 default number of tolerated errors per chip (4 chips per bit) // SX127X_REG_RX_TIMEOUT_1 -#define SX127X_TIMEOUT_RX_RSSI_OFF 0x00 // 7 0 disable receiver timeout when RSSI interrupt doesn't occur (default) +#define RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF 0x00 // 7 0 disable receiver timeout when RSSI interrupt doesn't occur (default) // SX127X_REG_RX_TIMEOUT_2 -#define SX127X_TIMEOUT_RX_PREAMBLE_OFF 0x00 // 7 0 disable receiver timeout when preamble interrupt doesn't occur (default) +#define RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF 0x00 // 7 0 disable receiver timeout when preamble interrupt doesn't occur (default) // SX127X_REG_RX_TIMEOUT_3 -#define SX127X_TIMEOUT_SIGNAL_SYNC_OFF 0x00 // 7 0 disable receiver timeout when sync address interrupt doesn't occur (default) +#define RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF 0x00 // 7 0 disable receiver timeout when sync address interrupt doesn't occur (default) // SX127X_REG_OSC -#define SX127X_RC_CAL_START 0b00000000 // 3 3 manually start RC oscillator calibration -#define SX127X_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) -#define SX127X_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 -#define SX127X_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 -#define SX127X_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 -#define SX127X_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 -#define SX127X_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 32 -#define SX127X_CLK_OUT_RC 0b00000110 // 2 0 RC -#define SX127X_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) +#define RADIOLIB_SX127X_RC_CAL_START 0b00000000 // 3 3 manually start RC oscillator calibration +#define RADIOLIB_SX127X_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 32 +#define RADIOLIB_SX127X_CLK_OUT_RC 0b00000110 // 2 0 RC +#define RADIOLIB_SX127X_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) // SX127X_REG_PREAMBLE_MSB_FSK + SX127X_REG_PREAMBLE_LSB_FSK -#define SX127X_PREAMBLE_SIZE_MSB 0x00 // 7 0 preamble size in bytes -#define SX127X_PREAMBLE_SIZE_LSB 0x03 // 7 0 default value: 3 bytes +#define RADIOLIB_SX127X_PREAMBLE_SIZE_MSB 0x00 // 7 0 preamble size in bytes +#define RADIOLIB_SX127X_PREAMBLE_SIZE_LSB 0x03 // 7 0 default value: 3 bytes // SX127X_REG_SYNC_CONFIG -#define SX127X_AUTO_RESTART_RX_MODE_OFF 0b00000000 // 7 6 Rx mode restart after packet reception: disabled -#define SX127X_AUTO_RESTART_RX_MODE_NO_PLL 0b01000000 // 7 6 enabled, don't wait for PLL lock -#define SX127X_AUTO_RESTART_RX_MODE_PLL 0b10000000 // 7 6 enabled, wait for PLL lock (default) -#define SX127X_PREAMBLE_POLARITY_AA 0b00000000 // 5 5 preamble polarity: 0xAA = 0b10101010 (default) -#define SX127X_PREAMBLE_POLARITY_55 0b00100000 // 5 5 0x55 = 0b01010101 -#define SX127X_SYNC_OFF 0b00000000 // 4 4 sync word disabled -#define SX127X_SYNC_ON 0b00010000 // 4 4 sync word enabled (default) -#define SX127X_SYNC_SIZE 0x03 // 2 0 sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_OFF 0b00000000 // 7 6 Rx mode restart after packet reception: disabled +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_NO_PLL 0b01000000 // 7 6 enabled, don't wait for PLL lock +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_PLL 0b10000000 // 7 6 enabled, wait for PLL lock (default) +#define RADIOLIB_SX127X_PREAMBLE_POLARITY_AA 0b00000000 // 5 5 preamble polarity: 0xAA = 0b10101010 (default) +#define RADIOLIB_SX127X_PREAMBLE_POLARITY_55 0b00100000 // 5 5 0x55 = 0b01010101 +#define RADIOLIB_SX127X_SYNC_OFF 0b00000000 // 4 4 sync word disabled +#define RADIOLIB_SX127X_SYNC_ON 0b00010000 // 4 4 sync word enabled (default) +#define RADIOLIB_SX127X_SYNC_SIZE 0x03 // 2 0 sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes // SX127X_REG_SYNC_VALUE_1 - SX127X_REG_SYNC_VALUE_8 -#define SX127X_SYNC_VALUE_1 0x01 // 7 0 sync word: 1st byte (MSB) -#define SX127X_SYNC_VALUE_2 0x01 // 7 0 2nd byte -#define SX127X_SYNC_VALUE_3 0x01 // 7 0 3rd byte -#define SX127X_SYNC_VALUE_4 0x01 // 7 0 4th byte -#define SX127X_SYNC_VALUE_5 0x01 // 7 0 5th byte -#define SX127X_SYNC_VALUE_6 0x01 // 7 0 6th byte -#define SX127X_SYNC_VALUE_7 0x01 // 7 0 7th byte -#define SX127X_SYNC_VALUE_8 0x01 // 7 0 8th byte (LSB) +#define RADIOLIB_SX127X_SYNC_VALUE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define RADIOLIB_SX127X_SYNC_VALUE_2 0x01 // 7 0 2nd byte +#define RADIOLIB_SX127X_SYNC_VALUE_3 0x01 // 7 0 3rd byte +#define RADIOLIB_SX127X_SYNC_VALUE_4 0x01 // 7 0 4th byte +#define RADIOLIB_SX127X_SYNC_VALUE_5 0x01 // 7 0 5th byte +#define RADIOLIB_SX127X_SYNC_VALUE_6 0x01 // 7 0 6th byte +#define RADIOLIB_SX127X_SYNC_VALUE_7 0x01 // 7 0 7th byte +#define RADIOLIB_SX127X_SYNC_VALUE_8 0x01 // 7 0 8th byte (LSB) // SX127X_REG_PACKET_CONFIG_1 -#define SX127X_PACKET_FIXED 0b00000000 // 7 7 packet format: fixed length -#define SX127X_PACKET_VARIABLE 0b10000000 // 7 7 variable length (default) -#define SX127X_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: disabled (default) -#define SX127X_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester -#define SX127X_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening -#define SX127X_CRC_OFF 0b00000000 // 4 4 CRC disabled -#define SX127X_CRC_ON 0b00010000 // 4 4 CRC enabled (default) -#define SX127X_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep FIFO on CRC mismatch, issue payload ready interrupt -#define SX127X_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 clear FIFO on CRC mismatch, do not issue payload ready interrupt -#define SX127X_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) -#define SX127X_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node -#define SX127X_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast -#define SX127X_CRC_WHITENING_TYPE_CCITT 0b00000000 // 0 0 CRC and whitening algorithms: CCITT CRC with standard whitening (default) -#define SX127X_CRC_WHITENING_TYPE_IBM 0b00000001 // 0 0 IBM CRC with alternate whitening +#define RADIOLIB_SX127X_PACKET_FIXED 0b00000000 // 7 7 packet format: fixed length +#define RADIOLIB_SX127X_PACKET_VARIABLE 0b10000000 // 7 7 variable length (default) +#define RADIOLIB_SX127X_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: disabled (default) +#define RADIOLIB_SX127X_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define RADIOLIB_SX127X_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define RADIOLIB_SX127X_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define RADIOLIB_SX127X_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define RADIOLIB_SX127X_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep FIFO on CRC mismatch, issue payload ready interrupt +#define RADIOLIB_SX127X_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 clear FIFO on CRC mismatch, do not issue payload ready interrupt +#define RADIOLIB_SX127X_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast +#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT 0b00000000 // 0 0 CRC and whitening algorithms: CCITT CRC with standard whitening (default) +#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM 0b00000001 // 0 0 IBM CRC with alternate whitening // SX127X_REG_PACKET_CONFIG_2 -#define SX127X_DATA_MODE_PACKET 0b01000000 // 6 6 data mode: packet (default) -#define SX127X_DATA_MODE_CONTINUOUS 0b00000000 // 6 6 continuous -#define SX127X_IO_HOME_OFF 0b00000000 // 5 5 io-homecontrol compatibility disabled (default) -#define SX127X_IO_HOME_ON 0b00100000 // 5 5 io-homecontrol compatibility enabled +#define RADIOLIB_SX127X_DATA_MODE_PACKET 0b01000000 // 6 6 data mode: packet (default) +#define RADIOLIB_SX127X_DATA_MODE_CONTINUOUS 0b00000000 // 6 6 continuous +#define RADIOLIB_SX127X_IO_HOME_OFF 0b00000000 // 5 5 io-homecontrol compatibility disabled (default) +#define RADIOLIB_SX127X_IO_HOME_ON 0b00100000 // 5 5 io-homecontrol compatibility enabled // SX127X_REG_FIFO_THRESH -#define SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD -#define SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) -#define SX127X_FIFO_THRESH 0x0F // 5 0 FIFO level threshold +#define RADIOLIB_SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD +#define RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) +#define RADIOLIB_SX127X_FIFO_THRESH 0x0F // 5 0 FIFO level threshold // SX127X_REG_SEQ_CONFIG_1 -#define SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer -#define SX127X_SEQUENCER_STOP 0b01000000 // 6 6 manually stop sequencer -#define SX127X_IDLE_MODE_STANDBY 0b00000000 // 5 5 chip mode during sequencer idle mode: standby (default) -#define SX127X_IDLE_MODE_SLEEP 0b00100000 // 5 5 sleep -#define SX127X_FROM_START_LP_SELECTION 0b00000000 // 4 3 mode that will be set after starting sequencer: low power selection (default) -#define SX127X_FROM_START_RECEIVE 0b00001000 // 4 3 receive -#define SX127X_FROM_START_TRANSMIT 0b00010000 // 4 3 transmit -#define SX127X_FROM_START_TRANSMIT_FIFO_LEVEL 0b00011000 // 4 3 transmit on a FIFO level interrupt -#define SX127X_LP_SELECTION_SEQ_OFF 0b00000000 // 2 2 mode that will be set after exiting low power selection: sequencer off (default) -#define SX127X_LP_SELECTION_IDLE 0b00000100 // 2 2 idle state -#define SX127X_FROM_IDLE_TRANSMIT 0b00000000 // 1 1 mode that will be set after exiting idle mode: transmit (default) -#define SX127X_FROM_IDLE_RECEIVE 0b00000010 // 1 1 receive -#define SX127X_FROM_TRANSMIT_LP_SELECTION 0b00000000 // 0 0 mode that will be set after exiting transmit mode: low power selection (default) -#define SX127X_FROM_TRANSMIT_RECEIVE 0b00000001 // 0 0 receive +#define RADIOLIB_SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer +#define RADIOLIB_SX127X_SEQUENCER_STOP 0b01000000 // 6 6 manually stop sequencer +#define RADIOLIB_SX127X_IDLE_MODE_STANDBY 0b00000000 // 5 5 chip mode during sequencer idle mode: standby (default) +#define RADIOLIB_SX127X_IDLE_MODE_SLEEP 0b00100000 // 5 5 sleep +#define RADIOLIB_SX127X_FROM_START_LP_SELECTION 0b00000000 // 4 3 mode that will be set after starting sequencer: low power selection (default) +#define RADIOLIB_SX127X_FROM_START_RECEIVE 0b00001000 // 4 3 receive +#define RADIOLIB_SX127X_FROM_START_TRANSMIT 0b00010000 // 4 3 transmit +#define RADIOLIB_SX127X_FROM_START_TRANSMIT_FIFO_LEVEL 0b00011000 // 4 3 transmit on a FIFO level interrupt +#define RADIOLIB_SX127X_LP_SELECTION_SEQ_OFF 0b00000000 // 2 2 mode that will be set after exiting low power selection: sequencer off (default) +#define RADIOLIB_SX127X_LP_SELECTION_IDLE 0b00000100 // 2 2 idle state +#define RADIOLIB_SX127X_FROM_IDLE_TRANSMIT 0b00000000 // 1 1 mode that will be set after exiting idle mode: transmit (default) +#define RADIOLIB_SX127X_FROM_IDLE_RECEIVE 0b00000010 // 1 1 receive +#define RADIOLIB_SX127X_FROM_TRANSMIT_LP_SELECTION 0b00000000 // 0 0 mode that will be set after exiting transmit mode: low power selection (default) +#define RADIOLIB_SX127X_FROM_TRANSMIT_RECEIVE 0b00000001 // 0 0 receive // SX127X_REG_SEQ_CONFIG_2 -#define SX127X_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD 0b00100000 // 7 5 mode that will be set after exiting receive mode: packet received on payload ready interrupt (default) -#define SX127X_FROM_RECEIVE_LP_SELECTION 0b01000000 // 7 5 low power selection -#define SX127X_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK 0b01100000 // 7 5 packet received on CRC OK interrupt -#define SX127X_FROM_RECEIVE_SEQ_OFF_RSSI 0b10000000 // 7 5 sequencer off on RSSI interrupt -#define SX127X_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR 0b10100000 // 7 5 sequencer off on sync address interrupt -#define SX127X_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT 0b11000000 // 7 5 sequencer off on preamble detect interrupt -#define SX127X_FROM_RX_TIMEOUT_RECEIVE 0b00000000 // 4 3 mode that will be set after Rx timeout: receive (default) -#define SX127X_FROM_RX_TIMEOUT_TRANSMIT 0b00001000 // 4 3 transmit -#define SX127X_FROM_RX_TIMEOUT_LP_SELECTION 0b00010000 // 4 3 low power selection -#define SX127X_FROM_RX_TIMEOUT_SEQ_OFF 0b00011000 // 4 3 sequencer off -#define SX127X_FROM_PACKET_RECEIVED_SEQ_OFF 0b00000000 // 2 0 mode that will be set after packet received: sequencer off (default) -#define SX127X_FROM_PACKET_RECEIVED_TRANSMIT 0b00000001 // 2 0 transmit -#define SX127X_FROM_PACKET_RECEIVED_LP_SELECTION 0b00000010 // 2 0 low power selection -#define SX127X_FROM_PACKET_RECEIVED_RECEIVE_FS 0b00000011 // 2 0 receive via FS -#define SX127X_FROM_PACKET_RECEIVED_RECEIVE 0b00000100 // 2 0 receive +#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD 0b00100000 // 7 5 mode that will be set after exiting receive mode: packet received on payload ready interrupt (default) +#define RADIOLIB_SX127X_FROM_RECEIVE_LP_SELECTION 0b01000000 // 7 5 low power selection +#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK 0b01100000 // 7 5 packet received on CRC OK interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_RSSI 0b10000000 // 7 5 sequencer off on RSSI interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR 0b10100000 // 7 5 sequencer off on sync address interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT 0b11000000 // 7 5 sequencer off on preamble detect interrupt +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_RECEIVE 0b00000000 // 4 3 mode that will be set after Rx timeout: receive (default) +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_TRANSMIT 0b00001000 // 4 3 transmit +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_LP_SELECTION 0b00010000 // 4 3 low power selection +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_SEQ_OFF 0b00011000 // 4 3 sequencer off +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_SEQ_OFF 0b00000000 // 2 0 mode that will be set after packet received: sequencer off (default) +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_TRANSMIT 0b00000001 // 2 0 transmit +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_LP_SELECTION 0b00000010 // 2 0 low power selection +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE_FS 0b00000011 // 2 0 receive via FS +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE 0b00000100 // 2 0 receive // SX127X_REG_TIMER_RESOL -#define SX127X_TIMER1_OFF 0b00000000 // 3 2 timer 1 resolution: disabled (default) -#define SX127X_TIMER1_RESOLUTION_64_US 0b00000100 // 3 2 64 us -#define SX127X_TIMER1_RESOLUTION_4_1_MS 0b00001000 // 3 2 4.1 ms -#define SX127X_TIMER1_RESOLUTION_262_MS 0b00001100 // 3 2 262 ms -#define SX127X_TIMER2_OFF 0b00000000 // 3 2 timer 2 resolution: disabled (default) -#define SX127X_TIMER2_RESOLUTION_64_US 0b00000001 // 3 2 64 us -#define SX127X_TIMER2_RESOLUTION_4_1_MS 0b00000010 // 3 2 4.1 ms -#define SX127X_TIMER2_RESOLUTION_262_MS 0b00000011 // 3 2 262 ms +#define RADIOLIB_SX127X_TIMER1_OFF 0b00000000 // 3 2 timer 1 resolution: disabled (default) +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_64_US 0b00000100 // 3 2 64 us +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_4_1_MS 0b00001000 // 3 2 4.1 ms +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_262_MS 0b00001100 // 3 2 262 ms +#define RADIOLIB_SX127X_TIMER2_OFF 0b00000000 // 3 2 timer 2 resolution: disabled (default) +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_64_US 0b00000001 // 3 2 64 us +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_4_1_MS 0b00000010 // 3 2 4.1 ms +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_262_MS 0b00000011 // 3 2 262 ms // SX127X_REG_TIMER1_COEF -#define SX127X_TIMER1_COEFFICIENT 0xF5 // 7 0 multiplication coefficient for timer 1 +#define RADIOLIB_SX127X_TIMER1_COEFFICIENT 0xF5 // 7 0 multiplication coefficient for timer 1 // SX127X_REG_TIMER2_COEF -#define SX127X_TIMER2_COEFFICIENT 0x20 // 7 0 multiplication coefficient for timer 2 +#define RADIOLIB_SX127X_TIMER2_COEFFICIENT 0x20 // 7 0 multiplication coefficient for timer 2 // SX127X_REG_IMAGE_CAL -#define SX127X_AUTO_IMAGE_CAL_OFF 0b00000000 // 7 7 temperature calibration disabled (default) -#define SX127X_AUTO_IMAGE_CAL_ON 0b10000000 // 7 7 temperature calibration enabled -#define SX127X_IMAGE_CAL_START 0b01000000 // 6 6 start temperature calibration -#define SX127X_IMAGE_CAL_RUNNING 0b00100000 // 5 5 temperature calibration is on-going -#define SX127X_IMAGE_CAL_COMPLETE 0b00000000 // 5 5 temperature calibration finished -#define SX127X_TEMP_CHANGED 0b00001000 // 3 3 temperature changed more than TEMP_THRESHOLD since last calibration -#define SX127X_TEMP_THRESHOLD_5_DEG_C 0b00000000 // 2 1 temperature change threshold: 5 deg. C -#define SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) -#define SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C -#define SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C -#define SX127X_TEMP_MONITOR_ON 0b00000000 // 0 0 temperature monitoring enabled (default) -#define SX127X_TEMP_MONITOR_OFF 0b00000001 // 0 0 temperature monitoring disabled +#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_OFF 0b00000000 // 7 7 temperature calibration disabled (default) +#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_ON 0b10000000 // 7 7 temperature calibration enabled +#define RADIOLIB_SX127X_IMAGE_CAL_START 0b01000000 // 6 6 start temperature calibration +#define RADIOLIB_SX127X_IMAGE_CAL_RUNNING 0b00100000 // 5 5 temperature calibration is on-going +#define RADIOLIB_SX127X_IMAGE_CAL_COMPLETE 0b00000000 // 5 5 temperature calibration finished +#define RADIOLIB_SX127X_TEMP_CHANGED 0b00001000 // 3 3 temperature changed more than TEMP_THRESHOLD since last calibration +#define RADIOLIB_SX127X_TEMP_THRESHOLD_5_DEG_C 0b00000000 // 2 1 temperature change threshold: 5 deg. C +#define RADIOLIB_SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) +#define RADIOLIB_SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C +#define RADIOLIB_SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C +#define RADIOLIB_SX127X_TEMP_MONITOR_ON 0b00000000 // 0 0 temperature monitoring enabled (default) +#define RADIOLIB_SX127X_TEMP_MONITOR_OFF 0b00000001 // 0 0 temperature monitoring disabled // SX127X_REG_LOW_BAT -#define SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled -#define SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled -#define SX127X_LOW_BAT_TRIM_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V -#define SX127X_LOW_BAT_TRIM_1_764_V 0b00000001 // 2 0 1.764 V -#define SX127X_LOW_BAT_TRIM_1_835_V 0b00000010 // 2 0 1.835 V (default) -#define SX127X_LOW_BAT_TRIM_1_905_V 0b00000011 // 2 0 1.905 V -#define SX127X_LOW_BAT_TRIM_1_976_V 0b00000100 // 2 0 1.976 V -#define SX127X_LOW_BAT_TRIM_2_045_V 0b00000101 // 2 0 2.045 V -#define SX127X_LOW_BAT_TRIM_2_116_V 0b00000110 // 2 0 2.116 V -#define SX127X_LOW_BAT_TRIM_2_185_V 0b00000111 // 2 0 2.185 V +#define RADIOLIB_SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled +#define RADIOLIB_SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_764_V 0b00000001 // 2 0 1.764 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_835_V 0b00000010 // 2 0 1.835 V (default) +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_905_V 0b00000011 // 2 0 1.905 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_976_V 0b00000100 // 2 0 1.976 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_045_V 0b00000101 // 2 0 2.045 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_116_V 0b00000110 // 2 0 2.116 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_185_V 0b00000111 // 2 0 2.185 V // SX127X_REG_IRQ_FLAGS_1 -#define SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready -#define SX127X_FLAG_RX_READY 0b01000000 // 6 6 reception ready (after RSSI, AGC, AFC) -#define SX127X_FLAG_TX_READY 0b00100000 // 5 5 transmission ready (after PA ramp-up) -#define SX127X_FLAG_PLL_LOCK 0b00010000 // 4 4 PLL locked -#define SX127X_FLAG_RSSI 0b00001000 // 3 3 RSSI value exceeds RSSI threshold -#define SX127X_FLAG_TIMEOUT 0b00000100 // 2 2 timeout occurred -#define SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected -#define SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched +#define RADIOLIB_SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready +#define RADIOLIB_SX127X_FLAG_RX_READY 0b01000000 // 6 6 reception ready (after RSSI, AGC, AFC) +#define RADIOLIB_SX127X_FLAG_TX_READY 0b00100000 // 5 5 transmission ready (after PA ramp-up) +#define RADIOLIB_SX127X_FLAG_PLL_LOCK 0b00010000 // 4 4 PLL locked +#define RADIOLIB_SX127X_FLAG_RSSI 0b00001000 // 3 3 RSSI value exceeds RSSI threshold +#define RADIOLIB_SX127X_FLAG_TIMEOUT 0b00000100 // 2 2 timeout occurred +#define RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected +#define RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched // SX127X_REG_IRQ_FLAGS_2 -#define SX127X_FLAG_FIFO_FULL 0b10000000 // 7 7 FIFO is full -#define SX127X_FLAG_FIFO_EMPTY 0b01000000 // 6 6 FIFO is empty -#define SX127X_FLAG_FIFO_LEVEL 0b00100000 // 5 5 number of bytes in FIFO exceeds FIFO_THRESHOLD -#define SX127X_FLAG_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred -#define SX127X_FLAG_PACKET_SENT 0b00001000 // 3 3 packet was successfully sent -#define SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received -#define SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed -#define SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold +#define RADIOLIB_SX127X_FLAG_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define RADIOLIB_SX127X_FLAG_FIFO_EMPTY 0b01000000 // 6 6 FIFO is empty +#define RADIOLIB_SX127X_FLAG_FIFO_LEVEL 0b00100000 // 5 5 number of bytes in FIFO exceeds FIFO_THRESHOLD +#define RADIOLIB_SX127X_FLAG_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred +#define RADIOLIB_SX127X_FLAG_PACKET_SENT 0b00001000 // 3 3 packet was successfully sent +#define RADIOLIB_SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received +#define RADIOLIB_SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed +#define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold // SX127X_REG_DIO_MAPPING_1 -#define SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 -#define SX127X_DIO0_CONT_RSSI_PREAMBLE_DETECTED 0b01000000 // 7 6 -#define SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 -#define SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 -#define SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 -#define SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 -#define SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 -#define SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECTED 0b00010000 // 5 4 -#define SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 -#define SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 -#define SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 -#define SX127X_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RSSI_RADIOLIB_PREAMBLE_DETECTED 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CONT_RSSI_RADIOLIB_PREAMBLE_DETECTED 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO2_CONT_DATA 0b00000000 // 3 2 // SX1272_REG_PLL_HOP + SX1278_REG_PLL_HOP -#define SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written -#define SX127X_FAST_HOP_ON 0b10000000 // 7 7 carrier frequency validated when FS modes are requested +#define RADIOLIB_SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written +#define RADIOLIB_SX127X_FAST_HOP_ON 0b10000000 // 7 7 carrier frequency validated when FS modes are requested // SX1272_REG_TCXO + SX1278_REG_TCXO -#define SX127X_TCXO_INPUT_EXTERNAL 0b00000000 // 4 4 use external crystal oscillator -#define SX127X_TCXO_INPUT_EXTERNAL_CLIPPED 0b00010000 // 4 4 use external crystal oscillator clipped sine connected to XTA pin +#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL 0b00000000 // 4 4 use external crystal oscillator +#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL_CLIPPED 0b00010000 // 4 4 use external crystal oscillator clipped sine connected to XTA pin // SX1272_REG_PLL + SX1278_REG_PLL -#define SX127X_PLL_BANDWIDTH_75_KHZ 0b00000000 // 7 6 PLL bandwidth: 75 kHz -#define SX127X_PLL_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz -#define SX127X_PLL_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz -#define SX127X_PLL_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) +#define RADIOLIB_SX127X_PLL_BANDWIDTH_75_KHZ 0b00000000 // 7 6 PLL bandwidth: 75 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) /*! \class SX127x @@ -561,6 +561,8 @@ class SX127x: public PhysicalLayer { */ SX127x(Module* mod); + Module* getMod(); + // basic methods /*! @@ -721,7 +723,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t startReceive(uint8_t len = 0, uint8_t mode = SX127X_RXCONTINUOUS); + int16_t startReceive(uint8_t len = 0, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. @@ -943,7 +945,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t fixedPacketLengthMode(uint8_t len = SX127X_MAX_PACKET_LENGTH_FSK); + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); /*! \brief Set modem in variable packet length mode. Available in FSK mode only. @@ -952,7 +954,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t variablePacketLengthMode(uint8_t maxLen = SX127X_MAX_PACKET_LENGTH_FSK); + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); /*! \brief Sets RSSI measurement configuration in FSK mode. @@ -1077,7 +1079,7 @@ class SX127x: public PhysicalLayer { #endif float _dataRate = 0; bool _packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once - uint8_t _packetLengthConfig = SX127X_PACKET_VARIABLE; + uint8_t _packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; bool findChip(uint8_t ver); int16_t setMode(uint8_t mode); From 1126e64587fb4cf82c49f271603d9ba8d0bb36f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:42:36 +0100 Subject: [PATCH 0050/1848] [SX128x] Update to 5.0.0 --- .../SX128x_BLE_Modem/SX128x_BLE_Modem.ino | 14 +- .../SX128x_Channel_Activity_Detection.ino | 6 +- .../SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino | 14 +- .../SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino | 14 +- .../SX128x/SX128x_Ranging/SX128x_Ranging.ino | 6 +- .../SX128x/SX128x_Receive/SX128x_Receive.ino | 8 +- .../SX128x_Receive_Interrupt.ino | 8 +- .../SX128x_Settings/SX128x_Settings.ino | 18 +- .../SX128x_Transmit/SX128x_Transmit.ino | 6 +- .../SX128x_Transmit_Interrupt.ino | 6 +- src/modules/SX128x/SX1280.cpp | 68 +- src/modules/SX128x/SX128x.cpp | 596 +++++++-------- src/modules/SX128x/SX128x.h | 676 +++++++++--------- 13 files changed, 721 insertions(+), 719 deletions(-) diff --git a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino index 96a96ffa20..3d9f5abd1c 100644 --- a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino +++ b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -38,7 +38,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.beginBLE(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -59,7 +59,7 @@ void setup() { state = radio.setOutputPower(5); state = radio.setDataShaping(1.0); state = radio.setAccessAddress(0x12345678); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); while (true); @@ -79,11 +79,11 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1280] Packet transmitted successfully!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { Serial.println(F("[SX1280] Packet too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while transmitting!")); } else { Serial.print(F("[SX1280] Failed to transmit packet, code ")); @@ -97,11 +97,11 @@ void loop() { byte byteArr[8]; int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1280] Received packet!")); Serial.print(F("[SX1280] Data:\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while waiting for packet!")); } else { Serial.print(F("[SX1280] Failed to receive packet, code ")); diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino b/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino index cec1560acb..96b1cb7213 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino @@ -33,7 +33,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -48,11 +48,11 @@ void loop() { // start scanning current channel int state = radio.scanChannel(); - if (state == LORA_DETECTED) { + if (state == RADIOLIB_LORA_DETECTED) { // LoRa preamble was detected Serial.println(F("detected!")); - } else if (state == CHANNEL_FREE) { + } else if (state == RADIOLIB_CHANNEL_FREE) { // no preamble was detected, channel is free Serial.println(F("channel is free!")); diff --git a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino index cf2d0e7cc1..168ab510a4 100644 --- a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino +++ b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino @@ -36,7 +36,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.beginFLRC(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -58,7 +58,7 @@ void setup() { state = radio.setDataShaping(1.0); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; state = radio.setSyncWord(syncWord, 4); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); while (true); @@ -78,11 +78,11 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1280] Packet transmitted successfully!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { Serial.println(F("[SX1280] Packet too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while transmitting!")); } else { Serial.println(F("[SX1280] Failed to transmit packet, code ")); @@ -96,11 +96,11 @@ void loop() { byte byteArr[8]; int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1280] Received packet!")); Serial.print(F("[SX1280] Data:\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while waiting for packet!")); } else { Serial.print(F("[SX1280] Failed to receive packet, code ")); diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino index 2df0d6acf1..13412b4930 100644 --- a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -36,7 +36,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.beginGFSK(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -58,7 +58,7 @@ void setup() { state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89}; state = radio.setSyncWord(syncWord, 5); - if (state != ERR_NONE) { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); while (true); @@ -78,11 +78,11 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1280] Packet transmitted successfully!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { Serial.println(F("[SX1280] Packet too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while transmitting!")); } else { Serial.println(F("[SX1280] Failed to transmit packet, code ")); @@ -96,11 +96,11 @@ void loop() { byte byteArr[8]; int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("[SX1280] Received packet!")); Serial.print(F("[SX1280] Data:\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while waiting for packet!")); } else { Serial.print(F("[SX1280] Failed to receive packet, code ")); diff --git a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino index f53b1a2d38..2776f4f6df 100644 --- a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino +++ b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -35,7 +35,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -57,14 +57,14 @@ void loop() { int state = radio.range(false, 0x12345678); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // ranging finished successfully Serial.println(F("success!")); Serial.print(F("[SX1280] Distance:\t\t\t")); Serial.print(radio.getRangingResult()); Serial.println(F(" meters")); - } else if (state == ERR_RANGING_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RANGING_TIMEOUT) { // timed out waiting for ranging packet Serial.println(F("timed out!")); diff --git a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino index ff5adc4156..47c6c63b0b 100644 --- a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino +++ b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino @@ -40,7 +40,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -65,7 +65,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -85,11 +85,11 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 65e03f7d73..9bc9eaaa60 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -41,7 +41,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -56,7 +56,7 @@ void setup() { // start listening for LoRa packets Serial.print(F("[SX1280] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -115,7 +115,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1280] Received packet!")); @@ -133,7 +133,7 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino index 0963d85a96..36b02da14b 100644 --- a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino +++ b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -48,7 +48,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio1.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -68,7 +68,7 @@ void setup() { // output power: 2 dBm // preamble length: 20 symbols state = radio2.begin(2450.0, 1625.0, 7, 5, 2, 20); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -80,43 +80,43 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 2410.5 MHz - if (radio1.setFrequency(2410.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(2410.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); while (true); } // set bandwidth to 203.125 kHz - if (radio1.setBandwidth(203.125) == ERR_INVALID_BANDWIDTH) { + if (radio1.setBandwidth(203.125) == RADIOLIB_ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); while (true); } // set spreading factor to 10 - if (radio1.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); while (true); } // set coding rate to 6 - if (radio1.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); while (true); } // set output power to -2 dBm - if (radio1.setOutputPower(-2) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(-2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); while (true); } // set LoRa preamble length to 16 symbols (accepted range is 2 - 65535) - if (radio1.setPreambleLength(16) == ERR_INVALID_PREAMBLE_LENGTH) { + if (radio1.setPreambleLength(16) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); while (true); } // disable CRC - if (radio1.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { + if (radio1.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { Serial.println(F("Selected CRC is invalid for this module!")); while (true); } diff --git a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino b/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino index a4037def4c..e525698aa6 100644 --- a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino +++ b/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino @@ -43,7 +43,7 @@ void setup() { // preamble length: 12 symbols // CRC: enabled int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -78,11 +78,11 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index ecdd9312d5..b23fb0c156 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -32,7 +32,7 @@ SX1280 radio = new Module(10, 2, 3, 9); //SX1280 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -40,7 +40,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -97,7 +97,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 4e07828045..69fbea972d 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -11,13 +11,13 @@ int16_t SX1280::range(bool master, uint32_t addr) { RADIOLIB_ASSERT(state); // wait until ranging is finished - uint32_t start = Module::millis(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::millis() - start > 10000) { + uint32_t start = _mod->millis(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->millis() - start > 10000) { clearIrqStatus(); standby(); - return(ERR_RANGING_TIMEOUT); + return(RADIOLIB_ERR_RANGING_TIMEOUT); } } @@ -34,8 +34,8 @@ int16_t SX1280::range(bool master, uint32_t addr) { int16_t SX1280::startRanging(bool master, uint32_t addr) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { - return(ERR_WRONG_MODEM); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -43,8 +43,8 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) { RADIOLIB_ASSERT(state); // ensure modem is set to ranging - if(modem == SX128X_PACKET_TYPE_LORA) { - state = setPacketType(SX128X_PACKET_TYPE_RANGING); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + state = setPacketType(RADIOLIB_SX128X_PACKET_TYPE_RANGING); RADIOLIB_ASSERT(state); } @@ -58,21 +58,21 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) { // check all address bits uint8_t regValue; - state = readRegister(SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + state = readRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); RADIOLIB_ASSERT(state); regValue &= 0b00111111; regValue |= 0b11000000; - state = writeRegister(SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + state = writeRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); RADIOLIB_ASSERT(state); // set remaining parameter values - uint32_t addrReg = SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3; - uint32_t irqMask = SX128X_IRQ_RANGING_SLAVE_RESP_DONE | SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD; - uint32_t irqDio1 = SX128X_IRQ_RANGING_SLAVE_RESP_DONE; + uint32_t addrReg = RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3; + uint32_t irqMask = RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE | RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD; + uint32_t irqDio1 = RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE; if(master) { - addrReg = SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3; - irqMask = SX128X_IRQ_RANGING_MASTER_RES_VALID | SX128X_IRQ_RANGING_MASTER_TIMEOUT; - irqDio1 = SX128X_IRQ_RANGING_MASTER_RES_VALID; + addrReg = RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3; + irqMask = RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID | RADIOLIB_SX128X_IRQ_RANGING_MASTER_TIMEOUT; + irqDio1 = RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID; } // set ranging address @@ -93,35 +93,35 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) { }; uint16_t val = 0; switch(_bw) { - case(SX128X_LORA_BW_406_25): + case(RADIOLIB_SX128X_LORA_BW_406_25): val = calTable[0][index]; break; - case(SX128X_LORA_BW_812_50): + case(RADIOLIB_SX128X_LORA_BW_812_50): val = calTable[1][index]; break; - case(SX128X_LORA_BW_1625_00): + case(RADIOLIB_SX128X_LORA_BW_1625_00): val = calTable[2][index]; break; default: - return(ERR_INVALID_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_BANDWIDTH); } uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) }; - state = writeRegister(SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 2); + state = writeRegister(RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 2); RADIOLIB_ASSERT(state); // set role and start ranging if(master) { - state = setRangingRole(SX128X_RANGING_ROLE_MASTER); + state = setRangingRole(RADIOLIB_SX128X_RANGING_ROLE_MASTER); RADIOLIB_ASSERT(state); - state = setTx(SX128X_TX_TIMEOUT_NONE); + state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); } else { - state = setRangingRole(SX128X_RANGING_ROLE_SLAVE); + state = setRangingRole(RADIOLIB_SX128X_RANGING_ROLE_SLAVE); RADIOLIB_ASSERT(state); - state = setRx(SX128X_RX_TIMEOUT_INF); + state = setRx(RADIOLIB_SX128X_RX_TIMEOUT_INF); RADIOLIB_ASSERT(state); } @@ -131,33 +131,33 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) { float SX1280::getRangingResult() { // set mode to standby XOSC - int16_t state = standby(SX128X_STANDBY_XOSC); + int16_t state = standby(RADIOLIB_SX128X_STANDBY_XOSC); RADIOLIB_ASSERT(state); // enable clock uint8_t data[4]; - state = readRegister(SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); RADIOLIB_ASSERT(state); data[0] |= (1 << 1); - state = writeRegister(SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); + state = writeRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); RADIOLIB_ASSERT(state); // set result type to filtered - state = readRegister(SX128X_REG_RANGING_TYPE, data, 1); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1); RADIOLIB_ASSERT(state); data[0] &= 0xCF; data[0] |= (1 << 4); - state = writeRegister(SX128X_REG_RANGING_TYPE, data, 1); + state = writeRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1); RADIOLIB_ASSERT(state); // read the register values - state = readRegister(SX128X_REG_RANGING_RESULT_MSB, &data[0], 1); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MSB, &data[0], 1); RADIOLIB_ASSERT(state); - state = readRegister(SX128X_REG_RANGING_RESULT_MID, &data[1], 1); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MID, &data[1], 1); RADIOLIB_ASSERT(state); - state = readRegister(SX128X_REG_RANGING_RESULT_LSB, &data[2], 1); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_LSB, &data[2], 1); RADIOLIB_ASSERT(state); // set mode to standby RC diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index d92b5e6d4c..cdf797d6d9 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1,27 +1,31 @@ #include "SX128x.h" #if !defined(RADIOLIB_EXCLUDE_SX128X) -SX128x::SX128x(Module* mod) : PhysicalLayer(SX128X_FREQUENCY_STEP_SIZE, SX128X_MAX_PACKET_LENGTH) { +SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { _mod = mod; } +Module* SX128x::getMod() { + return(_mod); +} + int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize LoRa modulation variables _bwKhz = bw; - _sf = SX128X_LORA_SF_9; - _cr = SX128X_LORA_CR_4_7; + _sf = RADIOLIB_SX128X_LORA_SF_9; + _cr = RADIOLIB_SX128X_LORA_CR_4_7; // initialize LoRa packet variables _preambleLengthLoRa = preambleLength; - _headerType = SX128X_LORA_HEADER_EXPLICIT; + _headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT; _payloadLen = 0xFF; - _crcLoRa = SX128X_LORA_CRC_ON; + _crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; // reset the module and verify startup int16_t state = reset(); @@ -32,7 +36,7 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); // configure settings not accessible by API - state = config(SX128X_PACKET_TYPE_LORA); + state = config(RADIOLIB_SX128X_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -62,24 +66,24 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, uint16_t preambleLength) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize GFSK modulation variables _brKbps = br; - _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; _modIndexReal = 1.0; - _modIndex = SX128X_BLE_GFSK_MOD_IND_1_00; - _shaping = SX128X_BLE_GFSK_BT_0_5; + _modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; + _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; // initialize GFSK packet variables _preambleLengthGFSK = preambleLength; _syncWordLen = 2; - _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; - _crcGFSK = SX128X_GFSK_FLRC_CRC_2_BYTE; - _whitening = SX128X_GFSK_BLE_WHITENING_ON; + _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + _crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; + _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; // reset the module and verify startup int16_t state = reset(); @@ -90,7 +94,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, RADIOLIB_ASSERT(state); // configure settings not accessible by API - state = config(SX128X_PACKET_TYPE_GFSK); + state = config(RADIOLIB_SX128X_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -125,21 +129,21 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, uint8_t dataShaping) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize BLE modulation variables _brKbps = br; - _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; _modIndexReal = 1.0; - _modIndex = SX128X_BLE_GFSK_MOD_IND_1_00; - _shaping = SX128X_BLE_GFSK_BT_0_5; + _modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; + _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; // initialize BLE packet variables - _crcGFSK = SX128X_BLE_CRC_3_BYTE; - _whitening = SX128X_GFSK_BLE_WHITENING_ON; + _crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE; + _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; // reset the module and verify startup int16_t state = reset(); @@ -150,7 +154,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u RADIOLIB_ASSERT(state); // configure settings not accessible by API - state = config(SX128X_PACKET_TYPE_BLE); + state = config(RADIOLIB_SX128X_PACKET_TYPE_BLE); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -174,23 +178,23 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, uint8_t dataShaping) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getGpio(), INPUT); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize FLRC modulation variables _brKbps = br; - _br = SX128X_FLRC_BR_0_650_BW_0_6; - _crFLRC = SX128X_FLRC_CR_3_4; - _shaping = SX128X_FLRC_BT_0_5; + _br = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; + _crFLRC = RADIOLIB_SX128X_FLRC_CR_3_4; + _shaping = RADIOLIB_SX128X_FLRC_BT_0_5; // initialize FLRC packet variables _preambleLengthGFSK = preambleLength; _syncWordLen = 2; - _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; - _crcGFSK = SX128X_GFSK_FLRC_CRC_2_BYTE; - _whitening = SX128X_GFSK_BLE_WHITENING_OFF; + _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + _crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; + _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; // reset the module and verify startup int16_t state = reset(); @@ -201,7 +205,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin RADIOLIB_ASSERT(state); // configure settings not accessible by API - state = config(SX128X_PACKET_TYPE_FLRC); + state = config(RADIOLIB_SX128X_PACKET_TYPE_FLRC); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -233,47 +237,47 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin int16_t SX128x::reset(bool verify) { // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), HIGH); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), LOW); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), HIGH); // return immediately when verification is disabled if(!verify) { - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } // set mode to standby - uint32_t start = Module::millis(); + uint32_t start = _mod->millis(); while(true) { // try to set mode to standby int16_t state = standby(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { // standby command successful - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } // standby command failed, check timeout and try again - if(Module::millis() - start >= 3000) { + if(_mod->millis() - start >= 3000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - Module::delay(10); + _mod->delay(10); } } int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length - if(len > SX128X_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // check active modem uint8_t modem = getPacketType(); - if(modem == SX128X_PACKET_TYPE_RANGING) { - return(ERR_WRONG_MODEM); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -292,13 +296,13 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { clearIrqStatus(); standby(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -315,8 +319,8 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX128x::receive(uint8_t* data, size_t len) { // check active modem uint8_t modem = getPacketType(); - if(modem == SX128X_PACKET_TYPE_RANGING) { - return(ERR_WRONG_MODEM); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -336,13 +340,13 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = Module::micros(); - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { clearIrqStatus(); standby(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -355,14 +359,14 @@ int16_t SX128x::transmitDirect(uint32_t frf) { _mod->setRfSwitchState(LOW, HIGH); // user requested to start transmitting immediately (required for RTTY) - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; if(frf != 0) { state = setRfFrequency(frf); } RADIOLIB_ASSERT(state); // start transmitting - return(SPIwriteCommand(SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); } int16_t SX128x::receiveDirect() { @@ -370,13 +374,13 @@ int16_t SX128x::receiveDirect() { _mod->setRfSwitchState(HIGH, LOW); // SX128x is unable to output received data directly - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX128x::scanChannel() { // check active modem - if(getPacketType() != SX128X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -384,7 +388,7 @@ int16_t SX128x::scanChannel() { RADIOLIB_ASSERT(state); // set DIO pin mapping - state = setDioIrqParams(SX128X_IRQ_CAD_DETECTED | SX128X_IRQ_CAD_DONE, SX128X_IRQ_CAD_DETECTED | SX128X_IRQ_CAD_DONE); + state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -399,43 +403,43 @@ int16_t SX128x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!Module::digitalRead(_mod->getIrq())) { - Module::yield(); + while(!_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); } // check CAD result uint16_t cadResult = getIrqStatus(); - if(cadResult & SX128X_IRQ_CAD_DETECTED) { + if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) { // detected some LoRa activity clearIrqStatus(); - return(LORA_DETECTED); - } else if(cadResult & SX128X_IRQ_CAD_DONE) { + return(RADIOLIB_LORA_DETECTED); + } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) { // channel is free clearIrqStatus(); - return(CHANNEL_FREE); + return(RADIOLIB_CHANNEL_FREE); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX128x::sleep(bool retainConfig) { // set RF switch (if present) _mod->setRfSwitchState(LOW, LOW); - uint8_t sleepConfig = SX128X_SLEEP_DATA_BUFFER_RETAIN | SX128X_SLEEP_DATA_RAM_RETAIN; + uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN; if(!retainConfig) { - sleepConfig = SX128X_SLEEP_DATA_BUFFER_FLUSH | SX128X_SLEEP_DATA_RAM_FLUSH; + sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; } - int16_t state = SPIwriteCommand(SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); + int16_t state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); // wait for SX128x to safely enter sleep mode - Module::delay(1); + _mod->delay(1); return(state); } int16_t SX128x::standby() { - return(SX128x::standby(SX128X_STANDBY_RC)); + return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC)); } int16_t SX128x::standby(uint8_t mode) { @@ -443,15 +447,15 @@ int16_t SX128x::standby(uint8_t mode) { _mod->setRfSwitchState(LOW, LOW); uint8_t data[] = { mode }; - return(SPIwriteCommand(SX128X_CMD_SET_STANDBY, data, 1)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); } void SX128x::setDio1Action(void (*func)(void)) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void SX128x::clearDio1Action() { - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -459,21 +463,21 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { (void)addr; // check packet length - if(len > SX128X_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set packet Length - int16_t state = ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = getPacketType(); - if(modem == SX128X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa); - } else if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len); - } else if(modem == SX128X_PACKET_TYPE_BLE) { + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { state = setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening); } else { - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } RADIOLIB_ASSERT(state); @@ -486,7 +490,7 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // write packet to buffer - if(modem == SX128X_PACKET_TYPE_BLE) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { // first 2 bytes of BLE payload are PDU header state = writeBuffer(data, len, 2); RADIOLIB_ASSERT(state); @@ -496,7 +500,7 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set DIO mapping - state = setDioIrqParams(SX128X_IRQ_TX_DONE | SX128X_IRQ_RX_TX_TIMEOUT, SX128X_IRQ_TX_DONE); + state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -507,12 +511,12 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->setRfSwitchState(LOW, HIGH); // start transmission - state = setTx(SX128X_TX_TIMEOUT_NONE); + state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); } return(state); @@ -520,12 +524,12 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX128x::startReceive(uint16_t timeout) { // check active modem - if(getPacketType() == SX128X_PACKET_TYPE_RANGING) { - return(ERR_WRONG_MODEM); + if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set DIO mapping - int16_t state = setDioIrqParams(SX128X_IRQ_RX_DONE | SX128X_IRQ_RX_TX_TIMEOUT | SX128X_IRQ_CRC_ERROR | SX128X_IRQ_HEADER_ERROR, SX128X_IRQ_RX_DONE); + int16_t state = setDioIrqParams(RADIOLIB_SX128X_IRQ_RX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT | RADIOLIB_SX128X_IRQ_CRC_ERROR | RADIOLIB_SX128X_IRQ_HEADER_ERROR, RADIOLIB_SX128X_IRQ_RX_DONE); RADIOLIB_ASSERT(state); // set buffer pointers @@ -537,7 +541,7 @@ int16_t SX128x::startReceive(uint16_t timeout) { RADIOLIB_ASSERT(state); // set implicit mode and expected len if applicable - if((_headerType == SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == SX128X_PACKET_TYPE_LORA)) { + if((_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); RADIOLIB_ASSERT(state); } @@ -553,8 +557,8 @@ int16_t SX128x::startReceive(uint16_t timeout) { int16_t SX128x::readData(uint8_t* data, size_t len) { // check active modem - if(getPacketType() == SX128X_PACKET_TYPE_RANGING) { - return(ERR_WRONG_MODEM); + if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set mode to standby @@ -563,14 +567,14 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { // check integrity CRC uint16_t irq = getIrqStatus(); - int16_t crcState = ERR_NONE; - if((irq & SX128X_IRQ_CRC_ERROR) || (irq & SX128X_IRQ_HEADER_ERROR)) { - crcState = ERR_CRC_MISMATCH; + int16_t crcState = RADIOLIB_ERR_NONE; + if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || (irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR)) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; } // get packet length size_t length = len; - if(len == SX128X_MAX_PACKET_LENGTH) { + if(len == RADIOLIB_SX128X_MAX_PACKET_LENGTH) { length = getPacketLength(); } @@ -588,36 +592,36 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { } int16_t SX128x::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY); // calculate raw value - uint32_t frf = (freq * (uint32_t(1) << SX128X_DIV_EXPONENT)) / SX128X_CRYSTAL_FREQ; + uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_SX128X_CRYSTAL_FREQ; return(setRfFrequency(frf)); } int16_t SX128x::setBandwidth(float bw) { // check active modem uint8_t modem = getPacketType(); - if(modem == SX128X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { // check range for LoRa - RADIOLIB_CHECK_RANGE(bw, 203.125, 1625.0, ERR_INVALID_BANDWIDTH); - } else if(modem == SX128X_PACKET_TYPE_RANGING) { + RADIOLIB_CHECK_RANGE(bw, 203.125, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { // check range for ranging - RADIOLIB_CHECK_RANGE(bw, 406.25, 1625.0, ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 406.25, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH); } else { - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } if(fabs(bw - 203.125) <= 0.001) { - _bw = SX128X_LORA_BW_203_125; + _bw = RADIOLIB_SX128X_LORA_BW_203_125; } else if(fabs(bw - 406.25) <= 0.001) { - _bw = SX128X_LORA_BW_406_25; + _bw = RADIOLIB_SX128X_LORA_BW_406_25; } else if(fabs(bw - 812.5) <= 0.001) { - _bw = SX128X_LORA_BW_812_50; + _bw = RADIOLIB_SX128X_LORA_BW_812_50; } else if(fabs(bw - 1625.0) <= 0.001) { - _bw = SX128X_LORA_BW_1625_00; + _bw = RADIOLIB_SX128X_LORA_BW_1625_00; } else { - return(ERR_INVALID_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // update modulation parameters @@ -628,14 +632,14 @@ int16_t SX128x::setBandwidth(float bw) { int16_t SX128x::setSpreadingFactor(uint8_t sf) { // check active modem uint8_t modem = getPacketType(); - if(modem == SX128X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { // check range for LoRa - RADIOLIB_CHECK_RANGE(sf, 5, 12, ERR_INVALID_SPREADING_FACTOR); - } else if(modem == SX128X_PACKET_TYPE_RANGING) { + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { // check range for ranging - RADIOLIB_CHECK_RANGE(sf, 5, 10, ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } else { - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } // update modulation parameters @@ -644,16 +648,16 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) { RADIOLIB_ASSERT(state); // update mystery register in LoRa mode - SX1280 datasheet v3.0 section 13.4.1 - if(modem == SX128X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { uint8_t data = 0; - if((_sf == SX128X_LORA_SF_5) || (_sf == SX128X_LORA_SF_6)) { + if((_sf == RADIOLIB_SX128X_LORA_SF_5) || (_sf == RADIOLIB_SX128X_LORA_SF_6)) { data = 0x1E; - } else if((_sf == SX128X_LORA_SF_7) || (_sf == SX128X_LORA_SF_8)) { + } else if((_sf == RADIOLIB_SX128X_LORA_SF_7) || (_sf == RADIOLIB_SX128X_LORA_SF_8)) { data = 0x37; } else { data = 0x32; } - state = SX128x::writeRegister(SX128X_REG_LORA_SF_CONFIG, &data, 1); + state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1); } return(state); @@ -664,11 +668,11 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { uint8_t modem = getPacketType(); // LoRa/ranging - if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { - RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE); + if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { + RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters - if(longInterleaving && (modem == SX128X_PACKET_TYPE_LORA)) { + if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { _cr = cr; } else { _cr = cr - 4; @@ -676,32 +680,32 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { return(setModulationParams(_sf, _bw, _cr)); // FLRC - } else if(modem == SX128X_PACKET_TYPE_FLRC) { - RADIOLIB_CHECK_RANGE(cr, 2, 4, ERR_INVALID_CODING_RATE); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { + RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters _crFLRC = (cr - 2) * 2; return(setModulationParams(_br, _crFLRC, _shaping)); } - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t SX128x::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -18, 13, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); _pwr = power + 18; return(setTxParams(_pwr)); } int16_t SX128x::setPreambleLength(uint32_t preambleLength) { uint8_t modem = getPacketType(); - if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // LoRa or ranging - RADIOLIB_CHECK_RANGE(preambleLength, 2, 491520, ERR_INVALID_PREAMBLE_LENGTH); + RADIOLIB_CHECK_RANGE(preambleLength, 2, 491520, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); // check preamble length is even - no point even trying odd numbers if(preambleLength % 2 != 0) { - return(ERR_INVALID_PREAMBLE_LENGTH); + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } // calculate exponent and mantissa values (use the next longer preamble if there's no exact match) @@ -724,13 +728,13 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { _preambleLengthLoRa = (e << 4) | m; return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa)); - } else if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { // GFSK or FLRC - RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, ERR_INVALID_PREAMBLE_LENGTH); + RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); // check preamble length is multiple of 4 if(preambleLength % 4 != 0) { - return(ERR_INVALID_PREAMBLE_LENGTH); + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } // update packet parameters @@ -738,7 +742,7 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); } - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t SX128x::setBitRate(uint16_t br) { @@ -746,25 +750,25 @@ int16_t SX128x::setBitRate(uint16_t br) { uint8_t modem = getPacketType(); // GFSK/BLE - if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE)) { + if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { if(br == 125) { - _br = SX128X_BLE_GFSK_BR_0_125_BW_0_3; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; } else if(br == 250) { - _br = SX128X_BLE_GFSK_BR_0_250_BW_0_6; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6; } else if(br == 400) { - _br = SX128X_BLE_GFSK_BR_0_400_BW_1_2; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2; } else if(br == 500) { - _br = SX128X_BLE_GFSK_BR_0_500_BW_1_2; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2; } else if(br == 800) { - _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; } else if(br == 1000) { - _br = SX128X_BLE_GFSK_BR_1_000_BW_2_4; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4; } else if(br == 1600) { - _br = SX128X_BLE_GFSK_BR_1_600_BW_2_4; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4; } else if(br == 2000) { - _br = SX128X_BLE_GFSK_BR_2_000_BW_2_4; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4; } else { - return(ERR_INVALID_BIT_RATE); + return(RADIOLIB_ERR_INVALID_BIT_RATE); } // update modulation parameters @@ -772,21 +776,21 @@ int16_t SX128x::setBitRate(uint16_t br) { return(setModulationParams(_br, _modIndex, _shaping)); // FLRC - } else if(modem == SX128X_PACKET_TYPE_FLRC) { + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { if(br == 260) { - _br = SX128X_FLRC_BR_0_260_BW_0_3; + _br = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3; } else if(br == 325) { - _br = SX128X_FLRC_BR_0_325_BW_0_3; + _br = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3; } else if(br == 520) { - _br = SX128X_FLRC_BR_0_520_BW_0_6; + _br = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6; } else if(br == 650) { - _br = SX128X_FLRC_BR_0_650_BW_0_6; + _br = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; } else if(br == 1000) { - _br = SX128X_FLRC_BR_1_000_BW_1_2; + _br = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2; } else if(br == 1300) { - _br = SX128X_FLRC_BR_1_300_BW_1_2; + _br = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2; } else { - return(ERR_INVALID_BIT_RATE); + return(RADIOLIB_ERR_INVALID_BIT_RATE); } // update modulation parameters @@ -795,14 +799,14 @@ int16_t SX128x::setBitRate(uint16_t br) { } - return(ERR_WRONG_MODEM); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t SX128x::setFrequencyDeviation(float freqDev) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { - return(ERR_WRONG_MODEM); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set frequency deviation to lowest available setting (required for digimodes) @@ -811,19 +815,19 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { newFreqDev = 62.5; } - RADIOLIB_CHECK_RANGE(newFreqDev, 62.5, 1000.0, ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 62.5, 1000.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols if(newFreqDev == 0.0) { - _modIndex = SX128X_BLE_GFSK_MOD_IND_0_35; - _br = SX128X_BLE_GFSK_BR_0_125_BW_0_3; + _modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35; + _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; return(setModulationParams(_br, _modIndex, _shaping)); } // update modulation parameters uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)_brKbps)) - 1.0); - if(modIndex > SX128X_BLE_GFSK_MOD_IND_4_00) { - return(ERR_INVALID_MODULATION_PARAMETERS); + if(modIndex > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) { + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); } // update modulation parameters @@ -834,27 +838,27 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { int16_t SX128x::setDataShaping(uint8_t sh) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE) || (modem == SX128X_PACKET_TYPE_FLRC))) { - return(ERR_WRONG_MODEM); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - _shaping = SX128X_BLE_GFSK_BT_OFF; + _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF; break; case RADIOLIB_SHAPING_0_5: - _shaping = SX128X_BLE_GFSK_BT_0_5; + _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; break; case RADIOLIB_SHAPING_1_0: - _shaping = SX128X_BLE_GFSK_BT_1_0; + _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0; break; default: - return(ERR_INVALID_DATA_SHAPING); + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } // update modulation parameters - if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE)) { + if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { return(setModulationParams(_br, _modIndex, _shaping)); } else { return(setModulationParams(_br, _crFLRC, _shaping)); @@ -864,14 +868,14 @@ int16_t SX128x::setDataShaping(uint8_t sh) { int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC))) { - return(ERR_WRONG_MODEM); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { + return(RADIOLIB_ERR_WRONG_MODEM); } - if(modem == SX128X_PACKET_TYPE_GFSK) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { // GFSK can use up to 5 bytes as sync word if(len > 5) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } // calculate sync word length parameter value @@ -882,7 +886,7 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { } else { // FLRC requires 32-bit sync word if(!((len == 0) || (len == 4))) { - return(ERR_INVALID_SYNC_WORD); + return(RADIOLIB_ERR_INVALID_SYNC_WORD); } // save sync word length parameter value @@ -896,28 +900,28 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { } // update sync word - int16_t state = SX128x::writeRegister(SX128X_REG_SYNC_WORD_1_BYTE_4, syncWordBuff, 5); + int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, syncWordBuff, 5); RADIOLIB_ASSERT(state); // update packet parameters if(_syncWordLen == 0) { - _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_OFF; + _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF; } else { /// \todo add support for multiple sync words - _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; + _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; } return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); } int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { // check active modem - if(getPacketType() != SX128X_PACKET_TYPE_LORA) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } // update register uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; - return(writeRegister(SX128X_REG_LORA_SYNC_WORD_MSB, data, 2)); + return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2)); } int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { @@ -925,15 +929,15 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { uint8_t modem = getPacketType(); int16_t state; - if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { + if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { // update packet parameters - if(modem == SX128X_PACKET_TYPE_GFSK) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { if(len > 2) { - return(ERR_INVALID_CRC_CONFIGURATION); + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } } else { if(len > 3) { - return(ERR_INVALID_CRC_CONFIGURATION); + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } } _crcGFSK = len << 4; @@ -942,63 +946,63 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { // set initial CRC value uint8_t data[] = { (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; - state = writeRegister(SX128X_REG_CRC_INITIAL_MSB, data, 2); + state = writeRegister(RADIOLIB_SX128X_REG_CRC_INITIAL_MSB, data, 2); RADIOLIB_ASSERT(state); // set CRC polynomial data[0] = (uint8_t)((polynomial >> 8) & 0xFF); data[1] = (uint8_t)(polynomial & 0xFF); - state = writeRegister(SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2); + state = writeRegister(RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2); return(state); - } else if(modem == SX128X_PACKET_TYPE_BLE) { + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { // update packet parameters if(len == 0) { - _crcBLE = SX128X_BLE_CRC_OFF; + _crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF; } else if(len == 3) { - _crcBLE = SX128X_BLE_CRC_3_BYTE; + _crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE; } else { - return(ERR_INVALID_CRC_CONFIGURATION); + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } state = setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening); RADIOLIB_ASSERT(state); // set initial CRC value uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; - state = writeRegister(SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3); + state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3); return(state); - } else if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // update packet parameters if(len == 0) { - _crcLoRa = SX128X_LORA_CRC_OFF; + _crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF; } else if(len == 2) { - _crcLoRa = SX128X_LORA_CRC_ON; + _crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; } else { - return(ERR_INVALID_CRC_CONFIGURATION); + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); return(state); } - return(ERR_UNKNOWN); + return(RADIOLIB_ERR_UNKNOWN); } int16_t SX128x::setWhitening(bool enabled) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { - return(ERR_WRONG_MODEM); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) { + return(RADIOLIB_ERR_WRONG_MODEM); } // update packet parameters if(enabled) { - _whitening = SX128X_GFSK_BLE_WHITENING_ON; + _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; } else { - _whitening = SX128X_GFSK_BLE_WHITENING_OFF; + _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; } - if(modem == SX128X_PACKET_TYPE_GFSK) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); } return(setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening)); @@ -1006,23 +1010,23 @@ int16_t SX128x::setWhitening(bool enabled) { int16_t SX128x::setAccessAddress(uint32_t addr) { // check active modem - if(getPacketType() != SX128X_PACKET_TYPE_BLE) { - return(ERR_WRONG_MODEM); + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_BLE) { + return(RADIOLIB_ERR_WRONG_MODEM); } // set the address uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - return(SX128x::writeRegister(SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); + return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); } float SX128x::getRSSI() { // get packet status uint8_t packetStatus[5]; - SPIreadCommand(SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + SPIreadCommand(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); // check active modem uint8_t modem = getPacketType(); - if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // LoRa or ranging uint8_t rssiSync = packetStatus[0]; float rssiMeasured = -1.0 * rssiSync/2.0; @@ -1042,13 +1046,13 @@ float SX128x::getRSSI() { float SX128x::getSNR() { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { return(0.0); } // get packet status uint8_t packetStatus[5]; - SPIreadCommand(SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + SPIreadCommand(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); // calculate real SNR uint8_t snr = packetStatus[1]; @@ -1062,18 +1066,18 @@ float SX128x::getSNR() { size_t SX128x::getPacketLength(bool update) { (void)update; uint8_t rxBufStatus[2] = {0, 0}; - SPIreadCommand(SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + SPIreadCommand(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } uint32_t SX128x::getTimeOnAir(size_t len) { // check active modem uint8_t modem = getPacketType(); - if(modem == SX128X_PACKET_TYPE_LORA) { + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { // calculate number of symbols float N_symbol = 0; uint8_t sf = _sf >> 4; - if(_cr <= SX128X_LORA_CR_4_8) { + if(_cr <= RADIOLIB_SX128X_LORA_CR_4_8) { // legacy coding rate - nice and simple // get SF coefficients @@ -1099,13 +1103,13 @@ uint32_t SX128x::getTimeOnAir(size_t len) { // get CRC length int16_t N_bitCRC = 16; - if(_crcLoRa == SX128X_LORA_CRC_OFF) { + if(_crcLoRa == RADIOLIB_SX128X_LORA_CRC_OFF) { N_bitCRC = 0; } // get header length int16_t N_symbolHeader = 20; - if(_headerType == SX128X_LORA_HEADER_IMPLICIT) { + if(_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) { N_symbolHeader = 0; } @@ -1131,11 +1135,11 @@ uint32_t SX128x::getTimeOnAir(size_t len) { } int16_t SX128x::implicitHeader(size_t len) { - return(setHeaderType(SX128X_LORA_HEADER_IMPLICIT, len)); + return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len)); } int16_t SX128x::explicitHeader() { - return(setHeaderType(SX128X_LORA_HEADER_EXPLICIT)); + return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_EXPLICIT)); } int16_t SX128x::setEncoding(uint8_t encoding) { @@ -1166,83 +1170,83 @@ void SX128x::readBit(RADIOLIB_PIN_TYPE pin) { uint8_t SX128x::getStatus() { uint8_t data = 0; - SPIreadCommand(SX128X_CMD_GET_STATUS, &data, 1); + SPIreadCommand(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 1); return(data); } int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { SX128X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; return(SPIwriteCommand(cmd, 3, data, numBytes)); } int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { SX128X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; return(SX128x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true)); } int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - uint8_t cmd[] = { SX128X_CMD_WRITE_BUFFER, offset }; + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset }; return(SPIwriteCommand(cmd, 2, data, numBytes)); } int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { SX128X_CMD_READ_BUFFER, SX128X_CMD_NOP }; + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, RADIOLIB_SX128X_CMD_NOP }; return(SPIreadCommand(cmd, 2, data, numBytes)); } int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) { uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; - return(SPIwriteCommand(SX128X_CMD_SET_TX, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); } int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; - return(SPIwriteCommand(SX128X_CMD_SET_RX, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); } int16_t SX128x::setCad() { - return(SPIwriteCommand(SX128X_CMD_SET_CAD, NULL, 0)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); } uint8_t SX128x::getPacketType() { uint8_t data = 0xFF; - SPIreadCommand(SX128X_CMD_GET_PACKET_TYPE, &data, 1); + SPIreadCommand(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1); return(data); } int16_t SX128x::setRfFrequency(uint32_t frf) { uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(SPIwriteCommand(SX128X_CMD_SET_RF_FREQUENCY, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); } int16_t SX128x::setTxParams(uint8_t power, uint8_t rampTime) { uint8_t data[] = { power, rampTime }; - return(SPIwriteCommand(SX128X_CMD_SET_TX_PARAMS, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { uint8_t data[] = { txBaseAddress, rxBaseAddress }; - return(SPIwriteCommand(SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { uint8_t data[] = { modParam1, modParam2, modParam3 }; - return(SPIwriteCommand(SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); } int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen, uint8_t headerType) { uint8_t data[] = { preambleLen, syncWordLen, syncWordMatch, headerType, payloadLen, crcLen, whitening }; - return(SPIwriteCommand(SX128X_CMD_SET_PACKET_PARAMS, data, 7)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening) { uint8_t data[] = { connState, crcLen, bleTestPayload, whitening, 0x00, 0x00, 0x00 }; - return(SPIwriteCommand(SX128X_CMD_SET_PACKET_PARAMS, data, 7)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ) { uint8_t data[] = { preambleLen, headerType, payloadLen, crc, invertIQ, 0x00, 0x00 }; - return(SPIwriteCommand(SX128X_CMD_SET_PACKET_PARAMS, data, 7)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { @@ -1250,35 +1254,35 @@ int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) }; - return(SPIwriteCommand(SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } uint16_t SX128x::getIrqStatus() { uint8_t data[] = { 0x00, 0x00 }; - SPIreadCommand(SX128X_CMD_GET_IRQ_STATUS, data, 2); + SPIreadCommand(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(SPIwriteCommand(SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX128x::setRangingRole(uint8_t role) { uint8_t data[] = { role }; - return(SPIwriteCommand(SX128X_CMD_SET_RANGING_ROLE, data, 1)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); } int16_t SX128x::setPacketType(uint8_t type) { uint8_t data[] = { type }; - return(SPIwriteCommand(SX128X_CMD_SET_PACKET_TYPE, data, 1)); + return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); } int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { - return(ERR_WRONG_MODEM); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(RADIOLIB_ERR_WRONG_MODEM); } // update packet parameters @@ -1295,20 +1299,20 @@ int16_t SX128x::config(uint8_t modem) { // set modem uint8_t data[1]; data[0] = modem; - state = SPIwriteCommand(SX128X_CMD_SET_PACKET_TYPE, data, 1); + state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1); RADIOLIB_ASSERT(state); // set CAD parameters - data[0] = SX128X_CAD_ON_8_SYMB; - state = SPIwriteCommand(SX128X_CMD_SET_CAD_PARAMS, data, 1); + data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB; + state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1); RADIOLIB_ASSERT(state); // set regulator mode to DC-DC - data[0] = SX128X_REGULATOR_DC_DC; - state = SPIwriteCommand(SX128X_CMD_SET_REGULATOR_MODE, data, 1); + data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC; + state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1); RADIOLIB_ASSERT(state); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t SX128x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { @@ -1328,33 +1332,29 @@ int16_t SX128x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, boo } int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { - // get pointer to used SPI interface and the settings - SPIClass* spi = _mod->getSpi(); - SPISettings spiSettings = _mod->getSpiSettings(); - - #ifdef RADIOLIB_VERBOSE + #if defined(RADIOLIB_VERBOSE) uint8_t debugBuff[256]; #endif // ensure BUSY is low (state machine ready) - uint32_t start = Module::millis(); - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); - if(Module::millis() - start >= timeout) { - Module::digitalWrite(_mod->getCs(), HIGH); - return(ERR_SPI_CMD_TIMEOUT); + uint32_t start = _mod->millis(); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); + if(_mod->millis() - start >= timeout) { + _mod->digitalWrite(_mod->getCs(), HIGH); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } // pull NSS low - Module::digitalWrite(_mod->getCs(), LOW); + _mod->digitalWrite(_mod->getCs(), LOW); // start transfer - spi->beginTransaction(spiSettings); + _mod->SPIbeginTransaction(); // send command byte(s) for(uint8_t n = 0; n < cmdLen; n++) { - spi->transfer(cmd[n]); + _mod->SPItransfer(cmd[n]); } // variable to save error during SPI transfer @@ -1364,63 +1364,63 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d if(write) { for(uint8_t n = 0; n < numBytes; n++) { // send byte - uint8_t in = spi->transfer(dataOut[n]); - #ifdef RADIOLIB_VERBOSE + uint8_t in = _mod->SPItransfer(dataOut[n]); + #if defined(RADIOLIB_VERBOSE) debugBuff[n] = in; #endif // check status - if(((in & 0b00011100) == SX128X_STATUS_CMD_TIMEOUT) || - ((in & 0b00011100) == SX128X_STATUS_CMD_ERROR) || - ((in & 0b00011100) == SX128X_STATUS_CMD_FAILED)) { + if(((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) || + ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) || + ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED)) { status = in & 0b00011100; break; } else if(in == 0x00 || in == 0xFF) { - status = SX128X_STATUS_SPI_FAILED; + status = RADIOLIB_SX128X_STATUS_SPI_FAILED; break; } } } else { // skip the first byte for read-type commands (status-only) - uint8_t in = spi->transfer(SX128X_CMD_NOP); - #ifdef RADIOLIB_VERBOSE + uint8_t in = _mod->SPItransfer(RADIOLIB_SX128X_CMD_NOP); + #if defined(RADIOLIB_VERBOSE) debugBuff[0] = in; #endif // check status - if(((in & 0b00011100) == SX128X_STATUS_CMD_TIMEOUT) || - ((in & 0b00011100) == SX128X_STATUS_CMD_ERROR) || - ((in & 0b00011100) == SX128X_STATUS_CMD_FAILED)) { + if(((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) || + ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) || + ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED)) { status = in & 0b00011100; } else if(in == 0x00 || in == 0xFF) { - status = SX128X_STATUS_SPI_FAILED; + status = RADIOLIB_SX128X_STATUS_SPI_FAILED; } else { for(uint8_t n = 0; n < numBytes; n++) { - dataIn[n] = spi->transfer(SX128X_CMD_NOP); + dataIn[n] = _mod->SPItransfer(RADIOLIB_SX128X_CMD_NOP); } } } // stop transfer - spi->endTransaction(); - Module::digitalWrite(_mod->getCs(), HIGH); + _mod->SPIendTransaction(); + _mod->digitalWrite(_mod->getCs(), HIGH); // wait for BUSY to go high and then low if(waitForBusy) { - Module::delayMicroseconds(1); - start = Module::millis(); - while(Module::digitalRead(_mod->getGpio())) { - Module::yield(); - if(Module::millis() - start >= timeout) { - status = SX128X_STATUS_CMD_TIMEOUT; + _mod->delayMicroseconds(1); + start = _mod->millis(); + while(_mod->digitalRead(_mod->getGpio())) { + _mod->yield(); + if(_mod->millis() - start >= timeout) { + status = RADIOLIB_SX128X_STATUS_CMD_TIMEOUT; break; } } } // print debug output - #ifdef RADIOLIB_VERBOSE + #if defined(RADIOLIB_VERBOSE) // print command byte(s) RADIOLIB_VERBOSE_PRINT("CMD\t"); for(uint8_t n = 0; n < cmdLen; n++) { @@ -1443,13 +1443,13 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d } else { RADIOLIB_VERBOSE_PRINT("R\t"); // skip the first byte for read-type commands (status-only) - RADIOLIB_VERBOSE_PRINT(SX128X_CMD_NOP, HEX); + RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX128X_CMD_NOP, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); RADIOLIB_VERBOSE_PRINT('\t') for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(SX128X_CMD_NOP, HEX); + RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX128X_CMD_NOP, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); @@ -1462,22 +1462,22 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // not sure why, but it seems that long enough SPI transaction // (e.g. setPacketParams for GFSK) will fail without it #if defined(RADIOLIB_SPI_SLOWDOWN) - Module::delay(1); + _mod->delay(1); #endif #endif // parse status switch(status) { - case SX128X_STATUS_CMD_TIMEOUT: - return(ERR_SPI_CMD_TIMEOUT); - case SX128X_STATUS_CMD_ERROR: - return(ERR_SPI_CMD_INVALID); - case SX128X_STATUS_CMD_FAILED: - return(ERR_SPI_CMD_FAILED); - case SX128X_STATUS_SPI_FAILED: - return(ERR_CHIP_NOT_FOUND); + case RADIOLIB_SX128X_STATUS_CMD_TIMEOUT: + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + case RADIOLIB_SX128X_STATUS_CMD_ERROR: + return(RADIOLIB_ERR_SPI_CMD_INVALID); + case RADIOLIB_SX128X_STATUS_CMD_FAILED: + return(RADIOLIB_ERR_SPI_CMD_FAILED); + case RADIOLIB_SX128X_STATUS_SPI_FAILED: + return(RADIOLIB_ERR_CHIP_NOT_FOUND); default: - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 377850c309..b1a39e94e6 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -10,336 +10,336 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // SX128X physical layer properties -#define SX128X_FREQUENCY_STEP_SIZE 198.3642578 -#define SX128X_MAX_PACKET_LENGTH 255 -#define SX128X_CRYSTAL_FREQ 52.0 -#define SX128X_DIV_EXPONENT 18 +#define RADIOLIB_SX128X_FREQUENCY_STEP_SIZE 198.3642578 +#define RADIOLIB_SX128X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0 +#define RADIOLIB_SX128X_DIV_EXPONENT 18 // SX128X SPI commands -#define SX128X_CMD_NOP 0x00 -#define SX128X_CMD_GET_STATUS 0xC0 -#define SX128X_CMD_WRITE_REGISTER 0x18 -#define SX128X_CMD_READ_REGISTER 0x19 -#define SX128X_CMD_WRITE_BUFFER 0x1A -#define SX128X_CMD_READ_BUFFER 0x1B -#define SX128X_CMD_SET_SLEEP 0x84 -#define SX128X_CMD_SET_STANDBY 0x80 -#define SX128X_CMD_SET_FS 0xC1 -#define SX128X_CMD_SET_TX 0x83 -#define SX128X_CMD_SET_RX 0x82 -#define SX128X_CMD_SET_RX_DUTY_CYCLE 0x94 -#define SX128X_CMD_SET_CAD 0xC5 -#define SX128X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 -#define SX128X_CMD_SET_TX_CONTINUOUS_PREAMBLE 0xD2 -#define SX128X_CMD_SET_PACKET_TYPE 0x8A -#define SX128X_CMD_GET_PACKET_TYPE 0x03 -#define SX128X_CMD_SET_RF_FREQUENCY 0x86 -#define SX128X_CMD_SET_TX_PARAMS 0x8E -#define SX128X_CMD_SET_CAD_PARAMS 0x88 -#define SX128X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F -#define SX128X_CMD_SET_MODULATION_PARAMS 0x8B -#define SX128X_CMD_SET_PACKET_PARAMS 0x8C -#define SX128X_CMD_GET_RX_BUFFER_STATUS 0x17 -#define SX128X_CMD_GET_PACKET_STATUS 0x1D -#define SX128X_CMD_GET_RSSI_INST 0x1F -#define SX128X_CMD_SET_DIO_IRQ_PARAMS 0x8D -#define SX128X_CMD_GET_IRQ_STATUS 0x15 -#define SX128X_CMD_CLEAR_IRQ_STATUS 0x97 -#define SX128X_CMD_SET_REGULATOR_MODE 0x96 -#define SX128X_CMD_SET_SAVE_CONTEXT 0xD5 -#define SX128X_CMD_SET_AUTO_TX 0x98 -#define SX128X_CMD_SET_AUTO_FS 0x9E -#define SX128X_CMD_SET_PERF_COUNTER_MODE 0x9C -#define SX128X_CMD_SET_LONG_PREAMBLE 0x9B -#define SX128X_CMD_SET_UART_SPEED 0x9D -#define SX128X_CMD_SET_RANGING_ROLE 0xA3 -#define SX128X_CMD_SET_ADVANCED_RANGING 0x9A +#define RADIOLIB_SX128X_CMD_NOP 0x00 +#define RADIOLIB_SX128X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX128X_CMD_WRITE_REGISTER 0x18 +#define RADIOLIB_SX128X_CMD_READ_REGISTER 0x19 +#define RADIOLIB_SX128X_CMD_WRITE_BUFFER 0x1A +#define RADIOLIB_SX128X_CMD_READ_BUFFER 0x1B +#define RADIOLIB_SX128X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX128X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX128X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX128X_CMD_SET_TX 0x83 +#define RADIOLIB_SX128X_CMD_SET_RX 0x82 +#define RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX128X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_PREAMBLE 0xD2 +#define RADIOLIB_SX128X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX128X_CMD_GET_PACKET_TYPE 0x03 +#define RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX128X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX128X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS 0x17 +#define RADIOLIB_SX128X_CMD_GET_PACKET_STATUS 0x1D +#define RADIOLIB_SX128X_CMD_GET_RSSI_INST 0x1F +#define RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS 0x8D +#define RADIOLIB_SX128X_CMD_GET_IRQ_STATUS 0x15 +#define RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS 0x97 +#define RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX128X_CMD_SET_SAVE_CONTEXT 0xD5 +#define RADIOLIB_SX128X_CMD_SET_AUTO_TX 0x98 +#define RADIOLIB_SX128X_CMD_SET_AUTO_FS 0x9E +#define RADIOLIB_SX128X_CMD_SET_PERF_COUNTER_MODE 0x9C +#define RADIOLIB_SX128X_CMD_SET_LONG_PREAMBLE 0x9B +#define RADIOLIB_SX128X_CMD_SET_UART_SPEED 0x9D +#define RADIOLIB_SX128X_CMD_SET_RANGING_ROLE 0xA3 +#define RADIOLIB_SX128X_CMD_SET_ADVANCED_RANGING 0x9A // SX128X register map -#define SX128X_REG_GAIN_MODE 0x0891 -#define SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 -#define SX128X_REG_MANUAL_GAIN_SETTING 0x089E -#define SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1 0x089F -#define SX128X_REG_SYNCH_PEAK_ATTENUATION 0x08C2 -#define SX128X_REG_LORA_FIXED_PAYLOAD_LENGTH 0x0901 -#define SX128X_REG_LORA_HEADER_MODE 0x0903 -#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3 0x0912 -#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_2 0x0913 -#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_1 0x0914 -#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_0 0x0915 -#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3 0x0916 -#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_2 0x0917 -#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_1 0x0918 -#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_0 0x0919 -#define SX128X_REG_RANGING_FILTER_WINDOW_SIZE 0x091E -#define SX128X_REG_RANGING_FILTER_RESET 0x0923 -#define SX128X_REG_RANGING_TYPE 0x0924 -#define SX128X_REG_LORA_SF_CONFIG 0x0925 -#define SX128X_REG_RANGING_ADDRESS_SWITCH 0x0927 -#define SX128X_REG_RANGING_CALIBRATION_BYTE_2 0x092B -#define SX128X_REG_RANGING_CALIBRATION_MSB 0x092C -#define SX128X_REG_RANGING_CALIBRATION_LSB 0x092D -#define SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH 0x0931 -#define SX128X_REG_FREQ_ERROR_CORRECTION 0x093C -#define SX128X_REG_LORA_SYNC_WORD_MSB 0x0944 -#define SX128X_REG_LORA_SYNC_WORD_LSB 0x0945 -#define SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 -#define SX128X_REG_FEI_MSB 0x0954 -#define SX128X_REG_FEI_MID 0x0955 -#define SX128X_REG_FEI_LSB 0x0956 -#define SX128X_REG_RANGING_ADDRESS_MSB 0x095F -#define SX128X_REG_RANGING_ADDRESS_LSB 0x0960 -#define SX128X_REG_RANGING_RESULT_MSB 0x0961 -#define SX128X_REG_RANGING_RESULT_MID 0x0962 -#define SX128X_REG_RANGING_RESULT_LSB 0x0963 -#define SX128X_REG_RANGING_RSSI 0x0964 -#define SX128X_REG_RANGING_LORA_CLOCK_ENABLE 0x097F -#define SX128X_REG_PACKET_PREAMBLE_SETTINGS 0x09C1 -#define SX128X_REG_WHITENING_INITIAL_VALUE 0x09C5 -#define SX128X_REG_CRC_POLYNOMIAL_MSB 0x09C6 -#define SX128X_REG_CRC_POLYNOMIAL_LSB 0x09C7 -#define SX128X_REG_CRC_INITIAL_MSB 0x09C8 -#define SX128X_REG_CRC_INITIAL_LSB 0x09C9 -#define SX128X_REG_BLE_CRC_INITIAL_MSB 0x09C7 -#define SX128X_REG_BLE_CRC_INITIAL_MID (SX128X_REG_CRC_INITIAL_MSB) -#define SX128X_REG_BLE_CRC_INITIAL_LSB (SX128X_REG_CRC_INITIAL_LSB) -#define SX128X_REG_SYNCH_ADDRESS_CONTROL 0x09CD -#define SX128X_REG_SYNC_WORD_1_BYTE_4 0x09CE -#define SX128X_REG_SYNC_WORD_1_BYTE_3 0x09CF -#define SX128X_REG_SYNC_WORD_1_BYTE_2 0x09D0 -#define SX128X_REG_SYNC_WORD_1_BYTE_1 0x09D1 -#define SX128X_REG_SYNC_WORD_1_BYTE_0 0x09D2 -#define SX128X_REG_SYNC_WORD_2_BYTE_4 0x09D3 -#define SX128X_REG_SYNC_WORD_2_BYTE_3 0x09D4 -#define SX128X_REG_SYNC_WORD_2_BYTE_2 0x09D5 -#define SX128X_REG_SYNC_WORD_2_BYTE_1 0x09D6 -#define SX128X_REG_SYNC_WORD_2_BYTE_0 0x09D7 -#define SX128X_REG_SYNC_WORD_3_BYTE_4 0x09D8 -#define SX128X_REG_SYNC_WORD_3_BYTE_3 0x09D9 -#define SX128X_REG_SYNC_WORD_3_BYTE_2 0x09DA -#define SX128X_REG_SYNC_WORD_3_BYTE_1 0x09DB -#define SX128X_REG_SYNC_WORD_3_BYTE_0 0x09DC -#define SX128X_REG_ACCESS_ADDRESS_BYTE_3 (SX128X_REG_SYNC_WORD_1_BYTE_3) -#define SX128X_REG_ACCESS_ADDRESS_BYTE_2 (SX128X_REG_SYNC_WORD_1_BYTE_2) -#define SX128X_REG_ACCESS_ADDRESS_BYTE_1 (SX128X_REG_SYNC_WORD_1_BYTE_1) -#define SX128X_REG_ACCESS_ADDRESS_BYTE_0 (SX128X_REG_SYNC_WORD_1_BYTE_0) +#define RADIOLIB_SX128X_REG_GAIN_MODE 0x0891 +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING 0x089E +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1 0x089F +#define RADIOLIB_SX128X_REG_SYNCH_PEAK_ATTENUATION 0x08C2 +#define RADIOLIB_SX128X_REG_LORA_FIXED_PAYLOAD_LENGTH 0x0901 +#define RADIOLIB_SX128X_REG_LORA_HEADER_MODE 0x0903 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3 0x0912 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_2 0x0913 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_1 0x0914 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_0 0x0915 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3 0x0916 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_2 0x0917 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_1 0x0918 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_0 0x0919 +#define RADIOLIB_SX128X_REG_RANGING_FILTER_WINDOW_SIZE 0x091E +#define RADIOLIB_SX128X_REG_RANGING_FILTER_RESET 0x0923 +#define RADIOLIB_SX128X_REG_RANGING_TYPE 0x0924 +#define RADIOLIB_SX128X_REG_LORA_SF_CONFIG 0x0925 +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_SWITCH 0x0927 +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_BYTE_2 0x092B +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB 0x092C +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_LSB 0x092D +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH 0x0931 +#define RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION 0x093C +#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB 0x0944 +#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_LSB 0x0945 +#define RADIOLIB_SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 +#define RADIOLIB_SX128X_REG_FEI_MSB 0x0954 +#define RADIOLIB_SX128X_REG_FEI_MID 0x0955 +#define RADIOLIB_SX128X_REG_FEI_LSB 0x0956 +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_MSB 0x095F +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_LSB 0x0960 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_MSB 0x0961 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_MID 0x0962 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_LSB 0x0963 +#define RADIOLIB_SX128X_REG_RANGING_RSSI 0x0964 +#define RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE 0x097F +#define RADIOLIB_SX128X_REG_PACKET_PREAMBLE_SETTINGS 0x09C1 +#define RADIOLIB_SX128X_REG_WHITENING_INITIAL_VALUE 0x09C5 +#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB 0x09C6 +#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_LSB 0x09C7 +#define RADIOLIB_SX128X_REG_CRC_INITIAL_MSB 0x09C8 +#define RADIOLIB_SX128X_REG_CRC_INITIAL_LSB 0x09C9 +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB 0x09C7 +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MID (RADIOLIB_SX128X_REG_CRC_INITIAL_MSB) +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_LSB (RADIOLIB_SX128X_REG_CRC_INITIAL_LSB) +#define RADIOLIB_SX128X_REG_SYNCH_ADDRESS_CONTROL 0x09CD +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 0x09CE +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3 0x09CF +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2 0x09D0 +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1 0x09D1 +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0 0x09D2 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_4 0x09D3 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_3 0x09D4 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_2 0x09D5 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_1 0x09D6 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_0 0x09D7 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_4 0x09D8 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_3 0x09D9 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_2 0x09DA +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_1 0x09DB +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_0 0x09DC +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_2 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_1 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_0 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0) // SX128X SPI command variables -//SX128X_CMD_GET_STATUS MSB LSB DESCRIPTION -#define SX128X_STATUS_MODE_STDBY_RC 0b01000000 // 7 5 current chip mode: STDBY_RC -#define SX128X_STATUS_MODE_STDBY_XOSC 0b01100000 // 7 5 STDBY_XOSC -#define SX128X_STATUS_MODE_FS 0b10000000 // 7 5 FS -#define SX128X_STATUS_MODE_RX 0b10100000 // 7 5 Rx -#define SX128X_STATUS_MODE_TX 0b11000000 // 7 5 Tx -#define SX128X_STATUS_CMD_PROCESSED 0b00000100 // 4 2 command status: processing OK -#define SX128X_STATUS_DATA_AVAILABLE 0b00001000 // 4 2 data available -#define SX128X_STATUS_CMD_TIMEOUT 0b00001100 // 4 2 timeout -#define SX128X_STATUS_CMD_ERROR 0b00010000 // 4 2 processing error -#define SX128X_STATUS_CMD_FAILED 0b00010100 // 4 2 failed to execute -#define SX128X_STATUS_TX_DONE 0b00011000 // 4 2 transmission finished -#define SX128X_STATUS_BUSY 0b00000001 // 0 0 chip busy -#define SX128X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed - -//SX128X_CMD_SET_SLEEP -#define SX128X_SLEEP_DATA_BUFFER_FLUSH 0b00000000 // 1 1 data buffer behavior in sleep mode: flush -#define SX128X_SLEEP_DATA_BUFFER_RETAIN 0b00000010 // 1 1 retain -#define SX128X_SLEEP_DATA_RAM_FLUSH 0b00000000 // 0 0 data RAM (configuration) behavior in sleep mode: flush -#define SX128X_SLEEP_DATA_RAM_RETAIN 0b00000001 // 0 0 retain - -//SX128X_CMD_SET_STANDBY -#define SX128X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator -#define SX128X_STANDBY_XOSC 0x01 // 7 0 52 MHz crystal oscillator - -//SX128X_CMD_SET_TX + SX128X_CMD_SET_RX + SX128X_CMD_SET_RX_DUTY_CYCLE -#define SX128X_PERIOD_BASE_15_625_US 0x00 // 7 0 time period step: 15.625 us -#define SX128X_PERIOD_BASE_62_5_US 0x01 // 7 0 62.5 us -#define SX128X_PERIOD_BASE_1_MS 0x02 // 7 0 1 ms -#define SX128X_PERIOD_BASE_4_MS 0x03 // 7 0 4 ms - -//SX128X_CMD_SET_TX -#define SX128X_TX_TIMEOUT_NONE 0x0000 // 15 0 Tx timeout duration: no timeout (Tx single mode) - -//SX128X_CMD_SET_RX -#define SX128X_RX_TIMEOUT_NONE 0x0000 // 15 0 Rx timeout duration: no timeout (Rx single mode) -#define SX128X_RX_TIMEOUT_INF 0xFFFF // 15 0 infinite (Rx continuous mode) - -//SX128X_CMD_SET_PACKET_TYPE -#define SX128X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: (G)FSK -#define SX128X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa -#define SX128X_PACKET_TYPE_RANGING 0x02 // 7 0 ranging engine -#define SX128X_PACKET_TYPE_FLRC 0x03 // 7 0 FLRC -#define SX128X_PACKET_TYPE_BLE 0x04 // 7 0 BLE - -//SX128X_CMD_SET_TX_PARAMS -#define SX128X_PA_RAMP_02_US 0x00 // 7 0 PA ramp time: 2 us -#define SX128X_PA_RAMP_04_US 0x20 // 7 0 4 us -#define SX128X_PA_RAMP_06_US 0x40 // 7 0 6 us -#define SX128X_PA_RAMP_08_US 0x60 // 7 0 8 us -#define SX128X_PA_RAMP_10_US 0x80 // 7 0 10 us -#define SX128X_PA_RAMP_12_US 0xA0 // 7 0 12 us -#define SX128X_PA_RAMP_16_US 0xC0 // 7 0 16 us -#define SX128X_PA_RAMP_20_US 0xE0 // 7 0 20 us - -//SX128X_CMD_SET_CAD_PARAMS -#define SX128X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 -#define SX128X_CAD_ON_2_SYMB 0x20 // 7 0 2 -#define SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 -#define SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 -#define SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 - -//SX128X_CMD_SET_MODULATION_PARAMS -#define SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz -#define SX128X_BLE_GFSK_BR_1_600_BW_2_4 0x28 // 7 0 1.6 Mbps 2.4 MHz -#define SX128X_BLE_GFSK_BR_1_000_BW_2_4 0x4C // 7 0 1.0 Mbps 2.4 MHz -#define SX128X_BLE_GFSK_BR_1_000_BW_1_2 0x45 // 7 0 1.0 Mbps 1.2 MHz -#define SX128X_BLE_GFSK_BR_0_800_BW_2_4 0x70 // 7 0 0.8 Mbps 2.4 MHz -#define SX128X_BLE_GFSK_BR_0_800_BW_1_2 0x69 // 7 0 0.8 Mbps 1.2 MHz -#define SX128X_BLE_GFSK_BR_0_500_BW_1_2 0x8D // 7 0 0.5 Mbps 1.2 MHz -#define SX128X_BLE_GFSK_BR_0_500_BW_0_6 0x86 // 7 0 0.5 Mbps 0.6 MHz -#define SX128X_BLE_GFSK_BR_0_400_BW_1_2 0xB1 // 7 0 0.4 Mbps 1.2 MHz -#define SX128X_BLE_GFSK_BR_0_400_BW_0_6 0xAA // 7 0 0.4 Mbps 0.6 MHz -#define SX128X_BLE_GFSK_BR_0_250_BW_0_6 0xCE // 7 0 0.25 Mbps 0.6 MHz -#define SX128X_BLE_GFSK_BR_0_250_BW_0_3 0xC7 // 7 0 0.25 Mbps 0.3 MHz -#define SX128X_BLE_GFSK_BR_0_125_BW_0_3 0xEF // 7 0 0.125 Mbps 0.3 MHz -#define SX128X_BLE_GFSK_MOD_IND_0_35 0x00 // 7 0 GFSK/BLE modulation index: 0.35 -#define SX128X_BLE_GFSK_MOD_IND_0_50 0x01 // 7 0 0.50 -#define SX128X_BLE_GFSK_MOD_IND_0_75 0x02 // 7 0 0.75 -#define SX128X_BLE_GFSK_MOD_IND_1_00 0x03 // 7 0 1.00 -#define SX128X_BLE_GFSK_MOD_IND_1_25 0x04 // 7 0 1.25 -#define SX128X_BLE_GFSK_MOD_IND_1_50 0x05 // 7 0 1.50 -#define SX128X_BLE_GFSK_MOD_IND_1_75 0x06 // 7 0 1.75 -#define SX128X_BLE_GFSK_MOD_IND_2_00 0x07 // 7 0 2.00 -#define SX128X_BLE_GFSK_MOD_IND_2_25 0x08 // 7 0 2.25 -#define SX128X_BLE_GFSK_MOD_IND_2_50 0x09 // 7 0 2.50 -#define SX128X_BLE_GFSK_MOD_IND_2_75 0x0A // 7 0 2.75 -#define SX128X_BLE_GFSK_MOD_IND_3_00 0x0B // 7 0 3.00 -#define SX128X_BLE_GFSK_MOD_IND_3_25 0x0C // 7 0 3.25 -#define SX128X_BLE_GFSK_MOD_IND_3_50 0x0D // 7 0 3.50 -#define SX128X_BLE_GFSK_MOD_IND_3_75 0x0E // 7 0 3.75 -#define SX128X_BLE_GFSK_MOD_IND_4_00 0x0F // 7 0 4.00 -#define SX128X_BLE_GFSK_BT_OFF 0x00 // 7 0 GFSK Gaussian filter BT product: filter disabled -#define SX128X_BLE_GFSK_BT_1_0 0x10 // 7 0 1.0 -#define SX128X_BLE_GFSK_BT_0_5 0x20 // 7 0 0.5 -#define SX128X_FLRC_BR_1_300_BW_1_2 0x45 // 7 0 FLRC bit rate and bandwidth setting: 1.3 Mbps 1.2 MHz -#define SX128X_FLRC_BR_1_000_BW_1_2 0x69 // 7 0 1.04 Mbps 1.2 MHz -#define SX128X_FLRC_BR_0_650_BW_0_6 0x86 // 7 0 0.65 Mbps 0.6 MHz -#define SX128X_FLRC_BR_0_520_BW_0_6 0xAA // 7 0 0.52 Mbps 0.6 MHz -#define SX128X_FLRC_BR_0_325_BW_0_3 0xC7 // 7 0 0.325 Mbps 0.3 MHz -#define SX128X_FLRC_BR_0_260_BW_0_3 0xEB // 7 0 0.260 Mbps 0.3 MHz -#define SX128X_FLRC_CR_1_2 0x00 // 7 0 FLRC coding rate: 1/2 -#define SX128X_FLRC_CR_3_4 0x02 // 7 0 3/4 -#define SX128X_FLRC_CR_1_0 0x04 // 7 0 1/1 -#define SX128X_FLRC_BT_OFF 0x00 // 7 0 FLRC Gaussian filter BT product: filter disabled -#define SX128X_FLRC_BT_1_0 0x10 // 7 0 1.0 -#define SX128X_FLRC_BT_0_5 0x20 // 7 0 0.5 -#define SX128X_LORA_SF_5 0x50 // 7 0 LoRa spreading factor: 5 -#define SX128X_LORA_SF_6 0x60 // 7 0 6 -#define SX128X_LORA_SF_7 0x70 // 7 0 7 -#define SX128X_LORA_SF_8 0x80 // 7 0 8 -#define SX128X_LORA_SF_9 0x90 // 7 0 9 -#define SX128X_LORA_SF_10 0xA0 // 7 0 10 -#define SX128X_LORA_SF_11 0xB0 // 7 0 11 -#define SX128X_LORA_SF_12 0xC0 // 7 0 12 -#define SX128X_LORA_BW_1625_00 0x0A // 7 0 LoRa bandwidth: 1625.0 kHz -#define SX128X_LORA_BW_812_50 0x18 // 7 0 812.5 kHz -#define SX128X_LORA_BW_406_25 0x26 // 7 0 406.25 kHz -#define SX128X_LORA_BW_203_125 0x34 // 7 0 203.125 kHz -#define SX128X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 -#define SX128X_LORA_CR_4_6 0x02 // 7 0 4/6 -#define SX128X_LORA_CR_4_7 0x03 // 7 0 4/7 -#define SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 -#define SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving -#define SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving -#define SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving - -//SX128X_CMD_SET_PACKET_PARAMS -#define SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none -#define SX128X_GFSK_FLRC_SYNC_WORD_1 0x10 // 7 0 sync word 1 -#define SX128X_GFSK_FLRC_SYNC_WORD_2 0x20 // 7 0 sync word 2 -#define SX128X_GFSK_FLRC_SYNC_WORD_1_2 0x30 // 7 0 sync words 1 and 2 -#define SX128X_GFSK_FLRC_SYNC_WORD_3 0x40 // 7 0 sync word 3 -#define SX128X_GFSK_FLRC_SYNC_WORD_1_3 0x50 // 7 0 sync words 1 and 3 -#define SX128X_GFSK_FLRC_SYNC_WORD_2_3 0x60 // 7 0 sync words 2 and 3 -#define SX128X_GFSK_FLRC_SYNC_WORD_1_2_3 0x70 // 7 0 sync words 1, 2 and 3 -#define SX128X_GFSK_FLRC_PACKET_FIXED 0x00 // 7 0 GFSK/FLRC packet length mode: fixed -#define SX128X_GFSK_FLRC_PACKET_VARIABLE 0x20 // 7 0 variable -#define SX128X_GFSK_FLRC_CRC_OFF 0x00 // 7 0 GFSK/FLRC packet CRC: none -#define SX128X_GFSK_FLRC_CRC_1_BYTE 0x10 // 7 0 1 byte -#define SX128X_GFSK_FLRC_CRC_2_BYTE 0x20 // 7 0 2 bytes -#define SX128X_GFSK_FLRC_CRC_3_BYTE 0x30 // 7 0 3 bytes (FLRC only) -#define SX128X_GFSK_BLE_WHITENING_ON 0x00 // 7 0 GFSK/BLE whitening: enabled -#define SX128X_GFSK_BLE_WHITENING_OFF 0x08 // 7 0 disabled -#define SX128X_BLE_PAYLOAD_LENGTH_MAX_31 0x00 // 7 0 BLE maximum payload length: 31 bytes -#define SX128X_BLE_PAYLOAD_LENGTH_MAX_37 0x20 // 7 0 37 bytes -#define SX128X_BLE_PAYLOAD_LENGTH_TEST 0x40 // 7 0 63 bytes (test mode) -#define SX128X_BLE_PAYLOAD_LENGTH_MAX_255 0x80 // 7 0 255 bytes (Bluetooth 4.2 and above) -#define SX128X_BLE_CRC_OFF 0x00 // 7 0 BLE packet CRC: none -#define SX128X_BLE_CRC_3_BYTE 0x10 // 7 0 3 byte -#define SX128X_BLE_PRBS_9 0x00 // 7 0 BLE test payload contents: PRNG sequence using x^9 + x^5 + x -#define SX128X_BLE_EYELONG 0x04 // 7 0 repeated 0xF0 -#define SX128X_BLE_EYESHORT 0x08 // 7 0 repeated 0xAA -#define SX128X_BLE_PRBS_15 0x0C // 7 0 PRNG sequence using x^15 + x^14 + x^13 + x^12 + x^2 + x + 1 -#define SX128X_BLE_ALL_1 0x10 // 7 0 repeated 0xFF -#define SX128X_BLE_ALL_0 0x14 // 7 0 repeated 0x00 -#define SX128X_BLE_EYELONG_INV 0x18 // 7 0 repeated 0x0F -#define SX128X_BLE_EYESHORT_INV 0x1C // 7 0 repeated 0x55 -#define SX128X_FLRC_SYNC_WORD_OFF 0x00 // 7 0 FLRC sync word: disabled -#define SX128X_FLRC_SYNC_WORD_ON 0x04 // 7 0 enabled -#define SX128X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit -#define SX128X_LORA_HEADER_IMPLICIT 0x80 // 7 0 implicit -#define SX128X_LORA_CRC_OFF 0x00 // 7 0 LoRa packet CRC: disabled -#define SX128X_LORA_CRC_ON 0x20 // 7 0 enabled -#define SX128X_LORA_IQ_STANDARD 0x40 // 7 0 LoRa IQ: standard -#define SX128X_LORA_IQ_INVERTED 0x00 // 7 0 inverted - -//SX128X_CMD_GET_PACKET_STATUS -#define SX128X_PACKET_STATUS_SYNC_ERROR 0b01000000 // 6 6 packet status errors byte: sync word error -#define SX128X_PACKET_STATUS_LENGTH_ERROR 0b00100000 // 5 5 packet length error -#define SX128X_PACKET_STATUS_CRC_ERROR 0b00010000 // 4 4 CRC error -#define SX128X_PACKET_STATUS_ABORT_ERROR 0b00001000 // 3 3 packet reception aborted -#define SX128X_PACKET_STATUS_HEADER_RECEIVED 0b00000100 // 2 2 header received -#define SX128X_PACKET_STATUS_PACKET_RECEIVED 0b00000010 // 1 1 packet received -#define SX128X_PACKET_STATUS_PACKET_CTRL_BUSY 0b00000001 // 0 0 packet controller is busy -#define SX128X_PACKET_STATUS_RX_PID 0b11000000 // 7 6 packet status status byte: PID field of the received packet -#define SX128X_PACKET_STATUS_NO_ACK 0b00100000 // 5 5 NO_ACK field of the received packet -#define SX128X_PACKET_STATUS_RX_PID_ERROR 0b00010000 // 4 4 PID field error -#define SX128X_PACKET_STATUS_PACKET_SENT 0b00000001 // 0 0 packet sent -#define SX128X_PACKET_STATUS_SYNC_DET_ERROR 0b00000000 // 2 0 packet status sync byte: sync word detection error -#define SX128X_PACKET_STATUS_SYNC_DET_1 0b00000001 // 2 0 detected sync word 1 -#define SX128X_PACKET_STATUS_SYNC_DET_2 0b00000010 // 2 0 detected sync word 2 -#define SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 - -//SX128X_CMD_SET_DIO_IRQ_PARAMS -#define SX128X_IRQ_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected -#define SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done -#define SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout -#define SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected -#define SX128X_IRQ_CAD_DONE 0x1000 // 12 12 CAD finished -#define SX128X_IRQ_RANGING_SLAVE_REQ_VALID 0x0800 // 11 11 ranging request valid (slave) -#define SX128X_IRQ_RANGING_MASTER_TIMEOUT 0x0400 // 10 10 ranging timeout (master) -#define SX128X_IRQ_RANGING_MASTER_RES_VALID 0x0200 // 9 9 ranging result valid (master) -#define SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD 0x0100 // 8 8 ranging result valid (master) -#define SX128X_IRQ_RANGING_SLAVE_RESP_DONE 0x0080 // 7 7 ranging response complete (slave) -#define SX128X_IRQ_CRC_ERROR 0x0040 // 6 6 CRC error -#define SX128X_IRQ_HEADER_ERROR 0x0020 // 5 5 header error -#define SX128X_IRQ_HEADER_VALID 0x0010 // 4 4 header valid -#define SX128X_IRQ_SYNC_WORD_ERROR 0x0008 // 3 3 sync word error -#define SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid -#define SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done -#define SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done -#define SX128X_IRQ_NONE 0x0000 // 15 0 none -#define SX128X_IRQ_ALL 0xFFFF // 15 0 all - -//SX128X_CMD_SET_REGULATOR_MODE -#define SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) -#define SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC - -//SX128X_CMD_SET_RANGING_ROLE -#define SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master -#define SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave - -//SX128X_REG_LORA_SYNC_WORD_1 - SX128X_REG_LORA_SYNC_WORD_2 -#define SX128X_SYNC_WORD_PRIVATE 0x12 +//RADIOLIB_SX128X_CMD_GET_STATUS MSB LSB DESCRIPTION +#define RADIOLIB_SX128X_STATUS_MODE_STDBY_RC 0b01000000 // 7 5 current chip mode: STDBY_RC +#define RADIOLIB_SX128X_STATUS_MODE_STDBY_XOSC 0b01100000 // 7 5 STDBY_XOSC +#define RADIOLIB_SX128X_STATUS_MODE_FS 0b10000000 // 7 5 FS +#define RADIOLIB_SX128X_STATUS_MODE_RX 0b10100000 // 7 5 Rx +#define RADIOLIB_SX128X_STATUS_MODE_TX 0b11000000 // 7 5 Tx +#define RADIOLIB_SX128X_STATUS_CMD_PROCESSED 0b00000100 // 4 2 command status: processing OK +#define RADIOLIB_SX128X_STATUS_DATA_AVAILABLE 0b00001000 // 4 2 data available +#define RADIOLIB_SX128X_STATUS_CMD_TIMEOUT 0b00001100 // 4 2 timeout +#define RADIOLIB_SX128X_STATUS_CMD_ERROR 0b00010000 // 4 2 processing error +#define RADIOLIB_SX128X_STATUS_CMD_FAILED 0b00010100 // 4 2 failed to execute +#define RADIOLIB_SX128X_STATUS_TX_DONE 0b00011000 // 4 2 transmission finished +#define RADIOLIB_SX128X_STATUS_BUSY 0b00000001 // 0 0 chip busy +#define RADIOLIB_SX128X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//RADIOLIB_SX128X_CMD_SET_SLEEP +#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH 0b00000000 // 1 1 data buffer behavior in sleep mode: flush +#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN 0b00000010 // 1 1 retain +#define RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH 0b00000000 // 0 0 data RAM (configuration) behavior in sleep mode: flush +#define RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN 0b00000001 // 0 0 retain + +//RADIOLIB_SX128X_CMD_SET_STANDBY +#define RADIOLIB_SX128X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX128X_STANDBY_XOSC 0x01 // 7 0 52 MHz crystal oscillator + +//RADIOLIB_SX128X_CMD_SET_TX + RADIOLIB_SX128X_CMD_SET_RX + RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE +#define RADIOLIB_SX128X_PERIOD_BASE_15_625_US 0x00 // 7 0 time period step: 15.625 us +#define RADIOLIB_SX128X_PERIOD_BASE_62_5_US 0x01 // 7 0 62.5 us +#define RADIOLIB_SX128X_PERIOD_BASE_1_MS 0x02 // 7 0 1 ms +#define RADIOLIB_SX128X_PERIOD_BASE_4_MS 0x03 // 7 0 4 ms + +//RADIOLIB_SX128X_CMD_SET_TX +#define RADIOLIB_SX128X_TX_TIMEOUT_NONE 0x0000 // 15 0 Tx timeout duration: no timeout (Tx single mode) + +//RADIOLIB_SX128X_CMD_SET_RX +#define RADIOLIB_SX128X_RX_TIMEOUT_NONE 0x0000 // 15 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX128X_RX_TIMEOUT_INF 0xFFFF // 15 0 infinite (Rx continuous mode) + +//RADIOLIB_SX128X_CMD_SET_PACKET_TYPE +#define RADIOLIB_SX128X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: (G)FSK +#define RADIOLIB_SX128X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX128X_PACKET_TYPE_RANGING 0x02 // 7 0 ranging engine +#define RADIOLIB_SX128X_PACKET_TYPE_FLRC 0x03 // 7 0 FLRC +#define RADIOLIB_SX128X_PACKET_TYPE_BLE 0x04 // 7 0 BLE + +//RADIOLIB_SX128X_CMD_SET_TX_PARAMS +#define RADIOLIB_SX128X_PA_RAMP_02_US 0x00 // 7 0 PA ramp time: 2 us +#define RADIOLIB_SX128X_PA_RAMP_04_US 0x20 // 7 0 4 us +#define RADIOLIB_SX128X_PA_RAMP_06_US 0x40 // 7 0 6 us +#define RADIOLIB_SX128X_PA_RAMP_08_US 0x60 // 7 0 8 us +#define RADIOLIB_SX128X_PA_RAMP_10_US 0x80 // 7 0 10 us +#define RADIOLIB_SX128X_PA_RAMP_12_US 0xA0 // 7 0 12 us +#define RADIOLIB_SX128X_PA_RAMP_16_US 0xC0 // 7 0 16 us +#define RADIOLIB_SX128X_PA_RAMP_20_US 0xE0 // 7 0 20 us + +//RADIOLIB_SX128X_CMD_SET_CAD_PARAMS +#define RADIOLIB_SX128X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX128X_CAD_ON_2_SYMB 0x20 // 7 0 2 +#define RADIOLIB_SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 +#define RADIOLIB_SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 +#define RADIOLIB_SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 + +//RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4 0x28 // 7 0 1.6 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4 0x4C // 7 0 1.0 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_1_2 0x45 // 7 0 1.0 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4 0x70 // 7 0 0.8 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_1_2 0x69 // 7 0 0.8 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2 0x8D // 7 0 0.5 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_0_6 0x86 // 7 0 0.5 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2 0xB1 // 7 0 0.4 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_0_6 0xAA // 7 0 0.4 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6 0xCE // 7 0 0.25 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_3 0xC7 // 7 0 0.25 Mbps 0.3 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3 0xEF // 7 0 0.125 Mbps 0.3 MHz +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35 0x00 // 7 0 GFSK/BLE modulation index: 0.35 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_50 0x01 // 7 0 0.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_75 0x02 // 7 0 0.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00 0x03 // 7 0 1.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_25 0x04 // 7 0 1.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_50 0x05 // 7 0 1.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_75 0x06 // 7 0 1.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_00 0x07 // 7 0 2.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_25 0x08 // 7 0 2.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_50 0x09 // 7 0 2.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_75 0x0A // 7 0 2.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_00 0x0B // 7 0 3.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_25 0x0C // 7 0 3.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_50 0x0D // 7 0 3.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_75 0x0E // 7 0 3.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00 0x0F // 7 0 4.00 +#define RADIOLIB_SX128X_BLE_GFSK_BT_OFF 0x00 // 7 0 GFSK Gaussian filter BT product: filter disabled +#define RADIOLIB_SX128X_BLE_GFSK_BT_1_0 0x10 // 7 0 1.0 +#define RADIOLIB_SX128X_BLE_GFSK_BT_0_5 0x20 // 7 0 0.5 +#define RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2 0x45 // 7 0 FLRC bit rate and bandwidth setting: 1.3 Mbps 1.2 MHz +#define RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2 0x69 // 7 0 1.04 Mbps 1.2 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6 0x86 // 7 0 0.65 Mbps 0.6 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6 0xAA // 7 0 0.52 Mbps 0.6 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3 0xC7 // 7 0 0.325 Mbps 0.3 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3 0xEB // 7 0 0.260 Mbps 0.3 MHz +#define RADIOLIB_SX128X_FLRC_CR_1_2 0x00 // 7 0 FLRC coding rate: 1/2 +#define RADIOLIB_SX128X_FLRC_CR_3_4 0x02 // 7 0 3/4 +#define RADIOLIB_SX128X_FLRC_CR_1_0 0x04 // 7 0 1/1 +#define RADIOLIB_SX128X_FLRC_BT_OFF 0x00 // 7 0 FLRC Gaussian filter BT product: filter disabled +#define RADIOLIB_SX128X_FLRC_BT_1_0 0x10 // 7 0 1.0 +#define RADIOLIB_SX128X_FLRC_BT_0_5 0x20 // 7 0 0.5 +#define RADIOLIB_SX128X_LORA_SF_5 0x50 // 7 0 LoRa spreading factor: 5 +#define RADIOLIB_SX128X_LORA_SF_6 0x60 // 7 0 6 +#define RADIOLIB_SX128X_LORA_SF_7 0x70 // 7 0 7 +#define RADIOLIB_SX128X_LORA_SF_8 0x80 // 7 0 8 +#define RADIOLIB_SX128X_LORA_SF_9 0x90 // 7 0 9 +#define RADIOLIB_SX128X_LORA_SF_10 0xA0 // 7 0 10 +#define RADIOLIB_SX128X_LORA_SF_11 0xB0 // 7 0 11 +#define RADIOLIB_SX128X_LORA_SF_12 0xC0 // 7 0 12 +#define RADIOLIB_SX128X_LORA_BW_1625_00 0x0A // 7 0 LoRa bandwidth: 1625.0 kHz +#define RADIOLIB_SX128X_LORA_BW_812_50 0x18 // 7 0 812.5 kHz +#define RADIOLIB_SX128X_LORA_BW_406_25 0x26 // 7 0 406.25 kHz +#define RADIOLIB_SX128X_LORA_BW_203_125 0x34 // 7 0 203.125 kHz +#define RADIOLIB_SX128X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX128X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX128X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving + +//RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1 0x10 // 7 0 sync word 1 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2 0x20 // 7 0 sync word 2 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2 0x30 // 7 0 sync words 1 and 2 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_3 0x40 // 7 0 sync word 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_3 0x50 // 7 0 sync words 1 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2_3 0x60 // 7 0 sync words 2 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2_3 0x70 // 7 0 sync words 1, 2 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED 0x00 // 7 0 GFSK/FLRC packet length mode: fixed +#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE 0x20 // 7 0 variable +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_OFF 0x00 // 7 0 GFSK/FLRC packet CRC: none +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_1_BYTE 0x10 // 7 0 1 byte +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE 0x20 // 7 0 2 bytes +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_3_BYTE 0x30 // 7 0 3 bytes (FLRC only) +#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON 0x00 // 7 0 GFSK/BLE whitening: enabled +#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF 0x08 // 7 0 disabled +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_31 0x00 // 7 0 BLE maximum payload length: 31 bytes +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_37 0x20 // 7 0 37 bytes +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_TEST 0x40 // 7 0 63 bytes (test mode) +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_255 0x80 // 7 0 255 bytes (Bluetooth 4.2 and above) +#define RADIOLIB_SX128X_BLE_CRC_OFF 0x00 // 7 0 BLE packet CRC: none +#define RADIOLIB_SX128X_BLE_CRC_3_BYTE 0x10 // 7 0 3 byte +#define RADIOLIB_SX128X_BLE_PRBS_9 0x00 // 7 0 BLE test payload contents: PRNG sequence using x^9 + x^5 + x +#define RADIOLIB_SX128X_BLE_EYELONG 0x04 // 7 0 repeated 0xF0 +#define RADIOLIB_SX128X_BLE_EYESHORT 0x08 // 7 0 repeated 0xAA +#define RADIOLIB_SX128X_BLE_PRBS_15 0x0C // 7 0 PRNG sequence using x^15 + x^14 + x^13 + x^12 + x^2 + x + 1 +#define RADIOLIB_SX128X_BLE_ALL_1 0x10 // 7 0 repeated 0xFF +#define RADIOLIB_SX128X_BLE_ALL_0 0x14 // 7 0 repeated 0x00 +#define RADIOLIB_SX128X_BLE_EYELONG_INV 0x18 // 7 0 repeated 0x0F +#define RADIOLIB_SX128X_BLE_EYESHORT_INV 0x1C // 7 0 repeated 0x55 +#define RADIOLIB_SX128X_FLRC_SYNC_WORD_OFF 0x00 // 7 0 FLRC sync word: disabled +#define RADIOLIB_SX128X_FLRC_SYNC_WORD_ON 0x04 // 7 0 enabled +#define RADIOLIB_SX128X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX128X_LORA_HEADER_IMPLICIT 0x80 // 7 0 implicit +#define RADIOLIB_SX128X_LORA_CRC_OFF 0x00 // 7 0 LoRa packet CRC: disabled +#define RADIOLIB_SX128X_LORA_CRC_ON 0x20 // 7 0 enabled +#define RADIOLIB_SX128X_LORA_IQ_STANDARD 0x40 // 7 0 LoRa IQ: standard +#define RADIOLIB_SX128X_LORA_IQ_INVERTED 0x00 // 7 0 inverted + +//RADIOLIB_SX128X_CMD_GET_PACKET_STATUS +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_ERROR 0b01000000 // 6 6 packet status errors byte: sync word error +#define RADIOLIB_SX128X_PACKET_STATUS_LENGTH_ERROR 0b00100000 // 5 5 packet length error +#define RADIOLIB_SX128X_PACKET_STATUS_CRC_ERROR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX128X_PACKET_STATUS_ABORT_ERROR 0b00001000 // 3 3 packet reception aborted +#define RADIOLIB_SX128X_PACKET_STATUS_HEADER_RECEIVED 0b00000100 // 2 2 header received +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_RECEIVED 0b00000010 // 1 1 packet received +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_CTRL_BUSY 0b00000001 // 0 0 packet controller is busy +#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID 0b11000000 // 7 6 packet status status byte: PID field of the received packet +#define RADIOLIB_SX128X_PACKET_STATUS_NO_ACK 0b00100000 // 5 5 NO_ACK field of the received packet +#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID_ERROR 0b00010000 // 4 4 PID field error +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_SENT 0b00000001 // 0 0 packet sent +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_ERROR 0b00000000 // 2 0 packet status sync byte: sync word detection error +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_1 0b00000001 // 2 0 detected sync word 1 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_2 0b00000010 // 2 0 detected sync word 2 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 + +//RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected +#define RADIOLIB_SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done +#define RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout +#define RADIOLIB_SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected +#define RADIOLIB_SX128X_IRQ_CAD_DONE 0x1000 // 12 12 CAD finished +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_VALID 0x0800 // 11 11 ranging request valid (slave) +#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_TIMEOUT 0x0400 // 10 10 ranging timeout (master) +#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID 0x0200 // 9 9 ranging result valid (master) +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD 0x0100 // 8 8 ranging result valid (master) +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE 0x0080 // 7 7 ranging response complete (slave) +#define RADIOLIB_SX128X_IRQ_CRC_ERROR 0x0040 // 6 6 CRC error +#define RADIOLIB_SX128X_IRQ_HEADER_ERROR 0x0020 // 5 5 header error +#define RADIOLIB_SX128X_IRQ_HEADER_VALID 0x0010 // 4 4 header valid +#define RADIOLIB_SX128X_IRQ_SYNC_WORD_ERROR 0x0008 // 3 3 sync word error +#define RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid +#define RADIOLIB_SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done +#define RADIOLIB_SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done +#define RADIOLIB_SX128X_IRQ_NONE 0x0000 // 15 0 none +#define RADIOLIB_SX128X_IRQ_ALL 0xFFFF // 15 0 all + +//RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE +#define RADIOLIB_SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + +//RADIOLIB_SX128X_CMD_SET_RANGING_ROLE +#define RADIOLIB_SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master +#define RADIOLIB_SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave + +//RADIOLIB_SX128X_REG_LORA_SYNC_WORD_1 - RADIOLIB_SX128X_REG_LORA_SYNC_WORD_2 +#define RADIOLIB_SX128X_SYNC_WORD_PRIVATE 0x12 /*! \class SX128x @@ -362,6 +362,8 @@ class SX128x: public PhysicalLayer { */ SX128x(Module* mod); + Module* getMod(); + // basic methods /*! @@ -375,7 +377,7 @@ class SX128x: public PhysicalLayer { \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to SX128X_SYNC_WORD_PRIVATE (0x12). + \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX128X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. @@ -383,7 +385,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 2400.0, float bw = 812.5, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX128X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 12); + int16_t begin(float freq = 2400.0, float bw = 812.5, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX128X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 12); /*! \brief Initialization method for GFSK modem. @@ -485,7 +487,7 @@ class SX128x: public PhysicalLayer { /*! \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX128x series does not support direct mode reception. - Will always return ERR_UNKNOWN. + Will always return RADIOLIB_ERR_UNKNOWN. \returns \ref status_codes */ @@ -517,7 +519,7 @@ class SX128x: public PhysicalLayer { /*! \brief Sets the module to standby mode. - \param mode Oscillator to be used in standby mode. Can be set to SX128X_STANDBY_RC (13 MHz RC oscillator) or SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). \returns \ref status_codes */ @@ -554,11 +556,11 @@ class SX128x: public PhysicalLayer { /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). \returns \ref status_codes */ - int16_t startReceive(uint16_t timeout = SX128X_RX_TIMEOUT_INF); + int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF); /*! \brief Reads data received after calling startReceive method. @@ -818,20 +820,20 @@ class SX128x: public PhysicalLayer { int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t readBuffer(uint8_t* data, uint8_t numBytes); - int16_t setTx(uint16_t periodBaseCount = SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = SX128X_PERIOD_BASE_15_625_US); - int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = SX128X_PERIOD_BASE_15_625_US); + int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); + int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); int16_t setCad(); uint8_t getPacketType(); int16_t setRfFrequency(uint32_t frf); - int16_t setTxParams(uint8_t power, uint8_t rampTime = SX128X_PA_RAMP_10_US); + int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3); - int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen = 0xFF, uint8_t headerType = SX128X_GFSK_FLRC_PACKET_VARIABLE); + int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen = 0xFF, uint8_t headerType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE); int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening); - int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ = SX128X_LORA_IQ_STANDARD); - int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX128X_IRQ_NONE, uint16_t dio3Mask = SX128X_IRQ_NONE); + int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD); + int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX128X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX128X_IRQ_NONE); uint16_t getIrqStatus(); - int16_t clearIrqStatus(uint16_t clearIrqParams = SX128X_IRQ_ALL); + int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX128X_IRQ_ALL); int16_t setRangingRole(uint8_t role); int16_t setPacketType(uint8_t type); From eb9903f1838bd4a10ed5b3ce21a9e885a477fe22 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:42:52 +0100 Subject: [PATCH 0051/1848] [Si443x] Update to 5.0.0 --- .../Si443x/Si443x_Receive/Si443x_Receive.ino | 8 +- .../Si443x_Receive_Interrupt.ino | 8 +- .../Si443x_Settings/Si443x_Settings.ino | 18 +- .../Si443x_Transmit/Si443x_Transmit.ino | 8 +- .../Si443x_Transmit_Interrupt.ino | 6 +- src/modules/Si443x/Si4430.cpp | 6 +- src/modules/Si443x/Si4431.cpp | 4 +- src/modules/Si443x/Si4432.cpp | 6 +- src/modules/Si443x/Si443x.cpp | 284 ++--- src/modules/Si443x/Si443x.h | 1068 +++++++++-------- 10 files changed, 711 insertions(+), 705 deletions(-) diff --git a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino b/examples/Si443x/Si443x_Receive/Si443x_Receive.ino index 846e46e306..b5ab2485f9 100644 --- a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino +++ b/examples/Si443x/Si443x_Receive/Si443x_Receive.ino @@ -37,7 +37,7 @@ void setup() { // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -59,7 +59,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -67,11 +67,11 @@ void loop() { Serial.print(F("[Si4432] Data:\t\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index e890b08d62..16c1af41ea 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -33,7 +33,7 @@ void setup() { // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -48,7 +48,7 @@ void setup() { // start listening for packets Serial.print(F("[Si4432] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -106,7 +106,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[Si4432] Received packet!")); @@ -114,7 +114,7 @@ void loop() { Serial.print(F("[Si4432] Data:\t\t\t")); Serial.println(str); - } else if (state == ERR_CRC_MISMATCH) { + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino index cd42050528..9823e97d0f 100644 --- a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino +++ b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino @@ -43,7 +43,7 @@ void setup() { // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); int state = radio1.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -60,7 +60,7 @@ void setup() { // output power: 17 dBm // preamble length: 32 bits state = radio2.begin(868.0, 200.0, 60.0, 335.5, 17, 32); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -72,17 +72,17 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("[Si4432] Selected frequency is invalid for this module!")); while (true); } // set bit rate to 100.0 kbps state = radio1.setBitRate(100.0); - if (state == ERR_INVALID_BIT_RATE) { + if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { Serial.println(F("[Si4432] Selected bit rate is invalid for this module!")); while (true); - } else if (state == ERR_INVALID_BIT_RATE_BW_RATIO) { + } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[Si4432] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[Si4432] Increase receiver bandwidth to set this bit rate.")); while (true); @@ -90,19 +90,19 @@ void setup() { // set receiver bandwidth to 284.8 kHz state = radio1.setRxBandwidth(284.8); - if (state == ERR_INVALID_RX_BANDWIDTH) { + if (state == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[Si4432] Selected receiver bandwidth is invalid for this module!")); while (true); } // set frequency deviation to 10.0 kHz - if (radio1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[Si4432] Selected frequency deviation is invalid for this module!")); while (true); } // set output power to 2 dBm - if (radio1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[Si4432] Selected output power is invalid for this module!")); while (true); } @@ -110,7 +110,7 @@ void setup() { // up to 4 bytes can be set as sync word // set sync word to 0x01234567 uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; - if (radio1.setSyncWord(syncWord, 4) == ERR_INVALID_SYNC_WORD) { + if (radio1.setSyncWord(syncWord, 4) == RADIOLIB_ERR_INVALID_SYNC_WORD) { Serial.println(F("[Si4432] Selected sync word is invalid for this module!")); while (true); } diff --git a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino b/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino index ca267624f3..2eddf96eeb 100644 --- a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino +++ b/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino @@ -35,7 +35,7 @@ void setup() { // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -60,15 +60,15 @@ void loop() { int state = radio.transmit(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F(" success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F(" too long!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { // timeout occured while transmitting packet Serial.println(F(" timeout!")); diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 82c5364dce..4703233a7f 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -30,7 +30,7 @@ Si4432 radio = new Module(10, 2, 9); //Si4432 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -38,7 +38,7 @@ void setup() { // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); int state = radio.begin(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -95,7 +95,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index 9114ac4bfc..d6f40326fb 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -22,17 +22,17 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po } int16_t Si4430::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency return(Si443x::setFrequencyRaw(freq)); } int16_t Si4430::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -8, 13, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 6f40616517..832ed4324b 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -22,10 +22,10 @@ int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t po } int16_t Si4431::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -8, 13, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index aef6dc537d..06921add6d 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -22,17 +22,17 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po } int16_t Si4432::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency return(Si443x::setFrequencyRaw(freq)); } int16_t Si4432::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -1, 20, ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -1, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 69111f4a8b..5c48561363 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -1,28 +1,32 @@ #include "Si443x.h" #if !defined(RADIOLIB_EXCLUDE_SI443X) -Si443x::Si443x(Module* mod) : PhysicalLayer(SI443X_FREQUENCY_STEP_SIZE, SI443X_MAX_PACKET_LENGTH) { +Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { _mod = mod; } +Module* Si443x::getMod() { + return(_mod); +} + int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { // set module properties - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), LOW); // try to find the Si443x chip if(!Si443x::findChip()) { RADIOLIB_DEBUG_PRINTLN(F("No Si443x found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { RADIOLIB_DEBUG_PRINTLN(F("M\tSi443x")); } // reset the device - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_SOFTWARE_RESET); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET); // clear POR interrupt clearIRQFlags(); @@ -61,11 +65,11 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) } void Si443x::reset() { - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), HIGH); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), LOW); - Module::delay(100); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), LOW); + _mod->delay(100); } int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -77,13 +81,13 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = Module::micros(); - while(Module::digitalRead(_mod->getIrq())) { - Module::yield(); - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); + if(_mod->micros() - start > timeout) { standby(); clearIRQFlags(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -98,19 +102,19 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t Si443x::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(SI443X_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = Module::micros(); - while(Module::digitalRead(_mod->getIrq())) { - if(Module::micros() - start > timeout) { + uint32_t start = _mod->micros(); + while(_mod->digitalRead(_mod->getIrq())) { + if(_mod->micros() - start > timeout) { standby(); clearIRQFlags(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -123,13 +127,13 @@ int16_t Si443x::sleep() { _mod->setRfSwitchState(LOW, LOW); // disable wakeup timer interrupt - int16_t state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, 0x00); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, 0x00); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); RADIOLIB_ASSERT(state); // enable wakeup timer to set mode to sleep - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_ENABLE_WAKEUP_TIMER); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER); return(state); } @@ -138,7 +142,7 @@ int16_t Si443x::standby() { // set RF switch (if present) _mod->setRfSwitchState(LOW, LOW); - return(_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_XTAL_ON, 7, 0, 10)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_XTAL_ON, 7, 0, 10)); } int16_t Si443x::transmitDirect(uint32_t frf) { @@ -152,10 +156,10 @@ int16_t Si443x::transmitDirect(uint32_t frf) { float newFreq = frf / 6400.0; // check high/low band - uint8_t bandSelect = SI443X_BAND_SELECT_LOW; + uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; uint8_t freqBand = (newFreq / 10) - 24; if(newFreq >= 480.0) { - bandSelect = SI443X_BAND_SELECT_HIGH; + bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; freqBand = (newFreq / 20) - 24; } @@ -163,15 +167,15 @@ int16_t Si443x::transmitDirect(uint32_t frf) { uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; // update registers - _mod->SPIwriteRegister(SI443X_REG_FREQUENCY_BAND_SELECT, SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); - _mod->SPIwriteRegister(SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); - _mod->SPIwriteRegister(SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); // start direct transmission directMode(); - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON | SI443X_XTAL_ON); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } // activate direct mode @@ -179,7 +183,7 @@ int16_t Si443x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON | SI443X_XTAL_ON); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } @@ -192,29 +196,29 @@ int16_t Si443x::receiveDirect() { RADIOLIB_ASSERT(state); // start receiving - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON | SI443X_XTAL_ON); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } int16_t Si443x::packetMode() { - int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_FSK, 1, 0); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); RADIOLIB_ASSERT(state); - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); } void Si443x::setIrqAction(void (*func)(void)) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); } void Si443x::clearIrqAction() { - Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length - if(len > SI443X_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set mode to standby @@ -222,31 +226,31 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // clear Tx FIFO - _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_RESET, 0, 0); - _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_CLEAR, 0, 0); + _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_RESET, 0, 0); + _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0); // clear interrupt flags clearIRQFlags(); // set packet length /// \todo variable packet length - _mod->SPIwriteRegister(SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); /// \todo use header as address field? (void)addr; // write packet to FIFO - _mod->SPIwriteRegisterBurst(SI443X_REG_FIFO_ACCESS, data, len); + _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); // set interrupt mapping - _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_PACKET_SENT_ENABLED); - _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_PACKET_SENT_ENABLED); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // set mode to transmit - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON | SI443X_XTAL_ON); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } @@ -257,8 +261,8 @@ int16_t Si443x::startReceive() { RADIOLIB_ASSERT(state); // clear Rx FIFO - _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_RESET, 1, 1); - _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_CLEAR, 1, 1); + _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_RESET, 1, 1); + _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1); // clear interrupt flags clearIRQFlags(); @@ -267,11 +271,11 @@ int16_t Si443x::startReceive() { _mod->setRfSwitchState(HIGH, LOW); // set interrupt mapping - _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_VALID_PACKET_RECEIVED_ENABLED | SI443X_CRC_ERROR_ENABLED); - _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // set mode to receive - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON | SI443X_XTAL_ON); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } @@ -282,12 +286,12 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { // get packet length size_t length = len; - if(len == SI443X_MAX_PACKET_LENGTH) { + if(len == RADIOLIB_SI443X_MAX_PACKET_LENGTH) { length = getPacketLength(); } // read packet data - _mod->SPIreadRegisterBurst(SI443X_REG_FIFO_ACCESS, length, data); + _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, length, data); // clear internal flag so getPacketLength can return the new packet length _packetLengthQueried = false; @@ -299,18 +303,18 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { // clear interrupt flags clearIRQFlags(); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t Si443x::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, RADIOLIB_ERR_INVALID_BIT_RATE); // check high data rate - uint8_t dataRateMode = SI443X_LOW_DATA_RATE_MODE; + uint8_t dataRateMode = RADIOLIB_SI443X_LOW_DATA_RATE_MODE; uint8_t exp = 21; if(br >= 30.0) { // bit rate above 30 kbps - dataRateMode = SI443X_HIGH_DATA_RATE_MODE; + dataRateMode = RADIOLIB_SI443X_HIGH_DATA_RATE_MODE; exp = 16; } @@ -318,11 +322,11 @@ int16_t Si443x::setBitRate(float br) { uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0; // update registers - int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); - _mod->SPIwriteRegister(SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); - _mod->SPIwriteRegister(SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { _br = br; } RADIOLIB_ASSERT(state); @@ -340,16 +344,16 @@ int16_t Si443x::setFrequencyDeviation(float freqDev) { newFreqDev = 0.625; } - RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // calculate raw frequency deviation value uint16_t fdev = (uint16_t)(newFreqDev / 0.625); // update registers - int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); - _mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { _freqDev = newFreqDev; } @@ -357,12 +361,12 @@ int16_t Si443x::setFrequencyDeviation(float freqDev) { } int16_t Si443x::setRxBandwidth(float rxBw) { - RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // decide which approximation to use for decimation rate and filter tap calculation - uint8_t bypass = SI443X_BYPASS_DEC_BY_3_OFF; - uint8_t decRate = SI443X_IF_FILTER_DEC_RATE; - uint8_t filterSet = SI443X_IF_FILTER_COEFF_SET; + uint8_t bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF; + uint8_t decRate = RADIOLIB_SI443X_IF_FILTER_DEC_RATE; + uint8_t filterSet = RADIOLIB_SI443X_IF_FILTER_COEFF_SET; // this is the "well-behaved" section - can be linearly approximated if((rxBw >= 2.6) && (rxBw <= 4.5)) { @@ -387,74 +391,74 @@ int16_t Si443x::setRxBandwidth(float rxBw) { // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess /// \todo float tolerance equality as macro? } else if(fabs(rxBw - 142.8) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 4; } else if(fabs(rxBw - 167.8) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 5; } else if(fabs(rxBw - 181.1) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 6; } else if(fabs(rxBw - 191.5) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 15; } else if(fabs(rxBw - 225.1) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 1; } else if(fabs(rxBw - 248.8) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 2; } else if(fabs(rxBw - 269.3) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 3; } else if(fabs(rxBw - 284.8) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 4; } else if(fabs(rxBw -335.5) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 8; } else if(fabs(rxBw - 391.8) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 9; } else if(fabs(rxBw - 420.2) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 10; } else if(fabs(rxBw - 468.4) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 11; } else if(fabs(rxBw - 518.8) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 12; } else if(fabs(rxBw - 577.0) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 13; } else if(fabs(rxBw - 620.7) <= 0.001) { - bypass = SI443X_BYPASS_DEC_BY_3_ON; + bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 14; } else { - return(ERR_INVALID_RX_BANDWIDTH); + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } // shift decimation rate bits decRate <<= 4; // update register - int16_t state = _mod->SPIsetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); RADIOLIB_ASSERT(state); // update clock recovery @@ -464,18 +468,18 @@ int16_t Si443x::setRxBandwidth(float rxBw) { } int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { - RADIOLIB_CHECK_RANGE(len, 1, 4, ERR_INVALID_SYNC_WORD); + RADIOLIB_CHECK_RANGE(len, 1, 4, RADIOLIB_ERR_INVALID_SYNC_WORD); // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); // set sync word length - state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); RADIOLIB_ASSERT(state); // set sync word bytes - _mod->SPIwriteRegisterBurst(SI443X_REG_SYNC_WORD_3, syncWord, len); + _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_SYNC_WORD_3, syncWord, len); return(state); } @@ -483,23 +487,23 @@ int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { int16_t Si443x::setPreambleLength(uint8_t preambleLen) { // Si443x configures preamble length in 4-bit nibbles if(preambleLen % 4 != 0) { - return(ERR_INVALID_PREAMBLE_LENGTH); + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } // set default preamble length uint8_t preLenNibbles = preambleLen / 4; - int16_t state = _mod->SPIsetRegValue(SI443X_REG_PREAMBLE_LENGTH, preLenNibbles); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_LENGTH, preLenNibbles); RADIOLIB_ASSERT(state); // set default preamble detection threshold to 5/8 of preamble length (in units of 4 bits) uint8_t preThreshold = 5*preLenNibbles / 8; - return(_mod->SPIsetRegValue(SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 3, 7, 3)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 3, 7, 3)); } size_t Si443x::getPacketLength(bool update) { /// \todo variable length mode if(!_packetLengthQueried && update) { - _packetLength = _mod->SPIreadRegister(SI443X_REG_RECEIVED_PACKET_LENGTH); + _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); _packetLengthQueried = true; } @@ -515,13 +519,13 @@ int16_t Si443x::setEncoding(uint8_t encoding) { /// \todo - add inverted Manchester? switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_OFF, 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_ENCODING_MANCHESTER: - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_ON | SI443X_WHITENING_OFF, 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_ENCODING_WHITENING: - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_ON, 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: - return(ERR_INVALID_ENCODING); + return(RADIOLIB_ERR_INVALID_ENCODING); } } @@ -533,14 +537,14 @@ int16_t Si443x::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_OFF, 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_SHAPING_0_3: case RADIOLIB_SHAPING_0_5: case RADIOLIB_SHAPING_1_0: /// \todo implement fiter configuration - docs claim this should be possible, but seems undocumented - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_ON, 2, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: - return(ERR_INVALID_ENCODING); + return(RADIOLIB_ERR_INVALID_ENCODING); } } @@ -550,15 +554,15 @@ void Si443x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { uint8_t Si443x::randomByte() { // set mode to Rx - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON | SI443X_XTAL_ON); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); // wait a bit for the RSSI reading to stabilise - Module::delay(10); + _mod->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { - randByte |= ((_mod->SPIreadRegister(SI443X_REG_RSSI) & 0x01) << i); + randByte |= ((_mod->SPIreadRegister(RADIOLIB_SI443X_REG_RSSI) & 0x01) << i); } // set mode to standby @@ -568,7 +572,7 @@ uint8_t Si443x::randomByte() { } int16_t Si443x::getChipVersion() { - return(_mod->SPIgetRegValue(SI443X_REG_DEVICE_VERSION)); + return(_mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); } void Si443x::setDirectAction(void (*func)(void)) { @@ -585,12 +589,12 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { RADIOLIB_ASSERT(state); // check high/low band - uint8_t bandSelect = SI443X_BAND_SELECT_LOW; + uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; uint8_t freqBand = (newFreq / 10) - 24; uint8_t afcLimiter = 80; _freq = newFreq; if(newFreq >= 480.0) { - bandSelect = SI443X_BAND_SELECT_HIGH; + bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; freqBand = (newFreq / 20) - 24; afcLimiter = 40; } @@ -599,10 +603,10 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; // update registers - state = _mod->SPIsetRegValue(SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); - state |= _mod->SPIsetRegValue(SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); - state |= _mod->SPIsetRegValue(SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); - state |= _mod->SPIsetRegValue(SI443X_REG_AFC_LIMITER, afcLimiter); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AFC_LIMITER, afcLimiter); return(state); } @@ -615,22 +619,22 @@ bool Si443x::findChip() { reset(); // check version register - uint8_t version = _mod->SPIreadRegister(SI443X_REG_DEVICE_VERSION); - if(version == SI443X_DEVICE_VERSION) { + uint8_t version = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_DEVICE_VERSION); + if(version == RADIOLIB_SI443X_DEVICE_VERSION) { flagFound = true; } else { - #ifdef RADIOLIB_DEBUG + #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINT(F("Si443x not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SI443X_REG_DEVICE_VERSION == ")); + RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == ")); char buffHex[5]; sprintf(buffHex, "0x%02X", version); RADIOLIB_DEBUG_PRINT(buffHex); RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); - RADIOLIB_DEBUG_PRINTLN(SI443X_DEVICE_VERSION, HEX); + RADIOLIB_DEBUG_PRINTLN(RADIOLIB_SI443X_DEVICE_VERSION, HEX); #endif - Module::delay(10); + _mod->delay(10); i++; } } @@ -640,7 +644,7 @@ bool Si443x::findChip() { void Si443x::clearIRQFlags() { uint8_t buff[2]; - _mod->SPIreadRegisterBurst(SI443X_REG_INTERRUPT_STATUS_1, 2, buff); + _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); } int16_t Si443x::config() { @@ -649,22 +653,22 @@ int16_t Si443x::config() { RADIOLIB_ASSERT(state); // disable POR and chip ready interrupts - _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // enable AGC - state = _mod->SPIsetRegValue(SI443X_REG_AGC_OVERRIDE_1, SI443X_AGC_GAIN_INCREASE_ON | SI443X_AGC_ON, 6, 5); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AGC_OVERRIDE_1, RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON | RADIOLIB_SI443X_AGC_ON, 6, 5); RADIOLIB_ASSERT(state); // disable packet header - state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, SI443X_SYNC_WORD_TIMEOUT_OFF | SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF | RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); RADIOLIB_ASSERT(state); // set antenna switching - _mod->SPIsetRegValue(SI443X_REG_GPIO0_CONFIG, SI443X_GPIOX_TX_STATE_OUT, 4, 0); - _mod->SPIsetRegValue(SI443X_REG_GPIO1_CONFIG, SI443X_GPIOX_RX_STATE_OUT, 4, 0); + _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO0_CONFIG, RADIOLIB_SI443X_GPIOX_TX_STATE_OUT, 4, 0); + _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_RX_STATE_OUT, 4, 0); // disable packet header checking - state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_1, SI443X_BROADCAST_ADDR_CHECK_NONE | SI443X_RECEIVED_HEADER_CHECK_NONE); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_1, RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE | RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE); RADIOLIB_ASSERT(state); return(state); @@ -672,9 +676,9 @@ int16_t Si443x::config() { int16_t Si443x::updateClockRecovery() { // get the parameters - uint8_t bypass = _mod->SPIgetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; - uint8_t decRate = _mod->SPIgetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; - uint8_t manch = _mod->SPIgetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; + uint8_t bypass = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; + uint8_t decRate = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; + uint8_t manch = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; // calculate oversampling ratio, NCO offset and clock recovery gain int8_t ndecExp = (int8_t)decRate - 3; @@ -707,39 +711,39 @@ int16_t Si443x::updateClockRecovery() { RADIOLIB_DEBUG_PRINTLN(crGain, HEX); // update oversampling ratio - int16_t state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); RADIOLIB_ASSERT(state); // update NCO offset - state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); RADIOLIB_ASSERT(state); // update clock recovery loop gain - state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); RADIOLIB_ASSERT(state); return(state); } int16_t Si443x::directMode() { - int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_GPIO, 5, 4); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO, 5, 4); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_GPIO1_CONFIG, SI443X_GPIOX_TX_RX_DATA_CLK_OUT, 4, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT, 4, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_GPIO2_CONFIG, SI443X_GPIOX_TX_DATA_IN, 4, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO2_CONFIG, RADIOLIB_SI443X_GPIOX_TX_DATA_IN, 4, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_FSK, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); return(state); } diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index cc9cf90573..1072e289ff 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -10,540 +10,540 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // Si443x physical layer properties -#define SI443X_FREQUENCY_STEP_SIZE 156.25 -#define SI443X_MAX_PACKET_LENGTH 64 +#define RADIOLIB_SI443X_FREQUENCY_STEP_SIZE 156.25 +#define RADIOLIB_SI443X_MAX_PACKET_LENGTH 64 // Si443x series common registers -#define SI443X_REG_DEVICE_TYPE 0x00 -#define SI443X_REG_DEVICE_VERSION 0x01 -#define SI443X_REG_DEVICE_STATUS 0x02 -#define SI443X_REG_INTERRUPT_STATUS_1 0x03 -#define SI443X_REG_INTERRUPT_STATUS_2 0x04 -#define SI443X_REG_INTERRUPT_ENABLE_1 0x05 -#define SI443X_REG_INTERRUPT_ENABLE_2 0x06 -#define SI443X_REG_OP_FUNC_CONTROL_1 0x07 -#define SI443X_REG_OP_FUNC_CONTROL_2 0x08 -#define SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09 -#define SI443X_REG_MCU_OUTPUT_CLOCK 0x0A -#define SI443X_REG_GPIO0_CONFIG 0x0B -#define SI443X_REG_GPIO1_CONFIG 0x0C -#define SI443X_REG_GPIO2_CONFIG 0x0D -#define SI443X_REG_IO_PORT_CONFIG 0x0E -#define SI443X_REG_ADC_CONFIG 0x0F -#define SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10 -#define SI443X_REG_ADC_VALUE 0x11 -#define SI443X_REG_TEMP_SENSOR_CONTROL 0x12 -#define SI443X_REG_TEMP_VALUE_OFFSET 0x13 -#define SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14 -#define SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15 -#define SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16 -#define SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17 -#define SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18 -#define SI443X_REG_LOW_DC_MODE_DURATION 0x19 -#define SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A -#define SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B -#define SI443X_REG_IF_FILTER_BANDWIDTH 0x1C -#define SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D -#define SI443X_REG_AFC_TIMING_CONTROL 0x1E -#define SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F -#define SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20 -#define SI443X_REG_CLOCK_REC_OFFSET_2 0x21 -#define SI443X_REG_CLOCK_REC_OFFSET_1 0x22 -#define SI443X_REG_CLOCK_REC_OFFSET_0 0x23 -#define SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24 -#define SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25 -#define SI443X_REG_RSSI 0x26 -#define SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27 -#define SI443X_REG_ANTENNA_DIVERSITY_1 0x28 -#define SI443X_REG_ANTENNA_DIVERSITY_2 0x29 -#define SI443X_REG_AFC_LIMITER 0x2A -#define SI443X_REG_AFC_CORRECTION 0x2B -#define SI443X_REG_OOK_COUNTER_1 0x2C -#define SI443X_REG_OOK_COUNTER_2 0x2D -#define SI443X_REG_SLICER_PEAK_HOLD 0x2E -#define SI443X_REG_DATA_ACCESS_CONTROL 0x30 -#define SI443X_REG_EZMAC_STATUS 0x31 -#define SI443X_REG_HEADER_CONTROL_1 0x32 -#define SI443X_REG_HEADER_CONTROL_2 0x33 -#define SI443X_REG_PREAMBLE_LENGTH 0x34 -#define SI443X_REG_PREAMBLE_DET_CONTROL 0x35 -#define SI443X_REG_SYNC_WORD_3 0x36 -#define SI443X_REG_SYNC_WORD_2 0x37 -#define SI443X_REG_SYNC_WORD_1 0x38 -#define SI443X_REG_SYNC_WORD_0 0x39 -#define SI443X_REG_TRANSMIT_HEADER_3 0x3A -#define SI443X_REG_TRANSMIT_HEADER_2 0x3B -#define SI443X_REG_TRANSMIT_HEADER_1 0x3C -#define SI443X_REG_TRANSMIT_HEADER_0 0x3D -#define SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E -#define SI443X_REG_CHECK_HEADER_3 0x3F -#define SI443X_REG_CHECK_HEADER_2 0x40 -#define SI443X_REG_CHECK_HEADER_1 0x41 -#define SI443X_REG_CHECK_HEADER_0 0x42 -#define SI443X_REG_HEADER_ENABLE_3 0x43 -#define SI443X_REG_HEADER_ENABLE_2 0x44 -#define SI443X_REG_HEADER_ENABLE_1 0x45 -#define SI443X_REG_HEADER_ENABLE_0 0x46 -#define SI443X_REG_RECEIVED_HEADER_3 0x47 -#define SI443X_REG_RECEIVED_HEADER_2 0x48 -#define SI443X_REG_RECEIVED_HEADER_1 0x49 -#define SI443X_REG_RECEIVED_HEADER_0 0x4A -#define SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B -#define SI443X_REG_ADC8_CONTROL 0x4F -#define SI443X_REG_CHANNEL_FILTER_COEFF 0x60 -#define SI443X_REG_XOSC_CONTROL_TEST 0x62 -#define SI443X_REG_AGC_OVERRIDE_1 0x69 -#define SI443X_REG_TX_POWER 0x6D -#define SI443X_REG_TX_DATA_RATE_1 0x6E -#define SI443X_REG_TX_DATA_RATE_0 0x6F -#define SI443X_REG_MODULATION_MODE_CONTROL_1 0x70 -#define SI443X_REG_MODULATION_MODE_CONTROL_2 0x71 -#define SI443X_REG_FREQUENCY_DEVIATION 0x72 -#define SI443X_REG_FREQUENCY_OFFSET_1 0x73 -#define SI443X_REG_FREQUENCY_OFFSET_2 0x74 -#define SI443X_REG_FREQUENCY_BAND_SELECT 0x75 -#define SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76 -#define SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77 -#define SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79 -#define SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A -#define SI443X_REG_TX_FIFO_CONTROL_1 0x7C -#define SI443X_REG_TX_FIFO_CONTROL_2 0x7D -#define SI443X_REG_RX_FIFO_CONTROL 0x7E -#define SI443X_REG_FIFO_ACCESS 0x7F - -// SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION -#define SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register - -// SI443X_REG_DEVICE_VERSION -#define SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register - -// SI443X_REG_DEVICE_STATUS -#define SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag -#define SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag -#define SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag -#define SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag -#define SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range) -#define SI443X_TX 0b00000010 // 1 0 power state: Tx -#define SI443X_RX 0b00000001 // 1 0 Rx -#define SI443X_IDLE 0b00000000 // 1 0 idle - -// SI443X_REG_INTERRUPT_STATUS_1 -#define SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow -#define SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full -#define SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty -#define SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full -#define SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx -#define SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done -#define SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received -#define SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed - -// SI443X_REG_INTERRUPT_STATUS_2 -#define SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected -#define SI443X_VALID_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected -#define SI443X_INVALID_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected -#define SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold -#define SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired -#define SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected -#define SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected -#define SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected - -// SI443X_REG_INTERRUPT_ENABLE_1 -#define SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled -#define SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled -#define SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled -#define SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled -#define SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled -#define SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled -#define SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled -#define SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled - -// SI443X_REG_INTERRUPT_ENABLE_2 -#define SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled -#define SI443X_VALID_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled -#define SI443X_INVALID_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled -#define SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled -#define SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled -#define SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled -#define SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled -#define SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled - -// SI443X_REG_OP_FUNC_CONTROL_1 -#define SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values -#define SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection -#define SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer -#define SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default) -#define SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator -#define SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode -#define SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode -#define SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode) -#define SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode) -#define SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode) - -// SI443X_REG_OP_FUNC_CONTROL_2 -#define SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default) -#define SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low -#define SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high -#define SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high -#define SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low -#define SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high -#define SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low -#define SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high -#define SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default) -#define SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled -#define SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default) -#define SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled -#define SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default) -#define SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled -#define SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first) -#define SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second) -#define SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first) -#define SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second) - -// SI443X_REG_XOSC_LOAD_CAPACITANCE -#define SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration: -#define SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * SI443X_XTAL_SHIFT - -// SI443X_REG_MCU_OUTPUT_CLOCK -#define SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default) -#define SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128 -#define SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256 -#define SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512 -#define SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default) -#define SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled -#define SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz -#define SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz -#define SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz -#define SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz -#define SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz -#define SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz -#define SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default) -#define SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz - -// SI443X_REG_GPIO0_CONFIG + SI443X_REG_GPIO1_CONFIG + SI443X_REG_GPIO2_CONFIG -#define SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive) -#define SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default) -#define SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled -#define SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default) -#define SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default) -#define SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default) -#define SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output -#define SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output -#define SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output -#define SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge -#define SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge -#define SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change -#define SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input -#define SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input -#define SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input -#define SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input -#define SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output -#define SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output -#define SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output -#define SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output -#define SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode -#define SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode -#define SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input -#define SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output -#define SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output -#define SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output -#define SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output -#define SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output -#define SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1 -#define SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2 -#define SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output -#define SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output -#define SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output -#define SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output -#define SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD -#define SI443X_GPIOX_GND 0b00011110 // 4 0 GND - -// SI443X_REG_IO_PORT_CONFIG -#define SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2 -#define SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1 -#define SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0 -#define SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default) -#define SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled -#define SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2 -#define SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1 -#define SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0 - -// SI443X_REG_ADC_CONFIG -#define SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement -#define SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress -#define SI443X_ADC_DONE 0b10000000 // 7 7 done -#define SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default) -#define SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0 -#define SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1 -#define SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2 -#define SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-) -#define SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-) -#define SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-) -#define SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND -#define SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default) -#define SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3 -#define SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2 -#define SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain - -// SI443X_REG_ADC_SENSOR_AMP_OFFSET -#define SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset - -// SI443X_REG_TEMP_SENSOR_CONTROL -#define SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default) -#define SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution -#define SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution -#define SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution -#define SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled -#define SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default) -#define SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default) -#define SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled -#define SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value - -// SI443X_REG_WAKEUP_TIMER_PERIOD_1 -#define SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent - -// SI443X_REG_WAKEUP_TIMER_PERIOD_2 + SI443X_REG_WAKEUP_TIMER_PERIOD_3 -#define SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value: -#define SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms - -// SI443X_REG_LOW_DC_MODE_DURATION -#define SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms - -// SI443X_REG_LOW_BATT_DET_THRESHOLD -#define SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V) - -// SI443X_REG_IF_FILTER_BANDWIDTH -#define SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default) -#define SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled -#define SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate -#define SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection - -// SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE -#define SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default) -#define SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled -#define SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled -#define SI443X_AFC_ON 0b01000000 // 6 6 enabled (default) -#define SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting -#define SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default) -#define SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB -#define SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb -#define SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default) -#define SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default) -#define SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases - -// SI443X_REG_AFC_TIMING_CONTROL -#define SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching -#define SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction -#define SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time - -// SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE -#define SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value -#define SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value - -// SI443X_REG_CLOCK_REC_OVERSAMP_RATIO -#define SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit - -// SI443X_REG_CLOCK_REC_OFFSET_2 -#define SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit -#define SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold -#define SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB - -// SI443X_REG_CLOCK_REC_OFFSET_1 -#define SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID - -// SI443X_REG_CLOCK_REC_OFFSET_0 -#define SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB - -// SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 -#define SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default) -#define SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled -#define SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default) -#define SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled -#define SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB - -// SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 -#define SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB - -// SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD -#define SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold - -// SI443X_REG_AFC_LIMITER -#define SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value - -// SI443X_REG_OOK_COUNTER_1 -#define SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default) -#define SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled -#define SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled -#define SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default) -#define SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled -#define SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default) -#define SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB - -// SI443X_REG_OOK_COUNTER_2 -#define SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB - -// SI443X_REG_SLICER_PEAK_HOLD -#define SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time -#define SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time - -// SI443X_REG_DATA_ACCESS_CONTROL -#define SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled -#define SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default) -#define SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default) -#define SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled -#define SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default) -#define SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled -#define SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default) -#define SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled -#define SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled -#define SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default) -#define SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled -#define SI443X_CRC_ON 0b00000100 // 2 2 enabled (default) -#define SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT -#define SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default) -#define SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16 -#define SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva - -// SI443X_REG_EZMAC_STATUS -#define SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones -#define SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet -#define SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet -#define SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received -#define SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed -#define SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet -#define SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent - -// SI443X_REG_HEADER_CONTROL_1 -#define SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default) -#define SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0 -#define SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1 -#define SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2 -#define SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3 -#define SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none -#define SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0 -#define SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1 -#define SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default) -#define SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default) - -// SI443X_REG_HEADER_CONTROL_2 -#define SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default) -#define SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled -#define SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none -#define SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3 -#define SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2 -#define SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default) -#define SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0 -#define SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default) -#define SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled -#define SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3 -#define SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default) -#define SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1 -#define SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0 -#define SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB - -// SI443X_REG_PREAMBLE_LENGTH -#define SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits - -// SI443X_REG_PREAMBLE_DET_CONTROL -#define SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits -#define SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB - -// SI443X_REG_SYNC_WORD_3 - SI443X_REG_SYNC_WORD_0 -#define SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB) -#define SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte -#define SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte -#define SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB) - -// SI443X_REG_CHANNEL_FILTER_COEFF -#define SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles - -// SI443X_REG_XOSC_CONTROL_TEST -#define SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power -#define SI443X_STATE_READY 0b00100000 // 7 5 ready -#define SI443X_STATE_TUNE 0b01100000 // 7 5 tune -#define SI443X_STATE_TX 0b01000000 // 7 5 Tx -#define SI443X_STATE_RX 0b11100000 // 7 5 Rx - -// SI443X_REG_AGC_OVERRIDE_1 -#define SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default) -#define SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled -#define SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled -#define SI443X_AGC_ON 0b00100000 // 5 5 enabled (default) -#define SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default) -#define SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB -#define SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = SI443X_PGA_GAIN_OVERRIDE * 3 dB - -// SI443X_REG_TX_POWER -#define SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled -#define SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default) -#define SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max - -// SI443X_REG_TX_DATA_RATE_1 + SI443X_REG_TX_DATA_RATE_0 -#define SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (SI443X_DATA_RATE / 2^16) in high data rate mode or -#define SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps) - -// SI443X_REG_MODULATION_MODE_CONTROL_1 -#define SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default) -#define SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps -#define SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default) -#define SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled -#define SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low -#define SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default) -#define SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled -#define SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default) -#define SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default) -#define SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled -#define SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default) -#define SI443X_WHITENING_ON 0b00000001 // 0 0 enabled - -// SI443X_REG_MODULATION_MODE_CONTROL_2 -#define SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default) -#define SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin -#define SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin -#define SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin -#define SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default) -#define SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin -#define SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO -#define SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal -#define SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default) -#define SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled -#define SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB -#define SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default) -#define SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK -#define SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK -#define SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK - -// SI443X_REG_FREQUENCY_DEVIATION -#define SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz - -// SI443X_REG_FREQUENCY_OFFSET_1 + SI443X_REG_FREQUENCY_OFFSET_2 -#define SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset: -#define SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (SI443X_BAND_SELECT + 1) * SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz - -// SI443X_REG_FREQUENCY_BAND_SELECT -#define SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default) -#define SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency -#define SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz -#define SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default) -#define SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select - -// SI443X_REG_NOM_CARRIER_FREQUENCY_1 + SI443X_REG_NOM_CARRIER_FREQUENCY_0 -#define SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency: -#define SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (SI443X_BAND_SELECT + 1)*10*(SI443X_FREQUENCY_BAND_SELECT + 24) + (SI443X_NOM_CARRIER_FREQUENCY - SI443X_FREQUENCY_OFFSET)/6400 [MHz] - -// SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL -#define SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number - -// SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE -#define SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size - -// SI443X_REG_TX_FIFO_CONTROL_1 -#define SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold - -// SI443X_REG_TX_FIFO_CONTROL_2 -#define SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold - -// SI443X_REG_RX_FIFO_CONTROL -#define SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold +#define RADIOLIB_SI443X_REG_DEVICE_TYPE 0x00 +#define RADIOLIB_SI443X_REG_DEVICE_VERSION 0x01 +#define RADIOLIB_SI443X_REG_DEVICE_STATUS 0x02 +#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 0x03 +#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 0x04 +#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 0x05 +#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 0x06 +#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 0x07 +#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 0x08 +#define RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09 +#define RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK 0x0A +#define RADIOLIB_SI443X_REG_GPIO0_CONFIG 0x0B +#define RADIOLIB_SI443X_REG_GPIO1_CONFIG 0x0C +#define RADIOLIB_SI443X_REG_GPIO2_CONFIG 0x0D +#define RADIOLIB_SI443X_REG_IO_PORT_CONFIG 0x0E +#define RADIOLIB_SI443X_REG_ADC_CONFIG 0x0F +#define RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10 +#define RADIOLIB_SI443X_REG_ADC_VALUE 0x11 +#define RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL 0x12 +#define RADIOLIB_SI443X_REG_TEMP_VALUE_OFFSET 0x13 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18 +#define RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION 0x19 +#define RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A +#define RADIOLIB_SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B +#define RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH 0x1C +#define RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D +#define RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL 0x1E +#define RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F +#define RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 0x21 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 0x22 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 0x23 +#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24 +#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25 +#define RADIOLIB_SI443X_REG_RSSI 0x26 +#define RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27 +#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_1 0x28 +#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_2 0x29 +#define RADIOLIB_SI443X_REG_AFC_LIMITER 0x2A +#define RADIOLIB_SI443X_REG_AFC_CORRECTION 0x2B +#define RADIOLIB_SI443X_REG_OOK_COUNTER_1 0x2C +#define RADIOLIB_SI443X_REG_OOK_COUNTER_2 0x2D +#define RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD 0x2E +#define RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL 0x30 +#define RADIOLIB_SI443X_REG_EZMAC_STATUS 0x31 +#define RADIOLIB_SI443X_REG_HEADER_CONTROL_1 0x32 +#define RADIOLIB_SI443X_REG_HEADER_CONTROL_2 0x33 +#define RADIOLIB_SI443X_REG_PREAMBLE_LENGTH 0x34 +#define RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL 0x35 +#define RADIOLIB_SI443X_REG_SYNC_WORD_3 0x36 +#define RADIOLIB_SI443X_REG_SYNC_WORD_2 0x37 +#define RADIOLIB_SI443X_REG_SYNC_WORD_1 0x38 +#define RADIOLIB_SI443X_REG_SYNC_WORD_0 0x39 +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_3 0x3A +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_2 0x3B +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_1 0x3C +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_0 0x3D +#define RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E +#define RADIOLIB_SI443X_REG_CHECK_HEADER_3 0x3F +#define RADIOLIB_SI443X_REG_CHECK_HEADER_2 0x40 +#define RADIOLIB_SI443X_REG_CHECK_HEADER_1 0x41 +#define RADIOLIB_SI443X_REG_CHECK_HEADER_0 0x42 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_3 0x43 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_2 0x44 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_1 0x45 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_0 0x46 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_3 0x47 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_2 0x48 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_1 0x49 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_0 0x4A +#define RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B +#define RADIOLIB_SI443X_REG_ADC8_CONTROL 0x4F +#define RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF 0x60 +#define RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST 0x62 +#define RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 0x69 +#define RADIOLIB_SI443X_REG_TX_POWER 0x6D +#define RADIOLIB_SI443X_REG_TX_DATA_RATE_1 0x6E +#define RADIOLIB_SI443X_REG_TX_DATA_RATE_0 0x6F +#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 0x70 +#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 0x71 +#define RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION 0x72 +#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 0x73 +#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 0x74 +#define RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT 0x75 +#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76 +#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77 +#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79 +#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A +#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 0x7C +#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 0x7D +#define RADIOLIB_SI443X_REG_RX_FIFO_CONTROL 0x7E +#define RADIOLIB_SI443X_REG_FIFO_ACCESS 0x7F + +// RADIOLIB_SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION +#define RADIOLIB_SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register + +// RADIOLIB_SI443X_REG_DEVICE_VERSION +#define RADIOLIB_SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register + +// RADIOLIB_SI443X_REG_DEVICE_STATUS +#define RADIOLIB_SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag +#define RADIOLIB_SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag +#define RADIOLIB_SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag +#define RADIOLIB_SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag +#define RADIOLIB_SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range) +#define RADIOLIB_SI443X_TX 0b00000010 // 1 0 power state: Tx +#define RADIOLIB_SI443X_RX 0b00000001 // 1 0 Rx +#define RADIOLIB_SI443X_IDLE 0b00000000 // 1 0 idle + +// RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full +#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx +#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received +#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed + +// RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 +#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected +#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected +#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected +#define RADIOLIB_SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold +#define RADIOLIB_SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired +#define RADIOLIB_SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected +#define RADIOLIB_SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected +#define RADIOLIB_SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected + +// RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled +#define RADIOLIB_SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled +#define RADIOLIB_SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled +#define RADIOLIB_SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled + +// RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 +#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled +#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled +#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled +#define RADIOLIB_SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled +#define RADIOLIB_SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled +#define RADIOLIB_SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled +#define RADIOLIB_SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled +#define RADIOLIB_SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled + +// RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 +#define RADIOLIB_SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values +#define RADIOLIB_SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection +#define RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer +#define RADIOLIB_SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default) +#define RADIOLIB_SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator +#define RADIOLIB_SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode +#define RADIOLIB_SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode +#define RADIOLIB_SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode) +#define RADIOLIB_SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode) +#define RADIOLIB_SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode) + +// RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 +#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default) +#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high +#define RADIOLIB_SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default) +#define RADIOLIB_SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default) +#define RADIOLIB_SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default) +#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first) +#define RADIOLIB_SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second) +#define RADIOLIB_SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first) +#define RADIOLIB_SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second) + +// RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE +#define RADIOLIB_SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration: +#define RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * RADIOLIB_SI443X_XTAL_SHIFT + +// RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default) +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128 +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256 +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512 +#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default) +#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default) +#define RADIOLIB_SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz + +// RADIOLIB_SI443X_REG_GPIO0_CONFIG + RADIOLIB_SI443X_REG_GPIO1_CONFIG + RADIOLIB_SI443X_REG_GPIO2_CONFIG +#define RADIOLIB_SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive) +#define RADIOLIB_SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default) +#define RADIOLIB_SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default) +#define RADIOLIB_SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default) +#define RADIOLIB_SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default) +#define RADIOLIB_SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output +#define RADIOLIB_SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output +#define RADIOLIB_SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output +#define RADIOLIB_SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge +#define RADIOLIB_SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge +#define RADIOLIB_SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change +#define RADIOLIB_SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input +#define RADIOLIB_SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input +#define RADIOLIB_SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output +#define RADIOLIB_SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output +#define RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode +#define RADIOLIB_SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode +#define RADIOLIB_SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input +#define RADIOLIB_SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output +#define RADIOLIB_SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output +#define RADIOLIB_SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output +#define RADIOLIB_SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output +#define RADIOLIB_SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output +#define RADIOLIB_SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1 +#define RADIOLIB_SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2 +#define RADIOLIB_SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output +#define RADIOLIB_SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output +#define RADIOLIB_SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output +#define RADIOLIB_SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output +#define RADIOLIB_SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD +#define RADIOLIB_SI443X_GPIOX_GND 0b00011110 // 4 0 GND + +// RADIOLIB_SI443X_REG_IO_PORT_CONFIG +#define RADIOLIB_SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2 +#define RADIOLIB_SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1 +#define RADIOLIB_SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0 +#define RADIOLIB_SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default) +#define RADIOLIB_SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2 +#define RADIOLIB_SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1 +#define RADIOLIB_SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0 + +// RADIOLIB_SI443X_REG_ADC_CONFIG +#define RADIOLIB_SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement +#define RADIOLIB_SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress +#define RADIOLIB_SI443X_ADC_DONE 0b10000000 // 7 7 done +#define RADIOLIB_SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND +#define RADIOLIB_SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default) +#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3 +#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2 +#define RADIOLIB_SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain + +// RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET +#define RADIOLIB_SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset + +// RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled +#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value + +// RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 +#define RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent + +// RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 + RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 +#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value: +#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms + +// RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION +#define RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms + +// RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD +#define RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V) + +// RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH +#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default) +#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate +#define RADIOLIB_SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection + +// RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE +#define RADIOLIB_SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default) +#define RADIOLIB_SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled +#define RADIOLIB_SI443X_AFC_ON 0b01000000 // 6 6 enabled (default) +#define RADIOLIB_SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting +#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default) +#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB +#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb +#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default) +#define RADIOLIB_SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default) +#define RADIOLIB_SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases + +// RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL +#define RADIOLIB_SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching +#define RADIOLIB_SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction +#define RADIOLIB_SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time + +// RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE +#define RADIOLIB_SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value +#define RADIOLIB_SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value + +// RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO +#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit + +// RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 +#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit +#define RADIOLIB_SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold +#define RADIOLIB_SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB + +// RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 +#define RADIOLIB_SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID + +// RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 +#define RADIOLIB_SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB + +// RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 +#define RADIOLIB_SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default) +#define RADIOLIB_SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default) +#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB + +// RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 +#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB + +// RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD +#define RADIOLIB_SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold + +// RADIOLIB_SI443X_REG_AFC_LIMITER +#define RADIOLIB_SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value + +// RADIOLIB_SI443X_REG_OOK_COUNTER_1 +#define RADIOLIB_SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default) +#define RADIOLIB_SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled +#define RADIOLIB_SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default) +#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled +#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB + +// RADIOLIB_SI443X_REG_OOK_COUNTER_2 +#define RADIOLIB_SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB + +// RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD +#define RADIOLIB_SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time +#define RADIOLIB_SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time + +// RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL +#define RADIOLIB_SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled +#define RADIOLIB_SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default) +#define RADIOLIB_SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default) +#define RADIOLIB_SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default) +#define RADIOLIB_SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default) +#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled +#define RADIOLIB_SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled +#define RADIOLIB_SI443X_CRC_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT +#define RADIOLIB_SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default) +#define RADIOLIB_SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16 +#define RADIOLIB_SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva + +// RADIOLIB_SI443X_REG_EZMAC_STATUS +#define RADIOLIB_SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones +#define RADIOLIB_SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet +#define RADIOLIB_SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received +#define RADIOLIB_SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed +#define RADIOLIB_SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet +#define RADIOLIB_SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent + +// RADIOLIB_SI443X_REG_HEADER_CONTROL_1 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default) +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default) +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default) + +// RADIOLIB_SI443X_REG_HEADER_CONTROL_2 +#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default) +#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3 +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2 +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default) +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0 +#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default) +#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3 +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default) +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1 +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0 +#define RADIOLIB_SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB + +// RADIOLIB_SI443X_REG_PREAMBLE_LENGTH +#define RADIOLIB_SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits + +// RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL +#define RADIOLIB_SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits +#define RADIOLIB_SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB + +// RADIOLIB_SI443X_REG_SYNC_WORD_3 - RADIOLIB_SI443X_REG_SYNC_WORD_0 +#define RADIOLIB_SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB) +#define RADIOLIB_SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte +#define RADIOLIB_SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte +#define RADIOLIB_SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB) + +// RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF +#define RADIOLIB_SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles + +// RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST +#define RADIOLIB_SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power +#define RADIOLIB_SI443X_STATE_READY 0b00100000 // 7 5 ready +#define RADIOLIB_SI443X_STATE_TUNE 0b01100000 // 7 5 tune +#define RADIOLIB_SI443X_STATE_TX 0b01000000 // 7 5 Tx +#define RADIOLIB_SI443X_STATE_RX 0b11100000 // 7 5 Rx + +// RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 +#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default) +#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled +#define RADIOLIB_SI443X_AGC_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default) +#define RADIOLIB_SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB +#define RADIOLIB_SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = RADIOLIB_SI443X_PGA_GAIN_OVERRIDE * 3 dB + +// RADIOLIB_SI443X_REG_TX_POWER +#define RADIOLIB_SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled +#define RADIOLIB_SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max + +// RADIOLIB_SI443X_REG_TX_DATA_RATE_1 + RADIOLIB_SI443X_REG_TX_DATA_RATE_0 +#define RADIOLIB_SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^16) in high data rate mode or +#define RADIOLIB_SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps) + +// RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 +#define RADIOLIB_SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default) +#define RADIOLIB_SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps +#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default) +#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low +#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default) +#define RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled +#define RADIOLIB_SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default) +#define RADIOLIB_SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default) +#define RADIOLIB_SI443X_WHITENING_ON 0b00000001 // 0 0 enabled + +// RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 +#define RADIOLIB_SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default) +#define RADIOLIB_SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin +#define RADIOLIB_SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin +#define RADIOLIB_SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin +#define RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default) +#define RADIOLIB_SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin +#define RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO +#define RADIOLIB_SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal +#define RADIOLIB_SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default) +#define RADIOLIB_SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB +#define RADIOLIB_SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default) +#define RADIOLIB_SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK +#define RADIOLIB_SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK +#define RADIOLIB_SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK + +// RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION +#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * RADIOLIB_SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz + +// RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 + RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 +#define RADIOLIB_SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset: +#define RADIOLIB_SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (RADIOLIB_SI443X_BAND_SELECT + 1) * RADIOLIB_SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz + +// RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT +#define RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default) +#define RADIOLIB_SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency +#define RADIOLIB_SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz +#define RADIOLIB_SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default) +#define RADIOLIB_SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select + +// RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 + RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 +#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency: +#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (RADIOLIB_SI443X_BAND_SELECT + 1)*10*(RADIOLIB_SI443X_FREQUENCY_BAND_SELECT + 24) + (RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY - RADIOLIB_SI443X_FREQUENCY_OFFSET)/6400 [MHz] + +// RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL +#define RADIOLIB_SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number + +// RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE +#define RADIOLIB_SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size + +// RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold + +// RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold + +// RADIOLIB_SI443X_REG_RX_FIFO_CONTROL +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold /*! \class Si443x @@ -568,6 +568,8 @@ class Si443x: public PhysicalLayer { */ Si443x(Module* mod); + Module* getMod(); + // basic methods /*! @@ -793,7 +795,7 @@ class Si443x: public PhysicalLayer { uint8_t randomByte(); /*! - \brief Read version SPI register. Should return SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working. + \brief Read version SPI register. Should return RADIOLIB_SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working. \returns Version register contents or \ref status_codes */ From a229912789a111bc4132a2843750112b957b0890 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:43:17 +0100 Subject: [PATCH 0052/1848] [nRF24] Update to 5.0.0 --- .../nRF24/nRF24_Receive/nRF24_Receive.ino | 8 +- .../nRF24_Receive_Interrupt.ino | 8 +- .../nRF24/nRF24_Transmit/nRF24_Transmit.ino | 12 +- .../nRF24_Transmit_Interrupt.ino | 8 +- src/modules/nRF24/nRF24.cpp | 266 ++++++++--------- src/modules/nRF24/nRF24.h | 268 +++++++++--------- 6 files changed, 286 insertions(+), 284 deletions(-) diff --git a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino index 2c036fd64c..4713141171 100644 --- a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino +++ b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino @@ -35,7 +35,7 @@ void setup() { // initialize nRF24 with default settings Serial.print(F("[nRF24] Initializing ... ")); int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -50,7 +50,7 @@ void setup() { Serial.print(F("[nRF24] Setting address for receive pipe 0 ... ")); byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; state = radio.setReceivePipe(0, addr); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -75,7 +75,7 @@ void loop() { int state = radio.receive(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("success!")); @@ -83,7 +83,7 @@ void loop() { Serial.print(F("[nRF24] Data:\t\t")); Serial.println(str); - } else if (state == ERR_RX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index 6d964bd1b8..cafa2964cd 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -36,7 +36,7 @@ void setup() { // initialize nRF24 with default settings Serial.print(F("[nRF24] Initializing ... ")); int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -51,7 +51,7 @@ void setup() { Serial.print(F("[nRF24] Setting address for receive pipe 0 ... ")); byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; state = radio.setReceivePipe(0, addr); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -66,7 +66,7 @@ void setup() { // start listening Serial.print(F("[nRF24] Starting to listen ... ")); state = radio.startReceive(); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -124,7 +124,7 @@ void loop() { int state = radio.readData(byteArr, 8); */ - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[nRF24] Received packet!")); diff --git a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino index c692e8a8ff..0b8c516c85 100644 --- a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino +++ b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino @@ -35,7 +35,7 @@ void setup() { // initialize nRF24 with default settings Serial.print(F("[nRF24] Initializing ... ")); int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -50,7 +50,7 @@ void setup() { byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; Serial.print(F("[nRF24] Setting transmit pipe ... ")); state = radio.setTransmitPipe(addr); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -66,20 +66,20 @@ void loop() { // 32 characters long int state = radio.transmit("Hello World!"); - if (state == ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted Serial.println(F("success!")); - } else if (state == ERR_PACKET_TOO_LONG) { + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 32 bytes Serial.println(F("too long!")); - } else if (state == ERR_ACK_NOT_RECEIVED) { + } else if (state == RADIOLIB_ERR_ACK_NOT_RECEIVED) { // acknowledge from destination module // was not received within 15 retries Serial.println(F("ACK not received!")); - } else if (state == ERR_TX_TIMEOUT) { + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { // timed out while transmitting Serial.println(F("timeout!")); diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 81b064b3cf..9b6720c505 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -30,7 +30,7 @@ nRF24 radio = new Module(10, 2, 3); //nRF24 radio = RadioShield.ModuleA; // save transmission state between loops -int transmissionState = ERR_NONE; +int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); @@ -38,7 +38,7 @@ void setup() { // initialize nRF24 with default settings Serial.print(F("[nRF24] Initializing ... ")); int state = radio.begin(); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -53,7 +53,7 @@ void setup() { byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; Serial.print(F("[nRF24] Setting transmit pipe ... ")); state = radio.setTransmitPipe(addr); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -110,7 +110,7 @@ void loop() { // reset flag transmittedFlag = false; - if (transmissionState == ERR_NONE) { + if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 90f8b3e09b..683d22f65a 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -1,30 +1,34 @@ #include "nRF24.h" #if !defined(RADIOLIB_EXCLUDE_NRF24) -nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_FREQUENCY_STEP_SIZE, NRF24_MAX_PACKET_LENGTH) { +nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) { _mod = mod; } +Module* nRF24::getMod() { + return(_mod); +} + int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrWidth) { // set module properties - _mod->SPIreadCommand = NRF24_CMD_READ; - _mod->SPIwriteCommand = NRF24_CMD_WRITE; - _mod->init(RADIOLIB_USE_SPI); - Module::pinMode(_mod->getIrq(), INPUT); + _mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; + _mod->SPIwriteCommand = RADIOLIB_NRF24_CMD_WRITE; + _mod->init(); + _mod->pinMode(_mod->getIrq(), INPUT); // set pin mode on RST (connected to nRF24 CE pin) - Module::pinMode(_mod->getRst(), OUTPUT); - Module::digitalWrite(_mod->getRst(), LOW); + _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->digitalWrite(_mod->getRst(), LOW); // wait for minimum power-on reset duration - Module::delay(100); + _mod->delay(100); // check SPI connection - int16_t val = _mod->SPIgetRegValue(NRF24_REG_SETUP_AW); + int16_t val = _mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); if(!((val >= 0) && (val <= 3))) { RADIOLIB_DEBUG_PRINTLN(F("No nRF24 found!")); - _mod->term(RADIOLIB_USE_SPI); - return(ERR_CHIP_NOT_FOUND); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN(F("M\tnRF24")); @@ -64,17 +68,17 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW } int16_t nRF24::sleep() { - return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_DOWN, 1, 1)); + return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_DOWN, 1, 1)); } int16_t nRF24::standby() { // make sure carrier output is disabled - _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_OFF, 7, 7); - _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_OFF, 4, 4); - Module::digitalWrite(_mod->getRst(), LOW); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_OFF, 7, 7); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_OFF, 4, 4); + _mod->digitalWrite(_mod->getRst(), LOW); // use standby-1 mode - return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1)); + return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1)); } int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -83,22 +87,22 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait until transmission is finished - uint32_t start = Module::micros(); - while(Module::digitalRead(_mod->getIrq())) { - Module::yield(); + uint32_t start = _mod->micros(); + while(_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); // check maximum number of retransmits - if(getStatus(NRF24_MAX_RT)) { + if(getStatus(RADIOLIB_NRF24_MAX_RT)) { standby(); clearIRQ(); - return(ERR_ACK_NOT_RECEIVED); + return(RADIOLIB_ERR_ACK_NOT_RECEIVED); } // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(Module::micros() - start >= 60000) { + if(_mod->micros() - start >= 60000) { standby(); clearIRQ(); - return(ERR_TX_TIMEOUT); + return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -114,15 +118,15 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for Rx_DataReady or timeout - uint32_t start = Module::micros(); - while(Module::digitalRead(_mod->getIrq())) { - Module::yield(); + uint32_t start = _mod->micros(); + while(_mod->digitalRead(_mod->getIrq())) { + _mod->yield(); // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(Module::micros() - start >= 60000) { + if(_mod->micros() - start >= 60000) { standby(); clearIRQ(); - return(ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -134,25 +138,25 @@ int16_t nRF24::transmitDirect(uint32_t frf) { // set raw frequency value if(frf != 0) { uint8_t freqRaw = frf - 2400; - _mod->SPIwriteRegister(NRF24_REG_RF_CH, freqRaw & 0b01111111); + _mod->SPIwriteRegister(RADIOLIB_NRF24_REG_RF_CH, freqRaw & 0b01111111); } // output carrier - int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0); - state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_ON, 7, 7); - state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_ON, 4, 4); - Module::digitalWrite(_mod->getRst(), HIGH); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_ON, 7, 7); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_ON, 4, 4); + _mod->digitalWrite(_mod->getRst(), HIGH); return(state); } int16_t nRF24::receiveDirect() { // nRF24 is unable to directly output demodulated data // this method is implemented only for PhysicalLayer compatibility - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } void nRF24::setIrqAction(void (*func)(void)) { - Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); } int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -160,8 +164,8 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { (void)addr; // check packet length - if(len > NRF24_MAX_PACKET_LENGTH) { - return(ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_NRF24_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } // set mode to standby @@ -169,17 +173,17 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // enable primary Tx mode - state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); // clear interrupts clearIRQ(); // enable Tx_DataSent interrupt - state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_TX_DS_IRQ_ON, 5, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON, 5, 5); RADIOLIB_ASSERT(state); // flush Tx FIFO - SPItransfer(NRF24_CMD_FLUSH_TX); + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_TX); // fill Tx FIFO uint8_t buff[32]; @@ -188,9 +192,9 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { SPIwriteTxPayload(data, len); // CE high to start transmitting - Module::digitalWrite(_mod->getRst(), HIGH); - Module::delay(1); - Module::digitalWrite(_mod->getRst(), LOW); + _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->delay(1); + _mod->digitalWrite(_mod->getRst(), LOW); return(state); } @@ -201,22 +205,22 @@ int16_t nRF24::startReceive() { RADIOLIB_ASSERT(state); // enable primary Rx mode - state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PRX, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PRX, 0, 0); RADIOLIB_ASSERT(state); // enable Rx_DataReady interrupt clearIRQ(); - state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_ON, 6, 6); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON, 6, 6); RADIOLIB_ASSERT(state); // flush Rx FIFO - SPItransfer(NRF24_CMD_FLUSH_RX); + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); // CE high to start receiving - Module::digitalWrite(_mod->getRst(), HIGH); + _mod->digitalWrite(_mod->getRst(), HIGH); // wait to enter Rx state - Module::delay(1); + _mod->delay(1); return(state); } @@ -228,7 +232,7 @@ int16_t nRF24::readData(uint8_t* data, size_t len) { // get packet length size_t length = len; - if(len == NRF24_MAX_PACKET_LENGTH) { + if(len == RADIOLIB_NRF24_MAX_PACKET_LENGTH) { length = getPacketLength(); } @@ -238,15 +242,15 @@ int16_t nRF24::readData(uint8_t* data, size_t len) { // clear interrupt clearIRQ(); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t nRF24::setFrequency(int16_t freq) { - RADIOLIB_CHECK_RANGE(freq, 2400, 2525, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 2400, 2525, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency uint8_t freqRaw = freq - 2400; - return(_mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0)); + return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0)); } int16_t nRF24::setDataRate(int16_t dataRate) { @@ -256,16 +260,16 @@ int16_t nRF24::setDataRate(int16_t dataRate) { // set data rate if(dataRate == 250) { - state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_250_KBPS, 5, 5); - state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_250_KBPS, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3); } else if(dataRate == 1000) { - state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_1_MBPS, 5, 5); - state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_1_MBPS, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 5, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 3, 3); } else if(dataRate == 2000) { - state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_2_MBPS, 5, 5); - state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_2_MBPS, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 5, 5); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 3, 3); } else { - return(ERR_INVALID_DATA_RATE); + return(RADIOLIB_ERR_INVALID_DATA_RATE); } return(state); @@ -280,23 +284,23 @@ int16_t nRF24::setOutputPower(int8_t power) { uint8_t powerRaw = 0; switch(power) { case -18: - powerRaw = NRF24_RF_PWR_18_DBM; + powerRaw = RADIOLIB_NRF24_RF_PWR_18_DBM; break; case -12: - powerRaw = NRF24_RF_PWR_12_DBM; + powerRaw = RADIOLIB_NRF24_RF_PWR_12_DBM; break; case -6: - powerRaw = NRF24_RF_PWR_6_DBM; + powerRaw = RADIOLIB_NRF24_RF_PWR_6_DBM; break; case 0: - powerRaw = NRF24_RF_PWR_0_DBM; + powerRaw = RADIOLIB_NRF24_RF_PWR_0_DBM; break; default: - return(ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } // write new register value - state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, powerRaw, 2, 1); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, powerRaw, 2, 1); return(state); } @@ -310,19 +314,19 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) { case 2: // Even if marked as 'Illegal' on the datasheet this will work: // http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html - state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_2_BYTES, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_2_BYTES, 1, 0); break; case 3: - state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_3_BYTES, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_3_BYTES, 1, 0); break; case 4: - state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_4_BYTES, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_4_BYTES, 1, 0); break; case 5: - state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_5_BYTES, 1, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_5_BYTES, 1, 0); break; default: - return(ERR_INVALID_ADDRESS_WIDTH); + return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); } // save address width @@ -337,11 +341,11 @@ int16_t nRF24::setTransmitPipe(uint8_t* addr) { RADIOLIB_ASSERT(state); // set transmit address - _mod->SPIwriteRegisterBurst(NRF24_REG_TX_ADDR, addr, _addrWidth); + _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_TX_ADDR, addr, _addrWidth); // set Rx pipe 0 address (for ACK) - _mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_ON, 0, 0); + _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, _addrWidth); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); return(state); } @@ -354,15 +358,15 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) { // write full pipe 0 - 1 address and enable the pipe switch(pipeNum) { case 0: - _mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_ON, 0, 0); + _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, _addrWidth); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); break; case 1: - _mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P1, addr, _addrWidth); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P1_ON, 1, 1); + _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P1, addr, _addrWidth); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_ON, 1, 1); break; default: - return(ERR_INVALID_PIPE_NUMBER); + return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); } return(state); @@ -376,23 +380,23 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) { // write unique pipe 2 - 5 address and enable the pipe switch(pipeNum) { case 2: - state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P2, addrByte); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P2_ON, 2, 2); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P2, addrByte); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_ON, 2, 2); break; case 3: - state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P3, addrByte); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P3_ON, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P3, addrByte); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_ON, 3, 3); break; case 4: - state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P4, addrByte); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P4_ON, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P4, addrByte); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_ON, 4, 4); break; case 5: - state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P5, addrByte); - state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P5_ON, 5, 5); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P5, addrByte); + state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_ON, 5, 5); break; default: - return(ERR_INVALID_PIPE_NUMBER); + return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); } return(state); @@ -405,49 +409,49 @@ int16_t nRF24::disablePipe(uint8_t pipeNum) { switch(pipeNum) { case 0: - state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_OFF, 0, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_OFF, 0, 0); break; case 1: - state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P1_OFF, 1, 1); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_OFF, 1, 1); break; case 2: - state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P2_OFF, 2, 2); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_OFF, 2, 2); break; case 3: - state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P3_OFF, 3, 3); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_OFF, 3, 3); break; case 4: - state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P4_OFF, 4, 4); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_OFF, 4, 4); break; case 5: - state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P5_OFF, 5, 5); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_OFF, 5, 5); break; default: - return(ERR_INVALID_PIPE_NUMBER); + return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); } return(state); } int16_t nRF24::getStatus(uint8_t mask) { - return(_mod->SPIgetRegValue(NRF24_REG_STATUS) & mask); + return(_mod->SPIgetRegValue(RADIOLIB_NRF24_REG_STATUS) & mask); } bool nRF24::isCarrierDetected() { - return(_mod->SPIgetRegValue(NRF24_REG_RPD, 0, 0) == 1); + return(_mod->SPIgetRegValue(RADIOLIB_NRF24_REG_RPD, 0, 0) == 1); } int16_t nRF24::setFrequencyDeviation(float freqDev) { // nRF24 is unable to set frequency deviation // this method is implemented only for PhysicalLayer compatibility (void)freqDev; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } size_t nRF24::getPacketLength(bool update) { (void)update; uint8_t length = 0; - SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, &length, 1); + SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, &length, 1); return((size_t)length); } @@ -459,35 +463,35 @@ int16_t nRF24::setCrcFiltering(bool crcOn) { } // Disable CRC - return _mod->SPIsetRegValue(NRF24_REG_CONFIG, (crcOn ? NRF24_CRC_ON : NRF24_CRC_OFF), 3, 3); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, (crcOn ? RADIOLIB_NRF24_CRC_ON : RADIOLIB_NRF24_CRC_OFF), 3, 3); } int16_t nRF24::setAutoAck(bool autoAckOn){ - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_ALL_ON : NRF24_AA_ALL_OFF), 5, 0); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_ALL_ON : RADIOLIB_NRF24_AA_ALL_OFF), 5, 0); } int16_t nRF24::setAutoAck(uint8_t pipeNum, bool autoAckOn){ switch(pipeNum) { case 0: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P0_ON : NRF24_AA_P0_OFF), 0, 0); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P0_ON : RADIOLIB_NRF24_AA_P0_OFF), 0, 0); break; case 1: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P1_ON : NRF24_AA_P1_OFF), 1, 1); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P1_ON : RADIOLIB_NRF24_AA_P1_OFF), 1, 1); break; case 2: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P2_ON : NRF24_AA_P2_OFF), 2, 2); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P2_ON : RADIOLIB_NRF24_AA_P2_OFF), 2, 2); break; case 3: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P3_ON : NRF24_AA_P3_OFF), 3, 3); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P3_ON : RADIOLIB_NRF24_AA_P3_OFF), 3, 3); break; case 4: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P4_ON : NRF24_AA_P4_OFF), 4, 4); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P4_ON : RADIOLIB_NRF24_AA_P4_OFF), 4, 4); break; case 5: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P5_ON : NRF24_AA_P5_OFF), 5, 5); + return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P5_ON : RADIOLIB_NRF24_AA_P5_OFF), 5, 5); break; default: - return (ERR_INVALID_PIPE_NUMBER); + return (RADIOLIB_ERR_INVALID_PIPE_NUMBER); } } @@ -495,14 +499,14 @@ int16_t nRF24::setDataShaping(uint8_t sh) { // nRF24 is unable to set data shaping // this method is implemented only for PhysicalLayer compatibility (void)sh; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t nRF24::setEncoding(uint8_t encoding) { // nRF24 is unable to set encoding // this method is implemented only for PhysicalLayer compatibility (void)encoding; - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } uint8_t nRF24::randomByte() { @@ -525,79 +529,75 @@ void nRF24::readBit(RADIOLIB_PIN_TYPE pin) { void nRF24::clearIRQ() { // clear status bits - _mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); // disable interrupts - _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_OFF | NRF24_MASK_TX_DS_IRQ_OFF | NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF | RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF | RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4); } int16_t nRF24::config() { // enable 16-bit CRC - int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_CRC_ON | NRF24_CRC_16, 3, 2); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_CRC_ON | RADIOLIB_NRF24_CRC_16, 3, 2); RADIOLIB_ASSERT(state); // set 15 retries and delay 1500 (5*250) us - _mod->SPIsetRegValue(NRF24_REG_SETUP_RETR, (5 << 4) | 5); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_RETR, (5 << 4) | 5); // set features: dynamic payload on, payload with ACK packets off, dynamic ACK off - state = _mod->SPIsetRegValue(NRF24_REG_FEATURE, NRF24_DPL_ON | NRF24_ACK_PAY_OFF | NRF24_DYN_ACK_OFF, 2, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_FEATURE, RADIOLIB_NRF24_DPL_ON | RADIOLIB_NRF24_ACK_PAY_OFF | RADIOLIB_NRF24_DYN_ACK_OFF, 2, 0); RADIOLIB_ASSERT(state); // enable dynamic payloads - state = _mod->SPIsetRegValue(NRF24_REG_DYNPD, NRF24_DPL_ALL_ON, 5, 0); + state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_DYNPD, RADIOLIB_NRF24_DPL_ALL_ON, 5, 0); RADIOLIB_ASSERT(state); // reset IRQ clearIRQ(); // clear status - _mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); // flush FIFOs - SPItransfer(NRF24_CMD_FLUSH_TX); - SPItransfer(NRF24_CMD_FLUSH_RX); + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_TX); + SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); // power up - _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1); - Module::delay(5); + _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1); + _mod->delay(5); return(state); } void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) { - SPItransfer(NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes); + SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes); } void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { - SPItransfer(NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes); + SPItransfer(RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes); } void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { - // get pointer to used SPI interface and the settings - SPIClass* spi = _mod->getSpi(); - SPISettings spiSettings = _mod->getSpiSettings(); - // start transfer - Module::digitalWrite(_mod->getCs(), LOW); - spi->beginTransaction(spiSettings); + _mod->digitalWrite(_mod->getCs(), LOW); + _mod->SPIbeginTransaction(); // send command - spi->transfer(cmd); + _mod->SPItransfer(cmd); // send data if(write) { for(uint8_t i = 0; i < numBytes; i++) { - spi->transfer(dataOut[i]); + _mod->SPItransfer(dataOut[i]); } } else { for(uint8_t i = 0; i < numBytes; i++) { - dataIn[i] = spi->transfer(0x00); + dataIn[i] = _mod->SPItransfer(0x00); } } // stop transfer - spi->endTransaction(); - Module::digitalWrite(_mod->getCs(), HIGH); + _mod->SPIendTransaction(); + _mod->digitalWrite(_mod->getCs(), HIGH); } #endif diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index d76a658df6..fead3bf1c4 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -7,169 +7,169 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // nRF24 physical layer properties -#define NRF24_FREQUENCY_STEP_SIZE 1000000.0 -#define NRF24_MAX_PACKET_LENGTH 32 +#define RADIOLIB_NRF24_FREQUENCY_STEP_SIZE 1000000.0 +#define RADIOLIB_NRF24_MAX_PACKET_LENGTH 32 // nRF24 SPI commands -#define NRF24_CMD_READ 0b00000000 -#define NRF24_CMD_WRITE 0b00100000 -#define NRF24_CMD_READ_RX_PAYLOAD 0b01100001 -#define NRF24_CMD_WRITE_TX_PAYLOAD 0b10100000 -#define NRF24_CMD_FLUSH_TX 0b11100001 -#define NRF24_CMD_FLUSH_RX 0b11100010 -#define NRF24_CMD_REUSE_TX_PAXLOAD 0b11100011 -#define NRF24_CMD_READ_RX_PAYLOAD_WIDTH 0b01100000 -#define NRF24_CMD_WRITE_ACK_PAYLOAD 0b10101000 -#define NRF24_CMD_WRITE_TX_PAYLOAD_NOACK 0b10110000 -#define NRF24_CMD_NOP 0b11111111 +#define RADIOLIB_NRF24_CMD_READ 0b00000000 +#define RADIOLIB_NRF24_CMD_WRITE 0b00100000 +#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD 0b01100001 +#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD 0b10100000 +#define RADIOLIB_NRF24_CMD_FLUSH_TX 0b11100001 +#define RADIOLIB_NRF24_CMD_FLUSH_RX 0b11100010 +#define RADIOLIB_NRF24_CMD_REUSE_TX_PAXLOAD 0b11100011 +#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD_WIDTH 0b01100000 +#define RADIOLIB_NRF24_CMD_WRITE_ACK_PAYLOAD 0b10101000 +#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD_NOACK 0b10110000 +#define RADIOLIB_NRF24_CMD_NOP 0b11111111 // nRF24 register map -#define NRF24_REG_CONFIG 0x00 -#define NRF24_REG_EN_AA 0x01 -#define NRF24_REG_EN_RXADDR 0x02 -#define NRF24_REG_SETUP_AW 0x03 -#define NRF24_REG_SETUP_RETR 0x04 -#define NRF24_REG_RF_CH 0x05 -#define NRF24_REG_RF_SETUP 0x06 -#define NRF24_REG_STATUS 0x07 -#define NRF24_REG_OBSERVE_TX 0x08 -#define NRF24_REG_RPD 0x09 -#define NRF24_REG_RX_ADDR_P0 0x0A -#define NRF24_REG_RX_ADDR_P1 0x0B -#define NRF24_REG_RX_ADDR_P2 0x0C -#define NRF24_REG_RX_ADDR_P3 0x0D -#define NRF24_REG_RX_ADDR_P4 0x0E -#define NRF24_REG_RX_ADDR_P5 0x0F -#define NRF24_REG_TX_ADDR 0x10 -#define NRF24_REG_RX_PW_P0 0x11 -#define NRF24_REG_RX_PW_P1 0x12 -#define NRF24_REG_RX_PW_P2 0x13 -#define NRF24_REG_RX_PW_P3 0x14 -#define NRF24_REG_RX_PW_P4 0x15 -#define NRF24_REG_RX_PW_P5 0x16 -#define NRF24_REG_FIFO_STATUS 0x17 -#define NRF24_REG_DYNPD 0x1C -#define NRF24_REG_FEATURE 0x1D +#define RADIOLIB_NRF24_REG_CONFIG 0x00 +#define RADIOLIB_NRF24_REG_EN_AA 0x01 +#define RADIOLIB_NRF24_REG_EN_RXADDR 0x02 +#define RADIOLIB_NRF24_REG_SETUP_AW 0x03 +#define RADIOLIB_NRF24_REG_SETUP_RETR 0x04 +#define RADIOLIB_NRF24_REG_RF_CH 0x05 +#define RADIOLIB_NRF24_REG_RF_SETUP 0x06 +#define RADIOLIB_NRF24_REG_STATUS 0x07 +#define RADIOLIB_NRF24_REG_OBSERVE_TX 0x08 +#define RADIOLIB_NRF24_REG_RPD 0x09 +#define RADIOLIB_NRF24_REG_RX_ADDR_P0 0x0A +#define RADIOLIB_NRF24_REG_RX_ADDR_P1 0x0B +#define RADIOLIB_NRF24_REG_RX_ADDR_P2 0x0C +#define RADIOLIB_NRF24_REG_RX_ADDR_P3 0x0D +#define RADIOLIB_NRF24_REG_RX_ADDR_P4 0x0E +#define RADIOLIB_NRF24_REG_RX_ADDR_P5 0x0F +#define RADIOLIB_NRF24_REG_TX_ADDR 0x10 +#define RADIOLIB_NRF24_REG_RX_PW_P0 0x11 +#define RADIOLIB_NRF24_REG_RX_PW_P1 0x12 +#define RADIOLIB_NRF24_REG_RX_PW_P2 0x13 +#define RADIOLIB_NRF24_REG_RX_PW_P3 0x14 +#define RADIOLIB_NRF24_REG_RX_PW_P4 0x15 +#define RADIOLIB_NRF24_REG_RX_PW_P5 0x16 +#define RADIOLIB_NRF24_REG_FIFO_STATUS 0x17 +#define RADIOLIB_NRF24_REG_DYNPD 0x1C +#define RADIOLIB_NRF24_REG_FEATURE 0x1D // NRF24_REG_CONFIG MSB LSB DESCRIPTION -#define NRF24_MASK_RX_DR_IRQ_OFF 0b01000000 // 6 6 RX_DR will not be reflected on IRQ pin -#define NRF24_MASK_RX_DR_IRQ_ON 0b00000000 // 6 6 RX_DR will be reflected on IRQ pin as active low (default) -#define NRF24_MASK_TX_DS_IRQ_OFF 0b00100000 // 5 5 TX_DS will not be reflected on IRQ pin -#define NRF24_MASK_TX_DS_IRQ_ON 0b00000000 // 5 5 TX_DS will be reflected on IRQ pin as active low (default) -#define NRF24_MASK_MAX_RT_IRQ_OFF 0b00010000 // 4 4 MAX_RT will not be reflected on IRQ pin -#define NRF24_MASK_MAX_RT_IRQ_ON 0b00000000 // 4 4 MAX_RT will be reflected on IRQ pin as active low (default) -#define NRF24_CRC_OFF 0b00000000 // 3 3 CRC calculation: disabled -#define NRF24_CRC_ON 0b00001000 // 3 3 enabled (default) -#define NRF24_CRC_8 0b00000000 // 2 2 CRC scheme: CRC8 (default) -#define NRF24_CRC_16 0b00000100 // 2 2 CRC16 -#define NRF24_POWER_UP 0b00000010 // 1 1 power up -#define NRF24_POWER_DOWN 0b00000000 // 1 1 power down -#define NRF24_PTX 0b00000000 // 0 0 enable primary Tx -#define NRF24_PRX 0b00000001 // 0 0 enable primary Rx +#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF 0b01000000 // 6 6 RX_DR will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON 0b00000000 // 6 6 RX_DR will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF 0b00100000 // 5 5 TX_DS will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON 0b00000000 // 5 5 TX_DS will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF 0b00010000 // 4 4 MAX_RT will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_ON 0b00000000 // 4 4 MAX_RT will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_CRC_OFF 0b00000000 // 3 3 CRC calculation: disabled +#define RADIOLIB_NRF24_CRC_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_NRF24_CRC_8 0b00000000 // 2 2 CRC scheme: CRC8 (default) +#define RADIOLIB_NRF24_CRC_16 0b00000100 // 2 2 CRC16 +#define RADIOLIB_NRF24_POWER_UP 0b00000010 // 1 1 power up +#define RADIOLIB_NRF24_POWER_DOWN 0b00000000 // 1 1 power down +#define RADIOLIB_NRF24_PTX 0b00000000 // 0 0 enable primary Tx +#define RADIOLIB_NRF24_PRX 0b00000001 // 0 0 enable primary Rx // NRF24_REG_EN_AA -#define NRF24_AA_ALL_OFF 0b00000000 // 5 0 auto-ACK on all pipes: disabled -#define NRF24_AA_ALL_ON 0b00111111 // 5 0 enabled (default) -#define NRF24_AA_P5_OFF 0b00000000 // 5 5 auto-ACK on pipe 5: disabled -#define NRF24_AA_P5_ON 0b00100000 // 5 5 enabled (default) -#define NRF24_AA_P4_OFF 0b00000000 // 4 4 auto-ACK on pipe 4: disabled -#define NRF24_AA_P4_ON 0b00010000 // 4 4 enabled (default) -#define NRF24_AA_P3_OFF 0b00000000 // 3 3 auto-ACK on pipe 3: disabled -#define NRF24_AA_P3_ON 0b00001000 // 3 3 enabled (default) -#define NRF24_AA_P2_OFF 0b00000000 // 2 2 auto-ACK on pipe 2: disabled -#define NRF24_AA_P2_ON 0b00000100 // 2 2 enabled (default) -#define NRF24_AA_P1_OFF 0b00000000 // 1 1 auto-ACK on pipe 1: disabled -#define NRF24_AA_P1_ON 0b00000010 // 1 1 enabled (default) -#define NRF24_AA_P0_OFF 0b00000000 // 0 0 auto-ACK on pipe 0: disabled -#define NRF24_AA_P0_ON 0b00000001 // 0 0 enabled (default) +#define RADIOLIB_NRF24_AA_ALL_OFF 0b00000000 // 5 0 auto-ACK on all pipes: disabled +#define RADIOLIB_NRF24_AA_ALL_ON 0b00111111 // 5 0 enabled (default) +#define RADIOLIB_NRF24_AA_P5_OFF 0b00000000 // 5 5 auto-ACK on pipe 5: disabled +#define RADIOLIB_NRF24_AA_P5_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_NRF24_AA_P4_OFF 0b00000000 // 4 4 auto-ACK on pipe 4: disabled +#define RADIOLIB_NRF24_AA_P4_ON 0b00010000 // 4 4 enabled (default) +#define RADIOLIB_NRF24_AA_P3_OFF 0b00000000 // 3 3 auto-ACK on pipe 3: disabled +#define RADIOLIB_NRF24_AA_P3_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_NRF24_AA_P2_OFF 0b00000000 // 2 2 auto-ACK on pipe 2: disabled +#define RADIOLIB_NRF24_AA_P2_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_NRF24_AA_P1_OFF 0b00000000 // 1 1 auto-ACK on pipe 1: disabled +#define RADIOLIB_NRF24_AA_P1_ON 0b00000010 // 1 1 enabled (default) +#define RADIOLIB_NRF24_AA_P0_OFF 0b00000000 // 0 0 auto-ACK on pipe 0: disabled +#define RADIOLIB_NRF24_AA_P0_ON 0b00000001 // 0 0 enabled (default) // NRF24_REG_EN_RXADDR -#define NRF24_P5_OFF 0b00000000 // 5 5 receive pipe 5: disabled (default) -#define NRF24_P5_ON 0b00100000 // 5 5 enabled -#define NRF24_P4_OFF 0b00000000 // 4 4 receive pipe 4: disabled (default) -#define NRF24_P4_ON 0b00010000 // 4 4 enabled -#define NRF24_P3_OFF 0b00000000 // 3 3 receive pipe 3: disabled (default) -#define NRF24_P3_ON 0b00001000 // 3 3 enabled -#define NRF24_P2_OFF 0b00000000 // 2 2 receive pipe 2: disabled (default) -#define NRF24_P2_ON 0b00000100 // 2 2 enabled -#define NRF24_P1_OFF 0b00000000 // 1 1 receive pipe 1: disabled -#define NRF24_P1_ON 0b00000010 // 1 1 enabled (default) -#define NRF24_P0_OFF 0b00000000 // 0 0 receive pipe 0: disabled -#define NRF24_P0_ON 0b00000001 // 0 0 enabled (default) +#define RADIOLIB_NRF24_P5_OFF 0b00000000 // 5 5 receive pipe 5: disabled (default) +#define RADIOLIB_NRF24_P5_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_NRF24_P4_OFF 0b00000000 // 4 4 receive pipe 4: disabled (default) +#define RADIOLIB_NRF24_P4_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_NRF24_P3_OFF 0b00000000 // 3 3 receive pipe 3: disabled (default) +#define RADIOLIB_NRF24_P3_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_NRF24_P2_OFF 0b00000000 // 2 2 receive pipe 2: disabled (default) +#define RADIOLIB_NRF24_P2_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_P1_OFF 0b00000000 // 1 1 receive pipe 1: disabled +#define RADIOLIB_NRF24_P1_ON 0b00000010 // 1 1 enabled (default) +#define RADIOLIB_NRF24_P0_OFF 0b00000000 // 0 0 receive pipe 0: disabled +#define RADIOLIB_NRF24_P0_ON 0b00000001 // 0 0 enabled (default) // NRF24_REG_SETUP_AW -#define NRF24_ADDRESS_2_BYTES 0b00000000 // 1 0 address width: 2 bytes -#define NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 3 bytes -#define NRF24_ADDRESS_4_BYTES 0b00000010 // 1 0 4 bytes -#define NRF24_ADDRESS_5_BYTES 0b00000011 // 1 0 5 bytes (default) +#define RADIOLIB_NRF24_ADDRESS_2_BYTES 0b00000000 // 1 0 address width: 2 bytes +#define RADIOLIB_NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 3 bytes +#define RADIOLIB_NRF24_ADDRESS_4_BYTES 0b00000010 // 1 0 4 bytes +#define RADIOLIB_NRF24_ADDRESS_5_BYTES 0b00000011 // 1 0 5 bytes (default) // NRF24_REG_SETUP_RETR -#define NRF24_ARD 0b00000000 // 7 4 auto retransmit delay: t[us] = (NRF24_ARD + 1) * 250 us -#define NRF24_ARC_OFF 0b00000000 // 3 0 auto retransmit count: auto retransmit disabled -#define NRF24_ARC 0b00000011 // 3 0 up to 3 retransmits on AA fail (default) +#define RADIOLIB_NRF24_ARD 0b00000000 // 7 4 auto retransmit delay: t[us] = (NRF24_ARD + 1) * 250 us +#define RADIOLIB_NRF24_ARC_OFF 0b00000000 // 3 0 auto retransmit count: auto retransmit disabled +#define RADIOLIB_NRF24_ARC 0b00000011 // 3 0 up to 3 retransmits on AA fail (default) // NRF24_REG_RF_CH -#define NRF24_RF_CH 0b00000010 // 6 0 RF channel: f_CH[MHz] = 2400 MHz + NRF24_RF_CH +#define RADIOLIB_NRF24_RF_CH 0b00000010 // 6 0 RF channel: f_CH[MHz] = 2400 MHz + NRF24_RF_CH // NRF24_REG_RF_SETUP -#define NRF24_CONT_WAVE_OFF 0b00000000 // 7 7 continuous carrier transmit: disabled (default) -#define NRF24_CONT_WAVE_ON 0b10000000 // 7 7 enabled -#define NRF24_DR_250_KBPS 0b00100000 // 5 5 data rate: 250 kbps -#define NRF24_DR_1_MBPS 0b00000000 // 3 3 1 Mbps (default) -#define NRF24_DR_2_MBPS 0b00001000 // 3 3 2 Mbps -#define NRF24_PLL_LOCK_ON 0b00010000 // 4 4 force PLL lock: enabled -#define NRF24_PLL_LOCK_OFF 0b00000000 // 4 4 disabled (default) -#define NRF24_RF_PWR_18_DBM 0b00000000 // 2 1 output power: -18 dBm -#define NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm -#define NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm -#define NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default) +#define RADIOLIB_NRF24_CONT_WAVE_OFF 0b00000000 // 7 7 continuous carrier transmit: disabled (default) +#define RADIOLIB_NRF24_CONT_WAVE_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_NRF24_DR_250_KBPS 0b00100000 // 5 5 data rate: 250 kbps +#define RADIOLIB_NRF24_DR_1_MBPS 0b00000000 // 3 3 1 Mbps (default) +#define RADIOLIB_NRF24_DR_2_MBPS 0b00001000 // 3 3 2 Mbps +#define RADIOLIB_NRF24_PLL_LOCK_ON 0b00010000 // 4 4 force PLL lock: enabled +#define RADIOLIB_NRF24_PLL_LOCK_OFF 0b00000000 // 4 4 disabled (default) +#define RADIOLIB_NRF24_RF_PWR_18_DBM 0b00000000 // 2 1 output power: -18 dBm +#define RADIOLIB_NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm +#define RADIOLIB_NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm +#define RADIOLIB_NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default) // NRF24_REG_STATUS -#define NRF24_RX_DR 0b01000000 // 6 6 Rx data ready -#define NRF24_TX_DS 0b00100000 // 5 5 Tx data sent -#define NRF24_MAX_RT 0b00010000 // 4 4 maximum number of retransmits reached (must be cleared to continue) -#define NRF24_RX_FIFO_EMPTY 0b00001110 // 3 1 Rx FIFO is empty -#define NRF24_RX_P_NO 0b00000000 // 3 1 number of data pipe that received data -#define NRF24_TX_FIFO_FULL 0b00000001 // 0 0 Tx FIFO is full +#define RADIOLIB_NRF24_RX_DR 0b01000000 // 6 6 Rx data ready +#define RADIOLIB_NRF24_TX_DS 0b00100000 // 5 5 Tx data sent +#define RADIOLIB_NRF24_MAX_RT 0b00010000 // 4 4 maximum number of retransmits reached (must be cleared to continue) +#define RADIOLIB_NRF24_RX_FIFO_EMPTY 0b00001110 // 3 1 Rx FIFO is empty +#define RADIOLIB_NRF24_RX_P_NO 0b00000000 // 3 1 number of data pipe that received data +#define RADIOLIB_NRF24_TX_FIFO_FULL 0b00000001 // 0 0 Tx FIFO is full // NRF24_REG_OBSERVE_TX -#define NRF24_PLOS_CNT 0b00000000 // 7 4 number of lost packets -#define NRF24_ARC_CNT 0b00000000 // 3 0 number of retransmitted packets +#define RADIOLIB_NRF24_PLOS_CNT 0b00000000 // 7 4 number of lost packets +#define RADIOLIB_NRF24_ARC_CNT 0b00000000 // 3 0 number of retransmitted packets // NRF24_REG_RPD -#define NRF24_RP_BELOW_64_DBM 0b00000000 // 0 0 received power in the current channel: less than -64 dBm -#define NRF24_RP_ABOVE_64_DBM 0b00000001 // 0 0 more than -64 dBm +#define RADIOLIB_NRF24_RP_BELOW_64_DBM 0b00000000 // 0 0 received power in the current channel: less than -64 dBm +#define RADIOLIB_NRF24_RP_ABOVE_64_DBM 0b00000001 // 0 0 more than -64 dBm // NRF24_REG_FIFO_STATUS -#define NRF24_TX_REUSE 0b01000000 // 6 6 reusing last transmitted payload -#define NRF24_TX_FIFO_FULL_FLAG 0b00100000 // 5 5 Tx FIFO is full -#define NRF24_TX_FIFO_EMPTY_FLAG 0b00010000 // 4 4 Tx FIFO is empty -#define NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 1 1 Rx FIFO is full -#define NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 0 0 Rx FIFO is empty +#define RADIOLIB_NRF24_TX_REUSE 0b01000000 // 6 6 reusing last transmitted payload +#define RADIOLIB_NRF24_TX_FIFO_FULL_FLAG 0b00100000 // 5 5 Tx FIFO is full +#define RADIOLIB_NRF24_TX_FIFO_EMPTY_FLAG 0b00010000 // 4 4 Tx FIFO is empty +#define RADIOLIB_NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 1 1 Rx FIFO is full +#define RADIOLIB_NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 0 0 Rx FIFO is empty // NRF24_REG_DYNPD -#define NRF24_DPL_P5_OFF 0b00000000 // 5 5 dynamic payload length on pipe 5: disabled (default) -#define NRF24_DPL_P5_ON 0b00100000 // 5 5 enabled -#define NRF24_DPL_P4_OFF 0b00000000 // 4 4 dynamic payload length on pipe 4: disabled (default) -#define NRF24_DPL_P4_ON 0b00010000 // 4 4 enabled -#define NRF24_DPL_P3_OFF 0b00000000 // 3 3 dynamic payload length on pipe 3: disabled (default) -#define NRF24_DPL_P3_ON 0b00001000 // 3 3 enabled -#define NRF24_DPL_P2_OFF 0b00000000 // 2 2 dynamic payload length on pipe 2: disabled (default) -#define NRF24_DPL_P2_ON 0b00000100 // 2 2 enabled -#define NRF24_DPL_P1_OFF 0b00000000 // 1 1 dynamic payload length on pipe 1: disabled (default) -#define NRF24_DPL_P1_ON 0b00000010 // 1 1 enabled -#define NRF24_DPL_P0_OFF 0b00000000 // 0 0 dynamic payload length on pipe 0: disabled (default) -#define NRF24_DPL_P0_ON 0b00000001 // 0 0 enabled -#define NRF24_DPL_ALL_OFF 0b00000000 // 5 0 disable all dynamic payloads -#define NRF24_DPL_ALL_ON 0b00111111 // 5 0 enable all dynamic payloads +#define RADIOLIB_NRF24_DPL_P5_OFF 0b00000000 // 5 5 dynamic payload length on pipe 5: disabled (default) +#define RADIOLIB_NRF24_DPL_P5_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_NRF24_DPL_P4_OFF 0b00000000 // 4 4 dynamic payload length on pipe 4: disabled (default) +#define RADIOLIB_NRF24_DPL_P4_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_NRF24_DPL_P3_OFF 0b00000000 // 3 3 dynamic payload length on pipe 3: disabled (default) +#define RADIOLIB_NRF24_DPL_P3_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_NRF24_DPL_P2_OFF 0b00000000 // 2 2 dynamic payload length on pipe 2: disabled (default) +#define RADIOLIB_NRF24_DPL_P2_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_DPL_P1_OFF 0b00000000 // 1 1 dynamic payload length on pipe 1: disabled (default) +#define RADIOLIB_NRF24_DPL_P1_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_NRF24_DPL_P0_OFF 0b00000000 // 0 0 dynamic payload length on pipe 0: disabled (default) +#define RADIOLIB_NRF24_DPL_P0_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_NRF24_DPL_ALL_OFF 0b00000000 // 5 0 disable all dynamic payloads +#define RADIOLIB_NRF24_DPL_ALL_ON 0b00111111 // 5 0 enable all dynamic payloads // NRF24_REG_FEATURE -#define NRF24_DPL_OFF 0b00000000 // 2 2 dynamic payload length: disabled (default) -#define NRF24_DPL_ON 0b00000100 // 2 2 enabled -#define NRF24_ACK_PAY_OFF 0b00000000 // 1 1 payload with ACK packets: disabled (default) -#define NRF24_ACK_PAY_ON 0b00000010 // 1 1 enabled -#define NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default) -#define NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_NRF24_DPL_OFF 0b00000000 // 2 2 dynamic payload length: disabled (default) +#define RADIOLIB_NRF24_DPL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_ACK_PAY_OFF 0b00000000 // 1 1 payload with ACK packets: disabled (default) +#define RADIOLIB_NRF24_ACK_PAY_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default) +#define RADIOLIB_NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled /*! \class nRF24 @@ -191,6 +191,8 @@ class nRF24: public PhysicalLayer { */ nRF24(Module* mod); + Module* getMod(); + // basic methods /*! From 8e134a7980876c80acf47e818e084093d2c49ffa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:43:25 +0100 Subject: [PATCH 0053/1848] [RFM9x] Update to 5.0.0 --- src/modules/RFM9x/RFM95.cpp | 12 ++++++------ src/modules/RFM9x/RFM95.h | 6 +++--- src/modules/RFM9x/RFM96.cpp | 12 ++++++------ src/modules/RFM9x/RFM96.h | 6 +++--- src/modules/RFM9x/RFM97.cpp | 16 ++++++++-------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 6953873162..2beb4b258a 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -7,12 +7,12 @@ RFM95::RFM95(Module* mod) : SX1278(mod) { int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); - if(state == ERR_CHIP_NOT_FOUND) { + int16_t state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { // SX127X_REG_VERSION might be set 0x12 - state = SX127x::begin(RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); + state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); RADIOLIB_ASSERT(state); - } else if(state != ERR_NONE) { + } else if(state != RADIOLIB_ERR_NONE) { // some other error return(state); } @@ -41,11 +41,11 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW } int16_t RFM95::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 862.0, 1020.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 862.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); diff --git a/src/modules/RFM9x/RFM95.h b/src/modules/RFM9x/RFM95.h index d98ed2ce37..6a6eb1c737 100644 --- a/src/modules/RFM9x/RFM95.h +++ b/src/modules/RFM9x/RFM95.h @@ -10,8 +10,8 @@ #include "../SX127x/SX1278.h" // SX127X_REG_VERSION -#define RFM9X_CHIP_VERSION_OFFICIAL 0x11 -#define RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 +#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 +#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 /*! \class RFM95 @@ -55,7 +55,7 @@ class RFM95: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); // configuration methods diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index ff937eb8a0..4e510a3aa6 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -7,12 +7,12 @@ RFM96::RFM96(Module* mod) : SX1278(mod) { int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); - if(state == ERR_CHIP_NOT_FOUND) { + int16_t state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { // SX127X_REG_VERSION might be set 0x12 - state = SX127x::begin(RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); + state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); RADIOLIB_ASSERT(state); - } else if(state != ERR_NONE) { + } else if(state != RADIOLIB_ERR_NONE) { // some other error return(state); } @@ -42,11 +42,11 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW } int16_t RFM96::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 410.0, 525.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 410.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_freq = freq; } return(state); diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h index 31a72cd60e..85389d3442 100644 --- a/src/modules/RFM9x/RFM96.h +++ b/src/modules/RFM9x/RFM96.h @@ -10,8 +10,8 @@ #include "../SX127x/SX1278.h" // SX127X_REG_VERSION -#define RFM9X_CHIP_VERSION_OFFICIAL 0x11 -#define RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 +#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 +#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 /*! \class RFM96 @@ -55,7 +55,7 @@ class RFM96: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); // configuration methods diff --git a/src/modules/RFM9x/RFM97.cpp b/src/modules/RFM9x/RFM97.cpp index ccf19134b1..e51e5a9945 100644 --- a/src/modules/RFM9x/RFM97.cpp +++ b/src/modules/RFM9x/RFM97.cpp @@ -7,8 +7,8 @@ RFM97::RFM97(Module* mod) : RFM95(mod) { int16_t RFM97::setSpreadingFactor(uint8_t sf) { // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newSpreadingFactor; @@ -16,24 +16,24 @@ int16_t RFM97::setSpreadingFactor(uint8_t sf) { // check allowed spreading factor values switch(sf) { case 6: - newSpreadingFactor = SX127X_SF_6; + newSpreadingFactor = RADIOLIB_SX127X_SF_6; break; case 7: - newSpreadingFactor = SX127X_SF_7; + newSpreadingFactor = RADIOLIB_SX127X_SF_7; break; case 8: - newSpreadingFactor = SX127X_SF_8; + newSpreadingFactor = RADIOLIB_SX127X_SF_8; break; case 9: - newSpreadingFactor = SX127X_SF_9; + newSpreadingFactor = RADIOLIB_SX127X_SF_9; break; default: - return(ERR_INVALID_SPREADING_FACTOR); + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } // set spreading factor and if successful, save the new setting int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); - if(state == ERR_NONE) { + if(state == RADIOLIB_ERR_NONE) { SX127x::_sf = sf; } return(state); From a6d901d57797266ec3af5ceaaa2d11277f95f661 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:43:32 +0100 Subject: [PATCH 0054/1848] [LLCC68] Update to 5.0.0 --- src/modules/LLCC68/LLCC68.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index cf9cb66c6d..dae54b5969 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -6,23 +6,23 @@ LLCC68::LLCC68(Module* mod) : SX1262(mod) { } int16_t LLCC68::setBandwidth(float bw) { - RADIOLIB_CHECK_RANGE(bw, 100.0, 510.0, ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); return(SX1262::setBandwidth(bw)); } int16_t LLCC68::setSpreadingFactor(uint8_t sf) { switch(SX126x::_bw) { - case SX126X_LORA_BW_125_0: - RADIOLIB_CHECK_RANGE(sf, 5, 9, ERR_INVALID_SPREADING_FACTOR); + case RADIOLIB_SX126X_LORA_BW_125_0: + RADIOLIB_CHECK_RANGE(sf, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); break; - case SX126X_LORA_BW_250_0: - RADIOLIB_CHECK_RANGE(sf, 5, 10, ERR_INVALID_SPREADING_FACTOR); + case RADIOLIB_SX126X_LORA_BW_250_0: + RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); break; - case SX126X_LORA_BW_500_0: - RADIOLIB_CHECK_RANGE(sf, 5, 11, ERR_INVALID_SPREADING_FACTOR); + case RADIOLIB_SX126X_LORA_BW_500_0: + RADIOLIB_CHECK_RANGE(sf, 5, 11, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); break; default: - return(ERR_INVALID_SPREADING_FACTOR); + return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } return(SX1262::setSpreadingFactor(sf)); From f233dbffcbb33e72d7b0303f3fcbe249dde10025 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:43:43 +0100 Subject: [PATCH 0055/1848] Update to 5.0.0 --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 563d444fb5..4bf96194b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,7 +52,7 @@ It is very easy to write code that machine can read. It is much harder to write // build a temporary buffer (first block) uint8_t* data = new uint8_t[len + 1]; if(!data) { - return(ERR_MEMORY_ALLOCATION_FAILED); + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } // read the received data (second block) @@ -73,12 +73,12 @@ Sometimes, RadioLib might be used in critical applications where dynamic memory ```c++ // build a temporary buffer -#ifdef RADIOLIB_STATIC_ONLY +#if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; if(!data) { - return(ERR_MEMORY_ALLOCATION_FAILED); + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } #endif @@ -86,7 +86,7 @@ Sometimes, RadioLib might be used in critical applications where dynamic memory readData(data, length); // deallocate temporary buffer -#ifndef RADIOLIB_STATIC_ONLY +#if !defined(RADIOLIB_STATIC_ONLY) delete[] data; #endif ``` @@ -98,7 +98,7 @@ During development, it can be useful to have access to the low level drivers, su class Module { void publicMethod(); -#ifndef RADIOLIB_GODMODE +#if defined(RADIOLIB_GODMODE) private: #endif From 9e9a65e19efc004f8976c32b9a9cc3ee8f978cfd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:47:33 +0100 Subject: [PATCH 0056/1848] Added missing macro guard --- src/Module.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Module.h b/src/Module.h index 6c44033bd5..53cfb589f6 100644 --- a/src/Module.h +++ b/src/Module.h @@ -3,7 +3,9 @@ #include "TypeDef.h" -#include +#if defined(RADIOLIB_BUILD_ARDUINO) + #include +#endif /*! \class Module From 5b1c793563f3cd3a3bd4fcabdd563639e200287b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:48:51 +0100 Subject: [PATCH 0057/1848] Added custom Arduino API arg macros --- src/BuildOpt.h | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index ba163c1d9d..12ecf7784e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -55,6 +55,28 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino API callbacks + // the following are signatures of Arduino API functions of the custom platform + // for example, pinMode on Arduino Uno is defined as void pinMode(uint8_t pin, uint8_t mode) + // all fo the callbacks below are taken from Arduino Uno + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + // the following must be defined if the Arduino core does not support tone function //#define RADIOLIB_TONE_UNSUPPORTED @@ -736,16 +758,8 @@ #else // generic non-Arduino platform #define RADIOLIB_PLATFORM "Generic" - #define RADIOLIB_PIN_TYPE int - #define RADIOLIB_PIN_MODE int - #define RADIOLIB_PIN_STATUS int - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) (p) - #define RADIOLIB_NC (-1) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // platform properties may be defined here, or somewhere else in the build system #endif From e2cedd1fbe871e55bc810d70862504db35d205dc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 11:50:44 +0100 Subject: [PATCH 0058/1848] Removed unused keywords CI_BUILD_ALL --- keywords.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index 00db446d65..7876882e7a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,7 +9,6 @@ RadioLib KEYWORD1 RadioShield KEYWORD1 Module KEYWORD1 -SerialModule KEYWORD1 # modules CC1101 KEYWORD1 @@ -43,7 +42,6 @@ SX1282 KEYWORD1 # protocols RTTYClient KEYWORD1 MorseClient KEYWORD1 -PagerClient KEYWORD1 AX25Client KEYWORD1 AX25Frame KEYWORD1 SSTVClient KEYWORD1 From 53d7a6a57713080bf6424ba9bf883da62f8046ee Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 12:28:05 +0100 Subject: [PATCH 0059/1848] [AX.25] Fixed macro names --- examples/AX25/AX25_Frames/AX25_Frames.ino | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index 232d05e228..809d7176c3 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -90,9 +90,9 @@ void loop() { // control field: UI, P/F not used, unnumbered frame // protocol identifier: no layer 3 protocol implemented // information field: "Hello World!" - AX25Frame frameUI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_U_UNNUMBERED_INFORMATION | - AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_UNNUMBERED_FRAME, - AX25_PID_NO_LAYER_3, "Hello World (unnumbered)!"); + AX25Frame frameUI("NJ7P", 0, "N7LEM", 0, RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, + RADIOLIB_AX25_PID_NO_LAYER_3, "Hello World (unnumbered)!"); // send the frame Serial.print(F("[AX.25] Sending UI frame ... ")); @@ -116,8 +116,8 @@ void loop() { // source station callsign: "N7LEM" // source station SSID: 0 // control field: RR, P/F not used, supervisory frame - AX25Frame frameRR("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_S_RECEIVE_READY | - AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_SUPERVISORY_FRAME); + AX25Frame frameRR("NJ7P", 0, "N7LEM", 0, RADIOLIB_AX25_CONTROL_S_RECEIVE_READY | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_SUPERVISORY_FRAME); // set receive sequence number (0 - 7) frameRR.setRecvSequence(0); @@ -146,8 +146,8 @@ void loop() { // control field: P/F not used, information frame // protocol identifier: no layer 3 protocol implemented // information field: "Hello World (numbered)!" - AX25Frame frameI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_POLL_FINAL_DISABLED | - AX25_CONTROL_INFORMATION_FRAME, AX25_PID_NO_LAYER_3, + AX25Frame frameI("NJ7P", 0, "N7LEM", 0, RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | + RADIOLIB_AX25_CONTROL_INFORMATION_FRAME, RADIOLIB_AX25_PID_NO_LAYER_3, "Hello World (numbered)!"); // set receive sequence number (0 - 7) From ebd9cb414775ab787e2206eaaa936c01b95e90f0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 12:35:45 +0100 Subject: [PATCH 0060/1848] Renamed callback build macros --- src/BuildOpt.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 12ecf7784e..3a8f916c0a 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -889,17 +889,17 @@ * Come one, come all and witness the horror: * Variadics, forced expansions, inlined function, string concatenation, and it even messes up access specifiers. */ -#define FIRST(arg, ...) arg -#define REST(arg, ...) __VA_ARGS__ -#define EXP(...) __VA_ARGS__ +#define RADIOLIB_FIRST(arg, ...) arg +#define RADIOLIB_REST(arg, ...) __VA_ARGS__ +#define RADIOLIB_EXP(...) __VA_ARGS__ #define RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, FUNC, ...) public: typedef RET (*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC; #define RADIOLIB_GENERATE_CALLBACK_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, __VA_ARGS__) -#define RADIOLIB_GENERATE_CALLBACK(CB) RADIOLIB_GENERATE_CALLBACK_RET(EXP(FIRST CB), EXP(REST CB)) +#define RADIOLIB_GENERATE_CALLBACK(CB) RADIOLIB_GENERATE_CALLBACK_RET(RADIOLIB_EXP(RADIOLIB_FIRST CB), RADIOLIB_EXP(RADIOLIB_REST CB)) #define RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, FUNC, ...) public: typedef RET (Module::*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC; #define RADIOLIB_GENERATE_CALLBACK_SPI_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, __VA_ARGS__) -#define RADIOLIB_GENERATE_CALLBACK_SPI(CB) RADIOLIB_GENERATE_CALLBACK_SPI_RET(EXP(FIRST CB), EXP(REST CB)) +#define RADIOLIB_GENERATE_CALLBACK_SPI(CB) RADIOLIB_GENERATE_CALLBACK_SPI_RET(RADIOLIB_EXP(RADIOLIB_FIRST CB), RADIOLIB_EXP(RADIOLIB_REST CB)) /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled From 8deec71b6f1db3b1eb3ff559a3b0a13d1a6b917f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 12:36:00 +0100 Subject: [PATCH 0061/1848] Use Arduino tone/noTone --- examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index f632817257..caf4fe4a44 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -175,15 +175,17 @@ void loop() { Serial.println(state); } - // transmit FM tone at 1000 Hz for 1 second + // transmit FM tone at 1000 Hz for 1 second, then 500 Hz for 1 second // (DIO2 is connected to Arduino pin 4) // Note: tone() function is not available on ESP32, Arduino Due and CubeCell // on these platforms, the following will do nothing - Module::tone(4, 1000); + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + tone(4, 1000); delay(1000); - // transmit FM note at 500 Hz for 1 second - Module::tone(4, 500); + tone(4, 500); delay(1000); + noTone(4); + #endif // NOTE: after calling transmitDirect(), SX127x will start // transmitting immediately! This signal can jam other From 4eeab0f55d20a5a66a72b9f47f7dd3a08f972e39 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 12:49:17 +0100 Subject: [PATCH 0062/1848] Updated readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 493983ae08..57fabc2120 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ ### _One radio library to rule them all!_ -## Universal wireless communication library for Arduino +## Universal wireless communication library for embedded devices ## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference. RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system. Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not! -RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your Arduino can handle! +RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your microcontroller can handle! ### Supported modules: * __CC1101__ FSK radio module @@ -36,7 +36,7 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x -### Supported platforms: +### Supported Arduino platforms: * __Arduino__ * [__AVR__](https://github.com/arduino/ArduinoCore-avr) - Arduino Uno, Mega, Leonardo, Pro Mini, Nano etc. * [__mbed__](https://github.com/arduino/ArduinoCore-mbed) - Arduino Nano 33 BLE and Arduino Portenta H7 @@ -71,7 +71,7 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __Heltec__ * [__CubeCell__](https://github.com/HelTecAutomation/CubeCell-Arduino) - ASR650X series (CubeCell-Board, CubeCell-Capsule, CubeCell-Module etc.) -The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platforms prior to releasing new version. +The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. ### In development: * __AX5243__ FSK module @@ -88,4 +88,4 @@ First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/ The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new/choose) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently. ### RadioLib doesn't support my module! What should I do? -Start by creating new issue (if it doesn't exist yet). If you have some experience with Arduino and C/C++ in general, you can try to add the support yourself! Use the template files in `/extras/` folder to get started. This is by far the fastest way to implement new modules into RadioLib, since I can't be working on everything all the time. If you don't trust your programming skills enough to have a go at it yourself, don't worry. I will try to implement all requested modules, but it will take me a while. +Start by creating new issue (if it doesn't exist yet). If you have some experience with microcontrollers and C/C++ in general, you can try to add the support yourself! Use the template files in `/extras/` folder to get started. This is by far the fastest way to implement new modules into RadioLib, since I can't be working on everything all the time. If you don't trust your programming skills enough to have a go at it yourself, don't worry. I will try to implement all requested modules, but it will take me a while. From 22ae7dfd9b73eea9f8ed8361b7a2b1f7cec35ef2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 13:00:28 +0100 Subject: [PATCH 0063/1848] [RF69] Update macro names --- src/modules/RF69/RF69.cpp | 8 ++++---- src/modules/RF69/RF69.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index a479f7e1c7..62ce873c9b 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -393,11 +393,11 @@ int16_t RF69::setOokThresholdType(uint8_t type) { } int16_t RF69::setOokFixedThreshold(uint8_t value) { - return(_mod->SPIsetRegValue(RF69_REG_OOK_FIX, value, 7, 0, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_FIX, value, 7, 0, 5)); } int16_t RF69::setOokPeakThresholdDecrement(uint8_t value) { - return(_mod->SPIsetRegValue(RF69_REG_OOK_PEAK, value, 2, 0, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, value, 2, 0, 5)); } int16_t RF69::setFrequency(float freq) { @@ -725,11 +725,11 @@ int16_t RF69::disableSyncWordFiltering() { } int16_t RF69::enableContinuousModeBitSync() { - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); } int16_t RF69::disableContinuousModeBitSync() { - return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE, 6, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5)); } int16_t RF69::setCrcFiltering(bool crcOn) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 311962708e..d91382f2d1 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -753,7 +753,7 @@ class RF69: public PhysicalLayer { /*! \brief Selects the type of threshold in the OOK data slicer - \param type Threshold type: RF69_OOK_THRESH_PEAK(default), RF69_OOK_THRESH_FIXED or RF69_OOK_THRESH_AVERAGE + \param type Threshold type: RADIOLIB_RF69_OOK_THRESH_PEAK(default), RADIOLIB_RF69_OOK_THRESH_FIXED or RADIOLIB_RF69_OOK_THRESH_AVERAGE \returns \ref status_codes */ @@ -762,7 +762,7 @@ class RF69: public PhysicalLayer { /*! \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. - \param value Fixed threshold value (in dB) in the OOK demodulator. Used when OokThresType = RF69_OOK_THRESH_FIXED. + \param value Fixed threshold value (in dB) in the OOK demodulator. Used when OokThresType = RADIOLIB_RF69_OOK_THRESH_FIXED. \returns \ref status_codes */ @@ -771,7 +771,7 @@ class RF69: public PhysicalLayer { /*! \brief Period of decrement of the RSSI threshold in the OOK demodulator. - \param value Use defines RF69_OOK_PEAK_THRESH_DEC_X_X_CHIP + \param value Use defines RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_X_X_CHIP \returns \ref status_codes */ From 03126f79d302d3cc6f7ec62bb444352b1ea3a683 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 13:00:34 +0100 Subject: [PATCH 0064/1848] [SX127x] Update macro names --- src/modules/SX127x/SX127x.cpp | 4 ++-- src/modules/SX127x/SX127x.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7be655d6b6..31baba137d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -944,11 +944,11 @@ int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { } int16_t SX127x::enableBitSync() { - return(_mod->SPIsetRegValue(SX127X_REG_OOK_PEAK, SX127X_BIT_SYNC_ON, 5, 5, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5)); } int16_t SX127x::disableBitSync() { - return(_mod->SPIsetRegValue(SX127X_REG_OOK_PEAK, SX127X_BIT_SYNC_OFF, 5, 5, 5)); + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5)); } int16_t SX127x::setOOK(bool enableOOK) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 30ca62cab1..e37c498d9f 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -914,7 +914,7 @@ class SX127x: public PhysicalLayer { /*! \brief Period of decrement of the RSSI threshold in the OOK demodulator. - \param value Use defines SX127X_OOK_PEAK_THRESH_DEC_X_X_CHIP + \param value Use defines RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_X_X_CHIP \returns \ref status_codes */ @@ -923,7 +923,7 @@ class SX127x: public PhysicalLayer { /*! \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. - \param value The actual value is devided by 2 because (0.5db step). ie: value=12 means 6dB + \param value Threshold level in steps of 0.5 dB. \returns \ref status_codes */ From 9d5a66573efe2b4b7a5b74d72aaaab885857cb3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 14:03:32 +0100 Subject: [PATCH 0065/1848] Indentation fix CI_BUILD_ALL --- src/TypeDef.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index 27751dc258..6a0b0a6083 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -12,27 +12,27 @@ /*! \brief No shaping. */ -#define RADIOLIB_SHAPING_NONE (0x00) +#define RADIOLIB_SHAPING_NONE (0x00) /*! \brief Gaussin shaping filter, BT = 0.3 */ -#define RADIOLIB_SHAPING_0_3 (0x01) +#define RADIOLIB_SHAPING_0_3 (0x01) /*! \brief Gaussin shaping filter, BT = 0.5 */ -#define RADIOLIB_SHAPING_0_5 (0x02) +#define RADIOLIB_SHAPING_0_5 (0x02) /*! \brief Gaussin shaping filter, BT = 0.7 */ -#define RADIOLIB_SHAPING_0_7 (0x03) +#define RADIOLIB_SHAPING_0_7 (0x03) /*! \brief Gaussin shaping filter, BT = 1.0 */ -#define RADIOLIB_SHAPING_1_0 (0x04) +#define RADIOLIB_SHAPING_1_0 (0x04) /*! \} @@ -47,17 +47,17 @@ /*! \brief Non-return to zero - no encoding. */ -#define RADIOLIB_ENCODING_NRZ (0x00) +#define RADIOLIB_ENCODING_NRZ (0x00) /*! \brief Manchester encoding. */ -#define RADIOLIB_ENCODING_MANCHESTER (0x01) +#define RADIOLIB_ENCODING_MANCHESTER (0x01) /*! \brief Whitening. */ -#define RADIOLIB_ENCODING_WHITENING (0x02) +#define RADIOLIB_ENCODING_WHITENING (0x02) /*! \} From 01f98e4d4c4c8f8aaa6bc1f6320f642dde011e9a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Nov 2021 14:13:50 +0100 Subject: [PATCH 0066/1848] Fixed digitalRead for Arduino Zero CI_BUILD_ALL --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 3a8f916c0a..745127092e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -306,7 +306,7 @@ // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pinNumber, PinMode pinMode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pinNumber, PinStatus status) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, pin_size_t pinNumber) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pinNumber) #define RADIOLIB_CB_ARGS_TONE (void, tone, unsigned char outputPin, unsigned int frequency, unsigned long duration) #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t outputPin) #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t pin, voidFuncPtr callback, PinStatus mode) From ffda180513a48971a7e9bbcf75819e65d3836010 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 16 Nov 2021 10:05:58 +0100 Subject: [PATCH 0067/1848] Fixed incorrect macro guards --- src/BuildOpt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 745127092e..cecf066363 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -819,7 +819,7 @@ * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. * Failure to heed the above warning may result in bricked module. */ -#if !defined(RADIOLIB_FIX_ERRATA_SX127X) +#if !defined(RADIOLIB_GODMODE) //#define RADIOLIB_GODMODE #endif @@ -828,7 +828,7 @@ * This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite" * Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this. */ -#if !defined(RADIOLIB_FIX_ERRATA_SX127X) +#if !defined(RADIOLIB_LOW_LEVEL) //#define RADIOLIB_LOW_LEVEL #endif @@ -843,7 +843,7 @@ * Uncomment to enable static-only memory management: no dynamic allocation will be performed. * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. */ -#if !defined(RADIOLIB_FIX_ERRATA_SX127X) +#if !defined(RADIOLIB_STATIC_ONLY) //#define RADIOLIB_STATIC_ONLY #endif From 88c1078ac746dc5927a65145b54c7da80002f888 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 16 Nov 2021 10:06:27 +0100 Subject: [PATCH 0068/1848] Added missing static macro guards (#407) --- src/protocols/RTTY/RTTY.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 432a645378..95d110186c 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -3,14 +3,18 @@ ITA2String::ITA2String(char c) { _len = 1; + #if !defined(RADIOLIB_STATIC_ONLY) _str = new char[1]; + #endif _str[0] = c; _ita2Len = 0; } ITA2String::ITA2String(const char* str) { _len = strlen(str); + #if !defined(RADIOLIB_STATIC_ONLY) _str = new char[_len + 1]; + #endif strcpy(_str, str); _ita2Len = 0; } From f8bdbae73a80b1842aabc624435dbde5b5f10133 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 16 Nov 2021 10:22:10 +0100 Subject: [PATCH 0069/1848] Fixed RadioShield definition --- src/BuildOpt.h | 2 +- src/RadioLib.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index cecf066363..e0924c94dc 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -835,7 +835,7 @@ /* * Uncomment to enable pre-defined modules when using RadioShield. */ -#if !defined(RADIOLIB_FIX_ERRATA_SX127X) +#if !defined(RADIOLIB_RADIOSHIELD) //#define RADIOLIB_RADIOSHIELD #endif diff --git a/src/RadioLib.h b/src/RadioLib.h index b7bca87c41..92b659ddeb 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -94,14 +94,14 @@ #if defined(RADIOLIB_RADIOSHIELD) // RadioShield pin definitions -#define RADIOSHIELD_CS_A 10 -#define RADIOSHIELD_RX_A 9 -#define RADIOSHIELD_TX_A 8 -#define RADIOSHIELD_CS_B 5 -#define RADIOSHIELD_RX_B 7 -#define RADIOSHIELD_TX_B 6 -#define RADIOSHIELD_INT_0 2 -#define RADIOSHIELD_INT_1 3 +#define RADIOSHIELD_CS_A 10 +#define RADIOSHIELD_IRQ_A 2 +#define RADIOSHIELD_RST_A 9 +#define RADIOSHIELD_GPIO_A 8 +#define RADIOSHIELD_CS_B 5 +#define RADIOSHIELD_IRQ_B 3 +#define RADIOSHIELD_RST_B 7 +#define RADIOSHIELD_GPIO_B 6 /*! \class Radio @@ -119,8 +119,8 @@ class Radio { \brief Default constructor. Only used to set ModuleA and ModuleB configuration. */ Radio() { - ModuleA = new Module(RADIOSHIELD_CS_A, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_A, RADIOSHIELD_TX_A, SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), nullptr); - ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_B, RADIOSHIELD_TX_B, SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), nullptr); + ModuleA = new Module(RADIOSHIELD_CS_A, RADIOSHIELD_IRQ_A, RADIOSHIELD_RST_A, RADIOSHIELD_GPIO_A); + ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_IRQ_B, RADIOSHIELD_RST_B, RADIOSHIELD_GPIO_B); } #if defined(RADIOLIB_GODMODE) From 77689e81e0c667113a272c4a302caa3a17619b48 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:16:23 +0100 Subject: [PATCH 0070/1848] [PHY] Fixed known binary receive length --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 5 ----- src/protocols/PhysicalLayer/PhysicalLayer.h | 6 ++++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index d6aec9f053..58bb9231a0 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -103,11 +103,6 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { // user can override the length of data to read size_t length = len; - if(len == 0) { - // unknown packet length, set to maximum - length = _maxPacketLength; - } - // build a temporary buffer #if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 0245b8f450..425dddc727 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -144,7 +144,8 @@ class PhysicalLayer { \param str Address of Arduino String to save the received data. - \param len Expected number of characters in the message. + \param len Expected number of characters in the message. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -155,7 +156,8 @@ class PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ From e4eec9c5bd5fd7300bf810ae94a317add3643781 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:16:31 +0100 Subject: [PATCH 0071/1848] [nRF24] Fixed known binary receive length --- src/modules/nRF24/nRF24.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 683d22f65a..d767dbd3f9 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -231,9 +231,10 @@ int16_t nRF24::readData(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // get packet length - size_t length = len; - if(len == RADIOLIB_NRF24_MAX_PACKET_LENGTH) { - length = getPacketLength(); + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; } // read packet data From c99e79073f9fc2ae6ff70179d9dad12502cca8c3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:16:37 +0100 Subject: [PATCH 0072/1848] [Si443x] Fixed known binary receive length --- src/modules/Si443x/Si443x.cpp | 21 ++++++++++++++++++--- src/modules/Si443x/Si443x.h | 4 +++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 5c48561363..1e4221e971 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -285,14 +285,22 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { clearIRQFlags(); // get packet length - size_t length = len; - if(len == RADIOLIB_SI443X_MAX_PACKET_LENGTH) { - length = getPacketLength(); + size_t length = getPacketLength(); + size_t dumpLen = 0; + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + dumpLen = length - len; + length = len; } // read packet data _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, length, data); + // dump the bytes that weren't requested + if(dumpLen != 0) { + clearFIFO(dumpLen); + } + // clear internal flag so getPacketLength can return the new packet length _packetLengthQueried = false; @@ -647,6 +655,13 @@ void Si443x::clearIRQFlags() { _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); } +void Si443x::clearFIFO(size_t count) { + while(count) { + _mod->SPIreadRegister(RADIOLIB_SI443X_REG_FIFO_ACCESS); + count--; + } +} + int16_t Si443x::config() { // set mode to standby int16_t state = standby(); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 1072e289ff..9a5c0df16f 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -695,7 +695,8 @@ class Si443x: public PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -838,6 +839,7 @@ class Si443x: public PhysicalLayer { #endif bool findChip(); void clearIRQFlags(); + void clearFIFO(size_t count); int16_t config(); int16_t updateClockRecovery(); int16_t directMode(); From c2cfe597ccbc9f7f0164850ece391d8a00d715ab Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:16:45 +0100 Subject: [PATCH 0073/1848] [SX128x] Fixed known binary receive length --- src/modules/SX128x/SX128x.cpp | 7 ++++--- src/modules/SX128x/SX128x.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index cdf797d6d9..972e6ffc35 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -573,9 +573,10 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { } // get packet length - size_t length = len; - if(len == RADIOLIB_SX128X_MAX_PACKET_LENGTH) { - length = getPacketLength(); + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; } // read packet data diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index b1a39e94e6..9f258bb121 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -567,7 +567,8 @@ class SX128x: public PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ From 3047409b2704fb04bd1f14c485dfadbceabe2f80 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:16:51 +0100 Subject: [PATCH 0074/1848] [SX127x] Fixed known binary receive length --- src/modules/SX127x/SX127x.cpp | 25 ++++++++++++------------- src/modules/SX127x/SX127x.h | 3 ++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 31baba137d..3295a5cc6a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -496,17 +496,20 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX127x::readData(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); - size_t length = len; // put module to standby standby(); - if(modem == RADIOLIB_SX127X_LORA) { - // len set to maximum indicates unknown packet length, read the number of actually received bytes - if(len == RADIOLIB_SX127X_MAX_PACKET_LENGTH) { - length = getPacketLength(); - } + // get packet length + size_t length = getPacketLength(); + size_t dumpLen = 0; + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + dumpLen = length - len; + length = len; + } + if(modem == RADIOLIB_SX127X_LORA) { // check packet header integrity if(_crcEnabled && (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6)) == 0) { // CRC is disabled according to packet header and enabled according to user @@ -523,9 +526,6 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // read packet length (always required in FSK) - length = getPacketLength(); - // check address filtering uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { @@ -536,10 +536,9 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // read packet data _mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data); - // dump bytes that weren't requested - size_t packetLength = getPacketLength(); - if(packetLength > length) { - clearFIFO(packetLength - length); + // dump the bytes that weren't requested + if(dumpLen != 0) { + clearFIFO(dumpLen); } // clear internal flag so getPacketLength can return the new packet length diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e37c498d9f..b61ca3b687 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -730,7 +730,8 @@ class SX127x: public PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ From f3de4602e69576ac1ed036478c37c2810455249f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:16:58 +0100 Subject: [PATCH 0075/1848] [SX126x] Fixed known binary receive length --- src/modules/SX126x/SX126x.cpp | 7 ++++--- src/modules/SX126x/SX126x.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2a308f1a8b..a8f4b013bf 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -563,9 +563,10 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { } // get packet length - size_t length = len; - if(len == RADIOLIB_SX126X_MAX_PACKET_LENGTH) { - length = getPacketLength(); + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; } // read packet data diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 79564f2fef..bd9525ce10 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -550,7 +550,8 @@ class SX126x: public PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ From 90b9bd02fb1333cea8151a478abb372a1ffee5ff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:17:10 +0100 Subject: [PATCH 0076/1848] [CC1101] Fixed known binary receive length --- src/modules/CC1101/CC1101.cpp | 7 ++++--- src/modules/CC1101/CC1101.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 5b6f441f4b..7af7fa82bc 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -335,9 +335,10 @@ int16_t CC1101::startReceive() { int16_t CC1101::readData(uint8_t* data, size_t len) { // get packet length - size_t length = len; - if (len == RADIOLIB_CC1101_MAX_PACKET_LENGTH) { - length = getPacketLength(true); + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; } // check address filtering diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 90c439abbe..7223042e12 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -652,7 +652,8 @@ class CC1101: public PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ From 1d4295feed7e6c9227d98ffdb34c9a87e4242cc3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Nov 2021 21:17:26 +0100 Subject: [PATCH 0077/1848] [RF69] Fixed known binary receive length (#408) --- src/modules/RF69/RF69.cpp | 21 ++++++++++++++++++--- src/modules/RF69/RF69.h | 4 +++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 62ce873c9b..8a41666cf4 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -347,9 +347,12 @@ int16_t RF69::readData(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // get packet length - size_t length = len; - if(len == RADIOLIB_RF69_MAX_PACKET_LENGTH) { - length = getPacketLength(); + size_t length = getPacketLength(); + size_t dumpLen = 0; + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + dumpLen = length - len; + length = len; } // check address filtering @@ -361,6 +364,11 @@ int16_t RF69::readData(uint8_t* data, size_t len) { // read packet data _mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, length, data); + // dump the bytes that weren't requested + if(dumpLen != 0) { + clearFIFO(dumpLen); + } + // clear internal flag so getPacketLength can return the new packet length _packetLengthQueried = false; @@ -935,4 +943,11 @@ void RF69::clearIRQFlags() { _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, 0b11111111); } +void RF69::clearFIFO(size_t count) { + while(count) { + _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + count--; + } +} + #endif diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d91382f2d1..697f99fe6a 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -616,7 +616,8 @@ class RF69: public PhysicalLayer { \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -950,6 +951,7 @@ class RF69: public PhysicalLayer { #endif int16_t setMode(uint8_t mode); void clearIRQFlags(); + void clearFIFO(size_t count); }; #endif From 7545343f0c2fcf51614202a542ad17b8b8d60d24 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 26 Nov 2021 08:02:49 +0100 Subject: [PATCH 0078/1848] [AX.25] Ensure transmission is stopped in AFSK mode (#411) --- src/protocols/AX25/AX25.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 790582fb3e..328f6950cf 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -415,6 +415,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } _audio->noTone(); + _phy->standby(); } else { #endif From afe524cfc7620aa1e0a35ab53e2e3942e9db5f95 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 10:20:51 +0100 Subject: [PATCH 0079/1848] [SX126x] Added builtin module for CubeCell (#412) --- .../SX126x_Channel_Activity_Detection.ino | 3 +++ ...x_Channel_Activity_Detection_Interrupt.ino | 3 +++ .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 3 +++ .../SX126x_PingPong/SX126x_PingPong.ino | 19 +++++++++++-------- .../SX126x/SX126x_Receive/SX126x_Receive.ino | 3 +++ .../SX126x_Receive_Interrupt.ino | 3 +++ .../SX126x_Settings/SX126x_Settings.ino | 3 +++ .../SX126x_Transmit/SX126x_Transmit.ino | 3 +++ .../SX126x_Transmit_Interrupt.ino | 3 +++ keywords.txt | 2 ++ src/BuildOpt.h | 5 +++++ 11 files changed, 42 insertions(+), 8 deletions(-) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino index 8a5b6e163f..8b28f2054a 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino @@ -29,6 +29,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index 2598e68c43..ed658daaf6 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -29,6 +29,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index 7231da009d..d3b910dbfe 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -30,6 +30,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index 1f0f8688fb..30c1550bb9 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -26,6 +26,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + // save transmission states between loops int transmissionState = RADIOLIB_ERR_NONE; @@ -105,17 +108,17 @@ void loop() { if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); - + } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); - + } // listen for response radio.startReceive(); transmitFlag = false; - + } else { // the previous operation was reception // print data and send another packet @@ -125,21 +128,21 @@ void loop() { if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1262] Received packet!")); - + // print data of the packet Serial.print(F("[SX1262] Data:\t\t")); Serial.println(str); - + // print RSSI (Received Signal Strength Indicator) Serial.print(F("[SX1262] RSSI:\t\t")); Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); - + // print SNR (Signal-to-Noise Ratio) Serial.print(F("[SX1262] SNR:\t\t")); Serial.print(radio.getSNR()); Serial.println(F(" dB")); - + } // wait a second before transmitting again @@ -154,6 +157,6 @@ void loop() { // we're ready to process more packets, // enable interrupt service routine enableInterrupt = true; - + } } diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino index 0c862e69f4..364509ea4a 100644 --- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino +++ b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino @@ -34,6 +34,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 2a732d91b3..d50f2849ed 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -35,6 +35,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index f33c9aa04a..b601ae181a 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -45,6 +45,9 @@ SX1268 radio2 = new Module(8, 4, 5, 6); // https://github.com/jgromes/RadioShield //SX1261 radio3 = RadioShield.ModuleB; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino index 5b4c5d0d33..c4857e2a6f 100644 --- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino +++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino @@ -30,6 +30,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 0ec70f65ee..19e76817c2 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -31,6 +31,9 @@ SX1262 radio = new Module(10, 2, 3, 9); // https://github.com/jgromes/RadioShield //SX1262 radio = RadioShield.ModuleA; +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); + // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/keywords.txt b/keywords.txt index e29eece109..7b86be5d26 100644 --- a/keywords.txt +++ b/keywords.txt @@ -234,6 +234,8 @@ RADIOLIB_ENCODING_NRZ LITERAL1 RADIOLIB_ENCODING_MANCHESTER LITERAL1 RADIOLIB_ENCODING_WHITENING LITERAL1 +RADIOLIB_BUILTIN_MODULE LITERAL1 + RADIOLIB_ERR_NONE LITERAL1 RADIOLIB_ERR_UNKNOWN LITERAL1 diff --git a/src/BuildOpt.h b/src/BuildOpt.h index e0924c94dc..e5221e5dfb 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -27,6 +27,7 @@ * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword. * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. + * RADIOLIB_BUILTIN_MODULE - some platforms have a builtin radio module on fixed pins, this macro is used to specify that pinout. * * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). * @@ -699,6 +700,10 @@ #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + // provide an easy access to the on-board module + #include "board-config.h" + #define RADIOLIB_BUILTIN_MODULE RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY + // CubeCell doesn't seem to define nullptr, let's do something like that now #define nullptr NULL From cc7551997236fd5153e4e315a8ced28f9c3f367f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 17:35:36 +0100 Subject: [PATCH 0080/1848] [AX.25] Removed redundant call to standby --- src/protocols/AX25/AX25.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 328f6950cf..790582fb3e 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -415,7 +415,6 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } _audio->noTone(); - _phy->standby(); } else { #endif From fe4830afa01f5d24df9844320e2ad669a33da124 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 17:53:17 +0100 Subject: [PATCH 0081/1848] [SX127x] Set default AFC/AGC trigger to RSSI (#402) --- src/modules/SX127x/SX127x.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 3295a5cc6a..45519523c2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -92,14 +92,15 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB state = SX127x::setFrequencyDeviation(freqDev); RADIOLIB_ASSERT(state); - //set AFC bandwidth + // set AFC bandwidth state = SX127x::setAFCBandwidth(rxBw); RADIOLIB_ASSERT(state); - // sets AFC&AGC trigger to RSSI and preamble detect - state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); + // set AFC&AGC trigger to RSSI + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); RADIOLIB_ASSERT(state); + // enable AFC state = SX127x::setAFC(true); RADIOLIB_ASSERT(state); From 495f1a7862f2629ff3ccc4d8ef5b09fdc1cd4156 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:12:34 +0100 Subject: [PATCH 0082/1848] [CC1101] Set default FSK bitrate to 4k8 --- src/modules/CC1101/CC1101.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 7223042e12..f58192b449 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -528,9 +528,9 @@ class CC1101: public PhysicalLayer { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br Bit rate to be used in kbps. Defaults to 48.0 kbps. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 48.0 kHz. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz. @@ -540,7 +540,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 48.0, float rxBw = 135.0, int8_t power = 10, uint8_t preambleLength = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 135.0, int8_t power = 10, uint8_t preambleLength = 16); /*! \brief Blocking binary transmit method. From 330e5ad543a6759523cb70d4a3a182279ffb094f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:12:40 +0100 Subject: [PATCH 0083/1848] [RF69] Set default FSK bitrate to 4k8 --- src/modules/RF69/RF69.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 697f99fe6a..8e4afdedd0 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -461,9 +461,9 @@ class RF69: public PhysicalLayer { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br Bit rate to be used in kbps. Defaults to 48.0 kbps. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 50.0 kHz. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. @@ -473,7 +473,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); /*! \brief Reset method. Will reset the chip to the default state using RST pin. From d949666a579b7a334897a1b0cafffc36c5e84ae8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:12:47 +0100 Subject: [PATCH 0084/1848] [SX1231] Set default FSK bitrate to 4k8 --- src/modules/SX1231/SX1231.cpp | 2 +- src/modules/SX1231/SX1231.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index 1681d6bf50..c3e750c96c 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -5,7 +5,7 @@ SX1231::SX1231(Module* mod) : RF69(mod) { } -int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t preambleLen) { +int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX1231/SX1231.h index ada7dbb9b3..e989fa20aa 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX1231/SX1231.h @@ -37,11 +37,11 @@ class SX1231: public RF69 { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br Bit rate to be used in kbps. Defaults to 48.0 kbps. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. - \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. - \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 50.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. \param power Output power in dBm. Defaults to 10 dBm. @@ -49,7 +49,7 @@ class SX1231: public RF69 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); #if !defined(RADIOLIB_GODMODE) private: From d931982594c5b2620aa3f7e8f698b79041564aaa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:12:57 +0100 Subject: [PATCH 0085/1848] [SX126x] Set default FSK bitrate to 4k8 --- src/modules/SX126x/SX1262.h | 6 +++--- src/modules/SX126x/SX1268.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index f259065f5c..31724bc31a 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -55,9 +55,9 @@ class SX1262: public SX126x { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br FSK bit rate in kbps. Defaults to 48.0 kbps. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 50.0 kHz. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. @@ -71,7 +71,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 0.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 4b575342bf..d58ca540e2 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -55,9 +55,9 @@ class SX1268: public SX126x { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br FSK bit rate in kbps. Defaults to 48.0 kbps. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 50.0 kHz. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. @@ -71,7 +71,7 @@ class SX1268: public SX126x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods From 1698409e84995e9e691285c9988f703898b31ff7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:13:06 +0100 Subject: [PATCH 0086/1848] [SX127x] Set default FSK bitrate to 4k8 --- src/modules/SX127x/SX1272.cpp | 4 ++-- src/modules/SX127x/SX1272.h | 2 +- src/modules/SX127x/SX1276.h | 2 +- src/modules/SX127x/SX1277.h | 2 +- src/modules/SX127x/SX1278.h | 2 +- src/modules/SX127x/SX1279.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 40dbbf9d44..b9f04a01b3 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -32,9 +32,9 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync return(state); } -int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint16_t preambleLength, bool enableOOK) { +int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1272_CHIP_VERSION, br, rxBw, freqDev, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1272_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 3e0aa8cb3c..7491ef2a9d 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -152,7 +152,7 @@ class SX1272: public SX127x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 915.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index acb5c78610..cdc4cac535 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -71,7 +71,7 @@ class SX1276: public SX1278 { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index f2375fdeb8..b9f7a5cf7d 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -71,7 +71,7 @@ class SX1277: public SX1278 { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index dd89f32b66..150b97c38c 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -160,7 +160,7 @@ class SX1278: public SX127x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index bfab291b34..c9ff8ab039 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -71,7 +71,7 @@ class SX1279: public SX1278 { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods From 1240659d0c7b787b74d3be80e6c6758778c232a6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:13:35 +0100 Subject: [PATCH 0087/1848] [Si443x] Set default FSK bitrate to 4k8 --- src/modules/Si443x/Si4430.h | 2 +- src/modules/Si443x/Si4431.h | 2 +- src/modules/Si443x/Si4432.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h index cb1b2be02a..5a9b72d3de 100644 --- a/src/modules/Si443x/Si4430.h +++ b/src/modules/Si443x/Si4430.h @@ -44,7 +44,7 @@ class Si4430: public Si4432 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h index b1495d8a9e..5cf6e7704c 100644 --- a/src/modules/Si443x/Si4431.h +++ b/src/modules/Si443x/Si4431.h @@ -44,7 +44,7 @@ class Si4431: public Si4432 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h index bb8a8b0187..2c38b36dce 100644 --- a/src/modules/Si443x/Si4432.h +++ b/src/modules/Si443x/Si4432.h @@ -44,7 +44,7 @@ class Si4432: public Si443x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods From 80441dd1ed353b995802bb6985c500af50a397d7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:20:40 +0100 Subject: [PATCH 0088/1848] Updated library description --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index c37f3f6a1e..d3cac8b378 100644 --- a/library.properties +++ b/library.properties @@ -2,8 +2,8 @@ name=RadioLib version=4.6.0 author=Jan Gromes maintainer=Jan Gromes -sentence=Universal wireless communication library for Arduino -paragraph=Enables user-friendly control of the RadioShield and various wireless modules. +sentence=Universal wireless communication library +paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.). category=Communication url=https://github.com/jgromes/RadioLib architectures=* From 24ea845c7c21c3d5df0b3816f902d3528a2e2802 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Nov 2021 18:20:59 +0100 Subject: [PATCH 0089/1848] Bump version to 5.0.0 --- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index d3cac8b378..2c8859f0f8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=4.6.0 +version=5.0.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index e5221e5dfb..6cf6c18b08 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -922,8 +922,8 @@ #endif // version definitions -#define RADIOLIB_VERSION_MAJOR (0x04) -#define RADIOLIB_VERSION_MINOR (0x06) +#define RADIOLIB_VERSION_MAJOR (0x05) +#define RADIOLIB_VERSION_MINOR (0x00) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 963ef4f36a0e3df34357713cf1d3bd2a77394b0c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Nov 2021 14:35:01 +0100 Subject: [PATCH 0090/1848] [AX.25] Fixed encoding issue of some frames (#407) --- src/protocols/AX25/AX25.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 790582fb3e..e844cdf068 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -240,7 +240,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; // set destination SSID - *(frameBuffPtr++) = RADIOLIB_AX25_SSID_COMMAND_DEST | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->destSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_RESPONSE_DEST | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->destSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; // set source callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit memset(frameBuffPtr, ' ' << 1, RADIOLIB_AX25_MAX_CALLSIGN_LEN); @@ -250,7 +250,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { frameBuffPtr += RADIOLIB_AX25_MAX_CALLSIGN_LEN; // set source SSID - *(frameBuffPtr++) = RADIOLIB_AX25_SSID_RESPONSE_SOURCE | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; + *(frameBuffPtr++) = RADIOLIB_AX25_SSID_COMMAND_SOURCE | RADIOLIB_AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE; // set repeater callsigns for(uint16_t i = 0; i < frame->numRepeaters; i++) { @@ -361,12 +361,12 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // set end flag field (may be split into two bytes due to misalignment caused by extra stuffing bits) if(trailingLen != 0) { stuffedFrameBuffLen++; - stuffedFrameBuff[stuffedFrameBuffLen - 2] = RADIOLIB_AX25_FLAG >> trailingLen; + stuffedFrameBuff[stuffedFrameBuffLen - 2] |= RADIOLIB_AX25_FLAG >> trailingLen; stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG << (8 - trailingLen); } else { stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG; } - + // convert to NRZI for(size_t i = _preambleLen + 1; i < stuffedFrameBuffLen*8; i++) { size_t currBitPos = i + 7 - 2*(i%8); From 14d3ac6dff5de8e81f376c39d98d81d0e7f2b85e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Nov 2021 22:54:01 +0100 Subject: [PATCH 0091/1848] [AX.25] Fixed macro guard --- src/protocols/AX25/AX25.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index d924840a99..a6e870cc98 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -342,7 +342,7 @@ class AX25Client { */ int16_t sendFrame(AX25Frame* frame); -#if !defined(ADIOLIB_GODMODE) +#if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* _phy; From 3eb831d7e1fb069615fd7f3bf57f36279eaab24f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Nov 2021 22:54:20 +0100 Subject: [PATCH 0092/1848] [AX.25] Added APRS classes --- src/protocols/AX25/AX25.cpp | 10 +++++++++- src/protocols/AX25/AX25.h | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index e844cdf068..87d97864a6 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -366,7 +366,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } else { stuffedFrameBuff[stuffedFrameBuffLen - 1] = RADIOLIB_AX25_FLAG; } - + // convert to NRZI for(size_t i = _preambleLen + 1; i < stuffedFrameBuffLen*8; i++) { size_t currBitPos = i + 7 - 2*(i%8); @@ -431,6 +431,14 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { return(state); } +void AX25Client::getCallsign(char* buff) { + strncpy(buff, _srcCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); +} + +uint8_t AX25Client::getSSID() { + return(_srcSSID); +} + /* CCITT CRC implementation based on https://github.com/kicksat/ax25 diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index a6e870cc98..afc110b4b4 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -345,6 +345,8 @@ class AX25Client { #if !defined(RADIOLIB_GODMODE) private: #endif + friend class APRSClient; + PhysicalLayer* _phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) AFSKClient* _audio; @@ -357,6 +359,9 @@ class AX25Client { uint16_t _preambleLen = 0; static uint16_t getFrameCheckSequence(uint8_t* buff, size_t len); + + void getCallsign(char* buff); + uint8_t getSSID(); }; #endif From df466486aab98b7a982c5ae73e75194576c0dc0e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Nov 2021 22:56:36 +0100 Subject: [PATCH 0093/1848] [APRS] Added APRS support --- README.md | 3 +- examples/APRS/APRS_Position/APRS_Position.ino | 123 ++++++++++++++++++ keywords.txt | 4 + src/RadioLib.h | 2 + src/TypeDef.h | 7 + src/protocols/APRS/APRS.cpp | 67 ++++++++++ src/protocols/APRS/APRS.h | 101 ++++++++++++++ 7 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 examples/APRS/APRS_Position/APRS_Position.ino create mode 100644 src/protocols/APRS/APRS.cpp create mode 100644 src/protocols/APRS/APRS.h diff --git a/README.md b/README.md index 57fabc2120..5e67821d16 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x ### Supported Arduino platforms: * __Arduino__ @@ -76,7 +78,6 @@ The list above is by no means exhaustive - RadioLib code is independent of the u ### In development: * __AX5243__ FSK module * __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules -* __APRS__ protocol for all the modules that can transmit AX.25 * ___and more!___ ## Frequently Asked Questions diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino new file mode 100644 index 0000000000..1fa8ca9e7c --- /dev/null +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -0,0 +1,123 @@ +/* + RadioLib APRS Position Example + + This example sends APRS position reports + using SX1278's FSK modem. The data is + modulated as AFSK at 1200 baud using Bell + 202 tones. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + Other modules that can be used for APRS: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +// create APRS client isntance using the AX.25 client +APRSClient aprs(&ax25); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + // NOTE: moved to ISM band on purpose + // DO NOT transmit in APRS bands without ham radio license! + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(434.0); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + state = aprs.begin('>'); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending position ... ")); + + // send a location without message or timestamp + int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E"); + delay(500); + + // send a location with message and without timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!"); + delay(500); + + // send a location with message and timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z"); + delay(500); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/keywords.txt b/keywords.txt index 7b86be5d26..4dd0c926ad 100644 --- a/keywords.txt +++ b/keywords.txt @@ -48,6 +48,7 @@ SSTVClient KEYWORD1 HellClient KEYWORD1 AFSKClient KEYWORD1 FSK4Client KEYWORD1 +APRSClient KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -217,6 +218,9 @@ printGlyph KEYWORD2 tone KEYWORD2 noTone KEYWORD2 +# APRS +sendPosition KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index 92b659ddeb..0d202699bd 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -21,6 +21,7 @@ - SSTV (SSTVClient) - Hellschreiber (HellClient) - 4-FSK (FSK4Client) + - APRS (APRSClient) \par Quick Links Documentation for most common methods can be found in its reference page (see the list above).\n @@ -89,6 +90,7 @@ #include "protocols/RTTY/RTTY.h" #include "protocols/SSTV/SSTV.h" #include "protocols/FSK4/FSK4.h" +#include "protocols/APRS/APRS.h" // only create Radio class when using RadioShield #if defined(RADIOLIB_RADIOSHIELD) diff --git a/src/TypeDef.h b/src/TypeDef.h index 6a0b0a6083..a9687c1385 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -245,6 +245,13 @@ */ #define RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE (-108) +// APRS status codes + +/*! + \brief Supplied APRS symbol is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SYMBOL (-201) + // RTTY status codes /*! diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp new file mode 100644 index 0000000000..045d09a0a6 --- /dev/null +++ b/src/protocols/APRS/APRS.cpp @@ -0,0 +1,67 @@ +#include "APRS.h" + +APRSClient::APRSClient(AX25Client* ax) { + _ax = ax; +} + +int16_t APRSClient::begin(char symbol, bool alt) { + RADIOLIB_CHECK_RANGE(symbol, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL); + _symbol = symbol; + + if(alt) { + _table = '\\'; + } else { + _table = '/'; + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg, char* time) { + #if !defined(RADIOLIB_STATIC_ONLY) + size_t len = 1 + strlen(lat) + 1 + strlen(lon); + if(msg != NULL) { + len += 1 + strlen(msg); + } + if(time != NULL) { + len += strlen(time); + } + char* info = new char[len]; + #else + char info[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // build the info field + if((msg == NULL) && (time == NULL)) { + // no message, no timestamp + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, _table, lon, _symbol); + } else if((msg != NULL) && (time == NULL)) { + // message, no timestamp + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, _table, lon, _symbol, msg); + } else if((msg == NULL) && (time != NULL)) { + // timestamp, no message + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, _table, lon, _symbol); + } else { + // timestamp and message + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, _table, lon, _symbol, msg); + } + + // send the frame + int16_t state = sendFrame(destCallsign, destSSID, info); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] info; + #endif + return(state); +} + +int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) { + // get AX.25 callsign + char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; + _ax->getCallsign(srcCallsign); + + AX25Frame frameUI(destCallsign, destSSID, srcCallsign, _ax->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, + RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); + + return(_ax->sendFrame(&frameUI)); +} diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h new file mode 100644 index 0000000000..6e272aa704 --- /dev/null +++ b/src/protocols/APRS/APRS.h @@ -0,0 +1,101 @@ +#if !defined(_RADIOLIB_RADIOLIB_APRS_H) +#define _RADIOLIB_RADIOLIB_APRS_H + +#include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_APRS) + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AX25/AX25.h" + +// APRS data type identifiers +#define RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "!" +#define RADIOLIB_APRS_DATA_TYPE_GPS_RAW "$" +#define RADIOLIB_APRS_DATA_TYPE_ITEM ")" +#define RADIOLIB_APRS_DATA_TYPE_TEST "," +#define RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "/" +#define RADIOLIB_APRS_DATA_TYPE_MSG ":" +#define RADIOLIB_APRS_DATA_TYPE_OBJECT ";" +#define RADIOLIB_APRS_DATA_TYPE_STATION_CAPABILITES "<" +#define RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "=" +#define RADIOLIB_APRS_DATA_TYPE_STATUS ">" +#define RADIOLIB_APRS_DATA_TYPE_QUERY "?" +#define RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "@" +#define RADIOLIB_APRS_DATA_TYPE_TELEMETRY "T" +#define RADIOLIB_APRS_DATA_TYPE_MAIDENHEAD_BEACON "[" +#define RADIOLIB_APRS_DATA_TYPE_WEATHER_REPORT "_" +#define RADIOLIB_APRS_DATA_TYPE_USER_DEFINED "{" +#define RADIOLIB_APRS_DATA_TYPE_THIRD_PARTY "}" + +/*! + \class APRSClient + + \brief Client for APRS communication. +*/ +class APRSClient { + public: + /*! + \brief Default constructor. + + \param ax Pointer to the instance of AX25Client to be used for APRS. + */ + explicit APRSClient(AX25Client* ax); + + // basic methods + + /*! + \brief Initialization method. + + \param symbol APRS symbol to be displayed. + + \param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table. + + \returns \ref status_codes + */ + int16_t begin(char symbol, bool alt = false); + + /*! + \brief Transmit position. + + \param destCallsign Destination station callsign. + + \param destSSID Destination station SSID. + + \param lat Latitude as a null-terminated string. + + \param long Longitude as a null-terminated string. + + \param msg Message to be transmitted. Defaults to NULL (no message). + + \param msg Position timestamp. Defaults to NULL (no timestamp). + + \returns \ref status_codes + */ + int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL); + + /*! + \brief Transmit generic APRS frame. + + \param destCallsign Destination station callsign. + + \param destSSID Destination station SSID. + + \param info AX.25 info field contents. + + \returns \ref status_codes + */ + int16_t sendFrame(char* destCallsign, uint8_t destSSID, char* info); + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + AX25Client* _ax; + + // default APRS symbol (car) + char _symbol = '>'; + char _table = '/'; +}; + +#endif + +#endif From ffe271b0c61100f858921e0cc71924591c5b7e52 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 29 Nov 2021 08:05:46 +0100 Subject: [PATCH 0094/1848] [PHY] Fix unknown string length buffer overrun (#413) --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 58bb9231a0..8b514a9c14 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -107,7 +107,12 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { #if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else - uint8_t* data = new uint8_t[length + 1]; + uint8_t* data = NULL; + if(length == 0) { + data = new uint8_t[_maxPacketLength + 1]; + } else { + data = new uint8_t[length + 1]; + } if(!data) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } From 1c54c1d1c66a75e182ae0e3dcf91c2b83b535d53 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 30 Nov 2021 23:19:17 +0100 Subject: [PATCH 0095/1848] Fixed incorrect debug macro called (#407) --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 6cf6c18b08..8750c723e9 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -876,7 +876,7 @@ #if defined(RADIOLIB_VERBOSE) #define RADIOLIB_VERBOSE_PRINT(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) - #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) + #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) #else #define RADIOLIB_VERBOSE_PRINT(...) {} #define RADIOLIB_VERBOSE_PRINTLN(...) {} From 97f3b94c4f5d13a1add3c6609e89768b32585a20 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 2 Dec 2021 23:31:12 +0100 Subject: [PATCH 0096/1848] [MOD] Added missing default SPI settings (#416) --- src/Module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.h b/src/Module.h index 53cfb589f6..3a7b098d42 100644 --- a/src/Module.h +++ b/src/Module.h @@ -46,7 +46,7 @@ class Module { \param spiSettings SPI interface settings. */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); #else From 1d42f1a0ffee1274485c2f63dfb7cf07b2c4f6ea Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 4 Dec 2021 17:04:59 +0100 Subject: [PATCH 0097/1848] [MOD] Use custom tone() on Arduino mbed boards (#407) --- src/BuildOpt.h | 12 ++++++++++++ src/Module.cpp | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 8750c723e9..1b19ffa73e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -512,6 +512,10 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE + // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) @@ -546,6 +550,10 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE + // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) @@ -648,6 +656,10 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE + // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) diff --git a/src/Module.cpp b/src/Module.cpp index 9ff2921394..f7e766cd01 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,6 +1,13 @@ #include "Module.h" #if defined(RADIOLIB_BUILD_ARDUINO) + +// we need this to emulate tone() on mbed Arduino boards +#if defined(ARDUINO_ARDUINO_NANO33BLE) +#include "mbed.h" +mbed::PwmOut *pwmPin = NULL; +#endif + Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), @@ -271,8 +278,17 @@ void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) { } #if defined(ESP32) // ESP32 tone() emulation + (void)duration; ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); + #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) + // better tone for mbed OS boards + (void)duration; + if(!pwmPin) { + pwmPin = new mbed::PwmOut(digitalPinToPinName(pin)); + } + pwmPin->period(1.0 / value); + pwmPin->write(0.5); #else (void)value; (void)duration; @@ -298,6 +314,10 @@ void Module::noTone(RADIOLIB_PIN_TYPE pin) { // ESP32 tone() emulation ledcDetachPin(pin); ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) + // better tone for mbed OS boards + (void)pin; + pwmPin->suspend(); #endif #endif } From 92682fc5d607fc6db92b99caf0fb3e4ca2dba4c0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Dec 2021 11:23:01 +0100 Subject: [PATCH 0098/1848] [RFM9x] Fixed incorrect frequency range applied in FSK mode (#407) --- src/modules/RFM9x/RFM95.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/modules/RFM9x/RFM96.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 2beb4b258a..98dbdd1ab1 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -40,6 +40,42 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW return(state); } +int16_t RFM95::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { + // SX127X_REG_VERSION might be set 0x12 + state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + } else if(state != RADIOLIB_ERR_NONE) { + // some other error + return(state); + } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); + RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95")); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + return(state); +} + int16_t RFM95::setFrequency(float freq) { RADIOLIB_CHECK_RANGE(freq, 862.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index 4e510a3aa6..c2b4230a51 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -41,6 +41,42 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW return(state); } +int16_t RFM96::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { + // SX127X_REG_VERSION might be set 0x12 + state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + } else if(state != RADIOLIB_ERR_NONE) { + // some other error + return(state); + } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); + RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96")); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + if(enableOOK) { + state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } else { + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + } + + return(state); +} + int16_t RFM96::setFrequency(float freq) { RADIOLIB_CHECK_RANGE(freq, 410.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY); From c1240c551f33f7cccb9047ed9bcd9846f5740318 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Dec 2021 11:26:54 +0100 Subject: [PATCH 0099/1848] [RFM9x] Added missing declarations --- src/modules/RFM9x/RFM95.h | 22 ++++++++++++++++++++++ src/modules/RFM9x/RFM96.h | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/modules/RFM9x/RFM95.h b/src/modules/RFM9x/RFM95.h index 6a6eb1c737..aa555103c5 100644 --- a/src/modules/RFM9x/RFM95.h +++ b/src/modules/RFM9x/RFM95.h @@ -57,6 +57,28 @@ class RFM95: public SX1278 { */ int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + + \param preambleLength Length of FSK preamble in bits. + + \param enableOOK Use OOK modulation instead of FSK. + + \returns \ref status_codes + */ + int16_t beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK); + // configuration methods /*! diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h index 85389d3442..3c1d1f8204 100644 --- a/src/modules/RFM9x/RFM96.h +++ b/src/modules/RFM9x/RFM96.h @@ -57,6 +57,28 @@ class RFM96: public SX1278 { */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + + \param preambleLength Length of FSK preamble in bits. + + \param enableOOK Use OOK modulation instead of FSK. + + \returns \ref status_codes + */ + int16_t beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK); + // configuration methods /*! From ee59967815bc44c1afaad677dd050b7a8cdc57f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Dec 2021 11:48:10 +0100 Subject: [PATCH 0100/1848] [SX127x] Fixed incorrect NSS pin in example --- examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino index 3eeabf57a2..7330481117 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino @@ -24,7 +24,7 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 radio = new Module(5, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield From 2c590971070a4ed1fe29da4b9c18d9d561a9b209 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Dec 2021 12:48:12 +0100 Subject: [PATCH 0101/1848] [SX127x] Fixed AFC trigger for FSK mode (#418) --- src/modules/SX127x/SX127x.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 45519523c2..af9f67cf69 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -96,8 +96,13 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB state = SX127x::setAFCBandwidth(rxBw); RADIOLIB_ASSERT(state); - // set AFC&AGC trigger to RSSI - state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); + // set AFC&AGC trigger to RSSI (in OOK) or both (in FSK) + if(enableOOK) { + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); + } else { + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); + } + RADIOLIB_ASSERT(state); // enable AFC @@ -961,8 +966,10 @@ int16_t SX127x::setOOK(bool enableOOK) { int16_t state = RADIOLIB_ERR_NONE; if(enableOOK) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5); + state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); } else { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5); + state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); } if(state == RADIOLIB_ERR_NONE) { _ook = enableOOK; From 04a164abdd12bd10a8148b150d3954f99236c6be Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Dec 2021 12:51:09 +0100 Subject: [PATCH 0102/1848] Bump version to 5.1.0 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 2c8859f0f8..e1cf56e093 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.0.0 +version=5.1.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 1b19ffa73e..cc40c7a3d5 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -935,7 +935,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x00) +#define RADIOLIB_VERSION_MINOR (0x01) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 61a593c6f741bf751909a1e6ff06c7ffbbdf77c4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Dec 2021 13:09:42 +0100 Subject: [PATCH 0103/1848] Fixed incorrect macro guards CI_BUILD_ALL --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index f7e766cd01..d430b9aaba 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -3,7 +3,7 @@ #if defined(RADIOLIB_BUILD_ARDUINO) // we need this to emulate tone() on mbed Arduino boards -#if defined(ARDUINO_ARDUINO_NANO33BLE) +#if defined(RADIOLIB_MBED_TONE_OVERRIDE) #include "mbed.h" mbed::PwmOut *pwmPin = NULL; #endif From cc9d7b7220730a59dbf284a5a9ecff9e45eb474a Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 Dec 2021 18:11:52 +0100 Subject: [PATCH 0104/1848] [SX126x] Moved SF and BW out of common part --- src/modules/SX126x/SX1262.cpp | 8 +++++++- src/modules/SX126x/SX1268.cpp | 8 +++++++- src/modules/SX126x/SX126x.cpp | 13 ++++--------- src/modules/SX126x/SX126x.h | 6 +----- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 33422125ec..fcfbb2b07b 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -7,10 +7,16 @@ SX1262::SX1262(Module* mod) : SX126x(mod) { int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part - int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); // configure publicly accessible settings + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + state = setFrequency(freq); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index dfa65430a4..fb6a95e0c9 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -7,13 +7,19 @@ SX1268::SX1268(Module* mod) : SX126x(mod) { int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part - int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index a8f4b013bf..bfe9dba548 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -9,7 +9,7 @@ Module* SX126x::getMod() { return(_mod); } -int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { +int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); @@ -17,8 +17,9 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams - _bwKhz = bw; - _sf = sf; + // set the defaults, this will get overwritten later anyway + _bwKhz = 125.0; + _sf = 9; // initialize configuration variables (will be overwritten during public settings configuration) _bw = RADIOLIB_SX126X_LORA_BW_125_0; @@ -49,12 +50,6 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 } // configure publicly accessible settings - state = setSpreadingFactor(sf); - RADIOLIB_ASSERT(state); - - state = setBandwidth(bw); - RADIOLIB_ASSERT(state); - state = setCodingRate(cr); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index bd9525ce10..8c9b34a3c2 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -361,10 +361,6 @@ class SX126x: public PhysicalLayer { /*! \brief Initialization method for LoRa modem. - \param bw LoRa bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz. - - \param sf LoRa spreading factor. Allowed values are in range 5 to 12. - \param cr LoRa coding rate denominator. Allowed values range from 5 to 8. \param syncWord 1-byte LoRa sync word. @@ -377,7 +373,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); + int16_t begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. From 0bd11f8c2f979d07d5db2c5db5c09f7dfcf21ff6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 Dec 2021 18:12:13 +0100 Subject: [PATCH 0105/1848] [LLCC68] Added missing begin method (#425) --- src/modules/LLCC68/LLCC68.cpp | 24 ++++++++++++++++++++++++ src/modules/LLCC68/LLCC68.h | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index dae54b5969..6987f6b540 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -5,6 +5,30 @@ LLCC68::LLCC68(Module* mod) : SX1262(mod) { } +int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t LLCC68::setBandwidth(float bw) { RADIOLIB_CHECK_RANGE(bw, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); return(SX1262::setBandwidth(bw)); diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 7bb8a810a7..f8dd221926 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -22,6 +22,29 @@ class LLCC68: public SX1262 { */ LLCC68(Module* mod); + /*! + \brief Initialization method for LoRa modem. + + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + + \param sf LoRa spreading factor. Defaults to 9. + + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + + \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + + \param power Output power in dBm. Defaults to 10 dBm. + + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + // configuration methods /*! From 9f842acfe79d943345aaa0356f09684b58b61562 Mon Sep 17 00:00:00 2001 From: Chris Terwilliger Date: Mon, 20 Dec 2021 18:21:27 -0500 Subject: [PATCH 0106/1848] Update SX127x.h --- src/modules/SX127x/SX127x.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index b61ca3b687..66ab01c8cc 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -930,6 +930,15 @@ class SX127x: public PhysicalLayer { */ int16_t setOokFixedOrFloorThreshold(uint8_t value); + /*! + \brief Size of each decrement of the RSSI threshold in the OOK demodulator. + + \param value Step size: RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB (default), RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB + + \returns \ref status_codes + */ + int16_t setOokPeakThresholdStep(uint8_t value); + /*! \brief Enable Bit synchronizer. From 2477d38727b82b61b4a4b8d9276094359e9c5db4 Mon Sep 17 00:00:00 2001 From: Chris Terwilliger Date: Mon, 20 Dec 2021 18:25:41 -0500 Subject: [PATCH 0107/1848] Update SX127x.cpp --- src/modules/SX127x/SX127x.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index af9f67cf69..243234473d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -948,6 +948,14 @@ int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5)); } +int16_t SX127x::setOokPeakThresholdStep(uint8_t value) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5)); +} + int16_t SX127x::enableBitSync() { return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5)); } From ab8adc9e5f8a2698b235ae92719e948ba800cef7 Mon Sep 17 00:00:00 2001 From: Chris Terwilliger Date: Mon, 20 Dec 2021 18:28:21 -0500 Subject: [PATCH 0108/1848] Update keywords.txt --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 4dd0c926ad..9167c2a638 100644 --- a/keywords.txt +++ b/keywords.txt @@ -136,6 +136,7 @@ invertIQ KEYWORD2 setOokThresholdType KEYWORD2 setOokPeakThresholdDecrement KEYWORD2 setOokFixedOrFloorThreshold KEYWORD2 +setOokPeakThresholdStep KEYWORD2 setDirectSyncWord KEYWORD2 setDirectAction KEYWORD2 readBit KEYWORD2 From ee5bdd35a81a83fb85ca2feb554f0d085391235b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 22 Dec 2021 14:49:47 +0100 Subject: [PATCH 0109/1848] [LLCC68] Swapped bw and sf configuration (#425) --- src/modules/LLCC68/LLCC68.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 6987f6b540..ef1cbb6208 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -14,12 +14,12 @@ int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setFrequency(freq); RADIOLIB_ASSERT(state); - state = setSpreadingFactor(sf); + state = setBandwidth(bw); RADIOLIB_ASSERT(state); - state = setBandwidth(bw); + state = setSpreadingFactor(sf); RADIOLIB_ASSERT(state); - + state = setOutputPower(power); RADIOLIB_ASSERT(state); From 09d9d2c615d2cf3fadb0b00643b4891125f3069a Mon Sep 17 00:00:00 2001 From: Chris Terwilliger Date: Wed, 22 Dec 2021 22:26:05 -0500 Subject: [PATCH 0110/1848] Update CC1101.h --- src/modules/CC1101/CC1101.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index f58192b449..1f93faaf3c 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -869,7 +869,7 @@ class CC1101: public PhysicalLayer { int16_t setDataShaping(uint8_t sh) override; /*! - \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ and RADIOLIB_ENCODING_WHITENING. + \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER, and RADIOLIB_ENCODING_WHITENING. \param encoding Encoding to be used. From 7a1d813dc49e6b6cff7a17cfb96e6422e8bdf1a4 Mon Sep 17 00:00:00 2001 From: Chris Terwilliger Date: Thu, 23 Dec 2021 20:57:25 -0500 Subject: [PATCH 0111/1848] Update CC1101.h --- src/modules/CC1101/CC1101.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 1f93faaf3c..5391203e5d 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -870,6 +870,7 @@ class CC1101: public PhysicalLayer { /*! \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER, and RADIOLIB_ENCODING_WHITENING. + Note that encoding on CC1101 is applied to the entire stream including preamble, sync word, and CRC. \param encoding Encoding to be used. From 5fb2ce66abd40e2667d15d7476974b48ea582588 Mon Sep 17 00:00:00 2001 From: Chris Terwilliger Date: Thu, 23 Dec 2021 22:03:39 -0500 Subject: [PATCH 0112/1848] Update SX127x.h --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 66ab01c8cc..ea1ecf66e9 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -791,7 +791,7 @@ class SX127x: public PhysicalLayer { float getAFCError(); /*! - \brief Gets signal-to-noise ratio of the latest received packet. + \brief Gets signal-to-noise ratio of the latest received packet. Only available in LoRa mode. \returns Last packet signal-to-noise ratio (SNR). */ From 4567044deb964beadd225b420f651df417a20026 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Dec 2021 13:47:06 +0100 Subject: [PATCH 0113/1848] Added support for Raspberry PI (#432) --- README.md | 1 + src/BuildOpt.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/README.md b/README.md index 5e67821d16..ab9cfdb77b 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __Raspberry Pi__ * [__RP2040__](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect + * [__Raspberry Pi__](https://github.com/me-no-dev/RasPiArduino) - Arduino framework for RaspberryPI * __Heltec__ * [__CubeCell__](https://github.com/HelTecAutomation/CubeCell-Arduino) - ASR650X series (CubeCell-Board, CubeCell-Capsule, CubeCell-Module etc.) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index cc40c7a3d5..37f3a426dd 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -734,6 +734,60 @@ #undef yield #endif +#elif defined(RASPI) + // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) + #define RADIOLIB_PLATFORM "RasPiArduino" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + + // let's start off easy - no tone on this platform, that can happen + #define RADIOLIB_TONE_UNSUPPORTED + + // hmm, no yield either - weird on something like Raspberry PI, but sure, we can handle it + #define RADIOLIB_YIELD_UNSUPPORTED + + // aight, getting to the juicy stuff - PGM_P seems missing, that's the first time + #define PGM_P const char * + + // ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS! + #if defined(millis) + #undef millis + inline unsigned long millis() { return((unsigned long)(STCV / 1000)); }; + #endif + + #if defined(micros) + #undef micros + inline unsigned long micros() { return((unsigned long)(STCV)); }; + #endif + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" From d53ddf1ca418243b3f02832497f553762f50b0e5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:48:40 +0100 Subject: [PATCH 0114/1848] [CC1101] Added ESP8266/ESP32 IRAM attribute --- .../CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino | 3 +++ .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index e52630a557..65ae79a26f 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -82,6 +82,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 29719ade4d..1d993a7784 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -75,6 +75,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From a7705236b12e2a74cd1667c83823ce1131ef2555 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:48:49 +0100 Subject: [PATCH 0115/1848] [RF69] Added ESP8266/ESP32 IRAM attribute --- .../RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino | 3 +++ .../RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 12d5de5db8..da520351b5 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -74,6 +74,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index eb54a54141..6ae3fa1c77 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -91,6 +91,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From bb2cf12c8d8556342d73efe41fe359a47e6695af Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:48:59 +0100 Subject: [PATCH 0116/1848] [SX126x] Added ESP8266/ESP32 IRAM attribute --- .../SX126x_Channel_Activity_Detection_Interrupt.ino | 3 +++ .../SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino | 3 +++ .../SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino | 3 +++ 3 files changed, 9 insertions(+) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index ed658daaf6..f776377315 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -71,6 +71,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index d50f2849ed..4132617c60 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -88,6 +88,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 19e76817c2..69fd17c7cf 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -80,6 +80,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From 5cb5836ed82f98caf2203a18536fd9b8edb7ecb7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:14 +0100 Subject: [PATCH 0117/1848] [SX127x] Added ESP8266/ESP32 IRAM attribute --- .../SX127x_Channel_Activity_Detection_Interrupt.ino | 11 +++++++---- .../SX127x_Receive_Interrupt.ino | 3 +++ .../SX127x_Transmit_Interrupt.ino | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 30f945e47b..55372452f2 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -79,6 +79,9 @@ volatile bool enableInterrupt = true; // is detected within timeout period // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlagTimeout(void) { // check if the interrupt is enabled if(!enableInterrupt) { @@ -115,14 +118,14 @@ void loop() { // LoRa preamble was detected Serial.print(F("[SX1278] Preamble detected!")); - + } - + // check if we need to restart channel activity detection if(detectedFlag || timeoutFlag) { // start scanning the channel Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); - + // start scanning current channel int state = radio.startChannelScan(); if (state == RADIOLIB_ERR_NONE) { @@ -131,6 +134,6 @@ void loop() { Serial.print(F("failed, code ")); Serial.println(state); } - + } } diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 9db3eaf3c7..e322897003 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -85,6 +85,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index b218a0a7cc..f0fe3e8bbb 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -77,6 +77,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From fa4a4de87980ee5fb26fb4ad4403f98f85494aef Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:22 +0100 Subject: [PATCH 0118/1848] [SX128x] Added ESP8266/ESP32 IRAM attribute --- .../SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino | 3 +++ .../SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 9bc9eaaa60..274121df25 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -85,6 +85,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index b23fb0c156..55d44faa4c 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -77,6 +77,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From 9f40d9a17a4c8a71038ec6674593afabe497bc0b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:30 +0100 Subject: [PATCH 0119/1848] [nRF24] Added ESP8266/ESP32 IRAM attribute --- .../nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino | 3 +++ .../nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index cafa2964cd..9e73394a50 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -94,6 +94,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 9b6720c505..14d0c0723f 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -90,6 +90,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From a2eb2d7aa5d673ad6af77ef841a737ffd2b950f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:44 +0100 Subject: [PATCH 0120/1848] [Si443x] Added ESP8266/ESP32 IRAM attribute (#434) --- .../Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino | 3 +++ .../Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index 16c1af41ea..061ee09462 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -76,6 +76,9 @@ volatile bool enableInterrupt = true; // is received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 4703233a7f..7f6877c693 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -75,6 +75,9 @@ volatile bool enableInterrupt = true; // is transmitted by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // check if the interrupt is enabled if(!enableInterrupt) { From 3cc299d17be4ea6a3ea2a6e33f57ccf72839bc33 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 13 Jan 2022 12:25:02 -0700 Subject: [PATCH 0121/1848] Add FHSS support --- .../SX127x_Receive_FHSS.ino | 122 +++++++++++++++++ .../SX127x_Transmit_FHSS.ino | 124 ++++++++++++++++++ keywords.txt | 4 + src/modules/SX127x/SX1276.cpp | 22 ++++ src/modules/SX127x/SX1276.h | 28 ++++ src/modules/SX127x/SX127x.cpp | 17 ++- 6 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino create mode 100644 examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino new file mode 100644 index 0000000000..d45bec3b57 --- /dev/null +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -0,0 +1,122 @@ +/* + RadioLib SX127x Transmit with Frequency Hopping Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. This allows a simple mechanism to abide by + the FCC 400ms max dwell time rule. + https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf +*/ + +#include //Click here to get the library: http://librarymanager/All#RadioLib + +//Pins for RFM97 100mW Shield to SparkFun ESP32 Thing Plus C +int pin_cs = 15; +int pin_dio0 = 26; +int pin_dio1 = 25; +int pin_rst = 32; +SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); + +int counter = 0; + +volatile bool rxComplete = false; +volatile bool fhssChange = false; + +//The channel frequencies can be generated randomly or hard coded +float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +int numberOfChannels = sizeof(channels) / sizeof(float); + +int hopsCompleted = 0; + +void setup() +{ + Serial.begin(115200); + + //Begin radio on home channel + Serial.print(F("[SX127x] Initializing ... ")); + int state = radio.begin(channels[0]); + if (state != RADIOLIB_ERR_NONE) + { + Serial.print(F("Failed with code: ")); + Serial.println(state); + } + else + Serial.println(F("Success!")); + + // Set hop period to enable FHSS + // We set an artifically short period to show lots of hops + // HoppingPeriod = Tsym * FreqHoppingPeriod + // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms + // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits + radio.setFHSSHoppingPeriod(9); + + Serial.print(F("Hopping period: ")); + Serial.println(radio.getFHSSHoppingPeriod()); + + radio.setDio0Action(dio0ISR); //Called when transmission is finished + radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq + + radio.startReceive(); + + Serial.println(F("Waiting for new packet")); +} + +void loop() +{ + if (rxComplete == true) + { + uint8_t incomingBuffer[255]; + radio.readData(incomingBuffer, 255); + uint8_t receivedBytes = radio.getPacketLength(); + Serial.write(incomingBuffer, receivedBytes); + Serial.println(); + + Serial.print(F("Hops completed: ")); + Serial.println(hopsCompleted); + hopsCompleted = 0; + + radio.startReceive(); + + rxComplete = false; + } + + if (fhssChange == true) + { + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + //Serial.print(F("Radio on channel: ")); + //Serial.println(radio.getFHSSChannel()); + + hopsCompleted++; + radio.clearFHSSInt(); + fhssChange = false; + } +} + +//ISR when DIO0 goes low +//Called when transmission is complete or when RX is received +void dio0ISR(void) +{ + rxComplete = true; +} + +//ISR when DIO1 goes low +//Called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) +void dio1ISR(void) +{ + fhssChange = true; +} diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino new file mode 100644 index 0000000000..504852e066 --- /dev/null +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -0,0 +1,124 @@ +/* + RadioLib SX127x Transmit with Frequency Hopping Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. This allows a simple mechanism to abide by + the FCC 400ms max dwell time rule. + https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf +*/ + +#include //Click here to get the library: http://librarymanager/All#RadioLib + +//Pins for SparkFun 1W EBYTE Breakout to Uno +int pin_cs = 7; +int pin_dio0 = 3; +int pin_dio1 = 2; +int pin_rst = A2; +SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); + +volatile bool xmitComplete = false; +volatile bool fhssChange = false; + +//The channel frequencies can be generated randomly or hard coded +float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +int numberOfChannels = sizeof(channels) / sizeof(float); + +int hopsCompleted = 0; +int counter = 0; + +void setup() +{ + Serial.begin(115200); + + //Begin radio on home channel + Serial.print(F("[SX127x] Initializing ... ")); + int state = radio.begin(channels[0]); + if (state != RADIOLIB_ERR_NONE) + { + Serial.print(F("Failed with code: ")); + Serial.println(state); + } + else + Serial.println(F("Success!")); + + // Set hop period to enable FHSS + // We set an artifically short period to show lots of hops + // HoppingPeriod = Tsym * FreqHoppingPeriod + // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms + // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits + radio.setFHSSHoppingPeriod(9); + + Serial.print(F("Hopping period: ")); + Serial.println(radio.getFHSSHoppingPeriod()); + + radio.setDio0Action(dio0ISR); //Called when transmission is finished + radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq + + Serial.print(F("Transmitting packet...")); + + char output[256]; + sprintf(output, "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: %d", counter++); + + radio.startTransmit(output, strlen(output) - 1); +} + +void loop() +{ + if (xmitComplete == true) + { + xmitComplete = false; + Serial.println(F("Transmit complete")); + Serial.print(F("Radio after xmit is on channel: ")); + Serial.println(radio.getFHSSChannel()); + //The FHSS channel is automatically reset to 0 upon end of transmission + + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); //Return to home channel before next transaction + + Serial.print(F("Hops completed: ")); + Serial.println(hopsCompleted); + hopsCompleted = 0; + + radio.startReceive(); + } + + if (fhssChange == true) + { + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + //Serial.print(F("Radio on channel: ")); + //Serial.println(radio.getFHSSChannel()); + + hopsCompleted++; + fhssChange = false; + radio.clearFHSSInt(); + } +} + +//ISR when DIO0 goes low +//Called when transmission is complete or when RX is received +void dio0ISR(void) +{ + xmitComplete = true; +} + +//ISR when DIO1 goes low +//Called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) +void dio1ISR(void) +{ + fhssChange = true; +} diff --git a/keywords.txt b/keywords.txt index 9167c2a638..31db163d91 100644 --- a/keywords.txt +++ b/keywords.txt @@ -142,6 +142,10 @@ setDirectAction KEYWORD2 readBit KEYWORD2 enableBitSync KEYWORD2 disableBitSync KEYWORD2 +setFHSSHoppingPeriod KEYWORD2 +getFHSSHoppingPeriod KEYWORD2 +getFHSSChannel KEYWORD2 +clearFHSSInt KEYWORD2 # RF69-specific setAESKey KEYWORD2 diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index c4c32f9c92..fa1b46b81b 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -70,4 +70,26 @@ int16_t SX1276::setFrequency(float freq) { return(state); } +int16_t SX1276::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1276::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1276::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1276::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + + #endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index cdc4cac535..15006ce367 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -84,6 +84,34 @@ class SX1276: public SX1278 { */ int16_t setFrequency(float freq); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 243234473d..9b099bbc9c 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -375,7 +375,10 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); + else + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); // set expected packet length for SF6 if(_sf == 6) { @@ -448,7 +451,10 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set DIO mapping - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); + else + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); // apply fixes to errata RADIOLIB_ERRATA_SX127X(false); @@ -987,8 +993,11 @@ int16_t SX127x::setOOK(bool enableOOK) { } int16_t SX127x::setFrequencyRaw(float newFreq) { - // set mode to standby - int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + int16_t state = RADIOLIB_ERR_NONE; + + // set mode to standby if not FHSS + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) + state = setMode(RADIOLIB_SX127X_STANDBY); // calculate register values uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; From 20e1ab23dfff7b9214079d053f1150fce7283cef Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 17 Jan 2022 11:35:19 -0700 Subject: [PATCH 0122/1848] Add helper functions for SX1277, SX1278, SX1279 --- src/modules/SX127x/SX1277.cpp | 20 ++++++++++++++++++++ src/modules/SX127x/SX1277.h | 28 ++++++++++++++++++++++++++++ src/modules/SX127x/SX1278.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1278.h | 28 ++++++++++++++++++++++++++++ src/modules/SX127x/SX1279.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1279.h | 28 ++++++++++++++++++++++++++++ src/modules/SX127x/SX127x.cpp | 15 ++++++++++----- 7 files changed, 156 insertions(+), 5 deletions(-) diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 59250e45ed..2bc2790ac9 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -100,4 +100,24 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } +int16_t SX1277::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1277::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1277::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1277::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index b9f7a5cf7d..fed18de59d 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -93,6 +93,34 @@ class SX1277: public SX1278 { */ int16_t setSpreadingFactor(uint8_t sf); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 317c38ee8b..71ba02e1ae 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -623,4 +623,25 @@ void SX1278::errataFix(bool rx) { _mod->SPIsetRegValue(0x30, fixedRegs[2]); } +int16_t SX1278::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1278::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1278::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1278::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 150b97c38c..533a0da9fa 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -302,6 +302,34 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 1eac9dc9ae..286d0f4702 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -70,4 +70,25 @@ int16_t SX1279::setFrequency(float freq) { return(state); } +int16_t SX1279::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1279::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1279::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1279::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + #endif diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index c9ff8ab039..5328213b9a 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -84,6 +84,34 @@ class SX1279: public SX1278 { */ int16_t setFrequency(float freq); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 9b099bbc9c..15736a0a5d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -375,10 +375,12 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); - else + } + else { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); + } // set expected packet length for SF6 if(_sf == 6) { @@ -451,10 +453,12 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set DIO mapping - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); - else + } + else { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); + } // apply fixes to errata RADIOLIB_ERRATA_SX127X(false); @@ -996,8 +1000,9 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { int16_t state = RADIOLIB_ERR_NONE; // set mode to standby if not FHSS - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = setMode(RADIOLIB_SX127X_STANDBY); + } // calculate register values uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; From c4fec32965abd7e81ce4e6b7f6fbf1abfcfddefd Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 17 Jan 2022 11:43:13 -0700 Subject: [PATCH 0123/1848] Change coding style to match library style guide. --- .../SX127x_Receive_FHSS.ino | 88 ++++++++----------- .../SX127x_Transmit_FHSS.ino | 83 ++++++++--------- 2 files changed, 74 insertions(+), 97 deletions(-) diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index d45bec3b57..7ee31b8353 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -18,68 +18,61 @@ The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. Once a hopping period is set and a transmission is started the radio will begin triggering interrupts every hop period where the radio frequency - is changed to the next channel. This allows a simple mechanism to abide by - the FCC 400ms max dwell time rule. - https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf + is changed to the next channel. */ #include //Click here to get the library: http://librarymanager/All#RadioLib -//Pins for RFM97 100mW Shield to SparkFun ESP32 Thing Plus C -int pin_cs = 15; -int pin_dio0 = 26; -int pin_dio1 = 25; -int pin_rst = 32; +// SX1276 has the following connections: +const int pin_cs = 10; +const int pin_dio0 = 2; +const int pin_dio1 = 9; +const int pin_rst = 3; SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); -int counter = 0; - volatile bool rxComplete = false; volatile bool fhssChange = false; -//The channel frequencies can be generated randomly or hard coded +// the channel frequencies can be generated randomly or hard coded float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; int numberOfChannels = sizeof(channels) / sizeof(float); int hopsCompleted = 0; -void setup() -{ - Serial.begin(115200); +void setup() { + Serial.begin(9600); - //Begin radio on home channel + // begin radio on home channel Serial.print(F("[SX127x] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) - { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed with code: ")); Serial.println(state); } else Serial.println(F("Success!")); - // Set hop period to enable FHSS - // We set an artifically short period to show lots of hops - // HoppingPeriod = Tsym * FreqHoppingPeriod - // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms - // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits - radio.setFHSSHoppingPeriod(9); - - Serial.print(F("Hopping period: ")); - Serial.println(radio.getFHSSHoppingPeriod()); - - radio.setDio0Action(dio0ISR); //Called when transmission is finished - radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq - - radio.startReceive(); - - Serial.println(F("Waiting for new packet")); + // set hop period to enable FHSS + state = radio.setFHSSHoppingPeriod(9); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Error setting hopping period: ")); + Serial.println(state); + } + radio.setDio0Action(dio0ISR); // called when transmission is finished + radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq + + // start listening for LoRa packets + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } } -void loop() -{ - if (rxComplete == true) - { +void loop() { + if (rxComplete == true) { uint8_t incomingBuffer[255]; radio.readData(incomingBuffer, 255); uint8_t receivedBytes = radio.getPacketLength(); @@ -95,11 +88,8 @@ void loop() rxComplete = false; } - if (fhssChange == true) - { + if (fhssChange == true) { radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); - //Serial.print(F("Radio on channel: ")); - //Serial.println(radio.getFHSSChannel()); hopsCompleted++; radio.clearFHSSInt(); @@ -107,16 +97,14 @@ void loop() } } -//ISR when DIO0 goes low -//Called when transmission is complete or when RX is received -void dio0ISR(void) -{ +// ISR when DIO0 goes low +// called when transmission is complete or when RX is received +void dio0ISR(void) { rxComplete = true; } -//ISR when DIO1 goes low -//Called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) -void dio1ISR(void) -{ +// ISR when DIO1 goes low +// called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) +void dio1ISR(void) { fhssChange = true; -} +} \ No newline at end of file diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index 504852e066..f1ecbaf8bc 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -18,77 +18,71 @@ The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. Once a hopping period is set and a transmission is started the radio will begin triggering interrupts every hop period where the radio frequency - is changed to the next channel. This allows a simple mechanism to abide by - the FCC 400ms max dwell time rule. - https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf + is changed to the next channel. */ #include //Click here to get the library: http://librarymanager/All#RadioLib -//Pins for SparkFun 1W EBYTE Breakout to Uno -int pin_cs = 7; -int pin_dio0 = 3; -int pin_dio1 = 2; -int pin_rst = A2; +// SX1276 has the following connections: +const int pin_cs = 10; +const int pin_dio0 = 2; +const int pin_dio1 = 9; +const int pin_rst = 3; SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); volatile bool xmitComplete = false; volatile bool fhssChange = false; -//The channel frequencies can be generated randomly or hard coded +// the channel frequencies can be generated randomly or hard coded float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; int numberOfChannels = sizeof(channels) / sizeof(float); int hopsCompleted = 0; int counter = 0; -void setup() -{ - Serial.begin(115200); +void setup() { + Serial.begin(9600); - //Begin radio on home channel + // begin radio on home channel Serial.print(F("[SX127x] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) - { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed with code: ")); Serial.println(state); } else Serial.println(F("Success!")); - // Set hop period to enable FHSS - // We set an artifically short period to show lots of hops - // HoppingPeriod = Tsym * FreqHoppingPeriod - // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms - // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits - radio.setFHSSHoppingPeriod(9); - - Serial.print(F("Hopping period: ")); - Serial.println(radio.getFHSSHoppingPeriod()); + // set hop period to enable FHSS + state = radio.setFHSSHoppingPeriod(9); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("Error setting hopping period: ")); + Serial.println(state); + } - radio.setDio0Action(dio0ISR); //Called when transmission is finished - radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq + radio.setDio0Action(dio0ISR); // called when transmission is finished + radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq Serial.print(F("Transmitting packet...")); - char output[256]; - sprintf(output, "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: %d", counter++); + String longOutput = "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; - radio.startTransmit(output, strlen(output) - 1); + state = radio.startTransmit(longOutput + counter); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Error transmitting with code: ")); + Serial.println(state); + } } -void loop() -{ - if (xmitComplete == true) - { +void loop() { + if (xmitComplete == true) { xmitComplete = false; Serial.println(F("Transmit complete")); Serial.print(F("Radio after xmit is on channel: ")); Serial.println(radio.getFHSSChannel()); - //The FHSS channel is automatically reset to 0 upon end of transmission + // the FHSS channel is automatically reset to 0 upon end of transmission - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); //Return to home channel before next transaction + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); // Return to home channel before next transaction Serial.print(F("Hops completed: ")); Serial.println(hopsCompleted); @@ -97,11 +91,8 @@ void loop() radio.startReceive(); } - if (fhssChange == true) - { + if (fhssChange == true) { radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); - //Serial.print(F("Radio on channel: ")); - //Serial.println(radio.getFHSSChannel()); hopsCompleted++; fhssChange = false; @@ -109,16 +100,14 @@ void loop() } } -//ISR when DIO0 goes low -//Called when transmission is complete or when RX is received -void dio0ISR(void) -{ +// ISR when DIO0 goes low +// called when transmission is complete or when RX is received +void dio0ISR(void) { xmitComplete = true; } -//ISR when DIO1 goes low -//Called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) -void dio1ISR(void) -{ +// ISR when DIO1 goes low +// called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) +void dio1ISR(void) { fhssChange = true; } From 06ef449b68fb698914d4becaff2fa18b099bb489 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 17 Jan 2022 11:47:49 -0700 Subject: [PATCH 0124/1848] Move helper functions from SX1276/7/8/9 to global SX127x. --- src/modules/SX127x/SX1276.cpp | 22 ---------------------- src/modules/SX127x/SX1276.h | 28 ---------------------------- src/modules/SX127x/SX1277.cpp | 20 -------------------- src/modules/SX127x/SX1277.h | 28 ---------------------------- src/modules/SX127x/SX1278.cpp | 21 --------------------- src/modules/SX127x/SX1278.h | 28 ---------------------------- src/modules/SX127x/SX1279.cpp | 21 --------------------- src/modules/SX127x/SX1279.h | 28 ---------------------------- src/modules/SX127x/SX127x.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX127x.h | 28 ++++++++++++++++++++++++++++ 10 files changed, 49 insertions(+), 196 deletions(-) diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index fa1b46b81b..c4c32f9c92 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -70,26 +70,4 @@ int16_t SX1276::setFrequency(float freq) { return(state); } -int16_t SX1276::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1276::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1276::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1276::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} - - #endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 15006ce367..cdc4cac535 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -84,34 +84,6 @@ class SX1276: public SX1278 { */ int16_t setFrequency(float freq); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 2bc2790ac9..59250e45ed 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -100,24 +100,4 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } -int16_t SX1277::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1277::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1277::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1277::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index fed18de59d..b9f7a5cf7d 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -93,34 +93,6 @@ class SX1277: public SX1278 { */ int16_t setSpreadingFactor(uint8_t sf); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 71ba02e1ae..317c38ee8b 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -623,25 +623,4 @@ void SX1278::errataFix(bool rx) { _mod->SPIsetRegValue(0x30, fixedRegs[2]); } -int16_t SX1278::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1278::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1278::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1278::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} - #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 533a0da9fa..150b97c38c 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -302,34 +302,6 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 286d0f4702..1eac9dc9ae 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -70,25 +70,4 @@ int16_t SX1279::setFrequency(float freq) { return(state); } -int16_t SX1279::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1279::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1279::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1279::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} - #endif diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 5328213b9a..c9ff8ab039 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -84,34 +84,6 @@ class SX1279: public SX1278 { */ int16_t setFrequency(float freq); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 15736a0a5d..1db50c20fa 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1367,4 +1367,25 @@ void SX127x::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX127x::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX127x::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX127x::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + #endif diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 66ab01c8cc..b0671bac80 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1073,6 +1073,34 @@ class SX127x: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif From 636719854642d841351105fa77f2f58caba1fb9c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 10:21:28 +0100 Subject: [PATCH 0125/1848] [SX127x] Fixed shaping disable (#452) --- src/modules/SX127x/SX1278.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 317c38ee8b..685fe175a7 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -314,6 +314,11 @@ int16_t SX1278::setDataShaping(uint8_t sh) { // check modulation if(SX127x::_ook) { + // we're in OOK mode, the only thing we can do is disable + if(sh == RADIOLIB_SHAPING_NONE) { + return(setDataShapingOOK(0)); + } + return(RADIOLIB_ERR_INVALID_MODULATION); } From 73e3da212a79ba0c6498083890201f4b7c7bf33f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 12:05:30 +0100 Subject: [PATCH 0126/1848] [SX127x] Updated FHSS example formatting --- .../SX127x_Receive_FHSS.ino | 164 +++++++++++----- .../SX127x_Transmit_FHSS.ino | 177 ++++++++++++------ 2 files changed, 239 insertions(+), 102 deletions(-) diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index 7ee31b8353..3aeca4a879 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -15,56 +15,98 @@ For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ - The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. - Once a hopping period is set and a transmission is started the radio + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio will begin triggering interrupts every hop period where the radio frequency is changed to the next channel. */ -#include //Click here to get the library: http://librarymanager/All#RadioLib +#include -// SX1276 has the following connections: -const int pin_cs = 10; -const int pin_dio0 = 2; -const int pin_dio1 = 9; -const int pin_rst = 3; -SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); -volatile bool rxComplete = false; -volatile bool fhssChange = false; +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// flag to indicate frequency must be changed +volatile bool fhssChangeFlag = false; // the channel frequencies can be generated randomly or hard coded -float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +// NOTE: The frequency list MUST be the same on both sides! +float channels[] = { 433.0, 433.4, 433.2, 433.6, 434.0, 433.8 }; int numberOfChannels = sizeof(channels) / sizeof(float); +// counter to keep track of how many frequency hops were performed int hopsCompleted = 0; +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setRxFlag(void) { + receivedFlag = true; +} + +// this function is called when FhssChangeChannel interrupt occurs +// (at the beginning of each transmission) +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFHSSFlag(void) { + fhssChangeFlag = true; +} + void setup() { Serial.begin(9600); // begin radio on home channel - Serial.print(F("[SX127x] Initializing ... ")); + Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Failed with code: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - else - Serial.println(F("Success!")); - // set hop period to enable FHSS + // set hop period in symbols + // this will also enable FHSS state = radio.setFHSSHoppingPeriod(9); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Error setting hopping period: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - radio.setDio0Action(dio0ISR); // called when transmission is finished - radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq + + // set the function to call when reception is finished + radio.setDio0Action(setRxFlag); + + // set the function to call when we need to hcange frequency + radio.setDio1Action(setFHSSFlag); // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); state = radio.startReceive(); - if (state != RADIOLIB_ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { Serial.print(F("failed, code ")); Serial.println(state); while (true); @@ -72,39 +114,67 @@ void setup() { } void loop() { - if (rxComplete == true) { - uint8_t incomingBuffer[255]; - radio.readData(incomingBuffer, 255); - uint8_t receivedBytes = radio.getPacketLength(); - Serial.write(incomingBuffer, receivedBytes); - Serial.println(); - - Serial.print(F("Hops completed: ")); + // check if the reception flag is set + if (receivedFlag == true) { + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[SX1278] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[SX1278] Failed, code ")); + Serial.println(state); + + } + + // print the number of hops it took + Serial.print(F("[SX1278] Hops completed: ")); Serial.println(hopsCompleted); + + // reset the counter hopsCompleted = 0; + // put the module back to listen mode radio.startReceive(); - rxComplete = false; + // we're ready to receive more packets, clear the flag + receivedFlag = false; } - if (fhssChange == true) { - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + // check if we need to do another frequency hop + if (fhssChangeFlag == true) { + // we do, change it now + int state = radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Failed to change frequency, code ")); + Serial.println(state); + } + // increment the counter hopsCompleted++; + + // clear the FHSS interrupt radio.clearFHSSInt(); - fhssChange = false; - } -} -// ISR when DIO0 goes low -// called when transmission is complete or when RX is received -void dio0ISR(void) { - rxComplete = true; + // we're ready to do another hop, clear the flag + fhssChangeFlag = false; + } } - -// ISR when DIO1 goes low -// called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) -void dio1ISR(void) { - fhssChange = true; -} \ No newline at end of file diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index f1ecbaf8bc..b6182af5f4 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -15,99 +15,166 @@ For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ - The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. - Once a hopping period is set and a transmission is started the radio + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio will begin triggering interrupts every hop period where the radio frequency is changed to the next channel. */ -#include //Click here to get the library: http://librarymanager/All#RadioLib +#include -// SX1276 has the following connections: -const int pin_cs = 10; -const int pin_dio0 = 2; -const int pin_dio1 = 9; -const int pin_rst = 3; -SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); -volatile bool xmitComplete = false; -volatile bool fhssChange = false; +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// flag to indicate that a packet was received +volatile bool transmittedFlag = false; + +// flag to indicate frequency must be changed +volatile bool fhssChangeFlag = false; // the channel frequencies can be generated randomly or hard coded -float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +// NOTE: The frequency list MUST be the same on both sides! +float channels[] = { 433.0, 433.4, 433.2, 433.6, 434.0, 433.8 }; int numberOfChannels = sizeof(channels) / sizeof(float); +// counter to keep track of how many frequency hops were performed int hopsCompleted = 0; -int counter = 0; + +// counter that increments with each sent packet +int packetCounter = 0; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// this is the packet that will be sent +String longPacket = "Let's create a really long packet to trigger \ +lots of hop interrupts. A packet can be up to 256 bytes long. \ +This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is \ +1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setTxFlag(void) { + transmittedFlag = true; +} + +// this function is called when FhssChangeChannel interrupt occurs +// (at the beginning of each transmission) +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFHSSFlag(void) { + fhssChangeFlag = true; +} void setup() { Serial.begin(9600); // begin radio on home channel - Serial.print(F("[SX127x] Initializing ... ")); + Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Failed with code: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - else - Serial.println(F("Success!")); - // set hop period to enable FHSS + // set hop period in symbols + // this will also enable FHSS state = radio.setFHSSHoppingPeriod(9); - if(state != RADIOLIB_ERR_NONE) { - Serial.print(F("Error setting hopping period: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - radio.setDio0Action(dio0ISR); // called when transmission is finished - radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq - - Serial.print(F("Transmitting packet...")); + // set the function to call when transmission is finished + radio.setDio0Action(setTxFlag); - String longOutput = "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; + // set the function to call when we need to hcange frequency + radio.setDio1Action(setFHSSFlag); - state = radio.startTransmit(longOutput + counter); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Error transmitting with code: ")); - Serial.println(state); - } + // start transmitting the first packet + Serial.print(F("[SX1278] Sending first packet ... ")); + transmissionState = radio.startTransmit(longPacket + packetCounter); } void loop() { - if (xmitComplete == true) { - xmitComplete = false; - Serial.println(F("Transmit complete")); - Serial.print(F("Radio after xmit is on channel: ")); - Serial.println(radio.getFHSSChannel()); - // the FHSS channel is automatically reset to 0 upon end of transmission + // check if the transmission flag is set + if (transmittedFlag == true) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); // Return to home channel before next transaction + // The channel is automatically reset to 0 upon completion + Serial.print(F("[SX1278] Radio is on channel: ")); + Serial.println(radio.getFHSSChannel()); - Serial.print(F("Hops completed: ")); + // print the number of hops it took + Serial.print(F("[SX1278] Hops completed: ")); Serial.println(hopsCompleted); + + // reset the counter hopsCompleted = 0; - radio.startReceive(); + // return to home channel before the next transaction + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + + // wait a second before transmitting again + delay(1000); + + // increment the packet counter + packetCounter++; + + // send another packet + Serial.print(F("[SX1278] Sending another packet ... ")); + transmissionState = radio.startTransmit(longPacket + packetCounter); } - if (fhssChange == true) { - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + // check if we need to do another frequency hop + if (fhssChangeFlag == true) { + // we do, change it now + int state = radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Failed to change frequency, code ")); + Serial.println(state); + } + // increment the counter hopsCompleted++; - fhssChange = false; - radio.clearFHSSInt(); - } -} -// ISR when DIO0 goes low -// called when transmission is complete or when RX is received -void dio0ISR(void) { - xmitComplete = true; -} + // clear the FHSS interrupt + radio.clearFHSSInt(); -// ISR when DIO1 goes low -// called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) -void dio1ISR(void) { - fhssChange = true; + // we're ready to do another hop, clear the flag + fhssChangeFlag = false; + } } From 0de8ef6bce29c5e4fbbe34226d5b827a77888f05 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 12:05:50 +0100 Subject: [PATCH 0127/1848] [SX127x] Fixed typo --- .../SX127x/SX127x_PingPong/SX127x_PingPong.ino | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index cd505a0672..e403c9027d 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -48,7 +48,7 @@ void setFlag(void) { return; } - // we sent aor received packet, set the flag + // we sent or received packet, set the flag operationDone = true; } @@ -105,17 +105,17 @@ void loop() { if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); - + } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); - + } // listen for response radio.startReceive(); transmitFlag = false; - + } else { // the previous operation was reception // print data and send another packet @@ -125,21 +125,21 @@ void loop() { if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1278] Received packet!")); - + // print data of the packet Serial.print(F("[SX1278] Data:\t\t")); Serial.println(str); - + // print RSSI (Received Signal Strength Indicator) Serial.print(F("[SX1278] RSSI:\t\t")); Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); - + // print SNR (Signal-to-Noise Ratio) Serial.print(F("[SX1278] SNR:\t\t")); Serial.print(radio.getSNR()); Serial.println(F(" dB")); - + } // wait a second before transmitting again @@ -154,6 +154,6 @@ void loop() { // we're ready to process more packets, // enable interrupt service routine enableInterrupt = true; - + } } From 19109bc7d84e462b1309b7e05332a8f112b4dcb4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 17:05:58 +0100 Subject: [PATCH 0128/1848] [Si443x] Added fixed packet length mode --- src/modules/Si443x/Si443x.cpp | 34 ++++++++++++++++++++++++++++++++-- src/modules/Si443x/Si443x.h | 20 ++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 1e4221e971..90bba72ea4 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -61,6 +61,8 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) state = setEncoding(0); RADIOLIB_ASSERT(state); + state = variablePacketLengthMode(); + return(state); } @@ -233,8 +235,9 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { clearIRQFlags(); // set packet length - /// \todo variable packet length - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + } /// \todo use header as address field? (void)addr; @@ -591,6 +594,14 @@ void Si443x::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +int16_t Si443x::fixedPacketLengthMode(uint8_t len) { + return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON, len)); +} + +int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) { + return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen)); +} + int16_t Si443x::setFrequencyRaw(float newFreq) { // set mode to standby int16_t state = standby(); @@ -619,6 +630,25 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { return(state); } +int16_t Si443x::setPacketMode(uint8_t mode, uint8_t len) { + // check packet length + if (len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set to fixed packet length + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, mode, 3, 3); + RADIOLIB_ASSERT(state); + + // set length to register + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update cached value + _packetLengthConfig = mode; + return(state); +} + bool Si443x::findChip() { uint8_t i = 0; bool flagFound = false; diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 9a5c0df16f..40feceef80 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -816,6 +816,24 @@ class Si443x: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); + /*! + \brief Set modem in fixed packet length mode. + + \param len Packet length. + + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. + + \param len Maximum packet length. + + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif @@ -831,8 +849,10 @@ class Si443x: public PhysicalLayer { size_t _packetLength = 0; bool _packetLengthQueried = false; + uint8_t _packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; int16_t setFrequencyRaw(float newFreq); + int16_t setPacketMode(uint8_t mode, uint8_t len); #if !defined(RADIOLIB_GODMODE) private: From b5e5e079c89b4bd7efc6d1724de527a39a5d7887 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 25 Jan 2022 12:17:01 -0700 Subject: [PATCH 0129/1848] Correct typos in explicit/implicitHeader functions. Add a few missing keywords. --- keywords.txt | 3 +++ src/modules/SX126x/SX126x.h | 6 +++--- src/modules/SX127x/SX1272.h | 6 +++--- src/modules/SX127x/SX1278.h | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/keywords.txt b/keywords.txt index 31db163d91..a0b8ea6c64 100644 --- a/keywords.txt +++ b/keywords.txt @@ -146,6 +146,9 @@ setFHSSHoppingPeriod KEYWORD2 getFHSSHoppingPeriod KEYWORD2 getFHSSChannel KEYWORD2 clearFHSSInt KEYWORD2 +randomByte KEYWORD2 +getPacketLength + # RF69-specific setAESKey KEYWORD2 diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 8c9b34a3c2..73d31b4341 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -827,7 +827,9 @@ class SX126x: public PhysicalLayer { float getRSSIInst(); /*! - \brief Set implicit header mode for future reception/transmission. + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. + + \param len Payload length in bytes. \returns \ref status_codes */ @@ -836,8 +838,6 @@ class SX126x: public PhysicalLayer { /*! \brief Set explicit header mode for future reception/transmission. - \param len Payload length in bytes. - \returns \ref status_codes */ int16_t explicitHeader(); diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 7491ef2a9d..e4343b66ac 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -278,7 +278,9 @@ class SX1272: public SX127x { int16_t autoLDRO(); /*! - \brief Set implicit header mode for future reception/transmission. + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. + + \param len Payload length in bytes. \returns \ref status_codes */ @@ -287,8 +289,6 @@ class SX1272: public SX127x { /*! \brief Set explicit header mode for future reception/transmission. - \param len Payload length in bytes. - \returns \ref status_codes */ int16_t explicitHeader(); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 150b97c38c..cffedc81fd 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -287,7 +287,9 @@ class SX1278: public SX127x { int16_t autoLDRO(); /*! - \brief Set implicit header mode for future reception/transmission. + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. + + \param len Payload length in bytes. \returns \ref status_codes */ @@ -296,8 +298,6 @@ class SX1278: public SX127x { /*! \brief Set explicit header mode for future reception/transmission. - \param len Payload length in bytes. - \returns \ref status_codes */ int16_t explicitHeader(); From 1e564730a4df65b57b3ca895ab2e4508e86febdd Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 25 Jan 2022 12:19:17 -0700 Subject: [PATCH 0130/1848] Update keywords.txt --- keywords.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index a0b8ea6c64..a2a656bcf0 100644 --- a/keywords.txt +++ b/keywords.txt @@ -147,7 +147,7 @@ getFHSSHoppingPeriod KEYWORD2 getFHSSChannel KEYWORD2 clearFHSSInt KEYWORD2 randomByte KEYWORD2 -getPacketLength +getPacketLength KEYWORD2 # RF69-specific From 74feffb4c7e10b4eebedcd55c5adf3cf389eaf4c Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 28 Jan 2022 15:50:59 -0700 Subject: [PATCH 0131/1848] Fix >= to allow 255 bytes --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 1db50c20fa..a0f967da6d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -448,7 +448,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // check packet length - if(len >= RADIOLIB_SX127X_MAX_PACKET_LENGTH) { + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } From bad3029f4f2a778f1faf10590ebd68859c3224b4 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 28 Jan 2022 15:54:44 -0700 Subject: [PATCH 0132/1848] Update SX126x.h --- src/modules/SX126x/SX126x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 73d31b4341..507fb1270c 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -827,7 +827,7 @@ class SX126x: public PhysicalLayer { float getRSSIInst(); /*! - \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. + \brief Set implicit header mode for future reception/transmission. \param len Payload length in bytes. From 2538af82a908fa144c33201ed954412e8dc28474 Mon Sep 17 00:00:00 2001 From: "Arthur B. Grossi" Date: Mon, 31 Jan 2022 18:10:41 -0300 Subject: [PATCH 0133/1848] [Si443x] Fixes getPacketLength Fixes getPacketLength function to read the correct register when on fixed packet length mode. --- src/modules/Si443x/Si443x.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 90bba72ea4..f033d0ece9 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -512,9 +512,12 @@ int16_t Si443x::setPreambleLength(uint8_t preambleLen) { } size_t Si443x::getPacketLength(bool update) { - /// \todo variable length mode if(!_packetLengthQueried && update) { - _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); + if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON) { + _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH); + } else { + _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); + } _packetLengthQueried = true; } From 5c5afdf99fb008a0c97c774b7fcbab4a9c6fba23 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Feb 2022 15:06:58 +0100 Subject: [PATCH 0134/1848] Bump version to 5.1.1 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index e1cf56e093..84445c266a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.1.0 +version=5.1.1 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 37f3a426dd..24a1550631 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -990,7 +990,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) #define RADIOLIB_VERSION_MINOR (0x01) -#define RADIOLIB_VERSION_PATCH (0x00) +#define RADIOLIB_VERSION_PATCH (0x01) #define RADIOLIB_VERSION_EXTRA (0x00) #define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) From d3d2f90627bea49c54633534d099b26ebbd1a59e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Feb 2022 15:08:12 +0100 Subject: [PATCH 0135/1848] Bump version to 5.1.2 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 84445c266a..26cf375567 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.1.1 +version=5.1.2 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 24a1550631..143e274e84 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -990,7 +990,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) #define RADIOLIB_VERSION_MINOR (0x01) -#define RADIOLIB_VERSION_PATCH (0x01) +#define RADIOLIB_VERSION_PATCH (0x02) #define RADIOLIB_VERSION_EXTRA (0x00) #define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) From d07ad57a88c544fdba82b86adaae86c2a2decaf1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Feb 2022 17:00:12 +0100 Subject: [PATCH 0136/1848] [CI] Suppress Adafruit Feather M0 (CI_BUILD_ALL) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d2eca1a85a..7a2a5e7fb8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: - arduino:megaavr:uno2018 - arduino:sam:arduino_due_x - arduino:samd:arduino_zero_native - - adafruit:samd:adafruit_feather_m0 + #- adafruit:samd:adafruit_feather_m0 - adafruit:nrf52:feather52832 - esp32:esp32:esp32 - esp8266:esp8266:generic From bc30785bea6ea5364ee8c7fe920ba6a39b3c3789 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Feb 2022 17:04:54 +0100 Subject: [PATCH 0137/1848] [CI] Fixed board URL for Adafruit (CI_BUILD_ALL) --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7a2a5e7fb8..e4a327114b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: - arduino:megaavr:uno2018 - arduino:sam:arduino_due_x - arduino:samd:arduino_zero_native - #- adafruit:samd:adafruit_feather_m0 + - adafruit:samd:adafruit_feather_m0 - adafruit:nrf52:feather52832 - esp32:esp32:esp32 - esp8266:esp8266:generic @@ -85,7 +85,7 @@ jobs: elif [[ "${{ contains(matrix.board, 'adafruit:samd') }}" == "true" ]]; then # Adafruit SAMD echo "::set-output name=options:::usbstack=arduino,debug=off" - echo "::set-output name=index-url::--additional-urls https://www.adafruit.com/package_adafruit_index.json" + echo "::set-output name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" elif [[ "${{ contains(matrix.board, 'adafruit:nrf52') }}" == "true" ]]; then # Adafruit Feather nRF52 @@ -95,7 +95,7 @@ jobs: pip3 install --user adafruit-nrfutil echo "/home/runner/.local/bin" >> $GITHUB_PATH echo "::set-output name=options:::softdevice=s132v6,debug=l0" - echo "::set-output name=index-url::--additional-urls https://www.adafruit.com/package_adafruit_index.json" + echo "::set-output name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then # ESP32 From 1017ec99fdab2183081b11b7c0ad47d6699ae9cb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Feb 2022 19:04:03 +0100 Subject: [PATCH 0138/1848] [SX127x] Fixed error on newer compilers (CI_BUILD_ALL) --- .../SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index b6182af5f4..6139ad366e 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -115,7 +115,8 @@ void setup() { // start transmitting the first packet Serial.print(F("[SX1278] Sending first packet ... ")); - transmissionState = radio.startTransmit(longPacket + packetCounter); + String packet = longPacket + packetCounter; + transmissionState = radio.startTransmit(packet); } void loop() { @@ -156,7 +157,8 @@ void loop() { // send another packet Serial.print(F("[SX1278] Sending another packet ... ")); - transmissionState = radio.startTransmit(longPacket + packetCounter); + String packet = longPacket + packetCounter; + transmissionState = radio.startTransmit(packet); } // check if we need to do another frequency hop From 78536f9427533da1d8750fe10502fc2a3201ba19 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Feb 2022 18:04:25 +0100 Subject: [PATCH 0139/1848] [SX126x] Fixed CubeCell predefined module macro (#479) --- .../SX126x_Channel_Activity_Detection.ino | 2 +- .../SX126x_Channel_Activity_Detection_Interrupt.ino | 2 +- examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 2 +- examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino | 2 +- examples/SX126x/SX126x_Receive/SX126x_Receive.ino | 2 +- .../SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino | 2 +- examples/SX126x/SX126x_Settings/SX126x_Settings.ino | 2 +- examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino | 2 +- .../SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino index 8b28f2054a..850347a2ff 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino @@ -30,7 +30,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index f776377315..91580d0e79 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -30,7 +30,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index d3b910dbfe..2c394c5ccc 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -31,7 +31,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index 30c1550bb9..ff386c3648 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -27,7 +27,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); // save transmission states between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino index 364509ea4a..b2f49d2810 100644 --- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino +++ b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino @@ -35,7 +35,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 4132617c60..1b3daefd0b 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -36,7 +36,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index b601ae181a..7777c75d80 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -46,7 +46,7 @@ SX1268 radio2 = new Module(8, 4, 5, 6); //SX1261 radio3 = RadioShield.ModuleB; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino index c4857e2a6f..a287034ed9 100644 --- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino +++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino @@ -31,7 +31,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 69fd17c7cf..b4d441701d 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -32,7 +32,7 @@ SX1262 radio = new Module(10, 2, 3, 9); //SX1262 radio = RadioShield.ModuleA; // or using CubeCell -//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE); +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; From 01fc7fb844cc394c373a14ca427f7c411f8c376d Mon Sep 17 00:00:00 2001 From: Robert <3704942+JasonRJ@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:41:29 -0500 Subject: [PATCH 0140/1848] Add method to support SX128x Frequency Error of last received LoRa or Ranging packet. Updated SX128x receive examples. --- .../SX128x/SX128x_Receive/SX128x_Receive.ino | 6 ++++ .../SX128x_Receive_Interrupt.ino | 6 ++++ src/modules/SX128x/SX128x.cpp | 33 +++++++++++++++++++ src/modules/SX128x/SX128x.h | 7 ++++ 4 files changed, 52 insertions(+) diff --git a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino index 47c6c63b0b..28dc8047cb 100644 --- a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino +++ b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino @@ -85,6 +85,12 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); + // print the Frequency Error + // of the last received packet + Serial.print(F("[SX1280] Frequency Error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 274121df25..77d452c6fc 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -136,6 +136,12 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); + // print the Frequency Error + // of the last received packet + Serial.print(F("[SX1280] Frequency Error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 972e6ffc35..a59572e48f 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1064,6 +1064,39 @@ float SX128x::getSNR() { } } +double SX128x::getFrequencyError() { + // check active modem + uint8_t modem = getPacketType(); + if (!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return (0.0); + } + + uint8_t efeRaw[3] = {0}; + // read the raw frequency error register values + int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1); + RADIOLIB_ASSERT(state); + uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; + efe &= 0x0FFFFF; + + double error; + + // check the first bit + if (efe & 0x80000) { + // frequency error is negative + efe |= (uint32_t) 0xFFF00000; + efe = ~efe + 1; + error = 1.55 * (double) efe / (1600.0 / (double) _bwKhz) * -1.0; + } else { + error = 1.55 * (double) efe / (1600.0 / (double) _bwKhz); + } + + return (error); +} + size_t SX128x::getPacketLength(bool update) { (void)update; uint8_t rxBufStatus[2] = {0, 0}; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 9f258bb121..cf358c7406 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -727,6 +727,13 @@ class SX128x: public PhysicalLayer { */ float getSNR(); + /*! + \brief Gets frequency error of the latest received packet. + + \returns Frequency error in Hz. + */ + double getFrequencyError(); + /*! \brief Query modem for the packet length of received payload. From 89de031e187fc37faa3620bea99728b39b8b6392 Mon Sep 17 00:00:00 2001 From: Robert <3704942+JasonRJ@users.noreply.github.com> Date: Wed, 23 Feb 2022 23:51:54 -0500 Subject: [PATCH 0141/1848] Add method to support SX128x High Sensitivity Mode. --- src/modules/SX128x/SX128x.cpp | 15 +++++++++++++++ src/modules/SX128x/SX128x.h | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a59572e48f..9316eae2d6 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1020,6 +1020,21 @@ int16_t SX128x::setAccessAddress(uint32_t addr) { return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); } +int16_t SX128x::setHighSensitivityMode(bool hsm) { + // update register + uint8_t RxGain = 0; + int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); + RADIOLIB_ASSERT(state); + if (hsm) { + RxGain |= 0xC0; // Set bits 6 and 7 + } else { + RxGain &= ~0xC0; // Unset bits 6 and 7 + } + state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); + RADIOLIB_ASSERT(state); + return(0); +} + float SX128x::getRSSI() { // get packet status uint8_t packetStatus[5]; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index cf358c7406..5c18d6d178 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -713,6 +713,15 @@ class SX128x: public PhysicalLayer { */ int16_t setAccessAddress(uint32_t addr); +/*! + \brief Enables or disables receiver high sensitivity mode. + + \param True to enable and false to disable. + + \returns 0 +*/ + int16_t setHighSensitivityMode(bool hsm = false); + /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. From da0cd455c93f31fe10910c65979190feffb4c822 Mon Sep 17 00:00:00 2001 From: Robert <3704942+JasonRJ@users.noreply.github.com> Date: Wed, 23 Feb 2022 23:58:56 -0500 Subject: [PATCH 0142/1848] Add method to support SX128x Manual Gain Mode. --- src/modules/SX128x/SX128x.cpp | 33 +++++++++++++++++++++++++++++++++ src/modules/SX128x/SX128x.h | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 9316eae2d6..a92417161e 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1035,6 +1035,39 @@ int16_t SX128x::setHighSensitivityMode(bool hsm) { return(0); } +int16_t SX128x::setGainControl(uint8_t gain) { + // update registers + uint8_t ManualGainSetting = 0; + int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); + RADIOLIB_ASSERT(state); + uint8_t LNAGainValue = 0; + state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); + RADIOLIB_ASSERT(state); + uint8_t LNAGainControl = 0; + state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); + RADIOLIB_ASSERT(state); + if (gain > 0 && gain < 14) { + // Set manual gain + ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control) + LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 + LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) + LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control) + } else { + // Set automatic gain if 0 or out of range + ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control) + LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 + LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) + LNAGainControl = 0x4D; // Set bit 7 to 0 (Enable Automatic Gain Control) + } + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); + RADIOLIB_ASSERT(state); + return(0); +} + float SX128x::getRSSI() { // get packet status uint8_t packetStatus[5]; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 5c18d6d178..2537fe43bc 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -722,6 +722,15 @@ class SX128x: public PhysicalLayer { */ int16_t setHighSensitivityMode(bool hsm = false); + /*! + \brief Enables or disables receiver manual gain control. + + \param Gain 0 automatic gain; 1 minimum gain to 13 maximum gain. + + \returns \ref status_codes + */ + int16_t setGainControl(uint8_t gain = 0); + /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. From ff43d95afa4d74176f6b2532989ac5b805325f53 Mon Sep 17 00:00:00 2001 From: Robert <3704942+JasonRJ@users.noreply.github.com> Date: Thu, 24 Feb 2022 00:29:51 -0500 Subject: [PATCH 0143/1848] Cleaned up formatting in header. Changed assigned value to set only the bit indicated in the documentation. --- src/modules/SX128x/SX128x.cpp | 2 +- src/modules/SX128x/SX128x.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a92417161e..5f5ac79eb7 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1057,7 +1057,7 @@ int16_t SX128x::setGainControl(uint8_t gain) { ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control) LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) - LNAGainControl = 0x4D; // Set bit 7 to 0 (Enable Automatic Gain Control) + LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control) } state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 2537fe43bc..b86c39843e 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -713,13 +713,13 @@ class SX128x: public PhysicalLayer { */ int16_t setAccessAddress(uint32_t addr); -/*! - \brief Enables or disables receiver high sensitivity mode. + /*! + \brief Enables or disables receiver high sensitivity mode. - \param True to enable and false to disable. + \param True to enable and false to disable. - \returns 0 -*/ + \returns 0 + */ int16_t setHighSensitivityMode(bool hsm = false); /*! @@ -727,7 +727,7 @@ class SX128x: public PhysicalLayer { \param Gain 0 automatic gain; 1 minimum gain to 13 maximum gain. - \returns \ref status_codes + \returns 0 */ int16_t setGainControl(uint8_t gain = 0); From 70acd5b9aaef25fe87eda86b155aa9081276040a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Feb 2022 18:01:34 +0100 Subject: [PATCH 0144/1848] [SX127x] Added missin ISR flag for ESP32/ESP8266 --- .../SX127x_Channel_Activity_Detection_Interrupt.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 55372452f2..c1e0b1054a 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -96,6 +96,9 @@ void setFlagTimeout(void) { // is detected within timeout period // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlagDetected(void) { // check if the interrupt is enabled if(!enableInterrupt) { From 89f202ce6a1fcc0ab4906ecd6d68b8b87e94cb9e Mon Sep 17 00:00:00 2001 From: Robert <3704942+JasonRJ@users.noreply.github.com> Date: Sat, 26 Feb 2022 18:44:05 -0500 Subject: [PATCH 0145/1848] Changed method to return float instead of double. All calculations within the method also use float instead of double. Results of the method do not seem to be effected. --- src/modules/SX128x/SX128x.cpp | 8 ++++---- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 5f5ac79eb7..3bc66b8911 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1112,7 +1112,7 @@ float SX128x::getSNR() { } } -double SX128x::getFrequencyError() { +float SX128x::getFrequencyError() { // check active modem uint8_t modem = getPacketType(); if (!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { @@ -1130,16 +1130,16 @@ double SX128x::getFrequencyError() { uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; efe &= 0x0FFFFF; - double error; + float error; // check the first bit if (efe & 0x80000) { // frequency error is negative efe |= (uint32_t) 0xFFF00000; efe = ~efe + 1; - error = 1.55 * (double) efe / (1600.0 / (double) _bwKhz) * -1.0; + error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz) * -1.0; } else { - error = 1.55 * (double) efe / (1600.0 / (double) _bwKhz); + error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz); } return (error); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index b86c39843e..18f12f72c9 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -750,7 +750,7 @@ class SX128x: public PhysicalLayer { \returns Frequency error in Hz. */ - double getFrequencyError(); + float getFrequencyError(); /*! \brief Query modem for the packet length of received payload. From fa1811fe73e8beae5f41526b81cfb698ffe4c735 Mon Sep 17 00:00:00 2001 From: OBones Date: Mon, 28 Feb 2022 17:27:29 +0100 Subject: [PATCH 0146/1848] Introduce asynchronous reception and transmission for CC1101 --- src/modules/CC1101/CC1101.cpp | 48 +++++++++++++++++++++++++++++++++++ src/modules/CC1101/CC1101.h | 17 +++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 7af7fa82bc..228c988c10 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -208,6 +208,41 @@ int16_t CC1101::receiveDirect() { return(RADIOLIB_ERR_NONE); } +int16_t CC1101::transmitDirectAsync(uint32_t frf) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + + // user requested to start transmitting immediately (required for RTTY) + if(frf != 0) { + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ2, (frf & 0xFF0000) >> 16); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ1, (frf & 0x00FF00) >> 8); + SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ0, frf & 0x0000FF); + + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + } + + // activate asynchronous direct mode + int16_t state = asyncDirectMode(); + RADIOLIB_ASSERT(state); + + // start transmitting + SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + return(state); +} + +int16_t CC1101::receiveDirectAsync() { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + + // activate asynchronous direct mode + int16_t state = asyncDirectMode(); + RADIOLIB_ASSERT(state); + + // start receiving + SPIsendCommand(RADIOLIB_CC1101_CMD_RX); + return(ERR_NONE); +} + int16_t CC1101::packetMode() { int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF | RADIOLIB_CC1101_APPEND_STATUS_ON | RADIOLIB_CC1101_ADR_CHK_NONE, 3, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF | RADIOLIB_CC1101_PKT_FORMAT_NORMAL, 6, 4); @@ -902,6 +937,19 @@ int16_t CC1101::directMode() { return(state); } +int16_t CC1101::asyncDirectMode() { + // set mode to standby + SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + + // set GDO0 mapping + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0); + + // set asynchronous continuous mode + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS, 5, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); + return(state); +} + void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant) { // get table origin point (exp = 0, mant = 0) float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 5391203e5d..2aeb0bbeca 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -591,6 +591,22 @@ class CC1101: public PhysicalLayer { */ int16_t receiveDirect() override; + /*! + \brief Starts asynchronous direct mode transmission. + + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + + \returns \ref status_codes + */ + int16_t transmitDirectAsync(uint32_t frf = 0); + + /*! + \brief Starts asynchronous direct mode reception. + + \returns \ref status_codes + */ + int16_t receiveDirectAsync(); + /*! \brief Stops direct mode. It is required to call this method to switch from direct transmissions to packet-based transmissions. */ @@ -953,6 +969,7 @@ class CC1101: public PhysicalLayer { int16_t config(); int16_t directMode(); + int16_t asyncDirectMode(); static void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant); int16_t setPacketMode(uint8_t mode, uint16_t len); }; From 64817ed4be16c8e1b493eff06c8e6b5056b5f4da Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Feb 2022 18:47:55 +0100 Subject: [PATCH 0147/1848] [SX128x] Minor formatting update --- src/modules/SX128x/SX128x.cpp | 141 ++++++++++++++++++---------------- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 74 insertions(+), 69 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3bc66b8911..cf09f0bb97 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1021,51 +1021,56 @@ int16_t SX128x::setAccessAddress(uint32_t addr) { } int16_t SX128x::setHighSensitivityMode(bool hsm) { - // update register - uint8_t RxGain = 0; - int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); - RADIOLIB_ASSERT(state); - if (hsm) { - RxGain |= 0xC0; // Set bits 6 and 7 - } else { - RxGain &= ~0xC0; // Unset bits 6 and 7 - } - state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); - RADIOLIB_ASSERT(state); - return(0); + // read the current registers + uint8_t RxGain = 0; + int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); + RADIOLIB_ASSERT(state); + + if(hsm) { + RxGain |= 0xC0; // Set bits 6 and 7 + } else { + RxGain &= ~0xC0; // Unset bits 6 and 7 + } + + // update all values + state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); + return(state); } int16_t SX128x::setGainControl(uint8_t gain) { - // update registers - uint8_t ManualGainSetting = 0; - int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); - RADIOLIB_ASSERT(state); - uint8_t LNAGainValue = 0; - state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); - RADIOLIB_ASSERT(state); - uint8_t LNAGainControl = 0; - state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); - RADIOLIB_ASSERT(state); - if (gain > 0 && gain < 14) { - // Set manual gain - ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control) - LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 - LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) - LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control) - } else { - // Set automatic gain if 0 or out of range - ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control) - LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 - LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) - LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control) - } - state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); - RADIOLIB_ASSERT(state); - state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); - RADIOLIB_ASSERT(state); - state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); - RADIOLIB_ASSERT(state); - return(0); + // read the current registers + uint8_t ManualGainSetting = 0; + int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); + RADIOLIB_ASSERT(state); + uint8_t LNAGainValue = 0; + state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); + RADIOLIB_ASSERT(state); + uint8_t LNAGainControl = 0; + state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); + RADIOLIB_ASSERT(state); + + // set the gain + if (gain > 0 && gain < 14) { + // Set manual gain + ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control) + LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 + LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) + LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control) + } else { + // Set automatic gain if 0 or out of range + ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control) + LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0 + LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13) + LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control) + } + + // update all values + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1); + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1); + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1); + return(state); } float SX128x::getRSSI() { @@ -1113,36 +1118,36 @@ float SX128x::getSNR() { } float SX128x::getFrequencyError() { - // check active modem - uint8_t modem = getPacketType(); - if (!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { - return (0.0); - } + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { + return(0.0); + } - uint8_t efeRaw[3] = {0}; - // read the raw frequency error register values - int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1); - RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1); - RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1); - RADIOLIB_ASSERT(state); - uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; - efe &= 0x0FFFFF; + // read the raw frequency error register values + uint8_t efeRaw[3] = {0}; + int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1); + RADIOLIB_ASSERT(state); + uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; + efe &= 0x0FFFFF; - float error; + float error = 0; - // check the first bit - if (efe & 0x80000) { - // frequency error is negative - efe |= (uint32_t) 0xFFF00000; - efe = ~efe + 1; - error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz) * -1.0; - } else { - error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz); - } + // check the first bit + if (efe & 0x80000) { + // frequency error is negative + efe |= (uint32_t) 0xFFF00000; + efe = ~efe + 1; + error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz) * -1.0; + } else { + error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz); + } - return (error); + return(error); } size_t SX128x::getPacketLength(bool update) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 18f12f72c9..f9df39e3eb 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -725,7 +725,7 @@ class SX128x: public PhysicalLayer { /*! \brief Enables or disables receiver manual gain control. - \param Gain 0 automatic gain; 1 minimum gain to 13 maximum gain. + \param gain Use 0 for automatic gain, 1 for minimum gain and up to 13 for maximum gain. \returns 0 */ From 14184700388b38ae53733dec837309d2376794b3 Mon Sep 17 00:00:00 2001 From: OBones Date: Fri, 4 Mar 2022 09:38:59 +0100 Subject: [PATCH 0148/1848] Use protected overloads that accept the sync mode to avoid code duplication --- src/modules/CC1101/CC1101.cpp | 83 +++++++++++++---------------------- src/modules/CC1101/CC1101.h | 5 ++- 2 files changed, 34 insertions(+), 54 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 228c988c10..a5ee25cb95 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -174,6 +174,14 @@ int16_t CC1101::standby() { } int16_t CC1101::transmitDirect(uint32_t frf) { + return transmitDirect(true, frf); +} + +int16_t CC1101::transmitDirectAsync(uint32_t frf) { + return transmitDirect(false, frf); +} + +int16_t CC1101::transmitDirect(bool sync, uint32_t frf) { // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); @@ -187,7 +195,7 @@ int16_t CC1101::transmitDirect(uint32_t frf) { } // activate direct mode - int16_t state = directMode(); + int16_t state = directMode(sync); RADIOLIB_ASSERT(state); // start transmitting @@ -196,51 +204,24 @@ int16_t CC1101::transmitDirect(uint32_t frf) { } int16_t CC1101::receiveDirect() { - // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); - - // activate direct mode - int16_t state = directMode(); - RADIOLIB_ASSERT(state); - - // start receiving - SPIsendCommand(RADIOLIB_CC1101_CMD_RX); - return(RADIOLIB_ERR_NONE); + return receiveDirect(true); } -int16_t CC1101::transmitDirectAsync(uint32_t frf) { - // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); - - // user requested to start transmitting immediately (required for RTTY) - if(frf != 0) { - SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ2, (frf & 0xFF0000) >> 16); - SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ1, (frf & 0x00FF00) >> 8); - SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ0, frf & 0x0000FF); - - SPIsendCommand(RADIOLIB_CC1101_CMD_TX); - } - - // activate asynchronous direct mode - int16_t state = asyncDirectMode(); - RADIOLIB_ASSERT(state); - - // start transmitting - SPIsendCommand(RADIOLIB_CC1101_CMD_TX); - return(state); +int16_t CC1101::receiveDirectAsync() { + return receiveDirect(false); } -int16_t CC1101::receiveDirectAsync() { +int16_t CC1101::receiveDirect(bool sync) { // set RF switch (if present) _mod->setRfSwitchState(HIGH, LOW); - // activate asynchronous direct mode - int16_t state = asyncDirectMode(); + // activate direct mode + int16_t state = directMode(sync); RADIOLIB_ASSERT(state); // start receiving SPIsendCommand(RADIOLIB_CC1101_CMD_RX); - return(ERR_NONE); + return(RADIOLIB_ERR_NONE); } int16_t CC1101::packetMode() { @@ -923,29 +904,27 @@ int16_t CC1101::config() { return(state); } -int16_t CC1101::directMode() { +int16_t CC1101::directMode(bool sync) { // set mode to standby SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); - // set GDO0 and GDO2 mapping - int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); - - // set continuous mode - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); - return(state); -} + int16_t state = 0; + if (sync) { + // set GDO0 and GDO2 mapping + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); -int16_t CC1101::asyncDirectMode() { - // set mode to standby - SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + // set continuous mode + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); + } + else { + // set GDO0 mapping + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0); - // set GDO0 mapping - int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0); + // set asynchronous continuous mode + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS, 5, 4); + } - // set asynchronous continuous mode - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS, 5, 4); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); return(state); } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 2aeb0bbeca..05afd0f1ad 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -968,8 +968,9 @@ class CC1101: public PhysicalLayer { int8_t _power = 0; int16_t config(); - int16_t directMode(); - int16_t asyncDirectMode(); + int16_t transmitDirect(bool sync, uint32_t frf); + int16_t receiveDirect(bool sync); + int16_t directMode(bool sync); static void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant); int16_t setPacketMode(uint8_t mode, uint16_t len); }; From 9117c6125474db6b29f13c7874e6494377661005 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 9 Mar 2022 22:18:46 +0100 Subject: [PATCH 0149/1848] [CC1101] Fixed incorrect fabs brackets (#490) --- src/modules/CC1101/CC1101.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index a5ee25cb95..bf581fd58c 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -487,7 +487,7 @@ int16_t CC1101::setRxBandwidth(float rxBw) { for(int8_t e = 3; e >= 0; e--) { for(int8_t m = 3; m >= 0; m --) { float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); - if((fabs(rxBw * 1000.0) - point) <= 1000) { + if(fabs((rxBw * 1000.0) - point) <= 1000) { // set Rx channel filter bandwidth return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); } From c24c7750244fee68565ba6f371d056e46d1a518b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Mar 2022 18:08:09 +0100 Subject: [PATCH 0150/1848] Added support for MegaCore boards --- .github/workflows/main.yml | 7 ++++++- README.md | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e4a327114b..c1e134c3ad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,6 +32,7 @@ jobs: - MegaCoreX:megaavr:4809 - arduino:mbed_rp2040:pico - CubeCell:CubeCell:CubeCell-Board + - MegaCore:avr:1281 runs-on: ubuntu-latest name: ${{ matrix.board }} @@ -129,9 +130,13 @@ jobs: echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" elif [[ "${{ contains(matrix.board, 'CubeCell:CubeCell') }}" == "true" ]]; then - # MegaCoreX + # CubeCell echo "::set-output name=index-url::--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" + elif [[ "${{ contains(matrix.board, 'MegaCore:avr') }}" == "true" ]]; then + # MegaCore + echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" + fi - name: Install platform diff --git a/README.md b/README.md index ab9cfdb77b..6229160f33 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __MCUdude__ * [__MegaCoreX__](https://github.com/MCUdude/MegaCoreX) - megaAVR-0 series (ATmega4809, ATmega3209 etc.) + * [__MegaCore__](https://github.com/MCUdude/MegaCore) - AVR (ATmega1281, ATmega640 etc.) * __Raspberry Pi__ * [__RP2040__](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect From dd0d48abe98ef3fb0a1ba349087707a60516722d Mon Sep 17 00:00:00 2001 From: James Smith Date: Tue, 22 Mar 2022 16:33:36 -0700 Subject: [PATCH 0151/1848] Fix setRxBandwidth by calculating mantissa and exponent, rather than comparing floats --- src/modules/RF69/RF69.cpp | 101 +++++++------------------------------- 1 file changed, 17 insertions(+), 84 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 8a41666cf4..8b3f441bbd 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -457,93 +457,26 @@ int16_t RF69::setRxBandwidth(float rxBw) { return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); } - // check allowed bandwidth values - uint8_t bwMant, bwExp; - if(rxBw == 2.6) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 7; - } else if(rxBw == 3.1) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 7; - } else if(rxBw == 3.9) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 7; - } else if(rxBw == 5.2) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 6; - } else if(rxBw == 6.3) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 6; - } else if(rxBw == 7.8) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 6; - } else if(rxBw == 10.4) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 5; - } else if(rxBw == 12.5) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 5; - } else if(rxBw == 15.6) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 5; - } else if(rxBw == 20.8) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 4; - } else if(rxBw == 25.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 4; - } else if(rxBw == 31.3) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 4; - } else if(rxBw == 41.7) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 3; - } else if(rxBw == 50.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 3; - } else if(rxBw == 62.5) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 3; - } else if(rxBw == 83.3) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 2; - } else if(rxBw == 100.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 2; - } else if(rxBw == 125.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 2; - } else if(rxBw == 166.7) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 1; - } else if(rxBw == 200.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 1; - } else if(rxBw == 250.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 1; - } else if(rxBw == 333.3) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_24; - bwExp = 0; - } else if(rxBw == 400.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_20; - bwExp = 0; - } else if(rxBw == 500.0) { - bwMant = RADIOLIB_RF69_RX_BW_MANT_16; - bwExp = 0; - } else { - return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); - } - // set mode to standby - setMode(RADIOLIB_RF69_STANDBY); + int16_t state = setMode(RADIOLIB_RF69_STANDBY); + RADIOLIB_ASSERT(state); - // set Rx bandwidth - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, RADIOLIB_RF69_DCC_FREQ | bwMant | bwExp, 7, 0); - if(state == RADIOLIB_ERR_NONE) { - RF69::_rxBw = rxBw; + // calculate exponent and mantissa values for receiver bandwidth + for(int8_t e = 7; e >= 0; e--) { + for(int8_t m = 2; m >= 0; m--) { + float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); + if(fabs(rxBw - (point / 1000.0)) <= 0.1) { + // set Rx bandwidth + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); + if(state == RADIOLIB_ERR_NONE) { + RF69::_rxBw = rxBw; + } + return(state); + } + } } - return(state); + + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } int16_t RF69::setFrequencyDeviation(float freqDev) { From e20058c93cedc9086332c88aeb2b11204d7fd7c5 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 24 Mar 2022 10:30:45 -0700 Subject: [PATCH 0152/1848] [CC1101] Data shaping and encoding params in right order For some reason, the `RADIOLIB_SHAPING_NONE` was being passed to `setEncoding` and `RADIOLIB_ENCODING_NRZ` was being passed to `setDataShaping`. Flipped these to be passed to the correct functions. Note: These are both defined as `0x00` so this should have no impact on functionality, just makes initialization less confusing. --- src/modules/CC1101/CC1101.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index bf581fd58c..98a2dadccf 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -81,11 +81,11 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // set default data shaping - state = setDataShaping(RADIOLIB_ENCODING_NRZ); + state = setDataShaping(RADIOLIB_SHAPING_NONE); RADIOLIB_ASSERT(state); // set default encoding - state = setEncoding(RADIOLIB_SHAPING_NONE); + state = setEncoding(RADIOLIB_ENCODING_NRZ); RADIOLIB_ASSERT(state); // set default sync word From 361eba8ebc5cd4aac056451ce98726b1c3399a51 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 26 Mar 2022 12:53:17 -0700 Subject: [PATCH 0153/1848] Set RX bandwidth correctly for OOK mode --- src/modules/RF69/RF69.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 8b3f441bbd..11491f6738 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -464,7 +464,7 @@ int16_t RF69::setRxBandwidth(float rxBw) { // calculate exponent and mantissa values for receiver bandwidth for(int8_t e = 7; e >= 0; e--) { for(int8_t m = 2; m >= 0; m--) { - float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); + float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (_ook ? 3 : 2)))); if(fabs(rxBw - (point / 1000.0)) <= 0.1) { // set Rx bandwidth state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); From eed4075cb1d77a01e6b71eaf2cb7f7c53403af06 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 26 Mar 2022 13:08:46 -0700 Subject: [PATCH 0154/1848] [RF69] Persist bit synchronization settings --- src/modules/RF69/RF69.cpp | 20 +++++++++++++++++--- src/modules/RF69/RF69.h | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 8b3f441bbd..4c0e15ed14 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -223,7 +223,11 @@ int16_t RF69::directMode() { RADIOLIB_ASSERT(state); // set continuous mode - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + if(_bitSync) { + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + } else { + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5)); + } } int16_t RF69::packetMode() { @@ -666,11 +670,21 @@ int16_t RF69::disableSyncWordFiltering() { } int16_t RF69::enableContinuousModeBitSync() { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5); + if(state == RADIOLIB_ERR_NONE) { + _bitSync = true; + } + + return(state); } int16_t RF69::disableContinuousModeBitSync() { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5)); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5); + if(state == RADIOLIB_ERR_NONE) { + _bitSync = false; + } + + return(state); } int16_t RF69::setCrcFiltering(bool crcOn) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 8e4afdedd0..42c36b1447 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -942,6 +942,8 @@ class RF69: public PhysicalLayer { uint8_t _syncWordLength = 2; + bool _bitSync = true; + int16_t config(); int16_t directMode(); int16_t setPacketMode(uint8_t mode, uint8_t len); From 2b99b6ec86ab787a8e7a0b7eec9d4dca4b0a0eb8 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 26 Mar 2022 14:45:54 -0700 Subject: [PATCH 0155/1848] Add enableOOK param to RF69::begin, false by default, mirrors SX127x --- src/modules/RF69/RF69.cpp | 6 +++++- src/modules/RF69/RF69.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 11491f6738..fdb83ef8e0 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -9,7 +9,7 @@ Module* RF69::getMod() { return(_mod); } -int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { +int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen, bool enableOOK) { // set module properties _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); @@ -54,6 +54,10 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe int16_t state = config(); RADIOLIB_ASSERT(state); + // enable/disable OOK + state = setOOK(enableOOK); + RADIOLIB_ASSERT(state); + // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 8e4afdedd0..3b31383054 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -473,7 +473,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16, bool enableOOK = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. From 4f19d97f428c2bb6ec89b4a3032ae396e1af0acd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Mar 2022 17:38:22 +0200 Subject: [PATCH 0156/1848] [SX126x] Set initial BW to 500 kHz for LLCC68 (#502) --- src/modules/SX126x/SX126x.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index bfe9dba548..56eb61b6e9 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -18,11 +18,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo // BW in kHz and SF are required in order to calculate LDRO for setModulationParams // set the defaults, this will get overwritten later anyway - _bwKhz = 125.0; + _bwKhz = 500.0; _sf = 9; // initialize configuration variables (will be overwritten during public settings configuration) - _bw = RADIOLIB_SX126X_LORA_BW_125_0; + _bw = RADIOLIB_SX126X_LORA_BW_500_0; // initialized to 500 kHz, since lower valeus will interfere with LLCC68 _cr = RADIOLIB_SX126X_LORA_CR_4_7; _ldro = 0x00; _crcType = RADIOLIB_SX126X_LORA_CRC_ON; @@ -1424,7 +1424,8 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t } else { _ldro = ldro; } - + // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 + // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 uint8_t data[4] = {sf, bw, cr, _ldro}; return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); } From 63ba279fd2b6973e52aad9ac87e602673b7ffa5d Mon Sep 17 00:00:00 2001 From: James Smith Date: Mon, 28 Mar 2022 17:28:01 -0700 Subject: [PATCH 0157/1848] Call setRxBandwidth again if setOOK is called --- src/modules/RF69/RF69.cpp | 10 +++++----- src/modules/RF69/RF69.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 1ae6e1dcb6..5a3881520f 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -9,7 +9,7 @@ Module* RF69::getMod() { return(_mod); } -int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen, bool enableOOK) { +int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); @@ -54,10 +54,6 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe int16_t state = config(); RADIOLIB_ASSERT(state); - // enable/disable OOK - state = setOOK(enableOOK); - RADIOLIB_ASSERT(state); - // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); @@ -394,10 +390,14 @@ int16_t RF69::setOOK(bool enableOOK) { } else { state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK, 4, 3, 5); } + if(state == RADIOLIB_ERR_NONE) { _ook = enableOOK; } + // call setRxBandwidth again, since register values differ based on OOK mode being enabled + state |= setRxBandwidth(_rxBw); + return(state); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 34152b0c56..7e13deb613 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -473,7 +473,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16, bool enableOOK = false); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -744,6 +744,7 @@ class RF69: public PhysicalLayer { /*! \brief Enables/disables OOK modulation instead of FSK. + Note: This function calls setRxBandwidth again, since register values differ based on OOK mode being enabled/disabled \param enableOOK Enable (true) or disable (false) OOK. From 3a55ad92e178c121f381f0ae22c54ced554ee4d0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 2 Apr 2022 19:20:28 +0200 Subject: [PATCH 0158/1848] [CC1101] Fixed RSSI/LQI always returning incorrect values (#504) --- src/modules/CC1101/CC1101.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 98a2dadccf..eadd6a2b17 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -375,12 +375,6 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { RADIOLIB_DEBUG_PRINTLN(F("No data for more than 5mS. Stop here.")); break; } else { - /* - * Does this work for all rates? If 1 ms is longer than the 1ms delay - * then the entire FIFO will be transmitted during that delay. - * - * TODO: drop this delay(1) or come up with a better solution: - */ delay(1); bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); continue; @@ -400,17 +394,21 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { // check if status bytes are enabled (default: RADIOLIB_CC1101_APPEND_STATUS_ON) bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; + // for some reason, we need this delay here to get the correct status bytes + delay(3); + // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. - if (bytesInFIFO >= 2 && isAppendStatus) { + if (isAppendStatus) { // read RSSI byte _rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); - // read LQI and CRC byte - uint8_t val = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); - _rawLQI = val & 0x7F; + // read LQI and CRC byte + uint8_t val = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); + _rawLQI = val & 0x7F; // check CRC if (_crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { + _packetLengthQueried = false; return (RADIOLIB_ERR_CRC_MISMATCH); } } From 2e183d70bb3f4717d70d096537b795f6d8cece8a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 3 Apr 2022 12:14:26 +0200 Subject: [PATCH 0159/1848] [SX127x] Use RSSI interrupt and disable AFC (#505) --- src/modules/SX127x/SX127x.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index a0f967da6d..0ab12eff64 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -96,17 +96,12 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB state = SX127x::setAFCBandwidth(rxBw); RADIOLIB_ASSERT(state); - // set AFC&AGC trigger to RSSI (in OOK) or both (in FSK) - if(enableOOK) { - state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); - } else { - state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); - } - + // set AFC&AGC trigger to RSSI (both in OOK and FSK) + state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); RADIOLIB_ASSERT(state); // enable AFC - state = SX127x::setAFC(true); + state = SX127x::setAFC(false); RADIOLIB_ASSERT(state); // set receiver bandwidth @@ -998,7 +993,7 @@ int16_t SX127x::setOOK(bool enableOOK) { int16_t SX127x::setFrequencyRaw(float newFreq) { int16_t state = RADIOLIB_ERR_NONE; - + // set mode to standby if not FHSS if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = setMode(RADIOLIB_SX127X_STANDBY); @@ -1372,11 +1367,11 @@ int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { } uint8_t SX127x::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); } uint8_t SX127x::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); } void SX127x::clearFHSSInt(void) { @@ -1385,7 +1380,7 @@ void SX127x::clearFHSSInt(void) { _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { return; //These are not the interrupts you are looking for - } + } } #endif From 7f09fc430aceff61a85112a7f2c7264e25bb43de Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 9 Apr 2022 19:58:29 +0200 Subject: [PATCH 0160/1848] [SX126x] Enable timeout to generate IRQ event --- keywords.txt | 2 ++ src/modules/SX126x/SX126x.cpp | 10 +++++++--- src/modules/SX126x/SX126x.h | 11 +++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/keywords.txt b/keywords.txt index a2a656bcf0..55262f3f6e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -182,6 +182,8 @@ startReceiveDutyCycleAuto KEYWORD2 setRegulatorLDO KEYWORD2 setRegulatorDCDC KEYWORD2 getCurrentLimit KEYWORD2 +getIrqStatus KEYWORD2 + # nRF24 setIrqAction KEYWORD2 setAddressWidth KEYWORD2 diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 56eb61b6e9..5d4f2736aa 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -441,7 +441,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } int16_t SX126x::startReceive(uint32_t timeout) { - int16_t state = startReceiveCommon(); + int16_t state = startReceiveCommon(timeout); RADIOLIB_ASSERT(state); // set RF switch (if present) @@ -520,9 +520,13 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ return(startReceiveDutyCycle(wakePeriod, sleepPeriod)); } -int16_t SX126x::startReceiveCommon() { +int16_t SX126x::startReceiveCommon(uint32_t timeout) { // set DIO mapping - int16_t state = setDioIrqParams(RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT | RADIOLIB_SX126X_IRQ_CRC_ERR | RADIOLIB_SX126X_IRQ_HEADER_ERR, RADIOLIB_SX126X_IRQ_RX_DONE); + uint16_t mask = RADIOLIB_SX126X_IRQ_RX_DONE; + if(timeout != RADIOLIB_SX126X_RX_TIMEOUT_INF) { + mask |= RADIOLIB_SX126X_IRQ_TIMEOUT; + } + int16_t state = setDioIrqParams(RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT | RADIOLIB_SX126X_IRQ_CRC_ERR | RADIOLIB_SX126X_IRQ_HEADER_ERR, mask); RADIOLIB_ASSERT(state); // set buffer pointers diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 507fb1270c..57f3df664f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -511,6 +511,7 @@ class SX126x: public PhysicalLayer { \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX126X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX126X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + If timeout other than infinite is set, signal will be generated on DIO1. \returns \ref status_codes */ @@ -541,6 +542,13 @@ class SX126x: public PhysicalLayer { */ int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8); + /*! + \brief Reads the current IRQ status. + + \returns IRQ status bits + */ + uint16_t getIrqStatus(); + /*! \brief Reads data received after calling startReceive method. @@ -927,7 +935,6 @@ class SX126x: public PhysicalLayer { int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t readBuffer(uint8_t* data, uint8_t numBytes); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); - uint16_t getIrqStatus(); int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); int16_t calibrateImage(uint8_t* data); @@ -944,7 +951,7 @@ class SX126x: public PhysicalLayer { uint16_t getDeviceErrors(); int16_t clearDeviceErrors(); - int16_t startReceiveCommon(); + int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF); int16_t setFrequencyRaw(float freq); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); From 57dcf48f6bc386f180eecd444acce3668ae0b579 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 May 2022 18:46:56 +0200 Subject: [PATCH 0161/1848] [SX126x] Fixed swapped IQ inversion fix branches (#516) --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 5d4f2736aa..0b9a9b3e21 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1561,7 +1561,7 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { RADIOLIB_ASSERT(state); // set correct IQ configuration - if(iqConfig == RADIOLIB_SX126X_LORA_IQ_STANDARD) { + if(iqConfig == RADIOLIB_SX126X_LORA_IQ_INVERTED) { iqConfigCurrent &= 0xFB; } else { iqConfigCurrent |= 0x04; From 206d49f802b9aebe5b76338b0e66fe9b3ac88da2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 May 2022 17:31:51 +0200 Subject: [PATCH 0162/1848] [CC1101] Fixed Tx buffer flushed on Rx timeout (#520) --- src/modules/CC1101/CC1101.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index eadd6a2b17..d55d222d0f 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -155,7 +155,7 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { if(_mod->micros() - start > timeout) { standby(); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); return(RADIOLIB_ERR_RX_TIMEOUT); } } From 9b392e349e49803df4fa79b204bef090650df852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 23 May 2022 13:46:36 +0200 Subject: [PATCH 0163/1848] [CC1101] Fixed incorrect parameter documentation (#523) --- src/modules/CC1101/CC1101.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 05afd0f1ad..ae440b4c8c 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -852,7 +852,7 @@ class CC1101: public PhysicalLayer { /*! \brief Enable CRC filtering and generation. - \param crcOn Set or unset promiscuous mode. + \param crcOn Set or unset CRC generation and filtering. \returns \ref status_codes */ From 0a79f7fc226bc5034dc1257788fbb529e63f4884 Mon Sep 17 00:00:00 2001 From: matthias-bs <83612361+matthias-bs@users.noreply.github.com> Date: Mon, 23 May 2022 17:30:40 +0200 Subject: [PATCH 0164/1848] added setCrcFiltering() --- src/modules/SX127x/SX127x.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index be3e2d0b9c..2597695ec2 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -980,6 +980,15 @@ class SX127x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); + /*! + \brief Enable CRC filtering and generation. + + \param crcOn Set or unset CRC filtering and generation. + + \returns \ref status_codes + */ + int16_t setCrcFiltering(bool crcOn = true); + /*! \brief Sets RSSI measurement configuration in FSK mode. @@ -1117,6 +1126,7 @@ class SX127x: public PhysicalLayer { float _br = 0; bool _ook = false; bool _crcEnabled = false; + bool _crcOn = true; // default value used in FSK mode size_t _packetLength = 0; int16_t setFrequencyRaw(float newFreq); From 76ddaf5f6747790820538f7de8afaaa46e4d6370 Mon Sep 17 00:00:00 2001 From: matthias-bs <83612361+matthias-bs@users.noreply.github.com> Date: Mon, 23 May 2022 17:32:58 +0200 Subject: [PATCH 0165/1848] added setCrcFiltering() --- src/modules/SX127x/SX127x.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 0ab12eff64..08680c063e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1045,6 +1045,16 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen)); } +int16_t SX127x::setCrcFiltering(bool crcOn) { + _crcOn = crcOn; + + if (crcOn == true) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4)); + } else { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4)); + } +} + int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { From 2faa4b5d71303a4ec82607025379debccc7aa495 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 May 2022 17:57:42 +0200 Subject: [PATCH 0166/1848] [Morse] Use out of band tone for space in AFSK mode (#529) --- src/protocols/AFSK/AFSK.cpp | 6 +++++- src/protocols/AFSK/AFSK.h | 4 +++- src/protocols/Morse/Morse.cpp | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index 53ffe7d960..29c0044815 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -24,9 +24,13 @@ int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { return(RADIOLIB_ERR_NONE); } -int16_t AFSKClient::noTone() { +int16_t AFSKClient::noTone(bool keepOn) { Module* mod = _phy->getMod(); mod->noTone(_pin); + if(keepOn) { + return(0); + } + return(_phy->standby()); } diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index 9df3cb41be..72b454717c 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -46,9 +46,11 @@ class AFSKClient { /*! \brief Stops transmitting audio tone. + \param freq Keep transmitter on - this may limit noise when switching transmitter on or off. + \returns \ref status_codes */ - int16_t noTone(); + int16_t noTone(bool keepOn = false); #if !defined(RADIOLIB_GODMODE) private: diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 2395562e2a..d3dd40f69f 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -308,7 +308,7 @@ int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { int16_t MorseClient::standby() { #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { - return(_audio->noTone()); + return(_audio->noTone(true)); } #endif return(_phy->standby()); From ed43f8062e3037cb84efb0389f1cb1b610e85825 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 May 2022 17:58:34 +0200 Subject: [PATCH 0167/1848] [Hell] Added method to invert text color (#529) --- .../Hellschreiber_Transmit_AFSK.ino | 6 ++++++ keywords.txt | 1 + src/protocols/Hellschreiber/Hellschreiber.cpp | 6 +++++- src/protocols/Hellschreiber/Hellschreiber.h | 10 ++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino index 79908b7d37..1fdff4a22e 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -90,6 +90,12 @@ void loop() { // string saved in flash hell.print(F("Flash String")); + // in AFSK mode, it is possible to invert the text colors + // use white text on black background + hell.setInversion(true); + hell.print("Inverted String"); + hell.setInversion(false); + // character hell.print('c'); diff --git a/keywords.txt b/keywords.txt index 55262f3f6e..236c8039af 100644 --- a/keywords.txt +++ b/keywords.txt @@ -223,6 +223,7 @@ getRangingResult KEYWORD2 # Hellschreiber printGlyph KEYWORD2 +setInversion KEYWORD2 # AFSK tone KEYWORD2 diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index a284eb60c3..6a32f306e5 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -49,6 +49,10 @@ size_t HellClient::printGlyph(uint8_t* buff) { return(1); } +void HellClient::setInversion(bool invert) { + _inv = invert; +} + size_t HellClient::write(const char* str) { if(str == NULL) { return(0); @@ -295,7 +299,7 @@ int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { int16_t HellClient::standby() { #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { - return(_audio->noTone()); + return(_audio->noTone(_inv)); } #endif return(_phy->standby()); diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 9e6913d9ad..59e1140976 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -119,9 +119,18 @@ class HellClient { \brief Method to "print" a buffer of pixels, this is exposed to allow users to send custom characters. \param buff Buffer of pixels to send, in a 7x7 pixel array. + + \returns Always returns the number of printed glyphs (1). */ size_t printGlyph(uint8_t* buff); + /*! + \brief Invert text color. + + \param invert Whether to enable color inversion (white text on black background), or not (black text on white background) + */ + void setInversion(bool invert); + size_t write(const char* str); size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); @@ -159,6 +168,7 @@ class HellClient { uint32_t _base = 0, _baseHz = 0; uint32_t _pixelDuration = 0; + bool _inv = false; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); From 3df3b092ebf412bd0b26524e7b296733bd6a62f7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 May 2022 18:22:03 +0200 Subject: [PATCH 0168/1848] [SX126x] Fixed default frequency deviation for SX1262 (#522) --- src/modules/SX126x/SX1262.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 31724bc31a..6d3f0258ab 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -71,7 +71,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 0.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods From 77c9a295ed15263aea2eec340f75655d50c0a2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 30 May 2022 10:49:55 +0200 Subject: [PATCH 0169/1848] [SX127x] Fixed RF switch not actuated in continuous Rx mode (#531) --- src/modules/SX127x/SX127x.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 08680c063e..20125c57c5 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -403,6 +403,8 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // FSK modem does not distinguish between Rx single and continuous if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); return(setMode(RADIOLIB_SX127X_RX)); } } From 05a4cf1ef145c9e6e61f760250241b75bd26f35c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jun 2022 11:15:54 +0200 Subject: [PATCH 0170/1848] [SX126x] Added LR-FHSS registers --- src/modules/SX126x/SX126x.cpp | 6 ++-- src/modules/SX126x/SX126x.h | 52 ++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 0b9a9b3e21..64161ea38b 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1538,17 +1538,17 @@ int16_t SX126x::fixImplicitTimeout() { // stop RTC counter uint8_t rtcStop = 0x00; - int16_t state = writeRegister(RADIOLIB_SX126X_REG_RTC_STOP, &rtcStop, 1); + int16_t state = writeRegister(RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL, &rtcStop, 1); RADIOLIB_ASSERT(state); // read currently active event uint8_t rtcEvent = 0; - state = readRegister(RADIOLIB_SX126X_REG_RTC_EVENT, &rtcEvent, 1); + state = readRegister(RADIOLIB_SX126X_REG_EVENT_MASK, &rtcEvent, 1); RADIOLIB_ASSERT(state); // clear events rtcEvent |= 0x02; - return(writeRegister(RADIOLIB_SX126X_REG_RTC_EVENT, &rtcEvent, 1)); + return(writeRegister(RADIOLIB_SX126X_REG_EVENT_MASK, &rtcEvent, 1)); } int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 57f3df664f..df2d295291 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -70,6 +70,19 @@ // SX126X register map +#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 +#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) +#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 +#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 +#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 +#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 #define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC @@ -86,6 +99,7 @@ #define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 #define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD #define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 @@ -93,16 +107,16 @@ #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C #define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC +#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 #define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 +#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 #define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 #define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 +#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 +#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 // undocumented registers #define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 -#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 // SX1268 datasheet v1.1, section 15.2 -#define RADIOLIB_SX126X_REG_RTC_STOP 0x0920 // SX1268 datasheet v1.1, section 15.3 -#define RADIOLIB_SX126X_REG_RTC_EVENT 0x0944 // SX1268 datasheet v1.1, section 15.3 -#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 // SX1268 datasheet v1.1, section 15.4 #define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 #define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 #define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 @@ -174,18 +188,19 @@ #define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) //RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b1000000000 // 9 9 Rx or Tx timeout -#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0100000000 // 8 8 channel activity detected -#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0010000000 // 7 7 channel activity detection finished -#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0001000000 // 6 6 wrong CRC received -#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000100000 // 5 5 LoRa header CRC error -#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received -#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000001000 // 3 3 valid sync word detected -#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000100 // 2 2 preamble detected -#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000010 // 1 1 packet received -#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000001 // 0 0 packet transmission completed -#define RADIOLIB_SX126X_IRQ_ALL 0b1111111111 // 9 0 all interrupts -#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000 // 9 0 no interrupts +#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop +#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout +#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected +#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished +#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received +#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error +#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received +#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected +#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received +#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts +#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts //RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL #define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ @@ -204,6 +219,7 @@ //RADIOLIB_SX126X_CMD_SET_PACKET_TYPE #define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK #define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS //RADIOLIB_SX126X_CMD_SET_TX_PARAMS #define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us @@ -328,6 +344,10 @@ // SX126X SPI register variables +//RADIOLIB_SX126X_REG_HOPPING_ENABLE +#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled +#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) + //RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB #define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. #define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. From 08989ff6fa615672938df2de9233af87d074da85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 10 Jun 2022 12:28:32 +0200 Subject: [PATCH 0171/1848] Allow SPItransfer to be overridden by subclasses This allows API clients to provide 'smarter' versions of Module that can do things like add thread safety so that multiple devices (and service threads) can share the same SPI bus. i.e. a subclass would lock some sort of mutex. This is used in the Radiolib Fork for Meshtastic to share an SPI bus with SD Card and TFT Display but we want to move back to upstream and not maintain our own fork. --- src/Module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.h b/src/Module.h index 3a7b098d42..2492c1a4be 100644 --- a/src/Module.h +++ b/src/Module.h @@ -190,7 +190,7 @@ class Module { \param numBytes Number of bytes to transfer. */ - void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + virtual void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); // pin number access methods From 6b83e08cfaa25ce520ee98da1bc68f8d70172a49 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Jun 2022 19:31:15 +0200 Subject: [PATCH 0172/1848] Added support for Teensy (#175) --- .github/workflows/main.yml | 5 +++++ README.md | 3 +++ src/BuildOpt.h | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1e134c3ad..bb7d6d5290 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,6 +33,7 @@ jobs: - arduino:mbed_rp2040:pico - CubeCell:CubeCell:CubeCell-Board - MegaCore:avr:1281 + - teensy:avr:teensy41 runs-on: ubuntu-latest name: ${{ matrix.board }} @@ -137,6 +138,10 @@ jobs: # MegaCore echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" + elif [[ "${{ contains(matrix.board, 'teensy:avr') }}" == "true" ]]; then + # Teensy + echo "::set-output name=index-url::--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" + fi - name: Install platform diff --git a/README.md b/README.md index 6229160f33..cd61be2f4c 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,9 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __Heltec__ * [__CubeCell__](https://github.com/HelTecAutomation/CubeCell-Arduino) - ASR650X series (CubeCell-Board, CubeCell-Capsule, CubeCell-Module etc.) +* __PJRC__ + * [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards + The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. ### In development: diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 143e274e84..29e80d2d07 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -734,7 +734,7 @@ #undef yield #endif -#elif defined(RASPI) + #elif defined(RASPI) // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) #define RADIOLIB_PLATFORM "RasPiArduino" #define RADIOLIB_PIN_TYPE uint8_t @@ -788,6 +788,40 @@ inline unsigned long micros() { return((unsigned long)(STCV)); }; #endif + #elif defined(TEENSYDUINO) + // Teensy + #define RADIOLIB_PLATFORM "Teensy" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint8_t, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, short unsigned int frequency, long unsigned int duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, long unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" From 1ebf420a868190911bde2bc59483c4a126e1bc4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 12 Jun 2022 21:20:48 +0200 Subject: [PATCH 0173/1848] change locking mechanism in patch to transactions --- src/Module.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module.h b/src/Module.h index 2492c1a4be..aa38f6d4ee 100644 --- a/src/Module.h +++ b/src/Module.h @@ -190,7 +190,7 @@ class Module { \param numBytes Number of bytes to transfer. */ - virtual void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); // pin number access methods @@ -361,9 +361,9 @@ class Module { // helper functions to set up SPI overrides on Arduino #if defined(RADIOLIB_BUILD_ARDUINO) void SPIbegin(); - void SPIbeginTransaction(); + virtual void SPIbeginTransaction(); uint8_t SPItransfer(uint8_t b); - void SPIendTransaction(); + virtual void SPIendTransaction(); void SPIend(); #endif From 0fab561713353ab57611325d40323fd2d71a9a89 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 13 Jun 2022 18:32:53 +0200 Subject: [PATCH 0174/1848] Bump version to 5.2.0 --- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index 26cf375567..999a3e6437 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.1.2 +version=5.2.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 29e80d2d07..6ca44f1d4c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1023,8 +1023,8 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x01) -#define RADIOLIB_VERSION_PATCH (0x02) +#define RADIOLIB_VERSION_MINOR (0x02) +#define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) #define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) From ba67ce2720d7809ff52bc3d58d61613a46481592 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 15 Jun 2022 19:31:53 +0200 Subject: [PATCH 0175/1848] [SX127x] Fixed RSSI offset not shifted (#538) --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 20125c57c5..7d850e240d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1075,7 +1075,7 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET); // set new register values - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset, 7, 3); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset << 3, 7, 3); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); return(state); } From e5e8947e94c7bf5cd683426b0e169d88ad093735 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jun 2022 16:10:33 +0200 Subject: [PATCH 0176/1848] [SX127x] Fixed incorrect packet length check in FSK mode --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7d850e240d..261e9814f0 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -472,7 +472,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // check packet length - if(len >= RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } From 298dbe8e5c2230903789d9a2f44f614babad6efe Mon Sep 17 00:00:00 2001 From: Jaimi5 Date: Fri, 24 Jun 2022 17:38:31 +0200 Subject: [PATCH 0177/1848] RadioLib - getTimeOnAir for SX127x modules --- src/modules/SX127x/SX127x.cpp | 24 ++++++++++++++---------- src/modules/SX127x/SX127x.h | 9 +++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 261e9814f0..cdcaf906e1 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -148,16 +148,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { uint32_t start = 0; if(modem == RADIOLIB_SX127X_LORA) { // calculate timeout (150 % of expected time-one-air) - float symbolLength = (float)(uint32_t(1) <<_sf) / (float)_bw; - float de = 0; - if(symbolLength >= 16.0) { - de = 1; - } - float ih = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); - float crc = (float)(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); - float n_pre = (float)((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); - float n_pay = 8.0 + max(ceil((8.0 * (float)len - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0.0); - uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1500.0); + uint32_t timeout = getTimeOnAir(len) * 1500.0; // start transmission state = startTransmit(data, len, addr); @@ -1047,6 +1038,19 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen)); } +uint32_t SX127x::getTimeOnAir(size_t len) { + float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw; + float de = 0; + if (symbolLength >= 16.0) { + de = 1; + } + float ih = (float) _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) _sf + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) _sf - 8.0 * de)) * (float) _cr, 0.0); + return ceil(symbolLength * (n_pre + n_pay + 4.25)); +} + int16_t SX127x::setCrcFiltering(bool crcOn) { _crcOn = crcOn; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 2597695ec2..15ba7154d4 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -980,6 +980,15 @@ class SX127x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); + /*! + \brief Get expected time-on-air for a given size of payload + + \param len Payload length in bytes. + + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len); + /*! \brief Enable CRC filtering and generation. From 19715ef204fa8e0768fee9412475e1753b223165 Mon Sep 17 00:00:00 2001 From: Jaimi5 Date: Sat, 25 Jun 2022 14:04:44 +0200 Subject: [PATCH 0178/1848] RadioLib - Now getTimeOnAir returns microseconds --- src/modules/SX127x/SX127x.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index cdcaf906e1..5b7198730f 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -148,7 +148,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { uint32_t start = 0; if(modem == RADIOLIB_SX127X_LORA) { // calculate timeout (150 % of expected time-one-air) - uint32_t timeout = getTimeOnAir(len) * 1500.0; + uint32_t timeout = getTimeOnAir(len) * 1.5; // start transmission state = startTransmit(data, len, addr); @@ -1039,15 +1039,23 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { } uint32_t SX127x::getTimeOnAir(size_t len) { - float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw; + // Get symbol length in us + float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw * 1000; + // Get Low Data Rate optimization flag float de = 0; if (symbolLength >= 16.0) { de = 1; } + // Get explicit/implicit header enabled flag float ih = (float) _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + // Get CRC enabled flag float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + // Get number of bits preamble float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + // Get number of bits payload float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) _sf + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) _sf - 8.0 * de)) * (float) _cr, 0.0); + + // Get time-on-air in us return ceil(symbolLength * (n_pre + n_pay + 4.25)); } From 314fcb2d6e9cc84696ba8d0571795eb21139b77c Mon Sep 17 00:00:00 2001 From: Jaimi5 Date: Sun, 26 Jun 2022 23:33:05 +0200 Subject: [PATCH 0179/1848] RadioLib - getTimeOnAir for FSK mode in module SX127x --- src/modules/SX127x/SX127x.cpp | 65 +++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 5b7198730f..a1b18e7071 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -147,7 +147,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t modem = getActiveModem(); uint32_t start = 0; if(modem == RADIOLIB_SX127X_LORA) { - // calculate timeout (150 % of expected time-one-air) + // calculate timeout (150 % of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 1.5; // start transmission @@ -166,7 +166,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); + uint32_t timeout = 5000 + getTimeOnAir(len) * 5; // start transmission state = startTransmit(data, len, addr); @@ -218,8 +218,8 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // calculate timeout (500 % of expected time-one-air) - uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); + // calculate timeout (500 % of expected time-on-air) + uint32_t timeout = getTimeOnAir(len) * 5; // set mode to receive state = startReceive(len, RADIOLIB_SX127X_RX); @@ -1039,24 +1039,45 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { } uint32_t SX127x::getTimeOnAir(size_t len) { - // Get symbol length in us - float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw * 1000; - // Get Low Data Rate optimization flag - float de = 0; - if (symbolLength >= 16.0) { - de = 1; - } - // Get explicit/implicit header enabled flag - float ih = (float) _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); - // Get CRC enabled flag - float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); - // Get number of bits preamble - float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); - // Get number of bits payload - float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) _sf + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) _sf - 8.0 * de)) * (float) _cr, 0.0); - - // Get time-on-air in us - return ceil(symbolLength * (n_pre + n_pay + 4.25)); + // check active modem + uint8_t modem = getActiveModem(); + if (modem == RADIOLIB_SX127X_LORA) { + // Get symbol length in us + float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw; + // Get Low Data Rate optimization flag + float de = 0; + if (symbolLength >= 16.0) { + de = 1; + } + // Get explicit/implicit header enabled flag + float ih = (float) _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + // Get CRC enabled flag + float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + // Get number of bits preamble + float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + // Get number of bits payload + float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) _sf + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) _sf - 8.0 * de)) * (float) _cr, 0.0); + + // Get time-on-air in us + return ceil(symbolLength * (n_pre + n_pay + 4.25)) * 1000; + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // Get number of bits preamble + float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; + //Get the number of bits of the sync word + float n_syncWord = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1); + //Get CRC enabled flag + float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) >> 2); + //Get payload length + uint16_t mode = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 7, 7); + if (mode == RADIOLIB_SX127X_PACKET_FIXED) + len = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + + // Calculate time-on-air in us ((length in bytes) * (8 bits / 1 byte)) / ((Bit Rate in kbps) * (1000 bps / 1 kbps)) * (1000000 us in 1 sec) + return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (_br * 1000.0)) * 1000000.0); + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + } int16_t SX127x::setCrcFiltering(bool crcOn) { From de84410e69793cd4832501216261ec46b18e8ae8 Mon Sep 17 00:00:00 2001 From: Jaimi5 Date: Sun, 26 Jun 2022 23:39:44 +0200 Subject: [PATCH 0180/1848] RadioLib - type of packet length FSK mode getter changed. --- src/modules/SX127x/SX127x.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index a1b18e7071..d4a093acd1 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1068,8 +1068,7 @@ uint32_t SX127x::getTimeOnAir(size_t len) { //Get CRC enabled flag float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) >> 2); //Get payload length - uint16_t mode = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 7, 7); - if (mode == RADIOLIB_SX127X_PACKET_FIXED) + if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) len = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); // Calculate time-on-air in us ((length in bytes) * (8 bits / 1 byte)) / ((Bit Rate in kbps) * (1000 bps / 1 kbps)) * (1000000 us in 1 sec) From 3b305591d269359c8527b976d77c2aff7dc02fc9 Mon Sep 17 00:00:00 2001 From: Jaimi5 Date: Sun, 26 Jun 2022 23:49:15 +0200 Subject: [PATCH 0181/1848] RadioLib - syncWord to bits --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index d4a093acd1..18282b5710 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1064,7 +1064,7 @@ uint32_t SX127x::getTimeOnAir(size_t len) { // Get number of bits preamble float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; //Get the number of bits of the sync word - float n_syncWord = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1); + float n_syncWord = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; //Get CRC enabled flag float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) >> 2); //Get payload length From 46919cb2499d0b4a6e8c541b92f5457dcb9797a1 Mon Sep 17 00:00:00 2001 From: Jaimi5 Date: Fri, 1 Jul 2022 17:03:02 +0200 Subject: [PATCH 0182/1848] RadioLib - FSK getTimeOnAir, crc bits and packet length configuration fixed --- src/modules/SX127x/SX127x.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 18282b5710..731b77d91f 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1065,13 +1065,18 @@ uint32_t SX127x::getTimeOnAir(size_t len) { float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; //Get the number of bits of the sync word float n_syncWord = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; - //Get CRC enabled flag - float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) >> 2); - //Get payload length - if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) + //Get CRC bits + float crc = (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16; + + if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { + //If Packet size fixed -> len = fixed packet length len = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + } else { + //if packet variable -> Add 1 extra byte for payload length + len += 1; + } - // Calculate time-on-air in us ((length in bytes) * (8 bits / 1 byte)) / ((Bit Rate in kbps) * (1000 bps / 1 kbps)) * (1000000 us in 1 sec) + // Calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (_br * 1000.0)) * 1000000.0); } else { return(RADIOLIB_ERR_UNKNOWN); From f8f73d2ccbb32b4134e441c2e8652400c1fd78ba Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 3 Jul 2022 11:05:56 +0200 Subject: [PATCH 0183/1848] [MOD] Added helper hexdump function --- src/Module.cpp | 20 ++++++++++++++++++++ src/Module.h | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index d430b9aaba..2a6e35cdc7 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -445,6 +445,26 @@ uint16_t Module::flipBits16(uint16_t i) { return i; } +void Module::hexdump(uint8_t* data, size_t len) { + for(int i = 0; i < len; i+=16) { + char str[80]; + sprintf(str, "%07x ", i); + for(int j = 0; j < 16; j++) { + sprintf(&str[8 + j*3], "%02x ", data[i+j]); + } + str[56] = '|'; + str[57] = ' '; + for(int j = 0; j < 16; j++) { + char c = data[i+j]; + if((c < ' ') || (c > '~')) { + c = '.'; + } + sprintf(&str[58 + j], "%c", c); + } + RADIOLIB_DEBUG_PRINTLN(str); + } +} + void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _useRfSwitch = true; _rxEn = rxEn; diff --git a/src/Module.h b/src/Module.h index aa38f6d4ee..7b93d154ec 100644 --- a/src/Module.h +++ b/src/Module.h @@ -377,6 +377,15 @@ class Module { */ static uint16_t flipBits16(uint16_t i); + /*! + \brief Function to dump data as hex into the debug port. + + \param data Data to dump. + + \param data Number of bytes to dump. + */ + static void hexdump(uint8_t* data, size_t len); + // hardware abstraction layer callbacks RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE); From 701e2c4a2118cdf9eb76bb8652602493aaf3b426 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 4 Jul 2022 15:17:41 +0200 Subject: [PATCH 0184/1848] [SX127x] Formatting fixes --- src/modules/SX127x/SX127x.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 731b77d91f..5c038033dc 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -443,8 +443,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set DIO mapping if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); - } - else { + } else { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); } @@ -816,7 +815,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) { return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0)); } -int16_t SX127x::setAFCBandwidth(float rxBw){ +int16_t SX127x::setAFCBandwidth(float rxBw) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK){ return(RADIOLIB_ERR_WRONG_MODEM); @@ -832,7 +831,7 @@ int16_t SX127x::setAFCBandwidth(float rxBw){ return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0)); } -int16_t SX127x::setAFC(bool isEnabled){ +int16_t SX127x::setAFC(bool isEnabled) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -842,7 +841,7 @@ int16_t SX127x::setAFC(bool isEnabled){ return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4)); } -int16_t SX127x::setAFCAGCTrigger(uint8_t trigger){ +int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) { if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } From 907de02a79406508e22c85045369977f38e551b1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 4 Jul 2022 15:28:26 +0200 Subject: [PATCH 0185/1848] [PHY] getMod moved to private and only acessible to friend classes --- src/protocols/PhysicalLayer/PhysicalLayer.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 425dddc727..c1d236d81d 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -300,8 +300,6 @@ class PhysicalLayer { */ uint8_t read(); - virtual Module* getMod() = 0; - protected: void updateDirectBuffer(uint8_t bit); @@ -320,6 +318,17 @@ class PhysicalLayer { uint8_t _directSyncWordLen; uint32_t _directSyncWordMask; bool _gotSync; + + virtual Module* getMod() = 0; + + // allow specific classes access the private getMod method + friend class AFSKClient; + friend class RTTYClient; + friend class MorseClient; + friend class HellClient; + friend class SSTVClient; + friend class AX25Client; + friend class FSK4Client; }; #endif From 8ae092ac8123716db58dda01af1486a87aab2964 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 4 Jul 2022 15:30:37 +0200 Subject: [PATCH 0186/1848] [MOD] Added regdump function --- src/Module.cpp | 13 +++++++++++++ src/Module.h | 11 ++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 2a6e35cdc7..eb20ff7b5b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -465,6 +465,19 @@ void Module::hexdump(uint8_t* data, size_t len) { } } +void Module::regdump(uint8_t start, uint8_t len) { + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buff = new uint8_t[len]; + #endif + SPIreadRegisterBurst(start, len, buff); + hexdump(buff, len); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buff; + #endif +} + void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _useRfSwitch = true; _rxEn = rxEn; diff --git a/src/Module.h b/src/Module.h index 7b93d154ec..93ddf15972 100644 --- a/src/Module.h +++ b/src/Module.h @@ -382,10 +382,19 @@ class Module { \param data Data to dump. - \param data Number of bytes to dump. + \param len Number of bytes to dump. */ static void hexdump(uint8_t* data, size_t len); + /*! + \brief Function to dump device registers as hex into the debug port. + + \param start First address to dump. + + \param len Number of bytes to dump. + */ + void regdump(uint8_t start, uint8_t len); + // hardware abstraction layer callbacks RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE); From e421ab4272d21af6d7b5e5d57f2dded84923b6e0 Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 6 Jul 2022 15:28:50 +0200 Subject: [PATCH 0187/1848] Introduce setDIOMapping on the PhysicalLayer class which, by default, returns "not implemented" --- src/TypeDef.h | 10 ++++++++++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 11 +++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/TypeDef.h b/src/TypeDef.h index a9687c1385..71b738c265 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -203,6 +203,16 @@ */ #define RADIOLIB_ERR_LORA_HEADER_DAMAGED (-24) +/*! + \brief The requested functionality is not supported for this device +*/ +#define RADIOLIB_ERR_UNSUPPORTED (-25) + +/*! + \brief The specified DIO pin does not exist on this device +*/ +#define RADIOLIB_ERR_INVALID_DIO_PIN (-26) + // RF69-specific status codes /*! diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 8b514a9c14..98c8778c41 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -246,3 +246,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { } } } + +int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { + return(RADIOLIB_ERR_UNSUPPORTED); +} diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index c1d236d81d..e67dd1e8e9 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -300,6 +300,17 @@ class PhysicalLayer { */ uint8_t read(); + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + + \param pin Pin number onto which a signal is to be placed. + + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + + \returns \ref status_codes + */ + virtual int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + protected: void updateDirectBuffer(uint8_t bit); From e1412108c108f5c7650ae89b55a61c7223071368 Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 6 Jul 2022 15:29:07 +0200 Subject: [PATCH 0188/1848] Implement setDIOMapping for CC1101 --- src/modules/CC1101/CC1101.cpp | 7 +++++++ src/modules/CC1101/CC1101.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index d55d222d0f..e0407ebab9 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -885,6 +885,13 @@ void CC1101::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +int16_t CC1101::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { + if (pin > 2) + return RADIOLIB_ERR_INVALID_DIO_PIN; + + return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0 - pin, value)); +} + int16_t CC1101::config() { // Reset the radio. Registers may be dirty from previous usage. SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index ae440b4c8c..e88d48e3a8 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -932,6 +932,17 @@ class CC1101: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + + \param pin Pin number onto which a signal is to be placed. + + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + + \returns \ref status_codes + */ + int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif From 069428a9f6ac94647b3e334fd3522ccbe56f45eb Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 6 Jul 2022 15:29:27 +0200 Subject: [PATCH 0189/1848] Implement setDIOMapping for SX1278 family --- src/modules/SX127x/SX1278.cpp | 14 ++++++ src/modules/SX127x/SX1278.h | 81 +++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 685fe175a7..94518c8e2a 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -471,6 +471,20 @@ int16_t SX1278::explicitHeader() { return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE)); } +int16_t SX1278::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { + if (pin > 5) + return RADIOLIB_ERR_INVALID_DIO_PIN; + + if (pin < 4) + return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + else + return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); +} + +int16_t SX1278::setDIOPreambleDetect(bool usePreambleDetect) { + return _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX1278_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX1278_DIO_MAP_RSSI, 0, 0); +} + int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index cffedc81fd..8ebbfe0aee 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -10,6 +10,8 @@ // SX1278 specific register map #define RADIOLIB_SX1278_REG_MODEM_CONFIG_3 0x26 +#define RADIOLIB_SX1278_REG_DIO_MAPPING_1 0x40 +#define RADIOLIB_SX1278_REG_DIO_MAPPING_2 0x41 #define RADIOLIB_SX1278_REG_PLL_HOP 0x44 #define RADIOLIB_SX1278_REG_TCXO 0x4B #define RADIOLIB_SX1278_REG_PA_DAC 0x4D @@ -95,6 +97,65 @@ #define RADIOLIB_SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold #define RADIOLIB_SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold +// SX1278_REG_DIO_MAPPING_1 +#define RADIOLIB_SX1278_DIO0_LORA_RX_DONE 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_LORA_TX_DONE 0b01000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_LORA_CAD_DONE 0b10000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_CONT_RSSI_PREAMBLE_DETECT 0b01000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_CONT_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_CONT_TX_READY 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_PACK_CRC_OK 0b01000000 // 7 6 +#define RADIOLIB_SX1278_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 +#define RADIOLIB_SX1278_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 +#define RADIOLIB_SX1278_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b01000000 // 5 4 +#define RADIOLIB_SX1278_DIO1_LORA_CAD_DETECTED 0b10000000 // 5 4 +#define RADIOLIB_SX1278_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX1278_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 +#define RADIOLIB_SX1278_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX1278_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 +#define RADIOLIB_SX1278_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 +#define RADIOLIB_SX1278_DIO2_LORA_FHSS_CHANGE_CHANNEL 0b00000000 // 3 2 +#define RADIOLIB_SX1278_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX1278_DIO2_PACK_FIFO_FULL 0b00000000 // 3 2 +#define RADIOLIB_SX1278_DIO2_PACK_RX_READY 0b00000100 // 3 2 +#define RADIOLIB_SX1278_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 +#define RADIOLIB_SX1278_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 +#define RADIOLIB_SX1278_DIO3_LORA_CAD_DONE 0b00000000 // 0 1 +#define RADIOLIB_SX1278_DIO3_LORA_VALID_HEADER 0b00000001 // 0 1 +#define RADIOLIB_SX1278_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 0 1 +#define RADIOLIB_SX1278_DIO3_CONT_TIMEOUT 0b00000000 // 0 1 +#define RADIOLIB_SX1278_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 0 1 +#define RADIOLIB_SX1278_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 0 1 +#define RADIOLIB_SX1278_DIO3_PACK_FIFO_EMPTY 0b00000000 // 0 1 +#define RADIOLIB_SX1278_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// SX1278_REG_DIO_MAPPING_2 +#define RADIOLIB_SX1278_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_LORA_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_CONT_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_CONT_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_CONT_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_PACK_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_PACK_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_PACK_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX1278_DIO4_PACK_RSSI_PREAMBLE_DETECT 0b11000000 // 7 6 +#define RADIOLIB_SX1278_DIO5_LORA_MODE_READY 0b00000000 // 5 4 +#define RADIOLIB_SX1278_DIO5_LORA_CLK_OUT 0b00010000 // 5 4 +#define RADIOLIB_SX1278_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1278_DIO5_CONT_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX1278_DIO5_CONT_RSSI_PREAMBLE_DETECT 0b00100000 // 5 4 +#define RADIOLIB_SX1278_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1278_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1278_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX1278_DIO5_PACK_DATA 0b00100000 // 5 4 +#define RADIOLIB_SX1278_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1278_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 +#define RADIOLIB_SX1278_DIO_MAP_RSSI 0b00000000 // 0 0 /*! \class SX1278 @@ -302,6 +363,26 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + + \param pin Pin number onto which a signal is to be placed. + + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + + \returns \ref status_codes + */ + int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + + /*! + \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. + + \param usePreambleDetect Whether to use PreambleDetect (true) or RSSI (false) on the pins that are mapped to this function. + + \returns \ref status_codes + */ + int16_t setDIOPreambleDetect(bool usePreambleDetect); + #if !defined(RADIOLIB_GODMODE) protected: #endif From bdb14b9e9d999855b1870a339129cd85f4ad4e68 Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 6 Jul 2022 15:29:40 +0200 Subject: [PATCH 0190/1848] Implement setDIOMapping for RF69 family --- src/modules/RF69/RF69.cpp | 10 ++++++++++ src/modules/RF69/RF69.h | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 5a3881520f..f21cb0b559 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -806,6 +806,16 @@ void RF69::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +int16_t RF69::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { + if (pin > 5) + return RADIOLIB_ERR_INVALID_DIO_PIN; + + if (pin < 4) + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + else + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); +} + int16_t RF69::getChipVersion() { return(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_VERSION)); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 7e13deb613..e3ade50e9c 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -295,8 +295,38 @@ #define RADIOLIB_RF69_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 #define RADIOLIB_RF69_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 #define RADIOLIB_RF69_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_DATA 0b00000100 // 3 2 +#define RADIOLIB_RF69_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_RSSI 0b00000000 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_RX_READY 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_RSSI 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_TX_READY 0b00000001 // 0 1 // RF69_REG_DIO_MAPPING_2 +#define RADIOLIB_RF69_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_RX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_RSSI 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_MODE_READY 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO5_CONT_RSSI 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_DATA 0b00010000 // 5 4 #define RADIOLIB_RF69_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) #define RADIOLIB_RF69_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 #define RADIOLIB_RF69_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 @@ -919,6 +949,17 @@ class RF69: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + + \param pin Pin number onto which a signal is to be placed. + + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + + \returns \ref status_codes + */ + int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif From f9ab9d80d503169ffb1e50d5cecd4ecc69421303 Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 6 Jul 2022 15:30:08 +0200 Subject: [PATCH 0191/1848] SX1231 has slightly different DIO mapping tables from the RF69 ones --- src/modules/SX1231/SX1231.h | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX1231/SX1231.h index e989fa20aa..21a14c686f 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX1231/SX1231.h @@ -18,6 +18,74 @@ //SX1231_REG_TEST_OOK #define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C +// SX1231_REG_DIO_MAPPING_1 +#define RADIOLIB_SX1231_DIO0_CONT_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_RSSI 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_CRC_OK 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_RSSI 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO1_CONT_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_RX_READY 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_TX_READY 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_LOW_BAT 0b00001000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_DATA 0b00000100 // 3 2 +#define RADIOLIB_SX1231_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_RSSI 0b00000000 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_RX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_LOW_BAT 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_RSSI 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// SX1231_REG_DIO_MAPPING_2 +#define RADIOLIB_SX1231_DIO4_CONT_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_RX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_RSSI 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_MODE_READY 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO5_CONT_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_RSSI 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_DATA 0b00010000 // 5 4 + /*! \class SX1231 From 9836e57616ada4a1d371917262aade4deca6701c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Jul 2022 17:43:51 +0200 Subject: [PATCH 0192/1848] [Stream] Added Stream mode support for SX127x (#201) (#403) --- .../Stream/Stream_Receive/Stream_Receive.ino | 142 ++++++++++++++++ .../Stream_Transmit/Stream_Transmit.ino | 154 ++++++++++++++++++ keywords.txt | 5 +- src/modules/SX127x/SX127x.cpp | 109 ++++++++++++- src/modules/SX127x/SX127x.h | 47 +++++- 5 files changed, 441 insertions(+), 16 deletions(-) create mode 100644 examples/Stream/Stream_Receive/Stream_Receive.ino create mode 100644 examples/Stream/Stream_Transmit/Stream_Transmit.ino diff --git a/examples/Stream/Stream_Receive/Stream_Receive.ino b/examples/Stream/Stream_Receive/Stream_Receive.ino new file mode 100644 index 0000000000..73904bb0ad --- /dev/null +++ b/examples/Stream/Stream_Receive/Stream_Receive.ino @@ -0,0 +1,142 @@ +/* + RadioLib Stream Receive Example + + This example shows how to receive data in "Stream" mode. + In this mode, arbitrary length of data may be sent, up to + "infinite" continuous transmission between two devices. + + Caveats: + - CRC of the payload is not supported + - the length of the payload must be known in advance + + Modules that can be used for Stream are: + - SX127x/RFM9x (FSK mode only) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Stream transmit + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when receive buffer is full + radio.setFifoFullAction(fifoGet); + + // fixed packet length mode is required + radio.fixedPacketLengthMode(0); + + // start listening for packets + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// how many bytes are there in total +const int totalLength = 512; + +// counter to keep track of how many bytes have been received so far +volatile int receivedLength = 0; + +// buffer to save the received data into +volatile uint8_t rxBuffer[totalLength + 1]; + +// this function is called when the radio receive buffer +// is full and ready to be read +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void fifoGet(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // set the flag when we receive the full packet + receivedFlag = radio.fifoGet(rxBuffer, totalLength, &receivedLength); +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println((char*)rxBuffer); + + // reset flag + receivedFlag = false; + receivedLength = 0; + + // put module back to listen mode + radio.startReceive(); + + // we're ready to receive more packets, + // enable interrupt service routine + enableInterrupt = true; + } + +} diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino new file mode 100644 index 0000000000..8be539f700 --- /dev/null +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -0,0 +1,154 @@ +/* + RadioLib Stream Transmit Example + + This example shows how to transmit data in "Stream" mode. + In this mode, arbitrary length of data may be sent, up to + "infinite" continuous transmission between two devices. + + Caveats: + - CRC of the payload is not supported + - the length of the payload must be known in advance + + Modules that can be used for Stream are: + - SX127x/RFM9x (FSK mode only) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// this packet is much longer than would normally fit +// into SX1278's internal buffer +String longPacket = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\ + Maecenas at urna ut nunc imperdiet laoreet. Aliquam erat volutpat.\ + Etiam mattis mauris vitae posuere tincidunt. In sit amet bibendum nisl,\ + a ultrices lorem. Duis hendrerit ultricies condimentum. Phasellus eget nisi\ + eget massa aliquam bibendum. Pellentesque ante neque, aliquam non diam non,\ + fringilla facilisis ipsum. Morbi in molestie orci. Vestibulum luctus\ + venenatis arcu sit amet pellentesque. Nulla posuere sit amet turpis\ + id pharetra. Curabitur nec."; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Stream transmit + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when transmit buffer is empty + radio.setFifoEmptyAction(fifoAdd); + + // fixed packet length mode is required + radio.fixedPacketLengthMode(0); + + // start transmitting the long packet + Serial.print(F("[SX1278] Sending a very long packet ... ")); + transmissionState = radio.startTransmit(longPacket); +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// how many bytes are there in total +volatile int totalLength = longPacket.length(); + +// counter to keep track of how many bytes still need to be sent +volatile int remLength = totalLength; + +// this function is called when the radio transmit buffer +// is empty and ready to be refilled +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void fifoAdd(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // add more bytes to the transmit buffer + uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str(); + transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength); +} + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + transmittedFlag = false; + + // reset the counter + remLength = totalLength; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // NOTE: in FSK mode, SX127x will not automatically + // turn transmitter off after sending a packet + // set mode to standby to ensure we don't jam others + radio.standby(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1278] Sending another long packet ... ")); + transmissionState = radio.startTransmit(longPacket); + + // we're ready to send more packets, + // enable interrupt service routine + enableInterrupt = true; + } +} diff --git a/keywords.txt b/keywords.txt index 236c8039af..30d7eb7e72 100644 --- a/keywords.txt +++ b/keywords.txt @@ -148,7 +148,10 @@ getFHSSChannel KEYWORD2 clearFHSSInt KEYWORD2 randomByte KEYWORD2 getPacketLength KEYWORD2 - +setFifoEmptyAction KEYWORD2 +clearFifoEmptyAction KEYWORD2 +fifoAdd KEYWORD2 +fifoGet KEYWORD2 # RF69-specific setAESKey KEYWORD2 diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 5c038033dc..22013554b4 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -429,6 +429,87 @@ void SX127x::clearDio1Action() { _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } +void SX127x::setFifoEmptyAction(void (*func)(void)) { + // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) + setDio1Action(func); +} + +void SX127x::clearFifoEmptyAction() { + clearDio1Action(); +} + +void SX127x::setFifoFullAction(void (*func)(void)) { + // set the interrupt + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4); + + // set DIO1 to the FIFO full event + setDio1Action(func); +} + +void SX127x::clearFifoFullAction() { + clearDio1Action(); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4); +} + +bool SX127x::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { + // subtract first (this may be the first time we get to modify the remaining length) + *remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1; + + // check if there is still something left to send + if(*remLen <= 0) { + // we're done + return(true); + } + + // calculate the number of bytes we can copy + int len = *remLen; + if(len > RADIOLIB_SX127X_FIFO_THRESH - 1) { + len = RADIOLIB_SX127X_FIFO_THRESH - 1; + } + + // clear interrupt flags + clearIRQFlags(); + + // copy the bytes to the FIFO + _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len); + + // this is a hack, but it seems Rx FIFO level is getting triggered 1 byte before it should + // we just add a padding byte that we can drop without consequence + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, '/'); + + // we're not done yet + return(false); +} + +bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { + // get pointer to the correct position in data buffer + uint8_t* dataPtr = &data[*rcvLen]; + + // check how much data are we still expecting + uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1; + if(totalLen - *rcvLen < len) { + // we're nearly at the end + len = totalLen - *rcvLen; + } + + // get the data + _mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr); + (*rcvLen) += (len); + + // dump the padding byte + _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + + // clear flags + clearIRQFlags(); + + // check if we're done + if(*rcvLen >= totalLen) { + return(true); + } + return(false); +} + int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); @@ -461,17 +542,16 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // check packet length - if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // set DIO mapping - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); - // clear interrupt flags clearIRQFlags(); + // set DIO mapping + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4); + } else { + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + } + // set packet length if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); @@ -485,7 +565,18 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // write packet to FIFO - _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, len); + size_t packetLen = len; + if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { + packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1; + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + } + _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); + + // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should + // just add a padding byte that can be dropped without consequence + if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, '/'); + } // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 15ba7154d4..bad363d3d3 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -12,7 +12,7 @@ // SX127x physical layer properties #define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 #define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 63 #define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 #define RADIOLIB_SX127X_DIV_EXPONENT 19 @@ -411,7 +411,7 @@ // SX127X_REG_FIFO_THRESH #define RADIOLIB_SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD #define RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) -#define RADIOLIB_SX127X_FIFO_THRESH 0x0F // 5 0 FIFO level threshold +#define RADIOLIB_SX127X_FIFO_THRESH 0x1F // 5 0 FIFO level threshold // SX127X_REG_SEQ_CONFIG_1 #define RADIOLIB_SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer @@ -701,6 +701,41 @@ class SX127x: public PhysicalLayer { */ void clearDio1Action(); + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + + \param func Pointer to interrupt service routine. + */ + void setFifoEmptyAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is empty. + */ + void clearFifoEmptyAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is full. + + \param func Pointer to interrupt service routine. + */ + void setFifoFullAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is full. + */ + void clearFifoFullAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + + \param func Pointer to interrupt service routine. + + \returns True when a complete packet is sent, false if more data is needed. + */ + bool fifoAdd(uint8_t* data, int totalLen, volatile int* remLen); + + bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); + /*! \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -933,12 +968,12 @@ class SX127x: public PhysicalLayer { /*! \brief Size of each decrement of the RSSI threshold in the OOK demodulator. - \param value Step size: RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB (default), RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB + \param value Step size: RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB (default), RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB \returns \ref status_codes */ - int16_t setOokPeakThresholdStep(uint8_t value); - + int16_t setOokPeakThresholdStep(uint8_t value); + /*! \brief Enable Bit synchronizer. @@ -988,7 +1023,7 @@ class SX127x: public PhysicalLayer { \returns Expected time-on-air in microseconds. */ uint32_t getTimeOnAir(size_t len); - + /*! \brief Enable CRC filtering and generation. From ce268925671b00dc4651478674cefb158135d7c0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Jul 2022 19:48:56 +0200 Subject: [PATCH 0193/1848] [SX127x] Fixed FSK maximum packet length --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index bad363d3d3..07a6e6540f 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -12,7 +12,7 @@ // SX127x physical layer properties #define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 #define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 63 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 #define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 #define RADIOLIB_SX127X_DIV_EXPONENT 19 From d8c11fa8c993fd2463d2f5f6d92352a7ce0cbe36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Jul 2022 19:54:57 +0200 Subject: [PATCH 0194/1848] [SX127x] Added missing Doxygen comments --- src/modules/SX127x/SX127x.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 07a6e6540f..d77d321f80 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -728,12 +728,27 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is empty. - \param func Pointer to interrupt service routine. + \param data Pointer to the transmission buffer. + + \param totalLen Total number of bytes to transmit. + + \param remLen Pointer to a counter holding the number of bytes that have been transmitted so far. \returns True when a complete packet is sent, false if more data is needed. */ bool fifoAdd(uint8_t* data, int totalLen, volatile int* remLen); + /*! + \brief Set interrupt service routine function to call when FIFO is sufficently full to read. + + \param data Pointer to a buffer that stores the receive data. + + \param totalLen Total number of bytes to receive. + + \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. + + \returns True when a complete packet is received, false if more data is needed. + */ bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); /*! From 31da00649cf3b32466fd033ef2c40c3e7f732006 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Jul 2022 20:35:49 +0200 Subject: [PATCH 0195/1848] [SX127x] Added missing cast --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 22013554b4..7426bf9d27 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -484,7 +484,7 @@ bool SX127x::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { // get pointer to the correct position in data buffer - uint8_t* dataPtr = &data[*rcvLen]; + uint8_t* dataPtr = (uint8_t*)&data[*rcvLen]; // check how much data are we still expecting uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1; From 60aa0098b364c951f53744b3a94808fc28644991 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Jul 2022 20:41:11 +0200 Subject: [PATCH 0196/1848] [RF69][SX1231] Added Stream support (#201) --- .../Stream/Stream_Receive/Stream_Receive.ino | 2 + .../Stream_Transmit/Stream_Transmit.ino | 2 + src/modules/RF69/RF69.cpp | 117 ++++++++++++++++-- src/modules/RF69/RF69.h | 52 +++++++- 4 files changed, 162 insertions(+), 11 deletions(-) diff --git a/examples/Stream/Stream_Receive/Stream_Receive.ino b/examples/Stream/Stream_Receive/Stream_Receive.ino index 73904bb0ad..2dc723ed62 100644 --- a/examples/Stream/Stream_Receive/Stream_Receive.ino +++ b/examples/Stream/Stream_Receive/Stream_Receive.ino @@ -11,6 +11,8 @@ Modules that can be used for Stream are: - SX127x/RFM9x (FSK mode only) + - RF69 + - SX1231 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index 8be539f700..26eb7f3aeb 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -11,6 +11,8 @@ Modules that can be used for Stream are: - SX127x/RFM9x (FSK mode only) + - RF69 + - SX1231 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 5a3881520f..0d513d1d0b 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -297,23 +297,109 @@ void RF69::clearDio1Action() { _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } -int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { - // check packet length - if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); +void RF69::setFifoEmptyAction(void (*func)(void)) { + // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) + if(_mod->getGpio() == RADIOLIB_NC) { + return; + } + _mod->pinMode(_mod->getGpio(), INPUT); + + // we need to invert the logic here (as compared to setDio1Action), since we are using the "FIFO not empty interrupt" + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, FALLING); +} + +void RF69::clearFifoEmptyAction() { + clearDio1Action(); +} + +void RF69::setFifoFullAction(void (*func)(void)) { + // set the interrupt + _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_FIFO_THRESH, 6, 0); + _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL, 5, 4); + + // set DIO1 to the FIFO full event + setDio1Action(func); +} + +void RF69::clearFifoFullAction() { + clearDio1Action(); + _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, 0x00, 5, 4); +} + +bool RF69::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { + // subtract first (this may be the first time we get to modify the remaining length) + *remLen -= RADIOLIB_RF69_FIFO_THRESH - 1; + + // check if there is still something left to send + if(*remLen <= 0) { + // we're done + return(true); + } + + // calculate the number of bytes we can copy + int len = *remLen; + if(len > RADIOLIB_RF69_FIFO_THRESH - 1) { + len = RADIOLIB_RF69_FIFO_THRESH - 1; + } + + // clear interrupt flags + clearIRQFlags(); + + // copy the bytes to the FIFO + _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, &data[totalLen - *remLen], len); + + // this is a hack, but it seems Rx FIFO level is getting triggered 1 byte before it should + // we just add a padding byte that we can drop without consequence + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); + + // we're not done yet + return(false); +} + +bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { + // get pointer to the correct position in data buffer + uint8_t* dataPtr = (uint8_t*)&data[*rcvLen]; + + // check how much data are we still expecting + uint8_t len = RADIOLIB_RF69_FIFO_THRESH - 1; + if(totalLen - *rcvLen < len) { + // we're nearly at the end + len = totalLen - *rcvLen; } + // get the data + _mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, len, dataPtr); + (*rcvLen) += (len); + + // dump the padding byte + _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + + // clear flags + clearIRQFlags(); + + // check if we're done + if(*rcvLen >= totalLen) { + return(true); + } + return(false); +} + +int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = setMode(RADIOLIB_RF69_STANDBY); RADIOLIB_ASSERT(state); - // set DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PACKET_SENT, 7, 6); - RADIOLIB_ASSERT(state); - // clear interrupt flags clearIRQFlags(); + // set DIO mapping + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY, 5, 4); + } else { + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PACKET_SENT, 7, 6); + } + RADIOLIB_ASSERT(state); + // optionally write packet length if (_packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, len); @@ -326,7 +412,18 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // write packet to FIFO - _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, len); + size_t packetLen = len; + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + packetLen = RADIOLIB_RF69_FIFO_THRESH - 1; + _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY, 7, 7); + } + _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, packetLen); + + // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should + // just add a padding byte that can be dropped without consequence + if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { + _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); + } // enable +20 dBm operation if(_power > 17) { @@ -852,7 +949,7 @@ int16_t RF69::config() { RADIOLIB_ASSERT(state); // set FIFO threshold - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RADIOLIB_RF69_FIFO_THRESHOLD, 7, 0); + state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RADIOLIB_RF69_FIFO_THRESH, 7, 0); RADIOLIB_ASSERT(state); // set Rx timeouts diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 7e13deb613..3c6d63c8b8 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -400,7 +400,7 @@ // RF69_REG_FIFO_THRESH #define RADIOLIB_RF69_TX_START_CONDITION_FIFO_LEVEL 0b00000000 // 7 7 packet transmission start condition: FifoLevel #define RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY 0b10000000 // 7 7 FifoNotEmpty (default) -#define RADIOLIB_RF69_FIFO_THRESHOLD 0b00001111 // 6 0 default threshold to trigger FifoLevel interrupt +#define RADIOLIB_RF69_FIFO_THRESH 0x1F // 6 0 default threshold to trigger FifoLevel interrupt // RF69_REG_PACKET_CONFIG_2 #define RADIOLIB_RF69_INTER_PACKET_RX_DELAY 0b00000000 // 7 4 delay between FIFO empty and start of new RSSI phase @@ -590,6 +590,56 @@ class RF69: public PhysicalLayer { */ void clearDio1Action(); + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + + \param func Pointer to interrupt service routine. + */ + void setFifoEmptyAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is empty. + */ + void clearFifoEmptyAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is full. + + \param func Pointer to interrupt service routine. + */ + void setFifoFullAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when FIFO is full. + */ + void clearFifoFullAction(); + + /*! + \brief Set interrupt service routine function to call when FIFO is empty. + + \param data Pointer to the transmission buffer. + + \param totalLen Total number of bytes to transmit. + + \param remLen Pointer to a counter holding the number of bytes that have been transmitted so far. + + \returns True when a complete packet is sent, false if more data is needed. + */ + bool fifoAdd(uint8_t* data, int totalLen, volatile int* remLen); + + /*! + \brief Set interrupt service routine function to call when FIFO is sufficently full to read. + + \param data Pointer to a buffer that stores the receive data. + + \param totalLen Total number of bytes to receive. + + \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. + + \returns True when a complete packet is received, false if more data is needed. + */ + bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); + /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. From 0b2238a0a45eea03e97072bb2fae0016eadcbe94 Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 13 Jul 2022 10:05:45 +0200 Subject: [PATCH 0197/1848] The SX127x family of chips shares the same DIO pin functions, so move all the support code in the base SX127x class --- src/modules/SX127x/SX1278.cpp | 14 ------ src/modules/SX127x/SX1278.h | 81 ----------------------------------- src/modules/SX127x/SX127x.cpp | 24 ++++++++--- src/modules/SX127x/SX127x.h | 78 ++++++++++++++++++++++++++++----- 4 files changed, 86 insertions(+), 111 deletions(-) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 94518c8e2a..685fe175a7 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -471,20 +471,6 @@ int16_t SX1278::explicitHeader() { return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE)); } -int16_t SX1278::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { - if (pin > 5) - return RADIOLIB_ERR_INVALID_DIO_PIN; - - if (pin < 4) - return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); - else - return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); -} - -int16_t SX1278::setDIOPreambleDetect(bool usePreambleDetect) { - return _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX1278_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX1278_DIO_MAP_RSSI, 0, 0); -} - int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 8ebbfe0aee..cffedc81fd 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -10,8 +10,6 @@ // SX1278 specific register map #define RADIOLIB_SX1278_REG_MODEM_CONFIG_3 0x26 -#define RADIOLIB_SX1278_REG_DIO_MAPPING_1 0x40 -#define RADIOLIB_SX1278_REG_DIO_MAPPING_2 0x41 #define RADIOLIB_SX1278_REG_PLL_HOP 0x44 #define RADIOLIB_SX1278_REG_TCXO 0x4B #define RADIOLIB_SX1278_REG_PA_DAC 0x4D @@ -97,65 +95,6 @@ #define RADIOLIB_SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold #define RADIOLIB_SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold -// SX1278_REG_DIO_MAPPING_1 -#define RADIOLIB_SX1278_DIO0_LORA_RX_DONE 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_LORA_TX_DONE 0b01000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_LORA_CAD_DONE 0b10000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_CONT_RSSI_PREAMBLE_DETECT 0b01000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_CONT_RX_READY 0b10000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_CONT_TX_READY 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_PACK_CRC_OK 0b01000000 // 7 6 -#define RADIOLIB_SX1278_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 -#define RADIOLIB_SX1278_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 -#define RADIOLIB_SX1278_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b01000000 // 5 4 -#define RADIOLIB_SX1278_DIO1_LORA_CAD_DETECTED 0b10000000 // 5 4 -#define RADIOLIB_SX1278_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define RADIOLIB_SX1278_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 -#define RADIOLIB_SX1278_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 -#define RADIOLIB_SX1278_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 -#define RADIOLIB_SX1278_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 -#define RADIOLIB_SX1278_DIO2_LORA_FHSS_CHANGE_CHANNEL 0b00000000 // 3 2 -#define RADIOLIB_SX1278_DIO2_CONT_DATA 0b00000000 // 3 2 -#define RADIOLIB_SX1278_DIO2_PACK_FIFO_FULL 0b00000000 // 3 2 -#define RADIOLIB_SX1278_DIO2_PACK_RX_READY 0b00000100 // 3 2 -#define RADIOLIB_SX1278_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 -#define RADIOLIB_SX1278_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 -#define RADIOLIB_SX1278_DIO3_LORA_CAD_DONE 0b00000000 // 0 1 -#define RADIOLIB_SX1278_DIO3_LORA_VALID_HEADER 0b00000001 // 0 1 -#define RADIOLIB_SX1278_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 0 1 -#define RADIOLIB_SX1278_DIO3_CONT_TIMEOUT 0b00000000 // 0 1 -#define RADIOLIB_SX1278_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 0 1 -#define RADIOLIB_SX1278_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 0 1 -#define RADIOLIB_SX1278_DIO3_PACK_FIFO_EMPTY 0b00000000 // 0 1 -#define RADIOLIB_SX1278_DIO3_PACK_TX_READY 0b00000001 // 0 1 - -// SX1278_REG_DIO_MAPPING_2 -#define RADIOLIB_SX1278_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_LORA_PLL_LOCK 0b01000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_CONT_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_CONT_PLL_LOCK 0b01000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_CONT_TIMEOUT 0b10000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_PACK_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_PACK_PLL_LOCK 0b01000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_PACK_TIMEOUT 0b10000000 // 7 6 -#define RADIOLIB_SX1278_DIO4_PACK_RSSI_PREAMBLE_DETECT 0b11000000 // 7 6 -#define RADIOLIB_SX1278_DIO5_LORA_MODE_READY 0b00000000 // 5 4 -#define RADIOLIB_SX1278_DIO5_LORA_CLK_OUT 0b00010000 // 5 4 -#define RADIOLIB_SX1278_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_SX1278_DIO5_CONT_PLL_LOCK 0b00010000 // 5 4 -#define RADIOLIB_SX1278_DIO5_CONT_RSSI_PREAMBLE_DETECT 0b00100000 // 5 4 -#define RADIOLIB_SX1278_DIO5_CONT_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX1278_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_SX1278_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 -#define RADIOLIB_SX1278_DIO5_PACK_DATA 0b00100000 // 5 4 -#define RADIOLIB_SX1278_DIO5_PACK_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX1278_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 -#define RADIOLIB_SX1278_DIO_MAP_RSSI 0b00000000 // 0 0 /*! \class SX1278 @@ -363,26 +302,6 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); - /*! - \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). - - \param pin Pin number onto which a signal is to be placed. - - \param value The value that indicates which function to place on that pin. See chip datasheet for details. - - \returns \ref status_codes - */ - int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); - - /*! - \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. - - \param usePreambleDetect Whether to use PreambleDetect (true) or RSSI (false) on the pins that are mapped to this function. - - \returns \ref status_codes - */ - int16_t setDIOPreambleDetect(bool usePreambleDetect); - #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 5c038033dc..427a6e0653 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -362,10 +362,10 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 7, 4); } // set expected packet length for SF6 @@ -442,9 +442,9 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set DIO mapping if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); } else { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6); } // apply fixes to errata @@ -564,7 +564,7 @@ int16_t SX127x::startChannelScan() { RADIOLIB_ASSERT(state); // set DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_CAD_DONE | RADIOLIB_SX127X_DIO1_CAD_DETECTED, 7, 4); + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -1431,4 +1431,18 @@ void SX127x::clearFHSSInt(void) { } } +int16_t SX127x::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { + if (pin > 5) + return RADIOLIB_ERR_INVALID_DIO_PIN; + + if (pin < 4) + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + else + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); +} + +int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) { + return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0); +} + #endif diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 15ba7154d4..656feae2cc 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -141,14 +141,6 @@ #define RADIOLIB_SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled #define RADIOLIB_SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0 -// SX127X_REG_DIO_MAPPING_1 -#define RADIOLIB_SX127X_DIO0_RX_DONE 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_TX_DONE 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CAD_DONE 0b10000000 // 7 6 -#define RADIOLIB_SX127X_DIO1_RX_TIMEOUT 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO1_CAD_DETECTED 0b00100000 // 5 4 - // SX127X_REG_IRQ_FLAGS #define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout #define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete @@ -509,20 +501,64 @@ #define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold // SX127X_REG_DIO_MAPPING_1 +#define RADIOLIB_SX127X_DIO0_LORA_RX_DONE 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_LORA_TX_DONE 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_LORA_CAD_DONE 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_MODE_READY 0b11000000 // 7 6 #define RADIOLIB_SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_RSSI_RADIOLIB_PREAMBLE_DETECTED 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RSSI_PREAMBLE_DETECT 0b01000000 // 7 6 #define RADIOLIB_SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 #define RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 #define RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 #define RADIOLIB_SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 #define RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b01000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED 0b10000000 // 5 4 #define RADIOLIB_SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_CONT_RSSI_RADIOLIB_PREAMBLE_DETECTED 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 #define RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 #define RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 #define RADIOLIB_SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO2_LORA_FHSS_CHANGE_CHANNEL 0b00000000 // 3 2 #define RADIOLIB_SX127X_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_FIFO_FULL 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_RX_READY 0b00000100 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 +#define RADIOLIB_SX127X_DIO3_LORA_CAD_DONE 0b00000000 // 0 1 +#define RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER 0b00000001 // 0 1 +#define RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 0 1 +#define RADIOLIB_SX127X_DIO3_CONT_TIMEOUT 0b00000000 // 0 1 +#define RADIOLIB_SX127X_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 0 1 +#define RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 0 1 +#define RADIOLIB_SX127X_DIO3_PACK_FIFO_EMPTY 0b00000000 // 0 1 +#define RADIOLIB_SX127X_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// SX127X_REG_DIO_MAPPING_2 +#define RADIOLIB_SX127X_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_LORA_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO5_LORA_MODE_READY 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_LORA_CLK_OUT 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_RSSI_PREAMBLE_DETECT 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_DATA 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 +#define RADIOLIB_SX127X_DIO_MAP_RSSI 0b00000000 // 0 0 // SX1272_REG_PLL_HOP + SX1278_REG_PLL_HOP #define RADIOLIB_SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written @@ -1119,6 +1155,26 @@ class SX127x: public PhysicalLayer { */ void clearFHSSInt(void); + /*! + \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). + + \param pin Pin number onto which a signal is to be placed. + + \param value The value that indicates which function to place on that pin. See chip datasheet for details. + + \returns \ref status_codes + */ + int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + + /*! + \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. + + \param usePreambleDetect Whether to use PreambleDetect (true) or RSSI (false) on the pins that are mapped to this function. + + \returns \ref status_codes + */ + int16_t setDIOPreambleDetect(bool usePreambleDetect); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif From a74c0536b8c0e9640ba8fe80c2a26a1d0d721b06 Mon Sep 17 00:00:00 2001 From: Northern Man Date: Sat, 16 Jul 2022 21:50:33 -0400 Subject: [PATCH 0198/1848] Tweaks for async direct mode usage with rtl_433_ESP --- src/modules/CC1101/CC1101.cpp | 22 ++++++++++++++++++---- src/modules/CC1101/CC1101.h | 7 +++++-- src/modules/SX127x/SX1278.cpp | 2 +- src/modules/SX127x/SX127x.cpp | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index d55d222d0f..75c59d963e 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -711,12 +711,25 @@ int16_t CC1101::setOOK(bool enableOOK) { return(setOutputPower(_power)); } -float CC1101::getRSSI() const { +float CC1101::getRSSI() { float rssi; - if(_rawRSSI >= 128) { - rssi = (((float)_rawRSSI - 256.0)/2.0) - 74.0; + + if (_directMode) { + if(_rawRSSI >= 128) { + rssi = (((float)_rawRSSI - 256.0)/2.0) - 74.0; + } else { + rssi = (((float)_rawRSSI)/2.0) - 74.0; + } } else { - rssi = (((float)_rawRSSI)/2.0) - 74.0; + uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI); + if (rawRssi >= 128) + { + rssi = ((rawRssi - 256) / 2) - 74; + } + else + { + rssi = (rawRssi / 2) - 74; + } } return(rssi); } @@ -907,6 +920,7 @@ int16_t CC1101::directMode(bool sync) { SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); int16_t state = 0; + _directMode = sync; if (sync) { // set GDO0 and GDO2 mapping state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index ae440b4c8c..58893005b8 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -791,9 +791,11 @@ class CC1101: public PhysicalLayer { /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. - \returns Last packet RSSI in dBm. + or in asynchronous direct mode the current RSSI level + + \returns RSSI in dBm. */ - float getRSSI() const; + float getRSSI(); /*! \brief Gets LQI (Link Quality Indicator) of the last received packet. @@ -963,6 +965,7 @@ class CC1101: public PhysicalLayer { bool _promiscuous = false; bool _crcOn = true; + bool _directMode = true; uint8_t _syncWordLength = 2; int8_t _power = 0; diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 685fe175a7..7d6d57aaec 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -297,7 +297,7 @@ int16_t SX1278::setGain(uint8_t gain) { // gain set to 0, enable AGC loop state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 20125c57c5..9b479d066e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -746,7 +746,7 @@ int16_t SX127x::setBitRate(float br) { // check allowed bit rate if(_ook) { - RADIOLIB_CHECK_RANGE(br, 1.2, 32.768, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 1.2, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 } else { RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); } From ae7065da7bae367ef0e0b12c758deb5c691ddfc7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 17 Jul 2022 10:14:24 +0200 Subject: [PATCH 0199/1848] Bump version to 5.3.0 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 999a3e6437..868e56d7d2 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.2.0 +version=5.3.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 6ca44f1d4c..657ed829c7 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1023,7 +1023,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x02) +#define RADIOLIB_VERSION_MINOR (0x03) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 356f1ef2fded158147c7fb0a9ce254723c561bd7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 24 Jul 2022 19:59:14 +0200 Subject: [PATCH 0200/1848] Fixed compatibility with STM32 core >2.0.0 (#549) --- .github/workflows/main.yml | 6 +++--- src/BuildOpt.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bb7d6d5290..a8bb6e6f47 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,7 @@ jobs: - esp8266:esp8266:generic - Intel:arc32:arduino_101 - SparkFun:apollo3:sfe_artemis - - STM32:stm32:GenF3 + - STMicroelectronics:stm32:GenF3 - stm32duino:STM32F1:mapleMini - MegaCoreX:megaavr:4809 - arduino:mbed_rp2040:pico @@ -116,10 +116,10 @@ jobs: echo "::set-output name=warnings::'none'" echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" - elif [[ "${{ contains(matrix.board, 'STM32:stm32') }}" == "true" ]]; then + elif [[ "${{ contains(matrix.board, 'STMicroelectronics:stm32') }}" == "true" ]]; then # STM32 (official core) echo "::set-output name=options:::pnum=BLACKPILL_F303CC" - echo "::set-output name=index-url::--additional-urls https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" + echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then # STM32 (unofficial core) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 657ed829c7..e58f93df85 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -239,7 +239,7 @@ #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin, bool destruct) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, callback_function_t callback, uint32_t mode) #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t ms) From 7735cffb6258c04c3a3d642e25321f0a33d1e8d7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 30 Jul 2022 08:51:44 +0200 Subject: [PATCH 0201/1848] [Morse] Reworked example naming --- .../Morse_Transmit_FM.ino} | 21 ++++++++++++++----- .../Morse_Transmit_SSB.ino} | 7 ++++--- 2 files changed, 20 insertions(+), 8 deletions(-) rename examples/Morse/{Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino => Morse_Transmit_FM/Morse_Transmit_FM.ino} (84%) rename examples/Morse/{Morse_Transmit/Morse_Transmit.ino => Morse_Transmit_SSB/Morse_Transmit_SSB.ino} (93%) diff --git a/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino similarity index 84% rename from examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino rename to examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino index ac5d284be8..3feb78bdca 100644 --- a/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino +++ b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -2,8 +2,8 @@ RadioLib Morse Transmit AFSK Example This example sends Morse code message using - SX1278's FSK modem. The data is modulated - as AFSK. + SX1278's FSK modem. The signal is modulated + as AFSK, and may be demodulated in FM mode. Other modules that can be used for Morse Code with AFSK modulation: @@ -28,7 +28,7 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 radio = new Module(10, 2, 9, 3); +SX1278 radio = new Module(5, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield @@ -36,7 +36,7 @@ SX1278 radio = new Module(10, 2, 9, 3); // create AFSK client instance using the FSK module // pin 5 is connected to SX1278 DIO2 -AFSKClient audio(&radio, 5); +AFSKClient audio(&radio, 10); // create Morse client instance using the AFSK instance MorseClient morse(&audio); @@ -62,7 +62,7 @@ void setup() { // initialize Morse client Serial.print(F("[Morse] Initializing ... ")); - // AFSK tone frequency: 400 MHz + // tone frequency: 400 Hz // speed: 20 words per minute state = morse.begin(400); if(state == RADIOLIB_ERR_NONE) { @@ -72,6 +72,17 @@ void setup() { Serial.println(state); while(true); } + + // after that, set mode to OOK + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } } void loop() { diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino similarity index 93% rename from examples/Morse/Morse_Transmit/Morse_Transmit.ino rename to examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino index 764fcd55ed..61abde3a51 100644 --- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino +++ b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino @@ -1,8 +1,9 @@ /* - RadioLib Morse Transmit Example + RadioLib Morse Transmit SSB Example This example sends Morse code message using - SX1278's FSK modem. + SX1278's FSK modem. The signal is an unmodulated + carrier wave, and may be demodulated in SSB mode. Other modules that can be used for Morse Code: - SX127x/RFM9x @@ -59,7 +60,7 @@ void setup() { // initialize Morse client Serial.print(F("[Morse] Initializing ... ")); - // base frequency: 434.0 MHz + // carrier wave frequency: 434.0 MHz // speed: 20 words per minute state = morse.begin(434.0); if(state == RADIOLIB_ERR_NONE) { From 8768900767bc677a5706a61ca2c382aa16bf7c0e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 30 Jul 2022 08:52:09 +0200 Subject: [PATCH 0202/1848] [Morse] Added Morse transmit AM example --- .../Morse_Transmit_AM/Morse_Transmit_AM.ino | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino diff --git a/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino b/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino new file mode 100644 index 0000000000..6bedffa673 --- /dev/null +++ b/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino @@ -0,0 +1,131 @@ +/* + RadioLib Morse Transmit AM Example + + This example sends Morse code message using + SX1278's FSK modem. The signal is modulated + as OOK, and may be demodulated in AM mode. + + Other modules that can be used for Morse Code + with AM modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // tone frequency: 400 Hz + // speed: 20 words per minute + state = morse.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after that, set mode to OOK to emulate AM modulation + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Morse] Sending Morse data ... ")); + + // MorseClient supports all methods of the Serial class + // NOTE: Characters that do not have ITU-R M.1677-1 + // representation will not be sent! Lower case + // letters will be capitalized. + + // send start signal first + morse.startSignal(); + + // Arduino String class + String aStr = "Arduino String"; + morse.print(aStr); + + // character array (C-String) + morse.print("C-String"); + + // string saved in flash + morse.print(F("Flash String")); + + // character + morse.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + morse.print(255, HEX); + + // integer number + int i = 1000; + morse.print(i); + + // floating point number + // NOTE: When using println(), the transmission will be + // terminated with end-of-work signal (...-.-). + float f = -3.1415; + morse.println(f, 3); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} From 8675f13e5db4a1d248b8a33a20a417c6c5d23dbb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 30 Jul 2022 08:53:57 +0200 Subject: [PATCH 0203/1848] [Morse] Added basic Morse receive support (#545) CI_BUILD_ALL --- .../Morse_Receive_AM/Morse_Receive_AM.ino | 112 ++++++++++++++++++ keywords.txt | 4 + src/BuildOpt.h | 23 +++- src/Module.cpp | 7 ++ src/Module.h | 6 + src/protocols/Morse/Morse.cpp | 88 +++++++++++++- src/protocols/Morse/Morse.h | 42 +++++++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 +- 8 files changed, 277 insertions(+), 7 deletions(-) create mode 100644 examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino diff --git a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino new file mode 100644 index 0000000000..62b9f7fe5c --- /dev/null +++ b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino @@ -0,0 +1,112 @@ +/* + RadioLib SX127x Morse Receive AM Example + + This example receives Morse code message using + SX1278's FSK modem. The signal is expected to be + modulated as OOK, to be demodulated in AM mode. + + Other modules that can be used for Morse Code + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // AFSK tone frequency: 400 Hz + // speed: 20 words per minute + state = morse.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after that, set mode to OOK to emulate AM modulation + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // start direct mode reception + radio.receiveDirect(); +} + +// save symbol and length between loops +byte symbol = 0; +byte len = 0; + +void loop() { + // try to read a new symbol + int state = morse.read(&symbol, &len); + + // check if we have a complete character + if(state == RADIOLIB_MORSE_CHAR_COMPLETE) { + // decode and print + Serial.print(MorseClient::decode(symbol, len)); + + // reset the symbol buffer + symbol = 0; + len = 0; + + } else if(state == RADIOLIB_MORSE_WORD_COMPLETE) { + // inter-word space, interpret that as a new line + Serial.println(); + + } +} diff --git a/keywords.txt b/keywords.txt index 30d7eb7e72..8c3a0a3399 100644 --- a/keywords.txt +++ b/keywords.txt @@ -254,6 +254,10 @@ RADIOLIB_ENCODING_WHITENING LITERAL1 RADIOLIB_BUILTIN_MODULE LITERAL1 +RADIOLIB_MORSE_INTER_SYMBOL LITERAL1 +RADIOLIB_MORSE_CHAR_COMPLETE LITERAL1 +RADIOLIB_MORSE_WORD_COMPLETE LITERAL1 + RADIOLIB_ERR_NONE LITERAL1 RADIOLIB_ERR_UNKNOWN LITERAL1 diff --git a/src/BuildOpt.h b/src/BuildOpt.h index e58f93df85..d122254c2d 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -59,7 +59,7 @@ // Arduino API callbacks // the following are signatures of Arduino API functions of the custom platform // for example, pinMode on Arduino Uno is defined as void pinMode(uint8_t pin, uint8_t mode) - // all fo the callbacks below are taken from Arduino Uno + // all of the callbacks below are taken from Arduino Uno #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) @@ -72,6 +72,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -137,6 +138,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -171,6 +173,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -209,6 +212,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -246,6 +250,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -283,6 +288,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -317,6 +323,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, pin_size_t pin, uint8_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -352,6 +359,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -386,6 +394,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -420,6 +429,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t dwUs) #define RADIOLIB_CB_ARGS_MILLIS (uint64_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint64_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -454,6 +464,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -491,6 +502,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -529,6 +541,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -567,6 +580,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -601,6 +615,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32 us) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t ulPin, uint32_t ulState, uint32_t ulTimeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -635,6 +650,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -673,6 +689,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -706,6 +723,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint16 microseconds) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint8_t pin_name, uint8_t mode, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -762,6 +780,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -816,6 +835,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, long unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -851,6 +871,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) diff --git a/src/Module.cpp b/src/Module.cpp index eb20ff7b5b..bc09de8fa0 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -373,6 +373,13 @@ uint32_t Module::micros() { return(cb_micros()); } +uint32_t Module::pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout) { + if(cb_pulseIn == nullptr) { + return(0); + } + return(cb_pulseIn(pin, state, timeout)); +} + void Module::begin() { if(cb_SPIbegin == nullptr) { return; diff --git a/src/Module.h b/src/Module.h index 93ddf15972..5148ace0f7 100644 --- a/src/Module.h +++ b/src/Module.h @@ -333,6 +333,11 @@ class Module { */ uint32_t micros(); + /*! + \brief Arduino core pulseIn override. + */ + uint32_t pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout); + /*! \brief Arduino core SPI begin override. */ @@ -408,6 +413,7 @@ class Module { RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY_MICROSECONDS); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MILLIS); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MICROS); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PULSE_IN); #if defined(RADIOLIB_BUILD_ARDUINO) RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index d3dd40f69f..65f1a11df4 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -20,8 +20,14 @@ int16_t MorseClient::begin(float base, uint8_t speed) { _baseHz = base; _base = (base * 1000000.0) / _phy->getFreqStep(); - // calculate dot length (assumes PARIS as typical word) + // calculate tone period for decoding + _basePeriod = (1000000.0f/base)/2.0f; + + // calculate symbol lengths (assumes PARIS as typical word) _dotLength = 1200 / speed; + _dashLength = 3*_dotLength; + _letterSpace = 3*_dotLength; + _wordSpace = 4*_dotLength; // configure for direct mode return(_phy->startDirect()); @@ -31,6 +37,78 @@ size_t MorseClient::startSignal() { return(MorseClient::write('_')); } +char MorseClient::decode(uint8_t symbol, uint8_t len) { + // add the guard bit + symbol |= (RADIOLIB_MORSE_DASH << len); + + // iterate over the table + for(uint8_t i = 0; i < sizeof(MorseTable); i++) { + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[i]); + if(code == symbol) { + // match, return the index + ASCII offset + return((char)(i + RADIOLIB_MORSE_ASCII_OFFSET)); + } + } + + // nothing found + return(RADIOLIB_MORSE_UNSUPORTED); +} + +#if !defined(RADIOLIB_EXCLUDE_AFSK) +int MorseClient::read(byte* symbol, byte* len, float low, float high) { + Module* mod = _phy->getMod(); + + // measure pulse duration in us + uint32_t duration = mod->pulseIn(_audio->_pin, LOW, 4*_basePeriod); + + // decide if this is a signal, or pause + if((duration > low*_basePeriod) && (duration < high*_basePeriod)) { + // this is a signal + signalCounter++; + } else if(duration == 0) { + // this is a pause + pauseCounter++; + } + + // update everything + if((pauseCounter > 0) && (signalCounter == 1)) { + // start of dot or dash + pauseCounter = 0; + signalStart = mod->millis(); + uint32_t pauseLen = mod->millis() - pauseStart; + + if((pauseLen >= low*(float)_letterSpace) && (pauseLen <= high*(float)_letterSpace)) { + return(RADIOLIB_MORSE_CHAR_COMPLETE); + } else if(pauseLen > _wordSpace) { + RADIOLIB_DEBUG_PRINTLN("\n"); + return(RADIOLIB_MORSE_WORD_COMPLETE); + } + + } else if((signalCounter > 0) && (pauseCounter == 1)) { + // end of dot or dash + signalCounter = 0; + pauseStart = mod->millis(); + uint32_t signalLen = mod->millis() - signalStart; + + if((signalLen >= low*(float)_dotLength) && (signalLen <= high*(float)_dotLength)) { + RADIOLIB_DEBUG_PRINT('.'); + (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); + (*len)++; + } else if((signalLen >= low*(float)_dashLength) && (signalLen <= high*(float)_dashLength)) { + RADIOLIB_DEBUG_PRINT('-'); + (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); + (*len)++; + } else { + RADIOLIB_DEBUG_PRINT(""); + } + } + + return(RADIOLIB_MORSE_INTER_SYMBOL); +} +#endif + size_t MorseClient::write(const char* str) { if(str == NULL) { return(0); @@ -59,12 +137,12 @@ size_t MorseClient::write(uint8_t b) { if(b == ' ') { RADIOLIB_DEBUG_PRINTLN(F("space")); standby(); - mod->delay(4 * _dotLength); + mod->delay(_wordSpace); return(1); } // get morse code from lookup table - uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - 32)]); + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]); // check unsupported characters if(code == RADIOLIB_MORSE_UNSUPORTED) { @@ -78,7 +156,7 @@ size_t MorseClient::write(uint8_t b) { if (code & RADIOLIB_MORSE_DASH) { RADIOLIB_DEBUG_PRINT('-'); transmitDirect(_base, _baseHz); - mod->delay(3 * _dotLength); + mod->delay(_dashLength); } else { RADIOLIB_DEBUG_PRINT('.'); transmitDirect(_base, _baseHz); @@ -95,7 +173,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); - mod->delay(2 * _dotLength); + mod->delay(_letterSpace - _dotLength); RADIOLIB_DEBUG_PRINTLN(); return(1); diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 66ead3b910..bfa72b52d5 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -9,6 +9,10 @@ #define RADIOLIB_MORSE_DASH 0b1 #define RADIOLIB_MORSE_GUARDBIT 0b1 #define RADIOLIB_MORSE_UNSUPORTED 0xFF +#define RADIOLIB_MORSE_ASCII_OFFSET 32 +#define RADIOLIB_MORSE_INTER_SYMBOL 0x00 +#define RADIOLIB_MORSE_CHAR_COMPLETE 0x01 +#define RADIOLIB_MORSE_WORD_COMPLETE 0x02 // Morse character table: - using codes defined in ITU-R M.1677-1 // - Morse code representation is saved LSb first, using additional bit as guard @@ -124,6 +128,34 @@ class MorseClient { */ size_t startSignal(); + /*! + \brief Decode Morse symbol to ASCII. + + \param symbol Morse code symbol, respresented as outlined in MorseTable. + + \param len Symbol length (number of dots and dashes). + + \returns ASCII character matching the symbol, or 0xFF if no match is found. + */ + static char decode(uint8_t symbol, uint8_t len); + + /*! + \brief Read Morse tone on input pin. + + \param symbol Pointer to the symbol buffer. + + \param len Pointer to the length counter. + + \param low Low threshold for decision limit (dot length, pause length etc.), defaults to 0.75. + + \param high High threshold for decision limit (dot length, pause length etc.), defaults to 1.25. + + \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, 2 if inter-word space was detected. + */ + #if !defined(RADIOLIB_EXCLUDE_AFSK) + int read(byte* symbol, byte* len, float low = 0.75f, float high = 1.25f); + #endif + size_t write(const char* str); size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); @@ -160,7 +192,17 @@ class MorseClient { #endif uint32_t _base = 0, _baseHz = 0; + float _basePeriod = 0.0f; uint16_t _dotLength = 0; + uint16_t _dashLength = 0; + uint16_t _letterSpace = 0; + uint16_t _wordSpace = 0; + + // variables to keep decoding state + uint32_t signalCounter = 0; + uint32_t signalStart = 0; + uint32_t pauseCounter = 0; + uint32_t pauseStart = 0; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 98c8778c41..f0e62cd0d3 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -248,5 +248,5 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { } int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { - return(RADIOLIB_ERR_UNSUPPORTED); + return(RADIOLIB_ERR_UNSUPPORTED); } From 4bdec52f882db957e72d498527bcf3971665dc25 Mon Sep 17 00:00:00 2001 From: Peter Lawrence <12226419+majbthrd@users.noreply.github.com> Date: Thu, 4 Aug 2022 17:46:58 -0500 Subject: [PATCH 0204/1848] remedy Module when RADIOLIB_BUILD_ARDUINO is not defined --- src/BuildOpt.h | 5 +++-- src/Module.cpp | 22 ++++++++++++++++++++++ src/Module.h | 6 +++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index d122254c2d..f09f75a9e6 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -886,6 +886,7 @@ #define RADIOLIB_PLATFORM "Generic" // platform properties may be defined here, or somewhere else in the build system + #include "noarduino.h" #endif @@ -1019,11 +1020,11 @@ #define RADIOLIB_REST(arg, ...) __VA_ARGS__ #define RADIOLIB_EXP(...) __VA_ARGS__ -#define RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, FUNC, ...) public: typedef RET (*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC; +#define RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, FUNC, ...) public: typedef RET (*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC = nullptr; #define RADIOLIB_GENERATE_CALLBACK_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, __VA_ARGS__) #define RADIOLIB_GENERATE_CALLBACK(CB) RADIOLIB_GENERATE_CALLBACK_RET(RADIOLIB_EXP(RADIOLIB_FIRST CB), RADIOLIB_EXP(RADIOLIB_REST CB)) -#define RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, FUNC, ...) public: typedef RET (Module::*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC; +#define RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, FUNC, ...) public: typedef RET (Module::*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC = nullptr; #define RADIOLIB_GENERATE_CALLBACK_SPI_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, __VA_ARGS__) #define RADIOLIB_GENERATE_CALLBACK_SPI(CB) RADIOLIB_GENERATE_CALLBACK_SPI_RET(RADIOLIB_EXP(RADIOLIB_FIRST CB), RADIOLIB_EXP(RADIOLIB_REST CB)) diff --git a/src/Module.cpp b/src/Module.cpp index bc09de8fa0..f5ce65edab 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -105,13 +105,16 @@ Module& Module::operator=(const Module& mod) { void Module::init() { this->pinMode(_cs, OUTPUT); this->digitalWrite(_cs, HIGH); +#if defined(RADIOLIB_BUILD_ARDUINO) if(_initInterface) { (this->*cb_SPIbegin)(); } +#endif } void Module::term() { // stop hardware interfaces (if they were initialized by the library) +#if defined(RADIOLIB_BUILD_ARDUINO) if(!_initInterface) { return; } @@ -119,6 +122,7 @@ void Module::term() { if(_spi != nullptr) { this->SPIend(); } +#endif } int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { @@ -381,57 +385,75 @@ uint32_t Module::pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint3 } void Module::begin() { +#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIbegin == nullptr) { return; } (this->*cb_SPIbegin)(); +#endif } void Module::beginTransaction() { +#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIbeginTransaction == nullptr) { return; } (this->*cb_SPIbeginTransaction)(); +#endif } uint8_t Module::transfer(uint8_t b) { +#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPItransfer == nullptr) { return(0xFF); } return((this->*cb_SPItransfer)(b)); +#endif } void Module::endTransaction() { +#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIendTransaction == nullptr) { return; } (this->*cb_SPIendTransaction)(); +#endif } void Module::end() { +#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIend == nullptr) { return; } (this->*cb_SPIend)(); +#endif } #if defined(RADIOLIB_BUILD_ARDUINO) void Module::SPIbegin() { _spi->begin(); } +#endif void Module::SPIbeginTransaction() { +#if defined(RADIOLIB_BUILD_ARDUINO) _spi->beginTransaction(_spiSettings); +#endif } uint8_t Module::SPItransfer(uint8_t b) { +#if defined(RADIOLIB_BUILD_ARDUINO) return(_spi->transfer(b)); +#endif } void Module::SPIendTransaction() { +#if defined(RADIOLIB_BUILD_ARDUINO) _spi->endTransaction(); +#endif } +#if defined(RADIOLIB_BUILD_ARDUINO) void Module::SPIend() { _spi->end(); } diff --git a/src/Module.h b/src/Module.h index 5148ace0f7..4a8da75a12 100644 --- a/src/Module.h +++ b/src/Module.h @@ -366,11 +366,11 @@ class Module { // helper functions to set up SPI overrides on Arduino #if defined(RADIOLIB_BUILD_ARDUINO) void SPIbegin(); - virtual void SPIbeginTransaction(); - uint8_t SPItransfer(uint8_t b); - virtual void SPIendTransaction(); void SPIend(); #endif + virtual void SPIbeginTransaction(); + virtual uint8_t SPItransfer(uint8_t b); + virtual void SPIendTransaction(); /*! \brief Function to reflect bits within a byte. From 655dfaae451d1c2f9a8f0018c2c6bb0586e2d3d2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 Aug 2022 09:57:41 +0200 Subject: [PATCH 0205/1848] Added missing pulsein callback set --- src/Module.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index f5ce65edab..04d996367c 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -34,6 +34,7 @@ Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rs setCb_delayMicroseconds(::delayMicroseconds); setCb_millis(::millis); setCb_micros(::micros); + setCb_pulseIn(::pulseIn); setCb_SPIbegin(&Module::SPIbegin); setCb_SPIbeginTransaction(&Module::beginTransaction); setCb_SPItransfer(&Module::transfer); @@ -68,6 +69,7 @@ Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rs setCb_delayMicroseconds(::delayMicroseconds); setCb_millis(::millis); setCb_micros(::micros); + setCb_pulseIn(::pulseIn); setCb_SPIbegin(&Module::SPIbegin); setCb_SPIbeginTransaction(&Module::beginTransaction); setCb_SPItransfer(&Module::transfer); From 4a637b44f1fbbbd383c5d00309e0dc9fca8b45fb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 Aug 2022 10:21:07 +0200 Subject: [PATCH 0206/1848] [Morse] Fixed bug in decoder logic --- .../Morse/Morse_Receive_AM/Morse_Receive_AM.ino | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino index 62b9f7fe5c..c078173f60 100644 --- a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino +++ b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino @@ -95,8 +95,8 @@ void loop() { // try to read a new symbol int state = morse.read(&symbol, &len); - // check if we have a complete character - if(state == RADIOLIB_MORSE_CHAR_COMPLETE) { + // check if we have something to decode + if(state != RADIOLIB_MORSE_INTER_SYMBOL) { // decode and print Serial.print(MorseClient::decode(symbol, len)); @@ -104,9 +104,12 @@ void loop() { symbol = 0; len = 0; - } else if(state == RADIOLIB_MORSE_WORD_COMPLETE) { - // inter-word space, interpret that as a new line - Serial.println(); - + // check if we have a complete word + if(state == RADIOLIB_MORSE_WORD_COMPLETE) { + // inter-word space, interpret that as a new line + Serial.println(); + } + } + } From ec94177c2a06d08fb4feca3baa2661e9bee952f6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 9 Aug 2022 20:20:19 +0200 Subject: [PATCH 0207/1848] [MOD] Cache tone value on ESP32 (#553) --- src/Module.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 04d996367c..90eb3c47d2 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -272,6 +272,11 @@ RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) { return(cb_digitalRead(pin)); } +#if defined(ESP32) +// we need to cache the previous tone value for emulation on ESP32 +int32_t prev = -1; +#endif + void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if((pin == RADIOLIB_NC) || (cb_tone == nullptr)) { @@ -285,8 +290,13 @@ void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) { #if defined(ESP32) // ESP32 tone() emulation (void)duration; - ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); - ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); + if(prev == -1) { + ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); + } + if(prev != value) { + ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); + } + prev = value; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) // better tone for mbed OS boards (void)duration; @@ -320,6 +330,7 @@ void Module::noTone(RADIOLIB_PIN_TYPE pin) { // ESP32 tone() emulation ledcDetachPin(pin); ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + prev = -1; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) // better tone for mbed OS boards (void)pin; From da0993a6edf9e48a66ad44a01923708244be01af Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 15 Aug 2022 19:19:59 +0200 Subject: [PATCH 0208/1848] Added RADIOLIB_EXCLUDE_DIRECT_RECEIVE exclusion macro (#557) --- src/BuildOpt.h | 1 + src/modules/CC1101/CC1101.cpp | 2 ++ src/modules/CC1101/CC1101.h | 2 ++ src/modules/RF69/RF69.cpp | 14 +++++++++----- src/modules/RF69/RF69.h | 2 ++ src/modules/SX126x/SX126x.cpp | 2 ++ src/modules/SX126x/SX126x.h | 3 +++ src/modules/SX127x/SX127x.cpp | 2 ++ src/modules/SX127x/SX127x.h | 6 ++++-- src/modules/SX128x/SX128x.cpp | 2 ++ src/modules/SX128x/SX128x.h | 2 ++ src/modules/Si443x/Si443x.cpp | 2 ++ src/modules/Si443x/Si443x.h | 2 ++ src/modules/nRF24/nRF24.cpp | 2 ++ src/modules/nRF24/nRF24.h | 2 ++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 6 ++++++ 17 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index f09f75a9e6..48ca539eb8 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -108,6 +108,7 @@ //#define RADIOLIB_EXCLUDE_MORSE //#define RADIOLIB_EXCLUDE_RTTY //#define RADIOLIB_EXCLUDE_SSTV + //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE #else #if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index bc188f4323..e9e367005a 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -890,6 +890,7 @@ int16_t CC1101::getChipVersion() { return(SPIgetRegValue(RADIOLIB_CC1101_REG_VERSION)); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void CC1101::setDirectAction(void (*func)(void)) { setGdo0Action(func); } @@ -897,6 +898,7 @@ void CC1101::setDirectAction(void (*func)(void)) { void CC1101::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +#endif int16_t CC1101::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { if (pin > 2) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index fd8cb621f6..a661107f9f 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -920,6 +920,7 @@ class CC1101: public PhysicalLayer { */ int16_t getChipVersion(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. @@ -933,6 +934,7 @@ class CC1101: public PhysicalLayer { \param pin Pin on which to read. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 82d47c18a4..9fc69ef200 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -895,6 +895,7 @@ uint8_t RF69::randomByte() { return(randByte); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void RF69::setDirectAction(void (*func)(void)) { setDio1Action(func); } @@ -902,15 +903,18 @@ void RF69::setDirectAction(void (*func)(void)) { void RF69::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +#endif int16_t RF69::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { - if (pin > 5) - return RADIOLIB_ERR_INVALID_DIO_PIN; + if(pin > 5) { + return(RADIOLIB_ERR_INVALID_DIO_PIN); + } - if (pin < 4) + if(pin < 4) { return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); - else - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); + } + + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); } int16_t RF69::getChipVersion() { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index e7652e5169..ef9969e25d 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -985,6 +985,7 @@ class RF69: public PhysicalLayer { */ int16_t getChipVersion(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. @@ -998,6 +999,7 @@ class RF69: public PhysicalLayer { \param pin Pin on which to read. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 64161ea38b..14868dd1e7 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1233,6 +1233,7 @@ uint8_t SX126x::randomByte() { return(randByte); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX126x::setDirectAction(void (*func)(void)) { // SX126x is unable to perform direct mode reception // this method is implemented only for PhysicalLayer compatibility @@ -1244,6 +1245,7 @@ void SX126x::readBit(RADIOLIB_PIN_TYPE pin) { // this method is implemented only for PhysicalLayer compatibility (void)pin; } +#endif int16_t SX126x::setTCXO(float voltage, uint32_t delay) { // set mode to standby diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index df2d295291..0c42656619 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -928,6 +928,7 @@ class SX126x: public PhysicalLayer { */ uint8_t randomByte(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -941,6 +942,8 @@ class SX126x: public PhysicalLayer { \param pin Ignored. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif + #if !defined(RADIOLIB_GODMODE) protected: diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 31396428eb..29980071b7 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1493,6 +1493,7 @@ int16_t SX127x::invertIQ(bool invertIQ) { return(state); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX127x::setDirectAction(void (*func)(void)) { setDio1Action(func); } @@ -1500,6 +1501,7 @@ void SX127x::setDirectAction(void (*func)(void)) { void SX127x::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +#endif int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 505abd6cf4..996776c9c8 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -557,8 +557,8 @@ #define RADIOLIB_SX127X_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 #define RADIOLIB_SX127X_DIO5_PACK_DATA 0b00100000 // 5 4 #define RADIOLIB_SX127X_DIO5_PACK_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 -#define RADIOLIB_SX127X_DIO_MAP_RSSI 0b00000000 // 0 0 +#define RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 +#define RADIOLIB_SX127X_DIO_MAP_RSSI 0b00000000 // 0 0 // SX1272_REG_PLL_HOP + SX1278_REG_PLL_HOP #define RADIOLIB_SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written @@ -1163,6 +1163,7 @@ class SX127x: public PhysicalLayer { */ int16_t invertIQ(bool invertIQ); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. @@ -1176,6 +1177,7 @@ class SX127x: public PhysicalLayer { \param pin Pin on which to read. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif /*! \brief Sets the hopping period and enables FHSS diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index cf09f0bb97..d61ce930f6 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1243,6 +1243,7 @@ uint8_t SX128x::randomByte() { return(0); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX128x::setDirectAction(void (*func)(void)) { // SX128x is unable to perform direct mode reception // this method is implemented only for PhysicalLayer compatibility @@ -1254,6 +1255,7 @@ void SX128x::readBit(RADIOLIB_PIN_TYPE pin) { // this method is implemented only for PhysicalLayer compatibility (void)pin; } +#endif uint8_t SX128x::getStatus() { uint8_t data = 0; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index f9df39e3eb..6e1a7894d3 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -812,6 +812,7 @@ class SX128x: public PhysicalLayer { */ uint8_t randomByte(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -825,6 +826,7 @@ class SX128x: public PhysicalLayer { \param pin Ignored. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index f033d0ece9..fcd418765c 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -589,6 +589,7 @@ int16_t Si443x::getChipVersion() { return(_mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void Si443x::setDirectAction(void (*func)(void)) { setIrqAction(func); } @@ -596,6 +597,7 @@ void Si443x::setDirectAction(void (*func)(void)) { void Si443x::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +#endif int16_t Si443x::fixedPacketLengthMode(uint8_t len) { return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON, len)); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 40feceef80..2175be7c56 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -802,6 +802,7 @@ class Si443x: public PhysicalLayer { */ int16_t getChipVersion(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. @@ -815,6 +816,7 @@ class Si443x: public PhysicalLayer { \param pin Pin on which to read. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif /*! \brief Set modem in fixed packet length mode. diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index d767dbd3f9..3b90ba702c 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -516,6 +516,7 @@ uint8_t nRF24::randomByte() { return(0); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void nRF24::setDirectAction(void (*func)(void)) { // nRF24 is unable to perform direct mode actions // this method is implemented only for PhysicalLayer compatibility @@ -527,6 +528,7 @@ void nRF24::readBit(RADIOLIB_PIN_TYPE pin) { // this method is implemented only for PhysicalLayer compatibility (void)pin; } +#endif void nRF24::clearIRQ() { // clear status bits diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index fead3bf1c4..8b6226dc31 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -473,6 +473,7 @@ class nRF24: public PhysicalLayer { */ uint8_t randomByte(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -486,6 +487,7 @@ class nRF24: public PhysicalLayer { \param pin Ignored. */ void readBit(RADIOLIB_PIN_TYPE pin); + #endif #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index f0e62cd0d3..71185909c9 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -3,8 +3,10 @@ PhysicalLayer::PhysicalLayer(float freqStep, size_t maxPacketLength) { _freqStep = freqStep; _maxPacketLength = maxPacketLength; + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) _bufferBitPos = 0; _bufferWritePos = 0; + #endif } int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { @@ -188,6 +190,7 @@ int16_t PhysicalLayer::startDirect() { return(state); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) int16_t PhysicalLayer::available() { return(_bufferWritePos); } @@ -246,6 +249,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { } } } +#endif int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { return(RADIOLIB_ERR_UNSUPPORTED); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index e67dd1e8e9..efee97fb3f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -261,6 +261,7 @@ class PhysicalLayer { */ int16_t startDirect(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set sync word to be used to determine start of packet in direct reception mode. @@ -299,6 +300,7 @@ class PhysicalLayer { \returns Byte from direct mode buffer. */ uint8_t read(); + #endif /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). @@ -311,8 +313,10 @@ class PhysicalLayer { */ virtual int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) protected: void updateDirectBuffer(uint8_t bit); +#endif #if !defined(RADIOLIB_GODMODE) private: @@ -320,6 +324,7 @@ class PhysicalLayer { float _freqStep; size_t _maxPacketLength; + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) uint8_t _bufferBitPos; uint8_t _bufferWritePos; uint8_t _bufferReadPos; @@ -329,6 +334,7 @@ class PhysicalLayer { uint8_t _directSyncWordLen; uint32_t _directSyncWordMask; bool _gotSync; + #endif virtual Module* getMod() = 0; From a8c079f85e9af860d02dbb1a741f2fea22b47693 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Aug 2022 20:48:51 +0200 Subject: [PATCH 0209/1848] [MOD] Fixed hexdump printing when length is not divisible by 16 --- src/Module.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 90eb3c47d2..c81d73029c 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -488,22 +488,34 @@ uint16_t Module::flipBits16(uint16_t i) { } void Module::hexdump(uint8_t* data, size_t len) { + size_t rem_len = len; for(int i = 0; i < len; i+=16) { char str[80]; sprintf(str, "%07x ", i); - for(int j = 0; j < 16; j++) { + size_t line_len = 16; + if(rem_len < line_len) { + line_len = rem_len; + } + for(int j = 0; j < line_len; j++) { sprintf(&str[8 + j*3], "%02x ", data[i+j]); } + for(int j = line_len; j < 16; j++) { + sprintf(&str[8 + j*3], " "); + } str[56] = '|'; str[57] = ' '; - for(int j = 0; j < 16; j++) { + for(int j = 0; j < line_len; j++) { char c = data[i+j]; if((c < ' ') || (c > '~')) { c = '.'; } sprintf(&str[58 + j], "%c", c); } + for(int j = line_len; j < 16; j++) { + sprintf(&str[58 + j], " "); + } RADIOLIB_DEBUG_PRINTLN(str); + rem_len -= 16; } } From 30cb7c8dd4447448e763f94d237ca39665ddbcfd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Aug 2022 18:14:13 +0200 Subject: [PATCH 0210/1848] [APRS] Added Mic-E (#430) --- examples/APRS/APRS_MicE/APRS_MicE.ino | 111 ++++++++++++++++++ keywords.txt | 9 ++ src/TypeDef.h | 15 +++ src/protocols/APRS/APRS.cpp | 160 ++++++++++++++++++++++++++ src/protocols/APRS/APRS.h | 56 +++++++++ 5 files changed, 351 insertions(+) create mode 100644 examples/APRS/APRS_MicE/APRS_MicE.ino diff --git a/examples/APRS/APRS_MicE/APRS_MicE.ino b/examples/APRS/APRS_MicE/APRS_MicE.ino new file mode 100644 index 0000000000..9ddd22873c --- /dev/null +++ b/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -0,0 +1,111 @@ +/* + RadioLib APRS Mic-E Example + + This example sends APRS position reports + encoded in the Mic-E format using SX1278's + FSK modem. The data is modulated as AFSK + at 1200 baud using Bell 202 tones. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + Other modules that can be used for APRS: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +// create APRS client isntance using the AX.25 client +APRSClient aprs(&ax25); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + // NOTE: moved to ISM band on purpose + // DO NOT transmit in APRS bands without ham radio license! + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + state = aprs.begin('>'); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending Mic-E position ... ")); + int state = aprs.sendMicE(49.1945, 16.6000, 120, 10, RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/keywords.txt b/keywords.txt index 8c3a0a3399..ce8ca0ae12 100644 --- a/keywords.txt +++ b/keywords.txt @@ -150,6 +150,8 @@ randomByte KEYWORD2 getPacketLength KEYWORD2 setFifoEmptyAction KEYWORD2 clearFifoEmptyAction KEYWORD2 +setFifoFullAction KEYWORD2 +clearFifoFullAction KEYWORD2 fifoAdd KEYWORD2 fifoGet KEYWORD2 @@ -234,6 +236,7 @@ noTone KEYWORD2 # APRS sendPosition KEYWORD2 +sendMicE KEYWORD2 ####################################### # Constants (LITERAL1) @@ -291,6 +294,12 @@ RADIOLIB_ERR_INVALID_RX_BANDWIDTH LITERAL1 RADIOLIB_ERR_INVALID_SYNC_WORD LITERAL1 RADIOLIB_ERR_INVALID_DATA_SHAPING LITERAL1 RADIOLIB_ERR_INVALID_MODULATION LITERAL1 +RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE LITERAL1 + +RADIOLIB_ERR_INVALID_SYMBOL LITERAL1 +RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY LITERAL1 +RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH LITERAL1 +RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS LITERAL1 RADIOLIB_ASCII LITERAL1 RADIOLIB_ASCII_EXTENDED LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index 71b738c265..0ac5d2ef01 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -262,6 +262,21 @@ */ #define RADIOLIB_ERR_INVALID_SYMBOL (-201) +/*! + \brief Mic-E Telemetry is invalid. +*/ +#define RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY (-202) + +/*! + \brief Mic-E Telemetry length is invalid (only 0, 2 or 5 is allowed). +*/ +#define RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH (-203) + +/*! + \brief Mic-E message cannot contaion both telemetry and status text. +*/ +#define RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS (-204) + // RTTY status codes /*! diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 045d09a0a6..7f4976b08d 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -54,6 +54,166 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat return(state); } +int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem, size_t telemLen, char* grid, char* status, int32_t alt) { + // sanity checks first + if(((telemLen == 0) && (telem != NULL)) || ((telemLen != 0) && (telem == NULL))) { + return(RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY); + } + + if((telemLen != 0) && (telemLen != 2) && (telemLen != 5)) { + return(RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH); + } + + if((telemLen > 0) && ((grid != NULL) || (status != NULL) || (alt != RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED))) { + // can't have both telemetry and status + return(RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS); + } + + // prepare buffers + char destCallsign[7]; + #if !defined(RADIOLIB_STATIC_ONLY) + size_t infoLen = 10; + if(telemLen > 0) { + infoLen += 1 + telemLen; + } else { + if(grid != NULL) { + infoLen += strlen(grid) + 2; + } + if(status != NULL) { + infoLen += strlen(status); + } + if(alt > RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED) { + infoLen += 4; + } + } + char* info = new char[infoLen]; + #else + char info[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + size_t infoPos = 0; + + // the following is based on APRS Mic-E implementation by https://github.com/omegat + // as discussed in https://github.com/jgromes/RadioLib/issues/430 + + // latitude first, because that is in the destination field + float lat_abs = abs(lat); + int lat_deg = (int)lat_abs; + int lat_min = (lat_abs - (float)lat_deg) * 60.0f; + int lat_hun = (((lat_abs - (float)lat_deg) * 60.0f) - lat_min) * 100.0f; + destCallsign[0] = lat_deg/10; + destCallsign[1] = lat_deg%10; + destCallsign[2] = lat_min/10; + destCallsign[3] = lat_min%10; + destCallsign[4] = lat_hun/10; + destCallsign[5] = lat_hun%10; + + // next, add the extra bits + if(type & 0x04) { destCallsign[0] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(type & 0x02) { destCallsign[1] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(type & 0x01) { destCallsign[2] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(lat >= 0) { destCallsign[3] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(lon >= 100 || lon <= -100) { destCallsign[4] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + if(lon < 0) { destCallsign[5] += RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET; } + destCallsign[6] = '\0'; + + // now convert to Mic-E characters to get the "callsign" + for(uint8_t i = 0; i < 6; i++) { + if(destCallsign[i] <= 9) { + destCallsign[i] += '0'; + } else { + destCallsign[i] += ('A' - 10); + } + } + + // setup the information field + info[infoPos++] = RADIOLIB_APRS_MIC_E_GPS_DATA_CURRENT; + + // encode the longtitude + float lon_abs = abs(lon); + int32_t lon_deg = (int32_t)lon_abs; + int32_t lon_min = (lon_abs - (float)lon_deg) * 60.0f; + int32_t lon_hun = (((lon_abs - (float)lon_deg) * 60.0f) - lon_min) * 100.0f; + + if(lon_deg <= 9) { + info[infoPos++] = lon_deg + 118; + } else if(lon_deg <= 99) { + info[infoPos++] = lon_deg + 28; + } else if(lon_deg <= 109) { + info[infoPos++] = lon_deg + 8; + } else { + info[infoPos++] = lon_deg - 72; + } + + if(lon_min <= 9){ + info[infoPos++] = lon_min + 88; + } else { + info[infoPos++] = lon_min + 28; + } + + info[infoPos++] = lon_hun + 28; + + // now the speed and heading - this gets really weird + int32_t speed_hun_ten = speed/10; + int32_t speed_uni = speed%10; + int32_t head_hun = heading/100; + int32_t head_ten_uni = heading%100; + + if(speed <= 199) { + info[infoPos++] = speed_hun_ten + 'l'; + } else { + info[infoPos++] = speed_hun_ten + '0'; + } + + info[infoPos++] = speed_uni*10 + head_hun + 32; + info[infoPos++] = head_ten_uni + 28; + info[infoPos++] = _symbol; + info[infoPos++] = _table; + + // onto the optional stuff - check telemetry first + if(telemLen > 0) { + if(telemLen == 2) { + info[infoPos++] = RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_2; + } else { + info[infoPos++] = RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_5; + } + for(uint8_t i = 0; i < telemLen; i++) { + sprintf(&(info[infoPos]), "%02X", telem[i]); + infoPos += 2; + } + + } else { + if(grid != NULL) { + memcpy(&(info[infoPos]), grid, strlen(grid)); + infoPos += strlen(grid); + info[infoPos++] = '/'; + info[infoPos++] = 'G'; + } + if(status != NULL) { + info[infoPos++] = ' '; + memcpy(&(info[infoPos]), status, strlen(status)); + infoPos += strlen(status); + } + if(alt > RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED) { + // altitude is offset by -10 km + int32_t alt_val = alt + 10000; + + // ... and encoded in base 91 for some reason + info[infoPos++] = (alt_val / 8281) + 33; + info[infoPos++] = ((alt_val % 8281) / 91) + 33; + info[infoPos++] = ((alt_val % 8281) % 91) + 33; + info[infoPos++] = '}'; + } + } + info[infoPos++] = '\0'; + + // send the frame + int16_t state = sendFrame(destCallsign, 0, info); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] info; + #endif + return(state); +} + int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) { // get AX.25 callsign char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index 6e272aa704..39f89c64da 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -27,6 +27,37 @@ #define RADIOLIB_APRS_DATA_TYPE_USER_DEFINED "{" #define RADIOLIB_APRS_DATA_TYPE_THIRD_PARTY "}" +/*! + \defgroup mic_e_message_types Mic-E message types. + + \{ +*/ +#define RADIOLIB_APRS_MIC_E_TYPE_OFF_DUTY 0b00000111 +#define RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE 0b00000110 +#define RADIOLIB_APRS_MIC_E_TYPE_IN_SERVICE 0b00000101 +#define RADIOLIB_APRS_MIC_E_TYPE_RETURNING 0b00000100 +#define RADIOLIB_APRS_MIC_E_TYPE_COMMITTED 0b00000011 +#define RADIOLIB_APRS_MIC_E_TYPE_SPECIAL 0b00000010 +#define RADIOLIB_APRS_MIC_E_TYPE_PRIORITY 0b00000001 +#define RADIOLIB_APRS_MIC_E_TYPE_EMERGENCY 0b00000000 +/*! + \} +*/ + +// magic offset applied to encode extra bits in the Mic-E destination field +#define RADIOLIB_APRS_MIC_E_DEST_BIT_OFFSET 25 + +// Mic-E data types +#define RADIOLIB_APRS_MIC_E_GPS_DATA_CURRENT '`' +#define RADIOLIB_APRS_MIC_E_GPS_DATA_OLD '\'' + +// Mic-E telemetry flags +#define RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_2 '`' +#define RADIOLIB_APRS_MIC_E_TELEMETRY_LEN_5 '\'' + +// alias for unused altitude in Mic-E +#define RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED -1000000 + /*! \class APRSClient @@ -73,6 +104,31 @@ class APRSClient { */ int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL); + /* + \brief Transmit position using Mic-E encoding. + + \param lat Geographical latitude, positive for north, negative for south. + + \param lon Geographical longitude, positive for east, negative for west. + + \param heading Heading in degrees. + + \param speed Speed in knots. + + \param type Mic-E message type - see \ref mic_e_message_types. + + \param telem Pointer to telemetry array (either 2 or 5 bytes long). NULL when telemetry is not used. + + \param telemLen Telemetry length, 2 or 5. 0 when telemetry is not used. + + \param grid Maidenhead grid locator. NULL when not used. + + \param status Status message to send. NULL when not used. + + \param alt Altitude to send. RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED when not used. + */ + int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem = NULL, size_t telemLen = 0, char* grid = NULL, char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED); + /*! \brief Transmit generic APRS frame. From bedbf7bb947182734478e72c3ab84167b060413b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Aug 2022 19:01:24 +0200 Subject: [PATCH 0211/1848] [RFM9x] Fixed missing default argument for beginFSK (#553) --- src/modules/RFM9x/RFM95.h | 2 +- src/modules/RFM9x/RFM96.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/RFM9x/RFM95.h b/src/modules/RFM9x/RFM95.h index aa555103c5..18d2a91eba 100644 --- a/src/modules/RFM9x/RFM95.h +++ b/src/modules/RFM9x/RFM95.h @@ -77,7 +77,7 @@ class RFM95: public SX1278 { \returns \ref status_codes */ - int16_t beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h index 3c1d1f8204..51bd481a0d 100644 --- a/src/modules/RFM9x/RFM96.h +++ b/src/modules/RFM9x/RFM96.h @@ -77,7 +77,7 @@ class RFM96: public SX1278 { \returns \ref status_codes */ - int16_t beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods From fd3b165bf0a13ef3c3adf17757e6eca40802eac5 Mon Sep 17 00:00:00 2001 From: OBones Date: Tue, 23 Aug 2022 17:41:37 +0200 Subject: [PATCH 0212/1848] Introduce setRSSIThreshold on RF69 modules --- src/TypeDef.h | 5 +++++ src/modules/RF69/RF69.cpp | 7 +++++++ src/modules/RF69/RF69.h | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/src/TypeDef.h b/src/TypeDef.h index 0ac5d2ef01..49a29f785f 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -213,6 +213,11 @@ */ #define RADIOLIB_ERR_INVALID_DIO_PIN (-26) +/*! + \brief The supplied RSSI threshold is invalid. +*/ +#define RADIOLIB_ERR_INVALID_RSSI_THRESHOLD (-27) + // RF69-specific status codes /*! diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 9fc69ef200..db39ff700d 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -872,6 +872,13 @@ float RF69::getRSSI() { return(-1.0 * (_mod->SPIgetRegValue(RADIOLIB_RF69_REG_RSSI_VALUE)/2.0)); } +int16_t RF69::setRSSIThreshold(float value) { + if (value < 127.5 || value > 0) + return RADIOLIB_ERR_INVALID_RSSI_THRESHOLD; + + return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * value), 7, 0); +} + void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index ef9969e25d..cb81cc4e0d 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -961,6 +961,15 @@ class RF69: public PhysicalLayer { */ float getRSSI(); + /*! + \brief Sets the RSSI value above which the RSSI interrupt is signaled + + \param value A value between -127.5 and 0 inclusive + + \returns \ref status_codes + */ + int16_t setRSSIThreshold(float value); + /*! \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! From 9a76aa1c841203a1a528e13b47e69ebd1bc25ddd Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 24 Aug 2022 15:05:20 +0200 Subject: [PATCH 0213/1848] Introduce setRSSIThreshold on SX127x modules --- src/modules/SX127x/SX127x.cpp | 7 +++++++ src/modules/SX127x/SX127x.h | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 29980071b7..2b2be9c27b 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1184,6 +1184,13 @@ int16_t SX127x::setCrcFiltering(bool crcOn) { } } +int16_t SX127x::setRSSIThreshold(float value) { + if (value < 127.5 || value > 0) + return RADIOLIB_ERR_INVALID_RSSI_THRESHOLD; + + return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * value), 7, 0); +} + int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 996776c9c8..b322df57dc 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1227,6 +1227,15 @@ class SX127x: public PhysicalLayer { */ int16_t setDIOPreambleDetect(bool usePreambleDetect); + /*! + \brief Sets the RSSI value above which the RSSI interrupt is signaled + + \param value A value between -127.5 and 0 inclusive + + \returns \ref status_codes + */ + int16_t setRSSIThreshold(float value); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif From a7b42b61b23546f6455c1cac75c619c2fc4b80d9 Mon Sep 17 00:00:00 2001 From: obones Date: Wed, 24 Aug 2022 15:38:12 +0200 Subject: [PATCH 0214/1848] Use a better name for the parameter so that it is clear that it's dBm that are expected here --- src/modules/RF69/RF69.cpp | 6 +++--- src/modules/RF69/RF69.h | 4 ++-- src/modules/SX127x/SX127x.cpp | 6 +++--- src/modules/SX127x/SX127x.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index db39ff700d..25818a4fd5 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -872,11 +872,11 @@ float RF69::getRSSI() { return(-1.0 * (_mod->SPIgetRegValue(RADIOLIB_RF69_REG_RSSI_VALUE)/2.0)); } -int16_t RF69::setRSSIThreshold(float value) { - if (value < 127.5 || value > 0) +int16_t RF69::setRSSIThreshold(float dbm) { + if (dbm < 127.5 || dbm > 0) return RADIOLIB_ERR_INVALID_RSSI_THRESHOLD; - return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * value), 7, 0); + return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index cb81cc4e0d..e1d3acf774 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -964,11 +964,11 @@ class RF69: public PhysicalLayer { /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled - \param value A value between -127.5 and 0 inclusive + \param dbm A dBm value between -127.5 and 0 inclusive \returns \ref status_codes */ - int16_t setRSSIThreshold(float value); + int16_t setRSSIThreshold(float dbm); /*! \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 2b2be9c27b..1adf22b894 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1184,11 +1184,11 @@ int16_t SX127x::setCrcFiltering(bool crcOn) { } } -int16_t SX127x::setRSSIThreshold(float value) { - if (value < 127.5 || value > 0) +int16_t SX127x::setRSSIThreshold(float dbm) { + if (dbm < 127.5 || dbm > 0) return RADIOLIB_ERR_INVALID_RSSI_THRESHOLD; - return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * value), 7, 0); + return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index b322df57dc..87be55e661 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1230,11 +1230,11 @@ class SX127x: public PhysicalLayer { /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled - \param value A value between -127.5 and 0 inclusive + \param dbm A dBm value between -127.5 and 0 inclusive \returns \ref status_codes */ - int16_t setRSSIThreshold(float value); + int16_t setRSSIThreshold(float dbm); #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: From 40599baef1c70db2d992bb6a6394f822af3ac658 Mon Sep 17 00:00:00 2001 From: obones Date: Thu, 25 Aug 2022 10:39:21 +0200 Subject: [PATCH 0215/1848] Use the RADIOLIB_CHECK_RANGE macro along with proper lower value (it has to be negative) --- src/modules/RF69/RF69.cpp | 3 +-- src/modules/SX127x/SX127x.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 25818a4fd5..9867b5760e 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -873,8 +873,7 @@ float RF69::getRSSI() { } int16_t RF69::setRSSIThreshold(float dbm) { - if (dbm < 127.5 || dbm > 0) - return RADIOLIB_ERR_INVALID_RSSI_THRESHOLD; + RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 1adf22b894..6734b1b599 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1185,8 +1185,7 @@ int16_t SX127x::setCrcFiltering(bool crcOn) { } int16_t SX127x::setRSSIThreshold(float dbm) { - if (dbm < 127.5 || dbm > 0) - return RADIOLIB_ERR_INVALID_RSSI_THRESHOLD; + RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } From ffb2c15a501939a70cb9e14e038204eedfd4e7e8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Sep 2022 19:47:09 +0200 Subject: [PATCH 0216/1848] [SX127x] Definition fixes suggested by @MrSniffer --- src/modules/SX127x/SX127x.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 87be55e661..553a2fe92e 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -514,8 +514,8 @@ #define RADIOLIB_SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 #define RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 #define RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b01000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED 0b10000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED 0b00100000 // 5 4 #define RADIOLIB_SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 #define RADIOLIB_SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 #define RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 @@ -527,14 +527,14 @@ #define RADIOLIB_SX127X_DIO2_PACK_RX_READY 0b00000100 // 3 2 #define RADIOLIB_SX127X_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 #define RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 -#define RADIOLIB_SX127X_DIO3_LORA_CAD_DONE 0b00000000 // 0 1 -#define RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER 0b00000001 // 0 1 -#define RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 0 1 -#define RADIOLIB_SX127X_DIO3_CONT_TIMEOUT 0b00000000 // 0 1 -#define RADIOLIB_SX127X_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 0 1 -#define RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 0 1 -#define RADIOLIB_SX127X_DIO3_PACK_FIFO_EMPTY 0b00000000 // 0 1 -#define RADIOLIB_SX127X_DIO3_PACK_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX127X_DIO3_LORA_CAD_DONE 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER 0b00000001 // 1 0 +#define RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_TIMEOUT 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 1 0 +#define RADIOLIB_SX127X_DIO3_PACK_FIFO_EMPTY 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_PACK_TX_READY 0b00000001 // 1 0 // SX127X_REG_DIO_MAPPING_2 #define RADIOLIB_SX127X_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 From cb5fd16710d0fe52f999b38c94d1fa5d808cfe8c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 15:07:57 +0200 Subject: [PATCH 0217/1848] [SX127x] Added software timeout when using blocking receive without DIO1 (#566) --- src/modules/SX127x/SX127x.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6734b1b599..9488556533 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -208,13 +208,32 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { state = startReceive(len, RADIOLIB_SX127X_RXSINGLE); RADIOLIB_ASSERT(state); - // wait for packet reception or timeout (100 LoRa symbols) + // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout) + uint32_t timeout = 0; + if(_mod->getGpio() == RADIOLIB_NC) { + float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw; + timeout = 100*symbolLength; + } + + // wait for packet reception or timeout + uint32_t start = _mod->micros(); while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); - if(_mod->digitalRead(_mod->getGpio())) { - clearIRQFlags(); - return(RADIOLIB_ERR_RX_TIMEOUT); + + if(_mod->getGpio() != RADIOLIB_NC) { + // no GPIO pin provided, use software timeout + if(_mod->micros() - start > timeout) { + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } else { + // GPIO provided, use that + if(_mod->digitalRead(_mod->getGpio())) { + clearIRQFlags(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } } + } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { From e1d4c2094b1c58647367969ba9c026bf86fe20f8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 15:42:06 +0200 Subject: [PATCH 0218/1848] [SX127x] Fixed software timeout logic --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 9488556533..143ab2c02a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -220,7 +220,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { // no GPIO pin provided, use software timeout if(_mod->micros() - start > timeout) { clearIRQFlags(); From 9db64292c49368831a8f696a5e81be41407114b4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:10:54 +0200 Subject: [PATCH 0219/1848] [PHY] Added finishTransmit --- keywords.txt | 1 + src/protocols/PhysicalLayer/PhysicalLayer.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/keywords.txt b/keywords.txt index ce8ca0ae12..733a8b9b97 100644 --- a/keywords.txt +++ b/keywords.txt @@ -86,6 +86,7 @@ setDio1Action KEYWORD2 clearDio0Action KEYWORD2 clearDio1Action KEYWORD2 startTransmit KEYWORD2 +finishTransmit KEYWORD2 startReceive KEYWORD2 readData KEYWORD2 startChannelScan KEYWORD2 diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index efee97fb3f..687ac0a402 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -139,6 +139,13 @@ class PhysicalLayer { */ virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) = 0; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + virtual int16_t finishTransmit() = 0; + /*! \brief Reads data that was received after calling startReceive method. From 9dff4e709e203f89b7ce5fc4aa1b9c1bbeda5eda Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:12:03 +0200 Subject: [PATCH 0220/1848] [CC1101] Added finishTransmit --- .../CC1101_Transmit_Interrupt.ino | 5 ++++ src/modules/CC1101/CC1101.cpp | 26 ++++++++++--------- src/modules/CC1101/CC1101.h | 7 +++++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 1d993a7784..b09c455e85 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -112,6 +112,11 @@ void loop() { } + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + // wait a second before transmitting again delay(1000); diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index e9e367005a..a2e2eafecd 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -113,8 +113,7 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { _mod->yield(); if(_mod->micros() - start > timeout) { - standby(); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -125,19 +124,12 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { _mod->yield(); if(_mod->micros() - start > timeout) { - standby(); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - // set mode to standby - standby(); - - // flush Tx FIFO - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); - - return(state); + return(finishTransmit()); } int16_t CC1101::receive(uint8_t* data, size_t len) { @@ -328,6 +320,16 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return (state); } +int16_t CC1101::finishTransmit() { + // set mode to standby to disable transmitter/RF switch + int16_t state = standby(); + + // flush Tx FIFO + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + + return(state); +} + int16_t CC1101::startReceive() { // set mode to standby standby(); @@ -711,7 +713,7 @@ int16_t CC1101::setOOK(bool enableOOK) { return(setOutputPower(_power)); } -float CC1101::getRSSI() { +float CC1101::getRSSI() { float rssi; if (_directMode) { diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index a661107f9f..3ae99b63f1 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -656,6 +656,13 @@ class CC1101: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. From 0ae6eae4d91911f60d25c50ac50cf386bf79ee9d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:12:53 +0200 Subject: [PATCH 0221/1848] [SX126x] Added finishTransmit --- .../SX126x_Transmit_Interrupt.ino | 5 +++++ src/modules/SX126x/SX126x.cpp | 20 +++++++++---------- src/modules/SX126x/SX126x.h | 7 +++++++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index b4d441701d..0bd011c702 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -117,6 +117,11 @@ void loop() { } + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + // wait a second before transmitting again delay(1000); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 14868dd1e7..6f85b1c015 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -228,8 +228,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); if(_mod->micros() - start > timeout) { - clearIrqStatus(); - standby(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -238,14 +237,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { // update data rate _dataRate = (len*8.0)/((float)elapsed/1000000.0); - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // set mode to standby to disable transmitter - state = standby(); - - return(state); + return(finishTransmit()); } int16_t SX126x::receive(uint8_t* data, size_t len) { @@ -440,6 +432,14 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(state); } +int16_t SX126x::finishTransmit() { + // clear interrupt flags + clearIrqStatus(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + int16_t SX126x::startReceive(uint32_t timeout) { int16_t state = startReceiveCommon(timeout); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 0c42656619..afd04fb95f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -527,6 +527,13 @@ class SX126x: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. From 0d72dd2ac3d48f3a3b069c3490166aaab8fa3a3f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:13:39 +0200 Subject: [PATCH 0222/1848] [SX127x] Added finishTransmit (#571) --- .../SX127x_Transmit_Interrupt.ino | 8 +++---- src/modules/SX127x/SX127x.cpp | 21 +++++++++++-------- src/modules/SX127x/SX127x.h | 7 +++++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index f0fe3e8bbb..ec3f03a384 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -114,10 +114,10 @@ void loop() { } - // NOTE: in FSK mode, SX127x will not automatically - // turn transmitter off after sending a packet - // set mode to standby to ensure we don't jam others - //radio.standby() + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); // wait a second before transmitting again delay(1000); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 143ab2c02a..db16ff81e7 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -159,7 +159,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); if(_mod->micros() - start > timeout) { - clearIRQFlags(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -177,8 +177,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); if(_mod->micros() - start > timeout) { - clearIRQFlags(); - standby(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -189,12 +188,8 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // update data rate uint32_t elapsed = _mod->micros() - start; _dataRate = (len*8.0)/((float)elapsed/1000000.0); - - // clear interrupt flags - clearIRQFlags(); - - // set mode to standby to disable transmitter - return(standby()); + + return(finishTransmit()); } int16_t SX127x::receive(uint8_t* data, size_t len) { @@ -607,6 +602,14 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_NONE); } +int16_t SX127x::finishTransmit() { + // clear interrupt flags + clearIRQFlags(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + int16_t SX127x::readData(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 553a2fe92e..c960f2d205 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -800,6 +800,13 @@ class SX127x: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. From 733835e9bad3b11c8329a06a48f23350c2a2d5f3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:14:04 +0200 Subject: [PATCH 0223/1848] [Si443x] Added finishTransmit --- .../Si443x_Transmit_Interrupt.ino | 5 +++++ src/modules/Si443x/Si443x.cpp | 19 ++++++++++--------- src/modules/Si443x/Si443x.h | 7 +++++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 7f6877c693..317932fcd0 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -108,6 +108,11 @@ void loop() { } + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + // wait a second before transmitting again delay(1000); diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index fcd418765c..c498622f3b 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -87,19 +87,12 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { while(_mod->digitalRead(_mod->getIrq())) { _mod->yield(); if(_mod->micros() - start > timeout) { - standby(); - clearIRQFlags(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - // clear interrupt flags - clearIRQFlags(); - - // set mode to standby - standby(); - - return(state); + return(finishTransmit()); } int16_t Si443x::receive(uint8_t* data, size_t len) { @@ -258,6 +251,14 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(state); } +int16_t Si443x::finishTransmit() { + // clear interrupt flags + clearIRQFlags(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + int16_t Si443x::startReceive() { // set mode to standby int16_t state = standby(); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 2175be7c56..1ee97a1210 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -683,6 +683,13 @@ class Si443x: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received. From 598982c78229efa3b78e6cc19a483f6eac1da66e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:14:19 +0200 Subject: [PATCH 0224/1848] [nRF24] Added finishTransmit --- .../nRF24_Transmit_Interrupt.ino | 5 +++++ src/modules/nRF24/nRF24.cpp | 21 +++++++++++-------- src/modules/nRF24/nRF24.h | 7 +++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 14d0c0723f..95cba472c3 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -127,6 +127,11 @@ void loop() { } + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + // wait a second before transmitting again delay(1000); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 3b90ba702c..5ac59810ae 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -93,23 +93,18 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { // check maximum number of retransmits if(getStatus(RADIOLIB_NRF24_MAX_RT)) { - standby(); - clearIRQ(); + finishTransmit(); return(RADIOLIB_ERR_ACK_NOT_RECEIVED); } // check timeout: 15 retries * 4ms (max Tx time as per datasheet) if(_mod->micros() - start >= 60000) { - standby(); - clearIRQ(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - - // clear interrupts - clearIRQ(); - - return(state); + + return(finishTransmit()); } int16_t nRF24::receive(uint8_t* data, size_t len) { @@ -199,6 +194,14 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(state); } +int16_t nRF24::finishTransmit() { + // clear interrupt flags + clearIRQ(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + int16_t nRF24::startReceive() { // set mode to standby int16_t state = standby(); diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 8b6226dc31..26f8393afc 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -289,6 +289,13 @@ class nRF24: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. IRQ will be activated when full packet is received. From 8a81a7c8279c2205d5cd4a2655238fc83f26f55f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:14:42 +0200 Subject: [PATCH 0225/1848] [RF69] Added finishTransmit --- .../RF69_Transmit_Interrupt.ino | 5 +++++ src/modules/RF69/RF69.cpp | 21 ++++++++++--------- src/modules/RF69/RF69.h | 7 +++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 6ae3fa1c77..214474f9c2 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -128,6 +128,11 @@ void loop() { } + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + // wait a second before transmitting again delay(1000); diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 9867b5760e..699bf16d16 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -125,19 +125,12 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { _mod->yield(); if(_mod->micros() - start > timeout) { - standby(); - clearIRQFlags(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - - // set mode to standby - standby(); - - // clear interrupt flags - clearIRQFlags(); - - return(RADIOLIB_ERR_NONE); + + return(finishTransmit()); } int16_t RF69::receive(uint8_t* data, size_t len) { @@ -442,6 +435,14 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(state); } +int16_t RF69::finishTransmit() { + // clear interrupt flags + clearIRQFlags(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + int16_t RF69::readData(uint8_t* data, size_t len) { // set mode to standby int16_t state = standby(); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index e1d3acf774..9233f57aff 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -684,6 +684,13 @@ class RF69: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. From 0b5cd51828d2bf4846bca9ba6a8df5b2e4532459 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:15:07 +0200 Subject: [PATCH 0226/1848] [SX128x] Added finishTransmit --- .../SX128x_Transmit_Interrupt.ino | 5 +++++ src/modules/SX128x/SX128x.cpp | 20 +++++++++---------- src/modules/SX128x/SX128x.h | 7 +++++++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 55d44faa4c..e8d78941c5 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -110,6 +110,11 @@ void loop() { } + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + // wait a second before transmitting again delay(1000); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index d61ce930f6..d147d738c0 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -300,20 +300,12 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); if(_mod->micros() - start > timeout) { - clearIrqStatus(); - standby(); + finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // set mode to standby to disable transmitter - state = standby(); - - return(state); + return(finishTransmit()); } int16_t SX128x::receive(uint8_t* data, size_t len) { @@ -522,6 +514,14 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(state); } +int16_t SX128x::finishTransmit() { + // clear interrupt flags + clearIrqStatus(); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + int16_t SX128x::startReceive(uint16_t timeout) { // check active modem if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 6e1a7894d3..3603b29d45 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -553,6 +553,13 @@ class SX128x: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Clean up after transmission is done. + + \returns \ref status_codes + */ + int16_t finishTransmit() override; + /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. From a1aa52cbea10b7247f0b66b832381ba1146199af Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:18:56 +0200 Subject: [PATCH 0227/1848] [PHY] Suppress unused arguments --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 71185909c9..e0fad08d21 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -252,5 +252,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { #endif int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { + (void)pin; + (void)value; return(RADIOLIB_ERR_UNSUPPORTED); } From 2980d8dbf188ebf44d835ba8138663c0b1b3c338 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Sep 2022 16:20:16 +0200 Subject: [PATCH 0228/1848] [MOD] Fixed signed/unsigned comparison warning --- src/Module.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index c81d73029c..72e5d9964a 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -489,29 +489,29 @@ uint16_t Module::flipBits16(uint16_t i) { void Module::hexdump(uint8_t* data, size_t len) { size_t rem_len = len; - for(int i = 0; i < len; i+=16) { + for(size_t i = 0; i < len; i+=16) { char str[80]; sprintf(str, "%07x ", i); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; } - for(int j = 0; j < line_len; j++) { + for(size_t j = 0; j < line_len; j++) { sprintf(&str[8 + j*3], "%02x ", data[i+j]); } - for(int j = line_len; j < 16; j++) { + for(size_t j = line_len; j < 16; j++) { sprintf(&str[8 + j*3], " "); } str[56] = '|'; str[57] = ' '; - for(int j = 0; j < line_len; j++) { + for(size_t j = 0; j < line_len; j++) { char c = data[i+j]; if((c < ' ') || (c > '~')) { c = '.'; } sprintf(&str[58 + j], "%c", c); } - for(int j = line_len; j < 16; j++) { + for(size_t j = line_len; j < 16; j++) { sprintf(&str[58 + j], " "); } RADIOLIB_DEBUG_PRINTLN(str); From 1f75ee0cc176fd5558ac5f259ed236c30cdc67b1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 14:56:37 +0200 Subject: [PATCH 0229/1848] [Pager] Implemented POCSAG (#7) --- .../Pager/Pager_Receive/Pager_Receive.ino | 121 +++ .../Pager/Pager_Transmit/Pager_Transmit.ino | 102 +++ keywords.txt | 7 + src/RadioLib.h | 1 + src/TypeDef.h | 12 + src/protocols/Pager/Pager.cpp | 708 ++++++++++++++++++ src/protocols/Pager/Pager.h | 216 ++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 19 + 8 files changed, 1186 insertions(+) create mode 100644 examples/Pager/Pager_Receive/Pager_Receive.ino create mode 100644 examples/Pager/Pager_Transmit/Pager_Transmit.ino create mode 100644 src/protocols/Pager/Pager.cpp create mode 100644 src/protocols/Pager/Pager.h diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino new file mode 100644 index 0000000000..8497a9ae6e --- /dev/null +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -0,0 +1,121 @@ +/* + RadioLib Pager (POCSAG) Receive Example + + This example shows how to receive FSK packets without using + SX127x packet engine. + + This example receives POCSAG messages using SX1278's + FSK modem in direct mode. + + Other modules that can be used to receive POCSAG: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(5, 2, 9, 3); + +// DIO2 pin: 5 +const int pin = 4; + +// create Pager client instance using the FSK module +PagerClient pager(&radio); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initalize Pager client + Serial.print(F("[Pager] Initializing ... ")); + // base (center) frequency: 434.0 MHz + // speed: 1200 bps + state = pager.begin(434.0, 1200); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // start receiving POCSAG messages + Serial.print(F("[Pager] Starting to listen ... ")); + // address of this "pager": 1234567 + state = pager.startReceive(pin, 1234567); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + +} + +void loop() { + // the number of batches to wait for + // 2 batches will usually be enough to fit short and medium messages + if (pager.available() >= 2) { + Serial.print(F("[Pager] Received pager data, decoding ... ")); + + // you can read the data as an Arduino String + String str; + int state = pager.readData(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + size_t numBytes = 0; + int state = radio.receive(byteArr, &numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print the received data + Serial.print(F("[Pager] Data:\t")); + Serial.println(str); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} diff --git a/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/examples/Pager/Pager_Transmit/Pager_Transmit.ino new file mode 100644 index 0000000000..0b3dae58c8 --- /dev/null +++ b/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -0,0 +1,102 @@ +/* + RadioLib Pager (POCSAG) Transmit Example + + This example sends POCSAG messages using SX1278's + FSK modem. + + Other modules that can be used to send POCSAG: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(5, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create Pager client instance using the FSK module +PagerClient pager(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initalize Pager client + Serial.print(F("[Pager] Initializing ... ")); + // base (center) frequency: 434.0 MHz + // speed: 1200 bps + state = pager.begin(434.0, 1200); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Pager] Transmitting messages ... ")); + + // the simples form of "message" is just a tone on the destination pager + int state = pager.sendTone(1234567); + delay(500); + + // next, transmit numeric (BCD) message to the destination pager + // NOTE: Only characters 0123456789*U-() and space + // can be sent in a BCD message! + state |= pager.transmit("0123456789*U -()", 1234567); + delay(500); + + // finally, let's transmit an ASCII message now + state |= pager.transmit("Hello World!", 1234567, RADIOLIB_PAGER_ASCII); + delay(500); + + // we can also send only a tone + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait for a second before transmitting again + delay(3000); +} diff --git a/keywords.txt b/keywords.txt index 733a8b9b97..cd5c8d0697 100644 --- a/keywords.txt +++ b/keywords.txt @@ -49,6 +49,7 @@ HellClient KEYWORD1 AFSKClient KEYWORD1 FSK4Client KEYWORD1 APRSClient KEYWORD1 +PagerClient KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -239,6 +240,9 @@ noTone KEYWORD2 sendPosition KEYWORD2 sendMicE KEYWORD2 +# Pager +sendTone KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### @@ -330,3 +334,6 @@ RADIOLIB_ERR_INVALID_NUM_REPEATERS LITERAL1 RADIOLIB_ERR_INVALID_REPEATER_CALLSIGN LITERAL1 RADIOLIB_ERR_RANGING_TIMEOUT LITERAL1 + +RADIOLIB_ERR_INVALID_PAYLOAD LITERAL1 +RADIOLIB_ERR_ADDRESS_NOT_FOUND LITERAL1 diff --git a/src/RadioLib.h b/src/RadioLib.h index 0d202699bd..50e2fc7f34 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -87,6 +87,7 @@ #include "protocols/AX25/AX25.h" #include "protocols/Hellschreiber/Hellschreiber.h" #include "protocols/Morse/Morse.h" +#include "protocols/Pager/Pager.h" #include "protocols/RTTY/RTTY.h" #include "protocols/SSTV/SSTV.h" #include "protocols/FSK4/FSK4.h" diff --git a/src/TypeDef.h b/src/TypeDef.h index 49a29f785f..0d250d5097 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -405,6 +405,18 @@ */ #define RADIOLIB_ERR_RANGING_TIMEOUT (-901) +// Pager-specific status codes + +/*! + \brief The provided payload data configuration is invalid. +*/ +#define RADIOLIB_ERR_INVALID_PAYLOAD (-1001) + +/*! + \brief The requested address was not found in the received data. +*/ +#define RADIOLIB_ERR_ADDRESS_NOT_FOUND (-1002) + /*! \} */ diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp new file mode 100644 index 0000000000..f75df51328 --- /dev/null +++ b/src/protocols/Pager/Pager.cpp @@ -0,0 +1,708 @@ +#include "Pager.h" + +// this is a massive hack, but we need a global-scope ISR to manage the bit reading +// let's hope nobody ever tries running two POCSAG receivers at the same time +static PhysicalLayer* _readBitInstance = NULL; +static RADIOLIB_PIN_TYPE _readBitPin = RADIOLIB_NC; +static void PagerClientReadBit(void) { + if(_readBitInstance) { + _readBitInstance->readBit(_readBitPin); + } +} + +PagerClient::PagerClient(PhysicalLayer* phy) { + _phy = phy; + _readBitInstance = _phy; +} + +int16_t PagerClient::begin(float base, uint16_t speed) { + // calculate duration of 1 bit in us + _speed = (float)speed/1000.0f; + _bitDuration = (uint32_t)1000000/speed; + + // calculate 24-bit frequency + _base = base; + _baseRaw = (_base * 1000000.0) / _phy->getFreqStep(); + + // calculate module carrier frequency resolution + uint16_t step = round(_phy->getFreqStep()); + + // calculate raw frequency shift + _shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ/step; + + // initialize BCH encoder + encoderInit(); + + // configure for direct mode + return(_phy->startDirect()); +} + +int16_t PagerClient::sendTone(uint32_t addr) { + return(PagerClient::transmit(NULL, 0, addr)); +} + +int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding) { + return(PagerClient::transmit(str.c_str(), addr, encoding)); +} + +int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding) { + return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding)); +} + +int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding) { + if(addr > RADIOLIB_PAGER_ADDRESS_MAX) { + return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); + } + + if(((data == NULL) && (len > 0)) || ((data != NULL) && (len == 0))) { + return(RADIOLIB_ERR_INVALID_PAYLOAD); + } + + // get symbol bit length based on encoding + uint8_t symbolLength = 0; + uint32_t function = 0; + if(encoding == RADIOLIB_PAGER_BCD) { + symbolLength = 4; + function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; + + } else if(encoding == RADIOLIB_PAGER_ASCII) { + symbolLength = 7; + function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; + + } else { + return(RADIOLIB_ERR_INVALID_ENCODING); + + } + + if(len == 0) { + function = RADIOLIB_PAGER_FUNC_BITS_TONE; + } + + // get target position in batch (3 LSB from address determine frame position in batch) + uint8_t framePos = 2*(addr & 0x07); + + // get address that will be written into address frame + uint32_t frameAddr = ((addr >> 3) << RADIOLIB_PAGER_ADDRESS_POS) | function; + + // calculate the number of 20-bit data blocks + size_t numDataBlocks = (len * symbolLength) / RADIOLIB_PAGER_MESSAGE_BITS_LENGTH; + if((len * symbolLength) % RADIOLIB_PAGER_MESSAGE_BITS_LENGTH > 0) { + numDataBlocks += 1; + } + + // calculate number of batches + size_t numBatches = (1 + framePos + numDataBlocks) / RADIOLIB_PAGER_BATCH_LEN + 1; + if((1 + numDataBlocks) % RADIOLIB_PAGER_BATCH_LEN == 0) { + numBatches -= 1; + } + + // calculate message length in 32-bit code words + size_t msgLen = RADIOLIB_PAGER_PREAMBLE_LENGTH + (1 + RADIOLIB_PAGER_BATCH_LEN) * numBatches; + + #if defined(RADIOLIB_STATIC_ONLY) + uint32_t msg[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint32_t* msg = new uint32_t[msgLen]; + #endif + + // build the message + memset(msg, 0x00, msgLen*sizeof(uint32_t)); + + // set preamble + for(size_t i = 0; i < RADIOLIB_PAGER_PREAMBLE_LENGTH; i++) { + msg[i] = RADIOLIB_PAGER_PREAMBLE_CODE_WORD; + } + + // start by setting everything after preamble to idle + for(size_t i = RADIOLIB_PAGER_PREAMBLE_LENGTH; i < msgLen; i++) { + msg[i] = RADIOLIB_PAGER_IDLE_CODE_WORD; + } + + // set frame synchronization code words + for(size_t i = 0; i < numBatches; i++) { + msg[RADIOLIB_PAGER_PREAMBLE_LENGTH + i*(1 + RADIOLIB_PAGER_BATCH_LEN)] = RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD; + } + + // write address code word + msg[RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos] = encodeBCH(frameAddr); + + // write the data as 20-bit code blocks + if(len > 0) { + int8_t remBits = 0; + uint8_t dataPos = 0; + for(uint8_t i = 0; i < numDataBlocks + numBatches - 1; i++) { + uint8_t blockPos = RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos + 1 + i; + + // check if we need to skip a frame sync marker + if(((blockPos - (RADIOLIB_PAGER_PREAMBLE_LENGTH + 1)) % RADIOLIB_PAGER_BATCH_LEN) == 0) { + blockPos++; + i++; + } + + // mark this as a message code word + msg[blockPos] = RADIOLIB_PAGER_MESSAGE_CODE_WORD << (RADIOLIB_PAGER_CODE_WORD_LEN - 1); + + // first insert the remainder from previous code word (if any) + if(remBits > 0) { + // this doesn't apply to BCD messages, so no need to check that here + uint8_t prev = Module::flipBits(data[dataPos - 1]); + prev >>= 1; + msg[blockPos] |= (uint32_t)prev << (RADIOLIB_PAGER_CODE_WORD_LEN - 1 - remBits); + } + + // set all message symbols until we overflow to the next code word or run out of message symbols + int8_t symbolPos = RADIOLIB_PAGER_CODE_WORD_LEN - 1 - symbolLength - remBits; + while(symbolPos > (RADIOLIB_PAGER_FUNC_BITS_POS - symbolLength)) { + + // for BCD, encode the symbol + uint8_t symbol = data[dataPos++]; + if(encoding == RADIOLIB_PAGER_BCD) { + symbol = encodeBCD(symbol); + } + symbol = Module::flipBits(symbol); + symbol >>= (8 - symbolLength); + + // insert the next message symbol + msg[blockPos] |= (uint32_t)symbol << symbolPos; + symbolPos -= symbolLength; + + // check if we ran out of message symbols + if(dataPos >= len) { + // in BCD mode, pad the rest of the code word with spaces (0xC) + if(encoding == RADIOLIB_PAGER_BCD) { + uint8_t numSteps = (symbolPos - RADIOLIB_PAGER_FUNC_BITS_POS + symbolLength)/symbolLength; + for(uint8_t i = 0; i < numSteps; i++) { + symbol = encodeBCD(' '); + symbol = Module::flipBits(symbol); + symbol >>= (8 - symbolLength); + msg[blockPos] |= (uint32_t)symbol << symbolPos; + symbolPos -= symbolLength; + } + } + break; + } + } + + // ensure the parity bits are not set due to overflow + msg[blockPos] &= ~(RADIOLIB_PAGER_BCH_BITS_MASK); + + // save the number of overflown bits + remBits = RADIOLIB_PAGER_FUNC_BITS_POS - symbolPos - symbolLength; + + // do the FEC + msg[blockPos] = encodeBCH(msg[blockPos]); + } + } + + // transmit the message + PagerClient::write(msg, msgLen); + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] msg; + #endif + + // turn transmitter off + _phy->standby(); + + return(RADIOLIB_ERR_NONE); +} + +int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t mask) { + // save the variables + _readBitPin = pin; + _filterAddr = addr; + _filterMask = mask; + + // set the carrier frequency + int16_t state = _phy->setFrequency(_base); + RADIOLIB_ASSERT(state); + + // set bitrate + state = _phy->setBitRate(_speed); + RADIOLIB_ASSERT(state); + + // set frequency deviation to 4.5 khz + state = _phy->setFrequencyDeviation((float)RADIOLIB_PAGER_FREQ_SHIFT_HZ / 1000.0f); + RADIOLIB_ASSERT(state); + + // now set up the direct mode reception + _phy->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + _phy->setDirectAction(PagerClientReadBit); + _phy->receiveDirect(); + + return(state); +} + +size_t PagerClient::available() { + return(_phy->available() + sizeof(uint32_t))/(sizeof(uint32_t) * (RADIOLIB_PAGER_BATCH_LEN + 1)); +} + +int16_t PagerClient::readData(String& str, size_t len) { + int16_t state = RADIOLIB_ERR_NONE; + + // determine the message length, based on user input or the amount of received data + size_t length = len; + if(length == 0) { + // one batch can contain at most 80 message symbols + length = available()*80; + } + + // build a temporary buffer + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; + #else + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + #endif + + // read the received data + state = readData(data, &length); + + if(state == RADIOLIB_ERR_NONE) { + // check tone-only tramsissions + if(length == 0) { + length = 6; + strncpy((char*)data, "", length); + } + + // add null terminator + data[length] = 0; + + // initialize Arduino String class + str = String((char*)data); + } + + // deallocate temporary buffer + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] data; + #endif + + return(state); +} + +int16_t PagerClient::readData(uint8_t* data, size_t* len) { + // find the correct address + bool match = false; + uint8_t framePos = 0; + uint8_t symbolLength = 0; + while(!match && _phy->available()) { + uint32_t cw = read(); + framePos++; + + // check if it's the idle code word + if(cw == RADIOLIB_PAGER_IDLE_CODE_WORD) { + continue; + } + + // check if it's the sync word + if(cw == RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD) { + framePos = 0; + continue; + } + + // not an idle code word, check if it's an address word + if(cw & (RADIOLIB_PAGER_MESSAGE_CODE_WORD << (RADIOLIB_PAGER_CODE_WORD_LEN - 1))) { + // this is pretty weird, it seems to be a message code word without address + continue; + } + + // should be an address code word, extract the address + uint32_t addr = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); + if((addr & _filterMask) == (_filterAddr & _filterMask)) { + // we have a match! + match = true; + + // determine the encoding from the function bits + if((cw & RADIOLIB_PAGER_FUNCTION_BITS_MASK) == RADIOLIB_PAGER_FUNC_BITS_NUMERIC) { + symbolLength = 4; + } else { + symbolLength = 7; + } + } + } + + if(!match) { + // address not found + return(RADIOLIB_ERR_ADDRESS_NOT_FOUND); + } + + // we have the address, start pulling out the message + bool complete = false; + size_t decodedBytes = 0; + uint32_t prevCw = 0; + bool overflow = false; + int8_t ovfBits = 0; + while(!complete && _phy->available()) { + uint32_t cw = read(); + + // check if it's the idle code word + if(cw == RADIOLIB_PAGER_IDLE_CODE_WORD) { + complete = true; + break; + } + + // skip the sync words + if(cw == RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD) { + continue; + } + + // check overflow from previous code word + uint8_t bitPos = RADIOLIB_PAGER_CODE_WORD_LEN - 1 - symbolLength; + if(overflow) { + overflow = false; + + // this is a bit convoluted - first, build masks for both previous and current code word + uint8_t currPos = RADIOLIB_PAGER_CODE_WORD_LEN - 1 - symbolLength + ovfBits; + uint8_t prevPos = RADIOLIB_PAGER_MESSAGE_END_POS; + uint32_t prevMask = (0x7FUL << prevPos) & ~((uint32_t)0x7FUL << (RADIOLIB_PAGER_MESSAGE_END_POS + ovfBits)); + uint32_t currMask = (0x7FUL << currPos) & ~((uint32_t)1 << (RADIOLIB_PAGER_CODE_WORD_LEN - 1)); + + // next, get the two parts of the message symbol and stick them together + uint8_t prevSymbol = (prevCw & prevMask) >> prevPos; + uint8_t currSymbol = (cw & currMask) >> currPos; + uint32_t symbol = prevSymbol << (symbolLength - ovfBits) | currSymbol; + + // finally, we can flip the bits + symbol = Module::flipBits((uint8_t)symbol); + symbol >>= (8 - symbolLength); + + // decode BCD and we're done + if(symbolLength == 4) { + symbol = decodeBCD(symbol); + } + data[decodedBytes++] = symbol; + + // adjust the bit position of the next message symbol + bitPos += ovfBits; + bitPos -= symbolLength; + } + + // get the message symbols based on the encoding type + while(bitPos >= RADIOLIB_PAGER_MESSAGE_END_POS) { + // get the message symbol from the code word and reverse bits + uint32_t symbol = (cw & (0x7FUL << bitPos)) >> bitPos; + symbol = Module::flipBits((uint8_t)symbol); + symbol >>= (8 - symbolLength); + + // decode BCD if needed + if(symbolLength == 4) { + symbol = decodeBCD(symbol); + } + data[decodedBytes++] = symbol; + + // now calculate if the next symbol is overflowing to the following code word + int8_t remBits = bitPos - RADIOLIB_PAGER_MESSAGE_END_POS; + if(remBits < symbolLength) { + // overflow! + prevCw = cw; + overflow = true; + ovfBits = remBits; + } + bitPos -= symbolLength; + } + + } + + // save the number of decoded bytes + *len = decodedBytes; + return(RADIOLIB_ERR_NONE); +} + +void PagerClient::write(uint32_t* data, size_t len) { + // write code words from buffer + for(size_t i = 0; i < len; i++) { + PagerClient::write(data[i]); + } +} + +void PagerClient::write(uint32_t codeWord) { + // write single code word + Module* mod = _phy->getMod(); + for(int8_t i = 31; i >= 0; i--) { + uint32_t mask = (uint32_t)0x01 << i; + if(codeWord & mask) { + // send 1 + uint32_t start = mod->micros(); + _phy->transmitDirect(_baseRaw + _shift); + while(mod->micros() - start < _bitDuration); + } else { + // send 0 + uint32_t start = mod->micros(); + _phy->transmitDirect(_baseRaw - _shift); + while(mod->micros() - start < _bitDuration); + } + } +} + +uint32_t PagerClient::read() { + uint32_t codeWord = 0; + codeWord |= (uint32_t)_phy->read() << 24; + codeWord |= (uint32_t)_phy->read() << 16; + codeWord |= (uint32_t)_phy->read() << 8; + codeWord |= (uint32_t)_phy->read(); + + // TODO BCH error correction here + return(codeWord); +} + +uint8_t PagerClient::encodeBCD(char c) { + switch(c) { + case '*': + return(0x0A); + case 'U': + return(0x0B); + case ' ': + return(0x0C); + case '-': + return(0x0D); + case ')': + return(0x0E); + case '(': + return(0x0F); + } + return(c - '0'); +} + +char PagerClient::decodeBCD(uint8_t b) { + switch(b) { + case 0x0A: + return('*'); + case 0x0B: + return('U'); + case 0x0C: + return(' '); + case 0x0D: + return('-'); + case 0x0E: + return(')'); + case 0x0F: + return('('); + } + return(b + '0'); +} + +/* + BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder + + Significantly cleaned up and slightly fixed. +*/ +void PagerClient::encoderInit() { + /* + * generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + * lookup tables: index->polynomial form _bchAlphaTo[] contains j=alpha**i; + * polynomial form -> index form _bchIndexOf[j=alpha**i] = i alpha=2 is the + * primitive element of GF(2**m) + */ + + int32_t mask = 1; + _bchAlphaTo[RADIOLIB_PAGER_BCH_M] = 0; + + for(uint8_t i = 0; i < RADIOLIB_PAGER_BCH_M; i++) { + _bchAlphaTo[i] = mask; + + _bchIndexOf[_bchAlphaTo[i]] = i; + + if(RADIOLIB_PAGER_BCH_PRIMITIVE_POLY & ((uint32_t)0x01 << i)) { + _bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^= mask; + } + + mask <<= 1; + } + + _bchIndexOf[_bchAlphaTo[RADIOLIB_PAGER_BCH_M]] = RADIOLIB_PAGER_BCH_M; + mask >>= 1; + + for(uint8_t i = RADIOLIB_PAGER_BCH_M + 1; i < RADIOLIB_PAGER_BCH_N; i++) { + if(_bchAlphaTo[i - 1] >= mask) { + _bchAlphaTo[i] = _bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^ ((_bchAlphaTo[i - 1] ^ mask) << 1); + } else { + _bchAlphaTo[i] = _bchAlphaTo[i - 1] << 1; + } + + _bchIndexOf[_bchAlphaTo[i]] = i; + } + + _bchIndexOf[0] = -1; + + /* + * Compute generator polynomial of BCH code of length = 31, redundancy = 10 + * (OK, this is not very efficient, but we only do it once, right? :) + */ + + int32_t ii = 0; + int32_t jj = 1; + int32_t ll = 0; + int32_t kaux = 0; + bool test = false; + int32_t aux = 0; + int32_t cycle[15][6] = { { 0 } }; + int32_t size[15] = { 0 }; + + // Generate cycle sets modulo 31 + cycle[0][0] = 0; size[0] = 1; + cycle[1][0] = 1; size[1] = 1; + + do { + // Generate the jj-th cycle set + ii = 0; + do { + ii++; + cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % RADIOLIB_PAGER_BCH_N; + size[jj]++; + aux = (cycle[jj][ii] * 2) % RADIOLIB_PAGER_BCH_N; + } while(aux != cycle[jj][0]); + + // Next cycle set representative + ll = 0; + do { + ll++; + test = false; + for(ii = 1; ((ii <= jj) && !test); ii++) { + // Examine previous cycle sets + for(kaux = 0; ((kaux < size[ii]) && !test); kaux++) { + test = (ll == cycle[ii][kaux]); + } + } + } while(test && (ll < (RADIOLIB_PAGER_BCH_N - 1))); + + if(!test) { + jj++; // next cycle set index + cycle[jj][0] = ll; + size[jj] = 1; + } + + } while(ll < (RADIOLIB_PAGER_BCH_N - 1)); + + // Search for roots 1, 2, ..., d-1 in cycle sets + int32_t rdncy = 0; + int32_t min[11]; + kaux = 0; + + for(ii = 1; ii <= jj; ii++) { + min[kaux] = 0; + for(jj = 0; jj < size[ii]; jj++) { + for(uint8_t root = 1; root < RADIOLIB_PAGER_BCH_D; root++) { + if(root == cycle[ii][jj]) { + min[kaux] = ii; + } + } + } + + if(min[kaux]) { + rdncy += size[min[kaux]]; + kaux++; + } + } + + int32_t noterms = kaux; + int32_t zeros[11]; + kaux = 1; + + for(ii = 0; ii < noterms; ii++) { + for(jj = 0; jj < size[min[ii]]; jj++) { + zeros[kaux] = cycle[min[ii]][jj]; + kaux++; + } + } + + // Compute generator polynomial + _bchG[0] = _bchAlphaTo[zeros[1]]; + _bchG[1] = 1; // g(x) = (X + zeros[1]) initially + + for(ii = 2; ii <= rdncy; ii++) { + _bchG[ii] = 1; + for(jj = ii - 1; jj > 0; jj--) { + if(_bchG[jj] != 0) { + _bchG[jj] = _bchG[jj - 1] ^ _bchAlphaTo[(_bchIndexOf[_bchG[jj]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; + } else { + _bchG[jj] = _bchG[jj - 1]; + } + } + _bchG[0] = _bchAlphaTo[(_bchIndexOf[_bchG[0]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; + } +} + +/* + BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder + + Significantly cleaned up and slightly fixed. +*/ +uint32_t PagerClient::encodeBCH(uint32_t dat) { + // we only use the 21 most significant bits + int32_t data[21]; + int32_t j1 = 0; + for(int32_t i = 31; i > 10; i--) { + if(dat & ((uint32_t)1< start-2; --i) { + if(Mr[start]) { + Mr[i] ^= _bchG[j]; + ++j; + } else { + ++start; + j = 0; + end = start + RADIOLIB_PAGER_BCH_N - RADIOLIB_PAGER_BCH_K; + break; + } + } + } + + int32_t bb[11]; + j = 0; + for(int32_t i = start; i < end; ++i) { + bb[j] = Mr[i]; + ++j; + } + + int32_t iEvenParity = 0; + int32_t recd[32]; + for(uint8_t i = 0; i < 21; i++) { + recd[31 - i] = data[i]; + if(data[i] == 1) { + iEvenParity++; + } + } + + for(uint8_t i = 0; i < 11; i++) { + recd[10 - i] = bb[i]; + if(bb[i] == 1) { + iEvenParity++; + } + } + + if((iEvenParity % 2) == 0) { + recd[0] = 0; + } else { + recd[0] = 1; + } + + int32_t Codeword[32]; + memcpy(Codeword, recd, sizeof(int32_t)*32); + + int32_t iResult = 0; + for(int32_t i = 0; i < 32; i++) { + if(Codeword[i]) { + iResult |= ((uint32_t)1< Date: Sat, 1 Oct 2022 15:06:09 +0200 Subject: [PATCH 0230/1848] [SX126x] Added missing setFrequency implementation for PhysicalLayer --- src/modules/SX126x/SX1262.cpp | 4 ++++ src/modules/SX126x/SX1262.h | 11 ++++++++++- src/modules/SX126x/SX1268.cpp | 4 ++++ src/modules/SX126x/SX1268.h | 11 ++++++++++- src/protocols/PhysicalLayer/PhysicalLayer.h | 7 +++---- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index fcfbb2b07b..076f2a7712 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -47,6 +47,10 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1262::setFrequency(float freq) { + return(setFrequency(freq, true)); +} + int16_t SX1262::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 6d3f0258ab..c33eaba900 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -75,6 +75,15 @@ class SX1262: public SX126x { // configuration methods + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + + \param freq Carrier frequency to be set in MHz. + + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. @@ -84,7 +93,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate = true); + int16_t setFrequency(float freq, bool calibrate); /*! \brief Sets output power. Allowed values are in range from -17 to 22 dBm. diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index fb6a95e0c9..30592bd6bd 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -47,6 +47,10 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1268::setFrequency(float freq) { + return(setFrequency(freq, true)); +} + /// \todo integers only (all modules - frequency, data rate, bandwidth etc.) int16_t SX1268::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index d58ca540e2..7b454baca2 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -75,6 +75,15 @@ class SX1268: public SX126x { // configuration methods + /*! + \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. + + \param freq Carrier frequency to be set in MHz. + + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + /*! \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. @@ -84,7 +93,7 @@ class SX1268: public SX126x { \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate = true); + int16_t setFrequency(float freq, bool calibrate); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index b280b3abdb..a8b011f7e3 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -191,7 +191,7 @@ class PhysicalLayer { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz. + \brief Sets carrier frequency. Must be implemented in module class. \param freq Carrier frequency to be set in MHz. @@ -200,7 +200,7 @@ class PhysicalLayer { virtual int16_t setFrequency(float freq) = 0; /*! - \brief Sets FSK bit rate. Allowed values range from 1.2 to 300 kbps. Only available in FSK mode. + \brief Sets FSK bit rate. Only available in FSK mode. Must be implemented in module class. \param br Bit rate to be set (in kbps). @@ -209,8 +209,7 @@ class PhysicalLayer { virtual int16_t setBitRate(float br) = 0; /*! - \brief Sets FSK frequency deviation from carrier frequency. Allowed values depend on bit rate setting and must be lower than 200 kHz. - Only available in FSK mode. Must be implemented in module class. + \brief Sets FSK frequency deviation from carrier frequency. Only available in FSK mode. Must be implemented in module class. \param freqDev Frequency deviation to be set (in kHz). From e5fe82f33427a44d3dc1298264d7fc9a5bd46876 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 15:16:01 +0200 Subject: [PATCH 0231/1848] [SX128x] Fixed setBitRate compatibility with PhysicalLayer --- src/modules/SX128x/SX128x.cpp | 34 +++++++++++++++++----------------- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index d147d738c0..39df762814 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -746,56 +746,56 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { return(RADIOLIB_ERR_WRONG_MODEM); } -int16_t SX128x::setBitRate(uint16_t br) { +int16_t SX128x::setBitRate(float br) { // check active modem uint8_t modem = getPacketType(); // GFSK/BLE if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { - if(br == 125) { + if((uint16_t)br == 125) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; - } else if(br == 250) { + } else if((uint16_t)br == 250) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6; - } else if(br == 400) { + } else if((uint16_t)br == 400) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2; - } else if(br == 500) { + } else if((uint16_t)br == 500) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2; - } else if(br == 800) { + } else if((uint16_t)br == 800) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; - } else if(br == 1000) { + } else if((uint16_t)br == 1000) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4; - } else if(br == 1600) { + } else if((uint16_t)br == 1600) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4; - } else if(br == 2000) { + } else if((uint16_t)br == 2000) { _br = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4; } else { return(RADIOLIB_ERR_INVALID_BIT_RATE); } // update modulation parameters - _brKbps = br; + _brKbps = (uint16_t)br; return(setModulationParams(_br, _modIndex, _shaping)); // FLRC } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { - if(br == 260) { + if((uint16_t)br == 260) { _br = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3; - } else if(br == 325) { + } else if((uint16_t)br == 325) { _br = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3; - } else if(br == 520) { + } else if((uint16_t)br == 520) { _br = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6; - } else if(br == 650) { + } else if((uint16_t)br == 650) { _br = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; - } else if(br == 1000) { + } else if((uint16_t)br == 1000) { _br = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2; - } else if(br == 1300) { + } else if((uint16_t)br == 1300) { _br = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2; } else { return(RADIOLIB_ERR_INVALID_BIT_RATE); } // update modulation parameters - _brKbps = br; + _brKbps = (uint16_t)br; return(setModulationParams(_br, _crFLRC, _shaping)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 3603b29d45..e25bf3bb34 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -646,7 +646,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setBitRate(uint16_t br); + int16_t setBitRate(float br); /*! \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 3200.0 kHz. From 15079334752c26ebd540e41ed8c1eea3876a8d11 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 15:29:29 +0200 Subject: [PATCH 0232/1848] [nRF24] Fixed interface for PhysicalLayer --- src/modules/nRF24/nRF24.cpp | 13 +++++++------ src/modules/nRF24/nRF24.h | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 5ac59810ae..972eaff73f 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -45,7 +45,7 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW RADIOLIB_ASSERT(state); // set data rate - state = setDataRate(dataRate); + state = setBitRate(dataRate); RADIOLIB_ASSERT(state); // set output power @@ -103,7 +103,7 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_TX_TIMEOUT); } } - + return(finishTransmit()); } @@ -249,20 +249,21 @@ int16_t nRF24::readData(uint8_t* data, size_t len) { return(RADIOLIB_ERR_NONE); } -int16_t nRF24::setFrequency(int16_t freq) { - RADIOLIB_CHECK_RANGE(freq, 2400, 2525, RADIOLIB_ERR_INVALID_FREQUENCY); +int16_t nRF24::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE((uint16_t)freq, 2400, 2525, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency - uint8_t freqRaw = freq - 2400; + uint8_t freqRaw = (uint16_t)freq - 2400; return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0)); } -int16_t nRF24::setDataRate(int16_t dataRate) { +int16_t nRF24::setBitRate(float br) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); // set data rate + uint16_t dataRate = (uint16_t)br; if(dataRate == 250) { state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5); state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3); diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 26f8393afc..3d4af39547 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -323,16 +323,16 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequency(int16_t freq); + int16_t setFrequency(float freq); /*! - \brief Sets data rate. Allowed values are 2000, 1000 or 250 kbps. + \brief Sets bit rate. Allowed values are 2000, 1000 or 250 kbps. - \param dataRate Data rate to be set in kbps. + \param br Bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setDataRate(int16_t dataRate); + int16_t setBitRate(float br); /*! \brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm. From 09c418ab43d128fee3033c7a94065c3fb558d05b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 16:04:24 +0200 Subject: [PATCH 0233/1848] Added POCSAG to the list of supported protocols --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cd61be2f4c..0720e7ec56 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: +SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x ### Supported Arduino platforms: * __Arduino__ From afcbfa9a21ba4b3f3b3134a6cbede2a0806ba291 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 16:08:28 +0200 Subject: [PATCH 0234/1848] Added missing link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0720e7ec56..adf6863b93 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __SX1231__ FSK/OOK radio module ### Supported protocols and digital modes: -* __AX.25__ using 2-FSK or AFSK for modules: +* [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x From 3baa4bd80ffccb879d5b5847579b31dbd62c788f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 16:11:07 +0200 Subject: [PATCH 0235/1848] [Pager] Fixed narrow type comparison --- src/protocols/Pager/Pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index f75df51328..37684208ee 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -130,7 +130,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t if(len > 0) { int8_t remBits = 0; uint8_t dataPos = 0; - for(uint8_t i = 0; i < numDataBlocks + numBatches - 1; i++) { + for(size_t i = 0; i < numDataBlocks + numBatches - 1; i++) { uint8_t blockPos = RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos + 1 + i; // check if we need to skip a frame sync marker From 3bdc8963a46598378f1c1179e8a49647160b58ba Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 22:46:17 +0200 Subject: [PATCH 0236/1848] [SX126x] Added post-transaction error checking (#575) --- src/modules/SX126x/SX126x.cpp | 78 ++++++++++++++++++++++++++++++++--- src/modules/SX126x/SX126x.h | 10 +++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6f85b1c015..77cc9eb375 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1233,6 +1233,10 @@ uint8_t SX126x::randomByte() { return(randByte); } +int16_t SX126x::getLastError() { + return(_lastError); +} + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX126x::setDirectAction(void (*func)(void)) { // SX126x is unable to perform direct mode reception @@ -1330,8 +1334,15 @@ int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { } int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + // send the command uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - return(SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true)); + int16_t state = SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); + } int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { @@ -1619,20 +1630,77 @@ int16_t SX126x::config(uint8_t modem) { return(RADIOLIB_ERR_NONE); } +int16_t SX126x::checkCommandResult() { + int16_t state = RADIOLIB_ERR_NONE; + + #if defined(RADIOLIB_SPI_PARANOID) + // get the status + uint8_t spiStatus = 0; + uint8_t cmd = RADIOLIB_SX126X_CMD_GET_STATUS; + state = SX126x::SPItransfer(&cmd, 1, false, NULL, &spiStatus, 1, true); + RADIOLIB_ASSERT(state); + + // translate to RadioLib status code + switch(spiStatus) { + case RADIOLIB_SX126X_STATUS_CMD_TIMEOUT: + _lastError = RADIOLIB_ERR_SPI_CMD_TIMEOUT; + break; + case RADIOLIB_SX126X_STATUS_CMD_INVALID: + _lastError = RADIOLIB_ERR_SPI_CMD_INVALID; + break; + case RADIOLIB_SX126X_STATUS_CMD_FAILED: + _lastError = RADIOLIB_ERR_SPI_CMD_FAILED; + break; + case RADIOLIB_SX126X_STATUS_SPI_FAILED: + _lastError = RADIOLIB_ERR_CHIP_NOT_FOUND; + break; + default: + _lastError = RADIOLIB_ERR_NONE; + } + + #endif + + return(state); +} + int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy)); + // send the command + int16_t state = SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy)); + // send the command + int16_t state = SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy)); + // send the command + int16_t state = SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy)); + // send the command + int16_t state = SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index afd04fb95f..2132a3fadd 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -935,6 +935,13 @@ class SX126x: public PhysicalLayer { */ uint8_t randomByte(); + /*! + \brief Get the last recorded transaction error. + + \returns \ref status_codes + */ + int16_t getLastError(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -1024,7 +1031,10 @@ class SX126x: public PhysicalLayer { size_t _implicitLen = 0; + int16_t _lastError = RADIOLIB_ERR_NONE; + int16_t config(uint8_t modem); + int16_t checkCommandResult(); }; #endif From e31bcd315bb0aa48c1f3a96f3939c823ce920595 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 22:46:50 +0200 Subject: [PATCH 0237/1848] [SX126x] Fixed RTC control register address (#575) --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 77cc9eb375..15aedaa78e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1551,7 +1551,7 @@ int16_t SX126x::fixImplicitTimeout() { // stop RTC counter uint8_t rtcStop = 0x00; - int16_t state = writeRegister(RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL, &rtcStop, 1); + int16_t state = writeRegister(RADIOLIB_SX126X_REG_RTC_CTRL, &rtcStop, 1); RADIOLIB_ASSERT(state); // read currently active event From fc3a85abf9f30885860b2f5231d7830d6b7e3248 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 22:54:36 +0200 Subject: [PATCH 0238/1848] [SX128x] Added post-transaction error checking --- src/modules/SX128x/SX128x.cpp | 76 ++++++++++++++++++++++++++++++++--- src/modules/SX128x/SX128x.h | 10 +++++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 39df762814..188fe127ee 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1243,6 +1243,10 @@ uint8_t SX128x::randomByte() { return(0); } +int16_t SX128x::getLastError() { + return(_lastError); +} + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX128x::setDirectAction(void (*func)(void)) { // SX128x is unable to perform direct mode reception @@ -1270,7 +1274,12 @@ int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - return(SX128x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true)); + int16_t state = SX128x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { @@ -1404,20 +1413,77 @@ int16_t SX128x::config(uint8_t modem) { return(RADIOLIB_ERR_NONE); } +int16_t SX128x::checkCommandResult() { + int16_t state = RADIOLIB_ERR_NONE; + + #if defined(RADIOLIB_SPI_PARANOID) + // get the status + uint8_t spiStatus = 0; + uint8_t cmd = RADIOLIB_SX128X_CMD_GET_STATUS; + state = SX128x::SPItransfer(&cmd, 1, false, NULL, &spiStatus, 1, true); + RADIOLIB_ASSERT(state); + + // translate to RadioLib status code + switch(spiStatus) { + case RADIOLIB_SX128X_STATUS_CMD_TIMEOUT: + _lastError = RADIOLIB_ERR_SPI_CMD_TIMEOUT; + break; + case RADIOLIB_SX128X_STATUS_CMD_ERROR: + _lastError = RADIOLIB_ERR_SPI_CMD_INVALID; + break; + case RADIOLIB_SX128X_STATUS_CMD_FAILED: + _lastError = RADIOLIB_ERR_SPI_CMD_FAILED; + break; + case RADIOLIB_SX128X_STATUS_SPI_FAILED: + _lastError = RADIOLIB_ERR_CHIP_NOT_FOUND; + break; + default: + _lastError = RADIOLIB_ERR_NONE; + } + + #endif + + return(state); +} + int16_t SX128x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX128x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy)); + // send the command + int16_t state = SX128x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX128x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX128x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy)); + // send the command + int16_t state = SX128x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX128x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX128x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy)); + // send the command + int16_t state = SX128x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX128x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - return(SX128x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy)); + // send the command + int16_t state = SX128x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy); + RADIOLIB_ASSERT(state); + + // check the status + state = checkCommandResult(); + return(state); } int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index e25bf3bb34..d3006ab064 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -819,6 +819,13 @@ class SX128x: public PhysicalLayer { */ uint8_t randomByte(); + /*! + \brief Get the last recorded transaction error. + + \returns \ref status_codes + */ + int16_t getLastError(); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -903,7 +910,10 @@ class SX128x: public PhysicalLayer { // cached BLE parameters uint8_t _connectionState = 0, _crcBLE = 0, _bleTestPayload = 0; + int16_t _lastError = RADIOLIB_ERR_NONE; + int16_t config(uint8_t modem); + int16_t checkCommandResult(); }; #endif From 9a55aa84949efd090c25390dac385418889b3bcd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 23:01:05 +0200 Subject: [PATCH 0239/1848] Added missing keyword --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index cd5c8d0697..cbc45aaea5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -190,6 +190,7 @@ setRegulatorLDO KEYWORD2 setRegulatorDCDC KEYWORD2 getCurrentLimit KEYWORD2 getIrqStatus KEYWORD2 +getLastError KEYWORD2 # nRF24 setIrqAction KEYWORD2 From 37f3f138ead553df5ba3a0549c0043dbf364179a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 23:01:45 +0200 Subject: [PATCH 0240/1848] Bump version to 5.4.0 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 868e56d7d2..d8d9ca4015 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.3.0 +version=5.4.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 48ca539eb8..fa61cec592 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1046,7 +1046,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x03) +#define RADIOLIB_VERSION_MINOR (0x04) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 0e43ee0efaaa9a2e8fa25813387ea02978765b5c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Oct 2022 23:55:50 +0200 Subject: [PATCH 0241/1848] Fixed pulseIn on mbed platforms (CI_BUILD_ALL) --- src/BuildOpt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index fa61cec592..4661406ec7 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -542,7 +542,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -581,7 +581,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -690,7 +690,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) From ae04d3dbb31d0679c91cdf01636910c14608435b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Oct 2022 00:00:50 +0200 Subject: [PATCH 0242/1848] [Pager] Fixed strncpy length --- src/protocols/Pager/Pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 37684208ee..85a6e76eb5 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -264,7 +264,7 @@ int16_t PagerClient::readData(String& str, size_t len) { // check tone-only tramsissions if(length == 0) { length = 6; - strncpy((char*)data, "", length); + strncpy((char*)data, "", length + 1); } // add null terminator From 1382e5650828224bb5fe0ffdd539098b7580409a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Oct 2022 00:02:17 +0200 Subject: [PATCH 0243/1848] [SX126x] Removed extra newline (CI_BUILD_ALL) --- src/modules/SX126x/SX126x.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 15aedaa78e..ad8668be84 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1342,7 +1342,6 @@ int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { // check the status state = checkCommandResult(); return(state); - } int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { From f6e5d02481e3fb801b862fc5f91ba1a1bb6399d4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Oct 2022 12:19:33 +0200 Subject: [PATCH 0244/1848] [Pager] Reworked logic to workaround linker error on MegaCore (CI_BUILD_ALL) --- src/protocols/Pager/Pager.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 85a6e76eb5..477fb5e858 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -422,16 +422,21 @@ void PagerClient::write(uint32_t codeWord) { Module* mod = _phy->getMod(); for(int8_t i = 31; i >= 0; i--) { uint32_t mask = (uint32_t)0x01 << i; + uint32_t start = mod->micros(); if(codeWord & mask) { // send 1 - uint32_t start = mod->micros(); _phy->transmitDirect(_baseRaw + _shift); - while(mod->micros() - start < _bitDuration); } else { // send 0 - uint32_t start = mod->micros(); _phy->transmitDirect(_baseRaw - _shift); - while(mod->micros() - start < _bitDuration); + } + + // this is pretty silly, while(mod->micros() ... ) would be enough + // but for some reason, MegaCore throws a linker error on it + // "relocation truncated to fit: R_AVR_7_PCREL against `no symbol'" + uint32_t now = mod->micros(); + while(now - start < _bitDuration) { + now = mod->micros(); } } } From 170ce9752bf7ccf78713d60fb1a0b93f9ba3e3d2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 4 Oct 2022 18:19:54 +0200 Subject: [PATCH 0245/1848] [SX126x] Skip SPI verification during block calibration (#583) --- src/modules/SX126x/SX126x.cpp | 30 +++++++++++++++++++++--------- src/modules/SX126x/SX126x.h | 8 ++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ad8668be84..4662bc3dc6 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1617,7 +1617,7 @@ int16_t SX126x::config(uint8_t modem) { // calibrate all blocks data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; - state = SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1); + state = SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); RADIOLIB_ASSERT(state); // wait for calibration completion @@ -1662,43 +1662,55 @@ int16_t SX126x::checkCommandResult() { return(state); } -int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { +int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command int16_t state = SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy); RADIOLIB_ASSERT(state); // check the status - state = checkCommandResult(); + if(verify) { + state = checkCommandResult(); + } + return(state); } -int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { +int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command int16_t state = SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy); RADIOLIB_ASSERT(state); // check the status - state = checkCommandResult(); + if(verify) { + state = checkCommandResult(); + } + return(state); } -int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { +int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command int16_t state = SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy); RADIOLIB_ASSERT(state); // check the status - state = checkCommandResult(); + if(verify) { + state = checkCommandResult(); + } + return(state); } -int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { +int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command int16_t state = SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy); RADIOLIB_ASSERT(state); // check the status - state = checkCommandResult(); + if(verify) { + state = checkCommandResult(); + } + return(state); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2132a3fadd..b1c783ab85 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1005,10 +1005,10 @@ class SX126x: public PhysicalLayer { Module* _mod; // common low-level SPI interface - int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); + int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); + int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); + int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); + int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000); #if !defined(RADIOLIB_GODMODE) From ee7cf446e2a6f73aae9f5c89db95ffdd6a592d47 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 4 Oct 2022 19:42:36 +0200 Subject: [PATCH 0246/1848] Bump version to 5.4.1 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index d8d9ca4015..eb14977c5b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.4.0 +version=5.4.1 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4661406ec7..ed55362ea3 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1047,7 +1047,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) #define RADIOLIB_VERSION_MINOR (0x04) -#define RADIOLIB_VERSION_PATCH (0x00) +#define RADIOLIB_VERSION_PATCH (0x01) #define RADIOLIB_VERSION_EXTRA (0x00) #define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) From 0b1a421863bc3a0b44ca90d11b2da5f293bcce21 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Oct 2022 19:30:13 +0200 Subject: [PATCH 0247/1848] [SX126x] Fixed receive always failing after timeout --- src/modules/SX126x/SX126x.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 4662bc3dc6..ebd259e2c1 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -552,6 +552,14 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout) { int16_t SX126x::readData(uint8_t* data, size_t len) { // set mode to standby int16_t state = standby(); + + // this method may get called from receive() after Rx timeout + // if that's the case, the standby call will return "SPI command timeout error" + // check the IRQ to be sure this really originated from timeout event + if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { + // this is definitely Rx timeout + return(RADIOLIB_ERR_RX_TIMEOUT); + } RADIOLIB_ASSERT(state); // check integrity CRC From ae64ec1911512a0b3e0df8d302d75381dd2c97c0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Oct 2022 19:14:07 +0200 Subject: [PATCH 0248/1848] [CC1101] Fixed incorrect GPIO NC check logic --- .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 5 ++++- src/modules/CC1101/CC1101.cpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index b09c455e85..c55b3a9f7b 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -48,7 +48,10 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setGdo0Action(setFlag); + // NOTE: Unlike other modules (such as SX127x), + // different GDOx pins are used for + // transmit and receive interrupts! + radio.setGdo2Action(setFlag); // start transmitting the first packet Serial.print(F("[CC1101] Sending first packet ... ")); diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index a2e2eafecd..b4f00fff2d 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -232,7 +232,7 @@ void CC1101::clearGdo0Action() { } void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { return; } _mod->pinMode(_mod->getGpio(), INPUT); @@ -240,7 +240,7 @@ void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { } void CC1101::clearGdo2Action() { - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { return; } _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); From 6eeee459680911086a20d8342d28d4b6a09402f0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Oct 2022 19:21:39 +0200 Subject: [PATCH 0249/1848] [CC1101] Use GDO2 for transmit interrupt (#357) --- examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino | 2 +- .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 2 +- src/modules/CC1101/CC1101.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino index 634dc6b624..4b2c960687 100644 --- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino +++ b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino @@ -21,7 +21,7 @@ // CS pin: 10 // GDO0 pin: 2 // RST pin: unused -// GDO2 pin: 3 (optional) +// GDO2 pin: 3 CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index c55b3a9f7b..5f9437dae3 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -22,7 +22,7 @@ // CS pin: 10 // GDO0 pin: 2 // RST pin: unused -// GDO2 pin: 3 (optional) +// GDO2 pin: 3 CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index b4f00fff2d..5b44bc5539 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -109,7 +109,7 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for transmission start or timeout uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { + while(!_mod->digitalRead(_mod->getGpio())) { _mod->yield(); if(_mod->micros() - start > timeout) { @@ -120,7 +120,7 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for transmission end or timeout start = _mod->micros(); - while(_mod->digitalRead(_mod->getIrq())) { + while(_mod->digitalRead(_mod->getGpio())) { _mod->yield(); if(_mod->micros() - start > timeout) { @@ -259,7 +259,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); // set GDO0 mapping - int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED, 5, 0); RADIOLIB_ASSERT(state); // data put on FIFO. From 39489aeae6157b7d4104845456fcc018cb807ff3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 16 Oct 2022 17:47:58 +0200 Subject: [PATCH 0250/1848] [AX25] Added override for Arduino String class transmit --- src/protocols/AX25/AX25.cpp | 4 ++++ src/protocols/AX25/AX25.h | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 87d97864a6..19e3c41622 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -192,6 +192,10 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea return(_phy->startDirect()); } +int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t destSSID) { + return(transmit(str.c_str(), destCallsign, destSSID)); +} + int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) { // create control field uint8_t controlField = RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME; diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index afc110b4b4..050c39ea3f 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -320,6 +320,19 @@ class AX25Client { */ int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preambleLen = 8); + /*! + \brief Transmit unnumbered information (UI) frame. + + \param str Data to be sent as Arduino String. + + \param destCallsign Callsign of the destination station. + + \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). Defaults to 0. + + \returns \ref status_codes + */ + int16_t transmit(String& str, const char* destCallsign, uint8_t destSSID = 0x00); + /*! \brief Transmit unnumbered information (UI) frame. From 88f528a78985a3b8a38bd7e482f2b56f4cc983d4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 19 Oct 2022 18:10:45 +0200 Subject: [PATCH 0251/1848] [PHY] Added method to manually drop synchronization in direct mode --- keywords.txt | 3 +++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 +++++++- src/protocols/PhysicalLayer/PhysicalLayer.h | 9 ++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index cbc45aaea5..9c8e6dca10 100644 --- a/keywords.txt +++ b/keywords.txt @@ -244,6 +244,9 @@ sendMicE KEYWORD2 # Pager sendTone KEYWORD2 +# PhysicalLayer +dropSync KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index e0fad08d21..1d414ac4a5 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -195,11 +195,17 @@ int16_t PhysicalLayer::available() { return(_bufferWritePos); } -uint8_t PhysicalLayer::read() { +void PhysicalLayer::dropSync() { if(_directSyncWordLen > 0) { _gotSync = false; _syncBuffer = 0; } +} + +uint8_t PhysicalLayer::read(bool drop) { + if(drop) { + dropSync(); + } _bufferWritePos--; return(_buffer[_bufferReadPos++]); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index a8b011f7e3..941181b10a 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -318,12 +318,19 @@ class PhysicalLayer { */ int16_t available(); + /*! + \brief Forcefully drop synchronization. + */ + void dropSync(); + /*! \brief Get data from direct mode buffer. + \param drop Drop synchronization on read - next reading will require waiting for the sync word again. Defautls to true. + \returns Byte from direct mode buffer. */ - uint8_t read(); + uint8_t read(bool drop = true); #endif /*! From baf2a78981e76bb9dd632ee764a7d5849ebb2946 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Oct 2022 23:48:17 +0200 Subject: [PATCH 0252/1848] [SX127x] Added missing GPIO input configuration in FSK mode --- src/modules/SX127x/SX127x.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index db16ff81e7..ad181ef235 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -60,6 +60,7 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB // set module properties _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); + _mod->pinMode(_mod->getGpio(), INPUT); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { From 45e65a281158cfa537fc79325e06593c7cd697ea Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Oct 2022 23:48:37 +0200 Subject: [PATCH 0253/1848] [SX127x] Removed comment suggesting setGain only available on LoRa mode --- src/modules/SX127x/SX1272.h | 2 +- src/modules/SX127x/SX1278.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index e4343b66ac..8ef723f763 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -210,7 +210,7 @@ class SX1272: public SX127x { /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. - Set to 0 to enable automatic gain control (recommended). Only available in %LoRa mode. + Set to 0 to enable automatic gain control (recommended). \param gain Gain of receiver LNA (low-noise amplifier) to be set. diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index cffedc81fd..fd2745722e 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -219,7 +219,7 @@ class SX1278: public SX127x { /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. - Set to 0 to enable automatic gain control (recommended). Only available in %LoRa mode. + Set to 0 to enable automatic gain control (recommended). \param gain Gain of receiver LNA (low-noise amplifier) to be set. From edc04f16bdcc65a8b5c71c761b781f080fb11a42 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Oct 2022 23:48:57 +0200 Subject: [PATCH 0254/1848] [Pager] Added missing input pinmode --- src/protocols/Pager/Pager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 477fb5e858..b63f0b6a43 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -226,6 +226,8 @@ int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t RADIOLIB_ASSERT(state); // now set up the direct mode reception + Module* mod = _phy->getMod(); + mod->pinMode(pin, INPUT); _phy->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); _phy->setDirectAction(PagerClientReadBit); _phy->receiveDirect(); From b903ddabc6efce2fb0c439c8678f002f6b38ab95 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Oct 2022 23:49:13 +0200 Subject: [PATCH 0255/1848] [Pager] Added missing IRAM_ATTR for ESP platforms --- src/protocols/Pager/Pager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index b63f0b6a43..59af5d1d69 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -4,6 +4,10 @@ // let's hope nobody ever tries running two POCSAG receivers at the same time static PhysicalLayer* _readBitInstance = NULL; static RADIOLIB_PIN_TYPE _readBitPin = RADIOLIB_NC; + +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif static void PagerClientReadBit(void) { if(_readBitInstance) { _readBitInstance->readBit(_readBitPin); From 67937f4f46d94c2c79129acc74f0fc6db7d836e8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Oct 2022 10:18:49 +0200 Subject: [PATCH 0256/1848] [AX25] Added option to modify tone length for AFSK mode --- src/protocols/AX25/AX25.cpp | 6 ++++-- src/protocols/AX25/AX25.h | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 19e3c41622..b386a33527 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -163,11 +163,13 @@ AX25Client::AX25Client(AFSKClient* audio) { _audio = audio; _afskMark = RADIOLIB_AX25_AFSK_MARK; _afskSpace = RADIOLIB_AX25_AFSK_SPACE; + _afskLen = RADIOLIB_AX25_AFSK_TONE_DURATION; } -int16_t AX25Client::setCorrection(int16_t mark, int16_t space) { +int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) { _afskMark = RADIOLIB_AX25_AFSK_MARK + mark; _afskSpace = RADIOLIB_AX25_AFSK_SPACE + space; + _afskLen = length*(float)RADIOLIB_AX25_AFSK_TONE_DURATION; return(RADIOLIB_ERR_NONE); } #endif @@ -411,7 +413,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } else { _audio->tone(_afskSpace, false); } - while(mod->micros() - start < RADIOLIB_AX25_AFSK_TONE_DURATION) { + while(mod->micros() - start < _afskLen) { mod->yield(); } } diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 050c39ea3f..dcf0333419 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -300,9 +300,11 @@ class AX25Client { \param space Positive or negative correction offset for space audio frequency in Hz. + \param length Audio tone length modifier, defaults to 1.0. + \returns \ref status_codes */ - int16_t setCorrection(int16_t mark, int16_t space); + int16_t setCorrection(int16_t mark, int16_t space, float length = 1.0f); #endif // basic methods @@ -365,6 +367,7 @@ class AX25Client { AFSKClient* _audio; uint32_t _afskMark; uint32_t _afskSpace; + uint32_t _afskLen; #endif char _srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; From 9497cd3af1b527c036e73aa93077a87bac0c3821 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Oct 2022 20:38:11 +0200 Subject: [PATCH 0257/1848] [SX127x] Minor formatting fixes --- src/modules/SX127x/SX127x.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index ad181ef235..66d9d7fe75 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -189,7 +189,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // update data rate uint32_t elapsed = _mod->micros() - start; _dataRate = (len*8.0)/((float)elapsed/1000000.0); - + return(finishTransmit()); } @@ -378,8 +378,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // set DIO pin mapping if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); - } - else { + } else { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 7, 4); } @@ -1322,7 +1321,7 @@ int8_t SX127x::getTempRaw() { previousOpMode = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE); // check if we need to step out of LoRa mode first - if ((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { + if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); } @@ -1348,14 +1347,14 @@ int8_t SX127x::getTempRaw() { ival = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP); // convert very raw value - if ((ival & 0x80) == 0x80) { + if((ival & 0x80) == 0x80) { temp = 255 - ival; } else { temp = -1 * ival; } // check if we need to step back into LoRa mode - if ((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { + if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); } @@ -1407,7 +1406,7 @@ int16_t SX127x::configFSK() { int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) { // check packet length - if (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } From d80f87410eb5ef9e61bdd47a043ecfc60998a17b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Oct 2022 20:38:36 +0200 Subject: [PATCH 0258/1848] [SX127x] Removed redundant IRQ clear --- src/modules/SX127x/SX127x.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 66d9d7fe75..44c29c6403 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -266,14 +266,10 @@ int16_t SX127x::scanChannel() { while(!_mod->digitalRead(_mod->getIrq())) { _mod->yield(); if(_mod->digitalRead(_mod->getGpio())) { - clearIRQFlags(); return(RADIOLIB_PREAMBLE_DETECTED); } } - // clear interrupt flags - clearIRQFlags(); - return(RADIOLIB_CHANNEL_FREE); } @@ -676,13 +672,13 @@ int16_t SX127x::startChannelScan() { int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); + // clear interrupt flags + clearIRQFlags(); + // set DIO pin mapping state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); RADIOLIB_ASSERT(state); - // clear interrupt flags - clearIRQFlags(); - // set RF switch (if present) _mod->setRfSwitchState(HIGH, LOW); From 1316a805f3c41e29a44e52532d96c84004380eff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Oct 2022 20:39:15 +0200 Subject: [PATCH 0259/1848] [SX127x] Added option to specify interrupt direction for DIO --- src/modules/SX127x/SX127x.cpp | 8 ++++---- src/modules/SX127x/SX127x.h | 8 ++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 44c29c6403..3072d925bd 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -417,19 +417,19 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { return(setMode(mode)); } -void SX127x::setDio0Action(void (*func)(void)) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); +void SX127x::setDio0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); } void SX127x::clearDio0Action() { _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } -void SX127x::setDio1Action(void (*func)(void)) { +void SX127x::setDio1Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); + _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir); } void SX127x::clearDio1Action() { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index c960f2d205..ba33b78ab5 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -717,8 +717,10 @@ class SX127x: public PhysicalLayer { \brief Set interrupt service routine function to call when DIO0 activates. \param func Pointer to interrupt service routine. + + \param dir Signal change direction. Defaults to RISING. */ - void setDio0Action(void (*func)(void)); + void setDio0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = RISING); /*! \brief Clears interrupt service routine to call when DIO0 activates. @@ -729,8 +731,10 @@ class SX127x: public PhysicalLayer { \brief Set interrupt service routine function to call when DIO1 activates. \param func Pointer to interrupt service routine. + + \param dir Signal change direction. Defaults to RISING. */ - void setDio1Action(void (*func)(void)); + void setDio1Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = RISING); /*! \brief Clears interrupt service routine to call when DIO1 activates. From c3fa027108af71a3975d75754ec21159b293c680 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Oct 2022 20:40:13 +0200 Subject: [PATCH 0260/1848] [SX127x] Fixed CAD interrupt example --- ...x_Channel_Activity_Detection_Interrupt.ino | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index c1e0b1054a..1c41ed3757 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -30,11 +30,9 @@ SX1278 radio = new Module(10, 2, 9, 3); // https://github.com/jgromes/RadioShield //SX1278 radio = RadioShield.ModuleA; -// save state between loops -int scanState = RADIOLIB_ERR_NONE; - void setup() { - Serial.begin(9600); + // Serial port speed must be high enough for this example + Serial.begin(115200); // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); @@ -110,22 +108,21 @@ void setFlagDetected(void) { } void loop() { - // check if we got a preamble - if(detectedFlag) { + // check if we need to restart channel activity detection + if(detectedFlag || timeoutFlag) { // disable the interrupt service routine while // processing the data enableInterrupt = false; - // reset flag - detectedFlag = false; - - // LoRa preamble was detected - Serial.print(F("[SX1278] Preamble detected!")); - - } - - // check if we need to restart channel activity detection - if(detectedFlag || timeoutFlag) { + // check if we got a preamble + if(detectedFlag) { + // LoRa preamble was detected + Serial.println(F("[SX1278] Preamble detected!")); + } else { + // nothing was detected + Serial.println(F("[SX1278] Channel free!")); + } + // start scanning the channel Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); @@ -138,5 +135,13 @@ void loop() { Serial.println(state); } + // reset flags + timeoutFlag = false; + detectedFlag = false; + + // enable interrupts again + enableInterrupt = true; + } + } From 1227ea4cd1e26d543ddfcaa7e69b3ae726abbd3e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Oct 2022 20:41:04 +0200 Subject: [PATCH 0261/1848] [SX127x] Added CAD receive example --- ...27x_Channel_Activity_Detection_Receive.ino | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino new file mode 100644 index 0000000000..4914aba41c --- /dev/null +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -0,0 +1,226 @@ +/* + RadioLib SX127x Receive after Channel Activity Detection Example + + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. If a preamble is detected, + the module will switch to receive mode and receive the packet. + + For most use-cases, it should be enough to just use the + interrupt-driven reception described in the example + "SX127x_Receive_Interrupt". + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +void setup() { + // Serial port speed must be high enough for this example + Serial.begin(115200); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa preamble is not detected within CAD timeout period + // or when a packet is received + radio.setDio0Action(setFlagTimeout); + + // set the function that will be called + // when LoRa preamble is detected + radio.setDio1Action(setFlagDetected); + + // start scanning the channel + Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a preamble was not detected +volatile bool timeoutFlag = false; + +// flag to indicate that a preamble was detected +volatile bool detectedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// flag to indicate if we are currently receiving +bool receiving = false; + +// this function is called when no preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagTimeout(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we timed out, set the flag + timeoutFlag = true; +} + +// this function is called when LoRa preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagDetected(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we got a preamble, set the flag + detectedFlag = true; +} + +void loop() { + // check if we need to restart channel activity detection + if(detectedFlag || timeoutFlag) { + int state = RADIOLIB_ERR_NONE; + + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // check ongoing reception + if(receiving) { + // DIO triggered while reception is ongoing + // that means we got a packet + + // reset flags first + detectedFlag = false; + timeoutFlag = false; + + // you can read received data as an Arduino String + String str; + state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1278] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1278] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1278] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[SX1278] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[SX1278] Failed, code ")); + Serial.println(state); + + } + + // reception is done now + receiving = false; + + } + + // check if we got a preamble + if(detectedFlag) { + // LoRa preamble was detected + Serial.print(F("[SX1278] Preamble detected, starting reception ... ")); + state = radio.startReceive(0, RADIOLIB_SX127X_RXSINGLE); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // set the flag for ongoing reception + receiving = true; + + } else if(!receiving) { + // nothing was detected + // do not print anything, it just spams the console + + } + + // if we're not receiving, start scanning again + if(!receiving) { + int state = radio.startChannelScan(); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Starting new scan failed, code ")); + Serial.println(state); + } + + } + + // reset flags + timeoutFlag = false; + detectedFlag = false; + + // enable interrupts again + enableInterrupt = true; + + } + +} From c9e11d4f375036d2d086c03cda65ae5c730efe38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 28 Oct 2022 21:03:20 +0200 Subject: [PATCH 0262/1848] Fixed some typos --- examples/AFSK/AFSK_Imperial_March/melody.h | 16 ++++++++-------- examples/APRS/APRS_MicE/APRS_MicE.ino | 4 ++-- examples/APRS/APRS_Position/APRS_Position.ino | 2 +- examples/Pager/Pager_Receive/Pager_Receive.ino | 10 +++++----- examples/Pager/Pager_Transmit/Pager_Transmit.ino | 2 +- .../SX126x/SX126x_PingPong/SX126x_PingPong.ino | 2 +- .../SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 4 ++-- .../SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino | 2 +- .../SX127x_Transmit_FHSS.ino | 2 +- .../SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino | 2 +- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/AFSK/AFSK_Imperial_March/melody.h b/examples/AFSK/AFSK_Imperial_March/melody.h index e4b151696b..2f70f12922 100644 --- a/examples/AFSK/AFSK_Imperial_March/melody.h +++ b/examples/AFSK/AFSK_Imperial_March/melody.h @@ -95,16 +95,16 @@ #define NOTE_DS8 4978 #define REST 0 -// notes of the moledy followed by the duration. +// notes of the melody followed by the duration. // a 4 means a quarter note, 8 an eighteenth , 16 sixteenth, so on // !!negative numbers are used to represent dotted notes, // so -4 means a dotted quarter note, that is, a quarter plus an eighteenth!! int melody[] = { - - // Darth Vader theme (Imperial March) - Star wars + + // Darth Vader theme (Imperial March) - Star wars // Score available at https://musescore.com/user/202909/scores/1141521 // The tenor saxophone part was used - + NOTE_A4,-4, NOTE_A4,-4, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_F4,8, REST,8, NOTE_A4,-4, NOTE_A4,-4, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_F4,8, REST,8, NOTE_A4,4, NOTE_A4,4, NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, @@ -112,17 +112,17 @@ int melody[] = { NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2,//4 NOTE_E5,4, NOTE_E5,4, NOTE_E5,4, NOTE_F5,-8, NOTE_C5,16, NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2, - - NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 + + NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 NOTE_DS5,16, NOTE_D5,16, NOTE_DS5,8, REST,8, NOTE_A4,8, NOTE_DS5,4, NOTE_D5,-8, NOTE_CS5,16, NOTE_C5,16, NOTE_B4,16, NOTE_C5,16, REST,8, NOTE_F4,8, NOTE_GS4,4, NOTE_F4,-8, NOTE_A4,-16,//9 NOTE_C5,4, NOTE_A4,-8, NOTE_C5,16, NOTE_E5,2, - NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 + NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 NOTE_DS5,16, NOTE_D5,16, NOTE_DS5,8, REST,8, NOTE_A4,8, NOTE_DS5,4, NOTE_D5,-8, NOTE_CS5,16, NOTE_C5,16, NOTE_B4,16, NOTE_C5,16, REST,8, NOTE_F4,8, NOTE_GS4,4, NOTE_F4,-8, NOTE_A4,-16,//9 NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2, - + }; diff --git a/examples/APRS/APRS_MicE/APRS_MicE.ino b/examples/APRS/APRS_MicE/APRS_MicE.ino index 9ddd22873c..9d8061cb41 100644 --- a/examples/APRS/APRS_MicE/APRS_MicE.ino +++ b/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -1,7 +1,7 @@ /* RadioLib APRS Mic-E Example - This example sends APRS position reports + This example sends APRS position reports encoded in the Mic-E format using SX1278's FSK modem. The data is modulated as AFSK at 1200 baud using Bell 202 tones. @@ -45,7 +45,7 @@ AFSKClient audio(&radio, 5); // create AX.25 client instance using the AFSK instance AX25Client ax25(&audio); -// create APRS client isntance using the AX.25 client +// create APRS client instance using the AX.25 client APRSClient aprs(&ax25); void setup() { diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index 1fa8ca9e7c..2478d64b64 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -45,7 +45,7 @@ AFSKClient audio(&radio, 5); // create AX.25 client instance using the AFSK instance AX25Client ax25(&audio); -// create APRS client isntance using the AX.25 client +// create APRS client instance using the AX.25 client APRSClient aprs(&ax25); void setup() { diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino index 8497a9ae6e..3daec5b064 100644 --- a/examples/Pager/Pager_Receive/Pager_Receive.ino +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -51,7 +51,7 @@ void setup() { // when using one of the non-LoRa modules // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = radio.begin(); - + if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -60,7 +60,7 @@ void setup() { while (true); } - // initalize Pager client + // initialize Pager client Serial.print(F("[Pager] Initializing ... ")); // base (center) frequency: 434.0 MHz // speed: 1200 bps @@ -84,7 +84,7 @@ void setup() { Serial.println(state); while (true); } - + } void loop() { @@ -110,12 +110,12 @@ void loop() { // print the received data Serial.print(F("[Pager] Data:\t")); Serial.println(str); - + } else { // some error occurred Serial.print(F("failed, code ")); Serial.println(state); - + } } } diff --git a/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/examples/Pager/Pager_Transmit/Pager_Transmit.ino index 0b3dae58c8..c9c3ad1cc7 100644 --- a/examples/Pager/Pager_Transmit/Pager_Transmit.ino +++ b/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -57,7 +57,7 @@ void setup() { while(true); } - // initalize Pager client + // initialize Pager client Serial.print(F("[Pager] Initializing ... ")); // base (center) frequency: 434.0 MHz // speed: 1200 bps diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index ff386c3648..e3ed4e9651 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -51,7 +51,7 @@ void setFlag(void) { return; } - // we sent aor received packet, set the flag + // we sent or received a packet, set the flag operationDone = true; } diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index caf4fe4a44..aa2b2127f0 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -28,7 +28,7 @@ SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); @@ -177,7 +177,7 @@ void loop() { // transmit FM tone at 1000 Hz for 1 second, then 500 Hz for 1 second // (DIO2 is connected to Arduino pin 4) - // Note: tone() function is not available on ESP32, Arduino Due and CubeCell + // Note: tone() function is not available on Arduino Due and CubeCell // on these platforms, the following will do nothing #if !defined(RADIOLIB_TONE_UNSUPPORTED) tone(4, 1000); diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index 3aeca4a879..957b7d8837 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -98,7 +98,7 @@ void setup() { // set the function to call when reception is finished radio.setDio0Action(setRxFlag); - // set the function to call when we need to hcange frequency + // set the function to call when we need to change frequency radio.setDio1Action(setFHSSFlag); // start listening for LoRa packets diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index 6139ad366e..faef426b58 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -110,7 +110,7 @@ void setup() { // set the function to call when transmission is finished radio.setDio0Action(setTxFlag); - // set the function to call when we need to hcange frequency + // set the function to call when we need to change frequency radio.setDio1Action(setFHSSFlag); // start transmitting the first packet diff --git a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino index 3d9f5abd1c..5b7a1ffd09 100644 --- a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino +++ b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -65,7 +65,7 @@ void setup() { while (true); } - #warning "This sketch is just an API guide! Read the note at line 6." + #warning "This sketch is just an API guide! Read the note at line 8." } void loop() { From df7d1a99fe3638595776781e17d8ea0f1b9aab54 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 31 Oct 2022 20:17:05 +0100 Subject: [PATCH 0263/1848] [SX126x] Fixed incorrect method called from derived class (#599) --- src/modules/SX126x/SX1262.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index c33eaba900..fc6e221d40 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -97,12 +97,13 @@ class SX1262: public SX126x { /*! \brief Sets output power. Allowed values are in range from -17 to 22 dBm. + This method is virtual to allow override from the SX1261 class. \param power Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + virtual int16_t setOutputPower(int8_t power); #if !defined(RADIOLIB_GODMODE) private: From 5efdeedd67f1ea015887d3cd82559acfba7a6c03 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Nov 2022 22:51:21 +0100 Subject: [PATCH 0264/1848] [SX1262] Fixed allowed output power range (-9 dBm minimum). --- src/modules/SX126x/SX1262.cpp | 2 +- src/modules/SX126x/SX1262.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 076f2a7712..1a2a60d371 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -82,7 +82,7 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) { } int16_t SX1262::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -17, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index fc6e221d40..cac19280cc 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -96,7 +96,7 @@ class SX1262: public SX126x { int16_t setFrequency(float freq, bool calibrate); /*! - \brief Sets output power. Allowed values are in range from -17 to 22 dBm. + \brief Sets output power. Allowed values are in range from -9 to 22 dBm. This method is virtual to allow override from the SX1261 class. \param power Output power to be set in dBm. From a28aff7971def6953c284ef98e06b3ad9c10ed22 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 13 Nov 2022 11:03:05 +0100 Subject: [PATCH 0265/1848] Moved callback generators to the end of Module declaration (#605) --- src/Module.h | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Module.h b/src/Module.h index 4a8da75a12..b12fe3551b 100644 --- a/src/Module.h +++ b/src/Module.h @@ -400,7 +400,31 @@ class Module { */ void regdump(uint8_t start, uint8_t len); +#if !defined(RADIOLIB_GODMODE) + private: +#endif + + // pins + RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _gpio = RADIOLIB_NC; + + // SPI interface (Arduino only) + #if defined(RADIOLIB_BUILD_ARDUINO) + SPIClass* _spi = NULL; + SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; + bool _initInterface = false; + #endif + + // RF switch presence and pins + bool _useRfSwitch = false; + RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC; + // hardware abstraction layer callbacks + // this is placed at the end of Module class because the callback generator macros + // screw with the private/public access specifiers RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_READ); @@ -428,28 +452,6 @@ class Module { RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END); #endif - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - - // pins - RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _gpio = RADIOLIB_NC; - - // SPI interface (Arduino only) - #if defined(RADIOLIB_BUILD_ARDUINO) - SPIClass* _spi = NULL; - SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; - bool _initInterface = false; - #endif - - // RF switch presence and pins - bool _useRfSwitch = false; - RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC; }; #endif From b11deda33d9ddf98e68d9492c78152bc8a7fdef8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 13 Nov 2022 22:12:04 +0100 Subject: [PATCH 0266/1848] [SX126x] Removed slowdown macro (#158) --- src/modules/SX126x/SX126x.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ebd259e2c1..73c2aa8479 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1848,13 +1848,6 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d RADIOLIB_VERBOSE_PRINTLN(); } RADIOLIB_VERBOSE_PRINTLN(); - #else - // some faster platforms require a short delay here - // not sure why, but it seems that long enough SPI transaction - // (e.g. setPacketParams for GFSK) will fail without it - #if defined(RADIOLIB_SPI_SLOWDOWN) - _mod->delay(1); - #endif #endif // parse status From 4667c26448e644cd9ae178eec800201fac925723 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 13 Nov 2022 22:12:34 +0100 Subject: [PATCH 0267/1848] [SX128x] Removed slowdown macro (#158) --- src/BuildOpt.h | 14 -------------- src/modules/SX128x/SX128x.cpp | 7 ------- 2 files changed, 21 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index ed55362ea3..c86f6167a9 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -82,11 +82,6 @@ // the following must be defined if the Arduino core does not support tone function //#define RADIOLIB_TONE_UNSUPPORTED - // some platforms seem to have issues with SPI modules that use a command interface - // this can be mitigated by adding delays into SPI communication - // (see https://github.com/jgromes/RadioLib/issues/158 for details) - //#define RADIOLIB_SPI_SLOWDOWN - // some of RadioLib drivers may be excluded, to prevent collisions with platforms (or to speed up build process) // the following is a complete list of all possible exclusion macros, uncomment any of them to disable that driver // NOTE: Some of the exclusion macros are dependent on each other. For example, it is not possible to exclude RF69 @@ -235,9 +230,6 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - // slow down SX126x/8x SPI on this platform - #define RADIOLIB_SPI_SLOWDOWN - // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) @@ -273,9 +265,6 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - // slow down SX126x/8x SPI on this platform - #define RADIOLIB_SPI_SLOWDOWN - // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) @@ -487,9 +476,6 @@ #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - // slow down SX126x/8x SPI on this platform - #define RADIOLIB_SPI_SLOWDOWN - // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pinName, Arduino_PinMode pinMode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pinName, PinStatus val) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 188fe127ee..3e08409038 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1612,13 +1612,6 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d RADIOLIB_VERBOSE_PRINTLN(); } RADIOLIB_VERBOSE_PRINTLN(); - #else - // some faster platforms require a short delay here - // not sure why, but it seems that long enough SPI transaction - // (e.g. setPacketParams for GFSK) will fail without it - #if defined(RADIOLIB_SPI_SLOWDOWN) - _mod->delay(1); - #endif #endif // parse status From 58d744ae7a63e956890dec69614ba902e05bddaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 14 Nov 2022 12:58:46 +0100 Subject: [PATCH 0268/1848] Portduino is simulating an UNO WIFI the same definition works now. --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index c86f6167a9..074908fa07 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -426,7 +426,7 @@ #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) + #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(PORTDUINO) // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every #define RADIOLIB_PLATFORM "Arduino megaAVR" #define RADIOLIB_PIN_TYPE uint8_t From 00fc7cd5b9bbc5b2ac6698bf3c95f4f0a4d1d4a0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 14 Nov 2022 21:18:42 +0100 Subject: [PATCH 0269/1848] [Pager] Added optional custom frequnecy shift --- src/protocols/Pager/Pager.cpp | 7 ++++--- src/protocols/Pager/Pager.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 59af5d1d69..73d0ef5d73 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -19,7 +19,7 @@ PagerClient::PagerClient(PhysicalLayer* phy) { _readBitInstance = _phy; } -int16_t PagerClient::begin(float base, uint16_t speed) { +int16_t PagerClient::begin(float base, uint16_t speed, uint16_t shift) { // calculate duration of 1 bit in us _speed = (float)speed/1000.0f; _bitDuration = (uint32_t)1000000/speed; @@ -32,7 +32,8 @@ int16_t PagerClient::begin(float base, uint16_t speed) { uint16_t step = round(_phy->getFreqStep()); // calculate raw frequency shift - _shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ/step; + _shiftHz = shift; + _shift = _shiftHz/step; // initialize BCH encoder encoderInit(); @@ -226,7 +227,7 @@ int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t RADIOLIB_ASSERT(state); // set frequency deviation to 4.5 khz - state = _phy->setFrequencyDeviation((float)RADIOLIB_PAGER_FREQ_SHIFT_HZ / 1000.0f); + state = _phy->setFrequencyDeviation((float)_shiftHz / 1000.0f); RADIOLIB_ASSERT(state); // now set up the direct mode reception diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 357e08a2be..21a71eb89f 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -86,7 +86,7 @@ class PagerClient { \returns \ref status_codes */ - int16_t begin(float base, uint16_t speed); + int16_t begin(float base, uint16_t speed, uint16_t shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ); /*! \brief Method to send a tone-only alert to a destination pager. @@ -192,6 +192,7 @@ class PagerClient { float _speed; uint32_t _baseRaw; uint16_t _shift; + uint16_t _shiftHz; uint16_t _bitDuration; uint32_t _readBatchPos; uint32_t _filterAddr; From a848cf281b6f4fe5475bf94cfc6b942792d741f9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 14 Nov 2022 21:19:16 +0100 Subject: [PATCH 0270/1848] [Pager] Added option to retrieve matched address on reception --- src/protocols/Pager/Pager.cpp | 13 ++++++++----- src/protocols/Pager/Pager.h | 8 ++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 73d0ef5d73..90ddaa5934 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -244,7 +244,7 @@ size_t PagerClient::available() { return(_phy->available() + sizeof(uint32_t))/(sizeof(uint32_t) * (RADIOLIB_PAGER_BATCH_LEN + 1)); } -int16_t PagerClient::readData(String& str, size_t len) { +int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { int16_t state = RADIOLIB_ERR_NONE; // determine the message length, based on user input or the amount of received data @@ -265,7 +265,7 @@ int16_t PagerClient::readData(String& str, size_t len) { #endif // read the received data - state = readData(data, &length); + state = readData(data, &length, addr); if(state == RADIOLIB_ERR_NONE) { // check tone-only tramsissions @@ -289,7 +289,7 @@ int16_t PagerClient::readData(String& str, size_t len) { return(state); } -int16_t PagerClient::readData(uint8_t* data, size_t* len) { +int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { // find the correct address bool match = false; uint8_t framePos = 0; @@ -316,10 +316,13 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len) { } // should be an address code word, extract the address - uint32_t addr = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); - if((addr & _filterMask) == (_filterAddr & _filterMask)) { + uint32_t addr_found = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); + if((addr_found & _filterMask) == (_filterAddr & _filterMask)) { // we have a match! match = true; + if(addr) { + *addr = addr_found; + } // determine the encoding from the function bits if((cw & RADIOLIB_PAGER_FUNCTION_BITS_MASK) == RADIOLIB_PAGER_FUNC_BITS_NUMERIC) { diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 21a71eb89f..6a831b9e84 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -166,9 +166,11 @@ class PagerClient { \param len Expected number of characters in the message. When set to 0, the message length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. + \param addr Pointer to variable holding the address of the received pager message. Set to NULL to not retrieve address. + \returns \ref status_codes */ - int16_t readData(String& str, size_t len = 0); + int16_t readData(String& str, size_t len = 0, uint32_t* addr = NULL); /*! \brief Reads data that was received after calling startReceive method. @@ -179,9 +181,11 @@ class PagerClient { When more bytes than received are requested, only the number of bytes requested will be returned. Upon completion, the number of bytes received will be written to this variable. + \param addr Pointer to variable holding the address of the received pager message. Set to NULL to not retrieve address. + \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t* len); + int16_t readData(uint8_t* data, size_t* len, uint32_t* addr = NULL); #if !defined(RADIOLIB_GODMODE) private: From f68bef287735a44c6232b31d15ad10d95d6120d1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 16 Nov 2022 19:21:52 +0100 Subject: [PATCH 0271/1848] [PHY] Added option to keep received data despite CRC error --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 1d414ac4a5..611425e81c 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -83,7 +83,9 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { // read the received data state = readData(data, length); - if(state == RADIOLIB_ERR_NONE) { + // any of the following leads to at least some data being available + // let's leave the decision of whether to keep it or not up to the user + if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) { // add null terminator data[length] = 0; @@ -123,7 +125,9 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { // attempt packet reception state = receive(data, length); - if(state == RADIOLIB_ERR_NONE) { + // any of the following leads to at least some data being available + // let's leave the decision of whether to keep it or not up to the user + if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) { // read the number of actually received bytes (for unknown packets) if(len == 0) { length = getPacketLength(false); From feb9aaa227190720565e82e720d6a3227e6b8c1b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 16 Nov 2022 19:21:55 +0100 Subject: [PATCH 0272/1848] [SX127x] Added option to keep received data despite CRC error (#610) --- src/modules/SX127x/SX127x.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 3072d925bd..a3a94345b0 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -621,20 +621,18 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { length = len; } + // check payload CRC + int16_t state = RADIOLIB_ERR_NONE; + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + state = RADIOLIB_ERR_CRC_MISMATCH; + } + if(modem == RADIOLIB_SX127X_LORA) { // check packet header integrity - if(_crcEnabled && (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6)) == 0) { + if(_crcEnabled && (state == RADIOLIB_ERR_NONE) && (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) == 0)) { // CRC is disabled according to packet header and enabled according to user // most likely damaged packet header - clearIRQFlags(); - return(RADIOLIB_ERR_LORA_HEADER_DAMAGED); - } - - // check payload CRC - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { - // clear interrupt flags - clearIRQFlags(); - return(RADIOLIB_ERR_CRC_MISMATCH); + state = RADIOLIB_ERR_LORA_HEADER_DAMAGED; } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { @@ -659,7 +657,7 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // clear interrupt flags clearIRQFlags(); - return(RADIOLIB_ERR_NONE); + return(state); } int16_t SX127x::startChannelScan() { From 1fc9b3a1422bf05662d5ff58cc59adf297f501ef Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Wed, 16 Nov 2022 14:41:30 +0100 Subject: [PATCH 0273/1848] fix: wrong cast Signed-off-by: Frederic Pillon --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 074908fa07..ee115575e6 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -222,7 +222,7 @@ #define RADIOLIB_PIN_MODE uint32_t #define RADIOLIB_PIN_STATUS uint32_t #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt((PinName)p) + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_DEFAULT_SPI SPI #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) From a7e56800a891a36e2db3a162267382b6984ea8c4 Mon Sep 17 00:00:00 2001 From: Amalinda Gamage <5582466+Amalinda@users.noreply.github.com> Date: Fri, 18 Nov 2022 16:08:57 +0800 Subject: [PATCH 0274/1848] Update SX126x.cpp --- src/modules/SX126x/SX126x.cpp | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 73c2aa8479..41c50ada45 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1328,6 +1328,51 @@ int16_t SX126x::setRx(uint32_t timeout) { } int16_t SX126x::setCad() { + // Configure CAD parameters for assigned SF as per Semtech AN1200.48, Rev 2.1, Page 50, November 2019. + // Parameters are configured in RADIOLIB_SX126X_CMD_SET_CAD_PARAMS register. + + uint8_t data[7]; + + switch(_sf) + { + case 7: + data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; + data[1] = 21; + break; + + case 8: + data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; + data[1] = 22; + break; + + case 9: + data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; + data[1] = 22; + break; + + case 10: + data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; + data[1] = 24; + break; + + case 11: + data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; + data[1] = 25; + break; + + default: + data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; + data[1] = 28; + break; + } + + data[2] = 10; + data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; + data[4] = 0x00; + data[5] = 0x00; + data[6] = 0x00; + SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); } From e02b3f2ce0cdad946fac5bc5980033dd498c3479 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 11:35:32 +0100 Subject: [PATCH 0275/1848] [SX126x] Added missing Rx write arguments --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 41c50ada45..23a9c847bd 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1324,7 +1324,7 @@ int16_t SX126x::setTx(uint32_t timeout) { int16_t SX126x::setRx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX, data, 3)); + return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } int16_t SX126x::setCad() { From f942ccaec717eff2b7d80fb84909df4e1056a1ca Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 13:39:51 +0100 Subject: [PATCH 0276/1848] [SX126x] Added option to specify custom CAD parameters --- src/modules/SX126x/SX126x.cpp | 85 ++++++++++++++++------------------- src/modules/SX126x/SX126x.h | 20 +++++++-- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 23a9c847bd..e77e402814 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -321,9 +321,9 @@ int16_t SX126x::receiveDirect() { return(RADIOLIB_ERR_UNKNOWN); } -int16_t SX126x::scanChannel() { +int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { // set mode to CAD - int state = startChannelScan(); + int state = startChannelScan(symbolNum, detPeak, detMin); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -589,7 +589,7 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { return(state); } -int16_t SX126x::startChannelScan() { +int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -611,7 +611,7 @@ int16_t SX126x::startChannelScan() { RADIOLIB_ASSERT(state); // set mode to CAD - state = setCad(); + state = setCad(symbolNum, detPeak, detMin); return(state); } @@ -1327,52 +1327,45 @@ int16_t SX126x::setRx(uint32_t timeout) { return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } -int16_t SX126x::setCad() { - // Configure CAD parameters for assigned SF as per Semtech AN1200.48, Rev 2.1, Page 50, November 2019. - // Parameters are configured in RADIOLIB_SX126X_CMD_SET_CAD_PARAMS register. - +int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // default CAD parameters for assigned SF as per Semtech AN1200.48, Rev 2.1, Page 50 + uint8_t detPeakValues[8] = { 22, 22, 22, 22, 23, 24, 25, 28}; + uint8_t symbolNumValues[8] = { RADIOLIB_SX126X_CAD_ON_2_SYMB, + RADIOLIB_SX126X_CAD_ON_2_SYMB, + RADIOLIB_SX126X_CAD_ON_2_SYMB, + RADIOLIB_SX126X_CAD_ON_2_SYMB, + RADIOLIB_SX126X_CAD_ON_4_SYMB, + RADIOLIB_SX126X_CAD_ON_4_SYMB, + RADIOLIB_SX126X_CAD_ON_4_SYMB, + RADIOLIB_SX126X_CAD_ON_4_SYMB }; + // build the packet uint8_t data[7]; - - switch(_sf) - { - case 7: - data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; - data[1] = 21; - break; - - case 8: - data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; - data[1] = 22; - break; - - case 9: - data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; - data[1] = 22; - break; - - case 10: - data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; - data[1] = 24; - break; - - case 11: - data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; - data[1] = 25; - break; - - default: - data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; - data[1] = 28; - break; - } - - data[2] = 10; + data[0] = symbolNumValues[_sf - 5]; + data[1] = detPeakValues[_sf - 5]; + data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[4] = 0x00; data[5] = 0x00; data[6] = 0x00; - SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + // set user-provided values + if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[0] = symbolNum; + } + + if(detPeak != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[1] = detPeak; + } + + if(detMin != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[2] = detMin; + } + + // configure paramaters + int16_t state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + RADIOLIB_ASSERT(state); + + // start CAD return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); } @@ -1652,10 +1645,10 @@ int16_t SX126x::config(uint8_t modem) { state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); - // set CAD parameters + // set some CAD parameters - will be overwritten whel calling CAD anyway data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; data[1] = _sf + 13; - data[2] = 10; + data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[4] = 0x00; data[5] = 0x00; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index b1c783ab85..8e80bebfc6 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -308,6 +308,8 @@ #define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 #define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode #define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected +#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value +#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter //RADIOLIB_SX126X_CMD_GET_STATUS #define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC @@ -470,9 +472,15 @@ class SX126x: public PhysicalLayer { /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. + + \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. + + \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. + \returns \ref status_codes */ - int16_t scanChannel(); + int16_t scanChannel(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); /*! \brief Sets the module to sleep mode. @@ -591,9 +599,15 @@ class SX126x: public PhysicalLayer { /*! \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected, or upon timeout. + \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. + + \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. + + \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. + \returns \ref status_codes */ - int16_t startChannelScan(); + int16_t startChannelScan(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); /*! \brief Read the channel scan result @@ -965,7 +979,7 @@ class SX126x: public PhysicalLayer { // SX126x SPI command implementations int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); - int16_t setCad(); + int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); From 29813352d4a5e2805368fd87a57209c6e98a1781 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 13:54:12 +0100 Subject: [PATCH 0277/1848] [SSTV] Moved correction factor to its own method --- examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino | 14 ++++++++-- .../SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino | 14 ++++++++-- src/protocols/SSTV/SSTV.cpp | 26 ++++++++++++------- src/protocols/SSTV/SSTV.h | 15 +++++++---- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino index 3a189c980b..e532e2d407 100644 --- a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino +++ b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -107,7 +107,16 @@ void setup() { Serial.print(F("[SSTV] Initializing ... ")); // 0 Hz tone frequency: 434.0 MHz // SSTV mode: Wrasse (SC2-180) - // correction factor: 0.95 + state = sstv.begin(434.0, Wrasse); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set correction factor // NOTE: Due to different speeds of various platforms // supported by RadioLib (Arduino Uno, ESP32 etc), // and because SSTV is analog protocol, incorrect @@ -116,7 +125,8 @@ void setup() { // to adjust the length of timing pulses // (lower number = shorter pulses). // The value is usually around 0.95 (95%). - state = sstv.begin(434.0, Wrasse, 0.95); + Serial.print(F("[SSTV] Setting correction ... ")); + state = sstv.setCorrection(0.95); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino index 8678fa7163..4719adaff3 100644 --- a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -105,7 +105,16 @@ void setup() { // initialize SSTV client Serial.print(F("[SSTV] Initializing ... ")); // SSTV mode: Wrasse (SC2-180) - // correction factor: 0.95 + state = sstv.begin(Wrasse); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // set correction factor // NOTE: Due to different speeds of various platforms // supported by RadioLib (Arduino Uno, ESP32 etc), // and because SSTV is analog protocol, incorrect @@ -114,7 +123,8 @@ void setup() { // to adjust the length of timing pulses // (lower number = shorter pulses). // The value is usually around 0.95 (95%). - state = sstv.begin(Wrasse, 0.95); + Serial.print(F("[SSTV] Setting correction ... ")); + state = sstv.setCorrection(0.95); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index ec5957c5c6..d8fda18609 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -169,26 +169,20 @@ SSTVClient::SSTVClient(AFSKClient* audio) { #endif #if !defined(RADIOLIB_EXCLUDE_AFSK) -int16_t SSTVClient::begin(const SSTVMode_t& mode, float correction) { +int16_t SSTVClient::begin(const SSTVMode_t& mode) { if(_audio == nullptr) { // this initialization method can only be used in AFSK mode return(RADIOLIB_ERR_WRONG_MODEM); } - return(begin(0, mode, correction)); + return(begin(0, mode)); } #endif -int16_t SSTVClient::begin(float base, const SSTVMode_t& mode, float correction) { +int16_t SSTVClient::begin(float base, const SSTVMode_t& mode) { // save mode _mode = mode; - // apply correction factor to all timings - _mode.scanPixelLen *= correction; - for(uint8_t i = 0; i < _mode.numTones; i++) { - _mode.tones[i].len *= correction; - } - // calculate 24-bit frequency _base = (base * 1000000.0) / _phy->getFreqStep(); @@ -196,6 +190,20 @@ int16_t SSTVClient::begin(float base, const SSTVMode_t& mode, float correction) return(_phy->startDirect()); } +int16_t SSTVClient::setCorrection(float correction) { + // check if mode is initialized + if(_mode.visCode == 0) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // apply correction factor to all timings + _mode.scanPixelLen *= correction; + for(uint8_t i = 0; i < _mode.numTones; i++) { + _mode.tones[i].len *= correction; + } + return(RADIOLIB_ERR_NONE); +} + void SSTVClient::idle() { _phy->transmitDirect(); this->tone(RADIOLIB_SSTV_TONE_LEADER); diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index f24053e439..5a094cd6dd 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -144,11 +144,9 @@ class SSTVClient { \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. - \param correction Timing correction factor, used to adjust the length of timing pulses. Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). - \returns \ref status_codes */ - int16_t begin(float base, const SSTVMode_t& mode, float correction = 1.0); + int16_t begin(float base, const SSTVMode_t& mode); #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! @@ -156,12 +154,19 @@ class SSTVClient { \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + \returns \ref status_codes + */ + int16_t begin(const SSTVMode_t& mode); + #endif + + /*! + \brief Set correction coefficient for tone length. + \param correction Timing correction factor, used to adjust the length of timing pulses. Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). \returns \ref status_codes */ - int16_t begin(const SSTVMode_t& mode, float correction = 1.0); - #endif + int16_t setCorrection(float correction); /*! \brief Sends out tone at 1900 Hz. From 355446c43a7d6d847e85100f7a682bd378d89e9e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 13:56:40 +0100 Subject: [PATCH 0278/1848] [FSK4] Added correction method --- examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino | 17 ++++++ .../FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino | 19 ++++++- src/protocols/FSK4/FSK4.cpp | 57 +++++++++++-------- src/protocols/FSK4/FSK4.h | 37 +++++++++++- 4 files changed, 104 insertions(+), 26 deletions(-) diff --git a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino index 9cd4d40c77..8a1153b05f 100644 --- a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino +++ b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino @@ -99,6 +99,23 @@ void setup() { Serial.println(state); while(true); } + + // sometimes, it may be needed to set some manual corrections + // this can be done for tone frequencies, + // as well as tone lengths + /* + // set frequency shift offsets to -120, 60, 0 and 60 Hz and decrease tone length to 95% + int offsets[4] = { -120, -60, 0, 60 }; + Serial.print(F("[FSK4] Setting corrections ... ")); + state = fsk4.setCorrection(offsets, 0.95); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ } void loop() { diff --git a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino index f4b4cceacb..73b4a704fd 100644 --- a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino +++ b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -1,7 +1,7 @@ /* RadioLib FSK4 Transmit AFSK Example - This example sends an example FSK-4 'Horus Binary' message + This example sends an example FSK-4 'Horus Binary' message using SX1278's FSK modem. The data is modulated as AFSK. This signal can be demodulated using an FM demodulator (SDR or otherwise), @@ -92,6 +92,23 @@ void setup() { Serial.println(state); while(true); } + + // sometimes, it may be needed to set some manual corrections + // this can be done for tone frequencies, + // as well as tone lengths + /* + // set audio tone offsets to -10, 20, 0 and 5 Hz and decrease tone length to 95% + int offsets[4] = { -10, 20, 0, 5 }; + Serial.print(F("[FSK4] Setting corrections ... ")); + state = fsk4.setCorrection(offsets, 0.95); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ } void loop() { diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 5e34c01450..a6f5826687 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -23,31 +23,14 @@ int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { // calculate duration of 1 bit _bitDuration = (uint32_t)1000000/rate; - // calculate module carrier frequency resolution - uint32_t step = round(_phy->getFreqStep()); - - // check minimum shift value - if(shift < step / 2) { - return(RADIOLIB_ERR_INVALID_RTTY_SHIFT); - } - - // round shift to multiples of frequency step size - if(shift % step < (step / 2)) { - _shift = shift / step; - } else { - _shift = (shift / step) + 1; - } + // calculate carrier shift + _shift = getRawShift(shift); // Write resultant tones into arrays for quick lookup when modulating. - _tones[0] = 0; - _tones[1] = _shift; - _tones[2] = _shift*2; - _tones[3] = _shift*3; - - _tonesHz[0] = 0; - _tonesHz[1] = _shiftHz; - _tonesHz[2] = _shiftHz*2; - _tonesHz[3] = _shiftHz*3; + for(uint8_t i = 0; i < 4; i++) { + _tones[i] = _shift*i; + _tonesHz[i] = _shiftHz*i; + } // calculate 24-bit frequency _base = (base * 1000000.0) / _phy->getFreqStep(); @@ -61,6 +44,15 @@ void FSK4Client::idle() { tone(0); } +int16_t FSK4Client::setCorrection(int16_t offsets[], float length) { + for(uint8_t i = 0; i < 4; i++) { + _tones[i] += getRawShift(offsets[i]); + _tonesHz[i] += offsets[i]; + } + _bitDuration *= length; + return(RADIOLIB_ERR_NONE); +} + size_t FSK4Client::write(uint8_t* buff, size_t len) { size_t n = 0; for(size_t i = 0; i < len; i++) { @@ -113,4 +105,23 @@ int16_t FSK4Client::standby() { return(_phy->standby()); } +int32_t FSK4Client::getRawShift(int32_t shift) { + // calculate module carrier frequency resolution + int32_t step = round(_phy->getFreqStep()); + + // check minimum shift value + if(abs(shift) < step / 2) { + return(0); + } + + // round shift to multiples of frequency step size + if(abs(shift) % step < (step / 2)) { + return(shift / step); + } + if(shift < 0) { + return((shift / step) - 1); + } + return((shift / step) + 1); +} + #endif diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index 049453bced..aecba119b4 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -42,7 +42,6 @@ class FSK4Client { \param rate Baud rate to be used during transmission. - \returns \ref status_codes */ int16_t begin(float base, uint32_t shift, uint16_t rate); @@ -52,9 +51,43 @@ class FSK4Client { */ void idle(); + /*! + \brief Set correction coefficients for frequencies and tone length. + + \param offsets Four positive or negative correction offsets for audio frequencies in Hz. + + \param length Tone length modifier, defaults to 1.0. + + \returns \ref status_codes + */ + int16_t setCorrection(int16_t offsets[4], float length = 1.0f); + + /*! + \brief Transmit binary data. + + \param buff Buffer to transmit. + + \param len Number of bytes to transmit. + + \returns Number of transmitted bytes. + */ size_t write(uint8_t* buff, size_t len); + + /*! + \brief Transmit a single byte. + + \param b Byte to transmit. + + \returns Number of transmitted bytes. + */ size_t write(uint8_t b); + /*! + \brief Stop transmitting. + + \returns \ref status_codes + */ + int16_t standby(); #if !defined(RADIOLIB_GODMODE) private: @@ -73,7 +106,7 @@ class FSK4Client { void tone(uint8_t i); int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); - int16_t standby(); + int32_t getRawShift(int32_t shift); }; #endif From 53f954a179412afa7b63adb27d47ee69ada457d9 Mon Sep 17 00:00:00 2001 From: CCChelios <34306652+CCChelios@users.noreply.github.com> Date: Fri, 18 Nov 2022 16:28:42 +0300 Subject: [PATCH 0279/1848] Update CC1101_Settings.ino --- examples/CC1101/CC1101_Settings/CC1101_Settings.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino index b8f8fb2fd9..680c60d119 100644 --- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino +++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -33,7 +33,7 @@ CC1101 radio1 = new Module(10, 2, RADIOLIB_NC, 3); // GDO0 pin: 4 // RST pin: unused // GDO2 pin: 5 (optional) -CC1101 radio2 = new Module(9, 4, RADIOLIB_NC, 53); +CC1101 radio2 = new Module(9, 4, RADIOLIB_NC, 5); // or using RadioShield // https://github.com/jgromes/RadioShield From 04357cb306e3968d856257d78bb8bf1d415f7f8f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:03:34 +0100 Subject: [PATCH 0280/1848] [MOD] Added support for interrupt-based timing --- keywords.txt | 2 ++ src/Module.cpp | 18 ++++++++++++++++++ src/Module.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/keywords.txt b/keywords.txt index 9c8e6dca10..edcb4faa42 100644 --- a/keywords.txt +++ b/keywords.txt @@ -246,6 +246,8 @@ sendTone KEYWORD2 # PhysicalLayer dropSync KEYWORD2 +setTimerFlag KEYWORD2 +setInterruptSetup KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/Module.cpp b/src/Module.cpp index 72e5d9964a..ba0674c00f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -251,6 +251,24 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da this->SPIendTransaction(); } +void Module::waitForMicroseconds(uint32_t start, uint32_t len) { + #if defined(RADIOLIB_INTERRUPT_TIMING) + (void)start; + if((this->TimerSetupCb != nullptr) && (len != this->_prevTimingLen)) { + _prevTimingLen = len; + this->TimerSetupCb(len); + } + this->TimerFlag = false; + while(!this->TimerFlag) { + this->yield(); + } + #else + while(this->micros() - start < len) { + this->yield(); + } + #endif +} + void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) { if((pin == RADIOLIB_NC) || (cb_pinMode == nullptr)) { return; diff --git a/src/Module.h b/src/Module.h index b12fe3551b..f699d5fe10 100644 --- a/src/Module.h +++ b/src/Module.h @@ -91,6 +91,25 @@ class Module { */ uint8_t SPIwriteCommand = 0b10000000; + #if defined(RADIOLIB_INTERRUPT_TIMING) + + /*! + \brief Timer interrupt setup callback typedef. + */ + typedef void (*TimerSetupCb_t)(uint32_t len); + + /*! + \brief Callback to timer interrupt setup function when running in interrupt timing control mode. + */ + TimerSetupCb_t TimerSetupCb = nullptr; + + /*! + \brief Timer flag variable to be controlled by a platform-dependent interrupt. + */ + volatile bool TimerFlag = false; + + #endif + // basic methods /*! @@ -241,6 +260,16 @@ class Module { */ void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState); + /*! + \brief Wait for time to elapse, either using the microsecond timer, or the TimerFlag. + Note that in interrupt timing mode, it is up to the user to set up the timing interrupt! + + \param start Waiting start timestamp, in microseconds. + + \param len Waiting duration, in microseconds; + */ + void waitForMicroseconds(uint32_t start, uint32_t len); + // Arduino core overrides /*! @@ -422,6 +451,10 @@ class Module { RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC; RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC; + #if defined(RADIOLIB_INTERRUPT_TIMING) + uint32_t _prevTimingLen = 0; + #endif + // hardware abstraction layer callbacks // this is placed at the end of Module class because the callback generator macros // screw with the private/public access specifiers From c3d6700e76be305f7411d1c6a3ddb9468706ae6e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:04:52 +0100 Subject: [PATCH 0281/1848] [PHY] Added support for interrupt-based timing --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 12 ++++++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 611425e81c..e1a881519f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -266,3 +266,15 @@ int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { (void)value; return(RADIOLIB_ERR_UNSUPPORTED); } + +#if defined(RADIOLIB_INTERRUPT_TIMING) +void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { + Module* mod = getMod(); + mod->TimerSetupCb = func; +} + +void PhysicalLayer::setTimerFlag() { + Module* mod = getMod(); + mod->TimerFlag = true; +} +#endif diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 941181b10a..4e33881a12 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -344,6 +344,22 @@ class PhysicalLayer { */ virtual int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + #if defined(RADIOLIB_INTERRUPT_TIMING) + + /*! + \brief Set function to be called to set up the timing interrupt. + + \param func Setup function to be called, with one argument (pulse length in microseconds). + */ + void setInterruptSetup(void (*func)(uint32_t)); + + /*! + \brief Set timing interrupt flag. + */ + void setTimerFlag(); + + #endif + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) protected: void updateDirectBuffer(uint8_t bit); From 5327952af5c76d565590d62e5ae24a3c33d02e4a Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:06:38 +0100 Subject: [PATCH 0282/1848] Added links to interrupt-based wiki page --- src/BuildOpt.h | 8 ++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index ee115575e6..5c77861df7 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -953,6 +953,14 @@ //#define RADIOLIB_RADIOSHIELD #endif +/* + * Uncomment to enable interrupt-based timing control + * For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing + */ +#if !defined(RADIOLIB_INTERRUPT_TIMING) + //#define RADIOLIB_INTERRUPT_TIMING +#endif + /* * Uncomment to enable static-only memory management: no dynamic allocation will be performed. * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 4e33881a12..9305cf0abb 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -348,6 +348,7 @@ class PhysicalLayer { /*! \brief Set function to be called to set up the timing interrupt. + For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing \param func Setup function to be called, with one argument (pulse length in microseconds). */ @@ -355,6 +356,7 @@ class PhysicalLayer { /*! \brief Set timing interrupt flag. + For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing */ void setTimerFlag(); From 3e64e819c740ec4626bae65009825bf1311ddf41 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:07:01 +0100 Subject: [PATCH 0283/1848] [RTTY] Added support for interrupt-based timing --- src/protocols/RTTY/RTTY.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 95d110186c..e1994978aa 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -407,18 +407,14 @@ void RTTYClient::mark() { Module* mod = _phy->getMod(); uint32_t start = mod->micros(); transmitDirect(_base + _shift, _baseHz + _shiftHz); - while(mod->micros() - start < _bitDuration) { - mod->yield(); - } + mod->waitForMicroseconds(start, _bitDuration); } void RTTYClient::space() { Module* mod = _phy->getMod(); uint32_t start = mod->micros(); transmitDirect(_base, _baseHz); - while(mod->micros() - start < _bitDuration) { - mod->yield(); - } + mod->waitForMicroseconds(start, _bitDuration); } size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { @@ -531,6 +527,9 @@ int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { } int16_t RTTYClient::standby() { + // ensure everything is stopped in interrupt timing mode + Module* mod = _phy->getMod(); + mod->waitForMicroseconds(0, 0); #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { return(_audio->noTone()); From abc7cf179affb998db5d29b857ebeca907493db6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:24:01 +0100 Subject: [PATCH 0284/1848] [AX25] Added support for interrupt-based timing --- src/protocols/AX25/AX25.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index b386a33527..8bc8de4bec 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -413,9 +413,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } else { _audio->tone(_afskSpace, false); } - while(mod->micros() - start < _afskLen) { - mod->yield(); - } + mod->waitForMicroseconds(start, _afskLen); } } From 2bf5297b32217df85e4e00dc5d8ff549b3652c96 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:24:20 +0100 Subject: [PATCH 0285/1848] [FSK4] ADded support for interrupt-based timing --- src/protocols/FSK4/FSK4.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index a6f5826687..4ec074b944 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -82,9 +82,7 @@ void FSK4Client::tone(uint8_t i) { Module* mod = _phy->getMod(); uint32_t start = mod->micros(); transmitDirect(_base + _tones[i], _baseHz + _tonesHz[i]); - while(mod->micros() - start < _bitDuration) { - mod->yield(); - } + mod->waitForMicroseconds(start, _bitDuration); } int16_t FSK4Client::transmitDirect(uint32_t freq, uint32_t freqHz) { @@ -97,6 +95,9 @@ int16_t FSK4Client::transmitDirect(uint32_t freq, uint32_t freqHz) { } int16_t FSK4Client::standby() { + // ensure everything is stopped in interrupt timing mode + Module* mod = _phy->getMod(); + mod->waitForMicroseconds(0, 0); #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { return(_audio->noTone()); From e1c217305f627e6b79bec1beafd12dbb640f396f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:39:18 +0100 Subject: [PATCH 0286/1848] [Hell] Added support for interrupt-based timing --- src/protocols/Hellschreiber/Hellschreiber.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 6a32f306e5..cab4759855 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -39,7 +39,7 @@ size_t HellClient::printGlyph(uint8_t* buff) { } else { standby(); } - while(mod->micros() - start < _pixelDuration); + mod->waitForMicroseconds(start, _pixelDuration); } } From f69723b96cf331e2a53df41166fbfbcd84798fce Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 17:55:08 +0100 Subject: [PATCH 0287/1848] [Morse] Added support for interrupt-based timing --- examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino | 2 +- src/protocols/Morse/Morse.cpp | 10 +++++----- src/protocols/Morse/Morse.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino index 3feb78bdca..b4f4b41794 100644 --- a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino +++ b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -28,7 +28,7 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 radio = new Module(5, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 65f1a11df4..8497259077 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -137,7 +137,7 @@ size_t MorseClient::write(uint8_t b) { if(b == ' ') { RADIOLIB_DEBUG_PRINTLN(F("space")); standby(); - mod->delay(_wordSpace); + mod->waitForMicroseconds(mod->micros(), _wordSpace*1000); return(1); } @@ -156,16 +156,16 @@ size_t MorseClient::write(uint8_t b) { if (code & RADIOLIB_MORSE_DASH) { RADIOLIB_DEBUG_PRINT('-'); transmitDirect(_base, _baseHz); - mod->delay(_dashLength); + mod->waitForMicroseconds(mod->micros(), _dashLength*1000); } else { RADIOLIB_DEBUG_PRINT('.'); transmitDirect(_base, _baseHz); - mod->delay(_dotLength); + mod->waitForMicroseconds(mod->micros(), _dotLength*1000); } // symbol space standby(); - mod->delay(_dotLength); + mod->waitForMicroseconds(mod->micros(), _dotLength*1000); // move onto the next bit code >>= 1; @@ -173,7 +173,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); - mod->delay(_letterSpace - _dotLength); + mod->waitForMicroseconds(mod->micros(), _letterSpace*1000 - _dotLength*1000); RADIOLIB_DEBUG_PRINTLN(); return(1); diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index bfa72b52d5..0ae567e7f4 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -193,9 +193,9 @@ class MorseClient { uint32_t _base = 0, _baseHz = 0; float _basePeriod = 0.0f; - uint16_t _dotLength = 0; - uint16_t _dashLength = 0; - uint16_t _letterSpace = 0; + uint32_t _dotLength = 0; + uint32_t _dashLength = 0; + uint32_t _letterSpace = 0; uint16_t _wordSpace = 0; // variables to keep decoding state From 2f0dac1bb7ffac74d56db184f4eaf2b3635d9031 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Nov 2022 18:05:42 +0100 Subject: [PATCH 0288/1848] [SSTV] Added support for interrupt-based timing (#596) --- src/protocols/SSTV/SSTV.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index d8fda18609..9b4bcf7f01 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -301,9 +301,7 @@ void SSTVClient::tone(float freq, uint32_t len) { #else _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); #endif - while(mod->micros() - start < len) { - mod->yield(); - } + mod->waitForMicroseconds(start, len); } #endif From 72ce5dfd93491a3ded83ccc8fa579c95d4d2ea7b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 19 Nov 2022 14:19:57 +0100 Subject: [PATCH 0289/1848] Reworked macro reporting in debug mode --- src/RadioLib.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index 50e2fc7f34..37963d1580 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -47,7 +47,14 @@ // print debug info #if defined(RADIOLIB_DEBUG) - #pragma message "RADIOLIB_PLATFORM: " RADIOLIB_PLATFORM + #define RADIOLIB_VALUE_TO_STRING(x) #x + #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) + #define RADIOLIB_VAR_NAME_VALUE(var) #var "=" RADIOLIB_VALUE(var) + #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_PLATFORM)) + #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_MAJOR)) + #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_MINOR)) + #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_PATCH)) + #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_EXTRA)) #endif // check unknown/unsupported platform From 3fa34b433a528b555998bb1f4d35bf108165a90f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 19 Nov 2022 14:20:14 +0100 Subject: [PATCH 0290/1848] Bump version to 5.5.0 --- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index eb14977c5b..87ce79d3b2 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.4.1 +version=5.5.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5c77861df7..5a2be397f9 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1040,8 +1040,8 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x04) -#define RADIOLIB_VERSION_PATCH (0x01) +#define RADIOLIB_VERSION_MINOR (0x05) +#define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) #define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) From 13227965428c40ed946f57c6c9128e919f42561d Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Sun, 20 Nov 2022 01:35:08 +0100 Subject: [PATCH 0291/1848] [RF69 & CC1101] Reworked cached parameters into getters Signed-off-by: Federico Maggi --- src/modules/CC1101/CC1101.cpp | 38 +++++++++++++++++---- src/modules/CC1101/CC1101.h | 28 +++++++++++++--- src/modules/RF69/RF69.cpp | 63 +++++++++++++++++++++++++++++------ src/modules/RF69/RF69.h | 47 ++++++++++++++++++++++---- src/modules/nRF24/nRF24.cpp | 24 +++++++++++-- src/modules/nRF24/nRF24.h | 22 ++++++++++-- 6 files changed, 189 insertions(+), 33 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 5b44bc5539..6a5a0f2bb7 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -89,7 +89,8 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // set default sync word - state = setSyncWord(0x12, 0xAD, 0, false); + uint8_t sw[2] = RADIOLIB_CC1101_DEFAULT_SW; + state = setSyncWord(sw[0], sw[1], 0, false); RADIOLIB_ASSERT(state); // flush FIFOs @@ -472,7 +473,7 @@ int16_t CC1101::setBitRate(float br) { int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG3, m); if(state == RADIOLIB_ERR_NONE) { - CC1101::_br = br; + _br = br; } return(state); } @@ -489,8 +490,11 @@ int16_t CC1101::setRxBandwidth(float rxBw) { float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); if(fabs((rxBw * 1000.0) - point) <= 1000) { // set Rx channel filter bandwidth - return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); + uint16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4); + + return(state); } + } } @@ -517,9 +521,31 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { // set frequency deviation value int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, (e << 4), 6, 4); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, m, 2, 0); + return(state); } +int16_t CC1101::getFrequencyDeviation(float *freqDev) { + // if ASK/OOK, deviation makes no sense + if (_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { + *freqDev = 0.0; + + return(RADIOLIB_ERR_NONE); + } + + // get exponent and mantissa values from registers + uint8_t e = (uint8_t)SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 6, 4); + uint8_t m = (uint8_t)SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 2, 0); + + // calculate frequency deviation (pag. 79 of the CC1101 datasheet): + // + // freqDev = (fXosc / 2^17) * (8 + m) * 2^e + // + *freqDev = (1000.0 / (uint32_t(1) << 17)) - (8 + m) * (uint32_t(1) << e); + + return(RADIOLIB_ERR_NONE); +} + int16_t CC1101::setOutputPower(int8_t power) { // round to the known frequency settings uint8_t f; @@ -608,8 +634,6 @@ int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, } } - _syncWordLength = len; - // enable sync word filtering int16_t state = enableSyncWordFiltering(maxErrBits, requireCarrierSense); RADIOLIB_ASSERT(state); @@ -658,11 +682,11 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) { return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } + uint16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4); - return SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4); + return(state); } - int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { RADIOLIB_CHECK_RANGE(numBroadcastAddrs, 1, 2, RADIOLIB_ERR_INVALID_NUM_BROAD_ADDRS); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 3ae99b63f1..8c2100f26a 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -499,6 +499,16 @@ #define RADIOLIB_CC1101_GDO2_ACTIVE 0b00000100 // 2 2 GDO2 is active/asserted #define RADIOLIB_CC1101_GDO0_ACTIVE 0b00000001 // 0 0 GDO0 is active/asserted +//Defaults +#define RADIOLIB_CC1101_DEFAULT_FREQ 434.0 +#define RADIOLIB_CC1101_DEFAULT_BR 48.0 +#define RADIOLIB_CC1101_DEFAULT_FREQDEV 48.0 +#define RADIOLIB_CC1101_DEFAULT_RXBW 135.0 +#define RADIOLIB_CC1101_DEFAULT_POWER 10 +#define RADIOLIB_CC1101_DEFAULT_PREAMBLELEN 16 +#define RADIOLIB_CC1101_DEFAULT_SW {0x12, 0xAD} +#define RADIOLIB_CC1101_DEFAULT_SW_LEN 2 + /*! \class CC1101 @@ -720,6 +730,15 @@ class CC1101: public PhysicalLayer { */ int16_t setFrequencyDeviation(float freqDev) override; + /*! + \brief Gets frequency deviation. + + \param[out] freqDev Pointer to variable where to save the frequency deviation. + + \returns \ref status_codes + */ + int16_t getFrequencyDeviation(float *freqDev); + /*! \brief Sets output power. Allowed values are -30, -20, -15, -10, 0, 5, 7 or 10 dBm. @@ -973,8 +992,8 @@ class CC1101: public PhysicalLayer { protected: #endif - float _freq = 0; - float _br = 0; + float _freq = RADIOLIB_CC1101_DEFAULT_FREQ; + float _br = RADIOLIB_CC1101_DEFAULT_BR; uint8_t _rawRSSI = 0; uint8_t _rawLQI = 0; uint8_t _modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; @@ -987,8 +1006,9 @@ class CC1101: public PhysicalLayer { bool _crcOn = true; bool _directMode = true; - uint8_t _syncWordLength = 2; - int8_t _power = 0; + uint8_t _syncWordLength = RADIOLIB_CC1101_DEFAULT_SW_LEN; + int8_t _power = RADIOLIB_CC1101_DEFAULT_POWER; + int16_t config(); int16_t transmitDirect(bool sync, uint32_t frf); diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 699bf16d16..5187c54c50 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -59,7 +59,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_ASSERT(state); // configure bitrate - _rxBw = 125.0; + _rxBw = rxBw; state = setBitRate(br); RADIOLIB_ASSERT(state); @@ -84,7 +84,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_ASSERT(state); // set default sync word - uint8_t syncWord[] = {0x12, 0xAD}; + uint8_t syncWord[] = RADIOLIB_RF69_DEFAULT_SW; state = setSyncWord(syncWord, sizeof(syncWord)); RADIOLIB_ASSERT(state); @@ -526,12 +526,26 @@ int16_t RF69::setFrequency(float freq) { setMode(RADIOLIB_RF69_STANDBY); //set carrier frequency + //FRF(23:0) = freq / Fstep = freq * (1 / Fstep) = freq * (2^19 / 32.0) (pag. 17 of datasheet) uint32_t FRF = (freq * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / RADIOLIB_RF69_CRYSTAL_FREQ; _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, FRF & 0x0000FF); - _freq = freq; + return(RADIOLIB_ERR_NONE); +} + +int16_t RF69::getFrequency(float *freq) { + uint32_t FRF = 0; + + //FRF(23:0) = [ [FRF_MSB]|[FRF_MID]|[FRF_LSB]] + //FRF(32:0) = [0x00|[FRF_MSB]|[FRF_MID]|[FRF_LSB]] + FRF |= (((uint32_t)(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MSB, 7, 0)) << 16) & 0x00FF0000); + FRF |= (((uint32_t)(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MID, 7, 0)) << 8) & 0x0000FF00); + FRF |= (((uint32_t)(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_LSB, 7, 0)) << 0) & 0x000000FF); + + //freq = Fstep * FRF(23:0) = (32.0 / 2^19) * FRF(23:0) (pag. 17 of datasheet) + *freq = FRF * ( RADIOLIB_RF69_CRYSTAL_FREQ / (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT) ); return(RADIOLIB_ERR_NONE); } @@ -552,7 +566,7 @@ int16_t RF69::setBitRate(float br) { int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); if(state == RADIOLIB_ERR_NONE) { - RF69::_br = br; + _br = br; } return(state); } @@ -575,7 +589,7 @@ int16_t RF69::setRxBandwidth(float rxBw) { // set Rx bandwidth state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); if(state == RADIOLIB_ERR_NONE) { - RF69::_rxBw = rxBw; + _rxBw = rxBw; } return(state); } @@ -602,13 +616,33 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { // set frequency deviation from carrier frequency uint32_t base = 1; - uint32_t fdev = (newFreqDev * (base << 19)) / 32000; + uint32_t fdev = (newFreqDev * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / 32000; int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); return(state); } +int16_t RF69::getFrequencyDeviation(float *freqDev) { + if (RF69::_ook) { + *freqDev = 0.0; + + return(RADIOLIB_ERR_NONE); + } + + // get raw value from register + uint32_t fdev = 0; + fdev |= (uint32_t)((_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, 5, 0) << 8) & 0x0000FF00); + fdev |= (uint32_t)((_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, 7, 0) << 0) & 0x000000FF); + + // calculate frequency deviation from raw value obtained from register + // Fdev = Fstep * Fdev(13:0) (pag. 20 of datasheet) + *freqDev = (fdev * RADIOLIB_RF69_CRYSTAL_FREQ) / + (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT); + + return(RADIOLIB_ERR_NONE); +} + int16_t RF69::setOutputPower(int8_t power, bool highPower) { if(highPower) { RADIOLIB_CHECK_RANGE(power, -2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); @@ -660,14 +694,17 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { } } - _syncWordLength = len; - int16_t state = enableSyncWordFiltering(maxErrBits); RADIOLIB_ASSERT(state); // set sync word register _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); - return(RADIOLIB_ERR_NONE); + + if(state == RADIOLIB_ERR_NONE) { + _syncWordLength = len; + } + + return(state); } int16_t RF69::setPreambleLength(uint8_t preambleLen) { @@ -678,7 +715,9 @@ int16_t RF69::setPreambleLength(uint8_t preambleLen) { uint8_t preLenBytes = preambleLen / 8; _mod->SPIwriteRegister(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0x00); - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes)); + uint16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes); + + return (state); } int16_t RF69::setNodeAddress(uint8_t nodeAddr) { @@ -819,6 +858,10 @@ int16_t RF69::setPromiscuousMode(bool promiscuous) { // enable CRC filtering state = setCrcFiltering(true); } + if(state == RADIOLIB_ERR_NONE) { + _promiscuous = promiscuous; + } + return(state); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 9233f57aff..777d8d0462 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -462,6 +462,15 @@ #define RADIOLIB_RF69_PA2_NORMAL 0x70 // 7 0 PA_BOOST: none #define RADIOLIB_RF69_PA2_20_DBM 0x7C // 7 0 +20 dBm +// Defaults +#define RADIOLIB_RF69_DEFAULT_FREQ 434.0 +#define RADIOLIB_RF69_DEFAULT_BR 48.0 +#define RADIOLIB_RF69_DEFAULT_FREQDEV 50.0 +#define RADIOLIB_RF69_DEFAULT_RXBW 125.0 +#define RADIOLIB_RF69_DEFAULT_POWER 10 +#define RADIOLIB_RF69_DEFAULT_PREAMBLELEN 16 +#define RADIOLIB_RF69_DEFAULT_SW {0x12, 0xAD} +#define RADIOLIB_RF69_DEFAULT_SW_LEN 2 /*! \class RF69 @@ -503,8 +512,14 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); - + //int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin( + float freq = RADIOLIB_RF69_DEFAULT_FREQ, + float br = RADIOLIB_RF69_DEFAULT_BR, + float freqDev = RADIOLIB_RF69_DEFAULT_FREQDEV, + float rxBw = RADIOLIB_RF69_DEFAULT_RXBW, + int8_t power = RADIOLIB_RF69_DEFAULT_POWER, + uint8_t preambleLen = RADIOLIB_RF69_DEFAULT_PREAMBLELEN); /*! \brief Reset method. Will reset the chip to the default state using RST pin. */ @@ -721,6 +736,15 @@ class RF69: public PhysicalLayer { */ int16_t setFrequency(float freq); + /*! + \brief Gets carrier frequency. + + \param[out] freq Variable to write carrier frequency currently set, in MHz. + + \returns \ref status_codes + */ + int16_t getFrequency(float *freq); + /*! \brief Sets bit rate. Allowed values range from 1.2 to 300.0 kbps. @@ -748,6 +772,15 @@ class RF69: public PhysicalLayer { */ int16_t setFrequencyDeviation(float freqDev) override; + /*! + \brief Gets frequency deviation. + + \param[out] freqDev Where to write the frequency deviation currently set, in kHz. + + \returns \ref status_codes + */ + int16_t getFrequencyDeviation(float *freqDev); + /*! \brief Sets output power. Allowed values range from -18 to 13 dBm for low power modules (RF69C/CW) or -2 to 20 dBm (RF69H/HC/HCW). @@ -1037,12 +1070,12 @@ class RF69: public PhysicalLayer { protected: #endif - float _freq = 0; - float _br = 0; - float _rxBw = 0; + float _freq = RADIOLIB_RF69_DEFAULT_FREQ; + float _br = RADIOLIB_RF69_DEFAULT_BR; + float _rxBw = RADIOLIB_RF69_DEFAULT_RXBW; bool _ook = false; int16_t _tempOffset = 0; - int8_t _power = 0; + int8_t _power = RADIOLIB_RF69_DEFAULT_POWER; size_t _packetLength = 0; bool _packetLengthQueried = false; @@ -1050,7 +1083,7 @@ class RF69: public PhysicalLayer { bool _promiscuous = false; - uint8_t _syncWordLength = 2; + uint8_t _syncWordLength = RADIOLIB_RF69_DEFAULT_SW_LEN; bool _bitSync = true; diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 972eaff73f..fdc3f6f971 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -254,7 +254,14 @@ int16_t nRF24::setFrequency(float freq) { // set frequency uint8_t freqRaw = (uint16_t)freq - 2400; - return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0)); + //return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0)); + uint16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0); + + if(state == RADIOLIB_ERR_NONE) { + _freq = freq; + } + + return(state); } int16_t nRF24::setBitRate(float br) { @@ -276,6 +283,11 @@ int16_t nRF24::setBitRate(float br) { } else { return(RADIOLIB_ERR_INVALID_DATA_RATE); } + + if(state == RADIOLIB_ERR_NONE) { + _dataRate = dataRate; + } + return(state); } @@ -306,6 +318,12 @@ int16_t nRF24::setOutputPower(int8_t power) { // write new register value state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, powerRaw, 2, 1); + + if(state == RADIOLIB_ERR_NONE) { + _power = power; + } + + return(state); } @@ -335,7 +353,9 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) { } // save address width - _addrWidth = addrWidth; + if(state == RADIOLIB_ERR_NONE) { + _addrWidth = addrWidth; + } return(state); } diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 3d4af39547..bf3d8b0654 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -171,6 +171,13 @@ #define RADIOLIB_NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default) #define RADIOLIB_NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled +// Defaults +#define RADIOLIB_NRF24_DEFAULT_FREQ 2400 +#define RADIOLIB_NRF24_DEFAULT_DR 1000 +#define RADIOLIB_NRF24_DEFAULT_POWER -12 +#define RADIOLIB_NRF24_DEFAULT_ADDRWIDTH 5 + + /*! \class nRF24 @@ -208,8 +215,12 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(int16_t freq = 2400, int16_t dataRate = 1000, int8_t power = -12, uint8_t addrWidth = 5); - + //int16_t begin(int16_t freq = 2400, int16_t dataRate = 1000, int8_t power = -12, uint8_t addrWidth = 5); + int16_t begin( + int16_t freq = RADIOLIB_NRF24_DEFAULT_FREQ, + int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR, + int8_t power = RADIOLIB_NRF24_DEFAULT_POWER, + uint8_t addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH); /*! \brief Sets the module to sleep mode. @@ -509,7 +520,12 @@ class nRF24: public PhysicalLayer { protected: #endif - uint8_t _addrWidth = 0; + //uint8_t _addrWidth = 0; + int16_t _freq = RADIOLIB_NRF24_DEFAULT_FREQ; + int16_t _dataRate = RADIOLIB_NRF24_DEFAULT_DR; + int8_t _power = RADIOLIB_NRF24_DEFAULT_POWER; + uint8_t _addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH; + int16_t config(); void clearIRQ(); From 05217c095b43df4a31f89b2c536e2ac601613ead Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Mon, 21 Nov 2022 09:09:56 +0100 Subject: [PATCH 0292/1848] - Defined new RADIOLIB_ERR_NULL_POINTER - all `begin()` now use macros for init values - addressed other styling comments as per PR#612 review Signed-off-by: Federico Maggi --- src/TypeDef.h | 5 +++++ src/modules/CC1101/CC1101.cpp | 16 ++++++++-------- src/modules/CC1101/CC1101.h | 15 ++++++++++----- src/modules/RF69/RF69.cpp | 10 ++++++---- src/modules/RF69/RF69.h | 18 +++++++++--------- src/modules/nRF24/nRF24.cpp | 3 +-- src/modules/nRF24/nRF24.h | 11 +++++------ 7 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index 0d250d5097..e2d8c91450 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -218,6 +218,11 @@ */ #define RADIOLIB_ERR_INVALID_RSSI_THRESHOLD (-27) +/*! + \brief A `NULL` pointer has been encountered. If you see this, there may be a potential security vulnerability. +*/ +#define RADIOLIB_ERR_NULL_POINTER (-28) + // RF69-specific status codes /*! diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 6a5a0f2bb7..9407523b95 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -89,7 +89,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // set default sync word - uint8_t sw[2] = RADIOLIB_CC1101_DEFAULT_SW; + uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW; state = setSyncWord(sw[0], sw[1], 0, false); RADIOLIB_ASSERT(state); @@ -490,9 +490,7 @@ int16_t CC1101::setRxBandwidth(float rxBw) { float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); if(fabs((rxBw * 1000.0) - point) <= 1000) { // set Rx channel filter bandwidth - uint16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4); - - return(state); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); } } @@ -526,6 +524,10 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { } int16_t CC1101::getFrequencyDeviation(float *freqDev) { + if (freqDev == NULL) { + return(RADIOLIB_ERR_NULL_POINTER); + } + // if ASK/OOK, deviation makes no sense if (_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { *freqDev = 0.0; @@ -534,7 +536,7 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { } // get exponent and mantissa values from registers - uint8_t e = (uint8_t)SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 6, 4); + uint8_t e = (uint8_t)(SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 6, 4) >> 4); uint8_t m = (uint8_t)SPIgetRegValue(RADIOLIB_CC1101_REG_DEVIATN, 2, 0); // calculate frequency deviation (pag. 79 of the CC1101 datasheet): @@ -682,9 +684,7 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) { return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } - uint16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4); - - return(state); + return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4)); } int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 8c2100f26a..bb245cbed8 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -501,8 +501,8 @@ //Defaults #define RADIOLIB_CC1101_DEFAULT_FREQ 434.0 -#define RADIOLIB_CC1101_DEFAULT_BR 48.0 -#define RADIOLIB_CC1101_DEFAULT_FREQDEV 48.0 +#define RADIOLIB_CC1101_DEFAULT_BR 4.8 +#define RADIOLIB_CC1101_DEFAULT_FREQDEV 5.0 #define RADIOLIB_CC1101_DEFAULT_RXBW 135.0 #define RADIOLIB_CC1101_DEFAULT_POWER 10 #define RADIOLIB_CC1101_DEFAULT_PREAMBLELEN 16 @@ -536,7 +536,7 @@ class CC1101: public PhysicalLayer { /*! \brief Initialization method. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param freq Carrier frequency in MHz. Defaults to 434 MHz. \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. @@ -550,7 +550,13 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 135.0, int8_t power = 10, uint8_t preambleLength = 16); + int16_t begin( + float freq = RADIOLIB_CC1101_DEFAULT_FREQ, + float br = RADIOLIB_CC1101_DEFAULT_BR, + float freqDev = RADIOLIB_CC1101_DEFAULT_FREQDEV, + float rxBw = RADIOLIB_CC1101_DEFAULT_RXBW, + int8_t power = RADIOLIB_CC1101_DEFAULT_POWER, + uint8_t preambleLength = RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); /*! \brief Blocking binary transmit method. @@ -1006,7 +1012,6 @@ class CC1101: public PhysicalLayer { bool _crcOn = true; bool _directMode = true; - uint8_t _syncWordLength = RADIOLIB_CC1101_DEFAULT_SW_LEN; int8_t _power = RADIOLIB_CC1101_DEFAULT_POWER; diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 5187c54c50..5cfd833a72 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -59,7 +59,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_ASSERT(state); // configure bitrate - _rxBw = rxBw; + _rxBw = rxBw; state = setBitRate(br); RADIOLIB_ASSERT(state); @@ -615,7 +615,6 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { setMode(RADIOLIB_RF69_STANDBY); // set frequency deviation from carrier frequency - uint32_t base = 1; uint32_t fdev = (newFreqDev * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / 32000; int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); @@ -624,6 +623,10 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { } int16_t RF69::getFrequencyDeviation(float *freqDev) { + if (freqDev == NULL) { + return(RADIOLIB_ERR_NULL_POINTER); + } + if (RF69::_ook) { *freqDev = 0.0; @@ -715,9 +718,8 @@ int16_t RF69::setPreambleLength(uint8_t preambleLen) { uint8_t preLenBytes = preambleLen / 8; _mod->SPIwriteRegister(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0x00); - uint16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes); - return (state); + return (_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes)); } int16_t RF69::setNodeAddress(uint8_t nodeAddr) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 777d8d0462..7cb41d9021 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -464,8 +464,8 @@ // Defaults #define RADIOLIB_RF69_DEFAULT_FREQ 434.0 -#define RADIOLIB_RF69_DEFAULT_BR 48.0 -#define RADIOLIB_RF69_DEFAULT_FREQDEV 50.0 +#define RADIOLIB_RF69_DEFAULT_BR 4.8 +#define RADIOLIB_RF69_DEFAULT_FREQDEV 5.0 #define RADIOLIB_RF69_DEFAULT_RXBW 125.0 #define RADIOLIB_RF69_DEFAULT_POWER 10 #define RADIOLIB_RF69_DEFAULT_PREAMBLELEN 16 @@ -512,14 +512,14 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - //int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); int16_t begin( - float freq = RADIOLIB_RF69_DEFAULT_FREQ, - float br = RADIOLIB_RF69_DEFAULT_BR, - float freqDev = RADIOLIB_RF69_DEFAULT_FREQDEV, - float rxBw = RADIOLIB_RF69_DEFAULT_RXBW, - int8_t power = RADIOLIB_RF69_DEFAULT_POWER, - uint8_t preambleLen = RADIOLIB_RF69_DEFAULT_PREAMBLELEN); + float freq = RADIOLIB_RF69_DEFAULT_FREQ, + float br = RADIOLIB_RF69_DEFAULT_BR, + float freqDev = RADIOLIB_RF69_DEFAULT_FREQDEV, + float rxBw = RADIOLIB_RF69_DEFAULT_RXBW, + int8_t power = RADIOLIB_RF69_DEFAULT_POWER, + uint8_t preambleLen = RADIOLIB_RF69_DEFAULT_PREAMBLELEN); + /*! \brief Reset method. Will reset the chip to the default state using RST pin. */ diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index fdc3f6f971..f00f42e3db 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -254,8 +254,7 @@ int16_t nRF24::setFrequency(float freq) { // set frequency uint8_t freqRaw = (uint16_t)freq - 2400; - //return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0)); - uint16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0); + int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0); if(state == RADIOLIB_ERR_NONE) { _freq = freq; diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index bf3d8b0654..72605c6ff0 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -215,12 +215,12 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - //int16_t begin(int16_t freq = 2400, int16_t dataRate = 1000, int8_t power = -12, uint8_t addrWidth = 5); int16_t begin( - int16_t freq = RADIOLIB_NRF24_DEFAULT_FREQ, - int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR, - int8_t power = RADIOLIB_NRF24_DEFAULT_POWER, - uint8_t addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH); + int16_t freq = RADIOLIB_NRF24_DEFAULT_FREQ, + int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR, + int8_t power = RADIOLIB_NRF24_DEFAULT_POWER, + uint8_t addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH); + /*! \brief Sets the module to sleep mode. @@ -520,7 +520,6 @@ class nRF24: public PhysicalLayer { protected: #endif - //uint8_t _addrWidth = 0; int16_t _freq = RADIOLIB_NRF24_DEFAULT_FREQ; int16_t _dataRate = RADIOLIB_NRF24_DEFAULT_DR; int8_t _power = RADIOLIB_NRF24_DEFAULT_POWER; From befba2862932734fe95cd92f8e4e09bdd303903f Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Sat, 26 Nov 2022 19:38:36 +0100 Subject: [PATCH 0293/1848] No bound checks on frequency deviation if ~FSK --- src/modules/CC1101/CC1101.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 9407523b95..1102723087 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -506,7 +506,9 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { newFreqDev = 1.587; } - RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + if (_modulation != RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { + RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } // set mode to standby SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); From 9422723bb7532bc9e5bc2893913c1788ea470ecf Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Sun, 27 Nov 2022 10:20:29 +0100 Subject: [PATCH 0294/1848] [CC1101] Validate freq-dev unless special value 0 Signed-off-by: Federico Maggi --- src/modules/CC1101/CC1101.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 1102723087..dc994bae39 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -506,7 +506,8 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { newFreqDev = 1.587; } - if (_modulation != RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { + // check range unless 0 (special value) + if (freqDev != 0) { RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } From f51229ef9a0be16079360641843edf219e0ad112 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Nov 2022 20:47:01 +0100 Subject: [PATCH 0295/1848] [Pager] Added option to invert frequencies (#7) --- src/protocols/Pager/Pager.cpp | 22 ++++++++++++++++------ src/protocols/Pager/Pager.h | 7 ++++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 90ddaa5934..144903a21b 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -19,7 +19,7 @@ PagerClient::PagerClient(PhysicalLayer* phy) { _readBitInstance = _phy; } -int16_t PagerClient::begin(float base, uint16_t speed, uint16_t shift) { +int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { // calculate duration of 1 bit in us _speed = (float)speed/1000.0f; _bitDuration = (uint32_t)1000000/speed; @@ -34,6 +34,7 @@ int16_t PagerClient::begin(float base, uint16_t speed, uint16_t shift) { // calculate raw frequency shift _shiftHz = shift; _shift = _shiftHz/step; + inv = invert; // initialize BCH encoder encoderInit(); @@ -433,14 +434,23 @@ void PagerClient::write(uint32_t codeWord) { for(int8_t i = 31; i >= 0; i--) { uint32_t mask = (uint32_t)0x01 << i; uint32_t start = mod->micros(); + + // figure out the shift direction - start by assuming the bit is 0 + int16_t change = _shift; + + // now check if it's actually 1 if(codeWord & mask) { - // send 1 - _phy->transmitDirect(_baseRaw + _shift); - } else { - // send 0 - _phy->transmitDirect(_baseRaw - _shift); + change = -_shift; } + // finally, check if inversion is enabled + if(inv) { + change = -change; + } + + // now transmit the shifted frequency + _phy->transmitDirect(_baseRaw + change); + // this is pretty silly, while(mod->micros() ... ) would be enough // but for some reason, MegaCore throws a linker error on it // "relocation truncated to fit: R_AVR_7_PCREL against `no symbol'" diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 6a831b9e84..eb828fbb7c 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -84,9 +84,13 @@ class PagerClient { \param speed Bit rate to use in bps. Common POCSAG decoders can receive 512, 1200 and 2400 bps. + \param invert Enable frequency inversion. Disabled by default (high frequency is digital 0). + + \param shift Set custom frequency shift, defaults to 4500 Hz. + \returns \ref status_codes */ - int16_t begin(float base, uint16_t speed, uint16_t shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ); + int16_t begin(float base, uint16_t speed, bool invert = false, uint16_t shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ); /*! \brief Method to send a tone-only alert to a destination pager. @@ -201,6 +205,7 @@ class PagerClient { uint32_t _readBatchPos; uint32_t _filterAddr; uint32_t _filterMask; + bool inv = false; // BCH encoder int32_t _bchAlphaTo[RADIOLIB_PAGER_BCH_N + 1]; From 7295e9731e1184485c1b5dd45d1b05f55f2efb06 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Nov 2022 20:47:18 +0100 Subject: [PATCH 0296/1848] [Pager] Fixed default example pins --- examples/Pager/Pager_Receive/Pager_Receive.ino | 4 ++-- examples/Pager/Pager_Transmit/Pager_Transmit.ino | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino index 3daec5b064..f2ecb9aec7 100644 --- a/examples/Pager/Pager_Receive/Pager_Receive.ino +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -29,10 +29,10 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 radio = new Module(5, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // DIO2 pin: 5 -const int pin = 4; +const int pin = 5; // create Pager client instance using the FSK module PagerClient pager(&radio); diff --git a/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/examples/Pager/Pager_Transmit/Pager_Transmit.ino index c9c3ad1cc7..d23452d410 100644 --- a/examples/Pager/Pager_Transmit/Pager_Transmit.ino +++ b/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -29,7 +29,7 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 radio = new Module(5, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield @@ -77,9 +77,9 @@ void loop() { // the simples form of "message" is just a tone on the destination pager int state = pager.sendTone(1234567); delay(500); - + // next, transmit numeric (BCD) message to the destination pager - // NOTE: Only characters 0123456789*U-() and space + // NOTE: Only characters 0123456789*U-() and space // can be sent in a BCD message! state |= pager.transmit("0123456789*U -()", 1234567); delay(500); @@ -89,7 +89,7 @@ void loop() { delay(500); // we can also send only a tone - + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { From 894e9122521655856276b6c477f6b2bd8c65623c Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Thu, 1 Dec 2022 13:24:42 +0100 Subject: [PATCH 0297/1848] [RF69] Fixed setPromiscuousMode(false) corner case Signed-off-by: Federico Maggi --- src/modules/RF69/RF69.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 5cfd833a72..bb9bd1bee5 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -801,15 +801,8 @@ int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) { } int16_t RF69::disableSyncWordFiltering() { - // disable preamble detection and generation - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, 0, 7, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0, 7, 0); - RADIOLIB_ASSERT(state); - // disable sync word detection and generation - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_OFF | RADIOLIB_RF69_FIFO_FILL_CONDITION, 7, 6); - - return(state); + return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_OFF | RADIOLIB_RF69_FIFO_FILL_CONDITION, 7, 6)); } int16_t RF69::enableContinuousModeBitSync() { @@ -846,14 +839,22 @@ int16_t RF69::setPromiscuousMode(bool promiscuous) { } if (promiscuous == true) { - // disable preamble and sync word filtering and insertion + // disable preamble detection and generation + state = setPreambleLength(0); + RADIOLIB_ASSERT(state); + + // disable sync word filtering and insertion state = disableSyncWordFiltering(); RADIOLIB_ASSERT(state); // disable CRC filtering state = setCrcFiltering(false); } else { - // enable preamble and sync word filtering and insertion + // enable preamble detection and generation + state = setPreambleLength(RADIOLIB_RF69_DEFAULT_PREAMBLELEN); + RADIOLIB_ASSERT(state); + + // enable sync word filtering and insertion state = enableSyncWordFiltering(); RADIOLIB_ASSERT(state); From 09669eeb268ea17703ffe77cda54f3074e97986c Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Thu, 1 Dec 2022 13:32:47 +0100 Subject: [PATCH 0298/1848] [CC1101] Fix `setPromiscuousMode(false)` bug Signed-off-by: Federico Maggi --- src/modules/CC1101/CC1101.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index dc994bae39..f943a47029 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -824,14 +824,21 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) { } if (promiscuous == true) { - // disable preamble and sync word filtering and insertion + // disable preamble detection and generation + state = setPreambleLength(0); + RADIOLIB_ASSERT(state); + + // disable sync word filtering and insertion state = disableSyncWordFiltering(); RADIOLIB_ASSERT(state); // disable CRC filtering state = setCrcFiltering(false); } else { - // enable preamble and sync word filtering and insertion + state = setPreambleLength(RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); + RADIOLIB_ASSERT(state); + + // enable sync word filtering and insertion state = enableSyncWordFiltering(); RADIOLIB_ASSERT(state); From ee32b3d82ad93a87c8d0e7413ca9d64212e50a97 Mon Sep 17 00:00:00 2001 From: Ihor Nehrutsa Date: Thu, 1 Dec 2022 17:47:34 +0200 Subject: [PATCH 0299/1848] Update APRS.cpp --- src/protocols/APRS/APRS.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 7f4976b08d..3d812bc80c 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -1,4 +1,5 @@ #include "APRS.h" +#if !defined(RADIOLIB_EXCLUDE_APRS) APRSClient::APRSClient(AX25Client* ax) { _ax = ax; @@ -225,3 +226,5 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) return(_ax->sendFrame(&frameUI)); } + +#endif From 9abb3fd3964ee28000d8fba39c63cb2d6fcba621 Mon Sep 17 00:00:00 2001 From: Ihor Nehrutsa Date: Thu, 1 Dec 2022 17:47:42 +0200 Subject: [PATCH 0300/1848] Update Pager.cpp --- src/protocols/Pager/Pager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 144903a21b..01fbbe98fd 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,4 +1,5 @@ #include "Pager.h" +#if !defined(RADIOLIB_EXCLUDE_PAGER) // this is a massive hack, but we need a global-scope ISR to manage the bit reading // let's hope nobody ever tries running two POCSAG receivers at the same time @@ -731,3 +732,5 @@ uint32_t PagerClient::encodeBCH(uint32_t dat) { return(iResult); } + +#endif From 7b4c27b70260c177d8d24a2eb4b86957079b25df Mon Sep 17 00:00:00 2001 From: Federico Maggi Date: Sun, 4 Dec 2022 00:14:32 +0100 Subject: [PATCH 0301/1848] [RF69] Missing 1000.0 multipler in --- src/modules/RF69/RF69.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index bb9bd1bee5..69eb68b277 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -640,7 +640,7 @@ int16_t RF69::getFrequencyDeviation(float *freqDev) { // calculate frequency deviation from raw value obtained from register // Fdev = Fstep * Fdev(13:0) (pag. 20 of datasheet) - *freqDev = (fdev * RADIOLIB_RF69_CRYSTAL_FREQ) / + *freqDev = (1000.0 * fdev * RADIOLIB_RF69_CRYSTAL_FREQ) / (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT); return(RADIOLIB_ERR_NONE); From aa8330cf571a40241cde30e9f4cb710244d27495 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 Dec 2022 10:19:42 +0100 Subject: [PATCH 0302/1848] [Si443x] Added GFSK with BT 0.5 (#625) --- src/modules/Si443x/Si443x.cpp | 3 ++- src/modules/Si443x/Si443x.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index c498622f3b..f7e8157654 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -554,9 +554,10 @@ int16_t Si443x::setDataShaping(uint8_t sh) { case RADIOLIB_SHAPING_NONE: return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_SHAPING_0_3: + return(RADIOLIB_ERR_INVALID_ENCODING); case RADIOLIB_SHAPING_0_5: + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_GFSK, 1, 0)); case RADIOLIB_SHAPING_1_0: - /// \todo implement fiter configuration - docs claim this should be possible, but seems undocumented return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: return(RADIOLIB_ERR_INVALID_ENCODING); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 1ee97a1210..cf4f689b7b 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -777,7 +777,7 @@ class Si443x: public PhysicalLayer { /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. - Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. + Allowed values are RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping From 08de95e15e019ab4dee0486c935b5b35099275d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 5 Dec 2022 11:17:59 +0100 Subject: [PATCH 0303/1848] Access getIrqStatus() without Godmode and change the flag setting like SX126x handles it. --- src/modules/SX128x/SX128x.cpp | 7 ++++++- src/modules/SX128x/SX128x.h | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3e08409038..a9e2deb073 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -529,7 +529,12 @@ int16_t SX128x::startReceive(uint16_t timeout) { } // set DIO mapping - int16_t state = setDioIrqParams(RADIOLIB_SX128X_IRQ_RX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT | RADIOLIB_SX128X_IRQ_CRC_ERROR | RADIOLIB_SX128X_IRQ_HEADER_ERROR, RADIOLIB_SX128X_IRQ_RX_DONE); + uint16_t mask = RADIOLIB_SX128X_IRQ_RX_DONE; + + if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) + mask |= RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; + + int16_t state = setDioIrqParams(RADIOLIB_SX128X_IRQ_RX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT | RADIOLIB_SX128X_IRQ_CRC_ERROR | RADIOLIB_SX128X_IRQ_HEADER_ERROR, mask); RADIOLIB_ASSERT(state); // set buffer pointers diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index d3006ab064..5c169fe2b3 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -564,11 +564,18 @@ class SX128x: public PhysicalLayer { \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + If timeout other than infinite is set, signal will be generated on DIO1. \returns \ref status_codes */ int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF); + /*! + \brief Reads the current IRQ status. + \returns IRQ status bits + */ + uint16_t getIrqStatus(); + /*! \brief Reads data received after calling startReceive method. @@ -874,7 +881,6 @@ class SX128x: public PhysicalLayer { int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening); int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX128X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX128X_IRQ_NONE); - uint16_t getIrqStatus(); int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX128X_IRQ_ALL); int16_t setRangingRole(uint8_t role); int16_t setPacketType(uint8_t type); From 0aa59f6abcaf9d9df0585c05013b6d6bddb2f01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 6 Dec 2022 07:53:14 +0100 Subject: [PATCH 0304/1848] Fix coding style --- src/modules/SX128x/SX128x.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a9e2deb073..32a2970e56 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -531,8 +531,9 @@ int16_t SX128x::startReceive(uint16_t timeout) { // set DIO mapping uint16_t mask = RADIOLIB_SX128X_IRQ_RX_DONE; - if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) + if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) { mask |= RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; + } int16_t state = setDioIrqParams(RADIOLIB_SX128X_IRQ_RX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT | RADIOLIB_SX128X_IRQ_CRC_ERROR | RADIOLIB_SX128X_IRQ_HEADER_ERROR, mask); RADIOLIB_ASSERT(state); From 60b73d5ccd1bf85abc9a105f9b90d56299ba1ed1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 12 Dec 2022 21:07:35 +0100 Subject: [PATCH 0305/1848] [Pager] Implemented inversion for receive (#641) --- src/protocols/Pager/Pager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 01fbbe98fd..086dcf38d7 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -469,6 +469,11 @@ uint32_t PagerClient::read() { codeWord |= (uint32_t)_phy->read() << 8; codeWord |= (uint32_t)_phy->read(); + // check if we need to invert bits + if(inv) { + codeWord = ~codeWord; + } + // TODO BCH error correction here return(codeWord); } From f66a31c4f494f087355b701a70f201094ae13cf2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Dec 2022 22:35:02 +0100 Subject: [PATCH 0306/1848] [CI] Removed old skip patterns --- .github/workflows/main.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a8bb6e6f47..f121845f79 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -72,14 +72,6 @@ jobs: # Arduino Mega echo "::set-output name=options:::cpu=atmega2560" - elif [[ "${{ contains(matrix.board, 'arduino:mbed') }}" == "true" ]]; then - # Arduino Nano 33 BLE - echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" - - elif [[ "${{ contains(matrix.board, 'arduino-beta:mbed') }}" == "true" ]]; then - # Arduino Portenta H7 - echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" - elif [[ "${{ contains(matrix.board, 'arduino:megaavr:uno2018') }}" == "true" ]]; then # Arduino Uno WiFi echo "::set-output name=options:::mode=on" @@ -108,13 +100,11 @@ jobs: # ESP8266 echo "::set-output name=options:::xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K" echo "::set-output name=index-url::--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" - echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" elif [[ "${{ contains(matrix.board, 'SparkFun:apollo3') }}" == "true" ]]; then # SparkFun Apollo echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" echo "::set-output name=warnings::'none'" - echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" elif [[ "${{ contains(matrix.board, 'STMicroelectronics:stm32') }}" == "true" ]]; then # STM32 (official core) From 947ff48df64886cb80a277ec6b5899b92e5ce509 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Dec 2022 22:37:25 +0100 Subject: [PATCH 0307/1848] Added support for unofficial Raspberry Pi Pico core (#643) --- .github/workflows/main.yml | 5 +++++ src/BuildOpt.h | 39 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f121845f79..688fe19c60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,6 +31,7 @@ jobs: - stm32duino:STM32F1:mapleMini - MegaCoreX:megaavr:4809 - arduino:mbed_rp2040:pico + - rp2040:rp2040:rpipico - CubeCell:CubeCell:CubeCell-Board - MegaCore:avr:1281 - teensy:avr:teensy41 @@ -124,6 +125,10 @@ jobs: # CubeCell echo "::set-output name=index-url::--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" + elif [[ "${{ contains(matrix.board, 'rp2040:rp2040') }}" == "true" ]]; then + # CubeCell + echo "::set-output name=index-url::--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" + elif [[ "${{ contains(matrix.board, 'MegaCore:avr') }}" == "true" ]]; then # MegaCore echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5a2be397f9..e28e7a5c38 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -644,8 +644,8 @@ #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - #elif defined(ARDUINO_ARCH_RP2040) - // Raspberry Pi Pico + #elif defined(ARDUINO_ARCH_MBED_RP2040) + // Raspberry Pi Pico (official mbed core) #define RADIOLIB_PLATFORM "Raspberry Pi Pico" #define RADIOLIB_PIN_TYPE pin_size_t #define RADIOLIB_PIN_MODE PinMode @@ -683,6 +683,41 @@ #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(ARDUINO_ARCH_RP2040) + // Raspberry Pi Pico (unofficial core) + #define RADIOLIB_PLATFORM "Raspberry Pi Pico (unofficial)" + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + #elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) // CubeCell #define RADIOLIB_PLATFORM "CubeCell" From c1674fba823ec0537e802e4d80f3a1162241d9f3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Dec 2022 22:42:07 +0100 Subject: [PATCH 0308/1848] Added unofficial RP2040 to list of supported platforms (CI_BUILD_ALL) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index adf6863b93..1885feb900 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,8 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__MegaCore__](https://github.com/MCUdude/MegaCore) - AVR (ATmega1281, ATmega640 etc.) * __Raspberry Pi__ - * [__RP2040__](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect + * [__RP2040__ (official core)](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect + * [__RP2040__ (unofficial core)](https://github.com/earlephilhower/arduino-pico) - Raspberry Pi Pico/RP2040-based boards * [__Raspberry Pi__](https://github.com/me-no-dev/RasPiArduino) - Arduino framework for RaspberryPI * __Heltec__ From 132c2b3b82982cf4a93ac3e65694abb59ad6f8cf Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 15 Dec 2022 17:37:41 +0100 Subject: [PATCH 0309/1848] Fixed inversion logic and inverted frame sync word (#641) --- src/protocols/Pager/Pager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 086dcf38d7..72a6ab597e 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -235,7 +235,11 @@ int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t // now set up the direct mode reception Module* mod = _phy->getMod(); mod->pinMode(pin, INPUT); - _phy->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + if(inv) { + _phy->setDirectSyncWord(~RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + } else { + _phy->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + } _phy->setDirectAction(PagerClientReadBit); _phy->receiveDirect(); @@ -445,7 +449,7 @@ void PagerClient::write(uint32_t codeWord) { } // finally, check if inversion is enabled - if(inv) { + if(!inv) { change = -change; } From 47163f4398aabae8c92a819608050aafcb40adcd Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 20 Dec 2022 20:58:19 +0100 Subject: [PATCH 0310/1848] [SX126x] Make begin parameter docs consistent This: - Updates syncWord comments after changing it from uint16_t to uint8_t in commit 55aff74a ([SX126x] Changed pin mapping, added reset, changed LoRa sync word to 1B). - Adds missing useRegulatorLDO comments forgoten in commit ea85a663 ([SX126x] Pass useRegulatorLDO to SX1262/SX1261/SX1268). - Makes useRegulatorLDO comments the same in all places (using the more explicit version). - Fixes a typo in the doxygen \parma -> \param command. --- src/modules/LLCC68/LLCC68.h | 4 +++- src/modules/SX126x/SX1262.h | 6 ++++-- src/modules/SX126x/SX1268.h | 6 ++++-- src/modules/SX126x/SX126x.h | 4 ++-- src/modules/SX128x/SX128x.h | 4 ++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index f8dd221926..2810041d38 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -33,7 +33,7 @@ class LLCC68: public SX1262 { \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. @@ -41,6 +41,8 @@ class LLCC68: public SX1262 { \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index cac19280cc..dbe6c1d203 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -38,7 +38,7 @@ class SX1262: public SX126x { \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. @@ -46,6 +46,8 @@ class SX1262: public SX126x { \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); @@ -63,7 +65,7 @@ class SX1262: public SX126x { \param power Output power in dBm. Defaults to 10 dBm. - \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 7b454baca2..2d4b90d9e8 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -38,7 +38,7 @@ class SX1268: public SX126x { \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. @@ -46,6 +46,8 @@ class SX1268: public SX126x { \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); @@ -63,7 +65,7 @@ class SX1268: public SX126x { \param power Output power in dBm. Defaults to 10 dBm. - \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 8e80bebfc6..a1c0eeafea 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -391,7 +391,7 @@ class SX126x: public PhysicalLayer { \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO use the LDO instead of DC-DC converter (default false). This is necessary for some modules such as the LAMBDA from RF solutions. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ @@ -410,7 +410,7 @@ class SX126x: public PhysicalLayer { \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO use the LDO instead of DC-DC converter (default false). This is necessary for some modules such as the LAMBDA from RF solutions. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 5c169fe2b3..c367013f4d 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -398,7 +398,7 @@ class SX128x: public PhysicalLayer { \param power Output power in dBm. Defaults to 10 dBm. - \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. \returns \ref status_codes */ @@ -432,7 +432,7 @@ class SX128x: public PhysicalLayer { \param power Output power in dBm. Defaults to 10 dBm. - \parma preambleLength FLRC preamble length in bits. Defaults to 16 bits. + \param preambleLength FLRC preamble length in bits. Defaults to 16 bits. \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. From dfbe6934bb452d7745acc3cf41fab0e4a6315881 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 20 Dec 2022 21:03:40 +0100 Subject: [PATCH 0311/1848] [SX126x] Set DIO2 to RF switch by default for FSK too In commit a1f94d9f ([SX126x] Set DIO2 to RF switch by default), this was changed for LoRa modulation in begin(), but since this is really a board-specific attribute, independent of the modulation used, there is no reason to have a different default for FSK (so this was probably just forgotten). --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e77e402814..f5de00b3d3 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -150,7 +150,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL state = setCRC(2); RADIOLIB_ASSERT(state); - state = setDio2AsRfSwitch(false); + state = setDio2AsRfSwitch(true); RADIOLIB_ASSERT(state); return(state); From e073da15da3ae9e6addc0f8681cecb1a53affb51 Mon Sep 17 00:00:00 2001 From: Mitrokhin Anton Date: Thu, 22 Dec 2022 12:21:01 +0700 Subject: [PATCH 0312/1848] Fix FSK Stream mode TX and RX --- .../Stream_Transmit/Stream_Transmit.ino | 16 ++++++++++++---- src/modules/SX127x/SX127x.cpp | 19 ------------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index 26eb7f3aeb..2d638fa483 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -86,6 +86,8 @@ volatile bool transmittedFlag = false; // disable interrupt when it's not needed volatile bool enableInterrupt = true; +bool isFifoEmpty = false; + // how many bytes are there in total volatile int totalLength = longPacket.length(); @@ -104,13 +106,19 @@ void fifoAdd(void) { if(!enableInterrupt) { return; } - - // add more bytes to the transmit buffer - uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str(); - transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength); + isFifoEmpty = true; } void loop() { + if (isFifoEmpty) { + enableInterrupt = false; + // add more bytes to the transmit buffer + uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str(); + transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength); + enableInterrupt = true; + isFifoEmpty = false; + } + // check if the previous transmission finished if(transmittedFlag) { // disable the interrupt service routine while diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index a3a94345b0..6cdb607ffc 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -478,16 +478,9 @@ bool SX127x::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { len = RADIOLIB_SX127X_FIFO_THRESH - 1; } - // clear interrupt flags - clearIRQFlags(); - // copy the bytes to the FIFO _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len); - // this is a hack, but it seems Rx FIFO level is getting triggered 1 byte before it should - // we just add a padding byte that we can drop without consequence - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, '/'); - // we're not done yet return(false); } @@ -507,12 +500,6 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) _mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr); (*rcvLen) += (len); - // dump the padding byte - _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); - - // clear flags - clearIRQFlags(); - // check if we're done if(*rcvLen >= totalLen) { return(true); @@ -582,12 +569,6 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); - // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should - // just add a padding byte that can be dropped without consequence - if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, '/'); - } - // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); From 81c5504260cb466d21db309b7829896966054ee2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 16:18:50 +0100 Subject: [PATCH 0313/1848] [PHY] Added debug direct mode output --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index e1a881519f..0c957e47c7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -235,6 +235,10 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { if(!_gotSync) { _syncBuffer <<= 1; _syncBuffer |= bit; + + RADIOLIB_VERBOSE_PRINT("S\t"); + RADIOLIB_VERBOSE_PRINTLN(_syncBuffer, HEX); + if((_syncBuffer & _directSyncWordMask) == _directSyncWord) { _gotSync = true; _bufferWritePos = 0; @@ -254,6 +258,9 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check complete byte if(_bufferBitPos == 8) { _buffer[_bufferWritePos] = Module::flipBits(_buffer[_bufferWritePos]); + RADIOLIB_VERBOSE_PRINT("R\t"); + RADIOLIB_VERBOSE_PRINTLN(_buffer[_bufferWritePos], HEX); + _bufferWritePos++; _bufferBitPos = 0; } From 607ae1035c3a6694a4fd6c2c5b93c2faa585c099 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 16:19:10 +0100 Subject: [PATCH 0314/1848] [Pager] Fixed inversion logic (#641) --- src/protocols/Pager/Pager.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 72a6ab597e..cc7591d8b7 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -235,11 +235,16 @@ int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t // now set up the direct mode reception Module* mod = _phy->getMod(); mod->pinMode(pin, INPUT); - if(inv) { + + // set direct sync word to the frame sync word + // the logic here is inverted, because modules like SX1278 + // assume high frequency to be logic 1, which is opposite to POCSAG + if(!inv) { _phy->setDirectSyncWord(~RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); } else { _phy->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); } + _phy->setDirectAction(PagerClientReadBit); _phy->receiveDirect(); @@ -449,7 +454,7 @@ void PagerClient::write(uint32_t codeWord) { } // finally, check if inversion is enabled - if(!inv) { + if(inv) { change = -change; } @@ -474,10 +479,15 @@ uint32_t PagerClient::read() { codeWord |= (uint32_t)_phy->read(); // check if we need to invert bits - if(inv) { + // the logic here is inverted, because modules like SX1278 + // assume high frequency to be logic 1, which is opposite to POCSAG + if(!inv) { codeWord = ~codeWord; } + RADIOLIB_VERBOSE_PRINT("R\t"); + RADIOLIB_VERBOSE_PRINTLN(codeWord, HEX); + // TODO BCH error correction here return(codeWord); } From 18fefc0ca9b4a600f352de73a8f4927f271e89aa Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 18:17:41 +0100 Subject: [PATCH 0315/1848] [SX127x] Removed unnecessary volatile --- src/modules/SX127x/SX127x.cpp | 2 +- src/modules/SX127x/SX127x.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6cdb607ffc..9930841ef7 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -462,7 +462,7 @@ void SX127x::clearFifoFullAction() { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4); } -bool SX127x::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { +bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) { // subtract first (this may be the first time we get to modify the remaining length) *remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index ba33b78ab5..302fabf4c0 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -776,7 +776,7 @@ class SX127x: public PhysicalLayer { \returns True when a complete packet is sent, false if more data is needed. */ - bool fifoAdd(uint8_t* data, int totalLen, volatile int* remLen); + bool fifoAdd(uint8_t* data, int totalLen, int* remLen); /*! \brief Set interrupt service routine function to call when FIFO is sufficently full to read. From 0144faf02a0f260aa6c49274d05aa1887b578404 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 18:18:16 +0100 Subject: [PATCH 0316/1848] [RF69] Fixed stream mode (#651) --- src/modules/RF69/RF69.cpp | 15 +-------------- src/modules/RF69/RF69.h | 2 +- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 69eb68b277..ec1f3c421c 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -319,7 +319,7 @@ void RF69::clearFifoFullAction() { _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, 0x00, 5, 4); } -bool RF69::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { +bool RF69::fifoAdd(uint8_t* data, int totalLen, int* remLen) { // subtract first (this may be the first time we get to modify the remaining length) *remLen -= RADIOLIB_RF69_FIFO_THRESH - 1; @@ -335,16 +335,9 @@ bool RF69::fifoAdd(uint8_t* data, int totalLen, volatile int* remLen) { len = RADIOLIB_RF69_FIFO_THRESH - 1; } - // clear interrupt flags - clearIRQFlags(); - // copy the bytes to the FIFO _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, &data[totalLen - *remLen], len); - // this is a hack, but it seems Rx FIFO level is getting triggered 1 byte before it should - // we just add a padding byte that we can drop without consequence - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); - // we're not done yet return(false); } @@ -364,12 +357,6 @@ bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { _mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, len, dataPtr); (*rcvLen) += (len); - // dump the padding byte - _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); - - // clear flags - clearIRQFlags(); - // check if we're done if(*rcvLen >= totalLen) { return(true); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 7cb41d9021..979f48454c 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -670,7 +670,7 @@ class RF69: public PhysicalLayer { \returns True when a complete packet is sent, false if more data is needed. */ - bool fifoAdd(uint8_t* data, int totalLen, volatile int* remLen); + bool fifoAdd(uint8_t* data, int totalLen, int* remLen); /*! \brief Set interrupt service routine function to call when FIFO is sufficently full to read. From 8b8c6614aa1a92d5c3e91f8c6cac81d4d49cf62f Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 18:18:55 +0100 Subject: [PATCH 0317/1848] Added VS code to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 58d337967a..374da672e5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ *.tags *.tags1 +# VS Code +.vscode + # Jetbrain IDEs .idea From 395844922c5d88d5db0481a9c91479931172428d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 18:19:54 +0100 Subject: [PATCH 0318/1848] [Stream] Cleaned up transmit example --- .../Stream_Transmit/Stream_Transmit.ino | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index 2d638fa483..02c6bec627 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -80,19 +80,20 @@ void setup() { transmissionState = radio.startTransmit(longPacket); } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - // disable interrupt when it's not needed volatile bool enableInterrupt = true; -bool isFifoEmpty = false; +// flag to indicate we can keep adding more bytes to FIFO +volatile bool fifoEmpty = false; + +// flag to indicate that a packet was sent +bool transmittedFlag = false; // how many bytes are there in total -volatile int totalLength = longPacket.length(); +int totalLength = longPacket.length(); // counter to keep track of how many bytes still need to be sent -volatile int remLength = totalLength; +int remLength = totalLength; // this function is called when the radio transmit buffer // is empty and ready to be refilled @@ -106,25 +107,31 @@ void fifoAdd(void) { if(!enableInterrupt) { return; } - isFifoEmpty = true; + + // we can send more bytes + fifoEmpty = true; } void loop() { - if (isFifoEmpty) { + if(fifoEmpty) { + // disable the interrupt service routine while + // processing the data enableInterrupt = false; + + // reset flag + fifoEmpty = false; + // add more bytes to the transmit buffer uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str(); transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength); + + // we're ready to send more packets, + // enable interrupt service routine enableInterrupt = true; - isFifoEmpty = false; } // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -156,9 +163,5 @@ void loop() { // send another one Serial.print(F("[SX1278] Sending another long packet ... ")); transmissionState = radio.startTransmit(longPacket); - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } From 088207df4cd68711ee4b72fa52fc257bc6a8c0a1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Jan 2023 18:03:48 +0100 Subject: [PATCH 0319/1848] [SX1280] Only check ranging address on slave --- src/modules/SX128x/SX1280.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 69fbea972d..293e588f41 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -57,13 +57,15 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) { RADIOLIB_ASSERT(state); // check all address bits - uint8_t regValue; - state = readRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); - RADIOLIB_ASSERT(state); - regValue &= 0b00111111; - regValue |= 0b11000000; - state = writeRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); - RADIOLIB_ASSERT(state); + if(!master) { + uint8_t regValue; + state = readRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + RADIOLIB_ASSERT(state); + regValue &= 0b00111111; + regValue |= 0b11000000; + state = writeRegister(RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + RADIOLIB_ASSERT(state); + } // set remaining parameter values uint32_t addrReg = RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3; From a0884bf1207c4eea0618c435ef0cd27deeea417d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Jan 2023 18:31:03 +0100 Subject: [PATCH 0320/1848] [SX128x] Added option to set custom ranging calibration (#293) --- .../SX128x/SX128x_Ranging/SX128x_Ranging.ino | 19 ++++++++++++-- src/modules/SX128x/SX1280.cpp | 25 ++++++++++++------- src/modules/SX128x/SX1280.h | 8 ++++-- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino index 2776f4f6df..d7427880ba 100644 --- a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino +++ b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -6,7 +6,10 @@ distance between the modules using time-of-flight measurement. - Only SX1280 and SX1282 support ranging! + Only SX1280 and SX1282 without external RF switch support ranging! + + Note that to get accurate ranging results, calibration is needed! + The process is described in Semtech SX1280 Application Note AN1200.29 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem @@ -57,12 +60,24 @@ void loop() { int state = radio.range(false, 0x12345678); */ + // if ranging calibration is known, it can be provided + // this should improve the accuracy and precision + /* + uint16_t calibration[3][6] = { + { 10299, 10271, 10244, 10242, 10230, 10246 }, + { 11486, 11474, 11453, 11426, 11417, 11401 }, + { 13308, 13493, 13528, 13515, 13430, 13376 } + }; + + int state = radio.range(true, 0x12345678, calibration); + */ + if (state == RADIOLIB_ERR_NONE) { // ranging finished successfully Serial.println(F("success!")); Serial.print(F("[SX1280] Distance:\t\t\t")); Serial.print(radio.getRangingResult()); - Serial.println(F(" meters")); + Serial.println(F(" meters (raw)")); } else if (state == RADIOLIB_ERR_RANGING_TIMEOUT) { // timed out waiting for ranging packet diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 293e588f41..3d963c8d71 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -5,9 +5,9 @@ SX1280::SX1280(Module* mod) : SX1281(mod) { } -int16_t SX1280::range(bool master, uint32_t addr) { +int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { // start ranging - int16_t state = startRanging(master, addr); + int16_t state = startRanging(master, addr, calTable); RADIOLIB_ASSERT(state); // wait until ranging is finished @@ -31,7 +31,7 @@ int16_t SX1280::range(bool master, uint32_t addr) { return(state); } -int16_t SX1280::startRanging(bool master, uint32_t addr) { +int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]) { // check active modem uint8_t modem = getPacketType(); if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { @@ -86,23 +86,30 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) { state = setDioIrqParams(irqMask, irqDio1); RADIOLIB_ASSERT(state); - // set calibration values - uint8_t index = (_sf >> 4) - 5; - static const uint16_t calTable[3][6] = { + // this is the default calibration from AN1200.29 + uint16_t calTbl[3][6] = { { 10299, 10271, 10244, 10242, 10230, 10246 }, { 11486, 11474, 11453, 11426, 11417, 11401 }, { 13308, 13493, 13528, 13515, 13430, 13376 } }; + + // check if user provided some custom calibration + if(calTable != NULL) { + memcpy(calTbl, calTable, sizeof(calTbl)); + } + + // set calibration values + uint8_t index = (_sf >> 4) - 5; uint16_t val = 0; switch(_bw) { case(RADIOLIB_SX128X_LORA_BW_406_25): - val = calTable[0][index]; + val = calTbl[0][index]; break; case(RADIOLIB_SX128X_LORA_BW_812_50): - val = calTable[1][index]; + val = calTbl[1][index]; break; case(RADIOLIB_SX128X_LORA_BW_1625_00): - val = calTable[2][index]; + val = calTbl[2][index]; break; default: return(RADIOLIB_ERR_INVALID_BANDWIDTH); diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index f72d125a95..10f48ab11c 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -30,9 +30,11 @@ class SX1280: public SX1281 { \param addr Ranging address to be used. + \param calTable Ranging calibration table - set to NULL to use the default. + \returns \ref status_codes */ - int16_t range(bool master, uint32_t addr); + int16_t range(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); /*! \brief Interrupt-driven ranging method. @@ -41,9 +43,11 @@ class SX1280: public SX1281 { \param addr Ranging address to be used. + \param calTable Ranging calibration table - set to NULL to use the default. + \returns \ref status_codes */ - int16_t startRanging(bool master, uint32_t addr); + int16_t startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); /*! \brief Gets ranging result of the last ranging exchange. From 3a34594b5b7ba647acda14a03fa8d3c03a6855ac Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 Jan 2023 20:20:58 +0100 Subject: [PATCH 0321/1848] [SX126x] Fixed incorrect OCP step in documentation (#654) --- src/modules/SX126x/SX126x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index a1c0eeafea..a96c510375 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -657,7 +657,7 @@ class SX126x: public PhysicalLayer { int16_t setSyncWord(uint8_t syncWord, uint8_t controlBits = 0x44); /*! - \brief Sets current protection limit. Can be set in 0.25 mA steps. + \brief Sets current protection limit. Can be set in 2.5 mA steps. \param currentLimit current protection limit to be set in mA. From 0cd9dd298349f3a113e79f0b36f45ec8621f5cbe Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 4 Jan 2023 10:22:06 +0100 Subject: [PATCH 0322/1848] [SX126x] Added note about allowed OCP range (#654) --- src/modules/SX126x/SX126x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index a96c510375..b56bcb29cd 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -659,7 +659,7 @@ class SX126x: public PhysicalLayer { /*! \brief Sets current protection limit. Can be set in 2.5 mA steps. - \param currentLimit current protection limit to be set in mA. + \param currentLimit current protection limit to be set in mA. Allowed values range from 0 to 140. \returns \ref status_codes */ From 6666060d52b993f36837d2361d5175f7877fd35b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 7 Jan 2023 22:21:16 +0100 Subject: [PATCH 0323/1848] Removed unnecessary interrupt enable (#657) --- .../CC1101_Receive_Interrupt.ino | 16 -------------- .../CC1101_Transmit_Interrupt.ino | 16 -------------- .../RF69_Receive_Interrupt.ino | 17 -------------- .../RF69_Transmit_Interrupt.ino | 16 -------------- ...x_Channel_Activity_Detection_Interrupt.ino | 16 -------------- .../SX126x_PingPong/SX126x_PingPong.ino | 18 +-------------- .../SX126x_Receive_Interrupt.ino | 17 -------------- .../SX126x_Transmit_Interrupt.ino | 16 -------------- ...x_Channel_Activity_Detection_Interrupt.ino | 22 ------------------- ...27x_Channel_Activity_Detection_Receive.ino | 22 ------------------- .../SX127x_Receive_Interrupt.ino | 17 -------------- .../SX127x_Transmit_Interrupt.ino | 16 -------------- .../SX128x_Receive_Interrupt.ino | 17 -------------- .../SX128x_Transmit_Interrupt.ino | 16 -------------- .../Si443x_Receive_Interrupt.ino | 17 -------------- .../Si443x_Transmit_Interrupt.ino | 16 -------------- .../nRF24_Receive_Interrupt.ino | 17 -------------- .../nRF24_Transmit_Interrupt.ino | 16 -------------- 18 files changed, 1 insertion(+), 307 deletions(-) diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 65ae79a26f..43250baed1 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -75,9 +75,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -86,11 +83,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -98,10 +90,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -147,10 +135,6 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 5f9437dae3..6afb1bd3c0 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -71,9 +71,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -82,11 +79,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -94,10 +86,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -136,9 +124,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index da520351b5..fc2c5804b0 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -67,9 +67,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -78,11 +75,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -90,10 +82,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -134,10 +122,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 214474f9c2..de73535d19 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -84,9 +84,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -95,11 +92,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -107,10 +99,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -149,9 +137,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index 91580d0e79..651da66b91 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -64,9 +64,6 @@ void setup() { // flag to indicate that a packet was detected or CAD timed out volatile bool scanFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -75,11 +72,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // something happened, set the flag scanFlag = true; } @@ -87,10 +79,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(scanFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag scanFlag = false; @@ -121,9 +109,5 @@ void loop() { Serial.print(F("failed, code ")); Serial.println(state); } - - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index e3ed4e9651..fcdff8a21f 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -35,9 +35,6 @@ int transmissionState = RADIOLIB_ERR_NONE; // flag to indicate transmission or reception state bool transmitFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // flag to indicate that a packet was sent or received volatile bool operationDone = false; @@ -46,11 +43,6 @@ volatile bool operationDone = false; // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent or received a packet, set the flag operationDone = true; } @@ -95,10 +87,6 @@ void setup() { void loop() { // check if the previous operation finished if(operationDone) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag operationDone = false; @@ -153,10 +141,6 @@ void loop() { transmissionState = radio.startTransmit("Hello World!"); transmitFlag = true; } - - // we're ready to process more packets, - // enable interrupt service routine - enableInterrupt = true; - + } } diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 1b3daefd0b..2e2c2faa46 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -81,9 +81,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -92,11 +89,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -104,10 +96,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -152,10 +140,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 0bd011c702..850ddbb87c 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -73,9 +73,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -84,11 +81,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -96,10 +88,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -138,9 +126,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 1c41ed3757..21ab7de509 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -70,9 +70,6 @@ volatile bool timeoutFlag = false; // flag to indicate that a preamble was detected volatile bool detectedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when no preamble // is detected within timeout period // IMPORTANT: this function MUST be 'void' type @@ -81,11 +78,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlagTimeout(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we timed out, set the flag timeoutFlag = true; } @@ -98,11 +90,6 @@ void setFlagTimeout(void) { ICACHE_RAM_ATTR #endif void setFlagDetected(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a preamble, set the flag detectedFlag = true; } @@ -110,10 +97,6 @@ void setFlagDetected(void) { void loop() { // check if we need to restart channel activity detection if(detectedFlag || timeoutFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // check if we got a preamble if(detectedFlag) { // LoRa preamble was detected @@ -138,10 +121,5 @@ void loop() { // reset flags timeoutFlag = false; detectedFlag = false; - - // enable interrupts again - enableInterrupt = true; - } - } diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino index 4914aba41c..6186227a14 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -76,9 +76,6 @@ volatile bool timeoutFlag = false; // flag to indicate that a preamble was detected volatile bool detectedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // flag to indicate if we are currently receiving bool receiving = false; @@ -90,11 +87,6 @@ bool receiving = false; ICACHE_RAM_ATTR #endif void setFlagTimeout(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we timed out, set the flag timeoutFlag = true; } @@ -107,11 +99,6 @@ void setFlagTimeout(void) { ICACHE_RAM_ATTR #endif void setFlagDetected(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a preamble, set the flag detectedFlag = true; } @@ -120,10 +107,6 @@ void loop() { // check if we need to restart channel activity detection if(detectedFlag || timeoutFlag) { int state = RADIOLIB_ERR_NONE; - - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; // check ongoing reception if(receiving) { @@ -217,10 +200,5 @@ void loop() { // reset flags timeoutFlag = false; detectedFlag = false; - - // enable interrupts again - enableInterrupt = true; - } - } diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index e322897003..6c0997bcf6 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -78,9 +78,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -89,11 +86,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -101,10 +93,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -154,10 +142,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index ec3f03a384..97b6e31964 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -70,9 +70,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -81,11 +78,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -93,10 +85,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -135,9 +123,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 77d452c6fc..211a906931 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -78,9 +78,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -89,11 +86,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -101,10 +93,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -155,10 +143,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index e8d78941c5..1784397060 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -70,9 +70,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -81,11 +78,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -93,10 +85,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -131,9 +119,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index 061ee09462..cb9c2d69b3 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -69,9 +69,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -80,11 +77,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -92,10 +84,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -130,10 +118,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 317932fcd0..d2edc6c87b 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -68,9 +68,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -79,11 +76,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -91,10 +83,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -129,9 +117,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index 9e73394a50..ccca2798b6 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -87,9 +87,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is received by the module // IMPORTANT: this function MUST be 'void' type @@ -98,11 +95,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we got a packet, set the flag receivedFlag = true; } @@ -110,10 +102,6 @@ void setFlag(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag receivedFlag = false; @@ -144,10 +132,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 95cba472c3..cdcbf997f2 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -83,9 +83,6 @@ void setup() { // flag to indicate that a packet was sent volatile bool transmittedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // this function is called when a complete packet // is transmitted by the module // IMPORTANT: this function MUST be 'void' type @@ -94,11 +91,6 @@ volatile bool enableInterrupt = true; ICACHE_RAM_ATTR #endif void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent a packet, set the flag transmittedFlag = true; } @@ -106,10 +98,6 @@ void setFlag(void) { void loop() { // check if the previous transmission finished if(transmittedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag transmittedFlag = false; @@ -148,9 +136,5 @@ void loop() { 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.startTransmit(byteArr, 8); */ - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } } From 27c1eb715aed100af43c59189d1fb7560c9c6689 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 7 Jan 2023 22:31:20 +0100 Subject: [PATCH 0324/1848] Removed remaining enable interrupt (#657) --- .../SX127x/SX127x_PingPong/SX127x_PingPong.ino | 17 ----------------- .../Stream/Stream_Receive/Stream_Receive.ino | 17 ----------------- .../Stream/Stream_Transmit/Stream_Transmit.ino | 16 ---------------- 3 files changed, 50 deletions(-) diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index e403c9027d..26d1132b50 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -32,9 +32,6 @@ int transmissionState = RADIOLIB_ERR_NONE; // flag to indicate transmission or reception state bool transmitFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // flag to indicate that a packet was sent or received volatile bool operationDone = false; @@ -43,11 +40,6 @@ volatile bool operationDone = false; // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! void setFlag(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we sent or received packet, set the flag operationDone = true; } @@ -92,10 +84,6 @@ void setup() { void loop() { // check if the previous operation finished if(operationDone) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag operationDone = false; @@ -150,10 +138,5 @@ void loop() { transmissionState = radio.startTransmit("Hello World!"); transmitFlag = true; } - - // we're ready to process more packets, - // enable interrupt service routine - enableInterrupt = true; - } } diff --git a/examples/Stream/Stream_Receive/Stream_Receive.ino b/examples/Stream/Stream_Receive/Stream_Receive.ino index 2dc723ed62..39fc1bb636 100644 --- a/examples/Stream/Stream_Receive/Stream_Receive.ino +++ b/examples/Stream/Stream_Receive/Stream_Receive.ino @@ -86,9 +86,6 @@ void setup() { // flag to indicate that a packet was received volatile bool receivedFlag = false; -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // how many bytes are there in total const int totalLength = 512; @@ -106,11 +103,6 @@ volatile uint8_t rxBuffer[totalLength + 1]; ICACHE_RAM_ATTR #endif void fifoGet(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // set the flag when we receive the full packet receivedFlag = radio.fifoGet(rxBuffer, totalLength, &receivedLength); } @@ -118,10 +110,6 @@ void fifoGet(void) { void loop() { // check if the flag is set if(receivedFlag) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // packet was successfully received Serial.println(F("[SX1278] Received packet!")); @@ -135,10 +123,5 @@ void loop() { // put module back to listen mode radio.startReceive(); - - // we're ready to receive more packets, - // enable interrupt service routine - enableInterrupt = true; } - } diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index 02c6bec627..4789a6ebed 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -80,9 +80,6 @@ void setup() { transmissionState = radio.startTransmit(longPacket); } -// disable interrupt when it's not needed -volatile bool enableInterrupt = true; - // flag to indicate we can keep adding more bytes to FIFO volatile bool fifoEmpty = false; @@ -103,31 +100,18 @@ int remLength = totalLength; ICACHE_RAM_ATTR #endif void fifoAdd(void) { - // check if the interrupt is enabled - if(!enableInterrupt) { - return; - } - // we can send more bytes fifoEmpty = true; } void loop() { if(fifoEmpty) { - // disable the interrupt service routine while - // processing the data - enableInterrupt = false; - // reset flag fifoEmpty = false; // add more bytes to the transmit buffer uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str(); transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength); - - // we're ready to send more packets, - // enable interrupt service routine - enableInterrupt = true; } // check if the previous transmission finished From 02de83f94194d6728fc406809e66f62bca9e1539 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 8 Jan 2023 15:10:48 +0100 Subject: [PATCH 0325/1848] [PHY] Made virtual overloads non-pure --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 154 ++++++++++++++---- src/protocols/PhysicalLayer/PhysicalLayer.h | 34 ++-- 2 files changed, 137 insertions(+), 51 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 0c957e47c7..7d45f9e0b7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -50,42 +50,45 @@ int16_t PhysicalLayer::transmit(const char* str, uint8_t addr) { return(transmit((uint8_t*)str, strlen(str), addr)); } -int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) { - return(startTransmit(str.c_str(), addr)); -} - -int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { - return(startTransmit((uint8_t*)str, strlen(str), addr)); +int16_t PhysicalLayer::transmit(uint8_t* data, size_t len, uint8_t addr) { + (void)data; + (void)len; + (void)addr; + return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::readData(String& str, size_t len) { +int16_t PhysicalLayer::receive(String& str, size_t len) { int16_t state = RADIOLIB_ERR_NONE; - // read the number of actually received bytes - size_t length = getPacketLength(); - - if((len < length) && (len != 0)) { - // user requested less bytes than were received, this is allowed (but frowned upon) - // requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive()) - length = len; - } + // user can override the length of data to read + size_t length = len; // build a temporary buffer #if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else - uint8_t* data = new uint8_t[length + 1]; + uint8_t* data = NULL; + if(length == 0) { + data = new uint8_t[_maxPacketLength + 1]; + } else { + data = new uint8_t[length + 1]; + } if(!data) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } #endif - // read the received data - state = readData(data, length); + // attempt packet reception + state = receive(data, length); // any of the following leads to at least some data being available // let's leave the decision of whether to keep it or not up to the user if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) { + // read the number of actually received bytes (for unknown packets) + if(len == 0) { + length = getPacketLength(false); + } + // add null terminator data[length] = 0; @@ -101,38 +104,63 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { return(state); } -int16_t PhysicalLayer::receive(String& str, size_t len) { +int16_t PhysicalLayer::receive(uint8_t* data, size_t len) { + (void)data; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::standby() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) { + return(startTransmit(str.c_str(), addr)); +} + +int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { + return(startTransmit((uint8_t*)str, strlen(str), addr)); +} + +int16_t PhysicalLayer::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + (void)data; + (void)len; + (void)addr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::finishTransmit() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::readData(String& str, size_t len) { int16_t state = RADIOLIB_ERR_NONE; - // user can override the length of data to read - size_t length = len; + // read the number of actually received bytes + size_t length = getPacketLength(); + + if((len < length) && (len != 0)) { + // user requested less bytes than were received, this is allowed (but frowned upon) + // requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive()) + length = len; + } // build a temporary buffer #if defined(RADIOLIB_STATIC_ONLY) uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else - uint8_t* data = NULL; - if(length == 0) { - data = new uint8_t[_maxPacketLength + 1]; - } else { - data = new uint8_t[length + 1]; - } + uint8_t* data = new uint8_t[length + 1]; if(!data) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } #endif - // attempt packet reception - state = receive(data, length); + // read the received data + state = readData(data, length); // any of the following leads to at least some data being available // let's leave the decision of whether to keep it or not up to the user if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) { - // read the number of actually received bytes (for unknown packets) - if(len == 0) { - length = getPacketLength(false); - } - // add null terminator data[length] = 0; @@ -148,10 +176,55 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { return(state); } +int16_t PhysicalLayer::readData(uint8_t* data, size_t len) { + (void)data; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::transmitDirect(uint32_t frf) { + (void)frf; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::receiveDirect() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setFrequency(float freq) { + (void)freq; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setBitRate(float br) { + (void)br; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setFrequencyDeviation(float freqDev) { + (void)freqDev; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setDataShaping(uint8_t sh) { + (void)sh; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setEncoding(uint8_t encoding) { + (void)encoding; + return(RADIOLIB_ERR_UNSUPPORTED); +} + float PhysicalLayer::getFreqStep() const { return(_freqStep); } +size_t PhysicalLayer::getPacketLength(bool update) { + (void)update; + return(0); +} + int32_t PhysicalLayer::random(int32_t max) { if(max == 0) { return(0); @@ -180,6 +253,10 @@ int32_t PhysicalLayer::random(int32_t min, int32_t max) { return(PhysicalLayer::random(max - min) + min); } +uint8_t PhysicalLayer::randomByte() { + return(0); +} + int16_t PhysicalLayer::startDirect() { // disable encodings int16_t state = setEncoding(RADIOLIB_ENCODING_NRZ); @@ -266,6 +343,15 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { } } } + +void PhysicalLayer::setDirectAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::readBit(RADIOLIB_PIN_TYPE pin) { + (void)pin; +} + #endif int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 9305cf0abb..a5886f5336 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -71,7 +71,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) = 0; + virtual int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); /*! \brief Arduino String receive method. @@ -89,7 +89,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t standby() = 0; + virtual int16_t standby(); /*! \brief Binary receive method. Must be implemented in module class. @@ -100,7 +100,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t receive(uint8_t* data, size_t len) = 0; + virtual int16_t receive(uint8_t* data, size_t len); /*! \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. @@ -137,14 +137,14 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) = 0; + virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); /*! \brief Clean up after transmission is done. \returns \ref status_codes */ - virtual int16_t finishTransmit() = 0; + virtual int16_t finishTransmit(); /*! \brief Reads data that was received after calling startReceive method. @@ -168,7 +168,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t readData(uint8_t* data, size_t len) = 0; + virtual int16_t readData(uint8_t* data, size_t len); /*! \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. @@ -178,7 +178,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t transmitDirect(uint32_t frf = 0) = 0; + virtual int16_t transmitDirect(uint32_t frf = 0); /*! \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. @@ -186,7 +186,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t receiveDirect() = 0; + virtual int16_t receiveDirect(); // configuration methods @@ -197,7 +197,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setFrequency(float freq) = 0; + virtual int16_t setFrequency(float freq); /*! \brief Sets FSK bit rate. Only available in FSK mode. Must be implemented in module class. @@ -206,7 +206,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setBitRate(float br) = 0; + virtual int16_t setBitRate(float br); /*! \brief Sets FSK frequency deviation from carrier frequency. Only available in FSK mode. Must be implemented in module class. @@ -215,7 +215,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setFrequencyDeviation(float freqDev) = 0; + virtual int16_t setFrequencyDeviation(float freqDev); /*! \brief Sets GFSK data shaping. Only available in FSK mode. Must be implemented in module class. @@ -224,7 +224,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setDataShaping(uint8_t sh) = 0; + virtual int16_t setDataShaping(uint8_t sh); /*! \brief Sets FSK data encoding. Only available in FSK mode. Must be implemented in module class. @@ -233,7 +233,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setEncoding(uint8_t encoding) = 0; + virtual int16_t setEncoding(uint8_t encoding); /*! \brief Gets the module frequency step size that was set in constructor. @@ -249,7 +249,7 @@ class PhysicalLayer { \returns Length of last received packet in bytes. */ - virtual size_t getPacketLength(bool update = true) = 0; + virtual size_t getPacketLength(bool update = true); /*! \brief Get truly random number in range 0 - max. @@ -276,7 +276,7 @@ class PhysicalLayer { \returns TRNG byte. */ - virtual uint8_t randomByte() = 0; + virtual uint8_t randomByte(); /*! \brief Configure module parameters for direct modes. Must be called prior to "ham" modes like RTTY or AX.25. Only available in FSK mode. @@ -302,14 +302,14 @@ class PhysicalLayer { \param func Pointer to interrupt service routine. */ - virtual void setDirectAction(void (*func)(void)) = 0; + virtual void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. Must be implemented in module class. \param pin Pin on which to read. */ - virtual void readBit(RADIOLIB_PIN_TYPE pin) = 0; + virtual void readBit(RADIOLIB_PIN_TYPE pin); /*! \brief Get the number of direct mode bytes currently available in buffer. From 139a68dfd4e70a86ad23953e4c22977fa6a7cc17 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 8 Jan 2023 15:12:49 +0100 Subject: [PATCH 0326/1848] [EXT] Added support for external radios (646) --- .../AFSK_External_Radio.ino | 89 +++++++++++++++++++ keywords.txt | 1 + src/RadioLib.h | 1 + src/protocols/ExternalRadio/ExternalRadio.cpp | 9 ++ src/protocols/ExternalRadio/ExternalRadio.h | 17 ++++ 5 files changed, 117 insertions(+) create mode 100644 examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino create mode 100644 src/protocols/ExternalRadio/ExternalRadio.cpp create mode 100644 src/protocols/ExternalRadio/ExternalRadio.h diff --git a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino new file mode 100644 index 0000000000..c933ebcc73 --- /dev/null +++ b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino @@ -0,0 +1,89 @@ +/* + RadioLib AFSK External Radio example + + This example shows how to use your Arduino + as modulator for an external analogue FM radio. + + The example sends APRS position reports with + audio modulated as AFSK at 1200 baud using + Bell 202 tones. However, any other AFSK + protocol (RTTY, SSTV, etc.) may be used as well. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// create a dummy radio module +ExternalRadio radio; + +// create AFSK client instance using the external radio +// pin 5 is connected to the radio sound input +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +// create APRS client instance using the AX.25 client +APRSClient aprs(&ax25); + +void setup() { + Serial.begin(9600); + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + int16_t state = ax25.begin("N7LEM"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + state = aprs.begin('>'); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending position ... ")); + + // send a location without message or timestamp + int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E"); + delay(500); + + // send a location with message and without timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!"); + delay(500); + + // send a location with message and timestamp + state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z"); + delay(500); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} diff --git a/keywords.txt b/keywords.txt index edcb4faa42..7ad8dbbdae 100644 --- a/keywords.txt +++ b/keywords.txt @@ -50,6 +50,7 @@ AFSKClient KEYWORD1 FSK4Client KEYWORD1 APRSClient KEYWORD1 PagerClient KEYWORD1 +ExternalRadio KEYWORD1 # SSTV modes Scottie1 KEYWORD1 diff --git a/src/RadioLib.h b/src/RadioLib.h index 37963d1580..be496dd613 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -99,6 +99,7 @@ #include "protocols/SSTV/SSTV.h" #include "protocols/FSK4/FSK4.h" #include "protocols/APRS/APRS.h" +#include "protocols/ExternalRadio/ExternalRadio.h" // only create Radio class when using RadioShield #if defined(RADIOLIB_RADIOSHIELD) diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp new file mode 100644 index 0000000000..9b9358b8df --- /dev/null +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -0,0 +1,9 @@ +#include "ExternalRadio.h" + +ExternalRadio::ExternalRadio() : PhysicalLayer(1, 0) { + mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); +} + +Module* ExternalRadio::getMod() { + return(mod); +} \ No newline at end of file diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h new file mode 100644 index 0000000000..524786435c --- /dev/null +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -0,0 +1,17 @@ +#if !defined(_RADIOLIB_EXTERNAL_RADIO_H) +#define _RADIOLIB_EXTERNAL_RADIO_H + +#include "../../TypeDef.h" +#include "../../Module.h" + +#include "../PhysicalLayer/PhysicalLayer.h" + +class ExternalRadio: public PhysicalLayer { + public: + ExternalRadio(); + Module* getMod(); + private: + Module* mod; +}; + +#endif \ No newline at end of file From 90b28d77223ecdd1699c8d3807f3477623bc5cea Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 6 Dec 2022 17:41:30 +0100 Subject: [PATCH 0327/1848] Remove duplicated setRfSwitchPins documentation All radios that support RfSwitch define this method that simply forwards to the `Module::setRfSwitchPins()` method. Previously, all these methods duplicated the documentation as well, but this uses the doxygen \copydoc to remove this duplication. --- src/modules/CC1101/CC1101.h | 9 +-------- src/modules/RF69/RF69.h | 9 +-------- src/modules/SX126x/SX126x.h | 9 +-------- src/modules/SX127x/SX127x.h | 9 +-------- src/modules/SX128x/SX128x.h | 9 +-------- src/modules/Si443x/Si443x.h | 9 +-------- 6 files changed, 6 insertions(+), 48 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index bb245cbed8..558519c2ac 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -928,14 +928,7 @@ class CC1101: public PhysicalLayer { */ int16_t setEncoding(uint8_t encoding) override; - /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! - - \param rxEn RX enable pin. - - \param txEn TX enable pin. - */ + /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 979f48454c..e799b716a9 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1010,14 +1010,7 @@ class RF69: public PhysicalLayer { */ int16_t setRSSIThreshold(float dbm); - /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! - - \param rxEn RX enable pin. - - \param txEn TX enable pin. - */ + /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index b56bcb29cd..0c8d17560f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -914,14 +914,7 @@ class SX126x: public PhysicalLayer { */ int16_t setEncoding(uint8_t encoding) override; - /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! - - \param rxEn RX enable pin. - - \param txEn TX enable pin. - */ + /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 302fabf4c0..4d68a2fab7 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1141,14 +1141,7 @@ class SX127x: public PhysicalLayer { */ int8_t getTempRaw(); - /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! - - \param rxEn RX enable pin. - - \param txEn TX enable pin. - */ + /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index c367013f4d..854ef06ac3 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -809,14 +809,7 @@ class SX128x: public PhysicalLayer { */ int16_t setEncoding(uint8_t encoding) override; - /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! - - \param rxEn RX enable pin. - - \param txEn TX enable pin. - */ + /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index cf4f689b7b..e3218c6866 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -785,14 +785,7 @@ class Si443x: public PhysicalLayer { */ int16_t setDataShaping(uint8_t sh) override; - /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! - - \param rxEn RX enable pin. - - \param txEn TX enable pin. - */ + /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! From 83ff964b6613beba695ac084b366f58f9b41bb8f Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 6 Dec 2022 17:52:18 +0100 Subject: [PATCH 0328/1848] [MOD] Generalize rfswitch pin handling This defines operation modes (IDLE, RX and TX) and allows defining up to to three pins to be controlled. For each mode a value can be specified for each pin a table. Compared to the previous handling, this: - Allows up to three pins instead of only two. - Gives more control over output pin values (e.g. to simply change polarity or support more complex control logic). In addition, the modes are treated as opaque by the Module code, allowing radio classes to define their own modes if needed. Some notes regarding the implementation: - The number of pins is limited at three, since most boards seem to need only two pins and only the Nucleo STM32WL55 board needs three. If more pins are needed in the future, the setRfSwitchTable() can be overloaded to accept either a 3-element or e.g. 4-element pins array, to allow new and old code to work as-is. Note that there is a RFSWITCH_MAX_PINS constant defined, but it is not recommended for sketches to use this constant when defining a rfswitch pins array, to prevent issues when this value is ever increased and such an array gets extra zero elements (that will be interpreted as pin 0). Note that this is not a problem for the RfSwitchMode_t values array, since any extra values in there will only be used if a valid pin was set in the pins array. - The pins array is passed by reference, so the compiler complains if the array passed is not the expected size. Since a reference to an array without a length is not supported (at least not by the gcc 7 used by the AVR core - gcc 10 for STM32 seems to accept it), the table array is passed as a pointer instead (but because arrays and pointers are reasonably interchangeable, the caller does not see the difference). - The existing setRfSwitchPins() method is still supported as before. Internally it creates a table with the right values and pins and passes those to setRfSwitchTable. - For easier review, this commit does not modify all calls to setRfSwitchState() in all radio modules yet, but has a compatibility wrapper to delay this change until the next commit. Similarly, the setRfSwitchTable() method is now defined on Module only, a wrapper for it will be defined in all radios that already have the setRfSwitchPins() wrapper in another commit. - To allow future radios to define any number of modes, the modes table does not have a fixed length, but instead is terminated by a special value. This is a bit fragile (if the terminator is omitted, the code will read past the end of the array), but rather flexible. One alternative to this approach would be to make setRfSwitchTable a template that deduces the array size from a template argument and then stores the size explicitly, but using templates probably reduces code clarity. --- src/Module.cpp | 50 ++++++++++++---- src/Module.h | 151 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 180 insertions(+), 21 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index ba0674c00f..5046da638e 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -551,20 +551,50 @@ void Module::regdump(uint8_t start, uint8_t len) { } void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { - _useRfSwitch = true; - _rxEn = rxEn; - _txEn = txEn; - this->pinMode(rxEn, OUTPUT); - this->pinMode(txEn, OUTPUT); + // This can be on the stack, setRfSwitchTable copies the contents + const RADIOLIB_PIN_TYPE pins[] = { + rxEn, txEn, RADIOLIB_NC, + }; + // This must be static, since setRfSwitchTable stores a reference. + static constexpr RfSwitchMode_t table[] = { + {MODE_IDLE, {LOW, LOW}}, + {MODE_RX, {HIGH, LOW}}, + {MODE_TX, {LOW, HIGH}}, + END_OF_MODE_TABLE, + }; + setRfSwitchTable(pins, table); +} + +void Module::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[3], const RfSwitchMode_t table[]) { + memcpy(_rfSwitchPins, pins, sizeof(_rfSwitchPins)); + _rfSwitchTable = table; + for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) + this->pinMode(pins[i], OUTPUT); +} + +const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const { + const RfSwitchMode_t *row = _rfSwitchTable; + while (row && row->mode != MODE_END_OF_TABLE) { + if (row->mode == mode) + return row; + ++row; + } + return nullptr; } -void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) { - // check RF switch control is enabled - if(!_useRfSwitch) { +void Module::setRfSwitchState(uint8_t mode) { + const RfSwitchMode_t *row = findRfSwitchMode(mode); + if(!row) { + // RF switch control is disabled or does not have this mode return; } // set pins - this->digitalWrite(_rxEn, rxPinState); - this->digitalWrite(_txEn, txPinState); + const RADIOLIB_PIN_STATUS *value = &row->values[0]; + for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { + RADIOLIB_PIN_TYPE pin = _rfSwitchPins[i]; + if (pin != RADIOLIB_NC) + this->digitalWrite(pin, *value); + ++value; + } } diff --git a/src/Module.h b/src/Module.h index f699d5fe10..d566b560ba 100644 --- a/src/Module.h +++ b/src/Module.h @@ -15,6 +15,49 @@ */ class Module { public: + /*! + * \brief The maximum number of pins supported by the RF switch + * code. + * + * Note: It is not recommended to use this constant in your sketch + * when defining a rfswitch pins array, to prevent issues when this + * value is ever increased and such an array gets extra zero + * elements (that will be interpreted as pin 0). + */ + static const size_t RFSWITCH_MAX_PINS = 3; + + /*! + * Description of RF switch pin states for a single mode. + * + * See setRfSwitchTable() for details. + */ + struct RfSwitchMode_t { + uint8_t mode; + RADIOLIB_PIN_STATUS values[RFSWITCH_MAX_PINS]; + }; + + /*! + * Constants to use in a mode table set be setRfSwitchTable. These + * constants work for most radios, but some radios define their own + * constants to be used instead. + * + * See setRfSwitchTable() for details. + */ + enum OpMode_t { + // Table end marker is zero to ensure zero-initialized mode ends the table + MODE_END_OF_TABLE = 0, + MODE_IDLE, + MODE_RX, + MODE_TX, + }; + + /*! + * Value to use as the last element in a mode table to indicate the + * end of the table. + * + * See setRfSwitchTable() for details. + */ + static constexpr RfSwitchMode_t END_OF_MODE_TABLE = {MODE_END_OF_TABLE, {}}; #if defined(RADIOLIB_BUILD_ARDUINO) @@ -242,23 +285,110 @@ class Module { RADIOLIB_PIN_TYPE getGpio() const { return(_gpio); } /*! - \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. - When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + \brief Some modules contain external RF switch controlled by pins. + This function gives RadioLib control over those pins to + automatically switch between various modes: When idle both pins + will be LOW, during TX the `txEn` pin will be HIGH, during RX the + `rxPin` will be HIGH. - \param rxEn RX enable pin. + Radiolib will automatically set the pin mode and value of these + pins, so do not control them from the sketch. + + When more than two pins or more control over the output values are + needed, use the setRfSwitchTable() function. + \param rxEn RX enable pin. \param txEn TX enable pin. */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); /*! - \brief Set RF switch state. + \brief Some modules contain external RF switch controlled by pins. + This function gives RadioLib control over those pins to + automatically switch between various modes. + + Radiolib will automatically set the pin mode and value of these + pins, so do not control them from the sketch. + + + \param pins A reference to an array of pins to control. This + should always be an array of 3 elements. If you need less pins, + use RADIOLIB_NC for the unused elements. + + \param table A reference to an array of pin values to use for each + supported mode. Each element is an RfSwitchMode_T struct that + lists the mode for which it applies and the values for each of the + pins passed in the pins argument respectively. + + The `pins` array will be copied into the Module object, so the + original array can be deallocated after this call. However, + a reference to the `table` array will be stored, so that array + must remain valid as long RadioLib is being used. + + The `mode` field in each table row should normally use any of the + `MODE_*` constants from the Module::OpMode_t enum. However, some + radios support additional modes and will define their own OpMode_t + enum. - \param rxPinState Pin state to set on Tx enable pin (usually high to transmit). + The length of the table is variable (to support radios that add + additional modes), so the table must always be terminated with the + special END_OF_MODE_TABLE value. - \param txPinState Pin state to set on Rx enable pin (usually high to receive). + Normally all modes should be listed in the table, but for some + radios, modes can be omitted to indicate they are not supported + (e.g. when a radio has a high power and low power TX mode but + external circuitry only supports low power). If applicable, this + is documented in the radio class itself. + + #### Example + For example, on a board that has an RF switch with an enable pin + connected to PA0 and a TX/RX select pin connected to PA1: + + \code + // In global scope, define the pin array and mode table + static const RADIOLIB_PIN_TYPE rfswitch_pins[] = + {PA0, PA1, RADIOLIB_NC}; + static const Module::RfSwitchMode_t rfswitch_table[] = { + {Module::MODE_IDLE, {LOW, LOW}}, + {Module::MODE_RX, {HIGH, LOW}}, + {Module::MODE_TX, {HIGH, HIGH}}, + Module::END_OF_MODE_TABLE, + }; + + void setup() { + ... + // Then somewhere in setup, pass them to radiolib + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + ... + } + \endcode */ - void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState); + + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); + + /*! + * \brief Find a mode in the RfSwitchTable. + * + * \param The mode to find. + * + * \returns A pointer to the RfSwitchMode_t struct in the table that + * matches the passed mode. Returns nullptr if no rfswitch pins are + * configured, or the passed mode is not listed in the table. + */ + const RfSwitchMode_t *findRfSwitchMode(uint8_t mode) const; + + /*! + \brief Set RF switch state. + \param mode The mode to set. This must be one of the MODE_ constants, or a radio-specific constant. + */ + void setRfSwitchState(uint8_t mode); + + /*! Temporary compatibility wrapper */ + void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) { + if (rxPinState) setRfSwitchState(MODE_RX); + else if (txPinState) setRfSwitchState(MODE_TX); + else setRfSwitchState(MODE_IDLE); + } /*! \brief Wait for time to elapse, either using the microsecond timer, or the TimerFlag. @@ -446,10 +576,9 @@ class Module { bool _initInterface = false; #endif - // RF switch presence and pins - bool _useRfSwitch = false; - RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC; + // RF switch pins and table + RADIOLIB_PIN_TYPE _rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + const RfSwitchMode_t *_rfSwitchTable = nullptr; #if defined(RADIOLIB_INTERRUPT_TIMING) uint32_t _prevTimingLen = 0; From 3779faf6007fdc29d296aa0dad671cb33b4c3c9a Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 9 Jan 2023 09:40:27 +0100 Subject: [PATCH 0329/1848] Add setRfSwitchTable() wrapper methods This gives all radios that use an rfswitch (i.e. have a setRfSwitchPins() wrapper already) a wrapper method for setRfSwitchTable() too. This wrapper just calls the same method on Module, to make it easier for sketches to use it. --- src/modules/CC1101/CC1101.cpp | 4 ++++ src/modules/CC1101/CC1101.h | 3 +++ src/modules/RF69/RF69.cpp | 4 ++++ src/modules/RF69/RF69.h | 3 +++ src/modules/SX126x/SX126x.cpp | 4 ++++ src/modules/SX126x/SX126x.h | 3 +++ src/modules/SX127x/SX127x.cpp | 4 ++++ src/modules/SX127x/SX127x.h | 3 +++ src/modules/SX128x/SX128x.cpp | 4 ++++ src/modules/SX128x/SX128x.h | 3 +++ src/modules/Si443x/Si443x.cpp | 4 ++++ src/modules/Si443x/Si443x.h | 3 +++ 12 files changed, 42 insertions(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f943a47029..b3cb622c67 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -902,6 +902,10 @@ void CC1101::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } +void CC1101::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + _mod->setRfSwitchTable(pins, table); +} + uint8_t CC1101::randomByte() { // set mode to Rx SPIsendCommand(RADIOLIB_CC1101_CMD_RX); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 558519c2ac..eb12b0be2b 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -931,6 +931,9 @@ class CC1101: public PhysicalLayer { /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Get one truly random byte from RSSI noise. diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index ec1f3c421c..b1ef42e3c9 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -916,6 +916,10 @@ void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } +void RF69::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + _mod->setRfSwitchTable(pins, table); +} + uint8_t RF69::randomByte() { // set mode to Rx setMode(RADIOLIB_RF69_RX); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index e799b716a9..d47673295e 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1013,6 +1013,9 @@ class RF69: public PhysicalLayer { /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Get one truly random byte from RSSI noise. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f5de00b3d3..8d9f67aacc 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1199,6 +1199,10 @@ void SX126x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } +void SX126x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + _mod->setRfSwitchTable(pins, table); +} + int16_t SX126x::forceLDRO(bool enable) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 0c8d17560f..47a9cb37d7 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -917,6 +917,9 @@ class SX126x: public PhysicalLayer { /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX126x::autoLDRO() diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 9930841ef7..6d1b77e4ea 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1258,6 +1258,10 @@ void SX127x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } +void SX127x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + _mod->setRfSwitchTable(pins, table); +} + uint8_t SX127x::randomByte() { // check active modem uint8_t rssiValueReg = RADIOLIB_SX127X_REG_RSSI_WIDEBAND; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 4d68a2fab7..e7502c1571 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1144,6 +1144,9 @@ class SX127x: public PhysicalLayer { /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Get one truly random byte from RSSI noise. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 32a2970e56..14313759ae 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1243,6 +1243,10 @@ void SX128x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } +void SX128x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + _mod->setRfSwitchTable(pins, table); +} + uint8_t SX128x::randomByte() { // it's unclear whether SX128x can measure RSSI while not receiving a packet // this method is implemented only for PhysicalLayer compatibility diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 854ef06ac3..98bd725214 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -812,6 +812,9 @@ class SX128x: public PhysicalLayer { /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Dummy random method, to ensure PhysicalLayer compatibility. diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index f7e8157654..7cfca65b9c 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -568,6 +568,10 @@ void Si443x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { _mod->setRfSwitchPins(rxEn, txEn); } +void Si443x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + _mod->setRfSwitchTable(pins, table); +} + uint8_t Si443x::randomByte() { // set mode to Rx _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index e3218c6866..6945e510e8 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -788,6 +788,9 @@ class Si443x: public PhysicalLayer { /*! \copydoc Module::setRfSwitchPins */ void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Get one truly random byte from RSSI noise. From 52ec165643fd697ae2b8e0f469e306a13de92a6a Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 6 Dec 2022 13:27:19 +0100 Subject: [PATCH 0330/1848] Update radios to use new setRfSwitchState This removes the compatibility wrapper and applies the following replacements: sed -i 's/setRfSwitchState(LOW, LOW)/setRfSwitchState(Module::MODE_IDLE)/' src/modules/*/*.cpp sed -i 's/setRfSwitchState(HIGH, LOW)/setRfSwitchState(Module::MODE_RX)/' src/modules/*/*.cpp sed -i 's/setRfSwitchState(LOW, HIGH)/setRfSwitchState(Module::MODE_TX)/' src/modules/*/*.cpp --- src/Module.h | 7 ------- src/modules/CC1101/CC1101.cpp | 10 +++++----- src/modules/RF69/RF69.cpp | 12 ++++++------ src/modules/SX126x/SX126x.cpp | 14 +++++++------- src/modules/SX127x/SX127x.cpp | 16 ++++++++-------- src/modules/SX128x/SX128x.cpp | 14 +++++++------- src/modules/Si443x/Si443x.cpp | 12 ++++++------ 7 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/Module.h b/src/Module.h index d566b560ba..9958a30f18 100644 --- a/src/Module.h +++ b/src/Module.h @@ -383,13 +383,6 @@ class Module { */ void setRfSwitchState(uint8_t mode); - /*! Temporary compatibility wrapper */ - void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) { - if (rxPinState) setRfSwitchState(MODE_RX); - else if (txPinState) setRfSwitchState(MODE_TX); - else setRfSwitchState(MODE_IDLE); - } - /*! \brief Wait for time to elapse, either using the microsecond timer, or the TimerFlag. Note that in interrupt timing mode, it is up to the user to set up the timing interrupt! diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index b3cb622c67..8ad06742a0 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -162,7 +162,7 @@ int16_t CC1101::standby() { SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); return(RADIOLIB_ERR_NONE); } @@ -176,7 +176,7 @@ int16_t CC1101::transmitDirectAsync(uint32_t frf) { int16_t CC1101::transmitDirect(bool sync, uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { @@ -206,7 +206,7 @@ int16_t CC1101::receiveDirectAsync() { int16_t CC1101::receiveDirect(bool sync) { // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(sync); @@ -291,7 +291,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { dataSent += initialWrite; // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // set mode to transmit SPIsendCommand(RADIOLIB_CC1101_CMD_TX); @@ -344,7 +344,7 @@ int16_t CC1101::startReceive() { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to receive SPIsendCommand(RADIOLIB_CC1101_CMD_RX); diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index b1ef42e3c9..ff6306da73 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -159,7 +159,7 @@ int16_t RF69::receive(uint8_t* data, size_t len) { int16_t RF69::sleep() { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); // set module to sleep return(setMode(RADIOLIB_RF69_SLEEP)); @@ -167,7 +167,7 @@ int16_t RF69::sleep() { int16_t RF69::standby() { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); // set module to standby return(setMode(RADIOLIB_RF69_STANDBY)); @@ -175,7 +175,7 @@ int16_t RF69::standby() { int16_t RF69::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { @@ -196,7 +196,7 @@ int16_t RF69::transmitDirect(uint32_t frf) { int16_t RF69::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(); @@ -254,7 +254,7 @@ int16_t RF69::startReceive() { clearIRQFlags(); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to receive state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM); @@ -414,7 +414,7 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // set mode to transmit state = setMode(RADIOLIB_RF69_TX); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 8d9f67aacc..6fcf956c42 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -299,7 +299,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { int16_t SX126x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) int16_t state = RADIOLIB_ERR_NONE; @@ -315,7 +315,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) { int16_t SX126x::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // SX126x is unable to output received data directly return(RADIOLIB_ERR_UNKNOWN); @@ -337,7 +337,7 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) int16_t SX126x::sleep(bool retainConfig) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF; if(!retainConfig) { @@ -357,7 +357,7 @@ int16_t SX126x::standby() { int16_t SX126x::standby(uint8_t mode) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = {mode}; return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); @@ -418,7 +418,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // start transmission state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); @@ -445,7 +445,7 @@ int16_t SX126x::startReceive(uint32_t timeout) { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to receive state = setRx(timeout); @@ -600,7 +600,7 @@ int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set DIO pin mapping state = setDioIrqParams(RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE, RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6d1b77e4ea..b6e4441af2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -275,7 +275,7 @@ int16_t SX127x::scanChannel() { int16_t SX127x::sleep() { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); // set mode to sleep return(setMode(RADIOLIB_SX127X_SLEEP)); @@ -283,7 +283,7 @@ int16_t SX127x::sleep() { int16_t SX127x::standby() { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); // set mode to standby return(setMode(RADIOLIB_SX127X_STANDBY)); @@ -296,7 +296,7 @@ int16_t SX127x::transmitDirect(uint32_t frf) { } // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { @@ -325,7 +325,7 @@ int16_t SX127x::receiveDirect() { } // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(); @@ -405,13 +405,13 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // FSK modem does not distinguish between Rx single and continuous if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); return(setMode(RADIOLIB_SX127X_RX)); } } // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to receive return(setMode(mode)); @@ -570,7 +570,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // start transmission state |= setMode(RADIOLIB_SX127X_TX); @@ -659,7 +659,7 @@ int16_t SX127x::startChannelScan() { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to CAD state = setMode(RADIOLIB_SX127X_CAD); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 14313759ae..531ebd0efb 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -348,7 +348,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { int16_t SX128x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) int16_t state = RADIOLIB_ERR_NONE; @@ -363,7 +363,7 @@ int16_t SX128x::transmitDirect(uint32_t frf) { int16_t SX128x::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // SX128x is unable to output received data directly return(RADIOLIB_ERR_UNKNOWN); @@ -388,7 +388,7 @@ int16_t SX128x::scanChannel() { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to CAD state = setCad(); @@ -416,7 +416,7 @@ int16_t SX128x::scanChannel() { int16_t SX128x::sleep(bool retainConfig) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN; if(!retainConfig) { @@ -436,7 +436,7 @@ int16_t SX128x::standby() { int16_t SX128x::standby(uint8_t mode) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = { mode }; return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); @@ -500,7 +500,7 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // start transmission state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); @@ -553,7 +553,7 @@ int16_t SX128x::startReceive(uint16_t timeout) { } // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set mode to receive state = setRx(timeout); diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 7cfca65b9c..b8641aeed4 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -119,7 +119,7 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { int16_t Si443x::sleep() { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); // disable wakeup timer interrupt int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, 0x00); @@ -135,14 +135,14 @@ int16_t Si443x::sleep() { int16_t Si443x::standby() { // set RF switch (if present) - _mod->setRfSwitchState(LOW, LOW); + _mod->setRfSwitchState(Module::MODE_IDLE); return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_XTAL_ON, 7, 0, 10)); } int16_t Si443x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { @@ -184,7 +184,7 @@ int16_t Si443x::transmitDirect(uint32_t frf) { int16_t Si443x::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(); @@ -239,7 +239,7 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); // set RF switch (if present) - _mod->setRfSwitchState(LOW, HIGH); + _mod->setRfSwitchState(Module::MODE_TX); // set interrupt mapping _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_PACKET_SENT_ENABLED); @@ -272,7 +272,7 @@ int16_t Si443x::startReceive() { clearIRQFlags(); // set RF switch (if present) - _mod->setRfSwitchState(HIGH, LOW); + _mod->setRfSwitchState(Module::MODE_RX); // set interrupt mapping _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); From da6c3f6a6ba190bdaaae0d7101952393c0940f2a Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 6 Dec 2022 21:21:09 +0100 Subject: [PATCH 0331/1848] [SX126x] Allow subclasses to change the TX mode used This prepares for adding a STM32WLx subclass later. --- src/modules/SX126x/SX126x.cpp | 4 ++-- src/modules/SX126x/SX126x.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6fcf956c42..73e8a4df40 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -299,7 +299,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { int16_t SX126x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + _mod->setRfSwitchState(_tx_mode); // user requested to start transmitting immediately (required for RTTY) int16_t state = RADIOLIB_ERR_NONE; @@ -418,7 +418,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + _mod->setRfSwitchState(_tx_mode); // start transmission state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 47a9cb37d7..ae47985907 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1043,6 +1043,9 @@ class SX126x: public PhysicalLayer { int16_t _lastError = RADIOLIB_ERR_NONE; + // Allow subclasses to define different TX modes + uint8_t _tx_mode = Module::MODE_TX; + int16_t config(uint8_t modem); int16_t checkCommandResult(); }; From 5e47d944188642ceba765a733db4dead681bf0a9 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 3 Nov 2022 10:45:07 +0100 Subject: [PATCH 0332/1848] [STM32WLx] Add module for STM32WL MCUs with integrated radio (#588) This is a nearly complete implementation, except that the Dio1 interrupt is not yet supported (this will be added in a subsequent commit to simplify review). This fixes #588. --- src/BuildOpt.h | 1 + src/Module.h | 7 +- src/RadioLib.h | 1 + src/modules/SX126x/STM32WLx.cpp | 76 +++++++++++++++ src/modules/SX126x/STM32WLx.h | 122 +++++++++++++++++++++++++ src/modules/SX126x/STM32WLx_Module.cpp | 99 ++++++++++++++++++++ src/modules/SX126x/STM32WLx_Module.h | 49 ++++++++++ 7 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 src/modules/SX126x/STM32WLx.cpp create mode 100644 src/modules/SX126x/STM32WLx.h create mode 100644 src/modules/SX126x/STM32WLx_Module.cpp create mode 100644 src/modules/SX126x/STM32WLx_Module.h diff --git a/src/BuildOpt.h b/src/BuildOpt.h index e28e7a5c38..2e2e883521 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -96,6 +96,7 @@ //#define RADIOLIB_EXCLUDE_SX127X //#define RADIOLIB_EXCLUDE_RFM9X // dependent on RADIOLIB_EXCLUDE_SX127X //#define RADIOLIB_EXCLUDE_SX126X + //#define RADIOLIB_EXCLUDE_STM32WLX // dependent on RADIOLIB_EXCLUDE_SX126X //#define RADIOLIB_EXCLUDE_SX128X //#define RADIOLIB_EXCLUDE_AFSK //#define RADIOLIB_EXCLUDE_AX25 diff --git a/src/Module.h b/src/Module.h index 9958a30f18..78793d0aa7 100644 --- a/src/Module.h +++ b/src/Module.h @@ -44,10 +44,15 @@ class Module { * See setRfSwitchTable() for details. */ enum OpMode_t { - // Table end marker is zero to ensure zero-initialized mode ends the table + /*! End of table marker, use \ref END_OF_MODE_TABLE constant + * instead. Value is zero to ensure zero-initialized mode ends the + * table */ MODE_END_OF_TABLE = 0, + /*! Idle mode */ MODE_IDLE, + /*! Receive mode */ MODE_RX, + /*! Transmission mode */ MODE_TX, }; diff --git a/src/RadioLib.h b/src/RadioLib.h index be496dd613..419e0beac7 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -78,6 +78,7 @@ #include "modules/SX126x/SX1261.h" #include "modules/SX126x/SX1262.h" #include "modules/SX126x/SX1268.h" +#include "modules/SX126x/STM32WLx.h" #include "modules/SX127x/SX1272.h" #include "modules/SX127x/SX1273.h" #include "modules/SX127x/SX1276.h" diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp new file mode 100644 index 0000000000..a1ec8a5819 --- /dev/null +++ b/src/modules/SX126x/STM32WLx.cpp @@ -0,0 +1,76 @@ +/* + +Copyright (c) 2018 Jan Gromeš +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#include "STM32WLx.h" +#if !defined(RADIOLIB_EXCLUDE_STM32WLX) + + +STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { +} + +int16_t STM32WLx::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // Execute common part + int16_t state = SX1262::begin(freq, bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // This overrides the value in SX126x::begin() + // On STM32WL, DIO2 is hardwired to the radio IRQ on the MCU, so it + // should really not be used as RfSwitch control output. + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t STM32WLx::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // Execute common part + int16_t state = SX1262::beginFSK(freq, br, freqDev, rxBw, power, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // This overrides the value in SX126x::beginFSK() + // On STM32WL, DIO2 is hardwired to the radio IRQ on the MCU, so it + // should really not be used as RfSwitch control output. + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t STM32WLx::setOutputPower(int8_t power) { + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + RADIOLIB_ASSERT(state); + + // Use HP only if available and needed for the requested power + bool hp_supported = _mod->findRfSwitchMode(MODE_TX_HP); + bool use_hp = power > 14 && hp_supported; + + // set PA config. + if(use_hp) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x00, 0x07); // HP output up to 22dBm + _tx_mode = MODE_TX_HP; + } else { + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x01, 0x00); // LP output up to 14dBm + _tx_mode = MODE_TX_LP; + } + RADIOLIB_ASSERT(state); + + // set output power + /// \todo power ramp time configuration + state = SX126x::setTxParams(power); + RADIOLIB_ASSERT(state); + + // restore OCP configuration + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); +} + + +#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h new file mode 100644 index 0000000000..d90f1450e2 --- /dev/null +++ b/src/modules/SX126x/STM32WLx.h @@ -0,0 +1,122 @@ +/* + +Copyright (c) 2018 Jan Gromeš +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#if !defined(_RADIOLIB_STM32WLx_H) +#define _RADIOLIB_STM32WLx_H + +#include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_STM32WLX) + +#include "../../Module.h" +#include "SX1262.h" +#include "STM32WLx_Module.h" + +/*! + \class STM32WLx + + \brief Derived class for STM32WL modules. + + The radio integrated into these modules is essentially the same as the + Semtech %SX126x external radio chips, so most of the documentation for + those also applies here. + + One notable difference with the %SX126x radios is that this radio + essentially combines the %SX1261 and %SX1262 by integrating both the + low-power (LP) and high-power (HP) amplifier. See setOutputPower() and + setRfSwitchTable() for details on how this is handled. +*/ +class STM32WLx : public SX1262 { + // NOTE: This class could not be named STM32WL (or STM32WLxx), since + // those are macros defined by + // system/Drivers/CMSIS/Device/ST/STM32WLxxx/Include/stm32wlxx.h + public: + /*! + \brief Default constructor. + + \param mod Instance of STM32WLx_Module that will be used to communicate with the radio. + */ + STM32WLx(STM32WLx_Module* mod); + + /*! + * \brief Custom operation modes for STMWLx. + * + * This splits the TX mode into two modes: Low-power and high-power. + * These constants can be used with the setRfSwitchTable() method, + * instead of the Module::OpMode_t constants. + */ + enum OpMode_t { + /*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */ + MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE, + /*! Idle mode */ + MODE_IDLE = Module::MODE_IDLE, + /*! Receive mode */ + MODE_RX = Module::MODE_RX, + /*! Low power transmission mode */ + MODE_TX_LP = Module::MODE_TX, + /*! High power transmission mode */ + MODE_TX_HP, + }; + /*! \copydoc Module::END_OF_MODE_TABLE */ + static constexpr auto END_OF_MODE_TABLE = Module::END_OF_MODE_TABLE; + + // basic methods + + /*! + \copydoc SX1262::begin + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + /*! + \copydoc SX1262::beginFSK + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + // configuration methods + + /*! + \brief Sets output power. Allowed values are in range from -17 to 22 dBm. + + This automatically switches between the low-power (LP) and high-power (HP) amplifier. + + LP is preferred and supports -17 to +14dBm. When a higher power is + requested (or the LP amplifier is marked as unvailable using + setRfSwitchTable()), HP is used, which supports -9 to +22dBm. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + virtual int16_t setOutputPower(int8_t power) override; + + /*! + \copybrief Module::setRfSwitchTable + + This method works like Module::setRfSwitchTable(), except that you + should use STM32WLx::OpMode_t constants for modes, which + distinguishes between a low-power (LP) and high-power (HP) TX mode. + + For boards that do not support both modes, just omit the + unsupported mode from the table and it will not be used (and the + valid power range is adjusted by setOutputPower() accordingly). + + Note that the setRfSwitchTable() method should be called *before* the + begin() method, to ensure the radio knows which modes are supported + during initialization. + */ + // Note: This explicitly inherits this method only to override docs + using SX126x::setRfSwitchTable; + +#if !defined(RADIOLIB_GODMODE) + private: +#endif +}; + +#endif // !defined(RADIOLIB_EXCLUDE_SX126X) + +#endif // _RADIOLIB_STM32WLX_MODULE_H diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp new file mode 100644 index 0000000000..1fa4725a2e --- /dev/null +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -0,0 +1,99 @@ +/* + +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#include "STM32WLx_Module.h" + +#if !defined(RADIOLIB_EXCLUDE_STM32WLX) + +#include + +// This defines some dummy pin numbers (starting at NUM_DIGITAL_PINS to +// guarantee these are not valid regular pin numbers) that can be passed +// to the parent Module class, to be stored here and then passed back to +// the overridden callbacks when these are used. +enum { + RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS = NUM_DIGITAL_PINS, + RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY, + RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ, + RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, +}; + + +STM32WLx_Module::STM32WLx_Module(): + Module( + RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS, + RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ, + RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, + RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY, + SubGhz.SPI, + SubGhz.spi_settings + ) +{ + setCb_pinMode(virtualPinMode); + setCb_digitalWrite(virtualDigitalWrite); + setCb_digitalRead(virtualDigitalRead); +} + +void STM32WLx_Module::virtualPinMode(uint32_t dwPin, uint32_t dwMode) { + switch(dwPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + // Nothing to do + break; + default: + ::pinMode(dwPin, dwMode); + break; + } +} + +void STM32WLx_Module::virtualDigitalWrite(uint32_t dwPin, uint32_t dwVal) { + switch (dwPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + SubGhz.setNssActive(dwVal == LOW); + break; + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + SubGhz.setResetActive(dwVal == LOW); + break; + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + // Should not (and cannot) be written, just ignore + break; + + default: + ::digitalWrite(dwPin, dwVal); + break; + } +} + +int STM32WLx_Module::virtualDigitalRead(uint32_t ulPin) { + switch (ulPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + return(SubGhz.isBusy() ? HIGH : LOW); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + // If the IRQ is disabled, we can read the value by clearing and + // seeing if it immediately becomes pending again. + // TODO: This seems a bit fragile, but it does work. + SubGhz.clearPendingInterrupt(); + return(SubGhz.isInterruptPending() ? HIGH : LOW); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + return(SubGhz.isNssActive() ? LOW : HIGH); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + return(SubGhz.isResetActive() ? LOW : HIGH); + + default: + return(::digitalRead(ulPin)); + } +} + +#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) diff --git a/src/modules/SX126x/STM32WLx_Module.h b/src/modules/SX126x/STM32WLx_Module.h new file mode 100644 index 0000000000..05f2b2fe12 --- /dev/null +++ b/src/modules/SX126x/STM32WLx_Module.h @@ -0,0 +1,49 @@ +/* + +Copyright (c) 2022 STMicroelectronics + +This file is licensed under the MIT License: https://opensource.org/licenses/MIT +*/ + +#if !defined(_RADIOLIB_STM32WLX_MODULE_H) +#define _RADIOLIB_STM32WLX_MODULE_H + +#include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_STM32WLX) + +#include "../../Module.h" + +/*! + * \class STM32WLx_Module + * + * This is a subclass of Module to be used with the STM32WLx driver. + * + * It is used to override some callbacks, allowing access to some of the + * radio control signals that are wired to internal registers instead of + * actual GPIO pins. + */ +class STM32WLx_Module : public Module { + // Note: We cannot easily override any methods here, since most calls + // are non-virtual and made through a Module*, so they would not be + // calling any overridden methods. This means this class works by + // overriding some of the callbacks in its constructor. + + public: + STM32WLx_Module(); + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + + // Replacement callbacks to handle virtual pins. These are static, + // since they replace global functions that cannot take any this + // pointer for context. + static void virtualPinMode(uint32_t dwPin, uint32_t dwMode); + static void virtualDigitalWrite(uint32_t dwPin, uint32_t dwVal); + static int virtualDigitalRead(uint32_t ulPin); +}; + +#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) + +#endif // _RADIOLIB_STM32WLX_MODULE_H From 9252cf53d3e154756aec94b9924eda0b4346ce3c Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 7 Dec 2022 09:17:44 +0100 Subject: [PATCH 0333/1848] [STM32WLx] Implement setDio1Action / interrupts Because this interrupt is not connected to a GPIO or even the EXTI unit, but directly to the MCU NVIC, the regular attachInterrupt flow cannot be used. Instead, this lets STM32WLx override the setDio1Action() and clearDio1Action() methods to register the radio IRQ directly. Note that it would have been nicer to implement this by overriding attachInterrupt in STM32WLx_Module, but that is never called for virtual pins (because the STM32Duino digitalPinToInterrupt() macro does not work for virtual pins). In addition, because the NVIC is level-sensitive and the code expects edge-sensitive interrupts (for GPIO, the EXTI module in front of the NVIC makes the interrupts edge-sensitive), this adds some additional handling around the user-registered interrupt callback. To prevent the ISR from triggering over and over again (and also to not require SPI transactions in the ISR to clear the IRQ flags inside the radio), the interrupt is disabled in the NVIC whenever it is trigered. Then, whenever the IRQ flags *are* cleared in the radio, the IRQ is enabled in the NVIC again. This requires making the SX126x::clearIrqStatus() method virtual so STM32WLx can override it. --- src/modules/SX126x/STM32WLx.cpp | 26 ++++++++++++++++++++++++++ src/modules/SX126x/STM32WLx.h | 17 +++++++++++++++++ src/modules/SX126x/SX126x.h | 2 +- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index a1ec8a5819..bad38dc9ca 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -9,6 +9,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include "STM32WLx.h" #if !defined(RADIOLIB_EXCLUDE_STM32WLX) +#include STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } @@ -72,5 +73,30 @@ int16_t STM32WLx::setOutputPower(int8_t power) { return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } +int16_t STM32WLx::clearIrqStatus(uint16_t clearIrqParams) { + int16_t res = SX126x::clearIrqStatus(clearIrqParams); + // The NVIC interrupt is level-sensitive, so clear away any pending + // flag that is only set because the radio IRQ status was not cleared + // in the interrupt (to prevent each IRQ triggering twice and allow + // reading the irq status through the pending flag). + SubGhz.clearPendingInterrupt(); + if(SubGhz.hasInterrupt()) + SubGhz.enableInterrupt(); + return(res); +} + +void STM32WLx::setDio1Action(void (*func)(void)) { + SubGhz.attachInterrupt([func]() { + // Because the interrupt is level-triggered, we disable it in the + // NVIC (otherwise we would need an SPI command to clear the IRQ in + // the radio, or it would trigger over and over again). + SubGhz.disableInterrupt(); + func(); + }); +} + +void STM32WLx::clearDio1Action() { + SubGhz.detachInterrupt(); +} #endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index d90f1450e2..5778dfb1cc 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -112,6 +112,23 @@ class STM32WLx : public SX1262 { // Note: This explicitly inherits this method only to override docs using SX126x::setRfSwitchTable; + /*! + \brief Sets interrupt service routine to call when DIO1/2/3 activates. + + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1/2/3 activates. + */ + void clearDio1Action(); + +#if !defined(RADIOLIB_GODMODE) + protected: +#endif + virtual int16_t clearIrqStatus(uint16_t clearIrqParams) override; + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index ae47985907..e1b603baab 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -982,7 +982,7 @@ class SX126x: public PhysicalLayer { int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t readBuffer(uint8_t* data, uint8_t numBytes); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); - int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); + virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); int16_t calibrateImage(uint8_t* data); uint8_t getPacketType(); From cd138dd6c7b099124ff7b82686c2e17f80be34bc Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 7 Dec 2022 09:50:31 +0100 Subject: [PATCH 0334/1848] [STM32WLx] Apply PA clamp workaround for HP only This modifies SX1262::begin and beginFSK to call setOutputPower after applying the workaround, so that can undo the workaround if needed. --- src/modules/SX126x/STM32WLx.cpp | 4 ++++ src/modules/SX126x/SX1262.cpp | 8 ++++---- src/modules/SX126x/SX126x.cpp | 10 +++++++--- src/modules/SX126x/SX126x.h | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index bad38dc9ca..744f88c377 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -64,6 +64,10 @@ int16_t STM32WLx::setOutputPower(int8_t power) { } RADIOLIB_ASSERT(state); + // Apply workaround for HP only + state = SX126x::fixPaClamping(use_hp); + RADIOLIB_ASSERT(state); + // set output power /// \todo power ramp time configuration state = SX126x::setTxParams(power); diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 1a2a60d371..a667525e50 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -20,10 +20,10 @@ int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setFrequency(freq); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = SX126x::fixPaClamping(); RADIOLIB_ASSERT(state); - state = SX126x::fixPaClamping(); + state = setOutputPower(power); RADIOLIB_ASSERT(state); return(state); @@ -38,10 +38,10 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = SX126x::fixPaClamping(); RADIOLIB_ASSERT(state); - state = SX126x::fixPaClamping(); + state = setOutputPower(power); RADIOLIB_ASSERT(state); return(state); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 73e8a4df40..2e95d77882 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1575,7 +1575,7 @@ int16_t SX126x::fixSensitivity() { return(writeRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1)); } -int16_t SX126x::fixPaClamping() { +int16_t SX126x::fixPaClamping(bool enable) { // fixes overly eager PA clamping // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.2 for details @@ -1584,8 +1584,12 @@ int16_t SX126x::fixPaClamping() { int16_t state = readRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1); RADIOLIB_ASSERT(state); - // update with the new value - clampConfig |= 0x1E; + // apply or undo workaround + if (enable) + clampConfig |= 0x1E; + else + clampConfig = (clampConfig & ~0x1E) | 0x08; + return(writeRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index e1b603baab..97cb77e1ba 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1005,7 +1005,7 @@ class SX126x: public PhysicalLayer { // fixes to errata int16_t fixSensitivity(); - int16_t fixPaClamping(); + int16_t fixPaClamping(bool enable = true); int16_t fixImplicitTimeout(); int16_t fixInvertedIQ(uint8_t iqConfig); From 3e2810cfbb07a559ae4fda9c57ff6b317a6dfdba Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 7 Dec 2022 10:52:17 +0100 Subject: [PATCH 0335/1848] [STM32WLx] Make reading IRQ flag more reliable Now that clearIrqStatus also clears the pending flag, reading the IRQ flag no longer has to, making this more reliable. --- src/modules/SX126x/STM32WLx_Module.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 1fa4725a2e..c824200a0d 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -79,10 +79,19 @@ int STM32WLx_Module::virtualDigitalRead(uint32_t ulPin) { return(SubGhz.isBusy() ? HIGH : LOW); case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: - // If the IRQ is disabled, we can read the value by clearing and - // seeing if it immediately becomes pending again. - // TODO: This seems a bit fragile, but it does work. - SubGhz.clearPendingInterrupt(); + // We cannot use the radio IRQ output directly, but since: + // - the pending flag will be set whenever the IRQ output is set, + // and + // - the pending flag will be cleared (by + // STM32WLx::clearIrqStatus()) whenever the radio IRQ output is + // cleared, + // the pending flag should always reflect the current radio IRQ + // output. There is one exception: when the ISR starts the pending + // flag is cleared by hardware and not set again until after the + // ISR finishes, so the value is incorrect *inside* the ISR, but + // running RadioLib code inside the ISR (especially code that + // polls the IRQ flag) is not supported and probably broken in + // other ways too. return(SubGhz.isInterruptPending() ? HIGH : LOW); case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: From e52ffb0a69264dc5e3a661cb7209b9991f500f0e Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 20 Dec 2022 16:21:48 +0100 Subject: [PATCH 0336/1848] [STM32WLx] Only build on compatible STM32 boards This checks for some system macros to be set, but also includes the doxygen build to generate documentation. This reuses the RADIOLIB_EXCLUDE_STM32WLX that the code already checks for to prevent having to duplicate this macro check in four places. To detect running inside doxygen, this configures doxygen to predefine a DOXYGEN macro (it seems no such macros are defined by default by doxygen). --- Doxyfile | 3 ++- src/BuildOpt.h | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Doxyfile b/Doxyfile index 3c1d2d186c..db6d223b33 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2172,7 +2172,8 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = protected=private +PREDEFINED = protected=private \ + DOXYGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 2e2e883521..5e6ca96584 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1010,6 +1010,13 @@ #define RADIOLIB_STATIC_ARRAY_SIZE (256) #endif + +// This only compiles on STM32 boards with SUBGHZ module, but also +// include when generating docs +#if (!defined(ARDUINO_ARCH_STM32) || !defined(SUBGHZSPI_BASE)) && !defined(DOXYGEN) + #define RADIOLIB_EXCLUDE_STM32WLX +#endif + #if defined(RADIOLIB_DEBUG) #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } From e116a20d89ae7f76eba72f4419cde34f8129ff0c Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 20 Dec 2022 21:31:43 +0100 Subject: [PATCH 0337/1848] [STM32WLx] Add examples Co-Authored-By: jgromes --- .../STM32WLx_Channel_Activity_Detection.ino | 61 +++++++ ...x_Channel_Activity_Detection_Interrupt.ino | 98 +++++++++++ .../STM32WLx_Receive/STM32WLx_Receive.ino | 124 ++++++++++++++ .../STM32WLx_Receive_Interrupt.ino | 158 ++++++++++++++++++ .../STM32WLx_Transmit/STM32WLx_Transmit.ino | 112 +++++++++++++ .../STM32WLx_Transmit_Interrupt.ino | 140 ++++++++++++++++ 6 files changed, 693 insertions(+) create mode 100644 examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino create mode 100644 examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino create mode 100644 examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino create mode 100644 examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino create mode 100644 examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino create mode 100644 examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino new file mode 100644 index 0000000000..ef511dc825 --- /dev/null +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino @@ -0,0 +1,61 @@ +/* + RadioLib STM32WLx Channel Activity Detection Example + + This example uses STM32WLx to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x/STM32WLx can detect any part + of LoRa transmission, not just the preamble. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + + +void setup() { + Serial.begin(9600); + + // initialize STM32WLx with default settings + Serial.print(F("[STM32WLx] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[STM32WLx] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 0000000000..374a41f11c --- /dev/null +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,98 @@ +/* + RadioLib STM32WLx Channel Activity Detection Example + + This example uses STM32WLx to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x/STM32WLx can detect any part + of LoRa transmission, not just the preamble. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + + +void setup() { + Serial.begin(9600); + + // initialize STM32WLx with default settings + Serial.print(F("[STM32WLx] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[STM32WLx] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[STM32WLx] Packet detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[STM32WLx] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[STM32WLx] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[STM32WLx] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino new file mode 100644 index 0000000000..b645affedf --- /dev/null +++ b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino @@ -0,0 +1,124 @@ +/* + RadioLib STM32WLx Receive Example + + This example listens for LoRa transmissions using STM32WL MCU with + integrated (SX126x) LoRa radio. + + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +static const RADIOLIB_PIN_TYPE rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + STM32WLx::END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[STM32WL] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + // NOTE: receive() is a blocking method! + // See example ReceiveInterrupt for details + // on non-blocking reception method. + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[STM32WL] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[STM32WL] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[STM32WL] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino new file mode 100644 index 0000000000..575630019d --- /dev/null +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -0,0 +1,158 @@ +/* + RadioLib STM32WLx Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +static const RADIOLIB_PIN_TYPE rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + STM32WLx::END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setDio1Action(setFlag); + + // start listening for LoRa packets + Serial.print(F("[STM32WL] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[STM32WL] Received packet!")); + + // print data of the packet + Serial.print(F("[STM32WL] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[STM32WL] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[STM32WL] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + radio.startReceive(); + } +} diff --git a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino new file mode 100644 index 0000000000..fb6dab5836 --- /dev/null +++ b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino @@ -0,0 +1,112 @@ +/* + RadioLib STM32WLx Transmit Example + + This example transmits packets using STM32WL MCU with integrated + (SX126x) LoRa radio. + + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +static const RADIOLIB_PIN_TYPE rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + STM32WLx::END_OF_MODE_TABLE, +}; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[STM32WL] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + // NOTE: transmit() is a blocking method! + // See example STM32WLx_Transmit_Interrupt for details + // on non-blocking transmission method. + int state = radio.transmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[STM32WL] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino new file mode 100644 index 0000000000..ea17838acb --- /dev/null +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -0,0 +1,140 @@ +/* + RadioLib STM32WLx Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// no need to configure pins, signals are routed to the radio internally +STM32WLx radio = new STM32WLx_Module(); + +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +static const RADIOLIB_PIN_TYPE rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + STM32WLx::END_OF_MODE_TABLE, +}; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WL with default settings, except frequency + Serial.print(F("[STM32WL] Initializing ... ")); + int state = radio.begin(868.0); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set appropriate TCXO voltage for Nucleo WL55JC1 + state = radio.setTCXO(1.7); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setDio1Action(setFlag); + + // start transmitting the first packet + Serial.print(F("[STM32WL] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[STM32WL] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.startTransmit(byteArr, 8); + */ + } +} From 6531ce7400cf2994ccc3cfdd9319c72014a4cf90 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 21 Dec 2022 18:16:07 +0100 Subject: [PATCH 0338/1848] [CI]: Set up CI for STM32WLx (CI_BUILD_ALL) This adds a build for the Nucleo WL55JC1 board, and ensures that the STM32WLx examples are skipped on all other boards. To slightly generalize the list of boards, this pushes the pnum option for the black pill into the boards list, instead of setting it into the options variable (even though it is technically a board option and not the board itself, conceptually it is part of the selected board and these values are just concatenated, so it can go in either place). Co-Authored-By: jgromes --- .github/workflows/main.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 688fe19c60..05a897f426 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,8 @@ jobs: - esp8266:esp8266:generic - Intel:arc32:arduino_101 - SparkFun:apollo3:sfe_artemis - - STMicroelectronics:stm32:GenF3 + - STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC + - STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1 - stm32duino:STM32F1:mapleMini - MegaCoreX:megaavr:4809 - arduino:mbed_rp2040:pico @@ -63,9 +64,9 @@ jobs: id: prep run: | - # common settings - no extra options, skip nothing, all warnings + # common settings - no extra options, skip STM32WL examples, all warnings echo "::set-output name=options::" - echo "::set-output name=skip-pattern::''" + echo "::set-output name=skip-pattern::'STM32WL'" echo "::set-output name=warnings::'all'" # platform-dependent settings - extra board options, board index URLs, skip patterns etc. @@ -109,9 +110,13 @@ jobs: elif [[ "${{ contains(matrix.board, 'STMicroelectronics:stm32') }}" == "true" ]]; then # STM32 (official core) - echo "::set-output name=options:::pnum=BLACKPILL_F303CC" echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" + if [[ "${{ contains(matrix.board, 'NUCLEO_WL55') }}" == "true" ]]; then + # Do *not* skip STM32WL examples + echo "::set-output name=skip-pattern::''" + fi + elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then # STM32 (unofficial core) echo "::set-output name=options:::bootloader_version=original,cpu_speed=speed_72mhz" From ba05317b7231bcf75ae8afb6071fabce201a18bc Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Dec 2022 12:40:46 +0100 Subject: [PATCH 0339/1848] Added new keywords --- keywords.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index 7ad8dbbdae..550790d257 100644 --- a/keywords.txt +++ b/keywords.txt @@ -38,6 +38,8 @@ SX1279 KEYWORD1 SX1280 KEYWORD1 SX1281 KEYWORD1 SX1282 KEYWORD1 +STM32WLx KEYWORD1 +STM32WLx_Module KEYWORD1 # protocols RTTYClient KEYWORD1 @@ -70,7 +72,7 @@ PasokonP7 KEYWORD1 # RadioLib ModuleA KEYWORD2 ModuleB KEYWORD2 -Module KEYWORD2 +setRfSwitchTable KEYWORD2 # SX127x/RFM9x + RF69 + CC1101 begin KEYWORD2 @@ -256,6 +258,7 @@ setInterruptSetup KEYWORD2 RADIOLIB_NC LITERAL1 RADIOLIB_VERSION LITERAL1 +RADIOLIB_PIN_TYPE LITERAL1 RADIOLIB_SHAPING_NONE LITERAL1 RADIOLIB_SHAPING_0_3 LITERAL1 From 5ca2c8533ca9e68e2246e77e0ff8eb11b2f5488c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Jan 2023 23:13:27 +0100 Subject: [PATCH 0340/1848] [PHY] Added standby types abstraction --- src/TypeDef.h | 25 +++++++++++++++++++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 +++ src/protocols/PhysicalLayer/PhysicalLayer.h | 7 ++++++ 3 files changed, 36 insertions(+) diff --git a/src/TypeDef.h b/src/TypeDef.h index e2d8c91450..50173814f4 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -63,6 +63,31 @@ \} */ +/*! + \defgroup config_standby Standby mode type aliases. + + \{ +*/ + +/*! + \brief Default standby used by the module +*/ +#define RADIOLIB_STANDBY_DEFAULT (0x00) + +/*! + \brief Warm standby (e.g. crystal left running). +*/ +#define RADIOLIB_STANDBY_WARM (0x01) + +/*! + \brief Cold standby (e.g. only internal RC oscillator running). +*/ +#define RADIOLIB_STANDBY_COLD (0x02) + +/*! + \} +*/ + /*! \defgroup status_codes Status Codes diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 7d45f9e0b7..48704beeba 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -111,6 +111,10 @@ int16_t PhysicalLayer::receive(uint8_t* data, size_t len) { } int16_t PhysicalLayer::standby() { + return(standby(RADIOLIB_STANDBY_DEFAULT)); +} + +int16_t PhysicalLayer::standby(uint8_t mode) { return(RADIOLIB_ERR_UNSUPPORTED); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index a5886f5336..aad936f8e4 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -91,6 +91,13 @@ class PhysicalLayer { */ virtual int16_t standby(); + /*! + \brief Sets module to a specific standby mode. + + \returns \ref status_codes + */ + virtual int16_t standby(uint8_t mode); + /*! \brief Binary receive method. Must be implemented in module class. From 2c8b63e0382b974e1c28826b079cdbca0f65960b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Jan 2023 23:13:58 +0100 Subject: [PATCH 0341/1848] [Hell] Fixed timing issues on SX126x with TCXO (#659) --- src/protocols/Hellschreiber/Hellschreiber.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index cab4759855..78eb3bdbc5 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -31,12 +31,15 @@ int16_t HellClient::begin(float base, float rate) { size_t HellClient::printGlyph(uint8_t* buff) { // print the character Module* mod = _phy->getMod(); + bool transmitting = false; for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { for(int8_t i = RADIOLIB_HELL_FONT_HEIGHT - 1; i >= 0; i--) { uint32_t start = mod->micros(); - if(buff[i] & mask) { + if((buff[i] & mask) && (!transmitting)) { + transmitting = true; transmitDirect(_base, _baseHz); - } else { + } else if((!(buff[i] & mask)) && (transmitting)) { + transmitting = false; standby(); } mod->waitForMicroseconds(start, _pixelDuration); @@ -302,7 +305,7 @@ int16_t HellClient::standby() { return(_audio->noTone(_inv)); } #endif - return(_phy->standby()); + return(_phy->standby(RADIOLIB_STANDBY_WARM)); } #endif From 5b963403327bb724e6db087f2d8f27cfd199015a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Jan 2023 23:20:27 +0100 Subject: [PATCH 0342/1848] [CC1101] Fixed setPromiscuousMode(true) always failing --- src/modules/CC1101/CC1101.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 8ad06742a0..72824fce1b 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -824,11 +824,8 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) { } if (promiscuous == true) { - // disable preamble detection and generation - state = setPreambleLength(0); - RADIOLIB_ASSERT(state); - // disable sync word filtering and insertion + // this also disables preamble state = disableSyncWordFiltering(); RADIOLIB_ASSERT(state); From 30489ba01077e34452e1da4e21ef3812dc4b2bb2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 15 Jan 2023 09:50:05 +0100 Subject: [PATCH 0343/1848] Added note about STM32WL to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1885feb900..c866a3430d 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __RFM2x__ series FSK modules (RFM22, RM23) * __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98) * __Si443x__ series FSK modules (Si4430, Si4431, Si4432) +* __STM32WL__ integrated microcontroller/LoRa module * __SX126x__ series LoRa modules (SX1261, SX1262, SX1268) * __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) * __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282) From eaaac36f286e29c6430819aaa0f5d7dcf041558b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 15 Jan 2023 17:42:44 +0100 Subject: [PATCH 0344/1848] Bump version to 5.6.0 --- library.properties | 2 +- src/BuildOpt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 87ce79d3b2..d6a1baaec1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.5.0 +version=5.6.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5e6ca96584..208add964e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1083,7 +1083,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x05) +#define RADIOLIB_VERSION_MINOR (0x06) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 3da909ec3dec81b3818813547c28d79b50ba0d81 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Jan 2023 18:12:56 +0100 Subject: [PATCH 0345/1848] [CI] Fixed deprecation warnings (CI_BUILD_ALL) --- .github/workflows/main.yml | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 05a897f426..53c5a02423 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,23 +65,23 @@ jobs: run: | # common settings - no extra options, skip STM32WL examples, all warnings - echo "::set-output name=options::" - echo "::set-output name=skip-pattern::'STM32WL'" - echo "::set-output name=warnings::'all'" + echo "name=options::" >> $GITHUB_OUTPUT + echo "name=skip-pattern::'STM32WL'" >> $GITHUB_OUTPUT + echo "name=warnings::'all'" >> $GITHUB_OUTPUT # platform-dependent settings - extra board options, board index URLs, skip patterns etc. if [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then # Arduino Mega - echo "::set-output name=options:::cpu=atmega2560" + echo "name=options:::cpu=atmega2560" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'arduino:megaavr:uno2018') }}" == "true" ]]; then # Arduino Uno WiFi - echo "::set-output name=options:::mode=on" + echo "name=options:::mode=on" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'adafruit:samd') }}" == "true" ]]; then # Adafruit SAMD - echo "::set-output name=options:::usbstack=arduino,debug=off" - echo "::set-output name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" + echo "name=options:::usbstack=arduino,debug=off" >> $GITHUB_OUTPUT + echo "name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'adafruit:nrf52') }}" == "true" ]]; then # Adafruit Feather nRF52 @@ -90,57 +90,57 @@ jobs: pip3 install wheel pip3 install --user adafruit-nrfutil echo "/home/runner/.local/bin" >> $GITHUB_PATH - echo "::set-output name=options:::softdevice=s132v6,debug=l0" - echo "::set-output name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" + echo "name=options:::softdevice=s132v6,debug=l0" >> $GITHUB_OUTPUT + echo "name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then # ESP32 python -m pip install pyserial - echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" - + echo "name=index-url::--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT + elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then # ESP8266 - echo "::set-output name=options:::xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K" - echo "::set-output name=index-url::--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" + echo "name=options:::xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K" >> $GITHUB_OUTPUT + echo "name=index-url::--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'SparkFun:apollo3') }}" == "true" ]]; then # SparkFun Apollo - echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" - echo "::set-output name=warnings::'none'" + echo "name=warnings::'none'" >> $GITHUB_OUTPUT + echo "name=index-url::--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'STMicroelectronics:stm32') }}" == "true" ]]; then # STM32 (official core) - echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" - + echo "name=index-url::--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT + if [[ "${{ contains(matrix.board, 'NUCLEO_WL55') }}" == "true" ]]; then # Do *not* skip STM32WL examples - echo "::set-output name=skip-pattern::''" + echo "name=skip-pattern::''" >> $GITHUB_OUTPUT fi elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then # STM32 (unofficial core) - echo "::set-output name=options:::bootloader_version=original,cpu_speed=speed_72mhz" - echo "::set-output name=index-url::--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" + echo "name=options:::bootloader_version=original,cpu_speed=speed_72mhz" >> $GITHUB_OUTPUT + echo "name=index-url::--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'MegaCoreX:megaavr') }}" == "true" ]]; then # MegaCoreX - echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" - + echo "name=index-url::--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT + elif [[ "${{ contains(matrix.board, 'CubeCell:CubeCell') }}" == "true" ]]; then # CubeCell - echo "::set-output name=index-url::--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" + echo "name=index-url::--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'rp2040:rp2040') }}" == "true" ]]; then # CubeCell - echo "::set-output name=index-url::--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" + echo "name=index-url::--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'MegaCore:avr') }}" == "true" ]]; then # MegaCore - echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" + echo "name=index-url::--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'teensy:avr') }}" == "true" ]]; then # Teensy - echo "::set-output name=index-url::--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" + echo "name=index-url::--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT fi From 143571e0a1dd4efe97b219c2f6991875ce9559fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Jan 2023 18:43:45 +0100 Subject: [PATCH 0346/1848] [CI] Try to fix broken index URLs (esp32:esp32:esp32) --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53c5a02423..5defc05c4f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,9 +65,9 @@ jobs: run: | # common settings - no extra options, skip STM32WL examples, all warnings - echo "name=options::" >> $GITHUB_OUTPUT - echo "name=skip-pattern::'STM32WL'" >> $GITHUB_OUTPUT - echo "name=warnings::'all'" >> $GITHUB_OUTPUT + echo "options=''" >> $GITHUB_OUTPUT + echo "skip-pattern='STM32WL'" >> $GITHUB_OUTPUT + echo "warnings='all'" >> $GITHUB_OUTPUT # platform-dependent settings - extra board options, board index URLs, skip patterns etc. if [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then @@ -96,7 +96,7 @@ jobs: elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then # ESP32 python -m pip install pyserial - echo "name=index-url::--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT + echo "index-url='--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json'" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then # ESP8266 From c478d9db209cf369ef86610bccc6f80ff02786e4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Jan 2023 18:45:37 +0100 Subject: [PATCH 0347/1848] [CI] Remove extra quotes (esp32:esp32:esp32) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5defc05c4f..83078ea816 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -96,7 +96,7 @@ jobs: elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then # ESP32 python -m pip install pyserial - echo "index-url='--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then # ESP8266 From 230fd3376a3be8d835c6370c3bbb2ca1253bf3b9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Jan 2023 18:52:28 +0100 Subject: [PATCH 0348/1848] [CI] Fixed remaining output variables (CI_BUILD_ALL) --- .github/workflows/main.yml | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 83078ea816..5267e28723 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,22 +66,22 @@ jobs: | # common settings - no extra options, skip STM32WL examples, all warnings echo "options=''" >> $GITHUB_OUTPUT - echo "skip-pattern='STM32WL'" >> $GITHUB_OUTPUT - echo "warnings='all'" >> $GITHUB_OUTPUT + echo "skip-pattern=STM32WL" >> $GITHUB_OUTPUT + echo "warnings=all" >> $GITHUB_OUTPUT # platform-dependent settings - extra board options, board index URLs, skip patterns etc. if [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then # Arduino Mega - echo "name=options:::cpu=atmega2560" >> $GITHUB_OUTPUT + echo "options='cpu=atmega2560'" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'arduino:megaavr:uno2018') }}" == "true" ]]; then # Arduino Uno WiFi - echo "name=options:::mode=on" >> $GITHUB_OUTPUT + echo "options='mode=on'" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'adafruit:samd') }}" == "true" ]]; then # Adafruit SAMD - echo "name=options:::usbstack=arduino,debug=off" >> $GITHUB_OUTPUT - echo "name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + echo "options='usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'adafruit:nrf52') }}" == "true" ]]; then # Adafruit Feather nRF52 @@ -90,8 +90,8 @@ jobs: pip3 install wheel pip3 install --user adafruit-nrfutil echo "/home/runner/.local/bin" >> $GITHUB_PATH - echo "name=options:::softdevice=s132v6,debug=l0" >> $GITHUB_OUTPUT - echo "name=index-url::--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + echo "options='softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then # ESP32 @@ -100,47 +100,47 @@ jobs: elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then # ESP8266 - echo "name=options:::xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K" >> $GITHUB_OUTPUT - echo "name=index-url::--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT + echo "options='xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'SparkFun:apollo3') }}" == "true" ]]; then # SparkFun Apollo - echo "name=warnings::'none'" >> $GITHUB_OUTPUT - echo "name=index-url::--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT + echo "warnings='none'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'STMicroelectronics:stm32') }}" == "true" ]]; then # STM32 (official core) - echo "name=index-url::--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT if [[ "${{ contains(matrix.board, 'NUCLEO_WL55') }}" == "true" ]]; then # Do *not* skip STM32WL examples - echo "name=skip-pattern::''" >> $GITHUB_OUTPUT + echo "skip-pattern=''" >> $GITHUB_OUTPUT fi elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then # STM32 (unofficial core) - echo "name=options:::bootloader_version=original,cpu_speed=speed_72mhz" >> $GITHUB_OUTPUT - echo "name=index-url::--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT + echo "options='bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'MegaCoreX:megaavr') }}" == "true" ]]; then # MegaCoreX - echo "name=index-url::--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'CubeCell:CubeCell') }}" == "true" ]]; then # CubeCell - echo "name=index-url::--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'rp2040:rp2040') }}" == "true" ]]; then # CubeCell - echo "name=index-url::--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'MegaCore:avr') }}" == "true" ]]; then # MegaCore - echo "name=index-url::--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'teensy:avr') }}" == "true" ]]; then # Teensy - echo "name=index-url::--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT fi From 39aac172a45a033a3e3bf0f3bed49592f52c19a8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Jan 2023 18:55:28 +0100 Subject: [PATCH 0349/1848] [CI] Fixed missing colon (CI_BUILD_ALL) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5267e28723..e207ccbb55 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -167,7 +167,7 @@ jobs: else # build sketch echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.board }}${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.board }}:${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} if [ $? -ne 0 ]; then echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; exit 1; From b78693b8fbb5f628cdc6dd12923de0f508eaab22 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Jan 2023 18:58:50 +0100 Subject: [PATCH 0350/1848] [CI] Fixed options (CI_BUILD_ALL) --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e207ccbb55..77630a1dd8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -72,15 +72,15 @@ jobs: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. if [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then # Arduino Mega - echo "options='cpu=atmega2560'" >> $GITHUB_OUTPUT + echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'arduino:megaavr:uno2018') }}" == "true" ]]; then # Arduino Uno WiFi - echo "options='mode=on'" >> $GITHUB_OUTPUT + echo "options=':mode=on'" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'adafruit:samd') }}" == "true" ]]; then # Adafruit SAMD - echo "options='usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT + echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'adafruit:nrf52') }}" == "true" ]]; then @@ -90,7 +90,7 @@ jobs: pip3 install wheel pip3 install --user adafruit-nrfutil echo "/home/runner/.local/bin" >> $GITHUB_PATH - echo "options='softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT + echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then @@ -100,7 +100,7 @@ jobs: elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then # ESP8266 - echo "options='xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT + echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'SparkFun:apollo3') }}" == "true" ]]; then @@ -119,7 +119,7 @@ jobs: elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then # STM32 (unofficial core) - echo "options='bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT + echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT elif [[ "${{ contains(matrix.board, 'MegaCoreX:megaavr') }}" == "true" ]]; then @@ -167,7 +167,7 @@ jobs: else # build sketch echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.board }}:${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.board }}${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} if [ $? -ne 0 ]; then echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; exit 1; From 35ed685c8a78188006e40939980620236c0c921b Mon Sep 17 00:00:00 2001 From: Andrew Moroz Date: Mon, 16 Jan 2023 00:14:54 -0500 Subject: [PATCH 0351/1848] andrew-moroz/sx126x-rx-boosted-gain: Add method to support SX126x Rx Boosted Gain mode --- keywords.txt | 1 + src/modules/SX126x/SX126x.cpp | 20 ++++++++++++++++++++ src/modules/SX126x/SX126x.h | 9 +++++++++ 3 files changed, 30 insertions(+) diff --git a/keywords.txt b/keywords.txt index 550790d257..c13d0ff667 100644 --- a/keywords.txt +++ b/keywords.txt @@ -194,6 +194,7 @@ setRegulatorDCDC KEYWORD2 getCurrentLimit KEYWORD2 getIrqStatus KEYWORD2 getLastError KEYWORD2 +setRxBoostedGainMode KEYWORD2 # nRF24 setIrqAction KEYWORD2 diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2e95d77882..1e23dda22a 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -870,6 +870,26 @@ int16_t SX126x::setRxBandwidth(float rxBw) { return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); } +int16_t SX126x::setRxBoostedGainMode(bool rxbgm) { + // read the current register value + uint8_t rxGain = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); + RADIOLIB_ASSERT(state); + + // gain mode register value (SX1261/2 datasheet v2.1 section 9.6) + if(rxbgm) { + rxGain = 0x96; // Rx Boosted Gain + } else { + rxGain = 0x94; // Rx Power Saving Gain + } + + // update RX gain setting register + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX126x::setDataShaping(uint8_t sh) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 97cb77e1ba..12a737f98e 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -708,6 +708,15 @@ class SX126x: public PhysicalLayer { */ int16_t setRxBandwidth(float rxBw); + /*! + \brief Enables or disables Rx Boosted Gain mode as described in SX126x datasheet section 9.6 (SX1261/2 v2.1, SX1268 v1.1) + + \param rxbgm True for Rx Boosted Gain, false for Rx Power Saving Gain + + \returns \ref status_codes + */ + int16_t setRxBoostedGainMode(bool rxbgm); + /*! \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. From 0a0f6979dde705126656b7858ce367df1edd4237 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Jan 2023 18:58:26 +0100 Subject: [PATCH 0352/1848] [RF69] Set minimum bit rate to 0.5 kbps --- src/modules/RF69/RF69.cpp | 3 ++- src/modules/RF69/RF69.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index ff6306da73..d2f17d826f 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -538,7 +538,8 @@ int16_t RF69::getFrequency(float *freq) { } int16_t RF69::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine + RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); // check bitrate-bandwidth ratio if(!(br < 2000 * _rxBw)) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d47673295e..f4cc8495f3 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -746,7 +746,7 @@ class RF69: public PhysicalLayer { int16_t getFrequency(float *freq); /*! - \brief Sets bit rate. Allowed values range from 1.2 to 300.0 kbps. + \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. \param br Bit rate to be set in kbps. From 91d42ebf0e1f8eac5c1387e9cd7e8db0843944a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Jan 2023 18:58:52 +0100 Subject: [PATCH 0353/1848] [SX127x] Set minimum bit rate to 0.5 kbps (#665) --- src/modules/SX127x/SX127x.cpp | 5 +++-- src/modules/SX127x/SX127x.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b6e4441af2..5052cc69c4 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -823,10 +823,11 @@ int16_t SX127x::setBitRate(float br) { } // check allowed bit rate + // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine if(_ook) { - RADIOLIB_CHECK_RANGE(br, 1.2, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 + RADIOLIB_CHECK_RANGE(br, 0.5, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 } else { - RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); } // set mode to STANDBY diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e7502c1571..13083b644f 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -902,7 +902,7 @@ class SX127x: public PhysicalLayer { float getDataRate() const; /*! - \brief Sets FSK bit rate. Allowed values range from 1.2 to 300 kbps. Only available in FSK mode. + \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. \param br Bit rate to be set (in kbps). From 18ff62890afcf8c0ddd20ab5d039b268d6753c88 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Jan 2023 22:00:26 +0100 Subject: [PATCH 0354/1848] [SX127x] Fixed packet length not proagating correctly (#666) --- src/modules/SX127x/SX127x.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 5052cc69c4..c5d857fc60 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -381,6 +381,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // set expected packet length for SF6 if(_sf == 6) { state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + _packetLength = len; } // apply fixes to errata From e353844afe1d415c1844ef2fceaa13447174b7d0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Jan 2023 19:13:06 +0100 Subject: [PATCH 0355/1848] Added uncrustify config file --- uncrustify.cfg | 3593 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3593 insertions(+) create mode 100644 uncrustify.cfg diff --git a/uncrustify.cfg b/uncrustify.cfg new file mode 100644 index 0000000000..6cdf9d4c5f --- /dev/null +++ b/uncrustify.cfg @@ -0,0 +1,3593 @@ +# Uncrustify-0.76.0-23-49c34941 + +# +# General options +# + +# The type of line endings. +# +# Default: auto +newlines = auto # lf/crlf/cr/auto + +# The original size of tabs in the input. +# +# Default: 8 +input_tab_size = 2 # unsigned number + +# The size of tabs in the output (only used if align_with_tabs=true). +# +# Default: 8 +output_tab_size = 2 # unsigned number + +# The ASCII value of the string escape char, usually 92 (\) or (Pawn) 94 (^). +# +# Default: 92 +string_escape_char = 92 # unsigned number + +# Alternate string escape char (usually only used for Pawn). +# Only works right before the quote char. +string_escape_char2 = 0 # unsigned number + +# Replace tab characters found in string literals with the escape sequence \t +# instead. +string_replace_tab_chars = true # true/false + +# Allow interpreting '>=' and '>>=' as part of a template in code like +# 'void f(list>=val);'. If true, 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # true/false + +# Disable formatting of NL_CONT ('\\n') ended lines (e.g. multi-line macros). +disable_processing_nl_cont = false # true/false + +# Specify the marker used in comments to disable processing of part of the +# file. +# +# Default: *INDENT-OFF* +disable_processing_cmt = " *INDENT-OFF*" # string + +# Specify the marker used in comments to (re)enable processing in a file. +# +# Default: *INDENT-ON* +enable_processing_cmt = " *INDENT-ON*" # string + +# Enable parsing of digraphs. +enable_digraphs = false # true/false + +# Option to allow both disable_processing_cmt and enable_processing_cmt +# strings, if specified, to be interpreted as ECMAScript regular expressions. +# If true, a regex search will be performed within comments according to the +# specified patterns in order to disable/enable processing. +processing_cmt_as_regex = false # true/false + +# Add or remove the UTF-8 BOM (recommend 'remove'). +utf8_bom = remove # ignore/add/remove/force/not_defined + +# If the file contains bytes with values between 128 and 255, but is not +# UTF-8, then output as UTF-8. +utf8_byte = false # true/false + +# Force the output encoding to UTF-8. +utf8_force = false # true/false + +# +# Spacing options +# + +# Add or remove space around non-assignment symbolic operators ('+', '/', '%', +# '<<', and so forth). +sp_arith = force # ignore/add/remove/force/not_defined + +# Add or remove space around arithmetic operators '+' and '-'. +# +# Overrides sp_arith. +sp_arith_additive = force # ignore/add/remove/force/not_defined + +# Add or remove space around assignment operator '=', '+=', etc. +sp_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space around '=' in C++11 lambda capture specifications. +# +# Overrides sp_assign. +sp_cpp_lambda_assign = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the capture specification of a C++11 lambda when +# an argument list is present, as in '[] (int x){ ... }'. +sp_cpp_lambda_square_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the capture specification of a C++11 lambda with +# no argument list is present, as in '[] { ... }'. +sp_cpp_lambda_square_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the opening parenthesis and before the closing +# parenthesis of a argument list of a C++11 lambda, as in +# '[]( int x ){ ... }'. +sp_cpp_lambda_argument_list = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the argument list of a C++11 lambda, as in +# '[](int x) { ... }'. +sp_cpp_lambda_paren_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a lambda body and its call operator of an +# immediately invoked lambda, as in '[]( ... ){ ... } ( ... )'. +sp_cpp_lambda_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around assignment operator '=' in a prototype. +# +# If set to ignore, use sp_assign. +sp_assign_default = force # ignore/add/remove/force/not_defined + +# Add or remove space before assignment operator '=', '+=', etc. +# +# Overrides sp_assign. +sp_before_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space after assignment operator '=', '+=', etc. +# +# Overrides sp_assign. +sp_after_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space in 'enum {'. +# +# Default: add +sp_enum_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space in 'NS_ENUM ('. +sp_enum_paren = force # ignore/add/remove/force/not_defined + +# Add or remove space around assignment '=' in enum. +sp_enum_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space before assignment '=' in enum. +# +# Overrides sp_enum_assign. +sp_enum_before_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space after assignment '=' in enum. +# +# Overrides sp_enum_assign. +sp_enum_after_assign = force # ignore/add/remove/force/not_defined + +# Add or remove space around assignment ':' in enum. +sp_enum_colon = force # ignore/add/remove/force/not_defined + +# Add or remove space around preprocessor '##' concatenation operator. +# +# Default: add +sp_pp_concat = remove # ignore/add/remove/force/not_defined + +# Add or remove space after preprocessor '#' stringify operator. +# Also affects the '#@' charizing operator. +sp_pp_stringify = remove # ignore/add/remove/force/not_defined + +# Add or remove space before preprocessor '#' stringify operator +# as in '#define x(y) L#y'. +sp_before_pp_stringify = remove # ignore/add/remove/force/not_defined + +# Add or remove space around boolean operators '&&' and '||'. +sp_bool = force # ignore/add/remove/force/not_defined + +# Add or remove space around compare operator '<', '>', '==', etc. +sp_compare = force # ignore/add/remove/force/not_defined + +# Add or remove space inside '(' and ')'. +sp_inside_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between nested parentheses, i.e. '((' vs. ') )'. +sp_paren_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. +sp_cparen_oparen = remove # ignore/add/remove/force/not_defined + +# Whether to balance spaces inside nested parentheses. +sp_balance_nested_parens = false # true/false + +# Add or remove space between ')' and '{'. +sp_paren_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space between nested braces, i.e. '{{' vs. '{ {'. +sp_brace_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space before pointer star '*'. +sp_before_ptr_star = remove # ignore/add/remove/force/not_defined + +# Add or remove space before pointer star '*' that isn't followed by a +# variable name. If set to ignore, sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = force # ignore/add/remove/force/not_defined + +# Add or remove space between pointer stars '*', as in 'int ***a;'. +sp_between_ptr_star = remove # ignore/add/remove/force/not_defined + +# Add or remove space after pointer star '*', if followed by a word. +# +# Overrides sp_type_func. +sp_after_ptr_star = force # ignore/add/remove/force/not_defined + +# Add or remove space after pointer caret '^', if followed by a word. +sp_after_ptr_block_caret = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after pointer star '*', if followed by a qualifier. +sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a pointer star '*', if followed by a function +# prototype or function definition. +# +# Overrides sp_after_ptr_star and sp_type_func. +sp_after_ptr_star_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a pointer star '*' in the trailing return of a +# function prototype or function definition. +sp_after_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the pointer star '*' and the name of the variable +# in a function pointer definition. +sp_ptr_star_func_var = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the pointer star '*' and the name of the type +# in a function pointer type definition. +sp_ptr_star_func_type = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a pointer star '*', if followed by an open +# parenthesis, as in 'void* (*)()'. +sp_ptr_star_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a pointer star '*', if followed by a function +# prototype or function definition. +sp_before_ptr_star_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a pointer star '*' in the trailing return of a +# function prototype or function definition. +sp_before_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a reference sign '&'. +sp_before_byref = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a reference sign '&' that isn't followed by a +# variable name. If set to ignore, sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after reference sign '&', if followed by a word. +# +# Overrides sp_type_func. +sp_after_byref = force # ignore/add/remove/force/not_defined + +# Add or remove space after a reference sign '&', if followed by a function +# prototype or function definition. +# +# Overrides sp_after_byref and sp_type_func. +sp_after_byref_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a reference sign '&', if followed by a function +# prototype or function definition. +sp_before_byref_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after a reference sign '&', if followed by an open +# parenthesis, as in 'char& (*)()'. +sp_byref_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between type and word. In cases where total removal of +# whitespace would be a syntax error, a value of 'remove' is treated the same +# as 'force'. +# +# This also affects some other instances of space following a type that are +# not covered by other options; for example, between the return type and +# parenthesis of a function type template argument, between the type and +# parenthesis of an array parameter, or between 'decltype(...)' and the +# following word. +# +# Default: force +sp_after_type = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'decltype(...)' and word, +# brace or function call. +sp_after_decltype = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space before the parenthesis in the D constructs +# 'template Foo(' and 'class Foo('. +sp_before_template_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'template' and '<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '<'. +sp_before_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '<' and '>'. +sp_inside_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '<>'. +sp_inside_angle_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and ':'. +sp_angle_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '>'. +sp_after_angle = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and '(' as found in 'new List(foo);'. +sp_angle_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and '()' as found in 'new List();'. +sp_angle_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and a word as in 'List m;' or +# 'template static ...'. +sp_angle_word = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '>' and '>' in '>>' (template stuff). +# +# Default: add +sp_angle_shift = add # ignore/add/remove/force/not_defined + +# (C++11) Permit removal of the space between '>>' in 'foo >'. Note +# that sp_angle_shift cannot remove the space without this option. +sp_permit_cpp11_shift = false # true/false + +# Add or remove space before '(' of control statements ('if', 'for', 'switch', +# 'while', etc.). +sp_before_sparen = remove # ignore/add/remove/force/not_defined + +# Add or remove space inside '(' and ')' of control statements other than +# 'for'. +sp_inside_sparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '(' of control statements other than 'for'. +# +# Overrides sp_inside_sparen. +sp_inside_sparen_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ')' of control statements other than 'for'. +# +# Overrides sp_inside_sparen. +sp_inside_sparen_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '(' and ')' of 'for' statements. +sp_inside_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '(' of 'for' statements. +# +# Overrides sp_inside_for. +sp_inside_for_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ')' of 'for' statements. +# +# Overrides sp_inside_for. +sp_inside_for_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '((' or '))' of control statements. +sp_sparen_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ')' of control statements. +sp_after_sparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '{' of control statements. +sp_sparen_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'do' and '{'. +sp_do_brace_open = force # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'while'. +sp_brace_close_while = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'while' and '('. Overrides sp_before_sparen. +sp_while_paren_open = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'invariant' and '('. +sp_invariant_paren = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space after the ')' in 'invariant (C) c'. +sp_after_invariant_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while'. +sp_special_semi = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ';'. +# +# Default: remove +sp_before_semi = remove # ignore/add/remove/force/not_defined + +# Add or remove space before ';' in non-empty 'for' statements. +sp_before_semi_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a semicolon of an empty left part of a for +# statement, as in 'for ( ; ; )'. +sp_before_semi_for_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the semicolons of an empty middle part of a for +# statement, as in 'for ( ; ; )'. +sp_between_semi_for_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ';', except when followed by a comment. +# +# Default: add +sp_after_semi = add # ignore/add/remove/force/not_defined + +# Add or remove space after ';' in non-empty 'for' statements. +# +# Default: force +sp_after_semi_for = force # ignore/add/remove/force/not_defined + +# Add or remove space after the final semicolon of an empty part of a for +# statement, as in 'for ( ; ; )'. +sp_after_semi_for_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '[' (except '[]'). +sp_before_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '[' for a variable definition. +# +# Default: remove +sp_before_vardef_square = remove # ignore/add/remove/force/not_defined + +# Add or remove space before '[' for asm block. +sp_before_square_asm_block = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before '[]'. +sp_before_squares = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before C++17 structured bindings. +sp_cpp_before_struct_binding = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside a non-empty '[' and ']'. +sp_inside_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '[]'. +sp_inside_square_empty = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and +# ']'. If set to ignore, sp_inside_square is used. +sp_inside_square_oc_array = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. +sp_after_comma = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ',', i.e. 'a,b' vs. 'a ,b'. +# +# Default: remove +sp_before_comma = remove # ignore/add/remove/force/not_defined + +# (C#, Vala) Add or remove space between ',' and ']' in multidimensional array type +# like 'int[,,]'. +sp_after_mdatype_commas = ignore # ignore/add/remove/force/not_defined + +# (C#, Vala) Add or remove space between '[' and ',' in multidimensional array type +# like 'int[,,]'. +sp_before_mdatype_commas = ignore # ignore/add/remove/force/not_defined + +# (C#, Vala) Add or remove space between ',' in multidimensional array type +# like 'int[,,]'. +sp_between_mdatype_commas = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between an open parenthesis and comma, +# i.e. '(,' vs. '( ,'. +# +# Default: force +sp_paren_comma = force # ignore/add/remove/force/not_defined + +# Add or remove space between a type and ':'. +sp_type_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the variadic '...' when preceded by a +# non-punctuator. +# The value REMOVE will be overridden with FORCE +sp_after_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the variadic '...' when preceded by a +# non-punctuator. +# The value REMOVE will be overridden with FORCE +sp_before_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a type and '...'. +sp_type_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a '*' and '...'. +sp_ptr_type_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '...'. +sp_paren_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '&&' and '...'. +sp_byref_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and a qualifier such as 'const'. +sp_paren_qualifier = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and 'noexcept'. +sp_paren_noexcept = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after class ':'. +sp_after_class_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before class ':'. +sp_before_class_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after class constructor ':'. +# +# Default: add +sp_after_constr_colon = add # ignore/add/remove/force/not_defined + +# Add or remove space before class constructor ':'. +# +# Default: add +sp_before_constr_colon = add # ignore/add/remove/force/not_defined + +# Add or remove space before case ':'. +# +# Default: remove +sp_before_case_colon = remove # ignore/add/remove/force/not_defined + +# Add or remove space between 'operator' and operator sign. +sp_after_operator = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the operator symbol and the open parenthesis, as +# in 'operator ++('. +sp_after_operator_sym = ignore # ignore/add/remove/force/not_defined + +# Overrides sp_after_operator_sym when the operator has no arguments, as in +# 'operator *()'. +sp_after_operator_sym_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or +# '(int)a' vs. '(int) a'. +sp_after_cast = ignore # ignore/add/remove/force/not_defined + +# Add or remove spaces inside cast parentheses. +sp_inside_paren_cast = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the type and open parenthesis in a C++ cast, +# i.e. 'int(exp)' vs. 'int (exp)'. +sp_cpp_cast_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'sizeof' and '('. +sp_sizeof_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'sizeof' and '...'. +sp_sizeof_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'sizeof...' and '('. +sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '...' and a parameter pack. +sp_ellipsis_parameter_pack = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a parameter pack and '...'. +sp_parameter_pack_ellipsis = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'decltype' and '('. +sp_decltype_paren = ignore # ignore/add/remove/force/not_defined + +# (Pawn) Add or remove space after the tag keyword. +sp_after_tag = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside enum '{' and '}'. +sp_inside_braces_enum = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside struct/union '{' and '}'. +sp_inside_braces_struct = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' +sp_inside_braces_oc_dict = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after open brace in an unnamed temporary +# direct-list-initialization +# if statement is a brace_init_lst +# works only if sp_brace_brace is set to ignore. +sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before close brace in an unnamed temporary +# direct-list-initialization +# if statement is a brace_init_lst +# works only if sp_brace_brace is set to ignore. +sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside an unnamed temporary direct-list-initialization +# if statement is a brace_init_lst +# works only if sp_brace_brace is set to ignore +# works only if sp_before_type_brace_init_lst_close is set to ignore. +sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '{' and '}'. +sp_inside_braces = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside '{}'. +sp_inside_braces_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around trailing return operator '->'. +sp_trailing_return = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between return type and function name. A minimum of 1 +# is forced except for pointer return types. +sp_type_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between type and open brace of an unnamed temporary +# direct-list-initialization. +sp_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '(' on function declaration. +sp_func_proto_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '()' on function declaration +# without parameters. +sp_func_proto_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '(' with a typedef specifier. +sp_func_type_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between alias name and '(' of a non-pointer function type typedef. +sp_func_def_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '()' on function definition +# without parameters. +sp_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside empty function '()'. +# Overrides sp_after_angle unless use_sp_after_angle_always is set to true. +sp_inside_fparens = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside function '(' and ')'. +sp_inside_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside the first parentheses in a function type, as in +# 'void (*x)(...)'. +sp_inside_tparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the ')' and '(' in a function type, as in +# 'void (*x)(...)'. +sp_after_tparen_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '{' of function. +sp_fparen_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and '{' of a function call in object +# initialization. +# +# Overrides sp_fparen_brace. +sp_fparen_brace_initializer = ignore # ignore/add/remove/force/not_defined + +# (Java) Add or remove space between ')' and '{{' of double brace initializer. +sp_fparen_dbrace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '(' on function calls. +sp_func_call_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between function name and '()' on function calls without +# parameters. If set to ignore (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between the user function name and '(' on function +# calls. You need to set a keyword to be a user function in the config file, +# like: +# set func_call_user tr _ i18n +sp_func_call_user_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside user function '(' and ')'. +sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between nested parentheses with user functions, +# i.e. '((' vs. '( ('. +sp_func_call_user_paren_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a constructor/destructor and the open +# parenthesis. +sp_func_class_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a constructor without parameters or destructor +# and '()'. +sp_func_class_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after 'return'. +# +# Default: force +sp_return = force # ignore/add/remove/force/not_defined + +# Add or remove space between 'return' and '('. +sp_return_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'return' and '{'. +sp_return_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '__attribute__' and '('. +sp_attribute_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)'. +sp_defined_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'throw' and '(' in 'throw (something)'. +sp_throw_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'throw' and anything other than '(' as in +# '@throw [...];'. +sp_after_throw = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'catch' and '(' in 'catch (something) { }'. +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@catch' and '(' +# in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. +sp_oc_catch_paren = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before Objective-C protocol list +# as in '@protocol Protocol' or '@interface MyClass : NSObject'. +sp_before_oc_proto_list = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between class name and '(' +# in '@interface className(categoryName):BaseClass' +sp_oc_classname_paren = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'version' and '(' +# in 'version (something) { }'. If set to ignore, sp_before_sparen is used. +sp_version_paren = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'scope' and '(' +# in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. +sp_scope_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'super' and '(' in 'super (something)'. +# +# Default: remove +sp_super_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between 'this' and '(' in 'this (something)'. +# +# Default: remove +sp_this_paren = remove # ignore/add/remove/force/not_defined + +# Add or remove space between a macro name and its definition. +sp_macro = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a macro function ')' and its definition. +sp_macro_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'else' and '{' if on the same line. +sp_else_brace = force # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'else' if on the same line. +sp_brace_else = force # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and the name of a typedef on the same line. +sp_brace_typedef = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the '{' of a 'catch' statement, if the '{' and +# 'catch' are on the same line, as in 'catch (decl) {'. +sp_catch_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' +# and '@catch' are on the same line, as in '@catch (decl) {'. +# If set to ignore, sp_catch_brace is used. +sp_oc_catch_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'catch' if on the same line. +sp_brace_catch = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '}' and '@catch' if on the same line. +# If set to ignore, sp_brace_catch is used. +sp_oc_brace_catch = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'finally' and '{' if on the same line. +sp_finally_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between '}' and 'finally' if on the same line. +sp_brace_finally = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'try' and '{' if on the same line. +sp_try_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between get/set and '{' if on the same line. +sp_getset_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a variable and '{' for C++ uniform +# initialization. +sp_word_brace_init_lst = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between a variable and '{' for a namespace. +# +# Default: add +sp_word_brace_ns = add # ignore/add/remove/force/not_defined + +# Add or remove space before the '::' operator. +sp_before_dc = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '::' operator. +sp_after_dc = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove around the D named array initializer ':' operator. +sp_d_array_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '!' (not) unary operator. +# +# Default: remove +sp_not = remove # ignore/add/remove/force/not_defined + +# Add or remove space between two '!' (not) unary operators. +# If set to ignore, sp_not will be used. +sp_not_not = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '~' (invert) unary operator. +# +# Default: remove +sp_inv = remove # ignore/add/remove/force/not_defined + +# Add or remove space after the '&' (address-of) unary operator. This does not +# affect the spacing after a '&' that is part of a type. +# +# Default: remove +sp_addr = remove # ignore/add/remove/force/not_defined + +# Add or remove space around the '.' or '->' operators. +# +# Default: remove +sp_member = remove # ignore/add/remove/force/not_defined + +# Add or remove space after the '*' (dereference) unary operator. This does +# not affect the spacing after a '*' that is part of a type. +# +# Default: remove +sp_deref = remove # ignore/add/remove/force/not_defined + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. +# +# Default: remove +sp_sign = remove # ignore/add/remove/force/not_defined + +# Add or remove space between '++' and '--' the word to which it is being +# applied, as in '(--x)' or 'y++;'. +# +# Default: remove +sp_incdec = remove # ignore/add/remove/force/not_defined + +# Add or remove space before a backslash-newline at the end of a line. +# +# Default: add +sp_before_nl_cont = add # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' +# or '+(int) bar;'. +sp_after_oc_scope = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the colon in message specs, +# i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. +sp_after_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the colon in message specs, +# i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. +sp_before_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};'. +sp_after_oc_dict_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};'. +sp_before_oc_dict_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the colon in message specs, +# i.e. '[object setValue:1];' vs. '[object setValue: 1];'. +sp_after_send_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before the colon in message specs, +# i.e. '[object setValue:1];' vs. '[object setValue :1];'. +sp_before_send_oc_colon = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the (type) in message specs, +# i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. +sp_after_oc_type = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after the first (type) in message specs, +# i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. +sp_after_oc_return_type = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@selector' and '(', +# i.e. '@selector(msgName)' vs. '@selector (msgName)'. +# Also applies to '@protocol()' constructs. +sp_after_oc_at_sel = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@selector(x)' and the following word, +# i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space inside '@selector' parentheses, +# i.e. '@selector(foo)' vs. '@selector( foo )'. +# Also applies to '@protocol()' constructs. +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space before a block pointer caret, +# i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. +sp_before_oc_block_caret = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after a block pointer caret, +# i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. +sp_after_oc_block_caret = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between the receiver and selector in a message, +# as in '[receiver selector ...]'. +sp_after_oc_msg_receiver = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space after '@property'. +sp_after_oc_property = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove space between '@synchronized' and the open parenthesis, +# i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. +sp_after_oc_synchronized = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around the ':' in 'b ? t : f'. +sp_cond_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the ':' in 'b ? t : f'. +# +# Overrides sp_cond_colon. +sp_cond_colon_before = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the ':' in 'b ? t : f'. +# +# Overrides sp_cond_colon. +sp_cond_colon_after = ignore # ignore/add/remove/force/not_defined + +# Add or remove space around the '?' in 'b ? t : f'. +sp_cond_question = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the '?' in 'b ? t : f'. +# +# Overrides sp_cond_question. +sp_cond_question_before = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the '?' in 'b ? t : f'. +# +# Overrides sp_cond_question. +sp_cond_question_after = ignore # ignore/add/remove/force/not_defined + +# In the abbreviated ternary form '(a ?: b)', add or remove space between '?' +# and ':'. +# +# Overrides all other sp_cond_* options. +sp_cond_ternary_short = ignore # ignore/add/remove/force/not_defined + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make +# sense here. +sp_case_label = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space around the D '..' operator. +sp_range = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after ':' in a Java/C++11 range-based 'for', +# as in 'for (Type var : expr)'. +sp_after_for_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before ':' in a Java/C++11 range-based 'for', +# as in 'for (Type var : expr)'. +sp_before_for_colon = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove space between 'extern' and '(' as in 'extern (C)'. +sp_extern_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the opening of a C++ comment, as in '// A'. +sp_cmt_cpp_start = force # ignore/add/remove/force/not_defined + +# Add or remove space in a C++ region marker comment, as in '// BEGIN'. +# A region marker is defined as a comment which is not preceded by other text +# (i.e. the comment is the first non-whitespace on the line), and which starts +# with either 'BEGIN' or 'END'. +# +# Overrides sp_cmt_cpp_start. +sp_cmt_cpp_region = ignore # ignore/add/remove/force/not_defined + +# If true, space added with sp_cmt_cpp_start will be added after Doxygen +# sequences like '///', '///<', '//!' and '//!<'. +sp_cmt_cpp_doxygen = true # true/false + +# If true, space added with sp_cmt_cpp_start will be added after Qt translator +# or meta-data comments like '//:', '//=', and '//~'. +sp_cmt_cpp_qttr = false # true/false + +# Add or remove space between #else or #endif and a trailing comment. +sp_endif_cmt = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after 'new', 'delete' and 'delete[]'. +sp_after_new = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between 'new' and '(' in 'new()'. +sp_between_new_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space between ')' and type in 'new(foo) BAR'. +sp_after_newop_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space inside parentheses of the new operator +# as in 'new(foo) BAR'. +sp_inside_newop_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after the open parenthesis of the new operator, +# as in 'new(foo) BAR'. +# +# Overrides sp_inside_newop_paren. +sp_inside_newop_paren_open = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before the close parenthesis of the new operator, +# as in 'new(foo) BAR'. +# +# Overrides sp_inside_newop_paren. +sp_inside_newop_paren_close = ignore # ignore/add/remove/force/not_defined + +# Add or remove space before a trailing comment. +sp_before_tr_cmt = ignore # ignore/add/remove/force/not_defined + +# Number of spaces before a trailing comment. +sp_num_before_tr_cmt = 0 # unsigned number + +# Add or remove space before an embedded comment. +# +# Default: force +sp_before_emb_cmt = force # ignore/add/remove/force/not_defined + +# Number of spaces before an embedded comment. +# +# Default: 1 +sp_num_before_emb_cmt = 1 # unsigned number + +# Add or remove space after an embedded comment. +# +# Default: force +sp_after_emb_cmt = remove # ignore/add/remove/force/not_defined + +# Number of spaces after an embedded comment. +# +# Default: 1 +sp_num_after_emb_cmt = 1 # unsigned number + +# (Java) Add or remove space between an annotation and the open parenthesis. +sp_annotation_paren = ignore # ignore/add/remove/force/not_defined + +# If true, vbrace tokens are dropped to the previous token and skipped. +sp_skip_vbrace_tokens = false # true/false + +# Add or remove space after 'noexcept'. +sp_after_noexcept = ignore # ignore/add/remove/force/not_defined + +# Add or remove space after '_'. +sp_vala_after_translation = ignore # ignore/add/remove/force/not_defined + +# If true, a is inserted after #define. +force_tab_after_define = false # true/false + +# +# Indenting options +# + +# The number of columns to indent per level. Usually 2, 3, 4, or 8. +# +# Default: 8 +indent_columns = 2 # unsigned number + +# Whether to ignore indent for the first continuation line. Subsequent +# continuation lines will still be indented to match the first. +indent_ignore_first_continue = false # true/false + +# The continuation indent. If non-zero, this overrides the indent of '(', '[' +# and '=' continuation indents. Negative values are OK; negative value is +# absolute and not increased for each '(' or '[' level. +# +# For FreeBSD, this is set to 4. +# Requires indent_ignore_first_continue=false. +indent_continue = 0 # number + +# The continuation indent, only for class header line(s). If non-zero, this +# overrides the indent of 'class' continuation indents. +# Requires indent_ignore_first_continue=false. +indent_continue_class_head = 0 # unsigned number + +# Whether to indent empty lines (i.e. lines which contain only spaces before +# the newline character). +indent_single_newlines = false # true/false + +# The continuation indent for func_*_param if they are true. If non-zero, this +# overrides the indent. +indent_param = 0 # unsigned number + +# How to use tabs when indenting code. +# +# 0: Spaces only +# 1: Indent with tabs to brace level, align with spaces (default) +# 2: Indent and align with tabs, using spaces when not on a tabstop +# +# Default: 1 +indent_with_tabs = 0 # unsigned number + +# Whether to indent comments that are not at a brace level with tabs on a +# tabstop. Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = false # true/false + +# Whether to indent strings broken by '\' so that they line up. +indent_align_string = false # true/false + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=true. +indent_xml_string = 0 # unsigned number + +# Spaces to indent '{' from level. +indent_brace = 0 # unsigned number + +# Whether braces are indented to the body level. +indent_braces = false # true/false + +# Whether to disable indenting function braces if indent_braces=true. +indent_braces_no_func = false # true/false + +# Whether to disable indenting class braces if indent_braces=true. +indent_braces_no_class = false # true/false + +# Whether to disable indenting struct braces if indent_braces=true. +indent_braces_no_struct = false # true/false + +# Whether to indent based on the size of the brace parent, +# i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # true/false + +# Whether to indent based on the open parenthesis instead of the open brace +# in '({\n'. +indent_paren_open_brace = false # true/false + +# (C#) Whether to indent the brace of a C# delegate by another level. +indent_cs_delegate_brace = false # true/false + +# (C#) Whether to indent a C# delegate (to handle delegates with no brace) by +# another level. +indent_cs_delegate_body = false # true/false + +# Whether to indent the body of a 'namespace'. +indent_namespace = false # true/false + +# Whether to indent only the first namespace, and not any nested namespaces. +# Requires indent_namespace=true. +indent_namespace_single_indent = false # true/false + +# The number of spaces to indent a namespace block. +# If set to zero, use the value indent_columns +indent_namespace_level = 0 # unsigned number + +# If the body of the namespace is longer than this number, it won't be +# indented. Requires indent_namespace=true. 0 means no limit. +indent_namespace_limit = 0 # unsigned number + +# Whether to indent only in inner namespaces (nested in other namespaces). +# Requires indent_namespace=true. +indent_namespace_inner_only = false # true/false + +# Whether the 'extern "C"' body is indented. +indent_extern = false # true/false + +# Whether the 'class' body is indented. +indent_class = true # true/false + +# Whether to ignore indent for the leading base class colon. +indent_ignore_before_class_colon = false # true/false + +# Additional indent before the leading base class colon. +# Negative values decrease indent down to the first column. +# Requires indent_ignore_before_class_colon=false and a newline break before +# the colon (see pos_class_colon and nl_class_colon) +indent_before_class_colon = 0 # number + +# Whether to indent the stuff after a leading base class colon. +indent_class_colon = false # true/false + +# Whether to indent based on a class colon instead of the stuff after the +# colon. Requires indent_class_colon=true. +indent_class_on_colon = false # true/false + +# Whether to ignore indent for a leading class initializer colon. +indent_ignore_before_constr_colon = false # true/false + +# Whether to indent the stuff after a leading class initializer colon. +indent_constr_colon = false # true/false + +# Virtual indent from the ':' for leading member initializers. +# +# Default: 2 +indent_ctor_init_leading = 2 # unsigned number + +# Virtual indent from the ':' for following member initializers. +# +# Default: 2 +indent_ctor_init_following = 2 # unsigned number + +# Additional indent for constructor initializer list. +# Negative values decrease indent down to the first column. +indent_ctor_init = 0 # number + +# Whether to indent 'if' following 'else' as a new block under the 'else'. +# If false, 'else\nif' is treated as 'else if' for indenting purposes. +indent_else_if = false # true/false + +# Amount to indent variable declarations after a open brace. +# +# <0: Relative +# >=0: Absolute +indent_var_def_blk = 0 # number + +# Whether to indent continued variable declarations instead of aligning. +indent_var_def_cont = false # true/false + +# How to indent continued shift expressions ('<<' and '>>'). +# Set align_left_shift=false when using this. +# 0: Align shift operators instead of indenting them (default) +# 1: Indent by one level +# -1: Preserve original indentation +indent_shift = 0 # number + +# Whether to force indentation of function definitions to start in column 1. +indent_func_def_force_col1 = false # true/false + +# Whether to indent continued function call parameters one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_call_param = false # true/false + +# Whether to indent continued function definition parameters one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_def_param = false # true/false + +# for function definitions, only if indent_func_def_param is false +# Allows to align params when appropriate and indent them when not +# behave as if it was true if paren position is more than this value +# if paren position is more than the option value +indent_func_def_param_paren_pos_threshold = 0 # unsigned number + +# Whether to indent continued function call prototype one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_proto_param = false # true/false + +# Whether to indent continued function call declaration one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_class_param = false # true/false + +# Whether to indent continued class variable constructors one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_ctor_var_param = false # true/false + +# Whether to indent continued template parameter list one indent level, +# rather than aligning parameters under the open parenthesis. +indent_template_param = false # true/false + +# Double the indent for indent_func_xxx_param options. +# Use both values of the options indent_columns and indent_param. +indent_func_param_double = false # true/false + +# Indentation column for standalone 'const' qualifier on a function +# prototype. +indent_func_const = 0 # unsigned number + +# Indentation column for standalone 'throw' qualifier on a function +# prototype. +indent_func_throw = 0 # unsigned number + +# How to indent within a macro followed by a brace on the same line +# This allows reducing the indent in macros that have (for example) +# `do { ... } while (0)` blocks bracketing them. +# +# true: add an indent for the brace on the same line as the macro +# false: do not add an indent for the brace on the same line as the macro +# +# Default: true +indent_macro_brace = true # true/false + +# The number of spaces to indent a continued '->' or '.'. +# Usually set to 0, 1, or indent_columns. +indent_member = 0 # unsigned number + +# Whether lines broken at '.' or '->' should be indented by a single indent. +# The indent_member option will not be effective if this is set to true. +indent_member_single = false # true/false + +# Spaces to indent single line ('//') comments on lines before code. +indent_single_line_comments_before = 0 # unsigned number + +# Spaces to indent single line ('//') comments on lines after code. +indent_single_line_comments_after = 0 # unsigned number + +# When opening a paren for a control statement (if, for, while, etc), increase +# the indent level by this value. Negative values decrease the indent level. +indent_sparen_extra = 0 # number + +# Whether to indent trailing single line ('//') comments relative to the code +# instead of trying to keep the same absolute column. +indent_relative_single_line_comments = false # true/false + +# Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns. +# It might be wise to choose the same value for the option indent_case_brace. +indent_switch_case = indent_columns # unsigned number + +# Spaces to indent the body of a 'switch' before any 'case'. +# Usually the same as indent_columns or indent_switch_case. +indent_switch_body = 0 # unsigned number + +# Whether to ignore indent for '{' following 'case'. +indent_ignore_case_brace = false # true/false + +# Spaces to indent '{' from 'case'. By default, the brace will appear under +# the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK. +# It might be wise to choose the same value for the option indent_switch_case. +indent_case_brace = 0 # number + +# indent 'break' with 'case' from 'switch'. +indent_switch_break_with_case = false # true/false + +# Whether to indent preprocessor statements inside of switch statements. +# +# Default: true +indent_switch_pp = true # true/false + +# Spaces to shift the 'case' line, without affecting any other lines. +# Usually 0. +indent_case_shift = 0 # unsigned number + +# Whether to align comments before 'case' with the 'case'. +# +# Default: true +indent_case_comment = true # true/false + +# Whether to indent comments not found in first column. +# +# Default: true +indent_comment = true # true/false + +# Whether to indent comments found in first column. +indent_col1_comment = true # true/false + +# Whether to indent multi string literal in first column. +indent_col1_multi_string_literal = false # true/false + +# Align comments on adjacent lines that are this many columns apart or less. +# +# Default: 3 +indent_comment_align_thresh = 3 # unsigned number + +# Whether to ignore indent for goto labels. +indent_ignore_label = false # true/false + +# How to indent goto labels. Requires indent_ignore_label=false. +# +# >0: Absolute column where 1 is the leftmost column +# <=0: Subtract from brace indent +# +# Default: 1 +indent_label = 1 # number + +# How to indent access specifiers that are followed by a +# colon. +# +# >0: Absolute column where 1 is the leftmost column +# <=0: Subtract from brace indent +# +# Default: 1 +indent_access_spec = 0 # number + +# Whether to indent the code after an access specifier by one level. +# If true, this option forces 'indent_access_spec=0'. +indent_access_spec_body = true # true/false + +# If an open parenthesis is followed by a newline, whether to indent the next +# line so that it lines up after the open parenthesis (not recommended). +indent_paren_nl = false # true/false + +# How to indent a close parenthesis after a newline. +# +# 0: Indent to body level (default) +# 1: Align under the open parenthesis +# 2: Indent to the brace level +# -1: Preserve original indentation +indent_paren_close = 0 # number + +# Whether to indent the open parenthesis of a function definition, +# if the parenthesis is on its own line. +indent_paren_after_func_def = false # true/false + +# Whether to indent the open parenthesis of a function declaration, +# if the parenthesis is on its own line. +indent_paren_after_func_decl = false # true/false + +# Whether to indent the open parenthesis of a function call, +# if the parenthesis is on its own line. +indent_paren_after_func_call = false # true/false + +# How to indent a comma when inside braces. +# 0: Indent by one level (default) +# 1: Align under the open brace +# -1: Preserve original indentation +indent_comma_brace = 0 # number + +# How to indent a comma when inside parentheses. +# 0: Indent by one level (default) +# 1: Align under the open parenthesis +# -1: Preserve original indentation +indent_comma_paren = 0 # number + +# How to indent a Boolean operator when inside parentheses. +# 0: Indent by one level (default) +# 1: Align under the open parenthesis +# -1: Preserve original indentation +indent_bool_paren = 0 # number + +# Whether to ignore the indentation of a Boolean operator when outside +# parentheses. +indent_ignore_bool = false # true/false + +# Whether to ignore the indentation of an arithmetic operator. +indent_ignore_arith = false # true/false + +# Whether to indent a semicolon when inside a for parenthesis. +# If true, aligns under the open for parenthesis. +indent_semicolon_for_paren = false # true/false + +# Whether to ignore the indentation of a semicolon outside of a 'for' +# statement. +indent_ignore_semicolon = false # true/false + +# Whether to align the first expression to following ones +# if indent_bool_paren=1. +indent_first_bool_expr = false # true/false + +# Whether to align the first expression to following ones +# if indent_semicolon_for_paren=true. +indent_first_for_expr = false # true/false + +# If an open square is followed by a newline, whether to indent the next line +# so that it lines up after the open square (not recommended). +indent_square_nl = false # true/false + +# (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies. +indent_preserve_sql = false # true/false + +# Whether to ignore the indentation of an assignment operator. +indent_ignore_assign = false # true/false + +# Whether to align continued statements at the '='. If false or if the '=' is +# followed by a newline, the next line is indent one tab. +# +# Default: true +indent_align_assign = true # true/false + +# If true, the indentation of the chunks after a '=' sequence will be set at +# LHS token indentation column before '='. +indent_off_after_assign = false # true/false + +# Whether to align continued statements at the '('. If false or the '(' is +# followed by a newline, the next line indent is one tab. +# +# Default: true +indent_align_paren = true # true/false + +# (OC) Whether to indent Objective-C code inside message selectors. +indent_oc_inside_msg_sel = false # true/false + +# (OC) Whether to indent Objective-C blocks at brace level instead of usual +# rules. +indent_oc_block = false # true/false + +# (OC) Indent for Objective-C blocks in a message relative to the parameter +# name. +# +# =0: Use indent_oc_block rules +# >0: Use specified number of spaces to indent +indent_oc_block_msg = 0 # unsigned number + +# (OC) Minimum indent for subsequent parameters +indent_oc_msg_colon = 0 # unsigned number + +# (OC) Whether to prioritize aligning with initial colon (and stripping spaces +# from lines, if necessary). +# +# Default: true +indent_oc_msg_prioritize_first_colon = true # true/false + +# (OC) Whether to indent blocks the way that Xcode does by default +# (from the keyword if the parameter is on its own line; otherwise, from the +# previous indentation level). Requires indent_oc_block_msg=true. +indent_oc_block_msg_xcode_style = false # true/false + +# (OC) Whether to indent blocks from where the brace is, relative to a +# message keyword. Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_keyword = false # true/false + +# (OC) Whether to indent blocks from where the brace is, relative to a message +# colon. Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_colon = false # true/false + +# (OC) Whether to indent blocks from where the block caret is. +# Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_caret = false # true/false + +# (OC) Whether to indent blocks from where the brace caret is. +# Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_brace = false # true/false + +# When indenting after virtual brace open and newline add further spaces to +# reach this minimum indent. +indent_min_vbrace_open = 0 # unsigned number + +# Whether to add further spaces after regular indent to reach next tabstop +# when indenting after virtual brace open and newline. +indent_vbrace_open_on_tabstop = false # true/false + +# How to indent after a brace followed by another token (not a newline). +# true: indent all contained lines to match the token +# false: indent all contained lines to match the brace +# +# Default: true +indent_token_after_brace = true # true/false + +# Whether to indent the body of a C++11 lambda. +indent_cpp_lambda_body = false # true/false + +# How to indent compound literals that are being returned. +# true: add both the indent from return & the compound literal open brace +# (i.e. 2 indent levels) +# false: only indent 1 level, don't add the indent for the open brace, only +# add the indent for the return. +# +# Default: true +indent_compound_literal_return = true # true/false + +# (C#) Whether to indent a 'using' block if no braces are used. +# +# Default: true +indent_using_block = true # true/false + +# How to indent the continuation of ternary operator. +# +# 0: Off (default) +# 1: When the `if_false` is a continuation, indent it under the `if_true` branch +# 2: When the `:` is a continuation, indent it under `?` +indent_ternary_operator = 0 # unsigned number + +# Whether to indent the statements inside ternary operator. +indent_inside_ternary_operator = false # true/false + +# If true, the indentation of the chunks after a `return` sequence will be set at return indentation column. +indent_off_after_return = false # true/false + +# If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column. +indent_off_after_return_new = false # true/false + +# If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token. +indent_single_after_return = false # true/false + +# Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they +# have their own indentation). +indent_ignore_asm_block = false # true/false + +# Don't indent the close parenthesis of a function definition, +# if the parenthesis is on its own line. +donot_indent_func_def_close_paren = false # true/false + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}' except for functions. +# Use nl_collapse_empty_body_functions to specify how empty function braces +# should be formatted. +nl_collapse_empty_body = false # true/false + +# Whether to collapse empty blocks between '{' and '}' for functions only. +# If true, overrides nl_inside_empty_func. +nl_collapse_empty_body_functions = false # true/false + +# Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. +nl_assign_leave_one_liners = false # true/false + +# Don't split one-line braced statements inside a 'class xx { }' body. +nl_class_leave_one_liners = false # true/false + +# Don't split one-line enums, as in 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = false # true/false + +# Don't split one-line get or set functions. +nl_getset_leave_one_liners = false # true/false + +# (C#) Don't split one-line property get or set functions. +nl_cs_property_leave_one_liners = false # true/false + +# Don't split one-line function definitions, as in 'int foo() { return 0; }'. +# might modify nl_func_type_name +nl_func_leave_one_liners = false # true/false + +# Don't split one-line C++11 lambdas, as in '[]() { return 0; }'. +nl_cpp_lambda_leave_one_liners = false # true/false + +# Don't split one-line if/else statements, as in 'if(...) b++;'. +nl_if_leave_one_liners = false # true/false + +# Don't split one-line while statements, as in 'while(...) b++;'. +nl_while_leave_one_liners = false # true/false + +# Don't split one-line do statements, as in 'do { b++; } while(...);'. +nl_do_leave_one_liners = false # true/false + +# Don't split one-line for statements, as in 'for(...) b++;'. +nl_for_leave_one_liners = false # true/false + +# (OC) Don't split one-line Objective-C messages. +nl_oc_msg_leave_one_liner = false # true/false + +# (OC) Add or remove newline between method declaration and '{'. +nl_oc_mdef_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between Objective-C block signature and '{'. +nl_oc_block_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove blank line before '@interface' statement. +nl_oc_before_interface = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove blank line before '@implementation' statement. +nl_oc_before_implementation = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove blank line before '@end' statement. +nl_oc_before_end = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between '@interface' and '{'. +nl_oc_interface_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between '@implementation' and '{'. +nl_oc_implementation_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newlines at the start of the file. +nl_start_of_file = ignore # ignore/add/remove/force/not_defined + +# The minimum number of newlines at the start of the file (only used if +# nl_start_of_file is 'add' or 'force'). +nl_start_of_file_min = 0 # unsigned number + +# Add or remove newline at the end of the file. +nl_end_of_file = ignore # ignore/add/remove/force/not_defined + +# The minimum number of newlines at the end of the file (only used if +# nl_end_of_file is 'add' or 'force'). +nl_end_of_file_min = 0 # unsigned number + +# Add or remove newline between '=' and '{'. +nl_assign_brace = remove # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between '=' and '['. +nl_assign_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '[]' and '{'. +nl_tsquare_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline after '= ['. Will also affect the newline before +# the ']'. +nl_after_square_assign = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function call's ')' and '{', as in +# 'list_for_each(item, &list) { }'. +nl_fcall_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum' and '{'. +nl_enum_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum' and 'class'. +nl_enum_class = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum class' and the identifier. +nl_enum_class_identifier = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum class' type and ':'. +nl_enum_identifier_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'enum class identifier :' and type. +nl_enum_colon_type = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'struct and '{'. +nl_struct_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'union' and '{'. +nl_union_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'if' and '{'. +nl_if_brace = remove # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'else'. +nl_brace_else = remove # ignore/add/remove/force/not_defined + +# Add or remove newline between 'else if' and '{'. If set to ignore, +# nl_if_brace is used instead. +nl_elseif_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'else' and '{'. +nl_else_brace = remove # ignore/add/remove/force/not_defined + +# Add or remove newline between 'else' and 'if'. +nl_else_if = remove # ignore/add/remove/force/not_defined + +# Add or remove newline before '{' opening brace +nl_before_opening_brace_func_class_def = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before 'if'/'else if' closing parenthesis. +nl_before_if_closing_paren = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'finally'. +nl_brace_finally = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'finally' and '{'. +nl_finally_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'try' and '{'. +nl_try_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between get/set and '{'. +nl_getset_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'for' and '{'. +nl_for_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before the '{' of a 'catch' statement, as in +# 'catch (decl) {'. +nl_catch_brace = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline before the '{' of a '@catch' statement, as in +# '@catch (decl) {'. If set to ignore, nl_catch_brace is used. +nl_oc_catch_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'catch'. +nl_brace_catch = ignore # ignore/add/remove/force/not_defined + +# (OC) Add or remove newline between '}' and '@catch'. If set to ignore, +# nl_brace_catch is used. +nl_oc_brace_catch = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and ']'. +nl_brace_square = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and ')' in a function invocation. +nl_brace_fparen = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'while' and '{'. +nl_while_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between 'scope (x)' and '{'. +nl_scope_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between 'unittest' and '{'. +nl_unittest_brace = ignore # ignore/add/remove/force/not_defined + +# (D) Add or remove newline between 'version (x)' and '{'. +nl_version_brace = ignore # ignore/add/remove/force/not_defined + +# (C#) Add or remove newline between 'using' and '{'. +nl_using_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between two open or close braces. Due to general +# newline/brace handling, REMOVE may not work. +nl_brace_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'do' and '{'. +nl_do_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '}' and 'while' of 'do' statement. +nl_brace_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'switch' and '{'. +nl_switch_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'synchronized' and '{'. +nl_synchronized_brace = ignore # ignore/add/remove/force/not_defined + +# Add a newline between ')' and '{' if the ')' is on a different line than the +# if/for/etc. +# +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and +# nl_catch_brace. +nl_multi_line_cond = false # true/false + +# Add a newline after '(' if an if/for/while/switch condition spans multiple +# lines +nl_multi_line_sparen_open = ignore # ignore/add/remove/force/not_defined + +# Add a newline before ')' if an if/for/while/switch condition spans multiple +# lines. Overrides nl_before_if_closing_paren if both are specified. +nl_multi_line_sparen_close = ignore # ignore/add/remove/force/not_defined + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # true/false + +# Whether to add a newline before 'case', and a blank line before a 'case' +# statement that follows a ';' or '}'. +nl_before_case = false # true/false + +# Whether to add a newline after a 'case' statement. +nl_after_case = false # true/false + +# Add or remove newline between a case ':' and '{'. +# +# Overrides nl_after_case. +nl_case_colon_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between ')' and 'throw'. +nl_before_throw = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'namespace' and '{'. +nl_namespace_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template class. +nl_template_class = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template class declaration. +# +# Overrides nl_template_class. +nl_template_class_decl = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized class declaration. +# +# Overrides nl_template_class_decl. +nl_template_class_decl_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template class definition. +# +# Overrides nl_template_class. +nl_template_class_def = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized class definition. +# +# Overrides nl_template_class_def. +nl_template_class_def_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template function. +nl_template_func = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template function +# declaration. +# +# Overrides nl_template_func. +nl_template_func_decl = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized function +# declaration. +# +# Overrides nl_template_func_decl. +nl_template_func_decl_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template function +# definition. +# +# Overrides nl_template_func. +nl_template_func_def = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<>' of a specialized function +# definition. +# +# Overrides nl_template_func_def. +nl_template_func_def_special = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after 'template<...>' of a template variable. +nl_template_var = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'template<...>' and 'using' of a templated +# type alias. +nl_template_using = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'class' and '{'. +nl_class_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before or after (depending on pos_class_comma, +# may not be IGNORE) each',' in the base class list. +nl_class_init_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after each ',' in the constructor member +# initialization. Related to nl_constr_colon, pos_constr_colon and +# pos_constr_comma. +nl_constr_init_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before first element, after comma, and after last +# element, in 'enum'. +nl_enum_own_lines = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between return type and function name in a function +# definition. +# might be modified by nl_func_leave_one_liners +nl_func_type_name = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between return type and function name inside a class +# definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name +# is used instead. +nl_func_type_name_class = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between class specification and '::' +# in 'void A::f() { }'. Only appears in separate member implementation (does +# not appear with in-line implementation). +nl_func_class_scope = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between function scope and name, as in +# 'void A :: f() { }'. +nl_func_scope_name = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between return type and function name in a prototype. +nl_func_proto_type_name = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function name and the opening '(' in the +# declaration. +nl_func_paren = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_paren for functions with no parameters. +nl_func_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function name and the opening '(' in the +# definition. +nl_func_def_paren = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_def_paren for functions with no parameters. +nl_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between a function name and the opening '(' in the +# call. +nl_func_call_paren = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_call_paren for functions with no parameters. +nl_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after '(' in a function declaration. +nl_func_decl_start = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after '(' in a function definition. +nl_func_def_start = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after '(' in a function declaration if '(' and ')' +# are in different lines. If false, nl_func_decl_start is used instead. +nl_func_decl_start_multi_line = false # true/false + +# Whether to add a newline after '(' in a function definition if '(' and ')' +# are in different lines. If false, nl_func_def_start is used instead. +nl_func_def_start_multi_line = false # true/false + +# Add or remove newline after each ',' in a function declaration. +nl_func_decl_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after each ',' in a function definition. +nl_func_def_args = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline after each ',' in a function call. +nl_func_call_args = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after each ',' in a function declaration if '(' +# and ')' are in different lines. If false, nl_func_decl_args is used instead. +nl_func_decl_args_multi_line = false # true/false + +# Whether to add a newline after each ',' in a function definition if '(' +# and ')' are in different lines. If false, nl_func_def_args is used instead. +nl_func_def_args_multi_line = false # true/false + +# Add or remove newline before the ')' in a function declaration. +nl_func_decl_end = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline before the ')' in a function definition. +nl_func_def_end = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = ignore # ignore/add/remove/force/not_defined + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before ')' in a function declaration if '(' and ')' +# are in different lines. If false, nl_func_decl_end is used instead. +nl_func_decl_end_multi_line = false # true/false + +# Whether to add a newline before ')' in a function definition if '(' and ')' +# are in different lines. If false, nl_func_def_end is used instead. +nl_func_def_end_multi_line = false # true/false + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between '()' in a function call. +nl_func_call_empty = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after '(' in a function call, +# has preference over nl_func_call_start_multi_line. +nl_func_call_start = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before ')' in a function call. +nl_func_call_end = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after '(' in a function call if '(' and ')' are in +# different lines. +nl_func_call_start_multi_line = false # true/false + +# Whether to add a newline after each ',' in a function call if '(' and ')' +# are in different lines. +nl_func_call_args_multi_line = false # true/false + +# Whether to add a newline before ')' in a function call if '(' and ')' are in +# different lines. +nl_func_call_end_multi_line = false # true/false + +# Whether to respect nl_func_call_XXX option in case of closure args. +nl_func_call_args_multi_line_ignore_closures = false # true/false + +# Whether to add a newline after '<' of a template parameter list. +nl_template_start = false # true/false + +# Whether to add a newline after each ',' in a template parameter list. +nl_template_args = false # true/false + +# Whether to add a newline before '>' of a template parameter list. +nl_template_end = false # true/false + +# (OC) Whether to put each Objective-C message parameter on a separate line. +# See nl_oc_msg_leave_one_liner. +nl_oc_msg_args = false # true/false + +# (OC) Minimum number of Objective-C message parameters before applying nl_oc_msg_args. +nl_oc_msg_args_min_params = 0 # unsigned number + +# (OC) Max code width of Objective-C message before applying nl_oc_msg_args. +nl_oc_msg_args_max_code_width = 0 # unsigned number + +# Add or remove newline between function signature and '{'. +nl_fdef_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between function signature and '{', +# if signature ends with ')'. Overrides nl_fdef_brace. +nl_fdef_brace_cond = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between C++11 lambda signature and '{'. +nl_cpp_ldef_brace = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'return' and the return expression. +nl_return_expr = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline between 'throw' and the throw expression. +nl_throw_expr = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after semicolons, except in 'for' statements. +nl_after_semicolon = false # true/false + +# (Java) Add or remove newline between the ')' and '{{' of the double brace +# initializer. +nl_paren_dbrace_open = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline after the type in an unnamed temporary +# direct-list-initialization, better: +# before a direct-list-initialization. +nl_type_brace_init_lst = remove # ignore/add/remove/force/not_defined + +# Whether to add a newline after the open brace in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before the close brace in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined + +# Whether to add a newline before '{'. +nl_before_brace_open = false # true/false + +# Whether to add a newline after '{'. +nl_after_brace_open = false # true/false + +# Whether to add a newline between the open brace and a trailing single-line +# comment. Requires nl_after_brace_open=true. +nl_after_brace_open_cmt = false # true/false + +# Whether to add a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # true/false + +# Whether to add a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # true/false + +# Whether to add a newline after '}'. Does not apply if followed by a +# necessary ';'. +nl_after_brace_close = false # true/false + +# Whether to add a newline after a virtual brace close, +# as in 'if (foo) a++; return;'. +nl_after_vbrace_close = false # true/false + +# Add or remove newline between the close brace and identifier, +# as in 'struct { int a; } b;'. Affects enumerations, unions and +# structures. If set to ignore, uses nl_after_brace_close. +nl_brace_struct_var = ignore # ignore/add/remove/force/not_defined + +# Whether to alter newlines in '#define' macros. +nl_define_macro = false # true/false + +# Whether to alter newlines between consecutive parenthesis closes. The number +# of closing parentheses in a line will depend on respective open parenthesis +# lines. +nl_squeeze_paren_close = false # true/false + +# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and +# '#endif'. Does not affect top-level #ifdefs. +nl_squeeze_ifdef = false # true/false + +# Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well. +nl_squeeze_ifdef_top_level = false # true/false + +# Add or remove blank line before 'if'. +nl_before_if = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'if' statement. Add/Force work only if the +# next token is not a closing brace. +nl_after_if = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'for'. +nl_before_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'for' statement. +nl_after_for = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'while'. +nl_before_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'while' statement. +nl_after_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'switch'. +nl_before_switch = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'switch' statement. +nl_after_switch = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'synchronized'. +nl_before_synchronized = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'synchronized' statement. +nl_after_synchronized = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line before 'do'. +nl_before_do = ignore # ignore/add/remove/force/not_defined + +# Add or remove blank line after 'do/while' statement. +nl_after_do = ignore # ignore/add/remove/force/not_defined + +# Ignore nl_before_{if,for,switch,do,synchronized} if the control +# statement is immediately after a case statement. +# if nl_before_{if,for,switch,do} is set to remove, this option +# does nothing. +nl_before_ignore_after_case = false # true/false + +# Whether to put a blank line before 'return' statements, unless after an open +# brace. +nl_before_return = false # true/false + +# Whether to put a blank line after 'return' statements, unless followed by a +# close brace. +nl_after_return = false # true/false + +# Whether to put a blank line before a member '.' or '->' operators. +nl_before_member = ignore # ignore/add/remove/force/not_defined + +# (Java) Whether to put a blank line after a member '.' or '->' operators. +nl_after_member = ignore # ignore/add/remove/force/not_defined + +# Whether to double-space commented-entries in 'struct'/'union'/'enum'. +nl_ds_struct_enum_cmt = false # true/false + +# Whether to force a newline before '}' of a 'struct'/'union'/'enum'. +# (Lower priority than eat_blanks_before_close_brace.) +nl_ds_struct_enum_close_brace = false # true/false + +# Add or remove newline before or after (depending on pos_class_colon) a class +# colon, as in 'class Foo : public Bar'. +nl_class_colon = ignore # ignore/add/remove/force/not_defined + +# Add or remove newline around a class constructor colon. The exact position +# depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma. +nl_constr_colon = ignore # ignore/add/remove/force/not_defined + +# Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }' +# into a single line. If true, prevents other brace newline rules from turning +# such code into four lines. If true, it also preserves one-liner namespaces. +nl_namespace_two_to_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced if statements, turning them +# into one-liners, as in 'if(b)\n i++;' => 'if(b) i++;'. +nl_create_if_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced for statements, turning them +# into one-liners, as in 'for (...)\n stmt;' => 'for (...) stmt;'. +nl_create_for_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced while statements, turning +# them into one-liners, as in 'while (expr)\n stmt;' => 'while (expr) stmt;'. +nl_create_while_one_liner = false # true/false + +# Whether to collapse a function definition whose body (not counting braces) +# is only one line so that the entire definition (prototype, braces, body) is +# a single line. +nl_create_func_def_one_liner = false # true/false + +# Whether to split one-line simple list definitions into three lines by +# adding newlines, as in 'int a[12] = { 0 };'. +nl_create_list_one_liner = false # true/false + +# Whether to split one-line simple unbraced if statements into two lines by +# adding a newline, as in 'if(b) i++;'. +nl_split_if_one_liner = false # true/false + +# Whether to split one-line simple unbraced for statements into two lines by +# adding a newline, as in 'for (...) stmt;'. +nl_split_for_one_liner = false # true/false + +# Whether to split one-line simple unbraced while statements into two lines by +# adding a newline, as in 'while (expr) stmt;'. +nl_split_while_one_liner = false # true/false + +# Don't add a newline before a cpp-comment in a parameter list of a function +# call. +donot_add_nl_before_cpp_comment = false # true/false + +# +# Blank line options +# + +# The maximum number of consecutive newlines (3 = 2 blank lines). +nl_max = 0 # unsigned number + +# The maximum number of consecutive newlines in a function. +nl_max_blank_in_func = 0 # unsigned number + +# The number of newlines inside an empty function body. +# This option overrides eat_blanks_after_open_brace and +# eat_blanks_before_close_brace, but is ignored when +# nl_collapse_empty_body_functions=true +nl_inside_empty_func = 0 # unsigned number + +# The number of newlines before a function prototype. +nl_before_func_body_proto = 0 # unsigned number + +# The number of newlines before a multi-line function definition. Where +# applicable, this option is overridden with eat_blanks_after_open_brace=true +nl_before_func_body_def = 0 # unsigned number + +# The number of newlines before a class constructor/destructor prototype. +nl_before_func_class_proto = 0 # unsigned number + +# The number of newlines before a class constructor/destructor definition. +nl_before_func_class_def = 0 # unsigned number + +# The number of newlines after a function prototype. +nl_after_func_proto = 0 # unsigned number + +# The number of newlines after a function prototype, if not followed by +# another function prototype. +nl_after_func_proto_group = 0 # unsigned number + +# The number of newlines after a class constructor/destructor prototype. +nl_after_func_class_proto = 0 # unsigned number + +# The number of newlines after a class constructor/destructor prototype, +# if not followed by another constructor/destructor prototype. +nl_after_func_class_proto_group = 0 # unsigned number + +# Whether one-line method definitions inside a class body should be treated +# as if they were prototypes for the purposes of adding newlines. +# +# Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def +# and nl_before_func_class_def for one-liners. +nl_class_leave_one_liner_groups = false # true/false + +# The number of newlines after '}' of a multi-line function body. +nl_after_func_body = 0 # unsigned number + +# The number of newlines after '}' of a multi-line function body in a class +# declaration. Also affects class constructors/destructors. +# +# Overrides nl_after_func_body. +nl_after_func_body_class = 0 # unsigned number + +# The number of newlines after '}' of a single line function body. Also +# affects class constructors/destructors. +# +# Overrides nl_after_func_body and nl_after_func_body_class. +nl_after_func_body_one_liner = 0 # unsigned number + +# The number of newlines before a block of typedefs. If nl_after_access_spec +# is non-zero, that option takes precedence. +# +# 0: No change (default). +nl_typedef_blk_start = 0 # unsigned number + +# The number of newlines after a block of typedefs. +# +# 0: No change (default). +nl_typedef_blk_end = 0 # unsigned number + +# The maximum number of consecutive newlines within a block of typedefs. +# +# 0: No change (default). +nl_typedef_blk_in = 0 # unsigned number + +# The minimum number of blank lines after a block of variable definitions +# at the top of a function body. If any preprocessor directives appear +# between the opening brace of the function and the variable block, then +# it is considered as not at the top of the function.Newlines are added +# before trailing preprocessor directives, if any exist. +# +# 0: No change (default). +nl_var_def_blk_end_func_top = 0 # unsigned number + +# The minimum number of empty newlines before a block of variable definitions +# not at the top of a function body. If nl_after_access_spec is non-zero, +# that option takes precedence. Newlines are not added at the top of the +# file or just after an opening brace. Newlines are added above any +# preprocessor directives before the block. +# +# 0: No change (default). +nl_var_def_blk_start = 0 # unsigned number + +# The minimum number of empty newlines after a block of variable definitions +# not at the top of a function body. Newlines are not added if the block +# is at the bottom of the file or just before a preprocessor directive. +# +# 0: No change (default). +nl_var_def_blk_end = 0 # unsigned number + +# The maximum number of consecutive newlines within a block of variable +# definitions. +# +# 0: No change (default). +nl_var_def_blk_in = 0 # unsigned number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 0 # unsigned number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 0 # unsigned number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 0 # unsigned number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = false # true/false + +# Whether to force a newline after a label's colon. +nl_after_label_colon = false # true/false + +# The number of newlines before a struct definition. +nl_before_struct = 0 # unsigned number + +# The number of newlines after '}' or ';' of a struct/enum/union definition. +nl_after_struct = 0 # unsigned number + +# The number of newlines before a class definition. +nl_before_class = 0 # unsigned number + +# The number of newlines after '}' or ';' of a class definition. +nl_after_class = 0 # unsigned number + +# The number of newlines before a namespace. +nl_before_namespace = 0 # unsigned number + +# The number of newlines after '{' of a namespace. This also adds newlines +# before the matching '}'. +# +# 0: Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if +# applicable, otherwise no change. +# +# Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace. +nl_inside_namespace = 0 # unsigned number + +# The number of newlines after '}' of a namespace. +nl_after_namespace = 0 # unsigned number + +# The number of newlines before an access specifier label. This also includes +# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +# if after a brace open. +# +# 0: No change (default). +nl_before_access_spec = 0 # unsigned number + +# The number of newlines after an access specifier label. This also includes +# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +# if after a brace open. +# +# 0: No change (default). +# +# Overrides nl_typedef_blk_start and nl_var_def_blk_start. +nl_after_access_spec = 0 # unsigned number + +# The number of newlines between a function definition and the function +# comment, as in '// comment\n void foo() {...}'. +# +# 0: No change (default). +nl_comment_func_def = 0 # unsigned number + +# The number of newlines after a try-catch-finally block that isn't followed +# by a brace close. +# +# 0: No change (default). +nl_after_try_catch_finally = 0 # unsigned number + +# (C#) The number of newlines before and after a property, indexer or event +# declaration. +# +# 0: No change (default). +nl_around_cs_property = 0 # unsigned number + +# (C#) The number of newlines between the get/set/add/remove handlers. +# +# 0: No change (default). +nl_between_get_set = 0 # unsigned number + +# (C#) Add or remove newline between property and the '{'. +nl_property_brace = ignore # ignore/add/remove/force/not_defined + +# Whether to remove blank lines after '{'. +eat_blanks_after_open_brace = false # true/false + +# Whether to remove blank lines before '}'. +eat_blanks_before_close_brace = false # true/false + +# How aggressively to remove extra newlines not in preprocessor. +# +# 0: No change (default) +# 1: Remove most newlines not handled by other config +# 2: Remove all newlines and reformat completely by config +nl_remove_extra_newlines = 0 # unsigned number + +# (Java) Add or remove newline after an annotation statement. Only affects +# annotations that are after a newline. +nl_after_annotation = ignore # ignore/add/remove/force/not_defined + +# (Java) Add or remove newline between two annotations. +nl_between_annotation = ignore # ignore/add/remove/force/not_defined + +# The number of newlines before a whole-file #ifdef. +# +# 0: No change (default). +nl_before_whole_file_ifdef = 0 # unsigned number + +# The number of newlines after a whole-file #ifdef. +# +# 0: No change (default). +nl_after_whole_file_ifdef = 0 # unsigned number + +# The number of newlines before a whole-file #endif. +# +# 0: No change (default). +nl_before_whole_file_endif = 0 # unsigned number + +# The number of newlines after a whole-file #endif. +# +# 0: No change (default). +nl_after_whole_file_endif = 0 # unsigned number + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions. +pos_arith = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of assignment in wrapped expressions. Do not affect '=' +# followed by '{'. +pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of Boolean operators in wrapped expressions. +pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of comparison operators in wrapped expressions. +pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of conditional operators, as in the '?' and ':' of +# 'expr ? stmt : stmt', in wrapped expressions. +pos_conditional = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in wrapped expressions. +pos_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in enum entries. +pos_enum_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in the base class list if there is more than one +# line. Affects nl_class_init_args. +pos_class_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in the constructor initialization list. +# Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon. +pos_constr_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of trailing/leading class colon, between class and base class +# list. Affects nl_class_colon. +pos_class_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of colons between constructor and member initialization. +# Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma. +pos_constr_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of shift operators in wrapped expressions. +pos_shift = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# +# Line splitting options +# + +# Try to limit code width to N columns. +code_width = 0 # unsigned number + +# Whether to fully split long 'for' statements at semi-colons. +ls_for_split_full = false # true/false + +# Whether to fully split long function prototypes/calls at commas. +# The option ls_code_width has priority over the option ls_func_split_full. +ls_func_split_full = false # true/false + +# Whether to split lines as close to code_width as possible and ignore some +# groupings. +# The option ls_code_width has priority over the option ls_func_split_full. +ls_code_width = false # true/false + +# +# Code alignment options (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs. +align_keep_tabs = false # true/false + +# Whether to use tabs for aligning. +align_with_tabs = false # true/false + +# Whether to bump out to the next tab when aligning. +align_on_tabstop = false # true/false + +# Whether to right-align numbers. +align_number_right = false # true/false + +# Whether to keep whitespace not required for alignment. +align_keep_extra_space = false # true/false + +# Whether to align variable definitions in prototypes and functions. +align_func_params = false # true/false + +# The span for aligning parameter definitions in function on parameter name. +# +# 0: Don't align (default). +align_func_params_span = 0 # unsigned number + +# The threshold for aligning function parameter definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_func_params_thresh = 0 # number + +# The gap for aligning function parameter definitions. +align_func_params_gap = 0 # unsigned number + +# The span for aligning constructor value. +# +# 0: Don't align (default). +align_constr_value_span = 0 # unsigned number + +# The threshold for aligning constructor value. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_constr_value_thresh = 0 # number + +# The gap for aligning constructor value. +align_constr_value_gap = 0 # unsigned number + +# Whether to align parameters in single-line functions that have the same +# name. The function names must already be aligned with each other. +align_same_func_call_params = false # true/false + +# The span for aligning function-call parameters for single line functions. +# +# 0: Don't align (default). +align_same_func_call_params_span = 0 # unsigned number + +# The threshold for aligning function-call parameters for single line +# functions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_same_func_call_params_thresh = 0 # number + +# The span for aligning variable definitions. +# +# 0: Don't align (default). +align_var_def_span = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of variable definitions. +# +# 0: Part of the type 'void * foo;' (default) +# 1: Part of the variable 'void *foo;' +# 2: Dangling 'void *foo;' +# Dangling: the '*' will not be taken into account when aligning. +align_var_def_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of variable definitions. +# +# 0: Part of the type 'long & foo;' (default) +# 1: Part of the variable 'long &foo;' +# 2: Dangling 'long &foo;' +# Dangling: the '&' will not be taken into account when aligning. +align_var_def_amp_style = 0 # unsigned number + +# The threshold for aligning variable definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions. +align_var_def_gap = 0 # unsigned number + +# Whether to align the colon in struct bit fields. +align_var_def_colon = false # true/false + +# The gap for aligning the colon in struct bit fields. +align_var_def_colon_gap = 0 # unsigned number + +# Whether to align any attribute after the variable name. +align_var_def_attribute = false # true/false + +# Whether to align inline struct/enum/union variable definitions. +align_var_def_inline = false # true/false + +# The span for aligning on '=' in assignments. +# +# 0: Don't align (default). +align_assign_span = 0 # unsigned number + +# The span for aligning on '=' in function prototype modifier. +# +# 0: Don't align (default). +align_assign_func_proto_span = 0 # unsigned number + +# The threshold for aligning on '=' in assignments. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_assign_thresh = 0 # number + +# Whether to align on the left most assignment when multiple +# definitions are found on the same line. +# Depends on 'align_assign_span' and 'align_assign_thresh' settings. +align_assign_on_multi_var_defs = false # true/false + +# The span for aligning on '{' in braced init list. +# +# 0: Don't align (default). +align_braced_init_list_span = 0 # unsigned number + +# The threshold for aligning on '{' in braced init list. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_braced_init_list_thresh = 0 # number + +# How to apply align_assign_span to function declaration "assignments", i.e. +# 'virtual void foo() = 0' or '~foo() = {default|delete}'. +# +# 0: Align with other assignments (default) +# 1: Align with each other, ignoring regular assignments +# 2: Don't align +align_assign_decl_func = 0 # unsigned number + +# The span for aligning on '=' in enums. +# +# 0: Don't align (default). +align_enum_equ_span = 0 # unsigned number + +# The threshold for aligning on '=' in enums. +# Use a negative number for absolute thresholds. +# +# 0: no limit (default). +align_enum_equ_thresh = 0 # number + +# The span for aligning class member definitions. +# +# 0: Don't align (default). +align_var_class_span = 0 # unsigned number + +# The threshold for aligning class member definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_var_class_thresh = 0 # number + +# The gap for aligning class member definitions. +align_var_class_gap = 0 # unsigned number + +# The span for aligning struct/union member definitions. +# +# 0: Don't align (default). +align_var_struct_span = 0 # unsigned number + +# The threshold for aligning struct/union member definitions. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions. +align_var_struct_gap = 0 # unsigned number + +# The span for aligning struct initializer values. +# +# 0: Don't align (default). +align_struct_init_span = 0 # unsigned number + +# The span for aligning single-line typedefs. +# +# 0: Don't align (default). +align_typedef_span = 0 # unsigned number + +# The minimum space between the type and the synonym of a typedef. +align_typedef_gap = 0 # unsigned number + +# How to align typedef'd functions with other typedefs. +# +# 0: Don't mix them at all (default) +# 1: Align the open parenthesis with the types +# 2: Align the function type name with the other type names +align_typedef_func = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of typedefs. +# +# 0: Part of the typedef type, 'typedef int * pint;' (default) +# 1: Part of type name: 'typedef int *pint;' +# 2: Dangling: 'typedef int *pint;' +# Dangling: the '*' will not be taken into account when aligning. +align_typedef_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of typedefs. +# +# 0: Part of the typedef type, 'typedef int & intref;' (default) +# 1: Part of type name: 'typedef int &intref;' +# 2: Dangling: 'typedef int &intref;' +# Dangling: the '&' will not be taken into account when aligning. +align_typedef_amp_style = 0 # unsigned number + +# The span for aligning comments that end lines. +# +# 0: Don't align (default). +align_right_cmt_span = 0 # unsigned number + +# Minimum number of columns between preceding text and a trailing comment in +# order for the comment to qualify for being aligned. Must be non-zero to have +# an effect. +align_right_cmt_gap = 0 # unsigned number + +# If aligning comments, whether to mix with comments after '}' and #endif with +# less than three spaces before the comment. +align_right_cmt_mix = false # true/false + +# Whether to only align trailing comments that are at the same brace level. +align_right_cmt_same_level = false # true/false + +# Minimum column at which to align trailing comments. Comments which are +# aligned beyond this column, but which can be aligned in a lesser column, +# may be "pulled in". +# +# 0: Ignore (default). +align_right_cmt_at_col = 0 # unsigned number + +# The span for aligning function prototypes. +# +# 0: Don't align (default). +align_func_proto_span = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of function prototypes. +# +# 0: Part of the type 'void * foo();' (default) +# 1: Part of the function 'void *foo();' +# 2: Dangling 'void *foo();' +# Dangling: the '*' will not be taken into account when aligning. +align_func_proto_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of function prototypes. +# +# 0: Part of the type 'long & foo();' (default) +# 1: Part of the function 'long &foo();' +# 2: Dangling 'long &foo();' +# Dangling: the '&' will not be taken into account when aligning. +align_func_proto_amp_style = 0 # unsigned number + +# The threshold for aligning function prototypes. +# Use a negative number for absolute thresholds. +# +# 0: No limit (default). +align_func_proto_thresh = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # unsigned number + +# Whether to align function prototypes on the 'operator' keyword instead of +# what follows. +align_on_operator = false # true/false + +# Whether to mix aligning prototype and variable declarations. If true, +# align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # true/false + +# Whether to align single-line functions with function prototypes. +# Uses align_func_proto_span. +align_single_line_func = false # true/false + +# Whether to align the open brace of single-line functions. +# Requires align_single_line_func=true. Uses align_func_proto_span. +align_single_line_brace = false # true/false + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # unsigned number + +# (OC) The span for aligning Objective-C message specifications. +# +# 0: Don't align (default). +align_oc_msg_spec_span = 0 # unsigned number + +# Whether to align macros wrapped with a backslash and a newline. This will +# not work right if the macro contains a multi-line comment. +align_nl_cont = false # true/false + +# Whether to align macro functions and variables together. +align_pp_define_together = false # true/false + +# The span for aligning on '#define' bodies. +# +# =0: Don't align (default) +# >0: Number of lines (including comments) between blocks +align_pp_define_span = 0 # unsigned number + +# The minimum space between label and value of a preprocessor define. +align_pp_define_gap = 0 # unsigned number + +# Whether to align lines that start with '<<' with previous '<<'. +# +# Default: true +align_left_shift = true # true/false + +# Whether to align comma-separated statements following '<<' (as used to +# initialize Eigen matrices). +align_eigen_comma_init = false # true/false + +# Whether to align text after 'asm volatile ()' colons. +align_asm_colon = false # true/false + +# (OC) Span for aligning parameters in an Objective-C message call +# on the ':'. +# +# 0: Don't align. +align_oc_msg_colon_span = 0 # unsigned number + +# (OC) Whether to always align with the first parameter, even if it is too +# short. +align_oc_msg_colon_first = false # true/false + +# (OC) Whether to align parameters in an Objective-C '+' or '-' declaration +# on the ':'. +align_oc_decl_colon = false # true/false + +# (OC) Whether to not align parameters in an Objectve-C message call if first +# colon is not on next line of the message call (the same way Xcode does +# alignment) +align_oc_msg_colon_xcode_like = false # true/false + +# +# Comment modification options +# + +# Try to wrap comments at N columns. +cmt_width = 0 # unsigned number + +# How to reflow comments. +# +# 0: No reflowing (apart from the line wrapping due to cmt_width) (default) +# 1: No touching at all +# 2: Full reflow (enable cmt_indent_multi for indent with line wrapping due to cmt_width) +cmt_reflow_mode = 0 # unsigned number + +# Path to a file that contains regular expressions describing patterns for +# which the end of one line and the beginning of the next will be folded into +# the same sentence or paragraph during full comment reflow. The regular +# expressions are described using ECMAScript syntax. The syntax for this +# specification is as follows, where "..." indicates the custom regular +# expression and "n" indicates the nth end_of_prev_line_regex and +# beg_of_next_line_regex regular expression pair: +# +# end_of_prev_line_regex[1] = "...$" +# beg_of_next_line_regex[1] = "^..." +# end_of_prev_line_regex[2] = "...$" +# beg_of_next_line_regex[2] = "^..." +# . +# . +# . +# end_of_prev_line_regex[n] = "...$" +# beg_of_next_line_regex[n] = "^..." +# +# Note that use of this option overrides the default reflow fold regular +# expressions, which are internally defined as follows: +# +# end_of_prev_line_regex[1] = "[\w,\]\)]$" +# beg_of_next_line_regex[1] = "^[\w,\[\(]" +# end_of_prev_line_regex[2] = "\.$" +# beg_of_next_line_regex[2] = "^[A-Z]" +cmt_reflow_fold_regex_file = "" # string + +# Whether to indent wrapped lines to the start of the encompassing paragraph +# during full comment reflow (cmt_reflow_mode = 2). Overrides the value +# specified by cmt_sp_after_star_cont. +# +# Note that cmt_align_doxygen_javadoc_tags overrides this option for +# paragraphs associated with javadoc tags +cmt_reflow_indent_to_paragraph_start = false # true/false + +# Whether to convert all tabs to spaces in comments. If false, tabs in +# comments are left alone, unless used for indenting. +cmt_convert_tab_to_spaces = false # true/false + +# Whether to apply changes to multi-line comments, including cmt_width, +# keyword substitution and leading chars. +# +# Default: true +cmt_indent_multi = true # true/false + +# Whether to align doxygen javadoc-style tags ('@param', '@return', etc.) +# and corresponding fields such that groups of consecutive block tags, +# parameter names, and descriptions align with one another. Overrides that +# which is specified by the cmt_sp_after_star_cont. If cmt_width > 0, it may +# be necessary to enable cmt_indent_multi and set cmt_reflow_mode = 2 +# in order to achieve the desired alignment for line-wrapping. +cmt_align_doxygen_javadoc_tags = false # true/false + +# The number of spaces to insert after the star and before doxygen +# javadoc-style tags (@param, @return, etc). Requires enabling +# cmt_align_doxygen_javadoc_tags. Overrides that which is specified by the +# cmt_sp_after_star_cont. +# +# Default: 1 +cmt_sp_before_doxygen_javadoc_tags = 1 # unsigned number + +# Whether to change trailing, single-line c-comments into cpp-comments. +cmt_trailing_single_line_c_to_cpp = false # true/false + +# Whether to group c-comments that look like they are in a block. +cmt_c_group = false # true/false + +# Whether to put an empty '/*' on the first line of the combined c-comment. +cmt_c_nl_start = false # true/false + +# Whether to add a newline before the closing '*/' of the combined c-comment. +cmt_c_nl_end = false # true/false + +# Whether to change cpp-comments into c-comments. +cmt_cpp_to_c = false # true/false + +# Whether to group cpp-comments that look like they are in a block. Only +# meaningful if cmt_cpp_to_c=true. +cmt_cpp_group = false # true/false + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +# when converting to a c-comment. +# +# Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +cmt_cpp_nl_start = false # true/false + +# Whether to add a newline before the closing '*/' of the combined cpp-comment +# when converting to a c-comment. +# +# Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +cmt_cpp_nl_end = false # true/false + +# Whether to put a star on subsequent comment lines. +cmt_star_cont = false # true/false + +# The number of spaces to insert at the start of subsequent comment lines. +cmt_sp_before_star_cont = 0 # unsigned number + +# The number of spaces to insert after the star on subsequent comment lines. +cmt_sp_after_star_cont = 0 # unsigned number + +# For multi-line comments with a '*' lead, remove leading spaces if the first +# and last lines of the comment are the same length. +# +# Default: true +cmt_multi_check_last = true # true/false + +# For multi-line comments with a '*' lead, remove leading spaces if the first +# and last lines of the comment are the same length AND if the length is +# bigger as the first_len minimum. +# +# Default: 4 +cmt_multi_first_len_minimum = 4 # unsigned number + +# Path to a file that contains text to insert at the beginning of a file if +# the file doesn't start with a C/C++ comment. If the inserted text contains +# '$(filename)', that will be replaced with the current file's name. +cmt_insert_file_header = "" # string + +# Path to a file that contains text to insert at the end of a file if the +# file doesn't end with a C/C++ comment. If the inserted text contains +# '$(filename)', that will be replaced with the current file's name. +cmt_insert_file_footer = "" # string + +# Path to a file that contains text to insert before a function definition if +# the function isn't preceded by a C/C++ comment. If the inserted text +# contains '$(function)', '$(javaparam)' or '$(fclass)', these will be +# replaced with, respectively, the name of the function, the javadoc '@param' +# and '@return' stuff, or the name of the class to which the member function +# belongs. +cmt_insert_func_header = "" # string + +# Path to a file that contains text to insert before a class if the class +# isn't preceded by a C/C++ comment. If the inserted text contains '$(class)', +# that will be replaced with the class name. +cmt_insert_class_header = "" # string + +# Path to a file that contains text to insert before an Objective-C message +# specification, if the method isn't preceded by a C/C++ comment. If the +# inserted text contains '$(message)' or '$(javaparam)', these will be +# replaced with, respectively, the name of the function, or the javadoc +# '@param' and '@return' stuff. +cmt_insert_oc_msg_header = "" # string + +# Whether a comment should be inserted if a preprocessor is encountered when +# stepping backwards from a function name. +# +# Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and +# cmt_insert_class_header. +cmt_insert_before_preproc = false # true/false + +# Whether a comment should be inserted if a function is declared inline to a +# class definition. +# +# Applies to cmt_insert_func_header. +# +# Default: true +cmt_insert_before_inlines = true # true/false + +# Whether a comment should be inserted if the function is a class constructor +# or destructor. +# +# Applies to cmt_insert_func_header. +cmt_insert_before_ctor_dtor = false # true/false + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on a single-line 'do' statement. +mod_full_brace_do = force # ignore/add/remove/force/not_defined + +# Add or remove braces on a single-line 'for' statement. +mod_full_brace_for = force # ignore/add/remove/force/not_defined + +# (Pawn) Add or remove braces on a single-line function definition. +mod_full_brace_function = force # ignore/add/remove/force/not_defined + +# Add or remove braces on a single-line 'if' statement. Braces will not be +# removed if the braced statement contains an 'else'. +mod_full_brace_if = force # ignore/add/remove/force/not_defined + +# Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either +# have, or do not have, braces. Overrides mod_full_brace_if. +# +# 0: Don't override mod_full_brace_if +# 1: Add braces to all blocks if any block needs braces and remove braces if +# they can be removed from all blocks +# 2: Add braces to all blocks if any block already has braces, regardless of +# whether it needs them +# 3: Add braces to all blocks if any block needs braces and remove braces if +# they can be removed from all blocks, except if all blocks have braces +# despite none needing them +mod_full_brace_if_chain = 0 # unsigned number + +# Whether to add braces to all blocks of an 'if'/'else if'/'else' chain. +# If true, mod_full_brace_if_chain will only remove braces from an 'if' that +# does not have an 'else if' or 'else'. +mod_full_brace_if_chain_only = false # true/false + +# Add or remove braces on single-line 'while' statement. +mod_full_brace_while = ignore # ignore/add/remove/force/not_defined + +# Add or remove braces on single-line 'using ()' statement. +mod_full_brace_using = ignore # ignore/add/remove/force/not_defined + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # unsigned number + +# Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks +# which span multiple lines. +# +# Affects: +# mod_full_brace_for +# mod_full_brace_if +# mod_full_brace_if_chain +# mod_full_brace_if_chain_only +# mod_full_brace_while +# mod_full_brace_using +# +# Does not affect: +# mod_full_brace_do +# mod_full_brace_function +mod_full_brace_nl_block_rem_mlcond = false # true/false + +# Add or remove unnecessary parentheses on 'return' statement. +mod_paren_on_return = ignore # ignore/add/remove/force/not_defined + +# Add or remove unnecessary parentheses on 'throw' statement. +mod_paren_on_throw = ignore # ignore/add/remove/force/not_defined + +# (Pawn) Whether to change optional semicolons to real semicolons. +mod_pawn_semicolon = false # true/false + +# Whether to fully parenthesize Boolean expressions in 'while' and 'if' +# statement, as in 'if (a && b > c)' => 'if (a && (b > c))'. +mod_full_paren_if_bool = false # true/false + +# Whether to fully parenthesize Boolean expressions after '=' +# statement, as in 'x = a && b > c;' => 'x = (a && (b > c));'. +mod_full_paren_assign_bool = false # true/false + +# Whether to fully parenthesize Boolean expressions after '=' +# statement, as in 'return a && b > c;' => 'return (a && (b > c));'. +mod_full_paren_return_bool = false # true/false + +# Whether to remove superfluous semicolons. +mod_remove_extra_semicolon = false # true/false + +# Whether to remove duplicate include. +mod_remove_duplicate_include = false # true/false + +# If a function body exceeds the specified number of newlines and doesn't have +# a comment after the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # unsigned number + +# If a namespace body exceeds the specified number of newlines and doesn't +# have a comment after the close brace, a comment will be added. +mod_add_long_namespace_closebrace_comment = 0 # unsigned number + +# If a class body exceeds the specified number of newlines and doesn't have a +# comment after the close brace, a comment will be added. +mod_add_long_class_closebrace_comment = 0 # unsigned number + +# If a switch body exceeds the specified number of newlines and doesn't have a +# comment after the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # unsigned number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have +# a comment after the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 0 # unsigned number + +# If an #ifdef or #else body exceeds the specified number of newlines and +# doesn't have a comment after the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 0 # unsigned number + +# Whether to take care of the case by the mod_sort_xx options. +mod_sort_case_sensitive = false # true/false + +# Whether to sort consecutive single-line 'import' statements. +mod_sort_import = false # true/false + +# (C#) Whether to sort consecutive single-line 'using' statements. +mod_sort_using = false # true/false + +# Whether to sort consecutive single-line '#include' statements (C/C++) and +# '#import' statements (Objective-C). Be aware that this has the potential to +# break your code if your includes/imports have ordering dependencies. +mod_sort_include = false # true/false + +# Whether to prioritize '#include' and '#import' statements that contain +# filename without extension when sorting is enabled. +mod_sort_incl_import_prioritize_filename = false # true/false + +# Whether to prioritize '#include' and '#import' statements that does not +# contain extensions when sorting is enabled. +mod_sort_incl_import_prioritize_extensionless = false # true/false + +# Whether to prioritize '#include' and '#import' statements that contain +# angle over quotes when sorting is enabled. +mod_sort_incl_import_prioritize_angle_over_quotes = false # true/false + +# Whether to ignore file extension in '#include' and '#import' statements +# for sorting comparison. +mod_sort_incl_import_ignore_extension = false # true/false + +# Whether to group '#include' and '#import' statements when sorting is enabled. +mod_sort_incl_import_grouping_enabled = false # true/false + +# Whether to move a 'break' that appears after a fully braced 'case' before +# the close brace, as in 'case X: { ... } break;' => 'case X: { ... break; }'. +mod_move_case_break = false # true/false + +# Whether to move a 'return' that appears after a fully braced 'case' before +# the close brace, as in 'case X: { ... } return;' => 'case X: { ... return; }'. +mod_move_case_return = false # true/false + +# Add or remove braces around a fully braced case statement. Will only remove +# braces if there are no variable declarations in the block. +mod_case_brace = ignore # ignore/add/remove/force/not_defined + +# Whether to remove a void 'return;' that appears as the last statement in a +# function. +mod_remove_empty_return = false # true/false + +# Add or remove the comma after the last value of an enumeration. +mod_enum_last_comma = ignore # ignore/add/remove/force/not_defined + +# Syntax to use for infinite loops. +# +# 0: Leave syntax alone (default) +# 1: Rewrite as `for(;;)` +# 2: Rewrite as `while(true)` +# 3: Rewrite as `do`...`while(true);` +# 4: Rewrite as `while(1)` +# 5: Rewrite as `do`...`while(1);` +# +# Infinite loops that do not already match one of these syntaxes are ignored. +# Other options that affect loop formatting will be applied after transforming +# the syntax. +mod_infinite_loop = 0 # unsigned number + +# Add or remove the 'int' keyword in 'int short'. +mod_int_short = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'short int'. +mod_short_int = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'int long'. +mod_int_long = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'long int'. +mod_long_int = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'int signed'. +mod_int_signed = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'signed int'. +mod_signed_int = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'int unsigned'. +mod_int_unsigned = ignore # ignore/add/remove/force/not_defined + +# Add or remove the 'int' keyword in 'unsigned int'. +mod_unsigned_int = ignore # ignore/add/remove/force/not_defined + +# If there is a situation where mod_int_* and mod_*_int would result in +# multiple int keywords, whether to keep the rightmost int (the default) or the +# leftmost int. +mod_int_prefer_int_on_left = false # true/false + +# (OC) Whether to organize the properties. If true, properties will be +# rearranged according to the mod_sort_oc_property_*_weight factors. +mod_sort_oc_properties = false # true/false + +# (OC) Weight of a class property modifier. +mod_sort_oc_property_class_weight = 0 # number + +# (OC) Weight of 'atomic' and 'nonatomic'. +mod_sort_oc_property_thread_safe_weight = 0 # number + +# (OC) Weight of 'readwrite' when organizing properties. +mod_sort_oc_property_readwrite_weight = 0 # number + +# (OC) Weight of a reference type specifier ('retain', 'copy', 'assign', +# 'weak', 'strong') when organizing properties. +mod_sort_oc_property_reference_weight = 0 # number + +# (OC) Weight of getter type ('getter=') when organizing properties. +mod_sort_oc_property_getter_weight = 0 # number + +# (OC) Weight of setter type ('setter=') when organizing properties. +mod_sort_oc_property_setter_weight = 0 # number + +# (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified', +# 'null_resettable') when organizing properties. +mod_sort_oc_property_nullability_weight = 0 # number + +# +# Preprocessor options +# + +# How to use tabs when indenting preprocessor code. +# +# -1: Use 'indent_with_tabs' setting (default) +# 0: Spaces only +# 1: Indent with tabs to brace level, align with spaces +# 2: Indent and align with tabs, using spaces when not on a tabstop +# +# Default: -1 +pp_indent_with_tabs = -1 # number + +# Add or remove indentation of preprocessor directives inside #if blocks +# at brace level 0 (file-level). +pp_indent = add # ignore/add/remove/force/not_defined + +# Whether to indent #if/#else/#endif at the brace level. If false, these are +# indented from column 1. +pp_indent_at_level = true # true/false + +# Whether to indent #if/#else/#endif at the parenthesis level if the brace +# level is 0. If false, these are indented from column 1. +pp_indent_at_level0 = false # true/false + +# Specifies the number of columns to indent preprocessors per level +# at brace level 0 (file-level). If pp_indent_at_level=false, also specifies +# the number of columns to indent preprocessors per level +# at brace level > 0 (function-level). +# +# Default: 1 +pp_indent_count = 2 # unsigned number + +# Add or remove space after # based on pp level of #if blocks. +pp_space_after = ignore # ignore/add/remove/force/not_defined + +# Sets the number of spaces per level added with pp_space_after. +pp_space_count = 0 # unsigned number + +# The indent for '#region' and '#endregion' in C# and '#pragma region' in +# C/C++. Negative values decrease indent down to the first column. +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion. +pp_region_indent_code = false # true/false + +# If pp_indent_at_level=true, sets the indent for #if, #else and #endif when +# not at file-level. Negative values decrease indent down to the first column. +# +# =0: Indent preprocessors using output_tab_size +# >0: Column at which all preprocessors will be indented +pp_indent_if = 0 # number + +# Whether to indent the code between #if, #else and #endif. +pp_if_indent_code = false # true/false + +# Whether to indent the body of an #if that encompasses all the code in the file. +pp_indent_in_guard = false # true/false + +# Whether to indent '#define' at the brace level. If false, these are +# indented from column 1. +pp_define_at_level = false # true/false + +# Whether to indent '#include' at the brace level. +pp_include_at_level = false # true/false + +# Whether to ignore the '#define' body while formatting. +pp_ignore_define_body = false # true/false + +# An offset value that controls the indentation of the body of a multiline #define. +# 'body' refers to all the lines of a multiline #define except the first line. +# Requires 'pp_ignore_define_body = false'. +# +# <0: Absolute column: the body indentation starts off at the specified column +# (ex. -3 ==> the body is indented starting from column 3) +# >=0: Relative to the column of the '#' of '#define' +# (ex. 3 ==> the body is indented starting 3 columns at the right of '#') +# +# Default: 8 +pp_multiline_define_body_indent = 8 # number + +# Whether to indent case statements between #if, #else, and #endif. +# Only applies to the indent of the preprocessor that the case statements +# directly inside of. +# +# Default: true +pp_indent_case = true # true/false + +# Whether to indent whole function definitions between #if, #else, and #endif. +# Only applies to the indent of the preprocessor that the function definition +# is directly inside of. +# +# Default: true +pp_indent_func_def = true # true/false + +# Whether to indent extern C blocks between #if, #else, and #endif. +# Only applies to the indent of the preprocessor that the extern block is +# directly inside of. +# +# Default: true +pp_indent_extern = true # true/false + +# How to indent braces directly inside #if, #else, and #endif. +# Requires pp_if_indent_code=true and only applies to the indent of the +# preprocessor that the braces are directly inside of. +# 0: No extra indent +# 1: Indent by one level +# -1: Preserve original indentation +# +# Default: 1 +pp_indent_brace = 1 # number + +# Whether to print warning messages for unbalanced #if and #else blocks. +# This will print a message in the following cases: +# - if an #ifdef block ends on a different indent level than +# where it started from. Example: +# +# #ifdef TEST +# int i; +# { +# int j; +# #endif +# +# - an #elif/#else block ends on a different indent level than +# the corresponding #ifdef block. Example: +# +# #ifdef TEST +# int i; +# #else +# } +# int j; +# #endif +pp_warn_unbalanced_if = false # true/false + +# +# Sort includes options +# + +# The regex for include category with priority 0. +include_category_0 = "" # string + +# The regex for include category with priority 1. +include_category_1 = "" # string + +# The regex for include category with priority 2. +include_category_2 = "" # string + +# +# Use or Do not Use options +# + +# true: indent_func_call_param will be used (default) +# false: indent_func_call_param will NOT be used +# +# Default: true +use_indent_func_call_param = true # true/false + +# The value of the indentation for a continuation line is calculated +# differently if the statement is: +# - a declaration: your case with QString fileName ... +# - an assignment: your case with pSettings = new QSettings( ... +# +# At the second case the indentation value might be used twice: +# - at the assignment +# - at the function call (if present) +# +# To prevent the double use of the indentation value, use this option with the +# value 'true'. +# +# true: indent_continue will be used only once +# false: indent_continue will be used every time (default) +# +# Requires indent_ignore_first_continue=false. +use_indent_continue_only_once = false # true/false + +# The indentation can be: +# - after the assignment, at the '[' character +# - at the beginning of the lambda body +# +# true: indentation will be at the beginning of the lambda body +# false: indentation will be after the assignment (default) +indent_cpp_lambda_only_once = false # true/false + +# Whether sp_after_angle takes precedence over sp_inside_fparen. This was the +# historic behavior, but is probably not the desired behavior, so this is off +# by default. +use_sp_after_angle_always = false # true/false + +# Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially, +# this tries to format these so that they match Qt's normalized form (i.e. the +# result of QMetaObject::normalizedSignature), which can slightly improve the +# performance of the QObject::connect call, rather than how they would +# otherwise be formatted. +# +# See options_for_QT.cpp for details. +# +# Default: true +use_options_overriding_for_qt_macros = true # true/false + +# If true: the form feed character is removed from the list of whitespace +# characters. See https://en.cppreference.com/w/cpp/string/byte/isspace. +use_form_feed_no_more_as_whitespace_character = false # true/false + +# +# Warn levels - 1: error, 2: warning (default), 3: note +# + +# (C#) Warning is given if doing tab-to-\t replacement and we have found one +# in a C# verbatim string literal. +# +# Default: 2 +warn_level_tabs_found_in_verbatim_string_literals = 2 # unsigned number + +# Limit the number of loops. +# Used by uncrustify.cpp to exit from infinite loop. +# 0: no limit. +debug_max_number_of_loops = 0 # number + +# Set the number of the line to protocol; +# Used in the function prot_the_line if the 2. parameter is zero. +# 0: nothing protocol. +debug_line_number_to_protocol = 0 # number + +# Set the number of second(s) before terminating formatting the current file, +# 0: no timeout. +# only for linux +debug_timeout = 0 # number + +# Set the number of characters to be printed if the text is too long, +# 0: do not truncate. +debug_truncate = 0 # unsigned number + +# sort (or not) the tracking info. +# +# Default: true +debug_sort_the_tracks = true # true/false + +# decode (or not) the flags as a new line. +# only if the -p option is set. +debug_decode_the_flags = false # true/false + +# insert the number of the line at the beginning of each line +set_numbering_for_html_output = false # true/false + +# Meaning of the settings: +# Ignore - do not do any changes +# Add - makes sure there is 1 or more space/brace/newline/etc +# Force - makes sure there is exactly 1 space/brace/newline/etc, +# behaves like Add in some contexts +# Remove - removes space/brace/newline/etc +# +# +# - Token(s) can be treated as specific type(s) with the 'set' option: +# `set tokenType tokenString [tokenString...]` +# +# Example: +# `set BOOL __AND__ __OR__` +# +# tokenTypes are defined in src/token_enum.h, use them without the +# 'CT_' prefix: 'CT_BOOL' => 'BOOL' +# +# +# - Token(s) can be treated as type(s) with the 'type' option. +# `type tokenString [tokenString...]` +# +# Example: +# `type int c_uint_8 Rectangle` +# +# This can also be achieved with `set TYPE int c_uint_8 Rectangle` +# +# +# To embed whitespace in tokenStrings use the '\' escape character, or quote +# the tokenStrings. These quotes are supported: "'` +# +# +# - Support for the auto detection of languages through the file ending can be +# added using the 'file_ext' command. +# `file_ext langType langString [langString..]` +# +# Example: +# `file_ext CPP .ch .cxx .cpp.in` +# +# langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use +# them without the 'LANG_' prefix: 'LANG_CPP' => 'CPP' +# +# +# - Custom macro-based indentation can be set up using 'macro-open', +# 'macro-else' and 'macro-close'. +# `(macro-open | macro-else | macro-close) tokenString` +# +# Example: +# `macro-open BEGIN_TEMPLATE_MESSAGE_MAP` +# `macro-open BEGIN_MESSAGE_MAP` +# `macro-close END_MESSAGE_MAP` +# +# +# option(s) with 'not default' value: 0 +# From 67e52ed27a4ab20da4ba3ee82c80477a617ca1e9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Jan 2023 19:33:36 +0100 Subject: [PATCH 0356/1848] [CI] Added uncrustify workflow --- .github/workflows/uncrustify.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/uncrustify.yml diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml new file mode 100644 index 0000000000..87b95b790c --- /dev/null +++ b/.github/workflows/uncrustify.yml @@ -0,0 +1,23 @@ +name: "Uncrustify" + +on: + push: + branches: [master, uncrustify] + pull_request: + branches: [master] + +jobs: + uncrustify: + name: Uncrustify + runs-on: ubuntu-latest + env: + run-uncrust: ${{ contains(github.event.head_commit.message, 'Bump version to') || github.event_name == 'pull_request' }} + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Run style check + uses: coleaeason/actions-uncrustify@v1 + with: + configPath: 'uncrustify.cfg' From ec2da7dc3e77c1135fe25797a5272cd633932ec4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Jan 2023 19:45:51 +0100 Subject: [PATCH 0357/1848] [CI] Added option to force check CI_FORCE_UNCRUST --- .github/workflows/uncrustify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 87b95b790c..31d2bd6ec7 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -11,7 +11,7 @@ jobs: name: Uncrustify runs-on: ubuntu-latest env: - run-uncrust: ${{ contains(github.event.head_commit.message, 'Bump version to') || github.event_name == 'pull_request' }} + run-uncrust: ${{ contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, 'CI_FORCE_UNCRUST') || github.event_name == 'pull_request' }} steps: - name: Checkout repository From dc3fb2d303c8669c7c44f47f32b5f77876610e53 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Jan 2023 19:55:59 +0100 Subject: [PATCH 0358/1848] [CI] Use patched action --- .github/workflows/uncrustify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 31d2bd6ec7..24d22b2849 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -18,6 +18,6 @@ jobs: uses: actions/checkout@v2 - name: Run style check - uses: coleaeason/actions-uncrustify@v1 + uses: jgromes/actions-uncrustify@v1 with: configPath: 'uncrustify.cfg' From 5f3fb5fa0db26d0f4a5fad18d6c7c454a44966e0 Mon Sep 17 00:00:00 2001 From: Andrew Moroz Date: Sat, 28 Jan 2023 17:46:01 -0500 Subject: [PATCH 0359/1848] sx126x-rx-gain-persist: add ability to persist Rx gain setting when calling SX126x::setRxBoostedGainMode --- src/modules/SX126x/SX126x.cpp | 19 ++++++++++++++++++- src/modules/SX126x/SX126x.h | 4 +++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1e23dda22a..d6fe884d68 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -870,7 +870,7 @@ int16_t SX126x::setRxBandwidth(float rxBw) { return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); } -int16_t SX126x::setRxBoostedGainMode(bool rxbgm) { +int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { // read the current register value uint8_t rxGain = 0; int16_t state = readRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); @@ -887,6 +887,23 @@ int16_t SX126x::setRxBoostedGainMode(bool rxbgm) { state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); RADIOLIB_ASSERT(state); + // add Rx Gain register to retention memory if requested + if(persist) { + // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3 + uint8_t value0 = 0x01; + uint8_t value1 = 0x08; + uint8_t value2 = 0xAC; + + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, &value0, 1); + RADIOLIB_ASSERT(state); + + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1, &value1, 1); + RADIOLIB_ASSERT(state); + + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2, &value2, 1); + RADIOLIB_ASSERT(state); + } + return(state); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 12a737f98e..57dcb7cb3d 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -713,9 +713,11 @@ class SX126x: public PhysicalLayer { \param rxbgm True for Rx Boosted Gain, false for Rx Power Saving Gain + \param persist True to persist Rx gain setting when waking up from warm-start mode (e.g. when using Rx duty cycle mode) + \returns \ref status_codes */ - int16_t setRxBoostedGainMode(bool rxbgm); + int16_t setRxBoostedGainMode(bool rxbgm, bool persist = true); /*! \brief Sets time-bandwidth product of Gaussian filter applied for shaping. From 1a0daa6eb516a13a97bc4432e7882e792086f2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 29 Jan 2023 17:37:11 +0100 Subject: [PATCH 0360/1848] Go back to the original action --- .github/workflows/uncrustify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 24d22b2849..31d2bd6ec7 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -18,6 +18,6 @@ jobs: uses: actions/checkout@v2 - name: Run style check - uses: jgromes/actions-uncrustify@v1 + uses: coleaeason/actions-uncrustify@v1 with: configPath: 'uncrustify.cfg' From 0c2d40fda7d2f09a7a8da1199670c623040dcc5c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Jan 2023 18:23:46 +0100 Subject: [PATCH 0361/1848] [CI] Fix dubious ownership error --- .github/workflows/uncrustify.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 31d2bd6ec7..2a77f69072 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -17,6 +17,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + # attempt to resolve "dubious ownership" error (https://github.com/actions/runner-images/issues/6775) + - name: Change Owner of Container Working Directory + run: chown root:root . + - name: Run style check uses: coleaeason/actions-uncrustify@v1 with: From 773b3e10aad5c9779b5e760a1eb80d8c6b0c2f14 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Jan 2023 18:28:01 +0100 Subject: [PATCH 0362/1848] [CI] Another attempt at dubious ownership fix (CI_FORCE_UNCRUST) --- .github/workflows/uncrustify.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 2a77f69072..cccdd4aa13 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -2,7 +2,7 @@ name: "Uncrustify" on: push: - branches: [master, uncrustify] + branches: [master] pull_request: branches: [master] @@ -15,13 +15,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 - - # attempt to resolve "dubious ownership" error (https://github.com/actions/runner-images/issues/6775) - - name: Change Owner of Container Working Directory - run: chown root:root . + if: ${{ env.run-uncrust == 'true' }} + uses: actions/checkout@v3 - name: Run style check + if: ${{ env.run-uncrust == 'true' }} uses: coleaeason/actions-uncrustify@v1 with: configPath: 'uncrustify.cfg' From 1afa947030c5637f71f6563bc22aa75032e53a57 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Jan 2023 18:31:01 +0100 Subject: [PATCH 0363/1848] [CI] Temporarily disable uncrustify action --- .github/workflows/uncrustify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index cccdd4aa13..1dcc7c4a1f 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -11,7 +11,7 @@ jobs: name: Uncrustify runs-on: ubuntu-latest env: - run-uncrust: ${{ contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, 'CI_FORCE_UNCRUST') || github.event_name == 'pull_request' }} + run-uncrust: ${{ false || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, 'CI_FORCE_UNCRUST') || github.event_name == 'pull_request' }} steps: - name: Checkout repository From 4c712c1f2cb88f63667c279239ff382438c2c116 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 3 Feb 2023 10:05:22 +0100 Subject: [PATCH 0364/1848] [MOD] Remove constexpr usage This was introduced when STM32WL support was added. Using constexpr for the END_OF_MODE_TABLE constant allows it to be initialized in the class declaration, but this needs C++11. This moves the initialization out of the class declaration to the .cpp file, which does not need constexpr. It also lets STM32WLx::END_OF_MODE_TABLE define its value directly (instead of aliasing Module::END_OF_MODE_TABLE) to prevent reduce runtime overhead (see below). The downside of this change is that the value of the END_OF_MODE_TABLE is no longer visible in other compilation units and thus cannot be inlined into the rfswitch_table (if used). For example, on STM32, this means that instead of having a pre-cooked rfswitch_table that lives in the .rodata section (so can be read directly from flash), the table lives in RAM and is initialized at runtime (the actual modes and pins are copied from flash to RAM by the standard startup loop that copies all of the .data section, and the END_OF_MODE_TABLE value is copied by a bit of new generated code). This means a little more runtime overhead, but the cost is mostly in RAM size (80 bytes for the SMT32WL sketches, 16 per mode plus 16 for the END_OF_MODE_TABLE). In a first attempt at this commit, STM32WLx::END_OF_MODE_TABLE was still initialized using the Module::END_OF_MODE_TABLE value, but since the latter is also not available at compiletime, this meant initialization of the former also needed to happen at runtime, adding even more code overhead (and possibly leading to ordering issues as well). To avoid this, the STM32WLx::END_OF_MODE_TABLE initialization now just duplicates that of Module::END_OF_MODE_TABLE. On AVR, the impact is not so much: Since AVR cannot address flash directly, the table was already copied from flash to RAM at startup, so the extra RAM usage is just 4 bytes because END_OF_MODE_TABLE is now also present in RAM, to be copied into rfswitch_table at startup. Options for avoiding this overhead (not implemented in this commit) could be (in no particular order): 1. Use a macro instead of a constant. Downside is that these cannot be scoped inside the Module/STM32WLx classes like now, so this requires changes to sketches that use a rfswitch_table (and reduced scoping and using macros adds more opportunity for conflicts and weird errors). 2. Apply the change in this commit only when C++11 is not available. Downside is that the initialization value of these constants must be duplicated in the .h and .cpp file for C++ and older versions respectively. 3. Let sketches just use `{Module::MODE_END_OF_TABLE, {}}` explicitly instead of `Module::END_OF_MODE_TABLE`. Downside of this is that this requires sketches to be modified and that it lets the sketch encode more of the table structure, potentially making future API changes harder (but it probably does not really matter in practice). 4. Turn END_OF_MODE_TABLE into a static method, which *can* then be defined in the class declaration and inlined. The method can then be conditionally marked as constexpr, which allows C++11 compilers to completely resolve the rfswitch_table value at compiletime, producing a binary identical to before this commit. When constexpr is omitted (e.g. on older compilers), some runtime overhead is added (pretty much the same as the result from this commit). Downside is that sketches must be modified, and the `END_OF_MODE_TABLE` "constant" must now be called, e.g. `END_OF_MODE_TABLE()` which might be a bit unexpected syntax. --- src/Module.cpp | 2 ++ src/Module.h | 2 +- src/modules/SX126x/STM32WLx.cpp | 2 ++ src/modules/SX126x/STM32WLx.h | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 5046da638e..522d6ae210 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -8,6 +8,8 @@ mbed::PwmOut *pwmPin = NULL; #endif +const Module::RfSwitchMode_t Module::END_OF_MODE_TABLE = {Module::MODE_END_OF_TABLE, {}}; + Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), diff --git a/src/Module.h b/src/Module.h index 78793d0aa7..526f24fa29 100644 --- a/src/Module.h +++ b/src/Module.h @@ -62,7 +62,7 @@ class Module { * * See setRfSwitchTable() for details. */ - static constexpr RfSwitchMode_t END_OF_MODE_TABLE = {MODE_END_OF_TABLE, {}}; + static const RfSwitchMode_t END_OF_MODE_TABLE; #if defined(RADIOLIB_BUILD_ARDUINO) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 744f88c377..6897dfc19e 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -11,6 +11,8 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include +const Module::RfSwitchMode_t STM32WLx::END_OF_MODE_TABLE = {Module::MODE_END_OF_TABLE, {}}; + STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index 5778dfb1cc..ad7faffbff 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -63,7 +63,7 @@ class STM32WLx : public SX1262 { MODE_TX_HP, }; /*! \copydoc Module::END_OF_MODE_TABLE */ - static constexpr auto END_OF_MODE_TABLE = Module::END_OF_MODE_TABLE; + static const Module::RfSwitchMode_t END_OF_MODE_TABLE; // basic methods From dc050df8d96301eaa0afe8b47e42ff8d8d29317b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Feb 2023 14:11:44 +0100 Subject: [PATCH 0365/1848] [SX126x] Added support for AFSK transmission --- src/modules/SX126x/SX126x.cpp | 57 +++++++++++++++++++++++++++++++++++ src/modules/SX126x/SX126x.h | 5 +++ 2 files changed, 62 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index d6fe884d68..9c6e5d1962 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -321,6 +321,63 @@ int16_t SX126x::receiveDirect() { return(RADIOLIB_ERR_UNKNOWN); } +int16_t SX126x::directMode() { + // check modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // disable DIO2 RF switch + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); + + // set DIO2 to clock output and DIO3 to data input + // this is done exclusively by writing magic values to even more magic registers + uint8_t val = 0; + + state = readRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, &val, 1); + RADIOLIB_ASSERT(state); + val &= ~(0x07 << 4); + val |= (0x01 << 4); + state = writeRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, &val, 1); + RADIOLIB_ASSERT(state); + + state = readRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, &val, 1); + RADIOLIB_ASSERT(state); + val &= ~(0x0F << 0); + val |= (0x0C << 0); + state = writeRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, &val, 1); + RADIOLIB_ASSERT(state); + + state = readRegister(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, &val, 1); + RADIOLIB_ASSERT(state); + val &= ~(0x01 << 3); + val |= (0x01 << 3); + state = writeRegister(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, &val, 1); + RADIOLIB_ASSERT(state); + + state = readRegister(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, &val, 1); + RADIOLIB_ASSERT(state); + val &= ~(0x01 << 3); + val |= (0x01 << 3); + state = writeRegister(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, &val, 1); + RADIOLIB_ASSERT(state); + + // enable TxDone interrupt + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE, RADIOLIB_SX126X_IRQ_TX_DONE); + RADIOLIB_ASSERT(state); + + // set preamble length to the maximum to prevent SX126x from exiting Tx mode for a while + state = setPreambleLength(0xFFFF); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { // set mode to CAD int state = startChannelScan(symbolNum, detPeak, detMin); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 57dcb7cb3d..8b8bd4fb68 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -83,8 +83,11 @@ #define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 #define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 #define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 +#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB #define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC #define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD #define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE @@ -102,6 +105,7 @@ #define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 +#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B @@ -1013,6 +1017,7 @@ class SX126x: public PhysicalLayer { int16_t setFrequencyRaw(float freq); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); + int16_t directMode(); // fixes to errata int16_t fixSensitivity(); From 455ce12eedf6f2491fdff3cdc6829db5a0f1bb36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Feb 2023 14:12:55 +0100 Subject: [PATCH 0366/1848] [AFSK] Added SX126x to examples --- .../AFSK_Imperial_March.ino | 2 ++ examples/AFSK/AFSK_Tone/AFSK_Tone.ino | 2 ++ examples/APRS/APRS_MicE/APRS_MicE.ino | 10 +++++++- examples/APRS/APRS_Position/APRS_Position.ino | 10 +++++++- .../AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino | 10 +++++++- .../FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino | 12 ++++++++-- .../Hellschreiber_Transmit_AFSK.ino | 10 +++++++- .../Morse_Transmit_FM/Morse_Transmit_FM.ino | 23 ++++++++----------- .../RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino | 10 +++++++- .../SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino | 10 +++++++- 10 files changed, 78 insertions(+), 21 deletions(-) diff --git a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino index b749bb6e49..7c8509166d 100644 --- a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino +++ b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -9,6 +9,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -38,6 +39,7 @@ SX1278 radio = new Module(10, 2, 9, 3); // SX1231: DIO2 // CC1101: GDO2 // Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); void setup() { diff --git a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino index e5dd0ab42f..3e2212269f 100644 --- a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino +++ b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -10,6 +10,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -36,6 +37,7 @@ SX1278 radio = new Module(10, 2, 9, 3); // SX1231: DIO2 // CC1101: GDO2 // Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); void setup() { diff --git a/examples/APRS/APRS_MicE/APRS_MicE.ino b/examples/APRS/APRS_MicE/APRS_MicE.ino index 9d8061cb41..5a84d0ea93 100644 --- a/examples/APRS/APRS_MicE/APRS_MicE.ino +++ b/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -16,6 +16,7 @@ - CC1101 - nRF24 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -39,7 +40,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create AX.25 client instance using the AFSK instance diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index 2478d64b64..c05ac1947a 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -16,6 +16,7 @@ - CC1101 - nRF24 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -39,7 +40,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create AX.25 client instance using the AFSK instance diff --git a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino index 540dc08d14..f60818c30e 100644 --- a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino +++ b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -13,6 +13,7 @@ - CC1101 - nRF24 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -36,7 +37,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create AX.25 client instance using the AFSK instance diff --git a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino index 73b4a704fd..9c32091817 100644 --- a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino +++ b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -13,6 +13,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -36,7 +37,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create FSK4 client instance using the AFSK instance @@ -81,7 +89,7 @@ void setup() { // NOTE: Unlike FSK FSK4, AFSK requires no rounding of // the frequency shift. Serial.print(F("[FSK4] Initializing ... ")); - // low ("space") frequency: 434.0 MHz + // lowest ("space") frequency: 400 Hz // frequency shift: 270 Hz // baud rate: 100 baud state = fsk4.begin(400, 270, 100); diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino index 1fdff4a22e..dbe267a5a8 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -12,6 +12,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -35,7 +36,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create Hellschreiber client instance using the AFSK instance diff --git a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino index b4f4b41794..3ab9d08df3 100644 --- a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino +++ b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -12,6 +12,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -35,8 +36,15 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 -AFSKClient audio(&radio, 10); +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 +AFSKClient audio(&radio, 5); // create Morse client instance using the AFSK instance MorseClient morse(&audio); @@ -72,17 +80,6 @@ void setup() { Serial.println(state); while(true); } - - // after that, set mode to OOK - Serial.print(F("[SX1278] Switching to OOK ... ")); - state = radio.setOOK(true); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } } void loop() { diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino index 58e6d8c083..c9b268cdd3 100644 --- a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -10,6 +10,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -33,7 +34,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create RTTY client instance using the AFSK instance diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino index 4719adaff3..924522b161 100644 --- a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -12,6 +12,7 @@ - SX1231 - CC1101 - Si443x/RFM2x + - SX126x/LLCC68 (only devices without TCXO!) NOTE: Some platforms (such as Arduino Uno) might not be fast enough to correctly @@ -42,7 +43,14 @@ SX1278 radio = new Module(10, 2, 9, 3); //SX1278 radio = RadioShield.ModuleA; // create AFSK client instance using the FSK module -// pin 5 is connected to SX1278 DIO2 +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 AFSKClient audio(&radio, 5); // create SSTV client instance using the AFSK instance From e07d1d9dc1354b02ebeb31f2be210083c6141b28 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 12:32:17 +0100 Subject: [PATCH 0367/1848] [MOD] Added stream SPI transfer --- src/Module.cpp | 126 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Module.h | 40 ++++++++++++++++ 2 files changed, 166 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index 522d6ae210..88d12d201d 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -253,6 +253,132 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da this->SPIendTransaction(); } +int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForGpio, uint32_t timeout) { + #if defined(RADIOLIB_VERBOSE) + uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // pull NSS low + this->digitalWrite(this->getCs(), LOW); + + // ensure GPIO is low + uint32_t start = this->millis(); + while(this->digitalRead(this->getGpio())) { + this->yield(); + if(this->millis() - start >= timeout) { + this->digitalWrite(this->getCs(), HIGH); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } + } + + // start transfer + this->SPIbeginTransaction(); + + // send command byte(s) + for(uint8_t n = 0; n < cmdLen; n++) { + this->SPItransfer(cmd[n]); + } + + // variable to save error during SPI transfer + int16_t state = RADIOLIB_ERR_NONE; + + // send/receive all bytes + if(write) { + for(uint8_t n = 0; n < numBytes; n++) { + // send byte + uint8_t in = this->SPItransfer(dataOut[n]); + #if defined(RADIOLIB_VERBOSE) + debugBuff[n] = in; + #endif + + // check status + if(this->SPIparseStatusCb != nullptr) { + state = this->SPIparseStatusCb(in); + } + } + + } else { + // skip the first byte for read-type commands (status-only) + uint8_t in = this->SPItransfer(this->SPIreadCommand); + #if defined(RADIOLIB_VERBOSE) + debugBuff[0] = in; + #endif + + // check status + if(this->SPIparseStatusCb != nullptr) { + state = this->SPIparseStatusCb(in); + } else { + state = RADIOLIB_ERR_NONE; + } + + // read the data + if(state == RADIOLIB_ERR_NONE) { + for(uint8_t n = 0; n < numBytes; n++) { + dataIn[n] = this->SPItransfer(this->SPIreadCommand); + } + } + } + + // stop transfer + this->SPIendTransaction(); + this->digitalWrite(this->getCs(), HIGH); + + // wait for GPIO to go high and then low + if(waitForGpio) { + this->delayMicroseconds(1); + uint32_t start = this->millis(); + while(this->digitalRead(this->getGpio())) { + this->yield(); + if(this->millis() - start >= timeout) { + state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; + break; + } + } + } + + // print debug output + #if defined(RADIOLIB_VERBOSE) + // print command byte(s) + RADIOLIB_VERBOSE_PRINT("CMD\t"); + for(uint8_t n = 0; n < cmdLen; n++) { + RADIOLIB_VERBOSE_PRINT(cmd[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } + RADIOLIB_VERBOSE_PRINTLN(); + + // print data bytes + RADIOLIB_VERBOSE_PRINT("DAT"); + if(write) { + RADIOLIB_VERBOSE_PRINT("W\t"); + for(uint8_t n = 0; n < numBytes; n++) { + RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } + RADIOLIB_VERBOSE_PRINTLN(); + } else { + RADIOLIB_VERBOSE_PRINT("R\t"); + // skip the first byte for read-type commands (status-only) + RADIOLIB_VERBOSE_PRINT(this->SPIreadCommand, HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); + RADIOLIB_VERBOSE_PRINT('\t') + + for(uint8_t n = 0; n < numBytes; n++) { + RADIOLIB_VERBOSE_PRINT(this->SPIreadCommand, HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } + RADIOLIB_VERBOSE_PRINTLN(); + } + RADIOLIB_VERBOSE_PRINTLN(); + #endif + + return(state); +} + void Module::waitForMicroseconds(uint32_t start, uint32_t len) { #if defined(RADIOLIB_INTERRUPT_TIMING) (void)start; diff --git a/src/Module.h b/src/Module.h index 526f24fa29..5597303f1d 100644 --- a/src/Module.h +++ b/src/Module.h @@ -139,6 +139,23 @@ class Module { */ uint8_t SPIwriteCommand = 0b10000000; + /*! + \brief Whether the SPI interface is stream-type (e.g. SX126x) or register-type (e.g. SX127x). + Defaults to register-type SPI interfaces. + */ + bool SPIstreamType = false; + + /*! + \brief SPI status parsing callback typedef. + */ + typedef int16_t (*SPIparseStatusCb_t)(uint8_t in); + + /*! + \brief Callback to function that will parse the module-specific status codes to RadioLib status codes. + Typically used for modules with SPI stream-type interface (e.g. SX126x/SX128x). + */ + SPIparseStatusCb_t SPIparseStatusCb = nullptr; + #if defined(RADIOLIB_INTERRUPT_TIMING) /*! @@ -258,6 +275,29 @@ class Module { \param numBytes Number of bytes to transfer. */ void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + + /*! + \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). + + \param cmd SPI operation command. + + \param cmd SPI command length in bytes. + + \param write Set to true for write commands, false for read commands. + + \param dataOut Data that will be transfered from master to slave. + + \param dataIn Data that was transfered from slave to master. + + \param numBytes Number of bytes to transfer. + + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + + \param timeout GPIO wait period timeout in milliseconds. + + \returns \ref status_codes + */ + int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForGpio, uint32_t timeout); // pin number access methods From 308ad8732079cf5af62912ed023f804c6af98bb9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 12:41:49 +0100 Subject: [PATCH 0368/1848] [MOD] Port 16-bit address from ax5x43 dev --- src/Module.cpp | 22 ++++++++++++++-------- src/Module.h | 19 ++++++++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 88d12d201d..942a00e1c6 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -129,7 +129,7 @@ void Module::term() { #endif } -int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { +int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } @@ -139,7 +139,7 @@ int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { return(maskedValue); } -int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { +int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } @@ -188,25 +188,25 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t #endif } -void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) { +void Module::SPIreadRegisterBurst(uint16_t reg, uint8_t numBytes, uint8_t* inBytes) { SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); } -uint8_t Module::SPIreadRegister(uint8_t reg) { +uint8_t Module::SPIreadRegister(uint16_t reg) { uint8_t resp = 0; SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); return(resp); } -void Module::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes) { +void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, uint8_t numBytes) { SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); } -void Module::SPIwriteRegister(uint8_t reg, uint8_t data) { +void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); } -void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { +void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // start SPI transaction this->SPIbeginTransaction(); @@ -214,7 +214,13 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da this->digitalWrite(_cs, LOW); // send SPI register address with access command - this->SPItransfer(reg | cmd); + if(this->SPIaddrWidth <= 8) { + this->SPItransfer(reg | cmd); + } else { + this->SPItransfer((reg >> 8) | cmd); + this->SPItransfer(reg & 0xFF); + } + #if defined(RADIOLIB_VERBOSE) if(cmd == SPIwriteCommand) { RADIOLIB_VERBOSE_PRINT('W'); diff --git a/src/Module.h b/src/Module.h index 5597303f1d..676b9a6304 100644 --- a/src/Module.h +++ b/src/Module.h @@ -139,6 +139,11 @@ class Module { */ uint8_t SPIwriteCommand = 0b10000000; + /*! + \brief SPI address width. Defaults to 8, currently only supports 8 and 16-bit addresses. + */ + uint8_t SPIaddrWidth = 8; + /*! \brief Whether the SPI interface is stream-type (e.g. SX126x) or register-type (e.g. SX127x). Defaults to register-type SPI interfaces. @@ -200,7 +205,7 @@ class Module { \returns Masked register value or status code. */ - int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0); + int16_t SPIgetRegValue(uint16_t reg, uint8_t msb = 7, uint8_t lsb = 0); /*! \brief Overwrite-safe SPI write method with verification. This method is the preferred SPI write mechanism. @@ -219,7 +224,7 @@ class Module { \returns \ref status_codes */ - int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); + int16_t SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); /*! \brief SPI burst read method. @@ -230,7 +235,7 @@ class Module { \param inBytes Pointer to array that will hold the read data. */ - void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes); + void SPIreadRegisterBurst(uint16_t reg, uint8_t numBytes, uint8_t* inBytes); /*! \brief SPI basic read method. Use of this method is reserved for special cases, SPIgetRegValue should be used instead. @@ -239,7 +244,7 @@ class Module { \returns Value that was read from register. */ - uint8_t SPIreadRegister(uint8_t reg); + uint8_t SPIreadRegister(uint16_t reg); /*! \brief SPI burst write method. @@ -250,7 +255,7 @@ class Module { \param numBytes Number of bytes that will be written. */ - void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes); + void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, uint8_t numBytes); /*! \brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead. @@ -259,7 +264,7 @@ class Module { \param data Value that will be written to the register. */ - void SPIwriteRegister(uint8_t reg, uint8_t data); + void SPIwriteRegister(uint16_t reg, uint8_t data); /*! \brief SPI single transfer method. @@ -274,7 +279,7 @@ class Module { \param numBytes Number of bytes to transfer. */ - void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); /*! \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). From a8d35f788171177e6b0747b118e3fba6539d283d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 14:22:30 +0100 Subject: [PATCH 0369/1848] [MOD] Use SPI stream for register read/write --- src/Module.cpp | 38 +++++++++++++++++++++++++++++--------- src/Module.h | 5 +++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 942a00e1c6..8984730c80 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -189,21 +189,41 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t } void Module::SPIreadRegisterBurst(uint16_t reg, uint8_t numBytes, uint8_t* inBytes) { - SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); + if(!SPIstreamType) { + SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); + } else { + uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, 5000); + } } uint8_t Module::SPIreadRegister(uint16_t reg) { uint8_t resp = 0; - SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); + if(!SPIstreamType) { + SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); + } else { + uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, 5000); + } return(resp); } void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, uint8_t numBytes) { - SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); + if(!SPIstreamType) { + SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); + } else { + uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, 5000); + } } void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { - SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); + if(!SPIstreamType) { + SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); + } else { + uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; + SPItransferStream(cmd, 3, true, &data, NULL, 1, true, 5000); + } } void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { @@ -220,7 +240,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->SPItransfer((reg >> 8) | cmd); this->SPItransfer(reg & 0xFF); } - + #if defined(RADIOLIB_VERBOSE) if(cmd == SPIwriteCommand) { RADIOLIB_VERBOSE_PRINT('W'); @@ -305,7 +325,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } else { // skip the first byte for read-type commands (status-only) - uint8_t in = this->SPItransfer(this->SPIreadCommand); + uint8_t in = this->SPItransfer(this->SPInopCommand); #if defined(RADIOLIB_VERBOSE) debugBuff[0] = in; #endif @@ -320,7 +340,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // read the data if(state == RADIOLIB_ERR_NONE) { for(uint8_t n = 0; n < numBytes; n++) { - dataIn[n] = this->SPItransfer(this->SPIreadCommand); + dataIn[n] = this->SPItransfer(this->SPInopCommand); } } } @@ -366,13 +386,13 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } else { RADIOLIB_VERBOSE_PRINT("R\t"); // skip the first byte for read-type commands (status-only) - RADIOLIB_VERBOSE_PRINT(this->SPIreadCommand, HEX); + RADIOLIB_VERBOSE_PRINT(this->SPInopCommand, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); RADIOLIB_VERBOSE_PRINT('\t') for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(this->SPIreadCommand, HEX); + RADIOLIB_VERBOSE_PRINT(this->SPInopCommand, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); diff --git a/src/Module.h b/src/Module.h index 676b9a6304..4bf4e48112 100644 --- a/src/Module.h +++ b/src/Module.h @@ -139,6 +139,11 @@ class Module { */ uint8_t SPIwriteCommand = 0b10000000; + /*! + \brief Basic SPI no-operation command. Defaults to 0x80. + */ + uint8_t SPInopCommand = 0x00; + /*! \brief SPI address width. Defaults to 8, currently only supports 8 and 16-bit addresses. */ From 299e5de3c42f28feab03f3ce9c39631a6c9cc3d1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 16:16:16 +0100 Subject: [PATCH 0370/1848] [SX126x] Use Module SPI tream --- src/modules/SX126x/SX126x.cpp | 235 +++++++++------------------------- src/modules/SX126x/SX126x.h | 28 +++- 2 files changed, 86 insertions(+), 177 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 9c6e5d1962..b0eaaae3a7 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -14,6 +14,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); _mod->pinMode(_mod->getGpio(), INPUT); + _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; + _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + _mod->SPIstreamType = true; + _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams @@ -80,6 +85,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); _mod->pinMode(_mod->getGpio(), INPUT); + _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; + _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + _mod->SPIstreamType = true; + _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // initialize configuration variables (will be overwritten during public settings configuration) @@ -337,42 +347,51 @@ int16_t SX126x::directMode() { // set DIO2 to clock output and DIO3 to data input // this is done exclusively by writing magic values to even more magic registers - uint8_t val = 0; + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_ENABLED, 6, 4); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_ENABLED, 3, 0); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_DISABLED, 3, 3); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_ENABLED, 3, 3); + RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, &val, 1); + // enable TxDone interrupt + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE, RADIOLIB_SX126X_IRQ_TX_DONE); RADIOLIB_ASSERT(state); - val &= ~(0x07 << 4); - val |= (0x01 << 4); - state = writeRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, &val, 1); + + // set preamble length to the maximum to prevent SX126x from exiting Tx mode for a while + state = setPreambleLength(0xFFFF); RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, &val, 1); - RADIOLIB_ASSERT(state); - val &= ~(0x0F << 0); - val |= (0x0C << 0); - state = writeRegister(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, &val, 1); + return(state); +} + +int16_t SX126x::packetMode() { + // set mode to standby + int16_t state = standby(); RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, &val, 1); + // set preamble length to the default + state = setPreambleLength(16); RADIOLIB_ASSERT(state); - val &= ~(0x01 << 3); - val |= (0x01 << 3); - state = writeRegister(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, &val, 1); + + // disable TxDone interrupt + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, &val, 1); + // restore the magic registers + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_DISABLED, 3, 3); RADIOLIB_ASSERT(state); - val &= ~(0x01 << 3); - val |= (0x01 << 3); - state = writeRegister(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, &val, 1); + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_ENABLED, 3, 3); RADIOLIB_ASSERT(state); - - // enable TxDone interrupt - state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE, RADIOLIB_SX126X_IRQ_TX_DONE); + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_DISABLED, 3, 0); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_DISABLED, 6, 4); RADIOLIB_ASSERT(state); - // set preamble length to the maximum to prevent SX126x from exiting Tx mode for a while - state = setPreambleLength(0xFFFF); + // enable DIO2 RF switch + state = setDio2AsRfSwitch(true); RADIOLIB_ASSERT(state); return(state); @@ -1345,15 +1364,11 @@ int16_t SX126x::getLastError() { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX126x::setDirectAction(void (*func)(void)) { - // SX126x is unable to perform direct mode reception - // this method is implemented only for PhysicalLayer compatibility - (void)func; + setDio1Action(func); } void SX126x::readBit(RADIOLIB_PIN_TYPE pin) { - // SX126x is unable to perform direct mode reception - // this method is implemented only for PhysicalLayer compatibility - (void)pin; + updateDirectBuffer((uint8_t)digitalRead(pin)); } #endif @@ -1473,18 +1488,16 @@ int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMa } int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - return(SPIwriteCommand(cmd, 3, data, numBytes)); + _mod->SPIwriteRegisterBurst(addr, data, numBytes); + return(RADIOLIB_ERR_NONE); } int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { // send the command - uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - int16_t state = SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true); - RADIOLIB_ASSERT(state); + _mod->SPIreadRegisterBurst(addr, numBytes, data); // check the status - state = checkCommandResult(); + int16_t state = checkCommandResult(); return(state); } @@ -1784,7 +1797,7 @@ int16_t SX126x::checkCommandResult() { // get the status uint8_t spiStatus = 0; uint8_t cmd = RADIOLIB_SX126X_CMD_GET_STATUS; - state = SX126x::SPItransfer(&cmd, 1, false, NULL, &spiStatus, 1, true); + state = _mod->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000); RADIOLIB_ASSERT(state); // translate to RadioLib status code @@ -1812,7 +1825,7 @@ int16_t SX126x::checkCommandResult() { int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command - int16_t state = SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1825,7 +1838,7 @@ int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uin int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command - int16_t state = SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(&cmd, 1, true, data, NULL, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1838,7 +1851,7 @@ int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bo int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command - int16_t state = SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1851,7 +1864,7 @@ int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { // send the command - int16_t state = SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(&cmd, 1, false, NULL, data, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1862,147 +1875,17 @@ int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, boo return(state); } -int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { - #if defined(RADIOLIB_VERBOSE) - uint8_t debugBuff[256]; - #endif - - // pull NSS low - _mod->digitalWrite(_mod->getCs(), LOW); - - // ensure BUSY is low (state machine ready) - uint32_t start = _mod->millis(); - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); - if(_mod->millis() - start >= timeout) { - _mod->digitalWrite(_mod->getCs(), HIGH); - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); - } - } - - // start transfer - _mod->SPIbeginTransaction(); - - // send command byte(s) - for(uint8_t n = 0; n < cmdLen; n++) { - _mod->SPItransfer(cmd[n]); - } - - // variable to save error during SPI transfer - uint8_t status = 0; - - // send/receive all bytes - if(write) { - for(uint8_t n = 0; n < numBytes; n++) { - // send byte - uint8_t in = _mod->SPItransfer(dataOut[n]); - #if defined(RADIOLIB_VERBOSE) - debugBuff[n] = in; - #endif - - // check status - if(((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) || - ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) || - ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED)) { - status = in & 0b00001110; - break; - } else if(in == 0x00 || in == 0xFF) { - status = RADIOLIB_SX126X_STATUS_SPI_FAILED; - break; - } - } - - } else { - // skip the first byte for read-type commands (status-only) - uint8_t in = _mod->SPItransfer(RADIOLIB_SX126X_CMD_NOP); - #if defined(RADIOLIB_VERBOSE) - debugBuff[0] = in; - #endif - - // check status - if(((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) || - ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) || - ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED)) { - status = in & 0b00001110; - } else if(in == 0x00 || in == 0xFF) { - status = RADIOLIB_SX126X_STATUS_SPI_FAILED; - } else { - for(uint8_t n = 0; n < numBytes; n++) { - dataIn[n] = _mod->SPItransfer(RADIOLIB_SX126X_CMD_NOP); - } - } - } - - // stop transfer - _mod->SPIendTransaction(); - _mod->digitalWrite(_mod->getCs(), HIGH); - - // wait for BUSY to go high and then low - if(waitForBusy) { - _mod->delayMicroseconds(1); - start = _mod->millis(); - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); - if(_mod->millis() - start >= timeout) { - status = RADIOLIB_SX126X_STATUS_CMD_TIMEOUT; - break; - } - } - } - - // print debug output - #if defined(RADIOLIB_VERBOSE) - // print command byte(s) - RADIOLIB_VERBOSE_PRINT("CMD\t"); - for(uint8_t n = 0; n < cmdLen; n++) { - RADIOLIB_VERBOSE_PRINT(cmd[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - } - RADIOLIB_VERBOSE_PRINTLN(); - - // print data bytes - RADIOLIB_VERBOSE_PRINT("DAT"); - if(write) { - RADIOLIB_VERBOSE_PRINT("W\t"); - for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - } - RADIOLIB_VERBOSE_PRINTLN(); - } else { - RADIOLIB_VERBOSE_PRINT("R\t"); - // skip the first byte for read-type commands (status-only) - RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX126X_CMD_NOP, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); - RADIOLIB_VERBOSE_PRINT('\t') - - for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX126X_CMD_NOP, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - } - RADIOLIB_VERBOSE_PRINTLN(); - } - RADIOLIB_VERBOSE_PRINTLN(); - #endif - - // parse status - switch(status) { - case RADIOLIB_SX126X_STATUS_CMD_TIMEOUT: +int16_t SX126x::SPIparseStatus(uint8_t in) { + if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) { return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); - case RADIOLIB_SX126X_STATUS_CMD_INVALID: + } else if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) { return(RADIOLIB_ERR_SPI_CMD_INVALID); - case RADIOLIB_SX126X_STATUS_CMD_FAILED: + } else if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED) { return(RADIOLIB_ERR_SPI_CMD_FAILED); - case RADIOLIB_SX126X_STATUS_SPI_FAILED: + } else if((in == 0x00) || (in == 0xFF)) { return(RADIOLIB_ERR_CHIP_NOT_FOUND); - default: - return(RADIOLIB_ERR_NONE); } + return(RADIOLIB_ERR_NONE); } #endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 8b8bd4fb68..b41b1ba05a 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -112,6 +112,8 @@ #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C #define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC #define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 #define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 #define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 #define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 @@ -358,6 +360,29 @@ #define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. #define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. +// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 +#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled + +// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 +#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled + +// RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE +#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled +#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled +#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled +#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled + +// RADIOLIB_SX126X_REG_DIOX_IN_ENABLE +#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled +#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled +#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled +#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled /*! \class SX126x @@ -1018,6 +1043,7 @@ class SX126x: public PhysicalLayer { int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); int16_t directMode(); + int16_t packetMode(); // fixes to errata int16_t fixSensitivity(); @@ -1035,7 +1061,7 @@ class SX126x: public PhysicalLayer { int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); - int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000); + static int16_t SPIparseStatus(uint8_t in); #if !defined(RADIOLIB_GODMODE) protected: From 7d286e32bc3e38f78945b82902b3d881ebe1273b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 16:23:08 +0100 Subject: [PATCH 0371/1848] [SX128x] Use Module SPI stream --- src/modules/SX128x/SX128x.cpp | 191 +++++++--------------------------- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 41 insertions(+), 152 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 531ebd0efb..a1bb18a29d 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -14,6 +14,11 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); _mod->pinMode(_mod->getGpio(), INPUT); + _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstreamType = true; + _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize LoRa modulation variables @@ -69,6 +74,11 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); _mod->pinMode(_mod->getGpio(), INPUT); + _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstreamType = true; + _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize GFSK modulation variables @@ -132,6 +142,11 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); _mod->pinMode(_mod->getGpio(), INPUT); + _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstreamType = true; + _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize BLE modulation variables @@ -181,6 +196,11 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); _mod->pinMode(_mod->getGpio(), INPUT); + _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstreamType = true; + _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize FLRC modulation variables @@ -1278,17 +1298,16 @@ uint8_t SX128x::getStatus() { } int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - return(SPIwriteCommand(cmd, 3, data, numBytes)); + _mod->SPIwriteRegisterBurst(addr, data, numBytes); + return(RADIOLIB_ERR_NONE); } int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - int16_t state = SX128x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true); - RADIOLIB_ASSERT(state); + // send the command + _mod->SPIreadRegisterBurst(addr, numBytes, data); // check the status - state = checkCommandResult(); + int16_t state = checkCommandResult(); return(state); } @@ -1430,7 +1449,7 @@ int16_t SX128x::checkCommandResult() { // get the status uint8_t spiStatus = 0; uint8_t cmd = RADIOLIB_SX128X_CMD_GET_STATUS; - state = SX128x::SPItransfer(&cmd, 1, false, NULL, &spiStatus, 1, true); + state = _mod->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000); RADIOLIB_ASSERT(state); // translate to RadioLib status code @@ -1458,7 +1477,7 @@ int16_t SX128x::checkCommandResult() { int16_t SX128x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { // send the command - int16_t state = SX128x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1468,7 +1487,7 @@ int16_t SX128x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uin int16_t SX128x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { // send the command - int16_t state = SX128x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(&cmd, 1, true, data, NULL, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1478,7 +1497,7 @@ int16_t SX128x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bo int16_t SX128x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { // send the command - int16_t state = SX128x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1488,7 +1507,7 @@ int16_t SX128x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint int16_t SX128x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { // send the command - int16_t state = SX128x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy); + int16_t state = _mod->SPItransferStream(&cmd, 1, false, NULL, data, numBytes, waitForBusy, 5000); RADIOLIB_ASSERT(state); // check the status @@ -1496,147 +1515,17 @@ int16_t SX128x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, boo return(state); } -int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { - #if defined(RADIOLIB_VERBOSE) - uint8_t debugBuff[256]; - #endif - - // ensure BUSY is low (state machine ready) - uint32_t start = _mod->millis(); - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); - if(_mod->millis() - start >= timeout) { - _mod->digitalWrite(_mod->getCs(), HIGH); - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); - } - } - - // pull NSS low - _mod->digitalWrite(_mod->getCs(), LOW); - - // start transfer - _mod->SPIbeginTransaction(); - - // send command byte(s) - for(uint8_t n = 0; n < cmdLen; n++) { - _mod->SPItransfer(cmd[n]); - } - - // variable to save error during SPI transfer - uint8_t status = 0; - - // send/receive all bytes - if(write) { - for(uint8_t n = 0; n < numBytes; n++) { - // send byte - uint8_t in = _mod->SPItransfer(dataOut[n]); - #if defined(RADIOLIB_VERBOSE) - debugBuff[n] = in; - #endif - - // check status - if(((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) || - ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) || - ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED)) { - status = in & 0b00011100; - break; - } else if(in == 0x00 || in == 0xFF) { - status = RADIOLIB_SX128X_STATUS_SPI_FAILED; - break; - } - } - - } else { - // skip the first byte for read-type commands (status-only) - uint8_t in = _mod->SPItransfer(RADIOLIB_SX128X_CMD_NOP); - #if defined(RADIOLIB_VERBOSE) - debugBuff[0] = in; - #endif - - // check status - if(((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) || - ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) || - ((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED)) { - status = in & 0b00011100; - } else if(in == 0x00 || in == 0xFF) { - status = RADIOLIB_SX128X_STATUS_SPI_FAILED; - } else { - for(uint8_t n = 0; n < numBytes; n++) { - dataIn[n] = _mod->SPItransfer(RADIOLIB_SX128X_CMD_NOP); - } - } - } - - // stop transfer - _mod->SPIendTransaction(); - _mod->digitalWrite(_mod->getCs(), HIGH); - - // wait for BUSY to go high and then low - if(waitForBusy) { - _mod->delayMicroseconds(1); - start = _mod->millis(); - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); - if(_mod->millis() - start >= timeout) { - status = RADIOLIB_SX128X_STATUS_CMD_TIMEOUT; - break; - } - } - } - - // print debug output - #if defined(RADIOLIB_VERBOSE) - // print command byte(s) - RADIOLIB_VERBOSE_PRINT("CMD\t"); - for(uint8_t n = 0; n < cmdLen; n++) { - RADIOLIB_VERBOSE_PRINT(cmd[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - } - RADIOLIB_VERBOSE_PRINTLN(); - - // print data bytes - RADIOLIB_VERBOSE_PRINT("DAT"); - if(write) { - RADIOLIB_VERBOSE_PRINT("W\t"); - for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - } - RADIOLIB_VERBOSE_PRINTLN(); - } else { - RADIOLIB_VERBOSE_PRINT("R\t"); - // skip the first byte for read-type commands (status-only) - RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX128X_CMD_NOP, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); - RADIOLIB_VERBOSE_PRINT('\t') - - for(uint8_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX128X_CMD_NOP, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - } - RADIOLIB_VERBOSE_PRINTLN(); - } - RADIOLIB_VERBOSE_PRINTLN(); - #endif - - // parse status - switch(status) { - case RADIOLIB_SX128X_STATUS_CMD_TIMEOUT: - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); - case RADIOLIB_SX128X_STATUS_CMD_ERROR: - return(RADIOLIB_ERR_SPI_CMD_INVALID); - case RADIOLIB_SX128X_STATUS_CMD_FAILED: - return(RADIOLIB_ERR_SPI_CMD_FAILED); - case RADIOLIB_SX128X_STATUS_SPI_FAILED: - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - default: - return(RADIOLIB_ERR_NONE); +int16_t SX128x::SPIparseStatus(uint8_t in) { + if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) { + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } else if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_ERROR) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } else if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_FAILED) { + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } else if((in == 0x00) || (in == 0xFF)) { + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } + return(RADIOLIB_ERR_NONE); } #endif diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 98bd725214..b6f26ca622 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -892,7 +892,7 @@ class SX128x: public PhysicalLayer { int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000); + static int16_t SPIparseStatus(uint8_t in); #if !defined(RADIOLIB_GODMODE) private: From 6bf9cebc43ba711a06c2e9f4feec24a3716a8ea9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 16:59:03 +0100 Subject: [PATCH 0372/1848] [MOD] Added SPI stream read/write --- src/Module.cpp | 54 +++++++++++++++++++++++++++++ src/Module.h | 93 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 8984730c80..b0ba3bc5dc 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -279,6 +279,60 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->SPIendTransaction(); } +int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { + return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify)); +} + +int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { + // send the command + int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, 5000); + RADIOLIB_ASSERT(state); + + // check the status + if(verify) { + state = this->SPIcheckStream(); + } + + return(state); +} + +int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { + return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify)); +} + +int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { + // send the command + int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, 5000); + RADIOLIB_ASSERT(state); + + // check the status + if(verify) { + state = this->SPIcheckStream(); + } + + return(state); +} + +int16_t Module::SPIcheckStream() { + int16_t state = RADIOLIB_ERR_NONE; + + #if defined(RADIOLIB_SPI_PARANOID) + // get the status + uint8_t spiStatus = 0; + uint8_t cmd = this->SPIstatusCommand; + state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000); + RADIOLIB_ASSERT(state); + + // translate to RadioLib status code + if(this->SPIparseStatusCb != nullptr) { + this->SPIstreamError = this->SPIparseStatusCb(spiStatus); + } + + #endif + + return(state); +} + int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForGpio, uint32_t timeout) { #if defined(RADIOLIB_VERBOSE) uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; diff --git a/src/Module.h b/src/Module.h index 4bf4e48112..e092aedbe3 100644 --- a/src/Module.h +++ b/src/Module.h @@ -140,10 +140,15 @@ class Module { uint8_t SPIwriteCommand = 0b10000000; /*! - \brief Basic SPI no-operation command. Defaults to 0x80. + \brief Basic SPI no-operation command. Defaults to 0x00. */ uint8_t SPInopCommand = 0x00; + /*! + \brief Basic SPI status read command. Defaults to 0x00. + */ + uint8_t SPIstatusCommand = 0x00; + /*! \brief SPI address width. Defaults to 8, currently only supports 8 and 16-bit addresses. */ @@ -155,6 +160,11 @@ class Module { */ bool SPIstreamType = false; + /*! + \brief The last recorded SPI stream error. + */ + int16_t SPIstreamError = RADIOLIB_ERR_UNKNOWN; + /*! \brief SPI status parsing callback typedef. */ @@ -285,13 +295,92 @@ class Module { \param numBytes Number of bytes to transfer. */ void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + + /*! + \brief Method to check the result of last SPI stream transfer. + + \returns \ref status_codes + */ + int16_t SPIcheckStream(); + + /*! + \brief Method to perform a read transaction with SPI stream. + + \param cmd SPI operation command. + + \param data Data that will be transferred from slave to master. + + \param numBytes Number of bytes to transfer. + + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + + \param verify Whether to verify the result of the transaction after it is finished. + + \returns \ref status_codes + */ + int16_t SPIreadStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief Method to perform a read transaction with SPI stream. + + \param cmd SPI operation command. + + \param cmdLen SPI command length in bytes. + + \param data Data that will be transferred from slave to master. + + \param numBytes Number of bytes to transfer. + + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + + \param verify Whether to verify the result of the transaction after it is finished. + + \returns \ref status_codes + */ + int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief Method to perform a write transaction with SPI stream. + + \param cmd SPI operation command. + + \param data Data that will be transferred from master to slave. + + \param numBytes Number of bytes to transfer. + + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + + \param verify Whether to verify the result of the transaction after it is finished. + + \returns \ref status_codes + */ + int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + + /*! + \brief Method to perform a write transaction with SPI stream. + + \param cmd SPI operation command. + + \param cmdLen SPI command length in bytes. + + \param data Data that will be transferred from master to slave. + + \param numBytes Number of bytes to transfer. + + \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). + + \param verify Whether to verify the result of the transaction after it is finished. + + \returns \ref status_codes + */ + int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). \param cmd SPI operation command. - \param cmd SPI command length in bytes. + \param cmdLen SPI command length in bytes. \param write Set to true for write commands, false for read commands. From 95083e32b1539ff02d8bfc37f77430f65cb7e9fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 17:02:51 +0100 Subject: [PATCH 0373/1848] [SX126x] Use module stream read/write --- src/modules/SX126x/SX126x.cpp | 169 ++++++++-------------------------- src/modules/SX126x/SX126x.h | 14 --- 2 files changed, 38 insertions(+), 145 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index b0eaaae3a7..2942c6a8a8 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -17,6 +17,7 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + _mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); @@ -88,6 +89,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + _mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); @@ -419,7 +421,7 @@ int16_t SX126x::sleep(bool retainConfig) { if(!retainConfig) { sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; } - int16_t state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); + int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); // wait for SX126x to safely enter sleep mode _mod->delay(1); @@ -436,7 +438,7 @@ int16_t SX126x::standby(uint8_t mode) { _mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = {mode}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } void SX126x::setDio1Action(void (*func)(void)) { @@ -553,7 +555,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) { uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), (uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); } int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols) { @@ -853,9 +855,6 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0)); // check modulation parameters - /*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) { - return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); - }*/ _freqDev = freqDevRaw; // update modulation parameters @@ -874,9 +873,6 @@ int16_t SX126x::setBitRate(float br) { uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); // check modulation parameters - /*if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) { - return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); - }*/ _br = brRaw; // update modulation parameters @@ -1234,7 +1230,7 @@ float SX126x::getSNR() { size_t SX126x::getPacketLength(bool update) { (void)update; uint8_t rxBufStatus[2] = {0, 0}; - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } @@ -1283,7 +1279,7 @@ uint32_t SX126x::getTimeOnAir(size_t len) { float SX126x::getRSSIInst() { uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); return (float)data[0] / (-2.0); } @@ -1358,10 +1354,6 @@ uint8_t SX126x::randomByte() { return(randByte); } -int16_t SX126x::getLastError() { - return(_lastError); -} - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); @@ -1417,7 +1409,7 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { _tcxoDelay = delay; // enable TCXO control on DIO3 - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); } int16_t SX126x::setDio2AsRfSwitch(bool enable) { @@ -1427,17 +1419,17 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { } else { data = RADIOLIB_SX126X_DIO2_AS_IRQ; } - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } int16_t SX126x::setTx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); } int16_t SX126x::setRx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { @@ -1475,16 +1467,16 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { } // configure paramaters - int16_t state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); // start CAD - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); } int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); } int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { @@ -1497,18 +1489,18 @@ int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { _mod->SPIreadRegisterBurst(addr, numBytes, data); // check the status - int16_t state = checkCommandResult(); + int16_t state = _mod->SPIcheckStream(); return(state); } int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; - return(SPIwriteCommand(cmd, 2, data, numBytes)); + return(_mod->SPIwriteStream(cmd, 2, data, numBytes)); } int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) { uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, RADIOLIB_SX126X_CMD_NOP }; - return(SPIreadCommand(cmd, 2, data, numBytes)); + return(_mod->SPIreadStream(cmd, 2, data, numBytes)); } int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { @@ -1516,38 +1508,38 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } uint16_t SX126x::getIrqStatus() { uint8_t data[] = { 0x00, 0x00 }; - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX126x::setRfFrequency(uint32_t frf) { uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } int16_t SX126x::calibrateImage(uint8_t* data) { - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2)); } uint8_t SX126x::getPacketType() { uint8_t data = 0xFF; - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); return(data); } int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) { uint8_t data[] = { power, rampTime }; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { @@ -1600,62 +1592,62 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 uint8_t data[4] = {sf, bw, cr, _ldro}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); } int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), pulseShape, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); } int16_t SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) { int16_t state = fixInvertedIQ(invertIQ); RADIOLIB_ASSERT(state); uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); } int16_t SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType, uint8_t payloadLength, uint8_t preambleDetectorLength) { uint8_t data[9] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), preambleDetectorLength, syncWordLength, addrComp, packetType, payloadLength, crcType, whitening}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); } int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { uint8_t data[2] = {txBaseAddress, rxBaseAddress}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX126x::setRegulatorMode(uint8_t mode) { uint8_t data[1] = {mode}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); } uint8_t SX126x::getStatus() { uint8_t data = 0; - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1); return(data); } uint32_t SX126x::getPacketStatus() { uint8_t data[3] = {0, 0, 0}; - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]); } uint16_t SX126x::getDeviceErrors() { uint8_t data[2] = {0, 0}; - SPIreadCommand(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) & ((uint16_t)data[1]); return(opError); } int16_t SX126x::clearDeviceErrors() { uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); } int16_t SX126x::setFrequencyRaw(float freq) { @@ -1752,12 +1744,12 @@ int16_t SX126x::config(uint8_t modem) { // set modem uint8_t data[7]; data[0] = modem; - state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); + state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); RADIOLIB_ASSERT(state); // set Rx/Tx fallback mode to STDBY_RC data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; - state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); + state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); // set some CAD parameters - will be overwritten whel calling CAD anyway @@ -1768,7 +1760,7 @@ int16_t SX126x::config(uint8_t modem) { data[4] = 0x00; data[5] = 0x00; data[6] = 0x00; - state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); // clear IRQ @@ -1778,7 +1770,7 @@ int16_t SX126x::config(uint8_t modem) { // calibrate all blocks data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; - state = SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); + state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); RADIOLIB_ASSERT(state); // wait for calibration completion @@ -1790,91 +1782,6 @@ int16_t SX126x::config(uint8_t modem) { return(RADIOLIB_ERR_NONE); } -int16_t SX126x::checkCommandResult() { - int16_t state = RADIOLIB_ERR_NONE; - - #if defined(RADIOLIB_SPI_PARANOID) - // get the status - uint8_t spiStatus = 0; - uint8_t cmd = RADIOLIB_SX126X_CMD_GET_STATUS; - state = _mod->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000); - RADIOLIB_ASSERT(state); - - // translate to RadioLib status code - switch(spiStatus) { - case RADIOLIB_SX126X_STATUS_CMD_TIMEOUT: - _lastError = RADIOLIB_ERR_SPI_CMD_TIMEOUT; - break; - case RADIOLIB_SX126X_STATUS_CMD_INVALID: - _lastError = RADIOLIB_ERR_SPI_CMD_INVALID; - break; - case RADIOLIB_SX126X_STATUS_CMD_FAILED: - _lastError = RADIOLIB_ERR_SPI_CMD_FAILED; - break; - case RADIOLIB_SX126X_STATUS_SPI_FAILED: - _lastError = RADIOLIB_ERR_CHIP_NOT_FOUND; - break; - default: - _lastError = RADIOLIB_ERR_NONE; - } - - #endif - - return(state); -} - -int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { - // send the command - int16_t state = _mod->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - if(verify) { - state = checkCommandResult(); - } - - return(state); -} - -int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { - // send the command - int16_t state = _mod->SPItransferStream(&cmd, 1, true, data, NULL, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - if(verify) { - state = checkCommandResult(); - } - - return(state); -} - -int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { - // send the command - int16_t state = _mod->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - if(verify) { - state = checkCommandResult(); - } - - return(state); -} - -int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy, bool verify) { - // send the command - int16_t state = _mod->SPItransferStream(&cmd, 1, false, NULL, data, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - if(verify) { - state = checkCommandResult(); - } - - return(state); -} - int16_t SX126x::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) { return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index b41b1ba05a..d92641788f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -985,13 +985,6 @@ class SX126x: public PhysicalLayer { */ uint8_t randomByte(); - /*! - \brief Get the last recorded transaction error. - - \returns \ref status_codes - */ - int16_t getLastError(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -1057,10 +1050,6 @@ class SX126x: public PhysicalLayer { Module* _mod; // common low-level SPI interface - int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); - int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); - int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); - int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true, bool verify = true); static int16_t SPIparseStatus(uint8_t in); #if !defined(RADIOLIB_GODMODE) @@ -1083,13 +1072,10 @@ class SX126x: public PhysicalLayer { size_t _implicitLen = 0; - int16_t _lastError = RADIOLIB_ERR_NONE; - // Allow subclasses to define different TX modes uint8_t _tx_mode = Module::MODE_TX; int16_t config(uint8_t modem); - int16_t checkCommandResult(); }; #endif From 60bd3d64402fc29b43f520a56c68d6789ffdc9a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 17:07:00 +0100 Subject: [PATCH 0374/1848] [SX128x] Use Module stream read/write --- src/modules/SX128x/SX128x.cpp | 139 ++++++++-------------------------- src/modules/SX128x/SX128x.h | 14 ---- 2 files changed, 33 insertions(+), 120 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a1bb18a29d..3a852300bd 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -17,6 +17,7 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); @@ -77,6 +78,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); @@ -145,6 +147,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); @@ -199,6 +202,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); @@ -378,7 +382,7 @@ int16_t SX128x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); } int16_t SX128x::receiveDirect() { @@ -442,7 +446,7 @@ int16_t SX128x::sleep(bool retainConfig) { if(!retainConfig) { sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; } - int16_t state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); + int16_t state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); // wait for SX128x to safely enter sleep mode _mod->delay(1); @@ -459,7 +463,7 @@ int16_t SX128x::standby(uint8_t mode) { _mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = { mode }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); } void SX128x::setDio1Action(void (*func)(void)) { @@ -1102,7 +1106,7 @@ int16_t SX128x::setGainControl(uint8_t gain) { float SX128x::getRSSI() { // get packet status uint8_t packetStatus[5]; - SPIreadCommand(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); // check active modem uint8_t modem = getPacketType(); @@ -1132,7 +1136,7 @@ float SX128x::getSNR() { // get packet status uint8_t packetStatus[5]; - SPIreadCommand(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); // calculate real SNR uint8_t snr = packetStatus[1]; @@ -1179,7 +1183,7 @@ float SX128x::getFrequencyError() { size_t SX128x::getPacketLength(bool update) { (void)update; uint8_t rxBufStatus[2] = {0, 0}; - SPIreadCommand(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } @@ -1273,10 +1277,6 @@ uint8_t SX128x::randomByte() { return(0); } -int16_t SX128x::getLastError() { - return(_lastError); -} - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX128x::setDirectAction(void (*func)(void)) { // SX128x is unable to perform direct mode reception @@ -1293,7 +1293,7 @@ void SX128x::readBit(RADIOLIB_PIN_TYPE pin) { uint8_t SX128x::getStatus() { uint8_t data = 0; - SPIreadCommand(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 1); + _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 1); return(data); } @@ -1307,73 +1307,73 @@ int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { _mod->SPIreadRegisterBurst(addr, numBytes, data); // check the status - int16_t state = checkCommandResult(); + int16_t state = _mod->SPIcheckStream(); return(state); } int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset }; - return(SPIwriteCommand(cmd, 2, data, numBytes)); + return(_mod->SPIwriteStream(cmd, 2, data, numBytes)); } int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes) { uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, RADIOLIB_SX128X_CMD_NOP }; - return(SPIreadCommand(cmd, 2, data, numBytes)); + return(_mod->SPIreadStream(cmd, 2, data, numBytes)); } int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) { uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); } int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); } int16_t SX128x::setCad() { - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); } uint8_t SX128x::getPacketType() { uint8_t data = 0xFF; - SPIreadCommand(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1); + _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1); return(data); } int16_t SX128x::setRfFrequency(uint32_t frf) { uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); } int16_t SX128x::setTxParams(uint8_t power, uint8_t rampTime) { uint8_t data[] = { power, rampTime }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { uint8_t data[] = { txBaseAddress, rxBaseAddress }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { uint8_t data[] = { modParam1, modParam2, modParam3 }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); } int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen, uint8_t headerType) { uint8_t data[] = { preambleLen, syncWordLen, syncWordMatch, headerType, payloadLen, crcLen, whitening }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening) { uint8_t data[] = { connState, crcLen, bleTestPayload, whitening, 0x00, 0x00, 0x00 }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ) { uint8_t data[] = { preambleLen, headerType, payloadLen, crc, invertIQ, 0x00, 0x00 }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { @@ -1381,28 +1381,28 @@ int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } uint16_t SX128x::getIrqStatus() { uint8_t data[] = { 0x00, 0x00 }; - SPIreadCommand(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2); + _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX128x::setRangingRole(uint8_t role) { uint8_t data[] = { role }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); } int16_t SX128x::setPacketType(uint8_t type) { uint8_t data[] = { type }; - return(SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); } int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { @@ -1426,95 +1426,22 @@ int16_t SX128x::config(uint8_t modem) { // set modem uint8_t data[1]; data[0] = modem; - state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1); + state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1); RADIOLIB_ASSERT(state); // set CAD parameters data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB; - state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1); + state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1); RADIOLIB_ASSERT(state); // set regulator mode to DC-DC data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC; - state = SPIwriteCommand(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1); + state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1); RADIOLIB_ASSERT(state); return(RADIOLIB_ERR_NONE); } -int16_t SX128x::checkCommandResult() { - int16_t state = RADIOLIB_ERR_NONE; - - #if defined(RADIOLIB_SPI_PARANOID) - // get the status - uint8_t spiStatus = 0; - uint8_t cmd = RADIOLIB_SX128X_CMD_GET_STATUS; - state = _mod->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000); - RADIOLIB_ASSERT(state); - - // translate to RadioLib status code - switch(spiStatus) { - case RADIOLIB_SX128X_STATUS_CMD_TIMEOUT: - _lastError = RADIOLIB_ERR_SPI_CMD_TIMEOUT; - break; - case RADIOLIB_SX128X_STATUS_CMD_ERROR: - _lastError = RADIOLIB_ERR_SPI_CMD_INVALID; - break; - case RADIOLIB_SX128X_STATUS_CMD_FAILED: - _lastError = RADIOLIB_ERR_SPI_CMD_FAILED; - break; - case RADIOLIB_SX128X_STATUS_SPI_FAILED: - _lastError = RADIOLIB_ERR_CHIP_NOT_FOUND; - break; - default: - _lastError = RADIOLIB_ERR_NONE; - } - - #endif - - return(state); -} - -int16_t SX128x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - // send the command - int16_t state = _mod->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - state = checkCommandResult(); - return(state); -} - -int16_t SX128x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - // send the command - int16_t state = _mod->SPItransferStream(&cmd, 1, true, data, NULL, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - state = checkCommandResult(); - return(state); -} - -int16_t SX128x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - // send the command - int16_t state = _mod->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - state = checkCommandResult(); - return(state); -} - -int16_t SX128x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { - // send the command - int16_t state = _mod->SPItransferStream(&cmd, 1, false, NULL, data, numBytes, waitForBusy, 5000); - RADIOLIB_ASSERT(state); - - // check the status - state = checkCommandResult(); - return(state); -} - int16_t SX128x::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) { return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index b6f26ca622..271c321f2a 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -822,13 +822,6 @@ class SX128x: public PhysicalLayer { */ uint8_t randomByte(); - /*! - \brief Get the last recorded transaction error. - - \returns \ref status_codes - */ - int16_t getLastError(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. @@ -888,10 +881,6 @@ class SX128x: public PhysicalLayer { #endif // common low-level SPI interface - int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); - int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); static int16_t SPIparseStatus(uint8_t in); #if !defined(RADIOLIB_GODMODE) @@ -912,10 +901,7 @@ class SX128x: public PhysicalLayer { // cached BLE parameters uint8_t _connectionState = 0, _crcBLE = 0, _bleTestPayload = 0; - int16_t _lastError = RADIOLIB_ERR_NONE; - int16_t config(uint8_t modem); - int16_t checkCommandResult(); }; #endif From 02d6062f094a43781545d3eb4024c36f963c4266 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 17:11:36 +0100 Subject: [PATCH 0375/1848] [SX126x] Fixed forgotten SPI write command --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2942c6a8a8..e6e0807dcd 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -322,7 +322,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) { // start transmitting uint8_t data[] = {RADIOLIB_SX126X_CMD_NOP}; - return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); } int16_t SX126x::receiveDirect() { From d8c50ae8ad2f40f7d7d20665e6f978395aef54fd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 17:12:05 +0100 Subject: [PATCH 0376/1848] [MOD] Remove default arguments from implementations --- src/Module.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index b0ba3bc5dc..594fe89e5a 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -279,11 +279,11 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->SPIendTransaction(); } -int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { +int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify)); } -int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { +int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { // send the command int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, 5000); RADIOLIB_ASSERT(state); @@ -296,11 +296,11 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8 return(state); } -int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { +int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify)); } -int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true) { +int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { // send the command int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, 5000); RADIOLIB_ASSERT(state); From 2b2dc2925fd6f80e921ccca35a4582120d2e20ef Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Feb 2023 17:14:31 +0100 Subject: [PATCH 0377/1848] [PHY] Fixed unused variable warning --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 48704beeba..e62edf7305 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -115,6 +115,7 @@ int16_t PhysicalLayer::standby() { } int16_t PhysicalLayer::standby(uint8_t mode) { + (void)mode; return(RADIOLIB_ERR_UNSUPPORTED); } From 547a522826eb299ec0329cfd03ad76833d5ba115 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Feb 2023 13:14:11 +0100 Subject: [PATCH 0378/1848] [SX126x] Added undocumented registers --- src/modules/SX126x/SX126x.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d92641788f..72bce81c77 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -68,8 +68,11 @@ #define RADIOLIB_SX126X_CMD_GET_STATS 0x10 #define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 +#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 +#define RADIOLIB_SX126X_CMD_SET_SCAN_PARAMS 0x9A // SX126X register map +#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 #define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 #define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 #define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 @@ -79,11 +82,13 @@ #define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) #define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) #define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 #define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 #define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 #define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 #define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 #define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 +#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 #define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 @@ -102,14 +107,24 @@ #define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 #define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD #define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 +#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 #define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 +#define RADIOLIB_SX126X_REG_FREQ_ERROR 0x076B +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD #define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C +#define RADIOLIB_SX126X_REG_TX_MODULATION 0x0889 +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E +#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B #define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC #define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 #define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 @@ -120,6 +135,7 @@ #define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 #define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 #define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 +#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 // undocumented registers #define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 @@ -384,6 +400,21 @@ #define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled #define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled +// RADIOLIB_SX126X_REG_RX_GAIN +#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted +#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving +#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan + +// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE +#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00010000 // 4 4 patch update: disabled +#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00000000 // 4 4 enabled + +// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS +#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted +#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed + /*! \class SX126x From bd258380c84185f44a1ec4db8d1e2fedaead1e09 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Feb 2023 13:16:21 +0100 Subject: [PATCH 0379/1848] [SX126x] Implemeted device type string check --- src/modules/SX126x/SX1261.cpp | 2 +- src/modules/SX126x/SX1261.h | 3 ++ src/modules/SX126x/SX1262.cpp | 14 ++++++++- src/modules/SX126x/SX1262.h | 9 ++++-- src/modules/SX126x/SX1268.cpp | 2 +- src/modules/SX126x/SX1268.h | 3 ++ src/modules/SX126x/SX126x.cpp | 53 +++++++++++++++++++++++++++++++++-- src/modules/SX126x/SX126x.h | 2 ++ 8 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index b3424f6fc2..41237b67d5 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX1261::SX1261(Module* mod): SX1262(mod) { - + _chipType = RADIOLIB_SX1261_CHIP_TYPE; } int16_t SX1261::setOutputPower(int8_t power) { diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 1dcd6d1980..195b4327ed 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -12,6 +12,9 @@ //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01 +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_SX1261_CHIP_TYPE 1 + /*! \class SX1261 diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index a667525e50..e5ca31df88 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX1262::SX1262(Module* mod) : SX126x(mod) { - + _chipType = RADIOLIB_SX1262_CHIP_TYPE; } int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { @@ -47,6 +47,18 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1262::beginLRFHSS(float freq, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginLRFHSS(tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX1262::setFrequency(float freq) { return(setFrequency(freq, true)); } diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index dbe6c1d203..491aa0b89d 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -11,6 +11,9 @@ //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_SX1262 0x00 +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_SX1262_CHIP_TYPE 2 + /*! \class SX1262 @@ -50,7 +53,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. @@ -73,8 +76,10 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 0, bool useRegulatorLDO = false); + int16_t beginLRFHSS(float freq = 434.0, float tcxoVoltage = 0, bool useRegulatorLDO = false); + // configuration methods /*! diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 30592bd6bd..db60aef9c2 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX1268::SX1268(Module* mod) : SX126x(mod) { - + _chipType = RADIOLIB_SX1268_CHIP_TYPE; } int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 2d4b90d9e8..d8dc0867e9 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -11,6 +11,9 @@ //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_SX1268 0x00 +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_SX1268_CHIP_TYPE 8 + /*! \class SX1268 diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e6e0807dcd..e1c9f5e1c5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -20,6 +20,13 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo _mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; + + // try to find the SX126x chip + if(!SX126x::findChip(_chipType)) { + RADIOLIB_DEBUG_PRINTLN(F("No SX126x found!")); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams @@ -92,6 +99,13 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL _mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; + + // try to find the SX126x chip + if(!SX126x::findChip(_chipType)) { + RADIOLIB_DEBUG_PRINTLN(F("No SX126x found!")); + _mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // initialize configuration variables (will be overwritten during public settings configuration) @@ -950,9 +964,9 @@ int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { // gain mode register value (SX1261/2 datasheet v2.1 section 9.6) if(rxbgm) { - rxGain = 0x96; // Rx Boosted Gain + rxGain = RADIOLIB_SX126X_RX_GAIN_BOOSTED; } else { - rxGain = 0x94; // Rx Power Saving Gain + rxGain = RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; } // update RX gain setting register @@ -1795,4 +1809,39 @@ int16_t SX126x::SPIparseStatus(uint8_t in) { return(RADIOLIB_ERR_NONE); } +bool SX126x::findChip(uint8_t ver) { + uint8_t i = 0; + bool flagFound = false; + char versionBuff[16]; + sprintf(versionBuff, "SX126%d", ver); + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // read the version string + char version[16]; + _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version); + + // check version register + if(strncmp(versionBuff, version, 6) == 0) { + RADIOLIB_DEBUG_PRINTLN(F("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:")); + _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_PRINTLN(); + flagFound = true; + } else { + #if defined(RADIOLIB_DEBUG) + RADIOLIB_DEBUG_PRINT(F("SX126x not found! (")); + RADIOLIB_DEBUG_PRINT(i + 1); + RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:")); + _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_PRINTLN(); + #endif + _mod->delay(10); + i++; + } + } + + return(flagFound); +} + #endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 72bce81c77..ceec1b21a3 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1102,11 +1102,13 @@ class SX126x: public PhysicalLayer { uint32_t _tcxoDelay = 0; size_t _implicitLen = 0; + uint8_t _chipType = 0; // Allow subclasses to define different TX modes uint8_t _tx_mode = Module::MODE_TX; int16_t config(uint8_t modem); + bool findChip(uint8_t type); }; #endif From b014a1f748a3aa9771423e29afc9e1f6d9581770 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Feb 2023 13:20:30 +0100 Subject: [PATCH 0380/1848] [MOD] Improved regdump and hexdump --- src/Module.cpp | 50 +++++++++++++++++++++++++++++++------------------- src/Module.h | 24 ++++++++++++++---------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 594fe89e5a..37266faf2b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -188,7 +188,7 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t #endif } -void Module::SPIreadRegisterBurst(uint16_t reg, uint8_t numBytes, uint8_t* inBytes) { +void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes) { if(!SPIstreamType) { SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); } else { @@ -208,7 +208,7 @@ uint8_t Module::SPIreadRegister(uint16_t reg) { return(resp); } -void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, uint8_t numBytes) { +void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) { if(!SPIstreamType) { SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); } else { @@ -226,7 +226,7 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { } } -void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { +void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { // start SPI transaction this->SPIbeginTransaction(); @@ -279,11 +279,11 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->SPIendTransaction(); } -int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify)); } -int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, 5000); RADIOLIB_ASSERT(state); @@ -296,11 +296,11 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8 return(state); } -int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify)); } -int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, 5000); RADIOLIB_ASSERT(state); @@ -333,7 +333,7 @@ int16_t Module::SPIcheckStream() { return(state); } -int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForGpio, uint32_t timeout) { +int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) { #if defined(RADIOLIB_VERBOSE) uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #endif @@ -364,7 +364,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // send/receive all bytes if(write) { - for(uint8_t n = 0; n < numBytes; n++) { + for(size_t n = 0; n < numBytes; n++) { // send byte uint8_t in = this->SPItransfer(dataOut[n]); #if defined(RADIOLIB_VERBOSE) @@ -393,7 +393,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // read the data if(state == RADIOLIB_ERR_NONE) { - for(uint8_t n = 0; n < numBytes; n++) { + for(size_t n = 0; n < numBytes; n++) { dataIn[n] = this->SPItransfer(this->SPInopCommand); } } @@ -430,7 +430,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint RADIOLIB_VERBOSE_PRINT("DAT"); if(write) { RADIOLIB_VERBOSE_PRINT("W\t"); - for(uint8_t n = 0; n < numBytes; n++) { + for(size_t n = 0; n < numBytes; n++) { RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX); @@ -445,7 +445,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); RADIOLIB_VERBOSE_PRINT('\t') - for(uint8_t n = 0; n < numBytes; n++) { + for(size_t n = 0; n < numBytes; n++) { RADIOLIB_VERBOSE_PRINT(this->SPInopCommand, HEX); RADIOLIB_VERBOSE_PRINT('\t'); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); @@ -713,17 +713,29 @@ uint16_t Module::flipBits16(uint16_t i) { return i; } -void Module::hexdump(uint8_t* data, size_t len) { +void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; - for(size_t i = 0; i < len; i+=16) { + for(int32_t i = 0; i < len; i+=16) { char str[80]; - sprintf(str, "%07x ", i); + sprintf(str, "%07x ", i+offset); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; } - for(size_t j = 0; j < line_len; j++) { - sprintf(&str[8 + j*3], "%02x ", data[i+j]); + for(int32_t j = 0; j < line_len; j+=width) { + if(width > 1) { + int m = 0; + int step = width/2; + if(be) { + step *= -1; + } + for(int32_t k = width - 1; k >= -width + 1; k+=step) { + sprintf(&str[8 + (j+m)*3], "%02x ", data[i+j+k+m]); + m++; + } + } else { + sprintf(&str[8 + (j)*3], "%02x ", data[i+j]); + } } for(size_t j = line_len; j < 16; j++) { sprintf(&str[8 + j*3], " "); @@ -745,14 +757,14 @@ void Module::hexdump(uint8_t* data, size_t len) { } } -void Module::regdump(uint8_t start, uint8_t len) { +void Module::regdump(uint16_t start, size_t len) { #if defined(RADIOLIB_STATIC_ONLY) uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* buff = new uint8_t[len]; #endif SPIreadRegisterBurst(start, len, buff); - hexdump(buff, len); + hexdump(buff, len, start); #if !defined(RADIOLIB_STATIC_ONLY) delete[] buff; #endif diff --git a/src/Module.h b/src/Module.h index e092aedbe3..89006acd06 100644 --- a/src/Module.h +++ b/src/Module.h @@ -250,7 +250,7 @@ class Module { \param inBytes Pointer to array that will hold the read data. */ - void SPIreadRegisterBurst(uint16_t reg, uint8_t numBytes, uint8_t* inBytes); + void SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes); /*! \brief SPI basic read method. Use of this method is reserved for special cases, SPIgetRegValue should be used instead. @@ -270,7 +270,7 @@ class Module { \param numBytes Number of bytes that will be written. */ - void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, uint8_t numBytes); + void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes); /*! \brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead. @@ -294,7 +294,7 @@ class Module { \param numBytes Number of bytes to transfer. */ - void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); /*! \brief Method to check the result of last SPI stream transfer. @@ -318,7 +318,7 @@ class Module { \returns \ref status_codes */ - int16_t SPIreadStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a read transaction with SPI stream. @@ -337,7 +337,7 @@ class Module { \returns \ref status_codes */ - int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. @@ -354,7 +354,7 @@ class Module { \returns \ref status_codes */ - int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. @@ -373,7 +373,7 @@ class Module { \returns \ref status_codes */ - int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). @@ -396,7 +396,7 @@ class Module { \returns \ref status_codes */ - int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForGpio, uint32_t timeout); + int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout); // pin number access methods @@ -684,8 +684,12 @@ class Module { \param data Data to dump. \param len Number of bytes to dump. + + \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). + + \param be Print multi-byte data as big endian. Defaults to false. */ - static void hexdump(uint8_t* data, size_t len); + static void hexdump(uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); /*! \brief Function to dump device registers as hex into the debug port. @@ -694,7 +698,7 @@ class Module { \param len Number of bytes to dump. */ - void regdump(uint8_t start, uint8_t len); + void regdump(uint16_t start, size_t len); #if !defined(RADIOLIB_GODMODE) private: From 3596f0f55bc2e2c85f3fb1e702faf1892364401e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Feb 2023 13:25:16 +0100 Subject: [PATCH 0381/1848] [SX126x] Removed WIP FHSS method --- src/modules/SX126x/SX1262.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index e5ca31df88..4cd8b9a9b5 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -47,18 +47,6 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } -int16_t SX1262::beginLRFHSS(float freq, float tcxoVoltage, bool useRegulatorLDO) { - // execute common part - int16_t state = SX126x::beginLRFHSS(tcxoVoltage, useRegulatorLDO); - RADIOLIB_ASSERT(state); - - // configure publicly accessible settings - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - return(state); -} - int16_t SX1262::setFrequency(float freq) { return(setFrequency(freq, true)); } From 32a42ee2c67ec987b115e82a285788b62bc6ecf5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Feb 2023 13:28:52 +0100 Subject: [PATCH 0382/1848] [MOD] Fixed format type --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 37266faf2b..27e9471faf 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -717,7 +717,7 @@ void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, size_t rem_len = len; for(int32_t i = 0; i < len; i+=16) { char str[80]; - sprintf(str, "%07x ", i+offset); + sprintf(str, "%07lx ", i+offset); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; From 00998b5185814b7678e181edf3d8011aeda88d42 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Feb 2023 13:47:54 +0100 Subject: [PATCH 0383/1848] [MOD] Fixed incorrect default TCXO voltage --- src/modules/SX126x/SX1262.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 491aa0b89d..108701b7a7 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -53,7 +53,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. @@ -76,7 +76,7 @@ class SX1262: public SX126x { \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 0, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); int16_t beginLRFHSS(float freq = 434.0, float tcxoVoltage = 0, bool useRegulatorLDO = false); From f59bf4750c7b086d16d288a3539ece9f99080739 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 26 Feb 2023 13:33:30 +0100 Subject: [PATCH 0384/1848] [SX126x] Add irqFlags and irqMask parameters to receive methods --- src/modules/SX126x/SX126x.cpp | 23 +++++++++++------------ src/modules/SX126x/SX126x.h | 21 +++++++++++++++++---- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e1c9f5e1c5..1e4e669866 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -532,8 +532,8 @@ int16_t SX126x::finishTransmit() { return(standby()); } -int16_t SX126x::startReceive(uint32_t timeout) { - int16_t state = startReceiveCommon(timeout); +int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { + int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); RADIOLIB_ASSERT(state); // set RF switch (if present) @@ -545,7 +545,7 @@ int16_t SX126x::startReceive(uint32_t timeout) { return(state); } -int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) { +int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags, uint16_t irqMask) { // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay uint32_t transitionTime = _tcxoDelay + 1000; sleepPeriod -= transitionTime; @@ -564,7 +564,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) { return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD); } - int16_t state = startReceiveCommon(); + int16_t state = startReceiveCommon(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask); RADIOLIB_ASSERT(state); uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), @@ -572,7 +572,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) { return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); } -int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols) { +int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, uint16_t irqFlags, uint16_t irqMask) { if(senderPreambleLength == 0) { senderPreambleLength = _preambleLength; } @@ -584,7 +584,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ // if we're not to sleep at all, just use the standard startReceive. if(2 * minSymbols > senderPreambleLength) { - return(startReceive()); + return(startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask)); } uint32_t symbolLength = ((uint32_t)(10 * 1000) << _sf) / (10 * _bwKhz); @@ -606,19 +606,18 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < _tcxoDelay + 1016) { - return(startReceive()); + return(startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask)); } - return(startReceiveDutyCycle(wakePeriod, sleepPeriod)); + return(startReceiveDutyCycle(wakePeriod, sleepPeriod, irqFlags, irqMask)); } -int16_t SX126x::startReceiveCommon(uint32_t timeout) { +int16_t SX126x::startReceiveCommon(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { // set DIO mapping - uint16_t mask = RADIOLIB_SX126X_IRQ_RX_DONE; if(timeout != RADIOLIB_SX126X_RX_TIMEOUT_INF) { - mask |= RADIOLIB_SX126X_IRQ_TIMEOUT; + irqMask |= RADIOLIB_SX126X_IRQ_TIMEOUT; } - int16_t state = setDioIrqParams(RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT | RADIOLIB_SX126X_IRQ_CRC_ERR | RADIOLIB_SX126X_IRQ_HEADER_ERR, mask); + int16_t state = setDioIrqParams(irqFlags, irqMask); RADIOLIB_ASSERT(state); // set buffer pointers diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index ceec1b21a3..05e2260131 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -221,6 +221,7 @@ #define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected #define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received #define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR) #define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts #define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts @@ -608,9 +609,13 @@ class SX126x: public PhysicalLayer { \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX126X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX126X_RX_TIMEOUT_NONE for no timeout (Rx single mode). If timeout other than infinite is set, signal will be generated on DIO1. + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF); + int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. @@ -620,9 +625,13 @@ class SX126x: public PhysicalLayer { \param sleepPeriod The duration the receiver will not be in Rx mode, in microseconds. + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \returns \ref status_codes */ - int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod); + int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); /*! \brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages. @@ -633,9 +642,13 @@ class SX126x: public PhysicalLayer { \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols of any preamble of the specified length. Defaults to 8. According to Semtech, receiver requires 8 symbols to reliably latch a preamble. This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1). + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \returns \ref status_codes */ - int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8); + int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); /*! \brief Reads the current IRQ status. @@ -1062,7 +1075,7 @@ class SX126x: public PhysicalLayer { uint16_t getDeviceErrors(); int16_t clearDeviceErrors(); - int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF); + int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); int16_t setFrequencyRaw(float freq); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); From edc8877adb1758240ea5b792209887ef8cd54525 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 26 Feb 2023 13:34:22 +0100 Subject: [PATCH 0385/1848] [SX128x] Add irqFlags and irqMask to startReceive --- src/modules/SX128x/SX128x.cpp | 8 +++----- src/modules/SX128x/SX128x.h | 7 ++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3a852300bd..b5aeed3118 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -546,20 +546,18 @@ int16_t SX128x::finishTransmit() { return(standby()); } -int16_t SX128x::startReceive(uint16_t timeout) { +int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask) { // check active modem if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { return(RADIOLIB_ERR_WRONG_MODEM); } // set DIO mapping - uint16_t mask = RADIOLIB_SX128X_IRQ_RX_DONE; - if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) { - mask |= RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; + irqMask |= RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; } - int16_t state = setDioIrqParams(RADIOLIB_SX128X_IRQ_RX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT | RADIOLIB_SX128X_IRQ_CRC_ERROR | RADIOLIB_SX128X_IRQ_HEADER_ERROR, mask); + int16_t state = setDioIrqParams(irqFlags, irqMask); RADIOLIB_ASSERT(state); // set buffer pointers diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 271c321f2a..b3dcfa8494 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -327,6 +327,7 @@ #define RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid #define RADIOLIB_SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done #define RADIOLIB_SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done +#define RADIOLIB_SX128X_IRQ_RX_DEFAULT 0x4062 // 15 0 default for Rx (RX_DONE, RX_TX_TIMEOUT, CRC_ERROR and HEADER_ERROR) #define RADIOLIB_SX128X_IRQ_NONE 0x0000 // 15 0 none #define RADIOLIB_SX128X_IRQ_ALL 0xFFFF // 15 0 all @@ -566,9 +567,13 @@ class SX128x: public PhysicalLayer { \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). If timeout other than infinite is set, signal will be generated on DIO1. + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX128X_IRQ_RX_DEFAULT. + + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX128X_IRQ_RX_DONE. + \returns \ref status_codes */ - int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF); + int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE); /*! \brief Reads the current IRQ status. From 3c9221948857feedd28f5c3be477a734f1024c56 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Mar 2023 21:50:40 +0100 Subject: [PATCH 0386/1848] [MOD] Fixed print format (#685) --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 27e9471faf..587b7f4f53 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -717,7 +717,7 @@ void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, size_t rem_len = len; for(int32_t i = 0; i < len; i+=16) { char str[80]; - sprintf(str, "%07lx ", i+offset); + sprintf(str, "%07" PRIx32 " ", i+offset); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; From 40450e699cba00d6be109207abe969381a1403c7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 2 Mar 2023 21:34:36 +0100 Subject: [PATCH 0387/1848] Fixed typo --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0258df195f..f02e63f88f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,7 +14,7 @@ Before submitting new issue, please check the [Wiki](https://github.com/jgromes/ A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode). **To Reproduce** -Minimal Arduino sketch to reproduce the behavior. Please user Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)). +Minimal Arduino sketch to reproduce the behavior. Please use Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)). **Expected behavior** A clear and concise description of what you expected to happen. From 7c083e07965c8d7015733bfd9f2773cdcfe79964 Mon Sep 17 00:00:00 2001 From: Branden Ghena Date: Thu, 2 Mar 2023 22:28:40 -0600 Subject: [PATCH 0388/1848] Fix args to begin() in SX12xx settings examples --- examples/SX126x/SX126x_Settings/SX126x_Settings.ino | 2 +- examples/SX128x/SX128x_Settings/SX128x_Settings.ino | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index 7777c75d80..530c49ab17 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -74,7 +74,7 @@ void setup() { // sync word: 0x34 (public network/LoRaWAN) // output power: 2 dBm // preamble length: 20 symbols - state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 20); + state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 2, 20); if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { diff --git a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino index 36b02da14b..1bd5f8fc44 100644 --- a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino +++ b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -65,9 +65,10 @@ void setup() { // bandwidth: 1625.0 kHz // spreading factor: 7 // coding rate: 5 + // sync word: 0x12 (private network) // output power: 2 dBm // preamble length: 20 symbols - state = radio2.begin(2450.0, 1625.0, 7, 5, 2, 20); + state = radio2.begin(2450.0, 1625.0, 7, 5, 0x12, 2, 20); if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { From 1b039e501ddf965ac534d1aef9749bfa3897d3a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 4 Mar 2023 23:42:11 +0100 Subject: [PATCH 0389/1848] [CI] Disable uncrustify action --- .github/workflows/uncrustify.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 1dcc7c4a1f..723929ab38 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -1,10 +1,10 @@ name: "Uncrustify" on: - push: - branches: [master] - pull_request: - branches: [master] + #push: + # branches: [master] + #pull_request: + # branches: [master] jobs: uncrustify: From 59b7d7df92a886111fd3665b4b6423b1ab400c10 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 14:44:53 +0100 Subject: [PATCH 0390/1848] [CI] Workaround for dubious ownership error --- .github/workflows/uncrustify.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml index 723929ab38..70a644c293 100644 --- a/.github/workflows/uncrustify.yml +++ b/.github/workflows/uncrustify.yml @@ -1,8 +1,8 @@ name: "Uncrustify" on: - #push: - # branches: [master] + push: + branches: [master] #pull_request: # branches: [master] @@ -11,12 +11,15 @@ jobs: name: Uncrustify runs-on: ubuntu-latest env: - run-uncrust: ${{ false || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, 'CI_FORCE_UNCRUST') || github.event_name == 'pull_request' }} + run-uncrust: ${{ contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, 'CI_FORCE_UNCRUST') || github.event_name == 'pull_request' }} steps: - name: Checkout repository if: ${{ env.run-uncrust == 'true' }} uses: actions/checkout@v3 + + - name: Workaround for https://github.com/actions/runner-images/issues/6775 + run: git config --global --add safe.directory /github/workspace - name: Run style check if: ${{ env.run-uncrust == 'true' }} From 25a5f7443ca259fca93c4f7a059df5e108deff36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 14:57:20 +0100 Subject: [PATCH 0391/1848] [SX127x] Fixed invalid sync word value in example --- examples/SX127x/SX127x_Settings/SX127x_Settings.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino index 834a6cc8a1..007a49fbb3 100644 --- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino +++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -68,11 +68,11 @@ void setup() { // bandwidth: 500.0 kHz // spreading factor: 6 // coding rate: 5 - // sync word: 0x14 + // sync word: 0x34 // output power: 2 dBm // preamble length: 20 symbols // amplifier gain: 1 (maximum gain) - state = radio2.begin(915.0, 500.0, 6, 5, 0x14, 2, 20, 1); + state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 2, 20, 1); if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { From 8bf15941c72af75e0ab07dfe336cecea392340b9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 16:38:28 +0100 Subject: [PATCH 0392/1848] [SX126x] Added option to control XTAL/TCXO via member variable --- src/modules/SX126x/SX126x.cpp | 5 +++-- src/modules/SX126x/SX126x.h | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1e4e669866..e1c9764e69 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -3,6 +3,7 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { _mod = mod; + this->XTAL = false; } Module* SX126x::getMod() { @@ -57,7 +58,7 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo RADIOLIB_ASSERT(state); // set TCXO control, if requested - if(tcxoVoltage > 0.0) { + if(!this->XTAL && tcxoVoltage > 0.0) { state = setTCXO(tcxoVoltage); RADIOLIB_ASSERT(state); } @@ -131,7 +132,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL RADIOLIB_ASSERT(state); // set TCXO control, if requested - if(tcxoVoltage > 0.0) { + if(!this->XTAL && tcxoVoltage > 0.0) { state = setTCXO(tcxoVoltage); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 05e2260131..afe12d1ee5 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -439,6 +439,11 @@ class SX126x: public PhysicalLayer { Module* getMod(); + /*! + \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. + */ + bool XTAL; + // basic methods /*! From 721962cacd5766c1d935d55f99a845d49fbd222d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 16:39:50 +0100 Subject: [PATCH 0393/1848] [SX126x] Fixed bug in getDeviceErrors --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e1c9764e69..a1102d0cb7 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1655,7 +1655,7 @@ uint32_t SX126x::getPacketStatus() { uint16_t SX126x::getDeviceErrors() { uint8_t data[2] = {0, 0}; _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); - uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) & ((uint16_t)data[1]); + uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]); return(opError); } From 7a8cadc63914616cfc02b06eda4ae89cd23222fb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 16:40:45 +0100 Subject: [PATCH 0394/1848] [SX126x] Added more verbose calibration result check (#689) --- src/modules/SX126x/SX126x.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index a1102d0cb7..81cf1f5fd4 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1542,7 +1542,19 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { } int16_t SX126x::calibrateImage(uint8_t* data) { - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2)); + int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); + + // if something failed, show the device errors + #if defined(RADIOLIB_DEBUG) + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_PRINT("Calibration failed, device errors: 0x"); + RADIOLIB_DEBUG_PRINTLN(errors, HEX); + } + #endif + return(state); } uint8_t SX126x::getPacketType() { @@ -1793,7 +1805,21 @@ int16_t SX126x::config(uint8_t modem) { _mod->yield(); } - return(RADIOLIB_ERR_NONE); + // check calibration result + state = _mod->SPIcheckStream(); + + // if something failed, show the device errors + #if defined(RADIOLIB_DEBUG) + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_PRINT("Calibration failed, device errors: 0x"); + RADIOLIB_DEBUG_PRINTLN(errors, HEX); + } + #endif + + return(state); } int16_t SX126x::SPIparseStatus(uint8_t in) { From 007d9ac2cb8e5ed452dc5fda38961ad0003d8eef Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 16:42:48 +0100 Subject: [PATCH 0395/1848] [SX126x] Set SX1262 to accept SX1261 device string (#683) --- src/modules/SX126x/SX1262.h | 3 ++- src/modules/SX126x/SX126x.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 108701b7a7..6da9e2a5a3 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -12,7 +12,8 @@ #define RADIOLIB_SX126X_PA_CONFIG_SX1262 0x00 //RADIOLIB_SX126X_REG_VERSION_STRING -#define RADIOLIB_SX1262_CHIP_TYPE 2 +// Note: this should really be "2", however, it seems that all SX1262 devices report as SX1261 +#define RADIOLIB_SX1262_CHIP_TYPE 1 /*! \class SX1262 diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 81cf1f5fd4..8b2404073d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1860,7 +1860,8 @@ bool SX126x::findChip(uint8_t ver) { RADIOLIB_DEBUG_PRINT(i + 1); RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:")); _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_PRINT(F("Expected string: ")); + RADIOLIB_DEBUG_PRINTLN(versionBuff); #endif _mod->delay(10); i++; From 0c84726f5ecea66d159c4b26724baec4c37e6ada Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 17:52:49 +0100 Subject: [PATCH 0396/1848] Added Platformio library JSON (#690) --- library.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 library.json diff --git a/library.json b/library.json new file mode 100644 index 0000000000..785b5fb85a --- /dev/null +++ b/library.json @@ -0,0 +1,26 @@ +{ + "name": "RadioLib", + "version": "5.6.0", + "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", + "keywords": "radio, sx1262", + "homepage": "https://github.com/jgromes/RadioLib", + "repository": + { + "type": "git", + "url": "https://github.com/jgromes/RadioLib.git" + }, + "authors": + { + "name": "Jan Gromeš", + "email": "gromes.jan@gmail.com", + "maintainer": true + }, + "license": "MIT", + "frameworks": "*", + "platforms": "*", + "headers": "RadioLib.h", + "build": + { + "libLDFMode": "chain+" + } +} \ No newline at end of file From 8392cea011edbc7808dd756b42d18ec4b21757be Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 18:08:14 +0100 Subject: [PATCH 0397/1848] [SX126x] Added more LBT/scan registers (CI_FORCE_UNCRUST) --- src/modules/SX126x/SX126x.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index afe12d1ee5..c90afedd18 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -69,7 +69,8 @@ #define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 #define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 -#define RADIOLIB_SX126X_CMD_SET_SCAN_PARAMS 0x9A +#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A +#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B // SX126X register map #define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 @@ -367,6 +368,10 @@ #define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed #define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed +//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS +#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us // SX126X SPI register variables //RADIOLIB_SX126X_REG_HOPPING_ENABLE From d1ab3cd9b0529c84272b8c9c40b8be26983b51d0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 18:16:16 +0100 Subject: [PATCH 0398/1848] [CI] Removed uncrustify action until dubious ownership error is fixed --- .github/workflows/uncrustify.yml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 .github/workflows/uncrustify.yml diff --git a/.github/workflows/uncrustify.yml b/.github/workflows/uncrustify.yml deleted file mode 100644 index 70a644c293..0000000000 --- a/.github/workflows/uncrustify.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: "Uncrustify" - -on: - push: - branches: [master] - #pull_request: - # branches: [master] - -jobs: - uncrustify: - name: Uncrustify - runs-on: ubuntu-latest - env: - run-uncrust: ${{ contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, 'CI_FORCE_UNCRUST') || github.event_name == 'pull_request' }} - - steps: - - name: Checkout repository - if: ${{ env.run-uncrust == 'true' }} - uses: actions/checkout@v3 - - - name: Workaround for https://github.com/actions/runner-images/issues/6775 - run: git config --global --add safe.directory /github/workspace - - - name: Run style check - if: ${{ env.run-uncrust == 'true' }} - uses: coleaeason/actions-uncrustify@v1 - with: - configPath: 'uncrustify.cfg' From c761e1e7caefeb87501adce871ee1cfa618e28fe Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 18:20:07 +0100 Subject: [PATCH 0399/1848] Added Platformio badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c866a3430d..a163e7061b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) +# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib) ### _One radio library to rule them all!_ From 6677b15d931360cf90dcf1c25fdc293bf4bcf935 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 18:24:14 +0100 Subject: [PATCH 0400/1848] Bump version to 5.7.0 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index 785b5fb85a..9aa74f5a4f 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "5.6.0", + "version": "5.7.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", "keywords": "radio, sx1262", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index d6a1baaec1..ea92ef7762 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.6.0 +version=5.7.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 208add964e..b868b99e50 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1083,7 +1083,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x06) +#define RADIOLIB_VERSION_MINOR (0x07) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From e920e1bf0743d59a2f2c326f339aa9f7d82ed8db Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 19:14:14 +0100 Subject: [PATCH 0401/1848] [MOD] Fixed some signed comparison warnings --- src/Module.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 587b7f4f53..c5deec4084 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -715,14 +715,14 @@ uint16_t Module::flipBits16(uint16_t i) { void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; - for(int32_t i = 0; i < len; i+=16) { + for(size_t i = 0; i < len; i+=16) { char str[80]; sprintf(str, "%07" PRIx32 " ", i+offset); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; } - for(int32_t j = 0; j < line_len; j+=width) { + for(size_t j = 0; j < line_len; j+=width) { if(width > 1) { int m = 0; int step = width/2; From 5ba6f41230323148c5fd2b40ee396fe412a9399f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 19:16:37 +0100 Subject: [PATCH 0402/1848] [MOD] Convert end of RF switch mode to macro (https://github.com/jgromes/RadioLib/actions/runs/4337180408) --- src/Module.cpp | 2 -- src/Module.h | 16 ++++++++-------- src/modules/SX126x/STM32WLx.cpp | 2 -- src/modules/SX126x/STM32WLx.h | 2 -- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index c5deec4084..7df4d0db8b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -8,8 +8,6 @@ mbed::PwmOut *pwmPin = NULL; #endif -const Module::RfSwitchMode_t Module::END_OF_MODE_TABLE = {Module::MODE_END_OF_TABLE, {}}; - Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): _cs(cs), _irq(irq), diff --git a/src/Module.h b/src/Module.h index 89006acd06..ac69b02e77 100644 --- a/src/Module.h +++ b/src/Module.h @@ -7,6 +7,14 @@ #include #endif +/*! +* Value to use as the last element in a mode table to indicate the +* end of the table. +* +* See setRfSwitchTable() for details. +*/ +#define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } + /*! \class Module @@ -56,14 +64,6 @@ class Module { MODE_TX, }; - /*! - * Value to use as the last element in a mode table to indicate the - * end of the table. - * - * See setRfSwitchTable() for details. - */ - static const RfSwitchMode_t END_OF_MODE_TABLE; - #if defined(RADIOLIB_BUILD_ARDUINO) /*! diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 6897dfc19e..744f88c377 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -11,8 +11,6 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include -const Module::RfSwitchMode_t STM32WLx::END_OF_MODE_TABLE = {Module::MODE_END_OF_TABLE, {}}; - STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index ad7faffbff..0618dd4331 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -62,8 +62,6 @@ class STM32WLx : public SX1262 { /*! High power transmission mode */ MODE_TX_HP, }; - /*! \copydoc Module::END_OF_MODE_TABLE */ - static const Module::RfSwitchMode_t END_OF_MODE_TABLE; // basic methods From 823c0ff82c4ed6212feaa09d946343c9acc54f73 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 19:28:21 +0100 Subject: [PATCH 0403/1848] [SX126x] Added missing XTAL check --- src/modules/SX126x/SX126x.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 8b2404073d..ae5cd09c36 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1379,6 +1379,11 @@ void SX126x::readBit(RADIOLIB_PIN_TYPE pin) { #endif int16_t SX126x::setTCXO(float voltage, uint32_t delay) { + // check if TCXO is enabled at all + if(this->XTAL) { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + // set mode to standby standby(); From 02306bda91bdeef3dea2def9513ffc05f90baf4e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 19:29:06 +0100 Subject: [PATCH 0404/1848] Added further explanation of the -707 error code (#691) --- src/TypeDef.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/TypeDef.h b/src/TypeDef.h index 50173814f4..128ae0bbfd 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -387,6 +387,11 @@ /*! \brief SX126x failed to execute SPI command. + Often this means that the module is trying to use TCXO while + XTAL is connected (or vice versa). Make sure your crystal setup + (e.g. TCXO reference voltage) matches your hardware by setting + "tcxoVoltage" to 0 when using XTAL module, or to appropriate value + when using TCXO module. */ #define RADIOLIB_ERR_SPI_CMD_FAILED (-707) From ed4fc84a70f59e61cce98543da381b77a47fad18 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 19:30:20 +0100 Subject: [PATCH 0405/1848] [SX126x] Fixed calibration order (#689) (CI_BUILD_ALL) --- src/modules/SX126x/SX126x.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ae5cd09c36..f78b9c1e9b 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -53,16 +53,16 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo state = standby(); RADIOLIB_ASSERT(state); - // configure settings not accessible by API - state = config(RADIOLIB_SX126X_PACKET_TYPE_LORA); - RADIOLIB_ASSERT(state); - // set TCXO control, if requested if(!this->XTAL && tcxoVoltage > 0.0) { state = setTCXO(tcxoVoltage); RADIOLIB_ASSERT(state); } + // configure settings not accessible by API + state = config(RADIOLIB_SX126X_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + // configure publicly accessible settings state = setCodingRate(cr); RADIOLIB_ASSERT(state); @@ -127,16 +127,16 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL state = standby(); RADIOLIB_ASSERT(state); - // configure settings not accessible by API - state = config(RADIOLIB_SX126X_PACKET_TYPE_GFSK); - RADIOLIB_ASSERT(state); - // set TCXO control, if requested if(!this->XTAL && tcxoVoltage > 0.0) { state = setTCXO(tcxoVoltage); RADIOLIB_ASSERT(state); } + // configure settings not accessible by API + state = config(RADIOLIB_SX126X_PACKET_TYPE_GFSK); + RADIOLIB_ASSERT(state); + // configure publicly accessible settings state = setBitRate(br); RADIOLIB_ASSERT(state); From ead59223faaf225087b1db8da852b49d5e5947d9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Mar 2023 20:33:27 +0100 Subject: [PATCH 0406/1848] [STM32WLx] Fixed end of table macro (CI_BUILD_ALL) --- examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino | 2 +- .../STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino | 2 +- examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino | 2 +- .../STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino index b645affedf..63846a0c87 100644 --- a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino +++ b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino @@ -39,7 +39,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, - STM32WLx::END_OF_MODE_TABLE, + END_OF_MODE_TABLE, }; void setup() { diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index 575630019d..c1400429a0 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -38,7 +38,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, - STM32WLx::END_OF_MODE_TABLE, + END_OF_MODE_TABLE, }; void setup() { diff --git a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino index fb6dab5836..19e8dc285a 100644 --- a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino +++ b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino @@ -35,7 +35,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, - STM32WLx::END_OF_MODE_TABLE, + END_OF_MODE_TABLE, }; void setup() { diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index ea17838acb..fdd56a0a2e 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -30,7 +30,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, - STM32WLx::END_OF_MODE_TABLE, + END_OF_MODE_TABLE, }; // save transmission state between loops From 15d698c38dc79117bf23a5328494cdcc6994faff Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 6 Mar 2023 19:03:06 +0100 Subject: [PATCH 0407/1848] Added missing Platformio keywords --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 9aa74f5a4f..2590de8c76 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "5.7.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", - "keywords": "radio, sx1262", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag", "homepage": "https://github.com/jgromes/RadioLib", "repository": { From 97ab0d357a78543f09e7739a9170a6bee469a4c7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Mar 2023 20:09:03 +0100 Subject: [PATCH 0408/1848] [SX126x] Added spectral scan --- .gitignore | 3 + .../SX126x_Spectrum_Scan.ino | 112 +++++++++++++++ extras/SX126x_Spectrum_Scan/SpectrumScan.py | 136 ++++++++++++++++++ keywords.txt | 5 + src/BuildOpt.h | 21 +++ src/RadioLib.h | 1 + src/modules/SX126x/SX126x.cpp | 93 +++++++++++- src/modules/SX126x/SX126x.h | 73 ++++++++-- .../SX126x/patches/SX126x_patch_scan.h | 80 +++++++++++ 9 files changed, 512 insertions(+), 12 deletions(-) create mode 100644 examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino create mode 100644 extras/SX126x_Spectrum_Scan/SpectrumScan.py create mode 100644 src/modules/SX126x/patches/SX126x_patch_scan.h diff --git a/.gitignore b/.gitignore index 374da672e5..8cf77745bb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,8 @@ extras/decoder/log.txt extras/decoder/out.txt +# Spectrum scan +extras/SX126x_Spectrum_Scan/out/* + # PlatformIO .pio* diff --git a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino new file mode 100644 index 0000000000..9e0bdcd2b7 --- /dev/null +++ b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino @@ -0,0 +1,112 @@ +/* + RadioLib SX126x Spectrum Scan Example + + This example shows how to perform a spectrum power scan using SX126x. + The output is in the form of scan lines, each line has 33 power bins. + First power bin corresponds to -11 dBm, the second to -15 dBm and so on. + Higher number of samples in a bin corresponds to more power received + at that level. + + To show the results in a plot, run the Python script + RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py + + WARNING: This functionality is experimental and requires a binary patch + to be uploaded to the SX126x device. There may be some undocumented + side effects! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// this file contains binary patch for the SX1262 +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +void setup() { + Serial.begin(115200); + + // initialize SX1262 FSK modem with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginFSK(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // upload a patch to the SX1262 to enable spectral scan + // NOTE: this patch is uploaded into volatile memory, + // and must be re-uploaded on every power up + Serial.print(F("[SX1262] Uploading patch ... ")); + state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan)); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // configure scan bandwidth to 234.4 kHz + // and disable the data shaping + Serial.print(F("[SX1262] Setting scan parameters ... ")); + state = radio.setRxBandwidth(234.3); + state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[SX1262] Starting spectral scan ... ")); + + // start spectral scan + // number of bands: 2048 (fewer bands = better temporal resolution) + int state = radio.spectralScanStart(2048); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // wait for spectral scan to finish + while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { + delay(10); + } + + // read the results + uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + state = radio.spectralScanGetResult(results); + if(state == RADIOLIB_ERR_NONE) { + // we have some results, print it + Serial.print("SCAN "); + for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { + Serial.print(results[i]); + Serial.print(','); + } + Serial.println(" END"); + } + + // wait a little bit before the next scan + delay(5); +} \ No newline at end of file diff --git a/extras/SX126x_Spectrum_Scan/SpectrumScan.py b/extras/SX126x_Spectrum_Scan/SpectrumScan.py new file mode 100644 index 0000000000..59eb9d63b9 --- /dev/null +++ b/extras/SX126x_Spectrum_Scan/SpectrumScan.py @@ -0,0 +1,136 @@ +#!/usr/bin/python3 +# -*- encoding: utf-8 -*- + +import argparse +import serial +import sys +import numpy as np +import matplotlib as mpl +import matplotlib.pyplot as plt + +from datetime import datetime +from argparse import RawTextHelpFormatter + +# number of samples in each scanline +SCAN_WIDTH = 33 + +# scanline Serial start/end markers +SCAN_MARK_START = 'SCAN ' +SCAN_MARK_END = ' END' + +# output path +OUT_PATH = 'out' + +# default settings +DEFAULT_BAUDRATE = 115200 +DEFAULT_COLOR_MAP = 'viridis' +DEFAULT_SCAN_LEN = 200 +DEFAULT_RSSI_OFFSET = -11 + +# Print iterations progress +# from https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters +def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 50, fill = '█', printEnd = "\r"): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + length - Optional : character length of bar (Int) + fill - Optional : bar fill character (Str) + printEnd - Optional : end character (e.g. "\r", "\r\n") (Str) + """ + percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) + filledLength = int(length * iteration // total) + bar = fill * filledLength + '-' * (length - filledLength) + print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd) + if iteration == total: + print() + + +def main(): + parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' + RadioLib SX126x_Spectrum_Scan plotter script. Displays output from SX126x_Spectrum_Scan example + as grayscale and + + Depends on pyserial and matplotlib, install by: + 'python3 -m pip install pyserial matplotlib' + + Step-by-step guide on how to use the script: + 1. Upload the SX126x_Spectrum_Scan example to your Arduino board with SX1262 connected. + 2. Run the script with appropriate arguments. + 3. Once the scan is complete, output files will be saved to out/ + ''') + parser.add_argument('port', + type=str, + help='COM port to connect to the device') + parser.add_argument('--speed', + default=DEFAULT_BAUDRATE, + type=int, + help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})') + parser.add_argument('--map', + default=DEFAULT_COLOR_MAP, + type=str, + help=f'Matplotlib color map to use for the output (defaults to "{DEFAULT_COLOR_MAP}")') + parser.add_argument('--len', + default=DEFAULT_SCAN_LEN, + type=int, + help=f'Number of scanlines to record (defaults to {DEFAULT_SCAN_LEN})') + parser.add_argument('--offset', + default=DEFAULT_RSSI_OFFSET, + type=int, + help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})') + args = parser.parse_args() + + # create the color map and the result array + arr = np.zeros((SCAN_WIDTH, args.len)) + + # scanline counter + row = 0 + + # open the COM port + with serial.Serial(args.port, args.speed, timeout=None) as com: + while(True): + # update the progress bar + printProgressBar(row, args.len) + + # read a single line + line = com.readline().decode('utf-8') + + # check the markers + if (SCAN_MARK_START in line) and (SCAN_MARK_END in line): + # get the values + scanline = line[len(SCAN_MARK_START):-len(SCAN_MARK_END)].split(',') + for col in range(SCAN_WIDTH): + arr[col][row] = int(scanline[col]) + + # increment the row counter + row = row + 1 + + # check if we're done + if row >= args.len: + break + + # create the figure + fig, ax = plt.subplots() + + # display the result as heatmap + extent = [0, args.len, -4*(SCAN_WIDTH + 1), args.offset] + im = ax.imshow(arr, cmap=args.map, extent=extent) + fig.colorbar(im) + + # set some properites and show + timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S') + title = f'RadioLib SX126x Spectral Scan {timestamp}' + plt.xlabel("Time [sample]") + plt.ylabel("RSSI [dBm]") + ax.set_aspect('auto') + fig.suptitle(title) + fig.canvas.manager.set_window_title(title) + plt.savefig(f'{OUT_PATH}/{title.replace(" ", "_")}.png', dpi=300) + plt.show() + +if __name__ == "__main__": + main() diff --git a/keywords.txt b/keywords.txt index c13d0ff667..664dee1165 100644 --- a/keywords.txt +++ b/keywords.txt @@ -195,6 +195,11 @@ getCurrentLimit KEYWORD2 getIrqStatus KEYWORD2 getLastError KEYWORD2 setRxBoostedGainMode KEYWORD2 +uploadPatch KEYWORD2 +spectralScanStart KEYWORD2 +spectralScanAbort KEYWORD2 +spectralScanGetStatus KEYWORD2 +spectralScanGetResult KEYWORD2 # nRF24 setIrqAction KEYWORD2 diff --git a/src/BuildOpt.h b/src/BuildOpt.h index b868b99e50..d376d2e81b 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -120,6 +120,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -155,6 +156,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -190,6 +192,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral @@ -229,6 +232,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -264,6 +268,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -299,6 +304,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -334,6 +340,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define RADIOLIB_TONE_UNSUPPORTED @@ -370,6 +377,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -405,6 +413,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -440,6 +449,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -475,6 +485,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -510,6 +521,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds @@ -549,6 +561,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds @@ -588,6 +601,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -623,6 +637,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -658,6 +673,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds @@ -697,6 +713,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -732,6 +749,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) // Arduino API callbacks #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, PINMODE mode) @@ -788,6 +806,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -843,6 +862,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks @@ -879,6 +899,7 @@ #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; // Arduino API callbacks diff --git a/src/RadioLib.h b/src/RadioLib.h index 419e0beac7..76bef67b20 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -98,6 +98,7 @@ #include "protocols/Pager/Pager.h" #include "protocols/RTTY/RTTY.h" #include "protocols/SSTV/SSTV.h" +#include "protocols/SSDV/SSDV.h" #include "protocols/FSK4/FSK4.h" #include "protocols/APRS/APRS.h" #include "protocols/ExternalRadio/ExternalRadio.h" diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f78b9c1e9b..f06009b2ac 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -206,13 +206,13 @@ int16_t SX126x::reset(bool verify) { } // standby command failed, check timeout and try again - if(_mod->millis() - start >= 3000) { + if(_mod->millis() - start >= 1000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - _mod->delay(10); + _mod->delay(100); } } @@ -1378,6 +1378,95 @@ void SX126x::readBit(RADIOLIB_PIN_TYPE pin) { } #endif +int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) { + // set to standby RC mode + int16_t state = standby(RADIOLIB_SX126X_STANDBY_RC); + RADIOLIB_ASSERT(state); + + // check the version + #if defined(RADIOLIB_DEBUG) + char ver_pre[16]; + _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); + RADIOLIB_DEBUG_PRINT(F("Pre-update version string: ")); + RADIOLIB_DEBUG_PRINTLN(ver_pre); + #endif + + // enable patch update + _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_ENABLED); + + // upload the patch + uint8_t data[4]; + for(uint32_t i = 0; i < len / sizeof(uint32_t); i++) { + uint32_t bin = 0; + if(nonvolatile) { + bin = RADIOLIB_NONVOLATILE_READ_DWORD(patch + i); + } else { + bin = patch[i]; + } + data[0] = (bin >> 24) & 0xFF; + data[1] = (bin >> 16) & 0xFF; + data[2] = (bin >> 8) & 0xFF; + data[3] = bin & 0xFF; + _mod->SPIwriteRegisterBurst(RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE + i*sizeof(uint32_t), data, sizeof(uint32_t)); + } + + // disable patch update + _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_DISABLED); + + // update + _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); + + // check the version again + #if defined(RADIOLIB_DEBUG) + char ver_post[16]; + _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); + RADIOLIB_DEBUG_PRINT(F("Post-update version string: ")); + RADIOLIB_DEBUG_PRINTLN(ver_post); + #endif + + return(state); +} + +int16_t SX126x::spectralScanStart(uint16_t numBands, uint8_t window, uint8_t interval) { + // abort first - not sure if this is strictly needed, but the example code does this + spectralScanAbort(); + + // set the RSSI window size + _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, window); + + // start Rx with infinite timeout + int16_t state = setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); + RADIOLIB_ASSERT(state); + + // now set the actual spectral scan parameters + uint8_t data[3] = { (uint8_t)((numBands >> 8) & 0xFF), (uint8_t)(numBands & 0xFF), interval }; + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); +} + +void SX126x::spectralScanAbort() { + _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00); +} + +int16_t SX126x::spectralScanGetStatus() { + uint8_t status = _mod->SPIreadRegister(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS); + if(status == RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED) { + return(RADIOLIB_ERR_NONE); + } + return(RADIOLIB_ERR_RANGING_TIMEOUT); +} + +int16_t SX126x::spectralScanGetResult(uint16_t* results) { + // read the raw results + uint8_t data[2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT, 2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, data); + + // convert it + for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { + results[i] = ((uint16_t)data[i*2] << 8) | ((uint16_t)data[i*2 + 1]); + } + return(RADIOLIB_ERR_NONE); +} + int16_t SX126x::setTCXO(float voltage, uint32_t delay) { // check if TCXO is enabled at all if(this->XTAL) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index c90afedd18..b680b702d8 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -412,14 +412,19 @@ #define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan // RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE -#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00010000 // 4 4 patch update: disabled -#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00000000 // 4 4 enabled +#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled +#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled // RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS -#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none -#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing -#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted -#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed +#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted +#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed + +// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW +#define RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window + +#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) /*! \class SX126x @@ -1041,20 +1046,68 @@ class SX126x: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! - \brief Dummy method, to ensure PhysicalLayer compatibility. + \brief Set interrupt service routine function to call when data bit is receveid in direct mode. - \param func Ignored. + \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); /*! - \brief Dummy method, to ensure PhysicalLayer compatibility. + \brief Function to read and process data bit in direct reception mode. - \param pin Ignored. + \param pin Pin on which to read. */ void readBit(RADIOLIB_PIN_TYPE pin); #endif + /*! + \brief Upload binary patch into the SX126x device RAM. + Patch is needed to e.g., enable spectral scan and must be uploaded again on every power cycle. + + \param patch Binary patch to upload. + + \param len Length of the binary patch in 4-byte words. + + \param nonvolatile Set to true when the patch is saved in non-volatile memory of the host processor, + or to false when the patch is in its RAM. + + \returns \ref status_codes + */ + int16_t uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile = true); + + /*! + \brief Start spectral scan. Requires binary path to be uploaded. + + \param numBands Number of bands for the scan. Fewer bands = better temporal resolution, but fewer power samples. + + \param window RSSI averaging window size. + + \param interval Scan interval length, one of RADIOLIB_SX126X_SCAN_INTERVAL_* macros. + + \returns \ref status_codes + */ + int16_t spectralScanStart(uint16_t numBands, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); + + /*! + \brief Abort an ongoing spectral scan. + */ + void spectralScanAbort(); + + /*! + \brief Read the status of spectral scan. + + \returns \ref status_codes + */ + int16_t spectralScanGetStatus(); + + /*! + \brief Read the result of spectral scan. + + \param results Array to which the results will be saved, must be RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE long. + + \returns \ref status_codes + */ + int16_t spectralScanGetResult(uint16_t* results); #if !defined(RADIOLIB_GODMODE) protected: diff --git a/src/modules/SX126x/patches/SX126x_patch_scan.h b/src/modules/SX126x/patches/SX126x_patch_scan.h new file mode 100644 index 0000000000..765e900374 --- /dev/null +++ b/src/modules/SX126x/patches/SX126x_patch_scan.h @@ -0,0 +1,80 @@ +#if !defined(_RADIOLIB_SX126X_PATCH_SCAN_H) +#define _RADIOLIB_SX126X_PATCH_SCAN_H + +#include "../../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX126X) + +// the following is a binary patch to the SX1262 +// this patch is needed to enable spectral scan functionality +const uint32_t sx126x_patch_scan[] RADIOLIB_NONVOLATILE = { + 0x337fe1, 0x337fdb, 0x337fd5, 0x337fcf, 0x3a7fc8, 0x3f3fff, + 0x0378ff, 0x0379ff, 0x3a7fb7, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7faf, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7f34, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7e80, 0x16a901, 0x16a801, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7fc3, 0x16a901, 0x16a801, 0x337fc9, + 0x0378ff, 0x0379ff, 0x3a7fc0, 0x16a901, 0x16a801, 0x337fc9, + 0x0378ff, 0x0379ff, 0x3a7fbd, 0x16a901, 0x16a801, 0x337fc9, + 0x0378ff, 0x0379ff, 0x3a7fba, 0x16a901, 0x16a801, 0x337fc9, + 0x23ffff, 0x0ea1fc, 0x0ea0df, 0x0eafc9, 0x02cf0e, 0x23ffff, + 0x0eacff, 0x0eabff, 0x23ffff, 0x0eacff, 0x0eabff, 0x23ffff, + 0x0eacff, 0x0eabff, 0x23ffff, 0x0eacff, 0x0eabff, 0x23ffff, + 0x0378ff, 0x0379ff, 0x3a7fc8, 0x0eacfd, 0x0eabff, 0x16a901, + 0x16a801, 0x23ffff, 0x0374ff, 0x0375ff, 0x0378ff, 0x0379ff, + 0x16affe, 0x0ea5ff, 0x0ea465, 0x1dbb04, 0x0e1bfd, 0x307fa3, + 0x1caf00, 0x327fa0, 0x0eacf7, 0x0eabff, 0x337f3a, 0x1cad04, + 0x0eacfe, 0x0eabff, 0x0dbfdd, 0x307f97, 0x0dafcc, 0x0defbb, + 0x0dbfdd, 0x347f9b, 0x0eecef, 0x0caffc, 0x04ade8, 0x0cbdcd, + 0x01bde8, 0x04abe8, 0x0ebbbf, 0x01bbe8, 0x04abe8, 0x0ebbdf, + 0x01bbe8, 0x1ca800, 0x0ea9ff, 0x04abe3, 0x0e2b01, 0x01bbe3, + 0x04abee, 0x0e2b01, 0x01bbee, 0x1ca202, 0x1ca301, 0x02f300, + 0x02f201, 0x0ea064, 0x0ea1f7, 0x18ab00, 0x367f58, 0x0ea041, + 0x0ea1f7, 0x18ab00, 0x1c1b03, 0x317f3f, 0x1ea201, 0x1ea300, + 0x0cb23f, 0x327f4a, 0x1cab04, 0x0eaefe, 0x0dbfbb, 0x307f6c, + 0x0dafee, 0x0dbfbb, 0x347f6f, 0x04abee, 0x0cbbeb, 0x01bbee, + 0x0eacff, 0x0eabff, 0x0c1b9f, 0x327f64, 0x0c1c8f, 0x317f5c, + 0x3fffff, 0x0d1fcc, 0x0d5fbb, 0x0c1b9f, 0x327f5d, 0x0c1c8f, + 0x357f63, 0x0ea064, 0x0ea1f7, 0x18ab00, 0x327f7c, 0x1cad04, + 0x0eacfe, 0x0dbfdd, 0x307f51, 0x0dafcc, 0x0dbfdd, 0x347f54, + 0x0d8fcb, 0x04acee, 0x0c2bcb, 0x01bbee, 0x0eacfd, 0x0eabff, + 0x337f3a, 0x1cad04, 0x0eacfe, 0x0dbfdd, 0x307f43, 0x0dafcc, + 0x0dbfdd, 0x347f46, 0x0d8fcb, 0x04acee, 0x0c2bcb, 0x337f6a, + 0x0cb23f, 0x367f75, 0x0dbf22, 0x0dff33, 0x337f75, 0x16af02, + 0x16a901, 0x16a801, 0x16a501, 0x16a401, 0x23ffff, 0x0374ff, + 0x0375ff, 0x0378ff, 0x0379ff, 0x16afe0, 0x0ea5ff, 0x0ea465, + 0x1ca802, 0x0ea9ff, 0x0eafff, 0x02ff00, 0x0eaff7, 0x02ff01, + 0x0eafef, 0x02ff02, 0x0eafe7, 0x02ff03, 0x0eafdf, 0x02ff04, + 0x0eafd7, 0x02ff05, 0x0eafcf, 0x02ff06, 0x0eafc7, 0x02ff07, + 0x0eafbf, 0x02ff08, 0x0eafb7, 0x02ff09, 0x0eafaf, 0x02ff0a, + 0x0eafa7, 0x02ff0b, 0x0eaf9f, 0x02ff0c, 0x0eaf97, 0x02ff0d, + 0x0eaf8f, 0x02ff0e, 0x0eaf87, 0x02ff0f, 0x0eaf7f, 0x02ff10, + 0x0eaf77, 0x02ff11, 0x0eaf6f, 0x02ff12, 0x0eaf67, 0x02ff13, + 0x0eaf5f, 0x02ff14, 0x0eaf57, 0x02ff15, 0x0eaf4f, 0x02ff16, + 0x0eaf47, 0x02ff17, 0x0eaf3f, 0x02ff18, 0x0eaf37, 0x02ff19, + 0x0eaf2f, 0x02ff1a, 0x0eaf27, 0x02ff1b, 0x0eaf1f, 0x02ff1c, + 0x0eaf17, 0x02ff1d, 0x0eaf0f, 0x02ff1e, 0x0eaf07, 0x02ff1f, + 0x04abee, 0x0e2b01, 0x01bbee, 0x0eacff, 0x0eabff, 0x0cafc0, + 0x0ec0ff, 0x0cafb1, 0x0ed1fb, 0x0eafff, 0x02cf00, 0x0d1fcc, + 0x0d5fbb, 0x0e1bff, 0x327edb, 0x0e1c00, 0x347ee6, 0x0ea2ff, + 0x0ea3ff, 0x0ea032, 0x0ea1f8, 0x0eaff0, 0x02cf00, 0x0ea064, + 0x0ea1f7, 0x18ad00, 0x1c1300, 0x327ece, 0x1c1201, 0x317e9b, + 0x0e1dff, 0x367e9b, 0x0ea041, 0x0ea1f7, 0x18ab00, 0x0eebdf, + 0x0cafbc, 0x0eabff, 0x0ccccc, 0x0cdbbb, 0x0cafc0, 0x0ec0ff, + 0x0cafb1, 0x0ed1fb, 0x18ab01, 0x0eacff, 0x18ae02, 0x0eadff, + 0x0ccecc, 0x0cddbb, 0x0d1fcc, 0x0d5fbb, 0x0cafbe, 0x0eadff, + 0x02ce01, 0x02cc02, 0x0d1f22, 0x0d5f33, 0x0ea064, 0x0ea1f7, + 0x18ad00, 0x0eacff, 0x0eabff, 0x0c1b9f, 0x327ea9, 0x0c1c8f, + 0x317ea1, 0x3fffff, 0x0d1fcc, 0x0d5fbb, 0x0c1b9f, 0x327ea2, + 0x0c1c8f, 0x357ea8, 0x1c1300, 0x327e9e, 0x1c1201, 0x317e9b, + 0x0e1dff, 0x327ecb, 0x0e1dff, 0x367e90, 0x0ea032, 0x0ea1f8, + 0x0eaf00, 0x02cf00, 0x0ea1fb, 0x0ea0ff, 0x0eaf00, 0x02cf00, + 0x337e88, 0x0ea032, 0x0ea1f8, 0x0eaf0f, 0x02cf00, 0x0ea1fb, + 0x0ea0ff, 0x0eaf0f, 0x02cf00, 0x0eacfd, 0x0eabff, 0x16af20, + 0x16a901, 0x16a801, 0x16a501, 0x16a401, 0x23ffff, 0x0eacf7, + 0x0eabff, 0x23ffff +}; + +#endif + +#endif From 265847b82dbda7db6f5a16e1f7680e387e441fff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Mar 2023 20:26:58 +0100 Subject: [PATCH 0409/1848] Removed WIP include --- src/RadioLib.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index 76bef67b20..419e0beac7 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -98,7 +98,6 @@ #include "protocols/Pager/Pager.h" #include "protocols/RTTY/RTTY.h" #include "protocols/SSTV/SSTV.h" -#include "protocols/SSDV/SSDV.h" #include "protocols/FSK4/FSK4.h" #include "protocols/APRS/APRS.h" #include "protocols/ExternalRadio/ExternalRadio.h" From 0818230a7c264cec0fbcc5d72c6c8e9ab5c7faa0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Mar 2023 20:57:32 +0100 Subject: [PATCH 0410/1848] [SX126x] Fixed incorrect variable names --- examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino | 3 ++- src/modules/SX126x/SX126x.cpp | 4 ++-- src/modules/SX126x/SX126x.h | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino index 9e0bdcd2b7..320c7e1958 100644 --- a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino +++ b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino @@ -79,7 +79,8 @@ void loop() { Serial.print(F("[SX1262] Starting spectral scan ... ")); // start spectral scan - // number of bands: 2048 (fewer bands = better temporal resolution) + // number of scans in each line is 2048 + // fewer scans leads to better temporal resolution, int state = radio.spectralScanStart(2048); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f06009b2ac..121670a786 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1427,7 +1427,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) return(state); } -int16_t SX126x::spectralScanStart(uint16_t numBands, uint8_t window, uint8_t interval) { +int16_t SX126x::spectralScanStart(uint16_t numScans, uint8_t window, uint8_t interval) { // abort first - not sure if this is strictly needed, but the example code does this spectralScanAbort(); @@ -1439,7 +1439,7 @@ int16_t SX126x::spectralScanStart(uint16_t numBands, uint8_t window, uint8_t int RADIOLIB_ASSERT(state); // now set the actual spectral scan parameters - uint8_t data[3] = { (uint8_t)((numBands >> 8) & 0xFF), (uint8_t)(numBands & 0xFF), interval }; + uint8_t data[3] = { (uint8_t)((numScans >> 8) & 0xFF), (uint8_t)(numScans & 0xFF), interval }; return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index b680b702d8..c27e64c35d 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1078,7 +1078,7 @@ class SX126x: public PhysicalLayer { /*! \brief Start spectral scan. Requires binary path to be uploaded. - \param numBands Number of bands for the scan. Fewer bands = better temporal resolution, but fewer power samples. + \param numScans Number of scans for each iteration. Fewer scans = better temporal resolution, but fewer power samples. \param window RSSI averaging window size. @@ -1086,7 +1086,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t spectralScanStart(uint16_t numBands, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); + int16_t spectralScanStart(uint16_t numScans, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); /*! \brief Abort an ongoing spectral scan. From 00bb31cb2e3abd90f9e5a0e7bcb4cd4b65676474 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Mar 2023 22:52:14 +0100 Subject: [PATCH 0411/1848] [SX126x] Added patch binary license --- .../SX126x/patches/SX126x_patch_scan.h | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/modules/SX126x/patches/SX126x_patch_scan.h b/src/modules/SX126x/patches/SX126x_patch_scan.h index 765e900374..3dff7be8eb 100644 --- a/src/modules/SX126x/patches/SX126x_patch_scan.h +++ b/src/modules/SX126x/patches/SX126x_patch_scan.h @@ -1,3 +1,33 @@ +/* +Binary in this file originates from https://github.com/Lora-net/sx1302_hal/tree/master +As such, license of the above repository is reproduced here. + +Copyright (c) 2019, SEMTECH S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #if !defined(_RADIOLIB_SX126X_PATCH_SCAN_H) #define _RADIOLIB_SX126X_PATCH_SCAN_H From 8ace6350cfa9bd4a4bff68f1bf9cea387a892d0d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Mar 2023 14:50:14 +0100 Subject: [PATCH 0412/1848] [SX127x] Added missing standby for PhysicalLayer (#695) --- src/modules/SX127x/SX127x.cpp | 5 +++++ src/modules/SX127x/SX127x.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index c5d857fc60..dace7ae01e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -289,6 +289,11 @@ int16_t SX127x::standby() { return(setMode(RADIOLIB_SX127X_STANDBY)); } +int16_t SX127x::standby(uint8_t mode) { + (void)mode; + return(standby()); +} + int16_t SX127x::transmitDirect(uint32_t frf) { // check modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 13083b644f..e40a5de429 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -686,6 +686,15 @@ class SX127x: public PhysicalLayer { */ int16_t standby() override; + /*! + \brief Sets the %LoRa module to standby. + + \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. + + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. From 45826fb00d1d23f71450809d8c149e98de1fe990 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Mar 2023 15:01:50 +0100 Subject: [PATCH 0413/1848] [nRF24] Added missing standby overload --- src/modules/nRF24/nRF24.cpp | 6 +++++- src/modules/nRF24/nRF24.h | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index f00f42e3db..776aacdafb 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -72,13 +72,17 @@ int16_t nRF24::sleep() { } int16_t nRF24::standby() { + return(standby(RADIOLIB_NRF24_POWER_UP)); +} + +int16_t nRF24::standby(uint8_t mode) { // make sure carrier output is disabled _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_OFF, 7, 7); _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_OFF, 4, 4); _mod->digitalWrite(_mod->getRst(), LOW); // use standby-1 mode - return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1)); + return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, mode, 1, 1)); } int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 72605c6ff0..7dbe9206ec 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -235,6 +235,15 @@ class nRF24: public PhysicalLayer { */ int16_t standby() override; + /*! + \brief Sets the module to standby. + + \param mode Standby mode to be used. + + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. From 874886b4cd9d2304890e4bbdf863b83ad0f44599 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Mar 2023 15:02:08 +0100 Subject: [PATCH 0414/1848] [RF69] Added missing standby overload --- src/modules/RF69/RF69.cpp | 5 +++++ src/modules/RF69/RF69.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index d2f17d826f..25a781abc6 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -173,6 +173,11 @@ int16_t RF69::standby() { return(setMode(RADIOLIB_RF69_STANDBY)); } +int16_t RF69::standby(uint8_t mode) { + (void)mode; + return(standby()); +} + int16_t RF69::transmitDirect(uint32_t frf) { // set RF switch (if present) _mod->setRfSwitchState(Module::MODE_TX); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index f4cc8495f3..5060a49c8d 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -565,6 +565,15 @@ class RF69: public PhysicalLayer { */ int16_t standby() override; + /*! + \brief Sets the module to standby. + + \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. + + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Starts direct mode transmission. From a4df77b76ef70079a3a98586521eab6b255bc2b5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Mar 2023 15:02:23 +0100 Subject: [PATCH 0415/1848] [Si443x] Added missing standby overload --- src/modules/Si443x/Si443x.cpp | 7 +++++-- src/modules/Si443x/Si443x.h | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index b8641aeed4..efc01c6da1 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -134,10 +134,13 @@ int16_t Si443x::sleep() { } int16_t Si443x::standby() { + return(standby(RADIOLIB_SI443X_XTAL_ON)); +} + +int16_t Si443x::standby(uint8_t mode) { // set RF switch (if present) _mod->setRfSwitchState(Module::MODE_IDLE); - - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_XTAL_ON, 7, 0, 10)); + return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, mode, 7, 0, 10)); } int16_t Si443x::transmitDirect(uint32_t frf) { diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 6945e510e8..454214bec3 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -627,12 +627,21 @@ class Si443x: public PhysicalLayer { int16_t sleep(); /*! - \brief Sets the module to standby. + \brief Sets the module to standby (with XTAL on). \returns \ref status_codes */ int16_t standby() override; + /*! + \brief Sets the module to standby. + + \param mode Standby mode to be used. + + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Enables direct transmission mode. While in direct mode, the module will not be able to transmit or receive packets. From 482b962f79304aea1248f13907547ce7bef02d78 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Mar 2023 15:03:16 +0100 Subject: [PATCH 0416/1848] [CC1101] Added missing standby overload --- src/modules/CC1101/CC1101.cpp | 5 +++++ src/modules/CC1101/CC1101.h | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 72824fce1b..06f42c1000 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -166,6 +166,11 @@ int16_t CC1101::standby() { return(RADIOLIB_ERR_NONE); } +int16_t CC1101::standby(uint8_t mode) { + (void)mode; + return(standby()); +} + int16_t CC1101::transmitDirect(uint32_t frf) { return transmitDirect(true, frf); } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index eb12b0be2b..3ecdcac26b 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -111,7 +111,7 @@ // CC1101_REG_IOCFG0 #define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_OFF 0b00000000 // 7 7 analog temperature sensor output: disabled (default) -#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 0 enabled +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 7 enabled #define RADIOLIB_CC1101_GDO0_NORM 0b00000000 // 6 6 GDO0 output: active high (default) #define RADIOLIB_CC1101_GDO0_INV 0b01000000 // 6 6 active low @@ -591,6 +591,15 @@ class CC1101: public PhysicalLayer { */ int16_t standby() override; + /*! + \brief Sets the module to standby. + + \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. + + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Starts direct mode transmission. From f809f17dc8207044bfe1dcd8c4648980cd6ffb63 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 13 Mar 2023 22:02:07 +0100 Subject: [PATCH 0417/1848] [Pager] Added missing exclude direct receive guards (#697) --- src/protocols/Pager/Pager.cpp | 8 ++++++++ src/protocols/Pager/Pager.h | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index cc7591d8b7..32f401f60c 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,6 +1,7 @@ #include "Pager.h" #if !defined(RADIOLIB_EXCLUDE_PAGER) +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) // this is a massive hack, but we need a global-scope ISR to manage the bit reading // let's hope nobody ever tries running two POCSAG receivers at the same time static PhysicalLayer* _readBitInstance = NULL; @@ -14,10 +15,13 @@ static void PagerClientReadBit(void) { _readBitInstance->readBit(_readBitPin); } } +#endif PagerClient::PagerClient(PhysicalLayer* phy) { _phy = phy; + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) _readBitInstance = _phy; + #endif } int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { @@ -214,6 +218,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t return(RADIOLIB_ERR_NONE); } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t mask) { // save the variables _readBitPin = pin; @@ -430,6 +435,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { *len = decodedBytes; return(RADIOLIB_ERR_NONE); } +#endif void PagerClient::write(uint32_t* data, size_t len) { // write code words from buffer @@ -471,6 +477,7 @@ void PagerClient::write(uint32_t codeWord) { } } +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) uint32_t PagerClient::read() { uint32_t codeWord = 0; codeWord |= (uint32_t)_phy->read() << 24; @@ -491,6 +498,7 @@ uint32_t PagerClient::read() { // TODO BCH error correction here return(codeWord); } +#endif uint8_t PagerClient::encodeBCD(char c) { switch(c) { diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index eb828fbb7c..844150bce5 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -142,6 +142,8 @@ class PagerClient { */ int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Start reception of POCSAG packets. @@ -190,6 +192,7 @@ class PagerClient { \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t* len, uint32_t* addr = NULL); +#endif #if !defined(RADIOLIB_GODMODE) private: @@ -202,7 +205,6 @@ class PagerClient { uint16_t _shift; uint16_t _shiftHz; uint16_t _bitDuration; - uint32_t _readBatchPos; uint32_t _filterAddr; uint32_t _filterMask; bool inv = false; @@ -214,7 +216,10 @@ class PagerClient { void write(uint32_t* data, size_t len); void write(uint32_t codeWord); + +#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) uint32_t read(); +#endif uint8_t encodeBCD(char c); char decodeBCD(uint8_t b); From 9c94111e73fa65cb71a3aaa2cea06483174695cd Mon Sep 17 00:00:00 2001 From: Davide Lasagna Date: Thu, 16 Mar 2023 19:35:27 +0000 Subject: [PATCH 0418/1848] add functions to PhysicalLayer interface --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 26 +++++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 46 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index e62edf7305..c872c7246f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -110,6 +110,10 @@ int16_t PhysicalLayer::receive(uint8_t* data, size_t len) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::sleep() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + int16_t PhysicalLayer::standby() { return(standby(RADIOLIB_STANDBY_DEFAULT)); } @@ -119,6 +123,13 @@ int16_t PhysicalLayer::standby(uint8_t mode) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + return(RADIOLIB_ERR_UNSUPPORTED); +} + int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) { return(startTransmit(str.c_str(), addr)); } @@ -230,6 +241,14 @@ size_t PhysicalLayer::getPacketLength(bool update) { return(0); } +float PhysicalLayer::getRSSI() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +float PhysicalLayer::getSNR() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + int32_t PhysicalLayer::random(int32_t max) { if(max == 0) { return(0); @@ -365,6 +384,13 @@ int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { return(RADIOLIB_ERR_UNSUPPORTED); } +void PhysicalLayer::setDio1Action(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::clearDio1Action() { +} + #if defined(RADIOLIB_INTERRUPT_TIMING) void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { Module* mod = getMod(); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index aad936f8e4..c53b7c419c 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -84,6 +84,13 @@ class PhysicalLayer { */ int16_t receive(String& str, size_t len = 0); + /*! + \brief Sets module to sleep. + + \returns \ref status_codes + */ + virtual int16_t sleep(); + /*! \brief Sets module to standby. @@ -98,6 +105,19 @@ class PhysicalLayer { */ virtual int16_t standby(uint8_t mode); + /*! + \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + + \param timeout Raw timeout value. + + \param irqFlags Sets the IRQ flags. + + \param irqMask Sets the mask of IRQ flags that will trigger DIO1. + + \returns \ref status_codes + */ + virtual int16_t startReceive(uint32_t timeout = 0, uint16_t irqFlags = 0, uint16_t irqMask = 0); + /*! \brief Binary receive method. Must be implemented in module class. @@ -258,6 +278,20 @@ class PhysicalLayer { */ virtual size_t getPacketLength(bool update = true); + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + + \returns RSSI of the last received packet in dBm. + */ + virtual float getRSSI(); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. + + \returns SNR of the last received packet in dB. + */ + virtual float getSNR(); + /*! \brief Get truly random number in range 0 - max. @@ -351,6 +385,18 @@ class PhysicalLayer { */ virtual int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + /*! + \brief Sets interrupt service routine to call when DIO1 activates. + + \param func ISR to call. + */ + virtual void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + virtual void clearDio1Action(); + #if defined(RADIOLIB_INTERRUPT_TIMING) /*! From b9b317100115f10d48f950dfc43830094839b14b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Mar 2023 23:01:24 +0100 Subject: [PATCH 0419/1848] Added user build opt --- src/BuildOptUser.h | 11 +++++++++++ src/TypeDef.h | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/BuildOptUser.h diff --git a/src/BuildOptUser.h b/src/BuildOptUser.h new file mode 100644 index 0000000000..5df3c2be71 --- /dev/null +++ b/src/BuildOptUser.h @@ -0,0 +1,11 @@ +#if !defined(_RADIOLIB_USER_BUILD_OPTIONS_H) +#define _RADIOLIB_USER_BUILD_OPTIONS_H + +// this file can be used to define any user build options +// most commonly, RADIOLIB_EXCLUDE_* macros +// or enabling debug output + +//#define RADIOLIB_DEBUG +//#define RADIOLIB_VERBOSE + +#endif diff --git a/src/TypeDef.h b/src/TypeDef.h index 128ae0bbfd..153f3a3c57 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -2,6 +2,7 @@ #define _RADIOLIB_TYPES_H #include "BuildOpt.h" +#include "BuildOptUser.h" /*! \defgroup config_shaping Data shaping filter values aliases. @@ -312,6 +313,28 @@ */ #define RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS (-204) +// SSDV status codes + +/*! + \brief SSDV mode is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SSDV_MODE (-301) + +/*! + \brief Image size is invalid. +*/ +#define RADIOLIB_ERR_INVALID_IMAGE_SIZE (-302) + +/*! + \brief Image quality is invalid. +*/ +#define RADIOLIB_ERR_INVALID_IMAGE_QUALITY (-303) + +/*! + \brief Image subsampling is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SUBSAMPLING (-304) + // RTTY status codes /*! From cfe6128656fb9fe6cc2a98c8b36bb9a99e3175be Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Mar 2023 10:56:00 +0100 Subject: [PATCH 0420/1848] [SX126x] Added frequency error reading --- .../SX126x/SX126x_Receive/SX126x_Receive.ino | 5 +++ .../SX126x_Receive_Interrupt.ino | 5 +++ src/modules/SX126x/SX126x.cpp | 33 +++++++++++++++++++ src/modules/SX126x/SX126x.h | 22 ++++++++----- 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino index b2f49d2810..d00f4f6409 100644 --- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino +++ b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino @@ -88,6 +88,11 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); + // print frequency error + Serial.print(F("[SX1262] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 2e2c2faa46..a7f87a36b0 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -127,6 +127,11 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); + // print frequency error + Serial.print(F("[SX1262] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 121670a786..70115feb7e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1241,6 +1241,39 @@ float SX126x::getSNR() { } } +float SX126x::getFrequencyError() { + // check active modem + uint8_t modem = getPacketType(); + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(0.0); + } + + // read the raw frequency error register values + uint8_t efeRaw[3] = {0}; + int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 2, &efeRaw[0], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 1, &efeRaw[1], 1); + RADIOLIB_ASSERT(state); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR, &efeRaw[2], 1); + RADIOLIB_ASSERT(state); + uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; + efe &= 0x0FFFFF; + + float error = 0; + + // check the first bit + if (efe & 0x80000) { + // frequency error is negative + efe |= (uint32_t) 0xFFF00000; + efe = ~efe + 1; + error = 1.55 * (float) efe / (160.0 / (float) _bwKhz) * -1.0; + } else { + error = 1.55 * (float) efe / (160.0 / (float) _bwKhz); + } + + return(error); +} + size_t SX126x::getPacketLength(bool update) { (void)update; uint8_t rxBufStatus[2] = {0, 0}; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index c27e64c35d..aca8356bd2 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -73,6 +73,9 @@ #define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B // SX126X register map +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 #define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 #define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 #define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 @@ -85,6 +88,7 @@ #define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) #define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 #define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 +#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582 #define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 #define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 #define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 @@ -120,7 +124,7 @@ #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C -#define RADIOLIB_SX126X_REG_TX_MODULATION 0x0889 +#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 #define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B #define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C #define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D @@ -138,13 +142,6 @@ #define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 #define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 -// undocumented registers -#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 - - // SX126X SPI command variables //RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION #define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) @@ -931,6 +928,15 @@ class SX126x: public PhysicalLayer { */ float getSNR(); + /*! + \brief Gets frequency error of the latest received packet. + WARNING: This functionality is based on SX128x implementation and not documented on SX126x. + While it seems to be working, it should be used with caution! + + \returns Frequency error in Hz. + */ + float getFrequencyError(); + /*! \brief Query modem for the packet length of received payload. From 9b9a34bd2cc53e4bdf37b976cd876b626af269e9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 Mar 2023 19:13:38 +0100 Subject: [PATCH 0421/1848] Fixed build options include order --- src/TypeDef.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index 153f3a3c57..6d41b56b3c 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -1,8 +1,9 @@ #if !defined(_RADIOLIB_TYPES_H) #define _RADIOLIB_TYPES_H -#include "BuildOpt.h" +// user build options may override the default #include "BuildOptUser.h" +#include "BuildOpt.h" /*! \defgroup config_shaping Data shaping filter values aliases. From dc2eb523a913bd7c9f39e5dbd12644958e6ca4f3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 Mar 2023 21:59:07 +0100 Subject: [PATCH 0422/1848] [SX126x] Cleanup whitespaces --- src/modules/SX126x/SX126x.cpp | 18 ++-- src/modules/SX126x/SX126x.h | 158 +++++++++++++++++----------------- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 70115feb7e..71f1b55bb3 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -380,7 +380,7 @@ int16_t SX126x::directMode() { // set preamble length to the maximum to prevent SX126x from exiting Tx mode for a while state = setPreambleLength(0xFFFF); RADIOLIB_ASSERT(state); - + return(state); } @@ -388,7 +388,7 @@ int16_t SX126x::packetMode() { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); - + // set preamble length to the default state = setPreambleLength(16); RADIOLIB_ASSERT(state); @@ -396,7 +396,7 @@ int16_t SX126x::packetMode() { // disable TxDone interrupt state = setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); RADIOLIB_ASSERT(state); - + // restore the magic registers state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_DISABLED, 3, 3); RADIOLIB_ASSERT(state); @@ -1951,15 +1951,15 @@ int16_t SX126x::config(uint8_t modem) { int16_t SX126x::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) { - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } else if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); + return(RADIOLIB_ERR_SPI_CMD_INVALID); } else if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED) { - return(RADIOLIB_ERR_SPI_CMD_FAILED); + return(RADIOLIB_ERR_SPI_CMD_FAILED); } else if((in == 0x00) || (in == 0xFF)) { - return(RADIOLIB_ERR_CHIP_NOT_FOUND); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - return(RADIOLIB_ERR_NONE); + return(RADIOLIB_ERR_NONE); } bool SX126x::findChip(uint8_t ver) { @@ -1986,7 +1986,7 @@ bool SX126x::findChip(uint8_t ver) { RADIOLIB_DEBUG_PRINT(F("SX126x not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:")); - _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINT(F("Expected string: ")); RADIOLIB_DEBUG_PRINTLN(versionBuff); #endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index aca8356bd2..5953adc1cd 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -947,124 +947,124 @@ class SX126x: public PhysicalLayer { size_t getPacketLength(bool update = true) override; /*! - \brief Set modem in fixed packet length mode. Available in FSK mode only. + \brief Set modem in fixed packet length mode. Available in FSK mode only. - \param len Packet length. + \param len Packet length. - \returns \ref status_codes - */ - int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX126X_MAX_PACKET_LENGTH); + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX126X_MAX_PACKET_LENGTH); - /*! - \brief Set modem in variable packet length mode. Available in FSK mode only. + /*! + \brief Set modem in variable packet length mode. Available in FSK mode only. - \param len Maximum packet length. + \param len Maximum packet length. - \returns \ref status_codes - */ - int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); - /*! - \brief Get expected time-on-air for a given size of payload + /*! + \brief Get expected time-on-air for a given size of payload - \param len Payload length in bytes. + \param len Payload length in bytes. - \returns Expected time-on-air in microseconds. - */ - uint32_t getTimeOnAir(size_t len); + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len); - /*! - \brief Get instantaneous RSSI value during recption of the packet. Should switch to FSK receive mode for LBT implementation. + /*! + \brief Get instantaneous RSSI value during recption of the packet. Should switch to FSK receive mode for LBT implementation. - \returns Instantaneous RSSI value in dBm, in steps of 0.5dBm - */ - float getRSSIInst(); + \returns Instantaneous RSSI value in dBm, in steps of 0.5dBm + */ + float getRSSIInst(); - /*! - \brief Set implicit header mode for future reception/transmission. + /*! + \brief Set implicit header mode for future reception/transmission. - \param len Payload length in bytes. + \param len Payload length in bytes. - \returns \ref status_codes - */ - int16_t implicitHeader(size_t len); + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); - /*! - \brief Set explicit header mode for future reception/transmission. + /*! + \brief Set explicit header mode for future reception/transmission. - \returns \ref status_codes - */ - int16_t explicitHeader(); + \returns \ref status_codes + */ + int16_t explicitHeader(); - /*! - \brief Set regulator mode to LDO. + /*! + \brief Set regulator mode to LDO. - \returns \ref status_codes - */ - int16_t setRegulatorLDO(); + \returns \ref status_codes + */ + int16_t setRegulatorLDO(); - /*! - \brief Set regulator mode to DC-DC. + /*! + \brief Set regulator mode to DC-DC. - \returns \ref status_codes - */ - int16_t setRegulatorDCDC(); + \returns \ref status_codes + */ + int16_t setRegulatorDCDC(); - /*! - \brief Sets transmission encoding. Available in FSK mode only. Serves only as alias for PhysicalLayer compatibility. + /*! + \brief Sets transmission encoding. Available in FSK mode only. Serves only as alias for PhysicalLayer compatibility. - \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. + \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. - \returns \ref status_codes - */ - int16_t setEncoding(uint8_t encoding) override; + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; - /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + /*! \copydoc Module::setRfSwitchPins */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); - /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); - /*! - \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to - the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX126x::autoLDRO() + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to + the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX126x::autoLDRO() - \param enable Force LDRO to be always enabled (true) or disabled (false). + \param enable Force LDRO to be always enabled (true) or disabled (false). - \returns \ref status_codes - */ - int16_t forceLDRO(bool enable); + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); - /*! - \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically - when symbol length exceeds 16 ms. + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically + when symbol length exceeds 16 ms. - \returns \ref status_codes - */ - int16_t autoLDRO(); + \returns \ref status_codes + */ + int16_t autoLDRO(); - /*! - \brief Get one truly random byte from RSSI noise. + /*! + \brief Get one truly random byte from RSSI noise. - \returns TRNG byte. - */ - uint8_t randomByte(); + \returns TRNG byte. + */ + uint8_t randomByte(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) - /*! + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. \param func Pointer to interrupt service routine. - */ - void setDirectAction(void (*func)(void)); + */ + void setDirectAction(void (*func)(void)); - /*! + /*! \brief Function to read and process data bit in direct reception mode. \param pin Pin on which to read. - */ - void readBit(RADIOLIB_PIN_TYPE pin); - #endif + */ + void readBit(RADIOLIB_PIN_TYPE pin); + #endif /*! \brief Upload binary patch into the SX126x device RAM. From cd4575ebb05de816003f10912b7f729584357b36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 21 Mar 2023 18:18:17 +0100 Subject: [PATCH 0423/1848] [SX126x] Fixed chip id (#707) --- src/modules/LLCC68/LLCC68.cpp | 2 +- src/modules/LLCC68/LLCC68.h | 3 +++ src/modules/SX126x/SX1261.h | 2 +- src/modules/SX126x/SX1262.h | 2 +- src/modules/SX126x/SX1268.h | 2 +- src/modules/SX126x/SX126x.cpp | 8 +++----- src/modules/SX126x/SX126x.h | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index ef1cbb6208..a0d077aab4 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) LLCC68::LLCC68(Module* mod) : SX1262(mod) { - + _chipType = RADIOLIB_LLCC68_CHIP_TYPE; } int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 2810041d38..424563ad88 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -8,6 +8,9 @@ #include "../../Module.h" #include "../SX126x/SX1262.h" +//RADIOLIB_SX126X_REG_VERSION_STRING +#define RADIOLIB_LLCC68_CHIP_TYPE "LLCC68" + /*! \class LLCC68 diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 195b4327ed..13c5ff7d7d 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -13,7 +13,7 @@ #define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01 //RADIOLIB_SX126X_REG_VERSION_STRING -#define RADIOLIB_SX1261_CHIP_TYPE 1 +#define RADIOLIB_SX1261_CHIP_TYPE "SX1261" /*! \class SX1261 diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 6da9e2a5a3..e9919b8379 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -13,7 +13,7 @@ //RADIOLIB_SX126X_REG_VERSION_STRING // Note: this should really be "2", however, it seems that all SX1262 devices report as SX1261 -#define RADIOLIB_SX1262_CHIP_TYPE 1 +#define RADIOLIB_SX1262_CHIP_TYPE "SX1261" /*! \class SX1262 diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index d8dc0867e9..ab1bd22251 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -12,7 +12,7 @@ #define RADIOLIB_SX126X_PA_CONFIG_SX1268 0x00 //RADIOLIB_SX126X_REG_VERSION_STRING -#define RADIOLIB_SX1268_CHIP_TYPE 8 +#define RADIOLIB_SX1268_CHIP_TYPE "SX1268" /*! \class SX1268 diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 71f1b55bb3..78727347a4 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1962,11 +1962,9 @@ int16_t SX126x::SPIparseStatus(uint8_t in) { return(RADIOLIB_ERR_NONE); } -bool SX126x::findChip(uint8_t ver) { +bool SX126x::findChip(const char* verStr) { uint8_t i = 0; bool flagFound = false; - char versionBuff[16]; - sprintf(versionBuff, "SX126%d", ver); while((i < 10) && !flagFound) { // reset the module reset(); @@ -1976,7 +1974,7 @@ bool SX126x::findChip(uint8_t ver) { _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version); // check version register - if(strncmp(versionBuff, version, 6) == 0) { + if(strncmp(verStr, version, 6) == 0) { RADIOLIB_DEBUG_PRINTLN(F("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:")); _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN(); @@ -1988,7 +1986,7 @@ bool SX126x::findChip(uint8_t ver) { RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:")); _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINT(F("Expected string: ")); - RADIOLIB_DEBUG_PRINTLN(versionBuff); + RADIOLIB_DEBUG_PRINTLN(verStr); #endif _mod->delay(10); i++; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 5953adc1cd..92b0f2c6db 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1184,13 +1184,13 @@ class SX126x: public PhysicalLayer { uint32_t _tcxoDelay = 0; size_t _implicitLen = 0; - uint8_t _chipType = 0; + const char* _chipType; // Allow subclasses to define different TX modes uint8_t _tx_mode = Module::MODE_TX; int16_t config(uint8_t modem); - bool findChip(uint8_t type); + bool findChip(const char* verStr); }; #endif From b7e12f5c7183c6e9bf356c4ad50e3cd61ccf59fb Mon Sep 17 00:00:00 2001 From: Davide Lasagna Date: Tue, 21 Mar 2023 19:56:21 +0000 Subject: [PATCH 0424/1848] fix for #705 --- src/modules/SX126x/SX126x.cpp | 2 +- src/modules/SX128x/SX128x.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 78727347a4..a7a17275f9 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -436,7 +436,7 @@ int16_t SX126x::sleep(bool retainConfig) { if(!retainConfig) { sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; } - int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); + int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); // wait for SX126x to safely enter sleep mode _mod->delay(1); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index b5aeed3118..9a31231d42 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -446,7 +446,7 @@ int16_t SX128x::sleep(bool retainConfig) { if(!retainConfig) { sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; } - int16_t state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); + int16_t state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); // wait for SX128x to safely enter sleep mode _mod->delay(1); From 8bbcc908f5f221c1bc1e9edbb47211eed689b143 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 22 Mar 2023 22:12:28 +0100 Subject: [PATCH 0425/1848] [SX126x] Fixed frequency error calculation (#706) --- src/modules/SX126x/SX126x.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 78727347a4..2963347369 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1250,11 +1250,11 @@ float SX126x::getFrequencyError() { // read the raw frequency error register values uint8_t efeRaw[3] = {0}; - int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 2, &efeRaw[0], 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR, &efeRaw[0], 1); RADIOLIB_ASSERT(state); state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 1, &efeRaw[1], 1); RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR, &efeRaw[2], 1); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 2, &efeRaw[2], 1); RADIOLIB_ASSERT(state); uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; efe &= 0x0FFFFF; @@ -1266,9 +1266,9 @@ float SX126x::getFrequencyError() { // frequency error is negative efe |= (uint32_t) 0xFFF00000; efe = ~efe + 1; - error = 1.55 * (float) efe / (160.0 / (float) _bwKhz) * -1.0; + error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz) * -1.0; } else { - error = 1.55 * (float) efe / (160.0 / (float) _bwKhz); + error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz); } return(error); From c3de8b9099654ad985f280c42c73ee0d319b7e1f Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 23 Mar 2023 19:06:43 +0100 Subject: [PATCH 0426/1848] [SX127x] Explicitly enabled CRC (#706) --- src/modules/SX127x/SX1272.cpp | 8 ++++++++ src/modules/SX127x/SX1278.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index b9f04a01b3..771555cac8 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -29,6 +29,10 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setGain(gain); RADIOLIB_ASSERT(state); + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } @@ -56,6 +60,10 @@ int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t RADIOLIB_ASSERT(state); } + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 7d6d57aaec..fda1b3c28f 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -29,6 +29,10 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setGain(gain); RADIOLIB_ASSERT(state); + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } @@ -56,6 +60,10 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t RADIOLIB_ASSERT(state); } + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } From 9dae818033e1702d5d0a7942e487772caa289a69 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 23 Mar 2023 19:07:04 +0100 Subject: [PATCH 0427/1848] [SX126x] Explicitly enabled CRC (#706) --- src/modules/SX126x/SX126x.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 44852fac7e..2c6c8c15a6 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -73,6 +73,12 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); + if (useRegulatorLDO) { + state = setRegulatorLDO(); + } else { + state = setRegulatorDCDC(); + } + // set publicly accessible settings that are not a part of begin method state = setCurrentLimit(60.0); RADIOLIB_ASSERT(state); @@ -80,11 +86,8 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo state = setDio2AsRfSwitch(true); RADIOLIB_ASSERT(state); - if (useRegulatorLDO) { - state = setRegulatorLDO(); - } else { - state = setRegulatorDCDC(); - } + state = setCRC(2); + RADIOLIB_ASSERT(state); return(state); } From 04e24ab9d14c23ac94fbe501b70122732e021569 Mon Sep 17 00:00:00 2001 From: G4lile0 Date: Fri, 24 Mar 2023 20:30:06 +0100 Subject: [PATCH 0428/1848] [SX1278] New getInstRSSI to get current RSSI --- src/modules/SX127x/SX1278.cpp | 33 +++++++++++++++++++++++++++++++++ src/modules/SX127x/SX1278.h | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index fda1b3c28f..4bcd3ee782 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -421,6 +421,39 @@ float SX1278::getRSSI(bool skipReceive) { } } +float SX1278::getInstRSSI(bool skipReceive) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + // for LoRa, get current RSSI + float currentRSSI; + + // RSSI calculation uses different constant for low-frequency and high-frequency ports + if(_freq < 868.0) { + currentRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + } else { + currentRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + } + + return(currentRSSI); + + } else { + // enable listen mode + if(!skipReceive) { + startReceive(); + } + + // read the value for FSK + float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; + + // set mode back to standby + if(!skipReceive) { + standby(); + } + + // return the value + return(rssi); + } +} + int16_t SX1278::setCRC(bool enable, bool mode) { if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index fd2745722e..51096cd5a2 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -257,6 +257,15 @@ class SX1278: public SX127x { */ float getRSSI(bool skipReceive = false); + /*! + \brief Gets current signal strength indicator of for LoRa modem, or current RSSI level for FSK modem. + + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode. + + \returns Current packet RSSI for LoRa modem, or FSK modem. + */ + float getInstRSSI(bool skipReceive = false); + /*! \brief Enables/disables CRC check of received packets. From 0c15424419114e3e2bbf58be031133175ead06da Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:17:19 +0200 Subject: [PATCH 0429/1848] [PHY] Fixed startReceive compatibility (#700) --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 3 ++- src/protocols/PhysicalLayer/PhysicalLayer.h | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index c872c7246f..78acfebb56 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -123,10 +123,11 @@ int16_t PhysicalLayer::standby(uint8_t mode) { return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { +int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; + (void)len; return(RADIOLIB_ERR_UNSUPPORTED); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index c53b7c419c..915faf4508 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -106,17 +106,19 @@ class PhysicalLayer { virtual int16_t standby(uint8_t mode); /*! - \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + \brief Interrupt-driven receive method. A DIO pin will be activated when full packet is received. Must be implemented in module class. - \param timeout Raw timeout value. + \param timeout Raw timeout value. Some modules use this argument to specify operation mode (single vs. continuous receive). \param irqFlags Sets the IRQ flags. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1. + \param irqMask Sets the mask of IRQ flags that will trigger the DIO pin. + + \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). \returns \ref status_codes */ - virtual int16_t startReceive(uint32_t timeout = 0, uint16_t irqFlags = 0, uint16_t irqMask = 0); + virtual int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Binary receive method. Must be implemented in module class. From 87c1d04b42bf52c67a9d4d7518994c0384548400 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:17:55 +0200 Subject: [PATCH 0430/1848] [CC1101] Added PHY startReceive (#700) --- src/modules/CC1101/CC1101.cpp | 8 ++++++++ src/modules/CC1101/CC1101.h | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 06f42c1000..4b1d7c30ba 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -357,6 +357,14 @@ int16_t CC1101::startReceive() { return(state); } +int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + int16_t CC1101::readData(uint8_t* data, size_t len) { // get packet length size_t length = getPacketLength(); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 3ecdcac26b..98f856588f 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -695,6 +695,21 @@ class CC1101: public PhysicalLayer { */ int16_t startReceive(); + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + + \param timeout Ignored. + + \param irqFlags Ignored. + + \param irqMask Ignored. + + \param len Ignored. + + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + /*! \brief Reads data received after calling startReceive method. From a534f490b19e0cdd9b51bad542d2cd241259e317 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:18:08 +0200 Subject: [PATCH 0431/1848] [nRF24] Added PHY startReceive (#700) --- src/modules/nRF24/nRF24.cpp | 8 ++++++++ src/modules/nRF24/nRF24.h | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 776aacdafb..28c207de13 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -232,6 +232,14 @@ int16_t nRF24::startReceive() { return(state); } +int16_t nRF24::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + int16_t nRF24::readData(uint8_t* data, size_t len) { // set mode to standby int16_t state = standby(); diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 7dbe9206ec..ae47877cb8 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -323,6 +323,21 @@ class nRF24: public PhysicalLayer { */ int16_t startReceive(); + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + + \param timeout Ignored. + + \param irqFlags Ignored. + + \param irqMask Ignored. + + \param len Ignored. + + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + /*! \brief Reads data received after calling startReceive method. From b108686a0f70ef2f953761efc28c6ab3e596a1b7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:18:16 +0200 Subject: [PATCH 0432/1848] [RF69] Added PHY startReceive (#700) --- src/modules/RF69/RF69.cpp | 8 ++++++++ src/modules/RF69/RF69.h | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 25a781abc6..87b5715dfb 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -272,6 +272,14 @@ int16_t RF69::startReceive() { return(state); } +int16_t RF69::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + void RF69::setDio0Action(void (*func)(void)) { _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 5060a49c8d..5b4109a626 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -722,6 +722,21 @@ class RF69: public PhysicalLayer { */ int16_t startReceive(); + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + + \param timeout Ignored. + + \param irqFlags Ignored. + + \param irqMask Ignored. + + \param len Ignored. + + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + /*! \brief Reads data received after calling startReceive method. From 1d92f1d78662db84c519e0fbf4d2c4ad4df3d4f7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:18:28 +0200 Subject: [PATCH 0433/1848] [Si443x] Added PHY startReceive (#700) --- src/modules/Si443x/Si443x.cpp | 8 ++++++++ src/modules/Si443x/Si443x.h | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index efc01c6da1..a2ef639905 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -287,6 +287,14 @@ int16_t Si443x::startReceive() { return(state); } +int16_t Si443x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)timeout; + (void)irqFlags; + (void)irqMask; + (void)len; + return(startReceive()); +} + int16_t Si443x::readData(uint8_t* data, size_t len) { // clear interrupt flags clearIRQFlags(); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 454214bec3..1cc75c5030 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -706,6 +706,21 @@ class Si443x: public PhysicalLayer { */ int16_t startReceive(); + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + + \param timeout Ignored. + + \param irqFlags Ignored. + + \param irqMask Ignored. + + \param len Ignored. + + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. From 9dd401e4a1c9fb1c9ce8ae8f64f86f51888194a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:19:53 +0200 Subject: [PATCH 0434/1848] [SX126x] Added PHY startReceive (#700) --- src/modules/SX126x/SX126x.cpp | 3 ++- src/modules/SX126x/SX126x.h | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2c6c8c15a6..ceb9bc6b46 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -536,7 +536,8 @@ int16_t SX126x::finishTransmit() { return(standby()); } -int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { +int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)len; int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 92b0f2c6db..f79bc854c1 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -554,7 +554,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ int16_t scanChannel(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); - + /*! \brief Sets the module to sleep mode. @@ -625,9 +625,11 @@ class SX126x: public PhysicalLayer { \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \param len Only for PhysicalLayer compatibility, not used. + \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. From 5d365d4da7b8e3d0643520cd2ca7cc09ce1a6500 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:20:08 +0200 Subject: [PATCH 0435/1848] [SX127x] Added PHY startReceive (#700) --- src/modules/SX127x/SX127x.cpp | 6 ++++++ src/modules/SX127x/SX127x.h | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index dace7ae01e..2919348466 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -423,6 +423,12 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { return(setMode(mode)); } +int16_t SX127x::startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)irqFlags; + (void)irqMask; + return(startReceive((uint8_t)len, (uint8_t)mode)); +} + void SX127x::setDio0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e40a5de429..1b81e698d3 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -830,6 +830,21 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ int16_t startReceive(uint8_t len = 0, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); + + /*! + \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. + + \param mode Receive mode to be used. + + \param irqFlags Ignored. + + \param irqMask Ignored. + + \param len Expected length of packet to be received. Required for LoRa spreading factor 6. + + \returns \ref status_codes + */ + int16_t startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. From ee7c1e76048bb152b4412cd974abe000d272b118 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Mar 2023 22:20:19 +0200 Subject: [PATCH 0436/1848] [SX128x] Added PHY startReceive (#700) --- src/modules/SX128x/SX128x.cpp | 4 +++- src/modules/SX128x/SX128x.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 9a31231d42..70ddf18e12 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -546,7 +546,9 @@ int16_t SX128x::finishTransmit() { return(standby()); } -int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask) { +int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { + (void)len; + // check active modem if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { return(RADIOLIB_ERR_WRONG_MODEM); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index b3dcfa8494..a3600f3249 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -571,9 +571,11 @@ class SX128x: public PhysicalLayer { \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX128X_IRQ_RX_DONE. + \param len Only for PhysicalLayer compatibility, not used. + \returns \ref status_codes */ - int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE); + int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); /*! \brief Reads the current IRQ status. From c10343e853e77186ceef19f8f55968077c70a341 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Mar 2023 18:48:32 +0200 Subject: [PATCH 0437/1848] [SX126x] Added spectral scan in frequency --- .../SX126x_Spectrum_Scan.ino | 2 +- .../SX126x_Spectrum_Scan_Frequency.ino | 129 ++++++++++++++++++ extras/SX126x_Spectrum_Scan/SpectrumScan.py | 54 +++++++- src/modules/SX126x/SX126x.cpp | 8 +- src/modules/SX126x/SX126x.h | 5 +- 5 files changed, 186 insertions(+), 12 deletions(-) create mode 100644 examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino diff --git a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino index 320c7e1958..dbf4a9d253 100644 --- a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino +++ b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino @@ -80,7 +80,7 @@ void loop() { // start spectral scan // number of scans in each line is 2048 - // fewer scans leads to better temporal resolution, + // number of samples: 2048 (fewer samples = better temporal resolution) int state = radio.spectralScanStart(2048); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); diff --git a/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino b/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino new file mode 100644 index 0000000000..e7d6b33a30 --- /dev/null +++ b/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino @@ -0,0 +1,129 @@ +/* + RadioLib SX126x Spectrum Scan Example + + This example shows how to perform a spectrum power scan using SX126x. + The output is in the form of scan lines, each line has 33 power bins. + First power bin corresponds to -11 dBm, the second to -15 dBm and so on. + Higher number of samples in a bin corresponds to more power received + at that level. The example performs frequency sweep over a given range. + + To show the results in a plot, run the Python script + RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py + + WARNING: This functionality is experimental and requires a binary patch + to be uploaded to the SX126x device. There may be some undocumented + side effects! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// this file contains binary patch for the SX1262 +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// frequency range in MHz to scan +const float freqStart = 431; +const float freqEnd = 435; + +void setup() { + Serial.begin(115200); + + // initialize SX1262 FSK modem at the initial frequency + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginFSK(freqStart); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // upload a patch to the SX1262 to enable spectral scan + // NOTE: this patch is uploaded into volatile memory, + // and must be re-uploaded on every power up + Serial.print(F("[SX1262] Uploading patch ... ")); + state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan)); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // configure scan bandwidth to 234.4 kHz + // and disable the data shaping + Serial.print(F("[SX1262] Setting scan parameters ... ")); + state = radio.setRxBandwidth(234.3); + state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // perform scan over the entire frequency range + float freq = freqStart; + while(freq <= freqEnd) { + Serial.print("FREQ "); + Serial.println(freq, 2); + + // start spectral scan + // number of samples: 2048 (fewer samples = better temporal resolution) + Serial.print(F("[SX1262] Starting spectral scan ... ")); + int state = radio.spectralScanStart(2048); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // wait for spectral scan to finish + while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { + delay(10); + } + + // read the results + uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + state = radio.spectralScanGetResult(results); + if(state == RADIOLIB_ERR_NONE) { + // we have some results, print it + Serial.print("SCAN "); + for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { + Serial.print(results[i]); + Serial.print(','); + } + Serial.println(" END"); + } + + // wait a little bit before the next scan + delay(5); + + // set the next frequency + // the frequency step should be slightly smaller + // or the same as the Rx bandwidth set in setup + freq += 0.2; + radio.setFrequency(freq); + } + +} diff --git a/extras/SX126x_Spectrum_Scan/SpectrumScan.py b/extras/SX126x_Spectrum_Scan/SpectrumScan.py index 59eb9d63b9..435a27a81d 100644 --- a/extras/SX126x_Spectrum_Scan/SpectrumScan.py +++ b/extras/SX126x_Spectrum_Scan/SpectrumScan.py @@ -16,6 +16,7 @@ # scanline Serial start/end markers SCAN_MARK_START = 'SCAN ' +SCAN_MARK_FREQ = 'FREQ ' SCAN_MARK_END = ' END' # output path @@ -82,22 +83,48 @@ def main(): default=DEFAULT_RSSI_OFFSET, type=int, help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})') + parser.add_argument('--freq', + default=-1, + type=float, + help=f'Default starting frequency in MHz') args = parser.parse_args() + freq_mode = False + scan_len = args.len + if (args.freq != -1): + freq_mode = True + scan_len = 1000 + # create the color map and the result array - arr = np.zeros((SCAN_WIDTH, args.len)) + arr = np.zeros((SCAN_WIDTH, scan_len)) # scanline counter row = 0 + # list of frequencies in frequency mode + freq_list = [] + # open the COM port with serial.Serial(args.port, args.speed, timeout=None) as com: while(True): # update the progress bar - printProgressBar(row, args.len) + if not freq_mode: + printProgressBar(row, scan_len) # read a single line - line = com.readline().decode('utf-8') + try: + line = com.readline().decode('utf-8') + except: + continue + + if SCAN_MARK_FREQ in line: + new_freq = float(line.split(' ')[1]) + if (len(freq_list) > 1) and (new_freq < freq_list[-1]): + break + + freq_list.append(new_freq) + print('{:.3f}'.format(new_freq), end = '\r') + continue # check the markers if (SCAN_MARK_START in line) and (SCAN_MARK_END in line): @@ -110,21 +137,34 @@ def main(): row = row + 1 # check if we're done - if row >= args.len: + if (not freq_mode) and (row >= scan_len): break + # scale to the number of scans (sum of any given scanline) + num_samples = arr.sum(axis=0)[0] + arr *= (num_samples/arr.max()) + + if freq_mode: + scan_len = len(freq_list) + # create the figure fig, ax = plt.subplots() # display the result as heatmap - extent = [0, args.len, -4*(SCAN_WIDTH + 1), args.offset] - im = ax.imshow(arr, cmap=args.map, extent=extent) + extent = [0, scan_len, -4*(SCAN_WIDTH + 1), args.offset] + if freq_mode: + extent[0] = freq_list[0] + extent[1] = freq_list[-1] + im = ax.imshow(arr[:,:scan_len], cmap=args.map, extent=extent) fig.colorbar(im) # set some properites and show timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S') title = f'RadioLib SX126x Spectral Scan {timestamp}' - plt.xlabel("Time [sample]") + if freq_mode: + plt.xlabel("Frequency [Hz]") + else: + plt.xlabel("Time [sample]") plt.ylabel("RSSI [dBm]") ax.set_aspect('auto') fig.suptitle(title) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ceb9bc6b46..8e3c234382 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1464,7 +1464,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) return(state); } -int16_t SX126x::spectralScanStart(uint16_t numScans, uint8_t window, uint8_t interval) { +int16_t SX126x::spectralScanStart(uint16_t numSamples, uint8_t window, uint8_t interval) { // abort first - not sure if this is strictly needed, but the example code does this spectralScanAbort(); @@ -1476,7 +1476,7 @@ int16_t SX126x::spectralScanStart(uint16_t numScans, uint8_t window, uint8_t int RADIOLIB_ASSERT(state); // now set the actual spectral scan parameters - uint8_t data[3] = { (uint8_t)((numScans >> 8) & 0xFF), (uint8_t)(numScans & 0xFF), interval }; + uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval }; return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); } @@ -1567,6 +1567,10 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } +int16_t SX126x::setFs() { + return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); +} + int16_t SX126x::setTx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index f79bc854c1..4c04483bb1 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1086,7 +1086,7 @@ class SX126x: public PhysicalLayer { /*! \brief Start spectral scan. Requires binary path to be uploaded. - \param numScans Number of scans for each iteration. Fewer scans = better temporal resolution, but fewer power samples. + \param numSamples Number of samples for each scan. Fewer samples = better temporal resolution. \param window RSSI averaging window size. @@ -1094,7 +1094,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t spectralScanStart(uint16_t numScans, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); + int16_t spectralScanStart(uint16_t numSamples, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); /*! \brief Abort an ongoing spectral scan. @@ -1121,6 +1121,7 @@ class SX126x: public PhysicalLayer { protected: #endif // SX126x SPI command implementations + int16_t setFs(); int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); From 09ab5f8073f7d9b2ca20492b2aa78fa9c3aa35a1 Mon Sep 17 00:00:00 2001 From: G4lile0 Date: Mon, 27 Mar 2023 20:51:44 +0200 Subject: [PATCH 0438/1848] [SX127x] & [SX126x] read current RSSI for getRSSI --- src/modules/SX126x/SX126x.cpp | 16 +++++++-- src/modules/SX126x/SX126x.h | 4 ++- src/modules/SX127x/SX1278.cpp | 64 +++++++++++++---------------------- src/modules/SX127x/SX1278.h | 13 ++----- 4 files changed, 42 insertions(+), 55 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2c6c8c15a6..9a55b23699 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1222,10 +1222,20 @@ float SX126x::getDataRate() const { } float SX126x::getRSSI() { + + if (packet) { // get last packet RSSI from packet status - uint32_t packetStatus = getPacketStatus(); - uint8_t rssiPkt = packetStatus & 0xFF; - return(-1.0 * rssiPkt/2.0); + uint32_t packetStatus = getPacketStatus(); + uint8_t rssiPkt = packetStatus & 0xFF; + return(-1.0 * rssiPkt/2.0); + } else { + // get instantaneous RSSI value + uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU + _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); + + return (float)data[0] / (-2.0); + } + } float SX126x::getSNR() { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 92b0f2c6db..6634ddf7ab 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -917,9 +917,11 @@ class SX126x: public PhysicalLayer { /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \param packet Set to false to gets current RSSI measurement in LoRa mode. + \returns RSSI of the last received packet in dBm. */ - float getRSSI(); + float getRSSI(bool packet = true); /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 4bcd3ee782..e06604bc70 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -381,60 +381,42 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { return(state); } -float SX1278::getRSSI(bool skipReceive) { +float SX1278::getRSSI(bool packet, bool skipReceive) { if(getActiveModem() == RADIOLIB_SX127X_LORA) { - // for LoRa, get RSSI of the last packet - float lastPacketRSSI; + if (packet) { + // for LoRa, get RSSI of the last packet + float lastPacketRSSI; // RSSI calculation uses different constant for low-frequency and high-frequency ports - if(_freq < 868.0) { - lastPacketRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); - } else { - lastPacketRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); - } + if(_freq < 868.0) { + lastPacketRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); + } else { + lastPacketRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); + } // spread-spectrum modulation signal can be received below noise floor // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value - float lastPacketSNR = SX127x::getSNR(); - if(lastPacketSNR < 0.0) { - lastPacketRSSI += lastPacketSNR; - } - - return(lastPacketRSSI); - - } else { - // enable listen mode - if(!skipReceive) { - startReceive(); - } - - // read the value for FSK - float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; - - // set mode back to standby - if(!skipReceive) { - standby(); - } + float lastPacketSNR = SX127x::getSNR(); + if(lastPacketSNR < 0.0) { + lastPacketRSSI += lastPacketSNR; + } + return(lastPacketRSSI); - // return the value - return(rssi); - } -} + } else { -float SX1278::getInstRSSI(bool skipReceive) { - if(getActiveModem() == RADIOLIB_SX127X_LORA) { // for LoRa, get current RSSI - float currentRSSI; + float currentRSSI; // RSSI calculation uses different constant for low-frequency and high-frequency ports - if(_freq < 868.0) { - currentRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); - } else { - currentRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + if(_freq < 868.0) { + currentRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + } else { + currentRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + } + return(currentRSSI); } - return(currentRSSI); - + } else { // enable listen mode if(!skipReceive) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 51096cd5a2..23ff405499 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -251,20 +251,13 @@ class SX1278: public SX127x { /*! \brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode. - - \returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem. - */ - float getRSSI(bool skipReceive = false); - - /*! - \brief Gets current signal strength indicator of for LoRa modem, or current RSSI level for FSK modem. + \param packet Set to false to gets current RSSI measurement in LoRa mode. \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode. - \returns Current packet RSSI for LoRa modem, or FSK modem. + \returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem. */ - float getInstRSSI(bool skipReceive = false); + float getRSSI(bool packet = true, bool skipReceive = false); /*! \brief Enables/disables CRC check of received packets. From 50318a6c602c9b0bf31b8d399b7bef6306708993 Mon Sep 17 00:00:00 2001 From: G4lile0 Date: Mon, 27 Mar 2023 21:21:45 +0200 Subject: [PATCH 0439/1848] bool packet miss on SX126x::getRSSI --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 9a55b23699..4ffbc9e042 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1221,7 +1221,7 @@ float SX126x::getDataRate() const { return(_dataRate); } -float SX126x::getRSSI() { +float SX126x::getRSSI(bool packet) { if (packet) { // get last packet RSSI from packet status From ab9cf0d52839bf28bd1108cd3efc9ae367ac05e4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Mar 2023 23:21:37 +0200 Subject: [PATCH 0440/1848] [SX126x] Unified getRSSI interface --- src/modules/SX126x/SX126x.cpp | 18 ++++-------------- src/modules/SX126x/SX126x.h | 13 +++---------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 4ffbc9e042..ea01e08806 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1222,20 +1222,17 @@ float SX126x::getDataRate() const { } float SX126x::getRSSI(bool packet) { - - if (packet) { - // get last packet RSSI from packet status + if(packet) { + // get last packet RSSI from packet status uint32_t packetStatus = getPacketStatus(); uint8_t rssiPkt = packetStatus & 0xFF; return(-1.0 * rssiPkt/2.0); } else { - // get instantaneous RSSI value + // get instantaneous RSSI value uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); - - return (float)data[0] / (-2.0); + return((float)data[0] / (-2.0)); } - } float SX126x::getSNR() { @@ -1337,13 +1334,6 @@ uint32_t SX126x::getTimeOnAir(size_t len) { } } -float SX126x::getRSSIInst() { - uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); - - return (float)data[0] / (-2.0); -} - int16_t SX126x::implicitHeader(size_t len) { return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 6634ddf7ab..deb437af46 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -915,11 +915,11 @@ class SX126x: public PhysicalLayer { float getDataRate() const; /*! - \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \brief GetsRSSI (Recorded Signal Strength Indicator). - \param packet Set to false to gets current RSSI measurement in LoRa mode. + \param packet Whether to read last packet RSSI, or the current value. - \returns RSSI of the last received packet in dBm. + \returns RSSI value in dBm. */ float getRSSI(bool packet = true); @@ -975,13 +975,6 @@ class SX126x: public PhysicalLayer { */ uint32_t getTimeOnAir(size_t len); - /*! - \brief Get instantaneous RSSI value during recption of the packet. Should switch to FSK receive mode for LBT implementation. - - \returns Instantaneous RSSI value in dBm, in steps of 0.5dBm - */ - float getRSSIInst(); - /*! \brief Set implicit header mode for future reception/transmission. From f62f912c877e59ef8f55cf0654edd674f6b31158 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Mar 2023 23:22:03 +0200 Subject: [PATCH 0441/1848] [SX127x] Unified getRSSI interface --- src/modules/SX127x/SX1272.cpp | 33 ++------------------- src/modules/SX127x/SX1272.h | 10 ++++--- src/modules/SX127x/SX1278.cpp | 55 +++-------------------------------- src/modules/SX127x/SX1278.h | 8 ++--- src/modules/SX127x/SX127x.cpp | 41 ++++++++++++++++++++++++++ src/modules/SX127x/SX127x.h | 11 +++++++ 6 files changed, 68 insertions(+), 90 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 771555cac8..5c8722e420 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -352,37 +352,8 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { return(state); } -float SX1272::getRSSI(bool skipReceive) { - if(getActiveModem() == RADIOLIB_SX127X_LORA) { - // RSSI calculation uses different constant for low-frequency and high-frequency ports - float lastPacketRSSI = -139 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); - - // spread-spectrum modulation signal can be received below noise floor - // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value - float lastPacketSNR = SX127x::getSNR(); - if(lastPacketSNR < 0.0) { - lastPacketRSSI += lastPacketSNR; - } - - return(lastPacketRSSI); - - } else { - // enable listen mode - if(!skipReceive) { - startReceive(); - } - - // read the value for FSK - float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; - - // set mode back to standby - if(!skipReceive) { - standby(); - } - - // return the value - return(rssi); - } +float SX1272::getRSSI(bool packet, bool skipReceive) { + return(SX127x::getRSSI(packet, skipReceive, -139)); } int16_t SX1272::setCRC(bool enable, bool mode) { diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 8ef723f763..3c74c6da53 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -240,13 +240,15 @@ class SX1272: public SX127x { int16_t setDataShapingOOK(uint8_t sh); /*! - \brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem. + \brief Gets recorded signal strength indicator. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode. + \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. - \returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem. + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. + + \returns RSSI value in dBm. */ - float getRSSI(bool skipReceive = false); + float getRSSI(bool packet = true, bool skipReceive = false); /*! \brief Enables/disables CRC check of received packets. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index e06604bc70..0feb05fc5b 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -382,58 +382,11 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { } float SX1278::getRSSI(bool packet, bool skipReceive) { - if(getActiveModem() == RADIOLIB_SX127X_LORA) { - - if (packet) { - // for LoRa, get RSSI of the last packet - float lastPacketRSSI; - // RSSI calculation uses different constant for low-frequency and high-frequency ports - if(_freq < 868.0) { - lastPacketRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); - } else { - lastPacketRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); - } - - // spread-spectrum modulation signal can be received below noise floor - // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value - float lastPacketSNR = SX127x::getSNR(); - if(lastPacketSNR < 0.0) { - lastPacketRSSI += lastPacketSNR; - } - return(lastPacketRSSI); - - } else { - - // for LoRa, get current RSSI - float currentRSSI; - - // RSSI calculation uses different constant for low-frequency and high-frequency ports - if(_freq < 868.0) { - currentRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); - } else { - currentRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); - } - return(currentRSSI); - } - - - } else { - // enable listen mode - if(!skipReceive) { - startReceive(); - } - - // read the value for FSK - float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; - - // set mode back to standby - if(!skipReceive) { - standby(); - } - - // return the value - return(rssi); + int16_t offset = -157; + if(_freq < 868.0) { + offset = -164; } + return(SX127x::getRSSI(packet, skipReceive, offset)); } int16_t SX1278::setCRC(bool enable, bool mode) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 23ff405499..6db1b516a6 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -249,13 +249,13 @@ class SX1278: public SX127x { int16_t setDataShapingOOK(uint8_t sh); /*! - \brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem. + \brief Gets recorded signal strength indicator. - \param packet Set to false to gets current RSSI measurement in LoRa mode. + \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode. + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. - \returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem. + \returns RSSI value in dBm. */ float getRSSI(bool packet = true, bool skipReceive = false); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index dace7ae01e..bf74ca46a2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1552,4 +1552,45 @@ int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) { return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0); } +float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + if(packet) { + // LoRa packet mode, get RSSI of the last packet + float lastPacketRSSI = offset + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); + + // spread-spectrum modulation signal can be received below noise floor + // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value + float lastPacketSNR = SX127x::getSNR(); + if(lastPacketSNR < 0.0) { + lastPacketRSSI += lastPacketSNR; + } + return(lastPacketRSSI); + + } else { + // LoRa instant, get current RSSI + float currentRSSI = offset + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + return(currentRSSI); + } + + } else { + // for FSK, there is no packet RSSI + + // enable listen mode + if(!skipReceive) { + startReceive(); + } + + // read the value for FSK + float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; + + // set mode back to standby + if(!skipReceive) { + standby(); + } + + // return the value + return(rssi); + } +} + #endif diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e40a5de429..c3b8ca7d19 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1243,6 +1243,17 @@ class SX127x: public PhysicalLayer { */ int16_t setDIOPreambleDetect(bool usePreambleDetect); + /*! + \brief Gets recorded signal strength indicator. + + \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. + + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. + + \returns RSSI value in dBm. + */ + float getRSSI(bool packet, bool skipReceive, int16_t offset); + /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled From c400a1428e83b268ee9a0158e26c619e15b3d599 Mon Sep 17 00:00:00 2001 From: Davide Lasagna Date: Wed, 29 Mar 2023 18:21:18 +0100 Subject: [PATCH 0442/1848] fix #709 --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index d376d2e81b..50ccb80924 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -746,7 +746,7 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) From 642cbd8bfd7b4e77e1d39a2c05b3e8fea15c756b Mon Sep 17 00:00:00 2001 From: Davide Lasagna Date: Thu, 30 Mar 2023 09:49:50 +0100 Subject: [PATCH 0443/1848] added link to original issue --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 50ccb80924..76770580a8 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -746,7 +746,7 @@ #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) // see issue #709 #define RADIOLIB_NONVOLATILE PROGMEM #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) From 0210e10a249f6bb085dfbb5921c4bd9140ab0f4b Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 30 Mar 2023 23:17:34 +0200 Subject: [PATCH 0444/1848] [MOD] Fixed swapped NSS/BUSY order (#716) --- src/Module.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 7df4d0db8b..d715b13d85 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -336,9 +336,6 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #endif - // pull NSS low - this->digitalWrite(this->getCs(), LOW); - // ensure GPIO is low uint32_t start = this->millis(); while(this->digitalRead(this->getGpio())) { @@ -349,6 +346,9 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } } + // pull NSS low + this->digitalWrite(this->getCs(), LOW); + // start transfer this->SPIbeginTransaction(); From ece2621a6f5a09530d76e29de603ae79a841d940 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 31 Mar 2023 22:02:35 +0200 Subject: [PATCH 0445/1848] [SX126x] Fixed packet length in LoRa implicit mode --- src/modules/SX126x/SX126x.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ea0a10486d..44f95a1a12 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1287,6 +1287,12 @@ float SX126x::getFrequencyError() { size_t SX126x::getPacketLength(bool update) { (void)update; + + // in implicit mode, return the cached value + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) { + return(_implicitLen); + } + uint8_t rxBufStatus[2] = {0, 0}; _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); From 45c5859338590b7eede23cb2f95284c3fb0cf08e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 31 Mar 2023 22:02:58 +0200 Subject: [PATCH 0446/1848] [SX128x] Fixed packet length in implicit mode (#716) --- src/modules/SX128x/SX128x.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 70ddf18e12..3456e7c383 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1182,6 +1182,12 @@ float SX128x::getFrequencyError() { size_t SX128x::getPacketLength(bool update) { (void)update; + + // in implicit mode, return the cached value + if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) { + return(_payloadLen); + } + uint8_t rxBufStatus[2] = {0, 0}; _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); From 5f0cfa9bf62fb6d25ed61c2e54c2af3414847ac9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Apr 2023 21:01:13 +0200 Subject: [PATCH 0447/1848] [SX126x] Improved RNG --- src/modules/SX126x/SX126x.cpp | 8 ++++++++ src/modules/SX126x/SX126x.h | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 44f95a1a12..e00bea5eda 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1391,6 +1391,10 @@ int16_t SX126x::autoLDRO() { } uint8_t SX126x::randomByte() { + // set some magic registers + _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_ENABLED, 0, 0); + _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_ENABLED, 0, 0); + // set mode to Rx setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); @@ -1408,6 +1412,10 @@ uint8_t SX126x::randomByte() { // set mode to standby standby(); + // restore the magic registers + _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_DISABLED, 0, 0); + _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_DISABLED, 0, 0); + return(randByte); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2fb142bd13..a19c724896 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -114,6 +114,7 @@ #define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE #define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 #define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 +#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 #define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 @@ -132,8 +133,10 @@ #define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B #define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC #define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 +#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 #define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 #define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 +#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5 #define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 #define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 #define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 @@ -419,8 +422,17 @@ #define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed // RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW -#define RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window +#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window +// RADIOLIB_SX126X_REG_ANA_LNA +#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled +#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled + +// RADIOLIB_SX126X_REG_ANA_MIXER +#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled +#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled + +// size of the spectral scan result #define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) /*! @@ -1089,7 +1101,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t spectralScanStart(uint16_t numSamples, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); + int16_t spectralScanStart(uint16_t numSamples, uint8_t window = RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); /*! \brief Abort an ongoing spectral scan. From 8ddc80831d4291428258b77da40210f2b529a852 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 7 Apr 2023 09:11:44 +0200 Subject: [PATCH 0448/1848] Updated readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a163e7061b..5ab0c02a79 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,9 @@ The list above is by no means exhaustive - RadioLib code is independent of the u ### Where should I start? First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. If something isn't working as expected, try searching the [issues](https://github.com/jgromes/RadioLib/issues/). +### Does RadioLib require Arduino? +While RadioLib was originally written with Arduino in mind, it has since evolved and contains its own lightweight hardware abstraction layer. Thanks to this layer, RadioLib can be used on non-Arduino frameworks as well. See (this Wiki page)[https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms] for details. + ### Help, my module isn't working! The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new/choose) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently. From 696d628ce9ac9309be42cb64c4c3ccf9d444fe67 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 7 Apr 2023 09:12:25 +0200 Subject: [PATCH 0449/1848] Fixed readme link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ab0c02a79..05fda5a438 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ The list above is by no means exhaustive - RadioLib code is independent of the u First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. If something isn't working as expected, try searching the [issues](https://github.com/jgromes/RadioLib/issues/). ### Does RadioLib require Arduino? -While RadioLib was originally written with Arduino in mind, it has since evolved and contains its own lightweight hardware abstraction layer. Thanks to this layer, RadioLib can be used on non-Arduino frameworks as well. See (this Wiki page)[https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms] for details. +While RadioLib was originally written with Arduino in mind, it has since evolved and contains its own lightweight hardware abstraction layer. Thanks to this layer, RadioLib can be used on non-Arduino frameworks as well. See [this Wiki page](https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms) for details. ### Help, my module isn't working! The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new/choose) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently. From 13248b6eab6856c4d828ef7a97f613350f0f90ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 8 Apr 2023 21:44:14 +0200 Subject: [PATCH 0450/1848] [SX127x] Fixed comments --- src/modules/SX127x/SX127x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 2f16874e7d..5a4e9278d0 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1186,9 +1186,9 @@ class SX127x: public PhysicalLayer { int16_t getChipVersion(); /*! - \brief Enables/disables Invert the LoRa I and Q signals. + \brief Enable/disable inversion of the I and Q signals - \param invertIQ Enable (true) or disable (false) LoRa I and Q signals. + \param invertIQ QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ From 9dde85598bf9e3ab8fbfa4549646c7fe4f2ffdae Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 8 Apr 2023 21:44:51 +0200 Subject: [PATCH 0451/1848] [SX126x] Added IQ inversion --- src/modules/SX126x/SX126x.cpp | 13 +++++++++++++ src/modules/SX126x/SX126x.h | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e00bea5eda..ab30896125 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1419,6 +1419,19 @@ uint8_t SX126x::randomByte() { return(randByte); } +int16_t SX126x::invertIQ(bool invertIQ) { + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t invert = RADIOLIB_SX126X_LORA_IQ_STANDARD; + if(invertIQ) { + invert = RADIOLIB_SX126X_LORA_IQ_INVERTED; + } + + return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, invert)); +} + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index a19c724896..51a5b4c609 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1059,6 +1059,15 @@ class SX126x: public PhysicalLayer { */ uint8_t randomByte(); + /*! + \brief Enable/disable inversion of the I and Q signals + + \param invertIQ QI inversion enabled (true) or disabled (false); + + \returns \ref status_codes + */ + int16_t invertIQ(bool invertIQ); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. From 9d3a2bb72f0d0689a6d4049716a35367dea11667 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 8 Apr 2023 21:45:15 +0200 Subject: [PATCH 0452/1848] [SX128x] Added IQ inversion (#724) --- src/modules/SX128x/SX128x.cpp | 13 +++++++++++++ src/modules/SX128x/SX128x.h | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3456e7c383..5a2619c823 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1283,6 +1283,19 @@ uint8_t SX128x::randomByte() { return(0); } +int16_t SX128x::invertIQ(bool invertIQ) { + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t invert = RADIOLIB_SX128X_LORA_IQ_STANDARD; + if(invertIQ) { + invert = RADIOLIB_SX128X_LORA_IQ_INVERTED; + } + + return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, invert)); +} + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX128x::setDirectAction(void (*func)(void)) { // SX128x is unable to perform direct mode reception diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index a3600f3249..1aac8c74a9 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -829,6 +829,15 @@ class SX128x: public PhysicalLayer { */ uint8_t randomByte(); + /*! + \brief Enable/disable inversion of the I and Q signals + + \param invertIQ QI inversion enabled (true) or disabled (false); + + \returns \ref status_codes + */ + int16_t invertIQ(bool invertIQ); + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. From 8587f73bd98ada2f20e5147c3656c7b391cff28f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Apr 2023 17:08:45 +0200 Subject: [PATCH 0453/1848] [SX127x] Implemented fractional bit rate (#505) --- src/modules/RFM9x/RFM95.cpp | 7 +++++-- src/modules/RFM9x/RFM96.cpp | 7 +++++-- src/modules/SX127x/SX1272.cpp | 9 ++++++++- src/modules/SX127x/SX1272.h | 9 +++++++++ src/modules/SX127x/SX1276.cpp | 5 ++++- src/modules/SX127x/SX1277.cpp | 5 ++++- src/modules/SX127x/SX1278.cpp | 9 ++++++++- src/modules/SX127x/SX1278.h | 11 ++++++++++- src/modules/SX127x/SX1279.cpp | 5 ++++- src/modules/SX127x/SX127x.cpp | 16 +++++++++------- src/modules/SX127x/SX127x.h | 14 ++------------ 11 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 98dbdd1ab1..640645da2f 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -42,10 +42,10 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW int16_t RFM95::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, freqDev, rxBw, preambleLength, enableOOK); if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { // SX127X_REG_VERSION might be set 0x12 - state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); } else if(state != RADIOLIB_ERR_NONE) { // some other error @@ -62,6 +62,9 @@ int16_t RFM95::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index c2b4230a51..78427b71ae 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -43,10 +43,10 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW int16_t RFM96::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, freqDev, rxBw, preambleLength, enableOOK); if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { // SX127X_REG_VERSION might be set 0x12 - state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK); + state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); } else if(state != RADIOLIB_ERR_NONE) { // some other error @@ -63,6 +63,9 @@ int16_t RFM96::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 5c8722e420..27a0172255 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -38,7 +38,7 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1272_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1272_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -49,6 +49,9 @@ int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); @@ -216,6 +219,10 @@ int16_t SX1272::setCodingRate(uint8_t cr) { return(state); } +int16_t SX1272::setBitRate(float br) { + return(SX127x::setBitRateCommon(br, RADIOLIB_SX1272_REG_BIT_RATE_FRAC)); +} + int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 3c74c6da53..ccd21fdbd8 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -197,6 +197,15 @@ class SX1272: public SX127x { */ int16_t setCodingRate(uint8_t cr); + /*! + \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. + + \param br Bit rate to be set (in kbps). + + \returns \ref status_codes + */ + int16_t setBitRate(float br) override; + /*! \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index c4c32f9c92..c4e98502d1 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -34,7 +34,7 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -45,6 +45,9 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 59250e45ed..c66c8f435c 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -34,7 +34,7 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -45,6 +45,9 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 0feb05fc5b..c8e5832a6d 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -38,7 +38,7 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -49,6 +49,9 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); @@ -230,6 +233,10 @@ int16_t SX1278::setCodingRate(uint8_t cr) { return(state); } +int16_t SX1278::setBitRate(float br) { + return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC)); +} + int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 6db1b516a6..92273a19a8 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -14,7 +14,7 @@ #define RADIOLIB_SX1278_REG_TCXO 0x4B #define RADIOLIB_SX1278_REG_PA_DAC 0x4D #define RADIOLIB_SX1278_REG_FORMER_TEMP 0x5B -#define RADIOLIB_SX1278_REG_REG_BIT_RATE_FRAC 0x5D +#define RADIOLIB_SX1278_REG_BIT_RATE_FRAC 0x5D #define RADIOLIB_SX1278_REG_AGC_REF 0x61 #define RADIOLIB_SX1278_REG_AGC_THRESH_1 0x62 #define RADIOLIB_SX1278_REG_AGC_THRESH_2 0x63 @@ -205,6 +205,15 @@ class SX1278: public SX127x { */ int16_t setCodingRate(uint8_t cr); + /*! + \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. + + \param br Bit rate to be set (in kbps). + + \returns \ref status_codes + */ + int16_t setBitRate(float br) override; + /*! \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 1eac9dc9ae..1f0237bb0d 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -34,7 +34,7 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API @@ -45,6 +45,9 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setBitRate(br); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index e80aeb2001..0dc1cbb4e1 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -56,7 +56,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe return(state); } -int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { +int16_t SX127x::beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties _mod->init(); _mod->pinMode(_mod->getIrq(), INPUT); @@ -85,10 +85,6 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB state = setOOK(enableOOK); RADIOLIB_ASSERT(state); - // set bit rate - state = SX127x::setBitRate(br); - RADIOLIB_ASSERT(state); - // set frequency deviation state = SX127x::setFrequencyDeviation(freqDev); RADIOLIB_ASSERT(state); @@ -828,7 +824,7 @@ float SX127x::getDataRate() const { return(_dataRate); } -int16_t SX127x::setBitRate(float br) { +int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -851,7 +847,13 @@ int16_t SX127x::setBitRate(float br) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); - /// \todo fractional part of bit rate setting (not in OOK) + // set fractional part of bit rate + if(!_ook) { + float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRate; + uint8_t bitRateFrac = bitRateRem * 16; + state |= _mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0); + } + if(state == RADIOLIB_ERR_NONE) { SX127x::_br = br; } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 5a4e9278d0..a6faa65f6c 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -624,8 +624,6 @@ class SX127x: public PhysicalLayer { \param chipVersion Value in SPI version register. Used to verify the connection and hardware version. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). - \param freqDev Frequency deviation of the FSK transmission in kHz. \param rxBw Receiver bandwidth in kHz. @@ -636,7 +634,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); + int16_t beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -925,15 +923,6 @@ class SX127x: public PhysicalLayer { */ float getDataRate() const; - /*! - \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. - - \param br Bit rate to be set (in kbps). - - \returns \ref status_codes - */ - int16_t setBitRate(float br); - /*! \brief Sets FSK frequency deviation from carrier frequency. Allowed values depend on bit rate setting and must be lower than 200 kHz. Only available in FSK mode. @@ -1298,6 +1287,7 @@ class SX127x: public PhysicalLayer { size_t _packetLength = 0; int16_t setFrequencyRaw(float newFreq); + int16_t setBitRateCommon(float br, uint8_t fracRegAddr); int16_t config(); int16_t configFSK(); int16_t getActiveModem(); From 9d36ae4bee950b396b926168a7904958867b716b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Apr 2023 22:37:36 +0200 Subject: [PATCH 0454/1848] [MOD] Fixed SPI callbacks on non-Arduino platforms (#725) --- src/Module.cpp | 30 ++++++------------------------ src/Module.h | 2 +- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index d715b13d85..7c4fc74212 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -350,11 +350,11 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint this->digitalWrite(this->getCs(), LOW); // start transfer - this->SPIbeginTransaction(); + this->beginTransaction(); // send command byte(s) for(uint8_t n = 0; n < cmdLen; n++) { - this->SPItransfer(cmd[n]); + this->transfer(cmd[n]); } // variable to save error during SPI transfer @@ -364,7 +364,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint if(write) { for(size_t n = 0; n < numBytes; n++) { // send byte - uint8_t in = this->SPItransfer(dataOut[n]); + uint8_t in = this->transfer(dataOut[n]); #if defined(RADIOLIB_VERBOSE) debugBuff[n] = in; #endif @@ -377,7 +377,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } else { // skip the first byte for read-type commands (status-only) - uint8_t in = this->SPItransfer(this->SPInopCommand); + uint8_t in = this->transfer(this->SPInopCommand); #if defined(RADIOLIB_VERBOSE) debugBuff[0] = in; #endif @@ -392,13 +392,13 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // read the data if(state == RADIOLIB_ERR_NONE) { for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->SPItransfer(this->SPInopCommand); + dataIn[n] = this->transfer(this->SPInopCommand); } } } // stop transfer - this->SPIendTransaction(); + this->endTransaction(); this->digitalWrite(this->getCs(), HIGH); // wait for GPIO to go high and then low @@ -622,75 +622,57 @@ uint32_t Module::pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint3 } void Module::begin() { -#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIbegin == nullptr) { return; } (this->*cb_SPIbegin)(); -#endif } void Module::beginTransaction() { -#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIbeginTransaction == nullptr) { return; } (this->*cb_SPIbeginTransaction)(); -#endif } uint8_t Module::transfer(uint8_t b) { -#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPItransfer == nullptr) { return(0xFF); } return((this->*cb_SPItransfer)(b)); -#endif } void Module::endTransaction() { -#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIendTransaction == nullptr) { return; } (this->*cb_SPIendTransaction)(); -#endif } void Module::end() { -#if defined(RADIOLIB_BUILD_ARDUINO) if(cb_SPIend == nullptr) { return; } (this->*cb_SPIend)(); -#endif } #if defined(RADIOLIB_BUILD_ARDUINO) void Module::SPIbegin() { _spi->begin(); } -#endif void Module::SPIbeginTransaction() { -#if defined(RADIOLIB_BUILD_ARDUINO) _spi->beginTransaction(_spiSettings); -#endif } uint8_t Module::SPItransfer(uint8_t b) { -#if defined(RADIOLIB_BUILD_ARDUINO) return(_spi->transfer(b)); -#endif } void Module::SPIendTransaction() { -#if defined(RADIOLIB_BUILD_ARDUINO) _spi->endTransaction(); -#endif } -#if defined(RADIOLIB_BUILD_ARDUINO) void Module::SPIend() { _spi->end(); } diff --git a/src/Module.h b/src/Module.h index ac69b02e77..7091879ec3 100644 --- a/src/Module.h +++ b/src/Module.h @@ -663,10 +663,10 @@ class Module { #if defined(RADIOLIB_BUILD_ARDUINO) void SPIbegin(); void SPIend(); - #endif virtual void SPIbeginTransaction(); virtual uint8_t SPItransfer(uint8_t b); virtual void SPIendTransaction(); + #endif /*! \brief Function to reflect bits within a byte. From cdbb82709103f361705737393ec6d5cd3db22354 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 09:06:08 +0200 Subject: [PATCH 0455/1848] [CC1101] Removed references to Arduino SPI callbacks (#725) --- src/modules/CC1101/CC1101.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 4b1d7c30ba..ffad818a16 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1095,13 +1095,13 @@ void CC1101::SPIsendCommand(uint8_t cmd) { _mod->digitalWrite(_mod->getCs(), LOW); // start transfer - _mod->SPIbeginTransaction(); + _mod->beginTransaction(); // send the command byte - _mod->SPItransfer(cmd); + _mod->transfer(cmd); // stop transfer - _mod->SPIendTransaction(); + _mod->endTransaction(); _mod->digitalWrite(_mod->getCs(), HIGH); } From efc2e9f291a48871ff0e0ef2a0ba4eefd4811311 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 09:06:24 +0200 Subject: [PATCH 0456/1848] [nRF24] Removed references to Arduino SPI callbacks (#725) --- src/modules/nRF24/nRF24.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 28c207de13..e158a043e9 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -617,24 +617,24 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // start transfer _mod->digitalWrite(_mod->getCs(), LOW); - _mod->SPIbeginTransaction(); + _mod->beginTransaction(); // send command - _mod->SPItransfer(cmd); + _mod->transfer(cmd); // send data if(write) { for(uint8_t i = 0; i < numBytes; i++) { - _mod->SPItransfer(dataOut[i]); + _mod->transfer(dataOut[i]); } } else { for(uint8_t i = 0; i < numBytes; i++) { - dataIn[i] = _mod->SPItransfer(0x00); + dataIn[i] = _mod->transfer(0x00); } } // stop transfer - _mod->SPIendTransaction(); + _mod->endTransaction(); _mod->digitalWrite(_mod->getCs(), HIGH); } From f59a69f5c430ca26d4432a97a7f2f66ad001e2ff Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 09:06:40 +0200 Subject: [PATCH 0457/1848] [MOD] Removed references to Arduino SPI callbacks (#725) --- src/Module.cpp | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 7c4fc74212..256f763e6c 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -226,17 +226,17 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { // start SPI transaction - this->SPIbeginTransaction(); + this->beginTransaction(); // pull CS low this->digitalWrite(_cs, LOW); // send SPI register address with access command if(this->SPIaddrWidth <= 8) { - this->SPItransfer(reg | cmd); + this->transfer(reg | cmd); } else { - this->SPItransfer((reg >> 8) | cmd); - this->SPItransfer(reg & 0xFF); + this->transfer((reg >> 8) | cmd); + this->transfer(reg & 0xFF); } #if defined(RADIOLIB_VERBOSE) @@ -254,7 +254,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d if(cmd == SPIwriteCommand) { if(dataOut != NULL) { for(size_t n = 0; n < numBytes; n++) { - this->SPItransfer(dataOut[n]); + this->transfer(dataOut[n]); RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); } @@ -262,7 +262,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d } else if (cmd == SPIreadCommand) { if(dataIn != NULL) { for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->SPItransfer(0x00); + dataIn[n] = this->transfer(0x00); RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); RADIOLIB_VERBOSE_PRINT('\t'); } @@ -274,7 +274,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->digitalWrite(_cs, HIGH); // end SPI transaction - this->SPIendTransaction(); + this->endTransaction(); } int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { @@ -625,35 +625,55 @@ void Module::begin() { if(cb_SPIbegin == nullptr) { return; } + #if defined(RADIOLIB_BUILD_ARDUINO) (this->*cb_SPIbegin)(); + #else + cb_SPIbegin(); + #endif } void Module::beginTransaction() { if(cb_SPIbeginTransaction == nullptr) { return; } + #if defined(RADIOLIB_BUILD_ARDUINO) (this->*cb_SPIbeginTransaction)(); + #else + cb_SPIbeginTransaction(); + #endif } uint8_t Module::transfer(uint8_t b) { if(cb_SPItransfer == nullptr) { return(0xFF); } + #if defined(RADIOLIB_BUILD_ARDUINO) return((this->*cb_SPItransfer)(b)); + #else + return(cb_SPItransfer(b)); + #endif } void Module::endTransaction() { if(cb_SPIendTransaction == nullptr) { return; } + #if defined(RADIOLIB_BUILD_ARDUINO) (this->*cb_SPIendTransaction)(); + #else + cb_SPIendTransaction(); + #endif } void Module::end() { if(cb_SPIend == nullptr) { return; } + #if defined(RADIOLIB_BUILD_ARDUINO) (this->*cb_SPIend)(); + #else + cb_SPIend(); + #endif } #if defined(RADIOLIB_BUILD_ARDUINO) From 7c0fc5305a5b2dcbfc74256282d17b47cb17ecfc Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 10:29:21 +0200 Subject: [PATCH 0458/1848] [STM32WL] Fixed build for Platformio (#718) --- src/Module.h | 4 ++++ src/modules/SX126x/STM32WLx.cpp | 2 -- src/modules/SX126x/STM32WLx_Module.cpp | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module.h b/src/Module.h index 7091879ec3..9cb55db9c2 100644 --- a/src/Module.h +++ b/src/Module.h @@ -7,6 +7,10 @@ #include #endif +#if defined(STM32WLxx) + #include +#endif + /*! * Value to use as the last element in a mode table to indicate the * end of the table. diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 744f88c377..5a88d8c16a 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -9,8 +9,6 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include "STM32WLx.h" #if !defined(RADIOLIB_EXCLUDE_STM32WLX) -#include - STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index c824200a0d..0d94f4223d 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -9,8 +9,6 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #if !defined(RADIOLIB_EXCLUDE_STM32WLX) -#include - // This defines some dummy pin numbers (starting at NUM_DIGITAL_PINS to // guarantee these are not valid regular pin numbers) that can be passed // to the parent Module class, to be stored here and then passed back to From 390b425b399b8358817a17850008a0bbca4b05eb Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 11:11:17 +0200 Subject: [PATCH 0459/1848] [MOD] Fixed default Arduino callbacks for SPI (#725) --- src/Module.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 256f763e6c..df60214fb2 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -36,10 +36,10 @@ Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rs setCb_micros(::micros); setCb_pulseIn(::pulseIn); setCb_SPIbegin(&Module::SPIbegin); - setCb_SPIbeginTransaction(&Module::beginTransaction); - setCb_SPItransfer(&Module::transfer); - setCb_SPIendTransaction(&Module::endTransaction); - setCb_SPIend(&Module::end); + setCb_SPIbeginTransaction(&Module::SPIbeginTransaction); + setCb_SPItransfer(&Module::SPItransfer); + setCb_SPIendTransaction(&Module::SPIendTransaction); + setCb_SPIend(&Module::SPIend); } Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings): @@ -71,10 +71,10 @@ Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rs setCb_micros(::micros); setCb_pulseIn(::pulseIn); setCb_SPIbegin(&Module::SPIbegin); - setCb_SPIbeginTransaction(&Module::beginTransaction); - setCb_SPItransfer(&Module::transfer); - setCb_SPIendTransaction(&Module::endTransaction); - setCb_SPIend(&Module::end); + setCb_SPIbeginTransaction(&Module::SPIbeginTransaction); + setCb_SPItransfer(&Module::SPItransfer); + setCb_SPIendTransaction(&Module::SPIendTransaction); + setCb_SPIend(&Module::SPIend); } #else From 7b6fd24c8ec2fc60aea31094d1a5f9fd94ce8d39 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sat, 8 Apr 2023 19:56:41 +0000 Subject: [PATCH 0460/1848] fix non arduino build --- src/protocols/AX25/AX25.cpp | 2 ++ src/protocols/AX25/AX25.h | 2 ++ src/protocols/Hellschreiber/Hellschreiber.cpp | 4 +++ src/protocols/Hellschreiber/Hellschreiber.h | 4 +++ src/protocols/Morse/Morse.cpp | 4 +++ src/protocols/Morse/Morse.h | 4 +++ src/protocols/Pager/Pager.cpp | 4 +++ src/protocols/Pager/Pager.h | 4 +++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 ++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 8 ++++++ src/protocols/RTTY/RTTY.cpp | 26 +++++++++++-------- src/protocols/RTTY/RTTY.h | 8 ++++-- 12 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 8bc8de4bec..5b657c4107 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -194,9 +194,11 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea return(_phy->startDirect()); } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t destSSID) { return(transmit(str.c_str(), destCallsign, destSSID)); } +#endif int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) { // create control field diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index dcf0333419..608f09a78e 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -322,6 +322,7 @@ class AX25Client { */ int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preambleLen = 8); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Transmit unnumbered information (UI) frame. @@ -334,6 +335,7 @@ class AX25Client { \returns \ref status_codes */ int16_t transmit(String& str, const char* destCallsign, uint8_t destSSID = 0x00); + #endif /*! \brief Transmit unnumbered information (UI) frame. diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 78eb3bdbc5..2607142b8a 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -94,6 +94,7 @@ size_t HellClient::write(uint8_t b) { return(printGlyph(buff)); } +#if defined(RADIOLIB_BUILD_ARDUINO) size_t HellClient::print(__FlashStringHelper* fstr) { PGM_P p = reinterpret_cast(fstr); size_t n = 0; @@ -110,6 +111,7 @@ size_t HellClient::print(__FlashStringHelper* fstr) { size_t HellClient::print(const String& str) { return(HellClient::write((uint8_t*)str.c_str(), str.length())); } +#endif size_t HellClient::print(const char* str) { return(HellClient::write((uint8_t*)str, strlen(str))); @@ -163,6 +165,7 @@ size_t HellClient::println(void) { return(HellClient::print(' ')); } +#if defined(RADIOLIB_BUILD_ARDUINO) size_t HellClient::println(__FlashStringHelper* fstr) { size_t n = HellClient::print(fstr); n += HellClient::println(); @@ -174,6 +177,7 @@ size_t HellClient::println(const String& str) { n += HellClient::println(); return(n); } +#endif size_t HellClient::println(const char* str) { size_t n = HellClient::print(str); diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 59e1140976..1609168aae 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -135,8 +135,10 @@ class HellClient { size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); + #if defined(RADIOLIB_BUILD_ARDUINO) size_t print(__FlashStringHelper*); size_t print(const String &); + #endif size_t print(const char[]); size_t print(char); size_t print(unsigned char, int = DEC); @@ -147,8 +149,10 @@ class HellClient { size_t print(double, int = 2); size_t println(void); + #if defined(RADIOLIB_BUILD_ARDUINO) size_t println(__FlashStringHelper*); size_t println(const String &); + #endif size_t println(const char[]); size_t println(char); size_t println(unsigned char, int = DEC); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 8497259077..3fbe3dd4ea 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -179,6 +179,7 @@ size_t MorseClient::write(uint8_t b) { return(1); } +#if defined(RADIOLIB_BUILD_ARDUINO) size_t MorseClient::print(__FlashStringHelper* fstr) { PGM_P p = reinterpret_cast(fstr); size_t n = 0; @@ -195,6 +196,7 @@ size_t MorseClient::print(__FlashStringHelper* fstr) { size_t MorseClient::print(const String& str) { return(MorseClient::write((uint8_t*)str.c_str(), str.length())); } +#endif size_t MorseClient::print(const char* str) { return(MorseClient::write((uint8_t*)str, strlen(str))); @@ -247,6 +249,7 @@ size_t MorseClient::println(void) { return(MorseClient::write('^')); } +#if defined(RADIOLIB_BUILD_ARDUINO) size_t MorseClient::println(__FlashStringHelper* fstr) { size_t n = MorseClient::print(fstr); n += MorseClient::println(); @@ -258,6 +261,7 @@ size_t MorseClient::println(const String& str) { n += MorseClient::println(); return(n); } +#endif size_t MorseClient::println(const char* str) { size_t n = MorseClient::print(str); diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 0ae567e7f4..fe60cc7cf9 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -160,8 +160,10 @@ class MorseClient { size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); + #if defined(RADIOLIB_BUILD_ARDUINO) size_t print(__FlashStringHelper*); size_t print(const String &); + #endif size_t print(const char[]); size_t print(char); size_t print(unsigned char, int = DEC); @@ -172,8 +174,10 @@ class MorseClient { size_t print(double, int = 2); size_t println(void); + #if defined(RADIOLIB_BUILD_ARDUINO) size_t println(__FlashStringHelper*); size_t println(const String &); + #endif size_t println(const char[]); size_t println(char); size_t println(unsigned char, int = DEC); diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 32f401f60c..f6aae335a1 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -52,9 +52,11 @@ int16_t PagerClient::sendTone(uint32_t addr) { return(PagerClient::transmit(NULL, 0, addr)); } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding) { return(PagerClient::transmit(str.c_str(), addr, encoding)); } +#endif int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding) { return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding)); @@ -260,6 +262,7 @@ size_t PagerClient::available() { return(_phy->available() + sizeof(uint32_t))/(sizeof(uint32_t) * (RADIOLIB_PAGER_BATCH_LEN + 1)); } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { int16_t state = RADIOLIB_ERR_NONE; @@ -304,6 +307,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { return(state); } +#endif int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { // find the correct address diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 844150bce5..966033fbca 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -101,6 +101,7 @@ class PagerClient { */ int16_t sendTone(uint32_t addr); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino String transmit method. @@ -113,6 +114,7 @@ class PagerClient { \returns \ref status_codes */ int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + #endif /*! \brief C-string transmit method. @@ -164,6 +166,7 @@ class PagerClient { */ size_t available(); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Reads data that was received after calling startReceive method. @@ -177,6 +180,7 @@ class PagerClient { \returns \ref status_codes */ int16_t readData(String& str, size_t len = 0, uint32_t* addr = NULL); + #endif /*! \brief Reads data that was received after calling startReceive method. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 78acfebb56..46093ba9de 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -9,6 +9,7 @@ PhysicalLayer::PhysicalLayer(float freqStep, size_t maxPacketLength) { #endif } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { // read flash string length size_t len = 0; @@ -45,6 +46,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { int16_t PhysicalLayer::transmit(String& str, uint8_t addr) { return(transmit(str.c_str(), addr)); } +#endif int16_t PhysicalLayer::transmit(const char* str, uint8_t addr) { return(transmit((uint8_t*)str, strlen(str), addr)); @@ -57,6 +59,7 @@ int16_t PhysicalLayer::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_UNSUPPORTED); } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t PhysicalLayer::receive(String& str, size_t len) { int16_t state = RADIOLIB_ERR_NONE; @@ -103,6 +106,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { return(state); } +#endif int16_t PhysicalLayer::receive(uint8_t* data, size_t len) { (void)data; @@ -131,9 +135,11 @@ int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_ return(RADIOLIB_ERR_UNSUPPORTED); } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) { return(startTransmit(str.c_str(), addr)); } +#endif int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { return(startTransmit((uint8_t*)str, strlen(str), addr)); @@ -150,6 +156,7 @@ int16_t PhysicalLayer::finishTransmit() { return(RADIOLIB_ERR_UNSUPPORTED); } +#if defined(RADIOLIB_BUILD_ARDUINO) int16_t PhysicalLayer::readData(String& str, size_t len) { int16_t state = RADIOLIB_ERR_NONE; @@ -192,6 +199,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { return(state); } +#endif int16_t PhysicalLayer::readData(uint8_t* data, size_t len) { (void)data; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 915faf4508..ddf742b71a 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -27,6 +27,7 @@ class PhysicalLayer { // basic methods + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino Flash String transmit method. @@ -48,6 +49,7 @@ class PhysicalLayer { \returns \ref status_codes */ int16_t transmit(String& str, uint8_t addr = 0); + #endif /*! \brief C-string transmit method. @@ -73,6 +75,7 @@ class PhysicalLayer { */ virtual int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino String receive method. @@ -83,6 +86,7 @@ class PhysicalLayer { \returns \ref status_codes */ int16_t receive(String& str, size_t len = 0); + #endif /*! \brief Sets module to sleep. @@ -131,6 +135,7 @@ class PhysicalLayer { */ virtual int16_t receive(uint8_t* data, size_t len); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. Interrupt pin will be activated when transmission finishes. @@ -142,6 +147,7 @@ class PhysicalLayer { \returns \ref status_codes */ int16_t startTransmit(String& str, uint8_t addr = 0); + #endif /*! \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. @@ -175,6 +181,7 @@ class PhysicalLayer { */ virtual int16_t finishTransmit(); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Reads data that was received after calling startReceive method. @@ -186,6 +193,7 @@ class PhysicalLayer { \returns \ref status_codes */ int16_t readData(String& str, size_t len = 0); + #endif /*! \brief Reads data that was received after calling startReceive method. diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index e1994978aa..abd4c6cb14 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -209,6 +209,7 @@ size_t RTTYClient::write(uint8_t b) { return(1); } +#if defined(RADIOLIB_BUILD_ARDUINO) size_t RTTYClient::print(__FlashStringHelper* fstr) { // read flash string length size_t len = 0; @@ -247,13 +248,6 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { return(n); } -size_t RTTYClient::print(ITA2String& ita2) { - uint8_t* arr = ita2.byteArr(); - size_t n = RTTYClient::write(arr, ita2.length()); - delete[] arr; - return(n); -} - size_t RTTYClient::print(const String& str) { size_t n = 0; if(_encoding == RADIOLIB_ITA2) { @@ -264,6 +258,14 @@ size_t RTTYClient::print(const String& str) { } return(n); } +#endif + +size_t RTTYClient::print(ITA2String& ita2) { + uint8_t* arr = ita2.byteArr(); + size_t n = RTTYClient::write(arr, ita2.length()); + delete[] arr; + return(n); +} size_t RTTYClient::print(const char str[]) { size_t n = 0; @@ -337,20 +339,22 @@ size_t RTTYClient::println(void) { return(n); } +#if defined(RADIOLIB_BUILD_ARDUINO) size_t RTTYClient::println(__FlashStringHelper* fstr) { size_t n = RTTYClient::print(fstr); n += RTTYClient::println(); return(n); } -size_t RTTYClient::println(ITA2String& ita2) { - size_t n = RTTYClient::print(ita2); +size_t RTTYClient::println(const String& str) { + size_t n = RTTYClient::print(str); n += RTTYClient::println(); return(n); } +#endif -size_t RTTYClient::println(const String& str) { - size_t n = RTTYClient::print(str); +size_t RTTYClient::println(ITA2String& ita2) { + size_t n = RTTYClient::print(ita2); n += RTTYClient::println(); return(n); } diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index a26b144b1d..e663d92cf8 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -138,9 +138,11 @@ class RTTYClient { size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); + #if defined(RADIOLIB_BUILD_ARDUINO) size_t print(__FlashStringHelper*); - size_t print(ITA2String &); size_t print(const String &); + #endif + size_t print(ITA2String &); size_t print(const char[]); size_t print(char); size_t print(unsigned char, int = DEC); @@ -151,9 +153,11 @@ class RTTYClient { size_t print(double, int = 2); size_t println(void); + #if defined(RADIOLIB_BUILD_ARDUINO) size_t println(__FlashStringHelper*); - size_t println(ITA2String &); size_t println(const String &); + #endif + size_t println(ITA2String &); size_t println(const char[]); size_t println(char); size_t println(unsigned char, int = DEC); From 2a45f713840a170eebcec63fad50b4361226ce9d Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 9 Apr 2023 16:58:56 +0200 Subject: [PATCH 0461/1848] fix undef digitalread --- src/modules/CC1101/CC1101.cpp | 2 +- src/modules/RF69/RF69.cpp | 2 +- src/modules/SX126x/SX126x.cpp | 2 +- src/modules/SX127x/SX127x.cpp | 2 +- src/modules/Si443x/Si443x.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index ffad818a16..dfa57aea7c 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -946,7 +946,7 @@ void CC1101::setDirectAction(void (*func)(void)) { } void CC1101::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)digitalRead(pin)); + updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); } #endif diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 87b5715dfb..45f53203bc 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -959,7 +959,7 @@ void RF69::setDirectAction(void (*func)(void)) { } void RF69::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)digitalRead(pin)); + updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); } #endif diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ab30896125..5288153a63 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1438,7 +1438,7 @@ void SX126x::setDirectAction(void (*func)(void)) { } void SX126x::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)digitalRead(pin)); + updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); } #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 0dc1cbb4e1..b7c4d8f58b 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1521,7 +1521,7 @@ void SX127x::setDirectAction(void (*func)(void)) { } void SX127x::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)digitalRead(pin)); + updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); } #endif diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index a2ef639905..cabf6789be 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -612,7 +612,7 @@ void Si443x::setDirectAction(void (*func)(void)) { } void Si443x::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)digitalRead(pin)); + updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); } #endif From 67e4dd481530bdfb55088cd754c21aeb0aa753c2 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 9 Apr 2023 20:34:42 +0200 Subject: [PATCH 0462/1848] fix delayMicroseconds --- src/modules/CC1101/CC1101.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index dfa57aea7c..3ab475ded0 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -319,7 +319,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { * * TODO: test this on real hardware */ - delayMicroseconds(250); + _mod->delayMicroseconds(250); } } From 6456da188de8e0cb8014bd88504e42938ecbb387 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 9 Apr 2023 21:34:13 +0200 Subject: [PATCH 0463/1848] fix debug print --- src/BuildOpt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 76770580a8..c6b0583daf 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1044,10 +1044,10 @@ #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } #else #if !defined(RADIOLIB_DEBUG_PRINT) - #define RADIOLIB_DEBUG_PRINT(...) { frintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__); } + #define RADIOLIB_DEBUG_PRINT(...) { fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__); } #endif #if !defined(RADIOLIB_DEBUG_PRINTLN) - #define RADIOLIB_DEBUG_PRINTLN(...) { printf(RADIOLIB_DEBUG_PORT, __VA_ARGS__ "\n"); } + #define RADIOLIB_DEBUG_PRINTLN(...) { fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__ "\n"); } #endif #endif #else From 220b4dad7fa4ae7520f93e74df49bb4c6f050b46 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 9 Apr 2023 23:47:44 +0200 Subject: [PATCH 0464/1848] use printf in both build --- src/BuildOpt.h | 31 ++++++-- src/Module.cpp | 71 ++++++++----------- src/modules/CC1101/CC1101.cpp | 20 ++---- src/modules/RF69/RF69.cpp | 16 +---- src/modules/RFM9x/RFM95.cpp | 8 +-- src/modules/RFM9x/RFM96.cpp | 8 +-- src/modules/SX1231/SX1231.cpp | 18 ++--- src/modules/SX126x/SX126x.cpp | 47 +++++------- src/modules/SX127x/SX1272.cpp | 8 +-- src/modules/SX127x/SX1278.cpp | 8 +-- src/modules/SX127x/SX127x.cpp | 20 ++---- src/modules/SX128x/SX128x.cpp | 16 ++--- src/modules/Si443x/Si4430.cpp | 2 +- src/modules/Si443x/Si4431.cpp | 2 +- src/modules/Si443x/Si4432.cpp | 2 +- src/modules/Si443x/Si443x.cpp | 32 ++------- src/modules/nRF24/nRF24.cpp | 4 +- src/protocols/Morse/Morse.cpp | 14 ++-- src/protocols/Pager/Pager.cpp | 4 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 +-- 20 files changed, 127 insertions(+), 212 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index c6b0583daf..0c02b351a2 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1040,14 +1040,37 @@ #if defined(RADIOLIB_DEBUG) #if defined(RADIOLIB_BUILD_ARDUINO) - #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } - #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } +// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 +size_t serialPrintf(const char *format, ...) { + va_list arg; + va_start(arg, format); + char temp[64]; + char* buffer = temp; + size_t len = vsnprintf(temp, sizeof(temp), format, arg); + va_end(arg); + if (len > sizeof(temp) - 1) { + buffer = new char[len + 1]; + if (!buffer) { + return 0; + } + va_start(arg, format); + vsnprintf(buffer, len + 1, format, arg); + va_end(arg); + } + len = RADIOLIB_DEBUG_PORT.write((const uint8_t*) buffer, len); + if (buffer != temp) { + delete[] buffer; + } + return len; +} + #define RADIOLIB_DEBUG_PRINT(...) serialPrintf(__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) serialPrintf(M "\n", ##__VA_ARGS__) #else #if !defined(RADIOLIB_DEBUG_PRINT) - #define RADIOLIB_DEBUG_PRINT(...) { fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__); } + #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) #endif #if !defined(RADIOLIB_DEBUG_PRINTLN) - #define RADIOLIB_DEBUG_PRINTLN(...) { fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__ "\n"); } + #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) #endif #endif #else diff --git a/src/Module.cpp b/src/Module.cpp index df60214fb2..77e4906d00 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -160,24 +160,26 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t } } + #if defined(RADIOLIB_DEBUG) && defined(RADIOLIB_BUILD_ARDUINO) + #define DEBUG_BIN(x) RADIOLIB_DEBUG_PORT.println(x, BIN) + #else // no bin representation, fallback to hex + #define DEBUG_BIN(x) RADIOLIB_DEBUG_PRINTLN("%X", x) + #endif + // check failed, print debug info RADIOLIB_DEBUG_PRINTLN(); - RADIOLIB_DEBUG_PRINT(F("address:\t0x")); - RADIOLIB_DEBUG_PRINTLN(reg, HEX); - RADIOLIB_DEBUG_PRINT(F("bits:\t\t")); - RADIOLIB_DEBUG_PRINT(msb); - RADIOLIB_DEBUG_PRINT(' '); - RADIOLIB_DEBUG_PRINTLN(lsb); - RADIOLIB_DEBUG_PRINT(F("value:\t\t0b")); - RADIOLIB_DEBUG_PRINTLN(value, BIN); - RADIOLIB_DEBUG_PRINT(F("current:\t0b")); - RADIOLIB_DEBUG_PRINTLN(currentValue, BIN); - RADIOLIB_DEBUG_PRINT(F("mask:\t\t0b")); - RADIOLIB_DEBUG_PRINTLN(mask, BIN); - RADIOLIB_DEBUG_PRINT(F("new:\t\t0b")); - RADIOLIB_DEBUG_PRINTLN(newValue, BIN); - RADIOLIB_DEBUG_PRINT(F("read:\t\t0b")); - RADIOLIB_DEBUG_PRINTLN(readValue, BIN); + RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg); + RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb); + RADIOLIB_DEBUG_PRINT("value:\t\t0b"); + DEBUG_BIN(value); + RADIOLIB_DEBUG_PRINT("current:\t0b"); + DEBUG_BIN(currentValue); + RADIOLIB_DEBUG_PRINT("mask:\t\t0b"); + DEBUG_BIN(mask); + RADIOLIB_DEBUG_PRINT("new:\t\t0b"); + DEBUG_BIN(newValue); + RADIOLIB_DEBUG_PRINT("read:\t\t0b"); + DEBUG_BIN(readValue); RADIOLIB_DEBUG_PRINTLN(); return(RADIOLIB_ERR_SPI_WRITE_FAILED); @@ -241,13 +243,11 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d #if defined(RADIOLIB_VERBOSE) if(cmd == SPIwriteCommand) { - RADIOLIB_VERBOSE_PRINT('W'); + RADIOLIB_VERBOSE_PRINT("W"); } else if(cmd == SPIreadCommand) { - RADIOLIB_VERBOSE_PRINT('R'); + RADIOLIB_VERBOSE_PRINT("R"); } - RADIOLIB_VERBOSE_PRINT('\t') - RADIOLIB_VERBOSE_PRINT(reg, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT("\t%X\t", reg); #endif // send data or get response @@ -255,16 +255,14 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d if(dataOut != NULL) { for(size_t n = 0; n < numBytes; n++) { this->transfer(dataOut[n]); - RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT("%X\t", dataOut[n]); } } } else if (cmd == SPIreadCommand) { if(dataIn != NULL) { for(size_t n = 0; n < numBytes; n++) { dataIn[n] = this->transfer(0x00); - RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT("%X\t", dataIn[n]); } } } @@ -419,8 +417,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // print command byte(s) RADIOLIB_VERBOSE_PRINT("CMD\t"); for(uint8_t n = 0; n < cmdLen; n++) { - RADIOLIB_VERBOSE_PRINT(cmd[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]); } RADIOLIB_VERBOSE_PRINTLN(); @@ -429,25 +426,14 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint if(write) { RADIOLIB_VERBOSE_PRINT("W\t"); for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT("%X\t%X\t", dataOut[n], debugBuff[n]); } RADIOLIB_VERBOSE_PRINTLN(); } else { - RADIOLIB_VERBOSE_PRINT("R\t"); - // skip the first byte for read-type commands (status-only) - RADIOLIB_VERBOSE_PRINT(this->SPInopCommand, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); - RADIOLIB_VERBOSE_PRINT('\t') + RADIOLIB_VERBOSE_PRINT("R\t%X\t%X\t", this->SPInopCommand, debugBuff[0]); for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT(this->SPInopCommand, HEX); - RADIOLIB_VERBOSE_PRINT('\t'); - RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT("%X\t%X\t", this->SPInopCommand, dataIn[n]); } RADIOLIB_VERBOSE_PRINTLN(); } @@ -752,7 +738,8 @@ void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, for(size_t j = line_len; j < 16; j++) { sprintf(&str[58 + j], " "); } - RADIOLIB_DEBUG_PRINTLN(str); + RADIOLIB_DEBUG_PRINT(str); + RADIOLIB_DEBUG_PRINTLN(); rem_len -= 16; } } diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 3ab475ded0..252ca8a2d2 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -24,28 +24,18 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { flagFound = true; } else { - #if defined(RADIOLIB_DEBUG) - RADIOLIB_DEBUG_PRINT(F("CC1101 not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_CC1101_REG_VERSION == ")); - - char buffHex[7]; - sprintf(buffHex, "0x%04X", version); - RADIOLIB_DEBUG_PRINT(buffHex); - RADIOLIB_DEBUG_PRINT(F(", expected 0x0004/0x0014")); - RADIOLIB_DEBUG_PRINTLN(); - #endif + RADIOLIB_DEBUG_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); _mod->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN(F("No CC1101 found!")); + RADIOLIB_DEBUG_PRINTLN("No CC1101 found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN(F("M\tCC1101")); + RADIOLIB_DEBUG_PRINTLN("M\tCC1101"); } // configure settings not accessible by API @@ -388,7 +378,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { if (bytesInFIFO == 0) { if (millis() - lastPop > 5) { // readData was required to read a packet longer than the one received. - RADIOLIB_DEBUG_PRINTLN(F("No data for more than 5mS. Stop here.")); + RADIOLIB_DEBUG_PRINTLN("No data for more than 5mS. Stop here."); break; } else { delay(1); @@ -919,7 +909,7 @@ void CC1101::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_M uint8_t CC1101::randomByte() { // set mode to Rx SPIsendCommand(RADIOLIB_CC1101_CMD_RX); - RADIOLIB_DEBUG_PRINTLN("random"); + RADIOLIB_DEBUG_PRINTLN("CC1101::randomByte"); // wait a bit for the RSSI reading to stabilise _mod->delay(10); diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 45f53203bc..a33e245f36 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -26,28 +26,18 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe if(version == RADIOLIB_RF69_CHIP_VERSION) { flagFound = true; } else { - #if defined(RADIOLIB_DEBUG) - RADIOLIB_DEBUG_PRINT(F("RF69 not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_RF69_REG_VERSION == ")); - - char buffHex[7]; - sprintf(buffHex, "0x%04X", version); - RADIOLIB_DEBUG_PRINT(buffHex); - RADIOLIB_DEBUG_PRINT(F(", expected 0x0024")); - RADIOLIB_DEBUG_PRINTLN(); - #endif + RADIOLIB_DEBUG_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); _mod->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN(F("No RF69 found!")); + RADIOLIB_DEBUG_PRINTLN("No RF69 found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN(F("M\tRF69")); + RADIOLIB_DEBUG_PRINTLN("M\tRF69"); } // configure settings not accessible by API diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 640645da2f..892fc53c6f 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -16,8 +16,8 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW // some other error return(state); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); - RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95")); + RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); + RADIOLIB_DEBUG_PRINTLN("M\tRFM95"); // configure publicly accessible settings state = setBandwidth(bw); @@ -51,8 +51,8 @@ int16_t RFM95::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t // some other error return(state); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); - RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95")); + RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); + RADIOLIB_DEBUG_PRINTLN("M\tRFM95"); // configure settings not accessible by API state = configFSK(); diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index 78427b71ae..2f7f451a35 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -16,8 +16,8 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW // some other error return(state); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); - RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96")); + RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); + RADIOLIB_DEBUG_PRINTLN("M\tRFM96"); // configure publicly accessible settings state = setBandwidth(bw); @@ -52,8 +52,8 @@ int16_t RFM96::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t // some other error return(state); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); - RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96")); + RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); + RADIOLIB_DEBUG_PRINTLN("M\tRFM96"); // configure settings not accessible by API state = configFSK(); diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index c3e750c96c..8e81d89263 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -20,33 +20,23 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; _chipRevision = version; } else { - #if defined(RADIOLIB_DEBUG) - RADIOLIB_DEBUG_PRINT(F("SX1231 not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RF69_REG_VERSION == ")); - - char buffHex[12]; - sprintf(buffHex, "0x%04X", version); - RADIOLIB_DEBUG_PRINT(buffHex); - RADIOLIB_DEBUG_PRINT(F(", expected 0x0021 / 0x0022 / 0x0023")); - RADIOLIB_DEBUG_PRINTLN(); - #endif + RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); _mod->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!")); + RADIOLIB_DEBUG_PRINTLN("No SX1231 found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX1231")); + RADIOLIB_DEBUG_PRINTLN("M\tSX1231"); // configure settings not accessible by API int16_t state = config(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN(F("M\tRF69")); + RADIOLIB_DEBUG_PRINTLN("M\tRF69"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 5288153a63..b5ed718838 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -24,11 +24,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo // try to find the SX126x chip if(!SX126x::findChip(_chipType)) { - RADIOLIB_DEBUG_PRINTLN(F("No SX126x found!")); + RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams // set the defaults, this will get overwritten later anyway @@ -106,11 +106,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL // try to find the SX126x chip if(!SX126x::findChip(_chipType)) { - RADIOLIB_DEBUG_PRINTLN(F("No SX126x found!")); + RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); // initialize configuration variables (will be overwritten during public settings configuration) _br = 21333; // 48.0 kbps @@ -245,9 +245,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINT(F("Timeout in ")); - RADIOLIB_DEBUG_PRINT(timeout); - RADIOLIB_DEBUG_PRINTLN(F(" us")); + RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -296,9 +294,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINT(F("Timeout in ")); - RADIOLIB_DEBUG_PRINT(timeout); - RADIOLIB_DEBUG_PRINTLN(F(" us")); + RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); @@ -594,8 +590,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t symbolLength = ((uint32_t)(10 * 1000) << _sf) / (10 * _bwKhz); uint32_t sleepPeriod = symbolLength * sleepSymbols; - RADIOLIB_DEBUG_PRINT(F("Auto sleep period: ")); - RADIOLIB_DEBUG_PRINTLN(sleepPeriod); + RADIOLIB_DEBUG_PRINTLN("Auto sleep period: %d", sleepPeriod); // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. // the duration is sleepPeriod + 2 * wakePeriod. @@ -606,8 +601,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t wakePeriod = max( (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) symbolLength * (minSymbols + 1)); //(B) - RADIOLIB_DEBUG_PRINT(F("Auto wake period: ")); - RADIOLIB_DEBUG_PRINTLN(wakePeriod); + RADIOLIB_DEBUG_PRINTLN("Auto wake period: ", wakePeriod); // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < _tcxoDelay + 1016) { @@ -1451,8 +1445,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) #if defined(RADIOLIB_DEBUG) char ver_pre[16]; _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); - RADIOLIB_DEBUG_PRINT(F("Pre-update version string: ")); - RADIOLIB_DEBUG_PRINTLN(ver_pre); + RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %d", ver_pre); #endif // enable patch update @@ -1484,8 +1477,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) #if defined(RADIOLIB_DEBUG) char ver_post[16]; _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); - RADIOLIB_DEBUG_PRINT(F("Post-update version string: ")); - RADIOLIB_DEBUG_PRINTLN(ver_post); + RADIOLIB_DEBUG_PRINTLN("Post-update version string: %d", ver_post); #endif return(state); @@ -1712,8 +1704,7 @@ int16_t SX126x::calibrateImage(uint8_t* data) { // unless mode is forced to standby, device errors will be 0 standby(); uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_PRINT("Calibration failed, device errors: 0x"); - RADIOLIB_DEBUG_PRINTLN(errors, HEX); + RADIOLIB_DEBUG_PRINTLN("Calibration failed, device errors: 0x%X", errors); } #endif return(state); @@ -1766,9 +1757,7 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); + RADIOLIB_DEBUG_PRINTLN("Symbol length: %d ms", symbolLength); if(symbolLength >= 16.0) { _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; } else { @@ -1976,8 +1965,7 @@ int16_t SX126x::config(uint8_t modem) { // unless mode is forced to standby, device errors will be 0 standby(); uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_PRINT("Calibration failed, device errors: 0x"); - RADIOLIB_DEBUG_PRINTLN(errors, HEX); + RADIOLIB_DEBUG_PRINTLN("Calibration failed, device errors: 0x%X", errors); } #endif @@ -2010,18 +1998,15 @@ bool SX126x::findChip(const char* verStr) { // check version register if(strncmp(verStr, version, 6) == 0) { - RADIOLIB_DEBUG_PRINTLN(F("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:")); + RADIOLIB_DEBUG_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN(); flagFound = true; } else { #if defined(RADIOLIB_DEBUG) - RADIOLIB_DEBUG_PRINT(F("SX126x not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:")); + RADIOLIB_DEBUG_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); - RADIOLIB_DEBUG_PRINT(F("Expected string: ")); - RADIOLIB_DEBUG_PRINTLN(verStr); + RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); #endif _mod->delay(10); i++; diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 27a0172255..64b75ba756 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -116,9 +116,7 @@ int16_t SX1272::setBandwidth(float bw) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); + RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { @@ -172,9 +170,7 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); + RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index c8e5832a6d..aeb947f0ef 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -130,9 +130,7 @@ int16_t SX1278::setBandwidth(float bw) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); + RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { @@ -186,9 +184,7 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); + RADIOLIB_DEBUG_PRINT("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b7c4d8f58b..e87428583e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -17,11 +17,11 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { - RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!")); + RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX127x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); // set mode to standby int16_t state = standby(); @@ -64,11 +64,11 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_ // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { - RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!")); + RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN(F("M\tSX127x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); // set mode to standby int16_t state = standby(); @@ -1434,17 +1434,7 @@ bool SX127x::findChip(uint8_t ver) { if(version == ver) { flagFound = true; } else { - #if defined(RADIOLIB_DEBUG) - RADIOLIB_DEBUG_PRINT(F("SX127x not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_SX127X_REG_VERSION == ")); - - char buffHex[12]; - sprintf(buffHex, "0x%04X", version); - RADIOLIB_DEBUG_PRINT(buffHex); - RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); - RADIOLIB_DEBUG_PRINTLN(ver, HEX); - #endif + RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X, expected 0x00%X", i + 1, version, ver); _mod->delay(10); i++; } diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 5a2619c823..8c6ec31a56 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -20,7 +20,7 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize LoRa modulation variables _bwKhz = bw; @@ -81,7 +81,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize GFSK modulation variables _brKbps = br; @@ -150,7 +150,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize BLE modulation variables _brKbps = br; @@ -205,7 +205,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; _mod->SPIstreamType = true; _mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); + RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize FLRC modulation variables _brKbps = br; @@ -311,9 +311,7 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (500% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 5; - RADIOLIB_DEBUG_PRINT(F("Timeout in ")); - RADIOLIB_DEBUG_PRINT(timeout); - RADIOLIB_DEBUG_PRINTLN(F(" us")); + RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -346,9 +344,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // calculate timeout (1000% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 10; - RADIOLIB_DEBUG_PRINT(F("Timeout in ")); - RADIOLIB_DEBUG_PRINT(timeout); - RADIOLIB_DEBUG_PRINTLN(F(" us")); + RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index d6f40326fb..ecc8d8c6b7 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -9,7 +9,7 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN(F("M\tSi4430")); + RADIOLIB_DEBUG_PRINTLN("M\tSi4430"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 832ed4324b..98b07a8fec 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -9,7 +9,7 @@ int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN(F("M\tSi4431")); + RADIOLIB_DEBUG_PRINTLN("M\tSi4431"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 06921add6d..76147df439 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -9,7 +9,7 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN(F("M\tSi4432")); + RADIOLIB_DEBUG_PRINTLN("M\tSi4432"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index cabf6789be..8571900423 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -18,11 +18,11 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) // try to find the Si443x chip if(!Si443x::findChip()) { - RADIOLIB_DEBUG_PRINTLN(F("No Si443x found!")); + RADIOLIB_DEBUG_PRINTLN("No Si443x found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN(F("M\tSi443x")); + RADIOLIB_DEBUG_PRINTLN("M\tSi443x"); } // reset the device @@ -683,17 +683,7 @@ bool Si443x::findChip() { if(version == RADIOLIB_SI443X_DEVICE_VERSION) { flagFound = true; } else { - #if defined(RADIOLIB_DEBUG) - RADIOLIB_DEBUG_PRINT(F("Si443x not found! (")); - RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == ")); - - char buffHex[5]; - sprintf(buffHex, "0x%02X", version); - RADIOLIB_DEBUG_PRINT(buffHex); - RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); - RADIOLIB_DEBUG_PRINTLN(RADIOLIB_SI443X_DEVICE_VERSION, HEX); - #endif + RADIOLIB_DEBUG_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); _mod->delay(10); i++; } @@ -762,20 +752,8 @@ int16_t Si443x::updateClockRecovery() { uint16_t rxOsr_fixed = (uint16_t)rxOsr; // print that whole mess - RADIOLIB_DEBUG_PRINTLN(bypass, HEX); - RADIOLIB_DEBUG_PRINTLN(decRate, HEX); - RADIOLIB_DEBUG_PRINTLN(manch, HEX); - RADIOLIB_DEBUG_PRINT(rxOsr, 3); - RADIOLIB_DEBUG_PRINT('\t'); - RADIOLIB_DEBUG_PRINT(rxOsr_fixed); - RADIOLIB_DEBUG_PRINT('\t'); - RADIOLIB_DEBUG_PRINTLN(rxOsr_fixed, HEX); - RADIOLIB_DEBUG_PRINT(ncoOff); - RADIOLIB_DEBUG_PRINT('\t'); - RADIOLIB_DEBUG_PRINTLN(ncoOff, HEX); - RADIOLIB_DEBUG_PRINT(crGain); - RADIOLIB_DEBUG_PRINT('\t'); - RADIOLIB_DEBUG_PRINTLN(crGain, HEX); + RADIOLIB_DEBUG_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); + RADIOLIB_DEBUG_PRINTLN("%f\t%d\t%X\n%d\t%X\n%d\t%X", rxOsr, rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); // update oversampling ratio int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index e158a043e9..d8194d217a 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -26,11 +26,11 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW // check SPI connection int16_t val = _mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); if(!((val >= 0) && (val <= 3))) { - RADIOLIB_DEBUG_PRINTLN(F("No nRF24 found!")); + RADIOLIB_DEBUG_PRINTLN("No nRF24 found!"); _mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN(F("M\tnRF24")); + RADIOLIB_DEBUG_PRINTLN("M\tnRF24"); // configure settings inaccessible by public API int16_t state = config(); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 3fbe3dd4ea..7810032f20 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -91,17 +91,15 @@ int MorseClient::read(byte* symbol, byte* len, float low, float high) { uint32_t signalLen = mod->millis() - signalStart; if((signalLen >= low*(float)_dotLength) && (signalLen <= high*(float)_dotLength)) { - RADIOLIB_DEBUG_PRINT('.'); + RADIOLIB_DEBUG_PRINT("."); (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); (*len)++; } else if((signalLen >= low*(float)_dashLength) && (signalLen <= high*(float)_dashLength)) { - RADIOLIB_DEBUG_PRINT('-'); + RADIOLIB_DEBUG_PRINT("-"); (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); (*len)++; } else { - RADIOLIB_DEBUG_PRINT(""); + RADIOLIB_DEBUG_PRINTLN("", signalLen); } } @@ -135,7 +133,7 @@ size_t MorseClient::write(uint8_t b) { // inter-word pause (space) if(b == ' ') { - RADIOLIB_DEBUG_PRINTLN(F("space")); + RADIOLIB_DEBUG_PRINTLN("space"); standby(); mod->waitForMicroseconds(mod->micros(), _wordSpace*1000); return(1); @@ -154,11 +152,11 @@ size_t MorseClient::write(uint8_t b) { // send dot or dash if (code & RADIOLIB_MORSE_DASH) { - RADIOLIB_DEBUG_PRINT('-'); + RADIOLIB_DEBUG_PRINT("-"); transmitDirect(_base, _baseHz); mod->waitForMicroseconds(mod->micros(), _dashLength*1000); } else { - RADIOLIB_DEBUG_PRINT('.'); + RADIOLIB_DEBUG_PRINT("."); transmitDirect(_base, _baseHz); mod->waitForMicroseconds(mod->micros(), _dotLength*1000); } diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index f6aae335a1..5a51030871 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -496,9 +496,7 @@ uint32_t PagerClient::read() { codeWord = ~codeWord; } - RADIOLIB_VERBOSE_PRINT("R\t"); - RADIOLIB_VERBOSE_PRINTLN(codeWord, HEX); - + RADIOLIB_VERBOSE_PRINTLN("R\t%X", codeWord); // TODO BCH error correction here return(codeWord); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 46093ba9de..48eeda6103 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -274,7 +274,7 @@ int32_t PhysicalLayer::random(int32_t max) { if(randNum < 0) { randNum *= -1; } - RADIOLIB_DEBUG_PRINTLN(randNum); + RADIOLIB_DEBUG_PRINTLN("%d", randNum); return(randNum % max); } @@ -346,8 +346,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { _syncBuffer <<= 1; _syncBuffer |= bit; - RADIOLIB_VERBOSE_PRINT("S\t"); - RADIOLIB_VERBOSE_PRINTLN(_syncBuffer, HEX); + RADIOLIB_VERBOSE_PRINTLN("S\t%X", _syncBuffer); if((_syncBuffer & _directSyncWordMask) == _directSyncWord) { _gotSync = true; @@ -368,8 +367,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check complete byte if(_bufferBitPos == 8) { _buffer[_bufferWritePos] = Module::flipBits(_buffer[_bufferWritePos]); - RADIOLIB_VERBOSE_PRINT("R\t"); - RADIOLIB_VERBOSE_PRINTLN(_buffer[_bufferWritePos], HEX); + RADIOLIB_VERBOSE_PRINTLN("R\t%X", _buffer[_bufferWritePos]); _bufferWritePos++; _bufferBitPos = 0; From cccc9742bbd1c62150b48acf7ec74b721fb9ffc0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 11:20:35 +0200 Subject: [PATCH 0465/1848] [CI] Skip SSTV examples for Arduino Uno (not enough RAM) --- .github/workflows/main.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 77630a1dd8..f05c5c5ec3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,7 +70,11 @@ jobs: echo "warnings=all" >> $GITHUB_OUTPUT # platform-dependent settings - extra board options, board index URLs, skip patterns etc. - if [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then + if [[ "${{ contains(matrix.board, 'arduino:avr:uno') }}" == "true" ]]; then + # Arduino Uno + echo "skip-pattern=(STM32WL|SSTV)" >> $GITHUB_OUTPUT + + elif [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then # Arduino Mega echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT From b9fb0893b34e5e41e782afc2550fd4b53bdd6a5e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 11:54:59 +0200 Subject: [PATCH 0466/1848] [SX127x] Added missing explicit CRC configuration --- src/modules/SX127x/SX1273.cpp | 4 ++++ src/modules/SX127x/SX1276.cpp | 4 ++++ src/modules/SX127x/SX1277.cpp | 4 ++++ src/modules/SX127x/SX1278.cpp | 4 ++-- src/modules/SX127x/SX1279.cpp | 4 ++++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 9856e3d269..06f7b78523 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -29,6 +29,10 @@ int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setGain(gain); RADIOLIB_ASSERT(state); + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index c4e98502d1..b937a8f45f 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -29,6 +29,10 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setGain(gain); RADIOLIB_ASSERT(state); + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index c66c8f435c..cc49a69c21 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -29,6 +29,10 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setGain(gain); RADIOLIB_ASSERT(state); + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index c8e5832a6d..94bfb55be6 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -470,12 +470,12 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? RADIOLIB_SX1278_RX_CRC_MODE_ON : RADIOLIB_SX1278_RX_CRC_MODE_OFF), 7, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? RADIOLIB_SX1278_RX_CRC_MODE_ON : RADIOLIB_SX1278_RX_CRC_MODE_OFF), 7, 2); + state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 1f0237bb0d..e191e6c7b0 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -29,6 +29,10 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setGain(gain); RADIOLIB_ASSERT(state); + // set publicly accessible settings that are not a part of begin method + state = setCRC(true); + RADIOLIB_ASSERT(state); + return(state); } From 0f5b31aa3ae2f07365eed18b5aec317680a9a960 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 13:57:00 +0200 Subject: [PATCH 0467/1848] [SX127x] Removed standby before data read --- .../SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino | 3 --- src/modules/SX127x/SX127x.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 6c0997bcf6..ca33a35ed9 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -139,8 +139,5 @@ void loop() { Serial.println(state); } - - // put module back to listen mode - radio.startReceive(); } } diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 0dc1cbb4e1..d28d985803 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -598,9 +598,6 @@ int16_t SX127x::finishTransmit() { int16_t SX127x::readData(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); - // put module to standby - standby(); - // get packet length size_t length = getPacketLength(); size_t dumpLen = 0; From c8b28887ee2f9349ece0cfba67f48102528f98fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 14:03:37 +0200 Subject: [PATCH 0468/1848] [SX127x] Fixed comment --- .../SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index ca33a35ed9..c1ba3ced1a 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -71,7 +71,6 @@ void setup() { // radio.sleep() // radio.transmit(); // radio.receive(); - // radio.readData(); // radio.scanChannel(); } From cb385f59468cd8bafe4fb8df5651295d605d7e2a Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Apr 2023 14:05:25 +0200 Subject: [PATCH 0469/1848] [SX126x] Remove standby before data read (#703) --- .../SX126x_Receive_Interrupt.ino | 4 ---- src/modules/SX126x/SX126x.cpp | 14 ++++++++------ src/modules/SX126x/SX126x.h | 8 +++++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index a7f87a36b0..76cd07bee5 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -74,7 +74,6 @@ void setup() { // radio.sleep() // radio.transmit(); // radio.receive(); - // radio.readData(); // radio.scanChannel(); } @@ -142,8 +141,5 @@ void loop() { Serial.println(state); } - - // put module back to listen mode - radio.startReceive(); } } diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ab30896125..ed4b5514fe 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -646,12 +646,10 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, uint16_t irqFlags, uint16_t } int16_t SX126x::readData(uint8_t* data, size_t len) { - // set mode to standby - int16_t state = standby(); - // this method may get called from receive() after Rx timeout - // if that's the case, the standby call will return "SPI command timeout error" + // if that's the case, the first call will return "SPI command timeout error" // check the IRQ to be sure this really originated from timeout event + int16_t state = _mod->SPIcheckStream(); if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { // this is definitely Rx timeout return(RADIOLIB_ERR_RX_TIMEOUT); @@ -676,6 +674,10 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { state = readBuffer(data, length); RADIOLIB_ASSERT(state); + // reset the base addresses + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + // clear interrupt flags state = clearIrqStatus(); @@ -1674,8 +1676,8 @@ int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { return(_mod->SPIwriteStream(cmd, 2, data, numBytes)); } -int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, RADIOLIB_SX126X_CMD_NOP }; +int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; return(_mod->SPIreadStream(cmd, 2, data, numBytes)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 51a5b4c609..54b3b4376f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -630,8 +630,10 @@ class SX126x: public PhysicalLayer { /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX126X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX126X_RX_TIMEOUT_NONE for no timeout (Rx single mode). - If timeout other than infinite is set, signal will be generated on DIO1. + \param timeout Receive mode type and/or raw timeout value, expressed as multiples of 15.625 us. + When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain in Rx mode until explicitly commanded to stop (Rx continuous mode). + When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return to standby when a packet is received (Rx single mode). + For any other value, timeout will be applied and signal will be generated on DIO1 for conditions defined by irqFlags and irqMask. \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. @@ -1145,7 +1147,7 @@ class SX126x: public PhysicalLayer { int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); - int16_t readBuffer(uint8_t* data, uint8_t numBytes); + int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); From 17ae017f89fd771bdf535f634a571cf359975363 Mon Sep 17 00:00:00 2001 From: Mestery Date: Mon, 10 Apr 2023 14:51:07 +0200 Subject: [PATCH 0470/1848] address changes --- src/BuildOpt.h | 27 ++------------------------- src/Module.cpp | 40 +++++++++++++++++++++++++++++++++------- src/Module.h | 4 ++++ 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 0c02b351a2..995f87192e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1040,31 +1040,8 @@ #if defined(RADIOLIB_DEBUG) #if defined(RADIOLIB_BUILD_ARDUINO) -// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 -size_t serialPrintf(const char *format, ...) { - va_list arg; - va_start(arg, format); - char temp[64]; - char* buffer = temp; - size_t len = vsnprintf(temp, sizeof(temp), format, arg); - va_end(arg); - if (len > sizeof(temp) - 1) { - buffer = new char[len + 1]; - if (!buffer) { - return 0; - } - va_start(arg, format); - vsnprintf(buffer, len + 1, format, arg); - va_end(arg); - } - len = RADIOLIB_DEBUG_PORT.write((const uint8_t*) buffer, len); - if (buffer != temp) { - delete[] buffer; - } - return len; -} - #define RADIOLIB_DEBUG_PRINT(...) serialPrintf(__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN(M, ...) serialPrintf(M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) #else #if !defined(RADIOLIB_DEBUG_PRINT) #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) diff --git a/src/Module.cpp b/src/Module.cpp index 77e4906d00..d7197ab748 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -161,9 +161,9 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t } #if defined(RADIOLIB_DEBUG) && defined(RADIOLIB_BUILD_ARDUINO) - #define DEBUG_BIN(x) RADIOLIB_DEBUG_PORT.println(x, BIN) + #define RADIOLIB_DEBUG_PRINT_BIN(x) RADIOLIB_DEBUG_PORT.println(x, BIN) #else // no bin representation, fallback to hex - #define DEBUG_BIN(x) RADIOLIB_DEBUG_PRINTLN("%X", x) + #define RADIOLIB_DEBUG_PRINT_BIN(x) RADIOLIB_DEBUG_PRINTLN("%X", x) #endif // check failed, print debug info @@ -171,15 +171,15 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg); RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb); RADIOLIB_DEBUG_PRINT("value:\t\t0b"); - DEBUG_BIN(value); + RADIOLIB_DEBUG_PRINT_BIN(value); RADIOLIB_DEBUG_PRINT("current:\t0b"); - DEBUG_BIN(currentValue); + RADIOLIB_DEBUG_PRINT_BIN(currentValue); RADIOLIB_DEBUG_PRINT("mask:\t\t0b"); - DEBUG_BIN(mask); + RADIOLIB_DEBUG_PRINT_BIN(mask); RADIOLIB_DEBUG_PRINT("new:\t\t0b"); - DEBUG_BIN(newValue); + RADIOLIB_DEBUG_PRINT_BIN(newValue); RADIOLIB_DEBUG_PRINT("read:\t\t0b"); - DEBUG_BIN(readValue); + RADIOLIB_DEBUG_PRINT_BIN(readValue); RADIOLIB_DEBUG_PRINTLN(); return(RADIOLIB_ERR_SPI_WRITE_FAILED); @@ -757,6 +757,32 @@ void Module::regdump(uint16_t start, size_t len) { #endif } +#if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO) +// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 +size_t Module::serialPrintf(const char* format, ...) { + va_list arg; + va_start(arg, format); + char temp[64]; + char* buffer = temp; + size_t len = vsnprintf(temp, sizeof(temp), format, arg); + va_end(arg); + if (len > sizeof(temp) - 1) { + buffer = new char[len + 1]; + if (!buffer) { + return 0; + } + va_start(arg, format); + vsnprintf(buffer, len + 1, format, arg); + va_end(arg); + } + len = RADIOLIB_DEBUG_PORT.write((const uint8_t*)buffer, len); + if (buffer != temp) { + delete[] buffer; + } + return len; +} +#endif + void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { // This can be on the stack, setRfSwitchTable copies the contents const RADIOLIB_PIN_TYPE pins[] = { diff --git a/src/Module.h b/src/Module.h index 9cb55db9c2..71ad40f9b2 100644 --- a/src/Module.h +++ b/src/Module.h @@ -704,6 +704,10 @@ class Module { */ void regdump(uint16_t start, size_t len); + #if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO) + static size_t serialPrintf(const char* format, ...); + #endif + #if !defined(RADIOLIB_GODMODE) private: #endif From 09fc9290bb383e24c70a1314830e060a76214bca Mon Sep 17 00:00:00 2001 From: Mestery Date: Wed, 12 Apr 2023 16:50:05 +0200 Subject: [PATCH 0471/1848] Undefine RADIOLIB_DEBUG_PRINT_BIN macro after use --- src/Module.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index d7197ab748..f408833040 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -181,6 +181,8 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t RADIOLIB_DEBUG_PRINT("read:\t\t0b"); RADIOLIB_DEBUG_PRINT_BIN(readValue); RADIOLIB_DEBUG_PRINTLN(); + + #undef RADIOLIB_DEBUG_PRINT_BIN return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else From 27575b8c49528d35750476c88aa1c13678caf5ba Mon Sep 17 00:00:00 2001 From: Mestery Date: Wed, 12 Apr 2023 18:43:43 +0200 Subject: [PATCH 0472/1848] Remove RADIOLIB_DEBUG_PRINT_BIN --- src/Module.cpp | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index f408833040..76d221dca0 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -160,29 +160,16 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t } } - #if defined(RADIOLIB_DEBUG) && defined(RADIOLIB_BUILD_ARDUINO) - #define RADIOLIB_DEBUG_PRINT_BIN(x) RADIOLIB_DEBUG_PORT.println(x, BIN) - #else // no bin representation, fallback to hex - #define RADIOLIB_DEBUG_PRINT_BIN(x) RADIOLIB_DEBUG_PRINTLN("%X", x) - #endif - // check failed, print debug info RADIOLIB_DEBUG_PRINTLN(); RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg); RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb); - RADIOLIB_DEBUG_PRINT("value:\t\t0b"); - RADIOLIB_DEBUG_PRINT_BIN(value); - RADIOLIB_DEBUG_PRINT("current:\t0b"); - RADIOLIB_DEBUG_PRINT_BIN(currentValue); - RADIOLIB_DEBUG_PRINT("mask:\t\t0b"); - RADIOLIB_DEBUG_PRINT_BIN(mask); - RADIOLIB_DEBUG_PRINT("new:\t\t0b"); - RADIOLIB_DEBUG_PRINT_BIN(newValue); - RADIOLIB_DEBUG_PRINT("read:\t\t0b"); - RADIOLIB_DEBUG_PRINT_BIN(readValue); + RADIOLIB_DEBUG_PRINT("value:\t\t0x%X", value); + RADIOLIB_DEBUG_PRINT("current:\t0x%X", currentValue); + RADIOLIB_DEBUG_PRINT("mask:\t\t0x%X", mask); + RADIOLIB_DEBUG_PRINT("new:\t\t0x%X", newValue); + RADIOLIB_DEBUG_PRINT("read:\t\t0x%X", readValue); RADIOLIB_DEBUG_PRINTLN(); - - #undef RADIOLIB_DEBUG_PRINT_BIN return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else From 45e9fd44bb533c99f627c89455d0ebc9c62ffe0c Mon Sep 17 00:00:00 2001 From: Mestery Date: Wed, 12 Apr 2023 18:44:12 +0200 Subject: [PATCH 0473/1848] nitpick --- src/Module.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 76d221dca0..c7aa8bdcb5 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -168,8 +168,7 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t RADIOLIB_DEBUG_PRINT("current:\t0x%X", currentValue); RADIOLIB_DEBUG_PRINT("mask:\t\t0x%X", mask); RADIOLIB_DEBUG_PRINT("new:\t\t0x%X", newValue); - RADIOLIB_DEBUG_PRINT("read:\t\t0x%X", readValue); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_PRINTLN("read:\t\t0x%X", readValue); return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else From ec3d4eaf202fe9c88466de4dd3eb19ae0c0f79d5 Mon Sep 17 00:00:00 2001 From: Mestery Date: Tue, 11 Apr 2023 04:51:29 +0200 Subject: [PATCH 0474/1848] Improve hardware abstraction layer --- .../CC1101_Receive_Interrupt.ino | 2 +- .../CC1101_Transmit_Interrupt.ino | 2 +- .../STM32WLx_Receive/STM32WLx_Receive.ino | 2 +- .../STM32WLx_Receive_Interrupt.ino | 2 +- .../STM32WLx_Transmit/STM32WLx_Transmit.ino | 2 +- .../STM32WLx_Transmit_Interrupt.ino | 2 +- ...x_Channel_Activity_Detection_Interrupt.ino | 4 +- ...27x_Channel_Activity_Detection_Receive.ino | 4 +- .../SX127x_PingPong/SX127x_PingPong.ino | 2 +- .../SX127x_Receive_FHSS.ino | 4 +- .../SX127x_Receive_Interrupt.ino | 2 +- .../SX127x_Transmit_FHSS.ino | 4 +- .../SX127x_Transmit_Interrupt.ino | 2 +- src/ArduinoHal.cpp | 146 +++ src/ArduinoHal.h | 62 + src/BuildOpt.h | 1085 ++++------------- src/Hal.cpp | 17 + src/Hal.h | 42 + src/Module.cpp | 434 +------ src/Module.h | 229 +--- src/RadioLib.h | 6 + src/modules/CC1101/CC1101.cpp | 81 +- src/modules/CC1101/CC1101.h | 16 +- src/modules/RF69/RF69.cpp | 59 +- src/modules/RF69/RF69.h | 8 +- src/modules/SX1231/SX1231.cpp | 6 +- src/modules/SX126x/STM32WLx_Module.cpp | 152 +-- src/modules/SX126x/STM32WLx_Module.h | 11 - src/modules/SX126x/SX126x.cpp | 74 +- src/modules/SX126x/SX126x.h | 6 +- src/modules/SX127x/SX1272.cpp | 11 +- src/modules/SX127x/SX1278.cpp | 11 +- src/modules/SX127x/SX127x.cpp | 85 +- src/modules/SX127x/SX127x.h | 16 +- src/modules/SX128x/SX1280.cpp | 9 +- src/modules/SX128x/SX128x.cpp | 67 +- src/modules/SX128x/SX128x.h | 6 +- src/modules/Si443x/Si443x.cpp | 47 +- src/modules/Si443x/Si443x.h | 6 +- src/modules/nRF24/nRF24.cpp | 59 +- src/modules/nRF24/nRF24.h | 2 +- src/protocols/AFSK/AFSK.cpp | 6 +- src/protocols/AFSK/AFSK.h | 4 +- src/protocols/APRS/APRS.cpp | 3 + src/protocols/AX25/AX25.cpp | 3 +- src/protocols/ExternalRadio/ExternalRadio.cpp | 6 + src/protocols/ExternalRadio/ExternalRadio.h | 5 + src/protocols/FSK4/FSK4.cpp | 3 +- src/protocols/Hellschreiber/Hellschreiber.cpp | 4 +- src/protocols/Morse/Morse.cpp | 23 +- src/protocols/Pager/Pager.cpp | 16 +- src/protocols/Pager/Pager.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 5 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 4 +- src/protocols/RTTY/RTTY.cpp | 6 +- src/protocols/SSTV/SSTV.cpp | 2 +- 56 files changed, 1014 insertions(+), 1865 deletions(-) create mode 100644 src/ArduinoHal.cpp create mode 100644 src/ArduinoHal.h create mode 100644 src/Hal.cpp create mode 100644 src/Hal.h diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 43250baed1..f61253fcc2 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -49,7 +49,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setGdo0Action(setFlag); + radio.setGdo0Action(setFlag, RISING); // start listening for packets Serial.print(F("[CC1101] Starting to listen ... ")); diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 6afb1bd3c0..699e88c432 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -51,7 +51,7 @@ void setup() { // NOTE: Unlike other modules (such as SX127x), // different GDOx pins are used for // transmit and receive interrupts! - radio.setGdo2Action(setFlag); + radio.setGdo2Action(setFlag, FALLING); // start transmitting the first packet Serial.print(F("[CC1101] Sending first packet ... ")); diff --git a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino index 63846a0c87..2b96d15777 100644 --- a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino +++ b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino @@ -32,7 +32,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const RADIOLIB_PIN_TYPE rfswitch_pins[] = +static const uint8_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index c1400429a0..0bb545134b 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -31,7 +31,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const RADIOLIB_PIN_TYPE rfswitch_pins[] = +static const uint8_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino index 19e8dc285a..cd1577d6f8 100644 --- a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino +++ b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino @@ -28,7 +28,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const RADIOLIB_PIN_TYPE rfswitch_pins[] = +static const uint8_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index fdd56a0a2e..6e4e361b18 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -23,7 +23,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const RADIOLIB_PIN_TYPE rfswitch_pins[] = +static const uint8_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 21ab7de509..631ae909bf 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -47,11 +47,11 @@ void setup() { // set the function that will be called // when LoRa preamble is not detected within CAD timeout period - radio.setDio0Action(setFlagTimeout); + radio.setDio0Action(setFlagTimeout, RISING); // set the function that will be called // when LoRa preamble is detected - radio.setDio1Action(setFlagDetected); + radio.setDio1Action(setFlagDetected, RISING); // start scanning the channel Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino index 6186227a14..945ded9fcf 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -53,11 +53,11 @@ void setup() { // set the function that will be called // when LoRa preamble is not detected within CAD timeout period // or when a packet is received - radio.setDio0Action(setFlagTimeout); + radio.setDio0Action(setFlagTimeout, RISING); // set the function that will be called // when LoRa preamble is detected - radio.setDio1Action(setFlagDetected); + radio.setDio1Action(setFlagDetected, RISING); // start scanning the channel Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index 26d1132b50..9e006639e8 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -60,7 +60,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setDio0Action(setFlag); + radio.setDio0Action(setFlag, RISING); #if defined(INITIATING_NODE) // send the first packet on this node diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index 957b7d8837..87be697a4b 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -96,10 +96,10 @@ void setup() { } // set the function to call when reception is finished - radio.setDio0Action(setRxFlag); + radio.setDio0Action(setRxFlag, RISING); // set the function to call when we need to change frequency - radio.setDio1Action(setFHSSFlag); + radio.setDio1Action(setFHSSFlag, RISING); // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index c1ba3ced1a..02cb5b096b 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -51,7 +51,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setDio0Action(setFlag); + radio.setDio0Action(setFlag, RISING); // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index faef426b58..9b8693e3c7 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -108,10 +108,10 @@ void setup() { } // set the function to call when transmission is finished - radio.setDio0Action(setTxFlag); + radio.setDio0Action(setTxFlag, RISING); // set the function to call when we need to change frequency - radio.setDio1Action(setFHSSFlag); + radio.setDio1Action(setFHSSFlag, RISING); // start transmitting the first packet Serial.print(F("[SX1278] Sending first packet ... ")); diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 97b6e31964..8cf0f059e2 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -50,7 +50,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setDio0Action(setFlag); + radio.setDio0Action(setFlag, RISING); // start transmitting the first packet Serial.print(F("[SX1278] Sending first packet ... ")); diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp new file mode 100644 index 0000000000..438e4c9f7c --- /dev/null +++ b/src/ArduinoHal.cpp @@ -0,0 +1,146 @@ +#include "ArduinoHal.h" + +#if defined(RADIOLIB_BUILD_ARDUINO) + +ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): Hal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&spi), _spiSettings(spiSettings) {} + +ArduinoHal::ArduinoHal(): Hal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&RADIOLIB_DEFAULT_SPI), _initInterface(true) {} + +void ArduinoHal::init() { + if(_initInterface) { + spiBegin(); + } +} + +void ArduinoHal::term() { + if(_initInterface) { + spiEnd(); + } +} + +void inline ArduinoHal::pinMode(uint8_t pin, uint8_t mode) { + if (pin == RADIOLIB_NC) { + return; + } + ::pinMode(pin, RADIOLIB_ARDUINOHAL_PIN_MODE_CAST mode); +} +void inline ArduinoHal::digitalWrite(uint8_t pin, uint8_t value) { + if (pin == RADIOLIB_NC) { + return; + } + ::digitalWrite(pin, RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST value); +} +uint8_t inline ArduinoHal::digitalRead(uint8_t pin) { + if (pin == RADIOLIB_NC) { + return 0; + } + return ::digitalRead(pin); +} +void inline ArduinoHal::attachInterrupt(uint8_t interruptNum, void (*interruptCb)(void), uint8_t mode) { + if (interruptNum == RADIOLIB_NC) { + return; + } + ::attachInterrupt(interruptNum, interruptCb, RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST mode); +} +void inline ArduinoHal::detachInterrupt(uint8_t interruptNum) { + if (interruptNum == RADIOLIB_NC) { + return; + } + ::detachInterrupt(interruptNum); +} +void inline ArduinoHal::delay(unsigned long ms) { + ::delay(ms); +} +void inline ArduinoHal::delayMicroseconds(unsigned long us) { + ::delayMicroseconds(us); +} +unsigned long inline ArduinoHal::millis() { + return ::millis(); +} +unsigned long inline ArduinoHal::micros() { + return ::micros(); +} +long inline ArduinoHal::pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) { + if (pin == RADIOLIB_NC) { + return 0; + } + return ::pulseIn(pin, state, timeout); +} +void inline ArduinoHal::spiBegin() { + _spi->begin(); +} +void inline ArduinoHal::spiBeginTransaction() { + _spi->beginTransaction(_spiSettings); +} +uint8_t inline ArduinoHal::spiTransfer(uint8_t b) { + return _spi->transfer(b); +} +void inline ArduinoHal::spiEndTransaction() { + _spi->endTransaction(); +} +void inline ArduinoHal::spiEnd() { + _spi->end(); +} +void inline ArduinoHal::tone(uint8_t pin, unsigned int frequency, unsigned long duration) { + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + if (pin == RADIOLIB_NC) { + return 0; + } + ::tone(pin, frequency, duration); + #elif defined(ESP32) + // ESP32 tone() emulation + (void)duration; + if(_prev == -1) { + ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); + } + if(_prev != frequency) { + ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); + } + _prev = frequency; + #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) + // better tone for mbed OS boards + (void)duration; + if(!pwmPin) { + pwmPin = new mbed::PwmOut(digitalPinToPinName(pin)); + } + pwmPin->period(1.0 / frequency); + pwmPin->write(0.5); + #endif +} +void inline ArduinoHal::noTone(uint8_t pin) { + #if !defined(RADIOLIB_TONE_UNSUPPORTED) and defined(ARDUINO_ARCH_STM32) + if (pin == RADIOLIB_NC) { + return 0; + } + ::noTone(pin, false); + #elif !defined(RADIOLIB_TONE_UNSUPPORTED) + if (pin == RADIOLIB_NC) { + return 0; + } + ::noTone(pin); + #elif defined(ESP32) + if (pin == RADIOLIB_NC) { + return 0; + } + // ESP32 tone() emulation + ledcDetachPin(pin); + ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + _prev = -1; + #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) + if (pin == RADIOLIB_NC) { + return 0; + } + // better tone for mbed OS boards + (void)pin; + pwmPin->suspend(); + #endif +} +void inline ArduinoHal::yield() { + #if !defined(RADIOLIB_YIELD_UNSUPPORTED) + ::yield(); + #endif +} +uint8_t inline ArduinoHal::pinToInterrupt(uint8_t pin) { + return digitalPinToInterrupt(pin); +} +#endif diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h new file mode 100644 index 0000000000..79df17b39d --- /dev/null +++ b/src/ArduinoHal.h @@ -0,0 +1,62 @@ +#include "TypeDef.h" + +#if !defined(_RADIOLIB_ARDUINOHAL_H) +#define _RADIOLIB_ARDUINOHAL_H + +#if defined(RADIOLIB_BUILD_ARDUINO) + +#if defined(RADIOLIB_MBED_TONE_OVERRIDE) +#include "mbed.h" +#endif + +#include "Hal.h" +#include + +#include + +class ArduinoHal : public Hal { + public: + ArduinoHal(); + ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); + + void init() override; + void term() override; + + void pinMode(uint8_t pin, uint8_t mode) override; + void digitalWrite(uint8_t pin, uint8_t value) override; + uint8_t digitalRead(uint8_t pin) override; + void attachInterrupt(uint8_t interruptNum, void (*interruptCb)(void), uint8_t mode) override; + void detachInterrupt(uint8_t interruptNum) override; + void delay(unsigned long ms) override; + void delayMicroseconds(unsigned long us) override; + unsigned long millis() override; + unsigned long micros() override; + long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) override; + void spiBegin() override; + void spiBeginTransaction() override; + uint8_t spiTransfer(uint8_t b) override; + void spiEndTransaction() override; + void spiEnd() override; + void tone(uint8_t pin, unsigned int frequency, unsigned long duration = 0) override; + void noTone(uint8_t pin) override; + void yield() override; + uint8_t pinToInterrupt(uint8_t pin) override; + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + SPIClass* _spi = NULL; + SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; + bool _initInterface = false; + + #if defined(RADIOLIB_MBED_TONE_OVERRIDE) + mbed::PwmOut *pwmPin = NULL; + #endif + + #if defined(ESP32) + int32_t _prev = -1; + #endif +}; + +#endif +#endif diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 995f87192e..8bded0cc9d 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -7,21 +7,16 @@ #define RADIOLIB_BUILD_ARDUINO #else // generic build + #include #define RADIOLIB_BUILD_GENERIC #endif #if defined(RADIOLIB_BUILD_ARDUINO) - /* * Platform-specific configuration. * * RADIOLIB_PLATFORM - platform name, used in debugging to quickly check the correct platform is detected. - * RADIOLIB_PIN_TYPE - which type should be used for pin numbers in functions like digitalRead(). - * RADIOLIB_PIN_MODE - which type should be used for pin modes in functions like pinMode(). - * RADIOLIB_PIN_STATUS - which type should be used for pin values in functions like digitalWrite(). - * RADIOLIB_INTERRUPT_STATUS - which type should be used for pin changes in functions like attachInterrupt(). - * RADIOLIB_DIGITAL_PIN_TO_INTERRUPT - function/macro to be used to convert digital pin number to interrupt pin number. - * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. + * RADIOLIB_NC - alias for unused pin, usually the largest possible value of uint8_t. * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. * RADIOLIB_NONVOLATILE - macro to place variable into program storage (usually Flash). * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). @@ -36,51 +31,16 @@ * platform detection. */ -// uncomment to enable custom platform definition -//#define RADIOLIB_CUSTOM_ARDUINO + // uncomment to enable custom platform definition + //#define RADIOLIB_CUSTOM_ARDUINO #if defined(RADIOLIB_CUSTOM_ARDUINO) // name for your platform #define RADIOLIB_PLATFORM "Custom" - // the following parameters must always be defined - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - // the following are signatures of Arduino API functions of the custom platform - // for example, pinMode on Arduino Uno is defined as void pinMode(uint8_t pin, uint8_t mode) - // all of the callbacks below are taken from Arduino Uno - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - // the following must be defined if the Arduino core does not support tone function + // the following must be defined if the Arduino core does not support tone or yield function //#define RADIOLIB_TONE_UNSUPPORTED + //#define RADIOLIB_YIELD_UNSUPPORTED // some of RadioLib drivers may be excluded, to prevent collisions with platforms (or to speed up build process) // the following is a complete list of all possible exclusion macros, uncomment any of them to disable that driver @@ -105,833 +65,218 @@ //#define RADIOLIB_EXCLUDE_RTTY //#define RADIOLIB_EXCLUDE_SSTV //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE +#elif defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) + // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. + #define RADIOLIB_PLATFORM "Arduino AVR" +#elif defined(ESP8266) + // ESP8266 boards + #define RADIOLIB_PLATFORM "ESP8266" +#elif defined(ESP32) + // ESP32 boards + #define RADIOLIB_PLATFORM "ESP32" + // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_TONE_ESP32_CHANNEL (1) +#elif defined(ARDUINO_ARCH_STM32) + // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32) + #define RADIOLIB_PLATFORM "Arduino STM32 (official)" +#elif defined(SAMD_SERIES) + // Adafruit SAMD boards (M0 and M4) + #define RADIOLIB_PLATFORM "Adafruit SAMD" +#elif defined(ARDUINO_ARCH_SAMD) + // Arduino SAMD (Zero, MKR, etc.) + #define RADIOLIB_PLATFORM "Arduino SAMD" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) +#elif defined(__SAM3X8E__) + // Arduino Due + #define RADIOLIB_PLATFORM "Arduino Due" + #define RADIOLIB_TONE_UNSUPPORTED +#elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) + // Adafruit nRF52 boards + #define RADIOLIB_PLATFORM "Adafruit nRF52" +#elif defined(ARDUINO_ARC32_TOOLS) + // Intel Curie + #define RADIOLIB_PLATFORM "Intel Curie" +#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(PORTDUINO) + // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every + #define RADIOLIB_PLATFORM "Arduino megaAVR" +#elif defined(ARDUINO_ARCH_APOLLO3) + // Sparkfun Apollo3 boards + #define RADIOLIB_PLATFORM "Sparkfun Apollo3" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (Arduino_PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) +#elif defined(ARDUINO_ARDUINO_NANO33BLE) + // Arduino Nano 33 BLE + #define RADIOLIB_PLATFORM "Arduino Nano 33 BLE" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE +#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) + // Arduino Portenta H7 + #define RADIOLIB_PLATFORM "Portenta H7" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE +#elif defined(__STM32F4__) || defined(__STM32F1__) + // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) + #define RADIOLIB_PLATFORM "STM32duino (unofficial)" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (WiringPinMode) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (ExtIntTriggerMode) +#elif defined(ARDUINO_ARCH_MEGAAVR) + // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX) + #define RADIOLIB_PLATFORM "MegaCoreX" +#elif defined(ARDUINO_ARCH_MBED_RP2040) + // Raspberry Pi Pico (official mbed core) + #define RADIOLIB_PLATFORM "Raspberry Pi Pico" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + + // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_MBED_TONE_OVERRIDE +#elif defined(ARDUINO_ARCH_RP2040) + // Raspberry Pi Pico (unofficial core) + #define RADIOLIB_PLATFORM "Raspberry Pi Pico (unofficial)" + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) +#elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) + // CubeCell + #define RADIOLIB_PLATFORM "CubeCell" + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) // see issue #709 + + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PINMODE) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (IrqModes) + + // provide an easy access to the on-board module + #include "board-config.h" + #define RADIOLIB_BUILTIN_MODULE RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY + + // CubeCell doesn't seem to define nullptr, let's do something like that now + #define nullptr NULL + + // ... and also defines pinMode() as a macro, which is by far the stupidest thing I have seen on Arduino + #undef pinMode + + // ... and uses an outdated GCC which does not support type aliases + #define RADIOLIB_TYPE_ALIAS(type, alias) typedef class type alias; + + // ... and it also has no tone(). This platform was designed by an idiot. + #define RADIOLIB_TONE_UNSUPPORTED + + // ... AND as the (hopefully) final nail in the coffin, IT F*CKING DEFINES YIELD() AS A MACRO THAT DOES NOTHING!!! + #define RADIOLIB_YIELD_UNSUPPORTED + #if defined(yield) + #undef yield + #endif +#elif defined(RASPI) + // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) + #define RADIOLIB_PLATFORM "RasPiArduino" -#else - #if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) - // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. - #define RADIOLIB_PLATFORM "Arduino AVR" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ESP8266) - // ESP8266 boards - #define RADIOLIB_PLATFORM "ESP8266" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ESP32) - // ESP32 boards - #define RADIOLIB_PLATFORM "ESP32" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral - #define RADIOLIB_TONE_UNSUPPORTED - #define RADIOLIB_TONE_ESP32_CHANNEL (1) - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, void) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, void) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARCH_STM32) - // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32) - #define RADIOLIB_PLATFORM "Arduino STM32 (official)" - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin, bool destruct) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, callback_function_t callback, uint32_t mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) - #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(SAMD_SERIES) - // Adafruit SAMD boards (M0 and M4) - #define RADIOLIB_PLATFORM "Adafruit SAMD" - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint32_t _pin, uint32_t frequency, uint32_t duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint32_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, voidFuncPtr callback, uint32_t mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long dwMs) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARCH_SAMD) - // Arduino SAMD (Zero, MKR, etc.) - #define RADIOLIB_PLATFORM "Arduino SAMD" - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pinNumber, PinMode pinMode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pinNumber, PinStatus status) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pinNumber) - #define RADIOLIB_CB_ARGS_TONE (void, tone, unsigned char outputPin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t outputPin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t pin, voidFuncPtr callback, PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, pin_size_t pin, uint8_t state, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(__SAM3X8E__) - // Arduino Due - #define RADIOLIB_PLATFORM "Arduino Due" - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #define RADIOLIB_TONE_UNSUPPORTED - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, void) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, void) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t dwMs) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) - #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) - // Adafruit nRF52 boards - #define RADIOLIB_PLATFORM "Adafruit nRF52" - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint32_t dwPin, uint32_t dwMode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint32_t dwPin, uint32_t dwVal) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint32_t ulPin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (int, attachInterrupt, uint32_t pin, voidFuncPtr callback, uint32_t mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t dwMs) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) - #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARC32_TOOLS) - // Intel Curie - #define RADIOLIB_PLATFORM "Intel Curie" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint32_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint32_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint32_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t dwMs) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t dwUs) - #define RADIOLIB_CB_ARGS_MILLIS (uint64_t, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (uint64_t, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(PORTDUINO) - // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every - #define RADIOLIB_PLATFORM "Arduino megaAVR" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, PinMode mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, PinStatus val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*userFunc)(void), PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARCH_APOLLO3) - // Sparkfun Apollo3 boards - #define RADIOLIB_PLATFORM "Sparkfun Apollo3" - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE Arduino_PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pinName, Arduino_PinMode pinMode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pinName, PinStatus val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pinName) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNumber) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARDUINO_NANO33BLE) - // Arduino Nano 33 BLE - #define RADIOLIB_PLATFORM "Arduino Nano 33 BLE" - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds - #define RADIOLIB_TONE_UNSUPPORTED - #define RADIOLIB_MBED_TONE_OVERRIDE - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) - // Arduino Portenta H7 - #define RADIOLIB_PLATFORM "Portenta H7" - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds - #define RADIOLIB_TONE_UNSUPPORTED - #define RADIOLIB_MBED_TONE_OVERRIDE - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(__STM32F4__) || defined(__STM32F1__) - // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) - #define RADIOLIB_PLATFORM "STM32duino (unofficial)" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE WiringPinMode - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS ExtIntTriggerMode - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8 pin, WiringPinMode mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8 pin, uint8 val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint32_t, digitalRead, uint8 pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint32_t _pin, uint32_t frequency, uint32_t duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint32_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8 pin) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32 us) - #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t ulPin, uint32_t ulState, uint32_t ulTimeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARCH_MEGAAVR) - // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX) - #define RADIOLIB_PLATFORM "MegaCoreX" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint8_t, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin, void (*userFunc)(void), uint8_t mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARCH_MBED_RP2040) - // Raspberry Pi Pico (official mbed core) - #define RADIOLIB_PLATFORM "Raspberry Pi Pico" - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds - #define RADIOLIB_TONE_UNSUPPORTED - #define RADIOLIB_MBED_TONE_OVERRIDE - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(ARDUINO_ARCH_RP2040) - // Raspberry Pi Pico (unofficial core) - #define RADIOLIB_PLATFORM "Raspberry Pi Pico (unofficial)" - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, pin_size_t pin, PinMode mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, pin_size_t pin, PinStatus val) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (PinStatus, digitalRead, pin_size_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, pin_size_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - #elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) - // CubeCell - #define RADIOLIB_PLATFORM "CubeCell" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE PINMODE - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS IrqModes - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) // see issue #709 - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, PINMODE mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin_name, uint8_t level) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint8_t, digitalRead, uint8_t pin_name) - #define RADIOLIB_CB_ARGS_TONE (void, tone, void) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, void) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t pin_name, GpioIrqHandler GpioIrqHandlerCallback, IrqModes interrupt_mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t pin_name) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t milliseconds) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint16 microseconds) - #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint8_t pin_name, uint8_t mode, uint32_t timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - // provide an easy access to the on-board module - #include "board-config.h" - #define RADIOLIB_BUILTIN_MODULE RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY - - // CubeCell doesn't seem to define nullptr, let's do something like that now - #define nullptr NULL - - // ... and also defines pinMode() as a macro, which is by far the stupidest thing I have seen on Arduino - #undef pinMode - - // ... and uses an outdated GCC which does not support type aliases - #define RADIOLIB_TYPE_ALIAS(type, alias) typedef class type alias; - - // ... and it also has no tone(). This platform was designed by an idiot. - #define RADIOLIB_TONE_UNSUPPORTED - - // ... AND as the (hopefully) final nail in the coffin, IT F*CKING DEFINES YIELD() AS A MACRO THAT DOES NOTHING!!! - #define RADIOLIB_YIELD_UNSUPPORTED - #if defined(yield) - #undef yield - #endif - - #elif defined(RASPI) - // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) - #define RADIOLIB_PLATFORM "RasPiArduino" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) - - // let's start off easy - no tone on this platform, that can happen - #define RADIOLIB_TONE_UNSUPPORTED - - // hmm, no yield either - weird on something like Raspberry PI, but sure, we can handle it - #define RADIOLIB_YIELD_UNSUPPORTED - - // aight, getting to the juicy stuff - PGM_P seems missing, that's the first time - #define PGM_P const char * - - // ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS! - #if defined(millis) - #undef millis - inline unsigned long millis() { return((unsigned long)(STCV / 1000)); }; - #endif - - #if defined(micros) - #undef micros - inline unsigned long micros() { return((unsigned long)(STCV)); }; - #endif - - #elif defined(TEENSYDUINO) - // Teensy - #define RADIOLIB_PLATFORM "Teensy" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // let's start off easy - no tone on this platform, that can happen + #define RADIOLIB_TONE_UNSUPPORTED - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (uint8_t, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, short unsigned int frequency, long unsigned int duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, long unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + // hmm, no yield either - weird on something like Raspberry PI, but sure, we can handle it + #define RADIOLIB_YIELD_UNSUPPORTED - #else - // other Arduino platforms not covered by the above list - this may or may not work - #define RADIOLIB_PLATFORM "Unknown Arduino" - #define RADIOLIB_UNKNOWN_PLATFORM - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS - #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_DEFAULT_SPI SPI - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) - #define RADIOLIB_NONVOLATILE PROGMEM - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + // aight, getting to the juicy stuff - PGM_P seems missing, that's the first time + #define PGM_P const char * - // Arduino API callbacks - #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) - #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) - #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) - #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) - #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) - #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) - #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) - #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) - #define RADIOLIB_CB_ARGS_DELAY (void, delay, unsigned long ms) - #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) - #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) - #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) - #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) - #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) - #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) - #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) - #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + // ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS! + #if defined(millis) + #undef millis + inline unsigned long millis() { return((unsigned long)(STCV / 1000)); }; + #endif + #if defined(micros) + #undef micros + inline unsigned long micros() { return((unsigned long)(STCV)); }; #endif +#elif defined(TEENSYDUINO) + // Teensy + #define RADIOLIB_PLATFORM "Teensy" +#else + // other Arduino platforms not covered by the above list - this may or may not work + #define RADIOLIB_PLATFORM "Unknown Arduino" + #define RADIOLIB_UNKNOWN_PLATFORM #endif + #if !defined(RADIOLIB_NC) + #define RADIOLIB_NC (0xFF) + #endif + #if !defined(RADIOLIB_DEFAULT_SPI) + #define RADIOLIB_DEFAULT_SPI SPI + #endif + #if !defined(RADIOLIB_DEFAULT_SPI_SETTINGS) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #endif + #if !defined(RADIOLIB_NONVOLATILE) + #define RADIOLIB_NONVOLATILE PROGMEM + #endif + #if !defined(RADIOLIB_NONVOLATILE_READ_BYTE) + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #endif + #if !defined(RADIOLIB_NONVOLATILE_READ_DWORD) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) + #endif + #if !defined(RADIOLIB_TYPE_ALIAS) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + #endif + + #if !defined(RADIOLIB_ARDUINOHAL_PIN_MODE_CAST) + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST + #endif + #if !defined(RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST + #endif + #if !defined(RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST + #endif #else // generic non-Arduino platform #define RADIOLIB_PLATFORM "Generic" - // platform properties may be defined here, or somewhere else in the build system - #include "noarduino.h" + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_NONVOLATILE + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*((uint8_t *)(void *)(addr))) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*((uint32_t *)(void *)(addr))) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + #if !defined(RADIOLIB_DEBUG_PORT) + #define RADIOLIB_DEBUG_PORT stdout + #endif + + #define DEC 10 + #define HEX 16 + #define OCT 8 + #define BIN 2 + + #include + #include + typedef uint8_t byte; + + using std::max; + using std::min; #endif /* @@ -950,7 +295,7 @@ // set which output port should be used for debug output // may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) -#if !defined(RADIOLIB_DEBUG_PORT) +#if defined(RADIOLIB_BUILD_ARDUINO) && !defined(RADIOLIB_DEBUG_PORT) #define RADIOLIB_DEBUG_PORT Serial #endif @@ -1068,24 +413,6 @@ */ #define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } } -/* - * Macros that create callback for the hardware abstraction layer. - * - * This is the most evil thing I have ever created. I am deeply sorry to anyone currently reading this text. - * Come one, come all and witness the horror: - * Variadics, forced expansions, inlined function, string concatenation, and it even messes up access specifiers. - */ -#define RADIOLIB_FIRST(arg, ...) arg -#define RADIOLIB_REST(arg, ...) __VA_ARGS__ -#define RADIOLIB_EXP(...) __VA_ARGS__ - -#define RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, FUNC, ...) public: typedef RET (*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC = nullptr; -#define RADIOLIB_GENERATE_CALLBACK_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, __VA_ARGS__) -#define RADIOLIB_GENERATE_CALLBACK(CB) RADIOLIB_GENERATE_CALLBACK_RET(RADIOLIB_EXP(RADIOLIB_FIRST CB), RADIOLIB_EXP(RADIOLIB_REST CB)) - -#define RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, FUNC, ...) public: typedef RET (Module::*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC = nullptr; -#define RADIOLIB_GENERATE_CALLBACK_SPI_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, __VA_ARGS__) -#define RADIOLIB_GENERATE_CALLBACK_SPI(CB) RADIOLIB_GENERATE_CALLBACK_SPI_RET(RADIOLIB_EXP(RADIOLIB_FIRST CB), RADIOLIB_EXP(RADIOLIB_REST CB)) /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled diff --git a/src/Hal.cpp b/src/Hal.cpp new file mode 100644 index 0000000000..627c7d4dad --- /dev/null +++ b/src/Hal.cpp @@ -0,0 +1,17 @@ +#include +#include "Hal.h" + +Hal::Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uint8_t high, const uint8_t rising, const uint8_t falling) + : GpioModeInput(input), + GpioModeOutput(output), + GpioLevelLow(high), + GpioLevelHigh(low), + GpioInterruptRising(rising), + GpioInterruptFalling(falling) {} + +void Hal::init(){}; +void Hal::term(){}; +void Hal::tone(uint8_t pin, unsigned int frequency, unsigned long duration){}; +void Hal::noTone(uint8_t pin){}; +void Hal::yield(){}; +uint8_t Hal::pinToInterrupt(uint8_t pin) { return pin; }; diff --git a/src/Hal.h b/src/Hal.h new file mode 100644 index 0000000000..1ee240d7d0 --- /dev/null +++ b/src/Hal.h @@ -0,0 +1,42 @@ +#include +#include +#if !defined(_RADIOLIB_HAL_H) +#define _RADIOLIB_HAL_H + +class Hal { + public: + const uint8_t GpioModeInput; + const uint8_t GpioModeOutput; + const uint8_t GpioLevelLow; + const uint8_t GpioLevelHigh; + const uint8_t GpioInterruptRising; + const uint8_t GpioInterruptFalling; + + Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uint8_t high, const uint8_t rising, const uint8_t falling); + + virtual void init(); + virtual void term(); + + virtual void pinMode(uint8_t pin, uint8_t mode) = 0; + virtual void digitalWrite(uint8_t pin, uint8_t value) = 0; + virtual uint8_t digitalRead(uint8_t pin) = 0; + virtual void attachInterrupt(uint8_t interruptNum, void (*interruptCb)(void), uint8_t mode) = 0; + virtual void detachInterrupt(uint8_t interruptNum) = 0; + virtual void delay(unsigned long ms) = 0; + virtual void delayMicroseconds(unsigned long us) = 0; + virtual unsigned long millis() = 0; + virtual unsigned long micros() = 0; + virtual long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) = 0; + virtual void spiBegin() = 0; + virtual void spiBeginTransaction() = 0; + virtual uint8_t spiTransfer(uint8_t b) = 0; + virtual void spiEndTransaction() = 0; + virtual void spiEnd() = 0; + + virtual void tone(uint8_t pin, unsigned int frequency, unsigned long duration = 0); + virtual void noTone(uint8_t pin); + virtual void yield(); + virtual uint8_t pinToInterrupt(uint8_t pin); +}; + +#endif diff --git a/src/Module.cpp b/src/Module.cpp index c7aa8bdcb5..c05bd1fce3 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,94 +1,24 @@ +#define __STDC_FORMAT_MACROS +#include +#include +#include #include "Module.h" #if defined(RADIOLIB_BUILD_ARDUINO) - -// we need this to emulate tone() on mbed Arduino boards -#if defined(RADIOLIB_MBED_TONE_OVERRIDE) -#include "mbed.h" -mbed::PwmOut *pwmPin = NULL; -#endif - -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): - _cs(cs), - _irq(irq), - _rst(rst), - _gpio(gpio) -{ - _spi = &RADIOLIB_DEFAULT_SPI; - _initInterface = true; - - // this is Arduino build, pre-set callbacks - setCb_pinMode(::pinMode); - setCb_digitalRead(::digitalRead); - setCb_digitalWrite(::digitalWrite); - #if !defined(RADIOLIB_TONE_UNSUPPORTED) - setCb_tone(::tone); - setCb_noTone(::noTone); - #endif - setCb_attachInterrupt(::attachInterrupt); - setCb_detachInterrupt(::detachInterrupt); - #if !defined(RADIOLIB_YIELD_UNSUPPORTED) - setCb_yield(::yield); - #endif - setCb_delay(::delay); - setCb_delayMicroseconds(::delayMicroseconds); - setCb_millis(::millis); - setCb_micros(::micros); - setCb_pulseIn(::pulseIn); - setCb_SPIbegin(&Module::SPIbegin); - setCb_SPIbeginTransaction(&Module::SPIbeginTransaction); - setCb_SPItransfer(&Module::SPItransfer); - setCb_SPIendTransaction(&Module::SPIendTransaction); - setCb_SPIend(&Module::SPIend); +#include "ArduinoHal.h" +Module::Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { + this->hal = new ArduinoHal; } -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings): - _cs(cs), - _irq(irq), - _rst(rst), - _gpio(gpio), - _spiSettings(spiSettings) -{ - _spi = &spi; - _initInterface = false; - - // this is Arduino build, pre-set callbacks - setCb_pinMode(::pinMode); - setCb_digitalRead(::digitalRead); - setCb_digitalWrite(::digitalWrite); - #if !defined(RADIOLIB_TONE_UNSUPPORTED) - setCb_tone(::tone); - setCb_noTone(::noTone); - #endif - setCb_attachInterrupt(::attachInterrupt); - setCb_detachInterrupt(::detachInterrupt); - #if !defined(RADIOLIB_YIELD_UNSUPPORTED) - setCb_yield(::yield); - #endif - setCb_delay(::delay); - setCb_delayMicroseconds(::delayMicroseconds); - setCb_millis(::millis); - setCb_micros(::micros); - setCb_pulseIn(::pulseIn); - setCb_SPIbegin(&Module::SPIbegin); - setCb_SPIbeginTransaction(&Module::SPIbeginTransaction); - setCb_SPItransfer(&Module::SPItransfer); - setCb_SPIendTransaction(&Module::SPIendTransaction); - setCb_SPIend(&Module::SPIend); -} -#else - -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): - _cs(cs), - _irq(irq), - _rst(rst), - _gpio(gpio) -{ - // not an Arduino build, it's up to the user to set all callbacks +Module::Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio, SPIClass& spi, SPISettings spiSettings) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { + this->hal = new ArduinoHal(spi, spiSettings); } - #endif +Module::Module(Hal *hal, uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { + this->hal = hal; +} + Module::Module(const Module& mod) { *this = mod; } @@ -96,35 +26,23 @@ Module::Module(const Module& mod) { Module& Module::operator=(const Module& mod) { this->SPIreadCommand = mod.SPIreadCommand; this->SPIwriteCommand = mod.SPIwriteCommand; - this->_cs = mod.getCs(); - this->_irq = mod.getIrq(); - this->_rst = mod.getRst(); - this->_gpio = mod.getGpio(); + this->_cs = mod._cs; + this->_irq = mod._irq; + this->_rst = mod._rst; + this->_gpio = mod._gpio; return(*this); } void Module::init() { - this->pinMode(_cs, OUTPUT); - this->digitalWrite(_cs, HIGH); -#if defined(RADIOLIB_BUILD_ARDUINO) - if(_initInterface) { - (this->*cb_SPIbegin)(); - } -#endif + this->hal->init(); + this->hal->pinMode(_cs, this->hal->GpioModeOutput); + this->hal->digitalWrite(_cs, this->hal->GpioLevelHigh); } void Module::term() { // stop hardware interfaces (if they were initialized by the library) -#if defined(RADIOLIB_BUILD_ARDUINO) - if(!_initInterface) { - return; - } - - if(_spi != nullptr) { - this->SPIend(); - } -#endif + this->hal->term(); } int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) { @@ -150,9 +68,9 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t #if defined(RADIOLIB_SPI_PARANOID) // check register value each millisecond until check interval is reached // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) - uint32_t start = this->micros(); + uint32_t start = this->hal->micros(); uint8_t readValue = 0x00; - while(this->micros() - start < (checkInterval * 1000)) { + while(this->hal->micros() - start < (checkInterval * 1000)) { readValue = SPIreadRegister(reg); if((readValue & checkMask) == (newValue & checkMask)) { // check passed, we can stop the loop @@ -216,17 +134,17 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { // start SPI transaction - this->beginTransaction(); + this->hal->spiBeginTransaction(); // pull CS low - this->digitalWrite(_cs, LOW); + this->hal->digitalWrite(this->_cs, this->hal->GpioLevelLow); // send SPI register address with access command if(this->SPIaddrWidth <= 8) { - this->transfer(reg | cmd); + this->hal->spiTransfer(reg | cmd); } else { - this->transfer((reg >> 8) | cmd); - this->transfer(reg & 0xFF); + this->hal->spiTransfer((reg >> 8) | cmd); + this->hal->spiTransfer(reg & 0xFF); } #if defined(RADIOLIB_VERBOSE) @@ -242,14 +160,14 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d if(cmd == SPIwriteCommand) { if(dataOut != NULL) { for(size_t n = 0; n < numBytes; n++) { - this->transfer(dataOut[n]); + this->hal->spiTransfer(dataOut[n]); RADIOLIB_VERBOSE_PRINT("%X\t", dataOut[n]); } } } else if (cmd == SPIreadCommand) { if(dataIn != NULL) { for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->transfer(0x00); + dataIn[n] = this->hal->spiTransfer(0x00); RADIOLIB_VERBOSE_PRINT("%X\t", dataIn[n]); } } @@ -257,10 +175,10 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d RADIOLIB_VERBOSE_PRINTLN(); // release CS - this->digitalWrite(_cs, HIGH); + this->hal->digitalWrite(this->_cs, this->hal->GpioLevelHigh); // end SPI transaction - this->endTransaction(); + this->hal->spiEndTransaction(); } int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { @@ -311,7 +229,6 @@ int16_t Module::SPIcheckStream() { if(this->SPIparseStatusCb != nullptr) { this->SPIstreamError = this->SPIparseStatusCb(spiStatus); } - #endif return(state); @@ -323,24 +240,24 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint #endif // ensure GPIO is low - uint32_t start = this->millis(); - while(this->digitalRead(this->getGpio())) { - this->yield(); - if(this->millis() - start >= timeout) { - this->digitalWrite(this->getCs(), HIGH); + uint32_t start = this->hal->millis(); + while(this->hal->digitalRead(this->_gpio)) { + this->hal->yield(); + if(this->hal->millis() - start >= timeout) { + this->hal->digitalWrite(this->_cs, this->hal->GpioLevelLow); return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } // pull NSS low - this->digitalWrite(this->getCs(), LOW); + this->hal->digitalWrite(this->_cs, this->hal->GpioLevelLow); // start transfer - this->beginTransaction(); + this->hal->spiBeginTransaction(); // send command byte(s) for(uint8_t n = 0; n < cmdLen; n++) { - this->transfer(cmd[n]); + this->hal->spiTransfer(cmd[n]); } // variable to save error during SPI transfer @@ -350,7 +267,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint if(write) { for(size_t n = 0; n < numBytes; n++) { // send byte - uint8_t in = this->transfer(dataOut[n]); + uint8_t in = this->hal->spiTransfer(dataOut[n]); #if defined(RADIOLIB_VERBOSE) debugBuff[n] = in; #endif @@ -363,7 +280,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } else { // skip the first byte for read-type commands (status-only) - uint8_t in = this->transfer(this->SPInopCommand); + uint8_t in = this->hal->spiTransfer(this->SPInopCommand); #if defined(RADIOLIB_VERBOSE) debugBuff[0] = in; #endif @@ -378,22 +295,22 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // read the data if(state == RADIOLIB_ERR_NONE) { for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->transfer(this->SPInopCommand); + dataIn[n] = this->hal->spiTransfer(this->SPInopCommand); } } } // stop transfer - this->endTransaction(); - this->digitalWrite(this->getCs(), HIGH); + this->hal->spiEndTransaction(); + this->hal->digitalWrite(this->_cs, this->hal->GpioLevelHigh); // wait for GPIO to go high and then low if(waitForGpio) { - this->delayMicroseconds(1); - uint32_t start = this->millis(); - while(this->digitalRead(this->getGpio())) { - this->yield(); - if(this->millis() - start >= timeout) { + this->hal->delayMicroseconds(1); + uint32_t start = this->hal->millis(); + while(this->hal->digitalRead(this->_gpio)) { + this->hal->yield(); + if(this->hal->millis() - start >= timeout) { state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; break; } @@ -440,238 +357,15 @@ void Module::waitForMicroseconds(uint32_t start, uint32_t len) { } this->TimerFlag = false; while(!this->TimerFlag) { - this->yield(); - } - #else - while(this->micros() - start < len) { - this->yield(); - } - #endif -} - -void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) { - if((pin == RADIOLIB_NC) || (cb_pinMode == nullptr)) { - return; - } - cb_pinMode(pin, mode); -} - -void Module::digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value) { - if((pin == RADIOLIB_NC) || (cb_digitalWrite == nullptr)) { - return; - } - cb_digitalWrite(pin, value); -} - -RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) { - if((pin == RADIOLIB_NC) || (cb_digitalRead == nullptr)) { - return((RADIOLIB_PIN_STATUS)0); - } - return(cb_digitalRead(pin)); -} - -#if defined(ESP32) -// we need to cache the previous tone value for emulation on ESP32 -int32_t prev = -1; -#endif - -void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) { - #if !defined(RADIOLIB_TONE_UNSUPPORTED) - if((pin == RADIOLIB_NC) || (cb_tone == nullptr)) { - return; - } - cb_tone(pin, value, duration); - #else - if(pin == RADIOLIB_NC) { - return; - } - #if defined(ESP32) - // ESP32 tone() emulation - (void)duration; - if(prev == -1) { - ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); - } - if(prev != value) { - ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); - } - prev = value; - #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) - // better tone for mbed OS boards - (void)duration; - if(!pwmPin) { - pwmPin = new mbed::PwmOut(digitalPinToPinName(pin)); - } - pwmPin->period(1.0 / value); - pwmPin->write(0.5); - #else - (void)value; - (void)duration; - #endif - #endif -} - -void Module::noTone(RADIOLIB_PIN_TYPE pin) { - #if !defined(RADIOLIB_TONE_UNSUPPORTED) - if((pin == RADIOLIB_NC) || (cb_noTone == nullptr)) { - return; - } - #if defined(ARDUINO_ARCH_STM32) - cb_noTone(pin, false); - #else - cb_noTone(pin); - #endif - #else - if(pin == RADIOLIB_NC) { - return; - } - #if defined(ESP32) - // ESP32 tone() emulation - ledcDetachPin(pin); - ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); - prev = -1; - #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) - // better tone for mbed OS boards - (void)pin; - pwmPin->suspend(); - #endif - #endif -} - -void Module::attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode) { - if((interruptNum == RADIOLIB_NC) || (cb_attachInterrupt == nullptr)) { - return; + this->hal->yield(); } - cb_attachInterrupt(interruptNum, userFunc, mode); -} - -void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) { - if((interruptNum == RADIOLIB_NC) || (cb_detachInterrupt == nullptr)) { - return; - } - cb_detachInterrupt(interruptNum); -} - -void Module::yield() { - if(cb_yield == nullptr) { - return; - } - #if !defined(RADIOLIB_YIELD_UNSUPPORTED) - cb_yield(); - #endif -} - -void Module::delay(uint32_t ms) { - if(cb_delay == nullptr) { - return; - } - cb_delay(ms); -} - -void Module::delayMicroseconds(uint32_t us) { - if(cb_delayMicroseconds == nullptr) { - return; - } - cb_delayMicroseconds(us); -} - -uint32_t Module::millis() { - if(cb_millis == nullptr) { - return(0); - } - return(cb_millis()); -} - -uint32_t Module::micros() { - if(cb_micros == nullptr) { - return(0); - } - return(cb_micros()); -} - -uint32_t Module::pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout) { - if(cb_pulseIn == nullptr) { - return(0); - } - return(cb_pulseIn(pin, state, timeout)); -} - -void Module::begin() { - if(cb_SPIbegin == nullptr) { - return; - } - #if defined(RADIOLIB_BUILD_ARDUINO) - (this->*cb_SPIbegin)(); - #else - cb_SPIbegin(); - #endif -} - -void Module::beginTransaction() { - if(cb_SPIbeginTransaction == nullptr) { - return; - } - #if defined(RADIOLIB_BUILD_ARDUINO) - (this->*cb_SPIbeginTransaction)(); - #else - cb_SPIbeginTransaction(); - #endif -} - -uint8_t Module::transfer(uint8_t b) { - if(cb_SPItransfer == nullptr) { - return(0xFF); - } - #if defined(RADIOLIB_BUILD_ARDUINO) - return((this->*cb_SPItransfer)(b)); - #else - return(cb_SPItransfer(b)); - #endif -} - -void Module::endTransaction() { - if(cb_SPIendTransaction == nullptr) { - return; - } - #if defined(RADIOLIB_BUILD_ARDUINO) - (this->*cb_SPIendTransaction)(); #else - cb_SPIendTransaction(); - #endif -} - -void Module::end() { - if(cb_SPIend == nullptr) { - return; + while(this->hal->micros() - start < len) { + this->hal->yield(); } - #if defined(RADIOLIB_BUILD_ARDUINO) - (this->*cb_SPIend)(); - #else - cb_SPIend(); #endif } -#if defined(RADIOLIB_BUILD_ARDUINO) -void Module::SPIbegin() { - _spi->begin(); -} - -void Module::SPIbeginTransaction() { - _spi->beginTransaction(_spiSettings); -} - -uint8_t Module::SPItransfer(uint8_t b) { - return(_spi->transfer(b)); -} - -void Module::SPIendTransaction() { - _spi->endTransaction(); -} - -void Module::SPIend() { - _spi->end(); -} -#endif - uint8_t Module::flipBits(uint8_t b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xCC) >> 2 | (b & 0x33) << 2; @@ -771,26 +465,26 @@ size_t Module::serialPrintf(const char* format, ...) { } #endif -void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void Module::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { // This can be on the stack, setRfSwitchTable copies the contents - const RADIOLIB_PIN_TYPE pins[] = { + const uint8_t pins[] = { rxEn, txEn, RADIOLIB_NC, }; // This must be static, since setRfSwitchTable stores a reference. - static constexpr RfSwitchMode_t table[] = { - {MODE_IDLE, {LOW, LOW}}, - {MODE_RX, {HIGH, LOW}}, - {MODE_TX, {LOW, HIGH}}, + static const RfSwitchMode_t table[] = { + {MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow}}, + {MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow}}, + {MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh}}, END_OF_MODE_TABLE, }; setRfSwitchTable(pins, table); } -void Module::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[3], const RfSwitchMode_t table[]) { +void Module::setRfSwitchTable(const uint8_t (&pins)[3], const RfSwitchMode_t table[]) { memcpy(_rfSwitchPins, pins, sizeof(_rfSwitchPins)); _rfSwitchTable = table; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) - this->pinMode(pins[i], OUTPUT); + this->hal->pinMode(pins[i], this->hal->GpioModeOutput); } const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const { @@ -811,11 +505,11 @@ void Module::setRfSwitchState(uint8_t mode) { } // set pins - const RADIOLIB_PIN_STATUS *value = &row->values[0]; + const uint8_t *value = &row->values[0]; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { - RADIOLIB_PIN_TYPE pin = _rfSwitchPins[i]; + uint8_t pin = _rfSwitchPins[i]; if (pin != RADIOLIB_NC) - this->digitalWrite(pin, *value); + this->hal->digitalWrite(pin, *value); ++value; } } diff --git a/src/Module.h b/src/Module.h index 71ad40f9b2..7652d5accf 100644 --- a/src/Module.h +++ b/src/Module.h @@ -1,8 +1,8 @@ +#include "TypeDef.h" +#include "Hal.h" #if !defined(_RADIOLIB_MODULE_H) #define _RADIOLIB_MODULE_H -#include "TypeDef.h" - #if defined(RADIOLIB_BUILD_ARDUINO) #include #endif @@ -45,7 +45,7 @@ class Module { */ struct RfSwitchMode_t { uint8_t mode; - RADIOLIB_PIN_STATUS values[RFSWITCH_MAX_PINS]; + uint8_t values[RFSWITCH_MAX_PINS]; }; /*! @@ -69,9 +69,8 @@ class Module { }; #if defined(RADIOLIB_BUILD_ARDUINO) - /*! - \brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it + \brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it. \param cs Arduino pin to be used as chip select. @@ -81,7 +80,7 @@ class Module { \param gpio Arduino pin to be used as additional interrupt/GPIO. */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC); + Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio = RADIOLIB_NC); /*! \brief Arduino Module constructor. Will not attempt SPI interface initialization. @@ -98,24 +97,23 @@ class Module { \param spiSettings SPI interface settings. */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); - - #else + Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); + #endif /*! - \brief Default constructor. + \brief Module constructor. - \param cs Pin to be used as chip select. + \param hal A Hardware abstraction layer instance. An ArduinoHal instance for example. - \param irq Pin to be used as interrupt/GPIO. + \param cs Arduino pin to be used as chip select. - \param rst Pin to be used as hardware reset for the module. + \param irq Arduino pin to be used as interrupt/GPIO. - \param gpio Pin to be used as additional interrupt/GPIO. - */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC); + \param rst Arduino pin to be used as hardware reset for the module. - #endif + \param gpio Arduino pin to be used as additional interrupt/GPIO. + */ + Module(Hal *hal, uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio = RADIOLIB_NC); /*! \brief Copy constructor. @@ -133,6 +131,8 @@ class Module { // public member variables + Hal* hal = NULL; + /*! \brief Basic SPI read command. Defaults to 0x00. */ @@ -409,28 +409,28 @@ class Module { \returns Pin number of SPI chip select configured in the constructor. */ - RADIOLIB_PIN_TYPE getCs() const { return(_cs); } + uint8_t getCs() const { return(_cs); } /*! \brief Access method to get the pin number of interrupt/GPIO. \returns Pin number of interrupt/GPIO configured in the constructor. */ - RADIOLIB_PIN_TYPE getIrq() const { return(_irq); } + uint8_t getIrq() const { return(_irq); } /*! \brief Access method to get the pin number of hardware reset pin. \returns Pin number of hardware reset pin configured in the constructor. */ - RADIOLIB_PIN_TYPE getRst() const { return(_rst); } + uint8_t getRst() const { return(_rst); } /*! \brief Access method to get the pin number of second interrupt/GPIO. \returns Pin number of second interrupt/GPIO configured in the constructor. */ - RADIOLIB_PIN_TYPE getGpio() const { return(_gpio); } + uint8_t getGpio() const { return(_gpio); } /*! \brief Some modules contain external RF switch controlled by pins. @@ -448,7 +448,7 @@ class Module { \param rxEn RX enable pin. \param txEn TX enable pin. */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \brief Some modules contain external RF switch controlled by pins. @@ -494,7 +494,7 @@ class Module { \code // In global scope, define the pin array and mode table - static const RADIOLIB_PIN_TYPE rfswitch_pins[] = + static const uint8_t rfswitch_pins[] = {PA0, PA1, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {Module::MODE_IDLE, {LOW, LOW}}, @@ -512,7 +512,7 @@ class Module { \endcode */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); /*! * \brief Find a mode in the RfSwitchTable. @@ -541,137 +541,6 @@ class Module { */ void waitForMicroseconds(uint32_t start, uint32_t len); - // Arduino core overrides - - /*! - \brief Arduino core pinMode override that checks RADIOLIB_NC as alias for unused pin. - - \param pin Pin to change the mode of. - - \param mode Which mode to set. - */ - void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode); - - /*! - \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin. - - \param pin Pin to write to. - - \param value Whether to set the pin high or low. - */ - void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value); - - /*! - \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin. - - \param pin Pin to read from. - - \returns Pin value. - */ - RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin); - - /*! - \brief Arduino core tone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone. - - \param pin Pin to write to. - - \param value Frequency to output. - */ - void tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration = 0); - - /*! - \brief Arduino core noTone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone. - - \param pin Pin to write to. - */ - void noTone(RADIOLIB_PIN_TYPE pin); - - /*! - \brief Arduino core attachInterrupt override. - - \param interruptNum Interrupt number. - - \param userFunc Interrupt service routine. - - \param mode Pin hcange direction. - */ - void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode); - - /*! - \brief Arduino core detachInterrupt override. - - \param interruptNum Interrupt number. - */ - void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum); - - /*! - \brief Arduino core yield override. - */ - void yield(); - - /*! - \brief Arduino core delay override. - - \param ms Delay length in milliseconds. - */ - void delay(uint32_t ms); - - /*! - \brief Arduino core delayMicroseconds override. - - \param us Delay length in microseconds. - */ - void delayMicroseconds(uint32_t us); - - /*! - \brief Arduino core millis override. - */ - uint32_t millis(); - - /*! - \brief Arduino core micros override. - */ - uint32_t micros(); - - /*! - \brief Arduino core pulseIn override. - */ - uint32_t pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout); - - /*! - \brief Arduino core SPI begin override. - */ - void begin(); - - /*! - \brief Arduino core SPI beginTransaction override. - */ - void beginTransaction(); - - /*! - \brief Arduino core SPI transfer override. - */ - uint8_t transfer(uint8_t b); - - /*! - \brief Arduino core SPI endTransaction override. - */ - void endTransaction(); - - /*! - \brief Arduino core SPI end override. - */ - void end(); - - // helper functions to set up SPI overrides on Arduino - #if defined(RADIOLIB_BUILD_ARDUINO) - void SPIbegin(); - void SPIend(); - virtual void SPIbeginTransaction(); - virtual uint8_t SPItransfer(uint8_t b); - virtual void SPIendTransaction(); - #endif - /*! \brief Function to reflect bits within a byte. */ @@ -711,58 +580,18 @@ class Module { #if !defined(RADIOLIB_GODMODE) private: #endif - - // pins - RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC; - RADIOLIB_PIN_TYPE _gpio = RADIOLIB_NC; - - // SPI interface (Arduino only) - #if defined(RADIOLIB_BUILD_ARDUINO) - SPIClass* _spi = NULL; - SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; - bool _initInterface = false; - #endif + uint8_t _cs = RADIOLIB_NC; + uint8_t _irq = RADIOLIB_NC; + uint8_t _rst = RADIOLIB_NC; + uint8_t _gpio = RADIOLIB_NC; // RF switch pins and table - RADIOLIB_PIN_TYPE _rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + uint8_t _rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; const RfSwitchMode_t *_rfSwitchTable = nullptr; #if defined(RADIOLIB_INTERRUPT_TIMING) uint32_t _prevTimingLen = 0; #endif - - // hardware abstraction layer callbacks - // this is placed at the end of Module class because the callback generator macros - // screw with the private/public access specifiers - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_READ); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_TONE); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_NO_TONE); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_ATTACH_INTERRUPT); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DETACH_INTERRUPT); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_YIELD); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY_MICROSECONDS); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MILLIS); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MICROS); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PULSE_IN); - - #if defined(RADIOLIB_BUILD_ARDUINO) - RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN); - RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION); - RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_TRANSFER); - RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION); - RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END); - #else - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_TRANSFER); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION); - RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END); - #endif }; #endif diff --git a/src/RadioLib.h b/src/RadioLib.h index 419e0beac7..669169a9f9 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -38,6 +38,12 @@ #include "TypeDef.h" #include "Module.h" +#include "Hal.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "ArduinoHal.h" +#endif + + // warnings are printed in this file since BuildOpt.h is compiled in multiple places // check God mode diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 252ca8a2d2..578be43911 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1,4 +1,5 @@ #include "CC1101.h" +#include #if !defined(RADIOLIB_EXCLUDE_CC1101) CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) { @@ -14,7 +15,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po _mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; _mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); // try to find the CC1101 chip uint8_t i = 0; @@ -25,7 +26,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); - _mod->delay(10); + _mod->hal->delay(10); i++; } } @@ -99,22 +100,22 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission start or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getGpio())) { + _mod->hal->yield(); - if(_mod->micros() - start > timeout) { + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } // wait for transmission end or timeout - start = _mod->micros(); - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); + start = _mod->hal->micros(); + while(_mod->hal->digitalRead(_mod->getGpio())) { + _mod->hal->yield(); - if(_mod->micros() - start > timeout) { + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -132,11 +133,11 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); - if(_mod->micros() - start > timeout) { + if(_mod->hal->micros() - start > timeout) { standby(); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -219,27 +220,27 @@ int16_t CC1101::packetMode() { return(state); } -void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); +void CC1101::setGdo0Action(void (*func)(void), uint8_t dir) { + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, dir); } void CC1101::clearGdo0Action() { - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } -void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { +void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->pinMode(_mod->getGpio(), INPUT); - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, dir); } void CC1101::clearGdo2Action() { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio())); } int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -309,7 +310,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { * * TODO: test this on real hardware */ - _mod->delayMicroseconds(250); + _mod->hal->delayMicroseconds(250); } } @@ -371,17 +372,17 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); size_t readBytes = 0; - uint32_t lastPop = millis(); + uint32_t lastPop = _mod->hal->millis(); // keep reading from FIFO until we get all the packet. while (readBytes < length) { if (bytesInFIFO == 0) { - if (millis() - lastPop > 5) { + if (_mod->hal->millis() - lastPop > 5) { // readData was required to read a packet longer than the one received. RADIOLIB_DEBUG_PRINTLN("No data for more than 5mS. Stop here."); break; } else { - delay(1); + _mod->hal->delay(1); bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); continue; } @@ -391,7 +392,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { uint8_t bytesToRead = min((uint8_t)(length - readBytes), bytesInFIFO); SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, bytesToRead, &(data[readBytes])); readBytes += bytesToRead; - lastPop = millis(); + lastPop = _mod->hal->millis(); // Get how many bytes are left in FIFO. bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); @@ -401,7 +402,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; // for some reason, we need this delay here to get the correct status bytes - delay(3); + _mod->hal->delay(3); // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. if (isAppendStatus) { @@ -898,11 +899,11 @@ int16_t CC1101::setEncoding(uint8_t encoding) { } } -void CC1101::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void CC1101::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void CC1101::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void CC1101::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -912,7 +913,7 @@ uint8_t CC1101::randomByte() { RADIOLIB_DEBUG_PRINTLN("CC1101::randomByte"); // wait a bit for the RSSI reading to stabilise - _mod->delay(10); + _mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -932,15 +933,15 @@ int16_t CC1101::getChipVersion() { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void CC1101::setDirectAction(void (*func)(void)) { - setGdo0Action(func); + setGdo0Action(func, _mod->hal->GpioInterruptRising); } -void CC1101::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); +void CC1101::readBit(uint8_t pin) { + updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif -int16_t CC1101::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { +int16_t CC1101::setDIOMapping(uint8_t pin, uint8_t value) { if (pin > 2) return RADIOLIB_ERR_INVALID_DIO_PIN; @@ -952,7 +953,7 @@ int16_t CC1101::config() { SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); // Wait a ridiculous amount of time to be sure radio is ready. - _mod->delay(150); + _mod->hal->delay(150); // enable automatic frequency synthesizer calibration int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); @@ -1082,17 +1083,17 @@ void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { void CC1101::SPIsendCommand(uint8_t cmd) { // pull NSS low - _mod->digitalWrite(_mod->getCs(), LOW); + _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelLow); // start transfer - _mod->beginTransaction(); + _mod->hal->spiBeginTransaction(); // send the command byte - _mod->transfer(cmd); + _mod->hal->spiTransfer(cmd); // stop transfer - _mod->endTransaction(); - _mod->digitalWrite(_mod->getCs(), HIGH); + _mod->hal->spiEndTransaction(); + _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelHigh); } #endif diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 98f856588f..7d3e6f7f12 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -644,9 +644,9 @@ class CC1101: public PhysicalLayer { \param func ISR to call. - \param dir Signal change direction. Defaults to RISING. + \param dir Signal change direction. */ - void setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = RISING); + void setGdo0Action(void (*func)(void), uint8_t dir); /*! \brief Clears interrupt service routine to call when GDO0 activates. @@ -658,9 +658,9 @@ class CC1101: public PhysicalLayer { \param func ISR to call. - \param dir Signal change direction. Defaults to FALLING. + \param dir Signal change direction. */ - void setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = FALLING); + void setGdo2Action(void (*func)(void), uint8_t dir); /*! \brief Clears interrupt service routine to call when GDO0 activates. @@ -953,10 +953,10 @@ class CC1101: public PhysicalLayer { int16_t setEncoding(uint8_t encoding) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -985,7 +985,7 @@ class CC1101: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif /*! @@ -997,7 +997,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + int16_t setDIOMapping(uint8_t pin, uint8_t value); #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index a33e245f36..ce10e30457 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -1,4 +1,5 @@ #include "RF69.h" +#include #if !defined(RADIOLIB_EXCLUDE_RF69) RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) { @@ -12,7 +13,7 @@ Module* RF69::getMod() { int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); // try to find the RF69 chip uint8_t i = 0; @@ -27,7 +28,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); - _mod->delay(10); + _mod->hal->delay(10); i++; } } @@ -94,11 +95,11 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe } void RF69::reset() { - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), HIGH); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), LOW); - _mod->delay(10); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + _mod->hal->delay(10); } int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -110,11 +111,11 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); - if(_mod->micros() - start > timeout) { + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -132,11 +133,11 @@ int16_t RF69::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); - if(_mod->micros() - start > timeout) { + if(_mod->hal->micros() - start > timeout) { standby(); clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -271,26 +272,26 @@ int16_t RF69::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask } void RF69::setDio0Action(void (*func)(void)) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptRising); } void RF69::clearDio0Action() { - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } void RF69::setDio1Action(void (*func)(void)) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->pinMode(_mod->getGpio(), INPUT); - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, _mod->hal->GpioInterruptRising); } void RF69::clearDio1Action() { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio())); } void RF69::setFifoEmptyAction(void (*func)(void)) { @@ -298,10 +299,10 @@ void RF69::setFifoEmptyAction(void (*func)(void)) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); // we need to invert the logic here (as compared to setDio1Action), since we are using the "FIFO not empty interrupt" - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, FALLING); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, _mod->hal->GpioInterruptFalling); } void RF69::clearFifoEmptyAction() { @@ -758,7 +759,7 @@ int16_t RF69::getTemperature() { // wait until measurement is finished while(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_1, 2, 2) == RADIOLIB_RF69_TEMP_MEAS_RUNNING) { // check every 10 us - _mod->delay(10); + _mod->hal->delay(10); } int8_t rawTemp = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_2); @@ -916,11 +917,11 @@ int16_t RF69::setRSSIThreshold(float dbm) { return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } -void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void RF69::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void RF69::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void RF69::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -929,7 +930,7 @@ uint8_t RF69::randomByte() { setMode(RADIOLIB_RF69_RX); // wait a bit for the RSSI reading to stabilise - _mod->delay(10); + _mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -948,12 +949,12 @@ void RF69::setDirectAction(void (*func)(void)) { setDio1Action(func); } -void RF69::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); +void RF69::readBit(uint8_t pin) { + updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif -int16_t RF69::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { +int16_t RF69::setDIOMapping(uint8_t pin, uint8_t value) { if(pin > 5) { return(RADIOLIB_ERR_INVALID_DIO_PIN); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 5b4109a626..d8b434736b 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1035,10 +1035,10 @@ class RF69: public PhysicalLayer { int16_t setRSSIThreshold(float dbm); /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -1067,7 +1067,7 @@ class RF69: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif /*! @@ -1079,7 +1079,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + int16_t setDIOMapping(uint8_t pin, uint8_t value); #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index 8e81d89263..3b1b72f6e7 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -8,8 +8,8 @@ SX1231::SX1231(Module* mod) : RF69(mod) { int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getRst(), OUTPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); // try to find the SX1231 chip uint8_t i = 0; @@ -21,7 +21,7 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po _chipRevision = version; } else { RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); - _mod->delay(10); + _mod->hal->delay(10); i++; } } diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 0d94f4223d..44d61a88a0 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -9,6 +9,8 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #if !defined(RADIOLIB_EXCLUDE_STM32WLX) +#include "../../ArduinoHal.h" + // This defines some dummy pin numbers (starting at NUM_DIGITAL_PINS to // guarantee these are not valid regular pin numbers) that can be passed // to the parent Module class, to be stored here and then passed back to @@ -20,87 +22,85 @@ enum { RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, }; +class Stm32wlxHal : public ArduinoHal { + public: + Stm32wlxHal(): ArduinoHal(SubGhz.SPI, SubGhz.spi_settings) {} + + void pinMode(uint8_t dwPin, uint8_t dwMode) { + switch(dwPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + // Nothing to do + break; + default: + ::pinMode(dwPin, dwMode); + break; + } + } + + void digitalWrite(uint8_t dwPin, uint8_t dwVal) { + switch (dwPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + SubGhz.setNssActive(dwVal == LOW); + break; + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + SubGhz.setResetActive(dwVal == LOW); + break; + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + // Should not (and cannot) be written, just ignore + break; + + default: + ::digitalWrite(dwPin, dwVal); + break; + } + } + + uint8_t digitalRead(uint8_t ulPin) { + switch (ulPin) { + case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: + return(SubGhz.isBusy() ? HIGH : LOW); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: + // We cannot use the radio IRQ output directly, but since: + // - the pending flag will be set whenever the IRQ output is set, + // and + // - the pending flag will be cleared (by + // STM32WLx::clearIrqStatus()) whenever the radio IRQ output is + // cleared, + // the pending flag should always reflect the current radio IRQ + // output. There is one exception: when the ISR starts the pending + // flag is cleared by hardware and not set again until after the + // ISR finishes, so the value is incorrect *inside* the ISR, but + // running RadioLib code inside the ISR (especially code that + // polls the IRQ flag) is not supported and probably broken in + // other ways too. + return(SubGhz.isInterruptPending() ? HIGH : LOW); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: + return(SubGhz.isNssActive() ? LOW : HIGH); + + case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: + return(SubGhz.isResetActive() ? LOW : HIGH); + + default: + return(::digitalRead(ulPin)); + } + } +}; STM32WLx_Module::STM32WLx_Module(): Module( + new Stm32wlxHal, RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS, RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ, RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, - RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY, - SubGhz.SPI, - SubGhz.spi_settings - ) -{ - setCb_pinMode(virtualPinMode); - setCb_digitalWrite(virtualDigitalWrite); - setCb_digitalRead(virtualDigitalRead); -} - -void STM32WLx_Module::virtualPinMode(uint32_t dwPin, uint32_t dwMode) { - switch(dwPin) { - case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: - case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: - case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: - case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: - // Nothing to do - break; - default: - ::pinMode(dwPin, dwMode); - break; - } -} - -void STM32WLx_Module::virtualDigitalWrite(uint32_t dwPin, uint32_t dwVal) { - switch (dwPin) { - case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: - SubGhz.setNssActive(dwVal == LOW); - break; - - case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: - SubGhz.setResetActive(dwVal == LOW); - break; - - case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: - case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: - // Should not (and cannot) be written, just ignore - break; - - default: - ::digitalWrite(dwPin, dwVal); - break; - } -} - -int STM32WLx_Module::virtualDigitalRead(uint32_t ulPin) { - switch (ulPin) { - case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: - return(SubGhz.isBusy() ? HIGH : LOW); - - case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ: - // We cannot use the radio IRQ output directly, but since: - // - the pending flag will be set whenever the IRQ output is set, - // and - // - the pending flag will be cleared (by - // STM32WLx::clearIrqStatus()) whenever the radio IRQ output is - // cleared, - // the pending flag should always reflect the current radio IRQ - // output. There is one exception: when the ISR starts the pending - // flag is cleared by hardware and not set again until after the - // ISR finishes, so the value is incorrect *inside* the ISR, but - // running RadioLib code inside the ISR (especially code that - // polls the IRQ flag) is not supported and probably broken in - // other ways too. - return(SubGhz.isInterruptPending() ? HIGH : LOW); - - case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: - return(SubGhz.isNssActive() ? LOW : HIGH); - - case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET: - return(SubGhz.isResetActive() ? LOW : HIGH); - - default: - return(::digitalRead(ulPin)); - } -} + RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY + ) {} #endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) diff --git a/src/modules/SX126x/STM32WLx_Module.h b/src/modules/SX126x/STM32WLx_Module.h index 05f2b2fe12..f7d1d64de9 100644 --- a/src/modules/SX126x/STM32WLx_Module.h +++ b/src/modules/SX126x/STM32WLx_Module.h @@ -31,17 +31,6 @@ class STM32WLx_Module : public Module { public: STM32WLx_Module(); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - - // Replacement callbacks to handle virtual pins. These are static, - // since they replace global functions that cannot take any this - // pointer for context. - static void virtualPinMode(uint32_t dwPin, uint32_t dwMode); - static void virtualDigitalWrite(uint32_t dwPin, uint32_t dwVal); - static int virtualDigitalRead(uint32_t ulPin); }; #endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c2c8d1be38..c1b7d165e4 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1,4 +1,6 @@ #include "SX126x.h" +#include +#include #if !defined(RADIOLIB_EXCLUDE_SX126X) SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { @@ -13,8 +15,8 @@ Module* SX126x::getMod() { int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; @@ -95,8 +97,8 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; @@ -188,10 +190,10 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL int16_t SX126x::reset(bool verify) { // run the reset sequence - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), LOW); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); // return immediately when verification is disabled if(!verify) { @@ -199,7 +201,7 @@ int16_t SX126x::reset(bool verify) { } // set mode to standby - SX126x often refuses first few commands after reset - uint32_t start = _mod->millis(); + uint32_t start = _mod->hal->millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -209,13 +211,13 @@ int16_t SX126x::reset(bool verify) { } // standby command failed, check timeout and try again - if(_mod->millis() - start >= 1000) { + if(_mod->hal->millis() - start >= 1000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - _mod->delay(100); + _mod->hal->delay(100); } } @@ -252,15 +254,15 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - uint32_t elapsed = _mod->micros() - start; + uint32_t elapsed = _mod->hal->micros() - start; // update data rate _dataRate = (len*8.0)/((float)elapsed/1000000.0); @@ -302,10 +304,10 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { fixImplicitTimeout(); clearIrqStatus(); standby(); @@ -419,8 +421,8 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); } // check CAD result @@ -438,7 +440,7 @@ int16_t SX126x::sleep(bool retainConfig) { int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); // wait for SX126x to safely enter sleep mode - _mod->delay(1); + _mod->hal->delay(1); return(state); } @@ -456,11 +458,11 @@ int16_t SX126x::standby(uint8_t mode) { } void SX126x::setDio1Action(void (*func)(void)) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptRising); } void SX126x::clearDio1Action() { - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -517,8 +519,8 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); + while(_mod->hal->digitalRead(_mod->getGpio())) { + _mod->hal->yield(); } return(state); @@ -1357,11 +1359,11 @@ int16_t SX126x::setEncoding(uint8_t encoding) { return(setWhitening(encoding)); } -void SX126x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void SX126x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void SX126x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void SX126x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -1395,7 +1397,7 @@ uint8_t SX126x::randomByte() { setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); // wait a bit for the RSSI reading to stabilise - _mod->delay(10); + _mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -1433,8 +1435,8 @@ void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); } -void SX126x::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); +void SX126x::readBit(uint8_t pin) { + updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif @@ -1953,9 +1955,9 @@ int16_t SX126x::config(uint8_t modem) { RADIOLIB_ASSERT(state); // wait for calibration completion - _mod->delay(5); - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); + _mod->hal->delay(5); + while(_mod->hal->digitalRead(_mod->getGpio())) { + _mod->hal->yield(); } // check calibration result @@ -2010,7 +2012,7 @@ bool SX126x::findChip(const char* verStr) { _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); #endif - _mod->delay(10); + _mod->hal->delay(10); i++; } } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 54b3b4376f..560ca57030 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1031,10 +1031,10 @@ class SX126x: public PhysicalLayer { int16_t setEncoding(uint8_t encoding) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to @@ -1083,7 +1083,7 @@ class SX126x: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif /*! diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 64b75ba756..cd1514f11c 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -1,4 +1,5 @@ #include "SX1272.h" +#include #if !defined(RADIOLIB_EXCLUDE_SX127X) SX1272::SX1272(Module* mod) : SX127x(mod) { @@ -71,11 +72,11 @@ int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1272::reset() { - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), HIGH); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), LOW); - _mod->delay(5); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + _mod->hal->delay(5); } int16_t SX1272::setFrequency(float freq) { diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 5633910fbc..4c8159a42b 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -1,4 +1,5 @@ #include "SX1278.h" +#include #if !defined(RADIOLIB_EXCLUDE_SX127X) SX1278::SX1278(Module* mod) : SX127x(mod) { @@ -71,11 +72,11 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1278::reset() { - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), LOW); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), HIGH); - _mod->delay(5); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + _mod->hal->delay(5); } int16_t SX1278::setFrequency(float freq) { diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index faf01796f5..7394f42b4a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1,4 +1,5 @@ #include "SX127x.h" +#include #if !defined(RADIOLIB_EXCLUDE_SX127X) SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) { @@ -12,8 +13,8 @@ Module* SX127x::getMod() { int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { @@ -59,8 +60,8 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe int16_t SX127x::beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { @@ -152,10 +153,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -170,10 +171,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -183,7 +184,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // update data rate - uint32_t elapsed = _mod->micros() - start; + uint32_t elapsed = _mod->hal->micros() - start; _dataRate = (len*8.0)/((float)elapsed/1000000.0); return(finishTransmit()); @@ -208,19 +209,19 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { } // wait for packet reception or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); if(_mod->getGpio() == RADIOLIB_NC) { // no GPIO pin provided, use software timeout - if(_mod->micros() - start > timeout) { + if(_mod->hal->micros() - start > timeout) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } } else { // GPIO provided, use that - if(_mod->digitalRead(_mod->getGpio())) { + if(_mod->hal->digitalRead(_mod->getGpio())) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -237,10 +238,10 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -259,9 +260,9 @@ int16_t SX127x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->digitalRead(_mod->getGpio())) { + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->digitalRead(_mod->getGpio())) { return(RADIOLIB_PREAMBLE_DETECTED); } } @@ -425,31 +426,31 @@ int16_t SX127x::startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, return(startReceive((uint8_t)len, (uint8_t)mode)); } -void SX127x::setDio0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); +void SX127x::setDio0Action(void (*func)(void), uint8_t dir) { + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, dir); } void SX127x::clearDio0Action() { - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } -void SX127x::setDio1Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { +void SX127x::setDio1Action(void (*func)(void), uint8_t dir) { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, dir); } void SX127x::clearDio1Action() { if(_mod->getGpio() == RADIOLIB_NC) { return; } - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio())); } void SX127x::setFifoEmptyAction(void (*func)(void)) { // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) - setDio1Action(func); + setDio1Action(func, _mod->hal->GpioInterruptRising); } void SX127x::clearFifoEmptyAction() { @@ -462,7 +463,7 @@ void SX127x::setFifoFullAction(void (*func)(void)) { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4); // set DIO1 to the FIFO full event - setDio1Action(func); + setDio1Action(func, _mod->hal->GpioInterruptRising); } void SX127x::clearFifoFullAction() { @@ -1266,11 +1267,11 @@ uint8_t SX127x::getModemStatus() { return(_mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT)); } -void SX127x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void SX127x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void SX127x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void SX127x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -1285,7 +1286,7 @@ uint8_t SX127x::randomByte() { setMode(RADIOLIB_SX127X_RX); // wait a bit for the RSSI reading to stabilise - _mod->delay(10); + _mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -1326,7 +1327,7 @@ int8_t SX127x::getTempRaw() { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0); // wait - _mod->delayMicroseconds(200); + _mod->hal->delayMicroseconds(200); // disable temperature reading _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0); @@ -1432,7 +1433,7 @@ bool SX127x::findChip(uint8_t ver) { flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X, expected 0x00%X", i + 1, version, ver); - _mod->delay(10); + _mod->hal->delay(10); i++; } } @@ -1504,11 +1505,11 @@ int16_t SX127x::invertIQ(bool invertIQ) { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX127x::setDirectAction(void (*func)(void)) { - setDio1Action(func); + setDio1Action(func, _mod->hal->GpioInterruptRising); } -void SX127x::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); +void SX127x::readBit(uint8_t pin) { + updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif @@ -1533,7 +1534,7 @@ void SX127x::clearFHSSInt(void) { } } -int16_t SX127x::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { +int16_t SX127x::setDIOMapping(uint8_t pin, uint8_t value) { if (pin > 5) return RADIOLIB_ERR_INVALID_DIO_PIN; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index a6faa65f6c..489b2efcd2 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -725,9 +725,9 @@ class SX127x: public PhysicalLayer { \param func Pointer to interrupt service routine. - \param dir Signal change direction. Defaults to RISING. + \param dir Signal change direction. */ - void setDio0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = RISING); + void setDio0Action(void (*func)(void), uint8_t dir); /*! \brief Clears interrupt service routine to call when DIO0 activates. @@ -739,9 +739,9 @@ class SX127x: public PhysicalLayer { \param func Pointer to interrupt service routine. - \param dir Signal change direction. Defaults to RISING. + \param dir Signal change direction. */ - void setDio1Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = RISING); + void setDio1Action(void (*func)(void), uint8_t dir); /*! \brief Clears interrupt service routine to call when DIO1 activates. @@ -1155,10 +1155,10 @@ class SX127x: public PhysicalLayer { int8_t getTempRaw(); /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -1196,7 +1196,7 @@ class SX127x: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif /*! @@ -1236,7 +1236,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + int16_t setDIOMapping(uint8_t pin, uint8_t value); /*! \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 3d963c8d71..224d4f8e90 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -1,4 +1,5 @@ #include "SX1280.h" +#include #if !defined(RADIOLIB_EXCLUDE_SX128X) SX1280::SX1280(Module* mod) : SX1281(mod) { @@ -11,10 +12,10 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { RADIOLIB_ASSERT(state); // wait until ranging is finished - uint32_t start = _mod->millis(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->millis() - start > 10000) { + uint32_t start = _mod->hal->millis(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->millis() - start > 10000) { clearIrqStatus(); standby(); return(RADIOLIB_ERR_RANGING_TIMEOUT); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 8c6ec31a56..47fb7d85dc 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1,4 +1,5 @@ #include "SX128x.h" +#include #if !defined(RADIOLIB_EXCLUDE_SX128X) SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { @@ -12,8 +13,8 @@ Module* SX128x::getMod() { int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; @@ -73,8 +74,8 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, uint16_t preambleLength) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; @@ -142,8 +143,8 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, uint8_t dataShaping) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; @@ -197,8 +198,8 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, uint8_t dataShaping) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getGpio(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; @@ -261,10 +262,10 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin int16_t SX128x::reset(bool verify) { // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), LOW); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); // return immediately when verification is disabled if(!verify) { @@ -272,7 +273,7 @@ int16_t SX128x::reset(bool verify) { } // set mode to standby - uint32_t start = _mod->millis(); + uint32_t start = _mod->hal->millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -282,13 +283,13 @@ int16_t SX128x::reset(bool verify) { } // standby command failed, check timeout and try again - if(_mod->millis() - start >= 3000) { + if(_mod->hal->millis() - start >= 3000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - _mod->delay(10); + _mod->hal->delay(10); } } @@ -318,10 +319,10 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -352,10 +353,10 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->micros(); - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { clearIrqStatus(); standby(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -415,8 +416,8 @@ int16_t SX128x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + while(!_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); } // check CAD result @@ -445,7 +446,7 @@ int16_t SX128x::sleep(bool retainConfig) { int16_t state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); // wait for SX128x to safely enter sleep mode - _mod->delay(1); + _mod->hal->delay(1); return(state); } @@ -463,11 +464,11 @@ int16_t SX128x::standby(uint8_t mode) { } void SX128x::setDio1Action(void (*func)(void)) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptRising); } void SX128x::clearDio1Action() { - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -527,8 +528,8 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(_mod->digitalRead(_mod->getGpio())) { - _mod->yield(); + while(_mod->hal->digitalRead(_mod->getGpio())) { + _mod->hal->yield(); } return(state); @@ -1265,11 +1266,11 @@ int16_t SX128x::setEncoding(uint8_t encoding) { return(setWhitening(encoding)); } -void SX128x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void SX128x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void SX128x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void SX128x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -1299,7 +1300,7 @@ void SX128x::setDirectAction(void (*func)(void)) { (void)func; } -void SX128x::readBit(RADIOLIB_PIN_TYPE pin) { +void SX128x::readBit(uint8_t pin) { // SX128x is unable to perform direct mode reception // this method is implemented only for PhysicalLayer compatibility (void)pin; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 1aac8c74a9..5a36b07b86 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -817,10 +817,10 @@ class SX128x: public PhysicalLayer { int16_t setEncoding(uint8_t encoding) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Dummy random method, to ensure PhysicalLayer compatibility. @@ -851,7 +851,7 @@ class SX128x: public PhysicalLayer { \param pin Ignored. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 8571900423..8fa4c505ef 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -1,4 +1,5 @@ #include "Si443x.h" +#include #if !defined(RADIOLIB_EXCLUDE_SI443X) Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { @@ -12,9 +13,9 @@ Module* Si443x::getMod() { int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { // set module properties _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), LOW); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); // try to find the Si443x chip if(!Si443x::findChip()) { @@ -67,11 +68,11 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) } void Si443x::reset() { - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), HIGH); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), LOW); - _mod->delay(100); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + _mod->hal->delay(100); } int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -83,10 +84,10 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = _mod->micros(); - while(_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); + if(_mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -104,9 +105,9 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->micros(); - while(_mod->digitalRead(_mod->getIrq())) { - if(_mod->micros() - start > timeout) { + uint32_t start = _mod->hal->micros(); + while(_mod->hal->digitalRead(_mod->getIrq())) { + if(_mod->hal->micros() - start > timeout) { standby(); clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -206,11 +207,11 @@ int16_t Si443x::packetMode() { } void Si443x::setIrqAction(void (*func)(void)) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptFalling); } void Si443x::clearIrqAction() { - _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); + _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -575,11 +576,11 @@ int16_t Si443x::setDataShaping(uint8_t sh) { } } -void Si443x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { +void Si443x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void Si443x::setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void Si443x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -588,7 +589,7 @@ uint8_t Si443x::randomByte() { _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); // wait a bit for the RSSI reading to stabilise - _mod->delay(10); + _mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -611,8 +612,8 @@ void Si443x::setDirectAction(void (*func)(void)) { setIrqAction(func); } -void Si443x::readBit(RADIOLIB_PIN_TYPE pin) { - updateDirectBuffer((uint8_t)_mod->digitalRead(pin)); +void Si443x::readBit(uint8_t pin) { + updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif @@ -684,7 +685,7 @@ bool Si443x::findChip() { flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); - _mod->delay(10); + _mod->hal->delay(10); i++; } } diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 1cc75c5030..924ad93661 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -810,10 +810,10 @@ class Si443x: public PhysicalLayer { int16_t setDataShaping(uint8_t sh) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const RADIOLIB_PIN_TYPE (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -842,7 +842,7 @@ class Si443x: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif /*! diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index d8194d217a..a2f8792f97 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -1,4 +1,5 @@ #include "nRF24.h" +#include #if !defined(RADIOLIB_EXCLUDE_NRF24) nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) { @@ -14,14 +15,14 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW _mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; _mod->SPIwriteCommand = RADIOLIB_NRF24_CMD_WRITE; _mod->init(); - _mod->pinMode(_mod->getIrq(), INPUT); + _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); // set pin mode on RST (connected to nRF24 CE pin) - _mod->pinMode(_mod->getRst(), OUTPUT); - _mod->digitalWrite(_mod->getRst(), LOW); + _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); // wait for minimum power-on reset duration - _mod->delay(100); + _mod->hal->delay(100); // check SPI connection int16_t val = _mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); @@ -79,7 +80,7 @@ int16_t nRF24::standby(uint8_t mode) { // make sure carrier output is disabled _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_OFF, 7, 7); _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_OFF, 4, 4); - _mod->digitalWrite(_mod->getRst(), LOW); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); // use standby-1 mode return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, mode, 1, 1)); @@ -91,9 +92,9 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait until transmission is finished - uint32_t start = _mod->micros(); - while(_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); // check maximum number of retransmits if(getStatus(RADIOLIB_NRF24_MAX_RT)) { @@ -102,7 +103,7 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { } // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(_mod->micros() - start >= 60000) { + if(_mod->hal->micros() - start >= 60000) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -117,12 +118,12 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for Rx_DataReady or timeout - uint32_t start = _mod->micros(); - while(_mod->digitalRead(_mod->getIrq())) { - _mod->yield(); + uint32_t start = _mod->hal->micros(); + while(_mod->hal->digitalRead(_mod->getIrq())) { + _mod->hal->yield(); // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(_mod->micros() - start >= 60000) { + if(_mod->hal->micros() - start >= 60000) { standby(); clearIRQ(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -144,7 +145,7 @@ int16_t nRF24::transmitDirect(uint32_t frf) { int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_ON, 7, 7); state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_ON, 4, 4); - _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); return(state); } @@ -155,7 +156,7 @@ int16_t nRF24::receiveDirect() { } void nRF24::setIrqAction(void (*func)(void)) { - _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); + _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptFalling); } int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -191,9 +192,9 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { SPIwriteTxPayload(data, len); // CE high to start transmitting - _mod->digitalWrite(_mod->getRst(), HIGH); - _mod->delay(1); - _mod->digitalWrite(_mod->getRst(), LOW); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + _mod->hal->delay(1); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); return(state); } @@ -224,10 +225,10 @@ int16_t nRF24::startReceive() { SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); // CE high to start receiving - _mod->digitalWrite(_mod->getRst(), HIGH); + _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); // wait to enter Rx state - _mod->delay(1); + _mod->hal->delay(1); return(state); } @@ -558,7 +559,7 @@ void nRF24::setDirectAction(void (*func)(void)) { (void)func; } -void nRF24::readBit(RADIOLIB_PIN_TYPE pin) { +void nRF24::readBit(uint8_t pin) { // nRF24 is unable to perform direct mode actions // this method is implemented only for PhysicalLayer compatibility (void)pin; @@ -601,7 +602,7 @@ int16_t nRF24::config() { // power up _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1); - _mod->delay(5); + _mod->hal->delay(5); return(state); } @@ -616,26 +617,26 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // start transfer - _mod->digitalWrite(_mod->getCs(), LOW); - _mod->beginTransaction(); + _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelLow); + _mod->hal->spiBeginTransaction(); // send command - _mod->transfer(cmd); + _mod->hal->spiTransfer(cmd); // send data if(write) { for(uint8_t i = 0; i < numBytes; i++) { - _mod->transfer(dataOut[i]); + _mod->hal->spiTransfer(dataOut[i]); } } else { for(uint8_t i = 0; i < numBytes; i++) { - dataIn[i] = _mod->transfer(0x00); + dataIn[i] = _mod->hal->spiTransfer(0x00); } } // stop transfer - _mod->endTransaction(); - _mod->digitalWrite(_mod->getCs(), HIGH); + _mod->hal->spiEndTransaction(); + _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelHigh); } #endif diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index ae47877cb8..574685c5dc 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -528,7 +528,7 @@ class nRF24: public PhysicalLayer { \param pin Ignored. */ - void readBit(RADIOLIB_PIN_TYPE pin); + void readBit(uint8_t pin); #endif #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index 29c0044815..080ebe7e7e 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -1,7 +1,7 @@ #include "AFSK.h" #if !defined(RADIOLIB_EXCLUDE_AFSK) -AFSKClient::AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin): _pin(pin) { +AFSKClient::AFSKClient(PhysicalLayer* phy, uint8_t pin): _pin(pin) { _phy = phy; } @@ -20,13 +20,13 @@ int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { } Module* mod = _phy->getMod(); - mod->tone(_pin, freq); + mod->hal->tone(_pin, freq); return(RADIOLIB_ERR_NONE); } int16_t AFSKClient::noTone(bool keepOn) { Module* mod = _phy->getMod(); - mod->noTone(_pin); + mod->hal->noTone(_pin); if(keepOn) { return(0); } diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index 72b454717c..d84e40fb28 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -23,7 +23,7 @@ class AFSKClient { \param pin The pin that will be used for audio output. */ - AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin); + AFSKClient(PhysicalLayer* phy, uint8_t pin); /*! \brief Initialization method. @@ -56,7 +56,7 @@ class AFSKClient { private: #endif PhysicalLayer* _phy; - RADIOLIB_PIN_TYPE _pin; + uint8_t _pin; // allow specific classes access the private PhysicalLayer pointer friend class RTTYClient; diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 3d812bc80c..fece55ef60 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -1,4 +1,7 @@ #include "APRS.h" +#include +#include +#include #if !defined(RADIOLIB_EXCLUDE_APRS) APRSClient::APRSClient(AX25Client* ax) { diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 5b657c4107..0e8a77b2c6 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -1,4 +1,5 @@ #include "AX25.h" +#include #if !defined(RADIOLIB_EXCLUDE_AX25) AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control) @@ -409,7 +410,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // check each bit for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); if(stuffedFrameBuff[i] & mask) { _audio->tone(_afskMark, false); } else { diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index 9b9358b8df..dc6d61d499 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -1,8 +1,14 @@ #include "ExternalRadio.h" +#if defined(RADIOLIB_BUILD_ARDUINO) ExternalRadio::ExternalRadio() : PhysicalLayer(1, 0) { mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); } +#endif + +ExternalRadio::ExternalRadio(Hal *hal) : PhysicalLayer(1, 0) { + mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); +} Module* ExternalRadio::getMod() { return(mod); diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 524786435c..2e222babfb 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -3,12 +3,17 @@ #include "../../TypeDef.h" #include "../../Module.h" +#include "../../ArduinoHal.h" #include "../PhysicalLayer/PhysicalLayer.h" class ExternalRadio: public PhysicalLayer { public: + #if defined(RADIOLIB_BUILD_ARDUINO) ExternalRadio(); + #endif + ExternalRadio(Hal *hal); + Module* getMod(); private: Module* mod; diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 4ec074b944..fcd1d1d398 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -1,4 +1,5 @@ #include "FSK4.h" +#include #if !defined(RADIOLIB_EXCLUDE_FSK4) FSK4Client::FSK4Client(PhysicalLayer* phy) { @@ -80,7 +81,7 @@ size_t FSK4Client::write(uint8_t b) { void FSK4Client::tone(uint8_t i) { Module* mod = _phy->getMod(); - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); transmitDirect(_base + _tones[i], _baseHz + _tonesHz[i]); mod->waitForMicroseconds(start, _bitDuration); } diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 2607142b8a..c25f05f25f 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -1,4 +1,6 @@ #include "Hellschreiber.h" +#include +#include #if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) HellClient::HellClient(PhysicalLayer* phy) { @@ -34,7 +36,7 @@ size_t HellClient::printGlyph(uint8_t* buff) { bool transmitting = false; for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { for(int8_t i = RADIOLIB_HELL_FONT_HEIGHT - 1; i >= 0; i--) { - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); if((buff[i] & mask) && (!transmitting)) { transmitting = true; transmitDirect(_base, _baseHz); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 7810032f20..da5b57ff97 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -1,4 +1,7 @@ #include "Morse.h" +#include +#include +#include #if !defined(RADIOLIB_EXCLUDE_MORSE) MorseClient::MorseClient(PhysicalLayer* phy) { @@ -59,7 +62,7 @@ int MorseClient::read(byte* symbol, byte* len, float low, float high) { Module* mod = _phy->getMod(); // measure pulse duration in us - uint32_t duration = mod->pulseIn(_audio->_pin, LOW, 4*_basePeriod); + uint32_t duration = mod->hal->pulseIn(_audio->_pin, mod->hal->GpioLevelLow, 4*_basePeriod); // decide if this is a signal, or pause if((duration > low*_basePeriod) && (duration < high*_basePeriod)) { @@ -74,8 +77,8 @@ int MorseClient::read(byte* symbol, byte* len, float low, float high) { if((pauseCounter > 0) && (signalCounter == 1)) { // start of dot or dash pauseCounter = 0; - signalStart = mod->millis(); - uint32_t pauseLen = mod->millis() - pauseStart; + signalStart = mod->hal->millis(); + uint32_t pauseLen = mod->hal->millis() - pauseStart; if((pauseLen >= low*(float)_letterSpace) && (pauseLen <= high*(float)_letterSpace)) { return(RADIOLIB_MORSE_CHAR_COMPLETE); @@ -87,8 +90,8 @@ int MorseClient::read(byte* symbol, byte* len, float low, float high) { } else if((signalCounter > 0) && (pauseCounter == 1)) { // end of dot or dash signalCounter = 0; - pauseStart = mod->millis(); - uint32_t signalLen = mod->millis() - signalStart; + pauseStart = mod->hal->millis(); + uint32_t signalLen = mod->hal->millis() - signalStart; if((signalLen >= low*(float)_dotLength) && (signalLen <= high*(float)_dotLength)) { RADIOLIB_DEBUG_PRINT("."); @@ -135,7 +138,7 @@ size_t MorseClient::write(uint8_t b) { if(b == ' ') { RADIOLIB_DEBUG_PRINTLN("space"); standby(); - mod->waitForMicroseconds(mod->micros(), _wordSpace*1000); + mod->waitForMicroseconds(mod->hal->micros(), _wordSpace*1000); return(1); } @@ -154,16 +157,16 @@ size_t MorseClient::write(uint8_t b) { if (code & RADIOLIB_MORSE_DASH) { RADIOLIB_DEBUG_PRINT("-"); transmitDirect(_base, _baseHz); - mod->waitForMicroseconds(mod->micros(), _dashLength*1000); + mod->waitForMicroseconds(mod->hal->micros(), _dashLength*1000); } else { RADIOLIB_DEBUG_PRINT("."); transmitDirect(_base, _baseHz); - mod->waitForMicroseconds(mod->micros(), _dotLength*1000); + mod->waitForMicroseconds(mod->hal->micros(), _dotLength*1000); } // symbol space standby(); - mod->waitForMicroseconds(mod->micros(), _dotLength*1000); + mod->waitForMicroseconds(mod->hal->micros(), _dotLength*1000); // move onto the next bit code >>= 1; @@ -171,7 +174,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); - mod->waitForMicroseconds(mod->micros(), _letterSpace*1000 - _dotLength*1000); + mod->waitForMicroseconds(mod->hal->micros(), _letterSpace*1000 - _dotLength*1000); RADIOLIB_DEBUG_PRINTLN(); return(1); diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 5a51030871..14bf78d2ad 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,11 +1,13 @@ #include "Pager.h" +#include +#include #if !defined(RADIOLIB_EXCLUDE_PAGER) #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) // this is a massive hack, but we need a global-scope ISR to manage the bit reading // let's hope nobody ever tries running two POCSAG receivers at the same time static PhysicalLayer* _readBitInstance = NULL; -static RADIOLIB_PIN_TYPE _readBitPin = RADIOLIB_NC; +static uint8_t _readBitPin = RADIOLIB_NC; #if defined(ESP8266) || defined(ESP32) ICACHE_RAM_ATTR @@ -221,7 +223,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) -int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t mask) { +int16_t PagerClient::startReceive(uint8_t pin, uint32_t addr, uint32_t mask) { // save the variables _readBitPin = pin; _filterAddr = addr; @@ -241,7 +243,7 @@ int16_t PagerClient::startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t // now set up the direct mode reception Module* mod = _phy->getMod(); - mod->pinMode(pin, INPUT); + mod->hal->pinMode(pin, mod->hal->GpioModeInput); // set direct sync word to the frame sync word // the logic here is inverted, because modules like SX1278 @@ -453,7 +455,7 @@ void PagerClient::write(uint32_t codeWord) { Module* mod = _phy->getMod(); for(int8_t i = 31; i >= 0; i--) { uint32_t mask = (uint32_t)0x01 << i; - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); // figure out the shift direction - start by assuming the bit is 0 int16_t change = _shift; @@ -471,12 +473,12 @@ void PagerClient::write(uint32_t codeWord) { // now transmit the shifted frequency _phy->transmitDirect(_baseRaw + change); - // this is pretty silly, while(mod->micros() ... ) would be enough + // this is pretty silly, while(mod->hal->micros() ... ) would be enough // but for some reason, MegaCore throws a linker error on it // "relocation truncated to fit: R_AVR_7_PCREL against `no symbol'" - uint32_t now = mod->micros(); + uint32_t now = mod->hal->micros(); while(now - start < _bitDuration) { - now = mod->micros(); + now = mod->hal->micros(); } } } diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 966033fbca..7992c00583 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -157,7 +157,7 @@ class PagerClient { \returns \ref status_codes */ - int16_t startReceive(RADIOLIB_PIN_TYPE pin, uint32_t addr, uint32_t mask = 0xFFFFF); + int16_t startReceive(uint8_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); /*! \brief Get the number of POCSAG batches available in buffer. Limited by the size of direct mode buffer! diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 48eeda6103..66e139fbca 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -1,4 +1,5 @@ #include "PhysicalLayer.h" +#include PhysicalLayer::PhysicalLayer(float freqStep, size_t maxPacketLength) { _freqStep = freqStep; @@ -379,13 +380,13 @@ void PhysicalLayer::setDirectAction(void (*func)(void)) { (void)func; } -void PhysicalLayer::readBit(RADIOLIB_PIN_TYPE pin) { +void PhysicalLayer::readBit(uint8_t pin) { (void)pin; } #endif -int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { +int16_t PhysicalLayer::setDIOMapping(uint8_t pin, uint8_t value) { (void)pin; (void)value; return(RADIOLIB_ERR_UNSUPPORTED); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index ddf742b71a..0df9fb665e 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -360,7 +360,7 @@ class PhysicalLayer { \param pin Pin on which to read. */ - virtual void readBit(RADIOLIB_PIN_TYPE pin); + virtual void readBit(uint8_t pin); /*! \brief Get the number of direct mode bytes currently available in buffer. @@ -393,7 +393,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value); + virtual int16_t setDIOMapping(uint8_t pin, uint8_t value); /*! \brief Sets interrupt service routine to call when DIO1 activates. diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index abd4c6cb14..5f6158913c 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -1,4 +1,6 @@ #include "RTTY.h" +#include +#include #if !defined(RADIOLIB_EXCLUDE_RTTY) ITA2String::ITA2String(char c) { @@ -409,14 +411,14 @@ size_t RTTYClient::println(double d, int digits) { void RTTYClient::mark() { Module* mod = _phy->getMod(); - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); transmitDirect(_base + _shift, _baseHz + _shiftHz); mod->waitForMicroseconds(start, _bitDuration); } void RTTYClient::space() { Module* mod = _phy->getMod(); - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); transmitDirect(_base, _baseHz); mod->waitForMicroseconds(start, _bitDuration); } diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 9b4bcf7f01..1e7b0c5a33 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -291,7 +291,7 @@ uint16_t SSTVClient::getPictureHeight() const { void SSTVClient::tone(float freq, uint32_t len) { Module* mod = _phy->getMod(); - uint32_t start = mod->micros(); + uint32_t start = mod->hal->micros(); #if !defined(RADIOLIB_EXCLUDE_AFSK) if(_audio != nullptr) { _audio->tone(freq, false); From 7faeb46ada637675e4c96677de370dd773435bc4 Mon Sep 17 00:00:00 2001 From: Mestery Date: Thu, 13 Apr 2023 01:42:19 +0200 Subject: [PATCH 0475/1848] im so stupid --- src/Hal.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Hal.cpp b/src/Hal.cpp index 627c7d4dad..855835b08c 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -4,8 +4,8 @@ Hal::Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uint8_t high, const uint8_t rising, const uint8_t falling) : GpioModeInput(input), GpioModeOutput(output), - GpioLevelLow(high), - GpioLevelHigh(low), + GpioLevelLow(low), + GpioLevelHigh(high), GpioInterruptRising(rising), GpioInterruptFalling(falling) {} From d8f0d36407ae0e9d9c85350577fb3b23e96f2236 Mon Sep 17 00:00:00 2001 From: Mestery Date: Thu, 13 Apr 2023 17:50:27 +0200 Subject: [PATCH 0476/1848] fix --- src/ArduinoHal.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 438e4c9f7c..98ef02c886 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -84,7 +84,7 @@ void inline ArduinoHal::spiEnd() { void inline ArduinoHal::tone(uint8_t pin, unsigned int frequency, unsigned long duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if (pin == RADIOLIB_NC) { - return 0; + return; } ::tone(pin, frequency, duration); #elif defined(ESP32) @@ -110,17 +110,17 @@ void inline ArduinoHal::tone(uint8_t pin, unsigned int frequency, unsigned long void inline ArduinoHal::noTone(uint8_t pin) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) and defined(ARDUINO_ARCH_STM32) if (pin == RADIOLIB_NC) { - return 0; + return; } ::noTone(pin, false); #elif !defined(RADIOLIB_TONE_UNSUPPORTED) if (pin == RADIOLIB_NC) { - return 0; + return; } ::noTone(pin); #elif defined(ESP32) if (pin == RADIOLIB_NC) { - return 0; + return; } // ESP32 tone() emulation ledcDetachPin(pin); @@ -128,7 +128,7 @@ void inline ArduinoHal::noTone(uint8_t pin) { _prev = -1; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) if (pin == RADIOLIB_NC) { - return 0; + return; } // better tone for mbed OS boards (void)pin; From 3d43a618e36e4f90d5ab28da7da994d609f5d5b0 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 20:54:31 +0200 Subject: [PATCH 0477/1848] guard arduinohal include --- src/protocols/ExternalRadio/ExternalRadio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 2e222babfb..0f72133011 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -3,7 +3,9 @@ #include "../../TypeDef.h" #include "../../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) #include "../../ArduinoHal.h" +#endif #include "../PhysicalLayer/PhysicalLayer.h" From f37c0b55c0bde726bb80e454f155fd93d2e6864e Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 20:54:48 +0200 Subject: [PATCH 0478/1848] try move include inside --- src/Module.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Module.h b/src/Module.h index 7652d5accf..ce0ee954bf 100644 --- a/src/Module.h +++ b/src/Module.h @@ -1,8 +1,9 @@ -#include "TypeDef.h" -#include "Hal.h" #if !defined(_RADIOLIB_MODULE_H) #define _RADIOLIB_MODULE_H +#include "TypeDef.h" +#include "Hal.h" + #if defined(RADIOLIB_BUILD_ARDUINO) #include #endif From 0cf308be04cc11f34f421d273663aec44fb185ec Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 21:00:05 +0200 Subject: [PATCH 0479/1848] remove byte usage --- src/BuildOpt.h | 2 -- src/protocols/Morse/Morse.cpp | 2 +- src/protocols/Morse/Morse.h | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 8bded0cc9d..cf219cfd06 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -273,8 +273,6 @@ #include #include - typedef uint8_t byte; - using std::max; using std::min; #endif diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index da5b57ff97..afbb03a7e8 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -58,7 +58,7 @@ char MorseClient::decode(uint8_t symbol, uint8_t len) { } #if !defined(RADIOLIB_EXCLUDE_AFSK) -int MorseClient::read(byte* symbol, byte* len, float low, float high) { +int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { Module* mod = _phy->getMod(); // measure pulse duration in us diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index fe60cc7cf9..3f0fc5cb36 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -153,7 +153,7 @@ class MorseClient { \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, 2 if inter-word space was detected. */ #if !defined(RADIOLIB_EXCLUDE_AFSK) - int read(byte* symbol, byte* len, float low = 0.75f, float high = 1.25f); + int read(uint8_t* symbol, uint8_t* len, float low = 0.75f, float high = 1.25f); #endif size_t write(const char* str); From e141f4f151c44caba978a713d070ad863437d61b Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 21:01:55 +0200 Subject: [PATCH 0480/1848] fix warnings --- src/Hal.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Hal.cpp b/src/Hal.cpp index 855835b08c..088665a64d 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -11,7 +11,15 @@ Hal::Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uin void Hal::init(){}; void Hal::term(){}; -void Hal::tone(uint8_t pin, unsigned int frequency, unsigned long duration){}; -void Hal::noTone(uint8_t pin){}; +void Hal::tone(uint8_t pin, unsigned int frequency, unsigned long duration){ + (void)pin; + (void)frequency; + (void)duration; +}; +void Hal::noTone(uint8_t pin){ + (void)pin; +}; void Hal::yield(){}; -uint8_t Hal::pinToInterrupt(uint8_t pin) { return pin; }; +uint8_t Hal::pinToInterrupt(uint8_t pin) { + return pin; +}; From 6695133576c5c421cab030dda2e891f93250764e Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 21:05:35 +0200 Subject: [PATCH 0481/1848] fix documentation --- keywords.txt | 2 ++ src/ArduinoHal.h | 11 +++++++++++ src/Module.h | 8 ++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/keywords.txt b/keywords.txt index 664dee1165..ab7dcfdb23 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,6 +9,8 @@ RadioLib KEYWORD1 RadioShield KEYWORD1 Module KEYWORD1 +Hal KEYWORD1 +ArduinoHal KEYWORD1 # modules CC1101 KEYWORD1 diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 79df17b39d..8a0044c58f 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -16,7 +16,18 @@ class ArduinoHal : public Hal { public: + /*! + \brief Arduino Hal constructor. Will use the default SPI interface and automatically initialize it. + */ ArduinoHal(); + + /*! + \brief Arduino Hal constructor. Will not attempt SPI interface initialization. + + \param spi SPI interface to be used, can also use software SPI implementations. + + \param spiSettings SPI interface settings. + */ ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); void init() override; diff --git a/src/Module.h b/src/Module.h index ce0ee954bf..4ff07380bb 100644 --- a/src/Module.h +++ b/src/Module.h @@ -106,13 +106,13 @@ class Module { \param hal A Hardware abstraction layer instance. An ArduinoHal instance for example. - \param cs Arduino pin to be used as chip select. + \param cs Pin to be used as chip select. - \param irq Arduino pin to be used as interrupt/GPIO. + \param irq Pin to be used as interrupt/GPIO. - \param rst Arduino pin to be used as hardware reset for the module. + \param rst Pin to be used as hardware reset for the module. - \param gpio Arduino pin to be used as additional interrupt/GPIO. + \param gpio Pin to be used as additional interrupt/GPIO. */ Module(Hal *hal, uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio = RADIOLIB_NC); From 9a68a3c9012e1ffe5dc94cb4d116cbe71ad3d3ea Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 21:39:00 +0200 Subject: [PATCH 0482/1848] use uint32 instead of uint8 for pin type --- .../STM32WLx_Receive/STM32WLx_Receive.ino | 2 +- .../STM32WLx_Receive_Interrupt.ino | 2 +- .../STM32WLx_Transmit/STM32WLx_Transmit.ino | 2 +- .../STM32WLx_Transmit_Interrupt.ino | 2 +- src/ArduinoHal.cpp | 18 ++++----- src/ArduinoHal.h | 24 +++++++----- src/BuildOpt.h | 2 +- src/Hal.cpp | 8 ++-- src/Hal.h | 37 +++++++++++-------- src/Module.cpp | 16 ++++---- src/Module.h | 32 ++++++++-------- src/modules/CC1101/CC1101.cpp | 8 ++-- src/modules/CC1101/CC1101.h | 8 ++-- src/modules/RF69/RF69.cpp | 8 ++-- src/modules/RF69/RF69.h | 8 ++-- src/modules/SX126x/STM32WLx_Module.cpp | 6 +-- src/modules/SX126x/SX126x.cpp | 6 +-- src/modules/SX126x/SX126x.h | 6 +-- src/modules/SX127x/SX127x.cpp | 8 ++-- src/modules/SX127x/SX127x.h | 8 ++-- src/modules/SX128x/SX128x.cpp | 6 +-- src/modules/SX128x/SX128x.h | 6 +-- src/modules/Si443x/Si443x.cpp | 6 +-- src/modules/Si443x/Si443x.h | 6 +-- src/modules/nRF24/nRF24.cpp | 2 +- src/modules/nRF24/nRF24.h | 2 +- src/protocols/AFSK/AFSK.cpp | 2 +- src/protocols/AFSK/AFSK.h | 4 +- src/protocols/Pager/Pager.cpp | 4 +- src/protocols/Pager/Pager.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 4 +- 32 files changed, 135 insertions(+), 124 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino index 2b96d15777..b5f159657c 100644 --- a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino +++ b/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino @@ -32,7 +32,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const uint8_t rfswitch_pins[] = +static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index 0bb545134b..2ce572121f 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -31,7 +31,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const uint8_t rfswitch_pins[] = +static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino index cd1577d6f8..7455cafd6b 100644 --- a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino +++ b/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino @@ -28,7 +28,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const uint8_t rfswitch_pins[] = +static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index 6e4e361b18..900e52d204 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -23,7 +23,7 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! -static const uint8_t rfswitch_pins[] = +static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 98ef02c886..6688a4f8e0 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -18,31 +18,31 @@ void ArduinoHal::term() { } } -void inline ArduinoHal::pinMode(uint8_t pin, uint8_t mode) { +void inline ArduinoHal::pinMode(uint32_t pin, uint32_t mode) { if (pin == RADIOLIB_NC) { return; } ::pinMode(pin, RADIOLIB_ARDUINOHAL_PIN_MODE_CAST mode); } -void inline ArduinoHal::digitalWrite(uint8_t pin, uint8_t value) { +void inline ArduinoHal::digitalWrite(uint32_t pin, uint32_t value) { if (pin == RADIOLIB_NC) { return; } ::digitalWrite(pin, RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST value); } -uint8_t inline ArduinoHal::digitalRead(uint8_t pin) { +uint32_t inline ArduinoHal::digitalRead(uint32_t pin) { if (pin == RADIOLIB_NC) { return 0; } return ::digitalRead(pin); } -void inline ArduinoHal::attachInterrupt(uint8_t interruptNum, void (*interruptCb)(void), uint8_t mode) { +void inline ArduinoHal::attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) { if (interruptNum == RADIOLIB_NC) { return; } ::attachInterrupt(interruptNum, interruptCb, RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST mode); } -void inline ArduinoHal::detachInterrupt(uint8_t interruptNum) { +void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) { if (interruptNum == RADIOLIB_NC) { return; } @@ -60,7 +60,7 @@ unsigned long inline ArduinoHal::millis() { unsigned long inline ArduinoHal::micros() { return ::micros(); } -long inline ArduinoHal::pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) { +long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) { if (pin == RADIOLIB_NC) { return 0; } @@ -81,7 +81,7 @@ void inline ArduinoHal::spiEndTransaction() { void inline ArduinoHal::spiEnd() { _spi->end(); } -void inline ArduinoHal::tone(uint8_t pin, unsigned int frequency, unsigned long duration) { +void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if (pin == RADIOLIB_NC) { return; @@ -107,7 +107,7 @@ void inline ArduinoHal::tone(uint8_t pin, unsigned int frequency, unsigned long pwmPin->write(0.5); #endif } -void inline ArduinoHal::noTone(uint8_t pin) { +void inline ArduinoHal::noTone(uint32_t pin) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) and defined(ARDUINO_ARCH_STM32) if (pin == RADIOLIB_NC) { return; @@ -140,7 +140,7 @@ void inline ArduinoHal::yield() { ::yield(); #endif } -uint8_t inline ArduinoHal::pinToInterrupt(uint8_t pin) { +uint32_t inline ArduinoHal::pinToInterrupt(uint32_t pin) { return digitalPinToInterrupt(pin); } #endif diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 8a0044c58f..cc6da0eabf 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -14,6 +14,12 @@ #include +/*! + \class ArduinoHal + + \brief Arduino default hardware abstraction library implementation. + This class can be extended to support other Arduino platform or change behaviour of the default implementation +*/ class ArduinoHal : public Hal { public: /*! @@ -33,25 +39,25 @@ class ArduinoHal : public Hal { void init() override; void term() override; - void pinMode(uint8_t pin, uint8_t mode) override; - void digitalWrite(uint8_t pin, uint8_t value) override; - uint8_t digitalRead(uint8_t pin) override; - void attachInterrupt(uint8_t interruptNum, void (*interruptCb)(void), uint8_t mode) override; - void detachInterrupt(uint8_t interruptNum) override; + void pinMode(uint32_t pin, uint32_t mode) override; + void digitalWrite(uint32_t pin, uint32_t value) override; + uint32_t digitalRead(uint32_t pin) override; + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override; + void detachInterrupt(uint32_t interruptNum) override; void delay(unsigned long ms) override; void delayMicroseconds(unsigned long us) override; unsigned long millis() override; unsigned long micros() override; - long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) override; + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override; void spiBegin() override; void spiBeginTransaction() override; uint8_t spiTransfer(uint8_t b) override; void spiEndTransaction() override; void spiEnd() override; - void tone(uint8_t pin, unsigned int frequency, unsigned long duration = 0) override; - void noTone(uint8_t pin) override; + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override; + void noTone(uint32_t pin) override; void yield() override; - uint8_t pinToInterrupt(uint8_t pin) override; + uint32_t pinToInterrupt(uint32_t pin) override; #if !defined(RADIOLIB_GODMODE) private: diff --git a/src/BuildOpt.h b/src/BuildOpt.h index cf219cfd06..b0a74076c3 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -221,7 +221,7 @@ #endif #if !defined(RADIOLIB_NC) - #define RADIOLIB_NC (0xFF) + #define RADIOLIB_NC (0xFFFFFFFF) #endif #if !defined(RADIOLIB_DEFAULT_SPI) #define RADIOLIB_DEFAULT_SPI SPI diff --git a/src/Hal.cpp b/src/Hal.cpp index 088665a64d..56d8905a13 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -1,7 +1,7 @@ #include #include "Hal.h" -Hal::Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uint8_t high, const uint8_t rising, const uint8_t falling) +Hal::Hal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling) : GpioModeInput(input), GpioModeOutput(output), GpioLevelLow(low), @@ -11,15 +11,15 @@ Hal::Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uin void Hal::init(){}; void Hal::term(){}; -void Hal::tone(uint8_t pin, unsigned int frequency, unsigned long duration){ +void Hal::tone(uint32_t pin, unsigned int frequency, unsigned long duration){ (void)pin; (void)frequency; (void)duration; }; -void Hal::noTone(uint8_t pin){ +void Hal::noTone(uint32_t pin){ (void)pin; }; void Hal::yield(){}; -uint8_t Hal::pinToInterrupt(uint8_t pin) { +uint32_t Hal::pinToInterrupt(uint32_t pin) { return pin; }; diff --git a/src/Hal.h b/src/Hal.h index 1ee240d7d0..3c940e463c 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -3,40 +3,45 @@ #if !defined(_RADIOLIB_HAL_H) #define _RADIOLIB_HAL_H +/*! + \class Hal + + \brief Hardware abstraction library base interface. +*/ class Hal { public: - const uint8_t GpioModeInput; - const uint8_t GpioModeOutput; - const uint8_t GpioLevelLow; - const uint8_t GpioLevelHigh; - const uint8_t GpioInterruptRising; - const uint8_t GpioInterruptFalling; + const uint32_t GpioModeInput; + const uint32_t GpioModeOutput; + const uint32_t GpioLevelLow; + const uint32_t GpioLevelHigh; + const uint32_t GpioInterruptRising; + const uint32_t GpioInterruptFalling; - Hal(const uint8_t input, const uint8_t output, const uint8_t low, const uint8_t high, const uint8_t rising, const uint8_t falling); + Hal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); virtual void init(); virtual void term(); - virtual void pinMode(uint8_t pin, uint8_t mode) = 0; - virtual void digitalWrite(uint8_t pin, uint8_t value) = 0; - virtual uint8_t digitalRead(uint8_t pin) = 0; - virtual void attachInterrupt(uint8_t interruptNum, void (*interruptCb)(void), uint8_t mode) = 0; - virtual void detachInterrupt(uint8_t interruptNum) = 0; + virtual void pinMode(uint32_t pin, uint32_t mode) = 0; + virtual void digitalWrite(uint32_t pin, uint32_t value) = 0; + virtual uint32_t digitalRead(uint32_t pin) = 0; + virtual void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) = 0; + virtual void detachInterrupt(uint32_t interruptNum) = 0; virtual void delay(unsigned long ms) = 0; virtual void delayMicroseconds(unsigned long us) = 0; virtual unsigned long millis() = 0; virtual unsigned long micros() = 0; - virtual long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) = 0; + virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0; virtual void spiBegin() = 0; virtual void spiBeginTransaction() = 0; virtual uint8_t spiTransfer(uint8_t b) = 0; virtual void spiEndTransaction() = 0; virtual void spiEnd() = 0; - virtual void tone(uint8_t pin, unsigned int frequency, unsigned long duration = 0); - virtual void noTone(uint8_t pin); + virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0); + virtual void noTone(uint32_t pin); virtual void yield(); - virtual uint8_t pinToInterrupt(uint8_t pin); + virtual uint32_t pinToInterrupt(uint32_t pin); }; #endif diff --git a/src/Module.cpp b/src/Module.cpp index c05bd1fce3..5ff133cf2d 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -6,16 +6,16 @@ #if defined(RADIOLIB_BUILD_ARDUINO) #include "ArduinoHal.h" -Module::Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { this->hal = new ArduinoHal; } -Module::Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio, SPIClass& spi, SPISettings spiSettings) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { this->hal = new ArduinoHal(spi, spiSettings); } #endif -Module::Module(Hal *hal, uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(Hal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { this->hal = hal; } @@ -465,9 +465,9 @@ size_t Module::serialPrintf(const char* format, ...) { } #endif -void Module::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { // This can be on the stack, setRfSwitchTable copies the contents - const uint8_t pins[] = { + const uint32_t pins[] = { rxEn, txEn, RADIOLIB_NC, }; // This must be static, since setRfSwitchTable stores a reference. @@ -480,7 +480,7 @@ void Module::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { setRfSwitchTable(pins, table); } -void Module::setRfSwitchTable(const uint8_t (&pins)[3], const RfSwitchMode_t table[]) { +void Module::setRfSwitchTable(const uint32_t (&pins)[3], const RfSwitchMode_t table[]) { memcpy(_rfSwitchPins, pins, sizeof(_rfSwitchPins)); _rfSwitchTable = table; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) @@ -505,9 +505,9 @@ void Module::setRfSwitchState(uint8_t mode) { } // set pins - const uint8_t *value = &row->values[0]; + const uint32_t *value = &row->values[0]; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { - uint8_t pin = _rfSwitchPins[i]; + uint32_t pin = _rfSwitchPins[i]; if (pin != RADIOLIB_NC) this->hal->digitalWrite(pin, *value); ++value; diff --git a/src/Module.h b/src/Module.h index 4ff07380bb..effc7140f0 100644 --- a/src/Module.h +++ b/src/Module.h @@ -46,7 +46,7 @@ class Module { */ struct RfSwitchMode_t { uint8_t mode; - uint8_t values[RFSWITCH_MAX_PINS]; + uint32_t values[RFSWITCH_MAX_PINS]; }; /*! @@ -81,7 +81,7 @@ class Module { \param gpio Arduino pin to be used as additional interrupt/GPIO. */ - Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio = RADIOLIB_NC); + Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); /*! \brief Arduino Module constructor. Will not attempt SPI interface initialization. @@ -98,7 +98,7 @@ class Module { \param spiSettings SPI interface settings. */ - Module(uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); + Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); #endif /*! @@ -114,7 +114,7 @@ class Module { \param gpio Pin to be used as additional interrupt/GPIO. */ - Module(Hal *hal, uint8_t cs, uint8_t irq, uint8_t rst, uint8_t gpio = RADIOLIB_NC); + Module(Hal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); /*! \brief Copy constructor. @@ -410,28 +410,28 @@ class Module { \returns Pin number of SPI chip select configured in the constructor. */ - uint8_t getCs() const { return(_cs); } + uint32_t getCs() const { return(_cs); } /*! \brief Access method to get the pin number of interrupt/GPIO. \returns Pin number of interrupt/GPIO configured in the constructor. */ - uint8_t getIrq() const { return(_irq); } + uint32_t getIrq() const { return(_irq); } /*! \brief Access method to get the pin number of hardware reset pin. \returns Pin number of hardware reset pin configured in the constructor. */ - uint8_t getRst() const { return(_rst); } + uint32_t getRst() const { return(_rst); } /*! \brief Access method to get the pin number of second interrupt/GPIO. \returns Pin number of second interrupt/GPIO configured in the constructor. */ - uint8_t getGpio() const { return(_gpio); } + uint32_t getGpio() const { return(_gpio); } /*! \brief Some modules contain external RF switch controlled by pins. @@ -449,7 +449,7 @@ class Module { \param rxEn RX enable pin. \param txEn TX enable pin. */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \brief Some modules contain external RF switch controlled by pins. @@ -495,7 +495,7 @@ class Module { \code // In global scope, define the pin array and mode table - static const uint8_t rfswitch_pins[] = + static const uint32_t rfswitch_pins[] = {PA0, PA1, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {Module::MODE_IDLE, {LOW, LOW}}, @@ -513,7 +513,7 @@ class Module { \endcode */ - void setRfSwitchTable(const uint8_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); /*! * \brief Find a mode in the RfSwitchTable. @@ -581,13 +581,13 @@ class Module { #if !defined(RADIOLIB_GODMODE) private: #endif - uint8_t _cs = RADIOLIB_NC; - uint8_t _irq = RADIOLIB_NC; - uint8_t _rst = RADIOLIB_NC; - uint8_t _gpio = RADIOLIB_NC; + uint32_t _cs = RADIOLIB_NC; + uint32_t _irq = RADIOLIB_NC; + uint32_t _rst = RADIOLIB_NC; + uint32_t _gpio = RADIOLIB_NC; // RF switch pins and table - uint8_t _rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + uint32_t _rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; const RfSwitchMode_t *_rfSwitchTable = nullptr; #if defined(RADIOLIB_INTERRUPT_TIMING) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 578be43911..9e7664baa9 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -899,11 +899,11 @@ int16_t CC1101::setEncoding(uint8_t encoding) { } } -void CC1101::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void CC1101::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void CC1101::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void CC1101::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -936,12 +936,12 @@ void CC1101::setDirectAction(void (*func)(void)) { setGdo0Action(func, _mod->hal->GpioInterruptRising); } -void CC1101::readBit(uint8_t pin) { +void CC1101::readBit(uint32_t pin) { updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif -int16_t CC1101::setDIOMapping(uint8_t pin, uint8_t value) { +int16_t CC1101::setDIOMapping(uint32_t pin, uint32_t value) { if (pin > 2) return RADIOLIB_ERR_INVALID_DIO_PIN; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 7d3e6f7f12..775659d042 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -953,10 +953,10 @@ class CC1101: public PhysicalLayer { int16_t setEncoding(uint8_t encoding) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -985,7 +985,7 @@ class CC1101: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif /*! @@ -997,7 +997,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDIOMapping(uint8_t pin, uint8_t value); + int16_t setDIOMapping(uint32_t pin, uint32_t value); #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index ce10e30457..9d46c3089f 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -917,11 +917,11 @@ int16_t RF69::setRSSIThreshold(float dbm) { return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } -void RF69::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void RF69::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void RF69::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void RF69::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -949,12 +949,12 @@ void RF69::setDirectAction(void (*func)(void)) { setDio1Action(func); } -void RF69::readBit(uint8_t pin) { +void RF69::readBit(uint32_t pin) { updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif -int16_t RF69::setDIOMapping(uint8_t pin, uint8_t value) { +int16_t RF69::setDIOMapping(uint32_t pin, uint32_t value) { if(pin > 5) { return(RADIOLIB_ERR_INVALID_DIO_PIN); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d8b434736b..3b7e7129fb 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1035,10 +1035,10 @@ class RF69: public PhysicalLayer { int16_t setRSSIThreshold(float dbm); /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -1067,7 +1067,7 @@ class RF69: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif /*! @@ -1079,7 +1079,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDIOMapping(uint8_t pin, uint8_t value); + int16_t setDIOMapping(uint32_t pin, uint32_t value); #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 44d61a88a0..1336325b3f 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -26,7 +26,7 @@ class Stm32wlxHal : public ArduinoHal { public: Stm32wlxHal(): ArduinoHal(SubGhz.SPI, SubGhz.spi_settings) {} - void pinMode(uint8_t dwPin, uint8_t dwMode) { + void pinMode(uint32_t dwPin, uint32_t dwMode) { switch(dwPin) { case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: @@ -40,7 +40,7 @@ class Stm32wlxHal : public ArduinoHal { } } - void digitalWrite(uint8_t dwPin, uint8_t dwVal) { + void digitalWrite(uint32_t dwPin, uint32_t dwVal) { switch (dwPin) { case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: SubGhz.setNssActive(dwVal == LOW); @@ -61,7 +61,7 @@ class Stm32wlxHal : public ArduinoHal { } } - uint8_t digitalRead(uint8_t ulPin) { + uint32_t digitalRead(uint32_t ulPin) { switch (ulPin) { case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: return(SubGhz.isBusy() ? HIGH : LOW); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c1b7d165e4..b6745caf30 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1359,11 +1359,11 @@ int16_t SX126x::setEncoding(uint8_t encoding) { return(setWhitening(encoding)); } -void SX126x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void SX126x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -1435,7 +1435,7 @@ void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); } -void SX126x::readBit(uint8_t pin) { +void SX126x::readBit(uint32_t pin) { updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 560ca57030..8db7d53665 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1031,10 +1031,10 @@ class SX126x: public PhysicalLayer { int16_t setEncoding(uint8_t encoding) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to @@ -1083,7 +1083,7 @@ class SX126x: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif /*! diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7394f42b4a..331364fbb8 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1267,11 +1267,11 @@ uint8_t SX127x::getModemStatus() { return(_mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT)); } -void SX127x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void SX127x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void SX127x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void SX127x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -1508,7 +1508,7 @@ void SX127x::setDirectAction(void (*func)(void)) { setDio1Action(func, _mod->hal->GpioInterruptRising); } -void SX127x::readBit(uint8_t pin) { +void SX127x::readBit(uint32_t pin) { updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif @@ -1534,7 +1534,7 @@ void SX127x::clearFHSSInt(void) { } } -int16_t SX127x::setDIOMapping(uint8_t pin, uint8_t value) { +int16_t SX127x::setDIOMapping(uint32_t pin, uint32_t value) { if (pin > 5) return RADIOLIB_ERR_INVALID_DIO_PIN; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 489b2efcd2..02f64ed339 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1155,10 +1155,10 @@ class SX127x: public PhysicalLayer { int8_t getTempRaw(); /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -1196,7 +1196,7 @@ class SX127x: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif /*! @@ -1236,7 +1236,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDIOMapping(uint8_t pin, uint8_t value); + int16_t setDIOMapping(uint32_t pin, uint32_t value); /*! \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 47fb7d85dc..268a4e229f 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1266,11 +1266,11 @@ int16_t SX128x::setEncoding(uint8_t encoding) { return(setWhitening(encoding)); } -void SX128x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void SX128x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void SX128x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void SX128x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -1300,7 +1300,7 @@ void SX128x::setDirectAction(void (*func)(void)) { (void)func; } -void SX128x::readBit(uint8_t pin) { +void SX128x::readBit(uint32_t pin) { // SX128x is unable to perform direct mode reception // this method is implemented only for PhysicalLayer compatibility (void)pin; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 5a36b07b86..8ff947d6d8 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -817,10 +817,10 @@ class SX128x: public PhysicalLayer { int16_t setEncoding(uint8_t encoding) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Dummy random method, to ensure PhysicalLayer compatibility. @@ -851,7 +851,7 @@ class SX128x: public PhysicalLayer { \param pin Ignored. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 8fa4c505ef..445a3ff077 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -576,11 +576,11 @@ int16_t Si443x::setDataShaping(uint8_t sh) { } } -void Si443x::setRfSwitchPins(uint8_t rxEn, uint8_t txEn) { +void Si443x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { _mod->setRfSwitchPins(rxEn, txEn); } -void Si443x::setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { +void Si443x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { _mod->setRfSwitchTable(pins, table); } @@ -612,7 +612,7 @@ void Si443x::setDirectAction(void (*func)(void)) { setIrqAction(func); } -void Si443x::readBit(uint8_t pin) { +void Si443x::readBit(uint32_t pin) { updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); } #endif diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 924ad93661..595b0d9178 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -810,10 +810,10 @@ class Si443x: public PhysicalLayer { int16_t setDataShaping(uint8_t sh) override; /*! \copydoc Module::setRfSwitchPins */ - void setRfSwitchPins(uint8_t rxEn, uint8_t txEn); + void setRfSwitchPins(uint32_t rxEn, uint32_t txEn); /*! \copydoc Module::setRfSwitchTable */ - void setRfSwitchTable(const uint8_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Get one truly random byte from RSSI noise. @@ -842,7 +842,7 @@ class Si443x: public PhysicalLayer { \param pin Pin on which to read. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif /*! diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index a2f8792f97..9f4cea9cbe 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -559,7 +559,7 @@ void nRF24::setDirectAction(void (*func)(void)) { (void)func; } -void nRF24::readBit(uint8_t pin) { +void nRF24::readBit(uint32_t pin) { // nRF24 is unable to perform direct mode actions // this method is implemented only for PhysicalLayer compatibility (void)pin; diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 574685c5dc..5f683c8729 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -528,7 +528,7 @@ class nRF24: public PhysicalLayer { \param pin Ignored. */ - void readBit(uint8_t pin); + void readBit(uint32_t pin); #endif #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index 080ebe7e7e..003c729db5 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -1,7 +1,7 @@ #include "AFSK.h" #if !defined(RADIOLIB_EXCLUDE_AFSK) -AFSKClient::AFSKClient(PhysicalLayer* phy, uint8_t pin): _pin(pin) { +AFSKClient::AFSKClient(PhysicalLayer* phy, uint32_t pin): _pin(pin) { _phy = phy; } diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index d84e40fb28..bd125784a0 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -23,7 +23,7 @@ class AFSKClient { \param pin The pin that will be used for audio output. */ - AFSKClient(PhysicalLayer* phy, uint8_t pin); + AFSKClient(PhysicalLayer* phy, uint32_t pin); /*! \brief Initialization method. @@ -56,7 +56,7 @@ class AFSKClient { private: #endif PhysicalLayer* _phy; - uint8_t _pin; + uint32_t _pin; // allow specific classes access the private PhysicalLayer pointer friend class RTTYClient; diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 14bf78d2ad..9d2aa8f135 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -7,7 +7,7 @@ // this is a massive hack, but we need a global-scope ISR to manage the bit reading // let's hope nobody ever tries running two POCSAG receivers at the same time static PhysicalLayer* _readBitInstance = NULL; -static uint8_t _readBitPin = RADIOLIB_NC; +static uint32_t _readBitPin = RADIOLIB_NC; #if defined(ESP8266) || defined(ESP32) ICACHE_RAM_ATTR @@ -223,7 +223,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) -int16_t PagerClient::startReceive(uint8_t pin, uint32_t addr, uint32_t mask) { +int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { // save the variables _readBitPin = pin; _filterAddr = addr; diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 7992c00583..c0dc496012 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -157,7 +157,7 @@ class PagerClient { \returns \ref status_codes */ - int16_t startReceive(uint8_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); + int16_t startReceive(uint32_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); /*! \brief Get the number of POCSAG batches available in buffer. Limited by the size of direct mode buffer! diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 66e139fbca..eeabf806a7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -380,13 +380,13 @@ void PhysicalLayer::setDirectAction(void (*func)(void)) { (void)func; } -void PhysicalLayer::readBit(uint8_t pin) { +void PhysicalLayer::readBit(uint32_t pin) { (void)pin; } #endif -int16_t PhysicalLayer::setDIOMapping(uint8_t pin, uint8_t value) { +int16_t PhysicalLayer::setDIOMapping(uint32_t pin, uint32_t value) { (void)pin; (void)value; return(RADIOLIB_ERR_UNSUPPORTED); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 0df9fb665e..9dca1f23db 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -360,7 +360,7 @@ class PhysicalLayer { \param pin Pin on which to read. */ - virtual void readBit(uint8_t pin); + virtual void readBit(uint32_t pin); /*! \brief Get the number of direct mode bytes currently available in buffer. @@ -393,7 +393,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t setDIOMapping(uint8_t pin, uint8_t value); + virtual int16_t setDIOMapping(uint32_t pin, uint32_t value); /*! \brief Sets interrupt service routine to call when DIO1 activates. From f20cc978a7c3b222e29b1bedeec28d3154e42ff1 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 16 Apr 2023 21:45:39 +0200 Subject: [PATCH 0483/1848] update interrupt action mode type --- src/modules/CC1101/CC1101.cpp | 4 ++-- src/modules/CC1101/CC1101.h | 4 ++-- src/modules/SX127x/SX127x.cpp | 4 ++-- src/modules/SX127x/SX127x.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 9e7664baa9..433e1f3b8b 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -220,7 +220,7 @@ int16_t CC1101::packetMode() { return(state); } -void CC1101::setGdo0Action(void (*func)(void), uint8_t dir) { +void CC1101::setGdo0Action(void (*func)(void), uint32_t dir) { _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, dir); } @@ -228,7 +228,7 @@ void CC1101::clearGdo0Action() { _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } -void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) { +void CC1101::setGdo2Action(void (*func)(void), uint32_t dir) { if(_mod->getGpio() == RADIOLIB_NC) { return; } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 775659d042..28643edcd6 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -646,7 +646,7 @@ class CC1101: public PhysicalLayer { \param dir Signal change direction. */ - void setGdo0Action(void (*func)(void), uint8_t dir); + void setGdo0Action(void (*func)(void), uint32_t dir); /*! \brief Clears interrupt service routine to call when GDO0 activates. @@ -660,7 +660,7 @@ class CC1101: public PhysicalLayer { \param dir Signal change direction. */ - void setGdo2Action(void (*func)(void), uint8_t dir); + void setGdo2Action(void (*func)(void), uint32_t dir); /*! \brief Clears interrupt service routine to call when GDO0 activates. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 331364fbb8..e08ad1813c 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -426,7 +426,7 @@ int16_t SX127x::startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, return(startReceive((uint8_t)len, (uint8_t)mode)); } -void SX127x::setDio0Action(void (*func)(void), uint8_t dir) { +void SX127x::setDio0Action(void (*func)(void), uint32_t dir) { _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, dir); } @@ -434,7 +434,7 @@ void SX127x::clearDio0Action() { _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); } -void SX127x::setDio1Action(void (*func)(void), uint8_t dir) { +void SX127x::setDio1Action(void (*func)(void), uint32_t dir) { if(_mod->getGpio() == RADIOLIB_NC) { return; } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 02f64ed339..112e7d4325 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -727,7 +727,7 @@ class SX127x: public PhysicalLayer { \param dir Signal change direction. */ - void setDio0Action(void (*func)(void), uint8_t dir); + void setDio0Action(void (*func)(void), uint32_t dir); /*! \brief Clears interrupt service routine to call when DIO0 activates. @@ -741,7 +741,7 @@ class SX127x: public PhysicalLayer { \param dir Signal change direction. */ - void setDio1Action(void (*func)(void), uint8_t dir); + void setDio1Action(void (*func)(void), uint32_t dir); /*! \brief Clears interrupt service routine to call when DIO1 activates. From 2e8d0ae8a35c57dc6019fe5b26d8c26faf502371 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 17 Apr 2023 19:10:26 +0200 Subject: [PATCH 0484/1848] [SX126x] Fixed IQ inversion not caching (#731) --- src/modules/SX126x/SX126x.cpp | 17 +++++++++-------- src/modules/SX126x/SX126x.h | 3 ++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c2c8d1be38..4113950bf1 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -481,7 +481,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - state = setPacketParams(_preambleLength, _crcType, len, _headerType); + state = setPacketParams(_preambleLength, _crcType, len, _headerType, _invertIQ); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType, len); } else { @@ -629,7 +629,7 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, uint16_t irqFlags, uint16_t // restore original packet length uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - state = setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType); + state = setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); } else { @@ -842,7 +842,7 @@ int16_t SX126x::setPreambleLength(uint16_t preambleLength) { uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { _preambleLength = preambleLength; - return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType)); + return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ)); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { _preambleLengthFSK = preambleLength; return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType)); @@ -1171,7 +1171,7 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool _crcType = RADIOLIB_SX126X_LORA_CRC_OFF; } - return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType)); + return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ)); } return(RADIOLIB_ERR_UNKNOWN); @@ -1420,12 +1420,13 @@ int16_t SX126x::invertIQ(bool invertIQ) { return(RADIOLIB_ERR_WRONG_MODEM); } - uint8_t invert = RADIOLIB_SX126X_LORA_IQ_STANDARD; if(invertIQ) { - invert = RADIOLIB_SX126X_LORA_IQ_INVERTED; + _invertIQ = RADIOLIB_SX126X_LORA_IQ_INVERTED; + } else { + _invertIQ = RADIOLIB_SX126X_LORA_IQ_STANDARD; } - return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, invert)); + return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ)); } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) @@ -1745,7 +1746,7 @@ int16_t SX126x::setHeaderType(uint8_t headerType, size_t len) { } // set requested packet mode - int16_t state = setPacketParams(_preambleLength, _crcType, len, headerType); + int16_t state = setPacketParams(_preambleLength, _crcType, len, headerType, _invertIQ); RADIOLIB_ASSERT(state); // update cached value diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 54b3b4376f..d22d20dc78 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1156,7 +1156,7 @@ class SX126x: public PhysicalLayer { int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); - int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ = RADIOLIB_SX126X_LORA_IQ_STANDARD); + int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ); int16_t setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLength = 0xFF, uint8_t preambleDetectorLength = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setRegulatorMode(uint8_t mode); @@ -1205,6 +1205,7 @@ class SX126x: public PhysicalLayer { uint32_t _tcxoDelay = 0; size_t _implicitLen = 0; + uint8_t _invertIQ = RADIOLIB_SX126X_LORA_IQ_STANDARD; const char* _chipType; // Allow subclasses to define different TX modes From 21f2ef6836fa44e3a1999ea9adeeec11ebd8d147 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 17 Apr 2023 19:12:42 +0200 Subject: [PATCH 0485/1848] [SX128x] Fixed IQ inversion --- src/modules/SX128x/SX128x.cpp | 17 +++++++++-------- src/modules/SX128x/SX128x.h | 3 +++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 8c6ec31a56..2d16acc9a8 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -483,7 +483,7 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa); + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa, _invertIQ); } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len); } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { @@ -568,7 +568,7 @@ int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMa // set implicit mode and expected len if applicable if((_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ); RADIOLIB_ASSERT(state); } @@ -753,7 +753,7 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { // update packet parameters _preambleLengthLoRa = (e << 4) | m; - return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa)); + return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ)); } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { // GFSK or FLRC @@ -1008,7 +1008,7 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { } else { return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ); return(state); } @@ -1284,12 +1284,13 @@ int16_t SX128x::invertIQ(bool invertIQ) { return(RADIOLIB_ERR_WRONG_MODEM); } - uint8_t invert = RADIOLIB_SX128X_LORA_IQ_STANDARD; if(invertIQ) { - invert = RADIOLIB_SX128X_LORA_IQ_INVERTED; + _invertIQ = RADIOLIB_SX128X_LORA_IQ_INVERTED; + } else { + _invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD; } - return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, invert)); + return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ)); } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) @@ -1430,7 +1431,7 @@ int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { // update packet parameters _headerType = headerType; _payloadLen = len; - return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa)); + return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ)); } int16_t SX128x::config(uint8_t modem) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 1aac8c74a9..51cb48e064 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -905,6 +905,9 @@ class SX128x: public PhysicalLayer { // common parameters uint8_t _pwr = 0; + // cached LoRa parameters + uint8_t _invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD; + // cached GFSK parameters float _modIndexReal = 0; uint16_t _brKbps = 0; From 94050efb1bc5c95f1f81ef2e9f87299e2a214c26 Mon Sep 17 00:00:00 2001 From: Mestery Date: Tue, 18 Apr 2023 19:21:01 +0200 Subject: [PATCH 0486/1848] add example --- examples/NonArduino/Raspberry/main.cpp | 148 +++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 examples/NonArduino/Raspberry/main.cpp diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp new file mode 100644 index 0000000000..a3992dcd5d --- /dev/null +++ b/examples/NonArduino/Raspberry/main.cpp @@ -0,0 +1,148 @@ +#include "RadioLib.h" +#include "pigpio.h" + +class PiHal : public Hal { + public: + PiHal(uint8_t spiChannel = 0, uint32_t spiSpeed = 2000000) + : Hal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), + _spiChannel(spiChannel), + _spiSpeed(spiSpeed) {} + + void init() override { + gpioInitialise(); + spiBegin(); + } + void term() override { + spiEnd(); + gpioTerminate(); + } + + void pinMode(uint32_t pin, uint32_t mode) override { + if (pin == RADIOLIB_NC) return; + gpioSetMode(pin, mode); + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if (pin == RADIOLIB_NC) return; + gpioWrite(pin, value); + } + + uint32_t digitalRead(uint32_t pin) override { + if (pin == RADIOLIB_NC) return 0; + return gpioRead(pin); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), + uint32_t mode) override { + if (interruptNum == RADIOLIB_NC) return; + gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); + } + + void detachInterrupt(uint32_t interruptNum) override { + if (interruptNum == RADIOLIB_NC) return; + gpioSetISRFunc(interruptNum, NULL, NULL, nullptr); + } + + void delay(unsigned long ms) override { gpioDelay(ms * 1000); } + + void delayMicroseconds(unsigned long us) override { gpioDelay(us); } + + unsigned long millis() override { return gpioTick() / 1000; } + + unsigned long micros() override { return gpioTick(); } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if (pin == RADIOLIB_NC) return 0; + gpioSetMode(pin, PI_INPUT); + uint32_t start = gpioTick(); + uint32_t curtick = gpioTick(); + + while (gpioRead(pin) == state) + if ((gpioTick() - curtick) > timeout) return 0; + while (gpioRead(pin) != state) + if ((gpioTick() - curtick) > timeout) return 0; + while (gpioRead(pin) == state) + if ((gpioTick() - curtick) > timeout) return 0; + + return gpioTick() - start; + } + + void spiBegin() { + if (_spiHandle < 0) { + _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + } + } + + void spiBeginTransaction() {} + + uint8_t spiTransfer(uint8_t b) { + char ret; + spiXfer(_spiHandle, (char*)&b, &ret, 1); + return ret; + } + + void spiEndTransaction() {} + + void spiEnd() { + if (_spiHandle >= 0) { + spiClose(_spiHandle); + _spiHandle = -1; + } + } + + private: + const unsigned int _spiSpeed; + const uint8_t _spiChannel; + int _spiHandle = -1; +}; + +CC1101 radio = new Module(new PiHal(), 8, 24, RADIOLIB_NC, 25); + +void onPacket() { + uint8_t* byteArr = new uint8_t[128]; + int state = radio.readData(byteArr, sizeof(byteArr)); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + printf("success!\n"); + + // print the data of the packet + printf("[CC1101] Data:\t\t"); + for (int b = 0; b < sizeof(byteArr); b++){ + printf("%X", byteArr[b]); + } + printf("\n"); + + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + printf("[CC1101] RSSI:\t\t%d dBm\n", radio.getRSSI()); + + // print LQI (Link Quality Indicator) + // of the last received packet, lower is better + printf("[CC1101] LQI:\t\t%d\n", radio.getLQI()); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + printf("timeout!\n"); + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + printf("CRC error!\n"); + } else { + printf("failed, code %d\n", state); + } + + radio.startReceive(); +} + +int main(int argc, char** argv) { + int state = radio.begin(); + if (state != RADIOLIB_ERR_NONE) { + printf("init failed, code %d", state); + return 1; + } + + radio.setGdo0Action(onPacket, RISING_EDGE); + state = radio.startReceive(); + if (state != RADIOLIB_ERR_NONE) { + printf("start receive failed, code %d", state); + return 1; + } +} + From 7e47910430c9f7f90cf45546c1d934eeaf00579c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:07:27 +0200 Subject: [PATCH 0487/1848] [HAL] Renamed Hal to RadioLibHal --- keywords.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index ab7dcfdb23..6a2d0f6d2b 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,7 +9,7 @@ RadioLib KEYWORD1 RadioShield KEYWORD1 Module KEYWORD1 -Hal KEYWORD1 +RadioLibHal KEYWORD1 ArduinoHal KEYWORD1 # modules From d5fe5e3e2d0d7963ce68c055a086ec11d65b517c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:07:47 +0200 Subject: [PATCH 0488/1848] [HAL] Cleaned up example and added comments --- examples/NonArduino/Raspberry/main.cpp | 260 ++++++++++++++++--------- 1 file changed, 166 insertions(+), 94 deletions(-) diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index a3992dcd5d..442145c85b 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -1,110 +1,195 @@ +/* + RadioLib Non-Arduino Raspberry Pi Example + + This example shows how to use RadioLib without Arduino. + In this case, a CC1101 module is connected to Raspberry Pi + using the pigpio library. + + Can be used as a starting point to port RadioLib to any platform! + See this API reference page for details on the RadioLib hardware abstraction + https://jgromes.github.io/RadioLib/class_hal.html + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library #include "RadioLib.h" + +// include the library for Raspberry GPIO pins #include "pigpio.h" -class PiHal : public Hal { - public: - PiHal(uint8_t spiChannel = 0, uint32_t spiSpeed = 2000000) - : Hal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), - _spiChannel(spiChannel), - _spiSpeed(spiSpeed) {} +// create a new Raspberry Pi hardware abstraction layer +// using the pigpio library +// the HAL must inherit from the base RadioLibHal class +// and implement all of its virtual methods +class PiHal : public RadioLibHal { + public: + // default constructor - initializes the base HAL and any needed private members + PiHal(uint8_t spiChannel = 0, uint32_t spiSpeed = 2000000) + : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), + _spiChannel(spiChannel), + _spiSpeed(spiSpeed) { + + } - void init() override { - gpioInitialise(); - spiBegin(); - } - void term() override { - spiEnd(); - gpioTerminate(); - } + void init() override { + // first initialise pigpio library + gpioInitialise(); - void pinMode(uint32_t pin, uint32_t mode) override { - if (pin == RADIOLIB_NC) return; - gpioSetMode(pin, mode); - } + // now the SPI + spiBegin(); + } - void digitalWrite(uint32_t pin, uint32_t value) override { - if (pin == RADIOLIB_NC) return; - gpioWrite(pin, value); - } + void term() override { + // stop the SPI + spiEnd(); - uint32_t digitalRead(uint32_t pin) override { - if (pin == RADIOLIB_NC) return 0; - return gpioRead(pin); - } + // and now the pigpio library + gpioTerminate(); + } - void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), - uint32_t mode) override { - if (interruptNum == RADIOLIB_NC) return; - gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); - } + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if(pin == RADIOLIB_NC) { + return; + } + gpioSetMode(pin, mode); + } - void detachInterrupt(uint32_t interruptNum) override { - if (interruptNum == RADIOLIB_NC) return; - gpioSetISRFunc(interruptNum, NULL, NULL, nullptr); - } + void digitalWrite(uint32_t pin, uint32_t value) override { + if(pin == RADIOLIB_NC) { + return; + } + gpioWrite(pin, value); + } - void delay(unsigned long ms) override { gpioDelay(ms * 1000); } + uint32_t digitalRead(uint32_t pin) override { + if(pin == RADIOLIB_NC) { + return(0); + } + return(gpioRead(pin)); + } - void delayMicroseconds(unsigned long us) override { gpioDelay(us); } + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); + } - unsigned long millis() override { return gpioTick() / 1000; } + void detachInterrupt(uint32_t interruptNum) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + gpioSetISRFunc(interruptNum, NULL, NULL, nullptr); + } - unsigned long micros() override { return gpioTick(); } + void delay(unsigned long ms) override { + gpioDelay(ms * 1000); + } - long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { - if (pin == RADIOLIB_NC) return 0; - gpioSetMode(pin, PI_INPUT); - uint32_t start = gpioTick(); - uint32_t curtick = gpioTick(); + void delayMicroseconds(unsigned long us) override { + gpioDelay(us); + } - while (gpioRead(pin) == state) - if ((gpioTick() - curtick) > timeout) return 0; - while (gpioRead(pin) != state) - if ((gpioTick() - curtick) > timeout) return 0; - while (gpioRead(pin) == state) - if ((gpioTick() - curtick) > timeout) return 0; + unsigned long millis() override { + return(gpioTick() / 1000); + } - return gpioTick() - start; - } + unsigned long micros() override { + return(gpioTick()); + } - void spiBegin() { - if (_spiHandle < 0) { - _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + gpioSetMode(pin, PI_INPUT); + uint32_t start = gpioTick(); + uint32_t curtick = gpioTick(); + + while(gpioRead(pin) == state) { + if((gpioTick() - curtick) > timeout) { + return(0); + } + } + + return(gpioTick() - start); + } + + void spiBegin() { + if(_spiHandle < 0) { + _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + } } - } - void spiBeginTransaction() {} + void spiBeginTransaction() {} - uint8_t spiTransfer(uint8_t b) { - char ret; - spiXfer(_spiHandle, (char*)&b, &ret, 1); - return ret; - } + uint8_t spiTransfer(uint8_t b) { + char ret; + spiXfer(_spiHandle, (char*)&b, &ret, 1); + return(ret); + } - void spiEndTransaction() {} + void spiEndTransaction() {} - void spiEnd() { - if (_spiHandle >= 0) { - spiClose(_spiHandle); - _spiHandle = -1; + void spiEnd() { + if (_spiHandle >= 0) { + spiClose(_spiHandle); + _spiHandle = -1; + } } - } - private: - const unsigned int _spiSpeed; - const uint8_t _spiChannel; - int _spiHandle = -1; + private: + // the HAL can contain any additional private members + const unsigned int _spiSpeed; + const uint8_t _spiChannel; + int _spiHandle = -1; }; +// now we can create the radio module +// the first argument is a new isntance of the HAL class defined above +// the others are pin numbers CC1101 radio = new Module(new PiHal(), 8, 24, RADIOLIB_NC, 25); +// forward declaration of ISR function +void onPacket(); + +// the entry point for the program +int main(int argc, char** argv) { + // initialize just like with Arduino + printf("[CC1101] Initializing ... "); + int state = radio.begin(); + if (state != RADIOLIB_ERR_NONE) { + printf("failed, code %d", state ); + return(1); + } + + // set the function that will be called + // when new packet is received + // RISING_EDGE is from the pigpio library + radio.setGdo0Action(onPacket, RISING_EDGE); + + // start listening for packets + printf(F("[CC1101] Starting to listen ... ")); + state = radio.startReceive(); + if(state != RADIOLIB_ERR_NONE) { + printf("failed, code %d", state); + return(1); + } +} + void onPacket() { - uint8_t* byteArr = new uint8_t[128]; + // packet received, read the data + uint8_t byteArr[128]; int state = radio.readData(byteArr, sizeof(byteArr)); if (state == RADIOLIB_ERR_NONE) { // packet was successfully received - printf("success!\n"); + printf("[CC1101] Received packet!"); // print the data of the packet printf("[CC1101] Data:\t\t"); @@ -120,29 +205,16 @@ void onPacket() { // print LQI (Link Quality Indicator) // of the last received packet, lower is better printf("[CC1101] LQI:\t\t%d\n", radio.getLQI()); - } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { - printf("timeout!\n"); + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { - printf("CRC error!\n"); + // packet was received, but is malformed + printf("[CC1101] CRC error!\n"); + } else { - printf("failed, code %d\n", state); + // some other error occurred + printf("[CC1101] Failed, code %d\n", state); } + // put module back to listen mode radio.startReceive(); } - -int main(int argc, char** argv) { - int state = radio.begin(); - if (state != RADIOLIB_ERR_NONE) { - printf("init failed, code %d", state); - return 1; - } - - radio.setGdo0Action(onPacket, RISING_EDGE); - state = radio.startReceive(); - if (state != RADIOLIB_ERR_NONE) { - printf("start receive failed, code %d", state); - return 1; - } -} - From 37bb8af7687ebb349137d01fbc0847dcd2c61d3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:08:08 +0200 Subject: [PATCH 0489/1848] [HAL] Fixed formatting --- src/ArduinoHal.cpp | 129 ++++++++++++++++++++++++++------------------- src/ArduinoHal.h | 19 ++++--- 2 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 6688a4f8e0..8b176feba5 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -2,9 +2,9 @@ #if defined(RADIOLIB_BUILD_ARDUINO) -ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): Hal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&spi), _spiSettings(spiSettings) {} +ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&RADIOLIB_DEFAULT_SPI), _initInterface(true) {} -ArduinoHal::ArduinoHal(): Hal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&RADIOLIB_DEFAULT_SPI), _initInterface(true) {} +ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&spi), _spiSettings(spiSettings) {} void ArduinoHal::init() { if(_initInterface) { @@ -19,128 +19,147 @@ void ArduinoHal::term() { } void inline ArduinoHal::pinMode(uint32_t pin, uint32_t mode) { - if (pin == RADIOLIB_NC) { + if(pin == RADIOLIB_NC) { return; } ::pinMode(pin, RADIOLIB_ARDUINOHAL_PIN_MODE_CAST mode); } + void inline ArduinoHal::digitalWrite(uint32_t pin, uint32_t value) { - if (pin == RADIOLIB_NC) { + if(pin == RADIOLIB_NC) { return; } ::digitalWrite(pin, RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST value); } + uint32_t inline ArduinoHal::digitalRead(uint32_t pin) { - if (pin == RADIOLIB_NC) { + if(pin == RADIOLIB_NC) { return 0; } - return ::digitalRead(pin); + return(::digitalRead(pin)); } + void inline ArduinoHal::attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) { - if (interruptNum == RADIOLIB_NC) { + if(interruptNum == RADIOLIB_NC) { return; } ::attachInterrupt(interruptNum, interruptCb, RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST mode); } + void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) { - if (interruptNum == RADIOLIB_NC) { + if(interruptNum == RADIOLIB_NC) { return; } ::detachInterrupt(interruptNum); } + void inline ArduinoHal::delay(unsigned long ms) { ::delay(ms); } + void inline ArduinoHal::delayMicroseconds(unsigned long us) { ::delayMicroseconds(us); } + unsigned long inline ArduinoHal::millis() { - return ::millis(); + return(::millis()); } + unsigned long inline ArduinoHal::micros() { - return ::micros(); + return(::micros()); } + long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) { - if (pin == RADIOLIB_NC) { + if(pin == RADIOLIB_NC) { return 0; } - return ::pulseIn(pin, state, timeout); + return(::pulseIn(pin, state, timeout)); } + void inline ArduinoHal::spiBegin() { _spi->begin(); } + void inline ArduinoHal::spiBeginTransaction() { _spi->beginTransaction(_spiSettings); } + uint8_t inline ArduinoHal::spiTransfer(uint8_t b) { - return _spi->transfer(b); + return(_spi->transfer(b)); } + void inline ArduinoHal::spiEndTransaction() { _spi->endTransaction(); } + void inline ArduinoHal::spiEnd() { _spi->end(); } + void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) - if (pin == RADIOLIB_NC) { - return; - } - ::tone(pin, frequency, duration); + if(pin == RADIOLIB_NC) { + return; + } + ::tone(pin, frequency, duration); #elif defined(ESP32) - // ESP32 tone() emulation - (void)duration; - if(_prev == -1) { - ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); - } - if(_prev != frequency) { - ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); - } - _prev = frequency; + // ESP32 tone() emulation + (void)duration; + if(_prev == -1) { + ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); + } + if(_prev != frequency) { + ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); + } + _prev = frequency; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) - // better tone for mbed OS boards - (void)duration; - if(!pwmPin) { - pwmPin = new mbed::PwmOut(digitalPinToPinName(pin)); - } - pwmPin->period(1.0 / frequency); - pwmPin->write(0.5); + // better tone for mbed OS boards + (void)duration; + if(!pwmPin) { + pwmPin = new mbed::PwmOut(digitalPinToPinName(pin)); + } + pwmPin->period(1.0 / frequency); + pwmPin->write(0.5); #endif } + void inline ArduinoHal::noTone(uint32_t pin) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) and defined(ARDUINO_ARCH_STM32) - if (pin == RADIOLIB_NC) { - return; - } - ::noTone(pin, false); + if(pin == RADIOLIB_NC) { + return; + } + ::noTone(pin, false); #elif !defined(RADIOLIB_TONE_UNSUPPORTED) - if (pin == RADIOLIB_NC) { - return; - } - ::noTone(pin); + if(pin == RADIOLIB_NC) { + return; + } + ::noTone(pin); #elif defined(ESP32) - if (pin == RADIOLIB_NC) { - return; - } - // ESP32 tone() emulation - ledcDetachPin(pin); - ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); - _prev = -1; + if(pin == RADIOLIB_NC) { + return; + } + // ESP32 tone() emulation + ledcDetachPin(pin); + ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + _prev = -1; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) - if (pin == RADIOLIB_NC) { - return; - } - // better tone for mbed OS boards - (void)pin; - pwmPin->suspend(); + if(pin == RADIOLIB_NC) { + return; + } + // better tone for mbed OS boards + (void)pin; + pwmPin->suspend(); #endif } + void inline ArduinoHal::yield() { #if !defined(RADIOLIB_YIELD_UNSUPPORTED) ::yield(); #endif } + uint32_t inline ArduinoHal::pinToInterrupt(uint32_t pin) { - return digitalPinToInterrupt(pin); + return(digitalPinToInterrupt(pin)); } + #endif diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index cc6da0eabf..eeb21d0fb6 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -1,8 +1,10 @@ +// make sure this is always compiled #include "TypeDef.h" #if !defined(_RADIOLIB_ARDUINOHAL_H) #define _RADIOLIB_ARDUINOHAL_H +// this file only makes sense for Arduino builds #if defined(RADIOLIB_BUILD_ARDUINO) #if defined(RADIOLIB_MBED_TONE_OVERRIDE) @@ -10,7 +12,7 @@ #endif #include "Hal.h" -#include +//#include #include @@ -18,9 +20,9 @@ \class ArduinoHal \brief Arduino default hardware abstraction library implementation. - This class can be extended to support other Arduino platform or change behaviour of the default implementation + This class can be extended to support other Arduino platform or change behaviour of the default implementation. */ -class ArduinoHal : public Hal { +class ArduinoHal : public RadioLibHal { public: /*! \brief Arduino Hal constructor. Will use the default SPI interface and automatically initialize it. @@ -29,16 +31,12 @@ class ArduinoHal : public Hal { /*! \brief Arduino Hal constructor. Will not attempt SPI interface initialization. - \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. */ ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); - void init() override; - void term() override; - + // implementations of pure virtual RadioLibHal methods void pinMode(uint32_t pin, uint32_t mode) override; void digitalWrite(uint32_t pin, uint32_t value) override; uint32_t digitalRead(uint32_t pin) override; @@ -54,6 +52,10 @@ class ArduinoHal : public Hal { uint8_t spiTransfer(uint8_t b) override; void spiEndTransaction() override; void spiEnd() override; + + // implementations of virtual RadioLibHal methods + void init() override; + void term() override; void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override; void noTone(uint32_t pin) override; void yield() override; @@ -76,4 +78,5 @@ class ArduinoHal : public Hal { }; #endif + #endif From 09c3ac4f6be982550b27b167eef9ce3d92e04f2d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:11:00 +0200 Subject: [PATCH 0490/1848] [HAL] Formatting cleanup, added doxygen comments --- src/ArduinoHal.h | 1 - src/BuildOpt.h | 115 ++++++++---- src/Hal.cpp | 28 ++- src/Hal.h | 176 +++++++++++++++++- src/Module.cpp | 9 +- src/Module.h | 4 +- src/protocols/ExternalRadio/ExternalRadio.cpp | 2 +- src/protocols/ExternalRadio/ExternalRadio.h | 2 +- 8 files changed, 274 insertions(+), 63 deletions(-) diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index eeb21d0fb6..a74f73a9a8 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -12,7 +12,6 @@ #endif #include "Hal.h" -//#include #include diff --git a/src/BuildOpt.h b/src/BuildOpt.h index b0a74076c3..b24e8aa78e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -42,6 +42,20 @@ //#define RADIOLIB_TONE_UNSUPPORTED //#define RADIOLIB_YIELD_UNSUPPORTED + // in addition, the following macros may be defined if the Arduino core differs from the defaults + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // you might also have to define these if the Arduino core has some uncommon pin mode/status types + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST + // some of RadioLib drivers may be excluded, to prevent collisions with platforms (or to speed up build process) // the following is a complete list of all possible exclusion macros, uncomment any of them to disable that driver // NOTE: Some of the exclusion macros are dependent on each other. For example, it is not possible to exclude RF69 @@ -65,107 +79,118 @@ //#define RADIOLIB_EXCLUDE_RTTY //#define RADIOLIB_EXCLUDE_SSTV //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE + #elif defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. #define RADIOLIB_PLATFORM "Arduino AVR" + #elif defined(ESP8266) // ESP8266 boards #define RADIOLIB_PLATFORM "ESP8266" + #elif defined(ESP32) // ESP32 boards #define RADIOLIB_PLATFORM "ESP32" + // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_TONE_ESP32_CHANNEL (1) + #elif defined(ARDUINO_ARCH_STM32) // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32) #define RADIOLIB_PLATFORM "Arduino STM32 (official)" + #elif defined(SAMD_SERIES) // Adafruit SAMD boards (M0 and M4) #define RADIOLIB_PLATFORM "Adafruit SAMD" + #elif defined(ARDUINO_ARCH_SAMD) // Arduino SAMD (Zero, MKR, etc.) #define RADIOLIB_PLATFORM "Arduino SAMD" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) #elif defined(__SAM3X8E__) // Arduino Due #define RADIOLIB_PLATFORM "Arduino Due" #define RADIOLIB_TONE_UNSUPPORTED + #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) // Adafruit nRF52 boards #define RADIOLIB_PLATFORM "Adafruit nRF52" + #elif defined(ARDUINO_ARC32_TOOLS) // Intel Curie #define RADIOLIB_PLATFORM "Intel Curie" + #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(PORTDUINO) // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every #define RADIOLIB_PLATFORM "Arduino megaAVR" + #elif defined(ARDUINO_ARCH_APOLLO3) // Sparkfun Apollo3 boards #define RADIOLIB_PLATFORM "Sparkfun Apollo3" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (Arduino_PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (Arduino_PinMode) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) #elif defined(ARDUINO_ARDUINO_NANO33BLE) // Arduino Nano 33 BLE #define RADIOLIB_PLATFORM "Arduino Nano 33 BLE" - - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_MBED_TONE_OVERRIDE + #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) // Arduino Portenta H7 #define RADIOLIB_PLATFORM "Portenta H7" - - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_MBED_TONE_OVERRIDE + #elif defined(__STM32F4__) || defined(__STM32F1__) // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) #define RADIOLIB_PLATFORM "STM32duino (unofficial)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (WiringPinMode) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (ExtIntTriggerMode) - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (WiringPinMode) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (ExtIntTriggerMode) #elif defined(ARDUINO_ARCH_MEGAAVR) // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX) #define RADIOLIB_PLATFORM "MegaCoreX" + #elif defined(ARDUINO_ARCH_MBED_RP2040) // Raspberry Pi Pico (official mbed core) #define RADIOLIB_PLATFORM "Raspberry Pi Pico" - - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_MBED_TONE_OVERRIDE + #elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico (unofficial core) #define RADIOLIB_PLATFORM "Raspberry Pi Pico (unofficial)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) #elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601) // CubeCell #define RADIOLIB_PLATFORM "CubeCell" #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(1000000, MSBFIRST, SPI_MODE0) // see issue #709 - - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PINMODE) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (IrqModes) + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PINMODE) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (IrqModes) // provide an easy access to the on-board module #include "board-config.h" @@ -188,6 +213,7 @@ #if defined(yield) #undef yield #endif + #elif defined(RASPI) // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) #define RADIOLIB_PLATFORM "RasPiArduino" @@ -211,46 +237,60 @@ #undef micros inline unsigned long micros() { return((unsigned long)(STCV)); }; #endif + #elif defined(TEENSYDUINO) // Teensy #define RADIOLIB_PLATFORM "Teensy" + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" #define RADIOLIB_UNKNOWN_PLATFORM + #endif + // set the default values for all macros + // these will be applied if they were not defined above #if !defined(RADIOLIB_NC) - #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_NC (0xFFFFFFFF) #endif + #if !defined(RADIOLIB_DEFAULT_SPI) - #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI SPI #endif + #if !defined(RADIOLIB_DEFAULT_SPI_SETTINGS) - #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) #endif + #if !defined(RADIOLIB_NONVOLATILE) - #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE PROGMEM #endif + #if !defined(RADIOLIB_NONVOLATILE_READ_BYTE) - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #endif + #if !defined(RADIOLIB_NONVOLATILE_READ_DWORD) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr) #endif + #if !defined(RADIOLIB_TYPE_ALIAS) - #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #endif #if !defined(RADIOLIB_ARDUINOHAL_PIN_MODE_CAST) - #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST #endif + #if !defined(RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST) - #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST #endif + #if !defined(RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST) - #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST #endif + #else // generic non-Arduino platform #define RADIOLIB_PLATFORM "Generic" @@ -262,7 +302,7 @@ #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #if !defined(RADIOLIB_DEBUG_PORT) - #define RADIOLIB_DEBUG_PORT stdout + #define RADIOLIB_DEBUG_PORT stdout #endif #define DEC 10 @@ -374,7 +414,6 @@ #define RADIOLIB_STATIC_ARRAY_SIZE (256) #endif - // This only compiles on STM32 boards with SUBGHZ module, but also // include when generating docs #if (!defined(ARDUINO_ARCH_STM32) || !defined(SUBGHZSPI_BASE)) && !defined(DOXYGEN) diff --git a/src/Hal.cpp b/src/Hal.cpp index 56d8905a13..0961fa4f85 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -1,7 +1,6 @@ -#include #include "Hal.h" -Hal::Hal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling) +RadioLibHal::RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling) : GpioModeInput(input), GpioModeOutput(output), GpioLevelLow(low), @@ -9,17 +8,28 @@ Hal::Hal(const uint32_t input, const uint32_t output, const uint32_t low, const GpioInterruptRising(rising), GpioInterruptFalling(falling) {} -void Hal::init(){}; -void Hal::term(){}; -void Hal::tone(uint32_t pin, unsigned int frequency, unsigned long duration){ +void RadioLibHal::init() { + +} + +void RadioLibHal::term() { + +} + +void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { (void)pin; (void)frequency; (void)duration; }; -void Hal::noTone(uint32_t pin){ + +void RadioLibHal::noTone(uint32_t pin) { (void)pin; }; -void Hal::yield(){}; -uint32_t Hal::pinToInterrupt(uint32_t pin) { - return pin; + +void RadioLibHal::yield() { + +}; + +uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { + return(pin); }; diff --git a/src/Hal.h b/src/Hal.h index 3c940e463c..64bfea2f0c 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -1,46 +1,208 @@ -#include -#include #if !defined(_RADIOLIB_HAL_H) #define _RADIOLIB_HAL_H +#include +#include + /*! \class Hal - \brief Hardware abstraction library base interface. */ -class Hal { +class RadioLibHal { public: + + // values for pin modes, levels and change directions + // these tell RadioLib how are different logic states represented on a given platform + + /*! + \brief Value to be used as the "input" GPIO direction. + */ const uint32_t GpioModeInput; + + /*! + \brief Value to be used as the "output" GPIO direction. + */ const uint32_t GpioModeOutput; + + /*! + \brief Value to be used as the "low" GPIO level. + */ const uint32_t GpioLevelLow; + + /*! + \brief Value to be used as the "high" GPIO level. + */ const uint32_t GpioLevelHigh; + + /*! + \brief Value to be used as the "rising" GPIO level change direction. + */ const uint32_t GpioInterruptRising; + + /*! + \brief Value to be used as the "falling" GPIO level change direction. + */ const uint32_t GpioInterruptFalling; - Hal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); + /*! + \brief Default constructor. + \param input Value to be used as the "input" GPIO direction. + \param output Value to be used as the "output" GPIO direction. + \param low Value to be used as the "low" GPIO level. + \param high Value to be used as the "high" GPIO level. + \param rising Value to be used as the "rising" GPIO level change direction. + \param falling Value to be used as the "falling" GPIO level change direction. + */ + RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); - virtual void init(); - virtual void term(); + // pure virtual methods - these must be implemented by the hardware abstraction for RadioLib to function + /*! + \brief GPIO pin mode (input/output/...) configuration method. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \param mode Mode to be set (platform-specific). + */ virtual void pinMode(uint32_t pin, uint32_t mode) = 0; + + /*! + \brief Digital write method. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \param value Value to set (platform-specific). + */ virtual void digitalWrite(uint32_t pin, uint32_t value) = 0; + + /*! + \brief Digital read method. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \returns Value read on the pin (platform-specific). + */ virtual uint32_t digitalRead(uint32_t pin) = 0; + + /*! + \brief Method to attach function to an external interrupt. + Must be implemented by the platform-specific hardware abstraction! + \param interruptNum Interrupt number to attach to (platform-specific). + \param interruptCb Interrupt service routine to execute. + \param mode Rising/falling mode (platform-specific). + */ virtual void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) = 0; + + /*! + \brief Method to detach function from an external interrupt. + Must be implemented by the platform-specific hardware abstraction! + \param interruptNum Interrupt number to detach from (platform-specific). + */ virtual void detachInterrupt(uint32_t interruptNum) = 0; + + /*! + \brief Blocking wait function. + Must be implemented by the platform-specific hardware abstraction! + \param ms Number of milliseconds to wait. + */ virtual void delay(unsigned long ms) = 0; + + /*! + \brief Blocking microsecond wait function. + Must be implemented by the platform-specific hardware abstraction! + \param us Number of microseconds to wait. + */ virtual void delayMicroseconds(unsigned long us) = 0; + + /*! + \brief Get number of milliseconds since start. + Must be implemented by the platform-specific hardware abstraction! + \returns Number of milliseconds since start. + */ virtual unsigned long millis() = 0; + + /*! + \brief Get number of microseconds since start. + Must be implemented by the platform-specific hardware abstraction! + \returns Number of microseconds since start. + */ virtual unsigned long micros() = 0; + + /*! + \brief Measure the length of incoming digital pulse in microseconds. + Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to measure on (platform-specific). + \param state Pin level to monitor (platform-specific). + \param timeout Timeout in microseconds. + \returns Pulse length in microseconds, or 0 if the pulse did not start before timeout. + */ virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0; + + /*! + \brief SPI initialization method. + */ virtual void spiBegin() = 0; + + /*! + \brief Method to start SPI transaction. + */ virtual void spiBeginTransaction() = 0; + + /*! + \brief Method to transfer one byte over SPI. + \param b Byte to send. + \returns Received byte. + */ virtual uint8_t spiTransfer(uint8_t b) = 0; + + /*! + \brief Method to end SPI transaction. + */ virtual void spiEndTransaction() = 0; + + /*! + \brief SPI termination method. + */ virtual void spiEnd() = 0; + // virtual methods - these may or may not exists on a given platform + // they exist in this implementation, but do nothing + + /*! + \brief Module initialization method. + This will be called by all radio modules at the beginning of startup. + Can be used to e.g., initalize SPI interface. + */ + virtual void init(); + + /*! + \brief Module termination method. + This will be called by all radio modules when the desctructor is called. + Can be used to e.g., stop SPI interface. + */ + virtual void term(); + + /*! + \brief Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin. + \param pin Pin to be used as the output. + \param frequency Frequency of the square wave. + \param duration Duration of the tone in ms. When set to 0, the tone will be infinite. + */ virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0); + + /*! + \brief Method to stop producing a tone. + \param pin Pin which is currently producing the tone. + */ virtual void noTone(uint32_t pin); + + /*! + \brief Yield method, called from long loops in multi-threaded environment (to prevent blocking other threads). + */ virtual void yield(); + + /*! + \brief Function to convert from pin number to interrupt number. + \param pin Pin to convert from. + \returns The interrupt number of a given pin. + */ virtual uint32_t pinToInterrupt(uint32_t pin); }; diff --git a/src/Module.cpp b/src/Module.cpp index 5ff133cf2d..21f37a97f1 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,13 +1,14 @@ -#define __STDC_FORMAT_MACROS +#include "Module.h" + +// the following is probably only needed on non-Arduino builds #include #include #include -#include "Module.h" #if defined(RADIOLIB_BUILD_ARDUINO) #include "ArduinoHal.h" Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { - this->hal = new ArduinoHal; + this->hal = new ArduinoHal(); } Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { @@ -15,7 +16,7 @@ Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& } #endif -Module::Module(Hal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { this->hal = hal; } diff --git a/src/Module.h b/src/Module.h index effc7140f0..dccc038dcd 100644 --- a/src/Module.h +++ b/src/Module.h @@ -114,7 +114,7 @@ class Module { \param gpio Pin to be used as additional interrupt/GPIO. */ - Module(Hal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); + Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); /*! \brief Copy constructor. @@ -132,7 +132,7 @@ class Module { // public member variables - Hal* hal = NULL; + RadioLibHal* hal = NULL; /*! \brief Basic SPI read command. Defaults to 0x00. diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index dc6d61d499..48332fec66 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -6,7 +6,7 @@ ExternalRadio::ExternalRadio() : PhysicalLayer(1, 0) { } #endif -ExternalRadio::ExternalRadio(Hal *hal) : PhysicalLayer(1, 0) { +ExternalRadio::ExternalRadio(RadioLibHal *hal) : PhysicalLayer(1, 0) { mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); } diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 0f72133011..bbbbd44749 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -14,7 +14,7 @@ class ExternalRadio: public PhysicalLayer { #if defined(RADIOLIB_BUILD_ARDUINO) ExternalRadio(); #endif - ExternalRadio(Hal *hal); + ExternalRadio(RadioLibHal *hal); Module* getMod(); private: From 876081958bc244c9ebe1274f4f3f52d475e0a072 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:22:46 +0200 Subject: [PATCH 0491/1848] [HAL] Doxygen comments fix --- src/ArduinoHal.h | 2 ++ src/Hal.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index a74f73a9a8..61ad272dfc 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -30,7 +30,9 @@ class ArduinoHal : public RadioLibHal { /*! \brief Arduino Hal constructor. Will not attempt SPI interface initialization. + \param spi SPI interface to be used, can also use software SPI implementations. + \param spiSettings SPI interface settings. */ ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); diff --git a/src/Hal.h b/src/Hal.h index 64bfea2f0c..bd2369d4be 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -6,6 +6,7 @@ /*! \class Hal + \brief Hardware abstraction library base interface. */ class RadioLibHal { @@ -46,11 +47,17 @@ class RadioLibHal { /*! \brief Default constructor. + \param input Value to be used as the "input" GPIO direction. + \param output Value to be used as the "output" GPIO direction. + \param low Value to be used as the "low" GPIO level. + \param high Value to be used as the "high" GPIO level. + \param rising Value to be used as the "rising" GPIO level change direction. + \param falling Value to be used as the "falling" GPIO level change direction. */ RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); @@ -60,7 +67,9 @@ class RadioLibHal { /*! \brief GPIO pin mode (input/output/...) configuration method. Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \param mode Mode to be set (platform-specific). */ virtual void pinMode(uint32_t pin, uint32_t mode) = 0; @@ -68,7 +77,9 @@ class RadioLibHal { /*! \brief Digital write method. Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \param value Value to set (platform-specific). */ virtual void digitalWrite(uint32_t pin, uint32_t value) = 0; @@ -76,7 +87,9 @@ class RadioLibHal { /*! \brief Digital read method. Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to be changed (platform-specific). + \returns Value read on the pin (platform-specific). */ virtual uint32_t digitalRead(uint32_t pin) = 0; @@ -84,8 +97,11 @@ class RadioLibHal { /*! \brief Method to attach function to an external interrupt. Must be implemented by the platform-specific hardware abstraction! + \param interruptNum Interrupt number to attach to (platform-specific). + \param interruptCb Interrupt service routine to execute. + \param mode Rising/falling mode (platform-specific). */ virtual void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) = 0; @@ -93,6 +109,7 @@ class RadioLibHal { /*! \brief Method to detach function from an external interrupt. Must be implemented by the platform-specific hardware abstraction! + \param interruptNum Interrupt number to detach from (platform-specific). */ virtual void detachInterrupt(uint32_t interruptNum) = 0; @@ -100,6 +117,7 @@ class RadioLibHal { /*! \brief Blocking wait function. Must be implemented by the platform-specific hardware abstraction! + \param ms Number of milliseconds to wait. */ virtual void delay(unsigned long ms) = 0; @@ -107,6 +125,7 @@ class RadioLibHal { /*! \brief Blocking microsecond wait function. Must be implemented by the platform-specific hardware abstraction! + \param us Number of microseconds to wait. */ virtual void delayMicroseconds(unsigned long us) = 0; @@ -114,6 +133,7 @@ class RadioLibHal { /*! \brief Get number of milliseconds since start. Must be implemented by the platform-specific hardware abstraction! + \returns Number of milliseconds since start. */ virtual unsigned long millis() = 0; @@ -121,6 +141,7 @@ class RadioLibHal { /*! \brief Get number of microseconds since start. Must be implemented by the platform-specific hardware abstraction! + \returns Number of microseconds since start. */ virtual unsigned long micros() = 0; @@ -128,9 +149,13 @@ class RadioLibHal { /*! \brief Measure the length of incoming digital pulse in microseconds. Must be implemented by the platform-specific hardware abstraction! + \param pin Pin to measure on (platform-specific). + \param state Pin level to monitor (platform-specific). + \param timeout Timeout in microseconds. + \returns Pulse length in microseconds, or 0 if the pulse did not start before timeout. */ virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0; @@ -147,7 +172,9 @@ class RadioLibHal { /*! \brief Method to transfer one byte over SPI. + \param b Byte to send. + \returns Received byte. */ virtual uint8_t spiTransfer(uint8_t b) = 0; @@ -181,14 +208,18 @@ class RadioLibHal { /*! \brief Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin. + \param pin Pin to be used as the output. + \param frequency Frequency of the square wave. + \param duration Duration of the tone in ms. When set to 0, the tone will be infinite. */ virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0); /*! \brief Method to stop producing a tone. + \param pin Pin which is currently producing the tone. */ virtual void noTone(uint32_t pin); @@ -200,7 +231,9 @@ class RadioLibHal { /*! \brief Function to convert from pin number to interrupt number. + \param pin Pin to convert from. + \returns The interrupt number of a given pin. */ virtual uint32_t pinToInterrupt(uint32_t pin); From 7ff785eb0004af375f157f1631557d902c153d4a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:33:21 +0200 Subject: [PATCH 0492/1848] [HAL] Trying Doxygen format --- src/Hal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Hal.h b/src/Hal.h index bd2369d4be..95463cb7af 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -231,9 +231,7 @@ class RadioLibHal { /*! \brief Function to convert from pin number to interrupt number. - \param pin Pin to convert from. - \returns The interrupt number of a given pin. */ virtual uint32_t pinToInterrupt(uint32_t pin); From 9749083573db2e1d0a5ee5cf8ad34737ee47c376 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:50:12 +0200 Subject: [PATCH 0493/1848] [MOD] Use compact Doxygen and stop using reserved format --- src/Module.cpp | 50 +++++++++---------- src/Module.h | 131 ++++++++----------------------------------------- 2 files changed, 45 insertions(+), 136 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 21f37a97f1..db3b56f20d 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -7,16 +7,16 @@ #if defined(RADIOLIB_BUILD_ARDUINO) #include "ArduinoHal.h" -Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { this->hal = new ArduinoHal(); } -Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { this->hal = new ArduinoHal(spi, spiSettings); } #endif -Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : _cs(cs), _irq(irq), _rst(rst), _gpio(gpio) { +Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { this->hal = hal; } @@ -27,18 +27,17 @@ Module::Module(const Module& mod) { Module& Module::operator=(const Module& mod) { this->SPIreadCommand = mod.SPIreadCommand; this->SPIwriteCommand = mod.SPIwriteCommand; - this->_cs = mod._cs; - this->_irq = mod._irq; - this->_rst = mod._rst; - this->_gpio = mod._gpio; - + this->csPin = mod.csPin; + this->irqPin = mod.irqPin; + this->rstPin = mod.rstPin; + this->gpioPin = mod.gpioPin; return(*this); } void Module::init() { this->hal->init(); - this->hal->pinMode(_cs, this->hal->GpioModeOutput); - this->hal->digitalWrite(_cs, this->hal->GpioLevelHigh); + this->hal->pinMode(csPin, this->hal->GpioModeOutput); + this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh); } void Module::term() { @@ -138,7 +137,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->hal->spiBeginTransaction(); // pull CS low - this->hal->digitalWrite(this->_cs, this->hal->GpioLevelLow); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); // send SPI register address with access command if(this->SPIaddrWidth <= 8) { @@ -176,7 +175,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d RADIOLIB_VERBOSE_PRINTLN(); // release CS - this->hal->digitalWrite(this->_cs, this->hal->GpioLevelHigh); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); // end SPI transaction this->hal->spiEndTransaction(); @@ -242,16 +241,16 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // ensure GPIO is low uint32_t start = this->hal->millis(); - while(this->hal->digitalRead(this->_gpio)) { + while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - this->hal->digitalWrite(this->_cs, this->hal->GpioLevelLow); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } // pull NSS low - this->hal->digitalWrite(this->_cs, this->hal->GpioLevelLow); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); // start transfer this->hal->spiBeginTransaction(); @@ -303,13 +302,13 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // stop transfer this->hal->spiEndTransaction(); - this->hal->digitalWrite(this->_cs, this->hal->GpioLevelHigh); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); // wait for GPIO to go high and then low if(waitForGpio) { this->hal->delayMicroseconds(1); uint32_t start = this->hal->millis(); - while(this->hal->digitalRead(this->_gpio)) { + while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; @@ -352,7 +351,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint void Module::waitForMicroseconds(uint32_t start, uint32_t len) { #if defined(RADIOLIB_INTERRUPT_TIMING) (void)start; - if((this->TimerSetupCb != nullptr) && (len != this->_prevTimingLen)) { + if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) { _prevTimingLen = len; this->TimerSetupCb(len); } @@ -471,25 +470,26 @@ void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { const uint32_t pins[] = { rxEn, txEn, RADIOLIB_NC, }; + // This must be static, since setRfSwitchTable stores a reference. static const RfSwitchMode_t table[] = { - {MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow}}, - {MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow}}, - {MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh}}, + { MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow} }, + { MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow} }, + { MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh} }, END_OF_MODE_TABLE, }; setRfSwitchTable(pins, table); } void Module::setRfSwitchTable(const uint32_t (&pins)[3], const RfSwitchMode_t table[]) { - memcpy(_rfSwitchPins, pins, sizeof(_rfSwitchPins)); - _rfSwitchTable = table; + memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins)); + this->rfSwitchTable = table; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) this->hal->pinMode(pins[i], this->hal->GpioModeOutput); } const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const { - const RfSwitchMode_t *row = _rfSwitchTable; + const RfSwitchMode_t *row = this->rfSwitchTable; while (row && row->mode != MODE_END_OF_TABLE) { if (row->mode == mode) return row; @@ -508,7 +508,7 @@ void Module::setRfSwitchState(uint8_t mode) { // set pins const uint32_t *value = &row->values[0]; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { - uint32_t pin = _rfSwitchPins[i]; + uint32_t pin = this->rfSwitchPins[i]; if (pin != RADIOLIB_NC) this->hal->digitalWrite(pin, *value); ++value; diff --git a/src/Module.h b/src/Module.h index dccc038dcd..03163d158c 100644 --- a/src/Module.h +++ b/src/Module.h @@ -22,7 +22,6 @@ /*! \class Module - \brief Implements all common low-level methods to control the wireless module. Every module class contains one private instance of this class. */ @@ -72,30 +71,20 @@ class Module { #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it. - \param cs Arduino pin to be used as chip select. - \param irq Arduino pin to be used as interrupt/GPIO. - \param rst Arduino pin to be used as hardware reset for the module. - \param gpio Arduino pin to be used as additional interrupt/GPIO. */ Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); /*! \brief Arduino Module constructor. Will not attempt SPI interface initialization. - \param cs Arduino pin to be used as chip select. - \param irq Arduino pin to be used as interrupt/GPIO. - \param rst Arduino pin to be used as hardware reset for the module. - \param gpio Arduino pin to be used as additional interrupt/GPIO. - \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. */ Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); @@ -103,35 +92,30 @@ class Module { /*! \brief Module constructor. - \param hal A Hardware abstraction layer instance. An ArduinoHal instance for example. - \param cs Pin to be used as chip select. - \param irq Pin to be used as interrupt/GPIO. - \param rst Pin to be used as hardware reset for the module. - \param gpio Pin to be used as additional interrupt/GPIO. */ Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC); /*! \brief Copy constructor. - \param mod Module instance to copy. */ Module(const Module& mod); /*! \brief Overload for assignment operator. - \param frame rvalue Module. */ Module& operator=(const Module& mod); // public member variables - + /*! + \brief Hardware abstraction layer to be used. + */ RadioLibHal* hal = NULL; /*! @@ -216,189 +200,127 @@ class Module { /*! \brief SPI read method that automatically masks unused bits. This method is the preferred SPI read mechanism. - \param reg Address of SPI register to read. - \param msb Most significant bit of the register variable. Bits above this one will be masked out. - \param lsb Least significant bit of the register variable. Bits below this one will be masked out. - \returns Masked register value or status code. */ int16_t SPIgetRegValue(uint16_t reg, uint8_t msb = 7, uint8_t lsb = 0); /*! \brief Overwrite-safe SPI write method with verification. This method is the preferred SPI write mechanism. - \param reg Address of SPI register to write. - \param value Single byte value that will be written to the SPI register. - \param msb Most significant bit of the register variable. Bits above this one will not be affected by the write operation. - \param lsb Least significant bit of the register variable. Bits below this one will not be affected by the write operation. - \param checkInterval Number of milliseconds between register writing and verification reading. Some registers need up to 10ms to process the change. - \param checkMask Mask of bits to check, only bits set to 1 will be verified. - \returns \ref status_codes */ int16_t SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); /*! \brief SPI burst read method. - \param reg Address of SPI register to read. - \param numBytes Number of bytes that will be read. - \param inBytes Pointer to array that will hold the read data. */ void SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes); /*! \brief SPI basic read method. Use of this method is reserved for special cases, SPIgetRegValue should be used instead. - \param reg Address of SPI register to read. - \returns Value that was read from register. */ uint8_t SPIreadRegister(uint16_t reg); /*! \brief SPI burst write method. - \param reg Address of SPI register to write. - \param data Pointer to array that holds the data that will be written. - \param numBytes Number of bytes that will be written. */ void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes); /*! \brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead. - \param reg Address of SPI register to write. - \param data Value that will be written to the register. */ void SPIwriteRegister(uint16_t reg, uint8_t data); /*! \brief SPI single transfer method. - \param cmd SPI access command (read/write/burst/...). - \param reg Address of SPI register to transfer to/from. - \param dataOut Data that will be transfered from master to slave. - \param dataIn Data that was transfered from slave to master. - \param numBytes Number of bytes to transfer. */ void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); /*! \brief Method to check the result of last SPI stream transfer. - \returns \ref status_codes */ int16_t SPIcheckStream(); /*! \brief Method to perform a read transaction with SPI stream. - \param cmd SPI operation command. - \param data Data that will be transferred from slave to master. - \param numBytes Number of bytes to transfer. - \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). - \param verify Whether to verify the result of the transaction after it is finished. - \returns \ref status_codes */ int16_t SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a read transaction with SPI stream. - \param cmd SPI operation command. - \param cmdLen SPI command length in bytes. - \param data Data that will be transferred from slave to master. - \param numBytes Number of bytes to transfer. - \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). - \param verify Whether to verify the result of the transaction after it is finished. - \returns \ref status_codes */ int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. - \param cmd SPI operation command. - \param data Data that will be transferred from master to slave. - \param numBytes Number of bytes to transfer. - \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). - \param verify Whether to verify the result of the transaction after it is finished. - \returns \ref status_codes */ int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. - \param cmd SPI operation command. - \param cmdLen SPI command length in bytes. - \param data Data that will be transferred from master to slave. - \param numBytes Number of bytes to transfer. - \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). - \param verify Whether to verify the result of the transaction after it is finished. - \returns \ref status_codes */ int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). - \param cmd SPI operation command. - \param cmdLen SPI command length in bytes. - \param write Set to true for write commands, false for read commands. - \param dataOut Data that will be transfered from master to slave. - \param dataIn Data that was transfered from slave to master. - \param numBytes Number of bytes to transfer. - \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). - \param timeout GPIO wait period timeout in milliseconds. - \returns \ref status_codes */ int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout); @@ -407,31 +329,27 @@ class Module { /*! \brief Access method to get the pin number of SPI chip select. - \returns Pin number of SPI chip select configured in the constructor. */ - uint32_t getCs() const { return(_cs); } + uint32_t getCs() const { return(csPin); } /*! \brief Access method to get the pin number of interrupt/GPIO. - \returns Pin number of interrupt/GPIO configured in the constructor. */ - uint32_t getIrq() const { return(_irq); } + uint32_t getIrq() const { return(irqPin); } /*! \brief Access method to get the pin number of hardware reset pin. - \returns Pin number of hardware reset pin configured in the constructor. */ - uint32_t getRst() const { return(_rst); } + uint32_t getRst() const { return(rstPin); } /*! \brief Access method to get the pin number of second interrupt/GPIO. - \returns Pin number of second interrupt/GPIO configured in the constructor. */ - uint32_t getGpio() const { return(_gpio); } + uint32_t getGpio() const { return(gpioPin); } /*! \brief Some modules contain external RF switch controlled by pins. @@ -516,14 +434,12 @@ class Module { void setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]); /*! - * \brief Find a mode in the RfSwitchTable. - * - * \param The mode to find. - * - * \returns A pointer to the RfSwitchMode_t struct in the table that - * matches the passed mode. Returns nullptr if no rfswitch pins are - * configured, or the passed mode is not listed in the table. - */ + \brief Find a mode in the RfSwitchTable. + \param The mode to find. + \returns A pointer to the RfSwitchMode_t struct in the table that + matches the passed mode. Returns nullptr if no rfswitch pins are + configured, or the passed mode is not listed in the table. + */ const RfSwitchMode_t *findRfSwitchMode(uint8_t mode) const; /*! @@ -537,7 +453,6 @@ class Module { Note that in interrupt timing mode, it is up to the user to set up the timing interrupt! \param start Waiting start timestamp, in microseconds. - \param len Waiting duration, in microseconds; */ void waitForMicroseconds(uint32_t start, uint32_t len); @@ -554,22 +469,16 @@ class Module { /*! \brief Function to dump data as hex into the debug port. - \param data Data to dump. - \param len Number of bytes to dump. - \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). - \param be Print multi-byte data as big endian. Defaults to false. */ static void hexdump(uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); /*! \brief Function to dump device registers as hex into the debug port. - \param start First address to dump. - \param len Number of bytes to dump. */ void regdump(uint16_t start, size_t len); @@ -581,17 +490,17 @@ class Module { #if !defined(RADIOLIB_GODMODE) private: #endif - uint32_t _cs = RADIOLIB_NC; - uint32_t _irq = RADIOLIB_NC; - uint32_t _rst = RADIOLIB_NC; - uint32_t _gpio = RADIOLIB_NC; + uint32_t csPin = RADIOLIB_NC; + uint32_t irqPin = RADIOLIB_NC; + uint32_t rstPin = RADIOLIB_NC; + uint32_t gpioPin = RADIOLIB_NC; // RF switch pins and table - uint32_t _rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; - const RfSwitchMode_t *_rfSwitchTable = nullptr; + uint32_t rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + const RfSwitchMode_t *rfSwitchTable = nullptr; #if defined(RADIOLIB_INTERRUPT_TIMING) - uint32_t _prevTimingLen = 0; + uint32_t prevTimingLen = 0; #endif }; From 7a99aa0ef48dd632b92fd32a375cbb593e017087 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 18:53:30 +0200 Subject: [PATCH 0494/1848] [HAL] Use compact Doxygen and stop using reserved format --- src/ArduinoHal.cpp | 26 +++++++++++++------------- src/ArduinoHal.h | 11 ++++------- src/Hal.h | 31 ------------------------------- 3 files changed, 17 insertions(+), 51 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 8b176feba5..fe471c155f 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -2,18 +2,18 @@ #if defined(RADIOLIB_BUILD_ARDUINO) -ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&RADIOLIB_DEFAULT_SPI), _initInterface(true) {} +ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {} -ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), _spi(&spi), _spiSettings(spiSettings) {} +ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&spi), spiSettings(spiSettings) {} void ArduinoHal::init() { - if(_initInterface) { + if(initInterface) { spiBegin(); } } void ArduinoHal::term() { - if(_initInterface) { + if(initInterface) { spiEnd(); } } @@ -77,23 +77,23 @@ long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long time } void inline ArduinoHal::spiBegin() { - _spi->begin(); + spi->begin(); } void inline ArduinoHal::spiBeginTransaction() { - _spi->beginTransaction(_spiSettings); + spi->beginTransaction(spiSettings); } uint8_t inline ArduinoHal::spiTransfer(uint8_t b) { - return(_spi->transfer(b)); + return(spi->transfer(b)); } void inline ArduinoHal::spiEndTransaction() { - _spi->endTransaction(); + spi->endTransaction(); } void inline ArduinoHal::spiEnd() { - _spi->end(); + spi->end(); } void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { @@ -105,13 +105,13 @@ void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long #elif defined(ESP32) // ESP32 tone() emulation (void)duration; - if(_prev == -1) { + if(prev == -1) { ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); } - if(_prev != frequency) { + if(prev != frequency) { ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); } - _prev = frequency; + prev = frequency; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) // better tone for mbed OS boards (void)duration; @@ -141,7 +141,7 @@ void inline ArduinoHal::noTone(uint32_t pin) { // ESP32 tone() emulation ledcDetachPin(pin); ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); - _prev = -1; + prev = -1; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) if(pin == RADIOLIB_NC) { return; diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 61ad272dfc..69fe50f534 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -17,7 +17,6 @@ /*! \class ArduinoHal - \brief Arduino default hardware abstraction library implementation. This class can be extended to support other Arduino platform or change behaviour of the default implementation. */ @@ -30,9 +29,7 @@ class ArduinoHal : public RadioLibHal { /*! \brief Arduino Hal constructor. Will not attempt SPI interface initialization. - \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. */ ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); @@ -65,16 +62,16 @@ class ArduinoHal : public RadioLibHal { #if !defined(RADIOLIB_GODMODE) private: #endif - SPIClass* _spi = NULL; - SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; - bool _initInterface = false; + SPIClass* spi = NULL; + SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; + bool initInterface = false; #if defined(RADIOLIB_MBED_TONE_OVERRIDE) mbed::PwmOut *pwmPin = NULL; #endif #if defined(ESP32) - int32_t _prev = -1; + int32_t prev = -1; #endif }; diff --git a/src/Hal.h b/src/Hal.h index 95463cb7af..64bfea2f0c 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -6,7 +6,6 @@ /*! \class Hal - \brief Hardware abstraction library base interface. */ class RadioLibHal { @@ -47,17 +46,11 @@ class RadioLibHal { /*! \brief Default constructor. - \param input Value to be used as the "input" GPIO direction. - \param output Value to be used as the "output" GPIO direction. - \param low Value to be used as the "low" GPIO level. - \param high Value to be used as the "high" GPIO level. - \param rising Value to be used as the "rising" GPIO level change direction. - \param falling Value to be used as the "falling" GPIO level change direction. */ RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); @@ -67,9 +60,7 @@ class RadioLibHal { /*! \brief GPIO pin mode (input/output/...) configuration method. Must be implemented by the platform-specific hardware abstraction! - \param pin Pin to be changed (platform-specific). - \param mode Mode to be set (platform-specific). */ virtual void pinMode(uint32_t pin, uint32_t mode) = 0; @@ -77,9 +68,7 @@ class RadioLibHal { /*! \brief Digital write method. Must be implemented by the platform-specific hardware abstraction! - \param pin Pin to be changed (platform-specific). - \param value Value to set (platform-specific). */ virtual void digitalWrite(uint32_t pin, uint32_t value) = 0; @@ -87,9 +76,7 @@ class RadioLibHal { /*! \brief Digital read method. Must be implemented by the platform-specific hardware abstraction! - \param pin Pin to be changed (platform-specific). - \returns Value read on the pin (platform-specific). */ virtual uint32_t digitalRead(uint32_t pin) = 0; @@ -97,11 +84,8 @@ class RadioLibHal { /*! \brief Method to attach function to an external interrupt. Must be implemented by the platform-specific hardware abstraction! - \param interruptNum Interrupt number to attach to (platform-specific). - \param interruptCb Interrupt service routine to execute. - \param mode Rising/falling mode (platform-specific). */ virtual void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) = 0; @@ -109,7 +93,6 @@ class RadioLibHal { /*! \brief Method to detach function from an external interrupt. Must be implemented by the platform-specific hardware abstraction! - \param interruptNum Interrupt number to detach from (platform-specific). */ virtual void detachInterrupt(uint32_t interruptNum) = 0; @@ -117,7 +100,6 @@ class RadioLibHal { /*! \brief Blocking wait function. Must be implemented by the platform-specific hardware abstraction! - \param ms Number of milliseconds to wait. */ virtual void delay(unsigned long ms) = 0; @@ -125,7 +107,6 @@ class RadioLibHal { /*! \brief Blocking microsecond wait function. Must be implemented by the platform-specific hardware abstraction! - \param us Number of microseconds to wait. */ virtual void delayMicroseconds(unsigned long us) = 0; @@ -133,7 +114,6 @@ class RadioLibHal { /*! \brief Get number of milliseconds since start. Must be implemented by the platform-specific hardware abstraction! - \returns Number of milliseconds since start. */ virtual unsigned long millis() = 0; @@ -141,7 +121,6 @@ class RadioLibHal { /*! \brief Get number of microseconds since start. Must be implemented by the platform-specific hardware abstraction! - \returns Number of microseconds since start. */ virtual unsigned long micros() = 0; @@ -149,13 +128,9 @@ class RadioLibHal { /*! \brief Measure the length of incoming digital pulse in microseconds. Must be implemented by the platform-specific hardware abstraction! - \param pin Pin to measure on (platform-specific). - \param state Pin level to monitor (platform-specific). - \param timeout Timeout in microseconds. - \returns Pulse length in microseconds, or 0 if the pulse did not start before timeout. */ virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0; @@ -172,9 +147,7 @@ class RadioLibHal { /*! \brief Method to transfer one byte over SPI. - \param b Byte to send. - \returns Received byte. */ virtual uint8_t spiTransfer(uint8_t b) = 0; @@ -208,18 +181,14 @@ class RadioLibHal { /*! \brief Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin. - \param pin Pin to be used as the output. - \param frequency Frequency of the square wave. - \param duration Duration of the tone in ms. When set to 0, the tone will be infinite. */ virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0); /*! \brief Method to stop producing a tone. - \param pin Pin which is currently producing the tone. */ virtual void noTone(uint32_t pin); From 47e759f322741555556de02ba232ca925118c810 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:34:27 +0200 Subject: [PATCH 0495/1848] [SSTV] Use compact Doxygen and stop using reserved format --- src/protocols/SSTV/SSTV.cpp | 60 ++++++++++++++++++------------------- src/protocols/SSTV/SSTV.h | 36 ++++++++-------------- 2 files changed, 43 insertions(+), 53 deletions(-) diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 1e7b0c5a33..107674fda8 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -155,22 +155,22 @@ const SSTVMode_t PasokonP7 { }; SSTVClient::SSTVClient(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - _audio = nullptr; + audioClient = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) SSTVClient::SSTVClient(AFSKClient* audio) { - _phy = audio->_phy; - _audio = audio; + phyLayer = audio->phyLayer; + audioClient = audio; } #endif #if !defined(RADIOLIB_EXCLUDE_AFSK) int16_t SSTVClient::begin(const SSTVMode_t& mode) { - if(_audio == nullptr) { + if(audioClient == nullptr) { // this initialization method can only be used in AFSK mode return(RADIOLIB_ERR_WRONG_MODEM); } @@ -181,38 +181,38 @@ int16_t SSTVClient::begin(const SSTVMode_t& mode) { int16_t SSTVClient::begin(float base, const SSTVMode_t& mode) { // save mode - _mode = mode; + txMode = mode; // calculate 24-bit frequency - _base = (base * 1000000.0) / _phy->getFreqStep(); + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } int16_t SSTVClient::setCorrection(float correction) { // check if mode is initialized - if(_mode.visCode == 0) { + if(txMode.visCode == 0) { return(RADIOLIB_ERR_WRONG_MODEM); } // apply correction factor to all timings - _mode.scanPixelLen *= correction; - for(uint8_t i = 0; i < _mode.numTones; i++) { - _mode.tones[i].len *= correction; + txMode.scanPixelLen *= correction; + for(uint8_t i = 0; i < txMode.numTones; i++) { + txMode.tones[i].len *= correction; } return(RADIOLIB_ERR_NONE); } void SSTVClient::idle() { - _phy->transmitDirect(); + phyLayer->transmitDirect(); this->tone(RADIOLIB_SSTV_TONE_LEADER); } void SSTVClient::sendHeader() { // save first header flag for Scottie modes - _firstLine = true; - _phy->transmitDirect(); + firstLine = true; + phyLayer->transmitDirect(); // send the first part of header (leader-break-leader) this->tone(RADIOLIB_SSTV_TONE_LEADER, RADIOLIB_SSTV_HEADER_LEADER_LENGTH); @@ -225,7 +225,7 @@ void SSTVClient::sendHeader() { // VIS code uint8_t parityCount = 0; for(uint8_t mask = 0x01; mask < 0x80; mask <<= 1) { - if(_mode.visCode & mask) { + if(txMode.visCode & mask) { this->tone(RADIOLIB_SSTV_TONE_VIS_1, RADIOLIB_SSTV_HEADER_BIT_LENGTH); parityCount++; } else { @@ -248,23 +248,23 @@ void SSTVClient::sendHeader() { void SSTVClient::sendLine(uint32_t* imgLine) { // check first line flag in Scottie modes - if(_firstLine && ((_mode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (_mode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (_mode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { - _firstLine = false; + if(firstLine && ((txMode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { + firstLine = false; // send start sync tone this->tone(RADIOLIB_SSTV_TONE_BREAK, 9000); } // send all tones in sequence - for(uint8_t i = 0; i < _mode.numTones; i++) { - if((_mode.tones[i].type == tone_t::GENERIC) && (_mode.tones[i].len > 0)) { + for(uint8_t i = 0; i < txMode.numTones; i++) { + if((txMode.tones[i].type == tone_t::GENERIC) && (txMode.tones[i].len > 0)) { // sync/porch tones - this->tone(_mode.tones[i].freq, _mode.tones[i].len); + this->tone(txMode.tones[i].freq, txMode.tones[i].len); } else { // scan lines - for(uint16_t j = 0; j < _mode.width; j++) { + for(uint16_t j = 0; j < txMode.width; j++) { uint32_t color = imgLine[j]; - switch(_mode.tones[i].type) { + switch(txMode.tones[i].type) { case(tone_t::SCAN_RED): color &= 0x00FF0000; color >>= 16; @@ -279,27 +279,27 @@ void SSTVClient::sendLine(uint32_t* imgLine) { case(tone_t::GENERIC): break; } - this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen); + this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), txMode.scanPixelLen); } } } } uint16_t SSTVClient::getPictureHeight() const { - return(_mode.height); + return(txMode.height); } void SSTVClient::tone(float freq, uint32_t len) { - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - _audio->tone(freq, false); + if(audioClient != nullptr) { + audioClient->tone(freq, false); } else { - _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); + phyLayer->transmitDirect(baseFreq + (freq / phyLayer->getFreqStep())); } #else - _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); + phyLayer->transmitDirect(baseFreq + (freq / phyLayer->getFreqStep())); #endif mod->waitForMicroseconds(start, len); } diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index 5a094cd6dd..df73d8f2de 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -37,7 +37,6 @@ /*! \struct tone_t - \brief Structure to save data about tone. */ struct tone_t { @@ -65,7 +64,6 @@ struct tone_t { /*! \struct SSTVMode_t - \brief Structure to save data about supported SSTV modes. */ struct SSTVMode_t { @@ -114,14 +112,12 @@ extern const SSTVMode_t PasokonP7; /*! \class SSTVClient - \brief Client for SSTV transmissions. */ class SSTVClient { public: /*! \brief Constructor for 2-FSK mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit SSTVClient(PhysicalLayer* phy); @@ -129,7 +125,6 @@ class SSTVClient { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. */ explicit SSTVClient(AFSKClient* audio); @@ -139,11 +134,9 @@ class SSTVClient { /*! \brief Initialization method for 2-FSK. - \param base Base "0 Hz tone" RF frequency to be used in MHz. - - \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. - + \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, + ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. \returns \ref status_codes */ int16_t begin(float base, const SSTVMode_t& mode); @@ -151,9 +144,8 @@ class SSTVClient { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Initialization method for AFSK. - - \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. - + \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, + ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. \returns \ref status_codes */ int16_t begin(const SSTVMode_t& mode); @@ -161,9 +153,8 @@ class SSTVClient { /*! \brief Set correction coefficient for tone length. - - \param correction Timing correction factor, used to adjust the length of timing pulses. Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). - + \param correction Timing correction factor, used to adjust the length of timing pulses. + Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). \returns \ref status_codes */ int16_t setCorrection(float correction); @@ -180,14 +171,13 @@ class SSTVClient { /*! \brief Sends single picture line in the currently configured SSTV mode. - - \param imgLine Image line to send, in 24-bit RGB. It is up to the user to ensure that imgLine has enough pixels to send it in the current SSTV mode. + \param imgLine Image line to send, in 24-bit RGB. It is up to the user to ensure that + imgLine has enough pixels to send it in the current SSTV mode. */ void sendLine(uint32_t* imgLine); /*! \brief Get picture height of the currently configured SSTV mode. - \returns Picture height of the currently configured SSTV mode in pixels. */ uint16_t getPictureHeight() const; @@ -195,14 +185,14 @@ class SSTVClient { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; + PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* _audio; + AFSKClient* audioClient; #endif - uint32_t _base = 0; - SSTVMode_t _mode = Scottie1; - bool _firstLine = true; + uint32_t baseFreq = 0; + SSTVMode_t txMode = Scottie1; + bool firstLine = true; void tone(float freq, uint32_t len = 0); }; From 5ab24e05dd1a442db37e5be6cb76517f7ad15909 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:34:38 +0200 Subject: [PATCH 0496/1848] [RTTY] Use compact Doxygen and stop using reserved format --- src/protocols/RTTY/RTTY.cpp | 138 ++++++++++++++++++------------------ src/protocols/RTTY/RTTY.h | 53 ++++++-------- 2 files changed, 89 insertions(+), 102 deletions(-) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 5f6158913c..21c3243ae7 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -4,39 +4,39 @@ #if !defined(RADIOLIB_EXCLUDE_RTTY) ITA2String::ITA2String(char c) { - _len = 1; + asciiLen = 1; #if !defined(RADIOLIB_STATIC_ONLY) - _str = new char[1]; + strAscii = new char[1]; #endif - _str[0] = c; - _ita2Len = 0; + strAscii[0] = c; + ita2Len = 0; } ITA2String::ITA2String(const char* str) { - _len = strlen(str); + asciiLen = strlen(str); #if !defined(RADIOLIB_STATIC_ONLY) - _str = new char[_len + 1]; + strAscii = new char[asciiLen + 1]; #endif - strcpy(_str, str); - _ita2Len = 0; + strcpy(strAscii, str); + ita2Len = 0; } ITA2String::~ITA2String() { #if !defined(RADIOLIB_STATIC_ONLY) - delete[] _str; + delete[] strAscii; #endif } size_t ITA2String::length() { - // length returned by this method is different than the length of ASCII-encoded _str + // length returned by this method is different than the length of ASCII-encoded strAscii // ITA2-encoded string length varies based on how many number and characters the string contains - if(_ita2Len == 0) { + if(ita2Len == 0) { // ITA2 length wasn't calculated yet, call byteArr() to calculate it byteArr(); } - return(_ita2Len); + return(ita2Len); } uint8_t* ITA2String::byteArr() { @@ -44,13 +44,13 @@ uint8_t* ITA2String::byteArr() { #if defined(RADIOLIB_STATIC_ONLY) uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; #else - uint8_t* temp = new uint8_t[_len*2 + 1]; + uint8_t* temp = new uint8_t[asciiLen*2 + 1]; #endif size_t arrayLen = 0; bool flagFigure = false; - for(size_t i = 0; i < _len; i++) { - uint16_t code = getBits(_str[i]); + for(size_t i = 0; i < asciiLen; i++) { + uint16_t code = getBits(strAscii[i]); uint8_t shift = (code >> 5) & 0b11111; uint8_t character = code & 0b11111; // check if the code is letter or figure @@ -65,8 +65,8 @@ uint8_t* ITA2String::byteArr() { temp[arrayLen++] = character & 0b11111; // check the following character (skip for message end) - if(i < (_len - 1)) { - uint16_t nextCode = getBits(_str[i+1]); + if(i < (asciiLen - 1)) { + uint16_t nextCode = getBits(strAscii[i+1]); uint8_t nextShift = (nextCode >> 5) & 0b11111; if(nextShift == RADIOLIB_ITA2_LTRS) { // next character is a letter, terminate figure shift @@ -84,7 +84,7 @@ uint8_t* ITA2String::byteArr() { } // save ITA2 string length - _ita2Len = arrayLen; + ita2Len = arrayLen; uint8_t* arr = new uint8_t[arrayLen]; memcpy(arr, temp, arrayLen); @@ -114,45 +114,45 @@ uint16_t ITA2String::getBits(char c) { } RTTYClient::RTTYClient(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - _audio = nullptr; + audioClient = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) RTTYClient::RTTYClient(AFSKClient* audio) { - _phy = audio->_phy; - _audio = audio; + phyLayer = audio->phyLayer; + audioClient = audio; } #endif -int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) { +int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc, uint8_t stopBits) { // save configuration - _encoding = encoding; - _stopBits = stopBits; - _baseHz = base; - _shiftHz = shift; + encoding = enc; + stopBitsNum = stopBits; + baseFreqHz = base; + shiftFreqHz = shift; switch(encoding) { case RADIOLIB_ASCII: - _dataBits = 7; + dataBitsNum = 7; break; case RADIOLIB_ASCII_EXTENDED: - _dataBits = 8; + dataBitsNum = 8; break; case RADIOLIB_ITA2: - _dataBits = 5; + dataBitsNum = 5; break; default: return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); } // calculate duration of 1 bit - _bitDuration = (uint32_t)1000000/rate; + bitDuration = (uint32_t)1000000/rate; // calculate module carrier frequency resolution - uint32_t step = round(_phy->getFreqStep()); + uint32_t step = round(phyLayer->getFreqStep()); // check minimum shift value if(shift < step / 2) { @@ -161,16 +161,16 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc // round shift to multiples of frequency step size if(shift % step < (step / 2)) { - _shift = shift / step; + shiftFreq = shift / step; } else { - _shift = (shift / step) + 1; + shiftFreq = (shift / step) + 1; } // calculate 24-bit frequency - _base = (base * 1000000.0) / _phy->getFreqStep(); + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } void RTTYClient::idle() { @@ -195,7 +195,7 @@ size_t RTTYClient::write(uint8_t* buff, size_t len) { size_t RTTYClient::write(uint8_t b) { space(); - uint16_t maxDataMask = 0x01 << (_dataBits - 1); + uint16_t maxDataMask = 0x01 << (dataBitsNum - 1); for(uint16_t mask = 0x01; mask <= maxDataMask; mask <<= 1) { if(b & mask) { mark(); @@ -204,7 +204,7 @@ size_t RTTYClient::write(uint8_t b) { } } - for(uint8_t i = 0; i < _stopBits; i++) { + for(uint8_t i = 0; i < stopBitsNum; i++) { mark(); } @@ -238,10 +238,10 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { } size_t n = 0; - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str); n = RTTYClient::print(ita2); - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, len); } #if !defined(RADIOLIB_STATIC_ONLY) @@ -252,10 +252,10 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { size_t RTTYClient::print(const String& str) { size_t n = 0; - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str.c_str()); n = RTTYClient::print(ita2); - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); } return(n); @@ -271,10 +271,10 @@ size_t RTTYClient::print(ITA2String& ita2) { size_t RTTYClient::print(const char str[]) { size_t n = 0; - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str); n = RTTYClient::print(ita2); - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, strlen(str)); } return(n); @@ -282,10 +282,10 @@ size_t RTTYClient::print(const char str[]) { size_t RTTYClient::print(char c) { size_t n = 0; - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(c); n = RTTYClient::print(ita2); - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write(c); } return(n); @@ -332,10 +332,10 @@ size_t RTTYClient::print(double n, int digits) { size_t RTTYClient::println(void) { size_t n = 0; - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String lf = ITA2String("\r\n"); n = RTTYClient::print(lf); - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n = RTTYClient::write("\r\n"); } return(n); @@ -410,17 +410,17 @@ size_t RTTYClient::println(double d, int digits) { } void RTTYClient::mark() { - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); - transmitDirect(_base + _shift, _baseHz + _shiftHz); - mod->waitForMicroseconds(start, _bitDuration); + transmitDirect(baseFreq + shiftFreq, baseFreqHz + shiftFreqHz); + mod->waitForMicroseconds(start, bitDuration); } void RTTYClient::space() { - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); - transmitDirect(_base, _baseHz); - mod->waitForMicroseconds(start, _bitDuration); + transmitDirect(baseFreq, baseFreqHz); + mod->waitForMicroseconds(start, bitDuration); } size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { @@ -441,12 +441,12 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { } while(n); size_t l = 0; - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(str); uint8_t* arr = ita2.byteArr(); l = RTTYClient::write(arr, ita2.length()); delete[] arr; - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { l = RTTYClient::write(str); } @@ -464,25 +464,25 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically if(code[0] != 0x00) { - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String(code); uint8_t* arr = ita2.byteArr(); n = RTTYClient::write(arr, ita2.length()); delete[] arr; return(n); - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { return(RTTYClient::write(code)); } } // Handle negative numbers if (number < 0.0) { - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String("-"); uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n += RTTYClient::print('-'); } number = -number; @@ -502,12 +502,12 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { // Print the decimal point, but only if there are digits beyond if(digits > 0) { - if(_encoding == RADIOLIB_ITA2) { + if(encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String("."); uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; - } else if((_encoding == RADIOLIB_ASCII) || (_encoding == RADIOLIB_ASCII_EXTENDED)) { + } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { n += RTTYClient::print('.'); } } @@ -525,23 +525,23 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->tone(freqHz)); + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); } #endif - return(_phy->transmitDirect(freq)); + return(phyLayer->transmitDirect(freq)); } int16_t RTTYClient::standby() { // ensure everything is stopped in interrupt timing mode - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); mod->waitForMicroseconds(0, 0); #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->noTone()); + if(audioClient != nullptr) { + return(audioClient->noTone()); } #endif - return(_phy->standby()); + return(phyLayer->standby()); } #endif diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index e663d92cf8..f8ee69348b 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -15,28 +15,27 @@ // ITA2 character table: - position in array corresponds to 5-bit ITA2 code // - characters to the left are in letters shift, characters to the right in figures shift // - characters marked 0x7F do not have ASCII equivalent -static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, - {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, - {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, - {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}}; +static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = { + {'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, + {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, + {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, + {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F} +}; /*! \class ITA2String - \brief ITA2-encoded string. */ class ITA2String { public: /*! \brief Default single-character constructor. - \param c ASCII-encoded character to encode as ITA2. */ explicit ITA2String(char c); /*! \brief Default string constructor. - \param str ASCII-encoded string to encode as ITA2. */ explicit ITA2String(const char* str); @@ -48,14 +47,12 @@ class ITA2String { /*! \brief Gets the length of the ITA2 string. This number is not the same as the length of ASCII-encoded string! - \returns Length of ITA2-encoded string. */ size_t length(); /*! \brief Gets the ITA2 representation of the ASCII string set in constructor. - \returns Pointer to dynamically allocated array, which contains ITA2-encoded bytes. It is the caller's responsibility to deallocate this memory! */ @@ -65,12 +62,12 @@ class ITA2String { private: #endif #if defined(RADIOLIB_STATIC_ONLY) - char _str[RADIOLIB_STATIC_ARRAY_SIZE]; + char strAscii[RADIOLIB_STATIC_ARRAY_SIZE]; #else - char* _str; + char* strAscii; #endif - size_t _len; - size_t _ita2Len; + size_t asciiLen; + size_t ita2Len; static uint16_t getBits(char c); }; @@ -82,14 +79,12 @@ class ITA2String { /*! \class RTTYClient - \brief Client for RTTY communication. The public interface is the same as Arduino Serial. */ class RTTYClient { public: /*! \brief Constructor for 2-FSK mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit RTTYClient(PhysicalLayer* phy); @@ -97,7 +92,6 @@ class RTTYClient { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. */ explicit RTTYClient(AFSKClient* audio); @@ -107,20 +101,14 @@ class RTTYClient { /*! \brief Initialization method. - \param base Base (space) frequency to be used in MHz (in 2-FSK mode), or the space tone frequency in Hz (in AFSK mode) - \param shift Frequency shift between mark and space in Hz. - \param rate Baud rate to be used during transmission. - - \param encoding Encoding to be used. Defaults to ASCII. - + \param enc Encoding to be used. Defaults to ASCII. \param stopBits Number of stop bits to be used. - \returns \ref status_codes */ - int16_t begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding = RADIOLIB_ASCII, uint8_t stopBits = 1); + int16_t begin(float base, uint32_t shift, uint16_t rate, uint8_t enc = RADIOLIB_ASCII, uint8_t stopBits = 1); /*! \brief Send out idle condition (RF tone at mark frequency). @@ -129,7 +117,6 @@ class RTTYClient { /*! \brief Stops transmitting. - \returns \ref status_codes */ int16_t standby(); @@ -170,17 +157,17 @@ class RTTYClient { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; + PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* _audio; + AFSKClient* audioClient; #endif - uint8_t _encoding = RADIOLIB_ASCII; - uint32_t _base = 0, _baseHz = 0; - uint32_t _shift = 0, _shiftHz = 0; - uint32_t _bitDuration = 0; - uint8_t _dataBits = 0; - uint8_t _stopBits = 0; + uint8_t encoding = RADIOLIB_ASCII; + uint32_t baseFreq = 0, baseFreqHz = 0; + uint32_t shiftFreq = 0, shiftFreqHz = 0; + uint32_t bitDuration = 0; + uint8_t dataBitsNum = 0; + uint8_t stopBitsNum = 0; void mark(); void space(); From 8722231ace72f759aad7fa12ea8bf9c2949d5f03 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:00 +0200 Subject: [PATCH 0497/1848] [PHY] Use compact Doxygen --- src/protocols/PhysicalLayer/PhysicalLayer.h | 113 ++++---------------- 1 file changed, 18 insertions(+), 95 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 9dca1f23db..a7a457c629 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -7,9 +7,10 @@ /*! \class PhysicalLayer - \brief Provides common interface for protocols that run on %LoRa/FSK modules, such as RTTY or LoRaWAN. Also extracts some common - module-independent methods. Using this interface class allows to use the protocols on various modules without much code duplicity. - Because this class is used mainly as interface, all of its virtual members must be implemented in the module class. + \brief Provides common interface for protocols that run on %LoRa/FSK modules, such as RTTY or LoRaWAN. + Also extracts some common module-independent methods. Using this interface class allows to use the protocols + on various modules without much code duplicity. Because this class is used mainly as interface, + all of its virtual members must be implemented in the module class. */ class PhysicalLayer { public: @@ -18,9 +19,7 @@ class PhysicalLayer { /*! \brief Default constructor. - \param freqStep Frequency step of the synthesizer in Hz. - \param maxPacketLength Maximum length of packet that can be received by the module. */ PhysicalLayer(float freqStep, size_t maxPacketLength); @@ -30,22 +29,16 @@ class PhysicalLayer { #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino Flash String transmit method. - \param str Pointer to Arduino Flash String that will be transmitted. - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t transmit(__FlashStringHelper* fstr, uint8_t addr = 0); /*! \brief Arduino String transmit method. - \param str Address of Arduino string that will be transmitted. - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t transmit(String& str, uint8_t addr = 0); @@ -53,24 +46,17 @@ class PhysicalLayer { /*! \brief C-string transmit method. - \param str C-string that will be transmitted. - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t transmit(const char* str, uint8_t addr = 0); /*! \brief Binary transmit method. Must be implemented in module class. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ virtual int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); @@ -78,11 +64,8 @@ class PhysicalLayer { #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino String receive method. - \param str Address of Arduino String to save the received data. - \param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet - \returns \ref status_codes */ int16_t receive(String& str, size_t len = 0); @@ -90,47 +73,38 @@ class PhysicalLayer { /*! \brief Sets module to sleep. - \returns \ref status_codes */ virtual int16_t sleep(); /*! \brief Sets module to standby. - \returns \ref status_codes */ virtual int16_t standby(); /*! \brief Sets module to a specific standby mode. - \returns \ref status_codes */ virtual int16_t standby(uint8_t mode); /*! - \brief Interrupt-driven receive method. A DIO pin will be activated when full packet is received. Must be implemented in module class. - - \param timeout Raw timeout value. Some modules use this argument to specify operation mode (single vs. continuous receive). - + \brief Interrupt-driven receive method. A DIO pin will be activated when full packet is received. + Must be implemented in module class. + \param timeout Raw timeout value. Some modules use this argument to specify operation mode + (single vs. continuous receive). \param irqFlags Sets the IRQ flags. - \param irqMask Sets the mask of IRQ flags that will trigger the DIO pin. - \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). - \returns \ref status_codes */ virtual int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Binary receive method. Must be implemented in module class. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. - \returns \ref status_codes */ virtual int16_t receive(uint8_t* data, size_t len); @@ -139,11 +113,8 @@ class PhysicalLayer { /*! \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. Interrupt pin will be activated when transmission finishes. - \param str Address of Arduino String that will be transmitted. - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t startTransmit(String& str, uint8_t addr = 0); @@ -152,31 +123,23 @@ class PhysicalLayer { /*! \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. Interrupt pin will be activated when transmission finishes. - \param str C-string that will be transmitted. - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t startTransmit(const char* str, uint8_t addr = 0); /*! \brief Interrupt-driven binary transmit method. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ virtual int16_t finishTransmit(); @@ -184,12 +147,9 @@ class PhysicalLayer { #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Reads data that was received after calling startReceive method. - \param str Address of Arduino String to save the received data. - - \param len Expected number of characters in the message. When set to 0, the packet length will be retreived automatically. - When more bytes than received are requested, only the number of bytes requested will be returned. - + \param len Expected number of characters in the message. When set to 0, the packet length will be retreived + automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ int16_t readData(String& str, size_t len = 0); @@ -197,12 +157,9 @@ class PhysicalLayer { /*! \brief Reads data that was received after calling startReceive method. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ virtual int16_t readData(uint8_t* data, size_t len); @@ -210,9 +167,7 @@ class PhysicalLayer { /*! \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. - \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. - \returns \ref status_codes */ virtual int16_t transmitDirect(uint32_t frf = 0); @@ -220,7 +175,6 @@ class PhysicalLayer { /*! \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. - \returns \ref status_codes */ virtual int16_t receiveDirect(); @@ -229,109 +183,89 @@ class PhysicalLayer { /*! \brief Sets carrier frequency. Must be implemented in module class. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ virtual int16_t setFrequency(float freq); /*! \brief Sets FSK bit rate. Only available in FSK mode. Must be implemented in module class. - \param br Bit rate to be set (in kbps). - \returns \ref status_codes */ virtual int16_t setBitRate(float br); /*! - \brief Sets FSK frequency deviation from carrier frequency. Only available in FSK mode. Must be implemented in module class. - + \brief Sets FSK frequency deviation from carrier frequency. Only available in FSK mode. + Must be implemented in module class. \param freqDev Frequency deviation to be set (in kHz). - \returns \ref status_codes */ virtual int16_t setFrequencyDeviation(float freqDev); /*! \brief Sets GFSK data shaping. Only available in FSK mode. Must be implemented in module class. - \param sh Shaping to be set. See \ref config_shaping for possible values. - \returns \ref status_codes */ virtual int16_t setDataShaping(uint8_t sh); /*! \brief Sets FSK data encoding. Only available in FSK mode. Must be implemented in module class. - \param enc Encoding to be used. See \ref config_encoding for possible values. - \returns \ref status_codes */ virtual int16_t setEncoding(uint8_t encoding); /*! \brief Gets the module frequency step size that was set in constructor. - \returns Synthesizer frequency step size in Hz. */ float getFreqStep() const; /*! \brief Query modem for the packet length of received payload. Must be implemented in module class. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ virtual size_t getPacketLength(bool update = true); /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. - \returns RSSI of the last received packet in dBm. */ virtual float getRSSI(); /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. - \returns SNR of the last received packet in dB. */ virtual float getSNR(); /*! \brief Get truly random number in range 0 - max. - \param max The maximum value of the random number (non-inclusive). - \returns Random number. */ int32_t random(int32_t max); /*! \brief Get truly random number in range min - max. - \param min The minimum value of the random number (inclusive). - \param max The maximum value of the random number (non-inclusive). - \returns Random number. */ int32_t random(int32_t min, int32_t max); /*! \brief Get one truly random byte from RSSI noise. Must be implemented in module class. - \returns TRNG byte. */ virtual uint8_t randomByte(); /*! - \brief Configure module parameters for direct modes. Must be called prior to "ham" modes like RTTY or AX.25. Only available in FSK mode. - + \brief Configure module parameters for direct modes. Must be called prior to "ham" modes like RTTY or AX.25. + Only available in FSK mode. \returns \ref status_codes */ int16_t startDirect(); @@ -339,32 +273,27 @@ class PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set sync word to be used to determine start of packet in direct reception mode. - \param syncWord Sync word bits. - \param len Sync word length in bits. Set to zero to disable sync word matching. - \returns \ref status_codes */ int16_t setDirectSyncWord(uint32_t syncWord, uint8_t len); /*! - \brief Set interrupt service routine function to call when data bit is receveid in direct mode. Must be implemented in module class. - + \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + Must be implemented in module class. \param func Pointer to interrupt service routine. */ virtual void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. Must be implemented in module class. - \param pin Pin on which to read. */ virtual void readBit(uint32_t pin); /*! \brief Get the number of direct mode bytes currently available in buffer. - \returns Number of available bytes. */ int16_t available(); @@ -376,9 +305,8 @@ class PhysicalLayer { /*! \brief Get data from direct mode buffer. - - \param drop Drop synchronization on read - next reading will require waiting for the sync word again. Defautls to true. - + \param drop Drop synchronization on read - next reading will require waiting for the sync word again. + Defaults to true. \returns Byte from direct mode buffer. */ uint8_t read(bool drop = true); @@ -386,18 +314,14 @@ class PhysicalLayer { /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). - \param pin Pin number onto which a signal is to be placed. - \param value The value that indicates which function to place on that pin. See chip datasheet for details. - \returns \ref status_codes */ virtual int16_t setDIOMapping(uint32_t pin, uint32_t value); /*! \brief Sets interrupt service routine to call when DIO1 activates. - \param func ISR to call. */ virtual void setDio1Action(void (*func)(void)); @@ -412,7 +336,6 @@ class PhysicalLayer { /*! \brief Set function to be called to set up the timing interrupt. For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing - \param func Setup function to be called, with one argument (pulse length in microseconds). */ void setInterruptSetup(void (*func)(uint32_t)); From 6bbd237fb35dd0fd7f33480e658557dfc6f3c967 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:14 +0200 Subject: [PATCH 0498/1848] [Pager] Use compact Doxygen and stop using reserved format --- src/protocols/Pager/Pager.cpp | 118 +++++++++++++++++----------------- src/protocols/Pager/Pager.h | 83 +++++++----------------- 2 files changed, 84 insertions(+), 117 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 9d2aa8f135..2ed9c5c319 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -6,48 +6,48 @@ #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) // this is a massive hack, but we need a global-scope ISR to manage the bit reading // let's hope nobody ever tries running two POCSAG receivers at the same time -static PhysicalLayer* _readBitInstance = NULL; -static uint32_t _readBitPin = RADIOLIB_NC; +static PhysicalLayer* readBitInstance = NULL; +static uint32_t readBitPin = RADIOLIB_NC; #if defined(ESP8266) || defined(ESP32) ICACHE_RAM_ATTR #endif static void PagerClientReadBit(void) { - if(_readBitInstance) { - _readBitInstance->readBit(_readBitPin); + if(readBitInstance) { + readBitInstance->readBit(readBitPin); } } #endif PagerClient::PagerClient(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) - _readBitInstance = _phy; + readBitInstance = phyLayer; #endif } int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { // calculate duration of 1 bit in us - _speed = (float)speed/1000.0f; - _bitDuration = (uint32_t)1000000/speed; + dataRate = (float)speed/1000.0f; + bitDuration = (uint32_t)1000000/speed; // calculate 24-bit frequency - _base = base; - _baseRaw = (_base * 1000000.0) / _phy->getFreqStep(); + baseFreq = base; + baseFreqRaw = (baseFreq * 1000000.0) / phyLayer->getFreqStep(); // calculate module carrier frequency resolution - uint16_t step = round(_phy->getFreqStep()); + uint16_t step = round(phyLayer->getFreqStep()); // calculate raw frequency shift - _shiftHz = shift; - _shift = _shiftHz/step; + shiftFreqHz = shift; + shiftFreq = shiftFreqHz/step; inv = invert; // initialize BCH encoder encoderInit(); // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } int16_t PagerClient::sendTone(uint32_t addr) { @@ -217,7 +217,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t #endif // turn transmitter off - _phy->standby(); + phyLayer->standby(); return(RADIOLIB_ERR_NONE); } @@ -225,43 +225,43 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { // save the variables - _readBitPin = pin; - _filterAddr = addr; - _filterMask = mask; + readBitPin = pin; + filterAddr = addr; + filterMask = mask; // set the carrier frequency - int16_t state = _phy->setFrequency(_base); + int16_t state = phyLayer->setFrequency(baseFreq); RADIOLIB_ASSERT(state); // set bitrate - state = _phy->setBitRate(_speed); + state = phyLayer->setBitRate(dataRate); RADIOLIB_ASSERT(state); // set frequency deviation to 4.5 khz - state = _phy->setFrequencyDeviation((float)_shiftHz / 1000.0f); + state = phyLayer->setFrequencyDeviation((float)shiftFreqHz / 1000.0f); RADIOLIB_ASSERT(state); // now set up the direct mode reception - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); mod->hal->pinMode(pin, mod->hal->GpioModeInput); // set direct sync word to the frame sync word // the logic here is inverted, because modules like SX1278 // assume high frequency to be logic 1, which is opposite to POCSAG if(!inv) { - _phy->setDirectSyncWord(~RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + phyLayer->setDirectSyncWord(~RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); } else { - _phy->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); + phyLayer->setDirectSyncWord(RADIOLIB_PAGER_FRAME_SYNC_CODE_WORD, 32); } - _phy->setDirectAction(PagerClientReadBit); - _phy->receiveDirect(); + phyLayer->setDirectAction(PagerClientReadBit); + phyLayer->receiveDirect(); return(state); } size_t PagerClient::available() { - return(_phy->available() + sizeof(uint32_t))/(sizeof(uint32_t) * (RADIOLIB_PAGER_BATCH_LEN + 1)); + return(phyLayer->available() + sizeof(uint32_t))/(sizeof(uint32_t) * (RADIOLIB_PAGER_BATCH_LEN + 1)); } #if defined(RADIOLIB_BUILD_ARDUINO) @@ -316,7 +316,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { bool match = false; uint8_t framePos = 0; uint8_t symbolLength = 0; - while(!match && _phy->available()) { + while(!match && phyLayer->available()) { uint32_t cw = read(); framePos++; @@ -339,7 +339,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { // should be an address code word, extract the address uint32_t addr_found = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); - if((addr_found & _filterMask) == (_filterAddr & _filterMask)) { + if((addr_found & filterMask) == (filterAddr & filterMask)) { // we have a match! match = true; if(addr) { @@ -366,7 +366,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { uint32_t prevCw = 0; bool overflow = false; int8_t ovfBits = 0; - while(!complete && _phy->available()) { + while(!complete && phyLayer->available()) { uint32_t cw = read(); // check if it's the idle code word @@ -452,17 +452,17 @@ void PagerClient::write(uint32_t* data, size_t len) { void PagerClient::write(uint32_t codeWord) { // write single code word - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); for(int8_t i = 31; i >= 0; i--) { uint32_t mask = (uint32_t)0x01 << i; uint32_t start = mod->hal->micros(); // figure out the shift direction - start by assuming the bit is 0 - int16_t change = _shift; + int16_t change = shiftFreq; // now check if it's actually 1 if(codeWord & mask) { - change = -_shift; + change = -shiftFreq; } // finally, check if inversion is enabled @@ -471,13 +471,13 @@ void PagerClient::write(uint32_t codeWord) { } // now transmit the shifted frequency - _phy->transmitDirect(_baseRaw + change); + phyLayer->transmitDirect(baseFreqRaw + change); // this is pretty silly, while(mod->hal->micros() ... ) would be enough // but for some reason, MegaCore throws a linker error on it // "relocation truncated to fit: R_AVR_7_PCREL against `no symbol'" uint32_t now = mod->hal->micros(); - while(now - start < _bitDuration) { + while(now - start < bitDuration) { now = mod->hal->micros(); } } @@ -486,10 +486,10 @@ void PagerClient::write(uint32_t codeWord) { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) uint32_t PagerClient::read() { uint32_t codeWord = 0; - codeWord |= (uint32_t)_phy->read() << 24; - codeWord |= (uint32_t)_phy->read() << 16; - codeWord |= (uint32_t)_phy->read() << 8; - codeWord |= (uint32_t)_phy->read(); + codeWord |= (uint32_t)phyLayer->read() << 24; + codeWord |= (uint32_t)phyLayer->read() << 16; + codeWord |= (uint32_t)phyLayer->read() << 8; + codeWord |= (uint32_t)phyLayer->read(); // check if we need to invert bits // the logic here is inverted, because modules like SX1278 @@ -548,40 +548,40 @@ char PagerClient::decodeBCD(uint8_t b) { void PagerClient::encoderInit() { /* * generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] - * lookup tables: index->polynomial form _bchAlphaTo[] contains j=alpha**i; - * polynomial form -> index form _bchIndexOf[j=alpha**i] = i alpha=2 is the + * lookup tables: index->polynomial form bchAlphaTo[] contains j=alpha**i; + * polynomial form -> index form bchIndexOf[j=alpha**i] = i alpha=2 is the * primitive element of GF(2**m) */ int32_t mask = 1; - _bchAlphaTo[RADIOLIB_PAGER_BCH_M] = 0; + bchAlphaTo[RADIOLIB_PAGER_BCH_M] = 0; for(uint8_t i = 0; i < RADIOLIB_PAGER_BCH_M; i++) { - _bchAlphaTo[i] = mask; + bchAlphaTo[i] = mask; - _bchIndexOf[_bchAlphaTo[i]] = i; + bchIndexOf[bchAlphaTo[i]] = i; if(RADIOLIB_PAGER_BCH_PRIMITIVE_POLY & ((uint32_t)0x01 << i)) { - _bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^= mask; + bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^= mask; } mask <<= 1; } - _bchIndexOf[_bchAlphaTo[RADIOLIB_PAGER_BCH_M]] = RADIOLIB_PAGER_BCH_M; + bchIndexOf[bchAlphaTo[RADIOLIB_PAGER_BCH_M]] = RADIOLIB_PAGER_BCH_M; mask >>= 1; for(uint8_t i = RADIOLIB_PAGER_BCH_M + 1; i < RADIOLIB_PAGER_BCH_N; i++) { - if(_bchAlphaTo[i - 1] >= mask) { - _bchAlphaTo[i] = _bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^ ((_bchAlphaTo[i - 1] ^ mask) << 1); + if(bchAlphaTo[i - 1] >= mask) { + bchAlphaTo[i] = bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^ ((bchAlphaTo[i - 1] ^ mask) << 1); } else { - _bchAlphaTo[i] = _bchAlphaTo[i - 1] << 1; + bchAlphaTo[i] = bchAlphaTo[i - 1] << 1; } - _bchIndexOf[_bchAlphaTo[i]] = i; + bchIndexOf[bchAlphaTo[i]] = i; } - _bchIndexOf[0] = -1; + bchIndexOf[0] = -1; /* * Compute generator polynomial of BCH code of length = 31, redundancy = 10 @@ -665,19 +665,19 @@ void PagerClient::encoderInit() { } // Compute generator polynomial - _bchG[0] = _bchAlphaTo[zeros[1]]; - _bchG[1] = 1; // g(x) = (X + zeros[1]) initially + bchG[0] = bchAlphaTo[zeros[1]]; + bchG[1] = 1; // g(x) = (X + zeros[1]) initially for(ii = 2; ii <= rdncy; ii++) { - _bchG[ii] = 1; + bchG[ii] = 1; for(jj = ii - 1; jj > 0; jj--) { - if(_bchG[jj] != 0) { - _bchG[jj] = _bchG[jj - 1] ^ _bchAlphaTo[(_bchIndexOf[_bchG[jj]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; + if(bchG[jj] != 0) { + bchG[jj] = bchG[jj - 1] ^ bchAlphaTo[(bchIndexOf[bchG[jj]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; } else { - _bchG[jj] = _bchG[jj - 1]; + bchG[jj] = bchG[jj - 1]; } } - _bchG[0] = _bchAlphaTo[(_bchIndexOf[_bchG[0]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; + bchG[0] = bchAlphaTo[(bchIndexOf[bchG[0]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; } } @@ -711,7 +711,7 @@ uint32_t PagerClient::encodeBCH(uint32_t dat) { while(end < RADIOLIB_PAGER_BCH_N) { for(int32_t i = end; i > start-2; --i) { if(Mr[start]) { - Mr[i] ^= _bchG[j]; + Mr[i] ^= bchG[j]; ++j; } else { ++start; diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index c0dc496012..5436bf9a02 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -63,14 +63,12 @@ /*! \class PagerClient - \brief Client for Pager communication. */ class PagerClient { public: /*! \brief Default constructor. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit PagerClient(PhysicalLayer* phy); @@ -79,24 +77,17 @@ class PagerClient { /*! \brief Initialization method. - \param base Base (center) frequency to be used in MHz. - \param speed Bit rate to use in bps. Common POCSAG decoders can receive 512, 1200 and 2400 bps. - \param invert Enable frequency inversion. Disabled by default (high frequency is digital 0). - \param shift Set custom frequency shift, defaults to 4500 Hz. - \returns \ref status_codes */ int16_t begin(float base, uint16_t speed, bool invert = false, uint16_t shift = RADIOLIB_PAGER_FREQ_SHIFT_HZ); /*! \brief Method to send a tone-only alert to a destination pager. - \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. - \returns \ref status_codes */ int16_t sendTone(uint32_t addr); @@ -104,13 +95,9 @@ class PagerClient { #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Arduino String transmit method. - \param str Address of Arduino string that will be transmitted. - \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. - \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. - \returns \ref status_codes */ int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); @@ -118,50 +105,36 @@ class PagerClient { /*! \brief C-string transmit method. - \param str C-string that will be transmitted. - \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. - \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. - \returns \ref status_codes */ int16_t transmit(const char* str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); /*! \brief Binary transmit method. Will transmit arbitrary binary data. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. - \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); - -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Start reception of POCSAG packets. - \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). - \param addr Address of this "pager". Allowed values are 0 to 2097151 - values above 2000000 are reserved. - - \param mask Address filter mask - set individual bits to enable or disable match on that bit of the address.¨Set to 0xFFFFF (all bits checked) by default. - + \param mask Address filter mask - set individual bits to enable or disable match on that bit of the address. + Set to 0xFFFFF (all bits checked) by default. \returns \ref status_codes */ int16_t startReceive(uint32_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); /*! \brief Get the number of POCSAG batches available in buffer. Limited by the size of direct mode buffer! - \returns Number of available batches. */ size_t available(); @@ -169,14 +142,11 @@ class PagerClient { #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Reads data that was received after calling startReceive method. - \param str Address of Arduino String to save the received data. - - \param len Expected number of characters in the message. When set to 0, the message length will be retreived automatically. - When more bytes than received are requested, only the number of bytes requested will be returned. - - \param addr Pointer to variable holding the address of the received pager message. Set to NULL to not retrieve address. - + \param len Expected number of characters in the message. When set to 0, the message lengthwill be retreived + automatically. When more bytes than received are requested, only the number of bytes requested will be returned. + \param addr Pointer to variable holding the address of the received pager message. + Set to NULL to not retrieve address. \returns \ref status_codes */ int16_t readData(String& str, size_t len = 0, uint32_t* addr = NULL); @@ -184,15 +154,12 @@ class PagerClient { /*! \brief Reads data that was received after calling startReceive method. - \param data Pointer to array to save the received message. - - \param len Pointer to variable holding the number of bytes that will be read. When set to 0, the packet length will be retreived automatically. - When more bytes than received are requested, only the number of bytes requested will be returned. - Upon completion, the number of bytes received will be written to this variable. - - \param addr Pointer to variable holding the address of the received pager message. Set to NULL to not retrieve address. - + \param len Pointer to variable holding the number of bytes that will be read. When set to 0, the packet length + will be retreived automatically. When more bytes than received are requested, only the number of bytes + requested will be returned. Upon completion, the number of bytes received will be written to this variable. + \param addr Pointer to variable holding the address of the received pager message. + Set to NULL to not retrieve address. \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t* len, uint32_t* addr = NULL); @@ -201,22 +168,22 @@ class PagerClient { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; - - float _base; - float _speed; - uint32_t _baseRaw; - uint16_t _shift; - uint16_t _shiftHz; - uint16_t _bitDuration; - uint32_t _filterAddr; - uint32_t _filterMask; + PhysicalLayer* phyLayer; + + float baseFreq; + float dataRate; + uint32_t baseFreqRaw; + uint16_t shiftFreq; + uint16_t shiftFreqHz; + uint16_t bitDuration; + uint32_t filterAddr; + uint32_t filterMask; bool inv = false; // BCH encoder - int32_t _bchAlphaTo[RADIOLIB_PAGER_BCH_N + 1]; - int32_t _bchIndexOf[RADIOLIB_PAGER_BCH_N + 1]; - int32_t _bchG[RADIOLIB_PAGER_BCH_N - RADIOLIB_PAGER_BCH_K + 1]; + int32_t bchAlphaTo[RADIOLIB_PAGER_BCH_N + 1]; + int32_t bchIndexOf[RADIOLIB_PAGER_BCH_N + 1]; + int32_t bchG[RADIOLIB_PAGER_BCH_N - RADIOLIB_PAGER_BCH_K + 1]; void write(uint32_t* data, size_t len); void write(uint32_t codeWord); From bb4e6cf9467bf391cb8eaff38beb4e6d8b8aa92a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:23 +0200 Subject: [PATCH 0499/1848] [Morse] Use compact Doxygen and stop using reserved format --- src/protocols/Morse/Morse.cpp | 66 +++++++++++++++++------------------ src/protocols/Morse/Morse.h | 34 ++++++------------ 2 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index afbb03a7e8..377b6c01ca 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -5,35 +5,35 @@ #if !defined(RADIOLIB_EXCLUDE_MORSE) MorseClient::MorseClient(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - _audio = nullptr; + audioClient = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) MorseClient::MorseClient(AFSKClient* audio) { - _phy = audio->_phy; - _audio = audio; + phyLayer = audio->phyLayer; + audioClient = audio; } #endif int16_t MorseClient::begin(float base, uint8_t speed) { // calculate 24-bit frequency - _baseHz = base; - _base = (base * 1000000.0) / _phy->getFreqStep(); + baseFreqHz = base; + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); // calculate tone period for decoding - _basePeriod = (1000000.0f/base)/2.0f; + basePeriod = (1000000.0f/base)/2.0f; // calculate symbol lengths (assumes PARIS as typical word) - _dotLength = 1200 / speed; - _dashLength = 3*_dotLength; - _letterSpace = 3*_dotLength; - _wordSpace = 4*_dotLength; + dotLength = 1200 / speed; + dashLength = 3*dotLength; + letterSpace = 3*dotLength; + wordSpace = 4*dotLength; // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } size_t MorseClient::startSignal() { @@ -59,13 +59,13 @@ char MorseClient::decode(uint8_t symbol, uint8_t len) { #if !defined(RADIOLIB_EXCLUDE_AFSK) int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); // measure pulse duration in us - uint32_t duration = mod->hal->pulseIn(_audio->_pin, mod->hal->GpioLevelLow, 4*_basePeriod); + uint32_t duration = mod->hal->pulseIn(audioClient->outPin, mod->hal->GpioLevelLow, 4*basePeriod); // decide if this is a signal, or pause - if((duration > low*_basePeriod) && (duration < high*_basePeriod)) { + if((duration > low*basePeriod) && (duration < high*basePeriod)) { // this is a signal signalCounter++; } else if(duration == 0) { @@ -80,9 +80,9 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { signalStart = mod->hal->millis(); uint32_t pauseLen = mod->hal->millis() - pauseStart; - if((pauseLen >= low*(float)_letterSpace) && (pauseLen <= high*(float)_letterSpace)) { + if((pauseLen >= low*(float)letterSpace) && (pauseLen <= high*(float)letterSpace)) { return(RADIOLIB_MORSE_CHAR_COMPLETE); - } else if(pauseLen > _wordSpace) { + } else if(pauseLen > wordSpace) { RADIOLIB_DEBUG_PRINTLN("\n"); return(RADIOLIB_MORSE_WORD_COMPLETE); } @@ -93,11 +93,11 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { pauseStart = mod->hal->millis(); uint32_t signalLen = mod->hal->millis() - signalStart; - if((signalLen >= low*(float)_dotLength) && (signalLen <= high*(float)_dotLength)) { + if((signalLen >= low*(float)dotLength) && (signalLen <= high*(float)dotLength)) { RADIOLIB_DEBUG_PRINT("."); (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); (*len)++; - } else if((signalLen >= low*(float)_dashLength) && (signalLen <= high*(float)_dashLength)) { + } else if((signalLen >= low*(float)dashLength) && (signalLen <= high*(float)dashLength)) { RADIOLIB_DEBUG_PRINT("-"); (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); (*len)++; @@ -127,7 +127,7 @@ size_t MorseClient::write(uint8_t* buff, size_t len) { } size_t MorseClient::write(uint8_t b) { - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); // check unprintable ASCII characters and boundaries if((b < ' ') || (b == 0x60) || (b > 'z')) { @@ -138,7 +138,7 @@ size_t MorseClient::write(uint8_t b) { if(b == ' ') { RADIOLIB_DEBUG_PRINTLN("space"); standby(); - mod->waitForMicroseconds(mod->hal->micros(), _wordSpace*1000); + mod->waitForMicroseconds(mod->hal->micros(), wordSpace*1000); return(1); } @@ -156,17 +156,17 @@ size_t MorseClient::write(uint8_t b) { // send dot or dash if (code & RADIOLIB_MORSE_DASH) { RADIOLIB_DEBUG_PRINT("-"); - transmitDirect(_base, _baseHz); - mod->waitForMicroseconds(mod->hal->micros(), _dashLength*1000); + transmitDirect(baseFreq, baseFreqHz); + mod->waitForMicroseconds(mod->hal->micros(), dashLength*1000); } else { RADIOLIB_DEBUG_PRINT("."); - transmitDirect(_base, _baseHz); - mod->waitForMicroseconds(mod->hal->micros(), _dotLength*1000); + transmitDirect(baseFreq, baseFreqHz); + mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); } // symbol space standby(); - mod->waitForMicroseconds(mod->hal->micros(), _dotLength*1000); + mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); // move onto the next bit code >>= 1; @@ -174,7 +174,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); - mod->waitForMicroseconds(mod->hal->micros(), _letterSpace*1000 - _dotLength*1000); + mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000); RADIOLIB_DEBUG_PRINTLN(); return(1); @@ -381,20 +381,20 @@ size_t MorseClient::printFloat(double number, uint8_t digits) { int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->tone(freqHz)); + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); } #endif - return(_phy->transmitDirect(freq)); + return(phyLayer->transmitDirect(freq)); } int16_t MorseClient::standby() { #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->noTone(true)); + if(audioClient != nullptr) { + return(audioClient->noTone(true)); } #endif - return(_phy->standby()); + return(phyLayer->standby()); } #endif diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 3f0fc5cb36..374ccd55cd 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -87,14 +87,12 @@ static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { /*! \class MorseClient - \brief Client for Morse Code communication. The public interface is the same as Arduino Serial. */ class MorseClient { public: /*! \brief Constructor for 2-FSK mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit MorseClient(PhysicalLayer* phy); @@ -102,7 +100,6 @@ class MorseClient { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. */ explicit MorseClient(AFSKClient* audio); @@ -112,45 +109,34 @@ class MorseClient { /*! \brief Initialization method. - \param base Base RF frequency to be used in MHz (in 2-FSK mode), or the tone frequency in Hz (in AFSK mode) - \param speed Coding speed in words per minute. - \returns \ref status_codes */ int16_t begin(float base, uint8_t speed = 20); /*! \brief Send start signal. - \returns Number of bytes sent (always 0). */ size_t startSignal(); /*! \brief Decode Morse symbol to ASCII. - \param symbol Morse code symbol, respresented as outlined in MorseTable. - \param len Symbol length (number of dots and dashes). - \returns ASCII character matching the symbol, or 0xFF if no match is found. */ static char decode(uint8_t symbol, uint8_t len); /*! \brief Read Morse tone on input pin. - \param symbol Pointer to the symbol buffer. - \param len Pointer to the length counter. - \param low Low threshold for decision limit (dot length, pause length etc.), defaults to 0.75. - \param high High threshold for decision limit (dot length, pause length etc.), defaults to 1.25. - - \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, 2 if inter-word space was detected. + \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, + 2 if inter-word space was detected. */ #if !defined(RADIOLIB_EXCLUDE_AFSK) int read(uint8_t* symbol, uint8_t* len, float low = 0.75f, float high = 1.25f); @@ -190,17 +176,17 @@ class MorseClient { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; + PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* _audio; + AFSKClient* audioClient; #endif - uint32_t _base = 0, _baseHz = 0; - float _basePeriod = 0.0f; - uint32_t _dotLength = 0; - uint32_t _dashLength = 0; - uint32_t _letterSpace = 0; - uint16_t _wordSpace = 0; + uint32_t baseFreq = 0, baseFreqHz = 0; + float basePeriod = 0.0f; + uint32_t dotLength = 0; + uint32_t dashLength = 0; + uint32_t letterSpace = 0; + uint16_t wordSpace = 0; // variables to keep decoding state uint32_t signalCounter = 0; From 34e59605b5655e42e86c90aaba258e1ff19f563d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:33 +0200 Subject: [PATCH 0500/1848] [Hell] Use compact Doxygen and stop using reserved format --- src/protocols/Hellschreiber/Hellschreiber.cpp | 38 +++++++++---------- src/protocols/Hellschreiber/Hellschreiber.h | 25 +++++------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index c25f05f25f..63fb915f1b 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -4,47 +4,47 @@ #if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) HellClient::HellClient(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - _audio = nullptr; + audioClient = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) HellClient::HellClient(AFSKClient* audio) { - _phy = audio->_phy; - _audio = audio; + phyLayer = audio->phyLayer; + audioClient = audio; } #endif int16_t HellClient::begin(float base, float rate) { // calculate 24-bit frequency - _baseHz = base; - _base = (base * 1000000.0) / _phy->getFreqStep(); + baseFreqHz = base; + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); // calculate "pixel" duration - _pixelDuration = 1000000.0/rate; + pixelDuration = 1000000.0/rate; // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } size_t HellClient::printGlyph(uint8_t* buff) { // print the character - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); bool transmitting = false; for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { for(int8_t i = RADIOLIB_HELL_FONT_HEIGHT - 1; i >= 0; i--) { uint32_t start = mod->hal->micros(); if((buff[i] & mask) && (!transmitting)) { transmitting = true; - transmitDirect(_base, _baseHz); + transmitDirect(baseFreq, baseFreqHz); } else if((!(buff[i] & mask)) && (transmitting)) { transmitting = false; standby(); } - mod->waitForMicroseconds(start, _pixelDuration); + mod->waitForMicroseconds(start, pixelDuration); } } @@ -54,8 +54,8 @@ size_t HellClient::printGlyph(uint8_t* buff) { return(1); } -void HellClient::setInversion(bool invert) { - _inv = invert; +void HellClient::setInversion(bool inv) { + invert = inv; } size_t HellClient::write(const char* str) { @@ -298,20 +298,20 @@ size_t HellClient::printFloat(double number, uint8_t digits) { int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->tone(freqHz)); + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); } #endif - return(_phy->transmitDirect(freq)); + return(phyLayer->transmitDirect(freq)); } int16_t HellClient::standby() { #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->noTone(_inv)); + if(audioClient != nullptr) { + return(audioClient->noTone(invert)); } #endif - return(_phy->standby(RADIOLIB_STANDBY_WARM)); + return(phyLayer->standby(RADIOLIB_STANDBY_WARM)); } #endif diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 1609168aae..ac7d5d6c64 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -13,7 +13,8 @@ // font definition: characters are stored in rows, // least significant byte of each character is the first row -// Hellschreiber use 7x7 characters, but this simplified font uses only 5x5 - the extra bytes aren't stored +// Hellschreiber use 7x7 characters, but this simplified font uses only 5x5 +// the extra bytes aren't stored static const uint8_t HellFont[64][RADIOLIB_HELL_FONT_WIDTH - 2] RADIOLIB_NONVOLATILE = { { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0000000 }, // space { 0b0001000, 0b0001000, 0b0001000, 0b0000000, 0b0001000 }, // ! @@ -83,14 +84,12 @@ static const uint8_t HellFont[64][RADIOLIB_HELL_FONT_WIDTH - 2] RADIOLIB_NONVOLA /*! \class HellClient - \brief Client for Hellschreiber transmissions. */ class HellClient { public: /*! \brief Constructor for 2-FSK mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit HellClient(PhysicalLayer* phy); @@ -98,7 +97,6 @@ class HellClient { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. */ explicit HellClient(AFSKClient* audio); @@ -108,28 +106,23 @@ class HellClient { /*! \brief Initialization method. - \param base Base RF frequency to be used in MHz (in 2-FSK mode), or the tone frequency in Hz (in AFSK mode). - \param rate Baud rate to be used during transmission. Defaults to 122.5 ("Feld Hell") */ int16_t begin(float base, float rate = 122.5); /*! \brief Method to "print" a buffer of pixels, this is exposed to allow users to send custom characters. - \param buff Buffer of pixels to send, in a 7x7 pixel array. - \returns Always returns the number of printed glyphs (1). */ size_t printGlyph(uint8_t* buff); /*! \brief Invert text color. - - \param invert Whether to enable color inversion (white text on black background), or not (black text on white background) + \param inv Whether to enable color inversion (white text on black background), or not (black text on white background) */ - void setInversion(bool invert); + void setInversion(bool inv); size_t write(const char* str); size_t write(uint8_t* buff, size_t len); @@ -165,14 +158,14 @@ class HellClient { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; + PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* _audio; + AFSKClient* audioClient; #endif - uint32_t _base = 0, _baseHz = 0; - uint32_t _pixelDuration = 0; - bool _inv = false; + uint32_t baseFreq = 0, baseFreqHz = 0; + uint32_t pixelDuration = 0; + bool invert = false; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); From c988f6492152824654c8967db36da2eaae933759 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:42 +0200 Subject: [PATCH 0501/1848] [FSK4] Use compact Doxygen and stop using reserved format --- src/protocols/FSK4/FSK4.cpp | 52 ++++++++++++++++++------------------- src/protocols/FSK4/FSK4.h | 33 +++++++---------------- 2 files changed, 35 insertions(+), 50 deletions(-) diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index fcd1d1d398..bb24e5bee2 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -3,41 +3,41 @@ #if !defined(RADIOLIB_EXCLUDE_FSK4) FSK4Client::FSK4Client(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - _audio = nullptr; + audioClient = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) FSK4Client::FSK4Client(AFSKClient* audio) { - _phy = audio->_phy; - _audio = audio; + phyLayer = audio->phyLayer; + audioClient = audio; } #endif int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { // save configuration - _baseHz = base; - _shiftHz = shift; + baseFreqHz = base; + shiftFreqHz = shift; // calculate duration of 1 bit - _bitDuration = (uint32_t)1000000/rate; + bitDuration = (uint32_t)1000000/rate; // calculate carrier shift - _shift = getRawShift(shift); + shiftFreq = getRawShift(shift); // Write resultant tones into arrays for quick lookup when modulating. for(uint8_t i = 0; i < 4; i++) { - _tones[i] = _shift*i; - _tonesHz[i] = _shiftHz*i; + tones[i] = shiftFreq*i; + tonesHz[i] = shiftFreqHz*i; } // calculate 24-bit frequency - _base = (base * 1000000.0) / _phy->getFreqStep(); + baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } void FSK4Client::idle() { @@ -47,10 +47,10 @@ void FSK4Client::idle() { int16_t FSK4Client::setCorrection(int16_t offsets[], float length) { for(uint8_t i = 0; i < 4; i++) { - _tones[i] += getRawShift(offsets[i]); - _tonesHz[i] += offsets[i]; + tones[i] += getRawShift(offsets[i]); + tonesHz[i] += offsets[i]; } - _bitDuration *= length; + bitDuration *= length; return(RADIOLIB_ERR_NONE); } @@ -80,36 +80,36 @@ size_t FSK4Client::write(uint8_t b) { } void FSK4Client::tone(uint8_t i) { - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); - transmitDirect(_base + _tones[i], _baseHz + _tonesHz[i]); - mod->waitForMicroseconds(start, _bitDuration); + transmitDirect(baseFreq + tones[i], baseFreqHz + tonesHz[i]); + mod->waitForMicroseconds(start, bitDuration); } int16_t FSK4Client::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->tone(freqHz)); + if(audioClient != nullptr) { + return(audioClient->tone(freqHz)); } #endif - return(_phy->transmitDirect(freq)); + return(phyLayer->transmitDirect(freq)); } int16_t FSK4Client::standby() { // ensure everything is stopped in interrupt timing mode - Module* mod = _phy->getMod(); + Module* mod = phyLayer->getMod(); mod->waitForMicroseconds(0, 0); #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - return(_audio->noTone()); + if(audioClient != nullptr) { + return(audioClient->noTone()); } #endif - return(_phy->standby()); + return(phyLayer->standby()); } int32_t FSK4Client::getRawShift(int32_t shift) { // calculate module carrier frequency resolution - int32_t step = round(_phy->getFreqStep()); + int32_t step = round(phyLayer->getFreqStep()); // check minimum shift value if(abs(shift) < step / 2) { diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index aecba119b4..d466d64299 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -10,14 +10,12 @@ /*! \class FSK4Client - \brief Client for FSK-4 communication. The public interface is the same as Arduino Serial. */ class FSK4Client { public: /*! \brief Constructor for FSK-4 mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit FSK4Client(PhysicalLayer* phy); @@ -25,7 +23,6 @@ class FSK4Client { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. */ explicit FSK4Client(AFSKClient* audio); @@ -35,13 +32,10 @@ class FSK4Client { /*! \brief Initialization method. - - \param base Base (space) frequency to be used in MHz (in FSK-4 mode), or the space tone frequency in Hz (in AFSK mode) - + \param base Base (space) frequency to be used in MHz (in FSK-4 mode), + or the space tone frequency in Hz (in AFSK mode) \param shift Frequency shift between each tone in Hz. - \param rate Baud rate to be used during transmission. - \returns \ref status_codes */ int16_t begin(float base, uint32_t shift, uint16_t rate); @@ -53,38 +47,29 @@ class FSK4Client { /*! \brief Set correction coefficients for frequencies and tone length. - \param offsets Four positive or negative correction offsets for audio frequencies in Hz. - \param length Tone length modifier, defaults to 1.0. - \returns \ref status_codes */ int16_t setCorrection(int16_t offsets[4], float length = 1.0f); /*! \brief Transmit binary data. - \param buff Buffer to transmit. - \param len Number of bytes to transmit. - \returns Number of transmitted bytes. */ size_t write(uint8_t* buff, size_t len); /*! \brief Transmit a single byte. - \param b Byte to transmit. - \returns Number of transmitted bytes. */ size_t write(uint8_t b); /*! \brief Stop transmitting. - \returns \ref status_codes */ int16_t standby(); @@ -92,16 +77,16 @@ class FSK4Client { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; + PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* _audio; + AFSKClient* audioClient; #endif - uint32_t _base = 0, _baseHz = 0; - uint32_t _shift = 0, _shiftHz = 0; - uint32_t _bitDuration = 0; - uint32_t _tones[4]; - uint32_t _tonesHz[4]; + uint32_t baseFreq = 0, baseFreqHz = 0; + uint32_t shiftFreq = 0, shiftFreqHz = 0; + uint32_t bitDuration = 0; + uint32_t tones[4]; + uint32_t tonesHz[4]; void tone(uint8_t i); From 5da2a023fe87b833c064a8feb59aea94c32c0f6c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:51 +0200 Subject: [PATCH 0502/1848] [AX25] Use compact Doxygen and stop using reserved format --- src/protocols/AX25/AX25.cpp | 64 ++++++++++++++-------------- src/protocols/AX25/AX25.h | 83 +++++++++---------------------------- 2 files changed, 51 insertions(+), 96 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 0e8a77b2c6..63f0bc4b87 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -152,32 +152,32 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) { } AX25Client::AX25Client(PhysicalLayer* phy) { - _phy = phy; + phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - _audio = nullptr; + audioClient = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) AX25Client::AX25Client(AFSKClient* audio) { - _phy = audio->_phy; - _audio = audio; - _afskMark = RADIOLIB_AX25_AFSK_MARK; - _afskSpace = RADIOLIB_AX25_AFSK_SPACE; - _afskLen = RADIOLIB_AX25_AFSK_TONE_DURATION; + phyLayer = audio->phyLayer; + audioClient = audio; + afskMark = RADIOLIB_AX25_AFSK_MARK; + afskSpace = RADIOLIB_AX25_AFSK_SPACE; + afskLen = RADIOLIB_AX25_AFSK_TONE_DURATION; } int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) { - _afskMark = RADIOLIB_AX25_AFSK_MARK + mark; - _afskSpace = RADIOLIB_AX25_AFSK_SPACE + space; - _afskLen = length*(float)RADIOLIB_AX25_AFSK_TONE_DURATION; + afskMark = RADIOLIB_AX25_AFSK_MARK + mark; + afskSpace = RADIOLIB_AX25_AFSK_SPACE + space; + afskLen = length*(float)RADIOLIB_AX25_AFSK_TONE_DURATION; return(RADIOLIB_ERR_NONE); } #endif -int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preambleLen) { +int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preLen) { // set source SSID - _srcSSID = srcSSID; + sourceSSID = srcSSID; // check source callsign length (6 characters max) if(strlen(srcCallsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { @@ -185,14 +185,14 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea } // copy callsign - memcpy(_srcCallsign, srcCallsign, strlen(srcCallsign)); - _srcCallsign[strlen(srcCallsign)] = '\0'; + memcpy(sourceCallsign, srcCallsign, strlen(srcCallsign)); + sourceCallsign[strlen(srcCallsign)] = '\0'; // save preamble length - _preambleLen = preambleLen; + preambleLen = preLen; // configure for direct mode - return(_phy->startDirect()); + return(phyLayer->startDirect()); } #if defined(RADIOLIB_BUILD_ARDUINO) @@ -206,7 +206,7 @@ int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t uint8_t controlField = RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME; // build the frame - AX25Frame frame(destCallsign, destSSID, _srcCallsign, _srcSSID, controlField, RADIOLIB_AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str)); + AX25Frame frame(destCallsign, destSSID, sourceCallsign, sourceSSID, controlField, RADIOLIB_AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str)); // send Unnumbered Information frame return(sendFrame(&frame)); @@ -312,16 +312,16 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // prepare buffer for the final frame (stuffed, with added preamble + flags and NRZI-encoded) #if !defined(RADIOLIB_STATIC_ONLY) // worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags - uint8_t* stuffedFrameBuff = new uint8_t[_preambleLen + 1 + (6*frameBuffLen)/5 + 2]; + uint8_t* stuffedFrameBuff = new uint8_t[preambleLen + 1 + (6*frameBuffLen)/5 + 2]; #else uint8_t stuffedFrameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #endif // initialize buffer to all zeros - memset(stuffedFrameBuff, 0x00, _preambleLen + 1 + (6*frameBuffLen)/5 + 2); + memset(stuffedFrameBuff, 0x00, preambleLen + 1 + (6*frameBuffLen)/5 + 2); // stuff bits (skip preamble and both flags) - uint16_t stuffedFrameBuffLenBits = 8*(_preambleLen + 1); + uint16_t stuffedFrameBuffLenBits = 8*(preambleLen + 1); uint8_t count = 0; for(size_t i = 0; i < frameBuffLen + 2; i++) { for(int8_t shift = 7; shift >= 0; shift--) { @@ -359,7 +359,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { #endif // set preamble bytes and start flag field - for(uint16_t i = 0; i < _preambleLen + 1; i++) { + for(uint16_t i = 0; i < preambleLen + 1; i++) { stuffedFrameBuff[i] = RADIOLIB_AX25_FLAG; } @@ -377,7 +377,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // convert to NRZI - for(size_t i = _preambleLen + 1; i < stuffedFrameBuffLen*8; i++) { + for(size_t i = preambleLen + 1; i < stuffedFrameBuffLen*8; i++) { size_t currBitPos = i + 7 - 2*(i%8); size_t prevBitPos = (i - 1) + 7 - 2*((i - 1)%8); if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos)) { @@ -401,9 +401,9 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // transmit int16_t state = RADIOLIB_ERR_NONE; #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(_audio != nullptr) { - Module* mod = _phy->getMod(); - _phy->transmitDirect(); + if(audioClient != nullptr) { + Module* mod = phyLayer->getMod(); + phyLayer->transmitDirect(); // iterate over all bytes in the buffer for(uint32_t i = 0; i < stuffedFrameBuffLen; i++) { @@ -412,20 +412,20 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { uint32_t start = mod->hal->micros(); if(stuffedFrameBuff[i] & mask) { - _audio->tone(_afskMark, false); + audioClient->tone(afskMark, false); } else { - _audio->tone(_afskSpace, false); + audioClient->tone(afskSpace, false); } - mod->waitForMicroseconds(start, _afskLen); + mod->waitForMicroseconds(start, afskLen); } } - _audio->noTone(); + audioClient->noTone(); } else { #endif - state = _phy->transmit(stuffedFrameBuff, stuffedFrameBuffLen); + state = phyLayer->transmit(stuffedFrameBuff, stuffedFrameBuffLen); #if !defined(RADIOLIB_EXCLUDE_AFSK) } #endif @@ -439,11 +439,11 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } void AX25Client::getCallsign(char* buff) { - strncpy(buff, _srcCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + strncpy(buff, sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); } uint8_t AX25Client::getSSID() { - return(_srcSSID); + return(sourceSSID); } /* diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 608f09a78e..a769edb8d7 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -82,7 +82,6 @@ /*! \class AX25Frame - \brief Abstraction of AX.25 frame format. */ class AX25Frame { @@ -171,62 +170,41 @@ class AX25Frame { /*! \brief Overloaded constructor, for frames without info field. - \param destCallsign Callsign of the destination station. - \param destSSID SSID of the destination station. - \param srcCallsign Callsign of the source station. - \param srcSSID SSID of the source station. - \param control The control field. */ AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control); /*! \brief Overloaded constructor, for frames with C-string info field. - \param destCallsign Callsign of the destination station. - \param destSSID SSID of the destination station. - \param srcCallsign Callsign of the source station. - \param srcSSID SSID of the source station. - \param control The control field. - \param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field. - \param info Information field, in the form of null-terminated C-string. */ AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info); /*! \brief Default constructor. - \param destCallsign Callsign of the destination station. - \param destSSID SSID of the destination station. - \param srcCallsign Callsign of the source station. - \param srcSSID SSID of the source station. - \param control The control field. - \param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field. - \param info Information field, in the form of arbitrary binary buffer. - \param infoLen Number of bytes in the information field. */ AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen); /*! \brief Copy constructor. - \param frame AX25Frame instance to copy. */ AX25Frame(const AX25Frame& frame); @@ -238,34 +216,27 @@ class AX25Frame { /*! \brief Overload for assignment operator. - \param frame rvalue AX25Frame. */ AX25Frame& operator=(const AX25Frame& frame); /*! \brief Method to set the repeater callsigns and SSIDs. - \param repeaterCallsigns Array of repeater callsigns in the form of null-terminated C-strings. - \param repeaterSSIDs Array of repeater SSIDs. - \param numRepeaters Number of repeaters, maximum is 8. - \returns \ref status_codes */ int16_t setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters); /*! \brief Method to set receive sequence number. - \param seqNumber Sequence number to set, 0 to 7. */ void setRecvSequence(uint8_t seqNumber); /*! \brief Method to set send sequence number. - \param seqNumber Sequence number to set, 0 to 7. */ void setSendSequence(uint8_t seqNumber); @@ -273,14 +244,12 @@ class AX25Frame { /*! \class AX25Client - \brief Client for AX25 communication. */ class AX25Client { public: /*! \brief Constructor for 2-FSK mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. */ explicit AX25Client(PhysicalLayer* phy); @@ -288,20 +257,16 @@ class AX25Client { #if !defined(RADIOLIB_EXCLUDE_AFSK) /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. */ explicit AX25Client(AFSKClient* audio); /*! - \brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced by the setup to match the expected 1200/2200 Hz tones. - + \brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced + by the setup to match the expected 1200/2200 Hz tones. \param mark Positive or negative correction offset for mark audio frequency in Hz. - \param space Positive or negative correction offset for space audio frequency in Hz. - \param length Audio tone length modifier, defaults to 1.0. - \returns \ref status_codes */ int16_t setCorrection(int16_t mark, int16_t space, float length = 1.0f); @@ -311,27 +276,22 @@ class AX25Client { /*! \brief Initialization method. - \param srcCallsign Callsign of the source station. - - \param srcSSID 4-bit SSID of the source station (in case there are more stations with the same callsign). Defaults to 0. - - \param preambleLen Number of "preamble" bytes (RADIOLIB_AX25_FLAG) sent ahead of the actual AX.25 frame. Does not include the first RADIOLIB_AX25_FLAG byte, which is considered part of the frame. Defaults to 8. - + \param srcSSID 4-bit SSID of the source station (in case there are more stations with the same callsign). + Defaults to 0. + \param preLen Number of "preamble" bytes (RADIOLIB_AX25_FLAG) sent ahead of the actual AX.25 frame. + Does not include the first RADIOLIB_AX25_FLAG byte, which is considered part of the frame. Defaults to 8. \returns \ref status_codes */ - int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preambleLen = 8); + int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preLen = 8); #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Transmit unnumbered information (UI) frame. - \param str Data to be sent as Arduino String. - \param destCallsign Callsign of the destination station. - - \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). Defaults to 0. - + \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). + Defaults to 0. \returns \ref status_codes */ int16_t transmit(String& str, const char* destCallsign, uint8_t destSSID = 0x00); @@ -339,22 +299,17 @@ class AX25Client { /*! \brief Transmit unnumbered information (UI) frame. - \param str Data to be sent. - \param destCallsign Callsign of the destination station. - - \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). Defaults to 0. - + \param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). + Defaults to 0. \returns \ref status_codes */ int16_t transmit(const char* str, const char* destCallsign, uint8_t destSSID = 0x00); /*! \brief Transmit arbitrary AX.25 frame. - \param frame Frame to be sent. - \returns \ref status_codes */ int16_t sendFrame(AX25Frame* frame); @@ -364,17 +319,17 @@ class AX25Client { #endif friend class APRSClient; - PhysicalLayer* _phy; + PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* _audio; - uint32_t _afskMark; - uint32_t _afskSpace; - uint32_t _afskLen; + AFSKClient* audioClient; + uint32_t afskMark; + uint32_t afskSpace; + uint32_t afskLen; #endif - char _srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; - uint8_t _srcSSID = 0; - uint16_t _preambleLen = 0; + char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; + uint8_t sourceSSID = 0; + uint16_t preambleLen = 0; static uint16_t getFrameCheckSequence(uint8_t* buff, size_t len); From 668ff4fb0112d79a5b1d7ae0e3fbbd43592929ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:35:58 +0200 Subject: [PATCH 0503/1848] [APRS] Use compact Doxygen and stop using reserved format --- src/protocols/APRS/APRS.cpp | 30 ++++++++++++++--------------- src/protocols/APRS/APRS.h | 38 ++++++------------------------------- 2 files changed, 21 insertions(+), 47 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index fece55ef60..6a9db01534 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -5,17 +5,17 @@ #if !defined(RADIOLIB_EXCLUDE_APRS) APRSClient::APRSClient(AX25Client* ax) { - _ax = ax; + axClient = ax; } -int16_t APRSClient::begin(char symbol, bool alt) { - RADIOLIB_CHECK_RANGE(symbol, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL); - _symbol = symbol; +int16_t APRSClient::begin(char sym, bool alt) { + RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL); + symbol = sym; if(alt) { - _table = '\\'; + table = '\\'; } else { - _table = '/'; + table = '/'; } return(RADIOLIB_ERR_NONE); @@ -38,16 +38,16 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat // build the info field if((msg == NULL) && (time == NULL)) { // no message, no timestamp - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, _table, lon, _symbol); + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, table, lon, symbol); } else if((msg != NULL) && (time == NULL)) { // message, no timestamp - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, _table, lon, _symbol, msg); + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, table, lon, symbol, msg); } else if((msg == NULL) && (time != NULL)) { // timestamp, no message - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, _table, lon, _symbol); + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, table, lon, symbol); } else { // timestamp and message - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, _table, lon, _symbol, msg); + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg); } // send the frame @@ -170,8 +170,8 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp info[infoPos++] = speed_uni*10 + head_hun + 32; info[infoPos++] = head_ten_uni + 28; - info[infoPos++] = _symbol; - info[infoPos++] = _table; + info[infoPos++] = symbol; + info[infoPos++] = table; // onto the optional stuff - check telemetry first if(telemLen > 0) { @@ -221,13 +221,13 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) { // get AX.25 callsign char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; - _ax->getCallsign(srcCallsign); + axClient->getCallsign(srcCallsign); - AX25Frame frameUI(destCallsign, destSSID, srcCallsign, _ax->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | + AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); - return(_ax->sendFrame(&frameUI)); + return(axClient->sendFrame(&frameUI)); } #endif diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index 39f89c64da..cf1abbded6 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -60,14 +60,12 @@ /*! \class APRSClient - \brief Client for APRS communication. */ class APRSClient { public: /*! \brief Default constructor. - \param ax Pointer to the instance of AX25Client to be used for APRS. */ explicit APRSClient(AX25Client* ax); @@ -76,68 +74,44 @@ class APRSClient { /*! \brief Initialization method. - - \param symbol APRS symbol to be displayed. - + \param sym APRS symbol to be displayed. \param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table. - \returns \ref status_codes */ - int16_t begin(char symbol, bool alt = false); + int16_t begin(char sym, bool alt = false); /*! \brief Transmit position. - \param destCallsign Destination station callsign. - \param destSSID Destination station SSID. - \param lat Latitude as a null-terminated string. - \param long Longitude as a null-terminated string. - \param msg Message to be transmitted. Defaults to NULL (no message). - \param msg Position timestamp. Defaults to NULL (no timestamp). - \returns \ref status_codes */ int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL); - /* + /*! \brief Transmit position using Mic-E encoding. - \param lat Geographical latitude, positive for north, negative for south. - \param lon Geographical longitude, positive for east, negative for west. - \param heading Heading in degrees. - \param speed Speed in knots. - \param type Mic-E message type - see \ref mic_e_message_types. - \param telem Pointer to telemetry array (either 2 or 5 bytes long). NULL when telemetry is not used. - \param telemLen Telemetry length, 2 or 5. 0 when telemetry is not used. - \param grid Maidenhead grid locator. NULL when not used. - \param status Status message to send. NULL when not used. - \param alt Altitude to send. RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED when not used. */ int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem = NULL, size_t telemLen = 0, char* grid = NULL, char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED); /*! \brief Transmit generic APRS frame. - \param destCallsign Destination station callsign. - \param destSSID Destination station SSID. - \param info AX.25 info field contents. - \returns \ref status_codes */ int16_t sendFrame(char* destCallsign, uint8_t destSSID, char* info); @@ -145,11 +119,11 @@ class APRSClient { #if !defined(RADIOLIB_GODMODE) private: #endif - AX25Client* _ax; + AX25Client* axClient; // default APRS symbol (car) - char _symbol = '>'; - char _table = '/'; + char symbol = '>'; + char table = '/'; }; #endif From 255838ed44bd56612fc5f1af1430be9ca292b8fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 19:36:12 +0200 Subject: [PATCH 0504/1848] [AFSK] Use compact Doxygen and stop using reserved format --- src/protocols/AFSK/AFSK.cpp | 18 +++++++++--------- src/protocols/AFSK/AFSK.h | 13 ++----------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index 003c729db5..bbf25b3a62 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -1,12 +1,12 @@ #include "AFSK.h" #if !defined(RADIOLIB_EXCLUDE_AFSK) -AFSKClient::AFSKClient(PhysicalLayer* phy, uint32_t pin): _pin(pin) { - _phy = phy; +AFSKClient::AFSKClient(PhysicalLayer* phy, uint32_t pin): outPin(pin) { + phyLayer = phy; } int16_t AFSKClient::begin() { - return(_phy->startDirect()); + return(phyLayer->startDirect()); } int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { @@ -15,23 +15,23 @@ int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { } if(autoStart) { - int16_t state = _phy->transmitDirect(); + int16_t state = phyLayer->transmitDirect(); RADIOLIB_ASSERT(state); } - Module* mod = _phy->getMod(); - mod->hal->tone(_pin, freq); + Module* mod = phyLayer->getMod(); + mod->hal->tone(outPin, freq); return(RADIOLIB_ERR_NONE); } int16_t AFSKClient::noTone(bool keepOn) { - Module* mod = _phy->getMod(); - mod->hal->noTone(_pin); + Module* mod = phyLayer->getMod(); + mod->hal->noTone(outPin); if(keepOn) { return(0); } - return(_phy->standby()); + return(phyLayer->standby()); } #endif diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index bd125784a0..cdf6ebcab2 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -11,43 +11,34 @@ /*! \class AFSKClient - \brief Client for audio-based transmissions. Requires Arduino tone() function, and a module capable of direct mode transmission using DIO pins. */ class AFSKClient { public: /*! \brief Default contructor. - \param phy Pointer to the wireless module providing PhysicalLayer communication. - \param pin The pin that will be used for audio output. */ AFSKClient(PhysicalLayer* phy, uint32_t pin); /*! \brief Initialization method. - \returns \ref status_codes */ int16_t begin(); /*! \brief Start transmitting audio tone. - \param freq Frequency of the tone in Hz. - \param autoStart Whether to automatically enter transmission mode. Defaults to true. - \returns \ref status_codes */ int16_t tone(uint16_t freq, bool autoStart = true); /*! \brief Stops transmitting audio tone. - \param freq Keep transmitter on - this may limit noise when switching transmitter on or off. - \returns \ref status_codes */ int16_t noTone(bool keepOn = false); @@ -55,8 +46,8 @@ class AFSKClient { #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* _phy; - uint32_t _pin; + PhysicalLayer* phyLayer; + uint32_t outPin; // allow specific classes access the private PhysicalLayer pointer friend class RTTYClient; From 61f6da0cb2a41e88bc13494c67a4ef01f6ed546c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 20:19:36 +0200 Subject: [PATCH 0505/1848] [MOD] Added missing stdarg include for some platforms --- src/Module.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index db3b56f20d..17e09480b3 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -5,8 +5,14 @@ #include #include +#if defined(RADIOLIB_DEBUG) +// needed for debug print +#include +#endif + #if defined(RADIOLIB_BUILD_ARDUINO) #include "ArduinoHal.h" + Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { this->hal = new ArduinoHal(); } From 767a2b006a0349c683624b33d3be3e8a9d5330c3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 22 Apr 2023 20:37:42 +0200 Subject: [PATCH 0506/1848] [Pager] Fixed deprecation warning for ESP --- src/protocols/Pager/Pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 2ed9c5c319..04b906ab62 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -10,7 +10,7 @@ static PhysicalLayer* readBitInstance = NULL; static uint32_t readBitPin = RADIOLIB_NC; #if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR + IRAM_ATTR #endif static void PagerClientReadBit(void) { if(readBitInstance) { From 78a576df12b3ffdd1b54a570a8c12d23d2a31f27 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 09:12:47 +0200 Subject: [PATCH 0507/1848] [PHY] Use compact Doxygen and stop using reserved format --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 70 +++++++++---------- src/protocols/PhysicalLayer/PhysicalLayer.h | 28 ++++---- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index eeabf806a7..dce1e13318 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -1,12 +1,12 @@ #include "PhysicalLayer.h" #include -PhysicalLayer::PhysicalLayer(float freqStep, size_t maxPacketLength) { - _freqStep = freqStep; - _maxPacketLength = maxPacketLength; +PhysicalLayer::PhysicalLayer(float step, size_t maxLen) { + this->freqStep = step; + this->maxPacketLength = maxLen; #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) - _bufferBitPos = 0; - _bufferWritePos = 0; + this->bufferBitPos = 0; + this->bufferWritePos = 0; #endif } @@ -73,7 +73,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { #else uint8_t* data = NULL; if(length == 0) { - data = new uint8_t[_maxPacketLength + 1]; + data = new uint8_t[this->maxPacketLength + 1]; } else { data = new uint8_t[length + 1]; } @@ -243,7 +243,7 @@ int16_t PhysicalLayer::setEncoding(uint8_t encoding) { } float PhysicalLayer::getFreqStep() const { - return(_freqStep); + return(this->freqStep); } size_t PhysicalLayer::getPacketLength(bool update) { @@ -307,13 +307,13 @@ int16_t PhysicalLayer::startDirect() { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) int16_t PhysicalLayer::available() { - return(_bufferWritePos); + return(this->bufferWritePos); } void PhysicalLayer::dropSync() { - if(_directSyncWordLen > 0) { - _gotSync = false; - _syncBuffer = 0; + if(this->directSyncWordLen > 0) { + this->gotSync = false; + this->syncBuffer = 0; } } @@ -321,21 +321,21 @@ uint8_t PhysicalLayer::read(bool drop) { if(drop) { dropSync(); } - _bufferWritePos--; - return(_buffer[_bufferReadPos++]); + this->bufferWritePos--; + return(this->buffer[this->bufferReadPos++]); } int16_t PhysicalLayer::setDirectSyncWord(uint32_t syncWord, uint8_t len) { if(len > 32) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } - _directSyncWordMask = 0xFFFFFFFF >> (32 - len); - _directSyncWordLen = len; - _directSyncWord = syncWord; + this->directSyncWordMask = 0xFFFFFFFF >> (32 - len); + this->directSyncWordLen = len; + this->directSyncWord = syncWord; // override sync word matching when length is set to 0 - if(_directSyncWordLen == 0) { - _gotSync = true; + if(this->directSyncWordLen == 0) { + this->gotSync = true; } return(RADIOLIB_ERR_NONE); @@ -343,35 +343,35 @@ int16_t PhysicalLayer::setDirectSyncWord(uint32_t syncWord, uint8_t len) { void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check sync word - if(!_gotSync) { - _syncBuffer <<= 1; - _syncBuffer |= bit; + if(!this->gotSync) { + this->syncBuffer <<= 1; + this->syncBuffer |= bit; - RADIOLIB_VERBOSE_PRINTLN("S\t%X", _syncBuffer); + RADIOLIB_VERBOSE_PRINTLN("S\t%X", this->syncBuffer); - if((_syncBuffer & _directSyncWordMask) == _directSyncWord) { - _gotSync = true; - _bufferWritePos = 0; - _bufferReadPos = 0; - _bufferBitPos = 0; + if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) { + this->gotSync = true; + this->bufferWritePos = 0; + this->bufferReadPos = 0; + this->bufferBitPos = 0; } } else { // save the bit if(bit) { - _buffer[_bufferWritePos] |= 0x01 << _bufferBitPos; + this->buffer[this->bufferWritePos] |= 0x01 << this->bufferBitPos; } else { - _buffer[_bufferWritePos] &= ~(0x01 << _bufferBitPos); + this->buffer[this->bufferWritePos] &= ~(0x01 << this->bufferBitPos); } - _bufferBitPos++; + this->bufferBitPos++; // check complete byte - if(_bufferBitPos == 8) { - _buffer[_bufferWritePos] = Module::flipBits(_buffer[_bufferWritePos]); - RADIOLIB_VERBOSE_PRINTLN("R\t%X", _buffer[_bufferWritePos]); + if(this->bufferBitPos == 8) { + this->buffer[this->bufferWritePos] = Module::flipBits(this->buffer[this->bufferWritePos]); + RADIOLIB_VERBOSE_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); - _bufferWritePos++; - _bufferBitPos = 0; + this->bufferWritePos++; + this->bufferBitPos = 0; } } } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index a7a457c629..9da9c78d3d 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -19,10 +19,10 @@ class PhysicalLayer { /*! \brief Default constructor. - \param freqStep Frequency step of the synthesizer in Hz. - \param maxPacketLength Maximum length of packet that can be received by the module. + \param step Frequency step of the synthesizer in Hz. + \param maxLen Maximum length of packet that can be received by the module. */ - PhysicalLayer(float freqStep, size_t maxPacketLength); + PhysicalLayer(float step, size_t maxLen); // basic methods @@ -356,19 +356,19 @@ class PhysicalLayer { #if !defined(RADIOLIB_GODMODE) private: #endif - float _freqStep; - size_t _maxPacketLength; + float freqStep; + size_t maxPacketLength; #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) - uint8_t _bufferBitPos; - uint8_t _bufferWritePos; - uint8_t _bufferReadPos; - uint8_t _buffer[RADIOLIB_STATIC_ARRAY_SIZE]; - uint32_t _syncBuffer; - uint32_t _directSyncWord; - uint8_t _directSyncWordLen; - uint32_t _directSyncWordMask; - bool _gotSync; + uint8_t bufferBitPos; + uint8_t bufferWritePos; + uint8_t bufferReadPos; + uint8_t buffer[RADIOLIB_STATIC_ARRAY_SIZE]; + uint32_t syncBuffer; + uint32_t directSyncWord; + uint8_t directSyncWordLen; + uint32_t directSyncWordMask; + bool gotSync; #endif virtual Module* getMod() = 0; From 5c6628b6ebb1dc9478090d20199087803212ce8d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 09:47:42 +0200 Subject: [PATCH 0508/1848] [CC1101] General reformatting --- src/modules/CC1101/CC1101.cpp | 292 ++++---- src/modules/CC1101/CC1101.h | 1169 +++++++++++++++------------------ 2 files changed, 713 insertions(+), 748 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 433e1f3b8b..208b47f88a 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -3,19 +3,19 @@ #if !defined(RADIOLIB_EXCLUDE_CC1101) CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) { - _mod = module; + this->mod = module; } Module* CC1101::getMod() { - return(_mod); + return(this->mod); } int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLength) { // set module properties - _mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; - _mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; + this->mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); // try to find the CC1101 chip uint8_t i = 0; @@ -26,14 +26,14 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); - _mod->hal->delay(10); + this->mod->hal->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN("No CC1101 found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { RADIOLIB_DEBUG_PRINTLN("M\tCC1101"); @@ -68,7 +68,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // configure default preamble length - state = setPreambleLength(preambleLength); + state = setPreambleLength(preambleLength, preambleLength - 4); RADIOLIB_ASSERT(state); // set default data shaping @@ -85,37 +85,48 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // flush FIFOs - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); return(state); } +void CC1101::reset() { + // this is the manual power-on-reset sequence + this->mod->hal->digitalWrite(this->mod->getCs(), LOW); + this->mod->hal->delayMicroseconds(5); + this->mod->hal->digitalWrite(this->mod->getCs(), HIGH); + this->mod->hal->delayMicroseconds(40); + this->mod->hal->digitalWrite(this->mod->getCs(), LOW); + this->mod->hal->delay(10); + SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); +} + int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission start or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getGpio())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } // wait for transmission end or timeout - start = _mod->hal->micros(); - while(_mod->hal->digitalRead(_mod->getGpio())) { - _mod->hal->yield(); + start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -126,18 +137,18 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t CC1101::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full max-length packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { standby(); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -153,7 +164,7 @@ int16_t CC1101::standby() { SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); return(RADIOLIB_ERR_NONE); } @@ -172,7 +183,7 @@ int16_t CC1101::transmitDirectAsync(uint32_t frf) { int16_t CC1101::transmitDirect(bool sync, uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { @@ -202,7 +213,7 @@ int16_t CC1101::receiveDirectAsync() { int16_t CC1101::receiveDirect(bool sync) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(sync); @@ -216,31 +227,33 @@ int16_t CC1101::receiveDirect(bool sync) { int16_t CC1101::packetMode() { int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF | RADIOLIB_CC1101_APPEND_STATUS_ON | RADIOLIB_CC1101_ADR_CHK_NONE, 3, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF | RADIOLIB_CC1101_PKT_FORMAT_NORMAL, 6, 4); - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON | _packetLengthConfig, 2, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON | this->packetLengthConfig, 2, 0); return(state); } void CC1101::setGdo0Action(void (*func)(void), uint32_t dir) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, dir); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir); } void CC1101::clearGdo0Action() { - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + } void CC1101::setGdo2Action(void (*func)(void), uint32_t dir) { - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, dir); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir); } void CC1101::clearGdo2Action() { - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); } int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -256,16 +269,16 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); // set GDO0 mapping - int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED, 5, 0); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); RADIOLIB_ASSERT(state); - // data put on FIFO. + // data put on FIFO uint8_t dataSent = 0; // optionally write packet length - if (_packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { - // enforce variable len limit. + // enforce variable len limit if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { return (RADIOLIB_ERR_PACKET_TOO_LONG); } @@ -281,36 +294,37 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { dataSent += 1; } - // fill the FIFO. + // fill the FIFO uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); dataSent += initialWrite; // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // set mode to transmit SPIsendCommand(RADIOLIB_CC1101_CMD_TX); - // keep feeding the FIFO until the packet is over. + + // keep feeding the FIFO until the packet is over while (dataSent < len) { - // get number of bytes in FIFO. + // get number of bytes in FIFO uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); - // if there's room then put other data. + // if there's room then put other data if (bytesInFIFO < RADIOLIB_CC1101_FIFO_SIZE) { uint8_t bytesToWrite = min((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, &data[dataSent], bytesToWrite); dataSent += bytesToWrite; } else { - // wait for radio to send some data. + // wait for radio to send some data /* * Does this work for all rates? If 1 ms is longer than the 1ms delay * then the entire FIFO will be transmitted during that delay. * * TODO: test this on real hardware */ - _mod->hal->delayMicroseconds(250); + this->mod->hal->delayMicroseconds(250); } } @@ -320,6 +334,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t CC1101::finishTransmit() { // set mode to standby to disable transmitter/RF switch int16_t state = standby(); + RADIOLIB_ASSERT(state); // flush Tx FIFO SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); @@ -329,18 +344,19 @@ int16_t CC1101::finishTransmit() { int16_t CC1101::startReceive() { // set mode to standby - standby(); + int16_t state = standby(); + RADIOLIB_ASSERT(state); // flush Rx FIFO SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); // set GDO0 mapping: Asserted when RX FIFO > 4 bytes. - int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4, 3, 0); RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to receive SPIsendCommand(RADIOLIB_CC1101_CMD_RX); @@ -372,17 +388,17 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); size_t readBytes = 0; - uint32_t lastPop = _mod->hal->millis(); + uint32_t lastPop = this->mod->hal->millis(); // keep reading from FIFO until we get all the packet. while (readBytes < length) { if (bytesInFIFO == 0) { - if (_mod->hal->millis() - lastPop > 5) { + if (this->mod->hal->millis() - lastPop > 5) { // readData was required to read a packet longer than the one received. RADIOLIB_DEBUG_PRINTLN("No data for more than 5mS. Stop here."); break; } else { - _mod->hal->delay(1); + this->mod->hal->delay(1); bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); continue; } @@ -392,7 +408,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { uint8_t bytesToRead = min((uint8_t)(length - readBytes), bytesInFIFO); SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, bytesToRead, &(data[readBytes])); readBytes += bytesToRead; - lastPop = _mod->hal->millis(); + lastPop = this->mod->hal->millis(); // Get how many bytes are left in FIFO. bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); @@ -402,26 +418,26 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; // for some reason, we need this delay here to get the correct status bytes - _mod->hal->delay(3); + this->mod->hal->delay(3); // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. if (isAppendStatus) { // read RSSI byte - _rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); + this->rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); // read LQI and CRC byte uint8_t val = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); - _rawLQI = val & 0x7F; + this->rawLQI = val & 0x7F; // check CRC - if (_crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { - _packetLengthQueried = false; + if (this->crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { + this->packetLengthQueried = false; return (RADIOLIB_ERR_CRC_MISMATCH); } } // clear internal flag so getPacketLength can return the new packet length - _packetLengthQueried = false; + this->packetLengthQueried = false; // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { @@ -455,11 +471,11 @@ int16_t CC1101::setFrequency(float freq) { state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); if(state == RADIOLIB_ERR_NONE) { - _freq = freq; + this->freq = freq; } // Update the TX power accordingly to new freq. (PA values depend on chosen freq) - return(setOutputPower(_power)); + return(setOutputPower(this->power)); } int16_t CC1101::setBitRate(float br) { @@ -477,7 +493,7 @@ int16_t CC1101::setBitRate(float br) { int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG3, m); if(state == RADIOLIB_ERR_NONE) { - _br = br; + this->bitRate = br; } return(state); } @@ -536,7 +552,7 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { } // if ASK/OOK, deviation makes no sense - if (_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { + if (this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) { *freqDev = 0.0; return(RADIOLIB_ERR_NONE); @@ -558,13 +574,13 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { int16_t CC1101::setOutputPower(int8_t power) { // round to the known frequency settings uint8_t f; - if(_freq < 374.0) { + if(this->freq < 374.0) { // 315 MHz f = 0; - } else if(_freq < 650.5) { + } else if(this->freq < 650.5) { // 434 MHz f = 1; - } else if(_freq < 891.5) { + } else if(this->freq < 891.5) { // 868 MHz f = 2; } else { @@ -613,9 +629,9 @@ int16_t CC1101::setOutputPower(int8_t power) { } // store the value - _power = power; + this->power = power; - if(_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ + if(this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ // Amplitude modulation: // PA_TABLE[0] is the power to be used when transmitting a 0 (no power) // PA_TABLE[1] is the power to be used when transmitting a 1 (full power) @@ -659,10 +675,10 @@ int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bo return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits, requireCarrierSense)); } -int16_t CC1101::setPreambleLength(uint8_t preambleLength) { +int16_t CC1101::setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold) { // check allowed values uint8_t value; - switch(preambleLength){ + switch(preambleLength) { case 16: value = RADIOLIB_CC1101_NUM_PREAMBLE_2; break; @@ -691,7 +707,14 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) { return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } - return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4)); + // set preabmble quality threshold and the actual length + uint8_t pqt = qualityThreshold/4; + if(pqt > 7) { + pqt = 7; + } + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, pqt << 5, 7, 5); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4); + return(state); } int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { @@ -727,7 +750,7 @@ int16_t CC1101::setOOK(bool enableOOK) { RADIOLIB_ASSERT(state); // update current modulation - _modulation = RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK; + this->modulation = RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK; } else { int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4); RADIOLIB_ASSERT(state); @@ -737,21 +760,21 @@ int16_t CC1101::setOOK(bool enableOOK) { RADIOLIB_ASSERT(state); // update current modulation - _modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; + this->modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; } - // Update PA_TABLE values according to the new _modulation. - return(setOutputPower(_power)); + // Update PA_TABLE values according to the new this->modulation. + return(setOutputPower(this->power)); } float CC1101::getRSSI() { float rssi; - if (_directMode) { - if(_rawRSSI >= 128) { - rssi = (((float)_rawRSSI - 256.0)/2.0) - 74.0; + if (this->directModeEnabled) { + if(this->rawRSSI >= 128) { + rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0; } else { - rssi = (((float)_rawRSSI)/2.0) - 74.0; + rssi = (((float)this->rawRSSI)/2.0) - 74.0; } } else { uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI); @@ -768,21 +791,25 @@ float CC1101::getRSSI() { } uint8_t CC1101::getLQI() const { - return(_rawLQI); + return(this->rawLQI); } size_t CC1101::getPacketLength(bool update) { - if(!_packetLengthQueried && update) { - if (_packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { - _packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + this->packetLength = 0; + while(this->packetLength == 0) { + this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); + } + } else { - _packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN); + this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN); } - _packetLengthQueried = true; + this->packetLengthQueried = true; } - return(_packetLength); + return(this->packetLength); } int16_t CC1101::fixedPacketLengthMode(uint8_t len) { @@ -794,20 +821,27 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) { } int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) { - switch(maxErrBits){ + int16_t state = RADIOLIB_ERR_NONE; + + switch(maxErrBits) { case 0: // in 16 bit sync word, expect all 16 bits - return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_16_16_THR : RADIOLIB_CC1101_SYNC_MODE_16_16), 2, 0)); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_16_16_THR : RADIOLIB_CC1101_SYNC_MODE_16_16), 2, 0); + break; case 1: // in 16 bit sync word, expect at least 15 bits - return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_15_16_THR : RADIOLIB_CC1101_SYNC_MODE_15_16), 2, 0)); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_15_16_THR : RADIOLIB_CC1101_SYNC_MODE_15_16), 2, 0); + break; default: - return(RADIOLIB_ERR_INVALID_SYNC_WORD); + state = RADIOLIB_ERR_INVALID_SYNC_WORD; + break; } + return(state); } int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) { - return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_NONE_THR : RADIOLIB_CC1101_SYNC_MODE_NONE), 2, 0)); + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_NONE_THR : RADIOLIB_CC1101_SYNC_MODE_NONE), 2, 0); + return(state); } int16_t CC1101::setCrcFiltering(bool crcOn) { @@ -820,14 +854,14 @@ int16_t CC1101::setCrcFiltering(bool crcOn) { } } -int16_t CC1101::setPromiscuousMode(bool promiscuous) { +int16_t CC1101::setPromiscuousMode(bool enable) { int16_t state = RADIOLIB_ERR_NONE; - if (_promiscuous == promiscuous) { + if(this->promiscuous == enable) { return(state); } - if (promiscuous == true) { + if(enable) { // disable sync word filtering and insertion // this also disables preamble state = disableSyncWordFiltering(); @@ -836,7 +870,7 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) { // disable CRC filtering state = setCrcFiltering(false); } else { - state = setPreambleLength(RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); + state = setPreambleLength(RADIOLIB_CC1101_DEFAULT_PREAMBLELEN, RADIOLIB_CC1101_DEFAULT_PREAMBLELEN/4); RADIOLIB_ASSERT(state); // enable sync word filtering and insertion @@ -847,13 +881,13 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) { state = setCrcFiltering(true); } - _promiscuous = promiscuous; + this->promiscuous = enable; return(state); } bool CC1101::getPromiscuousMode() { - return (_promiscuous); + return (this->promiscuous); } int16_t CC1101::setDataShaping(uint8_t sh) { @@ -900,11 +934,11 @@ int16_t CC1101::setEncoding(uint8_t encoding) { } void CC1101::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - _mod->setRfSwitchPins(rxEn, txEn); + this->mod->setRfSwitchPins(rxEn, txEn); } void CC1101::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - _mod->setRfSwitchTable(pins, table); + this->mod->setRfSwitchTable(pins, table); } uint8_t CC1101::randomByte() { @@ -913,7 +947,7 @@ uint8_t CC1101::randomByte() { RADIOLIB_DEBUG_PRINTLN("CC1101::randomByte"); // wait a bit for the RSSI reading to stabilise - _mod->hal->delay(10); + this->mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -933,30 +967,39 @@ int16_t CC1101::getChipVersion() { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void CC1101::setDirectAction(void (*func)(void)) { - setGdo0Action(func, _mod->hal->GpioInterruptRising); + setGdo0Action(func, this->mod->hal->GpioInterruptRising); } void CC1101::readBit(uint32_t pin) { - updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); } #endif int16_t CC1101::setDIOMapping(uint32_t pin, uint32_t value) { - if (pin > 2) - return RADIOLIB_ERR_INVALID_DIO_PIN; + if(pin > 2) { + return(RADIOLIB_ERR_INVALID_DIO_PIN); + } return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0 - pin, value)); } int16_t CC1101::config() { // Reset the radio. Registers may be dirty from previous usage. - SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); + reset(); // Wait a ridiculous amount of time to be sure radio is ready. - _mod->hal->delay(150); + this->mod->hal->delay(150); + + standby(); - // enable automatic frequency synthesizer calibration + // enable automatic frequency synthesizer calibration and disable pin control int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_PIN_CTRL_OFF, 1, 1); + RADIOLIB_ASSERT(state); + + // set GDOs to Hi-Z so that it doesn't output clock on startup (might confuse GDO0 action) + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0); RADIOLIB_ASSERT(state); // set packet mode @@ -970,16 +1013,15 @@ int16_t CC1101::directMode(bool sync) { SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); int16_t state = 0; - _directMode = sync; - if (sync) { + this->directModeEnabled = sync; + if(sync) { // set GDO0 and GDO2 mapping state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); // set continuous mode state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); - } - else { + } else { // set GDO0 mapping state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0); @@ -1032,8 +1074,8 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { RADIOLIB_ASSERT(state); // update the cached value - _packetLength = len; - _packetLengthConfig = mode; + this->packetLength = len; + this->packetLengthConfig = mode; return(state); } @@ -1043,7 +1085,7 @@ int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } - return(_mod->SPIgetRegValue(reg, msb, lsb)); + return(this->mod->SPIgetRegValue(reg, msb, lsb)); } int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval) { @@ -1052,11 +1094,11 @@ int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } - return(_mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval)); + return(this->mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval)); } void CC1101::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) { - _mod->SPIreadRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, numBytes, inBytes); + this->mod->SPIreadRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, numBytes, inBytes); } uint8_t CC1101::SPIreadRegister(uint8_t reg) { @@ -1065,7 +1107,7 @@ uint8_t CC1101::SPIreadRegister(uint8_t reg) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } - return(_mod->SPIreadRegister(reg)); + return(this->mod->SPIreadRegister(reg)); } void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) { @@ -1074,26 +1116,28 @@ void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } - return(_mod->SPIwriteRegister(reg, data)); + return(this->mod->SPIwriteRegister(reg, data)); } void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { - _mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len); + this->mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len); } void CC1101::SPIsendCommand(uint8_t cmd) { // pull NSS low - _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelLow); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); // start transfer - _mod->hal->spiBeginTransaction(); + this->mod->hal->spiBeginTransaction(); // send the command byte - _mod->hal->spiTransfer(cmd); + uint8_t status = this->mod->hal->spiTransfer(cmd); // stop transfer - _mod->hal->spiEndTransaction(); - _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelHigh); + this->mod->hal->spiEndTransaction(); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + RADIOLIB_VERBOSE_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); + (void)status; } #endif diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 28643edcd6..1080ce1978 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -7,511 +7,525 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // CC1101 physical layer properties -#define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 -#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 255 -#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 -#define RADIOLIB_CC1101_DIV_EXPONENT 16 -#define RADIOLIB_CC1101_FIFO_SIZE 64 +#define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 +#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 255 +#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 +#define RADIOLIB_CC1101_DIV_EXPONENT 16 +#define RADIOLIB_CC1101_FIFO_SIZE 64 // CC1101 SPI commands -#define RADIOLIB_CC1101_CMD_READ 0b10000000 -#define RADIOLIB_CC1101_CMD_WRITE 0b00000000 -#define RADIOLIB_CC1101_CMD_BURST 0b01000000 -#define RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG 0b01000000 -#define RADIOLIB_CC1101_CMD_FIFO_RX 0b10000000 -#define RADIOLIB_CC1101_CMD_FIFO_TX 0b00000000 -#define RADIOLIB_CC1101_CMD_RESET 0x30 -#define RADIOLIB_CC1101_CMD_FSTXON 0x31 -#define RADIOLIB_CC1101_CMD_XOFF 0x32 -#define RADIOLIB_CC1101_CMD_CAL 0x33 -#define RADIOLIB_CC1101_CMD_RX 0x34 -#define RADIOLIB_CC1101_CMD_TX 0x35 -#define RADIOLIB_CC1101_CMD_IDLE 0x36 -#define RADIOLIB_CC1101_CMD_WOR 0x38 -#define RADIOLIB_CC1101_CMD_POWER_DOWN 0x39 -#define RADIOLIB_CC1101_CMD_FLUSH_RX 0x3A -#define RADIOLIB_CC1101_CMD_FLUSH_TX 0x3B -#define RADIOLIB_CC1101_CMD_WOR_RESET 0x3C -#define RADIOLIB_CC1101_CMD_NOP 0x3D +#define RADIOLIB_CC1101_CMD_READ 0b10000000 +#define RADIOLIB_CC1101_CMD_WRITE 0b00000000 +#define RADIOLIB_CC1101_CMD_BURST 0b01000000 +#define RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG 0b01000000 +#define RADIOLIB_CC1101_CMD_FIFO_RX 0b10000000 +#define RADIOLIB_CC1101_CMD_FIFO_TX 0b00000000 +#define RADIOLIB_CC1101_CMD_RESET 0x30 +#define RADIOLIB_CC1101_CMD_FSTXON 0x31 +#define RADIOLIB_CC1101_CMD_XOFF 0x32 +#define RADIOLIB_CC1101_CMD_CAL 0x33 +#define RADIOLIB_CC1101_CMD_RX 0x34 +#define RADIOLIB_CC1101_CMD_TX 0x35 +#define RADIOLIB_CC1101_CMD_IDLE 0x36 +#define RADIOLIB_CC1101_CMD_WOR 0x38 +#define RADIOLIB_CC1101_CMD_POWER_DOWN 0x39 +#define RADIOLIB_CC1101_CMD_FLUSH_RX 0x3A +#define RADIOLIB_CC1101_CMD_FLUSH_TX 0x3B +#define RADIOLIB_CC1101_CMD_WOR_RESET 0x3C +#define RADIOLIB_CC1101_CMD_NOP 0x3D // CC1101 register map -#define RADIOLIB_CC1101_REG_IOCFG2 0x00 -#define RADIOLIB_CC1101_REG_IOCFG1 0x01 -#define RADIOLIB_CC1101_REG_IOCFG0 0x02 -#define RADIOLIB_CC1101_REG_FIFOTHR 0x03 -#define RADIOLIB_CC1101_REG_SYNC1 0x04 -#define RADIOLIB_CC1101_REG_SYNC0 0x05 -#define RADIOLIB_CC1101_REG_PKTLEN 0x06 -#define RADIOLIB_CC1101_REG_PKTCTRL1 0x07 -#define RADIOLIB_CC1101_REG_PKTCTRL0 0x08 -#define RADIOLIB_CC1101_REG_ADDR 0x09 -#define RADIOLIB_CC1101_REG_CHANNR 0x0A -#define RADIOLIB_CC1101_REG_FSCTRL1 0x0B -#define RADIOLIB_CC1101_REG_FSCTRL0 0x0C -#define RADIOLIB_CC1101_REG_FREQ2 0x0D -#define RADIOLIB_CC1101_REG_FREQ1 0x0E -#define RADIOLIB_CC1101_REG_FREQ0 0x0F -#define RADIOLIB_CC1101_REG_MDMCFG4 0x10 -#define RADIOLIB_CC1101_REG_MDMCFG3 0x11 -#define RADIOLIB_CC1101_REG_MDMCFG2 0x12 -#define RADIOLIB_CC1101_REG_MDMCFG1 0x13 -#define RADIOLIB_CC1101_REG_MDMCFG0 0x14 -#define RADIOLIB_CC1101_REG_DEVIATN 0x15 -#define RADIOLIB_CC1101_REG_MCSM2 0x16 -#define RADIOLIB_CC1101_REG_MCSM1 0x17 -#define RADIOLIB_CC1101_REG_MCSM0 0x18 -#define RADIOLIB_CC1101_REG_FOCCFG 0x19 -#define RADIOLIB_CC1101_REG_BSCFG 0x1A -#define RADIOLIB_CC1101_REG_AGCCTRL2 0x1B -#define RADIOLIB_CC1101_REG_AGCCTRL1 0x1C -#define RADIOLIB_CC1101_REG_AGCCTRL0 0x1D -#define RADIOLIB_CC1101_REG_WOREVT1 0x1E -#define RADIOLIB_CC1101_REG_WOREVT0 0x1F -#define RADIOLIB_CC1101_REG_WORCTRL 0x20 -#define RADIOLIB_CC1101_REG_FREND1 0x21 -#define RADIOLIB_CC1101_REG_FREND0 0x22 -#define RADIOLIB_CC1101_REG_FSCAL3 0x23 -#define RADIOLIB_CC1101_REG_FSCAL2 0x24 -#define RADIOLIB_CC1101_REG_FSCAL1 0x25 -#define RADIOLIB_CC1101_REG_FSCAL0 0x26 -#define RADIOLIB_CC1101_REG_RCCTRL1 0x27 -#define RADIOLIB_CC1101_REG_RCCTRL0 0x28 -#define RADIOLIB_CC1101_REG_FSTEST 0x29 -#define RADIOLIB_CC1101_REG_PTEST 0x2A -#define RADIOLIB_CC1101_REG_AGCTEST 0x2B -#define RADIOLIB_CC1101_REG_TEST2 0x2C -#define RADIOLIB_CC1101_REG_TEST1 0x2D -#define RADIOLIB_CC1101_REG_TEST0 0x2E -#define RADIOLIB_CC1101_REG_PARTNUM 0x30 -#define RADIOLIB_CC1101_REG_VERSION 0x31 -#define RADIOLIB_CC1101_REG_FREQEST 0x32 -#define RADIOLIB_CC1101_REG_LQI 0x33 -#define RADIOLIB_CC1101_REG_RSSI 0x34 -#define RADIOLIB_CC1101_REG_MARCSTATE 0x35 -#define RADIOLIB_CC1101_REG_WORTIME1 0x36 -#define RADIOLIB_CC1101_REG_WORTIME0 0x37 -#define RADIOLIB_CC1101_REG_PKTSTATUS 0x38 -#define RADIOLIB_CC1101_REG_VCO_VC_DAC 0x39 -#define RADIOLIB_CC1101_REG_TXBYTES 0x3A -#define RADIOLIB_CC1101_REG_RXBYTES 0x3B -#define RADIOLIB_CC1101_REG_RCCTRL1_STATUS 0x3C -#define RADIOLIB_CC1101_REG_RCCTRL0_STATUS 0x3D -#define RADIOLIB_CC1101_REG_PATABLE 0x3E -#define RADIOLIB_CC1101_REG_FIFO 0x3F - -// CC1101_REG_IOCFG2 MSB LSB DESCRIPTION -#define RADIOLIB_CC1101_GDO2_NORM 0b00000000 // 6 6 GDO2 output: active high (default) -#define RADIOLIB_CC1101_GDO2_INV 0b01000000 // 6 6 active low - -// CC1101_REG_IOCFG1 -#define RADIOLIB_CC1101_GDO1_DS_LOW 0b00000000 // 7 7 GDO1 output drive strength: low (default) -#define RADIOLIB_CC1101_GDO1_DS_HIGH 0b10000000 // 7 7 high -#define RADIOLIB_CC1101_GDO1_NORM 0b00000000 // 6 6 GDO1 output: active high (default) -#define RADIOLIB_CC1101_GDO1_INV 0b01000000 // 6 6 active low - -// CC1101_REG_IOCFG0 -#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_OFF 0b00000000 // 7 7 analog temperature sensor output: disabled (default) -#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 7 enabled -#define RADIOLIB_CC1101_GDO0_NORM 0b00000000 // 6 6 GDO0 output: active high (default) -#define RADIOLIB_CC1101_GDO0_INV 0b01000000 // 6 6 active low - -// CC1101_REG_IOCFG2 + REG_IOCFG1 + REG_IOCFG0 -#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL 0x00 // 5 0 Rx FIFO full or above threshold -#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END 0x01 // 5 0 Rx FIFO full or above threshold or reached packet end -#define RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR 0x02 // 5 0 Tx FIFO above threshold -#define RADIOLIB_CC1101_GDOX_TX_FIFO_FULL 0x03 // 5 0 Tx FIFO full -#define RADIOLIB_CC1101_GDOX_RX_FIFO_OVERFLOW 0x04 // 5 0 Rx FIFO overflowed -#define RADIOLIB_CC1101_GDOX_TX_FIFO_UNDERFLOW 0x05 // 5 0 Tx FIFO underflowed -#define RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED 0x06 // 5 0 sync word was sent or received -#define RADIOLIB_CC1101_GDOX_PKT_RECEIVED_CRC_OK 0x07 // 5 0 packet received and CRC check passed -#define RADIOLIB_CC1101_GDOX_PREAMBLE_QUALITY_REACHED 0x08 // 5 0 received preamble quality is above threshold -#define RADIOLIB_CC1101_GDOX_CHANNEL_CLEAR 0x09 // 5 0 RSSI level below threshold (channel is clear) -#define RADIOLIB_CC1101_GDOX_PLL_LOCKED 0x0A // 5 0 PLL is locked -#define RADIOLIB_CC1101_GDOX_SERIAL_CLOCK 0x0B // 5 0 serial data clock -#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC 0x0C // 5 0 serial data output in: synchronous mode -#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC 0x0D // 5 0 asynchronous mode -#define RADIOLIB_CC1101_GDOX_CARRIER_SENSE 0x0E // 5 0 RSSI above threshold -#define RADIOLIB_CC1101_GDOX_CRC_OK 0x0F // 5 0 CRC check passed -#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA1 0x16 // 5 0 direct access to demodulated data -#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA0 0x17 // 5 0 direct access to demodulated data -#define RADIOLIB_CC1101_GDOX_PA_PD 0x1B // 5 0 power amplifier circuit is powered down -#define RADIOLIB_CC1101_GDOX_LNA_PD 0x1C // 5 0 low-noise amplifier circuit is powered down -#define RADIOLIB_CC1101_GDOX_RX_SYMBOL_TICK 0x1D // 5 0 direct access to symbol tick of received data -#define RADIOLIB_CC1101_GDOX_WOR_EVNT0 0x24 // 5 0 wake-on-radio event 0 -#define RADIOLIB_CC1101_GDOX_WOR_EVNT1 0x25 // 5 0 wake-on-radio event 1 -#define RADIOLIB_CC1101_GDOX_CLK_256 0x26 // 5 0 256 Hz clock -#define RADIOLIB_CC1101_GDOX_CLK_32K 0x27 // 5 0 32 kHz clock -#define RADIOLIB_CC1101_GDOX_CHIP_RDYN 0x29 // 5 0 (default for GDO2) -#define RADIOLIB_CC1101_GDOX_XOSC_STABLE 0x2B // 5 0 -#define RADIOLIB_CC1101_GDOX_HIGH_Z 0x2E // 5 0 high impedance state (default for GDO1) -#define RADIOLIB_CC1101_GDOX_HW_TO_0 0x2F // 5 0 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1 0x30 // 5 0 crystal oscillator clock: f = f(XOSC)/1 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1_5 0x31 // 5 0 f = f(XOSC)/1.5 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_2 0x32 // 5 0 f = f(XOSC)/2 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_3 0x33 // 5 0 f = f(XOSC)/3 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_4 0x34 // 5 0 f = f(XOSC)/4 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_6 0x35 // 5 0 f = f(XOSC)/6 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_8 0x36 // 5 0 f = f(XOSC)/8 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_12 0x37 // 5 0 f = f(XOSC)/12 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_16 0x38 // 5 0 f = f(XOSC)/16 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_24 0x39 // 5 0 f = f(XOSC)/24 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_32 0x3A // 5 0 f = f(XOSC)/32 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_48 0x3B // 5 0 f = f(XOSC)/48 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_64 0x3C // 5 0 f = f(XOSC)/64 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_96 0x3D // 5 0 f = f(XOSC)/96 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_128 0x3E // 5 0 f = f(XOSC)/128 -#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_192 0x3F // 5 0 f = f(XOSC)/192 (default for GDO0) - -// CC1101_REG_FIFOTHR -#define RADIOLIB_CC1101_ADC_RETENTION_OFF 0b00000000 // 6 6 do not retain ADC settings in sleep mode (default) -#define RADIOLIB_CC1101_ADC_RETENTION_ON 0b01000000 // 6 6 retain ADC settings in sleep mode -#define RADIOLIB_CC1101_RX_ATTEN_0_DB 0b00000000 // 5 4 Rx attenuation: 0 dB (default) -#define RADIOLIB_CC1101_RX_ATTEN_6_DB 0b00010000 // 5 4 6 dB -#define RADIOLIB_CC1101_RX_ATTEN_12_DB 0b00100000 // 5 4 12 dB -#define RADIOLIB_CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB -#define RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4 - -// CC1101_REG_SYNC1 -#define RADIOLIB_CC1101_SYNC_WORD_MSB 0xD3 // 7 0 sync word MSB - -// CC1101_REG_SYNC0 -#define RADIOLIB_CC1101_SYNC_WORD_LSB 0x91 // 7 0 sync word LSB - -// CC1101_REG_PKTLEN -#define RADIOLIB_CC1101_PACKET_LENGTH 0xFF // 7 0 packet length in bytes - -// CC1101_REG_PKTCTRL1 -#define RADIOLIB_CC1101_PQT 0x00 // 7 5 preamble quality threshold -#define RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF 0b00000000 // 3 3 automatic Rx FIFO flush on CRC check fail: disabled (default) -#define RADIOLIB_CC1101_CRC_AUTOFLUSH_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_CC1101_APPEND_STATUS_OFF 0b00000000 // 2 2 append 2 status bytes to packet: disabled -#define RADIOLIB_CC1101_APPEND_STATUS_ON 0b00000100 // 2 2 enabled (default) -#define RADIOLIB_CC1101_ADR_CHK_NONE 0b00000000 // 1 0 address check: none (default) -#define RADIOLIB_CC1101_ADR_CHK_NO_BROADCAST 0b00000001 // 1 0 without broadcast -#define RADIOLIB_CC1101_ADR_CHK_SINGLE_BROADCAST 0b00000010 // 1 0 broadcast address 0x00 -#define RADIOLIB_CC1101_ADR_CHK_DOUBLE_BROADCAST 0b00000011 // 1 0 broadcast addresses 0x00 and 0xFF - -// CC1101_REG_PKTCTRL0 -#define RADIOLIB_CC1101_WHITE_DATA_OFF 0b00000000 // 6 6 data whitening: disabled -#define RADIOLIB_CC1101_WHITE_DATA_ON 0b01000000 // 6 6 enabled (default) -#define RADIOLIB_CC1101_PKT_FORMAT_NORMAL 0b00000000 // 5 4 packet format: normal (FIFOs) -#define RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS 0b00010000 // 5 4 synchronous serial -#define RADIOLIB_CC1101_PKT_FORMAT_RANDOM 0b00100000 // 5 4 random transmissions -#define RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS 0b00110000 // 5 4 asynchronous serial -#define RADIOLIB_CC1101_CRC_OFF 0b00000000 // 2 2 CRC disabled -#define RADIOLIB_CC1101_CRC_ON 0b00000100 // 2 2 CRC enabled (default) -#define RADIOLIB_CC1101_LENGTH_CONFIG_FIXED 0b00000000 // 1 0 packet length: fixed -#define RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE 0b00000001 // 1 0 variable (default) -#define RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE 0b00000010 // 1 0 infinite - -// CC1101_REG_ADDR -#define RADIOLIB_CC1101_DEVICE_ADDR 0x00 // 7 0 device address - -// CC1101_REG_CHANNR -#define RADIOLIB_CC1101_CHAN 0x00 // 7 0 channel number - -// CC1101_REG_FSCTRL1 -#define RADIOLIB_CC1101_FREQ_IF 0x0F // 4 0 IF frequency setting; f_IF = (f(XOSC) / 2^10) * CC1101_FREQ_IF +#define RADIOLIB_CC1101_REG_IOCFG2 0x00 +#define RADIOLIB_CC1101_REG_IOCFG1 0x01 +#define RADIOLIB_CC1101_REG_IOCFG0 0x02 +#define RADIOLIB_CC1101_REG_FIFOTHR 0x03 +#define RADIOLIB_CC1101_REG_SYNC1 0x04 +#define RADIOLIB_CC1101_REG_SYNC0 0x05 +#define RADIOLIB_CC1101_REG_PKTLEN 0x06 +#define RADIOLIB_CC1101_REG_PKTCTRL1 0x07 +#define RADIOLIB_CC1101_REG_PKTCTRL0 0x08 +#define RADIOLIB_CC1101_REG_ADDR 0x09 +#define RADIOLIB_CC1101_REG_CHANNR 0x0A +#define RADIOLIB_CC1101_REG_FSCTRL1 0x0B +#define RADIOLIB_CC1101_REG_FSCTRL0 0x0C +#define RADIOLIB_CC1101_REG_FREQ2 0x0D +#define RADIOLIB_CC1101_REG_FREQ1 0x0E +#define RADIOLIB_CC1101_REG_FREQ0 0x0F +#define RADIOLIB_CC1101_REG_MDMCFG4 0x10 +#define RADIOLIB_CC1101_REG_MDMCFG3 0x11 +#define RADIOLIB_CC1101_REG_MDMCFG2 0x12 +#define RADIOLIB_CC1101_REG_MDMCFG1 0x13 +#define RADIOLIB_CC1101_REG_MDMCFG0 0x14 +#define RADIOLIB_CC1101_REG_DEVIATN 0x15 +#define RADIOLIB_CC1101_REG_MCSM2 0x16 +#define RADIOLIB_CC1101_REG_MCSM1 0x17 +#define RADIOLIB_CC1101_REG_MCSM0 0x18 +#define RADIOLIB_CC1101_REG_FOCCFG 0x19 +#define RADIOLIB_CC1101_REG_BSCFG 0x1A +#define RADIOLIB_CC1101_REG_AGCCTRL2 0x1B +#define RADIOLIB_CC1101_REG_AGCCTRL1 0x1C +#define RADIOLIB_CC1101_REG_AGCCTRL0 0x1D +#define RADIOLIB_CC1101_REG_WOREVT1 0x1E +#define RADIOLIB_CC1101_REG_WOREVT0 0x1F +#define RADIOLIB_CC1101_REG_WORCTRL 0x20 +#define RADIOLIB_CC1101_REG_FREND1 0x21 +#define RADIOLIB_CC1101_REG_FREND0 0x22 +#define RADIOLIB_CC1101_REG_FSCAL3 0x23 +#define RADIOLIB_CC1101_REG_FSCAL2 0x24 +#define RADIOLIB_CC1101_REG_FSCAL1 0x25 +#define RADIOLIB_CC1101_REG_FSCAL0 0x26 +#define RADIOLIB_CC1101_REG_RCCTRL1 0x27 +#define RADIOLIB_CC1101_REG_RCCTRL0 0x28 +#define RADIOLIB_CC1101_REG_FSTEST 0x29 +#define RADIOLIB_CC1101_REG_PTEST 0x2A +#define RADIOLIB_CC1101_REG_AGCTEST 0x2B +#define RADIOLIB_CC1101_REG_TEST2 0x2C +#define RADIOLIB_CC1101_REG_TEST1 0x2D +#define RADIOLIB_CC1101_REG_TEST0 0x2E +#define RADIOLIB_CC1101_REG_PARTNUM 0x30 +#define RADIOLIB_CC1101_REG_VERSION 0x31 +#define RADIOLIB_CC1101_REG_FREQEST 0x32 +#define RADIOLIB_CC1101_REG_LQI 0x33 +#define RADIOLIB_CC1101_REG_RSSI 0x34 +#define RADIOLIB_CC1101_REG_MARCSTATE 0x35 +#define RADIOLIB_CC1101_REG_WORTIME1 0x36 +#define RADIOLIB_CC1101_REG_WORTIME0 0x37 +#define RADIOLIB_CC1101_REG_PKTSTATUS 0x38 +#define RADIOLIB_CC1101_REG_VCO_VC_DAC 0x39 +#define RADIOLIB_CC1101_REG_TXBYTES 0x3A +#define RADIOLIB_CC1101_REG_RXBYTES 0x3B +#define RADIOLIB_CC1101_REG_RCCTRL1_STATUS 0x3C +#define RADIOLIB_CC1101_REG_RCCTRL0_STATUS 0x3D +#define RADIOLIB_CC1101_REG_PATABLE 0x3E +#define RADIOLIB_CC1101_REG_FIFO 0x3F + +// status byte (returned during SPI transactions) MSB LSB DESCRIPTION +#define RADIOLIB_CC1101_STATUS_CHIP_READY 0b00000000 // 7 7 chip ready +#define RADIOLIB_CC1101_STATUS_CHIP_NOT_READY 0b10000000 // 7 7 chip not ready (power/crystal not stable) +#define RADIOLIB_CC1101_STATUS_IDLE 0b00000000 // 6 4 idle +#define RADIOLIB_CC1101_STATUS_RX 0b00010000 // 6 4 Rx +#define RADIOLIB_CC1101_STATUS_TX 0b00100000 // 6 4 Tx +#define RADIOLIB_CC1101_STATUS_FSTXON 0b00110000 // 6 4 Fast Tx ready +#define RADIOLIB_CC1101_STATUS_CALIBRATE 0b01000000 // 6 4 synthesizer calibration running +#define RADIOLIB_CC1101_STATUS_SETTLING 0b01010000 // 6 4 PLL settling +#define RADIOLIB_CC1101_STATUS_RXFIFO_OVERFLOW 0b01100000 // 6 4 Rx FIFO overflow +#define RADIOLIB_CC1101_STATUS_TXFIFO_UNDERFLOW 0b01110000 // 6 4 Tx FIFO underflow + +// RADIOLIB_CC1101_REG_IOCFG2 +#define RADIOLIB_CC1101_GDO2_NORM 0b00000000 // 6 6 GDO2 output: active high (default) +#define RADIOLIB_CC1101_GDO2_INV 0b01000000 // 6 6 active low + +// RADIOLIB_CC1101_REG_IOCFG1 +#define RADIOLIB_CC1101_GDO1_DS_LOW 0b00000000 // 7 7 GDO1 output drive strength: low (default) +#define RADIOLIB_CC1101_GDO1_DS_HIGH 0b10000000 // 7 7 high +#define RADIOLIB_CC1101_GDO1_NORM 0b00000000 // 6 6 GDO1 output: active high (default) +#define RADIOLIB_CC1101_GDO1_INV 0b01000000 // 6 6 active low + +// RADIOLIB_CC1101_REG_IOCFG0 +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_OFF 0b00000000 // 7 7 analog temperature sensor output: disabled (default) +#define RADIOLIB_CC1101_GDO0_TEMP_SENSOR_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_CC1101_GDO0_NORM 0b00000000 // 6 6 GDO0 output: active high (default) +#define RADIOLIB_CC1101_GDO0_INV 0b01000000 // 6 6 active low + +// RADIOLIB_CC1101_REG_IOCFG2 + REG_IOCFG1 + REG_IOCFG0 +#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL 0x00 // 5 0 Rx FIFO full or above threshold +#define RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END 0x01 // 5 0 Rx FIFO full or above threshold or reached packet end +#define RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR 0x02 // 5 0 Tx FIFO above threshold +#define RADIOLIB_CC1101_GDOX_TX_FIFO_FULL 0x03 // 5 0 Tx FIFO full +#define RADIOLIB_CC1101_GDOX_RX_FIFO_OVERFLOW 0x04 // 5 0 Rx FIFO overflowed +#define RADIOLIB_CC1101_GDOX_TX_FIFO_UNDERFLOW 0x05 // 5 0 Tx FIFO underflowed +#define RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED 0x06 // 5 0 sync word was sent or packet was received +#define RADIOLIB_CC1101_GDOX_PKT_RECEIVED_CRC_OK 0x07 // 5 0 packet received and CRC check passed +#define RADIOLIB_CC1101_GDOX_PREAMBLE_QUALITY_REACHED 0x08 // 5 0 received preamble quality is above threshold +#define RADIOLIB_CC1101_GDOX_CHANNEL_CLEAR 0x09 // 5 0 RSSI level below threshold (channel is clear) +#define RADIOLIB_CC1101_GDOX_PLL_LOCKED 0x0A // 5 0 PLL is locked +#define RADIOLIB_CC1101_GDOX_SERIAL_CLOCK 0x0B // 5 0 serial data clock +#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC 0x0C // 5 0 serial data output in: synchronous mode +#define RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC 0x0D // 5 0 asynchronous mode +#define RADIOLIB_CC1101_GDOX_CARRIER_SENSE 0x0E // 5 0 RSSI above threshold +#define RADIOLIB_CC1101_GDOX_CRC_OK 0x0F // 5 0 CRC check passed +#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA1 0x16 // 5 0 direct access to demodulated data +#define RADIOLIB_CC1101_GDOX_RX_HARD_DATA0 0x17 // 5 0 direct access to demodulated data +#define RADIOLIB_CC1101_GDOX_PA_PD 0x1B // 5 0 power amplifier circuit is powered down +#define RADIOLIB_CC1101_GDOX_LNA_PD 0x1C // 5 0 low-noise amplifier circuit is powered down +#define RADIOLIB_CC1101_GDOX_RX_SYMBOL_TICK 0x1D // 5 0 direct access to symbol tick of received data +#define RADIOLIB_CC1101_GDOX_WOR_EVNT0 0x24 // 5 0 wake-on-radio event 0 +#define RADIOLIB_CC1101_GDOX_WOR_EVNT1 0x25 // 5 0 wake-on-radio event 1 +#define RADIOLIB_CC1101_GDOX_CLK_256 0x26 // 5 0 256 Hz clock +#define RADIOLIB_CC1101_GDOX_CLK_32K 0x27 // 5 0 32 kHz clock +#define RADIOLIB_CC1101_GDOX_CHIP_RDYN 0x29 // 5 0 (default for GDO2) +#define RADIOLIB_CC1101_GDOX_XOSC_STABLE 0x2B // 5 0 +#define RADIOLIB_CC1101_GDOX_HIGH_Z 0x2E // 5 0 high impedance state (default for GDO1) +#define RADIOLIB_CC1101_GDOX_HW_TO_0 0x2F // 5 0 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1 0x30 // 5 0 crystal oscillator clock: f = f(XOSC)/1 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_1_5 0x31 // 5 0 f = f(XOSC)/1.5 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_2 0x32 // 5 0 f = f(XOSC)/2 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_3 0x33 // 5 0 f = f(XOSC)/3 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_4 0x34 // 5 0 f = f(XOSC)/4 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_6 0x35 // 5 0 f = f(XOSC)/6 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_8 0x36 // 5 0 f = f(XOSC)/8 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_12 0x37 // 5 0 f = f(XOSC)/12 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_16 0x38 // 5 0 f = f(XOSC)/16 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_24 0x39 // 5 0 f = f(XOSC)/24 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_32 0x3A // 5 0 f = f(XOSC)/32 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_48 0x3B // 5 0 f = f(XOSC)/48 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_64 0x3C // 5 0 f = f(XOSC)/64 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_96 0x3D // 5 0 f = f(XOSC)/96 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_128 0x3E // 5 0 f = f(XOSC)/128 +#define RADIOLIB_CC1101_GDOX_CLOCK_XOSC_192 0x3F // 5 0 f = f(XOSC)/192 (default for GDO0) + +// RADIOLIB_CC1101_REG_FIFOTHR +#define RADIOLIB_CC1101_ADC_RETENTION_OFF 0b00000000 // 6 6 do not retain ADC settings in sleep mode (default) +#define RADIOLIB_CC1101_ADC_RETENTION_ON 0b01000000 // 6 6 retain ADC settings in sleep mode +#define RADIOLIB_CC1101_RX_ATTEN_0_DB 0b00000000 // 5 4 Rx attenuation: 0 dB (default) +#define RADIOLIB_CC1101_RX_ATTEN_6_DB 0b00010000 // 5 4 6 dB +#define RADIOLIB_CC1101_RX_ATTEN_12_DB 0b00100000 // 5 4 12 dB +#define RADIOLIB_CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB +#define RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4 +#define RADIOLIB_CC1101_FIFO_THR_TX_33_RX_32 0b00000111 // 3 0 TX fifo threshold: 33, RX fifo threshold: 32 +#define RADIOLIB_CC1101_FIFO_THRESH_TX 33 +#define RADIOLIB_CC1101_FIFO_THRESH_RX 32 + +// RADIOLIB_CC1101_REG_SYNC1 +#define RADIOLIB_CC1101_SYNC_WORD_MSB 0xD3 // 7 0 sync word MSB + +// RADIOLIB_CC1101_REG_SYNC0 +#define RADIOLIB_CC1101_SYNC_WORD_LSB 0x91 // 7 0 sync word LSB + +// RADIOLIB_CC1101_REG_PKTLEN +#define RADIOLIB_CC1101_PACKET_LENGTH 0xFF // 7 0 packet length in bytes + +// RADIOLIB_CC1101_REG_PKTCTRL1 +#define RADIOLIB_CC1101_PQT 0x00 // 7 5 preamble quality threshold +#define RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF 0b00000000 // 3 3 automatic Rx FIFO flush on CRC check fail: disabled (default) +#define RADIOLIB_CC1101_CRC_AUTOFLUSH_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_CC1101_APPEND_STATUS_OFF 0b00000000 // 2 2 append 2 status bytes to packet: disabled +#define RADIOLIB_CC1101_APPEND_STATUS_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_CC1101_ADR_CHK_NONE 0b00000000 // 1 0 address check: none (default) +#define RADIOLIB_CC1101_ADR_CHK_NO_BROADCAST 0b00000001 // 1 0 without broadcast +#define RADIOLIB_CC1101_ADR_CHK_SINGLE_BROADCAST 0b00000010 // 1 0 broadcast address 0x00 +#define RADIOLIB_CC1101_ADR_CHK_DOUBLE_BROADCAST 0b00000011 // 1 0 broadcast addresses 0x00 and 0xFF + +// RADIOLIB_CC1101_REG_PKTCTRL0 +#define RADIOLIB_CC1101_WHITE_DATA_OFF 0b00000000 // 6 6 data whitening: disabled +#define RADIOLIB_CC1101_WHITE_DATA_ON 0b01000000 // 6 6 enabled (default) +#define RADIOLIB_CC1101_PKT_FORMAT_NORMAL 0b00000000 // 5 4 packet format: normal (FIFOs) +#define RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS 0b00010000 // 5 4 synchronous serial +#define RADIOLIB_CC1101_PKT_FORMAT_RANDOM 0b00100000 // 5 4 random transmissions +#define RADIOLIB_CC1101_PKT_FORMAT_ASYNCHRONOUS 0b00110000 // 5 4 asynchronous serial +#define RADIOLIB_CC1101_CRC_OFF 0b00000000 // 2 2 CRC disabled +#define RADIOLIB_CC1101_CRC_ON 0b00000100 // 2 2 CRC enabled (default) +#define RADIOLIB_CC1101_LENGTH_CONFIG_FIXED 0b00000000 // 1 0 packet length: fixed +#define RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE 0b00000001 // 1 0 variable (default) +#define RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE 0b00000010 // 1 0 infinite + +// RADIOLIB_CC1101_REG_ADDR +#define RADIOLIB_CC1101_DEVICE_ADDR 0x00 // 7 0 device address + +// RADIOLIB_CC1101_REG_CHANNR +#define RADIOLIB_CC1101_CHAN 0x00 // 7 0 channel number + +// RADIOLIB_CC1101_REG_FSCTRL1 +#define RADIOLIB_CC1101_FREQ_IF 0x0F // 4 0 IF frequency setting; f_IF = (f(XOSC) / 2^10) * CC1101_FREQ_IF // CC1101_REG_FSCTRL0 -#define RADIOLIB_CC1101_FREQOFF 0x00 // 7 0 base frequency offset (2s-compliment) - -// CC1101_REG_FREQ2 + REG_FREQ1 + REG_FREQ0 -#define RADIOLIB_CC1101_FREQ_MSB 0x1E // 5 0 base frequency setting: f_carrier = (f(XOSC) / 2^16) * FREQ -#define RADIOLIB_CC1101_FREQ_MID 0xC4 // 7 0 where f(XOSC) = 26 MHz -#define RADIOLIB_CC1101_FREQ_LSB 0xEC // 7 0 FREQ = 3-byte value of FREQ registers - -// CC1101_REG_MDMCFG4 -#define RADIOLIB_CC1101_CHANBW_E 0b10000000 // 7 6 channel bandwidth: BW_channel = f(XOSC) / (8 * (4 + CHANBW_M)*2^CHANBW_E) [Hz] -#define RADIOLIB_CC1101_CHANBW_M 0b00000000 // 5 4 default value for 26 MHz crystal: 203 125 Hz -#define RADIOLIB_CC1101_DRATE_E 0x0C // 3 0 symbol rate: R_data = (((256 + DRATE_M) * 2^DRATE_E) / 2^28) * f(XOSC) [Baud] - -// CC1101_REG_MDMCFG3 -#define RADIOLIB_CC1101_DRATE_M 0x22 // 7 0 default value for 26 MHz crystal: 115 051 Baud - -// CC1101_REG_MDMCFG2 -#define RADIOLIB_CC1101_DEM_DCFILT_OFF 0b10000000 // 7 7 digital DC filter: disabled -#define RADIOLIB_CC1101_DEM_DCFILT_ON 0b00000000 // 7 7 enabled - only for data rates above 250 kBaud (default) -#define RADIOLIB_CC1101_MOD_FORMAT_2_FSK 0b00000000 // 6 4 modulation format: 2-FSK (default) -#define RADIOLIB_CC1101_MOD_FORMAT_GFSK 0b00010000 // 6 4 GFSK -#define RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK 0b00110000 // 6 4 ASK/OOK -#define RADIOLIB_CC1101_MOD_FORMAT_4_FSK 0b01000000 // 6 4 4-FSK -#define RADIOLIB_CC1101_MOD_FORMAT_MFSK 0b01110000 // 6 4 MFSK - only for data rates above 26 kBaud -#define RADIOLIB_CC1101_MANCHESTER_EN_OFF 0b00000000 // 3 3 Manchester encoding: disabled (default) -#define RADIOLIB_CC1101_MANCHESTER_EN_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble/sync -#define RADIOLIB_CC1101_SYNC_MODE_15_16 0b00000001 // 2 0 15/16 sync word bits -#define RADIOLIB_CC1101_SYNC_MODE_16_16 0b00000010 // 2 0 16/16 sync word bits (default) -#define RADIOLIB_CC1101_SYNC_MODE_30_32 0b00000011 // 2 0 30/32 sync word bits -#define RADIOLIB_CC1101_SYNC_MODE_NONE_THR 0b00000100 // 2 0 no preamble sync, carrier sense above threshold -#define RADIOLIB_CC1101_SYNC_MODE_15_16_THR 0b00000101 // 2 0 15/16 sync word bits, carrier sense above threshold -#define RADIOLIB_CC1101_SYNC_MODE_16_16_THR 0b00000110 // 2 0 16/16 sync word bits, carrier sense above threshold -#define RADIOLIB_CC1101_SYNC_MODE_30_32_THR 0b00000111 // 2 0 30/32 sync word bits, carrier sense above threshold - -// CC1101_REG_MDMCFG1 -#define RADIOLIB_CC1101_FEC_OFF 0b00000000 // 7 7 forward error correction: disabled (default) -#define RADIOLIB_CC1101_FEC_ON 0b10000000 // 7 7 enabled - only for fixed packet length -#define RADIOLIB_CC1101_NUM_PREAMBLE_2 0b00000000 // 6 4 number of preamble bytes: 2 -#define RADIOLIB_CC1101_NUM_PREAMBLE_3 0b00010000 // 6 4 3 -#define RADIOLIB_CC1101_NUM_PREAMBLE_4 0b00100000 // 6 4 4 (default) -#define RADIOLIB_CC1101_NUM_PREAMBLE_6 0b00110000 // 6 4 6 -#define RADIOLIB_CC1101_NUM_PREAMBLE_8 0b01000000 // 6 4 8 -#define RADIOLIB_CC1101_NUM_PREAMBLE_12 0b01010000 // 6 4 12 -#define RADIOLIB_CC1101_NUM_PREAMBLE_16 0b01100000 // 6 4 16 -#define RADIOLIB_CC1101_NUM_PREAMBLE_24 0b01110000 // 6 4 24 -#define RADIOLIB_CC1101_CHANSPC_E 0x02 // 1 0 channel spacing: df_channel = (f(XOSC) / 2^18) * (256 + CHANSPC_M) * 2^CHANSPC_E [Hz] - -// CC1101_REG_MDMCFG0 -#define RADIOLIB_CC1101_CHANSPC_M 0xF8 // 7 0 default value for 26 MHz crystal: 199 951 kHz - -// CC1101_REG_DEVIATN -#define RADIOLIB_CC1101_DEVIATION_E 0b01000000 // 6 4 frequency deviation: f_dev = (f(XOSC) / 2^17) * (8 + DEVIATION_M) * 2^DEVIATION_E [Hz] -#define RADIOLIB_CC1101_DEVIATION_M 0b00000111 // 2 0 default value for 26 MHz crystal: +- 47 607 Hz -#define RADIOLIB_CC1101_MSK_PHASE_CHANGE_PERIOD 0x07 // 2 0 phase change symbol period fraction: 1 / (MSK_PHASE_CHANGE_PERIOD + 1) - -// CC1101_REG_MCSM2 -#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_OFF 0b00000000 // 4 4 Rx timeout based on RSSI value: disabled (default) -#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_OFF 0b00000000 // 3 3 check for sync word on Rx timeout -#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_ON 0b00001000 // 3 3 check for PQI set on Rx timeout -#define RADIOLIB_CC1101_RX_TIMEOUT_OFF 0b00000111 // 2 0 Rx timeout: disabled (default) -#define RADIOLIB_CC1101_RX_TIMEOUT_MAX 0b00000000 // 2 0 max value (actual value depends on WOR_RES, EVENT0 and f(XOSC)) - -// CC1101_REG_MCSM1 -#define RADIOLIB_CC1101_CCA_MODE_ALWAYS 0b00000000 // 5 4 clear channel indication: always -#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR 0b00010000 // 5 4 RSSI below threshold -#define RADIOLIB_CC1101_CCA_MODE_RX_PKT 0b00100000 // 5 4 unless receiving packet -#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR_RX_PKT 0b00110000 // 5 4 RSSI below threshold unless receiving packet (default) -#define RADIOLIB_CC1101_RXOFF_IDLE 0b00000000 // 3 2 next mode after packet reception: idle (default) -#define RADIOLIB_CC1101_RXOFF_FSTXON 0b00000100 // 3 2 FSTxOn -#define RADIOLIB_CC1101_RXOFF_TX 0b00001000 // 3 2 Tx -#define RADIOLIB_CC1101_RXOFF_RX 0b00001100 // 3 2 Rx -#define RADIOLIB_CC1101_TXOFF_IDLE 0b00000000 // 1 0 next mode after packet transmission: idle (default) -#define RADIOLIB_CC1101_TXOFF_FSTXON 0b00000001 // 1 0 FSTxOn -#define RADIOLIB_CC1101_TXOFF_TX 0b00000010 // 1 0 Tx -#define RADIOLIB_CC1101_TXOFF_RX 0b00000011 // 1 0 Rx - -// CC1101_REG_MCSM0 -#define RADIOLIB_CC1101_FS_AUTOCAL_NEVER 0b00000000 // 5 4 automatic calibration: never (default) -#define RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX 0b00010000 // 5 4 every transition from idle to Rx/Tx -#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE 0b00100000 // 5 4 every transition from Rx/Tx to idle -#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE_4TH 0b00110000 // 5 4 every 4th transition from Rx/Tx to idle -#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_1 0b00000000 // 3 2 number of counter expirations before CHP_RDYN goes low: 1 (default) -#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_16 0b00000100 // 3 2 16 -#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_64 0b00001000 // 3 2 64 -#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_256 0b00001100 // 3 2 256 -#define RADIOLIB_CC1101_PIN_CTRL_OFF 0b00000000 // 1 1 pin radio control: disabled (default) -#define RADIOLIB_CC1101_PIN_CTRL_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_CC1101_XOSC_FORCE_OFF 0b00000000 // 0 0 do not force XOSC to remain on in sleep (default) -#define RADIOLIB_CC1101_XOSC_FORCE_ON 0b00000001 // 0 0 force XOSC to remain on in sleep - -// CC1101_REG_FOCCFG -#define RADIOLIB_CC1101_FOC_BS_CS_GATE_OFF 0b00000000 // 5 5 do not freeze frequency compensation until CS goes high -#define RADIOLIB_CC1101_FOC_BS_CS_GATE_ON 0b00100000 // 5 5 freeze frequency compensation until CS goes high (default) -#define RADIOLIB_CC1101_FOC_PRE_K 0b00000000 // 4 3 frequency compensation loop gain before sync word: K -#define RADIOLIB_CC1101_FOC_PRE_2K 0b00001000 // 4 3 2K -#define RADIOLIB_CC1101_FOC_PRE_3K 0b00010000 // 4 3 3K (default) -#define RADIOLIB_CC1101_FOC_PRE_4K 0b00011000 // 4 3 4K -#define RADIOLIB_CC1101_FOC_POST_K 0b00000000 // 2 2 frequency compensation loop gain after sync word: same as FOC_PRE -#define RADIOLIB_CC1101_FOC_POST_K_2 0b00000100 // 2 2 K/2 (default) -#define RADIOLIB_CC1101_FOC_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 frequency compensation saturation point: no compensation - required for ASK/OOK -#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_8 0b00000001 // 1 0 +- BW_chan/8 -#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_4 0b00000010 // 1 0 +- BW_chan/4 (default) -#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_2 0b00000011 // 1 0 +- BW_chan/2 - -// CC1101_REG_BSCFG -#define RADIOLIB_CC1101_BS_PRE_KI 0b00000000 // 7 6 clock recovery integral gain before sync word: Ki -#define RADIOLIB_CC1101_BS_PRE_2KI 0b01000000 // 7 6 2Ki (default) -#define RADIOLIB_CC1101_BS_PRE_3KI 0b10000000 // 7 6 3Ki -#define RADIOLIB_CC1101_BS_PRE_4KI 0b11000000 // 7 6 4Ki -#define RADIOLIB_CC1101_BS_PRE_KP 0b00000000 // 5 4 clock recovery proportional gain before sync word: Kp -#define RADIOLIB_CC1101_BS_PRE_2KP 0b00010000 // 5 4 2Kp -#define RADIOLIB_CC1101_BS_PRE_3KP 0b00100000 // 5 4 3Kp (default) -#define RADIOLIB_CC1101_BS_PRE_4KP 0b00110000 // 5 4 4Kp -#define RADIOLIB_CC1101_BS_POST_KI 0b00000000 // 3 3 clock recovery integral gain after sync word: same as BS_PRE -#define RADIOLIB_CC1101_BS_POST_KI_2 0b00001000 // 3 3 Ki/2 (default) -#define RADIOLIB_CC1101_BS_POST_KP 0b00000000 // 2 2 clock recovery proportional gain after sync word: same as BS_PRE -#define RADIOLIB_CC1101_BS_POST_KP_1 0b00000100 // 2 2 Kp (default) -#define RADIOLIB_CC1101_BS_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 data rate compensation saturation point: no compensation -#define RADIOLIB_CC1101_BS_LIMIT_3_125 0b00000001 // 1 0 +- 3.125 % -#define RADIOLIB_CC1101_BS_LIMIT_6_25 0b00000010 // 1 0 +- 6.25 % -#define RADIOLIB_CC1101_BS_LIMIT_12_5 0b00000011 // 1 0 +- 12.5 % - -// CC1101_REG_AGCCTRL2 -#define RADIOLIB_CC1101_MAX_DVGA_GAIN_0 0b00000000 // 7 6 reduce maximum available DVGA gain: no reduction (default) -#define RADIOLIB_CC1101_MAX_DVGA_GAIN_1 0b01000000 // 7 6 disable top gain setting -#define RADIOLIB_CC1101_MAX_DVGA_GAIN_2 0b10000000 // 7 6 disable top two gain setting -#define RADIOLIB_CC1101_MAX_DVGA_GAIN_3 0b11000000 // 7 6 disable top three gain setting -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_0_DB 0b00000000 // 5 3 reduce maximum LNA gain by: 0 dB (default) -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_2_6_DB 0b00001000 // 5 3 2.6 dB -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_6_1_DB 0b00010000 // 5 3 6.1 dB -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_7_4_DB 0b00011000 // 5 3 7.4 dB -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_9_2_DB 0b00100000 // 5 3 9.2 dB -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_11_5_DB 0b00101000 // 5 3 11.5 dB -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_14_6_DB 0b00110000 // 5 3 14.6 dB -#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_17_1_DB 0b00111000 // 5 3 17.1 dB -#define RADIOLIB_CC1101_MAGN_TARGET_24_DB 0b00000000 // 2 0 average amplitude target for filter: 24 dB -#define RADIOLIB_CC1101_MAGN_TARGET_27_DB 0b00000001 // 2 0 27 dB -#define RADIOLIB_CC1101_MAGN_TARGET_30_DB 0b00000010 // 2 0 30 dB -#define RADIOLIB_CC1101_MAGN_TARGET_33_DB 0b00000011 // 2 0 33 dB (default) -#define RADIOLIB_CC1101_MAGN_TARGET_36_DB 0b00000100 // 2 0 36 dB -#define RADIOLIB_CC1101_MAGN_TARGET_38_DB 0b00000101 // 2 0 38 dB -#define RADIOLIB_CC1101_MAGN_TARGET_40_DB 0b00000110 // 2 0 40 dB -#define RADIOLIB_CC1101_MAGN_TARGET_42_DB 0b00000111 // 2 0 42 dB - -// CC1101_REG_AGCCTRL1 -#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA2 0b00000000 // 6 6 LNA priority setting: LNA2 first -#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA 0b01000000 // 6 6 LNA first (default) -#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_OFF 0b00000000 // 5 4 RSSI relative change to assert carrier sense: disabled (default) -#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_6_DB 0b00010000 // 5 4 6 dB -#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_10_DB 0b00100000 // 5 4 10 dB -#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_14_DB 0b00110000 // 5 4 14 dB -#define RADIOLIB_CC1101_CARRIER_SENSE_ABS_THR 0x00 // 3 0 RSSI threshold to assert carrier sense in 2s compliment, Thr = MAGN_TARGET + CARRIER_SENSE_ABS_TH [dB] - -// CC1101_REG_AGCCTRL0 -#define RADIOLIB_CC1101_HYST_LEVEL_NONE 0b00000000 // 7 6 AGC hysteresis level: none -#define RADIOLIB_CC1101_HYST_LEVEL_LOW 0b01000000 // 7 6 low -#define RADIOLIB_CC1101_HYST_LEVEL_MEDIUM 0b10000000 // 7 6 medium (default) -#define RADIOLIB_CC1101_HYST_LEVEL_HIGH 0b11000000 // 7 6 high -#define RADIOLIB_CC1101_WAIT_TIME_8_SAMPLES 0b00000000 // 5 4 AGC wait time: 8 samples -#define RADIOLIB_CC1101_WAIT_TIME_16_SAMPLES 0b00010000 // 5 4 16 samples (default) -#define RADIOLIB_CC1101_WAIT_TIME_24_SAMPLES 0b00100000 // 5 4 24 samples -#define RADIOLIB_CC1101_WAIT_TIME_32_SAMPLES 0b00110000 // 5 4 32 samples -#define RADIOLIB_CC1101_AGC_FREEZE_NEVER 0b00000000 // 3 2 freeze AGC gain: never (default) -#define RADIOLIB_CC1101_AGC_FREEZE_SYNC_WORD 0b00000100 // 3 2 when sync word is found -#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_A 0b00001000 // 3 2 manually freeze analog control -#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_AD 0b00001100 // 3 2 manually freeze analog and digital control -#define RADIOLIB_CC1101_FILTER_LENGTH_8 0b00000000 // 1 0 averaging length for channel filter: 8 samples -#define RADIOLIB_CC1101_FILTER_LENGTH_16 0b00000001 // 1 0 16 samples (default) -#define RADIOLIB_CC1101_FILTER_LENGTH_32 0b00000010 // 1 0 32 samples -#define RADIOLIB_CC1101_FILTER_LENGTH_64 0b00000011 // 1 0 64 samples -#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_4_DB 0b00000000 // 1 0 ASK/OOK decision boundary: 4 dB -#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_8_DB 0b00000001 // 1 0 8 dB (default) -#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_12_DB 0b00000010 // 1 0 12 dB -#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_16_DB 0b00000011 // 1 0 16 dB - -// CC1101_REG_WOREVT1 + REG_WOREVT0 -#define RADIOLIB_CC1101_EVENT0_TIMEOUT_MSB 0x87 // 7 0 EVENT0 timeout: t_event0 = (750 / f(XOSC)) * EVENT0_TIMEOUT * 2^(5 * WOR_RES) [s] -#define RADIOLIB_CC1101_EVENT0_TIMEOUT_LSB 0x6B // 7 0 default value for 26 MHz crystal: 1.0 s - -// CC1101_REG_WORCTRL -#define RADIOLIB_CC1101_RC_POWER_UP 0b00000000 // 7 7 power up RC oscillator -#define RADIOLIB_CC1101_RC_POWER_DOWN 0b10000000 // 7 7 power down RC oscillator -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_4 0b00000000 // 6 4 EVENT1 timeout: 4 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_6 0b00010000 // 6 4 6 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_8 0b00100000 // 6 4 8 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_12 0b00110000 // 6 4 12 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_16 0b01000000 // 6 4 16 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_24 0b01010000 // 6 4 24 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_32 0b01100000 // 6 4 32 RC periods -#define RADIOLIB_CC1101_EVENT1_TIMEOUT_48 0b01110000 // 6 4 48 RC periods (default) -#define RADIOLIB_CC1101_RC_CAL_OFF 0b00000000 // 3 3 disable RC oscillator calibration -#define RADIOLIB_CC1101_RC_CAL_ON 0b00001000 // 3 3 enable RC oscillator calibration (default) -#define RADIOLIB_CC1101_WOR_RES_1 0b00000000 // 1 0 EVENT0 resolution: 1 period (default) -#define RADIOLIB_CC1101_WOR_RES_2_5 0b00000001 // 1 0 2^5 periods -#define RADIOLIB_CC1101_WOR_RES_2_10 0b00000010 // 1 0 2^10 periods -#define RADIOLIB_CC1101_WOR_RES_2_15 0b00000011 // 1 0 2^15 periods - -// CC1101_REG_FREND1 -#define RADIOLIB_CC1101_LNA_CURRENT 0x01 // 7 6 front-end LNA PTAT current output adjustment -#define RADIOLIB_CC1101_LNA2MIX_CURRENT 0x01 // 5 4 front-end PTAT output adjustment -#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_RX 0x01 // 3 2 Rx LO buffer current adjustment -#define RADIOLIB_CC1101_MIX_CURRENT 0x02 // 1 0 mixer current adjustment - -// CC1101_REG_FREND0 -#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_TX 0x01 // 5 4 Tx LO buffer current adjustment -#define RADIOLIB_CC1101_PA_POWER 0x00 // 2 0 set power amplifier power according to PATABLE - -// CC1101_REG_FSCAL3 -#define RADIOLIB_CC1101_CHP_CURR_CAL_OFF 0b00000000 // 5 4 disable charge pump calibration -#define RADIOLIB_CC1101_CHP_CURR_CAL_ON 0b00100000 // 5 4 enable charge pump calibration (default) -#define RADIOLIB_CC1101_FSCAL3 0x09 // 3 0 charge pump output current: I_out = I_0 * 2^(FSCAL3/4) [A] - -// CC1101_REG_FSCAL2 -#define RADIOLIB_CC1101_VCO_CORE_LOW 0b00000000 // 5 5 VCO: low (default) -#define RADIOLIB_CC1101_VCO_CORE_HIGH 0b00100000 // 5 5 high -#define RADIOLIB_CC1101_FSCAL2 0x0A // 4 0 VCO current result/override - -// CC1101_REG_FSCAL1 -#define RADIOLIB_CC1101_FSCAL1 0x20 // 5 0 capacitor array setting for coarse VCO tuning - -// CC1101_REG_FSCAL0 -#define RADIOLIB_CC1101_FSCAL0 0x0D // 6 0 frequency synthesizer calibration setting - -// CC1101_REG_RCCTRL1 -#define RADIOLIB_CC1101_RCCTRL1 0x41 // 6 0 RC oscillator configuration - -// CC1101_REG_RCCTRL0 -#define RADIOLIB_CC1101_RCCTRL0 0x00 // 6 0 RC oscillator configuration - -// CC1101_REG_PTEST -#define RADIOLIB_CC1101_TEMP_SENS_IDLE_OFF 0x7F // 7 0 temperature sensor will not be available in idle mode (default) -#define RADIOLIB_CC1101_TEMP_SENS_IDLE_ON 0xBF // 7 0 temperature sensor will be available in idle mode - -// CC1101_REG_TEST0 -#define RADIOLIB_CC1101_VCO_SEL_CAL_OFF 0b00000000 // 1 1 disable VCO selection calibration stage -#define RADIOLIB_CC1101_VCO_SEL_CAL_ON 0b00000010 // 1 1 enable VCO selection calibration stage - -// CC1101_REG_PARTNUM -#define RADIOLIB_CC1101_PARTNUM 0x00 - -// CC1101_REG_VERSION -#define RADIOLIB_CC1101_VERSION_CURRENT 0x14 -#define RADIOLIB_CC1101_VERSION_LEGACY 0x04 -#define RADIOLIB_CC1101_VERSION_CLONE 0x17 - -// CC1101_REG_MARCSTATE -#define RADIOLIB_CC1101_MARC_STATE_SLEEP 0x00 // 4 0 main radio control state: sleep -#define RADIOLIB_CC1101_MARC_STATE_IDLE 0x01 // 4 0 idle -#define RADIOLIB_CC1101_MARC_STATE_XOFF 0x02 // 4 0 XOFF -#define RADIOLIB_CC1101_MARC_STATE_VCOON_MC 0x03 // 4 0 VCOON_MC -#define RADIOLIB_CC1101_MARC_STATE_REGON_MC 0x04 // 4 0 REGON_MC -#define RADIOLIB_CC1101_MARC_STATE_MANCAL 0x05 // 4 0 MANCAL -#define RADIOLIB_CC1101_MARC_STATE_VCOON 0x06 // 4 0 VCOON -#define RADIOLIB_CC1101_MARC_STATE_REGON 0x07 // 4 0 REGON -#define RADIOLIB_CC1101_MARC_STATE_STARTCAL 0x08 // 4 0 STARTCAL -#define RADIOLIB_CC1101_MARC_STATE_BWBOOST 0x09 // 4 0 BWBOOST -#define RADIOLIB_CC1101_MARC_STATE_FS_LOCK 0x0A // 4 0 FS_LOCK -#define RADIOLIB_CC1101_MARC_STATE_IFADCON 0x0B // 4 0 IFADCON -#define RADIOLIB_CC1101_MARC_STATE_ENDCAL 0x0C // 4 0 ENDCAL -#define RADIOLIB_CC1101_MARC_STATE_RX 0x0D // 4 0 RX -#define RADIOLIB_CC1101_MARC_STATE_RX_END 0x0E // 4 0 RX_END -#define RADIOLIB_CC1101_MARC_STATE_RX_RST 0x0F // 4 0 RX_RST -#define RADIOLIB_CC1101_MARC_STATE_TXRX_SWITCH 0x10 // 4 0 TXRX_SWITCH -#define RADIOLIB_CC1101_MARC_STATE_RXFIFO_OVERFLOW 0x11 // 4 0 RXFIFO_OVERFLOW -#define RADIOLIB_CC1101_MARC_STATE_FSTXON 0x12 // 4 0 FSTXON -#define RADIOLIB_CC1101_MARC_STATE_TX 0x13 // 4 0 TX -#define RADIOLIB_CC1101_MARC_STATE_TX_END 0x14 // 4 0 TX_END -#define RADIOLIB_CC1101_MARC_STATE_RXTX_SWITCH 0x15 // 4 0 RXTX_SWITCH -#define RADIOLIB_CC1101_MARC_STATE_TXFIFO_UNDERFLOW 0x16 // 4 0 TXFIFO_UNDERFLOW - -// CC1101_REG_WORTIME1 + REG_WORTIME0 -#define RADIOLIB_CC1101_WORTIME_MSB 0x00 // 7 0 WOR timer value -#define RADIOLIB_CC1101_WORTIME_LSB 0x00 // 7 0 - -// CC1101_REG_PKTSTATUS -#define RADIOLIB_CC1101_CRC_OK 0b10000000 // 7 7 CRC check passed -#define RADIOLIB_CC1101_CRC_ERROR 0b00000000 // 7 7 CRC check failed -#define RADIOLIB_CC1101_CS 0b01000000 // 6 6 carrier sense -#define RADIOLIB_CC1101_PQT_REACHED 0b00100000 // 5 5 preamble quality reached -#define RADIOLIB_CC1101_CCA 0b00010000 // 4 4 channel clear -#define RADIOLIB_CC1101_SFD 0b00001000 // 3 3 start of frame delimiter - sync word received -#define RADIOLIB_CC1101_GDO2_ACTIVE 0b00000100 // 2 2 GDO2 is active/asserted -#define RADIOLIB_CC1101_GDO0_ACTIVE 0b00000001 // 0 0 GDO0 is active/asserted - -//Defaults -#define RADIOLIB_CC1101_DEFAULT_FREQ 434.0 -#define RADIOLIB_CC1101_DEFAULT_BR 4.8 -#define RADIOLIB_CC1101_DEFAULT_FREQDEV 5.0 -#define RADIOLIB_CC1101_DEFAULT_RXBW 135.0 -#define RADIOLIB_CC1101_DEFAULT_POWER 10 -#define RADIOLIB_CC1101_DEFAULT_PREAMBLELEN 16 -#define RADIOLIB_CC1101_DEFAULT_SW {0x12, 0xAD} -#define RADIOLIB_CC1101_DEFAULT_SW_LEN 2 +#define RADIOLIB_CC1101_FREQOFF 0x00 // 7 0 base frequency offset (2s-compliment) + +// RADIOLIB_CC1101_REG_FREQ2 + REG_FREQ1 + REG_FREQ0 +#define RADIOLIB_CC1101_FREQ_MSB 0x1E // 5 0 base frequency setting: f_carrier = (f(XOSC) / 2^16) * FREQ +#define RADIOLIB_CC1101_FREQ_MID 0xC4 // 7 0 where f(XOSC) = 26 MHz +#define RADIOLIB_CC1101_FREQ_LSB 0xEC // 7 0 FREQ = 3-byte value of FREQ registers + +// RADIOLIB_CC1101_REG_MDMCFG4 +#define RADIOLIB_CC1101_CHANBW_E 0b10000000 // 7 6 channel bandwidth: BW_channel = f(XOSC) / (8 * (4 + CHANBW_M)*2^CHANBW_E) [Hz] +#define RADIOLIB_CC1101_CHANBW_M 0b00000000 // 5 4 default value for 26 MHz crystal: 203 125 Hz +#define RADIOLIB_CC1101_DRATE_E 0x0C // 3 0 symbol rate: R_data = (((256 + DRATE_M) * 2^DRATE_E) / 2^28) * f(XOSC) [Baud] + +// RADIOLIB_CC1101_REG_MDMCFG3 +#define RADIOLIB_CC1101_DRATE_M 0x22 // 7 0 default value for 26 MHz crystal: 115 051 Baud + +// RADIOLIB_CC1101_REG_MDMCFG2 +#define RADIOLIB_CC1101_DEM_DCFILT_OFF 0b10000000 // 7 7 digital DC filter: disabled +#define RADIOLIB_CC1101_DEM_DCFILT_ON 0b00000000 // 7 7 enabled - only for data rates above 250 kBaud (default) +#define RADIOLIB_CC1101_MOD_FORMAT_2_FSK 0b00000000 // 6 4 modulation format: 2-FSK (default) +#define RADIOLIB_CC1101_MOD_FORMAT_GFSK 0b00010000 // 6 4 GFSK +#define RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK 0b00110000 // 6 4 ASK/OOK +#define RADIOLIB_CC1101_MOD_FORMAT_4_FSK 0b01000000 // 6 4 4-FSK +#define RADIOLIB_CC1101_MOD_FORMAT_MFSK 0b01110000 // 6 4 MFSK - only for data rates above 26 kBaud +#define RADIOLIB_CC1101_MANCHESTER_EN_OFF 0b00000000 // 3 3 Manchester encoding: disabled (default) +#define RADIOLIB_CC1101_MANCHESTER_EN_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble/sync +#define RADIOLIB_CC1101_SYNC_MODE_15_16 0b00000001 // 2 0 15/16 sync word bits +#define RADIOLIB_CC1101_SYNC_MODE_16_16 0b00000010 // 2 0 16/16 sync word bits (default) +#define RADIOLIB_CC1101_SYNC_MODE_30_32 0b00000011 // 2 0 30/32 sync word bits +#define RADIOLIB_CC1101_SYNC_MODE_NONE_THR 0b00000100 // 2 0 no preamble sync, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_15_16_THR 0b00000101 // 2 0 15/16 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_16_16_THR 0b00000110 // 2 0 16/16 sync word bits, carrier sense above threshold +#define RADIOLIB_CC1101_SYNC_MODE_30_32_THR 0b00000111 // 2 0 30/32 sync word bits, carrier sense above threshold + +// RADIOLIB_CC1101_REG_MDMCFG1 +#define RADIOLIB_CC1101_FEC_OFF 0b00000000 // 7 7 forward error correction: disabled (default) +#define RADIOLIB_CC1101_FEC_ON 0b10000000 // 7 7 enabled - only for fixed packet length +#define RADIOLIB_CC1101_NUM_PREAMBLE_2 0b00000000 // 6 4 number of preamble bytes: 2 +#define RADIOLIB_CC1101_NUM_PREAMBLE_3 0b00010000 // 6 4 3 +#define RADIOLIB_CC1101_NUM_PREAMBLE_4 0b00100000 // 6 4 4 (default) +#define RADIOLIB_CC1101_NUM_PREAMBLE_6 0b00110000 // 6 4 6 +#define RADIOLIB_CC1101_NUM_PREAMBLE_8 0b01000000 // 6 4 8 +#define RADIOLIB_CC1101_NUM_PREAMBLE_12 0b01010000 // 6 4 12 +#define RADIOLIB_CC1101_NUM_PREAMBLE_16 0b01100000 // 6 4 16 +#define RADIOLIB_CC1101_NUM_PREAMBLE_24 0b01110000 // 6 4 24 +#define RADIOLIB_CC1101_CHANSPC_E 0x02 // 1 0 channel spacing: df_channel = (f(XOSC) / 2^18) * (256 + CHANSPC_M) * 2^CHANSPC_E [Hz] + +// RADIOLIB_CC1101_REG_MDMCFG0 +#define RADIOLIB_CC1101_CHANSPC_M 0xF8 // 7 0 default value for 26 MHz crystal: 199 951 kHz + +// RADIOLIB_CC1101_REG_DEVIATN +#define RADIOLIB_CC1101_DEVIATION_E 0b01000000 // 6 4 frequency deviation: f_dev = (f(XOSC) / 2^17) * (8 + DEVIATION_M) * 2^DEVIATION_E [Hz] +#define RADIOLIB_CC1101_DEVIATION_M 0b00000111 // 2 0 default value for 26 MHz crystal: +- 47 607 Hz +#define RADIOLIB_CC1101_MSK_PHASE_CHANGE_PERIOD 0x07 // 2 0 phase change symbol period fraction: 1 / (MSK_PHASE_CHANGE_PERIOD + 1) + +// RADIOLIB_CC1101_REG_MCSM2 +#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_OFF 0b00000000 // 4 4 Rx timeout based on RSSI value: disabled (default) +#define RADIOLIB_CC1101_RX_TIMEOUT_RSSI_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_OFF 0b00000000 // 3 3 check for sync word on Rx timeout +#define RADIOLIB_CC1101_RX_TIMEOUT_QUAL_ON 0b00001000 // 3 3 check for PQI set on Rx timeout +#define RADIOLIB_CC1101_RX_TIMEOUT_OFF 0b00000111 // 2 0 Rx timeout: disabled (default) +#define RADIOLIB_CC1101_RX_TIMEOUT_MAX 0b00000000 // 2 0 max value (actual value depends on WOR_RES, EVENT0 and f(XOSC)) + +// RADIOLIB_CC1101_REG_MCSM1 +#define RADIOLIB_CC1101_CCA_MODE_ALWAYS 0b00000000 // 5 4 clear channel indication: always +#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR 0b00010000 // 5 4 RSSI below threshold +#define RADIOLIB_CC1101_CCA_MODE_RX_PKT 0b00100000 // 5 4 unless receiving packet +#define RADIOLIB_CC1101_CCA_MODE_RSSI_THR_RX_PKT 0b00110000 // 5 4 RSSI below threshold unless receiving packet (default) +#define RADIOLIB_CC1101_RXOFF_IDLE 0b00000000 // 3 2 next mode after packet reception: idle (default) +#define RADIOLIB_CC1101_RXOFF_FSTXON 0b00000100 // 3 2 FSTxOn +#define RADIOLIB_CC1101_RXOFF_TX 0b00001000 // 3 2 Tx +#define RADIOLIB_CC1101_RXOFF_RX 0b00001100 // 3 2 Rx +#define RADIOLIB_CC1101_TXOFF_IDLE 0b00000000 // 1 0 next mode after packet transmission: idle (default) +#define RADIOLIB_CC1101_TXOFF_FSTXON 0b00000001 // 1 0 FSTxOn +#define RADIOLIB_CC1101_TXOFF_TX 0b00000010 // 1 0 Tx +#define RADIOLIB_CC1101_TXOFF_RX 0b00000011 // 1 0 Rx + +// RADIOLIB_CC1101_REG_MCSM0 +#define RADIOLIB_CC1101_FS_AUTOCAL_NEVER 0b00000000 // 5 4 automatic calibration: never (default) +#define RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX 0b00010000 // 5 4 every transition from idle to Rx/Tx +#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE 0b00100000 // 5 4 every transition from Rx/Tx to idle +#define RADIOLIB_CC1101_FS_AUTOCAL_RXTX_TO_IDLE_4TH 0b00110000 // 5 4 every 4th transition from Rx/Tx to idle +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_1 0b00000000 // 3 2 number of counter expirations before CHP_RDYN goes low: 1 (default) +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_16 0b00000100 // 3 2 16 +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_64 0b00001000 // 3 2 64 +#define RADIOLIB_CC1101_PO_TIMEOUT_COUNT_256 0b00001100 // 3 2 256 +#define RADIOLIB_CC1101_PIN_CTRL_OFF 0b00000000 // 1 1 pin radio control: disabled (default) +#define RADIOLIB_CC1101_PIN_CTRL_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_CC1101_XOSC_FORCE_OFF 0b00000000 // 0 0 do not force XOSC to remain on in sleep (default) +#define RADIOLIB_CC1101_XOSC_FORCE_ON 0b00000001 // 0 0 force XOSC to remain on in sleep + +// RADIOLIB_CC1101_REG_FOCCFG +#define RADIOLIB_CC1101_FOC_BS_CS_GATE_OFF 0b00000000 // 5 5 do not freeze frequency compensation until CS goes high +#define RADIOLIB_CC1101_FOC_BS_CS_GATE_ON 0b00100000 // 5 5 freeze frequency compensation until CS goes high (default) +#define RADIOLIB_CC1101_FOC_PRE_K 0b00000000 // 4 3 frequency compensation loop gain before sync word: K +#define RADIOLIB_CC1101_FOC_PRE_2K 0b00001000 // 4 3 2K +#define RADIOLIB_CC1101_FOC_PRE_3K 0b00010000 // 4 3 3K (default) +#define RADIOLIB_CC1101_FOC_PRE_4K 0b00011000 // 4 3 4K +#define RADIOLIB_CC1101_FOC_POST_K 0b00000000 // 2 2 frequency compensation loop gain after sync word: same as FOC_PRE +#define RADIOLIB_CC1101_FOC_POST_K_2 0b00000100 // 2 2 K/2 (default) +#define RADIOLIB_CC1101_FOC_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 frequency compensation saturation point: no compensation - required for ASK/OOK +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_8 0b00000001 // 1 0 +- BW_chan/8 +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_4 0b00000010 // 1 0 +- BW_chan/4 (default) +#define RADIOLIB_CC1101_FOC_LIMIT_BW_CHAN_2 0b00000011 // 1 0 +- BW_chan/2 + +// RADIOLIB_CC1101_REG_BSCFG +#define RADIOLIB_CC1101_BS_PRE_KI 0b00000000 // 7 6 clock recovery integral gain before sync word: Ki +#define RADIOLIB_CC1101_BS_PRE_2KI 0b01000000 // 7 6 2Ki (default) +#define RADIOLIB_CC1101_BS_PRE_3KI 0b10000000 // 7 6 3Ki +#define RADIOLIB_CC1101_BS_PRE_4KI 0b11000000 // 7 6 4Ki +#define RADIOLIB_CC1101_BS_PRE_KP 0b00000000 // 5 4 clock recovery proportional gain before sync word: Kp +#define RADIOLIB_CC1101_BS_PRE_2KP 0b00010000 // 5 4 2Kp +#define RADIOLIB_CC1101_BS_PRE_3KP 0b00100000 // 5 4 3Kp (default) +#define RADIOLIB_CC1101_BS_PRE_4KP 0b00110000 // 5 4 4Kp +#define RADIOLIB_CC1101_BS_POST_KI 0b00000000 // 3 3 clock recovery integral gain after sync word: same as BS_PRE +#define RADIOLIB_CC1101_BS_POST_KI_2 0b00001000 // 3 3 Ki/2 (default) +#define RADIOLIB_CC1101_BS_POST_KP 0b00000000 // 2 2 clock recovery proportional gain after sync word: same as BS_PRE +#define RADIOLIB_CC1101_BS_POST_KP_1 0b00000100 // 2 2 Kp (default) +#define RADIOLIB_CC1101_BS_LIMIT_NO_COMPENSATION 0b00000000 // 1 0 data rate compensation saturation point: no compensation +#define RADIOLIB_CC1101_BS_LIMIT_3_125 0b00000001 // 1 0 +- 3.125 % +#define RADIOLIB_CC1101_BS_LIMIT_6_25 0b00000010 // 1 0 +- 6.25 % +#define RADIOLIB_CC1101_BS_LIMIT_12_5 0b00000011 // 1 0 +- 12.5 % + +// RADIOLIB_CC1101_REG_AGCCTRL2 +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_0 0b00000000 // 7 6 reduce maximum available DVGA gain: no reduction (default) +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_1 0b01000000 // 7 6 disable top gain setting +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_2 0b10000000 // 7 6 disable top two gain setting +#define RADIOLIB_CC1101_MAX_DVGA_GAIN_3 0b11000000 // 7 6 disable top three gain setting +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_0_DB 0b00000000 // 5 3 reduce maximum LNA gain by: 0 dB (default) +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_2_6_DB 0b00001000 // 5 3 2.6 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_6_1_DB 0b00010000 // 5 3 6.1 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_7_4_DB 0b00011000 // 5 3 7.4 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_9_2_DB 0b00100000 // 5 3 9.2 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_11_5_DB 0b00101000 // 5 3 11.5 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_14_6_DB 0b00110000 // 5 3 14.6 dB +#define RADIOLIB_CC1101_LNA_GAIN_REDUCE_17_1_DB 0b00111000 // 5 3 17.1 dB +#define RADIOLIB_CC1101_MAGN_TARGET_24_DB 0b00000000 // 2 0 average amplitude target for filter: 24 dB +#define RADIOLIB_CC1101_MAGN_TARGET_27_DB 0b00000001 // 2 0 27 dB +#define RADIOLIB_CC1101_MAGN_TARGET_30_DB 0b00000010 // 2 0 30 dB +#define RADIOLIB_CC1101_MAGN_TARGET_33_DB 0b00000011 // 2 0 33 dB (default) +#define RADIOLIB_CC1101_MAGN_TARGET_36_DB 0b00000100 // 2 0 36 dB +#define RADIOLIB_CC1101_MAGN_TARGET_38_DB 0b00000101 // 2 0 38 dB +#define RADIOLIB_CC1101_MAGN_TARGET_40_DB 0b00000110 // 2 0 40 dB +#define RADIOLIB_CC1101_MAGN_TARGET_42_DB 0b00000111 // 2 0 42 dB + +// RADIOLIB_CC1101_REG_AGCCTRL1 +#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA2 0b00000000 // 6 6 LNA priority setting: LNA2 first +#define RADIOLIB_CC1101_AGC_LNA_PRIORITY_LNA 0b01000000 // 6 6 LNA first (default) +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_OFF 0b00000000 // 5 4 RSSI relative change to assert carrier sense: disabled (default) +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_6_DB 0b00010000 // 5 4 6 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_10_DB 0b00100000 // 5 4 10 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_REL_THR_14_DB 0b00110000 // 5 4 14 dB +#define RADIOLIB_CC1101_CARRIER_SENSE_ABS_THR 0x00 // 3 0 RSSI threshold to assert carrier sense in 2s compliment, Thr = MAGN_TARGET + CARRIER_SENSE_ABS_TH [dB] + +// RADIOLIB_CC1101_REG_AGCCTRL0 +#define RADIOLIB_CC1101_HYST_LEVEL_NONE 0b00000000 // 7 6 AGC hysteresis level: none +#define RADIOLIB_CC1101_HYST_LEVEL_LOW 0b01000000 // 7 6 low +#define RADIOLIB_CC1101_HYST_LEVEL_MEDIUM 0b10000000 // 7 6 medium (default) +#define RADIOLIB_CC1101_HYST_LEVEL_HIGH 0b11000000 // 7 6 high +#define RADIOLIB_CC1101_WAIT_TIME_8_SAMPLES 0b00000000 // 5 4 AGC wait time: 8 samples +#define RADIOLIB_CC1101_WAIT_TIME_16_SAMPLES 0b00010000 // 5 4 16 samples (default) +#define RADIOLIB_CC1101_WAIT_TIME_24_SAMPLES 0b00100000 // 5 4 24 samples +#define RADIOLIB_CC1101_WAIT_TIME_32_SAMPLES 0b00110000 // 5 4 32 samples +#define RADIOLIB_CC1101_AGC_FREEZE_NEVER 0b00000000 // 3 2 freeze AGC gain: never (default) +#define RADIOLIB_CC1101_AGC_FREEZE_SYNC_WORD 0b00000100 // 3 2 when sync word is found +#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_A 0b00001000 // 3 2 manually freeze analog control +#define RADIOLIB_CC1101_AGC_FREEZE_MANUAL_AD 0b00001100 // 3 2 manually freeze analog and digital control +#define RADIOLIB_CC1101_FILTER_LENGTH_8 0b00000000 // 1 0 averaging length for channel filter: 8 samples +#define RADIOLIB_CC1101_FILTER_LENGTH_16 0b00000001 // 1 0 16 samples (default) +#define RADIOLIB_CC1101_FILTER_LENGTH_32 0b00000010 // 1 0 32 samples +#define RADIOLIB_CC1101_FILTER_LENGTH_64 0b00000011 // 1 0 64 samples +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_4_DB 0b00000000 // 1 0 ASK/OOK decision boundary: 4 dB +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_8_DB 0b00000001 // 1 0 8 dB (default) +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_12_DB 0b00000010 // 1 0 12 dB +#define RADIOLIB_CC1101_ASK_OOK_BOUNDARY_16_DB 0b00000011 // 1 0 16 dB + +// RADIOLIB_CC1101_REG_WOREVT1 + REG_WOREVT0 +#define RADIOLIB_CC1101_EVENT0_TIMEOUT_MSB 0x87 // 7 0 EVENT0 timeout: t_event0 = (750 / f(XOSC)) * EVENT0_TIMEOUT * 2^(5 * WOR_RES) [s] +#define RADIOLIB_CC1101_EVENT0_TIMEOUT_LSB 0x6B // 7 0 default value for 26 MHz crystal: 1.0 s + +// RADIOLIB_CC1101_REG_WORCTRL +#define RADIOLIB_CC1101_RC_POWER_UP 0b00000000 // 7 7 power up RC oscillator +#define RADIOLIB_CC1101_RC_POWER_DOWN 0b10000000 // 7 7 power down RC oscillator +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_4 0b00000000 // 6 4 EVENT1 timeout: 4 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_6 0b00010000 // 6 4 6 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_8 0b00100000 // 6 4 8 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_12 0b00110000 // 6 4 12 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_16 0b01000000 // 6 4 16 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_24 0b01010000 // 6 4 24 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_32 0b01100000 // 6 4 32 RC periods +#define RADIOLIB_CC1101_EVENT1_TIMEOUT_48 0b01110000 // 6 4 48 RC periods (default) +#define RADIOLIB_CC1101_RC_CAL_OFF 0b00000000 // 3 3 disable RC oscillator calibration +#define RADIOLIB_CC1101_RC_CAL_ON 0b00001000 // 3 3 enable RC oscillator calibration (default) +#define RADIOLIB_CC1101_WOR_RES_1 0b00000000 // 1 0 EVENT0 resolution: 1 period (default) +#define RADIOLIB_CC1101_WOR_RES_2_5 0b00000001 // 1 0 2^5 periods +#define RADIOLIB_CC1101_WOR_RES_2_10 0b00000010 // 1 0 2^10 periods +#define RADIOLIB_CC1101_WOR_RES_2_15 0b00000011 // 1 0 2^15 periods + +// RADIOLIB_CC1101_REG_FREND1 +#define RADIOLIB_CC1101_LNA_CURRENT 0x01 // 7 6 front-end LNA PTAT current output adjustment +#define RADIOLIB_CC1101_LNA2MIX_CURRENT 0x01 // 5 4 front-end PTAT output adjustment +#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_RX 0x01 // 3 2 Rx LO buffer current adjustment +#define RADIOLIB_CC1101_MIX_CURRENT 0x02 // 1 0 mixer current adjustment + +// RADIOLIB_CC1101_REG_FREND0 +#define RADIOLIB_CC1101_LODIV_BUF_CURRENT_TX 0x01 // 5 4 Tx LO buffer current adjustment +#define RADIOLIB_CC1101_PA_POWER 0x00 // 2 0 set power amplifier power according to PATABLE + +// RADIOLIB_CC1101_REG_FSCAL3 +#define RADIOLIB_CC1101_CHP_CURR_CAL_OFF 0b00000000 // 5 4 disable charge pump calibration +#define RADIOLIB_CC1101_CHP_CURR_CAL_ON 0b00100000 // 5 4 enable charge pump calibration (default) +#define RADIOLIB_CC1101_FSCAL3 0x09 // 3 0 charge pump output current: I_out = I_0 * 2^(FSCAL3/4) [A] + +// RADIOLIB_CC1101_REG_FSCAL2 +#define RADIOLIB_CC1101_VCO_CORE_LOW 0b00000000 // 5 5 VCO: low (default) +#define RADIOLIB_CC1101_VCO_CORE_HIGH 0b00100000 // 5 5 high +#define RADIOLIB_CC1101_FSCAL2 0x0A // 4 0 VCO current result/override + +// RADIOLIB_CC1101_REG_FSCAL1 +#define RADIOLIB_CC1101_FSCAL1 0x20 // 5 0 capacitor array setting for coarse VCO tuning + +// RADIOLIB_CC1101_REG_FSCAL0 +#define RADIOLIB_CC1101_FSCAL0 0x0D // 6 0 frequency synthesizer calibration setting + +// RADIOLIB_CC1101_REG_RCCTRL1 +#define RADIOLIB_CC1101_RCCTRL1 0x41 // 6 0 RC oscillator configuration + +// RADIOLIB_CC1101_REG_RCCTRL0 +#define RADIOLIB_CC1101_RCCTRL0 0x00 // 6 0 RC oscillator configuration + +// RADIOLIB_CC1101_REG_PTEST +#define RADIOLIB_CC1101_TEMP_SENS_IDLE_OFF 0x7F // 7 0 temperature sensor will not be available in idle mode (default) +#define RADIOLIB_CC1101_TEMP_SENS_IDLE_ON 0xBF // 7 0 temperature sensor will be available in idle mode + +// RADIOLIB_CC1101_REG_TEST0 +#define RADIOLIB_CC1101_VCO_SEL_CAL_OFF 0b00000000 // 1 1 disable VCO selection calibration stage +#define RADIOLIB_CC1101_VCO_SEL_CAL_ON 0b00000010 // 1 1 enable VCO selection calibration stage + +// RADIOLIB_CC1101_REG_PARTNUM +#define RADIOLIB_CC1101_PARTNUM 0x00 + +// RADIOLIB_CC1101_REG_VERSION +#define RADIOLIB_CC1101_VERSION_CURRENT 0x14 +#define RADIOLIB_CC1101_VERSION_LEGACY 0x04 +#define RADIOLIB_CC1101_VERSION_CLONE 0x17 + +// RADIOLIB_CC1101_REG_MARCSTATE +#define RADIOLIB_CC1101_MARC_STATE_SLEEP 0x00 // 4 0 main radio control state: sleep +#define RADIOLIB_CC1101_MARC_STATE_IDLE 0x01 // 4 0 idle +#define RADIOLIB_CC1101_MARC_STATE_XOFF 0x02 // 4 0 XOFF +#define RADIOLIB_CC1101_MARC_STATE_VCOON_MC 0x03 // 4 0 VCOON_MC +#define RADIOLIB_CC1101_MARC_STATE_REGON_MC 0x04 // 4 0 REGON_MC +#define RADIOLIB_CC1101_MARC_STATE_MANCAL 0x05 // 4 0 MANCAL +#define RADIOLIB_CC1101_MARC_STATE_VCOON 0x06 // 4 0 VCOON +#define RADIOLIB_CC1101_MARC_STATE_REGON 0x07 // 4 0 REGON +#define RADIOLIB_CC1101_MARC_STATE_STARTCAL 0x08 // 4 0 STARTCAL +#define RADIOLIB_CC1101_MARC_STATE_BWBOOST 0x09 // 4 0 BWBOOST +#define RADIOLIB_CC1101_MARC_STATE_FS_LOCK 0x0A // 4 0 FS_LOCK +#define RADIOLIB_CC1101_MARC_STATE_IFADCON 0x0B // 4 0 IFADCON +#define RADIOLIB_CC1101_MARC_STATE_ENDCAL 0x0C // 4 0 ENDCAL +#define RADIOLIB_CC1101_MARC_STATE_RX 0x0D // 4 0 RX +#define RADIOLIB_CC1101_MARC_STATE_RX_END 0x0E // 4 0 RX_END +#define RADIOLIB_CC1101_MARC_STATE_RX_RST 0x0F // 4 0 RX_RST +#define RADIOLIB_CC1101_MARC_STATE_TXRX_SWITCH 0x10 // 4 0 TXRX_SWITCH +#define RADIOLIB_CC1101_MARC_STATE_RXFIFO_OVERFLOW 0x11 // 4 0 RXFIFO_OVERFLOW +#define RADIOLIB_CC1101_MARC_STATE_FSTXON 0x12 // 4 0 FSTXON +#define RADIOLIB_CC1101_MARC_STATE_TX 0x13 // 4 0 TX +#define RADIOLIB_CC1101_MARC_STATE_TX_END 0x14 // 4 0 TX_END +#define RADIOLIB_CC1101_MARC_STATE_RXTX_SWITCH 0x15 // 4 0 RXTX_SWITCH +#define RADIOLIB_CC1101_MARC_STATE_TXFIFO_UNDERFLOW 0x16 // 4 0 TXFIFO_UNDERFLOW + +// RADIOLIB_CC1101_REG_WORTIME1 + REG_WORTIME0 +#define RADIOLIB_CC1101_WORTIME_MSB 0x00 // 7 0 WOR timer value +#define RADIOLIB_CC1101_WORTIME_LSB 0x00 // 7 0 + +// RADIOLIB_CC1101_REG_PKTSTATUS +#define RADIOLIB_CC1101_CRC_OK 0b10000000 // 7 7 CRC check passed +#define RADIOLIB_CC1101_CRC_ERROR 0b00000000 // 7 7 CRC check failed +#define RADIOLIB_CC1101_CS 0b01000000 // 6 6 carrier sense +#define RADIOLIB_CC1101_PQT_REACHED 0b00100000 // 5 5 preamble quality reached +#define RADIOLIB_CC1101_CCA 0b00010000 // 4 4 channel clear +#define RADIOLIB_CC1101_SFD 0b00001000 // 3 3 start of frame delimiter - sync word received +#define RADIOLIB_CC1101_GDO2_ACTIVE 0b00000100 // 2 2 GDO2 is active/asserted +#define RADIOLIB_CC1101_GDO0_ACTIVE 0b00000001 // 0 0 GDO0 is active/asserted + +// RadioLib defaults +#define RADIOLIB_CC1101_DEFAULT_FREQ 434.0 +#define RADIOLIB_CC1101_DEFAULT_BR 4.8 +#define RADIOLIB_CC1101_DEFAULT_FREQDEV 5.0 +#define RADIOLIB_CC1101_DEFAULT_RXBW 135.0 +#define RADIOLIB_CC1101_DEFAULT_POWER 10 +#define RADIOLIB_CC1101_DEFAULT_PREAMBLELEN 16 +#define RADIOLIB_CC1101_DEFAULT_SW {0x12, 0xAD} +#define RADIOLIB_CC1101_DEFAULT_SW_LEN 2 /*! \class CC1101 - \brief Control class for %CC1101 module. */ class CC1101: public PhysicalLayer { @@ -524,7 +538,6 @@ class CC1101: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ CC1101(Module* module); @@ -535,19 +548,12 @@ class CC1101: public PhysicalLayer { /*! \brief Initialization method. - \param freq Carrier frequency in MHz. Defaults to 434 MHz. - \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. - \param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz. - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength Preamble Length in bits. Defaults to 16 bits. - \returns \ref status_codes */ int16_t begin( @@ -557,17 +563,18 @@ class CC1101: public PhysicalLayer { float rxBw = RADIOLIB_CC1101_DEFAULT_RXBW, int8_t power = RADIOLIB_CC1101_DEFAULT_POWER, uint8_t preambleLength = RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); + + /*! + \brief Reset method - resets the chip using manual reset sequence (without RESET pin). + */ + void reset(); /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; @@ -575,65 +582,54 @@ class CC1101: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; /*! \brief Sets the module to standby mode. - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the module to standby. - \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. - \returns \ref status_codes */ int16_t standby(uint8_t mode) override; /*! \brief Starts direct mode transmission. - \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Starts direct mode reception. - \returns \ref status_codes */ int16_t receiveDirect() override; /*! \brief Starts asynchronous direct mode transmission. - \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirectAsync(uint32_t frf = 0); /*! \brief Starts asynchronous direct mode reception. - \returns \ref status_codes */ int16_t receiveDirectAsync(); /*! - \brief Stops direct mode. It is required to call this method to switch from direct transmissions to packet-based transmissions. + \brief Stops direct mode. It is required to call this method to switch from direct transmissions + to packet-based transmissions. */ int16_t packetMode(); @@ -641,9 +637,7 @@ class CC1101: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when GDO0 activates. - \param func ISR to call. - \param dir Signal change direction. */ void setGdo0Action(void (*func)(void), uint32_t dir); @@ -655,9 +649,7 @@ class CC1101: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when GDO2 activates. - \param func ISR to call. - \param dir Signal change direction. */ void setGdo2Action(void (*func)(void), uint32_t dir); @@ -670,54 +662,40 @@ class CC1101: public PhysicalLayer { /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. - \returns \ref status_codes */ int16_t startReceive(); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param timeout Ignored. - \param irqFlags Ignored. - \param irqMask Ignored. - \param len Ignored. - \returns \ref status_codes */ int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data received after calling startReceive method. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; @@ -725,219 +703,171 @@ class CC1101: public PhysicalLayer { // configuration methods /*! - \brief Sets carrier frequency. Allowed values are in bands 300.0 to 348.0 MHz, 387.0 to 464.0 MHz and 779.0 to 928.0 MHz. - + \brief Sets carrier frequency. Allowed values are in bands 300.0 to 348.0 MHz, + 387.0 to 464.0 MHz and 779.0 to 928.0 MHz. \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets bit rate. Allowed values range from 0.025 to 600.0 kbps. - \param br Bit rate to be set in kbps. - \returns \ref status_codes */ int16_t setBitRate(float br); /*! \brief Sets receiver bandwidth. Allowed values range from 58.0 to 812.0 kHz. - \param rxBw Receiver bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setRxBandwidth(float rxBw); /*! \brief Sets frequency deviation. Allowed values range from 1.587 to 380.8 kHz. - \param freqDev Frequency deviation to be set in kHz. - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Gets frequency deviation. - \param[out] freqDev Pointer to variable where to save the frequency deviation. - \returns \ref status_codes */ int16_t getFrequencyDeviation(float *freqDev); /*! \brief Sets output power. Allowed values are -30, -20, -15, -10, 0, 5, 7 or 10 dBm. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); /*! \brief Sets 16-bit sync word as a two byte value. - \param syncH MSB of the sync word. - \param syncL LSB of the sync word. - \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. - \param requireCarrierSense Require carrier sense above threshold in addition to sync word. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits = 0, bool requireCarrierSense = false); /*! \brief Sets 1 or 2 bytes of sync word. - \param syncWord Pointer to the array of sync word bytes. - \param len Sync word length in bytes. - \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. - \param requireCarrierSense Require carrier sense above threshold in addition to sync word. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false); /*! \brief Sets preamble length. - \param preambleLength Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. - \returns \ref status_codes */ - int16_t setPreambleLength(uint8_t preambleLength); + int16_t setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold); /*! \brief Sets node and broadcast addresses. Calling this method will also enable address filtering. - \param nodeAddr Node address to be set. - - \param numBroadcastAddrs Number of broadcast addresses to be used. Can be set to 0 (no broadcast), 1 (broadcast at 0x00) or 2 (broadcast at 0x00 and 0xFF). - + \param numBroadcastAddrs Number of broadcast addresses to be used. Can be set to 0 (no broadcast), + 1 (broadcast at 0x00) or 2 (broadcast at 0x00 and 0xFF). \returns \ref status_codes */ int16_t setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs = 0); /*! \brief Disables address filtering. Calling this method will also erase previously set addresses. - \returns \ref status_codes */ int16_t disableAddressFiltering(); /*! \brief Enables/disables OOK modulation instead of FSK. - \param enableOOK Enable (true) or disable (false) OOK. - \returns \ref status_codes */ int16_t setOOK(bool enableOOK); /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. - - or in asynchronous direct mode the current RSSI level - + In asynchronous direct mode, returns the current RSSI level. \returns RSSI in dBm. */ float getRSSI(); /*! \brief Gets LQI (Link Quality Indicator) of the last received packet. - \returns Last packet LQI (lower is better). */ uint8_t getLQI() const; /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! \brief Set modem in fixed packet length mode. - \param len Packet length. - \returns \ref status_codes */ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_CC1101_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. - \param len Maximum packet length. - \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_CC1101_MAX_PACKET_LENGTH); /*! \brief Enable sync word filtering and generation. - \param numBits Sync word length in bits. - \param requireCarrierSense Require carrier sense above threshold in addition to sync word. - \returns \ref status_codes */ int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0, bool requireCarrierSense = false); /*! \brief Disable preamble and sync word filtering and generation. - \param requireCarrierSense Require carrier sense above threshold. - \returns \ref status_codes */ int16_t disableSyncWordFiltering(bool requireCarrierSense = false); /*! \brief Enable CRC filtering and generation. - - \param crcOn Set or unset CRC generation and filtering. - + \param enable Set or unset CRC generation and filtering. \returns \ref status_codes */ - int16_t setCrcFiltering(bool crcOn = true); + int16_t setCrcFiltering(bool enable = true); /*! \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). - - \param promiscuous Set or unset promiscuous mode. - + \param enable Set or unset promiscuous mode. \returns \ref status_codes */ - int16_t setPromiscuousMode(bool promiscuous = true); + int16_t setPromiscuousMode(bool enable = true); /*! - \brief Get whether the modem is in promiscuous mode: no packet filtering (e.g., no preamble, sync word, address, CRC). - - \returns Whether the modem is in promiscuous mode + \brief Get whether the modem is in promiscuous mode: no packet filtering + (e.g., no preamble, sync word, address, CRC). + \returns Whether the modem is in promiscuous mode. */ bool getPromiscuousMode(); /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Allowed value is RADIOLIB_SHAPING_0_5. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Gaussian shaping bandwidth-time product that will be used for data shaping. - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; @@ -945,9 +875,7 @@ class CC1101: public PhysicalLayer { /*! \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER, and RADIOLIB_ENCODING_WHITENING. Note that encoding on CC1101 is applied to the entire stream including preamble, sync word, and CRC. - \param encoding Encoding to be used. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; @@ -960,14 +888,13 @@ class CC1101: public PhysicalLayer { /*! \brief Get one truly random byte from RSSI noise. - \returns TRNG byte. */ uint8_t randomByte(); /*! - \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working. - + \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or + CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working. \returns Version register contents or \ref status_codes */ int16_t getChipVersion(); @@ -975,14 +902,12 @@ class CC1101: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. - \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. - \param pin Pin on which to read. */ void readBit(uint32_t pin); @@ -990,11 +915,8 @@ class CC1101: public PhysicalLayer { /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). - \param pin Pin number onto which a signal is to be placed. - \param value The value that indicates which function to place on that pin. See chip datasheet for details. - \returns \ref status_codes */ int16_t setDIOMapping(uint32_t pin, uint32_t value); @@ -1002,7 +924,7 @@ class CC1101: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; // SPI read overrides to set bit for burst write and status registers access int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0); @@ -1018,22 +940,21 @@ class CC1101: public PhysicalLayer { protected: #endif - float _freq = RADIOLIB_CC1101_DEFAULT_FREQ; - float _br = RADIOLIB_CC1101_DEFAULT_BR; - uint8_t _rawRSSI = 0; - uint8_t _rawLQI = 0; - uint8_t _modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; - - size_t _packetLength = 0; - bool _packetLengthQueried = false; - uint8_t _packetLengthConfig = RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE; + float freq = RADIOLIB_CC1101_DEFAULT_FREQ; + float bitRate = RADIOLIB_CC1101_DEFAULT_BR; + uint8_t rawRSSI = 0; + uint8_t rawLQI = 0; + uint8_t modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; - bool _promiscuous = false; - bool _crcOn = true; - bool _directMode = true; + size_t packetLength = 0; + bool packetLengthQueried = false; + uint8_t packetLengthConfig = RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE; - int8_t _power = RADIOLIB_CC1101_DEFAULT_POWER; + bool promiscuous = false; + bool crcOn = true; + bool directModeEnabled = true; + int8_t power = RADIOLIB_CC1101_DEFAULT_POWER; int16_t config(); int16_t transmitDirect(bool sync, uint32_t frf); From cab358ff09ccea11e1cff6b65dfe6fd0d307e434 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 09:57:50 +0200 Subject: [PATCH 0509/1848] [CC1101] Fixed axtra brace --- src/modules/CC1101/CC1101.cpp | 63 +++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 208b47f88a..242c5003e7 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -132,6 +132,8 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { } } + delay(20); + return(finishTransmit()); } @@ -239,8 +241,6 @@ void CC1101::clearGdo0Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } -} - void CC1101::setGdo2Action(void (*func)(void), uint32_t dir) { if(this->mod->getGpio() == RADIOLIB_NC) { return; @@ -258,9 +258,9 @@ void CC1101::clearGdo2Action() { int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length - if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + /*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); - } + }*/ // set mode to standby standby(); @@ -271,6 +271,12 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set GDO0 mapping int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); RADIOLIB_ASSERT(state); + /*int16_t state = RADIOLIB_ERR_NONE; + if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR); + } else { + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED); + }*/ // data put on FIFO uint8_t dataSent = 0; @@ -295,6 +301,13 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // fill the FIFO + /*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, RADIOLIB_CC1101_FIFO_THRESH_TX); + } else { + uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); + dataSent += initialWrite; + }*/ uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); dataSent += initialWrite; @@ -305,6 +318,9 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to transmit SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + return(state); + } // keep feeding the FIFO until the packet is over while (dataSent < len) { @@ -348,10 +364,11 @@ int16_t CC1101::startReceive() { RADIOLIB_ASSERT(state); // flush Rx FIFO - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); // set GDO0 mapping: Asserted when RX FIFO > 4 bytes. state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END); + //state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4, 3, 0); RADIOLIB_ASSERT(state); @@ -375,10 +392,19 @@ int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMa int16_t CC1101::readData(uint8_t* data, size_t len) { // get packet length size_t length = getPacketLength(); + /*RADIOLIB_DEBUG_PRINTLN("length = %d", length); + if(length == 0) { + this->packetLengthQueried = false; + standby(); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + return(RADIOLIB_ERR_RX_TIMEOUT); + }*/ if((len != 0) && (len < length)) { // user requested less data than we got, only return what was requested length = len; } + //SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE | RADIOLIB_CC1101_CMD_READ); + SPIreadRegister(RADIOLIB_CC1101_REG_RXBYTES); // check address filtering uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); @@ -440,14 +466,15 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { this->packetLengthQueried = false; // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) - if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { - - // flush Rx FIFO - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + //if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { // set mode to standby standby(); - } + + // flush Rx FIFO + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); + delay(10); + //} return(RADIOLIB_ERR_NONE); } @@ -795,6 +822,9 @@ uint8_t CC1101::getLQI() const { } size_t CC1101::getPacketLength(bool update) { + RADIOLIB_DEBUG_PRINTLN("this->packetLengthQueried=%d", this->packetLengthQueried); + RADIOLIB_DEBUG_PRINTLN("update=%d", update); + RADIOLIB_DEBUG_PRINTLN("this->packetLengthConfig=%d", this->packetLengthConfig); if(!this->packetLengthQueried && update) { if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { this->packetLength = 0; @@ -808,11 +838,18 @@ size_t CC1101::getPacketLength(bool update) { this->packetLengthQueried = true; } + RADIOLIB_DEBUG_PRINTLN("this->packetLength=%d", this->packetLength); return(this->packetLength); } int16_t CC1101::fixedPacketLengthMode(uint8_t len) { + if(len == 0) { + // infinite packet mode + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0); + RADIOLIB_ASSERT(state); + } + return(setPacketMode(RADIOLIB_CC1101_LENGTH_CONFIG_FIXED, len)); } @@ -844,10 +881,10 @@ int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) { return(state); } -int16_t CC1101::setCrcFiltering(bool crcOn) { - _crcOn = crcOn; +int16_t CC1101::setCrcFiltering(bool enable) { + this->crcOn = enable; - if (crcOn == true) { + if (this->crcOn == true) { return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON, 2, 2)); } else { return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_OFF, 2, 2)); From a015e541f6673c8df9cdc838ff81a480ae586588 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 19:06:45 +0200 Subject: [PATCH 0510/1848] [SX126x] General reformatting --- src/modules/LLCC68/LLCC68.cpp | 4 +- src/modules/LLCC68/LLCC68.h | 18 +- src/modules/SX126x/STM32WLx.cpp | 10 +- src/modules/SX126x/STM32WLx.h | 15 +- src/modules/SX126x/SX1261.cpp | 2 +- src/modules/SX126x/SX1261.h | 8 +- src/modules/SX126x/SX1262.cpp | 2 +- src/modules/SX126x/SX1262.h | 34 +- src/modules/SX126x/SX1268.cpp | 2 +- src/modules/SX126x/SX1268.h | 32 +- src/modules/SX126x/SX126x.cpp | 575 ++++++++++---------- src/modules/SX126x/SX126x.h | 922 ++++++++++++++------------------ 12 files changed, 708 insertions(+), 916 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index a0d077aab4..1a087c4039 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) LLCC68::LLCC68(Module* mod) : SX1262(mod) { - _chipType = RADIOLIB_LLCC68_CHIP_TYPE; + chipType = RADIOLIB_LLCC68_CHIP_TYPE; } int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { @@ -35,7 +35,7 @@ int16_t LLCC68::setBandwidth(float bw) { } int16_t LLCC68::setSpreadingFactor(uint8_t sf) { - switch(SX126x::_bw) { + switch(SX126x::bandwidth) { case RADIOLIB_SX126X_LORA_BW_125_0: RADIOLIB_CHECK_RANGE(sf, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); break; diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 424563ad88..d735aab185 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -9,43 +9,31 @@ #include "../SX126x/SX1262.h" //RADIOLIB_SX126X_REG_VERSION_STRING -#define RADIOLIB_LLCC68_CHIP_TYPE "LLCC68" +#define RADIOLIB_LLCC68_CHIP_TYPE "LLCC68" /*! \class LLCC68 - \brief Derived class for %LLCC68 modules. */ class LLCC68: public SX1262 { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ LLCC68(Module* mod); /*! \brief Initialization method for LoRa modem. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. - \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); @@ -54,18 +42,14 @@ class LLCC68: public SX1262 { /*! \brief Sets LoRa bandwidth. Allowed values are 125.0, 250.0 and 500.0 kHz. - \param bw LoRa bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setBandwidth(float bw); /*! \brief Sets LoRa spreading factor. Allowed values range from 5 to 11, depending on currently set spreading factor. - \param sf LoRa spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 5a88d8c16a..dcc8c82283 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -1,5 +1,4 @@ /* - Copyright (c) 2018 Jan Gromeš Copyright (c) 2022 STMicroelectronics @@ -9,8 +8,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include "STM32WLx.h" #if !defined(RADIOLIB_EXCLUDE_STM32WLX) -STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { -} +STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } int16_t STM32WLx::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // Execute common part @@ -47,18 +45,18 @@ int16_t STM32WLx::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // Use HP only if available and needed for the requested power - bool hp_supported = _mod->findRfSwitchMode(MODE_TX_HP); + bool hp_supported = this->mod->findRfSwitchMode(MODE_TX_HP); bool use_hp = power > 14 && hp_supported; // set PA config. if(use_hp) { RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); state = SX126x::setPaConfig(0x04, 0x00, 0x07); // HP output up to 22dBm - _tx_mode = MODE_TX_HP; + this->txMode = MODE_TX_HP; } else { RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); state = SX126x::setPaConfig(0x04, 0x01, 0x00); // LP output up to 14dBm - _tx_mode = MODE_TX_LP; + this->txMode = MODE_TX_LP; } RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index 0618dd4331..742d8c8cc7 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -1,5 +1,4 @@ /* - Copyright (c) 2018 Jan Gromeš Copyright (c) 2022 STMicroelectronics @@ -38,18 +37,17 @@ class STM32WLx : public SX1262 { public: /*! \brief Default constructor. - \param mod Instance of STM32WLx_Module that will be used to communicate with the radio. */ STM32WLx(STM32WLx_Module* mod); /*! - * \brief Custom operation modes for STMWLx. - * - * This splits the TX mode into two modes: Low-power and high-power. - * These constants can be used with the setRfSwitchTable() method, - * instead of the Module::OpMode_t constants. - */ + \brief Custom operation modes for STMWLx. + + This splits the TX mode into two modes: Low-power and high-power. + These constants can be used with the setRfSwitchTable() method, + instead of the Module::OpMode_t constants. + */ enum OpMode_t { /*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */ MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE, @@ -112,7 +110,6 @@ class STM32WLx : public SX1262 { /*! \brief Sets interrupt service routine to call when DIO1/2/3 activates. - \param func ISR to call. */ void setDio1Action(void (*func)(void)); diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index 41237b67d5..999f4f9f5d 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX1261::SX1261(Module* mod): SX1262(mod) { - _chipType = RADIOLIB_SX1261_CHIP_TYPE; + chipType = RADIOLIB_SX1261_CHIP_TYPE; } int16_t SX1261::setOutputPower(int8_t power) { diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 13c5ff7d7d..8d7663e556 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -10,30 +10,26 @@ #include "SX1262.h" //RADIOLIB_SX126X_CMD_SET_PA_CONFIG -#define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01 +#define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01 //RADIOLIB_SX126X_REG_VERSION_STRING -#define RADIOLIB_SX1261_CHIP_TYPE "SX1261" +#define RADIOLIB_SX1261_CHIP_TYPE "SX1261" /*! \class SX1261 - \brief Derived class for %SX1261 modules. */ class SX1261 : public SX1262 { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1261(Module* mod); /*! \brief Sets output power. Allowed values are in range from -17 to 14 dBm. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 4cd8b9a9b5..baa27ae865 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX1262::SX1262(Module* mod) : SX126x(mod) { - _chipType = RADIOLIB_SX1262_CHIP_TYPE; + chipType = RADIOLIB_SX1262_CHIP_TYPE; } int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index e9919b8379..32fd565cec 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -9,22 +9,20 @@ #include "SX126x.h" //RADIOLIB_SX126X_CMD_SET_PA_CONFIG -#define RADIOLIB_SX126X_PA_CONFIG_SX1262 0x00 +#define RADIOLIB_SX126X_PA_CONFIG_SX1262 0x00 //RADIOLIB_SX126X_REG_VERSION_STRING // Note: this should really be "2", however, it seems that all SX1262 devices report as SX1261 -#define RADIOLIB_SX1262_CHIP_TYPE "SX1261" +#define RADIOLIB_SX1262_CHIP_TYPE "SX1261" /*! \class SX1262 - \brief Derived class for %SX1262 modules. */ class SX1262: public SX126x { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1262(Module* mod); @@ -33,72 +31,46 @@ class SX1262: public SX126x { /*! \brief Initialization method for LoRa modem. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. - \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br FSK bit rate in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. - \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); - - int16_t beginLRFHSS(float freq = 434.0, float tcxoVoltage = 0, bool useRegulatorLDO = false); // configuration methods /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. - \param freq Carrier frequency to be set in MHz. - \param calibrate Run image calibration. - \returns \ref status_codes */ int16_t setFrequency(float freq, bool calibrate); @@ -106,9 +78,7 @@ class SX1262: public SX126x { /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. This method is virtual to allow override from the SX1261 class. - \param power Output power to be set in dBm. - \returns \ref status_codes */ virtual int16_t setOutputPower(int8_t power); diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index db60aef9c2..a2f60f239f 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -2,7 +2,7 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX1268::SX1268(Module* mod) : SX126x(mod) { - _chipType = RADIOLIB_SX1268_CHIP_TYPE; + chipType = RADIOLIB_SX1268_CHIP_TYPE; } int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index ab1bd22251..8c5225b18e 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -9,21 +9,19 @@ #include "SX126x.h" //RADIOLIB_SX126X_CMD_SET_PA_CONFIG -#define RADIOLIB_SX126X_PA_CONFIG_SX1268 0x00 +#define RADIOLIB_SX126X_PA_CONFIG_SX1268 0x00 //RADIOLIB_SX126X_REG_VERSION_STRING -#define RADIOLIB_SX1268_CHIP_TYPE "SX1268" +#define RADIOLIB_SX1268_CHIP_TYPE "SX1268" /*! \class SX1268 - \brief Derived class for %SX1268 modules. */ class SX1268: public SX126x { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1268(Module* mod); @@ -32,48 +30,29 @@ class SX1268: public SX126x { /*! \brief Initialization method for LoRa modem. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. - \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br FSK bit rate in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. - \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); @@ -82,29 +61,22 @@ class SX1268: public SX126x { /*! \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. - \param freq Carrier frequency to be set in MHz. - \param calibrate Run image calibration. - \returns \ref status_codes */ int16_t setFrequency(float freq, bool calibrate); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index fc94f1a009..00e3d1afa0 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -4,48 +4,48 @@ #if !defined(RADIOLIB_EXCLUDE_SX126X) SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { - _mod = mod; + this->mod = mod; this->XTAL = false; } Module* SX126x::getMod() { - return(_mod); + return(this->mod); } int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; - _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; - _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; - _mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; - _mod->SPIstreamType = true; - _mod->SPIparseStatusCb = SPIparseStatus; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; // try to find the SX126x chip - if(!SX126x::findChip(_chipType)) { + if(!SX126x::findChip(this->chipType)) { RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams // set the defaults, this will get overwritten later anyway - _bwKhz = 500.0; - _sf = 9; + this->bandwidthKhz = 500.0; + this->spreadingFactor = 9; // initialize configuration variables (will be overwritten during public settings configuration) - _bw = RADIOLIB_SX126X_LORA_BW_500_0; // initialized to 500 kHz, since lower valeus will interfere with LLCC68 - _cr = RADIOLIB_SX126X_LORA_CR_4_7; - _ldro = 0x00; - _crcType = RADIOLIB_SX126X_LORA_CRC_ON; - _preambleLength = preambleLength; - _tcxoDelay = 0; - _headerType = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT; - _implicitLen = 0xFF; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; // initialized to 500 kHz, since lower valeus will interfere with LLCC68 + this->codingRate = RADIOLIB_SX126X_LORA_CR_4_7; + this->ldrOptimize = 0x00; + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; + this->preambleLengthLoRa = preambleLength; + this->tcxoDelay = 0; + this->headerType = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT; + this->implicitLen = 0xFF; // reset the module and verify startup int16_t state = reset(); @@ -96,33 +96,33 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; - _mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; - _mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; - _mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; - _mod->SPIstreamType = true; - _mod->SPIparseStatusCb = SPIparseStatus; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; // try to find the SX126x chip - if(!SX126x::findChip(_chipType)) { + if(!SX126x::findChip(this->chipType)) { RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); // initialize configuration variables (will be overwritten during public settings configuration) - _br = 21333; // 48.0 kbps - _freqDev = 52428; // 50.0 kHz - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_156_2; - _rxBwKhz = 156.2; - _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; - _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration - _preambleLengthFSK = preambleLength; - _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; + this->bitRate = 21333; // 48.0 kbps + this->freqencyDev = 52428; // 50.0 kHz + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; + this->rxBandwidthKhz = 156.2; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration + this->preambleLengthFSK = preambleLength; + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; // reset the module and verify startup int16_t state = reset(); @@ -190,10 +190,10 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL int16_t SX126x::reset(bool verify) { // run the reset sequence - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); // return immediately when verification is disabled if(!verify) { @@ -201,7 +201,7 @@ int16_t SX126x::reset(bool verify) { } // set mode to standby - SX126x often refuses first few commands after reset - uint32_t start = _mod->hal->millis(); + uint32_t start = this->mod->hal->millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -211,13 +211,13 @@ int16_t SX126x::reset(bool verify) { } // standby command failed, check timeout and try again - if(_mod->hal->millis() - start >= 1000) { + if(this->mod->hal->millis() - start >= 1000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - _mod->hal->delay(100); + this->mod->hal->delay(100); } } @@ -254,18 +254,18 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - uint32_t elapsed = _mod->hal->micros() - start; + uint32_t elapsed = this->mod->hal->micros() - start; // update data rate - _dataRate = (len*8.0)/((float)elapsed/1000000.0); + this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0); return(finishTransmit()); } @@ -281,7 +281,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) - float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz; + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) @@ -289,7 +289,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { if(len == 0) { maxLen = 0xFF; } - float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br; + float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0); } else { @@ -304,10 +304,10 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { fixImplicitTimeout(); clearIrqStatus(); standby(); @@ -316,7 +316,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { } // fix timeout in implicit LoRa mode - if(((_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { + if(((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { state = fixImplicitTimeout(); RADIOLIB_ASSERT(state); } @@ -327,7 +327,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { int16_t SX126x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(_tx_mode); + this->mod->setRfSwitchState(this->txMode); // user requested to start transmitting immediately (required for RTTY) int16_t state = RADIOLIB_ERR_NONE; @@ -338,12 +338,12 @@ int16_t SX126x::transmitDirect(uint32_t frf) { // start transmitting uint8_t data[] = {RADIOLIB_SX126X_CMD_NOP}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); } int16_t SX126x::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // SX126x is unable to output received data directly return(RADIOLIB_ERR_UNKNOWN); @@ -365,13 +365,13 @@ int16_t SX126x::directMode() { // set DIO2 to clock output and DIO3 to data input // this is done exclusively by writing magic values to even more magic registers - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_ENABLED, 6, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_ENABLED, 6, 4); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_ENABLED, 3, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_ENABLED, 3, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_DISABLED, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_DISABLED, 3, 3); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_ENABLED, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_ENABLED, 3, 3); RADIOLIB_ASSERT(state); // enable TxDone interrupt @@ -399,13 +399,13 @@ int16_t SX126x::packetMode() { RADIOLIB_ASSERT(state); // restore the magic registers - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_DISABLED, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_IN_ENABLE, RADIOLIB_SX126X_DIO3_IN_DISABLED, 3, 3); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_ENABLED, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE, RADIOLIB_SX126X_DIO3_OUT_ENABLED, 3, 3); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_DISABLED, 3, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0, RADIOLIB_SX126X_TX_BITBANG_0_DISABLED, 3, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_DISABLED, 6, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1, RADIOLIB_SX126X_TX_BITBANG_1_DISABLED, 6, 4); RADIOLIB_ASSERT(state); // enable DIO2 RF switch @@ -421,8 +421,8 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); } // check CAD result @@ -431,16 +431,16 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) int16_t SX126x::sleep(bool retainConfig) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF; if(!retainConfig) { sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; } - int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); // wait for SX126x to safely enter sleep mode - _mod->hal->delay(1); + this->mod->hal->delay(1); return(state); } @@ -451,18 +451,18 @@ int16_t SX126x::standby() { int16_t SX126x::standby(uint8_t mode) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = {mode}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } void SX126x::setDio1Action(void (*func)(void)) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptRising); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); } void SX126x::clearDio1Action() { - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -475,7 +475,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // maximum packet length is decreased by 1 when address filtering is active - if((_addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { + if((this->addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } @@ -483,9 +483,9 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - state = setPacketParams(_preambleLength, _crcType, len, _headerType, _invertIQ); + state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType, len); + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); } else { return(RADIOLIB_ERR_UNKNOWN); } @@ -512,15 +512,15 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(_tx_mode); + this->mod->setRfSwitchState(this->txMode); // start transmission state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(_mod->hal->digitalRead(_mod->getGpio())) { - _mod->hal->yield(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); } return(state); @@ -540,7 +540,7 @@ int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMa RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to receive state = setRx(timeout); @@ -550,7 +550,7 @@ int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMa int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags, uint16_t irqMask) { // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay - uint32_t transitionTime = _tcxoDelay + 1000; + uint32_t transitionTime = this->tcxoDelay + 1000; sleepPeriod -= transitionTime; // divide by 15.625 @@ -572,12 +572,12 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, u uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), (uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); } int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, uint16_t irqFlags, uint16_t irqMask) { if(senderPreambleLength == 0) { - senderPreambleLength = _preambleLength; + senderPreambleLength = this->preambleLengthLoRa; } // worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep. @@ -590,7 +590,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ return(startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask)); } - uint32_t symbolLength = ((uint32_t)(10 * 1000) << _sf) / (10 * _bwKhz); + uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz); uint32_t sleepPeriod = symbolLength * sleepSymbols; RADIOLIB_DEBUG_PRINTLN("Auto sleep period: %d", sleepPeriod); @@ -606,7 +606,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ RADIOLIB_DEBUG_PRINTLN("Auto wake period: ", wakePeriod); // If our sleep period is shorter than our transition time, just use the standard startReceive - if(sleepPeriod < _tcxoDelay + 1016) { + if(sleepPeriod < this->tcxoDelay + 1016) { return(startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask)); } @@ -631,9 +631,9 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, uint16_t irqFlags, uint16_t // restore original packet length uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - state = setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ); + state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); } else { return(RADIOLIB_ERR_UNKNOWN); } @@ -645,7 +645,7 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { // this method may get called from receive() after Rx timeout // if that's the case, the first call will return "SPI command timeout error" // check the IRQ to be sure this really originated from timeout event - int16_t state = _mod->SPIcheckStream(); + int16_t state = this->mod->SPIcheckStream(); if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { // this is definitely Rx timeout return(RADIOLIB_ERR_RX_TIMEOUT); @@ -694,7 +694,7 @@ int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set DIO pin mapping state = setDioIrqParams(RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE, RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE); @@ -743,42 +743,42 @@ int16_t SX126x::setBandwidth(float bw) { uint8_t bw_div2 = bw / 2 + 0.01; switch (bw_div2) { case 3: // 7.8: - _bw = RADIOLIB_SX126X_LORA_BW_7_8; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8; break; case 5: // 10.4: - _bw = RADIOLIB_SX126X_LORA_BW_10_4; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4; break; case 7: // 15.6: - _bw = RADIOLIB_SX126X_LORA_BW_15_6; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6; break; case 10: // 20.8: - _bw = RADIOLIB_SX126X_LORA_BW_20_8; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8; break; case 15: // 31.25: - _bw = RADIOLIB_SX126X_LORA_BW_31_25; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25; break; case 20: // 41.7: - _bw = RADIOLIB_SX126X_LORA_BW_41_7; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7; break; case 31: // 62.5: - _bw = RADIOLIB_SX126X_LORA_BW_62_5; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5; break; case 62: // 125.0: - _bw = RADIOLIB_SX126X_LORA_BW_125_0; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0; break; case 125: // 250.0 - _bw = RADIOLIB_SX126X_LORA_BW_250_0; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0; break; case 250: // 500.0 - _bw = RADIOLIB_SX126X_LORA_BW_500_0; + this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; break; default: return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // update modulation parameters - _bwKhz = bw; - return(setModulationParams(_sf, _bw, _cr, _ldro)); + this->bandwidthKhz = bw; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } int16_t SX126x::setSpreadingFactor(uint8_t sf) { @@ -790,8 +790,8 @@ int16_t SX126x::setSpreadingFactor(uint8_t sf) { RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); // update modulation parameters - _sf = sf; - return(setModulationParams(_sf, _bw, _cr, _ldro)); + this->spreadingFactor = sf; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } int16_t SX126x::setCodingRate(uint8_t cr) { @@ -803,8 +803,8 @@ int16_t SX126x::setCodingRate(uint8_t cr) { RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters - _cr = cr - 4; - return(setModulationParams(_sf, _bw, _cr, _ldro)); + this->codingRate = cr - 4; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { @@ -843,11 +843,11 @@ float SX126x::getCurrentLimit() { int16_t SX126x::setPreambleLength(uint16_t preambleLength) { uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - _preambleLength = preambleLength; - return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ)); + this->preambleLengthLoRa = preambleLength; + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - _preambleLengthFSK = preambleLength; - return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType)); + this->preambleLengthFSK = preambleLength; + return(setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType)); } return(RADIOLIB_ERR_UNKNOWN); @@ -871,28 +871,31 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0)); // check modulation parameters - _freqDev = freqDevRaw; + this->freqencyDev = freqDevRaw; // update modulation parameters - return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); } int16_t SX126x::setBitRate(float br) { // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + uint8_t modem = getPacketType(); + if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + } // calculate raw bit rate value uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); // check modulation parameters - _br = brRaw; + this->bitRate = brRaw; // update modulation parameters - return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); } int16_t SX126x::setRxBandwidth(float rxBw) { @@ -902,60 +905,60 @@ int16_t SX126x::setRxBandwidth(float rxBw) { } // check modulation parameters - /*if(2 * _freqDev + _br > rxBw * 1000.0) { + /*if(2 * this->freqencyDev + this->bitRate > rxBw * 1000.0) { return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); }*/ - _rxBwKhz = rxBw; + this->rxBandwidthKhz = rxBw; // check allowed receiver bandwidth values if(fabs(rxBw - 4.8) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_4_8; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8; } else if(fabs(rxBw - 5.8) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_5_8; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8; } else if(fabs(rxBw - 7.3) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_7_3; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3; } else if(fabs(rxBw - 9.7) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_9_7; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7; } else if(fabs(rxBw - 11.7) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_11_7; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7; } else if(fabs(rxBw - 14.6) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_14_6; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6; } else if(fabs(rxBw - 19.5) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_19_5; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5; } else if(fabs(rxBw - 23.4) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_23_4; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4; } else if(fabs(rxBw - 29.3) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_29_3; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3; } else if(fabs(rxBw - 39.0) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_39_0; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0; } else if(fabs(rxBw - 46.9) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_46_9; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9; } else if(fabs(rxBw - 58.6) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_58_6; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6; } else if(fabs(rxBw - 78.2) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_78_2; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2; } else if(fabs(rxBw - 93.8) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_93_8; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8; } else if(fabs(rxBw - 117.3) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_117_3; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3; } else if(fabs(rxBw - 156.2) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_156_2; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; } else if(fabs(rxBw - 187.2) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_187_2; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2; } else if(fabs(rxBw - 234.3) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_234_3; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3; } else if(fabs(rxBw - 312.0) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_312_0; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0; } else if(fabs(rxBw - 373.6) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_373_6; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6; } else if(fabs(rxBw - 467.0) <= 0.001) { - _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_467_0; + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0; } else { return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } // update modulation parameters - return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); } int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { @@ -1004,26 +1007,26 @@ int16_t SX126x::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE; break; case RADIOLIB_SHAPING_0_3: - _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3; break; case RADIOLIB_SHAPING_0_5: - _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; break; case RADIOLIB_SHAPING_0_7: - _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7; break; case RADIOLIB_SHAPING_1_0: - _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; break; default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } // update modulation parameters - return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); } int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) { @@ -1042,8 +1045,8 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) { RADIOLIB_ASSERT(state); // update packet parameters - _syncWordLength = len * 8; - state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + this->syncWordLength = len * 8; + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); return(state); } @@ -1069,8 +1072,8 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { RADIOLIB_ASSERT(state); // update packet parameters - _syncWordLength = bitsLen; - state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + this->syncWordLength = bitsLen; + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); return(state); } @@ -1082,8 +1085,8 @@ int16_t SX126x::setNodeAddress(uint8_t nodeAddr) { } // enable address filtering (node only) - _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE; - int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE; + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // set node address @@ -1099,8 +1102,8 @@ int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) { } // enable address filtering (node and broadcast) - _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; - int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // set broadcast address @@ -1116,8 +1119,8 @@ int16_t SX126x::disableAddressFiltering() { } // disable address filtering - _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; - return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening)); + this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; + return(setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening)); } int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { @@ -1128,27 +1131,27 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool // update packet parameters switch(len) { case 0: - _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF; break; case 1: if(inverted) { - _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV; } else { - _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE; } break; case 2: if(inverted) { - _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; } else { - _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE; + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE; } break; default: return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // write initial CRC value @@ -1168,12 +1171,12 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool // update packet parameters if(len) { - _crcType = RADIOLIB_SX126X_LORA_CRC_ON; + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; } else { - _crcType = RADIOLIB_SX126X_LORA_CRC_OFF; + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF; } - return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ)); + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } return(RADIOLIB_ERR_UNKNOWN); @@ -1188,14 +1191,14 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { int16_t state = RADIOLIB_ERR_NONE; if(!enabled) { // disable whitening - _whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; + this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; - state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); } else { // enable whitening - _whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON; + this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON; // write initial whitening value // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register" @@ -1210,14 +1213,14 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); RADIOLIB_ASSERT(state); - state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); } return(state); } float SX126x::getDataRate() const { - return(_dataRate); + return(this->dataRateMeasured); } float SX126x::getRSSI(bool packet) { @@ -1229,7 +1232,7 @@ float SX126x::getRSSI(bool packet) { } else { // get instantaneous RSSI value uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); return((float)data[0] / (-2.0)); } } @@ -1275,9 +1278,9 @@ float SX126x::getFrequencyError() { // frequency error is negative efe |= (uint32_t) 0xFFF00000; efe = ~efe + 1; - error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz) * -1.0; + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0; } else { - error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz); + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz); } return(error); @@ -1287,12 +1290,12 @@ size_t SX126x::getPacketLength(bool update) { (void)update; // in implicit mode, return the cached value - if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) { - return(_implicitLen); + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) { + return(this->implicitLen); } uint8_t rxBufStatus[2] = {0, 0}; - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } @@ -1308,22 +1311,22 @@ uint32_t SX126x::getTimeOnAir(size_t len) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << _sf) / (_bwKhz * 10) ; + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) uint8_t sfCoeff2 = 8; - if(_sf == 5 || _sf == 6) { + if(this->spreadingFactor == 5 || this->spreadingFactor == 6) { sfCoeff1_x4 = 25; // 6.25 * 4 sfCoeff2 = 0; } - uint8_t sfDivisor = 4*_sf; + uint8_t sfDivisor = 4*this->spreadingFactor; if(symbolLength_us >= 16000) { - sfDivisor = 4*(_sf - 2); + sfDivisor = 4*(this->spreadingFactor - 2); } const int8_t bitsPerCrc = 16; - const int8_t N_symbol_header = _headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; + const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) - int16_t bitCount = (int16_t) 8 * len + _crcType * bitsPerCrc - 4 * _sf + sfCoeff2 + N_symbol_header; + int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header; if(bitCount < 0) { bitCount = 0; } @@ -1331,11 +1334,11 @@ uint32_t SX126x::getTimeOnAir(size_t len) { uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit - uint32_t nSymbol_x4 = (_preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (_cr + 4) * 4; + uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; return((symbolLength_us * nSymbol_x4) / 4); } else { - return((len * 8 * _br) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); + return((len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); } } @@ -1360,11 +1363,11 @@ int16_t SX126x::setEncoding(uint8_t encoding) { } void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - _mod->setRfSwitchPins(rxEn, txEn); + this->mod->setRfSwitchPins(rxEn, txEn); } void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - _mod->setRfSwitchTable(pins, table); + this->mod->setRfSwitchTable(pins, table); } int16_t SX126x::forceLDRO(bool enable) { @@ -1374,9 +1377,9 @@ int16_t SX126x::forceLDRO(bool enable) { } // update modulation parameters - _ldroAuto = false; - _ldro = (uint8_t)enable; - return(setModulationParams(_sf, _bw, _cr, _ldro)); + this->ldroAuto = false; + this->ldrOptimize = (uint8_t)enable; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } int16_t SX126x::autoLDRO() { @@ -1384,20 +1387,20 @@ int16_t SX126x::autoLDRO() { return(RADIOLIB_ERR_WRONG_MODEM); } - _ldroAuto = true; + this->ldroAuto = true; return(RADIOLIB_ERR_NONE); } uint8_t SX126x::randomByte() { // set some magic registers - _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_ENABLED, 0, 0); - _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_ENABLED, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_ENABLED, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_ENABLED, 0, 0); // set mode to Rx setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); // wait a bit for the RSSI reading to stabilise - _mod->hal->delay(10); + this->mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; @@ -1411,24 +1414,24 @@ uint8_t SX126x::randomByte() { standby(); // restore the magic registers - _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_DISABLED, 0, 0); - _mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_DISABLED, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_DISABLED, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_MIXER, RADIOLIB_SX126X_MIXER_RNG_DISABLED, 0, 0); return(randByte); } -int16_t SX126x::invertIQ(bool invertIQ) { +int16_t SX126x::invertIQ(bool enable) { if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } - if(invertIQ) { - _invertIQ = RADIOLIB_SX126X_LORA_IQ_INVERTED; + if(enable) { + this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED; } else { - _invertIQ = RADIOLIB_SX126X_LORA_IQ_STANDARD; + this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; } - return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType, _invertIQ)); + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) @@ -1437,7 +1440,7 @@ void SX126x::setDirectAction(void (*func)(void)) { } void SX126x::readBit(uint32_t pin) { - updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); } #endif @@ -1449,12 +1452,12 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) // check the version #if defined(RADIOLIB_DEBUG) char ver_pre[16]; - _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %d", ver_pre); #endif // enable patch update - _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_ENABLED); + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_ENABLED); // upload the patch uint8_t data[4]; @@ -1469,19 +1472,19 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) data[1] = (bin >> 16) & 0xFF; data[2] = (bin >> 8) & 0xFF; data[3] = bin & 0xFF; - _mod->SPIwriteRegisterBurst(RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE + i*sizeof(uint32_t), data, sizeof(uint32_t)); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE + i*sizeof(uint32_t), data, sizeof(uint32_t)); } // disable patch update - _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_DISABLED); + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_DISABLED); // update - _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); + this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); // check the version again #if defined(RADIOLIB_DEBUG) char ver_post[16]; - _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); RADIOLIB_DEBUG_PRINTLN("Post-update version string: %d", ver_post); #endif @@ -1493,7 +1496,7 @@ int16_t SX126x::spectralScanStart(uint16_t numSamples, uint8_t window, uint8_t i spectralScanAbort(); // set the RSSI window size - _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, window); + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, window); // start Rx with infinite timeout int16_t state = setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF); @@ -1501,15 +1504,15 @@ int16_t SX126x::spectralScanStart(uint16_t numSamples, uint8_t window, uint8_t i // now set the actual spectral scan parameters uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval }; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); } void SX126x::spectralScanAbort() { - _mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00); + this->mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00); } int16_t SX126x::spectralScanGetStatus() { - uint8_t status = _mod->SPIreadRegister(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS); + uint8_t status = this->mod->SPIreadRegister(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS); if(status == RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED) { return(RADIOLIB_ERR_NONE); } @@ -1519,7 +1522,7 @@ int16_t SX126x::spectralScanGetStatus() { int16_t SX126x::spectralScanGetResult(uint16_t* results) { // read the raw results uint8_t data[2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; - _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT, 2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, data); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT, 2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, data); // convert it for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { @@ -1575,10 +1578,10 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { data[2] = (uint8_t)((delayValue >> 8) & 0xFF); data[3] = (uint8_t)(delayValue & 0xFF); - _tcxoDelay = delay; + this->tcxoDelay = delay; // enable TCXO control on DIO3 - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); } int16_t SX126x::setDio2AsRfSwitch(bool enable) { @@ -1588,21 +1591,21 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { } else { data = RADIOLIB_SX126X_DIO2_AS_IRQ; } - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } int16_t SX126x::setFs() { - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); } int16_t SX126x::setTx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); } int16_t SX126x::setRx(uint32_t timeout) { uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { @@ -1618,8 +1621,8 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { RADIOLIB_SX126X_CAD_ON_4_SYMB }; // build the packet uint8_t data[7]; - data[0] = symbolNumValues[_sf - 5]; - data[1] = detPeakValues[_sf - 5]; + data[0] = symbolNumValues[this->spreadingFactor - 5]; + data[1] = detPeakValues[this->spreadingFactor - 5]; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[4] = 0x00; @@ -1640,40 +1643,40 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { } // configure paramaters - int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); // start CAD - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); } int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); } int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - _mod->SPIwriteRegisterBurst(addr, data, numBytes); + this->mod->SPIwriteRegisterBurst(addr, data, numBytes); return(RADIOLIB_ERR_NONE); } int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { // send the command - _mod->SPIreadRegisterBurst(addr, numBytes, data); + this->mod->SPIreadRegisterBurst(addr, numBytes, data); // check the status - int16_t state = _mod->SPIcheckStream(); + int16_t state = this->mod->SPIcheckStream(); return(state); } int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; - return(_mod->SPIwriteStream(cmd, 2, data, numBytes)); + return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); } int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; - return(_mod->SPIreadStream(cmd, 2, data, numBytes)); + return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); } int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { @@ -1681,27 +1684,27 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } uint16_t SX126x::getIrqStatus() { uint8_t data[] = { 0x00, 0x00 }; - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX126x::setRfFrequency(uint32_t frf) { uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } int16_t SX126x::calibrateImage(uint8_t* data) { - int16_t state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors #if defined(RADIOLIB_DEBUG) @@ -1717,13 +1720,13 @@ int16_t SX126x::calibrateImage(uint8_t* data) { uint8_t SX126x::getPacketType() { uint8_t data = 0xFF; - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); return(data); } int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) { uint8_t data[] = { power, rampTime }; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { @@ -1733,103 +1736,103 @@ int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { } // set requested packet mode - int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, mode, len); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, mode, len); RADIOLIB_ASSERT(state); // update cached value - _packetType = mode; + this->packetType = mode; return(state); } -int16_t SX126x::setHeaderType(uint8_t headerType, size_t len) { +int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } // set requested packet mode - int16_t state = setPacketParams(_preambleLength, _crcType, len, headerType, _invertIQ); + int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled); RADIOLIB_ASSERT(state); // update cached value - _headerType = headerType; - _implicitLen = len; + this->headerType = hdrType; + this->implicitLen = len; return(state); } int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled - if(_ldroAuto) { - float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz; + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; RADIOLIB_DEBUG_PRINTLN("Symbol length: %d ms", symbolLength); if(symbolLength >= 16.0) { - _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; + this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; } else { - _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; + this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; } } else { - _ldro = ldro; + this->ldrOptimize = ldro; } // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 - uint8_t data[4] = {sf, bw, cr, _ldro}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); + uint8_t data[4] = {sf, bw, cr, this->ldrOptimize}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); } int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), pulseShape, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); } -int16_t SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) { +int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) { int16_t state = fixInvertedIQ(invertIQ); RADIOLIB_ASSERT(state); - uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); + uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); } -int16_t SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType, uint8_t payloadLength, uint8_t preambleDetectorLength) { - uint8_t data[9] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), - preambleDetectorLength, syncWordLength, addrComp, - packetType, payloadLength, crcType, whitening}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); +int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen, uint8_t preambleDetectorLen) { + uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + preambleDetectorLen, syncWordLen, addrCmp, + packType, payloadLen, crcType, whiten}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); } int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { uint8_t data[2] = {txBaseAddress, rxBaseAddress}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX126x::setRegulatorMode(uint8_t mode) { uint8_t data[1] = {mode}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); } uint8_t SX126x::getStatus() { uint8_t data = 0; - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1); return(data); } uint32_t SX126x::getPacketStatus() { uint8_t data[3] = {0, 0, 0}; - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]); } uint16_t SX126x::getDeviceErrors() { uint8_t data[2] = {0, 0}; - _mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]); return(opError); } int16_t SX126x::clearDeviceErrors() { uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; - return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); } int16_t SX126x::setFrequencyRaw(float freq) { @@ -1848,7 +1851,7 @@ int16_t SX126x::fixSensitivity() { RADIOLIB_ASSERT(state); // fix the value for LoRa with 500 kHz bandwidth - if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabs(_bwKhz - 500.0) <= 0.001)) { + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabs(this->bandwidthKhz - 500.0) <= 0.001)) { sensitivityConfig &= 0xFB; } else { sensitivityConfig |= 0x04; @@ -1879,7 +1882,7 @@ int16_t SX126x::fixImplicitTimeout() { // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.3 for details //check if we're in implicit LoRa mode - if(!((_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { + if(!((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -1926,23 +1929,23 @@ int16_t SX126x::config(uint8_t modem) { // set modem uint8_t data[7]; data[0] = modem; - state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); RADIOLIB_ASSERT(state); // set Rx/Tx fallback mode to STDBY_RC data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; - state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); // set some CAD parameters - will be overwritten whel calling CAD anyway data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; - data[1] = _sf + 13; + data[1] = this->spreadingFactor + 13; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[4] = 0x00; data[5] = 0x00; data[6] = 0x00; - state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); // clear IRQ @@ -1952,17 +1955,17 @@ int16_t SX126x::config(uint8_t modem) { // calibrate all blocks data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; - state = _mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); RADIOLIB_ASSERT(state); // wait for calibration completion - _mod->hal->delay(5); - while(_mod->hal->digitalRead(_mod->getGpio())) { - _mod->hal->yield(); + this->mod->hal->delay(5); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); } // check calibration result - state = _mod->SPIcheckStream(); + state = this->mod->SPIcheckStream(); // if something failed, show the device errors #if defined(RADIOLIB_DEBUG) @@ -1999,21 +2002,21 @@ bool SX126x::findChip(const char* verStr) { // read the version string char version[16]; - _mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version); // check version register if(strncmp(verStr, version, 6) == 0) { RADIOLIB_DEBUG_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); - _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + this->mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN(); flagFound = true; } else { #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); - _mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + this->mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); #endif - _mod->hal->delay(10); + this->mod->hal->delay(10); i++; } } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index fd33c71320..5f92024fc9 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -10,29 +10,29 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // SX126X physical layer properties -#define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 -#define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0 -#define RADIOLIB_SX126X_DIV_EXPONENT 25 +#define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 +#define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX126X_DIV_EXPONENT 25 // SX126X SPI commands // operational modes commands -#define RADIOLIB_SX126X_CMD_NOP 0x00 -#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84 -#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80 -#define RADIOLIB_SX126X_CMD_SET_FS 0xC1 -#define RADIOLIB_SX126X_CMD_SET_TX 0x83 -#define RADIOLIB_SX126X_CMD_SET_RX 0x82 -#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F -#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 -#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5 -#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 -#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 -#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96 -#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89 -#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98 -#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95 -#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 +#define RADIOLIB_SX126X_CMD_NOP 0x00 +#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX126X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX126X_CMD_SET_TX 0x83 +#define RADIOLIB_SX126X_CMD_SET_RX 0x82 +#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F +#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 +#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89 +#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98 +#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95 +#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 // register and buffer access commands #define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D @@ -41,403 +41,402 @@ #define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E // DIO and IRQ control -#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 -#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12 -#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02 -#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D -#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 +#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 +#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12 +#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02 +#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D +#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 // RF, modulation and packet commands -#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86 -#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A -#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11 -#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E -#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B -#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C -#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 -#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F -#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A +#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11 +#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A // status commands -#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 -#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15 -#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 -#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14 -#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17 -#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 -#define RADIOLIB_SX126X_CMD_GET_STATS 0x10 -#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 - -#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 -#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A -#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B +#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15 +#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 +#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14 +#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17 +#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 +#define RADIOLIB_SX126X_CMD_GET_STATS 0x10 +#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 + +#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 +#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A +#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B // SX126X register map -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 -#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 -#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 -#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 -#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) -#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 -#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 -#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582 -#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 -#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 -#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 -#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 -#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 -#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 -#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 -#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 -#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB -#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC -#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD -#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE -#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF -#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0 -#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1 -#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2 -#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3 -#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4 -#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5 -#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6 -#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 -#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD -#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE -#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 -#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 -#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 -#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 -#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 -#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 -#define RADIOLIB_SX126X_REG_FREQ_ERROR 0x076B -#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD -#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C -#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E -#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B -#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC -#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 -#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 -#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 -#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 -#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5 -#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 -#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 -#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 -#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 -#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 -#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 -#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 +#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 +#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 +#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 +#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582 +#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 +#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 +#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 +#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 +#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB +#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC +#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF +#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0 +#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1 +#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2 +#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3 +#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4 +#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5 +#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6 +#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 +#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD +#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 +#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 +#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 +#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 +#define RADIOLIB_SX126X_REG_FREQ_ERROR 0x076B +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD +#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C +#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E +#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B +#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC +#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 +#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 +#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5 +#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 +#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 +#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 +#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 +#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 +#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 +#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 // SX126X SPI command variables -//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION -#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) -#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained -#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled -#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled +//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION +#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) +#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained +#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled +#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled //RADIOLIB_SX126X_CMD_SET_STANDBY -#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator -#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator +#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator //RADIOLIB_SX126X_CMD_SET_RX -#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) -#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) +#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) //RADIOLIB_SX126X_CMD_SET_TX -#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) +#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) //RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE -#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) -#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection //RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE -#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) -#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC +#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC //RADIOLIB_SX126X_CMD_CALIBRATE -#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled -#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks //RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 //RADIOLIB_SX126X_CMD_SET_PA_CONFIG -#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 -#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 -#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 +#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 +#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 +#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 //RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) //RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop -#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout -#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected -#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished -#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received -#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error -#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received -#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected -#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected -#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received -#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed -#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR) -#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts -#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts +#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop +#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout +#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected +#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished +#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received +#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error +#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received +#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected +#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received +#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR) +#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts +#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts //RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL -#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ -#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control +#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ +#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control //RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V //RADIOLIB_SX126X_CMD_SET_PACKET_TYPE -#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK -#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa -#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS +#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK +#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS //RADIOLIB_SX126X_CMD_SET_TX_PARAMS -#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us -#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us -#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us -#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us -#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us -#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us -#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us -#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us +#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us +#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us +#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us +#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us +#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us +#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us +#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us +#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us //RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS -#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 -#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz -#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz -#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz -#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz -#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz -#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz -#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz -#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz -#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz -#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz -#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz -#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 -#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 -#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 -#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 -#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled -#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 +#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz +#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz +#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz +#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz +#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz +#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz +#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz +#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz +#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz +#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz +#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz +#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled //RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast -#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) -#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) -#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled -#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte -#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte -#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted -#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted -#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled -#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled -#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit -#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit -#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled -#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled -#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard -#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast +#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) +#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) +#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted +#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled +#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit +#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled +#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard +#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted //RADIOLIB_SX126X_CMD_SET_CAD_PARAMS -#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 -#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 -#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 -#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 -#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 -#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode -#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected -#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value -#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter +#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 +#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 +#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 +#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 +#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode +#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected +#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value +#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter //RADIOLIB_SX126X_CMD_GET_STATUS -#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC -#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC -#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS -#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX -#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX -#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved -#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out -#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command -#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute -#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done -#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC +#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS +#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX +#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX +#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved +#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out +#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command +#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute +#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done +#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed //RADIOLIB_SX126X_CMD_GET_PACKET_STATUS -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent //RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS -#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed -#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock -#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start -#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed -#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed -#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed -#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed -#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed +#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed +#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock +#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start +#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed +#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed +#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed +#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed +#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed //RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS -#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us -#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us -#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us // SX126X SPI register variables //RADIOLIB_SX126X_REG_HOPPING_ENABLE -#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled -#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) +#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled +#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) //RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB -#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. -#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. +#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. +#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. // RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 -#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default) -#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled +#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled // RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 -#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default) -#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled +#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled // RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE -#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled -#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled -#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled -#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled -#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled -#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled +#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled +#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled +#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled +#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled // RADIOLIB_SX126X_REG_DIOX_IN_ENABLE -#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled -#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled -#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled -#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled -#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled -#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled +#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled +#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled +#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled +#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled // RADIOLIB_SX126X_REG_RX_GAIN -#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted -#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving -#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan +#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted +#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving +#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan // RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE -#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled -#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled +#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled +#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled // RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS -#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none -#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing -#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted -#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed +#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted +#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed // RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW -#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window +#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window // RADIOLIB_SX126X_REG_ANA_LNA -#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled -#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled +#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled +#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled // RADIOLIB_SX126X_REG_ANA_MIXER -#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled -#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled +#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled +#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled // size of the spectral scan result -#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) +#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) /*! \class SX126x - \brief Base class for %SX126x series. All derived classes for %SX126x (e.g. SX1262 or SX1268) inherit from this base class. This class should not be instantiated directly from Arduino sketch, only from its derived classes. */ @@ -451,7 +450,6 @@ class SX126x: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX126x(Module* mod); @@ -467,46 +465,32 @@ class SX126x: public PhysicalLayer { /*! \brief Initialization method for LoRa modem. - \param cr LoRa coding rate denominator. Allowed values range from 5 to 8. - \param syncWord 1-byte LoRa sync word. - \param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. - \param br FSK bit rate in kbps. Allowed values range from 0.6 to 300.0 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Allowed values range from 0.0 to 200.0 kHz. - - \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. - + \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, + 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. \param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. - \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. - \returns \ref status_codes */ int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. - \param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly by repeatedly issuing setStandby command. Enabled by default. - \returns \ref status_codes */ int16_t reset(bool verify = true); @@ -514,13 +498,9 @@ class SX126x: public PhysicalLayer { /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; @@ -528,20 +508,15 @@ class SX126x: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; /*! \brief Starts direct mode transmission. - \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; @@ -549,45 +524,37 @@ class SX126x: public PhysicalLayer { /*! \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX126x series does not support direct mode reception. Will always return RADIOLIB_ERR_UNKNOWN. - \returns \ref status_codes */ int16_t receiveDirect() override; /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. - \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. - \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. - \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. - \returns \ref status_codes */ int16_t scanChannel(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); /*! \brief Sets the module to sleep mode. - - \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") or to false to discard current configuration ("cold start"). Defaults to true. - + \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") + or to false to discard current configuration ("cold start"). Defaults to true. \returns \ref status_codes */ int16_t sleep(bool retainConfig = true); /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the module to standby mode. - - \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). - + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). \returns \ref status_codes */ int16_t standby(uint8_t mode); @@ -596,7 +563,6 @@ class SX126x: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when DIO1 activates. - \param func ISR to call. */ void setDio1Action(void (*func)(void)); @@ -609,110 +575,91 @@ class SX126x: public PhysicalLayer { /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - \param timeout Receive mode type and/or raw timeout value, expressed as multiples of 15.625 us. - When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain in Rx mode until explicitly commanded to stop (Rx continuous mode). - When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return to standby when a packet is received (Rx single mode). - For any other value, timeout will be applied and signal will be generated on DIO1 for conditions defined by irqFlags and irqMask. + When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain + in Rx mode until explicitly commanded to stop (Rx continuous mode). + When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return + to standby when a packet is received (Rx single mode). + For any other value, timeout will be applied and signal will be generated on DIO1 for conditions + defined by irqFlags and irqMask. \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. - \param len Only for PhysicalLayer compatibility, not used. - \returns \ref status_codes */ int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. - Note that this function assumes the unit will take 500us + TCXO_delay to change state. See datasheet section 13.1.7, version 1.2. - + Note that this function assumes the unit will take 500us + TCXO_delay to change state. + See datasheet section 13.1.7, version 1.2. \param rxPeriod The duration the receiver will be in Rx mode, in microseconds. - \param sleepPeriod The duration the receiver will not be in Rx mode, in microseconds. - \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. - \returns \ref status_codes */ int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); /*! \brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages. - \param senderPreambleLength Expected preamble length of the messages to receive. If set to zero, the currently configured preamble length will be used. Defaults to zero. - \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols of any preamble of the specified length. Defaults to 8. - According to Semtech, receiver requires 8 symbols to reliably latch a preamble. This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1). + \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols + of any preamble of the specified length. Defaults to 8. + According to Semtech, receiver requires 8 symbols to reliably latch a preamble. + This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1). \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. - \returns \ref status_codes */ int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); /*! \brief Reads the current IRQ status. - \returns IRQ status bits */ uint16_t getIrqStatus(); /*! \brief Reads data received after calling startReceive method. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; /*! - \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected, or upon timeout. - + \brief Interrupt-driven channel activity detection method. DIO0 will be activated + when LoRa preamble is detected, or upon timeout. \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. - \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. - \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. - \returns \ref status_codes */ int16_t startChannelScan(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); /*! \brief Read the channel scan result - \returns \ref status_codes */ int16_t getChannelScanResult(); @@ -721,101 +668,81 @@ class SX126x: public PhysicalLayer { /*! \brief Sets LoRa bandwidth. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz. - \param bw LoRa bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setBandwidth(float bw); /*! \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. - \param sf LoRa spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. - \param cr LoRa coding rate denominator to be set. - \returns \ref status_codes */ int16_t setCodingRate(uint8_t cr); /*! \brief Sets LoRa sync word. - \param syncWord LoRa sync word to be set. - \param controlBits Undocumented control bits, required for compatibility purposes. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t syncWord, uint8_t controlBits = 0x44); /*! \brief Sets current protection limit. Can be set in 2.5 mA steps. - \param currentLimit current protection limit to be set in mA. Allowed values range from 0 to 140. - \returns \ref status_codes */ int16_t setCurrentLimit(float currentLimit); /*! \brief Reads current protection limit. - \returns Currently configured overcurrent protection limit in mA. */ float getCurrentLimit(); /*! \brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535. - \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK). - \returns \ref status_codes */ int16_t setPreambleLength(uint16_t preambleLength); /*! \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. - \param freqDev FSK frequency deviation to be set in kHz. - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets FSK bit rate. Allowed values range from 0.6 to 300.0 kbps. - \param br FSK bit rate to be set in kbps. - \returns \ref status_codes */ int16_t setBitRate(float br); /*! - \brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. - - \param FSK receiver bandwidth to be set in kHz. - + \brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, + 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. + \param rxBw FSK receiver bandwidth to be set in kHz. \returns \ref status_codes */ int16_t setRxBandwidth(float rxBw); /*! - \brief Enables or disables Rx Boosted Gain mode as described in SX126x datasheet section 9.6 (SX1261/2 v2.1, SX1268 v1.1) - + \brief Enables or disables Rx Boosted Gain mode as described in SX126x datasheet + section 9.6 (SX1261/2 v2.1, SX1268 v1.1) \param rxbgm True for Rx Boosted Gain, false for Rx Power Saving Gain - - \param persist True to persist Rx gain setting when waking up from warm-start mode (e.g. when using Rx duty cycle mode) - + \param persist True to persist Rx gain setting when waking up from warm-start mode + (e.g. when using Rx duty cycle mode). \returns \ref status_codes */ int16_t setRxBoostedGainMode(bool rxbgm, bool persist = true); @@ -824,124 +751,100 @@ class SX126x: public PhysicalLayer { \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Time-bandwidth product of Gaussian filter to be set. - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; /*! \brief Sets FSK sync word in the form of array of up to 8 bytes. - \param syncWord FSK sync word to be set. - \param len FSK sync word length in bytes. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t* syncWord, uint8_t len); /*! \brief Sets FSK sync word in the form of array of up to 8 bytes. - \param syncWord FSK sync word to be set. - - \param bitsLen FSK sync word length in bits. If length is not divisible by 8, least significant bits of syncWord will be ignored. - + \param bitsLen FSK sync word length in bits. If length is not divisible by 8, + least significant bits of syncWord will be ignored. \returns \ref status_codes */ int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen); /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. - \param nodeAddr Node address to be set. - \returns \ref status_codes */ int16_t setNodeAddress(uint8_t nodeAddr); /*! - \brief Sets broadcast address. Calling this method will also enable address filtering for node and broadcast address. - + \brief Sets broadcast address. Calling this method will also enable address + filtering for node and broadcast address. \param broadAddr Node address to be set. - \returns \ref status_codes */ int16_t setBroadcastAddress(uint8_t broadAddr); /*! \brief Disables address filtering. Calling this method will also erase previously set addresses. - \returns \ref status_codes */ int16_t disableAddressFiltering(); /*! \brief Sets CRC configuration. - \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. - \param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC). - \param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC). - \param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC). - \returns \ref status_codes */ int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true); /*! \brief Sets FSK whitening parameters. - \param enabled True = Whitening enabled - - \param initial Initial value used for the whitening LFSR in FSK mode. Defaults to 0x0100, use 0x01FF for SX127x compatibility. - + \param initial Initial value used for the whitening LFSR in FSK mode. Defaults to 0x0100, + use 0x01FF for SX127x compatibility. \returns \ref status_codes */ int16_t setWhitening(bool enabled, uint16_t initial = 0x0100); /*! \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration. - - \param TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. Set to 0 to disable TCXO. + \param voltage TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. + Set to 0 to disable TCXO. NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO). - \param TCXO timeout in us. Defaults to 5000 us. - + \param delay TCXO timeout in us. Defaults to 5000 us. \returns \ref status_codes */ int16_t setTCXO(float voltage, uint32_t delay = 5000); /*! \brief Set DIO2 to function as RF switch (default in Semtech example designs). - \returns \ref status_codes */ int16_t setDio2AsRfSwitch(bool enable = true); /*! \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. - \returns Effective data rate in bps. */ float getDataRate() const; /*! \brief GetsRSSI (Recorded Signal Strength Indicator). - \param packet Whether to read last packet RSSI, or the current value. - \returns RSSI value in dBm. */ float getRSSI(bool packet = true); /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. - \returns SNR of the last received packet in dB. */ float getSNR(); @@ -957,75 +860,60 @@ class SX126x: public PhysicalLayer { /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! \brief Set modem in fixed packet length mode. Available in FSK mode only. - \param len Packet length. - \returns \ref status_codes */ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX126X_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. Available in FSK mode only. - \param len Maximum packet length. - \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); /*! \brief Get expected time-on-air for a given size of payload - \param len Payload length in bytes. - \returns Expected time-on-air in microseconds. */ uint32_t getTimeOnAir(size_t len); /*! \brief Set implicit header mode for future reception/transmission. - \param len Payload length in bytes. - \returns \ref status_codes */ int16_t implicitHeader(size_t len); /*! \brief Set explicit header mode for future reception/transmission. - \returns \ref status_codes */ int16_t explicitHeader(); /*! \brief Set regulator mode to LDO. - \returns \ref status_codes */ int16_t setRegulatorLDO(); /*! \brief Set regulator mode to DC-DC. - \returns \ref status_codes */ int16_t setRegulatorDCDC(); /*! \brief Sets transmission encoding. Available in FSK mode only. Serves only as alias for PhysicalLayer compatibility. - \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; @@ -1037,18 +925,18 @@ class SX126x: public PhysicalLayer { void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! - \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to - the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX126x::autoLDRO() + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, + LDRO will always be set to the provided value, regardless of symbol length. + To re-enable automatic LDRO configuration, call SX126x::autoLDRO() \param enable Force LDRO to be always enabled (true) or disabled (false). - \returns \ref status_codes */ int16_t forceLDRO(bool enable); /*! - \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically - when symbol length exceeds 16 ms. + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. + After calling this method, LDRO will be enabled automatically when symbol length exceeds 16 ms. \returns \ref status_codes */ @@ -1056,31 +944,26 @@ class SX126x: public PhysicalLayer { /*! \brief Get one truly random byte from RSSI noise. - \returns TRNG byte. */ uint8_t randomByte(); /*! \brief Enable/disable inversion of the I and Q signals - - \param invertIQ QI inversion enabled (true) or disabled (false); - + \param enable QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ - int16_t invertIQ(bool invertIQ); + int16_t invertIQ(bool enable); #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. - \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. - \param pin Pin on which to read. */ void readBit(uint32_t pin); @@ -1089,27 +972,19 @@ class SX126x: public PhysicalLayer { /*! \brief Upload binary patch into the SX126x device RAM. Patch is needed to e.g., enable spectral scan and must be uploaded again on every power cycle. - \param patch Binary patch to upload. - \param len Length of the binary patch in 4-byte words. - \param nonvolatile Set to true when the patch is saved in non-volatile memory of the host processor, or to false when the patch is in its RAM. - \returns \ref status_codes */ int16_t uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile = true); /*! \brief Start spectral scan. Requires binary path to be uploaded. - \param numSamples Number of samples for each scan. Fewer samples = better temporal resolution. - \param window RSSI averaging window size. - \param interval Scan interval length, one of RADIOLIB_SX126X_SCAN_INTERVAL_* macros. - \returns \ref status_codes */ int16_t spectralScanStart(uint16_t numSamples, uint8_t window = RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US); @@ -1121,16 +996,13 @@ class SX126x: public PhysicalLayer { /*! \brief Read the status of spectral scan. - \returns \ref status_codes */ int16_t spectralScanGetStatus(); /*! \brief Read the result of spectral scan. - \param results Array to which the results will be saved, must be RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE long. - \returns \ref status_codes */ int16_t spectralScanGetResult(uint16_t* results); @@ -1156,8 +1028,8 @@ class SX126x: public PhysicalLayer { int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); - int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ); - int16_t setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLength = 0xFF, uint8_t preambleDetectorLength = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); + int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ); + int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF, uint8_t preambleDetectorLen = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setRegulatorMode(uint8_t mode); uint8_t getStatus(); @@ -1168,7 +1040,7 @@ class SX126x: public PhysicalLayer { int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); int16_t setFrequencyRaw(float freq); int16_t setPacketMode(uint8_t mode, uint8_t len); - int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); int16_t directMode(); int16_t packetMode(); @@ -1181,7 +1053,7 @@ class SX126x: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; // common low-level SPI interface static int16_t SPIparseStatus(uint8_t in); @@ -1190,26 +1062,26 @@ class SX126x: public PhysicalLayer { protected: #endif - uint8_t _bw = 0, _sf = 0, _cr = 0, _ldro = 0, _crcType = 0, _headerType = 0; - uint16_t _preambleLength = 0; - float _bwKhz = 0; - bool _ldroAuto = true; + uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; + uint16_t preambleLengthLoRa = 0; + float bandwidthKhz = 0; + bool ldroAuto = true; - uint32_t _br = 0, _freqDev = 0; - uint8_t _rxBw = 0, _pulseShape = 0, _crcTypeFSK = 0, _syncWordLength = 0, _addrComp = 0, _whitening = 0, _packetType = 0; - uint16_t _preambleLengthFSK = 0; - float _rxBwKhz = 0; + uint32_t bitRate = 0, freqencyDev = 0; + uint8_t rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; + uint16_t preambleLengthFSK = 0; + float rxBandwidthKhz = 0; - float _dataRate = 0; + float dataRateMeasured = 0; - uint32_t _tcxoDelay = 0; + uint32_t tcxoDelay = 0; - size_t _implicitLen = 0; - uint8_t _invertIQ = RADIOLIB_SX126X_LORA_IQ_STANDARD; - const char* _chipType; + size_t implicitLen = 0; + uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + const char* chipType; // Allow subclasses to define different TX modes - uint8_t _tx_mode = Module::MODE_TX; + uint8_t txMode = Module::MODE_TX; int16_t config(uint8_t modem); bool findChip(const char* verStr); From bba644377a8c860e69770e5066fbfcda0de87031 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 19:19:11 +0200 Subject: [PATCH 0511/1848] [nRF24] General reformatting --- src/modules/nRF24/nRF24.cpp | 230 +++++++++--------- src/modules/nRF24/nRF24.h | 459 ++++++++++++++---------------------- 2 files changed, 288 insertions(+), 401 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 9f4cea9cbe..39baa96277 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -3,32 +3,32 @@ #if !defined(RADIOLIB_EXCLUDE_NRF24) nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) { - _mod = mod; + this->mod = mod; } Module* nRF24::getMod() { - return(_mod); + return(this->mod); } -int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrWidth) { +int16_t nRF24::begin(int16_t freq, int16_t dr, int8_t pwr, uint8_t addrWidth) { // set module properties - _mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; - _mod->SPIwriteCommand = RADIOLIB_NRF24_CMD_WRITE; - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; + this->mod->SPIwriteCommand = RADIOLIB_NRF24_CMD_WRITE; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); // set pin mode on RST (connected to nRF24 CE pin) - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); // wait for minimum power-on reset duration - _mod->hal->delay(100); + this->mod->hal->delay(100); // check SPI connection - int16_t val = _mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); + int16_t val = this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); if(!((val >= 0) && (val <= 3))) { RADIOLIB_DEBUG_PRINTLN("No nRF24 found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tnRF24"); @@ -46,11 +46,11 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW RADIOLIB_ASSERT(state); // set data rate - state = setBitRate(dataRate); + state = setBitRate(dr); RADIOLIB_ASSERT(state); // set output power - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); // set address width @@ -69,7 +69,7 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW } int16_t nRF24::sleep() { - return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_DOWN, 1, 1)); + return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_DOWN, 1, 1)); } int16_t nRF24::standby() { @@ -78,12 +78,12 @@ int16_t nRF24::standby() { int16_t nRF24::standby(uint8_t mode) { // make sure carrier output is disabled - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_OFF, 7, 7); - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_OFF, 4, 4); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_OFF, 7, 7); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_OFF, 4, 4); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); // use standby-1 mode - return(_mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, mode, 1, 1)); + return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, mode, 1, 1)); } int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -92,9 +92,9 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait until transmission is finished - uint32_t start = _mod->hal->micros(); - while(_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); // check maximum number of retransmits if(getStatus(RADIOLIB_NRF24_MAX_RT)) { @@ -103,7 +103,7 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { } // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(_mod->hal->micros() - start >= 60000) { + if(this->mod->hal->micros() - start >= 60000) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -118,12 +118,12 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for Rx_DataReady or timeout - uint32_t start = _mod->hal->micros(); - while(_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(_mod->hal->micros() - start >= 60000) { + if(this->mod->hal->micros() - start >= 60000) { standby(); clearIRQ(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -138,14 +138,14 @@ int16_t nRF24::transmitDirect(uint32_t frf) { // set raw frequency value if(frf != 0) { uint8_t freqRaw = frf - 2400; - _mod->SPIwriteRegister(RADIOLIB_NRF24_REG_RF_CH, freqRaw & 0b01111111); + this->mod->SPIwriteRegister(RADIOLIB_NRF24_REG_RF_CH, freqRaw & 0b01111111); } // output carrier - int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_ON, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_ON, 4, 4); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_CONT_WAVE_ON, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_PLL_LOCK_ON, 4, 4); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); return(state); } @@ -156,7 +156,7 @@ int16_t nRF24::receiveDirect() { } void nRF24::setIrqAction(void (*func)(void)) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptFalling); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptFalling); } int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -173,13 +173,13 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // enable primary Tx mode - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PTX, 0, 0); // clear interrupts clearIRQ(); // enable Tx_DataSent interrupt - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON, 5, 5); RADIOLIB_ASSERT(state); // flush Tx FIFO @@ -192,9 +192,9 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { SPIwriteTxPayload(data, len); // CE high to start transmitting - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); return(state); } @@ -213,22 +213,22 @@ int16_t nRF24::startReceive() { RADIOLIB_ASSERT(state); // enable primary Rx mode - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PRX, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_PRX, 0, 0); RADIOLIB_ASSERT(state); // enable Rx_DataReady interrupt clearIRQ(); - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON, 6, 6); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON, 6, 6); RADIOLIB_ASSERT(state); // flush Rx FIFO SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); // CE high to start receiving - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); // wait to enter Rx state - _mod->hal->delay(1); + this->mod->hal->delay(1); return(state); } @@ -267,10 +267,10 @@ int16_t nRF24::setFrequency(float freq) { // set frequency uint8_t freqRaw = (uint16_t)freq - 2400; - int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_CH, freqRaw, 6, 0); if(state == RADIOLIB_ERR_NONE) { - _freq = freq; + this->frequency = freq; } return(state); @@ -284,20 +284,20 @@ int16_t nRF24::setBitRate(float br) { // set data rate uint16_t dataRate = (uint16_t)br; if(dataRate == 250) { - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3); } else if(dataRate == 1000) { - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 5, 5); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 3, 3); } else if(dataRate == 2000) { - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 5, 5); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 3, 3); } else { return(RADIOLIB_ERR_INVALID_DATA_RATE); } if(state == RADIOLIB_ERR_NONE) { - _dataRate = dataRate; + this->dataRate = dataRate; } @@ -329,10 +329,10 @@ int16_t nRF24::setOutputPower(int8_t power) { } // write new register value - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, powerRaw, 2, 1); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, powerRaw, 2, 1); if(state == RADIOLIB_ERR_NONE) { - _power = power; + this->power = power; } @@ -349,16 +349,16 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) { case 2: // Even if marked as 'Illegal' on the datasheet this will work: // http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_2_BYTES, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_2_BYTES, 1, 0); break; case 3: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_3_BYTES, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_3_BYTES, 1, 0); break; case 4: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_4_BYTES, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_4_BYTES, 1, 0); break; case 5: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_5_BYTES, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_AW, RADIOLIB_NRF24_ADDRESS_5_BYTES, 1, 0); break; default: return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); @@ -366,7 +366,7 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) { // save address width if(state == RADIOLIB_ERR_NONE) { - _addrWidth = addrWidth; + this->addressWidth = addrWidth; } return(state); @@ -378,11 +378,11 @@ int16_t nRF24::setTransmitPipe(uint8_t* addr) { RADIOLIB_ASSERT(state); // set transmit address - _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_TX_ADDR, addr, _addrWidth); + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_TX_ADDR, addr, this->addressWidth); // set Rx pipe 0 address (for ACK) - _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, _addrWidth); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, this->addressWidth); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); return(state); } @@ -395,12 +395,12 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) { // write full pipe 0 - 1 address and enable the pipe switch(pipeNum) { case 0: - _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, _addrWidth); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P0, addr, this->addressWidth); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_ON, 0, 0); break; case 1: - _mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P1, addr, _addrWidth); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_ON, 1, 1); + this->mod->SPIwriteRegisterBurst(RADIOLIB_NRF24_REG_RX_ADDR_P1, addr, this->addressWidth); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_ON, 1, 1); break; default: return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); @@ -417,20 +417,20 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) { // write unique pipe 2 - 5 address and enable the pipe switch(pipeNum) { case 2: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P2, addrByte); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_ON, 2, 2); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P2, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_ON, 2, 2); break; case 3: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P3, addrByte); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_ON, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P3, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_ON, 3, 3); break; case 4: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P4, addrByte); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_ON, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P4, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_ON, 4, 4); break; case 5: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P5, addrByte); - state |= _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_ON, 5, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RX_ADDR_P5, addrByte); + state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_ON, 5, 5); break; default: return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); @@ -446,22 +446,22 @@ int16_t nRF24::disablePipe(uint8_t pipeNum) { switch(pipeNum) { case 0: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_OFF, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P0_OFF, 0, 0); break; case 1: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_OFF, 1, 1); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P1_OFF, 1, 1); break; case 2: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_OFF, 2, 2); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P2_OFF, 2, 2); break; case 3: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_OFF, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P3_OFF, 3, 3); break; case 4: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_OFF, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P4_OFF, 4, 4); break; case 5: - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_OFF, 5, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_RXADDR, RADIOLIB_NRF24_P5_OFF, 5, 5); break; default: return(RADIOLIB_ERR_INVALID_PIPE_NUMBER); @@ -471,11 +471,11 @@ int16_t nRF24::disablePipe(uint8_t pipeNum) { } int16_t nRF24::getStatus(uint8_t mask) { - return(_mod->SPIgetRegValue(RADIOLIB_NRF24_REG_STATUS) & mask); + return(this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_STATUS) & mask); } bool nRF24::isCarrierDetected() { - return(_mod->SPIgetRegValue(RADIOLIB_NRF24_REG_RPD, 0, 0) == 1); + return(this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_RPD, 0, 0) == 1); } int16_t nRF24::setFrequencyDeviation(float freqDev) { @@ -500,32 +500,32 @@ int16_t nRF24::setCrcFiltering(bool crcOn) { } // Disable CRC - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, (crcOn ? RADIOLIB_NRF24_CRC_ON : RADIOLIB_NRF24_CRC_OFF), 3, 3); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, (crcOn ? RADIOLIB_NRF24_CRC_ON : RADIOLIB_NRF24_CRC_OFF), 3, 3); } int16_t nRF24::setAutoAck(bool autoAckOn){ - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_ALL_ON : RADIOLIB_NRF24_AA_ALL_OFF), 5, 0); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_ALL_ON : RADIOLIB_NRF24_AA_ALL_OFF), 5, 0); } int16_t nRF24::setAutoAck(uint8_t pipeNum, bool autoAckOn){ switch(pipeNum) { case 0: - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P0_ON : RADIOLIB_NRF24_AA_P0_OFF), 0, 0); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P0_ON : RADIOLIB_NRF24_AA_P0_OFF), 0, 0); break; case 1: - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P1_ON : RADIOLIB_NRF24_AA_P1_OFF), 1, 1); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P1_ON : RADIOLIB_NRF24_AA_P1_OFF), 1, 1); break; case 2: - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P2_ON : RADIOLIB_NRF24_AA_P2_OFF), 2, 2); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P2_ON : RADIOLIB_NRF24_AA_P2_OFF), 2, 2); break; case 3: - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P3_ON : RADIOLIB_NRF24_AA_P3_OFF), 3, 3); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P3_ON : RADIOLIB_NRF24_AA_P3_OFF), 3, 3); break; case 4: - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P4_ON : RADIOLIB_NRF24_AA_P4_OFF), 4, 4); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P4_ON : RADIOLIB_NRF24_AA_P4_OFF), 4, 4); break; case 5: - return _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P5_ON : RADIOLIB_NRF24_AA_P5_OFF), 5, 5); + return this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_EN_AA, (autoAckOn ? RADIOLIB_NRF24_AA_P5_ON : RADIOLIB_NRF24_AA_P5_OFF), 5, 5); break; default: return (RADIOLIB_ERR_INVALID_PIPE_NUMBER); @@ -546,63 +546,43 @@ int16_t nRF24::setEncoding(uint8_t encoding) { return(RADIOLIB_ERR_NONE); } -uint8_t nRF24::randomByte() { - // nRF24 is unable to measure RSSI, hence no TRNG - // this method is implemented only for PhysicalLayer compatibility - return(0); -} - -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) -void nRF24::setDirectAction(void (*func)(void)) { - // nRF24 is unable to perform direct mode actions - // this method is implemented only for PhysicalLayer compatibility - (void)func; -} - -void nRF24::readBit(uint32_t pin) { - // nRF24 is unable to perform direct mode actions - // this method is implemented only for PhysicalLayer compatibility - (void)pin; -} -#endif - void nRF24::clearIRQ() { // clear status bits - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); // disable interrupts - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF | RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF | RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF | RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF | RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4); } int16_t nRF24::config() { // enable 16-bit CRC - int16_t state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_CRC_ON | RADIOLIB_NRF24_CRC_16, 3, 2); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_CRC_ON | RADIOLIB_NRF24_CRC_16, 3, 2); RADIOLIB_ASSERT(state); // set 15 retries and delay 1500 (5*250) us - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_RETR, (5 << 4) | 5); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_SETUP_RETR, (5 << 4) | 5); // set features: dynamic payload on, payload with ACK packets off, dynamic ACK off - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_FEATURE, RADIOLIB_NRF24_DPL_ON | RADIOLIB_NRF24_ACK_PAY_OFF | RADIOLIB_NRF24_DYN_ACK_OFF, 2, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_FEATURE, RADIOLIB_NRF24_DPL_ON | RADIOLIB_NRF24_ACK_PAY_OFF | RADIOLIB_NRF24_DYN_ACK_OFF, 2, 0); RADIOLIB_ASSERT(state); // enable dynamic payloads - state = _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_DYNPD, RADIOLIB_NRF24_DPL_ALL_ON, 5, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_DYNPD, RADIOLIB_NRF24_DPL_ALL_ON, 5, 0); RADIOLIB_ASSERT(state); // reset IRQ clearIRQ(); // clear status - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); // flush FIFOs SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_TX); SPItransfer(RADIOLIB_NRF24_CMD_FLUSH_RX); // power up - _mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1); - _mod->hal->delay(5); + this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, RADIOLIB_NRF24_POWER_UP, 1, 1); + this->mod->hal->delay(5); return(state); } @@ -617,26 +597,26 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // start transfer - _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelLow); - _mod->hal->spiBeginTransaction(); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + this->mod->hal->spiBeginTransaction(); // send command - _mod->hal->spiTransfer(cmd); + this->mod->hal->spiTransfer(cmd); // send data if(write) { for(uint8_t i = 0; i < numBytes; i++) { - _mod->hal->spiTransfer(dataOut[i]); + this->mod->hal->spiTransfer(dataOut[i]); } } else { for(uint8_t i = 0; i < numBytes; i++) { - dataIn[i] = _mod->hal->spiTransfer(0x00); + dataIn[i] = this->mod->hal->spiTransfer(0x00); } } // stop transfer - _mod->hal->spiEndTransaction(); - _mod->hal->digitalWrite(_mod->getCs(), _mod->hal->GpioLevelHigh); + this->mod->hal->spiEndTransaction(); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); } #endif diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 5f683c8729..afd68b1112 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -7,180 +7,178 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // nRF24 physical layer properties -#define RADIOLIB_NRF24_FREQUENCY_STEP_SIZE 1000000.0 -#define RADIOLIB_NRF24_MAX_PACKET_LENGTH 32 +#define RADIOLIB_NRF24_FREQUENCY_STEP_SIZE 1000000.0 +#define RADIOLIB_NRF24_MAX_PACKET_LENGTH 32 // nRF24 SPI commands -#define RADIOLIB_NRF24_CMD_READ 0b00000000 -#define RADIOLIB_NRF24_CMD_WRITE 0b00100000 -#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD 0b01100001 -#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD 0b10100000 -#define RADIOLIB_NRF24_CMD_FLUSH_TX 0b11100001 -#define RADIOLIB_NRF24_CMD_FLUSH_RX 0b11100010 -#define RADIOLIB_NRF24_CMD_REUSE_TX_PAXLOAD 0b11100011 -#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD_WIDTH 0b01100000 -#define RADIOLIB_NRF24_CMD_WRITE_ACK_PAYLOAD 0b10101000 -#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD_NOACK 0b10110000 -#define RADIOLIB_NRF24_CMD_NOP 0b11111111 +#define RADIOLIB_NRF24_CMD_READ 0b00000000 +#define RADIOLIB_NRF24_CMD_WRITE 0b00100000 +#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD 0b01100001 +#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD 0b10100000 +#define RADIOLIB_NRF24_CMD_FLUSH_TX 0b11100001 +#define RADIOLIB_NRF24_CMD_FLUSH_RX 0b11100010 +#define RADIOLIB_NRF24_CMD_REUSE_TX_PAXLOAD 0b11100011 +#define RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD_WIDTH 0b01100000 +#define RADIOLIB_NRF24_CMD_WRITE_ACK_PAYLOAD 0b10101000 +#define RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD_NOACK 0b10110000 +#define RADIOLIB_NRF24_CMD_NOP 0b11111111 // nRF24 register map -#define RADIOLIB_NRF24_REG_CONFIG 0x00 -#define RADIOLIB_NRF24_REG_EN_AA 0x01 -#define RADIOLIB_NRF24_REG_EN_RXADDR 0x02 -#define RADIOLIB_NRF24_REG_SETUP_AW 0x03 -#define RADIOLIB_NRF24_REG_SETUP_RETR 0x04 -#define RADIOLIB_NRF24_REG_RF_CH 0x05 -#define RADIOLIB_NRF24_REG_RF_SETUP 0x06 -#define RADIOLIB_NRF24_REG_STATUS 0x07 -#define RADIOLIB_NRF24_REG_OBSERVE_TX 0x08 -#define RADIOLIB_NRF24_REG_RPD 0x09 -#define RADIOLIB_NRF24_REG_RX_ADDR_P0 0x0A -#define RADIOLIB_NRF24_REG_RX_ADDR_P1 0x0B -#define RADIOLIB_NRF24_REG_RX_ADDR_P2 0x0C -#define RADIOLIB_NRF24_REG_RX_ADDR_P3 0x0D -#define RADIOLIB_NRF24_REG_RX_ADDR_P4 0x0E -#define RADIOLIB_NRF24_REG_RX_ADDR_P5 0x0F -#define RADIOLIB_NRF24_REG_TX_ADDR 0x10 -#define RADIOLIB_NRF24_REG_RX_PW_P0 0x11 -#define RADIOLIB_NRF24_REG_RX_PW_P1 0x12 -#define RADIOLIB_NRF24_REG_RX_PW_P2 0x13 -#define RADIOLIB_NRF24_REG_RX_PW_P3 0x14 -#define RADIOLIB_NRF24_REG_RX_PW_P4 0x15 -#define RADIOLIB_NRF24_REG_RX_PW_P5 0x16 -#define RADIOLIB_NRF24_REG_FIFO_STATUS 0x17 -#define RADIOLIB_NRF24_REG_DYNPD 0x1C -#define RADIOLIB_NRF24_REG_FEATURE 0x1D - -// NRF24_REG_CONFIG MSB LSB DESCRIPTION -#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF 0b01000000 // 6 6 RX_DR will not be reflected on IRQ pin -#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON 0b00000000 // 6 6 RX_DR will be reflected on IRQ pin as active low (default) -#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF 0b00100000 // 5 5 TX_DS will not be reflected on IRQ pin -#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON 0b00000000 // 5 5 TX_DS will be reflected on IRQ pin as active low (default) -#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF 0b00010000 // 4 4 MAX_RT will not be reflected on IRQ pin -#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_ON 0b00000000 // 4 4 MAX_RT will be reflected on IRQ pin as active low (default) -#define RADIOLIB_NRF24_CRC_OFF 0b00000000 // 3 3 CRC calculation: disabled -#define RADIOLIB_NRF24_CRC_ON 0b00001000 // 3 3 enabled (default) -#define RADIOLIB_NRF24_CRC_8 0b00000000 // 2 2 CRC scheme: CRC8 (default) -#define RADIOLIB_NRF24_CRC_16 0b00000100 // 2 2 CRC16 -#define RADIOLIB_NRF24_POWER_UP 0b00000010 // 1 1 power up -#define RADIOLIB_NRF24_POWER_DOWN 0b00000000 // 1 1 power down -#define RADIOLIB_NRF24_PTX 0b00000000 // 0 0 enable primary Tx -#define RADIOLIB_NRF24_PRX 0b00000001 // 0 0 enable primary Rx - -// NRF24_REG_EN_AA -#define RADIOLIB_NRF24_AA_ALL_OFF 0b00000000 // 5 0 auto-ACK on all pipes: disabled -#define RADIOLIB_NRF24_AA_ALL_ON 0b00111111 // 5 0 enabled (default) -#define RADIOLIB_NRF24_AA_P5_OFF 0b00000000 // 5 5 auto-ACK on pipe 5: disabled -#define RADIOLIB_NRF24_AA_P5_ON 0b00100000 // 5 5 enabled (default) -#define RADIOLIB_NRF24_AA_P4_OFF 0b00000000 // 4 4 auto-ACK on pipe 4: disabled -#define RADIOLIB_NRF24_AA_P4_ON 0b00010000 // 4 4 enabled (default) -#define RADIOLIB_NRF24_AA_P3_OFF 0b00000000 // 3 3 auto-ACK on pipe 3: disabled -#define RADIOLIB_NRF24_AA_P3_ON 0b00001000 // 3 3 enabled (default) -#define RADIOLIB_NRF24_AA_P2_OFF 0b00000000 // 2 2 auto-ACK on pipe 2: disabled -#define RADIOLIB_NRF24_AA_P2_ON 0b00000100 // 2 2 enabled (default) -#define RADIOLIB_NRF24_AA_P1_OFF 0b00000000 // 1 1 auto-ACK on pipe 1: disabled -#define RADIOLIB_NRF24_AA_P1_ON 0b00000010 // 1 1 enabled (default) -#define RADIOLIB_NRF24_AA_P0_OFF 0b00000000 // 0 0 auto-ACK on pipe 0: disabled -#define RADIOLIB_NRF24_AA_P0_ON 0b00000001 // 0 0 enabled (default) - -// NRF24_REG_EN_RXADDR -#define RADIOLIB_NRF24_P5_OFF 0b00000000 // 5 5 receive pipe 5: disabled (default) -#define RADIOLIB_NRF24_P5_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_NRF24_P4_OFF 0b00000000 // 4 4 receive pipe 4: disabled (default) -#define RADIOLIB_NRF24_P4_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_NRF24_P3_OFF 0b00000000 // 3 3 receive pipe 3: disabled (default) -#define RADIOLIB_NRF24_P3_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_NRF24_P2_OFF 0b00000000 // 2 2 receive pipe 2: disabled (default) -#define RADIOLIB_NRF24_P2_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_NRF24_P1_OFF 0b00000000 // 1 1 receive pipe 1: disabled -#define RADIOLIB_NRF24_P1_ON 0b00000010 // 1 1 enabled (default) -#define RADIOLIB_NRF24_P0_OFF 0b00000000 // 0 0 receive pipe 0: disabled -#define RADIOLIB_NRF24_P0_ON 0b00000001 // 0 0 enabled (default) - -// NRF24_REG_SETUP_AW -#define RADIOLIB_NRF24_ADDRESS_2_BYTES 0b00000000 // 1 0 address width: 2 bytes -#define RADIOLIB_NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 3 bytes -#define RADIOLIB_NRF24_ADDRESS_4_BYTES 0b00000010 // 1 0 4 bytes -#define RADIOLIB_NRF24_ADDRESS_5_BYTES 0b00000011 // 1 0 5 bytes (default) - -// NRF24_REG_SETUP_RETR -#define RADIOLIB_NRF24_ARD 0b00000000 // 7 4 auto retransmit delay: t[us] = (NRF24_ARD + 1) * 250 us -#define RADIOLIB_NRF24_ARC_OFF 0b00000000 // 3 0 auto retransmit count: auto retransmit disabled -#define RADIOLIB_NRF24_ARC 0b00000011 // 3 0 up to 3 retransmits on AA fail (default) - -// NRF24_REG_RF_CH -#define RADIOLIB_NRF24_RF_CH 0b00000010 // 6 0 RF channel: f_CH[MHz] = 2400 MHz + NRF24_RF_CH - -// NRF24_REG_RF_SETUP -#define RADIOLIB_NRF24_CONT_WAVE_OFF 0b00000000 // 7 7 continuous carrier transmit: disabled (default) -#define RADIOLIB_NRF24_CONT_WAVE_ON 0b10000000 // 7 7 enabled -#define RADIOLIB_NRF24_DR_250_KBPS 0b00100000 // 5 5 data rate: 250 kbps -#define RADIOLIB_NRF24_DR_1_MBPS 0b00000000 // 3 3 1 Mbps (default) -#define RADIOLIB_NRF24_DR_2_MBPS 0b00001000 // 3 3 2 Mbps -#define RADIOLIB_NRF24_PLL_LOCK_ON 0b00010000 // 4 4 force PLL lock: enabled -#define RADIOLIB_NRF24_PLL_LOCK_OFF 0b00000000 // 4 4 disabled (default) -#define RADIOLIB_NRF24_RF_PWR_18_DBM 0b00000000 // 2 1 output power: -18 dBm -#define RADIOLIB_NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm -#define RADIOLIB_NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm -#define RADIOLIB_NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default) - -// NRF24_REG_STATUS -#define RADIOLIB_NRF24_RX_DR 0b01000000 // 6 6 Rx data ready -#define RADIOLIB_NRF24_TX_DS 0b00100000 // 5 5 Tx data sent -#define RADIOLIB_NRF24_MAX_RT 0b00010000 // 4 4 maximum number of retransmits reached (must be cleared to continue) -#define RADIOLIB_NRF24_RX_FIFO_EMPTY 0b00001110 // 3 1 Rx FIFO is empty -#define RADIOLIB_NRF24_RX_P_NO 0b00000000 // 3 1 number of data pipe that received data -#define RADIOLIB_NRF24_TX_FIFO_FULL 0b00000001 // 0 0 Tx FIFO is full - -// NRF24_REG_OBSERVE_TX -#define RADIOLIB_NRF24_PLOS_CNT 0b00000000 // 7 4 number of lost packets -#define RADIOLIB_NRF24_ARC_CNT 0b00000000 // 3 0 number of retransmitted packets - -// NRF24_REG_RPD -#define RADIOLIB_NRF24_RP_BELOW_64_DBM 0b00000000 // 0 0 received power in the current channel: less than -64 dBm -#define RADIOLIB_NRF24_RP_ABOVE_64_DBM 0b00000001 // 0 0 more than -64 dBm - -// NRF24_REG_FIFO_STATUS -#define RADIOLIB_NRF24_TX_REUSE 0b01000000 // 6 6 reusing last transmitted payload -#define RADIOLIB_NRF24_TX_FIFO_FULL_FLAG 0b00100000 // 5 5 Tx FIFO is full -#define RADIOLIB_NRF24_TX_FIFO_EMPTY_FLAG 0b00010000 // 4 4 Tx FIFO is empty -#define RADIOLIB_NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 1 1 Rx FIFO is full -#define RADIOLIB_NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 0 0 Rx FIFO is empty - -// NRF24_REG_DYNPD -#define RADIOLIB_NRF24_DPL_P5_OFF 0b00000000 // 5 5 dynamic payload length on pipe 5: disabled (default) -#define RADIOLIB_NRF24_DPL_P5_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_NRF24_DPL_P4_OFF 0b00000000 // 4 4 dynamic payload length on pipe 4: disabled (default) -#define RADIOLIB_NRF24_DPL_P4_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_NRF24_DPL_P3_OFF 0b00000000 // 3 3 dynamic payload length on pipe 3: disabled (default) -#define RADIOLIB_NRF24_DPL_P3_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_NRF24_DPL_P2_OFF 0b00000000 // 2 2 dynamic payload length on pipe 2: disabled (default) -#define RADIOLIB_NRF24_DPL_P2_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_NRF24_DPL_P1_OFF 0b00000000 // 1 1 dynamic payload length on pipe 1: disabled (default) -#define RADIOLIB_NRF24_DPL_P1_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_NRF24_DPL_P0_OFF 0b00000000 // 0 0 dynamic payload length on pipe 0: disabled (default) -#define RADIOLIB_NRF24_DPL_P0_ON 0b00000001 // 0 0 enabled -#define RADIOLIB_NRF24_DPL_ALL_OFF 0b00000000 // 5 0 disable all dynamic payloads -#define RADIOLIB_NRF24_DPL_ALL_ON 0b00111111 // 5 0 enable all dynamic payloads - -// NRF24_REG_FEATURE -#define RADIOLIB_NRF24_DPL_OFF 0b00000000 // 2 2 dynamic payload length: disabled (default) -#define RADIOLIB_NRF24_DPL_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_NRF24_ACK_PAY_OFF 0b00000000 // 1 1 payload with ACK packets: disabled (default) -#define RADIOLIB_NRF24_ACK_PAY_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default) -#define RADIOLIB_NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled - -// Defaults -#define RADIOLIB_NRF24_DEFAULT_FREQ 2400 -#define RADIOLIB_NRF24_DEFAULT_DR 1000 -#define RADIOLIB_NRF24_DEFAULT_POWER -12 -#define RADIOLIB_NRF24_DEFAULT_ADDRWIDTH 5 - +#define RADIOLIB_NRF24_REG_CONFIG 0x00 +#define RADIOLIB_NRF24_REG_EN_AA 0x01 +#define RADIOLIB_NRF24_REG_EN_RXADDR 0x02 +#define RADIOLIB_NRF24_REG_SETUP_AW 0x03 +#define RADIOLIB_NRF24_REG_SETUP_RETR 0x04 +#define RADIOLIB_NRF24_REG_RF_CH 0x05 +#define RADIOLIB_NRF24_REG_RF_SETUP 0x06 +#define RADIOLIB_NRF24_REG_STATUS 0x07 +#define RADIOLIB_NRF24_REG_OBSERVE_TX 0x08 +#define RADIOLIB_NRF24_REG_RPD 0x09 +#define RADIOLIB_NRF24_REG_RX_ADDR_P0 0x0A +#define RADIOLIB_NRF24_REG_RX_ADDR_P1 0x0B +#define RADIOLIB_NRF24_REG_RX_ADDR_P2 0x0C +#define RADIOLIB_NRF24_REG_RX_ADDR_P3 0x0D +#define RADIOLIB_NRF24_REG_RX_ADDR_P4 0x0E +#define RADIOLIB_NRF24_REG_RX_ADDR_P5 0x0F +#define RADIOLIB_NRF24_REG_TX_ADDR 0x10 +#define RADIOLIB_NRF24_REG_RX_PW_P0 0x11 +#define RADIOLIB_NRF24_REG_RX_PW_P1 0x12 +#define RADIOLIB_NRF24_REG_RX_PW_P2 0x13 +#define RADIOLIB_NRF24_REG_RX_PW_P3 0x14 +#define RADIOLIB_NRF24_REG_RX_PW_P4 0x15 +#define RADIOLIB_NRF24_REG_RX_PW_P5 0x16 +#define RADIOLIB_NRF24_REG_FIFO_STATUS 0x17 +#define RADIOLIB_NRF24_REG_DYNPD 0x1C +#define RADIOLIB_NRF24_REG_FEATURE 0x1D + +// RADIOLIB_NRF24_REG_CONFIG MSB LSB DESCRIPTION +#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_OFF 0b01000000 // 6 6 RX_DR will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_RX_DR_IRQ_ON 0b00000000 // 6 6 RX_DR will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_OFF 0b00100000 // 5 5 TX_DS will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_TX_DS_IRQ_ON 0b00000000 // 5 5 TX_DS will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_OFF 0b00010000 // 4 4 MAX_RT will not be reflected on IRQ pin +#define RADIOLIB_NRF24_MASK_MAX_RT_IRQ_ON 0b00000000 // 4 4 MAX_RT will be reflected on IRQ pin as active low (default) +#define RADIOLIB_NRF24_CRC_OFF 0b00000000 // 3 3 CRC calculation: disabled +#define RADIOLIB_NRF24_CRC_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_NRF24_CRC_8 0b00000000 // 2 2 CRC scheme: CRC8 (default) +#define RADIOLIB_NRF24_CRC_16 0b00000100 // 2 2 CRC16 +#define RADIOLIB_NRF24_POWER_UP 0b00000010 // 1 1 power up +#define RADIOLIB_NRF24_POWER_DOWN 0b00000000 // 1 1 power down +#define RADIOLIB_NRF24_PTX 0b00000000 // 0 0 enable primary Tx +#define RADIOLIB_NRF24_PRX 0b00000001 // 0 0 enable primary Rx + +// RADIOLIB_NRF24_REG_EN_AA +#define RADIOLIB_NRF24_AA_ALL_OFF 0b00000000 // 5 0 auto-ACK on all pipes: disabled +#define RADIOLIB_NRF24_AA_ALL_ON 0b00111111 // 5 0 enabled (default) +#define RADIOLIB_NRF24_AA_P5_OFF 0b00000000 // 5 5 auto-ACK on pipe 5: disabled +#define RADIOLIB_NRF24_AA_P5_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_NRF24_AA_P4_OFF 0b00000000 // 4 4 auto-ACK on pipe 4: disabled +#define RADIOLIB_NRF24_AA_P4_ON 0b00010000 // 4 4 enabled (default) +#define RADIOLIB_NRF24_AA_P3_OFF 0b00000000 // 3 3 auto-ACK on pipe 3: disabled +#define RADIOLIB_NRF24_AA_P3_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_NRF24_AA_P2_OFF 0b00000000 // 2 2 auto-ACK on pipe 2: disabled +#define RADIOLIB_NRF24_AA_P2_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_NRF24_AA_P1_OFF 0b00000000 // 1 1 auto-ACK on pipe 1: disabled +#define RADIOLIB_NRF24_AA_P1_ON 0b00000010 // 1 1 enabled (default) +#define RADIOLIB_NRF24_AA_P0_OFF 0b00000000 // 0 0 auto-ACK on pipe 0: disabled +#define RADIOLIB_NRF24_AA_P0_ON 0b00000001 // 0 0 enabled (default) + +// RADIOLIB_NRF24_REG_EN_RXADDR +#define RADIOLIB_NRF24_P5_OFF 0b00000000 // 5 5 receive pipe 5: disabled (default) +#define RADIOLIB_NRF24_P5_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_NRF24_P4_OFF 0b00000000 // 4 4 receive pipe 4: disabled (default) +#define RADIOLIB_NRF24_P4_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_NRF24_P3_OFF 0b00000000 // 3 3 receive pipe 3: disabled (default) +#define RADIOLIB_NRF24_P3_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_NRF24_P2_OFF 0b00000000 // 2 2 receive pipe 2: disabled (default) +#define RADIOLIB_NRF24_P2_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_P1_OFF 0b00000000 // 1 1 receive pipe 1: disabled +#define RADIOLIB_NRF24_P1_ON 0b00000010 // 1 1 enabled (default) +#define RADIOLIB_NRF24_P0_OFF 0b00000000 // 0 0 receive pipe 0: disabled +#define RADIOLIB_NRF24_P0_ON 0b00000001 // 0 0 enabled (default) + +// RADIOLIB_NRF24_REG_SETUP_AW +#define RADIOLIB_NRF24_ADDRESS_2_BYTES 0b00000000 // 1 0 address width: 2 bytes +#define RADIOLIB_NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 3 bytes +#define RADIOLIB_NRF24_ADDRESS_4_BYTES 0b00000010 // 1 0 4 bytes +#define RADIOLIB_NRF24_ADDRESS_5_BYTES 0b00000011 // 1 0 5 bytes (default) + +// RADIOLIB_NRF24_REG_SETUP_RETR +#define RADIOLIB_NRF24_ARD 0b00000000 // 7 4 auto retransmit delay: t[us] = (NRF24_ARD + 1) * 250 us +#define RADIOLIB_NRF24_ARC_OFF 0b00000000 // 3 0 auto retransmit count: auto retransmit disabled +#define RADIOLIB_NRF24_ARC 0b00000011 // 3 0 up to 3 retransmits on AA fail (default) + +// RADIOLIB_NRF24_REG_RF_CH +#define RADIOLIB_NRF24_RF_CH 0b00000010 // 6 0 RF channel: f_CH[MHz] = 2400 MHz + NRF24_RF_CH + +// RADIOLIB_NRF24_REG_RF_SETUP +#define RADIOLIB_NRF24_CONT_WAVE_OFF 0b00000000 // 7 7 continuous carrier transmit: disabled (default) +#define RADIOLIB_NRF24_CONT_WAVE_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_NRF24_DR_250_KBPS 0b00100000 // 5 5 data rate: 250 kbps +#define RADIOLIB_NRF24_DR_1_MBPS 0b00000000 // 3 3 1 Mbps (default) +#define RADIOLIB_NRF24_DR_2_MBPS 0b00001000 // 3 3 2 Mbps +#define RADIOLIB_NRF24_PLL_LOCK_ON 0b00010000 // 4 4 force PLL lock: enabled +#define RADIOLIB_NRF24_PLL_LOCK_OFF 0b00000000 // 4 4 disabled (default) +#define RADIOLIB_NRF24_RF_PWR_18_DBM 0b00000000 // 2 1 output power: -18 dBm +#define RADIOLIB_NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm +#define RADIOLIB_NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm +#define RADIOLIB_NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default) + +// RADIOLIB_NRF24_REG_STATUS +#define RADIOLIB_NRF24_RX_DR 0b01000000 // 6 6 Rx data ready +#define RADIOLIB_NRF24_TX_DS 0b00100000 // 5 5 Tx data sent +#define RADIOLIB_NRF24_MAX_RT 0b00010000 // 4 4 maximum number of retransmits reached (must be cleared to continue) +#define RADIOLIB_NRF24_RX_FIFO_EMPTY 0b00001110 // 3 1 Rx FIFO is empty +#define RADIOLIB_NRF24_RX_P_NO 0b00000000 // 3 1 number of data pipe that received data +#define RADIOLIB_NRF24_TX_FIFO_FULL 0b00000001 // 0 0 Tx FIFO is full + +// RADIOLIB_NRF24_REG_OBSERVE_TX +#define RADIOLIB_NRF24_PLOS_CNT 0b00000000 // 7 4 number of lost packets +#define RADIOLIB_NRF24_ARC_CNT 0b00000000 // 3 0 number of retransmitted packets + +// RADIOLIB_NRF24_REG_RPD +#define RADIOLIB_NRF24_RP_BELOW_64_DBM 0b00000000 // 0 0 received power in the current channel: less than -64 dBm +#define RADIOLIB_NRF24_RP_ABOVE_64_DBM 0b00000001 // 0 0 more than -64 dBm + +// RADIOLIB_NRF24_REG_FIFO_STATUS +#define RADIOLIB_NRF24_TX_REUSE 0b01000000 // 6 6 reusing last transmitted payload +#define RADIOLIB_NRF24_TX_FIFO_FULL_FLAG 0b00100000 // 5 5 Tx FIFO is full +#define RADIOLIB_NRF24_TX_FIFO_EMPTY_FLAG 0b00010000 // 4 4 Tx FIFO is empty +#define RADIOLIB_NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 1 1 Rx FIFO is full +#define RADIOLIB_NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 0 0 Rx FIFO is empty + +// RADIOLIB_NRF24_REG_DYNPD +#define RADIOLIB_NRF24_DPL_P5_OFF 0b00000000 // 5 5 dynamic payload length on pipe 5: disabled (default) +#define RADIOLIB_NRF24_DPL_P5_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_NRF24_DPL_P4_OFF 0b00000000 // 4 4 dynamic payload length on pipe 4: disabled (default) +#define RADIOLIB_NRF24_DPL_P4_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_NRF24_DPL_P3_OFF 0b00000000 // 3 3 dynamic payload length on pipe 3: disabled (default) +#define RADIOLIB_NRF24_DPL_P3_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_NRF24_DPL_P2_OFF 0b00000000 // 2 2 dynamic payload length on pipe 2: disabled (default) +#define RADIOLIB_NRF24_DPL_P2_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_DPL_P1_OFF 0b00000000 // 1 1 dynamic payload length on pipe 1: disabled (default) +#define RADIOLIB_NRF24_DPL_P1_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_NRF24_DPL_P0_OFF 0b00000000 // 0 0 dynamic payload length on pipe 0: disabled (default) +#define RADIOLIB_NRF24_DPL_P0_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_NRF24_DPL_ALL_OFF 0b00000000 // 5 0 disable all dynamic payloads +#define RADIOLIB_NRF24_DPL_ALL_ON 0b00111111 // 5 0 enable all dynamic payloads + +// RADIOLIB_NRF24_REG_FEATURE +#define RADIOLIB_NRF24_DPL_OFF 0b00000000 // 2 2 dynamic payload length: disabled (default) +#define RADIOLIB_NRF24_DPL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_NRF24_ACK_PAY_OFF 0b00000000 // 1 1 payload with ACK packets: disabled (default) +#define RADIOLIB_NRF24_ACK_PAY_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default) +#define RADIOLIB_NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled + +// RadioLib defaults +#define RADIOLIB_NRF24_DEFAULT_FREQ 2400 +#define RADIOLIB_NRF24_DEFAULT_DR 1000 +#define RADIOLIB_NRF24_DEFAULT_POWER -12 +#define RADIOLIB_NRF24_DEFAULT_ADDRWIDTH 5 /*! \class nRF24 - \brief Control class for %nRF24 module. */ class nRF24: public PhysicalLayer { @@ -193,7 +191,6 @@ class nRF24: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ nRF24(Module* mod); @@ -204,42 +201,33 @@ class nRF24: public PhysicalLayer { /*! \brief Initialization method. - \param freq Carrier frequency in MHz. Defaults to 2400 MHz. - - \param dataRate Data rate to be used in kbps. Defaults to 1000 kbps. - - \param power Output power in dBm. Defaults to -12 dBm. - + \param dr Data rate to be used in kbps. Defaults to 1000 kbps. + \param pwr Output power in dBm. Defaults to -12 dBm. \param addrWidth Address width in bytes. Defaults to 5 bytes. - \returns \ref status_codes */ int16_t begin( int16_t freq = RADIOLIB_NRF24_DEFAULT_FREQ, - int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR, - int8_t power = RADIOLIB_NRF24_DEFAULT_POWER, + int16_t dr = RADIOLIB_NRF24_DEFAULT_DR, + int8_t pwr = RADIOLIB_NRF24_DEFAULT_POWER, uint8_t addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH); /*! \brief Sets the module to sleep mode. - \returns \ref status_codes */ int16_t sleep(); /*! \brief Sets the module to standby mode. - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the module to standby. - \param mode Standby mode to be used. - \returns \ref status_codes */ int16_t standby(uint8_t mode) override; @@ -247,13 +235,9 @@ class nRF24: public PhysicalLayer { /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Dummy address parameter, to ensure PhysicalLayer compatibility. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr) override; @@ -261,27 +245,21 @@ class nRF24: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; /*! \brief Starts direct mode transmission. - \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Dummy direct mode reception method, to ensure PhysicalLayer compatibility. - \returns \ref status_codes */ int16_t receiveDirect() override; @@ -290,7 +268,6 @@ class nRF24: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when IRQ activates. - \param func ISR to call. */ void setIrqAction(void (*func)(void)); @@ -298,53 +275,39 @@ class nRF24: public PhysicalLayer { /*! \brief Interrupt-driven binary transmit method. IRQ will be activated when full packet is transmitted. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Dummy address parameter, to ensure PhysicalLayer compatibility. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. IRQ will be activated when full packet is received. - \returns \ref status_codes */ int16_t startReceive(); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param timeout Ignored. - \param irqFlags Ignored. - \param irqMask Ignored. - \param len Ignored. - \returns \ref status_codes */ int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data received after calling startReceive method. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; @@ -353,188 +316,133 @@ class nRF24: public PhysicalLayer { /*! \brief Sets carrier frequency. Allowed values range from 2400 MHz to 2525 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets bit rate. Allowed values are 2000, 1000 or 250 kbps. - \param br Bit rate to be set in kbps. - \returns \ref status_codes */ int16_t setBitRate(float br); /*! \brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); /*! \brief Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes. - \param addrWidth Address width to be set in bytes. - \returns \ref status_codes */ int16_t setAddressWidth(uint8_t addrWidth); /*! - \brief Sets address of transmit pipe. The address width must be the same as the same as the configured in setAddressWidth. - + \brief Sets address of transmit pipe. The address width must be the same as the same + as the configured in setAddressWidth. \param addr Address to which the next packet shall be transmitted. - \returns \ref status_codes */ int16_t setTransmitPipe(uint8_t* addr); /*! - \brief Sets address of receive pipes 0 or 1. The address width must be the same as the same as the configured in setAddressWidth. - - \param pipeNum Number of pipe to which the address shall be set. Either 0 or 1, other pipes are handled using overloaded method. - + \brief Sets address of receive pipes 0 or 1. The address width must be the same as the same + as the configured in setAddressWidth. + \param pipeNum Number of pipe to which the address shall be set. Either 0 or 1, + other pipes are handled using overloaded method. \param addr Address from which %nRF24 shall receive new packets on the specified pipe. - \returns \ref status_codes */ int16_t setReceivePipe(uint8_t pipeNum, uint8_t* addr); /*! - \brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes are the same as for address pipe 1, only the last byte can be set. - + \brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes + are the same as for address pipe 1, only the last byte can be set. \param pipeNum Number of pipe to which the address shall be set. Allowed values range from 2 to 5. - \param addrByte LSB of address from which %nRF24 shall receive new packets on the specified pipe. - \returns \ref status_codes */ int16_t setReceivePipe(uint8_t pipeNum, uint8_t addrByte); /*! \brief Disables specified receive pipe. - \param pipeNum Receive pipe to be disabled. - \returns \ref status_codes */ int16_t disablePipe(uint8_t pipeNum); /*! \brief Gets nRF24 status register. - \param mask Bit mask to be used on the returned register value. - \returns Status register value or \ref status_codes */ int16_t getStatus(uint8_t mask = 0xFF); /*! \brief Checks if carrier was detected during last RX - \returns Whatever the carrier was above threshold. */ bool isCarrierDetected(); /*! \brief Dummy configuration method, to ensure PhysicalLayer compatibility. - \param freqDev Dummy frequency deviation parameter, no configuration will be changed. - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! \brief Enable CRC filtering and generation. - \param crcOn Set or unset CRC check. - \returns \ref status_codes */ int16_t setCrcFiltering(bool crcOn = true); /*! - \brief Enable or disable auto-acknowledge packets on all pipes - + \brief Enable or disable auto-acknowledge packets on all pipes. \param autoAckOn Enable (true) or disable (false) auto-acks. - \returns \ref status_codes */ int16_t setAutoAck(bool autoAckOn = true); /*! \brief Enable or disable auto-acknowledge packets on given pipe. - \param pipeNum Number of pipe to which enable / disable auto-acks. - \param autoAckOn Enable (true) or disable (false) auto-acks. - \returns \ref status_codes */ int16_t setAutoAck(uint8_t pipeNum, bool autoAckOn); /*! \brief Dummy data shaping configuration method, to ensure PhysicalLayer compatibility. - \param sh Ignored. - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; /*! \brief Dummy encoding configuration method, to ensure PhysicalLayer compatibility. - \param sh Ignored. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; - /*! - \brief Dummy random method, to ensure PhysicalLayer compatibility. - - \returns Always returns 0. - */ - uint8_t randomByte(); - - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) - /*! - \brief Dummy method, to ensure PhysicalLayer compatibility. - - \param func Ignored. - */ - void setDirectAction(void (*func)(void)); - - /*! - \brief Dummy method, to ensure PhysicalLayer compatibility. - - \param pin Ignored. - */ - void readBit(uint32_t pin); - #endif - #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; void SPIreadRxPayload(uint8_t* data, uint8_t numBytes); void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes); @@ -544,11 +452,10 @@ class nRF24: public PhysicalLayer { protected: #endif - int16_t _freq = RADIOLIB_NRF24_DEFAULT_FREQ; - int16_t _dataRate = RADIOLIB_NRF24_DEFAULT_DR; - int8_t _power = RADIOLIB_NRF24_DEFAULT_POWER; - uint8_t _addrWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH; - + int16_t frequency = RADIOLIB_NRF24_DEFAULT_FREQ; + int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR; + int8_t power = RADIOLIB_NRF24_DEFAULT_POWER; + uint8_t addressWidth = RADIOLIB_NRF24_DEFAULT_ADDRWIDTH; int16_t config(); void clearIRQ(); From c62bb74f9d3f2ed9e231093664e3653f071b1ffb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 19:40:56 +0200 Subject: [PATCH 0512/1848] [CC1101] Fixed shadowed variable name --- src/modules/CC1101/CC1101.cpp | 8 ++++---- src/modules/CC1101/CC1101.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 242c5003e7..d12251bd8a 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -498,7 +498,7 @@ int16_t CC1101::setFrequency(float freq) { state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); if(state == RADIOLIB_ERR_NONE) { - this->freq = freq; + this->frequency = freq; } // Update the TX power accordingly to new freq. (PA values depend on chosen freq) @@ -601,13 +601,13 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { int16_t CC1101::setOutputPower(int8_t power) { // round to the known frequency settings uint8_t f; - if(this->freq < 374.0) { + if(this->frequency < 374.0) { // 315 MHz f = 0; - } else if(this->freq < 650.5) { + } else if(this->frequency < 650.5) { // 434 MHz f = 1; - } else if(this->freq < 891.5) { + } else if(this->frequency < 891.5) { // 868 MHz f = 2; } else { diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 1080ce1978..7654173b56 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -940,7 +940,7 @@ class CC1101: public PhysicalLayer { protected: #endif - float freq = RADIOLIB_CC1101_DEFAULT_FREQ; + float frequency = RADIOLIB_CC1101_DEFAULT_FREQ; float bitRate = RADIOLIB_CC1101_DEFAULT_BR; uint8_t rawRSSI = 0; uint8_t rawLQI = 0; From 9be1cdfa4198e88966067a78237a4fabd778867e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 19:43:48 +0200 Subject: [PATCH 0513/1848] [RF69] General reformatting --- src/modules/RF69/RF69.cpp | 386 ++++++------- src/modules/RF69/RF69.h | 1111 +++++++++++++++++-------------------- 2 files changed, 694 insertions(+), 803 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 9d46c3089f..5bef0a2f14 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -3,17 +3,17 @@ #if !defined(RADIOLIB_EXCLUDE_RF69) RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) { - _mod = module; + this->mod = module; } Module* RF69::getMod() { - return(_mod); + return(this->mod); } int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); // try to find the RF69 chip uint8_t i = 0; @@ -28,14 +28,14 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); - _mod->hal->delay(10); + this->mod->hal->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN("No RF69 found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { RADIOLIB_DEBUG_PRINTLN("M\tRF69"); @@ -50,7 +50,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_ASSERT(state); // configure bitrate - _rxBw = rxBw; + this->rxBandwidth = rxBw; state = setBitRate(br); RADIOLIB_ASSERT(state); @@ -95,27 +95,27 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe } void RF69::reset() { - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); - _mod->hal->delay(10); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(10); } int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -126,18 +126,18 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t RF69::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { standby(); clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -150,7 +150,7 @@ int16_t RF69::receive(uint8_t* data, size_t len) { int16_t RF69::sleep() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); // set module to sleep return(setMode(RADIOLIB_RF69_SLEEP)); @@ -158,7 +158,7 @@ int16_t RF69::sleep() { int16_t RF69::standby() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); // set module to standby return(setMode(RADIOLIB_RF69_STANDBY)); @@ -171,13 +171,13 @@ int16_t RF69::standby(uint8_t mode) { int16_t RF69::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (frf & 0xFF0000) >> 16); - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (frf & 0x00FF00) >> 8); - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, frf & 0x0000FF); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (frf & 0x00FF00) >> 8); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, frf & 0x0000FF); return(setMode(RADIOLIB_RF69_TX)); } @@ -192,7 +192,7 @@ int16_t RF69::transmitDirect(uint32_t frf) { int16_t RF69::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(); @@ -208,31 +208,31 @@ int16_t RF69::directMode() { RADIOLIB_ASSERT(state); // set DIO mapping - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_CONT_DCLK | RADIOLIB_RF69_DIO2_CONT_DATA, 5, 2); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_CONT_DCLK | RADIOLIB_RF69_DIO2_CONT_DATA, 5, 2); RADIOLIB_ASSERT(state); // set continuous mode - if(_bitSync) { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); + if(this->bitSync) { + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5)); } } int16_t RF69::packetMode() { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE, 6, 5)); } void RF69::setAESKey(uint8_t* key) { - _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_AES_KEY_1, key, 16); + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_AES_KEY_1, key, 16); } int16_t RF69::enableAES() { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_ON, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_ON, 0, 0)); } int16_t RF69::disableAES() { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_OFF, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AES_OFF, 0, 0)); } int16_t RF69::startReceive() { @@ -241,21 +241,21 @@ int16_t RF69::startReceive() { RADIOLIB_ASSERT(state); // set RX timeouts and DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY, 7, 4); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY, 7, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH); RADIOLIB_ASSERT(state); // clear interrupt flags clearIRQFlags(); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to receive - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_NORMAL); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_NORMAL); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_NORMAL); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_NORMAL); RADIOLIB_ASSERT(state); state = setMode(RADIOLIB_RF69_RX); @@ -272,37 +272,37 @@ int16_t RF69::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask } void RF69::setDio0Action(void (*func)(void)) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptRising); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); } void RF69::clearDio0Action() { - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } void RF69::setDio1Action(void (*func)(void)) { - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, _mod->hal->GpioInterruptRising); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, this->mod->hal->GpioInterruptRising); } void RF69::clearDio1Action() { - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); } void RF69::setFifoEmptyAction(void (*func)(void)) { // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); // we need to invert the logic here (as compared to setDio1Action), since we are using the "FIFO not empty interrupt" - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, _mod->hal->GpioInterruptFalling); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, this->mod->hal->GpioInterruptFalling); } void RF69::clearFifoEmptyAction() { @@ -311,8 +311,8 @@ void RF69::clearFifoEmptyAction() { void RF69::setFifoFullAction(void (*func)(void)) { // set the interrupt - _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_FIFO_THRESH, 6, 0); - _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL, 5, 4); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_FIFO_THRESH, 6, 0); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL, 5, 4); // set DIO1 to the FIFO full event setDio1Action(func); @@ -320,7 +320,7 @@ void RF69::setFifoFullAction(void (*func)(void)) { void RF69::clearFifoFullAction() { clearDio1Action(); - _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, 0x00, 5, 4); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, 0x00, 5, 4); } bool RF69::fifoAdd(uint8_t* data, int totalLen, int* remLen) { @@ -340,7 +340,7 @@ bool RF69::fifoAdd(uint8_t* data, int totalLen, int* remLen) { } // copy the bytes to the FIFO - _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, &data[totalLen - *remLen], len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, &data[totalLen - *remLen], len); // we're not done yet return(false); @@ -358,7 +358,7 @@ bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { } // get the data - _mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, len, dataPtr); + this->mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, len, dataPtr); (*rcvLen) += (len); // check if we're done @@ -378,47 +378,47 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set DIO mapping if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY, 5, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY, 5, 4); } else { - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PACKET_SENT, 7, 6); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, RADIOLIB_RF69_DIO0_PACK_PACKET_SENT, 7, 6); } RADIOLIB_ASSERT(state); // optionally write packet length - if (_packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, len); + if (this->packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, len); } // check address filtering - uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); if((filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, addr); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, addr); } // write packet to FIFO size_t packetLen = len; if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { packetLen = RADIOLIB_RF69_FIFO_THRESH - 1; - _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY, 7, 7); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY, 7, 7); } - _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, packetLen); + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, packetLen); // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should // just add a padding byte that can be dropped without consequence if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); } // enable +20 dBm operation - if(_power > 17) { - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_OFF | 0x0F); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_20_DBM); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_20_DBM); + if(this->power > 17) { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_OFF | 0x0F); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA1, RADIOLIB_RF69_PA1_20_DBM); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_PA2, RADIOLIB_RF69_PA2_20_DBM); RADIOLIB_ASSERT(state); } // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // set mode to transmit state = setMode(RADIOLIB_RF69_TX); @@ -449,13 +449,13 @@ int16_t RF69::readData(uint8_t* data, size_t len) { } // check address filtering - uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, 2, 1); if((filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + this->mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); } // read packet data - _mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, length, data); + this->mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, length, data); // dump the bytes that weren't requested if(dumpLen != 0) { @@ -463,7 +463,7 @@ int16_t RF69::readData(uint8_t* data, size_t len) { } // clear internal flag so getPacketLength can return the new packet length - _packetLengthQueried = false; + this->packetLengthQueried = false; // clear interrupt flags clearIRQFlags(); @@ -471,21 +471,21 @@ int16_t RF69::readData(uint8_t* data, size_t len) { return(RADIOLIB_ERR_NONE); } -int16_t RF69::setOOK(bool enableOOK) { +int16_t RF69::setOOK(bool enable) { // set OOK and if successful, save the new setting int16_t state = RADIOLIB_ERR_NONE; - if(enableOOK) { - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_OOK, 4, 3, 5); + if(enable) { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_OOK, 4, 3, 5); } else { - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK, 4, 3, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK, 4, 3, 5); } if(state == RADIOLIB_ERR_NONE) { - _ook = enableOOK; + this->ookEnabled = enable; } // call setRxBandwidth again, since register values differ based on OOK mode being enabled - state |= setRxBandwidth(_rxBw); + state |= setRxBandwidth(this->rxBandwidth); return(state); } @@ -494,15 +494,15 @@ int16_t RF69::setOokThresholdType(uint8_t type) { if((type != RADIOLIB_RF69_OOK_THRESH_FIXED) && (type != RADIOLIB_RF69_OOK_THRESH_PEAK) && (type != RADIOLIB_RF69_OOK_THRESH_AVERAGE)) { return(RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE); } - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, type, 7, 3, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, type, 7, 3, 5)); } int16_t RF69::setOokFixedThreshold(uint8_t value) { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_FIX, value, 7, 0, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_FIX, value, 7, 0, 5)); } int16_t RF69::setOokPeakThresholdDecrement(uint8_t value) { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, value, 2, 0, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OOK_PEAK, value, 2, 0, 5)); } int16_t RF69::setFrequency(float freq) { @@ -519,9 +519,9 @@ int16_t RF69::setFrequency(float freq) { //set carrier frequency //FRF(23:0) = freq / Fstep = freq * (1 / Fstep) = freq * (2^19 / 32.0) (pag. 17 of datasheet) uint32_t FRF = (freq * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / RADIOLIB_RF69_CRYSTAL_FREQ; - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, FRF & 0x0000FF); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FRF_LSB, FRF & 0x0000FF); return(RADIOLIB_ERR_NONE); } @@ -531,9 +531,9 @@ int16_t RF69::getFrequency(float *freq) { //FRF(23:0) = [ [FRF_MSB]|[FRF_MID]|[FRF_LSB]] //FRF(32:0) = [0x00|[FRF_MSB]|[FRF_MID]|[FRF_LSB]] - FRF |= (((uint32_t)(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MSB, 7, 0)) << 16) & 0x00FF0000); - FRF |= (((uint32_t)(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MID, 7, 0)) << 8) & 0x0000FF00); - FRF |= (((uint32_t)(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_LSB, 7, 0)) << 0) & 0x000000FF); + FRF |= (((uint32_t)(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MSB, 7, 0)) << 16) & 0x00FF0000); + FRF |= (((uint32_t)(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_MID, 7, 0)) << 8) & 0x0000FF00); + FRF |= (((uint32_t)(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FRF_LSB, 7, 0)) << 0) & 0x000000FF); //freq = Fstep * FRF(23:0) = (32.0 / 2^19) * FRF(23:0) (pag. 17 of datasheet) *freq = FRF * ( RADIOLIB_RF69_CRYSTAL_FREQ / (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT) ); @@ -546,7 +546,7 @@ int16_t RF69::setBitRate(float br) { RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); // check bitrate-bandwidth ratio - if(!(br < 2000 * _rxBw)) { + if(!(br < 2000 * this->rxBandwidth)) { return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); } @@ -555,17 +555,17 @@ int16_t RF69::setBitRate(float br) { // set bit rate uint16_t bitRate = 32000 / br; - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); if(state == RADIOLIB_ERR_NONE) { - _br = br; + this->bitRate = br; } return(state); } int16_t RF69::setRxBandwidth(float rxBw) { // check bitrate-bandwidth ratio - if(!(_br < 2000 * rxBw)) { + if(!(this->bitRate < 2000 * rxBw)) { return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); } @@ -576,12 +576,12 @@ int16_t RF69::setRxBandwidth(float rxBw) { // calculate exponent and mantissa values for receiver bandwidth for(int8_t e = 7; e >= 0; e--) { for(int8_t m = 2; m >= 0; m--) { - float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (_ook ? 3 : 2)))); + float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2)))); if(fabs(rxBw - (point / 1000.0)) <= 0.1) { // set Rx bandwidth - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); if(state == RADIOLIB_ERR_NONE) { - _rxBw = rxBw; + this->rxBandwidth = rxBw; } return(state); } @@ -599,7 +599,7 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { } // check frequency deviation range - if(!((newFreqDev + _br/2 <= 500))) { + if(!((newFreqDev + this->bitRate/2 <= 500))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } @@ -608,18 +608,18 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { // set frequency deviation from carrier frequency uint32_t fdev = (newFreqDev * (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT)) / 32000; - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0); return(state); } int16_t RF69::getFrequencyDeviation(float *freqDev) { - if (freqDev == NULL) { + if(freqDev == NULL) { return(RADIOLIB_ERR_NULL_POINTER); } - if (RF69::_ook) { + if(this->ookEnabled) { *freqDev = 0.0; return(RADIOLIB_ERR_NONE); @@ -627,8 +627,8 @@ int16_t RF69::getFrequencyDeviation(float *freqDev) { // get raw value from register uint32_t fdev = 0; - fdev |= (uint32_t)((_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, 5, 0) << 8) & 0x0000FF00); - fdev |= (uint32_t)((_mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, 7, 0) << 0) & 0x000000FF); + fdev |= (uint32_t)((this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_MSB, 5, 0) << 8) & 0x0000FF00); + fdev |= (uint32_t)((this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_FDEV_LSB, 7, 0) << 0) & 0x000000FF); // calculate frequency deviation from raw value obtained from register // Fdev = Fstep * Fdev(13:0) (pag. 20 of datasheet) @@ -638,11 +638,11 @@ int16_t RF69::getFrequencyDeviation(float *freqDev) { return(RADIOLIB_ERR_NONE); } -int16_t RF69::setOutputPower(int8_t power, bool highPower) { +int16_t RF69::setOutputPower(int8_t pwr, bool highPower) { if(highPower) { - RADIOLIB_CHECK_RANGE(power, -2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(pwr, -2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } else { - RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } // set mode to standby @@ -652,25 +652,25 @@ int16_t RF69::setOutputPower(int8_t power, bool highPower) { int16_t state; if(highPower) { // check if both PA1 and PA2 are needed - if(power <= 10) { + if(pwr <= 10) { // -2 to 13 dBm, PA1 is enough - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); - } else if(power <= 17) { + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); + } else if(pwr <= 17) { // 13 to 17 dBm, both PAs required - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 14), 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 14), 7, 0); } else { // 18 - 20 dBm, both PAs and hig power settings required - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 11), 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_OFF | RADIOLIB_RF69_PA1_ON | RADIOLIB_RF69_PA2_ON | (power + 11), 7, 0); } } else { // low power module, use only PA0 - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_ON | RADIOLIB_RF69_PA1_OFF | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PA_LEVEL, RADIOLIB_RF69_PA0_ON | RADIOLIB_RF69_PA1_OFF | RADIOLIB_RF69_PA2_OFF | (power + 18), 7, 0); } // cache the power value if(state == RADIOLIB_ERR_NONE) { - _power = power; + this->power = pwr; } return(state); @@ -693,10 +693,10 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { RADIOLIB_ASSERT(state); // set sync word register - _mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); if(state == RADIOLIB_ERR_NONE) { - _syncWordLength = len; + this->syncWordLength = len; } return(state); @@ -709,44 +709,44 @@ int16_t RF69::setPreambleLength(uint8_t preambleLen) { } uint8_t preLenBytes = preambleLen / 8; - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0x00); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_PREAMBLE_MSB, 0x00); - return (_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes)); + return (this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PREAMBLE_LSB, preLenBytes)); } int16_t RF69::setNodeAddress(uint8_t nodeAddr) { // enable address filtering (node only) - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE, 2, 1); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE, 2, 1); RADIOLIB_ASSERT(state); // set node address - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, nodeAddr)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, nodeAddr)); } int16_t RF69::setBroadcastAddress(uint8_t broadAddr) { // enable address filtering (node + broadcast) - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); RADIOLIB_ASSERT(state); // set broadcast address - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, broadAddr)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, broadAddr)); } int16_t RF69::disableAddressFiltering() { // disable address filtering - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 2, 1); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 2, 1); RADIOLIB_ASSERT(state); // set node address to default (0x00) - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, 0x00); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_NODE_ADRS, 0x00); RADIOLIB_ASSERT(state); // set broadcast address to default (0x00) - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, 0x00)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BROADCAST_ADRS, 0x00)); } void RF69::setAmbientTemperature(int16_t tempAmbient) { - _tempOffset = getTemperature() - tempAmbient; + this->tempOffset = getTemperature() - tempAmbient; } int16_t RF69::getTemperature() { @@ -754,29 +754,29 @@ int16_t RF69::getTemperature() { setMode(RADIOLIB_RF69_STANDBY); // start temperature measurement - _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEMP_1, RADIOLIB_RF69_TEMP_MEAS_START, 3, 3); + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEMP_1, RADIOLIB_RF69_TEMP_MEAS_START, 3, 3); // wait until measurement is finished - while(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_1, 2, 2) == RADIOLIB_RF69_TEMP_MEAS_RUNNING) { + while(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_1, 2, 2) == RADIOLIB_RF69_TEMP_MEAS_RUNNING) { // check every 10 us - _mod->hal->delay(10); + this->mod->hal->delay(10); } - int8_t rawTemp = _mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_2); + int8_t rawTemp = this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_TEMP_2); - return(0 - (rawTemp + _tempOffset)); + return(0 - (rawTemp + this->tempOffset)); } size_t RF69::getPacketLength(bool update) { - if(!_packetLengthQueried && update) { - if (_packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { - _packetLength = _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_RF69_PACKET_FORMAT_VARIABLE) { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); } else { - _packetLength = _mod->SPIreadRegister(RADIOLIB_RF69_REG_PAYLOAD_LENGTH); + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_RF69_REG_PAYLOAD_LENGTH); } - _packetLengthQueried = true; + this->packetLengthQueried = true; } - return(_packetLength); + return(this->packetLength); } int16_t RF69::fixedPacketLengthMode(uint8_t len) { @@ -789,27 +789,27 @@ int16_t RF69::variablePacketLengthMode(uint8_t maxLen) { int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) { // enable sync word recognition - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC | (_syncWordLength - 1) << 3 | maxErrBits, 7, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC | (this->syncWordLength - 1) << 3 | maxErrBits, 7, 0)); } int16_t RF69::disableSyncWordFiltering() { // disable sync word detection and generation - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_OFF | RADIOLIB_RF69_FIFO_FILL_CONDITION, 7, 6)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_OFF | RADIOLIB_RF69_FIFO_FILL_CONDITION, 7, 6)); } int16_t RF69::enableContinuousModeBitSync() { - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5); if(state == RADIOLIB_ERR_NONE) { - _bitSync = true; + this->bitSync = true; } return(state); } int16_t RF69::disableContinuousModeBitSync() { - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_CONTINUOUS_MODE, 6, 5); if(state == RADIOLIB_ERR_NONE) { - _bitSync = false; + this->bitSync = false; } return(state); @@ -817,20 +817,20 @@ int16_t RF69::disableContinuousModeBitSync() { int16_t RF69::setCrcFiltering(bool crcOn) { if (crcOn == true) { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_ON, 4, 4)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_ON, 4, 4)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_OFF, 4, 4)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_CRC_OFF, 4, 4)); } } -int16_t RF69::setPromiscuousMode(bool promiscuous) { +int16_t RF69::setPromiscuousMode(bool enable) { int16_t state = RADIOLIB_ERR_NONE; - if (_promiscuous == promiscuous) { + if (this->promiscuous == enable) { return(state); } - if (promiscuous == true) { + if (enable == true) { // disable preamble detection and generation state = setPreambleLength(0); RADIOLIB_ASSERT(state); @@ -854,7 +854,7 @@ int16_t RF69::setPromiscuousMode(bool promiscuous) { state = setCrcFiltering(true); } if(state == RADIOLIB_ERR_NONE) { - _promiscuous = promiscuous; + this->promiscuous = enable; } @@ -869,13 +869,13 @@ int16_t RF69::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_NO_SHAPING, 1, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_NO_SHAPING, 1, 0)); case RADIOLIB_SHAPING_0_3: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0)); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_5, 1, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_5, 1, 0)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_1_0, 1, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_1_0, 1, 0)); default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } @@ -889,11 +889,11 @@ int16_t RF69::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_NONE, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_NONE, 6, 5)); case RADIOLIB_ENCODING_MANCHESTER: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_MANCHESTER, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_MANCHESTER, 6, 5)); case RADIOLIB_ENCODING_WHITENING: - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_WHITENING, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_DC_FREE_WHITENING, 6, 5)); default: return(RADIOLIB_ERR_INVALID_ENCODING); } @@ -901,28 +901,28 @@ int16_t RF69::setEncoding(uint8_t encoding) { int16_t RF69::setLnaTestBoost(bool value) { if(value) { - return (_mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_LNA, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); + return (this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_LNA, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); } - return(_mod->SPIsetRegValue(RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL, RADIOLIB_RF69_TEST_LNA_BOOST_HIGH, 7, 0)); } float RF69::getRSSI() { - return(-1.0 * (_mod->SPIgetRegValue(RADIOLIB_RF69_REG_RSSI_VALUE)/2.0)); + return(-1.0 * (this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_RSSI_VALUE)/2.0)); } int16_t RF69::setRSSIThreshold(float dbm) { RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); - return _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); + return this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } void RF69::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - _mod->setRfSwitchPins(rxEn, txEn); + this->mod->setRfSwitchPins(rxEn, txEn); } void RF69::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - _mod->setRfSwitchTable(pins, table); + this->mod->setRfSwitchTable(pins, table); } uint8_t RF69::randomByte() { @@ -930,12 +930,12 @@ uint8_t RF69::randomByte() { setMode(RADIOLIB_RF69_RX); // wait a bit for the RSSI reading to stabilise - _mod->hal->delay(10); + this->mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { - randByte |= ((_mod->SPIreadRegister(RADIOLIB_RF69_REG_RSSI_VALUE) & 0x01) << i); + randByte |= ((this->mod->SPIreadRegister(RADIOLIB_RF69_REG_RSSI_VALUE) & 0x01) << i); } // set mode to standby @@ -950,7 +950,7 @@ void RF69::setDirectAction(void (*func)(void)) { } void RF69::readBit(uint32_t pin) { - updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); } #endif @@ -960,14 +960,14 @@ int16_t RF69::setDIOMapping(uint32_t pin, uint32_t value) { } if(pin < 4) { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); } - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); } int16_t RF69::getChipVersion() { - return(_mod->SPIgetRegValue(RADIOLIB_RF69_REG_VERSION)); + return(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_VERSION)); } int16_t RF69::config() { @@ -978,50 +978,50 @@ int16_t RF69::config() { RADIOLIB_ASSERT(state); // set operation modes - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, RADIOLIB_RF69_SEQUENCER_ON | RADIOLIB_RF69_LISTEN_OFF, 7, 6); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, RADIOLIB_RF69_SEQUENCER_ON | RADIOLIB_RF69_LISTEN_OFF, 7, 6); RADIOLIB_ASSERT(state); // enable over-current protection - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON, 4, 4); RADIOLIB_ASSERT(state); // set data mode, modulation type and shaping - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE | RADIOLIB_RF69_FSK, 6, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE | RADIOLIB_RF69_FSK, 6, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_FSK_GAUSSIAN_0_3, 1, 0); RADIOLIB_ASSERT(state); // set RSSI threshold - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, RADIOLIB_RF69_RSSI_THRESHOLD, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, RADIOLIB_RF69_RSSI_THRESHOLD, 7, 0); RADIOLIB_ASSERT(state); // reset FIFO flag - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, RADIOLIB_RF69_IRQ_FIFO_OVERRUN); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, RADIOLIB_RF69_IRQ_FIFO_OVERRUN); // disable ClkOut on DIO5 - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, RADIOLIB_RF69_CLK_OUT_OFF, 2, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, RADIOLIB_RF69_CLK_OUT_OFF, 2, 0); RADIOLIB_ASSERT(state); // set packet configuration and disable encryption - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_PACKET_FORMAT_VARIABLE | RADIOLIB_RF69_DC_FREE_NONE | RADIOLIB_RF69_CRC_ON | RADIOLIB_RF69_CRC_AUTOCLEAR_ON | RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 7, 1); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_INTER_PACKET_RX_DELAY, 7, 4); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AUTO_RX_RESTART_ON | RADIOLIB_RF69_AES_OFF, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, RADIOLIB_RF69_PACKET_FORMAT_VARIABLE | RADIOLIB_RF69_DC_FREE_NONE | RADIOLIB_RF69_CRC_ON | RADIOLIB_RF69_CRC_AUTOCLEAR_ON | RADIOLIB_RF69_ADDRESS_FILTERING_OFF, 7, 1); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_INTER_PACKET_RX_DELAY, 7, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_2, RADIOLIB_RF69_AUTO_RX_RESTART_ON | RADIOLIB_RF69_AES_OFF, 1, 0); RADIOLIB_ASSERT(state); // set payload length - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, RADIOLIB_RF69_PAYLOAD_LENGTH, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, RADIOLIB_RF69_PAYLOAD_LENGTH, 7, 0); RADIOLIB_ASSERT(state); // set FIFO threshold - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RADIOLIB_RF69_FIFO_THRESH, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RADIOLIB_RF69_FIFO_THRESH, 7, 0); RADIOLIB_ASSERT(state); // set Rx timeouts - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START, 7, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_1, RADIOLIB_RF69_TIMEOUT_RX_START, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_TIMEOUT_2, RADIOLIB_RF69_TIMEOUT_RSSI_THRESH, 7, 0); RADIOLIB_ASSERT(state); // enable improved fading margin - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_DAGC, RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_TEST_DAGC, RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0); return(state); } @@ -1033,30 +1033,30 @@ int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) { } // set to fixed packet length - int16_t state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, mode, 7, 7); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PACKET_CONFIG_1, mode, 7, 7); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, len); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update the cached value - _packetLengthConfig = mode; + this->packetLengthConfig = mode; return(state); } int16_t RF69::setMode(uint8_t mode) { - return(_mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, mode, 4, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OP_MODE, mode, 4, 2)); } void RF69::clearIRQFlags() { - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_1, 0b11111111); - _mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_1, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_IRQ_FLAGS_2, 0b11111111); } void RF69::clearFIFO(size_t count) { while(count) { - _mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); + this->mod->SPIreadRegister(RADIOLIB_RF69_REG_FIFO); count--; } } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 3b7e7129fb..018e0ecc15 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -10,470 +10,470 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // RF69 physical layer properties -#define RADIOLIB_RF69_FREQUENCY_STEP_SIZE 61.03515625 -#define RADIOLIB_RF69_MAX_PACKET_LENGTH 64 -#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0 -#define RADIOLIB_RF69_DIV_EXPONENT 19 +#define RADIOLIB_RF69_FREQUENCY_STEP_SIZE 61.03515625 +#define RADIOLIB_RF69_MAX_PACKET_LENGTH 64 +#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0 +#define RADIOLIB_RF69_DIV_EXPONENT 19 // RF69 register map -#define RADIOLIB_RF69_REG_FIFO 0x00 -#define RADIOLIB_RF69_REG_OP_MODE 0x01 -#define RADIOLIB_RF69_REG_DATA_MODUL 0x02 -#define RADIOLIB_RF69_REG_BITRATE_MSB 0x03 -#define RADIOLIB_RF69_REG_BITRATE_LSB 0x04 -#define RADIOLIB_RF69_REG_FDEV_MSB 0x05 -#define RADIOLIB_RF69_REG_FDEV_LSB 0x06 -#define RADIOLIB_RF69_REG_FRF_MSB 0x07 -#define RADIOLIB_RF69_REG_FRF_MID 0x08 -#define RADIOLIB_RF69_REG_FRF_LSB 0x09 -#define RADIOLIB_RF69_REG_OSC_1 0x0A -#define RADIOLIB_RF69_REG_AFC_CTRL 0x0B -#define RADIOLIB_RF69_REG_LISTEN_1 0x0D -#define RADIOLIB_RF69_REG_LISTEN_2 0x0E -#define RADIOLIB_RF69_REG_LISTEN_3 0x0F -#define RADIOLIB_RF69_REG_VERSION 0x10 -#define RADIOLIB_RF69_REG_PA_LEVEL 0x11 -#define RADIOLIB_RF69_REG_PA_RAMP 0x12 -#define RADIOLIB_RF69_REG_OCP 0x13 -#define RADIOLIB_RF69_REG_LNA 0x18 -#define RADIOLIB_RF69_REG_RX_BW 0x19 -#define RADIOLIB_RF69_REG_AFC_BW 0x1A -#define RADIOLIB_RF69_REG_OOK_PEAK 0x1B -#define RADIOLIB_RF69_REG_OOK_AVG 0x1C -#define RADIOLIB_RF69_REG_OOK_FIX 0x1D -#define RADIOLIB_RF69_REG_AFC_FEI 0x1E -#define RADIOLIB_RF69_REG_AFC_MSB 0x1F -#define RADIOLIB_RF69_REG_AFC_LSB 0x20 -#define RADIOLIB_RF69_REG_FEI_MSB 0x21 -#define RADIOLIB_RF69_REG_FEI_LSB 0x22 -#define RADIOLIB_RF69_REG_RSSI_CONFIG 0x23 -#define RADIOLIB_RF69_REG_RSSI_VALUE 0x24 -#define RADIOLIB_RF69_REG_DIO_MAPPING_1 0x25 -#define RADIOLIB_RF69_REG_DIO_MAPPING_2 0x26 -#define RADIOLIB_RF69_REG_IRQ_FLAGS_1 0x27 -#define RADIOLIB_RF69_REG_IRQ_FLAGS_2 0x28 -#define RADIOLIB_RF69_REG_RSSI_THRESH 0x29 -#define RADIOLIB_RF69_REG_RX_TIMEOUT_1 0x2A -#define RADIOLIB_RF69_REG_RX_TIMEOUT_2 0x2B -#define RADIOLIB_RF69_REG_PREAMBLE_MSB 0x2C -#define RADIOLIB_RF69_REG_PREAMBLE_LSB 0x2D -#define RADIOLIB_RF69_REG_SYNC_CONFIG 0x2E -#define RADIOLIB_RF69_REG_SYNC_VALUE_1 0x2F -#define RADIOLIB_RF69_REG_SYNC_VALUE_2 0x30 -#define RADIOLIB_RF69_REG_SYNC_VALUE_3 0x31 -#define RADIOLIB_RF69_REG_SYNC_VALUE_4 0x32 -#define RADIOLIB_RF69_REG_SYNC_VALUE_5 0x33 -#define RADIOLIB_RF69_REG_SYNC_VALUE_6 0x34 -#define RADIOLIB_RF69_REG_SYNC_VALUE_7 0x35 -#define RADIOLIB_RF69_REG_SYNC_VALUE_8 0x36 -#define RADIOLIB_RF69_REG_PACKET_CONFIG_1 0x37 -#define RADIOLIB_RF69_REG_PAYLOAD_LENGTH 0x38 -#define RADIOLIB_RF69_REG_NODE_ADRS 0x39 -#define RADIOLIB_RF69_REG_BROADCAST_ADRS 0x3A -#define RADIOLIB_RF69_REG_AUTO_MODES 0x3B -#define RADIOLIB_RF69_REG_FIFO_THRESH 0x3C -#define RADIOLIB_RF69_REG_PACKET_CONFIG_2 0x3D -#define RADIOLIB_RF69_REG_AES_KEY_1 0x3E -#define RADIOLIB_RF69_REG_AES_KEY_2 0x3F -#define RADIOLIB_RF69_REG_AES_KEY_3 0x40 -#define RADIOLIB_RF69_REG_AES_KEY_4 0x41 -#define RADIOLIB_RF69_REG_AES_KEY_5 0x42 -#define RADIOLIB_RF69_REG_AES_KEY_6 0x43 -#define RADIOLIB_RF69_REG_AES_KEY_7 0x44 -#define RADIOLIB_RF69_REG_AES_KEY_8 0x45 -#define RADIOLIB_RF69_REG_AES_KEY_9 0x46 -#define RADIOLIB_RF69_REG_AES_KEY_10 0x47 -#define RADIOLIB_RF69_REG_AES_KEY_11 0x48 -#define RADIOLIB_RF69_REG_AES_KEY_12 0x49 -#define RADIOLIB_RF69_REG_AES_KEY_13 0x4A -#define RADIOLIB_RF69_REG_AES_KEY_14 0x4B -#define RADIOLIB_RF69_REG_AES_KEY_15 0x4C -#define RADIOLIB_RF69_REG_AES_KEY_16 0x4D -#define RADIOLIB_RF69_REG_TEMP_1 0x4E -#define RADIOLIB_RF69_REG_TEMP_2 0x4F -#define RADIOLIB_RF69_REG_TEST_LNA 0x58 -#define RADIOLIB_RF69_REG_TEST_PA1 0x5A -#define RADIOLIB_RF69_REG_TEST_PA2 0x5C -#define RADIOLIB_RF69_REG_TEST_DAGC 0x6F +#define RADIOLIB_RF69_REG_FIFO 0x00 +#define RADIOLIB_RF69_REG_OP_MODE 0x01 +#define RADIOLIB_RF69_REG_DATA_MODUL 0x02 +#define RADIOLIB_RF69_REG_BITRATE_MSB 0x03 +#define RADIOLIB_RF69_REG_BITRATE_LSB 0x04 +#define RADIOLIB_RF69_REG_FDEV_MSB 0x05 +#define RADIOLIB_RF69_REG_FDEV_LSB 0x06 +#define RADIOLIB_RF69_REG_FRF_MSB 0x07 +#define RADIOLIB_RF69_REG_FRF_MID 0x08 +#define RADIOLIB_RF69_REG_FRF_LSB 0x09 +#define RADIOLIB_RF69_REG_OSC_1 0x0A +#define RADIOLIB_RF69_REG_AFC_CTRL 0x0B +#define RADIOLIB_RF69_REG_LISTEN_1 0x0D +#define RADIOLIB_RF69_REG_LISTEN_2 0x0E +#define RADIOLIB_RF69_REG_LISTEN_3 0x0F +#define RADIOLIB_RF69_REG_VERSION 0x10 +#define RADIOLIB_RF69_REG_PA_LEVEL 0x11 +#define RADIOLIB_RF69_REG_PA_RAMP 0x12 +#define RADIOLIB_RF69_REG_OCP 0x13 +#define RADIOLIB_RF69_REG_LNA 0x18 +#define RADIOLIB_RF69_REG_RX_BW 0x19 +#define RADIOLIB_RF69_REG_AFC_BW 0x1A +#define RADIOLIB_RF69_REG_OOK_PEAK 0x1B +#define RADIOLIB_RF69_REG_OOK_AVG 0x1C +#define RADIOLIB_RF69_REG_OOK_FIX 0x1D +#define RADIOLIB_RF69_REG_AFC_FEI 0x1E +#define RADIOLIB_RF69_REG_AFC_MSB 0x1F +#define RADIOLIB_RF69_REG_AFC_LSB 0x20 +#define RADIOLIB_RF69_REG_FEI_MSB 0x21 +#define RADIOLIB_RF69_REG_FEI_LSB 0x22 +#define RADIOLIB_RF69_REG_RSSI_CONFIG 0x23 +#define RADIOLIB_RF69_REG_RSSI_VALUE 0x24 +#define RADIOLIB_RF69_REG_DIO_MAPPING_1 0x25 +#define RADIOLIB_RF69_REG_DIO_MAPPING_2 0x26 +#define RADIOLIB_RF69_REG_IRQ_FLAGS_1 0x27 +#define RADIOLIB_RF69_REG_IRQ_FLAGS_2 0x28 +#define RADIOLIB_RF69_REG_RSSI_THRESH 0x29 +#define RADIOLIB_RF69_REG_RX_TIMEOUT_1 0x2A +#define RADIOLIB_RF69_REG_RX_TIMEOUT_2 0x2B +#define RADIOLIB_RF69_REG_PREAMBLE_MSB 0x2C +#define RADIOLIB_RF69_REG_PREAMBLE_LSB 0x2D +#define RADIOLIB_RF69_REG_SYNC_CONFIG 0x2E +#define RADIOLIB_RF69_REG_SYNC_VALUE_1 0x2F +#define RADIOLIB_RF69_REG_SYNC_VALUE_2 0x30 +#define RADIOLIB_RF69_REG_SYNC_VALUE_3 0x31 +#define RADIOLIB_RF69_REG_SYNC_VALUE_4 0x32 +#define RADIOLIB_RF69_REG_SYNC_VALUE_5 0x33 +#define RADIOLIB_RF69_REG_SYNC_VALUE_6 0x34 +#define RADIOLIB_RF69_REG_SYNC_VALUE_7 0x35 +#define RADIOLIB_RF69_REG_SYNC_VALUE_8 0x36 +#define RADIOLIB_RF69_REG_PACKET_CONFIG_1 0x37 +#define RADIOLIB_RF69_REG_PAYLOAD_LENGTH 0x38 +#define RADIOLIB_RF69_REG_NODE_ADRS 0x39 +#define RADIOLIB_RF69_REG_BROADCAST_ADRS 0x3A +#define RADIOLIB_RF69_REG_AUTO_MODES 0x3B +#define RADIOLIB_RF69_REG_FIFO_THRESH 0x3C +#define RADIOLIB_RF69_REG_PACKET_CONFIG_2 0x3D +#define RADIOLIB_RF69_REG_AES_KEY_1 0x3E +#define RADIOLIB_RF69_REG_AES_KEY_2 0x3F +#define RADIOLIB_RF69_REG_AES_KEY_3 0x40 +#define RADIOLIB_RF69_REG_AES_KEY_4 0x41 +#define RADIOLIB_RF69_REG_AES_KEY_5 0x42 +#define RADIOLIB_RF69_REG_AES_KEY_6 0x43 +#define RADIOLIB_RF69_REG_AES_KEY_7 0x44 +#define RADIOLIB_RF69_REG_AES_KEY_8 0x45 +#define RADIOLIB_RF69_REG_AES_KEY_9 0x46 +#define RADIOLIB_RF69_REG_AES_KEY_10 0x47 +#define RADIOLIB_RF69_REG_AES_KEY_11 0x48 +#define RADIOLIB_RF69_REG_AES_KEY_12 0x49 +#define RADIOLIB_RF69_REG_AES_KEY_13 0x4A +#define RADIOLIB_RF69_REG_AES_KEY_14 0x4B +#define RADIOLIB_RF69_REG_AES_KEY_15 0x4C +#define RADIOLIB_RF69_REG_AES_KEY_16 0x4D +#define RADIOLIB_RF69_REG_TEMP_1 0x4E +#define RADIOLIB_RF69_REG_TEMP_2 0x4F +#define RADIOLIB_RF69_REG_TEST_LNA 0x58 +#define RADIOLIB_RF69_REG_TEST_PA1 0x5A +#define RADIOLIB_RF69_REG_TEST_PA2 0x5C +#define RADIOLIB_RF69_REG_TEST_DAGC 0x6F // RF69 modem settings -// RF69_REG_OP_MODE MSB LSB DESCRIPTION -#define RADIOLIB_RF69_SEQUENCER_OFF 0b00000000 // 7 7 disable automatic sequencer -#define RADIOLIB_RF69_SEQUENCER_ON 0b10000000 // 7 7 enable automatic sequencer -#define RADIOLIB_RF69_LISTEN_OFF 0b00000000 // 6 6 disable Listen mode -#define RADIOLIB_RF69_LISTEN_ON 0b01000000 // 6 6 enable Listen mode -#define RADIOLIB_RF69_LISTEN_ABORT 0b00100000 // 5 5 abort Listen mode (has to be set together with RF69_LISTEN_OFF) -#define RADIOLIB_RF69_SLEEP 0b00000000 // 4 2 sleep -#define RADIOLIB_RF69_STANDBY 0b00000100 // 4 2 standby -#define RADIOLIB_RF69_FS 0b00001000 // 4 2 frequency synthesis -#define RADIOLIB_RF69_TX 0b00001100 // 4 2 transmit -#define RADIOLIB_RF69_RX 0b00010000 // 4 2 receive - -// RF69_REG_DATA_MODUL -#define RADIOLIB_RF69_PACKET_MODE 0b00000000 // 6 5 packet mode (default) -#define RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC 0b01000000 // 6 5 continuous mode with bit synchronizer -#define RADIOLIB_RF69_CONTINUOUS_MODE 0b01100000 // 6 5 continuous mode without bit synchronizer -#define RADIOLIB_RF69_FSK 0b00000000 // 4 3 modulation: FSK (default) -#define RADIOLIB_RF69_OOK 0b00001000 // 4 3 OOK -#define RADIOLIB_RF69_NO_SHAPING 0b00000000 // 1 0 modulation shaping: no shaping (default) -#define RADIOLIB_RF69_FSK_GAUSSIAN_1_0 0b00000001 // 1 0 FSK modulation Gaussian filter, BT = 1.0 -#define RADIOLIB_RF69_FSK_GAUSSIAN_0_5 0b00000010 // 1 0 FSK modulation Gaussian filter, BT = 0.5 -#define RADIOLIB_RF69_FSK_GAUSSIAN_0_3 0b00000011 // 1 0 FSK modulation Gaussian filter, BT = 0.3 -#define RADIOLIB_RF69_OOK_FILTER_BR 0b00000001 // 1 0 OOK modulation filter, f_cutoff = BR -#define RADIOLIB_RF69_OOK_FILTER_2BR 0b00000010 // 1 0 OOK modulation filter, f_cutoff = 2*BR - -// RF69_REG_BITRATE_MSB + REG_BITRATE_LSB -#define RADIOLIB_RF69_BITRATE_MSB 0x1A // 7 0 bit rate setting: rate = F(XOSC) / BITRATE -#define RADIOLIB_RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps 0x40 // 7 0 - -// RF69_REG_FDEV_MSB + REG_FDEV_LSB -#define RADIOLIB_RF69_FDEV_MSB 0x00 // 5 0 frequency deviation: f_dev = f_step * FDEV -#define RADIOLIB_RF69_FDEV_LSB 0x52 // 7 0 default value: 5 kHz - -// RF69_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB -#define RADIOLIB_RF69_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 -#define RADIOLIB_RF69_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz -#define RADIOLIB_RF69_FRF_LSB 0x00 // 7 0 default value: 915 MHz - -// RF69_REG_OSC_1 -#define RADIOLIB_RF69_RC_CAL_START 0b10000000 // 7 7 force RC oscillator calibration -#define RADIOLIB_RF69_RC_CAL_RUNNING 0b00000000 // 6 6 RC oscillator calibration is still running -#define RADIOLIB_RF69_RC_CAL_DONE 0b00000000 // 5 5 RC oscillator calibration has finished - -// RF69_REG_AFC_CTRL -#define RADIOLIB_RF69_AFC_LOW_BETA_OFF 0b00000000 // 5 5 standard AFC routine -#define RADIOLIB_RF69_AFC_LOW_BETA_ON 0b00100000 // 5 5 improved AFC routine for signals with modulation index less than 2 - -// RF69_REG_LISTEN_1 -#define RADIOLIB_RF69_LISTEN_RES_IDLE_64_US 0b01000000 // 7 6 resolution of Listen mode idle time: 64 us -#define RADIOLIB_RF69_LISTEN_RES_IDLE_4_1_MS 0b10000000 // 7 6 4.1 ms (default) -#define RADIOLIB_RF69_LISTEN_RES_IDLE_262_MS 0b11000000 // 7 6 262 ms -#define RADIOLIB_RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode rx time: 64 us (default) -#define RADIOLIB_RF69_LISTEN_RES_RX_4_1_MS 0b00100000 // 5 4 4.1 ms -#define RADIOLIB_RF69_LISTEN_RES_RX_262_MS 0b00110000 // 5 4 262 ms -#define RADIOLIB_RF69_LISTEN_ACCEPT_ABOVE_RSSI_THRESH 0b00000000 // 3 3 packet acceptance criteria: RSSI above threshold -#define RADIOLIB_RF69_LISTEN_ACCEPT_MATCH_SYNC_ADDRESS 0b00001000 // 3 3 RSSI above threshold AND sync address matched -#define RADIOLIB_RF69_LISTEN_END_KEEP_RX 0b00000000 // 2 1 action after packet acceptance: stay in Rx mode -#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT 0b00000010 // 2 1 stay in Rx mode until timeout (default) -#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT_RESUME 0b00000100 // 2 1 stay in Rx mode until timeout, Listen mode will resume - -// RF69_REG_LISTEN_2 -#define RADIOLIB_RF69_LISTEN_COEF_IDLE 0xF5 // 7 0 duration of idle phase in Listen mode - -// RF69_REG_LISTEN_3 -#define RADIOLIB_RF69_LISTEN_COEF_RX 0x20 // 7 0 duration of Rx phase in Listen mode - -// RF69_REG_VERSION -#define RADIOLIB_RF69_CHIP_VERSION 0x24 // 7 0 - -// RF69_REG_PA_LEVEL -#define RADIOLIB_RF69_PA0_OFF 0b00000000 // 7 7 PA0 disabled -#define RADIOLIB_RF69_PA0_ON 0b10000000 // 7 7 PA0 enabled (default) -#define RADIOLIB_RF69_PA1_OFF 0b00000000 // 6 6 PA1 disabled (default) -#define RADIOLIB_RF69_PA1_ON 0b01000000 // 6 6 PA1 enabled -#define RADIOLIB_RF69_PA2_OFF 0b00000000 // 5 5 PA2 disabled (default) -#define RADIOLIB_RF69_PA2_ON 0b00100000 // 5 5 PA2 enabled -#define RADIOLIB_RF69_OUTPUT_POWER 0b00011111 // 4 0 output power: P_out = -18 + OUTPUT_POWER - -// RF69_REG_PA_RAMP -#define RADIOLIB_RF69_PA_RAMP_3_4_MS 0b00000000 // 3 0 PA ramp rise/fall time: 3.4 ms -#define RADIOLIB_RF69_PA_RAMP_2_MS 0b00000001 // 3 0 2 ms -#define RADIOLIB_RF69_PA_RAMP_1_MS 0b00000010 // 3 0 1 ms -#define RADIOLIB_RF69_PA_RAMP_500_US 0b00000011 // 3 0 500 us -#define RADIOLIB_RF69_PA_RAMP_250_US 0b00000100 // 3 0 250 us -#define RADIOLIB_RF69_PA_RAMP_125_US 0b00000101 // 3 0 125 us -#define RADIOLIB_RF69_PA_RAMP_100_US 0b00000110 // 3 0 100 us -#define RADIOLIB_RF69_PA_RAMP_62_US 0b00000111 // 3 0 62 us -#define RADIOLIB_RF69_PA_RAMP_50_US 0b00001000 // 3 0 50 us -#define RADIOLIB_RF69_PA_RAMP_40_US 0b00001001 // 3 0 40 us (default) -#define RADIOLIB_RF69_PA_RAMP_31_US 0b00001010 // 3 0 31 us -#define RADIOLIB_RF69_PA_RAMP_25_US 0b00001011 // 3 0 25 us -#define RADIOLIB_RF69_PA_RAMP_20_US 0b00001100 // 3 0 20 us -#define RADIOLIB_RF69_PA_RAMP_15_US 0b00001101 // 3 0 15 us -#define RADIOLIB_RF69_PA_RAMP_12_US 0b00001110 // 3 0 12 us -#define RADIOLIB_RF69_PA_RAMP_10_US 0b00001111 // 3 0 10 us - -// RF69_REG_OCP -#define RADIOLIB_RF69_OCP_OFF 0b00000000 // 4 4 PA overload current protection disabled -#define RADIOLIB_RF69_OCP_ON 0b00010000 // 4 4 PA overload current protection enabled -#define RADIOLIB_RF69_OCP_TRIM 0b00001010 // 3 0 OCP current: I_max(OCP_TRIM = 0b1010) = 95 mA - -// RF69_REG_LNA -#define RADIOLIB_RF69_LNA_Z_IN_50_OHM 0b00000000 // 7 7 LNA input impedance: 50 ohm -#define RADIOLIB_RF69_LNA_Z_IN_200_OHM 0b10000000 // 7 7 200 ohm -#define RADIOLIB_RF69_LNA_CURRENT_GAIN 0b00001000 // 5 3 manually set LNA current gain -#define RADIOLIB_RF69_LNA_GAIN_AUTO 0b00000000 // 2 0 LNA gain setting: set automatically by AGC -#define RADIOLIB_RF69_LNA_GAIN_MAX 0b00000001 // 2 0 max gain -#define RADIOLIB_RF69_LNA_GAIN_MAX_6_DB 0b00000010 // 2 0 max gain - 6 dB -#define RADIOLIB_RF69_LNA_GAIN_MAX_12_DB 0b00000011 // 2 0 max gain - 12 dB -#define RADIOLIB_RF69_LNA_GAIN_MAX_24_DB 0b00000100 // 2 0 max gain - 24 dB -#define RADIOLIB_RF69_LNA_GAIN_MAX_36_DB 0b00000101 // 2 0 max gain - 36 dB -#define RADIOLIB_RF69_LNA_GAIN_MAX_48_DB 0b00000110 // 2 0 max gain - 48 dB - -// RF69_REG_RX_BW -#define RADIOLIB_RF69_DCC_FREQ 0b01000000 // 7 5 DC offset canceller cutoff frequency (4% Rx BW by default) -#define RADIOLIB_RF69_RX_BW_MANT_16 0b00000000 // 4 3 Channel filter bandwidth FSK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 2)) -#define RADIOLIB_RF69_RX_BW_MANT_20 0b00001000 // 4 3 OOK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 3)) -#define RADIOLIB_RF69_RX_BW_MANT_24 0b00010000 // 4 3 -#define RADIOLIB_RF69_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp value = 5 - -// RF69_REG_AFC_BW -#define RADIOLIB_RF69_DCC_FREQ_AFC 0b10000000 // 7 5 default DccFreq parameter for AFC -#define RADIOLIB_RF69_DCC_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter for AFC -#define RADIOLIB_RF69_DCC_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter for AFC - -// RF69_REG_OOK_PEAK -#define RADIOLIB_RF69_OOK_THRESH_FIXED 0b00000000 // 7 6 OOK threshold type: fixed -#define RADIOLIB_RF69_OOK_THRESH_PEAK 0b01000000 // 7 6 peak (default) -#define RADIOLIB_RF69_OOK_THRESH_AVERAGE 0b10000000 // 7 6 average -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 5 3 OOK demodulator step size: 0.5 dB (default) -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_0_DB 0b00001000 // 5 3 1.0 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_5_DB 0b00010000 // 5 3 1.5 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_2_0_DB 0b00011000 // 5 3 2.0 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_3_0_DB 0b00100000 // 5 3 3.0 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_4_0_DB 0b00101000 // 5 3 4.0 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_5_0_DB 0b00110000 // 5 3 5.0 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_6_0_DB 0b00111000 // 5 3 6.0 dB -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 2 0 OOK demodulator step period: once per chip (default) -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00000001 // 2 0 once every 2 chips -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b00000010 // 2 0 once every 4 chips -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b00000011 // 2 0 once every 8 chips -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b00000100 // 2 0 2 times per chip -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b00000101 // 2 0 4 times per chip -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b00000110 // 2 0 8 times per chip -#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b00000111 // 2 0 16 times per chip - -// RF69_REG_OOK_AVG -#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 7 6 OOK average filter coefficient: chip rate / 32*pi -#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_8_PI 0b01000000 // 7 6 chip rate / 8*pi -#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_4_PI 0b10000000 // 7 6 chip rate / 4*pi (default) -#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_2_PI 0b11000000 // 7 6 chip rate / 2*pi - -// RF69_REG_OOK_FIX -#define RADIOLIB_RF69_OOK_FIXED_THRESH 0b00000110 // 7 0 default OOK fixed threshold (6 dB) - -// RF69_REG_AFC_FEI -#define RADIOLIB_RF69_FEI_RUNNING 0b00000000 // 6 6 FEI status: on-going -#define RADIOLIB_RF69_FEI_DONE 0b01000000 // 6 6 done -#define RADIOLIB_RF69_FEI_START 0b00100000 // 5 5 force new FEI measurement -#define RADIOLIB_RF69_AFC_RUNNING 0b00000000 // 4 4 AFC status: on-going -#define RADIOLIB_RF69_AFC_DONE 0b00010000 // 4 4 done -#define RADIOLIB_RF69_AFC_AUTOCLEAR_OFF 0b00000000 // 3 3 AFC register autoclear disabled -#define RADIOLIB_RF69_AFC_AUTOCLEAR_ON 0b00001000 // 3 3 AFC register autoclear enabled -#define RADIOLIB_RF69_AFC_AUTO_OFF 0b00000000 // 2 2 perform AFC only manually -#define RADIOLIB_RF69_AFC_AUTO_ON 0b00000100 // 2 2 perform AFC each time Rx mode is started -#define RADIOLIB_RF69_AFC_CLEAR 0b00000010 // 1 1 clear AFC register -#define RADIOLIB_RF69_AFC_START 0b00000001 // 0 0 start AFC - -// RF69_REG_RSSI_CONFIG -#define RADIOLIB_RF69_RSSI_RUNNING 0b00000000 // 1 1 RSSI status: on-going -#define RADIOLIB_RF69_RSSI_DONE 0b00000010 // 1 1 done -#define RADIOLIB_RF69_RSSI_START 0b00000001 // 0 0 start RSSI measurement - -// RF69_REG_DIO_MAPPING_1 -#define RADIOLIB_RF69_DIO0_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_RF69_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO0_CONT_RSSI 0b10000000 // 7 6 -#define RADIOLIB_RF69_DIO0_CONT_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_CRC_OK 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_RSSI 0b11000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO0_PACK_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 -#define RADIOLIB_RF69_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define RADIOLIB_RF69_DIO1_CONT_RX_READY 0b00010000 // 5 4 -#define RADIOLIB_RF69_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 -#define RADIOLIB_RF69_DIO1_CONT_TX_READY 0b00010000 // 5 4 -#define RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 -#define RADIOLIB_RF69_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 -#define RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 -#define RADIOLIB_RF69_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 -#define RADIOLIB_RF69_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 -#define RADIOLIB_RF69_DIO2_CONT_DATA 0b00000000 // 3 2 -#define RADIOLIB_RF69_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 -#define RADIOLIB_RF69_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 -#define RADIOLIB_RF69_DIO2_PACK_DATA 0b00000100 // 3 2 -#define RADIOLIB_RF69_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 -#define RADIOLIB_RF69_DIO3_CONT_RSSI 0b00000000 // 0 1 -#define RADIOLIB_RF69_DIO3_CONT_RX_READY 0b00000001 // 0 1 -#define RADIOLIB_RF69_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 -#define RADIOLIB_RF69_DIO3_CONT_TX_READY 0b00000001 // 0 1 -#define RADIOLIB_RF69_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 -#define RADIOLIB_RF69_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 -#define RADIOLIB_RF69_DIO3_PACK_RSSI 0b00000001 // 0 1 -#define RADIOLIB_RF69_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 -#define RADIOLIB_RF69_DIO3_PACK_TX_READY 0b00000001 // 0 1 - -// RF69_REG_DIO_MAPPING_2 -#define RADIOLIB_RF69_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 -#define RADIOLIB_RF69_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO4_CONT_RX_READY 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 -#define RADIOLIB_RF69_DIO4_CONT_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 -#define RADIOLIB_RF69_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO4_PACK_RSSI 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO4_PACK_RX_READY 0b10000000 // 7 6 -#define RADIOLIB_RF69_DIO4_PACK_MODE_READY 0b00000000 // 7 6 -#define RADIOLIB_RF69_DIO4_PACK_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_RF69_DIO5_CONT_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_RF69_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_RF69_DIO5_CONT_RSSI 0b00010000 // 5 4 -#define RADIOLIB_RF69_DIO5_PACK_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_RF69_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_RF69_DIO5_PACK_DATA 0b00010000 // 5 4 -#define RADIOLIB_RF69_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) -#define RADIOLIB_RF69_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 -#define RADIOLIB_RF69_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 -#define RADIOLIB_RF69_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 -#define RADIOLIB_RF69_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 -#define RADIOLIB_RF69_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 31 -#define RADIOLIB_RF69_CLK_OUT_RC 0b00000110 // 2 0 RC -#define RADIOLIB_RF69_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) - -// RF69_REG_IRQ_FLAGS_1 -#define RADIOLIB_RF69_IRQ_MODE_READY 0b10000000 // 7 7 requested mode was set -#define RADIOLIB_RF69_IRQ_RX_READY 0b01000000 // 6 6 Rx mode ready -#define RADIOLIB_RF69_IRQ_TX_READY 0b00100000 // 5 5 Tx mode ready -#define RADIOLIB_RF69_IRQ_PLL_LOCK 0b00010000 // 4 4 PLL is locked -#define RADIOLIB_RF69_IRQ_RSSI 0b00001000 // 3 3 RSSI value exceeded RssiThreshold -#define RADIOLIB_RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occurred -#define RADIOLIB_RF69_IRQ_AUTO_MODE 0b00000010 // 1 1 entered intermediate mode -#define RADIOLIB_RF69_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address detected - -// RF69_REG_IRQ_FLAGS_2 -#define RADIOLIB_RF69_IRQ_FIFO_FULL 0b10000000 // 7 7 FIFO is full -#define RADIOLIB_RF69_IRQ_FIFO_NOT_EMPTY 0b01000000 // 6 6 FIFO contains at least 1 byte -#define RADIOLIB_RF69_IRQ_FIFO_LEVEL 0b00100000 // 5 5 FIFO contains more than FifoThreshold bytes -#define RADIOLIB_RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred -#define RADIOLIB_RF69_IRQ_PACKET_SENT 0b00001000 // 3 3 packet was sent -#define RADIOLIB_RF69_IRQ_PAYLOAD_READY 0b00000100 // 2 2 last payload byte received and CRC check passed -#define RADIOLIB_RF69_IRQ_CRC_OK 0b00000010 // 1 1 CRC check passed - -// RF69_REG_RSSI_THRESH -#define RADIOLIB_RF69_RSSI_THRESHOLD 0xE4 // 7 0 RSSI threshold level (2 dB by default) - -// RF69_REG_RX_TIMEOUT_1 -#define RADIOLIB_RF69_TIMEOUT_RX_START_OFF 0x00 // 7 0 RSSI interrupt timeout disabled (default) -#define RADIOLIB_RF69_TIMEOUT_RX_START 0xFF // 7 0 timeout will occur if RSSI interrupt is not received - -// RF69_REG_RX_TIMEOUT_2 -#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH_OFF 0x00 // 7 0 PayloadReady interrupt timeout disabled (default) -#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH 0xFF // 7 0 timeout will occur if PayloadReady interrupt is not received - -// RF69_REG_PREAMBLE_MSB + REG_PREAMBLE_MSB -#define RADIOLIB_RF69_PREAMBLE_MSB 0x00 // 7 0 2-byte preamble size value -#define RADIOLIB_RF69_PREAMBLE_LSB 0x03 // 7 0 - -// RF69_REG_SYNC_CONFIG -#define RADIOLIB_RF69_SYNC_OFF 0b00000000 // 7 7 sync word detection off -#define RADIOLIB_RF69_SYNC_ON 0b10000000 // 7 7 sync word detection on (default) -#define RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC 0b00000000 // 6 6 FIFO fill condition: on SyncAddress interrupt (default) -#define RADIOLIB_RF69_FIFO_FILL_CONDITION 0b01000000 // 6 6 as long as the bit is set -#define RADIOLIB_RF69_SYNC_SIZE 0b00001000 // 5 3 size of sync word: SyncSize + 1 bytes -#define RADIOLIB_RF69_SYNC_TOL 0b00000000 // 2 0 number of tolerated errors in sync word - -// RF69_REG_SYNC_VALUE_1 - SYNC_VALUE_8 -#define RADIOLIB_RF69_SYNC_BYTE_1 0x01 // 7 0 sync word: 1st byte (MSB) -#define RADIOLIB_RF69_SYNC_BYTE_2 0x01 // 7 0 2nd byte -#define RADIOLIB_RF69_SYNC_BYTE_3 0x01 // 7 0 3rd byte -#define RADIOLIB_RF69_SYNC_BYTE_4 0x01 // 7 0 4th byte -#define RADIOLIB_RF69_SYNC_BYTE_5 0x01 // 7 0 5th byte -#define RADIOLIB_RF69_SYNC_BYTE_6 0x01 // 7 0 6th byte -#define RADIOLIB_RF69_SYNC_BYTE_7 0x01 // 7 0 7th byte -#define RADIOLIB_RF69_SYNC_BYTE_8 0x01 // 7 0 8th byte (LSB) - -// RF69_REG_PACKET_CONFIG_1 -#define RADIOLIB_RF69_PACKET_FORMAT_FIXED 0b00000000 // 7 7 fixed packet length (default) -#define RADIOLIB_RF69_PACKET_FORMAT_VARIABLE 0b10000000 // 7 7 variable packet length -#define RADIOLIB_RF69_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: none (default) -#define RADIOLIB_RF69_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester -#define RADIOLIB_RF69_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening -#define RADIOLIB_RF69_CRC_OFF 0b00000000 // 4 4 CRC disabled -#define RADIOLIB_RF69_CRC_ON 0b00010000 // 4 4 CRC enabled (default) -#define RADIOLIB_RF69_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 discard packet when CRC check fails (default) -#define RADIOLIB_RF69_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep packet when CRC check fails -#define RADIOLIB_RF69_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) -#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node -#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast - -// RF69_REG_PAYLOAD_LENGTH -#define RADIOLIB_RF69_PAYLOAD_LENGTH 0xFF // 7 0 payload length - -// RF69_REG_AUTO_MODES -#define RADIOLIB_RF69_ENTER_COND_NONE 0b00000000 // 7 5 condition for entering intermediate mode: none, AutoModes disabled (default) -#define RADIOLIB_RF69_ENTER_COND_FIFO_NOT_EMPTY 0b00100000 // 7 5 FifoNotEmpty rising edge -#define RADIOLIB_RF69_ENTER_COND_FIFO_LEVEL 0b01000000 // 7 5 FifoLevel rising edge -#define RADIOLIB_RF69_ENTER_COND_CRC_OK 0b01100000 // 7 5 CrcOk rising edge -#define RADIOLIB_RF69_ENTER_COND_PAYLOAD_READY 0b10000000 // 7 5 PayloadReady rising edge -#define RADIOLIB_RF69_ENTER_COND_SYNC_ADDRESS 0b10100000 // 7 5 SyncAddress rising edge -#define RADIOLIB_RF69_ENTER_COND_PACKET_SENT 0b11000000 // 7 5 PacketSent rising edge -#define RADIOLIB_RF69_ENTER_COND_FIFO_EMPTY 0b11100000 // 7 5 FifoNotEmpty falling edge -#define RADIOLIB_RF69_EXIT_COND_NONE 0b00000000 // 4 2 condition for exiting intermediate mode: none, AutoModes disabled (default) -#define RADIOLIB_RF69_EXIT_COND_FIFO_EMPTY 0b00100000 // 4 2 FifoNotEmpty falling edge -#define RADIOLIB_RF69_EXIT_COND_FIFO_LEVEL 0b01000000 // 4 2 FifoLevel rising edge -#define RADIOLIB_RF69_EXIT_COND_CRC_OK 0b01100000 // 4 2 CrcOk rising edge -#define RADIOLIB_RF69_EXIT_COND_PAYLOAD_READY 0b10000000 // 4 2 PayloadReady rising edge -#define RADIOLIB_RF69_EXIT_COND_SYNC_ADDRESS 0b10100000 // 4 2 SyncAddress rising edge -#define RADIOLIB_RF69_EXIT_COND_PACKET_SENT 0b11000000 // 4 2 PacketSent rising edge -#define RADIOLIB_RF69_EXIT_COND_TIMEOUT 0b11100000 // 4 2 timeout rising edge -#define RADIOLIB_RF69_INTER_MODE_SLEEP 0b00000000 // 1 0 intermediate mode: sleep (default) -#define RADIOLIB_RF69_INTER_MODE_STANDBY 0b00000001 // 1 0 standby -#define RADIOLIB_RF69_INTER_MODE_RX 0b00000010 // 1 0 Rx -#define RADIOLIB_RF69_INTER_MODE_TX 0b00000011 // 1 0 Tx - -// RF69_REG_FIFO_THRESH -#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_LEVEL 0b00000000 // 7 7 packet transmission start condition: FifoLevel -#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY 0b10000000 // 7 7 FifoNotEmpty (default) -#define RADIOLIB_RF69_FIFO_THRESH 0x1F // 6 0 default threshold to trigger FifoLevel interrupt - -// RF69_REG_PACKET_CONFIG_2 -#define RADIOLIB_RF69_INTER_PACKET_RX_DELAY 0b00000000 // 7 4 delay between FIFO empty and start of new RSSI phase -#define RADIOLIB_RF69_RESTART_RX 0b00000100 // 2 2 force receiver into wait mode -#define RADIOLIB_RF69_AUTO_RX_RESTART_OFF 0b00000000 // 1 1 auto Rx restart disabled -#define RADIOLIB_RF69_AUTO_RX_RESTART_ON 0b00000010 // 1 1 auto Rx restart enabled (default) -#define RADIOLIB_RF69_AES_OFF 0b00000000 // 0 0 AES encryption disabled (default) -#define RADIOLIB_RF69_AES_ON 0b00000001 // 0 0 AES encryption enabled, payload size limited to 66 bytes - -// RF69_REG_TEST_LNA -#define RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL 0x1B // 7 0 -#define RADIOLIB_RF69_TEST_LNA_BOOST_HIGH 0x2D // 7 0 - -// RF69_REG_TEMP_1 -#define RADIOLIB_RF69_TEMP_MEAS_START 0b00001000 // 3 3 trigger temperature measurement -#define RADIOLIB_RF69_TEMP_MEAS_RUNNING 0b00000100 // 2 2 temperature measurement status: on-going -#define RADIOLIB_RF69_TEMP_MEAS_DONE 0b00000000 // 2 2 done - -// RF69_REG_TEST_DAGC -#define RADIOLIB_RF69_CONTINUOUS_DAGC_NORMAL 0x00 // 7 0 fading margin improvement: normal mode -#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_ON 0x20 // 7 0 improved mode for AfcLowBetaOn -#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF 0x30 // 7 0 improved mode for AfcLowBetaOff (default) - -// RF69_REG_TEST_PA1 -#define RADIOLIB_RF69_PA1_NORMAL 0x55 // 7 0 PA_BOOST: none -#define RADIOLIB_RF69_PA1_20_DBM 0x5D // 7 0 +20 dBm - -// RF69_REG_TEST_PA2 -#define RADIOLIB_RF69_PA2_NORMAL 0x70 // 7 0 PA_BOOST: none -#define RADIOLIB_RF69_PA2_20_DBM 0x7C // 7 0 +20 dBm - -// Defaults -#define RADIOLIB_RF69_DEFAULT_FREQ 434.0 -#define RADIOLIB_RF69_DEFAULT_BR 4.8 -#define RADIOLIB_RF69_DEFAULT_FREQDEV 5.0 -#define RADIOLIB_RF69_DEFAULT_RXBW 125.0 -#define RADIOLIB_RF69_DEFAULT_POWER 10 -#define RADIOLIB_RF69_DEFAULT_PREAMBLELEN 16 -#define RADIOLIB_RF69_DEFAULT_SW {0x12, 0xAD} -#define RADIOLIB_RF69_DEFAULT_SW_LEN 2 +// RADIOLIB_RF69_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_RF69_SEQUENCER_OFF 0b00000000 // 7 7 disable automatic sequencer +#define RADIOLIB_RF69_SEQUENCER_ON 0b10000000 // 7 7 enable automatic sequencer +#define RADIOLIB_RF69_LISTEN_OFF 0b00000000 // 6 6 disable Listen mode +#define RADIOLIB_RF69_LISTEN_ON 0b01000000 // 6 6 enable Listen mode +#define RADIOLIB_RF69_LISTEN_ABORT 0b00100000 // 5 5 abort Listen mode (has to be set together with RF69_LISTEN_OFF) +#define RADIOLIB_RF69_SLEEP 0b00000000 // 4 2 sleep +#define RADIOLIB_RF69_STANDBY 0b00000100 // 4 2 standby +#define RADIOLIB_RF69_FS 0b00001000 // 4 2 frequency synthesis +#define RADIOLIB_RF69_TX 0b00001100 // 4 2 transmit +#define RADIOLIB_RF69_RX 0b00010000 // 4 2 receive + +// RADIOLIB_RF69_REG_DATA_MODUL +#define RADIOLIB_RF69_PACKET_MODE 0b00000000 // 6 5 packet mode (default) +#define RADIOLIB_RF69_CONTINUOUS_MODE_WITH_SYNC 0b01000000 // 6 5 continuous mode with bit synchronizer +#define RADIOLIB_RF69_CONTINUOUS_MODE 0b01100000 // 6 5 continuous mode without bit synchronizer +#define RADIOLIB_RF69_FSK 0b00000000 // 4 3 modulation: FSK (default) +#define RADIOLIB_RF69_OOK 0b00001000 // 4 3 OOK +#define RADIOLIB_RF69_NO_SHAPING 0b00000000 // 1 0 modulation shaping: no shaping (default) +#define RADIOLIB_RF69_FSK_GAUSSIAN_1_0 0b00000001 // 1 0 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_RF69_FSK_GAUSSIAN_0_5 0b00000010 // 1 0 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_RF69_FSK_GAUSSIAN_0_3 0b00000011 // 1 0 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_RF69_OOK_FILTER_BR 0b00000001 // 1 0 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_RF69_OOK_FILTER_2BR 0b00000010 // 1 0 OOK modulation filter, f_cutoff = 2*BR + +// RADIOLIB_RF69_REG_BITRATE_MSB + REG_BITRATE_LSB +#define RADIOLIB_RF69_BITRATE_MSB 0x1A // 7 0 bit rate setting: rate = F(XOSC) / BITRATE +#define RADIOLIB_RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps 0x40 // 7 0 + +// RADIOLIB_RF69_REG_FDEV_MSB + REG_FDEV_LSB +#define RADIOLIB_RF69_FDEV_MSB 0x00 // 5 0 frequency deviation: f_dev = f_step * FDEV +#define RADIOLIB_RF69_FDEV_LSB 0x52 // 7 0 default value: 5 kHz + +// RADIOLIB_RF69_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +#define RADIOLIB_RF69_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_RF69_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_RF69_FRF_LSB 0x00 // 7 0 default value: 915 MHz + +// RADIOLIB_RF69_REG_OSC_1 +#define RADIOLIB_RF69_RC_CAL_START 0b10000000 // 7 7 force RC oscillator calibration +#define RADIOLIB_RF69_RC_CAL_RUNNING 0b00000000 // 6 6 RC oscillator calibration is still running +#define RADIOLIB_RF69_RC_CAL_DONE 0b00000000 // 5 5 RC oscillator calibration has finished + +// RADIOLIB_RF69_REG_AFC_CTRL +#define RADIOLIB_RF69_AFC_LOW_BETA_OFF 0b00000000 // 5 5 standard AFC routine +#define RADIOLIB_RF69_AFC_LOW_BETA_ON 0b00100000 // 5 5 improved AFC routine for signals with modulation index less than 2 + +// RADIOLIB_RF69_REG_LISTEN_1 +#define RADIOLIB_RF69_LISTEN_RES_IDLE_64_US 0b01000000 // 7 6 resolution of Listen mode idle time: 64 us +#define RADIOLIB_RF69_LISTEN_RES_IDLE_4_1_MS 0b10000000 // 7 6 4.1 ms (default) +#define RADIOLIB_RF69_LISTEN_RES_IDLE_262_MS 0b11000000 // 7 6 262 ms +#define RADIOLIB_RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode rx time: 64 us (default) +#define RADIOLIB_RF69_LISTEN_RES_RX_4_1_MS 0b00100000 // 5 4 4.1 ms +#define RADIOLIB_RF69_LISTEN_RES_RX_262_MS 0b00110000 // 5 4 262 ms +#define RADIOLIB_RF69_LISTEN_ACCEPT_ABOVE_RSSI_THRESH 0b00000000 // 3 3 packet acceptance criteria: RSSI above threshold +#define RADIOLIB_RF69_LISTEN_ACCEPT_MATCH_SYNC_ADDRESS 0b00001000 // 3 3 RSSI above threshold AND sync address matched +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX 0b00000000 // 2 1 action after packet acceptance: stay in Rx mode +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT 0b00000010 // 2 1 stay in Rx mode until timeout (default) +#define RADIOLIB_RF69_LISTEN_END_KEEP_RX_TIMEOUT_RESUME 0b00000100 // 2 1 stay in Rx mode until timeout, Listen mode will resume + +// RADIOLIB_RF69_REG_LISTEN_2 +#define RADIOLIB_RF69_LISTEN_COEF_IDLE 0xF5 // 7 0 duration of idle phase in Listen mode + +// RADIOLIB_RF69_REG_LISTEN_3 +#define RADIOLIB_RF69_LISTEN_COEF_RX 0x20 // 7 0 duration of Rx phase in Listen mode + +// RADIOLIB_RF69_REG_VERSION +#define RADIOLIB_RF69_CHIP_VERSION 0x24 // 7 0 + +// RADIOLIB_RF69_REG_PA_LEVEL +#define RADIOLIB_RF69_PA0_OFF 0b00000000 // 7 7 PA0 disabled +#define RADIOLIB_RF69_PA0_ON 0b10000000 // 7 7 PA0 enabled (default) +#define RADIOLIB_RF69_PA1_OFF 0b00000000 // 6 6 PA1 disabled (default) +#define RADIOLIB_RF69_PA1_ON 0b01000000 // 6 6 PA1 enabled +#define RADIOLIB_RF69_PA2_OFF 0b00000000 // 5 5 PA2 disabled (default) +#define RADIOLIB_RF69_PA2_ON 0b00100000 // 5 5 PA2 enabled +#define RADIOLIB_RF69_OUTPUT_POWER 0b00011111 // 4 0 output power: P_out = -18 + OUTPUT_POWER + +// RADIOLIB_RF69_REG_PA_RAMP +#define RADIOLIB_RF69_PA_RAMP_3_4_MS 0b00000000 // 3 0 PA ramp rise/fall time: 3.4 ms +#define RADIOLIB_RF69_PA_RAMP_2_MS 0b00000001 // 3 0 2 ms +#define RADIOLIB_RF69_PA_RAMP_1_MS 0b00000010 // 3 0 1 ms +#define RADIOLIB_RF69_PA_RAMP_500_US 0b00000011 // 3 0 500 us +#define RADIOLIB_RF69_PA_RAMP_250_US 0b00000100 // 3 0 250 us +#define RADIOLIB_RF69_PA_RAMP_125_US 0b00000101 // 3 0 125 us +#define RADIOLIB_RF69_PA_RAMP_100_US 0b00000110 // 3 0 100 us +#define RADIOLIB_RF69_PA_RAMP_62_US 0b00000111 // 3 0 62 us +#define RADIOLIB_RF69_PA_RAMP_50_US 0b00001000 // 3 0 50 us +#define RADIOLIB_RF69_PA_RAMP_40_US 0b00001001 // 3 0 40 us (default) +#define RADIOLIB_RF69_PA_RAMP_31_US 0b00001010 // 3 0 31 us +#define RADIOLIB_RF69_PA_RAMP_25_US 0b00001011 // 3 0 25 us +#define RADIOLIB_RF69_PA_RAMP_20_US 0b00001100 // 3 0 20 us +#define RADIOLIB_RF69_PA_RAMP_15_US 0b00001101 // 3 0 15 us +#define RADIOLIB_RF69_PA_RAMP_12_US 0b00001110 // 3 0 12 us +#define RADIOLIB_RF69_PA_RAMP_10_US 0b00001111 // 3 0 10 us + +// RADIOLIB_RF69_REG_OCP +#define RADIOLIB_RF69_OCP_OFF 0b00000000 // 4 4 PA overload current protection disabled +#define RADIOLIB_RF69_OCP_ON 0b00010000 // 4 4 PA overload current protection enabled +#define RADIOLIB_RF69_OCP_TRIM 0b00001010 // 3 0 OCP current: I_max(OCP_TRIM = 0b1010) = 95 mA + +// RADIOLIB_RF69_REG_LNA +#define RADIOLIB_RF69_LNA_Z_IN_50_OHM 0b00000000 // 7 7 LNA input impedance: 50 ohm +#define RADIOLIB_RF69_LNA_Z_IN_200_OHM 0b10000000 // 7 7 200 ohm +#define RADIOLIB_RF69_LNA_CURRENT_GAIN 0b00001000 // 5 3 manually set LNA current gain +#define RADIOLIB_RF69_LNA_GAIN_AUTO 0b00000000 // 2 0 LNA gain setting: set automatically by AGC +#define RADIOLIB_RF69_LNA_GAIN_MAX 0b00000001 // 2 0 max gain +#define RADIOLIB_RF69_LNA_GAIN_MAX_6_DB 0b00000010 // 2 0 max gain - 6 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_12_DB 0b00000011 // 2 0 max gain - 12 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_24_DB 0b00000100 // 2 0 max gain - 24 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_36_DB 0b00000101 // 2 0 max gain - 36 dB +#define RADIOLIB_RF69_LNA_GAIN_MAX_48_DB 0b00000110 // 2 0 max gain - 48 dB + +// RADIOLIB_RF69_REG_RX_BW +#define RADIOLIB_RF69_DCC_FREQ 0b01000000 // 7 5 DC offset canceller cutoff frequency (4% Rx BW by default) +#define RADIOLIB_RF69_RX_BW_MANT_16 0b00000000 // 4 3 Channel filter bandwidth FSK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 2)) +#define RADIOLIB_RF69_RX_BW_MANT_20 0b00001000 // 4 3 OOK: RxBw = F(XOSC)/(RxBwMant * 2^(RxBwExp + 3)) +#define RADIOLIB_RF69_RX_BW_MANT_24 0b00010000 // 4 3 +#define RADIOLIB_RF69_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp value = 5 + +// RADIOLIB_RF69_REG_AFC_BW +#define RADIOLIB_RF69_DCC_FREQ_AFC 0b10000000 // 7 5 default DccFreq parameter for AFC +#define RADIOLIB_RF69_DCC_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter for AFC +#define RADIOLIB_RF69_DCC_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter for AFC + +// RADIOLIB_RF69_REG_OOK_PEAK +#define RADIOLIB_RF69_OOK_THRESH_FIXED 0b00000000 // 7 6 OOK threshold type: fixed +#define RADIOLIB_RF69_OOK_THRESH_PEAK 0b01000000 // 7 6 peak (default) +#define RADIOLIB_RF69_OOK_THRESH_AVERAGE 0b10000000 // 7 6 average +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 5 3 OOK demodulator step size: 0.5 dB (default) +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_0_DB 0b00001000 // 5 3 1.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_1_5_DB 0b00010000 // 5 3 1.5 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_2_0_DB 0b00011000 // 5 3 2.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_3_0_DB 0b00100000 // 5 3 3.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_4_0_DB 0b00101000 // 5 3 4.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_5_0_DB 0b00110000 // 5 3 5.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_STEP_6_0_DB 0b00111000 // 5 3 6.0 dB +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 2 0 OOK demodulator step period: once per chip (default) +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00000001 // 2 0 once every 2 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b00000010 // 2 0 once every 4 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b00000011 // 2 0 once every 8 chips +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b00000100 // 2 0 2 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b00000101 // 2 0 4 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b00000110 // 2 0 8 times per chip +#define RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b00000111 // 2 0 16 times per chip + +// RADIOLIB_RF69_REG_OOK_AVG +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 7 6 OOK average filter coefficient: chip rate / 32*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_8_PI 0b01000000 // 7 6 chip rate / 8*pi +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_4_PI 0b10000000 // 7 6 chip rate / 4*pi (default) +#define RADIOLIB_RF69_OOK_AVG_THRESH_FILT_2_PI 0b11000000 // 7 6 chip rate / 2*pi + +// RADIOLIB_RF69_REG_OOK_FIX +#define RADIOLIB_RF69_OOK_FIXED_THRESH 0b00000110 // 7 0 default OOK fixed threshold (6 dB) + +// RADIOLIB_RF69_REG_AFC_FEI +#define RADIOLIB_RF69_FEI_RUNNING 0b00000000 // 6 6 FEI status: on-going +#define RADIOLIB_RF69_FEI_DONE 0b01000000 // 6 6 done +#define RADIOLIB_RF69_FEI_START 0b00100000 // 5 5 force new FEI measurement +#define RADIOLIB_RF69_AFC_RUNNING 0b00000000 // 4 4 AFC status: on-going +#define RADIOLIB_RF69_AFC_DONE 0b00010000 // 4 4 done +#define RADIOLIB_RF69_AFC_AUTOCLEAR_OFF 0b00000000 // 3 3 AFC register autoclear disabled +#define RADIOLIB_RF69_AFC_AUTOCLEAR_ON 0b00001000 // 3 3 AFC register autoclear enabled +#define RADIOLIB_RF69_AFC_AUTO_OFF 0b00000000 // 2 2 perform AFC only manually +#define RADIOLIB_RF69_AFC_AUTO_ON 0b00000100 // 2 2 perform AFC each time Rx mode is started +#define RADIOLIB_RF69_AFC_CLEAR 0b00000010 // 1 1 clear AFC register +#define RADIOLIB_RF69_AFC_START 0b00000001 // 0 0 start AFC + +// RADIOLIB_RF69_REG_RSSI_CONFIG +#define RADIOLIB_RF69_RSSI_RUNNING 0b00000000 // 1 1 RSSI status: on-going +#define RADIOLIB_RF69_RSSI_DONE 0b00000010 // 1 1 done +#define RADIOLIB_RF69_RSSI_START 0b00000001 // 0 0 start RSSI measurement + +// RADIOLIB_RF69_REG_DIO_MAPPING_1 +#define RADIOLIB_RF69_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_RSSI 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO0_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_CRC_OK 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_RSSI 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO0_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_RX_READY 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_CONT_TX_READY 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 +#define RADIOLIB_RF69_DIO2_PACK_DATA 0b00000100 // 3 2 +#define RADIOLIB_RF69_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_RSSI 0b00000000 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_RX_READY 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 +#define RADIOLIB_RF69_DIO3_CONT_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_RSSI 0b00000001 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 +#define RADIOLIB_RF69_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// RADIOLIB_RF69_REG_DIO_MAPPING_2 +#define RADIOLIB_RF69_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_RX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO4_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_RSSI 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_MODE_READY 0b00000000 // 7 6 +#define RADIOLIB_RF69_DIO4_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_RF69_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO5_CONT_RSSI 0b00010000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_RF69_DIO5_PACK_DATA 0b00010000 // 5 4 +#define RADIOLIB_RF69_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define RADIOLIB_RF69_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define RADIOLIB_RF69_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 31 +#define RADIOLIB_RF69_CLK_OUT_RC 0b00000110 // 2 0 RC +#define RADIOLIB_RF69_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) + +// RADIOLIB_RF69_REG_IRQ_FLAGS_1 +#define RADIOLIB_RF69_IRQ_MODE_READY 0b10000000 // 7 7 requested mode was set +#define RADIOLIB_RF69_IRQ_RX_READY 0b01000000 // 6 6 Rx mode ready +#define RADIOLIB_RF69_IRQ_TX_READY 0b00100000 // 5 5 Tx mode ready +#define RADIOLIB_RF69_IRQ_PLL_LOCK 0b00010000 // 4 4 PLL is locked +#define RADIOLIB_RF69_IRQ_RSSI 0b00001000 // 3 3 RSSI value exceeded RssiThreshold +#define RADIOLIB_RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occurred +#define RADIOLIB_RF69_IRQ_AUTO_MODE 0b00000010 // 1 1 entered intermediate mode +#define RADIOLIB_RF69_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address detected + +// RADIOLIB_RF69_REG_IRQ_FLAGS_2 +#define RADIOLIB_RF69_IRQ_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define RADIOLIB_RF69_IRQ_FIFO_NOT_EMPTY 0b01000000 // 6 6 FIFO contains at least 1 byte +#define RADIOLIB_RF69_IRQ_FIFO_LEVEL 0b00100000 // 5 5 FIFO contains more than FifoThreshold bytes +#define RADIOLIB_RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred +#define RADIOLIB_RF69_IRQ_PACKET_SENT 0b00001000 // 3 3 packet was sent +#define RADIOLIB_RF69_IRQ_PAYLOAD_READY 0b00000100 // 2 2 last payload byte received and CRC check passed +#define RADIOLIB_RF69_IRQ_CRC_OK 0b00000010 // 1 1 CRC check passed + +// RADIOLIB_RF69_REG_RSSI_THRESH +#define RADIOLIB_RF69_RSSI_THRESHOLD 0xE4 // 7 0 RSSI threshold level (2 dB by default) + +// RADIOLIB_RF69_REG_RX_TIMEOUT_1 +#define RADIOLIB_RF69_TIMEOUT_RX_START_OFF 0x00 // 7 0 RSSI interrupt timeout disabled (default) +#define RADIOLIB_RF69_TIMEOUT_RX_START 0xFF // 7 0 timeout will occur if RSSI interrupt is not received + +// RADIOLIB_RF69_REG_RX_TIMEOUT_2 +#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH_OFF 0x00 // 7 0 PayloadReady interrupt timeout disabled (default) +#define RADIOLIB_RF69_TIMEOUT_RSSI_THRESH 0xFF // 7 0 timeout will occur if PayloadReady interrupt is not received + +// RADIOLIB_RF69_REG_PREAMBLE_MSB + REG_PREAMBLE_MSB +#define RADIOLIB_RF69_PREAMBLE_MSB 0x00 // 7 0 2-byte preamble size value +#define RADIOLIB_RF69_PREAMBLE_LSB 0x03 // 7 0 + +// RADIOLIB_RF69_REG_SYNC_CONFIG +#define RADIOLIB_RF69_SYNC_OFF 0b00000000 // 7 7 sync word detection off +#define RADIOLIB_RF69_SYNC_ON 0b10000000 // 7 7 sync word detection on (default) +#define RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC 0b00000000 // 6 6 FIFO fill condition: on SyncAddress interrupt (default) +#define RADIOLIB_RF69_FIFO_FILL_CONDITION 0b01000000 // 6 6 as long as the bit is set +#define RADIOLIB_RF69_SYNC_SIZE 0b00001000 // 5 3 size of sync word: SyncSize + 1 bytes +#define RADIOLIB_RF69_SYNC_TOL 0b00000000 // 2 0 number of tolerated errors in sync word + +// RADIOLIB_RF69_REG_SYNC_VALUE_1 - SYNC_VALUE_8 +#define RADIOLIB_RF69_SYNC_BYTE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define RADIOLIB_RF69_SYNC_BYTE_2 0x01 // 7 0 2nd byte +#define RADIOLIB_RF69_SYNC_BYTE_3 0x01 // 7 0 3rd byte +#define RADIOLIB_RF69_SYNC_BYTE_4 0x01 // 7 0 4th byte +#define RADIOLIB_RF69_SYNC_BYTE_5 0x01 // 7 0 5th byte +#define RADIOLIB_RF69_SYNC_BYTE_6 0x01 // 7 0 6th byte +#define RADIOLIB_RF69_SYNC_BYTE_7 0x01 // 7 0 7th byte +#define RADIOLIB_RF69_SYNC_BYTE_8 0x01 // 7 0 8th byte (LSB) + +// RADIOLIB_RF69_REG_PACKET_CONFIG_1 +#define RADIOLIB_RF69_PACKET_FORMAT_FIXED 0b00000000 // 7 7 fixed packet length (default) +#define RADIOLIB_RF69_PACKET_FORMAT_VARIABLE 0b10000000 // 7 7 variable packet length +#define RADIOLIB_RF69_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: none (default) +#define RADIOLIB_RF69_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define RADIOLIB_RF69_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define RADIOLIB_RF69_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define RADIOLIB_RF69_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define RADIOLIB_RF69_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 discard packet when CRC check fails (default) +#define RADIOLIB_RF69_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep packet when CRC check fails +#define RADIOLIB_RF69_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define RADIOLIB_RF69_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast + +// RADIOLIB_RF69_REG_PAYLOAD_LENGTH +#define RADIOLIB_RF69_PAYLOAD_LENGTH 0xFF // 7 0 payload length + +// RADIOLIB_RF69_REG_AUTO_MODES +#define RADIOLIB_RF69_ENTER_COND_NONE 0b00000000 // 7 5 condition for entering intermediate mode: none, AutoModes disabled (default) +#define RADIOLIB_RF69_ENTER_COND_FIFO_NOT_EMPTY 0b00100000 // 7 5 FifoNotEmpty rising edge +#define RADIOLIB_RF69_ENTER_COND_FIFO_LEVEL 0b01000000 // 7 5 FifoLevel rising edge +#define RADIOLIB_RF69_ENTER_COND_CRC_OK 0b01100000 // 7 5 CrcOk rising edge +#define RADIOLIB_RF69_ENTER_COND_PAYLOAD_READY 0b10000000 // 7 5 PayloadReady rising edge +#define RADIOLIB_RF69_ENTER_COND_SYNC_ADDRESS 0b10100000 // 7 5 SyncAddress rising edge +#define RADIOLIB_RF69_ENTER_COND_PACKET_SENT 0b11000000 // 7 5 PacketSent rising edge +#define RADIOLIB_RF69_ENTER_COND_FIFO_EMPTY 0b11100000 // 7 5 FifoNotEmpty falling edge +#define RADIOLIB_RF69_EXIT_COND_NONE 0b00000000 // 4 2 condition for exiting intermediate mode: none, AutoModes disabled (default) +#define RADIOLIB_RF69_EXIT_COND_FIFO_EMPTY 0b00100000 // 4 2 FifoNotEmpty falling edge +#define RADIOLIB_RF69_EXIT_COND_FIFO_LEVEL 0b01000000 // 4 2 FifoLevel rising edge +#define RADIOLIB_RF69_EXIT_COND_CRC_OK 0b01100000 // 4 2 CrcOk rising edge +#define RADIOLIB_RF69_EXIT_COND_PAYLOAD_READY 0b10000000 // 4 2 PayloadReady rising edge +#define RADIOLIB_RF69_EXIT_COND_SYNC_ADDRESS 0b10100000 // 4 2 SyncAddress rising edge +#define RADIOLIB_RF69_EXIT_COND_PACKET_SENT 0b11000000 // 4 2 PacketSent rising edge +#define RADIOLIB_RF69_EXIT_COND_TIMEOUT 0b11100000 // 4 2 timeout rising edge +#define RADIOLIB_RF69_INTER_MODE_SLEEP 0b00000000 // 1 0 intermediate mode: sleep (default) +#define RADIOLIB_RF69_INTER_MODE_STANDBY 0b00000001 // 1 0 standby +#define RADIOLIB_RF69_INTER_MODE_RX 0b00000010 // 1 0 Rx +#define RADIOLIB_RF69_INTER_MODE_TX 0b00000011 // 1 0 Tx + +// RADIOLIB_RF69_REG_FIFO_THRESH +#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_LEVEL 0b00000000 // 7 7 packet transmission start condition: FifoLevel +#define RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY 0b10000000 // 7 7 FifoNotEmpty (default) +#define RADIOLIB_RF69_FIFO_THRESH 0x1F // 6 0 default threshold to trigger FifoLevel interrupt + +// RADIOLIB_RF69_REG_PACKET_CONFIG_2 +#define RADIOLIB_RF69_INTER_PACKET_RX_DELAY 0b00000000 // 7 4 delay between FIFO empty and start of new RSSI phase +#define RADIOLIB_RF69_RESTART_RX 0b00000100 // 2 2 force receiver into wait mode +#define RADIOLIB_RF69_AUTO_RX_RESTART_OFF 0b00000000 // 1 1 auto Rx restart disabled +#define RADIOLIB_RF69_AUTO_RX_RESTART_ON 0b00000010 // 1 1 auto Rx restart enabled (default) +#define RADIOLIB_RF69_AES_OFF 0b00000000 // 0 0 AES encryption disabled (default) +#define RADIOLIB_RF69_AES_ON 0b00000001 // 0 0 AES encryption enabled, payload size limited to 66 bytes + +// RADIOLIB_RF69_REG_TEST_LNA +#define RADIOLIB_RF69_TEST_LNA_BOOST_NORMAL 0x1B // 7 0 +#define RADIOLIB_RF69_TEST_LNA_BOOST_HIGH 0x2D // 7 0 + +// RADIOLIB_RF69_REG_TEMP_1 +#define RADIOLIB_RF69_TEMP_MEAS_START 0b00001000 // 3 3 trigger temperature measurement +#define RADIOLIB_RF69_TEMP_MEAS_RUNNING 0b00000100 // 2 2 temperature measurement status: on-going +#define RADIOLIB_RF69_TEMP_MEAS_DONE 0b00000000 // 2 2 done + +// RADIOLIB_RF69_REG_TEST_DAGC +#define RADIOLIB_RF69_CONTINUOUS_DAGC_NORMAL 0x00 // 7 0 fading margin improvement: normal mode +#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_ON 0x20 // 7 0 improved mode for AfcLowBetaOn +#define RADIOLIB_RF69_CONTINUOUS_DAGC_LOW_BETA_OFF 0x30 // 7 0 improved mode for AfcLowBetaOff (default) + +// RADIOLIB_RF69_REG_TEST_PA1 +#define RADIOLIB_RF69_PA1_NORMAL 0x55 // 7 0 PA_BOOST: none +#define RADIOLIB_RF69_PA1_20_DBM 0x5D // 7 0 +20 dBm + +// RADIOLIB_RF69_REG_TEST_PA2 +#define RADIOLIB_RF69_PA2_NORMAL 0x70 // 7 0 PA_BOOST: none +#define RADIOLIB_RF69_PA2_20_DBM 0x7C // 7 0 +20 dBm + +// RadioLib defaults +#define RADIOLIB_RF69_DEFAULT_FREQ 434.0 +#define RADIOLIB_RF69_DEFAULT_BR 4.8 +#define RADIOLIB_RF69_DEFAULT_FREQDEV 5.0 +#define RADIOLIB_RF69_DEFAULT_RXBW 125.0 +#define RADIOLIB_RF69_DEFAULT_POWER 10 +#define RADIOLIB_RF69_DEFAULT_PREAMBLELEN 16 +#define RADIOLIB_RF69_DEFAULT_SW {0x12, 0xAD} +#define RADIOLIB_RF69_DEFAULT_SW_LEN 2 + /*! \class RF69 - \brief Control class for %RF69 module. Also serves as base class for SX1231. */ class RF69: public PhysicalLayer { @@ -486,7 +486,6 @@ class RF69: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ RF69(Module* module); @@ -497,19 +496,12 @@ class RF69: public PhysicalLayer { /*! \brief Initialization method. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. - \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLen Preamble Length in bits. Defaults to 16 bits. - \returns \ref status_codes */ int16_t begin( @@ -528,13 +520,9 @@ class RF69: public PhysicalLayer { /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; @@ -542,50 +530,40 @@ class RF69: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; /*! \brief Sets the module to sleep mode. - \returns \ref status_codes */ int16_t sleep(); /*! \brief Sets the module to standby mode. - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the module to standby. - \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. - \returns \ref status_codes */ int16_t standby(uint8_t mode) override; /*! \brief Starts direct mode transmission. - \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Starts direct mode reception. - \returns \ref status_codes */ int16_t receiveDirect() override; @@ -599,21 +577,18 @@ class RF69: public PhysicalLayer { /*! \brief Sets AES key. - \param Key to be used for AES encryption. Must be exactly 16 bytes long. */ void setAESKey(uint8_t* key); /*! \brief Enables AES encryption. - \returns \ref status_codes */ int16_t enableAES(); /*! \brief Disables AES encryption. - \returns \ref status_codes */ int16_t disableAES(); @@ -622,7 +597,6 @@ class RF69: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when DIO0 activates. - \param func ISR to call. */ void setDio0Action(void (*func)(void)); @@ -634,7 +608,6 @@ class RF69: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when DIO1 activates. - \param func ISR to call. */ void setDio1Action(void (*func)(void)); @@ -646,7 +619,6 @@ class RF69: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is empty. - \param func Pointer to interrupt service routine. */ void setFifoEmptyAction(void (*func)(void)); @@ -658,7 +630,6 @@ class RF69: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is full. - \param func Pointer to interrupt service routine. */ void setFifoFullAction(void (*func)(void)); @@ -670,26 +641,18 @@ class RF69: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is empty. - \param data Pointer to the transmission buffer. - \param totalLen Total number of bytes to transmit. - \param remLen Pointer to a counter holding the number of bytes that have been transmitted so far. - \returns True when a complete packet is sent, false if more data is needed. */ bool fifoAdd(uint8_t* data, int totalLen, int* remLen); /*! \brief Set interrupt service routine function to call when FIFO is sufficently full to read. - \param data Pointer to a buffer that stores the receive data. - \param totalLen Total number of bytes to receive. - \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. - \returns True when a complete packet is received, false if more data is needed. */ bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); @@ -697,54 +660,40 @@ class RF69: public PhysicalLayer { /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. - \returns \ref status_codes */ int16_t startReceive(); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param timeout Ignored. - \param irqFlags Ignored. - \param irqMask Ignored. - \param len Ignored. - \returns \ref status_codes */ int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data received after calling startReceive method. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; @@ -752,111 +701,90 @@ class RF69: public PhysicalLayer { // configuration methods /*! - \brief Sets carrier frequency. Allowed values are in bands 290.0 to 340.0 MHz, 431.0 to 510.0 MHz and 862.0 to 1020.0 MHz. - + \brief Sets carrier frequency. Allowed values are in bands 290.0 to 340.0 MHz, 431.0 to 510.0 MHz + and 862.0 to 1020.0 MHz. \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Gets carrier frequency. - \param[out] freq Variable to write carrier frequency currently set, in MHz. - \returns \ref status_codes */ int16_t getFrequency(float *freq); /*! \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. - \param br Bit rate to be set in kbps. - \returns \ref status_codes */ int16_t setBitRate(float br); /*! - \brief Sets receiver bandwidth. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25.0, 31.3, 41.7, 50.0, 62.5, 83.3, 100.0, 125.0, 166.7, 200.0, 250.0, 333.3, 400.0 and 500.0 kHz. - + \brief Sets receiver bandwidth. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, + 20.8, 25.0, 31.3, 41.7, 50.0, 62.5, 83.3, 100.0, 125.0, 166.7, 200.0, 250.0, 333.3, 400.0 and 500.0 kHz. \param rxBw Receiver bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setRxBandwidth(float rxBw); /*! \brief Sets frequency deviation. - \param freqDev Frequency deviation to be set in kHz. - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Gets frequency deviation. - \param[out] freqDev Where to write the frequency deviation currently set, in kHz. - \returns \ref status_codes */ int16_t getFrequencyDeviation(float *freqDev); /*! - \brief Sets output power. Allowed values range from -18 to 13 dBm for low power modules (RF69C/CW) or -2 to 20 dBm (RF69H/HC/HCW). - - \param power Output power to be set in dBm. - - \param highPower Set to true when using modules high power port (RF69H/HC/HCW). Defaults to false (models without high power port - RF69C/CW). - + \brief Sets output power. Allowed values range from -18 to 13 dBm for + low power modules (RF69C/CW) or -2 to 20 dBm (RF69H/HC/HCW). + \param pwr Output power to be set in dBm. + \param highPower Set to true when using modules high power port (RF69H/HC/HCW). + Defaults to false (models without high power port - RF69C/CW). \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool highPower = false); + int16_t setOutputPower(int8_t pwr, bool highPower = false); /*! \brief Sets sync word. Up to 8 bytes can be set as sync word. - \param syncWord Pointer to the array of sync word bytes. - \param len Sync word length in bytes. - \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. */ int16_t setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0); /*! \brief Sets preamble length. - \param preambleLen Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. - \returns \ref status_codes */ int16_t setPreambleLength(uint8_t preambleLen); /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. - \param nodeAddr Node address to be set. - \returns \ref status_codes */ int16_t setNodeAddress(uint8_t nodeAddr); /*! \brief Sets broadcast address. Calling this method will also enable address filtering for node and broadcast address. - \param broadAddr Node address to be set. - \returns \ref status_codes */ int16_t setBroadcastAddress(uint8_t broadAddr); /*! \brief Disables address filtering. Calling this method will also erase previously set addresses. - \returns \ref status_codes */ int16_t disableAddressFiltering(); @@ -865,136 +793,113 @@ class RF69: public PhysicalLayer { /*! \brief Sets ambient temperature. Required to correct values from on-board temperature sensor. - \param tempAmbient Ambient temperature in degrees Celsius. */ void setAmbientTemperature(int16_t tempAmbient); /*! \brief Measures temperature. - \returns Measured temperature in degrees Celsius. */ int16_t getTemperature(); /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! \brief Enables/disables OOK modulation instead of FSK. - Note: This function calls setRxBandwidth again, since register values differ based on OOK mode being enabled/disabled - - \param enableOOK Enable (true) or disable (false) OOK. - + Note: This function calls setRxBandwidth again, since register values differ based on OOK mode being enabled/disabled. + \param enable Enable (true) or disable (false) OOK. \returns \ref status_codes */ - int16_t setOOK(bool enableOOK); + int16_t setOOK(bool enable); /*! \brief Selects the type of threshold in the OOK data slicer - - \param type Threshold type: RADIOLIB_RF69_OOK_THRESH_PEAK(default), RADIOLIB_RF69_OOK_THRESH_FIXED or RADIOLIB_RF69_OOK_THRESH_AVERAGE - + \param type Threshold type: RADIOLIB_RF69_OOK_THRESH_PEAK(default), RADIOLIB_RF69_OOK_THRESH_FIXED or + RADIOLIB_RF69_OOK_THRESH_AVERAGE \returns \ref status_codes */ int16_t setOokThresholdType(uint8_t type); /*! - \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. - - \param value Fixed threshold value (in dB) in the OOK demodulator. Used when OokThresType = RADIOLIB_RF69_OOK_THRESH_FIXED. - + \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer + in OOK when Peak mode is used. + \param value Fixed threshold value (in dB) in the OOK demodulator. + Used when OokThresType = RADIOLIB_RF69_OOK_THRESH_FIXED. \returns \ref status_codes */ int16_t setOokFixedThreshold(uint8_t value); /*! \brief Period of decrement of the RSSI threshold in the OOK demodulator. - \param value Use defines RADIOLIB_RF69_OOK_PEAK_THRESH_DEC_X_X_CHIP - \returns \ref status_codes */ int16_t setOokPeakThresholdDecrement(uint8_t value); /*! \brief Set modem in fixed packet length mode. - \param len Packet length. - \returns \ref status_codes */ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_RF69_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. - \param len Maximum packet length. - \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_RF69_MAX_PACKET_LENGTH); /*! \brief Enable sync word filtering and generation. - \param numBits Sync word length in bits. - \returns \ref status_codes */ int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0); /*! \brief Disable preamble and sync word filtering and generation. - \returns \ref status_codes */ int16_t disableSyncWordFiltering(); /*! \brief Enable Bit synchronization in continuous mode. - \returns \ref status_codes */ int16_t enableContinuousModeBitSync(); /*! \brief Disable Bit synchronization in continuous mode. - \returns \ref status_codes */ int16_t disableContinuousModeBitSync(); /*! \brief Enable CRC filtering and generation. - \param crcOn Set or unset CRC filtering. - \returns \ref status_codes */ int16_t setCrcFiltering(bool crcOn = true); /*! \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). - - \param promiscuous Set or unset promiscuous mode. - + \param enable Set or unset promiscuous mode. \returns \ref status_codes */ - int16_t setPromiscuousMode(bool promiscuous = true); + int16_t setPromiscuousMode(bool enable = true); /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. - Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. + Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; @@ -1002,34 +907,27 @@ class RF69: public PhysicalLayer { /*! \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. - \param encoding Encoding to be used. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; /*! - \brief Enable/disable LNA Boost mode (disabled by default). - - \param value True to enable, false to disable. - - \returns \ref status_codes + \brief Enable/disable LNA Boost mode (disabled by default). + \param value True to enable, false to disable. + \returns \ref status_codes */ int16_t setLnaTestBoost(bool value); /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. - \returns Last packet RSSI in dBm. */ float getRSSI(); /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled - \param dbm A dBm value between -127.5 and 0 inclusive - \returns \ref status_codes */ int16_t setRSSIThreshold(float dbm); @@ -1041,30 +939,26 @@ class RF69: public PhysicalLayer { void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! - \brief Get one truly random byte from RSSI noise. - - \returns TRNG byte. + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. */ uint8_t randomByte(); /*! - \brief Read version SPI register. Should return RF69_CHIP_VERSION (0x24) if SX127x is connected and working. - - \returns Version register contents or \ref status_codes + \brief Read version SPI register. Should return RF69_CHIP_VERSION (0x24) if SX127x is connected and working. + \returns Version register contents or \ref status_codes */ int16_t getChipVersion(); #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. - \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. - \param pin Pin on which to read. */ void readBit(uint32_t pin); @@ -1072,11 +966,8 @@ class RF69: public PhysicalLayer { /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). - \param pin Pin number onto which a signal is to be placed. - \param value The value that indicates which function to place on that pin. See chip datasheet for details. - \returns \ref status_codes */ int16_t setDIOMapping(uint32_t pin, uint32_t value); @@ -1084,28 +975,28 @@ class RF69: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; #if !defined(RADIOLIB_GODMODE) protected: #endif - float _freq = RADIOLIB_RF69_DEFAULT_FREQ; - float _br = RADIOLIB_RF69_DEFAULT_BR; - float _rxBw = RADIOLIB_RF69_DEFAULT_RXBW; - bool _ook = false; - int16_t _tempOffset = 0; - int8_t _power = RADIOLIB_RF69_DEFAULT_POWER; + float frequency = RADIOLIB_RF69_DEFAULT_FREQ; + float bitRate = RADIOLIB_RF69_DEFAULT_BR; + float rxBandwidth = RADIOLIB_RF69_DEFAULT_RXBW; + bool ookEnabled = false; + int16_t tempOffset = 0; + int8_t power = RADIOLIB_RF69_DEFAULT_POWER; - size_t _packetLength = 0; - bool _packetLengthQueried = false; - uint8_t _packetLengthConfig = RADIOLIB_RF69_PACKET_FORMAT_VARIABLE; + size_t packetLength = 0; + bool packetLengthQueried = false; + uint8_t packetLengthConfig = RADIOLIB_RF69_PACKET_FORMAT_VARIABLE; - bool _promiscuous = false; + bool promiscuous = false; - uint8_t _syncWordLength = RADIOLIB_RF69_DEFAULT_SW_LEN; + uint8_t syncWordLength = RADIOLIB_RF69_DEFAULT_SW_LEN; - bool _bitSync = true; + bool bitSync = true; int16_t config(); int16_t directMode(); From 14302537ee4fc388cdc5164c11c2d9346acebdaa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 19:44:07 +0200 Subject: [PATCH 0514/1848] [SX1231] General reformatting --- src/modules/SX1231/SX1231.cpp | 20 ++--- src/modules/SX1231/SX1231.h | 165 ++++++++++++++++------------------ 2 files changed, 88 insertions(+), 97 deletions(-) diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index 3b1b72f6e7..cc9e3409bc 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -7,9 +7,9 @@ SX1231::SX1231(Module* mod) : RF69(mod) { int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); // try to find the SX1231 chip uint8_t i = 0; @@ -18,17 +18,17 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po int16_t version = getChipVersion(); if((version == 0x21) || (version == 0x22) || (version == 0x23)) { flagFound = true; - _chipRevision = version; + this->chipRevision = version; } else { RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); - _mod->hal->delay(10); + this->mod->hal->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN("No SX1231 found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX1231"); @@ -43,7 +43,7 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // configure bitrate - _rxBw = 125.0; + this->rxBandwidth = 125.0; state = setBitRate(br); RADIOLIB_ASSERT(state); @@ -75,13 +75,13 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po } // SX1231 V2a only - if(_chipRevision == RADIOLIB_SX1231_CHIP_REVISION_2_A) { + if(this->chipRevision == RADIOLIB_SX1231_CHIP_REVISION_2_A) { // modify default OOK threshold value - state = _mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); RADIOLIB_ASSERT(state); // enable OCP with 95 mA limit - state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX1231/SX1231.h index 21a14c686f..6054034510 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX1231/SX1231.h @@ -8,113 +8,104 @@ #include "../../Module.h" #include "../RF69/RF69.h" -#define RADIOLIB_SX1231_CHIP_REVISION_2_A 0x21 -#define RADIOLIB_SX1231_CHIP_REVISION_2_B 0x22 -#define RADIOLIB_SX1231_CHIP_REVISION_2_C 0x23 - -//SX1231 specific register map -#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E - -//SX1231_REG_TEST_OOK -#define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C - -// SX1231_REG_DIO_MAPPING_1 -#define RADIOLIB_SX1231_DIO0_CONT_LOW_BAT 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_RSSI 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_CONT_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_LOW_BAT 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_CRC_OK 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_RSSI 0b11000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO0_PACK_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO1_CONT_LOW_BAT 0b00100000 // 5 4 -#define RADIOLIB_SX1231_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 -#define RADIOLIB_SX1231_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define RADIOLIB_SX1231_DIO1_CONT_RX_READY 0b00010000 // 5 4 -#define RADIOLIB_SX1231_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 -#define RADIOLIB_SX1231_DIO1_CONT_TX_READY 0b00010000 // 5 4 -#define RADIOLIB_SX1231_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 -#define RADIOLIB_SX1231_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 -#define RADIOLIB_SX1231_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 -#define RADIOLIB_SX1231_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 -#define RADIOLIB_SX1231_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 -#define RADIOLIB_SX1231_DIO2_CONT_DATA 0b00000000 // 3 2 -#define RADIOLIB_SX1231_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 -#define RADIOLIB_SX1231_DIO2_PACK_LOW_BAT 0b00001000 // 3 2 -#define RADIOLIB_SX1231_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 -#define RADIOLIB_SX1231_DIO2_PACK_DATA 0b00000100 // 3 2 -#define RADIOLIB_SX1231_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 -#define RADIOLIB_SX1231_DIO3_CONT_RSSI 0b00000000 // 0 1 -#define RADIOLIB_SX1231_DIO3_CONT_RX_READY 0b00000001 // 0 1 -#define RADIOLIB_SX1231_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 -#define RADIOLIB_SX1231_DIO3_CONT_TX_READY 0b00000001 // 0 1 -#define RADIOLIB_SX1231_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 -#define RADIOLIB_SX1231_DIO3_PACK_LOW_BAT 0b00000010 // 0 1 -#define RADIOLIB_SX1231_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 -#define RADIOLIB_SX1231_DIO3_PACK_RSSI 0b00000001 // 0 1 -#define RADIOLIB_SX1231_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 -#define RADIOLIB_SX1231_DIO3_PACK_TX_READY 0b00000001 // 0 1 - -// SX1231_REG_DIO_MAPPING_2 -#define RADIOLIB_SX1231_DIO4_CONT_LOW_BAT 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_CONT_RX_READY 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_CONT_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_LOW_BAT 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_RSSI 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_RX_READY 0b10000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_MODE_READY 0b00000000 // 7 6 -#define RADIOLIB_SX1231_DIO4_PACK_TX_READY 0b01000000 // 7 6 -#define RADIOLIB_SX1231_DIO5_CONT_LOW_BAT 0b00100000 // 5 4 -#define RADIOLIB_SX1231_DIO5_CONT_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX1231_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_SX1231_DIO5_CONT_RSSI 0b00010000 // 5 4 -#define RADIOLIB_SX1231_DIO5_PACK_LOW_BAT 0b00100000 // 5 4 -#define RADIOLIB_SX1231_DIO5_PACK_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX1231_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_SX1231_DIO5_PACK_DATA 0b00010000 // 5 4 +#define RADIOLIB_SX1231_CHIP_REVISION_2_A 0x21 +#define RADIOLIB_SX1231_CHIP_REVISION_2_B 0x22 +#define RADIOLIB_SX1231_CHIP_REVISION_2_C 0x23 + +// RADIOLIB_SX1231 specific register map +#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E + +// RADIOLIB_SX1231_REG_TEST_OOK +#define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C + +// RADIOLIB_SX1231_REG_DIO_MAPPING_1 +#define RADIOLIB_SX1231_DIO0_CONT_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_TIMEOUT 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_RSSI 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_CRC_OK 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_RSSI 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO0_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO1_CONT_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_RX_READY 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_CONT_TX_READY 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO1_PACK_TIMEOUT 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_LOW_BAT 0b00001000 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2 +#define RADIOLIB_SX1231_DIO2_PACK_DATA 0b00000100 // 3 2 +#define RADIOLIB_SX1231_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_RSSI 0b00000000 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_RX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_TIMEOUT 0b00000011 // 0 1 +#define RADIOLIB_SX1231_DIO3_CONT_TX_READY 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_LOW_BAT 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_RSSI 0b00000001 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1 +#define RADIOLIB_SX1231_DIO3_PACK_TX_READY 0b00000001 // 0 1 + +// RADIOLIB_SX1231_REG_DIO_MAPPING_2 +#define RADIOLIB_SX1231_DIO4_CONT_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_RX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_CONT_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_LOW_BAT 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_TIMEOUT 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_RSSI 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_MODE_READY 0b00000000 // 7 6 +#define RADIOLIB_SX1231_DIO4_PACK_TX_READY 0b01000000 // 7 6 +#define RADIOLIB_SX1231_DIO5_CONT_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO5_CONT_RSSI 0b00010000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_LOW_BAT 0b00100000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX1231_DIO5_PACK_DATA 0b00010000 // 5 4 /*! \class SX1231 - \brief Control class for %SX1231 module. Overrides some methods from RF69 due to different register values. */ class SX1231: public RF69 { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1231(Module* mod); /*! \brief Initialization method. - \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. - \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. - \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLen Preamble Length in bits. Defaults to 16 bits. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); @@ -122,7 +113,7 @@ class SX1231: public RF69 { #if !defined(RADIOLIB_GODMODE) private: #endif - uint8_t _chipRevision = 0; + uint8_t chipRevision = 0; }; #endif From f1c9423035cc312a78fd0c504808e92170156941 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 21:11:27 +0200 Subject: [PATCH 0515/1848] [SX126x] Fixed typo --- src/modules/SX126x/SX126x.cpp | 14 +++++++------- src/modules/SX126x/SX126x.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 00e3d1afa0..f9c90dc185 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -116,7 +116,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL // initialize configuration variables (will be overwritten during public settings configuration) this->bitRate = 21333; // 48.0 kbps - this->freqencyDev = 52428; // 50.0 kHz + this->frequencyDev = 52428; // 50.0 kHz this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; this->rxBandwidthKhz = 156.2; this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; @@ -871,10 +871,10 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0)); // check modulation parameters - this->freqencyDev = freqDevRaw; + this->frequencyDev = freqDevRaw; // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } int16_t SX126x::setBitRate(float br) { @@ -895,7 +895,7 @@ int16_t SX126x::setBitRate(float br) { this->bitRate = brRaw; // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } int16_t SX126x::setRxBandwidth(float rxBw) { @@ -905,7 +905,7 @@ int16_t SX126x::setRxBandwidth(float rxBw) { } // check modulation parameters - /*if(2 * this->freqencyDev + this->bitRate > rxBw * 1000.0) { + /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) { return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); }*/ this->rxBandwidthKhz = rxBw; @@ -958,7 +958,7 @@ int16_t SX126x::setRxBandwidth(float rxBw) { } // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { @@ -1026,7 +1026,7 @@ int16_t SX126x::setDataShaping(uint8_t sh) { } // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->freqencyDev)); + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 5f92024fc9..15cddbe7ac 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1067,7 +1067,7 @@ class SX126x: public PhysicalLayer { float bandwidthKhz = 0; bool ldroAuto = true; - uint32_t bitRate = 0, freqencyDev = 0; + uint32_t bitRate = 0, frequencyDev = 0; uint8_t rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; uint16_t preambleLengthFSK = 0; float rxBandwidthKhz = 0; From 674c37d00bb8522c0b71057505486df8c2bcd1fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 21:14:01 +0200 Subject: [PATCH 0516/1848] [Si443x] General reformatting --- src/modules/RFM2x/RFM22.h | 1 - src/modules/RFM2x/RFM23.h | 1 - src/modules/Si443x/Si4430.cpp | 2 +- src/modules/Si443x/Si4430.h | 14 - src/modules/Si443x/Si4431.cpp | 2 +- src/modules/Si443x/Si4431.h | 12 - src/modules/Si443x/Si4432.cpp | 2 +- src/modules/Si443x/Si4432.h | 14 - src/modules/Si443x/Si443x.cpp | 246 ++++----- src/modules/Si443x/Si443x.h | 915 ++++++++++++++++------------------ 10 files changed, 553 insertions(+), 656 deletions(-) diff --git a/src/modules/RFM2x/RFM22.h b/src/modules/RFM2x/RFM22.h index 61387b178e..f1055a8deb 100644 --- a/src/modules/RFM2x/RFM22.h +++ b/src/modules/RFM2x/RFM22.h @@ -11,7 +11,6 @@ /*! \class RFM22 - \brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules. */ RADIOLIB_TYPE_ALIAS(Si4432, RFM22); diff --git a/src/modules/RFM2x/RFM23.h b/src/modules/RFM2x/RFM23.h index 02afc68ad6..3fd333624b 100644 --- a/src/modules/RFM2x/RFM23.h +++ b/src/modules/RFM2x/RFM23.h @@ -11,7 +11,6 @@ /*! \class RFM23 - \brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules. */ RADIOLIB_TYPE_ALIAS(Si4431, RFM23); diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index ecc8d8c6b7..9de46ae12b 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -32,7 +32,7 @@ int16_t Si4430::setOutputPower(int8_t power) { RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h index 5a9b72d3de..5b07350901 100644 --- a/src/modules/Si443x/Si4430.h +++ b/src/modules/Si443x/Si4430.h @@ -10,7 +10,6 @@ /*! \class Si4430 - \brief Derived class for %Si4430 modules. */ class Si4430: public Si4432 { @@ -20,7 +19,6 @@ class Si4430: public Si4432 { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio chip. */ Si4430(Module* mod); @@ -29,19 +27,12 @@ class Si4430: public Si4432 { /*! \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 900.0 MHz to 960.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. - \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. - \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. - \param preambleLen Preamble Length in bits. Defaults to 16 bits. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); @@ -50,23 +41,18 @@ class Si4430: public Si4432 { /*! \brief Sets carrier frequency. Allowed values range from 900.0 MHz to 960.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); - #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 98b07a8fec..566b245ae3 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -25,7 +25,7 @@ int16_t Si4431::setOutputPower(int8_t power) { RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h index 5cf6e7704c..8ca35a3449 100644 --- a/src/modules/Si443x/Si4431.h +++ b/src/modules/Si443x/Si4431.h @@ -10,7 +10,6 @@ /*! \class Si4431 - \brief Derived class for %Si4431 modules. */ class Si4431: public Si4432 { @@ -20,7 +19,6 @@ class Si4431: public Si4432 { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio chip. */ Si4431(Module* mod); @@ -29,19 +27,12 @@ class Si4431: public Si4432 { /*! \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 240.0 MHz to 930.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. - \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. - \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. - \param preambleLen Preamble Length in bits. Defaults to 16 bits. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); @@ -50,14 +41,11 @@ class Si4431: public Si4432 { /*! \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); - #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 76147df439..0f679d677e 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -32,7 +32,7 @@ int16_t Si4432::setOutputPower(int8_t power) { RADIOLIB_CHECK_RANGE(power, -1, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h index 2c38b36dce..3903a5acab 100644 --- a/src/modules/Si443x/Si4432.h +++ b/src/modules/Si443x/Si4432.h @@ -10,7 +10,6 @@ /*! \class Si4432 - \brief Derived class for %Si4432 modules. */ class Si4432: public Si443x { @@ -20,7 +19,6 @@ class Si4432: public Si443x { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio chip. */ Si4432(Module* mod); @@ -29,19 +27,12 @@ class Si4432: public Si443x { /*! \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 240.0 MHz to 930.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. - \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. - \param power Transmission output power in dBm. Allowed values range from -1 to 20 dBm in 3 dBm steps. - \param preambleLen Preamble Length in bits. Defaults to 16 bits. - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); @@ -50,23 +41,18 @@ class Si4432: public Si443x { /*! \brief Sets carrier frequency. Allowed values range from 240.0 MHz to 930.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets output power. Allowed values range from -1 to 20 dBm in 3 dBm steps. - \param power Output power to be set in dBm. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power); - #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 445a3ff077..c38e5b9fa4 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -3,31 +3,31 @@ #if !defined(RADIOLIB_EXCLUDE_SI443X) Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { - _mod = mod; + this->mod = mod; } Module* Si443x::getMod() { - return(_mod); + return(this->mod); } int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); // try to find the Si443x chip if(!Si443x::findChip()) { RADIOLIB_DEBUG_PRINTLN("No Si443x found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { RADIOLIB_DEBUG_PRINTLN("M\tSi443x"); } // reset the device - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET); // clear POR interrupt clearIRQFlags(); @@ -68,26 +68,26 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) } void Si443x::reset() { - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); - _mod->hal->delay(100); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(100); } int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = _mod->hal->micros(); - while(_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -98,16 +98,16 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t Si443x::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->hal->micros(); - while(_mod->hal->digitalRead(_mod->getIrq())) { - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(this->mod->hal->digitalRead(this->mod->getIrq())) { + if(this->mod->hal->micros() - start > timeout) { standby(); clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -120,16 +120,16 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { int16_t Si443x::sleep() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); // disable wakeup timer interrupt - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, 0x00); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, 0x00); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); RADIOLIB_ASSERT(state); // enable wakeup timer to set mode to sleep - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER); return(state); } @@ -140,13 +140,13 @@ int16_t Si443x::standby() { int16_t Si443x::standby(uint8_t mode) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, mode, 7, 0, 10)); + this->mod->setRfSwitchState(Module::MODE_IDLE); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, mode, 7, 0, 10)); } int16_t Si443x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { @@ -166,13 +166,13 @@ int16_t Si443x::transmitDirect(uint32_t frf) { uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; // update registers - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); // start direct transmission directMode(); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); return(RADIOLIB_ERR_NONE); } @@ -182,36 +182,36 @@ int16_t Si443x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } int16_t Si443x::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(); RADIOLIB_ASSERT(state); // start receiving - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } int16_t Si443x::packetMode() { - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); RADIOLIB_ASSERT(state); - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); } void Si443x::setIrqAction(void (*func)(void)) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptFalling); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptFalling); } void Si443x::clearIrqAction() { - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -225,32 +225,32 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // clear Tx FIFO - _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_RESET, 0, 0); - _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_RESET, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0); // clear interrupt flags clearIRQFlags(); // set packet length - if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + if (this->packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); } /// \todo use header as address field? (void)addr; // write packet to FIFO - _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // set interrupt mapping - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_PACKET_SENT_ENABLED); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_PACKET_SENT_ENABLED); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // set mode to transmit - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_TX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } @@ -269,21 +269,21 @@ int16_t Si443x::startReceive() { RADIOLIB_ASSERT(state); // clear Rx FIFO - _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_RESET, 1, 1); - _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_RESET, 1, 1); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1); // clear interrupt flags clearIRQFlags(); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set interrupt mapping - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // set mode to receive - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); return(state); } @@ -310,7 +310,7 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { } // read packet data - _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, length, data); + this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, length, data); // dump the bytes that weren't requested if(dumpLen != 0) { @@ -318,7 +318,7 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { } // clear internal flag so getPacketLength can return the new packet length - _packetLengthQueried = false; + this->packetLengthQueried = false; // set mode to standby int16_t state = standby(); @@ -346,12 +346,12 @@ int16_t Si443x::setBitRate(float br) { uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0; // update registers - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); if(state == RADIOLIB_ERR_NONE) { - _br = br; + this->bitRate = br; } RADIOLIB_ASSERT(state); @@ -374,11 +374,11 @@ int16_t Si443x::setFrequencyDeviation(float freqDev) { uint16_t fdev = (uint16_t)(newFreqDev / 0.625); // update registers - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); if(state == RADIOLIB_ERR_NONE) { - _freqDev = newFreqDev; + this->frequencyDev = newFreqDev; } return(state); @@ -482,7 +482,7 @@ int16_t Si443x::setRxBandwidth(float rxBw) { decRate <<= 4; // update register - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); RADIOLIB_ASSERT(state); // update clock recovery @@ -499,11 +499,11 @@ int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { RADIOLIB_ASSERT(state); // set sync word length - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); RADIOLIB_ASSERT(state); // set sync word bytes - _mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_SYNC_WORD_3, syncWord, len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_SYNC_WORD_3, syncWord, len); return(state); } @@ -516,25 +516,25 @@ int16_t Si443x::setPreambleLength(uint8_t preambleLen) { // set default preamble length uint8_t preLenNibbles = preambleLen / 4; - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_LENGTH, preLenNibbles); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_LENGTH, preLenNibbles); RADIOLIB_ASSERT(state); // set default preamble detection threshold to 5/8 of preamble length (in units of 4 bits) uint8_t preThreshold = 5*preLenNibbles / 8; - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 3, 7, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 3, 7, 3)); } size_t Si443x::getPacketLength(bool update) { - if(!_packetLengthQueried && update) { - if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON) { - _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH); + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON) { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH); } else { - _packetLength = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH); } - _packetLengthQueried = true; + this->packetLengthQueried = true; } - return(_packetLength); + return(this->packetLength); } int16_t Si443x::setEncoding(uint8_t encoding) { @@ -546,11 +546,11 @@ int16_t Si443x::setEncoding(uint8_t encoding) { /// \todo - add inverted Manchester? switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_ENCODING_MANCHESTER: - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_ENCODING_WHITENING: - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: return(RADIOLIB_ERR_INVALID_ENCODING); } @@ -564,37 +564,37 @@ int16_t Si443x::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_SHAPING_0_3: return(RADIOLIB_ERR_INVALID_ENCODING); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_GFSK, 1, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_GFSK, 1, 0)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: return(RADIOLIB_ERR_INVALID_ENCODING); } } void Si443x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - _mod->setRfSwitchPins(rxEn, txEn); + this->mod->setRfSwitchPins(rxEn, txEn); } void Si443x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - _mod->setRfSwitchTable(pins, table); + this->mod->setRfSwitchTable(pins, table); } uint8_t Si443x::randomByte() { // set mode to Rx - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_RX_ON | RADIOLIB_SI443X_XTAL_ON); // wait a bit for the RSSI reading to stabilise - _mod->hal->delay(10); + this->mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { - randByte |= ((_mod->SPIreadRegister(RADIOLIB_SI443X_REG_RSSI) & 0x01) << i); + randByte |= ((this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_RSSI) & 0x01) << i); } // set mode to standby @@ -604,7 +604,7 @@ uint8_t Si443x::randomByte() { } int16_t Si443x::getChipVersion() { - return(_mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); + return(this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) @@ -613,7 +613,7 @@ void Si443x::setDirectAction(void (*func)(void)) { } void Si443x::readBit(uint32_t pin) { - updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); } #endif @@ -634,7 +634,7 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; uint8_t freqBand = (newFreq / 10) - 24; uint8_t afcLimiter = 80; - _freq = newFreq; + this->frequency = newFreq; if(newFreq >= 480.0) { bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; freqBand = (newFreq / 20) - 24; @@ -645,10 +645,10 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; // update registers - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); - state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); - state |= _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AFC_LIMITER, afcLimiter); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AFC_LIMITER, afcLimiter); return(state); } @@ -660,15 +660,15 @@ int16_t Si443x::setPacketMode(uint8_t mode, uint8_t len) { } // set to fixed packet length - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, mode, 3, 3); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, mode, 3, 3); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value - _packetLengthConfig = mode; + this->packetLengthConfig = mode; return(state); } @@ -680,12 +680,12 @@ bool Si443x::findChip() { reset(); // check version register - uint8_t version = _mod->SPIreadRegister(RADIOLIB_SI443X_REG_DEVICE_VERSION); + uint8_t version = this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_DEVICE_VERSION); if(version == RADIOLIB_SI443X_DEVICE_VERSION) { flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); - _mod->hal->delay(10); + this->mod->hal->delay(10); i++; } } @@ -695,12 +695,12 @@ bool Si443x::findChip() { void Si443x::clearIRQFlags() { uint8_t buff[2]; - _mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); + this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); } void Si443x::clearFIFO(size_t count) { while(count) { - _mod->SPIreadRegister(RADIOLIB_SI443X_REG_FIFO_ACCESS); + this->mod->SPIreadRegister(RADIOLIB_SI443X_REG_FIFO_ACCESS); count--; } } @@ -711,22 +711,22 @@ int16_t Si443x::config() { RADIOLIB_ASSERT(state); // disable POR and chip ready interrupts - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // enable AGC - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AGC_OVERRIDE_1, RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON | RADIOLIB_SI443X_AGC_ON, 6, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_AGC_OVERRIDE_1, RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON | RADIOLIB_SI443X_AGC_ON, 6, 5); RADIOLIB_ASSERT(state); // disable packet header - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF | RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF | RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); RADIOLIB_ASSERT(state); // set antenna switching - _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO0_CONFIG, RADIOLIB_SI443X_GPIOX_TX_STATE_OUT, 4, 0); - _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_RX_STATE_OUT, 4, 0); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO0_CONFIG, RADIOLIB_SI443X_GPIOX_TX_STATE_OUT, 4, 0); + this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_RX_STATE_OUT, 4, 0); // disable packet header checking - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_1, RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE | RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_1, RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE | RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE); RADIOLIB_ASSERT(state); return(state); @@ -734,9 +734,9 @@ int16_t Si443x::config() { int16_t Si443x::updateClockRecovery() { // get the parameters - uint8_t bypass = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; - uint8_t decRate = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; - uint8_t manch = _mod->SPIgetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; + uint8_t bypass = this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; + uint8_t decRate = this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; + uint8_t manch = this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; // calculate oversampling ratio, NCO offset and clock recovery gain int8_t ndecExp = (int8_t)decRate - 3; @@ -747,9 +747,9 @@ int16_t Si443x::updateClockRecovery() { ndecExp *= -1; ndec = 1.0/(float)((uint16_t)1 << ndecExp); } - float rxOsr = ((float)(500 * (1 + 2*bypass))) / (ndec * _br * ((float)(1 + manch))); - uint32_t ncoOff = (_br * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass)); - uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * _br) / (rxOsr * (_freqDev / 0.625))); + float rxOsr = ((float)(500 * (1 + 2*bypass))) / (ndec * this->bitRate * ((float)(1 + manch))); + uint32_t ncoOff = (this->bitRate * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass)); + uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * this->bitRate) / (rxOsr * (this->frequencyDev / 0.625))); uint16_t rxOsr_fixed = (uint16_t)rxOsr; // print that whole mess @@ -757,39 +757,39 @@ int16_t Si443x::updateClockRecovery() { RADIOLIB_DEBUG_PRINTLN("%f\t%d\t%X\n%d\t%X\n%d\t%X", rxOsr, rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); // update oversampling ratio - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); RADIOLIB_ASSERT(state); // update NCO offset - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); RADIOLIB_ASSERT(state); // update clock recovery loop gain - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); RADIOLIB_ASSERT(state); return(state); } int16_t Si443x::directMode() { - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO, 5, 4); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO, 5, 4); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT, 4, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO1_CONFIG, RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT, 4, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO2_CONFIG, RADIOLIB_SI443X_GPIOX_TX_DATA_IN, 4, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_GPIO2_CONFIG, RADIOLIB_SI443X_GPIOX_TX_DATA_IN, 4, 0); RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_FSK, 1, 0); return(state); } diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 595b0d9178..e708204cac 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -10,544 +10,543 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // Si443x physical layer properties -#define RADIOLIB_SI443X_FREQUENCY_STEP_SIZE 156.25 -#define RADIOLIB_SI443X_MAX_PACKET_LENGTH 64 +#define RADIOLIB_SI443X_FREQUENCY_STEP_SIZE 156.25 +#define RADIOLIB_SI443X_MAX_PACKET_LENGTH 64 // Si443x series common registers -#define RADIOLIB_SI443X_REG_DEVICE_TYPE 0x00 -#define RADIOLIB_SI443X_REG_DEVICE_VERSION 0x01 -#define RADIOLIB_SI443X_REG_DEVICE_STATUS 0x02 -#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 0x03 -#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 0x04 -#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 0x05 -#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 0x06 -#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 0x07 -#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 0x08 -#define RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09 -#define RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK 0x0A -#define RADIOLIB_SI443X_REG_GPIO0_CONFIG 0x0B -#define RADIOLIB_SI443X_REG_GPIO1_CONFIG 0x0C -#define RADIOLIB_SI443X_REG_GPIO2_CONFIG 0x0D -#define RADIOLIB_SI443X_REG_IO_PORT_CONFIG 0x0E -#define RADIOLIB_SI443X_REG_ADC_CONFIG 0x0F -#define RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10 -#define RADIOLIB_SI443X_REG_ADC_VALUE 0x11 -#define RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL 0x12 -#define RADIOLIB_SI443X_REG_TEMP_VALUE_OFFSET 0x13 -#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14 -#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15 -#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16 -#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17 -#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18 -#define RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION 0x19 -#define RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A -#define RADIOLIB_SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B -#define RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH 0x1C -#define RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D -#define RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL 0x1E -#define RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F -#define RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20 -#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 0x21 -#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 0x22 -#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 0x23 -#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24 -#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25 -#define RADIOLIB_SI443X_REG_RSSI 0x26 -#define RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27 -#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_1 0x28 -#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_2 0x29 -#define RADIOLIB_SI443X_REG_AFC_LIMITER 0x2A -#define RADIOLIB_SI443X_REG_AFC_CORRECTION 0x2B -#define RADIOLIB_SI443X_REG_OOK_COUNTER_1 0x2C -#define RADIOLIB_SI443X_REG_OOK_COUNTER_2 0x2D -#define RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD 0x2E -#define RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL 0x30 -#define RADIOLIB_SI443X_REG_EZMAC_STATUS 0x31 -#define RADIOLIB_SI443X_REG_HEADER_CONTROL_1 0x32 -#define RADIOLIB_SI443X_REG_HEADER_CONTROL_2 0x33 -#define RADIOLIB_SI443X_REG_PREAMBLE_LENGTH 0x34 -#define RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL 0x35 -#define RADIOLIB_SI443X_REG_SYNC_WORD_3 0x36 -#define RADIOLIB_SI443X_REG_SYNC_WORD_2 0x37 -#define RADIOLIB_SI443X_REG_SYNC_WORD_1 0x38 -#define RADIOLIB_SI443X_REG_SYNC_WORD_0 0x39 -#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_3 0x3A -#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_2 0x3B -#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_1 0x3C -#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_0 0x3D -#define RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E -#define RADIOLIB_SI443X_REG_CHECK_HEADER_3 0x3F -#define RADIOLIB_SI443X_REG_CHECK_HEADER_2 0x40 -#define RADIOLIB_SI443X_REG_CHECK_HEADER_1 0x41 -#define RADIOLIB_SI443X_REG_CHECK_HEADER_0 0x42 -#define RADIOLIB_SI443X_REG_HEADER_ENABLE_3 0x43 -#define RADIOLIB_SI443X_REG_HEADER_ENABLE_2 0x44 -#define RADIOLIB_SI443X_REG_HEADER_ENABLE_1 0x45 -#define RADIOLIB_SI443X_REG_HEADER_ENABLE_0 0x46 -#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_3 0x47 -#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_2 0x48 -#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_1 0x49 -#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_0 0x4A -#define RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B -#define RADIOLIB_SI443X_REG_ADC8_CONTROL 0x4F -#define RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF 0x60 -#define RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST 0x62 -#define RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 0x69 -#define RADIOLIB_SI443X_REG_TX_POWER 0x6D -#define RADIOLIB_SI443X_REG_TX_DATA_RATE_1 0x6E -#define RADIOLIB_SI443X_REG_TX_DATA_RATE_0 0x6F -#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 0x70 -#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 0x71 -#define RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION 0x72 -#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 0x73 -#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 0x74 -#define RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT 0x75 -#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76 -#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77 -#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79 -#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A -#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 0x7C -#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 0x7D -#define RADIOLIB_SI443X_REG_RX_FIFO_CONTROL 0x7E -#define RADIOLIB_SI443X_REG_FIFO_ACCESS 0x7F - -// RADIOLIB_SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION -#define RADIOLIB_SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register +#define RADIOLIB_SI443X_REG_DEVICE_TYPE 0x00 +#define RADIOLIB_SI443X_REG_DEVICE_VERSION 0x01 +#define RADIOLIB_SI443X_REG_DEVICE_STATUS 0x02 +#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 0x03 +#define RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 0x04 +#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 0x05 +#define RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 0x06 +#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 0x07 +#define RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 0x08 +#define RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09 +#define RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK 0x0A +#define RADIOLIB_SI443X_REG_GPIO0_CONFIG 0x0B +#define RADIOLIB_SI443X_REG_GPIO1_CONFIG 0x0C +#define RADIOLIB_SI443X_REG_GPIO2_CONFIG 0x0D +#define RADIOLIB_SI443X_REG_IO_PORT_CONFIG 0x0E +#define RADIOLIB_SI443X_REG_ADC_CONFIG 0x0F +#define RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10 +#define RADIOLIB_SI443X_REG_ADC_VALUE 0x11 +#define RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL 0x12 +#define RADIOLIB_SI443X_REG_TEMP_VALUE_OFFSET 0x13 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17 +#define RADIOLIB_SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18 +#define RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION 0x19 +#define RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A +#define RADIOLIB_SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B +#define RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH 0x1C +#define RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D +#define RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL 0x1E +#define RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F +#define RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 0x21 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 0x22 +#define RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 0x23 +#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24 +#define RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25 +#define RADIOLIB_SI443X_REG_RSSI 0x26 +#define RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27 +#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_1 0x28 +#define RADIOLIB_SI443X_REG_ANTENNA_DIVERSITY_2 0x29 +#define RADIOLIB_SI443X_REG_AFC_LIMITER 0x2A +#define RADIOLIB_SI443X_REG_AFC_CORRECTION 0x2B +#define RADIOLIB_SI443X_REG_OOK_COUNTER_1 0x2C +#define RADIOLIB_SI443X_REG_OOK_COUNTER_2 0x2D +#define RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD 0x2E +#define RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL 0x30 +#define RADIOLIB_SI443X_REG_EZMAC_STATUS 0x31 +#define RADIOLIB_SI443X_REG_HEADER_CONTROL_1 0x32 +#define RADIOLIB_SI443X_REG_HEADER_CONTROL_2 0x33 +#define RADIOLIB_SI443X_REG_PREAMBLE_LENGTH 0x34 +#define RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL 0x35 +#define RADIOLIB_SI443X_REG_SYNC_WORD_3 0x36 +#define RADIOLIB_SI443X_REG_SYNC_WORD_2 0x37 +#define RADIOLIB_SI443X_REG_SYNC_WORD_1 0x38 +#define RADIOLIB_SI443X_REG_SYNC_WORD_0 0x39 +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_3 0x3A +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_2 0x3B +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_1 0x3C +#define RADIOLIB_SI443X_REG_TRANSMIT_HEADER_0 0x3D +#define RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E +#define RADIOLIB_SI443X_REG_CHECK_HEADER_3 0x3F +#define RADIOLIB_SI443X_REG_CHECK_HEADER_2 0x40 +#define RADIOLIB_SI443X_REG_CHECK_HEADER_1 0x41 +#define RADIOLIB_SI443X_REG_CHECK_HEADER_0 0x42 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_3 0x43 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_2 0x44 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_1 0x45 +#define RADIOLIB_SI443X_REG_HEADER_ENABLE_0 0x46 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_3 0x47 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_2 0x48 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_1 0x49 +#define RADIOLIB_SI443X_REG_RECEIVED_HEADER_0 0x4A +#define RADIOLIB_SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B +#define RADIOLIB_SI443X_REG_ADC8_CONTROL 0x4F +#define RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF 0x60 +#define RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST 0x62 +#define RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 0x69 +#define RADIOLIB_SI443X_REG_TX_POWER 0x6D +#define RADIOLIB_SI443X_REG_TX_DATA_RATE_1 0x6E +#define RADIOLIB_SI443X_REG_TX_DATA_RATE_0 0x6F +#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 0x70 +#define RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 0x71 +#define RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION 0x72 +#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 0x73 +#define RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 0x74 +#define RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT 0x75 +#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76 +#define RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77 +#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79 +#define RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A +#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 0x7C +#define RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 0x7D +#define RADIOLIB_SI443X_REG_RX_FIFO_CONTROL 0x7E +#define RADIOLIB_SI443X_REG_FIFO_ACCESS 0x7F + +// RADIOLIB_SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION +#define RADIOLIB_SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register // RADIOLIB_SI443X_REG_DEVICE_VERSION -#define RADIOLIB_SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register +#define RADIOLIB_SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register // RADIOLIB_SI443X_REG_DEVICE_STATUS -#define RADIOLIB_SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag -#define RADIOLIB_SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag -#define RADIOLIB_SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag -#define RADIOLIB_SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag -#define RADIOLIB_SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range) -#define RADIOLIB_SI443X_TX 0b00000010 // 1 0 power state: Tx -#define RADIOLIB_SI443X_RX 0b00000001 // 1 0 Rx -#define RADIOLIB_SI443X_IDLE 0b00000000 // 1 0 idle +#define RADIOLIB_SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag +#define RADIOLIB_SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag +#define RADIOLIB_SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag +#define RADIOLIB_SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag +#define RADIOLIB_SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range) +#define RADIOLIB_SI443X_TX 0b00000010 // 1 0 power state: Tx +#define RADIOLIB_SI443X_RX 0b00000001 // 1 0 Rx +#define RADIOLIB_SI443X_IDLE 0b00000000 // 1 0 idle // RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 -#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty -#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full -#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx -#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done -#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received -#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full +#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx +#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received +#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed // RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 -#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected -#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected -#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected -#define RADIOLIB_SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold -#define RADIOLIB_SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired -#define RADIOLIB_SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected -#define RADIOLIB_SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected -#define RADIOLIB_SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected +#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected +#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected +#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected +#define RADIOLIB_SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold +#define RADIOLIB_SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired +#define RADIOLIB_SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected +#define RADIOLIB_SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected +#define RADIOLIB_SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected // RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1 -#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled -#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled -#define RADIOLIB_SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled -#define RADIOLIB_SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled -#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled -#define RADIOLIB_SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled +#define RADIOLIB_SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled +#define RADIOLIB_SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled +#define RADIOLIB_SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled // RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 -#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled -#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled -#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled -#define RADIOLIB_SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled -#define RADIOLIB_SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled -#define RADIOLIB_SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled -#define RADIOLIB_SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled -#define RADIOLIB_SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled +#define RADIOLIB_SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled +#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled +#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled +#define RADIOLIB_SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled +#define RADIOLIB_SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled +#define RADIOLIB_SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled +#define RADIOLIB_SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled +#define RADIOLIB_SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled // RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1 -#define RADIOLIB_SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values -#define RADIOLIB_SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection -#define RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer -#define RADIOLIB_SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default) -#define RADIOLIB_SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator -#define RADIOLIB_SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode -#define RADIOLIB_SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode -#define RADIOLIB_SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode) -#define RADIOLIB_SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode) -#define RADIOLIB_SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode) +#define RADIOLIB_SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values +#define RADIOLIB_SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection +#define RADIOLIB_SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer +#define RADIOLIB_SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default) +#define RADIOLIB_SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator +#define RADIOLIB_SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode +#define RADIOLIB_SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode +#define RADIOLIB_SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode) +#define RADIOLIB_SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode) +#define RADIOLIB_SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode) // RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2 -#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default) -#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low -#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high -#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high -#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low -#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high -#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low -#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high -#define RADIOLIB_SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default) -#define RADIOLIB_SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default) -#define RADIOLIB_SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default) -#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first) -#define RADIOLIB_SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second) -#define RADIOLIB_SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first) -#define RADIOLIB_SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second) +#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default) +#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low +#define RADIOLIB_SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high +#define RADIOLIB_SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default) +#define RADIOLIB_SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default) +#define RADIOLIB_SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default) +#define RADIOLIB_SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first) +#define RADIOLIB_SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second) +#define RADIOLIB_SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first) +#define RADIOLIB_SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second) // RADIOLIB_SI443X_REG_XOSC_LOAD_CAPACITANCE -#define RADIOLIB_SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration: -#define RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * RADIOLIB_SI443X_XTAL_SHIFT +#define RADIOLIB_SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration: +#define RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * RADIOLIB_SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * RADIOLIB_SI443X_XTAL_SHIFT // RADIOLIB_SI443X_REG_MCU_OUTPUT_CLOCK -#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default) -#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128 -#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256 -#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512 -#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default) -#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz -#define RADIOLIB_SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz -#define RADIOLIB_SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz -#define RADIOLIB_SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz -#define RADIOLIB_SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz -#define RADIOLIB_SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz -#define RADIOLIB_SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default) -#define RADIOLIB_SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default) +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128 +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256 +#define RADIOLIB_SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512 +#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default) +#define RADIOLIB_SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz +#define RADIOLIB_SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default) +#define RADIOLIB_SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz // RADIOLIB_SI443X_REG_GPIO0_CONFIG + RADIOLIB_SI443X_REG_GPIO1_CONFIG + RADIOLIB_SI443X_REG_GPIO2_CONFIG -#define RADIOLIB_SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive) -#define RADIOLIB_SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default) -#define RADIOLIB_SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default) -#define RADIOLIB_SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default) -#define RADIOLIB_SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default) -#define RADIOLIB_SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output -#define RADIOLIB_SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output -#define RADIOLIB_SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output -#define RADIOLIB_SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge -#define RADIOLIB_SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge -#define RADIOLIB_SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change -#define RADIOLIB_SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input -#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input -#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input -#define RADIOLIB_SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input -#define RADIOLIB_SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output -#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output -#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output -#define RADIOLIB_SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output -#define RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode -#define RADIOLIB_SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode -#define RADIOLIB_SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input -#define RADIOLIB_SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output -#define RADIOLIB_SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output -#define RADIOLIB_SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output -#define RADIOLIB_SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output -#define RADIOLIB_SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output -#define RADIOLIB_SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1 -#define RADIOLIB_SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2 -#define RADIOLIB_SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output -#define RADIOLIB_SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output -#define RADIOLIB_SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output -#define RADIOLIB_SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output -#define RADIOLIB_SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD -#define RADIOLIB_SI443X_GPIOX_GND 0b00011110 // 4 0 GND +#define RADIOLIB_SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive) +#define RADIOLIB_SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default) +#define RADIOLIB_SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default) +#define RADIOLIB_SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default) +#define RADIOLIB_SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default) +#define RADIOLIB_SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output +#define RADIOLIB_SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output +#define RADIOLIB_SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output +#define RADIOLIB_SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge +#define RADIOLIB_SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge +#define RADIOLIB_SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change +#define RADIOLIB_SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input +#define RADIOLIB_SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input +#define RADIOLIB_SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output +#define RADIOLIB_SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output +#define RADIOLIB_SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output +#define RADIOLIB_SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode +#define RADIOLIB_SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode +#define RADIOLIB_SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input +#define RADIOLIB_SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output +#define RADIOLIB_SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output +#define RADIOLIB_SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output +#define RADIOLIB_SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output +#define RADIOLIB_SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output +#define RADIOLIB_SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1 +#define RADIOLIB_SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2 +#define RADIOLIB_SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output +#define RADIOLIB_SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output +#define RADIOLIB_SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output +#define RADIOLIB_SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output +#define RADIOLIB_SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD +#define RADIOLIB_SI443X_GPIOX_GND 0b00011110 // 4 0 GND // RADIOLIB_SI443X_REG_IO_PORT_CONFIG -#define RADIOLIB_SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2 -#define RADIOLIB_SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1 -#define RADIOLIB_SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0 -#define RADIOLIB_SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default) -#define RADIOLIB_SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2 -#define RADIOLIB_SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1 -#define RADIOLIB_SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0 +#define RADIOLIB_SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2 +#define RADIOLIB_SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1 +#define RADIOLIB_SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0 +#define RADIOLIB_SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default) +#define RADIOLIB_SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2 +#define RADIOLIB_SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1 +#define RADIOLIB_SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0 // RADIOLIB_SI443X_REG_ADC_CONFIG -#define RADIOLIB_SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement -#define RADIOLIB_SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress -#define RADIOLIB_SI443X_ADC_DONE 0b10000000 // 7 7 done -#define RADIOLIB_SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default) -#define RADIOLIB_SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0 -#define RADIOLIB_SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1 -#define RADIOLIB_SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2 -#define RADIOLIB_SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-) -#define RADIOLIB_SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-) -#define RADIOLIB_SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-) -#define RADIOLIB_SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND -#define RADIOLIB_SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default) -#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3 -#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2 -#define RADIOLIB_SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain +#define RADIOLIB_SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement +#define RADIOLIB_SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress +#define RADIOLIB_SI443X_ADC_DONE 0b10000000 // 7 7 done +#define RADIOLIB_SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2 +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-) +#define RADIOLIB_SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND +#define RADIOLIB_SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default) +#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3 +#define RADIOLIB_SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2 +#define RADIOLIB_SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain // RADIOLIB_SI443X_REG_ADC_SENSOR_AMP_OFFSET -#define RADIOLIB_SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset +#define RADIOLIB_SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset // RADIOLIB_SI443X_REG_TEMP_SENSOR_CONTROL -#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default) -#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution -#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution -#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution -#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled -#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default) -#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default) -#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution +#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled +#define RADIOLIB_SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default) +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value // RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_1 -#define RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent +#define RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent // RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_2 + RADIOLIB_SI443X_REG_WAKEUP_TIMER_PERIOD_3 -#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value: -#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms +#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value: +#define RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * RADIOLIB_SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms // RADIOLIB_SI443X_REG_LOW_DC_MODE_DURATION -#define RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms +#define RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * RADIOLIB_SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ RADIOLIB_SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms // RADIOLIB_SI443X_REG_LOW_BATT_DET_THRESHOLD -#define RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V) +#define RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + RADIOLIB_SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V) // RADIOLIB_SI443X_REG_IF_FILTER_BANDWIDTH -#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default) -#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled -#define RADIOLIB_SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate -#define RADIOLIB_SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection +#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default) +#define RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate +#define RADIOLIB_SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection // RADIOLIB_SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE -#define RADIOLIB_SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default) -#define RADIOLIB_SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled -#define RADIOLIB_SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled -#define RADIOLIB_SI443X_AFC_ON 0b01000000 // 6 6 enabled (default) -#define RADIOLIB_SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting -#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default) -#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB -#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb -#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default) -#define RADIOLIB_SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default) -#define RADIOLIB_SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases +#define RADIOLIB_SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default) +#define RADIOLIB_SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled +#define RADIOLIB_SI443X_AFC_ON 0b01000000 // 6 6 enabled (default) +#define RADIOLIB_SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting +#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default) +#define RADIOLIB_SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB +#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb +#define RADIOLIB_SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default) +#define RADIOLIB_SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default) +#define RADIOLIB_SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases // RADIOLIB_SI443X_REG_AFC_TIMING_CONTROL -#define RADIOLIB_SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching -#define RADIOLIB_SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction -#define RADIOLIB_SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time +#define RADIOLIB_SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching +#define RADIOLIB_SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction +#define RADIOLIB_SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time // RADIOLIB_SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE -#define RADIOLIB_SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value -#define RADIOLIB_SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value +#define RADIOLIB_SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value +#define RADIOLIB_SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value // RADIOLIB_SI443X_REG_CLOCK_REC_OVERSAMP_RATIO -#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit +#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit // RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2 -#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit -#define RADIOLIB_SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold -#define RADIOLIB_SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB +#define RADIOLIB_SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit +#define RADIOLIB_SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold +#define RADIOLIB_SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB // RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_1 -#define RADIOLIB_SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID +#define RADIOLIB_SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID // RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_0 -#define RADIOLIB_SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB +#define RADIOLIB_SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB // RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 -#define RADIOLIB_SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default) -#define RADIOLIB_SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default) -#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB +#define RADIOLIB_SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default) +#define RADIOLIB_SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default) +#define RADIOLIB_SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB // RADIOLIB_SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 -#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB +#define RADIOLIB_SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB // RADIOLIB_SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD -#define RADIOLIB_SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold +#define RADIOLIB_SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold // RADIOLIB_SI443X_REG_AFC_LIMITER -#define RADIOLIB_SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value +#define RADIOLIB_SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value // RADIOLIB_SI443X_REG_OOK_COUNTER_1 -#define RADIOLIB_SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default) -#define RADIOLIB_SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled -#define RADIOLIB_SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default) -#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled -#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default) -#define RADIOLIB_SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB +#define RADIOLIB_SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default) +#define RADIOLIB_SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled +#define RADIOLIB_SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default) +#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled +#define RADIOLIB_SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB // RADIOLIB_SI443X_REG_OOK_COUNTER_2 -#define RADIOLIB_SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB +#define RADIOLIB_SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB // RADIOLIB_SI443X_REG_SLICER_PEAK_HOLD -#define RADIOLIB_SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time -#define RADIOLIB_SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time +#define RADIOLIB_SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time +#define RADIOLIB_SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time // RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL -#define RADIOLIB_SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled -#define RADIOLIB_SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default) -#define RADIOLIB_SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default) -#define RADIOLIB_SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled -#define RADIOLIB_SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default) -#define RADIOLIB_SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default) -#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled -#define RADIOLIB_SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default) -#define RADIOLIB_SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled -#define RADIOLIB_SI443X_CRC_ON 0b00000100 // 2 2 enabled (default) -#define RADIOLIB_SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT -#define RADIOLIB_SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default) -#define RADIOLIB_SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16 -#define RADIOLIB_SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva +#define RADIOLIB_SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled +#define RADIOLIB_SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default) +#define RADIOLIB_SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default) +#define RADIOLIB_SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default) +#define RADIOLIB_SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default) +#define RADIOLIB_SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled +#define RADIOLIB_SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled +#define RADIOLIB_SI443X_CRC_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT +#define RADIOLIB_SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default) +#define RADIOLIB_SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16 +#define RADIOLIB_SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva // RADIOLIB_SI443X_REG_EZMAC_STATUS -#define RADIOLIB_SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones -#define RADIOLIB_SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet -#define RADIOLIB_SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet -#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received -#define RADIOLIB_SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed -#define RADIOLIB_SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet -#define RADIOLIB_SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent +#define RADIOLIB_SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones +#define RADIOLIB_SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet +#define RADIOLIB_SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received +#define RADIOLIB_SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed +#define RADIOLIB_SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet +#define RADIOLIB_SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent // RADIOLIB_SI443X_REG_HEADER_CONTROL_1 -#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default) -#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0 -#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1 -#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2 -#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3 -#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none -#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0 -#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1 -#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default) -#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default) +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default) +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2 +#define RADIOLIB_SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1 +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default) +#define RADIOLIB_SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default) // RADIOLIB_SI443X_REG_HEADER_CONTROL_2 -#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default) -#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled -#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none -#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3 -#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2 -#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default) -#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0 -#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default) -#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3 -#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default) -#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1 -#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0 -#define RADIOLIB_SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB +#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default) +#define RADIOLIB_SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3 +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2 +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default) +#define RADIOLIB_SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0 +#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default) +#define RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3 +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default) +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1 +#define RADIOLIB_SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0 +#define RADIOLIB_SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB // RADIOLIB_SI443X_REG_PREAMBLE_LENGTH -#define RADIOLIB_SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits +#define RADIOLIB_SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits // RADIOLIB_SI443X_REG_PREAMBLE_DET_CONTROL -#define RADIOLIB_SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits -#define RADIOLIB_SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB +#define RADIOLIB_SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits +#define RADIOLIB_SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB // RADIOLIB_SI443X_REG_SYNC_WORD_3 - RADIOLIB_SI443X_REG_SYNC_WORD_0 -#define RADIOLIB_SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB) -#define RADIOLIB_SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte -#define RADIOLIB_SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte -#define RADIOLIB_SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB) +#define RADIOLIB_SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB) +#define RADIOLIB_SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte +#define RADIOLIB_SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte +#define RADIOLIB_SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB) // RADIOLIB_SI443X_REG_CHANNEL_FILTER_COEFF -#define RADIOLIB_SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles +#define RADIOLIB_SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles // RADIOLIB_SI443X_REG_XOSC_CONTROL_TEST -#define RADIOLIB_SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power -#define RADIOLIB_SI443X_STATE_READY 0b00100000 // 7 5 ready -#define RADIOLIB_SI443X_STATE_TUNE 0b01100000 // 7 5 tune -#define RADIOLIB_SI443X_STATE_TX 0b01000000 // 7 5 Tx -#define RADIOLIB_SI443X_STATE_RX 0b11100000 // 7 5 Rx +#define RADIOLIB_SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power +#define RADIOLIB_SI443X_STATE_READY 0b00100000 // 7 5 ready +#define RADIOLIB_SI443X_STATE_TUNE 0b01100000 // 7 5 tune +#define RADIOLIB_SI443X_STATE_TX 0b01000000 // 7 5 Tx +#define RADIOLIB_SI443X_STATE_RX 0b11100000 // 7 5 Rx // RADIOLIB_SI443X_REG_AGC_OVERRIDE_1 -#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default) -#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled -#define RADIOLIB_SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled -#define RADIOLIB_SI443X_AGC_ON 0b00100000 // 5 5 enabled (default) -#define RADIOLIB_SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default) -#define RADIOLIB_SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB -#define RADIOLIB_SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = RADIOLIB_SI443X_PGA_GAIN_OVERRIDE * 3 dB +#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default) +#define RADIOLIB_SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled +#define RADIOLIB_SI443X_AGC_ON 0b00100000 // 5 5 enabled (default) +#define RADIOLIB_SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default) +#define RADIOLIB_SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB +#define RADIOLIB_SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = RADIOLIB_SI443X_PGA_GAIN_OVERRIDE * 3 dB // RADIOLIB_SI443X_REG_TX_POWER -#define RADIOLIB_SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled -#define RADIOLIB_SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default) -#define RADIOLIB_SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max +#define RADIOLIB_SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled +#define RADIOLIB_SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default) +#define RADIOLIB_SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max // RADIOLIB_SI443X_REG_TX_DATA_RATE_1 + RADIOLIB_SI443X_REG_TX_DATA_RATE_0 -#define RADIOLIB_SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^16) in high data rate mode or -#define RADIOLIB_SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps) +#define RADIOLIB_SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^16) in high data rate mode or +#define RADIOLIB_SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (RADIOLIB_SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps) // RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1 -#define RADIOLIB_SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default) -#define RADIOLIB_SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps -#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default) -#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low -#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default) -#define RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled -#define RADIOLIB_SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default) -#define RADIOLIB_SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default) -#define RADIOLIB_SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default) -#define RADIOLIB_SI443X_WHITENING_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default) +#define RADIOLIB_SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps +#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default) +#define RADIOLIB_SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low +#define RADIOLIB_SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default) +#define RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled +#define RADIOLIB_SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default) +#define RADIOLIB_SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default) +#define RADIOLIB_SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default) +#define RADIOLIB_SI443X_WHITENING_ON 0b00000001 // 0 0 enabled // RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2 -#define RADIOLIB_SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default) -#define RADIOLIB_SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin -#define RADIOLIB_SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin -#define RADIOLIB_SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin -#define RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default) -#define RADIOLIB_SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin -#define RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO -#define RADIOLIB_SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal -#define RADIOLIB_SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default) -#define RADIOLIB_SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB -#define RADIOLIB_SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default) -#define RADIOLIB_SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK -#define RADIOLIB_SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK -#define RADIOLIB_SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK +#define RADIOLIB_SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default) +#define RADIOLIB_SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin +#define RADIOLIB_SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin +#define RADIOLIB_SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin +#define RADIOLIB_SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default) +#define RADIOLIB_SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin +#define RADIOLIB_SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO +#define RADIOLIB_SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal +#define RADIOLIB_SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default) +#define RADIOLIB_SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB +#define RADIOLIB_SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default) +#define RADIOLIB_SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK +#define RADIOLIB_SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK +#define RADIOLIB_SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK // RADIOLIB_SI443X_REG_FREQUENCY_DEVIATION -#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * RADIOLIB_SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz +#define RADIOLIB_SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * RADIOLIB_SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz // RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_1 + RADIOLIB_SI443X_REG_FREQUENCY_OFFSET_2 -#define RADIOLIB_SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset: -#define RADIOLIB_SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (RADIOLIB_SI443X_BAND_SELECT + 1) * RADIOLIB_SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz +#define RADIOLIB_SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset: +#define RADIOLIB_SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (RADIOLIB_SI443X_BAND_SELECT + 1) * RADIOLIB_SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz // RADIOLIB_SI443X_REG_FREQUENCY_BAND_SELECT -#define RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default) -#define RADIOLIB_SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency -#define RADIOLIB_SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz -#define RADIOLIB_SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default) -#define RADIOLIB_SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select +#define RADIOLIB_SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default) +#define RADIOLIB_SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency +#define RADIOLIB_SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz +#define RADIOLIB_SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default) +#define RADIOLIB_SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select // RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_1 + RADIOLIB_SI443X_REG_NOM_CARRIER_FREQUENCY_0 -#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency: -#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (RADIOLIB_SI443X_BAND_SELECT + 1)*10*(RADIOLIB_SI443X_FREQUENCY_BAND_SELECT + 24) + (RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY - RADIOLIB_SI443X_FREQUENCY_OFFSET)/6400 [MHz] +#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency: +#define RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (RADIOLIB_SI443X_BAND_SELECT + 1)*10*(RADIOLIB_SI443X_FREQUENCY_BAND_SELECT + 24) + (RADIOLIB_SI443X_NOM_CARRIER_FREQUENCY - RADIOLIB_SI443X_FREQUENCY_OFFSET)/6400 [MHz] // RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL -#define RADIOLIB_SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number +#define RADIOLIB_SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number // RADIOLIB_SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE -#define RADIOLIB_SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size +#define RADIOLIB_SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size // RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_1 -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold // RADIOLIB_SI443X_REG_TX_FIFO_CONTROL_2 -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold // RADIOLIB_SI443X_REG_RX_FIFO_CONTROL -#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold /*! \class Si443x - \brief Base class for Si443x series. All derived classes for Si443x (e.g. Si4431 or Si4432) inherit from this base class. This class should not be instantiated directly from Arduino sketch, only from its derived classes. */ @@ -563,7 +562,6 @@ class Si443x: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ Si443x(Module* mod); @@ -574,15 +572,10 @@ class Si443x: public PhysicalLayer { /*! \brief Initialization method. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). - \param freqDev Frequency deviation of the FSK transmission in kHz. - \param rxBw Receiver bandwidth in kHz. - \param preambleLen Preamble Length in bits. - \returns \ref status_codes */ int16_t begin(float br, float freqDev, float rxBw, uint8_t preambleLen); @@ -595,13 +588,9 @@ class Si443x: public PhysicalLayer { /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 64 bytes long. For overloads to transmit Arduino String or C-string, see PhysicalLayer::transmit. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; @@ -609,11 +598,8 @@ class Si443x: public PhysicalLayer { /*! \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long. For overloads to receive Arduino String, see PhysicalLayer::receive. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; @@ -621,46 +607,38 @@ class Si443x: public PhysicalLayer { /*! \brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. %Module will wake up automatically when methods like transmit or receive are called. - \returns \ref status_codes */ int16_t sleep(); /*! \brief Sets the module to standby (with XTAL on). - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the module to standby. - \param mode Standby mode to be used. - \returns \ref status_codes */ int16_t standby(uint8_t mode) override; /*! \brief Enables direct transmission mode. While in direct mode, the module will not be able to transmit or receive packets. - - \param FRF 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. - + \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Enables direct reception mode. While in direct mode, the module will not be able to transmit or receive packets. - \returns \ref status_codes */ int16_t receiveDirect() override; /*! \brief Disables direct mode and enables packet mode, allowing the module to receive packets. - \returns \ref status_codes */ int16_t packetMode(); @@ -669,7 +647,6 @@ class Si443x: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when IRQ activates. - \param func ISR to call. */ void setIrqAction(void (*func)(void)); @@ -681,54 +658,40 @@ class Si443x: public PhysicalLayer { /*! \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 64 bytes long. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received. - \returns \ref status_codes */ int16_t startReceive(); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param timeout Ignored. - \param irqFlags Ignored. - \param irqMask Ignored. - \param len Ignored. - \returns \ref status_codes */ int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; @@ -737,54 +700,42 @@ class Si443x: public PhysicalLayer { /*! \brief Sets FSK bit rate. Allowed values range from 0.123 to 256.0 kbps. - \param br Bit rate to be set (in kbps). - \returns \ref status_codes */ int16_t setBitRate(float br); /*! \brief Sets FSK frequency deviation from carrier frequency. Allowed values range from 0.625 to 320.0 kHz. - \param freqDev Frequency deviation to be set (in kHz). - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets receiver bandwidth. Allowed values range from 2.6 to 620.7 kHz. - \param rxBw Receiver bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setRxBandwidth(float rxBw); /*! \brief Sets sync word. Up to 4 bytes can be set as sync word. - \param syncWord Pointer to the array of sync word bytes. - \param len Sync word length in bytes. */ int16_t setSyncWord(uint8_t* syncWord, size_t len); /*! \brief Sets preamble length. - \param preambleLen Preamble length to be set (in bits). - \returns \ref status_codes */ int16_t setPreambleLength(uint8_t preambleLen); /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; @@ -792,9 +743,7 @@ class Si443x: public PhysicalLayer { /*! \brief Sets transmission encoding. Only available in FSK mode. Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. - \param encoding Encoding to be used. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; @@ -802,9 +751,7 @@ class Si443x: public PhysicalLayer { /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. Allowed values are RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Gaussian shaping bandwidth-time product that will be used for data shaping - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; @@ -817,14 +764,12 @@ class Si443x: public PhysicalLayer { /*! \brief Get one truly random byte from RSSI noise. - \returns TRNG byte. */ uint8_t randomByte(); /*! \brief Read version SPI register. Should return RADIOLIB_SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working. - \returns Version register contents or \ref status_codes */ int16_t getChipVersion(); @@ -832,14 +777,12 @@ class Si443x: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. - \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. - \param pin Pin on which to read. */ void readBit(uint32_t pin); @@ -847,18 +790,14 @@ class Si443x: public PhysicalLayer { /*! \brief Set modem in fixed packet length mode. - \param len Packet length. - \returns \ref status_codes */ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH); /*! \brief Set modem in variable packet length mode. - - \param len Maximum packet length. - + \param maxLen Maximum packet length. \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); @@ -866,19 +805,19 @@ class Si443x: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; #if !defined(RADIOLIB_GODMODE) protected: #endif - float _br = 0; - float _freqDev = 0; - float _freq = 0; + float bitRate = 0; + float frequencyDev = 0; + float frequency = 0; - size_t _packetLength = 0; - bool _packetLengthQueried = false; - uint8_t _packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; + size_t packetLength = 0; + bool packetLengthQueried = false; + uint8_t packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; int16_t setFrequencyRaw(float newFreq); int16_t setPacketMode(uint8_t mode, uint8_t len); From c5a3c4d3612d4c9b7b147b777b56add40c5b886e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:02:33 +0200 Subject: [PATCH 0517/1848] [nRF24] Fixed variable shadowing --- src/modules/nRF24/nRF24.cpp | 7 +++---- src/modules/nRF24/nRF24.h | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 39baa96277..62cb2c2d69 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -304,14 +304,14 @@ int16_t nRF24::setBitRate(float br) { return(state); } -int16_t nRF24::setOutputPower(int8_t power) { +int16_t nRF24::setOutputPower(int8_t pwr) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); // check allowed values uint8_t powerRaw = 0; - switch(power) { + switch(pwr) { case -18: powerRaw = RADIOLIB_NRF24_RF_PWR_18_DBM; break; @@ -332,10 +332,9 @@ int16_t nRF24::setOutputPower(int8_t power) { state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, powerRaw, 2, 1); if(state == RADIOLIB_ERR_NONE) { - this->power = power; + this->power = pwr; } - return(state); } diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index afd68b1112..e94a742165 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -330,10 +330,10 @@ class nRF24: public PhysicalLayer { /*! \brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm. - \param power Output power to be set in dBm. + \param pwr Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t pwr); /*! \brief Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes. From bda6e220b6fcb39fca94eb1637bbf1721125d60e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:03:12 +0200 Subject: [PATCH 0518/1848] [CC1101] Fixed variable shadowing --- src/modules/CC1101/CC1101.cpp | 10 +++++----- src/modules/CC1101/CC1101.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index d12251bd8a..f392a4cc65 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -10,7 +10,7 @@ Module* CC1101::getMod() { return(this->mod); } -int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLength) { +int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { // set module properties this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; this->mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; @@ -60,7 +60,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // configure default TX output power - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); // set default packet length mode @@ -598,7 +598,7 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { return(RADIOLIB_ERR_NONE); } -int16_t CC1101::setOutputPower(int8_t power) { +int16_t CC1101::setOutputPower(int8_t pwr) { // round to the known frequency settings uint8_t f; if(this->frequency < 374.0) { @@ -626,7 +626,7 @@ int16_t CC1101::setOutputPower(int8_t power) { {0xC2, 0xC0, 0xC2, 0xC0}}; uint8_t powerRaw; - switch(power) { + switch(pwr) { case -30: powerRaw = paTable[0][f]; break; @@ -656,7 +656,7 @@ int16_t CC1101::setOutputPower(int8_t power) { } // store the value - this->power = power; + this->power = pwr; if(this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ // Amplitude modulation: diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 7654173b56..8dbf4326ac 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -552,7 +552,7 @@ class CC1101: public PhysicalLayer { \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz. - \param power Output power in dBm. Defaults to 10 dBm. + \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ @@ -561,7 +561,7 @@ class CC1101: public PhysicalLayer { float br = RADIOLIB_CC1101_DEFAULT_BR, float freqDev = RADIOLIB_CC1101_DEFAULT_FREQDEV, float rxBw = RADIOLIB_CC1101_DEFAULT_RXBW, - int8_t power = RADIOLIB_CC1101_DEFAULT_POWER, + int8_t pwr = RADIOLIB_CC1101_DEFAULT_POWER, uint8_t preambleLength = RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); /*! @@ -740,10 +740,10 @@ class CC1101: public PhysicalLayer { /*! \brief Sets output power. Allowed values are -30, -20, -15, -10, 0, 5, 7 or 10 dBm. - \param power Output power to be set in dBm. + \param pwr Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t pwr); /*! \brief Sets 16-bit sync word as a two byte value. From 8a878e8fe96f00d6dac2888cfe79bff9acb69f06 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:03:28 +0200 Subject: [PATCH 0519/1848] [LLCC68] Fixed variable shadowing --- src/modules/LLCC68/LLCC68.cpp | 4 ++-- src/modules/LLCC68/LLCC68.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 1a087c4039..47c8b60919 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -5,7 +5,7 @@ LLCC68::LLCC68(Module* mod) : SX1262(mod) { chipType = RADIOLIB_LLCC68_CHIP_TYPE; } -int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { +int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); @@ -20,7 +20,7 @@ int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setSpreadingFactor(sf); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); state = SX126x::fixPaClamping(); diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index d735aab185..b76f23ff79 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -30,13 +30,13 @@ class LLCC68: public SX1262 { \param sf LoRa spreading factor. Defaults to 9. \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). - \param power Output power in dBm. Defaults to 10 dBm. + \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods From 14529f36c7e0e90c92a82ebfdcf4400d0ef05623 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:03:37 +0200 Subject: [PATCH 0520/1848] [RF69] Fixed variable shadowing --- src/modules/RF69/RF69.cpp | 4 ++-- src/modules/RF69/RF69.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 5bef0a2f14..e06b107779 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -10,7 +10,7 @@ Module* RF69::getMod() { return(this->mod); } -int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { +int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLen) { // set module properties this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -63,7 +63,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_ASSERT(state); // configure default TX output power - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); // configure default preamble length diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 018e0ecc15..95b0677ab0 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -500,7 +500,7 @@ class RF69: public PhysicalLayer { \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. - \param power Output power in dBm. Defaults to 10 dBm. + \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ @@ -509,7 +509,7 @@ class RF69: public PhysicalLayer { float br = RADIOLIB_RF69_DEFAULT_BR, float freqDev = RADIOLIB_RF69_DEFAULT_FREQDEV, float rxBw = RADIOLIB_RF69_DEFAULT_RXBW, - int8_t power = RADIOLIB_RF69_DEFAULT_POWER, + int8_t pwr = RADIOLIB_RF69_DEFAULT_POWER, uint8_t preambleLen = RADIOLIB_RF69_DEFAULT_PREAMBLELEN); /*! From d4365a3b1ec38edc059064967c57614b1320738c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:04:40 +0200 Subject: [PATCH 0521/1848] [SX126x] Fixed variable shadowing --- src/modules/SX126x/SX126x.cpp | 8 ++++---- src/modules/SX126x/SX126x.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f9c90dc185..077b967566 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1724,8 +1724,8 @@ uint8_t SX126x::getPacketType() { return(data); } -int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) { - uint8_t data[] = { power, rampTime }; +int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) { + uint8_t data[] = { pwr, rampTime }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); } @@ -1780,9 +1780,9 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); } -int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { +int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), - pulseShape, rxBw, + sh, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 15cddbe7ac..01981ffac5 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1027,7 +1027,7 @@ class SX126x: public PhysicalLayer { uint8_t getPacketType(); int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); - int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); + int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev); int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ); int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF, uint8_t preambleDetectorLen = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); From 76c654c0c10b74eb97193e39ae7844776d077499 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:05:18 +0200 Subject: [PATCH 0522/1848] [SX128x] General reformatting --- src/modules/SX128x/SX1280.cpp | 18 +- src/modules/SX128x/SX1280.h | 11 - src/modules/SX128x/SX1281.h | 2 - src/modules/SX128x/SX1282.h | 2 - src/modules/SX128x/SX128x.cpp | 498 ++++++++++----------- src/modules/SX128x/SX128x.h | 793 +++++++++++++++------------------- 6 files changed, 601 insertions(+), 723 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 224d4f8e90..b53c1a62d3 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -12,10 +12,10 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { RADIOLIB_ASSERT(state); // wait until ranging is finished - uint32_t start = _mod->hal->millis(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->millis() - start > 10000) { + uint32_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > 10000) { clearIrqStatus(); standby(); return(RADIOLIB_ERR_RANGING_TIMEOUT); @@ -50,11 +50,11 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] } // set modulation parameters - state = setModulationParams(_sf, _bw, _cr); + state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa); RADIOLIB_ASSERT(state); // set packet parameters - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa); RADIOLIB_ASSERT(state); // check all address bits @@ -100,9 +100,9 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] } // set calibration values - uint8_t index = (_sf >> 4) - 5; + uint8_t index = (this->spreadingFactor >> 4) - 5; uint16_t val = 0; - switch(_bw) { + switch(this->bandwidth) { case(RADIOLIB_SX128X_LORA_BW_406_25): val = calTbl[0][index]; break; @@ -176,7 +176,7 @@ float SX1280::getRangingResult() { // calculate the real result uint32_t raw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; - return((float)raw * 150.0 / (4.096 * _bwKhz)); + return((float)raw * 150.0 / (4.096 * this->bandwidthKhz)); } #endif diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index 10f48ab11c..51bb7c0bb3 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -11,47 +11,36 @@ /*! \class SX1280 - \brief Derived class for %SX1280 modules. */ class SX1280: public SX1281 { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1280(Module* mod); /*! \brief Blocking ranging method. - \param master Whether to execute ranging in master mode (true) or slave mode (false). - \param addr Ranging address to be used. - \param calTable Ranging calibration table - set to NULL to use the default. - \returns \ref status_codes */ int16_t range(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); /*! \brief Interrupt-driven ranging method. - \param master Whether to execute ranging in master mode (true) or slave mode (false). - \param addr Ranging address to be used. - \param calTable Ranging calibration table - set to NULL to use the default. - \returns \ref status_codes */ int16_t startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); /*! \brief Gets ranging result of the last ranging exchange. - \returns Ranging result in meters. */ float getRangingResult(); diff --git a/src/modules/SX128x/SX1281.h b/src/modules/SX128x/SX1281.h index 4482e3c5bb..04a9eb1985 100644 --- a/src/modules/SX128x/SX1281.h +++ b/src/modules/SX128x/SX1281.h @@ -10,14 +10,12 @@ /*! \class SX1281 - \brief Derived class for %SX1281 modules. */ class SX1281: public SX128x { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1281(Module* mod); diff --git a/src/modules/SX128x/SX1282.h b/src/modules/SX128x/SX1282.h index 71feb29a68..864e463d4d 100644 --- a/src/modules/SX128x/SX1282.h +++ b/src/modules/SX128x/SX1282.h @@ -11,14 +11,12 @@ /*! \class SX1282 - \brief Derived class for %SX1282 modules. */ class SX1282: public SX1280 { public: /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX1282(Module* mod); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a16374924b..ffad917fca 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -3,36 +3,36 @@ #if !defined(RADIOLIB_EXCLUDE_SX128X) SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { - _mod = mod; + this->mod = mod; } Module* SX128x::getMod() { - return(_mod); + return(this->mod); } -int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength) { +int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - _mod->SPIstreamType = true; - _mod->SPIparseStatusCb = SPIparseStatus; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize LoRa modulation variables - _bwKhz = bw; - _sf = RADIOLIB_SX128X_LORA_SF_9; - _cr = RADIOLIB_SX128X_LORA_CR_4_7; + this->bandwidthKhz = bw; + this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9; + this->codingRateLoRa = RADIOLIB_SX128X_LORA_CR_4_7; // initialize LoRa packet variables - _preambleLengthLoRa = preambleLength; - _headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT; - _payloadLen = 0xFF; - _crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; + this->preambleLengthLoRa = preambleLength; + this->headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT; + this->payloadLen = 0xFF; + this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; // reset the module and verify startup int16_t state = reset(); @@ -65,38 +65,38 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); return(state); } -int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, uint16_t preambleLength) { +int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, uint16_t preambleLength) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - _mod->SPIstreamType = true; - _mod->SPIparseStatusCb = SPIparseStatus; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize GFSK modulation variables - _brKbps = br; - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; - _modIndexReal = 1.0; - _modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; - _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; + this->bitRateKbps = br; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; + this->modIndexReal = 1.0; + this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; // initialize GFSK packet variables - _preambleLengthGFSK = preambleLength; - _syncWordLen = 2; - _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; - _crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; - _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; + this->preambleLengthGFSK = preambleLength; + this->syncWordLen = 2; + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; // reset the module and verify startup int16_t state = reset(); @@ -120,7 +120,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, state = setFrequencyDeviation(freqDev); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); @@ -140,29 +140,29 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, return(state); } -int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, uint8_t dataShaping) { +int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uint8_t dataShaping) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - _mod->SPIstreamType = true; - _mod->SPIparseStatusCb = SPIparseStatus; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize BLE modulation variables - _brKbps = br; - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; - _modIndexReal = 1.0; - _modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; - _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; + this->bitRateKbps = br; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; + this->modIndexReal = 1.0; + this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; // initialize BLE packet variables - _crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE; - _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; + this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; // reset the module and verify startup int16_t state = reset(); @@ -186,7 +186,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u state = setFrequencyDeviation(freqDev); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); state = setDataShaping(dataShaping); @@ -195,31 +195,31 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u return(state); } -int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, uint8_t dataShaping) { +int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); - _mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - _mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - _mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - _mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - _mod->SPIstreamType = true; - _mod->SPIparseStatusCb = SPIparseStatus; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; + this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->SPIstreamType = true; + this->mod->SPIparseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); // initialize FLRC modulation variables - _brKbps = br; - _br = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; - _crFLRC = RADIOLIB_SX128X_FLRC_CR_3_4; - _shaping = RADIOLIB_SX128X_FLRC_BT_0_5; + this->bitRateKbps = br; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; + this->codingRateFLRC = RADIOLIB_SX128X_FLRC_CR_3_4; + this->shaping = RADIOLIB_SX128X_FLRC_BT_0_5; // initialize FLRC packet variables - _preambleLengthGFSK = preambleLength; - _syncWordLen = 2; - _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; - _crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; - _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; + this->preambleLengthGFSK = preambleLength; + this->syncWordLen = 2; + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; // reset the module and verify startup int16_t state = reset(); @@ -243,7 +243,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin state = setCodingRate(cr); RADIOLIB_ASSERT(state); - state = setOutputPower(power); + state = setOutputPower(pwr); RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); @@ -262,10 +262,10 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin int16_t SX128x::reset(bool verify) { // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); // return immediately when verification is disabled if(!verify) { @@ -273,7 +273,7 @@ int16_t SX128x::reset(bool verify) { } // set mode to standby - uint32_t start = _mod->hal->millis(); + uint32_t start = this->mod->hal->millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -283,13 +283,13 @@ int16_t SX128x::reset(bool verify) { } // standby command failed, check timeout and try again - if(_mod->hal->millis() - start >= 3000) { + if(this->mod->hal->millis() - start >= 3000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - _mod->hal->delay(10); + this->mod->hal->delay(10); } } @@ -319,10 +319,10 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -353,10 +353,10 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { clearIrqStatus(); standby(); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -369,7 +369,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { int16_t SX128x::transmitDirect(uint32_t frf) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) int16_t state = RADIOLIB_ERR_NONE; @@ -379,12 +379,12 @@ int16_t SX128x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); } int16_t SX128x::receiveDirect() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // SX128x is unable to output received data directly return(RADIOLIB_ERR_UNKNOWN); @@ -409,15 +409,15 @@ int16_t SX128x::scanChannel() { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to CAD state = setCad(); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); } // check CAD result @@ -437,16 +437,16 @@ int16_t SX128x::scanChannel() { int16_t SX128x::sleep(bool retainConfig) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN; if(!retainConfig) { sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; } - int16_t state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); // wait for SX128x to safely enter sleep mode - _mod->hal->delay(1); + this->mod->hal->delay(1); return(state); } @@ -457,18 +457,18 @@ int16_t SX128x::standby() { int16_t SX128x::standby(uint8_t mode) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = { mode }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); } void SX128x::setDio1Action(void (*func)(void)) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, _mod->hal->GpioInterruptRising); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); } void SX128x::clearDio1Action() { - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -484,18 +484,18 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa, _invertIQ); + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcLoRa, this->invertIQEnabled); } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { - state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len); + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, len); } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { - state = setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening); + state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); } else { return(RADIOLIB_ERR_WRONG_MODEM); } RADIOLIB_ASSERT(state); // update output power - state = setTxParams(_pwr); + state = setTxParams(this->power); RADIOLIB_ASSERT(state); // set buffer pointers @@ -521,15 +521,15 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // start transmission state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(_mod->hal->digitalRead(_mod->getGpio())) { - _mod->hal->yield(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); } return(state); @@ -568,13 +568,13 @@ int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMa RADIOLIB_ASSERT(state); // set implicit mode and expected len if applicable - if((_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ); + if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); RADIOLIB_ASSERT(state); } // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to receive state = setRx(timeout); @@ -641,20 +641,20 @@ int16_t SX128x::setBandwidth(float bw) { } if(fabs(bw - 203.125) <= 0.001) { - _bw = RADIOLIB_SX128X_LORA_BW_203_125; + this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125; } else if(fabs(bw - 406.25) <= 0.001) { - _bw = RADIOLIB_SX128X_LORA_BW_406_25; + this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25; } else if(fabs(bw - 812.5) <= 0.001) { - _bw = RADIOLIB_SX128X_LORA_BW_812_50; + this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50; } else if(fabs(bw - 1625.0) <= 0.001) { - _bw = RADIOLIB_SX128X_LORA_BW_1625_00; + this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // update modulation parameters - _bwKhz = bw; - return(setModulationParams(_sf, _bw, _cr)); + this->bandwidthKhz = bw; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa)); } int16_t SX128x::setSpreadingFactor(uint8_t sf) { @@ -671,16 +671,16 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) { } // update modulation parameters - _sf = sf << 4; - int16_t state = setModulationParams(_sf, _bw, _cr); + this->spreadingFactor = sf << 4; + int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa); RADIOLIB_ASSERT(state); // update mystery register in LoRa mode - SX1280 datasheet v3.0 section 13.4.1 if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { uint8_t data = 0; - if((_sf == RADIOLIB_SX128X_LORA_SF_5) || (_sf == RADIOLIB_SX128X_LORA_SF_6)) { + if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) { data = 0x1E; - } else if((_sf == RADIOLIB_SX128X_LORA_SF_7) || (_sf == RADIOLIB_SX128X_LORA_SF_8)) { + } else if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_7) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_8)) { data = 0x37; } else { data = 0x32; @@ -701,28 +701,28 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { // update modulation parameters if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { - _cr = cr; + this->codingRateLoRa = cr; } else { - _cr = cr - 4; + this->codingRateLoRa = cr - 4; } - return(setModulationParams(_sf, _bw, _cr)); + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa)); // FLRC } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters - _crFLRC = (cr - 2) * 2; - return(setModulationParams(_br, _crFLRC, _shaping)); + this->codingRateFLRC = (cr - 2) * 2; + return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping)); } return(RADIOLIB_ERR_WRONG_MODEM); } -int16_t SX128x::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - _pwr = power + 18; - return(setTxParams(_pwr)); +int16_t SX128x::setOutputPower(int8_t pwr) { + RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + this->power = pwr + 18; + return(setTxParams(this->power)); } int16_t SX128x::setPreambleLength(uint32_t preambleLength) { @@ -753,8 +753,8 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { } // update packet parameters - _preambleLengthLoRa = (e << 4) | m; - return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ)); + this->preambleLengthLoRa = (e << 4) | m; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { // GFSK or FLRC @@ -766,8 +766,8 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { } // update packet parameters - _preambleLengthGFSK = ((preambleLength / 4) - 1) << 4; - return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); + this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4; + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); } return(RADIOLIB_ERR_WRONG_MODEM); @@ -780,50 +780,50 @@ int16_t SX128x::setBitRate(float br) { // GFSK/BLE if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { if((uint16_t)br == 125) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; } else if((uint16_t)br == 250) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6; } else if((uint16_t)br == 400) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2; } else if((uint16_t)br == 500) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2; } else if((uint16_t)br == 800) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; } else if((uint16_t)br == 1000) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4; } else if((uint16_t)br == 1600) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4; } else if((uint16_t)br == 2000) { - _br = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4; } else { return(RADIOLIB_ERR_INVALID_BIT_RATE); } // update modulation parameters - _brKbps = (uint16_t)br; - return(setModulationParams(_br, _modIndex, _shaping)); + this->bitRateKbps = (uint16_t)br; + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); // FLRC } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) { if((uint16_t)br == 260) { - _br = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3; } else if((uint16_t)br == 325) { - _br = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3; } else if((uint16_t)br == 520) { - _br = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6; } else if((uint16_t)br == 650) { - _br = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; } else if((uint16_t)br == 1000) { - _br = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2; } else if((uint16_t)br == 1300) { - _br = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2; + this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2; } else { return(RADIOLIB_ERR_INVALID_BIT_RATE); } // update modulation parameters - _brKbps = (uint16_t)br; - return(setModulationParams(_br, _crFLRC, _shaping)); + this->bitRateKbps = (uint16_t)br; + return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping)); } @@ -847,20 +847,20 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols if(newFreqDev == 0.0) { - _modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35; - _br = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; - return(setModulationParams(_br, _modIndex, _shaping)); + this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35; + this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); } // update modulation parameters - uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)_brKbps)) - 1.0); + uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0); if(modIndex > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) { return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); } // update modulation parameters - _modIndex = modIndex; - return(setModulationParams(_br, _modIndex, _shaping)); + this->modIndex = modIndex; + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); } int16_t SX128x::setDataShaping(uint8_t sh) { @@ -870,16 +870,16 @@ int16_t SX128x::setDataShaping(uint8_t sh) { return(RADIOLIB_ERR_WRONG_MODEM); } - // set data shaping + // set data this->shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF; break; case RADIOLIB_SHAPING_0_5: - _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5; break; case RADIOLIB_SHAPING_1_0: - _shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0; + this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0; break; default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); @@ -887,9 +887,9 @@ int16_t SX128x::setDataShaping(uint8_t sh) { // update modulation parameters if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) { - return(setModulationParams(_br, _modIndex, _shaping)); + return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); } else { - return(setModulationParams(_br, _crFLRC, _shaping)); + return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping)); } } @@ -908,7 +908,7 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { // calculate sync word length parameter value if(len > 0) { - _syncWordLen = (len - 1)*2; + this->syncWordLen = (len - 1)*2; } } else { @@ -918,7 +918,7 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { } // save sync word length parameter value - _syncWordLen = len; + this->syncWordLen = len; } // reverse sync word byte order @@ -932,13 +932,13 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { RADIOLIB_ASSERT(state); // update packet parameters - if(_syncWordLen == 0) { - _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF; + if(this->syncWordLen == 0) { + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF; } else { /// \todo add support for multiple sync words - _syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; + this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; } - return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); } int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { @@ -968,8 +968,8 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } } - _crcGFSK = len << 4; - state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening); + this->crcGFSK = len << 4; + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening); RADIOLIB_ASSERT(state); // set initial CRC value @@ -986,13 +986,13 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { // update packet parameters if(len == 0) { - _crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF; + this->crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF; } else if(len == 3) { - _crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE; + this->crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE; } else { return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - state = setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening); + state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); RADIOLIB_ASSERT(state); // set initial CRC value @@ -1003,13 +1003,13 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // update packet parameters if(len == 0) { - _crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF; + this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF; } else if(len == 2) { - _crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; + this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; } else { return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ); + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); return(state); } @@ -1025,15 +1025,15 @@ int16_t SX128x::setWhitening(bool enabled) { // update packet parameters if(enabled) { - _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; } else { - _whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; + this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; } if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { - return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); } - return(setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening)); + return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening)); } int16_t SX128x::setAccessAddress(uint32_t addr) { @@ -1047,13 +1047,13 @@ int16_t SX128x::setAccessAddress(uint32_t addr) { return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); } -int16_t SX128x::setHighSensitivityMode(bool hsm) { +int16_t SX128x::setHighSensitivityMode(bool enable) { // read the current registers uint8_t RxGain = 0; int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1); RADIOLIB_ASSERT(state); - if(hsm) { + if(enable) { RxGain |= 0xC0; // Set bits 6 and 7 } else { RxGain &= ~0xC0; // Unset bits 6 and 7 @@ -1103,7 +1103,7 @@ int16_t SX128x::setGainControl(uint8_t gain) { float SX128x::getRSSI() { // get packet status uint8_t packetStatus[5]; - _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); // check active modem uint8_t modem = getPacketType(); @@ -1133,7 +1133,7 @@ float SX128x::getSNR() { // get packet status uint8_t packetStatus[5]; - _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); // calculate real SNR uint8_t snr = packetStatus[1]; @@ -1169,9 +1169,9 @@ float SX128x::getFrequencyError() { // frequency error is negative efe |= (uint32_t) 0xFFF00000; efe = ~efe + 1; - error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz) * -1.0; + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0; } else { - error = 1.55 * (float) efe / (1600.0 / (float) _bwKhz); + error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz); } return(error); @@ -1181,12 +1181,12 @@ size_t SX128x::getPacketLength(bool update) { (void)update; // in implicit mode, return the cached value - if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) { - return(_payloadLen); + if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) { + return(this->payloadLen); } uint8_t rxBufStatus[2] = {0, 0}; - _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } @@ -1196,8 +1196,8 @@ uint32_t SX128x::getTimeOnAir(size_t len) { if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { // calculate number of symbols float N_symbol = 0; - uint8_t sf = _sf >> 4; - if(_cr <= RADIOLIB_SX128X_LORA_CR_4_8) { + uint8_t sf = this->spreadingFactor >> 4; + if(this->codingRateLoRa <= RADIOLIB_SX128X_LORA_CR_4_8) { // legacy coding rate - nice and simple // get SF coefficients @@ -1223,21 +1223,21 @@ uint32_t SX128x::getTimeOnAir(size_t len) { // get CRC length int16_t N_bitCRC = 16; - if(_crcLoRa == RADIOLIB_SX128X_LORA_CRC_OFF) { + if(this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_OFF) { N_bitCRC = 0; } // get header length int16_t N_symbolHeader = 20; - if(_headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) { + if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) { N_symbolHeader = 0; } // calculate number of LoRa preamble symbols - uint32_t N_symbolPreamble = (_preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((_preambleLengthLoRa & 0xF0) >> 4)); + uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(max((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(_cr + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(max((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); } else { // long interleaving - abandon hope all ye who enter here @@ -1246,10 +1246,10 @@ uint32_t SX128x::getTimeOnAir(size_t len) { } // get time-on-air in us - return(((uint32_t(1) << sf) / _bwKhz) * N_symbol * 1000.0); + return(((uint32_t(1) << sf) / this->bandwidthKhz) * N_symbol * 1000.0); } else { - return(((uint32_t)len * 8 * 1000) / _brKbps); + return(((uint32_t)len * 8 * 1000) / this->bitRateKbps); } } @@ -1267,11 +1267,11 @@ int16_t SX128x::setEncoding(uint8_t encoding) { } void SX128x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - _mod->setRfSwitchPins(rxEn, txEn); + this->mod->setRfSwitchPins(rxEn, txEn); } void SX128x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - _mod->setRfSwitchTable(pins, table); + this->mod->setRfSwitchTable(pins, table); } uint8_t SX128x::randomByte() { @@ -1280,18 +1280,18 @@ uint8_t SX128x::randomByte() { return(0); } -int16_t SX128x::invertIQ(bool invertIQ) { +int16_t SX128x::invertIQ(bool enable) { if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } - if(invertIQ) { - _invertIQ = RADIOLIB_SX128X_LORA_IQ_INVERTED; + if(enable) { + this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_INVERTED; } else { - _invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD; + this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD; } - return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ)); + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); } #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) @@ -1310,87 +1310,87 @@ void SX128x::readBit(uint32_t pin) { uint8_t SX128x::getStatus() { uint8_t data = 0; - _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 1); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 1); return(data); } int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - _mod->SPIwriteRegisterBurst(addr, data, numBytes); + this->mod->SPIwriteRegisterBurst(addr, data, numBytes); return(RADIOLIB_ERR_NONE); } int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { // send the command - _mod->SPIreadRegisterBurst(addr, numBytes, data); + this->mod->SPIreadRegisterBurst(addr, numBytes, data); // check the status - int16_t state = _mod->SPIcheckStream(); + int16_t state = this->mod->SPIcheckStream(); return(state); } int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset }; - return(_mod->SPIwriteStream(cmd, 2, data, numBytes)); + return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); } int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes) { uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, RADIOLIB_SX128X_CMD_NOP }; - return(_mod->SPIreadStream(cmd, 2, data, numBytes)); + return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); } int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) { uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); } int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); } int16_t SX128x::setCad() { - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); } uint8_t SX128x::getPacketType() { uint8_t data = 0xFF; - _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1); return(data); } int16_t SX128x::setRfFrequency(uint32_t frf) { uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); } -int16_t SX128x::setTxParams(uint8_t power, uint8_t rampTime) { - uint8_t data[] = { power, rampTime }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); +int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) { + uint8_t data[] = { pwr, rampTime }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { uint8_t data[] = { txBaseAddress, rxBaseAddress }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { uint8_t data[] = { modParam1, modParam2, modParam3 }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); } -int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen, uint8_t headerType) { - uint8_t data[] = { preambleLen, syncWordLen, syncWordMatch, headerType, payloadLen, crcLen, whitening }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen, uint8_t hdrType) { + uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, this->payloadLen, crcLen, whiten }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } -int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening) { - uint8_t data[] = { connState, crcLen, bleTestPayload, whitening, 0x00, 0x00, 0x00 }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) { + uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } -int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ) { - uint8_t data[] = { preambleLen, headerType, payloadLen, crc, invertIQ, 0x00, 0x00 }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) { + uint8_t data[] = { preambleLen, hdrType, this->payloadLen, crc, invIQ, 0x00, 0x00 }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { @@ -1398,31 +1398,31 @@ int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } uint16_t SX128x::getIrqStatus() { uint8_t data[] = { 0x00, 0x00 }; - _mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX128x::setRangingRole(uint8_t role) { uint8_t data[] = { role }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); } int16_t SX128x::setPacketType(uint8_t type) { uint8_t data[] = { type }; - return(_mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); } -int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { +int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) { // check active modem uint8_t modem = getPacketType(); if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { @@ -1430,9 +1430,9 @@ int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { } // update packet parameters - _headerType = headerType; - _payloadLen = len; - return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa, _invertIQ)); + this->headerType = hdrType; + this->payloadLen = len; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); } int16_t SX128x::config(uint8_t modem) { @@ -1443,17 +1443,17 @@ int16_t SX128x::config(uint8_t modem) { // set modem uint8_t data[1]; data[0] = modem; - state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1); + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1); RADIOLIB_ASSERT(state); // set CAD parameters data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB; - state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1); + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1); RADIOLIB_ASSERT(state); // set regulator mode to DC-DC data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC; - state = _mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1); + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1); RADIOLIB_ASSERT(state); return(RADIOLIB_ERR_NONE); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 0dca7e49a0..804c4fa85d 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -10,341 +10,340 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // SX128X physical layer properties -#define RADIOLIB_SX128X_FREQUENCY_STEP_SIZE 198.3642578 -#define RADIOLIB_SX128X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0 -#define RADIOLIB_SX128X_DIV_EXPONENT 18 +#define RADIOLIB_SX128X_FREQUENCY_STEP_SIZE 198.3642578 +#define RADIOLIB_SX128X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0 +#define RADIOLIB_SX128X_DIV_EXPONENT 18 // SX128X SPI commands -#define RADIOLIB_SX128X_CMD_NOP 0x00 -#define RADIOLIB_SX128X_CMD_GET_STATUS 0xC0 -#define RADIOLIB_SX128X_CMD_WRITE_REGISTER 0x18 -#define RADIOLIB_SX128X_CMD_READ_REGISTER 0x19 -#define RADIOLIB_SX128X_CMD_WRITE_BUFFER 0x1A -#define RADIOLIB_SX128X_CMD_READ_BUFFER 0x1B -#define RADIOLIB_SX128X_CMD_SET_SLEEP 0x84 -#define RADIOLIB_SX128X_CMD_SET_STANDBY 0x80 -#define RADIOLIB_SX128X_CMD_SET_FS 0xC1 -#define RADIOLIB_SX128X_CMD_SET_TX 0x83 -#define RADIOLIB_SX128X_CMD_SET_RX 0x82 -#define RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE 0x94 -#define RADIOLIB_SX128X_CMD_SET_CAD 0xC5 -#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 -#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_PREAMBLE 0xD2 -#define RADIOLIB_SX128X_CMD_SET_PACKET_TYPE 0x8A -#define RADIOLIB_SX128X_CMD_GET_PACKET_TYPE 0x03 -#define RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY 0x86 -#define RADIOLIB_SX128X_CMD_SET_TX_PARAMS 0x8E -#define RADIOLIB_SX128X_CMD_SET_CAD_PARAMS 0x88 -#define RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F -#define RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS 0x8B -#define RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS 0x8C -#define RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS 0x17 -#define RADIOLIB_SX128X_CMD_GET_PACKET_STATUS 0x1D -#define RADIOLIB_SX128X_CMD_GET_RSSI_INST 0x1F -#define RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS 0x8D -#define RADIOLIB_SX128X_CMD_GET_IRQ_STATUS 0x15 -#define RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS 0x97 -#define RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE 0x96 -#define RADIOLIB_SX128X_CMD_SET_SAVE_CONTEXT 0xD5 -#define RADIOLIB_SX128X_CMD_SET_AUTO_TX 0x98 -#define RADIOLIB_SX128X_CMD_SET_AUTO_FS 0x9E -#define RADIOLIB_SX128X_CMD_SET_PERF_COUNTER_MODE 0x9C -#define RADIOLIB_SX128X_CMD_SET_LONG_PREAMBLE 0x9B -#define RADIOLIB_SX128X_CMD_SET_UART_SPEED 0x9D -#define RADIOLIB_SX128X_CMD_SET_RANGING_ROLE 0xA3 -#define RADIOLIB_SX128X_CMD_SET_ADVANCED_RANGING 0x9A +#define RADIOLIB_SX128X_CMD_NOP 0x00 +#define RADIOLIB_SX128X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX128X_CMD_WRITE_REGISTER 0x18 +#define RADIOLIB_SX128X_CMD_READ_REGISTER 0x19 +#define RADIOLIB_SX128X_CMD_WRITE_BUFFER 0x1A +#define RADIOLIB_SX128X_CMD_READ_BUFFER 0x1B +#define RADIOLIB_SX128X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX128X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX128X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX128X_CMD_SET_TX 0x83 +#define RADIOLIB_SX128X_CMD_SET_RX 0x82 +#define RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX128X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_PREAMBLE 0xD2 +#define RADIOLIB_SX128X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX128X_CMD_GET_PACKET_TYPE 0x03 +#define RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX128X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX128X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS 0x17 +#define RADIOLIB_SX128X_CMD_GET_PACKET_STATUS 0x1D +#define RADIOLIB_SX128X_CMD_GET_RSSI_INST 0x1F +#define RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS 0x8D +#define RADIOLIB_SX128X_CMD_GET_IRQ_STATUS 0x15 +#define RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS 0x97 +#define RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX128X_CMD_SET_SAVE_CONTEXT 0xD5 +#define RADIOLIB_SX128X_CMD_SET_AUTO_TX 0x98 +#define RADIOLIB_SX128X_CMD_SET_AUTO_FS 0x9E +#define RADIOLIB_SX128X_CMD_SET_PERF_COUNTER_MODE 0x9C +#define RADIOLIB_SX128X_CMD_SET_LONG_PREAMBLE 0x9B +#define RADIOLIB_SX128X_CMD_SET_UART_SPEED 0x9D +#define RADIOLIB_SX128X_CMD_SET_RANGING_ROLE 0xA3 +#define RADIOLIB_SX128X_CMD_SET_ADVANCED_RANGING 0x9A // SX128X register map -#define RADIOLIB_SX128X_REG_GAIN_MODE 0x0891 -#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 -#define RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING 0x089E -#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1 0x089F -#define RADIOLIB_SX128X_REG_SYNCH_PEAK_ATTENUATION 0x08C2 -#define RADIOLIB_SX128X_REG_LORA_FIXED_PAYLOAD_LENGTH 0x0901 -#define RADIOLIB_SX128X_REG_LORA_HEADER_MODE 0x0903 -#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3 0x0912 -#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_2 0x0913 -#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_1 0x0914 -#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_0 0x0915 -#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3 0x0916 -#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_2 0x0917 -#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_1 0x0918 -#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_0 0x0919 -#define RADIOLIB_SX128X_REG_RANGING_FILTER_WINDOW_SIZE 0x091E -#define RADIOLIB_SX128X_REG_RANGING_FILTER_RESET 0x0923 -#define RADIOLIB_SX128X_REG_RANGING_TYPE 0x0924 -#define RADIOLIB_SX128X_REG_LORA_SF_CONFIG 0x0925 -#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_SWITCH 0x0927 -#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_BYTE_2 0x092B -#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB 0x092C -#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_LSB 0x092D -#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH 0x0931 -#define RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION 0x093C -#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB 0x0944 -#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_LSB 0x0945 -#define RADIOLIB_SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 -#define RADIOLIB_SX128X_REG_FEI_MSB 0x0954 -#define RADIOLIB_SX128X_REG_FEI_MID 0x0955 -#define RADIOLIB_SX128X_REG_FEI_LSB 0x0956 -#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_MSB 0x095F -#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_LSB 0x0960 -#define RADIOLIB_SX128X_REG_RANGING_RESULT_MSB 0x0961 -#define RADIOLIB_SX128X_REG_RANGING_RESULT_MID 0x0962 -#define RADIOLIB_SX128X_REG_RANGING_RESULT_LSB 0x0963 -#define RADIOLIB_SX128X_REG_RANGING_RSSI 0x0964 -#define RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE 0x097F -#define RADIOLIB_SX128X_REG_PACKET_PREAMBLE_SETTINGS 0x09C1 -#define RADIOLIB_SX128X_REG_WHITENING_INITIAL_VALUE 0x09C5 -#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB 0x09C6 -#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_LSB 0x09C7 -#define RADIOLIB_SX128X_REG_CRC_INITIAL_MSB 0x09C8 -#define RADIOLIB_SX128X_REG_CRC_INITIAL_LSB 0x09C9 -#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB 0x09C7 -#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MID (RADIOLIB_SX128X_REG_CRC_INITIAL_MSB) -#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_LSB (RADIOLIB_SX128X_REG_CRC_INITIAL_LSB) -#define RADIOLIB_SX128X_REG_SYNCH_ADDRESS_CONTROL 0x09CD -#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 0x09CE -#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3 0x09CF -#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2 0x09D0 -#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1 0x09D1 -#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0 0x09D2 -#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_4 0x09D3 -#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_3 0x09D4 -#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_2 0x09D5 -#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_1 0x09D6 -#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_0 0x09D7 -#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_4 0x09D8 -#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_3 0x09D9 -#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_2 0x09DA -#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_1 0x09DB -#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_0 0x09DC -#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3) -#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_2 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2) -#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_1 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1) -#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_0 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0) +#define RADIOLIB_SX128X_REG_GAIN_MODE 0x0891 +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING 0x089E +#define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1 0x089F +#define RADIOLIB_SX128X_REG_SYNCH_PEAK_ATTENUATION 0x08C2 +#define RADIOLIB_SX128X_REG_LORA_FIXED_PAYLOAD_LENGTH 0x0901 +#define RADIOLIB_SX128X_REG_LORA_HEADER_MODE 0x0903 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3 0x0912 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_2 0x0913 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_1 0x0914 +#define RADIOLIB_SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_0 0x0915 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3 0x0916 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_2 0x0917 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_1 0x0918 +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_0 0x0919 +#define RADIOLIB_SX128X_REG_RANGING_FILTER_WINDOW_SIZE 0x091E +#define RADIOLIB_SX128X_REG_RANGING_FILTER_RESET 0x0923 +#define RADIOLIB_SX128X_REG_RANGING_TYPE 0x0924 +#define RADIOLIB_SX128X_REG_LORA_SF_CONFIG 0x0925 +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_SWITCH 0x0927 +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_BYTE_2 0x092B +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB 0x092C +#define RADIOLIB_SX128X_REG_RANGING_CALIBRATION_LSB 0x092D +#define RADIOLIB_SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH 0x0931 +#define RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION 0x093C +#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB 0x0944 +#define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_LSB 0x0945 +#define RADIOLIB_SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 +#define RADIOLIB_SX128X_REG_FEI_MSB 0x0954 +#define RADIOLIB_SX128X_REG_FEI_MID 0x0955 +#define RADIOLIB_SX128X_REG_FEI_LSB 0x0956 +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_MSB 0x095F +#define RADIOLIB_SX128X_REG_RANGING_ADDRESS_LSB 0x0960 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_MSB 0x0961 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_MID 0x0962 +#define RADIOLIB_SX128X_REG_RANGING_RESULT_LSB 0x0963 +#define RADIOLIB_SX128X_REG_RANGING_RSSI 0x0964 +#define RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE 0x097F +#define RADIOLIB_SX128X_REG_PACKET_PREAMBLE_SETTINGS 0x09C1 +#define RADIOLIB_SX128X_REG_WHITENING_INITIAL_VALUE 0x09C5 +#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB 0x09C6 +#define RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_LSB 0x09C7 +#define RADIOLIB_SX128X_REG_CRC_INITIAL_MSB 0x09C8 +#define RADIOLIB_SX128X_REG_CRC_INITIAL_LSB 0x09C9 +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB 0x09C7 +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MID (RADIOLIB_SX128X_REG_CRC_INITIAL_MSB) +#define RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_LSB (RADIOLIB_SX128X_REG_CRC_INITIAL_LSB) +#define RADIOLIB_SX128X_REG_SYNCH_ADDRESS_CONTROL 0x09CD +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 0x09CE +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3 0x09CF +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2 0x09D0 +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1 0x09D1 +#define RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0 0x09D2 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_4 0x09D3 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_3 0x09D4 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_2 0x09D5 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_1 0x09D6 +#define RADIOLIB_SX128X_REG_SYNC_WORD_2_BYTE_0 0x09D7 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_4 0x09D8 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_3 0x09D9 +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_2 0x09DA +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_1 0x09DB +#define RADIOLIB_SX128X_REG_SYNC_WORD_3_BYTE_0 0x09DC +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_3) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_2 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_2) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_1 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_1) +#define RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_0 (RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_0) // SX128X SPI command variables -//RADIOLIB_SX128X_CMD_GET_STATUS MSB LSB DESCRIPTION -#define RADIOLIB_SX128X_STATUS_MODE_STDBY_RC 0b01000000 // 7 5 current chip mode: STDBY_RC -#define RADIOLIB_SX128X_STATUS_MODE_STDBY_XOSC 0b01100000 // 7 5 STDBY_XOSC -#define RADIOLIB_SX128X_STATUS_MODE_FS 0b10000000 // 7 5 FS -#define RADIOLIB_SX128X_STATUS_MODE_RX 0b10100000 // 7 5 Rx -#define RADIOLIB_SX128X_STATUS_MODE_TX 0b11000000 // 7 5 Tx -#define RADIOLIB_SX128X_STATUS_CMD_PROCESSED 0b00000100 // 4 2 command status: processing OK -#define RADIOLIB_SX128X_STATUS_DATA_AVAILABLE 0b00001000 // 4 2 data available -#define RADIOLIB_SX128X_STATUS_CMD_TIMEOUT 0b00001100 // 4 2 timeout -#define RADIOLIB_SX128X_STATUS_CMD_ERROR 0b00010000 // 4 2 processing error -#define RADIOLIB_SX128X_STATUS_CMD_FAILED 0b00010100 // 4 2 failed to execute -#define RADIOLIB_SX128X_STATUS_TX_DONE 0b00011000 // 4 2 transmission finished -#define RADIOLIB_SX128X_STATUS_BUSY 0b00000001 // 0 0 chip busy -#define RADIOLIB_SX128X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed +//RADIOLIB_SX128X_CMD_GET_STATUS MSB LSB DESCRIPTION +#define RADIOLIB_SX128X_STATUS_MODE_STDBY_RC 0b01000000 // 7 5 current chip mode: STDBY_RC +#define RADIOLIB_SX128X_STATUS_MODE_STDBY_XOSC 0b01100000 // 7 5 STDBY_XOSC +#define RADIOLIB_SX128X_STATUS_MODE_FS 0b10000000 // 7 5 FS +#define RADIOLIB_SX128X_STATUS_MODE_RX 0b10100000 // 7 5 Rx +#define RADIOLIB_SX128X_STATUS_MODE_TX 0b11000000 // 7 5 Tx +#define RADIOLIB_SX128X_STATUS_CMD_PROCESSED 0b00000100 // 4 2 command status: processing OK +#define RADIOLIB_SX128X_STATUS_DATA_AVAILABLE 0b00001000 // 4 2 data available +#define RADIOLIB_SX128X_STATUS_CMD_TIMEOUT 0b00001100 // 4 2 timeout +#define RADIOLIB_SX128X_STATUS_CMD_ERROR 0b00010000 // 4 2 processing error +#define RADIOLIB_SX128X_STATUS_CMD_FAILED 0b00010100 // 4 2 failed to execute +#define RADIOLIB_SX128X_STATUS_TX_DONE 0b00011000 // 4 2 transmission finished +#define RADIOLIB_SX128X_STATUS_BUSY 0b00000001 // 0 0 chip busy +#define RADIOLIB_SX128X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed //RADIOLIB_SX128X_CMD_SET_SLEEP -#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH 0b00000000 // 1 1 data buffer behavior in sleep mode: flush -#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN 0b00000010 // 1 1 retain -#define RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH 0b00000000 // 0 0 data RAM (configuration) behavior in sleep mode: flush -#define RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN 0b00000001 // 0 0 retain +#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH 0b00000000 // 1 1 data buffer behavior in sleep mode: flush +#define RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN 0b00000010 // 1 1 retain +#define RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH 0b00000000 // 0 0 data RAM (configuration) behavior in sleep mode: flush +#define RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN 0b00000001 // 0 0 retain //RADIOLIB_SX128X_CMD_SET_STANDBY -#define RADIOLIB_SX128X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator -#define RADIOLIB_SX128X_STANDBY_XOSC 0x01 // 7 0 52 MHz crystal oscillator +#define RADIOLIB_SX128X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX128X_STANDBY_XOSC 0x01 // 7 0 52 MHz crystal oscillator //RADIOLIB_SX128X_CMD_SET_TX + RADIOLIB_SX128X_CMD_SET_RX + RADIOLIB_SX128X_CMD_SET_RX_DUTY_CYCLE -#define RADIOLIB_SX128X_PERIOD_BASE_15_625_US 0x00 // 7 0 time period step: 15.625 us -#define RADIOLIB_SX128X_PERIOD_BASE_62_5_US 0x01 // 7 0 62.5 us -#define RADIOLIB_SX128X_PERIOD_BASE_1_MS 0x02 // 7 0 1 ms -#define RADIOLIB_SX128X_PERIOD_BASE_4_MS 0x03 // 7 0 4 ms +#define RADIOLIB_SX128X_PERIOD_BASE_15_625_US 0x00 // 7 0 time period step: 15.625 us +#define RADIOLIB_SX128X_PERIOD_BASE_62_5_US 0x01 // 7 0 62.5 us +#define RADIOLIB_SX128X_PERIOD_BASE_1_MS 0x02 // 7 0 1 ms +#define RADIOLIB_SX128X_PERIOD_BASE_4_MS 0x03 // 7 0 4 ms //RADIOLIB_SX128X_CMD_SET_TX -#define RADIOLIB_SX128X_TX_TIMEOUT_NONE 0x0000 // 15 0 Tx timeout duration: no timeout (Tx single mode) +#define RADIOLIB_SX128X_TX_TIMEOUT_NONE 0x0000 // 15 0 Tx timeout duration: no timeout (Tx single mode) //RADIOLIB_SX128X_CMD_SET_RX -#define RADIOLIB_SX128X_RX_TIMEOUT_NONE 0x0000 // 15 0 Rx timeout duration: no timeout (Rx single mode) -#define RADIOLIB_SX128X_RX_TIMEOUT_INF 0xFFFF // 15 0 infinite (Rx continuous mode) +#define RADIOLIB_SX128X_RX_TIMEOUT_NONE 0x0000 // 15 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX128X_RX_TIMEOUT_INF 0xFFFF // 15 0 infinite (Rx continuous mode) //RADIOLIB_SX128X_CMD_SET_PACKET_TYPE -#define RADIOLIB_SX128X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: (G)FSK -#define RADIOLIB_SX128X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa -#define RADIOLIB_SX128X_PACKET_TYPE_RANGING 0x02 // 7 0 ranging engine -#define RADIOLIB_SX128X_PACKET_TYPE_FLRC 0x03 // 7 0 FLRC -#define RADIOLIB_SX128X_PACKET_TYPE_BLE 0x04 // 7 0 BLE +#define RADIOLIB_SX128X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: (G)FSK +#define RADIOLIB_SX128X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX128X_PACKET_TYPE_RANGING 0x02 // 7 0 ranging engine +#define RADIOLIB_SX128X_PACKET_TYPE_FLRC 0x03 // 7 0 FLRC +#define RADIOLIB_SX128X_PACKET_TYPE_BLE 0x04 // 7 0 BLE //RADIOLIB_SX128X_CMD_SET_TX_PARAMS -#define RADIOLIB_SX128X_PA_RAMP_02_US 0x00 // 7 0 PA ramp time: 2 us -#define RADIOLIB_SX128X_PA_RAMP_04_US 0x20 // 7 0 4 us -#define RADIOLIB_SX128X_PA_RAMP_06_US 0x40 // 7 0 6 us -#define RADIOLIB_SX128X_PA_RAMP_08_US 0x60 // 7 0 8 us -#define RADIOLIB_SX128X_PA_RAMP_10_US 0x80 // 7 0 10 us -#define RADIOLIB_SX128X_PA_RAMP_12_US 0xA0 // 7 0 12 us -#define RADIOLIB_SX128X_PA_RAMP_16_US 0xC0 // 7 0 16 us -#define RADIOLIB_SX128X_PA_RAMP_20_US 0xE0 // 7 0 20 us +#define RADIOLIB_SX128X_PA_RAMP_02_US 0x00 // 7 0 PA ramp time: 2 us +#define RADIOLIB_SX128X_PA_RAMP_04_US 0x20 // 7 0 4 us +#define RADIOLIB_SX128X_PA_RAMP_06_US 0x40 // 7 0 6 us +#define RADIOLIB_SX128X_PA_RAMP_08_US 0x60 // 7 0 8 us +#define RADIOLIB_SX128X_PA_RAMP_10_US 0x80 // 7 0 10 us +#define RADIOLIB_SX128X_PA_RAMP_12_US 0xA0 // 7 0 12 us +#define RADIOLIB_SX128X_PA_RAMP_16_US 0xC0 // 7 0 16 us +#define RADIOLIB_SX128X_PA_RAMP_20_US 0xE0 // 7 0 20 us //RADIOLIB_SX128X_CMD_SET_CAD_PARAMS -#define RADIOLIB_SX128X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 -#define RADIOLIB_SX128X_CAD_ON_2_SYMB 0x20 // 7 0 2 -#define RADIOLIB_SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 -#define RADIOLIB_SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 -#define RADIOLIB_SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 +#define RADIOLIB_SX128X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX128X_CAD_ON_2_SYMB 0x20 // 7 0 2 +#define RADIOLIB_SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 +#define RADIOLIB_SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 +#define RADIOLIB_SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 //RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS -#define RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4 0x28 // 7 0 1.6 Mbps 2.4 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4 0x4C // 7 0 1.0 Mbps 2.4 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_1_2 0x45 // 7 0 1.0 Mbps 1.2 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4 0x70 // 7 0 0.8 Mbps 2.4 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_1_2 0x69 // 7 0 0.8 Mbps 1.2 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2 0x8D // 7 0 0.5 Mbps 1.2 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_0_6 0x86 // 7 0 0.5 Mbps 0.6 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2 0xB1 // 7 0 0.4 Mbps 1.2 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_0_6 0xAA // 7 0 0.4 Mbps 0.6 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6 0xCE // 7 0 0.25 Mbps 0.6 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_3 0xC7 // 7 0 0.25 Mbps 0.3 MHz -#define RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3 0xEF // 7 0 0.125 Mbps 0.3 MHz -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35 0x00 // 7 0 GFSK/BLE modulation index: 0.35 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_50 0x01 // 7 0 0.50 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_75 0x02 // 7 0 0.75 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00 0x03 // 7 0 1.00 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_25 0x04 // 7 0 1.25 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_50 0x05 // 7 0 1.50 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_75 0x06 // 7 0 1.75 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_00 0x07 // 7 0 2.00 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_25 0x08 // 7 0 2.25 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_50 0x09 // 7 0 2.50 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_75 0x0A // 7 0 2.75 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_00 0x0B // 7 0 3.00 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_25 0x0C // 7 0 3.25 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_50 0x0D // 7 0 3.50 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_75 0x0E // 7 0 3.75 -#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00 0x0F // 7 0 4.00 -#define RADIOLIB_SX128X_BLE_GFSK_BT_OFF 0x00 // 7 0 GFSK Gaussian filter BT product: filter disabled -#define RADIOLIB_SX128X_BLE_GFSK_BT_1_0 0x10 // 7 0 1.0 -#define RADIOLIB_SX128X_BLE_GFSK_BT_0_5 0x20 // 7 0 0.5 -#define RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2 0x45 // 7 0 FLRC bit rate and bandwidth setting: 1.3 Mbps 1.2 MHz -#define RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2 0x69 // 7 0 1.04 Mbps 1.2 MHz -#define RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6 0x86 // 7 0 0.65 Mbps 0.6 MHz -#define RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6 0xAA // 7 0 0.52 Mbps 0.6 MHz -#define RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3 0xC7 // 7 0 0.325 Mbps 0.3 MHz -#define RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3 0xEB // 7 0 0.260 Mbps 0.3 MHz -#define RADIOLIB_SX128X_FLRC_CR_1_2 0x00 // 7 0 FLRC coding rate: 1/2 -#define RADIOLIB_SX128X_FLRC_CR_3_4 0x02 // 7 0 3/4 -#define RADIOLIB_SX128X_FLRC_CR_1_0 0x04 // 7 0 1/1 -#define RADIOLIB_SX128X_FLRC_BT_OFF 0x00 // 7 0 FLRC Gaussian filter BT product: filter disabled -#define RADIOLIB_SX128X_FLRC_BT_1_0 0x10 // 7 0 1.0 -#define RADIOLIB_SX128X_FLRC_BT_0_5 0x20 // 7 0 0.5 -#define RADIOLIB_SX128X_LORA_SF_5 0x50 // 7 0 LoRa spreading factor: 5 -#define RADIOLIB_SX128X_LORA_SF_6 0x60 // 7 0 6 -#define RADIOLIB_SX128X_LORA_SF_7 0x70 // 7 0 7 -#define RADIOLIB_SX128X_LORA_SF_8 0x80 // 7 0 8 -#define RADIOLIB_SX128X_LORA_SF_9 0x90 // 7 0 9 -#define RADIOLIB_SX128X_LORA_SF_10 0xA0 // 7 0 10 -#define RADIOLIB_SX128X_LORA_SF_11 0xB0 // 7 0 11 -#define RADIOLIB_SX128X_LORA_SF_12 0xC0 // 7 0 12 -#define RADIOLIB_SX128X_LORA_BW_1625_00 0x0A // 7 0 LoRa bandwidth: 1625.0 kHz -#define RADIOLIB_SX128X_LORA_BW_812_50 0x18 // 7 0 812.5 kHz -#define RADIOLIB_SX128X_LORA_BW_406_25 0x26 // 7 0 406.25 kHz -#define RADIOLIB_SX128X_LORA_BW_203_125 0x34 // 7 0 203.125 kHz -#define RADIOLIB_SX128X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 -#define RADIOLIB_SX128X_LORA_CR_4_6 0x02 // 7 0 4/6 -#define RADIOLIB_SX128X_LORA_CR_4_7 0x03 // 7 0 4/7 -#define RADIOLIB_SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 -#define RADIOLIB_SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving -#define RADIOLIB_SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving -#define RADIOLIB_SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving +#define RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4 0x28 // 7 0 1.6 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4 0x4C // 7 0 1.0 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_1_2 0x45 // 7 0 1.0 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4 0x70 // 7 0 0.8 Mbps 2.4 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_1_2 0x69 // 7 0 0.8 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2 0x8D // 7 0 0.5 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_0_6 0x86 // 7 0 0.5 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2 0xB1 // 7 0 0.4 Mbps 1.2 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_0_6 0xAA // 7 0 0.4 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6 0xCE // 7 0 0.25 Mbps 0.6 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_3 0xC7 // 7 0 0.25 Mbps 0.3 MHz +#define RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3 0xEF // 7 0 0.125 Mbps 0.3 MHz +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35 0x00 // 7 0 GFSK/BLE modulation index: 0.35 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_50 0x01 // 7 0 0.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_75 0x02 // 7 0 0.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00 0x03 // 7 0 1.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_25 0x04 // 7 0 1.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_50 0x05 // 7 0 1.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_75 0x06 // 7 0 1.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_00 0x07 // 7 0 2.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_25 0x08 // 7 0 2.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_50 0x09 // 7 0 2.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_2_75 0x0A // 7 0 2.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_00 0x0B // 7 0 3.00 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_25 0x0C // 7 0 3.25 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_50 0x0D // 7 0 3.50 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_3_75 0x0E // 7 0 3.75 +#define RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00 0x0F // 7 0 4.00 +#define RADIOLIB_SX128X_BLE_GFSK_BT_OFF 0x00 // 7 0 GFSK Gaussian filter BT product: filter disabled +#define RADIOLIB_SX128X_BLE_GFSK_BT_1_0 0x10 // 7 0 1.0 +#define RADIOLIB_SX128X_BLE_GFSK_BT_0_5 0x20 // 7 0 0.5 +#define RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2 0x45 // 7 0 FLRC bit rate and bandwidth setting: 1.3 Mbps 1.2 MHz +#define RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2 0x69 // 7 0 1.04 Mbps 1.2 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6 0x86 // 7 0 0.65 Mbps 0.6 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6 0xAA // 7 0 0.52 Mbps 0.6 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3 0xC7 // 7 0 0.325 Mbps 0.3 MHz +#define RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3 0xEB // 7 0 0.260 Mbps 0.3 MHz +#define RADIOLIB_SX128X_FLRC_CR_1_2 0x00 // 7 0 FLRC coding rate: 1/2 +#define RADIOLIB_SX128X_FLRC_CR_3_4 0x02 // 7 0 3/4 +#define RADIOLIB_SX128X_FLRC_CR_1_0 0x04 // 7 0 1/1 +#define RADIOLIB_SX128X_FLRC_BT_OFF 0x00 // 7 0 FLRC Gaussian filter BT product: filter disabled +#define RADIOLIB_SX128X_FLRC_BT_1_0 0x10 // 7 0 1.0 +#define RADIOLIB_SX128X_FLRC_BT_0_5 0x20 // 7 0 0.5 +#define RADIOLIB_SX128X_LORA_SF_5 0x50 // 7 0 LoRa spreading factor: 5 +#define RADIOLIB_SX128X_LORA_SF_6 0x60 // 7 0 6 +#define RADIOLIB_SX128X_LORA_SF_7 0x70 // 7 0 7 +#define RADIOLIB_SX128X_LORA_SF_8 0x80 // 7 0 8 +#define RADIOLIB_SX128X_LORA_SF_9 0x90 // 7 0 9 +#define RADIOLIB_SX128X_LORA_SF_10 0xA0 // 7 0 10 +#define RADIOLIB_SX128X_LORA_SF_11 0xB0 // 7 0 11 +#define RADIOLIB_SX128X_LORA_SF_12 0xC0 // 7 0 12 +#define RADIOLIB_SX128X_LORA_BW_1625_00 0x0A // 7 0 LoRa bandwidth: 1625.0 kHz +#define RADIOLIB_SX128X_LORA_BW_812_50 0x18 // 7 0 812.5 kHz +#define RADIOLIB_SX128X_LORA_BW_406_25 0x26 // 7 0 406.25 kHz +#define RADIOLIB_SX128X_LORA_BW_203_125 0x34 // 7 0 203.125 kHz +#define RADIOLIB_SX128X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX128X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX128X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving //RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1 0x10 // 7 0 sync word 1 -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2 0x20 // 7 0 sync word 2 -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2 0x30 // 7 0 sync words 1 and 2 -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_3 0x40 // 7 0 sync word 3 -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_3 0x50 // 7 0 sync words 1 and 3 -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2_3 0x60 // 7 0 sync words 2 and 3 -#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2_3 0x70 // 7 0 sync words 1, 2 and 3 -#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED 0x00 // 7 0 GFSK/FLRC packet length mode: fixed -#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE 0x20 // 7 0 variable -#define RADIOLIB_SX128X_GFSK_FLRC_CRC_OFF 0x00 // 7 0 GFSK/FLRC packet CRC: none -#define RADIOLIB_SX128X_GFSK_FLRC_CRC_1_BYTE 0x10 // 7 0 1 byte -#define RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE 0x20 // 7 0 2 bytes -#define RADIOLIB_SX128X_GFSK_FLRC_CRC_3_BYTE 0x30 // 7 0 3 bytes (FLRC only) -#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON 0x00 // 7 0 GFSK/BLE whitening: enabled -#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF 0x08 // 7 0 disabled -#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_31 0x00 // 7 0 BLE maximum payload length: 31 bytes -#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_37 0x20 // 7 0 37 bytes -#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_TEST 0x40 // 7 0 63 bytes (test mode) -#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_255 0x80 // 7 0 255 bytes (Bluetooth 4.2 and above) -#define RADIOLIB_SX128X_BLE_CRC_OFF 0x00 // 7 0 BLE packet CRC: none -#define RADIOLIB_SX128X_BLE_CRC_3_BYTE 0x10 // 7 0 3 byte -#define RADIOLIB_SX128X_BLE_PRBS_9 0x00 // 7 0 BLE test payload contents: PRNG sequence using x^9 + x^5 + x -#define RADIOLIB_SX128X_BLE_EYELONG 0x04 // 7 0 repeated 0xF0 -#define RADIOLIB_SX128X_BLE_EYESHORT 0x08 // 7 0 repeated 0xAA -#define RADIOLIB_SX128X_BLE_PRBS_15 0x0C // 7 0 PRNG sequence using x^15 + x^14 + x^13 + x^12 + x^2 + x + 1 -#define RADIOLIB_SX128X_BLE_ALL_1 0x10 // 7 0 repeated 0xFF -#define RADIOLIB_SX128X_BLE_ALL_0 0x14 // 7 0 repeated 0x00 -#define RADIOLIB_SX128X_BLE_EYELONG_INV 0x18 // 7 0 repeated 0x0F -#define RADIOLIB_SX128X_BLE_EYESHORT_INV 0x1C // 7 0 repeated 0x55 -#define RADIOLIB_SX128X_FLRC_SYNC_WORD_OFF 0x00 // 7 0 FLRC sync word: disabled -#define RADIOLIB_SX128X_FLRC_SYNC_WORD_ON 0x04 // 7 0 enabled -#define RADIOLIB_SX128X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit -#define RADIOLIB_SX128X_LORA_HEADER_IMPLICIT 0x80 // 7 0 implicit -#define RADIOLIB_SX128X_LORA_CRC_OFF 0x00 // 7 0 LoRa packet CRC: disabled -#define RADIOLIB_SX128X_LORA_CRC_ON 0x20 // 7 0 enabled -#define RADIOLIB_SX128X_LORA_IQ_STANDARD 0x40 // 7 0 LoRa IQ: standard -#define RADIOLIB_SX128X_LORA_IQ_INVERTED 0x00 // 7 0 inverted +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1 0x10 // 7 0 sync word 1 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2 0x20 // 7 0 sync word 2 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2 0x30 // 7 0 sync words 1 and 2 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_3 0x40 // 7 0 sync word 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_3 0x50 // 7 0 sync words 1 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_2_3 0x60 // 7 0 sync words 2 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1_2_3 0x70 // 7 0 sync words 1, 2 and 3 +#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED 0x00 // 7 0 GFSK/FLRC packet length mode: fixed +#define RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE 0x20 // 7 0 variable +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_OFF 0x00 // 7 0 GFSK/FLRC packet CRC: none +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_1_BYTE 0x10 // 7 0 1 byte +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE 0x20 // 7 0 2 bytes +#define RADIOLIB_SX128X_GFSK_FLRC_CRC_3_BYTE 0x30 // 7 0 3 bytes (FLRC only) +#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON 0x00 // 7 0 GFSK/BLE whitening: enabled +#define RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF 0x08 // 7 0 disabled +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_31 0x00 // 7 0 BLE maximum payload length: 31 bytes +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_37 0x20 // 7 0 37 bytes +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_TEST 0x40 // 7 0 63 bytes (test mode) +#define RADIOLIB_SX128X_BLE_PAYLOAD_LENGTH_MAX_255 0x80 // 7 0 255 bytes (Bluetooth 4.2 and above) +#define RADIOLIB_SX128X_BLE_CRC_OFF 0x00 // 7 0 BLE packet CRC: none +#define RADIOLIB_SX128X_BLE_CRC_3_BYTE 0x10 // 7 0 3 byte +#define RADIOLIB_SX128X_BLE_PRBS_9 0x00 // 7 0 BLE test payload contents: PRNG sequence using x^9 + x^5 + x +#define RADIOLIB_SX128X_BLE_EYELONG 0x04 // 7 0 repeated 0xF0 +#define RADIOLIB_SX128X_BLE_EYESHORT 0x08 // 7 0 repeated 0xAA +#define RADIOLIB_SX128X_BLE_PRBS_15 0x0C // 7 0 PRNG sequence using x^15 + x^14 + x^13 + x^12 + x^2 + x + 1 +#define RADIOLIB_SX128X_BLE_ALL_1 0x10 // 7 0 repeated 0xFF +#define RADIOLIB_SX128X_BLE_ALL_0 0x14 // 7 0 repeated 0x00 +#define RADIOLIB_SX128X_BLE_EYELONG_INV 0x18 // 7 0 repeated 0x0F +#define RADIOLIB_SX128X_BLE_EYESHORT_INV 0x1C // 7 0 repeated 0x55 +#define RADIOLIB_SX128X_FLRC_SYNC_WORD_OFF 0x00 // 7 0 FLRC sync word: disabled +#define RADIOLIB_SX128X_FLRC_SYNC_WORD_ON 0x04 // 7 0 enabled +#define RADIOLIB_SX128X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX128X_LORA_HEADER_IMPLICIT 0x80 // 7 0 implicit +#define RADIOLIB_SX128X_LORA_CRC_OFF 0x00 // 7 0 LoRa packet CRC: disabled +#define RADIOLIB_SX128X_LORA_CRC_ON 0x20 // 7 0 enabled +#define RADIOLIB_SX128X_LORA_IQ_STANDARD 0x40 // 7 0 LoRa IQ: standard +#define RADIOLIB_SX128X_LORA_IQ_INVERTED 0x00 // 7 0 inverted //RADIOLIB_SX128X_CMD_GET_PACKET_STATUS -#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_ERROR 0b01000000 // 6 6 packet status errors byte: sync word error -#define RADIOLIB_SX128X_PACKET_STATUS_LENGTH_ERROR 0b00100000 // 5 5 packet length error -#define RADIOLIB_SX128X_PACKET_STATUS_CRC_ERROR 0b00010000 // 4 4 CRC error -#define RADIOLIB_SX128X_PACKET_STATUS_ABORT_ERROR 0b00001000 // 3 3 packet reception aborted -#define RADIOLIB_SX128X_PACKET_STATUS_HEADER_RECEIVED 0b00000100 // 2 2 header received -#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_RECEIVED 0b00000010 // 1 1 packet received -#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_CTRL_BUSY 0b00000001 // 0 0 packet controller is busy -#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID 0b11000000 // 7 6 packet status status byte: PID field of the received packet -#define RADIOLIB_SX128X_PACKET_STATUS_NO_ACK 0b00100000 // 5 5 NO_ACK field of the received packet -#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID_ERROR 0b00010000 // 4 4 PID field error -#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_SENT 0b00000001 // 0 0 packet sent -#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_ERROR 0b00000000 // 2 0 packet status sync byte: sync word detection error -#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_1 0b00000001 // 2 0 detected sync word 1 -#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_2 0b00000010 // 2 0 detected sync word 2 -#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_ERROR 0b01000000 // 6 6 packet status errors byte: sync word error +#define RADIOLIB_SX128X_PACKET_STATUS_LENGTH_ERROR 0b00100000 // 5 5 packet length error +#define RADIOLIB_SX128X_PACKET_STATUS_CRC_ERROR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX128X_PACKET_STATUS_ABORT_ERROR 0b00001000 // 3 3 packet reception aborted +#define RADIOLIB_SX128X_PACKET_STATUS_HEADER_RECEIVED 0b00000100 // 2 2 header received +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_RECEIVED 0b00000010 // 1 1 packet received +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_CTRL_BUSY 0b00000001 // 0 0 packet controller is busy +#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID 0b11000000 // 7 6 packet status status byte: PID field of the received packet +#define RADIOLIB_SX128X_PACKET_STATUS_NO_ACK 0b00100000 // 5 5 NO_ACK field of the received packet +#define RADIOLIB_SX128X_PACKET_STATUS_RX_PID_ERROR 0b00010000 // 4 4 PID field error +#define RADIOLIB_SX128X_PACKET_STATUS_PACKET_SENT 0b00000001 // 0 0 packet sent +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_ERROR 0b00000000 // 2 0 packet status sync byte: sync word detection error +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_1 0b00000001 // 2 0 detected sync word 1 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_2 0b00000010 // 2 0 detected sync word 2 +#define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 //RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected -#define RADIOLIB_SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done -#define RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout -#define RADIOLIB_SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected -#define RADIOLIB_SX128X_IRQ_CAD_DONE 0x1000 // 12 12 CAD finished -#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_VALID 0x0800 // 11 11 ranging request valid (slave) -#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_TIMEOUT 0x0400 // 10 10 ranging timeout (master) -#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID 0x0200 // 9 9 ranging result valid (master) -#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD 0x0100 // 8 8 ranging result valid (master) -#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE 0x0080 // 7 7 ranging response complete (slave) -#define RADIOLIB_SX128X_IRQ_CRC_ERROR 0x0040 // 6 6 CRC error -#define RADIOLIB_SX128X_IRQ_HEADER_ERROR 0x0020 // 5 5 header error -#define RADIOLIB_SX128X_IRQ_HEADER_VALID 0x0010 // 4 4 header valid -#define RADIOLIB_SX128X_IRQ_SYNC_WORD_ERROR 0x0008 // 3 3 sync word error -#define RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid -#define RADIOLIB_SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done -#define RADIOLIB_SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done -#define RADIOLIB_SX128X_IRQ_RX_DEFAULT 0x4062 // 15 0 default for Rx (RX_DONE, RX_TX_TIMEOUT, CRC_ERROR and HEADER_ERROR) -#define RADIOLIB_SX128X_IRQ_NONE 0x0000 // 15 0 none -#define RADIOLIB_SX128X_IRQ_ALL 0xFFFF // 15 0 all +#define RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected +#define RADIOLIB_SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done +#define RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout +#define RADIOLIB_SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected +#define RADIOLIB_SX128X_IRQ_CAD_DONE 0x1000 // 12 12 CAD finished +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_VALID 0x0800 // 11 11 ranging request valid (slave) +#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_TIMEOUT 0x0400 // 10 10 ranging timeout (master) +#define RADIOLIB_SX128X_IRQ_RANGING_MASTER_RES_VALID 0x0200 // 9 9 ranging result valid (master) +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD 0x0100 // 8 8 ranging result valid (master) +#define RADIOLIB_SX128X_IRQ_RANGING_SLAVE_RESP_DONE 0x0080 // 7 7 ranging response complete (slave) +#define RADIOLIB_SX128X_IRQ_CRC_ERROR 0x0040 // 6 6 CRC error +#define RADIOLIB_SX128X_IRQ_HEADER_ERROR 0x0020 // 5 5 header error +#define RADIOLIB_SX128X_IRQ_HEADER_VALID 0x0010 // 4 4 header valid +#define RADIOLIB_SX128X_IRQ_SYNC_WORD_ERROR 0x0008 // 3 3 sync word error +#define RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid +#define RADIOLIB_SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done +#define RADIOLIB_SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done +#define RADIOLIB_SX128X_IRQ_RX_DEFAULT 0x4062 // 15 0 default for Rx (RX_DONE, RX_TX_TIMEOUT, CRC_ERROR and HEADER_ERROR) +#define RADIOLIB_SX128X_IRQ_NONE 0x0000 // 15 0 none +#define RADIOLIB_SX128X_IRQ_ALL 0xFFFF // 15 0 all //RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE -#define RADIOLIB_SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) -#define RADIOLIB_SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC +#define RADIOLIB_SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC //RADIOLIB_SX128X_CMD_SET_RANGING_ROLE -#define RADIOLIB_SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master -#define RADIOLIB_SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave +#define RADIOLIB_SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master +#define RADIOLIB_SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave //RADIOLIB_SX128X_REG_LORA_SYNC_WORD_1 - RADIOLIB_SX128X_REG_LORA_SYNC_WORD_2 -#define RADIOLIB_SX128X_SYNC_WORD_PRIVATE 0x12 +#define RADIOLIB_SX128X_SYNC_WORD_PRIVATE 0x12 /*! \class SX128x - \brief Base class for %SX128x series. All derived classes for %SX128x (e.g. SX1280 or SX1281) inherit from this base class. This class should not be instantiated directly from Arduino sketch, only from its derived classes. */ @@ -358,7 +357,6 @@ class SX128x: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. */ SX128x(Module* mod); @@ -369,84 +367,55 @@ class SX128x: public PhysicalLayer { /*! \brief Initialization method for LoRa modem. - \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. - \param bw LoRa bandwidth in kHz. Defaults to 812.5 kHz. - \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). - \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX128X_SYNC_WORD_PRIVATE (0x12). - - \param power Output power in dBm. Defaults to 10 dBm. - + \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 12 symbols. - \returns \ref status_codes */ - int16_t begin(float freq = 2400.0, float bw = 812.5, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX128X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 12); + int16_t begin(float freq = 2400.0, float bw = 812.5, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX128X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 12); /*! \brief Initialization method for GFSK modem. - \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. - \param br FSK bit rate in kbps. Defaults to 800 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 400.0 kHz. - - \param power Output power in dBm. Defaults to 10 dBm. - + \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength FSK preamble length in bits. Defaults to 16 bits. - \returns \ref status_codes */ - int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16); + int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t pwr = 10, uint16_t preambleLength = 16); /*! \brief Initialization method for BLE modem. - \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. - \param br BLE bit rate in kbps. Defaults to 800 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 400.0 kHz. - - \param power Output power in dBm. Defaults to 10 dBm. - + \param pwr Output power in dBm. Defaults to 10 dBm. \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. - \returns \ref status_codes */ - int16_t beginBLE(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); + int16_t beginBLE(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t pwr = 10, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); /*! \brief Initialization method for FLRC modem. - \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. - \param br FLRC bit rate in kbps. Defaults to 650 kbps. - \param cr FLRC coding rate. Defaults to 3 (coding rate 3/4). - - \param power Output power in dBm. Defaults to 10 dBm. - + \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength FLRC preamble length in bits. Defaults to 16 bits. - \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. - \returns \ref status_codes */ - int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t power = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); + int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t pwr = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); /*! \brief Reset method. Will reset the chip to the default state using RST pin. - \param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly by repeatedly issuing setStandby command. Enabled by default. - \returns \ref status_codes */ int16_t reset(bool verify = true); @@ -454,13 +423,9 @@ class SX128x: public PhysicalLayer { /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Unsupported, compatibility only. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; @@ -468,60 +433,50 @@ class SX128x: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; /*! \brief Starts direct mode transmission. - \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! - \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX128x series does not support direct mode reception. - Will always return RADIOLIB_ERR_UNKNOWN. - + \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, + as %SX128x series does not support direct mode reception. Will always return RADIOLIB_ERR_UNKNOWN. \returns \ref status_codes */ int16_t receiveDirect() override; /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. - \returns \ref status_codes */ int16_t scanChannel(); /*! \brief Sets the module to sleep mode. - - \param retainConfig Set to true to retain configuration and data buffer or to false to discard current configuration and data buffer. Defaults to true. - + \param retainConfig Set to true to retain configuration and data buffer or to false + to discard current configuration and data buffer. Defaults to true. \returns \ref status_codes */ int16_t sleep(bool retainConfig = true); /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the module to standby mode. - - \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). - + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC + (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). \returns \ref status_codes */ int16_t standby(uint8_t mode); @@ -530,7 +485,6 @@ class SX128x: public PhysicalLayer { /*! \brief Sets interrupt service routine to call when DIO1 activates. - \param func ISR to call. */ void setDio1Action(void (*func)(void)); @@ -543,36 +497,29 @@ class SX128x: public PhysicalLayer { /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Unsupported, compatibility only. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - - \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to + RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), + set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). If timeout other than infinite is set, signal will be generated on DIO1. \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX128X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX128X_IRQ_RX_DONE. - \param len Only for PhysicalLayer compatibility, not used. - \returns \ref status_codes */ int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); @@ -585,12 +532,9 @@ class SX128x: public PhysicalLayer { /*! \brief Reads data received after calling startReceive method. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; @@ -599,74 +543,59 @@ class SX128x: public PhysicalLayer { /*! \brief Sets carrier frequency. Allowed values are in range from 2400.0 to 2500.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets LoRa bandwidth. Allowed values are 203.125, 406.25, 812.5 and 1625.0 kHz. - \param bw LoRa bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setBandwidth(float bw); /*! \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. - \param sf LoRa spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. - \param cr LoRa coding rate denominator to be set. - - \param longInterleaving Whether to enable long interleaving mode. Not available for coding rate 4/7, defaults to false. - + \param longInterleaving Whether to enable long interleaving mode. Not available for coding rate 4/7, + defaults to false. \returns \ref status_codes */ int16_t setCodingRate(uint8_t cr, bool longInterleaving = false); /*! \brief Sets output power. Allowed values are in range from -18 to 13 dBm. - - \param power Output power to be set in dBm. - + \param pwr Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t pwr); /*! \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. - \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC). - \returns \ref status_codes */ int16_t setPreambleLength(uint32_t preambleLength); /*! - \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem). - + \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, + 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem). \param br FSK/FLRC bit rate to be set in kbps. - \returns \ref status_codes */ int16_t setBitRate(float br); /*! \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 3200.0 kHz. - \param freqDev FSK frequency deviation to be set in kHz. - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; @@ -674,144 +603,113 @@ class SX128x: public PhysicalLayer { /*! \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Time-bandwidth product of Gaussian filter to be set. - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; /*! - \brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, the sync word must be exactly 4 bytes long - + \brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, + the sync word must be exactly 4 bytes long \param syncWord Sync word to be set. - \param len Sync word length in bytes. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t* syncWord, uint8_t len); /*! \brief Sets LoRa sync word. - \param syncWord LoRa sync word to be set. - \param controlBits Undocumented control bits, required for compatibility purposes. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t syncWord, uint8_t controlBits = 0x44); /*! \brief Sets CRC configuration. - \param len CRC length in bytes, Allowed values are 1, 2 or 3, set to 0 to disable CRC. - \param initial Initial CRC value. Defaults to 0x1D0F (CCIT CRC), not available for LoRa modem. - \param polynomial Polynomial for CRC calculation. Defaults to 0x1021 (CCIT CRC), not available for LoRa or BLE modem. - \returns \ref status_codes */ int16_t setCRC(uint8_t len, uint32_t initial = 0x1D0F, uint16_t polynomial = 0x1021); /*! \brief Sets whitening parameters, not available for LoRa or FLRC modem. - \param enabled Set to true to enable whitening. - \returns \ref status_codes */ int16_t setWhitening(bool enabled); /*! \brief Sets BLE access address. - \param addr BLE access address. - \returns \ref status_codes */ int16_t setAccessAddress(uint32_t addr); /*! \brief Enables or disables receiver high sensitivity mode. - - \param True to enable and false to disable. - - \returns 0 + \param enable True to enable and false to disable. + \returns \ref status_codes */ - int16_t setHighSensitivityMode(bool hsm = false); + int16_t setHighSensitivityMode(bool enable); /*! \brief Enables or disables receiver manual gain control. - \param gain Use 0 for automatic gain, 1 for minimum gain and up to 13 for maximum gain. - - \returns 0 + \returns \ref status_codes */ int16_t setGainControl(uint8_t gain = 0); /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. - \returns RSSI of the last received packet in dBm. */ float getRSSI(); /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa or ranging modem. - \returns SNR of the last received packet in dB. */ float getSNR(); /*! \brief Gets frequency error of the latest received packet. - \returns Frequency error in Hz. */ float getFrequencyError(); /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! \brief Get expected time-on-air for a given size of payload. - \param len Payload length in bytes. - \returns Expected time-on-air in microseconds. */ uint32_t getTimeOnAir(size_t len); /*! \brief Set implicit header mode for future reception/transmission. - \returns \ref status_codes */ int16_t implicitHeader(size_t len); /*! \brief Set explicit header mode for future reception/transmission. - \param len Payload length in bytes. - \returns \ref status_codes */ int16_t explicitHeader(); /*! \brief Sets transmission encoding. Serves only as alias for PhysicalLayer compatibility. - \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; @@ -824,31 +722,26 @@ class SX128x: public PhysicalLayer { /*! \brief Dummy random method, to ensure PhysicalLayer compatibility. - \returns Always returns 0. */ uint8_t randomByte(); /*! \brief Enable/disable inversion of the I and Q signals - - \param invertIQ QI inversion enabled (true) or disabled (false); - + \param enable QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ - int16_t invertIQ(bool invertIQ); + int16_t invertIQ(bool enable); #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Dummy method, to ensure PhysicalLayer compatibility. - \param func Ignored. */ void setDirectAction(void (*func)(void)); /*! \brief Dummy method, to ensure PhysicalLayer compatibility. - \param pin Ignored. */ void readBit(uint32_t pin); @@ -857,16 +750,16 @@ class SX128x: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; #if !defined(RADIOLIB_GODMODE) protected: #endif // cached LoRa parameters - float _bwKhz = 0; - uint8_t _bw = 0, _sf = 0, _cr = 0; - uint8_t _preambleLengthLoRa = 0, _headerType = 0, _payloadLen = 0, _crcLoRa = 0; + float bandwidthKhz = 0; + uint8_t bandwidth = 0, spreadingFactor = 0, codingRateLoRa = 0; + uint8_t preambleLengthLoRa = 0, headerType = 0, payloadLen = 0, crcLoRa = 0; // SX128x SPI command implementations uint8_t getStatus(); @@ -879,18 +772,18 @@ class SX128x: public PhysicalLayer { int16_t setCad(); uint8_t getPacketType(); int16_t setRfFrequency(uint32_t frf); - int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US); + int16_t setTxParams(uint8_t pwr, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3); - int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen = 0xFF, uint8_t headerType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE); - int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening); - int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD); + int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen = 0xFF, uint8_t hdrType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE); + int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten); + int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX128X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX128X_IRQ_NONE); int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX128X_IRQ_ALL); int16_t setRangingRole(uint8_t role); int16_t setPacketType(uint8_t type); - int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) private: @@ -903,22 +796,22 @@ class SX128x: public PhysicalLayer { private: #endif // common parameters - uint8_t _pwr = 0; + uint8_t power = 0; // cached LoRa parameters - uint8_t _invertIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD; + uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD; // cached GFSK parameters - float _modIndexReal = 0; - uint16_t _brKbps = 0; - uint8_t _br = 0, _modIndex = 0, _shaping = 0; - uint8_t _preambleLengthGFSK = 0, _syncWordLen = 0, _syncWordMatch = 0, _crcGFSK = 0, _whitening = 0; + float modIndexReal = 0; + uint16_t bitRateKbps = 0; + uint8_t bitRate = 0, modIndex = 0, shaping = 0; + uint8_t preambleLengthGFSK = 0, syncWordLen = 0, syncWordMatch = 0, crcGFSK = 0, whitening = 0; // cached FLRC parameters - uint8_t _crFLRC = 0; + uint8_t codingRateFLRC = 0; // cached BLE parameters - uint8_t _connectionState = 0, _crcBLE = 0, _bleTestPayload = 0; + uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0; int16_t config(uint8_t modem); }; From cc8c8f2eedbe6162d1fa73967c9be25afee5f99b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Apr 2023 22:42:13 +0200 Subject: [PATCH 0523/1848] [SX127x] General reformatting --- src/modules/RFM9x/RFM95.cpp | 2 +- src/modules/RFM9x/RFM95.h | 25 +- src/modules/RFM9x/RFM96.cpp | 2 +- src/modules/RFM9x/RFM96.h | 40 +- src/modules/RFM9x/RFM97.cpp | 2 +- src/modules/RFM9x/RFM97.h | 4 - src/modules/SX127x/SX1272.cpp | 134 ++-- src/modules/SX127x/SX1272.h | 160 ++-- src/modules/SX127x/SX1273.cpp | 2 +- src/modules/SX127x/SX1273.h | 13 - src/modules/SX127x/SX1276.cpp | 2 +- src/modules/SX127x/SX1276.h | 21 - src/modules/SX127x/SX1277.cpp | 4 +- src/modules/SX127x/SX1277.h | 23 - src/modules/SX127x/SX1278.cpp | 182 ++--- src/modules/SX127x/SX1278.h | 184 ++--- src/modules/SX127x/SX1279.cpp | 2 +- src/modules/SX127x/SX1279.h | 21 - src/modules/SX127x/SX127x.cpp | 482 ++++++------ src/modules/SX127x/SX127x.h | 1335 +++++++++++++++------------------ 20 files changed, 1141 insertions(+), 1499 deletions(-) diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 892fc53c6f..90f1bc46f1 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -85,7 +85,7 @@ int16_t RFM95::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } diff --git a/src/modules/RFM9x/RFM95.h b/src/modules/RFM9x/RFM95.h index 18d2a91eba..c0128003df 100644 --- a/src/modules/RFM9x/RFM95.h +++ b/src/modules/RFM9x/RFM95.h @@ -10,12 +10,11 @@ #include "../SX127x/SX1278.h" // SX127X_REG_VERSION -#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 -#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 +#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 +#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 /*! \class RFM95 - \brief Derived class for %RFM95 modules. Overrides some methods from SX1278 due to different parameter ranges. */ class RFM95: public SX1278 { @@ -25,7 +24,6 @@ class RFM95: public SX1278 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ RFM95(Module* mod); @@ -34,47 +32,30 @@ class RFM95: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 868.0 MHz to 915.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -83,9 +64,7 @@ class RFM95: public SX1278 { /*! \brief Sets carrier frequency. Allowed values range from 868.0 MHz to 915.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index 2f7f451a35..0c74418402 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -86,7 +86,7 @@ int16_t RFM96::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h index 51bd481a0d..e599019784 100644 --- a/src/modules/RFM9x/RFM96.h +++ b/src/modules/RFM9x/RFM96.h @@ -10,12 +10,11 @@ #include "../SX127x/SX1278.h" // SX127X_REG_VERSION -#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 -#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 +#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 +#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 /*! \class RFM96 - \brief Derived class for %RFM96 modules. Overrides some methods from SX1278 due to different parameter ranges. */ class RFM96: public SX1278 { @@ -25,7 +24,6 @@ class RFM96: public SX1278 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ RFM96(Module* mod); @@ -34,47 +32,32 @@ class RFM96: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 433.0 MHz to 470.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - + \param syncWord %LoRa sync word. Can be used to distinguish different networks. + Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. - Allowed values range from 6 to 65535. - - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. - Set to 0 to enable automatic gain control (recommended). - + \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols + longer than the set number. Allowed values range from 6 to 65535. + \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 + where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, + 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -83,9 +66,7 @@ class RFM96: public SX1278 { /*! \brief Sets carrier frequency. Allowed values range from 433.0 MHz to 470.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); @@ -98,7 +79,6 @@ class RFM96: public SX1278 { /*! \class RFM98 - \brief Only exists as alias for RFM96, since there seems to be no difference between %RFM96 and %RFM98 modules. */ RADIOLIB_TYPE_ALIAS(RFM96, RFM98); diff --git a/src/modules/RFM9x/RFM97.cpp b/src/modules/RFM9x/RFM97.cpp index e51e5a9945..0d02c70765 100644 --- a/src/modules/RFM9x/RFM97.cpp +++ b/src/modules/RFM9x/RFM97.cpp @@ -34,7 +34,7 @@ int16_t RFM97::setSpreadingFactor(uint8_t sf) { // set spreading factor and if successful, save the new setting int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); if(state == RADIOLIB_ERR_NONE) { - SX127x::_sf = sf; + SX127x::spreadingFactor = sf; } return(state); } diff --git a/src/modules/RFM9x/RFM97.h b/src/modules/RFM9x/RFM97.h index aee0c0ad7c..b462349503 100644 --- a/src/modules/RFM9x/RFM97.h +++ b/src/modules/RFM9x/RFM97.h @@ -12,7 +12,6 @@ /*! \class RFM97 - \brief Derived class for %RFM97 modules. Overrides some methods from RFM95 due to different parameter ranges. */ class RFM97: public RFM95 { @@ -22,7 +21,6 @@ class RFM97: public RFM95 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ RFM97(Module* mod); @@ -31,9 +29,7 @@ class RFM97: public RFM95 { /*! \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. - \param sf %LoRa link spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index cd1514f11c..5ab4c1362b 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -72,11 +72,11 @@ int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1272::reset() { - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); - _mod->hal->delay(5); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(5); } int16_t SX1272::setFrequency(float freq) { @@ -85,7 +85,7 @@ int16_t SX1272::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } @@ -112,16 +112,16 @@ int16_t SX1272::setBandwidth(float bw) { // set bandwidth and if successful, save the new setting int16_t state = SX1272::setBandwidthRaw(newBandwidth); if(state == RADIOLIB_ERR_NONE) { - SX127x::_bw = bw; + SX127x::bandwidth = bw; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled - if(_ldroAuto) { - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } @@ -166,16 +166,16 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { // set spreading factor and if successful, save the new setting int16_t state = SX1272::setSpreadingFactorRaw(newSpreadingFactor); if(state == RADIOLIB_ERR_NONE) { - SX127x::_sf = sf; + SX127x::spreadingFactor = sf; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled - if(_ldroAuto) { - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } @@ -211,7 +211,7 @@ int16_t SX1272::setCodingRate(uint8_t cr) { // set coding rate and if successful, save the new setting int16_t state = SX1272::setCodingRateRaw(newCodingRate); if(state == RADIOLIB_ERR_NONE) { - SX127x::_cr = cr; + SX127x::codingRate = cr; } return(state); } @@ -233,22 +233,22 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { if(useRfo) { // RFO output - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power <= 17) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } @@ -272,20 +272,20 @@ int16_t SX1272::setGain(uint8_t gain) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } @@ -300,7 +300,7 @@ int16_t SX1272::setDataShaping(uint8_t sh) { } // check modulation - if(SX127x::_ook) { + if(SX127x::ookEnabled) { return(RADIOLIB_ERR_INVALID_MODULATION); } @@ -311,13 +311,13 @@ int16_t SX1272::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); case RADIOLIB_SHAPING_0_3: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } @@ -330,7 +330,7 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { } // check modulation - if(!SX127x::_ook) { + if(!SX127x::ookEnabled) { return(RADIOLIB_ERR_INVALID_MODULATION); } @@ -340,13 +340,13 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { // set data shaping switch(sh) { case 0: - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); break; case 1: - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); break; case 2: - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); break; default: state = RADIOLIB_ERR_INVALID_DATA_SHAPING; @@ -363,27 +363,27 @@ float SX1272::getRSSI(bool packet, bool skipReceive) { int16_t SX1272::setCRC(bool enable, bool mode) { if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC - SX127x::_crcEnabled = enable; + SX127x::crcEnabled = enable; if(enable) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_ON, 2, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_ON, 2, 2)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 2, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 2, 2)); } } else { // set FSK CRC int16_t state = RADIOLIB_ERR_NONE; if(enable) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } @@ -393,11 +393,11 @@ int16_t SX1272::forceLDRO(bool enable) { return(RADIOLIB_ERR_WRONG_MODEM); } - _ldroAuto = false; + this->ldroAuto = false; if(enable) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); } } @@ -406,7 +406,7 @@ int16_t SX1272::autoLDRO() { return(RADIOLIB_ERR_WRONG_MODEM); } - _ldroAuto = true; + this->ldroAuto = true; return(RADIOLIB_ERR_NONE); } @@ -423,7 +423,7 @@ int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); return(state); } @@ -433,15 +433,15 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::_crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::_crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } @@ -451,7 +451,7 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); return(state); } @@ -462,15 +462,15 @@ int16_t SX1272::setHeaderType(uint8_t headerType, size_t len) { } // set requested packet mode - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value - _packetLength = len; + SX127x::packetLength = len; return(state); } @@ -481,7 +481,7 @@ int16_t SX1272::configFSK() { RADIOLIB_ASSERT(state); // set fast PLL hop - state = _mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } @@ -490,7 +490,7 @@ void SX1272::errataFix(bool rx) { // mitigation of receiver spurious response // see SX1272/73 Errata, section 2.2 for details - _mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); + this->mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); } #endif diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index ccd21fdbd8..f997647dd4 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -9,86 +9,85 @@ #include "SX127x.h" // SX1272 specific register map -#define RADIOLIB_SX1272_REG_AGC_REF 0x43 -#define RADIOLIB_SX1272_REG_AGC_THRESH_1 0x44 -#define RADIOLIB_SX1272_REG_AGC_THRESH_2 0x45 -#define RADIOLIB_SX1272_REG_AGC_THRESH_3 0x46 -#define RADIOLIB_SX1272_REG_PLL_HOP 0x4B -#define RADIOLIB_SX1272_REG_TCXO 0x58 -#define RADIOLIB_SX1272_REG_PA_DAC 0x5A -#define RADIOLIB_SX1272_REG_PLL 0x5C -#define RADIOLIB_SX1272_REG_PLL_LOW_PN 0x5E -#define RADIOLIB_SX1272_REG_FORMER_TEMP 0x6C -#define RADIOLIB_SX1272_REG_BIT_RATE_FRAC 0x70 +#define RADIOLIB_SX1272_REG_AGC_REF 0x43 +#define RADIOLIB_SX1272_REG_AGC_THRESH_1 0x44 +#define RADIOLIB_SX1272_REG_AGC_THRESH_2 0x45 +#define RADIOLIB_SX1272_REG_AGC_THRESH_3 0x46 +#define RADIOLIB_SX1272_REG_PLL_HOP 0x4B +#define RADIOLIB_SX1272_REG_TCXO 0x58 +#define RADIOLIB_SX1272_REG_PA_DAC 0x5A +#define RADIOLIB_SX1272_REG_PLL 0x5C +#define RADIOLIB_SX1272_REG_PLL_LOW_PN 0x5E +#define RADIOLIB_SX1272_REG_FORMER_TEMP 0x6C +#define RADIOLIB_SX1272_REG_BIT_RATE_FRAC 0x70 // SX1272 LoRa modem settings // RADIOLIB_SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB -#define RADIOLIB_SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 -#define RADIOLIB_SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz -#define RADIOLIB_SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers +#define RADIOLIB_SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers // RADIOLIB_SX127X_REG_MODEM_CONFIG_1 -#define RADIOLIB_SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz -#define RADIOLIB_SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz -#define RADIOLIB_SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz -#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5 -#define RADIOLIB_SX1272_CR_4_6 0b00010000 // 5 3 4/6 -#define RADIOLIB_SX1272_CR_4_7 0b00011000 // 5 3 4/7 -#define RADIOLIB_SX1272_CR_4_8 0b00100000 // 5 3 4/8 -#define RADIOLIB_SX1272_HEADER_EXPL_MODE 0b00000000 // 2 2 explicit header mode -#define RADIOLIB_SX1272_HEADER_IMPL_MODE 0b00000100 // 2 2 implicit header mode -#define RADIOLIB_SX1272_RX_CRC_MODE_OFF 0b00000000 // 1 1 CRC disabled -#define RADIOLIB_SX1272_RX_CRC_MODE_ON 0b00000010 // 1 1 CRC enabled -#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled -#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz +#define RADIOLIB_SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz +#define RADIOLIB_SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz +#define RADIOLIB_SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz +#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5 +#define RADIOLIB_SX1272_CR_4_6 0b00010000 // 5 3 4/6 +#define RADIOLIB_SX1272_CR_4_7 0b00011000 // 5 3 4/7 +#define RADIOLIB_SX1272_CR_4_8 0b00100000 // 5 3 4/8 +#define RADIOLIB_SX1272_HEADER_EXPL_MODE 0b00000000 // 2 2 explicit header mode +#define RADIOLIB_SX1272_HEADER_IMPL_MODE 0b00000100 // 2 2 implicit header mode +#define RADIOLIB_SX1272_RX_CRC_MODE_OFF 0b00000000 // 1 1 CRC disabled +#define RADIOLIB_SX1272_RX_CRC_MODE_ON 0b00000010 // 1 1 CRC enabled +#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled +#define RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz // RADIOLIB_SX127X_REG_MODEM_CONFIG_2 -#define RADIOLIB_SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA -#define RADIOLIB_SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop +#define RADIOLIB_SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA +#define RADIOLIB_SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop // RADIOLIB_SX127X_REG_VERSION -#define RADIOLIB_SX1272_CHIP_VERSION 0x22 +#define RADIOLIB_SX1272_CHIP_VERSION 0x22 // SX1272 FSK modem settings // RADIOLIB_SX127X_REG_OP_MODE -#define RADIOLIB_SX1272_NO_SHAPING 0b00000000 // 4 3 data shaping: no shaping (default) -#define RADIOLIB_SX1272_FSK_GAUSSIAN_1_0 0b00001000 // 4 3 FSK modulation Gaussian filter, BT = 1.0 -#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_5 0b00010000 // 4 3 FSK modulation Gaussian filter, BT = 0.5 -#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_3 0b00011000 // 4 3 FSK modulation Gaussian filter, BT = 0.3 -#define RADIOLIB_SX1272_OOK_FILTER_BR 0b00001000 // 4 3 OOK modulation filter, f_cutoff = BR -#define RADIOLIB_SX1272_OOK_FILTER_2BR 0b00010000 // 4 3 OOK modulation filter, f_cutoff = 2*BR +#define RADIOLIB_SX1272_NO_SHAPING 0b00000000 // 4 3 data shaping: no shaping (default) +#define RADIOLIB_SX1272_FSK_GAUSSIAN_1_0 0b00001000 // 4 3 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_5 0b00010000 // 4 3 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_SX1272_FSK_GAUSSIAN_0_3 0b00011000 // 4 3 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_SX1272_OOK_FILTER_BR 0b00001000 // 4 3 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_SX1272_OOK_FILTER_2BR 0b00010000 // 4 3 OOK modulation filter, f_cutoff = 2*BR // RADIOLIB_SX127X_REG_PA_RAMP -#define RADIOLIB_SX1272_LOW_PN_TX_PLL_OFF 0b00010000 // 4 4 use standard PLL in transmit mode (default) -#define RADIOLIB_SX1272_LOW_PN_TX_PLL_ON 0b00000000 // 4 4 use lower phase noise PLL in transmit mode +#define RADIOLIB_SX1272_LOW_PN_TX_PLL_OFF 0b00010000 // 4 4 use standard PLL in transmit mode (default) +#define RADIOLIB_SX1272_LOW_PN_TX_PLL_ON 0b00000000 // 4 4 use lower phase noise PLL in transmit mode // RADIOLIB_SX127X_REG_SYNC_CONFIG -#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_SYNC_ADDRESS 0b00000000 // 3 3 FIFO will be filled when sync address interrupt occurs (default) -#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_ALWAYS 0b00001000 // 3 3 FIFO will be filled as long as this bit is set +#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_SYNC_ADDRESS 0b00000000 // 3 3 FIFO will be filled when sync address interrupt occurs (default) +#define RADIOLIB_SX1272_FIFO_FILL_CONDITION_ALWAYS 0b00001000 // 3 3 FIFO will be filled as long as this bit is set // RADIOLIB_SX1272_REG_AGC_REF -#define RADIOLIB_SX1272_AGC_REFERENCE_LEVEL 0x13 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm] +#define RADIOLIB_SX1272_AGC_REFERENCE_LEVEL 0x13 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm] // RADIOLIB_SX1272_REG_AGC_THRESH_1 -#define RADIOLIB_SX1272_AGC_STEP_1 0x0E // 4 0 1st AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_1 0x0E // 4 0 1st AGC threshold // RADIOLIB_SX1272_REG_AGC_THRESH_2 -#define RADIOLIB_SX1272_AGC_STEP_2 0x50 // 7 4 2nd AGC threshold -#define RADIOLIB_SX1272_AGC_STEP_3 0x0B // 4 0 3rd AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_2 0x50 // 7 4 2nd AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_3 0x0B // 4 0 3rd AGC threshold // RADIOLIB_SX1272_REG_AGC_THRESH_3 -#define RADIOLIB_SX1272_AGC_STEP_4 0xD0 // 7 4 4th AGC threshold -#define RADIOLIB_SX1272_AGC_STEP_5 0x0B // 4 0 5th AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_4 0xD0 // 7 4 4th AGC threshold +#define RADIOLIB_SX1272_AGC_STEP_5 0x0B // 4 0 5th AGC threshold // RADIOLIB_SX1272_REG_PLL_LOW_PN -#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_75_KHZ 0b00000000 // 7 6 low phase noise PLL bandwidth: 75 kHz -#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz -#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz -#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_75_KHZ 0b00000000 // 7 6 low phase noise PLL bandwidth: 75 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define RADIOLIB_SX1272_PLL_LOW_PN_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) /*! \class SX1272 - \brief Derived class for %SX1272 modules. Also used as base class for SX1273. Both modules use the same basic hardware and only differ in parameter ranges. */ @@ -99,7 +98,6 @@ class SX1272: public SX127x { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX1272(Module* mod); @@ -108,48 +106,31 @@ class SX1272: public SX127x { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 915.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -163,56 +144,43 @@ class SX1272: public SX127x { /*! \brief Sets carrier frequency. Allowed values range from 860.0 MHz to 1020.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets %LoRa link bandwidth. Allowed values are 125, 250 and 500 kHz. Only available in %LoRa mode. - \param bw %LoRa link bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setBandwidth(float bw); /*! \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode. - \param sf %LoRa link spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. - \param cr %LoRa link coding rate denominator to be set. - \returns \ref status_codes */ int16_t setCodingRate(uint8_t cr); /*! \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. - \param br Bit rate to be set (in kbps). - \returns \ref status_codes */ int16_t setBitRate(float br) override; /*! \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). - \param power Transmission output power in dBm. - \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. Defaults to PA_BOOST. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power, bool useRfo = false); @@ -220,9 +188,7 @@ class SX1272: public SX127x { /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \param gain Gain of receiver LNA (low-noise amplifier) to be set. - \returns \ref status_codes */ int16_t setGain(uint8_t gain); @@ -230,9 +196,7 @@ class SX1272: public SX127x { /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Gaussian shaping bandwidth-time product that will be used for data shaping - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; @@ -241,31 +205,25 @@ class SX1272: public SX127x { \brief Sets filter cutoff frequency that will be used for data shaping. Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping. Only available in FSK mode with OOK modulation. - \param sh Cutoff frequency that will be used for data shaping - \returns \ref status_codes */ int16_t setDataShapingOOK(uint8_t sh); /*! \brief Gets recorded signal strength indicator. - \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. - \returns RSSI value in dBm. */ float getRSSI(bool packet = true, bool skipReceive = false); /*! \brief Enables/disables CRC check of received packets. - \param enable Enable (true) or disable (false) CRC. - - \param mode Set CRC mode to RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) or RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. - + \param mode Set CRC mode to RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, + polynomial X16 + X12 + X5 + 1 (false) or RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM for IBM, + polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. \returns \ref status_codes */ int16_t setCRC(bool enable, bool mode = false); @@ -273,9 +231,7 @@ class SX1272: public SX127x { /*! \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX1278::autoLDRO() - \param enable Force LDRO to be always enabled (true) or disabled (false). - \returns \ref status_codes */ int16_t forceLDRO(bool enable); @@ -283,23 +239,19 @@ class SX1272: public SX127x { /*! \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically when symbol length exceeds 16 ms. - \returns \ref status_codes */ int16_t autoLDRO(); /*! - \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. - + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. \param len Payload length in bytes. - \returns \ref status_codes */ int16_t implicitHeader(size_t len); /*! \brief Set explicit header mode for future reception/transmission. - \returns \ref status_codes */ int16_t explicitHeader(); @@ -318,8 +270,8 @@ class SX1272: public SX127x { #if !defined(RADIOLIB_GODMODE) private: #endif - bool _ldroAuto = true; - bool _ldroEnabled = false; + bool ldroAuto = true; + bool ldroEnabled = false; }; diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 06f7b78523..0e4d287c75 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -60,7 +60,7 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) { // set spreading factor and if successful, save the new setting int16_t state = setSpreadingFactorRaw(newSpreadingFactor); if(state == RADIOLIB_ERR_NONE) { - SX127x::_sf = sf; + SX127x::spreadingFactor = sf; } return(state); diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 46127ba5af..4fab62151f 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -9,7 +9,6 @@ /*! \class SX1273 - \brief Derived class for %SX1273 modules. Overrides some methods from SX1272 due to different parameter ranges. */ class SX1273: public SX1272 { @@ -19,7 +18,6 @@ class SX1273: public SX1272 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX1273(Module* mod); @@ -28,25 +26,16 @@ class SX1273: public SX1272 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); @@ -55,9 +44,7 @@ class SX1273: public SX1272 { /*! \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. - \param sf %LoRa link spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index b937a8f45f..21eadb5722 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -72,7 +72,7 @@ int16_t SX1276::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index cdc4cac535..0d83fb367d 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -9,7 +9,6 @@ /*! \class SX1276 - \brief Derived class for %SX1276 modules. Overrides some methods from SX1278 due to different parameter ranges. */ class SX1276: public SX1278 { @@ -19,7 +18,6 @@ class SX1276: public SX1278 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX1276(Module* mod); @@ -28,47 +26,30 @@ class SX1276: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -77,9 +58,7 @@ class SX1276: public SX1278 { /*! \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index cc49a69c21..7e635756c5 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -72,7 +72,7 @@ int16_t SX1277::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } @@ -101,7 +101,7 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { // set spreading factor and if successful, save the new setting int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); if(state == RADIOLIB_ERR_NONE) { - SX127x::_sf = sf; + SX127x::spreadingFactor = sf; } return(state); diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index b9f7a5cf7d..76d8854b18 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -9,7 +9,6 @@ /*! \class SX1277 - \brief Derived class for %SX1277 modules. Overrides some methods from SX1278 due to different parameter ranges. */ class SX1277: public SX1278 { @@ -19,7 +18,6 @@ class SX1277: public SX1278 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX1277(Module* mod); @@ -28,47 +26,30 @@ class SX1277: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -77,18 +58,14 @@ class SX1277: public SX1278 { /*! \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. - \param sf %LoRa link spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 4c8159a42b..a1b92c0d3f 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -72,11 +72,11 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1278::reset() { - _mod->hal->pinMode(_mod->getRst(), _mod->hal->GpioModeOutput); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelLow); - _mod->hal->delay(1); - _mod->hal->digitalWrite(_mod->getRst(), _mod->hal->GpioLevelHigh); - _mod->hal->delay(5); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + this->mod->hal->delay(5); } int16_t SX1278::setFrequency(float freq) { @@ -85,7 +85,7 @@ int16_t SX1278::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } @@ -126,16 +126,16 @@ int16_t SX1278::setBandwidth(float bw) { // set bandwidth and if successful, save the new setting int16_t state = SX1278::setBandwidthRaw(newBandwidth); if(state == RADIOLIB_ERR_NONE) { - SX127x::_bw = bw; + SX127x::bandwidth = bw; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled - if(_ldroAuto) { - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } } @@ -180,16 +180,16 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { // set spreading factor and if successful, save the new setting int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); if(state == RADIOLIB_ERR_NONE) { - SX127x::_sf = sf; + SX127x::spreadingFactor = sf; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled - if(_ldroAuto) { - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; RADIOLIB_DEBUG_PRINT("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } } @@ -225,7 +225,7 @@ int16_t SX1278::setCodingRate(uint8_t cr) { // set coding rate and if successful, save the new setting int16_t state = SX1278::setCodingRateRaw(newCodingRate); if(state == RADIOLIB_ERR_NONE) { - SX127x::_cr = cr; + SX127x::codingRate = cr; } return(state); } @@ -259,22 +259,22 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { paCfg = RADIOLIB_SX1278_MAX_POWER | power; } - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power != 20) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } } @@ -297,20 +297,20 @@ int16_t SX1278::setGain(uint8_t gain) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } @@ -325,7 +325,7 @@ int16_t SX1278::setDataShaping(uint8_t sh) { } // check modulation - if(SX127x::_ook) { + if(SX127x::ookEnabled) { // we're in OOK mode, the only thing we can do is disable if(sh == RADIOLIB_SHAPING_NONE) { return(setDataShapingOOK(0)); @@ -341,13 +341,13 @@ int16_t SX1278::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5)); case RADIOLIB_SHAPING_0_3: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5)); case RADIOLIB_SHAPING_0_5: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5)); case RADIOLIB_SHAPING_1_0: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5)); default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } @@ -360,7 +360,7 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { } // check modulation - if(!SX127x::_ook) { + if(!SX127x::ookEnabled) { return(RADIOLIB_ERR_INVALID_MODULATION); } @@ -370,13 +370,13 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { // set data shaping switch(sh) { case 0: - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5); break; case 1: - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5); break; case 2: - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5); break; default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); @@ -387,7 +387,7 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { float SX1278::getRSSI(bool packet, bool skipReceive) { int16_t offset = -157; - if(_freq < 868.0) { + if(frequency < 868.0) { offset = -164; } return(SX127x::getRSSI(packet, skipReceive, offset)); @@ -396,27 +396,27 @@ float SX1278::getRSSI(bool packet, bool skipReceive) { int16_t SX1278::setCRC(bool enable, bool mode) { if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC - SX127x::_crcEnabled = enable; + SX127x::crcEnabled = enable; if(enable) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2)); } } else { // set FSK CRC int16_t state = RADIOLIB_ERR_NONE; if(enable) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } @@ -426,11 +426,11 @@ int16_t SX1278::forceLDRO(bool enable) { return(RADIOLIB_ERR_WRONG_MODEM); } - _ldroAuto = false; + this->ldroAuto = false; if(enable) { - return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); } } @@ -439,7 +439,7 @@ int16_t SX1278::autoLDRO() { return(RADIOLIB_ERR_WRONG_MODEM); } - _ldroAuto = true; + this->ldroAuto = true; return(RADIOLIB_ERR_NONE); } @@ -456,7 +456,7 @@ int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); return(state); } @@ -466,15 +466,15 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } @@ -484,7 +484,7 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) { int16_t state = SX127x::standby(); // write register - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); return(state); } @@ -495,15 +495,15 @@ int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) { } // set requested packet mode - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value - _packetLength = len; + SX127x::packetLength = len; return(state); } @@ -514,7 +514,7 @@ int16_t SX1278::configFSK() { RADIOLIB_ASSERT(state); // set fast PLL hop - state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); + state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } @@ -526,13 +526,13 @@ void SX1278::errataFix(bool rx) { // sensitivity optimization for 500kHz bandwidth // see SX1276/77/78 Errata, section 2.1 for details - if(fabs(_bw - 500.0) <= 0.001) { - if((_freq >= 862.0) && (_freq <= 1020.0)) { - _mod->SPIwriteRegister(0x36, 0x02); - _mod->SPIwriteRegister(0x3a, 0x64); - } else if((_freq >= 410.0) && (_freq <= 525.0)) { - _mod->SPIwriteRegister(0x36, 0x02); - _mod->SPIwriteRegister(0x3a, 0x7F); + if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { + if((frequency >= 862.0) && (frequency <= 1020.0)) { + this->mod->SPIwriteRegister(0x36, 0x02); + this->mod->SPIwriteRegister(0x3a, 0x64); + } else if((frequency >= 410.0) && (frequency <= 525.0)) { + this->mod->SPIwriteRegister(0x36, 0x02); + this->mod->SPIwriteRegister(0x3a, 0x7F); } } @@ -541,53 +541,53 @@ void SX1278::errataFix(bool rx) { // figure out what we need to set uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 }; - float rxFreq = _freq; - if(fabs(_bw - 7.8) <= 0.001) { + float rxFreq = frequency; + if(fabs(SX127x::bandwidth - 7.8) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x48; fixedRegs[2] = 0x00; rxFreq += 0.00781; - } else if(fabs(_bw - 10.4) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 10.4) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.01042; - } else if(fabs(_bw - 15.6) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 15.6) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.01562; - } else if(fabs(_bw - 20.8) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 20.8) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.02083; - } else if(fabs(_bw - 31.25) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 31.25) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.03125; - } else if(fabs(_bw - 41.7) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 41.7) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.04167; - } else if(fabs(_bw - 62.5) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 62.5) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabs(_bw - 125.0) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 125.0) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabs(_bw - 250.0) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 250.0) <= 0.001) { fixedRegs[0] = 0b0000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabs(_bw - 500.0) <= 0.001) { + } else if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { fixedRegs[0] = 0b1000000; - fixedRegs[1] = _mod->SPIreadRegister(0x2F); - fixedRegs[2] = _mod->SPIreadRegister(0x30); + fixedRegs[1] = this->mod->SPIreadRegister(0x2F); + fixedRegs[2] = this->mod->SPIreadRegister(0x30); } else { return; } @@ -599,13 +599,13 @@ void SX1278::errataFix(bool rx) { if(rx) { SX127x::setFrequencyRaw(rxFreq); } else { - SX127x::setFrequencyRaw(_freq); + SX127x::setFrequencyRaw(frequency); } // finally, apply errata fixes - _mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7); - _mod->SPIsetRegValue(0x2F, fixedRegs[1]); - _mod->SPIsetRegValue(0x30, fixedRegs[2]); + this->mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7); + this->mod->SPIsetRegValue(0x2F, fixedRegs[1]); + this->mod->SPIsetRegValue(0x30, fixedRegs[2]); } #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 92273a19a8..e5f8781cdf 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -9,95 +9,94 @@ #include "SX127x.h" // SX1278 specific register map -#define RADIOLIB_SX1278_REG_MODEM_CONFIG_3 0x26 -#define RADIOLIB_SX1278_REG_PLL_HOP 0x44 -#define RADIOLIB_SX1278_REG_TCXO 0x4B -#define RADIOLIB_SX1278_REG_PA_DAC 0x4D -#define RADIOLIB_SX1278_REG_FORMER_TEMP 0x5B -#define RADIOLIB_SX1278_REG_BIT_RATE_FRAC 0x5D -#define RADIOLIB_SX1278_REG_AGC_REF 0x61 -#define RADIOLIB_SX1278_REG_AGC_THRESH_1 0x62 -#define RADIOLIB_SX1278_REG_AGC_THRESH_2 0x63 -#define RADIOLIB_SX1278_REG_AGC_THRESH_3 0x64 -#define RADIOLIB_SX1278_REG_PLL 0x70 +#define RADIOLIB_SX1278_REG_MODEM_CONFIG_3 0x26 +#define RADIOLIB_SX1278_REG_PLL_HOP 0x44 +#define RADIOLIB_SX1278_REG_TCXO 0x4B +#define RADIOLIB_SX1278_REG_PA_DAC 0x4D +#define RADIOLIB_SX1278_REG_FORMER_TEMP 0x5B +#define RADIOLIB_SX1278_REG_BIT_RATE_FRAC 0x5D +#define RADIOLIB_SX1278_REG_AGC_REF 0x61 +#define RADIOLIB_SX1278_REG_AGC_THRESH_1 0x62 +#define RADIOLIB_SX1278_REG_AGC_THRESH_2 0x63 +#define RADIOLIB_SX1278_REG_AGC_THRESH_3 0x64 +#define RADIOLIB_SX1278_REG_PLL 0x70 // SX1278 LoRa modem settings -// RADIOLIB_SX1278_REG_OP_MODE MSB LSB DESCRIPTION -#define RADIOLIB_SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers -#define RADIOLIB_SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers +// RADIOLIB_SX1278_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers +#define RADIOLIB_SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers // RADIOLIB_SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB -#define RADIOLIB_SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 -#define RADIOLIB_SX1278_FRF_MID 0x80 // 7 0 where F(XOSC) = 32 MHz -#define RADIOLIB_SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers +#define RADIOLIB_SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 +#define RADIOLIB_SX1278_FRF_MID 0x80 // 7 0 where F(XOSC) = 32 MHz +#define RADIOLIB_SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers // RADIOLIB_SX1278_REG_PA_CONFIG -#define RADIOLIB_SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm -#define RADIOLIB_SX1278_LOW_POWER 0b00100000 // 6 4 +#define RADIOLIB_SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm +#define RADIOLIB_SX1278_LOW_POWER 0b00100000 // 6 4 // RADIOLIB_SX1278_REG_LNA -#define RADIOLIB_SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current +#define RADIOLIB_SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current // SX127X_REG_MODEM_CONFIG_1 -#define RADIOLIB_SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz -#define RADIOLIB_SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz -#define RADIOLIB_SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz -#define RADIOLIB_SX1278_BW_20_80_KHZ 0b00110000 // 7 4 20.80 kHz -#define RADIOLIB_SX1278_BW_31_25_KHZ 0b01000000 // 7 4 31.25 kHz -#define RADIOLIB_SX1278_BW_41_70_KHZ 0b01010000 // 7 4 41.70 kHz -#define RADIOLIB_SX1278_BW_62_50_KHZ 0b01100000 // 7 4 62.50 kHz -#define RADIOLIB_SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz -#define RADIOLIB_SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz -#define RADIOLIB_SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz -#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5 -#define RADIOLIB_SX1278_CR_4_6 0b00000100 // 3 1 4/6 -#define RADIOLIB_SX1278_CR_4_7 0b00000110 // 3 1 4/7 -#define RADIOLIB_SX1278_CR_4_8 0b00001000 // 3 1 4/8 -#define RADIOLIB_SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode -#define RADIOLIB_SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode +#define RADIOLIB_SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz +#define RADIOLIB_SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz +#define RADIOLIB_SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz +#define RADIOLIB_SX1278_BW_20_80_KHZ 0b00110000 // 7 4 20.80 kHz +#define RADIOLIB_SX1278_BW_31_25_KHZ 0b01000000 // 7 4 31.25 kHz +#define RADIOLIB_SX1278_BW_41_70_KHZ 0b01010000 // 7 4 41.70 kHz +#define RADIOLIB_SX1278_BW_62_50_KHZ 0b01100000 // 7 4 62.50 kHz +#define RADIOLIB_SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz +#define RADIOLIB_SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz +#define RADIOLIB_SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz +#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5 +#define RADIOLIB_SX1278_CR_4_6 0b00000100 // 3 1 4/6 +#define RADIOLIB_SX1278_CR_4_7 0b00000110 // 3 1 4/7 +#define RADIOLIB_SX1278_CR_4_8 0b00001000 // 3 1 4/8 +#define RADIOLIB_SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode +#define RADIOLIB_SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode // SX127X_REG_MODEM_CONFIG_2 -#define RADIOLIB_SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled -#define RADIOLIB_SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled +#define RADIOLIB_SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled +#define RADIOLIB_SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled // RADIOLIB_SX1278_REG_MODEM_CONFIG_3 -#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled -#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON 0b00001000 // 3 3 low data rate optimization enabled -#define RADIOLIB_SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA -#define RADIOLIB_SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop +#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled +#define RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON 0b00001000 // 3 3 low data rate optimization enabled +#define RADIOLIB_SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA +#define RADIOLIB_SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop // SX127X_REG_VERSION -#define RADIOLIB_SX1278_CHIP_VERSION 0x12 +#define RADIOLIB_SX1278_CHIP_VERSION 0x12 // SX1278 FSK modem settings // SX127X_REG_PA_RAMP -#define RADIOLIB_SX1278_NO_SHAPING 0b00000000 // 6 5 data shaping: no shaping (default) -#define RADIOLIB_SX1278_FSK_GAUSSIAN_1_0 0b00100000 // 6 5 FSK modulation Gaussian filter, BT = 1.0 -#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_5 0b01000000 // 6 5 FSK modulation Gaussian filter, BT = 0.5 -#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_3 0b01100000 // 6 5 FSK modulation Gaussian filter, BT = 0.3 -#define RADIOLIB_SX1278_OOK_FILTER_BR 0b00100000 // 6 5 OOK modulation filter, f_cutoff = BR -#define RADIOLIB_SX1278_OOK_FILTER_2BR 0b01000000 // 6 5 OOK modulation filter, f_cutoff = 2*BR +#define RADIOLIB_SX1278_NO_SHAPING 0b00000000 // 6 5 data shaping: no shaping (default) +#define RADIOLIB_SX1278_FSK_GAUSSIAN_1_0 0b00100000 // 6 5 FSK modulation Gaussian filter, BT = 1.0 +#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_5 0b01000000 // 6 5 FSK modulation Gaussian filter, BT = 0.5 +#define RADIOLIB_SX1278_FSK_GAUSSIAN_0_3 0b01100000 // 6 5 FSK modulation Gaussian filter, BT = 0.3 +#define RADIOLIB_SX1278_OOK_FILTER_BR 0b00100000 // 6 5 OOK modulation filter, f_cutoff = BR +#define RADIOLIB_SX1278_OOK_FILTER_2BR 0b01000000 // 6 5 OOK modulation filter, f_cutoff = 2*BR // RADIOLIB_SX1278_REG_AGC_REF -#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_LF 0x19 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm]: below 525 MHz -#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_HF 0x1C // 5 0 above 779 MHz +#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_LF 0x19 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm]: below 525 MHz +#define RADIOLIB_SX1278_AGC_REFERENCE_LEVEL_HF 0x1C // 5 0 above 779 MHz // RADIOLIB_SX1278_REG_AGC_THRESH_1 -#define RADIOLIB_SX1278_AGC_STEP_1_LF 0x0C // 4 0 1st AGC threshold: below 525 MHz -#define RADIOLIB_SX1278_AGC_STEP_1_HF 0x0E // 4 0 above 779 MHz +#define RADIOLIB_SX1278_AGC_STEP_1_LF 0x0C // 4 0 1st AGC threshold: below 525 MHz +#define RADIOLIB_SX1278_AGC_STEP_1_HF 0x0E // 4 0 above 779 MHz // RADIOLIB_SX1278_REG_AGC_THRESH_2 -#define RADIOLIB_SX1278_AGC_STEP_2_LF 0x40 // 7 4 2nd AGC threshold: below 525 MHz -#define RADIOLIB_SX1278_AGC_STEP_2_HF 0x50 // 7 4 above 779 MHz -#define RADIOLIB_SX1278_AGC_STEP_3 0x0B // 3 0 3rd AGC threshold +#define RADIOLIB_SX1278_AGC_STEP_2_LF 0x40 // 7 4 2nd AGC threshold: below 525 MHz +#define RADIOLIB_SX1278_AGC_STEP_2_HF 0x50 // 7 4 above 779 MHz +#define RADIOLIB_SX1278_AGC_STEP_3 0x0B // 3 0 3rd AGC threshold // RADIOLIB_SX1278_REG_AGC_THRESH_3 -#define RADIOLIB_SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold -#define RADIOLIB_SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold +#define RADIOLIB_SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold +#define RADIOLIB_SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold /*! \class SX1278 - \brief Derived class for %SX1278 modules. Also used as base class for SX1276, SX1277, SX1279, RFM95 and RFM96. All of these modules use the same basic hardware and only differ in parameter ranges (and names). */ @@ -108,7 +107,6 @@ class SX1278: public SX127x { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX1278(Module* mod); @@ -117,47 +115,30 @@ class SX1278: public SX127x { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -171,45 +152,35 @@ class SX1278: public SX127x { /*! \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); /*! \brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode. - \param bw %LoRa link bandwidth to be set in kHz. - \returns \ref status_codes */ int16_t setBandwidth(float bw); /*! \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode. - \param sf %LoRa link spreading factor to be set. - \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. - \param cr %LoRa link coding rate denominator to be set. - \returns \ref status_codes */ int16_t setCodingRate(uint8_t cr); /*! \brief Sets FSK bit rate. Allowed values range from 0.5 to 300 kbps. Only available in FSK mode. - \param br Bit rate to be set (in kbps). - \returns \ref status_codes */ int16_t setBitRate(float br) override; @@ -217,11 +188,8 @@ class SX1278: public SX127x { /*! \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. - \param power Transmission output power in dBm. - \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. Defaults to PA_BOOST. - \returns \ref status_codes */ int16_t setOutputPower(int8_t power, bool useRfo = false); @@ -229,9 +197,7 @@ class SX1278: public SX127x { /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \param gain Gain of receiver LNA (low-noise amplifier) to be set. - \returns \ref status_codes */ int16_t setGain(uint8_t gain); @@ -239,9 +205,7 @@ class SX1278: public SX127x { /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Gaussian shaping bandwidth-time product that will be used for data shaping - \returns \ref status_codes */ int16_t setDataShaping(uint8_t sh) override; @@ -250,65 +214,53 @@ class SX1278: public SX127x { \brief Sets filter cutoff frequency that will be used for data shaping. Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping. Only available in FSK mode with OOK modulation. - \param sh Cutoff frequency that will be used for data shaping - \returns \ref status_codes */ int16_t setDataShapingOOK(uint8_t sh); /*! \brief Gets recorded signal strength indicator. - \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. - \returns RSSI value in dBm. */ float getRSSI(bool packet = true, bool skipReceive = false); /*! \brief Enables/disables CRC check of received packets. - \param enable Enable (true) or disable (false) CRC. - - \param mode Set CRC mode to SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) or SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. - + \param mode Set CRC mode to SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) + or SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode. \returns \ref status_codes */ int16_t setCRC(bool enable, bool mode = false); /*! - \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to - the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX1278::autoLDRO() - + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, + LDRO will always be set to the provided value, regardless of symbol length. + To re-enable automatic LDRO configuration, call SX1278::autoLDRO() \param enable Force LDRO to be always enabled (true) or disabled (false). - \returns \ref status_codes */ int16_t forceLDRO(bool enable); /*! - \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically - when symbol length exceeds 16 ms. - + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, + LDRO will be enabled automatically when symbol length exceeds 16 ms. \returns \ref status_codes */ int16_t autoLDRO(); /*! - \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. - + \brief Set implicit header mode for future reception/transmission. Required for spreading factor 6. \param len Payload length in bytes. - \returns \ref status_codes */ int16_t implicitHeader(size_t len); /*! \brief Set explicit header mode for future reception/transmission. - \returns \ref status_codes */ int16_t explicitHeader(); @@ -327,8 +279,8 @@ class SX1278: public SX127x { #if !defined(RADIOLIB_GODMODE) private: #endif - bool _ldroAuto = true; - bool _ldroEnabled = false; + bool ldroAuto = true; + bool ldroEnabled = false; }; diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index e191e6c7b0..ae79f0f84f 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -72,7 +72,7 @@ int16_t SX1279::setFrequency(float freq) { // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { - SX127x::_freq = freq; + SX127x::frequency = freq; } return(state); } diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index c9ff8ab039..1b01368f4d 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -9,7 +9,6 @@ /*! \class SX1279 - \brief Derived class for %SX1279 modules. Overrides some methods from SX1278 due to different parameter ranges. */ class SX1279: public SX1278 { @@ -19,7 +18,6 @@ class SX1279: public SX1278 { /*! \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX1279(Module* mod); @@ -28,47 +26,30 @@ class SX1279: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 960.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); @@ -77,9 +58,7 @@ class SX1279: public SX1278 { /*! \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 960.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes */ int16_t setFrequency(float freq); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index e08ad1813c..4abac65227 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -3,23 +3,23 @@ #if !defined(RADIOLIB_EXCLUDE_SX127X) SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) { - _mod = mod; + this->mod = mod; } Module* SX127x::getMod() { - return(_mod); + return(this->mod); } int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); @@ -52,21 +52,21 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe RADIOLIB_ASSERT(state); // initialize internal variables - _dataRate = 0.0; + this->dataRate = 0.0; return(state); } int16_t SX127x::beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties - _mod->init(); - _mod->hal->pinMode(_mod->getIrq(), _mod->hal->GpioModeInput); - _mod->hal->pinMode(_mod->getGpio(), _mod->hal->GpioModeInput); + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); - _mod->term(); + this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); @@ -153,10 +153,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -171,10 +171,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -184,8 +184,8 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // update data rate - uint32_t elapsed = _mod->hal->micros() - start; - _dataRate = (len*8.0)/((float)elapsed/1000000.0); + uint32_t elapsed = this->mod->hal->micros() - start; + this->dataRate = (len*8.0)/((float)elapsed/1000000.0); return(finishTransmit()); } @@ -203,25 +203,25 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout) uint32_t timeout = 0; - if(_mod->getGpio() == RADIOLIB_NC) { - float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw; + if(this->mod->getGpio() == RADIOLIB_NC) { + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; timeout = 100*symbolLength; } // wait for packet reception or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { // no GPIO pin provided, use software timeout - if(_mod->hal->micros() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } } else { // GPIO provided, use that - if(_mod->hal->digitalRead(_mod->getGpio())) { + if(this->mod->hal->digitalRead(this->mod->getGpio())) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -238,10 +238,10 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = _mod->hal->micros(); - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->micros() - start > timeout) { + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -260,9 +260,9 @@ int16_t SX127x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!_mod->hal->digitalRead(_mod->getIrq())) { - _mod->hal->yield(); - if(_mod->hal->digitalRead(_mod->getGpio())) { + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->digitalRead(this->mod->getGpio())) { return(RADIOLIB_PREAMBLE_DETECTED); } } @@ -272,7 +272,7 @@ int16_t SX127x::scanChannel() { int16_t SX127x::sleep() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); // set mode to sleep return(setMode(RADIOLIB_SX127X_SLEEP)); @@ -280,7 +280,7 @@ int16_t SX127x::sleep() { int16_t SX127x::standby() { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_IDLE); + this->mod->setRfSwitchState(Module::MODE_IDLE); // set mode to standby return(setMode(RADIOLIB_SX127X_STANDBY)); @@ -298,13 +298,13 @@ int16_t SX127x::transmitDirect(uint32_t frf) { } // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16); - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8); - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_LSB, frf & 0x0000FF); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_LSB, frf & 0x0000FF); return(setMode(RADIOLIB_SX127X_TX)); } @@ -327,7 +327,7 @@ int16_t SX127x::receiveDirect() { } // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // activate direct mode int16_t state = directMode(); @@ -346,7 +346,7 @@ int16_t SX127x::directMode() { RADIOLIB_ASSERT(state); // set DIO mapping - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_CONT_DCLK | RADIOLIB_SX127X_DIO2_CONT_DATA, 5, 2); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_CONT_DCLK | RADIOLIB_SX127X_DIO2_CONT_DATA, 5, 2); RADIOLIB_ASSERT(state); // enable receiver startup without preamble or RSSI @@ -354,7 +354,7 @@ int16_t SX127x::directMode() { RADIOLIB_ASSERT(state); // set continuous mode - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_CONTINUOUS, 6, 6)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_CONTINUOUS, 6, 6)); } int16_t SX127x::packetMode() { @@ -363,7 +363,7 @@ int16_t SX127x::packetMode() { return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6)); } int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { @@ -374,16 +374,16 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 7, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 7, 4); } // set expected packet length for SF6 - if(_sf == 6) { - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); - _packetLength = len; + if(this->spreadingFactor == 6) { + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + this->packetLength = len; } // apply fixes to errata @@ -393,13 +393,13 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { clearIRQFlags(); // set FIFO pointers - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); RADIOLIB_ASSERT(state); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -408,13 +408,13 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // FSK modem does not distinguish between Rx single and continuous if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); return(setMode(RADIOLIB_SX127X_RX)); } } // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to receive return(setMode(mode)); @@ -427,30 +427,30 @@ int16_t SX127x::startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, } void SX127x::setDio0Action(void (*func)(void), uint32_t dir) { - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq()), func, dir); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir); } void SX127x::clearDio0Action() { - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getIrq())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } void SX127x::setDio1Action(void (*func)(void), uint32_t dir) { - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->attachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio()), func, dir); + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir); } void SX127x::clearDio1Action() { - if(_mod->getGpio() == RADIOLIB_NC) { + if(this->mod->getGpio() == RADIOLIB_NC) { return; } - _mod->hal->detachInterrupt(_mod->hal->pinToInterrupt(_mod->getGpio())); + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); } void SX127x::setFifoEmptyAction(void (*func)(void)) { // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) - setDio1Action(func, _mod->hal->GpioInterruptRising); + setDio1Action(func, this->mod->hal->GpioInterruptRising); } void SX127x::clearFifoEmptyAction() { @@ -459,16 +459,16 @@ void SX127x::clearFifoEmptyAction() { void SX127x::setFifoFullAction(void (*func)(void)) { // set the interrupt - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4); // set DIO1 to the FIFO full event - setDio1Action(func, _mod->hal->GpioInterruptRising); + setDio1Action(func, this->mod->hal->GpioInterruptRising); } void SX127x::clearFifoFullAction() { clearDio1Action(); - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4); } bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) { @@ -488,7 +488,7 @@ bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) { } // copy the bytes to the FIFO - _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len); // we're not done yet return(false); @@ -506,7 +506,7 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) } // get the data - _mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr); (*rcvLen) += (len); // check if we're done @@ -528,10 +528,10 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set DIO mapping - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); } else { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6); } // apply fixes to errata @@ -541,11 +541,11 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { clearIRQFlags(); // set packet length - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); // set FIFO pointers - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // clear interrupt flags @@ -553,20 +553,20 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set DIO mapping if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4); } else { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); } // set packet length - if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); } // check address filtering - uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); } } @@ -574,12 +574,12 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { size_t packetLen = len; if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1; - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); } - _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_TX); + this->mod->setRfSwitchState(Module::MODE_TX); // start transmission state |= setMode(RADIOLIB_SX127X_TX); @@ -610,13 +610,13 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // check payload CRC int16_t state = RADIOLIB_ERR_NONE; - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { state = RADIOLIB_ERR_CRC_MISMATCH; } if(modem == RADIOLIB_SX127X_LORA) { // check packet header integrity - if(_crcEnabled && (state == RADIOLIB_ERR_NONE) && (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) == 0)) { + if(this->crcEnabled && (state == RADIOLIB_ERR_NONE) && (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) == 0)) { // CRC is disabled according to packet header and enabled according to user // most likely damaged packet header state = RADIOLIB_ERR_LORA_HEADER_DAMAGED; @@ -624,14 +624,14 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // check address filtering - uint8_t filter = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { - _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); } } // read packet data - _mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data); // dump the bytes that weren't requested if(dumpLen != 0) { @@ -639,7 +639,7 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { } // clear internal flag so getPacketLength can return the new packet length - _packetLengthQueried = false; + this->packetLengthQueried = false; // clear interrupt flags clearIRQFlags(); @@ -661,11 +661,11 @@ int16_t SX127x::startChannelScan() { clearIRQFlags(); // set DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); RADIOLIB_ASSERT(state); // set RF switch (if present) - _mod->setRfSwitchState(Module::MODE_RX); + this->mod->setRfSwitchState(Module::MODE_RX); // set mode to CAD state = setMode(RADIOLIB_SX127X_CAD); @@ -682,7 +682,7 @@ int16_t SX127x::setSyncWord(uint8_t syncWord) { setMode(RADIOLIB_SX127X_STANDBY); // write register - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_WORD, syncWord)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_WORD, syncWord)); } int16_t SX127x::setCurrentLimit(uint8_t currentLimit) { @@ -698,13 +698,13 @@ int16_t SX127x::setCurrentLimit(uint8_t currentLimit) { uint8_t raw; if(currentLimit == 0) { // limit set to 0, disable OCP - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_OFF, 5, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_OFF, 5, 5); } else if(currentLimit <= 120) { raw = (currentLimit - 45) / 5; - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); } else if(currentLimit <= 240) { raw = (currentLimit + 30) / 10; - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0); } return(state); } @@ -723,15 +723,15 @@ int16_t SX127x::setPreambleLength(uint16_t preambleLength) { } // set preamble length - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF)); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF)); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF)); return(state); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set preamble length (in bytes) uint16_t numBytes = preambleLength / 8; - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF)); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF)); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF)); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF)); return(state); } @@ -742,9 +742,9 @@ float SX127x::getFrequencyError(bool autoCorrect) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // get raw frequency error - uint32_t raw = (uint32_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB, 3, 0) << 16; - raw |= (uint16_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MID) << 8; - raw |= _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB); + uint32_t raw = (uint32_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB, 3, 0) << 16; + raw |= (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MID) << 8; + raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB); uint32_t base = (uint32_t)2 << 23; float error; @@ -754,23 +754,23 @@ float SX127x::getFrequencyError(bool autoCorrect) { // frequency error is negative raw |= (uint32_t)0xFFF00000; raw = ~raw + 1; - error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0) * -1.0; + error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0) * -1.0; } else { - error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0); + error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0); } if(autoCorrect) { // adjust LoRa modem data rate float ppmOffset = 0.95 * (error/32.0); - _mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset); + this->mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset); } return(error); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // get raw frequency error - uint16_t raw = (uint16_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB_FSK) << 8; - raw |= _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB_FSK); + uint16_t raw = (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB_FSK) << 8; + raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB_FSK); uint32_t base = 1; float error; @@ -800,8 +800,8 @@ float SX127x::getAFCError() } // get raw frequency error - int16_t raw = (uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_MSB) << 8; - raw |= _mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB); + int16_t raw = (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_MSB) << 8; + raw |= this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB); uint32_t base = 1; return raw * (32000000.0 / (float)(base << 19)); @@ -814,12 +814,12 @@ float SX127x::getSNR() { } // get SNR value - int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_SNR_VALUE); + int8_t rawSNR = (int8_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_SNR_VALUE); return(rawSNR / 4.0); } float SX127x::getDataRate() const { - return(_dataRate); + return(this->dataRate); } int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { @@ -830,7 +830,7 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { // check allowed bit rate // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine - if(_ook) { + if(ookEnabled) { RADIOLIB_CHECK_RANGE(br, 0.5, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 } else { RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); @@ -842,18 +842,18 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { // set bit rate uint16_t bitRate = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br; - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); // set fractional part of bit rate - if(!_ook) { + if(!ookEnabled) { float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRate; uint8_t bitRateFrac = bitRateRem * 16; - state |= _mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0); + state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0); } if(state == RADIOLIB_ERR_NONE) { - SX127x::_br = br; + this->bitRate = br; } return(state); } @@ -871,7 +871,7 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) { } // check frequency deviation range - if(!((newFreqDev + _br/2.0 <= 250.0) && (freqDev <= 200.0))) { + if(!((newFreqDev + this->bitRate/2.0 <= 250.0) && (freqDev <= 200.0))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } @@ -882,8 +882,8 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) { // set allowed frequency deviation uint32_t base = 1; uint32_t FDEV = (newFreqDev * (base << 19)) / 32000; - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0); return(state); } @@ -913,7 +913,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) { RADIOLIB_ASSERT(state); // set Rx bandwidth - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0)); } int16_t SX127x::setAFCBandwidth(float rxBw) { @@ -929,7 +929,7 @@ int16_t SX127x::setAFCBandwidth(float rxBw) { RADIOLIB_ASSERT(state); // set AFC bandwidth - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0)); } int16_t SX127x::setAFC(bool isEnabled) { @@ -939,7 +939,7 @@ int16_t SX127x::setAFC(bool isEnabled) { } //set AFC auto on/off - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4)); } int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) { @@ -948,7 +948,7 @@ int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) { } //set AFC&AGC trigger - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0)); } int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { @@ -967,12 +967,12 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { } // enable sync word recognition - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); RADIOLIB_ASSERT(state); // set sync word - _mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len); return(RADIOLIB_ERR_NONE); } @@ -983,11 +983,11 @@ int16_t SX127x::setNodeAddress(uint8_t nodeAddr) { } // enable address filtering (node only) - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1); RADIOLIB_ASSERT(state); // set node address - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr)); } int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) { @@ -997,11 +997,11 @@ int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) { } // enable address filtering (node + broadcast) - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); RADIOLIB_ASSERT(state); // set broadcast address - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr)); } int16_t SX127x::disableAddressFiltering() { @@ -1011,15 +1011,15 @@ int16_t SX127x::disableAddressFiltering() { } // disable address filtering - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1); RADIOLIB_ASSERT(state); // set node address to default (0x00) - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00); RADIOLIB_ASSERT(state); // set broadcast address to default (0x00) - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00)); } int16_t SX127x::setOokThresholdType(uint8_t type) { @@ -1027,7 +1027,7 @@ int16_t SX127x::setOokThresholdType(uint8_t type) { if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5)); } int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) { @@ -1035,7 +1035,7 @@ int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) { if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5)); } int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { @@ -1043,7 +1043,7 @@ int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) { if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5)); } int16_t SX127x::setOokPeakThresholdStep(uint8_t value) { @@ -1051,15 +1051,15 @@ int16_t SX127x::setOokPeakThresholdStep(uint8_t value) { if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5)); } int16_t SX127x::enableBitSync() { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5)); } int16_t SX127x::disableBitSync() { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5)); } int16_t SX127x::setOOK(bool enableOOK) { @@ -1071,14 +1071,14 @@ int16_t SX127x::setOOK(bool enableOOK) { // set OOK and if successful, save the new setting int16_t state = RADIOLIB_ERR_NONE; if(enableOOK) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5); state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5); state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH); } if(state == RADIOLIB_ERR_NONE) { - _ook = enableOOK; + ookEnabled = enableOOK; } return(state); @@ -1088,7 +1088,7 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { int16_t state = RADIOLIB_ERR_NONE; // set mode to standby if not FHSS - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) { + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = setMode(RADIOLIB_SX127X_STANDBY); } @@ -1096,9 +1096,9 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; // write registers - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF); return(state); } @@ -1106,28 +1106,28 @@ size_t SX127x::getPacketLength(bool update) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { - if(_sf != 6) { + if(this->spreadingFactor != 6) { // get packet length for SF7 - SF12 - return(_mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES)); + return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES)); } else { // return the cached value for SF6 - return(_packetLength); + return(this->packetLength); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // get packet length - if(!_packetLengthQueried && update) { - if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { - _packetLength = _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + if(!this->packetLengthQueried && update) { + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); } else { - _packetLength = _mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); } - _packetLengthQueried = true; + this->packetLengthQueried = true; } } - return(_packetLength); + return(this->packetLength); } int16_t SX127x::fixedPacketLengthMode(uint8_t len) { @@ -1143,61 +1143,61 @@ uint32_t SX127x::getTimeOnAir(size_t len) { uint8_t modem = getActiveModem(); if (modem == RADIOLIB_SX127X_LORA) { // Get symbol length in us - float symbolLength = (float) (uint32_t(1) << _sf) / (float) _bw; + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; // Get Low Data Rate optimization flag float de = 0; if (symbolLength >= 16.0) { de = 1; } // Get explicit/implicit header enabled flag - float ih = (float) _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); // Get CRC enabled flag - float crc = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); // Get number of bits preamble - float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); // Get number of bits payload - float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) _sf + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) _sf - 8.0 * de)) * (float) _cr, 0.0); + float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); // Get time-on-air in us return ceil(symbolLength * (n_pre + n_pay + 4.25)) * 1000; } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // Get number of bits preamble - float n_pre = (float) ((_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; + float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; //Get the number of bits of the sync word - float n_syncWord = (float) (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; + float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; //Get CRC bits - float crc = (_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16; + float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16; - if (_packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { //If Packet size fixed -> len = fixed packet length - len = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); } else { //if packet variable -> Add 1 extra byte for payload length len += 1; } // Calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) - return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (_br * 1000.0)) * 1000000.0); + return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0); } else { return(RADIOLIB_ERR_UNKNOWN); } } -int16_t SX127x::setCrcFiltering(bool crcOn) { - _crcOn = crcOn; +int16_t SX127x::setCrcFiltering(bool enable) { + this->crcOn = enable; - if (crcOn == true) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4)); + if (enable == true) { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4)); } else { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4)); } } int16_t SX127x::setRSSIThreshold(float dbm) { RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); - return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); + return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); } int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { @@ -1218,8 +1218,8 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET); // set new register values - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset << 3, 7, 3); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset << 3, 7, 3); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); return(state); } @@ -1232,11 +1232,11 @@ int16_t SX127x::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5)); case RADIOLIB_ENCODING_MANCHESTER: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5)); case RADIOLIB_ENCODING_WHITENING: - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5)); default: return(RADIOLIB_ERR_INVALID_ENCODING); } @@ -1246,12 +1246,12 @@ uint16_t SX127x::getIRQFlags() { // check active modem if(getActiveModem() == RADIOLIB_SX127X_LORA) { // LoRa, just 8-bit value - return((uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS)); + return((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS)); } else { // FSK, the IRQ flags are 16 bits in total - uint16_t flags = ((uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8; - flags |= (uint16_t)_mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1); + uint16_t flags = ((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8; + flags |= (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1); return(flags); } @@ -1264,15 +1264,15 @@ uint8_t SX127x::getModemStatus() { } // read the register - return(_mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT)); + return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT)); } void SX127x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - _mod->setRfSwitchPins(rxEn, txEn); + this->mod->setRfSwitchPins(rxEn, txEn); } void SX127x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - _mod->setRfSwitchTable(pins, table); + this->mod->setRfSwitchTable(pins, table); } uint8_t SX127x::randomByte() { @@ -1286,12 +1286,12 @@ uint8_t SX127x::randomByte() { setMode(RADIOLIB_SX127X_RX); // wait a bit for the RSSI reading to stabilise - _mod->hal->delay(10); + this->mod->hal->delay(10); // read RSSI value 8 times, always keep just the least significant bit uint8_t randByte = 0x00; for(uint8_t i = 0; i < 8; i++) { - randByte |= ((_mod->SPIreadRegister(rssiValueReg) & 0x01) << i); + randByte |= ((this->mod->SPIreadRegister(rssiValueReg) & 0x01) << i); } // set mode to standby @@ -1301,7 +1301,7 @@ uint8_t SX127x::randomByte() { } int16_t SX127x::getChipVersion() { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION)); + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION)); } int8_t SX127x::getTempRaw() { @@ -1310,33 +1310,33 @@ int8_t SX127x::getTempRaw() { uint8_t ival; // save current Op Mode - previousOpMode = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE); + previousOpMode = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE); // check if we need to step out of LoRa mode first if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); } // put device in FSK sleep - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); // put device in FSK RxSynth - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX)); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX)); // enable temperature reading - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0); // wait - _mod->hal->delayMicroseconds(200); + this->mod->hal->delayMicroseconds(200); // disable temperature reading - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0); // put device in FSK sleep - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP)); // read temperature - ival = _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP); + ival = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP); // convert very raw value if((ival & 0x80) == 0x80) { @@ -1347,51 +1347,51 @@ int8_t SX127x::getTempRaw() { // check if we need to step back into LoRa mode if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) { - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP)); } // reload previous Op Mode - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode); + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode); return(temp); } int16_t SX127x::config() { // turn off frequency hopping - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF); return(state); } int16_t SX127x::configFSK() { // set RSSI threshold - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD); RADIOLIB_ASSERT(state); // reset FIFO flag - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN); // set packet configuration - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_PACKET_VARIABLE | RADIOLIB_SX127X_DC_FREE_NONE | RADIOLIB_SX127X_CRC_ON | RADIOLIB_SX127X_CRC_AUTOCLEAR_ON | RADIOLIB_SX127X_ADDRESS_FILTERING_OFF | RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_PACKET_VARIABLE | RADIOLIB_SX127X_DC_FREE_NONE | RADIOLIB_SX127X_CRC_ON | RADIOLIB_SX127X_CRC_AUTOCLEAR_ON | RADIOLIB_SX127X_ADDRESS_FILTERING_OFF | RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5); RADIOLIB_ASSERT(state); // set preamble polarity - state =_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_PREAMBLE_POLARITY_55, 5, 5); + state =this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_PREAMBLE_POLARITY_55, 5, 5); RADIOLIB_ASSERT(state); // set FIFO threshold - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); RADIOLIB_ASSERT(state); // disable Rx timeouts - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF); RADIOLIB_ASSERT(state); // enable preamble detector - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_DETECT, RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON | RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE | RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_DETECT, RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON | RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE | RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL); return(state); } @@ -1408,15 +1408,15 @@ int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) { } // set to fixed packet length - int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len); RADIOLIB_ASSERT(state); // update cached value - _packetLengthConfig = mode; + this->packetLengthConfig = mode; return(state); } @@ -1433,7 +1433,7 @@ bool SX127x::findChip(uint8_t ver) { flagFound = true; } else { RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X, expected 0x00%X", i + 1, version, ver); - _mod->hal->delay(10); + this->mod->hal->delay(10); i++; } } @@ -1447,11 +1447,11 @@ int16_t SX127x::setMode(uint8_t mode) { // disable checking of RX bit in FSK RX mode, as it sometimes seem to fail (#276) checkMask = 0xFE; } - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask)); } int16_t SX127x::getActiveModem() { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7)); + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7)); } int16_t SX127x::setActiveModem(uint8_t modem) { @@ -1459,7 +1459,7 @@ int16_t SX127x::setActiveModem(uint8_t modem) { int16_t state = setMode(RADIOLIB_SX127X_SLEEP); // set modem - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5); // set mode to STANDBY state |= setMode(RADIOLIB_SX127X_STANDBY); @@ -1469,16 +1469,16 @@ int16_t SX127x::setActiveModem(uint8_t modem) { void SX127x::clearIRQFlags() { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, 0b11111111); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, 0b11111111); - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, 0b11111111); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, 0b11111111); } } void SX127x::clearFIFO(size_t count) { while(count) { - _mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); + this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); count--; } } @@ -1491,13 +1491,13 @@ int16_t SX127x::invertIQ(bool invertIQ) { int16_t state; if(invertIQ) { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE); } else { - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); - state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE); } return(state); @@ -1505,30 +1505,30 @@ int16_t SX127x::invertIQ(bool invertIQ) { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) void SX127x::setDirectAction(void (*func)(void)) { - setDio1Action(func, _mod->hal->GpioInterruptRising); + setDio1Action(func, this->mod->hal->GpioInterruptRising); } void SX127x::readBit(uint32_t pin) { - updateDirectBuffer((uint8_t)_mod->hal->digitalRead(pin)); + updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin)); } #endif int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); } uint8_t SX127x::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); } uint8_t SX127x::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); + return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); } void SX127x::clearFHSSInt(void) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { return; //These are not the interrupts you are looking for } @@ -1539,20 +1539,20 @@ int16_t SX127x::setDIOMapping(uint32_t pin, uint32_t value) { return RADIOLIB_ERR_INVALID_DIO_PIN; if (pin < 4) - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin)); else - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); } int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) { - return _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0); + return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0); } float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { if(getActiveModem() == RADIOLIB_SX127X_LORA) { if(packet) { // LoRa packet mode, get RSSI of the last packet - float lastPacketRSSI = offset + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); + float lastPacketRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE); // spread-spectrum modulation signal can be received below noise floor // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value @@ -1564,7 +1564,7 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { } else { // LoRa instant, get current RSSI - float currentRSSI = offset + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); + float currentRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE); return(currentRSSI); } @@ -1577,7 +1577,7 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { } // read the value for FSK - float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; + float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; // set mode back to standby if(!skipReceive) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 112e7d4325..ebc0fb1936 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -10,573 +10,572 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // SX127x physical layer properties -#define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 -#define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 -#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 -#define RADIOLIB_SX127X_DIV_EXPONENT 19 +#define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 +#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX127X_DIV_EXPONENT 19 // SX127x series common LoRa registers -#define RADIOLIB_SX127X_REG_FIFO 0x00 -#define RADIOLIB_SX127X_REG_OP_MODE 0x01 -#define RADIOLIB_SX127X_REG_FRF_MSB 0x06 -#define RADIOLIB_SX127X_REG_FRF_MID 0x07 -#define RADIOLIB_SX127X_REG_FRF_LSB 0x08 -#define RADIOLIB_SX127X_REG_PA_CONFIG 0x09 -#define RADIOLIB_SX127X_REG_PA_RAMP 0x0A -#define RADIOLIB_SX127X_REG_OCP 0x0B -#define RADIOLIB_SX127X_REG_LNA 0x0C -#define RADIOLIB_SX127X_REG_FIFO_ADDR_PTR 0x0D -#define RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR 0x0E -#define RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR 0x0F -#define RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 -#define RADIOLIB_SX127X_REG_IRQ_FLAGS_MASK 0x11 -#define RADIOLIB_SX127X_REG_IRQ_FLAGS 0x12 -#define RADIOLIB_SX127X_REG_RX_NB_BYTES 0x13 -#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 -#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 -#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 -#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 -#define RADIOLIB_SX127X_REG_MODEM_STAT 0x18 -#define RADIOLIB_SX127X_REG_PKT_SNR_VALUE 0x19 -#define RADIOLIB_SX127X_REG_PKT_RSSI_VALUE 0x1A -#define RADIOLIB_SX127X_REG_RSSI_VALUE 0x1B -#define RADIOLIB_SX127X_REG_HOP_CHANNEL 0x1C -#define RADIOLIB_SX127X_REG_MODEM_CONFIG_1 0x1D -#define RADIOLIB_SX127X_REG_MODEM_CONFIG_2 0x1E -#define RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB 0x1F -#define RADIOLIB_SX127X_REG_PREAMBLE_MSB 0x20 -#define RADIOLIB_SX127X_REG_PREAMBLE_LSB 0x21 -#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH 0x22 -#define RADIOLIB_SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 -#define RADIOLIB_SX127X_REG_HOP_PERIOD 0x24 -#define RADIOLIB_SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 -#define RADIOLIB_SX127X_REG_FEI_MSB 0x28 -#define RADIOLIB_SX127X_REG_FEI_MID 0x29 -#define RADIOLIB_SX127X_REG_FEI_LSB 0x2A -#define RADIOLIB_SX127X_REG_RSSI_WIDEBAND 0x2C -#define RADIOLIB_SX127X_REG_DETECT_OPTIMIZE 0x31 -#define RADIOLIB_SX127X_REG_INVERT_IQ 0x33 -#define RADIOLIB_SX127X_REG_DETECTION_THRESHOLD 0x37 -#define RADIOLIB_SX127X_REG_SYNC_WORD 0x39 -#define RADIOLIB_SX127X_REG_INVERT_IQ2 0x3B -#define RADIOLIB_SX127X_REG_DIO_MAPPING_1 0x40 -#define RADIOLIB_SX127X_REG_DIO_MAPPING_2 0x41 -#define RADIOLIB_SX127X_REG_VERSION 0x42 +#define RADIOLIB_SX127X_REG_FIFO 0x00 +#define RADIOLIB_SX127X_REG_OP_MODE 0x01 +#define RADIOLIB_SX127X_REG_FRF_MSB 0x06 +#define RADIOLIB_SX127X_REG_FRF_MID 0x07 +#define RADIOLIB_SX127X_REG_FRF_LSB 0x08 +#define RADIOLIB_SX127X_REG_PA_CONFIG 0x09 +#define RADIOLIB_SX127X_REG_PA_RAMP 0x0A +#define RADIOLIB_SX127X_REG_OCP 0x0B +#define RADIOLIB_SX127X_REG_LNA 0x0C +#define RADIOLIB_SX127X_REG_FIFO_ADDR_PTR 0x0D +#define RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR 0x0E +#define RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR 0x0F +#define RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_MASK 0x11 +#define RADIOLIB_SX127X_REG_IRQ_FLAGS 0x12 +#define RADIOLIB_SX127X_REG_RX_NB_BYTES 0x13 +#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 +#define RADIOLIB_SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 +#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 +#define RADIOLIB_SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 +#define RADIOLIB_SX127X_REG_MODEM_STAT 0x18 +#define RADIOLIB_SX127X_REG_PKT_SNR_VALUE 0x19 +#define RADIOLIB_SX127X_REG_PKT_RSSI_VALUE 0x1A +#define RADIOLIB_SX127X_REG_RSSI_VALUE 0x1B +#define RADIOLIB_SX127X_REG_HOP_CHANNEL 0x1C +#define RADIOLIB_SX127X_REG_MODEM_CONFIG_1 0x1D +#define RADIOLIB_SX127X_REG_MODEM_CONFIG_2 0x1E +#define RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB 0x1F +#define RADIOLIB_SX127X_REG_PREAMBLE_MSB 0x20 +#define RADIOLIB_SX127X_REG_PREAMBLE_LSB 0x21 +#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH 0x22 +#define RADIOLIB_SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 +#define RADIOLIB_SX127X_REG_HOP_PERIOD 0x24 +#define RADIOLIB_SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 +#define RADIOLIB_SX127X_REG_FEI_MSB 0x28 +#define RADIOLIB_SX127X_REG_FEI_MID 0x29 +#define RADIOLIB_SX127X_REG_FEI_LSB 0x2A +#define RADIOLIB_SX127X_REG_RSSI_WIDEBAND 0x2C +#define RADIOLIB_SX127X_REG_DETECT_OPTIMIZE 0x31 +#define RADIOLIB_SX127X_REG_INVERT_IQ 0x33 +#define RADIOLIB_SX127X_REG_DETECTION_THRESHOLD 0x37 +#define RADIOLIB_SX127X_REG_SYNC_WORD 0x39 +#define RADIOLIB_SX127X_REG_INVERT_IQ2 0x3B +#define RADIOLIB_SX127X_REG_DIO_MAPPING_1 0x40 +#define RADIOLIB_SX127X_REG_DIO_MAPPING_2 0x41 +#define RADIOLIB_SX127X_REG_VERSION 0x42 // SX127x common LoRa modem settings -// SX127X_REG_OP_MODE MSB LSB DESCRIPTION -#define RADIOLIB_SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode -#define RADIOLIB_SX127X_LORA 0b10000000 // 7 7 LoRa mode -#define RADIOLIB_SX127X_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode -#define RADIOLIB_SX127X_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode -#define RADIOLIB_SX127X_SLEEP 0b00000000 // 2 0 sleep -#define RADIOLIB_SX127X_STANDBY 0b00000001 // 2 0 standby -#define RADIOLIB_SX127X_FSTX 0b00000010 // 2 0 frequency synthesis TX -#define RADIOLIB_SX127X_TX 0b00000011 // 2 0 transmit -#define RADIOLIB_SX127X_FSRX 0b00000100 // 2 0 frequency synthesis RX -#define RADIOLIB_SX127X_RXCONTINUOUS 0b00000101 // 2 0 receive continuous -#define RADIOLIB_SX127X_RXSINGLE 0b00000110 // 2 0 receive single -#define RADIOLIB_SX127X_CAD 0b00000111 // 2 0 channel activity detection - -// SX127X_REG_PA_CONFIG -#define RADIOLIB_SX127X_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm -#define RADIOLIB_SX127X_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm -#define RADIOLIB_SX127X_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST - // P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_RFO - -// SX127X_REG_OCP -#define RADIOLIB_SX127X_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled -#define RADIOLIB_SX127X_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled -#define RADIOLIB_SX127X_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA - -// SX127X_REG_LNA -#define RADIOLIB_SX127X_LNA_GAIN_1 0b00100000 // 7 5 LNA gain setting: max gain -#define RADIOLIB_SX127X_LNA_GAIN_2 0b01000000 // 7 5 . -#define RADIOLIB_SX127X_LNA_GAIN_3 0b01100000 // 7 5 . -#define RADIOLIB_SX127X_LNA_GAIN_4 0b10000000 // 7 5 . -#define RADIOLIB_SX127X_LNA_GAIN_5 0b10100000 // 7 5 . -#define RADIOLIB_SX127X_LNA_GAIN_6 0b11000000 // 7 5 min gain -#define RADIOLIB_SX127X_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current -#define RADIOLIB_SX127X_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current - -// SX127X_REG_MODEM_CONFIG_2 -#define RADIOLIB_SX127X_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit -#define RADIOLIB_SX127X_SF_7 0b01110000 // 7 4 128 chips/bit -#define RADIOLIB_SX127X_SF_8 0b10000000 // 7 4 256 chips/bit -#define RADIOLIB_SX127X_SF_9 0b10010000 // 7 4 512 chips/bit -#define RADIOLIB_SX127X_SF_10 0b10100000 // 7 4 1024 chips/bit -#define RADIOLIB_SX127X_SF_11 0b10110000 // 7 4 2048 chips/bit -#define RADIOLIB_SX127X_SF_12 0b11000000 // 7 4 4096 chips/bit -#define RADIOLIB_SX127X_TX_MODE_SINGLE 0b00000000 // 3 3 single TX -#define RADIOLIB_SX127X_TX_MODE_CONT 0b00001000 // 3 3 continuous TX -#define RADIOLIB_SX127X_RX_TIMEOUT_MSB 0b00000000 // 1 0 - -// SX127X_REG_SYMB_TIMEOUT_LSB -#define RADIOLIB_SX127X_RX_TIMEOUT_LSB 0b01100100 // 7 0 10 bit RX operation timeout - -// SX127X_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB -#define RADIOLIB_SX127X_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25 -#define RADIOLIB_SX127X_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length - -// SX127X_REG_DETECT_OPTIMIZE -#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization -#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization - -// SX127X_REG_INVERT_IQ -#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON 0b01000000 // 6 6 I and Q signals are inverted -#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF 0b00000000 // 6 6 normal mode -#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON 0b00000001 // 0 0 I and Q signals are inverted -#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF 0b00000000 // 0 0 normal mode - -// SX127X_REG_DETECTION_THRESHOLD -#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold -#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold - -// SX127X_REG_PA_DAC -#define RADIOLIB_SX127X_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled -#define RADIOLIB_SX127X_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111 - -// SX127X_REG_HOP_PERIOD -#define RADIOLIB_SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled -#define RADIOLIB_SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0 - -// SX127X_REG_IRQ_FLAGS -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel -#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation - -// SX127X_REG_IRQ_FLAGS_MASK -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation - -// SX127X_REG_FIFO_TX_BASE_ADDR -#define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only - -// SX127X_REG_FIFO_RX_BASE_ADDR -#define RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only - -// SX127X_REG_SYNC_WORD -#define RADIOLIB_SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word -#define RADIOLIB_SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks - -// SX127X_REG_INVERT_IQ2 -#define RADIOLIB_SX127X_IQ2_ENABLE 0x19 // 7 0 enable optimize for inverted IQ -#define RADIOLIB_SX127X_IQ2_DISABLE 0x1D // 7 0 reset optimize for inverted IQ +// RADIOLIB_SX127X_REG_OP_MODE MSB LSB DESCRIPTION +#define RADIOLIB_SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode +#define RADIOLIB_SX127X_LORA 0b10000000 // 7 7 LoRa mode +#define RADIOLIB_SX127X_ACCESS_SHARED_REG_OFF 0b00000000 // 6 6 access LoRa registers (0x0D:0x3F) in LoRa mode +#define RADIOLIB_SX127X_ACCESS_SHARED_REG_ON 0b01000000 // 6 6 access FSK registers (0x0D:0x3F) in LoRa mode +#define RADIOLIB_SX127X_SLEEP 0b00000000 // 2 0 sleep +#define RADIOLIB_SX127X_STANDBY 0b00000001 // 2 0 standby +#define RADIOLIB_SX127X_FSTX 0b00000010 // 2 0 frequency synthesis TX +#define RADIOLIB_SX127X_TX 0b00000011 // 2 0 transmit +#define RADIOLIB_SX127X_FSRX 0b00000100 // 2 0 frequency synthesis RX +#define RADIOLIB_SX127X_RXCONTINUOUS 0b00000101 // 2 0 receive continuous +#define RADIOLIB_SX127X_RXSINGLE 0b00000110 // 2 0 receive single +#define RADIOLIB_SX127X_CAD 0b00000111 // 2 0 channel activity detection + +// RADIOLIB_SX127X_REG_PA_CONFIG +#define RADIOLIB_SX127X_PA_SELECT_RFO 0b00000000 // 7 7 RFO pin output, power limited to +14 dBm +#define RADIOLIB_SX127X_PA_SELECT_BOOST 0b10000000 // 7 7 PA_BOOST pin output, power limited to +20 dBm +#define RADIOLIB_SX127X_OUTPUT_POWER 0b00001111 // 3 0 output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST + // P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_RFO + +// RADIOLIB_SX127X_REG_OCP +#define RADIOLIB_SX127X_OCP_OFF 0b00000000 // 5 5 PA overload current protection disabled +#define RADIOLIB_SX127X_OCP_ON 0b00100000 // 5 5 PA overload current protection enabled +#define RADIOLIB_SX127X_OCP_TRIM 0b00001011 // 4 0 OCP current: I_max(OCP_TRIM = 0b1011) = 100 mA + +// RADIOLIB_SX127X_REG_LNA +#define RADIOLIB_SX127X_LNA_GAIN_1 0b00100000 // 7 5 LNA gain setting: max gain +#define RADIOLIB_SX127X_LNA_GAIN_2 0b01000000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_3 0b01100000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_4 0b10000000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_5 0b10100000 // 7 5 . +#define RADIOLIB_SX127X_LNA_GAIN_6 0b11000000 // 7 5 min gain +#define RADIOLIB_SX127X_LNA_BOOST_OFF 0b00000000 // 1 0 default LNA current +#define RADIOLIB_SX127X_LNA_BOOST_ON 0b00000011 // 1 0 150% LNA current + +// RADIOLIB_SX127X_REG_MODEM_CONFIG_2 +#define RADIOLIB_SX127X_SF_6 0b01100000 // 7 4 spreading factor: 64 chips/bit +#define RADIOLIB_SX127X_SF_7 0b01110000 // 7 4 128 chips/bit +#define RADIOLIB_SX127X_SF_8 0b10000000 // 7 4 256 chips/bit +#define RADIOLIB_SX127X_SF_9 0b10010000 // 7 4 512 chips/bit +#define RADIOLIB_SX127X_SF_10 0b10100000 // 7 4 1024 chips/bit +#define RADIOLIB_SX127X_SF_11 0b10110000 // 7 4 2048 chips/bit +#define RADIOLIB_SX127X_SF_12 0b11000000 // 7 4 4096 chips/bit +#define RADIOLIB_SX127X_TX_MODE_SINGLE 0b00000000 // 3 3 single TX +#define RADIOLIB_SX127X_TX_MODE_CONT 0b00001000 // 3 3 continuous TX +#define RADIOLIB_SX127X_RX_TIMEOUT_MSB 0b00000000 // 1 0 + +// RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB +#define RADIOLIB_SX127X_RX_TIMEOUT_LSB 0b01100100 // 7 0 10-bit RX operation timeout + +// RADIOLIB_SX127X_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB +#define RADIOLIB_SX127X_PREAMBLE_LENGTH_MSB 0b00000000 // 7 0 2-byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25 +#define RADIOLIB_SX127X_PREAMBLE_LENGTH_LSB 0b00001000 // 7 0 where l_p = preamble length + +// RADIOLIB_SX127X_REG_DETECT_OPTIMIZE +#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization +#define RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization + +// RADIOLIB_SX127X_REG_INVERT_IQ +#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON 0b01000000 // 6 6 I and Q signals are inverted +#define RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF 0b00000000 // 6 6 normal mode +#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON 0b00000001 // 0 0 I and Q signals are inverted +#define RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF 0b00000000 // 0 0 normal mode + +// RADIOLIB_SX127X_REG_DETECTION_THRESHOLD +#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold +#define RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold + +// RADIOLIB_SX127X_REG_PA_DAC +#define RADIOLIB_SX127X_PA_BOOST_OFF 0b00000100 // 2 0 PA_BOOST disabled +#define RADIOLIB_SX127X_PA_BOOST_ON 0b00000111 // 2 0 +20 dBm on PA_BOOST when OUTPUT_POWER = 0b1111 + +// RADIOLIB_SX127X_REG_HOP_PERIOD +#define RADIOLIB_SX127X_HOP_PERIOD_OFF 0b00000000 // 7 0 number of periods between frequency hops; 0 = disabled +#define RADIOLIB_SX127X_HOP_PERIOD_MAX 0b11111111 // 7 0 + +// RADIOLIB_SX127X_REG_IRQ_FLAGS +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT 0b10000000 // 7 7 timeout +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE 0b01000000 // 6 6 packet reception complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b00100000 // 5 5 payload CRC error +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER 0b00010000 // 4 4 valid header received +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE 0b00001000 // 3 3 payload transmission complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE 0b00000100 // 2 2 CAD complete +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b00000010 // 1 1 FHSS change channel +#define RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED 0b00000001 // 0 0 valid LoRa signal detected during CAD operation + +// RADIOLIB_SX127X_REG_IRQ_FLAGS_MASK +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT 0b01111111 // 7 7 timeout +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE 0b10111111 // 6 6 packet reception complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR 0b11011111 // 5 5 payload CRC error +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER 0b11101111 // 4 4 valid header received +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_TX_DONE 0b11110111 // 3 3 payload transmission complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation + +// RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR +#define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only + +// RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR +#define RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for RX only + +// RADIOLIB_SX127X_REG_SYNC_WORD +#define RADIOLIB_SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word +#define RADIOLIB_SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks + +// RADIOLIB_SX127X_REG_INVERT_IQ2 +#define RADIOLIB_SX127X_IQ2_ENABLE 0x19 // 7 0 enable optimize for inverted IQ +#define RADIOLIB_SX127X_IQ2_DISABLE 0x1D // 7 0 reset optimize for inverted IQ // SX127x series common FSK registers // NOTE: FSK register names that are conflicting with LoRa registers are marked with "_FSK" suffix -#define RADIOLIB_SX127X_REG_BITRATE_MSB 0x02 -#define RADIOLIB_SX127X_REG_BITRATE_LSB 0x03 -#define RADIOLIB_SX127X_REG_FDEV_MSB 0x04 -#define RADIOLIB_SX127X_REG_FDEV_LSB 0x05 -#define RADIOLIB_SX127X_REG_RX_CONFIG 0x0D -#define RADIOLIB_SX127X_REG_RSSI_CONFIG 0x0E -#define RADIOLIB_SX127X_REG_RSSI_COLLISION 0x0F -#define RADIOLIB_SX127X_REG_RSSI_THRESH 0x10 -#define RADIOLIB_SX127X_REG_RSSI_VALUE_FSK 0x11 -#define RADIOLIB_SX127X_REG_RX_BW 0x12 -#define RADIOLIB_SX127X_REG_AFC_BW 0x13 -#define RADIOLIB_SX127X_REG_OOK_PEAK 0x14 -#define RADIOLIB_SX127X_REG_OOK_FIX 0x15 -#define RADIOLIB_SX127X_REG_OOK_AVG 0x16 -#define RADIOLIB_SX127X_REG_AFC_FEI 0x1A -#define RADIOLIB_SX127X_REG_AFC_MSB 0x1B -#define RADIOLIB_SX127X_REG_AFC_LSB 0x1C -#define RADIOLIB_SX127X_REG_FEI_MSB_FSK 0x1D -#define RADIOLIB_SX127X_REG_FEI_LSB_FSK 0x1E -#define RADIOLIB_SX127X_REG_PREAMBLE_DETECT 0x1F -#define RADIOLIB_SX127X_REG_RX_TIMEOUT_1 0x20 -#define RADIOLIB_SX127X_REG_RX_TIMEOUT_2 0x21 -#define RADIOLIB_SX127X_REG_RX_TIMEOUT_3 0x22 -#define RADIOLIB_SX127X_REG_RX_DELAY 0x23 -#define RADIOLIB_SX127X_REG_OSC 0x24 -#define RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK 0x25 -#define RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK 0x26 -#define RADIOLIB_SX127X_REG_SYNC_CONFIG 0x27 -#define RADIOLIB_SX127X_REG_SYNC_VALUE_1 0x28 -#define RADIOLIB_SX127X_REG_SYNC_VALUE_2 0x29 -#define RADIOLIB_SX127X_REG_SYNC_VALUE_3 0x2A -#define RADIOLIB_SX127X_REG_SYNC_VALUE_4 0x2B -#define RADIOLIB_SX127X_REG_SYNC_VALUE_5 0x2C -#define RADIOLIB_SX127X_REG_SYNC_VALUE_6 0x2D -#define RADIOLIB_SX127X_REG_SYNC_VALUE_7 0x2E -#define RADIOLIB_SX127X_REG_SYNC_VALUE_8 0x2F -#define RADIOLIB_SX127X_REG_PACKET_CONFIG_1 0x30 -#define RADIOLIB_SX127X_REG_PACKET_CONFIG_2 0x31 -#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK 0x32 -#define RADIOLIB_SX127X_REG_NODE_ADRS 0x33 -#define RADIOLIB_SX127X_REG_BROADCAST_ADRS 0x34 -#define RADIOLIB_SX127X_REG_FIFO_THRESH 0x35 -#define RADIOLIB_SX127X_REG_SEQ_CONFIG_1 0x36 -#define RADIOLIB_SX127X_REG_SEQ_CONFIG_2 0x37 -#define RADIOLIB_SX127X_REG_TIMER_RESOL 0x38 -#define RADIOLIB_SX127X_REG_TIMER1_COEF 0x39 -#define RADIOLIB_SX127X_REG_TIMER2_COEF 0x3A -#define RADIOLIB_SX127X_REG_IMAGE_CAL 0x3B -#define RADIOLIB_SX127X_REG_TEMP 0x3C -#define RADIOLIB_SX127X_REG_LOW_BAT 0x3D -#define RADIOLIB_SX127X_REG_IRQ_FLAGS_1 0x3E -#define RADIOLIB_SX127X_REG_IRQ_FLAGS_2 0x3F +#define RADIOLIB_SX127X_REG_BITRATE_MSB 0x02 +#define RADIOLIB_SX127X_REG_BITRATE_LSB 0x03 +#define RADIOLIB_SX127X_REG_FDEV_MSB 0x04 +#define RADIOLIB_SX127X_REG_FDEV_LSB 0x05 +#define RADIOLIB_SX127X_REG_RX_CONFIG 0x0D +#define RADIOLIB_SX127X_REG_RSSI_CONFIG 0x0E +#define RADIOLIB_SX127X_REG_RSSI_COLLISION 0x0F +#define RADIOLIB_SX127X_REG_RSSI_THRESH 0x10 +#define RADIOLIB_SX127X_REG_RSSI_VALUE_FSK 0x11 +#define RADIOLIB_SX127X_REG_RX_BW 0x12 +#define RADIOLIB_SX127X_REG_AFC_BW 0x13 +#define RADIOLIB_SX127X_REG_OOK_PEAK 0x14 +#define RADIOLIB_SX127X_REG_OOK_FIX 0x15 +#define RADIOLIB_SX127X_REG_OOK_AVG 0x16 +#define RADIOLIB_SX127X_REG_AFC_FEI 0x1A +#define RADIOLIB_SX127X_REG_AFC_MSB 0x1B +#define RADIOLIB_SX127X_REG_AFC_LSB 0x1C +#define RADIOLIB_SX127X_REG_FEI_MSB_FSK 0x1D +#define RADIOLIB_SX127X_REG_FEI_LSB_FSK 0x1E +#define RADIOLIB_SX127X_REG_PREAMBLE_DETECT 0x1F +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_1 0x20 +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_2 0x21 +#define RADIOLIB_SX127X_REG_RX_TIMEOUT_3 0x22 +#define RADIOLIB_SX127X_REG_RX_DELAY 0x23 +#define RADIOLIB_SX127X_REG_OSC 0x24 +#define RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK 0x25 +#define RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK 0x26 +#define RADIOLIB_SX127X_REG_SYNC_CONFIG 0x27 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_1 0x28 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_2 0x29 +#define RADIOLIB_SX127X_REG_SYNC_VALUE_3 0x2A +#define RADIOLIB_SX127X_REG_SYNC_VALUE_4 0x2B +#define RADIOLIB_SX127X_REG_SYNC_VALUE_5 0x2C +#define RADIOLIB_SX127X_REG_SYNC_VALUE_6 0x2D +#define RADIOLIB_SX127X_REG_SYNC_VALUE_7 0x2E +#define RADIOLIB_SX127X_REG_SYNC_VALUE_8 0x2F +#define RADIOLIB_SX127X_REG_PACKET_CONFIG_1 0x30 +#define RADIOLIB_SX127X_REG_PACKET_CONFIG_2 0x31 +#define RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK 0x32 +#define RADIOLIB_SX127X_REG_NODE_ADRS 0x33 +#define RADIOLIB_SX127X_REG_BROADCAST_ADRS 0x34 +#define RADIOLIB_SX127X_REG_FIFO_THRESH 0x35 +#define RADIOLIB_SX127X_REG_SEQ_CONFIG_1 0x36 +#define RADIOLIB_SX127X_REG_SEQ_CONFIG_2 0x37 +#define RADIOLIB_SX127X_REG_TIMER_RESOL 0x38 +#define RADIOLIB_SX127X_REG_TIMER1_COEF 0x39 +#define RADIOLIB_SX127X_REG_TIMER2_COEF 0x3A +#define RADIOLIB_SX127X_REG_IMAGE_CAL 0x3B +#define RADIOLIB_SX127X_REG_TEMP 0x3C +#define RADIOLIB_SX127X_REG_LOW_BAT 0x3D +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_1 0x3E +#define RADIOLIB_SX127X_REG_IRQ_FLAGS_2 0x3F // SX127x common FSK modem settings -// SX127X_REG_OP_MODE -#define RADIOLIB_SX127X_MODULATION_FSK 0b00000000 // 6 5 FSK modulation scheme -#define RADIOLIB_SX127X_MODULATION_OOK 0b00100000 // 6 5 OOK modulation scheme -#define RADIOLIB_SX127X_RX 0b00000101 // 2 0 receiver mode - -// SX127X_REG_BITRATE_MSB + SX127X_REG_BITRATE_LSB -#define RADIOLIB_SX127X_BITRATE_MSB 0x1A // 7 0 bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16) -#define RADIOLIB_SX127X_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps - -// SX127X_REG_FDEV_MSB + SX127X_REG_FDEV_LSB -#define RADIOLIB_SX127X_FDEV_MSB 0x00 // 5 0 frequency deviation: Fdev = Fstep * FDEV -#define RADIOLIB_SX127X_FDEV_LSB 0x52 // 7 0 default value: 5 kHz - -// SX127X_REG_RX_CONFIG -#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_OFF 0b00000000 // 7 7 automatic receiver restart disabled (default) -#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_ON 0b10000000 // 7 7 automatically restart receiver if it gets saturated or on packet collision -#define RADIOLIB_SX127X_RESTART_RX_WITHOUT_PLL_LOCK 0b01000000 // 6 6 manually restart receiver without frequency change -#define RADIOLIB_SX127X_RESTART_RX_WITH_PLL_LOCK 0b00100000 // 5 5 manually restart receiver with frequency change -#define RADIOLIB_SX127X_AFC_AUTO_OFF 0b00000000 // 4 4 no AFC performed (default) -#define RADIOLIB_SX127X_AFC_AUTO_ON 0b00010000 // 4 4 AFC performed at each receiver startup -#define RADIOLIB_SX127X_AGC_AUTO_OFF 0b00000000 // 3 3 LNA gain set manually by register -#define RADIOLIB_SX127X_AGC_AUTO_ON 0b00001000 // 3 3 LNA gain controlled by AGC -#define RADIOLIB_SX127X_RX_TRIGGER_NONE 0b00000000 // 2 0 receiver startup at: none -#define RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT 0b00000001 // 2 0 RSSI interrupt -#define RADIOLIB_SX127X_RX_TRIGGER_PREAMBLE_DETECT 0b00000110 // 2 0 preamble detected -#define RADIOLIB_SX127X_RX_TRIGGER_BOTH 0b00000111 // 2 0 RSSI interrupt and preamble detected - -// SX127X_REG_RSSI_CONFIG -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_2 0b00000000 // 2 0 number of samples for RSSI average: 2 -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_4 0b00000001 // 2 0 4 -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_8 0b00000010 // 2 0 8 (default) -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_16 0b00000011 // 2 0 16 -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_32 0b00000100 // 2 0 32 -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_64 0b00000101 // 2 0 64 -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_128 0b00000110 // 2 0 128 -#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_256 0b00000111 // 2 0 256 - -// SX127X_REG_RSSI_COLLISION -#define RADIOLIB_SX127X_RSSI_COLLISION_THRESHOLD 0x0A // 7 0 RSSI threshold in dB that will be considered a collision, default value: 10 dB - -// SX127X_REG_RSSI_THRESH -#define RADIOLIB_SX127X_RSSI_THRESHOLD 0xFF // 7 0 RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm] - -// SX127X_REG_RX_BW -#define RADIOLIB_SX127X_RX_BW_MANT_16 0b00000000 // 4 3 channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz] -#define RADIOLIB_SX127X_RX_BW_MANT_20 0b00001000 // 4 3 -#define RADIOLIB_SX127X_RX_BW_MANT_24 0b00010000 // 4 3 default RxBwMant parameter -#define RADIOLIB_SX127X_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp parameter - -// SX127X_REG_AFC_BW -#define RADIOLIB_SX127X_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter used during AFC -#define RADIOLIB_SX127X_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter used during AFC - -// SX127X_REG_OOK_PEAK -#define RADIOLIB_SX127X_BIT_SYNC_OFF 0b00000000 // 5 5 bit synchronizer disabled (not allowed in packet mode) -#define RADIOLIB_SX127X_BIT_SYNC_ON 0b00100000 // 5 5 bit synchronizer enabled (default) -#define RADIOLIB_SX127X_OOK_THRESH_FIXED 0b00000000 // 4 3 OOK threshold type: fixed value -#define RADIOLIB_SX127X_OOK_THRESH_PEAK 0b00001000 // 4 3 peak mode (default) -#define RADIOLIB_SX127X_OOK_THRESH_AVERAGE 0b00010000 // 4 3 average mode -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 2 0 OOK demodulator step size: 0.5 dB (default) -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB 0b00000001 // 2 0 1.0 dB -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB 0b00000010 // 2 0 1.5 dB -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB 0b00000011 // 2 0 2.0 dB -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB 0b00000100 // 2 0 3.0 dB -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB 0b00000101 // 2 0 4.0 dB -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB 0b00000110 // 2 0 5.0 dB -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB 0b00000111 // 2 0 6.0 dB - -// SX127X_REG_OOK_FIX -#define RADIOLIB_SX127X_OOK_FIXED_THRESHOLD 0x0C // 7 0 default fixed threshold for OOK data slicer - -// SX127X_REG_OOK_AVG -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 7 5 OOK demodulator step period: once per chip (default) -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00100000 // 7 5 once every 2 chips -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b01000000 // 7 5 once every 4 chips -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b01100000 // 7 5 once every 8 chips -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b10000000 // 7 5 2 times per chip -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b10100000 // 7 5 4 times per chip -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b11000000 // 7 5 8 times per chip -#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b11100000 // 7 5 16 times per chip -#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_0_DB 0b00000000 // 3 2 OOK average threshold offset: 0.0 dB (default) -#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_2_DB 0b00000100 // 3 2 2.0 dB -#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_4_DB 0b00001000 // 3 2 4.0 dB -#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_6_DB 0b00001100 // 3 2 6.0 dB -#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 1 0 OOK average filter coefficient: chip rate / 32*pi -#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_8_PI 0b00000001 // 1 0 chip rate / 8*pi -#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_4_PI 0b00000010 // 1 0 chip rate / 4*pi (default) -#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_2_PI 0b00000011 // 1 0 chip rate / 2*pi - -// SX127X_REG_AFC_FEI -#define RADIOLIB_SX127X_AGC_START 0b00010000 // 4 4 manually start AGC sequence -#define RADIOLIB_SX127X_AFC_CLEAR 0b00000010 // 1 1 manually clear AFC register -#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_OFF 0b00000000 // 0 0 AFC register will not be cleared at the start of AFC (default) -#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_ON 0b00000001 // 0 0 AFC register will be cleared at the start of AFC - -// SX127X_REG_PREAMBLE_DETECT -#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_OFF 0b00000000 // 7 7 preamble detection disabled -#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON 0b10000000 // 7 7 preamble detection enabled (default) -#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_1_BYTE 0b00000000 // 6 5 preamble detection size: 1 byte (default) -#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE 0b00100000 // 6 5 2 bytes -#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_3_BYTE 0b01000000 // 6 5 3 bytes -#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL 0x0A // 4 0 default number of tolerated errors per chip (4 chips per bit) - -// SX127X_REG_RX_TIMEOUT_1 -#define RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF 0x00 // 7 0 disable receiver timeout when RSSI interrupt doesn't occur (default) - -// SX127X_REG_RX_TIMEOUT_2 -#define RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF 0x00 // 7 0 disable receiver timeout when preamble interrupt doesn't occur (default) - -// SX127X_REG_RX_TIMEOUT_3 -#define RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF 0x00 // 7 0 disable receiver timeout when sync address interrupt doesn't occur (default) - -// SX127X_REG_OSC -#define RADIOLIB_SX127X_RC_CAL_START 0b00000000 // 3 3 manually start RC oscillator calibration -#define RADIOLIB_SX127X_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) -#define RADIOLIB_SX127X_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 -#define RADIOLIB_SX127X_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 -#define RADIOLIB_SX127X_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 -#define RADIOLIB_SX127X_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 -#define RADIOLIB_SX127X_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 32 -#define RADIOLIB_SX127X_CLK_OUT_RC 0b00000110 // 2 0 RC -#define RADIOLIB_SX127X_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) - -// SX127X_REG_PREAMBLE_MSB_FSK + SX127X_REG_PREAMBLE_LSB_FSK -#define RADIOLIB_SX127X_PREAMBLE_SIZE_MSB 0x00 // 7 0 preamble size in bytes -#define RADIOLIB_SX127X_PREAMBLE_SIZE_LSB 0x03 // 7 0 default value: 3 bytes - -// SX127X_REG_SYNC_CONFIG -#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_OFF 0b00000000 // 7 6 Rx mode restart after packet reception: disabled -#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_NO_PLL 0b01000000 // 7 6 enabled, don't wait for PLL lock -#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_PLL 0b10000000 // 7 6 enabled, wait for PLL lock (default) -#define RADIOLIB_SX127X_PREAMBLE_POLARITY_AA 0b00000000 // 5 5 preamble polarity: 0xAA = 0b10101010 (default) -#define RADIOLIB_SX127X_PREAMBLE_POLARITY_55 0b00100000 // 5 5 0x55 = 0b01010101 -#define RADIOLIB_SX127X_SYNC_OFF 0b00000000 // 4 4 sync word disabled -#define RADIOLIB_SX127X_SYNC_ON 0b00010000 // 4 4 sync word enabled (default) -#define RADIOLIB_SX127X_SYNC_SIZE 0x03 // 2 0 sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes - -// SX127X_REG_SYNC_VALUE_1 - SX127X_REG_SYNC_VALUE_8 -#define RADIOLIB_SX127X_SYNC_VALUE_1 0x01 // 7 0 sync word: 1st byte (MSB) -#define RADIOLIB_SX127X_SYNC_VALUE_2 0x01 // 7 0 2nd byte -#define RADIOLIB_SX127X_SYNC_VALUE_3 0x01 // 7 0 3rd byte -#define RADIOLIB_SX127X_SYNC_VALUE_4 0x01 // 7 0 4th byte -#define RADIOLIB_SX127X_SYNC_VALUE_5 0x01 // 7 0 5th byte -#define RADIOLIB_SX127X_SYNC_VALUE_6 0x01 // 7 0 6th byte -#define RADIOLIB_SX127X_SYNC_VALUE_7 0x01 // 7 0 7th byte -#define RADIOLIB_SX127X_SYNC_VALUE_8 0x01 // 7 0 8th byte (LSB) - -// SX127X_REG_PACKET_CONFIG_1 -#define RADIOLIB_SX127X_PACKET_FIXED 0b00000000 // 7 7 packet format: fixed length -#define RADIOLIB_SX127X_PACKET_VARIABLE 0b10000000 // 7 7 variable length (default) -#define RADIOLIB_SX127X_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: disabled (default) -#define RADIOLIB_SX127X_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester -#define RADIOLIB_SX127X_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening -#define RADIOLIB_SX127X_CRC_OFF 0b00000000 // 4 4 CRC disabled -#define RADIOLIB_SX127X_CRC_ON 0b00010000 // 4 4 CRC enabled (default) -#define RADIOLIB_SX127X_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep FIFO on CRC mismatch, issue payload ready interrupt -#define RADIOLIB_SX127X_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 clear FIFO on CRC mismatch, do not issue payload ready interrupt -#define RADIOLIB_SX127X_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) -#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node -#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast -#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT 0b00000000 // 0 0 CRC and whitening algorithms: CCITT CRC with standard whitening (default) -#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM 0b00000001 // 0 0 IBM CRC with alternate whitening - -// SX127X_REG_PACKET_CONFIG_2 -#define RADIOLIB_SX127X_DATA_MODE_PACKET 0b01000000 // 6 6 data mode: packet (default) -#define RADIOLIB_SX127X_DATA_MODE_CONTINUOUS 0b00000000 // 6 6 continuous -#define RADIOLIB_SX127X_IO_HOME_OFF 0b00000000 // 5 5 io-homecontrol compatibility disabled (default) -#define RADIOLIB_SX127X_IO_HOME_ON 0b00100000 // 5 5 io-homecontrol compatibility enabled - -// SX127X_REG_FIFO_THRESH -#define RADIOLIB_SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD -#define RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) -#define RADIOLIB_SX127X_FIFO_THRESH 0x1F // 5 0 FIFO level threshold - -// SX127X_REG_SEQ_CONFIG_1 -#define RADIOLIB_SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer -#define RADIOLIB_SX127X_SEQUENCER_STOP 0b01000000 // 6 6 manually stop sequencer -#define RADIOLIB_SX127X_IDLE_MODE_STANDBY 0b00000000 // 5 5 chip mode during sequencer idle mode: standby (default) -#define RADIOLIB_SX127X_IDLE_MODE_SLEEP 0b00100000 // 5 5 sleep -#define RADIOLIB_SX127X_FROM_START_LP_SELECTION 0b00000000 // 4 3 mode that will be set after starting sequencer: low power selection (default) -#define RADIOLIB_SX127X_FROM_START_RECEIVE 0b00001000 // 4 3 receive -#define RADIOLIB_SX127X_FROM_START_TRANSMIT 0b00010000 // 4 3 transmit -#define RADIOLIB_SX127X_FROM_START_TRANSMIT_FIFO_LEVEL 0b00011000 // 4 3 transmit on a FIFO level interrupt -#define RADIOLIB_SX127X_LP_SELECTION_SEQ_OFF 0b00000000 // 2 2 mode that will be set after exiting low power selection: sequencer off (default) -#define RADIOLIB_SX127X_LP_SELECTION_IDLE 0b00000100 // 2 2 idle state -#define RADIOLIB_SX127X_FROM_IDLE_TRANSMIT 0b00000000 // 1 1 mode that will be set after exiting idle mode: transmit (default) -#define RADIOLIB_SX127X_FROM_IDLE_RECEIVE 0b00000010 // 1 1 receive -#define RADIOLIB_SX127X_FROM_TRANSMIT_LP_SELECTION 0b00000000 // 0 0 mode that will be set after exiting transmit mode: low power selection (default) -#define RADIOLIB_SX127X_FROM_TRANSMIT_RECEIVE 0b00000001 // 0 0 receive - -// SX127X_REG_SEQ_CONFIG_2 -#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD 0b00100000 // 7 5 mode that will be set after exiting receive mode: packet received on payload ready interrupt (default) -#define RADIOLIB_SX127X_FROM_RECEIVE_LP_SELECTION 0b01000000 // 7 5 low power selection -#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK 0b01100000 // 7 5 packet received on CRC OK interrupt -#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_RSSI 0b10000000 // 7 5 sequencer off on RSSI interrupt -#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR 0b10100000 // 7 5 sequencer off on sync address interrupt -#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT 0b11000000 // 7 5 sequencer off on preamble detect interrupt -#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_RECEIVE 0b00000000 // 4 3 mode that will be set after Rx timeout: receive (default) -#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_TRANSMIT 0b00001000 // 4 3 transmit -#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_LP_SELECTION 0b00010000 // 4 3 low power selection -#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_SEQ_OFF 0b00011000 // 4 3 sequencer off -#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_SEQ_OFF 0b00000000 // 2 0 mode that will be set after packet received: sequencer off (default) -#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_TRANSMIT 0b00000001 // 2 0 transmit -#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_LP_SELECTION 0b00000010 // 2 0 low power selection -#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE_FS 0b00000011 // 2 0 receive via FS -#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE 0b00000100 // 2 0 receive - -// SX127X_REG_TIMER_RESOL -#define RADIOLIB_SX127X_TIMER1_OFF 0b00000000 // 3 2 timer 1 resolution: disabled (default) -#define RADIOLIB_SX127X_TIMER1_RESOLUTION_64_US 0b00000100 // 3 2 64 us -#define RADIOLIB_SX127X_TIMER1_RESOLUTION_4_1_MS 0b00001000 // 3 2 4.1 ms -#define RADIOLIB_SX127X_TIMER1_RESOLUTION_262_MS 0b00001100 // 3 2 262 ms -#define RADIOLIB_SX127X_TIMER2_OFF 0b00000000 // 3 2 timer 2 resolution: disabled (default) -#define RADIOLIB_SX127X_TIMER2_RESOLUTION_64_US 0b00000001 // 3 2 64 us -#define RADIOLIB_SX127X_TIMER2_RESOLUTION_4_1_MS 0b00000010 // 3 2 4.1 ms -#define RADIOLIB_SX127X_TIMER2_RESOLUTION_262_MS 0b00000011 // 3 2 262 ms - -// SX127X_REG_TIMER1_COEF -#define RADIOLIB_SX127X_TIMER1_COEFFICIENT 0xF5 // 7 0 multiplication coefficient for timer 1 - -// SX127X_REG_TIMER2_COEF -#define RADIOLIB_SX127X_TIMER2_COEFFICIENT 0x20 // 7 0 multiplication coefficient for timer 2 - -// SX127X_REG_IMAGE_CAL -#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_OFF 0b00000000 // 7 7 temperature calibration disabled (default) -#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_ON 0b10000000 // 7 7 temperature calibration enabled -#define RADIOLIB_SX127X_IMAGE_CAL_START 0b01000000 // 6 6 start temperature calibration -#define RADIOLIB_SX127X_IMAGE_CAL_RUNNING 0b00100000 // 5 5 temperature calibration is on-going -#define RADIOLIB_SX127X_IMAGE_CAL_COMPLETE 0b00000000 // 5 5 temperature calibration finished -#define RADIOLIB_SX127X_TEMP_CHANGED 0b00001000 // 3 3 temperature changed more than TEMP_THRESHOLD since last calibration -#define RADIOLIB_SX127X_TEMP_THRESHOLD_5_DEG_C 0b00000000 // 2 1 temperature change threshold: 5 deg. C -#define RADIOLIB_SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) -#define RADIOLIB_SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C -#define RADIOLIB_SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C -#define RADIOLIB_SX127X_TEMP_MONITOR_ON 0b00000000 // 0 0 temperature monitoring enabled (default) -#define RADIOLIB_SX127X_TEMP_MONITOR_OFF 0b00000001 // 0 0 temperature monitoring disabled - -// SX127X_REG_LOW_BAT -#define RADIOLIB_SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled -#define RADIOLIB_SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_764_V 0b00000001 // 2 0 1.764 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_835_V 0b00000010 // 2 0 1.835 V (default) -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_905_V 0b00000011 // 2 0 1.905 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_976_V 0b00000100 // 2 0 1.976 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_045_V 0b00000101 // 2 0 2.045 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_116_V 0b00000110 // 2 0 2.116 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_185_V 0b00000111 // 2 0 2.185 V - -// SX127X_REG_IRQ_FLAGS_1 -#define RADIOLIB_SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready -#define RADIOLIB_SX127X_FLAG_RX_READY 0b01000000 // 6 6 reception ready (after RSSI, AGC, AFC) -#define RADIOLIB_SX127X_FLAG_TX_READY 0b00100000 // 5 5 transmission ready (after PA ramp-up) -#define RADIOLIB_SX127X_FLAG_PLL_LOCK 0b00010000 // 4 4 PLL locked -#define RADIOLIB_SX127X_FLAG_RSSI 0b00001000 // 3 3 RSSI value exceeds RSSI threshold -#define RADIOLIB_SX127X_FLAG_TIMEOUT 0b00000100 // 2 2 timeout occurred -#define RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected -#define RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched - -// SX127X_REG_IRQ_FLAGS_2 -#define RADIOLIB_SX127X_FLAG_FIFO_FULL 0b10000000 // 7 7 FIFO is full -#define RADIOLIB_SX127X_FLAG_FIFO_EMPTY 0b01000000 // 6 6 FIFO is empty -#define RADIOLIB_SX127X_FLAG_FIFO_LEVEL 0b00100000 // 5 5 number of bytes in FIFO exceeds FIFO_THRESHOLD -#define RADIOLIB_SX127X_FLAG_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred -#define RADIOLIB_SX127X_FLAG_PACKET_SENT 0b00001000 // 3 3 packet was successfully sent -#define RADIOLIB_SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received -#define RADIOLIB_SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed -#define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold - -// SX127X_REG_DIO_MAPPING_1 -#define RADIOLIB_SX127X_DIO0_LORA_RX_DONE 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_LORA_TX_DONE 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_LORA_CAD_DONE 0b10000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_RSSI_PREAMBLE_DETECT 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 -#define RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED 0b00100000 // 5 4 -#define RADIOLIB_SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 -#define RADIOLIB_SX127X_DIO2_LORA_FHSS_CHANGE_CHANNEL 0b00000000 // 3 2 -#define RADIOLIB_SX127X_DIO2_CONT_DATA 0b00000000 // 3 2 -#define RADIOLIB_SX127X_DIO2_PACK_FIFO_FULL 0b00000000 // 3 2 -#define RADIOLIB_SX127X_DIO2_PACK_RX_READY 0b00000100 // 3 2 -#define RADIOLIB_SX127X_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 -#define RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 -#define RADIOLIB_SX127X_DIO3_LORA_CAD_DONE 0b00000000 // 1 0 -#define RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER 0b00000001 // 1 0 -#define RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 1 0 -#define RADIOLIB_SX127X_DIO3_CONT_TIMEOUT 0b00000000 // 1 0 -#define RADIOLIB_SX127X_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 1 0 -#define RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 1 0 -#define RADIOLIB_SX127X_DIO3_PACK_FIFO_EMPTY 0b00000000 // 1 0 -#define RADIOLIB_SX127X_DIO3_PACK_TX_READY 0b00000001 // 1 0 - -// SX127X_REG_DIO_MAPPING_2 -#define RADIOLIB_SX127X_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_LORA_PLL_LOCK 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_CONT_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_CONT_PLL_LOCK 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_CONT_TIMEOUT 0b10000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_CONT_MODE_READY 0b11000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_PACK_PLL_LOCK 0b01000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_PACK_TIMEOUT 0b10000000 // 7 6 -#define RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT 0b11000000 // 7 6 -#define RADIOLIB_SX127X_DIO5_LORA_MODE_READY 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO5_LORA_CLK_OUT 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO5_CONT_PLL_LOCK 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO5_CONT_RSSI_PREAMBLE_DETECT 0b00100000 // 5 4 -#define RADIOLIB_SX127X_DIO5_CONT_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX127X_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 -#define RADIOLIB_SX127X_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 -#define RADIOLIB_SX127X_DIO5_PACK_DATA 0b00100000 // 5 4 -#define RADIOLIB_SX127X_DIO5_PACK_MODE_READY 0b00110000 // 5 4 -#define RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 -#define RADIOLIB_SX127X_DIO_MAP_RSSI 0b00000000 // 0 0 +// RADIOLIB_SX127X_REG_OP_MODE +#define RADIOLIB_SX127X_MODULATION_FSK 0b00000000 // 6 5 FSK modulation scheme +#define RADIOLIB_SX127X_MODULATION_OOK 0b00100000 // 6 5 OOK modulation scheme +#define RADIOLIB_SX127X_RX 0b00000101 // 2 0 receiver mode + +// RADIOLIB_SX127X_REG_BITRATE_MSB + SX127X_REG_BITRATE_LSB +#define RADIOLIB_SX127X_BITRATE_MSB 0x1A // 7 0 bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16) +#define RADIOLIB_SX127X_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps + +// RADIOLIB_SX127X_REG_FDEV_MSB + SX127X_REG_FDEV_LSB +#define RADIOLIB_SX127X_FDEV_MSB 0x00 // 5 0 frequency deviation: Fdev = Fstep * FDEV +#define RADIOLIB_SX127X_FDEV_LSB 0x52 // 7 0 default value: 5 kHz + +// RADIOLIB_SX127X_REG_RX_CONFIG +#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_OFF 0b00000000 // 7 7 automatic receiver restart disabled (default) +#define RADIOLIB_SX127X_RESTART_RX_ON_COLLISION_ON 0b10000000 // 7 7 automatically restart receiver if it gets saturated or on packet collision +#define RADIOLIB_SX127X_RESTART_RX_WITHOUT_PLL_LOCK 0b01000000 // 6 6 manually restart receiver without frequency change +#define RADIOLIB_SX127X_RESTART_RX_WITH_PLL_LOCK 0b00100000 // 5 5 manually restart receiver with frequency change +#define RADIOLIB_SX127X_AFC_AUTO_OFF 0b00000000 // 4 4 no AFC performed (default) +#define RADIOLIB_SX127X_AFC_AUTO_ON 0b00010000 // 4 4 AFC performed at each receiver startup +#define RADIOLIB_SX127X_AGC_AUTO_OFF 0b00000000 // 3 3 LNA gain set manually by register +#define RADIOLIB_SX127X_AGC_AUTO_ON 0b00001000 // 3 3 LNA gain controlled by AGC +#define RADIOLIB_SX127X_RX_TRIGGER_NONE 0b00000000 // 2 0 receiver startup at: none +#define RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT 0b00000001 // 2 0 RSSI interrupt +#define RADIOLIB_SX127X_RX_TRIGGER_PREAMBLE_DETECT 0b00000110 // 2 0 preamble detected +#define RADIOLIB_SX127X_RX_TRIGGER_BOTH 0b00000111 // 2 0 RSSI interrupt and preamble detected + +// RADIOLIB_SX127X_REG_RSSI_CONFIG +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_2 0b00000000 // 2 0 number of samples for RSSI average: 2 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_4 0b00000001 // 2 0 4 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_8 0b00000010 // 2 0 8 (default) +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_16 0b00000011 // 2 0 16 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_32 0b00000100 // 2 0 32 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_64 0b00000101 // 2 0 64 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_128 0b00000110 // 2 0 128 +#define RADIOLIB_SX127X_RSSI_SMOOTHING_SAMPLES_256 0b00000111 // 2 0 256 + +// RADIOLIB_SX127X_REG_RSSI_COLLISION +#define RADIOLIB_SX127X_RSSI_COLLISION_THRESHOLD 0x0A // 7 0 RSSI threshold in dB that will be considered a collision, default value: 10 dB + +// RADIOLIB_SX127X_REG_RSSI_THRESH +#define RADIOLIB_SX127X_RSSI_THRESHOLD 0xFF // 7 0 RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm] + +// RADIOLIB_SX127X_REG_RX_BW +#define RADIOLIB_SX127X_RX_BW_MANT_16 0b00000000 // 4 3 channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz] +#define RADIOLIB_SX127X_RX_BW_MANT_20 0b00001000 // 4 3 +#define RADIOLIB_SX127X_RX_BW_MANT_24 0b00010000 // 4 3 default RxBwMant parameter +#define RADIOLIB_SX127X_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp parameter + +// RADIOLIB_SX127X_REG_AFC_BW +#define RADIOLIB_SX127X_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter used during AFC +#define RADIOLIB_SX127X_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter used during AFC + +// RADIOLIB_SX127X_REG_OOK_PEAK +#define RADIOLIB_SX127X_BIT_SYNC_OFF 0b00000000 // 5 5 bit synchronizer disabled (not allowed in packet mode) +#define RADIOLIB_SX127X_BIT_SYNC_ON 0b00100000 // 5 5 bit synchronizer enabled (default) +#define RADIOLIB_SX127X_OOK_THRESH_FIXED 0b00000000 // 4 3 OOK threshold type: fixed value +#define RADIOLIB_SX127X_OOK_THRESH_PEAK 0b00001000 // 4 3 peak mode (default) +#define RADIOLIB_SX127X_OOK_THRESH_AVERAGE 0b00010000 // 4 3 average mode +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 2 0 OOK demodulator step size: 0.5 dB (default) +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB 0b00000001 // 2 0 1.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB 0b00000010 // 2 0 1.5 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB 0b00000011 // 2 0 2.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB 0b00000100 // 2 0 3.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB 0b00000101 // 2 0 4.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB 0b00000110 // 2 0 5.0 dB +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB 0b00000111 // 2 0 6.0 dB + +// RADIOLIB_SX127X_REG_OOK_FIX +#define RADIOLIB_SX127X_OOK_FIXED_THRESHOLD 0x0C // 7 0 default fixed threshold for OOK data slicer + +// RADIOLIB_SX127X_REG_OOK_AVG +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 7 5 OOK demodulator step period: once per chip (default) +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00100000 // 7 5 once every 2 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b01000000 // 7 5 once every 4 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b01100000 // 7 5 once every 8 chips +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b10000000 // 7 5 2 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b10100000 // 7 5 4 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b11000000 // 7 5 8 times per chip +#define RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b11100000 // 7 5 16 times per chip +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_0_DB 0b00000000 // 3 2 OOK average threshold offset: 0.0 dB (default) +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_2_DB 0b00000100 // 3 2 2.0 dB +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_4_DB 0b00001000 // 3 2 4.0 dB +#define RADIOLIB_SX127X_OOK_AVERAGE_OFFSET_6_DB 0b00001100 // 3 2 6.0 dB +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 1 0 OOK average filter coefficient: chip rate / 32*pi +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_8_PI 0b00000001 // 1 0 chip rate / 8*pi +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_4_PI 0b00000010 // 1 0 chip rate / 4*pi (default) +#define RADIOLIB_SX127X_OOK_AVG_THRESH_FILT_2_PI 0b00000011 // 1 0 chip rate / 2*pi + +// RADIOLIB_SX127X_REG_AFC_FEI +#define RADIOLIB_SX127X_AGC_START 0b00010000 // 4 4 manually start AGC sequence +#define RADIOLIB_SX127X_AFC_CLEAR 0b00000010 // 1 1 manually clear AFC register +#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_OFF 0b00000000 // 0 0 AFC register will not be cleared at the start of AFC (default) +#define RADIOLIB_SX127X_AFC_AUTO_CLEAR_ON 0b00000001 // 0 0 AFC register will be cleared at the start of AFC + +// RADIOLIB_SX127X_REG_PREAMBLE_DETECT +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_OFF 0b00000000 // 7 7 preamble detection disabled +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON 0b10000000 // 7 7 preamble detection enabled (default) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_1_BYTE 0b00000000 // 6 5 preamble detection size: 1 byte (default) +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE 0b00100000 // 6 5 2 bytes +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_3_BYTE 0b01000000 // 6 5 3 bytes +#define RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL 0x0A // 4 0 default number of tolerated errors per chip (4 chips per bit) + +// RADIOLIB_SX127X_REG_RX_TIMEOUT_1 +#define RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF 0x00 // 7 0 disable receiver timeout when RSSI interrupt doesn't occur (default) + +// RADIOLIB_SX127X_REG_RX_TIMEOUT_2 +#define RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF 0x00 // 7 0 disable receiver timeout when preamble interrupt doesn't occur (default) + +// RADIOLIB_SX127X_REG_RX_TIMEOUT_3 +#define RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF 0x00 // 7 0 disable receiver timeout when sync address interrupt doesn't occur (default) + +// RADIOLIB_SX127X_REG_OSC +#define RADIOLIB_SX127X_RC_CAL_START 0b00000000 // 3 3 manually start RC oscillator calibration +#define RADIOLIB_SX127X_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define RADIOLIB_SX127X_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 32 +#define RADIOLIB_SX127X_CLK_OUT_RC 0b00000110 // 2 0 RC +#define RADIOLIB_SX127X_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) + +// RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK + SX127X_REG_PREAMBLE_LSB_FSK +#define RADIOLIB_SX127X_PREAMBLE_SIZE_MSB 0x00 // 7 0 preamble size in bytes +#define RADIOLIB_SX127X_PREAMBLE_SIZE_LSB 0x03 // 7 0 default value: 3 bytes + +// RADIOLIB_SX127X_REG_SYNC_CONFIG +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_OFF 0b00000000 // 7 6 Rx mode restart after packet reception: disabled +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_NO_PLL 0b01000000 // 7 6 enabled, don't wait for PLL lock +#define RADIOLIB_SX127X_AUTO_RESTART_RX_MODE_PLL 0b10000000 // 7 6 enabled, wait for PLL lock (default) +#define RADIOLIB_SX127X_PREAMBLE_POLARITY_AA 0b00000000 // 5 5 preamble polarity: 0xAA = 0b10101010 (default) +#define RADIOLIB_SX127X_PREAMBLE_POLARITY_55 0b00100000 // 5 5 0x55 = 0b01010101 +#define RADIOLIB_SX127X_SYNC_OFF 0b00000000 // 4 4 sync word disabled +#define RADIOLIB_SX127X_SYNC_ON 0b00010000 // 4 4 sync word enabled (default) +#define RADIOLIB_SX127X_SYNC_SIZE 0x03 // 2 0 sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes + +// RADIOLIB_SX127X_REG_SYNC_VALUE_1 - SX127X_REG_SYNC_VALUE_8 +#define RADIOLIB_SX127X_SYNC_VALUE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define RADIOLIB_SX127X_SYNC_VALUE_2 0x01 // 7 0 2nd byte +#define RADIOLIB_SX127X_SYNC_VALUE_3 0x01 // 7 0 3rd byte +#define RADIOLIB_SX127X_SYNC_VALUE_4 0x01 // 7 0 4th byte +#define RADIOLIB_SX127X_SYNC_VALUE_5 0x01 // 7 0 5th byte +#define RADIOLIB_SX127X_SYNC_VALUE_6 0x01 // 7 0 6th byte +#define RADIOLIB_SX127X_SYNC_VALUE_7 0x01 // 7 0 7th byte +#define RADIOLIB_SX127X_SYNC_VALUE_8 0x01 // 7 0 8th byte (LSB) + +// RADIOLIB_SX127X_REG_PACKET_CONFIG_1 +#define RADIOLIB_SX127X_PACKET_FIXED 0b00000000 // 7 7 packet format: fixed length +#define RADIOLIB_SX127X_PACKET_VARIABLE 0b10000000 // 7 7 variable length (default) +#define RADIOLIB_SX127X_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: disabled (default) +#define RADIOLIB_SX127X_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define RADIOLIB_SX127X_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define RADIOLIB_SX127X_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define RADIOLIB_SX127X_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define RADIOLIB_SX127X_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep FIFO on CRC mismatch, issue payload ready interrupt +#define RADIOLIB_SX127X_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 clear FIFO on CRC mismatch, do not issue payload ready interrupt +#define RADIOLIB_SX127X_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast +#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT 0b00000000 // 0 0 CRC and whitening algorithms: CCITT CRC with standard whitening (default) +#define RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM 0b00000001 // 0 0 IBM CRC with alternate whitening + +// RADIOLIB_SX127X_REG_PACKET_CONFIG_2 +#define RADIOLIB_SX127X_DATA_MODE_PACKET 0b01000000 // 6 6 data mode: packet (default) +#define RADIOLIB_SX127X_DATA_MODE_CONTINUOUS 0b00000000 // 6 6 continuous +#define RADIOLIB_SX127X_IO_HOME_OFF 0b00000000 // 5 5 io-homecontrol compatibility disabled (default) +#define RADIOLIB_SX127X_IO_HOME_ON 0b00100000 // 5 5 io-homecontrol compatibility enabled + +// RADIOLIB_SX127X_REG_FIFO_THRESH +#define RADIOLIB_SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD +#define RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) +#define RADIOLIB_SX127X_FIFO_THRESH 0x1F // 5 0 FIFO level threshold + +// RADIOLIB_SX127X_REG_SEQ_CONFIG_1 +#define RADIOLIB_SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer +#define RADIOLIB_SX127X_SEQUENCER_STOP 0b01000000 // 6 6 manually stop sequencer +#define RADIOLIB_SX127X_IDLE_MODE_STANDBY 0b00000000 // 5 5 chip mode during sequencer idle mode: standby (default) +#define RADIOLIB_SX127X_IDLE_MODE_SLEEP 0b00100000 // 5 5 sleep +#define RADIOLIB_SX127X_FROM_START_LP_SELECTION 0b00000000 // 4 3 mode that will be set after starting sequencer: low power selection (default) +#define RADIOLIB_SX127X_FROM_START_RECEIVE 0b00001000 // 4 3 receive +#define RADIOLIB_SX127X_FROM_START_TRANSMIT 0b00010000 // 4 3 transmit +#define RADIOLIB_SX127X_FROM_START_TRANSMIT_FIFO_LEVEL 0b00011000 // 4 3 transmit on a FIFO level interrupt +#define RADIOLIB_SX127X_LP_SELECTION_SEQ_OFF 0b00000000 // 2 2 mode that will be set after exiting low power selection: sequencer off (default) +#define RADIOLIB_SX127X_LP_SELECTION_IDLE 0b00000100 // 2 2 idle state +#define RADIOLIB_SX127X_FROM_IDLE_TRANSMIT 0b00000000 // 1 1 mode that will be set after exiting idle mode: transmit (default) +#define RADIOLIB_SX127X_FROM_IDLE_RECEIVE 0b00000010 // 1 1 receive +#define RADIOLIB_SX127X_FROM_TRANSMIT_LP_SELECTION 0b00000000 // 0 0 mode that will be set after exiting transmit mode: low power selection (default) +#define RADIOLIB_SX127X_FROM_TRANSMIT_RECEIVE 0b00000001 // 0 0 receive + +// RADIOLIB_SX127X_REG_SEQ_CONFIG_2 +#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD 0b00100000 // 7 5 mode that will be set after exiting receive mode: packet received on payload ready interrupt (default) +#define RADIOLIB_SX127X_FROM_RECEIVE_LP_SELECTION 0b01000000 // 7 5 low power selection +#define RADIOLIB_SX127X_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK 0b01100000 // 7 5 packet received on CRC OK interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_RSSI 0b10000000 // 7 5 sequencer off on RSSI interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR 0b10100000 // 7 5 sequencer off on sync address interrupt +#define RADIOLIB_SX127X_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT 0b11000000 // 7 5 sequencer off on preamble detect interrupt +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_RECEIVE 0b00000000 // 4 3 mode that will be set after Rx timeout: receive (default) +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_TRANSMIT 0b00001000 // 4 3 transmit +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_LP_SELECTION 0b00010000 // 4 3 low power selection +#define RADIOLIB_SX127X_FROM_RX_TIMEOUT_SEQ_OFF 0b00011000 // 4 3 sequencer off +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_SEQ_OFF 0b00000000 // 2 0 mode that will be set after packet received: sequencer off (default) +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_TRANSMIT 0b00000001 // 2 0 transmit +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_LP_SELECTION 0b00000010 // 2 0 low power selection +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE_FS 0b00000011 // 2 0 receive via FS +#define RADIOLIB_SX127X_FROM_PACKET_RECEIVED_RECEIVE 0b00000100 // 2 0 receive + +// RADIOLIB_SX127X_REG_TIMER_RESOL +#define RADIOLIB_SX127X_TIMER1_OFF 0b00000000 // 3 2 timer 1 resolution: disabled (default) +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_64_US 0b00000100 // 3 2 64 us +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_4_1_MS 0b00001000 // 3 2 4.1 ms +#define RADIOLIB_SX127X_TIMER1_RESOLUTION_262_MS 0b00001100 // 3 2 262 ms +#define RADIOLIB_SX127X_TIMER2_OFF 0b00000000 // 3 2 timer 2 resolution: disabled (default) +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_64_US 0b00000001 // 3 2 64 us +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_4_1_MS 0b00000010 // 3 2 4.1 ms +#define RADIOLIB_SX127X_TIMER2_RESOLUTION_262_MS 0b00000011 // 3 2 262 ms + +// RADIOLIB_SX127X_REG_TIMER1_COEF +#define RADIOLIB_SX127X_TIMER1_COEFFICIENT 0xF5 // 7 0 multiplication coefficient for timer 1 + +// RADIOLIB_SX127X_REG_TIMER2_COEF +#define RADIOLIB_SX127X_TIMER2_COEFFICIENT 0x20 // 7 0 multiplication coefficient for timer 2 + +// RADIOLIB_SX127X_REG_IMAGE_CAL +#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_OFF 0b00000000 // 7 7 temperature calibration disabled (default) +#define RADIOLIB_SX127X_AUTO_IMAGE_CAL_ON 0b10000000 // 7 7 temperature calibration enabled +#define RADIOLIB_SX127X_IMAGE_CAL_START 0b01000000 // 6 6 start temperature calibration +#define RADIOLIB_SX127X_IMAGE_CAL_RUNNING 0b00100000 // 5 5 temperature calibration is on-going +#define RADIOLIB_SX127X_IMAGE_CAL_COMPLETE 0b00000000 // 5 5 temperature calibration finished +#define RADIOLIB_SX127X_TEMP_CHANGED 0b00001000 // 3 3 temperature changed more than TEMP_THRESHOLD since last calibration +#define RADIOLIB_SX127X_TEMP_THRESHOLD_5_DEG_C 0b00000000 // 2 1 temperature change threshold: 5 deg. C +#define RADIOLIB_SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) +#define RADIOLIB_SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C +#define RADIOLIB_SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C +#define RADIOLIB_SX127X_TEMP_MONITOR_ON 0b00000000 // 0 0 temperature monitoring enabled (default) +#define RADIOLIB_SX127X_TEMP_MONITOR_OFF 0b00000001 // 0 0 temperature monitoring disabled + +// RADIOLIB_SX127X_REG_LOW_BAT +#define RADIOLIB_SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled +#define RADIOLIB_SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_764_V 0b00000001 // 2 0 1.764 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_835_V 0b00000010 // 2 0 1.835 V (default) +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_905_V 0b00000011 // 2 0 1.905 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_976_V 0b00000100 // 2 0 1.976 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_045_V 0b00000101 // 2 0 2.045 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_116_V 0b00000110 // 2 0 2.116 V +#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_185_V 0b00000111 // 2 0 2.185 V + +// RADIOLIB_SX127X_REG_IRQ_FLAGS_1 +#define RADIOLIB_SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready +#define RADIOLIB_SX127X_FLAG_RX_READY 0b01000000 // 6 6 reception ready (after RSSI, AGC, AFC) +#define RADIOLIB_SX127X_FLAG_TX_READY 0b00100000 // 5 5 transmission ready (after PA ramp-up) +#define RADIOLIB_SX127X_FLAG_PLL_LOCK 0b00010000 // 4 4 PLL locked +#define RADIOLIB_SX127X_FLAG_RSSI 0b00001000 // 3 3 RSSI value exceeds RSSI threshold +#define RADIOLIB_SX127X_FLAG_TIMEOUT 0b00000100 // 2 2 timeout occurred +#define RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected +#define RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched + +// RADIOLIB_SX127X_REG_IRQ_FLAGS_2 +#define RADIOLIB_SX127X_FLAG_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define RADIOLIB_SX127X_FLAG_FIFO_EMPTY 0b01000000 // 6 6 FIFO is empty +#define RADIOLIB_SX127X_FLAG_FIFO_LEVEL 0b00100000 // 5 5 number of bytes in FIFO exceeds FIFO_THRESHOLD +#define RADIOLIB_SX127X_FLAG_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred +#define RADIOLIB_SX127X_FLAG_PACKET_SENT 0b00001000 // 3 3 packet was successfully sent +#define RADIOLIB_SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received +#define RADIOLIB_SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed +#define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold + +// RADIOLIB_SX127X_REG_DIO_MAPPING_1 +#define RADIOLIB_SX127X_DIO0_LORA_RX_DONE 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_LORA_TX_DONE 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_LORA_CAD_DONE 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RSSI_PREAMBLE_DETECT 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECT 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO2_LORA_FHSS_CHANGE_CHANNEL 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_CONT_DATA 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_FIFO_FULL 0b00000000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_RX_READY 0b00000100 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_TIMEOUT 0b00001000 // 3 2 +#define RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS 0b00011000 // 3 2 +#define RADIOLIB_SX127X_DIO3_LORA_CAD_DONE 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER 0b00000001 // 1 0 +#define RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR 0b00000010 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_TIMEOUT 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_RSSI_PREAMBLE_DETECT 0b00000001 // 1 0 +#define RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT 0b00000011 // 1 0 +#define RADIOLIB_SX127X_DIO3_PACK_FIFO_EMPTY 0b00000000 // 1 0 +#define RADIOLIB_SX127X_DIO3_PACK_TX_READY 0b00000001 // 1 0 + +// RADIOLIB_SX127X_REG_DIO_MAPPING_2 +#define RADIOLIB_SX127X_DIO4_LORA_CAD_DETECTED 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_LORA_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_CONT_MODE_READY 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT 0b00000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_PLL_LOCK 0b01000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_TIMEOUT 0b10000000 // 7 6 +#define RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT 0b11000000 // 7 6 +#define RADIOLIB_SX127X_DIO5_LORA_MODE_READY 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_LORA_CLK_OUT 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_RSSI_PREAMBLE_DETECT 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO5_CONT_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_CLK_OUT 0b00000000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_PLL_LOCK 0b00010000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_DATA 0b00100000 // 5 4 +#define RADIOLIB_SX127X_DIO5_PACK_MODE_READY 0b00110000 // 5 4 +#define RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT 0b00000001 // 0 0 +#define RADIOLIB_SX127X_DIO_MAP_RSSI 0b00000000 // 0 0 // SX1272_REG_PLL_HOP + SX1278_REG_PLL_HOP -#define RADIOLIB_SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written -#define RADIOLIB_SX127X_FAST_HOP_ON 0b10000000 // 7 7 carrier frequency validated when FS modes are requested +#define RADIOLIB_SX127X_FAST_HOP_OFF 0b00000000 // 7 7 carrier frequency validated when FRF registers are written +#define RADIOLIB_SX127X_FAST_HOP_ON 0b10000000 // 7 7 carrier frequency validated when FS modes are requested // SX1272_REG_TCXO + SX1278_REG_TCXO -#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL 0b00000000 // 4 4 use external crystal oscillator -#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL_CLIPPED 0b00010000 // 4 4 use external crystal oscillator clipped sine connected to XTA pin +#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL 0b00000000 // 4 4 use external crystal oscillator +#define RADIOLIB_SX127X_TCXO_INPUT_EXTERNAL_CLIPPED 0b00010000 // 4 4 use external crystal oscillator clipped sine connected to XTA pin // SX1272_REG_PLL + SX1278_REG_PLL -#define RADIOLIB_SX127X_PLL_BANDWIDTH_75_KHZ 0b00000000 // 7 6 PLL bandwidth: 75 kHz -#define RADIOLIB_SX127X_PLL_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz -#define RADIOLIB_SX127X_PLL_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz -#define RADIOLIB_SX127X_PLL_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) +#define RADIOLIB_SX127X_PLL_BANDWIDTH_75_KHZ 0b00000000 // 7 6 PLL bandwidth: 75 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define RADIOLIB_SX127X_PLL_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) /*! \class SX127x - \brief Base class for SX127x series. All derived classes for SX127x (e.g. SX1278 or SX1272) inherit from this base class. This class should not be instantiated directly from Arduino sketch, only from its derived classes. */ @@ -592,7 +591,6 @@ class SX127x: public PhysicalLayer { /*! \brief Default constructor. Called internally when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ SX127x(Module* mod); @@ -603,13 +601,9 @@ class SX127x: public PhysicalLayer { /*! \brief Initialization method. Will be called with appropriate parameters when calling initialization method from derived class. - \param chipVersion Value in SPI version register. Used to verify the connection and hardware version. - \param syncWord %LoRa sync word. - \param preambleLength Length of %LoRa transmission preamble in symbols. - \returns \ref status_codes */ int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength); @@ -621,17 +615,11 @@ class SX127x: public PhysicalLayer { /*! \brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class. - \param chipVersion Value in SPI version register. Used to verify the connection and hardware version. - \param freqDev Frequency deviation of the FSK transmission in kHz. - \param rxBw Receiver bandwidth in kHz. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK. - \returns \ref status_codes */ int16_t beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); @@ -639,13 +627,9 @@ class SX127x: public PhysicalLayer { /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. For overloads to transmit Arduino String or C-string, see PhysicalLayer::transmit. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; @@ -653,18 +637,14 @@ class SX127x: public PhysicalLayer { /*! \brief Binary receive method. Will attempt to receive arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. For overloads to receive Arduino String, see PhysicalLayer::receive. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. - \returns \ref status_codes */ int16_t receive(uint8_t* data, size_t len) override; /*! \brief Performs scan for valid %LoRa preamble in the current channel. - \returns \ref status_codes */ int16_t scanChannel(); @@ -672,23 +652,19 @@ class SX127x: public PhysicalLayer { /*! \brief Sets the %LoRa module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. %Module will wake up automatically when methods like transmit or receive are called. - \returns \ref status_codes */ int16_t sleep(); /*! \brief Sets the %LoRa module to standby. - \returns \ref status_codes */ int16_t standby() override; /*! \brief Sets the %LoRa module to standby. - \param mode Standby mode to be used. No effect, implemented only for PhysicalLayer compatibility. - \returns \ref status_codes */ int16_t standby(uint8_t mode) override; @@ -696,9 +672,7 @@ class SX127x: public PhysicalLayer { /*! \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. - \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. - \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; @@ -706,14 +680,12 @@ class SX127x: public PhysicalLayer { /*! \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. - \returns \ref status_codes */ int16_t receiveDirect() override; /*! \brief Disables direct mode and enables packet mode, allowing the module to receive packets. Can only be activated in FSK mode. - \returns \ref status_codes */ int16_t packetMode(); @@ -722,9 +694,7 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when DIO0 activates. - \param func Pointer to interrupt service routine. - \param dir Signal change direction. */ void setDio0Action(void (*func)(void), uint32_t dir); @@ -736,9 +706,7 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when DIO1 activates. - \param func Pointer to interrupt service routine. - \param dir Signal change direction. */ void setDio1Action(void (*func)(void), uint32_t dir); @@ -750,7 +718,6 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is empty. - \param func Pointer to interrupt service routine. */ void setFifoEmptyAction(void (*func)(void)); @@ -762,7 +729,6 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is full. - \param func Pointer to interrupt service routine. */ void setFifoFullAction(void (*func)(void)); @@ -774,84 +740,60 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt service routine function to call when FIFO is empty. - \param data Pointer to the transmission buffer. - \param totalLen Total number of bytes to transmit. - \param remLen Pointer to a counter holding the number of bytes that have been transmitted so far. - \returns True when a complete packet is sent, false if more data is needed. */ bool fifoAdd(uint8_t* data, int totalLen, int* remLen); /*! \brief Set interrupt service routine function to call when FIFO is sufficently full to read. - \param data Pointer to a buffer that stores the receive data. - \param totalLen Total number of bytes to receive. - \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. - \returns True when a complete packet is received, false if more data is needed. */ bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); /*! \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. - \returns \ref status_codes */ int16_t finishTransmit() override; /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. - \param len Expected length of packet to be received. Required for LoRa spreading factor 6. - \param mode Receive mode to be used. Defaults to RxContinuous. - \returns \ref status_codes */ int16_t startReceive(uint8_t len = 0, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param mode Receive mode to be used. - \param irqFlags Ignored. - \param irqMask Ignored. - \param len Expected length of packet to be received. Required for LoRa spreading factor 6. - \returns \ref status_codes */ int16_t startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. - \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. - \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; @@ -859,7 +801,6 @@ class SX127x: public PhysicalLayer { /*! \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected. DIO1 will be activated if there's no preamble detected before timeout. - \returns \ref status_codes */ int16_t startChannelScan(); @@ -868,264 +809,208 @@ class SX127x: public PhysicalLayer { /*! \brief Sets %LoRa sync word. Only available in %LoRa mode. - \param syncWord Sync word to be set. - \returns \ref status_codes */ int16_t setSyncWord(uint8_t syncWord); /*! \brief Sets current limit for over current protection at transmitter amplifier. Allowed values range from 45 to 120 mA in 5 mA steps and 120 to 240 mA in 10 mA steps. - \param currentLimit Current limit to be set (in mA). - \returns \ref status_codes */ int16_t setCurrentLimit(uint8_t currentLimit); /*! \brief Sets %LoRa or FSK preamble length. Allowed values range from 6 to 65535 in %LoRa mode or 0 to 65535 in FSK mode. - \param preambleLength Preamble length to be set (in symbols when in LoRa mode or bits in FSK mode). - \returns \ref status_codes */ int16_t setPreambleLength(uint16_t preambleLength); /*! \brief Gets frequency error of the latest received packet. - \param autoCorrect When set to true, frequency will be automatically corrected. - \returns Frequency error in Hz. */ float getFrequencyError(bool autoCorrect = false); /*! \brief Gets current AFC error. - \returns Frequency offset from RF in Hz if AFC is enabled and triggered, zero otherwise. */ float getAFCError(); /*! \brief Gets signal-to-noise ratio of the latest received packet. Only available in LoRa mode. - \returns Last packet signal-to-noise ratio (SNR). */ float getSNR(); /*! \brief Get data rate of the latest transmitted packet. - \returns Last packet data rate in bps (bits per second). */ float getDataRate() const; /*! \brief Sets FSK frequency deviation from carrier frequency. Allowed values depend on bit rate setting and must be lower than 200 kHz. Only available in FSK mode. - \param freqDev Frequency deviation to be set (in kHz). - \returns \ref status_codes */ int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets FSK receiver bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode. - \param rxBw Receiver bandwidth to be set (in kHz). - \returns \ref status_codes */ int16_t setRxBandwidth(float rxBw); /*! \brief Sets FSK automatic frequency correction bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode. - \param rxBw Receiver AFC bandwidth to be set (in kHz). - \returns \ref status_codes */ int16_t setAFCBandwidth(float afcBw); /*! \brief Enables or disables FSK automatic frequency correction(AFC) - \param isEnabled AFC enabled or disabled - \return \ref status_codes */ int16_t setAFC(bool isEnabled); /*! \brief Controls trigger of AFC and AGC - \param trigger one from SX127X_RX_TRIGGER_NONE, SX127X_RX_TRIGGER_RSSI_INTERRUPT, SX127X_RX_TRIGGER_PREAMBLE_DETECT, SX127X_RX_TRIGGER_BOTH - \return \ref status_codes */ int16_t setAFCAGCTrigger(uint8_t trigger); /*! \brief Sets FSK sync word. Allowed sync words are up to 8 bytes long and can not contain null bytes. Only available in FSK mode. - \param syncWord Sync word array. - \param len Sync word length (in bytes). - \returns \ref status_codes */ int16_t setSyncWord(uint8_t* syncWord, size_t len); /*! \brief Sets FSK node address. Calling this method will enable address filtering. Only available in FSK mode. - \param nodeAddr Node address to be set. - \returns \ref status_codes */ int16_t setNodeAddress(uint8_t nodeAddr); /*! \brief Sets FSK broadcast address. Calling this method will enable address filtering. Only available in FSK mode. - \param broadAddr Broadcast address to be set. - \returns \ref status_codes */ int16_t setBroadcastAddress(uint8_t broadAddr); /*! \brief Disables FSK address filtering. - \returns \ref status_codes */ int16_t disableAddressFiltering(); /*! \brief Enables/disables OOK modulation instead of FSK. - \param enableOOK Enable (true) or disable (false) OOK. - \returns \ref status_codes */ int16_t setOOK(bool enableOOK); /*! \brief Selects the type of threshold in the OOK data slicer. - \param type Threshold type: SX127X_OOK_THRESH_PEAK(default), SX127X_OOK_THRESH_FIXED, SX127X_OOK_THRESH_AVERAGE - \returns \ref status_codes */ int16_t setOokThresholdType(uint8_t type); /*! \brief Period of decrement of the RSSI threshold in the OOK demodulator. - \param value Use defines RADIOLIB_SX127X_OOK_PEAK_THRESH_DEC_X_X_CHIP - \returns \ref status_codes */ int16_t setOokPeakThresholdDecrement(uint8_t value); /*! \brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used. - \param value Threshold level in steps of 0.5 dB. - \returns \ref status_codes */ int16_t setOokFixedOrFloorThreshold(uint8_t value); - /*! + /*! \brief Size of each decrement of the RSSI threshold in the OOK demodulator. - \param value Step size: RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_0_5_DB (default), RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_1_5_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_2_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_3_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_4_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_5_0_DB, RADIOLIB_SX127X_OOK_PEAK_THRESH_STEP_6_0_DB - \returns \ref status_codes */ int16_t setOokPeakThresholdStep(uint8_t value); /*! - \brief Enable Bit synchronizer. - - \returns \ref status_codes + \brief Enable Bit synchronizer. + \returns \ref status_codes */ int16_t enableBitSync(); /*! \brief Disable Bit synchronizer (not allowed in Packet mode). - \returns \ref status_codes */ int16_t disableBitSync(); /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. - \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! - \brief Set modem in fixed packet length mode. Available in FSK mode only. - - \param len Packet length. - - \returns \ref status_codes - */ - int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); + \brief Set modem in fixed packet length mode. Available in FSK mode only. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); /*! - \brief Set modem in variable packet length mode. Available in FSK mode only. - - \param len Maximum packet length. - - \returns \ref status_codes - */ - int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); - - /*! - \brief Get expected time-on-air for a given size of payload - - \param len Payload length in bytes. + \brief Set modem in variable packet length mode. Available in FSK mode only. + \param len Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); - \returns Expected time-on-air in microseconds. - */ - uint32_t getTimeOnAir(size_t len); + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len); - /*! + /*! \brief Enable CRC filtering and generation. - - \param crcOn Set or unset CRC filtering and generation. - + \param enable Set or unset CRC filtering and generation. \returns \ref status_codes - */ - int16_t setCrcFiltering(bool crcOn = true); + */ + int16_t setCrcFiltering(bool enable = true); /*! \brief Sets RSSI measurement configuration in FSK mode. - \param smoothingSamples Number of samples taken to average the RSSI result. numSamples = 2 ^ (1 + smoothingSamples), allowed values are in range 0 (2 samples) - 7 (256 samples) - \param offset Signed RSSI offset that will be automatically compensated. 1 dB per LSB, defaults to 0, allowed values are in range -16 dB to +15 dB. - \returns \ref status_codes */ int16_t setRSSIConfig(uint8_t smoothingSamples, int8_t offset = 0); /*! \brief Sets transmission encoding. Only available in FSK mode. - Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. - + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. \param encoding Encoding to be used. - \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; @@ -1134,14 +1019,12 @@ class SX127x: public PhysicalLayer { \brief Reads currently active IRQ flags, can be used to check which event caused an interrupt. In LoRa mode, this is the content of SX127X_REG_IRQ_FLAGS register. In FSK mode, this is the contents of SX127X_REG_IRQ_FLAGS_2 (MSB) and SX127X_REG_IRQ_FLAGS_1 (LSB) registers. - \returns IRQ flags. */ uint16_t getIRQFlags(); /*! \brief Reads modem status. Only available in LoRa mode. - \returns Modem status. */ uint8_t getModemStatus(); @@ -1149,7 +1032,6 @@ class SX127x: public PhysicalLayer { /*! \brief Reads uncalibrated temperature value. This function will change operating mode and should not be called during Tx, Rx or CAD. - \returns Uncalibrated temperature sensor reading. */ int8_t getTempRaw(); @@ -1161,24 +1043,20 @@ class SX127x: public PhysicalLayer { void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! - \brief Get one truly random byte from RSSI noise. - - \returns TRNG byte. - */ + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ uint8_t randomByte(); /*! - \brief Read version SPI register. Should return SX1278_CHIP_VERSION (0x12) or SX1272_CHIP_VERSION (0x22) if SX127x is connected and working. - - \returns Version register contents or \ref status_codes - */ + \brief Read version SPI register. Should return SX1278_CHIP_VERSION (0x12) or SX1272_CHIP_VERSION (0x22) if SX127x is connected and working. + \returns Version register contents or \ref status_codes + */ int16_t getChipVersion(); /*! \brief Enable/disable inversion of the I and Q signals - \param invertIQ QI inversion enabled (true) or disabled (false); - \returns \ref status_codes */ int16_t invertIQ(bool invertIQ); @@ -1186,14 +1064,12 @@ class SX127x: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. - \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); /*! \brief Function to read and process data bit in direct reception mode. - \param pin Pin on which to read. */ void readBit(uint32_t pin); @@ -1201,23 +1077,19 @@ class SX127x: public PhysicalLayer { /*! \brief Sets the hopping period and enables FHSS - \param freqHoppingPeriod Integer multiple of symbol periods between hops - \returns \ref status_codes */ int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - /*! + /*! \brief Gets FHSS hopping period - \returns 8 bit period */ uint8_t getFHSSHoppingPeriod(void); /*! \brief Gets the FHSS channel in use - \returns 6 bit channel number */ uint8_t getFHSSChannel(void); @@ -1229,40 +1101,30 @@ class SX127x: public PhysicalLayer { /*! \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). - \param pin Pin number onto which a signal is to be placed. - \param value The value that indicates which function to place on that pin. See chip datasheet for details. - \returns \ref status_codes */ int16_t setDIOMapping(uint32_t pin, uint32_t value); /*! \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. - \param usePreambleDetect Whether to use PreambleDetect (true) or RSSI (false) on the pins that are mapped to this function. - \returns \ref status_codes */ int16_t setDIOPreambleDetect(bool usePreambleDetect); /*! \brief Gets recorded signal strength indicator. - \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. - \returns RSSI value in dBm. */ float getRSSI(bool packet, bool skipReceive, int16_t offset); /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled - \param dbm A dBm value between -127.5 and 0 inclusive - \returns \ref status_codes */ int16_t setRSSIThreshold(float dbm); @@ -1270,21 +1132,21 @@ class SX127x: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif - Module* _mod; + Module* mod; #if !defined(RADIOLIB_GODMODE) protected: #endif - float _freq = 0; - float _bw = 0; - uint8_t _sf = 0; - uint8_t _cr = 0; - float _br = 0; - bool _ook = false; - bool _crcEnabled = false; - bool _crcOn = true; // default value used in FSK mode - size_t _packetLength = 0; + float frequency = 0; + float bandwidth = 0; + uint8_t spreadingFactor = 0; + uint8_t codingRate = 0; + float bitRate = 0; + bool ookEnabled = false; + bool crcEnabled = false; + bool crcOn = true; // default value used in FSK mode + size_t packetLength = 0; int16_t setFrequencyRaw(float newFreq); int16_t setBitRateCommon(float br, uint8_t fracRegAddr); @@ -1297,22 +1159,21 @@ class SX127x: public PhysicalLayer { #if !defined(RADIOLIB_GODMODE) private: #endif - float _dataRate = 0; - bool _packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once - uint8_t _packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; + float dataRate = 0; + bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once + uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; bool findChip(uint8_t ver); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); void clearIRQFlags(); void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read - /** - * @brief Calculate exponent and mantissa values for receiver bandwidth and AFC - * - * \param bandwidth bandwidth to be set (in kHz). - * - * \returns bandwidth in manitsa and exponent format - */ + + /*! + \brief Calculate exponent and mantissa values for receiver bandwidth and AFC + \param bandwidth bandwidth to be set (in kHz). + \returns bandwidth in manitsa and exponent format + */ static uint8_t calculateBWManExp(float bandwidth); virtual void errataFix(bool rx) = 0; From a22a4df88f4146b6218caeaf6e5089cfc4d193c2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 24 Apr 2023 18:25:09 +0200 Subject: [PATCH 0524/1848] [MOD] Added debug message when BUSY pin times out --- src/Module.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Module.cpp b/src/Module.cpp index 17e09480b3..b29eb6b876 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -251,6 +251,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint this->hal->yield(); if(this->hal->millis() - start >= timeout) { this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); + RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?"); return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } From 044b4789b23984f271bb8e61e46ee6fdf917a0f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 24 Apr 2023 18:25:42 +0200 Subject: [PATCH 0525/1848] [MOD] Decreased default SPI timeout to 1000 ms --- src/Module.cpp | 14 +++++++------- src/Module.h | 3 +++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index b29eb6b876..c0ce3f09e4 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -105,7 +105,7 @@ void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inByte SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); } else { uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, 5000); + SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); } } @@ -115,7 +115,7 @@ uint8_t Module::SPIreadRegister(uint16_t reg) { SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); } else { uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, 5000); + SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); } return(resp); } @@ -125,7 +125,7 @@ void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); } else { uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, 5000); + SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); } } @@ -134,7 +134,7 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); } else { uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, true, &data, NULL, 1, true, 5000); + SPItransferStream(cmd, 3, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); } } @@ -193,7 +193,7 @@ int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command - int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, 5000); + int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); // check the status @@ -210,7 +210,7 @@ int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command - int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, 5000); + int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); // check the status @@ -228,7 +228,7 @@ int16_t Module::SPIcheckStream() { // get the status uint8_t spiStatus = 0; uint8_t cmd = this->SPIstatusCommand; - state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, 5000); + state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); // translate to RadioLib status code diff --git a/src/Module.h b/src/Module.h index 03163d158c..b240653e67 100644 --- a/src/Module.h +++ b/src/Module.h @@ -20,6 +20,9 @@ */ #define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } +// default timeout for SPI transfers +#define RADIOLIB_MODULE_SPI_TIMEOUT (1000) + /*! \class Module \brief Implements all common low-level methods to control the wireless module. From 701d13b40f3963fe726f663a69a770ca8d58a406 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 24 Apr 2023 18:30:53 +0200 Subject: [PATCH 0526/1848] Added notes about non-Arduino environments --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05fda5a438..36228634f7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system. Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not! +RadioLib natively supports Arduino, but can run in non-Arduino environments as well! See [this Wiki page](https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms) and [examples/NonArduino](https://github.com/jgromes/RadioLib/tree/master/examples/NonArduino). + RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your microcontroller can handle! ### Supported modules: @@ -82,7 +84,7 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * __PJRC__ * [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards -The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. +The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstracton layer, which allows it to be easily ported even to non-Arduino encironments. ### In development: * __AX5243__ FSK module From f244caa0bb0b43cc2685a7ddf15a313db25b9c3e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 24 Apr 2023 18:32:02 +0200 Subject: [PATCH 0527/1848] Bump version to 6.0.0 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library.json b/library.json index 2590de8c76..222d7258a3 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "5.7.0", + "version": "6.0.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index ea92ef7762..88368d53f1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=5.7.0 +version=6.0.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index b24e8aa78e..4c3e25dd37 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -467,8 +467,8 @@ #endif // version definitions -#define RADIOLIB_VERSION_MAJOR (0x05) -#define RADIOLIB_VERSION_MINOR (0x07) +#define RADIOLIB_VERSION_MAJOR (0x06) +#define RADIOLIB_VERSION_MINOR (0x00) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 7f4ff615040d22caaac71505eeefa25d76203453 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:51:44 +0200 Subject: [PATCH 0528/1848] [SX128x] Fixed unused variable --- src/modules/SX128x/SX128x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index ffad917fca..ab3b40dfbb 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1379,7 +1379,7 @@ int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_ } int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen, uint8_t hdrType) { - uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, this->payloadLen, crcLen, whiten }; + uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } @@ -1389,7 +1389,7 @@ int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bl } int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) { - uint8_t data[] = { preambleLen, hdrType, this->payloadLen, crc, invIQ, 0x00, 0x00 }; + uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } From b2af390c148b1932cfde419b80c732ed73592da3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:52:11 +0200 Subject: [PATCH 0529/1848] Added nonvolatile pointer macro --- src/BuildOpt.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4c3e25dd37..4128d3354f 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -267,6 +267,10 @@ #define RADIOLIB_NONVOLATILE PROGMEM #endif + #if !defined(RADIOLIB_NONVOLATILE_PTR) + #define RADIOLIB_NONVOLATILE_PTR PGM_P + #endif + #if !defined(RADIOLIB_NONVOLATILE_READ_BYTE) #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) #endif From f0cf7ff9122b0f975f1ecc97a76d345d6c1de8fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:53:33 +0200 Subject: [PATCH 0530/1848] [Print] Added standalone ITA2 --- src/protocols/Print/ITA2String.cpp | 111 +++++++++++++++++++++++++++++ src/protocols/Print/ITA2String.h | 70 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 src/protocols/Print/ITA2String.cpp create mode 100644 src/protocols/Print/ITA2String.h diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp new file mode 100644 index 0000000000..0c93da2eba --- /dev/null +++ b/src/protocols/Print/ITA2String.cpp @@ -0,0 +1,111 @@ +#include "ITA2String.h" + +ITA2String::ITA2String(char c) { + asciiLen = 1; + #if !defined(RADIOLIB_STATIC_ONLY) + strAscii = new char[1]; + #endif + strAscii[0] = c; + ita2Len = 0; +} + +ITA2String::ITA2String(const char* str) { + asciiLen = strlen(str); + #if !defined(RADIOLIB_STATIC_ONLY) + strAscii = new char[asciiLen + 1]; + #endif + strcpy(strAscii, str); + ita2Len = 0; +} + +ITA2String::~ITA2String() { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] strAscii; + #endif +} + +size_t ITA2String::length() { + // length returned by this method is different than the length of ASCII-encoded strAscii + // ITA2-encoded string length varies based on how many number and characters the string contains + + if(ita2Len == 0) { + // ITA2 length wasn't calculated yet, call byteArr() to calculate it + byteArr(); + } + + return(ita2Len); +} + +uint8_t* ITA2String::byteArr() { + // create temporary array 2x the string length (figures may be 3 bytes) + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; + #else + uint8_t* temp = new uint8_t[asciiLen*2 + 1]; + #endif + + size_t arrayLen = 0; + bool flagFigure = false; + for(size_t i = 0; i < asciiLen; i++) { + uint16_t code = getBits(strAscii[i]); + uint8_t shift = (code >> 5) & 0b11111; + uint8_t character = code & 0b11111; + // check if the code is letter or figure + if(shift == RADIOLIB_ITA2_FIGS) { + // check if this is the first figure in sequence + if(!flagFigure) { + flagFigure = true; + temp[arrayLen++] = RADIOLIB_ITA2_FIGS; + } + + // add the character code + temp[arrayLen++] = character & 0b11111; + + // check the following character (skip for message end) + if(i < (asciiLen - 1)) { + uint16_t nextCode = getBits(strAscii[i+1]); + uint8_t nextShift = (nextCode >> 5) & 0b11111; + if(nextShift == RADIOLIB_ITA2_LTRS) { + // next character is a letter, terminate figure shift + temp[arrayLen++] = RADIOLIB_ITA2_LTRS; + flagFigure = false; + } + } else { + // reached the end of the message, terminate figure shift + temp[arrayLen++] = RADIOLIB_ITA2_LTRS; + flagFigure = false; + } + } else { + temp[arrayLen++] = character & 0b11111; + } + } + + // save ITA2 string length + ita2Len = arrayLen; + + uint8_t* arr = new uint8_t[arrayLen]; + memcpy(arr, temp, arrayLen); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] temp; + #endif + + return(arr); +} + +uint16_t ITA2String::getBits(char c) { + // search ITA2 table + uint16_t code = 0x0000; + for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { + if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { + // character is in letter shift + code = (RADIOLIB_ITA2_LTRS << 5) | i; + break; + } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { + // character is in figures shift + code = (RADIOLIB_ITA2_FIGS << 5) | i; + break; + } + } + + return(code); +} diff --git a/src/protocols/Print/ITA2String.h b/src/protocols/Print/ITA2String.h new file mode 100644 index 0000000000..556c0a3bbd --- /dev/null +++ b/src/protocols/Print/ITA2String.h @@ -0,0 +1,70 @@ +#if !defined(_RADIOLIB_ITA2_STRING_H) +#define _RADIOLIB_ITA2_STRING_H + +#include "../../TypeDef.h" + +#define RADIOLIB_ITA2_FIGS 0x1B +#define RADIOLIB_ITA2_LTRS 0x1F +#define RADIOLIB_ITA2_LENGTH 32 + +// ITA2 character table: - position in array corresponds to 5-bit ITA2 code +// - characters to the left are in letters shift, characters to the right in figures shift +// - characters marked 0x7F do not have ASCII equivalent +static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = { + {'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, + {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, + {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, + {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F} +}; + +/*! + \class ITA2String + \brief ITA2-encoded string. +*/ +class ITA2String { + public: + /*! + \brief Default single-character constructor. + \param c ASCII-encoded character to encode as ITA2. + */ + ITA2String(char c); + + /*! + \brief Default string constructor. + \param str ASCII-encoded string to encode as ITA2. + */ + ITA2String(const char* str); + + /*! + \brief Default destructor. + */ + ~ITA2String(); + + /*! + \brief Gets the length of the ITA2 string. This number is not the same as the length of ASCII-encoded string! + \returns Length of ITA2-encoded string. + */ + size_t length(); + + /*! + \brief Gets the ITA2 representation of the ASCII string set in constructor. + \returns Pointer to dynamically allocated array, which contains ITA2-encoded bytes. + It is the caller's responsibility to deallocate this memory! + */ + uint8_t* byteArr(); + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + #if defined(RADIOLIB_STATIC_ONLY) + char strAscii[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + char* strAscii; + #endif + size_t asciiLen; + size_t ita2Len; + + static uint16_t getBits(char c); +}; + +#endif From 089a81faec5b52584fcb87cf5e15786a58815865 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:53:55 +0200 Subject: [PATCH 0531/1848] [Print] Added common print class --- src/protocols/Print/Print.cpp | 309 ++++++++++++++++++++++++++++++++++ src/protocols/Print/Print.h | 64 +++++++ 2 files changed, 373 insertions(+) create mode 100644 src/protocols/Print/Print.cpp create mode 100644 src/protocols/Print/Print.h diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp new file mode 100644 index 0000000000..9d0fa5581a --- /dev/null +++ b/src/protocols/Print/Print.cpp @@ -0,0 +1,309 @@ +#include "Print.h" + +size_t RadioLibPrint::print(ITA2String& ita2) { + uint8_t enc = this->encoding; + this->encoding = RADIOLIB_ITA2; + uint8_t* arr = ita2.byteArr(); + size_t n = write(arr, ita2.length()); + delete[] arr; + this->encoding = enc; + return(n); +} + +size_t RadioLibPrint::println(ITA2String& ita2) { + size_t n = RadioLibPrint::print(ita2); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while (size--) { + if (write(*buffer++)) n++; + else break; + } + return n; +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +size_t RadioLibPrint::print(const __FlashStringHelper* fstr) { + // read flash string length + size_t len = 0; + RADIOLIB_NONVOLATILE_PTR p = reinterpret_cast(fstr); + while(true) { + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); + len++; + if(c == '\0') { + break; + } + } + + // dynamically allocate memory + #if defined(RADIOLIB_STATIC_ONLY) + char str[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + char* str = new char[len]; + #endif + + // copy string from flash + p = reinterpret_cast(fstr); + for(size_t i = 0; i < len; i++) { + str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); + } + + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str, len); + } + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] str; + #endif + return(n); +} + +size_t RadioLibPrint::print(const String& str) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str.c_str()); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str.c_str(), str.length()); + } + return(n); +} + +size_t RadioLibPrint::println(const __FlashStringHelper* fstr) { + size_t n = RadioLibPrint::print(fstr); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(const String& str) { + size_t n = RadioLibPrint::print(str); + n += RadioLibPrint::println(); + return(n); +} +#endif + +size_t RadioLibPrint::print(const char str[]) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str, strlen(str)); + } + return(n); +} + +size_t RadioLibPrint::print(char c) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(c); + n = RadioLibPrint::print(ita2); + } else { + n = write(c); + } + return(n); +} + +size_t RadioLibPrint::print(unsigned char b, int base) { + return(RadioLibPrint::print((unsigned long)b, base)); +} + +size_t RadioLibPrint::print(int n, int base) { + return(RadioLibPrint::print((long)n, base)); +} + +size_t RadioLibPrint::print(unsigned int n, int base) { + return(RadioLibPrint::print((unsigned long)n, base)); +} + +size_t RadioLibPrint::print(long n, int base) { + if(base == 0) { + return(write(n)); + } else if(base == DEC) { + if (n < 0) { + int t = RadioLibPrint::print('-'); + n = -n; + return(RadioLibPrint::printNumber(n, DEC) + t); + } + return(RadioLibPrint::printNumber(n, DEC)); + } else { + return(RadioLibPrint::printNumber(n, base)); + } +} + +size_t RadioLibPrint::print(unsigned long n, int base) { + if(base == 0) { + return(write(n)); + } else { + return(RadioLibPrint::printNumber(n, base)); + } +} + +size_t RadioLibPrint::print(double n, int digits) { + return(RadioLibPrint::printFloat(n, digits)); +} + +size_t RadioLibPrint::println(const char* str) { + size_t n = RadioLibPrint::print(str); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(char c) { + size_t n = RadioLibPrint::print(c); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned char b, int base) { + size_t n = RadioLibPrint::print(b, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(int num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned int num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(long num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned long num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(double d, int digits) { + size_t n = RadioLibPrint::print(d, digits); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(void) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String lf = ITA2String("\r\n"); + n = RadioLibPrint::print(lf); + } else { + n = write("\r\n"); + } + return(n); +} + +size_t RadioLibPrint::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + if(base < 2) { + base = 10; + } + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + size_t l = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + uint8_t* arr = ita2.byteArr(); + l = write(arr, ita2.length()); + delete[] arr; + } else { + l = write(str); + } + + return(l); +} + +/// \todo improve ITA2 float print speed (characters are sent one at a time) +size_t RadioLibPrint::printFloat(double number, uint8_t digits) { + size_t n = 0; + + char code[] = {0x00, 0x00, 0x00, 0x00}; + if (isnan(number)) strcpy(code, "nan"); + if (isinf(number)) strcpy(code, "inf"); + if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically + if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically + + if(code[0] != 0x00) { + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(code); + uint8_t* arr = ita2.byteArr(); + n = write(arr, ita2.length()); + delete[] arr; + return(n); + } else { + return(write(code)); + } + } + + // Handle negative numbers + if (number < 0.0) { + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String("-"); + uint8_t* arr = ita2.byteArr(); + n += write(arr, ita2.length()); + delete[] arr; + } else { + n += RadioLibPrint::print('-'); + } + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) { + rounding /= 10.0; + } + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + n += RadioLibPrint::print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + if(encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String("."); + uint8_t* arr = ita2.byteArr(); + n += write(arr, ita2.length()); + delete[] arr; + } else { + n += RadioLibPrint::print('.'); + } + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += RadioLibPrint::print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h new file mode 100644 index 0000000000..0dbc5edadf --- /dev/null +++ b/src/protocols/Print/Print.h @@ -0,0 +1,64 @@ +#if !defined(_RADIOLIB_PRINT_H) +#define _RADIOLIB_PRINT_H + +#include "ITA2String.h" + +// supported encoding schemes +#define RADIOLIB_ASCII 0 +#define RADIOLIB_ASCII_EXTENDED 1 +#define RADIOLIB_ITA2 2 + +// based on Arduino Print class +class RadioLibPrint { + public: + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + size_t print(ITA2String& ita2); + size_t println(ITA2String& ita2); + + #if defined(RADIOLIB_BUILD_ARDUINO) + size_t print(const __FlashStringHelper *); + size_t print(const String &); + + size_t println(const __FlashStringHelper *); + size_t println(const String &); + #endif + + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + + protected: + uint8_t encoding = RADIOLIB_ASCII_EXTENDED; + const char* lineFeed; + + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + + private: +}; + +#endif From d79ed24a26f61dd704ad0947e26b458d9a61763f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:54:27 +0200 Subject: [PATCH 0532/1848] [RTTY] Use common print class --- src/protocols/RTTY/RTTY.cpp | 455 ++---------------------------------- src/protocols/RTTY/RTTY.h | 114 +-------- 2 files changed, 25 insertions(+), 544 deletions(-) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 21c3243ae7..6dc66bd3f1 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -3,118 +3,9 @@ #include #if !defined(RADIOLIB_EXCLUDE_RTTY) -ITA2String::ITA2String(char c) { - asciiLen = 1; - #if !defined(RADIOLIB_STATIC_ONLY) - strAscii = new char[1]; - #endif - strAscii[0] = c; - ita2Len = 0; -} - -ITA2String::ITA2String(const char* str) { - asciiLen = strlen(str); - #if !defined(RADIOLIB_STATIC_ONLY) - strAscii = new char[asciiLen + 1]; - #endif - strcpy(strAscii, str); - ita2Len = 0; -} - -ITA2String::~ITA2String() { - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] strAscii; - #endif -} - -size_t ITA2String::length() { - // length returned by this method is different than the length of ASCII-encoded strAscii - // ITA2-encoded string length varies based on how many number and characters the string contains - - if(ita2Len == 0) { - // ITA2 length wasn't calculated yet, call byteArr() to calculate it - byteArr(); - } - - return(ita2Len); -} - -uint8_t* ITA2String::byteArr() { - // create temporary array 2x the string length (figures may be 3 bytes) - #if defined(RADIOLIB_STATIC_ONLY) - uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; - #else - uint8_t* temp = new uint8_t[asciiLen*2 + 1]; - #endif - - size_t arrayLen = 0; - bool flagFigure = false; - for(size_t i = 0; i < asciiLen; i++) { - uint16_t code = getBits(strAscii[i]); - uint8_t shift = (code >> 5) & 0b11111; - uint8_t character = code & 0b11111; - // check if the code is letter or figure - if(shift == RADIOLIB_ITA2_FIGS) { - // check if this is the first figure in sequence - if(!flagFigure) { - flagFigure = true; - temp[arrayLen++] = RADIOLIB_ITA2_FIGS; - } - - // add the character code - temp[arrayLen++] = character & 0b11111; - - // check the following character (skip for message end) - if(i < (asciiLen - 1)) { - uint16_t nextCode = getBits(strAscii[i+1]); - uint8_t nextShift = (nextCode >> 5) & 0b11111; - if(nextShift == RADIOLIB_ITA2_LTRS) { - // next character is a letter, terminate figure shift - temp[arrayLen++] = RADIOLIB_ITA2_LTRS; - flagFigure = false; - } - } else { - // reached the end of the message, terminate figure shift - temp[arrayLen++] = RADIOLIB_ITA2_LTRS; - flagFigure = false; - } - } else { - temp[arrayLen++] = character & 0b11111; - } - } - - // save ITA2 string length - ita2Len = arrayLen; - - uint8_t* arr = new uint8_t[arrayLen]; - memcpy(arr, temp, arrayLen); - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] temp; - #endif - - return(arr); -} - -uint16_t ITA2String::getBits(char c) { - // search ITA2 table - uint16_t code = 0x0000; - for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { - if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { - // character is in letter shift - code = (RADIOLIB_ITA2_LTRS << 5) | i; - break; - } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { - // character is in figures shift - code = (RADIOLIB_ITA2_FIGS << 5) | i; - break; - } - } - - return(code); -} - RTTYClient::RTTYClient(PhysicalLayer* phy) { phyLayer = phy; + lineFeed = "\r\n"; #if !defined(RADIOLIB_EXCLUDE_AFSK) audioClient = nullptr; #endif @@ -123,31 +14,18 @@ RTTYClient::RTTYClient(PhysicalLayer* phy) { #if !defined(RADIOLIB_EXCLUDE_AFSK) RTTYClient::RTTYClient(AFSKClient* audio) { phyLayer = audio->phyLayer; + lineFeed = "\r\n"; audioClient = audio; } #endif int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc, uint8_t stopBits) { // save configuration - encoding = enc; + RadioLibPrint::encoding = enc; stopBitsNum = stopBits; baseFreqHz = base; shiftFreqHz = shift; - switch(encoding) { - case RADIOLIB_ASCII: - dataBitsNum = 7; - break; - case RADIOLIB_ASCII_EXTENDED: - dataBitsNum = 8; - break; - case RADIOLIB_ITA2: - dataBitsNum = 5; - break; - default: - return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); - } - // calculate duration of 1 bit bitDuration = (uint32_t)1000000/rate; @@ -177,22 +55,21 @@ void RTTYClient::idle() { mark(); } -size_t RTTYClient::write(const char* str) { - if(str == NULL) { - return(0); - } - return(RTTYClient::write((uint8_t *)str, strlen(str))); -} - -size_t RTTYClient::write(uint8_t* buff, size_t len) { - size_t n = 0; - for(size_t i = 0; i < len; i++) { - n += RTTYClient::write(buff[i]); - } - return(n); -} - size_t RTTYClient::write(uint8_t b) { + uint8_t dataBitsNum = 0; + switch(RadioLibPrint::encoding) { + case RADIOLIB_ASCII: + dataBitsNum = 7; + break; + case RADIOLIB_ASCII_EXTENDED: + dataBitsNum = 8; + break; + case RADIOLIB_ITA2: + dataBitsNum = 5; + break; + default: + return(0); + } space(); uint16_t maxDataMask = 0x01 << (dataBitsNum - 1); @@ -211,204 +88,6 @@ size_t RTTYClient::write(uint8_t b) { return(1); } -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t RTTYClient::print(__FlashStringHelper* fstr) { - // read flash string length - size_t len = 0; - PGM_P p = reinterpret_cast(fstr); - while(true) { - char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); - len++; - if(c == '\0') { - break; - } - } - - // dynamically allocate memory - #if defined(RADIOLIB_STATIC_ONLY) - char str[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - char* str = new char[len]; - #endif - - // copy string from flash - p = reinterpret_cast(fstr); - for(size_t i = 0; i < len; i++) { - str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); - } - - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write((uint8_t*)str, len); - } - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] str; - #endif - return(n); -} - -size_t RTTYClient::print(const String& str) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str.c_str()); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); - } - return(n); -} -#endif - -size_t RTTYClient::print(ITA2String& ita2) { - uint8_t* arr = ita2.byteArr(); - size_t n = RTTYClient::write(arr, ita2.length()); - delete[] arr; - return(n); -} - -size_t RTTYClient::print(const char str[]) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write((uint8_t*)str, strlen(str)); - } - return(n); -} - -size_t RTTYClient::print(char c) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(c); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write(c); - } - return(n); -} - -size_t RTTYClient::print(unsigned char b, int base) { - return(RTTYClient::print((unsigned long)b, base)); -} - -size_t RTTYClient::print(int n, int base) { - return(RTTYClient::print((long)n, base)); -} - -size_t RTTYClient::print(unsigned int n, int base) { - return(RTTYClient::print((unsigned long)n, base)); -} - -size_t RTTYClient::print(long n, int base) { - if(base == 0) { - return(RTTYClient::write(n)); - } else if(base == DEC) { - if (n < 0) { - int t = RTTYClient::print('-'); - n = -n; - return(RTTYClient::printNumber(n, DEC) + t); - } - return(RTTYClient::printNumber(n, DEC)); - } else { - return(RTTYClient::printNumber(n, base)); - } -} - -size_t RTTYClient::print(unsigned long n, int base) { - if(base == 0) { - return(RTTYClient::write(n)); - } else { - return(RTTYClient::printNumber(n, base)); - } -} - -size_t RTTYClient::print(double n, int digits) { - return(RTTYClient::printFloat(n, digits)); -} - -size_t RTTYClient::println(void) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String lf = ITA2String("\r\n"); - n = RTTYClient::print(lf); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write("\r\n"); - } - return(n); -} - -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t RTTYClient::println(__FlashStringHelper* fstr) { - size_t n = RTTYClient::print(fstr); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(const String& str) { - size_t n = RTTYClient::print(str); - n += RTTYClient::println(); - return(n); -} -#endif - -size_t RTTYClient::println(ITA2String& ita2) { - size_t n = RTTYClient::print(ita2); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(const char* str) { - size_t n = RTTYClient::print(str); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(char c) { - size_t n = RTTYClient::print(c); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(unsigned char b, int base) { - size_t n = RTTYClient::print(b, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(int num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(unsigned int num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(long num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(unsigned long num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(double d, int digits) { - size_t n = RTTYClient::print(d, digits); - n += RTTYClient::println(); - return(n); -} - void RTTYClient::mark() { Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); @@ -423,106 +102,6 @@ void RTTYClient::space() { mod->waitForMicroseconds(start, bitDuration); } -size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { - char buf[8 * sizeof(long) + 1]; - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; - - if(base < 2) { - base = 10; - } - - do { - char c = n % base; - n /= base; - - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); - - size_t l = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str); - uint8_t* arr = ita2.byteArr(); - l = RTTYClient::write(arr, ita2.length()); - delete[] arr; - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - l = RTTYClient::write(str); - } - - return(l); -} - -/// \todo improve ITA2 float print speed (characters are sent one at a time) -size_t RTTYClient::printFloat(double number, uint8_t digits) { - size_t n = 0; - - char code[] = {0x00, 0x00, 0x00, 0x00}; - if (isnan(number)) strcpy(code, "nan"); - if (isinf(number)) strcpy(code, "inf"); - if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically - if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically - - if(code[0] != 0x00) { - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(code); - uint8_t* arr = ita2.byteArr(); - n = RTTYClient::write(arr, ita2.length()); - delete[] arr; - return(n); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - return(RTTYClient::write(code)); - } - } - - // Handle negative numbers - if (number < 0.0) { - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String("-"); - uint8_t* arr = ita2.byteArr(); - n += RTTYClient::write(arr, ita2.length()); - delete[] arr; - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n += RTTYClient::print('-'); - } - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) { - rounding /= 10.0; - } - number += rounding; - - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long)number; - double remainder = number - (double)int_part; - n += RTTYClient::print(int_part); - - // Print the decimal point, but only if there are digits beyond - if(digits > 0) { - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String("."); - uint8_t* arr = ita2.byteArr(); - n += RTTYClient::write(arr, ita2.length()); - delete[] arr; - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n += RTTYClient::print('.'); - } - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - unsigned int toPrint = (unsigned int)(remainder); - n += RTTYClient::print(toPrint); - remainder -= toPrint; - } - - return n; -} - int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) if(audioClient != nullptr) { diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index f8ee69348b..4ebbc7ccf8 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -7,81 +7,14 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" - -#define RADIOLIB_ITA2_FIGS 0x1B -#define RADIOLIB_ITA2_LTRS 0x1F -#define RADIOLIB_ITA2_LENGTH 32 - -// ITA2 character table: - position in array corresponds to 5-bit ITA2 code -// - characters to the left are in letters shift, characters to the right in figures shift -// - characters marked 0x7F do not have ASCII equivalent -static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = { - {'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, - {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, - {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, - {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F} -}; - -/*! - \class ITA2String - \brief ITA2-encoded string. -*/ -class ITA2String { - public: - /*! - \brief Default single-character constructor. - \param c ASCII-encoded character to encode as ITA2. - */ - explicit ITA2String(char c); - - /*! - \brief Default string constructor. - \param str ASCII-encoded string to encode as ITA2. - */ - explicit ITA2String(const char* str); - - /*! - \brief Default destructor. - */ - ~ITA2String(); - - /*! - \brief Gets the length of the ITA2 string. This number is not the same as the length of ASCII-encoded string! - \returns Length of ITA2-encoded string. - */ - size_t length(); - - /*! - \brief Gets the ITA2 representation of the ASCII string set in constructor. - \returns Pointer to dynamically allocated array, which contains ITA2-encoded bytes. - It is the caller's responsibility to deallocate this memory! - */ - uint8_t* byteArr(); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - #if defined(RADIOLIB_STATIC_ONLY) - char strAscii[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - char* strAscii; - #endif - size_t asciiLen; - size_t ita2Len; - - static uint16_t getBits(char c); -}; - -// supported encoding schemes -#define RADIOLIB_ASCII 0 -#define RADIOLIB_ASCII_EXTENDED 1 -#define RADIOLIB_ITA2 2 +#include "../Print/Print.h" +#include "../Print/ITA2String.h" /*! \class RTTYClient \brief Client for RTTY communication. The public interface is the same as Arduino Serial. */ -class RTTYClient { +class RTTYClient: public RadioLibPrint { public: /*! \brief Constructor for 2-FSK mode. @@ -121,39 +54,13 @@ class RTTYClient { */ int16_t standby(); - size_t write(const char* str); - size_t write(uint8_t* buff, size_t len); + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ size_t write(uint8_t b); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t print(__FlashStringHelper*); - size_t print(const String &); - #endif - size_t print(ITA2String &); - size_t print(const char[]); - size_t print(char); - size_t print(unsigned char, int = DEC); - size_t print(int, int = DEC); - size_t print(unsigned int, int = DEC); - size_t print(long, int = DEC); - size_t print(unsigned long, int = DEC); - size_t print(double, int = 2); - - size_t println(void); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t println(__FlashStringHelper*); - size_t println(const String &); - #endif - size_t println(ITA2String &); - size_t println(const char[]); - size_t println(char); - size_t println(unsigned char, int = DEC); - size_t println(int, int = DEC); - size_t println(unsigned int, int = DEC); - size_t println(long, int = DEC); - size_t println(unsigned long, int = DEC); - size_t println(double, int = 2); - #if !defined(RADIOLIB_GODMODE) private: #endif @@ -162,19 +69,14 @@ class RTTYClient { AFSKClient* audioClient; #endif - uint8_t encoding = RADIOLIB_ASCII; uint32_t baseFreq = 0, baseFreqHz = 0; uint32_t shiftFreq = 0, shiftFreqHz = 0; uint32_t bitDuration = 0; - uint8_t dataBitsNum = 0; uint8_t stopBitsNum = 0; void mark(); void space(); - size_t printNumber(unsigned long, uint8_t); - size_t printFloat(double, uint8_t); - int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); }; From 0030a590282fc72581d8f0d2d0fc5a38416b1b0d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:54:43 +0200 Subject: [PATCH 0533/1848] [Morse] Use common print class --- src/protocols/Morse/Morse.cpp | 217 +--------------------------------- src/protocols/Morse/Morse.h | 37 ++---- 2 files changed, 9 insertions(+), 245 deletions(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 377b6c01ca..4f7c576d16 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -6,6 +6,7 @@ MorseClient::MorseClient(PhysicalLayer* phy) { phyLayer = phy; + lineFeed = "^"; #if !defined(RADIOLIB_EXCLUDE_AFSK) audioClient = nullptr; #endif @@ -14,6 +15,7 @@ MorseClient::MorseClient(PhysicalLayer* phy) { #if !defined(RADIOLIB_EXCLUDE_AFSK) MorseClient::MorseClient(AFSKClient* audio) { phyLayer = audio->phyLayer; + lineFeed = "^"; audioClient = audio; } #endif @@ -110,22 +112,6 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { } #endif -size_t MorseClient::write(const char* str) { - if(str == NULL) { - return(0); - } - - return(MorseClient::write((uint8_t*)str, strlen(str))); -} - -size_t MorseClient::write(uint8_t* buff, size_t len) { - size_t n = 0; - for(size_t i = 0; i < len; i++) { - n += MorseClient::write(buff[i]); - } - return(n); -} - size_t MorseClient::write(uint8_t b) { Module* mod = phyLayer->getMod(); @@ -180,205 +166,6 @@ size_t MorseClient::write(uint8_t b) { return(1); } -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t MorseClient::print(__FlashStringHelper* fstr) { - PGM_P p = reinterpret_cast(fstr); - size_t n = 0; - while(true) { - char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); - if(c == '\0') { - break; - } - n += MorseClient::write(c); - } - return n; -} - -size_t MorseClient::print(const String& str) { - return(MorseClient::write((uint8_t*)str.c_str(), str.length())); -} -#endif - -size_t MorseClient::print(const char* str) { - return(MorseClient::write((uint8_t*)str, strlen(str))); -} - -size_t MorseClient::print(char c) { - return(MorseClient::write(c)); -} - -size_t MorseClient::print(unsigned char b, int base) { - return(MorseClient::print((unsigned long)b, base)); -} - -size_t MorseClient::print(int n, int base) { - return(MorseClient::print((long)n, base)); -} - -size_t MorseClient::print(unsigned int n, int base) { - return(MorseClient::print((unsigned long)n, base)); -} - -size_t MorseClient::print(long n, int base) { - if(base == 0) { - return(MorseClient::write(n)); - } else if(base == DEC) { - if (n < 0) { - int t = MorseClient::print('-'); - n = -n; - return(MorseClient::printNumber(n, DEC) + t); - } - return(MorseClient::printNumber(n, DEC)); - } else { - return(MorseClient::printNumber(n, base)); - } -} - -size_t MorseClient::print(unsigned long n, int base) { - if(base == 0) { - return(MorseClient::write(n)); - } else { - return(MorseClient::printNumber(n, base)); - } -} - -size_t MorseClient::print(double n, int digits) { - return(MorseClient::printFloat(n, digits)); -} - -size_t MorseClient::println(void) { - return(MorseClient::write('^')); -} - -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t MorseClient::println(__FlashStringHelper* fstr) { - size_t n = MorseClient::print(fstr); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(const String& str) { - size_t n = MorseClient::print(str); - n += MorseClient::println(); - return(n); -} -#endif - -size_t MorseClient::println(const char* str) { - size_t n = MorseClient::print(str); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(char c) { - size_t n = MorseClient::print(c); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(unsigned char b, int base) { - size_t n = MorseClient::print(b, base); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(int num, int base) { - size_t n = MorseClient::print(num, base); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(unsigned int num, int base) { - size_t n = MorseClient::print(num, base); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(long num, int base) { - size_t n = MorseClient::print(num, base); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(unsigned long num, int base) { - size_t n = MorseClient::print(num, base); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::println(double d, int digits) { - size_t n = MorseClient::print(d, digits); - n += MorseClient::println(); - return(n); -} - -size_t MorseClient::printNumber(unsigned long n, uint8_t base) { - char buf[8 * sizeof(long) + 1]; - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; - - if(base < 2) { - base = 10; - } - - do { - char c = n % base; - n /= base; - - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); - - return(MorseClient::write(str)); -} - -size_t MorseClient::printFloat(double number, uint8_t digits) { - size_t n = 0; - - char code[] = {0x00, 0x00, 0x00, 0x00}; - if (isnan(number)) strcpy(code, "nan"); - if (isinf(number)) strcpy(code, "inf"); - if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically - if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically - - if(code[0] != 0x00) { - return(MorseClient::write(code)); - } - - // Handle negative numbers - if (number < 0.0) { - n += MorseClient::print('-'); - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) { - rounding /= 10.0; - } - number += rounding; - - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long)number; - double remainder = number - (double)int_part; - n += MorseClient::print(int_part); - - // Print the decimal point, but only if there are digits beyond - if(digits > 0) { - n += MorseClient::print('.'); - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - unsigned int toPrint = (unsigned int)(remainder); - n += MorseClient::print(toPrint); - remainder -= toPrint; - } - - return n; -} - int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) if(audioClient != nullptr) { diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 374ccd55cd..3bc414644d 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -4,6 +4,7 @@ #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" +#include "../Print/Print.h" #define RADIOLIB_MORSE_DOT 0b0 #define RADIOLIB_MORSE_DASH 0b1 @@ -89,7 +90,7 @@ static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { \class MorseClient \brief Client for Morse Code communication. The public interface is the same as Arduino Serial. */ -class MorseClient { +class MorseClient: public RadioLibPrint { public: /*! \brief Constructor for 2-FSK mode. @@ -142,37 +143,13 @@ class MorseClient { int read(uint8_t* symbol, uint8_t* len, float low = 0.75f, float high = 1.25f); #endif - size_t write(const char* str); - size_t write(uint8_t* buff, size_t len); + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ size_t write(uint8_t b); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t print(__FlashStringHelper*); - size_t print(const String &); - #endif - size_t print(const char[]); - size_t print(char); - size_t print(unsigned char, int = DEC); - size_t print(int, int = DEC); - size_t print(unsigned int, int = DEC); - size_t print(long, int = DEC); - size_t print(unsigned long, int = DEC); - size_t print(double, int = 2); - - size_t println(void); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t println(__FlashStringHelper*); - size_t println(const String &); - #endif - size_t println(const char[]); - size_t println(char); - size_t println(unsigned char, int = DEC); - size_t println(int, int = DEC); - size_t println(unsigned int, int = DEC); - size_t println(long, int = DEC); - size_t println(unsigned long, int = DEC); - size_t println(double, int = 2); - #if !defined(RADIOLIB_GODMODE) private: #endif From 24f714b914eb63492930fb4e8501caf4190903c1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:55:04 +0200 Subject: [PATCH 0534/1848] [Hell] Use common print class --- src/protocols/Hellschreiber/Hellschreiber.cpp | 218 +----------------- src/protocols/Hellschreiber/Hellschreiber.h | 37 +-- 2 files changed, 9 insertions(+), 246 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 63fb915f1b..8a0e9376e8 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -5,7 +5,7 @@ HellClient::HellClient(PhysicalLayer* phy) { phyLayer = phy; - + lineFeed = " "; #if !defined(RADIOLIB_EXCLUDE_AFSK) audioClient = nullptr; #endif @@ -14,6 +14,7 @@ HellClient::HellClient(PhysicalLayer* phy) { #if !defined(RADIOLIB_EXCLUDE_AFSK) HellClient::HellClient(AFSKClient* audio) { phyLayer = audio->phyLayer; + lineFeed = " "; audioClient = audio; } #endif @@ -58,21 +59,6 @@ void HellClient::setInversion(bool inv) { invert = inv; } -size_t HellClient::write(const char* str) { - if(str == NULL) { - return(0); - } - return(HellClient::write((uint8_t *)str, strlen(str))); -} - -size_t HellClient::write(uint8_t* buff, size_t len) { - size_t n = 0; - for(size_t i = 0; i < len; i++) { - n += HellClient::write(buff[i]); - } - return(n); -} - size_t HellClient::write(uint8_t b) { // convert to position in font buffer uint8_t pos = b; @@ -96,206 +82,6 @@ size_t HellClient::write(uint8_t b) { return(printGlyph(buff)); } -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t HellClient::print(__FlashStringHelper* fstr) { - PGM_P p = reinterpret_cast(fstr); - size_t n = 0; - while(true) { - char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); - if(c == '\0') { - break; - } - n += HellClient::write(c); - } - return n; -} - -size_t HellClient::print(const String& str) { - return(HellClient::write((uint8_t*)str.c_str(), str.length())); -} -#endif - -size_t HellClient::print(const char* str) { - return(HellClient::write((uint8_t*)str, strlen(str))); -} - -size_t HellClient::print(char c) { - return(HellClient::write(c)); -} - -size_t HellClient::print(unsigned char b, int base) { - return(HellClient::print((unsigned long)b, base)); -} - -size_t HellClient::print(int n, int base) { - return(HellClient::print((long)n, base)); -} - -size_t HellClient::print(unsigned int n, int base) { - return(HellClient::print((unsigned long)n, base)); -} - -size_t HellClient::print(long n, int base) { - if(base == 0) { - return(HellClient::write(n)); - } else if(base == DEC) { - if (n < 0) { - int t = HellClient::print('-'); - n = -n; - return(HellClient::printNumber(n, DEC) + t); - } - return(HellClient::printNumber(n, DEC)); - } else { - return(HellClient::printNumber(n, base)); - } -} - -size_t HellClient::print(unsigned long n, int base) { - if(base == 0) { - return(HellClient::write(n)); - } else { - return(HellClient::printNumber(n, base)); - } -} - -size_t HellClient::print(double n, int digits) { - return(HellClient::printFloat(n, digits)); -} - -size_t HellClient::println(void) { - // Hellschreiber has no concept of "line ending", print one space instead - return(HellClient::print(' ')); -} - -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t HellClient::println(__FlashStringHelper* fstr) { - size_t n = HellClient::print(fstr); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(const String& str) { - size_t n = HellClient::print(str); - n += HellClient::println(); - return(n); -} -#endif - -size_t HellClient::println(const char* str) { - size_t n = HellClient::print(str); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(char c) { - size_t n = HellClient::print(c); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(unsigned char b, int base) { - size_t n = HellClient::print(b, base); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(int num, int base) { - size_t n = HellClient::print(num, base); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(unsigned int num, int base) { - size_t n = HellClient::print(num, base); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(long num, int base) { - size_t n = HellClient::print(num, base); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(unsigned long num, int base) { - size_t n = HellClient::print(num, base); - n += HellClient::println(); - return(n); -} - -size_t HellClient::println(double d, int digits) { - size_t n = HellClient::print(d, digits); - n += HellClient::println(); - return(n); -} - -size_t HellClient::printNumber(unsigned long n, uint8_t base) { - char buf[8 * sizeof(long) + 1]; - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; - - if(base < 2) { - base = 10; - } - - do { - char c = n % base; - n /= base; - - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); - - return(HellClient::write(str)); -} - -size_t HellClient::printFloat(double number, uint8_t digits) { - size_t n = 0; - - char code[] = {0x00, 0x00, 0x00, 0x00}; - if (isnan(number)) strcpy(code, "nan"); - if (isinf(number)) strcpy(code, "inf"); - if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically - if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically - - if(code[0] != 0x00) { - return(HellClient::write(code)); - } - - // Handle negative numbers - if (number < 0.0) { - n += HellClient::print('-'); - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) { - rounding /= 10.0; - } - number += rounding; - - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long)number; - double remainder = number - (double)int_part; - n += HellClient::print(int_part); - - // Print the decimal point, but only if there are digits beyond - if(digits > 0) { - n += HellClient::print('.'); - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - unsigned int toPrint = (unsigned int)(remainder); - n += HellClient::print(toPrint); - remainder -= toPrint; - } - - return n; -} - int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) if(audioClient != nullptr) { diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index ac7d5d6c64..7855dee8b0 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -7,6 +7,7 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" +#include "../Print/Print.h" #define RADIOLIB_HELL_FONT_WIDTH 7 #define RADIOLIB_HELL_FONT_HEIGHT 7 @@ -86,7 +87,7 @@ static const uint8_t HellFont[64][RADIOLIB_HELL_FONT_WIDTH - 2] RADIOLIB_NONVOLA \class HellClient \brief Client for Hellschreiber transmissions. */ -class HellClient { +class HellClient: public RadioLibPrint { public: /*! \brief Constructor for 2-FSK mode. @@ -124,37 +125,13 @@ class HellClient { */ void setInversion(bool inv); - size_t write(const char* str); - size_t write(uint8_t* buff, size_t len); + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ size_t write(uint8_t b); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t print(__FlashStringHelper*); - size_t print(const String &); - #endif - size_t print(const char[]); - size_t print(char); - size_t print(unsigned char, int = DEC); - size_t print(int, int = DEC); - size_t print(unsigned int, int = DEC); - size_t print(long, int = DEC); - size_t print(unsigned long, int = DEC); - size_t print(double, int = 2); - - size_t println(void); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t println(__FlashStringHelper*); - size_t println(const String &); - #endif - size_t println(const char[]); - size_t println(char); - size_t println(unsigned char, int = DEC); - size_t println(int, int = DEC); - size_t println(unsigned int, int = DEC); - size_t println(long, int = DEC); - size_t println(unsigned long, int = DEC); - size_t println(double, int = 2); - #if !defined(RADIOLIB_GODMODE) private: #endif From 99f1ad24b21dc937585b7639040fd2031044cd3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:55:27 +0200 Subject: [PATCH 0535/1848] [AFSK] Added copy constructor --- src/protocols/AFSK/AFSK.cpp | 5 +++++ src/protocols/AFSK/AFSK.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index bbf25b3a62..6d7e518d3e 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -5,6 +5,11 @@ AFSKClient::AFSKClient(PhysicalLayer* phy, uint32_t pin): outPin(pin) { phyLayer = phy; } +AFSKClient::AFSKClient(AFSKClient* aud) { + phyLayer = aud->phyLayer; + outPin = aud->outPin; +} + int16_t AFSKClient::begin() { return(phyLayer->startDirect()); } diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index cdf6ebcab2..3b69f3083f 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -22,6 +22,12 @@ class AFSKClient { */ AFSKClient(PhysicalLayer* phy, uint32_t pin); + /*! + \brief Copy contructor. + \param aud Pointer to the AFSKClient instance to copy. + */ + AFSKClient(AFSKClient* aud); + /*! \brief Initialization method. \returns \ref status_codes @@ -56,6 +62,7 @@ class AFSKClient { friend class SSTVClient; friend class AX25Client; friend class FSK4Client; + friend class BellClient; }; #endif From 8b73333a629253fafa75bd56033ccc95295d89f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:57:32 +0200 Subject: [PATCH 0536/1848] [Print] Added missing godmode guard --- src/protocols/Print/Print.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index 0dbc5edadf..c1f1d73806 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -50,15 +50,16 @@ class RadioLibPrint { size_t println(unsigned long, int = DEC); size_t println(double, int = 2); size_t println(void); - + +#if !defined(RADIOLIB_GODMODE) protected: +#endif uint8_t encoding = RADIOLIB_ASCII_EXTENDED; const char* lineFeed; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); - private: }; #endif From f1a8333591d6645e3727cc3edc21111701fb70b8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 23:01:23 +0200 Subject: [PATCH 0537/1848] [Bell] Added Bell-compatible modem --- keywords.txt | 9 ++ src/RadioLib.h | 2 + src/protocols/BellModem/BellModem.cpp | 97 +++++++++++++++ src/protocols/BellModem/BellModem.h | 127 ++++++++++++++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 1 + 5 files changed, 236 insertions(+) create mode 100644 src/protocols/BellModem/BellModem.cpp create mode 100644 src/protocols/BellModem/BellModem.h diff --git a/keywords.txt b/keywords.txt index 6a2d0f6d2b..b55879336c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -55,6 +55,7 @@ FSK4Client KEYWORD1 APRSClient KEYWORD1 PagerClient KEYWORD1 ExternalRadio KEYWORD1 +BellClient KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -67,6 +68,11 @@ PasokonP3 KEYWORD1 PasokonP5 KEYWORD1 PasokonP7 KEYWORD1 +# Bell Modems +Bell101 KEYWORD1 +Bell103 KEYWORD1 +Bell202 KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### @@ -260,6 +266,9 @@ dropSync KEYWORD2 setTimerFlag KEYWORD2 setInterruptSetup KEYWORD2 +# BellModem +setModem KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index 669169a9f9..f4e690a7a7 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -107,6 +107,8 @@ #include "protocols/FSK4/FSK4.h" #include "protocols/APRS/APRS.h" #include "protocols/ExternalRadio/ExternalRadio.h" +#include "protocols/Print/Print.h" +#include "protocols/BellModem/BellModem.h" // only create Radio class when using RadioShield #if defined(RADIOLIB_RADIOSHIELD) diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp new file mode 100644 index 0000000000..69a671879d --- /dev/null +++ b/src/protocols/BellModem/BellModem.cpp @@ -0,0 +1,97 @@ +#include "BellModem.h" +#if !defined(RADIOLIB_EXCLUDE_BELL) + +const struct BellModem_t Bell101 { + .freqMark = 1270, + .freqSpace = 1070, + .baudRate = 110, + .freqMarkReply = 2225, + .freqSpaceReply = 2025, +}; + +const struct BellModem_t Bell103 { + .freqMark = 1270, + .freqSpace = 1070, + .baudRate = 300, + .freqMarkReply = 2225, + .freqSpaceReply = 2025, +}; + +const struct BellModem_t Bell202 { + .freqMark = 1200, + .freqSpace = 2200, + .baudRate = 1200, + .freqMarkReply = 1200, + .freqSpaceReply = 2200, +}; + +BellClient::BellClient(PhysicalLayer* phy, uint32_t pin) : AFSKClient(phy, pin) { + this->reply = false; +} + +BellClient::BellClient(AFSKClient* aud) : AFSKClient(aud) { + this->reply = false; +} + +int16_t BellClient::begin(const BellModem_t& modem) { + int16_t state = setModem(modem); + RADIOLIB_ASSERT(state); + + state = phyLayer->startDirect(); + return(state); +} + +int16_t BellClient::setModem(const BellModem_t& modem) { + this->modemType = modem; + this->toneLen = (1000000.0/(float)this->modemType.baudRate)*this->correction; + return(RADIOLIB_ERR_NONE); +} + +int16_t BellClient::setCorrection(float corr) { + this->correction = corr; +} + +size_t BellClient::write(uint8_t b) { + // first get the frequencies + uint16_t toneMark = this->modemType.freqMark; + uint16_t toneSpace = this->modemType.freqSpace; + if(this->reply) { + toneMark = this->modemType.freqMarkReply; + toneMark = this->modemType.freqSpaceReply; + } + + // get the Module pointer to access HAL + Module* mod = this->phyLayer->getMod(); + + if(this->autoStart) { + phyLayer->transmitDirect(); + } + + // iterate over the bits and set correct frequencies + for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { + uint32_t start = mod->hal->micros(); + if(b & mask) { + this->tone(toneMark, false); + } else { + this->tone(toneSpace, false); + } + mod->waitForMicroseconds(start, this->toneLen); + } + + if(this->autoStart) { + phyLayer->standby(); + } + return(1); +} + +int16_t BellClient::idle() { + this->autoStart = false; + return(phyLayer->transmitDirect()); +} + +int16_t BellClient::standby() { + this->autoStart = true; + return(phyLayer->standby()); +} + +#endif diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h new file mode 100644 index 0000000000..d16c44d91c --- /dev/null +++ b/src/protocols/BellModem/BellModem.h @@ -0,0 +1,127 @@ +#if !defined(_RADIOLIB_BELL_MODEM_H) +#define _RADIOLIB_BELL_MODEM_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "../../ArduinoHal.h" +#endif + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../Print/Print.h" +#include "../Print/ITA2String.h" + +/*! + \struct BellModem_t + \brief Definition of the Bell-compatible modem. +*/ +struct BellModem_t { + /*! + \brief Frequency of the mark tone. + */ + int16_t freqMark; + + /*! + \brief Frequency of the space tone. + */ + int16_t freqSpace; + + /*! + \brief Baud rate. + */ + int16_t baudRate; + + /*! + \brief Frequency of the mark tone when replying. + */ + int16_t freqMarkReply; + + /*! + \brief Frequency of the space tone when replying. + */ + int16_t freqSpaceReply; +}; + +// currently implemented Bell modems +extern const struct BellModem_t Bell101; +extern const struct BellModem_t Bell103; +extern const struct BellModem_t Bell202; + +/*! + \class BellClient + \brief Client for Bell modem communication. The public interface is the same as Arduino Serial. +*/ +class BellClient: public AFSKClient, public RadioLibPrint { + + public: + + /*! + \brief Whether the modem is replying. + On some modems, the replying station has different tone frequencies. + */ + bool reply; + + /*! + \brief Default constructor. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + \param pin The GPIO pin at which the tones will be generated. + */ + explicit BellClient(PhysicalLayer* phy, uint32_t pin); + + /*! + \brief Audio-client constructor. Can be used when AFSKClient instance already exists. + \param aud Audio client to use. + */ + BellClient(AFSKClient* aud); + + /*! + \brief Initialization method. + \param modem Definition of the Bell modem to use for communication. + \returns \ref status_codes + */ + int16_t begin(const BellModem_t& modem); + + /*! + \brief Set Bell modem. + \param modem Definition of the Bell modem to use for communication. + \returns \ref status_codes + */ + int16_t setModem(const BellModem_t& modem); + + /*! + \brief Set correction coefficient for tone length. + \param correction Timing correction factor, used to adjust the length of tones. + Less than 1.0 leads to shorter tones, defaults to 1.0 (no correction). + \returns \ref status_codes + */ + int16_t setCorrection(float corr); + + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ + size_t write(uint8_t b); + + /*! + \brief Set the modem to idle (ready to transmit). + */ + int16_t idle(); + + /*! + \brief Set the modem to standby (transmitter off). + */ + int16_t standby(); + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + BellModem_t modemType; + float correction = 1.0; + uint16_t toneLen = 0; + bool autoStart = true; + +}; + +#endif diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 9da9c78d3d..b19339b6d0 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -382,6 +382,7 @@ class PhysicalLayer { friend class AX25Client; friend class FSK4Client; friend class PagerClient; + friend class BellClient; }; #endif From e8f94c25d1d19cafb7e727e0a6af7792dff568d7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 23:01:50 +0200 Subject: [PATCH 0538/1848] [AX.25] Use Bell modem --- src/protocols/AX25/AX25.cpp | 38 ++++++++++++++----------------------- src/protocols/AX25/AX25.h | 15 +++------------ 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 63f0bc4b87..53b4018c2d 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -154,23 +154,25 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) { AX25Client::AX25Client(PhysicalLayer* phy) { phyLayer = phy; #if !defined(RADIOLIB_EXCLUDE_AFSK) - audioClient = nullptr; + bellModem = nullptr; #endif } #if !defined(RADIOLIB_EXCLUDE_AFSK) AX25Client::AX25Client(AFSKClient* audio) { phyLayer = audio->phyLayer; - audioClient = audio; - afskMark = RADIOLIB_AX25_AFSK_MARK; - afskSpace = RADIOLIB_AX25_AFSK_SPACE; - afskLen = RADIOLIB_AX25_AFSK_TONE_DURATION; + bellModem = new BellClient(audio); + bellModem->setModem(Bell202); } int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) { - afskMark = RADIOLIB_AX25_AFSK_MARK + mark; - afskSpace = RADIOLIB_AX25_AFSK_SPACE + space; - afskLen = length*(float)RADIOLIB_AX25_AFSK_TONE_DURATION; + BellModem_t modem; + modem.freqMark = Bell202.freqMark + mark; + modem.freqSpace = Bell202.freqSpace + space; + modem.freqMarkReply = modem.freqMark; + modem.freqSpaceReply = modem.freqSpace; + modem.baudRate = length*(float)Bell202.baudRate; + bellModem->setModem(modem); return(RADIOLIB_ERR_NONE); } #endif @@ -401,27 +403,15 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // transmit int16_t state = RADIOLIB_ERR_NONE; #if !defined(RADIOLIB_EXCLUDE_AFSK) - if(audioClient != nullptr) { - Module* mod = phyLayer->getMod(); - phyLayer->transmitDirect(); + if(bellModem != nullptr) { + bellModem->idle(); // iterate over all bytes in the buffer for(uint32_t i = 0; i < stuffedFrameBuffLen; i++) { - - // check each bit - for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { - uint32_t start = mod->hal->micros(); - if(stuffedFrameBuff[i] & mask) { - audioClient->tone(afskMark, false); - } else { - audioClient->tone(afskSpace, false); - } - mod->waitForMicroseconds(start, afskLen); - } - + bellModem->write(stuffedFrameBuff[i]); } - audioClient->noTone(); + bellModem->standby(); } else { #endif diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index a769edb8d7..05399e601a 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -7,6 +7,7 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" +#include "../BellModem/BellModem.h" // macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html #define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) @@ -23,7 +24,7 @@ // maximum callsign length in bytes #define RADIOLIB_AX25_MAX_CALLSIGN_LEN 6 -// flag field MSB LSB DESCRIPTION +// flag field MSB LSB DESCRIPTION #define RADIOLIB_AX25_FLAG 0b01111110 // 7 0 AX.25 frame start/end flag // address field @@ -73,13 +74,6 @@ #define RADIOLIB_AX25_PID_NO_LAYER_3 0xF0 #define RADIOLIB_AX25_PID_ESCAPE_CHARACTER 0xFF -// AFSK tones in Hz -#define RADIOLIB_AX25_AFSK_MARK 1200 -#define RADIOLIB_AX25_AFSK_SPACE 2200 - -// tone duration in us (for 1200 baud AFSK) -#define RADIOLIB_AX25_AFSK_TONE_DURATION 833 - /*! \class AX25Frame \brief Abstraction of AX.25 frame format. @@ -321,10 +315,7 @@ class AX25Client { PhysicalLayer* phyLayer; #if !defined(RADIOLIB_EXCLUDE_AFSK) - AFSKClient* audioClient; - uint32_t afskMark; - uint32_t afskSpace; - uint32_t afskLen; + BellClient* bellModem; #endif char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; From f1a947c09d6c23ad78ff753e312ebe506e4984ff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 23:05:24 +0200 Subject: [PATCH 0539/1848] [Bell] Added missing return --- src/protocols/BellModem/BellModem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp index 69a671879d..087bde1705 100644 --- a/src/protocols/BellModem/BellModem.cpp +++ b/src/protocols/BellModem/BellModem.cpp @@ -49,6 +49,7 @@ int16_t BellClient::setModem(const BellModem_t& modem) { int16_t BellClient::setCorrection(float corr) { this->correction = corr; + return(RADIOLIB_ERR_NONE); } size_t BellClient::write(uint8_t b) { From 54c1255646ed416ae222184990ae1c1b514e2b34 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 10:18:50 +0200 Subject: [PATCH 0540/1848] [Bell] Added Bell modem example --- .../BellModem_Transmit/BellModem_Transmit.ino | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino diff --git a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino new file mode 100644 index 0000000000..7ac4d5b3fa --- /dev/null +++ b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino @@ -0,0 +1,116 @@ +/* + RadioLib Bell Modem Transmit Example + + This example shows how to transmit binary data + using audio Bell 202 tones. + + Other implemented Bell modems + - Bell 101 + - Bell 103 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create Bell modem instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 (only devices without TCXO!) +BellClient bell(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Bell 202 modem + Serial.print(F("[Bell 202] Initializing ... ")); + state = bell.begin(Bell202); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Bell 202] Sending data ... ")); + + // send out idle condition for 500 ms + bell.idle(); + delay(500); + + // BellClient supports all methods of the Serial class + + // Arduino String class + String aStr = "Arduino String"; + bell.println(aStr); + + // character array (C-String) + bell.println("C-String"); + + // string saved in flash + bell.println(F("Flash String")); + + // character + bell.println('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + bell.println(255, HEX); + + // integer number + int i = 1000; + bell.println(i); + + // floating point number + float f = -3.1415; + bell.println(f, 3); + + // ITA2-encoded string + ITA2String str("HELLO WORLD!"); + bell.print(str); + + // turn the transmitter off + bell.standby(); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} From 3df9cb27ff55fcb34fde6ee9ccff4bccc3426d2a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 11:26:53 +0200 Subject: [PATCH 0541/1848] [CC1101] Fixed non-Hal functions --- src/modules/CC1101/CC1101.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f392a4cc65..b7b4f4bd58 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -93,11 +93,11 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pw void CC1101::reset() { // this is the manual power-on-reset sequence - this->mod->hal->digitalWrite(this->mod->getCs(), LOW); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); this->mod->hal->delayMicroseconds(5); - this->mod->hal->digitalWrite(this->mod->getCs(), HIGH); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); this->mod->hal->delayMicroseconds(40); - this->mod->hal->digitalWrite(this->mod->getCs(), LOW); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); this->mod->hal->delay(10); SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); } @@ -132,8 +132,6 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { } } - delay(20); - return(finishTransmit()); } @@ -466,15 +464,14 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { this->packetLengthQueried = false; // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) - //if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { + if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { // set mode to standby standby(); // flush Rx FIFO SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); - delay(10); - //} + } return(RADIOLIB_ERR_NONE); } From a4bf746e1fbe94efec3954bcfde01d56aa8cdde7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 11:30:20 +0200 Subject: [PATCH 0542/1848] [Print] Added missing headers for non-Arduino builds --- src/protocols/Print/Print.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp index 9d0fa5581a..a6a71ae6fa 100644 --- a/src/protocols/Print/Print.cpp +++ b/src/protocols/Print/Print.cpp @@ -1,5 +1,9 @@ #include "Print.h" +#include +#include +#include + size_t RadioLibPrint::print(ITA2String& ita2) { uint8_t enc = this->encoding; this->encoding = RADIOLIB_ITA2; From 8f28b42d63b54bc54ffb3fc00fe2d25202e9ea8f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 11:31:52 +0200 Subject: [PATCH 0543/1848] [Print] Moved include to header --- src/protocols/Print/Print.cpp | 1 - src/protocols/Print/Print.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp index a6a71ae6fa..f944ec7545 100644 --- a/src/protocols/Print/Print.cpp +++ b/src/protocols/Print/Print.cpp @@ -1,6 +1,5 @@ #include "Print.h" -#include #include #include diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index c1f1d73806..a132cf6196 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -1,6 +1,8 @@ #if !defined(_RADIOLIB_PRINT_H) #define _RADIOLIB_PRINT_H +#include + #include "ITA2String.h" // supported encoding schemes From 4f0c400bd7d4df732509ddcdde9fdf387de8bb8e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 11:32:38 +0200 Subject: [PATCH 0544/1848] [ITA2] Added missing header --- src/protocols/Print/ITA2String.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp index 0c93da2eba..b162b25980 100644 --- a/src/protocols/Print/ITA2String.cpp +++ b/src/protocols/Print/ITA2String.cpp @@ -1,5 +1,7 @@ #include "ITA2String.h" +#include + ITA2String::ITA2String(char c) { asciiLen = 1; #if !defined(RADIOLIB_STATIC_ONLY) From adf2f3ba98c82a935441b2261d5b621d19d7dec0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 11:34:58 +0200 Subject: [PATCH 0545/1848] [Print] Removed redundant headers --- src/protocols/Hellschreiber/Hellschreiber.cpp | 3 +-- src/protocols/Morse/Morse.cpp | 4 +--- src/protocols/RTTY/RTTY.cpp | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 8a0e9376e8..06eaae7943 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -1,6 +1,5 @@ #include "Hellschreiber.h" -#include -#include + #if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) HellClient::HellClient(PhysicalLayer* phy) { diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 4f7c576d16..5b535ba69c 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -1,7 +1,5 @@ #include "Morse.h" -#include -#include -#include + #if !defined(RADIOLIB_EXCLUDE_MORSE) MorseClient::MorseClient(PhysicalLayer* phy) { diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 6dc66bd3f1..05dac1de33 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -1,6 +1,5 @@ #include "RTTY.h" -#include -#include + #if !defined(RADIOLIB_EXCLUDE_RTTY) RTTYClient::RTTYClient(PhysicalLayer* phy) { From 4be33895873efb1405a8c955c4e57880c6e6f9fd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 11:37:38 +0200 Subject: [PATCH 0546/1848] Added missing headers --- src/protocols/Morse/Morse.cpp | 2 ++ src/protocols/RTTY/RTTY.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 5b535ba69c..1f1c3c7018 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -1,5 +1,7 @@ #include "Morse.h" +#include + #if !defined(RADIOLIB_EXCLUDE_MORSE) MorseClient::MorseClient(PhysicalLayer* phy) { diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 05dac1de33..eff2d7ad03 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -1,5 +1,7 @@ #include "RTTY.h" +#include + #if !defined(RADIOLIB_EXCLUDE_RTTY) RTTYClient::RTTYClient(PhysicalLayer* phy) { From a9eaf5f2fbe7e29dde55af84898fddc6e6560b24 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 22:10:12 +0200 Subject: [PATCH 0547/1848] Added CMakeLists --- CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..e3497d06c7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.13) + +project(radiolib) + +file(GLOB_RECURSE RADIOLIB_SOURCES + "src/*.cpp" +) + +add_library(RadioLib ${RADIOLIB_SOURCES}) + +target_include_directories(RadioLib PUBLIC "src" "${CMAKE_CURRENT_BINARY_DIR}/include") From e1853ddf04df7fba95c905de5714407706612f02 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 22:10:48 +0200 Subject: [PATCH 0548/1848] Added CMake for NonArduino example --- examples/NonArduino/Raspberry/.gitignore | 1 + examples/NonArduino/Raspberry/CMakeLists.txt | 20 ++++ examples/NonArduino/Raspberry/build.sh | 8 ++ examples/NonArduino/Raspberry/clean.sh | 3 + examples/NonArduino/Raspberry/main.cpp | 107 +++++++++---------- 5 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 examples/NonArduino/Raspberry/.gitignore create mode 100644 examples/NonArduino/Raspberry/CMakeLists.txt create mode 100644 examples/NonArduino/Raspberry/build.sh create mode 100644 examples/NonArduino/Raspberry/clean.sh diff --git a/examples/NonArduino/Raspberry/.gitignore b/examples/NonArduino/Raspberry/.gitignore new file mode 100644 index 0000000000..567609b123 --- /dev/null +++ b/examples/NonArduino/Raspberry/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/examples/NonArduino/Raspberry/CMakeLists.txt b/examples/NonArduino/Raspberry/CMakeLists.txt new file mode 100644 index 0000000000..5853fe9eac --- /dev/null +++ b/examples/NonArduino/Raspberry/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.18) + +# create the project +project(rpi-sx1261) + +# when using debuggers such as gdb, the following line can be used +#set(CMAKE_BUILD_TYPE Debug) + +# add the RadioLib source directory +# this is a bit of a hack because the example is being built within a library +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +# add the executable +add_executable(${PROJECT_NAME} main.cpp) + +# link both libraries +target_link_libraries(${PROJECT_NAME} RadioLib pigpio) + +# you can also specify RadioLib compile-time flags here +#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE) diff --git a/examples/NonArduino/Raspberry/build.sh b/examples/NonArduino/Raspberry/build.sh new file mode 100644 index 0000000000..a46bbdf4f8 --- /dev/null +++ b/examples/NonArduino/Raspberry/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e +mkdir -p build +cd build +cmake -G "CodeBlocks - Unix Makefiles" .. +make -j4 +cd .. diff --git a/examples/NonArduino/Raspberry/clean.sh b/examples/NonArduino/Raspberry/clean.sh new file mode 100644 index 0000000000..27cfe2641d --- /dev/null +++ b/examples/NonArduino/Raspberry/clean.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf ./build diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index 442145c85b..a7e59c15ee 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -1,8 +1,8 @@ /* RadioLib Non-Arduino Raspberry Pi Example - + This example shows how to use RadioLib without Arduino. - In this case, a CC1101 module is connected to Raspberry Pi + In this case, a Raspberry Pi with WaveShare SX1302 LoRaWAN Hat using the pigpio library. Can be used as a starting point to port RadioLib to any platform! @@ -14,7 +14,7 @@ */ // include the library -#include "RadioLib.h" +#include // include the library for Raspberry GPIO pins #include "pigpio.h" @@ -26,11 +26,10 @@ class PiHal : public RadioLibHal { public: // default constructor - initializes the base HAL and any needed private members - PiHal(uint8_t spiChannel = 0, uint32_t spiSpeed = 2000000) + PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), _spiChannel(spiChannel), _spiSpeed(spiSpeed) { - } void init() override { @@ -39,6 +38,10 @@ class PiHal : public RadioLibHal { // now the SPI spiBegin(); + + // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_HIGH); } void term() override { @@ -47,6 +50,10 @@ class PiHal : public RadioLibHal { // and now the pigpio library gpioTerminate(); + + // finally, pull the enable pin low + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_LOW); } // GPIO-related methods (pinMode, digitalWrite etc.) should check @@ -55,6 +62,7 @@ class PiHal : public RadioLibHal { if(pin == RADIOLIB_NC) { return; } + gpioSetMode(pin, mode); } @@ -62,6 +70,7 @@ class PiHal : public RadioLibHal { if(pin == RADIOLIB_NC) { return; } + gpioWrite(pin, value); } @@ -69,6 +78,7 @@ class PiHal : public RadioLibHal { if(pin == RADIOLIB_NC) { return(0); } + return(gpioRead(pin)); } @@ -76,6 +86,7 @@ class PiHal : public RadioLibHal { if(interruptNum == RADIOLIB_NC) { return; } + gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); } @@ -83,6 +94,7 @@ class PiHal : public RadioLibHal { if(interruptNum == RADIOLIB_NC) { return; } + gpioSetISRFunc(interruptNum, NULL, NULL, nullptr); } @@ -119,8 +131,8 @@ class PiHal : public RadioLibHal { return(gpioTick() - start); } - - void spiBegin() { + + void spiBegin() { if(_spiHandle < 0) { _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); } @@ -137,7 +149,7 @@ class PiHal : public RadioLibHal { void spiEndTransaction() {} void spiEnd() { - if (_spiHandle >= 0) { + if(_spiHandle >= 0) { spiClose(_spiHandle); _spiHandle = -1; } @@ -150,71 +162,50 @@ class PiHal : public RadioLibHal { int _spiHandle = -1; }; +// create a new instance of the HAL class +// use SPI channel 1, because on Waveshare LoRaWAN Hat, +// the SX1261 CS is connected to CE1 +PiHal* hal = new PiHal(1); + // now we can create the radio module -// the first argument is a new isntance of the HAL class defined above +// the first argument is a new instance of the HAL class defined above // the others are pin numbers -CC1101 radio = new Module(new PiHal(), 8, 24, RADIOLIB_NC, 25); - -// forward declaration of ISR function -void onPacket(); +// pinout corresponds to the Waveshare LoRaWAN Hat +// NSS pin: 7 +// DIO1 pin: 17 +// NRST pin: 22 +// BUSY pin: 4 +SX1261 radio = new Module(hal, 7, 17, 22, 4); // the entry point for the program int main(int argc, char** argv) { // initialize just like with Arduino - printf("[CC1101] Initializing ... "); + printf("[SX1261] Initializing ... "); int state = radio.begin(); if (state != RADIOLIB_ERR_NONE) { - printf("failed, code %d", state ); - return(1); - } - - // set the function that will be called - // when new packet is received - // RISING_EDGE is from the pigpio library - radio.setGdo0Action(onPacket, RISING_EDGE); - - // start listening for packets - printf(F("[CC1101] Starting to listen ... ")); - state = radio.startReceive(); - if(state != RADIOLIB_ERR_NONE) { - printf("failed, code %d", state); + printf("failed, code %d\n", state); return(1); } -} + printf("success!\n"); -void onPacket() { - // packet received, read the data - uint8_t byteArr[128]; - int state = radio.readData(byteArr, sizeof(byteArr)); + // loop forever + for(;;) { + // send a packet + printf("[SX1261] Transmitting packet ... "); + state = radio.transmit("Hello World!"); + if(state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + printf("success!"); - if (state == RADIOLIB_ERR_NONE) { - // packet was successfully received - printf("[CC1101] Received packet!"); + // wait for a second before transmitting again + hal->delay(1000); + + } else { + printf("failed, code %d\n", state); - // print the data of the packet - printf("[CC1101] Data:\t\t"); - for (int b = 0; b < sizeof(byteArr); b++){ - printf("%X", byteArr[b]); } - printf("\n"); - - // print RSSI (Received Signal Strength Indicator) - // of the last received packet - printf("[CC1101] RSSI:\t\t%d dBm\n", radio.getRSSI()); - - // print LQI (Link Quality Indicator) - // of the last received packet, lower is better - printf("[CC1101] LQI:\t\t%d\n", radio.getLQI()); - - } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { - // packet was received, but is malformed - printf("[CC1101] CRC error!\n"); - } else { - // some other error occurred - printf("[CC1101] Failed, code %d\n", state); } - // put module back to listen mode - radio.startReceive(); + return(0); } From 2eff7a358fe4b61ac5c64b39d382784eabdc93d5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 30 Apr 2023 22:11:05 +0200 Subject: [PATCH 0549/1848] [MOD] Removed redundant NSS pull --- src/Module.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index c0ce3f09e4..8346d3fc86 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -250,7 +250,6 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?"); return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } From 70eb488c1cfae4792499baa9c1dfa0d5d73446c7 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 30 Apr 2023 23:38:17 +0200 Subject: [PATCH 0550/1848] improve build workflow for better flexibility --- .github/workflows/main.yml | 169 ++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 89 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f05c5c5ec3..869f276983 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,13 +6,14 @@ on: pull_request: branches: [ master ] workflow_dispatch: - -jobs: - - build: - strategy: - matrix: - board: + inputs: + id: + description: The ID of the platform on which the build is run + required: true + default: arduino:avr:uno + type: choice + options: + - all - arduino:avr:uno - arduino:avr:mega - arduino:avr:leonardo @@ -37,10 +38,76 @@ jobs: - MegaCore:avr:1281 - teensy:avr:teensy41 +jobs: + build: + strategy: + matrix: + # platform-dependent settings - extra board options, board index URLs, skip patterns etc. + include: + - id: arduino:avr:uno + run: echo "skip-pattern=(STM32WL|SSTV)" >> $GITHUB_OUTPUT + - id: arduino:avr:mega + run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT + - id: arduino:avr:leonardo + - id: arduino:mbed:nano33ble + - id: arduino:mbed:envie_m4 + - id: arduino:megaavr:uno2018 + run: echo "options=':mode=on'" >> $GITHUB_OUTPUT + - id: arduino:sam:arduino_due_x + - id: arduino:samd:arduino_zero_native + - id: adafruit:samd:adafruit_feather_m0 + run: | + echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + - id: adafruit:nrf52:feather52832 + run: | + sudo apt-get update + sudo apt-get install -y python3 python3-pip python3-setuptools + pip3 install wheel + pip3 install --user adafruit-nrfutil + echo "/home/runner/.local/bin" >> $GITHUB_PATH + echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + - id: esp32:esp32:esp32 + run: + python -m pip install pyserial + echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT + - id: esp8266:esp8266:generic + run: | + echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT + - id: Intel:arc32:arduino_101 + - id: SparkFun:apollo3:sfe_artemis + run: | + echo "warnings='none'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT + - id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC + run: echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT + - id: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1 + run: | + # Do *not* skip STM32WL examples + echo "skip-pattern=''" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT + - id: stm32duino:STM32F1:mapleMini + run: | + echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT + - id: MegaCoreX:megaavr:4809 + run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT + - id: arduino:mbed_rp2040:pico + - id: rp2040:rp2040:rpipico + run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT + - id: CubeCell:CubeCell:CubeCell-Board + run: echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT + - id: MegaCore:avr:1281 + run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT + - id: teensy:avr:teensy41 + run: echo "index-url=--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT + runs-on: ubuntu-latest - name: ${{ matrix.board }} + name: ${{ matrix.id }} env: - run-build: ${{ (matrix.board == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.board)) }} + run-build: ${{ (matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) }} steps: - name: Install arduino-cli @@ -56,7 +123,7 @@ jobs: uses: jungwinter/split@v1 id: split with: - msg: ${{ matrix.board }} + msg: ${{ matrix.id }} seperator: ':' - name: Prepare platform-specific settings @@ -69,84 +136,8 @@ jobs: echo "skip-pattern=STM32WL" >> $GITHUB_OUTPUT echo "warnings=all" >> $GITHUB_OUTPUT - # platform-dependent settings - extra board options, board index URLs, skip patterns etc. - if [[ "${{ contains(matrix.board, 'arduino:avr:uno') }}" == "true" ]]; then - # Arduino Uno - echo "skip-pattern=(STM32WL|SSTV)" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then - # Arduino Mega - echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'arduino:megaavr:uno2018') }}" == "true" ]]; then - # Arduino Uno WiFi - echo "options=':mode=on'" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'adafruit:samd') }}" == "true" ]]; then - # Adafruit SAMD - echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT - echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'adafruit:nrf52') }}" == "true" ]]; then - # Adafruit Feather nRF52 - sudo apt-get update - sudo apt-get install -y python3 python3-pip python3-setuptools - pip3 install wheel - pip3 install --user adafruit-nrfutil - echo "/home/runner/.local/bin" >> $GITHUB_PATH - echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT - echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then - # ESP32 - python -m pip install pyserial - echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then - # ESP8266 - echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT - echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'SparkFun:apollo3') }}" == "true" ]]; then - # SparkFun Apollo - echo "warnings='none'" >> $GITHUB_OUTPUT - echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'STMicroelectronics:stm32') }}" == "true" ]]; then - # STM32 (official core) - echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT - - if [[ "${{ contains(matrix.board, 'NUCLEO_WL55') }}" == "true" ]]; then - # Do *not* skip STM32WL examples - echo "skip-pattern=''" >> $GITHUB_OUTPUT - fi - - elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then - # STM32 (unofficial core) - echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT - echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'MegaCoreX:megaavr') }}" == "true" ]]; then - # MegaCoreX - echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'CubeCell:CubeCell') }}" == "true" ]]; then - # CubeCell - echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'rp2040:rp2040') }}" == "true" ]]; then - # CubeCell - echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'MegaCore:avr') }}" == "true" ]]; then - # MegaCore - echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT - - elif [[ "${{ contains(matrix.board, 'teensy:avr') }}" == "true" ]]; then - # Teensy - echo "index-url=--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT - - fi + # run platform-dependent scripts defined in matrix + ${{ matrix.run }} - name: Install platform if: ${{ env.run-build == 'true' }} @@ -171,7 +162,7 @@ jobs: else # build sketch echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.board }}${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.id }}${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} if [ $? -ne 0 ]; then echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; exit 1; From 28180af7621b0c473ead9d9deb64b02233a40562 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 30 Apr 2023 23:41:24 +0200 Subject: [PATCH 0551/1848] run build on platform choosen in workflow dispatch --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 869f276983..0435fbf2cb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -107,7 +107,7 @@ jobs: runs-on: ubuntu-latest name: ${{ matrix.id }} env: - run-build: ${{ (matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) }} + run-build: ${{ (matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) || inputs.id == 'all' || inputs.id == matrix.id }} steps: - name: Install arduino-cli From 84ebdddcaf5219699c431ddca590c6c1f033e9a7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 2 May 2023 18:58:59 +0200 Subject: [PATCH 0552/1848] [SX128x] Wakeup device on standby() call --- src/modules/SX128x/SX128x.cpp | 10 +++++++++- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index ab3b40dfbb..d03175f6dd 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -460,7 +460,15 @@ int16_t SX128x::standby(uint8_t mode) { this->mod->setRfSwitchState(Module::MODE_IDLE); uint8_t data[] = { mode }; - return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1); + if(state == RADIOLIB_ERR_NONE) { + return(state); + } else if(state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) { + // the device might be in sleep mode, pull NSS low to wake up and try again + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); + } + return(state); } void SX128x::setDio1Action(void (*func)(void)) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 804c4fa85d..97dea0366f 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -460,7 +460,7 @@ class SX128x: public PhysicalLayer { int16_t scanChannel(); /*! - \brief Sets the module to sleep mode. + \brief Sets the module to sleep mode. To wake the device up, call standby(). \param retainConfig Set to true to retain configuration and data buffer or to false to discard current configuration and data buffer. Defaults to true. \returns \ref status_codes From bdc5bb0bba86e5fd840ba55c9305ffc461e936a9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 2 May 2023 18:59:33 +0200 Subject: [PATCH 0553/1848] [SX126x] Wakeup device on standby() call (#740) --- src/modules/SX126x/SX126x.cpp | 12 ++++++++++-- src/modules/SX126x/SX126x.h | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 077b967566..bf25174a6e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -453,8 +453,16 @@ int16_t SX126x::standby(uint8_t mode) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); - uint8_t data[] = {mode}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); + uint8_t data[] = { mode }; + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1); + if(state == RADIOLIB_ERR_NONE) { + return(state); + } else if(state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) { + // the device might be in sleep mode, pull NSS low to wake up and try again + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); + } + return(state); } void SX126x::setDio1Action(void (*func)(void)) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 01981ffac5..f24fa80769 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -538,7 +538,7 @@ class SX126x: public PhysicalLayer { int16_t scanChannel(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); /*! - \brief Sets the module to sleep mode. + \brief Sets the module to sleep mode. To wake the device up, call standby(). \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") or to false to discard current configuration ("cold start"). Defaults to true. \returns \ref status_codes From c4517656021a352ca5e845bfae31b34044cb264a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 2 May 2023 21:04:49 +0200 Subject: [PATCH 0554/1848] [SX128x] Added force wakeup to standby --- src/modules/SX128x/SX128x.cpp | 15 ++++++--------- src/modules/SX128x/SX128x.h | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index d03175f6dd..a964383491 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -455,20 +455,17 @@ int16_t SX128x::standby() { return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC)); } -int16_t SX128x::standby(uint8_t mode) { +int16_t SX128x::standby(uint8_t mode, bool wakeup) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); - uint8_t data[] = { mode }; - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1); - if(state == RADIOLIB_ERR_NONE) { - return(state); - } else if(state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) { - // the device might be in sleep mode, pull NSS low to wake up and try again + if(wakeup) { + // pull NSS low to wake up this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); } - return(state); + + uint8_t data[] = { mode }; + return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); } void SX128x::setDio1Action(void (*func)(void)) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 97dea0366f..6b8f64673c 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -477,9 +477,10 @@ class SX128x: public PhysicalLayer { \brief Sets the module to standby mode. \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). + \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. \returns \ref status_codes */ - int16_t standby(uint8_t mode); + int16_t standby(uint8_t mode, bool wakeup = false); // interrupt methods From 89f909fc6eaeb99c8bd6b206c3712f66d993e641 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 2 May 2023 21:05:13 +0200 Subject: [PATCH 0555/1848] [SX126x] Added force wakeup to standby (#740) --- src/modules/SX126x/SX126x.cpp | 15 ++++++--------- src/modules/SX126x/SX126x.h | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index bf25174a6e..79212eee84 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -449,20 +449,17 @@ int16_t SX126x::standby() { return(SX126x::standby(RADIOLIB_SX126X_STANDBY_RC)); } -int16_t SX126x::standby(uint8_t mode) { +int16_t SX126x::standby(uint8_t mode, bool wakeup) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); - uint8_t data[] = { mode }; - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1); - if(state == RADIOLIB_ERR_NONE) { - return(state); - } else if(state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) { - // the device might be in sleep mode, pull NSS low to wake up and try again + if(wakeup) { + // pull NSS low to wake up this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } - return(state); + + uint8_t data[] = { mode }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } void SX126x::setDio1Action(void (*func)(void)) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index f24fa80769..e685338a2f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -555,9 +555,10 @@ class SX126x: public PhysicalLayer { \brief Sets the module to standby mode. \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). + \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. \returns \ref status_codes */ - int16_t standby(uint8_t mode); + int16_t standby(uint8_t mode, bool wakeup = true); // interrupt methods From b9e2ad1f73017fb3839aaa0ca3ba22be94cbc307 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 6 May 2023 17:59:55 +0100 Subject: [PATCH 0556/1848] Update gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8cf77745bb..226f5c8ebb 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ extras/SX126x_Spectrum_Scan/out/* # PlatformIO .pio* + +# cmake +build/ From 1889a1fe82bfabf143df9458c304f511580f21ab Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 6 May 2023 18:00:58 +0100 Subject: [PATCH 0557/1848] Update cmake to install --- CMakeLists.txt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3497d06c7..33f0ebfde1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,4 +8,19 @@ file(GLOB_RECURSE RADIOLIB_SOURCES add_library(RadioLib ${RADIOLIB_SOURCES}) -target_include_directories(RadioLib PUBLIC "src" "${CMAKE_CURRENT_BINARY_DIR}/include") +target_include_directories(RadioLib + PUBLIC $ + $) + +include(GNUInstallDirs) + +install(TARGETS RadioLib + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/RadioLib + FILES_MATCHING PATTERN "*.h" +) + From a21cabf3e34cc2b2d20a9c64c306da0aba7ea8be Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 6 May 2023 18:02:12 +0100 Subject: [PATCH 0558/1848] Make build scripts executable --- examples/NonArduino/Raspberry/build.sh | 0 examples/NonArduino/Raspberry/clean.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 examples/NonArduino/Raspberry/build.sh mode change 100644 => 100755 examples/NonArduino/Raspberry/clean.sh diff --git a/examples/NonArduino/Raspberry/build.sh b/examples/NonArduino/Raspberry/build.sh old mode 100644 new mode 100755 diff --git a/examples/NonArduino/Raspberry/clean.sh b/examples/NonArduino/Raspberry/clean.sh old mode 100644 new mode 100755 From 32cef2699d7e606e21d3037d1d828057687e9160 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 6 May 2023 18:34:41 +0100 Subject: [PATCH 0559/1848] Update Raspberry example --- examples/NonArduino/Raspberry/CMakeLists.txt | 7 +- examples/NonArduino/Raspberry/PiHal.h | 153 ++++++++++++++++++ examples/NonArduino/Raspberry/main.cpp | 155 +------------------ 3 files changed, 162 insertions(+), 153 deletions(-) create mode 100644 examples/NonArduino/Raspberry/PiHal.h diff --git a/examples/NonArduino/Raspberry/CMakeLists.txt b/examples/NonArduino/Raspberry/CMakeLists.txt index 5853fe9eac..e708c0a3a0 100644 --- a/examples/NonArduino/Raspberry/CMakeLists.txt +++ b/examples/NonArduino/Raspberry/CMakeLists.txt @@ -6,9 +6,10 @@ project(rpi-sx1261) # when using debuggers such as gdb, the following line can be used #set(CMAKE_BUILD_TYPE Debug) -# add the RadioLib source directory -# this is a bit of a hack because the example is being built within a library -add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") +# if you did not build RadioLib as shared library (see README), +# you will have to add it as source directory +# the following is just an example, yours will likely be different +#add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") # add the executable add_executable(${PROJECT_NAME} main.cpp) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h new file mode 100644 index 0000000000..7929138ee2 --- /dev/null +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -0,0 +1,153 @@ +#ifndef PI_HAL_H +#define PI_HAL_H + +// include RadioLib +#include + +// include the library for Raspberry GPIO pins +#include "pigpio.h" + +// create a new Raspberry Pi hardware abstraction layer +// using the pigpio library +// the HAL must inherit from the base RadioLibHal class +// and implement all of its virtual methods +class PiHal : public RadioLibHal { + public: + // default constructor - initializes the base HAL and any needed private members + PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) + : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), + _spiChannel(spiChannel), + _spiSpeed(spiSpeed) { + } + + void init() override { + // first initialise pigpio library + gpioInitialise(); + + // now the SPI + spiBegin(); + + // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_HIGH); + } + + void term() override { + // stop the SPI + spiEnd(); + + // and now the pigpio library + gpioTerminate(); + + // finally, pull the enable pin low + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_LOW); + } + + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpioSetMode(pin, mode); + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpioWrite(pin, value); + } + + uint32_t digitalRead(uint32_t pin) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + return(gpioRead(pin)); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); + } + + void detachInterrupt(uint32_t interruptNum) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpioSetISRFunc(interruptNum, 0, 0, NULL); + } + + void delay(unsigned long ms) override { + gpioDelay(ms * 1000); + } + + void delayMicroseconds(unsigned long us) override { + gpioDelay(us); + } + + unsigned long millis() override { + return(gpioTick() / 1000); + } + + unsigned long micros() override { + return(gpioTick()); + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + gpioSetMode(pin, PI_INPUT); + uint32_t start = gpioTick(); + uint32_t curtick = gpioTick(); + + while(gpioRead(pin) == state) { + if((gpioTick() - curtick) > timeout) { + return(0); + } + } + + return(gpioTick() - start); + } + + void spiBegin() { + if(_spiHandle < 0) { + _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + } + } + + void spiBeginTransaction() {} + + uint8_t spiTransfer(uint8_t b) { + char ret; + spiXfer(_spiHandle, (char*)&b, &ret, 1); + return(ret); + } + + void spiEndTransaction() {} + + void spiEnd() { + if(_spiHandle >= 0) { + spiClose(_spiHandle); + _spiHandle = -1; + } + } + + private: + // the HAL can contain any additional private members + const unsigned int _spiSpeed; + const uint8_t _spiChannel; + int _spiHandle = -1; +}; + +#endif diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index a7e59c15ee..ec28a312e3 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -14,153 +14,10 @@ */ // include the library -#include +#include -// include the library for Raspberry GPIO pins -#include "pigpio.h" - -// create a new Raspberry Pi hardware abstraction layer -// using the pigpio library -// the HAL must inherit from the base RadioLibHal class -// and implement all of its virtual methods -class PiHal : public RadioLibHal { - public: - // default constructor - initializes the base HAL and any needed private members - PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) - : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), - _spiChannel(spiChannel), - _spiSpeed(spiSpeed) { - } - - void init() override { - // first initialise pigpio library - gpioInitialise(); - - // now the SPI - spiBegin(); - - // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio - gpioSetMode(18, PI_OUTPUT); - gpioWrite(18, PI_HIGH); - } - - void term() override { - // stop the SPI - spiEnd(); - - // and now the pigpio library - gpioTerminate(); - - // finally, pull the enable pin low - gpioSetMode(18, PI_OUTPUT); - gpioWrite(18, PI_LOW); - } - - // GPIO-related methods (pinMode, digitalWrite etc.) should check - // RADIOLIB_NC as an alias for non-connected pins - void pinMode(uint32_t pin, uint32_t mode) override { - if(pin == RADIOLIB_NC) { - return; - } - - gpioSetMode(pin, mode); - } - - void digitalWrite(uint32_t pin, uint32_t value) override { - if(pin == RADIOLIB_NC) { - return; - } - - gpioWrite(pin, value); - } - - uint32_t digitalRead(uint32_t pin) override { - if(pin == RADIOLIB_NC) { - return(0); - } - - return(gpioRead(pin)); - } - - void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { - if(interruptNum == RADIOLIB_NC) { - return; - } - - gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); - } - - void detachInterrupt(uint32_t interruptNum) override { - if(interruptNum == RADIOLIB_NC) { - return; - } - - gpioSetISRFunc(interruptNum, NULL, NULL, nullptr); - } - - void delay(unsigned long ms) override { - gpioDelay(ms * 1000); - } - - void delayMicroseconds(unsigned long us) override { - gpioDelay(us); - } - - unsigned long millis() override { - return(gpioTick() / 1000); - } - - unsigned long micros() override { - return(gpioTick()); - } - - long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { - if(pin == RADIOLIB_NC) { - return(0); - } - - gpioSetMode(pin, PI_INPUT); - uint32_t start = gpioTick(); - uint32_t curtick = gpioTick(); - - while(gpioRead(pin) == state) { - if((gpioTick() - curtick) > timeout) { - return(0); - } - } - - return(gpioTick() - start); - } - - void spiBegin() { - if(_spiHandle < 0) { - _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); - } - } - - void spiBeginTransaction() {} - - uint8_t spiTransfer(uint8_t b) { - char ret; - spiXfer(_spiHandle, (char*)&b, &ret, 1); - return(ret); - } - - void spiEndTransaction() {} - - void spiEnd() { - if(_spiHandle >= 0) { - spiClose(_spiHandle); - _spiHandle = -1; - } - } - - private: - // the HAL can contain any additional private members - const unsigned int _spiSpeed; - const uint8_t _spiChannel; - int _spiHandle = -1; -}; +// include the hardware abstraction layer +#include "PiHal.h" // create a new instance of the HAL class // use SPI channel 1, because on Waveshare LoRaWAN Hat, @@ -168,8 +25,6 @@ class PiHal : public RadioLibHal { PiHal* hal = new PiHal(1); // now we can create the radio module -// the first argument is a new instance of the HAL class defined above -// the others are pin numbers // pinout corresponds to the Waveshare LoRaWAN Hat // NSS pin: 7 // DIO1 pin: 17 @@ -199,12 +54,12 @@ int main(int argc, char** argv) { // wait for a second before transmitting again hal->delay(1000); - + } else { printf("failed, code %d\n", state); } - + } return(0); From 39948f613047eda6a6cfe45c78c67210e112f8c3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 6 May 2023 20:32:18 +0200 Subject: [PATCH 0560/1848] Added Rpi action --- .github/workflows/main.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0435fbf2cb..3ab16cf4f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -171,3 +171,27 @@ jobs: fi fi done + + rpi-build: + runs-on: [self-hosted, ARM64] + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y pigpio cmake + + - name: Install the library + run: | + cd $PWD + mkdir build + cd build + cmake .. + sudo make install + + - name: Build the example + run: | + cd $PWD/examples/NonArduino/RaspberryPi + ./build.sh From f96881700f22dc93ce7e015300512e091abd5203 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 6 May 2023 20:34:01 +0200 Subject: [PATCH 0561/1848] Fixed example path --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3ab16cf4f7..227b249468 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -193,5 +193,5 @@ jobs: - name: Build the example run: | - cd $PWD/examples/NonArduino/RaspberryPi + cd $PWD/examples/NonArduino/Raspberry ./build.sh From a797bef0d24176ebb08cdc5723337911566f8802 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 May 2023 07:17:47 +0100 Subject: [PATCH 0562/1848] Fixed term order for RPi example --- examples/NonArduino/Raspberry/PiHal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 7929138ee2..4c9c7bef16 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -36,12 +36,12 @@ class PiHal : public RadioLibHal { // stop the SPI spiEnd(); - // and now the pigpio library - gpioTerminate(); - - // finally, pull the enable pin low + // pull the enable pin low gpioSetMode(18, PI_OUTPUT); gpioWrite(18, PI_LOW); + + // finally, stop the pigpio library + gpioTerminate(); } // GPIO-related methods (pinMode, digitalWrite etc.) should check From 9ce25819425ceb4c18afe6d5ae6d14d182f1f8d2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 May 2023 08:19:14 +0200 Subject: [PATCH 0563/1848] Added CI autotest file --- extras/test/SX126x/.gitignore | 1 + extras/test/SX126x/CMakeLists.txt | 21 ++++ extras/test/SX126x/PiHal.h | 153 ++++++++++++++++++++++++++++++ extras/test/SX126x/build.sh | 8 ++ extras/test/SX126x/clean.sh | 3 + extras/test/SX126x/main.cpp | 21 ++++ 6 files changed, 207 insertions(+) create mode 100644 extras/test/SX126x/.gitignore create mode 100644 extras/test/SX126x/CMakeLists.txt create mode 100644 extras/test/SX126x/PiHal.h create mode 100644 extras/test/SX126x/build.sh create mode 100644 extras/test/SX126x/clean.sh create mode 100644 extras/test/SX126x/main.cpp diff --git a/extras/test/SX126x/.gitignore b/extras/test/SX126x/.gitignore new file mode 100644 index 0000000000..567609b123 --- /dev/null +++ b/extras/test/SX126x/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/extras/test/SX126x/CMakeLists.txt b/extras/test/SX126x/CMakeLists.txt new file mode 100644 index 0000000000..e708c0a3a0 --- /dev/null +++ b/extras/test/SX126x/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.18) + +# create the project +project(rpi-sx1261) + +# when using debuggers such as gdb, the following line can be used +#set(CMAKE_BUILD_TYPE Debug) + +# if you did not build RadioLib as shared library (see README), +# you will have to add it as source directory +# the following is just an example, yours will likely be different +#add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +# add the executable +add_executable(${PROJECT_NAME} main.cpp) + +# link both libraries +target_link_libraries(${PROJECT_NAME} RadioLib pigpio) + +# you can also specify RadioLib compile-time flags here +#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE) diff --git a/extras/test/SX126x/PiHal.h b/extras/test/SX126x/PiHal.h new file mode 100644 index 0000000000..4c9c7bef16 --- /dev/null +++ b/extras/test/SX126x/PiHal.h @@ -0,0 +1,153 @@ +#ifndef PI_HAL_H +#define PI_HAL_H + +// include RadioLib +#include + +// include the library for Raspberry GPIO pins +#include "pigpio.h" + +// create a new Raspberry Pi hardware abstraction layer +// using the pigpio library +// the HAL must inherit from the base RadioLibHal class +// and implement all of its virtual methods +class PiHal : public RadioLibHal { + public: + // default constructor - initializes the base HAL and any needed private members + PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) + : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), + _spiChannel(spiChannel), + _spiSpeed(spiSpeed) { + } + + void init() override { + // first initialise pigpio library + gpioInitialise(); + + // now the SPI + spiBegin(); + + // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_HIGH); + } + + void term() override { + // stop the SPI + spiEnd(); + + // pull the enable pin low + gpioSetMode(18, PI_OUTPUT); + gpioWrite(18, PI_LOW); + + // finally, stop the pigpio library + gpioTerminate(); + } + + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpioSetMode(pin, mode); + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpioWrite(pin, value); + } + + uint32_t digitalRead(uint32_t pin) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + return(gpioRead(pin)); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); + } + + void detachInterrupt(uint32_t interruptNum) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpioSetISRFunc(interruptNum, 0, 0, NULL); + } + + void delay(unsigned long ms) override { + gpioDelay(ms * 1000); + } + + void delayMicroseconds(unsigned long us) override { + gpioDelay(us); + } + + unsigned long millis() override { + return(gpioTick() / 1000); + } + + unsigned long micros() override { + return(gpioTick()); + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + gpioSetMode(pin, PI_INPUT); + uint32_t start = gpioTick(); + uint32_t curtick = gpioTick(); + + while(gpioRead(pin) == state) { + if((gpioTick() - curtick) > timeout) { + return(0); + } + } + + return(gpioTick() - start); + } + + void spiBegin() { + if(_spiHandle < 0) { + _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + } + } + + void spiBeginTransaction() {} + + uint8_t spiTransfer(uint8_t b) { + char ret; + spiXfer(_spiHandle, (char*)&b, &ret, 1); + return(ret); + } + + void spiEndTransaction() {} + + void spiEnd() { + if(_spiHandle >= 0) { + spiClose(_spiHandle); + _spiHandle = -1; + } + } + + private: + // the HAL can contain any additional private members + const unsigned int _spiSpeed; + const uint8_t _spiChannel; + int _spiHandle = -1; +}; + +#endif diff --git a/extras/test/SX126x/build.sh b/extras/test/SX126x/build.sh new file mode 100644 index 0000000000..a46bbdf4f8 --- /dev/null +++ b/extras/test/SX126x/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e +mkdir -p build +cd build +cmake -G "CodeBlocks - Unix Makefiles" .. +make -j4 +cd .. diff --git a/extras/test/SX126x/clean.sh b/extras/test/SX126x/clean.sh new file mode 100644 index 0000000000..27cfe2641d --- /dev/null +++ b/extras/test/SX126x/clean.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf ./build diff --git a/extras/test/SX126x/main.cpp b/extras/test/SX126x/main.cpp new file mode 100644 index 0000000000..2d15c9941d --- /dev/null +++ b/extras/test/SX126x/main.cpp @@ -0,0 +1,21 @@ +// this is an autotest file for the SX126x +// runs on Raspberry Pi with Waveshare LoRaWAN hat + +#include +#include "PiHal.h" + +PiHal* hal = new PiHal(1); +SX1261 radio = new Module(hal, 7, 17, 22, 4); + +// the entry point for the program +int main(int argc, char** argv) { + int state = RADIOLIB_ERR_UNKNOWN; + + state = radio.begin(); + printf("[SX1261] Test:begin() = %d\n", state); + + state = radio.transmit("Hello World!"); + printf("[SX1261] Test:transmit() = %d\n", state); + + return(0); +} From a00e5bb6af9df3967c3bd0b3a53f7a1dcc913cdd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 May 2023 08:20:31 +0200 Subject: [PATCH 0564/1848] [CI] Added autotest job --- .github/workflows/main.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 227b249468..f8ff3e5dd8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -195,3 +195,14 @@ jobs: run: | cd $PWD/examples/NonArduino/Raspberry ./build.sh + + rpi-test: + needs: rpi-build + runs-on: [self-hosted, ARM64] + steps: + - name: SX126x test + run: | + cd $PWD/extras/test/SX126x + ./clean.sh + ./build.sh + sudo ./build/rpi-sx1261 From 2a265251b179165101fd38933197d20799203f5b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 May 2023 07:23:25 +0100 Subject: [PATCH 0565/1848] Made test scripts executable --- extras/test/SX126x/build.sh | 0 extras/test/SX126x/clean.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 extras/test/SX126x/build.sh mode change 100644 => 100755 extras/test/SX126x/clean.sh diff --git a/extras/test/SX126x/build.sh b/extras/test/SX126x/build.sh old mode 100644 new mode 100755 diff --git a/extras/test/SX126x/clean.sh b/extras/test/SX126x/clean.sh old mode 100644 new mode 100755 From 54c1b309596f4e38e48c8b1827641a0d48edca81 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 May 2023 07:40:12 +0100 Subject: [PATCH 0566/1848] Added cleanup to test --- extras/test/SX126x/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extras/test/SX126x/main.cpp b/extras/test/SX126x/main.cpp index 2d15c9941d..40e8bfebd6 100644 --- a/extras/test/SX126x/main.cpp +++ b/extras/test/SX126x/main.cpp @@ -14,8 +14,9 @@ int main(int argc, char** argv) { state = radio.begin(); printf("[SX1261] Test:begin() = %d\n", state); - state = radio.transmit("Hello World!"); - printf("[SX1261] Test:transmit() = %d\n", state); + //state = radio.transmit("Hello World!"); + //printf("[SX1261] Test:transmit() = %d\n", state); + hal->term(); return(0); } From 0c40aa7f85950cb60c39cbea31d04e17a4fd7cab Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 8 May 2023 20:12:51 +0200 Subject: [PATCH 0567/1848] [Pager] Added note about module pin --- examples/Pager/Pager_Receive/Pager_Receive.ino | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino index f2ecb9aec7..c8368930e0 100644 --- a/examples/Pager/Pager_Receive/Pager_Receive.ino +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -31,7 +31,15 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// DIO2 pin: 5 +// receiving packets requires connection +// to the module direct output pin, +// here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +// SX126x/LLCC68: DIO2 const int pin = 5; // create Pager client instance using the FSK module From acc16c25bdfd09d8f62510f79f6c6c897ba3e449 Mon Sep 17 00:00:00 2001 From: Olocool17 <22843298+Olocool17@users.noreply.github.com> Date: Thu, 11 May 2023 20:47:19 +0200 Subject: [PATCH 0568/1848] [SX1272] Correct LoRa mode CRC register values --- src/modules/SX127x/SX1272.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 5ab4c1362b..5d5b27acbb 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -365,9 +365,9 @@ int16_t SX1272::setCRC(bool enable, bool mode) { // set LoRa CRC SX127x::crcEnabled = enable; if(enable) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_ON, 2, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_ON, 1, 1)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 2, 2)); + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 1, 1)); } } else { // set FSK CRC From 3b8218c3970a98a569d89b30f74705e25ce86df6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 May 2023 20:54:36 +0200 Subject: [PATCH 0569/1848] [CRC] Added common CRC --- src/RadioLib.h | 3 ++ src/utils/CRC.cpp | 39 ++++++++++++++++++++++++++ src/utils/CRC.h | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 src/utils/CRC.cpp create mode 100644 src/utils/CRC.h diff --git a/src/RadioLib.h b/src/RadioLib.h index f4e690a7a7..b8a363853d 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -110,6 +110,9 @@ #include "protocols/Print/Print.h" #include "protocols/BellModem/BellModem.h" +// utilities +#include "utils/CRC.h" + // only create Radio class when using RadioShield #if defined(RADIOLIB_RADIOSHIELD) diff --git a/src/utils/CRC.cpp b/src/utils/CRC.cpp new file mode 100644 index 0000000000..5001a48450 --- /dev/null +++ b/src/utils/CRC.cpp @@ -0,0 +1,39 @@ +#include "CRC.h" + +RadioLibCRC::RadioLibCRC(uint8_t size, uint32_t poly, uint32_t init, uint32_t out, bool refIn, bool refOut) { + this->size = size; + this->poly = poly; + this->init = init; + this->out = out; + this->refIn = refIn; + this->refOut = refOut; +} + +uint32_t RadioLibCRC::checksum(uint8_t* buff, size_t len) { + uint32_t crc = this->init; + for(size_t i = 0; i < len; i+=this->size/8) { + uint32_t window = 0; + for(uint8_t j = 0; j < this->size/8; j++) { + uint8_t inByte = buff[i + j]; + if(this->refIn) { + inByte = Module::reflect(inByte, 8); + } + window |= (inByte << ((this->size - 8) - 8*j)); + } + crc ^= window; + for(size_t k = 0; k < this->size; k++) { + if(crc & ((uint32_t)1 << (this->size - 1))) { + crc <<= (uint32_t)1; + crc ^= this->poly; + } else { + crc <<= (uint32_t)1; + } + } + } + crc ^= this->out; + if(this->refOut) { + crc = Module::reflect(crc, this->size); + } + crc &= (uint32_t)0xFFFFFFFF >> (32 - this->size); + return(crc); +} diff --git a/src/utils/CRC.h b/src/utils/CRC.h new file mode 100644 index 0000000000..bf2998dde7 --- /dev/null +++ b/src/utils/CRC.h @@ -0,0 +1,71 @@ +#if !defined(_RADIOLIB_CRC_H) +#define _RADIOLIB_CRC_H + +#include "../TypeDef.h" +#include "../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "../ArduinoHal.h" +#endif + +// CCITT CRC properties (used by AX.25) +#define RADIOLIB_CRC_CCITT_POLY (0x1021) +#define RADIOLIB_CRC_CCITT_INIT (0xFFFF) +#define RADIOLIB_CRC_CCITT_OUT (0xFFFF) + +/*! + \class AX25Frame + \brief Abstraction of AX.25 frame format. +*/ +class RadioLibCRC { + public: + /*! + \brief CRC size in bits. + */ + uint8_t size; + + /*! + \brief CRC polynomial. + */ + uint32_t poly; + + /*! + \brief Initial value. + */ + uint32_t init; + + /*! + \brief Final XOR value. + */ + uint32_t out; + + /*! + \brief Whether to reflect input bytes. + */ + bool refIn; + + /*! + \brief Whether to reflect the result. + */ + bool refOut; + + /*! + \brief Default constructor. + \param size CRC size in bits. + \param poly CRC polynomial. + \param init Initial value. + \param out Final XOR value. + \param refIn Whether to reflect input bytes. + \param refOut Whether to reflect the result. + */ + RadioLibCRC(uint8_t size, uint32_t poly, uint32_t init, uint32_t out, bool refIn, bool refOut); + + /*! + \brief Calcualte checksum of a buffer. + \param buff Buffer to calculate the checksum over. + \param len Size of the buffer in bytes. + \returns The resulting checksum. + */ + uint32_t checksum(uint8_t* buff, size_t len); +}; + +#endif From 03d2a9bf265e70e06c8b43af53cd02a626207161 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 May 2023 20:55:51 +0200 Subject: [PATCH 0570/1848] [MOD] Added common reflect method --- src/Module.cpp | 19 ++++++------------- src/Module.h | 10 ++++------ src/protocols/AX25/AX25.cpp | 2 +- src/protocols/Pager/Pager.cpp | 10 +++++----- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 +- 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 8346d3fc86..c4d72df834 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -372,19 +372,12 @@ void Module::waitForMicroseconds(uint32_t start, uint32_t len) { #endif } -uint8_t Module::flipBits(uint8_t b) { - b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; - b = (b & 0xCC) >> 2 | (b & 0x33) << 2; - b = (b & 0xAA) >> 1 | (b & 0x55) << 1; - return b; -} - -uint16_t Module::flipBits16(uint16_t i) { - i = (i & 0xFF00) >> 8 | (i & 0x00FF) << 8; - i = (i & 0xF0F0) >> 4 | (i & 0x0F0F) << 4; - i = (i & 0xCCCC) >> 2 | (i & 0x3333) << 2; - i = (i & 0xAAAA) >> 1 | (i & 0x5555) << 1; - return i; +uint32_t Module::reflect(uint32_t in, uint8_t bits) { + uint32_t res = 0; + for(uint8_t i = 0; i < bits; i++) { + res |= (((in & ((uint32_t)1 << i)) >> i) << (bits - i - 1)); + } + return(res); } void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { diff --git a/src/Module.h b/src/Module.h index b240653e67..7c5216d56b 100644 --- a/src/Module.h +++ b/src/Module.h @@ -462,13 +462,11 @@ class Module { /*! \brief Function to reflect bits within a byte. + \param in The input to reflect. + \param bits Number of bits to reflect. + \return The reflected input. */ - static uint8_t flipBits(uint8_t b); - - /*! - \brief Function to reflect bits within an integer. - */ - static uint16_t flipBits16(uint16_t i); + static uint32_t reflect(uint32_t in, uint8_t bits); /*! \brief Function to dump data as hex into the debug port. diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 53b4018c2d..62db834aa5 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -303,7 +303,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // flip bit order for(size_t i = 0; i < frameBuffLen; i++) { - frameBuff[i] = Module::flipBits(frameBuff[i]); + frameBuff[i] = Module::reflect(frameBuff[i], 8); } // calculate FCS diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 04b906ab62..006f5e81ac 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -160,7 +160,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t // first insert the remainder from previous code word (if any) if(remBits > 0) { // this doesn't apply to BCD messages, so no need to check that here - uint8_t prev = Module::flipBits(data[dataPos - 1]); + uint8_t prev = Module::reflect(data[dataPos - 1], 8); prev >>= 1; msg[blockPos] |= (uint32_t)prev << (RADIOLIB_PAGER_CODE_WORD_LEN - 1 - remBits); } @@ -174,7 +174,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t if(encoding == RADIOLIB_PAGER_BCD) { symbol = encodeBCD(symbol); } - symbol = Module::flipBits(symbol); + symbol = Module::reflect(symbol, 8); symbol >>= (8 - symbolLength); // insert the next message symbol @@ -188,7 +188,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t uint8_t numSteps = (symbolPos - RADIOLIB_PAGER_FUNC_BITS_POS + symbolLength)/symbolLength; for(uint8_t i = 0; i < numSteps; i++) { symbol = encodeBCD(' '); - symbol = Module::flipBits(symbol); + symbol = Module::reflect(symbol, 8); symbol >>= (8 - symbolLength); msg[blockPos] |= (uint32_t)symbol << symbolPos; symbolPos -= symbolLength; @@ -397,7 +397,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { uint32_t symbol = prevSymbol << (symbolLength - ovfBits) | currSymbol; // finally, we can flip the bits - symbol = Module::flipBits((uint8_t)symbol); + symbol = Module::reflect((uint8_t)symbol, 8); symbol >>= (8 - symbolLength); // decode BCD and we're done @@ -415,7 +415,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { while(bitPos >= RADIOLIB_PAGER_MESSAGE_END_POS) { // get the message symbol from the code word and reverse bits uint32_t symbol = (cw & (0x7FUL << bitPos)) >> bitPos; - symbol = Module::flipBits((uint8_t)symbol); + symbol = Module::reflect((uint8_t)symbol, 8); symbol >>= (8 - symbolLength); // decode BCD if needed diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index dce1e13318..eee43ca66f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -367,7 +367,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check complete byte if(this->bufferBitPos == 8) { - this->buffer[this->bufferWritePos] = Module::flipBits(this->buffer[this->bufferWritePos]); + this->buffer[this->bufferWritePos] = Module::reflect(this->buffer[this->bufferWritePos], 8); RADIOLIB_VERBOSE_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); this->bufferWritePos++; From 32a5166ae36efe866e396c1dd82f7f834ed88592 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 May 2023 20:56:23 +0200 Subject: [PATCH 0571/1848] [Bell] Added missing exclude guard --- src/protocols/BellModem/BellModem.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h index d16c44d91c..13ab710641 100644 --- a/src/protocols/BellModem/BellModem.h +++ b/src/protocols/BellModem/BellModem.h @@ -7,6 +7,8 @@ #include "../../ArduinoHal.h" #endif +#if !defined(RADIOLIB_EXCLUDE_BELL) + #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" #include "../Print/Print.h" @@ -125,3 +127,5 @@ class BellClient: public AFSKClient, public RadioLibPrint { }; #endif + +#endif From efd449875df4240f22a593e0d2d4d6b16f5d48bc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 May 2023 20:57:15 +0200 Subject: [PATCH 0572/1848] [AX.25] Use common CRC implementation --- src/protocols/AX25/AX25.cpp | 28 +++------------------------- src/protocols/AX25/AX25.h | 9 +-------- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 62db834aa5..0e8f55aeef 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -306,8 +306,9 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { frameBuff[i] = Module::reflect(frameBuff[i], 8); } - // calculate FCS - uint16_t fcs = getFrameCheckSequence(frameBuff, frameBuffLen); + // calculate + RadioLibCRC crc(16, RADIOLIB_CRC_CCITT_POLY, RADIOLIB_CRC_CCITT_INIT, RADIOLIB_CRC_CCITT_OUT, false, false); + uint16_t fcs = crc.checksum(frameBuff, frameBuffLen); *(frameBuffPtr++) = (uint8_t)((fcs >> 8) & 0xFF); *(frameBuffPtr++) = (uint8_t)(fcs & 0xFF); @@ -436,27 +437,4 @@ uint8_t AX25Client::getSSID() { return(sourceSSID); } -/* - CCITT CRC implementation based on https://github.com/kicksat/ax25 - - Licensed under Creative Commons Attribution-ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -*/ -uint16_t AX25Client::getFrameCheckSequence(uint8_t* buff, size_t len) { - uint8_t outBit; - uint16_t mask; - uint16_t shiftReg = CRC_CCITT_INIT; - - for(size_t i = 0; i < len; i++) { - for(uint8_t b = 0x80; b > 0x00; b /= 2) { - outBit = (shiftReg & 0x01) ? 0x01 : 0x00; - shiftReg >>= 1; - mask = XOR((buff[i] & b), outBit) ? CRC_CCITT_POLY_REVERSED : 0x0000; - shiftReg ^= mask; - } - } - - return(Module::flipBits16(~shiftReg)); -} - #endif diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 05399e601a..9d6c60a63c 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -8,6 +8,7 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" #include "../BellModem/BellModem.h" +#include "../../utils/CRC.h" // macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html #define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) @@ -15,12 +16,6 @@ #define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) #define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) -// CRC-CCITT calculation macros -#define XOR(A, B) ( ((A) || (B)) && !((A) && (B)) ) -#define CRC_CCITT_POLY 0x1021 // generator polynomial -#define CRC_CCITT_POLY_REVERSED 0x8408 // CRC_CCITT_POLY in reversed bit order -#define CRC_CCITT_INIT 0xFFFF // initial value - // maximum callsign length in bytes #define RADIOLIB_AX25_MAX_CALLSIGN_LEN 6 @@ -322,8 +317,6 @@ class AX25Client { uint8_t sourceSSID = 0; uint16_t preambleLen = 0; - static uint16_t getFrameCheckSequence(uint8_t* buff, size_t len); - void getCallsign(char* buff); uint8_t getSSID(); }; From 8062a322c604c4caabfac3560c225bb06f0da78c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 May 2023 21:08:43 +0200 Subject: [PATCH 0573/1848] [CRC] Convert into singleton --- src/protocols/AX25/AX25.cpp | 11 ++++++++--- src/utils/CRC.cpp | 11 ++++------- src/utils/CRC.h | 11 ++++------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 0e8f55aeef..e7470b5f33 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -306,9 +306,14 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { frameBuff[i] = Module::reflect(frameBuff[i], 8); } - // calculate - RadioLibCRC crc(16, RADIOLIB_CRC_CCITT_POLY, RADIOLIB_CRC_CCITT_INIT, RADIOLIB_CRC_CCITT_OUT, false, false); - uint16_t fcs = crc.checksum(frameBuff, frameBuffLen); + // calculate + RadioLibCRCInstance.size = 16; + RadioLibCRCInstance.poly = RADIOLIB_CRC_CCITT_POLY; + RadioLibCRCInstance.init = RADIOLIB_CRC_CCITT_INIT; + RadioLibCRCInstance.out = RADIOLIB_CRC_CCITT_OUT; + RadioLibCRCInstance.refIn = false; + RadioLibCRCInstance.refOut = false; + uint16_t fcs = RadioLibCRCInstance.checksum(frameBuff, frameBuffLen); *(frameBuffPtr++) = (uint8_t)((fcs >> 8) & 0xFF); *(frameBuffPtr++) = (uint8_t)(fcs & 0xFF); diff --git a/src/utils/CRC.cpp b/src/utils/CRC.cpp index 5001a48450..f6cbfa23a8 100644 --- a/src/utils/CRC.cpp +++ b/src/utils/CRC.cpp @@ -1,12 +1,7 @@ #include "CRC.h" -RadioLibCRC::RadioLibCRC(uint8_t size, uint32_t poly, uint32_t init, uint32_t out, bool refIn, bool refOut) { - this->size = size; - this->poly = poly; - this->init = init; - this->out = out; - this->refIn = refIn; - this->refOut = refOut; +RadioLibCRC::RadioLibCRC() { + } uint32_t RadioLibCRC::checksum(uint8_t* buff, size_t len) { @@ -37,3 +32,5 @@ uint32_t RadioLibCRC::checksum(uint8_t* buff, size_t len) { crc &= (uint32_t)0xFFFFFFFF >> (32 - this->size); return(crc); } + +RadioLibCRC RadioLibCRCInstance; diff --git a/src/utils/CRC.h b/src/utils/CRC.h index bf2998dde7..d34cbeebe4 100644 --- a/src/utils/CRC.h +++ b/src/utils/CRC.h @@ -50,14 +50,8 @@ class RadioLibCRC { /*! \brief Default constructor. - \param size CRC size in bits. - \param poly CRC polynomial. - \param init Initial value. - \param out Final XOR value. - \param refIn Whether to reflect input bytes. - \param refOut Whether to reflect the result. */ - RadioLibCRC(uint8_t size, uint32_t poly, uint32_t init, uint32_t out, bool refIn, bool refOut); + RadioLibCRC(); /*! \brief Calcualte checksum of a buffer. @@ -68,4 +62,7 @@ class RadioLibCRC { uint32_t checksum(uint8_t* buff, size_t len); }; +// the global singleton +extern RadioLibCRC RadioLibCRCInstance; + #endif From acf683b91b4d9e9e6f3df00ed24f053a903a18bf Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 13 May 2023 16:40:01 +0200 Subject: [PATCH 0574/1848] [CRC] Reworked for non-standard CRC lengths --- src/utils/CRC.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/utils/CRC.cpp b/src/utils/CRC.cpp index f6cbfa23a8..4422942b05 100644 --- a/src/utils/CRC.cpp +++ b/src/utils/CRC.cpp @@ -6,25 +6,24 @@ RadioLibCRC::RadioLibCRC() { uint32_t RadioLibCRC::checksum(uint8_t* buff, size_t len) { uint32_t crc = this->init; - for(size_t i = 0; i < len; i+=this->size/8) { - uint32_t window = 0; - for(uint8_t j = 0; j < this->size/8; j++) { - uint8_t inByte = buff[i + j]; + size_t pos = 0; + for(size_t i = 0; i < 8*len; i++) { + if(i % 8 == 0) { + uint32_t in = buff[pos++]; if(this->refIn) { - inByte = Module::reflect(inByte, 8); + in = Module::reflect(in, 8); } - window |= (inByte << ((this->size - 8) - 8*j)); + crc ^= (in << (this->size - 8)); } - crc ^= window; - for(size_t k = 0; k < this->size; k++) { - if(crc & ((uint32_t)1 << (this->size - 1))) { - crc <<= (uint32_t)1; - crc ^= this->poly; - } else { - crc <<= (uint32_t)1; - } + + if(crc & ((uint32_t)1 << (this->size - 1))) { + crc <<= (uint32_t)1; + crc ^= this->poly; + } else { + crc <<= (uint32_t)1; } } + crc ^= this->out; if(this->refOut) { crc = Module::reflect(crc, this->size); From c2b9e195515f36776317b258dbe98c130d109633 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 15 May 2023 20:34:19 +0200 Subject: [PATCH 0575/1848] Removed dependency on algorithm (#748) --- src/BuildOpt.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4128d3354f..0e58322179 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -314,11 +314,15 @@ #define OCT 8 #define BIN 2 - #include #include - using std::max; - using std::min; + #if !defined(min) + #define min(a,b) ((a)<(b)?(a):(b)) + #endif + + #if !defined(max) + #define max(a,b) ((a)>(b)?(a):(b)) + #endif #endif /* From 1a5522002068be01e398fb4433808fa580760b06 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 16 May 2023 17:12:45 +0100 Subject: [PATCH 0576/1848] Updated non-Arduino example --- examples/NonArduino/Raspberry/CMakeLists.txt | 4 ++-- examples/NonArduino/Raspberry/PiHal.h | 2 +- examples/NonArduino/Raspberry/build.sh | 2 +- examples/NonArduino/Raspberry/main.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/NonArduino/Raspberry/CMakeLists.txt b/examples/NonArduino/Raspberry/CMakeLists.txt index e708c0a3a0..79feff1266 100644 --- a/examples/NonArduino/Raspberry/CMakeLists.txt +++ b/examples/NonArduino/Raspberry/CMakeLists.txt @@ -6,10 +6,10 @@ project(rpi-sx1261) # when using debuggers such as gdb, the following line can be used #set(CMAKE_BUILD_TYPE Debug) -# if you did not build RadioLib as shared library (see README), +# if you did not build RadioLib as shared library (see wiki), # you will have to add it as source directory # the following is just an example, yours will likely be different -#add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") # add the executable add_executable(${PROJECT_NAME} main.cpp) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 4c9c7bef16..83991f7853 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -2,7 +2,7 @@ #define PI_HAL_H // include RadioLib -#include +#include // include the library for Raspberry GPIO pins #include "pigpio.h" diff --git a/examples/NonArduino/Raspberry/build.sh b/examples/NonArduino/Raspberry/build.sh index a46bbdf4f8..5d55b66e33 100755 --- a/examples/NonArduino/Raspberry/build.sh +++ b/examples/NonArduino/Raspberry/build.sh @@ -4,5 +4,5 @@ set -e mkdir -p build cd build cmake -G "CodeBlocks - Unix Makefiles" .. -make -j4 +make cd .. diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index ec28a312e3..5e57c98321 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -14,7 +14,7 @@ */ // include the library -#include +#include // include the hardware abstraction layer #include "PiHal.h" From efbec6b9d13057a3d2df4bae9d0af3062fe70716 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 16 May 2023 17:13:43 +0100 Subject: [PATCH 0577/1848] Added custom min/max/abs macros --- src/BuildOpt.h | 13 +++++-------- src/modules/CC1101/CC1101.cpp | 8 ++++---- src/modules/SX126x/SX126x.cpp | 2 +- src/modules/SX127x/SX127x.cpp | 2 +- src/modules/SX128x/SX128x.cpp | 2 +- src/protocols/APRS/APRS.cpp | 4 ++-- 6 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 0e58322179..db8184c7b0 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -316,13 +316,6 @@ #include - #if !defined(min) - #define min(a,b) ((a)<(b)?(a):(b)) - #endif - - #if !defined(max) - #define max(a,b) ((a)>(b)?(a):(b)) - #endif #endif /* @@ -458,7 +451,6 @@ */ #define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } } - /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled */ @@ -474,6 +466,11 @@ #define RADIOLIB_ERRATA_SX127X(...) {} #endif +// these macros are usually defined by Arduino, but some platforms undef them, so its safer to use our own +#define RADIOLIB_MIN(a,b) ((a)<(b)?(a):(b)) +#define RADIOLIB_MAX(a,b) ((a)>(b)?(a):(b)) +#define RADIOLIB_ABS(x) ((x)>0?(x):-(x)) + // version definitions #define RADIOLIB_VERSION_MAJOR (0x06) #define RADIOLIB_VERSION_MINOR (0x00) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index b7b4f4bd58..2472101706 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -302,11 +302,11 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { /*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, RADIOLIB_CC1101_FIFO_THRESH_TX); } else { - uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); + uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); dataSent += initialWrite; }*/ - uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); + uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); dataSent += initialWrite; @@ -327,7 +327,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // if there's room then put other data if (bytesInFIFO < RADIOLIB_CC1101_FIFO_SIZE) { - uint8_t bytesToWrite = min((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent)); + uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, &data[dataSent], bytesToWrite); dataSent += bytesToWrite; } else { @@ -429,7 +429,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { } // read the minimum between "remaining length" and bytesInFifo - uint8_t bytesToRead = min((uint8_t)(length - readBytes), bytesInFIFO); + uint8_t bytesToRead = RADIOLIB_MIN((uint8_t)(length - readBytes), bytesInFIFO); SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, bytesToRead, &(data[readBytes])); readBytes += bytesToRead; lastPop = this->mod->hal->millis(); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 79212eee84..e46dc66ece 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -605,7 +605,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ // We need to ensure that the timeout is longer than senderPreambleLength. // So we must satisfy: wakePeriod > (preamblePeriod - (sleepPeriod - 1000)) / 2. (A) // we also need to ensure the unit is awake to see at least minSymbols. (B) - uint32_t wakePeriod = max( + uint32_t wakePeriod = RADIOLIB_MAX( (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) symbolLength * (minSymbols + 1)); //(B) RADIOLIB_DEBUG_PRINTLN("Auto wake period: ", wakePeriod); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 4abac65227..ccae2f27d9 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1156,7 +1156,7 @@ uint32_t SX127x::getTimeOnAir(size_t len) { // Get number of bits preamble float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); // Get number of bits payload - float n_pay = 8.0 + max(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); + float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); // Get time-on-air in us return ceil(symbolLength * (n_pre + n_pay + 4.25)) * 1000; diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a964383491..bd27231131 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1242,7 +1242,7 @@ uint32_t SX128x::getTimeOnAir(size_t len) { uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(max((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); } else { // long interleaving - abandon hope all ye who enter here diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 6a9db01534..8ae93e8c0b 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -100,7 +100,7 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp // as discussed in https://github.com/jgromes/RadioLib/issues/430 // latitude first, because that is in the destination field - float lat_abs = abs(lat); + float lat_abs = RADIOLIB_ABS(lat); int lat_deg = (int)lat_abs; int lat_min = (lat_abs - (float)lat_deg) * 60.0f; int lat_hun = (((lat_abs - (float)lat_deg) * 60.0f) - lat_min) * 100.0f; @@ -133,7 +133,7 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp info[infoPos++] = RADIOLIB_APRS_MIC_E_GPS_DATA_CURRENT; // encode the longtitude - float lon_abs = abs(lon); + float lon_abs = RADIOLIB_ABS(lon); int32_t lon_deg = (int32_t)lon_abs; int32_t lon_min = (lon_abs - (float)lon_deg) * 60.0f; int32_t lon_hun = (((lon_abs - (float)lon_deg) * 60.0f) - lon_min) * 100.0f; From 6d54ea65db520829b5e6206e43d5201ff63dacfe Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 May 2023 20:49:37 +0100 Subject: [PATCH 0578/1848] [MOD] Added option to use SX126x without GPIO --- src/Module.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index c4d72df834..ddf8116dfb 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -246,12 +246,16 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint #endif // ensure GPIO is low - uint32_t start = this->hal->millis(); - while(this->hal->digitalRead(this->gpioPin)) { - this->hal->yield(); - if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?"); - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + if(this->gpioPin == RADIOLIB_NC) { + this->hal->delay(1); + } else { + uint32_t start = this->hal->millis(); + while(this->hal->digitalRead(this->gpioPin)) { + this->hal->yield(); + if(this->hal->millis() - start >= timeout) { + RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?"); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } } } @@ -312,13 +316,17 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // wait for GPIO to go high and then low if(waitForGpio) { - this->hal->delayMicroseconds(1); - uint32_t start = this->hal->millis(); - while(this->hal->digitalRead(this->gpioPin)) { - this->hal->yield(); - if(this->hal->millis() - start >= timeout) { - state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; - break; + if(this->gpioPin == RADIOLIB_NC) { + this->hal->delay(1); + } else { + this->hal->delayMicroseconds(1); + uint32_t start = this->hal->millis(); + while(this->hal->digitalRead(this->gpioPin)) { + this->hal->yield(); + if(this->hal->millis() - start >= timeout) { + state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; + break; + } } } } From b02a5c1867094d9256ecbd66744912da34c113d1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 May 2023 20:52:28 +0100 Subject: [PATCH 0579/1848] Updated raspberry example --- examples/NonArduino/Raspberry/PiHal.h | 12 ++++++------ examples/NonArduino/Raspberry/main.cpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 83991f7853..5a94fe8d2a 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -107,17 +107,17 @@ class PiHal : public RadioLibHal { return(0); } - gpioSetMode(pin, PI_INPUT); - uint32_t start = gpioTick(); - uint32_t curtick = gpioTick(); + this->pinMode(pin, PI_INPUT); + uint32_t start = this->micros(); + uint32_t curtick = this->micros(); - while(gpioRead(pin) == state) { - if((gpioTick() - curtick) > timeout) { + while(this->digitalRead(pin) == state) { + if((this->micros() - curtick) > timeout) { return(0); } } - return(gpioTick() - start); + return(this->micros() - start); } void spiBegin() { diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index 5e57c98321..54ae3850a2 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -29,8 +29,8 @@ PiHal* hal = new PiHal(1); // NSS pin: 7 // DIO1 pin: 17 // NRST pin: 22 -// BUSY pin: 4 -SX1261 radio = new Module(hal, 7, 17, 22, 4); +// BUSY pin: not connected +SX1261 radio = new Module(hal, 7, 17, 22, RADIOLIB_NC); // the entry point for the program int main(int argc, char** argv) { @@ -50,7 +50,7 @@ int main(int argc, char** argv) { state = radio.transmit("Hello World!"); if(state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted - printf("success!"); + printf("success!\n"); // wait for a second before transmitting again hal->delay(1000); From a97baa6fc2a32dc44c93e7ce5d451d111e9b7376 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 May 2023 21:57:24 +0200 Subject: [PATCH 0580/1848] [CI] Updated SX1261 autotest --- extras/test/SX126x/PiHal.h | 14 +++++++------- extras/test/SX126x/main.cpp | 10 +++++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/extras/test/SX126x/PiHal.h b/extras/test/SX126x/PiHal.h index 4c9c7bef16..5a94fe8d2a 100644 --- a/extras/test/SX126x/PiHal.h +++ b/extras/test/SX126x/PiHal.h @@ -2,7 +2,7 @@ #define PI_HAL_H // include RadioLib -#include +#include // include the library for Raspberry GPIO pins #include "pigpio.h" @@ -107,17 +107,17 @@ class PiHal : public RadioLibHal { return(0); } - gpioSetMode(pin, PI_INPUT); - uint32_t start = gpioTick(); - uint32_t curtick = gpioTick(); + this->pinMode(pin, PI_INPUT); + uint32_t start = this->micros(); + uint32_t curtick = this->micros(); - while(gpioRead(pin) == state) { - if((gpioTick() - curtick) > timeout) { + while(this->digitalRead(pin) == state) { + if((this->micros() - curtick) > timeout) { return(0); } } - return(gpioTick() - start); + return(this->micros() - start); } void spiBegin() { diff --git a/extras/test/SX126x/main.cpp b/extras/test/SX126x/main.cpp index 40e8bfebd6..4b88d4438c 100644 --- a/extras/test/SX126x/main.cpp +++ b/extras/test/SX126x/main.cpp @@ -4,8 +4,10 @@ #include #include "PiHal.h" +#define RADIOLIB_TEST_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(-1*(STATEVAR)); } } + PiHal* hal = new PiHal(1); -SX1261 radio = new Module(hal, 7, 17, 22, 4); +SX1261 radio = new Module(hal, 7, 17, 22, RADIOLIB_NC); // the entry point for the program int main(int argc, char** argv) { @@ -13,9 +15,11 @@ int main(int argc, char** argv) { state = radio.begin(); printf("[SX1261] Test:begin() = %d\n", state); + RADIOLIB_TEST_ASSERT(state); - //state = radio.transmit("Hello World!"); - //printf("[SX1261] Test:transmit() = %d\n", state); + state = radio.transmit("Hello World!"); + printf("[SX1261] Test:transmit() = %d\n", state); + RADIOLIB_TEST_ASSERT(state); hal->term(); return(0); From 397bd9ab042ef3fb49c7d0e70bf6e962d8d2c22d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 May 2023 21:59:45 +0200 Subject: [PATCH 0581/1848] [CI] Fix lib include path --- extras/test/SX126x/PiHal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/test/SX126x/PiHal.h b/extras/test/SX126x/PiHal.h index 5a94fe8d2a..e8c27db03e 100644 --- a/extras/test/SX126x/PiHal.h +++ b/extras/test/SX126x/PiHal.h @@ -2,7 +2,7 @@ #define PI_HAL_H // include RadioLib -#include +#include // include the library for Raspberry GPIO pins #include "pigpio.h" From 4e2ff97afc4c395a731e9623ceeb8b956ffc0647 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:24:18 +0200 Subject: [PATCH 0582/1848] Added ESP-IDF example (#748) --- examples/NonArduino/ESP-IDF/CMakeLists.txt | 7 + .../components/RadioLib/CMakeLists.txt | 10 + .../NonArduino/ESP-IDF/main/CMakeLists.txt | 4 + examples/NonArduino/ESP-IDF/main/EspHal.h | 316 ++++ examples/NonArduino/ESP-IDF/main/main.cpp | 67 + examples/NonArduino/ESP-IDF/sdkconfig | 1669 +++++++++++++++++ 6 files changed, 2073 insertions(+) create mode 100644 examples/NonArduino/ESP-IDF/CMakeLists.txt create mode 100644 examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt create mode 100644 examples/NonArduino/ESP-IDF/main/CMakeLists.txt create mode 100644 examples/NonArduino/ESP-IDF/main/EspHal.h create mode 100644 examples/NonArduino/ESP-IDF/main/main.cpp create mode 100644 examples/NonArduino/ESP-IDF/sdkconfig diff --git a/examples/NonArduino/ESP-IDF/CMakeLists.txt b/examples/NonArduino/ESP-IDF/CMakeLists.txt new file mode 100644 index 0000000000..a726278da6 --- /dev/null +++ b/examples/NonArduino/ESP-IDF/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.16) + +# include the top-level cmake +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# name the project something nice +project(esp-sx1261) diff --git a/examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt b/examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt new file mode 100644 index 0000000000..6adf691b09 --- /dev/null +++ b/examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt @@ -0,0 +1,10 @@ +# this is required for ESP IDF +idf_component_register() + +# if you did not build RadioLib as shared library (see wiki), +# you will have to add it as source directory +# the following is just an example, yours will likely be different +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +# link RadioLib as interface +target_link_libraries(${COMPONENT_LIB} INTERFACE RadioLib) diff --git a/examples/NonArduino/ESP-IDF/main/CMakeLists.txt b/examples/NonArduino/ESP-IDF/main/CMakeLists.txt new file mode 100644 index 0000000000..52e0183312 --- /dev/null +++ b/examples/NonArduino/ESP-IDF/main/CMakeLists.txt @@ -0,0 +1,4 @@ +# register the component and set "RadioLib", "esp_timer" and "driver" ad required +idf_component_register(SRCS "main.cpp" + INCLUDE_DIRS "." + REQUIRES RadioLib esp_timer driver) diff --git a/examples/NonArduino/ESP-IDF/main/EspHal.h b/examples/NonArduino/ESP-IDF/main/EspHal.h new file mode 100644 index 0000000000..a4f64d1cfa --- /dev/null +++ b/examples/NonArduino/ESP-IDF/main/EspHal.h @@ -0,0 +1,316 @@ +#ifndef ESP_HAL_H +#define ESP_HAL_H + +// include RadioLib +#include + +// this example only works on ESP32 and is unlikely to work on ESP32S2/S3 etc. +// if you need high portability, you should probably use Arduino anyway ... +#if CONFIG_IDF_TARGET_ESP32 == 0 + #error Target is not ESP32! +#endif + +// include all the dependencies +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp32/rom/gpio.h" +#include "soc/rtc.h" +#include "soc/dport_reg.h" +#include "soc/spi_reg.h" +#include "soc/spi_struct.h" +#include "driver/gpio.h" +#include "hal/gpio_hal.h" +#include "esp_timer.h" +#include "esp_log.h" + +// define Arduino-style macros +#define LOW (0x0) +#define HIGH (0x1) +#define INPUT (0x01) +#define OUTPUT (0x03) +#define RISING (0x01) +#define FALLING (0x02) +#define NOP() asm volatile ("nop") + +#define MATRIX_DETACH_OUT_SIG (0x100) +#define MATRIX_DETACH_IN_LOW_PIN (0x30) + +// all of the following is needed to calculate SPI clock divider +#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1))) + +typedef union { + uint32_t value; + struct { + uint32_t clkcnt_l: 6; + uint32_t clkcnt_h: 6; + uint32_t clkcnt_n: 6; + uint32_t clkdiv_pre: 13; + uint32_t clk_equ_sysclk: 1; + }; +} spiClk_t; + +uint32_t getApbFrequency() { + rtc_cpu_freq_config_t conf; + rtc_clk_cpu_freq_get_config(&conf); + + if(conf.freq_mhz >= 80) { + return(80 * MHZ); + } + + return((conf.source_freq_mhz * MHZ) / conf.div); +} + +uint32_t spiFrequencyToClockDiv(uint32_t freq) { + uint32_t apb_freq = getApbFrequency(); + if(freq >= apb_freq) { + return SPI_CLK_EQU_SYSCLK; + } + + const spiClk_t minFreqReg = { 0x7FFFF000 }; + uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); + if(freq < minFreq) { + return minFreqReg.value; + } + + uint8_t calN = 1; + spiClk_t bestReg = { 0 }; + int32_t bestFreq = 0; + while(calN <= 0x3F) { + spiClk_t reg = { 0 }; + int32_t calFreq; + int32_t calPre; + int8_t calPreVari = -2; + + reg.clkcnt_n = calN; + + while(calPreVari++ <= 1) { + calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; + if(calPre > 0x1FFF) { + reg.clkdiv_pre = 0x1FFF; + } else if(calPre <= 0) { + reg.clkdiv_pre = 0; + } else { + reg.clkdiv_pre = calPre; + } + reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2); + calFreq = ClkRegToFreq(®); + if(calFreq == (int32_t) freq) { + memcpy(&bestReg, ®, sizeof(bestReg)); + break; + } else if(calFreq < (int32_t) freq) { + if(RADIOLIB_ABS(freq - calFreq) < RADIOLIB_ABS(freq - bestFreq)) { + bestFreq = calFreq; + memcpy(&bestReg, ®, sizeof(bestReg)); + } + } + } + if(calFreq == (int32_t) freq) { + break; + } + calN++; + } + return(bestReg.value); +} + +// create a new ESP-IDF hardware abstraction layer +// the HAL must inherit from the base RadioLibHal class +// and implement all of its virtual methods +// this is pretty much just copied from Arduino ESP32 core +class EspHal : public RadioLibHal { + public: + // default constructor - initializes the base HAL and any needed private members + EspHal(int8_t sck, int8_t miso, int8_t mosi) + : RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), + spiSCK(sck), spiMISO(miso), spiMOSI(mosi) { + } + + void init() override { + // we only need to init the SPI here + spiBegin(); + } + + void term() override { + // we only need to stop the SPI here + spiEnd(); + } + + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpio_hal_context_t gpiohal; + gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); + + gpio_config_t conf = { + .pin_bit_mask = (1ULL<pin[pin].int_type, + }; + gpio_config(&conf); + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if(pin == RADIOLIB_NC) { + return; + } + + gpio_set_level((gpio_num_t)pin, value); + } + + uint32_t digitalRead(uint32_t pin) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + return(gpio_get_level((gpio_num_t)pin)); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM); + gpio_set_intr_type((gpio_num_t)interruptNum, (gpio_int_type_t)(mode & 0x7)); + + // this uses function typecasting, which is not defined when the functions have different signatures + // untested and might not work + gpio_isr_handler_add((gpio_num_t)interruptNum, (void (*)(void*))interruptCb, NULL); + } + + void detachInterrupt(uint32_t interruptNum) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + gpio_isr_handler_remove((gpio_num_t)interruptNum); + gpio_wakeup_disable((gpio_num_t)interruptNum); + gpio_set_intr_type((gpio_num_t)interruptNum, GPIO_INTR_DISABLE); + } + + void delay(unsigned long ms) override { + vTaskDelay(ms / portTICK_PERIOD_MS); + } + + void delayMicroseconds(unsigned long us) override { + uint64_t m = (uint64_t)esp_timer_get_time(); + if(us) { + uint64_t e = (m + us); + if(m > e) { // overflow + while((uint64_t)esp_timer_get_time() > e) { + NOP(); + } + } + while((uint64_t)esp_timer_get_time() < e) { + NOP(); + } + } + } + + unsigned long millis() override { + return((unsigned long)(esp_timer_get_time() / 1000ULL)); + } + + unsigned long micros() override { + return((unsigned long)(esp_timer_get_time())); + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if(pin == RADIOLIB_NC) { + return(0); + } + + this->pinMode(pin, INPUT); + uint32_t start = this->micros(); + uint32_t curtick = this->micros(); + + while(this->digitalRead(pin) == state) { + if((this->micros() - curtick) > timeout) { + return(0); + } + } + + return(this->micros() - start); + } + + void spiBegin() { + // enable peripheral + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); + + // reset the control struct + this->spi->slave.trans_done = 0; + this->spi->slave.val = 0; + this->spi->pin.val = 0; + this->spi->user.val = 0; + this->spi->user1.val = 0; + this->spi->ctrl.val = 0; + this->spi->ctrl1.val = 0; + this->spi->ctrl2.val = 0; + this->spi->clock.val = 0; + this->spi->user.usr_mosi = 1; + this->spi->user.usr_miso = 1; + this->spi->user.doutdin = 1; + for(uint8_t i = 0; i < 16; i++) { + this->spi->data_buf[i] = 0x00000000; + } + + // set SPI mode 0 + this->spi->pin.ck_idle_edge = 0; + this->spi->user.ck_out_edge = 0; + + // set bit order to MSB first + this->spi->ctrl.wr_bit_order = 0; + this->spi->ctrl.rd_bit_order = 0; + + // set the clock + this->spi->clock.val = spiFrequencyToClockDiv(2000000); + + // initialize pins + this->pinMode(this->spiSCK, OUTPUT); + this->pinMode(this->spiMISO, INPUT); + this->pinMode(this->spiMOSI, OUTPUT); + gpio_matrix_out(this->spiSCK, HSPICLK_OUT_IDX, false, false); + gpio_matrix_in(this->spiMISO, HSPIQ_OUT_IDX, false); + gpio_matrix_out(this->spiMOSI, HSPID_IN_IDX, false, false); + } + + void spiBeginTransaction() { + // not needed - in ESP32 Arduino core, this function + // repeats clock div, mode and bit order configuration + } + + uint8_t spiTransfer(uint8_t b) { + this->spi->mosi_dlen.usr_mosi_dbitlen = 7; + this->spi->miso_dlen.usr_miso_dbitlen = 7; + this->spi->data_buf[0] = b; + this->spi->cmd.usr = 1; + while(this->spi->cmd.usr); + return(this->spi->data_buf[0] & 0xFF); + } + + void spiEndTransaction() { + // nothing needs to be done here + } + + void spiEnd() { + // detach pins + gpio_matrix_out(this->spiSCK, MATRIX_DETACH_OUT_SIG, false, false); + gpio_matrix_in(this->spiMISO, MATRIX_DETACH_IN_LOW_PIN, false); + gpio_matrix_out(this->spiMOSI, MATRIX_DETACH_OUT_SIG, false, false); + } + + private: + // the HAL can contain any additional private members + int8_t spiSCK; + int8_t spiMISO; + int8_t spiMOSI; + spi_dev_t * spi = (volatile spi_dev_t *)(DR_REG_SPI2_BASE); +}; + +#endif diff --git a/examples/NonArduino/ESP-IDF/main/main.cpp b/examples/NonArduino/ESP-IDF/main/main.cpp new file mode 100644 index 0000000000..9a2272b6ed --- /dev/null +++ b/examples/NonArduino/ESP-IDF/main/main.cpp @@ -0,0 +1,67 @@ +/* + RadioLib Non-Arduino ESP-IDF Example + + This example shows how to use RadioLib without Arduino. + In this case, a Liligo T-BEAM (ESP32 and SX1276) + is used. + + Can be used as a starting point to port RadioLib to any platform! + See this API reference page for details on the RadioLib hardware abstraction + https://jgromes.github.io/RadioLib/class_hal.html + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// include the hardware abstraction layer +#include "EspHal.h" + +// create a new instance of the HAL class +EspHal* hal = new EspHal(5, 19, 27); + +// now we can create the radio module +// NSS pin: 18 +// DIO0 pin: 26 +// NRST pin: 14 +// DIO1 pin: 33 +SX1276 radio = new Module(hal, 18, 26, 14, 33); + +static const char *TAG = "main"; + +// the entry point for the program +// it must be declared as "extern C" because the compiler assumes this will be a C function +extern "C" void app_main(void) { + // initialize just like with Arduino + ESP_LOGI(TAG, "[SX1276] Initializing ... "); + int state = radio.begin(); + if (state != RADIOLIB_ERR_NONE) { + ESP_LOGI(TAG, "failed, code %d\n", state); + while(true) { + hal->delay(1000); + } + } + ESP_LOGI(TAG, "success!\n"); + + // loop forever + for(;;) { + // send a packet + ESP_LOGI(TAG, "[SX1276] Transmitting packet ... "); + state = radio.transmit("Hello World!"); + if(state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + ESP_LOGI(TAG, "success!"); + + } else { + ESP_LOGI(TAG, "failed, code %d\n", state); + + } + + // wait for a second before transmitting again + hal->delay(1000); + + } + +} diff --git a/examples/NonArduino/ESP-IDF/sdkconfig b/examples/NonArduino/ESP-IDF/sdkconfig new file mode 100644 index 0000000000..ea8d75690c --- /dev/null +++ b/examples/NonArduino/ESP-IDF/sdkconfig @@ -0,0 +1,1669 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Configuration +# +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" +CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" +CONFIG_SOC_DPORT_WORKAROUND="Not determined" +CONFIG_SOC_CAPS_ECO_VER_MAX=301 +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DAC_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_SDMMC_HOST_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_EMAC_SUPPORTED=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y +CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5 +CONFIG_SOC_XTAL_SUPPORT_26M=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_XTAL_SUPPORT_AUTO_DETECT=y +CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=2 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2 +CONFIG_SOC_ADC_PATT_LEN_MAX=16 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=2 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=2 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=20 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_RTC_SLOW_CLOCK_SUPPORT_8MD256=y +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=5 +CONFIG_SOC_CPU_CORES_NUM=2 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FPU=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINT_SIZE=64 +CONFIG_SOC_DAC_PERIPH_NUM=2 +CONFIG_SOC_DAC_RESOLUTION=8 +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=40 +CONFIG_SOC_GPIO_VALID_GPIO_MASK=0xFFFFFFFFFF +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_APB=y +CONFIG_SOC_CLK_APLL_SUPPORTED=y +CONFIG_SOC_APLL_MULTIPLIER_OUT_MIN_HZ=350000000 +CONFIG_SOC_APLL_MULTIPLIER_OUT_MAX_HZ=500000000 +CONFIG_SOC_APLL_MIN_HZ=5303031 +CONFIG_SOC_APLL_MAX_HZ=125000000 +CONFIG_SOC_I2S_NUM=2 +CONFIG_SOC_I2S_HW_VERSION_1=y +CONFIG_SOC_I2S_SUPPORTS_APLL=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y +CONFIG_SOC_I2S_SUPPORTS_ADC=y +CONFIG_SOC_I2S_SUPPORTS_DAC=y +CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y +CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y +CONFIG_SOC_I2S_LCD_I80_VARIANT=y +CONFIG_SOC_LCD_I80_SUPPORTED=y +CONFIG_SOC_LCD_I80_BUSES=2 +CONFIG_SOC_LCD_I80_BUS_WIDTH=24 +CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y +CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y +CONFIG_SOC_LEDC_CHANNEL_NUM=8 +CONFIG_SOC_LEDC_TIMER_BIT_WIDE_NUM=20 +CONFIG_SOC_MCPWM_GROUPS=2 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=8 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=64 +CONFIG_SOC_RMT_SUPPORT_REF_TICK=y +CONFIG_SOC_RMT_SUPPORT_APB=y +CONFIG_SOC_RMT_CHANNEL_CLK_INDEPENDENT=y +CONFIG_SOC_RTCIO_PIN_COUNT=18 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8 +CONFIG_SOC_SPI_HD_BOTH_INOUT_SUPPORTED=y +CONFIG_SOC_SPI_AS_CS_SUPPORTED=y +CONFIG_SOC_SPI_PERIPH_NUM=3 +CONFIG_SOC_SPI_DMA_CHAN_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=3 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=8192 +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 +CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y +CONFIG_SOC_TOUCH_VERSION_1=y +CONFIG_SOC_TOUCH_SENSOR_NUM=10 +CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +CONFIG_SOC_UART_SUPPORT_REF_TICK=y +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_SPIRAM_SUPPORTED=y +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SHA_SUPPORT_SHA384=y +CONFIG_SOC_SHA_SUPPORT_SHA512=y +CONFIG_SOC_RSA_MAX_BIT_LEN=4096 +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_192=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_SECURE_BOOT_V1=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_FAST_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_SLOW_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_SDMMC_USE_IOMUX=y +CONFIG_SOC_SDMMC_NUM_SLOTS=2 +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_BT_CLASSIC_SUPPORTED=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET_ARCH="xtensa" +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# end of Build type + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 +# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V1_SUPPORTED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_40M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="40m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# Driver Configurations +# + +# +# Legacy ADC Configuration +# +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y +CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CAL_LUT_ENABLE=y +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Configuration + +# +# SPI Configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI Configuration + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y +CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y +CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y +CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y +CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y +# end of TWAI Configuration + +# +# UART Configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART Configuration + +# +# GPIO Configuration +# +# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of GPIO Configuration + +# +# Sigma Delta Modulator Configuration +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of Sigma Delta Modulator Configuration + +# +# GPTimer Configuration +# +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of GPTimer Configuration + +# +# PCNT Configuration +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of PCNT Configuration + +# +# RMT Configuration +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of RMT Configuration + +# +# MCPWM Configuration +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of MCPWM Configuration + +# +# I2S Configuration +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of I2S Configuration +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set +CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set +CONFIG_EFUSE_MAX_BLK_LEN=192 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set + +# +# ADC Calibration Configurations +# +CONFIG_ADC_CALI_EFUSE_TP_ENABLE=y +CONFIG_ADC_CALI_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CALI_LUT_ENABLE=y +# end of ADC Calibration Configurations + +CONFIG_ADC_DISABLE_DAC_OUTPUT=y +# end of ADC and ADC Calibration + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_ESP32_EMAC=y +CONFIG_ETH_PHY_INTERFACE_RMII=y +CONFIG_ETH_RMII_CLK_INPUT=y +# CONFIG_ETH_RMII_CLK_OUTPUT is not set +CONFIG_ETH_RMII_CLK_IN_GPIO=0 +CONFIG_ETH_DMA_BUFFER_SIZE=512 +CONFIG_ETH_DMA_RX_BUFFER_NUM=10 +CONFIG_ETH_DMA_TX_BUFFER_NUM=10 +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32_REV_MIN_0=y +# CONFIG_ESP32_REV_MIN_1 is not set +# CONFIG_ESP32_REV_MIN_1_1 is not set +# CONFIG_ESP32_REV_MIN_2 is not set +# CONFIG_ESP32_REV_MIN_3 is not set +# CONFIG_ESP32_REV_MIN_3_1 is not set +CONFIG_ESP32_REV_MIN=0 +CONFIG_ESP32_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32 Revision (Rev v3.99) +# +CONFIG_ESP32_REV_MAX_FULL=399 +CONFIG_ESP_REV_MAX_FULL=399 +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000 +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +# CONFIG_PERIPH_CTRL_FUNC_IN_IRAM is not set +# end of Peripheral Control + +# +# Main XTAL Config +# +# CONFIG_XTAL_FREQ_26 is not set +CONFIG_XTAL_FREQ_40=y +# CONFIG_XTAL_FREQ_AUTO is not set +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config +# end of Hardware Settings + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# end of ESP NETIF Adapter + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +CONFIG_ESP_PHY_REDUCE_TX_POWER=y +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +# end of Power Management + +# +# ESP PSRAM +# +# CONFIG_SPIRAM is not set +# end of ESP PSRAM + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 + +# +# Memory +# +# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set +# end of Memory + +# +# Trace memory +# +# CONFIG_ESP32_TRAX is not set +CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 +# end of Trace memory + +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +# CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 is not set +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=0 +# end of Brownout Detector + +# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_TG0_LAC=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +# CONFIG_FATFS_SECTOR_512 is not set +# CONFIG_FATFS_SECTOR_1024 is not set +# CONFIG_FATFS_SECTOR_2048 is not set +CONFIG_FATFS_SECTOR_4096=y +CONFIG_FATFS_SECTORS_PER_CLUSTER_1=y +# CONFIG_FATFS_SECTORS_PER_CLUSTER_2 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_4 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_8 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_16 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_32 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_64 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_128 is not set +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_AUTO_TYPE=y +# CONFIG_FATFS_FAT12 is not set +# CONFIG_FATFS_FAT16 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_HZ=1000 +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +# CONFIG_FREERTOS_FPU_IN_ISR is not set +CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y +CONFIG_FREERTOS_CORETIMER_0=y +# CONFIG_FREERTOS_CORETIMER_1 is not set +CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# end of Port + +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=3 +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 +CONFIG_LWIP_TCP_WND_DEFAULT=5744 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +# CONFIG_LWIP_TCP_SACK_OUT is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# CONFIG_MBEDTLS_CMAC_C is not set +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Root Hub configuration +# +# end of Root Hub configuration + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# end of Supplicant +# end of Component config + +# Deprecated options for backward compatibility +# CONFIG_NO_BLOBS is not set +# CONFIG_ESP32_NO_BLOBS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_ADC2_DISABLE_DAC=y +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set +CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y +CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y +CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y +# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set +# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set +# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set +CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 +# CONFIG_ESP32_XTAL_FREQ_26 is not set +CONFIG_ESP32_XTAL_FREQ_40=y +# CONFIG_ESP32_XTAL_FREQ_AUTO is not set +CONFIG_ESP32_XTAL_FREQ=40 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +CONFIG_REDUCE_PHY_TX_POWER=y +CONFIG_ESP32_REDUCE_PHY_TX_POWER=y +# CONFIG_SPIRAM_SUPPORT is not set +# CONFIG_ESP32_SPIRAM_SUPPORT is not set +# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y +# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32_PANIC_PRINT_HALT is not set +CONFIG_ESP32_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32_PANIC_GDBSTUB is not set +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32_DEBUG_OCDAWARE=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_0=y +CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_BROWNOUT_DET_LVL=0 +CONFIG_ESP32_BROWNOUT_DET_LVL=0 +# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5744 +CONFIG_TCP_WND_DEFAULT=5744 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_HRT is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_ESP32_ULP_COPROC_ENABLED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options From 642f1bb1579a95ca7cee47805607bf7b67fbc5f2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:24:31 +0200 Subject: [PATCH 0583/1848] [MOD] Added missing newlines --- src/Module.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index ddf8116dfb..329bdd49d4 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -88,10 +88,10 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t RADIOLIB_DEBUG_PRINTLN(); RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg); RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb); - RADIOLIB_DEBUG_PRINT("value:\t\t0x%X", value); - RADIOLIB_DEBUG_PRINT("current:\t0x%X", currentValue); - RADIOLIB_DEBUG_PRINT("mask:\t\t0x%X", mask); - RADIOLIB_DEBUG_PRINT("new:\t\t0x%X", newValue); + RADIOLIB_DEBUG_PRINTLN("value:\t\t0x%X", value); + RADIOLIB_DEBUG_PRINTLN("current:\t0x%X", currentValue); + RADIOLIB_DEBUG_PRINTLN("mask:\t\t0x%X", mask); + RADIOLIB_DEBUG_PRINTLN("new:\t\t0x%X", newValue); RADIOLIB_DEBUG_PRINTLN("read:\t\t0x%X", readValue); return(RADIOLIB_ERR_SPI_WRITE_FAILED); From bb17b3dff289080abed0b5e67a7db128fcb5001c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:25:07 +0200 Subject: [PATCH 0584/1848] [Si443x] Fixed long prints --- src/modules/Si443x/Si443x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index c38e5b9fa4..6498518acb 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -754,7 +754,7 @@ int16_t Si443x::updateClockRecovery() { // print that whole mess RADIOLIB_DEBUG_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); - RADIOLIB_DEBUG_PRINTLN("%f\t%d\t%X\n%d\t%X\n%d\t%X", rxOsr, rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); + RADIOLIB_DEBUG_PRINTLN("%f\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr, rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); // update oversampling ratio int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); From 5158ac5b6b007cdeb7fcf0e05b1e1b10b8207f22 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:26:03 +0200 Subject: [PATCH 0585/1848] [SX126x] Fixed long prints --- src/modules/SX126x/SX126x.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e46dc66ece..9d0c1aec2d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -247,7 +247,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); + RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -296,7 +296,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); + RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); @@ -608,7 +608,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t wakePeriod = RADIOLIB_MAX( (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) symbolLength * (minSymbols + 1)); //(B) - RADIOLIB_DEBUG_PRINTLN("Auto wake period: ", wakePeriod); + RADIOLIB_DEBUG_PRINTLN("Auto wake period: %lu", wakePeriod); // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < this->tcxoDelay + 1016) { @@ -1458,7 +1458,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) #if defined(RADIOLIB_DEBUG) char ver_pre[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); - RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %d", ver_pre); + RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %s", ver_pre); #endif // enable patch update @@ -1490,7 +1490,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) #if defined(RADIOLIB_DEBUG) char ver_post[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); - RADIOLIB_DEBUG_PRINTLN("Post-update version string: %d", ver_post); + RADIOLIB_DEBUG_PRINTLN("Post-update version string: %s", ver_post); #endif return(state); @@ -1770,7 +1770,7 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - RADIOLIB_DEBUG_PRINTLN("Symbol length: %d ms", symbolLength); + RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; } else { From c93d6eff65c7127148645e7d126743eee11d0508 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:26:16 +0200 Subject: [PATCH 0586/1848] [SX128x] Fixed long prints --- src/modules/SX128x/SX128x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index bd27231131..522160900a 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -312,7 +312,7 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (500% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 5; - RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); + RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -345,7 +345,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // calculate timeout (1000% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 10; - RADIOLIB_DEBUG_PRINTLN("Timeout in %d us", timeout); + RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); From a5edb9b1e624460d69bdc2445f1060b0c2de96da Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:26:23 +0200 Subject: [PATCH 0587/1848] [Morse] Fixed long prints --- src/protocols/Morse/Morse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 1f1c3c7018..e2a80cf612 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -104,7 +104,7 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); (*len)++; } else { - RADIOLIB_DEBUG_PRINTLN("", signalLen); + RADIOLIB_DEBUG_PRINTLN("", signalLen); } } From bb4a45e850df98bd282218e40ec43798c8643283 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:26:46 +0200 Subject: [PATCH 0588/1848] [Pager] Fixed long prints --- src/protocols/Pager/Pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 006f5e81ac..fafade1f0b 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -498,7 +498,7 @@ uint32_t PagerClient::read() { codeWord = ~codeWord; } - RADIOLIB_VERBOSE_PRINTLN("R\t%X", codeWord); + RADIOLIB_VERBOSE_PRINTLN("R\t%lX", codeWord); // TODO BCH error correction here return(codeWord); } From 3968e611af3bd0302c0e05bb74f9a6f118779d42 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 May 2023 18:26:59 +0200 Subject: [PATCH 0589/1848] [PHY] Fixed long prints --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index eee43ca66f..77adf4778d 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -275,7 +275,6 @@ int32_t PhysicalLayer::random(int32_t max) { if(randNum < 0) { randNum *= -1; } - RADIOLIB_DEBUG_PRINTLN("%d", randNum); return(randNum % max); } @@ -347,7 +346,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { this->syncBuffer <<= 1; this->syncBuffer |= bit; - RADIOLIB_VERBOSE_PRINTLN("S\t%X", this->syncBuffer); + RADIOLIB_VERBOSE_PRINTLN("S\t%lu", this->syncBuffer); if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) { this->gotSync = true; From 551c6fd304ada349629ad6f9e4bb2314c650cc97 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 23 May 2023 22:41:32 +0200 Subject: [PATCH 0590/1848] [CRC] Fixed incorrect doxygen class name --- src/utils/CRC.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/CRC.h b/src/utils/CRC.h index d34cbeebe4..bc711e8aa1 100644 --- a/src/utils/CRC.h +++ b/src/utils/CRC.h @@ -13,8 +13,8 @@ #define RADIOLIB_CRC_CCITT_OUT (0xFFFF) /*! - \class AX25Frame - \brief Abstraction of AX.25 frame format. + \class RadioLibCRC + \brief Class to calculate CRCs of varying formats. */ class RadioLibCRC { public: From 191db8b5ffc62f0c4482bb606cd5042b8d0ef561 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 23 May 2023 22:41:53 +0200 Subject: [PATCH 0591/1848] [FEC] Added FEC class --- src/utils/FEC.cpp | 252 ++++++++++++++++++++++++++++++++++++++++++++++ src/utils/FEC.h | 57 +++++++++++ 2 files changed, 309 insertions(+) create mode 100644 src/utils/FEC.cpp create mode 100644 src/utils/FEC.h diff --git a/src/utils/FEC.cpp b/src/utils/FEC.cpp new file mode 100644 index 0000000000..d08f9426fa --- /dev/null +++ b/src/utils/FEC.cpp @@ -0,0 +1,252 @@ +#include "FEC.h" +#include + +RadioLibBCH::RadioLibBCH() { + +} + +/* + BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder + + Significantly cleaned up and slightly fixed. +*/ +void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { + this->n = n; + this->k = k; + this->poly = poly; + this->alphaTo = new int32_t[n + 1]; + this->indexOf = new int32_t[n + 1]; + this->generator = new int32_t[n - k + 1]; + + // find the maximum power of the polynomial + for(this->m = 0; this->m < 31; this->m++) { + if((poly >> this->m) == 1) { + break; + } + } + + /* + * generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] + * lookup tables: index->polynomial form this->alphaTo[] contains j=alpha**i; + * polynomial form -> index form this->indexOf[j=alpha**i] = i alpha=2 is the + * primitive element of GF(2**m) + */ + + int32_t mask = 1; + this->alphaTo[this->m] = 0; + + for(uint8_t i = 0; i < this->m; i++) { + this->alphaTo[i] = mask; + + this->indexOf[this->alphaTo[i]] = i; + + if(this->poly & ((uint32_t)0x01 << i)) { + this->alphaTo[this->m] ^= mask; + } + + mask <<= 1; + } + + this->indexOf[this->alphaTo[this->m]] = this->m; + mask >>= 1; + + for(uint8_t i = this->m + 1; i < this->n; i++) { + if(this->alphaTo[i - 1] >= mask) { + this->alphaTo[i] = this->alphaTo[this->m] ^ ((this->alphaTo[i - 1] ^ mask) << 1); + } else { + this->alphaTo[i] = this->alphaTo[i - 1] << 1; + } + + this->indexOf[this->alphaTo[i]] = i; + } + + this->indexOf[0] = -1; + + /* + * Compute generator polynomial of BCH code of length = 31, redundancy = 10 + * (OK, this is not very efficient, but we only do it once, right? :) + */ + + int32_t ii = 0; + int32_t jj = 1; + int32_t ll = 0; + int32_t kaux = 0; + bool test = false; + int32_t aux = 0; + int32_t cycle[15][6] = { { 0 } }; + int32_t size[15] = { 0 }; + + // Generate cycle sets modulo 31 + cycle[0][0] = 0; size[0] = 1; + cycle[1][0] = 1; size[1] = 1; + + do { + // Generate the jj-th cycle set + ii = 0; + do { + ii++; + cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % this->n; + size[jj]++; + aux = (cycle[jj][ii] * 2) % this->n; + } while(aux != cycle[jj][0]); + + // Next cycle set representative + ll = 0; + do { + ll++; + test = false; + for(ii = 1; ((ii <= jj) && !test); ii++) { + // Examine previous cycle sets + for(kaux = 0; ((kaux < size[ii]) && !test); kaux++) { + test = (ll == cycle[ii][kaux]); + } + } + } while(test && (ll < (this->n - 1))); + + if(!test) { + jj++; // next cycle set index + cycle[jj][0] = ll; + size[jj] = 1; + } + + } while(ll < (this->n - 1)); + + // Search for roots 1, 2, ..., m-1 in cycle sets + int32_t rdncy = 0; + int32_t* min = new int32_t[this->n - this->k + 1]; + kaux = 0; + + for(ii = 1; ii <= jj; ii++) { + min[kaux] = 0; + for(jj = 0; jj < size[ii]; jj++) { + for(uint8_t root = 1; root < this->m; root++) { + if(root == cycle[ii][jj]) { + min[kaux] = ii; + } + } + } + + if(min[kaux]) { + rdncy += size[min[kaux]]; + kaux++; + } + } + + int32_t noterms = kaux; + int32_t* zeros = new int32_t[this->n - this->k + 1]; + kaux = 1; + + for(ii = 0; ii < noterms; ii++) { + for(jj = 0; jj < size[min[ii]]; jj++) { + zeros[kaux] = cycle[min[ii]][jj]; + kaux++; + } + } + + delete[] min; + + // Compute generator polynomial + this->generator[0] = this->alphaTo[zeros[1]]; + this->generator[1] = 1; // g(x) = (X + zeros[1]) initially + + for(ii = 2; ii <= rdncy; ii++) { + this->generator[ii] = 1; + for(jj = ii - 1; jj > 0; jj--) { + if(this->generator[jj] != 0) { + this->generator[jj] = this->generator[jj - 1] ^ this->alphaTo[(this->indexOf[this->generator[jj]] + zeros[ii]) % this->n]; + } else { + this->generator[jj] = this->generator[jj - 1]; + } + } + this->generator[0] = this->alphaTo[(this->indexOf[this->generator[0]] + zeros[ii]) % this->n]; + } + + delete[] zeros; +} + +/* + BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder + + Significantly cleaned up and slightly fixed. +*/ +uint32_t RadioLibBCH::encode(uint32_t dataword) { + // we only use the "k" most significant bits + int32_t* data = new int32_t[this->k]; + int32_t j1 = 0; + for(int32_t i = this->n; i > (this->n - this->k); i--) { + if(dataword & ((uint32_t)1<n]; + memset(Mr, 0x00, this->n*sizeof(int32_t)); + + // copy the contents of data into Mr and add the zeros + memcpy(Mr, data, this->k*sizeof(int32_t)); + + int32_t j = 0; + int32_t start = 0; + int32_t end = this->n - this->k; + while(end < this->n) { + for(int32_t i = end; i > start-2; --i) { + if(Mr[start]) { + Mr[i] ^= this->generator[j]; + ++j; + } else { + ++start; + j = 0; + end = start + this->n - this->k; + break; + } + } + } + + int32_t* bb = new int32_t[this->n - this->k + 1]; + j = 0; + for(int32_t i = start; i < end; ++i) { + bb[j] = Mr[i]; + ++j; + } + delete[] Mr; + + int32_t iEvenParity = 0; + int32_t* recd = new int32_t[this->n + 1]; + for(uint8_t i = 0; i < this->k; i++) { + recd[this->n - i] = data[i]; + if(data[i] == 1) { + iEvenParity++; + } + } + + delete[] data; + + for(uint8_t i = 0; i < this->n - this->k + 1; i++) { + recd[this->n - this->k - i] = bb[i]; + if(bb[i] == 1) { + iEvenParity++; + } + } + + delete[] bb; + + if((iEvenParity % 2) == 0) { + recd[0] = 0; + } else { + recd[0] = 1; + } + + int32_t res = 0; + for(int32_t i = 0; i < this->n + 1; i++) { + if(recd[i]) { + res |= ((uint32_t)1< Date: Tue, 23 May 2023 22:44:44 +0200 Subject: [PATCH 0592/1848] [Pager] Use FEC util --- src/protocols/Pager/Pager.cpp | 230 +--------------------------------- src/protocols/Pager/Pager.h | 18 +-- 2 files changed, 4 insertions(+), 244 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index fafade1f0b..b7dd00bbbd 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -44,7 +44,7 @@ int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shi inv = invert; // initialize BCH encoder - encoderInit(); + RadioLibBCHInstance.begin(RADIOLIB_PAGER_BCH_N, RADIOLIB_PAGER_BCH_K, RADIOLIB_PAGER_BCH_PRIMITIVE_POLY); // configure for direct mode return(phyLayer->startDirect()); @@ -139,7 +139,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t } // write address code word - msg[RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos] = encodeBCH(frameAddr); + msg[RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos] = RadioLibBCHInstance.encode(frameAddr); // write the data as 20-bit code blocks if(len > 0) { @@ -205,7 +205,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t remBits = RADIOLIB_PAGER_FUNC_BITS_POS - symbolPos - symbolLength; // do the FEC - msg[blockPos] = encodeBCH(msg[blockPos]); + msg[blockPos] = RadioLibBCHInstance.encode(msg[blockPos]); } } @@ -540,228 +540,4 @@ char PagerClient::decodeBCD(uint8_t b) { return(b + '0'); } -/* - BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder - - Significantly cleaned up and slightly fixed. -*/ -void PagerClient::encoderInit() { - /* - * generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] - * lookup tables: index->polynomial form bchAlphaTo[] contains j=alpha**i; - * polynomial form -> index form bchIndexOf[j=alpha**i] = i alpha=2 is the - * primitive element of GF(2**m) - */ - - int32_t mask = 1; - bchAlphaTo[RADIOLIB_PAGER_BCH_M] = 0; - - for(uint8_t i = 0; i < RADIOLIB_PAGER_BCH_M; i++) { - bchAlphaTo[i] = mask; - - bchIndexOf[bchAlphaTo[i]] = i; - - if(RADIOLIB_PAGER_BCH_PRIMITIVE_POLY & ((uint32_t)0x01 << i)) { - bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^= mask; - } - - mask <<= 1; - } - - bchIndexOf[bchAlphaTo[RADIOLIB_PAGER_BCH_M]] = RADIOLIB_PAGER_BCH_M; - mask >>= 1; - - for(uint8_t i = RADIOLIB_PAGER_BCH_M + 1; i < RADIOLIB_PAGER_BCH_N; i++) { - if(bchAlphaTo[i - 1] >= mask) { - bchAlphaTo[i] = bchAlphaTo[RADIOLIB_PAGER_BCH_M] ^ ((bchAlphaTo[i - 1] ^ mask) << 1); - } else { - bchAlphaTo[i] = bchAlphaTo[i - 1] << 1; - } - - bchIndexOf[bchAlphaTo[i]] = i; - } - - bchIndexOf[0] = -1; - - /* - * Compute generator polynomial of BCH code of length = 31, redundancy = 10 - * (OK, this is not very efficient, but we only do it once, right? :) - */ - - int32_t ii = 0; - int32_t jj = 1; - int32_t ll = 0; - int32_t kaux = 0; - bool test = false; - int32_t aux = 0; - int32_t cycle[15][6] = { { 0 } }; - int32_t size[15] = { 0 }; - - // Generate cycle sets modulo 31 - cycle[0][0] = 0; size[0] = 1; - cycle[1][0] = 1; size[1] = 1; - - do { - // Generate the jj-th cycle set - ii = 0; - do { - ii++; - cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % RADIOLIB_PAGER_BCH_N; - size[jj]++; - aux = (cycle[jj][ii] * 2) % RADIOLIB_PAGER_BCH_N; - } while(aux != cycle[jj][0]); - - // Next cycle set representative - ll = 0; - do { - ll++; - test = false; - for(ii = 1; ((ii <= jj) && !test); ii++) { - // Examine previous cycle sets - for(kaux = 0; ((kaux < size[ii]) && !test); kaux++) { - test = (ll == cycle[ii][kaux]); - } - } - } while(test && (ll < (RADIOLIB_PAGER_BCH_N - 1))); - - if(!test) { - jj++; // next cycle set index - cycle[jj][0] = ll; - size[jj] = 1; - } - - } while(ll < (RADIOLIB_PAGER_BCH_N - 1)); - - // Search for roots 1, 2, ..., d-1 in cycle sets - int32_t rdncy = 0; - int32_t min[11]; - kaux = 0; - - for(ii = 1; ii <= jj; ii++) { - min[kaux] = 0; - for(jj = 0; jj < size[ii]; jj++) { - for(uint8_t root = 1; root < RADIOLIB_PAGER_BCH_D; root++) { - if(root == cycle[ii][jj]) { - min[kaux] = ii; - } - } - } - - if(min[kaux]) { - rdncy += size[min[kaux]]; - kaux++; - } - } - - int32_t noterms = kaux; - int32_t zeros[11]; - kaux = 1; - - for(ii = 0; ii < noterms; ii++) { - for(jj = 0; jj < size[min[ii]]; jj++) { - zeros[kaux] = cycle[min[ii]][jj]; - kaux++; - } - } - - // Compute generator polynomial - bchG[0] = bchAlphaTo[zeros[1]]; - bchG[1] = 1; // g(x) = (X + zeros[1]) initially - - for(ii = 2; ii <= rdncy; ii++) { - bchG[ii] = 1; - for(jj = ii - 1; jj > 0; jj--) { - if(bchG[jj] != 0) { - bchG[jj] = bchG[jj - 1] ^ bchAlphaTo[(bchIndexOf[bchG[jj]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; - } else { - bchG[jj] = bchG[jj - 1]; - } - } - bchG[0] = bchAlphaTo[(bchIndexOf[bchG[0]] + zeros[ii]) % RADIOLIB_PAGER_BCH_N]; - } -} - -/* - BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder - - Significantly cleaned up and slightly fixed. -*/ -uint32_t PagerClient::encodeBCH(uint32_t dat) { - // we only use the 21 most significant bits - int32_t data[21]; - int32_t j1 = 0; - for(int32_t i = 31; i > 10; i--) { - if(dat & ((uint32_t)1< start-2; --i) { - if(Mr[start]) { - Mr[i] ^= bchG[j]; - ++j; - } else { - ++start; - j = 0; - end = start + RADIOLIB_PAGER_BCH_N - RADIOLIB_PAGER_BCH_K; - break; - } - } - } - - int32_t bb[11]; - j = 0; - for(int32_t i = start; i < end; ++i) { - bb[j] = Mr[i]; - ++j; - } - - int32_t iEvenParity = 0; - int32_t recd[32]; - for(uint8_t i = 0; i < 21; i++) { - recd[31 - i] = data[i]; - if(data[i] == 1) { - iEvenParity++; - } - } - - for(uint8_t i = 0; i < 11; i++) { - recd[10 - i] = bb[i]; - if(bb[i] == 1) { - iEvenParity++; - } - } - - if((iEvenParity % 2) == 0) { - recd[0] = 0; - } else { - recd[0] = 1; - } - - int32_t Codeword[32]; - memcpy(Codeword, recd, sizeof(int32_t)*32); - - int32_t iResult = 0; - for(int32_t i = 0; i < 32; i++) { - if(Codeword[i]) { - iResult |= ((uint32_t)1< Date: Sun, 28 May 2023 22:13:51 +0200 Subject: [PATCH 0593/1848] [SX127x] Fixed missing debug newline --- src/modules/SX127x/SX1278.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index a1b92c0d3f..ec5266ad68 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -185,7 +185,7 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; - RADIOLIB_DEBUG_PRINT("Symbol length: %f ms", symbolLength); + RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { From f936d53639f2e10d9177bd0f4deece69dcfc9c8d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:19:03 +0200 Subject: [PATCH 0594/1848] [SX128x] Added default startReceive method --- src/modules/SX128x/SX128x.cpp | 4 ++++ src/modules/SX128x/SX128x.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 522160900a..783b3f512c 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -548,6 +548,10 @@ int16_t SX128x::finishTransmit() { return(standby()); } +int16_t SX128x::startReceive() { + return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT, RADIOLIB_SX128X_IRQ_RX_DONE, 0)); +} + int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { (void)len; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 6b8f64673c..beb0080cef 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -510,6 +510,14 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + + \returns \ref status_codes + */ + int16_t startReceive(); /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. From a16322097a1742c291ff91663782e86b740e8576 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:20:25 +0200 Subject: [PATCH 0595/1848] [SX127x] Added default startReceive method --- src/modules/SX127x/SX127x.cpp | 4 ++++ src/modules/SX127x/SX127x.h | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index ccae2f27d9..9b8202be48 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -366,6 +366,10 @@ int16_t SX127x::packetMode() { return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6)); } +int16_t SX127x::startReceive() { + return(this->startReceive(0, RADIOLIB_SX127X_RXCONTINUOUS)); +} + int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index ebc0fb1936..f15338e378 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -770,14 +770,22 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + \returns \ref status_codes + */ + int16_t startReceive(); /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. - \param len Expected length of packet to be received. Required for LoRa spreading factor 6. - \param mode Receive mode to be used. Defaults to RxContinuous. + \param len Expected length of packet to be received, or 0 when unused. + Defaults to 0, non-zero required for LoRa spreading factor 6. + \param mode Receive mode to be used. \returns \ref status_codes */ - int16_t startReceive(uint8_t len = 0, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); + int16_t startReceive(uint8_t len, uint8_t mode); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. From 2b28296c942fd4c624414924cb259d0b76a68f1b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:20:54 +0200 Subject: [PATCH 0596/1848] [SX128x] Added default startReceive method --- src/modules/SX126x/SX126x.cpp | 4 ++++ src/modules/SX126x/SX126x.h | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 9d0c1aec2d..6dbb4af2f2 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -539,6 +539,10 @@ int16_t SX126x::finishTransmit() { return(standby()); } +int16_t SX126x::startReceive() { + return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_SX126X_IRQ_RX_DEFAULT, RADIOLIB_SX126X_IRQ_RX_DONE, 0)); +} + int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { (void)len; int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index e685338a2f..da1de755ce 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -588,6 +588,14 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + + \returns \ref status_codes + */ + int16_t startReceive(); /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. @@ -599,12 +607,12 @@ class SX126x: public PhysicalLayer { For any other value, timeout will be applied and signal will be generated on DIO1 for conditions defined by irqFlags and irqMask. - \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \param irqFlags Sets the IRQ flags. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1. \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. From f513226376b9eddac1a66fbcb5b47f326ab9b06a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:22:00 +0200 Subject: [PATCH 0597/1848] [PHY] Added default start receive --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 77adf4778d..e0652bf640 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -128,6 +128,10 @@ int16_t PhysicalLayer::standby(uint8_t mode) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::startReceive() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { (void)timeout; (void)irqFlags; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index b19339b6d0..a4375320d1 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -89,6 +89,12 @@ class PhysicalLayer { */ virtual int16_t standby(uint8_t mode); + /*! + \brief Sets module to received mode using its default configuration. + \returns \ref status_codes + */ + virtual int16_t startReceive(); + /*! \brief Interrupt-driven receive method. A DIO pin will be activated when full packet is received. Must be implemented in module class. @@ -383,6 +389,8 @@ class PhysicalLayer { friend class FSK4Client; friend class PagerClient; friend class BellClient; + friend class FT8Client; + friend class LoRaWANNode; }; #endif From ca319c9c0badbdda0985239fde8e43f00ec47d46 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:25:07 +0200 Subject: [PATCH 0598/1848] [Crypto] Added AES-128 --- src/RadioLib.h | 1 + src/utils/Cryptography.cpp | 294 +++++++++++++++++++++++++++++++++++++ src/utils/Cryptography.h | 173 ++++++++++++++++++++++ 3 files changed, 468 insertions(+) create mode 100644 src/utils/Cryptography.cpp create mode 100644 src/utils/Cryptography.h diff --git a/src/RadioLib.h b/src/RadioLib.h index b8a363853d..b7df08d986 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -112,6 +112,7 @@ // utilities #include "utils/CRC.h" +#include "utils/Cryptography.h" // only create Radio class when using RadioShield #if defined(RADIOLIB_RADIOSHIELD) diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp new file mode 100644 index 0000000000..1339c3bba6 --- /dev/null +++ b/src/utils/Cryptography.cpp @@ -0,0 +1,294 @@ +#include "Cryptography.h" + +#include + +RadioLibAES128::RadioLibAES128() { + +} + +void RadioLibAES128::init(uint8_t* key) { + this->keyPtr = key; + this->keyExpansion(this->roundKey, key); +} + +size_t RadioLibAES128::encryptECB(uint8_t* in, size_t len, uint8_t* out) { + size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + num_blocks++; + } + + memset(out, 0x00, RADIOLIB_AES128_BLOCK_SIZE * num_blocks); + memcpy(out, in, len); + + for(size_t i = 0; i < num_blocks; i++) { + this->cipher((state_t*)(out + (RADIOLIB_AES128_BLOCK_SIZE * i)), this->roundKey); + } + + return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); +} + +size_t RadioLibAES128::decryptECB(uint8_t* in, size_t len, uint8_t* out) { + size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + num_blocks++; + } + + memset(out, 0x00, RADIOLIB_AES128_BLOCK_SIZE * num_blocks); + memcpy(out, in, len); + + for(size_t i = 0; i < num_blocks; i++) { + this->decipher((state_t*)(out + (RADIOLIB_AES128_BLOCK_SIZE * i)), this->roundKey); + } + + return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); +} + +void RadioLibAES128::generateCMAC(uint8_t* in, size_t len, uint8_t* cmac) { + uint8_t key1[RADIOLIB_AES128_BLOCK_SIZE]; + uint8_t key2[RADIOLIB_AES128_BLOCK_SIZE]; + this->generateSubkeys(key1, key2); + + size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; + bool flag = true; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + num_blocks++; + flag = false; + } + + uint8_t* buff = new uint8_t[num_blocks * RADIOLIB_AES128_BLOCK_SIZE]; + memset(buff, 0, num_blocks * RADIOLIB_AES128_BLOCK_SIZE); + memcpy(buff, in, len); + if (flag) { + this->blockXor(&buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], key1); + } else { + buff[len] = 0x80; + this->blockXor(&buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], key2); + } + + uint8_t X[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + uint8_t Y[RADIOLIB_AES128_BLOCK_SIZE]; + + for(uint8_t i = 0; i < num_blocks - 1; i++) { + this->blockXor(Y, &buff[i*RADIOLIB_AES128_BLOCK_SIZE], X); + this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, X); + } + this->blockXor(Y, &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], X); + this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, cmac); + delete[] buff; +} + +bool RadioLibAES128::verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac) { + uint8_t cmacReal[RADIOLIB_AES128_BLOCK_SIZE]; + this->generateCMAC(in, len, cmacReal); + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + if((cmacReal[i] != cmac[i])) { + return(false); + } + } + return(true); +} + +void RadioLibAES128::keyExpansion(uint8_t* roundKey, uint8_t* key) { + uint8_t tmp[4]; + + // the first round key is the key itself + for(uint8_t i = 0; i < RADIOLIB_AES128_N_K; i++) { + for(uint8_t j = 0; j < 4; j++) { + roundKey[(i * 4) + j] = key[(i * 4) + j]; + } + } + + // All other round keys are found from the previous round keys. + for(uint8_t i = RADIOLIB_AES128_N_K; i < RADIOLIB_AES128_N_B * (RADIOLIB_AES128_N_R + 1); ++i) { + uint8_t j = (i - 1) * 4; + for(uint8_t k = 0; k < 4; k++) { + tmp[k] = roundKey[j + k]; + } + + if(i % RADIOLIB_AES128_N_K == 0) { + this->rotWord(tmp); + this->subWord(tmp); + tmp[0] = tmp[0] ^ aesRcon[i/RADIOLIB_AES128_N_K]; + } + + j = i * 4; + uint8_t k = (i - RADIOLIB_AES128_N_K) * 4; + for(uint8_t l = 0; l < 4; l++) { + roundKey[j + l] = roundKey[k + l] ^ tmp[l]; + } + } +} + +void RadioLibAES128::cipher(state_t* state, uint8_t* roundKey) { + this->addRoundKey(0, state, roundKey); + for(uint8_t round = 1; round < RADIOLIB_AES128_N_R; round++) { + this->subBytes(state, aesSbox); + this->shiftRows(state, false); + this->mixColumns(state, false); + this->addRoundKey(round, state, roundKey); + } + + this->subBytes(state, aesSbox); + this->shiftRows(state, false); + this->addRoundKey(RADIOLIB_AES128_N_R, state, roundKey); +} + + +void RadioLibAES128::decipher(state_t* state, uint8_t* roundKey) { + this->addRoundKey(RADIOLIB_AES128_N_R, state, roundKey); + for(uint8_t round = RADIOLIB_AES128_N_R - 1; round > 0; --round) { + this->shiftRows(state, true); + this->subBytes(state, aesSboxInv); + this->addRoundKey(round, state, roundKey); + this->mixColumns(state, true); + } + + this->shiftRows(state, true); + this->subBytes(state, aesSboxInv); + this->addRoundKey(0, state, roundKey); +} + +void RadioLibAES128::subWord(uint8_t* word) { + for(size_t i = 0; i < 4; i++) { + word[i] = RADIOLIB_NONVOLATILE_READ_BYTE(&aesSbox[word[i]]); + } +} + +void RadioLibAES128::rotWord(uint8_t* word) { + uint8_t tmp[4]; + memcpy(tmp, word, 4); + for(size_t i = 0; i < 4; i++) { + word[i] = tmp[(i + 1) % 4]; + } +} + +void RadioLibAES128::addRoundKey(uint8_t round, state_t* state, uint8_t* roundKey) { + for(size_t row = 0; row < 4; row++) { + for(size_t col = 0; col < 4; col++) { + (*state)[row][col] ^= roundKey[(round * RADIOLIB_AES128_N_B * 4) + (row * RADIOLIB_AES128_N_B) + col]; + } + } +} + +void RadioLibAES128::blockXor(uint8_t* dst, uint8_t* a, uint8_t* b) { + for(uint8_t j = 0; j < RADIOLIB_AES128_BLOCK_SIZE; j++) { + dst[j] = a[j] ^ b[j]; + } +} + +void RadioLibAES128::blockLeftshift(uint8_t* dst, uint8_t* src) { + uint8_t ovf = 0x00; + for(int8_t i = RADIOLIB_AES128_BLOCK_SIZE - 1; i >= 0; i--) { + dst[i] = src[i] << 1; + dst[i] |= ovf; + ovf = (src[i] & 0x80) ? 1 : 0; + } +} + +void RadioLibAES128::generateSubkeys(uint8_t* key1, uint8_t* key2) { + uint8_t const_Zero[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + uint8_t const_Rb[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x87 + }; + + uint8_t L[RADIOLIB_AES128_BLOCK_SIZE]; + this->encryptECB(const_Zero, RADIOLIB_AES128_BLOCK_SIZE, L); + this->blockLeftshift(key1, L); + if(L[0] & 0x80) { + this->blockXor(key1, key1, const_Rb); + } + + this->blockLeftshift(key2, key1); + if(key1[0] & 0x80) { + this->blockXor(key2, key2, const_Rb); + } +} + +void RadioLibAES128::subBytes(state_t* state, const uint8_t* box) { + for(size_t row = 0; row < 4; row++) { + for(size_t col = 0; col < 4; col++) { + (*state)[col][row] = box[(*state)[col][row]]; + } + } +} + +void RadioLibAES128::shiftRows(state_t* state, bool inv) { + uint8_t tmp[4]; + for(size_t row = 1; row < 4; row++) { + for(size_t col = 0; col < 4; col++) { + if(!inv) { + tmp[col] = (*state)[(row + col) % 4][row]; + } else { + tmp[(row + col) % 4] = (*state)[col][row]; + } + } + for(size_t col = 0; col < 4; col++) { + (*state)[col][row] = tmp[col]; + } + } +} + +void RadioLibAES128::mixColumns(state_t* state, bool inv) { + uint8_t tmp[4]; + uint8_t matmul[][4] = { + 0x02, 0x03, 0x01, 0x01, + 0x01, 0x02, 0x03, 0x01, + 0x01, 0x01, 0x02, 0x03, + 0x03, 0x01, 0x01, 0x02 + }; + if(inv) { + uint8_t matmul_inv[][4] = { + 0x0e, 0x0b, 0x0d, 0x09, + 0x09, 0x0e, 0x0b, 0x0d, + 0x0d, 0x09, 0x0e, 0x0b, + 0x0b, 0x0d, 0x09, 0x0e + }; + memcpy(matmul, matmul_inv, sizeof(matmul_inv)); + } + + for(size_t col = 0; col < 4; col++) { + for(size_t row = 0; row < 4; row++) { + tmp[row] = (*state)[col][row]; + } + for(size_t i = 0; i < 4; i++) { + (*state)[col][i] = 0x00; + for(size_t j = 0; j < 4; j++) { + (*state)[col][i] ^= mul(matmul[i][j], tmp[j]); + } + } + } +} + +uint8_t RadioLibAES128::mul(uint8_t a, uint8_t b) { + uint8_t sb[4]; + uint8_t out = 0; + sb[0] = b; + for(size_t i = 1; i < 4; i++) { + sb[i] = sb[i - 1] << 1; + if (sb[i - 1] & 0x80) { + sb[i] ^= 0x1b; + } + } + for(size_t i = 0; i < 4; i++) { + if(a >> i & 0x01) { + out ^= sb[i]; + } + } + return(out); +} + +RadioLibAES128 RadioLibAES128Instance; diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h new file mode 100644 index 0000000000..3b7a479914 --- /dev/null +++ b/src/utils/Cryptography.h @@ -0,0 +1,173 @@ +#if !defined(_RADIOLIB_CRYPTOGRAPHY_H) +#define _RADIOLIB_CRYPTOGRAPHY_H + +#include "../TypeDef.h" +#include "../Module.h" + +// AES-128 constants +#define RADIOLIB_AES128_BLOCK_SIZE (16) +#define RADIOLIB_AES128_N_K ((RADIOLIB_AES128_BLOCK_SIZE) / sizeof(uint32_t)) +#define RADIOLIB_AES128_N_B (4) +#define RADIOLIB_AES128_N_R (10) +#define RADIOLIB_AES128_KEY_EXP_SIZE (176) + +// helper type +typedef uint8_t state_t[4][4]; + +// AES lookup tables +static const uint8_t aesSbox[] RADIOLIB_NONVOLATILE = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +static const uint8_t aesSboxInv[] RADIOLIB_NONVOLATILE = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +static const uint8_t aesRcon[] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +/*! + \class RadioLibAES128 + Most of the implementation here is adapted from https://github.com/kokke/tiny-AES-c + Additional code and CMAC calculation is from https://github.com/megrxu/AES-CMAC + \brief Class to perform AES encryption, decryption and CMAC. +*/ +class RadioLibAES128 { + public: + /*! + \brief Default constructor. + */ + RadioLibAES128(); + + /*! + \brief Initialize the AES. + \param key AES key to use. + */ + void init(uint8_t* key); + + /*! + \brief Perform ECB-type AES encryption. + \param in Input plaintext data (unpadded). + \param len Length of the input data. + \param out Buffer to save the output ciphertext into. It is up to the caller + to ensure the buffer is sufficiently large to save the data! + \returns The number of bytes saved into the output buffer. + */ + size_t encryptECB(uint8_t* in, size_t len, uint8_t* out); + + /*! + \brief Perform ECB-type AES decryption. + \param in Input ciphertext data. + \param len Length of the input data. + \param out Buffer to save the output plaintext into. It is up to the caller + to ensure the buffer is sufficiently large to save the data! + \returns The number of bytes saved into the output buffer. + */ + size_t decryptECB(uint8_t* in, size_t len, uint8_t* out); + + /*! + \brief Calculate message authentication code according to RFC4493. + \param in Input data (unpadded). + \param len Length of the input data. + \param cmac Buffer to save the output MAC into. The buffer must be at least 16 bytes long! + */ + void generateCMAC(uint8_t* in, size_t len, uint8_t* cmac); + + /*! + \brief Verify the recevied CMAC. This just calculates the CMAC again and compares the results. + \param in Input data (unpadded). + \param len Length of the input data. + \param cmac CMAC to verify. + \returns True if valid, false otherwise. + */ + bool verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac); + + private: + uint8_t* keyPtr; + uint8_t roundKey[RADIOLIB_AES128_KEY_EXP_SIZE]; + + void keyExpansion(uint8_t* roundKey, uint8_t* key); + void cipher(state_t* state, uint8_t* roundKey); + void decipher(state_t* state, uint8_t* roundKey); + + void subWord(uint8_t* word); + void rotWord(uint8_t* word); + + void addRoundKey(uint8_t round, state_t* state, uint8_t* roundKey); + + void blockXor(uint8_t* dst, uint8_t* a, uint8_t* b); + void blockLeftshift(uint8_t* dst, uint8_t* src); + void generateSubkeys(uint8_t* key1, uint8_t* key2); + + void subBytes(state_t* state, const uint8_t* box); + void shiftRows(state_t* state, bool inv); + void mixColumns(state_t* state, bool inv); + + uint8_t mul(uint8_t a, uint8_t b); +}; + +// the global singleton +extern RadioLibAES128 RadioLibAES128Instance; + +#endif From 1597e8d7540df439b9f641914ca682685a35a33f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:32:06 +0200 Subject: [PATCH 0599/1848] [SX128x] Fixed default parameters --- src/modules/SX128x/SX128x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index beb0080cef..756165b6af 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -531,7 +531,7 @@ class SX128x: public PhysicalLayer { \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint16_t timeout = RADIOLIB_SX128X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint16_t timeout, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); /*! \brief Reads the current IRQ status. From 522aff911fc82b61dff9a44c64f7bfe6d95e6010 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:32:13 +0200 Subject: [PATCH 0600/1848] [SX127x] Fixed default parameters --- src/modules/SX127x/SX127x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index f15338e378..e738f844a8 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -782,10 +782,10 @@ class SX127x: public PhysicalLayer { \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. \param len Expected length of packet to be received, or 0 when unused. Defaults to 0, non-zero required for LoRa spreading factor 6. - \param mode Receive mode to be used. + \param mode Receive mode to be used. Defaults to RxContinuous. \returns \ref status_codes */ - int16_t startReceive(uint8_t len, uint8_t mode); + int16_t startReceive(uint8_t len, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. From cf677e6b15819bbb5f6b5d490b491fe435db939c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:32:24 +0200 Subject: [PATCH 0601/1848] [SX126x] Fixed default parameters --- src/modules/SX126x/SX126x.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index da1de755ce..7921c60824 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -607,12 +607,12 @@ class SX126x: public PhysicalLayer { For any other value, timeout will be applied and signal will be generated on DIO1 for conditions defined by irqFlags and irqMask. - \param irqFlags Sets the IRQ flags. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1. + \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. From 3029f0a4f8401bfedeb855012df51e171f56a973 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 May 2023 22:35:48 +0200 Subject: [PATCH 0602/1848] [CI] Added cleanup step --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f8ff3e5dd8..dfd2c70c1c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -175,6 +175,10 @@ jobs: rpi-build: runs-on: [self-hosted, ARM64] steps: + - name: Cleanup from previous run + run: | + sudo rm -rf /home/pi/actions-runner/_work/RadioLib/RadioLib/build + - name: Checkout repository uses: actions/checkout@v2 From 1161f67fa0916faf4d682c2fd5280c5978879210 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 29 May 2023 17:32:16 +0200 Subject: [PATCH 0603/1848] [Crypto] Fixed type comparison warning --- src/utils/Cryptography.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp index 1339c3bba6..7be62b6ce5 100644 --- a/src/utils/Cryptography.cpp +++ b/src/utils/Cryptography.cpp @@ -73,7 +73,7 @@ void RadioLibAES128::generateCMAC(uint8_t* in, size_t len, uint8_t* cmac) { }; uint8_t Y[RADIOLIB_AES128_BLOCK_SIZE]; - for(uint8_t i = 0; i < num_blocks - 1; i++) { + for(size_t i = 0; i < num_blocks - 1; i++) { this->blockXor(Y, &buff[i*RADIOLIB_AES128_BLOCK_SIZE], X); this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, X); } From 9d96cab4a6776cc7481f6ef57b3cfe54eaeed337 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 30 May 2023 17:35:22 +0200 Subject: [PATCH 0604/1848] [CI] Added none option to only run self-hosted rpi --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dfd2c70c1c..0c6cd18068 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,7 @@ on: type: choice options: - all + - none - arduino:avr:uno - arduino:avr:mega - arduino:avr:leonardo From 8e6bd972a98e5e3b31b16c7fd709035e41839e00 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 30 May 2023 21:05:43 +0200 Subject: [PATCH 0605/1848] [CI] Moved cleanup step to pre-run script --- .github/workflows/main.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0c6cd18068..f8ff3e5dd8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,6 @@ on: type: choice options: - all - - none - arduino:avr:uno - arduino:avr:mega - arduino:avr:leonardo @@ -176,10 +175,6 @@ jobs: rpi-build: runs-on: [self-hosted, ARM64] steps: - - name: Cleanup from previous run - run: | - sudo rm -rf /home/pi/actions-runner/_work/RadioLib/RadioLib/build - - name: Checkout repository uses: actions/checkout@v2 From f63d228d0b378c426e1a287626a64578dff9f0ba Mon Sep 17 00:00:00 2001 From: Kevin Walton Date: Thu, 1 Jun 2023 21:51:57 +0100 Subject: [PATCH 0606/1848] Bug in waitForMicroseconds prevTimingLen in V6.0.0 In Module::waitForMicroseconds if RADIOLIB_INTERRUPT_TIMING is defined the variable prevTimingLen has been incorrectly upated in v6.0.0 introducing a bug that stops compilation. Fix: renamed _prevTimingLen to prevTimingLen to match other updates --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 329bdd49d4..3959dee86b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -366,7 +366,7 @@ void Module::waitForMicroseconds(uint32_t start, uint32_t len) { #if defined(RADIOLIB_INTERRUPT_TIMING) (void)start; if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) { - _prevTimingLen = len; + prevTimingLen = len; this->TimerSetupCb(len); } this->TimerFlag = false; From 9f5e77616b1955307206fba6dccd6fdcc8754420 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 Jun 2023 13:23:22 +0200 Subject: [PATCH 0607/1848] Updated CMake for ESP-IDF (#748) --- CMakeLists.txt | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 33f0ebfde1..ffcc6abc21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,25 @@ cmake_minimum_required(VERSION 3.13) +if(ESP_PLATFORM) + # Build RadioLib as an ESP-IDF component + # required because ESP-IDF runs cmake in script mode + # and needs idf_component_register() + file(GLOB_RECURSE RADIOLIB_ESP_SOURCES + "src/*.*" + ) + + idf_component_register( + SRCS ${RADIOLIB_ESP_SOURCES} + INCLUDE_DIRS . src + ) + + return() +endif() + +if(CMAKE_SCRIPT_MODE_FILE) + message(FATAL_ERROR "Attempted to build RadioLib in script mode") +endif() + project(radiolib) file(GLOB_RECURSE RADIOLIB_SOURCES @@ -23,4 +43,3 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/RadioLib FILES_MATCHING PATTERN "*.h" ) - From cb7b282c9bad155b54cf8e16f9a5664a852ebbf4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 Jun 2023 13:25:08 +0200 Subject: [PATCH 0608/1848] Updae ESP-IFD example (#748) --- examples/NonArduino/ESP-IDF/.gitignore | 3 +++ .../ESP-IDF/components/RadioLib/CMakeLists.txt | 10 ---------- examples/NonArduino/ESP-IDF/main/CMakeLists.txt | 2 +- examples/NonArduino/ESP-IDF/main/idf_component.yml | 7 +++++++ 4 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 examples/NonArduino/ESP-IDF/.gitignore delete mode 100644 examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt create mode 100644 examples/NonArduino/ESP-IDF/main/idf_component.yml diff --git a/examples/NonArduino/ESP-IDF/.gitignore b/examples/NonArduino/ESP-IDF/.gitignore new file mode 100644 index 0000000000..f9b3ce2818 --- /dev/null +++ b/examples/NonArduino/ESP-IDF/.gitignore @@ -0,0 +1,3 @@ +# generated by ESP-IDF +managed_components/ +dependencies.lock diff --git a/examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt b/examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt deleted file mode 100644 index 6adf691b09..0000000000 --- a/examples/NonArduino/ESP-IDF/components/RadioLib/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# this is required for ESP IDF -idf_component_register() - -# if you did not build RadioLib as shared library (see wiki), -# you will have to add it as source directory -# the following is just an example, yours will likely be different -add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") - -# link RadioLib as interface -target_link_libraries(${COMPONENT_LIB} INTERFACE RadioLib) diff --git a/examples/NonArduino/ESP-IDF/main/CMakeLists.txt b/examples/NonArduino/ESP-IDF/main/CMakeLists.txt index 52e0183312..1f57116422 100644 --- a/examples/NonArduino/ESP-IDF/main/CMakeLists.txt +++ b/examples/NonArduino/ESP-IDF/main/CMakeLists.txt @@ -1,4 +1,4 @@ -# register the component and set "RadioLib", "esp_timer" and "driver" ad required +# register the component and set "RadioLib", "esp_timer" and "driver" as required idf_component_register(SRCS "main.cpp" INCLUDE_DIRS "." REQUIRES RadioLib esp_timer driver) diff --git a/examples/NonArduino/ESP-IDF/main/idf_component.yml b/examples/NonArduino/ESP-IDF/main/idf_component.yml new file mode 100644 index 0000000000..38382f42d0 --- /dev/null +++ b/examples/NonArduino/ESP-IDF/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + RadioLib: + # referenced locally because the example is a part of the repository itself + # under normal circumstances, it's preferrable to reference the repository instead + # for other options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html + path: ../../../../../RadioLib + #git: https://github.com/jgromes/RadioLib.git From 8adf4fd4f21dca24294385e1b9c1e58bb1e43b1d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 Jun 2023 13:43:46 +0200 Subject: [PATCH 0609/1848] [CI] Added option to only run rpi build --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f8ff3e5dd8..b5c76bfee0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,7 @@ on: type: choice options: - all + - none - arduino:avr:uno - arduino:avr:mega - arduino:avr:leonardo @@ -107,7 +108,7 @@ jobs: runs-on: ubuntu-latest name: ${{ matrix.id }} env: - run-build: ${{ (matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) || inputs.id == 'all' || inputs.id == matrix.id }} + run-build: ${{ (inputs.id != 'none' && matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) || inputs.id == 'all' || inputs.id == matrix.id }} steps: - name: Install arduino-cli From 27ef744edf017fef6ecd91e8b69a55e458dc2962 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 7 Jun 2023 20:41:14 +0200 Subject: [PATCH 0610/1848] [SX127x] Fixed references to 256 byte packets --- examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino | 4 ++-- .../SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino | 4 ++-- .../SX127x_Transmit_Interrupt.ino | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino index 7330481117..f8c0533a33 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino @@ -2,7 +2,7 @@ RadioLib SX127x Transmit Example This example transmits packets using SX1278 LoRa radio module. - Each packet contains up to 256 bytes of data, in the form of: + Each packet contains up to 255 bytes of data, in the form of: - Arduino String - null-terminated char array (C-string) - arbitrary binary data (byte array) @@ -59,7 +59,7 @@ void loop() { Serial.print(F("[SX1278] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to - // 256 characters long + // 255 characters long // NOTE: transmit() is a blocking method! // See example SX127x_Transmit_Interrupt for details // on non-blocking transmission method. diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index 9b8693e3c7..15ef3ae818 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -2,7 +2,7 @@ RadioLib SX127x Transmit with Frequency Hopping Example This example transmits packets using SX1278 LoRa radio module. - Each packet contains up to 256 bytes of data, in the form of: + Each packet contains up to 255 bytes of data, in the form of: - Arduino String - null-terminated char array (C-string) - arbitrary binary data (byte array) @@ -56,7 +56,7 @@ int transmissionState = RADIOLIB_ERR_NONE; // this is the packet that will be sent String longPacket = "Let's create a really long packet to trigger \ -lots of hop interrupts. A packet can be up to 256 bytes long. \ +lots of hop interrupts. A packet can be up to 255 bytes long. \ This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is \ 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 8cf0f059e2..6d60cd72cc 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -2,7 +2,7 @@ RadioLib SX127x Transmit with Interrupts Example This example transmits LoRa packets with one second delays - between them. Each packet contains up to 256 bytes + between them. Each packet contains up to 255 bytes of data, in the form of: - Arduino String - null-terminated char array (C-string) @@ -56,10 +56,10 @@ void setup() { Serial.print(F("[SX1278] Sending first packet ... ")); // you can transmit C-string or Arduino string up to - // 256 characters long + // 255 characters long transmissionState = radio.startTransmit("Hello World!"); - // you can also transmit byte array up to 256 bytes long + // you can also transmit byte array up to 255 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; @@ -114,10 +114,10 @@ void loop() { Serial.print(F("[SX1278] Sending another packet ... ")); // you can transmit C-string or Arduino string up to - // 256 characters long + // 255 characters long transmissionState = radio.startTransmit("Hello World!"); - // you can also transmit byte array up to 256 bytes long + // you can also transmit byte array up to 255 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; From 69bc96ac08e47385e060cafa05308df55c1ef817 Mon Sep 17 00:00:00 2001 From: Hendrik Langer Date: Fri, 16 Jun 2023 14:42:22 +0200 Subject: [PATCH 0611/1848] Pager: allow manual override of function bits --- keywords.txt | 1 + src/TypeDef.h | 5 +++++ src/protocols/Pager/Pager.cpp | 37 +++++++++++++++++++++++------------ src/protocols/Pager/Pager.h | 17 ++++++++++------ 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/keywords.txt b/keywords.txt index b55879336c..8109484b3d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -364,3 +364,4 @@ RADIOLIB_ERR_RANGING_TIMEOUT LITERAL1 RADIOLIB_ERR_INVALID_PAYLOAD LITERAL1 RADIOLIB_ERR_ADDRESS_NOT_FOUND LITERAL1 +RADIOLIB_ERR_INVALID_FUNCTION LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index 6d41b56b3c..32e54a46b8 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -476,6 +476,11 @@ */ #define RADIOLIB_ERR_ADDRESS_NOT_FOUND (-1002) +/*! + \brief The requested address was not found in the received data. +*/ +#define RADIOLIB_ERR_INVALID_FUNCTION (-1003) + /*! \} */ diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index b7dd00bbbd..1416247a41 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -55,16 +55,16 @@ int16_t PagerClient::sendTone(uint32_t addr) { } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding) { - return(PagerClient::transmit(str.c_str(), addr, encoding)); +int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding, uint8_t function) { + return(PagerClient::transmit(str.c_str(), addr, encoding, function)); } #endif -int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding) { - return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding)); +int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding, uint8_t function) { + return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding, function)); } -int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding) { +int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding, uint8_t function) { if(addr > RADIOLIB_PAGER_ADDRESS_MAX) { return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); } @@ -75,29 +75,42 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t // get symbol bit length based on encoding uint8_t symbolLength = 0; - uint32_t function = 0; if(encoding == RADIOLIB_PAGER_BCD) { symbolLength = 4; - function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; } else if(encoding == RADIOLIB_PAGER_ASCII) { symbolLength = 7; - function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; } else { return(RADIOLIB_ERR_INVALID_ENCODING); } - if(len == 0) { - function = RADIOLIB_PAGER_FUNC_BITS_TONE; + // Automatically set function bits based on given encoding + if (function == RADIOLIB_PAGER_FUNC_AUTO) { + if(encoding == RADIOLIB_PAGER_BCD) { + function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; + + } else if(encoding == RADIOLIB_PAGER_ASCII) { + function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; + + } else { + return(RADIOLIB_ERR_INVALID_ENCODING); + + } + if(len == 0) { + function = RADIOLIB_PAGER_FUNC_BITS_TONE; + } + } + if (function > RADIOLIB_PAGER_FUNC_BITS_ALPHA) { + return(RADIOLIB_ERR_INVALID_FUNCTION); } // get target position in batch (3 LSB from address determine frame position in batch) uint8_t framePos = 2*(addr & 0x07); // get address that will be written into address frame - uint32_t frameAddr = ((addr >> 3) << RADIOLIB_PAGER_ADDRESS_POS) | function; + uint32_t frameAddr = ((addr >> 3) << RADIOLIB_PAGER_ADDRESS_POS) | (function << RADIOLIB_PAGER_FUNC_BITS_POS); // calculate the number of 20-bit data blocks size_t numDataBlocks = (len * symbolLength) / RADIOLIB_PAGER_MESSAGE_BITS_LENGTH; @@ -347,7 +360,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { } // determine the encoding from the function bits - if((cw & RADIOLIB_PAGER_FUNCTION_BITS_MASK) == RADIOLIB_PAGER_FUNC_BITS_NUMERIC) { + if((cw & RADIOLIB_PAGER_FUNCTION_BITS_MASK) >> RADIOLIB_PAGER_FUNC_BITS_POS == RADIOLIB_PAGER_FUNC_BITS_NUMERIC) { symbolLength = 4; } else { symbolLength = 7; diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 8e588ef307..ca84f73314 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -46,9 +46,11 @@ #define RADIOLIB_PAGER_BCH_BITS_MASK (0x000007FFUL) // message type functional bits -#define RADIOLIB_PAGER_FUNC_BITS_NUMERIC (0b00UL << RADIOLIB_PAGER_FUNC_BITS_POS) -#define RADIOLIB_PAGER_FUNC_BITS_TONE (0b01UL << RADIOLIB_PAGER_FUNC_BITS_POS) -#define RADIOLIB_PAGER_FUNC_BITS_ALPHA (0b11UL << RADIOLIB_PAGER_FUNC_BITS_POS) +#define RADIOLIB_PAGER_FUNC_BITS_NUMERIC (0b00) +#define RADIOLIB_PAGER_FUNC_BITS_TONE (0b01) +#define RADIOLIB_PAGER_FUNC_BITS_ACTIVATION (0b10) +#define RADIOLIB_PAGER_FUNC_BITS_ALPHA (0b11) +#define RADIOLIB_PAGER_FUNC_AUTO 0xFF // the maximum allowed address (2^22 - 1) #define RADIOLIB_PAGER_ADDRESS_MAX (2097151) @@ -90,9 +92,10 @@ class PagerClient { \param str Address of Arduino string that will be transmitted. \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + int16_t transmit(String& str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); #endif /*! @@ -100,9 +103,10 @@ class PagerClient { \param str C-string that will be transmitted. \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(const char* str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + int16_t transmit(const char* str, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); /*! \brief Binary transmit method. Will transmit arbitrary binary data. @@ -110,9 +114,10 @@ class PagerClient { \param len Length of binary data to transmit (in bytes). \param addr Address of the destination pager. Allowed values are 0 to 2097151 - values above 2000000 are reserved. \param encoding Encoding to be used (BCD or ASCII). Defaults to RADIOLIB_PAGER_BCD. + \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD); + int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! From 79725481cff827326d2e8a9c2ce3f8e2f557777f Mon Sep 17 00:00:00 2001 From: Hendrik Langer Date: Fri, 16 Jun 2023 15:58:59 +0200 Subject: [PATCH 0612/1848] fix error description --- src/TypeDef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index 32e54a46b8..64fba9ced3 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -477,7 +477,7 @@ #define RADIOLIB_ERR_ADDRESS_NOT_FOUND (-1002) /*! - \brief The requested address was not found in the received data. + \brief The function code is invalid. 2 Bits only. */ #define RADIOLIB_ERR_INVALID_FUNCTION (-1003) From be7dc572a662fc34262cf02309f2b11e15399b08 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:02:40 +0200 Subject: [PATCH 0613/1848] [PHY] Added generic actions --- keywords.txt | 4 ++++ src/protocols/PhysicalLayer/PhysicalLayer.cpp | 13 +++++++++++-- src/protocols/PhysicalLayer/PhysicalLayer.h | 19 +++++++++++++++---- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/keywords.txt b/keywords.txt index 8109484b3d..34d077d681 100644 --- a/keywords.txt +++ b/keywords.txt @@ -265,6 +265,10 @@ sendTone KEYWORD2 dropSync KEYWORD2 setTimerFlag KEYWORD2 setInterruptSetup KEYWORD2 +setPacketReceivedAction KEYWORD2 +clearPacketReceivedAction KEYWORD2 +setPacketSentAction KEYWORD2 +clearPacketSentAction KEYWORD2 # BellModem setModem KEYWORD2 diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index e0652bf640..1e9d35844e 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -395,11 +395,20 @@ int16_t PhysicalLayer::setDIOMapping(uint32_t pin, uint32_t value) { return(RADIOLIB_ERR_UNSUPPORTED); } -void PhysicalLayer::setDio1Action(void (*func)(void)) { +void PhysicalLayer::setPacketReceivedAction(void (*func)(void)) { (void)func; } -void PhysicalLayer::clearDio1Action() { +void PhysicalLayer::clearPacketReceivedAction() { + +} + +void PhysicalLayer::setPacketSentAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::clearPacketSentAction() { + } #if defined(RADIOLIB_INTERRUPT_TIMING) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index a4375320d1..4e9ceb5123 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -327,15 +327,26 @@ class PhysicalLayer { virtual int16_t setDIOMapping(uint32_t pin, uint32_t value); /*! - \brief Sets interrupt service routine to call when DIO1 activates. + \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - virtual void setDio1Action(void (*func)(void)); + virtual void setPacketReceivedAction(void (*func)(void)); /*! - \brief Clears interrupt service routine to call when DIO1 activates. + \brief Clears interrupt service routine to call when a packet is received. */ - virtual void clearDio1Action(); + virtual void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + virtual void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + virtual void clearPacketSentAction(); #if defined(RADIOLIB_INTERRUPT_TIMING) From a6ba423c73018684a3aca870918e218df564a209 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:03:07 +0200 Subject: [PATCH 0614/1848] [SX127x] Implemented generic actions --- .../SX127x_Receive_Interrupt.ino | 2 +- .../SX127x_Transmit_Interrupt.ino | 2 +- src/modules/SX127x/SX127x.cpp | 16 ++++++++++++++ src/modules/SX127x/SX127x.h | 22 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 02cb5b096b..76c641d32c 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -51,7 +51,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setDio0Action(setFlag, RISING); + radio.setPacketReceivedAction(setFlag); // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 6d60cd72cc..b0551083ef 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -50,7 +50,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setDio0Action(setFlag, RISING); + radio.setPacketSentAction(setFlag); // start transmitting the first packet Serial.print(F("[SX1278] Sending first packet ... ")); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 9b8202be48..679681f4ad 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -452,6 +452,22 @@ void SX127x::clearDio1Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); } +void SX127x::setPacketReceivedAction(void (*func)(void)) { + this->setDio0Action(func, RISING); +} + +void SX127x::clearPacketReceivedAction() { + this->clearDio0Action(); +} + +void SX127x::setPacketSentAction(void (*func)(void)) { + this->setDio0Action(func, RISING); +} + +void SX127x::clearPacketSentAction() { + this->clearDio0Action(); +} + void SX127x::setFifoEmptyAction(void (*func)(void)) { // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) setDio1Action(func, this->mod->hal->GpioInterruptRising); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e738f844a8..951ee31baa 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -716,6 +716,28 @@ class SX127x: public PhysicalLayer { */ void clearDio1Action(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Set interrupt service routine function to call when FIFO is empty. \param func Pointer to interrupt service routine. From 8567c77641f255277c24e3f6377daf3de173bfeb Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:07:24 +0200 Subject: [PATCH 0615/1848] [CC1101] Implemented generic actions --- .../CC1101_Receive_Interrupt.ino | 2 +- .../CC1101_Transmit_Interrupt.ino | 5 +---- src/modules/CC1101/CC1101.cpp | 16 ++++++++++++++ src/modules/CC1101/CC1101.h | 22 +++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index f61253fcc2..4dbd17f1d0 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -49,7 +49,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setGdo0Action(setFlag, RISING); + radio.setPacketReceivedAction(setFlag); // start listening for packets Serial.print(F("[CC1101] Starting to listen ... ")); diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 699e88c432..ee88090aaf 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -48,10 +48,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - // NOTE: Unlike other modules (such as SX127x), - // different GDOx pins are used for - // transmit and receive interrupts! - radio.setGdo2Action(setFlag, FALLING); + radio.setPacketSentAction(setFlag); // start transmitting the first packet Serial.print(F("[CC1101] Sending first packet ... ")); diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 2472101706..8a90f4800b 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -239,6 +239,22 @@ void CC1101::clearGdo0Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } +void CC1101::setPacketReceivedAction(void (*func)(void)) { + this->setGdo0Action(func, RISING); +} + +void CC1101::clearPacketReceivedAction() { + this->clearGdo0Action(); +} + +void CC1101::setPacketSentAction(void (*func)(void)) { + this->setGdo2Action(func, FALLING); +} + +void CC1101::clearPacketSentAction() { + this->clearGdo2Action(); +} + void CC1101::setGdo2Action(void (*func)(void), uint32_t dir) { if(this->mod->getGpio() == RADIOLIB_NC) { return; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 8dbf4326ac..4ca73c6072 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -659,6 +659,28 @@ class CC1101: public PhysicalLayer { */ void clearGdo2Action(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. From 291251ea725fb2b2e395d4ebd21a5d77667033fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:11:36 +0200 Subject: [PATCH 0616/1848] [nRF24] Implemented generic actions --- .../nRF24_Receive_Interrupt.ino | 2 +- .../nRF24_Transmit_Interrupt.ino | 2 +- src/modules/nRF24/nRF24.cpp | 20 ++++++++++++++ src/modules/nRF24/nRF24.h | 27 +++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index ccca2798b6..c41bb2b8d2 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -61,7 +61,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setIrqAction(setFlag); + radio.setPacketReceivedAction(setFlag); // start listening Serial.print(F("[nRF24] Starting to listen ... ")); diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index cdcbf997f2..05398fc40b 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -63,7 +63,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setIrqAction(setFlag); + radio.setPacketSentAction(setFlag); // start transmitting the first packet Serial.print(F("[nRF24] Sending first packet ... ")); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 62cb2c2d69..3257187b42 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -159,6 +159,26 @@ void nRF24::setIrqAction(void (*func)(void)) { this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptFalling); } +void nRF24::clearIrqAction() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void nRF24::setPacketReceivedAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void nRF24::clearPacketReceivedAction() { + this->clearIrqAction(); +} + +void nRF24::setPacketSentAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void nRF24::clearPacketSentAction() { + this->clearIrqAction(); +} + int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index e94a742165..22a161ef60 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -272,6 +272,33 @@ class nRF24: public PhysicalLayer { */ void setIrqAction(void (*func)(void)); + /*! + \brief Clears interrupt service routine . + */ + void clearIrqAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Interrupt-driven binary transmit method. IRQ will be activated when full packet is transmitted. Overloads for string-based transmissions are implemented in PhysicalLayer. From a21fb9f136c2e5503c5a90be284344c9c001ec98 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:13:44 +0200 Subject: [PATCH 0617/1848] [CC1101] Fixed direction from HAL --- src/modules/CC1101/CC1101.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 8a90f4800b..52a9b6bc91 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -240,7 +240,7 @@ void CC1101::clearGdo0Action() { } void CC1101::setPacketReceivedAction(void (*func)(void)) { - this->setGdo0Action(func, RISING); + this->setGdo0Action(func, this->mod->hal->GpioInterruptRising); } void CC1101::clearPacketReceivedAction() { @@ -248,7 +248,7 @@ void CC1101::clearPacketReceivedAction() { } void CC1101::setPacketSentAction(void (*func)(void)) { - this->setGdo2Action(func, FALLING); + this->setGdo2Action(func, this->mod->hal->GpioInterruptFalling); } void CC1101::clearPacketSentAction() { From 43b9b139038894416f4a9dc55aec9d904a978de7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:13:54 +0200 Subject: [PATCH 0618/1848] [SX127x] Fixed direction from HAL --- src/modules/SX127x/SX127x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 679681f4ad..467bbecd6e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -453,7 +453,7 @@ void SX127x::clearDio1Action() { } void SX127x::setPacketReceivedAction(void (*func)(void)) { - this->setDio0Action(func, RISING); + this->setDio0Action(func, this->mod->hal->GpioInterruptRising); } void SX127x::clearPacketReceivedAction() { @@ -461,7 +461,7 @@ void SX127x::clearPacketReceivedAction() { } void SX127x::setPacketSentAction(void (*func)(void)) { - this->setDio0Action(func, RISING); + this->setDio0Action(func, this->mod->hal->GpioInterruptRising); } void SX127x::clearPacketSentAction() { From df126c92f90767ccecd1926c4ef13cd7b67936e5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:15:54 +0200 Subject: [PATCH 0619/1848] [RF69] Implemented generic actions --- .../RF69_Receive_Interrupt.ino | 2 +- .../RF69_Transmit_Interrupt.ino | 2 +- src/modules/RF69/RF69.cpp | 16 ++++++++++++++ src/modules/RF69/RF69.h | 22 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index fc2c5804b0..0a125883e8 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -41,7 +41,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setDio0Action(setFlag); + radio.setPacketReceivedAction(setFlag); // start listening for packets Serial.print(F("[RF69] Starting to listen ... ")); diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index de73535d19..cd29c59cb1 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -47,7 +47,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setDio0Action(setFlag); + radio.setPacketSentAction(setFlag); // NOTE: some RF69 modules use high power output, // those are usually marked RF69H(C/CW). diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index e06b107779..6af30faeba 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -294,6 +294,22 @@ void RF69::clearDio1Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); } +void RF69::setPacketReceivedAction(void (*func)(void)) { + this->setDio0Action(func); +} + +void RF69::clearPacketReceivedAction() { + this->clearDio0Action(); +} + +void RF69::setPacketSentAction(void (*func)(void)) { + this->setDio0Action(func); +} + +void RF69::clearPacketSentAction() { + this->clearDio0Action(); +} + void RF69::setFifoEmptyAction(void (*func)(void)) { // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) if(this->mod->getGpio() == RADIOLIB_NC) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 95b0677ab0..dfe0308fb6 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -617,6 +617,28 @@ class RF69: public PhysicalLayer { */ void clearDio1Action(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Set interrupt service routine function to call when FIFO is empty. \param func Pointer to interrupt service routine. From 46e1af764e7c40ee5cd37b3ed5b7b12051e3456f Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:17:48 +0200 Subject: [PATCH 0620/1848] [Si443x] Implemented generic IRQ actions --- .../Si443x_Receive_Interrupt.ino | 2 +- .../Si443x_Transmit_Interrupt.ino | 2 +- src/modules/Si443x/Si443x.cpp | 16 ++++++++++++++ src/modules/Si443x/Si443x.h | 22 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index cb9c2d69b3..2ef80c6908 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -43,7 +43,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setIrqAction(setFlag); + radio.setPacketReceivedAction(setFlag); // start listening for packets Serial.print(F("[Si4432] Starting to listen ... ")); diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index d2edc6c87b..b13bcafc56 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -48,7 +48,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setIrqAction(setFlag); + radio.setPacketSentAction(setFlag); // start transmitting the first packet Serial.print(F("[Si4432] Sending first packet ... ")); diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 6498518acb..62695fc4ff 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -214,6 +214,22 @@ void Si443x::clearIrqAction() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } +void Si443x::setPacketReceivedAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void Si443x::clearPacketReceivedAction() { + this->clearIrqAction(); +} + +void Si443x::setPacketSentAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void Si443x::clearPacketSentAction() { + this->clearIrqAction(); +} + int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length if(len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index e708204cac..c2841b9d1b 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -656,6 +656,28 @@ class Si443x: public PhysicalLayer { */ void clearIrqAction(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 64 bytes long. \param data Binary data that will be transmitted. From 787ebde43e2c1a58d1491c04c1df87d4ea10960f Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:21:55 +0200 Subject: [PATCH 0621/1848] [SX126x] Implemented generic IRQ actions (#773) --- .../SX126x_Receive_Interrupt.ino | 2 +- .../SX126x_Transmit_Interrupt.ino | 2 +- src/modules/SX126x/SX126x.cpp | 16 ++++++++++++++ src/modules/SX126x/SX126x.h | 22 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 76cd07bee5..0786d4b607 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -54,7 +54,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setDio1Action(setFlag); + radio.setPacketReceivedAction(setFlag); // start listening for LoRa packets Serial.print(F("[SX1262] Starting to listen ... ")); diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 850ddbb87c..6bf9be2bc0 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -53,7 +53,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setDio1Action(setFlag); + radio.setPacketSentAction(setFlag); // start transmitting the first packet Serial.print(F("[SX1262] Sending first packet ... ")); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6dbb4af2f2..1cbb5df37f 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -470,6 +470,22 @@ void SX126x::clearDio1Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } +void SX126x::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void SX126x::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearPacketSentAction() { + this->clearDio1Action(); +} + int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 7921c60824..ce363187c4 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -573,6 +573,28 @@ class SX126x: public PhysicalLayer { */ void clearDio1Action(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. From 1f6acc8347a89a456c4ca3dc8a47ec28ba3f105e Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:23:43 +0200 Subject: [PATCH 0622/1848] [SX128x] Implemented generic IRQ actions --- .../SX128x_Receive_Interrupt.ino | 2 +- .../SX128x_Transmit_Interrupt.ino | 2 +- src/modules/SX128x/SX128x.cpp | 16 ++++++++++++++ src/modules/SX128x/SX128x.h | 22 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 211a906931..5d0e499280 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -51,7 +51,7 @@ void setup() { // set the function that will be called // when new packet is received - radio.setDio1Action(setFlag); + radio.setPacketReceivedAction(setFlag); // start listening for LoRa packets Serial.print(F("[SX1280] Starting to listen ... ")); diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 1784397060..9a49003087 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -50,7 +50,7 @@ void setup() { // set the function that will be called // when packet transmission is finished - radio.setDio1Action(setFlag); + radio.setPacketSentAction(setFlag); // start transmitting the first packet Serial.print(F("[SX1280] Sending first packet ... ")); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 783b3f512c..f3eb20d6b9 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -476,6 +476,22 @@ void SX128x::clearDio1Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } +void SX128x::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX128x::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void SX128x::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX128x::clearPacketSentAction() { + this->clearDio1Action(); +} + int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 756165b6af..ca69f843e9 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -495,6 +495,28 @@ class SX128x: public PhysicalLayer { */ void clearDio1Action(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. From 9472d5b63524bbba3f06ab418b67f53cc67753c4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jun 2023 22:25:31 +0200 Subject: [PATCH 0623/1848] [PHY] Added interface showcase example (#773) --- .../PhysicalLayer_Interface.ino | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino diff --git a/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino b/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino new file mode 100644 index 0000000000..58a95360fa --- /dev/null +++ b/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino @@ -0,0 +1,137 @@ +/* + RadioLib PhysicalLayer Interface Example + + This example shows how to use the common PhysicalLayer + to interface with different radio modules using the same + methods. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// select which radio to use +// this can be any radio supported by RadioLib! +#define RADIO_TYPE SX1278 + +// set the pinout depending on the wiring and module type +// SPI NSS pin: 10 +// interrupt pin: 2 +// reset pin: 9 (unused on some modules) +// extra GPIO/interrupt pin: 3 (unused on some modules) +RADIO_TYPE radio = new Module(10, 2, 9, 3); + +// get pointer to the common layer +PhysicalLayer* phy = (PhysicalLayer*)&radio; + +void dummyISR(void) { + // nothing here, this example is just a showcase +} + +void setup() { + Serial.begin(9600); + + // now we can use "radio" to access the features + // specific to that radio type, such as the begin() method + Serial.print(F("[Radio] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // or we can use the "phy" pointer to access the common layer + // PhysicalLayer has some common configuration + Serial.print(F("[PHY] Changing frequency ... ")); + state = phy->setFrequency(433.5); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // PhysicalLayer also contains basic functionality + // like transmitting and receiving packets + Serial.print(F("[PHY] Sending packet ... ")); + state = phy->transmit("Hello World!"); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // try to receive now - this will almost certainly timeout + // unless by chance there is a transmitter nearby, + // but the point of this example is to showcase the interface + String str; + Serial.print(F("[PHY] Listening for packets ... ")); + state = phy->receive(str); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // interrupt-driven versions of Rx/Tx are supported as well + // for these to work, you have to configure the interrupt actions + phy->setPacketReceivedAction(dummyISR); + phy->setPacketSentAction(dummyISR); + + // now you can use methods like startTransmit(), startReceive(), + // readData() etc. + + // interrupt actions can be cleared as well + phy->clearPacketReceivedAction(); + phy->clearPacketSentAction(); + + // PhysicalLayer supports basic mode changes like sleep ... + Serial.print(F("[PHY] Going to sleep ... ")); + state = phy->sleep(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // ... or standby + Serial.print(F("[PHY] Going to standby ... ")); + state = phy->standby(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // there are also common SNR/RSSI measurement functions + Serial.print(F("[PHY] Measured SNR = ")); + Serial.print(phy->getSNR()); + Serial.println(F(" dB")); + Serial.print(F("[PHY] Measured RSSI = ")); + Serial.print(phy->getRSSI()); + Serial.println(F(" dBm")); + + // and also a true random number generator + Serial.print(F("[PHY] Random number between 0 and 100 = ")); + Serial.println(phy->random(100)); +} + +void loop() { + // nothing here, the example is just a showcase +} From 7f40ee49c6a9be61bb8e533f22012ee1e51af6fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 19:23:09 +0200 Subject: [PATCH 0624/1848] [SX126x] Fixed blocking receive (#777) --- src/modules/SX126x/SX126x.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1cbb5df37f..95aeafcd4d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -304,17 +304,31 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout + bool softTimeout = false; uint32_t start = this->mod->hal->micros(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); + // safety check, the timeout should be done by the radio if(this->mod->hal->micros() - start > timeout) { - fixImplicitTimeout(); - clearIrqStatus(); - standby(); - return(RADIOLIB_ERR_RX_TIMEOUT); + softTimeout = true; + break; } } + // if it was a timeout, this will return an error code + state = standby(); + if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) { + return(state); + } + + // check whether this was a timeout or not + if((getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { + standby(); + fixImplicitTimeout(); + clearIrqStatus(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + // fix timeout in implicit LoRa mode if(((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { state = fixImplicitTimeout(); From 36530b00fc3515ba33caf89699aa6f85cb119371 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 19:23:26 +0200 Subject: [PATCH 0625/1848] [SX128x] Fixed blocking receive --- src/modules/SX128x/SX128x.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index f3eb20d6b9..bf46421898 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -353,16 +353,30 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout + bool softTimeout = false; uint32_t start = this->mod->hal->micros(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); + // safety check, the timeout should be done by the radio if(this->mod->hal->micros() - start > timeout) { - clearIrqStatus(); - standby(); - return(RADIOLIB_ERR_RX_TIMEOUT); + softTimeout = true; + break; } } + // if it was a timeout, this will return an error code + state = standby(); + if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) { + return(state); + } + + // check whether this was a timeout or not + if((getIrqStatus() & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT) || softTimeout) { + standby(); + clearIrqStatus(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + // read the received data return(readData(data, len)); } From ac78f31532920fac74f0a3333464e15063585adf Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 19:51:09 +0200 Subject: [PATCH 0626/1848] [CC1101] Renamed basic examples to _Blocking --- .../CC1101_Receive_Blocking.ino} | 35 +++++++++++-------- .../CC1101_Transmit_Blocking.ino} | 29 +++++++++------ 2 files changed, 38 insertions(+), 26 deletions(-) rename examples/CC1101/{CC1101_Receive/CC1101_Receive.ino => CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino} (73%) rename examples/CC1101/{CC1101_Transmit/CC1101_Transmit.ino => CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino} (65%) diff --git a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino b/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino similarity index 73% rename from examples/CC1101/CC1101_Receive/CC1101_Receive.ino rename to examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino index e79ba1f0db..32dbe6bf15 100644 --- a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino +++ b/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino @@ -1,19 +1,24 @@ /* - RadioLib CC1101 Receive Example - - This example receives packets using CC1101 FSK radio module. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bit rate - - frequency deviation - - sync word - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib CC1101 Blocking Receive Example + + This example receives packets using CC1101 FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino similarity index 65% rename from examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino rename to examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index 4b2c960687..b01114a68e 100644 --- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -1,17 +1,21 @@ /* - RadioLib CC1101 Transmit Example + RadioLib CC1101 Blocking Transmit Example - This example transmits packets using CC1101 FSK radio module. - Each packet contains up to 64 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using CC1101 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -43,11 +47,14 @@ void setup() { } } +// use a counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 63 characters long - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 63 bytes long /* From 90368db27abdeae993c656bcde15a7ba55e76709 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 21:48:25 +0200 Subject: [PATCH 0627/1848] [nRF24] Renamed basic examples to _Blocking --- .../nRF24_Receive_Blocking.ino} | 28 +++++++++++-------- .../nRF24_Transmit_Blocking.ino} | 5 +++- 2 files changed, 20 insertions(+), 13 deletions(-) rename examples/nRF24/{nRF24_Receive/nRF24_Receive.ino => nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino} (72%) rename examples/nRF24/{nRF24_Transmit/nRF24_Transmit.ino => nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino} (95%) diff --git a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino b/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino similarity index 72% rename from examples/nRF24/nRF24_Receive/nRF24_Receive.ino rename to examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino index 4713141171..6ae29bbaff 100644 --- a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino +++ b/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino @@ -1,19 +1,23 @@ /* - RadioLib nRF24 Receive Example + RadioLib nRF24 Blocking Receive Example - This example listens for FSK transmissions using nRF24 2.4 GHz radio module. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - data rate - - transmit pipe on transmitter must match receive pipe - on receiver + This example listens for FSK transmissions using nRF24 2.4 GHz radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - data rate + - transmit pipe on transmitter must match receive pipe on receiver - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino similarity index 95% rename from examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino rename to examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino index 0b8c516c85..10a7963095 100644 --- a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino +++ b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino @@ -59,12 +59,15 @@ void setup() { } } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[nRF24] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to // 32 characters long - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted From 4981ce9934d03290f6472f2ef409af2b91604ed2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 21:50:30 +0200 Subject: [PATCH 0628/1848] [CC1101] Added packet counter --- .../CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino | 2 +- .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index b01114a68e..f9be306a3a 100644 --- a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -47,7 +47,7 @@ void setup() { } } -// use a counter to keep track of transmitted packets +// counter to keep track of transmitted packets int count = 0; void loop() { diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index ee88090aaf..752fac8a69 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -80,6 +80,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -113,7 +116,7 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* From be97ba85434628c3e64d7988b201caa2b7074f9a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 21:51:20 +0200 Subject: [PATCH 0629/1848] [nRF24] Added packet counter --- .../nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 05398fc40b..0df454afa1 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -95,6 +95,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -127,8 +130,8 @@ void loop() { Serial.print(F("[nRF24] Sending another packet ... ")); // you can transmit C-string or Arduino string up to - // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + // 32 characters long + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* From 18307f478d113f38bc2948ad15dd79b0d2003836 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 21:55:20 +0200 Subject: [PATCH 0630/1848] [RF69] Renamed basic examples to _Blocking --- .../RF69_Receive_Blocking.ino} | 35 +++++++++++-------- .../RF69_Transmit_Blocking.ino} | 29 +++++++++------ .../RF69_Transmit_Interrupt.ino | 9 +++-- 3 files changed, 44 insertions(+), 29 deletions(-) rename examples/RF69/{RF69_Receive/RF69_Receive.ino => RF69_Receive_Blocking/RF69_Receive_Blocking.ino} (70%) rename examples/RF69/{RF69_Transmit/RF69_Transmit.ino => RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino} (71%) diff --git a/examples/RF69/RF69_Receive/RF69_Receive.ino b/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino similarity index 70% rename from examples/RF69/RF69_Receive/RF69_Receive.ino rename to examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino index f38dcc44fb..a886b87dc6 100644 --- a/examples/RF69/RF69_Receive/RF69_Receive.ino +++ b/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino @@ -1,19 +1,24 @@ /* - RadioLib RF69 Receive Example - - This example receives packets using RF69 FSK radio module. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bit rate - - frequency deviation - - sync word - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib RF69 Blocking Receive Example + + This example receives packets using RF69 FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can miss some packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/RF69/RF69_Transmit/RF69_Transmit.ino b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino similarity index 71% rename from examples/RF69/RF69_Transmit/RF69_Transmit.ino rename to examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino index 8c6866d662..c229a74edd 100644 --- a/examples/RF69/RF69_Transmit/RF69_Transmit.ino +++ b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino @@ -1,17 +1,21 @@ /* - RadioLib RF69 Transmit Example + RadioLib RF69 Blocking Transmit Example - This example transmits packets using RF69 FSK radio module. - Each packet contains up to 64 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using RF69 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -59,11 +63,14 @@ void setup() { */ } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[RF69] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 64 characters long - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 64 bytes long /* diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index cd29c59cb1..68ba0d9335 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -96,6 +96,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -128,14 +131,14 @@ void loop() { Serial.print(F("[RF69] Sending another packet ... ")); // you can transmit C-string or Arduino string up to - // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + // 64 characters long + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } } From 06529844c3c1e6ac895f7ef6c323db33acfd9d21 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 21:59:18 +0200 Subject: [PATCH 0631/1848] [Si443x] Renamed basic examples to _Blocking --- .../Si443x_Receive_Blocking.ino} | 31 ++++++++++------- .../Si443x_Transmit_Blocking.ino} | 34 +++++++++++-------- .../Si443x_Transmit_Interrupt.ino | 29 +++++++++------- 3 files changed, 53 insertions(+), 41 deletions(-) rename examples/Si443x/{Si443x_Receive/Si443x_Receive.ino => Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino} (66%) rename examples/Si443x/{Si443x_Transmit/Si443x_Transmit.ino => Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino} (65%) diff --git a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino b/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino similarity index 66% rename from examples/Si443x/Si443x_Receive/Si443x_Receive.ino rename to examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino index b5ab2485f9..54715ffa84 100644 --- a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino +++ b/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino @@ -1,21 +1,26 @@ /* - RadioLib Si443x Receive Example + RadioLib Si443x Blocking Receive Example - This example receives packets using Si443x FSK radio module. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bit rate - - frequency deviation - - sync word + This example receives packets using Si443x FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word - Other modules from Si443x/RFM2x family can also be used. + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + Other modules from Si443x/RFM2x family can also be used. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino similarity index 65% rename from examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino rename to examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino index 2eddf96eeb..10bb994267 100644 --- a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino +++ b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino @@ -1,19 +1,23 @@ /* - RadioLib Si443x Transmit Example + RadioLib Si443x Blocking Transmit Example - This example transmits packets using Si4432 FSK radio module. - Each packet contains up to 64 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using Si4432 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from Si443x/RFM2x family can also be used. + Other modules from Si443x/RFM2x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -44,15 +48,15 @@ void setup() { } } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[Si4432] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to // 64 characters long - // NOTE: transmit() is a blocking method! - // See example Si443x_Transmit_Interrupt for details - // on non-blocking transmission method. - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 64 bytes long /* diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index b13bcafc56..1e064a910a 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -1,19 +1,19 @@ /* - RadioLib Si443x Transmit with Interrupts Example + RadioLib Si443x Transmit with Interrupts Example - This example transmits packets using Si4432 FSK radio module. - Each packet contains up to 64 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using Si4432 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from Si443x/RFM2x family can also be used. + Other modules from Si443x/RFM2x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -80,6 +80,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -109,13 +112,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } } From 9bad00ed39cb6cd36297a6ee984a4f329eb92246 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:03:28 +0200 Subject: [PATCH 0632/1848] [STM32WL] Renamed basic examples to _Blocking --- .../STM32WLx_Receive_Blocking.ino} | 48 ++++++++++--------- .../STM32WLx_Transmit_Blocking.ino} | 42 ++++++++-------- .../STM32WLx_Transmit_Interrupt.ino | 29 ++++++----- 3 files changed, 64 insertions(+), 55 deletions(-) rename examples/STM32WLx/{STM32WLx_Receive/STM32WLx_Receive.ino => STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino} (73%) rename examples/STM32WLx/{STM32WLx_Transmit/STM32WLx_Transmit.ino => STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino} (71%) diff --git a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino similarity index 73% rename from examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino rename to examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino index b5f159657c..ae2cbdb192 100644 --- a/examples/STM32WLx/STM32WLx_Receive/STM32WLx_Receive.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino @@ -1,27 +1,32 @@ /* - RadioLib STM32WLx Receive Example - - This example listens for LoRa transmissions using STM32WL MCU with - integrated (SX126x) LoRa radio. - - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - preamble length + RadioLib STM32WLx Blocking Receive Example + + This example listens for LoRa transmissions using STM32WL MCU with + integrated (SX126x) LoRa radio. + + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length - This example assumes Nucleo WL55JC1 is used. For other Nucleo boards - or standalone STM32WL, some configuration such as TCXO voltage and - RF switch control may have to be adjusted. + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -75,9 +80,6 @@ void loop() { Serial.print(F("[STM32WL] Waiting for incoming transmission ... ")); // you can receive data as an Arduino String - // NOTE: receive() is a blocking method! - // See example ReceiveInterrupt for details - // on non-blocking reception method. String str; int state = radio.receive(str); diff --git a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino similarity index 71% rename from examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino rename to examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino index 7455cafd6b..961a475453 100644 --- a/examples/STM32WLx/STM32WLx_Transmit/STM32WLx_Transmit.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -1,23 +1,27 @@ /* - RadioLib STM32WLx Transmit Example + RadioLib STM32WLx Blocking Transmit Example - This example transmits packets using STM32WL MCU with integrated - (SX126x) LoRa radio. + This example transmits packets using STM32WL MCU with integrated + (SX126x) LoRa radio. - Each packet contains up to 256 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) - - This example assumes Nucleo WL55JC1 is used. For other Nucleo boards - or standalone STM32WL, some configuration such as TCXO voltage and - RF switch control may have to be adjusted. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -67,15 +71,15 @@ void setup() { } } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[STM32WL] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to // 256 characters long - // NOTE: transmit() is a blocking method! - // See example STM32WLx_Transmit_Interrupt for details - // on non-blocking transmission method. - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index 900e52d204..bcd3f718de 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -1,18 +1,18 @@ /* - RadioLib STM32WLx Transmit with Interrupts Example + RadioLib STM32WLx Transmit with Interrupts Example - This example transmits LoRa packets with one second delays - between them. Each packet contains up to 256 bytes - of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -95,6 +95,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -128,13 +131,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } } From 24be1747d01555eb6c5db171084956735ab3d06c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:12:11 +0200 Subject: [PATCH 0633/1848] [SX126x] Renamed basic examples to _Blocking --- ...x_Channel_Activity_Detection_Blocking.ino} | 25 ++++++++------ .../SX126x_Receive_Blocking.ino} | 10 +++--- .../SX126x_Transmit_Blocking.ino} | 34 +++++++++++-------- .../SX126x_Transmit_Interrupt.ino | 31 +++++++++-------- 4 files changed, 57 insertions(+), 43 deletions(-) rename examples/SX126x/{SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino => SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino} (64%) rename examples/SX126x/{SX126x_Receive/SX126x_Receive.ino => SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino} (91%) rename examples/SX126x/{SX126x_Transmit/SX126x_Transmit.ino => SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino} (71%) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino similarity index 64% rename from examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino rename to examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino index 850347a2ff..0d2380dd76 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino @@ -1,18 +1,23 @@ /* - RadioLib SX126x Channel Activity Detection Example + RadioLib SX126x Blocking Channel Activity Detection Example - This example uses SX1262 to scan the current LoRa - channel and detect ongoing LoRa transmissions. - Unlike SX127x CAD, SX126x can detect any part - of LoRa transmission, not just the preamble. + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. - Other modules from SX126x family can also be used. + Other modules from SX126x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino similarity index 91% rename from examples/SX126x/SX126x_Receive/SX126x_Receive.ino rename to examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino index d00f4f6409..75fda8f65a 100644 --- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino +++ b/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino @@ -1,5 +1,5 @@ /* - RadioLib SX126x Receive Example + RadioLib SX126x Blocking Receive Example This example listens for LoRa transmissions using SX126x Lora modules. To successfully receive data, the following settings have to be the same @@ -13,6 +13,11 @@ Other modules from SX126x family can also be used. + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem @@ -56,9 +61,6 @@ void loop() { Serial.print(F("[SX1262] Waiting for incoming transmission ... ")); // you can receive data as an Arduino String - // NOTE: receive() is a blocking method! - // See example ReceiveInterrupt for details - // on non-blocking reception method. String str; int state = radio.receive(str); diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino similarity index 71% rename from examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino rename to examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino index a287034ed9..a9aa4953dc 100644 --- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino +++ b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino @@ -1,19 +1,23 @@ /* - RadioLib SX126x Transmit Example + RadioLib SX126x Blocking Transmit Example - This example transmits packets using SX1262 LoRa radio module. - Each packet contains up to 256 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using SX1262 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX126x family can also be used. + Other modules from SX126x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -58,15 +62,15 @@ void setup() { */ } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[SX1262] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to // 256 characters long - // NOTE: transmit() is a blocking method! - // See example SX126x_Transmit_Interrupt for details - // on non-blocking transmission method. - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 6bf9be2bc0..20acbcb4a0 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -1,20 +1,20 @@ /* - RadioLib SX126x Transmit with Interrupts Example + RadioLib SX126x Transmit with Interrupts Example - This example transmits LoRa packets with one second delays - between them. Each packet contains up to 256 bytes - of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX126x family can also be used. + Other modules from SX126x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -85,6 +85,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -118,13 +121,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } } From c9191858492c50c56ab6c8b21870d79cb929082c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:12:53 +0200 Subject: [PATCH 0634/1848] [SX127x] Renamed basic examples to _Blocking --- ...x_Channel_Activity_Detection_Blocking.ino} | 27 ++++++----- .../SX127x_Receive_Blocking.ino} | 46 ++++++++++--------- .../SX127x_Transmit_Blocking.ino} | 34 ++++++++------ .../SX127x_Transmit_Interrupt.ino | 30 ++++++------ 4 files changed, 74 insertions(+), 63 deletions(-) rename examples/SX127x/{SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino => SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino} (58%) rename examples/SX127x/{SX127x_Receive/SX127x_Receive.ino => SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino} (72%) rename examples/SX127x/{SX127x_Transmit/SX127x_Transmit.ino => SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino} (70%) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino similarity index 58% rename from examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino rename to examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino index ad7126d434..6a23001aa5 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino @@ -1,19 +1,24 @@ /* - RadioLib SX127x Channel Activity Detection Example + RadioLib SX127x Blocking Channel Activity Detection Example - This example scans the current LoRa channel and detects - valid LoRa preambles. Preamble is the first part of - LoRa transmission, so this can be used to check - if the LoRa channel is free, or if you should start - receiving a message. + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino similarity index 72% rename from examples/SX127x/SX127x_Receive/SX127x_Receive.ino rename to examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino index e67fbc82b4..bdfae6d5e8 100644 --- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino +++ b/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino @@ -1,23 +1,28 @@ /* - RadioLib SX127x Receive Example - - This example listens for LoRa transmissions using SX127x Lora modules. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - preamble length - - Other modules from SX127x/RFM9x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX127x Blocking Receive Example + + This example listens for LoRa transmissions using SX127x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from SX127x/RFM9x family can also be used. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -53,9 +58,6 @@ void loop() { Serial.print(F("[SX1278] Waiting for incoming transmission ... ")); // you can receive data as an Arduino String - // NOTE: receive() is a blocking method! - // See example ReceiveInterrupt for details - // on non-blocking reception method. String str; int state = radio.receive(str); diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino similarity index 70% rename from examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino rename to examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino index f8c0533a33..467b11e987 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino @@ -1,19 +1,23 @@ /* - RadioLib SX127x Transmit Example + RadioLib SX127x Blocking Transmit Example - This example transmits packets using SX1278 LoRa radio module. - Each packet contains up to 255 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 255 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -55,15 +59,15 @@ void setup() { */ } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[SX1278] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to // 255 characters long - // NOTE: transmit() is a blocking method! - // See example SX127x_Transmit_Interrupt for details - // on non-blocking transmission method. - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index b0551083ef..640eec5aed 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -1,20 +1,20 @@ /* - RadioLib SX127x Transmit with Interrupts Example + RadioLib SX127x Transmit with Interrupts Example - This example transmits LoRa packets with one second delays - between them. Each packet contains up to 255 bytes - of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 255 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -63,7 +63,7 @@ void setup() { /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } @@ -115,13 +115,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 255 characters long - transmissionState = radio.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 255 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } } From 3a07f0aa022d01e60f2895088812cb5bc8eeef39 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:17:13 +0200 Subject: [PATCH 0635/1848] [SX128x] Renamed basic examples to _Blocking --- ...x_Channel_Activity_Detection_Blocking.ino} | 21 ++++++----- .../SX128x_Receive_Blocking.ino} | 36 ++++++++++--------- .../SX128x_Transmit_Blocking.ino} | 34 ++++++++++-------- .../SX128x_Transmit_Interrupt.ino | 31 ++++++++-------- 4 files changed, 68 insertions(+), 54 deletions(-) rename examples/SX128x/{SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino => SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino} (65%) rename examples/SX128x/{SX128x_Receive/SX128x_Receive.ino => SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino} (74%) rename examples/SX128x/{SX128x_Transmit/SX128x_Transmit.ino => SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino} (70%) diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino similarity index 65% rename from examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino rename to examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino index 96b1cb7213..fef3ccc0e8 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino @@ -1,16 +1,21 @@ /* - RadioLib SX128x Channel Activity Detection Example + RadioLib SX128x Blocking Channel Activity Detection Example - This example uses SX1280 to scan the current LoRa - channel and detect ongoing LoRa transmissions. + This example uses SX1280 to scan the current LoRa + channel and detect ongoing LoRa transmissions. - Other modules from SX128x family can also be used. + Other modules from SX128x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino b/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino similarity index 74% rename from examples/SX128x/SX128x_Receive/SX128x_Receive.ino rename to examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino index 28dc8047cb..2ba27130a4 100644 --- a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino +++ b/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino @@ -1,23 +1,28 @@ /* - RadioLib SX128x Receive Example + RadioLib SX128x Blocking Receive Example - This example listens for LoRa transmissions using SX126x Lora modules. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - preamble length + This example listens for LoRa transmissions using SX126x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length - Other modules from SX128x family can also be used. + Other modules from SX128x family can also be used. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -53,9 +58,6 @@ void loop() { Serial.print(F("[SX1280] Waiting for incoming transmission ... ")); // you can receive data as an Arduino String - // NOTE: receive() is a blocking method! - // See example ReceiveInterrupt for details - // on non-blocking reception method. String str; int state = radio.receive(str); diff --git a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino similarity index 70% rename from examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino rename to examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino index e525698aa6..cc222a61a6 100644 --- a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino +++ b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino @@ -1,19 +1,23 @@ /* - RadioLib SX128x Transmit Example + RadioLib SX128x Blocking Transmit Example - This example transmits packets using SX1280 LoRa radio module. - Each packet contains up to 256 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using SX1280 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX128x family can also be used. + Other modules from SX128x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -62,15 +66,15 @@ void setup() { */ } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[SX1280] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to // 256 characters long - // NOTE: transmit() is a blocking method! - // See example SX128x_Transmit_Interrupt for details - // on non-blocking transmission method. - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 9a49003087..21252f622e 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -1,20 +1,20 @@ /* - RadioLib SX128x Transmit with Interrupts Example + RadioLib SX128x Transmit with Interrupts Example - This example transmits LoRa packets with one second delays - between them. Each packet contains up to 256 bytes - of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX128x family can also be used. + Other modules from SX128x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -82,6 +82,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { @@ -111,13 +114,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.startTransmit(byteArr, 8); + transmissionState = radio.startTransmit(byteArr, 8); */ } } From 2dafa830585467350c3942fffb8370cfdf213239 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:18:59 +0200 Subject: [PATCH 0636/1848] [SX1231] Renamed basic examples to _Blocking --- .../SX1231/SX1231_Receive/SX1231_Receive.ino | 23 +++++++++------- .../SX1231_Transmit/SX1231_Transmit.ino | 27 ++++++++++++------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino index cd3efea455..9071e31007 100644 --- a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino +++ b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino @@ -1,17 +1,22 @@ /* - RadioLib SX1231 Receive Example + RadioLib SX1231 Blocking Receive Example - This example receives packets using SX1231 FSK radio module. + This example receives packets using SX1231 FSK radio module. - NOTE: SX1231 offers the same features as RF69 and has the same - interface. Please see RF69 examples for examples on AES, - address filtering, interrupts and settings. + NOTE: SX1231 offers the same features as RF69 and has the same + interface. Please see RF69 examples for examples on AES, + address filtering, interrupts and settings. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino index 44db4556d7..6dd4e3f09f 100644 --- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino +++ b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino @@ -1,17 +1,21 @@ /* - RadioLib SX1231 Transmit Example + RadioLib SX1231 Blocking Transmit Example - This example transmits packets using SX1231 FSK radio module. + This example transmits packets using SX1231 FSK radio module. - NOTE: SX1231 offers the same features as RF69 and has the same - interface. Please see RF69 examples for examples on AES, - address filtering, interrupts and settings. + NOTE: SX1231 offers the same features as RF69 and has the same + interface. Please see RF69 examples for examples on AES, + address filtering, interrupts and settings. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -42,11 +46,14 @@ void setup() { } } +// counter to keep track of transmitted packets +int count = 0; + void loop() { Serial.print(F("[SX1231] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 256 characters long - int state = radio.transmit("Hello World!"); + int state = radio.transmit("Hello World! #" + String(count++)); // you can also transmit byte array up to 256 bytes long /* From 4975828d034ddbec585a44ec1abf20d804915273 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:22:56 +0200 Subject: [PATCH 0637/1848] [SX126x] Fixed debug print format --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 95aeafcd4d..2ece718d63 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -631,7 +631,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz); uint32_t sleepPeriod = symbolLength * sleepSymbols; - RADIOLIB_DEBUG_PRINTLN("Auto sleep period: %d", sleepPeriod); + RADIOLIB_DEBUG_PRINTLN("Auto sleep period: %lu", sleepPeriod); // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. // the duration is sleepPeriod + 2 * wakePeriod. From 4949d10b00dc617d904f273a034530f1f5a3d789 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:23:14 +0200 Subject: [PATCH 0638/1848] [CI] Fixed CodeQL build example --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d95c71d9b6..78230b2569 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -60,7 +60,7 @@ jobs: - name: Build example run: - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:uno $PWD/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino --warnings=all + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:uno $PWD/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino --warnings=all - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 From 43ff5906c25da1d116773200431d21dfa7dd0f38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jun 2023 22:24:49 +0200 Subject: [PATCH 0639/1848] [SX127x] Added missing counter --- .../SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 640eec5aed..041ba597df 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -82,6 +82,9 @@ void setFlag(void) { transmittedFlag = true; } +// counter to keep track of transmitted packets +int count = 0; + void loop() { // check if the previous transmission finished if(transmittedFlag) { From 8acaca488402fae8481da9f16a6f859315ab3421 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 25 Jun 2023 09:33:17 +0200 Subject: [PATCH 0640/1848] [SX127x] Swap Tx IQ inversion (#778) --- src/modules/SX127x/SX127x.cpp | 10 ++++++---- src/modules/SX127x/SX127x.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 467bbecd6e..4e9d5adcc5 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1503,20 +1503,22 @@ void SX127x::clearFIFO(size_t count) { } } -int16_t SX127x::invertIQ(bool invertIQ) { +int16_t SX127x::invertIQ(bool enable) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } + // Tx path inversion is swapped, because it seems that setting it according to the datsheet + // will actually lead to the wrong inversion. See https://github.com/jgromes/RadioLib/issues/778 int16_t state; - if(invertIQ) { + if(enable) { state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE); } else { state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0); state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE); } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 951ee31baa..dcd84790dd 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1086,10 +1086,10 @@ class SX127x: public PhysicalLayer { /*! \brief Enable/disable inversion of the I and Q signals - \param invertIQ QI inversion enabled (true) or disabled (false); + \param enable QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ - int16_t invertIQ(bool invertIQ); + int16_t invertIQ(bool enable); #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! From a01b02fae207b62a5e605484822606e751c8f308 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 19:36:45 +0200 Subject: [PATCH 0641/1848] [MOD] Rework for buffered SPI (#776) --- src/ArduinoHal.cpp | 6 +- src/ArduinoHal.h | 2 +- src/Hal.cpp | 8 +- src/Hal.h | 9 +- src/Module.cpp | 225 ++++++++++++++++++---------------- src/modules/CC1101/CC1101.cpp | 3 +- src/modules/nRF24/nRF24.cpp | 46 ++++--- 7 files changed, 165 insertions(+), 134 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index fe471c155f..d42f0d0ba5 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -84,8 +84,10 @@ void inline ArduinoHal::spiBeginTransaction() { spi->beginTransaction(spiSettings); } -uint8_t inline ArduinoHal::spiTransfer(uint8_t b) { - return(spi->transfer(b)); +void ArduinoHal::spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + for(size_t i = 0; i < len; i++) { + in[i] = spi->transfer(out[i]); + } } void inline ArduinoHal::spiEndTransaction() { diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 69fe50f534..59b0f1aa16 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -47,7 +47,7 @@ class ArduinoHal : public RadioLibHal { long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override; void spiBegin() override; void spiBeginTransaction() override; - uint8_t spiTransfer(uint8_t b) override; + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) override; void spiEndTransaction() override; void spiEnd() override; diff --git a/src/Hal.cpp b/src/Hal.cpp index 0961fa4f85..1a42aa15a7 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -20,16 +20,16 @@ void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long durat (void)pin; (void)frequency; (void)duration; -}; +} void RadioLibHal::noTone(uint32_t pin) { (void)pin; -}; +} void RadioLibHal::yield() { -}; +} uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); -}; +} diff --git a/src/Hal.h b/src/Hal.h index 64bfea2f0c..87fb561e3b 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -146,11 +146,12 @@ class RadioLibHal { virtual void spiBeginTransaction() = 0; /*! - \brief Method to transfer one byte over SPI. - \param b Byte to send. - \returns Received byte. + \brief Method to transfer buffer over SPI. + \param out Buffer to send. + \param len Number of data to send or receive. + \param in Buffer to save received data into. */ - virtual uint8_t spiTransfer(uint8_t b) = 0; + virtual void spiTransfer(uint8_t* out, size_t len, uint8_t* in) = 0; /*! \brief Method to end SPI transaction. diff --git a/src/Module.cpp b/src/Module.cpp index 3959dee86b..37da31d6dc 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -139,52 +139,64 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { } void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { - // start SPI transaction - this->hal->spiBeginTransaction(); - - // pull CS low - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); + // prepare the buffers + size_t buffLen = this->SPIaddrWidth/8 + numBytes; + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; - // send SPI register address with access command + // copy the command if(this->SPIaddrWidth <= 8) { - this->hal->spiTransfer(reg | cmd); + *(buffOutPtr++) = reg | cmd; } else { - this->hal->spiTransfer((reg >> 8) | cmd); - this->hal->spiTransfer(reg & 0xFF); + *(buffOutPtr++) = (reg >> 8) | cmd; + *(buffOutPtr++) = reg & 0xFF; + } + + // copy the data + if(cmd == SPIwriteCommand) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, this->SPInopCommand, numBytes); + } + + // do the transfer + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); + this->hal->spiBeginTransaction(); + this->hal->spiTransfer(buffOut, buffLen, buffIn); + this->hal->spiEndTransaction(); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + + // copy the data + if(cmd == SPIreadCommand) { + memcpy(dataIn, &buffIn[this->SPIaddrWidth/8], numBytes); } + // print debug information #if defined(RADIOLIB_VERBOSE) + uint8_t* debugBuffPtr = NULL; if(cmd == SPIwriteCommand) { - RADIOLIB_VERBOSE_PRINT("W"); + RADIOLIB_VERBOSE_PRINT("W\t%X\t", reg); + debugBuffPtr = &buffOut[this->SPIaddrWidth/8]; } else if(cmd == SPIreadCommand) { - RADIOLIB_VERBOSE_PRINT("R"); - } - RADIOLIB_VERBOSE_PRINT("\t%X\t", reg); - #endif - - // send data or get response - if(cmd == SPIwriteCommand) { - if(dataOut != NULL) { - for(size_t n = 0; n < numBytes; n++) { - this->hal->spiTransfer(dataOut[n]); - RADIOLIB_VERBOSE_PRINT("%X\t", dataOut[n]); - } + RADIOLIB_VERBOSE_PRINT("R\t%X\t", reg); + debugBuffPtr = &buffIn[this->SPIaddrWidth/8]; } - } else if (cmd == SPIreadCommand) { - if(dataIn != NULL) { - for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->hal->spiTransfer(0x00); - RADIOLIB_VERBOSE_PRINT("%X\t", dataIn[n]); - } + for(size_t n = 0; n < numBytes; n++) { + RADIOLIB_VERBOSE_PRINT("%X\t", debugBuffPtr[n]); } - } - RADIOLIB_VERBOSE_PRINTLN(); - - // release CS - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + RADIOLIB_VERBOSE_PRINTLN(); + #endif - // end SPI transaction - this->hal->spiEndTransaction(); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif } int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { @@ -241,9 +253,31 @@ int16_t Module::SPIcheckStream() { } int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) { - #if defined(RADIOLIB_VERBOSE) - uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + // prepare the buffers + size_t buffLen = cmdLen + numBytes; + if(!write) { + buffLen++; + } + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; #endif + uint8_t* buffOutPtr = buffOut; + + // copy the command + for(uint8_t n = 0; n < cmdLen; n++) { + *(buffOutPtr++) = cmd[n]; + } + + // copy the data + if(write) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, this->SPInopCommand, numBytes + 1); + } // ensure GPIO is low if(this->gpioPin == RADIOLIB_NC) { @@ -253,64 +287,20 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?"); + RADIOLIB_DEBUG_PRINTLN("GPIO pre-transfer timeout, is it connected?"); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } } - // pull NSS low + // do the transfer this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); - - // start transfer this->hal->spiBeginTransaction(); - - // send command byte(s) - for(uint8_t n = 0; n < cmdLen; n++) { - this->hal->spiTransfer(cmd[n]); - } - - // variable to save error during SPI transfer - int16_t state = RADIOLIB_ERR_NONE; - - // send/receive all bytes - if(write) { - for(size_t n = 0; n < numBytes; n++) { - // send byte - uint8_t in = this->hal->spiTransfer(dataOut[n]); - #if defined(RADIOLIB_VERBOSE) - debugBuff[n] = in; - #endif - - // check status - if(this->SPIparseStatusCb != nullptr) { - state = this->SPIparseStatusCb(in); - } - } - - } else { - // skip the first byte for read-type commands (status-only) - uint8_t in = this->hal->spiTransfer(this->SPInopCommand); - #if defined(RADIOLIB_VERBOSE) - debugBuff[0] = in; - #endif - - // check status - if(this->SPIparseStatusCb != nullptr) { - state = this->SPIparseStatusCb(in); - } else { - state = RADIOLIB_ERR_NONE; - } - - // read the data - if(state == RADIOLIB_ERR_NONE) { - for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->hal->spiTransfer(this->SPInopCommand); - } - } - } - - // stop transfer + this->hal->spiTransfer(buffOut, buffLen, buffIn); this->hal->spiEndTransaction(); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); @@ -324,39 +314,60 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; - break; + RADIOLIB_DEBUG_PRINTLN("GPIO post-transfer timeout, is it connected?"); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } } } - // print debug output + // parse status + int16_t state = RADIOLIB_ERR_NONE; + if(this->SPIparseStatusCb != nullptr) { + state = this->SPIparseStatusCb(buffIn[0]); + } + + // copy the data + if(!write) { + // skip the first byte for read-type commands (status-only) + memcpy(dataIn, &buffIn[cmdLen + 1], numBytes); + } + + // print debug information #if defined(RADIOLIB_VERBOSE) // print command byte(s) - RADIOLIB_VERBOSE_PRINT("CMD\t"); - for(uint8_t n = 0; n < cmdLen; n++) { + RADIOLIB_VERBOSE_PRINT("CMD"); + if(write) { + RADIOLIB_VERBOSE_PRINT("W\t"); + } else { + RADIOLIB_VERBOSE_PRINT("R\t"); + } + size_t n = 0; + for(; n < cmdLen; n++) { RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]); } RADIOLIB_VERBOSE_PRINTLN(); // print data bytes - RADIOLIB_VERBOSE_PRINT("DAT"); - if(write) { - RADIOLIB_VERBOSE_PRINT("W\t"); - for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t%X\t", dataOut[n], debugBuff[n]); - } - RADIOLIB_VERBOSE_PRINTLN(); - } else { - RADIOLIB_VERBOSE_PRINT("R\t%X\t%X\t", this->SPInopCommand, debugBuff[0]); - - for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t%X\t", this->SPInopCommand, dataIn[n]); - } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_VERBOSE_PRINT("SI\t"); + for(; n < buffLen; n++) { + RADIOLIB_VERBOSE_PRINT("%X\t", buffOut[n]); } RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_VERBOSE_PRINT("SO\t"); + for(n = cmdLen; n < buffLen; n++) { + RADIOLIB_VERBOSE_PRINT("%X\t", buffIn[n]); + } + RADIOLIB_VERBOSE_PRINTLN(); + #endif + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; #endif return(state); diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 52a9b6bc91..235ef13df2 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1181,7 +1181,8 @@ void CC1101::SPIsendCommand(uint8_t cmd) { this->mod->hal->spiBeginTransaction(); // send the command byte - uint8_t status = this->mod->hal->spiTransfer(cmd); + uint8_t status = 0; + this->mod->hal->spiTransfer(&cmd, 1, &status); // stop transfer this->mod->hal->spiEndTransaction(); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 3257187b42..c48b5b17fa 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -615,27 +615,43 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { } void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { - // start transfer - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - this->mod->hal->spiBeginTransaction(); - - // send command - this->mod->hal->spiTransfer(cmd); - - // send data + // prepare the buffers + size_t buffLen = 1 + numBytes; + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; + + // copy the command + *(buffOutPtr++) = cmd; + + // copy the data if(write) { - for(uint8_t i = 0; i < numBytes; i++) { - this->mod->hal->spiTransfer(dataOut[i]); - } + memcpy(buffOutPtr, dataOut, numBytes); } else { - for(uint8_t i = 0; i < numBytes; i++) { - dataIn[i] = this->mod->hal->spiTransfer(0x00); - } + memset(buffOutPtr, 0x00, numBytes); } - // stop transfer + // do the transfer + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + this->mod->hal->spiBeginTransaction(); + this->mod->hal->spiTransfer(buffOut, buffLen, buffIn); this->mod->hal->spiEndTransaction(); this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + + // copy the data + if(!write) { + memcpy(dataIn, &buffIn[1], numBytes); + } + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif } #endif From f4f11a35d357519e5483ad1a61b96ab72a0ac5ed Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 19:39:10 +0200 Subject: [PATCH 0642/1848] [Mod] Updated examples to use buffered SPI (#776) --- examples/NonArduino/ESP-IDF/main/EspHal.h | 8 +++++++- examples/NonArduino/Raspberry/PiHal.h | 6 ++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/NonArduino/ESP-IDF/main/EspHal.h b/examples/NonArduino/ESP-IDF/main/EspHal.h index a4f64d1cfa..340adbd630 100644 --- a/examples/NonArduino/ESP-IDF/main/EspHal.h +++ b/examples/NonArduino/ESP-IDF/main/EspHal.h @@ -285,7 +285,7 @@ class EspHal : public RadioLibHal { // repeats clock div, mode and bit order configuration } - uint8_t spiTransfer(uint8_t b) { + uint8_t spiTransferByte(uint8_t b) { this->spi->mosi_dlen.usr_mosi_dbitlen = 7; this->spi->miso_dlen.usr_miso_dbitlen = 7; this->spi->data_buf[0] = b; @@ -294,6 +294,12 @@ class EspHal : public RadioLibHal { return(this->spi->data_buf[0] & 0xFF); } + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + for(size_t i = 0; i < len; i++) { + in[i] = this->spiTransferByte(out[i]); + } + } + void spiEndTransaction() { // nothing needs to be done here } diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 5a94fe8d2a..695dc5233a 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -128,10 +128,8 @@ class PiHal : public RadioLibHal { void spiBeginTransaction() {} - uint8_t spiTransfer(uint8_t b) { - char ret; - spiXfer(_spiHandle, (char*)&b, &ret, 1); - return(ret); + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + spiXfer(_spiHandle, (char*)out, in, len); } void spiEndTransaction() {} From a4dbae03a3b34bbfc0320cb4a1ed0d53f1687e58 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 19:41:12 +0200 Subject: [PATCH 0643/1848] [MOD] Fixed missing cast (#776) --- examples/NonArduino/Raspberry/PiHal.h | 2 +- extras/test/SX126x/PiHal.h | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 695dc5233a..8394ad23dc 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -129,7 +129,7 @@ class PiHal : public RadioLibHal { void spiBeginTransaction() {} void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { - spiXfer(_spiHandle, (char*)out, in, len); + spiXfer(_spiHandle, (char*)out, (char*)in, len); } void spiEndTransaction() {} diff --git a/extras/test/SX126x/PiHal.h b/extras/test/SX126x/PiHal.h index e8c27db03e..9bf4f8f183 100644 --- a/extras/test/SX126x/PiHal.h +++ b/extras/test/SX126x/PiHal.h @@ -127,11 +127,9 @@ class PiHal : public RadioLibHal { } void spiBeginTransaction() {} - - uint8_t spiTransfer(uint8_t b) { - char ret; - spiXfer(_spiHandle, (char*)&b, &ret, 1); - return(ret); + + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + spiXfer(_spiHandle, (char*)out, (char*)in, len); } void spiEndTransaction() {} From 1881381caab25b837317da5883fa4a8bed0e23f6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 19:56:28 +0200 Subject: [PATCH 0644/1848] [CI] Fix missing pipe --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b5c76bfee0..ef8e37d3f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,7 +70,7 @@ jobs: echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - id: esp32:esp32:esp32 - run: + run: | python -m pip install pyserial echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT - id: esp8266:esp8266:generic From 523f28fd6b8d0ab962adaacf6f404ee2d4a481b3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 20:18:01 +0200 Subject: [PATCH 0645/1848] Bump version to 6.1.0 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index 222d7258a3..a12059531e 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.0.0", + "version": "6.1.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 88368d53f1..e2f70317b3 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.0.0 +version=6.1.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index db8184c7b0..d0572f69ca 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -473,7 +473,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x06) -#define RADIOLIB_VERSION_MINOR (0x00) +#define RADIOLIB_VERSION_MINOR (0x01) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From 64b9c669dde2c9e7055fa3c0a0d141e22fae30dd Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 20:22:32 +0200 Subject: [PATCH 0646/1848] [CI] Skip Pager for Arduino Leonardo --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ef8e37d3f1..c75cdc6c0b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,6 +50,7 @@ jobs: - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - id: arduino:avr:leonardo + run: echo "skip-pattern=(STM32WL|SSTV|Pager)" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble - id: arduino:mbed:envie_m4 - id: arduino:megaavr:uno2018 From 58c9e9fe0313b64bca4eefd52d2c3b35ca195823 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 20:39:33 +0200 Subject: [PATCH 0647/1848] Fixed String counters in examples (CI_BUILD_ALL) --- .../CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino | 3 ++- .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 3 ++- .../RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino | 3 ++- .../RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino | 3 ++- .../STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino | 3 ++- .../STM32WLx_Transmit_Interrupt.ino | 3 ++- examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino | 3 ++- .../SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino | 3 ++- .../SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino | 3 ++- .../SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino | 3 ++- .../SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino | 3 ++- .../SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino | 3 ++- .../SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino | 3 ++- .../Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino | 3 ++- .../Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino | 3 ++- .../nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino | 3 ++- .../nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino | 3 ++- 17 files changed, 34 insertions(+), 17 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index f9be306a3a..fc62ec6364 100644 --- a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -54,7 +54,8 @@ void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 63 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 63 bytes long /* diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 752fac8a69..455d83ddff 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -116,7 +116,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino index c229a74edd..0a4897805a 100644 --- a/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino +++ b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino @@ -70,7 +70,8 @@ void loop() { Serial.print(F("[RF69] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 64 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 64 bytes long /* diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 68ba0d9335..b168af7301 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -132,7 +132,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 64 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 64 bytes long /* diff --git a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino index 961a475453..3d2e354085 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -79,7 +79,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index bcd3f718de..527c897cee 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -131,7 +131,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino index 6dd4e3f09f..02a883b412 100644 --- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino +++ b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino @@ -53,7 +53,8 @@ void loop() { Serial.print(F("[SX1231] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 256 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino index a9aa4953dc..8cf890eb5e 100644 --- a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino +++ b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino @@ -70,7 +70,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 20acbcb4a0..be281597a1 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -121,7 +121,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino index 467b11e987..2298ac2cb0 100644 --- a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino +++ b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino @@ -67,7 +67,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 255 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 041ba597df..7cdce59379 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -118,7 +118,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 255 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 255 bytes long /* diff --git a/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino index cc222a61a6..18a26c9790 100644 --- a/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino +++ b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino @@ -74,7 +74,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 21252f622e..811743da2c 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -114,7 +114,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 256 bytes long /* diff --git a/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino index 10bb994267..7197281a97 100644 --- a/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino +++ b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino @@ -56,7 +56,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 64 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); // you can also transmit byte array up to 64 bytes long /* diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 1e064a910a..685574746e 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -112,7 +112,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 64 bytes long /* diff --git a/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino index 10a7963095..402a3cffc8 100644 --- a/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino +++ b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino @@ -67,7 +67,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 32 characters long - int state = radio.transmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); if (state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 0df454afa1..55834b8d78 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -131,7 +131,8 @@ void loop() { // you can transmit C-string or Arduino string up to // 32 characters long - transmissionState = radio.startTransmit("Hello World! #" + String(count++)); + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); // you can also transmit byte array up to 256 bytes long /* From d1f7c182402ecc1a2e6a1eba95115d19e9d539aa Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jun 2023 07:28:57 +0200 Subject: [PATCH 0648/1848] Added support for Arduino Uno R4 --- .github/workflows/main.yml | 1 + README.md | 1 + src/BuildOpt.h | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c75cdc6c0b..4bcb17b178 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -105,6 +105,7 @@ jobs: run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT - id: teensy:avr:teensy41 run: echo "index-url=--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT + - id: arduino:renesas_uno:minima runs-on: ubuntu-latest name: ${{ matrix.id }} diff --git a/README.md b/README.md index 36228634f7..ede2443455 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__megaAVR__](https://github.com/arduino/ArduinoCore-megaavr) - Arduino Uno WiFi Rev.2 and Nano Every * [__SAM__](https://github.com/arduino/ArduinoCore-sam) - Arduino Due * [__SAMD__](https://github.com/arduino/ArduinoCore-samd) - Arduino Zero, MKR boards, M0 Pro etc. + * [__Renesas__](https://github.com/arduino/ArduinoCore-renesas) - Arduino Uno R4 * __Adafruit__ * [__SAMD__](https://github.com/adafruit/ArduinoCore-samd) - Adafruit Feather M0 and M4 boards (Feather, Metro, Gemma, Trinket etc.) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index d0572f69ca..53d104d0d1 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -242,6 +242,13 @@ // Teensy #define RADIOLIB_PLATFORM "Teensy" +#elif defined(ARDUINO_ARCH_RENESAS) + // Arduino Renesas (UNO R4) + #define RADIOLIB_PLATFORM "Arduino Renesas (UNO R4)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" From 9c2d457eeba29e661e86b91209875d22953f3b0d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jun 2023 07:30:36 +0200 Subject: [PATCH 0649/1848] [CI] Added Uno R4 to matrix --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4bcb17b178..88b3af3fd7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,6 +38,7 @@ on: - CubeCell:CubeCell:CubeCell-Board - MegaCore:avr:1281 - teensy:avr:teensy41 + - arduino:renesas_uno:minima jobs: build: From 445bc014508f50d2e8cec4c32ff42942e5ec2876 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 27 Jun 2023 21:29:02 +1000 Subject: [PATCH 0650/1848] modules: Don't read excess status data The SX126x get status command returns a single status byte. The status byte is automatically read in the `Module::SPItransferStream()` function when we increment buffLen (see https://github.com/jgromes/RadioLib/blob/master/src/Module.cpp#L259). By setting numBytes we incorrectly end up reading 2 bytes. Instead set numBytes to zero so we only read the single status byte. Signed-off-by: Alistair Francis --- src/Module.cpp | 2 +- src/modules/SX126x/SX126x.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 37da31d6dc..9856ff5b62 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -240,7 +240,7 @@ int16_t Module::SPIcheckStream() { // get the status uint8_t spiStatus = 0; uint8_t cmd = this->SPIstatusCommand; - state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 0, true, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); // translate to RadioLib status code diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2ece718d63..c7f7fc7551 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1852,7 +1852,7 @@ int16_t SX126x::setRegulatorMode(uint8_t mode) { uint8_t SX126x::getStatus() { uint8_t data = 0; - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1); + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 0); return(data); } From 3359907fa5659e0aab84d80c98fbbc8c6ca3ec07 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jun 2023 17:35:50 +0200 Subject: [PATCH 0651/1848] [SX128x] Fixed getStatus (#779) --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index bf46421898..bdd2e0c215 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1349,7 +1349,7 @@ void SX128x::readBit(uint32_t pin) { uint8_t SX128x::getStatus() { uint8_t data = 0; - this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 1); + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0); return(data); } From e88cf386d69486ba30d5f352ad6c6870f92b1279 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 28 Jun 2023 20:43:28 +1000 Subject: [PATCH 0652/1848] Module: Get status from first byte after the command Instead of getting the status from the very first byte in the input buffer, which will be what we read when we send the first byte. Let's instead get the status from the first byte after the command. This provides a more accurate status value. Signed-off-by: Alistair Francis --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 9856ff5b62..2e7340347b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -328,7 +328,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // parse status int16_t state = RADIOLIB_ERR_NONE; if(this->SPIparseStatusCb != nullptr) { - state = this->SPIparseStatusCb(buffIn[0]); + state = this->SPIparseStatusCb(buffIn[cmdLen]); } // copy the data From a8172308fef035a64b0faed0321054b675e14adb Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Jun 2023 22:28:39 +1000 Subject: [PATCH 0653/1848] examples: NonArduino: Tock: Initial commit Add support for running RadioLib on Tock. Tock is an embedded operating system designed for running multiple concurrent, mutually distrustful applications on Cortex-M and RISC-V based embedded platforms (https://github.com/tock/tock). This PR uses libtock-c (https://github.com/tock/libtock-c) to add support to running RadioLib as a Tock userspace application. This has been tested on the SparkFun LoRa Thing Plus - expLoRaBLE board (https://github.com/tock/tock/tree/master/boards/apollo3/lora_things_plus) but will work on any LoRa compatible Tock board (currently only the expLoRaBLE board). Signed-off-by: Alistair Francis --- .gitmodules | 3 + examples/NonArduino/Tock/.gitignore | 1 + examples/NonArduino/Tock/CMakeLists.txt | 61 ++++++ examples/NonArduino/Tock/build.sh | 16 ++ examples/NonArduino/Tock/libtock-c | 1 + examples/NonArduino/Tock/libtockHal.h | 196 ++++++++++++++++++ examples/NonArduino/Tock/main.cpp | 77 +++++++ examples/NonArduino/Tock/tock.cmake | 51 +++++ .../Tock/toolchain-arm-none-eabi.cmake | 98 +++++++++ 9 files changed, 504 insertions(+) create mode 100644 .gitmodules create mode 100644 examples/NonArduino/Tock/.gitignore create mode 100644 examples/NonArduino/Tock/CMakeLists.txt create mode 100755 examples/NonArduino/Tock/build.sh create mode 160000 examples/NonArduino/Tock/libtock-c create mode 100644 examples/NonArduino/Tock/libtockHal.h create mode 100644 examples/NonArduino/Tock/main.cpp create mode 100644 examples/NonArduino/Tock/tock.cmake create mode 100644 examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..7eb86944a2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "examples/NonArduino/Tock/libtock-c"] + path = examples/NonArduino/Tock/libtock-c + url = https://github.com/tock/libtock-c.git diff --git a/examples/NonArduino/Tock/.gitignore b/examples/NonArduino/Tock/.gitignore new file mode 100644 index 0000000000..567609b123 --- /dev/null +++ b/examples/NonArduino/Tock/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/examples/NonArduino/Tock/CMakeLists.txt b/examples/NonArduino/Tock/CMakeLists.txt new file mode 100644 index 0000000000..19f6e2b4b0 --- /dev/null +++ b/examples/NonArduino/Tock/CMakeLists.txt @@ -0,0 +1,61 @@ +# RadioLib Non-Arduino Tock Library CMake script +# +# Licensed under the MIT License +# +# Copyright (c) 2023 Alistair Francis +# +# 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. + +cmake_minimum_required(VERSION 3.18) + +# create the project +project(tock-sx1261) + +set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/userland_generic.ld) + +include("tock.cmake") + +# when using debuggers such as gdb, the following line can be used +#set(CMAKE_BUILD_TYPE Debug) + +# if you did not build RadioLib as shared library (see wiki), +# you will have to add it as source directory +# the following is just an example, yours will likely be different +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +# add the executable +add_executable(${PROJECT_NAME} main.cpp) + +# link with RadioLib and libtock-c +target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + gcc + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libstdc++.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libm.a +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c +) + +# you can also specify RadioLib compile-time flags here +#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE) diff --git a/examples/NonArduino/Tock/build.sh b/examples/NonArduino/Tock/build.sh new file mode 100755 index 0000000000..b7b21caa1b --- /dev/null +++ b/examples/NonArduino/Tock/build.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -e + +rm -rf ./build + +mkdir -p build +cd build + +cmake -G "CodeBlocks - Unix Makefiles" .. +make -j4 + +cd .. + +elf2tab -n radio-lib --stack 4096 --app-heap 2048 --kernel-heap 2048 \ + --kernel-major 2 --kernel-minor 1 \ + -v ./build/tock-sx1261 diff --git a/examples/NonArduino/Tock/libtock-c b/examples/NonArduino/Tock/libtock-c new file mode 160000 index 0000000000..1c1f4c0810 --- /dev/null +++ b/examples/NonArduino/Tock/libtock-c @@ -0,0 +1 @@ +Subproject commit 1c1f4c0810aa0fbd50aa91a11aaa7c05d2abb1bc diff --git a/examples/NonArduino/Tock/libtockHal.h b/examples/NonArduino/Tock/libtockHal.h new file mode 100644 index 0000000000..34af2dfcaa --- /dev/null +++ b/examples/NonArduino/Tock/libtockHal.h @@ -0,0 +1,196 @@ +/* + RadioLib Non-Arduino Tock Library helper functions + + Licensed under the MIT License + + Copyright (c) 2023 Alistair Francis + + 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 TOCK_HAL_H +#define TOCK_HAL_H + +// include RadioLib +#include + +// include all the dependencies +#include "libtock/lora_phy.h" +#include "libtock/gpio.h" +#include "libtock/timer.h" +#include "libtock/read_only_state.h" + +#define RADIO_BUSY 1 +#define RADIO_DIO_1 2 +#define RADIO_DIO_3 3 +#define RADIO_RESET 4 +// Skip the chips select as Tock handles this for us +#define RADIO_NSS RADIOLIB_NC + +// define Arduino-style macros +#define PIN_LOW (0x0) +#define PIN_HIGH (0x1) +#define PIN_INPUT (0x01) +#define PIN_OUTPUT (0x03) +#define PIN_RISING (0x01) +#define PIN_FALLING (0x02) + +typedef void (*gpioIrqFn)(void); + +/* + * Get the the timer frequency in Hz. + */ +int alarm_internal_frequency(uint32_t* frequency) { + syscall_return_t rval = command(0x0, 1, 0, 0); + return tock_command_return_u32_to_returncode(rval, frequency); +} + +int alarm_internal_read(uint32_t* time) { + syscall_return_t rval = command(0x0, 2, 0, 0); + return tock_command_return_u32_to_returncode(rval, time); +} + +static void lora_phy_gpio_Callback (int gpioPin, + __attribute__ ((unused)) int arg2, + __attribute__ ((unused)) int arg3, + void* userdata) +{ + gpioIrqFn fn = *(gpioIrqFn*)(&userdata); + + if (fn != NULL ) { + fn(); + } +} + +class TockHal : public RadioLibHal { + public: + // default constructor - initializes the base HAL and any needed private members + TockHal() + : RadioLibHal(PIN_INPUT, PIN_OUTPUT, PIN_LOW, PIN_HIGH, PIN_RISING, PIN_FALLING) { + } + + void init() override { + } + + void term() override { + } + + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if(pin == RADIOLIB_NC) { + return; + } + + if (mode == PIN_OUTPUT) { + lora_phy_gpio_enable_output(pin); + } else if (mode == PIN_INPUT) { + lora_phy_gpio_enable_input(pin, PullDown); + } + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if(pin == RADIOLIB_NC) { + return; + } + + if (value) { + lora_phy_gpio_set(pin); + } else { + lora_phy_gpio_clear(pin); + } + } + + uint32_t digitalRead(uint32_t pin) override { + int value; + + if(pin == RADIOLIB_NC) { + return 0; + } + + lora_phy_gpio_read(pin, &value); + + return value; + } + + void attachInterrupt(uint32_t interruptNum, gpioIrqFn interruptCb, uint32_t mode) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + lora_phy_gpio_interrupt_callback(lora_phy_gpio_Callback, &interruptCb); + + // set GPIO as input and enable interrupts on it + lora_phy_gpio_enable_input(interruptNum, PullDown); + lora_phy_gpio_enable_interrupt(interruptNum, Change); + } + + void detachInterrupt(uint32_t interruptNum) override { + if(interruptNum == RADIOLIB_NC) { + return; + } + + lora_phy_gpio_disable_interrupt(interruptNum); + } + + void delay(unsigned long ms) override { + delay_ms( ms ); + } + + void delayMicroseconds(unsigned long us) override { + delay_ms( us * 1000 ); + } + + unsigned long millis() override { + uint32_t frequency, now; + + alarm_internal_frequency(&frequency); + alarm_internal_read(&now); + + return (now / frequency) * 1000; + } + + unsigned long micros() override { + return millis() / 1000; + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + return 0; + } + + void spiBegin() { + } + + void spiBeginTransaction() { + } + + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + lora_phy_read_write_sync((const char*) out, (char*) in, len); + } + + void spiEndTransaction() { + } + + void spiEnd() { + } + + private: +}; + +#endif diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp new file mode 100644 index 0000000000..56df5fb4e8 --- /dev/null +++ b/examples/NonArduino/Tock/main.cpp @@ -0,0 +1,77 @@ +/* + RadioLib Non-Arduino Tock Library test application + + Licensed under the MIT License + + Copyright (c) 2023 Alistair Francis + + 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 the library +#include + +// include the hardware abstraction layer +#include "libtockHal.h" + +// the entry point for the program +int main(void) { + printf("[SX1261] Initializing ... \n"); + + // create a new instance of the HAL class + TockHal* hal = new TockHal(); + + // now we can create the radio module + // pinout corresponds to the SparkFun LoRa Thing Plus - expLoRaBLE + // NSS pin: 0 + // DIO1 pin: 2 + // NRST pin: 4 + // BUSY pin: 1 + Module* tock_module = new Module(hal, RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY); + SX1262* radio = new SX1262(tock_module); + + int state = radio->begin(); + if (state != RADIOLIB_ERR_NONE) { + printf("failed, code %d\n", state); + return 1; + } + printf("success!\n"); + + // loop forever + for(;;) { + yield_no_wait(); + // send a packet + printf("[SX1261] Transmitting packet ... \n"); + + state = radio->transmit("Hello World!"); + + if(state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + printf("success!\n"); + + // wait for a second before transmitting again + hal->delay(1000); + } else { + printf("failed, code %d\n", state); + } + + } + + return 0; +} diff --git a/examples/NonArduino/Tock/tock.cmake b/examples/NonArduino/Tock/tock.cmake new file mode 100644 index 0000000000..fb3682fc70 --- /dev/null +++ b/examples/NonArduino/Tock/tock.cmake @@ -0,0 +1,51 @@ +# Tock target specific CMake file +# +# Licensed under the MIT License +# +# Copyright (c) 2023 Alistair Francis +# +# 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. +# +# This is copied from https://github.com/Lora-net/LoRaMac-node/pull/1390 +# and has been relicensed by the original author + +include("toolchain-arm-none-eabi.cmake") + +if(NOT DEFINED LINKER_SCRIPT) +message(FATAL_ERROR "No linker script defined") +endif(NOT DEFINED LINKER_SCRIPT) +message("Linker script: ${LINKER_SCRIPT}") + +#--------------------------------------------------------------------------------------- +# Set compiler/linker flags +#--------------------------------------------------------------------------------------- + +set(STACK_SIZE 4096) +set(APP_HEAP_SIZE 2048) +set(KERNEL_HEAP_SIZE 2048) + +# Object build options +set(OBJECT_GEN_FLAGS "-mthumb -g2 -fno-builtin -mcpu=cortex-m4 -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -Wl,--emit-relocs -fPIC -mthumb -mfloat-abi=soft -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -D__TOCK__ -DSVCALL_AS_NORMAL_FUNCTION -DSOFTDEVICE_s130") + +set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options") +set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++20 " CACHE INTERNAL "C++ Compiler options") +set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options") + +# Linker flags +set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections --specs=nano.specs --specs=nosys.specs -mthumb -g2 -mcpu=cortex-m4 -mabi=aapcs -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Xlinker --defsym=STACK_SIZE=${STACK_SIZE} -Xlinker --defsym=APP_HEAP_SIZE=${APP_HEAP_SIZE} -Xlinker --defsym=KERNEL_HEAP_SIZE=${KERNEL_HEAP_SIZE} -nostdlib -Wl,--start-group" CACHE INTERNAL "Linker options") diff --git a/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake b/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake new file mode 100644 index 0000000000..685b070f59 --- /dev/null +++ b/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake @@ -0,0 +1,98 @@ +# Arm specific CMake file +# +# This is copied from: +# https://github.com/Lora-net/LoRaMac-node/blob/2bf36bde72f68257eb96b5c00900619546bedca8/cmake/toolchain-arm-none-eabi.cmake +# +# The below file is licensed as Revised BSD License +# See https://github.com/Lora-net/LoRaMac-node/blob/master/LICENSE for details + +## +## ______ _ +## / _____) _ | | +## ( (____ _____ ____ _| |_ _____ ____| |__ +## \____ \| ___ | (_ _) ___ |/ ___) _ \ +## _____) ) ____| | | || |_| ____( (___| | | | +## (______/|_____)_|_|_| \__)_____)\____)_| |_| +## (C)2013-2017 Semtech +## ___ _____ _ ___ _ _____ ___ ___ ___ ___ +## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +## embedded.connectivity.solutions.============== +## +## License: Revised BSD License, see LICENSE.TXT file included in the project +## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) +## +## +## CMake arm-none-eabi toolchain file +## + +# Append current directory to CMAKE_MODULE_PATH for making device specific cmake modules visible +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +# Target definition +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR ARM) + +#--------------------------------------------------------------------------------------- +# Set toolchain paths +#--------------------------------------------------------------------------------------- +set(TOOLCHAIN arm-none-eabi) +if(NOT DEFINED TOOLCHAIN_PREFIX) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux) + set(TOOLCHAIN_PREFIX "/usr") + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin) + set(TOOLCHAIN_PREFIX "/usr/local") + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) + message(STATUS "Please specify the TOOLCHAIN_PREFIX !\n For example: -DTOOLCHAIN_PREFIX=\"C:/Program Files/GNU Tools ARM Embedded\" ") + else() + set(TOOLCHAIN_PREFIX "/usr") + message(STATUS "No TOOLCHAIN_PREFIX specified, using default: " ${TOOLCHAIN_PREFIX}) + endif() +endif() +set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/bin) +set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/${TOOLCHAIN}/include) +set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/${TOOLCHAIN}/lib) + +# Set system depended extensions +if(WIN32) + set(TOOLCHAIN_EXT ".exe" ) +else() + set(TOOLCHAIN_EXT "" ) +endif() + +# Perform compiler test with static library +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +#--------------------------------------------------------------------------------------- +# Preset some general GCC Options +#--------------------------------------------------------------------------------------- + +# Options for DEBUG build +# -Og enables optimizations that do not interfere with debugging +# -g produce debugging information in the operating system's native format +set(CMAKE_C_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C Compiler options for debug build type") +set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C++ Compiler options for debug build type") +set(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "ASM Compiler options for debug build type") +set(CMAKE_EXE_LINKER_FLAGS_DEBUG "" CACHE INTERNAL "Linker options for debug build type") + +# Options for RELEASE build +# -Os Optimize for size. -Os enables all -O2 optimizations +set(CMAKE_C_FLAGS_RELEASE "-Os" CACHE INTERNAL "C Compiler options for release build type") +set(CMAKE_CXX_FLAGS_RELEASE "-Os" CACHE INTERNAL "C++ Compiler options for release build type") +set(CMAKE_ASM_FLAGS_RELEASE "" CACHE INTERNAL "ASM Compiler options for release build type") +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "" CACHE INTERNAL "Linker options for release build type") + +#--------------------------------------------------------------------------------------- +# Set compilers +#--------------------------------------------------------------------------------------- +set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "C Compiler") +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++${TOOLCHAIN_EXT} CACHE INTERNAL "C++ Compiler") +set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "ASM Compiler") + +set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX}/${${TOOLCHAIN}} ${CMAKE_PREFIX_PATH}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + From ac15b9ae7db2bedc8d8802e48c51e5531d399241 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Jul 2023 09:02:43 +0200 Subject: [PATCH 0654/1848] [SX126x] Added comments about TCXO/XTAL (#784) --- src/modules/SX126x/SX1262.h | 8 ++++++-- src/modules/SX126x/SX1268.h | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 32fd565cec..d3b67ae5d6 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -38,7 +38,9 @@ class SX1262: public SX126x { \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ @@ -52,7 +54,9 @@ class SX1262: public SX126x { \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 8c5225b18e..c3e2a607fc 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -37,7 +37,9 @@ class SX1268: public SX126x { \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ @@ -51,7 +53,9 @@ class SX1268: public SX126x { \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ From bea5e70d0ad4f6df74a4eb2a3d1bdb683014d6c1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Jul 2023 09:03:42 +0200 Subject: [PATCH 0655/1848] [LLCC68] Changed default crystal to XTAL (#784) --- src/modules/LLCC68/LLCC68.cpp | 1 + src/modules/LLCC68/LLCC68.h | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 47c8b60919..034835847b 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -3,6 +3,7 @@ LLCC68::LLCC68(Module* mod) : SX1262(mod) { chipType = RADIOLIB_LLCC68_CHIP_TYPE; + this->XTAL = true; } int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index b76f23ff79..1cec96f1e2 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -32,11 +32,13 @@ class LLCC68: public SX1262 { \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 0 V (XTAL). + If you are seeing -706/-707 error codes, it likely means you are using a module with TCXO. + To use TCXO, either set this value to its reference voltage, or set SX126x::XTAL to false. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false); // configuration methods From 47f9ab8463efd465bb35d981d2130f3cd4f3714c Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 5 Jul 2023 09:46:12 +0200 Subject: [PATCH 0656/1848] Fixed typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ede2443455..32d45a2c48 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * __PJRC__ * [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards -The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstracton layer, which allows it to be easily ported even to non-Arduino encironments. +The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstraction layer, which allows it to be easily ported even to non-Arduino environments. ### In development: * __AX5243__ FSK module From 91787eb26926c48d265768586d33a80ed8a03a2e Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 11:10:20 +0200 Subject: [PATCH 0657/1848] [PHY] Implemented more common methods --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 26 +++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 54 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 1e9d35844e..84d8283200 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -246,6 +246,32 @@ int16_t PhysicalLayer::setEncoding(uint8_t encoding) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::invertIQ(bool enable) { + (void)enable; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setOutputPower(int8_t power) { + (void)power; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setSyncWord(uint8_t* sync, size_t len) { + (void)sync; + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setPreambleLength(size_t len) { + (void)len; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setDataRate(DataRate_t dr) { + (void)dr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + float PhysicalLayer::getFreqStep() const { return(this->freqStep); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 4e9ceb5123..95a7ae6c8e 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -4,6 +4,24 @@ #include "../../TypeDef.h" #include "../../Module.h" +// data rate structure interpretation in case LoRa is used +struct LoRaRate_t { + uint8_t spreadingFactor; + float bandwidth; +}; + +// data rate structure interpretation in case FSK is used +struct FSKRate_t { + float bitRate; + float freqDev; +}; + +// common data rate +union DataRate_t { + LoRaRate_t lora; + FSKRate_t fsk; +}; + /*! \class PhysicalLayer @@ -223,6 +241,42 @@ class PhysicalLayer { */ virtual int16_t setEncoding(uint8_t encoding); + /*! + \brief Set IQ inversion. Must be implemented in module class if the module supports it. + \param enable True to use inverted IQ, false for non-inverted. + \returns \ref status_codes + */ + virtual int16_t invertIQ(bool enable); + + /*! + \brief Set output power. Must be implemented in module class if the module supports it. + \param power Output power in dBm. The allowed range depends on the module used. + \returns \ref status_codes + */ + virtual int16_t setOutputPower(int8_t power); + + /*! + \brief Set sync word. Must be implemented in module class if the module supports it. + \param sync Pointer to the sync word. + \param len Sync word length in bytes. Maximum length depends on the module used. + \returns \ref status_codes + */ + virtual int16_t setSyncWord(uint8_t* sync, size_t len); + + /*! + \brief Set preamble length. Must be implemented in module class if the module supports it. + \param len Preamble length in bytes. Maximum length depends on the module used. + \returns \ref status_codes + */ + virtual int16_t setPreambleLength(size_t len); + + /*! + \brief Set data. Must be implemented in module class if the module supports it. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + virtual int16_t setDataRate(DataRate_t dr); + /*! \brief Gets the module frequency step size that was set in constructor. \returns Synthesizer frequency step size in Hz. From d561d41e958602d0257dc45db8b66670c9594c2d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 11:14:44 +0200 Subject: [PATCH 0658/1848] [SX126x] Implemented new common PHY methods --- src/modules/SX126x/SX126x.cpp | 65 ++++++++++++++++++++++++++--------- src/modules/SX126x/SX126x.h | 13 +++++-- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c7f7fc7551..6ec42bbdd1 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -879,7 +879,7 @@ float SX126x::getCurrentLimit() { return((float)ocp * 2.5); } -int16_t SX126x::setPreambleLength(uint16_t preambleLength) { +int16_t SX126x::setPreambleLength(size_t preambleLength) { uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { this->preambleLengthLoRa = preambleLength; @@ -937,6 +937,31 @@ int16_t SX126x::setBitRate(float br) { return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } +int16_t SX126x::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + int16_t SX126x::setRxBandwidth(float rxBw) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { @@ -1068,26 +1093,34 @@ int16_t SX126x::setDataShaping(uint8_t sh) { return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } -int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) { +int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // check sync word Length + if(len > 8) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } - // check sync word Length - if(len > 8) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } + // write sync word + int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len); + RADIOLIB_ASSERT(state); - // write sync word - int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len); - RADIOLIB_ASSERT(state); + // update packet parameters + this->syncWordLength = len * 8; + state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); - // update packet parameters - this->syncWordLength = len * 8; - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + return(state); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + return(setSyncWord(syncWord[0])); + } - return(state); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index ce363187c4..d2ea17162f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -744,7 +744,7 @@ class SX126x: public PhysicalLayer { \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK). \returns \ref status_codes */ - int16_t setPreambleLength(uint16_t preambleLength); + int16_t setPreambleLength(size_t preambleLength) override; /*! \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. @@ -760,6 +760,13 @@ class SX126x: public PhysicalLayer { */ int16_t setBitRate(float br); + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + /*! \brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. @@ -793,7 +800,7 @@ class SX126x: public PhysicalLayer { \param len FSK sync word length in bytes. \returns \ref status_codes */ - int16_t setSyncWord(uint8_t* syncWord, uint8_t len); + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; /*! \brief Sets FSK sync word in the form of array of up to 8 bytes. @@ -984,7 +991,7 @@ class SX126x: public PhysicalLayer { \param enable QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ - int16_t invertIQ(bool enable); + int16_t invertIQ(bool enable) override; #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! From d5ce384bdaa6ec3abbed7972fb765eeb204610a4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 11:17:29 +0200 Subject: [PATCH 0659/1848] [SX127x] Implemented new common PHY methods --- src/modules/SX127x/SX1272.cpp | 29 +++++++++++++++++++++++++ src/modules/SX127x/SX1272.h | 19 ++++++++++++++-- src/modules/SX127x/SX1273.cpp | 25 +++++++++++++++++++++ src/modules/SX127x/SX1273.h | 7 ++++++ src/modules/SX127x/SX1277.cpp | 25 +++++++++++++++++++++ src/modules/SX127x/SX1277.h | 7 ++++++ src/modules/SX127x/SX1278.cpp | 29 +++++++++++++++++++++++++ src/modules/SX127x/SX1278.h | 19 ++++++++++++++-- src/modules/SX127x/SX127x.cpp | 41 +++++++++++++++++++++-------------- src/modules/SX127x/SX127x.h | 6 ++--- 10 files changed, 184 insertions(+), 23 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 5d5b27acbb..b198d46a4e 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -220,6 +220,35 @@ int16_t SX1272::setBitRate(float br) { return(SX127x::setBitRateCommon(br, RADIOLIB_SX1272_REG_BIT_RATE_FRAC)); } +int16_t SX1272::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + +int16_t SX1272::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index f997647dd4..f389230b25 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -176,14 +176,29 @@ class SX1272: public SX127x { \returns \ref status_codes */ int16_t setBitRate(float br) override; + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). + High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST. + \param power Transmission output power in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; /*! \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). \param power Transmission output power in dBm. - \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. Defaults to PA_BOOST. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool useRfo = false); + int16_t setOutputPower(int8_t power, bool useRfo); /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 0e4d287c75..4b180694be 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -66,4 +66,29 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) { return(state); } +int16_t SX1273::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + #endif diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 4fab62151f..2ceb58bc26 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -49,6 +49,13 @@ class SX1273: public SX1272 { */ int16_t setSpreadingFactor(uint8_t sf); + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 7e635756c5..d466a385c5 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -107,4 +107,29 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } +int16_t SX1277::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 76d8854b18..88fb58fede 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -69,6 +69,13 @@ class SX1277: public SX1278 { \returns \ref status_codes */ int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; #if !defined(RADIOLIB_GODMODE) private: diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index ec5266ad68..e61a1ef3f9 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -234,6 +234,35 @@ int16_t SX1278::setBitRate(float br) { return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC)); } +int16_t SX1278::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + } + + return(state); +} + +int16_t SX1278::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { // check allowed power range if(useRfo) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index e5f8781cdf..92c996ed1f 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -184,15 +184,30 @@ class SX1278: public SX127x { \returns \ref status_codes */ int16_t setBitRate(float br) override; + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). + High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST. + \param power Transmission output power in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; /*! \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. \param power Transmission output power in dBm. - \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. Defaults to PA_BOOST. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool useRfo = false); + int16_t setOutputPower(int8_t power, bool useRfo); /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 4e9d5adcc5..027d512ea4 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -729,7 +729,7 @@ int16_t SX127x::setCurrentLimit(uint8_t currentLimit) { return(state); } -int16_t SX127x::setPreambleLength(uint16_t preambleLength) { +int16_t SX127x::setPreambleLength(size_t preambleLength) { // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); @@ -973,27 +973,36 @@ int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) { int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { // check active modem - if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } + uint8_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD); - RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD); + // sync word must not contain value 0x00 + for(size_t i = 0; i < len; i++) { + if(syncWord[i] == 0x00) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + } - // sync word must not contain value 0x00 - for(size_t i = 0; i < len; i++) { - if(syncWord[i] == 0x00) { + // enable sync word recognition + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); + RADIOLIB_ASSERT(state); + + // set sync word + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_LORA) { + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } - } - // enable sync word recognition - int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0); - RADIOLIB_ASSERT(state); + return(this->setSyncWord(syncWord[0])); + } - // set sync word - this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len); - return(RADIOLIB_ERR_NONE); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t SX127x::setNodeAddress(uint8_t nodeAddr) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index dcd84790dd..3ba9a3196c 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -856,7 +856,7 @@ class SX127x: public PhysicalLayer { \param preambleLength Preamble length to be set (in symbols when in LoRa mode or bits in FSK mode). \returns \ref status_codes */ - int16_t setPreambleLength(uint16_t preambleLength); + int16_t setPreambleLength(size_t preambleLength) override; /*! \brief Gets frequency error of the latest received packet. @@ -924,7 +924,7 @@ class SX127x: public PhysicalLayer { \param len Sync word length (in bytes). \returns \ref status_codes */ - int16_t setSyncWord(uint8_t* syncWord, size_t len); + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; /*! \brief Sets FSK node address. Calling this method will enable address filtering. Only available in FSK mode. @@ -1089,7 +1089,7 @@ class SX127x: public PhysicalLayer { \param enable QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ - int16_t invertIQ(bool enable); + int16_t invertIQ(bool enable) override; #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! From e486829b8f432ca12b2c91d8aee78f4d4270ab73 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 11:19:18 +0200 Subject: [PATCH 0660/1848] [HAL] Implemented basic persistent storage --- src/ArduinoHal.cpp | 27 ++++++++++++++++++++ src/ArduinoHal.h | 3 +++ src/Hal.cpp | 29 +++++++++++++++++++++ src/Hal.h | 63 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index d42f0d0ba5..5bcafb057a 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -2,6 +2,8 @@ #if defined(RADIOLIB_BUILD_ARDUINO) +#include + ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {} ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&spi), spiSettings(spiSettings) {} @@ -98,6 +100,31 @@ void inline ArduinoHal::spiEnd() { spi->end(); } +void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { + #if defined(ESP32) + EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); + #endif + for(size_t i = 0; i < len; i++) { + buff[i] = EEPROM.read(addr + i); + } + #if defined(ESP32) + EEPROM.end(); + #endif +} + +void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { + #if defined(ESP32) + EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); + #endif + for(size_t i = 0; i < len; i++) { + EEPROM.write(addr + i, buff[i]); + } + #if defined(ESP32) + EEPROM.commit(); + EEPROM.end(); + #endif +} + void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if(pin == RADIOLIB_NC) { diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 59b0f1aa16..7f9620d14d 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -51,6 +51,9 @@ class ArduinoHal : public RadioLibHal { void spiEndTransaction() override; void spiEnd() override; + void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) override; + void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) override; + // implementations of virtual RadioLibHal methods void init() override; void term() override; diff --git a/src/Hal.cpp b/src/Hal.cpp index 1a42aa15a7..bd65819f9d 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -33,3 +33,32 @@ void RadioLibHal::yield() { uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); } + +void RadioLibHal::wipePersistentStorage() { + uint8_t dummy = 0; + for(size_t i = 0; i < RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE; i++) { + this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + i, &dummy, sizeof(uint8_t)); + } +} + +template +void RadioLibHal::setPersistentParameter(uint32_t id, T val) { + uint8_t *ptr = (uint8_t*)&val; + this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id], ptr, sizeof(T)); +} + +template void RadioLibHal::setPersistentParameter(uint32_t id, uint8_t val); +template void RadioLibHal::setPersistentParameter(uint32_t id, uint16_t val); +template void RadioLibHal::setPersistentParameter(uint32_t id, uint32_t val); + +template +T RadioLibHal::getPersistentParameter(uint32_t id) { + T val = 0; + uint8_t *ptr = (uint8_t*)&val; + this->readPersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id], ptr, sizeof(T)); + return(val); +} + +template uint8_t RadioLibHal::getPersistentParameter(uint32_t id); +template uint16_t RadioLibHal::getPersistentParameter(uint32_t id); +template uint32_t RadioLibHal::getPersistentParameter(uint32_t id); diff --git a/src/Hal.h b/src/Hal.h index 87fb561e3b..1be814e364 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -4,8 +4,27 @@ #include #include +#include "BuildOpt.h" + +// list of persistent parameters +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (0) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (1) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (2) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_DOWN_ID (3) + +static const uint32_t RadioLibPersistentParamTable[] = { + 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID + 0x02, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID + 0x06, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 0x0A, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_DOWN_ID +}; + +// static assert to make sure that the persistent parameter table will fit to the allocated storage space +#define RADIOLIB_STATIC_ASSERT(test) typedef char radiolib_static_assert[( !!(test) )*2-1 ] +RADIOLIB_STATIC_ASSERT( sizeof(RadioLibPersistentParamTable) <= RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE ); + /*! - \class Hal + \class RadioLibHal \brief Hardware abstraction library base interface. */ class RadioLibHal { @@ -205,6 +224,48 @@ class RadioLibHal { \returns The interrupt number of a given pin. */ virtual uint32_t pinToInterrupt(uint32_t pin); + + /*! + \brief Method to read from persistent storage (e.g. EEPROM). + \param addr Address to start reading at. + \param buff Buffer to read into. + \param len Number of bytes to read. + */ + virtual void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) = 0; + + /*! + \brief Method to write to persistent storage (e.g. EEPROM). + \param addr Address to start writing to. + \param buff Buffer to write. + \param len Number of bytes to write. + */ + virtual void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) = 0; + + /*! + \brief Method to wipe the persistent storage by writing to 0. + Will write at most RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE bytes. + */ + void wipePersistentStorage(); + + /*! + \brief Method to set arbitrary parameter to persistent storage. + This method DOES NOT perform any endianness conversion, so the value + will be stored in the system endian! + \param id Parameter ID to save at. + \param val Value to set. + */ + template + void setPersistentParameter(uint32_t id, T val); + + /*! + \brief Method to get arbitrary parameter from persistent storage. + This method DOES NOT perform any endianness conversion, so the value + will be retrieved in the system endian! + \param id Parameter ID to load from. + \returns The lodaded value. + */ + template + T getPersistentParameter(uint32_t id); }; #endif From d725215e2081e6ffcf3e438bc9205b660fb03190 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 11:19:44 +0200 Subject: [PATCH 0661/1848] [HAL] Added persistent parameters to buildopt --- src/BuildOpt.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 53d104d0d1..de1a363033 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -422,6 +422,21 @@ #define RADIOLIB_STATIC_ARRAY_SIZE (256) #endif +// the base address for persistent storage +// some protocols (e.g. LoRaWAN) require a method +// to store some data persistently +// on Arduino, this will use EEPROM, on non-Arduino platform, +// it will use anything provided by the hardware abstraction layer +// RadioLib will place these starting at this address +#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_BASE (0) +#endif + +// the amount of space allocated to the persistent storage +#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (32) +#endif + // This only compiles on STM32 boards with SUBGHZ module, but also // include when generating docs #if (!defined(ARDUINO_ARCH_STM32) || !defined(SUBGHZSPI_BASE)) && !defined(DOXYGEN) From df691db0a5faf71680d40b1c5429c6330276acb3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 13:30:29 +0200 Subject: [PATCH 0662/1848] [HAL] Updated persistent management --- src/BuildOpt.h | 2 +- src/Hal.cpp | 18 ++++++++++++++++++ src/Hal.h | 27 +++++++++++++++++---------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index de1a363033..9b7950f466 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -434,7 +434,7 @@ // the amount of space allocated to the persistent storage #if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (32) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x60) #endif // This only compiles on STM32 boards with SUBGHZ module, but also diff --git a/src/Hal.cpp b/src/Hal.cpp index bd65819f9d..6ba08bb755 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -34,6 +34,20 @@ uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); } +void RadioLibHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { + // these are only needed for some protocols, so it's not needed to have them by default + (void)addr; + (void)buff; + (void)len; +} + +void RadioLibHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { + // these are only needed for some protocols, so it's not needed to have them by default + (void)addr; + (void)buff; + (void)len; +} + void RadioLibHal::wipePersistentStorage() { uint8_t dummy = 0; for(size_t i = 0; i < RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE; i++) { @@ -41,6 +55,10 @@ void RadioLibHal::wipePersistentStorage() { } } +uint32_t RadioLibHal::getPersistentAddr(uint32_t id) { + return(RadioLibPersistentParamTable[id]); +} + template void RadioLibHal::setPersistentParameter(uint32_t id, T val) { uint8_t *ptr = (uint8_t*)&val; diff --git a/src/Hal.h b/src/Hal.h index 1be814e364..ef8c0ee09a 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -10,19 +10,24 @@ #define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (0) #define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (1) #define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (2) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_DOWN_ID (3) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (3) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (4) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (5) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (6) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (7) static const uint32_t RadioLibPersistentParamTable[] = { 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID - 0x02, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID - 0x06, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID - 0x0A, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_DOWN_ID + 0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID + 0x08, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID + 0x10, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID + 0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID + 0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID + 0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID + 0x50, // end }; -// static assert to make sure that the persistent parameter table will fit to the allocated storage space -#define RADIOLIB_STATIC_ASSERT(test) typedef char radiolib_static_assert[( !!(test) )*2-1 ] -RADIOLIB_STATIC_ASSERT( sizeof(RadioLibPersistentParamTable) <= RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE ); - /*! \class RadioLibHal \brief Hardware abstraction library base interface. @@ -231,7 +236,7 @@ class RadioLibHal { \param buff Buffer to read into. \param len Number of bytes to read. */ - virtual void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) = 0; + virtual void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len); /*! \brief Method to write to persistent storage (e.g. EEPROM). @@ -239,7 +244,7 @@ class RadioLibHal { \param buff Buffer to write. \param len Number of bytes to write. */ - virtual void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) = 0; + virtual void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len); /*! \brief Method to wipe the persistent storage by writing to 0. @@ -247,6 +252,8 @@ class RadioLibHal { */ void wipePersistentStorage(); + uint32_t getPersistentAddr(uint32_t id); + /*! \brief Method to set arbitrary parameter to persistent storage. This method DOES NOT perform any endianness conversion, so the value From 3012185af4d08bd9cf6cbd4927777d4614c13f41 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 13:30:56 +0200 Subject: [PATCH 0663/1848] [Crypto] Added AES key size macro --- src/utils/Cryptography.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index 3b7a479914..31e56c6868 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -6,6 +6,7 @@ // AES-128 constants #define RADIOLIB_AES128_BLOCK_SIZE (16) +#define RADIOLIB_AES128_KEY_SIZE (RADIOLIB_AES128_BLOCK_SIZE) #define RADIOLIB_AES128_N_K ((RADIOLIB_AES128_BLOCK_SIZE) / sizeof(uint32_t)) #define RADIOLIB_AES128_N_B (4) #define RADIOLIB_AES128_N_R (10) From 0d2ef419bf404b4af90026ae7fa48f8c52091937 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 13:41:31 +0200 Subject: [PATCH 0664/1848] [LoRaWAN] Added basic LoRaWAN support (#58) --- README.md | 7 +- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 124 +++++ keywords.txt | 10 + src/RadioLib.h | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 494 ++++++++++++++++++ src/protocols/LoRaWAN/LoRaWAN.h | 324 ++++++++++++ src/protocols/LoRaWAN/LoRaWANBands.cpp | 191 +++++++ 7 files changed, 1146 insertions(+), 5 deletions(-) create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino create mode 100644 src/protocols/LoRaWAN/LoRaWAN.cpp create mode 100644 src/protocols/LoRaWAN/LoRaWAN.h create mode 100644 src/protocols/LoRaWAN/LoRaWANBands.cpp diff --git a/README.md b/README.md index 32d45a2c48..f33652be7d 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x +* [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules: +SX127x, RFM9x, SX126x and SX128x ### Supported Arduino platforms: * __Arduino__ @@ -87,11 +89,6 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstraction layer, which allows it to be easily ported even to non-Arduino environments. -### In development: -* __AX5243__ FSK module -* __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules -* ___and more!___ - ## Frequently Asked Questions ### Where should I start? diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino new file mode 100644 index 0000000000..c1553c7a37 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -0,0 +1,124 @@ +/* + RadioLib LoRaWAN End Device Example + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will join the network and start uploading data. + + NOTE: LoRaWAN requires storing some parameters persistently! + RadioLib does this by using EEPROM, by default + starting at address 0 and using 32 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // first we need to initialize the device storage + // this will reset all persistently stored parameters + // NOTE: This should only be done once prior to first joining a network! + // After wiping persistent storage, you will also have to reset + // the end device in TTN and perform the join procedure again! + //node.wipe(); + + // application identifier - in LoRaWAN 1.1, it is also called joinEUI + // when adding new end device in TTN, you will have to enter this number + // you can pick any number you want, but it has to be unique + uint64_t appEUI = 0x12AD1011B0C0FFEE; + + // device identifier - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is also unique + uint64_t devEUI = 0x70B3D57ED005E120; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + const char nwkKey[] = "topSecretKey1234"; + const char appKey[] = "aDifferentKeyABC"; + + // now we can start the activation + // this can take up to 20 seconds, and requires a LoRaWAN gateway in range + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginOTAA(appEUI, devEUI, (uint8_t*)nwkKey, (uint8_t*)appKey); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after the device has been activated, + // network can be rejoined after device power cycle + // by calling "begin" + /* + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String str = "Hello World! #" + String(count++); + int state = node.uplink(str, 10); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait before sending another one + delay(10000); +} diff --git a/keywords.txt b/keywords.txt index 34d077d681..acb0254375 100644 --- a/keywords.txt +++ b/keywords.txt @@ -56,6 +56,8 @@ APRSClient KEYWORD1 PagerClient KEYWORD1 ExternalRadio KEYWORD1 BellClient KEYWORD1 +LoRaWANNode KEYWORD1 +LoRaWANBand_t KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -269,10 +271,18 @@ setPacketReceivedAction KEYWORD2 clearPacketReceivedAction KEYWORD2 setPacketSentAction KEYWORD2 clearPacketSentAction KEYWORD2 +setDataRate KEYWORD2 # BellModem setModem KEYWORD2 +# LoRaWAN +wipe KEYWORD2 +beginOTAA KEYWORD2 +beginAPB KEYWORD2 +uplink KEYWORD2 +configureChannel KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index b7df08d986..e4ea62ad70 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -109,6 +109,7 @@ #include "protocols/ExternalRadio/ExternalRadio.h" #include "protocols/Print/Print.h" #include "protocols/BellModem/BellModem.h" +#include "protocols/LoRaWAN/LoRaWAN.h" // utilities #include "utils/CRC.h" diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp new file mode 100644 index 0000000000..dafbe9bd08 --- /dev/null +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -0,0 +1,494 @@ +#include "LoRaWAN.h" + +#include + +#if !defined(RADIOLIB_EXCLUDE_LORAWAN) + +// flag to indicate whether we have received a downlink +static volatile bool downlinkReceived = false; + +// interrupt service routine to handle downlinks automatically +#if defined(ESP8266) || defined(ESP32) + IRAM_ATTR +#endif +static void LoRaWANNodeOnDownlink(void) { + downlinkReceived = true; +} + +LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { + this->phyLayer = phy; + this->band = band; +} + +void LoRaWANNode::wipe() { + Module* mod = this->phyLayer->getMod(); + mod->hal->wipePersistentStorage(); +} + +int16_t LoRaWANNode::begin() { + int16_t state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + + // check the magic value + Module* mod = this->phyLayer->getMod(); + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) != RADIOLIB_LORAWAN_MAGIC) { + // the magic value is not set, user will have to do perform the join procedure + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + + // pull all needed information from persistent storage + this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID); + RADIOLIB_DEBUG_PRINTLN("devAddr = 0x%08x", this->devAddr); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force) { + // check if we actually need to send the join request + Module* mod = this->phyLayer->getMod(); + if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { + // the device has joined already, we can just pull the data from persistent storage + return(this->begin()); + } + + // set the physical layer configuration + int16_t state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + + // get dev nonce from persistent storage and increment it + uint16_t devNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID, devNonce + 1); + RADIOLIB_DEBUG_PRINTLN("devNonce = %d", devNonce); + + // build the join-request message + uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; + + // set the packet fields + joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], appEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonce); + + // add the authentication code + uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); + + // send it + state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + RADIOLIB_ASSERT(state); + + // set the function that will be called when the reply is received + this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); + + // downlink messages are sent with interted IQ + state = this->phyLayer->invertIQ(true); + RADIOLIB_ASSERT(state); + + // start receiving + uint32_t start = mod->hal->millis(); + state = this->phyLayer->startReceive(); + RADIOLIB_ASSERT(state); + + // wait for the reply or timeout + while(!downlinkReceived) { + if(mod->hal->millis() - start >= RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS + 2000) { + downlinkReceived = false; + this->phyLayer->invertIQ(false); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // we have a message, reset the IQ inversion + downlinkReceived = false; + this->phyLayer->clearPacketReceivedAction(); + state = this->phyLayer->invertIQ(false); + RADIOLIB_ASSERT(state); + + // build the buffer for the reply data + uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; + + // check received length + size_t lenRx = this->phyLayer->getPacketLength(true); + if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { + RADIOLIB_DEBUG_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // read the packet + state = this->phyLayer->readData(joinAcceptMsgEnc, lenRx); + RADIOLIB_ASSERT(state); + + // check reply message type + if(joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { + RADIOLIB_DEBUG_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // decrypt the join accept message + // this is done by encrypting again in ECB mode + // the first byte is the MAC header which is not encrpyted + uint8_t joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; + joinAcceptMsg[0] = joinAcceptMsgEnc[0]; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); + + //Module::hexdump(joinAcceptMsg, RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN); + + // verify MIC + if(!verifyMIC(joinAcceptMsg, lenRx, nwkKey)) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + // parse the contents + uint32_t joinNonce = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + uint32_t homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); + this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); + uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; + this->rxDelay = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + + // process CFlist if present + if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { + if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { + // list of frequencies + for(uint8_t i = 0; i < 5; i++) { + uint32_t freq = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + 3*i], 3); + availableChannelsFreq[i] = (float)freq/10000.0; + RADIOLIB_DEBUG_PRINTLN("Channel %d frequency = %f MHz", i, availableChannelsFreq[i]); + } + + } else { + // TODO list of masks + RADIOLIB_DEBUG_PRINTLN("CFlist masks not supported (yet)"); + return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); + + } + + } + + RADIOLIB_DEBUG_PRINTLN("joinNonce = %lu", joinNonce); + RADIOLIB_DEBUG_PRINTLN("homeNetId = %lu", homeNetId); + RADIOLIB_DEBUG_PRINTLN("devAddr = 0x%08x", devAddr); + RADIOLIB_DEBUG_PRINTLN("dlSettings = 0x%02x", dlSettings); + RADIOLIB_DEBUG_PRINTLN("rxDelay = %d", this->rxDelay); + + // prepare buffer for key derivation + uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce); + + // check protocol version (1.0 vs 1.1) + if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { + // TODO implement 1.1 + RADIOLIB_DEBUG_PRINTLN("LoRaWAN 1.1 not supported (yet)"); + return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); + + } else { + // 1.0 version, just derive the keys + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); + + memcpy(this->sNwkSIntKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->nwkSEncKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + + } + + // save the device address + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); + + // update the keys + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + // all complete, reset device counters and set the magic number + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, 0); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t net, uint8_t* nwkSKey, uint8_t* appSKey) { + this->devAddr = (((uint32_t)net << 25) & 0xFE000000) | (addr & 0x01FFFFFF); + memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::uplink(String& str, uint8_t port) { + return(this->uplink(str.c_str(), port)); +} +#endif + +int16_t LoRaWANNode::uplink(const char* str, uint8_t port) { + return(this->uplink((uint8_t*)str, strlen(str), port)); +} + +int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { + // check destination port + RADIOLIB_CHECK_RANGE(port, 0x01, 0xDF, RADIOLIB_ERR_INVALID_PAYLOAD); + + // check maximum payload len as defiend in phy + // TODO implement Fopts + uint8_t foptsLen = 0; + if(len > this->band->payloadLenMax[this->dataRate]) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // build the uplink message + // the first 16 bytes are reserved for MIC calculation blocks + size_t uplinkMsgLen = RADIOLIB_LORAWAN_UPLINK_LEN(len, foptsLen); + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen]; + #endif + + // set the packet fields + uplinkMsg[RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_UPLINK_DEV_ADDR_POS], this->devAddr); + + // TODO implement adaptive data rate + uplinkMsg[RADIOLIB_LORAWAN_UPLINK_FCTRL_POS] = 0x00; + + // get frame counter from persistent storage + Module* mod = this->phyLayer->getMod(); + uint32_t fcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, fcnt + 1); + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_UPLINK_FCNT_POS], (uint16_t)fcnt); + + // TODO implement FOpts + uplinkMsg[RADIOLIB_LORAWAN_UPLINK_FPORT_POS(foptsLen)] = port; + + // select encryption key based on the target port + uint8_t* encKey = this->appSKey; + if(port == 0) { + encKey = this->nwkSEncKey; + } + + // figure out how many encryption blocks are there + size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + numBlocks++; + } + + // generate the encryption blocks + uint8_t encBuffer[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + uint8_t encBlock[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; + encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + + //Module::hexdump(uplinkMsg, uplinkMsgLen); + + // now encrypt the payload + size_t remLen = len; + for(size_t i = 0; i < numBlocks; i++) { + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; + + // encrypt the buffer + RadioLibAES128Instance.init(encKey); + RadioLibAES128Instance.encryptECB(encBlock, RADIOLIB_AES128_BLOCK_SIZE, encBuffer); + + // now xor the buffer with the payload + size_t xorLen = remLen; + if(xorLen > RADIOLIB_AES128_BLOCK_SIZE) { + xorLen = RADIOLIB_AES128_BLOCK_SIZE; + } + for(uint8_t j = 0; j < xorLen; j++) { + uplinkMsg[RADIOLIB_LORAWAN_UPLINK_PAYLOAD_POS(foptsLen) + i*RADIOLIB_AES128_BLOCK_SIZE + j] = data[i*RADIOLIB_AES128_BLOCK_SIZE + j] ^ encBuffer[j]; + } + remLen -= xorLen; + } + + // create blocks for MIC calculation + uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; + block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); + + uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); + // TODO implement confirmed frames + block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRate; + block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->chIndex; + + //Module::hexdump(uplinkMsg, uplinkMsgLen); + + // calculate authentication codes + memcpy(uplinkMsg, block1, RADIOLIB_AES128_BLOCK_SIZE); + uint32_t micS = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->sNwkSIntKey); + memcpy(uplinkMsg, block0, RADIOLIB_AES128_BLOCK_SIZE); + uint32_t micF = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->fNwkSIntKey); + // TODO check LoRaWAN 1.0/1.1 + LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); + + //Module::hexdump(uplinkMsg, uplinkMsgLen); + + // send it (without the MIC calculation blocks) + int16_t state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] uplinkMsg; + #endif + RADIOLIB_ASSERT(state); + + // TODO implement listening for downlinks in RX1/RX2 slots + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::configureChannel(uint8_t chan, uint8_t dr) { + // find the span based on the channel ID + uint8_t span = 0; + uint8_t spanChannelId = 0; + bool found = false; + for(uint8_t chanCtr = 0; span < this->band->numChannelSpans; span++) { + for(; spanChannelId < this->band->defaultChannels[span].numChannels; spanChannelId++) { + if(chanCtr >= chan) { + found = true; + break; + } + chanCtr++; + } + if(found) { + break; + } + } + + if(!found) { + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); + } + + this->chIndex = chan; + RADIOLIB_DEBUG_PRINTLN("Channel span %d, channel %d", span, spanChannelId); + + // set the frequency + float freq = this->band->defaultChannels[span].freqStart + this->band->defaultChannels[span].freqStep * (float)spanChannelId; + RADIOLIB_DEBUG_PRINTLN("Frequency %f MHz", freq); + int state = this->phyLayer->setFrequency(freq); + RADIOLIB_ASSERT(state); + + // set the data rate + uint8_t dataRateBand = this->band->defaultChannels[span].dataRates[dr]; + this->dataRate = dr; + if(dr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + // find the first usable data rate + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; i++) { + if(this->band->defaultChannels[span].dataRates[i] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + dataRateBand = this->band->defaultChannels[span].dataRates[i]; + this->dataRate = i; + break; + } + } + } + + RADIOLIB_DEBUG_PRINTLN("Data rate %02x", dataRateBand); + DataRate_t datr; + uint8_t bw = dataRateBand & 0x03; + switch(bw) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + datr.lora.bandwidth = 125.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + datr.lora.bandwidth = 250.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + datr.lora.bandwidth = 500.0; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + datr.lora.spreadingFactor = ((dataRateBand & 0xF0) >> 4) + 6; + state = this->phyLayer->setDataRate(datr); + + return(state); +} + +uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { + if((msg == NULL) || (len == 0)) { + return(0); + } + + RadioLibAES128Instance.init(key); + uint8_t cmac[RADIOLIB_AES128_BLOCK_SIZE]; + RadioLibAES128Instance.generateCMAC(msg, len, cmac); + return(((uint32_t)cmac[0]) | ((uint32_t)cmac[1] << 8) | ((uint32_t)cmac[2] << 16) | ((uint32_t)cmac[3]) << 24); +} + +bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { + if((msg == NULL) || (len < sizeof(uint32_t))) { + return(0); + } + + // extract MIC from the message + uint32_t micReceived = LoRaWANNode::ntoh(&msg[len - sizeof(uint32_t)]); + + // calculate the expected value and compare + uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); + if(micCalculated != micReceived) { + RADIOLIB_DEBUG_PRINTLN("MIC mismatch, expected 0x%08x, got 0x%08x", micCalculated, micReceived); + return(false); + } + + return(true); +} + +int16_t LoRaWANNode::setPhyProperties() { + // set the physical layer configuration + // TODO select channel span based on channel ID + // TODO select channel randomly + uint8_t channelId = 0; + int16_t state = this->configureChannel(channelId, this->band->defaultChannels[0].joinRequestDataRate); + RADIOLIB_ASSERT(state); + + state = this->phyLayer->setOutputPower(this->band->powerMax); + RADIOLIB_ASSERT(state); + + uint8_t syncWord = RADIOLIB_LORAWAN_LORA_SYNC_WORD; + state = this->phyLayer->setSyncWord(&syncWord, 1); + RADIOLIB_ASSERT(state); + + state = this->phyLayer->setPreambleLength(RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN); + return(state); +} + +template +T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { + uint8_t* buffPtr = buff; + size_t targetSize = sizeof(T); + if(size != 0) { + targetSize = size; + } + T res = 0; + for(uint8_t i = 0; i < targetSize; i++) { + res |= (uint32_t)(*(buffPtr++)) << 8*i; + } + return(res); +} + +template +void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { + uint8_t* buffPtr = buff; + size_t targetSize = sizeof(T); + if(size != 0) { + targetSize = size; + } + for(uint8_t i = 0; i < targetSize; i++) { + *(buffPtr++) = val >> 8*i; + } +} + +#endif diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h new file mode 100644 index 0000000000..ac5d74672e --- /dev/null +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -0,0 +1,324 @@ +#if !defined(_RADIOLIB_LORAWAN_H) && !defined(RADIOLIB_EXCLUDE_LORAWAN) +#define _RADIOLIB_LORAWAN_H + +#include "../../TypeDef.h" +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../../utils/Cryptography.h" + +// preamble format +#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) +#define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) +#define RADIOLIB_LORAWAN_GFSK_SYNC_WORD (0xC194C1) +#define RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN (5) + +// MAC header field encoding MSB LSB DESCRIPTION +#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request +#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT (0x01 << 5) // 7 5 join accept +#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP (0x02 << 5) // 7 5 unconfirmed data up +#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_DOWN (0x03 << 5) // 7 5 unconfirmed data down +#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP (0x04 << 5) // 7 5 confirmed data up +#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN (0x05 << 5) // 7 5 confirmed data down +#define RADIOLIB_LORAWAN_MHDR_MTYPE_PROPRIETARY (0x07 << 5) // 7 5 proprietary +#define RADIOLIB_LORAWAN_MHDR_MTYPE_MASK (0x07 << 5) // 7 5 bitmask of all possible options +#define RADIOLIB_LORAWAN_MHDR_MAJOR_R1 (0x00 << 0) // 1 0 major version: LoRaWAN R1 + +// frame control field encoding +#define RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED (0x01 << 7) // 7 7 adaptive data rate: enabled +#define RADIOLIB_LORAWAN_FCTRL_ADR_DISABLED (0x00 << 7) // 7 7 disabled +#define RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ (0x01 << 6) // 6 6 adaptive data rate ACK request +#define RADIOLIB_LORAWAN_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge +#define RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending + +// port field +#define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only +#define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved port values + +// MAC commands - only those sent from end-device to gateway +#define RADIOLIB_LORAWAN_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network +#define RADIOLIB_LORAWAN_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change +#define RADIOLIB_LORAWAN_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change +#define RADIOLIB_LORAWAN_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request +#define RADIOLIB_LORAWAN_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information +#define RADIOLIB_LORAWAN_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel +#define RADIOLIB_LORAWAN_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing + +#define RADIOLIB_LORAWAN_NOPTS_LEN (8) + +// data rat encoding +#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 7 4 LoRaWAN spreading factor: SF12 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 7 4 SF11 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 7 4 SF10 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 7 4 SF9 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 7 4 SF8 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 7 4 SF7 +#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x00 << 4) // 7 4 FSK @ 50 kbps +#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 0) // 3 0 LoRaWAN bandwidth: 500 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 0) // 3 0 250 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 0) // 3 0 125 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate + +#define RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK (0x00 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0) +#define RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES (0) +#define RADIOLIB_LORAWAN_CFLIST_TYPE_MASK (1) +#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (16) + +// recommended default settings +#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) +#define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000) +#define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) +#define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384) +#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT (64) +#define RADIOLIB_LORAWAN_ADR_ACK_DELAY (32) +#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) +#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000) +#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2) + +// join request message layout +#define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS (9) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS (17) + +// join accept message layout +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN (33) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS (1) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS (4) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS (7) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS (11) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS (13) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN (16) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN - 1) + +// join accept message variables +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY (0x01) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY (0x02) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) + +// uplink message layout +#define RADIOLIB_LORAWAN_UPLINK_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) +#define RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS (16) +#define RADIOLIB_LORAWAN_UPLINK_DEV_ADDR_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 1) +#define RADIOLIB_LORAWAN_UPLINK_FCTRL_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 5) +#define RADIOLIB_LORAWAN_UPLINK_FCNT_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 6) +#define RADIOLIB_LORAWAN_UPLINK_FOPTS_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 8) +#define RADIOLIB_LORAWAN_UPLINK_FOPTS_MAX_LEN (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 16) +#define RADIOLIB_LORAWAN_UPLINK_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 8 + (FOPTS)) +#define RADIOLIB_LORAWAN_UPLINK_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 9 + (FOPTS)) + +// payload encryption/MIC blocks common layout +#define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0) +#define RADIOLIB_LORAWAN_BLOCK_DIR_POS (5) +#define RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS (6) +#define RADIOLIB_LORAWAN_BLOCK_FCNT_POS (10) + +// payload encryption block layout +#define RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC (0x01) +#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS (15) + +// payload MIC blocks layout +#define RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC (0x49) +#define RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS (15) +#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) +#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) + +#define RADIOLIB_LORAWAN_MAGIC (0x12AD101B) + +/*! + \struct LoRaWANChannelSpan_t + \brief Structure to save information about LoRaWAN channels. + To save space, adjacent channels are saved in "spans". +*/ +struct LoRaWANChannelSpan_t { + /*! \brief Whether this channel span is for uplink, downlink, or both directions*/ + uint8_t direction; + + /*! \brief Allowed data rates for a join request message */ + uint8_t joinRequestDataRate; + + /*! \brief Total number of channels in the span */ + uint8_t numChannels; + + /*! \brief Center frequency of the first channel in span */ + float freqStart; + + /*! \brief Frequency step between adjacent channels */ + float freqStep; + + /*! \brief Array of datarates supported by all channels in the span */ + uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; +}; + +// alias for unused channel span +#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_NONE, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .numChannels = 0, .freqStart = 0, .freqStep = 0, .dataRates = { 0 } } + +/*! + \struct LoRaWANBand_t + \brief Structure to save information about LoRaWAN band +*/ +struct LoRaWANBand_t { + /*! \brief The base downlik data rate. Used to calculate data rate changes for adaptive data rate */ + uint8_t downlinkDataRateBase; + + /*! \brief The minimum allowed downlik data rate. Used to calculate data rate changes for adaptive data rate */ + uint8_t downlinkDataRateMin; + + /*! \brief Array of allowed maximum payload lengths for each data rate */ + uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; + + /*! \brief Maximum allowed output power in this band in dBm */ + int8_t powerMax; + + /*! \brief Number of power steps in this band */ + int8_t powerNumSteps; + + /*! \brief Whether the optional channels are defined as list of frequencies or bit mask */ + uint8_t cfListType; + + /*! \brief Number of channel spans in the band */ + uint8_t numChannelSpans; + + /*! \brief Default uplink (TX/RX1) channels defined by LoRaWAN Regional Parameters */ + LoRaWANChannelSpan_t defaultChannels[3]; + + /*! \brief Backup downlink (RX2) channel - just a single channel, but using the same structure for convenience */ + LoRaWANChannelSpan_t backupChannel; +}; + +// supported bands +extern const LoRaWANBand_t EU868; +extern const LoRaWANBand_t US915; + +/*! + \class LoRaWANNode + \brief LoRaWAN-compatible node (class A device). +*/ +class LoRaWANNode { + public: + /*! + \brief Default constructor. + \param phy Pointer to the PhysicalLayer radio module. + \param band Pointer to the LoRaWAN band to use. + */ + LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band); + + /*! + \brief Wipe internal persistent parameters. + This will reset all counters and saved variables, so the device will have to rejoin the network. + */ + void wipe(); + + /*! + \brief Join network by loading information from persistent storage. + \returns \ref status_codes + */ + int16_t begin(); + + /*! + \brief Join network by performing over-the-air activation. By this procedure, + the device will perform an exchange with the network server and set all necessary configuration. + \param appEUI 8-byte application identifier. + \param devEUI 8-byte device identifier. + \param nwkKey Pointer to the network AES-128 key. + \param appKey Pointer to the application AES-128 key. + \param force Set to true to force joining even if previously joined. + \returns \ref status_codes + */ + int16_t beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false); + + /*! + \brief Join network by performing activation by personalization. + In this procedure, all necessary configuration must be provided by the user. + \param addr Device address. + \param net Network ID. + \param nwkSKey Pointer to the network session AES-128 key. + \param appSKey Pointer to the application session AES-128 key. + \returns \ref status_codes + */ + int16_t beginAPB(uint32_t addr, uint8_t net, uint8_t* nwkSKey, uint8_t* appSKey); + + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Send a message to the server. + \param str Address of Arduino String that will be transmitted. + \param port Port number to send the message to. + \returns \ref status_codes + */ + int16_t uplink(String& str, uint8_t port); + #endif + + /*! + \brief Send a message to the server. + \param str C-string that will be transmitted. + \param port Port number to send the message to. + \returns \ref status_codes + */ + int16_t uplink(const char* str, uint8_t port); + + /*! + \brief Send a message to the server. + \param data Data to send. + \param len Length of the data. + \param port Port number to send the message to. + \returns \ref status_codes + */ + int16_t uplink(uint8_t* data, size_t len, uint8_t port); + + /*! + \brief Configure the radio to a given channel frequency and data rate. + \param chan Channel ID to set. + \param dr Data rate to set, DR0 - DR15. + \returns \ref status_codes + */ + int16_t configureChannel(uint8_t chan, uint8_t dr); + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + PhysicalLayer* phyLayer; + const LoRaWANBand_t* band; + + // the following is either provided by the network server (OTAA) + // or directly entered by the user (ABP) + uint32_t devAddr; + uint8_t appSKey[RADIOLIB_AES128_KEY_SIZE]; + uint8_t fNwkSIntKey[RADIOLIB_AES128_KEY_SIZE]; + uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE]; + uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE]; + uint8_t rxDelay; + float availableChannelsFreq[5]; + uint16_t availableChannelsMask[6]; + + // currently configured data rate DR0 - DR15 (band-dependent!) + uint8_t dataRate; + + // currently configured channel (band-dependent!) + uint8_t chIndex; + + // method to generate message integrity code + uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); + + // method to verify message integrity code + // it assumes that the MIC is the last 4 bytes of the message + bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); + + int16_t setPhyProperties(); + + // network-to-host conversion method - takes data from network packet and converts it to the host endians + template + static T ntoh(uint8_t* buff, size_t size = 0); + + // host-to-network conversion method - takes data from host variable and and converts it to network packet endiands + template + static void hton(uint8_t* buff, T val, size_t size = 0); +}; + +#endif diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp new file mode 100644 index 0000000000..57f026d2c6 --- /dev/null +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -0,0 +1,191 @@ +#include "LoRaWAN.h" + +#if !defined(RADIOLIB_EXCLUDE_LORAWAN) + +uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_t lim) { + int8_t dr = uplink - offset + base; + if(dr < lim) { + dr = lim; + } + return(dr); +} + +const LoRaWANBand_t EU868 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .numChannelSpans = 1, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 3, + .freqStart = 868.1, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 869.858, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t US915 = { + .downlinkDataRateBase = 10, + .downlinkDataRateMin = 8, + .payloadLenMax = { + 19, 61, 133, 250, 250, 0, 0, 0, + 41, 117, 230, 230, 230, 230, 0, 0 }, + .powerMax = 30, + .powerNumSteps = 10, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, + .numChannelSpans = 3, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + .joinRequestDataRate = 0, + .numChannels = 64, + .freqStart = 902.3, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + .joinRequestDataRate = 4, + .numChannels = 8, + .freqStart = 903, + .freqStep = 1.6, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 8, + .freqStart = 923.3, + .freqStep = 0.6, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 869.858, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +#endif From a27d54716cb555395711c18f4e9868151d910473 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 18:38:20 +0200 Subject: [PATCH 0665/1848] [LoRaWAN] Added all official bands --- keywords.txt | 11 + src/protocols/LoRaWAN/LoRaWAN.h | 7 + src/protocols/LoRaWAN/LoRaWANBands.cpp | 533 ++++++++++++++++++++++++- 3 files changed, 550 insertions(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index acb0254375..70935d1077 100644 --- a/keywords.txt +++ b/keywords.txt @@ -75,6 +75,17 @@ Bell101 KEYWORD1 Bell103 KEYWORD1 Bell202 KEYWORD1 +# LoRaWAN bands +EU868 KEYWORD1 +US915 KEYWORD1 +CN780 KEYWORD1 +EU433 KEYWORD1 +AU915 KEYWORD1 +CN500 KEYWORD1 +AS923 KEYWORD1 +KR920 KEYWORD1 +IN865 KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index ac5d74672e..1d1b0620a7 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -196,6 +196,13 @@ struct LoRaWANBand_t { // supported bands extern const LoRaWANBand_t EU868; extern const LoRaWANBand_t US915; +extern const LoRaWANBand_t CN780; +extern const LoRaWANBand_t EU433; +extern const LoRaWANBand_t AU915; +extern const LoRaWANBand_t CN500; +extern const LoRaWANBand_t AS923; +extern const LoRaWANBand_t KR920; +extern const LoRaWANBand_t IN865; /*! \class LoRaWANNode diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 57f026d2c6..c04269dc6c 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -165,7 +165,340 @@ const LoRaWANBand_t US915 = { .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .numChannels = 1, - .freqStart = 869.858, + .freqStart = 923.3, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t CN780 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 250, 230, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 12, + .powerNumSteps = 5, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .numChannelSpans = 1, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 6, + .freqStart = 779.5, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 786, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t EU433 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 12, + .powerNumSteps = 5, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .numChannelSpans = 1, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 3, + .freqStart = 433.175, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 434.665, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t AU915 = { + .downlinkDataRateBase = 8, + .downlinkDataRateMin = 8, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 230, 0, + 41, 117, 230, 230, 230, 230, 0, 0 }, + .powerMax = 30, + .powerNumSteps = 10, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, + .numChannelSpans = 3, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + .joinRequestDataRate = 0, + .numChannels = 64, + .freqStart = 915.2, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + .joinRequestDataRate = 6, + .numChannels = 8, + .freqStart = 915.9, + .freqStep = 1.6, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 8, + .freqStart = 923.3, + .freqStep = 0.6, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 923.3, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t CN500 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 19, + .powerNumSteps = 7, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, + .numChannelSpans = 2, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 96, + .freqStart = 470.3, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 48, + .freqStart = 500.3, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 505.3, .freqStep = 0, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, @@ -188,4 +521,202 @@ const LoRaWANBand_t US915 = { } }; +const LoRaWANBand_t AS923 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .numChannelSpans = 1, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, + .joinRequestDataRate = 2, + .numChannels = 2, + .freqStart = 923.2, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 923.2, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t KR920 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 14, + .powerNumSteps = 7, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .numChannelSpans = 1, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 3, + .freqStart = 922.1, + .freqStep = 0.2, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 921.9, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + +const LoRaWANBand_t IN865 = { + .downlinkDataRateBase = 0, + .downlinkDataRateMin = 0, + .payloadLenMax = { + 59, 59, 59, 123, 230, 230, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 30, + .powerNumSteps = 10, + .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .numChannelSpans = 1, + .defaultChannels = { + { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 3, + .freqStart = 865.0625, + .freqStep = 0.36, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } + }, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + }, + .backupChannel = { + .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .numChannels = 1, + .freqStart = 866.55, + .freqStep = 0, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + } + } +}; + #endif From f354903864f404e306b5ffeaed3ea097bef0ef7d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 18:50:04 +0200 Subject: [PATCH 0666/1848] [LoRaWAN] Added rev 1.1 checking --- src/protocols/LoRaWAN/LoRaWAN.cpp | 13 +++++++++++-- src/protocols/LoRaWAN/LoRaWAN.h | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index dafbe9bd08..a25b236871 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -183,11 +183,14 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // check protocol version (1.0 vs 1.1) if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { // TODO implement 1.1 + this->rev = 1; RADIOLIB_DEBUG_PRINTLN("LoRaWAN 1.1 not supported (yet)"); + (void)appKey; return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); } else { // 1.0 version, just derive the keys + this->rev = 0; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -332,8 +335,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { uint32_t micS = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->sNwkSIntKey); memcpy(uplinkMsg, block0, RADIOLIB_AES128_BLOCK_SIZE); uint32_t micF = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->fNwkSIntKey); - // TODO check LoRaWAN 1.0/1.1 - LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); + + // check LoRaWAN revision + if(this->rev == 1) { + uint32_t mic = ((uint32_t)(micS & 0x00FF) << 24) | ((uint32_t)(micS & 0xFF00) << 8) | ((uint32_t)(micF & 0xFF00) >> 8) | ((uint32_t)(micF & 0x00FF) << 8); + LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], mic); + } else { + LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); + } //Module::hexdump(uplinkMsg, uplinkMsgLen); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 1d1b0620a7..7c1ee123fd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -304,6 +304,9 @@ class LoRaWANNode { float availableChannelsFreq[5]; uint16_t availableChannelsMask[6]; + // LoRaWAN revision (1.0 vs 1.1) + uint8_t rev; + // currently configured data rate DR0 - DR15 (band-dependent!) uint8_t dataRate; From a78c41561633fc7f05678121bfff9ed72a3a74ad Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 6 Jul 2023 19:00:41 +0200 Subject: [PATCH 0667/1848] [LoRaWAN] Fixed loop comparison --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a25b236871..12769cb547 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -482,7 +482,7 @@ T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { targetSize = size; } T res = 0; - for(uint8_t i = 0; i < targetSize; i++) { + for(size_t i = 0; i < targetSize; i++) { res |= (uint32_t)(*(buffPtr++)) << 8*i; } return(res); @@ -495,7 +495,7 @@ void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { if(size != 0) { targetSize = size; } - for(uint8_t i = 0; i < targetSize; i++) { + for(size_t i = 0; i < targetSize; i++) { *(buffPtr++) = val >> 8*i; } } From d9538f959a5281d2fbc01aa81e0a8b36a4023a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicklas=20B=C3=B6rjesson?= Date: Thu, 6 Jul 2023 22:43:33 +0200 Subject: [PATCH 0668/1848] Add parenthesis for compatibility Hi, I am getting a compile error on ESP-IDF/Platformio: ``` managed_components/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp: In member function 'int16_t LoRaWANNode::beginOTAA(uint64_t, uint64_t, uint8_t*, uint8_t*, bool)': managed_components/RadioLib/src/protocols/LoRaWAN/LoRaWAN.cpp:125:61: error: suggest parentheses around comparison in operand of '&' [-Werror=parentheses] 125 | if(joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { cc1plus: some warnings being treated as errors *** [.pio/build/TTGO-LoRa32-v1/managed_components/RadioLib/src/protocols/LoRaWAN/LoRaWAN.o] Error 1 I propose adding a parenthesis, for clarity and compatibility. --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 12769cb547..734c9b8db8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -122,7 +122,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey RADIOLIB_ASSERT(state); // check reply message type - if(joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { + if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { RADIOLIB_DEBUG_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); return(RADIOLIB_ERR_RX_TIMEOUT); } From ccbec2c7bdb499a2a769e2f6335de53647ed53a3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 7 Jul 2023 20:33:48 +0200 Subject: [PATCH 0669/1848] [FEC] Fixed memory leak (#646) --- src/utils/FEC.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/FEC.cpp b/src/utils/FEC.cpp index d08f9426fa..107ec1b5a1 100644 --- a/src/utils/FEC.cpp +++ b/src/utils/FEC.cpp @@ -246,6 +246,8 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } + delete[] recd; + return(res); } From 01917ad0c220c9a9e1921102ad1aa3ecc21a10db Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 7 Jul 2023 20:39:00 +0200 Subject: [PATCH 0670/1848] [FEC] Implemented static-only memory management --- src/utils/FEC.cpp | 51 +++++++++++++++++++++++++++++++++++++++++------ src/utils/FEC.h | 18 ++++++++++++++--- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/utils/FEC.cpp b/src/utils/FEC.cpp index 107ec1b5a1..e8cf260ea9 100644 --- a/src/utils/FEC.cpp +++ b/src/utils/FEC.cpp @@ -14,9 +14,11 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { this->n = n; this->k = k; this->poly = poly; + #if !defined(RADIOLIB_STATIC_ONLY) this->alphaTo = new int32_t[n + 1]; this->indexOf = new int32_t[n + 1]; this->generator = new int32_t[n - k + 1]; + #endif // find the maximum power of the polynomial for(this->m = 0; this->m < 31; this->m++) { @@ -113,7 +115,11 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { // Search for roots 1, 2, ..., m-1 in cycle sets int32_t rdncy = 0; - int32_t* min = new int32_t[this->n - this->k + 1]; + #if defined(RADIOLIB_STATIC_ONLY) + int32_t min[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* min = new int32_t[this->n - this->k + 1]; + #endif kaux = 0; for(ii = 1; ii <= jj; ii++) { @@ -133,7 +139,11 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { } int32_t noterms = kaux; - int32_t* zeros = new int32_t[this->n - this->k + 1]; + #if defined(RADIOLIB_STATIC_ONLY) + int32_t zeros[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* zeros = new int32_t[this->n - this->k + 1]; + #endif kaux = 1; for(ii = 0; ii < noterms; ii++) { @@ -143,7 +153,9 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { } } + #if !defined(RADIOLIB_STATIC_ONLY) delete[] min; + #endif // Compute generator polynomial this->generator[0] = this->alphaTo[zeros[1]]; @@ -161,7 +173,9 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { this->generator[0] = this->alphaTo[(this->indexOf[this->generator[0]] + zeros[ii]) % this->n]; } + #if !defined(RADIOLIB_STATIC_ONLY) delete[] zeros; + #endif } /* @@ -171,7 +185,11 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { */ uint32_t RadioLibBCH::encode(uint32_t dataword) { // we only use the "k" most significant bits - int32_t* data = new int32_t[this->k]; + #if defined(RADIOLIB_STATIC_ONLY) + int32_t data[RADIOLIB_BCH_MAX_K]; + #else + int32_t* data = new int32_t[this->k]; + #endif int32_t j1 = 0; for(int32_t i = this->n; i > (this->n - this->k); i--) { if(dataword & ((uint32_t)1<n]; + #if defined(RADIOLIB_STATIC_ONLY) + int32_t Mr[RADIOLIB_BCH_MAX_N]; + #else + int32_t* Mr = new int32_t[this->n]; + #endif memset(Mr, 0x00, this->n*sizeof(int32_t)); // copy the contents of data into Mr and add the zeros @@ -205,16 +227,27 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } - int32_t* bb = new int32_t[this->n - this->k + 1]; + #if defined(RADIOLIB_STATIC_ONLY) + int32_t bb[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* bb = new int32_t[this->n - this->k + 1]; + #endif j = 0; for(int32_t i = start; i < end; ++i) { bb[j] = Mr[i]; ++j; } + + #if !defined(RADIOLIB_STATIC_ONLY) delete[] Mr; + #endif int32_t iEvenParity = 0; - int32_t* recd = new int32_t[this->n + 1]; + #if defined(RADIOLIB_STATIC_ONLY) + int32_t recd[RADIOLIB_BCH_MAX_N + 1]; + #else + int32_t* recd = new int32_t[this->n + 1]; + #endif for(uint8_t i = 0; i < this->k; i++) { recd[this->n - i] = data[i]; if(data[i] == 1) { @@ -222,7 +255,9 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } + #if !defined(RADIOLIB_STATIC_ONLY) delete[] data; + #endif for(uint8_t i = 0; i < this->n - this->k + 1; i++) { recd[this->n - this->k - i] = bb[i]; @@ -231,7 +266,9 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } + #if !defined(RADIOLIB_STATIC_ONLY) delete[] bb; + #endif if((iEvenParity % 2) == 0) { recd[0] = 0; @@ -246,7 +283,9 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } + #if !defined(RADIOLIB_STATIC_ONLY) delete[] recd; + #endif return(res); } diff --git a/src/utils/FEC.h b/src/utils/FEC.h index acdb457188..76f2bcad17 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -12,6 +12,11 @@ #define RADIOLIB_PAGER_BCH_K (21) #define RADIOLIB_PAGER_BCH_PRIMITIVE_POLY (0x25) +#if defined(RADIOLIB_STATIC_ONLY) +#define RADIOLIB_BCH_MAX_N (63) +#define RADIOLIB_BCH_MAX_K (31) +#endif + /*! \class RadioLibBCH \brief Class to calculate Bose–Chaudhuri–Hocquenghem (BCH) class of forward error correction codes. @@ -46,9 +51,16 @@ class RadioLibBCH { uint8_t k; uint32_t poly; uint8_t m; - int32_t* alphaTo; - int32_t* indexOf; - int32_t* generator; + + #if defined(RADIOLIB_STATIC_ONLY) + int32_t alphaTo[RADIOLIB_BCH_MAX_N + 1]; + int32_t indexOf[RADIOLIB_BCH_MAX_N + 1]; + int32_t generator[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + #else + int32_t* alphaTo; + int32_t* indexOf; + int32_t* generator; + #endif }; // the global singleton From b1397675591e37bfedd7a11c92741ef4b9d3f450 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 7 Jul 2023 20:48:51 +0200 Subject: [PATCH 0671/1848] [EXT] Implemented direct transmit (#646) --- src/protocols/ExternalRadio/ExternalRadio.cpp | 40 +++++++++++++-- src/protocols/ExternalRadio/ExternalRadio.h | 49 ++++++++++++++++++- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index 48332fec66..0748b4955e 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -1,15 +1,47 @@ #include "ExternalRadio.h" #if defined(RADIOLIB_BUILD_ARDUINO) -ExternalRadio::ExternalRadio() : PhysicalLayer(1, 0) { - mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); +ExternalRadio::ExternalRadio(uint32_t pin) : PhysicalLayer(1, 0) { + mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin); + mod->hal->pinMode(pin, mod->hal->GpioModeOutput); + this->prevFrf = 0; } #endif -ExternalRadio::ExternalRadio(RadioLibHal *hal) : PhysicalLayer(1, 0) { - mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); +ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer(1, 0) { + mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin); + mod->hal->pinMode(pin, mod->hal->GpioModeOutput); + this->prevFrf = 0; } Module* ExternalRadio::getMod() { return(mod); +} + +int16_t ExternalRadio::setFrequencyDeviation(float freqDev) { + (void)freqDev; + return(RADIOLIB_ERR_NONE); +} + +int16_t ExternalRadio::setDataShaping(uint8_t sh) { + (void)sh; + return(RADIOLIB_ERR_NONE); +} + +int16_t ExternalRadio::setEncoding(uint8_t encoding) { + (void)encoding; + return(RADIOLIB_ERR_NONE); +} + +int16_t ExternalRadio::transmitDirect(uint32_t frf) { + if(frf != this->prevFrf) { + uint32_t val = this->mod->hal->GpioLevelLow; + if(frf > this->prevFrf) { + val = this->mod->hal->GpioLevelHigh; + } + this->prevFrf = frf; + this->mod->hal->digitalWrite(this->mod->getGpio(), val); + } + + return(RADIOLIB_ERR_NONE); } \ No newline at end of file diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index bbbbd44749..25908fd0b4 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -12,13 +12,58 @@ class ExternalRadio: public PhysicalLayer { public: #if defined(RADIOLIB_BUILD_ARDUINO) - ExternalRadio(); + /*! + \brief Default constructor. + \param pin Output pin when using direct transmission, defaults to unused pin. + */ + ExternalRadio(uint32_t pin = RADIOLIB_NC); #endif - ExternalRadio(RadioLibHal *hal); + + /*! + \brief Default constructor. + \param hal Pointer to the hardware abstraction layer to use. + \param pin Output pin when using direct transmission, defaults to unused pin. + */ + ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC); + /*! + \brief Method to retrieve pointer to the underlying Module instance. + \returns Pointer to the Module instance. + */ Module* getMod(); + + /*! + \brief Dummy implementation overriding PhysicalLayer. + \param freqDev Ignored. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Dummy implementation overriding PhysicalLayer. + \param sh Ignored. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Dummy implementation overriding PhysicalLayer. + \param encoding Ignored. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Direct transmission to drive external radio. + \param frf "Frequency" to control the output pin. If the frequency is higher than the one sent previously, + the output pin will be set to logic high. Otherwise it will be set to logic low. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0); + private: Module* mod; + uint32_t prevFrf; }; #endif \ No newline at end of file From fc983efafb0d586b0890d2b649cb128833de4206 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 8 Jul 2023 08:51:58 +0200 Subject: [PATCH 0672/1848] [Crypto] Fixed missing nonvolatile read --- src/utils/Cryptography.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp index 7be62b6ce5..16d1c46da9 100644 --- a/src/utils/Cryptography.cpp +++ b/src/utils/Cryptography.cpp @@ -221,7 +221,7 @@ void RadioLibAES128::generateSubkeys(uint8_t* key1, uint8_t* key2) { void RadioLibAES128::subBytes(state_t* state, const uint8_t* box) { for(size_t row = 0; row < 4; row++) { for(size_t col = 0; col < 4; col++) { - (*state)[col][row] = box[(*state)[col][row]]; + (*state)[col][row] = RADIOLIB_NONVOLATILE_READ_BYTE(&box[(*state)[col][row]]); } } } From 89e405eebad21b3e37a6c76aba903459e2bf73ec Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 8 Jul 2023 09:37:43 +0200 Subject: [PATCH 0673/1848] [LoRaWAN] Fixes for SX127x series --- src/protocols/LoRaWAN/LoRaWAN.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 734c9b8db8..ecaf44654a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -89,6 +89,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // start receiving uint32_t start = mod->hal->millis(); + downlinkReceived = false; state = this->phyLayer->startReceive(); RADIOLIB_ASSERT(state); @@ -119,7 +120,11 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // read the packet state = this->phyLayer->readData(joinAcceptMsgEnc, lenRx); - RADIOLIB_ASSERT(state); + // downlink frames are sent without CRC, which will raise error on SX127x + // we can ignore that error + if(state != RADIOLIB_ERR_LORA_HEADER_DAMAGED) { + RADIOLIB_ASSERT(state); + } // check reply message type if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { From ae05a4283e2838190f1bac51f6ebb6033d75e040 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 7 Jul 2023 21:05:48 +1000 Subject: [PATCH 0674/1848] Tock: Use Tock's libgcc The Tock specific version of libgcc is built to be position independent, so use that instead of the one supplied by the compiler. This fixes a few odd corner cases when using printf(). Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/NonArduino/Tock/CMakeLists.txt b/examples/NonArduino/Tock/CMakeLists.txt index 19f6e2b4b0..c7aaf866bd 100644 --- a/examples/NonArduino/Tock/CMakeLists.txt +++ b/examples/NonArduino/Tock/CMakeLists.txt @@ -45,8 +45,8 @@ add_executable(${PROJECT_NAME} main.cpp) # link with RadioLib and libtock-c target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib - gcc ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libgcc.a ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libstdc++.a ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libc.a ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libm.a From a72b549450a77f7517360bc0a0d0fcb68258116a Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 8 Jul 2023 21:39:44 +1000 Subject: [PATCH 0675/1848] Tock: Implement yield() Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/libtockHal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/NonArduino/Tock/libtockHal.h b/examples/NonArduino/Tock/libtockHal.h index 34af2dfcaa..d9acf717f3 100644 --- a/examples/NonArduino/Tock/libtockHal.h +++ b/examples/NonArduino/Tock/libtockHal.h @@ -190,6 +190,10 @@ class TockHal : public RadioLibHal { void spiEnd() { } + void yield() { + ::yield(); + } + private: }; From 6a6bb8526b2477fa63409b8bf45b95b45ca298e8 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 8 Jul 2023 22:14:33 +1000 Subject: [PATCH 0676/1848] Tock: Update Radio config for SparkFun LoRa Thing Plus - expLoRaBLE Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index 56df5fb4e8..d3bbc6c5ca 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -46,7 +46,10 @@ int main(void) { Module* tock_module = new Module(hal, RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY); SX1262* radio = new SX1262(tock_module); - int state = radio->begin(); + // Setup the radio + // The settings here work for the SparkFun LoRa Thing Plus - expLoRaBLE + int state = radio->begin(915.0, 125.0, 9, 7, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 10, 8, 0, false); + if (state != RADIOLIB_ERR_NONE) { printf("failed, code %d\n", state); return 1; From 5750d8879795becc9e7d3b64afc9a9b9e7488ad2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 8 Jul 2023 22:15:07 +1000 Subject: [PATCH 0677/1848] Tock: Use \r\n for all new lines Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index d3bbc6c5ca..a5cab8b60d 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -32,7 +32,7 @@ // the entry point for the program int main(void) { - printf("[SX1261] Initializing ... \n"); + printf("[SX1261] Initialising Radio ... \r\n"); // create a new instance of the HAL class TockHal* hal = new TockHal(); @@ -51,27 +51,27 @@ int main(void) { int state = radio->begin(915.0, 125.0, 9, 7, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 10, 8, 0, false); if (state != RADIOLIB_ERR_NONE) { - printf("failed, code %d\n", state); + printf("failed, code %d\r\n", state); return 1; } - printf("success!\n"); + printf("success!\r\n"); // loop forever for(;;) { yield_no_wait(); // send a packet - printf("[SX1261] Transmitting packet ... \n"); + printf("[SX1261] Transmitting '%s' \r\n", transmit_string); state = radio->transmit("Hello World!"); if(state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted - printf("success!\n"); + printf("success!\r\n"); // wait for a second before transmitting again hal->delay(1000); } else { - printf("failed, code %d\n", state); + printf("failed, code %d\r\n", state); } } From 3c7dc7acba2f90200aea3235eba5d22d7d981e62 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 11 Jul 2023 22:10:32 +1000 Subject: [PATCH 0678/1848] Tock: README: Initial commit Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 examples/NonArduino/Tock/README.md diff --git a/examples/NonArduino/Tock/README.md b/examples/NonArduino/Tock/README.md new file mode 100644 index 0000000000..cd13b6dcd7 --- /dev/null +++ b/examples/NonArduino/Tock/README.md @@ -0,0 +1,28 @@ +# RadioLib as Tock application + +[Tock](https://github.com/tock/tock) is an embedded operating system designed +for running multiple concurrent, mutually distrustful applications on Cortex-M +and RISC-V based embedded platforms. + +RadioLib can be built as a Tock application using +[libtock-c](https://github.com/tock/libtock-c). This is an example of running +RadioLib as a Tock application. + +This has been tested on the +[SparkFun LoRa Thing Plus - expLoRaBLE board] (https://github.com/tock/tock/tree/master/boards/apollo3/lora_things_plus) +but will work on any LoRa compatible Tock board (currently only the +expLoRaBLE board). + +The RadioLib example can be built with: + +```shell +$ git clone https://github.com/jgromes/RadioLib.git +$ cd RadioLib/examples/NonArduino/Tock/ +$ ./build.sh +``` + +Then in the Tock repo you can flash the kernel and app with: + +```shell +$ make flash; APP=RadioLib/examples/NonArduino/Tock/build/tock-sx1261.tbf make flash-app +``` From bb6106381009fb091bf597d1e79cf104e7d2bc78 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 11 Jul 2023 22:11:27 +1000 Subject: [PATCH 0679/1848] Tock: Expand the .gitignore Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/NonArduino/Tock/.gitignore b/examples/NonArduino/Tock/.gitignore index 567609b123..bd0079c9ae 100644 --- a/examples/NonArduino/Tock/.gitignore +++ b/examples/NonArduino/Tock/.gitignore @@ -1 +1,2 @@ build/ +TockApp.tab From 8fd0a67a78e444ca3a74aa5779a0722f39f2c244 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Jul 2023 19:13:16 +0200 Subject: [PATCH 0680/1848] Typo fixes --- src/BuildOpt.h | 2 +- src/Hal.h | 13 +++++++--- src/Module.h | 8 +++--- src/TypeDef.h | 10 ++++---- src/modules/RF69/RF69.h | 8 +++--- src/modules/SX126x/STM32WLx.h | 2 +- src/modules/SX126x/SX126x.h | 10 ++++---- src/modules/SX127x/SX127x.h | 8 +++--- src/modules/SX128x/SX128x.h | 2 +- src/modules/Si443x/Si443x.h | 4 +-- src/protocols/LoRaWAN/LoRaWAN.h | 6 ++--- src/protocols/Morse/Morse.h | 28 ++++++++++----------- src/protocols/Pager/Pager.h | 4 +-- src/protocols/PhysicalLayer/PhysicalLayer.h | 6 ++--- src/utils/CRC.h | 2 +- src/utils/Cryptography.h | 2 +- 16 files changed, 60 insertions(+), 55 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 9b7950f466..80a2839c01 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -348,7 +348,7 @@ /* * Uncomment to enable "paranoid" SPI mode * Every write to an SPI register using SPI set function will be verified by a subsequent read operation. - * This improves reliablility, but slightly slows down communication. + * This improves reliability, but slightly slows down communication. * Note: Enabled by default. */ #if !defined(RADIOLIB_SPI_PARANOID) diff --git a/src/Hal.h b/src/Hal.h index ef8c0ee09a..6fa800b14a 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -193,13 +193,13 @@ class RadioLibHal { /*! \brief Module initialization method. This will be called by all radio modules at the beginning of startup. - Can be used to e.g., initalize SPI interface. + Can be used to e.g., initialize SPI interface. */ virtual void init(); /*! \brief Module termination method. - This will be called by all radio modules when the desctructor is called. + This will be called by all radio modules when the destructor is called. Can be used to e.g., stop SPI interface. */ virtual void term(); @@ -251,7 +251,12 @@ class RadioLibHal { Will write at most RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE bytes. */ void wipePersistentStorage(); - + + /*! + \brief Method to convert from persistent parameter ID to its physical address. + \param id Parameter ID. + \returns Parameter physical address. + */ uint32_t getPersistentAddr(uint32_t id); /*! @@ -269,7 +274,7 @@ class RadioLibHal { This method DOES NOT perform any endianness conversion, so the value will be retrieved in the system endian! \param id Parameter ID to load from. - \returns The lodaded value. + \returns The loaded value. */ template T getPersistentParameter(uint32_t id); diff --git a/src/Module.h b/src/Module.h index 7c5216d56b..2540673425 100644 --- a/src/Module.h +++ b/src/Module.h @@ -256,8 +256,8 @@ class Module { \brief SPI single transfer method. \param cmd SPI access command (read/write/burst/...). \param reg Address of SPI register to transfer to/from. - \param dataOut Data that will be transfered from master to slave. - \param dataIn Data that was transfered from slave to master. + \param dataOut Data that will be transferred from master to slave. + \param dataIn Data that was transferred from slave to master. \param numBytes Number of bytes to transfer. */ void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); @@ -319,8 +319,8 @@ class Module { \param cmd SPI operation command. \param cmdLen SPI command length in bytes. \param write Set to true for write commands, false for read commands. - \param dataOut Data that will be transfered from master to slave. - \param dataIn Data that was transfered from slave to master. + \param dataOut Data that will be transferred from master to slave. + \param dataIn Data that was transferred from slave to master. \param numBytes Number of bytes to transfer. \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). \param timeout GPIO wait period timeout in milliseconds. diff --git a/src/TypeDef.h b/src/TypeDef.h index 64fba9ced3..a363f3abab 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -17,22 +17,22 @@ #define RADIOLIB_SHAPING_NONE (0x00) /*! - \brief Gaussin shaping filter, BT = 0.3 + \brief Gaussian shaping filter, BT = 0.3 */ #define RADIOLIB_SHAPING_0_3 (0x01) /*! - \brief Gaussin shaping filter, BT = 0.5 + \brief Gaussian shaping filter, BT = 0.5 */ #define RADIOLIB_SHAPING_0_5 (0x02) /*! - \brief Gaussin shaping filter, BT = 0.7 + \brief Gaussian shaping filter, BT = 0.7 */ #define RADIOLIB_SHAPING_0_7 (0x03) /*! - \brief Gaussin shaping filter, BT = 1.0 + \brief Gaussian shaping filter, BT = 1.0 */ #define RADIOLIB_SHAPING_1_0 (0x04) @@ -310,7 +310,7 @@ #define RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY_LENGTH (-203) /*! - \brief Mic-E message cannot contaion both telemetry and status text. + \brief Mic-E message cannot contain both telemetry and status text. */ #define RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS (-204) diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index dfe0308fb6..5facc34816 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -124,7 +124,7 @@ // RADIOLIB_RF69_REG_BITRATE_MSB + REG_BITRATE_LSB #define RADIOLIB_RF69_BITRATE_MSB 0x1A // 7 0 bit rate setting: rate = F(XOSC) / BITRATE -#define RADIOLIB_RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps 0x40 // 7 0 +#define RADIOLIB_RF69_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps // RADIOLIB_RF69_REG_FDEV_MSB + REG_FDEV_LSB #define RADIOLIB_RF69_FDEV_MSB 0x00 // 5 0 frequency deviation: f_dev = f_step * FDEV @@ -671,7 +671,7 @@ class RF69: public PhysicalLayer { bool fifoAdd(uint8_t* data, int totalLen, int* remLen); /*! - \brief Set interrupt service routine function to call when FIFO is sufficently full to read. + \brief Set interrupt service routine function to call when FIFO is sufficiently full to read. \param data Pointer to a buffer that stores the receive data. \param totalLen Total number of bytes to receive. \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. @@ -714,7 +714,7 @@ class RF69: public PhysicalLayer { /*! \brief Reads data received after calling startReceive method. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -974,7 +974,7 @@ class RF69: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! - \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index 742d8c8cc7..42e073a4bf 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -81,7 +81,7 @@ class STM32WLx : public SX1262 { This automatically switches between the low-power (LP) and high-power (HP) amplifier. LP is preferred and supports -17 to +14dBm. When a higher power is - requested (or the LP amplifier is marked as unvailable using + requested (or the LP amplifier is marked as unavailable using setRfSwitchTable()), HP is used, which supports -9 to +22dBm. \param power Output power to be set in dBm. diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d2ea17162f..398a29e450 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -35,10 +35,10 @@ #define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 // register and buffer access commands -#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D -#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D -#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E -#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E +#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D +#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D +#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E +#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E // DIO and IRQ control #define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 @@ -673,7 +673,7 @@ class SX126x: public PhysicalLayer { /*! \brief Reads data received after calling startReceive method. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 3ba9a3196c..7730b14732 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -770,7 +770,7 @@ class SX127x: public PhysicalLayer { bool fifoAdd(uint8_t* data, int totalLen, int* remLen); /*! - \brief Set interrupt service routine function to call when FIFO is sufficently full to read. + \brief Set interrupt service routine function to call when FIFO is sufficiently full to read. \param data Pointer to a buffer that stores the receive data. \param totalLen Total number of bytes to receive. \param rcvLen Pointer to a counter holding the number of bytes that have been received so far. @@ -822,7 +822,7 @@ class SX127x: public PhysicalLayer { /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -1093,7 +1093,7 @@ class SX127x: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! - \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); @@ -1202,7 +1202,7 @@ class SX127x: public PhysicalLayer { /*! \brief Calculate exponent and mantissa values for receiver bandwidth and AFC \param bandwidth bandwidth to be set (in kHz). - \returns bandwidth in manitsa and exponent format + \returns bandwidth in mantissa and exponent format */ static uint8_t calculateBWManExp(float bandwidth); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index ca69f843e9..cb22ac2f66 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -564,7 +564,7 @@ class SX128x: public PhysicalLayer { /*! \brief Reads data received after calling startReceive method. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index c2841b9d1b..b4c3f7dc42 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -712,7 +712,7 @@ class Si443x: public PhysicalLayer { /*! \brief Reads data that was received after calling startReceive method. This method reads len characters. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -798,7 +798,7 @@ class Si443x: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! - \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 7c1ee123fd..4b33f93249 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -165,10 +165,10 @@ struct LoRaWANChannelSpan_t { \brief Structure to save information about LoRaWAN band */ struct LoRaWANBand_t { - /*! \brief The base downlik data rate. Used to calculate data rate changes for adaptive data rate */ + /*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */ uint8_t downlinkDataRateBase; - /*! \brief The minimum allowed downlik data rate. Used to calculate data rate changes for adaptive data rate */ + /*! \brief The minimum allowed downlink data rate. Used to calculate data rate changes for adaptive data rate */ uint8_t downlinkDataRateMin; /*! \brief Array of allowed maximum payload lengths for each data rate */ @@ -326,7 +326,7 @@ class LoRaWANNode { template static T ntoh(uint8_t* buff, size_t size = 0); - // host-to-network conversion method - takes data from host variable and and converts it to network packet endiands + // host-to-network conversion method - takes data from host variable and and converts it to network packet endians template static void hton(uint8_t* buff, T val, size_t size = 0); }; diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 3bc414644d..df44bc1f84 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -9,7 +9,7 @@ #define RADIOLIB_MORSE_DOT 0b0 #define RADIOLIB_MORSE_DASH 0b1 #define RADIOLIB_MORSE_GUARDBIT 0b1 -#define RADIOLIB_MORSE_UNSUPORTED 0xFF +#define RADIOLIB_MORSE_UNSUPPORTED 0xFF #define RADIOLIB_MORSE_ASCII_OFFSET 32 #define RADIOLIB_MORSE_INTER_SYMBOL 0x00 #define RADIOLIB_MORSE_CHAR_COMPLETE 0x01 @@ -18,19 +18,19 @@ // Morse character table: - using codes defined in ITU-R M.1677-1 // - Morse code representation is saved LSb first, using additional bit as guard // - position in array corresponds ASCII code minus RADIOLIB_MORSE_ASCII_OFFSET -// - ASCII characters marked RADIOLIB_MORSE_UNSUPORTED do not have ITU-R M.1677-1 equivalent +// - ASCII characters marked RADIOLIB_MORSE_UNSUPPORTED do not have ITU-R M.1677-1 equivalent static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { 0b00, // space 0b110101, // ! (unsupported) 0b1010010, // " - RADIOLIB_MORSE_UNSUPORTED, // # (unsupported) - RADIOLIB_MORSE_UNSUPORTED, // $ (unsupported) - RADIOLIB_MORSE_UNSUPORTED, // % (unsupported) - RADIOLIB_MORSE_UNSUPORTED, // & (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // # (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // $ (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // % (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // & (unsupported) 0b1011110, // ' 0b101101, // ( 0b1101101, // ) - RADIOLIB_MORSE_UNSUPORTED, // * (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // * (unsupported) 0b101010, // + 0b1110011, // , 0b1100001, // - @@ -47,10 +47,10 @@ static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { 0b100111, // 8 0b101111, // 9 0b1000111, // : - RADIOLIB_MORSE_UNSUPORTED, // ; (unsupported) - RADIOLIB_MORSE_UNSUPORTED, // < (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // ; (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // < (unsupported) 0b110001, // = - RADIOLIB_MORSE_UNSUPORTED, // > (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // > (unsupported) 0b1001100, // ? 0b1010110, // @ 0b110, // A @@ -79,9 +79,9 @@ static const uint8_t MorseTable[] RADIOLIB_NONVOLATILE = { 0b11001, // X 0b11101, // Y 0b10011, // Z - RADIOLIB_MORSE_UNSUPORTED, // [ (unsupported) - RADIOLIB_MORSE_UNSUPORTED, // \ (unsupported) - RADIOLIB_MORSE_UNSUPORTED, // ] (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // [ (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // \ (unsupported) + RADIOLIB_MORSE_UNSUPPORTED, // ] (unsupported) 0b1101000, // ^ (unsupported, used as alias for end of work) 0b110101 // _ (unsupported, used as alias for starting signal) }; @@ -124,7 +124,7 @@ class MorseClient: public RadioLibPrint { /*! \brief Decode Morse symbol to ASCII. - \param symbol Morse code symbol, respresented as outlined in MorseTable. + \param symbol Morse code symbol, represented as outlined in MorseTable. \param len Symbol length (number of dots and dashes). \returns ASCII character matching the symbol, or 0xFF if no match is found. */ diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index ca84f73314..a7ecef46be 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -140,7 +140,7 @@ class PagerClient { /*! \brief Reads data that was received after calling startReceive method. \param str Address of Arduino String to save the received data. - \param len Expected number of characters in the message. When set to 0, the message lengthwill be retreived + \param len Expected number of characters in the message. When set to 0, the message length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \param addr Pointer to variable holding the address of the received pager message. Set to NULL to not retrieve address. @@ -153,7 +153,7 @@ class PagerClient { \brief Reads data that was received after calling startReceive method. \param data Pointer to array to save the received message. \param len Pointer to variable holding the number of bytes that will be read. When set to 0, the packet length - will be retreived automatically. When more bytes than received are requested, only the number of bytes + will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. Upon completion, the number of bytes received will be written to this variable. \param addr Pointer to variable holding the address of the received pager message. Set to NULL to not retrieve address. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 95a7ae6c8e..fa0ec23168 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -172,7 +172,7 @@ class PhysicalLayer { /*! \brief Reads data that was received after calling startReceive method. \param str Address of Arduino String to save the received data. - \param len Expected number of characters in the message. When set to 0, the packet length will be retreived + \param len Expected number of characters in the message. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -182,7 +182,7 @@ class PhysicalLayer { /*! \brief Reads data that was received after calling startReceive method. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. \returns \ref status_codes */ @@ -340,7 +340,7 @@ class PhysicalLayer { int16_t setDirectSyncWord(uint32_t syncWord, uint8_t len); /*! - \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + \brief Set interrupt service routine function to call when data bit is received in direct mode. Must be implemented in module class. \param func Pointer to interrupt service routine. */ diff --git a/src/utils/CRC.h b/src/utils/CRC.h index bc711e8aa1..124fa49d93 100644 --- a/src/utils/CRC.h +++ b/src/utils/CRC.h @@ -54,7 +54,7 @@ class RadioLibCRC { RadioLibCRC(); /*! - \brief Calcualte checksum of a buffer. + \brief Calculate checksum of a buffer. \param buff Buffer to calculate the checksum over. \param len Size of the buffer in bytes. \returns The resulting checksum. diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index 31e56c6868..661996c5fc 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -136,7 +136,7 @@ class RadioLibAES128 { void generateCMAC(uint8_t* in, size_t len, uint8_t* cmac); /*! - \brief Verify the recevied CMAC. This just calculates the CMAC again and compares the results. + \brief Verify the received CMAC. This just calculates the CMAC again and compares the results. \param in Input data (unpadded). \param len Length of the input data. \param cmac CMAC to verify. From 498c5d5e22c885caf6e0385e1b96bc35b45723d1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Jul 2023 19:25:51 +0200 Subject: [PATCH 0681/1848] [Morse] Fix typo --- src/protocols/Morse/Morse.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index e2a80cf612..27cb5eaccd 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -56,7 +56,7 @@ char MorseClient::decode(uint8_t symbol, uint8_t len) { } // nothing found - return(RADIOLIB_MORSE_UNSUPORTED); + return(RADIOLIB_MORSE_UNSUPPORTED); } #if !defined(RADIOLIB_EXCLUDE_AFSK) @@ -132,7 +132,7 @@ size_t MorseClient::write(uint8_t b) { uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]); // check unsupported characters - if(code == RADIOLIB_MORSE_UNSUPORTED) { + if(code == RADIOLIB_MORSE_UNSUPPORTED) { return(0); } From 5f2e5a1997814a93408c539cd5d1680151121a96 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Jul 2023 19:36:23 +0200 Subject: [PATCH 0682/1848] Added getPacketLength to examples (#214) --- .../CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino | 3 ++- .../RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino | 3 ++- .../STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino | 3 ++- .../SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino | 3 ++- examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino | 3 ++- .../SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino | 3 ++- .../SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino | 3 ++- .../Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino | 3 ++- .../nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino | 3 ++- 9 files changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 4dbd17f1d0..4f3e69d8e0 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -100,7 +100,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 0a125883e8..1bc87276ba 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -92,7 +92,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index 2ce572121f..d8b0af7146 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -120,7 +120,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 0786d4b607..11d6ea81e8 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -105,7 +105,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index 87be697a4b..d3423b9e54 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -123,7 +123,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 76c641d32c..0e833e0d99 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -102,7 +102,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 5d0e499280..01ec27f3a9 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -103,7 +103,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index 2ef80c6908..a12d2ee390 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -94,7 +94,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index c41bb2b8d2..1535bc661a 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -112,7 +112,8 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = radio.readData(byteArr, 8); + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); */ if (state == RADIOLIB_ERR_NONE) { From d1e3691c3228cf56f495710fb22dd7894b938e5f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Jul 2023 19:40:07 +0200 Subject: [PATCH 0683/1848] Added notes about getPacketLength (#214) --- src/modules/CC1101/CC1101.h | 3 ++- src/modules/RF69/RF69.h | 3 ++- src/modules/SX126x/SX126x.h | 3 ++- src/modules/SX127x/SX127x.h | 3 ++- src/modules/SX128x/SX128x.h | 3 ++- src/modules/Si443x/Si443x.h | 3 ++- src/modules/nRF24/nRF24.h | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 4ca73c6072..129aebd014 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -714,7 +714,8 @@ class CC1101: public PhysicalLayer { int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! - \brief Reads data received after calling startReceive method. + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be read. When set to 0, the packet length will be retreived automatically. When more bytes than received are requested, only the number of bytes requested will be returned. diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 5facc34816..82426cad3d 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -712,7 +712,8 @@ class RF69: public PhysicalLayer { int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! - \brief Reads data received after calling startReceive method. + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 398a29e450..015215d12a 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -671,7 +671,8 @@ class SX126x: public PhysicalLayer { uint16_t getIrqStatus(); /*! - \brief Reads data received after calling startReceive method. + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 7730b14732..e52df4e24f 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -820,7 +820,8 @@ class SX127x: public PhysicalLayer { int16_t startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! - \brief Reads data that was received after calling startReceive method. This method reads len characters. + \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index cb22ac2f66..1aa69115fa 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -562,7 +562,8 @@ class SX128x: public PhysicalLayer { uint16_t getIrqStatus(); /*! - \brief Reads data received after calling startReceive method. + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index b4c3f7dc42..463b6851da 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -710,7 +710,8 @@ class Si443x: public PhysicalLayer { int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! - \brief Reads data that was received after calling startReceive method. This method reads len characters. + \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. When more bytes than received are requested, only the number of bytes requested will be returned. diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 22a161ef60..5a59877f3f 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -332,7 +332,8 @@ class nRF24: public PhysicalLayer { int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! - \brief Reads data received after calling startReceive method. + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! \param data Pointer to array to save the received binary data. \param len Number of bytes that will be received. Must be known in advance for binary transmissions. \returns \ref status_codes From 65a43dbd134bbee52362094bfd9281abad3c7f50 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 16 Jul 2023 11:49:20 +0200 Subject: [PATCH 0684/1848] Added issue template config --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..8f41cab9f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: RadioLib Discussions + url: https://github.com/jgromes/RadioLib/discussions + about: Please ask generic questions here. From 76ac7d3dad557b1094fe0b82046e90bc914f1376 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 16 Jul 2023 15:50:26 +0200 Subject: [PATCH 0685/1848] [STM32WL] Fixed output power for modules without LP (#798) --- .../STM32WLx_Channel_Activity_Detection.ino | 19 +++++++- ...x_Channel_Activity_Detection_Interrupt.ino | 19 +++++++- .../STM32WLx_Receive_Blocking.ino | 2 + .../STM32WLx_Receive_Interrupt.ino | 2 + .../STM32WLx_Transmit_Blocking.ino | 2 + .../STM32WLx_Transmit_Interrupt.ino | 2 + src/modules/SX126x/STM32WLx.cpp | 45 +++++++++++++++---- src/modules/SX126x/STM32WLx.h | 3 +- 8 files changed, 82 insertions(+), 12 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino index ef511dc825..da07078265 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino @@ -19,11 +19,28 @@ // no need to configure pins, signals are routed to the radio internally STM32WLx radio = new STM32WLx_Module(); +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); - // initialize STM32WLx with default settings + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WLx with default settings, except frequency Serial.print(F("[STM32WLx] Initializing ... ")); int state = radio.begin(868.0); if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino index 374a41f11c..9c14329d24 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -19,11 +19,28 @@ // no need to configure pins, signals are routed to the radio internally STM32WLx radio = new STM32WLx_Module(); +// set RF switch configuration for Nucleo WL55JC1 +// NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. +static const uint32_t rfswitch_pins[] = + {PC3, PC4, PC5}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}}, + {STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}}, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); - // initialize STM32WLx with default settings + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + // initialize STM32WLx with default settings, except frequency Serial.print(F("[STM32WLx] Initializing ... ")); int state = radio.begin(868.0); if (state == RADIOLIB_ERR_NONE) { diff --git a/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino index ae2cbdb192..e2e90d62ba 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino @@ -37,6 +37,8 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index d8b0af7146..6d91cea4b6 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -31,6 +31,8 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { diff --git a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino index 3d2e354085..d35680a3a4 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -32,6 +32,8 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index 527c897cee..60777c0284 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -23,6 +23,8 @@ STM32WLx radio = new STM32WLx_Module(); // set RF switch configuration for Nucleo WL55JC1 // NOTE: other boards may be different! +// Some boards may not have either LP or HP. +// For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = {PC3, PC4, PC5}; static const Module::RfSwitchMode_t rfswitch_table[] = { diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index dcc8c82283..095e13ecb1 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -44,21 +44,48 @@ int16_t STM32WLx::setOutputPower(int8_t power) { int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); - // Use HP only if available and needed for the requested power + // check the user did not request power output that is not possible bool hp_supported = this->mod->findRfSwitchMode(MODE_TX_HP); - bool use_hp = power > 14 && hp_supported; + bool lp_supported = this->mod->findRfSwitchMode(MODE_TX_LP); + if((!lp_supported && (power < -9)) || (!hp_supported && (power > 14))) { + // LP not supported but requested power is below HP low bound or + // HP not supported but requested power is above LP high bound + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } - // set PA config. - if(use_hp) { + // set PA config based on which PAs are supported + bool use_hp = false; + if(hp_supported && lp_supported) { + // both PAs supported, use HP when above 14 dBm + if(power > 14) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x00, 0x07); // HP output up to 22dBm + this->txMode = MODE_TX_HP; + use_hp = true; + } else { + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x01, 0x00); // LP output up to 14dBm + this->txMode = MODE_TX_LP; + } + + } else if(!hp_supported && lp_supported) { + // only LP supported + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + state = SX126x::setPaConfig(0x04, 0x01, 0x00); + this->txMode = MODE_TX_LP; + + } else if(hp_supported && !lp_supported) { + // only HP supported RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - state = SX126x::setPaConfig(0x04, 0x00, 0x07); // HP output up to 22dBm + state = SX126x::setPaConfig(0x04, 0x00, 0x07); this->txMode = MODE_TX_HP; + use_hp = true; + } else { - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - state = SX126x::setPaConfig(0x04, 0x01, 0x00); // LP output up to 14dBm - this->txMode = MODE_TX_LP; + // neither PA is supported + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } - RADIOLIB_ASSERT(state); // Apply workaround for HP only state = SX126x::fixPaClamping(use_hp); diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index 42e073a4bf..aa96491727 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -82,7 +82,8 @@ class STM32WLx : public SX1262 { LP is preferred and supports -17 to +14dBm. When a higher power is requested (or the LP amplifier is marked as unavailable using - setRfSwitchTable()), HP is used, which supports -9 to +22dBm. + setRfSwitchTable()), HP is used, which supports -9 to +22dBm. If the LP is marked as unavailable, + HP output will be used instead. \param power Output power to be set in dBm. From d52c9e3183a82fe4311e6cc36f19f90fb1a99a16 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 16 Jul 2023 16:33:47 +0200 Subject: [PATCH 0686/1848] [LoRaWAN] Added preliminary FSK support --- src/protocols/LoRaWAN/LoRaWAN.cpp | 97 +++++++++++++++++++------- src/protocols/LoRaWAN/LoRaWANBands.cpp | 9 +++ 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ecaf44654a..e5636067be 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -18,6 +18,7 @@ static void LoRaWANNodeOnDownlink(void) { LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->phyLayer = phy; this->band = band; + this->FSK = false; } void LoRaWANNode::wipe() { @@ -83,10 +84,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // set the function that will be called when the reply is received this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); - // downlink messages are sent with interted IQ - state = this->phyLayer->invertIQ(true); - RADIOLIB_ASSERT(state); - + // downlink messages are sent with inverted IQ + if(!this->FSK) { + state = this->phyLayer->invertIQ(true); + RADIOLIB_ASSERT(state); + } + // start receiving uint32_t start = mod->hal->millis(); downlinkReceived = false; @@ -97,7 +100,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey while(!downlinkReceived) { if(mod->hal->millis() - start >= RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS + 2000) { downlinkReceived = false; - this->phyLayer->invertIQ(false); + if(!this->FSK) { + this->phyLayer->invertIQ(false); + } return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -105,9 +110,11 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // we have a message, reset the IQ inversion downlinkReceived = false; this->phyLayer->clearPacketReceivedAction(); - state = this->phyLayer->invertIQ(false); - RADIOLIB_ASSERT(state); - + if(!this->FSK) { + state = this->phyLayer->invertIQ(false); + RADIOLIB_ASSERT(state); + } + // build the buffer for the reply data uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; @@ -410,22 +417,30 @@ int16_t LoRaWANNode::configureChannel(uint8_t chan, uint8_t dr) { RADIOLIB_DEBUG_PRINTLN("Data rate %02x", dataRateBand); DataRate_t datr; - uint8_t bw = dataRateBand & 0x03; - switch(bw) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - datr.lora.bandwidth = 125.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - datr.lora.bandwidth = 250.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - datr.lora.bandwidth = 500.0; - break; - default: - return(RADIOLIB_ERR_INVALID_BANDWIDTH); + if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + datr.fsk.bitRate = 50; + datr.fsk.freqDev = 25; + + } else { + uint8_t bw = dataRateBand & 0x03; + switch(bw) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + datr.lora.bandwidth = 125.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + datr.lora.bandwidth = 250.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + datr.lora.bandwidth = 500.0; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + datr.lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; + } - datr.lora.spreadingFactor = ((dataRateBand & 0xF0) >> 4) + 6; state = this->phyLayer->setDataRate(datr); return(state); @@ -465,17 +480,47 @@ int16_t LoRaWANNode::setPhyProperties() { // TODO select channel span based on channel ID // TODO select channel randomly uint8_t channelId = 0; - int16_t state = this->configureChannel(channelId, this->band->defaultChannels[0].joinRequestDataRate); + int16_t state = RADIOLIB_ERR_NONE; + if(this->FSK) { + state = this->phyLayer->setFrequency(this->band->fskFreq); + RADIOLIB_ASSERT(state); + DataRate_t dr; + dr.fsk.bitRate = 50; + dr.fsk.freqDev = 25; + state = this->phyLayer->setDataRate(dr); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); + } else { + state = this->configureChannel(channelId, this->band->defaultChannels[0].joinRequestDataRate); + } RADIOLIB_ASSERT(state); state = this->phyLayer->setOutputPower(this->band->powerMax); RADIOLIB_ASSERT(state); - uint8_t syncWord = RADIOLIB_LORAWAN_LORA_SYNC_WORD; - state = this->phyLayer->setSyncWord(&syncWord, 1); + uint8_t syncWord[3] = { 0 }; + uint8_t syncWordLen = 0; + size_t preLen = 0; + if(this->FSK) { + preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); + syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; + syncWordLen = 3; + + } else { + preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; + syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; + syncWordLen = 1; + + } + + state = this->phyLayer->setSyncWord(syncWord, syncWordLen); RADIOLIB_ASSERT(state); - state = this->phyLayer->setPreambleLength(RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN); + state = this->phyLayer->setPreambleLength(preLen); return(state); } diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index c04269dc6c..d51a508ce5 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -19,6 +19,7 @@ const LoRaWANBand_t EU868 = { .powerMax = 16, .powerNumSteps = 7, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .fskFreq = 868.8, .numChannelSpans = 1, .defaultChannels = { { @@ -85,6 +86,7 @@ const LoRaWANBand_t US915 = { .powerMax = 30, .powerNumSteps = 10, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, + .fskFreq = 0, .numChannelSpans = 3, .defaultChannels = { { @@ -197,6 +199,7 @@ const LoRaWANBand_t CN780 = { .powerMax = 12, .powerNumSteps = 5, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .fskFreq = 0, .numChannelSpans = 1, .defaultChannels = { { @@ -263,6 +266,7 @@ const LoRaWANBand_t EU433 = { .powerMax = 12, .powerNumSteps = 5, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .fskFreq = 0, .numChannelSpans = 1, .defaultChannels = { { @@ -329,6 +333,7 @@ const LoRaWANBand_t AU915 = { .powerMax = 30, .powerNumSteps = 10, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, + .fskFreq = 0, .numChannelSpans = 3, .defaultChannels = { { @@ -441,6 +446,7 @@ const LoRaWANBand_t CN500 = { .powerMax = 19, .powerNumSteps = 7, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, + .fskFreq = 0, .numChannelSpans = 2, .defaultChannels = { { @@ -530,6 +536,7 @@ const LoRaWANBand_t AS923 = { .powerMax = 16, .powerNumSteps = 7, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .fskFreq = 921.8, .numChannelSpans = 1, .defaultChannels = { { @@ -596,6 +603,7 @@ const LoRaWANBand_t KR920 = { .powerMax = 14, .powerNumSteps = 7, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .fskFreq = 0, .numChannelSpans = 1, .defaultChannels = { { @@ -662,6 +670,7 @@ const LoRaWANBand_t IN865 = { .powerMax = 30, .powerNumSteps = 10, .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, + .fskFreq = 0, .numChannelSpans = 1, .defaultChannels = { { From 6a7773e00511e5124d9e7c3bdd4b289c98f82426 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 16 Jul 2023 16:34:32 +0200 Subject: [PATCH 0687/1848] [LoRaWAN] Fixed APB begin --- src/protocols/LoRaWAN/LoRaWAN.cpp | 18 +++++++++++++++--- src/protocols/LoRaWAN/LoRaWAN.h | 28 ++++++++++++++++++---------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e5636067be..1cacfda523 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -231,11 +231,23 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t net, uint8_t* nwkSKey, uint8_t* appSKey) { - this->devAddr = (((uint32_t)net << 25) & 0xFE000000) | (addr & 0x01FFFFFF); +int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntkey) { + this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); - return(RADIOLIB_ERR_NONE); + if(fNwkSIntKey) { + this->rev = 1; + memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + } else { + memcpy(this->fNwkSIntKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); + } + if(sNwkSIntKey) { + memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + } + + // set the physical layer configuration + int16_t state = this->setPhyProperties(); + return(state); } #if defined(RADIOLIB_BUILD_ARDUINO) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 4b33f93249..36550e9a7e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -45,13 +45,13 @@ #define RADIOLIB_LORAWAN_NOPTS_LEN (8) // data rat encoding -#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 7 4 LoRaWAN spreading factor: SF12 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 7 4 SF11 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 7 4 SF10 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 7 4 SF9 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 7 4 SF8 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 7 4 SF7 -#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x00 << 4) // 7 4 FSK @ 50 kbps +#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps +#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRaWAN spreading factor: SF12 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 #define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 0) // 3 0 LoRaWAN bandwidth: 500 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 0) // 3 0 250 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 0) // 3 0 125 kHz @@ -130,6 +130,7 @@ #define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) #define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) +// magic word saved in persistent memory upon activation #define RADIOLIB_LORAWAN_MAGIC (0x12AD101B) /*! @@ -182,6 +183,9 @@ struct LoRaWANBand_t { /*! \brief Whether the optional channels are defined as list of frequencies or bit mask */ uint8_t cfListType; + + /*! \brief FSK channel frequency */ + float fskFreq; /*! \brief Number of channel spans in the band */ uint8_t numChannelSpans; @@ -210,6 +214,9 @@ extern const LoRaWANBand_t IN865; */ class LoRaWANNode { public: + /*! \brief Set to true to force the node to only use FSK channels. Set to false by default. */ + bool FSK; + /*! \brief Default constructor. \param phy Pointer to the PhysicalLayer radio module. @@ -245,12 +252,13 @@ class LoRaWANNode { \brief Join network by performing activation by personalization. In this procedure, all necessary configuration must be provided by the user. \param addr Device address. - \param net Network ID. - \param nwkSKey Pointer to the network session AES-128 key. + \param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1). \param appSKey Pointer to the application session AES-128 key. + \param fNwkSIntKey Pointer to the network session F key (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param sNwkSIntkey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0. \returns \ref status_codes */ - int16_t beginAPB(uint32_t addr, uint8_t net, uint8_t* nwkSKey, uint8_t* appSKey); + int16_t beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntkey = NULL); #if defined(RADIOLIB_BUILD_ARDUINO) /*! From 5e9b60a4b42c9bdde4b56e63f2b92ceef1e03c20 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 16 Jul 2023 16:54:13 +0200 Subject: [PATCH 0688/1848] [LoRaWAN] Added APB example --- .../LoRaWAN_End_Device_APB.ino | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino new file mode 100644 index 0000000000..8f3a4a0e06 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino @@ -0,0 +1,119 @@ +/* + RadioLib LoRaWAN End Device APB Example + + This example sets up a LoRaWAN node using APB (activation + by personalization). Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will start uploading data directly, + without having to join the network. + + NOTE: LoRaWAN requires storing some parameters persistently! + RadioLib does this by using EEPROM, by default + starting at address 0 and using 32 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // first we need to initialize the device storage + // this will reset all persistently stored parameters + // NOTE: This should only be done once prior to first joining a network! + // After wiping persistent storage, you will also have to reset + // the end device in TTN! + //node.wipe(); + + // device address - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is unique + uint32_t devAddr = 0x12345678; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + const char nwkSKey[] = "topSecretKey1234"; + const char appSKey[] = "aDifferentKeyABC"; + + // start the device by directly providing the encryption keys and device address + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginAPB(devAddr, (uint8_t*)nwkSKey, (uint8_t*)appSKey); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after the device has been activated, + // network can be rejoined after device power cycle + // by calling "begin" + /* + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String str = "Hello World! #" + String(count++); + int state = node.uplink(str, 10); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait before sending another one + delay(10000); +} From 2edbe9cd577c7d267c9ce5fd7ccd9534818b976c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 20 Jul 2023 21:40:50 +1000 Subject: [PATCH 0689/1848] Tock: Fixup time calculation Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/libtockHal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/NonArduino/Tock/libtockHal.h b/examples/NonArduino/Tock/libtockHal.h index d9acf717f3..f75d6e69c0 100644 --- a/examples/NonArduino/Tock/libtockHal.h +++ b/examples/NonArduino/Tock/libtockHal.h @@ -154,7 +154,7 @@ class TockHal : public RadioLibHal { } void delayMicroseconds(unsigned long us) override { - delay_ms( us * 1000 ); + delay_ms( us / 1000 ); } unsigned long millis() override { @@ -163,7 +163,7 @@ class TockHal : public RadioLibHal { alarm_internal_frequency(&frequency); alarm_internal_read(&now); - return (now / frequency) * 1000; + return (now / frequency) / 1000; } unsigned long micros() override { From 377385fb13abcd0705214b7e54e6905a99b1edaa Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 20 Jul 2023 21:41:43 +1000 Subject: [PATCH 0690/1848] Tock: Don't call blocking yield Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/libtockHal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/NonArduino/Tock/libtockHal.h b/examples/NonArduino/Tock/libtockHal.h index f75d6e69c0..76ed42df14 100644 --- a/examples/NonArduino/Tock/libtockHal.h +++ b/examples/NonArduino/Tock/libtockHal.h @@ -191,7 +191,7 @@ class TockHal : public RadioLibHal { } void yield() { - ::yield(); + ::yield_no_wait(); } private: From 0a6026e69e69840051d26b03601168a55850252b Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 20 Jul 2023 18:43:49 +0200 Subject: [PATCH 0691/1848] [LoRaWAN] Fixed typo in variable name --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- src/protocols/LoRaWAN/LoRaWAN.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 1cacfda523..a5bb9465d3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -231,7 +231,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntkey) { +int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey) { this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 36550e9a7e..d0262df129 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -255,10 +255,10 @@ class LoRaWANNode { \param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1). \param appSKey Pointer to the application session AES-128 key. \param fNwkSIntKey Pointer to the network session F key (LoRaWAN 1.1), unused for LoRaWAN 1.0. - \param sNwkSIntkey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param sNwkSIntKey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0. \returns \ref status_codes */ - int16_t beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntkey = NULL); + int16_t beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL); #if defined(RADIOLIB_BUILD_ARDUINO) /*! From 6234a84ac9f41d877ca9e1eae4783809a7c2f690 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 21 Jul 2023 22:01:56 +1000 Subject: [PATCH 0692/1848] Tock: Build libtock-c lib with the build script Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/build.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/NonArduino/Tock/build.sh b/examples/NonArduino/Tock/build.sh index b7b21caa1b..a527bc9df6 100755 --- a/examples/NonArduino/Tock/build.sh +++ b/examples/NonArduino/Tock/build.sh @@ -3,6 +3,10 @@ set -e rm -rf ./build +cd libtock-c/libtock +make -j4 +cd ../../ + mkdir -p build cd build From fe892ecd3183981586d34d5f415f5cea80c2ebe6 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 21 Jul 2023 22:03:45 +1000 Subject: [PATCH 0693/1848] Tock: Fixup the radio setup Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index a5cab8b60d..6a57dc25e1 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -48,7 +48,7 @@ int main(void) { // Setup the radio // The settings here work for the SparkFun LoRa Thing Plus - expLoRaBLE - int state = radio->begin(915.0, 125.0, 9, 7, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 10, 8, 0, false); + int state = radio->begin(915.0, 125.0, 7, 5, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 0, 8, 0, false); if (state != RADIOLIB_ERR_NONE) { printf("failed, code %d\r\n", state); From 1bc7c5771cf8b11d6b24b681a9bfac25de6f4cdc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jul 2023 18:08:40 +0200 Subject: [PATCH 0694/1848] [AX25] Added check for Bell modem --- src/protocols/AX25/AX25.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index e7470b5f33..fc3e24e021 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -194,7 +194,12 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preL preambleLen = preLen; // configure for direct mode - return(phyLayer->startDirect()); + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(bellModem != nullptr) { + return(phyLayer->startDirect()); + } + #endif + return(RADIOLIB_ERR_NONE); } #if defined(RADIOLIB_BUILD_ARDUINO) From 247ca753f1bf90f7f6de283e3fc457a611143f9f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jul 2023 18:18:05 +0200 Subject: [PATCH 0695/1848] [APRS] Added support for APRS over LoRa --- src/protocols/APRS/APRS.cpp | 58 ++++++++++++++++++++++++++++++------- src/protocols/APRS/APRS.h | 21 ++++++++++++-- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 8ae93e8c0b..a7300bc9d6 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -6,9 +6,15 @@ APRSClient::APRSClient(AX25Client* ax) { axClient = ax; + phyLayer = nullptr; } -int16_t APRSClient::begin(char sym, bool alt) { +APRSClient::APRSClient(PhysicalLayer* phy) { + axClient = nullptr; + phyLayer = phy; +} + +int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL); symbol = sym; @@ -18,6 +24,16 @@ int16_t APRSClient::begin(char sym, bool alt) { table = '/'; } + if((!src) && (this->phyLayer != nullptr)) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); + } + + if(strlen(callsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { + return(RADIOLIB_ERR_INVALID_CALLSIGN); + } + memcpy(this->src, callsign, strlen(callsign)); + this->id = ssid; + return(RADIOLIB_ERR_NONE); } @@ -30,7 +46,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat if(time != NULL) { len += strlen(time); } - char* info = new char[len]; + char* info = new char[len + 1]; #else char info[RADIOLIB_STATIC_ARRAY_SIZE]; #endif @@ -49,6 +65,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat // timestamp and message sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg); } + info[len] = '\0'; // send the frame int16_t state = sendFrame(destCallsign, destSSID, info); @@ -211,7 +228,12 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp info[infoPos++] = '\0'; // send the frame - int16_t state = sendFrame(destCallsign, 0, info); + uint8_t destSSID = 0; + if(this->phyLayer != nullptr) { + // TODO make SSID configurable? + destSSID = 1; + } + int16_t state = sendFrame(destCallsign, destSSID, info); #if !defined(RADIOLIB_STATIC_ONLY) delete[] info; #endif @@ -219,15 +241,31 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp } int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) { - // get AX.25 callsign - char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; - axClient->getCallsign(srcCallsign); + // encoding depends on whether AX.25 should be used or not + if(this->axClient != nullptr) { + // AX.25/classical mode, get AX.25 callsign + char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; + axClient->getCallsign(srcCallsign); + + AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | + RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, + RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); - AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | - RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, - RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); + return(axClient->sendFrame(&frameUI)); + + } else if(this->phyLayer != nullptr) { + // non-AX.25/LoRa mode + size_t len = RADIOLIB_APRS_LORA_HEADER_LEN + strlen(this->src) + 4 + strlen(destCallsign) + 11 + strlen(info); + Serial.println(len); + uint8_t* buff = new uint8_t[len]; + snprintf(buff, len, RADIOLIB_APRS_LORA_HEADER "%s-%d>%s,WIDE%d-%d:%s", this->src, this->id, destCallsign, destSSID, destSSID, info); - return(axClient->sendFrame(&frameUI)); + int16_t res = this->phyLayer->transmit(buff, strlen(buff)); + delete[] buff; + return(res); + } + + return(RADIOLIB_ERR_WRONG_MODEM); } #endif diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index cf1abbded6..ee74cfa059 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -58,6 +58,10 @@ // alias for unused altitude in Mic-E #define RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED -1000000 +// special header applied for APRS over LoRa +#define RADIOLIB_APRS_LORA_HEADER "<\xff\x01" +#define RADIOLIB_APRS_LORA_HEADER_LEN (3) + /*! \class APRSClient \brief Client for APRS communication. @@ -65,20 +69,28 @@ class APRSClient { public: /*! - \brief Default constructor. + \brief Constructor for "classic" mode using AX.25/AFSK. \param ax Pointer to the instance of AX25Client to be used for APRS. */ explicit APRSClient(AX25Client* ax); + /*! + \brief Constructor for LoRa mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit APRSClient(PhysicalLayer* phy); + // basic methods /*! \brief Initialization method. \param sym APRS symbol to be displayed. + \param callsign Source callsign. Required and only used for APRS over LoRa, ignored in classic mode. + \param ssid Source SSID. Only used for APRS over LoRa, ignored in classic mode, defaults to 0. \param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table. \returns \ref status_codes */ - int16_t begin(char sym, bool alt = false); + int16_t begin(char sym, char* callsign = NULL, uint8_t ssid = 0, bool alt = false); /*! \brief Transmit position. @@ -120,10 +132,15 @@ class APRSClient { private: #endif AX25Client* axClient; + PhysicalLayer* phyLayer; // default APRS symbol (car) char symbol = '>'; char table = '/'; + + // source callsign when using APRS over LoRa + char src[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 }; + uint8_t id = 0; }; #endif From 26222cc97fd2d4dbd38c120c203ad4ae4c7df434 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jul 2023 18:26:15 +0200 Subject: [PATCH 0696/1848] [APRS] Fixed buffer type --- src/protocols/APRS/APRS.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index a7300bc9d6..0c86de42c5 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -256,11 +256,10 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) } else if(this->phyLayer != nullptr) { // non-AX.25/LoRa mode size_t len = RADIOLIB_APRS_LORA_HEADER_LEN + strlen(this->src) + 4 + strlen(destCallsign) + 11 + strlen(info); - Serial.println(len); - uint8_t* buff = new uint8_t[len]; + char* buff = new char[len]; snprintf(buff, len, RADIOLIB_APRS_LORA_HEADER "%s-%d>%s,WIDE%d-%d:%s", this->src, this->id, destCallsign, destSSID, destSSID, info); - int16_t res = this->phyLayer->transmit(buff, strlen(buff)); + int16_t res = this->phyLayer->transmit((uint8_t*)buff, strlen(buff)); delete[] buff; return(res); } From 7de29965059bc77b3617a1f1a0e256d81886216b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jul 2023 18:35:48 +0200 Subject: [PATCH 0697/1848] [APRS] Added APRS over LoRa example --- .../APRS_Position_LoRa/APRS_Position_LoRa.ino | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino diff --git a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino new file mode 100644 index 0000000000..6b3053a1d1 --- /dev/null +++ b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino @@ -0,0 +1,95 @@ +/* + RadioLib APRS Position over LoRa Example + + This example sends APRS position reports + using SX1278's LoRa modem. + + Other modules that can be used for APRS: + - SX127x/RFM9x + - SX126x/LLCC68 + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create APRS client instance using the LoRa radio +APRSClient aprs(&radio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with the settings necessary for LoRa iGates + Serial.print(F("[SX1278] Initializing ... ")); + // frequency: 433.775 MHz + // bandwidth: 125 kHz + // spreading factor: 12 + // coding rate: 4/5 + int state = radio.begin(433.775, 125, 12, 5); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize APRS client + Serial.print(F("[APRS] Initializing ... ")); + // symbol: '>' (car) + // callsign "N7LEM" + // SSID 1 + state = aprs.begin('>', "N7LEM", 1); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[APRS] Sending position ... ")); + + // send a location with message and timestamp + // SSID is set to 1, as APRS over LoRa uses WIDE1-1 path by default + int state = aprs.sendPosition("GPS", 1, "4911.67N", "01635.96E", "I'm here!", "093045z"); + delay(500); + + // you can also send Mic-E encoded messages + state |= state = aprs.sendMicE(49.1945, 16.6000, 120, 10, RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE); + delay(500); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait one minute before transmitting again + delay(60000); +} From 87200bd312fe87ac71af846a855ed9e5440cf1fe Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 24 Jul 2023 19:21:11 +1000 Subject: [PATCH 0698/1848] Tock: Use the default radio begin() Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index 6a57dc25e1..d8bf33d729 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -48,7 +48,8 @@ int main(void) { // Setup the radio // The settings here work for the SparkFun LoRa Thing Plus - expLoRaBLE - int state = radio->begin(915.0, 125.0, 7, 5, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 0, 8, 0, false); + radio->XTAL = true; + int state = radio->begin(915.0); if (state != RADIOLIB_ERR_NONE) { printf("failed, code %d\r\n", state); From 72b95e5c820051fa805ee5dcbddc965d92d7f20b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 2 Aug 2023 22:04:20 +0200 Subject: [PATCH 0699/1848] [CC1101] Decreased default Rx bandwidth --- src/modules/CC1101/CC1101.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 129aebd014..012b7bda7d 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -518,7 +518,7 @@ #define RADIOLIB_CC1101_DEFAULT_FREQ 434.0 #define RADIOLIB_CC1101_DEFAULT_BR 4.8 #define RADIOLIB_CC1101_DEFAULT_FREQDEV 5.0 -#define RADIOLIB_CC1101_DEFAULT_RXBW 135.0 +#define RADIOLIB_CC1101_DEFAULT_RXBW 58.0 #define RADIOLIB_CC1101_DEFAULT_POWER 10 #define RADIOLIB_CC1101_DEFAULT_PREAMBLELEN 16 #define RADIOLIB_CC1101_DEFAULT_SW {0x12, 0xAD} From 6247cb7e85f0ba8ea3733b53e5663859dd8e0497 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 2 Aug 2023 22:08:52 +0200 Subject: [PATCH 0700/1848] [CC1101] Fixed garbage data (#733) --- src/modules/CC1101/CC1101.cpp | 155 ++++++++-------------------------- src/modules/CC1101/CC1101.h | 7 +- 2 files changed, 37 insertions(+), 125 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 235ef13df2..5e2fc776ed 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -85,7 +85,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pw RADIOLIB_ASSERT(state); // flush FIFOs - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); return(state); @@ -163,6 +163,16 @@ int16_t CC1101::standby() { // set idle mode SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); + // wait until idle is reached + uint32_t start = this->mod->hal->millis(); + while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != RADIOLIB_CC1101_MARC_STATE_IDLE) { + mod->hal->yield(); + if(this->mod->hal->millis() - start > 100) { + // timeout, this should really not happen + return(RADIOLIB_ERR_UNKNOWN); + } + }; + // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); return(RADIOLIB_ERR_NONE); @@ -272,9 +282,9 @@ void CC1101::clearGdo2Action() { int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length - /*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { + if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); - }*/ + } // set mode to standby standby(); @@ -285,46 +295,20 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set GDO0 mapping int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); RADIOLIB_ASSERT(state); - /*int16_t state = RADIOLIB_ERR_NONE; - if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { - state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR); - } else { - state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED); - }*/ - - // data put on FIFO - uint8_t dataSent = 0; // optionally write packet length - if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { - - // enforce variable len limit - if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { - return (RADIOLIB_ERR_PACKET_TOO_LONG); - } - + if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len); - dataSent += 1; } // check address filtering uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr); - dataSent += 1; } // fill the FIFO - /*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, RADIOLIB_CC1101_FIFO_THRESH_TX); - } else { - uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); - dataSent += initialWrite; - }*/ - uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite); - dataSent += initialWrite; + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, len); // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_TX); @@ -332,33 +316,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to transmit SPIsendCommand(RADIOLIB_CC1101_CMD_TX); - if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { - return(state); - } - - // keep feeding the FIFO until the packet is over - while (dataSent < len) { - // get number of bytes in FIFO - uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); - - // if there's room then put other data - if (bytesInFIFO < RADIOLIB_CC1101_FIFO_SIZE) { - uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent)); - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, &data[dataSent], bytesToWrite); - dataSent += bytesToWrite; - } else { - // wait for radio to send some data - /* - * Does this work for all rates? If 1 ms is longer than the 1ms delay - * then the entire FIFO will be transmitted during that delay. - * - * TODO: test this on real hardware - */ - this->mod->hal->delayMicroseconds(250); - } - } - - return (state); + return(state); } int16_t CC1101::finishTransmit() { @@ -378,12 +336,11 @@ int16_t CC1101::startReceive() { RADIOLIB_ASSERT(state); // flush Rx FIFO - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); - // set GDO0 mapping: Asserted when RX FIFO > 4 bytes. - state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END); - //state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED); - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4, 3, 0); + // set GDO0 mapping + // GDO0 is de-asserted at packet end, hence it is inverted here + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDO0_INV | RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 6, 0); RADIOLIB_ASSERT(state); // set RF switch (if present) @@ -406,19 +363,10 @@ int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMa int16_t CC1101::readData(uint8_t* data, size_t len) { // get packet length size_t length = getPacketLength(); - /*RADIOLIB_DEBUG_PRINTLN("length = %d", length); - if(length == 0) { - this->packetLengthQueried = false; - standby(); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); - return(RADIOLIB_ERR_RX_TIMEOUT); - }*/ if((len != 0) && (len < length)) { // user requested less data than we got, only return what was requested length = len; } - //SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE | RADIOLIB_CC1101_CMD_READ); - SPIreadRegister(RADIOLIB_CC1101_REG_RXBYTES); // check address filtering uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); @@ -426,41 +374,14 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); } - uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); - size_t readBytes = 0; - uint32_t lastPop = this->mod->hal->millis(); - - // keep reading from FIFO until we get all the packet. - while (readBytes < length) { - if (bytesInFIFO == 0) { - if (this->mod->hal->millis() - lastPop > 5) { - // readData was required to read a packet longer than the one received. - RADIOLIB_DEBUG_PRINTLN("No data for more than 5mS. Stop here."); - break; - } else { - this->mod->hal->delay(1); - bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); - continue; - } - } - - // read the minimum between "remaining length" and bytesInFifo - uint8_t bytesToRead = RADIOLIB_MIN((uint8_t)(length - readBytes), bytesInFIFO); - SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, bytesToRead, &(data[readBytes])); - readBytes += bytesToRead; - lastPop = this->mod->hal->millis(); - - // Get how many bytes are left in FIFO. - bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0); - } + // read packet data + SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, length, data); // check if status bytes are enabled (default: RADIOLIB_CC1101_APPEND_STATUS_ON) bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; - // for some reason, we need this delay here to get the correct status bytes - this->mod->hal->delay(3); - // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. + int16_t state = RADIOLIB_ERR_NONE; if (isAppendStatus) { // read RSSI byte this->rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO); @@ -470,9 +391,9 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { this->rawLQI = val & 0x7F; // check CRC - if (this->crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { + if(this->crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) { this->packetLengthQueried = false; - return (RADIOLIB_ERR_CRC_MISMATCH); + state = RADIOLIB_ERR_CRC_MISMATCH; } } @@ -480,16 +401,16 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { this->packetLengthQueried = false; // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) - if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { + if(SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { // set mode to standby standby(); // flush Rx FIFO - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); } - return(RADIOLIB_ERR_NONE); + return(state); } int16_t CC1101::setFrequency(float freq) { @@ -835,23 +756,15 @@ uint8_t CC1101::getLQI() const { } size_t CC1101::getPacketLength(bool update) { - RADIOLIB_DEBUG_PRINTLN("this->packetLengthQueried=%d", this->packetLengthQueried); - RADIOLIB_DEBUG_PRINTLN("update=%d", update); - RADIOLIB_DEBUG_PRINTLN("this->packetLengthConfig=%d", this->packetLengthConfig); if(!this->packetLengthQueried && update) { - if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { - this->packetLength = 0; - while(this->packetLength == 0) { - this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); - } - + if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO); } else { this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN); } this->packetLengthQueried = true; } - RADIOLIB_DEBUG_PRINTLN("this->packetLength=%d", this->packetLength); return(this->packetLength); } @@ -1131,7 +1044,7 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { // status registers require special command - if(reg > RADIOLIB_CC1101_REG_TEST0) { + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } @@ -1140,7 +1053,7 @@ int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval) { // status registers require special command - if(reg > RADIOLIB_CC1101_REG_TEST0) { + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } @@ -1153,7 +1066,7 @@ void CC1101::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inByte uint8_t CC1101::SPIreadRegister(uint8_t reg) { // status registers require special command - if(reg > RADIOLIB_CC1101_REG_TEST0) { + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } @@ -1162,7 +1075,7 @@ uint8_t CC1101::SPIreadRegister(uint8_t reg) { void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) { // status registers require special command - if(reg > RADIOLIB_CC1101_REG_TEST0) { + if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG; } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 012b7bda7d..a13327e919 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -8,10 +8,9 @@ // CC1101 physical layer properties #define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 -#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 255 +#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 63 #define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 #define RADIOLIB_CC1101_DIV_EXPONENT 16 -#define RADIOLIB_CC1101_FIFO_SIZE 64 // CC1101 SPI commands #define RADIOLIB_CC1101_CMD_READ 0b10000000 @@ -116,8 +115,8 @@ #define RADIOLIB_CC1101_GDO2_INV 0b01000000 // 6 6 active low // RADIOLIB_CC1101_REG_IOCFG1 -#define RADIOLIB_CC1101_GDO1_DS_LOW 0b00000000 // 7 7 GDO1 output drive strength: low (default) -#define RADIOLIB_CC1101_GDO1_DS_HIGH 0b10000000 // 7 7 high +#define RADIOLIB_CC1101_GDO_DS_LOW 0b00000000 // 7 7 GDOx output drive strength: low (default) +#define RADIOLIB_CC1101_GDO_DS_HIGH 0b10000000 // 7 7 high #define RADIOLIB_CC1101_GDO1_NORM 0b00000000 // 6 6 GDO1 output: active high (default) #define RADIOLIB_CC1101_GDO1_INV 0b01000000 // 6 6 active low From f81f37cf431d5e589c59a99feb5d9c0a9749e584 Mon Sep 17 00:00:00 2001 From: fraboe Date: Sat, 5 Aug 2023 08:55:50 +0200 Subject: [PATCH 0701/1848] Fixed wrong register definition for RADIOLIB_RF69_SEQUENCER_OFF and RADIOLIB_RF69_SEQUENCER_ON --- src/modules/RF69/RF69.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 82426cad3d..8ecb2a85ae 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -98,8 +98,8 @@ // RF69 modem settings // RADIOLIB_RF69_REG_OP_MODE MSB LSB DESCRIPTION -#define RADIOLIB_RF69_SEQUENCER_OFF 0b00000000 // 7 7 disable automatic sequencer -#define RADIOLIB_RF69_SEQUENCER_ON 0b10000000 // 7 7 enable automatic sequencer +#define RADIOLIB_RF69_SEQUENCER_OFF 0b10000000 // 7 7 disable automatic sequencer +#define RADIOLIB_RF69_SEQUENCER_ON 0b00000000 // 7 7 enable automatic sequencer #define RADIOLIB_RF69_LISTEN_OFF 0b00000000 // 6 6 disable Listen mode #define RADIOLIB_RF69_LISTEN_ON 0b01000000 // 6 6 enable Listen mode #define RADIOLIB_RF69_LISTEN_ABORT 0b00100000 // 5 5 abort Listen mode (has to be set together with RF69_LISTEN_OFF) From 68c5edd7c2693911604806369e0022657a06d59c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Aug 2023 09:31:39 +0200 Subject: [PATCH 0702/1848] [SX127x] Add delay before IRQ clearing (#808) --- src/modules/SX127x/SX127x.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 027d512ea4..ca6633bb2a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -609,6 +609,11 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } int16_t SX127x::finishTransmit() { + // wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags + // not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO, + // which can lead to mangling of the last bit (#808) + mod->hal->delayMicroseconds(1000000/1200); + // clear interrupt flags clearIRQFlags(); From 532caaa0891322566642e8723597f8e2f6c0b870 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Aug 2023 16:02:24 +0200 Subject: [PATCH 0703/1848] [PHY] Added virtual channel scan method --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 84d8283200..5c9b697ca2 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -289,6 +289,10 @@ float PhysicalLayer::getSNR() { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::scanChannel() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + int32_t PhysicalLayer::random(int32_t max) { if(max == 0) { return(0); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index fa0ec23168..ef5dd93e42 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -302,6 +302,14 @@ class PhysicalLayer { */ virtual float getSNR(); + /*! + \brief Check whether the current communication channel is free or occupied. Performs CAD for LoRa modules, + or RSSI measurement for FSK modules. + \returns RADIOLIB_CHANNEL_FREE when channel is free, + RADIOLIB_PREAMBLE_DETECTEDwhen occupied or other \ref status_codes. + */ + virtual int16_t scanChannel(); + /*! \brief Get truly random number in range 0 - max. \param max The maximum value of the random number (non-inclusive). From f589d77e09d271895924fc0b79f1db54182992e3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Aug 2023 16:06:15 +0200 Subject: [PATCH 0704/1848] [SX127x] Override default channel scan method --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e52df4e24f..b18f679167 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -647,7 +647,7 @@ class SX127x: public PhysicalLayer { \brief Performs scan for valid %LoRa preamble in the current channel. \returns \ref status_codes */ - int16_t scanChannel(); + int16_t scanChannel() override; /*! \brief Sets the %LoRa module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. From 86724197ec6b200c6cdc1166de9e6092cbf6b455 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Aug 2023 16:07:28 +0200 Subject: [PATCH 0705/1848] [SX126x] Added default channel scan override --- src/modules/SX126x/SX126x.cpp | 4 ++++ src/modules/SX126x/SX126x.h | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6ec42bbdd1..94195b4f8e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -429,6 +429,10 @@ int16_t SX126x::packetMode() { return(state); } +int16_t SX126x::scanChannel() { + return(this->scanChannel(RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT)); +} + int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { // set mode to CAD int state = startChannelScan(symbolNum, detPeak, detMin); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 015215d12a..9b691b9c9c 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -528,6 +528,12 @@ class SX126x: public PhysicalLayer { */ int16_t receiveDirect() override; + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \returns \ref status_codes + */ + int16_t scanChannel() override; + /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. @@ -535,7 +541,7 @@ class SX126x: public PhysicalLayer { \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. \returns \ref status_codes */ - int16_t scanChannel(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); + int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). From ebfe7972fc8eea90d4c4d20a0de3e05b07244898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicklas=20B=C3=B6rjesson?= Date: Wed, 9 Aug 2023 23:38:39 +0200 Subject: [PATCH 0706/1848] Remove unnecessary condition This will never be NULL and thus causes an error in ESP-IDF --- src/protocols/APRS/APRS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 0c86de42c5..33559e7919 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -24,7 +24,7 @@ int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { table = '/'; } - if((!src) && (this->phyLayer != nullptr)) { + if(this->phyLayer != nullptr) { return(RADIOLIB_ERR_INVALID_CALLSIGN); } From 3e5c0d59c77f2c0ae35368a4050b418a676fc3d7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:35:08 +0200 Subject: [PATCH 0707/1848] [MOD] Moved CS pin toggling inside SPI transaction block --- src/Module.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 2e7340347b..68fbcf0cfa 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -166,11 +166,11 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d } // do the transfer - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); this->hal->spiBeginTransaction(); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); this->hal->spiTransfer(buffOut, buffLen, buffIn); - this->hal->spiEndTransaction(); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + this->hal->spiEndTransaction(); // copy the data if(cmd == SPIreadCommand) { @@ -298,11 +298,11 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } // do the transfer - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); this->hal->spiBeginTransaction(); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); this->hal->spiTransfer(buffOut, buffLen, buffIn); - this->hal->spiEndTransaction(); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + this->hal->spiEndTransaction(); // wait for GPIO to go high and then low if(waitForGpio) { From bfe2c0829a21fa1c46cbcffc74b7ed5d531d9bc3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:35:48 +0200 Subject: [PATCH 0708/1848] [MOD] Moved debug info to runtime --- src/Module.cpp | 4 ++++ src/RadioLib.h | 12 ------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 68fbcf0cfa..399dec466f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -44,6 +44,10 @@ void Module::init() { this->hal->init(); this->hal->pinMode(csPin, this->hal->GpioModeOutput); this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh); + RADIOLIB_DEBUG_PRINTLN("\nRadioLib Debug Info"); + RADIOLIB_DEBUG_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); + RADIOLIB_DEBUG_PRINTLN("Platform: " RADIOLIB_PLATFORM); + RADIOLIB_DEBUG_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); } void Module::term() { diff --git a/src/RadioLib.h b/src/RadioLib.h index e4ea62ad70..e3b9db4f3f 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -51,18 +51,6 @@ #warning "God mode active, I hope it was intentional. Buckle up, lads." #endif -// print debug info -#if defined(RADIOLIB_DEBUG) - #define RADIOLIB_VALUE_TO_STRING(x) #x - #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) - #define RADIOLIB_VAR_NAME_VALUE(var) #var "=" RADIOLIB_VALUE(var) - #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_PLATFORM)) - #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_MAJOR)) - #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_MINOR)) - #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_PATCH)) - #pragma message(RADIOLIB_VAR_NAME_VALUE(RADIOLIB_VERSION_EXTRA)) -#endif - // check unknown/unsupported platform #if defined(RADIOLIB_UNKNOWN_PLATFORM) #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" From 8c63f93820c23c44b362ebb30f972e9df8e721c7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:36:12 +0200 Subject: [PATCH 0709/1848] [MOD] Skip SPI status parsing for single-byte commands --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 399dec466f..80c430375e 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -331,7 +331,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // parse status int16_t state = RADIOLIB_ERR_NONE; - if(this->SPIparseStatusCb != nullptr) { + if((this->SPIparseStatusCb != nullptr) && (numBytes > 0)) { state = this->SPIparseStatusCb(buffIn[cmdLen]); } From 2f36d5901e71201196218b40becb2c9e3ddc6736 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:37:46 +0200 Subject: [PATCH 0710/1848] [LoRaWAN] Added LoRaWAN-specific status codes --- keywords.txt | 8 ++++++++ src/TypeDef.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/keywords.txt b/keywords.txt index 70935d1077..1595839565 100644 --- a/keywords.txt +++ b/keywords.txt @@ -390,3 +390,11 @@ RADIOLIB_ERR_RANGING_TIMEOUT LITERAL1 RADIOLIB_ERR_INVALID_PAYLOAD LITERAL1 RADIOLIB_ERR_ADDRESS_NOT_FOUND LITERAL1 RADIOLIB_ERR_INVALID_FUNCTION LITERAL1 + +RADIOLIB_ERR_NETWORK_NOT_JOINED LITERAL1 +RADIOLIB_ERR_DOWNLINK_MALFORMED LITERAL1 +RADIOLIB_ERR_INVALID_REVISION LITERAL1 +RADIOLIB_ERR_INVALID_PORT LITERAL1 +RADIOLIB_ERR_NO_RX_WINDOW LITERAL1 +RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 +RADIOLIB_ERR_INVALID_CID LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index a363f3abab..e24675b2de 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -481,6 +481,43 @@ */ #define RADIOLIB_ERR_INVALID_FUNCTION (-1003) +// LoRaWAN-specific status codes + +/*! + \brief Unable to restore existing LoRaWAN session because this node did not join any network yet. +*/ +#define RADIOLIB_ERR_NETWORK_NOT_JOINED (-1101) + +/*! + \brief Malformed downlink packet received from network server. +*/ +#define RADIOLIB_ERR_DOWNLINK_MALFORMED (-1102) + +/*! + \brief Network server requested switch to unsupported LoRaWAN revision. +*/ +#define RADIOLIB_ERR_INVALID_REVISION (-1103) + +/*! + \brief Invalid LoRaWAN uplink port requested by user. +*/ +#define RADIOLIB_ERR_INVALID_PORT (-1104) + +/*! + \brief User did not enable downlink in time. +*/ +#define RADIOLIB_ERR_NO_RX_WINDOW (-1105) + +/*! + \brief No valid channel for the currently active LoRaWAN band was found. +*/ +#define RADIOLIB_ERR_INVALID_CHANNEL (-1106) + +/*! + \brief Invalid LoRaWAN MAC command ID. +*/ +#define RADIOLIB_ERR_INVALID_CID (-1107) + /*! \} */ From 5d80dd46ae746e9f04af84f5c144c03def2741e2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:38:15 +0200 Subject: [PATCH 0711/1848] [SX126x] Explicitly set non-inverted IQ on startup --- src/modules/SX126x/SX126x.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 94195b4f8e..358cfe7946 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -91,6 +91,9 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo state = setCRC(2); RADIOLIB_ASSERT(state); + state = invertIQ(false); + RADIOLIB_ASSERT(state); + return(state); } From bb468ad59f37100c083ebc92478519c5bfd1ec09 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:38:46 +0200 Subject: [PATCH 0712/1848] [SX127x] Explicitly set non-inverted IQ on startup --- src/modules/SX127x/SX127x.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index ca6633bb2a..3e5cccb497 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -51,6 +51,10 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe state = SX127x::setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); + // disable IQ inversion + state = SX127x::invertIQ(false); + RADIOLIB_ASSERT(state); + // initialize internal variables this->dataRate = 0.0; From b48567722bd61a3c5bb0f0fccca84fdd4be45e84 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:40:38 +0200 Subject: [PATCH 0713/1848] [SX127x] Added method to get CAD result --- src/modules/SX127x/SX127x.cpp | 7 +++++++ src/modules/SX127x/SX127x.h | 12 +++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 3e5cccb497..6009b177f5 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -701,6 +701,13 @@ int16_t SX127x::startChannelScan() { return(state); } +int16_t SX127x::getChannelScanResult() { + if(this->getIRQFlags() & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) { + return(RADIOLIB_PREAMBLE_DETECTED); + } + return(RADIOLIB_CHANNEL_FREE); +} + int16_t SX127x::setSyncWord(uint8_t syncWord) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index b18f679167..6544016d30 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -834,7 +834,13 @@ class SX127x: public PhysicalLayer { DIO1 will be activated if there's no preamble detected before timeout. \returns \ref status_codes */ - int16_t startChannelScan(); + int16_t startChannelScan() override; + + /*! + \brief Read the channel scan result. + \returns \ref status_codes + */ + int16_t getChannelScanResult() override; // configuration methods @@ -1016,11 +1022,11 @@ class SX127x: public PhysicalLayer { int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); /*! - \brief Get expected time-on-air for a given size of payload + \brief Get expected time-on-air for a given size of payload. \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - uint32_t getTimeOnAir(size_t len); + uint32_t getTimeOnAir(size_t len) override; /*! \brief Enable CRC filtering and generation. From 58da2a28ac5cde63cf1da68d774e793672878176 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:42:37 +0200 Subject: [PATCH 0714/1848] [PHY] Added channel scan methods to common interface --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 21 +++++++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 31 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 5c9b697ca2..b244b8565c 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -289,6 +289,19 @@ float PhysicalLayer::getSNR() { return(RADIOLIB_ERR_UNSUPPORTED); } +uint32_t PhysicalLayer::getTimeOnAir(size_t len) { + (void)len; + return(0); +} + +int16_t PhysicalLayer::startChannelScan() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::getChannelScanResult() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + int16_t PhysicalLayer::scanChannel() { return(RADIOLIB_ERR_UNSUPPORTED); } @@ -441,6 +454,14 @@ void PhysicalLayer::clearPacketSentAction() { } +void PhysicalLayer::setChannelScanAction(void (*func)(void)) { + (void)func; +} + +void PhysicalLayer::clearChannelScanAction() { + +} + #if defined(RADIOLIB_INTERRUPT_TIMING) void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { Module* mod = getMod(); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index ef5dd93e42..ba7df2128f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -302,6 +302,26 @@ class PhysicalLayer { */ virtual float getSNR(); + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + virtual uint32_t getTimeOnAir(size_t len); + + /*! + \brief Interrupt-driven channel activity detection method. interrupt will be activated + when packet is detected. Must be implemented in module class. + \returns \ref status_codes + */ + virtual int16_t startChannelScan(); + + /*! + \brief Read the channel scan result + \returns \ref status_codes + */ + virtual int16_t getChannelScanResult(); + /*! \brief Check whether the current communication channel is free or occupied. Performs CAD for LoRa modules, or RSSI measurement for FSK modules. @@ -409,6 +429,17 @@ class PhysicalLayer { \brief Clears interrupt service routine to call when a packet is sent. */ virtual void clearPacketSentAction(); + + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + virtual void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + virtual void clearChannelScanAction(); #if defined(RADIOLIB_INTERRUPT_TIMING) From ea4018d3102db7ed994ce0aa0abd76d284bf45d9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:43:26 +0200 Subject: [PATCH 0715/1848] [SX127x] Added common CAD methods --- src/modules/SX127x/SX127x.cpp | 8 ++++++++ src/modules/SX127x/SX127x.h | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6009b177f5..bd0b0d46df 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -472,6 +472,14 @@ void SX127x::clearPacketSentAction() { this->clearDio0Action(); } +void SX127x::setChannelScanAction(void (*func)(void)) { + this->setDio0Action(func, this->mod->hal->GpioInterruptRising); +} + +void SX127x::clearChannelScanAction() { + this->clearDio0Action(); +} + void SX127x::setFifoEmptyAction(void (*func)(void)) { // set DIO1 to the FIFO empty event (the register setting is done in startTransmit) setDio1Action(func, this->mod->hal->GpioInterruptRising); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 6544016d30..9ef2890fba 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -738,6 +738,17 @@ class SX127x: public PhysicalLayer { */ void clearPacketSentAction(); + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + void clearChannelScanAction(); + /*! \brief Set interrupt service routine function to call when FIFO is empty. \param func Pointer to interrupt service routine. From db3ac8bf1974dba764f53b4d755c768fc38b6a83 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:45:42 +0200 Subject: [PATCH 0716/1848] [SX126x] Implemented common CAD methods --- src/modules/SX126x/SX126x.cpp | 15 ++++++++++++++- src/modules/SX126x/SX126x.h | 32 +++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 358cfe7946..ce34e2f4cc 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -507,6 +507,15 @@ void SX126x::clearPacketSentAction() { this->clearDio1Action(); } +void SX126x::setChannelScanAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearChannelScanAction() { + this->clearDio1Action(); +} + + int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; @@ -729,6 +738,10 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { return(state); } +int16_t SX126x::startChannelScan() { + return(this->startChannelScan(RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT)); +} + int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { @@ -1721,7 +1734,7 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { data[2] = detMin; } - // configure paramaters + // configure parameters int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 9b691b9c9c..5b18b969e7 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -601,6 +601,17 @@ class SX126x: public PhysicalLayer { */ void clearPacketSentAction(); + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + void clearChannelScanAction(); + /*! \brief Interrupt-driven binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. @@ -685,22 +696,29 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. + \returns \ref status_codes + */ + int16_t startChannelScan() override; /*! - \brief Interrupt-driven channel activity detection method. DIO0 will be activated + \brief Interrupt-driven channel activity detection method. DIO1 will be activated when LoRa preamble is detected, or upon timeout. - \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. - \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. - \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. + \param symbolNum Number of symbols for CAD detection. + \param detPeak Peak value for CAD detection. + \param detMin Minimum value for CAD detection. \returns \ref status_codes */ - int16_t startChannelScan(uint8_t symbolNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, uint8_t detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT); + int16_t startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); /*! \brief Read the channel scan result \returns \ref status_codes */ - int16_t getChannelScanResult(); + int16_t getChannelScanResult() override; // configuration methods @@ -929,7 +947,7 @@ class SX126x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - uint32_t getTimeOnAir(size_t len); + uint32_t getTimeOnAir(size_t len) override; /*! \brief Set implicit header mode for future reception/transmission. From ca95135d8a8e035b4f557550a212a9603d9ce5cf Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:49:05 +0200 Subject: [PATCH 0717/1848] [SX126x] Skip wiping IRQ flags on CAD done --- src/modules/SX126x/SX126x.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ce34e2f4cc..69abb1734c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -778,11 +778,9 @@ int16_t SX126x::getChannelScanResult() { uint16_t cadResult = getIrqStatus(); if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DETECTED) { // detected some LoRa activity - clearIrqStatus(); return(RADIOLIB_LORA_DETECTED); } else if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DONE) { // channel is free - clearIrqStatus(); return(RADIOLIB_CHANNEL_FREE); } From 23fbd87d14a2e90d7aaf9c5d36162d0eac526349 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 18:58:11 +0200 Subject: [PATCH 0718/1848] [SX126x] Added Rx after CAD example --- ...nel_Activity_Detection_Interrupt_Lolin.ino | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino new file mode 100644 index 0000000000..20b0ae92d5 --- /dev/null +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino @@ -0,0 +1,185 @@ +/* + RadioLib SX126x Receive after Channel Activity Detection Example + + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. + If a packet is detected, the module will switch + to receive mode and receive the packet. + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +bool receiving = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + int state = RADIOLIB_ERR_NONE; + + // reset flag + scanFlag = false; + + // check ongoing reception + if(receiving) { + // DIO triggered while reception is ongoing + // that means we got a packet + + // you can read received data as an Arduino String + String str; + state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1262] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1262] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1262] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1262] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[SX1262] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else { + // some other error occurred + Serial.print(F("[SX1262] Failed, code ")); + Serial.println(state); + + } + + // reception is done now + receiving = false; + + } else { + // check CAD result + state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.print(F("[SX1262] Packet detected, starting reception ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // set the flag for ongoing reception + receiving = true; + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[SX1262] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[SX1262] Failed, code ")); + Serial.println(state); + + } + + } + + // if we're not receiving, start scanning again + if(!receiving) { + Serial.print(F("[SX1262] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + } + + } + +} From d34902ee46afab71b6ba2c2c64ad103222289d14 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 19:44:13 +0200 Subject: [PATCH 0719/1848] [SX127x] Added missing parentheses --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index bd0b0d46df..1a8f2eaff9 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -710,7 +710,7 @@ int16_t SX127x::startChannelScan() { } int16_t SX127x::getChannelScanResult() { - if(this->getIRQFlags() & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) { + if((this->getIRQFlags() & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) { return(RADIOLIB_PREAMBLE_DETECTED); } return(RADIOLIB_CHANNEL_FREE); From cd9ac9916cd95c887967bd3a17cd8ed6626dac14 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 19:49:37 +0200 Subject: [PATCH 0720/1848] [LoRaWAN] Added support for 1.1 and downlink (#58) --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 53 +- .../LoRaWAN_End_Device_APB.ino | 47 +- keywords.txt | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 631 ++++++++++++++---- src/protocols/LoRaWAN/LoRaWAN.h | 128 +++- 5 files changed, 705 insertions(+), 155 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index c1553c7a37..a239ee08f7 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -60,10 +60,10 @@ void setup() { // the end device in TTN and perform the join procedure again! //node.wipe(); - // application identifier - in LoRaWAN 1.1, it is also called joinEUI + // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI // when adding new end device in TTN, you will have to enter this number // you can pick any number you want, but it has to be unique - uint64_t appEUI = 0x12AD1011B0C0FFEE; + uint64_t joinEUI = 0x12AD1011B0C0FFEE; // device identifier - this number can be anything // when adding new end device in TTN, you can generate this number, @@ -76,10 +76,14 @@ void setup() { const char nwkKey[] = "topSecretKey1234"; const char appKey[] = "aDifferentKeyABC"; + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + // now we can start the activation // this can take up to 20 seconds, and requires a LoRaWAN gateway in range Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginOTAA(appEUI, devEUI, (uint8_t*)nwkKey, (uint8_t*)appKey); + state = node.beginOTAA(joinEUI, devEUI, (uint8_t*)nwkKey, (uint8_t*)appKey); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -110,8 +114,8 @@ int count = 0; void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String str = "Hello World! #" + String(count++); - int state = node.uplink(str, 10); + String strUp = "Hello World! #" + String(count++); + int state = node.uplink(strUp, 10); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -119,6 +123,43 @@ void loop() { Serial.println(state); } - // wait before sending another one + // after uplink, you can call downlink(), + // to receive any possible reply from the server + // this function must be called within a few seconds + // after uplink to receive the downlink! + Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + String strDown; + state = node.downlink(strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print data of the packet + Serial.print(F("[LoRaWAN] Data:\t\t")); + Serial.println(strDown); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait before sending another packet delay(10000); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino index 8f3a4a0e06..a19effdc1d 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino @@ -72,6 +72,10 @@ void setup() { const char nwkSKey[] = "topSecretKey1234"; const char appSKey[] = "aDifferentKeyABC"; + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + // start the device by directly providing the encryption keys and device address Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginAPB(devAddr, (uint8_t*)nwkSKey, (uint8_t*)appSKey); @@ -105,8 +109,8 @@ int count = 0; void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String str = "Hello World! #" + String(count++); - int state = node.uplink(str, 10); + String strUp = "Hello World! #" + String(count++); + int state = node.uplink(strUp, 10); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -114,6 +118,43 @@ void loop() { Serial.println(state); } - // wait before sending another one + // after uplink, you can call downlink(), + // to receive any possible reply from the server + // this function must be called within a few seconds + // after uplink to receive the downlink! + Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + String strDown; + state = node.downlink(strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print data of the packet + Serial.print(F("[LoRaWAN] Data:\t\t")); + Serial.println(strDown); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // wait before sending another packet delay(10000); } diff --git a/keywords.txt b/keywords.txt index 1595839565..617a3983a8 100644 --- a/keywords.txt +++ b/keywords.txt @@ -292,6 +292,7 @@ wipe KEYWORD2 beginOTAA KEYWORD2 beginAPB KEYWORD2 uplink KEYWORD2 +downlink KEYWORD2 configureChannel KEYWORD2 ####################################### diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a5bb9465d3..83fb49e39e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -15,6 +15,17 @@ static void LoRaWANNodeOnDownlink(void) { downlinkReceived = true; } +// flag to indicate whether channel scan operation is complete +static volatile bool scanFlag = false; + +// interrupt service routine to handle downlinks automatically +#if defined(ESP8266) || defined(ESP32) + IRAM_ATTR +#endif +static void LoRaWANNodeOnChannelScan(void) { + scanFlag = true; +} + LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->phyLayer = phy; this->band = band; @@ -34,12 +45,11 @@ int16_t LoRaWANNode::begin() { Module* mod = this->phyLayer->getMod(); if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) != RADIOLIB_LORAWAN_MAGIC) { // the magic value is not set, user will have to do perform the join procedure - return(RADIOLIB_ERR_CHIP_NOT_FOUND); + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } // pull all needed information from persistent storage this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID); - RADIOLIB_DEBUG_PRINTLN("devAddr = 0x%08x", this->devAddr); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); @@ -47,7 +57,7 @@ int16_t LoRaWANNode::begin() { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force) { +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force) { // check if we actually need to send the join request Module* mod = this->phyLayer->getMod(); if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { @@ -62,14 +72,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // get dev nonce from persistent storage and increment it uint16_t devNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID); mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID, devNonce + 1); - RADIOLIB_DEBUG_PRINTLN("devNonce = %d", devNonce); // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; // set the packet fields joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], appEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonce); @@ -85,6 +94,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); // downlink messages are sent with inverted IQ + // TODO use downlink() for this if(!this->FSK) { state = this->phyLayer->invertIQ(true); RADIOLIB_ASSERT(state); @@ -122,7 +132,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey size_t lenRx = this->phyLayer->getPacketLength(true); if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { RADIOLIB_DEBUG_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); - return(RADIOLIB_ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } // read the packet @@ -136,30 +146,59 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey // check reply message type if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { RADIOLIB_DEBUG_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); - return(RADIOLIB_ERR_RX_TIMEOUT); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } // decrypt the join accept message // this is done by encrypting again in ECB mode - // the first byte is the MAC header which is not encrpyted + // the first byte is the MAC header which is not encrypted uint8_t joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; joinAcceptMsg[0] = joinAcceptMsgEnc[0]; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); - //Module::hexdump(joinAcceptMsg, RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN); + //Module::hexdump(joinAcceptMsg, lenRx); + + // check LoRaWAN revision (the MIC verification depends on this) + uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; + if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { + // 1.1 version, first we need to derive the join accept integrity key + uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY; + LoRaWANNode::hton(&keyDerivationBuff[1], devEUI); + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey); + + // prepare the buffer for MIC calculation + uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; + LoRaWANNode::hton(&micBuff[1], joinEUI); + LoRaWANNode::hton(&micBuff[9], devNonce); + memcpy(&micBuff[11], joinAcceptMsg, lenRx); + + //Module::hexdump(micBuff, lenRx + 11); + + if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + } else { + // 1.0 version + if(!verifyMIC(joinAcceptMsg, lenRx, nwkKey)) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } - // verify MIC - if(!verifyMIC(joinAcceptMsg, lenRx, nwkKey)) { - return(RADIOLIB_ERR_CRC_MISMATCH); } // parse the contents uint32_t joinNonce = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); uint32_t homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); - uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; - this->rxDelay = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + this->rxDelays[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]*1000; + if(this->rxDelays[0] == 0) { + this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; + } + this->rxDelays[1] = this->rxDelays[0] + 1000; // process CFlist if present if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { @@ -174,35 +213,59 @@ int16_t LoRaWANNode::beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey } else { // TODO list of masks RADIOLIB_DEBUG_PRINTLN("CFlist masks not supported (yet)"); - return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); + return(RADIOLIB_ERR_UNSUPPORTED); } } - RADIOLIB_DEBUG_PRINTLN("joinNonce = %lu", joinNonce); - RADIOLIB_DEBUG_PRINTLN("homeNetId = %lu", homeNetId); - RADIOLIB_DEBUG_PRINTLN("devAddr = 0x%08x", devAddr); - RADIOLIB_DEBUG_PRINTLN("dlSettings = 0x%02x", dlSettings); - RADIOLIB_DEBUG_PRINTLN("rxDelay = %d", this->rxDelay); - // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce); // check protocol version (1.0 vs 1.1) if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { - // TODO implement 1.1 + // 1.1 version, derive the keys + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonce); + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; + //Module::hexdump(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE); + + RadioLibAES128Instance.init(appKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); + //Module::hexdump(this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); + //Module::hexdump(this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey); + //Module::hexdump(this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY; + RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); + //Module::hexdump(this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + // send the RekeyInd MAC command this->rev = 1; - RADIOLIB_DEBUG_PRINTLN("LoRaWAN 1.1 not supported (yet)"); - (void)appKey; - return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); + uint8_t serverRev = 0xFF; + state = sendMacCommand(RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND, &this->rev, sizeof(uint8_t), &serverRev, sizeof(uint8_t)); + RADIOLIB_ASSERT(state); + + // check the supported server version + if(serverRev != this->rev) { + return(RADIOLIB_ERR_INVALID_REVISION); + } } else { // 1.0 version, just derive the keys this->rev = 0; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -262,18 +325,28 @@ int16_t LoRaWANNode::uplink(const char* str, uint8_t port) { int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { // check destination port - RADIOLIB_CHECK_RANGE(port, 0x01, 0xDF, RADIOLIB_ERR_INVALID_PAYLOAD); + RADIOLIB_CHECK_RANGE(port, 0x00, 0xDF, RADIOLIB_ERR_INVALID_PORT); - // check maximum payload len as defiend in phy - // TODO implement Fopts + // check if there is a MAC command to piggyback uint8_t foptsLen = 0; + if(this->command) { + foptsLen = 1 + this->command->len; + } + + // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRate]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } + // check if sufficient time has elapsed since the last uplink + Module* mod = this->phyLayer->getMod(); + /*if(mod->hal->millis() - this->rxDelayStart < ) { + + }*/ + // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LORAWAN_UPLINK_LEN(len, foptsLen); + size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); #if defined(RADIOLIB_STATIC_ONLY) uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -281,62 +354,41 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { #endif // set the packet fields - uplinkMsg[RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_UPLINK_DEV_ADDR_POS], this->devAddr); + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); // TODO implement adaptive data rate - uplinkMsg[RADIOLIB_LORAWAN_UPLINK_FCTRL_POS] = 0x00; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00 | foptsLen; // get frame counter from persistent storage - Module* mod = this->phyLayer->getMod(); - uint32_t fcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, fcnt + 1); - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_UPLINK_FCNT_POS], (uint16_t)fcnt); + uint32_t fcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID) + 1; + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, fcnt); + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)fcnt); + + // check if there is something in FOpts + if(this->command) { + // append MAC command + uint8_t foptsBuff[RADIOLIB_AES128_BLOCK_SIZE]; + foptsBuff[0] = this->command->cid; + for(size_t i = 1; i < this->command->len; i++) { + foptsBuff[i] = this->command->payload[i]; + } + + // encrypt it + processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, false); + } - // TODO implement FOpts - uplinkMsg[RADIOLIB_LORAWAN_UPLINK_FPORT_POS(foptsLen)] = port; + // set the port + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] = port; // select encryption key based on the target port uint8_t* encKey = this->appSKey; - if(port == 0) { + if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { encKey = this->nwkSEncKey; } - // figure out how many encryption blocks are there - size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; - if(len % RADIOLIB_AES128_BLOCK_SIZE) { - numBlocks++; - } - - // generate the encryption blocks - uint8_t encBuffer[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - uint8_t encBlock[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; - encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; - LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); - - //Module::hexdump(uplinkMsg, uplinkMsgLen); - - // now encrypt the payload - size_t remLen = len; - for(size_t i = 0; i < numBlocks; i++) { - encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; - - // encrypt the buffer - RadioLibAES128Instance.init(encKey); - RadioLibAES128Instance.encryptECB(encBlock, RADIOLIB_AES128_BLOCK_SIZE, encBuffer); - - // now xor the buffer with the payload - size_t xorLen = remLen; - if(xorLen > RADIOLIB_AES128_BLOCK_SIZE) { - xorLen = RADIOLIB_AES128_BLOCK_SIZE; - } - for(uint8_t j = 0; j < xorLen; j++) { - uplinkMsg[RADIOLIB_LORAWAN_UPLINK_PAYLOAD_POS(foptsLen) + i*RADIOLIB_AES128_BLOCK_SIZE + j] = data[i*RADIOLIB_AES128_BLOCK_SIZE + j] ^ encBuffer[j]; - } - remLen -= xorLen; - } + // encrypt the frame payload + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; @@ -362,7 +414,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { // check LoRaWAN revision if(this->rev == 1) { - uint32_t mic = ((uint32_t)(micS & 0x00FF) << 24) | ((uint32_t)(micS & 0xFF00) << 8) | ((uint32_t)(micF & 0xFF00) >> 8) | ((uint32_t)(micF & 0x00FF) << 8); + uint32_t mic = ((uint32_t)(micF & 0x0000FF00) << 16) | ((uint32_t)(micF & 0x0000000FF) << 16) | ((uint32_t)(micS & 0x0000FF00) >> 0) | ((uint32_t)(micS & 0x0000000FF) >> 0); LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], mic); } else { LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); @@ -371,88 +423,329 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { //Module::hexdump(uplinkMsg, uplinkMsgLen); // send it (without the MIC calculation blocks) - int16_t state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS); + uint32_t txStart = mod->hal->millis(); + uint32_t timeOnAir = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; + int16_t state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); #if !defined(RADIOLIB_STATIC_ONLY) delete[] uplinkMsg; #endif RADIOLIB_ASSERT(state); - // TODO implement listening for downlinks in RX1/RX2 slots - + // set the timestamp so that we can measure when to start receiving + this->command = NULL; + this->rxDelayStart = txStart + timeOnAir; return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::configureChannel(uint8_t chan, uint8_t dr) { - // find the span based on the channel ID - uint8_t span = 0; - uint8_t spanChannelId = 0; - bool found = false; - for(uint8_t chanCtr = 0; span < this->band->numChannelSpans; span++) { - for(; spanChannelId < this->band->defaultChannels[span].numChannels; spanChannelId++) { - if(chanCtr >= chan) { - found = true; +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::downlink(String& str) { + int16_t state = RADIOLIB_ERR_NONE; + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t length = 0; + uint8_t data[251]; + + // wait for downlink + state = this->downlink(data, &length); + if(state == RADIOLIB_ERR_NONE) { + // add null terminator + data[length] = '\0'; + + // initialize Arduino String class + str = String((char*)data); + } + + return(state); +} +#endif + +int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { + // check if there are any upcoming Rx windows + Module* mod = this->phyLayer->getMod(); + const uint32_t scanGuard = 500; + if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[1] + scanGuard)) { + // time since last Tx is greater than RX2 delay + some guard period + // we have nothing to downlink + return(RADIOLIB_ERR_NO_RX_WINDOW); + } + + // downlink messages are sent with inverted IQ + int16_t state = RADIOLIB_ERR_UNKNOWN; + if(!this->FSK) { + state = this->phyLayer->invertIQ(true); + RADIOLIB_ASSERT(state); + } + + // calculate the channel scanning timeout + // according to the spec, this must be at least enough time to effectively detect a preamble + uint32_t scanTimeout = this->phyLayer->getTimeOnAir(0)/1000; + + // set up everything for channel scan + downlinkReceived = false; + scanFlag = false; + bool packetDetected = false; + this->phyLayer->setChannelScanAction(LoRaWANNodeOnChannelScan); + + // perform listening in the two Rx windows + for(uint8_t i = 0; i < 2; i++) { + // wait for the start of the Rx window + // the waiting duration is shortened a bit to cover any possible timing errors + uint32_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart); + if(waitLen > scanGuard) { + waitLen -= scanGuard; + } + mod->hal->delay(waitLen); + + // wait until we get a preamble + uint32_t scanStart = mod->hal->millis(); + while((mod->hal->millis() - scanStart) < (scanTimeout + scanGuard)) { + // check channel detection timeout + state = this->phyLayer->startChannelScan(); + RADIOLIB_ASSERT(state); + + // wait with some timeout, though it should not be hit + uint32_t cadStart = mod->hal->millis(); + while(!scanFlag) { + mod->hal->yield(); + if(mod->hal->millis() - cadStart >= 3000) { + // timed out, stop waiting + break; + } + } + + // check the scan result + scanFlag = false; + state = this->phyLayer->getChannelScanResult(); + if((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { + packetDetected = true; break; } - chanCtr++; + } - if(found) { + + // check if we have a packet + if(packetDetected) { break; + + } else if(i == 0) { + // nothing in the first window, configure for the second + state = this->phyLayer->setFrequency(this->band->backupChannel.freqStart); + RADIOLIB_ASSERT(state); + + DataRate_t datr; + findDataRate(RADIOLIB_LORAWAN_DATA_RATE_UNUSED, &datr, &this->band->backupChannel); + state = this->phyLayer->setDataRate(datr); + RADIOLIB_ASSERT(state); + } + } - if(!found) { - return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); + // check if we received a packet at all + if(!packetDetected) { + this->phyLayer->standby(); + if(!this->FSK) { + this->phyLayer->invertIQ(false); + } + + // restore the original uplink channel + this->configureChannel(0, this->dataRate); + + return(RADIOLIB_ERR_RX_TIMEOUT); } - this->chIndex = chan; - RADIOLIB_DEBUG_PRINTLN("Channel span %d, channel %d", span, spanChannelId); + // channel scan is finished, swap the actions + this->phyLayer->clearChannelScanAction(); + downlinkReceived = false; + this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); - // set the frequency - float freq = this->band->defaultChannels[span].freqStart + this->band->defaultChannels[span].freqStep * (float)spanChannelId; - RADIOLIB_DEBUG_PRINTLN("Frequency %f MHz", freq); - int state = this->phyLayer->setFrequency(freq); + // start receiving + state = this->phyLayer->startReceive(); RADIOLIB_ASSERT(state); - // set the data rate - uint8_t dataRateBand = this->band->defaultChannels[span].dataRates[dr]; + // wait for reception with some timeout + uint32_t rxStart = mod->hal->millis(); + while(!downlinkReceived) { + mod->hal->yield(); + // let's hope 30 seconds is long enough timeout + if(mod->hal->millis() - rxStart >= 30000) { + // timed out + this->phyLayer->standby(); + if(!this->FSK) { + this->phyLayer->invertIQ(false); + } + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + // we have a message, clear actions, go to standby and reset the IQ inversion + downlinkReceived = false; + this->phyLayer->standby(); + this->phyLayer->clearPacketReceivedAction(); + if(!this->FSK) { + state = this->phyLayer->invertIQ(false); + RADIOLIB_ASSERT(state); + } + + // get the packet length + size_t downlinkMsgLen = this->phyLayer->getPacketLength(); + + // check the minimum required frame length + // an extra byte is subtracted because downlink frames may not have a port + if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { + RADIOLIB_DEBUG_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // build the buffer for the downlink message + // the first 16 bytes are reserved for MIC calculation block + #if !defined(RADIOLIB_STATIC_ONLY) + uint8_t* downlinkMsg = new uint8_t[RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen]; + #else + uint8_t downlinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // set the MIC calculation block + // TODO implement confirmed frames + memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); + + // read the data + state = this->phyLayer->readData(&downlinkMsg[RADIOLIB_AES128_BLOCK_SIZE], downlinkMsgLen); + // downlink frames are sent without CRC, which will raise error on SX127x + // we can ignore that error + if(state == RADIOLIB_ERR_LORA_HEADER_DAMAGED) { + state = RADIOLIB_ERR_NONE; + } + + //Module::hexdump(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + + if(state != RADIOLIB_ERR_NONE) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif + return(state); + } + + // check the MIC + if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + // check the address + uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); + if(addr != this->devAddr) { + RADIOLIB_DEBUG_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // TODO cache the ADR bit? + // TODO cache and check fcnt? + uint16_t fcnt = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); + + // check fopts len + uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + if(foptsLen > 0) { + // there are some Fopts, decrypt them + *len = foptsLen; + + // according to the specification, the last two arguments should be 0x00 and false, + // but that will fail even for LoRaWAN 1.1.0 server + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], foptsLen, this->nwkSEncKey, data, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x01, true); + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_NONE); + } + + // no fopts, just payload + // TODO implement decoding piggybacked Fopts? + *len = downlinkMsgLen; + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], downlinkMsgLen, this->appSKey, data, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif + + return(state); +} + +void LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span) { + uint8_t dataRateBand = span->dataRates[dr]; this->dataRate = dr; if(dr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - // find the first usable data rate for(uint8_t i = 0; i < RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; i++) { - if(this->band->defaultChannels[span].dataRates[i] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - dataRateBand = this->band->defaultChannels[span].dataRates[i]; + if(span->dataRates[i] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + dataRateBand = span->dataRates[i]; this->dataRate = i; break; } } } - - RADIOLIB_DEBUG_PRINTLN("Data rate %02x", dataRateBand); - DataRate_t datr; + if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - datr.fsk.bitRate = 50; - datr.fsk.freqDev = 25; + datr->fsk.bitRate = 50; + datr->fsk.freqDev = 25; } else { uint8_t bw = dataRateBand & 0x03; switch(bw) { case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - datr.lora.bandwidth = 125.0; + datr->lora.bandwidth = 125.0; break; case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - datr.lora.bandwidth = 250.0; + datr->lora.bandwidth = 250.0; break; case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - datr.lora.bandwidth = 500.0; + datr->lora.bandwidth = 500.0; break; default: - return(RADIOLIB_ERR_INVALID_BANDWIDTH); + datr->lora.bandwidth = 125.0; } - datr.lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; + datr->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; } - + +} + +int16_t LoRaWANNode::configureChannel(uint8_t chan, uint8_t dr) { + // find the span based on the channel ID + uint8_t span = 0; + uint8_t spanChannelId = 0; + bool found = false; + for(uint8_t chanCtr = 0; span < this->band->numChannelSpans; span++) { + for(; spanChannelId < this->band->defaultChannels[span].numChannels; spanChannelId++) { + if(chanCtr >= chan) { + found = true; + break; + } + chanCtr++; + } + if(found) { + break; + } + } + + if(!found) { + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + + this->chIndex = chan; + + // set the frequency + float freq = this->band->defaultChannels[span].freqStart + this->band->defaultChannels[span].freqStep * (float)spanChannelId; + int state = this->phyLayer->setFrequency(freq); + RADIOLIB_ASSERT(state); + + // set the data rate + DataRate_t datr; + findDataRate(dr, &datr, &this->band->defaultChannels[span]); state = this->phyLayer->setDataRate(datr); return(state); @@ -480,7 +773,6 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { // calculate the expected value and compare uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); if(micCalculated != micReceived) { - RADIOLIB_DEBUG_PRINTLN("MIC mismatch, expected 0x%08x, got 0x%08x", micCalculated, micReceived); return(false); } @@ -536,6 +828,113 @@ int16_t LoRaWANNode::setPhyProperties() { return(state); } +int16_t LoRaWANNode::sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen) { + // build the command + size_t macReqLen = 1 + payloadLen; + #if !defined(RADIOLIB_STATIC_ONLY) + uint8_t* macReqBuff = new uint8_t[macReqLen]; + #else + uint8_t macReqBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + macReqBuff[0] = cid; + memcpy(&macReqBuff[1], payload, payloadLen); + + // uplink it + int16_t state = this->uplink(macReqBuff, macReqLen, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] macReqBuff; + #endif + RADIOLIB_ASSERT(state); + + // build the reply buffer + size_t macRplLen = 1 + replyLen; + #if !defined(RADIOLIB_STATIC_ONLY) + uint8_t* macRplBuff = new uint8_t[this->band->payloadLenMax[this->dataRate]]; + #else + uint8_t macRplBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // wait for reply from the server + size_t rxRplLen = 0; + state = this->downlink(macRplBuff, &rxRplLen); + if(state != RADIOLIB_ERR_NONE) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] macRplBuff; + #endif + return(state); + } + + //Module::hexdump(macRplBuff, rxRplLen); + + // check the length - it may be longer than expected + // if the server decided to append more MAC commands, but never shorter + // TODO how to handle the additional command(s)? + if(rxRplLen < macRplLen) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] macRplBuff; + #endif + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // check the CID + if(macRplBuff[0] != cid) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] macRplBuff; + #endif + return(RADIOLIB_ERR_INVALID_CID); + } + + // copy the data + memcpy(reply, &macRplBuff[1], replyLen); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] macRplBuff; + #endif + + return(state); +} + +void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) { + // figure out how many encryption blocks are there + size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; + if(len % RADIOLIB_AES128_BLOCK_SIZE) { + numBlocks++; + } + + // generate the encryption blocks + uint8_t encBuffer[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + uint8_t encBlock[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS] = ctrId; + encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = dir; + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + + //Module::hexdump(uplinkMsg, uplinkMsgLen); + + // now encrypt the input + // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext + size_t remLen = len; + for(size_t i = 0; i < numBlocks; i++) { + if(counter) { + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; + } + + // encrypt the buffer + RadioLibAES128Instance.init(key); + RadioLibAES128Instance.encryptECB(encBlock, RADIOLIB_AES128_BLOCK_SIZE, encBuffer); + + // now xor the buffer with the input + size_t xorLen = remLen; + if(xorLen > RADIOLIB_AES128_BLOCK_SIZE) { + xorLen = RADIOLIB_AES128_BLOCK_SIZE; + } + for(uint8_t j = 0; j < xorLen; j++) { + out[i*RADIOLIB_AES128_BLOCK_SIZE + j] = in[i*RADIOLIB_AES128_BLOCK_SIZE + j] ^ encBuffer[j]; + } + remLen -= xorLen; + } +} + template T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { uint8_t* buffPtr = buff; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index d0262df129..098d4a57a2 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -68,6 +68,7 @@ // recommended default settings #define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) #define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000) +#define RADIOLIB_LORAWAN_RX_WINDOW_LEN_MS (500) #define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) @@ -83,14 +84,20 @@ #define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) #define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS (9) #define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS (17) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE (0xFF) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_0 (0x00) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_1 (0x01) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_2 (0x02) // join accept message layout #define RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN (33) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS (1) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS (4) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS (7) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS (4) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS (11) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS (12) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS (13) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN (16) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN - 1) @@ -102,17 +109,20 @@ #define RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY (0x02) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) - -// uplink message layout -#define RADIOLIB_LORAWAN_UPLINK_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) -#define RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS (16) -#define RADIOLIB_LORAWAN_UPLINK_DEV_ADDR_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 1) -#define RADIOLIB_LORAWAN_UPLINK_FCTRL_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 5) -#define RADIOLIB_LORAWAN_UPLINK_FCNT_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 6) -#define RADIOLIB_LORAWAN_UPLINK_FOPTS_POS (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 8) -#define RADIOLIB_LORAWAN_UPLINK_FOPTS_MAX_LEN (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 16) -#define RADIOLIB_LORAWAN_UPLINK_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 8 + (FOPTS)) -#define RADIOLIB_LORAWAN_UPLINK_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_UPLINK_LEN_START_OFFS + 9 + (FOPTS)) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_ENC_KEY (0x05) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY (0x06) + +// frame header layout +#define RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS (16) +#define RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 1) +#define RADIOLIB_LORAWAN_FHDR_FCTRL_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 5) +#define RADIOLIB_LORAWAN_FHDR_FCNT_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 6) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK (0x0F) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 16) +#define RADIOLIB_LORAWAN_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8 + (FOPTS)) +#define RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 9 + (FOPTS)) +#define RADIOLIB_LORAWAN_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) // payload encryption/MIC blocks common layout #define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0) @@ -122,6 +132,7 @@ // payload encryption block layout #define RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC (0x01) +#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS (4) #define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS (15) // payload MIC blocks layout @@ -133,6 +144,22 @@ // magic word saved in persistent memory upon activation #define RADIOLIB_LORAWAN_MAGIC (0x12AD101B) +// MAC commands +#define RADIOLIB_LORAWAN_MAC_CMD_RESET_IND (0x01) +#define RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK_REQ (0x02) +#define RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR_ANS (0x03) +#define RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE_ANS (0x04) +#define RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP_ANS (0x05) +#define RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS_ANS (0x06) +#define RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL_ANS (0x07) +#define RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP_ANS (0x08) +#define RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP_ANS (0x09) +#define RADIOLIB_LORAWAN_MAC_CMD_DI_CHANNEL_ANS (0x0A) +#define RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND (0x0B) +#define RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP_ANS (0x0C) +#define RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME_REQ (0x0D) +#define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP_ANS (0x0F) + /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. @@ -208,6 +235,12 @@ extern const LoRaWANBand_t AS923; extern const LoRaWANBand_t KR920; extern const LoRaWANBand_t IN865; +struct LoRaWANMacCommand_t { + uint8_t cid; + size_t len; + uint8_t* payload; +}; + /*! \class LoRaWANNode \brief LoRaWAN-compatible node (class A device). @@ -239,14 +272,14 @@ class LoRaWANNode { /*! \brief Join network by performing over-the-air activation. By this procedure, the device will perform an exchange with the network server and set all necessary configuration. - \param appEUI 8-byte application identifier. + \param joinEUI 8-byte application identifier. \param devEUI 8-byte device identifier. \param nwkKey Pointer to the network AES-128 key. \param appKey Pointer to the application AES-128 key. \param force Set to true to force joining even if previously joined. \returns \ref status_codes */ - int16_t beginOTAA(uint64_t appEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false); /*! \brief Join network by performing activation by personalization. @@ -287,39 +320,67 @@ class LoRaWANNode { */ int16_t uplink(uint8_t* data, size_t len, uint8_t port); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! - \brief Configure the radio to a given channel frequency and data rate. - \param chan Channel ID to set. - \param dr Data rate to set, DR0 - DR15. + \brief Wait for downlink from the server in either RX1 or RX2 window. + \param str Address of Arduino String to save the received data. \returns \ref status_codes */ - int16_t configureChannel(uint8_t chan, uint8_t dr); + int16_t downlink(String& str); + #endif + + /*! + \brief Wait for downlink from the server in either RX1 or RX2 window. + \param data Buffer to save received data into. + \param len Pointer to variable that will be used to save the number of received bytes. + \returns \ref status_codes + */ + int16_t downlink(uint8_t* data, size_t* len); #if !defined(RADIOLIB_GODMODE) private: #endif - PhysicalLayer* phyLayer; - const LoRaWANBand_t* band; + PhysicalLayer* phyLayer = NULL; + const LoRaWANBand_t* band = NULL; + + LoRaWANMacCommand_t* command = NULL; // the following is either provided by the network server (OTAA) // or directly entered by the user (ABP) - uint32_t devAddr; - uint8_t appSKey[RADIOLIB_AES128_KEY_SIZE]; - uint8_t fNwkSIntKey[RADIOLIB_AES128_KEY_SIZE]; - uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE]; - uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE]; - uint8_t rxDelay; - float availableChannelsFreq[5]; - uint16_t availableChannelsMask[6]; + uint32_t devAddr = 0; + uint8_t appSKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t fNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + float availableChannelsFreq[5] = { 0 }; + uint16_t availableChannelsMask[6] = { 0 }; // LoRaWAN revision (1.0 vs 1.1) - uint8_t rev; + uint8_t rev = 0; // currently configured data rate DR0 - DR15 (band-dependent!) - uint8_t dataRate; + uint8_t dataRate = 0; // currently configured channel (band-dependent!) - uint8_t chIndex; + uint8_t chIndex = 0; + + // timestamp to measure the RX1/2 delay (from uplink end) + uint32_t rxDelayStart = 0; + + // delays between the uplink and RX1/2 windows + uint32_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; + + // find the first usable data rate in a given channel span + void findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span); + + /*! + \brief Configure the radio to a given channel frequency and data rate. + \param chan Channel ID to set. + \param dr Data rate to set, DR0 - DR15. + \returns \ref status_codes + */ + int16_t configureChannel(uint8_t chan, uint8_t dr); // method to generate message integrity code uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); @@ -328,8 +389,15 @@ class LoRaWANNode { // it assumes that the MIC is the last 4 bytes of the message bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); + // configure the physical layer properties (frequency, sync word etc.) int16_t setPhyProperties(); + // send a MAC command to the network server + int16_t sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen); + + // function to encrypt and decrypt payloads + void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); + // network-to-host conversion method - takes data from network packet and converts it to the host endians template static T ntoh(uint8_t* buff, size_t size = 0); From cbd15192bc7538e0ecd0505a64866975b9387e16 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 19:52:41 +0200 Subject: [PATCH 0721/1848] [SX126x] Fixed example path --- ...pt_Lolin.ino => SX126x_Channel_Activity_Detection_Receive.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/SX126x/SX126x_Channel_Activity_Detection_Receive/{SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino => SX126x_Channel_Activity_Detection_Receive.ino} (100%) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino similarity index 100% rename from examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Interrupt_Lolin.ino rename to examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino From 1a31efbf7464b4d2886e0c7d30f907507200be52 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 19:57:22 +0200 Subject: [PATCH 0722/1848] [LoRaWAN] Drop examples on Uno --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 88b3af3fd7..cdc256b8b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,7 +47,7 @@ jobs: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. include: - id: arduino:avr:uno - run: echo "skip-pattern=(STM32WL|SSTV)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - id: arduino:avr:leonardo From 45c376bde6370175796c0434dabb6e65091ec2f3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 19:58:00 +0200 Subject: [PATCH 0723/1848] [LoRaWAN] Fixed variable range warning --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 83fb49e39e..b31abbb291 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -325,7 +325,9 @@ int16_t LoRaWANNode::uplink(const char* str, uint8_t port) { int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { // check destination port - RADIOLIB_CHECK_RANGE(port, 0x00, 0xDF, RADIOLIB_ERR_INVALID_PORT); + if(port > 0xDF) { + return(RADIOLIB_ERR_INVALID_PORT); + } // check if there is a MAC command to piggyback uint8_t foptsLen = 0; From 1ed22717d748db981c3c7d002c6fd9f9226137a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Aug 2023 21:48:31 +0200 Subject: [PATCH 0724/1848] [LoRaWAN] Added check to not uplink in Rx slots --- src/TypeDef.h | 5 +++++ src/protocols/LoRaWAN/LoRaWAN.cpp | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index e24675b2de..96058827c3 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -518,6 +518,11 @@ */ #define RADIOLIB_ERR_INVALID_CID (-1107) +/*! + \brief User requested to start uplink while still inside RX window. +*/ +#define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108) + /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b31abbb291..c2cd77d75a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -342,9 +342,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { // check if sufficient time has elapsed since the last uplink Module* mod = this->phyLayer->getMod(); - /*if(mod->hal->millis() - this->rxDelayStart < ) { - - }*/ + if(mod->hal->millis() - this->rxDelayStart < rxDelays[1]) { + // not enough time elapsed since the last uplink, we may still be in an RX window + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks From 0a72d98750326a66dd509cb2f93bbac4b8ab4219 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 14 Aug 2023 21:38:31 +0200 Subject: [PATCH 0725/1848] [LoRaWAN] Fixed MIC calculation for downlink packets --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c2cd77d75a..0c36377da0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -625,6 +625,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { state = RADIOLIB_ERR_NONE; } + // get the frame counter and set it to the MIC calculation block + // TODO this will not handle overflow into 32-bits! + // TODO cache the ADR bit? + uint16_t fcnt = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + //Module::hexdump(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); if(state != RADIOLIB_ERR_NONE) { @@ -646,10 +652,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } - // TODO cache the ADR bit? - // TODO cache and check fcnt? - uint16_t fcnt = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); - // check fopts len uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; if(foptsLen > 0) { From 3e8636b1f2002b3d9f129482f0d6ad49220129e0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 18 Aug 2023 20:21:53 +0200 Subject: [PATCH 0726/1848] [APRS] Removed redundant condition (#810) --- src/protocols/APRS/APRS.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 33559e7919..780dddf4d5 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -24,13 +24,10 @@ int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { table = '/'; } - if(this->phyLayer != nullptr) { - return(RADIOLIB_ERR_INVALID_CALLSIGN); - } - if(strlen(callsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { return(RADIOLIB_ERR_INVALID_CALLSIGN); } + memcpy(this->src, callsign, strlen(callsign)); this->id = ssid; From b2b176f1c35c0409333a97202969571ce6bd4ffd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Aug 2023 19:16:07 +0200 Subject: [PATCH 0727/1848] [LoRaWAN] Added MIC mismatch debug message --- src/protocols/LoRaWAN/LoRaWAN.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0c36377da0..75266256fb 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -778,6 +778,7 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { // calculate the expected value and compare uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); if(micCalculated != micReceived) { + RADIOLIB_DEBUG_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); return(false); } From 73382c293347480509bce6276f66b6028f74fc42 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Aug 2023 19:16:38 +0200 Subject: [PATCH 0728/1848] [LoRaWAN] Fixed output power configuration (#814) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 75266256fb..568abbcadc 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -806,8 +806,14 @@ int16_t LoRaWANNode::setPhyProperties() { state = this->configureChannel(channelId, this->band->defaultChannels[0].joinRequestDataRate); } RADIOLIB_ASSERT(state); - - state = this->phyLayer->setOutputPower(this->band->powerMax); + + // set the maximum power supported by both the module and the band + int8_t pwr = this->band->powerMax; + state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power in band and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(pwr--); + } RADIOLIB_ASSERT(state); uint8_t syncWord[3] = { 0 }; From 16f0ba7cce84d40ed82dc50c55e14633ee530a60 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 23 Aug 2023 19:22:23 +0200 Subject: [PATCH 0729/1848] [LoRaWAN] Implemented MAC command support --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 8 +- .../LoRaWAN_End_Device_APB.ino | 8 +- keywords.txt | 2 + src/TypeDef.h | 10 ++ src/protocols/LoRaWAN/LoRaWAN.cpp | 169 +++++++++++++++--- src/protocols/LoRaWAN/LoRaWAN.h | 44 ++++- 6 files changed, 206 insertions(+), 35 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index a239ee08f7..a28cad77a3 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -133,9 +133,13 @@ void loop() { if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); - // print data of the packet + // print data of the packet (if there are any) Serial.print(F("[LoRaWAN] Data:\t\t")); - Serial.println(strDown); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } // print RSSI (Received Signal Strength Indicator) Serial.print(F("[LoRaWAN] RSSI:\t\t")); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino index a19effdc1d..2ecf656920 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino @@ -128,9 +128,13 @@ void loop() { if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); - // print data of the packet + // print data of the packet (if there are any) Serial.print(F("[LoRaWAN] Data:\t\t")); - Serial.println(strDown); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } // print RSSI (Received Signal Strength Indicator) Serial.print(F("[LoRaWAN] RSSI:\t\t")); diff --git a/keywords.txt b/keywords.txt index 617a3983a8..36bfb988f1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -399,3 +399,5 @@ RADIOLIB_ERR_INVALID_PORT LITERAL1 RADIOLIB_ERR_NO_RX_WINDOW LITERAL1 RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 RADIOLIB_ERR_INVALID_CID LITERAL1 +RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 +RADIOLIB_ERR_COMMAND_QUEUE_EMPTY LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index 96058827c3..11b3f7f6c4 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -523,6 +523,16 @@ */ #define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108) +/*! + \brief Unable to push new MAC command because the queue is full. +*/ +#define RADIOLIB_ERR_COMMAND_QUEUE_FULL (-1109) + +/*! + \brief Unable to pop existing MAC command because the queue is empty. +*/ +#define RADIOLIB_ERR_COMMAND_QUEUE_EMPTY (-1110) + /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 568abbcadc..63d4d1548f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -250,16 +250,16 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); //Module::hexdump(this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - // send the RekeyInd MAC command + // enqueue the RekeyInd MAC command to be sent in the next uplink this->rev = 1; - uint8_t serverRev = 0xFF; - state = sendMacCommand(RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND, &this->rev, sizeof(uint8_t), &serverRev, sizeof(uint8_t)); + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND, + .len = sizeof(uint8_t), + .payload = { this->rev }, + .repeat = RADIOLIB_LORAWAN_ADR_ACK_LIMIT, + }; + state = pushMacCommand(&cmd, &this->commandsUp); RADIOLIB_ASSERT(state); - - // check the supported server version - if(serverRev != this->rev) { - return(RADIOLIB_ERR_INVALID_REVISION); - } } else { // 1.0 version, just derive the keys @@ -329,10 +329,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { return(RADIOLIB_ERR_INVALID_PORT); } - // check if there is a MAC command to piggyback - uint8_t foptsLen = 0; - if(this->command) { - foptsLen = 1 + this->command->len; + // check if there are some MAC commands to piggyback + size_t foptsLen = 0; + if(this->commandsUp.numCommands > 0) { + // there are, assume the maximum possible FOpts len for buffer allocation + foptsLen = 15; } // check maximum payload len as defined in phy @@ -361,24 +362,30 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); // TODO implement adaptive data rate - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00 | foptsLen; + // foptslen will be added later + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; // get frame counter from persistent storage uint32_t fcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID) + 1; mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, fcnt); LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)fcnt); - // check if there is something in FOpts - if(this->command) { - // append MAC command + // check if we have some MAC command to append + // TODO implement appending multiple MAC commands + LoRaWANMacCommand_t cmd = { 0 }; + if(popMacCommand(&cmd, &this->commandsUp) == RADIOLIB_ERR_NONE) { + // we do, add it to fopts uint8_t foptsBuff[RADIOLIB_AES128_BLOCK_SIZE]; - foptsBuff[0] = this->command->cid; - for(size_t i = 1; i < this->command->len; i++) { - foptsBuff[i] = this->command->payload[i]; + foptsBuff[0] = cmd.cid; + for(size_t i = 1; i < cmd.len; i++) { + foptsBuff[i] = cmd.payload[i]; } + foptsLen = 1 + cmd.len; + uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= foptsLen; // encrypt it - processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, false); + processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); } // set the port @@ -435,7 +442,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { RADIOLIB_ASSERT(state); // set the timestamp so that we can measure when to start receiving - this->command = NULL; this->rxDelayStart = txStart + timeOnAir; return(RADIOLIB_ERR_NONE); } @@ -656,21 +662,46 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; if(foptsLen > 0) { // there are some Fopts, decrypt them - *len = foptsLen; + uint8_t fopts[RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK]; // according to the specification, the last two arguments should be 0x00 and false, // but that will fail even for LoRaWAN 1.1.0 server - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], foptsLen, this->nwkSEncKey, data, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x01, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x01, true); + + //Module::hexdump(fopts, foptsLen); + + // process the MAC command(s) + int8_t remLen = foptsLen; + uint8_t* foptsPtr = fopts; + while(remLen > 0) { + LoRaWANMacCommand_t cmd = { + .cid = *foptsPtr, + .len = remLen - 1, + .payload = { 0 }, + }; + memcpy(cmd.payload, foptsPtr + 1, cmd.len); + + // try to process the mac command + // TODO how to handle incomplete commands? + size_t processedLen = execMacCommand(&cmd) + 1; + + // processing succeeded, move in the buffer to the next command + remLen -= processedLen; + foptsPtr += processedLen; + } + } - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] downlinkMsg; - #endif + // fopts are processed or not present, check if there is payload + int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); + if(payLen <= 0) { + // no payload + *len = 0; return(RADIOLIB_ERR_NONE); } - // no fopts, just payload - // TODO implement decoding piggybacked Fopts? - *len = downlinkMsgLen; + // there is payload, and so there should be a port too + // TODO pass the port? + *len = payLen - 1; processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], downlinkMsgLen, this->appSKey, data, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !defined(RADIOLIB_STATIC_ONLY) @@ -680,6 +711,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { return(state); } +void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { + this->battLevel = battLevel; +} + void LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span) { uint8_t dataRateBand = span->dataRates[dr]; this->dataRate = dr; @@ -905,6 +940,82 @@ int16_t LoRaWANNode::sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloa return(state); } +int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { + if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { + return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); + } + + memcpy(&queue->commands[queue->numCommands], cmd, sizeof(LoRaWANMacCommand_t)); + /*RADIOLIB_DEBUG_PRINTLN("push MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", + queue->commands[queue->numCommands - 1].cid, + queue->commands[queue->numCommands - 1].len, + queue->commands[queue->numCommands - 1].payload[0], + queue->commands[queue->numCommands - 1].payload[1], + queue->commands[queue->numCommands - 1].payload[2], + queue->commands[queue->numCommands - 1].payload[3], + queue->commands[queue->numCommands - 1].payload[4], + queue->commands[queue->numCommands - 1].repeat);*/ + queue->numCommands++; + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, bool force) { + if(queue->numCommands == 0) { + return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); + } + + if(cmd) { + /*RADIOLIB_DEBUG_PRINTLN("pop MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", + queue->commands[queue->numCommands - 1].cid, + queue->commands[queue->numCommands - 1].len, + queue->commands[queue->numCommands - 1].payload[0], + queue->commands[queue->numCommands - 1].payload[1], + queue->commands[queue->numCommands - 1].payload[2], + queue->commands[queue->numCommands - 1].payload[3], + queue->commands[queue->numCommands - 1].payload[4], + queue->commands[queue->numCommands - 1].repeat);*/ + memcpy(cmd, &queue->commands[queue->numCommands - 1], sizeof(LoRaWANMacCommand_t)); + } + + if((!force) && (queue->commands[queue->numCommands - 1].repeat > 0)) { + queue->commands[queue->numCommands - 1].repeat--; + } else { + queue->commands[queue->numCommands - 1].repeat = 0; + queue->numCommands--; + } + + return(RADIOLIB_ERR_NONE); +} + +size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { + //RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); + + switch(cmd->cid) { + case(RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS_ANS): { + // set the uplink reply + cmd->len = 2; + cmd->payload[1] = this->battLevel; + int8_t snr = this->phyLayer->getSNR(); + cmd->payload[0] = snr & 0x3F; + + // push it to the uplink queue + pushMacCommand(cmd, &this->commandsUp); + return(0); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND): { + // TODO verify the actual server version here + + // stop sending the ReKey MAC command + popMacCommand(NULL, &this->commandsUp, true); + return(1); + } break; + } + + return(0); +} + void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) { // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 098d4a57a2..73ebbf3596 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -160,6 +160,9 @@ #define RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME_REQ (0x0D) #define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP_ANS (0x0F) +// the length of internal MAC command queue - hopefully this is enough for most use cases +#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8) + /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. @@ -235,10 +238,27 @@ extern const LoRaWANBand_t AS923; extern const LoRaWANBand_t KR920; extern const LoRaWANBand_t IN865; +/*! + \struct LoRaWANMacCommand_t + \brief Structure to save information about MAC command +*/ struct LoRaWANMacCommand_t { + /*! \brief The command ID */ uint8_t cid; + + /*! \brief Length of the payload */ size_t len; - uint8_t* payload; + + /*! \brief Payload buffer (5 bytes is the longest possible) */ + uint8_t payload[5]; + + /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ + uint8_t repeat; +}; + +struct LoRaWANMacCommandQueue_t { + LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; + size_t numCommands; }; /*! @@ -337,13 +357,21 @@ class LoRaWANNode { */ int16_t downlink(uint8_t* data, size_t* len); + /*! + \brief Set device status. + \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, + 254 for highest battery, 255 for unable to measure. + */ + void setDeviceStatus(uint8_t battLevel); + #if !defined(RADIOLIB_GODMODE) private: #endif PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; - LoRaWANMacCommand_t* command = NULL; + LoRaWANMacCommandQueue_t commandsUp = { .commands = { 0 }, .numCommands = 0 }; + LoRaWANMacCommandQueue_t commandsDown = { .commands = { 0 }, .numCommands = 0 }; // the following is either provided by the network server (OTAA) // or directly entered by the user (ABP) @@ -371,6 +399,9 @@ class LoRaWANNode { // delays between the uplink and RX1/2 windows uint32_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; + // device status - battery level + uint8_t battLevel = 0xFF; + // find the first usable data rate in a given channel span void findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span); @@ -395,6 +426,15 @@ class LoRaWANNode { // send a MAC command to the network server int16_t sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen); + // push MAC command to queue, done by copy + int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); + + // pop MAC command from queue, done by copy unless CMD is NULL + int16_t popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, bool force = false); + + // execute mac command, return the number of processed bytes for sequential processing + size_t execMacCommand(LoRaWANMacCommand_t* cmd); + // function to encrypt and decrypt payloads void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); From 2555857013a676f28798e550921ac6f0305b0e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicklas=20B=C3=B6rjesson?= Date: Wed, 23 Aug 2023 20:16:57 +0200 Subject: [PATCH 0730/1848] Fix "narrowing conversion" error on ESP-IDF The 1 without a cast caused the result to be an integer. --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 63d4d1548f..8445c46584 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -676,7 +676,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { while(remLen > 0) { LoRaWANMacCommand_t cmd = { .cid = *foptsPtr, - .len = remLen - 1, + .len = (uint8_t)(remLen - 1), .payload = { 0 }, }; memcpy(cmd.payload, foptsPtr + 1, cmd.len); From 95e383934276954aefc59b86b6b15757b82badcf Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 24 Aug 2023 17:54:49 +0200 Subject: [PATCH 0731/1848] [LoRaWAN] Represent keys as byte arrays (#58) (#811) --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 12 +++++++++--- .../LoRaWAN_End_Device_APB.ino | 10 ++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index a28cad77a3..408784a830 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -73,8 +73,14 @@ void setup() { // select some encryption keys which will be used to secure the communication // there are two of them - network key and application key // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long - const char nwkKey[] = "topSecretKey1234"; - const char appKey[] = "aDifferentKeyABC"; + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded @@ -83,7 +89,7 @@ void setup() { // now we can start the activation // this can take up to 20 seconds, and requires a LoRaWAN gateway in range Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginOTAA(joinEUI, devEUI, (uint8_t*)nwkKey, (uint8_t*)appKey); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino index 2ecf656920..9ac61b4ec2 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino @@ -69,8 +69,14 @@ void setup() { // select some encryption keys which will be used to secure the communication // there are two of them - network key and application key // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long - const char nwkSKey[] = "topSecretKey1234"; - const char appSKey[] = "aDifferentKeyABC"; + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkSKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appSKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded From c999ac2cab10b65147d40cb45bda09410369ba85 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 24 Aug 2023 20:48:50 +0200 Subject: [PATCH 0732/1848] [CI] Added CI action for ESP-IDF to catch -Werrors --- .github/workflows/main.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cdc256b8b5..df6165430b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -176,6 +176,32 @@ jobs: fi done + esp-build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies + run: sudo apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 + + - name: Clone ESP-IDF + run: | + mkdir -p ~/esp + cd ~/esp + git clone --recursive https://github.com/espressif/esp-idf.git + + - name: Install ESP-IDF + run: | + cd ~/esp/esp-idf + ./install.sh esp32 + . ./export.sh + + - name: Build the example + run: | + cd $PWD/examples/NonArduino/ESP-IDF + idf.py build + rpi-build: runs-on: [self-hosted, ARM64] steps: From 3eb397adfd986fab1843cedc8a5fa9113f28e5c5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 24 Aug 2023 20:54:20 +0200 Subject: [PATCH 0733/1848] [CI] Moved IDF export to build step --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index df6165430b..ef6f6cfab0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -195,11 +195,11 @@ jobs: run: | cd ~/esp/esp-idf ./install.sh esp32 - . ./export.sh - name: Build the example run: | cd $PWD/examples/NonArduino/ESP-IDF + . ~/esp/esp-idf/export.sh idf.py build rpi-build: From d170c0256153550b02fabbfd6c468625dbb23499 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Aug 2023 20:34:37 +0200 Subject: [PATCH 0734/1848] [LoRaWAN] Fixed initialization warnings --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 ++- src/protocols/LoRaWAN/LoRaWAN.h | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 8445c46584..fc2b2275be 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -372,7 +372,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { // check if we have some MAC command to append // TODO implement appending multiple MAC commands - LoRaWANMacCommand_t cmd = { 0 }; + LoRaWANMacCommand_t cmd = { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, }; if(popMacCommand(&cmd, &this->commandsUp) == RADIOLIB_ERR_NONE) { // we do, add it to fopts uint8_t foptsBuff[RADIOLIB_AES128_BLOCK_SIZE]; @@ -678,6 +678,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { .cid = *foptsPtr, .len = (uint8_t)(remLen - 1), .payload = { 0 }, + .repeat = 0, }; memcpy(cmd.payload, foptsPtr + 1, cmd.len); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 73ebbf3596..7086b8aa1c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -370,8 +370,14 @@ class LoRaWANNode { PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; - LoRaWANMacCommandQueue_t commandsUp = { .commands = { 0 }, .numCommands = 0 }; - LoRaWANMacCommandQueue_t commandsDown = { .commands = { 0 }, .numCommands = 0 }; + LoRaWANMacCommandQueue_t commandsUp = { + .commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } }, + .numCommands = 0, + }; + LoRaWANMacCommandQueue_t commandsDown = { + .commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } }, + .numCommands = 0, + }; // the following is either provided by the network server (OTAA) // or directly entered by the user (ABP) From b54aa77b4243526a06e52157b828de18703eecff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Aug 2023 20:35:48 +0200 Subject: [PATCH 0735/1848] [LoRaWAN] Fixed incorrect example name --- .../LoRaWAN_End_Device_ABP.ino} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename examples/LoRaWAN/{LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino => LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino} (98%) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino similarity index 98% rename from examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino rename to examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index 9ac61b4ec2..e464830edf 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_APB/LoRaWAN_End_Device_APB.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -1,7 +1,7 @@ /* - RadioLib LoRaWAN End Device APB Example + RadioLib LoRaWAN End Device ABP Example - This example sets up a LoRaWAN node using APB (activation + This example sets up a LoRaWAN node using ABP (activation by personalization). Before you start, you will have to register your device at https://www.thethingsnetwork.org/ After your device is registered, you can run this example. From 7e9e7ba7be64e7286964d34c12e981afd48e7601 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 29 Aug 2023 21:00:47 +1000 Subject: [PATCH 0736/1848] Tock: Fixup build failure Signed-off-by: Alistair Francis --- examples/NonArduino/Tock/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index d8bf33d729..c8a5628d4a 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -61,7 +61,7 @@ int main(void) { for(;;) { yield_no_wait(); // send a packet - printf("[SX1261] Transmitting '%s' \r\n", transmit_string); + printf("[SX1261] Transmitting\r\n"); state = radio->transmit("Hello World!"); From 414e338505f6f9873190266131208c149706cd6a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 29 Aug 2023 21:57:51 +0200 Subject: [PATCH 0737/1848] Fixed ESP32 platform detection --- src/ArduinoHal.cpp | 12 ++++++------ src/ArduinoHal.h | 2 +- src/BuildOpt.h | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 5bcafb057a..69b8d90df4 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -101,25 +101,25 @@ void inline ArduinoHal::spiEnd() { } void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if defined(ESP32) + #if defined(RADIOLIB_ESP32) EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); #endif for(size_t i = 0; i < len; i++) { buff[i] = EEPROM.read(addr + i); } - #if defined(ESP32) + #if defined(RADIOLIB_ESP32) EEPROM.end(); #endif } void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if defined(ESP32) + #if defined(RADIOLIB_ESP32) EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); #endif for(size_t i = 0; i < len; i++) { EEPROM.write(addr + i, buff[i]); } - #if defined(ESP32) + #if defined(RADIOLIB_ESP32) EEPROM.commit(); EEPROM.end(); #endif @@ -131,7 +131,7 @@ void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long return; } ::tone(pin, frequency, duration); - #elif defined(ESP32) + #elif defined(RADIOLIB_ESP32) // ESP32 tone() emulation (void)duration; if(prev == -1) { @@ -163,7 +163,7 @@ void inline ArduinoHal::noTone(uint32_t pin) { return; } ::noTone(pin); - #elif defined(ESP32) + #elif defined(RADIOLIB_ESP32) if(pin == RADIOLIB_NC) { return; } diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 7f9620d14d..2b650db872 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -73,7 +73,7 @@ class ArduinoHal : public RadioLibHal { mbed::PwmOut *pwmPin = NULL; #endif - #if defined(ESP32) + #if defined(RADIOLIB_ESP32) int32_t prev = -1; #endif }; diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 80a2839c01..48081988f4 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -88,7 +88,9 @@ // ESP8266 boards #define RADIOLIB_PLATFORM "ESP8266" -#elif defined(ESP32) +#elif defined(ESP32) || defined(ARDUINO_ARCH_ESP32) + #define RADIOLIB_ESP32 + // ESP32 boards #define RADIOLIB_PLATFORM "ESP32" From aa24052fda9a6fc5d47c573734445867feff87d5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 30 Aug 2023 16:21:23 +0200 Subject: [PATCH 0738/1848] Moved gitmodule file to tock example --- .gitmodules => examples/NonArduino/Tock/.gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .gitmodules => examples/NonArduino/Tock/.gitmodules (100%) diff --git a/.gitmodules b/examples/NonArduino/Tock/.gitmodules similarity index 100% rename from .gitmodules rename to examples/NonArduino/Tock/.gitmodules From 84c6e8c9ed7bea4fb732ef80b7511073856b5159 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 30 Aug 2023 20:30:57 +1000 Subject: [PATCH 0739/1848] github: Add Tock CI Signed-off-by: Alistair Francis --- .github/workflows/main.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ef6f6cfab0..599c5c9bf8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -202,6 +202,27 @@ jobs: . ~/esp/esp-idf/export.sh idf.py build + tock-build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install dependencies + run: | + sudo apt-get install -y gcc-arm-none-eabi + cargo install elf2tab + + - name: Build the example + run: | + cd $PWD/examples/NonArduino/Tock + ./build.sh + rpi-build: runs-on: [self-hosted, ARM64] steps: From b114295c54f069f1cbb124ff1a2248a54532650d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 31 Aug 2023 16:33:06 +0200 Subject: [PATCH 0740/1848] Revert "Moved gitmodule file to tock example" This reverts commit aa24052fda9a6fc5d47c573734445867feff87d5. --- examples/NonArduino/Tock/.gitmodules => .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/NonArduino/Tock/.gitmodules => .gitmodules (100%) diff --git a/examples/NonArduino/Tock/.gitmodules b/.gitmodules similarity index 100% rename from examples/NonArduino/Tock/.gitmodules rename to .gitmodules From ffbcbdfc841cc7f816f5822b4d60d1c1b95bdba2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 8 Sep 2023 19:26:47 +1000 Subject: [PATCH 0741/1848] Tock: toolchain: Try to be smarter about finding toolchains Instead of hard coding paths, let's instead try to find the toolchain from the users PATH. Signed-off-by: Alistair Francis --- .../Tock/toolchain-arm-none-eabi.cmake | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake b/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake index 685b070f59..87a23f6309 100644 --- a/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake +++ b/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake @@ -38,21 +38,13 @@ set(CMAKE_SYSTEM_PROCESSOR ARM) # Set toolchain paths #--------------------------------------------------------------------------------------- set(TOOLCHAIN arm-none-eabi) -if(NOT DEFINED TOOLCHAIN_PREFIX) - if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux) - set(TOOLCHAIN_PREFIX "/usr") - elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin) - set(TOOLCHAIN_PREFIX "/usr/local") - elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) - message(STATUS "Please specify the TOOLCHAIN_PREFIX !\n For example: -DTOOLCHAIN_PREFIX=\"C:/Program Files/GNU Tools ARM Embedded\" ") - else() - set(TOOLCHAIN_PREFIX "/usr") - message(STATUS "No TOOLCHAIN_PREFIX specified, using default: " ${TOOLCHAIN_PREFIX}) - endif() -endif() -set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/bin) -set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/${TOOLCHAIN}/include) -set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/${TOOLCHAIN}/lib) + +find_program(TOOLCHAIN_PREFIX ${TOOLCHAIN}-gcc NO_CACHE) +get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN_PREFIX} DIRECTORY) + +set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin) +set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include) +set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib) # Set system depended extensions if(WIN32) From 392708f8b5731ffa988455cd0edf28c25a3638ba Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Sep 2023 17:13:07 +0200 Subject: [PATCH 0742/1848] [MOD] Make regdump and hexdump only available in debug --- src/Module.cpp | 2 ++ src/Module.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index 80c430375e..0848a746f6 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -403,6 +403,7 @@ uint32_t Module::reflect(uint32_t in, uint8_t bits) { return(res); } +#if defined(RADIOLIB_DEBUG) void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { @@ -460,6 +461,7 @@ void Module::regdump(uint16_t start, size_t len) { delete[] buff; #endif } +#endif #if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO) // https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 diff --git a/src/Module.h b/src/Module.h index 2540673425..56697ac953 100644 --- a/src/Module.h +++ b/src/Module.h @@ -468,6 +468,7 @@ class Module { */ static uint32_t reflect(uint32_t in, uint8_t bits); + #if defined(RADIOLIB_DEBUG) /*! \brief Function to dump data as hex into the debug port. \param data Data to dump. @@ -483,6 +484,7 @@ class Module { \param len Number of bytes to dump. */ void regdump(uint16_t start, size_t len); + #endif #if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO) static size_t serialPrintf(const char* format, ...); From eb21f320ac3de6730ed11b537e8c1e5ce5bdd5d1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Sep 2023 17:20:27 +0200 Subject: [PATCH 0743/1848] [SX126x] Use debug macro for hexdump --- src/BuildOpt.h | 2 ++ src/modules/SX126x/SX126x.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 48081988f4..82c777a181 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -457,9 +457,11 @@ #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) #endif #endif + #define RADIOLIB_DEBUG_HEXDUMP(...) Module::hexdump(__VA_ARGS__) #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} + #define RADIOLIB_DEBUG_HEXDUMP(...) {} #endif #if defined(RADIOLIB_VERBOSE) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 69abb1734c..a4257510a1 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -2097,13 +2097,13 @@ bool SX126x::findChip(const char* verStr) { // check version register if(strncmp(verStr, version, 6) == 0) { RADIOLIB_DEBUG_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); - this->mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN(); flagFound = true; } else { #if defined(RADIOLIB_DEBUG) RADIOLIB_DEBUG_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); - this->mod->hexdump((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); #endif this->mod->hal->delay(10); From d0c4e3d6fb3b03c1ee4c696dfd1f4ea15681216a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Sep 2023 19:04:26 +0200 Subject: [PATCH 0744/1848] [SX126x] Skip printing symbol length --- src/modules/SX126x/SX126x.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index a4257510a1..dbf141cfcd 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1855,7 +1855,6 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; } else { From 44ffce1725c2ead3dac16a78b706757c5754446d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Sep 2023 19:05:06 +0200 Subject: [PATCH 0745/1848] [SX127x] Skip printing symbol length --- src/modules/SX127x/SX1272.cpp | 2 -- src/modules/SX127x/SX1278.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index b198d46a4e..2aad0fad36 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -117,7 +117,6 @@ int16_t SX1272::setBandwidth(float bw) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; - RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { @@ -171,7 +170,6 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; - RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index e61a1ef3f9..6c27542716 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -131,7 +131,6 @@ int16_t SX1278::setBandwidth(float bw) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; - RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { @@ -185,7 +184,6 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; - RADIOLIB_DEBUG_PRINTLN("Symbol length: %f ms", symbolLength); if(symbolLength >= 16.0) { state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { From 7dec9477ae281c298712055adfdbdd4a4dd1a99e Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Sep 2023 19:06:30 +0200 Subject: [PATCH 0746/1848] [PHY] Added coding rate to data rate struct --- src/modules/SX126x/SX126x.cpp | 4 ++++ src/modules/SX127x/SX1272.cpp | 4 ++++ src/modules/SX127x/SX1278.cpp | 4 ++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 1 + 4 files changed, 13 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index dbf141cfcd..7f739cf806 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -975,6 +975,10 @@ int16_t SX126x::setDataRate(DataRate_t dr) { // set the bandwidth state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); } return(state); diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 2aad0fad36..ac57210159 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -238,6 +238,10 @@ int16_t SX1272::setDataRate(DataRate_t dr) { // set the bandwidth state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); } return(state); diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 6c27542716..9fb0c5df90 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -252,6 +252,10 @@ int16_t SX1278::setDataRate(DataRate_t dr) { // set the bandwidth state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); } return(state); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index ba7df2128f..c083e4765c 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -8,6 +8,7 @@ struct LoRaRate_t { uint8_t spreadingFactor; float bandwidth; + uint8_t codingRate; }; // data rate structure interpretation in case FSK is used From 3055613b6d6521e01dd73c9399cf41a95182e2e1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Sep 2023 19:10:44 +0200 Subject: [PATCH 0747/1848] [LoRaWAN] Added support for US bands and reworked channel selection process (#814) --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 8 + .../LoRaWAN_End_Device_ABP.ino | 8 + src/protocols/LoRaWAN/LoRaWAN.cpp | 365 ++++++++++++------ src/protocols/LoRaWAN/LoRaWAN.h | 89 +++-- src/protocols/LoRaWAN/LoRaWANBands.cpp | 172 ++++----- 5 files changed, 418 insertions(+), 224 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index 408784a830..63dfe2bf89 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -86,6 +86,14 @@ void setup() { // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded // and can be set to NULL + // some frequency bands only use a subset of the available channels + // you can set the starting channel and their number + // for example, the following corresponds to US915 FSB2 in TTN + /* + node.startChannel = 8; + node.numChannels = 8; + */ + // now we can start the activation // this can take up to 20 seconds, and requires a LoRaWAN gateway in range Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index e464830edf..2f1d4f184a 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -82,6 +82,14 @@ void setup() { // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded // and can be set to NULL + // some frequency bands only use a subset of the available channels + // you can set the starting channel and their number + // for example, the following corresponds to US915 FSB2 in TTN + /* + node.startChannel = 8; + node.numChannels = 8; + */ + // start the device by directly providing the encryption keys and device address Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginAPB(devAddr, (uint8_t*)nwkSKey, (uint8_t*)appSKey); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index fc2b2275be..0a20169aa9 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -30,6 +30,8 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->phyLayer = phy; this->band = band; this->FSK = false; + this->startChannel = -1; + this->numChannels = -1; } void LoRaWANNode::wipe() { @@ -69,6 +71,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe int16_t state = this->setPhyProperties(); RADIOLIB_ASSERT(state); + // setup uplink/downlink frequencies and datarates + state = this->setupChannels(); + RADIOLIB_ASSERT(state); + // get dev nonce from persistent storage and increment it uint16_t devNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID); mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID, devNonce + 1); @@ -89,6 +95,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // send it state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); RADIOLIB_ASSERT(state); + + // configure for downlink with default configuration + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); + RADIOLIB_ASSERT(state); // set the function that will be called when the reply is received this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); @@ -156,8 +166,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe joinAcceptMsg[0] = joinAcceptMsgEnc[0]; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); - - //Module::hexdump(joinAcceptMsg, lenRx); + + RADIOLIB_DEBUG_PRINTLN("joinAcceptMsg:"); + RADIOLIB_DEBUG_HEXDUMP(joinAcceptMsg, lenRx); // check LoRaWAN revision (the MIC verification depends on this) uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; @@ -175,8 +186,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe LoRaWANNode::hton(&micBuff[1], joinEUI); LoRaWANNode::hton(&micBuff[9], devNonce); memcpy(&micBuff[11], joinAcceptMsg, lenRx); - - //Module::hexdump(micBuff, lenRx + 11); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { return(RADIOLIB_ERR_CRC_MISMATCH); @@ -206,14 +215,42 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // list of frequencies for(uint8_t i = 0; i < 5; i++) { uint32_t freq = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + 3*i], 3); - availableChannelsFreq[i] = (float)freq/10000.0; - RADIOLIB_DEBUG_PRINTLN("Channel %d frequency = %f MHz", i, availableChannelsFreq[i]); + availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = (float)freq/10000.0; + availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", i, availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); } } else { - // TODO list of masks - RADIOLIB_DEBUG_PRINTLN("CFlist masks not supported (yet)"); - return(RADIOLIB_ERR_UNSUPPORTED); + // frequency mask, we need to find out which frequencies are actually being used + uint8_t channelId = 0; + uint8_t chSpan = 0; + uint8_t chNum = 0; + for(uint8_t i = 0; i < 5; i++) { + uint16_t mask = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + 2*i]); + RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", i, mask); + for(uint8_t j = 0; j < 16; j++) { + if(chNum >= this->band->defaultChannels[chSpan].numChannels) { + chNum -= this->band->defaultChannels[chSpan].numChannels; + chSpan++; + + if(chSpan >= this->band->numChannelSpans) { + RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); + return(RADIOLIB_ERR_UNKNOWN); + } + } + + if(mask & (1UL << j)) { + RADIOLIB_DEBUG_PRINTLN("chNum = %d, chSpan = %d", chNum, chSpan); + uint8_t dir = this->band->defaultChannels[chSpan].direction; + float freq = this->band->defaultChannels[chSpan].freqStart + chNum*this->band->defaultChannels[chSpan].freqStep; + availableChannelsFreq[dir][channelId] = freq; + RADIOLIB_DEBUG_PRINTLN("Channel %cL %d frequency = %f MHz", dir ? 'U': 'D', channelId, availableChannelsFreq[dir][channelId]); + channelId++; + } + + chNum++; + } + } } @@ -229,26 +266,21 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonce); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; - //Module::hexdump(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE); RadioLibAES128Instance.init(appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); - //Module::hexdump(this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); - //Module::hexdump(this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey); - //Module::hexdump(this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); - //Module::hexdump(this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); // enqueue the RekeyInd MAC command to be sent in the next uplink this->rev = 1; @@ -310,6 +342,10 @@ int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, // set the physical layer configuration int16_t state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + + // setup uplink/downlink frequencies and datarates + state = this->setupChannels(); return(state); } @@ -337,10 +373,15 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { } // check maximum payload len as defined in phy - if(len > this->band->payloadLenMax[this->dataRate]) { + if(len > this->band->payloadLenMax[this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } + // configure for uplink + // TODO select randomly from available channels + int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + RADIOLIB_ASSERT(state); + // check if sufficient time has elapsed since the last uplink Module* mod = this->phyLayer->getMod(); if(mod->hal->millis() - this->rxDelayStart < rxDelays[1]) { @@ -411,10 +452,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); // TODO implement confirmed frames - block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRate; - block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->chIndex; - - //Module::hexdump(uplinkMsg, uplinkMsgLen); + block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + + RADIOLIB_DEBUG_PRINTLN("uplinkMsg pre-MIC:"); + RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); // calculate authentication codes memcpy(uplinkMsg, block1, RADIOLIB_AES128_BLOCK_SIZE); @@ -430,12 +472,13 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } - //Module::hexdump(uplinkMsg, uplinkMsgLen); + RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); + RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); // send it (without the MIC calculation blocks) uint32_t txStart = mod->hal->millis(); uint32_t timeOnAir = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; - int16_t state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); + state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); #if !defined(RADIOLIB_STATIC_ONLY) delete[] uplinkMsg; #endif @@ -479,8 +522,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { return(RADIOLIB_ERR_NO_RX_WINDOW); } + // configure for downlink + int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); + RADIOLIB_ASSERT(state); + // downlink messages are sent with inverted IQ - int16_t state = RADIOLIB_ERR_UNKNOWN; if(!this->FSK) { state = this->phyLayer->invertIQ(true); RADIOLIB_ASSERT(state); @@ -559,7 +605,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { } // restore the original uplink channel - this->configureChannel(0, this->dataRate); + this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -637,7 +683,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { uint16_t fcnt = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); - //Module::hexdump(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + RADIOLIB_DEBUG_PRINTLN("downlinkMsg:"); + RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); if(state != RADIOLIB_ERR_NONE) { #if !defined(RADIOLIB_STATIC_ONLY) @@ -668,7 +715,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // but that will fail even for LoRaWAN 1.1.0 server processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x01, true); - //Module::hexdump(fopts, foptsLen); + RADIOLIB_DEBUG_PRINTLN("fopts:"); + RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); // process the MAC command(s) int8_t remLen = foptsLen; @@ -716,82 +764,6 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { this->battLevel = battLevel; } -void LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span) { - uint8_t dataRateBand = span->dataRates[dr]; - this->dataRate = dr; - if(dr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; i++) { - if(span->dataRates[i] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - dataRateBand = span->dataRates[i]; - this->dataRate = i; - break; - } - } - } - - if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - datr->fsk.bitRate = 50; - datr->fsk.freqDev = 25; - - } else { - uint8_t bw = dataRateBand & 0x03; - switch(bw) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - datr->lora.bandwidth = 125.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - datr->lora.bandwidth = 250.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - datr->lora.bandwidth = 500.0; - break; - default: - datr->lora.bandwidth = 125.0; - } - - datr->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; - - } - -} - -int16_t LoRaWANNode::configureChannel(uint8_t chan, uint8_t dr) { - // find the span based on the channel ID - uint8_t span = 0; - uint8_t spanChannelId = 0; - bool found = false; - for(uint8_t chanCtr = 0; span < this->band->numChannelSpans; span++) { - for(; spanChannelId < this->band->defaultChannels[span].numChannels; spanChannelId++) { - if(chanCtr >= chan) { - found = true; - break; - } - chanCtr++; - } - if(found) { - break; - } - } - - if(!found) { - return(RADIOLIB_ERR_INVALID_CHANNEL); - } - - this->chIndex = chan; - - // set the frequency - float freq = this->band->defaultChannels[span].freqStart + this->band->defaultChannels[span].freqStep * (float)spanChannelId; - int state = this->phyLayer->setFrequency(freq); - RADIOLIB_ASSERT(state); - - // set the data rate - DataRate_t datr; - findDataRate(dr, &datr, &this->band->defaultChannels[span]); - state = this->phyLayer->setDataRate(datr); - - return(state); -} - uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { if((msg == NULL) || (len == 0)) { return(0); @@ -823,11 +795,9 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { int16_t LoRaWANNode::setPhyProperties() { // set the physical layer configuration - // TODO select channel span based on channel ID - // TODO select channel randomly - uint8_t channelId = 0; int16_t state = RADIOLIB_ERR_NONE; if(this->FSK) { + // for FSK, configure the channel state = this->phyLayer->setFrequency(this->band->fskFreq); RADIOLIB_ASSERT(state); DataRate_t dr; @@ -838,8 +808,6 @@ int16_t LoRaWANNode::setPhyProperties() { state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); RADIOLIB_ASSERT(state); state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); - } else { - state = this->configureChannel(channelId, this->band->defaultChannels[0].joinRequestDataRate); } RADIOLIB_ASSERT(state); @@ -876,6 +844,184 @@ int16_t LoRaWANNode::setPhyProperties() { return(state); } +int16_t LoRaWANNode::setupChannels() { + // find appropriate channel IDs for uplink and downlink, the uplink channel is random + int8_t chMin = -1; + int8_t chMax = -1; + if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_MASK) { + chMin = this->startChannel; + chMax = this->startChannel + this->numChannels; + } + int16_t state = this->findChannelId(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + &this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], + &this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], chMin, chMax); + RADIOLIB_ASSERT(state); + + // RX1 channel is not random, but determined by uplink channel + if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { + // for frequency-list type bands, it's just the previous uplink channel + this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + + } else { + // for mask type bands, it's the uplink mod num_downlink_channels + for(uint8_t i = 0; i < this->band->numChannelSpans; i++) { + const LoRaWANChannelSpan_t* span = &this->band->defaultChannels[i]; + if(span->direction == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { + this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] % span->numChannels; + this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = span->joinRequestDataRate; + break; + } + } + } + + // based on the channel IDs, find the frequencies + state = this->findChannelFreq(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, + this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], + &this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]); + RADIOLIB_ASSERT(state); + state = this->findChannelFreq(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, + this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK], + &this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]); + RADIOLIB_ASSERT(state); + + // configure channel for uplink + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + return(state); +} + +uint8_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span) { + uint8_t dataRateBand = 0; + uint8_t dataRateFound = 0; + if(dr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; i++) { + if(span->dataRates[i] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + dataRateBand = span->dataRates[i]; + dataRateFound = i; + break; + } + } + } else { + dataRateBand = span->dataRates[dr]; + dataRateFound = dr; + } + + if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + datr->fsk.bitRate = 50; + datr->fsk.freqDev = 25; + + } else { + uint8_t bw = dataRateBand & 0x0C; + switch(bw) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + datr->lora.bandwidth = 125.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + datr->lora.bandwidth = 250.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + datr->lora.bandwidth = 500.0; + break; + default: + datr->lora.bandwidth = 125.0; + } + + datr->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; + datr->lora.codingRate = (dataRateBand & 0x03) + 5; + } + + return(dataRateFound); +} + +int16_t LoRaWANNode::findChannelId(uint8_t dir, uint8_t* ch, uint8_t* dr, int8_t min, int8_t max) { + // find the first channel span that supports the requested direction + uint8_t spanId = 0; + LoRaWANChannelSpan_t* span = NULL; + for(; spanId < this->band->numChannelSpans; spanId++) { + span = (LoRaWANChannelSpan_t*)&this->band->defaultChannels[spanId]; + if((span->direction == dir) || (span->direction == RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH)) { + break; + } + } + + // shouldn't happen, but just to be sure + if(!span) { + RADIOLIB_DEBUG_PRINTLN("findChannelId span not found"); + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + + // if requested, save the data rate + if(dr) { + *dr = span->joinRequestDataRate; + } + + // determine min and max based on number of channels in span and user constraints + uint8_t chMin = (min > 0) ? min : 0; + uint8_t chMax = (max > 0) ? max : span->numChannels; + + // select channel ID as random number between min and max (global number 0 - N for single direction) + int32_t chId = this->phyLayer->random(chMin, chMax); + *ch = chId; + return(RADIOLIB_ERR_NONE); +} + +LoRaWANChannelSpan_t* LoRaWANNode::findChannelSpan(uint8_t dir, uint8_t ch, uint8_t* spanChannelId) { + // find the span based on the channel ID + uint8_t chanCtr = 0; + *spanChannelId = 0; + for(uint8_t span = 0; span < this->band->numChannelSpans; span++) { + // check if this channel span can be used + uint8_t direction = this->band->defaultChannels[span].direction; + if((direction != dir) && (direction != RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH)) { + continue; + } + + // iterate over the usable spans to the channel ID + for(; *spanChannelId < this->band->defaultChannels[span].numChannels; (*spanChannelId)++) { + if(chanCtr >= ch) { + // we found it, return the pointer (channel ID within the span is already set) + return((LoRaWANChannelSpan_t*)&this->band->defaultChannels[span]); + } + chanCtr++; + } + } + + return(NULL); +} + +int16_t LoRaWANNode::findChannelFreq(uint8_t dir, uint8_t ch, float* freq) { + // find the channel span based on channel ID and direction + uint8_t spanChannelId = 0; + LoRaWANChannelSpan_t* span = findChannelSpan(dir, ch, &spanChannelId); + if(!span) { + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + + // set the frequency + *freq = span->freqStart + span->freqStep * (float)spanChannelId; + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::configureChannel(uint8_t dir) { + // set the frequency + RADIOLIB_DEBUG_PRINTLN("Channel frequency %cL = %f MHz", dir ? 'D' : 'U', this->channelFreq[dir]); + int state = this->phyLayer->setFrequency(this->channelFreq[dir]); + RADIOLIB_ASSERT(state); + + // find the channel span based on channel ID and direction + uint8_t spanChannelId = 0; + LoRaWANChannelSpan_t* span = findChannelSpan(dir, this->chIndex[dir], &spanChannelId); + if(!span) { + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + + // set the data rate + DataRate_t datr; + this->dataRate[dir] = findDataRate(this->dataRate[dir], &datr, span); + state = this->phyLayer->setDataRate(datr); + return(state); +} + int16_t LoRaWANNode::sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen) { // build the command size_t macReqLen = 1 + payloadLen; @@ -897,7 +1043,7 @@ int16_t LoRaWANNode::sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloa // build the reply buffer size_t macRplLen = 1 + replyLen; #if !defined(RADIOLIB_STATIC_ONLY) - uint8_t* macRplBuff = new uint8_t[this->band->payloadLenMax[this->dataRate]]; + uint8_t* macRplBuff = new uint8_t[this->band->payloadLenMax[this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; #else uint8_t macRplBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #endif @@ -912,7 +1058,8 @@ int16_t LoRaWANNode::sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloa return(state); } - //Module::hexdump(macRplBuff, rxRplLen); + RADIOLIB_DEBUG_PRINTLN("macRplBuff:"); + RADIOLIB_DEBUG_HEXDUMP(macRplBuff, rxRplLen); // check the length - it may be longer than expected // if the server decided to append more MAC commands, but never shorter @@ -1033,8 +1180,6 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); - //Module::hexdump(uplinkMsg, uplinkMsgLen); - // now encrypt the input // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext size_t remLen = len; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 7086b8aa1c..628ebf7924 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -44,17 +44,22 @@ #define RADIOLIB_LORAWAN_NOPTS_LEN (8) -// data rat encoding +// data rate encoding #define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps -#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRaWAN spreading factor: SF12 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 -#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 0) // 3 0 LoRaWAN bandwidth: 500 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 0) // 3 0 250 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 0) // 3 0 125 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 +#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 #define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate #define RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK (0x00 << 0) @@ -163,6 +168,9 @@ // the length of internal MAC command queue - hopefully this is enough for most use cases #define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8) +// the maximum number of simultaneously available channels +#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (8) + /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. @@ -270,6 +278,18 @@ class LoRaWANNode { /*! \brief Set to true to force the node to only use FSK channels. Set to false by default. */ bool FSK; + /*! \brief Starting channel offset. + Some band plans only support a subset of available channels. + Set to a positive value to set the first channel that will be used (e.g. 8 for US915 FSB2 used by TTN). + By default -1 (no channel offset). */ + int8_t startChannel; + + /*! \brief Number of supported channels. + Some band plans only support a subset of available channels. + Set to a positive value to set the number of channels that will be used + (e.g. 8 for US915 FSB2 used by TTN). By default -1 (no channel offset). */ + int8_t numChannels; + /*! \brief Default constructor. \param phy Pointer to the PhysicalLayer radio module. @@ -387,17 +407,21 @@ class LoRaWANNode { uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; - float availableChannelsFreq[5] = { 0 }; - uint16_t availableChannelsMask[6] = { 0 }; + + // available channel frequencies from list passed during OTA activation + float availableChannelsFreq[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } }; + + // currently configured channel frequency + float channelFreq[2] = { 0 }; // LoRaWAN revision (1.0 vs 1.1) uint8_t rev = 0; - // currently configured data rate DR0 - DR15 (band-dependent!) - uint8_t dataRate = 0; + // currently configured data rate for uplink and downlink: DR0 - DR15 (band-dependent!) + uint8_t dataRate[2] = { 0 }; - // currently configured channel (band-dependent!) - uint8_t chIndex = 0; + // currently configured channel for uplink and downlink (band-dependent!) + uint8_t chIndex[2] = { 0 }; // timestamp to measure the RX1/2 delay (from uplink end) uint32_t rxDelayStart = 0; @@ -408,17 +432,6 @@ class LoRaWANNode { // device status - battery level uint8_t battLevel = 0xFF; - // find the first usable data rate in a given channel span - void findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span); - - /*! - \brief Configure the radio to a given channel frequency and data rate. - \param chan Channel ID to set. - \param dr Data rate to set, DR0 - DR15. - \returns \ref status_codes - */ - int16_t configureChannel(uint8_t chan, uint8_t dr); - // method to generate message integrity code uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); @@ -426,9 +439,29 @@ class LoRaWANNode { // it assumes that the MIC is the last 4 bytes of the message bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); - // configure the physical layer properties (frequency, sync word etc.) + // configure the common physical layer properties (preamble, sync word etc.) + // channels must be configured separately by setupChannels()! int16_t setPhyProperties(); + // setup uplink/downlink channel data rates and frequencies + // will attempt to randomly select based on currently used band plan + int16_t setupChannels(); + + // find the first usable data rate in a given channel span + uint8_t findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span); + + // find a channel ID that conforms to the requested direction and ID range + int16_t findChannelId(uint8_t dir, uint8_t* ch, uint8_t* dr, int8_t min, int8_t max); + + // find a channel span that any given channel id belongs to + LoRaWANChannelSpan_t* findChannelSpan(uint8_t dir, uint8_t ch, uint8_t* spanChannelId); + + // calculate channel frequency in MHz based on channel ID and direction + int16_t findChannelFreq(uint8_t dir, uint8_t ch, float* freq); + + // configure channel based on cached data rate ID and frequency + int16_t configureChannel(uint8_t dir); + // send a MAC command to the network server int16_t sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen); diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index d51a508ce5..c25b0af9f5 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -29,13 +29,13 @@ const LoRaWANBand_t EU868 = { .freqStart = 868.1, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -57,7 +57,7 @@ const LoRaWANBand_t EU868 = { .freqStart = 869.858, .freqStep = 0, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -96,10 +96,10 @@ const LoRaWANBand_t US915 = { .freqStart = 902.3, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -124,7 +124,7 @@ const LoRaWANBand_t US915 = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -139,7 +139,7 @@ const LoRaWANBand_t US915 = { } }, { .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + .joinRequestDataRate = 10, .numChannels = 8, .freqStart = 923.3, .freqStep = 0.6, @@ -152,12 +152,12 @@ const LoRaWANBand_t US915 = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, } @@ -178,7 +178,7 @@ const LoRaWANBand_t US915 = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -209,13 +209,13 @@ const LoRaWANBand_t CN780 = { .freqStart = 779.5, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -237,7 +237,7 @@ const LoRaWANBand_t CN780 = { .freqStart = 786, .freqStep = 0, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -276,13 +276,13 @@ const LoRaWANBand_t EU433 = { .freqStart = 433.175, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -343,12 +343,12 @@ const LoRaWANBand_t AU915 = { .freqStart = 915.2, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -371,7 +371,7 @@ const LoRaWANBand_t AU915 = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -399,12 +399,12 @@ const LoRaWANBand_t AU915 = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, } @@ -425,7 +425,7 @@ const LoRaWANBand_t AU915 = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -456,12 +456,12 @@ const LoRaWANBand_t CN500 = { .freqStart = 470.3, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -480,12 +480,12 @@ const LoRaWANBand_t CN500 = { .freqStart = 500.3, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -507,7 +507,7 @@ const LoRaWANBand_t CN500 = { .freqStart = 505.3, .freqStep = 0, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -546,13 +546,13 @@ const LoRaWANBand_t AS923 = { .freqStart = 923.2, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -576,7 +576,7 @@ const LoRaWANBand_t AS923 = { .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -613,13 +613,13 @@ const LoRaWANBand_t KR920 = { .freqStart = 922.1, .freqStep = 0.2, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -641,7 +641,7 @@ const LoRaWANBand_t KR920 = { .freqStart = 921.9, .freqStep = 0, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -680,12 +680,12 @@ const LoRaWANBand_t IN865 = { .freqStart = 865.0625, .freqStep = 0.36, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -710,7 +710,7 @@ const LoRaWANBand_t IN865 = { .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, From a23d85c19609df568a182c75e93f67a423ec42a1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 13 Sep 2023 17:05:19 +0200 Subject: [PATCH 0748/1848] [LoRaWAN] Typo fixes --- src/protocols/LoRaWAN/LoRaWAN.cpp | 32 +++++++++++++++---------------- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0a20169aa9..fdc8661c72 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -403,7 +403,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); // TODO implement adaptive data rate - // foptslen will be added later + // length of fopts will be added later uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; // get frame counter from persistent storage @@ -588,9 +588,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { state = this->phyLayer->setFrequency(this->band->backupChannel.freqStart); RADIOLIB_ASSERT(state); - DataRate_t datr; - findDataRate(RADIOLIB_LORAWAN_DATA_RATE_UNUSED, &datr, &this->band->backupChannel); - state = this->phyLayer->setDataRate(datr); + DataRate_t dataRate; + findDataRate(RADIOLIB_LORAWAN_DATA_RATE_UNUSED, &dataRate, &this->band->backupChannel); + state = this->phyLayer->setDataRate(dataRate); RADIOLIB_ASSERT(state); } @@ -890,7 +890,7 @@ int16_t LoRaWANNode::setupChannels() { return(state); } -uint8_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span) { +uint8_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate, const LoRaWANChannelSpan_t* span) { uint8_t dataRateBand = 0; uint8_t dataRateFound = 0; if(dr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { @@ -907,27 +907,27 @@ uint8_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANCha } if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - datr->fsk.bitRate = 50; - datr->fsk.freqDev = 25; + dataRate->fsk.bitRate = 50; + dataRate->fsk.freqDev = 25; } else { uint8_t bw = dataRateBand & 0x0C; switch(bw) { case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - datr->lora.bandwidth = 125.0; + dataRate->lora.bandwidth = 125.0; break; case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - datr->lora.bandwidth = 250.0; + dataRate->lora.bandwidth = 250.0; break; case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - datr->lora.bandwidth = 500.0; + dataRate->lora.bandwidth = 500.0; break; default: - datr->lora.bandwidth = 125.0; + dataRate->lora.bandwidth = 125.0; } - datr->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; - datr->lora.codingRate = (dataRateBand & 0x03) + 5; + dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; + dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; } return(dataRateFound); @@ -1016,9 +1016,9 @@ int16_t LoRaWANNode::configureChannel(uint8_t dir) { } // set the data rate - DataRate_t datr; - this->dataRate[dir] = findDataRate(this->dataRate[dir], &datr, span); - state = this->phyLayer->setDataRate(datr); + DataRate_t dataRate; + this->dataRate[dir] = findDataRate(this->dataRate[dir], &dataRate, span); + state = this->phyLayer->setDataRate(dataRate); return(state); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 628ebf7924..b17bb7a30e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -448,7 +448,7 @@ class LoRaWANNode { int16_t setupChannels(); // find the first usable data rate in a given channel span - uint8_t findDataRate(uint8_t dr, DataRate_t* datr, const LoRaWANChannelSpan_t* span); + uint8_t findDataRate(uint8_t dr, DataRate_t* dataRate, const LoRaWANChannelSpan_t* span); // find a channel ID that conforms to the requested direction and ID range int16_t findChannelId(uint8_t dir, uint8_t* ch, uint8_t* dr, int8_t min, int8_t max); From 2638fd0ad05ab3d4ad2b1f426317ca069c4d0144 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 14 Sep 2023 20:58:04 +0200 Subject: [PATCH 0749/1848] [LoRaWAN] Fixed memory leak in downlink --- src/protocols/LoRaWAN/LoRaWAN.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index fdc8661c72..7d5b88e0c9 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -695,6 +695,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // check the MIC if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif return(RADIOLIB_ERR_CRC_MISMATCH); } @@ -702,6 +705,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { RADIOLIB_DEBUG_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -745,6 +751,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { if(payLen <= 0) { // no payload *len = 0; + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif return(RADIOLIB_ERR_NONE); } From 58eab402ad0a0b55a6890e891cbe63c4f8b72304 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 14 Sep 2023 20:58:46 +0200 Subject: [PATCH 0750/1848] [LoRaWAN] Implemented most MAC commands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 236 +++++++++++++++++++++++++++++- src/protocols/LoRaWAN/LoRaWAN.h | 34 +++-- 2 files changed, 248 insertions(+), 22 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7d5b88e0c9..679d76b695 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -32,6 +32,7 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->FSK = false; this->startChannel = -1; this->numChannels = -1; + this->backupFreq = this->band->backupChannel.freqStart; } void LoRaWANNode::wipe() { @@ -285,7 +286,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // enqueue the RekeyInd MAC command to be sent in the next uplink this->rev = 1; LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND, + .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY, .len = sizeof(uint8_t), .payload = { this->rev }, .repeat = RADIOLIB_LORAWAN_ADR_ACK_LIMIT, @@ -585,7 +586,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { } else if(i == 0) { // nothing in the first window, configure for the second - state = this->phyLayer->setFrequency(this->band->backupChannel.freqStart); + state = this->phyLayer->setFrequency(this->backupFreq); RADIOLIB_ASSERT(state); DataRate_t dataRate; @@ -1146,10 +1147,131 @@ int16_t LoRaWANNode::popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQu } size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { - //RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); + RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); + + if(cmd->cid >= RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY) { + // TODO call user-provided callback for proprietary MAC commands? + return(cmd->len - 1); + } switch(cmd->cid) { - case(RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS_ANS): { + case(RADIOLIB_LORAWAN_MAC_CMD_RESET): { + // get the server version + uint8_t srvVersion = cmd->payload[0]; + RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); + if(srvVersion == this->rev) { + // valid server version, stop sending the ResetInd MAC command + popMacCommand(NULL, &this->commandsUp, true); + } + return(1); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK): { + // TODO sent by gateway as reply to node request, how to get this info to the user? + uint8_t margin = cmd->payload[0]; + uint8_t gwCnt = cmd->payload[1]; + RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); + return(2); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR): { + // get the ADR configuration + uint8_t dr = (cmd->payload[0] & 0xF0) >> 4; + uint8_t txPower = cmd->payload[0] & 0x0F; + uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); + uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; + uint8_t nbTrans = cmd->payload[3] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", dr, txPower, chMask, chMaskCntl, nbTrans); + + // apply the configuration + uint8_t drAck = 0; + if(dr != 0x0F) { + // first figure out which channel span this data rate applies to + // TODO do that by processing the chMask/chMaskCntl? + uint8_t spanChannelId = 0; + LoRaWANChannelSpan_t* span = findChannelSpan(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &spanChannelId); + + // seems to be only applicable to uplink + if(span) { + DataRate_t dataRate; + this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = findDataRate(dr, &dataRate, span); + if(this->phyLayer->setDataRate(dataRate) == RADIOLIB_ERR_NONE) { + RADIOLIB_DEBUG_PRINTLN("ADR set dr = %d channel = %d", dr, spanChannelId); + drAck = 1; + } + } + + } else { + drAck = 1; + + } + + // try to apply the power configuration + uint8_t pwrAck = 0; + if(txPower != 0x0F) { + int8_t pwr = this->band->powerMax - 2*txPower; + if(this->phyLayer->setOutputPower(pwr) == RADIOLIB_ERR_NONE) { + RADIOLIB_DEBUG_PRINTLN("ADR set pwr = %d", pwr); + pwrAck = 1; + } + + } else { + pwrAck = 1; + } + + // TODO implement repeated uplinks with nbTrans + // TODO implement channel mask + uint8_t chMaskAck = 0; + + // send the reply + cmd->len = 1; + cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); + RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); + pushMacCommand(cmd, &this->commandsUp); + return(4); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE): { + uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); + + // TODO implement this + + return(1); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP): { + // get the configuration + uint8_t rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; + uint8_t rx2DataRate = cmd->payload[0] & 0x0F; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + float freq = (float)freqRaw/10000.0; + RADIOLIB_DEBUG_PRINTLN("RX Param: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", rx1DrOffset, rx2DataRate, freq); + + // apply the configuration + this->backupFreq = freq; + float prevFreq = this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; + uint8_t chanAck = 0; + if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { + chanAck = 1; + this->phyLayer->setFrequency(prevFreq); + } + + // TODO process the RX2 data rate + uint8_t rx2Ack = 0; + + // TODO process the data rate offset + uint8_t rx1OffsAck = 0; + + // send the reply + cmd->len = 1; + cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); + RADIOLIB_DEBUG_PRINTLN("Rx param ANS: status = 0x%02x", cmd->payload[0]); + pushMacCommand(cmd, &this->commandsUp); + return(4); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS): { // set the uplink reply cmd->len = 2; cmd->payload[1] = this->battLevel; @@ -1161,13 +1283,111 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(0); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND): { - // TODO verify the actual server version here + case(RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL): { + // get the configuration + uint8_t chIndex = cmd->payload[0]; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + float freq = (float)freqRaw/10000.0; + uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; + uint8_t minDr = cmd->payload[4] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); + + // TODO implement this + + return(5); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP): { + // get the configuration + uint8_t delay = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("RX timing: delay = %d sec", delay); + + // apply the configuration + if(delay == 0) { + delay = 1; + } + this->rxDelays[0] = delay * 1000; + this->rxDelays[1] = this->rxDelays[0] + 1000; + + // send the reply + cmd->len = 0; + + // TODO this should be sent repeatedly until the next downlink + pushMacCommand(cmd, &this->commandsUp); + + return(1); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP): { + uint8_t dlDwell = (cmd->payload[0] & 0x20) >> 5; + uint8_t ulDwell = (cmd->payload[0] & 0x10) >> 4; + uint8_t maxEirpRaw = cmd->payload[0] & 0x0F; + + // who the f came up with this ... + const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; + uint8_t maxEirp = eirpEncoding[maxEirpRaw]; + RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, dlDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, maxEirp); - // stop sending the ReKey MAC command - popMacCommand(NULL, &this->commandsUp, true); + // TODO implement this return(1); } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL): { + // get the configuration + uint8_t chIndex = cmd->payload[0]; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + float freq = (float)freqRaw/10000.0; + RADIOLIB_DEBUG_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); + + // TODO implement this + return(4); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_REKEY): { + // get the server version + uint8_t srvVersion = cmd->payload[0]; + RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); + if((srvVersion > 0) && (srvVersion <= this->rev)) { + // valid server version, stop sending the ReKey MAC command + popMacCommand(NULL, &this->commandsUp, true); + } + return(1); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP): { + // TODO implement this + uint8_t limitExp = (cmd->payload[0] & 0xF0) >> 4; + uint8_t delayExp = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", limitExp, delayExp); + return(1); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME): { + // TODO implement this - sent by gateway as reply to node request + uint32_t gpsEpoch = LoRaWANNode::ntoh(&cmd->payload[0]); + uint8_t fraction = cmd->payload[5]; + RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)fraction/256.0f); + return(5); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_FORCE_REJOIN): { + // TODO implement this + uint16_t rejoinReq = LoRaWANNode::ntoh(&cmd->payload[0]); + uint8_t period = (rejoinReq & 0x3800) >> 11; + uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; + uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; + uint8_t dr = rejoinReq & 0x000F; + RADIOLIB_DEBUG_PRINTLN("Force rejoin: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + return(2); + } break; + + case(RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP): { + // TODO implement this + uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; + uint8_t maxCount = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); + return(0); + } break; } return(0); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index b17bb7a30e..e0ec0af435 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -150,20 +150,22 @@ #define RADIOLIB_LORAWAN_MAGIC (0x12AD101B) // MAC commands -#define RADIOLIB_LORAWAN_MAC_CMD_RESET_IND (0x01) -#define RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK_REQ (0x02) -#define RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR_ANS (0x03) -#define RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE_ANS (0x04) -#define RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP_ANS (0x05) -#define RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS_ANS (0x06) -#define RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL_ANS (0x07) -#define RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP_ANS (0x08) -#define RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP_ANS (0x09) -#define RADIOLIB_LORAWAN_MAC_CMD_DI_CHANNEL_ANS (0x0A) -#define RADIOLIB_LORAWAN_MAC_CMD_REKEY_IND (0x0B) -#define RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP_ANS (0x0C) -#define RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME_REQ (0x0D) -#define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP_ANS (0x0F) +#define RADIOLIB_LORAWAN_MAC_CMD_RESET (0x01) +#define RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK (0x02) +#define RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR (0x03) +#define RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE (0x04) +#define RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP (0x05) +#define RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS (0x06) +#define RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL (0x07) +#define RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP (0x08) +#define RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP (0x09) +#define RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL (0x0A) +#define RADIOLIB_LORAWAN_MAC_CMD_REKEY (0x0B) +#define RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP (0x0C) +#define RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME (0x0D) +#define RADIOLIB_LORAWAN_MAC_CMD_FORCE_REJOIN (0x0E) +#define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP (0x0F) +#define RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY (0x80) // the length of internal MAC command queue - hopefully this is enough for most use cases #define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8) @@ -423,6 +425,10 @@ class LoRaWANNode { // currently configured channel for uplink and downlink (band-dependent!) uint8_t chIndex[2] = { 0 }; + // backup channel properties - may be changed by MAC command + float backupFreq = 0; + uint8_t backupDataRate = 0; + // timestamp to measure the RX1/2 delay (from uplink end) uint32_t rxDelayStart = 0; From 7de4a4693e69538994926c4b6460f92151e2ad5e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:10:47 +0200 Subject: [PATCH 0751/1848] [HAL] Disable EEPROM on Arduino Due --- src/ArduinoHal.cpp | 40 ++++++++++++++++++------------- src/BuildOpt.h | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++++ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 69b8d90df4..b1d4a92f43 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -2,7 +2,9 @@ #if defined(RADIOLIB_BUILD_ARDUINO) +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) #include +#endif ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {} @@ -101,27 +103,31 @@ void inline ArduinoHal::spiEnd() { } void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if defined(RADIOLIB_ESP32) - EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); - #endif - for(size_t i = 0; i < len; i++) { - buff[i] = EEPROM.read(addr + i); - } - #if defined(RADIOLIB_ESP32) - EEPROM.end(); + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + #if defined(RADIOLIB_ESP32) + EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); + #endif + for(size_t i = 0; i < len; i++) { + buff[i] = EEPROM.read(addr + i); + } + #if defined(RADIOLIB_ESP32) + EEPROM.end(); + #endif #endif } void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if defined(RADIOLIB_ESP32) - EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); - #endif - for(size_t i = 0; i < len; i++) { - EEPROM.write(addr + i, buff[i]); - } - #if defined(RADIOLIB_ESP32) - EEPROM.commit(); - EEPROM.end(); + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + #if defined(RADIOLIB_ESP32) + EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); + #endif + for(size_t i = 0; i < len; i++) { + EEPROM.write(addr + i, buff[i]); + } + #if defined(RADIOLIB_ESP32) + EEPROM.commit(); + EEPROM.end(); + #endif #endif } diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 82c777a181..22a1110ed4 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -117,6 +117,7 @@ // Arduino Due #define RADIOLIB_PLATFORM "Arduino Due" #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_EEPROM_UNSUPPORTED #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) // Adafruit nRF52 boards diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 679d76b695..56fe4ea075 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -7,6 +7,10 @@ // flag to indicate whether we have received a downlink static volatile bool downlinkReceived = false; +#if defined(RADIOLIB_EEPROM_UNSUPPORTED) + #warning "Persistent storage not supported!" +#endif + // interrupt service routine to handle downlinks automatically #if defined(ESP8266) || defined(ESP32) IRAM_ATTR From a4aace3ad03fd71feda200100301707dd49e7a7c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:13:26 +0200 Subject: [PATCH 0752/1848] Disable EEPROM on Nano 33 BLE and RP2040 --- src/BuildOpt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 22a1110ed4..85ececf19a 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -144,6 +144,7 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -176,6 +177,7 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED From 253dfd8c508a4e2f32c78ee60cb82f71d7cca7ef Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:31:31 +0200 Subject: [PATCH 0753/1848] [LoRaWAN] Temporarily cast unused variables until implemented --- src/protocols/LoRaWAN/LoRaWAN.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 56fe4ea075..0275b3c120 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1175,6 +1175,8 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t margin = cmd->payload[0]; uint8_t gwCnt = cmd->payload[1]; RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); + (void)margin; + (void)gwCnt; return(2); } break; @@ -1240,7 +1242,7 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); // TODO implement this - + (void)maxDutyCycle; return(1); } break; @@ -1297,7 +1299,10 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); // TODO implement this - + (void)chIndex; + (void)freq; + (void)maxDr; + (void)minDr; return(5); } break; @@ -1333,6 +1338,9 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, dlDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, maxEirp); // TODO implement this + (void)dlDwell; + (void)ulDwell; + (void)maxEirp; return(1); } break; @@ -1344,6 +1352,8 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); // TODO implement this + (void)chIndex; + (void)freq; return(4); } break; @@ -1363,14 +1373,18 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t limitExp = (cmd->payload[0] & 0xF0) >> 4; uint8_t delayExp = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", limitExp, delayExp); + (void)limitExp; + (void)delayExp; return(1); } break; case(RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME): { // TODO implement this - sent by gateway as reply to node request uint32_t gpsEpoch = LoRaWANNode::ntoh(&cmd->payload[0]); - uint8_t fraction = cmd->payload[5]; + uint8_t fraction = cmd->payload[4]; RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)fraction/256.0f); + (void)gpsEpoch; + (void)fraction; return(5); } break; @@ -1382,6 +1396,10 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; uint8_t dr = rejoinReq & 0x000F; RADIOLIB_DEBUG_PRINTLN("Force rejoin: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + (void)period; + (void)maxRetries; + (void)rejoinType; + (void)dr; return(2); } break; @@ -1390,6 +1408,8 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); + (void)maxTime; + (void)maxCount; return(0); } break; } From 4b80080a373a2d3dff9c25bef4da2109e9563176 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:31:53 +0200 Subject: [PATCH 0754/1848] Disable EEPROM on nRF52 and Portenta --- src/BuildOpt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 85ececf19a..0f4ca55d8e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -122,6 +122,7 @@ #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) // Adafruit nRF52 boards #define RADIOLIB_PLATFORM "Adafruit nRF52" + #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ARDUINO_ARC32_TOOLS) // Intel Curie @@ -156,6 +157,7 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED From 9279b8ab6d1761ba49ac8a257a99742046b384b4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:36:08 +0200 Subject: [PATCH 0755/1848] [LoRaWAN] Workaround unused variable warning for unimplemented fields --- src/protocols/LoRaWAN/LoRaWAN.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0275b3c120..d2a1860fb3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1226,8 +1226,11 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } // TODO implement repeated uplinks with nbTrans + (void)nbTrans; // TODO implement channel mask uint8_t chMaskAck = 0; + (void)chMask; + (void)chMaskCntl; // send the reply cmd->len = 1; @@ -1264,9 +1267,11 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } // TODO process the RX2 data rate + (void)rx2DataRate; uint8_t rx2Ack = 0; // TODO process the data rate offset + (void)rx1DrOffset; uint8_t rx1OffsAck = 0; // send the reply From a9c66e25f5909e62a681a4178a617b74ba08c355 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:42:21 +0200 Subject: [PATCH 0756/1848] [CI] Drop Arduino Leonardo --- .github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 599c5c9bf8..eeb1025ad5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,8 +50,6 @@ jobs: run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - - id: arduino:avr:leonardo - run: echo "skip-pattern=(STM32WL|SSTV|Pager)" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble - id: arduino:mbed:envie_m4 - id: arduino:megaavr:uno2018 From 1dec070c0e043f69881badf06cae16a096627b7e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 18:42:55 +0200 Subject: [PATCH 0757/1848] [CI] Remove Leonardo option --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index eeb1025ad5..512989e050 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,6 @@ on: - none - arduino:avr:uno - arduino:avr:mega - - arduino:avr:leonardo - arduino:mbed:nano33ble - arduino:mbed:envie_m4 - arduino:megaavr:uno2018 From bc7e82999c5c80a47a2a2e336d3db24d8246e5dc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Sep 2023 20:20:00 +0200 Subject: [PATCH 0758/1848] Disable EEPROM on SAMD --- src/BuildOpt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 0f4ca55d8e..4aeeb80f98 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -105,6 +105,7 @@ #elif defined(SAMD_SERIES) // Adafruit SAMD boards (M0 and M4) #define RADIOLIB_PLATFORM "Adafruit SAMD" + #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ARDUINO_ARCH_SAMD) // Arduino SAMD (Zero, MKR, etc.) @@ -112,6 +113,7 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(__SAM3X8E__) // Arduino Due From c13ab856703f4056cabcd8c2d65bb31bdcaa69b2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 16 Sep 2023 07:45:35 +0200 Subject: [PATCH 0759/1848] Added LoRaWAN to properties files --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index a12059531e..19a4120d0f 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "6.1.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", - "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", "repository": { diff --git a/library.properties b/library.properties index e2f70317b3..1429d3b1e1 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=6.1.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library -paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.). +paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). category=Communication url=https://github.com/jgromes/RadioLib architectures=* From d03d4c29eed59f24d6214bcd3e6c1cdb1065b5be Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 16 Sep 2023 07:45:52 +0200 Subject: [PATCH 0760/1848] Moved FAQ to Wiki --- README.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/README.md b/README.md index f33652be7d..6d2904bcd8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Universal wireless communication library for embedded devices -## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference. +## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) and [FAQ](https://github.com/jgromes/RadioLib/wiki/Frequently-Asked-Questions) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference. RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system. Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not! @@ -88,17 +88,3 @@ SX127x, RFM9x, SX126x and SX128x * [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstraction layer, which allows it to be easily ported even to non-Arduino environments. - -## Frequently Asked Questions - -### Where should I start? -First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. If something isn't working as expected, try searching the [issues](https://github.com/jgromes/RadioLib/issues/). - -### Does RadioLib require Arduino? -While RadioLib was originally written with Arduino in mind, it has since evolved and contains its own lightweight hardware abstraction layer. Thanks to this layer, RadioLib can be used on non-Arduino frameworks as well. See [this Wiki page](https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms) for details. - -### Help, my module isn't working! -The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new/choose) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently. - -### RadioLib doesn't support my module! What should I do? -Start by creating new issue (if it doesn't exist yet). If you have some experience with microcontrollers and C/C++ in general, you can try to add the support yourself! Use the template files in `/extras/` folder to get started. This is by far the fastest way to implement new modules into RadioLib, since I can't be working on everything all the time. If you don't trust your programming skills enough to have a go at it yourself, don't worry. I will try to implement all requested modules, but it will take me a while. From df8eeebb7209eeea5810ee15866ac99f1fe677aa Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 16 Sep 2023 08:20:25 +0200 Subject: [PATCH 0761/1848] Added debug info to compilation process --- src/RadioLib.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/RadioLib.h b/src/RadioLib.h index e3b9db4f3f..8eaa072a1b 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -51,6 +51,20 @@ #warning "God mode active, I hope it was intentional. Buckle up, lads." #endif +// print debug info +#if defined(RADIOLIB_DEBUG) + #define RADIOLIB_VALUE_TO_STRING(x) #x + #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) + #pragma message("\nRadioLib Debug Info\nVersion " \ + RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\n" \ + "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \ + "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) \ + ) +#endif + // check unknown/unsupported platform #if defined(RADIOLIB_UNKNOWN_PLATFORM) #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" From 690a050ebb46e6097c5d00c371e961c1caa3b52e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 16 Sep 2023 08:21:25 +0200 Subject: [PATCH 0762/1848] Bump version to 6.2.0 --- library.json | 4 ++-- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library.json b/library.json index 19a4120d0f..55a0bc467c 100644 --- a/library.json +++ b/library.json @@ -1,7 +1,7 @@ { "name": "RadioLib", - "version": "6.1.0", - "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).", + "version": "6.2.0", + "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", "repository": diff --git a/library.properties b/library.properties index 1429d3b1e1..1a4c6ebe03 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.1.0 +version=6.2.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4aeeb80f98..5fe2e0ba6f 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -506,7 +506,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR (0x06) -#define RADIOLIB_VERSION_MINOR (0x01) +#define RADIOLIB_VERSION_MINOR (0x02) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) From b65fb885260fe1c345f61433645e09b5752497fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 24 Sep 2023 18:17:32 +0200 Subject: [PATCH 0763/1848] [RFM9x] Use RFM9x only as alias for SX127x (#833) --- src/modules/RFM9x/RFM95.cpp | 93 ------------------------------------ src/modules/RFM9x/RFM95.h | 80 ------------------------------- src/modules/RFM9x/RFM96.cpp | 94 ------------------------------------- src/modules/RFM9x/RFM96.h | 88 ---------------------------------- src/modules/RFM9x/RFM97.cpp | 42 ----------------- src/modules/RFM9x/RFM97.h | 45 ------------------ src/modules/SX127x/SX1276.h | 6 +++ src/modules/SX127x/SX1277.h | 6 +++ src/modules/SX127x/SX1278.h | 6 +++ 9 files changed, 18 insertions(+), 442 deletions(-) delete mode 100644 src/modules/RFM9x/RFM95.cpp delete mode 100644 src/modules/RFM9x/RFM95.h delete mode 100644 src/modules/RFM9x/RFM96.cpp delete mode 100644 src/modules/RFM9x/RFM96.h delete mode 100644 src/modules/RFM9x/RFM97.cpp delete mode 100644 src/modules/RFM9x/RFM97.h diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp deleted file mode 100644 index 90f1bc46f1..0000000000 --- a/src/modules/RFM9x/RFM95.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "RFM95.h" -#if !defined(RADIOLIB_EXCLUDE_RFM9X) - -RFM95::RFM95(Module* mod) : SX1278(mod) { - -} - -int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { - // execute common part - int16_t state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); - if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { - // SX127X_REG_VERSION might be set 0x12 - state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); - RADIOLIB_ASSERT(state); - } else if(state != RADIOLIB_ERR_NONE) { - // some other error - return(state); - } - RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); - RADIOLIB_DEBUG_PRINTLN("M\tRFM95"); - - // configure publicly accessible settings - state = setBandwidth(bw); - RADIOLIB_ASSERT(state); - - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setSpreadingFactor(sf); - RADIOLIB_ASSERT(state); - - state = setCodingRate(cr); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); - - state = setGain(gain); - - return(state); -} - -int16_t RFM95::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { - // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, freqDev, rxBw, preambleLength, enableOOK); - if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { - // SX127X_REG_VERSION might be set 0x12 - state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, freqDev, rxBw, preambleLength, enableOOK); - RADIOLIB_ASSERT(state); - } else if(state != RADIOLIB_ERR_NONE) { - // some other error - return(state); - } - RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); - RADIOLIB_DEBUG_PRINTLN("M\tRFM95"); - - // configure settings not accessible by API - state = configFSK(); - RADIOLIB_ASSERT(state); - - // configure publicly accessible settings - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setBitRate(br); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); - - if(enableOOK) { - state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); - } else { - state = setDataShaping(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); - } - - return(state); -} - -int16_t RFM95::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 862.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); - - // set frequency and if successful, save the new setting - int16_t state = SX127x::setFrequencyRaw(freq); - if(state == RADIOLIB_ERR_NONE) { - SX127x::frequency = freq; - } - return(state); -} - -#endif diff --git a/src/modules/RFM9x/RFM95.h b/src/modules/RFM9x/RFM95.h deleted file mode 100644 index c0128003df..0000000000 --- a/src/modules/RFM9x/RFM95.h +++ /dev/null @@ -1,80 +0,0 @@ -#if !defined(_RADIOLIB_RFM95_H) -#define _RADIOLIB_RFM95_H - -#include "../../TypeDef.h" - -#if !defined(RADIOLIB_EXCLUDE_RFM9X) - -#include "../../Module.h" -#include "../SX127x/SX127x.h" -#include "../SX127x/SX1278.h" - -// SX127X_REG_VERSION -#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 -#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 - -/*! - \class RFM95 - \brief Derived class for %RFM95 modules. Overrides some methods from SX1278 due to different parameter ranges. -*/ -class RFM95: public SX1278 { - public: - - // constructor - - /*! - \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. - */ - RFM95(Module* mod); - - // basic methods - - /*! - \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 868.0 MHz to 915.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. - Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. - Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes - */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); - - /*! - \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. - Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes - */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); - - // configuration methods - - /*! - \brief Sets carrier frequency. Allowed values range from 868.0 MHz to 915.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes - */ - int16_t setFrequency(float freq); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - -}; - -#endif - -#endif diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp deleted file mode 100644 index 0c74418402..0000000000 --- a/src/modules/RFM9x/RFM96.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "RFM96.h" -#if !defined(RADIOLIB_EXCLUDE_RFM9X) - -RFM96::RFM96(Module* mod) : SX1278(mod) { - -} - -int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { - // execute common part - int16_t state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); - if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { - // SX127X_REG_VERSION might be set 0x12 - state = SX127x::begin(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); - RADIOLIB_ASSERT(state); - } else if(state != RADIOLIB_ERR_NONE) { - // some other error - return(state); - } - RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); - RADIOLIB_DEBUG_PRINTLN("M\tRFM96"); - - // configure publicly accessible settings - state = setBandwidth(bw); - RADIOLIB_ASSERT(state); - - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setSpreadingFactor(sf); - RADIOLIB_ASSERT(state); - - state = setCodingRate(cr); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); - - state = setGain(gain); - RADIOLIB_ASSERT(state); - - return(state); -} - -int16_t RFM96::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { - // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, freqDev, rxBw, preambleLength, enableOOK); - if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { - // SX127X_REG_VERSION might be set 0x12 - state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, freqDev, rxBw, preambleLength, enableOOK); - RADIOLIB_ASSERT(state); - } else if(state != RADIOLIB_ERR_NONE) { - // some other error - return(state); - } - RADIOLIB_DEBUG_PRINTLN("M\tSX1278"); - RADIOLIB_DEBUG_PRINTLN("M\tRFM96"); - - // configure settings not accessible by API - state = configFSK(); - RADIOLIB_ASSERT(state); - - // configure publicly accessible settings - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setBitRate(br); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); - - if(enableOOK) { - state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); - } else { - state = setDataShaping(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); - } - - return(state); -} - -int16_t RFM96::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 410.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY); - - // set frequency and if successful, save the new setting - int16_t state = SX127x::setFrequencyRaw(freq); - if(state == RADIOLIB_ERR_NONE) { - SX127x::frequency = freq; - } - return(state); -} - -#endif diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h deleted file mode 100644 index e599019784..0000000000 --- a/src/modules/RFM9x/RFM96.h +++ /dev/null @@ -1,88 +0,0 @@ -#if !defined(_RADIOLIB_RFM96_H) -#define _RADIOLIB_RFM96_H - -#include "../../TypeDef.h" - -#if !defined(RADIOLIB_EXCLUDE_RFM9X) - -#include "../../Module.h" -#include "../SX127x/SX127x.h" -#include "../SX127x/SX1278.h" - -// SX127X_REG_VERSION -#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11 -#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 - -/*! - \class RFM96 - \brief Derived class for %RFM96 modules. Overrides some methods from SX1278 due to different parameter ranges. -*/ -class RFM96: public SX1278 { - public: - - // constructor - - /*! - \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. - */ - RFM96(Module* mod); - - // basic methods - - /*! - \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 433.0 MHz to 470.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. - \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. - \param syncWord %LoRa sync word. Can be used to distinguish different networks. - Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols - longer than the set number. Allowed values range from 6 to 65535. - \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 - where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). - \returns \ref status_codes - */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); - - /*! - \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. - \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. - \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. - Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. - \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, - 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param preambleLength Length of FSK preamble in bits. - \param enableOOK Use OOK modulation instead of FSK. - \returns \ref status_codes - */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); - - // configuration methods - - /*! - \brief Sets carrier frequency. Allowed values range from 433.0 MHz to 470.0 MHz. - \param freq Carrier frequency to be set in MHz. - \returns \ref status_codes - */ - int16_t setFrequency(float freq); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - -}; - -/*! - \class RFM98 - \brief Only exists as alias for RFM96, since there seems to be no difference between %RFM96 and %RFM98 modules. -*/ -RADIOLIB_TYPE_ALIAS(RFM96, RFM98); - -#endif - -#endif diff --git a/src/modules/RFM9x/RFM97.cpp b/src/modules/RFM9x/RFM97.cpp deleted file mode 100644 index 0d02c70765..0000000000 --- a/src/modules/RFM9x/RFM97.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "RFM97.h" -#if !defined(RADIOLIB_EXCLUDE_RFM9X) - -RFM97::RFM97(Module* mod) : RFM95(mod) { - -}; - -int16_t RFM97::setSpreadingFactor(uint8_t sf) { - // check active modem - if(getActiveModem() != RADIOLIB_SX127X_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - uint8_t newSpreadingFactor; - - // check allowed spreading factor values - switch(sf) { - case 6: - newSpreadingFactor = RADIOLIB_SX127X_SF_6; - break; - case 7: - newSpreadingFactor = RADIOLIB_SX127X_SF_7; - break; - case 8: - newSpreadingFactor = RADIOLIB_SX127X_SF_8; - break; - case 9: - newSpreadingFactor = RADIOLIB_SX127X_SF_9; - break; - default: - return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - } - - // set spreading factor and if successful, save the new setting - int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor); - if(state == RADIOLIB_ERR_NONE) { - SX127x::spreadingFactor = sf; - } - return(state); -} - -#endif diff --git a/src/modules/RFM9x/RFM97.h b/src/modules/RFM9x/RFM97.h deleted file mode 100644 index b462349503..0000000000 --- a/src/modules/RFM9x/RFM97.h +++ /dev/null @@ -1,45 +0,0 @@ -#if !defined(_RADIOLIB_RFM97_H) -#define _RADIOLIB_RFM97_H - -#include "../../TypeDef.h" - -#if !defined(RADIOLIB_EXCLUDE_RFM9X) - -#include "../../Module.h" -#include "../SX127x/SX127x.h" -#include "../SX127x/SX1278.h" -#include "RFM95.h" - -/*! - \class RFM97 - \brief Derived class for %RFM97 modules. Overrides some methods from RFM95 due to different parameter ranges. -*/ -class RFM97: public RFM95 { - public: - - // constructor - - /*! - \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. - \param mod Instance of Module that will be used to communicate with the %LoRa chip. - */ - RFM97(Module* mod); - - // configuration methods - - /*! - \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. - \param sf %LoRa link spreading factor to be set. - \returns \ref status_codes - */ - int16_t setSpreadingFactor(uint8_t sf); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - -}; - -#endif - -#endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 0d83fb367d..659e22d788 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -69,6 +69,12 @@ class SX1276: public SX1278 { }; +/*! + \class RFM96 + \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM96 and %SX1276 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1276, RFM96); + #endif #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 88fb58fede..15804d6114 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -83,6 +83,12 @@ class SX1277: public SX1278 { }; +/*! + \class RFM97 + \brief Only exists as alias for SX1277, since there seems to be no difference between %RFM97 and %SX1277 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1277, RFM97); + #endif #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 92c996ed1f..a6db429786 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -299,6 +299,12 @@ class SX1278: public SX127x { }; +/*! + \class RFM98 + \brief Only exists as alias for SX1278, since there seems to be no difference between %RFM98 and %SX1278 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1278, RFM98); + #endif #endif From 10d225fadb6bcecea440788689330d66cee2fca2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 24 Sep 2023 18:19:19 +0200 Subject: [PATCH 0764/1848] [SX127x] Allow alternate chip versions --- src/modules/SX127x/SX1272.cpp | 6 ++++-- src/modules/SX127x/SX1273.cpp | 3 ++- src/modules/SX127x/SX1276.cpp | 6 ++++-- src/modules/SX127x/SX1277.cpp | 6 ++++-- src/modules/SX127x/SX1278.cpp | 6 ++++-- src/modules/SX127x/SX1278.h | 4 +++- src/modules/SX127x/SX1279.cpp | 6 ++++-- src/modules/SX127x/SX127x.cpp | 24 +++++++++++++++--------- src/modules/SX127x/SX127x.h | 12 +++++++----- 9 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index ac57210159..45bf8802b2 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -8,7 +8,8 @@ SX1272::SX1272(Module* mod) : SX127x(mod) { int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RADIOLIB_SX1272_CHIP_VERSION, syncWord, preambleLength); + uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; + int16_t state = SX127x::begin(&version, 1, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -39,7 +40,8 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1272_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); + uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; + int16_t state = SX127x::beginFSK(&version, 1, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 4b180694be..ea021c66e4 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -7,7 +7,8 @@ SX1273::SX1273(Module* mod) : SX1272(mod) { int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RADIOLIB_SX1272_CHIP_VERSION, syncWord, preambleLength); + uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; + int16_t state = SX127x::begin(&version, 1, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 21eadb5722..b20fd7d117 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -7,7 +7,8 @@ SX1276::SX1276(Module* mod) : SX1278(mod) { int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -38,7 +39,8 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index d466a385c5..5875bd9f71 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -7,7 +7,8 @@ SX1277::SX1277(Module* mod) : SX1278(mod) { int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -38,7 +39,8 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 9fb0c5df90..90325ff066 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -8,7 +8,8 @@ SX1278::SX1278(Module* mod) : SX127x(mod) { int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -39,7 +40,8 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index a6db429786..c9f966a2ad 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -67,7 +67,9 @@ #define RADIOLIB_SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop // SX127X_REG_VERSION -#define RADIOLIB_SX1278_CHIP_VERSION 0x12 +#define RADIOLIB_SX1278_CHIP_VERSION 0x12 // this is the "official" version listed in datasheet +#define RADIOLIB_SX1278_CHIP_VERSION_ALT 0x13 // appears sometimes +#define RADIOLIB_SX1278_CHIP_VERSION_RFM9X 0x11 // this value is used for the RFM9x // SX1278 FSK modem settings // SX127X_REG_PA_RAMP diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index ae79f0f84f..4fdd4daa97 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -7,7 +7,8 @@ SX1279::SX1279(Module* mod) : SX1278(mod) { int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -38,7 +39,8 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, freqDev, rxBw, preambleLength, enableOOK); + uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 1a8f2eaff9..7198e43259 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -10,14 +10,14 @@ Module* SX127x::getMod() { return(this->mod); } -int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength) { +int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) { // set module properties this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); // try to find the SX127x chip - if(!SX127x::findChip(chipVersion)) { + if(!SX127x::findChip(chipVersions, numVersions)) { RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); @@ -61,14 +61,14 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe return(state); } -int16_t SX127x::beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { +int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); // try to find the SX127x chip - if(!SX127x::findChip(chipVersion)) { + if(!SX127x::findChip(chipVersions, numVersions)) { RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); @@ -1473,7 +1473,7 @@ int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) { return(state); } -bool SX127x::findChip(uint8_t ver) { +bool SX127x::findChip(uint8_t* vers, uint8_t num) { uint8_t i = 0; bool flagFound = false; while((i < 10) && !flagFound) { @@ -1482,13 +1482,19 @@ bool SX127x::findChip(uint8_t ver) { // check version register int16_t version = getChipVersion(); - if(version == ver) { - flagFound = true; - } else { - RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X, expected 0x00%X", i + 1, version, ver); + for(uint8_t i = 0; i < num; i++) { + if(version == vers[i]) { + flagFound = true; + break; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version); this->mod->hal->delay(10); i++; } + } return(flagFound); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 9ef2890fba..9a622538f7 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -601,12 +601,13 @@ class SX127x: public PhysicalLayer { /*! \brief Initialization method. Will be called with appropriate parameters when calling initialization method from derived class. - \param chipVersion Value in SPI version register. Used to verify the connection and hardware version. + \param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version. + \param numVersions Number of possible chip versions. \param syncWord %LoRa sync word. \param preambleLength Length of %LoRa transmission preamble in symbols. \returns \ref status_codes */ - int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength); + int16_t begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength); /*! \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ. @@ -615,14 +616,15 @@ class SX127x: public PhysicalLayer { /*! \brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class. - \param chipVersion Value in SPI version register. Used to verify the connection and hardware version. + \param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version. + \param numVersions Number of possible chip versions. \param freqDev Frequency deviation of the FSK transmission in kHz. \param rxBw Receiver bandwidth in kHz. \param preambleLength Length of FSK preamble in bits. \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK. \returns \ref status_codes */ - int16_t beginFSK(uint8_t chipVersion, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); + int16_t beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -1211,7 +1213,7 @@ class SX127x: public PhysicalLayer { bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; - bool findChip(uint8_t ver); + bool findChip(uint8_t* vers, uint8_t num); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); void clearIRQFlags(); From b817819c60b1b2af6dcd69f678ce4dcaa41db1b0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 24 Sep 2023 18:19:48 +0200 Subject: [PATCH 0765/1848] [RM9x] Drop RFM9x as separate class --- src/BuildOpt.h | 1 - src/RadioLib.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5fe2e0ba6f..275539c690 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -68,7 +68,6 @@ //#define RADIOLIB_EXCLUDE_SI443X //#define RADIOLIB_EXCLUDE_RFM2X // dependent on RADIOLIB_EXCLUDE_SI443X //#define RADIOLIB_EXCLUDE_SX127X - //#define RADIOLIB_EXCLUDE_RFM9X // dependent on RADIOLIB_EXCLUDE_SX127X //#define RADIOLIB_EXCLUDE_SX126X //#define RADIOLIB_EXCLUDE_STM32WLX // dependent on RADIOLIB_EXCLUDE_SX126X //#define RADIOLIB_EXCLUDE_SX128X diff --git a/src/RadioLib.h b/src/RadioLib.h index 8eaa072a1b..ee7026d2fa 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -76,9 +76,6 @@ #include "modules/RF69/RF69.h" #include "modules/RFM2x/RFM22.h" #include "modules/RFM2x/RFM23.h" -#include "modules/RFM9x/RFM95.h" -#include "modules/RFM9x/RFM96.h" -#include "modules/RFM9x/RFM97.h" #include "modules/Si443x/Si4430.h" #include "modules/Si443x/Si4431.h" #include "modules/Si443x/Si4432.h" From 44bdf0dba422e24276b473de13bc138728f49c99 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 25 Sep 2023 06:42:15 +0200 Subject: [PATCH 0766/1848] [SX126x] Changed default whitening initial value for SX127x/LoRaWAN compatibility (#832) --- src/modules/SX126x/SX126x.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 5b18b969e7..21db66eb1f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -870,11 +870,11 @@ class SX126x: public PhysicalLayer { /*! \brief Sets FSK whitening parameters. \param enabled True = Whitening enabled - \param initial Initial value used for the whitening LFSR in FSK mode. Defaults to 0x0100, - use 0x01FF for SX127x compatibility. + \param initial Initial value used for the whitening LFSR in FSK mode. + By default set to 0x01FF for compatibility with SX127x and LoRaWAN. \returns \ref status_codes */ - int16_t setWhitening(bool enabled, uint16_t initial = 0x0100); + int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF); /*! \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration. @@ -1020,7 +1020,7 @@ class SX126x: public PhysicalLayer { #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) /*! - \brief Set interrupt service routine function to call when data bit is receveid in direct mode. + \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ void setDirectAction(void (*func)(void)); From d329c609063ec59040233e5c6dab63e4115bced2 Mon Sep 17 00:00:00 2001 From: BayCom GmbH Date: Fri, 29 Sep 2023 14:27:31 +0200 Subject: [PATCH 0767/1848] [SX127x] disable syncword generation & detection, add method to set preamble polarity (#834) * allow syncword to be disabled if length is 0 * add method to change preamble polarity in FSK mode * add new method 'setPreamblePolarity' * move RADIOLIB_SX127X_PREAMBLE_POLARITY_55 from ::config to ::begin & ::beginFSK * [SX127x] Remove FSK preamble config from LoRa init method * [SX127x] Rename preamble inversion method --------- Co-authored-by: BayCom GmbH Co-authored-by: jgromes --- keywords.txt | 1 + src/modules/SX127x/SX127x.cpp | 34 ++++++++++++++++++++++++++++++---- src/modules/SX127x/SX127x.h | 7 +++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/keywords.txt b/keywords.txt index 36bfb988f1..a7d5d12e6f 100644 --- a/keywords.txt +++ b/keywords.txt @@ -124,6 +124,7 @@ setSyncWord KEYWORD2 setOutputPower KEYWORD2 setCurrentLimit KEYWORD2 setPreambleLength KEYWORD2 +invertPreamble KEYWORD2 setGain KEYWORD2 getFrequencyError KEYWORD2 getRSSI KEYWORD2 diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7198e43259..38fb6979af 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -118,6 +118,10 @@ int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqD state = SX127x::setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); + // set preamble polarity + state = invertPreamble(false); + RADIOLIB_ASSERT(state); + // set default sync word uint8_t syncWord[] = {0x12, 0xAD}; state = setSyncWord(syncWord, 2); @@ -782,6 +786,25 @@ int16_t SX127x::setPreambleLength(size_t preambleLength) { return(RADIOLIB_ERR_UNKNOWN); } +int16_t SX127x::invertPreamble(bool enable) { + // set mode to standby + int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // check active modem + uint8_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // set preamble polarity + uint8_t polarity = enable ? RADIOLIB_SX127X_PREAMBLE_POLARITY_AA : RADIOLIB_SX127X_PREAMBLE_POLARITY_55; + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, polarity, 5, 5); + return(state); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + float SX127x::getFrequencyError(bool autoCorrect) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { @@ -999,6 +1022,13 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { // check active modem uint8_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { + + // disable sync word in case len is 0 + if(len == 0) { + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_OFF, 4, 4); + return(state); + } + RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD); // sync word must not contain value 0x00 @@ -1428,10 +1458,6 @@ int16_t SX127x::configFSK() { state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5); RADIOLIB_ASSERT(state); - // set preamble polarity - state =this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_PREAMBLE_POLARITY_55, 5, 5); - RADIOLIB_ASSERT(state); - // set FIFO threshold state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 9a622538f7..59fc29a511 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -878,6 +878,13 @@ class SX127x: public PhysicalLayer { */ int16_t setPreambleLength(size_t preambleLength) override; + /*! + \brief Invert FSK preamble polarity. The default (non-inverted) is 0x55, the inverted is 0xAA. + \param enable Preamble polarity in FSK mode - 0xAA when true, 0x55 when false. + \returns \ref status_codes + */ + int16_t invertPreamble(bool enable); + /*! \brief Gets frequency error of the latest received packet. \param autoCorrect When set to true, frequency will be automatically corrected. From 49a0a1cf44e19ddf7a84a02d309a212fb0e522b4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 9 Oct 2023 17:40:22 +0200 Subject: [PATCH 0768/1848] [CC1101] Added list of supported bandwidths (#842) --- src/modules/CC1101/CC1101.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index a13327e919..2e83d926e6 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -740,7 +740,8 @@ class CC1101: public PhysicalLayer { int16_t setBitRate(float br); /*! - \brief Sets receiver bandwidth. Allowed values range from 58.0 to 812.0 kHz. + \brief Sets receiver bandwidth. Allowed values are 58, 68, 81, 102, 116, 135, 162, + 203, 232, 270, 325, 406, 464, 541, 650 and 812 kHz. \param rxBw Receiver bandwidth to be set in kHz. \returns \ref status_codes */ From ddcce424c8d3fc8d54c00ec4cfabd5fd53e933a0 Mon Sep 17 00:00:00 2001 From: chemary Date: Wed, 11 Oct 2023 07:20:11 +0200 Subject: [PATCH 0769/1848] Incorrectly checking sx1280 command status (#843) --- src/modules/SX128x/SX128x.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index bdd2e0c215..3e26382e78 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1499,11 +1499,11 @@ int16_t SX128x::config(uint8_t modem) { } int16_t SX128x::SPIparseStatus(uint8_t in) { - if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) { + if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) { return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); - } else if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_ERROR) { + } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) { return(RADIOLIB_ERR_SPI_CMD_INVALID); - } else if((in & 0b00001110) == RADIOLIB_SX128X_STATUS_CMD_FAILED) { + } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED) { return(RADIOLIB_ERR_SPI_CMD_FAILED); } else if((in == 0x00) || (in == 0xFF)) { return(RADIOLIB_ERR_CHIP_NOT_FOUND); From 6e2685268921c47d1910d38369cf9d2445a8aa31 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Oct 2023 10:27:31 +0200 Subject: [PATCH 0770/1848] Fixed debug float print --- src/BuildOpt.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 275539c690..c764f4d0ab 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -455,6 +455,9 @@ #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) + + // some platforms do not support printf("%f"), so it has to be done this way + #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) #else #if !defined(RADIOLIB_DEBUG_PRINT) #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) @@ -462,11 +465,13 @@ #if !defined(RADIOLIB_DEBUG_PRINTLN) #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) #endif + #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PRINT("%.3f", VAL) #endif #define RADIOLIB_DEBUG_HEXDUMP(...) Module::hexdump(__VA_ARGS__) #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} + #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) {} #define RADIOLIB_DEBUG_HEXDUMP(...) {} #endif From 96f90c8ee00fb51b9fbb26be5e0066695c572f5d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Oct 2023 10:27:53 +0200 Subject: [PATCH 0771/1848] [Si443x] Fixed debug float print --- src/modules/Si443x/Si443x.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 62695fc4ff..2b2bf83585 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -770,7 +770,8 @@ int16_t Si443x::updateClockRecovery() { // print that whole mess RADIOLIB_DEBUG_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); - RADIOLIB_DEBUG_PRINTLN("%f\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr, rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); + RADIOLIB_DEBUG_PRINT_FLOAT(rxOsr, 2); + RADIOLIB_DEBUG_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); // update oversampling ratio int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); From f4f00537c619e299b8b00d7607b49e4f855d5c03 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Oct 2023 10:28:27 +0200 Subject: [PATCH 0772/1848] [LoRaWAN] Fixed debug float print (#844) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 32 +++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index d2a1860fb3..37abf74539 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -222,7 +222,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint32_t freq = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + 3*i], 3); availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = (float)freq/10000.0; availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", i, availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); + RADIOLIB_DEBUG_PRINT("Channel UL/DL %d frequency = ", i); + RADIOLIB_DEBUG_PRINT_FLOAT(availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i], 3); + RADIOLIB_DEBUG_PRINTLN(" MHz"); } } else { @@ -249,7 +251,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint8_t dir = this->band->defaultChannels[chSpan].direction; float freq = this->band->defaultChannels[chSpan].freqStart + chNum*this->band->defaultChannels[chSpan].freqStep; availableChannelsFreq[dir][channelId] = freq; - RADIOLIB_DEBUG_PRINTLN("Channel %cL %d frequency = %f MHz", dir ? 'U': 'D', channelId, availableChannelsFreq[dir][channelId]); + RADIOLIB_DEBUG_PRINT("Channel %cL %d frequency = ", dir ? 'U': 'D', channelId); + RADIOLIB_DEBUG_PRINT_FLOAT(availableChannelsFreq[dir][channelId], 3); + RADIOLIB_DEBUG_PRINTLN(" MHz"); channelId++; } @@ -1018,7 +1022,9 @@ int16_t LoRaWANNode::findChannelFreq(uint8_t dir, uint8_t ch, float* freq) { int16_t LoRaWANNode::configureChannel(uint8_t dir) { // set the frequency - RADIOLIB_DEBUG_PRINTLN("Channel frequency %cL = %f MHz", dir ? 'D' : 'U', this->channelFreq[dir]); + RADIOLIB_DEBUG_PRINT("Channel frequency %cL = ", dir ? 'D' : 'U'); + RADIOLIB_DEBUG_PRINT_FLOAT(this->channelFreq[dir], 3); + RADIOLIB_DEBUG_PRINTLN(" MHz"); int state = this->phyLayer->setFrequency(this->channelFreq[dir]); RADIOLIB_ASSERT(state); @@ -1254,14 +1260,14 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; uint8_t rx2DataRate = cmd->payload[0] & 0x0F; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); - float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINTLN("RX Param: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", rx1DrOffset, rx2DataRate, freq); - + RADIOLIB_DEBUG_PRINTLN("RX Param: rx1DrOffset = %d, rx2DataRate = %d, freq = %d", rx1DrOffset, rx2DataRate, freqRaw); + // apply the configuration - this->backupFreq = freq; + float freq = (float)freqRaw/10000.0; float prevFreq = this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; uint8_t chanAck = 0; if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { + this->backupFreq = freq; chanAck = 1; this->phyLayer->setFrequency(prevFreq); } @@ -1301,7 +1307,9 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { float freq = (float)freqRaw/10000.0; uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; uint8_t minDr = cmd->payload[4] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); + RADIOLIB_DEBUG_PRINT("New channel: index = %d, freq = ", chIndex); + RADIOLIB_DEBUG_PRINT_FLOAT(freq, 3); + RADIOLIB_DEBUG_PRINTLN(" MHz, maxDr = %d, minDr = %d", maxDr, minDr); // TODO implement this (void)chIndex; @@ -1354,7 +1362,9 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); + RADIOLIB_DEBUG_PRINT("DL channel: index = %d, freq = ", chIndex); + RADIOLIB_DEBUG_PRINT_FLOAT(freq, 3); + RADIOLIB_DEBUG_PRINTLN(" MHz"); // TODO implement this (void)chIndex; @@ -1387,7 +1397,9 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // TODO implement this - sent by gateway as reply to node request uint32_t gpsEpoch = LoRaWANNode::ntoh(&cmd->payload[0]); uint8_t fraction = cmd->payload[4]; - RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)fraction/256.0f); + RADIOLIB_DEBUG_PRINT("Network time: gpsEpoch = %d s, delayExp = ", gpsEpoch, (float)fraction/256.0f); + RADIOLIB_DEBUG_PRINT_FLOAT((float)fraction/256.0f, 2); + RADIOLIB_DEBUG_PRINTLN(); (void)gpsEpoch; (void)fraction; return(5); From 0d438910707ad0dd19de44bfb5473bceceaafb59 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Oct 2023 14:05:55 +0200 Subject: [PATCH 0773/1848] [STM32WLx] Added missing interrupt actions (#844) --- src/modules/SX126x/STM32WLx.cpp | 24 ++++++++++++++++++++++++ src/modules/SX126x/STM32WLx.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 095e13ecb1..f64b493369 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -126,4 +126,28 @@ void STM32WLx::clearDio1Action() { SubGhz.detachInterrupt(); } +void STM32WLx::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void STM32WLx::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void STM32WLx::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void STM32WLx::clearPacketSentAction() { + this->clearDio1Action(); +} + +void STM32WLx::setChannelScanAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void STM32WLx::clearChannelScanAction() { + this->clearDio1Action(); +} + #endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index aa96491727..cab2fc54ca 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -120,6 +120,39 @@ class STM32WLx : public SX1262 { */ void clearDio1Action(); + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Sets interrupt service routine to call when a channel scan is finished. + \param func ISR to call. + */ + void setChannelScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a channel scan is finished. + */ + void clearChannelScanAction(); + #if !defined(RADIOLIB_GODMODE) protected: #endif From 4e0ed033db37aba5fc91dc9b936a607202a124ad Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 15 Oct 2023 08:48:37 +0200 Subject: [PATCH 0774/1848] [HAL] Fixed persistent storage on Sparkfun Apollo (#848) --- src/ArduinoHal.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index b1d4a92f43..d585590b4f 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -106,6 +106,8 @@ void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) #if defined(RADIOLIB_ESP32) EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); + #elif defined(ARDUINO_ARCH_APOLLO3) + EEPROM.init(); #endif for(size_t i = 0; i < len; i++) { buff[i] = EEPROM.read(addr + i); @@ -120,6 +122,8 @@ void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) #if defined(RADIOLIB_ESP32) EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); + #elif defined(ARDUINO_ARCH_APOLLO3) + EEPROM.init(); #endif for(size_t i = 0; i < len; i++) { EEPROM.write(addr + i, buff[i]); From 46bf0445fa9ef7aa7457c2ebe81d09042f8f3749 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 Oct 2023 20:14:26 +0200 Subject: [PATCH 0775/1848] [SX126x] Decrease startup wait to 10 ms (#850) --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 7f739cf806..a312a01103 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -220,7 +220,7 @@ int16_t SX126x::reset(bool verify) { } // wait a bit to not spam the module - this->mod->hal->delay(100); + this->mod->hal->delay(10); } } From eabc7527032b0889917edac0ded83dad8a9921e3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Oct 2023 17:47:09 +0200 Subject: [PATCH 0776/1848] [APRS] Fix array length calculation in static only mode --- src/protocols/APRS/APRS.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 780dddf4d5..3458272ea5 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -35,14 +35,14 @@ int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { } int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg, char* time) { + size_t len = 1 + strlen(lat) + 1 + strlen(lon); + if(msg != NULL) { + len += 1 + strlen(msg); + } + if(time != NULL) { + len += strlen(time); + } #if !defined(RADIOLIB_STATIC_ONLY) - size_t len = 1 + strlen(lat) + 1 + strlen(lon); - if(msg != NULL) { - len += 1 + strlen(msg); - } - if(time != NULL) { - len += strlen(time); - } char* info = new char[len + 1]; #else char info[RADIOLIB_STATIC_ARRAY_SIZE]; From f1f3336e5995b4c76e059c9f84b1ff94c13c2998 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 20 Oct 2023 19:37:44 +0200 Subject: [PATCH 0777/1848] [SX126x] Make setPaConfig public (#852) --- keywords.txt | 1 + src/modules/SX126x/SX126x.h | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/keywords.txt b/keywords.txt index a7d5d12e6f..73568a89f4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -222,6 +222,7 @@ spectralScanStart KEYWORD2 spectralScanAbort KEYWORD2 spectralScanGetStatus KEYWORD2 spectralScanGetResult KEYWORD2 +setPaConfig KEYWORD2 # nRF24 setIrqAction KEYWORD2 diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 21db66eb1f..13efeadd6d 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1070,6 +1070,19 @@ class SX126x: public PhysicalLayer { */ int16_t spectralScanGetResult(uint16_t* results); + /*! + \brief Set the PA configuration. Allows user to optimize PA for a specific output power + and matching network. Any calls to this method must be done after calling begin/beginFSK and/or setOutputPower. + WARNING: Use at your own risk! Setting invalid values can and will lead to permanent damage! + \param paDutyCycle PA duty cycle raw value. + \param deviceSel Device select, usually RADIOLIB_SX126X_PA_CONFIG_SX1261, + RADIOLIB_SX126X_PA_CONFIG_SX1262 or RADIOLIB_SX126X_PA_CONFIG_SX1268. + \param hpMax hpMax raw value. + \param paLut paLut PA lookup table raw value. + \returns \ref status_codes + */ + int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); + #if !defined(RADIOLIB_GODMODE) protected: #endif From 29c891e01784c147bd9110baec81becf8c534604 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 20 Oct 2023 19:45:50 +0200 Subject: [PATCH 0778/1848] [SX126x] Fixed duplicate setPaConfig --- src/modules/SX126x/SX126x.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 13efeadd6d..30900802bf 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1091,7 +1091,6 @@ class SX126x: public PhysicalLayer { int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); - int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); From 556f37f608a3208430814e52fd4249463e90d61e Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:50:16 +0200 Subject: [PATCH 0779/1848] [LoRaWAN] Implement full session persistence & more v1.1 specification (#835) * Implement session persistence & more 1.1 protocol * [LoRaW] Improve session persistence, check frame counters & Nonces, multiple MAC commands * [LoRaWAN] fix popping MAC command from queue I just realized that the method popMacCommand did not correctly remove items from the queue - this should solve the problem * [LoRaWAN] implement improvements from #835 * [LoRaWAN] String --> uint8_t[] * [LoRaWAN] Fix typo --- keywords.txt | 8 +- src/BuildOpt.h | 2 +- src/Hal.h | 48 +++- src/TypeDef.h | 20 ++ src/protocols/LoRaWAN/LoRaWAN.cpp | 386 +++++++++++++++++++++++++----- src/protocols/LoRaWAN/LoRaWAN.h | 22 +- 6 files changed, 404 insertions(+), 82 deletions(-) diff --git a/keywords.txt b/keywords.txt index 73568a89f4..4cd39fb45a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -291,8 +291,9 @@ setModem KEYWORD2 # LoRaWAN wipe KEYWORD2 +restoreOTAA KEYWORD2 beginOTAA KEYWORD2 -beginAPB KEYWORD2 +beginABP KEYWORD2 uplink KEYWORD2 downlink KEYWORD2 configureChannel KEYWORD2 @@ -401,5 +402,10 @@ RADIOLIB_ERR_INVALID_PORT LITERAL1 RADIOLIB_ERR_NO_RX_WINDOW LITERAL1 RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 RADIOLIB_ERR_INVALID_CID LITERAL1 +RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_EMPTY LITERAL1 +RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 +RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 +RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 \ No newline at end of file diff --git a/src/BuildOpt.h b/src/BuildOpt.h index c764f4d0ab..324a7fbefd 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -442,7 +442,7 @@ // the amount of space allocated to the persistent storage #if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x60) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0xD0) #endif // This only compiles on STM32 boards with SUBGHZ module, but also diff --git a/src/Hal.h b/src/Hal.h index 6fa800b14a..9d89811f30 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -7,25 +7,47 @@ #include "BuildOpt.h" // list of persistent parameters -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (0) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (1) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (2) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (3) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (4) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (5) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (6) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (7) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (2) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (3) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (4) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (5) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (6) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (7) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (8) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (9) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID (10) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID (11) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID (12) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (13) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (14) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (15) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID (16) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_ID (17) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (18) static const uint32_t RadioLibPersistentParamTable[] = { - 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID - 0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID - 0x08, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID - 0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID + 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION + 0x08, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID + 0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID 0x10, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID 0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID 0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID 0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID - 0x50, // end + 0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID + 0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID + 0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID + 0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID + 0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST + 0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID + 0x74, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 0x78, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID + 0x7C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID + 0x80, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID + 0x84, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_ID + 0x88, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID + 0xD0, // end }; /*! diff --git a/src/TypeDef.h b/src/TypeDef.h index 11b3f7f6c4..0ebcbbb176 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -533,6 +533,26 @@ */ #define RADIOLIB_ERR_COMMAND_QUEUE_EMPTY (-1110) +/*! + \brief Unable to delete MAC command because it was not found in the queue. +*/ +#define RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND (-1111) + +/*! + \brief Unable to join network because JoinNonce is not higher than saved value. +*/ +#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1112) + +/*! + \brief Received downlink Network frame counter is invalid (lower than last heard value). +*/ +#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1113) + +/*! + \brief Received downlink Application frame counter is invalid (lower than last heard value). +*/ +#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114) + /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 37abf74539..b903343c3c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -44,7 +44,7 @@ void LoRaWANNode::wipe() { mod->hal->wipePersistentStorage(); } -int16_t LoRaWANNode::begin() { +int16_t LoRaWANNode::restoreOTAA() { int16_t state = this->setPhyProperties(); RADIOLIB_ASSERT(state); @@ -55,12 +55,99 @@ int16_t LoRaWANNode::begin() { return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } + // in case of future revisions of NVM, use a version parameter to allow transitioning from one version to another while keeping session alive + uint16_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID); + // if (RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION > nvm_table_version) { + // // set default values for variables that are new or something + // } + (void)nvm_table_version; + // pull all needed information from persistent storage this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + RADIOLIB_DEBUG_PRINTLN("appSKey:"); + RADIOLIB_DEBUG_HEXDUMP(this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + + uint32_t dlSettings = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID); + this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; + uint8_t rx1DrOffset = (dlSettings & 0x70) >> 4; + uint8_t rx2DataRate = dlSettings & 0x0F; + RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: %d", this->rev); + + // TODO process the RX2 data rate + (void)rx2DataRate; + + // TODO process the data rate offset + (void)rx1DrOffset; + + // parse Rx1 delay (and subsequently Rx2) + this->rxDelays[0] = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID); + if(this->rxDelays[0] == 0) { + this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; + } + this->rxDelays[1] = this->rxDelays[0] + 1000; + + // process CFlist if any bit is non-zero + uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; + uint8_t allZero[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID), cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); + RADIOLIB_DEBUG_PRINTLN("cfList:"); + RADIOLIB_DEBUG_HEXDUMP(cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); + if(memcmp(cfList, allZero, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { + if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { + // list of frequencies + for(uint8_t i = 0; i < 5; i++) { + uint32_t freq = LoRaWANNode::ntoh(&cfList[3*i], 3); + availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = (float)freq/10000.0; + availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", i, availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); + } + + } else { + // frequency mask, we need to find out which frequencies are actually being used + uint8_t channelId = 0; + uint8_t chSpan = 0; + uint8_t chNum = 0; + for(uint8_t i = 0; i < 5; i++) { + uint16_t mask = LoRaWANNode::ntoh(&cfList[2*i]); + RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", i, mask); + for(uint8_t j = 0; j < 16; j++) { + if(chNum >= this->band->defaultChannels[chSpan].numChannels) { + chNum -= this->band->defaultChannels[chSpan].numChannels; + chSpan++; + + if(chSpan >= this->band->numChannelSpans) { + RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); + return(RADIOLIB_ERR_UNKNOWN); + } + } + + if(mask & (1UL << j)) { + RADIOLIB_DEBUG_PRINTLN("chNum = %d, chSpan = %d", chNum, chSpan); + uint8_t dir = this->band->defaultChannels[chSpan].direction; + float freq = this->band->defaultChannels[chSpan].freqStart + chNum*this->band->defaultChannels[chSpan].freqStep; + availableChannelsFreq[dir][channelId] = freq; + RADIOLIB_DEBUG_PRINTLN("Channel %cL %d frequency = %f MHz", dir ? 'U': 'D', channelId, availableChannelsFreq[dir][channelId]); + channelId++; + } + + chNum++; + } + } + + } + } + + uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + + state = this->setupChannels(); + RADIOLIB_ASSERT(state); + return(RADIOLIB_ERR_NONE); } @@ -69,7 +156,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe Module* mod = this->phyLayer->getMod(); if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { // the device has joined already, we can just pull the data from persistent storage - return(this->begin()); + return(this->restoreOTAA()); } // set the physical layer configuration @@ -175,9 +262,23 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RADIOLIB_DEBUG_PRINTLN("joinAcceptMsg:"); RADIOLIB_DEBUG_HEXDUMP(joinAcceptMsg, lenRx); + // get current JoinNonce from downlink and previous JoinNonce from NVM + uint32_t joinNonce = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + uint32_t joinNoncePrev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID); + RADIOLIB_DEBUG_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", joinNoncePrev, joinNonce); + + // JoinNonce received must be greater than the last JoinNonce heard, else error + if(joinNonce <= joinNoncePrev) { + return(RADIOLIB_ERR_JOIN_NONCE_INVALID); + } + // check LoRaWAN revision (the MIC verification depends on this) uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; - if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { + this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; + RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: 1.%d", this->rev); + + // verify MIC + if(this->rev == 1) { // 1.1 version, first we need to derive the join accept integrity key uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY; @@ -203,11 +304,20 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } } + uint8_t rx1DrOffset = (dlSettings & 0x70) >> 4; + uint8_t rx2DataRate = dlSettings & 0x0F; + + // TODO process the RX2 data rate + (void)rx2DataRate; - // parse the contents - uint32_t joinNonce = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + // TODO process the data rate offset + (void)rx1DrOffset; + + // parse other contents uint32_t homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); + + // parse Rx1 delay (and subsequently Rx2) this->rxDelays[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]*1000; if(this->rxDelays[0] == 0) { this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; @@ -215,7 +325,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->rxDelays[1] = this->rxDelays[0] + 1000; // process CFlist if present + uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { + memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { // list of frequencies for(uint8_t i = 0; i < 5; i++) { @@ -262,15 +374,14 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } } - - } + } // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); // check protocol version (1.0 vs 1.1) - if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { + if(this->rev == 1) { // 1.1 version, derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonce); @@ -292,7 +403,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); // enqueue the RekeyInd MAC command to be sent in the next uplink - this->rev = 1; LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY, .len = sizeof(uint8_t), @@ -304,7 +414,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } else { // 1.0 version, just derive the keys - this->rev = 0; LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3); LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; @@ -329,13 +438,27 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + // save uplink parameters + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID, joinNonce); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID, homeNetId); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID, this->rxDelays[0]); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID, (uint32_t)dlSettings); + + // save cfList (all 0 if none is present) + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID), cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); + // all complete, reset device counters and set the magic number mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, 0); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID, 0); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID, 0); mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); + + // everything written to NVM, write current version to NVM + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION); return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey) { +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey) { this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); @@ -355,7 +478,13 @@ int16_t LoRaWANNode::beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, // setup uplink/downlink frequencies and datarates state = this->setupChannels(); - return(state); + RADIOLIB_ASSERT(state); + + // everything written to NVM, write current version to NVM + Module* mod = this->phyLayer->getMod(); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION); + + return(RADIOLIB_ERR_NONE); } #if defined(RADIOLIB_BUILD_ARDUINO) @@ -373,12 +502,24 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { if(port > 0xDF) { return(RADIOLIB_ERR_INVALID_PORT); } + // port 0 is only allowed for MAC-only payloads + if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if (!isMACPayload) { + return(RADIOLIB_ERR_INVALID_PORT); + } + // if this is MAC only payload, continue and reset for next uplink + isMACPayload = false; + } + + Module* mod = this->phyLayer->getMod(); - // check if there are some MAC commands to piggyback - size_t foptsLen = 0; - if(this->commandsUp.numCommands > 0) { + // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) + uint8_t foptsLen = 0; + size_t foptsBufSize = 0; + if(this->commandsUp.numCommands > 0 && port != RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { // there are, assume the maximum possible FOpts len for buffer allocation - foptsLen = 15; + foptsLen = this->commandsUp.len; + foptsBufSize = 15; } // check maximum payload len as defined in phy @@ -392,7 +533,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { RADIOLIB_ASSERT(state); // check if sufficient time has elapsed since the last uplink - Module* mod = this->phyLayer->getMod(); if(mod->hal->millis() - this->rxDelayStart < rxDelays[1]) { // not enough time elapsed since the last uplink, we may still be in an RX window return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); @@ -400,7 +540,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); + size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsBufSize); #if defined(RADIOLIB_STATIC_ONLY) uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -420,22 +560,37 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, fcnt); LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)fcnt); - // check if we have some MAC command to append - // TODO implement appending multiple MAC commands - LoRaWANMacCommand_t cmd = { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, }; - if(popMacCommand(&cmd, &this->commandsUp) == RADIOLIB_ERR_NONE) { - // we do, add it to fopts - uint8_t foptsBuff[RADIOLIB_AES128_BLOCK_SIZE]; - foptsBuff[0] = cmd.cid; - for(size_t i = 1; i < cmd.len; i++) { - foptsBuff[i] = cmd.payload[i]; + // check if we have some MAC commands to append + if(foptsLen > 0) { + uint8_t foptsNum = this->commandsUp.numCommands; + uint8_t foptsBuff[foptsBufSize]; + size_t idx = 0; + for (size_t i = 0; i < foptsNum; i++) { + LoRaWANMacCommand_t cmd = { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, }; + popMacCommand(&cmd, &this->commandsUp, i); + if (cmd.cid == 0) { + break; + } + foptsBuff[idx] = cmd.cid; + for(size_t i = 1; i < cmd.len; i++) { + foptsBuff[idx + i] = cmd.payload[i]; + } + idx += cmd.len + 1; } - foptsLen = 1 + cmd.len; + + RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", foptsNum); + RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); + uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= foptsLen; // encrypt it processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + + // write the current MAC command queue to nvm for next uplink + uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)]; + memcpy(&queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); } // set the port @@ -448,6 +603,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { } // encrypt the frame payload + // TODO check ctrId --> erratum says it should be 0x01? processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation @@ -685,23 +841,63 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { if(state == RADIOLIB_ERR_LORA_HEADER_DAMAGED) { state = RADIOLIB_ERR_NONE; } + + if(state != RADIOLIB_ERR_NONE) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif + return(state); + } // get the frame counter and set it to the MIC calculation block - // TODO this will not handle overflow into 32-bits! // TODO cache the ADR bit? - uint16_t fcnt = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); - + uint16_t fcnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16); + uint32_t fcnt32 = fcnt16; // calculate possible rollover once decided if this is network downlink or application downlink + RADIOLIB_DEBUG_PRINTLN("downlinkMsg:"); RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); - - if(state != RADIOLIB_ERR_NONE) { + + // calculate length of FOpts and payload + uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); + + bool isAppDownlink = true; + if (payLen <= 0 && this->rev == 1) { // no payload => MAC commands only => Network frame (LoRaWAN v1.1 only) + isAppDownlink = false; + } + + // check the FcntDown value (Network or Application) + uint32_t fcntDownPrev = 0; + if (isAppDownlink) { + fcntDownPrev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID); + } else { + fcntDownPrev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID); + } + + // assume a 16-bit to 32-bit rollover when difference in LSB is smaller than MAX_FCNT_GAP + // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error + if ((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { #if !defined(RADIOLIB_STATIC_ONLY) delete[] downlinkMsg; #endif - return(state); + if (isAppDownlink) { + return(RADIOLIB_ERR_A_FCNT_DOWN_INVALID); + } else { + return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID); + } + } else if (fcnt16 <= fcntDownPrev) { + uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover + fcnt32 |= (msb << 16); // add back the MSB part } + // save current fcnt to NVM + if (isAppDownlink) { + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID, fcnt32); + } else { + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID, fcnt32); + } + // check the MIC if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { #if !defined(RADIOLIB_STATIC_ONLY) @@ -720,15 +916,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } - // check fopts len - uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + // process FOpts (if there are any) if(foptsLen > 0) { // there are some Fopts, decrypt them uint8_t fopts[RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK]; - // according to the specification, the last two arguments should be 0x00 and false, - // but that will fail even for LoRaWAN 1.1.0 server - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x01, true); + // TODO it COULD be the case that the assumed rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 + uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); RADIOLIB_DEBUG_PRINTLN("fopts:"); RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); @@ -753,23 +948,59 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { remLen -= processedLen; foptsPtr += processedLen; } + + // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink + if(this->commandsUp.len > 15) { + uint8_t foptsNum = this->commandsUp.numCommands; + size_t foptsBufSize = this->commandsUp.len; + uint8_t foptsBuff[foptsBufSize]; + size_t idx = 0; + for(size_t i = 0; i < foptsNum; i++) { + LoRaWANMacCommand_t cmd = { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, }; + popMacCommand(&cmd, &this->commandsUp, i); + if(cmd.cid == 0) { + break; + } + foptsBuff[idx] = cmd.cid; + for(size_t i = 1; i < cmd.len; i++) { + foptsBuff[idx + i] = cmd.payload[i]; + } + idx += cmd.len + 1; + } + RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", foptsNum); + RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); + + isMACPayload = true; + this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + uint8_t strDown[this->band->payloadLenMax[this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; + size_t lenDown = 0; + state = this->downlink(strDown, &lenDown); + RADIOLIB_ASSERT(state); + } + + // write the MAC command queue to nvm for next uplink + uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)]; + memcpy(&queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); } - // fopts are processed or not present, check if there is payload - int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); + // process payload (if there is any) if(payLen <= 0) { // no payload *len = 0; #if !defined(RADIOLIB_STATIC_ONLY) delete[] downlinkMsg; #endif + return(RADIOLIB_ERR_NONE); } // there is payload, and so there should be a port too // TODO pass the port? *len = payLen - 1; - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], downlinkMsgLen, this->appSKey, data, fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 + // TODO does the erratum hold here as well? + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], downlinkMsgLen, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !defined(RADIOLIB_STATIC_ONLY) delete[] downlinkMsg; @@ -1124,38 +1355,69 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ queue->commands[queue->numCommands - 1].payload[4], queue->commands[queue->numCommands - 1].repeat);*/ queue->numCommands++; + queue->len += 1 + cmd->len; // 1 byte for command ID, len bytes for payload return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, bool force) { +int16_t LoRaWANNode::popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, size_t index) { if(queue->numCommands == 0) { return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); } if(cmd) { - /*RADIOLIB_DEBUG_PRINTLN("pop MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", - queue->commands[queue->numCommands - 1].cid, - queue->commands[queue->numCommands - 1].len, - queue->commands[queue->numCommands - 1].payload[0], - queue->commands[queue->numCommands - 1].payload[1], - queue->commands[queue->numCommands - 1].payload[2], - queue->commands[queue->numCommands - 1].payload[3], - queue->commands[queue->numCommands - 1].payload[4], - queue->commands[queue->numCommands - 1].repeat);*/ - memcpy(cmd, &queue->commands[queue->numCommands - 1], sizeof(LoRaWANMacCommand_t)); - } - - if((!force) && (queue->commands[queue->numCommands - 1].repeat > 0)) { - queue->commands[queue->numCommands - 1].repeat--; + // RADIOLIB_DEBUG_PRINTLN("pop MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", + // queue->commands[index].cid, + // queue->commands[index].len, + // queue->commands[index].payload[0], + // queue->commands[index].payload[1], + // queue->commands[index].payload[2], + // queue->commands[index].payload[3], + // queue->commands[index].payload[4], + // queue->commands[index].repeat); + memcpy(cmd, &queue->commands[index], sizeof(LoRaWANMacCommand_t)); + } + + if(queue->commands[index].repeat > 0) { + queue->commands[index].repeat--; } else { - queue->commands[queue->numCommands - 1].repeat = 0; - queue->numCommands--; + deleteMacCommand(queue->commands[index].cid, queue); } return(RADIOLIB_ERR_NONE); } +int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue) { + if(queue->numCommands == 0) { + return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); + } + + for(size_t index = 0; index < queue->numCommands; index++) { + if(queue->commands[index].cid == cid) { + // RADIOLIB_DEBUG_PRINTLN("delete MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", + // queue->commands[index].cid, + // queue->commands[index].len, + // queue->commands[index].payload[0], + // queue->commands[index].payload[1], + // queue->commands[index].payload[2], + // queue->commands[index].payload[3], + // queue->commands[index].payload[4], + // queue->commands[index].repeat); + queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload + // move all subsequent commands one forward in the queue + if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { + memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index) * sizeof(LoRaWANMacCommand_t)); + } + // set the latest element to all 0 + memset(&queue->commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); + queue->numCommands--; + return(RADIOLIB_ERR_NONE); + } + } + + return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); +} + size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); @@ -1171,7 +1433,7 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command - popMacCommand(NULL, &this->commandsUp, true); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_RESET, &this->commandsUp); } return(1); } break; @@ -1378,7 +1640,7 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command - popMacCommand(NULL, &this->commandsUp, true); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_REKEY, &this->commandsUp); } return(1); } break; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index e0ec0af435..65efe7eb20 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -5,6 +5,9 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../../utils/Cryptography.h" +// version of NVM table layout (NOT the LoRaWAN version) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION (0x01) + // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) #define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) @@ -257,7 +260,7 @@ struct LoRaWANMacCommand_t { uint8_t cid; /*! \brief Length of the payload */ - size_t len; + uint8_t len; /*! \brief Payload buffer (5 bytes is the longest possible) */ uint8_t payload[5]; @@ -269,6 +272,7 @@ struct LoRaWANMacCommand_t { struct LoRaWANMacCommandQueue_t { LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; size_t numCommands; + size_t len; }; /*! @@ -306,10 +310,10 @@ class LoRaWANNode { void wipe(); /*! - \brief Join network by loading information from persistent storage. + \brief Restore OTAA session by loading information from persistent storage. \returns \ref status_codes */ - int16_t begin(); + int16_t restoreOTAA(); /*! \brief Join network by performing over-the-air activation. By this procedure, @@ -333,7 +337,7 @@ class LoRaWANNode { \param sNwkSIntKey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0. \returns \ref status_codes */ - int16_t beginAPB(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL); + int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL); #if defined(RADIOLIB_BUILD_ARDUINO) /*! @@ -395,10 +399,12 @@ class LoRaWANNode { LoRaWANMacCommandQueue_t commandsUp = { .commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } }, .numCommands = 0, + .len = 0, }; LoRaWANMacCommandQueue_t commandsDown = { .commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } }, .numCommands = 0, + .len = 0, }; // the following is either provided by the network server (OTAA) @@ -438,6 +444,9 @@ class LoRaWANNode { // device status - battery level uint8_t battLevel = 0xFF; + // indicates whether an uplink has MAC commands as payload + bool isMACPayload = false; + // method to generate message integrity code uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); @@ -475,7 +484,10 @@ class LoRaWANNode { int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); // pop MAC command from queue, done by copy unless CMD is NULL - int16_t popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, bool force = false); + int16_t popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, size_t index); + + // delete a specific MAC command from queue, indicated by the command ID + int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue); // execute mac command, return the number of processed bytes for sequential processing size_t execMacCommand(LoRaWANMacCommand_t* cmd); From 039fa0fc59af9e367ea8c4b8429466f297f7d7ce Mon Sep 17 00:00:00 2001 From: Lewis He Date: Sun, 29 Oct 2023 01:41:51 +0800 Subject: [PATCH 0780/1848] Update api adapt esp core 3.0.0-alpha2 (#860) --- src/ArduinoHal.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index d585590b4f..f2ed4f8c58 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -145,10 +145,16 @@ void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long // ESP32 tone() emulation (void)duration; if(prev == -1) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0) ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); +#endif } if(prev != frequency) { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0) ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); +#else + ledcWriteTone(pin, frequency); +#endif } prev = frequency; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) @@ -178,8 +184,13 @@ void inline ArduinoHal::noTone(uint32_t pin) { return; } // ESP32 tone() emulation +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0) ledcDetachPin(pin); ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); +#else + ledcDetach(pin); + ledcWrite(pin, 0); +#endif prev = -1; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) if(pin == RADIOLIB_NC) { From 912333c408b107623c46a75c0b2e56ceeb543f29 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 Oct 2023 21:54:31 +0200 Subject: [PATCH 0781/1848] [HAL] Added check for defined ESP version macro (#860) --- src/ArduinoHal.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index f2ed4f8c58..322a690649 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -145,16 +145,16 @@ void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long // ESP32 tone() emulation (void)duration; if(prev == -1) { -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0) + #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); -#endif + #endif } if(prev != frequency) { -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0) + #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency); -#else + #else ledcWriteTone(pin, frequency); -#endif + #endif } prev = frequency; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) @@ -184,13 +184,13 @@ void inline ArduinoHal::noTone(uint32_t pin) { return; } // ESP32 tone() emulation -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0) + #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) ledcDetachPin(pin); ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); -#else + #else ledcDetach(pin); ledcWrite(pin, 0); -#endif + #endif prev = -1; #elif defined(RADIOLIB_MBED_TONE_OVERRIDE) if(pin == RADIOLIB_NC) { From aca1d78a9742e17947eaf5cddb63a10f10e3fafe Mon Sep 17 00:00:00 2001 From: Amalinda Gamage <5582466+jgamage91@users.noreply.github.com> Date: Sun, 29 Oct 2023 21:19:00 +0800 Subject: [PATCH 0782/1848] added functionality for LoRa Alliance TR-13 Enabling CSMA for LoRaWAN (#859) * added functionality for LoRa Alliance TR-13 Enabling CSMA for LoRaWAN * Addressed feedback on CSMA implementation * symbolNumValues[6] array no longer needed as we will utilize only two symbol CAD operations for all SFs. --- src/modules/SX126x/SX126x.cpp | 43 ++++++++++++++------ src/protocols/LoRaWAN/LoRaWAN.cpp | 66 ++++++++++++++++++++++++++++++- src/protocols/LoRaWAN/LoRaWAN.h | 25 ++++++++++++ 3 files changed, 120 insertions(+), 14 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index a312a01103..7c6f8baac5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1702,27 +1702,41 @@ int16_t SX126x::setRx(uint32_t timeout) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } + int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { - // default CAD parameters for assigned SF as per Semtech AN1200.48, Rev 2.1, Page 50 - uint8_t detPeakValues[8] = { 22, 22, 22, 22, 23, 24, 25, 28}; - uint8_t symbolNumValues[8] = { RADIOLIB_SX126X_CAD_ON_2_SYMB, - RADIOLIB_SX126X_CAD_ON_2_SYMB, - RADIOLIB_SX126X_CAD_ON_2_SYMB, - RADIOLIB_SX126X_CAD_ON_2_SYMB, - RADIOLIB_SX126X_CAD_ON_4_SYMB, - RADIOLIB_SX126X_CAD_ON_4_SYMB, - RADIOLIB_SX126X_CAD_ON_4_SYMB, - RADIOLIB_SX126X_CAD_ON_4_SYMB }; + // default CAD parameters are shown in Semtech AN1200.48, page 41. + uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30}; + + // CAD parameters aren't available for SF-6. Just to be safe. + if(this->spreadingFactor < 7) { + this->spreadingFactor = 7; + } else if(this->spreadingFactor > 12) { + this->spreadingFactor = 12; + } + // build the packet uint8_t data[7]; - data[0] = symbolNumValues[this->spreadingFactor - 5]; - data[1] = detPeakValues[this->spreadingFactor - 5]; + data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; + data[1] = detPeakValues[this->spreadingFactor - 7]; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[4] = 0x00; data[5] = 0x00; data[6] = 0x00; + + /* + CAD Configuration Note: + The default CAD configuration applied by `scanChannel` overrides the optimal SF-specific configurations, leading to suboptimal detection. + I.e., anything that is not RADIOLIB_SX126X_CAD_PARAM_DEFAULT is overridden. But CAD settings are SF specific. + To address this, the user override has been commented out, ensuring consistent application of the optimal CAD settings as + per Semtech's Application Note AN1200.48 (page 41) for the 125KHz setting. This approach significantly reduces false CAD occurrences. + Testing has shown that there is no reason for a user to change CAD settings for anything other than most optimal ones described in AN1200.48 . + However, this change deos not respect CAD configs from the LoRaWAN layer. Future considerations or use cases might require revisiting this decision. + Hence this note. +*/ + +/* // set user-provided values if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { data[0] = symbolNum; @@ -1736,6 +1750,9 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { data[2] = detMin; } +*/ + + // configure parameters int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); RADIOLIB_ASSERT(state); @@ -2030,7 +2047,7 @@ int16_t SX126x::config(uint8_t modem) { state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); - // set some CAD parameters - will be overwritten whel calling CAD anyway + // set some CAD parameters - will be overwritten when calling CAD anyway data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; data[1] = this->spreadingFactor + 13; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b903343c3c..30ffe5ee10 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -37,6 +37,10 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->startChannel = -1; this->numChannels = -1; this->backupFreq = this->band->backupChannel.freqStart; + this->difsSlots = 2; + this->backoffMax = 6; + this->enableCSMA = false; + } void LoRaWANNode::wipe() { @@ -44,6 +48,13 @@ void LoRaWANNode::wipe() { mod->hal->wipePersistentStorage(); } +void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { + this->backoffMax = backoffMax; + this->difsSlots = difsSlots; + this->enableCSMA = enableCSMA; +} + + int16_t LoRaWANNode::restoreOTAA() { int16_t state = this->setPhyProperties(); RADIOLIB_ASSERT(state); @@ -637,6 +648,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } + // perform CSMA if enabled. + if (enableCSMA) { + performCSMA(); + } + RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -1762,4 +1778,52 @@ void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { } } -#endif +// The following function enables LMAC, a CSMA scheme for LoRa as specified +// in the LoRa Alliance Technical Recommendation #13. +// A user may enable CSMA to provide frames an additional layer of protection from interference. +// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma +void LoRaWANNode::performCSMA() { + + // Compute initial random back-off. + // When BO is reduced to zero, the function returns and the frame is transmitted. + uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1); + + while (BO > 0) { + // DIFS: Check channel for DIFS_slots + bool channelFreeDuringDIFS = true; + for (uint8_t i = 0; i < this->difsSlots; i++) { + if (performCAD()) { + RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); + channelFreeDuringDIFS = false; + // Channel is occupied during DIFS, hop to another. + this->setupChannels(); + break; + } + } + + // Start reducing BO counter if DIFS slot was free. + if (channelFreeDuringDIFS) { + // Continue decrementing BO with per each CAD reporting free channel. + while (BO > 0) { + if (performCAD()) { + RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO"); + // Channel is busy during CAD, hop to another and return to DIFS state again. + this->setupChannels(); + break; // Exit loop. Go back to DIFS state. + } + BO--; // Decrement BO by one if channel is free + } + } + } +} + +bool LoRaWANNode::performCAD() { + int16_t state = this->phyLayer->scanChannel(); + + if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { + return true; // Channel is busy + } + return false; // Channel is free +} + +#endif \ No newline at end of file diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 65efe7eb20..82b081277a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -296,6 +296,17 @@ class LoRaWANNode { (e.g. 8 for US915 FSB2 used by TTN). By default -1 (no channel offset). */ int8_t numChannels; + /*! \brief Num of Back Off(BO) slots to be decremented after DIFS phase. 0 to disable BO. + A random BO avoids collisions in the case where two or more nodes start the CSMA + process at the same time. */ + uint8_t backoffMax; + + /*! \brief Num of CADs to estimate a clear CH. */ + uint8_t difsSlots; + + /*! \brief enable/disable CSMA for LoRaWAN. */ + bool enableCSMA; + /*! \brief Default constructor. \param phy Pointer to the PhysicalLayer radio module. @@ -309,6 +320,14 @@ class LoRaWANNode { */ void wipe(); + /*! + \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. + \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. + \param difsSlots Num of CADs to estimate a clear CH. + \param enableCSMA enable/disable CSMA for LoRaWAN. + */ + void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); + /*! \brief Restore OTAA session by loading information from persistent storage. \returns \ref status_codes @@ -502,6 +521,12 @@ class LoRaWANNode { // host-to-network conversion method - takes data from host variable and and converts it to network packet endians template static void hton(uint8_t* buff, T val, size_t size = 0); + + // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. + bool performCAD(); + + // Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013). + void performCSMA(); }; #endif From f691b11c38a7160dc31ceb8b2fc3f4bb27da1296 Mon Sep 17 00:00:00 2001 From: Nico Maas Date: Sat, 4 Nov 2023 16:09:13 +0100 Subject: [PATCH 0783/1848] Fixed Persistent Storage Issue for RP2040 with Arduino Pico Framework (#868) RP2040 does not have an EEPROM but always uses the last 4K chunk of the flash for a software EEPROM - if used. It is exactly handled as ESP32 "SoftEEPROMs", meaning it does copy the "flashEEPROM" to memory on .begin(); and does need to commit(); to write it back. We saw in the past that a node could successfully get an OTAA on an RP2040, but could never join - due to the missing commit and wrong init, this was the reason. As the "SoftEEPROM" is always written at the end of the flash, it also survives an Arduino Sketch reflash if not wiped afterwards by node.wipe(); More info and documentation here: https://arduino-pico.readthedocs.io/en/latest/eeprom.html --- src/ArduinoHal.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 322a690649..86a58f9013 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -104,7 +104,7 @@ void inline ArduinoHal::spiEnd() { void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - #if defined(RADIOLIB_ESP32) + #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); #elif defined(ARDUINO_ARCH_APOLLO3) EEPROM.init(); @@ -112,7 +112,7 @@ void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) for(size_t i = 0; i < len; i++) { buff[i] = EEPROM.read(addr + i); } - #if defined(RADIOLIB_ESP32) + #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) EEPROM.end(); #endif #endif @@ -120,7 +120,7 @@ void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - #if defined(RADIOLIB_ESP32) + #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); #elif defined(ARDUINO_ARCH_APOLLO3) EEPROM.init(); @@ -128,7 +128,7 @@ void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len for(size_t i = 0; i < len; i++) { EEPROM.write(addr + i, buff[i]); } - #if defined(RADIOLIB_ESP32) + #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) EEPROM.commit(); EEPROM.end(); #endif From d262732554e2d1266d543182ac1be62a8e3bcc3e Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Nov 2023 07:13:02 +0100 Subject: [PATCH 0784/1848] [RFM9x] Added missing alias for RFM95 --- src/modules/SX127x/SX1276.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 659e22d788..aaf2cc4bb7 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -69,6 +69,12 @@ class SX1276: public SX1278 { }; +/*! + \class RFM95 + \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM95 and %SX1276 modules. +*/ +RADIOLIB_TYPE_ALIAS(SX1276, RFM95); + /*! \class RFM96 \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM96 and %SX1276 modules. From 82258105b798bc3e2a57a3de42d8a44e370f16a1 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sun, 12 Nov 2023 14:02:39 +0100 Subject: [PATCH 0785/1848] [LoRaWAN] Rework bands, official Rx windows, support ADR, confirm frames, improve EEPROM handling, support clock drift (#867) * [LoRaWAN] rework bands, add ADR, partial MAC support Known problem: terribly bad at receiving downlinks Mask-list bands (e.g. US915) untested, likely a few bugs * [LoRaWAN] Change Rx windows from CAD to RxSingle * [LoRaWAN] improve persistence, better Rx windows, wear leveling, confirmed frames * [LoRaWAN] Module-independent (OTAA) Rx windows, fix confirming downlinks * [LoRaWAN] Implement SX127x support, fix MAC uplinking, support clock drift * [ArduinoHal] fix clock drift calculation * [LoRaWAN] Improve band & ADR logic, allow setting ADR, DR, subband, update examples * [LoRaWAN] Fix EU868 coding rate, improve example * [LoRaWAN] fix unused channel index * [LoRaWAN] fix merge issue (deleted line) * [LoRaWAN] fix CSMA calling now incorrect function * [LoRaWAN] fix include logic * [LoRaWAN] fix warnings, remove duplicate function * [LoRaWAN] improve examples, add unified sendReceive, bugfixes, add FSK * [LoRaWAN] improve examples * [LoRaWAN] add new keywords, add debug guard * [SX127x] Updated startReceive interface to be more in line with SX126x * [SX127x] Added public method to convert from bytes to symbols * [LoRaWAN] Update start receive for SX127x * Added note about LoRaWAN beta * [SX127x] Fixed potential float overflow --------- Co-authored-by: jgromes --- README.md | 3 +- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 72 +- .../LoRaWAN_End_Device_ABP.ino | 79 +- .../LoRaWAN_End_Device_persistent.ino | 145 ++ .../LoRaWAN_End_Device_reference.ino | 216 ++ keywords.txt | 15 +- src/ArduinoHal.cpp | 16 + src/BuildOpt.h | 14 +- src/Hal.cpp | 10 +- src/Hal.h | 83 +- src/TypeDef.h | 5 + src/modules/SX126x/SX126x.cpp | 19 + src/modules/SX126x/SX126x.h | 25 +- src/modules/SX127x/SX127x.cpp | 83 +- src/modules/SX127x/SX127x.h | 36 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 2052 ++++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 372 ++- src/protocols/LoRaWAN/LoRaWANBands.cpp | 1004 +++----- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 17 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 23 +- 20 files changed, 2539 insertions(+), 1750 deletions(-) create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino diff --git a/README.md b/README.md index 6d2904bcd8..dbe288bc78 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules: -SX127x, RFM9x, SX126x and SX128x +SX127x, RFM9x, SX126x and SX128x + * NOTE: LoRaWAN support is currently in beta, feedback via [Issues](https://github.com/jgromes/RadioLib/issues) and [Discussions](https://github.com/jgromes/RadioLib/discussions) is appreciated! ### Supported Arduino platforms: * __Arduino__ diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index 63dfe2bf89..b5eaaf8c95 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -7,14 +7,12 @@ After your device is registered, you can run this example. The device will join the network and start uploading data. - NOTE: LoRaWAN requires storing some parameters persistently! - RadioLib does this by using EEPROM, by default - starting at address 0 and using 32 bytes. - If you already use EEPROM in your application, - you will have to either avoid this range, or change it - by setting a different start address by changing the value of - RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either - during build or in src/BuildOpt.h. + LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + Please refer to the 'persistent' example once you are familiar + with LoRaWAN. + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -53,13 +51,6 @@ void setup() { while(true); } - // first we need to initialize the device storage - // this will reset all persistently stored parameters - // NOTE: This should only be done once prior to first joining a network! - // After wiping persistent storage, you will also have to reset - // the end device in TTN and perform the join procedure again! - //node.wipe(); - // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI // when adding new end device in TTN, you will have to enter this number // you can pick any number you want, but it has to be unique @@ -87,17 +78,23 @@ void setup() { // and can be set to NULL // some frequency bands only use a subset of the available channels - // you can set the starting channel and their number - // for example, the following corresponds to US915 FSB2 in TTN + // you can select the specific band or set the first channel and last channel + // for example, either of the following corresponds to US915 FSB2 in TTN /* - node.startChannel = 8; - node.numChannels = 8; + node.selectSubband(2); + node.selectSubband(8, 15); */ // now we can start the activation - // this can take up to 20 seconds, and requires a LoRaWAN gateway in range + // this can take up to 10 seconds, and requires a LoRaWAN gateway in range + // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): + /* + uint8_t joinDr = 4; + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); + */ Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -106,20 +103,6 @@ void setup() { while(true); } - // after the device has been activated, - // network can be rejoined after device power cycle - // by calling "begin" - /* - Serial.print(F("[LoRaWAN] Resuming previous session ... ")); - state = node.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - */ } // counter to keep track of transmitted packets @@ -129,23 +112,10 @@ void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); String strUp = "Hello World! #" + String(count++); - int state = node.uplink(strUp, 10); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // after uplink, you can call downlink(), - // to receive any possible reply from the server - // this function must be called within a few seconds - // after uplink to receive the downlink! - Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); String strDown; - state = node.downlink(strDown); + int state = node.sendReceive(strUp, 10, strDown); if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); + Serial.println(F("received a downlink!")); // print data of the packet (if there are any) Serial.print(F("[LoRaWAN] Data:\t\t")); @@ -171,7 +141,7 @@ void loop() { Serial.println(F(" Hz")); } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("timeout!")); + Serial.println(F("no downlink!")); } else { Serial.print(F("failed, code ")); @@ -179,5 +149,5 @@ void loop() { } // wait before sending another packet - delay(10000); + delay(30000); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index 2f1d4f184a..05198f5ffd 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -8,15 +8,13 @@ The device will start uploading data directly, without having to join the network. - NOTE: LoRaWAN requires storing some parameters persistently! - RadioLib does this by using EEPROM, by default - starting at address 0 and using 32 bytes. - If you already use EEPROM in your application, - you will have to either avoid this range, or change it - by setting a different start address by changing the value of - RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either - during build or in src/BuildOpt.h. - + LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + Please refer to the 'persistent' example once you are familiar + with LoRaWAN. + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -54,13 +52,6 @@ void setup() { while(true); } - // first we need to initialize the device storage - // this will reset all persistently stored parameters - // NOTE: This should only be done once prior to first joining a network! - // After wiping persistent storage, you will also have to reset - // the end device in TTN! - //node.wipe(); - // device address - this number can be anything // when adding new end device in TTN, you can generate this number, // or you can set any value you want, provided it is unique @@ -83,16 +74,27 @@ void setup() { // and can be set to NULL // some frequency bands only use a subset of the available channels - // you can set the starting channel and their number - // for example, the following corresponds to US915 FSB2 in TTN + // you can select the specific band or set the first channel and last channel + // for example, either of the following corresponds to US915 FSB2 in TTN + /* + node.selectSubband(2); + node.selectSubband(8, 15); + */ + + // if using EU868 on ABP in TTN, you need to set the SF for RX2 window manually + /* + node.rx2.drMax = 3; + */ + + // to start a LoRaWAN v1.1 session, the user should also provide + // fNwkSIntKey and sNwkSIntKey similar to nwkSKey and appSKey /* - node.startChannel = 8; - node.numChannels = 8; + state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey); */ // start the device by directly providing the encryption keys and device address Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginAPB(devAddr, (uint8_t*)nwkSKey, (uint8_t*)appSKey); + state = node.beginABP(devAddr, nwkSKey, appSKey); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -101,20 +103,6 @@ void setup() { while(true); } - // after the device has been activated, - // network can be rejoined after device power cycle - // by calling "begin" - /* - Serial.print(F("[LoRaWAN] Resuming previous session ... ")); - state = node.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - */ } // counter to keep track of transmitted packets @@ -124,23 +112,10 @@ void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); String strUp = "Hello World! #" + String(count++); - int state = node.uplink(strUp, 10); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // after uplink, you can call downlink(), - // to receive any possible reply from the server - // this function must be called within a few seconds - // after uplink to receive the downlink! - Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); String strDown; - state = node.downlink(strDown); + int state = node.sendReceive(strUp, 10, strDown); if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); + Serial.println(F("received a downlink!")); // print data of the packet (if there are any) Serial.print(F("[LoRaWAN] Data:\t\t")); @@ -166,7 +141,7 @@ void loop() { Serial.println(F(" Hz")); } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("timeout!")); + Serial.println(F("no downlink!")); } else { Serial.print(F("failed, code ")); @@ -174,5 +149,5 @@ void loop() { } // wait before sending another packet - delay(10000); + delay(30000); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino new file mode 100644 index 0000000000..43275a7ca9 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino @@ -0,0 +1,145 @@ +/* + RadioLib LoRaWAN End Device Example + + This example assumes you have tried one of the OTAA or ABP + examples and are familiar with the required keys and procedures. + This example restores and saves a session such that you can use + deepsleep or survive power cycles. Before you start, you will + have to register your device at https://www.thethingsnetwork.org/ + and join the network using either OTAA or ABP. + Please refer to one of the other examples for more + information regarding joining a network. + + NOTE: LoRaWAN requires storing some parameters persistently! + RadioLib does this by using EEPROM, by default + starting at address 0 and using 384 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // first we need to initialize the device storage + // this will reset all persistently stored parameters + // NOTE: This should only be done once prior to first joining a network! + // After wiping persistent storage, you will also have to reset + // the end device in TTN and perform the join procedure again! + // Here, a delay is added to make sure that during re-flashing + // the .wipe() is not triggered and the session is lost + //delay(5000); + //node.wipe(); + + // now we can start the activation + // Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + // uint64_t joinEUI = 0x12AD1011B0C0FFEE; + // uint64_t devEUI = 0x70B3D57ED005E120; + // uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + // 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + // uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + // 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + // state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + // after the device has been activated, + // the session can be restored without rejoining after device power cycle + // on EEPROM-enabled boards by calling "restore" + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello World! #" + String(count++); + String strDown; + int state = node.sendReceive(strUp, 10, strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("received a downlink!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("no downlink!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + + // wait before sending another packet + // alternatively, call a deepsleep function here + // make sure to send the radio to sleep as well using radio.sleep() + delay(30000); +} diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino new file mode 100644 index 0000000000..e72e977cf4 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino @@ -0,0 +1,216 @@ +/* + RadioLib LoRaWAN End Device Example + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will join the network and start uploading data. + + Also, most of the possible and available functions are + shown here for reference. + + LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + Please refer to the 'persistent' example once you are familiar + with LoRaWAN. + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI + // when adding new end device in TTN, you will have to enter this number + // you can pick any number you want, but it has to be unique + uint64_t joinEUI = 0x12AD1011B0C0FFEE; + + // device identifier - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is also unique + uint64_t devEUI = 0x70B3D57ED005E120; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + + // some frequency bands only use a subset of the available channels + // you can select the specific band or set the first channel and last channel + // for example, either of the following corresponds to US915 FSB2 in TTN + /* + node.selectSubband(2); + node.selectSubband(8, 15); + */ + + // now we can start the activation + // this can take up to 10 seconds, and requires a LoRaWAN gateway in range + // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): + /* + uint8_t joinDr = 4; + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); + */ + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after the device has been activated, + // the session can be restored without rejoining after device power cycle + // on EEPROM-enabled boards by calling "restore" + /* + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ + + // disable the ADR algorithm + node.setADR(false); + + // set a fixed datarate + node.setDatarate(5); + + // enable CSMA + // this tries to minimize packet loss by searching for a free channel + // before actually sending an uplink + node.setCSMA(6, 2, true); + +} + +void loop() { + int state = RADIOLIB_ERR_NONE; + + // set battery fill level, + // 0 = external power source + // 1 = lowest (empty battery) + // 254 = highest (full battery) + // 255 = unable to measure + uint8_t battLevel = 146; + node.setDeviceStatus(battLevel); + + // retrieve the last uplink frame counter + uint32_t fcntUp = node.getFcntUp(); + + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello World! #" + String(fcntUp); + + // send a confirmed uplink to port 10 every 64th frame + if(fcntUp % 64 == 0) { + state = node.uplink(strUp, 10, true); + } else { + state = node.uplink(strUp, 10); + } + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // after uplink, you can call downlink(), + // to receive any possible reply from the server + // this function must be called within a few seconds + // after uplink to receive the downlink! + Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + String strDown; + state = node.downlink(strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + /* + node.saveSession(); + */ + + // wait before sending another packet + delay(30000); +} diff --git a/keywords.txt b/keywords.txt index 4cd39fb45a..a791ce5177 100644 --- a/keywords.txt +++ b/keywords.txt @@ -124,7 +124,6 @@ setSyncWord KEYWORD2 setOutputPower KEYWORD2 setCurrentLimit KEYWORD2 setPreambleLength KEYWORD2 -invertPreamble KEYWORD2 setGain KEYWORD2 getFrequencyError KEYWORD2 getRSSI KEYWORD2 @@ -222,7 +221,6 @@ spectralScanStart KEYWORD2 spectralScanAbort KEYWORD2 spectralScanGetStatus KEYWORD2 spectralScanGetResult KEYWORD2 -setPaConfig KEYWORD2 # nRF24 setIrqAction KEYWORD2 @@ -291,12 +289,18 @@ setModem KEYWORD2 # LoRaWAN wipe KEYWORD2 -restoreOTAA KEYWORD2 +restore KEYWORD2 beginOTAA KEYWORD2 beginABP KEYWORD2 +saveSession KEYWORD2 uplink KEYWORD2 downlink KEYWORD2 -configureChannel KEYWORD2 +sendReceive KEYWORD2 +setDeviceStatus KEYWORD2 +setDatarate KEYWORD2 +setADR KEYWORD2 +selectSubband KEYWORD2 +setCSMA KEYWORD2 ####################################### # Constants (LITERAL1) @@ -408,4 +412,5 @@ RADIOLIB_ERR_COMMAND_QUEUE_EMPTY LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 -RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 \ No newline at end of file +RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 \ No newline at end of file diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 86a58f9013..0485fad8a7 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -58,19 +58,35 @@ void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) { } void inline ArduinoHal::delay(unsigned long ms) { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) ::delay(ms); +#else + ::delay(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif } void inline ArduinoHal::delayMicroseconds(unsigned long us) { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) ::delayMicroseconds(us); +#else + ::delayMicroseconds(us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif } unsigned long inline ArduinoHal::millis() { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) return(::millis()); +#else + return(::millis() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif } unsigned long inline ArduinoHal::micros() { +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) return(::micros()); +#else + return(::micros() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif } long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) { diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 324a7fbefd..5ade1f4935 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -442,7 +442,19 @@ // the amount of space allocated to the persistent storage #if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0xD0) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x0180) +#endif + +/* + * Uncomment on boards whose clock runs too slow or too fast + * Set the value according to the following scheme: + * Enable timestamps on your terminal + * Print something to terminal, wait 1000 milliseconds, print something again + * If the difference is e.g. 1014 milliseconds between the prints, set this value to 14 + * Or, for more accuracy, wait for 100,000 milliseconds and divide the total drift by 100 + */ +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + //#define RADIOLIB_CLOCK_DRIFT_MS (0) #endif // This only compiles on STM32 boards with SUBGHZ module, but also diff --git a/src/Hal.cpp b/src/Hal.cpp index 6ba08bb755..1b4e818e25 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -60,14 +60,14 @@ uint32_t RadioLibHal::getPersistentAddr(uint32_t id) { } template -void RadioLibHal::setPersistentParameter(uint32_t id, T val) { +void RadioLibHal::setPersistentParameter(uint32_t id, T val, uint32_t offset) { uint8_t *ptr = (uint8_t*)&val; - this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id], ptr, sizeof(T)); + this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id] + offset, ptr, sizeof(T)); } -template void RadioLibHal::setPersistentParameter(uint32_t id, uint8_t val); -template void RadioLibHal::setPersistentParameter(uint32_t id, uint16_t val); -template void RadioLibHal::setPersistentParameter(uint32_t id, uint32_t val); +template void RadioLibHal::setPersistentParameter(uint32_t id, uint8_t val, uint32_t offset); +template void RadioLibHal::setPersistentParameter(uint32_t id, uint16_t val, uint32_t offset); +template void RadioLibHal::setPersistentParameter(uint32_t id, uint32_t val, uint32_t offset); template T RadioLibHal::getPersistentParameter(uint32_t id) { diff --git a/src/Hal.h b/src/Hal.h index 9d89811f30..780c348318 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -7,47 +7,59 @@ #include "BuildOpt.h" // list of persistent parameters -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (2) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (3) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (4) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (5) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (6) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (7) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (8) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (9) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID (10) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID (11) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID (12) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (13) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (14) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (15) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID (16) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_ID (17) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (18) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (2) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID (3) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID (4) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID (5) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID (6) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID (7) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID (8) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (9) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (10) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (11) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (12) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (13) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (14) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (15) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (16) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (17) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (18) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID (19) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID (20) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID (21) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (22) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (23) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID (24) static const uint32_t RadioLibPersistentParamTable[] = { - 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION - 0x08, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID + 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID + 0x01, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID + 0x03, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION + 0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID + 0x05, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID + 0x06, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID + 0x07, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID + 0x0A, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID + 0x0B, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID 0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID 0x10, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID 0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID 0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID 0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID - 0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID - 0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID - 0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID - 0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID - 0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST - 0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID - 0x74, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID - 0x78, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID - 0x7C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID - 0x80, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID - 0x84, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_ID - 0x88, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID - 0xD0, // end + 0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID + 0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID + 0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID + 0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID + 0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID + 0x64, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID + 0x68, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID + 0x6C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID + 0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 0x8E, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID + 0xD0, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID + 0x0180, // end }; /*! @@ -287,9 +299,10 @@ class RadioLibHal { will be stored in the system endian! \param id Parameter ID to save at. \param val Value to set. + \param offset An additional offset added to the address. */ template - void setPersistentParameter(uint32_t id, T val); + void setPersistentParameter(uint32_t id, T val, uint32_t offset = 0); /*! \brief Method to get arbitrary parameter from persistent storage. diff --git a/src/TypeDef.h b/src/TypeDef.h index 0ebcbbb176..2e16145c0d 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -553,6 +553,11 @@ */ #define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114) +/*! + \brief Datarate requested by user is invalid. +*/ +#define RADIOLIB_ERR_DATA_RATE_INVALID (-1115) + /*! \} */ diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 7c6f8baac5..28e55b7966 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1436,6 +1436,25 @@ uint32_t SX126x::getTimeOnAir(size_t len) { } } +uint32_t SX126x::calculateRxTimeout(uint32_t timeoutUs) { + // the timeout value is given in units of 15.625 microseconds + // the calling function should provide some extra width, as this number of units is truncated to integer + uint32_t timeout = timeoutUs / 15.625; + return(timeout); +} + +int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { + irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register + irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0 + return(RADIOLIB_ERR_NONE); +} + +bool SX126x::isRxTimeout() { + uint16_t irq = getIrqStatus(); + bool rxTimedOut = irq & RADIOLIB_SX126X_IRQ_TIMEOUT; + return(rxTimedOut); +} + int16_t SX126x::implicitHeader(size_t len) { return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 30900802bf..0c2f9e2081 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -56,7 +56,7 @@ #define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C #define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 #define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F -#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0x0A +#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0 // status commands #define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 @@ -219,7 +219,7 @@ #define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error #define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received #define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected -#define RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected #define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received #define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed #define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR) @@ -949,6 +949,27 @@ class SX126x: public PhysicalLayer { */ uint32_t getTimeOnAir(size_t len) override; + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + uint32_t calculateRxTimeout(uint32_t timeoutUs); + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns \ref RxTimeout IRQ is set + */ + bool isRxTimeout(); + /*! \brief Set implicit header mode for future reception/transmission. \param len Payload length in bytes. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 38fb6979af..02a2d3780e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -432,10 +432,20 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { return(setMode(mode)); } -int16_t SX127x::startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t SX127x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { (void)irqFlags; (void)irqMask; - return(startReceive((uint8_t)len, (uint8_t)mode)); + uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS; + if(timeout != 0) { + // for non-zero timeout value, change mode to Rx single and set the timeout + mode = RADIOLIB_SX127X_RXSINGLE; + uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8); + uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym); + RADIOLIB_ASSERT(state); + } + return(startReceive((uint8_t)len, mode)); } void SX127x::setDio0Action(void (*func)(void), uint32_t dir) { @@ -1221,28 +1231,45 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen)); } +float SX127x::getNumSymbols(size_t len) { + // get symbol length in us + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + + // get Low Data Rate optimization flag + float de = 0; + if (symbolLength >= 16.0) { + de = 1; + } + + // get explicit/implicit header enabled flag + float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); + + // get CRC enabled flag + float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + + // get number of preamble symbols + float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + + // get number of payload symbols + float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); + + // add 4.25 symbols for the sync + return(n_pre + n_pay + 4.25f); +} + uint32_t SX127x::getTimeOnAir(size_t len) { // check active modem uint8_t modem = getActiveModem(); if (modem == RADIOLIB_SX127X_LORA) { - // Get symbol length in us + // get symbol length in us float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - // Get Low Data Rate optimization flag - float de = 0; - if (symbolLength >= 16.0) { - de = 1; - } - // Get explicit/implicit header enabled flag - float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); - // Get CRC enabled flag - float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); - // Get number of bits preamble - float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); - // Get number of bits payload - float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); + + // get number of symbols + float n_sym = getNumSymbols(len); // Get time-on-air in us - return ceil(symbolLength * (n_pre + n_pay + 4.25)) * 1000; + return ceil((double)symbolLength * (double)n_sym) * 1000; + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // Get number of bits preamble float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; @@ -1267,6 +1294,28 @@ uint32_t SX127x::getTimeOnAir(size_t len) { } +uint32_t SX127x::calculateRxTimeout(uint32_t timeoutUs) { + // the timeout is given as the number of symbols + // the calling function should provide some extra width, as this number of symbols is truncated to integer + // the order of operators is swapped here to decrease the effects of this truncation error + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + uint32_t numSymbols = (timeoutUs / symbolLength) / 1000; + return(numSymbols); +} + +int16_t SX127x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { + // IRQ flags/masks are inverted to what seems logical for SX127x (0 being activated, 1 being deactivated) + irqFlags = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT; + irqMask = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE & RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT; + return(RADIOLIB_ERR_NONE); +} + +bool SX127x::isRxTimeout() { + uint16_t irq = getIRQFlags(); + bool rxTimedOut = irq & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT; + return(rxTimedOut); +} + int16_t SX127x::setCrcFiltering(bool enable) { this->crcOn = enable; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 59fc29a511..fa4ab65ba3 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -160,6 +160,7 @@ #define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete #define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel #define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation +#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT 0b00011111 // 7 0 default for Rx (RX_TIMEOUT, RX_DONE, CRC_ERR) // RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR #define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only @@ -824,13 +825,16 @@ class SX127x: public PhysicalLayer { /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param mode Receive mode to be used. + \param timeout Receive mode type and/or raw timeout value in symbols. + When set to 0, the timeout will be infinite and the device will remain + in Rx mode until explicitly commanded to stop (Rx continuous mode). + When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set. \param irqFlags Ignored. \param irqMask Ignored. \param len Expected length of packet to be received. Required for LoRa spreading factor 6. \returns \ref status_codes */ - int16_t startReceive(uint32_t mode, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, @@ -1041,6 +1045,13 @@ class SX127x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); + /*! + \brief Convert from bytes to LoRa symbols. + \param len Payload length in bytes. + \returns The total number of LoRa symbols, including preamble, sync and possible header. + */ + float getNumSymbols(size_t len); + /*! \brief Get expected time-on-air for a given size of payload. \param len Payload length in bytes. @@ -1048,6 +1059,27 @@ class SX127x: public PhysicalLayer { */ uint32_t getTimeOnAir(size_t len) override; + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + uint32_t calculateRxTimeout(uint32_t timeoutUs); + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns \ref RxTimeout IRQ is set + */ + bool isRxTimeout(); + /*! \brief Enable CRC filtering and generation. \param enable Set or unset CRC filtering and generation. diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 30ffe5ee10..fc0b31645d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1,51 +1,40 @@ #include "LoRaWAN.h" - #include #if !defined(RADIOLIB_EXCLUDE_LORAWAN) -// flag to indicate whether we have received a downlink -static volatile bool downlinkReceived = false; - #if defined(RADIOLIB_EEPROM_UNSUPPORTED) #warning "Persistent storage not supported!" #endif +// flag to indicate whether there was some action during Rx mode (timeout or downlink) +static volatile bool downlinkAction = false; + // interrupt service routine to handle downlinks automatically #if defined(ESP8266) || defined(ESP32) IRAM_ATTR #endif -static void LoRaWANNodeOnDownlink(void) { - downlinkReceived = true; +static void LoRaWANNodeOnDownlinkAction(void) { + downlinkAction = true; } -// flag to indicate whether channel scan operation is complete -static volatile bool scanFlag = false; - -// interrupt service routine to handle downlinks automatically -#if defined(ESP8266) || defined(ESP32) - IRAM_ATTR -#endif -static void LoRaWANNodeOnChannelScan(void) { - scanFlag = true; +uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_t min, uint8_t max) { + int8_t dr = uplink - offset + base; + if(dr < min) { + dr = min; + } else if (dr > max) { + dr = max; + } + return(dr); } LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->phyLayer = phy; this->band = band; - this->FSK = false; - this->startChannel = -1; - this->numChannels = -1; - this->backupFreq = this->band->backupChannel.freqStart; + this->rx2 = this->band->rx2; this->difsSlots = 2; this->backoffMax = 6; this->enableCSMA = false; - -} - -void LoRaWANNode::wipe() { - Module* mod = this->phyLayer->getMod(); - mod->hal->wipePersistentStorage(); } void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { @@ -54,133 +43,195 @@ void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA this->enableCSMA = enableCSMA; } +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) +void LoRaWANNode::wipe() { + Module* mod = this->phyLayer->getMod(); + mod->hal->wipePersistentStorage(); +} -int16_t LoRaWANNode::restoreOTAA() { - int16_t state = this->setPhyProperties(); - RADIOLIB_ASSERT(state); +int16_t LoRaWANNode::restore() { + // if already joined, ignore + if(this->isJoinedFlag) { + return(RADIOLIB_ERR_NONE); + } - // check the magic value Module* mod = this->phyLayer->getMod(); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) != RADIOLIB_LORAWAN_MAGIC) { - // the magic value is not set, user will have to do perform the join procedure - return(RADIOLIB_ERR_NETWORK_NOT_JOINED); - } - // in case of future revisions of NVM, use a version parameter to allow transitioning from one version to another while keeping session alive - uint16_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID); - // if (RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION > nvm_table_version) { + uint8_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID); + // if (RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION > nvm_table_version) { // // set default values for variables that are new or something // } (void)nvm_table_version; - // pull all needed information from persistent storage + // check the magic value + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) != RADIOLIB_LORAWAN_MAGIC) { + #if defined(RADIOLIB_DEBUG) + RADIOLIB_DEBUG_PRINTLN("magic id not set (no saved session)"); + RADIOLIB_DEBUG_PRINTLN("first 16 bytes of NVM:"); + uint8_t nvmBuff[16]; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); + RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); + #endif + // the magic value is not set, user will have to do perform the join procedure + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // pull all authentication keys from persistent storage this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - RADIOLIB_DEBUG_PRINTLN("appSKey:"); - RADIOLIB_DEBUG_HEXDUMP(this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - uint32_t dlSettings = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID); - this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; - uint8_t rx1DrOffset = (dlSettings & 0x70) >> 4; - uint8_t rx2DataRate = dlSettings & 0x0F; - RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: %d", this->rev); + // get session parameters + this->rev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID); + RADIOLIB_DEBUG_PRINTLN("LoRaWAN session: v1.%d", this->rev); + this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID); + this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID); - // TODO process the RX2 data rate - (void)rx2DataRate; - - // TODO process the data rate offset - (void)rx1DrOffset; - - // parse Rx1 delay (and subsequently Rx2) - this->rxDelays[0] = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID); + // get MAC state + uint8_t txDrRx2Dr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = (txDrRx2Dr >> 4) & 0x0F; + + this->txPwrCur = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID); + + uint8_t rx1DrOffDel = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID); + this->rx1DrOffset = (rx1DrOffDel >> 4) & 0x0F; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] + this->band->rx1DataRateBase + this->rx1DrOffset; + this->rxDelays[0] = ((rx1DrOffDel >> 0) & 0x0F) * 1000; if(this->rxDelays[0] == 0) { this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; } - this->rxDelays[1] = this->rxDelays[0] + 1000; + this->rxDelays[1] = this->rxDelays[0] + 1000; + + uint8_t rx2FreqBuf[3]; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID), rx2FreqBuf, 3); + uint32_t rx2Freq = LoRaWANNode::ntoh(&rx2FreqBuf[0], 3); + this->rx2.drMax = (txDrRx2Dr >> 0) & 0x0F; + this->rx2.freq = (float)rx2Freq / 10000.0; + + uint8_t adrLimDel = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID); + this->adrLimitExp = (adrLimDel >> 4) & 0x0F; + this->adrDelayExp = (adrLimDel >> 0) & 0x0F; + + this->nbTrans = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID); - // process CFlist if any bit is non-zero - uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; - uint8_t allZero[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID), cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); - RADIOLIB_DEBUG_PRINTLN("cfList:"); - RADIOLIB_DEBUG_HEXDUMP(cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); - if(memcmp(cfList, allZero, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { - // list of frequencies - for(uint8_t i = 0; i < 5; i++) { - uint32_t freq = LoRaWANNode::ntoh(&cfList[3*i], 3); - availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = (float)freq/10000.0; - availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", i, availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); - } + this->aFcntDown = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID); + this->nFcntDown = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID); + this->confFcntUp = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID); + this->confFcntDown = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID); + this->adrFcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID); + + // fcntUp is stored in highly efficient wear-leveling system, so parse it as required + this->restoreFcntUp(); - } else { - // frequency mask, we need to find out which frequencies are actually being used - uint8_t channelId = 0; - uint8_t chSpan = 0; - uint8_t chNum = 0; - for(uint8_t i = 0; i < 5; i++) { - uint16_t mask = LoRaWANNode::ntoh(&cfList[2*i]); - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", i, mask); - for(uint8_t j = 0; j < 16; j++) { - if(chNum >= this->band->defaultChannels[chSpan].numChannels) { - chNum -= this->band->defaultChannels[chSpan].numChannels; - chSpan++; + uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&this->commandsUp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + RADIOLIB_DEBUG_PRINTLN("Number of MAC commands: %d", this->commandsUp.numCommands); + + int16_t state = this->restoreChannels(); + RADIOLIB_ASSERT(state); - if(chSpan >= this->band->numChannelSpans) { - RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); - return(RADIOLIB_ERR_UNKNOWN); - } - } + state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); - if(mask & (1UL << j)) { - RADIOLIB_DEBUG_PRINTLN("chNum = %d, chSpan = %d", chNum, chSpan); - uint8_t dir = this->band->defaultChannels[chSpan].direction; - float freq = this->band->defaultChannels[chSpan].freqStart + chNum*this->band->defaultChannels[chSpan].freqStep; - availableChannelsFreq[dir][channelId] = freq; - RADIOLIB_DEBUG_PRINTLN("Channel %cL %d frequency = %f MHz", dir ? 'U': 'D', channelId, availableChannelsFreq[dir][channelId]); - channelId++; - } + // full session is restored, so set joined flag + this->isJoinedFlag = true; - chNum++; - } - } + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::restoreFcntUp() { + Module* mod = this->phyLayer->getMod(); + uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID); + uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 1); + uint8_t buffSize = fcntBuffEnd - fcntBuffStart; + uint8_t fcntBuff[buffSize] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); + + // copy the two most significant bytes from the first two bytes + uint32_t bits_30_22 = (uint32_t)fcntBuff[0]; + uint32_t bits_22_14 = (uint32_t)fcntBuff[1]; + + // the next 7 bits must be retrieved from the byte to which was written most recently + // this is the last byte that has its state bit (most significant bit) set equal to its predecessor + // we find the first byte that has its state bit different, and subtract one + uint8_t idx = 2; + uint8_t state = fcntBuff[idx] >> 7; + for(; idx < 5; idx++) { + if(fcntBuff[idx] >> 7 != state) { + break; } } + uint32_t bits_14_7 = (uint32_t)fcntBuff[idx-1] & 0x7F; - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - memcpy(&queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + // equally, the last 7 bits must be retrieved from the byte to which was written most recently + // this is the last byte that has its state bit (most significant bit) set equal to its predecessor + // we find the first byte that has its state bit different, and subtract one + idx = 5; + state = fcntBuff[idx] >> 7; + for(; idx < buffSize; idx++) { + if(fcntBuff[idx] >> 7 != state) { + break; + } + } + uint32_t bits_7_0 = (uint32_t)fcntBuff[idx-1] & 0x7F; - state = this->setupChannels(); - RADIOLIB_ASSERT(state); - + this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::restoreChannels() { + uint8_t bytesPerChannel = 5; + uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; + uint8_t buffer[numBytes]; + Module* mod = this->phyLayer->getMod(); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID), buffer, numBytes); + for(uint8_t dir = 0; dir < 2; dir++) { + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + uint8_t chBuff[bytesPerChannel] = { 0 }; + memcpy(chBuff, &buffer[(dir * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel) + i * bytesPerChannel], bytesPerChannel); + this->availableChannels[dir][i].enabled = (chBuff[0] & 0x80) >> 7; + this->availableChannels[dir][i].idx = chBuff[0] & 0x7F; + uint32_t freq = LoRaWANNode::ntoh(&chBuff[1], 3); + this->availableChannels[dir][i].freq = (float)freq/10000.0; + this->availableChannels[dir][i].drMax = (chBuff[4] & 0xF0) >> 4; + this->availableChannels[dir][i].drMin = (chBuff[4] & 0x0F) >> 0; + } + } return(RADIOLIB_ERR_NONE); } +#endif -int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force) { +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr, bool force) { // check if we actually need to send the join request Module* mod = this->phyLayer->getMod(); - if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { // the device has joined already, we can just pull the data from persistent storage - return(this->restoreOTAA()); + return(this->restore()); } +#endif // set the physical layer configuration + this->txPwrCur = this->band->powerMax; int16_t state = this->setPhyProperties(); RADIOLIB_ASSERT(state); // setup uplink/downlink frequencies and datarates - state = this->setupChannels(); + state = this->selectChannelsJR(this->devNonce, joinDr); + RADIOLIB_ASSERT(state); + + // configure for uplink with default configuration + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); - // get dev nonce from persistent storage and increment it - uint16_t devNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID, devNonce + 1); + // increment devNonce as we are sending another join-request + this->devNonce += 1; // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; @@ -189,7 +240,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonce); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], this->devNonce); // add the authentication code uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); @@ -197,47 +248,18 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // send it state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + this->rxDelayStart = mod->hal->millis(); + RADIOLIB_DEBUG_PRINTLN("Join-request sent <-- Rx Delay start"); RADIOLIB_ASSERT(state); - // configure for downlink with default configuration - state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); - RADIOLIB_ASSERT(state); - - // set the function that will be called when the reply is received - this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); + // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received + this->rxDelays[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; + this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; - // downlink messages are sent with inverted IQ - // TODO use downlink() for this - if(!this->FSK) { - state = this->phyLayer->invertIQ(true); - RADIOLIB_ASSERT(state); - } - - // start receiving - uint32_t start = mod->hal->millis(); - downlinkReceived = false; - state = this->phyLayer->startReceive(); + // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received + state = downlinkCommon(); RADIOLIB_ASSERT(state); - // wait for the reply or timeout - while(!downlinkReceived) { - if(mod->hal->millis() - start >= RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS + 2000) { - downlinkReceived = false; - if(!this->FSK) { - this->phyLayer->invertIQ(false); - } - return(RADIOLIB_ERR_RX_TIMEOUT); - } - } - - // we have a message, reset the IQ inversion - downlinkReceived = false; - this->phyLayer->clearPacketReceivedAction(); - if(!this->FSK) { - state = this->phyLayer->invertIQ(false); - RADIOLIB_ASSERT(state); - } - // build the buffer for the reply data uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; @@ -273,20 +295,22 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RADIOLIB_DEBUG_PRINTLN("joinAcceptMsg:"); RADIOLIB_DEBUG_HEXDUMP(joinAcceptMsg, lenRx); - // get current JoinNonce from downlink and previous JoinNonce from NVM - uint32_t joinNonce = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); - uint32_t joinNoncePrev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID); - RADIOLIB_DEBUG_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", joinNoncePrev, joinNonce); - - // JoinNonce received must be greater than the last JoinNonce heard, else error - if(joinNonce <= joinNoncePrev) { + // get current JoinNonce from downlink and previous JoinNonce from persistent storage + uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + + RADIOLIB_DEBUG_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); + // JoinNonce received must be greater than the last JoinNonce heard, else error + if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { return(RADIOLIB_ERR_JOIN_NONCE_INVALID); } + this->joinNonce = joinNonceNew; // check LoRaWAN revision (the MIC verification depends on this) uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: 1.%d", this->rev); + this->rx1DrOffset = (dlSettings & 0x70) >> 4; + this->rx2.drMax = dlSettings & 0x0F; // verify MIC if(this->rev == 1) { @@ -301,7 +325,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], joinEUI); - LoRaWANNode::hton(&micBuff[9], devNonce); + LoRaWANNode::hton(&micBuff[9], this->devNonce); memcpy(&micBuff[11], joinAcceptMsg, lenRx); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { @@ -315,17 +339,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } } - uint8_t rx1DrOffset = (dlSettings & 0x70) >> 4; - uint8_t rx2DataRate = dlSettings & 0x0F; - // TODO process the RX2 data rate - (void)rx2DataRate; - - // TODO process the data rate offset - (void)rx1DrOffset; - // parse other contents - uint32_t homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); + this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); // parse Rx1 delay (and subsequently Rx2) @@ -336,56 +352,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->rxDelays[1] = this->rxDelays[0] + 1000; // process CFlist if present - uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { + uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); - if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { - // list of frequencies - for(uint8_t i = 0; i < 5; i++) { - uint32_t freq = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + 3*i], 3); - availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = (float)freq/10000.0; - availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; - RADIOLIB_DEBUG_PRINT("Channel UL/DL %d frequency = ", i); - RADIOLIB_DEBUG_PRINT_FLOAT(availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i], 3); - RADIOLIB_DEBUG_PRINTLN(" MHz"); - } - - } else { - // frequency mask, we need to find out which frequencies are actually being used - uint8_t channelId = 0; - uint8_t chSpan = 0; - uint8_t chNum = 0; - for(uint8_t i = 0; i < 5; i++) { - uint16_t mask = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + 2*i]); - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", i, mask); - for(uint8_t j = 0; j < 16; j++) { - if(chNum >= this->band->defaultChannels[chSpan].numChannels) { - chNum -= this->band->defaultChannels[chSpan].numChannels; - chSpan++; - - if(chSpan >= this->band->numChannelSpans) { - RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); - return(RADIOLIB_ERR_UNKNOWN); - } - } - - if(mask & (1UL << j)) { - RADIOLIB_DEBUG_PRINTLN("chNum = %d, chSpan = %d", chNum, chSpan); - uint8_t dir = this->band->defaultChannels[chSpan].direction; - float freq = this->band->defaultChannels[chSpan].freqStart + chNum*this->band->defaultChannels[chSpan].freqStep; - availableChannelsFreq[dir][channelId] = freq; - RADIOLIB_DEBUG_PRINT("Channel %cL %d frequency = ", dir ? 'U': 'D', channelId); - RADIOLIB_DEBUG_PRINT_FLOAT(availableChannelsFreq[dir][channelId], 3); - RADIOLIB_DEBUG_PRINTLN(" MHz"); - channelId++; - } - - chNum++; - } - } - - } - } + this->setupChannels(cfList); + } else { + this->setupChannels(nullptr); + } // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; @@ -395,7 +368,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe if(this->rev == 1) { // 1.1 version, derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], this->devNonce); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(appKey); @@ -416,17 +389,17 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // enqueue the RekeyInd MAC command to be sent in the next uplink LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY, - .len = sizeof(uint8_t), .payload = { this->rev }, - .repeat = RADIOLIB_LORAWAN_ADR_ACK_LIMIT, + .len = sizeof(uint8_t), + .repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP, }; state = pushMacCommand(&cmd, &this->commandsUp); RADIOLIB_ASSERT(state); } else { // 1.0 version, just derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -440,36 +413,50 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } - // save the device address - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); + // reset all frame counters + this->fcntUp = 0; + this->aFcntDown = 0; + this->nFcntDown = 0; + this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFcnt = 0; - // update the keys +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // save the device address & keys as well as JoinAccept values; these are only ever set when joining + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - // save uplink parameters - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID, joinNonce); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID, homeNetId); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID, this->rxDelays[0]); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID, (uint32_t)dlSettings); + // save join-request parameters + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID, this->homeNetId); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); + + this->saveSession(); + this->saveChannels(); - // save cfList (all 0 if none is present) - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID), cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); + // everything written to NVM, write current table version to persistent storage and set magic number + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); +#endif - // all complete, reset device counters and set the magic number - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, 0); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID, 0); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID, 0); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); + this->isJoinedFlag = true; - // everything written to NVM, write current version to NVM - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION); return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey) { +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // check if we actually need to restart from a clean session + Module* mod = this->phyLayer->getMod(); + if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { + // the device has joined already, we can just pull the data from persistent storage + return(this->restore()); + } +#endif + this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); @@ -484,45 +471,223 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, } // set the physical layer configuration + this->txPwrCur = this->band->powerMax; int16_t state = this->setPhyProperties(); RADIOLIB_ASSERT(state); // setup uplink/downlink frequencies and datarates - state = this->setupChannels(); + state = this->setupChannels(nullptr); RADIOLIB_ASSERT(state); - // everything written to NVM, write current version to NVM +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // save the device address & keys + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + this->saveSession(); + this->saveChannels(); + + // everything written to NVM, write current table version to persistent storage and set magic number + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); +#endif + + this->isJoinedFlag = true; + + return(RADIOLIB_ERR_NONE); +} + +bool LoRaWANNode::isJoined() { + return(this->isJoinedFlag); +} + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) +int16_t LoRaWANNode::saveSession() { + Module* mod = this->phyLayer->getMod(); + + // store session configuration (MAC commands) + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID) != this->rev) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID, this->rev); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID) != this->devNonce) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID, this->devNonce); + + uint8_t txDrRx2Dr = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4) | this->rx2.drMax; + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID) != txDrRx2Dr) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID, txDrRx2Dr); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID) != this->txPwrCur) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID, this->txPwrCur); + + uint8_t rx1DrOffDel = (this->rx1DrOffset << 4) | (this->rxDelays[0] / 1000); + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID) != rx1DrOffDel) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID, rx1DrOffDel); + + uint8_t rx2FreqBuf[3]; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID), rx2FreqBuf, 3); + uint32_t rx2Freq = LoRaWANNode::ntoh(&rx2FreqBuf[0], 3); + if(rx2Freq != uint32_t(this->rx2.freq * 10000)) { + rx2Freq = uint32_t(this->rx2.freq * 10000); + LoRaWANNode::hton(&rx2FreqBuf[0], rx2Freq, 3); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID), rx2FreqBuf, 3); + } + + uint8_t adrLimDel = (this->adrLimitExp << 4) | (this->adrDelayExp << 0); + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID) != adrLimDel) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID, adrLimDel); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID) != this->nbTrans) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID, this->nbTrans); + + // store all frame counters + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); + + if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); + + // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often + this->saveFcntUp(); + + // if there is, or was, any MAC command in the queue, overwrite with the current MAC queue + uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + LoRaWANMacCommandQueue_t cmdTemp; + memcpy(&cmdTemp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + if(this->commandsUp.numCommands > 0 || cmdTemp.numCommands > 0) { + memcpy(queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::saveFcntUp() { Module* mod = this->phyLayer->getMod(); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION); + uint8_t fcntBuff[30] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID), fcntBuff, 30); + + // we discard the first two bits - your flash will likely be far dead by the time you reach 2^30 uplinks + // the first two bytes of the remaining 30 bytes are stored straight into storage without additional wear leveling + // because they hardly ever change + uint8_t bits_30_22 = (uint8_t)(this->fcntUp >> 22); + if(fcntBuff[0] != bits_30_22) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_30_22, 0); + uint8_t bits_22_14 = (uint8_t)(this->fcntUp >> 14); + if(fcntBuff[1] != bits_22_14) + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_22_14, 1); + + // the next 7 bits are stored into one of few indices + // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor + // if all have an equal state, restart from the beginning + // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte + uint8_t idx = 2; + uint8_t state = fcntBuff[idx] >> 7; + for(; idx < 5; idx++) { + if(fcntBuff[idx] >> 7 != state) { + break; + } + } + // check if the last written byte is equal to current, only rewrite if different + uint8_t bits_14_7 = (this->fcntUp >> 7) & 0x7F; + if((fcntBuff[idx - 1] & 0x7F) != bits_14_7) { + // find next index to write + idx = idx < 5 ? idx : 2; + + // flip the first bit of this byte to indicate that we just wrote here + bits_14_7 |= (~(fcntBuff[idx] >> 7)) << 7; + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_14_7, idx); + } + + // equally, the last 7 bits are stored into one of many indices + // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor + // if all have an equal state, restart from the beginning + // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte + idx = 5; + state = fcntBuff[idx] >> 7; + for(; idx < 30; idx++) { + if(fcntBuff[idx] >> 7 != state) { + break; + } + } + idx = idx < 30 ? idx : 5; + uint8_t bits_7_0 = (this->fcntUp >> 0) & 0x7F; + + // flip the first bit of this byte to indicate that we just wrote here + bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7; + mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); + + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::saveChannels() { + uint8_t bytesPerChannel = 5; + uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; + uint8_t buffer[numBytes]; + for(uint8_t dir = 0; dir < 2; dir++) { + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + uint8_t chBuff[bytesPerChannel] = { 0 }; + chBuff[0] = (uint8_t)this->availableChannels[dir][i].enabled << 7; + chBuff[0] |= this->availableChannels[dir][i].idx; + uint32_t freq = this->availableChannels[dir][i].freq*10000.0; + LoRaWANNode::hton(&chBuff[1], freq, 3); + chBuff[4] = this->availableChannels[dir][i].drMax << 4; + chBuff[4] |= this->availableChannels[dir][i].drMin << 0; + memcpy(&buffer[(dir * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel) + i * bytesPerChannel], chBuff, bytesPerChannel); + } + } + Module* mod = this->phyLayer->getMod(); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID), buffer, numBytes); return(RADIOLIB_ERR_NONE); } +#endif // RADIOLIB_EEPROM_UNSUPPORTED + #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::uplink(String& str, uint8_t port) { - return(this->uplink(str.c_str(), port)); +int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed) { + return(this->uplink(str.c_str(), port, isConfirmed)); } #endif -int16_t LoRaWANNode::uplink(const char* str, uint8_t port) { - return(this->uplink((uint8_t*)str, strlen(str), port)); +int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed) { + return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed)); } -int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { +int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed) { + Module* mod = this->phyLayer->getMod(); + + // check if the Rx windows were closed after sending the previous uplink + // this FORCES a user to call downlink() after an uplink() + if(this->rxDelayEnd < this->rxDelayStart) { + // not enough time elapsed since the last uplink, we may still be in an Rx window + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + // check destination port if(port > 0xDF) { return(RADIOLIB_ERR_INVALID_PORT); } // port 0 is only allowed for MAC-only payloads if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - if (!isMACPayload) { + if (!this->isMACPayload) { return(RADIOLIB_ERR_INVALID_PORT); } // if this is MAC only payload, continue and reset for next uplink - isMACPayload = false; + this->isMACPayload = false; } - - Module* mod = this->phyLayer->getMod(); // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; @@ -534,21 +699,61 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { } // check maximum payload len as defined in phy - if(len > this->band->payloadLenMax[this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { + if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } + // increase frame counter by one + this->fcntUp += 1; + + // check if we need to do ADR stuff + uint32_t adrLimit = 0x01 << this->adrLimitExp; + uint32_t adrDelay = 0x01 << this->adrDelayExp; + bool adrAckReq = false; + if((this->fcntUp - this->adrFcnt) >= adrLimit) { + adrAckReq = true; + } + if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { + // try one of three, in order: set TxPower to max, set DR to min, enable all defined channels + + // set the maximum power supported by both the module and the band + int8_t pwr = this->band->powerMax; + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power in band and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(pwr--); + } + RADIOLIB_ASSERT(state); + if(pwr == this->txPwrCur) { + + // failed to increase Tx power, so try to decrease the datarate + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]--; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]--; + } else { + + // failed to decrease datarate, so enable all available channels + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled = true; + } + } + } + + } else { + this->txPwrCur = pwr; + } + + // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' + this->adrFcnt += adrDelay; + } + // configure for uplink - // TODO select randomly from available channels + this->selectChannels(); int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); - // check if sufficient time has elapsed since the last uplink - if(mod->hal->millis() - this->rxDelayStart < rxDelays[1]) { - // not enough time elapsed since the last uplink, we may still be in an RX window - return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); - } - // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsBufSize); @@ -559,49 +764,67 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { #endif // set the packet fields - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + if(isConfirmed) { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; + this->confFcntUp = this->fcntUp; + } else { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP; + } + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] |= RADIOLIB_LORAWAN_MHDR_MAJOR_R1; LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); - // TODO implement adaptive data rate // length of fopts will be added later uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; + if(this->adrEnabled) { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; + if(adrAckReq) { + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + } + } + + // if the saved confirm-fcnt is set, set the ACK bit + bool isConfirmingDown; + if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { + isConfirmingDown = true; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; + } + (void)isConfirmingDown; - // get frame counter from persistent storage - uint32_t fcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID) + 1; - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, fcnt); - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)fcnt); + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fcntUp); // check if we have some MAC commands to append if(foptsLen > 0) { - uint8_t foptsNum = this->commandsUp.numCommands; uint8_t foptsBuff[foptsBufSize]; - size_t idx = 0; - for (size_t i = 0; i < foptsNum; i++) { - LoRaWANMacCommand_t cmd = { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, }; - popMacCommand(&cmd, &this->commandsUp, i); - if (cmd.cid == 0) { - break; + uint8_t* foptsPtr = foptsBuff; + + // append all MAC replies into fopts buffer + size_t i = 0; + for (; i < this->commandsUp.numCommands; i++) { + LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; + memcpy(foptsPtr, &cmd, 1 + cmd.len); + foptsPtr += cmd.len + 1; + } + RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsLen); + + // pop the commands from back to front + for (; i >= 0; i--) { + if(this->commandsUp.commands[i].repeat > 0) { + this->commandsUp.commands[i].repeat--; + } else { + deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); } - foptsBuff[idx] = cmd.cid; - for(size_t i = 1; i < cmd.len; i++) { - foptsBuff[idx + i] = cmd.payload[i]; + if(i == 0) { + break; } - idx += cmd.len + 1; } - RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", foptsNum); - RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); - uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= foptsLen; // encrypt it - processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); - // write the current MAC command queue to nvm for next uplink - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)]; - memcpy(&queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); } // set the port @@ -614,22 +837,23 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { } // encrypt the frame payload - // TODO check ctrId --> erratum says it should be 0x01? - processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], fcnt, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], this->fcntUp); block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); - // TODO implement confirmed frames - block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; - block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { + LoRaWANNode::hton(&block1[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntDown); + } + block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; RADIOLIB_DEBUG_PRINTLN("uplinkMsg pre-MIC:"); RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -648,58 +872,53 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) { LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } + RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); + RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); + // perform CSMA if enabled. if (enableCSMA) { performCSMA(); } - RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); - RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); - // send it (without the MIC calculation blocks) - uint32_t txStart = mod->hal->millis(); - uint32_t timeOnAir = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); + + // set the timestamp so that we can measure when to start receiving + this->rxDelayStart = mod->hal->millis(); + RADIOLIB_DEBUG_PRINTLN("Uplink sent <-- Rx Delay start"); + #if !defined(RADIOLIB_STATIC_ONLY) delete[] uplinkMsg; #endif RADIOLIB_ASSERT(state); + + // the downlink confirmation was acknowledged, so clear the counter value + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + + // LoRaWANEvent: + // dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK + // confirmed = isConfirmed + // confirming = isConfirmingDown + // power = this->txPwrCur + // fcnt = this->fcntUp + // port = port - // set the timestamp so that we can measure when to start receiving - this->rxDelayStart = txStart + timeOnAir; return(RADIOLIB_ERR_NONE); } -#if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::downlink(String& str) { - int16_t state = RADIOLIB_ERR_NONE; +int16_t LoRaWANNode::downlinkCommon() { + Module* mod = this->phyLayer->getMod(); + const uint32_t scanGuard = 10; - // build a temporary buffer - // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL - size_t length = 0; - uint8_t data[251]; - - // wait for downlink - state = this->downlink(data, &length); - if(state == RADIOLIB_ERR_NONE) { - // add null terminator - data[length] = '\0'; - - // initialize Arduino String class - str = String((char*)data); - } - - return(state); -} -#endif - -int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // check if there are any upcoming Rx windows - Module* mod = this->phyLayer->getMod(); - const uint32_t scanGuard = 500; - if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[1] + scanGuard)) { - // time since last Tx is greater than RX2 delay + some guard period - // we have nothing to downlink + // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 + if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[0] - scanGuard)) { + // if between start of Rx1 and end of Rx2, wait until Rx2 closes + if(mod->hal->millis() - this->rxDelayStart < this->rxDelays[1]) { + mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - mod->hal->millis()); + } + // update the end timestamp in case user got stuck between uplink and downlink + this->rxDelayEnd = mod->hal->millis(); return(RADIOLIB_ERR_NO_RX_WINDOW); } @@ -713,18 +932,23 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { RADIOLIB_ASSERT(state); } - // calculate the channel scanning timeout - // according to the spec, this must be at least enough time to effectively detect a preamble - uint32_t scanTimeout = this->phyLayer->getTimeOnAir(0)/1000; + // create the masks that are required for receiving downlinks + uint16_t irqFlags = 0x0000; + uint16_t irqMask = 0x0000; + this->phyLayer->irqRxDoneRxTimeout(irqFlags, irqMask); - // set up everything for channel scan - downlinkReceived = false; - scanFlag = false; - bool packetDetected = false; - this->phyLayer->setChannelScanAction(LoRaWANNodeOnChannelScan); + this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); // perform listening in the two Rx windows for(uint8_t i = 0; i < 2; i++) { + downlinkAction = false; + + // calculate the Rx timeout + // according to the spec, this must be at least enough time to effectively detect a preamble + // but pad it a bit on both sides (start and end) to make sure it is wide enough + uint32_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000; + uint32_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); + // wait for the start of the Rx window // the waiting duration is shortened a bit to cover any possible timing errors uint32_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart); @@ -733,99 +957,92 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { } mod->hal->delay(waitLen); - // wait until we get a preamble - uint32_t scanStart = mod->hal->millis(); - while((mod->hal->millis() - scanStart) < (scanTimeout + scanGuard)) { - // check channel detection timeout - state = this->phyLayer->startChannelScan(); - RADIOLIB_ASSERT(state); - - // wait with some timeout, though it should not be hit - uint32_t cadStart = mod->hal->millis(); - while(!scanFlag) { - mod->hal->yield(); - if(mod->hal->millis() - cadStart >= 3000) { - // timed out, stop waiting - break; - } - } - - // check the scan result - scanFlag = false; - state = this->phyLayer->getChannelScanResult(); - if((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { - packetDetected = true; - break; - } + // open Rx window by starting receive with specified timeout + state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); + RADIOLIB_DEBUG_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); - } + // wait for the timeout to complete (and a small additional delay) + mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); + RADIOLIB_DEBUG_PRINTLN("closing"); - // check if we have a packet - if(packetDetected) { + // check if the IRQ bit for Rx Timeout is set + if(!this->phyLayer->isRxTimeout()) { break; } else if(i == 0) { // nothing in the first window, configure for the second - state = this->phyLayer->setFrequency(this->backupFreq); + this->phyLayer->standby(); + state = this->phyLayer->setFrequency(this->rx2.freq); RADIOLIB_ASSERT(state); DataRate_t dataRate; - findDataRate(RADIOLIB_LORAWAN_DATA_RATE_UNUSED, &dataRate, &this->band->backupChannel); + findDataRate(this->rx2.drMax, &dataRate); state = this->phyLayer->setDataRate(dataRate); RADIOLIB_ASSERT(state); - } } + // Rx windows are now closed + this->rxDelayEnd = mod->hal->millis(); - // check if we received a packet at all - if(!packetDetected) { - this->phyLayer->standby(); + // if we got here due to a timeout, stop ongoing activities + if(this->phyLayer->isRxTimeout()) { + this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? if(!this->FSK) { this->phyLayer->invertIQ(false); } - // restore the original uplink channel - this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); - return(RADIOLIB_ERR_RX_TIMEOUT); } - // channel scan is finished, swap the actions - this->phyLayer->clearChannelScanAction(); - downlinkReceived = false; - this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlink); - - // start receiving - state = this->phyLayer->startReceive(); - RADIOLIB_ASSERT(state); - - // wait for reception with some timeout - uint32_t rxStart = mod->hal->millis(); - while(!downlinkReceived) { + // wait for the DIO to fire indicating a downlink is received + while(!downlinkAction) { mod->hal->yield(); - // let's hope 30 seconds is long enough timeout - if(mod->hal->millis() - rxStart >= 30000) { - // timed out - this->phyLayer->standby(); - if(!this->FSK) { - this->phyLayer->invertIQ(false); - } - return(RADIOLIB_ERR_RX_TIMEOUT); - } } // we have a message, clear actions, go to standby and reset the IQ inversion - downlinkReceived = false; - this->phyLayer->standby(); + this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? this->phyLayer->clearPacketReceivedAction(); if(!this->FSK) { state = this->phyLayer->invertIQ(false); RADIOLIB_ASSERT(state); } + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::downlink(String& str) { + int16_t state = RADIOLIB_ERR_NONE; + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t length = 0; + uint8_t data[251]; + + // wait for downlink + state = this->downlink(data, &length); + if(state == RADIOLIB_ERR_NONE) { + // add null terminator + data[length] = '\0'; + + // initialize Arduino String class + str = String((char*)data); + } + + return(state); +} +#endif + +int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { + + // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received + int16_t state = downlinkCommon(); + RADIOLIB_ASSERT(state); + // get the packet length size_t downlinkMsgLen = this->phyLayer->getPacketLength(); + RADIOLIB_DEBUG_PRINTLN("Downlink message length: %d", downlinkMsgLen); // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a port @@ -843,7 +1060,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { #endif // set the MIC calculation block - // TODO implement confirmed frames memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); @@ -866,10 +1082,17 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { } // get the frame counter and set it to the MIC calculation block - // TODO cache the ADR bit? uint16_t fcnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16); - uint32_t fcnt32 = fcnt16; // calculate possible rollover once decided if this is network downlink or application downlink + + // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fcntUp + // TODO get this to the user somehow + bool isConfirmingUp = false; + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK) && (this->rev == 1)) { + isConfirmingUp = true; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); + } + (void)isConfirmingUp; RADIOLIB_DEBUG_PRINTLN("downlinkMsg:"); RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); @@ -886,32 +1109,31 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // check the FcntDown value (Network or Application) uint32_t fcntDownPrev = 0; if (isAppDownlink) { - fcntDownPrev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID); + fcntDownPrev = this->aFcntDown; } else { - fcntDownPrev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID); + fcntDownPrev = this->nFcntDown; } - // assume a 16-bit to 32-bit rollover when difference in LSB is smaller than MAX_FCNT_GAP + RADIOLIB_DEBUG_PRINTLN("fcnt: %d, fcntPrev: %d, isAppDownlink: %d", fcnt16, fcntDownPrev, (int)isAppDownlink); + + // if this is not the first downlink... + // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error - if ((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] downlinkMsg; - #endif - if (isAppDownlink) { - return(RADIOLIB_ERR_A_FCNT_DOWN_INVALID); - } else { - return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID); + uint32_t fcnt32 = fcnt16; + if(fcntDownPrev > 0) { + if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] downlinkMsg; + #endif + if (isAppDownlink) { + return(RADIOLIB_ERR_A_FCNT_DOWN_INVALID); + } else { + return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID); + } + } else if (fcnt16 <= fcntDownPrev) { + uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover + fcnt32 |= ((uint32_t)msb << 16); // add back the MSB part } - } else if (fcnt16 <= fcntDownPrev) { - uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover - fcnt32 |= (msb << 16); // add back the MSB part - } - - // save current fcnt to NVM - if (isAppDownlink) { - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID, fcnt32); - } else { - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID, fcnt32); } // check the MIC @@ -921,6 +1143,21 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { #endif return(RADIOLIB_ERR_CRC_MISMATCH); } + + // save current fcnt to respective frame counter + if (isAppDownlink) { + this->aFcntDown = fcnt32; + } else { + this->nFcntDown = fcnt32; + } + + // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) + bool isConfirmedDown = false; + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { + this->confFcntDown = this->aFcntDown; + isConfirmedDown = true; + } + (void)isConfirmedDown; // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); @@ -950,8 +1187,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { while(remLen > 0) { LoRaWANMacCommand_t cmd = { .cid = *foptsPtr, - .len = (uint8_t)(remLen - 1), .payload = { 0 }, + .len = (uint8_t)(remLen - 1), .repeat = 0, }; memcpy(cmd.payload, foptsPtr + 1, cmd.len); @@ -967,39 +1204,52 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { - uint8_t foptsNum = this->commandsUp.numCommands; size_t foptsBufSize = this->commandsUp.len; uint8_t foptsBuff[foptsBufSize]; - size_t idx = 0; - for(size_t i = 0; i < foptsNum; i++) { - LoRaWANMacCommand_t cmd = { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, }; - popMacCommand(&cmd, &this->commandsUp, i); - if(cmd.cid == 0) { - break; + uint8_t* foptsPtr = foptsBuff; + // append all MAC replies into fopts buffer + size_t i = 0; + for (; i < this->commandsUp.numCommands; i++) { + LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; + memcpy(foptsPtr, &cmd, 1 + cmd.len); + foptsPtr += cmd.len + 1; + } + RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); + + // pop the commands from back to front + for (; i >= 0; i--) { + if(this->commandsUp.commands[i].repeat > 0) { + this->commandsUp.commands[i].repeat--; + } else { + deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); } - foptsBuff[idx] = cmd.cid; - for(size_t i = 1; i < cmd.len; i++) { - foptsBuff[idx + i] = cmd.payload[i]; + if(i == 0) { + break; } - idx += cmd.len + 1; } - RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", foptsNum); - RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); - isMACPayload = true; + this->isMACPayload = true; this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - uint8_t strDown[this->band->payloadLenMax[this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; + uint8_t strDown[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; size_t lenDown = 0; state = this->downlink(strDown, &lenDown); RADIOLIB_ASSERT(state); } - // write the MAC command queue to nvm for next uplink - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)]; - memcpy(&queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); } + // a downlink was received, so reset the ADR counter to this uplink's fcnt + this->adrFcnt = this->fcntUp; + + // LoRaWANEvent: + // dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK + // confirmed = isConfirmedDown + // confirming = isConfirmingUp + // power = this->txPwrCur + // fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown + // port = ... + // process payload (if there is any) if(payLen <= 0) { // no payload @@ -1014,14 +1264,46 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // there is payload, and so there should be a port too // TODO pass the port? *len = payLen - 1; + // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 - // TODO does the erratum hold here as well? - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], downlinkMsgLen, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !defined(RADIOLIB_STATIC_ONLY) delete[] downlinkMsg; #endif + return(RADIOLIB_ERR_NONE); +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed) { + // send the uplink + int16_t state = this->uplink(strUp, port, isConfirmed); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(strDown); + return(state); +} +#endif + +int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed) { + // send the uplink + int16_t state = this->uplink(strUp, port, isConfirmed); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(dataDown, lenDown); + return(state); +} + +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed) { + // send the uplink + int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(dataDown, lenDown); return(state); } @@ -1029,6 +1311,10 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { this->battLevel = battLevel; } +uint32_t LoRaWANNode::getFcntUp() { + return(this->fcntUp); +} + uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { if((msg == NULL) || (len == 0)) { return(0); @@ -1060,30 +1346,15 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { int16_t LoRaWANNode::setPhyProperties() { // set the physical layer configuration - int16_t state = RADIOLIB_ERR_NONE; - if(this->FSK) { - // for FSK, configure the channel - state = this->phyLayer->setFrequency(this->band->fskFreq); - RADIOLIB_ASSERT(state); - DataRate_t dr; - dr.fsk.bitRate = 50; - dr.fsk.freqDev = 25; - state = this->phyLayer->setDataRate(dr); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); - } - RADIOLIB_ASSERT(state); - + // set the maximum power supported by both the module and the band - int8_t pwr = this->band->powerMax; - state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { // go from the highest power in band and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(pwr--); + state = this->phyLayer->setOutputPower(this->txPwrCur--); } RADIOLIB_ASSERT(state); + this->txPwrCur++; uint8_t syncWord[3] = { 0 }; uint8_t syncWordLen = 0; @@ -1109,249 +1380,351 @@ int16_t LoRaWANNode::setPhyProperties() { return(state); } -int16_t LoRaWANNode::setupChannels() { - // find appropriate channel IDs for uplink and downlink, the uplink channel is random - int8_t chMin = -1; - int8_t chMax = -1; - if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_MASK) { - chMin = this->startChannel; - chMax = this->startChannel + this->numChannels; - } - int16_t state = this->findChannelId(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - &this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], - &this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], chMin, chMax); - RADIOLIB_ASSERT(state); - - // RX1 channel is not random, but determined by uplink channel - if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { - // for frequency-list type bands, it's just the previous uplink channel - this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; - this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; +int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { + size_t num = 0; + + // in case of frequency list-type band, copy the default TX channels into the available channels, with RX1 = TX + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // copy the default defined channels into the first slots + for(; num < 3 && this->band->txFreqs[num].enabled; num++) { + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + } + // if there is a cflist present, parse its frequencies into the next five slots, with datarate range copied from default channel 0 + if(cfList != nullptr) { + for(uint8_t i = 0; i < 5; i++, num++) { + LoRaWANChannel_t chnl; + chnl.enabled = true; + chnl.idx = num; + uint32_t freq = LoRaWANNode::ntoh(&cfList[3*i], 3); + chnl.freq = (float)freq/10000.0; + chnl.drMin = this->band->txFreqs[0].drMin; // drMin is equal for all channels + chnl.drMax = this->band->txFreqs[0].drMax; // drMax is equal for all channels + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", chnl.idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + } + } + for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } - } else { - // for mask type bands, it's the uplink mod num_downlink_channels - for(uint8_t i = 0; i < this->band->numChannelSpans; i++) { - const LoRaWANChannelSpan_t* span = &this->band->defaultChannels[i]; - if(span->direction == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { - this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] % span->numChannels; - this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = span->joinRequestDataRate; - break; + } else { // RADIOLIB_LORAWAN_BAND_FIXED + if(cfList != nullptr) { + uint8_t chSpan = 0; + uint8_t chNum = 0; + // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels + for(size_t chMaskCntl = 0; chMaskCntl < 5; chMaskCntl++) { + uint16_t mask = LoRaWANNode::ntoh(&cfList[2*chMaskCntl]); + RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, mask); + for(size_t i = 0; i < 16; i++) { + // if we must roll over to next span, reset chNum and move to next channel span + if(chNum >= this->band->txSpans[chSpan].numChannels) { + chNum = 0; + chSpan++; + } + + if(mask & (1UL << i)) { + if(chSpan >= this->band->numTxSpans) { + RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); + return(RADIOLIB_ERR_UNKNOWN); + } + LoRaWANChannel_t chnl; + chnl.enabled = true; + chnl.idx = chMaskCntl*16 + i; + chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; + chnl.drMin = this->band->txSpans[chSpan].drMin; + chnl.drMax = this->band->txSpans[chSpan].drMax; + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; + // downlink channels are dynamically calculated on each uplink in selectChannels() + RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + num++; + } + chNum++; + } + } + for(; chNum < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; chNum++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = RADIOLIB_LORAWAN_CHANNEL_NONE; } } } + return(RADIOLIB_ERR_NONE); +} - // based on the channel IDs, find the frequencies - state = this->findChannelFreq(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], - &this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]); - RADIOLIB_ASSERT(state); - state = this->findChannelFreq(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK], - &this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]); - RADIOLIB_ASSERT(state); - - // configure channel for uplink - state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); +int16_t LoRaWANNode::selectSubband(uint8_t idx) { + int16_t state = this->selectSubband((idx - 1) * 8, idx * 8 - 1); return(state); } -uint8_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate, const LoRaWANChannelSpan_t* span) { - uint8_t dataRateBand = 0; - uint8_t dataRateFound = 0; - if(dr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; i++) { - if(span->dataRates[i] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - dataRateBand = span->dataRates[i]; - dataRateFound = i; - break; - } - } - } else { - dataRateBand = span->dataRates[dr]; - dataRateFound = dr; +int16_t LoRaWANNode::selectSubband(uint8_t startChannel, uint8_t endChannel) { + if(this->isJoinedFlag) { + RADIOLIB_DEBUG_PRINTLN("There is already an active session - cannot change subband"); + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + RADIOLIB_DEBUG_PRINTLN("This is a dynamic band plan which does not support subbands"); + return(RADIOLIB_ERR_INVALID_CHANNEL); } - if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - dataRate->fsk.bitRate = 50; - dataRate->fsk.freqDev = 25; + uint8_t numChannels = endChannel - startChannel + 1; + if(startChannel > this->band->txSpans[0].numChannels) { + RADIOLIB_DEBUG_PRINTLN("There are only %d channels available in this band", this->band->txSpans[0].numChannels); + return(RADIOLIB_ERR_INVALID_CHANNEL); + } + if(startChannel + numChannels > this->band->txSpans[0].numChannels) { + numChannels = this->band->txSpans[0].numChannels - startChannel; + RADIOLIB_DEBUG_PRINTLN("Could only select %d channels due to end of band", numChannels); + } + if(numChannels > RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { + numChannels = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; + RADIOLIB_DEBUG_PRINTLN("Could only select %d channels due to specified limit", numChannels); + } - } else { - uint8_t bw = dataRateBand & 0x0C; - switch(bw) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - dataRate->lora.bandwidth = 125.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - dataRate->lora.bandwidth = 250.0; + LoRaWANChannel_t chnl; + for(size_t chNum = 0; chNum < numChannels; chNum++) { + chnl.enabled = true; + chnl.idx = startChannel + chNum; + chnl.freq = this->band->txSpans[0].freqStart + chnl.idx*this->band->txSpans[0].freqStep; + chnl.drMin = this->band->txSpans[0].drMin; + chnl.drMax = this->band->txSpans[0].drMax; + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = chnl; + // downlink channel is dynamically calculated on each uplink in selectChannels() + RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", chNum, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum].freq); + } + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::selectChannelsJR(uint16_t devNonce, uint8_t joinDr) { + LoRaWANChannel_t channelUp; + LoRaWANChannel_t channelDown; + uint8_t drUp; + uint8_t drDown; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // count the number of available channels for a join-request (default channels + join-request channels) + uint8_t numJRChannels = 0; + for(size_t i = 0; i < 3; i++) { + if(this->band->txFreqs[i].enabled) { + numJRChannels++; + } + if(this->band->txJoinReq[i].enabled) { + numJRChannels++; + } + } + + // cycle through the available channels (seed with devNonce) + uint8_t channelId = devNonce % numJRChannels; + + // find the channel whose index is selected + for(size_t i = 0; i < 3; i++) { + if(this->band->txFreqs[i].idx == channelId) { + channelUp = this->band->txFreqs[i]; break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - dataRate->lora.bandwidth = 500.0; + } + if(this->band->txJoinReq[i].idx == channelId) { + channelUp = this->band->txJoinReq[i]; + } + } + + // if join datarate is user-specified and valid, select that value; otherwise use + if(joinDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(joinDr >= channelUp.drMin && joinDr <= channelUp.drMax) { + drUp = joinDr; + } else { + RADIOLIB_DEBUG_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", joinDr, channelUp.drMin, channelUp.drMax); + joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + if(joinDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + drUp = int((channelUp.drMax + channelUp.drMin) / 2); + } + + // derive the downlink channel and datarate from the uplink channel and datarate + channelDown = channelUp; + drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, channelDown.drMin, channelDown.drMax); + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + uint8_t spanID = 0; + uint8_t channelID = 0; + uint8_t numEnabledChannels = 0; + // if there are any predefined channels because user selected a subband, select one of these channels + for(; numEnabledChannels < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; numEnabledChannels++) { + if(this->availableChannels[numEnabledChannels][RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].enabled == false) { break; - default: - dataRate->lora.bandwidth = 125.0; + } + } + if(numEnabledChannels > 0) { + uint8_t channelID = this->phyLayer->random(numEnabledChannels); + channelUp = this->availableChannels[channelID][RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + spanID = channelUp.idx / this->band->txSpans[0].numChannels; + channelID = channelUp.idx; + + } else { // no pre-selected subband, cycle through size-8 (or size-9) blocks + channelUp.enabled = true; + uint8_t numBlocks = this->band->txSpans[0].numChannels / 8; // calculate number of 8-channel blocks + uint8_t numBlockChannels = 8 + (this->band->numTxSpans == 2 ? 1 : 0); // add a 9th channel if there's a second span + uint8_t blockID = devNonce % numBlocks; // currently selected block (seed with devNonce) + channelID = this->phyLayer->random(numBlockChannels); // select randomly from these 8 or 9 channels + RADIOLIB_DEBUG_PRINTLN("blocks: %d, channels/block: %d, blockID: %d, channelID: %d", numBlocks, numBlockChannels, blockID, channelID); + + // if channel 0-7 is selected, retrieve this channel from span 0; otherwise span 1 + if(channelID < 8) { + spanID = 0; + channelUp.idx = blockID * 8 + channelID; + } else { + spanID = 1; + channelUp.idx = blockID; + } + channelUp.freq = this->band->txSpans[spanID].freqStart + channelUp.idx*this->band->txSpans[spanID].freqStep; } - dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; - dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; + // for fixed channel plans, the user-specified datarate is ignored and span-specific value must be used + drUp = this->band->txSpans[spanID].joinRequestDataRate; + + // derive the downlink channel and datarate from the uplink channel and datarate + channelDown.enabled = true; + channelDown.idx = channelID % this->band->rx1Span.numChannels; + channelDown.freq = this->band->rx1Span.freqStart + channelDown.idx*this->band->rx1Span.freqStep; + channelDown.drMin = this->band->rx1Span.drMin; + channelDown.drMax = this->band->rx1Span.drMax; + drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, channelDown.drMin, channelDown.drMax); + } + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = channelUp; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDown; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; - return(dataRateFound); + return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::findChannelId(uint8_t dir, uint8_t* ch, uint8_t* dr, int8_t min, int8_t max) { - // find the first channel span that supports the requested direction - uint8_t spanId = 0; - LoRaWANChannelSpan_t* span = NULL; - for(; spanId < this->band->numChannelSpans; spanId++) { - span = (LoRaWANChannelSpan_t*)&this->band->defaultChannels[spanId]; - if((span->direction == dir) || (span->direction == RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH)) { +int16_t LoRaWANNode::selectChannels() { + // figure out which channel IDs are enabled (chMask may have disabled some) and are valid for the current datarate + uint8_t numChannels = 0; + uint8_t channelsEnabled[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + channelsEnabled[numChannels] = i; + numChannels++; + } + } else { break; } } - - // shouldn't happen, but just to be sure - if(!span) { - RADIOLIB_DEBUG_PRINTLN("findChannelId span not found"); + if(numChannels == 0) { + RADIOLIB_DEBUG_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); return(RADIOLIB_ERR_INVALID_CHANNEL); } + // select a random ID & channel from the list of enabled and possible channels + uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // for dynamic bands, the downlink channel is the one matched to the uplink channel + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels + LoRaWANChannel_t channelDn; + channelDn.enabled = true; + channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; + channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; + channelDn.drMin = this->band->rx1Span.drMin; + channelDn.drMax = this->band->rx1Span.drMax; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn; - // if requested, save the data rate - if(dr) { - *dr = span->joinRequestDataRate; } + uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; - // determine min and max based on number of channels in span and user constraints - uint8_t chMin = (min > 0) ? min : 0; - uint8_t chMax = (max > 0) ? max : span->numChannels; - - // select channel ID as random number between min and max (global number 0 - N for single direction) - int32_t chId = this->phyLayer->random(chMin, chMax); - *ch = chId; return(RADIOLIB_ERR_NONE); } -LoRaWANChannelSpan_t* LoRaWANNode::findChannelSpan(uint8_t dir, uint8_t ch, uint8_t* spanChannelId) { - // find the span based on the channel ID - uint8_t chanCtr = 0; - *spanChannelId = 0; - for(uint8_t span = 0; span < this->band->numChannelSpans; span++) { - // check if this channel span can be used - uint8_t direction = this->band->defaultChannels[span].direction; - if((direction != dir) && (direction != RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH)) { - continue; - } - - // iterate over the usable spans to the channel ID - for(; *spanChannelId < this->band->defaultChannels[span].numChannels; (*spanChannelId)++) { - if(chanCtr >= ch) { - // we found it, return the pointer (channel ID within the span is already set) - return((LoRaWANChannelSpan_t*)&this->band->defaultChannels[span]); - } - chanCtr++; +int16_t LoRaWANNode::setDatarate(uint8_t drUp) { + // find the minimum and maximum available datarates by checking the enabled uplink channels + uint8_t drMin = RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; + uint8_t drMax = 0; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + drMin = RADIOLIB_MIN(drMin, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin); + drMax = RADIOLIB_MAX(drMax, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax); } } + if((drUp < drMin) || (drUp > drMax)) { + RADIOLIB_DEBUG_PRINTLN("Cannot configure DR %d (min: %d, max: %d)", drUp, drMin, drMax); + return(RADIOLIB_ERR_DATA_RATE_INVALID); + } + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; - return(NULL); + RADIOLIB_DEBUG_PRINTLN("Configured DR up = %d", drUp); + + return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::findChannelFreq(uint8_t dir, uint8_t ch, float* freq) { - // find the channel span based on channel ID and direction - uint8_t spanChannelId = 0; - LoRaWANChannelSpan_t* span = findChannelSpan(dir, ch, &spanChannelId); - if(!span) { - return(RADIOLIB_ERR_INVALID_CHANNEL); +void LoRaWANNode::setADR(bool enable) { + this->adrEnabled = enable; +} + +int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { + uint8_t dataRateBand = this->band->dataRates[dr]; + + if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + dataRate->fsk.bitRate = 50; + dataRate->fsk.freqDev = 25; + + } else { + uint8_t bw = dataRateBand & 0x0C; + switch(bw) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + dataRate->lora.bandwidth = 125.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + dataRate->lora.bandwidth = 250.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + dataRate->lora.bandwidth = 500.0; + break; + default: + dataRate->lora.bandwidth = 125.0; + } + + dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; + dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; + RADIOLIB_DEBUG_PRINTLN("DR %d: LORA (SF: %d, BW: %f, CR: %d)", + dataRateBand, dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); } - // set the frequency - *freq = span->freqStart + span->freqStep * (float)spanChannelId; return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::configureChannel(uint8_t dir) { // set the frequency - RADIOLIB_DEBUG_PRINT("Channel frequency %cL = ", dir ? 'D' : 'U'); - RADIOLIB_DEBUG_PRINT_FLOAT(this->channelFreq[dir], 3); - RADIOLIB_DEBUG_PRINTLN(" MHz"); - int state = this->phyLayer->setFrequency(this->channelFreq[dir]); + RADIOLIB_DEBUG_PRINTLN(""); + RADIOLIB_DEBUG_PRINTLN("Channel frequency %cL = %f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); RADIOLIB_ASSERT(state); - // find the channel span based on channel ID and direction - uint8_t spanChannelId = 0; - LoRaWANChannelSpan_t* span = findChannelSpan(dir, this->chIndex[dir], &spanChannelId); - if(!span) { - return(RADIOLIB_ERR_INVALID_CHANNEL); + // if this channel is an FSK channel, toggle the FSK switch + if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + this->FSK = true; + } else { + this->FSK = false; } - // set the data rate - DataRate_t dataRate; - this->dataRate[dir] = findDataRate(this->dataRate[dir], &dataRate, span); - state = this->phyLayer->setDataRate(dataRate); - return(state); -} - -int16_t LoRaWANNode::sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen) { - // build the command - size_t macReqLen = 1 + payloadLen; - #if !defined(RADIOLIB_STATIC_ONLY) - uint8_t* macReqBuff = new uint8_t[macReqLen]; - #else - uint8_t macReqBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #endif - macReqBuff[0] = cid; - memcpy(&macReqBuff[1], payload, payloadLen); - - // uplink it - int16_t state = this->uplink(macReqBuff, macReqLen, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] macReqBuff; - #endif + DataRate_t dr; + findDataRate(this->dataRates[dir], &dr); + state = this->phyLayer->setDataRate(dr); RADIOLIB_ASSERT(state); - // build the reply buffer - size_t macRplLen = 1 + replyLen; - #if !defined(RADIOLIB_STATIC_ONLY) - uint8_t* macRplBuff = new uint8_t[this->band->payloadLenMax[this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; - #else - uint8_t macRplBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #endif - - // wait for reply from the server - size_t rxRplLen = 0; - state = this->downlink(macRplBuff, &rxRplLen); - if(state != RADIOLIB_ERR_NONE) { - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] macRplBuff; - #endif - return(state); - } - - RADIOLIB_DEBUG_PRINTLN("macRplBuff:"); - RADIOLIB_DEBUG_HEXDUMP(macRplBuff, rxRplLen); - - // check the length - it may be longer than expected - // if the server decided to append more MAC commands, but never shorter - // TODO how to handle the additional command(s)? - if(rxRplLen < macRplLen) { - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] macRplBuff; - #endif - return(RADIOLIB_ERR_DOWNLINK_MALFORMED); - } - - // check the CID - if(macRplBuff[0] != cid) { - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] macRplBuff; - #endif - return(RADIOLIB_ERR_INVALID_CID); + if(this->FSK) { + state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); } - // copy the data - memcpy(reply, &macRplBuff[1], replyLen); - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] macRplBuff; - #endif - return(state); } @@ -1361,48 +1734,12 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ } memcpy(&queue->commands[queue->numCommands], cmd, sizeof(LoRaWANMacCommand_t)); - /*RADIOLIB_DEBUG_PRINTLN("push MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", - queue->commands[queue->numCommands - 1].cid, - queue->commands[queue->numCommands - 1].len, - queue->commands[queue->numCommands - 1].payload[0], - queue->commands[queue->numCommands - 1].payload[1], - queue->commands[queue->numCommands - 1].payload[2], - queue->commands[queue->numCommands - 1].payload[3], - queue->commands[queue->numCommands - 1].payload[4], - queue->commands[queue->numCommands - 1].repeat);*/ queue->numCommands++; queue->len += 1 + cmd->len; // 1 byte for command ID, len bytes for payload return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, size_t index) { - if(queue->numCommands == 0) { - return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); - } - - if(cmd) { - // RADIOLIB_DEBUG_PRINTLN("pop MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", - // queue->commands[index].cid, - // queue->commands[index].len, - // queue->commands[index].payload[0], - // queue->commands[index].payload[1], - // queue->commands[index].payload[2], - // queue->commands[index].payload[3], - // queue->commands[index].payload[4], - // queue->commands[index].repeat); - memcpy(cmd, &queue->commands[index], sizeof(LoRaWANMacCommand_t)); - } - - if(queue->commands[index].repeat > 0) { - queue->commands[index].repeat--; - } else { - deleteMacCommand(queue->commands[index].cid, queue); - } - - return(RADIOLIB_ERR_NONE); -} - int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue) { if(queue->numCommands == 0) { return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); @@ -1410,19 +1747,10 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que for(size_t index = 0; index < queue->numCommands; index++) { if(queue->commands[index].cid == cid) { - // RADIOLIB_DEBUG_PRINTLN("delete MAC CID = %02x, len = %d, payload = %02x %02x %02x %02x %02x, repeat = %d ", - // queue->commands[index].cid, - // queue->commands[index].len, - // queue->commands[index].payload[0], - // queue->commands[index].payload[1], - // queue->commands[index].payload[2], - // queue->commands[index].payload[3], - // queue->commands[index].payload[4], - // queue->commands[index].repeat); queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload // move all subsequent commands one forward in the queue if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { - memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index) * sizeof(LoRaWANMacCommand_t)); + memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); } // set the latest element to all 0 memset(&queue->commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); @@ -1466,55 +1794,102 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { case(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR): { // get the ADR configuration - uint8_t dr = (cmd->payload[0] & 0xF0) >> 4; + // TODO all these configuration should only be set if all ACKs are set, otherwise retain previous state (per spec) + uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; uint8_t txPower = cmd->payload[0] & 0x0F; uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; uint8_t nbTrans = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", dr, txPower, chMask, chMaskCntl, nbTrans); + RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); // apply the configuration uint8_t drAck = 0; - if(dr != 0x0F) { - // first figure out which channel span this data rate applies to - // TODO do that by processing the chMask/chMaskCntl? - uint8_t spanChannelId = 0; - LoRaWANChannelSpan_t* span = findChannelSpan(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, this->chIndex[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &spanChannelId); - - // seems to be only applicable to uplink - if(span) { - DataRate_t dataRate; - this->dataRate[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = findDataRate(dr, &dataRate, span); - if(this->phyLayer->setDataRate(dataRate) == RADIOLIB_ERR_NONE) { - RADIOLIB_DEBUG_PRINTLN("ADR set dr = %d channel = %d", dr, spanChannelId); - drAck = 1; - } - } - - } else { + if(drUp == 0x0F) { drAck = 1; - - } + } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + drAck = 1; + } // try to apply the power configuration uint8_t pwrAck = 0; - if(txPower != 0x0F) { + if(txPower == 0x0F) { + pwrAck = 1; + } else { int8_t pwr = this->band->powerMax - 2*txPower; if(this->phyLayer->setOutputPower(pwr) == RADIOLIB_ERR_NONE) { RADIOLIB_DEBUG_PRINTLN("ADR set pwr = %d", pwr); pwrAck = 1; } + this->txPwrCur = pwr; + } - } else { - pwrAck = 1; + uint8_t chMaskAck = 1; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(chMaskCntl == 0) { + // if chMaskCntl == 0, apply the mask by looking at each channel bit + RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); + if(chMask & (1UL << i)) { + // if it should be enabled but is not currently defined, stop immediately + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + chMaskAck = 0; + break; + } + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } else { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; + } + + } else if(chMaskCntl == 6) { + // if chMaskCntl == 6, enable all defined channels + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } + } + + } + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // delete any prior ADR responses from the uplink queue, but do not care if none is present yet + (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR, &this->commandsUp); + RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); + uint8_t num = 0; + uint8_t chNum = chMaskCntl*16; + uint8_t chSpan = 0; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("chNum: %d, chSpan: %d, i: %d, mask: %d", chNum, chSpan, i, chMask & (1UL << i)); + // if we must roll over to next span, reset chNum and move to next channel span + if(chNum >= this->band->txSpans[chSpan].numChannels) { + chNum = 0; + chSpan++; + } + + if(chMask & (1UL << i)) { + if(chSpan >= this->band->numTxSpans) { + RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); + return(RADIOLIB_ERR_UNKNOWN); + } + LoRaWANChannel_t chnl; + chnl.enabled = true; + chnl.idx = chMaskCntl*16 + i; + chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; + chnl.drMin = this->band->txSpans[chSpan].drMin; + chnl.drMax = this->band->txSpans[chSpan].drMax; + availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; + // downlink channels are dynamically calculated on each uplink in selectChannels() + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", num, chnl.idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + num++; + } + chNum++; + } } + // TODO should we actually save the channels because the masks may have changed stuff? + // this may wear the storage quickly on more mobile devices / changing RF environment - // TODO implement repeated uplinks with nbTrans - (void)nbTrans; - // TODO implement channel mask - uint8_t chMaskAck = 0; - (void)chMask; - (void)chMaskCntl; + this->nbTrans = nbTrans; // send the reply cmd->len = 1; @@ -1535,29 +1910,22 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { case(RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP): { // get the configuration - uint8_t rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; - uint8_t rx2DataRate = cmd->payload[0] & 0x0F; + this->rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; + uint8_t rx1OffsAck = 1; + this->rx2.drMax = cmd->payload[0] & 0x0F; + uint8_t rx2Ack = 1; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); - RADIOLIB_DEBUG_PRINTLN("RX Param: rx1DrOffset = %d, rx2DataRate = %d, freq = %d", rx1DrOffset, rx2DataRate, freqRaw); - + this->rx2.freq = (float)freqRaw/10000.0; + RADIOLIB_DEBUG_PRINTLN("Rx param REQ: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); + // apply the configuration - float freq = (float)freqRaw/10000.0; - float prevFreq = this->channelFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; uint8_t chanAck = 0; - if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { - this->backupFreq = freq; + if(this->phyLayer->setFrequency(this->rx2.freq) == RADIOLIB_ERR_NONE) { chanAck = 1; - this->phyLayer->setFrequency(prevFreq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - // TODO process the RX2 data rate - (void)rx2DataRate; - uint8_t rx2Ack = 0; - - // TODO process the data rate offset - (void)rx1DrOffset; - uint8_t rx1OffsAck = 0; - + // TODO this should be sent repeatedly until the next downlink // send the reply cmd->len = 1; cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); @@ -1585,18 +1953,86 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { float freq = (float)freqRaw/10000.0; uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; uint8_t minDr = cmd->payload[4] & 0x0F; - RADIOLIB_DEBUG_PRINT("New channel: index = %d, freq = ", chIndex); - RADIOLIB_DEBUG_PRINT_FLOAT(freq, 3); - RADIOLIB_DEBUG_PRINTLN(" MHz, maxDr = %d, minDr = %d", maxDr, minDr); + RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); + uint8_t newChAck = 0; + uint8_t freqAck = 0; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + // find first empty channel and configure this as the new channel + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx = chIndex; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq = freq; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin = minDr; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax = maxDr; + + // downlink channel is identical to uplink channel + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; + newChAck = 1; + + // check if the frequency is possible + if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq) == RADIOLIB_ERR_NONE) { + freqAck = 1; + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + } + + break; + } + } + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // update saved frequencies + this->saveChannels(); +#endif + + // send the reply + cmd->len = 1; + cmd->payload[0] = (newChAck << 1) | (freqAck << 0); + + pushMacCommand(cmd, &this->commandsUp); - // TODO implement this - (void)chIndex; - (void)freq; - (void)maxDr; - (void)minDr; return(5); } break; + case(RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL): { + // get the configuration + uint8_t chIndex = cmd->payload[0]; + uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); + float freq = (float)freqRaw/10000.0; + RADIOLIB_DEBUG_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); + uint8_t freqDlAck = 0; + uint8_t freqUlAck = 0; + + // check if the frequency is possible + if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { + freqDlAck = 1; + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + } + + // update the downlink frequency + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq = freq; + // check if the corresponding uplink frequency is actually set + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { + freqUlAck = 1; + } + } + } + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // update saved frequencies + this->saveChannels(); +#endif + + // send the reply + cmd->len = 1; + cmd->payload[0] = (freqUlAck << 1) | (freqDlAck << 0); + + pushMacCommand(cmd, &this->commandsUp); + + return(4); + } break; + case(RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; @@ -1635,21 +2071,6 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(1); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL): { - // get the configuration - uint8_t chIndex = cmd->payload[0]; - uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); - float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINT("DL channel: index = %d, freq = ", chIndex); - RADIOLIB_DEBUG_PRINT_FLOAT(freq, 3); - RADIOLIB_DEBUG_PRINTLN(" MHz"); - - // TODO implement this - (void)chIndex; - (void)freq; - return(4); - } break; - case(RADIOLIB_LORAWAN_MAC_CMD_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; @@ -1662,12 +2083,10 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } break; case(RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP): { - // TODO implement this - uint8_t limitExp = (cmd->payload[0] & 0xF0) >> 4; - uint8_t delayExp = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", limitExp, delayExp); - (void)limitExp; - (void)delayExp; + this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; + this->adrDelayExp = cmd->payload[0] & 0x0F; + RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); + return(1); } break; @@ -1675,9 +2094,7 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // TODO implement this - sent by gateway as reply to node request uint32_t gpsEpoch = LoRaWANNode::ntoh(&cmd->payload[0]); uint8_t fraction = cmd->payload[4]; - RADIOLIB_DEBUG_PRINT("Network time: gpsEpoch = %d s, delayExp = ", gpsEpoch, (float)fraction/256.0f); - RADIOLIB_DEBUG_PRINT_FLOAT((float)fraction/256.0f, 2); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)fraction/256.0f); (void)gpsEpoch; (void)fraction; return(5); @@ -1712,6 +2129,50 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(0); } +// The following function enables LMAC, a CSMA scheme for LoRa as specified +// in the LoRa Alliance Technical Recommendation #13. +// A user may enable CSMA to provide frames an additional layer of protection from interference. +// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma +void LoRaWANNode::performCSMA() { + + // Compute initial random back-off. + // When BO is reduced to zero, the function returns and the frame is transmitted. + uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1); + while (BO > 0) { + // DIFS: Check channel for DIFS_slots + bool channelFreeDuringDIFS = true; + for (uint8_t i = 0; i < this->difsSlots; i++) { + if (performCAD()) { + RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); + channelFreeDuringDIFS = false; + // Channel is occupied during DIFS, hop to another. + this->selectChannels(); + break; + } + } + // Start reducing BO counter if DIFS slot was free. + if (channelFreeDuringDIFS) { + // Continue decrementing BO with per each CAD reporting free channel. + while (BO > 0) { + if (performCAD()) { + RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO"); + // Channel is busy during CAD, hop to another and return to DIFS state again. + this->selectChannels(); + break; // Exit loop. Go back to DIFS state. + } + BO--; // Decrement BO by one if channel is free + } + } + } +} +bool LoRaWANNode::performCAD() { + int16_t state = this->phyLayer->scanChannel(); + if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { + return true; // Channel is busy + } + return false; // Channel is free +} + void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) { // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; @@ -1732,6 +2193,7 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext size_t remLen = len; for(size_t i = 0; i < numBlocks; i++) { + if(counter) { encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; } @@ -1778,52 +2240,4 @@ void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { } } -// The following function enables LMAC, a CSMA scheme for LoRa as specified -// in the LoRa Alliance Technical Recommendation #13. -// A user may enable CSMA to provide frames an additional layer of protection from interference. -// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma -void LoRaWANNode::performCSMA() { - - // Compute initial random back-off. - // When BO is reduced to zero, the function returns and the frame is transmitted. - uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1); - - while (BO > 0) { - // DIFS: Check channel for DIFS_slots - bool channelFreeDuringDIFS = true; - for (uint8_t i = 0; i < this->difsSlots; i++) { - if (performCAD()) { - RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); - channelFreeDuringDIFS = false; - // Channel is occupied during DIFS, hop to another. - this->setupChannels(); - break; - } - } - - // Start reducing BO counter if DIFS slot was free. - if (channelFreeDuringDIFS) { - // Continue decrementing BO with per each CAD reporting free channel. - while (BO > 0) { - if (performCAD()) { - RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO"); - // Channel is busy during CAD, hop to another and return to DIFS state again. - this->setupChannels(); - break; // Exit loop. Go back to DIFS state. - } - BO--; // Decrement BO by one if channel is free - } - } - } -} - -bool LoRaWANNode::performCAD() { - int16_t state = this->phyLayer->scanChannel(); - - if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { - return true; // Channel is busy - } - return false; // Channel is free -} - -#endif \ No newline at end of file +#endif diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 82b081277a..5d0eacc151 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -6,7 +6,7 @@ #include "../../utils/Cryptography.h" // version of NVM table layout (NOT the LoRaWAN version) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION (0x01) +#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION (0x01) // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) @@ -69,9 +69,10 @@ #define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0) #define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0) #define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0) -#define RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES (0) -#define RADIOLIB_LORAWAN_CFLIST_TYPE_MASK (1) -#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (16) +#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) +#define RADIOLIB_LORAWAN_BAND_FIXED (1) +#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) +#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 1) // reserve first bit for enable-flag // recommended default settings #define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) @@ -81,8 +82,8 @@ #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) #define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384) -#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT (64) -#define RADIOLIB_LORAWAN_ADR_ACK_DELAY (32) +#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP (0x06) +#define RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP (0x05) #define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) #define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000) #define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2) @@ -134,6 +135,7 @@ // payload encryption/MIC blocks common layout #define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0) +#define RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS (1) #define RADIOLIB_LORAWAN_BLOCK_DIR_POS (5) #define RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS (6) #define RADIOLIB_LORAWAN_BLOCK_FCNT_POS (10) @@ -150,7 +152,7 @@ #define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) // magic word saved in persistent memory upon activation -#define RADIOLIB_LORAWAN_MAGIC (0x12AD101B) +#define RADIOLIB_LORAWAN_MAGIC (0x39EA) // MAC commands #define RADIOLIB_LORAWAN_MAC_CMD_RESET (0x01) @@ -170,24 +172,46 @@ #define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP (0x0F) #define RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY (0x80) +// unused frame counter value +#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) + // the length of internal MAC command queue - hopefully this is enough for most use cases #define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8) // the maximum number of simultaneously available channels -#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (8) +#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. To save space, adjacent channels are saved in "spans". */ -struct LoRaWANChannelSpan_t { - /*! \brief Whether this channel span is for uplink, downlink, or both directions*/ - uint8_t direction; +struct LoRaWANChannel_t { + /*! \brief Whether this channel is enabled (can be used) or is disabled */ + bool enabled; - /*! \brief Allowed data rates for a join request message */ - uint8_t joinRequestDataRate; + /*! \brief The channel number, as specified by defaults or the network */ + uint8_t idx; + + /*! \brief The channel frequency */ + float freq; + + /*! \brief Minimum allowed datarate for this channel */ + uint8_t drMin; + + /*! \brief Maximum allowed datarate for this channel (inclusive) */ + uint8_t drMax; +}; + +// alias for unused channel +#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } +/*! + \struct LoRaWANChannelSpan_t + \brief Structure to save information about LoRaWAN channels. + To save space, adjacent channels are saved in "spans". +*/ +struct LoRaWANChannelSpan_t { /*! \brief Total number of channels in the span */ uint8_t numChannels; @@ -197,23 +221,26 @@ struct LoRaWANChannelSpan_t { /*! \brief Frequency step between adjacent channels */ float freqStep; - /*! \brief Array of datarates supported by all channels in the span */ - uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; + /*! \brief Minimum allowed datarate for all channels in this span */ + uint8_t drMin; + + /*! \brief Maximum allowed datarate for all channels in this span (inclusive) */ + uint8_t drMax; + + /*! \brief Allowed data rates for a join request message */ + uint8_t joinRequestDataRate; }; // alias for unused channel span -#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_NONE, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .numChannels = 0, .freqStart = 0, .freqStep = 0, .dataRates = { 0 } } +#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } /*! \struct LoRaWANBand_t \brief Structure to save information about LoRaWAN band */ struct LoRaWANBand_t { - /*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */ - uint8_t downlinkDataRateBase; - - /*! \brief The minimum allowed downlink data rate. Used to calculate data rate changes for adaptive data rate */ - uint8_t downlinkDataRateMin; + /*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */ + uint8_t bandType; /*! \brief Array of allowed maximum payload lengths for each data rate */ uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; @@ -224,20 +251,29 @@ struct LoRaWANBand_t { /*! \brief Number of power steps in this band */ int8_t powerNumSteps; - /*! \brief Whether the optional channels are defined as list of frequencies or bit mask */ - uint8_t cfListType; + /*! \brief A set of default uplink (TX) channels for frequency-type bands */ + LoRaWANChannel_t txFreqs[3]; - /*! \brief FSK channel frequency */ - float fskFreq; + /*! \brief A set of possible extra channels for the Join-Request message for frequency-type bands */ + LoRaWANChannel_t txJoinReq[3]; - /*! \brief Number of channel spans in the band */ - uint8_t numChannelSpans; + /*! \brief The number of TX channel spans for mask-type bands */ + uint8_t numTxSpans; + + /*! \brief Default uplink (TX) channel spans for mask-type bands, including Join-Request parameters */ + LoRaWANChannelSpan_t txSpans[2]; + + /*! \brief Default downlink (RX1) channel span for mask-type bands */ + LoRaWANChannelSpan_t rx1Span; + + /*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */ + uint8_t rx1DataRateBase; - /*! \brief Default uplink (TX/RX1) channels defined by LoRaWAN Regional Parameters */ - LoRaWANChannelSpan_t defaultChannels[3]; + /*! \brief Backup channel for downlink (RX2) window */ + LoRaWANChannel_t rx2; - /*! \brief Backup downlink (RX2) channel - just a single channel, but using the same structure for convenience */ - LoRaWANChannelSpan_t backupChannel; + /*! \brief The corresponding datarates, bandwidths and coding rates for DR index */ + uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; }; // supported bands @@ -259,20 +295,20 @@ struct LoRaWANMacCommand_t { /*! \brief The command ID */ uint8_t cid; - /*! \brief Length of the payload */ - uint8_t len; - /*! \brief Payload buffer (5 bytes is the longest possible) */ uint8_t payload[5]; + /*! \brief Length of the payload */ + uint8_t len; + /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ uint8_t repeat; }; struct LoRaWANMacCommandQueue_t { + uint8_t numCommands; + uint8_t len; LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; - size_t numCommands; - size_t len; }; /*! @@ -281,31 +317,12 @@ struct LoRaWANMacCommandQueue_t { */ class LoRaWANNode { public: - /*! \brief Set to true to force the node to only use FSK channels. Set to false by default. */ - bool FSK; - /*! \brief Starting channel offset. - Some band plans only support a subset of available channels. - Set to a positive value to set the first channel that will be used (e.g. 8 for US915 FSB2 used by TTN). - By default -1 (no channel offset). */ - int8_t startChannel; - - /*! \brief Number of supported channels. - Some band plans only support a subset of available channels. - Set to a positive value to set the number of channels that will be used - (e.g. 8 for US915 FSB2 used by TTN). By default -1 (no channel offset). */ - int8_t numChannels; - - /*! \brief Num of Back Off(BO) slots to be decremented after DIFS phase. 0 to disable BO. - A random BO avoids collisions in the case where two or more nodes start the CSMA - process at the same time. */ - uint8_t backoffMax; + // Offset between TX and RX1 (such that RX1 has equal or lower DR) + uint8_t rx1DrOffset; - /*! \brief Num of CADs to estimate a clear CH. */ - uint8_t difsSlots; - - /*! \brief enable/disable CSMA for LoRaWAN. */ - bool enableCSMA; + // RX2 channel properties - may be changed by MAC command + LoRaWANChannel_t rx2; /*! \brief Default constructor. @@ -314,6 +331,7 @@ class LoRaWANNode { */ LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band); +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) /*! \brief Wipe internal persistent parameters. This will reset all counters and saved variables, so the device will have to rejoin the network. @@ -321,18 +339,11 @@ class LoRaWANNode { void wipe(); /*! - \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. - \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. - \param difsSlots Num of CADs to estimate a clear CH. - \param enableCSMA enable/disable CSMA for LoRaWAN. - */ - void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); - - /*! - \brief Restore OTAA session by loading information from persistent storage. + \brief Restore session by loading information from persistent storage. \returns \ref status_codes */ - int16_t restoreOTAA(); + int16_t restore(); +#endif /*! \brief Join network by performing over-the-air activation. By this procedure, @@ -341,10 +352,12 @@ class LoRaWANNode { \param devEUI 8-byte device identifier. \param nwkKey Pointer to the network AES-128 key. \param appKey Pointer to the application AES-128 key. + \param joinDr (OTAA:) The datarate at which to send the join-request; (ABP:) ignored \param force Set to true to force joining even if previously joined. + \returns \ref status_codes */ - int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, bool force = false); /*! \brief Join network by performing activation by personalization. @@ -354,36 +367,50 @@ class LoRaWANNode { \param appSKey Pointer to the application session AES-128 key. \param fNwkSIntKey Pointer to the network session F key (LoRaWAN 1.1), unused for LoRaWAN 1.0. \param sNwkSIntKey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param force Set to true to force a new session, even if one exists. \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL); + int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false); + + /*! \brief Whether there is an ongoing session active */ + bool isJoined(); + + /*! + \brief Save the current state of the session. + All variables are compared to what is saved and only the differences are rewritten. + \returns \ref status_codes + */ + int16_t saveSession(); #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Send a message to the server. \param str Address of Arduino String that will be transmitted. \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. \returns \ref status_codes */ - int16_t uplink(String& str, uint8_t port); + int16_t uplink(String& str, uint8_t port, bool isConfirmed = false); #endif /*! \brief Send a message to the server. \param str C-string that will be transmitted. \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. \returns \ref status_codes */ - int16_t uplink(const char* str, uint8_t port); + int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false); /*! \brief Send a message to the server. \param data Data to send. \param len Length of the data. \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. \returns \ref status_codes */ - int16_t uplink(uint8_t* data, size_t len, uint8_t port); + int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false); #if defined(RADIOLIB_BUILD_ARDUINO) /*! @@ -402,6 +429,41 @@ class LoRaWANNode { */ int16_t downlink(uint8_t* data, size_t* len); + #if defined(RADIOLIB_BUILD_ARDUINO) + /*! + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param strUp Address of Arduino String that will be transmitted. + \param port Port number to send the message to. + \param strDown Address of Arduino String to save the received data. + \param isConfirmed Whether to send a confirmed uplink or not. + \returns \ref status_codes + */ + int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false); + #endif + + /*! + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param strUp C-string that will be transmitted. + \param port Port number to send the message to. + \param dataDown Buffer to save received data into. + \param lenDown Pointer to variable that will be used to save the number of received bytes. + \param isConfirmed Whether to send a confirmed uplink or not. + \returns \ref status_codes + */ + int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false); + + /*! + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param dataUp Data to send. + \param lenUp Length of the data. + \param port Port number to send the message to. + \param dataDown Buffer to save received data into. + \param lenDown Pointer to variable that will be used to save the number of received bytes. + \param isConfirmed Whether to send a confirmed uplink or not. + \returns \ref status_codes + */ + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false); + /*! \brief Set device status. \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, @@ -409,6 +471,47 @@ class LoRaWANNode { */ void setDeviceStatus(uint8_t battLevel); + /*! \brief Returns the last uplink's frame counter */ + uint32_t getFcntUp(); + + /*! + \brief Set uplink datarate. This should not be used when ADR is enabled. + \param dr Datarate to use for uplinks. + \returns \ref status_codes + */ + int16_t setDatarate(uint8_t drUp); + + /*! + \brief Toggle ADR to on or off + \param enable Whether to disable ADR or not + */ + void setADR(bool enable = true); + + /*! + \brief Select a single subband (8 channels) for fixed bands such as US915. + Only available before joining a network. + \param idx The subband to be used (starting from 1!) + \returns \ref status_codes + */ + int16_t selectSubband(uint8_t idx); + + /*! + \brief Select a set of channels for fixed bands such as US915. + Only available before joining a network. + \param startChannel The first channel of the band to be used (inclusive) + \param endChannel The last channel of the band to be used (inclusive) + \returns \ref status_codes + */ + int16_t selectSubband(uint8_t startChannel, uint8_t endChannel); + + /*! + \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. + \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. + \param difsSlots Num of CADs to estimate a clear CH. + \param enableCSMA enable/disable CSMA for LoRaWAN. + */ + void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); + #if !defined(RADIOLIB_GODMODE) private: #endif @@ -416,14 +519,14 @@ class LoRaWANNode { const LoRaWANBand_t* band = NULL; LoRaWANMacCommandQueue_t commandsUp = { - .commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } }, .numCommands = 0, .len = 0, + .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, }; LoRaWANMacCommandQueue_t commandsDown = { - .commands = { { .cid = 0, .len = 0, .payload = { 0 }, .repeat = 0, } }, .numCommands = 0, .len = 0, + .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, }; // the following is either provided by the network server (OTAA) @@ -434,29 +537,62 @@ class LoRaWANNode { uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + + // device-specific parameters, persistent through sessions + uint16_t devNonce = 0; + uint32_t joinNonce = 0; + + // session-specific parameters + uint32_t homeNetId = 0; + uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; + uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + uint8_t nbTrans = 1; // Number of allowed frame retransmissions + uint8_t txPwrCur = 0; + uint32_t fcntUp = 0; + uint32_t aFcntDown = 0; + uint32_t nFcntDown = 0; + uint32_t confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + uint32_t confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + uint32_t adrFcnt = 0; + + // whether the current configured channel is in FSK mode + bool FSK; - // available channel frequencies from list passed during OTA activation - float availableChannelsFreq[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } }; + // flag that shows whether the device is joined and there is an ongoing session + bool isJoinedFlag = false; - // currently configured channel frequency - float channelFreq[2] = { 0 }; + // ADR is enabled by default + bool adrEnabled = true; + + // enable/disable CSMA for LoRaWAN + bool enableCSMA; - // LoRaWAN revision (1.0 vs 1.1) - uint8_t rev = 0; + // number of backoff slots to be decremented after DIFS phase. 0 to disable BO. + // A random BO avoids collisions in the case where two or more nodes start the CSMA + // process at the same time. + uint8_t backoffMax; + + // number of CADs to estimate a clear CH + uint8_t difsSlots; - // currently configured data rate for uplink and downlink: DR0 - DR15 (band-dependent!) - uint8_t dataRate[2] = { 0 }; + // available channel frequencies from list passed during OTA activation + LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } }; - // currently configured channel for uplink and downlink (band-dependent!) - uint8_t chIndex[2] = { 0 }; + // currently configured channels for TX and RX1 + LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; - // backup channel properties - may be changed by MAC command - float backupFreq = 0; - uint8_t backupDataRate = 0; + // currently configured datarates for TX and RX1 + uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED }; + + // LoRaWAN revision (1.0 vs 1.1) + uint8_t rev = 0; // timestamp to measure the RX1/2 delay (from uplink end) uint32_t rxDelayStart = 0; + // timestamp when the Rx1/2 windows were closed (timeout or uplink received) + uint32_t rxDelayEnd = 0; + // delays between the uplink and RX1/2 windows uint32_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; @@ -466,6 +602,25 @@ class LoRaWANNode { // indicates whether an uplink has MAC commands as payload bool isMACPayload = false; +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + /*! + \brief Save the current uplink frame counter. + Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. + \returns \ref status_codes + */ + int16_t saveFcntUp(); + + /*! + \brief Restore frame counter for uplinks from persistent storage. + Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. + \returns \ref status_codes + */ + int16_t restoreFcntUp(); +#endif + + // wait for, open and listen during Rx1 and Rx2 windows; only performs listening + int16_t downlinkCommon(); + // method to generate message integrity code uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); @@ -479,37 +634,40 @@ class LoRaWANNode { // setup uplink/downlink channel data rates and frequencies // will attempt to randomly select based on currently used band plan - int16_t setupChannels(); - - // find the first usable data rate in a given channel span - uint8_t findDataRate(uint8_t dr, DataRate_t* dataRate, const LoRaWANChannelSpan_t* span); + int16_t setupChannels(uint8_t* cfList); - // find a channel ID that conforms to the requested direction and ID range - int16_t findChannelId(uint8_t dir, uint8_t* ch, uint8_t* dr, int8_t min, int8_t max); + // select a set of semi-random TX/RX channels for the join-request and -accept message + int16_t selectChannelsJR(uint16_t devNonce, uint8_t drJoinSubband); - // find a channel span that any given channel id belongs to - LoRaWANChannelSpan_t* findChannelSpan(uint8_t dir, uint8_t ch, uint8_t* spanChannelId); + // select a set of random TX/RX channels for up- and downlink + int16_t selectChannels(); - // calculate channel frequency in MHz based on channel ID and direction - int16_t findChannelFreq(uint8_t dir, uint8_t ch, float* freq); + // find the first usable data rate for the given band + int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); // configure channel based on cached data rate ID and frequency int16_t configureChannel(uint8_t dir); - // send a MAC command to the network server - int16_t sendMacCommand(uint8_t cid, uint8_t* payload, size_t payloadLen, uint8_t* reply, size_t replyLen); + // save all available channels to persistent storage + int16_t saveChannels(); + + // restore all available channels from persistent storage + int16_t restoreChannels(); // push MAC command to queue, done by copy int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); - - // pop MAC command from queue, done by copy unless CMD is NULL - int16_t popMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue, size_t index); // delete a specific MAC command from queue, indicated by the command ID int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue); // execute mac command, return the number of processed bytes for sequential processing size_t execMacCommand(LoRaWANMacCommand_t* cmd); + + // Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013). + void performCSMA(); + + // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. + bool performCAD(); // function to encrypt and decrypt payloads void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); @@ -521,12 +679,6 @@ class LoRaWANNode { // host-to-network conversion method - takes data from host variable and and converts it to network packet endians template static void hton(uint8_t* buff, T val, size_t size = 0); - - // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. - bool performCAD(); - - // Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013). - void performCSMA(); }; #endif diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index c25b0af9f5..8e36f9c2f7 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -2,729 +2,437 @@ #if !defined(RADIOLIB_EXCLUDE_LORAWAN) -uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_t lim) { - int8_t dr = uplink - offset + base; - if(dr < lim) { - dr = lim; - } - return(dr); -} - const LoRaWANBand_t EU868 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 230, 230, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, - .fskFreq = 868.8, - .numChannelSpans = 1, - .defaultChannels = { - { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 3, - .freqStart = 868.1, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } - }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 868.500, .drMin = 0, .drMax = 5}, + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 869.858, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 869.525, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t US915 = { - .downlinkDataRateBase = 10, - .downlinkDataRateMin = 8, - .payloadLenMax = { - 19, 61, 133, 250, 250, 0, 0, 0, - 41, 117, 230, 230, 230, 230, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, - .fskFreq = 0, - .numChannelSpans = 3, - .defaultChannels = { + .txFreqs = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 2, + .txSpans = { { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - .joinRequestDataRate = 0, .numChannels = 64, - .freqStart = 902.3, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } - }, { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - .joinRequestDataRate = 4, - .numChannels = 8, - .freqStart = 903, - .freqStep = 1.6, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } - }, { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = 10, - .numChannels = 8, - .freqStart = 923.3, - .freqStep = 0.6, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .freqStart = 902.300, + .freqStep = 0.200, + .drMin = 0, + .drMax = 3, + .joinRequestDataRate = 0 }, - }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 923.3, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + { + .numChannels = 8, + .freqStart = 903.000, + .freqStep = 1.600, + .drMin = 4, + .drMax = 4, + .joinRequestDataRate = 4 } + }, + .rx1Span = { + .numChannels = 8, + .freqStart = 923.300, + .freqStep = 0.600, + .drMin = 8, + .drMax = 13, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DataRateBase = 10, + .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t CN780 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 250, 230, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, - .fskFreq = 0, - .numChannelSpans = 1, - .defaultChannels = { - { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 6, - .freqStart = 779.5, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } - }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 779.900, .drMin = 0, .drMax = 5}, + }, + .txJoinReq = { + { .enabled = true, .idx = 3, .freq = 780.500, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 4, .freq = 780.700, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 5, .freq = 780.900, .drMin = 0, .drMax = 5} + }, + .numTxSpans = 0, + .txSpans = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 786, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 786.000, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t EU433 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 230, 230, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, - .fskFreq = 0, - .numChannelSpans = 1, - .defaultChannels = { - { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 3, - .freqStart = 433.175, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } - }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 433.575, .drMin = 0, .drMax = 5}, + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 434.665, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 434.665, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t AU915 = { - .downlinkDataRateBase = 8, - .downlinkDataRateMin = 8, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 230, 0, - 41, 117, 230, 230, 230, 230, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, - .fskFreq = 0, - .numChannelSpans = 3, - .defaultChannels = { + .txFreqs = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 2, + .txSpans = { { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - .joinRequestDataRate = 0, .numChannels = 64, - .freqStart = 915.2, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } - }, { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - .joinRequestDataRate = 6, - .numChannels = 8, - .freqStart = 915.9, - .freqStep = 1.6, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } - }, { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 8, - .freqStart = 923.3, - .freqStep = 0.6, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .freqStart = 915.200, + .freqStep = 0.200, + .drMin = 0, + .drMax = 5, + .joinRequestDataRate = 0 }, - }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 923.3, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + { + .numChannels = 8, + .freqStart = 915.900, + .freqStep = 1.600, + .drMin = 6, + .drMax = 6, + .joinRequestDataRate = 6 } + }, + .rx1Span = { + .numChannels = 8, + .freqStart = 923.300, + .freqStep = 0.600, + .drMin = 8, + .drMax = 13, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DataRateBase = 8, + .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t CN500 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, .powerNumSteps = 7, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_MASK, - .fskFreq = 0, - .numChannelSpans = 2, - .defaultChannels = { + .txFreqs = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 1, + .txSpans = { { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .numChannels = 96, - .freqStart = 470.3, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } - }, { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 48, - .freqStart = 500.3, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .freqStart = 470.300, + .freqStep = 0.200, + .drMin = 0, + .drMax = 5, + .joinRequestDataRate = 0 }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 505.3, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = { + .numChannels = 48, + .freqStart = 500.300, + .freqStep = 0.200, + .drMin = 0, + .drMax = 5, + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 505.300, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t AS923 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 230, 230, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, - .fskFreq = 921.8, - .numChannelSpans = 1, - .defaultChannels = { - { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, - .joinRequestDataRate = 2, - .numChannels = 2, - .freqStart = 923.2, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } - }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 923.2, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t KR920 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, .powerNumSteps = 7, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, - .fskFreq = 0, - .numChannelSpans = 1, - .defaultChannels = { - { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 3, - .freqStart = 922.1, - .freqStep = 0.2, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } - }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 922.500, .drMin = 0, .drMax = 5} + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 921.9, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 921.900, .drMin = 0, .drMax = 0 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t IN865 = { - .downlinkDataRateBase = 0, - .downlinkDataRateMin = 0, - .payloadLenMax = { - 59, 59, 59, 123, 230, 230, 230, 230, - 0, 0, 0, 0, 0, 0, 0, 0 }, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, .powerNumSteps = 10, - .cfListType = RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES, - .fskFreq = 0, - .numChannelSpans = 1, - .defaultChannels = { - { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 3, - .freqStart = 865.0625, - .freqStep = 0.36, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } - }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 2, .freq = 865.9850, .drMin = 0, .drMax = 5} + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .backupChannel = { - .direction = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - .numChannels = 1, - .freqStart = 866.55, - .freqStep = 0, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - } + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 866.550, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index b244b8565c..0bb634f93f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -293,7 +293,22 @@ uint32_t PhysicalLayer::getTimeOnAir(size_t len) { (void)len; return(0); } - + +uint32_t PhysicalLayer::calculateRxTimeout(uint32_t timeoutUs) { + (void)timeoutUs; + return(0); +} + +int16_t PhysicalLayer::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { + (void)irqFlags; + (void)irqMask; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +bool PhysicalLayer::isRxTimeout() { + return(false); +} + int16_t PhysicalLayer::startChannelScan() { return(RADIOLIB_ERR_UNSUPPORTED); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index c083e4765c..741cdb8cef 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -309,7 +309,28 @@ class PhysicalLayer { \returns Expected time-on-air in microseconds. */ virtual uint32_t getTimeOnAir(size_t len); - + + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + virtual uint32_t calculateRxTimeout(uint32_t timeoutUs); + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + virtual int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns \ref RxTimeout IRQ is set + */ + virtual bool isRxTimeout(); + /*! \brief Interrupt-driven channel activity detection method. interrupt will be activated when packet is detected. Must be implemented in module class. From cb9ba88d038e0526db75489df414f1c16b3cdd5c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Nov 2023 17:51:34 +0100 Subject: [PATCH 0786/1848] Fix some tabs --- keywords.txt | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/keywords.txt b/keywords.txt index a791ce5177..63a578438a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -145,10 +145,10 @@ setDataShapingOOK KEYWORD2 setCRC KEYWORD2 variablePacketLengthMode KEYWORD2 fixedPacketLengthMode KEYWORD2 -setCrcFiltering KEYWORD2 -enableSyncWordFiltering KEYWORD2 -disableSyncWordFiltering KEYWORD2 -setPromiscuous KEYWORD2 +setCrcFiltering KEYWORD2 +enableSyncWordFiltering KEYWORD2 +disableSyncWordFiltering KEYWORD2 +setPromiscuous KEYWORD2 setRSSIConfig KEYWORD2 setEncoding KEYWORD2 getIRQFlags KEYWORD2 @@ -158,11 +158,11 @@ setRfSwitchPins KEYWORD2 forceLDRO KEYWORD2 autoLDRO KEYWORD2 getChipVersion KEYWORD2 -invertIQ KEYWORD2 +invertIQ KEYWORD2 setOokThresholdType KEYWORD2 setOokPeakThresholdDecrement KEYWORD2 setOokFixedOrFloorThreshold KEYWORD2 -setOokPeakThresholdStep KEYWORD2 +setOokPeakThresholdStep KEYWORD2 setDirectSyncWord KEYWORD2 setDirectAction KEYWORD2 readBit KEYWORD2 @@ -289,18 +289,18 @@ setModem KEYWORD2 # LoRaWAN wipe KEYWORD2 -restore KEYWORD2 +restore KEYWORD2 beginOTAA KEYWORD2 beginABP KEYWORD2 -saveSession KEYWORD2 +saveSession KEYWORD2 uplink KEYWORD2 downlink KEYWORD2 -sendReceive KEYWORD2 -setDeviceStatus KEYWORD2 -setDatarate KEYWORD2 -setADR KEYWORD2 -selectSubband KEYWORD2 -setCSMA KEYWORD2 +sendReceive KEYWORD2 +setDeviceStatus KEYWORD2 +setDatarate KEYWORD2 +setADR KEYWORD2 +selectSubband KEYWORD2 +setCSMA KEYWORD2 ####################################### # Constants (LITERAL1) @@ -406,11 +406,11 @@ RADIOLIB_ERR_INVALID_PORT LITERAL1 RADIOLIB_ERR_NO_RX_WINDOW LITERAL1 RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 RADIOLIB_ERR_INVALID_CID LITERAL1 -RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 +RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_EMPTY LITERAL1 -RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 -RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 -RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 -RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 -RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 \ No newline at end of file +RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 +RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 +RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 \ No newline at end of file From 75a9420552a7892a754d0b8037a027ee709b7e7a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Nov 2023 17:53:05 +0100 Subject: [PATCH 0787/1848] [LoRaWAN] Added event struct to pass extra info (#821) --- .../LoRaWAN_End_Device_persistent.ino | 4 +- .../LoRaWAN_End_Device_reference.ino | 38 +++++++++- keywords.txt | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 75 ++++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 66 ++++++++++++++-- 5 files changed, 133 insertions(+), 51 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino index 43275a7ca9..3c96fb9134 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino @@ -1,5 +1,5 @@ /* - RadioLib LoRaWAN End Device Example + RadioLib LoRaWAN End Device Persistent Example This example assumes you have tried one of the OTAA or ABP examples and are familiar with the required keys and procedures. @@ -7,7 +7,7 @@ deepsleep or survive power cycles. Before you start, you will have to register your device at https://www.thethingsnetwork.org/ and join the network using either OTAA or ABP. - Please refer to one of the other examples for more + Please refer to one of the other LoRaWAN examples for more information regarding joining a network. NOTE: LoRaWAN requires storing some parameters persistently! diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino index e72e977cf4..c31752e7e8 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino @@ -1,5 +1,5 @@ /* - RadioLib LoRaWAN End Device Example + RadioLib LoRaWAN End Device Reference Example This example joins a LoRaWAN network and will send uplink packets. Before you start, you will have to @@ -131,13 +131,13 @@ void setup() { // this tries to minimize packet loss by searching for a free channel // before actually sending an uplink node.setCSMA(6, 2, true); - } void loop() { int state = RADIOLIB_ERR_NONE; - // set battery fill level, + // set battery fill level - the LoRaWAN network server + // may periodically request this information // 0 = external power source // 1 = lowest (empty battery) // 254 = highest (full battery) @@ -170,7 +170,12 @@ void loop() { // after uplink to receive the downlink! Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); String strDown; - state = node.downlink(strDown); + + // you can also retrieve additional information about + // uplink or downlink by passing a reference to + // LoRaWANEvent_t structure + LoRaWANEvent_t event; + state = node.downlink(strDown, &event); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -196,6 +201,31 @@ void loop() { Serial.print(F("[LoRaWAN] Frequency error:\t")); Serial.print(radio.getFrequencyError()); Serial.println(F(" Hz")); + + // print extra information about the event + Serial.println(F("[LoRaWAN] Event information:")); + Serial.print(F("[LoRaWAN] Direction:\t")); + if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) { + Serial.println(F("uplink")); + } else { + Serial.println(F("downlink")); + } + Serial.print(F("[LoRaWAN] Confirmed:\t")); + Serial.println(event.confirmed); + Serial.print(F("[LoRaWAN] Confirming:\t")); + Serial.println(event.confirming); + Serial.print(F("[LoRaWAN] Frequency:\t")); + Serial.print(event.freq, 3); + Serial.println(F(" MHz")); + Serial.print(F("[LoRaWAN] Output power:\t")); + Serial.print(event.power); + Serial.println(F(" dBm")); + Serial.print(F("[LoRaWAN] Frame count:\t")); + Serial.println(event.fcnt); + Serial.print(F("[LoRaWAN] Port:\t\t")); + Serial.println(event.port); + + Serial.print(radio.getFrequencyError()); } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("timeout!")); diff --git a/keywords.txt b/keywords.txt index 63a578438a..1a19ea40c9 100644 --- a/keywords.txt +++ b/keywords.txt @@ -58,6 +58,7 @@ ExternalRadio KEYWORD1 BellClient KEYWORD1 LoRaWANNode KEYWORD1 LoRaWANBand_t KEYWORD1 +LoRaWANEvent_t KEYWORD1 # SSTV modes Scottie1 KEYWORD1 diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index fc0b31645d..02ff3f9df8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -657,16 +657,16 @@ int16_t LoRaWANNode::saveChannels() { #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed) { - return(this->uplink(str.c_str(), port, isConfirmed)); +int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + return(this->uplink(str.c_str(), port, isConfirmed, event)); } #endif -int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed) { - return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed)); +int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed, event)); } -int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed) { +int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { Module* mod = this->phyLayer->getMod(); // check if the Rx windows were closed after sending the previous uplink @@ -783,12 +783,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } // if the saved confirm-fcnt is set, set the ACK bit - bool isConfirmingDown; + bool isConfirmingDown = false; if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { isConfirmingDown = true; uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; } - (void)isConfirmingDown; LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fcntUp); @@ -895,13 +894,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // the downlink confirmation was acknowledged, so clear the counter value this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; - // LoRaWANEvent: - // dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK - // confirmed = isConfirmed - // confirming = isConfirmingDown - // power = this->txPwrCur - // fcnt = this->fcntUp - // port = port + // pass the extra info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + event->confirmed = isConfirmed; + event->confirming = isConfirmingDown; + event->freq = currentChannels[event->dir].freq; + event->power = this->txPwrCur; + event->fcnt = this->fcntUp; + event->port = port; + } return(RADIOLIB_ERR_NONE); } @@ -1012,7 +1014,7 @@ int16_t LoRaWANNode::downlinkCommon() { } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::downlink(String& str) { +int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { int16_t state = RADIOLIB_ERR_NONE; // build a temporary buffer @@ -1021,7 +1023,7 @@ int16_t LoRaWANNode::downlink(String& str) { uint8_t data[251]; // wait for downlink - state = this->downlink(data, &length); + state = this->downlink(data, &length, event); if(state == RADIOLIB_ERR_NONE) { // add null terminator data[length] = '\0'; @@ -1034,8 +1036,7 @@ int16_t LoRaWANNode::downlink(String& str) { } #endif -int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { - +int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received int16_t state = downlinkCommon(); RADIOLIB_ASSERT(state); @@ -1086,13 +1087,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16); // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fcntUp - // TODO get this to the user somehow bool isConfirmingUp = false; if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK) && (this->rev == 1)) { isConfirmingUp = true; LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); } - (void)isConfirmingUp; RADIOLIB_DEBUG_PRINTLN("downlinkMsg:"); RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); @@ -1157,7 +1156,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { this->confFcntDown = this->aFcntDown; isConfirmedDown = true; } - (void)isConfirmedDown; // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); @@ -1242,13 +1240,16 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { // a downlink was received, so reset the ADR counter to this uplink's fcnt this->adrFcnt = this->fcntUp; - // LoRaWANEvent: - // dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK - // confirmed = isConfirmedDown - // confirming = isConfirmingUp - // power = this->txPwrCur - // fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown - // port = ... + // pass the extra info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + event->confirmed = isConfirmedDown; + event->confirming = isConfirmingUp; + event->freq = currentChannels[event->dir].freq; + event->power = this->txPwrCur; + event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; + event->port = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)]; + } // process payload (if there is any) if(payLen <= 0) { @@ -1276,34 +1277,34 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) { } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed) { +int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(strUp, port, isConfirmed); + int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink - state = this->downlink(strDown); + state = this->downlink(strDown, eventDown); return(state); } #endif -int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed) { +int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(strUp, port, isConfirmed); + int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink - state = this->downlink(dataDown, lenDown); + state = this->downlink(dataDown, lenDown, eventDown); return(state); } -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed) { +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed); + int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink - state = this->downlink(dataDown, lenDown); + state = this->downlink(dataDown, lenDown, eventDown); return(state); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 5d0eacc151..54351a034c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -311,6 +311,34 @@ struct LoRaWANMacCommandQueue_t { LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; }; +/*! + \struct LoRaWANEvent_t + \brief Structure to save extra information about uplink/downlink event. +*/ +struct LoRaWANEvent_t { + /*! \brief Event direction, one of RADIOLIB_LORAWAN_CHANNEL_DIR_* */ + uint8_t dir; + + /*! \brief Whether the event is confirmed or not (e.g., confirmed uplink sent by user application) */ + bool confirmed; + + /*! \brief Whether the event is confirming a previous request + (e.g., server downlink reply to confirmed uplink sent by user application)*/ + bool confirming; + + /*! \brief Frequency in MHz */ + float freq; + + /*! \brief Transmit power in dBm for uplink, or RSSI for downlink */ + int16_t power; + + /*! \brief The appropriate frame counter - for different events, different frame counters will be reported! */ + uint32_t fcnt; + + /*! \brief Port number */ + uint8_t port; +}; + /*! \class LoRaWANNode \brief LoRaWAN-compatible node (class A device). @@ -388,9 +416,11 @@ class LoRaWANNode { \param str Address of Arduino String that will be transmitted. \param port Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t uplink(String& str, uint8_t port, bool isConfirmed = false); + int16_t uplink(String& str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); #endif /*! @@ -398,9 +428,11 @@ class LoRaWANNode { \param str C-string that will be transmitted. \param port Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false); + int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); /*! \brief Send a message to the server. @@ -408,26 +440,32 @@ class LoRaWANNode { \param len Length of the data. \param port Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false); + int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Wait for downlink from the server in either RX1 or RX2 window. \param str Address of Arduino String to save the received data. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t downlink(String& str); + int16_t downlink(String& str, LoRaWANEvent_t* event = NULL); #endif /*! \brief Wait for downlink from the server in either RX1 or RX2 window. \param data Buffer to save received data into. \param len Pointer to variable that will be used to save the number of received bytes. + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t downlink(uint8_t* data, size_t* len); + int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); #if defined(RADIOLIB_BUILD_ARDUINO) /*! @@ -436,9 +474,13 @@ class LoRaWANNode { \param port Port number to send the message to. \param strDown Address of Arduino String to save the received data. \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false); + int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); #endif /*! @@ -448,9 +490,13 @@ class LoRaWANNode { \param dataDown Buffer to save received data into. \param lenDown Pointer to variable that will be used to save the number of received bytes. \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false); + int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. @@ -460,9 +506,13 @@ class LoRaWANNode { \param dataDown Buffer to save received data into. \param lenDown Pointer to variable that will be used to save the number of received bytes. \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false); + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Set device status. From 063b42752f675f0dea4a7908bb8f6cd6f5b51f55 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 15:03:48 +0100 Subject: [PATCH 0788/1848] [LoRaWAN] Fixed a few warnings --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++-------- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 02ff3f9df8..80ecde7c39 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -797,7 +797,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer - size_t i = 0; + int16_t i = 0; for (; i < this->commandsUp.numCommands; i++) { LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; memcpy(foptsPtr, &cmd, 1 + cmd.len); @@ -813,9 +813,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } else { deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); } - if(i == 0) { - break; - } } uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); @@ -1206,7 +1203,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t foptsBuff[foptsBufSize]; uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer - size_t i = 0; + int16_t i = 0; for (; i < this->commandsUp.numCommands; i++) { LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; memcpy(foptsPtr, &cmd, 1 + cmd.len); @@ -1222,9 +1219,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } else { deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); } - if(i == 0) { - break; - } } this->isMACPayload = true; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 54351a034c..da1a435675 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -626,7 +626,7 @@ class LoRaWANNode { uint8_t difsSlots; // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } }; + LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; // currently configured channels for TX and RX1 LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; From bd1fbb3b0a759fbb2c3b58798da55ccddbdd0cbb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 15:06:46 +0100 Subject: [PATCH 0789/1848] Updated version macro print --- src/BuildOpt.h | 10 +++++----- src/RadioLib.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5ade1f4935..be96ee1226 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -521,11 +521,11 @@ #define RADIOLIB_ABS(x) ((x)>0?(x):-(x)) // version definitions -#define RADIOLIB_VERSION_MAJOR (0x06) -#define RADIOLIB_VERSION_MINOR (0x02) -#define RADIOLIB_VERSION_PATCH (0x00) -#define RADIOLIB_VERSION_EXTRA (0x00) +#define RADIOLIB_VERSION_MAJOR 6 +#define RADIOLIB_VERSION_MINOR 2 +#define RADIOLIB_VERSION_PATCH 0 +#define RADIOLIB_VERSION_EXTRA 0 -#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) +#define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) #endif diff --git a/src/RadioLib.h b/src/RadioLib.h index ee7026d2fa..9a673cb13b 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -55,11 +55,11 @@ #if defined(RADIOLIB_DEBUG) #define RADIOLIB_VALUE_TO_STRING(x) #x #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) - #pragma message("\nRadioLib Debug Info\nVersion " \ + #pragma message("\nRadioLib Debug Info\nVersion: \"" \ RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ - RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\n" \ + RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \ "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \ "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) \ ) From 615cebcf6bd363b86e8495ade20fdf996165f9e6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 15:07:19 +0100 Subject: [PATCH 0790/1848] Added warning for low-end platforms (Uno etc.) --- src/BuildOpt.h | 4 ++++ src/RadioLib.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index be96ee1226..813dac83e3 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -83,6 +83,10 @@ // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. #define RADIOLIB_PLATFORM "Arduino AVR" + #if !(defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)) + #define RADIOLIB_LOWEND_PLATFORM + #endif + #elif defined(ESP8266) // ESP8266 boards #define RADIOLIB_PLATFORM "ESP8266" diff --git a/src/RadioLib.h b/src/RadioLib.h index 9a673cb13b..735309d289 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -70,6 +70,11 @@ #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" #endif +// print warning for low-end platforms +#if defined(RADIOLIB_LOWEND_PLATFORM) + #warning "Low-end platform detected, stability issues are likely!" +#endif + #include "modules/CC1101/CC1101.h" #include "modules/LLCC68/LLCC68.h" #include "modules/nRF24/nRF24.h" From 455c3c8dd0c9db4373cb641ad30db484d591b25b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 15:11:10 +0100 Subject: [PATCH 0791/1848] [CC1101] Fixed crash in blocking receive (#839) --- src/modules/CC1101/CC1101.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 5e2fc776ed..be2056b25c 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -145,7 +145,7 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { // wait for packet or timeout uint32_t start = this->mod->hal->micros(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->micros() - start > timeout) { @@ -155,6 +155,13 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { } } + // for some reason, blocking receive will sometimes return impossible packet lengths + // reading packet length again in readData seems to resolve this + size_t length = getPacketLength(); + if((length == 0) || (length > RADIOLIB_CC1101_MAX_PACKET_LENGTH)) { + this->packetLengthQueried = false; + } + // read packet data return(readData(data, len)); } @@ -1036,7 +1043,7 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTLEN, len); RADIOLIB_ASSERT(state); - // update the cached value + // update the cached values this->packetLength = len; this->packetLengthConfig = mode; return(state); From e4bfb6429b2273ff8dd2440775ecbfdc357c2223 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:15:48 +0100 Subject: [PATCH 0792/1848] [LoRaWAN] Fixed variable-sized arrays --- src/protocols/LoRaWAN/LoRaWAN.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 80ecde7c39..4b309e6752 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -148,7 +148,11 @@ int16_t LoRaWANNode::restoreFcntUp() { uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID); uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 1); uint8_t buffSize = fcntBuffEnd - fcntBuffStart; - uint8_t fcntBuff[buffSize] = { 0 }; + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* fcntBuff = new uint8_t[buffSize]; + #endif mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); // copy the two most significant bytes from the first two bytes @@ -178,16 +182,18 @@ int16_t LoRaWANNode::restoreFcntUp() { } } uint32_t bits_7_0 = (uint32_t)fcntBuff[idx-1] & 0x7F; + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] fcntBuff; + #endif this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; - return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::restoreChannels() { - uint8_t bytesPerChannel = 5; - uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; - uint8_t buffer[numBytes]; + const uint8_t bytesPerChannel = 5; + const uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; + uint8_t buffer[numBytes] = { 0 }; Module* mod = this->phyLayer->getMod(); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID), buffer, numBytes); for(uint8_t dir = 0; dir < 2; dir++) { @@ -634,9 +640,9 @@ int16_t LoRaWANNode::saveFcntUp() { } int16_t LoRaWANNode::saveChannels() { - uint8_t bytesPerChannel = 5; - uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; - uint8_t buffer[numBytes]; + const uint8_t bytesPerChannel = 5; + const uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; + uint8_t buffer[numBytes] = { 0 }; for(uint8_t dir = 0; dir < 2; dir++) { for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { uint8_t chBuff[bytesPerChannel] = { 0 }; @@ -655,7 +661,6 @@ int16_t LoRaWANNode::saveChannels() { } #endif // RADIOLIB_EEPROM_UNSUPPORTED - #if defined(RADIOLIB_BUILD_ARDUINO) int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { return(this->uplink(str.c_str(), port, isConfirmed, event)); From 5b406688a3f6aa4a822ac32765887d32a5477f36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:24:46 +0100 Subject: [PATCH 0793/1848] [CI] Skip persistent LoRaWAN example on platforms without EEPROM --- .github/workflows/main.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 512989e050..c7acfc0758 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,15 +50,20 @@ jobs: - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble + run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:mbed:envie_m4 + run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:megaavr:uno2018 run: echo "options=':mode=on'" >> $GITHUB_OUTPUT - id: arduino:sam:arduino_due_x + run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:samd:arduino_zero_native + run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: adafruit:samd:adafruit_feather_m0 run: | echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: adafruit:nrf52:feather52832 run: | sudo apt-get update @@ -68,6 +73,7 @@ jobs: echo "/home/runner/.local/bin" >> $GITHUB_PATH echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: esp32:esp32:esp32 run: | python -m pip install pyserial @@ -95,6 +101,7 @@ jobs: - id: MegaCoreX:megaavr:4809 run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT - id: arduino:mbed_rp2040:pico + run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: rp2040:rp2040:rpipico run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT - id: CubeCell:CubeCell:CubeCell-Board From c96dd51f574ac2c5e73483e4bce3ca12a7310337 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:27:05 +0100 Subject: [PATCH 0794/1848] [LoRaWAN] Fixed inconsistent naming --- .../LoRaWAN_End_Device_persistent.ino | 145 ----------- .../LoRaWAN_End_Device_reference.ino | 246 ------------------ 2 files changed, 391 deletions(-) delete mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino delete mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino deleted file mode 100644 index 3c96fb9134..0000000000 --- a/examples/LoRaWAN/LoRaWAN_End_Device_persistent/LoRaWAN_End_Device_persistent.ino +++ /dev/null @@ -1,145 +0,0 @@ -/* - RadioLib LoRaWAN End Device Persistent Example - - This example assumes you have tried one of the OTAA or ABP - examples and are familiar with the required keys and procedures. - This example restores and saves a session such that you can use - deepsleep or survive power cycles. Before you start, you will - have to register your device at https://www.thethingsnetwork.org/ - and join the network using either OTAA or ABP. - Please refer to one of the other LoRaWAN examples for more - information regarding joining a network. - - NOTE: LoRaWAN requires storing some parameters persistently! - RadioLib does this by using EEPROM, by default - starting at address 0 and using 384 bytes. - If you already use EEPROM in your application, - you will have to either avoid this range, or change it - by setting a different start address by changing the value of - RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either - during build or in src/BuildOpt.h. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// SX1278 has the following connections: -// NSS pin: 10 -// DIO0 pin: 2 -// RESET pin: 9 -// DIO1 pin: 3 -SX1278 radio = new Module(10, 2, 9, 3); - -// create the node instance on the EU-868 band -// using the radio module and the encryption key -// make sure you are using the correct band -// based on your geographical location! -LoRaWANNode node(&radio, &EU868); - -void setup() { - Serial.begin(9600); - - // initialize SX1278 with default settings - Serial.print(F("[SX1278] Initializing ... ")); - int state = radio.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // first we need to initialize the device storage - // this will reset all persistently stored parameters - // NOTE: This should only be done once prior to first joining a network! - // After wiping persistent storage, you will also have to reset - // the end device in TTN and perform the join procedure again! - // Here, a delay is added to make sure that during re-flashing - // the .wipe() is not triggered and the session is lost - //delay(5000); - //node.wipe(); - - // now we can start the activation - // Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - // uint64_t joinEUI = 0x12AD1011B0C0FFEE; - // uint64_t devEUI = 0x70B3D57ED005E120; - // uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, - // 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; - // uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - // 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; - // state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - - // after the device has been activated, - // the session can be restored without rejoining after device power cycle - // on EEPROM-enabled boards by calling "restore" - Serial.print(F("[LoRaWAN] Resuming previous session ... ")); - state = node.restore(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - -} - -// counter to keep track of transmitted packets -int count = 0; - -void loop() { - // send uplink to port 10 - Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello World! #" + String(count++); - String strDown; - int state = node.sendReceive(strUp, 10, strDown); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("received a downlink!")); - - // print data of the packet (if there are any) - Serial.print(F("[LoRaWAN] Data:\t\t")); - if(strDown.length() > 0) { - Serial.println(strDown); - } else { - Serial.println(F("")); - } - - // print RSSI (Received Signal Strength Indicator) - Serial.print(F("[LoRaWAN] RSSI:\t\t")); - Serial.print(radio.getRSSI()); - Serial.println(F(" dBm")); - - // print SNR (Signal-to-Noise Ratio) - Serial.print(F("[LoRaWAN] SNR:\t\t")); - Serial.print(radio.getSNR()); - Serial.println(F(" dB")); - - // print frequency error - Serial.print(F("[LoRaWAN] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); - - } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("no downlink!")); - - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // on EEPROM enabled boards, you can save the current session - // by calling "saveSession" which allows retrieving the session after reboot or deepsleep - node.saveSession(); - - // wait before sending another packet - // alternatively, call a deepsleep function here - // make sure to send the radio to sleep as well using radio.sleep() - delay(30000); -} diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino deleted file mode 100644 index c31752e7e8..0000000000 --- a/examples/LoRaWAN/LoRaWAN_End_Device_reference/LoRaWAN_End_Device_reference.ino +++ /dev/null @@ -1,246 +0,0 @@ -/* - RadioLib LoRaWAN End Device Reference Example - - This example joins a LoRaWAN network and will send - uplink packets. Before you start, you will have to - register your device at https://www.thethingsnetwork.org/ - After your device is registered, you can run this example. - The device will join the network and start uploading data. - - Also, most of the possible and available functions are - shown here for reference. - - LoRaWAN v1.1 requires the use of EEPROM (persistent storage). - Please refer to the 'persistent' example once you are familiar - with LoRaWAN. - Running this examples REQUIRES you to check "Resets DevNonces" - on your LoRaWAN dashboard. Refer to the network's - documentation on how to do this. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// SX1278 has the following connections: -// NSS pin: 10 -// DIO0 pin: 2 -// RESET pin: 9 -// DIO1 pin: 3 -SX1278 radio = new Module(10, 2, 9, 3); - -// create the node instance on the EU-868 band -// using the radio module and the encryption key -// make sure you are using the correct band -// based on your geographical location! -LoRaWANNode node(&radio, &EU868); - -void setup() { - Serial.begin(9600); - - // initialize SX1278 with default settings - Serial.print(F("[SX1278] Initializing ... ")); - int state = radio.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI - // when adding new end device in TTN, you will have to enter this number - // you can pick any number you want, but it has to be unique - uint64_t joinEUI = 0x12AD1011B0C0FFEE; - - // device identifier - this number can be anything - // when adding new end device in TTN, you can generate this number, - // or you can set any value you want, provided it is also unique - uint64_t devEUI = 0x70B3D57ED005E120; - - // select some encryption keys which will be used to secure the communication - // there are two of them - network key and application key - // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long - - // network key is the ASCII string "topSecretKey1234" - uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; - - // application key is the ASCII string "aDifferentKeyABC" - uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; - - // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used - // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded - // and can be set to NULL - - // some frequency bands only use a subset of the available channels - // you can select the specific band or set the first channel and last channel - // for example, either of the following corresponds to US915 FSB2 in TTN - /* - node.selectSubband(2); - node.selectSubband(8, 15); - */ - - // now we can start the activation - // this can take up to 10 seconds, and requires a LoRaWAN gateway in range - // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): - /* - uint8_t joinDr = 4; - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); - */ - Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // after the device has been activated, - // the session can be restored without rejoining after device power cycle - // on EEPROM-enabled boards by calling "restore" - /* - Serial.print(F("[LoRaWAN] Resuming previous session ... ")); - state = node.restore(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - */ - - // disable the ADR algorithm - node.setADR(false); - - // set a fixed datarate - node.setDatarate(5); - - // enable CSMA - // this tries to minimize packet loss by searching for a free channel - // before actually sending an uplink - node.setCSMA(6, 2, true); -} - -void loop() { - int state = RADIOLIB_ERR_NONE; - - // set battery fill level - the LoRaWAN network server - // may periodically request this information - // 0 = external power source - // 1 = lowest (empty battery) - // 254 = highest (full battery) - // 255 = unable to measure - uint8_t battLevel = 146; - node.setDeviceStatus(battLevel); - - // retrieve the last uplink frame counter - uint32_t fcntUp = node.getFcntUp(); - - Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello World! #" + String(fcntUp); - - // send a confirmed uplink to port 10 every 64th frame - if(fcntUp % 64 == 0) { - state = node.uplink(strUp, 10, true); - } else { - state = node.uplink(strUp, 10); - } - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // after uplink, you can call downlink(), - // to receive any possible reply from the server - // this function must be called within a few seconds - // after uplink to receive the downlink! - Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); - String strDown; - - // you can also retrieve additional information about - // uplink or downlink by passing a reference to - // LoRaWANEvent_t structure - LoRaWANEvent_t event; - state = node.downlink(strDown, &event); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - - // print data of the packet (if there are any) - Serial.print(F("[LoRaWAN] Data:\t\t")); - if(strDown.length() > 0) { - Serial.println(strDown); - } else { - Serial.println(F("")); - } - - // print RSSI (Received Signal Strength Indicator) - Serial.print(F("[LoRaWAN] RSSI:\t\t")); - Serial.print(radio.getRSSI()); - Serial.println(F(" dBm")); - - // print SNR (Signal-to-Noise Ratio) - Serial.print(F("[LoRaWAN] SNR:\t\t")); - Serial.print(radio.getSNR()); - Serial.println(F(" dB")); - - // print frequency error - Serial.print(F("[LoRaWAN] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); - - // print extra information about the event - Serial.println(F("[LoRaWAN] Event information:")); - Serial.print(F("[LoRaWAN] Direction:\t")); - if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) { - Serial.println(F("uplink")); - } else { - Serial.println(F("downlink")); - } - Serial.print(F("[LoRaWAN] Confirmed:\t")); - Serial.println(event.confirmed); - Serial.print(F("[LoRaWAN] Confirming:\t")); - Serial.println(event.confirming); - Serial.print(F("[LoRaWAN] Frequency:\t")); - Serial.print(event.freq, 3); - Serial.println(F(" MHz")); - Serial.print(F("[LoRaWAN] Output power:\t")); - Serial.print(event.power); - Serial.println(F(" dBm")); - Serial.print(F("[LoRaWAN] Frame count:\t")); - Serial.println(event.fcnt); - Serial.print(F("[LoRaWAN] Port:\t\t")); - Serial.println(event.port); - - Serial.print(radio.getFrequencyError()); - - } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("timeout!")); - - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // on EEPROM enabled boards, you can save the current session - // by calling "saveSession" which allows retrieving the session after reboot or deepsleep - /* - node.saveSession(); - */ - - // wait before sending another packet - delay(30000); -} From 7d57a5f6c7d4321e57112aa786ccd6d146411671 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:27:29 +0100 Subject: [PATCH 0795/1848] [LoRaWAN] Fixed example naming --- .../LoRaWAN_End_Device_Persistent.ino | 145 +++++++++++ .../LoRaWAN_End_Device_Reference.ino | 246 ++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino new file mode 100644 index 0000000000..3c96fb9134 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino @@ -0,0 +1,145 @@ +/* + RadioLib LoRaWAN End Device Persistent Example + + This example assumes you have tried one of the OTAA or ABP + examples and are familiar with the required keys and procedures. + This example restores and saves a session such that you can use + deepsleep or survive power cycles. Before you start, you will + have to register your device at https://www.thethingsnetwork.org/ + and join the network using either OTAA or ABP. + Please refer to one of the other LoRaWAN examples for more + information regarding joining a network. + + NOTE: LoRaWAN requires storing some parameters persistently! + RadioLib does this by using EEPROM, by default + starting at address 0 and using 384 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // first we need to initialize the device storage + // this will reset all persistently stored parameters + // NOTE: This should only be done once prior to first joining a network! + // After wiping persistent storage, you will also have to reset + // the end device in TTN and perform the join procedure again! + // Here, a delay is added to make sure that during re-flashing + // the .wipe() is not triggered and the session is lost + //delay(5000); + //node.wipe(); + + // now we can start the activation + // Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + // uint64_t joinEUI = 0x12AD1011B0C0FFEE; + // uint64_t devEUI = 0x70B3D57ED005E120; + // uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + // 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + // uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + // 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + // state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + // after the device has been activated, + // the session can be restored without rejoining after device power cycle + // on EEPROM-enabled boards by calling "restore" + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello World! #" + String(count++); + String strDown; + int state = node.sendReceive(strUp, 10, strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("received a downlink!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("no downlink!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + + // wait before sending another packet + // alternatively, call a deepsleep function here + // make sure to send the radio to sleep as well using radio.sleep() + delay(30000); +} diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino new file mode 100644 index 0000000000..c31752e7e8 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -0,0 +1,246 @@ +/* + RadioLib LoRaWAN End Device Reference Example + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will join the network and start uploading data. + + Also, most of the possible and available functions are + shown here for reference. + + LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + Please refer to the 'persistent' example once you are familiar + with LoRaWAN. + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI + // when adding new end device in TTN, you will have to enter this number + // you can pick any number you want, but it has to be unique + uint64_t joinEUI = 0x12AD1011B0C0FFEE; + + // device identifier - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is also unique + uint64_t devEUI = 0x70B3D57ED005E120; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + + // some frequency bands only use a subset of the available channels + // you can select the specific band or set the first channel and last channel + // for example, either of the following corresponds to US915 FSB2 in TTN + /* + node.selectSubband(2); + node.selectSubband(8, 15); + */ + + // now we can start the activation + // this can take up to 10 seconds, and requires a LoRaWAN gateway in range + // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): + /* + uint8_t joinDr = 4; + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); + */ + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after the device has been activated, + // the session can be restored without rejoining after device power cycle + // on EEPROM-enabled boards by calling "restore" + /* + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ + + // disable the ADR algorithm + node.setADR(false); + + // set a fixed datarate + node.setDatarate(5); + + // enable CSMA + // this tries to minimize packet loss by searching for a free channel + // before actually sending an uplink + node.setCSMA(6, 2, true); +} + +void loop() { + int state = RADIOLIB_ERR_NONE; + + // set battery fill level - the LoRaWAN network server + // may periodically request this information + // 0 = external power source + // 1 = lowest (empty battery) + // 254 = highest (full battery) + // 255 = unable to measure + uint8_t battLevel = 146; + node.setDeviceStatus(battLevel); + + // retrieve the last uplink frame counter + uint32_t fcntUp = node.getFcntUp(); + + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello World! #" + String(fcntUp); + + // send a confirmed uplink to port 10 every 64th frame + if(fcntUp % 64 == 0) { + state = node.uplink(strUp, 10, true); + } else { + state = node.uplink(strUp, 10); + } + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // after uplink, you can call downlink(), + // to receive any possible reply from the server + // this function must be called within a few seconds + // after uplink to receive the downlink! + Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + String strDown; + + // you can also retrieve additional information about + // uplink or downlink by passing a reference to + // LoRaWANEvent_t structure + LoRaWANEvent_t event; + state = node.downlink(strDown, &event); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LoRaWAN] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + // print extra information about the event + Serial.println(F("[LoRaWAN] Event information:")); + Serial.print(F("[LoRaWAN] Direction:\t")); + if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) { + Serial.println(F("uplink")); + } else { + Serial.println(F("downlink")); + } + Serial.print(F("[LoRaWAN] Confirmed:\t")); + Serial.println(event.confirmed); + Serial.print(F("[LoRaWAN] Confirming:\t")); + Serial.println(event.confirming); + Serial.print(F("[LoRaWAN] Frequency:\t")); + Serial.print(event.freq, 3); + Serial.println(F(" MHz")); + Serial.print(F("[LoRaWAN] Output power:\t")); + Serial.print(event.power); + Serial.println(F(" dBm")); + Serial.print(F("[LoRaWAN] Frame count:\t")); + Serial.println(event.fcnt); + Serial.print(F("[LoRaWAN] Port:\t\t")); + Serial.println(event.port); + + Serial.print(radio.getFrequencyError()); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + /* + node.saveSession(); + */ + + // wait before sending another packet + delay(30000); +} From 51169106c2c7b8281c95db2c5b3c9f9fdf494c50 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:34:48 +0100 Subject: [PATCH 0796/1848] [SX126x] Fixed unused variable warning --- src/modules/SX126x/SX126x.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 28e55b7966..51e1b8ae8e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1751,7 +1751,7 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { To address this, the user override has been commented out, ensuring consistent application of the optimal CAD settings as per Semtech's Application Note AN1200.48 (page 41) for the 125KHz setting. This approach significantly reduces false CAD occurrences. Testing has shown that there is no reason for a user to change CAD settings for anything other than most optimal ones described in AN1200.48 . - However, this change deos not respect CAD configs from the LoRaWAN layer. Future considerations or use cases might require revisiting this decision. + However, this change does not respect CAD configs from the LoRaWAN layer. Future considerations or use cases might require revisiting this decision. Hence this note. */ @@ -1770,7 +1770,9 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { } */ - + (void)symbolNum; + (void)detPeak; + (void)detMin; // configure parameters int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); From 0dbe05229a963f2d250fe4681dcd22705fb67b38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:36:46 +0100 Subject: [PATCH 0797/1848] [CI] Fixed STM32WL not skipped properly --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c7acfc0758..b136960adc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,20 +50,20 @@ jobs: - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble - run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:mbed:envie_m4 - run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:megaavr:uno2018 run: echo "options=':mode=on'" >> $GITHUB_OUTPUT - id: arduino:sam:arduino_due_x - run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:samd:arduino_zero_native - run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: adafruit:samd:adafruit_feather_m0 run: | echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: adafruit:nrf52:feather52832 run: | sudo apt-get update @@ -73,7 +73,7 @@ jobs: echo "/home/runner/.local/bin" >> $GITHUB_PATH echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: esp32:esp32:esp32 run: | python -m pip install pyserial @@ -101,7 +101,7 @@ jobs: - id: MegaCoreX:megaavr:4809 run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT - id: arduino:mbed_rp2040:pico - run: echo "skip-pattern=(LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: rp2040:rp2040:rpipico run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT - id: CubeCell:CubeCell:CubeCell-Board From 713162fcc721fa6b11ae85545add727c25ad16c4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:38:03 +0100 Subject: [PATCH 0798/1848] [LoRaWAN] Fixed unused variable warning on non-EEPROM boards --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 4b309e6752..dc958b176c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -221,6 +221,8 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // the device has joined already, we can just pull the data from persistent storage return(this->restore()); } +#else + (void)force; #endif // set the physical layer configuration @@ -461,6 +463,8 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, // the device has joined already, we can just pull the data from persistent storage return(this->restore()); } +#else + (void)force; #endif this->devAddr = addr; From 7e707859098f876ad05d567d2b3ffc6edad3b47c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:46:12 +0100 Subject: [PATCH 0799/1848] [LoRaWAN] Replaced VLAs with dynamically allocated memory --- src/protocols/LoRaWAN/LoRaWAN.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index dc958b176c..af930be921 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -802,7 +802,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if we have some MAC commands to append if(foptsLen > 0) { - uint8_t foptsBuff[foptsBufSize]; + // assume maximum possible buffer size + uint8_t foptsBuff[15]; uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer @@ -1209,7 +1210,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { size_t foptsBufSize = this->commandsUp.len; - uint8_t foptsBuff[foptsBufSize]; + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t foptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* foptsBuff = new uint8_t[foptsBufSize]; + #endif uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer int16_t i = 0; @@ -1232,9 +1237,20 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) this->isMACPayload = true; this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - uint8_t strDown[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] foptsBuff; + #endif + + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; + #endif size_t lenDown = 0; state = this->downlink(strDown, &lenDown); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] strDown; + #endif RADIOLIB_ASSERT(state); } From 4aadd7aab2b1654af5279d278bc683e6ab094dc7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:56:45 +0100 Subject: [PATCH 0800/1848] [HAL] Fixed unused variable warnings --- src/ArduinoHal.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 0485fad8a7..11422d59d8 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -131,6 +131,10 @@ void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) EEPROM.end(); #endif + #else + (void)addr; + (void)buff; + (void)len; #endif } @@ -148,6 +152,10 @@ void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len EEPROM.commit(); EEPROM.end(); #endif + #else + (void)addr; + (void)buff; + (void)len; #endif } @@ -181,6 +189,10 @@ void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long } pwmPin->period(1.0 / frequency); pwmPin->write(0.5); + #else + (void)pin; + (void)frequency; + (void)duration; #endif } @@ -215,6 +227,8 @@ void inline ArduinoHal::noTone(uint32_t pin) { // better tone for mbed OS boards (void)pin; pwmPin->suspend(); + #else + (void)pin; #endif } From 81c59f61ff69749be9579a3566dc55d3bfb765b8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 21 Nov 2023 20:48:06 +0100 Subject: [PATCH 0801/1848] [SX127x] Fixed copy-pasted code snippet --- src/modules/SX127x/SX127x.cpp | 47 ++++++++++++++--------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 02a2d3780e..fe953f3366 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -152,43 +152,32 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t modem = getActiveModem(); uint32_t start = 0; + uint32_t timeout = 0; if(modem == RADIOLIB_SX127X_LORA) { // calculate timeout (150 % of expected time-on-air) - uint32_t timeout = getTimeOnAir(len) * 1.5; - - // start transmission - state = startTransmit(data, len, addr); - RADIOLIB_ASSERT(state); - - // wait for packet transmission or timeout - start = this->mod->hal->micros(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { - finishTransmit(); - return(RADIOLIB_ERR_TX_TIMEOUT); - } - } + timeout = getTimeOnAir(len) * 1.5; } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000 + getTimeOnAir(len) * 5; - - // start transmission - state = startTransmit(data, len, addr); - RADIOLIB_ASSERT(state); + timeout = 5000 + getTimeOnAir(len) * 5; - // wait for transmission end or timeout - start = this->mod->hal->micros(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { - finishTransmit(); - return(RADIOLIB_ERR_TX_TIMEOUT); - } - } } else { return(RADIOLIB_ERR_UNKNOWN); + + } + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } } // update data rate From 594d8cbba11add408844950f6f726bc31c9138b8 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 27 Nov 2023 12:39:14 +0100 Subject: [PATCH 0802/1848] [LoRaWAN] Move TX power logic to function --- src/protocols/LoRaWAN/LoRaWAN.cpp | 50 +++++++++++++++++-------------- src/protocols/LoRaWAN/LoRaWAN.h | 11 +++++-- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index af930be921..a8f1fd2b3d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -698,6 +698,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf this->isMACPayload = false; } + int16_t state = RADIOLIB_ERR_NONE; + // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; size_t foptsBufSize = 0; @@ -722,18 +724,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf if((this->fcntUp - this->adrFcnt) >= adrLimit) { adrAckReq = true; } + // if we hit the Limit + Delay, try one of three, in order: + // set TxPower to max, set DR to min, enable all defined channels if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { - // try one of three, in order: set TxPower to max, set DR to min, enable all defined channels // set the maximum power supported by both the module and the band - int8_t pwr = this->band->powerMax; - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power in band and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(pwr--); - } + int8_t pwrPrev = this->txPwrCur; + state = this->setTxPower(this->band->powerMax); RADIOLIB_ASSERT(state); - if(pwr == this->txPwrCur) { + + if(this->txPwrCur == pwrPrev) { // failed to increase Tx power, so try to decrease the datarate if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { @@ -750,8 +750,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } } - } else { - this->txPwrCur = pwr; } // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' @@ -760,7 +758,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // configure for uplink this->selectChannels(); - int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // build the uplink message @@ -1366,15 +1364,8 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { int16_t LoRaWANNode::setPhyProperties() { // set the physical layer configuration - - // set the maximum power supported by both the module and the band - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power in band and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(this->txPwrCur--); - } + int16_t state = this->setTxPower(this->txPwrCur); RADIOLIB_ASSERT(state); - this->txPwrCur++; uint8_t syncWord[3] = { 0 }; uint8_t syncWordLen = 0; @@ -1688,6 +1679,19 @@ void LoRaWANNode::setADR(bool enable) { this->adrEnabled = enable; } +int16_t LoRaWANNode::setTxPower(int8_t txPower) { + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(txPower--); + } + if(state == RADIOLIB_ERR_NONE) { + txPower++; + this->txPwrCur = txPower; + } + return(state); +} + int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { uint8_t dataRateBand = this->band->dataRates[dr]; @@ -1838,13 +1842,15 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t pwrAck = 0; if(txPower == 0x0F) { pwrAck = 1; + } else { int8_t pwr = this->band->powerMax - 2*txPower; - if(this->phyLayer->setOutputPower(pwr) == RADIOLIB_ERR_NONE) { - RADIOLIB_DEBUG_PRINTLN("ADR set pwr = %d", pwr); + int16_t state = this->setTxPower(pwr); + // only acknowledge if the requested datarate was succesfully configured + if((state == RADIOLIB_ERR_NONE) && (this->txPwrCur == pwr)) { pwrAck = 1; } - this->txPwrCur = pwr; + } uint8_t chMaskAck = 1; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index da1a435675..6e4523d0cd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -532,11 +532,18 @@ class LoRaWANNode { int16_t setDatarate(uint8_t drUp); /*! - \brief Toggle ADR to on or off - \param enable Whether to disable ADR or not + \brief Toggle ADR to on or off. + \param enable Whether to disable ADR or not. */ void setADR(bool enable = true); + /*! + \brief Configure TX power of the radio module. + \param txPower Output power during TX mode to be set in dBm. + \returns \ref status_codes + */ + int16_t setTxPower(int8_t txPower); + /*! \brief Select a single subband (8 channels) for fixed bands such as US915. Only available before joining a network. From 3d6db1b79a387d6111b4b1e7827cea1d3a8cd3ab Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 27 Nov 2023 15:41:41 +0100 Subject: [PATCH 0803/1848] Update keywords --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 1a19ea40c9..24369e1776 100644 --- a/keywords.txt +++ b/keywords.txt @@ -300,6 +300,7 @@ sendReceive KEYWORD2 setDeviceStatus KEYWORD2 setDatarate KEYWORD2 setADR KEYWORD2 +setTxPower KEYWORD2 selectSubband KEYWORD2 setCSMA KEYWORD2 From b2b73ab21db9a5e66e7b9acc0639a412f7eee70a Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:10:47 +0100 Subject: [PATCH 0804/1848] [LoRaWAN] Move TX power logic to function (#884) * [LoRaWAN] Move TX power logic to function * Update keywords --- keywords.txt | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 50 +++++++++++++++++-------------- src/protocols/LoRaWAN/LoRaWAN.h | 11 +++++-- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/keywords.txt b/keywords.txt index 1a19ea40c9..24369e1776 100644 --- a/keywords.txt +++ b/keywords.txt @@ -300,6 +300,7 @@ sendReceive KEYWORD2 setDeviceStatus KEYWORD2 setDatarate KEYWORD2 setADR KEYWORD2 +setTxPower KEYWORD2 selectSubband KEYWORD2 setCSMA KEYWORD2 diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index af930be921..a8f1fd2b3d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -698,6 +698,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf this->isMACPayload = false; } + int16_t state = RADIOLIB_ERR_NONE; + // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; size_t foptsBufSize = 0; @@ -722,18 +724,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf if((this->fcntUp - this->adrFcnt) >= adrLimit) { adrAckReq = true; } + // if we hit the Limit + Delay, try one of three, in order: + // set TxPower to max, set DR to min, enable all defined channels if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { - // try one of three, in order: set TxPower to max, set DR to min, enable all defined channels // set the maximum power supported by both the module and the band - int8_t pwr = this->band->powerMax; - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power in band and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(pwr--); - } + int8_t pwrPrev = this->txPwrCur; + state = this->setTxPower(this->band->powerMax); RADIOLIB_ASSERT(state); - if(pwr == this->txPwrCur) { + + if(this->txPwrCur == pwrPrev) { // failed to increase Tx power, so try to decrease the datarate if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { @@ -750,8 +750,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } } - } else { - this->txPwrCur = pwr; } // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' @@ -760,7 +758,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // configure for uplink this->selectChannels(); - int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // build the uplink message @@ -1366,15 +1364,8 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { int16_t LoRaWANNode::setPhyProperties() { // set the physical layer configuration - - // set the maximum power supported by both the module and the band - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power in band and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(this->txPwrCur--); - } + int16_t state = this->setTxPower(this->txPwrCur); RADIOLIB_ASSERT(state); - this->txPwrCur++; uint8_t syncWord[3] = { 0 }; uint8_t syncWordLen = 0; @@ -1688,6 +1679,19 @@ void LoRaWANNode::setADR(bool enable) { this->adrEnabled = enable; } +int16_t LoRaWANNode::setTxPower(int8_t txPower) { + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(txPower--); + } + if(state == RADIOLIB_ERR_NONE) { + txPower++; + this->txPwrCur = txPower; + } + return(state); +} + int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { uint8_t dataRateBand = this->band->dataRates[dr]; @@ -1838,13 +1842,15 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t pwrAck = 0; if(txPower == 0x0F) { pwrAck = 1; + } else { int8_t pwr = this->band->powerMax - 2*txPower; - if(this->phyLayer->setOutputPower(pwr) == RADIOLIB_ERR_NONE) { - RADIOLIB_DEBUG_PRINTLN("ADR set pwr = %d", pwr); + int16_t state = this->setTxPower(pwr); + // only acknowledge if the requested datarate was succesfully configured + if((state == RADIOLIB_ERR_NONE) && (this->txPwrCur == pwr)) { pwrAck = 1; } - this->txPwrCur = pwr; + } uint8_t chMaskAck = 1; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index da1a435675..6e4523d0cd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -532,11 +532,18 @@ class LoRaWANNode { int16_t setDatarate(uint8_t drUp); /*! - \brief Toggle ADR to on or off - \param enable Whether to disable ADR or not + \brief Toggle ADR to on or off. + \param enable Whether to disable ADR or not. */ void setADR(bool enable = true); + /*! + \brief Configure TX power of the radio module. + \param txPower Output power during TX mode to be set in dBm. + \returns \ref status_codes + */ + int16_t setTxPower(int8_t txPower); + /*! \brief Select a single subband (8 channels) for fixed bands such as US915. Only available before joining a network. From 4703f58b7f4509a7bf59975dcac17be8808e6259 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 27 Nov 2023 16:20:06 +0100 Subject: [PATCH 0805/1848] [LoRaWAN] Add datarate into event structure --- .../LoRaWAN_End_Device_Reference.ino | 2 ++ src/protocols/LoRaWAN/LoRaWAN.cpp | 2 ++ src/protocols/LoRaWAN/LoRaWAN.h | 3 +++ 3 files changed, 7 insertions(+) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index c31752e7e8..bf70f13951 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -214,6 +214,8 @@ void loop() { Serial.println(event.confirmed); Serial.print(F("[LoRaWAN] Confirming:\t")); Serial.println(event.confirming); + Serial.print(F("[LoRaWAN] Datarate:\t")); + Serial.print(event.datarate); Serial.print(F("[LoRaWAN] Frequency:\t")); Serial.print(event.freq, 3); Serial.println(F(" MHz")); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a8f1fd2b3d..99c93549ec 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -904,6 +904,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; event->confirmed = isConfirmed; event->confirming = isConfirmingDown; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPwrCur; event->fcnt = this->fcntUp; @@ -1262,6 +1263,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; event->confirmed = isConfirmedDown; event->confirming = isConfirmingUp; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPwrCur; event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 6e4523d0cd..30ff25123c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -325,6 +325,9 @@ struct LoRaWANEvent_t { /*! \brief Whether the event is confirming a previous request (e.g., server downlink reply to confirmed uplink sent by user application)*/ bool confirming; + + /*! \brief Datarate */ + uint8_t datarate; /*! \brief Frequency in MHz */ float freq; From b6f6718f1ff0fac5e0938cead16ea4ad1453a738 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:43:56 +0100 Subject: [PATCH 0806/1848] [LoRaWAN] Add datarate into event structure (#885) * [LoRaWAN] Move TX power logic to function * Update keywords * [LoRaWAN] Add datarate into event structure --- .../LoRaWAN_End_Device_Reference.ino | 2 ++ src/protocols/LoRaWAN/LoRaWAN.cpp | 2 ++ src/protocols/LoRaWAN/LoRaWAN.h | 3 +++ 3 files changed, 7 insertions(+) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index c31752e7e8..bf70f13951 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -214,6 +214,8 @@ void loop() { Serial.println(event.confirmed); Serial.print(F("[LoRaWAN] Confirming:\t")); Serial.println(event.confirming); + Serial.print(F("[LoRaWAN] Datarate:\t")); + Serial.print(event.datarate); Serial.print(F("[LoRaWAN] Frequency:\t")); Serial.print(event.freq, 3); Serial.println(F(" MHz")); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a8f1fd2b3d..99c93549ec 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -904,6 +904,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; event->confirmed = isConfirmed; event->confirming = isConfirmingDown; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPwrCur; event->fcnt = this->fcntUp; @@ -1262,6 +1263,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; event->confirmed = isConfirmedDown; event->confirming = isConfirmingUp; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPwrCur; event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 6e4523d0cd..30ff25123c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -325,6 +325,9 @@ struct LoRaWANEvent_t { /*! \brief Whether the event is confirming a previous request (e.g., server downlink reply to confirmed uplink sent by user application)*/ bool confirming; + + /*! \brief Datarate */ + uint8_t datarate; /*! \brief Frequency in MHz */ float freq; From f4938ea5854e006eb731555023ecae34bec82c6e Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 27 Nov 2023 11:45:18 -0600 Subject: [PATCH 0807/1848] Check for RADIOLIB_SPI_PARANOID = 1 rather than just defined (#883) * Update BuildOpt.h to set RADIOLIB_SPI_PARANOID to 1 by default * Update Module.cpp to check for RADIOLIB_SPI_PARANOID set to 1 --- src/BuildOpt.h | 4 ++-- src/Module.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 813dac83e3..ee8fab5411 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -358,13 +358,13 @@ #endif /* - * Uncomment to enable "paranoid" SPI mode + * Comment to disable "paranoid" SPI mode, or set RADIOLIB_SPI_PARANOID to 0 * Every write to an SPI register using SPI set function will be verified by a subsequent read operation. * This improves reliability, but slightly slows down communication. * Note: Enabled by default. */ #if !defined(RADIOLIB_SPI_PARANOID) - #define RADIOLIB_SPI_PARANOID + #define RADIOLIB_SPI_PARANOID 1 #endif /* diff --git a/src/Module.cpp b/src/Module.cpp index 0848a746f6..cd710eaa58 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -75,7 +75,7 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t uint8_t newValue = (currentValue & ~mask) | (value & mask); SPIwriteRegister(reg, newValue); - #if defined(RADIOLIB_SPI_PARANOID) + #if RADIOLIB_SPI_PARANOID // check register value each millisecond until check interval is reached // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) uint32_t start = this->hal->micros(); @@ -240,7 +240,7 @@ int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size int16_t Module::SPIcheckStream() { int16_t state = RADIOLIB_ERR_NONE; - #if defined(RADIOLIB_SPI_PARANOID) + #if RADIOLIB_SPI_PARANOID // get the status uint8_t spiStatus = 0; uint8_t cmd = this->SPIstatusCommand; From a2e2003001120b50f8bae3e8f41e94fcd71ddf17 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:38:10 +0100 Subject: [PATCH 0808/1848] Reworked macro configuration system --- src/ArduinoHal.h | 2 +- src/BuildOpt.h | 294 +++++++++++++++++++++++---------------------- src/BuildOptUser.h | 4 +- src/Module.cpp | 28 ++--- src/Module.h | 10 +- src/RadioLib.h | 6 +- 6 files changed, 173 insertions(+), 171 deletions(-) diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 2b650db872..bcda95aece 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -62,7 +62,7 @@ class ArduinoHal : public RadioLibHal { void yield() override; uint32_t pinToInterrupt(uint32_t pin) override; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif SPIClass* spi = NULL; diff --git a/src/BuildOpt.h b/src/BuildOpt.h index ee8fab5411..f2b9bc31b4 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1,6 +1,132 @@ #if !defined(_RADIOLIB_BUILD_OPTIONS_H) #define _RADIOLIB_BUILD_OPTIONS_H +/* RadioLib build configuration options */ + +/* + * Debug output enable. + * Warning: Debug output will slow down the whole system significantly. + * Also, it will result in larger compiled binary. + * Levels: debug - only main info + * verbose - full transcript of all SPI communication + */ +#if !defined(RADIOLIB_DEBUG) + #define RADIOLIB_DEBUG (0) +#endif +#if !defined(RADIOLIB_VERBOSE) + #define RADIOLIB_VERBOSE (0) +#endif + +// set which output port should be used for debug output +// may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) +#if !defined(RADIOLIB_DEBUG_PORT) + #define RADIOLIB_DEBUG_PORT Serial +#endif + +/* + * Comment to disable "paranoid" SPI mode, or set RADIOLIB_SPI_PARANOID to 0 + * Every write to an SPI register using SPI set function will be verified by a subsequent read operation. + * This improves reliability, but slightly slows down communication. + * Note: Enabled by default. + */ +#if !defined(RADIOLIB_SPI_PARANOID) + #define RADIOLIB_SPI_PARANOID (1) +#endif + +/* + * Comment to disable parameter range checking + * RadioLib will check provided parameters (such as frequency) against limits determined by the device manufacturer. + * It is highly advised to keep this macro defined, removing it will allow invalid values to be set, + * possibly leading to bricked module and/or program crashing. + * Note: Enabled by default. + */ +#if !defined(RADIOLIB_CHECK_PARAMS) + #define RADIOLIB_CHECK_PARAMS (1) +#endif + +/* + * SX127x errata fix enable + * Warning: SX127x errata fix has been reported to cause issues with LoRa bandwidths lower than 62.5 kHz. + * It should only be enabled if you really are observing some errata-related issue. + * Note: Disabled by default. + */ +#if !defined(RADIOLIB_FIX_ERRATA_SX127X) + #define RADIOLIB_FIX_ERRATA_SX127X (0) +#endif + +/* + * God mode enable - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code. + * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. + * Failure to heed the above warning may result in bricked module. + */ +#if !defined(RADIOLIB_GODMODE) + #define RADIOLIB_GODMODE (0) +#endif + +/* + * Low-level hardware access enable + * This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite" + * Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this. + */ +#if !defined(RADIOLIB_LOW_LEVEL) + #define RADIOLIB_LOW_LEVEL (0) +#endif + +/* + * Enable pre-defined modules when using RadioShield, disabled by default. + */ +#if !defined(RADIOLIB_RADIOSHIELD) + #define RADIOLIB_RADIOSHIELD (0) +#endif + +/* + * Enable interrupt-based timing control + * For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing + */ +#if !defined(RADIOLIB_INTERRUPT_TIMING) + #define RADIOLIB_INTERRUPT_TIMING (0) +#endif + +/* + * Enable static-only memory management: no dynamic allocation will be performed. + * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. + */ +#if !defined(RADIOLIB_STATIC_ONLY) + #define RADIOLIB_STATIC_ONLY (0) +#endif + +// set the size of static arrays to use +#if !defined(RADIOLIB_STATIC_ARRAY_SIZE) + #define RADIOLIB_STATIC_ARRAY_SIZE (256) +#endif + +// the base address for persistent storage +// some protocols (e.g. LoRaWAN) require a method +// to store some data persistently +// on Arduino, this will use EEPROM, on non-Arduino platform, +// it will use anything provided by the hardware abstraction layer +// RadioLib will place these starting at this address +#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_BASE (0) +#endif + +// the amount of space allocated to the persistent storage +#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x0180) +#endif + +/* + * Uncomment on boards whose clock runs too slow or too fast + * Set the value according to the following scheme: + * Enable timestamps on your terminal + * Print something to terminal, wait 1000 milliseconds, print something again + * If the difference is e.g. 1014 milliseconds between the prints, set this value to 14 + * Or, for more accuracy, wait for 100,000 milliseconds and divide the total drift by 100 + */ +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + //#define RADIOLIB_CLOCK_DRIFT_MS (0) +#endif + #if ARDUINO >= 100 // Arduino build #include "Arduino.h" @@ -61,23 +187,23 @@ // NOTE: Some of the exclusion macros are dependent on each other. For example, it is not possible to exclude RF69 // while keeping SX1231 (because RF69 is the base class for SX1231). The dependency is always uni-directional, // so excluding SX1231 and keeping RF69 is valid. - //#define RADIOLIB_EXCLUDE_CC1101 - //#define RADIOLIB_EXCLUDE_NRF24 - //#define RADIOLIB_EXCLUDE_RF69 - //#define RADIOLIB_EXCLUDE_SX1231 // dependent on RADIOLIB_EXCLUDE_RF69 - //#define RADIOLIB_EXCLUDE_SI443X - //#define RADIOLIB_EXCLUDE_RFM2X // dependent on RADIOLIB_EXCLUDE_SI443X - //#define RADIOLIB_EXCLUDE_SX127X - //#define RADIOLIB_EXCLUDE_SX126X - //#define RADIOLIB_EXCLUDE_STM32WLX // dependent on RADIOLIB_EXCLUDE_SX126X - //#define RADIOLIB_EXCLUDE_SX128X - //#define RADIOLIB_EXCLUDE_AFSK - //#define RADIOLIB_EXCLUDE_AX25 - //#define RADIOLIB_EXCLUDE_HELLSCHREIBER - //#define RADIOLIB_EXCLUDE_MORSE - //#define RADIOLIB_EXCLUDE_RTTY - //#define RADIOLIB_EXCLUDE_SSTV - //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE + //#define RADIOLIB_EXCLUDE_CC1101 (1) + //#define RADIOLIB_EXCLUDE_NRF24 (1) + //#define RADIOLIB_EXCLUDE_RF69 (1) + //#define RADIOLIB_EXCLUDE_SX1231 (1) // dependent on RADIOLIB_EXCLUDE_RF69 + //#define RADIOLIB_EXCLUDE_SI443X (1) + //#define RADIOLIB_EXCLUDE_RFM2X (1) // dependent on RADIOLIB_EXCLUDE_SI443X + //#define RADIOLIB_EXCLUDE_SX127X (1) + //#define RADIOLIB_EXCLUDE_SX126X (1) + //#define RADIOLIB_EXCLUDE_STM32WLX (1) // dependent on RADIOLIB_EXCLUDE_SX126X + //#define RADIOLIB_EXCLUDE_SX128X (1) + //#define RADIOLIB_EXCLUDE_AFSK (1) + //#define RADIOLIB_EXCLUDE_AX25 (1) + //#define RADIOLIB_EXCLUDE_HELLSCHREIBER (1) + //#define RADIOLIB_EXCLUDE_MORSE (1) + //#define RADIOLIB_EXCLUDE_RTTY (1) + //#define RADIOLIB_EXCLUDE_SSTV (1) + //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE (1) #elif defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. @@ -337,137 +463,13 @@ #endif -/* - * Uncomment to enable debug output. - * Warning: Debug output will slow down the whole system significantly. - * Also, it will result in larger compiled binary. - * Levels: debug - only main info - * verbose - full transcript of all SPI communication - */ -#if !defined(RADIOLIB_DEBUG) - //#define RADIOLIB_DEBUG -#endif -#if !defined(RADIOLIB_VERBOSE) - //#define RADIOLIB_VERBOSE -#endif - -// set which output port should be used for debug output -// may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) -#if defined(RADIOLIB_BUILD_ARDUINO) && !defined(RADIOLIB_DEBUG_PORT) - #define RADIOLIB_DEBUG_PORT Serial -#endif - -/* - * Comment to disable "paranoid" SPI mode, or set RADIOLIB_SPI_PARANOID to 0 - * Every write to an SPI register using SPI set function will be verified by a subsequent read operation. - * This improves reliability, but slightly slows down communication. - * Note: Enabled by default. - */ -#if !defined(RADIOLIB_SPI_PARANOID) - #define RADIOLIB_SPI_PARANOID 1 -#endif - -/* - * Uncomment to enable parameter range checking - * RadioLib will check provided parameters (such as frequency) against limits determined by the device manufacturer. - * It is highly advised to keep this macro defined, removing it will allow invalid values to be set, - * possibly leading to bricked module and/or program crashing. - * Note: Enabled by default. - */ -#if !defined(RADIOLIB_CHECK_PARAMS) - #define RADIOLIB_CHECK_PARAMS -#endif - -/* - * Uncomment to enable SX127x errata fix - * Warning: SX127x errata fix has been reported to cause issues with LoRa bandwidths lower than 62.5 kHz. - * It should only be enabled if you really are observing some errata-related issue. - * Note: Disabled by default. - */ -#if !defined(RADIOLIB_FIX_ERRATA_SX127X) - //#define RADIOLIB_FIX_ERRATA_SX127X -#endif - -/* - * Uncomment to enable god mode - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code. - * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. - * Failure to heed the above warning may result in bricked module. - */ -#if !defined(RADIOLIB_GODMODE) - //#define RADIOLIB_GODMODE -#endif - -/* - * Uncomment to enable low-level hardware access - * This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite" - * Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this. - */ -#if !defined(RADIOLIB_LOW_LEVEL) - //#define RADIOLIB_LOW_LEVEL -#endif - -/* - * Uncomment to enable pre-defined modules when using RadioShield. - */ -#if !defined(RADIOLIB_RADIOSHIELD) - //#define RADIOLIB_RADIOSHIELD -#endif - -/* - * Uncomment to enable interrupt-based timing control - * For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing - */ -#if !defined(RADIOLIB_INTERRUPT_TIMING) - //#define RADIOLIB_INTERRUPT_TIMING -#endif - -/* - * Uncomment to enable static-only memory management: no dynamic allocation will be performed. - * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. - */ -#if !defined(RADIOLIB_STATIC_ONLY) - //#define RADIOLIB_STATIC_ONLY -#endif - -// set the size of static arrays to use -#if !defined(RADIOLIB_STATIC_ARRAY_SIZE) - #define RADIOLIB_STATIC_ARRAY_SIZE (256) -#endif - -// the base address for persistent storage -// some protocols (e.g. LoRaWAN) require a method -// to store some data persistently -// on Arduino, this will use EEPROM, on non-Arduino platform, -// it will use anything provided by the hardware abstraction layer -// RadioLib will place these starting at this address -#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_BASE (0) -#endif - -// the amount of space allocated to the persistent storage -#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x0180) -#endif - -/* - * Uncomment on boards whose clock runs too slow or too fast - * Set the value according to the following scheme: - * Enable timestamps on your terminal - * Print something to terminal, wait 1000 milliseconds, print something again - * If the difference is e.g. 1014 milliseconds between the prints, set this value to 14 - * Or, for more accuracy, wait for 100,000 milliseconds and divide the total drift by 100 - */ -#if !defined(RADIOLIB_CLOCK_DRIFT_MS) - //#define RADIOLIB_CLOCK_DRIFT_MS (0) -#endif - // This only compiles on STM32 boards with SUBGHZ module, but also // include when generating docs #if (!defined(ARDUINO_ARCH_STM32) || !defined(SUBGHZSPI_BASE)) && !defined(DOXYGEN) - #define RADIOLIB_EXCLUDE_STM32WLX + #define RADIOLIB_EXCLUDE_STM32WLX (1) #endif -#if defined(RADIOLIB_DEBUG) +#if RADIOLIB_DEBUG #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) @@ -491,7 +493,7 @@ #define RADIOLIB_DEBUG_HEXDUMP(...) {} #endif -#if defined(RADIOLIB_VERBOSE) +#if RADIOLIB_VERBOSE #define RADIOLIB_VERBOSE_PRINT(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) #else @@ -507,13 +509,13 @@ /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled */ -#if defined(RADIOLIB_CHECK_PARAMS) +#if RADIOLIB_CHECK_PARAMS #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } #else #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {} #endif -#if defined(RADIOLIB_FIX_ERRATA_SX127X) +#if RADIOLIB_FIX_ERRATA_SX127X #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); } #else #define RADIOLIB_ERRATA_SX127X(...) {} diff --git a/src/BuildOptUser.h b/src/BuildOptUser.h index 5df3c2be71..fc1a565743 100644 --- a/src/BuildOptUser.h +++ b/src/BuildOptUser.h @@ -5,7 +5,7 @@ // most commonly, RADIOLIB_EXCLUDE_* macros // or enabling debug output -//#define RADIOLIB_DEBUG -//#define RADIOLIB_VERBOSE +//#define RADIOLIB_DEBUG (1) +//#define RADIOLIB_VERBOSE (1) #endif diff --git a/src/Module.cpp b/src/Module.cpp index cd710eaa58..b6f8583d0f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -5,7 +5,7 @@ #include #include -#if defined(RADIOLIB_DEBUG) +#if RADIOLIB_DEBUG // needed for debug print #include #endif @@ -145,7 +145,7 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { // prepare the buffers size_t buffLen = this->SPIaddrWidth/8 + numBytes; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -182,7 +182,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d } // print debug information - #if defined(RADIOLIB_VERBOSE) + #if RADIOLIB_VERBOSE uint8_t* debugBuffPtr = NULL; if(cmd == SPIwriteCommand) { RADIOLIB_VERBOSE_PRINT("W\t%X\t", reg); @@ -197,7 +197,7 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d RADIOLIB_VERBOSE_PRINTLN(); #endif - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; #endif @@ -262,7 +262,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint if(!write) { buffLen++; } - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -292,7 +292,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint this->hal->yield(); if(this->hal->millis() - start >= timeout) { RADIOLIB_DEBUG_PRINTLN("GPIO pre-transfer timeout, is it connected?"); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; #endif @@ -319,7 +319,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint this->hal->yield(); if(this->hal->millis() - start >= timeout) { RADIOLIB_DEBUG_PRINTLN("GPIO post-transfer timeout, is it connected?"); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; #endif @@ -342,7 +342,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } // print debug information - #if defined(RADIOLIB_VERBOSE) + #if RADIOLIB_VERBOSE // print command byte(s) RADIOLIB_VERBOSE_PRINT("CMD"); if(write) { @@ -369,7 +369,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint RADIOLIB_VERBOSE_PRINTLN(); #endif - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; #endif @@ -378,7 +378,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } void Module::waitForMicroseconds(uint32_t start, uint32_t len) { - #if defined(RADIOLIB_INTERRUPT_TIMING) + #if RADIOLIB_INTERRUPT_TIMING (void)start; if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) { prevTimingLen = len; @@ -403,7 +403,7 @@ uint32_t Module::reflect(uint32_t in, uint8_t bits) { return(res); } -#if defined(RADIOLIB_DEBUG) +#if RADIOLIB_DEBUG void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { @@ -450,20 +450,20 @@ void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, } void Module::regdump(uint16_t start, size_t len) { - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* buff = new uint8_t[len]; #endif SPIreadRegisterBurst(start, len, buff); hexdump(buff, len, start); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] buff; #endif } #endif -#if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO) +#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) // https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 size_t Module::serialPrintf(const char* format, ...) { va_list arg; diff --git a/src/Module.h b/src/Module.h index 56697ac953..c67aaf6aa6 100644 --- a/src/Module.h +++ b/src/Module.h @@ -168,7 +168,7 @@ class Module { */ SPIparseStatusCb_t SPIparseStatusCb = nullptr; - #if defined(RADIOLIB_INTERRUPT_TIMING) + #if RADIOLIB_INTERRUPT_TIMING /*! \brief Timer interrupt setup callback typedef. @@ -468,7 +468,7 @@ class Module { */ static uint32_t reflect(uint32_t in, uint8_t bits); - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG /*! \brief Function to dump data as hex into the debug port. \param data Data to dump. @@ -486,11 +486,11 @@ class Module { void regdump(uint16_t start, size_t len); #endif - #if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO) + #if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) static size_t serialPrintf(const char* format, ...); #endif -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif uint32_t csPin = RADIOLIB_NC; @@ -502,7 +502,7 @@ class Module { uint32_t rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; const RfSwitchMode_t *rfSwitchTable = nullptr; - #if defined(RADIOLIB_INTERRUPT_TIMING) + #if RADIOLIB_INTERRUPT_TIMING uint32_t prevTimingLen = 0; #endif }; diff --git a/src/RadioLib.h b/src/RadioLib.h index 735309d289..3fd9632aa3 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -47,7 +47,7 @@ // warnings are printed in this file since BuildOpt.h is compiled in multiple places // check God mode -#if defined(RADIOLIB_GODMODE) +#if RADIOLIB_GODMODE #warning "God mode active, I hope it was intentional. Buckle up, lads." #endif @@ -120,7 +120,7 @@ #include "utils/Cryptography.h" // only create Radio class when using RadioShield -#if defined(RADIOLIB_RADIOSHIELD) +#if RADIOLIB_RADIOSHIELD // RadioShield pin definitions #define RADIOSHIELD_CS_A 10 @@ -152,7 +152,7 @@ class Radio { ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_IRQ_B, RADIOSHIELD_RST_B, RADIOSHIELD_GPIO_B); } -#if defined(RADIOLIB_GODMODE) +#if RADIOLIB_GODMODE private: #endif From 1d77d8bd556efe75c92a74e297a6e385f1868985 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:38:30 +0100 Subject: [PATCH 0809/1848] [FEC] Reworked macro configuration system --- src/utils/FEC.cpp | 26 +++++++++++++------------- src/utils/FEC.h | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/utils/FEC.cpp b/src/utils/FEC.cpp index e8cf260ea9..39d7f5d5fe 100644 --- a/src/utils/FEC.cpp +++ b/src/utils/FEC.cpp @@ -14,7 +14,7 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { this->n = n; this->k = k; this->poly = poly; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY this->alphaTo = new int32_t[n + 1]; this->indexOf = new int32_t[n + 1]; this->generator = new int32_t[n - k + 1]; @@ -115,7 +115,7 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { // Search for roots 1, 2, ..., m-1 in cycle sets int32_t rdncy = 0; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t min[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; #else int32_t* min = new int32_t[this->n - this->k + 1]; @@ -139,7 +139,7 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { } int32_t noterms = kaux; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t zeros[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; #else int32_t* zeros = new int32_t[this->n - this->k + 1]; @@ -153,7 +153,7 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { } } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] min; #endif @@ -173,7 +173,7 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { this->generator[0] = this->alphaTo[(this->indexOf[this->generator[0]] + zeros[ii]) % this->n]; } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] zeros; #endif } @@ -185,7 +185,7 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { */ uint32_t RadioLibBCH::encode(uint32_t dataword) { // we only use the "k" most significant bits - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t data[RADIOLIB_BCH_MAX_K]; #else int32_t* data = new int32_t[this->k]; @@ -200,7 +200,7 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } // reset the M(x)+r array elements - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t Mr[RADIOLIB_BCH_MAX_N]; #else int32_t* Mr = new int32_t[this->n]; @@ -227,7 +227,7 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t bb[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; #else int32_t* bb = new int32_t[this->n - this->k + 1]; @@ -238,12 +238,12 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { ++j; } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] Mr; #endif int32_t iEvenParity = 0; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t recd[RADIOLIB_BCH_MAX_N + 1]; #else int32_t* recd = new int32_t[this->n + 1]; @@ -255,7 +255,7 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] data; #endif @@ -266,7 +266,7 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] bb; #endif @@ -283,7 +283,7 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] recd; #endif diff --git a/src/utils/FEC.h b/src/utils/FEC.h index 76f2bcad17..0716fe11c7 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -12,7 +12,7 @@ #define RADIOLIB_PAGER_BCH_K (21) #define RADIOLIB_PAGER_BCH_PRIMITIVE_POLY (0x25) -#if defined(RADIOLIB_STATIC_ONLY) +#if RADIOLIB_STATIC_ONLY #define RADIOLIB_BCH_MAX_N (63) #define RADIOLIB_BCH_MAX_K (31) #endif @@ -52,7 +52,7 @@ class RadioLibBCH { uint32_t poly; uint8_t m; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY int32_t alphaTo[RADIOLIB_BCH_MAX_N + 1]; int32_t indexOf[RADIOLIB_BCH_MAX_N + 1]; int32_t generator[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; From 0c436e5ed8885fdfd42e119b316d51ba876b532f Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:39:24 +0100 Subject: [PATCH 0810/1848] [CC1101] Reworked macro configuration system --- src/modules/CC1101/CC1101.cpp | 4 ++-- src/modules/CC1101/CC1101.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index be2056b25c..6cae666a64 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1,6 +1,6 @@ #include "CC1101.h" #include -#if !defined(RADIOLIB_EXCLUDE_CC1101) +#if !RADIOLIB_EXCLUDE_CC1101 CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) { this->mod = module; @@ -935,7 +935,7 @@ int16_t CC1101::getChipVersion() { return(SPIgetRegValue(RADIOLIB_CC1101_REG_VERSION)); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void CC1101::setDirectAction(void (*func)(void)) { setGdo0Action(func, this->mod->hal->GpioInterruptRising); } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 2e83d926e6..53652f3538 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -1,4 +1,4 @@ -#if !defined(_RADIOLIB_CC1101_H) && !defined(RADIOLIB_EXCLUDE_CC1101) +#if !defined(_RADIOLIB_CC1101_H) && !RADIOLIB_EXCLUDE_CC1101 #define _RADIOLIB_CC1101_H #include "../../TypeDef.h" @@ -922,7 +922,7 @@ class CC1101: public PhysicalLayer { */ int16_t getChipVersion(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is receveid in direct mode. \param func Pointer to interrupt service routine. @@ -944,7 +944,7 @@ class CC1101: public PhysicalLayer { */ int16_t setDIOMapping(uint32_t pin, uint32_t value); - #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; @@ -959,7 +959,7 @@ class CC1101: public PhysicalLayer { void SPIsendCommand(uint8_t cmd); - #if !defined(RADIOLIB_GODMODE) + #if !RADIOLIB_GODMODE protected: #endif From 509b8204f1281c32add627763b0c13a6dfbb0f3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:39:35 +0100 Subject: [PATCH 0811/1848] [LLCC68] Reworked macro configuration system --- src/modules/LLCC68/LLCC68.cpp | 2 +- src/modules/LLCC68/LLCC68.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 034835847b..30c12ec823 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -1,5 +1,5 @@ #include "LLCC68.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X LLCC68::LLCC68(Module* mod) : SX1262(mod) { chipType = RADIOLIB_LLCC68_CHIP_TYPE; diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 1cec96f1e2..0ed55902b6 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X #include "../../Module.h" #include "../SX126x/SX1262.h" @@ -56,7 +56,7 @@ class LLCC68: public SX1262 { */ int16_t setSpreadingFactor(uint8_t sf); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif From 63287ab6fda74435fd7ee19122c8739acef1711a Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:40:00 +0100 Subject: [PATCH 0812/1848] [nRF24] Reworked macro configuration system --- src/modules/nRF24/nRF24.cpp | 6 +++--- src/modules/nRF24/nRF24.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index c48b5b17fa..e4923bcded 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -1,6 +1,6 @@ #include "nRF24.h" #include -#if !defined(RADIOLIB_EXCLUDE_NRF24) +#if !RADIOLIB_EXCLUDE_NRF24 nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) { this->mod = mod; @@ -617,7 +617,7 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { // prepare the buffers size_t buffLen = 1 + numBytes; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -648,7 +648,7 @@ void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* data memcpy(dataIn, &buffIn[1], numBytes); } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; #endif diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 5a59877f3f..d6f9346a7f 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -1,4 +1,4 @@ -#if !defined(_RADIOLIB_NRF24_H) && !defined(RADIOLIB_EXCLUDE_NRF24) +#if !defined(_RADIOLIB_NRF24_H) && !RADIOLIB_EXCLUDE_NRF24 #define _RADIOLIB_NRF24_H #include "../../Module.h" @@ -467,7 +467,7 @@ class nRF24: public PhysicalLayer { */ int16_t setEncoding(uint8_t encoding) override; -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; @@ -476,7 +476,7 @@ class nRF24: public PhysicalLayer { void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes); void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif From 2e1ce8ce8988820cf5892540afe386085ec9d787 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:40:19 +0100 Subject: [PATCH 0813/1848] [RF69] Reworked macro configuration system --- src/modules/RF69/RF69.cpp | 4 ++-- src/modules/RF69/RF69.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 6af30faeba..b414d0f3cc 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -1,6 +1,6 @@ #include "RF69.h" #include -#if !defined(RADIOLIB_EXCLUDE_RF69) +#if !RADIOLIB_EXCLUDE_RF69 RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) { this->mod = module; @@ -960,7 +960,7 @@ uint8_t RF69::randomByte() { return(randByte); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void RF69::setDirectAction(void (*func)(void)) { setDio1Action(func); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 8ecb2a85ae..93d1dff33b 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_RF69) +#if !RADIOLIB_EXCLUDE_RF69 #include "../../Module.h" @@ -973,7 +973,7 @@ class RF69: public PhysicalLayer { */ int16_t getChipVersion(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. @@ -995,12 +995,12 @@ class RF69: public PhysicalLayer { */ int16_t setDIOMapping(uint32_t pin, uint32_t value); -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif @@ -1025,7 +1025,7 @@ class RF69: public PhysicalLayer { int16_t directMode(); int16_t setPacketMode(uint8_t mode, uint8_t len); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif int16_t setMode(uint8_t mode); From f0f9200269dc8e20d0aae021ebed400cf97b45b5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:40:32 +0100 Subject: [PATCH 0814/1848] [RFM2x] Reworked macro configuration system --- src/modules/RFM2x/RFM22.h | 2 +- src/modules/RFM2x/RFM23.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/RFM2x/RFM22.h b/src/modules/RFM2x/RFM22.h index f1055a8deb..12317017c1 100644 --- a/src/modules/RFM2x/RFM22.h +++ b/src/modules/RFM2x/RFM22.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_RFM2X) +#if !RADIOLIB_EXCLUDE_RFM2X #include "../../Module.h" #include "../Si443x/Si443x.h" diff --git a/src/modules/RFM2x/RFM23.h b/src/modules/RFM2x/RFM23.h index 3fd333624b..fb7f0591ee 100644 --- a/src/modules/RFM2x/RFM23.h +++ b/src/modules/RFM2x/RFM23.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_RFM2X) +#if !RADIOLIB_EXCLUDE_RFM2X #include "../../Module.h" #include "../Si443x/Si443x.h" From 77c9b2875d028915d71ae8151036feacadc78294 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:40:57 +0100 Subject: [PATCH 0815/1848] [Si443x] Reworked macro configuration system --- src/modules/Si443x/Si4430.cpp | 2 +- src/modules/Si443x/Si4430.h | 6 +++--- src/modules/Si443x/Si4431.cpp | 2 +- src/modules/Si443x/Si4431.h | 6 +++--- src/modules/Si443x/Si4432.cpp | 2 +- src/modules/Si443x/Si4432.h | 6 +++--- src/modules/Si443x/Si443x.cpp | 4 ++-- src/modules/Si443x/Si443x.h | 10 +++++----- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index 9de46ae12b..c8b030cb0a 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -1,5 +1,5 @@ #include "Si4430.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X Si4430::Si4430(Module* mod) : Si4432(mod) { diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h index 5b07350901..6acac97d18 100644 --- a/src/modules/Si443x/Si4430.h +++ b/src/modules/Si443x/Si4430.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X #include "../../Module.h" #include "Si4432.h" @@ -53,11 +53,11 @@ class Si4430: public Si4432 { */ int16_t setOutputPower(int8_t power); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif }; diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 566b245ae3..953c888f85 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -1,5 +1,5 @@ #include "Si4431.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X Si4431::Si4431(Module* mod) : Si4432(mod) { diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h index 8ca35a3449..8d3d9dd928 100644 --- a/src/modules/Si443x/Si4431.h +++ b/src/modules/Si443x/Si4431.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X #include "../../Module.h" #include "Si4432.h" @@ -46,11 +46,11 @@ class Si4431: public Si4432 { */ int16_t setOutputPower(int8_t power); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif }; diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 0f679d677e..12c212efc1 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -1,5 +1,5 @@ #include "Si4432.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X Si4432::Si4432(Module* mod) : Si443x(mod) { diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h index 3903a5acab..b0a8cb877a 100644 --- a/src/modules/Si443x/Si4432.h +++ b/src/modules/Si443x/Si4432.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X #include "../../Module.h" #include "Si443x.h" @@ -53,11 +53,11 @@ class Si4432: public Si443x { */ int16_t setOutputPower(int8_t power); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif }; diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 2b2bf83585..95ad385a40 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -1,6 +1,6 @@ #include "Si443x.h" #include -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { this->mod = mod; @@ -623,7 +623,7 @@ int16_t Si443x::getChipVersion() { return(this->mod->SPIgetRegValue(RADIOLIB_SI443X_REG_DEVICE_VERSION)); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void Si443x::setDirectAction(void (*func)(void)) { setIrqAction(func); } diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 463b6851da..ca83ba1258 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SI443X) +#if !RADIOLIB_EXCLUDE_SI443X #include "../../Module.h" @@ -797,7 +797,7 @@ class Si443x: public PhysicalLayer { */ int16_t getChipVersion(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. @@ -825,12 +825,12 @@ class Si443x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif @@ -845,7 +845,7 @@ class Si443x: public PhysicalLayer { int16_t setFrequencyRaw(float newFreq); int16_t setPacketMode(uint8_t mode, uint8_t len); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif bool findChip(); From 49feff6df297016036feefb068e1904098ca8a74 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 19:43:01 +0100 Subject: [PATCH 0816/1848] [SX126x] Reworked macro configuration system --- src/modules/SX126x/STM32WLx.cpp | 4 ++-- src/modules/SX126x/STM32WLx.h | 10 +++++----- src/modules/SX126x/STM32WLx_Module.cpp | 4 ++-- src/modules/SX126x/STM32WLx_Module.h | 6 +++--- src/modules/SX126x/SX1261.cpp | 2 +- src/modules/SX126x/SX1261.h | 4 ++-- src/modules/SX126x/SX1262.cpp | 2 +- src/modules/SX126x/SX1262.h | 4 ++-- src/modules/SX126x/SX1268.cpp | 2 +- src/modules/SX126x/SX1268.h | 4 ++-- src/modules/SX126x/SX126x.cpp | 14 +++++++------- src/modules/SX126x/SX126x.h | 10 +++++----- src/modules/SX126x/patches/SX126x_patch_scan.h | 2 +- 13 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index f64b493369..313f8343b2 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -6,7 +6,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT */ #include "STM32WLx.h" -#if !defined(RADIOLIB_EXCLUDE_STM32WLX) +#if !RADIOLIB_EXCLUDE_STM32WLX STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { } @@ -150,4 +150,4 @@ void STM32WLx::clearChannelScanAction() { this->clearDio1Action(); } -#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) +#endif diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index cab2fc54ca..16c88cc95e 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -10,7 +10,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_STM32WLX) +#if !RADIOLIB_EXCLUDE_STM32WLX #include "../../Module.h" #include "SX1262.h" @@ -153,16 +153,16 @@ class STM32WLx : public SX1262 { */ void clearChannelScanAction(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif virtual int16_t clearIrqStatus(uint16_t clearIrqParams) override; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif }; -#endif // !defined(RADIOLIB_EXCLUDE_SX126X) +#endif -#endif // _RADIOLIB_STM32WLX_MODULE_H +#endif diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 1336325b3f..57d0445cd1 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -7,7 +7,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include "STM32WLx_Module.h" -#if !defined(RADIOLIB_EXCLUDE_STM32WLX) +#if !RADIOLIB_EXCLUDE_STM32WLX #include "../../ArduinoHal.h" @@ -103,4 +103,4 @@ STM32WLx_Module::STM32WLx_Module(): RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY ) {} -#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) +#endif diff --git a/src/modules/SX126x/STM32WLx_Module.h b/src/modules/SX126x/STM32WLx_Module.h index f7d1d64de9..878ba775ea 100644 --- a/src/modules/SX126x/STM32WLx_Module.h +++ b/src/modules/SX126x/STM32WLx_Module.h @@ -10,7 +10,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_STM32WLX) +#if !RADIOLIB_EXCLUDE_STM32WLX #include "../../Module.h" @@ -33,6 +33,6 @@ class STM32WLx_Module : public Module { STM32WLx_Module(); }; -#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX) +#endif -#endif // _RADIOLIB_STM32WLX_MODULE_H +#endif diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index 999f4f9f5d..dd39bfef0f 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -1,5 +1,5 @@ #include "SX1261.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X SX1261::SX1261(Module* mod): SX1262(mod) { chipType = RADIOLIB_SX1261_CHIP_TYPE; diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 8d7663e556..01375d5582 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X #include "../../Module.h" #include "SX126x.h" @@ -34,7 +34,7 @@ class SX1261 : public SX1262 { */ int16_t setOutputPower(int8_t power); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index baa27ae865..d24e0f436a 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -1,5 +1,5 @@ #include "SX1262.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X SX1262::SX1262(Module* mod) : SX126x(mod) { chipType = RADIOLIB_SX1262_CHIP_TYPE; diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index d3b67ae5d6..f47b1a8131 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X #include "../../Module.h" #include "SX126x.h" @@ -87,7 +87,7 @@ class SX1262: public SX126x { */ virtual int16_t setOutputPower(int8_t power); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index a2f60f239f..596ce7e451 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -1,5 +1,5 @@ #include "SX1268.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X SX1268::SX1268(Module* mod) : SX126x(mod) { chipType = RADIOLIB_SX1268_CHIP_TYPE; diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index c3e2a607fc..08b3eb4149 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X #include "../../Module.h" #include "SX126x.h" @@ -85,7 +85,7 @@ class SX1268: public SX126x { */ int16_t setOutputPower(int8_t power); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 51e1b8ae8e..797968a83d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1,7 +1,7 @@ #include "SX126x.h" #include #include -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { this->mod = mod; @@ -1547,7 +1547,7 @@ int16_t SX126x::invertIQ(bool enable) { return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); } @@ -1563,7 +1563,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) RADIOLIB_ASSERT(state); // check the version - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG char ver_pre[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %s", ver_pre); @@ -1595,7 +1595,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); // check the version again - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG char ver_post[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); RADIOLIB_DEBUG_PRINTLN("Post-update version string: %s", ver_post); @@ -1839,7 +1839,7 @@ int16_t SX126x::calibrateImage(uint8_t* data) { int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 standby(); @@ -2099,7 +2099,7 @@ int16_t SX126x::config(uint8_t modem) { state = this->mod->SPIcheckStream(); // if something failed, show the device errors - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 standby(); @@ -2142,7 +2142,7 @@ bool SX126x::findChip(const char* verStr) { RADIOLIB_DEBUG_PRINTLN(); flagFound = true; } else { - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG RADIOLIB_DEBUG_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 0c2f9e2081..5e8c03b68b 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X #include "../../Module.h" @@ -1039,7 +1039,7 @@ class SX126x: public PhysicalLayer { */ int16_t invertIQ(bool enable) override; - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. @@ -1104,7 +1104,7 @@ class SX126x: public PhysicalLayer { */ int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif // SX126x SPI command implementations @@ -1146,7 +1146,7 @@ class SX126x: public PhysicalLayer { int16_t fixImplicitTimeout(); int16_t fixInvertedIQ(uint8_t iqConfig); -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; @@ -1154,7 +1154,7 @@ class SX126x: public PhysicalLayer { // common low-level SPI interface static int16_t SPIparseStatus(uint8_t in); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif diff --git a/src/modules/SX126x/patches/SX126x_patch_scan.h b/src/modules/SX126x/patches/SX126x_patch_scan.h index 3dff7be8eb..bc918749a7 100644 --- a/src/modules/SX126x/patches/SX126x_patch_scan.h +++ b/src/modules/SX126x/patches/SX126x_patch_scan.h @@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX126X) +#if !RADIOLIB_EXCLUDE_SX126X // the following is a binary patch to the SX1262 // this patch is needed to enable spectral scan functionality From 34c861cfbe771f2ed2e1d41cf31bc5fc40139d2e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:14:33 +0100 Subject: [PATCH 0817/1848] [SX127x] Reworked macro configuration system --- src/modules/SX127x/SX1272.cpp | 2 +- src/modules/SX127x/SX1272.h | 6 +++--- src/modules/SX127x/SX1273.cpp | 2 +- src/modules/SX127x/SX1273.h | 4 ++-- src/modules/SX127x/SX1276.cpp | 2 +- src/modules/SX127x/SX1276.h | 4 ++-- src/modules/SX127x/SX1277.cpp | 2 +- src/modules/SX127x/SX1277.h | 4 ++-- src/modules/SX127x/SX1278.cpp | 2 +- src/modules/SX127x/SX1278.h | 6 +++--- src/modules/SX127x/SX1279.cpp | 2 +- src/modules/SX127x/SX1279.h | 4 ++-- src/modules/SX127x/SX127x.cpp | 4 ++-- src/modules/SX127x/SX127x.h | 10 +++++----- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 45bf8802b2..ae900a2a10 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -1,6 +1,6 @@ #include "SX1272.h" #include -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX1272::SX1272(Module* mod) : SX127x(mod) { diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index f389230b25..974fa16bdb 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "../../Module.h" #include "SX127x.h" @@ -271,7 +271,7 @@ class SX1272: public SX127x { */ int16_t explicitHeader(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif int16_t setBandwidthRaw(uint8_t newBandwidth); @@ -282,7 +282,7 @@ class SX1272: public SX127x { int16_t configFSK(); void errataFix(bool rx); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif bool ldroAuto = true; diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index ea021c66e4..c3ae5eda9c 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -1,5 +1,5 @@ #include "SX1273.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX1273::SX1273(Module* mod) : SX1272(mod) { diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 2ceb58bc26..12bd05df3c 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "SX1272.h" @@ -56,7 +56,7 @@ class SX1273: public SX1272 { */ int16_t setDataRate(DataRate_t dr) override; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index b20fd7d117..d45826fcc0 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -1,5 +1,5 @@ #include "SX1276.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX1276::SX1276(Module* mod) : SX1278(mod) { diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index aaf2cc4bb7..dd9907d5b8 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "SX1278.h" @@ -63,7 +63,7 @@ class SX1276: public SX1278 { */ int16_t setFrequency(float freq); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 5875bd9f71..76bbb0f61b 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -1,5 +1,5 @@ #include "SX1277.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX1277::SX1277(Module* mod) : SX1278(mod) { diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 15804d6114..0289021fbe 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "SX1278.h" @@ -77,7 +77,7 @@ class SX1277: public SX1278 { */ int16_t setDataRate(DataRate_t dr) override; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 90325ff066..57c9f6f96b 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -1,6 +1,6 @@ #include "SX1278.h" #include -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX1278::SX1278(Module* mod) : SX127x(mod) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index c9f966a2ad..685f08ee35 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "../../Module.h" #include "SX127x.h" @@ -282,7 +282,7 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif int16_t setBandwidthRaw(uint8_t newBandwidth); @@ -293,7 +293,7 @@ class SX1278: public SX127x { int16_t configFSK(); void errataFix(bool rx); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif bool ldroAuto = true; diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 4fdd4daa97..9f9ac03794 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -1,5 +1,5 @@ #include "SX1279.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX1279::SX1279(Module* mod) : SX1278(mod) { diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 1b01368f4d..e802e9c43c 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "SX1278.h" @@ -63,7 +63,7 @@ class SX1279: public SX1278 { */ int16_t setFrequency(float freq); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index fe953f3366..a3ca76c82c 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1,6 +1,6 @@ #include "SX127x.h" #include -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) { this->mod = mod; @@ -1628,7 +1628,7 @@ int16_t SX127x::invertIQ(bool enable) { return(state); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX127x::setDirectAction(void (*func)(void)) { setDio1Action(func, this->mod->hal->GpioInterruptRising); } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index fa4ab65ba3..721c5d4816 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX127X) +#if !RADIOLIB_EXCLUDE_SX127X #include "../../Module.h" @@ -1150,7 +1150,7 @@ class SX127x: public PhysicalLayer { */ int16_t invertIQ(bool enable) override; - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. @@ -1218,12 +1218,12 @@ class SX127x: public PhysicalLayer { */ int16_t setRSSIThreshold(float dbm); -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif @@ -1245,7 +1245,7 @@ class SX127x: public PhysicalLayer { int16_t directMode(); int16_t setPacketMode(uint8_t mode, uint8_t len); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif float dataRate = 0; From 827aac593807cc728b0a1b3bc20e8df3e7f5eb22 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:15:07 +0100 Subject: [PATCH 0818/1848] [SX128x] Reworked macro configuration system --- src/modules/SX128x/SX1280.cpp | 2 +- src/modules/SX128x/SX1280.h | 4 ++-- src/modules/SX128x/SX1281.cpp | 2 +- src/modules/SX128x/SX1281.h | 4 ++-- src/modules/SX128x/SX1282.cpp | 2 +- src/modules/SX128x/SX1282.h | 4 ++-- src/modules/SX128x/SX128x.cpp | 4 ++-- src/modules/SX128x/SX128x.h | 12 ++++++------ 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index b53c1a62d3..cc4c97983c 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -1,6 +1,6 @@ #include "SX1280.h" #include -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X SX1280::SX1280(Module* mod) : SX1281(mod) { diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index 51bb7c0bb3..c798f044a0 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X #include "../../Module.h" #include "SX128x.h" @@ -45,7 +45,7 @@ class SX1280: public SX1281 { */ float getRangingResult(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX128x/SX1281.cpp b/src/modules/SX128x/SX1281.cpp index c6b2b5eba2..71e7476e78 100644 --- a/src/modules/SX128x/SX1281.cpp +++ b/src/modules/SX128x/SX1281.cpp @@ -1,5 +1,5 @@ #include "SX1281.h" -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X SX1281::SX1281(Module* mod) : SX128x(mod) { diff --git a/src/modules/SX128x/SX1281.h b/src/modules/SX128x/SX1281.h index 04a9eb1985..3a41b60a61 100644 --- a/src/modules/SX128x/SX1281.h +++ b/src/modules/SX128x/SX1281.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X #include "../../Module.h" #include "SX128x.h" @@ -20,7 +20,7 @@ class SX1281: public SX128x { */ SX1281(Module* mod); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX128x/SX1282.cpp b/src/modules/SX128x/SX1282.cpp index 33deee97f6..d58ba3d37f 100644 --- a/src/modules/SX128x/SX1282.cpp +++ b/src/modules/SX128x/SX1282.cpp @@ -1,5 +1,5 @@ #include "SX1282.h" -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X /// \todo implement advanced ranging SX1282::SX1282(Module* mod) : SX1280(mod) { diff --git a/src/modules/SX128x/SX1282.h b/src/modules/SX128x/SX1282.h index 864e463d4d..091bf133b5 100644 --- a/src/modules/SX128x/SX1282.h +++ b/src/modules/SX128x/SX1282.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X #include "../../Module.h" #include "SX128x.h" @@ -21,7 +21,7 @@ class SX1282: public SX1280 { */ SX1282(Module* mod); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3e26382e78..6f14b536cc 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1,6 +1,6 @@ #include "SX128x.h" #include -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { this->mod = mod; @@ -1333,7 +1333,7 @@ int16_t SX128x::invertIQ(bool enable) { return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX128x::setDirectAction(void (*func)(void)) { // SX128x is unable to perform direct mode reception // this method is implemented only for PhysicalLayer compatibility diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 1aa69115fa..b2e63bbdd5 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX128X) +#if !RADIOLIB_EXCLUDE_SX128X #include "../../Module.h" @@ -765,7 +765,7 @@ class SX128x: public PhysicalLayer { */ int16_t invertIQ(bool enable); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Dummy method, to ensure PhysicalLayer compatibility. \param func Ignored. @@ -779,12 +779,12 @@ class SX128x: public PhysicalLayer { void readBit(uint32_t pin); #endif -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif Module* mod; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif @@ -817,14 +817,14 @@ class SX128x: public PhysicalLayer { int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); -#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL private: #endif // common low-level SPI interface static int16_t SPIparseStatus(uint8_t in); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif // common parameters From 379c475d5e9eda4e82198c35bf252052476058af Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:15:21 +0100 Subject: [PATCH 0819/1848] [SX1231] Reworked macro configuration system --- src/modules/SX1231/SX1231.cpp | 2 +- src/modules/SX1231/SX1231.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index cc9e3409bc..7cce2cce0f 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -1,5 +1,5 @@ #include "SX1231.h" -#if !defined(RADIOLIB_EXCLUDE_SX1231) +#if !RADIOLIB_EXCLUDE_SX1231 SX1231::SX1231(Module* mod) : RF69(mod) { diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX1231/SX1231.h index 6054034510..e9631a8741 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX1231/SX1231.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SX1231) +#if !RADIOLIB_EXCLUDE_SX1231 #include "../../Module.h" #include "../RF69/RF69.h" @@ -110,7 +110,7 @@ class SX1231: public RF69 { */ int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif uint8_t chipRevision = 0; From fe0136b15c3dd10ead46b3c858f198bd979a7801 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:15:52 +0100 Subject: [PATCH 0820/1848] [AFSK] Reworked macro configuration system --- src/protocols/AFSK/AFSK.cpp | 2 +- src/protocols/AFSK/AFSK.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index 6d7e518d3e..bf0ddc4c2b 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -1,5 +1,5 @@ #include "AFSK.h" -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK AFSKClient::AFSKClient(PhysicalLayer* phy, uint32_t pin): outPin(pin) { phyLayer = phy; diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index 3b69f3083f..ea48630e94 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK #include "../../Module.h" @@ -49,7 +49,7 @@ class AFSKClient { */ int16_t noTone(bool keepOn = false); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; From 98054055bd128956f950585ce9d3977d1165ed5e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:16:13 +0100 Subject: [PATCH 0821/1848] [APRS] Reworked macro configuration system --- src/protocols/APRS/APRS.cpp | 10 +++++----- src/protocols/APRS/APRS.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 3458272ea5..55b034d170 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -2,7 +2,7 @@ #include #include #include -#if !defined(RADIOLIB_EXCLUDE_APRS) +#if !RADIOLIB_EXCLUDE_APRS APRSClient::APRSClient(AX25Client* ax) { axClient = ax; @@ -42,7 +42,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat if(time != NULL) { len += strlen(time); } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY char* info = new char[len + 1]; #else char info[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -66,7 +66,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat // send the frame int16_t state = sendFrame(destCallsign, destSSID, info); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] info; #endif return(state); @@ -89,7 +89,7 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp // prepare buffers char destCallsign[7]; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY size_t infoLen = 10; if(telemLen > 0) { infoLen += 1 + telemLen; @@ -231,7 +231,7 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp destSSID = 1; } int16_t state = sendFrame(destCallsign, destSSID, info); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] info; #endif return(state); diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index ee74cfa059..8369a6f3f7 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_APRS) +#if !RADIOLIB_EXCLUDE_APRS #include "../PhysicalLayer/PhysicalLayer.h" #include "../AX25/AX25.h" @@ -128,7 +128,7 @@ class APRSClient { */ int16_t sendFrame(char* destCallsign, uint8_t destSSID, char* info); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif AX25Client* axClient; From 6c07552f8433dda7c38c7d5888ef7b9068609681 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:16:34 +0100 Subject: [PATCH 0822/1848] [AX25] Reworked macro configuration system --- src/protocols/AX25/AX25.cpp | 30 +++++++++++++++--------------- src/protocols/AX25/AX25.h | 10 +++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index fc3e24e021..3c60072e43 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -1,6 +1,6 @@ #include "AX25.h" #include -#if !defined(RADIOLIB_EXCLUDE_AX25) +#if !RADIOLIB_EXCLUDE_AX25 AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control) : AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, 0, NULL, 0) { @@ -25,7 +25,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src // set repeaters this->numRepeaters = 0; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY this->repeaterCallsigns = NULL; this->repeaterSSIDs = NULL; #endif @@ -43,7 +43,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src // info field this->infoLen = infoLen; if(infoLen > 0) { - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY this->info = new uint8_t[infoLen]; #endif memcpy(this->info, info, infoLen); @@ -55,7 +55,7 @@ AX25Frame::AX25Frame(const AX25Frame& frame) { } AX25Frame::~AX25Frame() { - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY // deallocate info field if(infoLen > 0) { delete[] this->info; @@ -124,7 +124,7 @@ int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs } // create buffers - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY this->repeaterCallsigns = new char*[numRepeaters]; for(uint8_t i = 0; i < numRepeaters; i++) { this->repeaterCallsigns[i] = new char[strlen(repeaterCallsigns[i]) + 1]; @@ -153,12 +153,12 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) { AX25Client::AX25Client(PhysicalLayer* phy) { phyLayer = phy; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK bellModem = nullptr; #endif } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK AX25Client::AX25Client(AFSKClient* audio) { phyLayer = audio->phyLayer; bellModem = new BellClient(audio); @@ -194,7 +194,7 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preL preambleLen = preLen; // configure for direct mode - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(bellModem != nullptr) { return(phyLayer->startDirect()); } @@ -226,7 +226,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // check repeater configuration - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY if(!(((frame->repeaterCallsigns == NULL) && (frame->repeaterSSIDs == NULL) && (frame->numRepeaters == 0)) || ((frame->repeaterCallsigns != NULL) && (frame->repeaterSSIDs != NULL) && (frame->numRepeaters != 0)))) { return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); @@ -241,7 +241,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // calculate frame length without FCS (destination address, source address, repeater addresses, control, PID, info) size_t frameBuffLen = ((2 + frame->numRepeaters)*(RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1)) + 1 + 1 + frame->infoLen; // create frame buffer without preamble, start or stop flags - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY uint8_t* frameBuff = new uint8_t[frameBuffLen + 2]; #else uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -323,7 +323,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { *(frameBuffPtr++) = (uint8_t)(fcs & 0xFF); // prepare buffer for the final frame (stuffed, with added preamble + flags and NRZI-encoded) - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY // worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags uint8_t* stuffedFrameBuff = new uint8_t[preambleLen + 1 + (6*frameBuffLen)/5 + 2]; #else @@ -367,7 +367,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // deallocate memory - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] frameBuff; #endif @@ -413,7 +413,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // transmit int16_t state = RADIOLIB_ERR_NONE; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(bellModem != nullptr) { bellModem->idle(); @@ -427,12 +427,12 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } else { #endif state = phyLayer->transmit(stuffedFrameBuff, stuffedFrameBuffLen); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK } #endif // deallocate memory - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] stuffedFrameBuff; #endif diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 9d6c60a63c..28ddd5aabe 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_AX25) +#if !RADIOLIB_EXCLUDE_AX25 #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" @@ -125,7 +125,7 @@ class AX25Frame { */ uint16_t sendSeqNumber; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY /*! \brief The info field. */ @@ -243,7 +243,7 @@ class AX25Client { */ explicit AX25Client(PhysicalLayer* phy); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. \param audio Pointer to the AFSK instance providing audio. @@ -303,13 +303,13 @@ class AX25Client { */ int16_t sendFrame(AX25Frame* frame); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif friend class APRSClient; PhysicalLayer* phyLayer; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK BellClient* bellModem; #endif From f85abafe19c1f057d13c4ccdd6c2edb93044d97d Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:16:43 +0100 Subject: [PATCH 0823/1848] [Bell] Reworked macro configuration system --- src/protocols/BellModem/BellModem.cpp | 2 +- src/protocols/BellModem/BellModem.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp index 087bde1705..8d08943ee6 100644 --- a/src/protocols/BellModem/BellModem.cpp +++ b/src/protocols/BellModem/BellModem.cpp @@ -1,5 +1,5 @@ #include "BellModem.h" -#if !defined(RADIOLIB_EXCLUDE_BELL) +#if !RADIOLIB_EXCLUDE_BELL const struct BellModem_t Bell101 { .freqMark = 1270, diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h index 13ab710641..b98479e4e4 100644 --- a/src/protocols/BellModem/BellModem.h +++ b/src/protocols/BellModem/BellModem.h @@ -7,7 +7,7 @@ #include "../../ArduinoHal.h" #endif -#if !defined(RADIOLIB_EXCLUDE_BELL) +#if !RADIOLIB_EXCLUDE_BELL #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" @@ -116,7 +116,7 @@ class BellClient: public AFSKClient, public RadioLibPrint { */ int16_t standby(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif BellModem_t modemType; From 71dbf371e7d57eca2878e2094a7d171f18315613 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:16:56 +0100 Subject: [PATCH 0824/1848] [FSK4] Reworked macro configuration system --- src/protocols/FSK4/FSK4.cpp | 10 +++++----- src/protocols/FSK4/FSK4.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index bb24e5bee2..f589f4595f 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -1,15 +1,15 @@ #include "FSK4.h" #include -#if !defined(RADIOLIB_EXCLUDE_FSK4) +#if !RADIOLIB_EXCLUDE_FSK4 FSK4Client::FSK4Client(PhysicalLayer* phy) { phyLayer = phy; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK audioClient = nullptr; #endif } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK FSK4Client::FSK4Client(AFSKClient* audio) { phyLayer = audio->phyLayer; audioClient = audio; @@ -87,7 +87,7 @@ void FSK4Client::tone(uint8_t i) { } int16_t FSK4Client::transmitDirect(uint32_t freq, uint32_t freqHz) { - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->tone(freqHz)); } @@ -99,7 +99,7 @@ int16_t FSK4Client::standby() { // ensure everything is stopped in interrupt timing mode Module* mod = phyLayer->getMod(); mod->waitForMicroseconds(0, 0); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->noTone()); } diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index d466d64299..a1e91e3723 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_FSK4) +#if !RADIOLIB_EXCLUDE_FSK4 #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" @@ -20,7 +20,7 @@ class FSK4Client { */ explicit FSK4Client(PhysicalLayer* phy); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. \param audio Pointer to the AFSK instance providing audio. @@ -74,11 +74,11 @@ class FSK4Client { */ int16_t standby(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK AFSKClient* audioClient; #endif From ac18a2c8f79b3d1c6b2d1a954f9163791f854bf1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:17:06 +0100 Subject: [PATCH 0825/1848] [Hell] Reworked macro configuration system --- src/protocols/Hellschreiber/Hellschreiber.cpp | 10 +++++----- src/protocols/Hellschreiber/Hellschreiber.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 06eaae7943..f23bc40fa6 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -1,16 +1,16 @@ #include "Hellschreiber.h" -#if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) +#if !RADIOLIB_EXCLUDE_HELLSCHREIBER HellClient::HellClient(PhysicalLayer* phy) { phyLayer = phy; lineFeed = " "; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK audioClient = nullptr; #endif } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK HellClient::HellClient(AFSKClient* audio) { phyLayer = audio->phyLayer; lineFeed = " "; @@ -82,7 +82,7 @@ size_t HellClient::write(uint8_t b) { } int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->tone(freqHz)); } @@ -91,7 +91,7 @@ int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { } int16_t HellClient::standby() { - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->noTone(invert)); } diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 7855dee8b0..3ee42174d2 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) +#if !RADIOLIB_EXCLUDE_HELLSCHREIBER #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" @@ -95,7 +95,7 @@ class HellClient: public RadioLibPrint { */ explicit HellClient(PhysicalLayer* phy); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. \param audio Pointer to the AFSK instance providing audio. @@ -132,11 +132,11 @@ class HellClient: public RadioLibPrint { */ size_t write(uint8_t b); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK AFSKClient* audioClient; #endif From 670e70bd9fb8054b219193e26f121ed8d5414d88 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:17:26 +0100 Subject: [PATCH 0826/1848] [LoRaWAN] Reworked macro configuration system --- src/protocols/LoRaWAN/LoRaWAN.cpp | 34 +++++++++++++------------- src/protocols/LoRaWAN/LoRaWAN.h | 4 +-- src/protocols/LoRaWAN/LoRaWANBands.cpp | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 99c93549ec..575943c75a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1,7 +1,7 @@ #include "LoRaWAN.h" #include -#if !defined(RADIOLIB_EXCLUDE_LORAWAN) +#if !RADIOLIB_EXCLUDE_LORAWAN #if defined(RADIOLIB_EEPROM_UNSUPPORTED) #warning "Persistent storage not supported!" @@ -65,7 +65,7 @@ int16_t LoRaWANNode::restore() { // check the magic value if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) != RADIOLIB_LORAWAN_MAGIC) { - #if defined(RADIOLIB_DEBUG) + #if RADIOLIB_DEBUG RADIOLIB_DEBUG_PRINTLN("magic id not set (no saved session)"); RADIOLIB_DEBUG_PRINTLN("first 16 bytes of NVM:"); uint8_t nvmBuff[16]; @@ -148,7 +148,7 @@ int16_t LoRaWANNode::restoreFcntUp() { uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID); uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 1); uint8_t buffSize = fcntBuffEnd - fcntBuffStart; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* fcntBuff = new uint8_t[buffSize]; @@ -182,7 +182,7 @@ int16_t LoRaWANNode::restoreFcntUp() { } } uint32_t bits_7_0 = (uint32_t)fcntBuff[idx-1] & 0x7F; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] fcntBuff; #endif @@ -764,7 +764,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsBufSize); - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen]; @@ -891,7 +891,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf this->rxDelayStart = mod->hal->millis(); RADIOLIB_DEBUG_PRINTLN("Uplink sent <-- Rx Delay start"); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] uplinkMsg; #endif RADIOLIB_ASSERT(state); @@ -1060,7 +1060,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // build the buffer for the downlink message // the first 16 bytes are reserved for MIC calculation block - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY uint8_t* downlinkMsg = new uint8_t[RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen]; #else uint8_t downlinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -1082,7 +1082,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } if(state != RADIOLIB_ERR_NONE) { - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif return(state); @@ -1127,7 +1127,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint32_t fcnt32 = fcnt16; if(fcntDownPrev > 0) { if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif if (isAppDownlink) { @@ -1143,7 +1143,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // check the MIC if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif return(RADIOLIB_ERR_CRC_MISMATCH); @@ -1167,7 +1167,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { RADIOLIB_DEBUG_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif return(RADIOLIB_ERR_DOWNLINK_MALFORMED); @@ -1209,7 +1209,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { size_t foptsBufSize = this->commandsUp.len; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t foptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* foptsBuff = new uint8_t[foptsBufSize]; @@ -1236,18 +1236,18 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) this->isMACPayload = true; this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] foptsBuff; #endif - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; #endif size_t lenDown = 0; state = this->downlink(strDown, &lenDown); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] strDown; #endif RADIOLIB_ASSERT(state); @@ -1274,7 +1274,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) if(payLen <= 0) { // no payload *len = 0; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1288,7 +1288,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 30ff25123c..ee1d6b9543 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1,4 +1,4 @@ -#if !defined(_RADIOLIB_LORAWAN_H) && !defined(RADIOLIB_EXCLUDE_LORAWAN) +#if !defined(_RADIOLIB_LORAWAN_H) && !RADIOLIB_EXCLUDE_LORAWAN #define _RADIOLIB_LORAWAN_H #include "../../TypeDef.h" @@ -572,7 +572,7 @@ class LoRaWANNode { */ void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer = NULL; diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 8e36f9c2f7..7b0e04cf09 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -1,6 +1,6 @@ #include "LoRaWAN.h" -#if !defined(RADIOLIB_EXCLUDE_LORAWAN) +#if !RADIOLIB_EXCLUDE_LORAWAN const LoRaWANBand_t EU868 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, From 8f5cff0cd41a49e1a887762ba87d28832851e614 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:17:35 +0100 Subject: [PATCH 0827/1848] [Morse] Reworked macro configuration system --- src/protocols/Morse/Morse.cpp | 12 ++++++------ src/protocols/Morse/Morse.h | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 27cb5eaccd..8ec0c469fe 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -2,17 +2,17 @@ #include -#if !defined(RADIOLIB_EXCLUDE_MORSE) +#if !RADIOLIB_EXCLUDE_MORSE MorseClient::MorseClient(PhysicalLayer* phy) { phyLayer = phy; lineFeed = "^"; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK audioClient = nullptr; #endif } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK MorseClient::MorseClient(AFSKClient* audio) { phyLayer = audio->phyLayer; lineFeed = "^"; @@ -59,7 +59,7 @@ char MorseClient::decode(uint8_t symbol, uint8_t len) { return(RADIOLIB_MORSE_UNSUPPORTED); } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { Module* mod = phyLayer->getMod(); @@ -167,7 +167,7 @@ size_t MorseClient::write(uint8_t b) { } int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->tone(freqHz)); } @@ -176,7 +176,7 @@ int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { } int16_t MorseClient::standby() { - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->noTone(true)); } diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index df44bc1f84..3c995c426c 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -1,4 +1,4 @@ -#if !defined(_RADIOLIB_RADIOLIB_MORSE_H) && !defined(RADIOLIB_EXCLUDE_MORSE) +#if !defined(_RADIOLIB_RADIOLIB_MORSE_H) && !RADIOLIB_EXCLUDE_MORSE #define _RADIOLIB_RADIOLIB_MORSE_H #include "../../TypeDef.h" @@ -98,7 +98,7 @@ class MorseClient: public RadioLibPrint { */ explicit MorseClient(PhysicalLayer* phy); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. \param audio Pointer to the AFSK instance providing audio. @@ -139,7 +139,7 @@ class MorseClient: public RadioLibPrint { \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, 2 if inter-word space was detected. */ - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK int read(uint8_t* symbol, uint8_t* len, float low = 0.75f, float high = 1.25f); #endif @@ -150,11 +150,11 @@ class MorseClient: public RadioLibPrint { */ size_t write(uint8_t b); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK AFSKClient* audioClient; #endif From 074b707924cfe5bd047555221e49f4fe64da6731 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:17:45 +0100 Subject: [PATCH 0828/1848] [Pager] Reworked macro configuration system --- src/protocols/Pager/Pager.cpp | 18 +++++++++--------- src/protocols/Pager/Pager.h | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 1416247a41..6b9ade4f92 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,9 +1,9 @@ #include "Pager.h" #include #include -#if !defined(RADIOLIB_EXCLUDE_PAGER) +#if !RADIOLIB_EXCLUDE_PAGER -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE // this is a massive hack, but we need a global-scope ISR to manage the bit reading // let's hope nobody ever tries running two POCSAG receivers at the same time static PhysicalLayer* readBitInstance = NULL; @@ -21,7 +21,7 @@ static void PagerClientReadBit(void) { PagerClient::PagerClient(PhysicalLayer* phy) { phyLayer = phy; - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE readBitInstance = phyLayer; #endif } @@ -127,7 +127,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t // calculate message length in 32-bit code words size_t msgLen = RADIOLIB_PAGER_PREAMBLE_LENGTH + (1 + RADIOLIB_PAGER_BATCH_LEN) * numBatches; - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint32_t msg[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint32_t* msg = new uint32_t[msgLen]; @@ -225,7 +225,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t // transmit the message PagerClient::write(msg, msgLen); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] msg; #endif @@ -235,7 +235,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t return(RADIOLIB_ERR_NONE); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { // save the variables readBitPin = pin; @@ -289,7 +289,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { } // build a temporary buffer - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; @@ -316,7 +316,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { } // deallocate temporary buffer - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] data; #endif @@ -496,7 +496,7 @@ void PagerClient::write(uint32_t codeWord) { } } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE uint32_t PagerClient::read() { uint32_t codeWord = 0; codeWord |= (uint32_t)phyLayer->read() << 24; diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index a7ecef46be..11b9c4dd02 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -1,4 +1,4 @@ -#if !defined(_RADIOLIB_PAGER_H) && !defined(RADIOLIB_EXCLUDE_PAGER) +#if !defined(_RADIOLIB_PAGER_H) && !RADIOLIB_EXCLUDE_PAGER #define _RADIOLIB_PAGER_H #include "../../TypeDef.h" @@ -119,7 +119,7 @@ class PagerClient { */ int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Start reception of POCSAG packets. \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). @@ -162,7 +162,7 @@ class PagerClient { int16_t readData(uint8_t* data, size_t* len, uint32_t* addr = NULL); #endif -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; @@ -180,7 +180,7 @@ class PagerClient { void write(uint32_t* data, size_t len); void write(uint32_t codeWord); -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE uint32_t read(); #endif From 395101ec2045cec8a7631581e3e35fa74b00ec2c Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:17:58 +0100 Subject: [PATCH 0829/1848] [PHY] Reworked macro configuration system --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 18 +++++++++--------- src/protocols/PhysicalLayer/PhysicalLayer.h | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 0bb634f93f..8b99932576 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -4,7 +4,7 @@ PhysicalLayer::PhysicalLayer(float step, size_t maxLen) { this->freqStep = step; this->maxPacketLength = maxLen; - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE this->bufferBitPos = 0; this->bufferWritePos = 0; #endif @@ -24,7 +24,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { } // dynamically allocate memory - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY char str[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* str = new char[len]; @@ -38,7 +38,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { // transmit string int16_t state = transmit(str, addr); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] str; #endif return(state); @@ -68,7 +68,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { size_t length = len; // build a temporary buffer - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = NULL; @@ -101,7 +101,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { } // deallocate temporary buffer - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] data; #endif @@ -175,7 +175,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { } // build a temporary buffer - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; @@ -198,7 +198,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { } // deallocate temporary buffer - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] data; #endif @@ -366,7 +366,7 @@ int16_t PhysicalLayer::startDirect() { return(state); } -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE int16_t PhysicalLayer::available() { return(this->bufferWritePos); } @@ -477,7 +477,7 @@ void PhysicalLayer::clearChannelScanAction() { } -#if defined(RADIOLIB_INTERRUPT_TIMING) +#if RADIOLIB_INTERRUPT_TIMING void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { Module* mod = getMod(); mod->TimerSetupCb = func; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 741cdb8cef..513a3e1d41 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -380,7 +380,7 @@ class PhysicalLayer { */ int16_t startDirect(); - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set sync word to be used to determine start of packet in direct reception mode. \param syncWord Sync word bits. @@ -463,7 +463,7 @@ class PhysicalLayer { */ virtual void clearChannelScanAction(); - #if defined(RADIOLIB_INTERRUPT_TIMING) + #if RADIOLIB_INTERRUPT_TIMING /*! \brief Set function to be called to set up the timing interrupt. @@ -480,18 +480,18 @@ class PhysicalLayer { #endif -#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE protected: void updateDirectBuffer(uint8_t bit); #endif -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif float freqStep; size_t maxPacketLength; - #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE) + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE uint8_t bufferBitPos; uint8_t bufferWritePos; uint8_t bufferReadPos; From e6a6923b25d96904e95c27b70bad76f0f7c4974a Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:18:10 +0100 Subject: [PATCH 0830/1848] [Print] Reworked macro configuration system --- src/protocols/Print/ITA2String.cpp | 10 +++++----- src/protocols/Print/ITA2String.h | 4 ++-- src/protocols/Print/Print.cpp | 4 ++-- src/protocols/Print/Print.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp index b162b25980..4f2d99a7c7 100644 --- a/src/protocols/Print/ITA2String.cpp +++ b/src/protocols/Print/ITA2String.cpp @@ -4,7 +4,7 @@ ITA2String::ITA2String(char c) { asciiLen = 1; - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY strAscii = new char[1]; #endif strAscii[0] = c; @@ -13,7 +13,7 @@ ITA2String::ITA2String(char c) { ITA2String::ITA2String(const char* str) { asciiLen = strlen(str); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY strAscii = new char[asciiLen + 1]; #endif strcpy(strAscii, str); @@ -21,7 +21,7 @@ ITA2String::ITA2String(const char* str) { } ITA2String::~ITA2String() { - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] strAscii; #endif } @@ -40,7 +40,7 @@ size_t ITA2String::length() { uint8_t* ITA2String::byteArr() { // create temporary array 2x the string length (figures may be 3 bytes) - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; #else uint8_t* temp = new uint8_t[asciiLen*2 + 1]; @@ -87,7 +87,7 @@ uint8_t* ITA2String::byteArr() { uint8_t* arr = new uint8_t[arrayLen]; memcpy(arr, temp, arrayLen); - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] temp; #endif diff --git a/src/protocols/Print/ITA2String.h b/src/protocols/Print/ITA2String.h index 556c0a3bbd..579bb1c48f 100644 --- a/src/protocols/Print/ITA2String.h +++ b/src/protocols/Print/ITA2String.h @@ -53,10 +53,10 @@ class ITA2String { */ uint8_t* byteArr(); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY char strAscii[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* strAscii; diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp index f944ec7545..94b7b33459 100644 --- a/src/protocols/Print/Print.cpp +++ b/src/protocols/Print/Print.cpp @@ -42,7 +42,7 @@ size_t RadioLibPrint::print(const __FlashStringHelper* fstr) { } // dynamically allocate memory - #if defined(RADIOLIB_STATIC_ONLY) + #if RADIOLIB_STATIC_ONLY char str[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* str = new char[len]; @@ -61,7 +61,7 @@ size_t RadioLibPrint::print(const __FlashStringHelper* fstr) { } else { n = write((uint8_t*)str, len); } - #if !defined(RADIOLIB_STATIC_ONLY) + #if !RADIOLIB_STATIC_ONLY delete[] str; #endif return(n); diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index a132cf6196..48bd7e702b 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -53,7 +53,7 @@ class RadioLibPrint { size_t println(double, int = 2); size_t println(void); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE protected: #endif uint8_t encoding = RADIOLIB_ASCII_EXTENDED; From eddde76371dcee46eb42f87540b2976756f5da9a Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:18:20 +0100 Subject: [PATCH 0831/1848] [RTTY] Reworked macro configuration system --- src/protocols/RTTY/RTTY.cpp | 10 +++++----- src/protocols/RTTY/RTTY.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index eff2d7ad03..c823fb280b 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -2,17 +2,17 @@ #include -#if !defined(RADIOLIB_EXCLUDE_RTTY) +#if !RADIOLIB_EXCLUDE_RTTY RTTYClient::RTTYClient(PhysicalLayer* phy) { phyLayer = phy; lineFeed = "\r\n"; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK audioClient = nullptr; #endif } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK RTTYClient::RTTYClient(AFSKClient* audio) { phyLayer = audio->phyLayer; lineFeed = "\r\n"; @@ -104,7 +104,7 @@ void RTTYClient::space() { } int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->tone(freqHz)); } @@ -116,7 +116,7 @@ int16_t RTTYClient::standby() { // ensure everything is stopped in interrupt timing mode Module* mod = phyLayer->getMod(); mod->waitForMicroseconds(0, 0); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { return(audioClient->noTone()); } diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index 4ebbc7ccf8..4da4ca6316 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_RTTY) +#if !RADIOLIB_EXCLUDE_RTTY #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" @@ -22,7 +22,7 @@ class RTTYClient: public RadioLibPrint { */ explicit RTTYClient(PhysicalLayer* phy); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. \param audio Pointer to the AFSK instance providing audio. @@ -61,11 +61,11 @@ class RTTYClient: public RadioLibPrint { */ size_t write(uint8_t b); -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK AFSKClient* audioClient; #endif From 974c027452afa896300004795b9009b04c125ae6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:19:04 +0100 Subject: [PATCH 0832/1848] [SSTV] Reworked macro configuration system --- src/protocols/SSTV/SSTV.cpp | 10 +++++----- src/protocols/SSTV/SSTV.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 107674fda8..b06df29753 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -1,5 +1,5 @@ #include "SSTV.h" -#if !defined(RADIOLIB_EXCLUDE_SSTV) +#if !RADIOLIB_EXCLUDE_SSTV const SSTVMode_t Scottie1 { .visCode = RADIOLIB_SSTV_SCOTTIE_1, @@ -156,19 +156,19 @@ const SSTVMode_t PasokonP7 { SSTVClient::SSTVClient(PhysicalLayer* phy) { phyLayer = phy; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK audioClient = nullptr; #endif } -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK SSTVClient::SSTVClient(AFSKClient* audio) { phyLayer = audio->phyLayer; audioClient = audio; } #endif -#if !defined(RADIOLIB_EXCLUDE_AFSK) +#if !RADIOLIB_EXCLUDE_AFSK int16_t SSTVClient::begin(const SSTVMode_t& mode) { if(audioClient == nullptr) { // this initialization method can only be used in AFSK mode @@ -292,7 +292,7 @@ uint16_t SSTVClient::getPictureHeight() const { void SSTVClient::tone(float freq, uint32_t len) { Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { audioClient->tone(freq, false); } else { diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index df73d8f2de..cbf69d8c90 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !defined(RADIOLIB_EXCLUDE_SSTV) +#if !RADIOLIB_EXCLUDE_SSTV #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" @@ -122,7 +122,7 @@ class SSTVClient { */ explicit SSTVClient(PhysicalLayer* phy); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. \param audio Pointer to the AFSK instance providing audio. @@ -141,7 +141,7 @@ class SSTVClient { */ int16_t begin(float base, const SSTVMode_t& mode); - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Initialization method for AFSK. \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, @@ -182,11 +182,11 @@ class SSTVClient { */ uint16_t getPictureHeight() const; -#if !defined(RADIOLIB_GODMODE) +#if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer; - #if !defined(RADIOLIB_EXCLUDE_AFSK) + #if !RADIOLIB_EXCLUDE_AFSK AFSKClient* audioClient; #endif From 34d2bc85b3fd12e5b05f93eba385a742b41f250e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Nov 2023 21:24:32 +0100 Subject: [PATCH 0833/1848] Print debug info correctly --- src/RadioLib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index 3fd9632aa3..df54fc518d 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -52,7 +52,7 @@ #endif // print debug info -#if defined(RADIOLIB_DEBUG) +#if RADIOLIB_DEBUG #define RADIOLIB_VALUE_TO_STRING(x) #x #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) #pragma message("\nRadioLib Debug Info\nVersion: \"" \ From 94bd83329d4c5e73acd21815f40dfd538e3d7501 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Nov 2023 17:31:00 +0100 Subject: [PATCH 0834/1848] Bump version to 6.3.0 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index 55a0bc467c..9822a1c042 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.2.0", + "version": "6.3.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 1a4c6ebe03..8dda9bb6db 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.2.0 +version=6.3.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index f2b9bc31b4..308dc8969f 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -528,7 +528,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 6 -#define RADIOLIB_VERSION_MINOR 2 +#define RADIOLIB_VERSION_MINOR 3 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From 14a2238ca6b19987a420534d306d685d77780efb Mon Sep 17 00:00:00 2001 From: S5NC <145265251+S5NC@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:18:13 +0000 Subject: [PATCH 0835/1848] Update SX128x.h --- src/modules/SX128x/SX128x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index b2e63bbdd5..4029635f00 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -310,7 +310,7 @@ #define RADIOLIB_SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 //RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected +#define RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected #define RADIOLIB_SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done #define RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout #define RADIOLIB_SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected From ed15ce3569082ce1e6cab867ac16f0dfe27c5626 Mon Sep 17 00:00:00 2001 From: S5NC <145265251+S5NC@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:23:45 +0000 Subject: [PATCH 0836/1848] Remove double '_RADIOLIB's --- src/protocols/APRS/APRS.h | 4 ++-- src/protocols/AX25/AX25.h | 4 ++-- src/protocols/Morse/Morse.h | 4 ++-- src/protocols/SSTV/SSTV.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index 8369a6f3f7..66555334e5 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -1,5 +1,5 @@ -#if !defined(_RADIOLIB_RADIOLIB_APRS_H) -#define _RADIOLIB_RADIOLIB_APRS_H +#if !defined(_RADIOLIB_APRS_H) +#define _RADIOLIB_APRS_H #include "../../TypeDef.h" diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 28ddd5aabe..d1688d9e1a 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -1,5 +1,5 @@ -#if !defined(_RADIOLIB_RADIOLIB_AX25_H) -#define _RADIOLIB_RADIOLIB_AX25_H +#if !defined(_RADIOLIB_AX25_H) +#define _RADIOLIB_AX25_H #include "../../TypeDef.h" diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 3c995c426c..3edb0beae2 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -1,5 +1,5 @@ -#if !defined(_RADIOLIB_RADIOLIB_MORSE_H) && !RADIOLIB_EXCLUDE_MORSE -#define _RADIOLIB_RADIOLIB_MORSE_H +#if !defined(_RADIOLIB_MORSE_H) && !RADIOLIB_EXCLUDE_MORSE +#define _RADIOLIB_MORSE_H #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index cbf69d8c90..986dd0cbbe 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -1,5 +1,5 @@ -#if !defined(_RADIOLIB_RADIOLIB_SSTV_H) -#define _RADIOLIB_RADIOLIB_SSTV_H +#if !defined(_RADIOLIB_SSTV_H) +#define _RADIOLIB_SSTV_H #include "../../TypeDef.h" From 79fbe9be8e9924c86d595e00c16edc70e1ee5a28 Mon Sep 17 00:00:00 2001 From: Andrzej Perczak Date: Fri, 8 Dec 2023 18:34:21 +0100 Subject: [PATCH 0837/1848] LoRaWAN: Fix uninitialized variables --- src/protocols/LoRaWAN/LoRaWAN.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index ee1d6b9543..82960f5316 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -350,7 +350,7 @@ class LoRaWANNode { public: // Offset between TX and RX1 (such that RX1 has equal or lower DR) - uint8_t rx1DrOffset; + uint8_t rx1DrOffset = 0; // RX2 channel properties - may be changed by MAC command LoRaWANChannel_t rx2; @@ -616,7 +616,7 @@ class LoRaWANNode { uint32_t adrFcnt = 0; // whether the current configured channel is in FSK mode - bool FSK; + bool FSK = false; // flag that shows whether the device is joined and there is an ongoing session bool isJoinedFlag = false; From 62276e070bcc4baac09236f2ecd7409eaf51728d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 9 Dec 2023 10:28:13 +0100 Subject: [PATCH 0838/1848] [LoRaWAN] Expose downlink framecounters --- keywords.txt | 3 +++ src/protocols/LoRaWAN/LoRaWAN.cpp | 8 ++++++++ src/protocols/LoRaWAN/LoRaWAN.h | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/keywords.txt b/keywords.txt index 24369e1776..6394b32a55 100644 --- a/keywords.txt +++ b/keywords.txt @@ -298,6 +298,9 @@ uplink KEYWORD2 downlink KEYWORD2 sendReceive KEYWORD2 setDeviceStatus KEYWORD2 +getFcntUp KEYWORD2 +getNFcntDown KEYWORD2 +getAFcntDown KEYWORD2 setDatarate KEYWORD2 setADR KEYWORD2 setTxPower KEYWORD2 diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 99c93549ec..a9370da50c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1335,6 +1335,14 @@ uint32_t LoRaWANNode::getFcntUp() { return(this->fcntUp); } +uint32_t LoRaWANNode::getNFcntDown() { + return(this->nFcntDown); +} + +uint32_t LoRaWANNode::getAFcntDown() { + return(this->aFcntDown); +} + uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { if((msg == NULL) || (len == 0)) { return(0); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 30ff25123c..f8e1365fdf 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -527,6 +527,12 @@ class LoRaWANNode { /*! \brief Returns the last uplink's frame counter */ uint32_t getFcntUp(); + /*! \brief Returns the last network downlink's frame counter */ + uint32_t getNFcntDown(); + + /*! \brief Returns the last application downlink's frame counter */ + uint32_t getAFcntDown(); + /*! \brief Set uplink datarate. This should not be used when ADR is enabled. \param dr Datarate to use for uplinks. From c0d8d7871ea399ec7a0b7ad20f2238b1171f0bcb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 9 Dec 2023 15:34:56 +0100 Subject: [PATCH 0839/1848] [SX123x] Added support for SX1233 (#898) --- README.md | 2 +- .../SX123x_Receive_Blocking.ino} | 5 +- .../SX123x_Transmit_Blocking.ino} | 5 +- keywords.txt | 1 + src/RadioLib.h | 3 +- src/modules/{SX1231 => SX123x}/SX1231.cpp | 6 +- src/modules/{SX1231 => SX123x}/SX1231.h | 6 +- src/modules/SX123x/SX1233.cpp | 124 ++++++++++++++++++ src/modules/SX123x/SX1233.h | 59 +++++++++ 9 files changed, 199 insertions(+), 12 deletions(-) rename examples/{SX1231/SX1231_Receive/SX1231_Receive.ino => SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino} (92%) rename examples/{SX1231/SX1231_Transmit/SX1231_Transmit.ino => SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino} (92%) rename src/modules/{SX1231 => SX123x}/SX1231.cpp (91%) rename src/modules/{SX1231 => SX123x}/SX1231.h (97%) create mode 100644 src/modules/SX123x/SX1233.cpp create mode 100644 src/modules/SX123x/SX1233.h diff --git a/README.md b/README.md index dbe288bc78..e726a7ad62 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __SX126x__ series LoRa modules (SX1261, SX1262, SX1268) * __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) * __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282) -* __SX1231__ FSK/OOK radio module +* __SX123x__ FSK/OOK radio modules (SX1231, SX1233) ### Supported protocols and digital modes: * [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules: diff --git a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino b/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino similarity index 92% rename from examples/SX1231/SX1231_Receive/SX1231_Receive.ino rename to examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino index 9071e31007..f79d35462a 100644 --- a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino +++ b/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino @@ -1,9 +1,10 @@ /* - RadioLib SX1231 Blocking Receive Example + RadioLib SX123x Blocking Receive Example This example receives packets using SX1231 FSK radio module. + Other modules from SX123x family can also be used. - NOTE: SX1231 offers the same features as RF69 and has the same + NOTE: SX123x modules offer the same features as RF69 and have the same interface. Please see RF69 examples for examples on AES, address filtering, interrupts and settings. diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino similarity index 92% rename from examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino rename to examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino index 02a883b412..e311737e56 100644 --- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino +++ b/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino @@ -1,9 +1,10 @@ /* - RadioLib SX1231 Blocking Transmit Example + RadioLib SX123x Blocking Transmit Example This example transmits packets using SX1231 FSK radio module. + Other modules from SX123x family can also be used. - NOTE: SX1231 offers the same features as RF69 and has the same + NOTE: SX123x modules offer the same features as RF69 and have the same interface. Please see RF69 examples for examples on AES, address filtering, interrupts and settings. diff --git a/keywords.txt b/keywords.txt index 24369e1776..981d213349 100644 --- a/keywords.txt +++ b/keywords.txt @@ -28,6 +28,7 @@ Si4431 KEYWORD1 Si4432 KEYWORD1 SIM800 KEYWORD1 SX1231 KEYWORD1 +SX1233 KEYWORD1 SX1261 KEYWORD1 SX1262 KEYWORD1 SX1268 KEYWORD1 diff --git a/src/RadioLib.h b/src/RadioLib.h index df54fc518d..0e3d7f6d1f 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -84,7 +84,8 @@ #include "modules/Si443x/Si4430.h" #include "modules/Si443x/Si4431.h" #include "modules/Si443x/Si4432.h" -#include "modules/SX1231/SX1231.h" +#include "modules/SX123x/SX1231.h" +#include "modules/SX123x/SX1233.h" #include "modules/SX126x/SX1261.h" #include "modules/SX126x/SX1262.h" #include "modules/SX126x/SX1268.h" diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX123x/SX1231.cpp similarity index 91% rename from src/modules/SX1231/SX1231.cpp rename to src/modules/SX123x/SX1231.cpp index 7cce2cce0f..8d38edaf70 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX123x/SX1231.cpp @@ -16,7 +16,7 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po bool flagFound = false; while((i < 10) && !flagFound) { int16_t version = getChipVersion(); - if((version == 0x21) || (version == 0x22) || (version == 0x23)) { + if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) { flagFound = true; this->chipRevision = version; } else { @@ -74,8 +74,8 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po return(state); } - // SX1231 V2a only - if(this->chipRevision == RADIOLIB_SX1231_CHIP_REVISION_2_A) { + // SX123x V2a only + if(this->chipRevision == RADIOLIB_SX123X_CHIP_REVISION_2_A) { // modify default OOK threshold value state = this->mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX123x/SX1231.h similarity index 97% rename from src/modules/SX1231/SX1231.h rename to src/modules/SX123x/SX1231.h index e9631a8741..569a8403af 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX123x/SX1231.h @@ -8,9 +8,9 @@ #include "../../Module.h" #include "../RF69/RF69.h" -#define RADIOLIB_SX1231_CHIP_REVISION_2_A 0x21 -#define RADIOLIB_SX1231_CHIP_REVISION_2_B 0x22 -#define RADIOLIB_SX1231_CHIP_REVISION_2_C 0x23 +#define RADIOLIB_SX123X_CHIP_REVISION_2_A 0x21 +#define RADIOLIB_SX123X_CHIP_REVISION_2_B 0x22 +#define RADIOLIB_SX123X_CHIP_REVISION_2_C 0x23 // RADIOLIB_SX1231 specific register map #define RADIOLIB_SX1231_REG_TEST_OOK 0x6E diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp new file mode 100644 index 0000000000..cece36ba91 --- /dev/null +++ b/src/modules/SX123x/SX1233.cpp @@ -0,0 +1,124 @@ +#include "SX1233.h" +#if !RADIOLIB_EXCLUDE_SX1233 + +SX1233::SX1233(Module* mod) : SX1231(mod) { + +} + +int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + + // try to find the SX1233 chip + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + int16_t version = getChipVersion(); + if((version == 0x21) || (version == 0x22) || (version == 0x23)) { + flagFound = true; + this->chipRevision = version; + } else { + RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + this->mod->hal->delay(10); + i++; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_PRINTLN("No SX1233 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_PRINTLN("M\tSX1233"); + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // configure bitrate + this->rxBandwidth = 125.0; + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // configure default RX bandwidth + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // configure default frequency deviation + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // configure default TX output power + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + // configure default preamble length + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + + // default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library + uint8_t syncWord[] = {0x2D, 0x01}; + state = setSyncWord(syncWord, 2); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + if (state != RADIOLIB_ERR_NONE) { + return(state); + } + + // SX123x V2a only + if(this->chipRevision == RADIOLIB_SX123X_CHIP_REVISION_2_A) { + // modify default OOK threshold value + state = this->mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); + RADIOLIB_ASSERT(state); + + // enable OCP with 95 mA limit + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); + RADIOLIB_ASSERT(state); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t SX1233::setBitRate(float br) { + // check high bit-rate operation + uint8_t pllBandwidth = RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE; + if((fabs(br - 500.0f) < 0.1) || (fabs(br - 600.0f) < 0.1)) { + pllBandwidth = RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE; + } else { + // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine + RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + } + + + // check bitrate-bandwidth ratio + if(!(br < 2000 * this->rxBandwidth)) { + return(RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO); + } + + // set mode to standby + setMode(RADIOLIB_RF69_STANDBY); + + // set PLL bandwidth + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX1233_REG_TEST_PLL, pllBandwidth, 7, 0); + RADIOLIB_ASSERT(state); + + // set bit rate + uint16_t bitRate = 32000 / br; + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + if(state == RADIOLIB_ERR_NONE) { + this->bitRate = br; + } + return(state); +} + +#endif diff --git a/src/modules/SX123x/SX1233.h b/src/modules/SX123x/SX1233.h new file mode 100644 index 0000000000..b8f078ef69 --- /dev/null +++ b/src/modules/SX123x/SX1233.h @@ -0,0 +1,59 @@ +#if !defined(_RADIOLIB_SX1233_H) +#define _RADIOLIB_SX1233_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX1233 + +#include "../../Module.h" +#include "../RF69/RF69.h" +#include "SX1231.h" + +// RADIOLIB_SX1233 specific register map +#define RADIOLIB_SX1233_REG_TEST_PLL 0x5F + +// RADIOLIB_SX1233_REG_TEST_PLL +#define RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE 0x0C +#define RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE 0x08 + +/*! + \class SX1233 + \brief Control class for %SX1233 module. Overrides some methods from SX1231/RF69 due to different register values. +*/ +class SX1233: public SX1231 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1233(Module* mod); + + /*! + \brief Initialization method. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + + /*! + \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. + SX1233 also allows 500 kbps and 600 kbps operation. + \param br Bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + +#if !RADIOLIB_GODMODE + private: +#endif + uint8_t chipRevision = 0; +}; + +#endif + +#endif From af9073fae45d06637c51650e18d9de3b00d79a0b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 9 Dec 2023 15:38:38 +0100 Subject: [PATCH 0840/1848] [RF69] Make setMode protected --- src/modules/RF69/RF69.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 93d1dff33b..d71d91c6d4 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1024,11 +1024,11 @@ class RF69: public PhysicalLayer { int16_t config(); int16_t directMode(); int16_t setPacketMode(uint8_t mode, uint8_t len); + int16_t setMode(uint8_t mode); #if !RADIOLIB_GODMODE private: #endif - int16_t setMode(uint8_t mode); void clearIRQFlags(); void clearFIFO(size_t count); }; From 57a6a9ccc3cbb2307aa81546e2e0144f321dd358 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 9 Dec 2023 16:00:42 +0100 Subject: [PATCH 0841/1848] [SX123x] Added missing include --- src/modules/SX123x/SX1233.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index cece36ba91..6a481046d8 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -1,4 +1,5 @@ #include "SX1233.h" +#include #if !RADIOLIB_EXCLUDE_SX1233 SX1233::SX1233(Module* mod) : SX1231(mod) { From a30d3da2964e02bc0179cb18ec411b7f2aa429d9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 9 Dec 2023 16:12:10 +0100 Subject: [PATCH 0842/1848] [SX123x] Added note about high bit rate mode for SX1233 --- src/modules/SX123x/SX1233.cpp | 2 +- src/modules/SX123x/SX1233.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index 6a481046d8..c13d5e3982 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -17,7 +17,7 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po bool flagFound = false; while((i < 10) && !flagFound) { int16_t version = getChipVersion(); - if((version == 0x21) || (version == 0x22) || (version == 0x23)) { + if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) { flagFound = true; this->chipRevision = version; } else { diff --git a/src/modules/SX123x/SX1233.h b/src/modules/SX123x/SX1233.h index b8f078ef69..c6f11d3f47 100644 --- a/src/modules/SX123x/SX1233.h +++ b/src/modules/SX123x/SX1233.h @@ -43,6 +43,8 @@ class SX1233: public SX1231 { /*! \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. SX1233 also allows 500 kbps and 600 kbps operation. + NOTE: For 500 kbps rate, the receiver frequency should be offset by 50 kHz from the transmitter. + For 600 kbps rate, the receiver frequency should be offset by 40 kHz from the transmitter. \param br Bit rate to be set in kbps. \returns \ref status_codes */ From 6bac59ce08bc48bda565c8605579b52ac6d1b3fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 22 Dec 2023 15:04:19 +0100 Subject: [PATCH 0843/1848] [CC1101] Fixed direct transmit (#911) --- src/modules/CC1101/CC1101.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 6cae666a64..f65d913fd7 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -209,6 +209,7 @@ int16_t CC1101::transmitDirect(bool sync, uint32_t frf) { SPIwriteRegister(RADIOLIB_CC1101_REG_FREQ0, frf & 0x0000FF); SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + return(RADIOLIB_ERR_NONE); } // activate direct mode From badcbbe80902958457a0f33c1b068fb53d7c2e55 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 29 Dec 2023 16:38:55 +0100 Subject: [PATCH 0844/1848] [LoRaWAN] Fix ABP initialization, support MAC in payload --- src/protocols/LoRaWAN/LoRaWAN.cpp | 82 ++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index af9c77e816..3750b99945 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -219,6 +219,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { // the device has joined already, we can just pull the data from persistent storage + RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); return(this->restore()); } #else @@ -461,6 +462,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, Module* mod = this->phyLayer->getMod(); if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { // the device has joined already, we can just pull the data from persistent storage + RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); return(this->restore()); } #else @@ -489,6 +491,9 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, state = this->setupChannels(nullptr); RADIOLIB_ASSERT(state); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = (this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMin) / 2; + // downlink datarate is calculated using a specific uplink channel, so don't care here + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the device address & keys mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); @@ -1106,10 +1111,23 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); + RADIOLIB_DEBUG_PRINTLN("FOpts: %02X", downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS]); + + // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload + // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) bool isAppDownlink = true; - if (payLen <= 0 && this->rev == 1) { // no payload => MAC commands only => Network frame (LoRaWAN v1.1 only) - isAppDownlink = false; + if(payLen <= 0) { + if(this->rev == 1) { + isAppDownlink = false; + } + } + else if(downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + foptsLen = payLen - 1; + if(this->rev == 1) { + isAppDownlink = false; + } } + RADIOLIB_DEBUG_PRINTLN("FOptsLen: %d", foptsLen); // check the FcntDown value (Network or Application) uint32_t fcntDownPrev = 0; @@ -1176,11 +1194,17 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // process FOpts (if there are any) if(foptsLen > 0) { // there are some Fopts, decrypt them - uint8_t fopts[RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK]; - - // TODO it COULD be the case that the assumed rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 - uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); + uint8_t fopts[max(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + + // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 + // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload + // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey + if(foptsLen <= RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK) { + uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); + } else { + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + } RADIOLIB_DEBUG_PRINTLN("fopts:"); RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); @@ -1192,10 +1216,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) LoRaWANMacCommand_t cmd = { .cid = *foptsPtr, .payload = { 0 }, - .len = (uint8_t)(remLen - 1), + .len = (uint8_t)min((remLen - 1), 5), .repeat = 0, }; memcpy(cmd.payload, foptsPtr + 1, cmd.len); + RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", + cmd.cid, cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); // try to process the mac command // TODO how to handle incomplete commands? @@ -1204,6 +1230,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // processing succeeded, move in the buffer to the next command remLen -= processedLen; foptsPtr += processedLen; + RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", processedLen, remLen); } // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink @@ -1270,8 +1297,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->port = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)]; } - // process payload (if there is any) - if(payLen <= 0) { + // process Application payload (if there is any) + if(payLen <= 0 || foptsLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { // no payload *len = 0; #if !RADIOLIB_STATIC_ONLY @@ -1403,17 +1430,20 @@ int16_t LoRaWANNode::setPhyProperties() { int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { size_t num = 0; + RADIOLIB_DEBUG_PRINTLN("Setting up channels"); // in case of frequency list-type band, copy the default TX channels into the available channels, with RX1 = TX if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + RADIOLIB_DEBUG_PRINTLN("Dynamic band"); // copy the default defined channels into the first slots for(; num < 3 && this->band->txFreqs[num].enabled; num++) { - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } // if there is a cflist present, parse its frequencies into the next five slots, with datarate range copied from default channel 0 if(cfList != nullptr) { + RADIOLIB_DEBUG_PRINTLN("CFList present"); for(uint8_t i = 0; i < 5; i++, num++) { LoRaWANChannel_t chnl; chnl.enabled = true; @@ -1422,9 +1452,9 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { chnl.freq = (float)freq/10000.0; chnl.drMin = this->band->txFreqs[0].drMin; // drMin is equal for all channels chnl.drMax = this->band->txFreqs[0].drMax; // drMax is equal for all channels - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", chnl.idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", chnl.idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } } for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { @@ -1457,9 +1487,9 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; chnl.drMin = this->band->txSpans[chSpan].drMin; chnl.drMax = this->band->txSpans[chSpan].drMax; - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; // downlink channels are dynamically calculated on each uplink in selectChannels() - RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", num, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", num, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); num++; } chNum++; @@ -1470,6 +1500,21 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { } } } + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } return(RADIOLIB_ERR_NONE); } @@ -1978,6 +2023,7 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { cmd->payload[0] = snr & 0x3F; // push it to the uplink queue + RADIOLIB_DEBUG_PRINTLN("DevStatus ANS: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); pushMacCommand(cmd, &this->commandsUp); return(0); } break; From 797b7a4323788bb50b6899bf08cc5a2552bae2d8 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 29 Dec 2023 23:53:44 +0100 Subject: [PATCH 0845/1848] [LoRaWAN] Fix macros --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 3750b99945..89117a4c8b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1194,7 +1194,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // process FOpts (if there are any) if(foptsLen > 0) { // there are some Fopts, decrypt them - uint8_t fopts[max(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + uint8_t fopts[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload @@ -1216,7 +1216,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) LoRaWANMacCommand_t cmd = { .cid = *foptsPtr, .payload = { 0 }, - .len = (uint8_t)min((remLen - 1), 5), + .len = (uint8_t)RADIOLIB_MIN((remLen - 1), 5), .repeat = 0, }; memcpy(cmd.payload, foptsPtr + 1, cmd.len); From cc76bad06fc6a15d99de363b1b0fc33517bae0f6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 30 Dec 2023 23:03:16 +0100 Subject: [PATCH 0846/1848] Fix tabs --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffcc6abc21..680864d287 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,19 @@ cmake_minimum_required(VERSION 3.13) if(ESP_PLATFORM) - # Build RadioLib as an ESP-IDF component + # Build RadioLib as an ESP-IDF component # required because ESP-IDF runs cmake in script mode # and needs idf_component_register() file(GLOB_RECURSE RADIOLIB_ESP_SOURCES "src/*.*" ) - idf_component_register( + idf_component_register( SRCS ${RADIOLIB_ESP_SOURCES} INCLUDE_DIRS . src ) - return() + return() endif() if(CMAKE_SCRIPT_MODE_FILE) From 3478d908196469ee34461365e2f5c107651e8dae Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 4 Jan 2024 18:21:35 +0100 Subject: [PATCH 0847/1848] [SX126x] Improved image calibration --- src/modules/SX126x/SX1262.cpp | 21 ++------------------- src/modules/SX126x/SX1268.cpp | 15 ++------------- src/modules/SX126x/SX126x.h | 14 +------------- 3 files changed, 5 insertions(+), 45 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index d24e0f436a..b6f68cb491 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -54,26 +54,9 @@ int16_t SX1262::setFrequency(float freq) { int16_t SX1262::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); - // calibrate image + // calibrate image rejection - assume band to be the selected frequency +- 4 MHz if(calibrate) { - uint8_t data[2]; - if(freq > 900.0) { - data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2; - } else if(freq > 850.0) { - data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; - } else if(freq > 770.0) { - data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; - } else if(freq > 460.0) { - data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else { - data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; - } - int16_t state = SX126x::calibrateImage(data); + int16_t state = SX126x::calibrateImage(freq - 4, freq + 4); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 596ce7e451..8aad25b70e 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -55,20 +55,9 @@ int16_t SX1268::setFrequency(float freq) { int16_t SX1268::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); - // calibrate image + // calibrate image rejection - assume band to be the selected frequency +- 4 MHz if(calibrate) { - uint8_t data[2]; - if(freq > 770.0) { - data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; - } else if(freq > 460.0) { - data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else { - data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; - } - int16_t state = SX126x::calibrateImage(data); + int16_t state = SX126x::calibrateImage(freq - 4, freq + 4); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 5e8c03b68b..2fb3fdb4a2 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -188,18 +188,6 @@ #define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled #define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks -//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 - //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 #define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 @@ -1119,7 +1107,7 @@ class SX126x: public PhysicalLayer { int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); - int16_t calibrateImage(uint8_t* data); + int16_t calibrateImage(float freqMin, float freqMax); uint8_t getPacketType(); int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); From 19b61739e629aed397ed6b5fd6e455e114884907 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 4 Jan 2024 18:23:36 +0100 Subject: [PATCH 0848/1848] [SX126x] Fixed image calibration --- src/modules/SX126x/SX126x.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 797968a83d..e2ffdb74a8 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1835,7 +1835,8 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } -int16_t SX126x::calibrateImage(uint8_t* data) { +int16_t SX126x::calibrateImage(float freqMin, float freqMax) { + uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)floor((freqMax - 1.0f) / 4.0f) }; int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors From bf061c655ffee2373c90cade51253cf0fe466c8d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 4 Jan 2024 18:30:22 +0100 Subject: [PATCH 0849/1848] [SX126x] Allow custom band calibration --- src/modules/SX126x/SX1262.cpp | 6 +++--- src/modules/SX126x/SX1262.h | 5 ++++- src/modules/SX126x/SX1268.cpp | 6 +++--- src/modules/SX126x/SX1268.h | 7 +++++-- src/modules/SX126x/SX126x.cpp | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index b6f68cb491..0bbce30d4e 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -51,12 +51,12 @@ int16_t SX1262::setFrequency(float freq) { return(setFrequency(freq, true)); } -int16_t SX1262::setFrequency(float freq, bool calibrate) { +int16_t SX1262::setFrequency(float freq, bool calibrate, float band) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); - // calibrate image rejection - assume band to be the selected frequency +- 4 MHz + // calibrate image rejection if(calibrate) { - int16_t state = SX126x::calibrateImage(freq - 4, freq + 4); + int16_t state = SX126x::calibrateImage(freq - band, freq + band); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index f47b1a8131..61f8facc73 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -75,9 +75,12 @@ class SX1262: public SX126x { \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \param freq Carrier frequency to be set in MHz. \param calibrate Run image calibration. + \param band Half bandwidth for image calibration. For example, + if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate + for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate); + int16_t setFrequency(float freq, bool calibrate, float band = 4); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 8aad25b70e..7f14e9fae9 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -52,12 +52,12 @@ int16_t SX1268::setFrequency(float freq) { } /// \todo integers only (all modules - frequency, data rate, bandwidth etc.) -int16_t SX1268::setFrequency(float freq, bool calibrate) { +int16_t SX1268::setFrequency(float freq, bool calibrate, float band) { RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); - // calibrate image rejection - assume band to be the selected frequency +- 4 MHz + // calibrate image rejection if(calibrate) { - int16_t state = SX126x::calibrateImage(freq - 4, freq + 4); + int16_t state = SX126x::calibrateImage(freq - band, freq + band); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 08b3eb4149..f3f61dc86d 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -71,12 +71,15 @@ class SX1268: public SX126x { int16_t setFrequency(float freq); /*! - \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \param freq Carrier frequency to be set in MHz. \param calibrate Run image calibration. + \param band Half bandwidth for image calibration. For example, + if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate + for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate); + int16_t setFrequency(float freq, bool calibrate, float band = 4); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index e2ffdb74a8..59d4e764dc 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1836,7 +1836,7 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { } int16_t SX126x::calibrateImage(float freqMin, float freqMax) { - uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)floor((freqMax - 1.0f) / 4.0f) }; + uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) }; int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors From 574555ca098d5b134da69b615f04669b62f625e0 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 5 Jan 2024 11:06:24 +0100 Subject: [PATCH 0850/1848] [LoRaWAN] Revamp internal processing, key checking, new MAC commands, implement DutyCycle & DwellTime --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 24 +- .../LoRaWAN_End_Device_ABP.ino | 38 +- .../LoRaWAN_End_Device_Persistent.ino | 47 +- .../LoRaWAN_End_Device_Reference.ino | 57 +- keywords.txt | 9 + src/BuildOpt.h | 2 +- src/Hal.h | 128 +- src/TypeDef.h | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 1279 +++++++++++------ src/protocols/LoRaWAN/LoRaWAN.h | 191 ++- src/protocols/LoRaWAN/LoRaWANBands.cpp | 27 + 11 files changed, 1254 insertions(+), 550 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index b5eaaf8c95..c2ea337fc5 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -24,11 +24,12 @@ // include the library #include -// SX1278 has the following connections: -// NSS pin: 10 -// DIO0 pin: 2 -// RESET pin: 9 -// DIO1 pin: 3 +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) SX1278 radio = new Module(10, 2, 9, 3); // create the node instance on the EU-868 band @@ -85,6 +86,11 @@ void setup() { node.selectSubband(8, 15); */ + // on EEPROM-enabled boards, after the device has been activated, + // the session can be restored without rejoining after device power cycle + // this is intrinsically done when calling `beginOTAA()` with the same keys + // in that case, the function will not need to transmit a JoinRequest + // now we can start the activation // this can take up to 10 seconds, and requires a LoRaWAN gateway in range // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): @@ -147,7 +153,11 @@ void loop() { Serial.print(F("failed, code ")); Serial.println(state); } - + // wait before sending another packet - delay(30000); + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index 05198f5ffd..c2bd5ff130 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -25,11 +25,12 @@ // include the library #include -// SX1278 has the following connections: -// NSS pin: 10 -// DIO0 pin: 2 -// RESET pin: 9 -// DIO1 pin: 3 +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) SX1278 radio = new Module(10, 2, 9, 3); // create the node instance on the EU-868 band @@ -69,6 +70,14 @@ void setup() { uint8_t appSKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + // network key 2 is the ASCII string "topSecretKey5678" + uint8_t fNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x35, 0x36, 0x37, 0x38 }; + + // network key 3 is the ASCII string "aDifferentKeyDEF" + uint8_t sNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x44, 0x45, 0x46 }; + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded // and can be set to NULL @@ -86,15 +95,20 @@ void setup() { node.rx2.drMax = 3; */ - // to start a LoRaWAN v1.1 session, the user should also provide - // fNwkSIntKey and sNwkSIntKey similar to nwkSKey and appSKey + // on EEPROM-enabled boards, after the device has been activated, + // the session can be restored without rejoining after device power cycle + // this is intrinsically done when calling `beginABP()` with the same keys + // in that case, the function will not need to transmit a JoinRequest + + // to start a LoRaWAN v1.0 session, + // the user can remove the fNwkSIntKey and sNwkSIntKey /* - state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey); + state = node.beginABP(devAddr, nwkSKey, appSKey); */ // start the device by directly providing the encryption keys and device address Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginABP(devAddr, nwkSKey, appSKey); + state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -149,5 +163,9 @@ void loop() { } // wait before sending another packet - delay(30000); + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino index 3c96fb9134..983a82a08a 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino @@ -12,7 +12,7 @@ NOTE: LoRaWAN requires storing some parameters persistently! RadioLib does this by using EEPROM, by default - starting at address 0 and using 384 bytes. + starting at address 0 and using 448 bytes. If you already use EEPROM in your application, you will have to either avoid this range, or change it by setting a different start address by changing the value of @@ -29,11 +29,12 @@ // include the library #include -// SX1278 has the following connections: -// NSS pin: 10 -// DIO0 pin: 2 -// RESET pin: 9 -// DIO1 pin: 3 +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) SX1278 radio = new Module(10, 2, 9, 3); // create the node instance on the EU-868 band @@ -56,33 +57,31 @@ void setup() { while(true); } - // first we need to initialize the device storage - // this will reset all persistently stored parameters - // NOTE: This should only be done once prior to first joining a network! - // After wiping persistent storage, you will also have to reset - // the end device in TTN and perform the join procedure again! - // Here, a delay is added to make sure that during re-flashing - // the .wipe() is not triggered and the session is lost - //delay(5000); - //node.wipe(); - - // now we can start the activation + // start the activation // Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); // uint64_t joinEUI = 0x12AD1011B0C0FFEE; - // uint64_t devEUI = 0x70B3D57ED005E120; + // uint64_t devEUI = 0x70B3D57ED005E120; // uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, // 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; // uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, // 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; // state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - // after the device has been activated, + // on EEPROM-enabled boards, after the device has been activated, // the session can be restored without rejoining after device power cycle - // on EEPROM-enabled boards by calling "restore" + // by calling the same `beginOTAA()` or `beginABP()` function with the same keys + // or call `restore()` where it will restore any existing session + // `restore()` returns the active mode if it succeeded (OTAA or ABP) Serial.print(F("[LoRaWAN] Resuming previous session ... ")); state = node.restore(); - if(state == RADIOLIB_ERR_NONE) { + if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); + Serial.print(F("Restored an ")); + if(state == RADIOLIB_LORAWAN_MODE_OTAA) + Serial.println(F("OTAA session.")); + else { + Serial.println(F("ABP session.")); + } } else { Serial.print(F("failed, code ")); Serial.println(state); @@ -141,5 +140,9 @@ void loop() { // wait before sending another packet // alternatively, call a deepsleep function here // make sure to send the radio to sleep as well using radio.sleep() - delay(30000); + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index bf70f13951..52d5904f26 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -27,11 +27,12 @@ // include the library #include -// SX1278 has the following connections: -// NSS pin: 10 -// DIO0 pin: 2 -// RESET pin: 9 -// DIO1 pin: 3 +// SX1262 has the following pin order: +// Module(NSS/CS, DIO1, RESET, BUSY) +// SX1262 radio = new Module(8, 14, 12, 13); + +// SX1278 has the following pin order: +// Module(NSS/CS, DIO0, RESET, DIO1) SX1278 radio = new Module(10, 2, 9, 3); // create the node instance on the EU-868 band @@ -106,9 +107,11 @@ void setup() { while(true); } - // after the device has been activated, + // on EEPROM-enabled boards, after the device has been activated, // the session can be restored without rejoining after device power cycle - // on EEPROM-enabled boards by calling "restore" + // this is intrinsically done when calling `beginOTAA()` with the same keys + // or if you 'lost' the keys or don't want them included in your sketch + // you can call `restore()` /* Serial.print(F("[LoRaWAN] Resuming previous session ... ")); state = node.restore(); @@ -131,6 +134,19 @@ void setup() { // this tries to minimize packet loss by searching for a free channel // before actually sending an uplink node.setCSMA(6, 2, true); + + // enable or disable the dutycycle + // the second argument specific allowed airtime per hour in milliseconds + // 1250 = TTN FUP (30 seconds / 24 hours) + // if not called, this corresponds to setDutyCycle(true, 0) + // setting this to 0 corresponds to the band's maximum allowed dutycycle by law + node.setDutyCycle(true, 1250); + + // enable or disable the dwell time limits + // the second argument specific allowed airtime per uplink in milliseconds + // if not called, this corresponds to setDwellTime(true, 0) + // setting this to 0 corresponds to the band's maximum allowed dwell time by law + node.setDwellTime(true, 1000); } void loop() { @@ -152,8 +168,11 @@ void loop() { String strUp = "Hello World! #" + String(fcntUp); // send a confirmed uplink to port 10 every 64th frame + // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { state = node.uplink(strUp, 10, true); + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); } else { state = node.uplink(strUp, 10); } @@ -228,6 +247,24 @@ void loop() { Serial.println(event.port); Serial.print(radio.getFrequencyError()); + + uint8_t margin = 0; + uint8_t gwCnt = 0; + if(node.getMacLinkCheckAns(&margin, &gwCnt)) { + Serial.print(F("[LoRaWAN] LinkCheck margin:\t")); + Serial.println(margin); + Serial.print(F("[LoRaWAN] LinkCheck count:\t")); + Serial.println(gwCnt); + } + + uint32_t networkTime = 0; + uint8_t fracSecond = 0; + if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true)) { + Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); + Serial.println(networkTime); + Serial.print(F("[LoRaWAN] LinkCheck second:\t1/")); + Serial.println(fracSecond); + } } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { Serial.println(F("timeout!")); @@ -244,5 +281,9 @@ void loop() { */ // wait before sending another packet - delay(30000); + uint32_t minimumDelay = 60000; // try to send once every minute + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + delay(delayMs); } diff --git a/keywords.txt b/keywords.txt index 065991a091..3f2da44a59 100644 --- a/keywords.txt +++ b/keywords.txt @@ -295,6 +295,7 @@ restore KEYWORD2 beginOTAA KEYWORD2 beginABP KEYWORD2 saveSession KEYWORD2 +sendMacCommandReq KEYWORD2 uplink KEYWORD2 downlink KEYWORD2 sendReceive KEYWORD2 @@ -302,11 +303,19 @@ setDeviceStatus KEYWORD2 getFcntUp KEYWORD2 getNFcntDown KEYWORD2 getAFcntDown KEYWORD2 +resetFcntDown KEYWORD2 setDatarate KEYWORD2 setADR KEYWORD2 +setDutyCycle KEYWORD2 +dutyCycleInterval KEYWORD2 +timeUntilUplink KEYWORD2 +setDwellTime KEYWORD2 +maxPayloadDwellTime KEYWORD2 setTxPower KEYWORD2 selectSubband KEYWORD2 setCSMA KEYWORD2 +getMacLinkCheckAns KEYWORD2 +getMacDeviceTimeAns KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 308dc8969f..a95b6cdd1c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -112,7 +112,7 @@ // the amount of space allocated to the persistent storage #if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x0180) + #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x01C0) #endif /* diff --git a/src/Hal.h b/src/Hal.h index 780c348318..20d858ff72 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -6,60 +6,86 @@ #include "BuildOpt.h" +#define RADIOLIB_EEPROM_TABLE_VERSION (0x0002) + // list of persistent parameters -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID (0) // this is NOT the LoRaWAN version, but version of this table -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID (1) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID (2) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID (3) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID (4) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID (5) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID (6) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID (7) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID (8) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID (9) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID (10) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID (11) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (12) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (13) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (14) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID (15) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (16) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID (17) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID (18) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID (19) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID (20) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID (21) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID (22) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID (23) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID (24) +enum RADIOLIB_EEPROM_PARAMS { + RADIOLIB_EEPROM_TABLE_VERSION_ID, // table layout version + RADIOLIB_EEPROM_LORAWAN_CLASS_ID, // class A, B or C + RADIOLIB_EEPROM_LORAWAN_MODE_ID, // none, OTAA or ABP + RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, // checksum of keys used for device activation + RADIOLIB_EEPROM_LORAWAN_VERSION_ID, // LoRaWAN version + RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID, // last heard time through DeviceTimeReq or Beacon + RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, + RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID, + RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID, + RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID, + RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID, + RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, + RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, + RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, + RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, + RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, + RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, + RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, + RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, + RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID, + RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID, + RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, + RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID, + RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID, + RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID, + RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID, + RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID, + RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID, + RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID, + RADIOLIB_EEPROM_LORAWAN_BEACON_FREQ_ID, + RADIOLIB_EEPROM_LORAWAN_PING_SLOT_CHANNEL_ID, + RADIOLIB_EEPROM_LORAWAN_PERIODICITY_ID, + RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, + RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID, + RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID, + RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID +}; static const uint32_t RadioLibPersistentParamTable[] = { - 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID - 0x01, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID - 0x03, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION - 0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID - 0x05, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID - 0x06, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID - 0x07, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID - 0x0A, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID - 0x0B, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID - 0x0C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID - 0x10, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID - 0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID - 0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID - 0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID - 0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID - 0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID - 0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID - 0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID - 0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID - 0x64, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID - 0x68, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID - 0x6C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID - 0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID - 0x8E, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID - 0xD0, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID - 0x0180, // end + 0x00, // RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION_ID + 0x02, // RADIOLIB_EEPROM_LORAWAN_CLASS_ID + 0x03, // RADIOLIB_EEPROM_LORAWAN_MODE_ID + 0x05, // RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID + 0x07, // RADIOLIB_EEPROM_LORAWAN_VERSION_ID + 0x08, // RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID + 0x0C, // RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID + 0x10, // RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID + 0x20, // RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID + 0x30, // RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID + 0x40, // RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID + 0x50, // RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID + 0x54, // RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID + 0x58, // RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID + 0x5C, // RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID + 0x60, // RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID + 0x64, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID + 0x68, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID + 0x6C, // RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID + 0x70, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID + 0x72, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID + 0x74, // RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 0xA0, // RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID - NOTE change upon ADR Ack Req + 0xA4, // RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID + 0xA5, // RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID + 0xA9, // RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID + 0xAA, // RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID + 0xAB, // RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID + 0xAC, // RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID + 0xAD, // RADIOLIB_EEPROM_LORAWAN_BEACON_FREQ_ID + 0xB0, // RADIOLIB_EEPROM_LORAWAN_PING_SLOT_CHANNEL_ID + 0xB4, // RADIOLIB_EEPROM_LORAWAN_PERIODICITY_ID + 0xB5, // RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID + 0xB6, // RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID + 0x0100, // RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID + 0x0180, // RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID + 0x01C0, // end }; /*! diff --git a/src/TypeDef.h b/src/TypeDef.h index 2e16145c0d..64d1a1a291 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -519,7 +519,7 @@ #define RADIOLIB_ERR_INVALID_CID (-1107) /*! - \brief User requested to start uplink while still inside RX window. + \brief User requested to start uplink while still inside RX window or under dutycycle. */ #define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 89117a4c8b..e7217f4e96 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -28,10 +28,57 @@ uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_ return(dr); } +uint16_t checkSum16(uint32_t key) { + uint8_t bufLen = 2; + uint16_t buf16[bufLen]; + memcpy(buf16, &key, bufLen); + uint16_t checkSum = 0; + for(int i = 0; i < bufLen; i++) { + checkSum ^= buf16[i]; + } + return(checkSum); +} + +uint16_t checkSum16(uint64_t key) { + uint8_t bufLen = 4; + uint16_t buf16[bufLen]; + memcpy(buf16, &key, bufLen); + uint16_t checkSum = 0; + for(int i = 0; i < bufLen; i++) { + checkSum ^= buf16[i]; + } + return(checkSum); +} + +uint16_t checkSum16(uint8_t *key, uint8_t keyLen) { + uint8_t bufLen = keyLen / 2; + uint16_t buf16[bufLen]; + memcpy(buf16, key, bufLen); + uint16_t checkSum = 0; + for(int i = 0; i < bufLen; i++) { + checkSum ^= buf16[i]; + } + return(checkSum); +} + LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->phyLayer = phy; this->band = band; this->rx2 = this->band->rx2; + this->dutyCycle = this->band->dutyCycle; + if(this->dutyCycle > 0) { + this->dutyCycleEnabled = true; + } + this->dwellTimeUp = this->band->dwellTimeUp; + if(this->dwellTimeUp > 0) { + this->dwellTimeEnabledUp = true; + } + this->dwellTimeDn = this->band->dwellTimeDn; + if(this->dwellTimeDn) { + this->dwellTimeEnabledDn = true; + } + this->txPowerMax = this->band->powerMax; + this->txPowerCur = 0; // start at 0 offset = full power this->difsSlots = 2; this->backoffMax = 6; this->enableCSMA = false; @@ -49,22 +96,24 @@ void LoRaWANNode::wipe() { mod->hal->wipePersistentStorage(); } +// TODO do not return status code, but return LoRaWAN mode (OTAA, ABP, none) int16_t LoRaWANNode::restore() { // if already joined, ignore - if(this->isJoinedFlag) { - return(RADIOLIB_ERR_NONE); + if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { + return(this->activeMode); } Module* mod = this->phyLayer->getMod(); - uint8_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID); - // if (RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION > nvm_table_version) { + uint8_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID); + // if (RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION > nvm_table_version) { // // set default values for variables that are new or something // } (void)nvm_table_version; // check the magic value - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) != RADIOLIB_LORAWAN_MAGIC) { + uint8_t lwMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID); + if(lwMode == RADIOLIB_LORAWAN_MODE_NONE) { #if RADIOLIB_DEBUG RADIOLIB_DEBUG_PRINTLN("magic id not set (no saved session)"); RADIOLIB_DEBUG_PRINTLN("first 16 bytes of NVM:"); @@ -75,85 +124,95 @@ int16_t LoRaWANNode::restore() { // the magic value is not set, user will have to do perform the join procedure return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } - + // pull all authentication keys from persistent storage - this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); // get session parameters - this->rev = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID); + this->rev = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID); RADIOLIB_DEBUG_PRINTLN("LoRaWAN session: v1.%d", this->rev); - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID); - - // get MAC state - uint8_t txDrRx2Dr = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID); - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = (txDrRx2Dr >> 4) & 0x0F; - - this->txPwrCur = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID); - - uint8_t rx1DrOffDel = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID); - this->rx1DrOffset = (rx1DrOffDel >> 4) & 0x0F; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] + this->band->rx1DataRateBase + this->rx1DrOffset; - this->rxDelays[0] = ((rx1DrOffDel >> 0) & 0x0F) * 1000; - if(this->rxDelays[0] == 0) { - this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; - } - this->rxDelays[1] = this->rxDelays[0] + 1000; - - uint8_t rx2FreqBuf[3]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID), rx2FreqBuf, 3); - uint32_t rx2Freq = LoRaWANNode::ntoh(&rx2FreqBuf[0], 3); - this->rx2.drMax = (txDrRx2Dr >> 0) & 0x0F; - this->rx2.freq = (float)rx2Freq / 10000.0; + this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); + this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); + this->aFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID); + this->nFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID); + this->confFcntUp = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID); + this->confFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID); + this->adrFcnt = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID); - uint8_t adrLimDel = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID); - this->adrLimitExp = (adrLimDel >> 4) & 0x0F; - this->adrDelayExp = (adrLimDel >> 0) & 0x0F; - - this->nbTrans = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID); - - this->aFcntDown = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID); - this->nFcntDown = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID); - this->confFcntUp = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID); - this->confFcntDown = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID); - this->adrFcnt = mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID); - - // fcntUp is stored in highly efficient wear-leveling system, so parse it as required + // fcntUp is stored in highly efficient wear-leveling system, so parse it this->restoreFcntUp(); + // get the defined channels + int16_t state = this->restoreChannels(); + RADIOLIB_ASSERT(state); + + // get MAC state + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + + cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + + cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + + cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + + cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); memcpy(&this->commandsUp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); RADIOLIB_DEBUG_PRINTLN("Number of MAC commands: %d", this->commandsUp.numCommands); - - int16_t state = this->restoreChannels(); - RADIOLIB_ASSERT(state); state = this->setPhyProperties(); RADIOLIB_ASSERT(state); - // full session is restored, so set joined flag - this->isJoinedFlag = true; + // full session is restored, so set joined flag to whichever mode is restored + this->activeMode = lwMode; - return(RADIOLIB_ERR_NONE); + return(this->activeMode); } int16_t LoRaWANNode::restoreFcntUp() { Module* mod = this->phyLayer->getMod(); - uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID); - uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID + 1); + uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); + uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 1); uint8_t buffSize = fcntBuffEnd - fcntBuffStart; #if RADIOLIB_STATIC_ONLY uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* fcntBuff = new uint8_t[buffSize]; #endif - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); // copy the two most significant bytes from the first two bytes uint32_t bits_30_22 = (uint32_t)fcntBuff[0]; @@ -191,50 +250,193 @@ int16_t LoRaWANNode::restoreFcntUp() { } int16_t LoRaWANNode::restoreChannels() { - const uint8_t bytesPerChannel = 5; - const uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; - uint8_t buffer[numBytes] = { 0 }; + // first do the default channels + this->setupChannels(nullptr); + Module* mod = this->phyLayer->getMod(); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID), buffer, numBytes); - for(uint8_t dir = 0; dir < 2; dir++) { - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - uint8_t chBuff[bytesPerChannel] = { 0 }; - memcpy(chBuff, &buffer[(dir * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel) + i * bytesPerChannel], bytesPerChannel); - this->availableChannels[dir][i].enabled = (chBuff[0] & 0x80) >> 7; - this->availableChannels[dir][i].idx = chBuff[0] & 0x7F; - uint32_t freq = LoRaWANNode::ntoh(&chBuff[1], 3); - this->availableChannels[dir][i].freq = (float)freq/10000.0; - this->availableChannels[dir][i].drMax = (chBuff[4] & 0xF0) >> 4; - this->availableChannels[dir][i].drMin = (chBuff[4] & 0x0F) >> 0; + uint8_t bufferZeroes[5] = { 0 }; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + uint8_t numBytesUp = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + uint8_t bufferUp[numBytesUp] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), bufferUp, numBytesUp); + + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + (void)execMacCommand(&cmd, false); + } + } + + uint8_t numBytesDn = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; + uint8_t bufferDn[numBytesDn] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID), bufferDn, numBytesDn); + + cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; + + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + memcpy(cmd.payload, &bufferDn[i * cmd.len], cmd.len); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + (void)execMacCommand(&cmd, false); + } + } + + } else { + uint8_t numBytes = 8 * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + uint8_t buffer[numBytes] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); + + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + + for(int i = 0; i < 8; i++) { + memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len); + // there COULD, according to spec, be an all zeroes ADR command - meh + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { + execMacCommand(&cmd, false); + } } } return(RADIOLIB_ERR_NONE); } #endif +void LoRaWANNode::beginCommon() { + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + cmd.payload[0] |= 0; // default to max Tx Power + cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; + uint8_t maxDCyclePower; + switch(this->band->dutyCycle) { + case(0): + maxDCyclePower = 0; + break; + case(3600): + maxDCyclePower = 10; + break; + case(36000): + maxDCyclePower = 7; + break; + default: + maxDCyclePower = 0; + break; + } + cmd.payload[0] = maxDCyclePower; + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); + cmd.payload[0] |= this->rx2.drMax; // may be set by user, otherwise band's default upon initialization + uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); + LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; + cmd.payload[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; + cmd.payload[0] |= (this->band->dwellTimeUp > 0 ? 1 : 0) << 4; + uint8_t maxEIRPRaw; + switch(this->band->powerMax) { + case(12): + maxEIRPRaw = 2; + break; + case(14): + maxEIRPRaw = 4; + break; + case(16): + maxEIRPRaw = 5; + break; + case(19): // this option does not exist for the TxParamSetupReq but will be caught during execution + maxEIRPRaw = 7; + break; + case(30): + maxEIRPRaw = 13; + break; + default: + maxEIRPRaw = 2; + break; + } + cmd.payload[0] |= maxEIRPRaw; + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); + cmd.payload[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + (void)execMacCommand(&cmd); + + cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); + cmd.payload[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; + (void)execMacCommand(&cmd); +} + int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr, bool force) { // check if we actually need to send the join request Module* mod = this->phyLayer->getMod(); #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { + uint16_t checkSum = 0; + checkSum ^= checkSum16(joinEUI); + checkSum ^= checkSum16(devEUI); + checkSum ^= checkSum16(nwkKey, 16); + checkSum ^= checkSum16(appKey, 16); + + bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; + bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; + + if(!force && validCheckSum && validMode) { // the device has joined already, we can just pull the data from persistent storage RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); + return(this->restore()); + } else { + #if RADIOLIB_DEBUG + RADIOLIB_DEBUG_PRINTLN("Failed to restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); + uint8_t nvmBuff[16]; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); + RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); + RADIOLIB_DEBUG_PRINTLN("Wiping EEPROM and starting a clean session"); + #endif + + this->wipe(); } #else (void)force; #endif - // set the physical layer configuration - this->txPwrCur = this->band->powerMax; - int16_t state = this->setPhyProperties(); - RADIOLIB_ASSERT(state); + int16_t state = RADIOLIB_ERR_NONE; // setup uplink/downlink frequencies and datarates state = this->selectChannelsJR(this->devNonce, joinDr); RADIOLIB_ASSERT(state); + // setup all MAC properties to default values + this->beginCommon(); + + // set the physical layer configuration + state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + // configure for uplink with default configuration state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); @@ -314,12 +516,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } this->joinNonce = joinNonceNew; + this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); + this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); + // check LoRaWAN revision (the MIC verification depends on this) uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: 1.%d", this->rev); - this->rx1DrOffset = (dlSettings & 0x70) >> 4; - this->rx2.drMax = dlSettings & 0x0F; // verify MIC if(this->rev == 1) { @@ -348,18 +551,20 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } } - - // parse other contents - this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); - this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); - // parse Rx1 delay (and subsequently Rx2) - this->rxDelays[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]*1000; - if(this->rxDelays[0] == 0) { - this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; - } - this->rxDelays[1] = this->rxDelays[0] + 1000; + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + cmd.payload[0] = dlSettings & 0x7F; + uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); // default Rx2 frequency + LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); + (void)execMacCommand(&cmd); + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + (void)execMacCommand(&cmd); + // process CFlist if present if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; @@ -397,7 +602,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // enqueue the RekeyInd MAC command to be sent in the next uplink LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY, + .cid = RADIOLIB_LORAWAN_MAC_REKEY, .payload = { this->rev }, .len = sizeof(uint8_t), .repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP, @@ -431,39 +636,63 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->adrFcnt = 0; #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // save the device address & keys as well as JoinAccept values; these are only ever set when joining - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); // save join-request parameters - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID, this->homeNetId); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); this->saveSession(); - this->saveChannels(); - // everything written to NVM, write current table version to persistent storage and set magic number - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); + // everything written to NVM, write current table version to persistent storage and set mode + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA); #endif - this->isJoinedFlag = true; + this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { + Module* mod = this->phyLayer->getMod(); #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // check if we actually need to restart from a clean session - Module* mod = this->phyLayer->getMod(); - if(!force && (mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID) == RADIOLIB_LORAWAN_MAGIC)) { + uint16_t checkSum = 0; + checkSum ^= checkSum16(addr); + checkSum ^= checkSum16(nwkSKey, 16); + checkSum ^= checkSum16(appSKey, 16); + if(fNwkSIntKey) + checkSum ^= checkSum16(fNwkSIntKey, 16); + if(sNwkSIntKey) + checkSum ^= checkSum16(sNwkSIntKey, 16); + + bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; + bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; + + if(!force && validCheckSum && validMode) { // the device has joined already, we can just pull the data from persistent storage RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); + return(this->restore()); + } else { + #if RADIOLIB_DEBUG + RADIOLIB_DEBUG_PRINTLN("Failed to restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); + uint8_t nvmBuff[16]; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); + RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); + RADIOLIB_DEBUG_PRINTLN("Wiping EEPROM and starting a clean session"); + #endif + + this->wipe(); } #else (void)force; @@ -482,41 +711,43 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } - // set the physical layer configuration - this->txPwrCur = this->band->powerMax; - int16_t state = this->setPhyProperties(); - RADIOLIB_ASSERT(state); - - // setup uplink/downlink frequencies and datarates - state = this->setupChannels(nullptr); - RADIOLIB_ASSERT(state); + int16_t state = RADIOLIB_ERR_NONE; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = (this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMin) / 2; + // calculate initial datarate - in case of fixed bands, this requires a subband to be selected // downlink datarate is calculated using a specific uplink channel, so don't care here + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = (this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMin) / 2; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // save the device address & keys - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + // setup all MAC properties to default values + this->beginCommon(); + // set the physical layer configuration + state = this->setPhyProperties(); + RADIOLIB_ASSERT(state); + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // save the activation keys checksum, device address & keys + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + // save all new frame counters this->saveSession(); - this->saveChannels(); - // everything written to NVM, write current table version to persistent storage and set magic number - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION_ID, RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION); - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); + // everything written to NVM, write current table version to persistent storage and set mode + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP); #endif - this->isJoinedFlag = true; + this->activeMode = RADIOLIB_LORAWAN_MODE_ABP; return(RADIOLIB_ERR_NONE); } bool LoRaWANNode::isJoined() { - return(this->isJoinedFlag); + return(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE); } #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) @@ -524,66 +755,39 @@ int16_t LoRaWANNode::saveSession() { Module* mod = this->phyLayer->getMod(); // store session configuration (MAC commands) - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID) != this->rev) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_VERSION_ID, this->rev); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID) != this->rev) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID) != this->devNonce) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID, this->devNonce); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID) != this->devNonce) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); - uint8_t txDrRx2Dr = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4) | this->rx2.drMax; - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID) != txDrRx2Dr) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXDR_RX2DR_ID, txDrRx2Dr); - - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID) != this->txPwrCur) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_TXPWR_CUR_ID, this->txPwrCur); - - uint8_t rx1DrOffDel = (this->rx1DrOffset << 4) | (this->rxDelays[0] / 1000); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID) != rx1DrOffDel) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX1_DROFF_DEL_ID, rx1DrOffDel); - - uint8_t rx2FreqBuf[3]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID), rx2FreqBuf, 3); - uint32_t rx2Freq = LoRaWANNode::ntoh(&rx2FreqBuf[0], 3); - if(rx2Freq != uint32_t(this->rx2.freq * 10000)) { - rx2Freq = uint32_t(this->rx2.freq * 10000); - LoRaWANNode::hton(&rx2FreqBuf[0], rx2Freq, 3); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX2FREQ_ID), rx2FreqBuf, 3); - } - - uint8_t adrLimDel = (this->adrLimitExp << 4) | (this->adrDelayExp << 0); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID) != adrLimDel) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_LIM_DEL_ID, adrLimDel); - - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID) != this->nbTrans) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NBTRANS_ID, this->nbTrans); - // store all frame counters - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); - if(mod->hal->getPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often this->saveFcntUp(); // if there is, or was, any MAC command in the queue, overwrite with the current MAC queue uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); LoRaWANMacCommandQueue_t cmdTemp; memcpy(&cmdTemp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); if(this->commandsUp.numCommands > 0 || cmdTemp.numCommands > 0) { memcpy(queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FOPTS_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); } return(RADIOLIB_ERR_NONE); @@ -593,17 +797,17 @@ int16_t LoRaWANNode::saveFcntUp() { Module* mod = this->phyLayer->getMod(); uint8_t fcntBuff[30] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID), fcntBuff, 30); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, 30); // we discard the first two bits - your flash will likely be far dead by the time you reach 2^30 uplinks // the first two bytes of the remaining 30 bytes are stored straight into storage without additional wear leveling // because they hardly ever change uint8_t bits_30_22 = (uint8_t)(this->fcntUp >> 22); if(fcntBuff[0] != bits_30_22) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_30_22, 0); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_30_22, 0); uint8_t bits_22_14 = (uint8_t)(this->fcntUp >> 14); if(fcntBuff[1] != bits_22_14) - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_22_14, 1); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_22_14, 1); // the next 7 bits are stored into one of few indices // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor @@ -624,7 +828,7 @@ int16_t LoRaWANNode::saveFcntUp() { // flip the first bit of this byte to indicate that we just wrote here bits_14_7 |= (~(fcntBuff[idx] >> 7)) << 7; - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_14_7, idx); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_14_7, idx); } // equally, the last 7 bits are stored into one of many indices @@ -643,31 +847,10 @@ int16_t LoRaWANNode::saveFcntUp() { // flip the first bit of this byte to indicate that we just wrote here bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7; - mod->hal->setPersistentParameter(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); return(RADIOLIB_ERR_NONE); } - -int16_t LoRaWANNode::saveChannels() { - const uint8_t bytesPerChannel = 5; - const uint8_t numBytes = 2 * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel; - uint8_t buffer[numBytes] = { 0 }; - for(uint8_t dir = 0; dir < 2; dir++) { - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - uint8_t chBuff[bytesPerChannel] = { 0 }; - chBuff[0] = (uint8_t)this->availableChannels[dir][i].enabled << 7; - chBuff[0] |= this->availableChannels[dir][i].idx; - uint32_t freq = this->availableChannels[dir][i].freq*10000.0; - LoRaWANNode::hton(&chBuff[1], freq, 3); - chBuff[4] = this->availableChannels[dir][i].drMax << 4; - chBuff[4] |= this->availableChannels[dir][i].drMin << 0; - memcpy(&buffer[(dir * RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * bytesPerChannel) + i * bytesPerChannel], chBuff, bytesPerChannel); - } - } - Module* mod = this->phyLayer->getMod(); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FREQS_ID), buffer, numBytes); - return(RADIOLIB_ERR_NONE); -} #endif // RADIOLIB_EEPROM_UNSUPPORTED #if defined(RADIOLIB_BUILD_ARDUINO) @@ -690,6 +873,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); } + // if adhering to dutyCycle and the time since last uplink + interval has not elapsed, return an error + if(this->dutyCycleEnabled && this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA) > mod->hal->millis()) { + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + // check destination port if(port > 0xDF) { return(RADIOLIB_ERR_INVALID_PORT); @@ -716,8 +904,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); + len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; + // return(RADIOLIB_ERR_PACKET_TOO_LONG); } + if(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen)) // increase frame counter by one this->fcntUp += 1; @@ -732,14 +922,15 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // if we hit the Limit + Delay, try one of three, in order: // set TxPower to max, set DR to min, enable all defined channels if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { - - // set the maximum power supported by both the module and the band - int8_t pwrPrev = this->txPwrCur; - state = this->setTxPower(this->band->powerMax); - RADIOLIB_ASSERT(state); - - if(this->txPwrCur == pwrPrev) { - + + // if the TxPower field has some offset, remove it and switch to maximum power + if(this->txPowerCur > 0) { + this->txPowerCur = 0; + // set the maximum power supported by both the module and the band + state = this->setTxPower(this->txPowerMax); + RADIOLIB_ASSERT(state); + + } else { // failed to increase Tx power, so try to decrease the datarate if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]--; @@ -757,6 +948,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + cmd.payload[0] |= 0; // default to max Tx Power + cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + (void)execMacCommand(&cmd); + // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' this->adrFcnt += adrDelay; } @@ -766,6 +965,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); + // if dwell time is imposed, calculated expected time on air and cancel if exceeds + if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsBufSize); @@ -896,6 +1100,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf this->rxDelayStart = mod->hal->millis(); RADIOLIB_DEBUG_PRINTLN("Uplink sent <-- Rx Delay start"); + // calculate Time on Air of this uplink in milliseconds + this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; + #if !RADIOLIB_STATIC_ONLY delete[] uplinkMsg; #endif @@ -911,7 +1118,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf event->confirming = isConfirmingDown; event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; - event->power = this->txPwrCur; + event->power = this->txPowerMax - this->txPowerCur * 2; event->fcnt = this->fcntUp; event->port = port; } @@ -1115,6 +1322,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) + // TODO "NFCntDown is used for MAC communication on port 0 and when the FPort field is missing" + // so what about empty frames for ACK? Per TS008, these should be Application downlinks bool isAppDownlink = true; if(payLen <= 0) { if(this->rev == 1) { @@ -1213,26 +1422,39 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) int8_t remLen = foptsLen; uint8_t* foptsPtr = fopts; while(remLen > 0) { + uint8_t cid = *foptsPtr; + uint8_t macLen = getMacPayloadLength(cid); + if(macLen + 1 > remLen) + break; LoRaWANMacCommand_t cmd = { - .cid = *foptsPtr, + .cid = cid, .payload = { 0 }, - .len = (uint8_t)RADIOLIB_MIN((remLen - 1), 5), + .len = macLen, .repeat = 0, }; - memcpy(cmd.payload, foptsPtr + 1, cmd.len); + memcpy(cmd.payload, foptsPtr + 1, macLen); RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", cmd.cid, cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); - // try to process the mac command - // TODO how to handle incomplete commands? - size_t processedLen = execMacCommand(&cmd) + 1; + // process the MAC command + bool sendUp = execMacCommand(&cmd); + if(sendUp) { + pushMacCommand(&cmd, &this->commandsUp); + } // processing succeeded, move in the buffer to the next command - remLen -= processedLen; - foptsPtr += processedLen; - RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", processedLen, remLen); + remLen -= (macLen + 1); + foptsPtr += (macLen + 1); + RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); } + RADIOLIB_DEBUG_PRINTLN("MAC response:"); + for (int x; x < this->commandsUp.numCommands; x++) { + LoRaWANMacCommand_t cmd = this->commandsUp.commands[x]; + RADIOLIB_DEBUG_PRINTLN("[%02x] %02x %02x %02x %02x %02x (%02x)", cmd.cid, + cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); + } + // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { size_t foptsBufSize = this->commandsUp.len; @@ -1262,7 +1484,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } this->isMACPayload = true; - this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + // temporarily lift dutyCycle restrictions to allow immediate MAC response + bool prevDC = this->dutyCycleEnabled; + this->dutyCycleEnabled = false; + RADIOLIB_DEBUG_PRINTLN("Sending MAC-only uplink .. "); + state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + RADIOLIB_DEBUG_PRINTLN(" .. state: %d", state); + this->dutyCycleEnabled = prevDC; + #if !RADIOLIB_STATIC_ONLY delete[] foptsBuff; #endif @@ -1273,7 +1502,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; #endif size_t lenDown = 0; + RADIOLIB_DEBUG_PRINTLN("Receiving after MAC-only uplink .. "); state = this->downlink(strDown, &lenDown); + RADIOLIB_DEBUG_PRINTLN(" .. state: %d", state); #if !RADIOLIB_STATIC_ONLY delete[] strDown; #endif @@ -1292,7 +1523,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->confirming = isConfirmingUp; event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; - event->power = this->txPwrCur; + event->power = this->txPowerMax - this->txPowerCur * 2; event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; event->port = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)]; } @@ -1370,6 +1601,11 @@ uint32_t LoRaWANNode::getAFcntDown() { return(this->aFcntDown); } +void LoRaWANNode::resetFcntDown() { + this->nFcntDown = 0; + this->aFcntDown = 0; +} + uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { if((msg == NULL) || (len == 0)) { return(0); @@ -1401,7 +1637,8 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { int16_t LoRaWANNode::setPhyProperties() { // set the physical layer configuration - int16_t state = this->setTxPower(this->txPwrCur); + int8_t pwr = this->txPowerMax - this->txPowerCur * 2; + int16_t state = this->setTxPower(pwr); RADIOLIB_ASSERT(state); uint8_t syncWord[3] = { 0 }; @@ -1429,12 +1666,12 @@ int16_t LoRaWANNode::setPhyProperties() { } int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { - size_t num = 0; RADIOLIB_DEBUG_PRINTLN("Setting up channels"); // in case of frequency list-type band, copy the default TX channels into the available channels, with RX1 = TX if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { RADIOLIB_DEBUG_PRINTLN("Dynamic band"); + size_t num = 0; // copy the default defined channels into the first slots for(; num < 3 && this->band->txFreqs[num].enabled; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; @@ -1444,59 +1681,36 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { // if there is a cflist present, parse its frequencies into the next five slots, with datarate range copied from default channel 0 if(cfList != nullptr) { RADIOLIB_DEBUG_PRINTLN("CFList present"); + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + // datarate range for all new channels is equal to the default channels + cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; for(uint8_t i = 0; i < 5; i++, num++) { - LoRaWANChannel_t chnl; - chnl.enabled = true; - chnl.idx = num; - uint32_t freq = LoRaWANNode::ntoh(&cfList[3*i], 3); - chnl.freq = (float)freq/10000.0; - chnl.drMin = this->band->txFreqs[0].drMin; // drMin is equal for all channels - chnl.drMax = this->band->txFreqs[0].drMax; // drMax is equal for all channels - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", chnl.idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + cmd.payload[0] = num; + memcpy(&cmd.payload[1], &cfList[i*3], 3); + (void)execMacCommand(&cmd); } } for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } + } else { // RADIOLIB_LORAWAN_BAND_FIXED if(cfList != nullptr) { - uint8_t chSpan = 0; - uint8_t chNum = 0; - // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels - for(size_t chMaskCntl = 0; chMaskCntl < 5; chMaskCntl++) { - uint16_t mask = LoRaWANNode::ntoh(&cfList[2*chMaskCntl]); - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, mask); - for(size_t i = 0; i < 16; i++) { - // if we must roll over to next span, reset chNum and move to next channel span - if(chNum >= this->band->txSpans[chSpan].numChannels) { - chNum = 0; - chSpan++; - } + RADIOLIB_DEBUG_PRINTLN("CFList present"); + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = 0xFF; // same datarate and payload - if(mask & (1UL << i)) { - if(chSpan >= this->band->numTxSpans) { - RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); - return(RADIOLIB_ERR_UNKNOWN); - } - LoRaWANChannel_t chnl; - chnl.enabled = true; - chnl.idx = chMaskCntl*16 + i; - chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; - chnl.drMin = this->band->txSpans[chSpan].drMin; - chnl.drMax = this->band->txSpans[chSpan].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; - // downlink channels are dynamically calculated on each uplink in selectChannels() - RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", num, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); - num++; - } - chNum++; - } - } - for(; chNum < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; chNum++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = RADIOLIB_LORAWAN_CHANNEL_NONE; + // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels + size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span + for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { + cmd.payload[3] = chMaskCntl << 4; // NbTrans = 0 -> keep the same + memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); + (void)execMacCommand(&cmd); } } } @@ -1524,7 +1738,7 @@ int16_t LoRaWANNode::selectSubband(uint8_t idx) { } int16_t LoRaWANNode::selectSubband(uint8_t startChannel, uint8_t endChannel) { - if(this->isJoinedFlag) { + if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { RADIOLIB_DEBUG_PRINTLN("There is already an active session - cannot change subband"); return(RADIOLIB_ERR_INVALID_CHANNEL); } @@ -1554,9 +1768,9 @@ int16_t LoRaWANNode::selectSubband(uint8_t startChannel, uint8_t endChannel) { chnl.freq = this->band->txSpans[0].freqStart + chnl.idx*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = chnl; // downlink channel is dynamically calculated on each uplink in selectChannels() - RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", chNum, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum].freq); + RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", chNum, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum].freq); } return(RADIOLIB_ERR_NONE); } @@ -1685,11 +1899,11 @@ int16_t LoRaWANNode::selectChannels() { } // select a random ID & channel from the list of enabled and possible channels uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // for dynamic bands, the downlink channel is the one matched to the uplink channel - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; } else { // RADIOLIB_LORAWAN_BAND_FIXED // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels @@ -1734,16 +1948,69 @@ void LoRaWANNode::setADR(bool enable) { this->adrEnabled = enable; } +void LoRaWANNode::setDutyCycle(bool enable, uint32_t msPerHour) { + this->dutyCycleEnabled = true; + if(msPerHour <= 0) { + this->dutyCycle = this->band->dutyCycle; + } else { + this->dutyCycle = msPerHour; + } +} + +// given an airtime in milliseconds, calculate the minimum uplink interval +// to adhere to a given dutyCycle +uint32_t LoRaWANNode::dutyCycleInterval(uint32_t msPerHour, uint32_t airtime) { + if(msPerHour == 0 || airtime == 0) { + return(0); + } + uint32_t oneHourInMs = 60 * 60 * 1000; + float numPackets = msPerHour / airtime; + uint32_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems + return(delayMs); +} + +uint32_t LoRaWANNode::timeUntilUplink() { + Module* mod = this->phyLayer->getMod(); + uint32_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); + uint32_t timeRemaining = RADIOLIB_MAX(0, nextUplink - mod->hal->millis() + 1); + return(timeRemaining); +} + +void LoRaWANNode::setDwellTime(bool enable, uint32_t msPerUplink) { + this->dwellTimeEnabledUp = enable; + if(msPerUplink <= 0) { + this->dwellTimeUp = this->band->dwellTimeUp; + } else { + this->dwellTimeUp = msPerUplink; + } +} + +uint8_t LoRaWANNode::maxPayloadDwellTime() { + // configure current datarate + DataRate_t dr; + findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); + (void)this->phyLayer->setDataRate(dr); + uint8_t minPayLen = 0; + uint8_t maxPayLen = 255; + uint8_t payLen = (minPayLen + maxPayLen) / 2; + // do some binary search to find maximum allowed payload length + while(payLen != minPayLen && payLen != maxPayLen) { + if(this->phyLayer->getTimeOnAir(payLen) > this->dwellTimeUp) { + maxPayLen = payLen; + } else { + minPayLen = payLen; + } + payLen = (minPayLen + maxPayLen) / 2; + } + return(payLen - 13); // fixed 13-byte header +} + int16_t LoRaWANNode::setTxPower(int8_t txPower) { int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { // go from the highest power and lower it until we hit one supported by the module state = this->phyLayer->setOutputPower(txPower--); } - if(state == RADIOLIB_ERR_NONE) { - txPower++; - this->txPwrCur = txPower; - } return(state); } @@ -1807,6 +2074,21 @@ int16_t LoRaWANNode::configureChannel(uint8_t dir) { return(state); } +bool LoRaWANNode::sendMacCommandReq(uint8_t cid) { + bool valid = false; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { + if(MacTable[i].cid == cid) { + valid = MacTable[i].user; + } + } + if(!valid) + return(false); + + LoRaWANMacCommand_t cmd = { cid, 0, 0, 0 }; + pushMacCommand(&cmd, &this->commandsUp); + return(true); +} + int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); @@ -1819,13 +2101,17 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue) { +int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t payload[5]) { if(queue->numCommands == 0) { return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); } for(size_t index = 0; index < queue->numCommands; index++) { if(queue->commands[index].cid == cid) { + // if a pointer to a payload is supplied, copy the command's payload over + if(payload) { + memcpy(payload, queue->commands[index].payload, queue->commands[index].len); + } queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload // move all subsequent commands one forward in the queue if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { @@ -1841,39 +2127,41 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); } -size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { +bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); - if(cmd->cid >= RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY) { + Module* mod = this->phyLayer->getMod(); +#if defined(RADIOLIB_EEPROM_UNSUPPORTED) + (void)saveToEeprom; + (void)mod; +#endif + + if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { // TODO call user-provided callback for proprietary MAC commands? - return(cmd->len - 1); + return(false); } switch(cmd->cid) { - case(RADIOLIB_LORAWAN_MAC_CMD_RESET): { + case(RADIOLIB_LORAWAN_MAC_RESET): { // get the server version uint8_t srvVersion = cmd->payload[0]; RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command - deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_RESET, &this->commandsUp); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); } - return(1); + return(false); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK): { - // TODO sent by gateway as reply to node request, how to get this info to the user? - uint8_t margin = cmd->payload[0]; - uint8_t gwCnt = cmd->payload[1]; - RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); - (void)margin; - (void)gwCnt; - return(2); + case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + pushMacCommand(cmd, &this->commandsDown); + return(false); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR): { + case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { // get the ADR configuration - // TODO all these configuration should only be set if all ACKs are set, otherwise retain previous state (per spec) + // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state + // but we don't bother and try to set each individual command uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; uint8_t txPower = cmd->payload[0] & 0x0F; uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); @@ -1883,8 +2171,12 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // apply the configuration uint8_t drAck = 0; - if(drUp == 0x0F) { + if(drUp == 0x0F) { // keep the same drAck = 1; + + // replace the 'placeholder' with the current actual value for saving + cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); @@ -1898,98 +2190,158 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { if(txPower == 0x0F) { pwrAck = 1; + // replace the 'placeholder' with the current actual value for saving + cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; + } else { - int8_t pwr = this->band->powerMax - 2*txPower; + int8_t pwr = this->txPowerMax - 2*txPower; int16_t state = this->setTxPower(pwr); // only acknowledge if the requested datarate was succesfully configured - if((state == RADIOLIB_ERR_NONE) && (this->txPwrCur == pwr)) { + if(state == RADIOLIB_ERR_NONE) { pwrAck = 1; + this->txPowerCur = txPower; } } + bool isSuccessive = false; uint8_t chMaskAck = 1; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(chMaskCntl == 0) { - // if chMaskCntl == 0, apply the mask by looking at each channel bit - RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); - if(chMask & (1UL << i)) { - // if it should be enabled but is not currently defined, stop immediately - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - chMaskAck = 0; - break; + // only apply channel mask when the RFU bit is not set + // (which is set on the internal MAC command when creating new session) + if((cmd->payload[3] >> 7) == 0) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(chMaskCntl == 0) { + // if chMaskCntl == 0, apply the mask by looking at each channel bit + RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); + if(chMask & (1UL << i)) { + // if it should be enabled but is not currently defined, stop immediately + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + chMaskAck = 0; + break; + } + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } else { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; } - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - } else { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; - } - } else if(chMaskCntl == 6) { - // if chMaskCntl == 6, enable all defined channels - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } else if(chMaskCntl == 6) { + // if chMaskCntl == 6, enable all defined channels + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } } + } - - } - } else { // RADIOLIB_LORAWAN_BAND_FIXED - // delete any prior ADR responses from the uplink queue, but do not care if none is present yet - (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR, &this->commandsUp); - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); - uint8_t num = 0; - uint8_t chNum = chMaskCntl*16; - uint8_t chSpan = 0; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("chNum: %d, chSpan: %d, i: %d, mask: %d", chNum, chSpan, i, chMask & (1UL << i)); - // if we must roll over to next span, reset chNum and move to next channel span - if(chNum >= this->band->txSpans[chSpan].numChannels) { - chNum = 0; - chSpan++; + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // delete any prior ADR responses from the uplink queue, but do not care if none is present yet + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); + if(state == RADIOLIB_ERR_NONE) { + isSuccessive = true; // if we found an ADR Ans in the uplink MAC queue, this is a successive ADR MAC request } + RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); + uint8_t num = 0; + uint8_t chNum = chMaskCntl*16; + uint8_t chSpan = 0; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("chNum: %d, chSpan: %d, i: %d, mask: %d", chNum, chSpan, i, chMask & (1UL << i)); + // if we must roll over to next span, reset chNum and move to next channel span + if(chNum >= this->band->txSpans[chSpan].numChannels) { + chNum = 0; + chSpan++; + } - if(chMask & (1UL << i)) { - if(chSpan >= this->band->numTxSpans) { - RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); - return(RADIOLIB_ERR_UNKNOWN); + if(chMask & (1UL << i)) { + if(chSpan >= this->band->numTxSpans) { + RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); + return(RADIOLIB_ERR_UNKNOWN); + } + LoRaWANChannel_t chnl; + chnl.enabled = true; + chnl.idx = chMaskCntl*16 + i; + chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; + chnl.drMin = this->band->txSpans[chSpan].drMin; + chnl.drMax = this->band->txSpans[chSpan].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; + // downlink channels are dynamically calculated on each uplink in selectChannels() + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", num, chnl.idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + num++; } - LoRaWANChannel_t chnl; - chnl.enabled = true; - chnl.idx = chMaskCntl*16 + i; - chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; - chnl.drMin = this->band->txSpans[chSpan].drMin; - chnl.drMax = this->band->txSpans[chSpan].drMax; - availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; - // downlink channels are dynamically calculated on each uplink in selectChannels() - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", num, chnl.idx, availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); - num++; + chNum++; } - chNum++; } } - // TODO should we actually save the channels because the masks may have changed stuff? - // this may wear the storage quickly on more mobile devices / changing RF environment - this->nbTrans = nbTrans; + if(nbTrans == 0) { // keep the same + cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; // set current number of retransmissions for saving + } else { + this->nbTrans = nbTrans; + } + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + + // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte + if((cmd->payload[3] >> 7) == 1) { + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID) + 1, &(cmd->payload[1]), 3); + } + + // save to the single ADR MAC location + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); + + } else { + // read how many ADR masks are already stored + uint8_t macNumADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); + + // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte + if((cmd->payload[3] >> 7) == 1) { + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + macNumADR * payLen + 1, &(cmd->payload[1]), 3); + } else { + if(isSuccessive) { + // saved another ADR mask, so increase counter + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, macNumADR + 1); + } else { + // this is the first ADR mask in this downlink, so (re)set counter to 1 + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, 1); + } + } + + // save to the uplink channel location, to the macNumADR-th slot of 4 bytes + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + macNumADR * payLen, &(cmd->payload[0]), payLen); + } + } +#endif // send the reply cmd->len = 1; cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); - pushMacCommand(cmd, &this->commandsUp); - return(4); + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE): { + case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); + if(maxDutyCycle == 0) { + this->dutyCycle = this->band->dutyCycle; + } else { + this->dutyCycle = 60 * 60 * 1000 / (1 << maxDutyCycle); + } - // TODO implement this - (void)maxDutyCycle; - return(1); +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID, cmd->payload[0]); + + } +#endif + + cmd->len = 0; + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP): { // get the configuration this->rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; uint8_t rx1OffsAck = 1; @@ -2006,29 +2358,33 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID), &(cmd->payload[0]), payLen); + + } +#endif + // TODO this should be sent repeatedly until the next downlink - // send the reply cmd->len = 1; cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); RADIOLIB_DEBUG_PRINTLN("Rx param ANS: status = 0x%02x", cmd->payload[0]); - pushMacCommand(cmd, &this->commandsUp); - return(4); + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS): { + case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { // set the uplink reply cmd->len = 2; cmd->payload[1] = this->battLevel; int8_t snr = this->phyLayer->getSNR(); cmd->payload[0] = snr & 0x3F; - // push it to the uplink queue RADIOLIB_DEBUG_PRINTLN("DevStatus ANS: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); - pushMacCommand(cmd, &this->commandsUp); - return(0); + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL): { + case(RADIOLIB_LORAWAN_MAC_NEW_CHANNEL): { // get the configuration uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); @@ -2038,44 +2394,56 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); uint8_t newChAck = 0; uint8_t freqAck = 0; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - // find first empty channel and configure this as the new channel - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx = chIndex; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq = freq; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin = minDr; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax = maxDr; - - // downlink channel is identical to uplink channel - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]; - newChAck = 1; - - // check if the frequency is possible - if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq) == RADIOLIB_ERR_NONE) { - freqAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); - } - break; - } + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq = freq; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; + + // downlink channel is identical to uplink channel + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex]; + newChAck = 1; + + // check if the frequency is possible + if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { + freqAck = 1; + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } + + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax + ); #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // update saved frequencies - this->saveChannels(); + if(saveToEeprom) { + // save to uplink channels location, to the chIndex-th slot of 5 bytes + uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + RADIOLIB_DEBUG_PRINTLN("Saving channel:"); + RADIOLIB_DEBUG_HEXDUMP(&(cmd->payload[0]), payLen); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); + + } #endif // send the reply cmd->len = 1; cmd->payload[0] = (newChAck << 1) | (freqAck << 0); - pushMacCommand(cmd, &this->commandsUp); - - return(5); + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL): { + case(RADIOLIB_LORAWAN_MAC_DL_CHANNEL): { // get the configuration uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); @@ -2102,20 +2470,22 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // update saved frequencies - this->saveChannels(); -#endif + if(saveToEeprom) { + // save to downlink channels location, to the chIndex-th slot of 4 bytes + uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); - // send the reply + } +#endif + + // TODO send this repeatedly until a downlink is received cmd->len = 1; cmd->payload[0] = (freqUlAck << 1) | (freqDlAck << 0); - pushMacCommand(cmd, &this->commandsUp); - - return(4); + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP): { + case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PRINTLN("RX timing: delay = %d sec", delay); @@ -2127,62 +2497,80 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { this->rxDelays[0] = delay * 1000; this->rxDelays[1] = this->rxDelays[0] + 1000; +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID, cmd->payload[0]); + + } +#endif + // send the reply cmd->len = 0; - // TODO this should be sent repeatedly until the next downlink - pushMacCommand(cmd, &this->commandsUp); - - return(1); + // TODO send this repeatedly until a downlink is received + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP): { uint8_t dlDwell = (cmd->payload[0] & 0x20) >> 5; uint8_t ulDwell = (cmd->payload[0] & 0x10) >> 4; uint8_t maxEirpRaw = cmd->payload[0] & 0x0F; // who the f came up with this ... const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; - uint8_t maxEirp = eirpEncoding[maxEirpRaw]; - RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, dlDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, maxEirp); + this->txPowerMax = eirpEncoding[maxEirpRaw]; + RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax); - // TODO implement this - (void)dlDwell; - (void)ulDwell; - (void)maxEirp; - return(1); + this->dwellTimeEnabledUp = ulDwell ? true : false; + this->dwellTimeUp = ulDwell ? 400 : 0; + + this->dwellTimeEnabledDn = dlDwell ? true : false; + this->dwellTimeDn = dlDwell ? 400 : 0; + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID, cmd->payload[0]); + + } +#endif + + cmd->len = 0; + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_REKEY): { + case(RADIOLIB_LORAWAN_MAC_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command - deleteMacCommand(RADIOLIB_LORAWAN_MAC_CMD_REKEY, &this->commandsUp); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); } - return(1); + return(false); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; this->adrDelayExp = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); - return(1); +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID, cmd->payload[0]); + + } +#endif + + cmd->len = 0; + return(true); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME): { - // TODO implement this - sent by gateway as reply to node request - uint32_t gpsEpoch = LoRaWANNode::ntoh(&cmd->payload[0]); - uint8_t fraction = cmd->payload[4]; - RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)fraction/256.0f); - (void)gpsEpoch; - (void)fraction; - return(5); + case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + pushMacCommand(cmd, &this->commandsDown); + return(false); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_FORCE_REJOIN): { + case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { // TODO implement this uint16_t rejoinReq = LoRaWANNode::ntoh(&cmd->payload[0]); uint8_t period = (rejoinReq & 0x3800) >> 11; @@ -2194,23 +2582,72 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { (void)maxRetries; (void)rejoinType; (void)dr; - return(2); + return(false); } break; - case(RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP): { // TODO implement this uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); + +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + if(saveToEeprom) { + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID, cmd->payload[0]); + + } +#endif + + cmd->len = 0; + cmd->payload[0] = (1 << 1) | 1; + (void)maxTime; (void)maxCount; - return(0); + return(true); } break; } - return(0); + return(false); +} + +uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { + for (LoRaWANMacSpec_t entry : MacTable) { + if (entry.cid == cid) { + return entry.lenDn; + } + } + // no idea about the length + return 0; +} + +bool LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { + uint8_t payload[5]; + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); + if(state != RADIOLIB_ERR_NONE) + return false; + + *margin = payload[0]; + *gwCnt = payload[1]; + RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); + return(true); } +bool LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { + uint8_t payload[5]; + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); + if(state != RADIOLIB_ERR_NONE) + return false; + + *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); + *fraction = payload[4]; + RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f); + + uint32_t unixOffset = 315964800; + *gpsEpoch += unixOffset; + return(true); +} + + // The following function enables LMAC, a CSMA scheme for LoRa as specified // in the LoRa Alliance Technical Recommendation #13. // A user may enable CSMA to provide frames an additional layer of protection from interference. diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 47be7cb354..81e87dbd63 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -5,8 +5,15 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../../utils/Cryptography.h" -// version of NVM table layout (NOT the LoRaWAN version) -#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_TABLE_VERSION (0x01) +// activation mode +#define RADIOLIB_LORAWAN_MODE_OTAA (0x01AA) +#define RADIOLIB_LORAWAN_MODE_ABP (0x0AB9) +#define RADIOLIB_LORAWAN_MODE_NONE (0x0000) + +// operation mode +#define RADIOLIB_LORAWAN_CLASS_A (0x00) +#define RADIOLIB_LORAWAN_CLASS_B (0x01) +#define RADIOLIB_LORAWAN_CLASS_C (0x02) // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) @@ -77,7 +84,6 @@ // recommended default settings #define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) #define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000) -#define RADIOLIB_LORAWAN_RX_WINDOW_LEN_MS (500) #define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) @@ -87,6 +93,8 @@ #define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) #define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000) #define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2) +#define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks +#define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented // join request message layout #define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) @@ -155,32 +163,61 @@ #define RADIOLIB_LORAWAN_MAGIC (0x39EA) // MAC commands -#define RADIOLIB_LORAWAN_MAC_CMD_RESET (0x01) -#define RADIOLIB_LORAWAN_MAC_CMD_LINK_CHECK (0x02) -#define RADIOLIB_LORAWAN_MAC_CMD_LINK_ADR (0x03) -#define RADIOLIB_LORAWAN_MAC_CMD_DUTY_CYCLE (0x04) -#define RADIOLIB_LORAWAN_MAC_CMD_RX_PARAM_SETUP (0x05) -#define RADIOLIB_LORAWAN_MAC_CMD_DEV_STATUS (0x06) -#define RADIOLIB_LORAWAN_MAC_CMD_NEW_CHANNEL (0x07) -#define RADIOLIB_LORAWAN_MAC_CMD_RX_TIMING_SETUP (0x08) -#define RADIOLIB_LORAWAN_MAC_CMD_TX_PARAM_SETUP (0x09) -#define RADIOLIB_LORAWAN_MAC_CMD_DL_CHANNEL (0x0A) -#define RADIOLIB_LORAWAN_MAC_CMD_REKEY (0x0B) -#define RADIOLIB_LORAWAN_MAC_CMD_ADR_PARAM_SETUP (0x0C) -#define RADIOLIB_LORAWAN_MAC_CMD_DEVICE_TIME (0x0D) -#define RADIOLIB_LORAWAN_MAC_CMD_FORCE_REJOIN (0x0E) -#define RADIOLIB_LORAWAN_MAC_CMD_REJOIN_PARAM_SETUP (0x0F) -#define RADIOLIB_LORAWAN_MAC_CMD_PROPRIETARY (0x80) +#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) + +#define RADIOLIB_LORAWAN_MAC_RESET (0x01) +#define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02) +#define RADIOLIB_LORAWAN_MAC_LINK_ADR (0x03) +#define RADIOLIB_LORAWAN_MAC_DUTY_CYCLE (0x04) +#define RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP (0x05) +#define RADIOLIB_LORAWAN_MAC_DEV_STATUS (0x06) +#define RADIOLIB_LORAWAN_MAC_NEW_CHANNEL (0x07) +#define RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP (0x08) +#define RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP (0x09) +#define RADIOLIB_LORAWAN_MAC_DL_CHANNEL (0x0A) +#define RADIOLIB_LORAWAN_MAC_REKEY (0x0B) +#define RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP (0x0C) +#define RADIOLIB_LORAWAN_MAC_DEVICE_TIME (0x0D) +#define RADIOLIB_LORAWAN_MAC_FORCE_REJOIN (0x0E) +#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) +#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) // unused frame counter value #define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) // the length of internal MAC command queue - hopefully this is enough for most use cases -#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (8) +#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) // the maximum number of simultaneously available channels #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) +struct LoRaWANMacSpec_t { + const uint8_t cid; + const uint8_t lenDn; + const uint8_t lenUp; + const bool user; // whether this MAC command can be issued by a user or not +}; + +const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { + { 0x00, 0, 0, false }, // not an actual MAC command, exists for offsetting + { 0x01, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_RESET + { 0x02, 2, 0, true }, // RADIOLIB_LORAWAN_MAC_LINK_CHECK + { 0x03, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_LINK_ADR + { 0x04, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_DUTY_CYCLE + { 0x05, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP + { 0x06, 0, 2, false }, // RADIOLIB_LORAWAN_MAC_DEV_STATUS + { 0x07, 5, 1, false }, // RADIOLIB_LORAWAN_MAC_NEW_CHANNEL + { 0x08, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP + { 0x09, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP + { 0x0A, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_DL_CHANNEL + { 0x0B, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REKEY + { 0x0C, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP + { 0x0D, 5, 0, true }, // RADIOLIB_LORAWAN_MAC_DEVICE_TIME + { 0x0E, 2, 0, false }, // RADIOLIB_LORAWAN_MAC_FORCE_REJOIN + { 0x0F, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP + { 0x80, 5, 0, true } // RADIOLIB_LORAWAN_MAC_PROPRIETARY +}; + /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. @@ -251,6 +288,13 @@ struct LoRaWANBand_t { /*! \brief Number of power steps in this band */ int8_t powerNumSteps; + /*! \brief Number of milliseconds per hour of allowed Time-on-Air */ + uint32_t dutyCycle; + + /*! \brief Maximum dwell time per message in milliseconds */ + uint32_t dwellTimeUp; + uint32_t dwellTimeDn; + /*! \brief A set of default uplink (TX) channels for frequency-type bands */ LoRaWANChannel_t txFreqs[3]; @@ -371,7 +415,8 @@ class LoRaWANNode { /*! \brief Restore session by loading information from persistent storage. - \returns \ref status_codes + \returns \ref status_codes in case of error, + else LoRaWAN session mode (0 = no active session, 0xAA / 170 = OTAA, 0xAB / 171 = ABP) */ int16_t restore(); #endif @@ -413,6 +458,15 @@ class LoRaWANNode { */ int16_t saveSession(); + /*! + \brief Add a MAC command to the uplink queue. + Only LinkCheck and DeviceTime are available to the user. + Other commands are ignored; duplicate MAC commands are discarded. + \param cid ID of the MAC command + \returns Whether or not the MAC command was added to the queue. + */ + bool sendMacCommandReq(uint8_t cid); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Send a message to the server. @@ -533,6 +587,12 @@ class LoRaWANNode { /*! \brief Returns the last application downlink's frame counter */ uint32_t getAFcntDown(); + /*! \brief Reset the downlink frame counters (application and network) + This is unsafe and can possibly allow replay attacks using downlinks. + It mainly exists as part of the TS008 Specification Verification protocol. + */ + void resetFcntDown(); + /*! \brief Set uplink datarate. This should not be used when ADR is enabled. \param dr Datarate to use for uplinks. @@ -546,6 +606,41 @@ class LoRaWANNode { */ void setADR(bool enable = true); + /*! + \brief Toggle adherence to dutyCycle limits to on or off. + \param enable Whether to adhere to dutyCycle limits or not (default true). + \param msPerHour The maximum allowed Time-on-Air per hour in milliseconds + (default 0 = maximum allowed for configured band). + */ + void setDutyCycle(bool enable = true, uint32_t msPerHour = 0); + + /*! + \brief Calculate the minimum interval to adhere to a certain dutyCycle. + This interval is based on the ToA of one uplink and does not actually keep track of total airtime. + \param msPerHour The maximum allowed dutycyle (in milliseconds per hour). + \param airtime The airtime of the uplink. + \returns Required interval (delay) in milliseconds between consecutive uplinks. + */ + uint32_t dutyCycleInterval(uint32_t msPerHour, uint32_t airtime); + + /*! \brief Returns time in milliseconds until next uplink is available under dutyCycle limits */ + uint32_t timeUntilUplink(); + + /*! + \brief Toggle adherence to dwellTime limits to on or off. + \param enable Whether to adhere to dwellTime limits or not (default true). + \param msPerHour The maximum allowed Time-on-Air per uplink in milliseconds + (default 0 = maximum allowed for configured band). + */ + void setDwellTime(bool enable, uint32_t msPerUplink = 0); + + /*! + \brief Returns the maximum payload given the currently present dwelltime limits. + WARNING: the addition of MAC commands may cause uplink errors; + if you want to be sure that your payload fits within dwelltime limits, subtract 16 from the result! + */ + uint8_t maxPayloadDwellTime(); + /*! \brief Configure TX power of the radio module. \param txPower Output power during TX mode to be set in dBm. @@ -578,12 +673,35 @@ class LoRaWANNode { */ void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); + /*! + \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. + Returns 'true' if a network response was succesfully parsed. + Returns 'false' if there was no network response / parsing failed. + \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. + \param gwCnt Number of gateways that received the LinkCheckReq. + \returns Whether the parameters where succesfully parsed. + */ + bool getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt); + + /*! + \brief Returns the network time after requesting a DeviceTime MAC command. + Returns 'true' if a network response was succesfully parsed. + Returns 'false' if there was no network response / parsing failed. + \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) + \param fraction Fractional-second, in 1/256-second steps + \param returnUnix If true, returns Unix timestamp instead of GPS (default true) + \returns Whether the parameters where succesfully parsed. + */ + bool getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); + #if !RADIOLIB_GODMODE private: #endif PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; + void beginCommon(); + LoRaWANMacCommandQueue_t commandsUp = { .numCommands = 0, .len = 0, @@ -613,7 +731,8 @@ class LoRaWANNode { uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; uint8_t nbTrans = 1; // Number of allowed frame retransmissions - uint8_t txPwrCur = 0; + uint8_t txPowerCur = 0; + uint8_t txPowerMax = 0; uint32_t fcntUp = 0; uint32_t aFcntDown = 0; uint32_t nFcntDown = 0; @@ -624,11 +743,21 @@ class LoRaWANNode { // whether the current configured channel is in FSK mode bool FSK = false; - // flag that shows whether the device is joined and there is an ongoing session - bool isJoinedFlag = false; + // flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA) + uint16_t activeMode = 0; // ADR is enabled by default bool adrEnabled = true; + + // duty cycle is set upon initialization and activated in regions that impose this + bool dutyCycleEnabled = false; + uint32_t dutyCycle = 0; + + // dwell time is set upon initialization and activated in regions that impose this + bool dwellTimeEnabledUp = false; + uint16_t dwellTimeUp = 0; + bool dwellTimeEnabledDn = false; + uint16_t dwellTimeDn = 0; // enable/disable CSMA for LoRaWAN bool enableCSMA; @@ -653,6 +782,9 @@ class LoRaWANNode { // LoRaWAN revision (1.0 vs 1.1) uint8_t rev = 0; + // Time on Air of last uplink + uint32_t lastToA = 0; + // timestamp to measure the RX1/2 delay (from uplink end) uint32_t rxDelayStart = 0; @@ -714,9 +846,6 @@ class LoRaWANNode { // configure channel based on cached data rate ID and frequency int16_t configureChannel(uint8_t dir); - // save all available channels to persistent storage - int16_t saveChannels(); - // restore all available channels from persistent storage int16_t restoreChannels(); @@ -724,10 +853,14 @@ class LoRaWANNode { int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); // delete a specific MAC command from queue, indicated by the command ID - int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue); + // if a payload pointer is supplied, this returns the payload of the MAC command + int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t payload[5] = NULL); // execute mac command, return the number of processed bytes for sequential processing - size_t execMacCommand(LoRaWANMacCommand_t* cmd); + bool execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom = true); + + // get the payload length for a specific MAC command + uint8_t getMacPayloadLength(uint8_t cid); // Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013). void performCSMA(); diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 7b0e04cf09..54580b0ee2 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -7,6 +7,9 @@ const LoRaWANBand_t EU868 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { { .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5}, @@ -49,6 +52,9 @@ const LoRaWANBand_t US915 = { .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, + .dutyCycle = 0, + .dwellTimeUp = 400, + .dwellTimeDn = 0, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -112,6 +118,9 @@ const LoRaWANBand_t CN780 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, + .dutyCycle = 3600, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { { .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5}, @@ -154,6 +163,9 @@ const LoRaWANBand_t EU433 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, + .dutyCycle = 36000, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { { .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5}, @@ -196,6 +208,9 @@ const LoRaWANBand_t AU915 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -259,6 +274,9 @@ const LoRaWANBand_t CN500 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, .powerNumSteps = 7, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -315,6 +333,9 @@ const LoRaWANBand_t AS923 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = 400, + .dwellTimeDn = 400, .txFreqs = { { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, @@ -357,6 +378,9 @@ const LoRaWANBand_t KR920 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, .powerNumSteps = 7, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { { .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5}, @@ -399,6 +423,9 @@ const LoRaWANBand_t IN865 = { .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, .powerNumSteps = 10, + .dutyCycle = 0, + .dwellTimeUp = 0, + .dwellTimeDn = 0, .txFreqs = { { .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5}, From 853c1731ca241b7a9345e1ef3fbe4c7babc693aa Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 5 Jan 2024 11:36:01 +0100 Subject: [PATCH 0851/1848] [LoRaWAN] Fix warnings --- src/protocols/LoRaWAN/LoRaWAN.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e7217f4e96..49c90a494a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -307,7 +307,7 @@ int16_t LoRaWANNode::restoreChannels() { #endif void LoRaWANNode::beginCommon() { - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); @@ -1449,11 +1449,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } RADIOLIB_DEBUG_PRINTLN("MAC response:"); - for (int x; x < this->commandsUp.numCommands; x++) { - LoRaWANMacCommand_t cmd = this->commandsUp.commands[x]; - RADIOLIB_DEBUG_PRINTLN("[%02x] %02x %02x %02x %02x %02x (%02x)", cmd.cid, - cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); - } + for (int i = 0; i < this->commandsUp.numCommands; i++) { + RADIOLIB_DEBUG_HEXDUMP(&this->commandsUp[i].cid, sizeof(LoRaWANMacCommand_t)); + } // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { @@ -1972,8 +1970,10 @@ uint32_t LoRaWANNode::dutyCycleInterval(uint32_t msPerHour, uint32_t airtime) { uint32_t LoRaWANNode::timeUntilUplink() { Module* mod = this->phyLayer->getMod(); uint32_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); - uint32_t timeRemaining = RADIOLIB_MAX(0, nextUplink - mod->hal->millis() + 1); - return(timeRemaining); + if(mod->hal->millis() > nextUplink){ + return(0); + } + return(nextUplink - mod->hal->millis() + 1); } void LoRaWANNode::setDwellTime(bool enable, uint32_t msPerUplink) { From 00264f48a90ad82a37887b129d63154e3f631a17 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 5 Jan 2024 11:49:59 +0100 Subject: [PATCH 0852/1848] [HAL] Fix a comment --- src/Hal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hal.h b/src/Hal.h index 20d858ff72..fbc8d5f757 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -71,7 +71,7 @@ static const uint32_t RadioLibPersistentParamTable[] = { 0x70, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID 0x72, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID 0x74, // RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID - 0xA0, // RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID - NOTE change upon ADR Ack Req + 0xA0, // RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID 0xA4, // RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID 0xA5, // RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID 0xA9, // RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID From f7730463bd40d03547751875a02feed4229e93c0 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 5 Jan 2024 13:41:00 +0100 Subject: [PATCH 0853/1848] [LoRaWAN] Fix ADR bug if not enabled --- src/protocols/LoRaWAN/LoRaWAN.cpp | 78 ++++++++++++++++--------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 49c90a494a..43fe0514a0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -912,52 +912,54 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // increase frame counter by one this->fcntUp += 1; - // check if we need to do ADR stuff - uint32_t adrLimit = 0x01 << this->adrLimitExp; - uint32_t adrDelay = 0x01 << this->adrDelayExp; bool adrAckReq = false; - if((this->fcntUp - this->adrFcnt) >= adrLimit) { - adrAckReq = true; - } - // if we hit the Limit + Delay, try one of three, in order: - // set TxPower to max, set DR to min, enable all defined channels - if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { - - // if the TxPower field has some offset, remove it and switch to maximum power - if(this->txPowerCur > 0) { - this->txPowerCur = 0; - // set the maximum power supported by both the module and the band - state = this->setTxPower(this->txPowerMax); - RADIOLIB_ASSERT(state); - - } else { - // failed to increase Tx power, so try to decrease the datarate - if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]--; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]--; + if(this->adrEnabled) { + // check if we need to do ADR stuff + uint32_t adrLimit = 0x01 << this->adrLimitExp; + uint32_t adrDelay = 0x01 << this->adrDelayExp; + if((this->fcntUp - this->adrFcnt) >= adrLimit) { + adrAckReq = true; + } + // if we hit the Limit + Delay, try one of three, in order: + // set TxPower to max, set DR to min, enable all defined channels + if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { + + // if the TxPower field has some offset, remove it and switch to maximum power + if(this->txPowerCur > 0) { + this->txPowerCur = 0; + // set the maximum power supported by both the module and the band + state = this->setTxPower(this->txPowerMax); + RADIOLIB_ASSERT(state); + } else { + // failed to increase Tx power, so try to decrease the datarate + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]--; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]--; + } else { - // failed to decrease datarate, so enable all available channels - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled = true; + // failed to decrease datarate, so enable all available channels + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled = true; + } } } - } - } + } - LoRaWANMacCommand_t cmd; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); - cmd.payload[0] |= 0; // default to max Tx Power - cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored - (void)execMacCommand(&cmd); + LoRaWANMacCommand_t cmd; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + cmd.payload[0] |= 0; // default to max Tx Power + cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + (void)execMacCommand(&cmd); - // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' - this->adrFcnt += adrDelay; + // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' + this->adrFcnt += adrDelay; + } } // configure for uplink From 2da09b5adcd67297dacd33db94e40506902bda2c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 6 Jan 2024 15:03:55 +0100 Subject: [PATCH 0854/1848] [LoRaWAN] Convert setDatarate() and setTxPower() to internal MAC; improve ADR --- .../LoRaWAN_End_Device_Reference.ino | 4 + src/protocols/LoRaWAN/LoRaWAN.cpp | 171 ++++++++++++------ src/protocols/LoRaWAN/LoRaWAN.h | 9 +- 3 files changed, 122 insertions(+), 62 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 52d5904f26..2d8c84cf10 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -129,6 +129,10 @@ void setup() { // set a fixed datarate node.setDatarate(5); + // in order to save the datarate persistent across reboot/deepsleep, use the following: + /* + node.setDatarate(5, true); + */ // enable CSMA // this tries to minimize packet loss by searching for a free channel diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 43fe0514a0..56fd5b6394 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -151,7 +151,7 @@ int16_t LoRaWANNode::restore() { RADIOLIB_ASSERT(state); // get MAC state - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); @@ -260,7 +260,7 @@ int16_t LoRaWANNode::restoreChannels() { uint8_t bufferUp[numBytesUp] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), bufferUp, numBytesUp); - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { @@ -276,9 +276,9 @@ int16_t LoRaWANNode::restoreChannels() { mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID), bufferDn, numBytesDn); cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; memcpy(cmd.payload, &bufferDn[i * cmd.len], cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes (void)execMacCommand(&cmd, false); @@ -290,7 +290,7 @@ int16_t LoRaWANNode::restoreChannels() { uint8_t buffer[numBytes] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; @@ -552,7 +552,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; cmd.payload[0] = dlSettings & 0x7F; @@ -921,42 +921,54 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf adrAckReq = true; } // if we hit the Limit + Delay, try one of three, in order: - // set TxPower to max, set DR to min, enable all defined channels + // set TxPower to max, set DR to min, enable all default channels if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { - - // if the TxPower field has some offset, remove it and switch to maximum power - if(this->txPowerCur > 0) { - this->txPowerCur = 0; - // set the maximum power supported by both the module and the band - state = this->setTxPower(this->txPowerMax); - RADIOLIB_ASSERT(state); - - } else { - // failed to increase Tx power, so try to decrease the datarate - if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].drMin) { - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]--; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]--; - } else { - - // failed to decrease datarate, so enable all available channels - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled = true; + uint8_t adrStage = 1; + while(adrStage != 0) { + switch(adrStage) { + case(1): { + // if the TxPower field has some offset, remove it and switch to maximum power + if(this->txPowerCur > 0) { + // set the maximum power supported by both the module and the band + state = this->setTxPower(this->txPowerMax, true); + if(state == RADIOLIB_ERR_NONE) { + this->txPowerCur = 0; + adrStage = 0; // successfully did some ADR stuff + } + } + if(adrStage == 1) { // if nothing succeeded, proceed to stage 2 + adrStage = 2; + } } - } + break; + case(2): { + // try to decrease the datarate + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { + if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1, true) == RADIOLIB_ERR_NONE) { + adrStage = 0; // successfully did some ADR stuff + } + } + if(adrStage == 2) { // if nothing succeeded, proceed to stage 3 + adrStage = 3; + } + } + break; + case(3): { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannels(nullptr); // revert to default frequencies + } else { + // if a subband was selected by user, go back to its default state + // hopefully it'll help something, but probably not; at least we tried.. + if(this->selectedSubband >= 0) { + this->selectSubband(this->selectedSubband); + } + } + adrStage = 0; // nothing else to do, so end the cycle + } + break; } - } - LoRaWANMacCommand_t cmd; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); - cmd.payload[0] |= 0; // default to max Tx Power - cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored - (void)execMacCommand(&cmd); - // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' this->adrFcnt += adrDelay; } @@ -1452,7 +1464,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) RADIOLIB_DEBUG_PRINTLN("MAC response:"); for (int i = 0; i < this->commandsUp.numCommands; i++) { - RADIOLIB_DEBUG_HEXDUMP(&this->commandsUp[i].cid, sizeof(LoRaWANMacCommand_t)); + RADIOLIB_DEBUG_HEXDUMP(&(this->commandsUp.commands[i].cid), sizeof(LoRaWANMacCommand_t)); } // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink @@ -1638,7 +1650,11 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { int16_t LoRaWANNode::setPhyProperties() { // set the physical layer configuration int8_t pwr = this->txPowerMax - this->txPowerCur * 2; - int16_t state = this->setTxPower(pwr); + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(pwr--); + } RADIOLIB_ASSERT(state); uint8_t syncWord[3] = { 0 }; @@ -1681,7 +1697,7 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { // if there is a cflist present, parse its frequencies into the next five slots, with datarate range copied from default channel 0 if(cfList != nullptr) { RADIOLIB_DEBUG_PRINTLN("CFList present"); - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; // datarate range for all new channels is equal to the default channels @@ -1700,7 +1716,7 @@ int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { } else { // RADIOLIB_LORAWAN_BAND_FIXED if(cfList != nullptr) { RADIOLIB_DEBUG_PRINTLN("CFList present"); - LoRaWANMacCommand_t cmd; + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; cmd.payload[0] = 0xFF; // same datarate and payload @@ -1746,6 +1762,7 @@ int16_t LoRaWANNode::selectSubband(uint8_t startChannel, uint8_t endChannel) { RADIOLIB_DEBUG_PRINTLN("This is a dynamic band plan which does not support subbands"); return(RADIOLIB_ERR_INVALID_CHANNEL); } + this->selectedSubband = startChannel % 8; // save selected subband - assumed a block of 8 channels uint8_t numChannels = endChannel - startChannel + 1; if(startChannel > this->band->txSpans[0].numChannels) { @@ -1923,24 +1940,37 @@ int16_t LoRaWANNode::selectChannels() { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::setDatarate(uint8_t drUp) { - // find the minimum and maximum available datarates by checking the enabled uplink channels - uint8_t drMin = RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES; - uint8_t drMax = 0; +int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { + // scan through all enabled channels and check if the requested datarate is available + bool isValidDR = false; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - drMin = RADIOLIB_MIN(drMin, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin); - drMax = RADIOLIB_MAX(drMax, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax); + LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); + if(chnl->enabled) { + if(drUp > chnl->drMin && drUp < chnl->drMax) { + isValidDR = true; + break; + } } } - if((drUp < drMin) || (drUp > drMax)) { - RADIOLIB_DEBUG_PRINTLN("Cannot configure DR %d (min: %d, max: %d)", drUp, drMin, drMax); + if(!isValidDR) { + RADIOLIB_DEBUG_PRINTLN("No defined channel allows datarate %d", drUp); return(RADIOLIB_ERR_DATA_RATE_INVALID); } - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; - - RADIOLIB_DEBUG_PRINTLN("Configured DR up = %d", drUp); + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = (drUp << 4); + cmd.payload[0] |= 0x0F; // keep Tx Power the same + cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] |= 0; // keep NbTrans the same + (void)execMacCommand(&cmd, saveToEeprom); + + // check if ACK is set for Tx Power + if((cmd.payload[0] >> 1) != 1) { + return(RADIOLIB_ERR_DATA_RATE_INVALID); + } + return(RADIOLIB_ERR_NONE); } @@ -2007,13 +2037,31 @@ uint8_t LoRaWANNode::maxPayloadDwellTime() { return(payLen - 13); // fixed 13-byte header } -int16_t LoRaWANNode::setTxPower(int8_t txPower) { - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(txPower--); +int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { + // only allow values within the band's (or MAC state) maximum + if(txPower > this->txPowerMax) { + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } - return(state); + // Tx Power is set in steps of two + // the selected value is rounded down to nearest multiple of two away from txPowerMax + // e.g. on EU868, max is 16; if 13 is selected then we set to 12 + uint8_t txPowerNew = (this->txPowerMax - txPower) / 2 + 1; + + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = 0xF0; // keep datarate the same + cmd.payload[0] |= txPowerNew; // set the Tx Power + cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] |= 0; // keep NbTrans the same + (void)execMacCommand(&cmd, saveToEeprom); + + // check if ACK is set for Tx Power + if((cmd.payload[0] >> 2) != 1) { + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { @@ -2197,13 +2245,16 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else { int8_t pwr = this->txPowerMax - 2*txPower; - int16_t state = this->setTxPower(pwr); + int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + // go from the highest power and lower it until we hit one supported by the module + state = this->phyLayer->setOutputPower(pwr--); + } // only acknowledge if the requested datarate was succesfully configured if(state == RADIOLIB_ERR_NONE) { pwrAck = 1; this->txPowerCur = txPower; } - } bool isSuccessive = false; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 81e87dbd63..4387070d07 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -596,9 +596,10 @@ class LoRaWANNode { /*! \brief Set uplink datarate. This should not be used when ADR is enabled. \param dr Datarate to use for uplinks. + \param saveToEeprom Whether to save this setting to EEPROM or not (default false). \returns \ref status_codes */ - int16_t setDatarate(uint8_t drUp); + int16_t setDatarate(uint8_t drUp, bool saveToEeprom = false); /*! \brief Toggle ADR to on or off. @@ -644,9 +645,10 @@ class LoRaWANNode { /*! \brief Configure TX power of the radio module. \param txPower Output power during TX mode to be set in dBm. + \param saveToEeprom Whether to save this setting to EEPROM or not (default false). \returns \ref status_codes */ - int16_t setTxPower(int8_t txPower); + int16_t setTxPower(int8_t txPower, bool saveToEeprom = false); /*! \brief Select a single subband (8 channels) for fixed bands such as US915. @@ -800,6 +802,9 @@ class LoRaWANNode { // indicates whether an uplink has MAC commands as payload bool isMACPayload = false; + // save the selected subband in case this must be restored in ADR control + int8_t selectedSubband = -1; + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) /*! \brief Save the current uplink frame counter. From 7c676f939373c5c8505c5707897fc15a6cf9ccb5 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 8 Jan 2024 22:33:34 +0100 Subject: [PATCH 0855/1848] [LoRaWAN] Implement requested changes --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 2 +- .../LoRaWAN_End_Device_ABP.ino | 2 +- .../LoRaWAN_End_Device_Persistent.ino | 4 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 100 +++++++----------- src/protocols/LoRaWAN/LoRaWAN.h | 51 ++++----- src/protocols/LoRaWAN/LoRaWANBands.cpp | 6 +- 6 files changed, 72 insertions(+), 93 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index c2ea337fc5..732da594ae 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -157,7 +157,7 @@ void loop() { // wait before sending another packet uint32_t minimumDelay = 60000; // try to send once every minute uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows delay(delayMs); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index c2bd5ff130..5ac9261f12 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -165,7 +165,7 @@ void loop() { // wait before sending another packet uint32_t minimumDelay = 60000; // try to send once every minute uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows delay(delayMs); } diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino index 983a82a08a..672506c6bd 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino @@ -77,7 +77,7 @@ void setup() { if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); Serial.print(F("Restored an ")); - if(state == RADIOLIB_LORAWAN_MODE_OTAA) + if(state == RADIOLIB_LORAWAN_MODE_OTAA) Serial.println(F("OTAA session.")); else { Serial.println(F("ABP session.")); @@ -142,7 +142,7 @@ void loop() { // make sure to send the radio to sleep as well using radio.sleep() uint32_t minimumDelay = 60000; // try to send once every minute uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows delay(delayMs); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 56fd5b6394..2af2ae8b23 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -28,39 +28,6 @@ uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_ return(dr); } -uint16_t checkSum16(uint32_t key) { - uint8_t bufLen = 2; - uint16_t buf16[bufLen]; - memcpy(buf16, &key, bufLen); - uint16_t checkSum = 0; - for(int i = 0; i < bufLen; i++) { - checkSum ^= buf16[i]; - } - return(checkSum); -} - -uint16_t checkSum16(uint64_t key) { - uint8_t bufLen = 4; - uint16_t buf16[bufLen]; - memcpy(buf16, &key, bufLen); - uint16_t checkSum = 0; - for(int i = 0; i < bufLen; i++) { - checkSum ^= buf16[i]; - } - return(checkSum); -} - -uint16_t checkSum16(uint8_t *key, uint8_t keyLen) { - uint8_t bufLen = keyLen / 2; - uint16_t buf16[bufLen]; - memcpy(buf16, key, bufLen); - uint16_t checkSum = 0; - for(int i = 0; i < bufLen; i++) { - checkSum ^= buf16[i]; - } - return(checkSum); -} - LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { this->phyLayer = phy; this->band = band; @@ -395,8 +362,8 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) uint16_t checkSum = 0; - checkSum ^= checkSum16(joinEUI); - checkSum ^= checkSum16(devEUI); + checkSum ^= checkSum16((uint8_t*)joinEUI, 8); + checkSum ^= checkSum16((uint8_t*)devEUI, 8); checkSum ^= checkSum16(nwkKey, 16); checkSum ^= checkSum16(appKey, 16); @@ -666,13 +633,11 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // check if we actually need to restart from a clean session uint16_t checkSum = 0; - checkSum ^= checkSum16(addr); + checkSum ^= checkSum16((uint8_t*)addr, 4); checkSum ^= checkSum16(nwkSKey, 16); checkSum ^= checkSum16(appSKey, 16); - if(fNwkSIntKey) - checkSum ^= checkSum16(fNwkSIntKey, 16); - if(sNwkSIntKey) - checkSum ^= checkSum16(sNwkSIntKey, 16); + if(fNwkSIntKey) { checkSum ^= checkSum16(fNwkSIntKey, 16); } + if(sNwkSIntKey) { checkSum ^= checkSum16(sNwkSIntKey, 16); } bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; @@ -904,10 +869,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { - len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; - // return(RADIOLIB_ERR_PACKET_TOO_LONG); + // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; + return(RADIOLIB_ERR_PACKET_TOO_LONG); } - if(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen)) // increase frame counter by one this->fcntUp += 1; @@ -2575,10 +2539,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax); this->dwellTimeEnabledUp = ulDwell ? true : false; - this->dwellTimeUp = ulDwell ? 400 : 0; + this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; this->dwellTimeEnabledDn = dlDwell ? true : false; - this->dwellTimeDn = dlDwell ? 400 : 0; + this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) if(saveToEeprom) { @@ -2673,31 +2637,32 @@ uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { return 0; } -bool LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { +int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { uint8_t payload[5]; int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); - if(state != RADIOLIB_ERR_NONE) - return false; + RADIOLIB_ASSERT(state); - *margin = payload[0]; - *gwCnt = payload[1]; - RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); - return(true); + if(margin) { *margin = payload[0]; } + if(gwCnt) { *gwCnt = payload[1]; } + // RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); + return(RADIOLIB_ERR_NONE); } -bool LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { +int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { uint8_t payload[5]; int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); - if(state != RADIOLIB_ERR_NONE) - return false; - - *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); - *fraction = payload[4]; - RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f); + RADIOLIB_ASSERT(state); - uint32_t unixOffset = 315964800; - *gpsEpoch += unixOffset; - return(true); + if(gpsEpoch) { + *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); + if(returnUnix) { + uint32_t unixOffset = 315964800; + *gpsEpoch += unixOffset; + } + } + if(fraction) { *fraction = payload[4]; } + // RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f); + return(RADIOLIB_ERR_NONE); } @@ -2786,6 +2751,17 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out } } +uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint8_t keyLen) { + uint16_t buf16[RADIOLIB_AES128_KEY_SIZE/2]; + uint8_t bufLen = keyLen / 2; + memcpy(buf16, key, bufLen); + uint16_t checkSum = 0; + for(int i = 0; i < bufLen; i++) { + checkSum ^= buf16[i]; + } + return(checkSum); +} + template T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { uint8_t* buffPtr = buff; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 4387070d07..de4b3ea0ac 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -159,9 +159,6 @@ #define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) #define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) -// magic word saved in persistent memory upon activation -#define RADIOLIB_LORAWAN_MAGIC (0x39EA) - // MAC commands #define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) @@ -191,6 +188,9 @@ // the maximum number of simultaneously available channels #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) +// maximum allowed dwell time on bands that implement dwell time limitations +#define RADIOLIB_LORAWAN_DWELL_TIME (400) + struct LoRaWANMacSpec_t { const uint8_t cid; const uint8_t lenDn; @@ -199,23 +199,23 @@ struct LoRaWANMacSpec_t { }; const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { - { 0x00, 0, 0, false }, // not an actual MAC command, exists for offsetting - { 0x01, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_RESET - { 0x02, 2, 0, true }, // RADIOLIB_LORAWAN_MAC_LINK_CHECK - { 0x03, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_LINK_ADR - { 0x04, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_DUTY_CYCLE - { 0x05, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP - { 0x06, 0, 2, false }, // RADIOLIB_LORAWAN_MAC_DEV_STATUS - { 0x07, 5, 1, false }, // RADIOLIB_LORAWAN_MAC_NEW_CHANNEL - { 0x08, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP - { 0x09, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP - { 0x0A, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_DL_CHANNEL - { 0x0B, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REKEY - { 0x0C, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP - { 0x0D, 5, 0, true }, // RADIOLIB_LORAWAN_MAC_DEVICE_TIME - { 0x0E, 2, 0, false }, // RADIOLIB_LORAWAN_MAC_FORCE_REJOIN - { 0x0F, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP - { 0x80, 5, 0, true } // RADIOLIB_LORAWAN_MAC_PROPRIETARY + { 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting + { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, + { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, + { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, + { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, + { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, + { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } }; /*! @@ -681,9 +681,9 @@ class LoRaWANNode { Returns 'false' if there was no network response / parsing failed. \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. \param gwCnt Number of gateways that received the LinkCheckReq. - \returns Whether the parameters where succesfully parsed. + \returns \ref status_codes */ - bool getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt); + int16_t getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt); /*! \brief Returns the network time after requesting a DeviceTime MAC command. @@ -692,9 +692,9 @@ class LoRaWANNode { \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) \param fraction Fractional-second, in 1/256-second steps \param returnUnix If true, returns Unix timestamp instead of GPS (default true) - \returns Whether the parameters where succesfully parsed. + \returns \ref status_codes */ - bool getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); + int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); #if !RADIOLIB_GODMODE private: @@ -876,6 +876,9 @@ class LoRaWANNode { // function to encrypt and decrypt payloads void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); + // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum + static uint16_t checkSum16(uint8_t *key, uint8_t keyLen); + // network-to-host conversion method - takes data from network packet and converts it to the host endians template static T ntoh(uint8_t* buff, size_t size = 0); diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 54580b0ee2..e8b244bd9a 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -53,7 +53,7 @@ const LoRaWANBand_t US915 = { .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, - .dwellTimeUp = 400, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -334,8 +334,8 @@ const LoRaWANBand_t AS923 = { .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, - .dwellTimeUp = 400, - .dwellTimeDn = 400, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txFreqs = { { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, From d0979ce853302af89f6438e99812e14afd58014d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 8 Jan 2024 23:36:17 +0100 Subject: [PATCH 0856/1848] [LoRaWAN] Fix checksum calculation --- src/protocols/LoRaWAN/LoRaWAN.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 2af2ae8b23..6e7e0d6c7a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -362,10 +362,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) uint16_t checkSum = 0; - checkSum ^= checkSum16((uint8_t*)joinEUI, 8); - checkSum ^= checkSum16((uint8_t*)devEUI, 8); - checkSum ^= checkSum16(nwkKey, 16); - checkSum ^= checkSum16(appKey, 16); + checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); + checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); + checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); + checkSum ^= LoRaWANNode::checkSum16(appKey, 16); bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; @@ -633,11 +633,11 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // check if we actually need to restart from a clean session uint16_t checkSum = 0; - checkSum ^= checkSum16((uint8_t*)addr, 4); - checkSum ^= checkSum16(nwkSKey, 16); - checkSum ^= checkSum16(appSKey, 16); - if(fNwkSIntKey) { checkSum ^= checkSum16(fNwkSIntKey, 16); } - if(sNwkSIntKey) { checkSum ^= checkSum16(sNwkSIntKey, 16); } + checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); + checkSum ^= LoRaWANNode::checkSum16(nwkSKey, 16); + checkSum ^= LoRaWANNode::checkSum16(appSKey, 16); + if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } + if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; @@ -2752,9 +2752,9 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out } uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint8_t keyLen) { - uint16_t buf16[RADIOLIB_AES128_KEY_SIZE/2]; + uint16_t buf16[RADIOLIB_AES128_KEY_SIZE/2] = { 0 }; uint8_t bufLen = keyLen / 2; - memcpy(buf16, key, bufLen); + memcpy(buf16, key, keyLen); uint16_t checkSum = 0; for(int i = 0; i < bufLen; i++) { checkSum ^= buf16[i]; From 6600860915d91ad872bf29b5e7222af814c6cbf1 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 11 Jan 2024 17:51:39 +0100 Subject: [PATCH 0857/1848] Update RF69.cpp --- src/modules/RF69/RF69.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index b414d0f3cc..db3335dbf2 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -375,7 +375,7 @@ bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { // get the data this->mod->SPIreadRegisterBurst(RADIOLIB_RF69_REG_FIFO, len, dataPtr); - (*rcvLen) += (len); + *rcvLen = *rcvLen + len; // check if we're done if(*rcvLen >= totalLen) { From abfc91a9bc4f3408e9a55569f12f91ebaceb7670 Mon Sep 17 00:00:00 2001 From: Peter Buchegger Date: Thu, 11 Jan 2024 17:52:50 +0100 Subject: [PATCH 0858/1848] Update SX127x.cpp --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index a3ca76c82c..00fae8f272 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -542,7 +542,7 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) // get the data this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr); - (*rcvLen) += (len); + *rcvLen = *rcvLen + len; // check if we're done if(*rcvLen >= totalLen) { From bbe407b50fd8132d659997a9234feef69866ec2b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 18:51:55 +0100 Subject: [PATCH 0859/1848] [SX127x] Cleanup private/protected members --- src/modules/SX127x/SX1272.cpp | 123 ++++++++++++++++-------------- src/modules/SX127x/SX1278.cpp | 137 +++++++++++++++++++--------------- src/modules/SX127x/SX127x.cpp | 8 +- src/modules/SX127x/SX127x.h | 25 +++---- 4 files changed, 161 insertions(+), 132 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index ae900a2a10..8864297e89 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -74,11 +74,12 @@ int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1272::reset() { - this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); - this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); - this->mod->hal->delay(1); - this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); - this->mod->hal->delay(5); + Module* mod = this->getMod(); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh); + mod->hal->delay(1); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow); + mod->hal->delay(5); } int16_t SX1272::setFrequency(float freq) { @@ -119,10 +120,11 @@ int16_t SX1272::setBandwidth(float bw) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); if(symbolLength >= 16.0) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } @@ -171,11 +173,12 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { - float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); if(symbolLength >= 16.0) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } @@ -263,25 +266,26 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { // set mode to standby int16_t state = SX127x::standby(); + Module* mod = this->getMod(); if(useRfo) { // RFO output - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power <= 17) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } @@ -298,6 +302,7 @@ int16_t SX1272::setGain(uint8_t gain) { // set mode to standby int16_t state = SX127x::standby(); + Module* mod = this->getMod(); // get modem int16_t modem = getActiveModem(); @@ -305,20 +310,20 @@ int16_t SX1272::setGain(uint8_t gain) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); } else { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } @@ -342,15 +347,16 @@ int16_t SX1272::setDataShaping(uint8_t sh) { RADIOLIB_ASSERT(state); // set data shaping + Module* mod = this->getMod(); switch(sh) { case RADIOLIB_SHAPING_NONE: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); case RADIOLIB_SHAPING_0_3: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); case RADIOLIB_SHAPING_0_5: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); case RADIOLIB_SHAPING_1_0: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } @@ -371,15 +377,16 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { int16_t state = SX127x::standby(); // set data shaping + Module* mod = this->getMod(); switch(sh) { case 0: - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); break; case 1: - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); break; case 2: - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); break; default: state = RADIOLIB_ERR_INVALID_DATA_SHAPING; @@ -394,29 +401,30 @@ float SX1272::getRSSI(bool packet, bool skipReceive) { } int16_t SX1272::setCRC(bool enable, bool mode) { + Module* mod = this->getMod(); if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC SX127x::crcEnabled = enable; if(enable) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_ON, 1, 1)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_ON, 1, 1)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 1, 1)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 1, 1)); } } else { // set FSK CRC int16_t state = RADIOLIB_ERR_NONE; if(enable) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } @@ -427,10 +435,11 @@ int16_t SX1272::forceLDRO(bool enable) { } this->ldroAuto = false; + Module* mod = this->getMod(); if(enable) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); } } @@ -456,7 +465,8 @@ int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { int16_t state = SX127x::standby(); // write register - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); return(state); } @@ -465,16 +475,17 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { int16_t state = SX127x::standby(); // write registers + Module* mod = this->getMod(); if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } @@ -484,7 +495,8 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) { int16_t state = SX127x::standby(); // write register - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); return(state); } @@ -495,11 +507,12 @@ int16_t SX1272::setHeaderType(uint8_t headerType, size_t len) { } // set requested packet mode - int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); RADIOLIB_ASSERT(state); // set length to register - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value @@ -514,7 +527,8 @@ int16_t SX1272::configFSK() { RADIOLIB_ASSERT(state); // set fast PLL hop - state = this->mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); + Module* mod = this->getMod(); + state = mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } @@ -523,7 +537,8 @@ void SX1272::errataFix(bool rx) { // mitigation of receiver spurious response // see SX1272/73 Errata, section 2.2 for details - this->mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); + Module* mod = this->getMod(); + mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); } #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 57c9f6f96b..560a10bcdd 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -74,11 +74,12 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } void SX1278::reset() { - this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); - this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); - this->mod->hal->delay(1); - this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); - this->mod->hal->delay(5); + Module* mod = this->getMod(); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow); + mod->hal->delay(1); + mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh); + mod->hal->delay(5); } int16_t SX1278::setFrequency(float freq) { @@ -133,10 +134,11 @@ int16_t SX1278::setBandwidth(float bw) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); if(symbolLength >= 16.0) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } } @@ -186,10 +188,11 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; + Module* mod = this->getMod(); if(symbolLength >= 16.0) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } } @@ -281,6 +284,7 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { // set mode to standby int16_t state = SX127x::standby(); + Module* mod = this->getMod(); if(useRfo) { uint8_t paCfg = 0; @@ -292,22 +296,22 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { paCfg = RADIOLIB_SX1278_MAX_POWER | power; } - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power != 20) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } } @@ -323,6 +327,7 @@ int16_t SX1278::setGain(uint8_t gain) { // set mode to standby int16_t state = SX127x::standby(); + Module* mod = this->getMod(); // get modem int16_t modem = getActiveModem(); @@ -330,20 +335,20 @@ int16_t SX1278::setGain(uint8_t gain) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); } else { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } @@ -372,15 +377,16 @@ int16_t SX1278::setDataShaping(uint8_t sh) { RADIOLIB_ASSERT(state); // set data shaping + Module* mod = this->getMod(); switch(sh) { case RADIOLIB_SHAPING_NONE: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5)); case RADIOLIB_SHAPING_0_3: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5)); case RADIOLIB_SHAPING_0_5: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5)); case RADIOLIB_SHAPING_1_0: - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5)); default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } @@ -401,15 +407,16 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { int16_t state = SX127x::standby(); // set data shaping + Module* mod = this->getMod(); switch(sh) { case 0: - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5); break; case 1: - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5); break; case 2: - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5); break; default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); @@ -427,29 +434,30 @@ float SX1278::getRSSI(bool packet, bool skipReceive) { } int16_t SX1278::setCRC(bool enable, bool mode) { + Module* mod = this->getMod(); if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC SX127x::crcEnabled = enable; if(enable) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2)); } } else { // set FSK CRC int16_t state = RADIOLIB_ERR_NONE; if(enable) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); + return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } @@ -459,11 +467,12 @@ int16_t SX1278::forceLDRO(bool enable) { return(RADIOLIB_ERR_WRONG_MODEM); } + Module* mod = this->getMod(); this->ldroAuto = false; if(enable) { - return(this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); + return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); } else { - return(this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); + return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); } } @@ -489,7 +498,8 @@ int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { int16_t state = SX127x::standby(); // write register - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4); return(state); } @@ -498,16 +508,17 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { int16_t state = SX127x::standby(); // write registers + Module* mod = this->getMod(); if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } @@ -517,7 +528,8 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) { int16_t state = SX127x::standby(); // write register - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); + Module* mod = this->getMod(); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1); return(state); } @@ -528,11 +540,12 @@ int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) { } // set requested packet mode - int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); RADIOLIB_ASSERT(state); // set length to register - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value @@ -547,7 +560,8 @@ int16_t SX1278::configFSK() { RADIOLIB_ASSERT(state); // set fast PLL hop - state = this->mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); + Module* mod = this->getMod(); + state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } @@ -559,13 +573,14 @@ void SX1278::errataFix(bool rx) { // sensitivity optimization for 500kHz bandwidth // see SX1276/77/78 Errata, section 2.1 for details + Module* mod = this->getMod(); if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { if((frequency >= 862.0) && (frequency <= 1020.0)) { - this->mod->SPIwriteRegister(0x36, 0x02); - this->mod->SPIwriteRegister(0x3a, 0x64); + mod->SPIwriteRegister(0x36, 0x02); + mod->SPIwriteRegister(0x3a, 0x64); } else if((frequency >= 410.0) && (frequency <= 525.0)) { - this->mod->SPIwriteRegister(0x36, 0x02); - this->mod->SPIwriteRegister(0x3a, 0x7F); + mod->SPIwriteRegister(0x36, 0x02); + mod->SPIwriteRegister(0x3a, 0x7F); } } @@ -619,8 +634,8 @@ void SX1278::errataFix(bool rx) { fixedRegs[2] = 0x00; } else if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { fixedRegs[0] = 0b1000000; - fixedRegs[1] = this->mod->SPIreadRegister(0x2F); - fixedRegs[2] = this->mod->SPIreadRegister(0x30); + fixedRegs[1] = mod->SPIreadRegister(0x2F); + fixedRegs[2] = mod->SPIreadRegister(0x30); } else { return; } @@ -636,9 +651,9 @@ void SX1278::errataFix(bool rx) { } // finally, apply errata fixes - this->mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7); - this->mod->SPIsetRegValue(0x2F, fixedRegs[1]); - this->mod->SPIsetRegValue(0x30, fixedRegs[2]); + mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7); + mod->SPIsetRegValue(0x2F, fixedRegs[1]); + mod->SPIsetRegValue(0x30, fixedRegs[2]); } #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 00fae8f272..38953a145f 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -6,10 +6,6 @@ SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, this->mod = mod; } -Module* SX127x::getMod() { - return(this->mod); -} - int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) { // set module properties this->mod->init(); @@ -1477,6 +1473,10 @@ int8_t SX127x::getTempRaw() { return(temp); } +Module* SX127x::getMod() { + return(this->mod); +} + int16_t SX127x::config() { // turn off frequency hopping int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 721c5d4816..bf09b925c9 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -596,8 +596,6 @@ class SX127x: public PhysicalLayer { */ SX127x(Module* mod); - Module* getMod(); - // basic methods /*! @@ -1221,37 +1219,38 @@ class SX127x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* mod; + Module* getMod(); #if !RADIOLIB_GODMODE protected: #endif - float frequency = 0; float bandwidth = 0; uint8_t spreadingFactor = 0; + size_t packetLength = 0; uint8_t codingRate = 0; - float bitRate = 0; - bool ookEnabled = false; bool crcEnabled = false; - bool crcOn = true; // default value used in FSK mode - size_t packetLength = 0; + bool ookEnabled = false; - int16_t setFrequencyRaw(float newFreq); - int16_t setBitRateCommon(float br, uint8_t fracRegAddr); - int16_t config(); int16_t configFSK(); int16_t getActiveModem(); - int16_t directMode(); - int16_t setPacketMode(uint8_t mode, uint8_t len); + int16_t setFrequencyRaw(float newFreq); + int16_t setBitRateCommon(float br, uint8_t fracRegAddr); #if !RADIOLIB_GODMODE private: #endif + Module* mod; + + float bitRate = 0; + bool crcOn = true; // default value used in FSK mode float dataRate = 0; bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; + int16_t config(); + int16_t directMode(); + int16_t setPacketMode(uint8_t mode, uint8_t len); bool findChip(uint8_t* vers, uint8_t num); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); From b5d931ec7911597c7668b9c669a5f59253c0255c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 19:45:41 +0100 Subject: [PATCH 0860/1848] [SX128x] Cleanup private/protected members --- src/modules/SX128x/SX1280.cpp | 9 +++++---- src/modules/SX128x/SX128x.cpp | 8 ++++---- src/modules/SX128x/SX128x.h | 15 +++------------ 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index cc4c97983c..b5b30dd09f 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -12,10 +12,11 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { RADIOLIB_ASSERT(state); // wait until ranging is finished - uint32_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start > 10000) { + Module* mod = this->getMod(); + uint32_t start = mod->hal->millis(); + while(!mod->hal->digitalRead(mod->getIrq())) { + mod->hal->yield(); + if(mod->hal->millis() - start > 10000) { clearIrqStatus(); standby(); return(RADIOLIB_ERR_RANGING_TIMEOUT); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 6f14b536cc..07d8661bfa 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -6,10 +6,6 @@ SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, this->mod = mod; } -Module* SX128x::getMod() { - return(this->mod); -} - int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) { // set module properties this->mod->init(); @@ -1347,6 +1343,10 @@ void SX128x::readBit(uint32_t pin) { } #endif +Module* SX128x::getMod() { + return(this->mod); +} + uint8_t SX128x::getStatus() { uint8_t data = 0; this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 4029635f00..8d4526ac22 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -361,8 +361,6 @@ class SX128x: public PhysicalLayer { */ SX128x(Module* mod); - Module* getMod(); - // basic methods /*! @@ -782,11 +780,7 @@ class SX128x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* mod; - -#if !RADIOLIB_GODMODE - protected: -#endif + Module* getMod(); // cached LoRa parameters float bandwidthKhz = 0; @@ -814,19 +808,16 @@ class SX128x: public PhysicalLayer { int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX128X_IRQ_ALL); int16_t setRangingRole(uint8_t role); int16_t setPacketType(uint8_t type); - int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); -#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL +#if !RADIOLIB_GODMODE private: #endif + Module* mod; // common low-level SPI interface static int16_t SPIparseStatus(uint8_t in); -#if !RADIOLIB_GODMODE - private: -#endif // common parameters uint8_t power = 0; From 948088c1e1ca97af8a7f1c184bcf5acc56f5162e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 19:49:17 +0100 Subject: [PATCH 0861/1848] [SX128x] Moved setHeaderType to private methods --- src/modules/SX128x/SX128x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 8d4526ac22..1348f3aeda 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -808,7 +808,6 @@ class SX128x: public PhysicalLayer { int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX128X_IRQ_ALL); int16_t setRangingRole(uint8_t role); int16_t setPacketType(uint8_t type); - int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); #if !RADIOLIB_GODMODE private: @@ -837,6 +836,7 @@ class SX128x: public PhysicalLayer { uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0; int16_t config(uint8_t modem); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); }; #endif From 34d80faaf04bf16e5ee18d16b2f3a39c584c62ce Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 20:00:08 +0100 Subject: [PATCH 0862/1848] [SX126x] Cleanup private/protected members --- src/modules/SX126x/SX126x.cpp | 8 +++--- src/modules/SX126x/SX126x.h | 49 ++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 59d4e764dc..888542e8d0 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -8,10 +8,6 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, this->XTAL = false; } -Module* SX126x::getMod() { - return(this->mod); -} - int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties this->mod->init(); @@ -2053,6 +2049,10 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1)); } +Module* SX126x::getMod() { + return(this->mod); +} + int16_t SX126x::config(uint8_t modem) { // reset buffer base address int16_t state = setBufferBaseAddress(); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2fb3fdb4a2..8c9c35d243 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -442,8 +442,6 @@ class SX126x: public PhysicalLayer { */ SX126x(Module* mod); - Module* getMod(); - /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. */ @@ -1092,9 +1090,11 @@ class SX126x: public PhysicalLayer { */ int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); -#if !RADIOLIB_GODMODE +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif + Module* getMod(); + // SX126x SPI command implementations int16_t setFs(); int16_t setTx(uint32_t timeout = 0); @@ -1121,32 +1121,24 @@ class SX126x: public PhysicalLayer { uint16_t getDeviceErrors(); int16_t clearDeviceErrors(); - int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); - int16_t setFrequencyRaw(float freq); - int16_t setPacketMode(uint8_t mode, uint8_t len); - int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); - int16_t directMode(); - int16_t packetMode(); - - // fixes to errata - int16_t fixSensitivity(); - int16_t fixPaClamping(bool enable = true); - int16_t fixImplicitTimeout(); - int16_t fixInvertedIQ(uint8_t iqConfig); - -#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL +#if !RADIOLIB_GODMODE protected: #endif - Module* mod; + const char* chipType; + uint8_t bandwidth = 0; + + int16_t setFrequencyRaw(float freq); + int16_t fixPaClamping(bool enable = true); // common low-level SPI interface static int16_t SPIparseStatus(uint8_t in); #if !RADIOLIB_GODMODE - protected: + private: #endif + Module* mod; - uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; + uint8_t spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; uint16_t preambleLengthLoRa = 0; float bandwidthKhz = 0; bool ldroAuto = true; @@ -1162,13 +1154,28 @@ class SX126x: public PhysicalLayer { size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; - const char* chipType; // Allow subclasses to define different TX modes uint8_t txMode = Module::MODE_TX; int16_t config(uint8_t modem); bool findChip(const char* verStr); + int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + int16_t setPacketMode(uint8_t mode, uint8_t len); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); + int16_t directMode(); + int16_t packetMode(); + + // fixes to errata + int16_t fixSensitivity(); + int16_t fixImplicitTimeout(); + int16_t fixInvertedIQ(uint8_t iqConfig); + + + void regdump(); + void effectEvalPre(uint8_t* buff, uint32_t start); + void effectEvalPost(uint8_t* buff, uint32_t start); + void effectEval(); }; #endif From d31b4836e15b9a57c4319a61ad86183582a326ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 20:12:45 +0100 Subject: [PATCH 0863/1848] [Si443x] Cleanup private/protected members --- src/modules/Si443x/Si4430.cpp | 3 ++- src/modules/Si443x/Si4431.cpp | 3 ++- src/modules/Si443x/Si4432.cpp | 3 ++- src/modules/Si443x/Si443x.h | 17 ++++++++--------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index c8b030cb0a..45b5535692 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -32,7 +32,8 @@ int16_t Si4430::setOutputPower(int8_t power) { RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); + Module* mod = this->getMod(); + return(mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 953c888f85..799cec763c 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -25,7 +25,8 @@ int16_t Si4431::setOutputPower(int8_t power) { RADIOLIB_CHECK_RANGE(power, -8, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); + Module* mod = this->getMod(); + return(mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 12c212efc1..40a97226ba 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -32,7 +32,8 @@ int16_t Si4432::setOutputPower(int8_t power) { RADIOLIB_CHECK_RANGE(power, -1, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); // set output power - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); + Module* mod = this->getMod(); + return(mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); } #endif diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index ca83ba1258..9d6398064a 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -566,8 +566,6 @@ class Si443x: public PhysicalLayer { */ Si443x(Module* mod); - Module* getMod(); - // basic methods /*! @@ -828,11 +826,17 @@ class Si443x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* mod; + Module* getMod(); #if !RADIOLIB_GODMODE protected: #endif + int16_t setFrequencyRaw(float newFreq); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; float bitRate = 0; float frequencyDev = 0; @@ -842,18 +846,13 @@ class Si443x: public PhysicalLayer { bool packetLengthQueried = false; uint8_t packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; - int16_t setFrequencyRaw(float newFreq); - int16_t setPacketMode(uint8_t mode, uint8_t len); - -#if !RADIOLIB_GODMODE - private: -#endif bool findChip(); void clearIRQFlags(); void clearFIFO(size_t count); int16_t config(); int16_t updateClockRecovery(); int16_t directMode(); + int16_t setPacketMode(uint8_t mode, uint8_t len); }; #endif From 935c316f7cd61f194776f8942bc3c5d635009658 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 20:14:18 +0100 Subject: [PATCH 0864/1848] [Si443x] cleanup --- src/modules/Si443x/Si443x.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 95ad385a40..2097ee58c4 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -6,10 +6,6 @@ Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, this->mod = mod; } -Module* Si443x::getMod() { - return(this->mod); -} - int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { // set module properties this->mod->init(); @@ -641,6 +637,10 @@ int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) { return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen)); } +Module* Si443x::getMod() { + return(this->mod); +} + int16_t Si443x::setFrequencyRaw(float newFreq) { // set mode to standby int16_t state = standby(); From 3a5d9b5c321ea881966f7836380e7237a702e317 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 20:26:07 +0100 Subject: [PATCH 0865/1848] [RF69] Cleanup private/protected members --- src/modules/RF69/RF69.cpp | 8 ++++---- src/modules/RF69/RF69.h | 22 +++++++++++----------- src/modules/SX123x/SX1231.cpp | 15 ++++++++------- src/modules/SX123x/SX1233.cpp | 22 ++++++++++++---------- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index db3335dbf2..54e6cc7492 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -6,10 +6,6 @@ RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RA this->mod = module; } -Module* RF69::getMod() { - return(this->mod); -} - int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLen) { // set module properties this->mod->init(); @@ -982,6 +978,10 @@ int16_t RF69::setDIOMapping(uint32_t pin, uint32_t value) { return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin)); } +Module* RF69::getMod() { + return(this->mod); +} + int16_t RF69::getChipVersion() { return(this->mod->SPIgetRegValue(RADIOLIB_RF69_REG_VERSION)); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d71d91c6d4..177b839ca6 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -490,8 +490,6 @@ class RF69: public PhysicalLayer { */ RF69(Module* module); - Module* getMod(); - // basic methods /*! @@ -998,15 +996,23 @@ class RF69: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* mod; + Module* getMod(); #if !RADIOLIB_GODMODE protected: #endif - - float frequency = RADIOLIB_RF69_DEFAULT_FREQ; float bitRate = RADIOLIB_RF69_DEFAULT_BR; float rxBandwidth = RADIOLIB_RF69_DEFAULT_RXBW; + + int16_t config(); + int16_t setMode(uint8_t mode); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + float frequency = RADIOLIB_RF69_DEFAULT_FREQ; bool ookEnabled = false; int16_t tempOffset = 0; int8_t power = RADIOLIB_RF69_DEFAULT_POWER; @@ -1021,14 +1027,8 @@ class RF69: public PhysicalLayer { bool bitSync = true; - int16_t config(); int16_t directMode(); int16_t setPacketMode(uint8_t mode, uint8_t len); - int16_t setMode(uint8_t mode); - -#if !RADIOLIB_GODMODE - private: -#endif void clearIRQFlags(); void clearFIFO(size_t count); }; diff --git a/src/modules/SX123x/SX1231.cpp b/src/modules/SX123x/SX1231.cpp index 8d38edaf70..44ff904d72 100644 --- a/src/modules/SX123x/SX1231.cpp +++ b/src/modules/SX123x/SX1231.cpp @@ -7,9 +7,10 @@ SX1231::SX1231(Module* mod) : RF69(mod) { int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + Module* mod = this->getMod(); + mod->init(); + mod->hal->pinMode(mod->getIrq(), mod->hal->GpioModeInput); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); // try to find the SX1231 chip uint8_t i = 0; @@ -21,14 +22,14 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po this->chipRevision = version; } else { RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); - this->mod->hal->delay(10); + mod->hal->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN("No SX1231 found!"); - this->mod->term(); + mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX1231"); @@ -77,11 +78,11 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po // SX123x V2a only if(this->chipRevision == RADIOLIB_SX123X_CHIP_REVISION_2_A) { // modify default OOK threshold value - state = this->mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); + state = mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); RADIOLIB_ASSERT(state); // enable OCP with 95 mA limit - state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); + state = mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index c13d5e3982..6acf5a7e36 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -8,9 +8,10 @@ SX1233::SX1233(Module* mod) : SX1231(mod) { int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + Module* mod = this->getMod(); + mod->init(); + mod->hal->pinMode(mod->getIrq(), mod->hal->GpioModeInput); + mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); // try to find the SX1233 chip uint8_t i = 0; @@ -22,14 +23,14 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po this->chipRevision = version; } else { RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); - this->mod->hal->delay(10); + mod->hal->delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN("No SX1233 found!"); - this->mod->term(); + mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } RADIOLIB_DEBUG_PRINTLN("M\tSX1233"); @@ -78,11 +79,11 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po // SX123x V2a only if(this->chipRevision == RADIOLIB_SX123X_CHIP_REVISION_2_A) { // modify default OOK threshold value - state = this->mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); + state = mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD); RADIOLIB_ASSERT(state); // enable OCP with 95 mA limit - state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); + state = mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0); RADIOLIB_ASSERT(state); } @@ -109,13 +110,14 @@ int16_t SX1233::setBitRate(float br) { setMode(RADIOLIB_RF69_STANDBY); // set PLL bandwidth - int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX1233_REG_TEST_PLL, pllBandwidth, 7, 0); + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX1233_REG_TEST_PLL, pllBandwidth, 7, 0); RADIOLIB_ASSERT(state); // set bit rate uint16_t bitRate = 32000 / br; - state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + state = mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); if(state == RADIOLIB_ERR_NONE) { this->bitRate = br; } From 1575e3735549a8d7f82f66c340e00d84e1a1cb19 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 20:29:09 +0100 Subject: [PATCH 0866/1848] [nRF24] Cleanup private/protected members --- src/modules/nRF24/nRF24.cpp | 8 ++++---- src/modules/nRF24/nRF24.h | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index e4923bcded..3f64f27f16 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -6,10 +6,6 @@ nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RA this->mod = mod; } -Module* nRF24::getMod() { - return(this->mod); -} - int16_t nRF24::begin(int16_t freq, int16_t dr, int8_t pwr, uint8_t addrWidth) { // set module properties this->mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; @@ -606,6 +602,10 @@ int16_t nRF24::config() { return(state); } +Module* nRF24::getMod() { + return(this->mod); +} + void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) { SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes); } diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index d6f9346a7f..54ed9c2569 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -195,8 +195,6 @@ class nRF24: public PhysicalLayer { */ nRF24(Module* mod); - Module* getMod(); - // basic methods /*! @@ -470,15 +468,16 @@ class nRF24: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* mod; + Module* getMod(); void SPIreadRxPayload(uint8_t* data, uint8_t numBytes); void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes); void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0); #if !RADIOLIB_GODMODE - protected: + private: #endif + Module* mod; int16_t frequency = RADIOLIB_NRF24_DEFAULT_FREQ; int16_t dataRate = RADIOLIB_NRF24_DEFAULT_DR; From 30961964c538cb8fb8fb57ab444b3a2345b13724 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 12 Jan 2024 20:35:10 +0100 Subject: [PATCH 0867/1848] [CC1101] Cleanup private/protected members --- src/modules/CC1101/CC1101.cpp | 8 ++++---- src/modules/CC1101/CC1101.h | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f65d913fd7..d36c3d2b90 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -6,10 +6,6 @@ CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SI this->mod = module; } -Module* CC1101::getMod() { - return(this->mod); -} - int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { // set module properties this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; @@ -1050,6 +1046,10 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { return(state); } +Module* CC1101::getMod() { + return(this->mod); +} + int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { // status registers require special command if((reg > RADIOLIB_CC1101_REG_TEST0) && (reg < RADIOLIB_CC1101_REG_PATABLE)) { diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 53652f3538..e3354ae100 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -541,8 +541,6 @@ class CC1101: public PhysicalLayer { */ CC1101(Module* module); - Module* getMod(); - // basic methods /*! @@ -947,21 +945,22 @@ class CC1101: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* mod; + Module* getMod(); - // SPI read overrides to set bit for burst write and status registers access - int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0); - int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2); - void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes); - uint8_t SPIreadRegister(uint8_t reg); - void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len); - void SPIwriteRegister(uint8_t reg, uint8_t data); + // SPI read overrides to set bit for burst write and status registers access + int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0); + int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2); + void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes); + uint8_t SPIreadRegister(uint8_t reg); + void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len); + void SPIwriteRegister(uint8_t reg, uint8_t data); - void SPIsendCommand(uint8_t cmd); + void SPIsendCommand(uint8_t cmd); #if !RADIOLIB_GODMODE - protected: + private: #endif + Module* mod; float frequency = RADIOLIB_CC1101_DEFAULT_FREQ; float bitRate = RADIOLIB_CC1101_DEFAULT_BR; From 0bba68f3ae9321e8e2f3bd9ac97946ec79126bf6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 13 Jan 2024 00:05:25 +0100 Subject: [PATCH 0868/1848] [LoRaWAN] Rework channel logic --- keywords.txt | 2 +- src/TypeDef.h | 5 - src/protocols/LoRaWAN/LoRaWAN.cpp | 701 +++++++++++++++++------------- src/protocols/LoRaWAN/LoRaWAN.h | 47 +- 4 files changed, 423 insertions(+), 332 deletions(-) diff --git a/keywords.txt b/keywords.txt index 3f2da44a59..ad416f4e26 100644 --- a/keywords.txt +++ b/keywords.txt @@ -294,6 +294,7 @@ wipe KEYWORD2 restore KEYWORD2 beginOTAA KEYWORD2 beginABP KEYWORD2 +isJoined KEYWORD2 saveSession KEYWORD2 sendMacCommandReq KEYWORD2 uplink KEYWORD2 @@ -312,7 +313,6 @@ timeUntilUplink KEYWORD2 setDwellTime KEYWORD2 maxPayloadDwellTime KEYWORD2 setTxPower KEYWORD2 -selectSubband KEYWORD2 setCSMA KEYWORD2 getMacLinkCheckAns KEYWORD2 getMacDeviceTimeAns KEYWORD2 diff --git a/src/TypeDef.h b/src/TypeDef.h index 64d1a1a291..f82e787b17 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -553,11 +553,6 @@ */ #define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114) -/*! - \brief Datarate requested by user is invalid. -*/ -#define RADIOLIB_ERR_DATA_RATE_INVALID (-1115) - /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6e7e0d6c7a..ba2c6be02b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -28,24 +28,12 @@ uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_ return(dr); } -LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { +LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand) { this->phyLayer = phy; this->band = band; this->rx2 = this->band->rx2; - this->dutyCycle = this->band->dutyCycle; - if(this->dutyCycle > 0) { - this->dutyCycleEnabled = true; - } - this->dwellTimeUp = this->band->dwellTimeUp; - if(this->dwellTimeUp > 0) { - this->dwellTimeEnabledUp = true; - } - this->dwellTimeDn = this->band->dwellTimeDn; - if(this->dwellTimeDn) { - this->dwellTimeEnabledDn = true; - } this->txPowerMax = this->band->powerMax; - this->txPowerCur = 0; // start at 0 offset = full power + this->subBand = subBand; this->difsSlots = 2; this->backoffMax = 6; this->enableCSMA = false; @@ -63,7 +51,6 @@ void LoRaWANNode::wipe() { mod->hal->wipePersistentStorage(); } -// TODO do not return status code, but return LoRaWAN mode (OTAA, ABP, none) int16_t LoRaWANNode::restore() { // if already joined, ignore if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { @@ -218,7 +205,11 @@ int16_t LoRaWANNode::restoreFcntUp() { int16_t LoRaWANNode::restoreChannels() { // first do the default channels - this->setupChannels(nullptr); + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(false); + } else { // RADIOLIB_LORAWAN_BAND_FIXED + this->setupChannelsFix(this->subBand); + } Module* mod = this->phyLayer->getMod(); uint8_t bufferZeroes[5] = { 0 }; @@ -252,16 +243,17 @@ int16_t LoRaWANNode::restoreChannels() { } } - } else { - uint8_t numBytes = 8 * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + } else { // RADIOLIB_LORAWAN_BAND_FIXED + uint8_t numADRCommands = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); + uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; uint8_t buffer[numBytes] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - for(int i = 0; i < 8; i++) { + for(int i = 0; i < numADRCommands; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len); // there COULD, according to spec, be an all zeroes ADR command - meh if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { @@ -273,13 +265,32 @@ int16_t LoRaWANNode::restoreChannels() { } #endif -void LoRaWANNode::beginCommon() { +void LoRaWANNode::beginCommon(uint8_t joinDr) { LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + uint8_t drUp = 0; + // if join datarate is user-specified and valid, select that value; otherwise use + if(joinDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(joinDr >= this->band->txFreqs[0].drMin && joinDr <= this->band->txFreqs[0].drMax) { + drUp = joinDr; + } else { + RADIOLIB_DEBUG_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", + joinDr, this->band->txFreqs[0].drMin, this->band->txFreqs[0].drMax); + joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + if(joinDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; + } + cmd.payload[0] = (drUp << 4); + } else { + uint8_t drJr = this->band->txSpans[0].joinRequestDataRate; + cmd.payload[0] = (drJr << 4); + } cmd.payload[0] |= 0; // default to max Tx Power - cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; @@ -393,17 +404,25 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe int16_t state = RADIOLIB_ERR_NONE; - // setup uplink/downlink frequencies and datarates - state = this->selectChannelsJR(this->devNonce, joinDr); + // setup join-request uplink/downlink frequencies and datarates + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + state = this->setupChannelsDyn(true); + } else { + state = this->setupChannelsFix(this->subBand); + } RADIOLIB_ASSERT(state); // setup all MAC properties to default values - this->beginCommon(); + this->beginCommon(joinDr); // set the physical layer configuration state = this->setPhyProperties(); RADIOLIB_ASSERT(state); + // select a random pair of Tx/Rx channels + state = this->selectChannels(); + RADIOLIB_ASSERT(state); + // configure for uplink with default configuration state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); @@ -532,14 +551,17 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; (void)execMacCommand(&cmd); + // in case of dynamic band, setup the default channels first + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(false); + } // process CFlist if present if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); - this->setupChannels(cfList); - } else { - this->setupChannels(nullptr); - } + this->processCFList(cfList); + } + // if no CFList was received, default or subband are already setup so don't need to do anything else // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; @@ -678,9 +700,12 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, int16_t state = RADIOLIB_ERR_NONE; - // calculate initial datarate - in case of fixed bands, this requires a subband to be selected - // downlink datarate is calculated using a specific uplink channel, so don't care here - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = (this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][0].drMin) / 2; + // setup the uplink/downlink channels and initial datarate + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->setupChannelsDyn(); + } else { + this->setupChannelsFix(this->subBand); + } // setup all MAC properties to default values this->beginCommon(); @@ -869,8 +894,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { - // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; return(RADIOLIB_ERR_PACKET_TOO_LONG); + // if testing with TS008 specification verification protocol, don't throw error but clip the message + // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; } // increase frame counter by one @@ -919,13 +945,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf break; case(3): { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->setupChannels(nullptr); // revert to default frequencies + this->setupChannelsDyn(false); // revert to default frequencies } else { - // if a subband was selected by user, go back to its default state + // go back to default selected subband // hopefully it'll help something, but probably not; at least we tried.. - if(this->selectedSubband >= 0) { - this->selectSubband(this->selectedSubband); - } + this->setupChannelsFix(this->subBand); } adrStage = 0; // nothing else to do, so end the cycle } @@ -1645,216 +1669,135 @@ int16_t LoRaWANNode::setPhyProperties() { return(state); } -int16_t LoRaWANNode::setupChannels(uint8_t* cfList) { - RADIOLIB_DEBUG_PRINTLN("Setting up channels"); +int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { + RADIOLIB_DEBUG_PRINTLN("Setting up dynamic channels"); - // in case of frequency list-type band, copy the default TX channels into the available channels, with RX1 = TX - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - RADIOLIB_DEBUG_PRINTLN("Dynamic band"); - size_t num = 0; - // copy the default defined channels into the first slots - for(; num < 3 && this->band->txFreqs[num].enabled; num++) { + size_t num = 0; + // copy the default defined channels into the first slots (where Tx = Rx) + for(; num < 3 && this->band->txFreqs[num].enabled; num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); + } + + // if we're about to send a join-request, copy the join-request channels to the next slots + if(joinRequest) { + size_t numJR = 0; + for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } - // if there is a cflist present, parse its frequencies into the next five slots, with datarate range copied from default channel 0 - if(cfList != nullptr) { - RADIOLIB_DEBUG_PRINTLN("CFList present"); - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - // datarate range for all new channels is equal to the default channels - cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; - for(uint8_t i = 0; i < 5; i++, num++) { - cmd.payload[0] = num; - memcpy(&cmd.payload[1], &cfList[i*3], 3); - (void)execMacCommand(&cmd); - } - } - for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - - - } else { // RADIOLIB_LORAWAN_BAND_FIXED - if(cfList != nullptr) { - RADIOLIB_DEBUG_PRINTLN("CFList present"); - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = 0xFF; // same datarate and payload - - // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels - size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span - for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { - cmd.payload[3] = chMaskCntl << 4; // NbTrans = 0 -> keep the same - memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); - (void)execMacCommand(&cmd); - } - } - } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); } + return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::selectSubband(uint8_t idx) { - int16_t state = this->selectSubband((idx - 1) * 8, idx * 8 - 1); - return(state); -} - -int16_t LoRaWANNode::selectSubband(uint8_t startChannel, uint8_t endChannel) { - if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { - RADIOLIB_DEBUG_PRINTLN("There is already an active session - cannot change subband"); - return(RADIOLIB_ERR_INVALID_CHANNEL); - } - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - RADIOLIB_DEBUG_PRINTLN("This is a dynamic band plan which does not support subbands"); - return(RADIOLIB_ERR_INVALID_CHANNEL); +// setup a subband and its corresponding join-request datarate +// WARNING: subBand starts at 1 (corresponds to all populair schemes) +int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { + RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels"); + // randomly select one of 8 or 9 channels and find corresponding datarate + uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; + uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 + uint8_t drJR = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + if(rand <= 8) { + drJR = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 + } else { + drJR = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 } - this->selectedSubband = startChannel % 8; // save selected subband - assumed a block of 8 channels - uint8_t numChannels = endChannel - startChannel + 1; - if(startChannel > this->band->txSpans[0].numChannels) { - RADIOLIB_DEBUG_PRINTLN("There are only %d channels available in this band", this->band->txSpans[0].numChannels); - return(RADIOLIB_ERR_INVALID_CHANNEL); - } - if(startChannel + numChannels > this->band->txSpans[0].numChannels) { - numChannels = this->band->txSpans[0].numChannels - startChannel; - RADIOLIB_DEBUG_PRINTLN("Could only select %d channels due to end of band", numChannels); - } - if(numChannels > RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { - numChannels = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; - RADIOLIB_DEBUG_PRINTLN("Could only select %d channels due to specified limit", numChannels); + // if no subband is selected by user, cycle through banks of 8 using devNonce value + if(subBand == 0) { + uint8_t numBanks8 = this->band->txSpans[0].numChannels / 8; + subBand = this->devNonce % numBanks8; } - LoRaWANChannel_t chnl; - for(size_t chNum = 0; chNum < numChannels; chNum++) { - chnl.enabled = true; - chnl.idx = startChannel + chNum; - chnl.freq = this->band->txSpans[0].freqStart + chnl.idx*this->band->txSpans[0].freqStep; - chnl.drMin = this->band->txSpans[0].drMin; - chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum] = chnl; - // downlink channel is dynamically calculated on each uplink in selectChannels() - RADIOLIB_DEBUG_PRINTLN("Channel UL %d frequency = %f MHz", chNum, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chNum].freq); + // chMask is set for 16 channels at once, so widen the Cntl value + uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset + + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + + // if there are two channel spans, first set the channel from second span + if(this->band->numTxSpans == 2) { + cmd.payload[0] = (drJR << 4); // set join-request datarate + cmd.payload[0] |= 0; // set Tx power to maximum + // enable channel that belongs to this subband + cmd.payload[1] = (1 << (subBand - 1)); // set channel mask + cmd.payload[2] = 0; + cmd.payload[3] = (7 << 4); // set the chMaskCntl value to all channels off + cmd.payload[3] |= 0; // keep NbTrans the same + (void)execMacCommand(&cmd, false); + } + + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[0] = (drJR << 4); // set join-request datarate + cmd.payload[0] |= 0; // set Tx power to maximum + // now select the correct bank of 8 channels + // 0x00 0xFF channel mask for subband = 2, 4.. (even) + // 0xFF 0x00 channel mask for subband = 1, 3.. (odd) + if(subBand % 2 == 0) { + cmd.payload[1] = 0x00; + cmd.payload[2] = 0xFF; + } else { + cmd.payload[1] = 0xFF; + cmd.payload[2] = 0x00; } + cmd.payload[3] = (chMaskCntl << 4); // set the chMaskCntl value + cmd.payload[3] |= 0; // keep NbTrans the same + (void)execMacCommand(&cmd, false); + return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::selectChannelsJR(uint16_t devNonce, uint8_t joinDr) { - LoRaWANChannel_t channelUp; - LoRaWANChannel_t channelDown; - uint8_t drUp; - uint8_t drDown; +int16_t LoRaWANNode::processCFList(uint8_t* cfList) { + RADIOLIB_DEBUG_PRINTLN("Processing CFList"); + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // count the number of available channels for a join-request (default channels + join-request channels) - uint8_t numJRChannels = 0; - for(size_t i = 0; i < 3; i++) { - if(this->band->txFreqs[i].enabled) { - numJRChannels++; - } - if(this->band->txJoinReq[i].enabled) { - numJRChannels++; - } - } - - // cycle through the available channels (seed with devNonce) - uint8_t channelId = devNonce % numJRChannels; - - // find the channel whose index is selected - for(size_t i = 0; i < 3; i++) { - if(this->band->txFreqs[i].idx == channelId) { - channelUp = this->band->txFreqs[i]; + // retrieve number of existing (default) channels + size_t num = 0; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(!this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { break; } - if(this->band->txJoinReq[i].idx == channelId) { - channelUp = this->band->txJoinReq[i]; - } + num++; } - // if join datarate is user-specified and valid, select that value; otherwise use - if(joinDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - if(joinDr >= channelUp.drMin && joinDr <= channelUp.drMax) { - drUp = joinDr; - } else { - RADIOLIB_DEBUG_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", joinDr, channelUp.drMin, channelUp.drMax); - joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - } - } - if(joinDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - drUp = int((channelUp.drMax + channelUp.drMin) / 2); + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; + cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + // datarate range for all new channels is equal to the default channels + cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; + for(uint8_t i = 0; i < 5; i++, num++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + cmd.payload[0] = num; + memcpy(&cmd.payload[1], &cfList[i*3], 3); + (void)execMacCommand(&cmd); } - - // derive the downlink channel and datarate from the uplink channel and datarate - channelDown = channelUp; - drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, channelDown.drMin, channelDown.drMax); - - } else { // RADIOLIB_LORAWAN_BAND_FIXED - uint8_t spanID = 0; - uint8_t channelID = 0; - uint8_t numEnabledChannels = 0; - // if there are any predefined channels because user selected a subband, select one of these channels - for(; numEnabledChannels < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; numEnabledChannels++) { - if(this->availableChannels[numEnabledChannels][RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].enabled == false) { - break; - } + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // complete channel mask received, so clear all existing channels + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - if(numEnabledChannels > 0) { - uint8_t channelID = this->phyLayer->random(numEnabledChannels); - channelUp = this->availableChannels[channelID][RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; - spanID = channelUp.idx / this->band->txSpans[0].numChannels; - channelID = channelUp.idx; - - } else { // no pre-selected subband, cycle through size-8 (or size-9) blocks - channelUp.enabled = true; - uint8_t numBlocks = this->band->txSpans[0].numChannels / 8; // calculate number of 8-channel blocks - uint8_t numBlockChannels = 8 + (this->band->numTxSpans == 2 ? 1 : 0); // add a 9th channel if there's a second span - uint8_t blockID = devNonce % numBlocks; // currently selected block (seed with devNonce) - channelID = this->phyLayer->random(numBlockChannels); // select randomly from these 8 or 9 channels - RADIOLIB_DEBUG_PRINTLN("blocks: %d, channels/block: %d, blockID: %d, channelID: %d", numBlocks, numBlockChannels, blockID, channelID); - - // if channel 0-7 is selected, retrieve this channel from span 0; otherwise span 1 - if(channelID < 8) { - spanID = 0; - channelUp.idx = blockID * 8 + channelID; - } else { - spanID = 1; - channelUp.idx = blockID; - } - channelUp.freq = this->band->txSpans[spanID].freqStart + channelUp.idx*this->band->txSpans[spanID].freqStep; + + LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.payload[0] = 0xFF; // same datarate and payload + + // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels + size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span + for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.payload[3] = chMaskCntl << 4; // NbTrans = 0 -> keep the same + memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); + (void)execMacCommand(&cmd); + // save the response as a MAC answer, as this signals execMacCommand() to store the masks contiguously + pushMacCommand(&cmd, &this->commandsUp); } - - // for fixed channel plans, the user-specified datarate is ignored and span-specific value must be used - drUp = this->band->txSpans[spanID].joinRequestDataRate; - - // derive the downlink channel and datarate from the uplink channel and datarate - channelDown.enabled = true; - channelDown.idx = channelID % this->band->rx1Span.numChannels; - channelDown.freq = this->band->rx1Span.freqStart + channelDown.idx*this->band->rx1Span.freqStep; - channelDown.drMin = this->band->rx1Span.drMin; - channelDown.drMax = this->band->rx1Span.drMax; - drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, channelDown.drMin, channelDown.drMax); - + // delete the ADR response + (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = channelUp; - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDown; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; return(RADIOLIB_ERR_NONE); } @@ -1869,9 +1812,7 @@ int16_t LoRaWANNode::selectChannels() { && this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { channelsEnabled[numChannels] = i; numChannels++; - } - } else { - break; + } } } if(numChannels == 0) { @@ -1886,7 +1827,7 @@ int16_t LoRaWANNode::selectChannels() { // for dynamic bands, the downlink channel is the one matched to the uplink channel this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; - } else { // RADIOLIB_LORAWAN_BAND_FIXED + } else { // RADIOLIB_LORAWAN_BAND_FIXED // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels LoRaWANChannel_t channelDn; channelDn.enabled = true; @@ -1918,7 +1859,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { } if(!isValidDR) { RADIOLIB_DEBUG_PRINTLN("No defined channel allows datarate %d", drUp); - return(RADIOLIB_ERR_DATA_RATE_INVALID); + return(RADIOLIB_ERR_INVALID_DATA_RATE); } LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; @@ -1926,13 +1867,13 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; cmd.payload[0] = (drUp << 4); cmd.payload[0] |= 0x0F; // keep Tx Power the same - cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same (void)execMacCommand(&cmd, saveToEeprom); // check if ACK is set for Tx Power if((cmd.payload[0] >> 1) != 1) { - return(RADIOLIB_ERR_DATA_RATE_INVALID); + return(RADIOLIB_ERR_INVALID_DATA_RATE); } return(RADIOLIB_ERR_NONE); @@ -2016,7 +1957,7 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; cmd.payload[0] = 0xF0; // keep datarate the same cmd.payload[0] |= txPowerNew; // set the Tx Power - cmd.payload[3] |= (1 << 7); // set the RFU bit, which means that the channel mask gets ignored + cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same (void)execMacCommand(&cmd, saveToEeprom); @@ -2227,65 +2168,17 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // (which is set on the internal MAC command when creating new session) if((cmd->payload[3] >> 7) == 0) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(chMaskCntl == 0) { - // if chMaskCntl == 0, apply the mask by looking at each channel bit - RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); - if(chMask & (1UL << i)) { - // if it should be enabled but is not currently defined, stop immediately - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - chMaskAck = 0; - break; - } - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - } else { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; - } + chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); - } else if(chMaskCntl == 6) { - // if chMaskCntl == 6, enable all defined channels - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - } - } - - } - } else { // RADIOLIB_LORAWAN_BAND_FIXED - // delete any prior ADR responses from the uplink queue, but do not care if none is present yet + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // if there was already an ADR response in the uplink MAC queue, + // this is a consecutive ADR command, so we delete the prior response int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); if(state == RADIOLIB_ERR_NONE) { - isSuccessive = true; // if we found an ADR Ans in the uplink MAC queue, this is a successive ADR MAC request + isSuccessive = true; } - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); - uint8_t num = 0; - uint8_t chNum = chMaskCntl*16; - uint8_t chSpan = 0; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("chNum: %d, chSpan: %d, i: %d, mask: %d", chNum, chSpan, i, chMask & (1UL << i)); - // if we must roll over to next span, reset chNum and move to next channel span - if(chNum >= this->band->txSpans[chSpan].numChannels) { - chNum = 0; - chSpan++; - } + chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, !isSuccessive); - if(chMask & (1UL << i)) { - if(chSpan >= this->band->numTxSpans) { - RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!"); - return(RADIOLIB_ERR_UNKNOWN); - } - LoRaWANChannel_t chnl; - chnl.enabled = true; - chnl.idx = chMaskCntl*16 + i; - chnl.freq = this->band->txSpans[chSpan].freqStart + chNum*this->band->txSpans[chSpan].freqStep; - chnl.drMin = this->band->txSpans[chSpan].drMin; - chnl.drMax = this->band->txSpans[chSpan].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = chnl; - // downlink channels are dynamically calculated on each uplink in selectChannels() - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", num, chnl.idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); - num++; - } - chNum++; - } } } @@ -2299,7 +2192,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { if(saveToEeprom) { uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte if((cmd->payload[3] >> 7) == 1) { mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID) + 1, &(cmd->payload[1]), 3); @@ -2310,23 +2202,31 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else { // read how many ADR masks are already stored - uint8_t macNumADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - - // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte + uint8_t numMacADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); + RADIOLIB_DEBUG_PRINTLN("[1] Successive: %d, numMacADR: %d, RFU: %d, payload: %02X %02X %02X %02X", + isSuccessive, numMacADR, (cmd->payload[3] >> 7), + cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); + // if RFU bit is set, this is just a change in Datarate or TxPower + // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it if((cmd->payload[3] >> 7) == 1) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + macNumADR * payLen + 1, &(cmd->payload[1]), 3); + if(numMacADR > 0) { + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen + 1, &(cmd->payload[1]), 3); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen, &(cmd->payload[0]), payLen); + } + } else { - if(isSuccessive) { - // saved another ADR mask, so increase counter - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, macNumADR + 1); - } else { - // this is the first ADR mask in this downlink, so (re)set counter to 1 - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, 1); + // if no previous mask was processed, reset counter to 0 + if(!isSuccessive) { + numMacADR = 0; } + // save to the uplink channel location, to the numMacADR-th slot of 4 bytes + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + numMacADR * payLen, &(cmd->payload[0]), payLen); + // saved an ADR mask, so increase counter + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, numMacADR + 1); } - - // save to the uplink channel location, to the macNumADR-th slot of 4 bytes - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + macNumADR * payLen, &(cmd->payload[0]), payLen); + RADIOLIB_DEBUG_PRINTLN("[2] Successive: %d, numMacADR: %d, RFU: %d, payload: %02X %02X %02X %02X", + isSuccessive, numMacADR, (cmd->payload[3] >> 7), + cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); } } #endif @@ -2627,6 +2527,204 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { return(false); } +bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(chMaskCntl == 0) { + // apply the mask by looking at each channel bit + RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); + if(chMask & (1UL << i)) { + // if it should be enabled but is not currently defined, stop immediately + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + return(false); + } + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } else { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; + } + + } else if(chMaskCntl == 6) { + // enable all defined channels + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } + } + + } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + + return(true); +} + +bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear) { + RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); + if(clear) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + } + // find out how many channels have already been configured + uint8_t idx = 0; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { + idx++; + } + } + + if((this->band->numTxSpans == 1 && chMaskCntl <= 5) || (this->band->numTxSpans == 2 && chMaskCntl <= 3)) { + // select channels from first span + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 16; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95 + this->subBand = chNum % 8; // keep track of configured subband in case we must reset the channels + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; + chnl.drMin = this->band->txSpans[0].drMin; + chnl.drMax = this->band->txSpans[0].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); + } + } + + } + if(this->band->numTxSpans == 1 && chMaskCntl == 6) { + // all channels on (but we revert to user-selected subband) + this->setupChannelsFix(this->subBand); + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 4) { + // select channels from second span + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + uint8_t chNum = chMaskCntl * 16 + i; // 64 through 71 + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx-1, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); + } + } + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 5) { + // a '1' enables a bank of 8 + 1 channels from 1st and 2nd span respectively + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + // enable bank of 8 channels from first span + for(uint8_t j = 0; j < 8; i++) { + uint8_t chNum = i * 8 + j; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; + chnl.drMin = this->band->txSpans[0].drMin; + chnl.drMax = this->band->txSpans[0].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); + } + // enable single channel from second span + uint8_t chNum = 64 + i; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); + } + } + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 6) { + // all channels on (but we revert to selected subband) + if(this->subBand >= 0) { + this->setupChannelsFix(this->subBand); + } + // a '1' enables a single channel from second span + LoRaWANChannel_t chnl; + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + // enable single channel from second span + uint8_t chNum = 64 + i; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); + } + } + + } + if(this->band->numTxSpans == 2 && chMaskCntl == 7) { + // all channels off (clear all channels) + LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl; + // downlink channels are not defined so don't need to reset + } + idx = 0; + // a '1' enables a single channel from second span + for(uint8_t i = 0; i < 8; i++) { + uint16_t mask = 1 << i; + if(mask & chMask) { + // enable single channel from second span + uint8_t chNum = 64 + i; + chnl.enabled = true; + chnl.idx = chNum; + chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; + chnl.drMin = this->band->txSpans[1].drMin; + chnl.drMax = this->band->txSpans[1].drMax; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); + } + } + + } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + + return(true); +} + uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { for (LoRaWANMacSpec_t entry : MacTable) { if (entry.cid == cid) { @@ -2752,7 +2850,10 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out } uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint8_t keyLen) { - uint16_t buf16[RADIOLIB_AES128_KEY_SIZE/2] = { 0 }; + if(keyLen > RADIOLIB_AES128_KEY_SIZE / 2) { + keyLen = RADIOLIB_AES128_KEY_SIZE / 2; + } + uint16_t buf16[RADIOLIB_AES128_KEY_SIZE / 2] = { 0 }; uint8_t bufLen = keyLen / 2; memcpy(buf16, key, keyLen); uint16_t checkSum = 0; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index de4b3ea0ac..e62ddb24c1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -79,7 +79,7 @@ #define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) #define RADIOLIB_LORAWAN_BAND_FIXED (1) #define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) -#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 1) // reserve first bit for enable-flag +#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 0) // recommended default settings #define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) @@ -403,8 +403,9 @@ class LoRaWANNode { \brief Default constructor. \param phy Pointer to the PhysicalLayer radio module. \param band Pointer to the LoRaWAN band to use. + \param subBand The subband to be used (starting from 1!) */ - LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band); + LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) /*! @@ -650,23 +651,6 @@ class LoRaWANNode { */ int16_t setTxPower(int8_t txPower, bool saveToEeprom = false); - /*! - \brief Select a single subband (8 channels) for fixed bands such as US915. - Only available before joining a network. - \param idx The subband to be used (starting from 1!) - \returns \ref status_codes - */ - int16_t selectSubband(uint8_t idx); - - /*! - \brief Select a set of channels for fixed bands such as US915. - Only available before joining a network. - \param startChannel The first channel of the band to be used (inclusive) - \param endChannel The last channel of the band to be used (inclusive) - \returns \ref status_codes - */ - int16_t selectSubband(uint8_t startChannel, uint8_t endChannel); - /*! \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. @@ -702,7 +686,7 @@ class LoRaWANNode { PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; - void beginCommon(); + void beginCommon(uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); LoRaWANMacCommandQueue_t commandsUp = { .numCommands = 0, @@ -803,7 +787,7 @@ class LoRaWANNode { bool isMACPayload = false; // save the selected subband in case this must be restored in ADR control - int8_t selectedSubband = -1; + int8_t subBand = -1; #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) /*! @@ -832,15 +816,20 @@ class LoRaWANNode { bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); // configure the common physical layer properties (preamble, sync word etc.) - // channels must be configured separately by setupChannels()! + // channels must be configured separately by setupChannelsDyn()! int16_t setPhyProperties(); // setup uplink/downlink channel data rates and frequencies - // will attempt to randomly select based on currently used band plan - int16_t setupChannels(uint8_t* cfList); + // for dynamic channels, there is a small set of predefined channels + // in case of JoinRequest, add some optional extra frequencies + int16_t setupChannelsDyn(bool joinRequest = false); + + // setup uplink/downlink channel data rates and frequencies + // for fixed bands, we only allow one subband at a time to be selected + int16_t setupChannelsFix(uint8_t subBand); - // select a set of semi-random TX/RX channels for the join-request and -accept message - int16_t selectChannelsJR(uint16_t devNonce, uint8_t drJoinSubband); + // a join-accept can piggy-back a set of channels or channel masks + int16_t processCFList(uint8_t* cfList); // select a set of random TX/RX channels for up- and downlink int16_t selectChannels(); @@ -864,6 +853,12 @@ class LoRaWANNode { // execute mac command, return the number of processed bytes for sequential processing bool execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom = true); + // apply a channel mask to a set of readily defined channels (dynamic bands only) + bool applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask); + + // define or delete channels from a fixed set of channels (fixed bands only) + bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear); + // get the payload length for a specific MAC command uint8_t getMacPayloadLength(uint8_t cid); From 3338034ac7966b7fe2cf45b5f8501c54651f5d45 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 13 Jan 2024 00:15:52 +0100 Subject: [PATCH 0869/1848] [LoRaWAN] Update examples --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 15 ++++++++------- .../LoRaWAN_End_Device_ABP.ino | 15 ++++++++------- .../LoRaWAN_End_Device_Persistent.ino | 8 ++++++++ .../LoRaWAN_End_Device_Reference.ino | 15 ++++++++------- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index 732da594ae..c755a8bd07 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -38,6 +38,14 @@ SX1278 radio = new Module(10, 2, 9, 3); // based on your geographical location! LoRaWANNode node(&radio, &EU868); +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + void setup() { Serial.begin(9600); @@ -78,13 +86,6 @@ void setup() { // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded // and can be set to NULL - // some frequency bands only use a subset of the available channels - // you can select the specific band or set the first channel and last channel - // for example, either of the following corresponds to US915 FSB2 in TTN - /* - node.selectSubband(2); - node.selectSubband(8, 15); - */ // on EEPROM-enabled boards, after the device has been activated, // the session can be restored without rejoining after device power cycle diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index 5ac9261f12..ec1252e9ed 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -39,6 +39,14 @@ SX1278 radio = new Module(10, 2, 9, 3); // based on your geographical location! LoRaWANNode node(&radio, &EU868); +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + void setup() { Serial.begin(9600); @@ -82,13 +90,6 @@ void setup() { // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded // and can be set to NULL - // some frequency bands only use a subset of the available channels - // you can select the specific band or set the first channel and last channel - // for example, either of the following corresponds to US915 FSB2 in TTN - /* - node.selectSubband(2); - node.selectSubband(8, 15); - */ // if using EU868 on ABP in TTN, you need to set the SF for RX2 window manually /* diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino index 672506c6bd..a475e72558 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino @@ -43,6 +43,14 @@ SX1278 radio = new Module(10, 2, 9, 3); // based on your geographical location! LoRaWANNode node(&radio, &EU868); +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + void setup() { Serial.begin(9600); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 2d8c84cf10..0507d5f2d4 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -41,6 +41,14 @@ SX1278 radio = new Module(10, 2, 9, 3); // based on your geographical location! LoRaWANNode node(&radio, &EU868); +// for fixed bands with subband selection +// such as US915 and AU915, you must specify +// the subband that matches the Frequency Plan +// that you selected on your LoRaWAN console +/* + LoRaWANNode node(&radio, &US915, 2); +*/ + void setup() { Serial.begin(9600); @@ -81,13 +89,6 @@ void setup() { // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded // and can be set to NULL - // some frequency bands only use a subset of the available channels - // you can select the specific band or set the first channel and last channel - // for example, either of the following corresponds to US915 FSB2 in TTN - /* - node.selectSubband(2); - node.selectSubband(8, 15); - */ // now we can start the activation // this can take up to 10 seconds, and requires a LoRaWAN gateway in range From 842c54849da573e041192db5bb2032f32f7e9ac3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 13 Jan 2024 13:39:51 +0100 Subject: [PATCH 0870/1848] [SX127x] Added setLowBatteryThreshold (#925) --- keywords.txt | 1 + src/modules/SX127x/SX127x.cpp | 22 ++++++++++++++++++++++ src/modules/SX127x/SX127x.h | 26 ++++++++++++++++++-------- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/keywords.txt b/keywords.txt index 065991a091..c68cc5bd0a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -182,6 +182,7 @@ setFifoFullAction KEYWORD2 clearFifoFullAction KEYWORD2 fifoAdd KEYWORD2 fifoGet KEYWORD2 +setLowBatteryThreshold KEYWORD2 # RF69-specific setAESKey KEYWORD2 diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 38953a145f..cdf68ad324 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1714,4 +1714,26 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { } } +int16_t SX127x::setLowBatteryThreshold(int8_t level, uint32_t pin) { + // check disable + if(level < 0) { + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_OFF, 3, 3)); + } + + // enable detector and set the threshold + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_ON | level, 3, 0); + RADIOLIB_ASSERT(state); + + // set DIO mapping + switch(pin) { + case(0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT, 7, 6)); + case(3): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT, 1, 0)); + case(4): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT, 7, 6)); + } + return(RADIOLIB_ERR_INVALID_DIO_PIN); +} + #endif diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index bf09b925c9..fd3d4a94a2 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -472,14 +472,14 @@ // RADIOLIB_SX127X_REG_LOW_BAT #define RADIOLIB_SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled #define RADIOLIB_SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_764_V 0b00000001 // 2 0 1.764 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_835_V 0b00000010 // 2 0 1.835 V (default) -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_905_V 0b00000011 // 2 0 1.905 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_1_976_V 0b00000100 // 2 0 1.976 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_045_V 0b00000101 // 2 0 2.045 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_116_V 0b00000110 // 2 0 2.116 V -#define RADIOLIB_SX127X_LOW_BAT_TRIM_2_185_V 0b00000111 // 2 0 2.185 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_764_V 0b00000001 // 2 0 1.764 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_835_V 0b00000010 // 2 0 1.835 V (default) +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_905_V 0b00000011 // 2 0 1.905 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_1_976_V 0b00000100 // 2 0 1.976 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_2_045_V 0b00000101 // 2 0 2.045 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_2_116_V 0b00000110 // 2 0 2.116 V +#define RADIOLIB_SX127X_LOW_BAT_THRESHOLD_2_185_V 0b00000111 // 2 0 2.185 V // RADIOLIB_SX127X_REG_IRQ_FLAGS_1 #define RADIOLIB_SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready @@ -1216,6 +1216,16 @@ class SX127x: public PhysicalLayer { */ int16_t setRSSIThreshold(float dbm); + /*! + \brief Set low battery indicator threshold. + \param level Battery threshold level (one of RADIOLIB_SX127X_LOW_BAT_THRESHOLD_*), + or -1 to disable the detector. Disabled by default. Note that this will not attach any interrupts! + \param pin DIO pin number which will be used to signal low battery. Only DIO0/4 can be used + (in packet mode) or DIO3/4 (in continuous mode). Ignored when disabling the detector. + \returns \ref status_codes + */ + int16_t setLowBatteryThreshold(int8_t level, uint32_t pin = RADIOLIB_NC); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif From ab41bcac002182a88895c3dc096f50fb46744a29 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sat, 13 Jan 2024 17:18:23 +0000 Subject: [PATCH 0871/1848] [CC1101] Correctly wait for packet end on blocking receive. When using a blocking receive, I was getting non-sensical packet length and garbage data, whereas IRQ mode was working fine. This was happening despite what looked like a workaround for this in the code which would read the length twice. I tracked it down to the receive function trying to read the data too early, before the packet had even been received. The receive function would wait for the GDO0 pin to become low, then assume the packet was ready and read off the data. However, the GD0 pin is set by the `startReceive` as inverted and, according to the datasheet, in a mode which "asserts when sync word has been received, and de-asserts at the end of the packet". In other words, taking into account the inversion, GDO0 becomes low at the start of the packet and high at the end of it. Therefore the receive function would actually try to read the packet data as soon as the packet had started, rather than wait until the end, explaining the garbage data. I suspect that with a slow MCU and a fast transmission rate, the previous workaround of reading the length field twice may have delayed the data read just enough to allow the packet to be fully received, but this does not work in the general case. This commit updates the logic by first waiting for a low signal, followed by a high one. This is actually the exact same logic used in the blocking transmit implementation, but inverted to account for the INV flag set on GDO0. The commit also removes the past workaround, since it should not be necessary anymore. --- src/modules/CC1101/CC1101.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index d36c3d2b90..fbfa212bc8 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -139,7 +139,7 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { int16_t state = startReceive(); RADIOLIB_ASSERT(state); - // wait for packet or timeout + // wait for packet start or timeout uint32_t start = this->mod->hal->micros(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); @@ -151,11 +151,16 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { } } - // for some reason, blocking receive will sometimes return impossible packet lengths - // reading packet length again in readData seems to resolve this - size_t length = getPacketLength(); - if((length == 0) || (length > RADIOLIB_CC1101_MAX_PACKET_LENGTH)) { - this->packetLengthQueried = false; + // wait for packet end or timeout + start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + + if(this->mod->hal->micros() - start > timeout) { + standby(); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + return(RADIOLIB_ERR_RX_TIMEOUT); + } } // read packet data From c1bf281f2149dc66129de3157ed1099e04517db6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:00:57 +0100 Subject: [PATCH 0872/1848] Bump version to 6.4.0 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index 9822a1c042..dd65132087 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.3.0", + "version": "6.4.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 8dda9bb6db..4685c4f0a4 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.3.0 +version=6.4.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index a95b6cdd1c..a981263a39 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -528,7 +528,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 6 -#define RADIOLIB_VERSION_MINOR 3 +#define RADIOLIB_VERSION_MINOR 4 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From 8c1d0521c5a145082842ce43ba56951fc1ebdb9e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:29:57 +0100 Subject: [PATCH 0873/1848] [SX127x] Removed extra semicolons --- src/modules/RFM2x/RFM22.h | 2 +- src/modules/RFM2x/RFM23.h | 2 +- src/modules/SX127x/SX1276.h | 4 ++-- src/modules/SX127x/SX1277.h | 2 +- src/modules/SX127x/SX1278.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/RFM2x/RFM22.h b/src/modules/RFM2x/RFM22.h index 12317017c1..95a8177af6 100644 --- a/src/modules/RFM2x/RFM22.h +++ b/src/modules/RFM2x/RFM22.h @@ -13,7 +13,7 @@ \class RFM22 \brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules. */ -RADIOLIB_TYPE_ALIAS(Si4432, RFM22); +RADIOLIB_TYPE_ALIAS(Si4432, RFM22) #endif diff --git a/src/modules/RFM2x/RFM23.h b/src/modules/RFM2x/RFM23.h index fb7f0591ee..fa28a07e0e 100644 --- a/src/modules/RFM2x/RFM23.h +++ b/src/modules/RFM2x/RFM23.h @@ -13,7 +13,7 @@ \class RFM23 \brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules. */ -RADIOLIB_TYPE_ALIAS(Si4431, RFM23); +RADIOLIB_TYPE_ALIAS(Si4431, RFM23) #endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index dd9907d5b8..c15f98128d 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -73,13 +73,13 @@ class SX1276: public SX1278 { \class RFM95 \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM95 and %SX1276 modules. */ -RADIOLIB_TYPE_ALIAS(SX1276, RFM95); +RADIOLIB_TYPE_ALIAS(SX1276, RFM95) /*! \class RFM96 \brief Only exists as alias for SX1276, since there seems to be no difference between %RFM96 and %SX1276 modules. */ -RADIOLIB_TYPE_ALIAS(SX1276, RFM96); +RADIOLIB_TYPE_ALIAS(SX1276, RFM96) #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 0289021fbe..fa2ac5acd9 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -87,7 +87,7 @@ class SX1277: public SX1278 { \class RFM97 \brief Only exists as alias for SX1277, since there seems to be no difference between %RFM97 and %SX1277 modules. */ -RADIOLIB_TYPE_ALIAS(SX1277, RFM97); +RADIOLIB_TYPE_ALIAS(SX1277, RFM97) #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 685f08ee35..2140430e03 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -305,7 +305,7 @@ class SX1278: public SX127x { \class RFM98 \brief Only exists as alias for SX1278, since there seems to be no difference between %RFM98 and %SX1278 modules. */ -RADIOLIB_TYPE_ALIAS(SX1278, RFM98); +RADIOLIB_TYPE_ALIAS(SX1278, RFM98) #endif From e392c7b91f834e8a9d10ecb11db4d13efcd5e073 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:31:24 +0100 Subject: [PATCH 0874/1848] [LoRaWAN] Fixed duty cycle enable ignored (CI_BUILD_ALL) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ba2c6be02b..dbf18ed3bd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1884,7 +1884,7 @@ void LoRaWANNode::setADR(bool enable) { } void LoRaWANNode::setDutyCycle(bool enable, uint32_t msPerHour) { - this->dutyCycleEnabled = true; + this->dutyCycleEnabled = enable; if(msPerHour <= 0) { this->dutyCycle = this->band->dutyCycle; } else { From be52cd8edd64e144adaa53f9dce8eae5994c7c3f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:33:17 +0100 Subject: [PATCH 0875/1848] [LoRaWAN] Fix possible integer overflow --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index dbf18ed3bd..130811e9f0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1898,7 +1898,7 @@ uint32_t LoRaWANNode::dutyCycleInterval(uint32_t msPerHour, uint32_t airtime) { if(msPerHour == 0 || airtime == 0) { return(0); } - uint32_t oneHourInMs = 60 * 60 * 1000; + uint32_t oneHourInMs = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000; float numPackets = msPerHour / airtime; uint32_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems return(delayMs); @@ -2244,7 +2244,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { if(maxDutyCycle == 0) { this->dutyCycle = this->band->dutyCycle; } else { - this->dutyCycle = 60 * 60 * 1000 / (1 << maxDutyCycle); + this->dutyCycle = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000 / (uint32_t)(1UL << maxDutyCycle); } #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) From 1681eeead30adf86a3c327a636193b7536d07e96 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:37:01 +0100 Subject: [PATCH 0876/1848] [LoRaWAN] Fix MAC command initialization --- src/protocols/LoRaWAN/LoRaWAN.cpp | 85 ++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 130811e9f0..7338f0b6dc 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -105,9 +105,12 @@ int16_t LoRaWANNode::restore() { RADIOLIB_ASSERT(state); // get MAC state - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); execMacCommand(&cmd, false); @@ -249,8 +252,12 @@ int16_t LoRaWANNode::restoreChannels() { uint8_t buffer[numBytes] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; for(int i = 0; i < numADRCommands; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; @@ -266,9 +273,12 @@ int16_t LoRaWANNode::restoreChannels() { #endif void LoRaWANNode::beginCommon(uint8_t joinDr) { - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { uint8_t drUp = 0; // if join datarate is user-specified and valid, select that value; otherwise use @@ -538,9 +548,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, + .repeat = 0, + }; cmd.payload[0] = dlSettings & 0x7F; uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); // default Rx2 frequency LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); @@ -1716,9 +1729,12 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { // chMask is set for 16 channels at once, so widen the Cntl value uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; // if there are two channel spans, first set the channel from second span if(this->band->numTxSpans == 2) { @@ -1765,8 +1781,12 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { num++; } - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; // datarate range for all new channels is equal to the default channels cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; for(uint8_t i = 0; i < 5; i++, num++) { @@ -1781,8 +1801,12 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; cmd.payload[0] = 0xFF; // same datarate and payload // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels @@ -1862,9 +1886,12 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { return(RADIOLIB_ERR_INVALID_DATA_RATE); } - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; cmd.payload[0] = (drUp << 4); cmd.payload[0] |= 0x0F; // keep Tx Power the same cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored @@ -1952,9 +1979,12 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { // e.g. on EU868, max is 16; if 13 is selected then we set to 12 uint8_t txPowerNew = (this->txPowerMax - txPower) / 2 + 1; - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; cmd.payload[0] = 0xF0; // keep datarate the same cmd.payload[0] |= txPowerNew; // set the Tx Power cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored @@ -2039,7 +2069,12 @@ bool LoRaWANNode::sendMacCommandReq(uint8_t cid) { if(!valid) return(false); - LoRaWANMacCommand_t cmd = { cid, 0, 0, 0 }; + LoRaWANMacCommand_t cmd = { + .cid = cid, + .payload = { 0 }, + .len = 0, + .repeat = 0, + }; pushMacCommand(&cmd, &this->commandsUp); return(true); } From 1467f98202c7ae1c91138e128d790595c0ba34a8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:37:48 +0100 Subject: [PATCH 0877/1848] [CI] Remove LoRaWAN from megaAVR platform --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b136960adc..1346f73d31 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -54,7 +54,9 @@ jobs: - id: arduino:mbed:envie_m4 run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:megaavr:uno2018 - run: echo "options=':mode=on'" >> $GITHUB_OUTPUT + run: | + echo "options=':mode=on'" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT - id: arduino:sam:arduino_due_x run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:samd:arduino_zero_native From b2d1306e9e03a8aeb1bd13d21583d182d5908446 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:40:23 +0100 Subject: [PATCH 0878/1848] [LoRaWAN] Simplify variable length arrays (CI_BUILD_ALL) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++------ src/protocols/LoRaWAN/LoRaWAN.h | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7338f0b6dc..f02677b78c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -218,12 +218,10 @@ int16_t LoRaWANNode::restoreChannels() { uint8_t bufferZeroes[5] = { 0 }; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { uint8_t numBytesUp = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - uint8_t bufferUp[numBytesUp] = { 0 }; + uint8_t bufferUp[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), bufferUp, numBytesUp); - LoRaWANMacCommand_t cmd = { 0, 0, 0, 0 }; - cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; - + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len); @@ -233,7 +231,7 @@ int16_t LoRaWANNode::restoreChannels() { } uint8_t numBytesDn = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - uint8_t bufferDn[numBytesDn] = { 0 }; + uint8_t bufferDn[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID), bufferDn, numBytesDn); cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; @@ -249,7 +247,7 @@ int16_t LoRaWANNode::restoreChannels() { } else { // RADIOLIB_LORAWAN_BAND_FIXED uint8_t numADRCommands = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - uint8_t buffer[numBytes] = { 0 }; + uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); LoRaWANMacCommand_t cmd = { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index e62ddb24c1..fdc8c6f99c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -191,6 +191,11 @@ // maximum allowed dwell time on bands that implement dwell time limitations #define RADIOLIB_LORAWAN_DWELL_TIME (400) +// Maximum MAC command sizes +#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) +#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) +#define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) + struct LoRaWANMacSpec_t { const uint8_t cid; const uint8_t lenDn; From d301aa6a3768d6527f0156469c4e8b01258076b3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:48:06 +0100 Subject: [PATCH 0879/1848] [SX126x] Fix txMode made private --- src/modules/SX126x/SX126x.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 8c9c35d243..f162dc932b 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1126,6 +1126,9 @@ class SX126x: public PhysicalLayer { #endif const char* chipType; uint8_t bandwidth = 0; + + // Allow subclasses to define different TX modes + uint8_t txMode = Module::MODE_TX; int16_t setFrequencyRaw(float freq); int16_t fixPaClamping(bool enable = true); @@ -1155,9 +1158,6 @@ class SX126x: public PhysicalLayer { size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; - // Allow subclasses to define different TX modes - uint8_t txMode = Module::MODE_TX; - int16_t config(uint8_t modem); bool findChip(const char* verStr); int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); From ea66037c1162b71f1ded95a4c88c7c68a6f72db5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 16:48:32 +0100 Subject: [PATCH 0880/1848] [STM32WL] Fix Module pinter (CI_BUILD_ALL) --- src/modules/SX126x/STM32WLx.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 313f8343b2..508ea4e591 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -45,8 +45,9 @@ int16_t STM32WLx::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // check the user did not request power output that is not possible - bool hp_supported = this->mod->findRfSwitchMode(MODE_TX_HP); - bool lp_supported = this->mod->findRfSwitchMode(MODE_TX_LP); + Module* mod = this->getMod(); + bool hp_supported = mod->findRfSwitchMode(MODE_TX_HP); + bool lp_supported = mod->findRfSwitchMode(MODE_TX_LP); if((!lp_supported && (power < -9)) || (!hp_supported && (power > 14))) { // LP not supported but requested power is below HP low bound or // HP not supported but requested power is above LP high bound From 3cbf6669df6614c72d901d2181532fe80c2373ef Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 17:00:24 +0100 Subject: [PATCH 0881/1848] [CI] Temporarily remove Teensy from CI (broken platform) (CI_BUILD_ALL) --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1346f73d31..ccf0d03031 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,6 @@ on: - rp2040:rp2040:rpipico - CubeCell:CubeCell:CubeCell-Board - MegaCore:avr:1281 - - teensy:avr:teensy41 - arduino:renesas_uno:minima jobs: From 718dae3f358e98baf136134cd2cc5198887dfd97 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 17:08:54 +0100 Subject: [PATCH 0882/1848] [CI] Temporarily remove Teensy (CI_BUILD_ALL) --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ccf0d03031..6a03953aed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,7 @@ on: - rp2040:rp2040:rpipico - CubeCell:CubeCell:CubeCell-Board - MegaCore:avr:1281 + - teensy:avr:teensy41 - arduino:renesas_uno:minima jobs: @@ -109,8 +110,6 @@ jobs: run: echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT - id: MegaCore:avr:1281 run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT - - id: teensy:avr:teensy41 - run: echo "index-url=--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT - id: arduino:renesas_uno:minima runs-on: ubuntu-latest From 132aae944f1ac6a4bdf1d887025a65ab9cb7be29 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 18:25:04 +0100 Subject: [PATCH 0883/1848] [LoRaWAN] Fix Module* not needed without persistent storage --- src/protocols/LoRaWAN/LoRaWAN.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index f02677b78c..54c36b197d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -661,9 +661,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { - Module* mod = this->phyLayer->getMod(); - #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + // only needed for persistent storage + Module* mod = this->phyLayer->getMod(); + // check if we actually need to restart from a clean session uint16_t checkSum = 0; checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); From 8c5ae6d2660a5690b8da16cc0fca7352fb510e1b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 18:25:51 +0100 Subject: [PATCH 0884/1848] [LoRaWAN] Remove variable length array (CI_BUILD_ALL) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 54c36b197d..931f3bdde8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1417,7 +1417,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // process FOpts (if there are any) if(foptsLen > 0) { // there are some Fopts, decrypt them - uint8_t fopts[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + uint8_t fopts[RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK]; // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload From efe303ca69463bac0b71d386e3717cf687e1af79 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 19:05:52 +0100 Subject: [PATCH 0885/1848] [LoRaWAN] Properly size fopts buffer --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 931f3bdde8..499d202734 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1417,7 +1417,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // process FOpts (if there are any) if(foptsLen > 0) { // there are some Fopts, decrypt them - uint8_t fopts[RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK]; + #if !RADIOLIB_STATIC_ONLY + uint8_t* fopts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + #else + uint8_t fopts[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload @@ -1462,6 +1466,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); } + #if !RADIOLIB_STATIC_ONLY + delete[] fopts; + #endif + RADIOLIB_DEBUG_PRINTLN("MAC response:"); for (int i = 0; i < this->commandsUp.numCommands; i++) { RADIOLIB_DEBUG_HEXDUMP(&(this->commandsUp.commands[i].cid), sizeof(LoRaWANMacCommand_t)); From 4c5321e5cb2e98717ac27963a3af0af6732ceb8b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Jan 2024 21:56:18 +0100 Subject: [PATCH 0886/1848] [SX1233] Fix incorrect exclude macro guard (#929) --- src/modules/SX123x/SX1233.cpp | 2 +- src/modules/SX123x/SX1233.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index 6acf5a7e36..ab8808f9a4 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -1,6 +1,6 @@ #include "SX1233.h" #include -#if !RADIOLIB_EXCLUDE_SX1233 +#if !RADIOLIB_EXCLUDE_SX1231 SX1233::SX1233(Module* mod) : SX1231(mod) { diff --git a/src/modules/SX123x/SX1233.h b/src/modules/SX123x/SX1233.h index c6f11d3f47..029b0cc217 100644 --- a/src/modules/SX123x/SX1233.h +++ b/src/modules/SX123x/SX1233.h @@ -3,7 +3,7 @@ #include "../../TypeDef.h" -#if !RADIOLIB_EXCLUDE_SX1233 +#if !RADIOLIB_EXCLUDE_SX1231 #include "../../Module.h" #include "../RF69/RF69.h" From 598228fba006d283d2e263bde90e055ef29b3251 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 20 Jan 2024 11:03:54 +0100 Subject: [PATCH 0887/1848] [LoRaWAN] Fix session restore throwing unnecessary error --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 2 +- .../LoRaWAN_End_Device_ABP.ino | 2 +- .../LoRaWAN_End_Device_Reference.ino | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index c755a8bd07..10af3b626d 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -102,7 +102,7 @@ void setup() { Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - if(state == RADIOLIB_ERR_NONE) { + if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index ec1252e9ed..0a6dfcf1d8 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -110,7 +110,7 @@ void setup() { // start the device by directly providing the encryption keys and device address Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey); - if(state == RADIOLIB_ERR_NONE) { + if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 0507d5f2d4..87d350b078 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -100,7 +100,7 @@ void setup() { Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - if(state == RADIOLIB_ERR_NONE) { + if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 499d202734..21a31819de 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -65,17 +65,17 @@ int16_t LoRaWANNode::restore() { // } (void)nvm_table_version; - // check the magic value - uint8_t lwMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID); + // check the mode value + uint16_t lwMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID); if(lwMode == RADIOLIB_LORAWAN_MODE_NONE) { #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("magic id not set (no saved session)"); + RADIOLIB_DEBUG_PRINTLN("mode value not set (no saved session)"); RADIOLIB_DEBUG_PRINTLN("first 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); #endif - // the magic value is not set, user will have to do perform the join procedure + // the mode value is not set, user will have to do perform the join procedure return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } @@ -396,7 +396,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe return(this->restore()); } else { #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Failed to restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); @@ -683,7 +683,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, return(this->restore()); } else { #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Failed to restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); From e558f541e1d19ae38a3e7d6c1633c80587faf68e Mon Sep 17 00:00:00 2001 From: Cameron Goddard Date: Sun, 21 Jan 2024 15:39:28 -0500 Subject: [PATCH 0888/1848] add Pico HAL --- examples/NonArduino/Pico/.gitignore | 1 + examples/NonArduino/Pico/CMakeLists.txt | 33 ++++ examples/NonArduino/Pico/PicoHal.h | 142 ++++++++++++++++++ examples/NonArduino/Pico/main.cpp | 102 +++++++++++++ .../NonArduino/Pico/pico_sdk_import.cmake | 73 +++++++++ 5 files changed, 351 insertions(+) create mode 100644 examples/NonArduino/Pico/.gitignore create mode 100644 examples/NonArduino/Pico/CMakeLists.txt create mode 100644 examples/NonArduino/Pico/PicoHal.h create mode 100644 examples/NonArduino/Pico/main.cpp create mode 100644 examples/NonArduino/Pico/pico_sdk_import.cmake diff --git a/examples/NonArduino/Pico/.gitignore b/examples/NonArduino/Pico/.gitignore new file mode 100644 index 0000000000..d16386367f --- /dev/null +++ b/examples/NonArduino/Pico/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/examples/NonArduino/Pico/CMakeLists.txt b/examples/NonArduino/Pico/CMakeLists.txt new file mode 100644 index 0000000000..e58520ff3d --- /dev/null +++ b/examples/NonArduino/Pico/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.18) + +# Pull in SDK (must be before project) +include(pico_sdk_import.cmake) + +project(pico-sx1276 C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +# Initialize the SDK +pico_sdk_init() + +add_compile_options( + -Wall + -Wno-format + -Wno-unused-function +) + +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +add_executable(${PROJECT_NAME} + main.cpp +) + +# Pull in common dependencies +target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer RadioLib) + + +pico_enable_stdio_usb(${PROJECT_NAME} 1) +pico_enable_stdio_uart(${PROJECT_NAME} 0) + +# Create map/bin/hex file etc. +pico_add_extra_outputs(${PROJECT_NAME}) \ No newline at end of file diff --git a/examples/NonArduino/Pico/PicoHal.h b/examples/NonArduino/Pico/PicoHal.h new file mode 100644 index 0000000000..c474b43d83 --- /dev/null +++ b/examples/NonArduino/Pico/PicoHal.h @@ -0,0 +1,142 @@ +#ifndef PICO_HAL_H +#define PICO_HAL_H + +// include RadioLib +#include + +// include the necessary Pico libraries +#include +#include "hardware/spi.h" +#include "hardware/timer.h" + +// create a new Raspberry Pi Pico hardware abstraction +// layer using the Pico SDK +// the HAL must inherit from the base RadioLibHal class +// and implement all of its virtual methods +class PicoHal : public RadioLibHal { +public: + PicoHal(spi_inst_t *spiChannel, uint32_t misoPin, uint32_t mosiPin, uint32_t sckPin, uint32_t spiSpeed = 500 * 1000) + : RadioLibHal(GPIO_IN, GPIO_OUT, 0, 1, GPIO_IRQ_EDGE_RISE, GPIO_IRQ_EDGE_FALL), + _spiChannel(spiChannel), + _spiSpeed(spiSpeed), + _misoPin(misoPin), + _mosiPin(mosiPin), + _sckPin(sckPin) { + } + + void init() override { + stdio_init_all(); + spiBegin(); + } + + void term() override { + spiEnd(); + } + + // GPIO-related methods (pinMode, digitalWrite etc.) should check + // RADIOLIB_NC as an alias for non-connected pins + void pinMode(uint32_t pin, uint32_t mode) override { + if (pin == RADIOLIB_NC) { + return; + } + + gpio_set_dir(pin, mode); + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + if (pin == RADIOLIB_NC) { + return; + } + + gpio_put(pin, (bool)value); + } + + uint32_t digitalRead(uint32_t pin) override { + if (pin == RADIOLIB_NC) { + return 0; + } + + return gpio_get(pin); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + if (interruptNum == RADIOLIB_NC) { + return; + } + + gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)interruptCb); + } + + void detachInterrupt(uint32_t interruptNum) override { + if (interruptNum == RADIOLIB_NC) { + return; + } + + gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL); + } + + void delay(unsigned long ms) override { + sleep_ms(ms); + } + + void delayMicroseconds(unsigned long us) override { + sleep_us(us); + } + + unsigned long millis() override { + return to_ms_since_boot(get_absolute_time()); + } + + unsigned long micros() override { + return to_us_since_boot(get_absolute_time()); + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + if (pin == RADIOLIB_NC) { + return 0; + } + + this->pinMode(pin, GPIO_IN); + uint32_t start = this->micros(); + uint32_t curtick = this->micros(); + + while (this->digitalRead(pin) == state) { + if ((this->micros() - curtick) > timeout) { + return 0; + } + } + + return (this->micros() - start); + } + + void spiBegin() { + spi_init(_spiChannel, _spiSpeed); + spi_set_format(_spiChannel, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); + + gpio_set_function(_sckPin, GPIO_FUNC_SPI); + gpio_set_function(_mosiPin, GPIO_FUNC_SPI); + gpio_set_function(_misoPin, GPIO_FUNC_SPI); + } + + void spiBeginTransaction() {} + + void spiTransfer(uint8_t *out, size_t len, uint8_t *in) { + spi_write_read_blocking(_spiChannel, out, in, len); + } + + void spiEndTransaction() {} + + void spiEnd() { + spi_deinit(_spiChannel); + } + +private: + // the HAL can contain any additional private members + spi_inst_t *_spiChannel; + uint32_t _spiSpeed; + uint32_t _misoPin; + uint32_t _mosiPin; + uint32_t _sckPin; +}; + +#endif \ No newline at end of file diff --git a/examples/NonArduino/Pico/main.cpp b/examples/NonArduino/Pico/main.cpp new file mode 100644 index 0000000000..282831fc80 --- /dev/null +++ b/examples/NonArduino/Pico/main.cpp @@ -0,0 +1,102 @@ +/* + RadioLib Non-Arduino Raspberry Pi Pico library example + + Licensed under the MIT License + + Copyright (c) 2024 Cameron Goddard + + 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. +*/ + +// define pins to be used +#define SPI_PORT spi0 +#define SPI_MISO 4 +#define SPI_MOSI 3 +#define SPI_SCK 2 + +#define RFM_NSS 26 +#define RFM_RST 22 +#define RFM_DIO0 14 +#define RFM_DIO1 15 + +#include + +// include the library +#include + +// include the hardware abstraction layer +#include "PicoHal.h" + +// create a new instance of the HAL class +PicoHal* hal = new PicoHal(SPI_PORT, SPI_MISO, SPI_MOSI, SPI_SCK); + +// now we can create the radio module +// NSS pin: 26 +// DIO0 pin: 14 +// RESET pin: 22 +// DIO1 pin: 15 +SX1276 radio = new Module(hal, RFM_NSS, RFM_DIO0, RFM_RST, RFM_DIO1); + + +int main() { + stdio_init_all(); + + gpio_init(RFM_NSS); + gpio_init(RFM_RST); + + gpio_set_dir(RFM_NSS, GPIO_OUT); + gpio_set_dir(RFM_RST, GPIO_OUT); + + // reset the RF module + + sleep_ms(10); + gpio_put(RFM_RST, 0); + sleep_ms(10); + gpio_put(RFM_RST, 1); + + // initialize just like with Arduino + printf("[SX1276] Initializing ... "); + int state = radio.begin(); + if (state != RADIOLIB_ERR_NONE) { + printf("failed, code %d\n", state); + return(1); + } + printf("success!\n"); + + // loop forever + for(;;) { + // send a packet + printf("[SX1276] Transmitting packet ... "); + state = radio.transmit("Hello World!"); + if(state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + printf("success!\n"); + + // wait for a second before transmitting again + hal->delay(1000); + + } else { + printf("failed, code %d\n", state); + + } + + } + + return(0); +} diff --git a/examples/NonArduino/Pico/pico_sdk_import.cmake b/examples/NonArduino/Pico/pico_sdk_import.cmake new file mode 100644 index 0000000000..65f8a6f7db --- /dev/null +++ b/examples/NonArduino/Pico/pico_sdk_import.cmake @@ -0,0 +1,73 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) From 6979bff863a64b5cf072bef1a80e435c5ec1adc3 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 22 Jan 2024 11:40:57 +0100 Subject: [PATCH 0889/1848] [LoRaWAN] Improve channel masks for fixed bands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 81 +++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 21a31819de..b4ae4ba07f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -111,8 +111,12 @@ int16_t LoRaWANNode::restore() { .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, .repeat = 0, }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + + // only apply the single ADR command on dynamic bands; fixed bands is done through channel restore + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); + execMacCommand(&cmd, false); + } cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; @@ -207,7 +211,7 @@ int16_t LoRaWANNode::restoreFcntUp() { } int16_t LoRaWANNode::restoreChannels() { - // first do the default channels + // first do the default channels, in case these are not covered by restored channels if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(false); } else { // RADIOLIB_LORAWAN_BAND_FIXED @@ -226,6 +230,7 @@ int16_t LoRaWANNode::restoreChannels() { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + cmd.repeat = 1; (void)execMacCommand(&cmd, false); } } @@ -262,6 +267,7 @@ int16_t LoRaWANNode::restoreChannels() { memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len); // there COULD, according to spec, be an all zeroes ADR command - meh if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { + cmd.repeat = (i+1); execMacCommand(&cmd, false); } } @@ -1436,19 +1442,36 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) RADIOLIB_DEBUG_PRINTLN("fopts:"); RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); + bool hasADR = false; + uint8_t numADR = 0; + uint8_t lastCID = 0; + // process the MAC command(s) int8_t remLen = foptsLen; uint8_t* foptsPtr = fopts; while(remLen > 0) { uint8_t cid = *foptsPtr; uint8_t macLen = getMacPayloadLength(cid); + if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + // if there was an earlier ADR command but it was not the last, ignore it + if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { + RADIOLIB_DEBUG_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); + remLen -= (macLen + 1); + foptsPtr += (macLen + 1); + lastCID = cid; + continue; + } + // otherwise, set ADR flag to true and increase counter + hasADR = true; + numADR++; + } if(macLen + 1 > remLen) break; LoRaWANMacCommand_t cmd = { .cid = cid, .payload = { 0 }, .len = macLen, - .repeat = 0, + .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), }; memcpy(cmd.payload, foptsPtr + 1, macLen); RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", @@ -1463,6 +1486,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // processing succeeded, move in the buffer to the next command remLen -= (macLen + 1); foptsPtr += (macLen + 1); + lastCID = cid; RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); } @@ -1736,6 +1760,8 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { // chMask is set for 16 channels at once, so widen the Cntl value uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset + uint8_t numADR = 1; + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, @@ -1752,6 +1778,7 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { cmd.payload[2] = 0; cmd.payload[3] = (7 << 4); // set the chMaskCntl value to all channels off cmd.payload[3] |= 0; // keep NbTrans the same + cmd.repeat = numADR++; (void)execMacCommand(&cmd, false); } @@ -1770,6 +1797,7 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { } cmd.payload[3] = (chMaskCntl << 4); // set the chMaskCntl value cmd.payload[3] |= 0; // keep NbTrans the same + cmd.repeat = numADR++; (void)execMacCommand(&cmd, false); return(RADIOLIB_ERR_NONE); @@ -2204,7 +2232,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } } - bool isSuccessive = false; + uint8_t chMaskAck = 1; // only apply channel mask when the RFU bit is not set // (which is set on the internal MAC command when creating new session) @@ -2213,13 +2241,17 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); } else { // RADIOLIB_LORAWAN_BAND_FIXED - // if there was already an ADR response in the uplink MAC queue, - // this is a consecutive ADR command, so we delete the prior response - int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); - if(state == RADIOLIB_ERR_NONE) { - isSuccessive = true; + bool clearChannels = false; + if(cmd->repeat == 1) { + // if this is the first ADR command in the queue, clear all saved channels + // so we can apply the new channel mask + clearChannels = true; + } else { + // if this is not the first ADR command, clear the ADR response that was in the queue + (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } - chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, !isSuccessive); + RADIOLIB_DEBUG_PRINTLN("ADR mask: clearing channels"); + chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, clearChannels); } } @@ -2242,32 +2274,28 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // save to the single ADR MAC location mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); - } else { - // read how many ADR masks are already stored - uint8_t numMacADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - RADIOLIB_DEBUG_PRINTLN("[1] Successive: %d, numMacADR: %d, RFU: %d, payload: %02X %02X %02X %02X", - isSuccessive, numMacADR, (cmd->payload[3] >> 7), + } else { // RADIOLIB_LORAWAN_BAND_FIXED + RADIOLIB_DEBUG_PRINTLN("[1] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", + cmd->repeat, (cmd->payload[3] >> 7), cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); // if RFU bit is set, this is just a change in Datarate or TxPower // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it if((cmd->payload[3] >> 7) == 1) { + // read how many ADR masks are already stored + uint8_t numMacADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); if(numMacADR > 0) { mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen + 1, &(cmd->payload[1]), 3); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen, &(cmd->payload[0]), payLen); } } else { - // if no previous mask was processed, reset counter to 0 - if(!isSuccessive) { - numMacADR = 0; - } - // save to the uplink channel location, to the numMacADR-th slot of 4 bytes - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + numMacADR * payLen, &(cmd->payload[0]), payLen); - // saved an ADR mask, so increase counter - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, numMacADR + 1); + // save to the uplink channel location, to the cmd->repeat-th slot of 4 bytes + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (cmd->repeat - 1) * payLen, &(cmd->payload[0]), payLen); + // saved an ADR mask, so re-store counter + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat); } - RADIOLIB_DEBUG_PRINTLN("[2] Successive: %d, numMacADR: %d, RFU: %d, payload: %02X %02X %02X %02X", - isSuccessive, numMacADR, (cmd->payload[3] >> 7), + RADIOLIB_DEBUG_PRINTLN("[2] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", + cmd->repeat, (cmd->payload[3] >> 7), cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); } } @@ -2276,6 +2304,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // send the reply cmd->len = 1; cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); + cmd->repeat = 0; // discard any repeat value that may have been set RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); return(true); } break; From 4ec10a47498ef2beaad6ea9d41ecae8032fd0175 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 22 Jan 2024 12:32:15 +0100 Subject: [PATCH 0890/1848] [LoRaWAN] Fix fixed band CFList processing --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b4ae4ba07f..02f5034d97 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1849,13 +1849,11 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; cmd.payload[3] = chMaskCntl << 4; // NbTrans = 0 -> keep the same + cmd.repeat = (chMaskCntl + 1); memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); (void)execMacCommand(&cmd); - // save the response as a MAC answer, as this signals execMacCommand() to store the masks contiguously - pushMacCommand(&cmd, &this->commandsUp); } // delete the ADR response - (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } return(RADIOLIB_ERR_NONE); @@ -2246,11 +2244,11 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask clearChannels = true; + RADIOLIB_DEBUG_PRINTLN("ADR mask: clearing channels"); } else { // if this is not the first ADR command, clear the ADR response that was in the queue (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } - RADIOLIB_DEBUG_PRINTLN("ADR mask: clearing channels"); chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, clearChannels); } From aedf519ea4c86ee3d2bbb09a7ba3350821131569 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 22 Jan 2024 12:53:18 +0100 Subject: [PATCH 0891/1848] [LoRaWAN] Fix rejoining during active session --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 02f5034d97..5ad8bcc76c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -277,6 +277,11 @@ int16_t LoRaWANNode::restoreChannels() { #endif void LoRaWANNode::beginCommon(uint8_t joinDr) { + // in case a new session is started while there is an ongoing session + // clear the MAC queues completely + memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); + memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, @@ -1733,6 +1738,11 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } } + + // clear all remaining channels + for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } return(RADIOLIB_ERR_NONE); } From ee542c3b564cbb96d0c06c9aa6c84e2ddec517c0 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 22 Jan 2024 13:34:00 +0100 Subject: [PATCH 0892/1848] [LoRaWAN] Fix dynamic-band non-ADR session persistance --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 5ad8bcc76c..b0d92a49d8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2278,6 +2278,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { if((cmd->payload[3] >> 7) == 1) { mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID) + 1, &(cmd->payload[1]), 3); } + // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again + if(cmd->payload[1] == 0 && cmd->payload[2] == 0) { + cmd->payload[3] |= (1 << 7); + } // save to the single ADR MAC location mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); From 9008fb00a78220c8b7662c21806812f961df9146 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 22 Jan 2024 14:38:35 +0100 Subject: [PATCH 0893/1848] [LoRaWAN] Fix setDatarate function --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b0d92a49d8..640b35bcb0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1918,7 +1918,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); if(chnl->enabled) { - if(drUp > chnl->drMin && drUp < chnl->drMax) { + if(drUp >= chnl->drMin && drUp <= chnl->drMax) { isValidDR = true; break; } From 51ab103d07acfc6f61d11759553725c84cf3327c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 23 Jan 2024 09:04:25 +0100 Subject: [PATCH 0894/1848] [LoRaWAN] Keep Dev/JoinNonce on OTAA wipe with same credentials --- src/protocols/LoRaWAN/LoRaWAN.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 640b35bcb0..5984653c95 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -400,12 +400,21 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; - if(!force && validCheckSum && validMode) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); - - return(this->restore()); - } else { + if(validCheckSum && validMode) { + if(!force) { + // the device has joined already, we can just pull the data from persistent storage + RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); + return(this->restore()); + + } else { + // the credentials are still the same, so restore only DevNonce and JoinNonce + this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); + this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); + } + } + + // if forced by user, keys are new or changed mode, wipe the previous session + if(force || !validCheckSum || !validMode) { #if RADIOLIB_DEBUG RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); @@ -657,6 +666,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // save join-request parameters mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); this->saveSession(); @@ -766,14 +776,10 @@ bool LoRaWANNode::isJoined() { #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) int16_t LoRaWANNode::saveSession() { Module* mod = this->phyLayer->getMod(); - - // store session configuration (MAC commands) + if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID) != this->rev) mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID) != this->devNonce) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); - // store all frame counters if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); From b98a5c6b292d14448d71d360301ee87fd78bf740 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Wed, 24 Jan 2024 08:46:10 +0100 Subject: [PATCH 0895/1848] [LoRaWAN] Fix Tx power calculation --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 5984653c95..76497cfc88 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2026,7 +2026,7 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { // Tx Power is set in steps of two // the selected value is rounded down to nearest multiple of two away from txPowerMax // e.g. on EU868, max is 16; if 13 is selected then we set to 12 - uint8_t txPowerNew = (this->txPowerMax - txPower) / 2 + 1; + uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM); LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, @@ -2035,7 +2035,7 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { .repeat = 0, }; cmd.payload[0] = 0xF0; // keep datarate the same - cmd.payload[0] |= txPowerNew; // set the Tx Power + cmd.payload[0] |= numSteps; // set the Tx Power cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same (void)execMacCommand(&cmd, saveToEeprom); From eaa42b0d6b1e0a198a003918a08c0fb1ddcde0a5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 14:03:40 +0100 Subject: [PATCH 0896/1848] Update RPi Pico SDK example --- examples/NonArduino/Pico/PicoHal.h | 1 + examples/NonArduino/Pico/build.sh | 8 ++++++++ examples/NonArduino/Pico/clean.sh | 3 +++ examples/NonArduino/Pico/main.cpp | 16 ---------------- 4 files changed, 12 insertions(+), 16 deletions(-) create mode 100755 examples/NonArduino/Pico/build.sh create mode 100755 examples/NonArduino/Pico/clean.sh diff --git a/examples/NonArduino/Pico/PicoHal.h b/examples/NonArduino/Pico/PicoHal.h index c474b43d83..d01842574c 100644 --- a/examples/NonArduino/Pico/PicoHal.h +++ b/examples/NonArduino/Pico/PicoHal.h @@ -40,6 +40,7 @@ class PicoHal : public RadioLibHal { return; } + gpio_init(pin); gpio_set_dir(pin, mode); } diff --git a/examples/NonArduino/Pico/build.sh b/examples/NonArduino/Pico/build.sh new file mode 100755 index 0000000000..1a556bf4c2 --- /dev/null +++ b/examples/NonArduino/Pico/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e +mkdir -p build +cd build +cmake .. +make +cd .. diff --git a/examples/NonArduino/Pico/clean.sh b/examples/NonArduino/Pico/clean.sh new file mode 100755 index 0000000000..27cfe2641d --- /dev/null +++ b/examples/NonArduino/Pico/clean.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf ./build diff --git a/examples/NonArduino/Pico/main.cpp b/examples/NonArduino/Pico/main.cpp index 282831fc80..28b32251c1 100644 --- a/examples/NonArduino/Pico/main.cpp +++ b/examples/NonArduino/Pico/main.cpp @@ -53,23 +53,7 @@ PicoHal* hal = new PicoHal(SPI_PORT, SPI_MISO, SPI_MOSI, SPI_SCK); // DIO1 pin: 15 SX1276 radio = new Module(hal, RFM_NSS, RFM_DIO0, RFM_RST, RFM_DIO1); - int main() { - stdio_init_all(); - - gpio_init(RFM_NSS); - gpio_init(RFM_RST); - - gpio_set_dir(RFM_NSS, GPIO_OUT); - gpio_set_dir(RFM_RST, GPIO_OUT); - - // reset the RF module - - sleep_ms(10); - gpio_put(RFM_RST, 0); - sleep_ms(10); - gpio_put(RFM_RST, 1); - // initialize just like with Arduino printf("[SX1276] Initializing ... "); int state = radio.begin(); From 9053786c02c114885b68f30eb29d9a8122409585 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 14:03:58 +0100 Subject: [PATCH 0897/1848] Added RPi Pico build to CI --- .github/workflows/main.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a03953aed..9c20211913 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -261,3 +261,27 @@ jobs: ./clean.sh ./build.sh sudo ./build/rpi-sx1261 + + rpi-pico-build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies + run: | + sudo apt update + sudo apt install git cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib + + - name: Clone the SDK + run: | + mkdir -p ~/rpi-pico + cd ~/rpi-pico + git clone https://github.com/raspberrypi/pico-sdk.git + cd pico-sdk && git checkout 1.5.1 + export PICO_SDK_PATH=~/rpi-pico/pico-sdk + + - name: Build the example + run: | + cd $PWD/examples/NonArduino/Pico + ./build.sh From 1025abce8b4d26fdf58d7aec5a2511b6f78e884b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 14:07:46 +0100 Subject: [PATCH 0898/1848] [CI] Fixed SDK path export --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9c20211913..e55b6d4c5e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -279,9 +279,9 @@ jobs: cd ~/rpi-pico git clone https://github.com/raspberrypi/pico-sdk.git cd pico-sdk && git checkout 1.5.1 - export PICO_SDK_PATH=~/rpi-pico/pico-sdk - name: Build the example run: | + export PICO_SDK_PATH=~/rpi-pico/pico-sdk cd $PWD/examples/NonArduino/Pico ./build.sh From b734e23460cced8e6224fbdec6caa6645c7b8f99 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:23:52 +0100 Subject: [PATCH 0899/1848] [PHY] Added data rate check method --- keywords.txt | 1 + src/protocols/PhysicalLayer/PhysicalLayer.cpp | 5 +++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/keywords.txt b/keywords.txt index a50032e3b7..ace5e99326 100644 --- a/keywords.txt +++ b/keywords.txt @@ -286,6 +286,7 @@ clearPacketReceivedAction KEYWORD2 setPacketSentAction KEYWORD2 clearPacketSentAction KEYWORD2 setDataRate KEYWORD2 +checkDataRate KEYWORD2 # BellModem setModem KEYWORD2 diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 8b99932576..f5ca56caf7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -272,6 +272,11 @@ int16_t PhysicalLayer::setDataRate(DataRate_t dr) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::checkDataRate(DataRate_t dr) { + (void)dr; + return(RADIOLIB_ERR_UNSUPPORTED); +} + float PhysicalLayer::getFreqStep() const { return(this->freqStep); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 513a3e1d41..4847b826dc 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -278,6 +278,13 @@ class PhysicalLayer { */ virtual int16_t setDataRate(DataRate_t dr); + /*! + \brief Check the data rate can be configured by this module. Must be implemented in module class if the module supports it. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + virtual int16_t checkDataRate(DataRate_t dr); + /*! \brief Gets the module frequency step size that was set in constructor. \returns Synthesizer frequency step size in Hz. From a4b148d60929ef1a7ada4f26084939f3c1dcc795 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:45:37 +0100 Subject: [PATCH 0900/1848] [SX127x] Implemented data rate check --- src/modules/SX127x/SX1272.cpp | 23 ++++++++++++++++++++++- src/modules/SX127x/SX1272.h | 7 +++++++ src/modules/SX127x/SX1273.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1273.h | 7 +++++++ src/modules/SX127x/SX1277.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1277.h | 7 +++++++ src/modules/SX127x/SX1278.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1278.h | 7 +++++++ 8 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 8864297e89..2c951401b4 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -252,6 +252,27 @@ int16_t SX1272::setDataRate(DataRate_t dr) { return(state); } +int16_t SX1272::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + } + + return(state); +} + int16_t SX1272::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } @@ -306,7 +327,7 @@ int16_t SX1272::setGain(uint8_t gain) { // get modem int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA){ + if(modem == RADIOLIB_SX127X_LORA) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 974fa16bdb..3ea740acb5 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -183,6 +183,13 @@ class SX1272: public SX127x { \returns \ref status_codes */ int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; /*! \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index c3ae5eda9c..6edc8e4b5f 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -92,4 +92,25 @@ int16_t SX1273::setDataRate(DataRate_t dr) { return(state); } +int16_t SX1273::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + } + + return(state); +} + #endif diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 12bd05df3c..610bbccf7e 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -55,6 +55,13 @@ class SX1273: public SX1272 { \returns \ref status_codes */ int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 76bbb0f61b..d808906645 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -134,4 +134,25 @@ int16_t SX1277::setDataRate(DataRate_t dr) { return(state); } +int16_t SX1277::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + } + + return(state); +} + #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index fa2ac5acd9..1d334cdca1 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -76,6 +76,13 @@ class SX1277: public SX1278 { \returns \ref status_codes */ int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 560a10bcdd..f20867ac68 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -266,6 +266,27 @@ int16_t SX1278::setDataRate(DataRate_t dr) { return(state); } +int16_t SX1278::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_FSK_OOK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + } + + } else if(modem == RADIOLIB_SX127X_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + } + + return(state); +} + int16_t SX1278::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 2140430e03..979edb75a1 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -193,6 +193,13 @@ class SX1278: public SX127x { \returns \ref status_codes */ int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; /*! \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). From a642f5a8dff5020d259faf0f51a62f51a30e7271 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:46:22 +0100 Subject: [PATCH 0901/1848] [SX126x] Implemented data rate check --- src/modules/SX126x/SX126x.cpp | 19 +++++++++++++++++++ src/modules/SX126x/SX126x.h | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 888542e8d0..ec508049f3 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -980,6 +980,25 @@ int16_t SX126x::setDataRate(DataRate_t dr) { return(state); } +int16_t SX126x::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + } + + return(state); +} + int16_t SX126x::setRxBandwidth(float rxBw) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index f162dc932b..f02d5f7d39 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -778,6 +778,13 @@ class SX126x: public PhysicalLayer { */ int16_t setDataRate(DataRate_t dr) override; + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + /*! \brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. From f109fd015899a1f26019712395257b87f8188989 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:47:05 +0100 Subject: [PATCH 0902/1848] [LLCC68] Fixed set data rate for LLCC68 (#946) --- src/modules/LLCC68/LLCC68.cpp | 61 +++++++++++++++++++++++++++++++++++ src/modules/LLCC68/LLCC68.h | 14 ++++++++ 2 files changed, 75 insertions(+) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 30c12ec823..516a854a06 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -53,4 +53,65 @@ int16_t LLCC68::setSpreadingFactor(uint8_t sf) { return(SX1262::setSpreadingFactor(sf)); } +int16_t LLCC68::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + } + + return(state); +} + +int16_t LLCC68::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01; + switch (bw_div2) { + case 62: // 125.0: + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + case 125: // 250.0 + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + case 250: // 500.0 + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 11, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + } + + return(state); +} + #endif diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 0ed55902b6..3a737060fb 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -56,6 +56,20 @@ class LLCC68: public SX1262 { */ int16_t setSpreadingFactor(uint8_t sf); + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + #if !RADIOLIB_GODMODE private: #endif From f35e3282f5adf0164315875440646ba2047573c2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:47:40 +0100 Subject: [PATCH 0903/1848] [LoRaWAN] Added ADR data rate check (#946) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 76497cfc88..6c8d9506a3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2198,6 +2198,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } break; case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { + int16_t state = RADIOLIB_ERR_UNKNOWN; // get the ADR configuration // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state // but we don't bother and try to set each individual command @@ -2217,12 +2218,22 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; - drAck = 1; - } + // check if the module supports this data rate + DataRate_t dr = { 0 }; + findDataRate(drUp, &dr); + state = this->phyLayer->checkDataRate(dr); + if(state == RADIOLIB_ERR_NONE) { + uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + drAck = 1; + } else { + RADIOLIB_DEBUG_PRINTLN("ADR failed to configure dataRate = %d!", drUp); + } + + } // try to apply the power configuration uint8_t pwrAck = 0; @@ -2234,7 +2245,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else { int8_t pwr = this->txPowerMax - 2*txPower; - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; + state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { // go from the highest power and lower it until we hit one supported by the module state = this->phyLayer->setOutputPower(pwr--); From 1c8d2d5cfb53d873879824ac4fc358194148c7c3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:49:34 +0100 Subject: [PATCH 0904/1848] [LoRaWAN] Typo fixes --- src/protocols/LoRaWAN/LoRaWAN.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index fdc8c6f99c..b881501dfa 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -408,7 +408,7 @@ class LoRaWANNode { \brief Default constructor. \param phy Pointer to the PhysicalLayer radio module. \param band Pointer to the LoRaWAN band to use. - \param subBand The subband to be used (starting from 1!) + \param subBand The sub-band to be used (starting from 1!) */ LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); @@ -624,7 +624,7 @@ class LoRaWANNode { /*! \brief Calculate the minimum interval to adhere to a certain dutyCycle. This interval is based on the ToA of one uplink and does not actually keep track of total airtime. - \param msPerHour The maximum allowed dutycyle (in milliseconds per hour). + \param msPerHour The maximum allowed duty cycle (in milliseconds per hour). \param airtime The airtime of the uplink. \returns Required interval (delay) in milliseconds between consecutive uplinks. */ @@ -642,9 +642,9 @@ class LoRaWANNode { void setDwellTime(bool enable, uint32_t msPerUplink = 0); /*! - \brief Returns the maximum payload given the currently present dwelltime limits. + \brief Returns the maximum payload given the currently present dwell time limits. WARNING: the addition of MAC commands may cause uplink errors; - if you want to be sure that your payload fits within dwelltime limits, subtract 16 from the result! + if you want to be sure that your payload fits within dwell time limits, subtract 16 from the result! */ uint8_t maxPayloadDwellTime(); @@ -666,7 +666,7 @@ class LoRaWANNode { /*! \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. - Returns 'true' if a network response was succesfully parsed. + Returns 'true' if a network response was successfully parsed. Returns 'false' if there was no network response / parsing failed. \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. \param gwCnt Number of gateways that received the LinkCheckReq. @@ -676,7 +676,7 @@ class LoRaWANNode { /*! \brief Returns the network time after requesting a DeviceTime MAC command. - Returns 'true' if a network response was succesfully parsed. + Returns 'true' if a network response was successfully parsed. Returns 'false' if there was no network response / parsing failed. \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) \param fraction Fractional-second, in 1/256-second steps @@ -791,7 +791,7 @@ class LoRaWANNode { // indicates whether an uplink has MAC commands as payload bool isMACPayload = false; - // save the selected subband in case this must be restored in ADR control + // save the selected sub-band in case this must be restored in ADR control int8_t subBand = -1; #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) @@ -830,7 +830,7 @@ class LoRaWANNode { int16_t setupChannelsDyn(bool joinRequest = false); // setup uplink/downlink channel data rates and frequencies - // for fixed bands, we only allow one subband at a time to be selected + // for fixed bands, we only allow one sub-band at a time to be selected int16_t setupChannelsFix(uint8_t subBand); // a join-accept can piggy-back a set of channels or channel masks @@ -867,7 +867,7 @@ class LoRaWANNode { // get the payload length for a specific MAC command uint8_t getMacPayloadLength(uint8_t cid); - // Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013). + // Performs CSMA as per LoRa Alliance Technical Recommendation 13 (TR-013). void performCSMA(); // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. From 139574d9630b8b9d63dec49a5b383b1c4fcee3e4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:50:16 +0100 Subject: [PATCH 0905/1848] Bump version to 6.4.1 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index dd65132087..bd42b5969b 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.4.0", + "version": "6.4.1", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 4685c4f0a4..4bf1b255a4 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.4.0 +version=6.4.1 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index a981263a39..b12c057605 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -529,7 +529,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 6 #define RADIOLIB_VERSION_MINOR 4 -#define RADIOLIB_VERSION_PATCH 0 +#define RADIOLIB_VERSION_PATCH 1 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 7c50be31583906d03feb68296819e1299b36973d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:57:11 +0100 Subject: [PATCH 0906/1848] [LoRaWAN] Add explicit initialization --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6c8d9506a3..3d8e0a56ff 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2219,7 +2219,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // check if the module supports this data rate - DataRate_t dr = { 0 }; + DataRate_t dr = { .lora = { .bandwidth = 0, .codingRate = 0, .spreadingFactor = 0 }; findDataRate(drUp, &dr); state = this->phyLayer->checkDataRate(dr); if(state == RADIOLIB_ERR_NONE) { From 50d335e339e99a442fe296a2652bedd5e2767ed5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 18:58:36 +0100 Subject: [PATCH 0907/1848] [CI] Skip LoRaWAN on MegaAVR (CI_BUILD_ALL) --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e55b6d4c5e..1fc5f5e3ba 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -101,7 +101,9 @@ jobs: echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - id: MegaCoreX:megaavr:4809 - run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT + run: | + echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT - id: arduino:mbed_rp2040:pico run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: rp2040:rp2040:rpipico From 070a0bf240df2177b4f727619816a965c7941ca5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 19:00:16 +0100 Subject: [PATCH 0908/1848] [LoRaWAN] Fixed missing bracket (CI_BUILD_ALL) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 3d8e0a56ff..a841d28a80 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2219,7 +2219,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // check if the module supports this data rate - DataRate_t dr = { .lora = { .bandwidth = 0, .codingRate = 0, .spreadingFactor = 0 }; + DataRate_t dr = { .lora = { .bandwidth = 0, .codingRate = 0, .spreadingFactor = 0 } }; findDataRate(drUp, &dr); state = this->phyLayer->checkDataRate(dr); if(state == RADIOLIB_ERR_NONE) { From a44a3daa1c073e53c3849409576c5aed0d078a9a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 27 Jan 2024 19:05:44 +0100 Subject: [PATCH 0909/1848] [LoRaWAN] Removed unsupported initializer (CI_BUILD_ALL)[ --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a841d28a80..bb318aa49e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2219,7 +2219,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // check if the module supports this data rate - DataRate_t dr = { .lora = { .bandwidth = 0, .codingRate = 0, .spreadingFactor = 0 } }; + DataRate_t dr; findDataRate(drUp, &dr); state = this->phyLayer->checkDataRate(dr); if(state == RADIOLIB_ERR_NONE) { From 5ebea1857216ee1894bc565ecaaa8c2f0247226e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Jan 2024 13:28:21 +0100 Subject: [PATCH 0910/1848] [LLCC68] Fixed data rate checking --- src/modules/LLCC68/LLCC68.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 516a854a06..f7d458ad9b 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -90,6 +90,7 @@ int16_t LLCC68::checkDataRate(DataRate_t dr) { if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); @@ -108,6 +109,7 @@ int16_t LLCC68::checkDataRate(DataRate_t dr) { default: return(RADIOLIB_ERR_INVALID_BANDWIDTH); } + return(RADIOLIB_ERR_NONE); } From 118980fd27f97ec99f8eef9af54bbc5160fa461d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Jan 2024 13:28:48 +0100 Subject: [PATCH 0911/1848] [SX126x] Fixed data rate checking (#948) --- src/modules/SX126x/SX126x.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ec508049f3..8ba17ac0cb 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -988,11 +988,13 @@ int16_t SX126x::checkDataRate(DataRate_t dr) { if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); } From a168f9ba418d5fa959735b05c633a2c8e3828672 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Jan 2024 13:29:14 +0100 Subject: [PATCH 0912/1848] [SX127x] Fixed data rate checking --- src/modules/SX127x/SX1272.cpp | 2 ++ src/modules/SX127x/SX1273.cpp | 2 ++ src/modules/SX127x/SX1277.cpp | 2 ++ src/modules/SX127x/SX1278.cpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 2c951401b4..808d55d24b 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -262,11 +262,13 @@ int16_t SX1272::checkDataRate(DataRate_t dr) { if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } + return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 6edc8e4b5f..9ef7c17552 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -102,11 +102,13 @@ int16_t SX1273::checkDataRate(DataRate_t dr) { if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } + return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index d808906645..fea394cd3a 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -144,11 +144,13 @@ int16_t SX1277::checkDataRate(DataRate_t dr) { if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } + return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index f20867ac68..cefb352cb5 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -276,11 +276,13 @@ int16_t SX1278::checkDataRate(DataRate_t dr) { if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } + return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); } From d208f46f93526e7d5a08e256aa68d9f6edd06088 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Jan 2024 13:31:08 +0100 Subject: [PATCH 0913/1848] [LoRaWAN] Added data rate check debug print --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index bb318aa49e..bfe6d0a3ca 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2230,7 +2230,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; drAck = 1; } else { - RADIOLIB_DEBUG_PRINTLN("ADR failed to configure dataRate = %d!", drUp); + RADIOLIB_DEBUG_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); } } From 547328f375998c663fd88f9b9f1143abc281de6d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Jan 2024 14:04:33 +0100 Subject: [PATCH 0914/1848] Bump version to 6.4.2 --- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index bd42b5969b..2927c2f6dc 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.4.1", + "version": "6.4.2", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 4bf1b255a4..9fd734b105 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.4.1 +version=6.4.2 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index b12c057605..4609a1da48 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -529,7 +529,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 6 #define RADIOLIB_VERSION_MINOR 4 -#define RADIOLIB_VERSION_PATCH 1 +#define RADIOLIB_VERSION_PATCH 2 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From bce14023f99bd32e12d69170057374ae9d7ffa30 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 2 Feb 2024 16:36:50 +0100 Subject: [PATCH 0915/1848] [PHY] Fixed godmode not exposing private member (#950) --- src/protocols/PhysicalLayer/PhysicalLayer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 4847b826dc..173c2939af 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -487,8 +487,10 @@ class PhysicalLayer { #endif -#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE +#if !RADIOLIB_GODMODE protected: +#endif +#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void updateDirectBuffer(uint8_t bit); #endif From 7945ffb996106329472cd828c98ee86af3d4cbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliv=C3=A9r=20Rem=C3=A9ny?= <25034625+remenyo@users.noreply.github.com> Date: Fri, 2 Feb 2024 16:57:43 +0100 Subject: [PATCH 0916/1848] include esp_attr.h where IRAM_ATTR is used (#952) * Update LoRaWAN.cpp * Update Pager.cpp --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 +++ src/protocols/Pager/Pager.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index bfe6d0a3ca..f0ca926868 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1,5 +1,8 @@ #include "LoRaWAN.h" #include +#if defined(ESP8266) || defined(ESP32) +#include "esp_attr.h" +#endif #if !RADIOLIB_EXCLUDE_LORAWAN diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 6b9ade4f92..2432dc93d7 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,6 +1,10 @@ #include "Pager.h" #include #include +#if defined(ESP8266) || defined(ESP32) +#include "esp_attr.h" +#endif + #if !RADIOLIB_EXCLUDE_PAGER #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE From e4267760f97f0447d829286c0f51b9e4748b4d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliv=C3=A9r=20Rem=C3=A9ny?= <25034625+remenyo@users.noreply.github.com> Date: Sun, 11 Feb 2024 09:41:41 +0100 Subject: [PATCH 0917/1848] Fix stringop-truncation warning in AX25 callsign getter (#958) * Update LoRaWAN.cpp * Update Pager.cpp * Update AX25.cpp Fixed stringop-truncation error --- src/protocols/AX25/AX25.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 3c60072e43..7fe3f4969b 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -440,7 +440,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } void AX25Client::getCallsign(char* buff) { - strncpy(buff, sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + strncpy(buff, sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); } uint8_t AX25Client::getSSID() { From a907026c7b2a213e62a631c092b32a273616ce6a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Feb 2024 07:04:04 +0100 Subject: [PATCH 0918/1848] [SX127x] Fixed software timeout duration (#962) --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index cdf68ad324..bdf4bae51f 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -198,7 +198,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { uint32_t timeout = 0; if(this->mod->getGpio() == RADIOLIB_NC) { float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - timeout = 100*symbolLength; + timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); } // wait for packet reception or timeout From ea2ccfd6d011bdfb358180b80c0bda2e2ddb12c3 Mon Sep 17 00:00:00 2001 From: Leonard Techel Date: Tue, 13 Feb 2024 19:58:02 +0100 Subject: [PATCH 0919/1848] [LoRaWAN] Fix fcntUp wrap-around after 50 transmissions Resolves #950 --- src/protocols/LoRaWAN/LoRaWAN.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index f0ca926868..ddd1e88abf 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -818,8 +818,15 @@ int16_t LoRaWANNode::saveSession() { int16_t LoRaWANNode::saveFcntUp() { Module* mod = this->phyLayer->getMod(); - uint8_t fcntBuff[30] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, 30); + uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); + uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 1); + uint8_t buffSize = fcntBuffEnd - fcntBuffStart; + #if RADIOLIB_STATIC_ONLY + uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* fcntBuff = new uint8_t[buffSize]; + #endif + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); // we discard the first two bits - your flash will likely be far dead by the time you reach 2^30 uplinks // the first two bytes of the remaining 30 bytes are stored straight into storage without additional wear leveling @@ -859,12 +866,12 @@ int16_t LoRaWANNode::saveFcntUp() { // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte idx = 5; state = fcntBuff[idx] >> 7; - for(; idx < 30; idx++) { + for(; idx < buffSize; idx++) { if(fcntBuff[idx] >> 7 != state) { break; } } - idx = idx < 30 ? idx : 5; + idx = idx < buffSize ? idx : 5; uint8_t bits_7_0 = (this->fcntUp >> 0) & 0x7F; // flip the first bit of this byte to indicate that we just wrote here From 0ea00fad44ffdadd3279d8fdd66fc259df8879f0 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:36:03 +0100 Subject: [PATCH 0920/1848] [LoRaWAN] Improve examples, add getter for DevAddr (#974) --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 25 ++- .../LoRaWAN_End_Device_ABP.ino | 24 ++- .../LoRaWAN_End_Device_Persistent.ino | 156 ------------------ .../LoRaWAN_End_Device_Reference.ino | 24 +-- keywords.txt | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 3 + src/protocols/LoRaWAN/LoRaWAN.h | 6 + 7 files changed, 55 insertions(+), 184 deletions(-) delete mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index 10af3b626d..95777c5aad 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -7,12 +7,14 @@ After your device is registered, you can run this example. The device will join the network and start uploading data. - LoRaWAN v1.1 requires the use of EEPROM (persistent storage). - Please refer to the 'persistent' example once you are familiar - with LoRaWAN. - Running this examples REQUIRES you to check "Resets DevNonces" - on your LoRaWAN dashboard. Refer to the network's - documentation on how to do this. + NOTE: LoRaWAN v1.1 requires storing parameters persistently! + RadioLib does this by using EEPROM (persistent storage), + by default starting at address 0 and using 448 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -49,8 +51,8 @@ LoRaWANNode node(&radio, &EU868); void setup() { Serial.begin(9600); - // initialize SX1278 with default settings - Serial.print(F("[SX1278] Initializing ... ")); + // initialize radio (SX1262 / SX1278 / ... ) with default settings + Serial.print(F("[Radio] Initializing ... ")); int state = radio.begin(); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -104,6 +106,7 @@ void setup() { if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); + delay(2000); // small delay between joining and uplink } else { Serial.print(F("failed, code ")); Serial.println(state); @@ -118,7 +121,7 @@ int count = 0; void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello World! #" + String(count++); + String strUp = "Hello!" + String(count++); String strDown; int state = node.sendReceive(strUp, 10, strDown); if(state == RADIOLIB_ERR_NONE) { @@ -154,6 +157,10 @@ void loop() { Serial.print(F("failed, code ")); Serial.println(state); } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); // wait before sending another packet uint32_t minimumDelay = 60000; // try to send once every minute diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index 0a6dfcf1d8..cf765cb168 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -8,12 +8,14 @@ The device will start uploading data directly, without having to join the network. - LoRaWAN v1.1 requires the use of EEPROM (persistent storage). - Please refer to the 'persistent' example once you are familiar - with LoRaWAN. - Running this examples REQUIRES you to check "Resets DevNonces" - on your LoRaWAN dashboard. Refer to the network's - documentation on how to do this. + NOTE: LoRaWAN v1.1 requires storing parameters persistently! + RadioLib does this by using EEPROM (persistent storage), + by default starting at address 0 and using 448 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -50,8 +52,8 @@ LoRaWANNode node(&radio, &EU868); void setup() { Serial.begin(9600); - // initialize SX1278 with default settings - Serial.print(F("[SX1278] Initializing ... ")); + // initialize radio (SX1262 / SX1278 / ... ) with default settings + Serial.print(F("[Radio] Initializing ... ")); int state = radio.begin(); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -126,7 +128,7 @@ int count = 0; void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello World! #" + String(count++); + String strUp = "Hello!" + String(count++); String strDown; int state = node.sendReceive(strUp, 10, strDown); if(state == RADIOLIB_ERR_NONE) { @@ -163,6 +165,10 @@ void loop() { Serial.println(state); } + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + // wait before sending another packet uint32_t minimumDelay = 60000; // try to send once every minute uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino deleted file mode 100644 index a475e72558..0000000000 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino +++ /dev/null @@ -1,156 +0,0 @@ -/* - RadioLib LoRaWAN End Device Persistent Example - - This example assumes you have tried one of the OTAA or ABP - examples and are familiar with the required keys and procedures. - This example restores and saves a session such that you can use - deepsleep or survive power cycles. Before you start, you will - have to register your device at https://www.thethingsnetwork.org/ - and join the network using either OTAA or ABP. - Please refer to one of the other LoRaWAN examples for more - information regarding joining a network. - - NOTE: LoRaWAN requires storing some parameters persistently! - RadioLib does this by using EEPROM, by default - starting at address 0 and using 448 bytes. - If you already use EEPROM in your application, - you will have to either avoid this range, or change it - by setting a different start address by changing the value of - RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either - during build or in src/BuildOpt.h. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// SX1262 has the following pin order: -// Module(NSS/CS, DIO1, RESET, BUSY) -// SX1262 radio = new Module(8, 14, 12, 13); - -// SX1278 has the following pin order: -// Module(NSS/CS, DIO0, RESET, DIO1) -SX1278 radio = new Module(10, 2, 9, 3); - -// create the node instance on the EU-868 band -// using the radio module and the encryption key -// make sure you are using the correct band -// based on your geographical location! -LoRaWANNode node(&radio, &EU868); - -// for fixed bands with subband selection -// such as US915 and AU915, you must specify -// the subband that matches the Frequency Plan -// that you selected on your LoRaWAN console -/* - LoRaWANNode node(&radio, &US915, 2); -*/ - -void setup() { - Serial.begin(9600); - - // initialize SX1278 with default settings - Serial.print(F("[SX1278] Initializing ... ")); - int state = radio.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // start the activation - // Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - // uint64_t joinEUI = 0x12AD1011B0C0FFEE; - // uint64_t devEUI = 0x70B3D57ED005E120; - // uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, - // 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; - // uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - // 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; - // state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - - // on EEPROM-enabled boards, after the device has been activated, - // the session can be restored without rejoining after device power cycle - // by calling the same `beginOTAA()` or `beginABP()` function with the same keys - // or call `restore()` where it will restore any existing session - // `restore()` returns the active mode if it succeeded (OTAA or ABP) - Serial.print(F("[LoRaWAN] Resuming previous session ... ")); - state = node.restore(); - if(state >= RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - Serial.print(F("Restored an ")); - if(state == RADIOLIB_LORAWAN_MODE_OTAA) - Serial.println(F("OTAA session.")); - else { - Serial.println(F("ABP session.")); - } - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - -} - -// counter to keep track of transmitted packets -int count = 0; - -void loop() { - // send uplink to port 10 - Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello World! #" + String(count++); - String strDown; - int state = node.sendReceive(strUp, 10, strDown); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("received a downlink!")); - - // print data of the packet (if there are any) - Serial.print(F("[LoRaWAN] Data:\t\t")); - if(strDown.length() > 0) { - Serial.println(strDown); - } else { - Serial.println(F("")); - } - - // print RSSI (Received Signal Strength Indicator) - Serial.print(F("[LoRaWAN] RSSI:\t\t")); - Serial.print(radio.getRSSI()); - Serial.println(F(" dBm")); - - // print SNR (Signal-to-Noise Ratio) - Serial.print(F("[LoRaWAN] SNR:\t\t")); - Serial.print(radio.getSNR()); - Serial.println(F(" dB")); - - // print frequency error - Serial.print(F("[LoRaWAN] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); - - } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("no downlink!")); - - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // on EEPROM enabled boards, you can save the current session - // by calling "saveSession" which allows retrieving the session after reboot or deepsleep - node.saveSession(); - - // wait before sending another packet - // alternatively, call a deepsleep function here - // make sure to send the radio to sleep as well using radio.sleep() - uint32_t minimumDelay = 60000; // try to send once every minute - uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows - - delay(delayMs); -} diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 87d350b078..771890b518 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -52,8 +52,8 @@ LoRaWANNode node(&radio, &EU868); void setup() { Serial.begin(9600); - // initialize SX1278 with default settings - Serial.print(F("[SX1278] Initializing ... ")); + // initialize radio (SX1262 / SX1278 / ... ) with default settings + Serial.print(F("[Radio] Initializing ... ")); int state = radio.begin(); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -102,12 +102,16 @@ void setup() { if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); + delay(2000); // small delay between joining and uplink } else { Serial.print(F("failed, code ")); Serial.println(state); while(true); } + Serial.print("[LoRaWAN] DevAddr: "); + Serial.println(node.getDevAddr(), HEX); + // on EEPROM-enabled boards, after the device has been activated, // the session can be restored without rejoining after device power cycle // this is intrinsically done when calling `beginOTAA()` with the same keys @@ -116,7 +120,7 @@ void setup() { /* Serial.print(F("[LoRaWAN] Resuming previous session ... ")); state = node.restore(); - if(state == RADIOLIB_ERR_NONE) { + if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { Serial.print(F("failed, code ")); @@ -130,7 +134,7 @@ void setup() { // set a fixed datarate node.setDatarate(5); - // in order to save the datarate persistent across reboot/deepsleep, use the following: + // in order to set the datarate persistent across reboot/deepsleep, use the following: /* node.setDatarate(5, true); */ @@ -148,10 +152,10 @@ void setup() { node.setDutyCycle(true, 1250); // enable or disable the dwell time limits - // the second argument specific allowed airtime per uplink in milliseconds - // if not called, this corresponds to setDwellTime(true, 0) + // the second argument specifies the allowed airtime per uplink in milliseconds + // unless specified, this argument is set to 0 // setting this to 0 corresponds to the band's maximum allowed dwell time by law - node.setDwellTime(true, 1000); + node.setDwellTime(true, 400); } void loop() { @@ -170,14 +174,14 @@ void loop() { uint32_t fcntUp = node.getFcntUp(); Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello World! #" + String(fcntUp); + String strUp = "Hello!" + String(fcntUp); // send a confirmed uplink to port 10 every 64th frame // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { - state = node.uplink(strUp, 10, true); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); + state = node.uplink(strUp, 10, true); } else { state = node.uplink(strUp, 10); } @@ -239,7 +243,7 @@ void loop() { Serial.print(F("[LoRaWAN] Confirming:\t")); Serial.println(event.confirming); Serial.print(F("[LoRaWAN] Datarate:\t")); - Serial.print(event.datarate); + Serial.println(event.datarate); Serial.print(F("[LoRaWAN] Frequency:\t")); Serial.print(event.freq, 3); Serial.println(F(" MHz")); diff --git a/keywords.txt b/keywords.txt index ace5e99326..6ee6222c8c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -318,6 +318,7 @@ setTxPower KEYWORD2 setCSMA KEYWORD2 getMacLinkCheckAns KEYWORD2 getMacDeviceTimeAns KEYWORD2 +getDevAddr KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ddd1e88abf..6a038746dd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2873,6 +2873,9 @@ int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, return(RADIOLIB_ERR_NONE); } +uint64_t LoRaWANNode::getDevAddr() { + return(this->devAddr); +} // The following function enables LMAC, a CSMA scheme for LoRa as specified // in the LoRa Alliance Technical Recommendation #13. diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index b881501dfa..157945a0c0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -685,6 +685,12 @@ class LoRaWANNode { */ int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); + /*! + \brief Returns the DevAddr of the device, regardless of OTAA or ABP mode + \returns 8-byte DevAddr + */ + uint64_t getDevAddr(); + #if !RADIOLIB_GODMODE private: #endif From 9f0bdffc50f71c04123741b47099fd3f5a16e570 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 25 Feb 2024 18:02:31 +0100 Subject: [PATCH 0921/1848] [LoRaWAN] Use ESP_PLATFORM macro to include esp_attr.h (#952) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- src/protocols/Pager/Pager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6a038746dd..88790e7f25 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1,6 +1,6 @@ #include "LoRaWAN.h" #include -#if defined(ESP8266) || defined(ESP32) +#if defined(ESP_PLATFORM) #include "esp_attr.h" #endif diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 2432dc93d7..799fd626cf 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,7 +1,7 @@ #include "Pager.h" #include #include -#if defined(ESP8266) || defined(ESP32) +#if defined(ESP_PLATFORM) #include "esp_attr.h" #endif From 5c30bb1e326f7033d76a199710f0e97803b5f6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Tue, 27 Feb 2024 17:16:33 +0100 Subject: [PATCH 0922/1848] [CI] Run apt-get update before install (#989) --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1fc5f5e3ba..ce1032973c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -189,7 +189,9 @@ jobs: uses: actions/checkout@v2 - name: Install dependencies - run: sudo apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 + run: | + sudo apt-get update + sudo apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 - name: Clone ESP-IDF run: | From 5766d386af3242099129d34ac916c5f55793fc47 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:29:45 +0100 Subject: [PATCH 0923/1848] [LoRaWAN] Improve persistence behaviour, add dwell time error, clear up debug output (#980) * [LoRaWAN] Improve examples, add getter for DevAddr * [ArduinoHAL] Only (over)write new values * [HAL] Fix comment * [TypeDef] Introduce error for LoRaWAN dwell time * [LoRaWAN] Improve persistence behaviour, add dwell time error, clear up debug output * [LoRaWAN] Prevent incorrect behaviour in restore() * [LoRaWAN] Improve example comments and persistence * [LoRaWAN] Fix DeviceTime and LinkCheck, fix FcntUp offset * [LoRaWAN] Fix example incorrectly processing MAC commands * [LoRaWAN] Fix downlink port, Fcnt 'underflow', user MAC processing * [LoRaWAN] Add simple receive methods * [LoRaWAN] Add co-author Co-Authored-By: HeadBoffin <60431281+HeadBoffin@users.noreply.github.com> * [LoRaWAN] Fix example output * [LoRaWAN] Improve persistence behaviour, bugfix subband * [LoRaWAN] Prevent useless rejoin during nonpersistent session * [LoRaWAN] Graciously block an uplink if not joined --------- Co-authored-by: HeadBoffin <60431281+HeadBoffin@users.noreply.github.com> --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 2 +- .../LoRaWAN_End_Device_ABP.ino | 2 +- .../LoRaWAN_End_Device_Reference.ino | 12 +- src/ArduinoHal.cpp | 4 +- src/Hal.h | 2 +- src/TypeDef.h | 5 + src/protocols/LoRaWAN/LoRaWAN.cpp | 317 +++++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 69 +++- 8 files changed, 270 insertions(+), 143 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index 95777c5aad..d4ec506d17 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -158,7 +158,7 @@ void loop() { Serial.println(state); } - // on EEPROM enabled boards, you can save the current session + // on EEPROM enabled boards, you should save the current session // by calling "saveSession" which allows retrieving the session after reboot or deepsleep node.saveSession(); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino index cf765cb168..02089e4bca 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino @@ -165,7 +165,7 @@ void loop() { Serial.println(state); } - // on EEPROM enabled boards, you can save the current session + // on EEPROM enabled boards, you should save the current session // by calling "saveSession" which allows retrieving the session after reboot or deepsleep node.saveSession(); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 771890b518..207dd356d2 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -259,7 +259,7 @@ void loop() { uint8_t margin = 0; uint8_t gwCnt = 0; - if(node.getMacLinkCheckAns(&margin, &gwCnt)) { + if(node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) { Serial.print(F("[LoRaWAN] LinkCheck margin:\t")); Serial.println(margin); Serial.print(F("[LoRaWAN] LinkCheck count:\t")); @@ -268,10 +268,10 @@ void loop() { uint32_t networkTime = 0; uint8_t fracSecond = 0; - if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true)) { + if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) { Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); Serial.println(networkTime); - Serial.print(F("[LoRaWAN] LinkCheck second:\t1/")); + Serial.print(F("[LoRaWAN] DeviceTime second:\t1/")); Serial.println(fracSecond); } @@ -283,11 +283,9 @@ void loop() { Serial.println(state); } - // on EEPROM enabled boards, you can save the current session + // on EEPROM enabled boards, you should save the current session // by calling "saveSession" which allows retrieving the session after reboot or deepsleep - /* - node.saveSession(); - */ + node.saveSession(); // wait before sending another packet uint32_t minimumDelay = 60000; // try to send once every minute diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 11422d59d8..59b5fb5e5b 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -146,7 +146,9 @@ void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len EEPROM.init(); #endif for(size_t i = 0; i < len; i++) { - EEPROM.write(addr + i, buff[i]); + if(EEPROM.read(addr + i) != buff[i]) { // only write if value is new + EEPROM.write(addr + i, buff[i]); + } } #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) EEPROM.commit(); diff --git a/src/Hal.h b/src/Hal.h index fbc8d5f757..4a0c72c3e1 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -49,7 +49,7 @@ enum RADIOLIB_EEPROM_PARAMS { }; static const uint32_t RadioLibPersistentParamTable[] = { - 0x00, // RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION_ID + 0x00, // RADIOLIB_EEPROM_TABLE_VERSION_ID 0x02, // RADIOLIB_EEPROM_LORAWAN_CLASS_ID 0x03, // RADIOLIB_EEPROM_LORAWAN_MODE_ID 0x05, // RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID diff --git a/src/TypeDef.h b/src/TypeDef.h index f82e787b17..42334988db 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -553,6 +553,11 @@ */ #define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114) +/*! + \brief Uplink payload length at this datarate exceeds the active dwell time limitations. +*/ +#define RADIOLIB_ERR_DWELL_TIME_EXCEEDED (-1115) + /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 88790e7f25..cbbe15a16d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -81,6 +81,10 @@ int16_t LoRaWANNode::restore() { // the mode value is not set, user will have to do perform the join procedure return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } + + if(!this->isValidSession()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } // pull all authentication keys from persistent storage this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID); @@ -165,7 +169,7 @@ int16_t LoRaWANNode::restore() { return(this->activeMode); } -int16_t LoRaWANNode::restoreFcntUp() { +void LoRaWANNode::restoreFcntUp() { Module* mod = this->phyLayer->getMod(); uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); @@ -210,7 +214,6 @@ int16_t LoRaWANNode::restoreFcntUp() { #endif this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; - return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::restoreChannels() { @@ -254,6 +257,7 @@ int16_t LoRaWANNode::restoreChannels() { } else { // RADIOLIB_LORAWAN_BAND_FIXED uint8_t numADRCommands = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); + RADIOLIB_DEBUG_PRINTLN("Restoring %d stored channel masks", numADRCommands); uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); @@ -277,7 +281,47 @@ int16_t LoRaWANNode::restoreChannels() { } return(RADIOLIB_ERR_NONE); } -#endif + +void LoRaWANNode::clearSession() { + Module* mod = this->phyLayer->getMod(); + uint8_t zeroes[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID), zeroes, sizeof(uint32_t)); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + this->activeMode = RADIOLIB_LORAWAN_MODE_NONE; +} + +bool LoRaWANNode::isValidSession() { + uint8_t mask = 0; + Module* mod = this->phyLayer->getMod(); + uint8_t dummyBuf[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID), dummyBuf, sizeof(uint32_t)); + for(size_t i = 0; i < sizeof(uint32_t); i++) { + mask |= dummyBuf[i]; + } + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= dummyBuf[i]; + } + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= dummyBuf[i]; + } + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= dummyBuf[i]; + } + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= dummyBuf[i]; + } + + return(mask > 0); +} + +#endif // RADIOLIB_EEPROM_UNSUPPORTED void LoRaWANNode::beginCommon(uint8_t joinDr) { // in case a new session is started while there is an ongoing session @@ -390,6 +434,11 @@ void LoRaWANNode::beginCommon(uint8_t joinDr) { } int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr, bool force) { + // if not forced and already joined, don't do anything + if(!force && this->isJoined()) { + return(this->activeMode); + } + // check if we actually need to send the join request Module* mod = this->phyLayer->getMod(); @@ -400,26 +449,23 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); checkSum ^= LoRaWANNode::checkSum16(appKey, 16); - bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; + bool isValidCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; + bool isValidMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; - if(validCheckSum && validMode) { - if(!force) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); + if(isValidCheckSum && isValidMode) { + // if not forced and a valid session is stored, restore it + if(!force && this->isValidSession()) { return(this->restore()); - - } else { - // the credentials are still the same, so restore only DevNonce and JoinNonce - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); } - } - - // if forced by user, keys are new or changed mode, wipe the previous session - if(force || !validCheckSum || !validMode) { + // either forced or no active session (a join was issued previously but didn't result in an active session) + this->clearSession(); + // the credentials are still the same, so restore the DevNonce and JoinNonce + this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); + this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); + } else { + // either invalid key checksum or mode, so wipe either way #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); @@ -458,9 +504,15 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); + // copy devNonce currently in use + uint16_t devNonceUsed = this->devNonce; // increment devNonce as we are sending another join-request this->devNonce += 1; +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); +#endif + // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; @@ -468,7 +520,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], this->devNonce); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); @@ -554,7 +606,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], joinEUI); - LoRaWANNode::hton(&micBuff[9], this->devNonce); + LoRaWANNode::hton(&micBuff[9], devNonceUsed); memcpy(&micBuff[11], joinAcceptMsg, lenRx); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { @@ -605,7 +657,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe if(this->rev == 1) { // 1.1 version, derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], this->devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(appKey); @@ -636,7 +688,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } else { // 1.0 version, just derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -660,23 +712,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - - // save join-request parameters - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); - - this->saveSession(); - - // everything written to NVM, write current table version to persistent storage and set mode mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); #endif this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; @@ -685,6 +724,11 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { + // if not forced and already joined, don't do anything + if(!force && this->isJoined()) { + return(this->activeMode); + } + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // only needed for persistent storage Module* mod = this->phyLayer->getMod(); @@ -697,17 +741,20 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } - bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; + bool isValidCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; + bool isValidMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; - if(!force && validCheckSum && validMode) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); - - return(this->restore()); + if(isValidCheckSum && isValidMode) { + // if not forced and a valid session is stored, restore it + if(!force && this->isValidSession()) { + return(this->restore()); + } + // either forced or no active session (a join was issued previously but didn't result in an active session) + this->clearSession(); } else { + // either invalid key checksum or mode, so wipe either way #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); @@ -750,20 +797,18 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, state = this->setPhyProperties(); RADIOLIB_ASSERT(state); + // reset all frame counters + this->fcntUp = 0; + this->aFcntDown = 0; + this->nFcntDown = 0; + this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFcnt = 0; + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the activation keys checksum, device address & keys - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - - // save all new frame counters - this->saveSession(); - - // everything written to NVM, write current table version to persistent storage and set mode mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP); #endif @@ -780,25 +825,24 @@ bool LoRaWANNode::isJoined() { int16_t LoRaWANNode::saveSession() { Module* mod = this->phyLayer->getMod(); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID) != this->rev) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); + // store DevAddr and all keys + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + // store network parameters + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); // store all frame counters - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); - // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often this->saveFcntUp(); @@ -815,7 +859,7 @@ int16_t LoRaWANNode::saveSession() { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::saveFcntUp() { +void LoRaWANNode::saveFcntUp() { Module* mod = this->phyLayer->getMod(); uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); @@ -878,7 +922,6 @@ int16_t LoRaWANNode::saveFcntUp() { bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7; mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); - return(RADIOLIB_ERR_NONE); } #endif // RADIOLIB_EEPROM_UNSUPPORTED @@ -893,6 +936,11 @@ int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, LoR } int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { + // if not joined, don't do anything + if(!this->isJoined()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + Module* mod = this->phyLayer->getMod(); // check if the Rx windows were closed after sending the previous uplink @@ -934,13 +982,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); - // if testing with TS008 specification verification protocol, don't throw error but clip the message + // if testing with TS009 specification verification protocol, don't throw error but clip the message // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; } - // increase frame counter by one - this->fcntUp += 1; - bool adrAckReq = false; if(this->adrEnabled) { // check if we need to do ADR stuff @@ -1008,7 +1053,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // if dwell time is imposed, calculated expected time on air and cancel if exceeds if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } // build the uplink message @@ -1109,6 +1154,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; + RADIOLIB_DEBUG_PRINTLN("FcntUp: %d", this->fcntUp); + RADIOLIB_DEBUG_PRINTLN("uplinkMsg pre-MIC:"); RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -1126,9 +1173,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } - RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); - RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); - // perform CSMA if enabled. if (enableCSMA) { performCSMA(); @@ -1164,6 +1208,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf event->port = port; } + // increase frame counter by one for the next uplink + this->fcntUp += 1; + return(RADIOLIB_ERR_NONE); } @@ -1224,7 +1271,7 @@ int16_t LoRaWANNode::downlinkCommon() { // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); - RADIOLIB_DEBUG_PRINTLN("closing"); + RADIOLIB_DEBUG_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set if(!this->phyLayer->isRxTimeout()) { @@ -1233,6 +1280,7 @@ int16_t LoRaWANNode::downlinkCommon() { } else if(i == 0) { // nothing in the first window, configure for the second this->phyLayer->standby(); + RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); state = this->phyLayer->setFrequency(this->rx2.freq); RADIOLIB_ASSERT(state); @@ -1295,6 +1343,20 @@ int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { } #endif +int16_t LoRaWANNode::downlink(LoRaWANEvent_t* event) { + int16_t state = RADIOLIB_ERR_NONE; + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t length = 0; + uint8_t data[251]; + + // wait for downlink + state = this->downlink(data, &length, event); + + return(state); +} + int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received int16_t state = downlinkCommon(); @@ -1578,8 +1640,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } - // a downlink was received, so reset the ADR counter to this uplink's fcnt - this->adrFcnt = this->fcntUp; + // a downlink was received, so reset the ADR counter to the last uplink's fcnt + this->adrFcnt = this->fcntUp - 1; // pass the extra info if requested if(event) { @@ -1590,7 +1652,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; - event->port = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)]; + event->port = isAppDownlink ? downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; } // process Application payload (if there is any) @@ -1604,8 +1666,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) return(RADIOLIB_ERR_NONE); } - // there is payload, and so there should be a port too - // TODO pass the port? *len = payLen - 1; // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 @@ -1630,6 +1690,16 @@ int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, b } #endif +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // send the uplink + int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); + RADIOLIB_ASSERT(state); + + // wait for the downlink + state = this->downlink(eventDown); + return(state); +} + int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); @@ -1654,8 +1724,12 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { this->battLevel = battLevel; } +// return Fcnt of last uplink; also return 0 if no uplink occured yet uint32_t LoRaWANNode::getFcntUp() { - return(this->fcntUp); + if(this->fcntUp == 0) { + return(0); + } + return(this->fcntUp - 1); } uint32_t LoRaWANNode::getNFcntDown() { @@ -1742,7 +1816,6 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; num < 3 && this->band->txFreqs[num].enabled; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } // if we're about to send a join-request, copy the join-request channels to the next slots @@ -1751,7 +1824,6 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } } @@ -1759,6 +1831,22 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } return(RADIOLIB_ERR_NONE); } @@ -1766,7 +1854,7 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { // setup a subband and its corresponding join-request datarate // WARNING: subBand starts at 1 (corresponds to all populair schemes) int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { - RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels"); + RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels (subband %d)", subBand); // randomly select one of 8 or 9 channels and find corresponding datarate uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 @@ -2083,8 +2171,8 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; - RADIOLIB_DEBUG_PRINTLN("DR %d: LORA (SF: %d, BW: %f, CR: %d)", - dataRateBand, dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); + RADIOLIB_DEBUG_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", + dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); } return(RADIOLIB_ERR_NONE); @@ -2093,7 +2181,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::configureChannel(uint8_t dir) { // set the frequency RADIOLIB_DEBUG_PRINTLN(""); - RADIOLIB_DEBUG_PRINTLN("Channel frequency %cL = %f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); RADIOLIB_ASSERT(state); @@ -2150,7 +2238,7 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t payload[5]) { +int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload) { if(queue->numCommands == 0) { return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); } @@ -2203,6 +2291,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } break; case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + // delete any existing response (does nothing if there is none) + deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); + + // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; @@ -2314,9 +2406,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); } else { // RADIOLIB_LORAWAN_BAND_FIXED - RADIOLIB_DEBUG_PRINTLN("[1] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", - cmd->repeat, (cmd->payload[3] >> 7), - cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); // if RFU bit is set, this is just a change in Datarate or TxPower // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it if((cmd->payload[3] >> 7) == 1) { @@ -2333,9 +2422,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // saved an ADR mask, so re-store counter mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat); } - RADIOLIB_DEBUG_PRINTLN("[2] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", - cmd->repeat, (cmd->payload[3] >> 7), - cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); } } #endif @@ -2438,7 +2524,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, @@ -2593,6 +2679,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } break; case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + // delete any existing response (does nothing if there is none) + deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); + + // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; @@ -2641,7 +2731,6 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskCntl == 0) { // apply the mask by looking at each channel bit - RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); if(chMask & (1UL << i)) { // if it should be enabled but is not currently defined, stop immediately if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { @@ -2662,7 +2751,7 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, @@ -2702,14 +2791,13 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool uint16_t mask = 1 << i; if(mask & chMask) { uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95 - this->subBand = chNum % 8; // keep track of configured subband in case we must reset the channels + this->subBand = chNum / 8 + 1; // save configured subband in case we must reset the channels (1-based) chnl.enabled = true; chnl.idx = chNum; chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2732,7 +2820,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx-1, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2752,7 +2839,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } // enable single channel from second span uint8_t chNum = 64 + i; @@ -2762,7 +2848,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2785,7 +2870,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2810,14 +2894,13 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, @@ -2852,7 +2935,7 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { if(margin) { *margin = payload[0]; } if(gwCnt) { *gwCnt = payload[1]; } - // RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt); + return(RADIOLIB_ERR_NONE); } @@ -2864,12 +2947,12 @@ int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, if(gpsEpoch) { *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); if(returnUnix) { - uint32_t unixOffset = 315964800; + uint32_t unixOffset = 315964800 - 18; // 18 leap seconds since GPS epoch (Jan. 6th 1980) *gpsEpoch += unixOffset; } } if(fraction) { *fraction = payload[4]; } - // RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f); + return(RADIOLIB_ERR_NONE); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 157945a0c0..44941a4de8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -179,6 +179,12 @@ #define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) #define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) +// maximum allowed dwell time on bands that implement dwell time limitations +#define RADIOLIB_LORAWAN_DWELL_TIME (400) + +// unused LoRaWAN version +#define RADIOLIB_LORAWAN_VERSION_NONE (0xFF) + // unused frame counter value #define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) @@ -188,10 +194,7 @@ // the maximum number of simultaneously available channels #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) -// maximum allowed dwell time on bands that implement dwell time limitations -#define RADIOLIB_LORAWAN_DWELL_TIME (400) - -// Maximum MAC command sizes +// maximum MAC command sizes #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) @@ -530,6 +533,14 @@ class LoRaWANNode { */ int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); + /*! + \brief Wait for downlink, simplified to allow for simpler sendReceive + \param event Pointer to a structure to store extra information about the event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t downlink(LoRaWANEvent_t* event = NULL); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. @@ -577,6 +588,20 @@ class LoRaWANNode { */ int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + /*! + \brief Send a message to the server and wait for a downlink but don't bother the user with downlink contents + \param dataUp Data to send. + \param lenUp Length of the data. + \param port Port number to send the message to. + \param isConfirmed Whether to send a confirmed uplink or not. + \param eventUp Pointer to a structure to store extra information about the uplink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \param eventDown Pointer to a structure to store extra information about the downlink event + (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns \ref status_codes + */ + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + /*! \brief Set device status. \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, @@ -584,18 +609,28 @@ class LoRaWANNode { */ void setDeviceStatus(uint8_t battLevel); - /*! \brief Returns the last uplink's frame counter */ + /*! + \brief Returns the last uplink's frame counter; + also 0 if no uplink occured yet. + */ uint32_t getFcntUp(); - /*! \brief Returns the last network downlink's frame counter */ + /*! + \brief Returns the last network downlink's frame counter; + also 0 if no network downlink occured yet. + */ uint32_t getNFcntDown(); - /*! \brief Returns the last application downlink's frame counter */ + /*! + \brief Returns the last application downlink's frame counter; + also 0 if no application downlink occured yet. + */ uint32_t getAFcntDown(); - /*! \brief Reset the downlink frame counters (application and network) + /*! + \brief Reset the downlink frame counters (application and network) This is unsafe and can possibly allow replay attacks using downlinks. - It mainly exists as part of the TS008 Specification Verification protocol. + It mainly exists as part of the TS009 Specification Verification protocol. */ void resetFcntDown(); @@ -798,22 +833,26 @@ class LoRaWANNode { bool isMACPayload = false; // save the selected sub-band in case this must be restored in ADR control - int8_t subBand = -1; + uint8_t subBand = 0; #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) /*! \brief Save the current uplink frame counter. Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. - \returns \ref status_codes */ - int16_t saveFcntUp(); + void saveFcntUp(); /*! \brief Restore frame counter for uplinks from persistent storage. Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. - \returns \ref status_codes */ - int16_t restoreFcntUp(); + void restoreFcntUp(); + + // set all keys to zero + void clearSession(); + + // test if saved keys are non-zero + bool isValidSession(); #endif // wait for, open and listen during Rx1 and Rx2 windows; only performs listening @@ -859,7 +898,7 @@ class LoRaWANNode { // delete a specific MAC command from queue, indicated by the command ID // if a payload pointer is supplied, this returns the payload of the MAC command - int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t payload[5] = NULL); + int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload = NULL); // execute mac command, return the number of processed bytes for sequential processing bool execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom = true); From a52920bcb20671c59d887ca6f8cedb10e02970ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicklas=20B=C3=B6rjesson?= Date: Wed, 28 Feb 2024 17:50:04 +0100 Subject: [PATCH 0924/1848] IDF Component Registry manifest (#990) * Add idf_component.yxml * Fix URL, add compote dist to .gitignore --- .gitignore | 3 +++ idf_component.yml | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 idf_component.yml diff --git a/.gitignore b/.gitignore index 226f5c8ebb..b65463c981 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ extras/SX126x_Spectrum_Scan/out/* # cmake build/ + +# Compote build output +dist diff --git a/idf_component.yml b/idf_component.yml new file mode 100644 index 0000000000..09f82ad98d --- /dev/null +++ b/idf_component.yml @@ -0,0 +1,11 @@ +version: "6.4.2" +description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." +tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan" +url: "https://github.com/jgromes/RadioLib" +repository: "https://github.com/jgromes/RadioLib.git" +license: "MIT" +dependencies: + # Required IDF version + idf: ">=4.1" +maintainers: + "Jan Gromeš " From 10acb6d9cac46b9e33b1d0535cc2cba95938ff92 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 28 Feb 2024 18:09:24 +0100 Subject: [PATCH 0925/1848] Added ESP-IDF badge to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e726a7ad62..d33794b37e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib) +# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib) [![Component Registry](https://components.espressif.com/components/jgromes/radiolib/badge.svg)](https://components.espressif.com/components/jgromes/radiolib) ### _One radio library to rule them all!_ From 22045d71896e3240e54c2d22d9e6a5fb18b5641c Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Wed, 28 Feb 2024 20:46:47 +0000 Subject: [PATCH 0926/1848] Range of tweaks & dutycycle / FUP --- .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 98 ++++++++----------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index d4ec506d17..f7db5b952a 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -21,6 +21,9 @@ For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ + + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN */ // include the library @@ -28,11 +31,11 @@ // SX1262 has the following pin order: // Module(NSS/CS, DIO1, RESET, BUSY) -// SX1262 radio = new Module(8, 14, 12, 13); +SX1262 radio = new Module(8, 14, 12, 13); // SX1278 has the following pin order: // Module(NSS/CS, DIO0, RESET, DIO1) -SX1278 radio = new Module(10, 2, 9, 3); +// SX1278 radio = new Module(10, 2, 9, 3); // create the node instance on the EU-868 band // using the radio module and the encryption key @@ -44,13 +47,12 @@ LoRaWANNode node(&radio, &EU868); // such as US915 and AU915, you must specify // the subband that matches the Frequency Plan // that you selected on your LoRaWAN console -/* - LoRaWANNode node(&radio, &US915, 2); -*/ +// LoRaWANNode node(&radio, &US915, 2); + void setup() { Serial.begin(9600); - + // initialize radio (SX1262 / SX1278 / ... ) with default settings Serial.print(F("[Radio] Initializing ... ")); int state = radio.begin(); @@ -62,48 +64,29 @@ void setup() { while(true); } - // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI - // when adding new end device in TTN, you will have to enter this number - // you can pick any number you want, but it has to be unique - uint64_t joinEUI = 0x12AD1011B0C0FFEE; - - // device identifier - this number can be anything - // when adding new end device in TTN, you can generate this number, - // or you can set any value you want, provided it is also unique - uint64_t devEUI = 0x70B3D57ED005E120; - - // select some encryption keys which will be used to secure the communication - // there are two of them - network key and application key - // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long - - // network key is the ASCII string "topSecretKey1234" - uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; - - // application key is the ASCII string "aDifferentKeyABC" - uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; - - // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used - // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded - // and can be set to NULL - - - // on EEPROM-enabled boards, after the device has been activated, - // the session can be restored without rejoining after device power cycle - // this is intrinsically done when calling `beginOTAA()` with the same keys - // in that case, the function will not need to transmit a JoinRequest - - // now we can start the activation - // this can take up to 10 seconds, and requires a LoRaWAN gateway in range - // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): - /* - uint8_t joinDr = 4; - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); - */ + // JoinEUI - previous versions of LoRaWAN called this AppEUI + // for development purposes you can use all zeros - see wiki for details + uint64_t joinEUI = 0x0000000000000000; + + // DevEUI - The device's Extended Unique Identifier + // TTN will generate one for you + uint64_t devEUI = 0x----------------; + + // encryption keys used to secure the communication + // TTN will generate them for you + // see wiki for details on copying & pasting them + uint8_t nwkKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, + 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; + uint8_t appKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, + 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; + + + // Manages uplink intervals to the TTN Fair Use Policy + node.setDutyCycle(true, 1250); + + // Begin the join to the network Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); delay(2000); // small delay between joining and uplink @@ -112,8 +95,7 @@ void setup() { Serial.println(state); while(true); } - -} +} // setup // counter to keep track of transmitted packets int count = 0; @@ -121,7 +103,7 @@ int count = 0; void loop() { // send uplink to port 10 Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello!" + String(count++); + String strUp = "Hello! " + String(count++); String strDown; int state = node.sendReceive(strUp, 10, strDown); if(state == RADIOLIB_ERR_NONE) { @@ -151,21 +133,25 @@ void loop() { Serial.println(F(" Hz")); } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("no downlink!")); + Serial.println(F("")); } else { Serial.print(F("failed, code ")); Serial.println(state); } - // on EEPROM enabled boards, you should save the current session - // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + // on boards that can save to Flash or EEPROMthis saves the session + // which allows recall of the session after reboot or deepsleep node.saveSession(); // wait before sending another packet - uint32_t minimumDelay = 60000; // try to send once every minute - uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) + uint32_t minimumDelay = 300000; // try to send once every 3 minutes + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per FUP & law!) uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows - + + Serial.print(F("[LoRaWAN] Next uplink in ")); + Serial.print(delayMs/60); + Serial.println(F("s")); + delay(delayMs); -} +} // loop From 7389d74e69c139eb857e07881762fd393faa8d96 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Fri, 1 Mar 2024 09:46:38 +0000 Subject: [PATCH 0927/1848] Update the reference version to latest LW code base --- .../LoRaWAN_End_Device_Reference.ino | 191 +++++++----------- 1 file changed, 75 insertions(+), 116 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 207dd356d2..1e5faf6d42 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -22,6 +22,9 @@ For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ + + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN */ // include the library @@ -29,11 +32,11 @@ // SX1262 has the following pin order: // Module(NSS/CS, DIO1, RESET, BUSY) -// SX1262 radio = new Module(8, 14, 12, 13); +SX1262 radio = new Module(8, 14, 12, 13); // SX1278 has the following pin order: // Module(NSS/CS, DIO0, RESET, DIO1) -SX1278 radio = new Module(10, 2, 9, 3); +// SX1278 radio = new Module(10, 2, 9, 3); // create the node instance on the EU-868 band // using the radio module and the encryption key @@ -45,9 +48,8 @@ LoRaWANNode node(&radio, &EU868); // such as US915 and AU915, you must specify // the subband that matches the Frequency Plan // that you selected on your LoRaWAN console -/* - LoRaWANNode node(&radio, &US915, 2); -*/ +// LoRaWANNode node(&radio, &US915, 2); + void setup() { Serial.begin(9600); @@ -63,43 +65,29 @@ void setup() { while(true); } - // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI - // when adding new end device in TTN, you will have to enter this number - // you can pick any number you want, but it has to be unique - uint64_t joinEUI = 0x12AD1011B0C0FFEE; - - // device identifier - this number can be anything - // when adding new end device in TTN, you can generate this number, - // or you can set any value you want, provided it is also unique - uint64_t devEUI = 0x70B3D57ED005E120; - - // select some encryption keys which will be used to secure the communication - // there are two of them - network key and application key - // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + // JoinEUI - previous versions of LoRaWAN this was AppEUI + // for development purposes you can use all zeros - see wiki for details + uint64_t joinEUI = 0x0000000000000000; - // network key is the ASCII string "topSecretKey1234" - uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + // DevEUI - The device's Extended Unique Identifier + // TTN will generate one for you + uint64_t devEUI = 0x----------------; - // application key is the ASCII string "aDifferentKeyABC" - uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + // encryption keys used to secure the communication + // TTN will generate them for you + // see wiki for details on copying & pasting them + uint8_t nwkKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, + 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; + uint8_t appKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, + 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; - // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used - // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded - // and can be set to NULL + // Override the default join rate + uint8_t joinDR = 3; - // now we can start the activation - // this can take up to 10 seconds, and requires a LoRaWAN gateway in range - // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): - /* - uint8_t joinDr = 4; - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); - */ + // Begin the join to the network Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDR); if(state >= RADIOLIB_ERR_NONE) { Serial.println(F("success!")); delay(2000); // small delay between joining and uplink @@ -112,51 +100,24 @@ void setup() { Serial.print("[LoRaWAN] DevAddr: "); Serial.println(node.getDevAddr(), HEX); - // on EEPROM-enabled boards, after the device has been activated, - // the session can be restored without rejoining after device power cycle - // this is intrinsically done when calling `beginOTAA()` with the same keys - // or if you 'lost' the keys or don't want them included in your sketch - // you can call `restore()` - /* - Serial.print(F("[LoRaWAN] Resuming previous session ... ")); - state = node.restore(); - if(state >= RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - */ - - // disable the ADR algorithm + // disable the ADR algorithm (on by default which is preferable) node.setADR(false); - // set a fixed datarate - node.setDatarate(5); - // in order to set the datarate persistent across reboot/deepsleep, use the following: - /* - node.setDatarate(5, true); - */ + // set a fixed datarate & make it persistent (not normal) + node.setDatarate(5, true); - // enable CSMA - // this tries to minimize packet loss by searching for a free channel - // before actually sending an uplink + // enable CSMA which tries to minimize packet loss by searching + // for a free channel before actually sending an uplink node.setCSMA(6, 2, true); - // enable or disable the dutycycle - // the second argument specific allowed airtime per hour in milliseconds - // 1250 = TTN FUP (30 seconds / 24 hours) - // if not called, this corresponds to setDutyCycle(true, 0) - // setting this to 0 corresponds to the band's maximum allowed dutycycle by law - node.setDutyCycle(true, 1250); - - // enable or disable the dwell time limits - // the second argument specifies the allowed airtime per uplink in milliseconds - // unless specified, this argument is set to 0 - // setting this to 0 corresponds to the band's maximum allowed dwell time by law + // manages uplink intervals to the TTN Fair Use Policy + node.setDutyCycle(true, 1250); + + // enable the dwell time limits - 400ms is the limit for the US node.setDwellTime(true, 400); -} + +} // setup + void loop() { int state = RADIOLIB_ERR_NONE; @@ -173,44 +134,45 @@ void loop() { // retrieve the last uplink frame counter uint32_t fcntUp = node.getFcntUp(); - Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello!" + String(fcntUp); + Serial.print(F("[LoRaWAN] Sending uplink packet #")); + Serial.println(fcntUp); + String strUp = "Hello! " + String(fcntUp); // send a confirmed uplink to port 10 every 64th frame // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { + Serial.print(F("[LoRaWAN] Requesting LinkCheck and DeviceTime")); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); state = node.uplink(strUp, 10, true); } else { state = node.uplink(strUp, 10); } - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { + if(state != RADIOLIB_ERR_NONE) { Serial.print(F("failed, code ")); Serial.println(state); } - // after uplink, you can call downlink(), - // to receive any possible reply from the server - // this function must be called within a few seconds - // after uplink to receive the downlink! - Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + // after uplink, you must call downlink() to receive any possible reply + // from the server. This function must be called before the Rx1 delay + // for the network. Typically this is 5s after end of uplink. + Serial.println(F("[LoRaWAN] Waiting for downlink ... ")); String strDown; - // you can also retrieve additional information about - // uplink or downlink by passing a reference to - // LoRaWANEvent_t structure - LoRaWANEvent_t event; - state = node.downlink(strDown, &event); + // you can also retrieve additional information about an uplink or + // downlink by passing a reference to LoRaWANEvent_t structure + LoRaWANEvent_t downlinkDetails; + state = node.downlink(strDown, &downlinkDetails); if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - - // print data of the packet (if there are any) + // print data of the packet Serial.print(F("[LoRaWAN] Data:\t\t")); if(strDown.length() > 0) { - Serial.println(strDown); + for (uint8_t c = 0; c < strDown.length(); c++) { + uint8_t value = strDown[c]; + if (value < 10) Serial.print(F("0")); + Serial.print(value, HEX); + } + Serial.println(); } else { Serial.println(F("")); } @@ -232,30 +194,22 @@ void loop() { // print extra information about the event Serial.println(F("[LoRaWAN] Event information:")); - Serial.print(F("[LoRaWAN] Direction:\t")); - if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) { - Serial.println(F("uplink")); - } else { - Serial.println(F("downlink")); - } Serial.print(F("[LoRaWAN] Confirmed:\t")); - Serial.println(event.confirmed); + Serial.println(downlinkDetails.confirmed); Serial.print(F("[LoRaWAN] Confirming:\t")); - Serial.println(event.confirming); + Serial.println(downlinkDetails.confirming); Serial.print(F("[LoRaWAN] Datarate:\t")); - Serial.println(event.datarate); + Serial.println(downlinkDetails.datarate); Serial.print(F("[LoRaWAN] Frequency:\t")); - Serial.print(event.freq, 3); + Serial.print(downlinkDetails.freq, 3); Serial.println(F(" MHz")); Serial.print(F("[LoRaWAN] Output power:\t")); - Serial.print(event.power); + Serial.print(downlinkDetails.power); Serial.println(F(" dBm")); Serial.print(F("[LoRaWAN] Frame count:\t")); - Serial.println(event.fcnt); + Serial.println(downlinkDetails.fcnt); Serial.print(F("[LoRaWAN] Port:\t\t")); - Serial.println(event.port); - - Serial.print(radio.getFrequencyError()); + Serial.println(downlinkDetails.port); uint8_t margin = 0; uint8_t gwCnt = 0; @@ -276,21 +230,26 @@ void loop() { } } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("timeout!")); + // Not really necessary to report normal operation } else { Serial.print(F("failed, code ")); Serial.println(state); } - // on EEPROM enabled boards, you should save the current session - // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + // on boards that can save to Flash or EEPROM this saves the session + // which allows recall of the session after reboot or deepsleep node.saveSession(); // wait before sending another packet - uint32_t minimumDelay = 60000; // try to send once every minute - uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + uint32_t minimumDelay = 3 * 60 * 1000; // try to send once every 3 minutes + uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per FUP & law!) + uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows + + Serial.print(F("[LoRaWAN] Next uplink in ")); + Serial.print(delayMs/1000); + Serial.println(F("s")); delay(delayMs); -} + +} // loop \ No newline at end of file From ec9126dae0e31ec8b3fd63e0b2fccda4c27c1ab9 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Fri, 1 Mar 2024 09:48:55 +0000 Subject: [PATCH 0928/1848] Added last updated dates & corresponding RadioLib version number --- examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 6 +++++- .../LoRaWAN_End_Device_Reference.ino | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino index f7db5b952a..9089a77c9e 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino @@ -24,6 +24,10 @@ For LoRaWAN details, see the wiki page https://github.com/jgromes/RadioLib/wiki/LoRaWAN + + + Last updated 1st March 2024 for RadioLib 6.4.2 + */ // include the library @@ -140,7 +144,7 @@ void loop() { Serial.println(state); } - // on boards that can save to Flash or EEPROMthis saves the session + // on boards that can save to Flash or EEPROM this saves the session // which allows recall of the session after reboot or deepsleep node.saveSession(); diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino index 1e5faf6d42..8e50b7a504 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -25,6 +25,10 @@ For LoRaWAN details, see the wiki page https://github.com/jgromes/RadioLib/wiki/LoRaWAN + + + Last updated 1st March 2024 for RadioLib 6.4.2 + */ // include the library From 3d8c2e866dd2f56a8d6cecbdbc55e04695e3e70b Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Sat, 2 Mar 2024 13:54:49 +0000 Subject: [PATCH 0929/1848] WIP Starter for preview --- examples/LoRaWAN/Starter/config.h | 85 +++++++++++++ examples/LoRaWAN/Starter/main.cpp | 44 +++++++ examples/LoRaWAN/Starter/notes.md | 202 ++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 examples/LoRaWAN/Starter/config.h create mode 100644 examples/LoRaWAN/Starter/main.cpp create mode 100644 examples/LoRaWAN/Starter/notes.md diff --git a/examples/LoRaWAN/Starter/config.h b/examples/LoRaWAN/Starter/config.h new file mode 100644 index 0000000000..bc50acf65a --- /dev/null +++ b/examples/LoRaWAN/Starter/config.h @@ -0,0 +1,85 @@ + +#include + +// How often to send an uplink - consider legal & FUP constraints - see notes +uint32_t uplinkInterval = 3 * 60 * 1000; // minutes x seconds x milliseconds + +uint64_t joinEUI = 0x0000000000000000; +uint64_t devEUI = 0x0000000000000000; +uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t nwkKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + + +// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// Auto select MCU <-> radio connections +// If you get an error message when compiling, it may be that the +// pinmap could not be determined - see the notes for more info + +#if defined(ARDUINO_TTGO_LORA32_V1) + #pragma message ("TTGO LoRa32 v1 - no Display") + SX1276 radio = new Module(18, 26, 14, 33); + +// #elif defined(ARDUINO_TTGO_LORA32_V2) +// #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + +#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 14, 33); + +// #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) +// #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") + +// #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) +// #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") +// SX1276 radio = new Module(18, 26, 23, 33); + +// #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) +// #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") + +#elif defined(ARDUINO_heltec_wifi_kit_32_V2) + #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_heltec_wifi_kit_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +// #elif defined(ARDUINO_CUBECELL_BOARD) +// #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") +// SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +// #elif defined(ARDUINO_CUBECELL_BOARD_V2) +// #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") + +#elif defined(ARDUINO_SAMD_FEATHER_M0) + #pragma message ("Adafruit Feather M0 with RFM95") + #pragma message ("Link required on board") + SX1276 radio = new Module(8, 3, 4, 6); + +#else + #pragma message ("Unknown board - no pinmap") + SX1262 radio = new Module(8, 14, 12, 13); + +#endif + +LoRaWANNode node(&radio, &Region, subBand); + + +// Helper function to display any issues +void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { + if (isFail) { + Serial.print(message); + Serial.print("("); + Serial.print(state); + Serial.println(")"); + while (Freeze); + } +} diff --git a/examples/LoRaWAN/Starter/main.cpp b/examples/LoRaWAN/Starter/main.cpp new file mode 100644 index 0000000000..a2ca1265fd --- /dev/null +++ b/examples/LoRaWAN/Starter/main.cpp @@ -0,0 +1,44 @@ +#include + +#include "config.h" + +void setup() { + Serial.begin(115200); + while (!Serial); + Serial.println(F("\nSetup ... ")); + + Serial.println(F("Initalise the radio")); + int state = radio.begin(); + debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + + Serial.println(F("Join ('login') to the LoRaWAN Network")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true); + + Serial.println(F("Ready!\n")); +} + + +void loop() { + Serial.print(F("Sending uplink #")); + + // Read some inputs + uint8_t Digital1 = digitalRead(2); + uint16_t Analog1 = analogRead(A0); + + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = Digital1; + uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(Analog1); + + // Perform an uplink + int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + + // Complete serial line with the uplink counter + Serial.println(node.getFcntUp()); + + // Wait until next uplink - observing legal & TTN FUP constraints + delay(uplinkInterval); +} diff --git a/examples/LoRaWAN/Starter/notes.md b/examples/LoRaWAN/Starter/notes.md new file mode 100644 index 0000000000..4f56a617a9 --- /dev/null +++ b/examples/LoRaWAN/Starter/notes.md @@ -0,0 +1,202 @@ + + +# RadioLib LoRaWAN on TTN starter script + +## Welcome + +These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C coding ninja but some familarity with C and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration. + + +## Introduction + +LoRaWAN is an amazing system for small battery powered sensors collecting data for years at a time. With great features comes some more complex elements which means it is not quite as simple as just providing WiFi credentials and pushing data through. It is in the range of setting up & customising the settings for a home router but with no wizards to do the heavy lifting for you. So we strongly recommend spending a couple of hours reviewing the TTN Getting Started section so you are aware of the minimum knowledge to make a successful start: https://www.thethingsnetwork.org/docs/lorawan/. Johan's video is amazing but is also drinking from the firehose. Read the text first and then watch the video on Youtube where there are bookmarks to deliver it in small digestable chunks. + +These notes plus a lot more are available in the wiki: https://github.com/jgromes/RadioLib/wiki/LoRaWAN + +For questions about using RadioLib there is the discussions section (https://github.com/jgromes/RadioLib/discussions) and if you believe you've found an issue (aka bug), the issues section (https://github.com/jgromes/RadioLib/issues). If posting an issue please ensure you tell us what hardware you are using and provide a debug log - please do not use verbose mode unless asked to. If the question is more LoRaWAN or firmware related, then you can use the TTN forum: https://www.thethingsnetwork.org/forum/ + + +## Register & setup on TTN + +This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Helium does not support LoRaWAN v1.1 which is the version implemented by RadioLib. Chirpstack & other LoRaWAN Network Server (LNS) stacks have not yet been tried so YMMV. + +Why no screen shots? TTS is a web based app, one that you will need to become familiar with and we will need to direct you to some of the less obvious parts. So much better that you learn the layouts in concept than slavishly follow screen shots that can & will go stale. + +There will be some instructions that you have to take on face value. You didn't learn to run before you walked and it's so much more encouraging to get started and build on success than get bogged down in endless details. Once you are up & running more of the details start to slot in to place. + +### Register on TTN + +Go to https://www.thethingsnetwork.org/get-started and register - just like any other website. These instructions are for TTS Sandbox. + +Once you have confirmed your email address, you can login to the console here: https://console.cloud.thethings.network/. If you allow your browser to share you location the best console will be selected. For most users the best one is the obvious one, if you have any doubts you can ask on the forum here: https://www.thethingsnetwork.org/forum/ - you login with the exact same details. + +It is simpler to register your gateway first. If you don't have a gateway, then a The Things Indoor Gateway (TTIG) is a very affordable option. A gateway gives you a console to see if your device is being heard and is hugely useful when debugging a DIY device. If you are in range of a community gateway you may be lucky with your first device creation but you will never know if you are in range unless you have access to that gateways console. + +You can read up on key concepts and troubleshooting here: https://www.thethingsindustries.com/docs/gateways/ + +LoRa stands for Long Range - having the gateway & device on the same desk tends to overload both receiver circuits when they hear a transmission so close to hand. The gateway should be 5 - 10m away, preferably with a solid wall in the way as well. + +### Create your application + +An application is like a box to keep some devices in - normally doing the same thing - on larger deployments this may be 1,000's of similar devices. Starting out it it is likely to be just a few so there is no need to get concerned about how to divide up your use just yet. + +Onced logged in to the console you can go in to Applications to create your first application. The ID must be all lower case or numbers, no spaces, dashes are OK and it has to be unique to the entire TTN community - so `first-app` will be rejected - you could use `your-username-first-app` as that's likely to be unique. The name and description are for your own use and are optional. + +The main menu for an application is in the left hand panel - nothing is needed there just yet. + +### Create your device + +On the right hand side about half way down on your application's summary is a big blue button `+ Register end device`. Click this to create the settings for your first device. + +You are making your own device using a third party LoRaWAN stack so there will not be an entry in the device repository so choose 'Enter end device specifics manually'. + +Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'. + +Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B. + +At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the cosole generate them so they are properly formatted. + +Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like devicename-01. The you can click the blue 'Register device'. + +When many sensors are big deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do. + +Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the Resets join nonces option. You will see a warning about replay attacks which is entirely proper & correct. If anyone evesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password. + +You then need to copy over the device details in to the config file for RadioLib. There are buttons to copy items to the clipboard so you don't have to hand type them. + +### Copy & Paste made easy + +You can copy the EUIs & keys from the device overview section. + +The EUIs are really straightforward - click the clipboard icon at the right hand end of the EUI display field and it will be copied in the format you need. You can then paste it in to the code - you must leave the 0x in place so the compiler knows that it's a hex value. + +The keys are relatively straightforward. Click the eye icon at the right hand end of the field. Then click the <> icon that will appear to the left. This will format the hex values as an array. Then you can click the clipboard icon to copy the array and then paste it between the { } brackets. + +### Secrets to keep safe. + +The Join & Dev EUI's are transmitted in plain text when the device joins a network. The gateway ID is public. If you have an issue and are asked for details, there are only three things to keep private - your password, the keys which are used for encryption and any API keys you create which are used for accessing your data & configuration. + + +### Monitoring your device + +If you are on your application summary page you'll see uplinks in the small activity box top right with a link to the full size table. If you click the Live Data menu item on the left it will show activity for all the devices registered on the application in the full window. + +If you just want your devices activity, from the summary page click on the device in the list in the middle of the page. + +The main menu for a device is the horizontal band: Overview, Live Data, Messaging etc. You can click Live Data or the link above the small activity box. + +**The console shows LIVE data - not a history of everything that has ever happened. A LNS is a management & relay service, not a database. When you open the console you may see a summary of recent activity - this is a bonus. You must leave the console open, even in another tab, if you want to see live activity.** + + +### Explore + +Nothing on the console can be upset unless you confirm a warning message, so you are safe to explore the different menus to orientate yourself. This is very good idea so you are have an understanding of the layout of the land and shouldn't take more than 10 or 15 minutes. The documentation & volunteers on GitHub and the TTN forum will make refer to parts of the console without giving blow by blow directions. + + + + +## The config.h + +### The uplinkInterval + +LoRaWAN devices typically send small amounts of data at intervals between 15 minutes through to once per day. This allows a device to run on two AA batteries for 2 to 5 years. Hoping that LoRaWAN can move lots of data and your device can regularly receive commands to do something on demand is trying to bend the LoRaWAN system in ways it is not designed for and usually ends up with far too many issues to unravel. + +The radio frequencies that are used are usually shared with other Industrial, Scientific & Medical, known as ISM, users. The LoRa modulation is particularly resistance to interference due to other simultaneous transmissions on the same frequency but too much local activity will mean that not all uplinks get through. The Things Industries suggest designing a system to a potential packet loss rate of 10%. Typically we see 1 or 2% loss. This is entirely down to shared use of the radio waves, once an uplink is heard by a gateway the system is super reliable through The Things Stack. + +To ensure that the shared ISM bands are fairly used there are limits defined in law on how often you can transmit, called Duty Cycle. The details vary by region or country but typically you can only transmit for 1% of the time. Some frequencies you can only use 0.1% of the time. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/ for more information. + +Additionally, as The Things Stack Sandbox aka TTN is an array of servers in three locations around the world paid for by The Things Industries, there is a Fair Use Policy so that those learning LoRaWAN, communities, hobbyists & makers are guided on how much of the resource any one device can use. In short, it's 30 seconds of airtime a day and 10 downlinks. When a gateway is transmitting a downlink it can not hear any uplinks (contributing to the potential uplink loss outlined above). The community concensus is that 1 downlink a fortnight to update or adjust settings is appropriate. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/#fair-use-policy for more information. + +You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. A uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so + +With all thes considerations, trying to use LoRaWAN for command & control isn't appropriate and realtime GPS tracking almost always breaches FUP and usually legal limits, leaving aside the challenges of coverage. + +See the hints & tips section on testing your device. + + +### EUI's & Keys + +In the config.h towards the top there are four lines thus: + +// replace-with-your-device-id +uint64_t joinEUI = 0x0000000000000000; +uint64_t devEUI = 0x0000000000000000; +uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t nwkKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +On the TTN console on the device summary page, click the clipboard icon next to the DevEUI, highlight the 16 0's in the third line after the x and paste. + +The devEUI must start with 0x and will end up looking something like 0x70B3D57ED006544E + +For the appKey we need TTN to format it correctly. Click the eye icon and an extra icon will appear <> - click this and the key will be formatted for you. Click the clipboard icon and then paste over the 32 0x00's in the config file. Then do the same for nwkKey. + +A key will end up something like 0x31, 0x16, 0x6A, 0x22, 0x97, 0x52, 0xB6, 0x34, 0x57, 0x45, 0x1B, 0xC3, 0xC9, 0xD8, 0x83, 0xE8 + + +### Region + +The region value you use MUST match the one you selected on the console. + +If you are using US915 or AU915 then you should change the subBand const to 2. + +### The pinmap + +This is the connections between the MCU (ESP32/ATmega/SAMD) and the LoRa radio (SX1276/SX1262). + +Prebuilt modules are easy - we can detect the board and setup the pinmap for you. These boards are: + +* TTGO_LoRa32 +* TTGO_LoRa32_V1 +* TTGO_LORA32_V2 +* TTGO_LORA32_v21NEW +* HELTEC_WIFI_LORA_32 +* HELTEC_WIFI_LORA_32_V2 +* HELTEC_WIFI_LORA_32_V3 +* CUBECELL_BOARD + +If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu. + +* TBEAM_USE_RADIO_SX1262 +* TBEAM_USE_RADIO_SX1276 + +If you have an Adafruit Feather M0 with RFM95 then you must solder a wire or use a jumper to link from pin 6 to io1: https://learn.adafruit.com/the-things-network-for-feather/arduino-wiring + + +If you have a module that's not on this list, please go to the "Pinmap How-To" below. + + + +## Observations on the main sketch + +Most of the sketch has comments that tell you what the various parts are doing. This should add a little more info: + +### The Join + +When a device is first started, it needs to register with the LoRaWAN Network Server (LNS) and setup it's session. With the settings from the console copied over and a gateway an appropriate distance away, most of the time the join will 'just work'. + +If it doesn't, then there is no point trying repeatedly without going through the troubleshootng sequence. So this starter sketch will try once only to save the airwaves & TTN Community servers from repeated misfires. + + +### The payload + +You may see other starter sketches sending text. Apart from being massively inefficient, the text isn't easily displayed on the TTN console which makes it rather pointless and pro embedded engineers don't send strings. So this sketch sends the data as a sequence of bytes as recommended. + +Further reading on this can be found here, just ignore the pink message about v2, it's all still valid: https://www.thethingsnetwork.org/docs/devices/bytes/ + +We've not assumed anything about any sensors you have, so we are just reading a digital & an analog pin. An analog reading is typically a two byte value - an integer - this is split using the Arduino highByte & lowByte function. You'll see how we put it back together in the TTN console below. + + +## TTN Console Payload Decoder + +Coming soon + +## Hints & Tips + +### Device testing + +The LoRaWAN code base works to a specification and once you are happy your device is able to join & send a few dozen uplinks, continuing to sit around waiting for an uplink to test your sensor code & payload format is a waste of your time. The solution is to write everything else in a different sketch, output the array to the serial console and then you can copy & paste the hex array in to the TTN console Payload Formatters section to test the decoding. + + +## Pinmap How-To + + From a926d5e13ad6548c683eefce88d52394a05f8115 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Sat, 2 Mar 2024 14:01:32 +0000 Subject: [PATCH 0930/1848] Change the names to protect the innocent --- examples/LoRaWAN/Starter/{main.cpp => Starter.ino} | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) rename examples/LoRaWAN/Starter/{main.cpp => Starter.ino} (90%) diff --git a/examples/LoRaWAN/Starter/main.cpp b/examples/LoRaWAN/Starter/Starter.ino similarity index 90% rename from examples/LoRaWAN/Starter/main.cpp rename to examples/LoRaWAN/Starter/Starter.ino index a2ca1265fd..ced6020ffd 100644 --- a/examples/LoRaWAN/Starter/main.cpp +++ b/examples/LoRaWAN/Starter/Starter.ino @@ -20,7 +20,7 @@ void setup() { void loop() { - Serial.print(F("Sending uplink #")); + Serial.println(F("Sending uplink")); // Read some inputs uint8_t Digital1 = digitalRead(2); @@ -36,9 +36,6 @@ void loop() { int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); - // Complete serial line with the uplink counter - Serial.println(node.getFcntUp()); - // Wait until next uplink - observing legal & TTN FUP constraints delay(uplinkInterval); } From 268e2d704fe8ad7cdb501490a0933f0c1d717221 Mon Sep 17 00:00:00 2001 From: Jan Szumiec Date: Sat, 2 Mar 2024 18:01:32 +0100 Subject: [PATCH 0931/1848] Receive messages for multiple POCSAG RICs (#998) * Make it possible to supply a list of addresses for POCSAG reception. * Initialize some instance variables to sensible values. --- src/protocols/Pager/Pager.cpp | 39 ++++++++++++++++++++++++++++++++--- src/protocols/Pager/Pager.h | 14 +++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 799fd626cf..e1682de651 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -28,6 +28,9 @@ PagerClient::PagerClient(PhysicalLayer* phy) { #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE readBitInstance = phyLayer; #endif + filterNumAddresses = 0; + filterAddresses = NULL; + filterMasks = NULL; } int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { @@ -246,6 +249,21 @@ int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { filterAddr = addr; filterMask = mask; + return startReceiveCommon(); +} + +int16_t PagerClient::startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddresses) { + // save the variables + readBitPin = pin; + + filterAddresses = addrs; + filterMasks = masks; + filterNumAddresses = numAddresses; + + return startReceiveCommon(); +} + +uint16_t PagerClient::startReceiveCommon() { // set the carrier frequency int16_t state = phyLayer->setFrequency(baseFreq); RADIOLIB_ASSERT(state); @@ -260,7 +278,7 @@ int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { // now set up the direct mode reception Module* mod = phyLayer->getMod(); - mod->hal->pinMode(pin, mod->hal->GpioModeInput); + mod->hal->pinMode(readBitPin, mod->hal->GpioModeInput); // set direct sync word to the frame sync word // the logic here is inverted, because modules like SX1278 @@ -356,8 +374,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { // should be an address code word, extract the address uint32_t addr_found = ((cw & RADIOLIB_PAGER_ADDRESS_BITS_MASK) >> (RADIOLIB_PAGER_ADDRESS_POS - 3)) | (framePos/2); - if((addr_found & filterMask) == (filterAddr & filterMask)) { - // we have a match! + if (addressMatched(addr_found)) { match = true; if(addr) { *addr = addr_found; @@ -460,6 +477,22 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { } #endif +bool PagerClient::addressMatched(uint32_t addr) { + if (filterNumAddresses == 0) { + return ((addr & filterMask) == (filterAddr & filterMask)); + } else { + if (filterAddresses == NULL || filterMasks == NULL) { + return false; + } + for (size_t i = 0; i < filterNumAddresses; i++) { + if ((filterAddresses[i] & filterMasks[i]) == (addr & filterMasks[i])) { + return true; + } + } + return false; + } +} + void PagerClient::write(uint32_t* data, size_t len) { // write code words from buffer for(size_t i = 0; i < len; i++) { diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 11b9c4dd02..db372613cc 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -130,6 +130,15 @@ class PagerClient { */ int16_t startReceive(uint32_t pin, uint32_t addr, uint32_t mask = 0xFFFFF); + /*! + \brief Start reception of POCSAG packets for multiple addresses and masks. + \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). + \param addrs Array of addresses to receive. + \param masks Array of address masks to use for filtering. Masks will be applied to corresponding addresses in addr array. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddress); + /*! \brief Get the number of POCSAG batches available in buffer. Limited by the size of direct mode buffer! \returns Number of available batches. @@ -175,10 +184,15 @@ class PagerClient { uint16_t bitDuration; uint32_t filterAddr; uint32_t filterMask; + uint32_t *filterAddresses; + uint32_t *filterMasks; + size_t filterNumAddresses; bool inv = false; void write(uint32_t* data, size_t len); void write(uint32_t codeWord); + uint16_t startReceiveCommon(); + bool addressMatched(uint32_t addr); #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE uint32_t read(); From cf561733d254b29d559972d00e8c288445c11f36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 2 Mar 2024 18:09:56 +0100 Subject: [PATCH 0932/1848] [Pager] Minor fixes --- src/protocols/Pager/Pager.cpp | 40 ++++++++++++++++++++--------------- src/protocols/Pager/Pager.h | 3 ++- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index e1682de651..989338c866 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -248,22 +248,24 @@ int16_t PagerClient::startReceive(uint32_t pin, uint32_t addr, uint32_t mask) { readBitPin = pin; filterAddr = addr; filterMask = mask; - - return startReceiveCommon(); + filterAddresses = NULL; + filterMasks = NULL; + filterNumAddresses = 0; + return(startReceiveCommon()); } int16_t PagerClient::startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddresses) { // save the variables readBitPin = pin; - + filterAddr = 0; + filterMask = 0; filterAddresses = addrs; filterMasks = masks; filterNumAddresses = numAddresses; - - return startReceiveCommon(); + return(startReceiveCommon()); } -uint16_t PagerClient::startReceiveCommon() { +int16_t PagerClient::startReceiveCommon() { // set the carrier frequency int16_t state = phyLayer->setFrequency(baseFreq); RADIOLIB_ASSERT(state); @@ -478,19 +480,23 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { #endif bool PagerClient::addressMatched(uint32_t addr) { - if (filterNumAddresses == 0) { - return ((addr & filterMask) == (filterAddr & filterMask)); - } else { - if (filterAddresses == NULL || filterMasks == NULL) { - return false; - } - for (size_t i = 0; i < filterNumAddresses; i++) { - if ((filterAddresses[i] & filterMasks[i]) == (addr & filterMasks[i])) { - return true; - } + // check whether to match single or multiple addresses/masks + if(filterNumAddresses == 0) { + return((addr & filterMask) == (filterAddr & filterMask)); + } + + // multiple addresses, check there are some to match + if((filterAddresses == NULL) || (filterMasks == NULL)) { + return(false); + } + + for(size_t i = 0; i < filterNumAddresses; i++) { + if((filterAddresses[i] & filterMasks[i]) == (addr & filterMasks[i])) { + return(true); } - return false; } + + return(false); } void PagerClient::write(uint32_t* data, size_t len) { diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index db372613cc..f5cdb81902 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -135,6 +135,7 @@ class PagerClient { \param pin Pin to receive digital data on (e.g., DIO2 for SX127x). \param addrs Array of addresses to receive. \param masks Array of address masks to use for filtering. Masks will be applied to corresponding addresses in addr array. + \param numAddress Number of addresses/masks to match. \returns \ref status_codes */ int16_t startReceive(uint32_t pin, uint32_t *addrs, uint32_t *masks, size_t numAddress); @@ -191,7 +192,7 @@ class PagerClient { void write(uint32_t* data, size_t len); void write(uint32_t codeWord); - uint16_t startReceiveCommon(); + int16_t startReceiveCommon(); bool addressMatched(uint32_t addr); #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE From 9774a2299b48bbb3fa9029956b711e0567137c77 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Mar 2024 09:56:23 +0100 Subject: [PATCH 0933/1848] Update issue template for new debug levels --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/module-not-working.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f02e63f88f..ae6f4ecd3b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,7 +11,7 @@ assignees: '' Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. **Describe the bug** -A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode). +A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode) **using the appropriate debug mode**. **To Reproduce** Minimal Arduino sketch to reproduce the behavior. Please use Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)). diff --git a/.github/ISSUE_TEMPLATE/module-not-working.md b/.github/ISSUE_TEMPLATE/module-not-working.md index 1b67e8d6fe..189d98f453 100644 --- a/.github/ISSUE_TEMPLATE/module-not-working.md +++ b/.github/ISSUE_TEMPLATE/module-not-working.md @@ -24,7 +24,7 @@ paste the sketch here, even if it is an unmodified example code Wiring diagram, schematic, pictures etc. **Debug mode output** -Enable all [debug levels](https://github.com/jgromes/RadioLib/wiki/Debug-mode) and paste the Serial monitor output here. +Enable the appropriate [debug levels](https://github.com/jgromes/RadioLib/wiki/Debug-mode) and paste the Serial monitor output here. For debugging protocols, enable `RADIOLIB_DEBUG_PROTOCOL`. For debugging issues with the radio module itself, enable `RADIOLIB_DEBUG_SPI`. **Additional info (please complete):** - MCU: [e.g. Arduino Uno, ESP8266 etc.] From 4ee17cc168b5c8e94756502fd513f2554309cdbc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Mar 2024 11:07:23 +0100 Subject: [PATCH 0934/1848] Debugging rework --- src/BuildOpt.h | 79 ++++++-- src/BuildOptUser.h | 5 +- src/Module.cpp | 67 ++++--- src/modules/CC1101/CC1101.cpp | 9 +- src/modules/RF69/RF69.cpp | 6 +- src/modules/SX123x/SX1231.cpp | 8 +- src/modules/SX123x/SX1233.cpp | 8 +- src/modules/SX126x/SX126x.cpp | 46 ++--- src/modules/SX127x/SX127x.cpp | 10 +- src/modules/SX128x/SX128x.cpp | 12 +- src/modules/Si443x/Si4430.cpp | 2 +- src/modules/Si443x/Si4431.cpp | 2 +- src/modules/Si443x/Si4432.cpp | 2 +- src/modules/Si443x/Si443x.cpp | 12 +- src/modules/nRF24/nRF24.cpp | 4 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 182 +++++++++--------- src/protocols/Morse/Morse.cpp | 16 +- src/protocols/Pager/Pager.cpp | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 +- 19 files changed, 265 insertions(+), 211 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4609a1da48..a7adfbbc09 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -7,14 +7,18 @@ * Debug output enable. * Warning: Debug output will slow down the whole system significantly. * Also, it will result in larger compiled binary. - * Levels: debug - only main info - * verbose - full transcript of all SPI communication + * Levels: basic - only main info + * protocol - mainly LoRaWAN stuff, but other protocols as well + * SPI - full transcript of all SPI communication */ -#if !defined(RADIOLIB_DEBUG) - #define RADIOLIB_DEBUG (0) +#if !defined(RADIOLIB_DEBUG_BASIC) + #define RADIOLIB_DEBUG_BASIC (0) #endif -#if !defined(RADIOLIB_VERBOSE) - #define RADIOLIB_VERBOSE (0) +#if !defined(RADIOLIB_DEBUG_PROTOCOL) + #define RADIOLIB_DEBUG_PROTOCOL (0) +#endif +#if !defined(RADIOLIB_DEBUG_SPI) + #define RADIOLIB_DEBUG_SPI (0) #endif // set which output port should be used for debug output @@ -469,23 +473,35 @@ #define RADIOLIB_EXCLUDE_STM32WLX (1) #endif +// set the global debug mode flag +#if RADIOLIB_DEBUG_BASIC || RADIOLIB_DEBUG_PROTOCOL || RADIOLIB_DEBUG_SPI + #define RADIOLIB_DEBUG (1) +#else + #define RADIOLIB_DEBUG (0) +#endif + #if RADIOLIB_DEBUG #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M "\n", ##__VA_ARGS__) // some platforms do not support printf("%f"), so it has to be done this way - #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) #else #if !defined(RADIOLIB_DEBUG_PRINT) #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M, ##__VA_ARGS__) #endif #if !defined(RADIOLIB_DEBUG_PRINTLN) #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "\n", ##__VA_ARGS__) #endif - #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PRINT("%.3f", VAL) + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif - #define RADIOLIB_DEBUG_HEXDUMP(...) Module::hexdump(__VA_ARGS__) + + #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) RADIOLIB_DEBUG_PRINT(LEVEL); Module::hexdump(__VA_ARGS__) #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} @@ -493,14 +509,49 @@ #define RADIOLIB_DEBUG_HEXDUMP(...) {} #endif -#if RADIOLIB_VERBOSE - #define RADIOLIB_VERBOSE_PRINT(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) - #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) +#if RADIOLIB_DEBUG_BASIC + #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_DBG: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_DBG: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_DBG: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_DBG: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_BASIC_PRINT(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) {} +#endif + +#if RADIOLIB_DEBUG_PROTOCOL + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_PRO: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_PRO: ", __VA_ARGS__); +#else + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) {} +#endif + +#if RADIOLIB_DEBUG_SPI + #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_SPI: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_SPI: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN_LVL("", __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_SPI: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_SPI: ", __VA_ARGS__); #else - #define RADIOLIB_VERBOSE_PRINT(...) {} - #define RADIOLIB_VERBOSE_PRINTLN(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {} #endif + /*! \brief A simple assert macro, will return on error. */ diff --git a/src/BuildOptUser.h b/src/BuildOptUser.h index fc1a565743..d81104d7d2 100644 --- a/src/BuildOptUser.h +++ b/src/BuildOptUser.h @@ -5,7 +5,8 @@ // most commonly, RADIOLIB_EXCLUDE_* macros // or enabling debug output -//#define RADIOLIB_DEBUG (1) -//#define RADIOLIB_VERBOSE (1) +//#define RADIOLIB_DEBUG_BASIC (1) // basic debugging (e.g. reporting GPIO timeouts or module not being found) +//#define RADIOLIB_DEBUG_PROTOCOL (1) // protocol information (e.g. LoRaWAN internal information) +//#define RADIOLIB_DEBUG_SPI (1) // verbose transcription of all SPI communication - produces large debug logs! #endif diff --git a/src/Module.cpp b/src/Module.cpp index b6f8583d0f..ee1705842a 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -44,10 +44,10 @@ void Module::init() { this->hal->init(); this->hal->pinMode(csPin, this->hal->GpioModeOutput); this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh); - RADIOLIB_DEBUG_PRINTLN("\nRadioLib Debug Info"); - RADIOLIB_DEBUG_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); - RADIOLIB_DEBUG_PRINTLN("Platform: " RADIOLIB_PLATFORM); - RADIOLIB_DEBUG_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); + RADIOLIB_DEBUG_BASIC_PRINTLN("RadioLib Debug Info"); + RADIOLIB_DEBUG_BASIC_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); + RADIOLIB_DEBUG_BASIC_PRINTLN("Platform: " RADIOLIB_PLATFORM); + RADIOLIB_DEBUG_BASIC_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); } void Module::term() { @@ -89,14 +89,14 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t } // check failed, print debug info - RADIOLIB_DEBUG_PRINTLN(); - RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg); - RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb); - RADIOLIB_DEBUG_PRINTLN("value:\t\t0x%X", value); - RADIOLIB_DEBUG_PRINTLN("current:\t0x%X", currentValue); - RADIOLIB_DEBUG_PRINTLN("mask:\t\t0x%X", mask); - RADIOLIB_DEBUG_PRINTLN("new:\t\t0x%X", newValue); - RADIOLIB_DEBUG_PRINTLN("read:\t\t0x%X", readValue); + RADIOLIB_DEBUG_SPI_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN("address:\t0x%X", reg); + RADIOLIB_DEBUG_SPI_PRINTLN("bits:\t\t%d %d", msb, lsb); + RADIOLIB_DEBUG_SPI_PRINTLN("value:\t\t0x%X", value); + RADIOLIB_DEBUG_SPI_PRINTLN("current:\t0x%X", currentValue); + RADIOLIB_DEBUG_SPI_PRINTLN("mask:\t\t0x%X", mask); + RADIOLIB_DEBUG_SPI_PRINTLN("new:\t\t0x%X", newValue); + RADIOLIB_DEBUG_SPI_PRINTLN("read:\t\t0x%X", readValue); return(RADIOLIB_ERR_SPI_WRITE_FAILED); #else @@ -182,19 +182,19 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d } // print debug information - #if RADIOLIB_VERBOSE + #if RADIOLIB_DEBUG_SPI uint8_t* debugBuffPtr = NULL; if(cmd == SPIwriteCommand) { - RADIOLIB_VERBOSE_PRINT("W\t%X\t", reg); + RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg); debugBuffPtr = &buffOut[this->SPIaddrWidth/8]; } else if(cmd == SPIreadCommand) { - RADIOLIB_VERBOSE_PRINT("R\t%X\t", reg); + RADIOLIB_DEBUG_SPI_PRINT("R\t%X\t", reg); debugBuffPtr = &buffIn[this->SPIaddrWidth/8]; } for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", debugBuffPtr[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]); } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); #endif #if !RADIOLIB_STATIC_ONLY @@ -291,7 +291,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("GPIO pre-transfer timeout, is it connected?"); + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; @@ -318,7 +318,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("GPIO post-transfer timeout, is it connected?"); + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; delete[] buffIn; @@ -342,31 +342,34 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint } // print debug information - #if RADIOLIB_VERBOSE + #if RADIOLIB_DEBUG_SPI // print command byte(s) - RADIOLIB_VERBOSE_PRINT("CMD"); + RADIOLIB_DEBUG_SPI_PRINT("CMD"); if(write) { - RADIOLIB_VERBOSE_PRINT("W\t"); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("W\t"); } else { - RADIOLIB_VERBOSE_PRINT("R\t"); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("R\t"); } size_t n = 0; for(; n < cmdLen; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", cmd[n]); } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); // print data bytes - RADIOLIB_VERBOSE_PRINT("SI\t"); + RADIOLIB_DEBUG_SPI_PRINT("SI\t"); + for(n = 0; n < cmdLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("\t"); + } for(; n < buffLen; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", buffOut[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]); } - RADIOLIB_VERBOSE_PRINTLN(); - RADIOLIB_VERBOSE_PRINT("SO\t"); - for(n = cmdLen; n < buffLen; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t", buffIn[n]); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINT("SO\t"); + for(n = 0; n < buffLen; n++) { + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffIn[n]); } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); #endif #if !RADIOLIB_STATIC_ONLY diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index fbfa212bc8..447e0420e9 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -21,18 +21,18 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pw if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { flagFound = true; } else { - RADIOLIB_DEBUG_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); this->mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No CC1101 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No CC1101 found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN("M\tCC1101"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tCC1101"); } // configure settings not accessible by API @@ -916,7 +916,6 @@ void CC1101::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], uint8_t CC1101::randomByte() { // set mode to Rx SPIsendCommand(RADIOLIB_CC1101_CMD_RX); - RADIOLIB_DEBUG_PRINTLN("CC1101::randomByte"); // wait a bit for the RSSI reading to stabilise this->mod->hal->delay(10); @@ -1113,7 +1112,7 @@ void CC1101::SPIsendCommand(uint8_t cmd) { // stop transfer this->mod->hal->spiEndTransaction(); this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); - RADIOLIB_VERBOSE_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); + RADIOLIB_DEBUG_SPI_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); (void)status; } diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 54e6cc7492..a934898eda 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -23,18 +23,18 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, if(version == RADIOLIB_RF69_CHIP_VERSION) { flagFound = true; } else { - RADIOLIB_DEBUG_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("RF69 not found! (%d of 10 tries) RADIOLIB_RF69_REG_VERSION == 0x%04X, expected 0x0024", i + 1, version); this->mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No RF69 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No RF69 found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); } // configure settings not accessible by API diff --git a/src/modules/SX123x/SX1231.cpp b/src/modules/SX123x/SX1231.cpp index 44ff904d72..11424eed31 100644 --- a/src/modules/SX123x/SX1231.cpp +++ b/src/modules/SX123x/SX1231.cpp @@ -21,23 +21,23 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; this->chipRevision = version; } else { - RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No SX1231 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX1231 found!"); mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX1231"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX1231"); // configure settings not accessible by API int16_t state = config(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index ab8808f9a4..16c4bca143 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -22,23 +22,23 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po flagFound = true; this->chipRevision = version; } else { - RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version); mod->hal->delay(10); i++; } } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("No SX1233 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX1233 found!"); mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX1233"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX1233"); // configure settings not accessible by API int16_t state = config(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tRF69"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tRF69"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 8ba17ac0cb..716971c5a5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -22,11 +22,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo // try to find the SX126x chip if(!SX126x::findChip(this->chipType)) { - RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams // set the defaults, this will get overwritten later anyway @@ -107,11 +107,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL // try to find the SX126x chip if(!SX126x::findChip(this->chipType)) { - RADIOLIB_DEBUG_PRINTLN("No SX126x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX126x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); // initialize configuration variables (will be overwritten during public settings configuration) this->bitRate = 21333; // 48.0 kbps @@ -246,7 +246,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -295,7 +295,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { return(RADIOLIB_ERR_UNKNOWN); } - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); @@ -643,7 +643,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz); uint32_t sleepPeriod = symbolLength * sleepSymbols; - RADIOLIB_DEBUG_PRINTLN("Auto sleep period: %lu", sleepPeriod); + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", sleepPeriod); // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. // the duration is sleepPeriod + 2 * wakePeriod. @@ -654,7 +654,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t wakePeriod = RADIOLIB_MAX( (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) symbolLength * (minSymbols + 1)); //(B) - RADIOLIB_DEBUG_PRINTLN("Auto wake period: %lu", wakePeriod); + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", wakePeriod); // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < this->tcxoDelay + 1016) { @@ -1580,10 +1580,10 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) RADIOLIB_ASSERT(state); // check the version - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC char ver_pre[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); - RADIOLIB_DEBUG_PRINTLN("Pre-update version string: %s", ver_pre); + RADIOLIB_DEBUG_BASIC_PRINTLN("Pre-update version string: %s", ver_pre); #endif // enable patch update @@ -1612,10 +1612,10 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0); // check the version again - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC char ver_post[16]; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); - RADIOLIB_DEBUG_PRINTLN("Post-update version string: %s", ver_post); + RADIOLIB_DEBUG_BASIC_PRINTLN("Post-update version string: %s", ver_post); #endif return(state); @@ -1857,12 +1857,12 @@ int16_t SX126x::calibrateImage(float freqMin, float freqMax) { int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 standby(); uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_PRINTLN("Calibration failed, device errors: 0x%X", errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); } #endif return(state); @@ -2121,12 +2121,12 @@ int16_t SX126x::config(uint8_t modem) { state = this->mod->SPIcheckStream(); // if something failed, show the device errors - #if RADIOLIB_DEBUG + #if RADIOLIB_DEBUG_BASIC if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 standby(); uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_PRINTLN("Calibration failed, device errors: 0x%X", errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); } #endif @@ -2159,15 +2159,15 @@ bool SX126x::findChip(const char* verStr) { // check version register if(strncmp(verStr, version, 6) == 0) { - RADIOLIB_DEBUG_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); - RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); + RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN(); flagFound = true; } else { - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); - RADIOLIB_DEBUG_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); - RADIOLIB_DEBUG_PRINTLN("Expected string: %s", verStr); + #if RADIOLIB_DEBUG_BASIC + RADIOLIB_DEBUG_BASIC_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); + RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr); #endif this->mod->hal->delay(10); i++; diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index bdf4bae51f..7606f001b8 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -14,11 +14,11 @@ int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWo // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { - RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x"); // set mode to standby int16_t state = standby(); @@ -65,11 +65,11 @@ int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqD // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { - RADIOLIB_DEBUG_PRINTLN("No SX127x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tSX127x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x"); // set mode to standby int16_t state = standby(); @@ -1554,7 +1554,7 @@ bool SX127x::findChip(uint8_t* vers, uint8_t num) { } if(!flagFound) { - RADIOLIB_DEBUG_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version); + RADIOLIB_DEBUG_BASIC_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version); this->mod->hal->delay(10); i++; } diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 07d8661bfa..55b18dd96b 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -17,7 +17,7 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize LoRa modulation variables this->bandwidthKhz = bw; @@ -78,7 +78,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize GFSK modulation variables this->bitRateKbps = br; @@ -147,7 +147,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize BLE modulation variables this->bitRateKbps = br; @@ -202,7 +202,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1 this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; this->mod->SPIstreamType = true; this->mod->SPIparseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_PRINTLN("M\tSX128x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize FLRC modulation variables this->bitRateKbps = br; @@ -308,7 +308,7 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (500% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 5; - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start transmission state = startTransmit(data, len, addr); @@ -341,7 +341,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // calculate timeout (1000% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 10; - RADIOLIB_DEBUG_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index 45b5535692..7f9ed5fbe1 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -9,7 +9,7 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tSi4430"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4430"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 799cec763c..c603e6f150 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -9,7 +9,7 @@ int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tSi4431"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4431"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 40a97226ba..56690862fd 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -9,7 +9,7 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po // execute common part int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PRINTLN("M\tSi4432"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi4432"); // configure publicly accessible settings state = setFrequency(freq); diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 2097ee58c4..541f3eb743 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -15,11 +15,11 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) // try to find the Si443x chip if(!Si443x::findChip()) { - RADIOLIB_DEBUG_PRINTLN("No Si443x found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No Si443x found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN("M\tSi443x"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSi443x"); } // reset the device @@ -700,7 +700,7 @@ bool Si443x::findChip() { if(version == RADIOLIB_SI443X_DEVICE_VERSION) { flagFound = true; } else { - RADIOLIB_DEBUG_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); + RADIOLIB_DEBUG_BASIC_PRINTLN("Si443x not found! (%d of 10 tries) RADIOLIB_SI443X_REG_DEVICE_VERSION == 0x%02X, expected 0x0%X", i + 1, version, RADIOLIB_SI443X_DEVICE_VERSION); this->mod->hal->delay(10); i++; } @@ -769,9 +769,9 @@ int16_t Si443x::updateClockRecovery() { uint16_t rxOsr_fixed = (uint16_t)rxOsr; // print that whole mess - RADIOLIB_DEBUG_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); - RADIOLIB_DEBUG_PRINT_FLOAT(rxOsr, 2); - RADIOLIB_DEBUG_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); + RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); + RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2); + RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); // update oversampling ratio int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 3f64f27f16..a54298844e 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -23,11 +23,11 @@ int16_t nRF24::begin(int16_t freq, int16_t dr, int8_t pwr, uint8_t addrWidth) { // check SPI connection int16_t val = this->mod->SPIgetRegValue(RADIOLIB_NRF24_REG_SETUP_AW); if(!((val >= 0) && (val <= 3))) { - RADIOLIB_DEBUG_PRINTLN("No nRF24 found!"); + RADIOLIB_DEBUG_BASIC_PRINTLN("No nRF24 found!"); this->mod->term(); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } - RADIOLIB_DEBUG_PRINTLN("M\tnRF24"); + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tnRF24"); // configure settings inaccessible by public API int16_t state = config(); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index cbbe15a16d..fef8ff8110 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -71,12 +71,12 @@ int16_t LoRaWANNode::restore() { // check the mode value uint16_t lwMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID); if(lwMode == RADIOLIB_LORAWAN_MODE_NONE) { - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("mode value not set (no saved session)"); - RADIOLIB_DEBUG_PRINTLN("first 16 bytes of NVM:"); + #if RADIOLIB_DEBUG_PROTOCOL + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mode value not set (no saved session)"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("first 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(nvmBuff, 16); #endif // the mode value is not set, user will have to do perform the join procedure return(RADIOLIB_ERR_NETWORK_NOT_JOINED); @@ -95,7 +95,7 @@ int16_t LoRaWANNode::restore() { // get session parameters this->rev = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID); - RADIOLIB_DEBUG_PRINTLN("LoRaWAN session: v1.%d", this->rev); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); this->aFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID); @@ -158,7 +158,7 @@ int16_t LoRaWANNode::restore() { uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); memcpy(&this->commandsUp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - RADIOLIB_DEBUG_PRINTLN("Number of MAC commands: %d", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Number of MAC commands: %d", this->commandsUp.numCommands); state = this->setPhyProperties(); RADIOLIB_ASSERT(state); @@ -257,7 +257,7 @@ int16_t LoRaWANNode::restoreChannels() { } else { // RADIOLIB_LORAWAN_BAND_FIXED uint8_t numADRCommands = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - RADIOLIB_DEBUG_PRINTLN("Restoring %d stored channel masks", numADRCommands); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Restoring %d stored channel masks", numADRCommands); uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); @@ -342,7 +342,7 @@ void LoRaWANNode::beginCommon(uint8_t joinDr) { if(joinDr >= this->band->txFreqs[0].drMin && joinDr <= this->band->txFreqs[0].drMax) { drUp = joinDr; } else { - RADIOLIB_DEBUG_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", joinDr, this->band->txFreqs[0].drMin, this->band->txFreqs[0].drMax); joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; } @@ -464,13 +464,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); } else { // either invalid key checksum or mode, so wipe either way - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); - RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); + #if RADIOLIB_DEBUG_PROTOCOL + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); - RADIOLIB_DEBUG_PRINTLN("Wiping EEPROM and starting a clean session"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(nvmBuff, 16); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Wiping EEPROM and starting a clean session"); #endif this->wipe(); @@ -529,7 +529,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // send it state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); this->rxDelayStart = mod->hal->millis(); - RADIOLIB_DEBUG_PRINTLN("Join-request sent <-- Rx Delay start"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); RADIOLIB_ASSERT(state); // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received @@ -546,7 +546,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check received length size_t lenRx = this->phyLayer->getPacketLength(true); if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -560,7 +560,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check reply message type if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { - RADIOLIB_DEBUG_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -572,13 +572,13 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); - RADIOLIB_DEBUG_PRINTLN("joinAcceptMsg:"); - RADIOLIB_DEBUG_HEXDUMP(joinAcceptMsg, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); // get current JoinNonce from downlink and previous JoinNonce from persistent storage uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); - RADIOLIB_DEBUG_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); // JoinNonce received must be greater than the last JoinNonce heard, else error if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { return(RADIOLIB_ERR_JOIN_NONCE_INVALID); @@ -591,7 +591,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check LoRaWAN revision (the MIC verification depends on this) uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; - RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: 1.%d", this->rev); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN revision: 1.%d", this->rev); // verify MIC if(this->rev == 1) { @@ -753,13 +753,13 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, this->clearSession(); } else { // either invalid key checksum or mode, so wipe either way - #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); - RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); + #if RADIOLIB_DEBUG_PROTOCOL + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_HEXDUMP(nvmBuff, 16); - RADIOLIB_DEBUG_PRINTLN("Wiping EEPROM and starting a clean session"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(nvmBuff, 16); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Wiping EEPROM and starting a clean session"); #endif this->wipe(); @@ -1106,8 +1106,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf memcpy(foptsPtr, &cmd, 1 + cmd.len); foptsPtr += cmd.len + 1; } - RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsLen); // pop the commands from back to front for (; i >= 0; i--) { @@ -1154,10 +1154,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; - RADIOLIB_DEBUG_PRINTLN("FcntUp: %d", this->fcntUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FcntUp: %d", this->fcntUp); - RADIOLIB_DEBUG_PRINTLN("uplinkMsg pre-MIC:"); - RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("uplinkMsg pre-MIC:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); // calculate authentication codes memcpy(uplinkMsg, block1, RADIOLIB_AES128_BLOCK_SIZE); @@ -1183,7 +1183,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // set the timestamp so that we can measure when to start receiving this->rxDelayStart = mod->hal->millis(); - RADIOLIB_DEBUG_PRINTLN("Uplink sent <-- Rx Delay start"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); // calculate Time on Air of this uplink in milliseconds this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; @@ -1267,11 +1267,11 @@ int16_t LoRaWANNode::downlinkCommon() { // open Rx window by starting receive with specified timeout state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); - RADIOLIB_DEBUG_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); - RADIOLIB_DEBUG_PRINTLN("Closing Rx%d window", i+1); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set if(!this->phyLayer->isRxTimeout()) { @@ -1280,7 +1280,7 @@ int16_t LoRaWANNode::downlinkCommon() { } else if(i == 0) { // nothing in the first window, configure for the second this->phyLayer->standby(); - RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); state = this->phyLayer->setFrequency(this->rx2.freq); RADIOLIB_ASSERT(state); @@ -1364,12 +1364,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // get the packet length size_t downlinkMsgLen = this->phyLayer->getPacketLength(); - RADIOLIB_DEBUG_PRINTLN("Downlink message length: %d", downlinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message length: %d", downlinkMsgLen); // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a port if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { - RADIOLIB_DEBUG_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -1414,14 +1414,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); } - RADIOLIB_DEBUG_PRINTLN("downlinkMsg:"); - RADIOLIB_DEBUG_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("downlinkMsg:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); // calculate length of FOpts and payload uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); - RADIOLIB_DEBUG_PRINTLN("FOpts: %02X", downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FOpts: %02X", downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS]); // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) @@ -1439,7 +1439,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) isAppDownlink = false; } } - RADIOLIB_DEBUG_PRINTLN("FOptsLen: %d", foptsLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FOptsLen: %d", foptsLen); // check the FcntDown value (Network or Application) uint32_t fcntDownPrev = 0; @@ -1449,7 +1449,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) fcntDownPrev = this->nFcntDown; } - RADIOLIB_DEBUG_PRINTLN("fcnt: %d, fcntPrev: %d, isAppDownlink: %d", fcnt16, fcntDownPrev, (int)isAppDownlink); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("fcnt: %d, fcntPrev: %d, isAppDownlink: %d", fcnt16, fcntDownPrev, (int)isAppDownlink); // if this is not the first downlink... // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP @@ -1496,7 +1496,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { - RADIOLIB_DEBUG_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1522,8 +1522,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); } - RADIOLIB_DEBUG_PRINTLN("fopts:"); - RADIOLIB_DEBUG_HEXDUMP(fopts, foptsLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("fopts:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fopts, foptsLen); bool hasADR = false; uint8_t numADR = 0; @@ -1538,7 +1538,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { // if there was an earlier ADR command but it was not the last, ignore it if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { - RADIOLIB_DEBUG_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); remLen -= (macLen + 1); foptsPtr += (macLen + 1); lastCID = cid; @@ -1557,7 +1557,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), }; memcpy(cmd.payload, foptsPtr + 1, macLen); - RADIOLIB_DEBUG_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", cmd.cid, cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); // process the MAC command @@ -1570,16 +1570,16 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) remLen -= (macLen + 1); foptsPtr += (macLen + 1); lastCID = cid; - RADIOLIB_DEBUG_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); } #if !RADIOLIB_STATIC_ONLY delete[] fopts; #endif - RADIOLIB_DEBUG_PRINTLN("MAC response:"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MAC response:"); for (int i = 0; i < this->commandsUp.numCommands; i++) { - RADIOLIB_DEBUG_HEXDUMP(&(this->commandsUp.commands[i].cid), sizeof(LoRaWANMacCommand_t)); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&(this->commandsUp.commands[i].cid), sizeof(LoRaWANMacCommand_t)); } // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink @@ -1598,8 +1598,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) memcpy(foptsPtr, &cmd, 1 + cmd.len); foptsPtr += cmd.len + 1; } - RADIOLIB_DEBUG_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_HEXDUMP(foptsBuff, foptsBufSize); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsBufSize); // pop the commands from back to front for (; i >= 0; i--) { @@ -1614,9 +1614,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // temporarily lift dutyCycle restrictions to allow immediate MAC response bool prevDC = this->dutyCycleEnabled; this->dutyCycleEnabled = false; - RADIOLIB_DEBUG_PRINTLN("Sending MAC-only uplink .. "); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - RADIOLIB_DEBUG_PRINTLN(" .. state: %d", state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); this->dutyCycleEnabled = prevDC; #if !RADIOLIB_STATIC_ONLY @@ -1629,9 +1629,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; #endif size_t lenDown = 0; - RADIOLIB_DEBUG_PRINTLN("Receiving after MAC-only uplink .. "); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Receiving after MAC-only uplink .. "); state = this->downlink(strDown, &lenDown); - RADIOLIB_DEBUG_PRINTLN(" .. state: %d", state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); #if !RADIOLIB_STATIC_ONLY delete[] strDown; #endif @@ -1767,7 +1767,7 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { // calculate the expected value and compare uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); if(micCalculated != micReceived) { - RADIOLIB_DEBUG_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); return(false); } @@ -1809,7 +1809,7 @@ int16_t LoRaWANNode::setPhyProperties() { } int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { - RADIOLIB_DEBUG_PRINTLN("Setting up dynamic channels"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); size_t num = 0; // copy the default defined channels into the first slots (where Tx = Rx) @@ -1833,7 +1833,7 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, @@ -1854,7 +1854,7 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { // setup a subband and its corresponding join-request datarate // WARNING: subBand starts at 1 (corresponds to all populair schemes) int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { - RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels (subband %d)", subBand); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); // randomly select one of 8 or 9 channels and find corresponding datarate uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 @@ -1918,7 +1918,7 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { } int16_t LoRaWANNode::processCFList(uint8_t* cfList) { - RADIOLIB_DEBUG_PRINTLN("Processing CFList"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // retrieve number of existing (default) channels @@ -1987,7 +1987,7 @@ int16_t LoRaWANNode::selectChannels() { } } if(numChannels == 0) { - RADIOLIB_DEBUG_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); return(RADIOLIB_ERR_INVALID_CHANNEL); } // select a random ID & channel from the list of enabled and possible channels @@ -2029,7 +2029,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { } } if(!isValidDR) { - RADIOLIB_DEBUG_PRINTLN("No defined channel allows datarate %d", drUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); return(RADIOLIB_ERR_INVALID_DATA_RATE); } @@ -2171,7 +2171,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; - RADIOLIB_DEBUG_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); } @@ -2180,8 +2180,8 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::configureChannel(uint8_t dir) { // set the frequency - RADIOLIB_DEBUG_PRINTLN(""); - RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); RADIOLIB_ASSERT(state); @@ -2265,7 +2265,7 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que } bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { - RADIOLIB_DEBUG_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); Module* mod = this->phyLayer->getMod(); #if defined(RADIOLIB_EEPROM_UNSUPPORTED) @@ -2282,7 +2282,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_RESET): { // get the server version uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Server version: 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); @@ -2309,7 +2309,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; uint8_t nbTrans = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); // apply the configuration uint8_t drAck = 0; @@ -2332,7 +2332,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; drAck = 1; } else { - RADIOLIB_DEBUG_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); } } @@ -2373,7 +2373,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask clearChannels = true; - RADIOLIB_DEBUG_PRINTLN("ADR mask: clearing channels"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); } else { // if this is not the first ADR command, clear the ADR response that was in the queue (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); @@ -2430,13 +2430,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { cmd->len = 1; cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); cmd->repeat = 0; // discard any repeat value that may have been set - RADIOLIB_DEBUG_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); return(true); } break; case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); if(maxDutyCycle == 0) { this->dutyCycle = this->band->dutyCycle; } else { @@ -2462,7 +2462,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t rx2Ack = 1; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); this->rx2.freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINTLN("Rx param REQ: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rx param REQ: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); // apply the configuration uint8_t chanAck = 0; @@ -2482,7 +2482,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // TODO this should be sent repeatedly until the next downlink cmd->len = 1; cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); - RADIOLIB_DEBUG_PRINTLN("Rx param ANS: status = 0x%02x", cmd->payload[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rx param ANS: status = 0x%02x", cmd->payload[0]); return(true); } break; @@ -2493,7 +2493,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { int8_t snr = this->phyLayer->getSNR(); cmd->payload[0] = snr & 0x3F; - RADIOLIB_DEBUG_PRINTLN("DevStatus ANS: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatus ANS: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); return(true); } break; @@ -2504,7 +2504,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { float freq = (float)freqRaw/10000.0; uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; uint8_t minDr = cmd->payload[4] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); uint8_t newChAck = 0; uint8_t freqAck = 0; @@ -2524,7 +2524,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, @@ -2542,8 +2542,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { if(saveToEeprom) { // save to uplink channels location, to the chIndex-th slot of 5 bytes uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - RADIOLIB_DEBUG_PRINTLN("Saving channel:"); - RADIOLIB_DEBUG_HEXDUMP(&(cmd->payload[0]), payLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving channel:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&(cmd->payload[0]), payLen); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); } @@ -2561,7 +2561,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); uint8_t freqDlAck = 0; uint8_t freqUlAck = 0; @@ -2601,7 +2601,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("RX timing: delay = %d sec", delay); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RX timing: delay = %d sec", delay); // apply the configuration if(delay == 0) { @@ -2632,7 +2632,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // who the f came up with this ... const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; this->txPowerMax = eirpEncoding[maxEirpRaw]; - RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax); this->dwellTimeEnabledUp = ulDwell ? true : false; this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; @@ -2654,7 +2654,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PRINTLN("Server version: 1.%d", srvVersion); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Server version: 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); @@ -2665,7 +2665,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; this->adrDelayExp = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) if(saveToEeprom) { @@ -2694,7 +2694,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; uint8_t dr = rejoinReq & 0x000F; - RADIOLIB_DEBUG_PRINTLN("Force rejoin: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Force rejoin: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); (void)period; (void)maxRetries; (void)rejoinType; @@ -2706,7 +2706,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // TODO implement this uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) if(saveToEeprom) { @@ -2751,7 +2751,7 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, @@ -2770,7 +2770,7 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { } bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear) { - RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); if(clear) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; @@ -2900,7 +2900,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, @@ -2974,7 +2974,7 @@ void LoRaWANNode::performCSMA() { bool channelFreeDuringDIFS = true; for (uint8_t i = 0; i < this->difsSlots; i++) { if (performCAD()) { - RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); channelFreeDuringDIFS = false; // Channel is occupied during DIFS, hop to another. this->selectChannels(); @@ -2986,7 +2986,7 @@ void LoRaWANNode::performCSMA() { // Continue decrementing BO with per each CAD reporting free channel. while (BO > 0) { if (performCAD()) { - RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("OCCUPIED CHANNEL DURING BO"); // Channel is busy during CAD, hop to another and return to DIFS state again. this->selectChannels(); break; // Exit loop. Go back to DIFS state. diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 8ec0c469fe..90cc2a68b5 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -85,7 +85,7 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { if((pauseLen >= low*(float)letterSpace) && (pauseLen <= high*(float)letterSpace)) { return(RADIOLIB_MORSE_CHAR_COMPLETE); } else if(pauseLen > wordSpace) { - RADIOLIB_DEBUG_PRINTLN("\n"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("\n"); return(RADIOLIB_MORSE_WORD_COMPLETE); } @@ -96,15 +96,15 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { uint32_t signalLen = mod->hal->millis() - signalStart; if((signalLen >= low*(float)dotLength) && (signalLen <= high*(float)dotLength)) { - RADIOLIB_DEBUG_PRINT("."); + RADIOLIB_DEBUG_PROTOCOL_PRINT("."); (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); (*len)++; } else if((signalLen >= low*(float)dashLength) && (signalLen <= high*(float)dashLength)) { - RADIOLIB_DEBUG_PRINT("-"); + RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); (*len)++; } else { - RADIOLIB_DEBUG_PRINTLN("", signalLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("", signalLen); } } @@ -122,7 +122,7 @@ size_t MorseClient::write(uint8_t b) { // inter-word pause (space) if(b == ' ') { - RADIOLIB_DEBUG_PRINTLN("space"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("space"); standby(); mod->waitForMicroseconds(mod->hal->micros(), wordSpace*1000); return(1); @@ -141,11 +141,11 @@ size_t MorseClient::write(uint8_t b) { // send dot or dash if (code & RADIOLIB_MORSE_DASH) { - RADIOLIB_DEBUG_PRINT("-"); + RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(mod->hal->micros(), dashLength*1000); } else { - RADIOLIB_DEBUG_PRINT("."); + RADIOLIB_DEBUG_PROTOCOL_PRINT("."); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); } @@ -161,7 +161,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000); - RADIOLIB_DEBUG_PRINTLN(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(); return(1); } diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 989338c866..1db47da619 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -554,7 +554,7 @@ uint32_t PagerClient::read() { codeWord = ~codeWord; } - RADIOLIB_VERBOSE_PRINTLN("R\t%lX", codeWord); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%lX", codeWord); // TODO BCH error correction here return(codeWord); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index f5ca56caf7..a1b51730e6 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -413,7 +413,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { this->syncBuffer <<= 1; this->syncBuffer |= bit; - RADIOLIB_VERBOSE_PRINTLN("S\t%lu", this->syncBuffer); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("S\t%lu", this->syncBuffer); if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) { this->gotSync = true; @@ -434,7 +434,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check complete byte if(this->bufferBitPos == 8) { this->buffer[this->bufferWritePos] = Module::reflect(this->buffer[this->bufferWritePos], 8); - RADIOLIB_VERBOSE_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); this->bufferWritePos++; this->bufferBitPos = 0; From 4993ac7c9dc56e8a604b1cb987ce8d3e98521c56 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Mar 2024 12:44:04 +0100 Subject: [PATCH 0935/1848] Added links to troubleshooting guide --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .github/ISSUE_TEMPLATE/module-not-working.md | 2 +- .github/ISSUE_TEMPLATE/regular-issue.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ae6f4ecd3b..c1f2273c11 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- **IMPORTANT: Check the wiki** -Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. **Describe the bug** A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode) **using the appropriate debug mode**. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 4d2c9a3c7e..ec5c496ef0 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ assignees: '' --- **IMPORTANT: Check the wiki** -Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] diff --git a/.github/ISSUE_TEMPLATE/module-not-working.md b/.github/ISSUE_TEMPLATE/module-not-working.md index 189d98f453..096d07a372 100644 --- a/.github/ISSUE_TEMPLATE/module-not-working.md +++ b/.github/ISSUE_TEMPLATE/module-not-working.md @@ -9,7 +9,7 @@ assignees: '' **IMPORTANT: Before submitting an issue, please check the following:** 1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. -2. RadioLib has a [Wiki](https://github.com/jgromes/RadioLib/wiki) and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. 3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). diff --git a/.github/ISSUE_TEMPLATE/regular-issue.md b/.github/ISSUE_TEMPLATE/regular-issue.md index 4e488b9a78..c55b36a1a2 100644 --- a/.github/ISSUE_TEMPLATE/regular-issue.md +++ b/.github/ISSUE_TEMPLATE/regular-issue.md @@ -9,7 +9,7 @@ assignees: '' **IMPORTANT: Before submitting an issue, please check the following:** 1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. -2. RadioLib has a [Wiki](https://github.com/jgromes/RadioLib/wiki) and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. 3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). From 24ffbfc2849a52731809baefc1dacbd123bd36a3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Mar 2024 20:40:41 +0100 Subject: [PATCH 0936/1848] Added ESP IRAM attribute to examples (#1010) --- examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino | 3 +++ examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index fcdff8a21f..99a962b272 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -42,6 +42,9 @@ volatile bool operationDone = false; // is transmitted or received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // we sent or received a packet, set the flag operationDone = true; diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index 9e006639e8..df025bc99d 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -39,6 +39,9 @@ volatile bool operationDone = false; // is transmitted or received by the module // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlag(void) { // we sent or received packet, set the flag operationDone = true; From b288485d6c43feddb1c56a66d75ae08e7e8defab Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 12 Mar 2024 21:52:17 +0100 Subject: [PATCH 0937/1848] [SX126x] Added option to select standby mode (#1008) --- src/modules/SX126x/SX126x.cpp | 3 ++- src/modules/SX126x/SX126x.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 716971c5a5..74178eb1fd 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -6,6 +6,7 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { this->mod = mod; this->XTAL = false; + this->standbyXOSC = false; } int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { @@ -463,7 +464,7 @@ int16_t SX126x::sleep(bool retainConfig) { } int16_t SX126x::standby() { - return(SX126x::standby(RADIOLIB_SX126X_STANDBY_RC)); + return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC)); } int16_t SX126x::standby(uint8_t mode, bool wakeup) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index f02d5f7d39..848433b8c8 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -447,6 +447,11 @@ class SX126x: public PhysicalLayer { */ bool XTAL; + /*! + \brief Whether to use XOSC (true) or RC (false) oscillator in standby mode. Defaults to false. + */ + bool standbyXOSC; + // basic methods /*! From 9fd7db4d13ada0f7681900ff8ab3512d93440fc5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 13 Mar 2024 07:00:20 +0100 Subject: [PATCH 0938/1848] [SX126x] Fix rx/tx fallback mode (#1008) --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 74178eb1fd..161a524536 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -2087,7 +2087,7 @@ int16_t SX126x::config(uint8_t modem) { RADIOLIB_ASSERT(state); // set Rx/Tx fallback mode to STDBY_RC - data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; + data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); RADIOLIB_ASSERT(state); From 0b11d101aa32eec914fac2fb4431e9d12bc799eb Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 15 Mar 2024 19:32:57 +0100 Subject: [PATCH 0939/1848] [CC1101] Clarify direct methods are synchronous (#1016) --- src/modules/CC1101/CC1101.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index e3354ae100..9d2254a4ce 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -599,14 +599,14 @@ class CC1101: public PhysicalLayer { int16_t standby(uint8_t mode) override; /*! - \brief Starts direct mode transmission. + \brief Starts synchronous direct mode transmission. \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. \returns \ref status_codes */ int16_t transmitDirect(uint32_t frf = 0) override; /*! - \brief Starts direct mode reception. + \brief Starts synchronous direct mode reception. \returns \ref status_codes */ int16_t receiveDirect() override; From 3d5f05b963ac99db141bfb343caa30e38864f902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 17 Mar 2024 18:10:54 +0100 Subject: [PATCH 0940/1848] Static check (#1019) * Update CodeQL action * [CI] Added workflow dispatch for codeql * [CI] Use v4 checkout action * [CI] Add cppcheck action (#1018) --- .github/workflows/codeql-analysis.yml | 18 ++++++------------ .github/workflows/cppcheck.yml | 27 +++++++++++++++++++++++++++ .github/workflows/doxygen.yml | 2 +- .github/workflows/main.yml | 10 +++++----- 4 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/cppcheck.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 78230b2569..c90f7c9d74 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -5,11 +5,14 @@ on: branches: [master] pull_request: branches: [master] + workflow_dispatch: jobs: analyze: name: Analyze runs-on: ubuntu-latest + permissions: + security-events: write strategy: fail-fast: false @@ -18,20 +21,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} @@ -63,4 +57,4 @@ jobs: arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:uno $PWD/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino --warnings=all - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml new file mode 100644 index 0000000000..684e11f9c1 --- /dev/null +++ b/.github/workflows/cppcheck.yml @@ -0,0 +1,27 @@ +name: "Cppcheck" + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + check: + name: Perform static code check + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install cppcheck + run: + | + sudo apt-get update + sudo apt-get install -y cppcheck + + - name: Run cppcheck + run: + cppcheck src --enable=all --force diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index ae64566798..5ebdd8608d 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -13,7 +13,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y doxygen - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Generate docs run: doxygen Doxyfile diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ce1032973c..6dfb1a823a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -158,7 +158,7 @@ jobs: - name: Checkout repository if: ${{ env.run-build == 'true' }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build examples if: ${{ env.run-build == 'true' }} @@ -186,7 +186,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install dependencies run: | @@ -214,7 +214,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive @@ -235,7 +235,7 @@ jobs: runs-on: [self-hosted, ARM64] steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install dependencies run: | @@ -270,7 +270,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install dependencies run: | From ca2a3073b94738554262ba58e53c359b8037df90 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 18 Mar 2024 08:51:38 +0100 Subject: [PATCH 0941/1848] [LoRaWAN] Change and upgrade persistence handling (#1017) * [LoRaWAN] Change and upgrade persistence handling * [BuildOpt] Patch to upstream * [LoRaWAN] Fix #1018 * [LoRaWAN] Remove outdated parts * [LoRaWAN] Resolve feedback Warning: untested - am not at my desk * [LoRaWAN] Small bugfixes --- keywords.txt | 4 + src/ArduinoHal.cpp | 47 -- src/ArduinoHal.h | 3 - src/BuildOpt.h | 24 +- src/Hal.cpp | 47 -- src/Hal.h | 132 ---- src/TypeDef.h | 5 + src/protocols/LoRaWAN/LoRaWAN.cpp | 994 ++++++++++--------------- src/protocols/LoRaWAN/LoRaWAN.h | 148 ++-- src/protocols/LoRaWAN/LoRaWANBands.cpp | 22 + 10 files changed, 542 insertions(+), 884 deletions(-) diff --git a/keywords.txt b/keywords.txt index 6ee6222c8c..2cfc5eae4a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -293,6 +293,10 @@ setModem KEYWORD2 # LoRaWAN wipe KEYWORD2 +getBufferNonces KEYWORD2 +setBufferNonces KEYWORD2 +getBufferSession KEYWORD2 +setBufferSession KEYWORD2 restore KEYWORD2 beginOTAA KEYWORD2 beginABP KEYWORD2 diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 59b5fb5e5b..9c5fd571aa 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -2,10 +2,6 @@ #if defined(RADIOLIB_BUILD_ARDUINO) -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) -#include -#endif - ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {} ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&spi), spiSettings(spiSettings) {} @@ -118,49 +114,6 @@ void inline ArduinoHal::spiEnd() { spi->end(); } -void ArduinoHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); - #elif defined(ARDUINO_ARCH_APOLLO3) - EEPROM.init(); - #endif - for(size_t i = 0; i < len; i++) { - buff[i] = EEPROM.read(addr + i); - } - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.end(); - #endif - #else - (void)addr; - (void)buff; - (void)len; - #endif -} - -void ArduinoHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.begin(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE); - #elif defined(ARDUINO_ARCH_APOLLO3) - EEPROM.init(); - #endif - for(size_t i = 0; i < len; i++) { - if(EEPROM.read(addr + i) != buff[i]) { // only write if value is new - EEPROM.write(addr + i, buff[i]); - } - } - #if defined(RADIOLIB_ESP32) || defined(ARDUINO_ARCH_RP2040) - EEPROM.commit(); - EEPROM.end(); - #endif - #else - (void)addr; - (void)buff; - (void)len; - #endif -} - void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if(pin == RADIOLIB_NC) { diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index bcda95aece..00074c1d31 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -51,9 +51,6 @@ class ArduinoHal : public RadioLibHal { void spiEndTransaction() override; void spiEnd() override; - void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) override; - void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) override; - // implementations of virtual RadioLibHal methods void init() override; void term() override; diff --git a/src/BuildOpt.h b/src/BuildOpt.h index a7adfbbc09..635acd9cec 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -104,21 +104,6 @@ #define RADIOLIB_STATIC_ARRAY_SIZE (256) #endif -// the base address for persistent storage -// some protocols (e.g. LoRaWAN) require a method -// to store some data persistently -// on Arduino, this will use EEPROM, on non-Arduino platform, -// it will use anything provided by the hardware abstraction layer -// RadioLib will place these starting at this address -#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_BASE (0) -#endif - -// the amount of space allocated to the persistent storage -#if !defined(RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE) - #define RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE (0x01C0) -#endif - /* * Uncomment on boards whose clock runs too slow or too fast * Set the value according to the following scheme: @@ -238,7 +223,6 @@ #elif defined(SAMD_SERIES) // Adafruit SAMD boards (M0 and M4) #define RADIOLIB_PLATFORM "Adafruit SAMD" - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ARDUINO_ARCH_SAMD) // Arduino SAMD (Zero, MKR, etc.) @@ -246,18 +230,15 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(__SAM3X8E__) // Arduino Due #define RADIOLIB_PLATFORM "Arduino Due" #define RADIOLIB_TONE_UNSUPPORTED - #define RADIOLIB_EEPROM_UNSUPPORTED #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) // Adafruit nRF52 boards #define RADIOLIB_PLATFORM "Adafruit nRF52" - #define RADIOLIB_EEPROM_UNSUPPORTED #elif defined(ARDUINO_ARC32_TOOLS) // Intel Curie @@ -280,7 +261,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -292,7 +272,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -314,7 +293,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) - #define RADIOLIB_EEPROM_UNSUPPORTED // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED @@ -585,4 +563,4 @@ #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) -#endif +#endif \ No newline at end of file diff --git a/src/Hal.cpp b/src/Hal.cpp index 1b4e818e25..1a42aa15a7 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -33,50 +33,3 @@ void RadioLibHal::yield() { uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); } - -void RadioLibHal::readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - // these are only needed for some protocols, so it's not needed to have them by default - (void)addr; - (void)buff; - (void)len; -} - -void RadioLibHal::writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len) { - // these are only needed for some protocols, so it's not needed to have them by default - (void)addr; - (void)buff; - (void)len; -} - -void RadioLibHal::wipePersistentStorage() { - uint8_t dummy = 0; - for(size_t i = 0; i < RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE; i++) { - this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + i, &dummy, sizeof(uint8_t)); - } -} - -uint32_t RadioLibHal::getPersistentAddr(uint32_t id) { - return(RadioLibPersistentParamTable[id]); -} - -template -void RadioLibHal::setPersistentParameter(uint32_t id, T val, uint32_t offset) { - uint8_t *ptr = (uint8_t*)&val; - this->writePersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id] + offset, ptr, sizeof(T)); -} - -template void RadioLibHal::setPersistentParameter(uint32_t id, uint8_t val, uint32_t offset); -template void RadioLibHal::setPersistentParameter(uint32_t id, uint16_t val, uint32_t offset); -template void RadioLibHal::setPersistentParameter(uint32_t id, uint32_t val, uint32_t offset); - -template -T RadioLibHal::getPersistentParameter(uint32_t id) { - T val = 0; - uint8_t *ptr = (uint8_t*)&val; - this->readPersistentStorage(RADIOLIB_HAL_PERSISTENT_STORAGE_BASE + RadioLibPersistentParamTable[id], ptr, sizeof(T)); - return(val); -} - -template uint8_t RadioLibHal::getPersistentParameter(uint32_t id); -template uint16_t RadioLibHal::getPersistentParameter(uint32_t id); -template uint32_t RadioLibHal::getPersistentParameter(uint32_t id); diff --git a/src/Hal.h b/src/Hal.h index 4a0c72c3e1..03bf174cee 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -6,88 +6,6 @@ #include "BuildOpt.h" -#define RADIOLIB_EEPROM_TABLE_VERSION (0x0002) - -// list of persistent parameters -enum RADIOLIB_EEPROM_PARAMS { - RADIOLIB_EEPROM_TABLE_VERSION_ID, // table layout version - RADIOLIB_EEPROM_LORAWAN_CLASS_ID, // class A, B or C - RADIOLIB_EEPROM_LORAWAN_MODE_ID, // none, OTAA or ABP - RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, // checksum of keys used for device activation - RADIOLIB_EEPROM_LORAWAN_VERSION_ID, // LoRaWAN version - RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID, // last heard time through DeviceTimeReq or Beacon - RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, - RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID, - RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, - RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, - RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, - RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, - RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, - RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, - RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, - RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, - RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID, - RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID, - RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, - RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID, - RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID, - RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID, - RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID, - RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID, - RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID, - RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID, - RADIOLIB_EEPROM_LORAWAN_BEACON_FREQ_ID, - RADIOLIB_EEPROM_LORAWAN_PING_SLOT_CHANNEL_ID, - RADIOLIB_EEPROM_LORAWAN_PERIODICITY_ID, - RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, - RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID, - RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID, - RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID -}; - -static const uint32_t RadioLibPersistentParamTable[] = { - 0x00, // RADIOLIB_EEPROM_TABLE_VERSION_ID - 0x02, // RADIOLIB_EEPROM_LORAWAN_CLASS_ID - 0x03, // RADIOLIB_EEPROM_LORAWAN_MODE_ID - 0x05, // RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID - 0x07, // RADIOLIB_EEPROM_LORAWAN_VERSION_ID - 0x08, // RADIOLIB_EEPROM_LORAWAN_LAST_TIME_ID - 0x0C, // RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID - 0x10, // RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID - 0x20, // RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID - 0x30, // RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID - 0x40, // RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID - 0x50, // RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID - 0x54, // RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID - 0x58, // RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID - 0x5C, // RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID - 0x60, // RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID - 0x64, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID - 0x68, // RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID - 0x6C, // RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID - 0x70, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT0_ID - 0x72, // RADIOLIB_EEPROM_LORAWAN_RJ_COUNT1_ID - 0x74, // RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID - 0xA0, // RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID - 0xA4, // RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID - 0xA5, // RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID - 0xA9, // RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID - 0xAA, // RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID - 0xAB, // RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID - 0xAC, // RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID - 0xAD, // RADIOLIB_EEPROM_LORAWAN_BEACON_FREQ_ID - 0xB0, // RADIOLIB_EEPROM_LORAWAN_PING_SLOT_CHANNEL_ID - 0xB4, // RADIOLIB_EEPROM_LORAWAN_PERIODICITY_ID - 0xB5, // RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID - 0xB6, // RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID - 0x0100, // RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID - 0x0180, // RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID - 0x01C0, // end -}; - /*! \class RadioLibHal \brief Hardware abstraction library base interface. @@ -289,56 +207,6 @@ class RadioLibHal { \returns The interrupt number of a given pin. */ virtual uint32_t pinToInterrupt(uint32_t pin); - - /*! - \brief Method to read from persistent storage (e.g. EEPROM). - \param addr Address to start reading at. - \param buff Buffer to read into. - \param len Number of bytes to read. - */ - virtual void readPersistentStorage(uint32_t addr, uint8_t* buff, size_t len); - - /*! - \brief Method to write to persistent storage (e.g. EEPROM). - \param addr Address to start writing to. - \param buff Buffer to write. - \param len Number of bytes to write. - */ - virtual void writePersistentStorage(uint32_t addr, uint8_t* buff, size_t len); - - /*! - \brief Method to wipe the persistent storage by writing to 0. - Will write at most RADIOLIB_HAL_PERSISTENT_STORAGE_SIZE bytes. - */ - void wipePersistentStorage(); - - /*! - \brief Method to convert from persistent parameter ID to its physical address. - \param id Parameter ID. - \returns Parameter physical address. - */ - uint32_t getPersistentAddr(uint32_t id); - - /*! - \brief Method to set arbitrary parameter to persistent storage. - This method DOES NOT perform any endianness conversion, so the value - will be stored in the system endian! - \param id Parameter ID to save at. - \param val Value to set. - \param offset An additional offset added to the address. - */ - template - void setPersistentParameter(uint32_t id, T val, uint32_t offset = 0); - - /*! - \brief Method to get arbitrary parameter from persistent storage. - This method DOES NOT perform any endianness conversion, so the value - will be retrieved in the system endian! - \param id Parameter ID to load from. - \returns The loaded value. - */ - template - T getPersistentParameter(uint32_t id); }; #endif diff --git a/src/TypeDef.h b/src/TypeDef.h index 42334988db..0135cac2ad 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -558,6 +558,11 @@ */ #define RADIOLIB_ERR_DWELL_TIME_EXCEEDED (-1115) +/*! + \brief The buffer integrity check did not match the supplied checksum value. +*/ +#define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1116) + /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index fef8ff8110..d4295cde06 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -6,10 +6,6 @@ #if !RADIOLIB_EXCLUDE_LORAWAN -#if defined(RADIOLIB_EEPROM_UNSUPPORTED) - #warning "Persistent storage not supported!" -#endif - // flag to indicate whether there was some action during Rx mode (timeout or downlink) static volatile bool downlinkAction = false; @@ -48,172 +44,210 @@ void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA this->enableCSMA = enableCSMA; } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) void LoRaWANNode::wipe() { - Module* mod = this->phyLayer->getMod(); - mod->hal->wipePersistentStorage(); + memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); +} + +uint8_t* LoRaWANNode::getBufferNonces() { + return(this->bufferNonces); +} + +int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { + if(this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_ASSERT(state); + + // copy the whole buffer over + memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + + // revert to inactive as long as no session is restored + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + + return(state); } -int16_t LoRaWANNode::restore() { +uint8_t* LoRaWANNode::getBufferSession() { + // update buffer contents + this->saveSession(); + + return(this->bufferSession); +} + +int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { + if(this->isJoined()) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); + return(RADIOLIB_ERR_NONE); + } + + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + RADIOLIB_ASSERT(state); + + // the Nonces buffer holds a checksum signature - compare this to the signature that is in the session buffer + uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE]); + if(signatureNonces != signatureInSession) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + + // copy the whole buffer over + memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + + // as both the Nonces and session are restored, revert to active session + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + + return(state); +} + +int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { + // check if there are actually values in the buffer + size_t i = 0; + for(; i < size; i++) { + if(buffer[i]) { + break; + } + } + if(i == size) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // check integrity of the whole buffer (compare checksum to included checksum) + uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); + uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); + if(signature != checkSum) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04X, expected: %04X", checkSum, signature); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) { // if already joined, ignore if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { - return(this->activeMode); + return(RADIOLIB_ERR_NONE); } - Module* mod = this->phyLayer->getMod(); + bool isSameKeys = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == checkSum; + bool isSameMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]) == lwMode; + bool isSameClass = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS]) == lwClass; + bool isSamePlan = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN]) == freqPlan; - uint8_t nvm_table_version = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID); - // if (RADIOLIB_EEPROM_LORAWAN_TABLE_VERSION > nvm_table_version) { - // // set default values for variables that are new or something - // } - (void)nvm_table_version; - - // check the mode value - uint16_t lwMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID); - if(lwMode == RADIOLIB_LORAWAN_MODE_NONE) { - #if RADIOLIB_DEBUG_PROTOCOL - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mode value not set (no saved session)"); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("first 16 bytes of NVM:"); - uint8_t nvmBuff[16]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(nvmBuff, 16); - #endif - // the mode value is not set, user will have to do perform the join procedure + // check if Nonces buffer matches the current configuration + if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { + // if configuration did not match, discard whatever is currently in the buffers and start fresh + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (checksum: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Nonces buffer:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Clearing buffer and starting fresh"); + this->wipe(); return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } - if(!this->isValidSession()) { + if(lwMode == RADIOLIB_LORAWAN_MODE_OTAA) { + // Nonces buffer is OK, so we can at least restore Nonces + this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); + this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); + } + + // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; + // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { + // // set default values for variables that are new or something + // } + + if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] == 0) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No active session in progress; please join the network"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } // pull all authentication keys from persistent storage - this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - - // get session parameters - this->rev = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID); + this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); + memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + + // restore session parameters + this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); - this->aFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID); - this->nFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID); - this->confFcntUp = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID); - this->confFcntDown = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID); - this->adrFcnt = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID); + this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); + this->aFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); + this->nFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); + this->confFcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); + this->confFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); + this->adrFcnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); + this->fcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); - // fcntUp is stored in highly efficient wear-leveling system, so parse it - this->restoreFcntUp(); + int16_t state = RADIOLIB_ERR_UNKNOWN; - // get the defined channels - int16_t state = this->restoreChannels(); - RADIOLIB_ASSERT(state); + // for dynamic bands, first restore the defined channels before restoring ADR + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // restore the defined channels + state = this->restoreChannels(); + RADIOLIB_ASSERT(state); + } - // get MAC state + // restore the complete MAC state LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, .repeat = 0, }; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); - // only apply the single ADR command on dynamic bands; fixed bands is done through channel restore - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cmd.len); + (void)execMacCommand(&cmd); + + // for fixed bands, first restore ADR, then the defined channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + state = this->restoreChannels(); + RADIOLIB_ASSERT(state); } cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); - - cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID), cmd.payload, cmd.len); - execMacCommand(&cmd, false); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd.len); + (void)execMacCommand(&cmd); - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - memcpy(&this->commandsUp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Number of MAC commands: %d", this->commandsUp.numCommands); + // copy uplink MAC command queue back in place + memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); state = this->setPhyProperties(); RADIOLIB_ASSERT(state); // full session is restored, so set joined flag to whichever mode is restored - this->activeMode = lwMode; - - return(this->activeMode); -} + this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]); -void LoRaWANNode::restoreFcntUp() { - Module* mod = this->phyLayer->getMod(); - - uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); - uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 1); - uint8_t buffSize = fcntBuffEnd - fcntBuffStart; - #if RADIOLIB_STATIC_ONLY - uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* fcntBuff = new uint8_t[buffSize]; - #endif - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); - - // copy the two most significant bytes from the first two bytes - uint32_t bits_30_22 = (uint32_t)fcntBuff[0]; - uint32_t bits_22_14 = (uint32_t)fcntBuff[1]; - - // the next 7 bits must be retrieved from the byte to which was written most recently - // this is the last byte that has its state bit (most significant bit) set equal to its predecessor - // we find the first byte that has its state bit different, and subtract one - uint8_t idx = 2; - uint8_t state = fcntBuff[idx] >> 7; - for(; idx < 5; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - uint32_t bits_14_7 = (uint32_t)fcntBuff[idx-1] & 0x7F; - - // equally, the last 7 bits must be retrieved from the byte to which was written most recently - // this is the last byte that has its state bit (most significant bit) set equal to its predecessor - // we find the first byte that has its state bit different, and subtract one - idx = 5; - state = fcntBuff[idx] >> 7; - for(; idx < buffSize; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - uint32_t bits_7_0 = (uint32_t)fcntBuff[idx-1] & 0x7F; - #if !RADIOLIB_STATIC_ONLY - delete[] fcntBuff; - #endif - - this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; + return(state); } int16_t LoRaWANNode::restoreChannels() { @@ -227,41 +261,32 @@ int16_t LoRaWANNode::restoreChannels() { Module* mod = this->phyLayer->getMod(); uint8_t bufferZeroes[5] = { 0 }; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - uint8_t numBytesUp = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - uint8_t bufferUp[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), bufferUp, numBytesUp); - + uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - memcpy(cmd.payload, &(bufferUp[i * cmd.len]), cmd.len); + memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes cmd.repeat = 1; - (void)execMacCommand(&cmd, false); + (void)execMacCommand(&cmd); } } - uint8_t numBytesDn = RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - uint8_t bufferDn[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID), bufferDn, numBytesDn); - + uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; + cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - memcpy(cmd.payload, &bufferDn[i * cmd.len], cmd.len); + memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes - (void)execMacCommand(&cmd, false); + (void)execMacCommand(&cmd); } } } else { // RADIOLIB_LORAWAN_BAND_FIXED - uint8_t numADRCommands = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Restoring %d stored channel masks", numADRCommands); - uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); - + uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, @@ -269,60 +294,21 @@ int16_t LoRaWANNode::restoreChannels() { .repeat = 0, }; - for(int i = 0; i < numADRCommands; i++) { + // there are at most 8 channel masks present + for(int i = 0; i < 8; i++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, &buffer[i * cmd.len], cmd.len); + memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); // there COULD, according to spec, be an all zeroes ADR command - meh - if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { - cmd.repeat = (i+1); - execMacCommand(&cmd, false); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { + break; } + cmd.repeat = (i+1); + (void)execMacCommand(&cmd); } } return(RADIOLIB_ERR_NONE); } -void LoRaWANNode::clearSession() { - Module* mod = this->phyLayer->getMod(); - uint8_t zeroes[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID), zeroes, sizeof(uint32_t)); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); - this->activeMode = RADIOLIB_LORAWAN_MODE_NONE; -} - -bool LoRaWANNode::isValidSession() { - uint8_t mask = 0; - Module* mod = this->phyLayer->getMod(); - uint8_t dummyBuf[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID), dummyBuf, sizeof(uint32_t)); - for(size_t i = 0; i < sizeof(uint32_t); i++) { - mask |= dummyBuf[i]; - } - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); - for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { - mask |= dummyBuf[i]; - } - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); - for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { - mask |= dummyBuf[i]; - } - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); - for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { - mask |= dummyBuf[i]; - } - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE); - for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { - mask |= dummyBuf[i]; - } - - return(mask > 0); -} - -#endif // RADIOLIB_EEPROM_UNSUPPORTED - void LoRaWANNode::beginCommon(uint8_t joinDr) { // in case a new session is started while there is an ongoing session // clear the MAC queues completely @@ -433,54 +419,36 @@ void LoRaWANNode::beginCommon(uint8_t joinDr) { (void)execMacCommand(&cmd); } -int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr, bool force) { +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force, uint8_t joinDr) { // if not forced and already joined, don't do anything if(!force && this->isJoined()) { - return(this->activeMode); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginOTAA(): Did not rejoin: session already active"); + return(RADIOLIB_ERR_NONE); } - - // check if we actually need to send the join request - Module* mod = this->phyLayer->getMod(); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // generate activation key checksum uint16_t checkSum = 0; checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); checkSum ^= LoRaWANNode::checkSum16(appKey, 16); - bool isValidCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool isValidMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; - - if(isValidCheckSum && isValidMode) { - // if not forced and a valid session is stored, restore it - if(!force && this->isValidSession()) { - return(this->restore()); - } - // either forced or no active session (a join was issued previously but didn't result in an active session) - this->clearSession(); - // the credentials are still the same, so restore the DevNonce and JoinNonce - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); - } else { - // either invalid key checksum or mode, so wipe either way - #if RADIOLIB_DEBUG_PROTOCOL - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("First 16 bytes of NVM:"); - uint8_t nvmBuff[16]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(nvmBuff, 16); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Wiping EEPROM and starting a clean session"); - #endif - - this->wipe(); + // if The Force is used, disable the active session; + // as a result, restore() will only restore Nonces if they are available, not the session + if(force) { + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; } -#else - (void)force; -#endif - int16_t state = RADIOLIB_ERR_NONE; + state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_OTAA, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + + if(!force) { + return(state); + } + Module* mod = this->phyLayer->getMod(); + // setup join-request uplink/downlink frequencies and datarates if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { state = this->setupChannelsDyn(true); @@ -509,9 +477,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // increment devNonce as we are sending another join-request this->devNonce += 1; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); -#endif + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; @@ -710,28 +676,32 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFcnt = 0; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); -#endif - + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_OTAA); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); + + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { // if not forced and already joined, don't do anything if(!force && this->isJoined()) { - return(this->activeMode); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active"); + return(RADIOLIB_ERR_NONE); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // only needed for persistent storage - Module* mod = this->phyLayer->getMod(); + int16_t state = RADIOLIB_ERR_UNKNOWN; // check if we actually need to restart from a clean session uint16_t checkSum = 0; @@ -741,32 +711,17 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } - bool isValidCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool isValidMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; - - if(isValidCheckSum && isValidMode) { - // if not forced and a valid session is stored, restore it - if(!force && this->isValidSession()) { - return(this->restore()); - } - // either forced or no active session (a join was issued previously but didn't result in an active session) - this->clearSession(); - } else { - // either invalid key checksum or mode, so wipe either way - #if RADIOLIB_DEBUG_PROTOCOL - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("First 16 bytes of NVM:"); - uint8_t nvmBuff[16]; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(nvmBuff, 16); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Wiping EEPROM and starting a clean session"); - #endif + // if The Force is used, disable the active session; + // as a result, restore() will not restore the session (and there are no Nonces in ABP mode) + if(force) { + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + } - this->wipe(); + state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_ABP, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + + if(!force) { + return(state); } -#else - (void)force; -#endif this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); @@ -781,8 +736,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } - int16_t state = RADIOLIB_ERR_NONE; - // setup the uplink/downlink channels and initial datarate if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(); @@ -805,15 +758,20 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFcnt = 0; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - // save the activation keys checksum, device address & keys - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP); -#endif + // save the activation keys checksum, mode, class, frequency plan + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_ABP); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; this->activeMode = RADIOLIB_LORAWAN_MODE_ABP; + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + return(RADIOLIB_ERR_NONE); } @@ -821,110 +779,42 @@ bool LoRaWANNode::isJoined() { return(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) int16_t LoRaWANNode::saveSession() { Module* mod = this->phyLayer->getMod(); // store DevAddr and all keys - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + + // copy the signature of the Nonces buffer over to the Session buffer + uint16_t noncesSignature = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], noncesSignature); // store network parameters - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); // store all frame counters - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN], this->aFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN], this->nFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP], this->confFcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFcnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fcntUp); - // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often - this->saveFcntUp(); + // save the current uplink MAC command queue + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - // if there is, or was, any MAC command in the queue, overwrite with the current MAC queue - uint8_t queueBuff[sizeof(LoRaWANMacCommandQueue_t)] = { 0 }; - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - LoRaWANMacCommandQueue_t cmdTemp; - memcpy(&cmdTemp, queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - if(this->commandsUp.numCommands > 0 || cmdTemp.numCommands > 0) { - memcpy(queueBuff, &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_MAC_QUEUE_UL_ID), queueBuff, sizeof(LoRaWANMacCommandQueue_t)); - } + // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); return(RADIOLIB_ERR_NONE); } -void LoRaWANNode::saveFcntUp() { - Module* mod = this->phyLayer->getMod(); - - uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); - uint8_t fcntBuffEnd = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID + 1); - uint8_t buffSize = fcntBuffEnd - fcntBuffStart; - #if RADIOLIB_STATIC_ONLY - uint8_t fcntBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* fcntBuff = new uint8_t[buffSize]; - #endif - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID), fcntBuff, buffSize); - - // we discard the first two bits - your flash will likely be far dead by the time you reach 2^30 uplinks - // the first two bytes of the remaining 30 bytes are stored straight into storage without additional wear leveling - // because they hardly ever change - uint8_t bits_30_22 = (uint8_t)(this->fcntUp >> 22); - if(fcntBuff[0] != bits_30_22) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_30_22, 0); - uint8_t bits_22_14 = (uint8_t)(this->fcntUp >> 14); - if(fcntBuff[1] != bits_22_14) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_22_14, 1); - - // the next 7 bits are stored into one of few indices - // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor - // if all have an equal state, restart from the beginning - // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte - uint8_t idx = 2; - uint8_t state = fcntBuff[idx] >> 7; - for(; idx < 5; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - // check if the last written byte is equal to current, only rewrite if different - uint8_t bits_14_7 = (this->fcntUp >> 7) & 0x7F; - if((fcntBuff[idx - 1] & 0x7F) != bits_14_7) { - // find next index to write - idx = idx < 5 ? idx : 2; - - // flip the first bit of this byte to indicate that we just wrote here - bits_14_7 |= (~(fcntBuff[idx] >> 7)) << 7; - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_14_7, idx); - } - - // equally, the last 7 bits are stored into one of many indices - // this index is indicated by the first byte that has its state (most significant bit) different from its predecessor - // if all have an equal state, restart from the beginning - // always flip the state bit of the byte that we write to, to indicate that this is the most recently written byte - idx = 5; - state = fcntBuff[idx] >> 7; - for(; idx < buffSize; idx++) { - if(fcntBuff[idx] >> 7 != state) { - break; - } - } - idx = idx < buffSize ? idx : 5; - uint8_t bits_7_0 = (this->fcntUp >> 0) & 0x7F; - - // flip the first bit of this byte to indicate that we just wrote here - bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7; - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); - -} -#endif // RADIOLIB_EEPROM_UNSUPPORTED - #if defined(RADIOLIB_BUILD_ARDUINO) int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { return(this->uplink(str.c_str(), port, isConfirmed, event)); @@ -968,7 +858,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf this->isMACPayload = false; } - int16_t state = RADIOLIB_ERR_NONE; + int16_t state = RADIOLIB_ERR_UNKNOWN; // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; @@ -1004,7 +894,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // if the TxPower field has some offset, remove it and switch to maximum power if(this->txPowerCur > 0) { // set the maximum power supported by both the module and the band - state = this->setTxPower(this->txPowerMax, true); + state = this->setTxPower(this->txPowerMax); if(state == RADIOLIB_ERR_NONE) { this->txPowerCur = 0; adrStage = 0; // successfully did some ADR stuff @@ -1018,7 +908,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf case(2): { // try to decrease the datarate if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { - if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1, true) == RADIOLIB_ERR_NONE) { + if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { adrStage = 0; // successfully did some ADR stuff } } @@ -1154,9 +1044,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FcntUp: %d", this->fcntUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fcntUp); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("uplinkMsg pre-MIC:"); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); // calculate authentication codes @@ -1322,7 +1211,7 @@ int16_t LoRaWANNode::downlinkCommon() { #if defined(RADIOLIB_BUILD_ARDUINO) int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { - int16_t state = RADIOLIB_ERR_NONE; + int16_t state = RADIOLIB_ERR_UNKNOWN; // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL @@ -1344,7 +1233,7 @@ int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { #endif int16_t LoRaWANNode::downlink(LoRaWANEvent_t* event) { - int16_t state = RADIOLIB_ERR_NONE; + int16_t state = RADIOLIB_ERR_UNKNOWN; // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL @@ -1364,7 +1253,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // get the packet length size_t downlinkMsgLen = this->phyLayer->getPacketLength(); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message length: %d", downlinkMsgLen); // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a port @@ -1414,15 +1302,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("downlinkMsg:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); - // calculate length of FOpts and payload uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FOpts: %02X", downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS]); - // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) // TODO "NFCntDown is used for MAC communication on port 0 and when the FPort field is missing" @@ -1439,7 +1322,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) isAppDownlink = false; } } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FOptsLen: %d", foptsLen); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFcntDown = %d) encoded:", isAppDownlink ? "A" : "N", fcnt16); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); // check the FcntDown value (Network or Application) uint32_t fcntDownPrev = 0; @@ -1449,8 +1334,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) fcntDownPrev = this->nFcntDown; } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("fcnt: %d, fcntPrev: %d, isAppDownlink: %d", fcnt16, fcntDownPrev, (int)isAppDownlink); - // if this is not the first downlink... // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error @@ -1522,9 +1405,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("fopts:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fopts, foptsLen); - bool hasADR = false; uint8_t numADR = 0; uint8_t lastCID = 0; @@ -1557,8 +1437,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), }; memcpy(cmd.payload, foptsPtr + 1, macLen); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[%02X]: %02X %02X %02X %02X %02X (%d)", - cmd.cid, cmd.payload[0], cmd.payload[1], cmd.payload[2], cmd.payload[3], cmd.payload[4], cmd.len); // process the MAC command bool sendUp = execMacCommand(&cmd); @@ -1570,18 +1448,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) remLen -= (macLen + 1); foptsPtr += (macLen + 1); lastCID = cid; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processed: %d, remaining: %d", (macLen + 1), remLen); } #if !RADIOLIB_STATIC_ONLY delete[] fopts; #endif - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MAC response:"); - for (int i = 0; i < this->commandsUp.numCommands; i++) { - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&(this->commandsUp.commands[i].cid), sizeof(LoRaWANMacCommand_t)); - } - // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > 15) { size_t foptsBufSize = this->commandsUp.len; @@ -1833,19 +1705,21 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } } return(RADIOLIB_ERR_NONE); @@ -1855,6 +1729,12 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { // WARNING: subBand starts at 1 (corresponds to all populair schemes) int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); + + // clear all existing channels + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + // randomly select one of 8 or 9 channels and find corresponding datarate uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 @@ -1870,49 +1750,27 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { uint8_t numBanks8 = this->band->txSpans[0].numChannels / 8; subBand = this->devNonce % numBanks8; } - - // chMask is set for 16 channels at once, so widen the Cntl value - uint8_t chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset - - uint8_t numADR = 1; - - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, - .repeat = 0, - }; + uint8_t chMaskCntl = 0; + uint16_t chMask = 0; + // if there are two channel spans, first set the channel from second span if(this->band->numTxSpans == 2) { - cmd.payload[0] = (drJR << 4); // set join-request datarate - cmd.payload[0] |= 0; // set Tx power to maximum - // enable channel that belongs to this subband - cmd.payload[1] = (1 << (subBand - 1)); // set channel mask - cmd.payload[2] = 0; - cmd.payload[3] = (7 << 4); // set the chMaskCntl value to all channels off - cmd.payload[3] |= 0; // keep NbTrans the same - cmd.repeat = numADR++; - (void)execMacCommand(&cmd, false); + chMaskCntl = 7; + chMask = (1 << (subBand - 1)); // set channel mask + this->applyChannelMaskFix(chMaskCntl, chMask); } - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = (drJR << 4); // set join-request datarate - cmd.payload[0] |= 0; // set Tx power to maximum + // chMask is set for 16 channels at once, so widen the Cntl value + chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset + // now select the correct bank of 8 channels - // 0x00 0xFF channel mask for subband = 2, 4.. (even) - // 0xFF 0x00 channel mask for subband = 1, 3.. (odd) - if(subBand % 2 == 0) { - cmd.payload[1] = 0x00; - cmd.payload[2] = 0xFF; + if(subBand % 2 == 0) { // even subbands + chMask = 0xFF00; } else { - cmd.payload[1] = 0xFF; - cmd.payload[2] = 0x00; + chMask = 0x00FF; // odd subbands } - cmd.payload[3] = (chMaskCntl << 4); // set the chMaskCntl value - cmd.payload[3] |= 0; // keep NbTrans the same - cmd.repeat = numADR++; - (void)execMacCommand(&cmd, false); + this->applyChannelMaskFix(chMaskCntl, chMask); return(RADIOLIB_ERR_NONE); } @@ -2016,7 +1874,7 @@ int16_t LoRaWANNode::selectChannels() { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { +int16_t LoRaWANNode::setDatarate(uint8_t drUp) { // scan through all enabled channels and check if the requested datarate is available bool isValidDR = false; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { @@ -2043,7 +1901,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp, bool saveToEeprom) { cmd.payload[0] |= 0x0F; // keep Tx Power the same cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same - (void)execMacCommand(&cmd, saveToEeprom); + (void)execMacCommand(&cmd); // check if ACK is set for Tx Power if((cmd.payload[0] >> 1) != 1) { @@ -2116,7 +1974,7 @@ uint8_t LoRaWANNode::maxPayloadDwellTime() { return(payLen - 13); // fixed 13-byte header } -int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { +int16_t LoRaWANNode::setTxPower(int8_t txPower) { // only allow values within the band's (or MAC state) maximum if(txPower > this->txPowerMax) { return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); @@ -2136,7 +1994,7 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower, bool saveToEeprom) { cmd.payload[0] |= numSteps; // set the Tx Power cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored cmd.payload[3] |= 0; // keep NbTrans the same - (void)execMacCommand(&cmd, saveToEeprom); + (void)execMacCommand(&cmd); // check if ACK is set for Tx Power if((cmd.payload[0] >> 2) != 1) { @@ -2264,14 +2122,12 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); } -bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("exe MAC CID = %02x, len = %d", cmd->cid, cmd->len); - - Module* mod = this->phyLayer->getMod(); -#if defined(RADIOLIB_EEPROM_UNSUPPORTED) - (void)saveToEeprom; - (void)mod; -#endif +bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { + RADIOLIB_DEBUG_PROTOCOL_PRINT("[MAC] 0x%02X %s", cmd->cid, cmd->len ? "= 0x" : ""); + for(uint8_t i = 0; i < cmd->len; i++) { + RADIOLIB_DEBUG_PROTOCOL_PRINT("%02X", cmd->payload[i]); + } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(); if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { // TODO call user-provided callback for proprietary MAC commands? @@ -2282,7 +2138,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_RESET): { // get the server version uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Server version: 1.%d", srvVersion); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); @@ -2291,6 +2147,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } break; case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); // delete any existing response (does nothing if there is none) deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); @@ -2306,10 +2163,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // but we don't bother and try to set each individual command uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; uint8_t txPower = cmd->payload[0] & 0x0F; + bool isInternalTxDr = cmd->payload[3] >> 7; + uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; uint8_t nbTrans = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR REQ: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %02x, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); // apply the configuration uint8_t drAck = 0; @@ -2347,6 +2206,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } else { int8_t pwr = this->txPowerMax - 2*txPower; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr); state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { // go from the highest power and lower it until we hit one supported by the module @@ -2362,8 +2222,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t chMaskAck = 1; // only apply channel mask when the RFU bit is not set - // (which is set on the internal MAC command when creating new session) - if((cmd->payload[3] >> 7) == 0) { + // (which is only set in internal MAC commands for changing Tx/Dr) + if(!isInternalTxDr) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); @@ -2372,13 +2232,17 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { if(cmd->repeat == 1) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask - clearChannels = true; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + } + // clear all previous channel masks + memset(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS], 0, 16*8); } else { // if this is not the first ADR command, clear the ADR response that was in the queue (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } - chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask, clearChannels); + chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask); } } @@ -2389,66 +2253,58 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->nbTrans = nbTrans; } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte - if((cmd->payload[3] >> 7) == 1) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID) + 1, &(cmd->payload[1]), 3); + if(isInternalTxDr) { + memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, 3); } + // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again if(cmd->payload[1] == 0 && cmd->payload[2] == 0) { cmd->payload[3] |= (1 << 7); } // save to the single ADR MAC location - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); } else { // RADIOLIB_LORAWAN_BAND_FIXED - // if RFU bit is set, this is just a change in Datarate or TxPower - // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it - if((cmd->payload[3] >> 7) == 1) { - // read how many ADR masks are already stored - uint8_t numMacADR = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); - if(numMacADR > 0) { - mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen + 1, &(cmd->payload[1]), 3); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (numMacADR - 1) * payLen, &(cmd->payload[0]), payLen); - } + + // save Tx/Dr to the Link ADR position in the session buffer + uint8_t bufTxDr[cmd->len] = { 0 }; + bufTxDr[0] = cmd->payload[0]; + bufTxDr[3] = 1 << 7; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); - } else { - // save to the uplink channel location, to the cmd->repeat-th slot of 4 bytes - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + (cmd->repeat - 1) * payLen, &(cmd->payload[0]), payLen); - // saved an ADR mask, so re-store counter - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat); + // if RFU bit is set, this is just a change in Datarate or TxPower, in which case we don't save the channel masks + // if the RFU bit is not set, we must save this channel mask + if(!isInternalTxDr) { + // save the channel mask to the uplink channels position in session buffer, with Tx and DR set to 'same' + cmd->payload[0] = 0xFF; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving mask to ULChannels[%d]:", (cmd->repeat - 1) * cmd->len); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); } + } - } -#endif // send the reply cmd->len = 1; cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); cmd->repeat = 0; // discard any repeat value that may have been set - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR ANS: status = 0x%02x", cmd->payload[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRAns: status = 0x%02x", cmd->payload[0]); return(true); } break; case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Max duty cycle: 1/2^%d", maxDutyCycle); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); if(maxDutyCycle == 0) { this->dutyCycle = this->band->dutyCycle; } else { this->dutyCycle = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000 / (uint32_t)(1UL << maxDutyCycle); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DUTY_CYCLE_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); cmd->len = 0; return(true); @@ -2462,7 +2318,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t rx2Ack = 1; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); this->rx2.freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rx param REQ: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupReq: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); // apply the configuration uint8_t chanAck = 0; @@ -2471,29 +2327,24 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_RX_PARAM_SETUP_ID), &(cmd->payload[0]), payLen); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); // TODO this should be sent repeatedly until the next downlink cmd->len = 1; cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rx param ANS: status = 0x%02x", cmd->payload[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupAns: status = 0x%02x", cmd->payload[0]); return(true); } break; case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { // set the uplink reply + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); cmd->len = 2; cmd->payload[1] = this->battLevel; int8_t snr = this->phyLayer->getSNR(); cmd->payload[0] = snr & 0x3F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatus ANS: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusAns: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); return(true); } break; @@ -2504,7 +2355,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { float freq = (float)freqRaw/10000.0; uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; uint8_t minDr = cmd->payload[4] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("New channel: index = %d, freq = %f MHz, maxDr = %d, minDr = %d", chIndex, freq, maxDr, minDr); + uint8_t newChAck = 0; uint8_t freqAck = 0; @@ -2524,7 +2375,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq:"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, @@ -2538,20 +2390,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax ); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - // save to uplink channels location, to the chIndex-th slot of 5 bytes - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving channel:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&(cmd->payload[0]), payLen); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // send the reply cmd->len = 1; cmd->payload[0] = (newChAck << 1) | (freqAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelAns: status = 0x%02x", cmd->payload[0]); return(true); } break; @@ -2561,7 +2405,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DL channel: index = %d, freq = %f MHz", chIndex, freq); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %f MHz", chIndex, freq); uint8_t freqDlAck = 0; uint8_t freqUlAck = 0; @@ -2582,18 +2426,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { } } -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - // save to downlink channels location, to the chIndex-th slot of 4 bytes - uint8_t payLen = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DL_CHANNELS_ID) + chIndex * payLen, &(cmd->payload[0]), payLen); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // TODO send this repeatedly until a downlink is received cmd->len = 1; cmd->payload[0] = (freqUlAck << 1) | (freqDlAck << 0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelAns: status = 0x%02x", cmd->payload[0]); return(true); } break; @@ -2601,7 +2439,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RX timing: delay = %d sec", delay); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); // apply the configuration if(delay == 0) { @@ -2610,12 +2448,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->rxDelays[0] = delay * 1000; this->rxDelays[1] = this->rxDelays[0] + 1000; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_RX_TIMING_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); // send the reply cmd->len = 0; @@ -2632,7 +2465,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // who the f came up with this ... const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; this->txPowerMax = eirpEncoding[maxEirpRaw]; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); this->dwellTimeEnabledUp = ulDwell ? true : false; this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; @@ -2640,12 +2473,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->dwellTimeEnabledDn = dlDwell ? true : false; this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_TX_PARAM_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); @@ -2654,7 +2482,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Server version: 1.%d", srvVersion); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); @@ -2665,20 +2493,16 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; this->adrDelayExp = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR param setup: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_PARAM_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); // delete any existing response (does nothing if there is none) deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); @@ -2689,12 +2513,12 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { // TODO implement this - uint16_t rejoinReq = LoRaWANNode::ntoh(&cmd->payload[0]); + uint16_t rejoinReq = LoRaWANNode::ntoh(cmd->payload); uint8_t period = (rejoinReq & 0x3800) >> 11; uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; uint8_t dr = rejoinReq & 0x000F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Force rejoin: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ForceRejoinReq: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); (void)period; (void)maxRetries; (void)rejoinType; @@ -2706,17 +2530,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // TODO implement this uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rejoin setup: maxTime = %d, maxCount = %d", maxTime, maxCount); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - if(saveToEeprom) { - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_REJOIN_PARAM_SETUP_ID, cmd->payload[0]); - - } -#endif + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; cmd->payload[0] = (1 << 1) | 1; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupAns: status = 0x%02x", cmd->payload[0]); (void)maxTime; (void)maxCount; @@ -2751,31 +2571,29 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } } return(true); } -bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear) { +bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); - if(clear) { - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - } + // find out how many channels have already been configured uint8_t idx = 0; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { @@ -2831,7 +2649,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool uint16_t mask = 1 << i; if(mask & chMask) { // enable bank of 8 channels from first span - for(uint8_t j = 0; j < 8; i++) { + for(uint8_t j = 0; j < 8; j++) { uint8_t chNum = i * 8 + j; chnl.enabled = true; chnl.idx = chNum; @@ -2900,19 +2718,21 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } } return(true); @@ -2974,7 +2794,7 @@ void LoRaWANNode::performCSMA() { bool channelFreeDuringDIFS = true; for (uint8_t i = 0; i < this->difsSlots; i++) { if (performCAD()) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("OCCUPIED CHANNEL DURING DIFS"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during DIFS"); channelFreeDuringDIFS = false; // Channel is occupied during DIFS, hop to another. this->selectChannels(); @@ -2986,7 +2806,7 @@ void LoRaWANNode::performCSMA() { // Continue decrementing BO with per each CAD reporting free channel. while (BO > 0) { if (performCAD()) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("OCCUPIED CHANNEL DURING BO"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during BO"); // Channel is busy during CAD, hop to another and return to DIFS state again. this->selectChannels(); break; // Exit loop. Go back to DIFS state. @@ -3045,16 +2865,14 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out } } -uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint8_t keyLen) { - if(keyLen > RADIOLIB_AES128_KEY_SIZE / 2) { - keyLen = RADIOLIB_AES128_KEY_SIZE / 2; - } - uint16_t buf16[RADIOLIB_AES128_KEY_SIZE / 2] = { 0 }; - uint8_t bufLen = keyLen / 2; - memcpy(buf16, key, keyLen); +uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint16_t keyLen) { uint16_t checkSum = 0; - for(int i = 0; i < bufLen; i++) { - checkSum ^= buf16[i]; + for(uint16_t i = 0; i < keyLen; i += 2) { + checkSum ^= ((uint16_t)key[i] << 8) | key[i + 1]; + } + if(keyLen % 2 == 1) { + uint16_t val = ((uint16_t)key[keyLen - 1] << 8); + checkSum ^= val; } return(checkSum); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 44941a4de8..9c90202b8e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -6,14 +6,14 @@ #include "../../utils/Cryptography.h" // activation mode -#define RADIOLIB_LORAWAN_MODE_OTAA (0x01AA) +#define RADIOLIB_LORAWAN_MODE_OTAA (0x07AA) #define RADIOLIB_LORAWAN_MODE_ABP (0x0AB9) #define RADIOLIB_LORAWAN_MODE_NONE (0x0000) // operation mode -#define RADIOLIB_LORAWAN_CLASS_A (0x00) -#define RADIOLIB_LORAWAN_CLASS_B (0x01) -#define RADIOLIB_LORAWAN_CLASS_C (0x02) +#define RADIOLIB_LORAWAN_CLASS_A (0x0A) +#define RADIOLIB_LORAWAN_CLASS_B (0x0B) +#define RADIOLIB_LORAWAN_CLASS_C (0x0C) // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) @@ -226,6 +226,56 @@ const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } }; +#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) + +enum LoRaWANSchemeBase_t { + RADIOLIB_LORAWAN_NONCES_VERSION = 0x00, // 2 bytes + RADIOLIB_LORAWAN_NONCES_MODE = 0x02, // 2 bytes + RADIOLIB_LORAWAN_NONCES_CLASS = 0x04, // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = 0x05, // 1 byte + RADIOLIB_LORAWAN_NONCES_CHECKSUM = 0x06, // 2 bytes + RADIOLIB_LORAWAN_NONCES_DEV_NONCE = 0x08, // 2 bytes + RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = 0x0A, // 3 bytes + RADIOLIB_LORAWAN_NONCES_ACTIVE = 0x0D, // 1 byte + RADIOLIB_LORAWAN_NONCES_SIGNATURE = 0x0E, // 2 bytes + RADIOLIB_LORAWAN_NONCES_BUF_SIZE = 0x10 // = 16 bytes +}; + +enum LoRaWANSchemeSession_t { + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = 0x00, // 16 bytes + RADIOLIB_LORAWAN_SESSION_APP_SKEY = 0x10, // 16 bytes + RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = 0x20, // 16 bytes + RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = 0x30, // 16 bytes + RADIOLIB_LORAWAN_SESSION_DEV_ADDR = 0x40, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = 0x44, // 2 bytes + RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = 0x46, // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = 0x4A, // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = 0x4E, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = 0x52, // 2 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = 0x54, // 2 bytes + RADIOLIB_LORAWAN_SESSION_HOMENET_ID = 0x56, // 4 bytes + RADIOLIB_LORAWAN_SESSION_VERSION = 0x5A, // 1 byte + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = 0x5B, // 1 byte + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = 0x5C, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = 0x60, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = 0x61, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = 0x62, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = 0x63, // 1 byte + RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = 0x64, // 3 bytes + RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = 0x67, // 4 bytes + RADIOLIB_LORAWAN_SESSION_PERIODICITY = 0x6B, // 1 byte + RADIOLIB_LORAWAN_SESSION_LAST_TIME = 0x6C, // 4 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = 0x70, // 16*8 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = 0xF0, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = 0x0130, // 9*8+2 bytes + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = 0x017A, // 4 bytes + RADIOLIB_LORAWAN_SESSION_ADR_FCNT = 0x017E, // 4 bytes + RADIOLIB_LORAWAN_SESSION_LINK_ADR = 0x0182, // 4 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = 0x0186, // 4 bytes + RADIOLIB_LORAWAN_SESSION_SIGNATURE = 0x018A, // 2 bytes + RADIOLIB_LORAWAN_SESSION_BUF_SIZE = 0x018C // 396 bytes +}; + /*! \struct LoRaWANChannelSpan_t \brief Structure to save information about LoRaWAN channels. @@ -284,6 +334,9 @@ struct LoRaWANChannelSpan_t { \brief Structure to save information about LoRaWAN band */ struct LoRaWANBand_t { + /*! \brief Identier for this band */ + uint8_t bandNum; + /*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */ uint8_t bandType; @@ -415,20 +468,43 @@ class LoRaWANNode { */ LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) /*! \brief Wipe internal persistent parameters. This will reset all counters and saved variables, so the device will have to rejoin the network. */ void wipe(); + /*! + \brief Returns the pointer to the internal buffer that holds the LW base parameters + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_NONCES_BUF_SIZE + */ + uint8_t* getBufferNonces(); + + /*! + \brief Fill the internal buffer that holds the LW base parameters with a supplied buffer + \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferNonces) + \returns \ref status_codes + */ + int16_t setBufferNonces(uint8_t* persistentBuffer); + + /*! + \brief Returns the pointer to the internal buffer that holds the LW session parameters + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_SESSION_BUF_SIZE + */ + uint8_t* getBufferSession(); + + /*! + \brief Fill the internal buffer that holds the LW session parameters with a supplied buffer + \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferSession) + \returns \ref status_codes + */ + int16_t setBufferSession(uint8_t* persistentBuffer); + /*! \brief Restore session by loading information from persistent storage. - \returns \ref status_codes in case of error, - else LoRaWAN session mode (0 = no active session, 0xAA / 170 = OTAA, 0xAB / 171 = ABP) + \returns \ref status_codes */ - int16_t restore(); -#endif + int16_t restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan); /*! \brief Join network by performing over-the-air activation. By this procedure, @@ -437,12 +513,11 @@ class LoRaWANNode { \param devEUI 8-byte device identifier. \param nwkKey Pointer to the network AES-128 key. \param appKey Pointer to the application AES-128 key. - \param joinDr (OTAA:) The datarate at which to send the join-request; (ABP:) ignored \param force Set to true to force joining even if previously joined. - + \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, bool force = false); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \brief Join network by performing activation by personalization. @@ -450,8 +525,8 @@ class LoRaWANNode { \param addr Device address. \param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1). \param appSKey Pointer to the application session AES-128 key. - \param fNwkSIntKey Pointer to the network session F key (LoRaWAN 1.1), unused for LoRaWAN 1.0. - \param sNwkSIntKey Pointer to the network session S key (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. + \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. \param force Set to true to force a new session, even if one exists. \returns \ref status_codes */ @@ -461,8 +536,7 @@ class LoRaWANNode { bool isJoined(); /*! - \brief Save the current state of the session. - All variables are compared to what is saved and only the differences are rewritten. + \brief Save the current state of the session to the session buffer. \returns \ref status_codes */ int16_t saveSession(); @@ -637,10 +711,9 @@ class LoRaWANNode { /*! \brief Set uplink datarate. This should not be used when ADR is enabled. \param dr Datarate to use for uplinks. - \param saveToEeprom Whether to save this setting to EEPROM or not (default false). \returns \ref status_codes */ - int16_t setDatarate(uint8_t drUp, bool saveToEeprom = false); + int16_t setDatarate(uint8_t drUp); /*! \brief Toggle ADR to on or off. @@ -686,10 +759,9 @@ class LoRaWANNode { /*! \brief Configure TX power of the radio module. \param txPower Output power during TX mode to be set in dBm. - \param saveToEeprom Whether to save this setting to EEPROM or not (default false). \returns \ref status_codes */ - int16_t setTxPower(int8_t txPower, bool saveToEeprom = false); + int16_t setTxPower(int8_t txPower); /*! \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. @@ -732,8 +804,16 @@ class LoRaWANNode { PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; + static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); + void beginCommon(uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + // a buffer that holds all LW base parameters that should persist at all times! + uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; + + // a buffer that holds all LW session parameters that preferably persist, but can be afforded to get lost + uint8_t bufferSession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE] = { 0 }; + LoRaWANMacCommandQueue_t commandsUp = { .numCommands = 0, .len = 0, @@ -776,7 +856,7 @@ class LoRaWANNode { bool FSK = false; // flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA) - uint16_t activeMode = 0; + uint16_t activeMode = RADIOLIB_LORAWAN_MODE_NONE; // ADR is enabled by default bool adrEnabled = true; @@ -835,26 +915,6 @@ class LoRaWANNode { // save the selected sub-band in case this must be restored in ADR control uint8_t subBand = 0; -#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) - /*! - \brief Save the current uplink frame counter. - Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. - */ - void saveFcntUp(); - - /*! - \brief Restore frame counter for uplinks from persistent storage. - Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. - */ - void restoreFcntUp(); - - // set all keys to zero - void clearSession(); - - // test if saved keys are non-zero - bool isValidSession(); -#endif - // wait for, open and listen during Rx1 and Rx2 windows; only performs listening int16_t downlinkCommon(); @@ -901,13 +961,13 @@ class LoRaWANNode { int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload = NULL); // execute mac command, return the number of processed bytes for sequential processing - bool execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom = true); + bool execMacCommand(LoRaWANMacCommand_t* cmd); // apply a channel mask to a set of readily defined channels (dynamic bands only) bool applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask); // define or delete channels from a fixed set of channels (fixed bands only) - bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool clear); + bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask); // get the payload length for a specific MAC command uint8_t getMacPayloadLength(uint8_t cid); @@ -922,7 +982,7 @@ class LoRaWANNode { void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum - static uint16_t checkSum16(uint8_t *key, uint8_t keyLen); + static uint16_t checkSum16(uint8_t *key, uint16_t keyLen); // network-to-host conversion method - takes data from network packet and converts it to the host endians template diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index e8b244bd9a..ad0b1b9ee2 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -2,7 +2,21 @@ #if !RADIOLIB_EXCLUDE_LORAWAN +enum LoRaWANBandNum_t { + BandNone, + BandEU868, + BandUS915, + BandCN780, + BandEU433, + BandAU915, + BandCN500, + BandAS923, + BandKR920, + BandIN865 +}; + const LoRaWANBand_t EU868 = { + .bandNum = BandEU868, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, @@ -48,6 +62,7 @@ const LoRaWANBand_t EU868 = { }; const LoRaWANBand_t US915 = { + .bandNum = BandUS915, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, @@ -114,6 +129,7 @@ const LoRaWANBand_t US915 = { }; const LoRaWANBand_t CN780 = { + .bandNum = BandCN780, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, @@ -159,6 +175,7 @@ const LoRaWANBand_t CN780 = { }; const LoRaWANBand_t EU433 = { + .bandNum = BandEU433, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, @@ -204,6 +221,7 @@ const LoRaWANBand_t EU433 = { }; const LoRaWANBand_t AU915 = { + .bandNum = BandAU915, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, @@ -270,6 +288,7 @@ const LoRaWANBand_t AU915 = { }; const LoRaWANBand_t CN500 = { + .bandNum = BandCN500, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, @@ -329,6 +348,7 @@ const LoRaWANBand_t CN500 = { }; const LoRaWANBand_t AS923 = { + .bandNum = BandAS923, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, @@ -374,6 +394,7 @@ const LoRaWANBand_t AS923 = { }; const LoRaWANBand_t KR920 = { + .bandNum = BandKR920, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, @@ -419,6 +440,7 @@ const LoRaWANBand_t KR920 = { }; const LoRaWANBand_t IN865 = { + .bandNum = BandIN865, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, From 44f6c1d432e37e8860dcab5c6ee1365ccdb58c72 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 18 Mar 2024 09:37:16 +0100 Subject: [PATCH 0942/1848] [CI] Enable LoRaWAN builds for previously disabled platforms --- .github/workflows/main.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6dfb1a823a..12c45391ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,22 +50,17 @@ jobs: - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble - run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:mbed:envie_m4 - run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:megaavr:uno2018 run: | echo "options=':mode=on'" >> $GITHUB_OUTPUT echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT - id: arduino:sam:arduino_due_x - run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: arduino:samd:arduino_zero_native - run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: adafruit:samd:adafruit_feather_m0 run: | echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: adafruit:nrf52:feather52832 run: | sudo apt-get update @@ -75,7 +70,6 @@ jobs: echo "/home/runner/.local/bin" >> $GITHUB_PATH echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT - echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: esp32:esp32:esp32 run: | python -m pip install pyserial @@ -102,10 +96,8 @@ jobs: echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - id: MegaCoreX:megaavr:4809 run: | - echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT - id: arduino:mbed_rp2040:pico - run: echo "skip-pattern=(STM32WL|LoRaWAN_End_Device_Persistent)" >> $GITHUB_OUTPUT - id: rp2040:rp2040:rpipico run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT - id: CubeCell:CubeCell:CubeCell-Board From cfc425970cbcb2355c0d8c02d6d589228c0d144e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 18 Mar 2024 16:39:55 +0100 Subject: [PATCH 0943/1848] [LoRaWAN] Resolve warnings, fix bugs for fixed bands (#1021) * [LoRaWAN] Resolve warnings * [LoRaWAN] Fixed bands: improve initial datarate, fix CFList bug * [LoRaWAN] Improve MAC debug output formatting * Fix hexdump debug level * Remove unnecessary error, add new ones to keywords * [LoRaWAN] Discard useless check --------- Co-authored-by: StevenCellist --- keywords.txt | 5 +- src/BuildOpt.h | 2 +- src/Module.cpp | 9 ++- src/Module.h | 6 +- src/TypeDef.h | 17 ++-- src/protocols/LoRaWAN/LoRaWAN.cpp | 126 +++++++++++++++++------------- src/protocols/LoRaWAN/LoRaWAN.h | 5 +- 7 files changed, 94 insertions(+), 76 deletions(-) diff --git a/keywords.txt b/keywords.txt index 2cfc5eae4a..48efe63259 100644 --- a/keywords.txt +++ b/keywords.txt @@ -430,9 +430,10 @@ RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 RADIOLIB_ERR_INVALID_CID LITERAL1 RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 -RADIOLIB_ERR_COMMAND_QUEUE_EMPTY LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 -RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 \ No newline at end of file +RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 +RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 +RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 \ No newline at end of file diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 635acd9cec..5653a1ef1e 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -479,7 +479,7 @@ #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif - #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) RADIOLIB_DEBUG_PRINT(LEVEL); Module::hexdump(__VA_ARGS__) + #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) Module::hexdump(LEVEL, __VA_ARGS__) #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} diff --git a/src/Module.cpp b/src/Module.cpp index ee1705842a..c46e26e9c3 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -407,7 +407,7 @@ uint32_t Module::reflect(uint32_t in, uint8_t bits) { } #if RADIOLIB_DEBUG -void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { +void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { char str[80]; @@ -446,20 +446,23 @@ void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, for(size_t j = line_len; j < 16; j++) { sprintf(&str[58 + j], " "); } + if(level) { + RADIOLIB_DEBUG_PRINT(level); + } RADIOLIB_DEBUG_PRINT(str); RADIOLIB_DEBUG_PRINTLN(); rem_len -= 16; } } -void Module::regdump(uint16_t start, size_t len) { +void Module::regdump(const char* level, uint16_t start, size_t len) { #if RADIOLIB_STATIC_ONLY uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* buff = new uint8_t[len]; #endif SPIreadRegisterBurst(start, len, buff); - hexdump(buff, len, start); + hexdump(level, buff, len, start); #if !RADIOLIB_STATIC_ONLY delete[] buff; #endif diff --git a/src/Module.h b/src/Module.h index c67aaf6aa6..9b5b78dbce 100644 --- a/src/Module.h +++ b/src/Module.h @@ -471,19 +471,21 @@ class Module { #if RADIOLIB_DEBUG /*! \brief Function to dump data as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. \param data Data to dump. \param len Number of bytes to dump. \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). \param be Print multi-byte data as big endian. Defaults to false. */ - static void hexdump(uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); + static void hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); /*! \brief Function to dump device registers as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. \param start First address to dump. \param len Number of bytes to dump. */ - void regdump(uint16_t start, size_t len); + void regdump(const char* level, uint16_t start, size_t len); #endif #if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) diff --git a/src/TypeDef.h b/src/TypeDef.h index 0135cac2ad..818d99d59a 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -528,40 +528,35 @@ */ #define RADIOLIB_ERR_COMMAND_QUEUE_FULL (-1109) -/*! - \brief Unable to pop existing MAC command because the queue is empty. -*/ -#define RADIOLIB_ERR_COMMAND_QUEUE_EMPTY (-1110) - /*! \brief Unable to delete MAC command because it was not found in the queue. */ -#define RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND (-1111) +#define RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND (-1110) /*! \brief Unable to join network because JoinNonce is not higher than saved value. */ -#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1112) +#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111) /*! \brief Received downlink Network frame counter is invalid (lower than last heard value). */ -#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1113) +#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1112) /*! \brief Received downlink Application frame counter is invalid (lower than last heard value). */ -#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1114) +#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1113) /*! \brief Uplink payload length at this datarate exceeds the active dwell time limitations. */ -#define RADIOLIB_ERR_DWELL_TIME_EXCEEDED (-1115) +#define RADIOLIB_ERR_DWELL_TIME_EXCEEDED (-1114) /*! \brief The buffer integrity check did not match the supplied checksum value. */ -#define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1116) +#define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1115) /*! \} diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index d4295cde06..0e7692c3a3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -258,7 +258,6 @@ int16_t LoRaWANNode::restoreChannels() { this->setupChannelsFix(this->subBand); } - Module* mod = this->phyLayer->getMod(); uint8_t bufferZeroes[5] = { 0 }; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; @@ -309,38 +308,72 @@ int16_t LoRaWANNode::restoreChannels() { return(RADIOLIB_ERR_NONE); } -void LoRaWANNode::beginCommon(uint8_t joinDr) { +void LoRaWANNode::beginCommon(uint8_t initialDr) { // in case a new session is started while there is an ongoing session // clear the MAC queues completely memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, - .repeat = 0, - }; + uint8_t drUp = 0; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - uint8_t drUp = 0; - // if join datarate is user-specified and valid, select that value; otherwise use - if(joinDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - if(joinDr >= this->band->txFreqs[0].drMin && joinDr <= this->band->txFreqs[0].drMax) { - drUp = joinDr; + // if join datarate is user-specified and valid, select that value + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr >= this->band->txFreqs[0].drMin && initialDr <= this->band->txFreqs[0].drMax) { + drUp = initialDr; } else { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid (min: %d, max %d) - using default", - joinDr, this->band->txFreqs[0].drMin, this->band->txFreqs[0].drMax); - joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + // if there is no channel that allowed the user-specified datarate, revert to default datarate + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; } - } - if(joinDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the floor of the average datarate of the first default channel + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; } - cmd.payload[0] = (drUp << 4); + } else { - uint8_t drJr = this->band->txSpans[0].joinRequestDataRate; - cmd.payload[0] = (drJr << 4); + // if the user specified a certain datarate, check if any of the configured channels allows it + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + uint8_t i = 0; + for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(initialDr >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && initialDr <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + break; + } + } + } + // if there is no channel that allowed the user-specified datarate, revert to default datarate + if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the join-request datarate for one of the available channels + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + // randomly select one of 8 or 9 channels and find corresponding datarate + uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; + uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 + if(rand <= 8) { + drUp = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 + } else { + drUp = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 + } + } + } + + LoRaWANMacCommand_t cmd = { + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .payload = { 0 }, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .repeat = 0, + }; + cmd.payload[0] = (drUp << 4); // set uplink datarate cmd.payload[0] |= 0; // default to max Tx Power cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored (void)execMacCommand(&cmd); @@ -457,7 +490,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } RADIOLIB_ASSERT(state); - // setup all MAC properties to default values + // on fixed bands, the join-datarate is specified per specification + // therefore, we ignore the value that was specified by the user + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + // setup all MAC properties to default values this->beginCommon(joinDr); // set the physical layer configuration @@ -694,7 +732,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force) { +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force, uint8_t initialDr) { // if not forced and already joined, don't do anything if(!force && this->isJoined()) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active"); @@ -744,7 +782,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, } // setup all MAC properties to default values - this->beginCommon(); + this->beginCommon(initialDr); // set the physical layer configuration state = this->setPhyProperties(); @@ -780,8 +818,6 @@ bool LoRaWANNode::isJoined() { } int16_t LoRaWANNode::saveSession() { - Module* mod = this->phyLayer->getMod(); - // store DevAddr and all keys LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); @@ -1734,16 +1770,6 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - - // randomly select one of 8 or 9 channels and find corresponding datarate - uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; - uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 - uint8_t drJR = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - if(rand <= 8) { - drJR = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 - } else { - drJR = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 - } // if no subband is selected by user, cycle through banks of 8 using devNonce value if(subBand == 0) { @@ -1814,18 +1840,17 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { .len = 0, .repeat = 0, }; - cmd.payload[0] = 0xFF; // same datarate and payload // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels - size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span + size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[3] = chMaskCntl << 4; // NbTrans = 0 -> keep the same + cmd.payload[0] = 0xFF; // same datarate and payload + memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); // copy mask + cmd.payload[3] = chMaskCntl << 4; // set chMaskCntl, set NbTrans = 0 -> keep the same cmd.repeat = (chMaskCntl + 1); - memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); (void)execMacCommand(&cmd); } - // delete the ADR response } return(RADIOLIB_ERR_NONE); @@ -2097,10 +2122,6 @@ int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQ } int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload) { - if(queue->numCommands == 0) { - return(RADIOLIB_ERR_COMMAND_QUEUE_EMPTY); - } - for(size_t index = 0; index < queue->numCommands; index++) { if(queue->commands[index].cid == cid) { // if a pointer to a payload is supplied, copy the command's payload over @@ -2123,11 +2144,8 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que } bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { - RADIOLIB_DEBUG_PROTOCOL_PRINT("[MAC] 0x%02X %s", cmd->cid, cmd->len ? "= 0x" : ""); - for(uint8_t i = 0; i < cmd->len; i++) { - RADIOLIB_DEBUG_PROTOCOL_PRINT("%02X", cmd->payload[i]); - } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02X", cmd->cid); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { // TODO call user-provided callback for proprietary MAC commands? @@ -2228,7 +2246,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); } else { // RADIOLIB_LORAWAN_BAND_FIXED - bool clearChannels = false; if(cmd->repeat == 1) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask @@ -2270,7 +2287,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } else { // RADIOLIB_LORAWAN_BAND_FIXED // save Tx/Dr to the Link ADR position in the session buffer - uint8_t bufTxDr[cmd->len] = { 0 }; + uint8_t bufTxDr[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; bufTxDr[0] = cmd->payload[0]; bufTxDr[3] = 1 << 7; memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); @@ -2672,9 +2689,8 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { } if(this->band->numTxSpans == 2 && chMaskCntl == 6) { // all channels on (but we revert to selected subband) - if(this->subBand >= 0) { - this->setupChannelsFix(this->subBand); - } + this->setupChannelsFix(this->subBand); + // a '1' enables a single channel from second span LoRaWANChannel_t chnl; for(uint8_t i = 0; i < 8; i++) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 9c90202b8e..0aab1fa7a0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -528,9 +528,10 @@ class LoRaWANNode { \param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. \param force Set to true to force a new session, even if one exists. + \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false); + int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \brief Whether there is an ongoing session active */ bool isJoined(); @@ -806,7 +807,7 @@ class LoRaWANNode { static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); - void beginCommon(uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + void beginCommon(uint8_t initialDr); // a buffer that holds all LW base parameters that should persist at all times! uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; From 0182a123fb4c4b6896759b5e54c6736cb1192443 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Sat, 23 Mar 2024 17:00:13 +0000 Subject: [PATCH 0944/1848] Update of examples to latest API, testing, repeat --- .../LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino | 196 +++++++++++++++++ examples/LoRaWAN/LoRaWAN_ESP32/config.h | 130 +++++++++++ examples/LoRaWAN/LoRaWAN_Reference/config.h | 130 +++++++++++ .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 41 ++++ examples/LoRaWAN/LoRaWAN_Starter/config.h | 130 +++++++++++ examples/LoRaWAN/LoRaWAN_Starter/notes.md | 202 ++++++++++++++++++ 6 files changed, 829 insertions(+) create mode 100644 examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino create mode 100644 examples/LoRaWAN/LoRaWAN_ESP32/config.h create mode 100644 examples/LoRaWAN/LoRaWAN_Reference/config.h create mode 100644 examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino create mode 100644 examples/LoRaWAN/LoRaWAN_Starter/config.h create mode 100644 examples/LoRaWAN/LoRaWAN_Starter/notes.md diff --git a/examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino b/examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino new file mode 100644 index 0000000000..f2d567bbd3 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino @@ -0,0 +1,196 @@ + +/* + +This demonstrates how to save the join information in to permanent memory +so that if the power fails, batteries run out or are changed, the rejoin +is more efficient & happens sooner due to the way that LoRaWAN secures +the join process - see the wiki for more details. + +This is typically useful for devices that need more power than a battery +driven sensor - something like a air quality monitor or GPS based device that +is likely to use up it's power source resulting in loss of the session. + +The relevant code is flagged with a ##### comment + +Saving the entire session is possible but not demonstrated here - it has +implications for flash wearing and complications with which parts of the +session may have changed after an uplink. So it is assumed that the device +is going in to deep-sleep, as below, between normal uplinks. + +*/ + +#if !defined(ESP32) + #pragma error ("This is not the example your device is looking for - ESP32 only") +#endif + +// ##### Load the ESP32 preferences facilites +#include +Preferences store; + +// LoRaWAN config, credentials & pinmap +#include "config.h" + +#include + +// Utilities & vars to support ESP32 deep-sleep. The RTC_DATA_ATTR attribute +// puts these in to the RTC memory which is preserved during deep-sleep +RTC_DATA_ATTR uint16_t bootCount = 1; +RTC_DATA_ATTR uint16_t bootCountSinceUnsuccessfulJoin = 0; +RTC_DATA_ATTR uint8_t LWsession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE]; + +// Abbreviated version from the Arduino-ESP32 package, see +// https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/deepsleep.html +// for the complete set of options +void print_wakeup_reason() { + esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); + if (wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) { + Serial.println(F("Wake from sleep")); + } else { + Serial.print(F("Wake not caused by deep sleep: ")); + Serial.println(wakeup_reason); + } + + Serial.print(F("Boot count: ")); + Serial.println(bootCount++); +} + +// Put device in to lowest power deep-sleep mode +void gotoSleep(uint32_t seconds) { + esp_sleep_enable_timer_wakeup(seconds * 1000UL * 1000UL); // Function uses uS + Serial.println(F("Sleeping\n")); + Serial.flush(); + + esp_deep_sleep_start(); + + // If this appears in the serial debug, we didn't go to sleep! + // So take defensive action so we don't continually uplink + Serial.println(F("\n\n### Sleep failed, delay of 5 minutes & then restart ###\n")); + delay(5UL * 60UL * 1000UL); + ESP.restart(); +} + + + +// Setup & execute all device functions ... +void setup() { + Serial.begin(115200); + while (!Serial); // Wait for serial to be initalised + delay(2000); // Give time to switch to the serial monitor + Serial.println(F("\nSetup")); + print_wakeup_reason(); + + int16_t state = 0; // return value for calls to RadioLib + + // Setup the radio based on the pinmap (connections) in config.h + Serial.println(F("Initalise the radio")); + state = radio.begin(); + debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + + Serial.println(F("Recalling LoRaWAN nonces & session")); + // ##### Setup the flash storage + store.begin("radiolib"); + // ##### If we have previously saved nonces, restore them + if (store.isKey("nonces")) { + uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE];// Create somewhere to store nonces + store.getBytes("nonces", buffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);// Get them to the store + state = node.setBufferNonces(buffer); // Send them to LoRaWAN + debug(state != RADIOLIB_ERR_NONE, F("Restoring nonces buffer failed"), state, false); + } + + // Recall session from RTC deep-sleep preserved variable + state = node.setBufferSession(LWsession); // Send them to LoRaWAN stack + // If we have booted at least once we should have a session to restore, so report any failure + // Otherwise no point saying there's been a failure when it was bound to fail with an empty + // LWsession var. At this point, bootCount has already been incremented, hence the > 2 + debug((state != RADIOLIB_ERR_NONE) && (bootCount > 2), F("Restoring session buffer failed"), state, false); + + // Process the restored session or failing that, create a new one & + // return flag to indicate a fresh join is required + Serial.println(F("Setup LoRaWAN session")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, false); + // See comment above, no need to report a failure that is bound to occur on first boot + debug((state != RADIOLIB_ERR_NONE) && (bootCount > 2), F("Restore session failed"), state, false); + + // Loop until successful join + while (state != RADIOLIB_ERR_NONE) { + Serial.println(F("Join ('login') to the LoRaWAN Network")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); + + if (state < RADIOLIB_ERR_NONE) { + Serial.print(F("Join failed: ")); + Serial.println(state); + + // How long to wait before join attenpts. This is an interim solution pending + // implementation of TS001 LoRaWAN Specification section #7 - this doc applies to v1.0.4 & v1.1 + // It sleeps for longer & longer durations to give time for any gateway issues to resolve + // or whatever is interfering with the device <-> gateway airwaves. + uint32_t sleepForSeconds = min((bootCountSinceUnsuccessfulJoin++ + 1UL) * 60UL, 3UL * 60UL); + Serial.print(F("Boots since unsuccessful join: ")); + Serial.println(bootCountSinceUnsuccessfulJoin); + Serial.print(F("Retrying join in ")); + Serial.print(sleepForSeconds); + Serial.println(F(" seconds")); + + gotoSleep(sleepForSeconds); + + } else { // Join was successful + Serial.println(F("Joined")); + + // ##### Save the join counters (nonces) to permanent store + Serial.println(F("Saving nonces to flash")); + uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE]; // Create somewhere to store nonces + uint8_t *persist = node.getBufferNonces(); // Get pointer to nonces + memcpy(buffer, persist, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // Copy in to buffer + store.putBytes("nonces", buffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // Send them to the store + + // We'll save the session after the uplink + + // Reset the failed join count + bootCountSinceUnsuccessfulJoin = 0; + + delay(1000); // Hold off off hitting the airwaves again too soon - an issue in the US + + } // if beginOTAA state + } // while join + + // ##### Close the store + store.end(); + + + // ----- And now for the main event ----- + Serial.println(F("Sending uplink")); + + // Read some inputs + uint8_t Digital2 = digitalRead(2); + uint16_t Analog1 = analogRead(A1); + + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = Digital2; + uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(Analog1); + + // Perform an uplink + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + + Serial.print(F("FcntUp: ")); + Serial.println(node.getFcntUp()); + + // Now save session to RTC memory + uint8_t *persist = node.getBufferSession(); + memcpy(LWsession, persist, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + + // Wait until next uplink - observing legal & TTN FUP constraints + gotoSleep(uplinkIntervalSeconds); + +} + + +// The ESP32 wakes from deep-sleep and starts from the very beginning +// which is a very good place to start, as any singing nun knows. +// It then goes back to sleep, so loop() is never called and which is +// why it is empty. + +void loop() {} + diff --git a/examples/LoRaWAN/LoRaWAN_ESP32/config.h b/examples/LoRaWAN/LoRaWAN_ESP32/config.h new file mode 100644 index 0000000000..bba38e4fe7 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_ESP32/config.h @@ -0,0 +1,130 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +// How often to send an uplink - consider legal & FUP constraints - see notes +const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds + +// JoinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// The Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// For the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + + + +// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// Auto select MCU <-> radio connections +// If you get an error message when compiling, it may be that the +// pinmap could not be determined - see the notes for more info + +// Adafruit +#if defined(ARDUINO_SAMD_FEATHER_M0) + #pragma message ("Adafruit Feather M0 with RFM95") + #pragma message ("Link required on board") + SX1276 radio = new Module(8, 3, 4, 6); + + +// LilyGo +#elif defined(ARDUINO_TTGO_LORA32_V1) + #pragma message ("TTGO LoRa32 v1 - no Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TTGO_LORA32_V2) + #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + +#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) + #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 23, 33); + + +// Heltec +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) + #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") + +#elif defined(ARDUINO_heltec_wifi_kit_32_V2) + #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_heltec_wifi_kit_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +#elif defined(ARDUINO_CUBECELL_BOARD) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +#elif defined(ARDUINO_CUBECELL_BOARD_V2) + #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") + + +#else + #pragma message ("Unknown board - no automagic pinmap available") + + // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); + // SX1262 radio = new Module(8, 14, 12, 13); + + // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); + // SX1278 radio = new Module(10, 2, 9, 3); + +#endif + + +// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; + +// Create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + + +// Helper function to display any issues +void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { + if (isFail) { + Serial.print(message); + Serial.print("("); + Serial.print(state); + Serial.println(")"); + while (Freeze); + } +} + +// Helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for (uint16_t c; c < len; c++) { + Serial.printf("%02X", buffer[c]); + } + Serial.println(); +} + + +#endif diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h new file mode 100644 index 0000000000..bba38e4fe7 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -0,0 +1,130 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +// How often to send an uplink - consider legal & FUP constraints - see notes +const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds + +// JoinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// The Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// For the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + + + +// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// Auto select MCU <-> radio connections +// If you get an error message when compiling, it may be that the +// pinmap could not be determined - see the notes for more info + +// Adafruit +#if defined(ARDUINO_SAMD_FEATHER_M0) + #pragma message ("Adafruit Feather M0 with RFM95") + #pragma message ("Link required on board") + SX1276 radio = new Module(8, 3, 4, 6); + + +// LilyGo +#elif defined(ARDUINO_TTGO_LORA32_V1) + #pragma message ("TTGO LoRa32 v1 - no Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TTGO_LORA32_V2) + #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + +#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) + #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 23, 33); + + +// Heltec +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) + #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") + +#elif defined(ARDUINO_heltec_wifi_kit_32_V2) + #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_heltec_wifi_kit_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +#elif defined(ARDUINO_CUBECELL_BOARD) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +#elif defined(ARDUINO_CUBECELL_BOARD_V2) + #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") + + +#else + #pragma message ("Unknown board - no automagic pinmap available") + + // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); + // SX1262 radio = new Module(8, 14, 12, 13); + + // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); + // SX1278 radio = new Module(10, 2, 9, 3); + +#endif + + +// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; + +// Create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + + +// Helper function to display any issues +void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { + if (isFail) { + Serial.print(message); + Serial.print("("); + Serial.print(state); + Serial.println(")"); + while (Freeze); + } +} + +// Helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for (uint16_t c; c < len; c++) { + Serial.printf("%02X", buffer[c]); + } + Serial.println(); +} + + +#endif diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino new file mode 100644 index 0000000000..4ccc372ec8 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -0,0 +1,41 @@ +#include + +#include "config.h" + +void setup() { + Serial.begin(115200); + while (!Serial); + Serial.println(F("\nSetup ... ")); + + Serial.println(F("Initalise the radio")); + int state = radio.begin(); + debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + + Serial.println(F("Join ('login') to the LoRaWAN Network")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); + debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true); + + Serial.println(F("Ready!\n")); +} + + +void loop() { + Serial.println(F("Sending uplink")); + + // Read some inputs + uint8_t Digital1 = digitalRead(2); + uint16_t Analog1 = analogRead(A0); + + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = Digital1; + uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(Analog1); + + // Perform an uplink + int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + + // Wait until next uplink - observing legal & TTN FUP constraints + delay(uplinkIntervalSeconds * 1000UL); +} diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h new file mode 100644 index 0000000000..bba38e4fe7 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -0,0 +1,130 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +// How often to send an uplink - consider legal & FUP constraints - see notes +const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds + +// JoinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// The Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// For the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + + + +// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// Auto select MCU <-> radio connections +// If you get an error message when compiling, it may be that the +// pinmap could not be determined - see the notes for more info + +// Adafruit +#if defined(ARDUINO_SAMD_FEATHER_M0) + #pragma message ("Adafruit Feather M0 with RFM95") + #pragma message ("Link required on board") + SX1276 radio = new Module(8, 3, 4, 6); + + +// LilyGo +#elif defined(ARDUINO_TTGO_LORA32_V1) + #pragma message ("TTGO LoRa32 v1 - no Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TTGO_LORA32_V2) + #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + +#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) + #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 23, 33); + + +// Heltec +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) + #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") + +#elif defined(ARDUINO_heltec_wifi_kit_32_V2) + #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_heltec_wifi_kit_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +#elif defined(ARDUINO_CUBECELL_BOARD) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +#elif defined(ARDUINO_CUBECELL_BOARD_V2) + #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") + + +#else + #pragma message ("Unknown board - no automagic pinmap available") + + // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); + // SX1262 radio = new Module(8, 14, 12, 13); + + // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); + // SX1278 radio = new Module(10, 2, 9, 3); + +#endif + + +// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; + +// Create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + + +// Helper function to display any issues +void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { + if (isFail) { + Serial.print(message); + Serial.print("("); + Serial.print(state); + Serial.println(")"); + while (Freeze); + } +} + +// Helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for (uint16_t c; c < len; c++) { + Serial.printf("%02X", buffer[c]); + } + Serial.println(); +} + + +#endif diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md new file mode 100644 index 0000000000..4f56a617a9 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -0,0 +1,202 @@ + + +# RadioLib LoRaWAN on TTN starter script + +## Welcome + +These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C coding ninja but some familarity with C and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration. + + +## Introduction + +LoRaWAN is an amazing system for small battery powered sensors collecting data for years at a time. With great features comes some more complex elements which means it is not quite as simple as just providing WiFi credentials and pushing data through. It is in the range of setting up & customising the settings for a home router but with no wizards to do the heavy lifting for you. So we strongly recommend spending a couple of hours reviewing the TTN Getting Started section so you are aware of the minimum knowledge to make a successful start: https://www.thethingsnetwork.org/docs/lorawan/. Johan's video is amazing but is also drinking from the firehose. Read the text first and then watch the video on Youtube where there are bookmarks to deliver it in small digestable chunks. + +These notes plus a lot more are available in the wiki: https://github.com/jgromes/RadioLib/wiki/LoRaWAN + +For questions about using RadioLib there is the discussions section (https://github.com/jgromes/RadioLib/discussions) and if you believe you've found an issue (aka bug), the issues section (https://github.com/jgromes/RadioLib/issues). If posting an issue please ensure you tell us what hardware you are using and provide a debug log - please do not use verbose mode unless asked to. If the question is more LoRaWAN or firmware related, then you can use the TTN forum: https://www.thethingsnetwork.org/forum/ + + +## Register & setup on TTN + +This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Helium does not support LoRaWAN v1.1 which is the version implemented by RadioLib. Chirpstack & other LoRaWAN Network Server (LNS) stacks have not yet been tried so YMMV. + +Why no screen shots? TTS is a web based app, one that you will need to become familiar with and we will need to direct you to some of the less obvious parts. So much better that you learn the layouts in concept than slavishly follow screen shots that can & will go stale. + +There will be some instructions that you have to take on face value. You didn't learn to run before you walked and it's so much more encouraging to get started and build on success than get bogged down in endless details. Once you are up & running more of the details start to slot in to place. + +### Register on TTN + +Go to https://www.thethingsnetwork.org/get-started and register - just like any other website. These instructions are for TTS Sandbox. + +Once you have confirmed your email address, you can login to the console here: https://console.cloud.thethings.network/. If you allow your browser to share you location the best console will be selected. For most users the best one is the obvious one, if you have any doubts you can ask on the forum here: https://www.thethingsnetwork.org/forum/ - you login with the exact same details. + +It is simpler to register your gateway first. If you don't have a gateway, then a The Things Indoor Gateway (TTIG) is a very affordable option. A gateway gives you a console to see if your device is being heard and is hugely useful when debugging a DIY device. If you are in range of a community gateway you may be lucky with your first device creation but you will never know if you are in range unless you have access to that gateways console. + +You can read up on key concepts and troubleshooting here: https://www.thethingsindustries.com/docs/gateways/ + +LoRa stands for Long Range - having the gateway & device on the same desk tends to overload both receiver circuits when they hear a transmission so close to hand. The gateway should be 5 - 10m away, preferably with a solid wall in the way as well. + +### Create your application + +An application is like a box to keep some devices in - normally doing the same thing - on larger deployments this may be 1,000's of similar devices. Starting out it it is likely to be just a few so there is no need to get concerned about how to divide up your use just yet. + +Onced logged in to the console you can go in to Applications to create your first application. The ID must be all lower case or numbers, no spaces, dashes are OK and it has to be unique to the entire TTN community - so `first-app` will be rejected - you could use `your-username-first-app` as that's likely to be unique. The name and description are for your own use and are optional. + +The main menu for an application is in the left hand panel - nothing is needed there just yet. + +### Create your device + +On the right hand side about half way down on your application's summary is a big blue button `+ Register end device`. Click this to create the settings for your first device. + +You are making your own device using a third party LoRaWAN stack so there will not be an entry in the device repository so choose 'Enter end device specifics manually'. + +Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'. + +Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B. + +At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the cosole generate them so they are properly formatted. + +Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like devicename-01. The you can click the blue 'Register device'. + +When many sensors are big deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do. + +Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the Resets join nonces option. You will see a warning about replay attacks which is entirely proper & correct. If anyone evesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password. + +You then need to copy over the device details in to the config file for RadioLib. There are buttons to copy items to the clipboard so you don't have to hand type them. + +### Copy & Paste made easy + +You can copy the EUIs & keys from the device overview section. + +The EUIs are really straightforward - click the clipboard icon at the right hand end of the EUI display field and it will be copied in the format you need. You can then paste it in to the code - you must leave the 0x in place so the compiler knows that it's a hex value. + +The keys are relatively straightforward. Click the eye icon at the right hand end of the field. Then click the <> icon that will appear to the left. This will format the hex values as an array. Then you can click the clipboard icon to copy the array and then paste it between the { } brackets. + +### Secrets to keep safe. + +The Join & Dev EUI's are transmitted in plain text when the device joins a network. The gateway ID is public. If you have an issue and are asked for details, there are only three things to keep private - your password, the keys which are used for encryption and any API keys you create which are used for accessing your data & configuration. + + +### Monitoring your device + +If you are on your application summary page you'll see uplinks in the small activity box top right with a link to the full size table. If you click the Live Data menu item on the left it will show activity for all the devices registered on the application in the full window. + +If you just want your devices activity, from the summary page click on the device in the list in the middle of the page. + +The main menu for a device is the horizontal band: Overview, Live Data, Messaging etc. You can click Live Data or the link above the small activity box. + +**The console shows LIVE data - not a history of everything that has ever happened. A LNS is a management & relay service, not a database. When you open the console you may see a summary of recent activity - this is a bonus. You must leave the console open, even in another tab, if you want to see live activity.** + + +### Explore + +Nothing on the console can be upset unless you confirm a warning message, so you are safe to explore the different menus to orientate yourself. This is very good idea so you are have an understanding of the layout of the land and shouldn't take more than 10 or 15 minutes. The documentation & volunteers on GitHub and the TTN forum will make refer to parts of the console without giving blow by blow directions. + + + + +## The config.h + +### The uplinkInterval + +LoRaWAN devices typically send small amounts of data at intervals between 15 minutes through to once per day. This allows a device to run on two AA batteries for 2 to 5 years. Hoping that LoRaWAN can move lots of data and your device can regularly receive commands to do something on demand is trying to bend the LoRaWAN system in ways it is not designed for and usually ends up with far too many issues to unravel. + +The radio frequencies that are used are usually shared with other Industrial, Scientific & Medical, known as ISM, users. The LoRa modulation is particularly resistance to interference due to other simultaneous transmissions on the same frequency but too much local activity will mean that not all uplinks get through. The Things Industries suggest designing a system to a potential packet loss rate of 10%. Typically we see 1 or 2% loss. This is entirely down to shared use of the radio waves, once an uplink is heard by a gateway the system is super reliable through The Things Stack. + +To ensure that the shared ISM bands are fairly used there are limits defined in law on how often you can transmit, called Duty Cycle. The details vary by region or country but typically you can only transmit for 1% of the time. Some frequencies you can only use 0.1% of the time. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/ for more information. + +Additionally, as The Things Stack Sandbox aka TTN is an array of servers in three locations around the world paid for by The Things Industries, there is a Fair Use Policy so that those learning LoRaWAN, communities, hobbyists & makers are guided on how much of the resource any one device can use. In short, it's 30 seconds of airtime a day and 10 downlinks. When a gateway is transmitting a downlink it can not hear any uplinks (contributing to the potential uplink loss outlined above). The community concensus is that 1 downlink a fortnight to update or adjust settings is appropriate. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/#fair-use-policy for more information. + +You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. A uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so + +With all thes considerations, trying to use LoRaWAN for command & control isn't appropriate and realtime GPS tracking almost always breaches FUP and usually legal limits, leaving aside the challenges of coverage. + +See the hints & tips section on testing your device. + + +### EUI's & Keys + +In the config.h towards the top there are four lines thus: + +// replace-with-your-device-id +uint64_t joinEUI = 0x0000000000000000; +uint64_t devEUI = 0x0000000000000000; +uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t nwkKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +On the TTN console on the device summary page, click the clipboard icon next to the DevEUI, highlight the 16 0's in the third line after the x and paste. + +The devEUI must start with 0x and will end up looking something like 0x70B3D57ED006544E + +For the appKey we need TTN to format it correctly. Click the eye icon and an extra icon will appear <> - click this and the key will be formatted for you. Click the clipboard icon and then paste over the 32 0x00's in the config file. Then do the same for nwkKey. + +A key will end up something like 0x31, 0x16, 0x6A, 0x22, 0x97, 0x52, 0xB6, 0x34, 0x57, 0x45, 0x1B, 0xC3, 0xC9, 0xD8, 0x83, 0xE8 + + +### Region + +The region value you use MUST match the one you selected on the console. + +If you are using US915 or AU915 then you should change the subBand const to 2. + +### The pinmap + +This is the connections between the MCU (ESP32/ATmega/SAMD) and the LoRa radio (SX1276/SX1262). + +Prebuilt modules are easy - we can detect the board and setup the pinmap for you. These boards are: + +* TTGO_LoRa32 +* TTGO_LoRa32_V1 +* TTGO_LORA32_V2 +* TTGO_LORA32_v21NEW +* HELTEC_WIFI_LORA_32 +* HELTEC_WIFI_LORA_32_V2 +* HELTEC_WIFI_LORA_32_V3 +* CUBECELL_BOARD + +If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu. + +* TBEAM_USE_RADIO_SX1262 +* TBEAM_USE_RADIO_SX1276 + +If you have an Adafruit Feather M0 with RFM95 then you must solder a wire or use a jumper to link from pin 6 to io1: https://learn.adafruit.com/the-things-network-for-feather/arduino-wiring + + +If you have a module that's not on this list, please go to the "Pinmap How-To" below. + + + +## Observations on the main sketch + +Most of the sketch has comments that tell you what the various parts are doing. This should add a little more info: + +### The Join + +When a device is first started, it needs to register with the LoRaWAN Network Server (LNS) and setup it's session. With the settings from the console copied over and a gateway an appropriate distance away, most of the time the join will 'just work'. + +If it doesn't, then there is no point trying repeatedly without going through the troubleshootng sequence. So this starter sketch will try once only to save the airwaves & TTN Community servers from repeated misfires. + + +### The payload + +You may see other starter sketches sending text. Apart from being massively inefficient, the text isn't easily displayed on the TTN console which makes it rather pointless and pro embedded engineers don't send strings. So this sketch sends the data as a sequence of bytes as recommended. + +Further reading on this can be found here, just ignore the pink message about v2, it's all still valid: https://www.thethingsnetwork.org/docs/devices/bytes/ + +We've not assumed anything about any sensors you have, so we are just reading a digital & an analog pin. An analog reading is typically a two byte value - an integer - this is split using the Arduino highByte & lowByte function. You'll see how we put it back together in the TTN console below. + + +## TTN Console Payload Decoder + +Coming soon + +## Hints & Tips + +### Device testing + +The LoRaWAN code base works to a specification and once you are happy your device is able to join & send a few dozen uplinks, continuing to sit around waiting for an uplink to test your sensor code & payload format is a waste of your time. The solution is to write everything else in a different sketch, output the array to the serial console and then you can copy & paste the hex array in to the TTN console Payload Formatters section to test the decoding. + + +## Pinmap How-To + + From 5bc97550ecf976c9e3146b4c26bd1a5312f27e04 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Sat, 23 Mar 2024 17:03:21 +0000 Subject: [PATCH 0945/1848] Clean up prior named directories plus neglected Reference is included --- .../LoRaWAN_ABP.ino} | 0 examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 130 +++++++++++ .../LoRaWAN_End_Device/LoRaWAN_End_Device.ino | 161 -------------- .../LoRaWAN_Reference.ino} | 167 +++++---------- examples/LoRaWAN/Starter/Starter.ino | 41 ---- examples/LoRaWAN/Starter/config.h | 85 -------- examples/LoRaWAN/Starter/notes.md | 202 ------------------ 7 files changed, 185 insertions(+), 601 deletions(-) rename examples/LoRaWAN/{LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino => LoRaWAN_ABP/LoRaWAN_ABP.ino} (100%) create mode 100644 examples/LoRaWAN/LoRaWAN_ABP/configABP.h delete mode 100644 examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino rename examples/LoRaWAN/{LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino => LoRaWAN_Reference/LoRaWAN_Reference.ino} (52%) delete mode 100644 examples/LoRaWAN/Starter/Starter.ino delete mode 100644 examples/LoRaWAN/Starter/config.h delete mode 100644 examples/LoRaWAN/Starter/notes.md diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino similarity index 100% rename from examples/LoRaWAN/LoRaWAN_End_Device_ABP/LoRaWAN_End_Device_ABP.ino rename to examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h new file mode 100644 index 0000000000..bba38e4fe7 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -0,0 +1,130 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +// How often to send an uplink - consider legal & FUP constraints - see notes +const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds + +// JoinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// The Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// For the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + + + +// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// Auto select MCU <-> radio connections +// If you get an error message when compiling, it may be that the +// pinmap could not be determined - see the notes for more info + +// Adafruit +#if defined(ARDUINO_SAMD_FEATHER_M0) + #pragma message ("Adafruit Feather M0 with RFM95") + #pragma message ("Link required on board") + SX1276 radio = new Module(8, 3, 4, 6); + + +// LilyGo +#elif defined(ARDUINO_TTGO_LORA32_V1) + #pragma message ("TTGO LoRa32 v1 - no Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TTGO_LORA32_V2) + #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + +#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 14, 33); + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) + #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") + +#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1276 radio = new Module(18, 26, 23, 33); + + +// Heltec +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) + #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") + +#elif defined(ARDUINO_heltec_wifi_kit_32_V2) + #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_heltec_wifi_kit_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +#elif defined(ARDUINO_CUBECELL_BOARD) + #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +#elif defined(ARDUINO_CUBECELL_BOARD_V2) + #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") + + +#else + #pragma message ("Unknown board - no automagic pinmap available") + + // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); + // SX1262 radio = new Module(8, 14, 12, 13); + + // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); + // SX1278 radio = new Module(10, 2, 9, 3); + +#endif + + +// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; + +// Create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + + +// Helper function to display any issues +void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { + if (isFail) { + Serial.print(message); + Serial.print("("); + Serial.print(state); + Serial.println(")"); + while (Freeze); + } +} + +// Helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for (uint16_t c; c < len; c++) { + Serial.printf("%02X", buffer[c]); + } + Serial.println(); +} + + +#endif diff --git a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino b/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino deleted file mode 100644 index 9089a77c9e..0000000000 --- a/examples/LoRaWAN/LoRaWAN_End_Device/LoRaWAN_End_Device.ino +++ /dev/null @@ -1,161 +0,0 @@ -/* - RadioLib LoRaWAN End Device Example - - This example joins a LoRaWAN network and will send - uplink packets. Before you start, you will have to - register your device at https://www.thethingsnetwork.org/ - After your device is registered, you can run this example. - The device will join the network and start uploading data. - - NOTE: LoRaWAN v1.1 requires storing parameters persistently! - RadioLib does this by using EEPROM (persistent storage), - by default starting at address 0 and using 448 bytes. - If you already use EEPROM in your application, - you will have to either avoid this range, or change it - by setting a different start address by changing the value of - RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either - during build or in src/BuildOpt.h. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ - - For LoRaWAN details, see the wiki page - https://github.com/jgromes/RadioLib/wiki/LoRaWAN - - - Last updated 1st March 2024 for RadioLib 6.4.2 - -*/ - -// include the library -#include - -// SX1262 has the following pin order: -// Module(NSS/CS, DIO1, RESET, BUSY) -SX1262 radio = new Module(8, 14, 12, 13); - -// SX1278 has the following pin order: -// Module(NSS/CS, DIO0, RESET, DIO1) -// SX1278 radio = new Module(10, 2, 9, 3); - -// create the node instance on the EU-868 band -// using the radio module and the encryption key -// make sure you are using the correct band -// based on your geographical location! -LoRaWANNode node(&radio, &EU868); - -// for fixed bands with subband selection -// such as US915 and AU915, you must specify -// the subband that matches the Frequency Plan -// that you selected on your LoRaWAN console -// LoRaWANNode node(&radio, &US915, 2); - - -void setup() { - Serial.begin(9600); - - // initialize radio (SX1262 / SX1278 / ... ) with default settings - Serial.print(F("[Radio] Initializing ... ")); - int state = radio.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // JoinEUI - previous versions of LoRaWAN called this AppEUI - // for development purposes you can use all zeros - see wiki for details - uint64_t joinEUI = 0x0000000000000000; - - // DevEUI - The device's Extended Unique Identifier - // TTN will generate one for you - uint64_t devEUI = 0x----------------; - - // encryption keys used to secure the communication - // TTN will generate them for you - // see wiki for details on copying & pasting them - uint8_t nwkKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, - 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; - uint8_t appKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, - 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; - - - // Manages uplink intervals to the TTN Fair Use Policy - node.setDutyCycle(true, 1250); - - // Begin the join to the network - Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - if(state >= RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - delay(2000); // small delay between joining and uplink - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } -} // setup - -// counter to keep track of transmitted packets -int count = 0; - -void loop() { - // send uplink to port 10 - Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello! " + String(count++); - String strDown; - int state = node.sendReceive(strUp, 10, strDown); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("received a downlink!")); - - // print data of the packet (if there are any) - Serial.print(F("[LoRaWAN] Data:\t\t")); - if(strDown.length() > 0) { - Serial.println(strDown); - } else { - Serial.println(F("")); - } - - // print RSSI (Received Signal Strength Indicator) - Serial.print(F("[LoRaWAN] RSSI:\t\t")); - Serial.print(radio.getRSSI()); - Serial.println(F(" dBm")); - - // print SNR (Signal-to-Noise Ratio) - Serial.print(F("[LoRaWAN] SNR:\t\t")); - Serial.print(radio.getSNR()); - Serial.println(F(" dB")); - - // print frequency error - Serial.print(F("[LoRaWAN] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); - - } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("")); - - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // on boards that can save to Flash or EEPROM this saves the session - // which allows recall of the session after reboot or deepsleep - node.saveSession(); - - // wait before sending another packet - uint32_t minimumDelay = 300000; // try to send once every 3 minutes - uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per FUP & law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows - - Serial.print(F("[LoRaWAN] Next uplink in ")); - Serial.print(delayMs/60); - Serial.println(F("s")); - - delay(delayMs); -} // loop diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino similarity index 52% rename from examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino rename to examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 8e50b7a504..5df3114e8d 100644 --- a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -27,99 +27,54 @@ https://github.com/jgromes/RadioLib/wiki/LoRaWAN - Last updated 1st March 2024 for RadioLib 6.4.2 - */ +#include "config.h" + // include the library #include -// SX1262 has the following pin order: -// Module(NSS/CS, DIO1, RESET, BUSY) -SX1262 radio = new Module(8, 14, 12, 13); - -// SX1278 has the following pin order: -// Module(NSS/CS, DIO0, RESET, DIO1) -// SX1278 radio = new Module(10, 2, 9, 3); - -// create the node instance on the EU-868 band -// using the radio module and the encryption key -// make sure you are using the correct band -// based on your geographical location! -LoRaWANNode node(&radio, &EU868); - -// for fixed bands with subband selection -// such as US915 and AU915, you must specify -// the subband that matches the Frequency Plan -// that you selected on your LoRaWAN console -// LoRaWANNode node(&radio, &US915, 2); - void setup() { - Serial.begin(9600); - - // initialize radio (SX1262 / SX1278 / ... ) with default settings - Serial.print(F("[Radio] Initializing ... ")); - int state = radio.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // JoinEUI - previous versions of LoRaWAN this was AppEUI - // for development purposes you can use all zeros - see wiki for details - uint64_t joinEUI = 0x0000000000000000; - - // DevEUI - The device's Extended Unique Identifier - // TTN will generate one for you - uint64_t devEUI = 0x----------------; + Serial.begin(115200); + while (!Serial); // Wait for serial to be initalised + delay(2000); // Give time to switch to the serial monitor + Serial.println(F("\nSetup")); - // encryption keys used to secure the communication - // TTN will generate them for you - // see wiki for details on copying & pasting them - uint8_t nwkKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, - 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; - uint8_t appKey[] = { 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, - 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- }; + int16_t state = 0; // return value for calls to RadioLib + Serial.println(F("Initalise the radio")); + state = radio.begin(); + debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); // Override the default join rate - uint8_t joinDR = 3; - - // Begin the join to the network - Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDR); - if(state >= RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - delay(2000); // small delay between joining and uplink - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } + // uint8_t joinDR = 3; + Serial.println(F("Join ('login') to the LoRaWAN Network")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); + debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true); + + // Print the DevAddr Serial.print("[LoRaWAN] DevAddr: "); Serial.println(node.getDevAddr(), HEX); - // disable the ADR algorithm (on by default which is preferable) + // Disable the ADR algorithm (on by default which is preferable) node.setADR(false); - // set a fixed datarate & make it persistent (not normal) - node.setDatarate(5, true); + // Set a fixed datarate & make it persistent (not normal) + node.setDatarate(4); - // enable CSMA which tries to minimize packet loss by searching + // Enable CSMA which tries to minimize packet loss by searching // for a free channel before actually sending an uplink node.setCSMA(6, 2, true); - // manages uplink intervals to the TTN Fair Use Policy - node.setDutyCycle(true, 1250); + // Manages uplink intervals to the TTN Fair Use Policy + node.setDutyCycle(true, 1250); - // enable the dwell time limits - 400ms is the limit for the US + // Enable the dwell time limits - 400ms is the limit for the US node.setDwellTime(true, 400); + Serial.println(F("Ready!\n")); } // setup @@ -135,48 +90,46 @@ void loop() { uint8_t battLevel = 146; node.setDeviceStatus(battLevel); - // retrieve the last uplink frame counter - uint32_t fcntUp = node.getFcntUp(); - Serial.print(F("[LoRaWAN] Sending uplink packet #")); - Serial.println(fcntUp); - String strUp = "Hello! " + String(fcntUp); + // Read some inputs + uint8_t Digital1 = digitalRead(2); + uint16_t Analog1 = analogRead(A0); + + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = Digital1; + uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(Analog1); + + uint8_t downlinkPayload[10]; // Make sure this fits your plans! + size_t downlinkSize; // To hold the actual payload size rec'd + + // you can also retrieve additional information about an uplink or + // downlink by passing a reference to LoRaWANEvent_t structure + LoRaWANEvent_t uplinkDetails; + LoRaWANEvent_t downlinkDetails; - // send a confirmed uplink to port 10 every 64th frame + uint8_t Port = 10; + + // Retrieve the last uplink frame counter + uint32_t fcntUp = node.getFcntUp(); + // Send a confirmed uplink every 64th frame // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { - Serial.print(F("[LoRaWAN] Requesting LinkCheck and DeviceTime")); + Serial.println(F("[LoRaWAN] Requesting LinkCheck and DeviceTime")); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); - state = node.uplink(strUp, 10, true); + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails); } else { - state = node.uplink(strUp, 10); + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize); } - if(state != RADIOLIB_ERR_NONE) { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // after uplink, you must call downlink() to receive any possible reply - // from the server. This function must be called before the Rx1 delay - // for the network. Typically this is 5s after end of uplink. - Serial.println(F("[LoRaWAN] Waiting for downlink ... ")); - String strDown; + debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); - // you can also retrieve additional information about an uplink or - // downlink by passing a reference to LoRaWANEvent_t structure - LoRaWANEvent_t downlinkDetails; - state = node.downlink(strDown, &downlinkDetails); if(state == RADIOLIB_ERR_NONE) { - // print data of the packet - Serial.print(F("[LoRaWAN] Data:\t\t")); - if(strDown.length() > 0) { - for (uint8_t c = 0; c < strDown.length(); c++) { - uint8_t value = strDown[c]; - if (value < 10) Serial.print(F("0")); - Serial.print(value, HEX); - } - Serial.println(); + // Did we get a downlink with data for us + if (downlinkSize > 0) { + Serial.println(F("Downlink data: ")); + arrayDump(downlinkPayload, downlinkSize); } else { Serial.println(F("")); } @@ -233,20 +186,10 @@ void loop() { Serial.println(fracSecond); } - } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - // Not really necessary to report normal operation - - } else { - Serial.print(F("failed, code ")); - Serial.println(state); } - // on boards that can save to Flash or EEPROM this saves the session - // which allows recall of the session after reboot or deepsleep - node.saveSession(); - // wait before sending another packet - uint32_t minimumDelay = 3 * 60 * 1000; // try to send once every 3 minutes + uint32_t minimumDelay = uplinkIntervalSeconds * 1000UL; uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per FUP & law!) uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows diff --git a/examples/LoRaWAN/Starter/Starter.ino b/examples/LoRaWAN/Starter/Starter.ino deleted file mode 100644 index ced6020ffd..0000000000 --- a/examples/LoRaWAN/Starter/Starter.ino +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#include "config.h" - -void setup() { - Serial.begin(115200); - while (!Serial); - Serial.println(F("\nSetup ... ")); - - Serial.println(F("Initalise the radio")); - int state = radio.begin(); - debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); - - Serial.println(F("Join ('login') to the LoRaWAN Network")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); - debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true); - - Serial.println(F("Ready!\n")); -} - - -void loop() { - Serial.println(F("Sending uplink")); - - // Read some inputs - uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(A0); - - // Build payload byte array - uint8_t uplinkPayload[3]; - uplinkPayload[0] = Digital1; - uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions - uplinkPayload[2] = lowByte(Analog1); - - // Perform an uplink - int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); - debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); - - // Wait until next uplink - observing legal & TTN FUP constraints - delay(uplinkInterval); -} diff --git a/examples/LoRaWAN/Starter/config.h b/examples/LoRaWAN/Starter/config.h deleted file mode 100644 index bc50acf65a..0000000000 --- a/examples/LoRaWAN/Starter/config.h +++ /dev/null @@ -1,85 +0,0 @@ - -#include - -// How often to send an uplink - consider legal & FUP constraints - see notes -uint32_t uplinkInterval = 3 * 60 * 1000; // minutes x seconds x milliseconds - -uint64_t joinEUI = 0x0000000000000000; -uint64_t devEUI = 0x0000000000000000; -uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -uint8_t nwkKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - - -// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 -const LoRaWANBand_t Region = EU868; -const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 - - -// ============================================================================ -// Below is to support the sketch - only make changes if the notes say so ... - -// Auto select MCU <-> radio connections -// If you get an error message when compiling, it may be that the -// pinmap could not be determined - see the notes for more info - -#if defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("TTGO LoRa32 v1 - no Display") - SX1276 radio = new Module(18, 26, 14, 33); - -// #elif defined(ARDUINO_TTGO_LORA32_V2) -// #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") - -#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1276 radio = new Module(18, 26, 14, 33); - -// #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) -// #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") - -// #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) -// #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") -// SX1276 radio = new Module(18, 26, 23, 33); - -// #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) -// #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") - -#elif defined(ARDUINO_heltec_wifi_kit_32_V2) - #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined(ARDUINO_heltec_wifi_kit_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") - SX1262 radio = new Module(8, 14, 12, 13); - -// #elif defined(ARDUINO_CUBECELL_BOARD) -// #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") -// SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); - -// #elif defined(ARDUINO_CUBECELL_BOARD_V2) -// #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") - -#elif defined(ARDUINO_SAMD_FEATHER_M0) - #pragma message ("Adafruit Feather M0 with RFM95") - #pragma message ("Link required on board") - SX1276 radio = new Module(8, 3, 4, 6); - -#else - #pragma message ("Unknown board - no pinmap") - SX1262 radio = new Module(8, 14, 12, 13); - -#endif - -LoRaWANNode node(&radio, &Region, subBand); - - -// Helper function to display any issues -void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { - if (isFail) { - Serial.print(message); - Serial.print("("); - Serial.print(state); - Serial.println(")"); - while (Freeze); - } -} diff --git a/examples/LoRaWAN/Starter/notes.md b/examples/LoRaWAN/Starter/notes.md deleted file mode 100644 index 4f56a617a9..0000000000 --- a/examples/LoRaWAN/Starter/notes.md +++ /dev/null @@ -1,202 +0,0 @@ - - -# RadioLib LoRaWAN on TTN starter script - -## Welcome - -These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C coding ninja but some familarity with C and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration. - - -## Introduction - -LoRaWAN is an amazing system for small battery powered sensors collecting data for years at a time. With great features comes some more complex elements which means it is not quite as simple as just providing WiFi credentials and pushing data through. It is in the range of setting up & customising the settings for a home router but with no wizards to do the heavy lifting for you. So we strongly recommend spending a couple of hours reviewing the TTN Getting Started section so you are aware of the minimum knowledge to make a successful start: https://www.thethingsnetwork.org/docs/lorawan/. Johan's video is amazing but is also drinking from the firehose. Read the text first and then watch the video on Youtube where there are bookmarks to deliver it in small digestable chunks. - -These notes plus a lot more are available in the wiki: https://github.com/jgromes/RadioLib/wiki/LoRaWAN - -For questions about using RadioLib there is the discussions section (https://github.com/jgromes/RadioLib/discussions) and if you believe you've found an issue (aka bug), the issues section (https://github.com/jgromes/RadioLib/issues). If posting an issue please ensure you tell us what hardware you are using and provide a debug log - please do not use verbose mode unless asked to. If the question is more LoRaWAN or firmware related, then you can use the TTN forum: https://www.thethingsnetwork.org/forum/ - - -## Register & setup on TTN - -This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Helium does not support LoRaWAN v1.1 which is the version implemented by RadioLib. Chirpstack & other LoRaWAN Network Server (LNS) stacks have not yet been tried so YMMV. - -Why no screen shots? TTS is a web based app, one that you will need to become familiar with and we will need to direct you to some of the less obvious parts. So much better that you learn the layouts in concept than slavishly follow screen shots that can & will go stale. - -There will be some instructions that you have to take on face value. You didn't learn to run before you walked and it's so much more encouraging to get started and build on success than get bogged down in endless details. Once you are up & running more of the details start to slot in to place. - -### Register on TTN - -Go to https://www.thethingsnetwork.org/get-started and register - just like any other website. These instructions are for TTS Sandbox. - -Once you have confirmed your email address, you can login to the console here: https://console.cloud.thethings.network/. If you allow your browser to share you location the best console will be selected. For most users the best one is the obvious one, if you have any doubts you can ask on the forum here: https://www.thethingsnetwork.org/forum/ - you login with the exact same details. - -It is simpler to register your gateway first. If you don't have a gateway, then a The Things Indoor Gateway (TTIG) is a very affordable option. A gateway gives you a console to see if your device is being heard and is hugely useful when debugging a DIY device. If you are in range of a community gateway you may be lucky with your first device creation but you will never know if you are in range unless you have access to that gateways console. - -You can read up on key concepts and troubleshooting here: https://www.thethingsindustries.com/docs/gateways/ - -LoRa stands for Long Range - having the gateway & device on the same desk tends to overload both receiver circuits when they hear a transmission so close to hand. The gateway should be 5 - 10m away, preferably with a solid wall in the way as well. - -### Create your application - -An application is like a box to keep some devices in - normally doing the same thing - on larger deployments this may be 1,000's of similar devices. Starting out it it is likely to be just a few so there is no need to get concerned about how to divide up your use just yet. - -Onced logged in to the console you can go in to Applications to create your first application. The ID must be all lower case or numbers, no spaces, dashes are OK and it has to be unique to the entire TTN community - so `first-app` will be rejected - you could use `your-username-first-app` as that's likely to be unique. The name and description are for your own use and are optional. - -The main menu for an application is in the left hand panel - nothing is needed there just yet. - -### Create your device - -On the right hand side about half way down on your application's summary is a big blue button `+ Register end device`. Click this to create the settings for your first device. - -You are making your own device using a third party LoRaWAN stack so there will not be an entry in the device repository so choose 'Enter end device specifics manually'. - -Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'. - -Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B. - -At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the cosole generate them so they are properly formatted. - -Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like devicename-01. The you can click the blue 'Register device'. - -When many sensors are big deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do. - -Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the Resets join nonces option. You will see a warning about replay attacks which is entirely proper & correct. If anyone evesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password. - -You then need to copy over the device details in to the config file for RadioLib. There are buttons to copy items to the clipboard so you don't have to hand type them. - -### Copy & Paste made easy - -You can copy the EUIs & keys from the device overview section. - -The EUIs are really straightforward - click the clipboard icon at the right hand end of the EUI display field and it will be copied in the format you need. You can then paste it in to the code - you must leave the 0x in place so the compiler knows that it's a hex value. - -The keys are relatively straightforward. Click the eye icon at the right hand end of the field. Then click the <> icon that will appear to the left. This will format the hex values as an array. Then you can click the clipboard icon to copy the array and then paste it between the { } brackets. - -### Secrets to keep safe. - -The Join & Dev EUI's are transmitted in plain text when the device joins a network. The gateway ID is public. If you have an issue and are asked for details, there are only three things to keep private - your password, the keys which are used for encryption and any API keys you create which are used for accessing your data & configuration. - - -### Monitoring your device - -If you are on your application summary page you'll see uplinks in the small activity box top right with a link to the full size table. If you click the Live Data menu item on the left it will show activity for all the devices registered on the application in the full window. - -If you just want your devices activity, from the summary page click on the device in the list in the middle of the page. - -The main menu for a device is the horizontal band: Overview, Live Data, Messaging etc. You can click Live Data or the link above the small activity box. - -**The console shows LIVE data - not a history of everything that has ever happened. A LNS is a management & relay service, not a database. When you open the console you may see a summary of recent activity - this is a bonus. You must leave the console open, even in another tab, if you want to see live activity.** - - -### Explore - -Nothing on the console can be upset unless you confirm a warning message, so you are safe to explore the different menus to orientate yourself. This is very good idea so you are have an understanding of the layout of the land and shouldn't take more than 10 or 15 minutes. The documentation & volunteers on GitHub and the TTN forum will make refer to parts of the console without giving blow by blow directions. - - - - -## The config.h - -### The uplinkInterval - -LoRaWAN devices typically send small amounts of data at intervals between 15 minutes through to once per day. This allows a device to run on two AA batteries for 2 to 5 years. Hoping that LoRaWAN can move lots of data and your device can regularly receive commands to do something on demand is trying to bend the LoRaWAN system in ways it is not designed for and usually ends up with far too many issues to unravel. - -The radio frequencies that are used are usually shared with other Industrial, Scientific & Medical, known as ISM, users. The LoRa modulation is particularly resistance to interference due to other simultaneous transmissions on the same frequency but too much local activity will mean that not all uplinks get through. The Things Industries suggest designing a system to a potential packet loss rate of 10%. Typically we see 1 or 2% loss. This is entirely down to shared use of the radio waves, once an uplink is heard by a gateway the system is super reliable through The Things Stack. - -To ensure that the shared ISM bands are fairly used there are limits defined in law on how often you can transmit, called Duty Cycle. The details vary by region or country but typically you can only transmit for 1% of the time. Some frequencies you can only use 0.1% of the time. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/ for more information. - -Additionally, as The Things Stack Sandbox aka TTN is an array of servers in three locations around the world paid for by The Things Industries, there is a Fair Use Policy so that those learning LoRaWAN, communities, hobbyists & makers are guided on how much of the resource any one device can use. In short, it's 30 seconds of airtime a day and 10 downlinks. When a gateway is transmitting a downlink it can not hear any uplinks (contributing to the potential uplink loss outlined above). The community concensus is that 1 downlink a fortnight to update or adjust settings is appropriate. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/#fair-use-policy for more information. - -You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. A uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so - -With all thes considerations, trying to use LoRaWAN for command & control isn't appropriate and realtime GPS tracking almost always breaches FUP and usually legal limits, leaving aside the challenges of coverage. - -See the hints & tips section on testing your device. - - -### EUI's & Keys - -In the config.h towards the top there are four lines thus: - -// replace-with-your-device-id -uint64_t joinEUI = 0x0000000000000000; -uint64_t devEUI = 0x0000000000000000; -uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -uint8_t nwkKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -On the TTN console on the device summary page, click the clipboard icon next to the DevEUI, highlight the 16 0's in the third line after the x and paste. - -The devEUI must start with 0x and will end up looking something like 0x70B3D57ED006544E - -For the appKey we need TTN to format it correctly. Click the eye icon and an extra icon will appear <> - click this and the key will be formatted for you. Click the clipboard icon and then paste over the 32 0x00's in the config file. Then do the same for nwkKey. - -A key will end up something like 0x31, 0x16, 0x6A, 0x22, 0x97, 0x52, 0xB6, 0x34, 0x57, 0x45, 0x1B, 0xC3, 0xC9, 0xD8, 0x83, 0xE8 - - -### Region - -The region value you use MUST match the one you selected on the console. - -If you are using US915 or AU915 then you should change the subBand const to 2. - -### The pinmap - -This is the connections between the MCU (ESP32/ATmega/SAMD) and the LoRa radio (SX1276/SX1262). - -Prebuilt modules are easy - we can detect the board and setup the pinmap for you. These boards are: - -* TTGO_LoRa32 -* TTGO_LoRa32_V1 -* TTGO_LORA32_V2 -* TTGO_LORA32_v21NEW -* HELTEC_WIFI_LORA_32 -* HELTEC_WIFI_LORA_32_V2 -* HELTEC_WIFI_LORA_32_V3 -* CUBECELL_BOARD - -If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu. - -* TBEAM_USE_RADIO_SX1262 -* TBEAM_USE_RADIO_SX1276 - -If you have an Adafruit Feather M0 with RFM95 then you must solder a wire or use a jumper to link from pin 6 to io1: https://learn.adafruit.com/the-things-network-for-feather/arduino-wiring - - -If you have a module that's not on this list, please go to the "Pinmap How-To" below. - - - -## Observations on the main sketch - -Most of the sketch has comments that tell you what the various parts are doing. This should add a little more info: - -### The Join - -When a device is first started, it needs to register with the LoRaWAN Network Server (LNS) and setup it's session. With the settings from the console copied over and a gateway an appropriate distance away, most of the time the join will 'just work'. - -If it doesn't, then there is no point trying repeatedly without going through the troubleshootng sequence. So this starter sketch will try once only to save the airwaves & TTN Community servers from repeated misfires. - - -### The payload - -You may see other starter sketches sending text. Apart from being massively inefficient, the text isn't easily displayed on the TTN console which makes it rather pointless and pro embedded engineers don't send strings. So this sketch sends the data as a sequence of bytes as recommended. - -Further reading on this can be found here, just ignore the pink message about v2, it's all still valid: https://www.thethingsnetwork.org/docs/devices/bytes/ - -We've not assumed anything about any sensors you have, so we are just reading a digital & an analog pin. An analog reading is typically a two byte value - an integer - this is split using the Arduino highByte & lowByte function. You'll see how we put it back together in the TTN console below. - - -## TTN Console Payload Decoder - -Coming soon - -## Hints & Tips - -### Device testing - -The LoRaWAN code base works to a specification and once you are happy your device is able to join & send a few dozen uplinks, continuing to sit around waiting for an uplink to test your sensor code & payload format is a waste of your time. The solution is to write everything else in a different sketch, output the array to the serial console and then you can copy & paste the hex array in to the TTN console Payload Formatters section to test the decoding. - - -## Pinmap How-To - - From c0ebd5a92e6b3ad8d007b6a01276753d35d16bd0 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Mon, 25 Mar 2024 11:55:29 +0000 Subject: [PATCH 0946/1848] Header comments & ABP --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 192 ++++------------- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 37 ++-- .../LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino | 196 ------------------ examples/LoRaWAN/LoRaWAN_ESP32/config.h | 130 ------------ .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 5 +- .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 25 ++- 6 files changed, 87 insertions(+), 498 deletions(-) delete mode 100644 examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino delete mode 100644 examples/LoRaWAN/LoRaWAN_ESP32/config.h diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 02089e4bca..c31da1ec48 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -1,178 +1,68 @@ /* - RadioLib LoRaWAN End Device ABP Example + RadioLib LoRaWAN ABP Example - This example sets up a LoRaWAN node using ABP (activation - by personalization). Before you start, you will have to + ABP = Activation by Personalisation, an alternative + to OTAA (Over the Air Activation). OTAA is preferable. + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to register your device at https://www.thethingsnetwork.org/ After your device is registered, you can run this example. - The device will start uploading data directly, - without having to join the network. + The device will join the network and start uploading data. + + LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + Running this examples REQUIRES you to check "Resets frame counters" + on your LoRaWAN dashboard. Refer to the network's documentation + on how to do this. - NOTE: LoRaWAN v1.1 requires storing parameters persistently! - RadioLib does this by using EEPROM (persistent storage), - by default starting at address 0 and using 448 bytes. - If you already use EEPROM in your application, - you will have to either avoid this range, or change it - by setting a different start address by changing the value of - RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either - during build or in src/BuildOpt.h. - For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// SX1262 has the following pin order: -// Module(NSS/CS, DIO1, RESET, BUSY) -// SX1262 radio = new Module(8, 14, 12, 13); - -// SX1278 has the following pin order: -// Module(NSS/CS, DIO0, RESET, DIO1) -SX1278 radio = new Module(10, 2, 9, 3); -// create the node instance on the EU-868 band -// using the radio module and the encryption key -// make sure you are using the correct band -// based on your geographical location! -LoRaWANNode node(&radio, &EU868); + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN -// for fixed bands with subband selection -// such as US915 and AU915, you must specify -// the subband that matches the Frequency Plan -// that you selected on your LoRaWAN console -/* - LoRaWANNode node(&radio, &US915, 2); */ +#include "configABP.h" + void setup() { - Serial.begin(9600); + Serial.begin(115200); + while (!Serial); + delay(5000); // Give time to switch to the serial monitor + Serial.println(F("\nSetup ... ")); - // initialize radio (SX1262 / SX1278 / ... ) with default settings - Serial.print(F("[Radio] Initializing ... ")); + Serial.println(F("Initalise the radio")); int state = radio.begin(); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } - - // device address - this number can be anything - // when adding new end device in TTN, you can generate this number, - // or you can set any value you want, provided it is unique - uint32_t devAddr = 0x12345678; - - // select some encryption keys which will be used to secure the communication - // there are two of them - network key and application key - // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long - - // network key is the ASCII string "topSecretKey1234" - uint8_t nwkSKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; - - // application key is the ASCII string "aDifferentKeyABC" - uint8_t appSKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; - - // network key 2 is the ASCII string "topSecretKey5678" - uint8_t fNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x74, 0x4B, 0x65, 0x35, 0x36, 0x37, 0x38 }; - - // network key 3 is the ASCII string "aDifferentKeyDEF" - uint8_t sNwkSIntKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x44, 0x45, 0x46 }; - - // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used - // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded - // and can be set to NULL - - - // if using EU868 on ABP in TTN, you need to set the SF for RX2 window manually - /* - node.rx2.drMax = 3; - */ - - // on EEPROM-enabled boards, after the device has been activated, - // the session can be restored without rejoining after device power cycle - // this is intrinsically done when calling `beginABP()` with the same keys - // in that case, the function will not need to transmit a JoinRequest - - // to start a LoRaWAN v1.0 session, - // the user can remove the fNwkSIntKey and sNwkSIntKey - /* - state = node.beginABP(devAddr, nwkSKey, appSKey); - */ - - // start the device by directly providing the encryption keys and device address - Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); - state = node.beginABP(devAddr, nwkSKey, appSKey, fNwkSIntKey, sNwkSIntKey); - if(state >= RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while(true); - } + debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + + Serial.println(F("Initalise LoRaWAN Network credentials")); + state = node.beginABP(devAddr, NwkSEncKey, AppSKey, NwkSKey, SNwkSIntKey, true); + debug(state < RADIOLIB_ERR_NONE, F("Session setup failed"), state, true); + Serial.println(F("Ready!\n")); } -// counter to keep track of transmitted packets -int count = 0; void loop() { - // send uplink to port 10 - Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); - String strUp = "Hello!" + String(count++); - String strDown; - int state = node.sendReceive(strUp, 10, strDown); - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("received a downlink!")); - - // print data of the packet (if there are any) - Serial.print(F("[LoRaWAN] Data:\t\t")); - if(strDown.length() > 0) { - Serial.println(strDown); - } else { - Serial.println(F("")); - } - - // print RSSI (Received Signal Strength Indicator) - Serial.print(F("[LoRaWAN] RSSI:\t\t")); - Serial.print(radio.getRSSI()); - Serial.println(F(" dBm")); + Serial.println(F("Sending uplink")); - // print SNR (Signal-to-Noise Ratio) - Serial.print(F("[LoRaWAN] SNR:\t\t")); - Serial.print(radio.getSNR()); - Serial.println(F(" dB")); + // Read some inputs + uint8_t Digital1 = digitalRead(2); + uint16_t Analog1 = analogRead(A0); - // print frequency error - Serial.print(F("[LoRaWAN] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = Digital1; + uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(Analog1); - } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("no downlink!")); + // Perform an uplink + int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - } - - // on EEPROM enabled boards, you should save the current session - // by calling "saveSession" which allows retrieving the session after reboot or deepsleep - node.saveSession(); - - // wait before sending another packet - uint32_t minimumDelay = 60000; // try to send once every minute - uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!) - uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows - - delay(delayMs); + // Wait until next uplink - observing legal & TTN FUP constraints + delay(uplinkIntervalSeconds * 1000UL); } diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index bba38e4fe7..33fd9fa0d3 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -6,26 +6,29 @@ // How often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds -// JoinEUI - previous versions of LoRaWAN called this AppEUI -// for development purposes you can use all zeros - see wiki for details -#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 +// Device address - either a development address or one assigned +// to the LoRaWAN Service Provider - TTN will generate one for you +#ifndef RADIOLIB_LORAWAN_DEV_ADDR // Replace with your DevAddr +#define RADIOLIB_LORAWAN_DEV_ADDR 0x------ +#endif -// The Device EUI & two keys can be generated on the TTN console -#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI -#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#ifndef RADIOLIB_LORAWAN_NWKS_KEY // Replace with your NwkS Key +#define RADIOLIB_LORAWAN_NWKS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key +#define RADIOLIB_LORAWAN_SNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif -#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key -#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#ifndef RADIOLIB_LORAWAN_NWKSENC_KEY // Replace with your NwkSEnc Key +#define RADIOLIB_LORAWAN_NWKSENC_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif -#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here -#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#ifndef RADIOLIB_LORAWAN_APPS_KEY // Replace with your AppS Key +#define RADIOLIB_LORAWAN_APPS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif // For the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips - // Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 @@ -97,11 +100,13 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #endif -// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted -uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; -uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; -uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; -uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; +// Copy over the keys in to the something that will not compile if incorrectly formatted +uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR; +uint8_t NwkSKey[] = { RADIOLIB_LORAWAN_NWKS_KEY }; +uint8_t SNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // Previously sNwkSIntKey +uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey +uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; + // Create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); diff --git a/examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino b/examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino deleted file mode 100644 index f2d567bbd3..0000000000 --- a/examples/LoRaWAN/LoRaWAN_ESP32/LoRaWAN_ESP32.ino +++ /dev/null @@ -1,196 +0,0 @@ - -/* - -This demonstrates how to save the join information in to permanent memory -so that if the power fails, batteries run out or are changed, the rejoin -is more efficient & happens sooner due to the way that LoRaWAN secures -the join process - see the wiki for more details. - -This is typically useful for devices that need more power than a battery -driven sensor - something like a air quality monitor or GPS based device that -is likely to use up it's power source resulting in loss of the session. - -The relevant code is flagged with a ##### comment - -Saving the entire session is possible but not demonstrated here - it has -implications for flash wearing and complications with which parts of the -session may have changed after an uplink. So it is assumed that the device -is going in to deep-sleep, as below, between normal uplinks. - -*/ - -#if !defined(ESP32) - #pragma error ("This is not the example your device is looking for - ESP32 only") -#endif - -// ##### Load the ESP32 preferences facilites -#include -Preferences store; - -// LoRaWAN config, credentials & pinmap -#include "config.h" - -#include - -// Utilities & vars to support ESP32 deep-sleep. The RTC_DATA_ATTR attribute -// puts these in to the RTC memory which is preserved during deep-sleep -RTC_DATA_ATTR uint16_t bootCount = 1; -RTC_DATA_ATTR uint16_t bootCountSinceUnsuccessfulJoin = 0; -RTC_DATA_ATTR uint8_t LWsession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE]; - -// Abbreviated version from the Arduino-ESP32 package, see -// https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/deepsleep.html -// for the complete set of options -void print_wakeup_reason() { - esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); - if (wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) { - Serial.println(F("Wake from sleep")); - } else { - Serial.print(F("Wake not caused by deep sleep: ")); - Serial.println(wakeup_reason); - } - - Serial.print(F("Boot count: ")); - Serial.println(bootCount++); -} - -// Put device in to lowest power deep-sleep mode -void gotoSleep(uint32_t seconds) { - esp_sleep_enable_timer_wakeup(seconds * 1000UL * 1000UL); // Function uses uS - Serial.println(F("Sleeping\n")); - Serial.flush(); - - esp_deep_sleep_start(); - - // If this appears in the serial debug, we didn't go to sleep! - // So take defensive action so we don't continually uplink - Serial.println(F("\n\n### Sleep failed, delay of 5 minutes & then restart ###\n")); - delay(5UL * 60UL * 1000UL); - ESP.restart(); -} - - - -// Setup & execute all device functions ... -void setup() { - Serial.begin(115200); - while (!Serial); // Wait for serial to be initalised - delay(2000); // Give time to switch to the serial monitor - Serial.println(F("\nSetup")); - print_wakeup_reason(); - - int16_t state = 0; // return value for calls to RadioLib - - // Setup the radio based on the pinmap (connections) in config.h - Serial.println(F("Initalise the radio")); - state = radio.begin(); - debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); - - Serial.println(F("Recalling LoRaWAN nonces & session")); - // ##### Setup the flash storage - store.begin("radiolib"); - // ##### If we have previously saved nonces, restore them - if (store.isKey("nonces")) { - uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE];// Create somewhere to store nonces - store.getBytes("nonces", buffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);// Get them to the store - state = node.setBufferNonces(buffer); // Send them to LoRaWAN - debug(state != RADIOLIB_ERR_NONE, F("Restoring nonces buffer failed"), state, false); - } - - // Recall session from RTC deep-sleep preserved variable - state = node.setBufferSession(LWsession); // Send them to LoRaWAN stack - // If we have booted at least once we should have a session to restore, so report any failure - // Otherwise no point saying there's been a failure when it was bound to fail with an empty - // LWsession var. At this point, bootCount has already been incremented, hence the > 2 - debug((state != RADIOLIB_ERR_NONE) && (bootCount > 2), F("Restoring session buffer failed"), state, false); - - // Process the restored session or failing that, create a new one & - // return flag to indicate a fresh join is required - Serial.println(F("Setup LoRaWAN session")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, false); - // See comment above, no need to report a failure that is bound to occur on first boot - debug((state != RADIOLIB_ERR_NONE) && (bootCount > 2), F("Restore session failed"), state, false); - - // Loop until successful join - while (state != RADIOLIB_ERR_NONE) { - Serial.println(F("Join ('login') to the LoRaWAN Network")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); - - if (state < RADIOLIB_ERR_NONE) { - Serial.print(F("Join failed: ")); - Serial.println(state); - - // How long to wait before join attenpts. This is an interim solution pending - // implementation of TS001 LoRaWAN Specification section #7 - this doc applies to v1.0.4 & v1.1 - // It sleeps for longer & longer durations to give time for any gateway issues to resolve - // or whatever is interfering with the device <-> gateway airwaves. - uint32_t sleepForSeconds = min((bootCountSinceUnsuccessfulJoin++ + 1UL) * 60UL, 3UL * 60UL); - Serial.print(F("Boots since unsuccessful join: ")); - Serial.println(bootCountSinceUnsuccessfulJoin); - Serial.print(F("Retrying join in ")); - Serial.print(sleepForSeconds); - Serial.println(F(" seconds")); - - gotoSleep(sleepForSeconds); - - } else { // Join was successful - Serial.println(F("Joined")); - - // ##### Save the join counters (nonces) to permanent store - Serial.println(F("Saving nonces to flash")); - uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE]; // Create somewhere to store nonces - uint8_t *persist = node.getBufferNonces(); // Get pointer to nonces - memcpy(buffer, persist, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // Copy in to buffer - store.putBytes("nonces", buffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); // Send them to the store - - // We'll save the session after the uplink - - // Reset the failed join count - bootCountSinceUnsuccessfulJoin = 0; - - delay(1000); // Hold off off hitting the airwaves again too soon - an issue in the US - - } // if beginOTAA state - } // while join - - // ##### Close the store - store.end(); - - - // ----- And now for the main event ----- - Serial.println(F("Sending uplink")); - - // Read some inputs - uint8_t Digital2 = digitalRead(2); - uint16_t Analog1 = analogRead(A1); - - // Build payload byte array - uint8_t uplinkPayload[3]; - uplinkPayload[0] = Digital2; - uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions - uplinkPayload[2] = lowByte(Analog1); - - // Perform an uplink - state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); - debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); - - Serial.print(F("FcntUp: ")); - Serial.println(node.getFcntUp()); - - // Now save session to RTC memory - uint8_t *persist = node.getBufferSession(); - memcpy(LWsession, persist, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); - - // Wait until next uplink - observing legal & TTN FUP constraints - gotoSleep(uplinkIntervalSeconds); - -} - - -// The ESP32 wakes from deep-sleep and starts from the very beginning -// which is a very good place to start, as any singing nun knows. -// It then goes back to sleep, so loop() is never called and which is -// why it is empty. - -void loop() {} - diff --git a/examples/LoRaWAN/LoRaWAN_ESP32/config.h b/examples/LoRaWAN/LoRaWAN_ESP32/config.h deleted file mode 100644 index bba38e4fe7..0000000000 --- a/examples/LoRaWAN/LoRaWAN_ESP32/config.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef _CONFIG_H -#define _CONFIG_H - -#include - -// How often to send an uplink - consider legal & FUP constraints - see notes -const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds - -// JoinEUI - previous versions of LoRaWAN called this AppEUI -// for development purposes you can use all zeros - see wiki for details -#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 - -// The Device EUI & two keys can be generated on the TTN console -#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI -#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- -#endif -#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key -#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- -#endif -#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here -#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- -#endif - -// For the curious, the #ifndef blocks allow for automated testing &/or you can -// put your EUI & keys in to your platformio.ini - see wiki for more tips - - - -// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 -const LoRaWANBand_t Region = EU868; -const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 - - -// ============================================================================ -// Below is to support the sketch - only make changes if the notes say so ... - -// Auto select MCU <-> radio connections -// If you get an error message when compiling, it may be that the -// pinmap could not be determined - see the notes for more info - -// Adafruit -#if defined(ARDUINO_SAMD_FEATHER_M0) - #pragma message ("Adafruit Feather M0 with RFM95") - #pragma message ("Link required on board") - SX1276 radio = new Module(8, 3, 4, 6); - - -// LilyGo -#elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("TTGO LoRa32 v1 - no Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") - -#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) - #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1276 radio = new Module(18, 26, 23, 33); - - -// Heltec -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") - -#elif defined(ARDUINO_heltec_wifi_kit_32_V2) - #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined(ARDUINO_heltec_wifi_kit_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") - SX1262 radio = new Module(8, 14, 12, 13); - -#elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); - -#elif defined(ARDUINO_CUBECELL_BOARD_V2) - #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") - - -#else - #pragma message ("Unknown board - no automagic pinmap available") - - // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); - // SX1262 radio = new Module(8, 14, 12, 13); - - // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); - // SX1278 radio = new Module(10, 2, 9, 3); - -#endif - - -// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted -uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; -uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; -uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; -uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; - -// Create the LoRaWAN node -LoRaWANNode node(&radio, &Region, subBand); - - -// Helper function to display any issues -void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { - if (isFail) { - Serial.print(message); - Serial.print("("); - Serial.print(state); - Serial.println(")"); - while (Freeze); - } -} - -// Helper function to display a byte array -void arrayDump(uint8_t *buffer, uint16_t len) { - for (uint16_t c; c < len; c++) { - Serial.printf("%02X", buffer[c]); - } - Serial.println(); -} - - -#endif diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 5df3114e8d..0d9b15eec0 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -11,8 +11,6 @@ shown here for reference. LoRaWAN v1.1 requires the use of EEPROM (persistent storage). - Please refer to the 'persistent' example once you are familiar - with LoRaWAN. Running this examples REQUIRES you to check "Resets DevNonces" on your LoRaWAN dashboard. Refer to the network's documentation on how to do this. @@ -26,7 +24,6 @@ For LoRaWAN details, see the wiki page https://github.com/jgromes/RadioLib/wiki/LoRaWAN - */ #include "config.h" @@ -38,7 +35,7 @@ void setup() { Serial.begin(115200); while (!Serial); // Wait for serial to be initalised - delay(2000); // Give time to switch to the serial monitor + delay(5000); // Give time to switch to the serial monitor Serial.println(F("\nSetup")); int16_t state = 0; // return value for calls to RadioLib diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 4ccc372ec8..30d15c1525 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -1,10 +1,33 @@ -#include +/* + RadioLib LoRaWAN Starter Example + + This example joins a LoRaWAN network and will send + uplink packets. Before you start, you will have to + register your device at https://www.thethingsnetwork.org/ + After your device is registered, you can run this example. + The device will join the network and start uploading data. + + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN + +*/ #include "config.h" void setup() { Serial.begin(115200); while (!Serial); + delay(5000); // Give time to switch to the serial monitor Serial.println(F("\nSetup ... ")); Serial.println(F("Initalise the radio")); From 18c1ce47b4ffe4a31ff6dd0044a5afd3110594ee Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:41:04 +0100 Subject: [PATCH 0947/1848] Improve introductory comments in LoRaWAN ABP example --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index c31da1ec48..ec27df6310 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -4,16 +4,19 @@ ABP = Activation by Personalisation, an alternative to OTAA (Over the Air Activation). OTAA is preferable. - This example joins a LoRaWAN network and will send - uplink packets. Before you start, you will have to - register your device at https://www.thethingsnetwork.org/ + This example will send uplink packets to a LoRaWAN network. + Before you start, you will have to register your device at + https://www.thethingsnetwork.org/ After your device is registered, you can run this example. The device will join the network and start uploading data. - LoRaWAN v1.1 requires the use of EEPROM (persistent storage). - Running this examples REQUIRES you to check "Resets frame counters" - on your LoRaWAN dashboard. Refer to the network's documentation - on how to do this. + LoRaWAN v1.1 requires the use of persistent storage. + As this example does not use persistent storage, running this + examples REQUIRES you to check "Resets frame counters" + on your LoRaWAN dashboard. Refer to the notes or the + network's documentation on how to do this. + To comply with LoRaWAN v1.1's persistent storage, refer to + https://github.com/radiolib-org/radiolib-persistence For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration From d1b911b2736df60bdf6825691ad3d6b321745772 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:42:52 +0100 Subject: [PATCH 0948/1848] Add link to persistence repository in LoRaWAN Reference example --- examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 0d9b15eec0..770b47956f 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -12,8 +12,10 @@ LoRaWAN v1.1 requires the use of EEPROM (persistent storage). Running this examples REQUIRES you to check "Resets DevNonces" - on your LoRaWAN dashboard. Refer to the network's - documentation on how to do this. + on your LoRaWAN dashboard. Refer to the notes or the + network's documentation on how to do this. + To comply with LoRaWAN v1.1's persistent storage, refer to + https://github.com/radiolib-org/radiolib-persistence For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration @@ -196,4 +198,4 @@ void loop() { delay(delayMs); -} // loop \ No newline at end of file +} // loop From 2f1efdb8a0536949476d3e1a6a0aa63d0261cb34 Mon Sep 17 00:00:00 2001 From: HeadBoffin <60431281+HeadBoffin@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:00:22 +0000 Subject: [PATCH 0949/1848] Create README.md --- examples/LoRaWAN/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/LoRaWAN/README.md diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/LoRaWAN/README.md @@ -0,0 +1 @@ + From 2d454bdc618a536d7efc1ea8e36afb113cce1329 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:05:54 +0100 Subject: [PATCH 0950/1848] Populate README with direct links to (persistence) examples --- examples/LoRaWAN/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index 8b13789179..a269810b3b 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -1 +1,18 @@ +# LoRaWAN examples +RadioLib LoRaWAN v1.1 examples. +* [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the `notes` that come with this example to learn more about LoRaWAN and how to use it in RadioLib! +* [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the `notes` for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)! +* [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib. + +--- + +All three of these examples do not fully comply with LoRaWAN v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: + +## RadioLib persistence +In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN v1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!** +Currently, examples are available for the following platforms: + +* [LoRaWAN for ESP32](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP32) + +_This list is last updated for RadioLib 6.5.0_ From 61b94bf4fcdb112b4b1fd78680c368aa329e9184 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:13:57 +0100 Subject: [PATCH 0951/1848] Fix typos in the LoRaWAN Starter notes --- examples/LoRaWAN/LoRaWAN_Starter/notes.md | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md index 4f56a617a9..9fdd6bd53c 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/notes.md +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -13,7 +13,7 @@ LoRaWAN is an amazing system for small battery powered sensors collecting data f These notes plus a lot more are available in the wiki: https://github.com/jgromes/RadioLib/wiki/LoRaWAN -For questions about using RadioLib there is the discussions section (https://github.com/jgromes/RadioLib/discussions) and if you believe you've found an issue (aka bug), the issues section (https://github.com/jgromes/RadioLib/issues). If posting an issue please ensure you tell us what hardware you are using and provide a debug log - please do not use verbose mode unless asked to. If the question is more LoRaWAN or firmware related, then you can use the TTN forum: https://www.thethingsnetwork.org/forum/ +For questions about using RadioLib there is the discussions section (https://github.com/jgromes/RadioLib/discussions) and if you believe you've found an issue (aka bug), the issues section (https://github.com/jgromes/RadioLib/issues). If posting an issue please ensure you tell us what hardware you are using and provide a debug log - make sure you enable `RADIOLIB_DEBUG_PROTOCOL`. If the question is more LoRaWAN or firmware related, then you can use the TTN forum: https://www.thethingsnetwork.org/forum/ ## Register & setup on TTN @@ -28,9 +28,9 @@ There will be some instructions that you have to take on face value. You didn't Go to https://www.thethingsnetwork.org/get-started and register - just like any other website. These instructions are for TTS Sandbox. -Once you have confirmed your email address, you can login to the console here: https://console.cloud.thethings.network/. If you allow your browser to share you location the best console will be selected. For most users the best one is the obvious one, if you have any doubts you can ask on the forum here: https://www.thethingsnetwork.org/forum/ - you login with the exact same details. +Once you have confirmed your email address, you can login to the console here: https://console.cloud.thethings.network/. If you allow your browser to share your location the best console will be selected. For most users the best one is the obvious one, if you have any doubts you can ask on the forum here: https://www.thethingsnetwork.org/forum/ - you login with the exact same details. -It is simpler to register your gateway first. If you don't have a gateway, then a The Things Indoor Gateway (TTIG) is a very affordable option. A gateway gives you a console to see if your device is being heard and is hugely useful when debugging a DIY device. If you are in range of a community gateway you may be lucky with your first device creation but you will never know if you are in range unless you have access to that gateways console. +It is simpler to register your gateway first. If you don't have a gateway, then a The Things Indoor Gateway (TTIG) is a very affordable option. A gateway gives you a console to see if your device is being heard and is hugely useful when debugging a DIY device. If you are in range of a community gateway you may be lucky with your first device creation but you will never know if you are in range unless you have access to that gateway's console. You can read up on key concepts and troubleshooting here: https://www.thethingsindustries.com/docs/gateways/ @@ -38,7 +38,7 @@ LoRa stands for Long Range - having the gateway & device on the same desk tends ### Create your application -An application is like a box to keep some devices in - normally doing the same thing - on larger deployments this may be 1,000's of similar devices. Starting out it it is likely to be just a few so there is no need to get concerned about how to divide up your use just yet. +An application is like a box to keep some devices in - normally doing the same thing - on larger deployments this may be 1,000's of similar devices. Starting out it is likely to be just a few so there is no need to get concerned about how to divide up your use just yet. Onced logged in to the console you can go in to Applications to create your first application. The ID must be all lower case or numbers, no spaces, dashes are OK and it has to be unique to the entire TTN community - so `first-app` will be rejected - you could use `your-username-first-app` as that's likely to be unique. The name and description are for your own use and are optional. @@ -52,15 +52,15 @@ You are making your own device using a third party LoRaWAN stack so there will n Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'. -Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B. +Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision A. -At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the cosole generate them so they are properly formatted. +At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the console generate them so they are properly formatted. Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like devicename-01. The you can click the blue 'Register device'. When many sensors are big deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do. -Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the Resets join nonces option. You will see a warning about replay attacks which is entirely proper & correct. If anyone evesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password. +Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the 'Resets join nonces' option. You will see a warning about replay attacks which is entirely proper & correct. If anyone eavesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password. You then need to copy over the device details in to the config file for RadioLib. There are buttons to copy items to the clipboard so you don't have to hand type them. @@ -90,7 +90,7 @@ The main menu for a device is the horizontal band: Overview, Live Data, Messagin ### Explore -Nothing on the console can be upset unless you confirm a warning message, so you are safe to explore the different menus to orientate yourself. This is very good idea so you are have an understanding of the layout of the land and shouldn't take more than 10 or 15 minutes. The documentation & volunteers on GitHub and the TTN forum will make refer to parts of the console without giving blow by blow directions. +Nothing on the console can be upset unless you confirm a warning message, so you are safe to explore the different menus to orientate yourself. This is very good idea so you have an understanding of the layout of the land and shouldn't take more than 10 or 15 minutes. The documentation & volunteers on GitHub and the TTN forum will make refer to parts of the console without giving blow by blow directions. @@ -101,22 +101,22 @@ Nothing on the console can be upset unless you confirm a warning message, so you LoRaWAN devices typically send small amounts of data at intervals between 15 minutes through to once per day. This allows a device to run on two AA batteries for 2 to 5 years. Hoping that LoRaWAN can move lots of data and your device can regularly receive commands to do something on demand is trying to bend the LoRaWAN system in ways it is not designed for and usually ends up with far too many issues to unravel. -The radio frequencies that are used are usually shared with other Industrial, Scientific & Medical, known as ISM, users. The LoRa modulation is particularly resistance to interference due to other simultaneous transmissions on the same frequency but too much local activity will mean that not all uplinks get through. The Things Industries suggest designing a system to a potential packet loss rate of 10%. Typically we see 1 or 2% loss. This is entirely down to shared use of the radio waves, once an uplink is heard by a gateway the system is super reliable through The Things Stack. +The radio frequencies that are used are usually shared with other Industrial, Scientific & Medical, known as ISM, users. The LoRa modulation is particularly resistant to interference due to other simultaneous transmissions on the same frequency but too much local activity will mean that not all uplinks get through. The Things Industries suggest designing a system to a potential packet loss rate of 10%. Typically we see 1 or 2% loss. This is entirely down to shared use of the radio waves, once an uplink is heard by a gateway the system is super reliable through The Things Stack. To ensure that the shared ISM bands are fairly used there are limits defined in law on how often you can transmit, called Duty Cycle. The details vary by region or country but typically you can only transmit for 1% of the time. Some frequencies you can only use 0.1% of the time. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/ for more information. Additionally, as The Things Stack Sandbox aka TTN is an array of servers in three locations around the world paid for by The Things Industries, there is a Fair Use Policy so that those learning LoRaWAN, communities, hobbyists & makers are guided on how much of the resource any one device can use. In short, it's 30 seconds of airtime a day and 10 downlinks. When a gateway is transmitting a downlink it can not hear any uplinks (contributing to the potential uplink loss outlined above). The community concensus is that 1 downlink a fortnight to update or adjust settings is appropriate. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/#fair-use-policy for more information. -You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. A uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so +You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. An uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so -With all thes considerations, trying to use LoRaWAN for command & control isn't appropriate and realtime GPS tracking almost always breaches FUP and usually legal limits, leaving aside the challenges of coverage. +With all these considerations, trying to use LoRaWAN for command & control isn't appropriate and realtime GPS tracking almost always breaches FUP and usually legal limits, leaving aside the challenges of coverage. See the hints & tips section on testing your device. ### EUI's & Keys -In the config.h towards the top there are four lines thus: +In the `config.h` towards the top there are four lines thus: // replace-with-your-device-id uint64_t joinEUI = 0x0000000000000000; From 14e1a9bd42b2815e582dd3999062f6a18c0733a1 Mon Sep 17 00:00:00 2001 From: HeadBoffin <60431281+HeadBoffin@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:09:09 +0000 Subject: [PATCH 0952/1848] Update notes.md --- examples/LoRaWAN/LoRaWAN_Starter/notes.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md index 9fdd6bd53c..b56675995a 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/notes.md +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -105,9 +105,9 @@ The radio frequencies that are used are usually shared with other Industrial, Sc To ensure that the shared ISM bands are fairly used there are limits defined in law on how often you can transmit, called Duty Cycle. The details vary by region or country but typically you can only transmit for 1% of the time. Some frequencies you can only use 0.1% of the time. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/ for more information. -Additionally, as The Things Stack Sandbox aka TTN is an array of servers in three locations around the world paid for by The Things Industries, there is a Fair Use Policy so that those learning LoRaWAN, communities, hobbyists & makers are guided on how much of the resource any one device can use. In short, it's 30 seconds of airtime a day and 10 downlinks. When a gateway is transmitting a downlink it can not hear any uplinks (contributing to the potential uplink loss outlined above). The community concensus is that 1 downlink a fortnight to update or adjust settings is appropriate. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/#fair-use-policy for more information. +Additionally, as The Things Stack Sandbox aka TTN is an array of servers in three locations around the world paid for by The Things Industries, there is a Fair Use Policy so that those learning LoRaWAN, communities, hobbyists & makers are guided on how much of the resource any one device can use. In short, it's 30 seconds of airtime a day and 10 downlinks. When a gateway is transmitting a downlink it can not hear any uplinks (contributing to the potential uplink loss outlined above). The community consensus is that 1 downlink a fortnight to update or adjust settings is appropriate. See https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/#fair-use-policy for more information. -You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. An uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so +You can see what intervals can be used with this interactive calculator: https://avbentem.github.io/airtime-calculator/ttn/. Devices further away from gateways will have to use a higher Spread Factor to be heard - do not assume everything will happen at SF7. An uplink takes a minimum of 6 seconds from start to end, sometimes longer if the device is further away from the gateway, so you will need to be patient for just a short while whilst waiting for feedback after seeing "Sending uplink" With all these considerations, trying to use LoRaWAN for command & control isn't appropriate and realtime GPS tracking almost always breaches FUP and usually legal limits, leaving aside the challenges of coverage. @@ -141,7 +141,7 @@ If you are using US915 or AU915 then you should change the subBand const to 2. ### The pinmap -This is the connections between the MCU (ESP32/ATmega/SAMD) and the LoRa radio (SX1276/SX1262). +This is the connection between the MCU (ESP32/ATmega/SAMD) and the LoRa radio (SX1276/SX1262). Prebuilt modules are easy - we can detect the board and setup the pinmap for you. These boards are: @@ -152,15 +152,13 @@ Prebuilt modules are easy - we can detect the board and setup the pinmap for you * HELTEC_WIFI_LORA_32 * HELTEC_WIFI_LORA_32_V2 * HELTEC_WIFI_LORA_32_V3 -* CUBECELL_BOARD If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu. * TBEAM_USE_RADIO_SX1262 * TBEAM_USE_RADIO_SX1276 -If you have an Adafruit Feather M0 with RFM95 then you must solder a wire or use a jumper to link from pin 6 to io1: https://learn.adafruit.com/the-things-network-for-feather/arduino-wiring - +Auto-setup for the Adafruit Feather M0 with RFM95 is included but you must solder a wire or use a jumper to link from pin 6 to io1: https://learn.adafruit.com/the-things-network-for-feather/arduino-wiring If you have a module that's not on this list, please go to the "Pinmap How-To" below. @@ -199,4 +197,4 @@ The LoRaWAN code base works to a specification and once you are happy your devic ## Pinmap How-To - +Coming soon From 388a714e535d3da1848cf90017079ff86d817211 Mon Sep 17 00:00:00 2001 From: Nick McCloud Date: Mon, 25 Mar 2024 14:21:14 +0000 Subject: [PATCH 0953/1848] Added uplink complete msg --- examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 30d15c1525..7b584dcc90 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -58,7 +58,11 @@ void loop() { // Perform an uplink int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + + Serial.print(F("Uplink complete, next in ")); + Serial.print(uplinkIntervalSeconds); + Serial.println(F(" seconds")); // Wait until next uplink - observing legal & TTN FUP constraints - delay(uplinkIntervalSeconds * 1000UL); + delay(uplinkIntervalSeconds * 1000UL); // delay needs milli-seconds } From 9e4783cf8b647865ce2259ca736de8ba93fe220a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Tue, 26 Mar 2024 06:55:37 +0100 Subject: [PATCH 0954/1848] [CI] Fix for new LoraWAN examples (#1035) * Update CI for new LoRaWAN examples * Use single line for flags * Fixup flag strings * Fixup array dump helper * Added missing LoRaWAN defines * Drop Teensy from CI (still broken) * Define a board for CI runs --- .github/workflows/main.yml | 7 ++++++- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 6 ++++-- examples/LoRaWAN/LoRaWAN_Reference/config.h | 6 ++++-- examples/LoRaWAN/LoRaWAN_Starter/config.h | 6 ++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 12c45391ce..31dcf040ec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -162,9 +162,14 @@ jobs: # skip sketch echo -e "\n\033[1;33mSkipped ${example##*/} (matched with ${{ steps.prep.outputs.skip-pattern }})\033[0m"; else + # apply special flags for LoRaWAN + if [[ ${example} =~ "LoRaWAN" ]]; then + flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_NWKS_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1" + fi + # build sketch echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.id }}${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.id }}${{ steps.prep.outputs.options }} --build-property compiler.cpp.extra_flags="$flags" $example --warnings=${{ steps.prep.outputs.warnings }} if [ $? -ne 0 ]; then echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; exit 1; diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index 33fd9fa0d3..5d8d29e184 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -125,8 +125,10 @@ void debug(bool isFail, const __FlashStringHelper* message, int state, bool Free // Helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { - for (uint16_t c; c < len; c++) { - Serial.printf("%02X", buffer[c]); + for(uint16_t c = 0; c < len; c++) { + char b = buffer[c]; + if(b < 0x10) { Serial.print('0'); } + Serial.print(b, HEX); } Serial.println(); } diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index bba38e4fe7..b9c1bf71d9 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -120,8 +120,10 @@ void debug(bool isFail, const __FlashStringHelper* message, int state, bool Free // Helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { - for (uint16_t c; c < len; c++) { - Serial.printf("%02X", buffer[c]); + for(uint16_t c = 0; c < len; c++) { + char b = buffer[c]; + if(b < 0x10) { Serial.print('0'); } + Serial.print(b, HEX); } Serial.println(); } diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index bba38e4fe7..b9c1bf71d9 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -120,8 +120,10 @@ void debug(bool isFail, const __FlashStringHelper* message, int state, bool Free // Helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { - for (uint16_t c; c < len; c++) { - Serial.printf("%02X", buffer[c]); + for(uint16_t c = 0; c < len; c++) { + char b = buffer[c]; + if(b < 0x10) { Serial.print('0'); } + Serial.print(b, HEX); } Serial.println(); } From 648b455cfffff0de279025c3f96f4d3ca40dd041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Tue, 26 Mar 2024 06:57:25 +0100 Subject: [PATCH 0955/1848] [LoRaWAN] Added array of supported bands (#1032) --- src/protocols/LoRaWAN/LoRaWAN.h | 23 +++++++++++++++++++++++ src/protocols/LoRaWAN/LoRaWANBands.cpp | 22 +++++++++++----------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 0aab1fa7a0..875ac7cb28 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -392,6 +392,29 @@ extern const LoRaWANBand_t AS923; extern const LoRaWANBand_t KR920; extern const LoRaWANBand_t IN865; +/*! + \struct LoRaWANBandNum_t + \brief IDs of all currently supported bands +*/ +enum LoRaWANBandNum_t { + BandEU868, + BandUS915, + BandCN780, + BandEU433, + BandAU915, + BandCN500, + BandAS923, + BandKR920, + BandIN865, + BandLast +}; + +// provide easy access to the number of currently supported bands +#define RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS (BandLast - BandEU868) + +// array of currently supported bands +extern const LoRaWANBand_t* LoRaWANBands[]; + /*! \struct LoRaWANMacCommand_t \brief Structure to save information about MAC command diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index ad0b1b9ee2..eaeb0841ab 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -2,17 +2,17 @@ #if !RADIOLIB_EXCLUDE_LORAWAN -enum LoRaWANBandNum_t { - BandNone, - BandEU868, - BandUS915, - BandCN780, - BandEU433, - BandAU915, - BandCN500, - BandAS923, - BandKR920, - BandIN865 +// array of pointers to currently supported LoRaWAN bands +const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { + &EU868, + &US915, + &CN780, + &EU433, + &AU915, + &CN500, + &AS923, + &KR920, + &IN865, }; const LoRaWANBand_t EU868 = { From b3ed84a0359e03128d5930e528114bcd0fdaaf36 Mon Sep 17 00:00:00 2001 From: Crsarmv7l <85343771+Crsarmv7l@users.noreply.github.com> Date: Tue, 26 Mar 2024 02:24:02 -0400 Subject: [PATCH 0956/1848] [CC1101] PQT = 0 in setPromiscuous (#1033) * PQT = 0 in setPromiscuous * Carriersense in promiscuous * carriersense to promiscuous * Fix explanation --- src/modules/CC1101/CC1101.cpp | 9 +++++++-- src/modules/CC1101/CC1101.h | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 447e0420e9..64ef8ab3c4 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -826,7 +826,7 @@ int16_t CC1101::setCrcFiltering(bool enable) { } } -int16_t CC1101::setPromiscuousMode(bool enable) { +int16_t CC1101::setPromiscuousMode(bool enable, bool requireCarrierSense) { int16_t state = RADIOLIB_ERR_NONE; if(this->promiscuous == enable) { @@ -834,9 +834,14 @@ int16_t CC1101::setPromiscuousMode(bool enable) { } if(enable) { + // Lets set PQT to 0 with Promiscuous too + // We have to set the length to set PQT, but it should get disabled with disableSyncWordFiltering() + state = setPreambleLength(16, 0); + RADIOLIB_ASSERT(state); // disable sync word filtering and insertion // this also disables preamble - state = disableSyncWordFiltering(); + // Can enable Sync Mode with carriersense when promiscuous is enabled. Default is false: Sync Mode None + state = disableSyncWordFiltering(requireCarrierSense); RADIOLIB_ASSERT(state); // disable CRC filtering diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 9d2254a4ce..a0c2d78937 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -874,9 +874,10 @@ class CC1101: public PhysicalLayer { /*! \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). \param enable Set or unset promiscuous mode. + \param defaults to false: no carriersense, true: sets carriersense above threshold \returns \ref status_codes */ - int16_t setPromiscuousMode(bool enable = true); + int16_t setPromiscuousMode(bool enable = true, bool requireCarrierSense = false); /*! \brief Get whether the modem is in promiscuous mode: no packet filtering From 0ed586a840b1f778610c50abf3eb47f2c2fcf087 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 07:26:16 +0100 Subject: [PATCH 0957/1848] [CC1101] Fixup tabs --- src/modules/CC1101/CC1101.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 64ef8ab3c4..16bd25ee50 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -992,11 +992,11 @@ int16_t CC1101::directMode(bool sync) { this->directModeEnabled = sync; if(sync) { // set GDO0 and GDO2 mapping - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); - // set continuous mode - state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); + // set continuous mode + state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); } else { // set GDO0 mapping state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0); @@ -1016,23 +1016,23 @@ void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8 // iterate over possible exponent values for(int8_t e = expMax; e >= 0; e--) { // get table column start value (exp = e, mant = 0); - float intervalStart = ((uint32_t)1 << e) * origin; + float intervalStart = ((uint32_t)1 << e) * origin; // check if target value is in this column - if(target >= intervalStart) { + if(target >= intervalStart) { // save exponent value exp = e; // calculate size of step between table rows - float stepSize = intervalStart/(float)mantOffset; + float stepSize = intervalStart/(float)mantOffset; // get target point position (exp = e, mant = m) - mant = ((target - intervalStart) / stepSize); + mant = ((target - intervalStart) / stepSize); // we only need the first match, terminate - return; - } - } + return; + } + } } int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { From 7b5211130ae992adcd3f90892cb729f718818eb5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 07:27:16 +0100 Subject: [PATCH 0958/1848] [CC1101] Fix doxygen comment --- src/modules/CC1101/CC1101.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index a0c2d78937..bb97911670 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -874,7 +874,7 @@ class CC1101: public PhysicalLayer { /*! \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). \param enable Set or unset promiscuous mode. - \param defaults to false: no carriersense, true: sets carriersense above threshold + \param requireCarrierSense Set carriersense required above threshold, defaults to false. \returns \ref status_codes */ int16_t setPromiscuousMode(bool enable = true, bool requireCarrierSense = false); From c77670c0765e45afa2f35692d0e603a0cc3168e5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 20:03:54 +0100 Subject: [PATCH 0959/1848] [CI] Disable build for Arduino 101 (platform broken) --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 31dcf040ec..ab444e0d5c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -78,7 +78,6 @@ jobs: run: | echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - - id: Intel:arc32:arduino_101 - id: SparkFun:apollo3:sfe_artemis run: | echo "warnings='none'" >> $GITHUB_OUTPUT From 5391d5d383ae007c0083cb3d3c6ddca029fd9f6a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 20:15:03 +0100 Subject: [PATCH 0960/1848] [LoRaWAN] Add cast for DevAddr print --- examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 770b47956f..a098fbec92 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -55,7 +55,7 @@ void setup() { // Print the DevAddr Serial.print("[LoRaWAN] DevAddr: "); - Serial.println(node.getDevAddr(), HEX); + Serial.println((unsigned long)node.getDevAddr(), HEX); // Disable the ADR algorithm (on by default which is preferable) node.setADR(false); From 5c891ae33798280bd400dc1737aa2d1aff8c77f2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 20:23:53 +0100 Subject: [PATCH 0961/1848] [LoRaWAN] Do not use analog pin macros that may not be defined --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 2 +- examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino | 2 +- examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index ec27df6310..7b199c3e69 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -54,7 +54,7 @@ void loop() { // Read some inputs uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(A0); + uint16_t Analog1 = analogRead(3); // Build payload byte array uint8_t uplinkPayload[3]; diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index a098fbec92..23d2ef75dc 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -92,7 +92,7 @@ void loop() { // Read some inputs uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(A0); + uint16_t Analog1 = analogRead(3); // Build payload byte array uint8_t uplinkPayload[3]; diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 7b584dcc90..72c65096e9 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -47,7 +47,7 @@ void loop() { // Read some inputs uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(A0); + uint16_t Analog1 = analogRead(3); // Build payload byte array uint8_t uplinkPayload[3]; From 9cf04b633da36db8736c4962c617da536ce65952 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 20:40:43 +0100 Subject: [PATCH 0962/1848] [CI] Disable LoRaWAN CI build for UNO R4 (unable to pass flags) --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ab444e0d5c..1ee4fa8649 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -104,6 +104,8 @@ jobs: - id: MegaCore:avr:1281 run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT - id: arduino:renesas_uno:minima + run: | + echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT runs-on: ubuntu-latest name: ${{ matrix.id }} From b91fd2bdada6f424e9f4cfd250c29d0ec6dab19d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Mar 2024 21:23:54 +0100 Subject: [PATCH 0963/1848] [CI] Disable LoRaWAN CI build for Apollo3 (unable to pass flags) --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1ee4fa8649..5eaf568b63 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,6 +80,7 @@ jobs: echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - id: SparkFun:apollo3:sfe_artemis run: | + echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT echo "warnings='none'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT - id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC From 78211e756694b0bbc125c02313310bfc718c2a77 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Mar 2024 18:48:16 +0100 Subject: [PATCH 0964/1848] [LoRaWAN] Added specific error code for no downlink received --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 2 +- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 21 +++++++--------- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 5 ++-- examples/LoRaWAN/LoRaWAN_Reference/config.h | 24 +++++++------------ .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 2 +- examples/LoRaWAN/LoRaWAN_Starter/config.h | 24 +++++++------------ keywords.txt | 3 ++- src/TypeDef.h | 5 ++++ src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 9 files changed, 39 insertions(+), 49 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 7b199c3e69..99c65225eb 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -64,7 +64,7 @@ void loop() { // Perform an uplink int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); - debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); // Wait until next uplink - observing legal & TTN FUP constraints delay(uplinkIntervalSeconds * 1000UL); diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index 5d8d29e184..a536ff1492 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -3,10 +3,10 @@ #include -// How often to send an uplink - consider legal & FUP constraints - see notes +// how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds -// Device address - either a development address or one assigned +// device address - either a development address or one assigned // to the LoRaWAN Service Provider - TTN will generate one for you #ifndef RADIOLIB_LORAWAN_DEV_ADDR // Replace with your DevAddr #define RADIOLIB_LORAWAN_DEV_ADDR 0x------ @@ -25,11 +25,10 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds #define RADIOLIB_LORAWAN_APPS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif -// For the curious, the #ifndef blocks allow for automated testing &/or you can +// for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips - -// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 @@ -99,20 +98,17 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #endif - -// Copy over the keys in to the something that will not compile if incorrectly formatted +// copy over the keys in to the something that will not compile if incorrectly formatted uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR; uint8_t NwkSKey[] = { RADIOLIB_LORAWAN_NWKS_KEY }; uint8_t SNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // Previously sNwkSIntKey uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; - -// Create the LoRaWAN node +// create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); - -// Helper function to display any issues +// helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); @@ -123,7 +119,7 @@ void debug(bool isFail, const __FlashStringHelper* message, int state, bool Free } } -// Helper function to display a byte array +// helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { char b = buffer[c]; @@ -133,5 +129,4 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } - #endif diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 23d2ef75dc..ad49a261c0 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -122,9 +122,10 @@ void loop() { } else { state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize); } - debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); - if(state == RADIOLIB_ERR_NONE) { + // Check if downlink was received + if(state != RADIOLIB_LORAWAN_NO_DOWNLINK) { // Did we get a downlink with data for us if (downlinkSize > 0) { Serial.println(F("Downlink data: ")); diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index b9c1bf71d9..cb681da2ff 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -3,14 +3,14 @@ #include -// How often to send an uplink - consider legal & FUP constraints - see notes +// how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds -// JoinEUI - previous versions of LoRaWAN called this AppEUI +// joinEUI - previous versions of LoRaWAN called this AppEUI // for development purposes you can use all zeros - see wiki for details #define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 -// The Device EUI & two keys can be generated on the TTN console +// the Device EUI & two keys can be generated on the TTN console #ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI #define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- #endif @@ -21,16 +21,13 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds #define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif -// For the curious, the #ifndef blocks allow for automated testing &/or you can +// for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips - - -// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 - // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... @@ -96,18 +93,16 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #endif - -// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; -// Create the LoRaWAN node +// create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); - -// Helper function to display any issues +// helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); @@ -118,7 +113,7 @@ void debug(bool isFail, const __FlashStringHelper* message, int state, bool Free } } -// Helper function to display a byte array +// helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { char b = buffer[c]; @@ -128,5 +123,4 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } - #endif diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 72c65096e9..0914c1c071 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -57,7 +57,7 @@ void loop() { // Perform an uplink int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); - debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); Serial.print(F("Uplink complete, next in ")); Serial.print(uplinkIntervalSeconds); diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index b9c1bf71d9..cb681da2ff 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -3,14 +3,14 @@ #include -// How often to send an uplink - consider legal & FUP constraints - see notes +// how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds -// JoinEUI - previous versions of LoRaWAN called this AppEUI +// joinEUI - previous versions of LoRaWAN called this AppEUI // for development purposes you can use all zeros - see wiki for details #define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 -// The Device EUI & two keys can be generated on the TTN console +// the Device EUI & two keys can be generated on the TTN console #ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI #define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- #endif @@ -21,16 +21,13 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds #define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif -// For the curious, the #ifndef blocks allow for automated testing &/or you can +// for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips - - -// Regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 - // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... @@ -96,18 +93,16 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #endif - -// Copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; -// Create the LoRaWAN node +// create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); - -// Helper function to display any issues +// helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); @@ -118,7 +113,7 @@ void debug(bool isFail, const __FlashStringHelper* message, int state, bool Free } } -// Helper function to display a byte array +// helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { char b = buffer[c]; @@ -128,5 +123,4 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } - #endif diff --git a/keywords.txt b/keywords.txt index 48efe63259..cb12945445 100644 --- a/keywords.txt +++ b/keywords.txt @@ -436,4 +436,5 @@ RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 -RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 \ No newline at end of file +RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 +RADIOLIB_LORAWAN_NO_DOWNLINK LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index 818d99d59a..6cb67247ee 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -558,6 +558,11 @@ */ #define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1115) +/*! + \brief No downlink was received - most likely none was sent from the server. +*/ +#define RADIOLIB_LORAWAN_NO_DOWNLINK (-1116) + /*! \} */ diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0e7692c3a3..a29aaf1b1b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1226,7 +1226,7 @@ int16_t LoRaWANNode::downlinkCommon() { this->phyLayer->invertIQ(false); } - return(RADIOLIB_ERR_RX_TIMEOUT); + return(RADIOLIB_LORAWAN_NO_DOWNLINK); } // wait for the DIO to fire indicating a downlink is received From 0707a326a55bcc5b12b78b35f41223d66a6d2ec2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 27 Mar 2024 19:03:51 +0100 Subject: [PATCH 0965/1848] Bump version to 6.5.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 09f82ad98d..572ca4d832 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "6.4.2" +version: "6.5.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan" url: "https://github.com/jgromes/RadioLib" diff --git a/library.json b/library.json index 2927c2f6dc..0758385243 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.4.2", + "version": "6.5.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 9fd734b105..0b435dfc1f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.4.2 +version=6.5.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5653a1ef1e..9b25d3fec1 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -557,8 +557,8 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 6 -#define RADIOLIB_VERSION_MINOR 4 -#define RADIOLIB_VERSION_PATCH 2 +#define RADIOLIB_VERSION_MINOR 5 +#define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 1fb51004134a66d001f3065ddf8bab50d7ff1e59 Mon Sep 17 00:00:00 2001 From: Crsarmv7l <85343771+Crsarmv7l@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:44:10 -0400 Subject: [PATCH 0966/1848] [CC1101] 3 New CC1101 Functions (#1038) * getFrequency implementation * getFrequency Method * Get bitrate method * getBitRate * CalcRxBandwidth() method * CalcRxBandwidth(); * Fix Notes * Changes for pull * Changes for pull 2 * Update keywords.txt * Revert to hopefully bring in current * Fix () * Re add --- keywords.txt | 1 + src/modules/CC1101/CC1101.cpp | 18 ++++++++++++++++++ src/modules/CC1101/CC1101.h | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/keywords.txt b/keywords.txt index cb12945445..d9d5950728 100644 --- a/keywords.txt +++ b/keywords.txt @@ -134,6 +134,7 @@ getSNR KEYWORD2 getDataRate KEYWORD2 setBitRate KEYWORD2 setRxBandwidth KEYWORD2 +autoSetRxBandwidth KEYWORD2 setAFCBandwidth KEYWORD2 setAFC KEYWORD2 setAFCAGCTrigger KEYWORD2 diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 16bd25ee50..2965a343a4 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -489,6 +489,24 @@ int16_t CC1101::setRxBandwidth(float rxBw) { return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); } +int16_t CC1101::autoSetRxBandwidth() { + // Uncertainty ~ +/- 40ppm for a cheap CC1101 + // Uncertainty * 2 for both transmitter and receiver + float uncertainty = ((this->frequency) * 40 * 2); + uncertainty = (uncertainty/1000); //Since bitrate is in kBit + float minbw = ((this->bitRate) + uncertainty); + + int possibles[16] = {58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650, 812}; + + for (int i = 0; i < 16; i++) { + if (possibles[i] > minbw) { + int16_t state = setRxBandwidth(possibles[i]); + return(state); + } + } + return(RADIOLIB_ERR_UNKNOWN); + } + int16_t CC1101::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index bb97911670..69b8e4eb2f 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -745,6 +745,14 @@ class CC1101: public PhysicalLayer { */ int16_t setRxBandwidth(float rxBw); + /*! + \brief calculates and sets Rx bandwidth based on the freq, baud and freq uncertainty. + Reimplement of atlas0fd00m's (RfCat) CalculatePktChanBw function. + Modified for worse ppm with the CC1101, and adjusted for the supportted CC1101 bw. + \returns \ref status_codes + */ + int16_t autoSetRxBandwidth(); + /*! \brief Sets frequency deviation. Allowed values range from 1.587 to 380.8 kHz. \param freqDev Frequency deviation to be set in kHz. From 936a39ad985b2acced3900fc3ef7ebbbb960cfc4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:34:35 +0100 Subject: [PATCH 0967/1848] [CC1101] Use millis for timeouts --- src/modules/CC1101/CC1101.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 2965a343a4..af7f1df997 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -100,29 +100,29 @@ void CC1101::reset() { int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); + uint32_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission start or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getGpio())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } // wait for transmission end or timeout - start = this->mod->hal->micros(); + start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getGpio())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -133,18 +133,18 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t CC1101::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full max-length packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet start or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { standby(); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); return(RADIOLIB_ERR_RX_TIMEOUT); @@ -152,11 +152,11 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { } // wait for packet end or timeout - start = this->mod->hal->micros(); + start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { standby(); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); return(RADIOLIB_ERR_RX_TIMEOUT); From aafe96faf8b44aec9cc957f5b65c78a32ebdf9ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:34:48 +0100 Subject: [PATCH 0968/1848] [nRF24] Use millis for timeouts --- src/modules/nRF24/nRF24.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index a54298844e..40678b8c41 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -88,7 +88,7 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait until transmission is finished - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); @@ -98,8 +98,8 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_ACK_NOT_RECEIVED); } - // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(this->mod->hal->micros() - start >= 60000) { + // check timeout: 15 retries * 4ms (max Tx time as per datasheet) + 10 ms + if(this->mod->hal->millis() - start >= ((15 * 4) + 10)) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -114,12 +114,12 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for Rx_DataReady or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(this->mod->hal->micros() - start >= 60000) { + // check timeout: 15 retries * 4ms (max Tx time as per datasheet) + 10 ms + if(this->mod->hal->millis() - start >= ((15 * 4) + 10)) { standby(); clearIRQ(); return(RADIOLIB_ERR_RX_TIMEOUT); From 5980e0fb005eb03b907464402959293dd58def3c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:34:56 +0100 Subject: [PATCH 0969/1848] [RF69] Use millis for timeouts --- src/modules/RF69/RF69.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index a934898eda..604b9af525 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -100,18 +100,18 @@ void RF69::reset() { int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); + uint32_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -122,18 +122,18 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t RF69::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { standby(); clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); From eba32d7dcde3fe1f12cbd44e4f9fed59917e5d5d Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:35:08 +0100 Subject: [PATCH 0970/1848] [Si443x] Use millis for timeouts --- src/modules/Si443x/Si443x.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 541f3eb743..dcd6375165 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -73,17 +73,17 @@ void Si443x::reset() { int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0); + uint32_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -94,16 +94,16 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t Si443x::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { standby(); clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); From 8098bea254dabe7e90939d23ca20f25ab767bc38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:35:29 +0100 Subject: [PATCH 0971/1848] [SX128x] Use millis for timeouts --- src/modules/SX128x/SX128x.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 55b18dd96b..2df75594de 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -305,20 +305,19 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t state = standby(); RADIOLIB_ASSERT(state); - // calculate timeout (500% of expected time-on-air) - uint32_t timeout = getTimeOnAir(len) * 5; - - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + // calculate timeout in ms (500% of expected time-on-air) + uint32_t timeout = (getTimeOnAir(len) * 5) / 1000; + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start transmission state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } @@ -340,8 +339,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // calculate timeout (1000% of expected time-on-air) uint32_t timeout = getTimeOnAir(len) * 10; - - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); @@ -350,11 +348,11 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout bool softTimeout = false; - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { softTimeout = true; break; } From fb7d69800750f520952f7cfc53de507f0bb49c40 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:36:05 +0100 Subject: [PATCH 0972/1848] [SX127x] Use millis for timeouts --- src/modules/SX127x/SX127x.cpp | 53 ++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7606f001b8..98d78394d7 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -149,13 +149,14 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t modem = getActiveModem(); uint32_t start = 0; uint32_t timeout = 0; + uint32_t toa = getTimeOnAir(len); if(modem == RADIOLIB_SX127X_LORA) { - // calculate timeout (150 % of expected time-on-air) - timeout = getTimeOnAir(len) * 1.5; + // calculate timeout in ms (150 % of expected time-on-air) + timeout = (toa * 1.5) / 1000; } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // calculate timeout (5ms + 500 % of expected time-on-air) - timeout = 5000 + getTimeOnAir(len) * 5; + // calculate timeout in ms (5ms + 500 % of expected time-on-air) + timeout = 5 + (toa * 5) / 1000; } else { return(RADIOLIB_ERR_UNKNOWN); @@ -163,22 +164,23 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // start transmission + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - start = this->mod->hal->micros(); + start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } // update data rate - uint32_t elapsed = this->mod->hal->micros() - start; - this->dataRate = (len*8.0)/((float)elapsed/1000000.0); + uint32_t elapsed = this->mod->hal->millis() - start; + this->dataRate = (len*8.0)/((float)elapsed/1000.0); return(finishTransmit()); } @@ -198,17 +200,17 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { uint32_t timeout = 0; if(this->mod->getGpio() == RADIOLIB_NC) { float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); + timeout = (uint32_t)(symbolLength * 100.0); } // wait for packet reception or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->getGpio() == RADIOLIB_NC) { // no GPIO pin provided, use software timeout - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -223,18 +225,18 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // calculate timeout (500 % of expected time-on-air) - uint32_t timeout = getTimeOnAir(len) * 5; + // calculate timeout in ms (500 % of expected time-on-air) + uint32_t timeout = (getTimeOnAir(len) * 5) / 1000; // set mode to receive state = startReceive(len, RADIOLIB_SX127X_RX); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { clearIRQFlags(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -1252,31 +1254,30 @@ uint32_t SX127x::getTimeOnAir(size_t len) { // get number of symbols float n_sym = getNumSymbols(len); - // Get time-on-air in us + // get time-on-air in us return ceil((double)symbolLength * (double)n_sym) * 1000; } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // Get number of bits preamble + // get number of bits preamble float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; - //Get the number of bits of the sync word + // get the number of bits of the sync word float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; - //Get CRC bits + // get CRC bits float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16; if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { - //If Packet size fixed -> len = fixed packet length + // if packet size fixed -> len = fixed packet length len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); } else { - //if packet variable -> Add 1 extra byte for payload length + // if packet variable -> Add 1 extra byte for payload length len += 1; } - // Calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) - return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0); - } else { - return(RADIOLIB_ERR_UNKNOWN); + // calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) + return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0)); } - + + return(RADIOLIB_ERR_UNKNOWN); } uint32_t SX127x::calculateRxTimeout(uint32_t timeoutUs) { From 88f26c4aabb58a1c634be0d26bea7490801b0301 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:36:51 +0100 Subject: [PATCH 0973/1848] [SX126x] Use millis for timeouts (#1013) --- src/modules/SX126x/SX126x.cpp | 42 +++++++++++++---------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 161a524536..2c029e5475 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -231,41 +231,27 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } - uint32_t timeout = 0; - - // get currently active modem - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - // calculate timeout (150% of expected time-on-air) - timeout = (getTimeOnAir(len) * 3) / 2; - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - // calculate timeout (500% of expected time-on-air) - timeout = getTimeOnAir(len) * 5; - - } else { - return(RADIOLIB_ERR_UNKNOWN); - } - - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + // calculate timeout in ms (500% of expected time-on-air) + uint32_t timeout = (getTimeOnAir(len) * 5) / 1000; + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start transmission state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - uint32_t elapsed = this->mod->hal->micros() - start; // update data rate - this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0); + uint32_t elapsed = this->mod->hal->millis() - start; + this->dataRateMeasured = (len*8.0)/((float)elapsed/1000.0); return(finishTransmit()); } @@ -282,7 +268,8 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (uint32_t)(symbolLength * 100.0 * 1000.0); + timeout = (uint32_t)(symbolLength * 100.0); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) size_t maxLen = len; @@ -290,26 +277,27 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { maxLen = 0xFF; } float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; - timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0); + timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); } else { return(RADIOLIB_ERR_UNKNOWN); + } - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start reception - uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); + uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 15.625); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); // wait for packet reception or timeout bool softTimeout = false; - uint32_t start = this->mod->hal->micros(); + uint32_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio - if(this->mod->hal->micros() - start > timeout) { + if(this->mod->hal->millis() - start > timeout) { softTimeout = true; break; } From 721a44c6e442a81a2173347054ddf7a0380d42dc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 29 Mar 2024 08:40:25 +0100 Subject: [PATCH 0974/1848] [RF69] Fix copy-pate error (#1013) --- src/modules/RF69/RF69.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 604b9af525..84080f38ac 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -122,7 +122,7 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t RF69::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); + uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); From b2c7e98d6cfab071f20566d23d0380dd26839c91 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sat, 30 Mar 2024 09:33:30 +0100 Subject: [PATCH 0975/1848] Update examples/LoRaWAN/README --- examples/LoRaWAN/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index a269810b3b..8a44860f68 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -1,18 +1,20 @@ # LoRaWAN examples RadioLib LoRaWAN v1.1 examples. -* [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the `notes` that come with this example to learn more about LoRaWAN and how to use it in RadioLib! -* [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the `notes` for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)! +* [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) that come with this example to learn more about LoRaWAN and how to use it in RadioLib! +* [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)! * [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib. --- -All three of these examples do not fully comply with LoRaWAN v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: +> [!WARNING] +> These examples do not fully comply with LoRaWAN v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: ## RadioLib persistence In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN v1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!** Currently, examples are available for the following platforms: * [LoRaWAN for ESP32](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP32) +* [LoRaWAN for ESP8266](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP8266) -_This list is last updated for RadioLib 6.5.0_ +_This list is last updated at 30/03/2024._ From 9daf4c4f2685ec8f15134b395be8ce7c7ba9c9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 31 Mar 2024 21:41:12 +0200 Subject: [PATCH 0976/1848] [CI] Minor fixes (#1045) * [CI] Add Teensy back in * [CI] Add Arduino 101 back to build matrix * [CI] Try different path to libs * [CI] Skip LoRaWAN on Teensy --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5eaf568b63..e7d4cbe3f4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -104,6 +104,10 @@ jobs: run: echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT - id: MegaCore:avr:1281 run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT + - id: teensy:avr:teensy41 + run: | + echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://www.pjrc.com/teensy/package_teensy_index.json" >> $GITHUB_OUTPUT - id: arduino:renesas_uno:minima run: | echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT From e5493618a476170077f734d52573d40cfc600747 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 31 Mar 2024 14:43:30 -0500 Subject: [PATCH 0977/1848] Update ArduinoHal.h to make spi and friends protected (#1044) Most of the "override" functions here can't actually be overridden in a useful way when spi, spiSettings, and everything else is marked private. If everything is override, then nothing should be private. --- src/ArduinoHal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 00074c1d31..2fa8b5d6c9 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -60,7 +60,7 @@ class ArduinoHal : public RadioLibHal { uint32_t pinToInterrupt(uint32_t pin) override; #if !RADIOLIB_GODMODE - private: + protected: #endif SPIClass* spi = NULL; SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS; From e57c9b08ea5cef1ee4beeba2329842c8b68005dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 1 Apr 2024 11:11:24 +0200 Subject: [PATCH 0978/1848] [Doxygen] Warnings fixes (#1046) * [APRS] Fix Doxygen warnings * [Print] Fix Doxygen warnings * [CC1101] Fixed doxygen warnings * [nRF24] Fixed doxygen warnings * [RF69] Fixed doxygen warnings * [SX126x] Fixed doxygen warnings * [SX127x] Fixed doxygen warnings * [AFSK] Fixed doxygen warnings * [APRS] Fixed doxygen warnings * [Bell] Fixed doxygen warnings * [Ext] Fixed doxygen warnings * [LoRaWAN] Fixed doxygen warnings * [PHY] Fixed doxygen warnings * [Print] Fixed doxygen warnings * [Mod] Fixed doxygen warnings --- src/Module.h | 65 +++++++++++---------- src/modules/CC1101/CC1101.h | 39 +++++++------ src/modules/RF69/RF69.h | 8 +-- src/modules/SX126x/STM32WLx_Module.cpp | 19 ++++++ src/modules/SX126x/SX126x.h | 2 +- src/modules/SX127x/SX1272.h | 3 +- src/modules/SX127x/SX127x.h | 17 ++---- src/modules/nRF24/nRF24.h | 2 +- src/protocols/AFSK/AFSK.h | 2 +- src/protocols/APRS/APRS.h | 22 ++++++- src/protocols/BellModem/BellModem.h | 2 +- src/protocols/ExternalRadio/ExternalRadio.h | 4 ++ src/protocols/LoRaWAN/LoRaWAN.h | 37 +++++++++--- src/protocols/PhysicalLayer/PhysicalLayer.h | 30 ++++++++-- src/protocols/Print/Print.cpp | 2 +- src/protocols/Print/Print.h | 5 +- 16 files changed, 170 insertions(+), 89 deletions(-) diff --git a/src/Module.h b/src/Module.h index 9b5b78dbce..c61b74b81e 100644 --- a/src/Module.h +++ b/src/Module.h @@ -13,10 +13,9 @@ #endif /*! -* Value to use as the last element in a mode table to indicate the -* end of the table. -* -* See setRfSwitchTable() for details. + \brief Value to use as the last element in a mode table to indicate the + end of the table. + See \ref setRfSwitchTable for details. */ #define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } @@ -31,43 +30,49 @@ class Module { public: /*! - * \brief The maximum number of pins supported by the RF switch - * code. - * - * Note: It is not recommended to use this constant in your sketch - * when defining a rfswitch pins array, to prevent issues when this - * value is ever increased and such an array gets extra zero - * elements (that will be interpreted as pin 0). - */ + \brief The maximum number of pins supported by the RF switch code. + Note: It is not recommended to use this constant in your sketch + when defining a rfswitch pins array, to prevent issues when this + value is ever increased and such an array gets extra zero + elements (that will be interpreted as pin 0). + */ static const size_t RFSWITCH_MAX_PINS = 3; /*! - * Description of RF switch pin states for a single mode. - * - * See setRfSwitchTable() for details. - */ + \struct RfSwitchMode_t + \brief Description of RF switch pin states for a single mode. + See \ref setRfSwitchTable for details. + */ struct RfSwitchMode_t { + /*! \brief RF switching mode, one of \ref OpMode_t or a custom radio-defined value. */ uint8_t mode; + + /*! \brief Output pin values */ uint32_t values[RFSWITCH_MAX_PINS]; }; /*! - * Constants to use in a mode table set be setRfSwitchTable. These - * constants work for most radios, but some radios define their own - * constants to be used instead. - * - * See setRfSwitchTable() for details. - */ + \enum OpMode_t + \brief Constants to use in a mode table set be setRfSwitchTable. These + constants work for most radios, but some radios define their own + constants to be used instead. + + See \ref setRfSwitchTable for details. + */ enum OpMode_t { - /*! End of table marker, use \ref END_OF_MODE_TABLE constant - * instead. Value is zero to ensure zero-initialized mode ends the - * table */ + /*! + \brief End of table marker, use \ref END_OF_MODE_TABLE constant instead. + Value is zero to ensure zero-initialized mode ends the table. + */ MODE_END_OF_TABLE = 0, - /*! Idle mode */ + + /*! \brief Idle mode */ MODE_IDLE, - /*! Receive mode */ + + /*! \brief Receive mode */ MODE_RX, - /*! Transmission mode */ + + /*! \brief Transmission mode */ MODE_TX, }; @@ -111,7 +116,7 @@ class Module { /*! \brief Overload for assignment operator. - \param frame rvalue Module. + \param mod rvalue Module. */ Module& operator=(const Module& mod); @@ -438,7 +443,7 @@ class Module { /*! \brief Find a mode in the RfSwitchTable. - \param The mode to find. + \param mode The mode to find. \returns A pointer to the RfSwitchMode_t struct in the table that matches the passed mode. Returns nullptr if no rfswitch pins are configured, or the passed mode is not listed in the table. diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 69b8e4eb2f..3619d21846 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -537,7 +537,7 @@ class CC1101: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. + \param module Instance of Module that will be used to communicate with the radio. */ CC1101(Module* module); @@ -797,6 +797,7 @@ class CC1101: public PhysicalLayer { /*! \brief Sets preamble length. \param preambleLength Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. + \param qualityThreshold Preamble quality threshold (PQT) to set. \returns \ref status_codes */ int16_t setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold); @@ -834,52 +835,52 @@ class CC1101: public PhysicalLayer { \brief Gets LQI (Link Quality Indicator) of the last received packet. \returns Last packet LQI (lower is better). */ - uint8_t getLQI() const; + uint8_t getLQI() const; - /*! + /*! \brief Query modem for the packet length of received payload. \param update Update received packet length. Will return cached value when set to false. \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; - /*! + /*! \brief Set modem in fixed packet length mode. \param len Packet length. \returns \ref status_codes */ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_CC1101_MAX_PACKET_LENGTH); - /*! + /*! \brief Set modem in variable packet length mode. - \param len Maximum packet length. + \param maxLen Maximum packet length. \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_CC1101_MAX_PACKET_LENGTH); - /*! + /*! \brief Enable sync word filtering and generation. - \param numBits Sync word length in bits. + \param maxErrBits Maximum number of allowed error bits in sync word. \param requireCarrierSense Require carrier sense above threshold in addition to sync word. \returns \ref status_codes */ int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0, bool requireCarrierSense = false); - /*! + /*! \brief Disable preamble and sync word filtering and generation. \param requireCarrierSense Require carrier sense above threshold. \returns \ref status_codes */ int16_t disableSyncWordFiltering(bool requireCarrierSense = false); - /*! + /*! \brief Enable CRC filtering and generation. \param enable Set or unset CRC generation and filtering. \returns \ref status_codes */ int16_t setCrcFiltering(bool enable = true); - /*! + /*! \brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC). \param enable Set or unset promiscuous mode. \param requireCarrierSense Set carriersense required above threshold, defaults to false. @@ -887,7 +888,7 @@ class CC1101: public PhysicalLayer { */ int16_t setPromiscuousMode(bool enable = true, bool requireCarrierSense = false); - /*! + /*! \brief Get whether the modem is in promiscuous mode: no packet filtering (e.g., no preamble, sync word, address, CRC). \returns Whether the modem is in promiscuous mode. @@ -917,16 +918,16 @@ class CC1101: public PhysicalLayer { void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! - \brief Get one truly random byte from RSSI noise. - \returns TRNG byte. - */ + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ uint8_t randomByte(); /*! - \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or - CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working. - \returns Version register contents or \ref status_codes - */ + \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or + CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working. + \returns Version register contents or \ref status_codes + */ int16_t getChipVersion(); #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 177b839ca6..9eda1d886d 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -486,7 +486,7 @@ class RF69: public PhysicalLayer { /*! \brief Default constructor. - \param mod Instance of Module that will be used to communicate with the radio. + \param module Instance of Module that will be used to communicate with the radio. */ RF69(Module* module); @@ -575,7 +575,7 @@ class RF69: public PhysicalLayer { /*! \brief Sets AES key. - \param Key to be used for AES encryption. Must be exactly 16 bytes long. + \param key Key to be used for AES encryption. Must be exactly 16 bytes long. */ void setAESKey(uint8_t* key); @@ -872,14 +872,14 @@ class RF69: public PhysicalLayer { /*! \brief Set modem in variable packet length mode. - \param len Maximum packet length. + \param maxLen Maximum packet length. \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_RF69_MAX_PACKET_LENGTH); /*! \brief Enable sync word filtering and generation. - \param numBits Sync word length in bits. + \param maxErrBits Maximum allowed number of error bits in sync word. \returns \ref status_codes */ int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0); diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 57d0445cd1..0e1191290b 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -22,10 +22,19 @@ enum { RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET, }; +/*! + \class Stm32wlxHal + \brief Hardware Abstraction Layer for STM32WL. +*/ class Stm32wlxHal : public ArduinoHal { public: Stm32wlxHal(): ArduinoHal(SubGhz.SPI, SubGhz.spi_settings) {} + /*! + \brief Pin mode override to handle STM32WL virtual pins. + \param dwPin Pin to set. + \param dwMode Mode to set. + */ void pinMode(uint32_t dwPin, uint32_t dwMode) { switch(dwPin) { case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: @@ -40,6 +49,11 @@ class Stm32wlxHal : public ArduinoHal { } } + /*! + \brief Digital write override to handle STM32WL virtual pins. + \param dwPin Pin to set. + \param dwVal Value to set. + */ void digitalWrite(uint32_t dwPin, uint32_t dwVal) { switch (dwPin) { case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS: @@ -61,6 +75,11 @@ class Stm32wlxHal : public ArduinoHal { } } + /*! + \brief Digital read override to handle STM32WL virtual pins. + \param dwPin Pin to set. + \returns Value read on the pin. + */ uint32_t digitalRead(uint32_t ulPin) { switch (ulPin) { case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY: diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 848433b8c8..4a04fd48de 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -964,7 +964,7 @@ class SX126x: public PhysicalLayer { /*! \brief Check whether the IRQ bit for RxTimeout is set - \returns \ref RxTimeout IRQ is set + \returns Whether RxTimeout IRQ is set */ bool isRxTimeout(); diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 3ea740acb5..5ea92db5b5 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -111,8 +111,7 @@ class SX1272: public SX127x { \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index fd3d4a94a2..113f417d0a 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -600,7 +600,7 @@ class SX127x: public PhysicalLayer { /*! \brief Initialization method. Will be called with appropriate parameters when calling initialization method from derived class. - \param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version. + \param chipVersions Array of possible values in SPI version register. Used to verify the connection and hardware version. \param numVersions Number of possible chip versions. \param syncWord %LoRa sync word. \param preambleLength Length of %LoRa transmission preamble in symbols. @@ -615,7 +615,7 @@ class SX127x: public PhysicalLayer { /*! \brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class. - \param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version. + \param chipVersions Array of possible values in SPI version register. Used to verify the connection and hardware version. \param numVersions Number of possible chip versions. \param freqDev Frequency deviation of the FSK transmission in kHz. \param rxBw Receiver bandwidth in kHz. @@ -928,7 +928,7 @@ class SX127x: public PhysicalLayer { /*! \brief Sets FSK automatic frequency correction bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode. - \param rxBw Receiver AFC bandwidth to be set (in kHz). + \param afcBw Receiver AFC bandwidth to be set (in kHz). \returns \ref status_codes */ int16_t setAFCBandwidth(float afcBw); @@ -1038,7 +1038,7 @@ class SX127x: public PhysicalLayer { /*! \brief Set modem in variable packet length mode. Available in FSK mode only. - \param len Maximum packet length. + \param maxLen Maximum packet length. \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK); @@ -1201,14 +1201,6 @@ class SX127x: public PhysicalLayer { */ int16_t setDIOPreambleDetect(bool usePreambleDetect); - /*! - \brief Gets recorded signal strength indicator. - \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. - \returns RSSI value in dBm. - */ - float getRSSI(bool packet, bool skipReceive, int16_t offset); - /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled \param dbm A dBm value between -127.5 and 0 inclusive @@ -1246,6 +1238,7 @@ class SX127x: public PhysicalLayer { int16_t getActiveModem(); int16_t setFrequencyRaw(float newFreq); int16_t setBitRateCommon(float br, uint8_t fracRegAddr); + float getRSSI(bool packet, bool skipReceive, int16_t offset); #if !RADIOLIB_GODMODE private: diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 54ed9c2569..cb63256612 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -460,7 +460,7 @@ class nRF24: public PhysicalLayer { /*! \brief Dummy encoding configuration method, to ensure PhysicalLayer compatibility. - \param sh Ignored. + \param encoding Ignored. \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index ea48630e94..d4ca58d64c 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -44,7 +44,7 @@ class AFSKClient { /*! \brief Stops transmitting audio tone. - \param freq Keep transmitter on - this may limit noise when switching transmitter on or off. + \param keepOn Keep transmitter on - this may limit noise when switching transmitter on or off. \returns \ref status_codes */ int16_t noTone(bool keepOn = false); diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index 66555334e5..7b14ad8891 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -29,17 +29,33 @@ /*! \defgroup mic_e_message_types Mic-E message types. - \{ */ + +/*! \brief Mic-E "Off duty" message. */ #define RADIOLIB_APRS_MIC_E_TYPE_OFF_DUTY 0b00000111 + +/*! \brief Mic-E "En route" message. */ #define RADIOLIB_APRS_MIC_E_TYPE_EN_ROUTE 0b00000110 + +/*! \brief Mic-E "In service" message. */ #define RADIOLIB_APRS_MIC_E_TYPE_IN_SERVICE 0b00000101 + +/*! \brief Mic-E "Returning" message. */ #define RADIOLIB_APRS_MIC_E_TYPE_RETURNING 0b00000100 + +/*! \brief Mic-E "Commited" message. */ #define RADIOLIB_APRS_MIC_E_TYPE_COMMITTED 0b00000011 + +/*! \brief Mic-E special message. */ #define RADIOLIB_APRS_MIC_E_TYPE_SPECIAL 0b00000010 + +/*! \brief Mic-E priority message. */ #define RADIOLIB_APRS_MIC_E_TYPE_PRIORITY 0b00000001 + +/*! \brief Mic-E emergency message. */ #define RADIOLIB_APRS_MIC_E_TYPE_EMERGENCY 0b00000000 + /*! \} */ @@ -97,9 +113,9 @@ class APRSClient { \param destCallsign Destination station callsign. \param destSSID Destination station SSID. \param lat Latitude as a null-terminated string. - \param long Longitude as a null-terminated string. + \param lon Longitude as a null-terminated string. \param msg Message to be transmitted. Defaults to NULL (no message). - \param msg Position timestamp. Defaults to NULL (no timestamp). + \param time Position timestamp. Defaults to NULL (no timestamp). \returns \ref status_codes */ int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL); diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h index b98479e4e4..045c2feba6 100644 --- a/src/protocols/BellModem/BellModem.h +++ b/src/protocols/BellModem/BellModem.h @@ -93,7 +93,7 @@ class BellClient: public AFSKClient, public RadioLibPrint { /*! \brief Set correction coefficient for tone length. - \param correction Timing correction factor, used to adjust the length of tones. + \param corr Timing correction factor, used to adjust the length of tones. Less than 1.0 leads to shorter tones, defaults to 1.0 (no correction). \returns \ref status_codes */ diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 25908fd0b4..22a0c41e95 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -9,6 +9,10 @@ #include "../PhysicalLayer/PhysicalLayer.h" +/*! + \class ExternalRadio + \brief Class to interface with external radio hardware. +*/ class ExternalRadio: public PhysicalLayer { public: #if defined(RADIOLIB_BUILD_ARDUINO) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 875ac7cb28..7d927cbbeb 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -199,11 +199,22 @@ #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) +/*! + \struct LoRaWANMacSpec_t + \brief MAC command specification structure. +*/ struct LoRaWANMacSpec_t { + /*! \brief Command ID */ const uint8_t cid; + + /*! \brief Uplink message length */ const uint8_t lenDn; + + /*! \brief Downlink message length */ const uint8_t lenUp; - const bool user; // whether this MAC command can be issued by a user or not + + /*! \brief Whether this MAC command can be issued by the user or not */ + const bool user; }; const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { @@ -277,7 +288,7 @@ enum LoRaWANSchemeSession_t { }; /*! - \struct LoRaWANChannelSpan_t + \struct LoRaWANChannel_t \brief Structure to save information about LoRaWAN channels. To save space, adjacent channels are saved in "spans". */ @@ -352,8 +363,10 @@ struct LoRaWANBand_t { /*! \brief Number of milliseconds per hour of allowed Time-on-Air */ uint32_t dutyCycle; - /*! \brief Maximum dwell time per message in milliseconds */ + /*! \brief Maximum dwell time per uplink message in milliseconds */ uint32_t dwellTimeUp; + + /*! \brief Maximum dwell time per downlink message in milliseconds */ uint32_t dwellTimeDn; /*! \brief A set of default uplink (TX) channels for frequency-type bands */ @@ -432,10 +445,18 @@ struct LoRaWANMacCommand_t { /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ uint8_t repeat; }; - +/*! + \struct LoRaWANMacCommandQueue_t + \brief Structure to hold information about a queue of MAC commands +*/ struct LoRaWANMacCommandQueue_t { + /*! \brief Number of commands in the queue */ uint8_t numCommands; + + /*! \brief Total length of the queue */ uint8_t len; + + /*! \brief MAC command buffer */ LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; }; @@ -477,10 +498,10 @@ struct LoRaWANEvent_t { class LoRaWANNode { public: - // Offset between TX and RX1 (such that RX1 has equal or lower DR) + /*! \brief Offset between TX and RX1 (such that RX1 has equal or lower DR) */ uint8_t rx1DrOffset = 0; - // RX2 channel properties - may be changed by MAC command + /*! \brief RX2 channel properties - may be changed by MAC command */ LoRaWANChannel_t rx2; /*! @@ -734,7 +755,7 @@ class LoRaWANNode { /*! \brief Set uplink datarate. This should not be used when ADR is enabled. - \param dr Datarate to use for uplinks. + \param drUp Datarate to use for uplinks. \returns \ref status_codes */ int16_t setDatarate(uint8_t drUp); @@ -768,7 +789,7 @@ class LoRaWANNode { /*! \brief Toggle adherence to dwellTime limits to on or off. \param enable Whether to adhere to dwellTime limits or not (default true). - \param msPerHour The maximum allowed Time-on-Air per uplink in milliseconds + \param msPerUplink The maximum allowed Time-on-Air per uplink in milliseconds (default 0 = maximum allowed for configured band). */ void setDwellTime(bool enable, uint32_t msPerUplink = 0); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 173c2939af..e30329ea19 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -4,22 +4,42 @@ #include "../../TypeDef.h" #include "../../Module.h" -// data rate structure interpretation in case LoRa is used +/*! + \struct LoRaRate_t + \brief Data rate structure interpretation in case LoRa is used +*/ struct LoRaRate_t { + /*! \brief LoRa spreading factor */ uint8_t spreadingFactor; + + /*! \brief LoRa bandwidth in kHz */ float bandwidth; + + /*! \brief LoRa coding rate */ uint8_t codingRate; }; -// data rate structure interpretation in case FSK is used +/*! + \struct FSKRate_t + \brief Data rate structure interpretation in case FSK is used +*/ struct FSKRate_t { + /*! \brief FSK bit rate in kbps */ float bitRate; + + /*! \brief FS frequency deviation in kHz*/ float freqDev; }; -// common data rate +/*! + \union DataRate_t + \brief Common data rate structure +*/ union DataRate_t { + /*! \brief Interpretation for LoRa modems */ LoRaRate_t lora; + + /*! \brief Interpretation for FSK modems */ FSKRate_t fsk; }; @@ -237,7 +257,7 @@ class PhysicalLayer { /*! \brief Sets FSK data encoding. Only available in FSK mode. Must be implemented in module class. - \param enc Encoding to be used. See \ref config_encoding for possible values. + \param encoding Encoding to be used. See \ref config_encoding for possible values. \returns \ref status_codes */ virtual int16_t setEncoding(uint8_t encoding); @@ -334,7 +354,7 @@ class PhysicalLayer { /*! \brief Check whether the IRQ bit for RxTimeout is set - \returns \ref RxTimeout IRQ is set + \returns Whether RxTimeout IRQ is set */ virtual bool isRxTimeout(); diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp index 94b7b33459..52e767beb5 100644 --- a/src/protocols/Print/Print.cpp +++ b/src/protocols/Print/Print.cpp @@ -152,7 +152,7 @@ size_t RadioLibPrint::print(double n, int digits) { return(RadioLibPrint::printFloat(n, digits)); } -size_t RadioLibPrint::println(const char* str) { +size_t RadioLibPrint::println(const char str[]) { size_t n = RadioLibPrint::print(str); n += RadioLibPrint::println(); return(n); diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index 48bd7e702b..72ba461501 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -10,7 +10,10 @@ #define RADIOLIB_ASCII_EXTENDED 1 #define RADIOLIB_ITA2 2 -// based on Arduino Print class +/*! + \class RadioLibPrint + \brief Printing class, based on Arduino Print class with additional encodings. +*/ class RadioLibPrint { public: virtual size_t write(uint8_t) = 0; From e7ee407b0dcb39f93ed184ce37b3c8e34c108ebd Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 1 Apr 2024 12:11:13 +0200 Subject: [PATCH 0979/1848] [Doc] Additional doxygen fixes --- src/Module.h | 2 +- src/modules/SX126x/STM32WLx_Module.cpp | 2 +- src/modules/SX126x/SX126x.h | 2 +- src/modules/SX127x/SX127x.h | 2 +- src/protocols/BellModem/BellModem.cpp | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Module.h b/src/Module.h index c61b74b81e..f5660e6800 100644 --- a/src/Module.h +++ b/src/Module.h @@ -13,7 +13,7 @@ #endif /*! - \brief Value to use as the last element in a mode table to indicate the + \def Value to use as the last element in a mode table to indicate the end of the table. See \ref setRfSwitchTable for details. */ diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 0e1191290b..0f48d9aa65 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -77,7 +77,7 @@ class Stm32wlxHal : public ArduinoHal { /*! \brief Digital read override to handle STM32WL virtual pins. - \param dwPin Pin to set. + \param ulPin Pin to read. \returns Value read on the pin. */ uint32_t digitalRead(uint32_t ulPin) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 4a04fd48de..d5cfd4c1cc 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -935,7 +935,7 @@ class SX126x: public PhysicalLayer { /*! \brief Set modem in variable packet length mode. Available in FSK mode only. - \param len Maximum packet length. + \param maxLen Maximum packet length. \returns \ref status_codes */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 113f417d0a..70713d8891 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1074,7 +1074,7 @@ class SX127x: public PhysicalLayer { /*! \brief Check whether the IRQ bit for RxTimeout is set - \returns \ref RxTimeout IRQ is set + \returns Whether RxTimeout IRQ is set */ bool isRxTimeout(); diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp index 8d08943ee6..bab036e99f 100644 --- a/src/protocols/BellModem/BellModem.cpp +++ b/src/protocols/BellModem/BellModem.cpp @@ -1,7 +1,7 @@ #include "BellModem.h" #if !RADIOLIB_EXCLUDE_BELL -const struct BellModem_t Bell101 { +const BellModem_t Bell101 = { .freqMark = 1270, .freqSpace = 1070, .baudRate = 110, @@ -9,7 +9,7 @@ const struct BellModem_t Bell101 { .freqSpaceReply = 2025, }; -const struct BellModem_t Bell103 { +const BellModem_t Bell103 = { .freqMark = 1270, .freqSpace = 1070, .baudRate = 300, @@ -17,7 +17,7 @@ const struct BellModem_t Bell103 { .freqSpaceReply = 2025, }; -const struct BellModem_t Bell202 { +const BellModem_t Bell202 = { .freqMark = 1200, .freqSpace = 2200, .baudRate = 1200, From fbee7471c72cedde2f8e62da6b136a754fddae50 Mon Sep 17 00:00:00 2001 From: Matthias Prinke <83612361+matthias-bs@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:03:38 +0200 Subject: [PATCH 0980/1848] [LoRaWAN] Added pin maps (#1047) * Added pin maps * Modified pin map for ARDUINO_TTGO_LORA32_V2 (DIO1 not connected & not needed) --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 11 ++++++++++- examples/LoRaWAN/LoRaWAN_Reference/config.h | 11 ++++++++++- examples/LoRaWAN/LoRaWAN_Starter/config.h | 11 ++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index a536ff1492..e79960a1da 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -53,7 +53,8 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + #pragma message ("ARDUINO_TTGO_LORA32_V2 + Display") + SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") @@ -71,6 +72,14 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") +#elif defined (ARDUINO_heltec_wireless_stick) + #pragma message ("Using Heltec Wireless Stick") + SX1278 radio = new Module(14, 4, 12, 16); + +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) + #pragma message ("Using Heltec WiFi LoRa32 v2") + SX1278 radio = new Module(14, 4, 12, 16); + #elif defined(ARDUINO_heltec_wifi_kit_32_V2) #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") SX1276 radio = new Module(18, 26, 14, 35); diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index cb681da2ff..d91e4a554e 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -48,7 +48,8 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + #pragma message ("ARDUINO_TTGO_LORA32_V2 + Display") + SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") @@ -66,6 +67,14 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") +#elif defined (ARDUINO_heltec_wireless_stick) + #pragma message ("Using Heltec Wireless Stick") + SX1278 radio = new Module(14, 4, 12, 16); + +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) + #pragma message ("Using Heltec WiFi LoRa32 v2") + SX1278 radio = new Module(14, 4, 12, 16); + #elif defined(ARDUINO_heltec_wifi_kit_32_V2) #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") SX1276 radio = new Module(18, 26, 14, 35); diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index cb681da2ff..d91e4a554e 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -48,7 +48,8 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map") + #pragma message ("ARDUINO_TTGO_LORA32_V2 + Display") + SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") @@ -66,6 +67,14 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") +#elif defined (ARDUINO_heltec_wireless_stick) + #pragma message ("Using Heltec Wireless Stick") + SX1278 radio = new Module(14, 4, 12, 16); + +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) + #pragma message ("Using Heltec WiFi LoRa32 v2") + SX1278 radio = new Module(14, 4, 12, 16); + #elif defined(ARDUINO_heltec_wifi_kit_32_V2) #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") SX1276 radio = new Module(18, 26, 14, 35); From a4ad32e6ff3186270936592fddb4ac74677cbf0c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 2 Apr 2024 22:24:06 +0200 Subject: [PATCH 0981/1848] [LoRaWAN] Fix downlink crashes (#1049), remove redundant parameter --- src/protocols/LoRaWAN/LoRaWAN.cpp | 32 ++++++++++++++++--------------- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a29aaf1b1b..bb51ea2419 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -583,7 +583,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); - // JoinNonce received must be greater than the last JoinNonce heard, else error + // JoinNonce received must be greater than the last JoinNonce heard, else error if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { return(RADIOLIB_ERR_JOIN_NONCE_INVALID); } @@ -898,11 +898,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; - size_t foptsBufSize = 0; if(this->commandsUp.numCommands > 0 && port != RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { // there are, assume the maximum possible FOpts len for buffer allocation foptsLen = this->commandsUp.len; - foptsBufSize = 15; } // check maximum payload len as defined in phy @@ -984,7 +982,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsBufSize); + size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); #if RADIOLIB_STATIC_ONLY uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -1021,8 +1019,12 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if we have some MAC commands to append if(foptsLen > 0) { + #if RADIOLIB_STATIC_ONLY // assume maximum possible buffer size - uint8_t foptsBuff[15]; + uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; + #else + uint8_t foptsBuff[foptsLen]; + #endif uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer @@ -1491,7 +1493,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #endif // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink - if(this->commandsUp.len > 15) { + if(this->commandsUp.len > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { size_t foptsBufSize = this->commandsUp.len; #if RADIOLIB_STATIC_ONLY uint8_t foptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -1549,7 +1551,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // a downlink was received, so reset the ADR counter to the last uplink's fcnt - this->adrFcnt = this->fcntUp - 1; + this->adrFcnt = this->getFcntUp(); // pass the extra info if requested if(event) { @@ -2180,13 +2182,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state // but we don't bother and try to set each individual command uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; - uint8_t txPower = cmd->payload[0] & 0x0F; + uint8_t txSteps = cmd->payload[0] & 0x0F; bool isInternalTxDr = cmd->payload[3] >> 7; uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; uint8_t nbTrans = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txPower = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txPower, chMask, chMaskCntl, nbTrans); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTrans); // apply the configuration uint8_t drAck = 0; @@ -2216,14 +2218,14 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // try to apply the power configuration uint8_t pwrAck = 0; - if(txPower == 0x0F) { + if(txSteps == 0x0F) { pwrAck = 1; // replace the 'placeholder' with the current actual value for saving cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; } else { - int8_t pwr = this->txPowerMax - 2*txPower; + int8_t pwr = this->txPowerMax - 2*txSteps; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr); state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { @@ -2233,7 +2235,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // only acknowledge if the requested datarate was succesfully configured if(state == RADIOLIB_ERR_NONE) { pwrAck = 1; - this->txPowerCur = txPower; + this->txPowerCur = txSteps; } } @@ -2765,7 +2767,7 @@ uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { } int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { - uint8_t payload[5]; + uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); RADIOLIB_ASSERT(state); @@ -2776,14 +2778,14 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { } int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { - uint8_t payload[5]; + uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); RADIOLIB_ASSERT(state); if(gpsEpoch) { *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); if(returnUnix) { - uint32_t unixOffset = 315964800 - 18; // 18 leap seconds since GPS epoch (Jan. 6th 1980) + uint32_t unixOffset = 315964800UL - 18UL; // 18 leap seconds since GPS epoch (Jan. 6th 1980) *gpsEpoch += unixOffset; } } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 7d927cbbeb..37e1c04356 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -136,7 +136,7 @@ #define RADIOLIB_LORAWAN_FHDR_FCNT_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 6) #define RADIOLIB_LORAWAN_FHDR_FOPTS_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8) #define RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK (0x0F) -#define RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 16) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN (15) #define RADIOLIB_LORAWAN_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8 + (FOPTS)) #define RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 9 + (FOPTS)) #define RADIOLIB_LORAWAN_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) From aa46a0c8b3f4943a6ab8ff90a22f19c25d912e8e Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 2 Apr 2024 22:25:50 +0200 Subject: [PATCH 0982/1848] [LoRaWAN] Hide broken CSMA --- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 6 +----- src/protocols/LoRaWAN/LoRaWAN.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index ad49a261c0..608fb82f9f 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -60,13 +60,9 @@ void setup() { // Disable the ADR algorithm (on by default which is preferable) node.setADR(false); - // Set a fixed datarate & make it persistent (not normal) + // Set a fixed datarate node.setDatarate(4); - // Enable CSMA which tries to minimize packet loss by searching - // for a free channel before actually sending an uplink - node.setCSMA(6, 2, true); - // Manages uplink intervals to the TTN Fair Use Policy node.setDutyCycle(true, 1250); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 37e1c04356..d2f05e9b93 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -808,14 +808,6 @@ class LoRaWANNode { */ int16_t setTxPower(int8_t txPower); - /*! - \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. - \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. - \param difsSlots Num of CADs to estimate a clear CH. - \param enableCSMA enable/disable CSMA for LoRaWAN. - */ - void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); - /*! \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. Returns 'true' if a network response was successfully parsed. @@ -1017,6 +1009,14 @@ class LoRaWANNode { // get the payload length for a specific MAC command uint8_t getMacPayloadLength(uint8_t cid); + /*! + \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. + \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. + \param difsSlots Num of CADs to estimate a clear CH. + \param enableCSMA enable/disable CSMA for LoRaWAN. + */ + void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); + // Performs CSMA as per LoRa Alliance Technical Recommendation 13 (TR-013). void performCSMA(); From 5d741779a1badda90f20b7e6a320f958c6069ef9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 4 Apr 2024 21:27:12 +0200 Subject: [PATCH 0983/1848] [SX126x] Use predefined image calibration bands (#1051) --- src/modules/SX126x/SX1262.cpp | 37 +++++++++++++++++++++++++++++++++-- src/modules/SX126x/SX1262.h | 5 +---- src/modules/SX126x/SX1268.cpp | 31 +++++++++++++++++++++++++++-- src/modules/SX126x/SX1268.h | 5 +---- src/modules/SX126x/SX126x.h | 23 +++++++++++++++++++++- 5 files changed, 88 insertions(+), 13 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 0bbce30d4e..7400da47db 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -51,13 +51,46 @@ int16_t SX1262::setFrequency(float freq) { return(setFrequency(freq, true)); } -int16_t SX1262::setFrequency(float freq, bool calibrate, float band) { +int16_t SX1262::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); // calibrate image rejection if(calibrate) { - int16_t state = SX126x::calibrateImage(freq - band, freq + band); + uint8_t data[2] = { 0, 0 }; + + // try to match the frequency ranges + int freqBand = (int)freq; + if((freq >= 902) && (freq <= 928)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2; + } else if((freq >= 863) && (freq <= 870)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; + } else if((freq >= 779) && (freq <= 787)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; + } else if((freq >= 470) && (freq <= 510)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; + } else if((freq >= 430) && (freq <= 440)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; + } + + int16_t state; + if(data[0]) { + // matched with predefined ranges, do the calibration + state = SX126x::calibrateImage(data); + + } else { + // if nothing matched, try custom calibration - the may or may not work + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom"); + state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f); + + } + RADIOLIB_ASSERT(state); + } // set frequency diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 61f8facc73..f47b1a8131 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -75,12 +75,9 @@ class SX1262: public SX126x { \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \param freq Carrier frequency to be set in MHz. \param calibrate Run image calibration. - \param band Half bandwidth for image calibration. For example, - if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate - for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate, float band = 4); + int16_t setFrequency(float freq, bool calibrate); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 7f14e9fae9..2b00d55073 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -52,13 +52,40 @@ int16_t SX1268::setFrequency(float freq) { } /// \todo integers only (all modules - frequency, data rate, bandwidth etc.) -int16_t SX1268::setFrequency(float freq, bool calibrate, float band) { +int16_t SX1268::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); // calibrate image rejection if(calibrate) { - int16_t state = SX126x::calibrateImage(freq - band, freq + band); + uint8_t data[2] = { 0, 0 }; + + // try to match the frequency ranges + int freqBand = (int)freq; + if((freq >= 779) && (freq <= 787)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; + } else if((freq >= 470) && (freq <= 510)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; + } else if((freq >= 430) && (freq <= 440)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; + } + + int16_t state; + if(data[0]) { + // matched with predefined ranges, do the calibration + state = SX126x::calibrateImage(data); + + } else { + // if nothing matched, try custom calibration - the may or may not work + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom"); + state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f); + + } + RADIOLIB_ASSERT(state); + } // set frequency diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index f3f61dc86d..04edba39f5 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -74,12 +74,9 @@ class SX1268: public SX126x { \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \param freq Carrier frequency to be set in MHz. \param calibrate Run image calibration. - \param band Half bandwidth for image calibration. For example, - if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate - for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate, float band = 4); + int16_t setFrequency(float freq, bool calibrate); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d5cfd4c1cc..d2b9ecfeff 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -188,6 +188,18 @@ #define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled #define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks +//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 + //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 #define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 @@ -1102,6 +1114,15 @@ class SX126x: public PhysicalLayer { */ int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); + /*! + \brief Perform image rejection calibration for the specified frequency band. + WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance + \param freqMin Frequency band lower bound. + \param freqMax Frequency band upper bound. + \returns \ref status_codes + */ + int16_t calibrateImageRejection(float freqMin, float freqMax); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -1119,7 +1140,7 @@ class SX126x: public PhysicalLayer { int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); - int16_t calibrateImage(float freqMin, float freqMax); + int16_t calibrateImage(uint8_t* data); uint8_t getPacketType(); int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); From a387b3b70648ffb7714b01c17bfdb7bbc7071e0a Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 4 Apr 2024 21:28:17 +0200 Subject: [PATCH 0984/1848] [SX126x] Fix image calibration (#1051) --- src/modules/SX126x/SX126x.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2c029e5475..c0db2f846c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1841,8 +1841,13 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } -int16_t SX126x::calibrateImage(float freqMin, float freqMax) { +int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) { + // calculate the calibration coefficients and calibrate image uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) }; + return(this->calibrateImage(data)); +} + +int16_t SX126x::calibrateImage(uint8_t* data) { int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors From 263f7883cf222f8ccb79788e68a653eab17d88e6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 4 Apr 2024 21:31:09 +0200 Subject: [PATCH 0985/1848] [SX126x] Use integer frequency for band selection --- src/modules/SX126x/SX1262.cpp | 10 +++++----- src/modules/SX126x/SX1268.cpp | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 7400da47db..807b80d6d9 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -60,19 +60,19 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) { // try to match the frequency ranges int freqBand = (int)freq; - if((freq >= 902) && (freq <= 928)) { + if((freqBand >= 902) && (freqBand <= 928)) { data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2; - } else if((freq >= 863) && (freq <= 870)) { + } else if((freqBand >= 863) && (freqBand <= 870)) { data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; - } else if((freq >= 779) && (freq <= 787)) { + } else if((freqBand >= 779) && (freqBand <= 787)) { data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; - } else if((freq >= 470) && (freq <= 510)) { + } else if((freqBand >= 470) && (freqBand <= 510)) { data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else if((freq >= 430) && (freq <= 440)) { + } else if((freqBand >= 430) && (freqBand <= 440)) { data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; } diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 2b00d55073..86df6fa5cf 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -61,13 +61,13 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) { // try to match the frequency ranges int freqBand = (int)freq; - if((freq >= 779) && (freq <= 787)) { + if((freqBand >= 779) && (freqBand <= 787)) { data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; - } else if((freq >= 470) && (freq <= 510)) { + } else if((freqBand >= 470) && (freqBand <= 510)) { data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else if((freq >= 430) && (freq <= 440)) { + } else if((freqBand >= 430) && (freqBand <= 440)) { data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; } From f61be0d273372c502578dee4a2b9bc7af59af2dc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 5 Apr 2024 17:30:05 +0200 Subject: [PATCH 0986/1848] [SX126x] Added public method to set PA ramp time (#1054) --- keywords.txt | 1 + src/modules/SX126x/SX1261.cpp | 5 ++--- src/modules/SX126x/SX1262.cpp | 5 ++--- src/modules/SX126x/SX1268.cpp | 5 ++--- src/modules/SX126x/SX126x.cpp | 10 +++++++++- src/modules/SX126x/SX126x.h | 9 ++++++++- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/keywords.txt b/keywords.txt index d9d5950728..2fee742103 100644 --- a/keywords.txt +++ b/keywords.txt @@ -225,6 +225,7 @@ spectralScanStart KEYWORD2 spectralScanAbort KEYWORD2 spectralScanGetStatus KEYWORD2 spectralScanGetResult KEYWORD2 +setPaRampTime KEYWORD2 # nRF24 setIrqAction KEYWORD2 diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index dd39bfef0f..cabe2b5791 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -17,9 +17,8 @@ int16_t SX1261::setOutputPower(int8_t power) { state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1261, 0x00); RADIOLIB_ASSERT(state); - // set output power - /// \todo power ramp time configuration - state = SX126x::setTxParams(power); + // set output power with default 200us ramp + state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); RADIOLIB_ASSERT(state); // restore OCP configuration diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 807b80d6d9..036cba0ada 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -109,9 +109,8 @@ int16_t SX1262::setOutputPower(int8_t power) { state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1262); RADIOLIB_ASSERT(state); - // set output power - /// \todo power ramp time configuration - state = SX126x::setTxParams(power); + // set output power with default 200us ramp + state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); RADIOLIB_ASSERT(state); // restore OCP configuration diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 86df6fa5cf..1b63c4d069 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -104,9 +104,8 @@ int16_t SX1268::setOutputPower(int8_t power) { state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1268); RADIOLIB_ASSERT(state); - // set output power - /// \todo power ramp time configuration - state = SX126x::setTxParams(power); + // set output power with default 200us ramp + state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); RADIOLIB_ASSERT(state); // restore OCP configuration diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c0db2f846c..fe633fe055 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1847,6 +1847,10 @@ int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) { return(this->calibrateImage(data)); } +int16_t SX126x::setPaRampTime(uint8_t rampTime) { + return(this->setTxParams(this->pwr, rampTime)); +} + int16_t SX126x::calibrateImage(uint8_t* data) { int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); @@ -1870,7 +1874,11 @@ uint8_t SX126x::getPacketType() { int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) { uint8_t data[] = { pwr, rampTime }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2)); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2); + if(state == RADIOLIB_ERR_NONE) { + this->pwr = pwr; + } + return(state); } int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d2b9ecfeff..ec25fb66bc 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1123,6 +1123,12 @@ class SX126x: public PhysicalLayer { */ int16_t calibrateImageRejection(float freqMin, float freqMax); + /*! + \brief Set PA ramp-up time. Set to 200us by default. + \returns \ref status_codes + */ + int16_t setPaRampTime(uint8_t rampTime); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -1142,7 +1148,7 @@ class SX126x: public PhysicalLayer { int16_t setRfFrequency(uint32_t frf); int16_t calibrateImage(uint8_t* data); uint8_t getPacketType(); - int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U); + int16_t setTxParams(uint8_t power, uint8_t rampTime); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev); int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ); @@ -1187,6 +1193,7 @@ class SX126x: public PhysicalLayer { float dataRateMeasured = 0; uint32_t tcxoDelay = 0; + uint8_t pwr = 0; size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; From 4fa0656ddd75dd1c50eab918c6f1e5ca08a18141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 7 Apr 2024 17:05:07 +0200 Subject: [PATCH 0987/1848] [MOD] SPI configuration interface rework (#1057) * [MOD] Rework SPI config interface * [CC1101] Rework SPI config interface * [nRF24] Rework SPI config interface * [SX126x] Rework SPI config interface * [SX128x] Rework SPI config interface * Fix missing moved debug info * [MOD] Fix signed warnings --- src/BuildOpt.h | 11 +++ src/Module.cpp | 168 ++++++++++++++++++++++------------ src/Module.h | 135 ++++++++++++++++----------- src/RadioLib.h | 11 +-- src/modules/CC1101/CC1101.cpp | 4 +- src/modules/SX126x/SX126x.cpp | 30 +++--- src/modules/SX128x/SX128x.cpp | 60 +++++++----- src/modules/nRF24/nRF24.cpp | 4 +- 8 files changed, 264 insertions(+), 159 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 9b25d3fec1..f220e46d59 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -529,6 +529,17 @@ #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {} #endif +// debug info strings +#define RADIOLIB_VALUE_TO_STRING(x) #x +#define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) + +#define RADIOLIB_INFO "\nRadioLib Info\nVersion: \"" \ + RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ + RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \ + "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \ + "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) /*! \brief A simple assert macro, will return on error. diff --git a/src/Module.cpp b/src/Module.cpp index c46e26e9c3..3d8872bfe7 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -31,8 +31,7 @@ Module::Module(const Module& mod) { } Module& Module::operator=(const Module& mod) { - this->SPIreadCommand = mod.SPIreadCommand; - this->SPIwriteCommand = mod.SPIwriteCommand; + memcpy((void*)&mod.spiConfig, &this->spiConfig, sizeof(SPIConfig_t)); this->csPin = mod.csPin; this->irqPin = mod.irqPin; this->rstPin = mod.rstPin; @@ -40,14 +39,12 @@ Module& Module::operator=(const Module& mod) { return(*this); } +static const char info[] = RADIOLIB_INFO; void Module::init() { this->hal->init(); this->hal->pinMode(csPin, this->hal->GpioModeOutput); this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh); - RADIOLIB_DEBUG_BASIC_PRINTLN("RadioLib Debug Info"); - RADIOLIB_DEBUG_BASIC_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA); - RADIOLIB_DEBUG_BASIC_PRINTLN("Platform: " RADIOLIB_PLATFORM); - RADIOLIB_DEBUG_BASIC_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n"); + RADIOLIB_DEBUG_BASIC_PRINTLN(RADIOLIB_INFO); } void Module::term() { @@ -55,7 +52,7 @@ void Module::term() { this->hal->term(); } -int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) { +int16_t Module::SPIgetRegValue(uint32_t reg, uint8_t msb, uint8_t lsb) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } @@ -65,7 +62,7 @@ int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) { return(maskedValue); } -int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { +int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } @@ -104,47 +101,75 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t #endif } -void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes) { - if(!SPIstreamType) { - SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); +void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inBytes) { + if(!this->spiConfig.stream) { + SPItransfer(this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ], reg, NULL, inBytes, numBytes); } else { - uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); + uint8_t cmd[6]; + uint8_t* cmdPtr = cmd; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF; + } + for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + *(cmdPtr++) = (reg >> 8*i) & 0xFF; + } + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); } } -uint8_t Module::SPIreadRegister(uint16_t reg) { +uint8_t Module::SPIreadRegister(uint32_t reg) { uint8_t resp = 0; - if(!SPIstreamType) { - SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); + if(!spiConfig.stream) { + SPItransfer(this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ], reg, NULL, &resp, 1); } else { - uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + uint8_t cmd[6]; + uint8_t* cmdPtr = cmd; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF; + } + for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + *(cmdPtr++) = (reg >> 8*i) & 0xFF; + } + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); } return(resp); } -void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) { - if(!SPIstreamType) { - SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); +void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) { + if(!spiConfig.stream) { + SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], reg, data, NULL, numBytes); } else { - uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); + uint8_t cmd[6]; + uint8_t* cmdPtr = cmd; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF; + } + for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + *(cmdPtr++) = (reg >> 8*i) & 0xFF; + } + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); } } -void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { - if(!SPIstreamType) { - SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); +void Module::SPIwriteRegister(uint32_t reg, uint8_t data) { + if(!spiConfig.stream) { + SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], reg, &data, NULL, 1); } else { - uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) }; - SPItransferStream(cmd, 3, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + uint8_t cmd[6]; + uint8_t* cmdPtr = cmd; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF; + } + for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + *(cmdPtr++) = (reg >> 8*i) & 0xFF; + } + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); } } -void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { +void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { // prepare the buffers - size_t buffLen = this->SPIaddrWidth/8 + numBytes; + size_t buffLen = this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8 + numBytes; #if RADIOLIB_STATIC_ONLY uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -155,7 +180,8 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d uint8_t* buffOutPtr = buffOut; // copy the command - if(this->SPIaddrWidth <= 8) { + // TODO properly handle variable commands and addresses + if(this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] <= 8) { *(buffOutPtr++) = reg | cmd; } else { *(buffOutPtr++) = (reg >> 8) | cmd; @@ -163,10 +189,10 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d } // copy the data - if(cmd == SPIwriteCommand) { + if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) { memcpy(buffOutPtr, dataOut, numBytes); } else { - memset(buffOutPtr, this->SPInopCommand, numBytes); + memset(buffOutPtr, this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP], numBytes); } // do the transfer @@ -177,19 +203,19 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d this->hal->spiEndTransaction(); // copy the data - if(cmd == SPIreadCommand) { - memcpy(dataIn, &buffIn[this->SPIaddrWidth/8], numBytes); + if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ]) { + memcpy(dataIn, &buffIn[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8], numBytes); } // print debug information #if RADIOLIB_DEBUG_SPI uint8_t* debugBuffPtr = NULL; - if(cmd == SPIwriteCommand) { + if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) { RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg); - debugBuffPtr = &buffOut[this->SPIaddrWidth/8]; - } else if(cmd == SPIreadCommand) { + debugBuffPtr = &buffOut[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8]; + } else if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ]) { RADIOLIB_DEBUG_SPI_PRINT("R\t%X\t", reg); - debugBuffPtr = &buffIn[this->SPIaddrWidth/8]; + debugBuffPtr = &buffIn[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8]; } for(size_t n = 0; n < numBytes; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]); @@ -203,8 +229,13 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d #endif } -int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { - return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify)); +int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { + uint8_t cmdBuf[2]; + uint8_t* cmdPtr = cmdBuf; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = (cmd >> 8*i) & 0xFF; + } + return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); } int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { @@ -212,16 +243,27 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_ int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); + #if !RADIOLIB_SPI_PARANOID + (void)verify; + return(RADIOLIB_ERR_NONE); + #else + // check the status - if(verify) { - state = this->SPIcheckStream(); + if(verify && (this->spiConfig.checkStatusCb != nullptr)) { + state = this->spiConfig.checkStatusCb(this); } return(state); + #endif } -int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { - return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify)); +int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { + uint8_t cmdBuf[2]; + uint8_t* cmdPtr = cmdBuf; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = (cmd >> 8*i) & 0xFF; + } + return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); } int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { @@ -229,12 +271,18 @@ int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); + #if !RADIOLIB_SPI_PARANOID + (void)verify; + return(RADIOLIB_ERR_NONE); + #else + // check the status - if(verify) { - state = this->SPIcheckStream(); + if(verify && (this->spiConfig.checkStatusCb != nullptr)) { + state = this->spiConfig.checkStatusCb(this); } return(state); + #endif } int16_t Module::SPIcheckStream() { @@ -243,13 +291,17 @@ int16_t Module::SPIcheckStream() { #if RADIOLIB_SPI_PARANOID // get the status uint8_t spiStatus = 0; - uint8_t cmd = this->SPIstatusCommand; - state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 0, true, RADIOLIB_MODULE_SPI_TIMEOUT); + uint8_t cmdBuf[2]; + uint8_t* cmdPtr = cmdBuf; + for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + *(cmdPtr++) = ( this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] >> 8*i) & 0xFF; + } + state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); RADIOLIB_ASSERT(state); // translate to RadioLib status code - if(this->SPIparseStatusCb != nullptr) { - this->SPIstreamError = this->SPIparseStatusCb(spiStatus); + if(this->spiConfig.parseStatusCb != nullptr) { + this->spiConfig.err = this->spiConfig.parseStatusCb(spiStatus); } #endif @@ -260,7 +312,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // prepare the buffers size_t buffLen = cmdLen + numBytes; if(!write) { - buffLen++; + buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8); } #if RADIOLIB_STATIC_ONLY uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -280,12 +332,12 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint if(write) { memcpy(buffOutPtr, dataOut, numBytes); } else { - memset(buffOutPtr, this->SPInopCommand, numBytes + 1); + memset(buffOutPtr, this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP], numBytes + (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8)); } // ensure GPIO is low if(this->gpioPin == RADIOLIB_NC) { - this->hal->delay(1); + this->hal->delay(50); } else { uint32_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { @@ -331,14 +383,14 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint // parse status int16_t state = RADIOLIB_ERR_NONE; - if((this->SPIparseStatusCb != nullptr) && (numBytes > 0)) { - state = this->SPIparseStatusCb(buffIn[cmdLen]); + if((this->spiConfig.parseStatusCb != nullptr) && (numBytes > 0)) { + state = this->spiConfig.parseStatusCb(buffIn[this->spiConfig.statusPos]); } // copy the data if(!write) { - // skip the first byte for read-type commands (status-only) - memcpy(dataIn, &buffIn[cmdLen + 1], numBytes); + // skip the status bytes if present + memcpy(dataIn, &buffIn[cmdLen + (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8)], numBytes); } // print debug information diff --git a/src/Module.h b/src/Module.h index f5660e6800..0341a5b2ac 100644 --- a/src/Module.h +++ b/src/Module.h @@ -13,15 +13,53 @@ #endif /*! - \def Value to use as the last element in a mode table to indicate the - end of the table. - See \ref setRfSwitchTable for details. + \def END_OF_MODE_TABLE Value to use as the last element in a mode table to indicate the + end of the table. See \ref setRfSwitchTable for details. */ #define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } // default timeout for SPI transfers #define RADIOLIB_MODULE_SPI_TIMEOUT (1000) +/*! + \defgroup module_spi_command_pos Position of commands in Module::spiConfig command array. + \{ +*/ + +/*! \def RADIOLIB_MODULE_SPI_COMMAND_READ Position of the read command. */ +#define RADIOLIB_MODULE_SPI_COMMAND_READ (0) + +/*! \def RADIOLIB_MODULE_SPI_COMMAND_WRITE Position of the write command. */ +#define RADIOLIB_MODULE_SPI_COMMAND_WRITE (1) + +/*! \def RADIOLIB_MODULE_SPI_COMMAND_NOP Position of the no-operation command. */ +#define RADIOLIB_MODULE_SPI_COMMAND_NOP (2) + +/*! \def RADIOLIB_MODULE_SPI_COMMAND_STATUS Position of the status command. */ +#define RADIOLIB_MODULE_SPI_COMMAND_STATUS (3) + +/*! + \} +*/ + +/*! + \defgroup module_spi_width_pos Position of bit field widths in Module::spiConfig width array. + \{ +*/ + +/*! \def RADIOLIB_MODULE_SPI_WIDTH_ADDR Position of the address width. */ +#define RADIOLIB_MODULE_SPI_WIDTH_ADDR (0) + +/*! \def RADIOLIB_MODULE_SPI_WIDTH_CMD Position of the command width. */ +#define RADIOLIB_MODULE_SPI_WIDTH_CMD (1) + +/*! \def RADIOLIB_MODULE_SPI_WIDTH_STATUS Position of the status width. */ +#define RADIOLIB_MODULE_SPI_WIDTH_STATUS (2) + +/*! + \} +*/ + /*! \class Module \brief Implements all common low-level methods to control the wireless module. @@ -121,57 +159,52 @@ class Module { Module& operator=(const Module& mod); // public member variables - /*! - \brief Hardware abstraction layer to be used. - */ + /*! \brief Hardware abstraction layer to be used. */ RadioLibHal* hal = NULL; - /*! - \brief Basic SPI read command. Defaults to 0x00. - */ - uint8_t SPIreadCommand = 0b00000000; + /*! \brief Callback for parsing SPI status. */ + typedef int16_t (*SPIparseStatusCb_t)(uint8_t in); - /*! - \brief Basic SPI write command. Defaults to 0x80. - */ - uint8_t SPIwriteCommand = 0b10000000; + /*! \brief Callback for validation SPI status. */ + typedef int16_t (*SPIcheckStatusCb_t)(Module* mod); /*! - \brief Basic SPI no-operation command. Defaults to 0x00. + \struct SPIConfig_t + \brief SPI configuration structure. */ - uint8_t SPInopCommand = 0x00; + struct SPIConfig_t { + /*! \brief Whether the SPI module is stream-type (SX126x/8x) or registrer access type (SX127x, CC1101 etc). */ + bool stream; - /*! - \brief Basic SPI status read command. Defaults to 0x00. - */ - uint8_t SPIstatusCommand = 0x00; + /*! \brief Last recorded SPI error - only updated for modules that return status during SPI transfers. */ + int16_t err; - /*! - \brief SPI address width. Defaults to 8, currently only supports 8 and 16-bit addresses. - */ - uint8_t SPIaddrWidth = 8; + /*! \brief SPI commands */ + uint16_t cmds[4]; - /*! - \brief Whether the SPI interface is stream-type (e.g. SX126x) or register-type (e.g. SX127x). - Defaults to register-type SPI interfaces. - */ - bool SPIstreamType = false; + /*! \brief Bit widths of SPI addresses, commands and status bytes */ + size_t widths[3]; - /*! - \brief The last recorded SPI stream error. - */ - int16_t SPIstreamError = RADIOLIB_ERR_UNKNOWN; + /*! \brief Byte position of status command in SPI stream */ + uint8_t statusPos; - /*! - \brief SPI status parsing callback typedef. - */ - typedef int16_t (*SPIparseStatusCb_t)(uint8_t in); + /*! \brief Callback for parsing SPI status. */ + SPIparseStatusCb_t parseStatusCb; - /*! - \brief Callback to function that will parse the module-specific status codes to RadioLib status codes. - Typically used for modules with SPI stream-type interface (e.g. SX126x/SX128x). - */ - SPIparseStatusCb_t SPIparseStatusCb = nullptr; + /*! \brief Callback for validation SPI status. */ + SPIcheckStatusCb_t checkStatusCb; + }; + + /*! \brief SPI configuration structure. The default configuration corresponds to register-access modules, such as SX127x. */ + SPIConfig_t spiConfig = { + .stream = false, + .err = RADIOLIB_ERR_UNKNOWN, + .cmds = { 0x00, 0x80, 0x00, 0x00 }, + .widths = { 8, 0, 8 }, + .statusPos = 0, + .parseStatusCb = nullptr, + .checkStatusCb = nullptr, + }; #if RADIOLIB_INTERRUPT_TIMING @@ -213,7 +246,7 @@ class Module { \param lsb Least significant bit of the register variable. Bits below this one will be masked out. \returns Masked register value or status code. */ - int16_t SPIgetRegValue(uint16_t reg, uint8_t msb = 7, uint8_t lsb = 0); + int16_t SPIgetRegValue(uint32_t reg, uint8_t msb = 7, uint8_t lsb = 0); /*! \brief Overwrite-safe SPI write method with verification. This method is the preferred SPI write mechanism. @@ -225,7 +258,7 @@ class Module { \param checkMask Mask of bits to check, only bits set to 1 will be verified. \returns \ref status_codes */ - int16_t SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); + int16_t SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); /*! \brief SPI burst read method. @@ -233,14 +266,14 @@ class Module { \param numBytes Number of bytes that will be read. \param inBytes Pointer to array that will hold the read data. */ - void SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes); + void SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inBytes); /*! \brief SPI basic read method. Use of this method is reserved for special cases, SPIgetRegValue should be used instead. \param reg Address of SPI register to read. \returns Value that was read from register. */ - uint8_t SPIreadRegister(uint16_t reg); + uint8_t SPIreadRegister(uint32_t reg); /*! \brief SPI burst write method. @@ -248,14 +281,14 @@ class Module { \param data Pointer to array that holds the data that will be written. \param numBytes Number of bytes that will be written. */ - void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes); + void SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes); /*! \brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead. \param reg Address of SPI register to write. \param data Value that will be written to the register. */ - void SPIwriteRegister(uint16_t reg, uint8_t data); + void SPIwriteRegister(uint32_t reg, uint8_t data); /*! \brief SPI single transfer method. @@ -265,7 +298,7 @@ class Module { \param dataIn Data that was transferred from slave to master. \param numBytes Number of bytes to transfer. */ - void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); + void SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); /*! \brief Method to check the result of last SPI stream transfer. @@ -282,7 +315,7 @@ class Module { \param verify Whether to verify the result of the transaction after it is finished. \returns \ref status_codes */ - int16_t SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a read transaction with SPI stream. @@ -305,7 +338,7 @@ class Module { \param verify Whether to verify the result of the transaction after it is finished. \returns \ref status_codes */ - int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. diff --git a/src/RadioLib.h b/src/RadioLib.h index 0e3d7f6d1f..94b8016c60 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -53,16 +53,7 @@ // print debug info #if RADIOLIB_DEBUG - #define RADIOLIB_VALUE_TO_STRING(x) #x - #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) - #pragma message("\nRadioLib Debug Info\nVersion: \"" \ - RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ - RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ - RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ - RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \ - "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \ - "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) \ - ) + #pragma message(RADIOLIB_INFO) #endif // check unknown/unsupported platform diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index af7f1df997..f8d2bd5afe 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -8,8 +8,8 @@ CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SI int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { // set module properties - this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ; - this->mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_CC1101_CMD_READ; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_CC1101_CMD_WRITE; this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index fe633fe055..fea71c9572 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -14,12 +14,15 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; - this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; - this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; - this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; - this->mod->SPIstreamType = true; - this->mod->SPIparseStatusCb = SPIparseStatus; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; // try to find the SX126x chip if(!SX126x::findChip(this->chipType)) { @@ -99,12 +102,15 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER; - this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER; - this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP; - this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS; - this->mod->SPIstreamType = true; - this->mod->SPIparseStatusCb = SPIparseStatus; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; // try to find the SX126x chip if(!SX126x::findChip(this->chipType)) { diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 2df75594de..4bd6da73a2 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -11,12 +11,15 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->SPIstreamType = true; - this->mod->SPIparseStatusCb = SPIparseStatus; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize LoRa modulation variables @@ -72,12 +75,15 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->SPIstreamType = true; - this->mod->SPIparseStatusCb = SPIparseStatus; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize GFSK modulation variables @@ -141,12 +147,15 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->SPIstreamType = true; - this->mod->SPIparseStatusCb = SPIparseStatus; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize BLE modulation variables @@ -196,12 +205,15 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1 this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP; - this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->SPIstreamType = true; - this->mod->SPIparseStatusCb = SPIparseStatus; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); // initialize FLRC modulation variables diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 40678b8c41..0e9d45c19f 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -8,8 +8,8 @@ nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RA int16_t nRF24::begin(int16_t freq, int16_t dr, int8_t pwr, uint8_t addrWidth) { // set module properties - this->mod->SPIreadCommand = RADIOLIB_NRF24_CMD_READ; - this->mod->SPIwriteCommand = RADIOLIB_NRF24_CMD_WRITE; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_NRF24_CMD_READ; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_NRF24_CMD_WRITE; this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); From f982314858fb47e60c8545af0583a034a1c29f0f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 Apr 2024 16:13:33 +0100 Subject: [PATCH 0988/1848] Eanble all warnings in CMake --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 680864d287..2291050918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,12 @@ target_include_directories(RadioLib PUBLIC $ $) +# use c++20 standard +set_property(TARGET RadioLib PROPERTY CXX_STANDARD 20) + +# enable most warnings +target_compile_options(RadioLib PRIVATE -Wall -Wextra) + include(GNUInstallDirs) install(TARGETS RadioLib From c9d8c601dfc972f196780ee6059eafa887afc9ec Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 Apr 2024 17:34:31 +0100 Subject: [PATCH 0989/1848] [Mod] Use enum for bit widths --- src/Module.cpp | 24 ++++++++++++------------ src/Module.h | 11 +++++++++-- src/modules/SX126x/SX126x.cpp | 8 ++++---- src/modules/SX128x/SX128x.cpp | 16 ++++++++-------- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 3d8872bfe7..d17caf9f90 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -39,7 +39,7 @@ Module& Module::operator=(const Module& mod) { return(*this); } -static const char info[] = RADIOLIB_INFO; +static volatile const char info[] = RADIOLIB_INFO; void Module::init() { this->hal->init(); this->hal->pinMode(csPin, this->hal->GpioModeOutput); @@ -107,10 +107,10 @@ void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inByte } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF; } - for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); @@ -124,10 +124,10 @@ uint8_t Module::SPIreadRegister(uint32_t reg) { } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF; } - for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); @@ -141,10 +141,10 @@ void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF; } - for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); @@ -157,10 +157,10 @@ void Module::SPIwriteRegister(uint32_t reg, uint8_t data) { } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF; } - for(int8_t i = (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1; i >= 0; i--) { + for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); @@ -232,7 +232,7 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = (cmd >> 8*i) & 0xFF; } return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); @@ -260,7 +260,7 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_ int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = (cmd >> 8*i) & 0xFF; } return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); @@ -293,7 +293,7 @@ int16_t Module::SPIcheckStream() { uint8_t spiStatus = 0; uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; - for(size_t i = 0; i < this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { *(cmdPtr++) = ( this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] >> 8*i) & 0xFF; } state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); diff --git a/src/Module.h b/src/Module.h index 0341a5b2ac..630f431b5b 100644 --- a/src/Module.h +++ b/src/Module.h @@ -168,6 +168,13 @@ class Module { /*! \brief Callback for validation SPI status. */ typedef int16_t (*SPIcheckStatusCb_t)(Module* mod); + enum BitWidth_t { + BITS_0 = 0, + BITS_8 = 8, + BITS_16 = 16, + BITS_32 = 32, + }; + /*! \struct SPIConfig_t \brief SPI configuration structure. @@ -183,7 +190,7 @@ class Module { uint16_t cmds[4]; /*! \brief Bit widths of SPI addresses, commands and status bytes */ - size_t widths[3]; + BitWidth_t widths[3]; /*! \brief Byte position of status command in SPI stream */ uint8_t statusPos; @@ -200,7 +207,7 @@ class Module { .stream = false, .err = RADIOLIB_ERR_UNKNOWN, .cmds = { 0x00, 0x80, 0x00, 0x00 }, - .widths = { 8, 0, 8 }, + .widths = { Module::BITS_8, Module::BITS_0, Module::BITS_8 }, .statusPos = 0, .parseStatusCb = nullptr, .checkStatusCb = nullptr, diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index fea71c9572..1b37d6b506 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -14,8 +14,8 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; this->mod->spiConfig.statusPos = 1; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; @@ -102,8 +102,8 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; this->mod->spiConfig.statusPos = 1; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 4bd6da73a2..45873e5af8 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -11,8 +11,8 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; this->mod->spiConfig.statusPos = 1; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; @@ -75,8 +75,8 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; this->mod->spiConfig.statusPos = 1; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; @@ -147,8 +147,8 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; this->mod->spiConfig.statusPos = 1; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; @@ -205,8 +205,8 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1 this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = 16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = 8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; this->mod->spiConfig.statusPos = 1; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; From d77823375a3c4329a1a1182fcf4787f008878810 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 9 Apr 2024 22:18:40 +0200 Subject: [PATCH 0990/1848] [LoRaWAN] Generate random numbers instead of digital/analog read (#1056) --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 22 ++++++------- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 32 +++++++++---------- .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 20 ++++++------ 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 99c65225eb..4d12601e30 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -33,34 +33,34 @@ void setup() { Serial.begin(115200); - while (!Serial); + while(!Serial); delay(5000); // Give time to switch to the serial monitor Serial.println(F("\nSetup ... ")); - Serial.println(F("Initalise the radio")); + Serial.println(F("Initialise the radio")); int state = radio.begin(); - debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); - Serial.println(F("Initalise LoRaWAN Network credentials")); + Serial.println(F("Initialise LoRaWAN Network credentials")); state = node.beginABP(devAddr, NwkSEncKey, AppSKey, NwkSKey, SNwkSIntKey, true); debug(state < RADIOLIB_ERR_NONE, F("Session setup failed"), state, true); Serial.println(F("Ready!\n")); } - void loop() { Serial.println(F("Sending uplink")); - // Read some inputs - uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(3); + // This is the place to gather the sensor inputs + // Instead of reading any real sensor, we just generate some random numbers as example + uint8_t value1 = radio.random(100); + uint16_t value2 = radio.random(2000); // Build payload byte array uint8_t uplinkPayload[3]; - uplinkPayload[0] = Digital1; - uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions - uplinkPayload[2] = lowByte(Analog1); + uplinkPayload[0] = value1; + uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(value2); // Perform an uplink int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 608fb82f9f..e7253f2c54 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -33,18 +33,17 @@ // include the library #include - void setup() { Serial.begin(115200); - while (!Serial); // Wait for serial to be initalised + while(!Serial); // Wait for serial to be initialised delay(5000); // Give time to switch to the serial monitor Serial.println(F("\nSetup")); int16_t state = 0; // return value for calls to RadioLib - Serial.println(F("Initalise the radio")); + Serial.println(F("Initialise the radio")); state = radio.begin(); - debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); // Override the default join rate // uint8_t joinDR = 3; @@ -70,8 +69,7 @@ void setup() { node.setDwellTime(true, 400); Serial.println(F("Ready!\n")); -} // setup - +} void loop() { int state = RADIOLIB_ERR_NONE; @@ -85,19 +83,19 @@ void loop() { uint8_t battLevel = 146; node.setDeviceStatus(battLevel); - - // Read some inputs - uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(3); + // This is the place to gather the sensor inputs + // Instead of reading any real sensor, we just generate some random numbers as example + uint8_t value1 = radio.random(100); + uint16_t value2 = radio.random(2000); // Build payload byte array uint8_t uplinkPayload[3]; - uplinkPayload[0] = Digital1; - uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions - uplinkPayload[2] = lowByte(Analog1); + uplinkPayload[0] = value1; + uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(value2); uint8_t downlinkPayload[10]; // Make sure this fits your plans! - size_t downlinkSize; // To hold the actual payload size rec'd + size_t downlinkSize; // To hold the actual payload size received // you can also retrieve additional information about an uplink or // downlink by passing a reference to LoRaWANEvent_t structure @@ -108,6 +106,7 @@ void loop() { // Retrieve the last uplink frame counter uint32_t fcntUp = node.getFcntUp(); + // Send a confirmed uplink every 64th frame // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { @@ -123,7 +122,7 @@ void loop() { // Check if downlink was received if(state != RADIOLIB_LORAWAN_NO_DOWNLINK) { // Did we get a downlink with data for us - if (downlinkSize > 0) { + if(downlinkSize > 0) { Serial.println(F("Downlink data: ")); arrayDump(downlinkPayload, downlinkSize); } else { @@ -194,5 +193,4 @@ void loop() { Serial.println(F("s")); delay(delayMs); - -} // loop +} diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 0914c1c071..c9b32eb3a0 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -26,13 +26,13 @@ void setup() { Serial.begin(115200); - while (!Serial); + while(!Serial); delay(5000); // Give time to switch to the serial monitor Serial.println(F("\nSetup ... ")); - Serial.println(F("Initalise the radio")); + Serial.println(F("Initialise the radio")); int state = radio.begin(); - debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true); + debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); Serial.println(F("Join ('login') to the LoRaWAN Network")); state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); @@ -41,19 +41,19 @@ void setup() { Serial.println(F("Ready!\n")); } - void loop() { Serial.println(F("Sending uplink")); - // Read some inputs - uint8_t Digital1 = digitalRead(2); - uint16_t Analog1 = analogRead(3); + // This is the place to gather the sensor inputs + // Instead of reading any real sensor, we just generate some random numbers as example + uint8_t value1 = radio.random(100); + uint16_t value2 = radio.random(2000); // Build payload byte array uint8_t uplinkPayload[3]; - uplinkPayload[0] = Digital1; - uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions - uplinkPayload[2] = lowByte(Analog1); + uplinkPayload[0] = value1; + uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(value2); // Perform an uplink int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); From c11ac4703b3b5fc45c3594c41ac1bb21f6d03375 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 13 Apr 2024 21:21:33 +0200 Subject: [PATCH 0991/1848] [SX127x] Fixed getRSSI overload for PhysicalLayer (#1064) --- src/modules/SX127x/SX1272.cpp | 4 ++++ src/modules/SX127x/SX1272.h | 9 ++++++++- src/modules/SX127x/SX1278.cpp | 4 ++++ src/modules/SX127x/SX1278.h | 9 ++++++++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 808d55d24b..003a1cc205 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -419,6 +419,10 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) { return(state); } +float SX1272::getRSSI() { + return(SX1272::getRSSI(true, false)); +} + float SX1272::getRSSI(bool packet, bool skipReceive) { return(SX127x::getRSSI(packet, skipReceive, -139)); } diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 5ea92db5b5..37e468ee06 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -231,13 +231,20 @@ class SX1272: public SX127x { */ int16_t setDataShapingOOK(uint8_t sh); + /*! + \brief Gets recorded signal strength indicator. + Overload with packet mode enabled for PhysicalLayer compatibility. + \returns RSSI value in dBm. + */ + float getRSSI(); + /*! \brief Gets recorded signal strength indicator. \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. \returns RSSI value in dBm. */ - float getRSSI(bool packet = true, bool skipReceive = false); + float getRSSI(bool packet, bool skipReceive = false); /*! \brief Enables/disables CRC check of received packets. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index cefb352cb5..22c2430384 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -448,6 +448,10 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) { return(state); } +float SX1278::getRSSI() { + return(SX1278::getRSSI(true, false)); +} + float SX1278::getRSSI(bool packet, bool skipReceive) { int16_t offset = -157; if(frequency < 868.0) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 979edb75a1..371b166012 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -243,13 +243,20 @@ class SX1278: public SX127x { */ int16_t setDataShapingOOK(uint8_t sh); + /*! + \brief Gets recorded signal strength indicator. + Overload with packet mode enabled for PhysicalLayer compatibility. + \returns RSSI value in dBm. + */ + float getRSSI(); + /*! \brief Gets recorded signal strength indicator. \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. \returns RSSI value in dBm. */ - float getRSSI(bool packet = true, bool skipReceive = false); + float getRSSI(bool packet, bool skipReceive = false); /*! \brief Enables/disables CRC check of received packets. From 91f89fa1f3ed95bed3efcc01e7092264691b582b Mon Sep 17 00:00:00 2001 From: Velocet Date: Sun, 14 Apr 2024 08:15:50 +0200 Subject: [PATCH 0992/1848] Updated board definitions for the LoRaWAN Examples (#1052) * Update README.md Clarify intended purpose. Remove unsupported modules. * Update board configs in configABP.h Added HelTec boards and corrected some errors * Update board configs in config.h Added HelTec boards and corrected some errors * Update board configs in config.h Added HelTec boards and corrected some errors * Update prebuilt modules in notes.md * Delete README.md * Recreate README.md --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 41 +++++++++++++-------- examples/LoRaWAN/LoRaWAN_Reference/config.h | 41 +++++++++++++-------- examples/LoRaWAN/LoRaWAN_Starter/config.h | 41 +++++++++++++-------- examples/LoRaWAN/LoRaWAN_Starter/notes.md | 4 ++ 4 files changed, 79 insertions(+), 48 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index e79960a1da..52e39d8e6e 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -49,11 +49,11 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // LilyGo #elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("TTGO LoRa32 v1 - no Display") + #pragma message ("Using TTGO LoRa32 v1 - no Display") SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma message ("ARDUINO_TTGO_LORA32_V2 + Display") + #pragma message ("Using TTGO LoRa32 v2 + Display") SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 @@ -64,32 +64,41 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + #pragma message ("Using TTGO T-Beam") SX1276 radio = new Module(18, 26, 23, 33); -// Heltec +// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") - -#elif defined (ARDUINO_heltec_wireless_stick) - #pragma message ("Using Heltec Wireless Stick") - SX1278 radio = new Module(14, 4, 12, 16); + #pragma message ("Using Heltec WiFi LoRa32") + SX1276 radio = new Module(18, 26, 14, 33); -#elif defined(ARDUINO_heltec_wifi_lora_32_V2) +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1278 radio = new Module(14, 4, 12, 16); + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3") + SX1262 radio = new Module(8, 14, 12, 13); -#elif defined(ARDUINO_heltec_wifi_kit_32_V2) - #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK) + #pragma message ("Using Heltec Wireless Stick") SX1276 radio = new Module(18, 26, 14, 35); -#elif defined(ARDUINO_heltec_wifi_kit_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3) + #pragma message ("Using Heltec Wireless Stick v3") SX1262 radio = new Module(8, 14, 12, 13); +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE) + #pragma message ("Using Heltec Wireless Stick Lite") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3) + #pragma message ("Using Heltec Wireless Stick Lite v3") + SX1262 radio = new Module(34, 14, 12, 13); + #elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + #pragma message ("Using CubeCell") SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); #elif defined(ARDUINO_CUBECELL_BOARD_V2) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index d91e4a554e..19eaf57ef5 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -44,11 +44,11 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // LilyGo #elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("TTGO LoRa32 v1 - no Display") + #pragma message ("Using TTGO LoRa32 v1 - no Display") SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma message ("ARDUINO_TTGO_LORA32_V2 + Display") + #pragma message ("Using TTGO LoRa32 v2 + Display") SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 @@ -59,32 +59,41 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + #pragma message ("Using TTGO T-Beam") SX1276 radio = new Module(18, 26, 23, 33); -// Heltec +// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") - -#elif defined (ARDUINO_heltec_wireless_stick) - #pragma message ("Using Heltec Wireless Stick") - SX1278 radio = new Module(14, 4, 12, 16); + #pragma message ("Using Heltec WiFi LoRa32") + SX1276 radio = new Module(18, 26, 14, 33); -#elif defined(ARDUINO_heltec_wifi_lora_32_V2) +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1278 radio = new Module(14, 4, 12, 16); + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3") + SX1262 radio = new Module(8, 14, 12, 13); -#elif defined(ARDUINO_heltec_wifi_kit_32_V2) - #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK) + #pragma message ("Using Heltec Wireless Stick") SX1276 radio = new Module(18, 26, 14, 35); -#elif defined(ARDUINO_heltec_wifi_kit_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3) + #pragma message ("Using Heltec Wireless Stick v3") SX1262 radio = new Module(8, 14, 12, 13); +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE) + #pragma message ("Using Heltec Wireless Stick Lite") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3) + #pragma message ("Using Heltec Wireless Stick Lite v3") + SX1262 radio = new Module(34, 14, 12, 13); + #elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + #pragma message ("Using CubeCell") SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); #elif defined(ARDUINO_CUBECELL_BOARD_V2) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index d91e4a554e..19eaf57ef5 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -44,11 +44,11 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // LilyGo #elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("TTGO LoRa32 v1 - no Display") + #pragma message ("Using TTGO LoRa32 v1 - no Display") SX1276 radio = new Module(18, 26, 14, 33); #elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma message ("ARDUINO_TTGO_LORA32_V2 + Display") + #pragma message ("Using TTGO LoRa32 v2 + Display") SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); #elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 @@ -59,32 +59,41 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") #elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + #pragma message ("Using TTGO T-Beam") SX1276 radio = new Module(18, 26, 23, 33); -// Heltec +// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h #elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map") - -#elif defined (ARDUINO_heltec_wireless_stick) - #pragma message ("Using Heltec Wireless Stick") - SX1278 radio = new Module(14, 4, 12, 16); + #pragma message ("Using Heltec WiFi LoRa32") + SX1276 radio = new Module(18, 26, 14, 33); -#elif defined(ARDUINO_heltec_wifi_lora_32_V2) +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1278 radio = new Module(14, 4, 12, 16); + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3") + SX1262 radio = new Module(8, 14, 12, 13); -#elif defined(ARDUINO_heltec_wifi_kit_32_V2) - #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK) + #pragma message ("Using Heltec Wireless Stick") SX1276 radio = new Module(18, 26, 14, 35); -#elif defined(ARDUINO_heltec_wifi_kit_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3) + #pragma message ("Using Heltec Wireless Stick v3") SX1262 radio = new Module(8, 14, 12, 13); +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE) + #pragma message ("Using Heltec Wireless Stick Lite") + SX1276 radio = new Module(18, 26, 14, 35); + +#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3) + #pragma message ("Using Heltec Wireless Stick Lite v3") + SX1262 radio = new Module(34, 14, 12, 13); + #elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") + #pragma message ("Using CubeCell") SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); #elif defined(ARDUINO_CUBECELL_BOARD_V2) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md index b56675995a..2821bef3e2 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/notes.md +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -152,6 +152,10 @@ Prebuilt modules are easy - we can detect the board and setup the pinmap for you * HELTEC_WIFI_LORA_32 * HELTEC_WIFI_LORA_32_V2 * HELTEC_WIFI_LORA_32_V3 +* HELTEC_WIRELESS_STICK +* HELTEC_WIRELESS_STICK_V3 +* HELTEC_WIRELESS_STICK_LITE +* HELTEC_WIRELESS_STICK_LITE_V3 If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu. From 46ef20ebe9c671da35a9a7a02f59d1498eb2bf61 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 14:37:55 +0100 Subject: [PATCH 0993/1848] Fix interrupt emulation in Raspberry Pi example --- examples/NonArduino/Raspberry/PiHal.h | 55 +++++++++++++++++++++++--- examples/NonArduino/Raspberry/build.sh | 1 + 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 8394ad23dc..162a223425 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -7,6 +7,14 @@ // include the library for Raspberry GPIO pins #include "pigpio.h" +// these should really be swapped, but for some reason, +// it seems like the change directions are inverted in gpioSetAlert functions +#define PI_RISING (FALLING_EDGE) +#define PI_FALLING (RISING_EDGE) + +// forward declaration of alert handler that will be used to emulate interrupts +static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata); + // create a new Raspberry Pi hardware abstraction layer // using the pigpio library // the HAL must inherit from the base RadioLibHal class @@ -15,7 +23,7 @@ class PiHal : public RadioLibHal { public: // default constructor - initializes the base HAL and any needed private members PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) - : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), + : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING), _spiChannel(spiChannel), _spiSpeed(spiSpeed) { } @@ -71,19 +79,31 @@ class PiHal : public RadioLibHal { } void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { - if(interruptNum == RADIOLIB_NC) { + if((interruptNum == RADIOLIB_NC) || (interruptNum > PI_MAX_USER_GPIO)) { return; } - gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb); + // enable emulated interrupt + interruptEnabled[interruptNum] = true; + interruptModes[interruptNum] = mode; + interruptCallbacks[interruptNum] = interruptCb; + + // set pigpio alert callback + gpioSetAlertFuncEx(interruptNum, pigpioAlertHandler, (void*)this); } void detachInterrupt(uint32_t interruptNum) override { - if(interruptNum == RADIOLIB_NC) { + if((interruptNum == RADIOLIB_NC) || (interruptNum > PI_MAX_USER_GPIO)) { return; } - gpioSetISRFunc(interruptNum, 0, 0, NULL); + // clear emulated interrupt + interruptEnabled[interruptNum] = false; + interruptModes[interruptNum] = 0; + interruptCallbacks[interruptNum] = NULL; + + // disable pigpio alert callback + gpioSetAlertFuncEx(interruptNum, NULL, NULL); } void delay(unsigned long ms) override { @@ -120,7 +140,7 @@ class PiHal : public RadioLibHal { return(this->micros() - start); } - void spiBegin() { + void spiBegin() { if(_spiHandle < 0) { _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); } @@ -141,6 +161,12 @@ class PiHal : public RadioLibHal { } } + // interrupt emulation + bool interruptEnabled[PI_MAX_USER_GPIO + 1]; + uint32_t interruptModes[PI_MAX_USER_GPIO + 1]; + typedef void (*RadioLibISR)(void); + RadioLibISR interruptCallbacks[PI_MAX_USER_GPIO + 1]; + private: // the HAL can contain any additional private members const unsigned int _spiSpeed; @@ -148,4 +174,21 @@ class PiHal : public RadioLibHal { int _spiHandle = -1; }; +// this handler emulates interrupts +static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata) { + if((event > PI_MAX_USER_GPIO) || (!userdata)) { + return; + } + + // PiHal isntance is passed via the user data + PiHal* hal = (PiHal*)userdata; + + // check the interrupt is enabled, the level matches and a callback exists + if((hal->interruptEnabled[event]) && + (hal->interruptModes[event] == level) && + (hal->interruptCallbacks[event])) { + hal->interruptCallbacks[event](); + } +} + #endif diff --git a/examples/NonArduino/Raspberry/build.sh b/examples/NonArduino/Raspberry/build.sh index 5d55b66e33..55caae99a5 100755 --- a/examples/NonArduino/Raspberry/build.sh +++ b/examples/NonArduino/Raspberry/build.sh @@ -6,3 +6,4 @@ cd build cmake -G "CodeBlocks - Unix Makefiles" .. make cd .. +size build/rpi-sx1261 From e7da14421de7dfade754a262f6872989d82ee4a5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 20:22:16 +0200 Subject: [PATCH 0994/1848] [Mod] Fix SPI command byte order --- src/Module.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index d17caf9f90..05de592250 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -107,7 +107,7 @@ void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inByte } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF; } for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { @@ -124,7 +124,7 @@ uint8_t Module::SPIreadRegister(uint32_t reg) { } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF; } for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { @@ -141,7 +141,7 @@ void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF; } for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { @@ -157,7 +157,7 @@ void Module::SPIwriteRegister(uint32_t reg, uint8_t data) { } else { uint8_t cmd[6]; uint8_t* cmdPtr = cmd; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF; } for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { @@ -232,7 +232,7 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = (cmd >> 8*i) & 0xFF; } return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); @@ -260,7 +260,7 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_ int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = (cmd >> 8*i) & 0xFF; } return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); @@ -293,7 +293,7 @@ int16_t Module::SPIcheckStream() { uint8_t spiStatus = 0; uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; - for(uint8_t i = 0; i < (uint8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8; i++) { + for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = ( this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] >> 8*i) & 0xFF; } state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); From 77ed4452aed3e95e739ab521b0fd85dfc17a8c47 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 20:22:55 +0200 Subject: [PATCH 0995/1848] [LR11x0] Added basic LR11x0 support (#679) --- .../LR11x0_Receive_Blocking.ino | 104 + .../LR11x0_Receive_Interrupt.ino | 138 + .../LR11x0_Transmit_Blocking.ino | 106 + .../LR11x0_Transmit_Interrupt.ino | 131 + keywords.txt | 3 + src/RadioLib.h | 1 + src/modules/LR11x0/LR1110.cpp | 75 + src/modules/LR11x0/LR1110.h | 95 + src/modules/LR11x0/LR11x0.cpp | 2255 +++++++++++++++++ src/modules/LR11x0/LR11x0.h | 1018 ++++++++ 10 files changed, 3926 insertions(+) create mode 100644 examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino create mode 100644 examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino create mode 100644 examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino create mode 100644 examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino create mode 100644 src/modules/LR11x0/LR1110.cpp create mode 100644 src/modules/LR11x0/LR1110.h create mode 100644 src/modules/LR11x0/LR11x0.cpp create mode 100644 src/modules/LR11x0/LR11x0.h diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino new file mode 100644 index 0000000000..e29806bd2d --- /dev/null +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -0,0 +1,104 @@ +/* + RadioLib LR11x0 Blocking Receive Example + + This example listens for LoRa transmissions using LR11x0 Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from LR11x0 family can also be used. + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[LR1110] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[LR1110] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[LR1110] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[LR1110] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino new file mode 100644 index 0000000000..0539104a62 --- /dev/null +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -0,0 +1,138 @@ +/* + RadioLib LR11x0 Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from LR11x0 family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[LR1110] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[LR1110] Received packet!")); + + // print data of the packet + Serial.print(F("[LR1110] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LR1110] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LR1110] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino new file mode 100644 index 0000000000..93dab374b4 --- /dev/null +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -0,0 +1,106 @@ +/* + RadioLib LR11x0 Blocking Transmit Example + + This example transmits packets using LR1110 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from LR11x0 family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + delay(1000); + while (true); + } + + // some modules have an external RF switch + + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[LR1110] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + // NOTE: transmit() is a blocking method! + // See example LR11x0_Transmit_Interrupt for details + // on non-blocking transmission method. + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[LR1110] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino new file mode 100644 index 0000000000..6de582c6a2 --- /dev/null +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -0,0 +1,131 @@ +/* + RadioLib LR11x0 Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from LR11x0 family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[LR1110] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[LR1110] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} diff --git a/keywords.txt b/keywords.txt index 2fee742103..0ace7c6c92 100644 --- a/keywords.txt +++ b/keywords.txt @@ -15,6 +15,9 @@ ArduinoHal KEYWORD1 # modules CC1101 KEYWORD1 LLCC68 KEYWORD1 +LR1110 KEYWORD1 +LR1120 KEYWORD1 +LR1121 KEYWORD1 nRF24 KEYWORD1 RF69 KEYWORD1 RFM22 KEYWORD1 diff --git a/src/RadioLib.h b/src/RadioLib.h index 94b8016c60..304dae6d90 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -68,6 +68,7 @@ #include "modules/CC1101/CC1101.h" #include "modules/LLCC68/LLCC68.h" +#include "modules/LR11x0/LR1110.h" #include "modules/nRF24/nRF24.h" #include "modules/RF69/RF69.h" #include "modules/RFM2x/RFM22.h" diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp new file mode 100644 index 0000000000..a540ce5c52 --- /dev/null +++ b/src/modules/LR11x0/LR1110.cpp @@ -0,0 +1,75 @@ +#include "LR1110.h" +#if !RADIOLIB_EXCLUDE_LR11X0 + +LR1110::LR1110(Module* mod) : LR11x0(mod) { + chipType = RADIOLIB_LR11X0_HW_LR1110; +} + +int16_t LR1110::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { + // execute common part + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + return(state); +} + +int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { + // execute common part + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + return(state); +} + +int16_t LR1110::setFrequency(float freq) { + return(this->setFrequency(freq, true)); +} + +int16_t LR1110::setFrequency(float freq, bool calibrate, float band) { + RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + + // calibrate image rejection + if(calibrate) { + int16_t state = LR11x0::calibImage(freq - band, freq + band); + RADIOLIB_ASSERT(state); + } + + // set frequency + return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); +} + +int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { + // determine whether to use HP or LP PA and check range accordingly + bool useHp = forceHighPower || (power > 14); + if(useHp) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + useHp = true; + + } else { + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + useHp = false; + + } + + // TODO how and when to configure OCP? + + // update PA config - always use VBAT for high-power PA + int16_t state = LR11x0::setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); + RADIOLIB_ASSERT(state); + + // set output power + state = LR11x0::setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + return(state); +} + +#endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h new file mode 100644 index 0000000000..636724e6a8 --- /dev/null +++ b/src/modules/LR11x0/LR1110.h @@ -0,0 +1,95 @@ +#if !defined(_RADIOLIB_LR1110_H) +#define _RADIOLIB_LR1110_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +#include "../../Module.h" +#include "LR11x0.h" + +/*! + \class LR1110 + \brief Derived class for %LR1110 modules. +*/ +class LR1110: public LR11x0 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + LR1110(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12). + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6); + + /*! + \brief Initialization method for FSK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t beginGFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + Will also perform calibrations. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + \param freq Carrier frequency to be set in MHz. + \param calibrate Run image calibration. + \param band Half bandwidth for image calibration. For example, + if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate + for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz + \returns \ref status_codes + */ + int16_t setFrequency(float freq, bool calibrate, float band = 4); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + Defaults to false. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool forceHighPower = false); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp new file mode 100644 index 0000000000..a2cfb53d62 --- /dev/null +++ b/src/modules/LR11x0/LR11x0.cpp @@ -0,0 +1,2255 @@ +#include "LR11x0.h" + +#include "../../utils/CRC.h" +#include "../../utils/Cryptography.h" + +#include + +#if !RADIOLIB_EXCLUDE_LR11X0 + +LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { + this->mod = mod; + this->XTAL = false; +} + +int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.statusPos = 0; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + this->mod->spiConfig.checkStatusCb = SPIcheckStatus; + + // try to find the LR11x0 chip - this will also reset the module at least once + if(!LR11x0::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0"); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(RADIOLIB_LR11X0_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setSyncWord(syncWord); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + // TODO looks like CRC does not work for SX127x + state = setCRC(0); + RADIOLIB_ASSERT(state); + + state = invertIQ(false); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.statusPos = 0; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + this->mod->spiConfig.checkStatusCb = SPIcheckStatus; + + // try to find the LR11x0 chip - this will also reset the module at least once + if(!LR11x0::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0"); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::reset() { + // run the reset sequence + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(10); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + + // the typical transition duration should be 273 ms + this->mod->hal->delay(300); + + // wait for BUSY to go low + uint32_t start = this->mod->hal->millis(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start >= 3000) { + RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after reset!"); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check packet length + if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + uint32_t timeout = 0; + + // get currently active modem + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + // calculate timeout (150% of expected time-on-air) + timeout = (getTimeOnAir(len) * 3) / 2; + + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // calculate timeout (500% of expected time-on-air) + timeout = getTimeOnAir(len) * 5; + + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + uint32_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + uint32_t elapsed = this->mod->hal->micros() - start; + + // update data rate + this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0); + + return(finishTransmit()); +} + +int16_t LR11x0::receive(uint8_t* data, size_t len) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + uint32_t timeout = 0; + + // get currently active modem + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + // calculate timeout (100 LoRa symbols, the default for SX127x series) + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + timeout = (uint32_t)(symbolLength * 100.0); + + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // calculate timeout (500 % of expected time-one-air) + size_t maxLen = len; + if(len == 0) { + maxLen = 0xFF; + } + float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; + timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); + + } else { + return(RADIOLIB_ERR_UNKNOWN); + + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); + + // start reception + uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 30.52); + state = startReceive(timeoutValue); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + bool softTimeout = false; + uint32_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + // safety check, the timeout should be done by the radio + if(this->mod->hal->millis() - start > timeout) { + softTimeout = true; + break; + } + } + + // if it was a timeout, this will return an error code + // TODO taken from SX126x, does this really work? + state = standby(); + if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) { + return(state); + } + + // check whether this was a timeout or not + if((getIrqStatus() & RADIOLIB_LR11X0_IRQ_TIMEOUT) || softTimeout) { + standby(); + clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // read the received data + return(readData(data, len)); +} + +int16_t LR11x0::standby() { + return(LR11x0::standby(RADIOLIB_LR11X0_STANDBY_RC)); +} + +int16_t LR11x0::standby(uint8_t mode, bool wakeup) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + // TODO this will block BUSY forever + /*if(wakeup) { + // pull NSS low to wake up + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + }*/ + + uint8_t buff[] = { mode }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1)); +} + +int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + uint8_t buff[] = { + (uint8_t)retainConfig, + (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF), + (uint8_t)((sleepTime >> 16) & 0xFF), (uint8_t)(sleepTime & 0xFF), + }; + if(sleepTime) { + buff[0] |= RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED; + } + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_SLEEP, true, buff, sizeof(buff)); + + // wait for the module to safely enter sleep mode + this->mod->hal->delay(1); + + return(state); +} + +void LR11x0::setDio1Action(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); +} + +void LR11x0::clearDio1Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void LR11x0::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void LR11x0::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void LR11x0::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void LR11x0::clearPacketSentAction() { + this->clearDio1Action(); +} + +int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // suppress unused variable warning + (void)addr; + + // check packet length + if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // maximum packet length is decreased by 1 when address filtering is active + if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set packet Length + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcTypeLoRa, this->invertIQEnabled); + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT, 0); + RADIOLIB_ASSERT(state); + + // write packet to buffer + state = writeBuffer8(data, len); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // start transmission + state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + return(state); +} + +int16_t LR11x0::finishTransmit() { + // clear interrupt flags + clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t LR11x0::startReceive() { + return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE, 0)); +} + +int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, size_t len) { + (void)len; + + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set DIO mapping + uint32_t irq = irqFlags; + if(timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) { + irq |= RADIOLIB_LR11X0_IRQ_TIMEOUT; + } + + state = setDioIrqParams(irq, RADIOLIB_LR11X0_IRQ_NONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // set implicit mode and expected len if applicable + if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + } + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to receive + state = setRx(timeout); + + return(state); +} + +uint32_t LR11x0::getIrqStatus() { + // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes + uint8_t buff[6] = { 0 }; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; + mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; + return(irq); +} + +int16_t LR11x0::readData(uint8_t* data, size_t len) { + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check integrity CRC + uint32_t irq = getIrqStatus(); + int16_t crcState = RADIOLIB_ERR_NONE; + if((irq & RADIOLIB_LR11X0_IRQ_CRC_ERR) || (irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR)) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; + } + + // get packet length + // the offset is needed since LR11x0 seems to move the buffer base by 4 bytes on every packet + uint8_t offset = 0; + size_t length = getPacketLength(true, &offset); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; + } + + // read packet data + state = readBuffer8(data, length, offset); + RADIOLIB_ASSERT(state); + + // clear the Rx buffer + state = clearRxBuffer(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + + // check if CRC failed - this is done after reading data to give user the option to keep them + RADIOLIB_ASSERT(crcState); + + return(state); +} + +int16_t LR11x0::setBandwidth(float bw) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // ensure byte conversion doesn't overflow + RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + + // check allowed bandwidth values + uint8_t bw_div2 = bw / 2 + 0.01; + switch (bw_div2) { + case 31: // 62.5: + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5; + break; + case 62: // 125.0: + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_125_0; + break; + case 125: // 250.0 + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_250_0; + break; + case 250: // 500.0 + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_500_0; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // update modulation parameters + this->bandwidthKhz = bw; + return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR11x0::setSpreadingFactor(uint8_t sf, bool legacy) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + + // enable SF6 legacy mode + if(legacy && (sf == 6)) { + //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18); + } + + // update modulation parameters + this->spreadingFactor = sf; + return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + if(longInterleave) { + switch(cr) { + case 5: + case 6: + this->codingRate = cr; + break; + case 8: + this->codingRate = cr - 1; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + } else { + this->codingRate = cr - 4; + + } + + // update modulation parameters + return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR11x0::setSyncWord(uint8_t syncWord) { + return(setLoRaSyncWord(syncWord)); +} + +int16_t LR11x0::setPreambleLength(size_t preambleLength) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + this->preambleLengthLoRa = preambleLength; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t LR11x0::setTCXO(float voltage, uint32_t delay) { + // check if TCXO is enabled at all + if(this->XTAL) { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // set mode to standby + standby(); + + // check RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR flag and clear it + uint16_t errors = 0; + int16_t state = getErrors(&errors); + RADIOLIB_ASSERT(state); + if(errors & RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR) { + clearErrors(); + } + + // check 0 V disable + if(fabs(voltage - 0.0) <= 0.001) { + setTcxoMode(0, 0); + return(reset()); + } + + // check allowed voltage values + uint8_t tune = 0; + if(fabs(voltage - 1.6) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6; + } else if(fabs(voltage - 1.7) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7; + } else if(fabs(voltage - 1.8) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8; + } else if(fabs(voltage - 2.2) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2; + } else if(fabs(voltage - 2.4) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4; + } else if(fabs(voltage - 2.7) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7; + } else if(fabs(voltage - 3.0) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0; + } else if(fabs(voltage - 3.3) <= 0.001) { + tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3; + } else { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // calculate delay value + uint32_t delayValue = (uint32_t)((float)delay / 30.52f); + if(delayValue == 0) { + delayValue = 1; + } + + // enable TCXO control + return(setTcxoMode(tune, delayValue)); +} + +int16_t LR11x0::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion + this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled)); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t LR11x0::invertIQ(bool enable) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->invertIQEnabled = enable; + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled)); +} + +float LR11x0::getRSSI() { + float val = 0; + + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + getPacketType(&type); + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + getPacketStatusLoRa(&val, NULL, NULL); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + getPacketStatusGFSK(NULL, &val, NULL, NULL); + + } + + return(val); +} + +float LR11x0::getSNR() { + float val = 0; + + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + getPacketType(&type); + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + getPacketStatusLoRa(NULL, &val, NULL); + } + + return(val); +} + +float LR11x0::getFrequencyError() { + // TODO implement this + return(0); +} + +size_t LR11x0::getPacketLength(bool update) { + return(this->getPacketLength(update, NULL)); +} + +size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { + (void)update; + + // in implicit mode, return the cached value + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + (void)getPacketType(&type); + if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT)) { + return(this->implicitLen); + } + + uint8_t len = 0; + (void)getRxBufferStatus(&len, offset); + return((size_t)len); +} + +uint32_t LR11x0::getTimeOnAir(size_t len) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + getPacketType(&type); + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + // calculate number of symbols + float N_symbol = 0; + if(this->codingRate <= RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) { + // legacy coding rate - nice and simple + + // get SF coefficients + float coeff1 = 0; + int16_t coeff2 = 0; + int16_t coeff3 = 0; + if(this->spreadingFactor < 7) { + // SF5, SF6 + coeff1 = 6.25; + coeff2 = 4*this->spreadingFactor; + coeff3 = 4*this->spreadingFactor; + } else if(this->spreadingFactor < 11) { + // SF7. SF8, SF9, SF10 + coeff1 = 4.25; + coeff2 = 4*this->spreadingFactor + 8; + coeff3 = 4*this->spreadingFactor; + } else { + // SF11, SF12 + coeff1 = 4.25; + coeff2 = 4*this->spreadingFactor + 8; + coeff3 = 4*(this->spreadingFactor - 2); + } + + // get CRC length + int16_t N_bitCRC = 16; + if(this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_DISABLED) { + N_bitCRC = 0; + } + + // get header length + int16_t N_symbolHeader = 20; + if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) { + N_symbolHeader = 0; + } + + // calculate number of LoRa preamble symbols + uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); + + // calculate the number of symbols + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + + } else { + // long interleaving - abandon hope all ye who enter here + /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 + + } + + // get time-on-air in us + return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(((uint32_t)len * 8 * 1000) / this->bitRateKbps); + + } + + return(0); +} + +float LR11x0::getDataRate() const { + return(this->dataRateMeasured); +} + +int16_t LR11x0::SPIparseStatus(uint8_t in) { + if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } else if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_FAIL) { + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } else if((in == 0x00) || (in == 0xFF)) { + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::SPIcheckStatus(Module* mod) { + // the status check command doesn't return status in the same place as other read commands, + // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used + // it also seems to ignore the actual command, and just sending in bunch of NOPs will work + uint8_t buff[6] = { 0 }; + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; + int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + RADIOLIB_ASSERT(state); + return(LR11x0::SPIparseStatus(buff[0])); +} + +int16_t LR11x0::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, uint8_t* out, size_t outLen) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + if(!write) { + // the SPI interface of LR11x0 requires two separate transactions for reading + // send the 16-bit command + state = this->mod->SPIwriteStream(cmd, out, outLen, true, false); + RADIOLIB_ASSERT(state); + + // read the result without command + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0; + state = this->mod->SPIreadStream(RADIOLIB_LR11X0_CMD_NOP, data, len, true, false); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + + } else { + // write is just a single transaction + state = this->mod->SPIwriteStream(cmd, data, len, true, true); + + } + + return(state); +} + +bool LR11x0::findChip(uint8_t ver) { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // read the version + uint8_t device = 0xFF; + if((this->getVersion(NULL, &device, NULL, NULL) == RADIOLIB_ERR_NONE) && (device == ver)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", device); + flagFound = true; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, device); + RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: 0x%02x", ver); + this->mod->hal->delay(10); + i++; + } + } + + return(flagFound); +} + +int16_t LR11x0::config(uint8_t modem) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // set Rx/Tx fallback mode to STDBY_RC + state = this->setRxTxFallbackMode(RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC); + RADIOLIB_ASSERT(state); + + // TODO set some CAD parameters - will be overwritten when calling CAD anyway + + // clear IRQ + state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE, RADIOLIB_LR11X0_IRQ_NONE); + RADIOLIB_ASSERT(state); + + // calibrate all blocks + state = this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL); + + // wait for calibration completion + this->mod->hal->delay(5); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + // if something failed, show the device errors + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = 0; + getErrors(&errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); + } + #endif + + // set modem + state = this->setPacketType(modem); + return(state); +} + +Module* LR11x0::getMod() { + return(this->mod); +} + +int16_t LR11x0::writeRegMem32(uint32_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len)); +} + +int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len >= (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + RADIOLIB_ASSERT(state); + + // convert endians + if(data) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + + return(state); +} + +int16_t LR11x0::writeBuffer8(uint8_t* data, size_t len) { + // check maximum size + if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, data, len)); +} + +int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) { + // check maximum size + if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t reqLen = 2*sizeof(uint8_t) + len; + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + #endif + + // set the offset and length + reqBuff[0] = (uint8_t)offset; + reqBuff[1] = (uint8_t)len; + + // send the request + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_BUFFER, false, data, len, reqBuff, reqLen); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + return(state); +} + +int16_t LR11x0::clearRxBuffer(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER, true, NULL, 0)); +} + +int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { + uint8_t buff[12] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff))); +} + +int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { + uint8_t buff[6] = { 0 }; + + // the status check command doesn't return status in the same place as other read commands + // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used + // it also seems to ignore the actual command, and just sending in bunch of NOPs will work + int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + + // pass the replies + if(stat1) { *stat1 = buff[0]; } + if(stat2) { *stat2 = buff[1]; } + if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; } + + return(state); +} + +int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff)); + + // pass the replies + if(hw) { *hw = buff[0]; } + if(device) { *device = buff[1]; } + if(major) { *major = buff[2]; } + if(minor) { *minor = buff[3]; } + + return(state); +} + +int16_t LR11x0::getErrors(uint16_t* err) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_ERRORS, false, buff, sizeof(buff)); + + // pass the replies + if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + + return(state); +} + +int16_t LR11x0::clearErrors(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_ERRORS, true, NULL, 0)); +} + +int16_t LR11x0::calibrate(uint8_t params) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIBRATE, true, ¶ms, 1)); +} + +int16_t LR11x0::setRegMode(uint8_t mode) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1)); +} + +int16_t LR11x0::calibImage(float freq1, float freq2) { + uint8_t buff[2] = { + (uint8_t)floor((freq1 - 1.0f) / 4.0f), + (uint8_t)ceil((freq2 + 1.0f) / 4.0f) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t gnssCfg, uint8_t wifiCfg) { + uint8_t buff[7] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, gnssCfg, wifiCfg }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) { + uint8_t buff[8] = { + (uint8_t)((irq1 >> 24) & 0xFF), (uint8_t)((irq1 >> 16) & 0xFF), (uint8_t)((irq1 >> 8) & 0xFF), (uint8_t)(irq1 & 0xFF), + (uint8_t)((irq2 >> 24) & 0xFF), (uint8_t)((irq2 >> 16) & 0xFF), (uint8_t)((irq2 >> 8) & 0xFF), (uint8_t)(irq2 & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::clearIrq(uint32_t irq) { + uint8_t buff[4] = { + (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, true, buff, sizeof(buff))); +} + +int16_t LR11x0::configLfClock(uint8_t setup) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &setup, 1)); +} + +int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) { + uint8_t buff[4] = { + tune, (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TCXO_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::reboot(bool stay) { + uint8_t buff[1] = { (uint8_t)stay }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_REBOOT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::getVbat(float* vbat) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VBAT, false, buff, sizeof(buff)); + + // pass the replies + if(vbat) { *vbat = (((float)buff[0]/51.0f) - 1.0f)*1.35f; } + + return(state); +} + +int16_t LR11x0::getTemp(float* temp) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_TEMP, false, buff, sizeof(buff)); + + // pass the replies + if(temp) { + uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; + *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1350.0f - 0.7295f); + } + + return(state); +} + +int16_t LR11x0::setFs(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_FS, true, NULL, 0)); +} + +int16_t LR11x0::getRandomNumber(uint32_t* rnd) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff)); + + // pass the replies + if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + + return(state); +} + +int16_t LR11x0::eraseInfoPage(void) { + // only page 1 can be erased + uint8_t buff[1] = { RADIOLIB_LR11X0_INFO_PAGE }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::writeInfoPage(uint16_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + size_t buffLen = sizeof(uint8_t) + sizeof(uint16_t) + len*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint8_t) + sizeof(uint16_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set the address + dataBuff[0] = RADIOLIB_LR11X0_INFO_PAGE; + dataBuff[1] = (uint8_t)((addr >> 8) & 0xFF); + dataBuff[2] = (uint8_t)(addr & 0xFF); + + // convert endians + for(size_t i = 0; i < len; i++) { + dataBuff[3 + i] = (uint8_t)((data[i] >> 24) & 0xFF); + dataBuff[4 + i] = (uint8_t)((data[i] >> 16) & 0xFF); + dataBuff[5 + i] = (uint8_t)((data[i] >> 8) & 0xFF); + dataBuff[6 + i] = (uint8_t)(data[i] & 0xFF); + } + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen); + #if RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[4] = { + RADIOLIB_LR11X0_INFO_PAGE, + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + RADIOLIB_ASSERT(state); + + // convert endians + if(data) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + + return(state); +} + +int16_t LR11x0::getChipEui(uint8_t* eui) { + if(!eui) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) { + if(!eui) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) { + if(!pin) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); +} + +int16_t LR11x0::enableSpiCrc(bool en) { + // TODO implement this + // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected + /*RadioLibCRCInstance.size = 8; + RadioLibCRCInstance.poly = 0xA6; + RadioLibCRCInstance.init = 0xFF; + RadioLibCRCInstance.out = 0x00; + RadioLibCRCInstance.refIn = true; + RadioLibCRCInstance.refOut = true;*/ + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t LR11x0::driveDiosInSleepMode(bool en) { + uint8_t buff[1] = { (uint8_t)en }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::resetStats(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_RESET_STATS, true, NULL, 0)); +} + +int16_t LR11x0::getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2) { + uint8_t buff[8] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_STATS, false, buff, sizeof(buff)); + + // pass the replies + if(nbPktReceived) { *nbPktReceived = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(nbPktCrcError) { *nbPktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(data1) { *data1 = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + if(data2) { *data2 = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } + + return(state); +} + +int16_t LR11x0::getPacketType(uint8_t* type) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE, false, buff, sizeof(buff)); + + // pass the replies + if(type) { *type = buff[0]; } + + return(state); +} + +int16_t LR11x0::getRxBufferStatus(uint8_t* len, uint8_t* startOffset) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(len) { *len = buff[0]; } + if(startOffset) { *startOffset = buff[1]; } + + return(state); +} + +int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt) { + uint8_t buff[3] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; } + if(snrPkt) { *snrPkt = (float)buff[1] / 4.0f; } + if(signalRssiPkt) { *signalRssiPkt = buff[2]; } + + return(state); +} + +int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); + + // pass the replies + // TODO do the value conversion for RSSI (fixed point?) + if(rssiSync) { *rssiSync = (float)buff[0]; } + if(rssiAvg) { *rssiAvg = (float)buff[1]; } + if(rxLen) { *rxLen = buff[2]; } + if(stat) { *stat = buff[3]; } + + return(state); +} + +int16_t LR11x0::getRssiInst(float* rssi) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RSSI_INST, false, buff, sizeof(buff)); + + // pass the replies + if(rssi) { *rssi = (float)buff[0] / -2.0f; } + + return(state); +} + +int16_t LR11x0::setGfskSyncWord(uint8_t* sync) { + if(!sync) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, false, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)); +} + +int16_t LR11x0::setLoRaPublicNetwork(bool pub) { + uint8_t buff[1] = { (uint8_t)pub }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRx(uint32_t timeout) { + uint8_t buff[3] = { + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setTx(uint32_t timeout) { + uint8_t buff[3] = { + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRfFrequency(uint32_t rfFreq) { + uint8_t buff[4] = { + (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF), + (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff))); +} + +int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) { + uint8_t buff[7] = { + (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), intMode, + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_AUTO_TX_RX, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout) { + uint8_t buff[7] = { + symNum, detPeak, detMin, cadExitMode, + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketType(uint8_t type) { + uint8_t buff[1] = { type }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { + uint8_t buff[4] = { sf, bw, cr, ldro }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { + uint8_t buff[10] = { + (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF), + (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw, + (uint8_t)((freqDev >> 24) & 0xFF), (uint8_t)((freqDev >> 16) & 0xFF), + (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsLrFhss(uint32_t br, uint8_t sh) { + uint8_t buff[5] = { + (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF), + (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsSigfox(uint32_t br, uint8_t sh) { + // same as for LR-FHSS + return(this->setModulationParamsLrFhss(br, sh)); +} + +int16_t LR11x0::setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) { + uint8_t buff[6] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + hdrType, payloadLen, crcType, invertIQ + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten) { + uint8_t buff[9] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum) { + uint8_t buff[7] = { + payloadLen, (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF), + (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF), + (uint8_t)((bitNum >> 8) & 0xFF), (uint8_t)(bitNum & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setTxParams(int8_t pwr, uint8_t ramp) { + uint8_t buff[2] = { (uint8_t)pwr, ramp }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketAdrs(uint8_t node, uint8_t broadcast) { + uint8_t buff[2] = { node, broadcast }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRxTxFallbackMode(uint8_t mode) { + uint8_t buff[1] = { mode }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode) { + uint8_t buff[7] = { + (uint8_t)((rxPeriod >> 16) & 0xFF), (uint8_t)((rxPeriod >> 8) & 0xFF), (uint8_t)(rxPeriod & 0xFF), + (uint8_t)((sleepPeriod >> 16) & 0xFF), (uint8_t)((sleepPeriod >> 8) & 0xFF), (uint8_t)(sleepPeriod & 0xFF), + mode + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel) { + uint8_t buff[4] = { paSel, regPaSupply, paDutyCycle, paHpSel }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PA_CONFIG, true, buff, sizeof(buff))); +} + +int16_t LR11x0::stopTimeoutOnPreamble(bool stop) { + uint8_t buff[1] = { (uint8_t)stop }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setCad(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD, true, NULL, 0)); +} + +int16_t LR11x0::setTxCw(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_CW, true, NULL, 0)); +} + +int16_t LR11x0::setTxInfinitePreamble(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE, true, NULL, 0)); +} + +int16_t LR11x0::setLoRaSynchTimeout(uint8_t symbolNum) { + uint8_t buff[1] = { symbolNum }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) { + uint8_t buff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), checkLen + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRangingReqAddr(uint32_t addr) { + uint8_t buff[4] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff))); +} + +int16_t LR11x0::getRangingResult(uint8_t type, float* res) { + uint8_t reqBuff[1] = { type }; + uint8_t rplBuff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_NOP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(res) { + if(type == RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE) { + uint32_t raw = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; + *res = ((float)(raw*3e8))/((float)(4096*this->bandwidthKhz*1000)); + } else { + *res = (float)rplBuff[3]/2.0f; + } + } + + return(state); +} + +int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) { + uint8_t buff[4] = { + (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF), + (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) { + uint8_t buff[8] = { + (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF), + (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), + (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF), + (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff))); + +} + +int16_t LR11x0::setGfskWhitParams(uint16_t seed) { + uint8_t buff[2] = { + (uint8_t)((seed >> 8) & 0xFF), (uint8_t)(seed & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRxBoosted(bool en) { + uint8_t buff[1] = { (uint8_t)en }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRangingParameter(uint8_t symbolNum) { + // the first byte is reserved + uint8_t buff[2] = { 0x00, symbolNum }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { + uint8_t buff[1] = { sync }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff))); +} + +int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len) { + // check maximum size + const uint8_t maxLen[4][4] = { + { 189, 178, 167, 155, }, + { 151, 142, 133, 123, }, + { 112, 105, 99, 92, }, + { 74, 69, 65, 60, }, + }; + if((cr > RADIOLIB_LR11X0_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t buffLen = 9 + len; + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[9 + 190]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set properties of the packet + dataBuff[0] = hdrCount; + dataBuff[1] = cr; + dataBuff[2] = RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK; + dataBuff[3] = grid; + dataBuff[4] = (uint8_t)hop; + dataBuff[5] = bw; + dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01); + dataBuff[7] = (uint8_t)(hopSeq & 0xFF); + dataBuff[8] = devOffset; + memcpy(&dataBuff[9], payload, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen); + #if RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) { + uint8_t buff[4] = { + (uint8_t)((sync >> 24) & 0xFF), (uint8_t)((sync >> 16) & 0xFF), + (uint8_t)((sync >> 8) & 0xFF), (uint8_t)(sync & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, true, buff, sizeof(buff))); +} + +int16_t LR11x0::configBleBeacon(uint8_t chan, uint8_t* payload, size_t len) { + return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len)); +} + +int16_t LR11x0::getLoRaRxHeaderInfos(uint8_t* info) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff)); + + // pass the replies + if(info) { *info = buff[0]; } + + return(state); +} + +int16_t LR11x0::bleBeaconSend(uint8_t chan, uint8_t* payload, size_t len) { + return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len)); +} + +int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len) { + // check maximum size + // TODO what is the actual maximum? + if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[sizeof(uint8_t) + len]; + #endif + + // set the channel + dataBuff[0] = chan; + memcpy(&dataBuff[1], payload, len); + + int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len); + #if RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) { + uint8_t buff[9] = { + type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + acqMode, nbMaxRes, nbScanPerChan, + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + abortOnTimeout + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { + uint8_t buff[9] = { + type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + acqMode, nbMaxRes, + (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF), + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiCountryCode(uint16_t mask, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) { + uint8_t buff[7] = { + (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + nbMaxRes, nbScanPerChan, + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + abortOnTimeout + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { + uint8_t buff[7] = { + (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + nbMaxRes, + (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF), + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiGetNbResults(uint8_t* nbResults) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff)); + + // pass the replies + if(nbResults) { *nbResults = buff[0]; } + + return(state); +} + +int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) { + uint8_t reqBuff[3] = { index, nbResults, format }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::wifiResetCumulTimings(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS, true, NULL, 0)); +} + +int16_t LR11x0::wifiReadCumulTimings(uint32_t* detection, uint32_t* capture, uint32_t* demodulation) { + uint8_t buff[16] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS, false, buff, sizeof(buff)); + + // pass the replies + if(detection) { *detection = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } + if(capture) { *capture = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; } + if(demodulation) { *demodulation = ((uint32_t)(buff[12]) << 24) | ((uint32_t)(buff[13]) << 16) | ((uint32_t)(buff[14]) << 8) | (uint32_t)buff[15]; } + + return(state); +} + +int16_t LR11x0::wifiGetNbCountryCodeResults(uint8_t* nbResults) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS, false, buff, sizeof(buff)); + + // pass the replies + if(nbResults) { *nbResults = buff[0]; } + + return(state); +} + +int16_t LR11x0::wifiReadCountryCodeResults(uint8_t index, uint8_t nbResults, uint8_t* results) { + uint8_t reqBuff[2] = { index, nbResults }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::wifiCfgTimestampAPphone(uint32_t timestamp) { + uint8_t buff[4] = { + (uint8_t)((timestamp >> 24) & 0xFF), (uint8_t)((timestamp >> 16) & 0xFF), + (uint8_t)((timestamp >> 8) & 0xFF), (uint8_t)(timestamp & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiReadVersion(uint8_t* major, uint8_t* minor) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION, false, buff, sizeof(buff)); + + // pass the replies + if(major) { *major = buff[0]; } + if(minor) { *minor = buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssSetConstellationToUse(uint8_t mask) { + uint8_t buff[1] = { mask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadConstellationToUse(uint8_t* mask) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE, false, buff, sizeof(buff)); + + // pass the replies + if(mask) { *mask = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssSetAlmanacUpdate(uint8_t mask) { + uint8_t buff[1] = { mask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAlmanacUpdate(uint8_t* mask) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE, false, buff, sizeof(buff)); + + // pass the replies + if(mask) { *mask = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssReadVersion(uint8_t* fw, uint8_t* almanac) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION, false, buff, sizeof(buff)); + + // pass the replies + if(fw) { *fw = buff[0]; } + if(almanac) { *almanac = buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadSupportedConstellations(uint8_t* mask) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS, false, buff, sizeof(buff)); + + // pass the replies + if(mask) { *mask = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssSetMode(uint8_t mode) { + uint8_t buff[1] = { mode }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAutonomous(uint32_t gpsTime, uint8_t resMask, uint8_t nbSvMask) { + uint8_t buff[7] = { + (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF), + (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF), + RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE, resMask, nbSvMask + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, uint8_t nbSvMask) { + uint8_t buff[7] = { + (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF), + (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF), + effort, resMask, nbSvMask + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ASSISTED, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) { + uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; + uint16_t lonRaw = (lat*2048.0f)/180.0f + 0.5f; + uint8_t buff[4] = { + (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), + (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAssistancePosition(float* lat, float* lon) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION, false, buff, sizeof(buff)); + + // pass the replies + if(lat) { + uint16_t latRaw = ((uint16_t)(buff[0]) << 8) | (uint16_t)(buff[1]); + *lat = ((float)latRaw*90.0f)/2048.0f; + } + if(lon) { + uint16_t lonRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)(buff[3]); + *lon = ((float)lonRaw*180.0f)/2048.0f; + } + + return(state); +} + +int16_t LR11x0::gnssPushSolverMsg(uint8_t* payload, size_t len) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG, true, payload, len)); +} + +int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG, true, payload, len)); +} + +int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) { + // send the command + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, true, NULL, 0); + RADIOLIB_ASSERT(state); + + // read the result - this requires some magic bytes first, that's why LR11x0::SPIcommand cannot be used + uint8_t cmd_buff[3] = { 0x00, 0x02, 0x18 }; + uint8_t buff[9] = { 0 }; + state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + + // pass the replies + if(fwVersion) { *fwVersion = buff[0]; } + if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; } + if(errCode) { *errCode = (buff[5] & 0xF0) >> 4; } + if(almUpdMask) { *almUpdMask = (buff[5] & 0x0E) >> 1; } + if(freqSpace) { *freqSpace = ((buff[5] & 0x01) << 1) | ((buff[6] & 0x80) >> 7); } + + return(state); +} + +int16_t LR11x0::gnssGetNbSvDetected(uint8_t* nbSv) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED, false, buff, sizeof(buff)); + + // pass the replies + if(nbSv) { *nbSv = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, uint16_t* doppler, size_t nbSv) { + // TODO this is arbitrary - is there an actual maximum? + if(nbSv > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t)) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t buffLen = nbSv*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED, false, dataBuff, buffLen); + if(state == RADIOLIB_ERR_NONE) { + for(size_t i = 0; i < nbSv; i++) { + if(svId) { svId[i] = dataBuff[4*i]; } + if(snr) { snr[i] = dataBuff[4*i + 1]; } + if(doppler) { doppler[i] = ((uint16_t)(dataBuff[4*i + 2]) << 8) | (uint16_t)dataBuff[4*i + 3]; } + } + } + + #if RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::gnssGetConsumption(uint32_t* cpu, uint32_t* radio) { + uint8_t buff[8] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION, false, buff, sizeof(buff)); + + // pass the replies + if(cpu) { *cpu = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + if(radio) { *radio = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } + + return(state); +} + +int16_t LR11x0::gnssGetResultSize(uint16_t* size) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE, false, buff, sizeof(buff)); + + // pass the replies + if(size) { *size = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadResults(uint8_t* result, uint16_t size) { + if(!result) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS, false, result, size)); +} + +int16_t LR11x0::gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc) { + uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { + RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID, + (uint8_t)((date >> 8) & 0xFF), (uint8_t)(date & 0xFF), + (uint8_t)((globalCrc >> 24) & 0xFF), (uint8_t)((globalCrc >> 16) & 0xFF), + (uint8_t)((globalCrc >> 8) & 0xFF), (uint8_t)(globalCrc & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac) { + uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { svn }; + memcpy(&buff[1], svnAlmanac, RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE - 1); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { + uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; + uint16_t lonRaw = (lat*2048.0f)/180.0f + 0.5f; + uint8_t reqBuff[9] = { + (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), + (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), + (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), + (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), + constellation, + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { + if(!key) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; + buff[0] = keyId; + memcpy(&buff[1], key, RADIOLIB_AES128_KEY_SIZE); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY, false, buff, sizeof(buff))); +} + +int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key) { + if(!key) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; + buff[0] = srcKeyId; + buff[1] = dstKeyId; + memcpy(&buff[2], key, RADIOLIB_AES128_KEY_SIZE); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY, false, buff, sizeof(buff))); +} + +int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, uint8_t* header, uint8_t* dataIn, size_t len, uint8_t* dataOut) { + // calculate buffer sizes + size_t headerLen = 1; + if(lwVer) { + headerLen += 11; // LoRaWAN 1.1 header is 11 bytes longer than 1.0 + } + size_t reqLen = 3*sizeof(uint8_t) + headerLen + len; + size_t rplLen = sizeof(uint8_t) + len; + + // build buffers + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + uint8_t* rplBuff = new uint8_t[rplLen]; + #endif + + // set the request fields + reqBuff[0] = decKeyId; + reqBuff[1] = verKeyId; + reqBuff[2] = lwVer; + memcpy(&reqBuff[3], header, headerLen); + memcpy(&reqBuff[3 + headerLen], dataIn, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT, false, rplBuff, rplLen, reqBuff, reqLen); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + if(state != RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); + } + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + // pass the data + memcpy(dataOut, &rplBuff[1], len); + return(state); +} + +int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, uint32_t* mic) { + size_t reqLen = sizeof(uint8_t) + len; + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + #endif + uint8_t rplBuff[5] = { 0 }; + + reqBuff[0] = keyId; + memcpy(&reqBuff[1], data, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); + #if RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + if(mic) { *mic = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } + return(state); +} + +int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* data, size_t len, bool* result) { + size_t reqLen = sizeof(uint8_t) + sizeof(uint32_t) + len; + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[sizeof(uint8_t) + sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + #endif + uint8_t rplBuff[1] = { 0 }; + + reqBuff[0] = keyId; + reqBuff[1] = (uint8_t)((micExp >> 24) & 0xFF); + reqBuff[2] = (uint8_t)((micExp >> 16) & 0xFF); + reqBuff[3] = (uint8_t)((micExp >> 8) & 0xFF); + reqBuff[4] = (uint8_t)(micExp & 0xFF); + memcpy(&reqBuff[5], data, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); + #if RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + if(result) { *result = (rplBuff[0] == RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS); } + return(state); +} + +int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { + return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01, keyId, dataIn, len, dataOut)); +} + +int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { + return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT, keyId, dataIn, len, dataOut)); +} + +int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { + return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT, keyId, dataIn, len, dataOut)); +} + +int16_t LR11x0::cryptoStoreToFlash(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH, true, NULL, 0)); +} + +int16_t LR11x0::cryptoRestoreFromFlash(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH, true, NULL, 0)); +} + +int16_t LR11x0::cryptoSetParam(uint8_t id, uint32_t value) { + uint8_t buff[5] = { + id, + (uint8_t)((value >> 24) & 0xFF), (uint8_t)((value >> 16) & 0xFF), + (uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM, true, buff, sizeof(buff))); +} + +int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) { + uint8_t reqBuff[1] = { id }; + uint8_t rplBuff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + if(value) { *value = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } + return(state); +} + +int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len)); +} + +int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT, false, buff, sizeof(buff)); + + // pass the replies + if(result) { *result = (bool)buff[0]; } + + return(state); +} + +int16_t LR11x0::bootEraseFlash(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, true, NULL, 0)); +} + +int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len) { + RADIOLIB_CHECK_RANGE(len, 1, 32, RADIOLIB_ERR_SPI_CMD_INVALID); + return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len)); +} + +int16_t LR11x0::bootReboot(bool stay) { + uint8_t buff[1] = { (uint8_t)stay }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::bootGetPin(uint8_t* pin) { + if(!pin) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); +} + +int16_t LR11x0::bootGetChipEui(uint8_t* eui) { + if(!eui) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { + if(!eui) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, size_t len) { + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set the address or offset + dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF); + dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF); + dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF); + dataBuff[3] = (uint8_t)(addrOffset & 0xFF); + + // convert endians + for(size_t i = 0; i < len; i++) { + dataBuff[4 + i] = (uint8_t)((data[i] >> 24) & 0xFF); + dataBuff[5 + i] = (uint8_t)((data[i] >> 16) & 0xFF); + dataBuff[6 + i] = (uint8_t)((data[i] >> 8) & 0xFF); + dataBuff[7 + i] = (uint8_t)(data[i] & 0xFF); + } + + int16_t state = this->SPIcommand(cmd, true, dataBuff, buffLen); + #if RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { + // build buffers + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[sizeof(uint8_t) + len]; + uint8_t* rplBuff = new uint8_t[sizeof(uint8_t) + len]; + #endif + + // set the request fields + reqBuff[0] = keyId; + memcpy(&reqBuff[1], dataIn, len); + + int16_t state = this->SPIcommand(cmd, false, rplBuff, sizeof(uint8_t) + len, reqBuff, sizeof(uint8_t) + len); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + if(state != RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); + } + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + // pass the data + memcpy(dataOut, &rplBuff[1], len); + return(state); +} + +#endif diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h new file mode 100644 index 0000000000..88c4eee7d0 --- /dev/null +++ b/src/modules/LR11x0/LR11x0.h @@ -0,0 +1,1018 @@ +#if !defined(_RADIOLIB_LR11X0_H) +#define _RADIOLIB_LR11X0_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// LR11X0 physical layer properties +#define RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE 0.9536743164 +#define RADIOLIB_LR11X0_MAX_PACKET_LENGTH 255 +#define RADIOLIB_LR11X0_CRYSTAL_FREQ 32.0 +#define RADIOLIB_LR11X0_DIV_EXPONENT 25 + +// LR11X0 SPI commands +#define RADIOLIB_LR11X0_CMD_NOP (0x0000) +#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM (0x0105) +#define RADIOLIB_LR11X0_CMD_READ_REG_MEM (0x0106) +#define RADIOLIB_LR11X0_CMD_WRITE_BUFFER (0x0109) +#define RADIOLIB_LR11X0_CMD_READ_BUFFER (0x010A) +#define RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER (0x010B) +#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK (0x010C) +#define RADIOLIB_LR11X0_CMD_GET_STATUS (0x0100) +#define RADIOLIB_LR11X0_CMD_GET_VERSION (0x0101) +#define RADIOLIB_LR11X0_CMD_GET_ERRORS (0x010D) +#define RADIOLIB_LR11X0_CMD_CLEAR_ERRORS (0x010E) +#define RADIOLIB_LR11X0_CMD_CALIBRATE (0x010F) +#define RADIOLIB_LR11X0_CMD_SET_REG_MODE (0x0110) +#define RADIOLIB_LR11X0_CMD_CALIB_IMAGE (0x0111) +#define RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH (0x0112) +#define RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS (0x0113) +#define RADIOLIB_LR11X0_CMD_CLEAR_IRQ (0x0114) +#define RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK (0x0116) +#define RADIOLIB_LR11X0_CMD_SET_TCXO_MODE (0x0117) +#define RADIOLIB_LR11X0_CMD_REBOOT (0x0118) +#define RADIOLIB_LR11X0_CMD_GET_VBAT (0x0119) +#define RADIOLIB_LR11X0_CMD_GET_TEMP (0x011A) +#define RADIOLIB_LR11X0_CMD_SET_SLEEP (0x011B) +#define RADIOLIB_LR11X0_CMD_SET_STANDBY (0x011C) +#define RADIOLIB_LR11X0_CMD_SET_FS (0x011D) +#define RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER (0x0120) +#define RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE (0x0121) +#define RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE (0x0122) +#define RADIOLIB_LR11X0_CMD_READ_INFO_PAGE (0x0123) +#define RADIOLIB_LR11X0_CMD_GET_CHIP_EUI (0x0125) +#define RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI (0x0126) +#define RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN (0x0127) +#define RADIOLIB_LR11X0_CMD_ENABLE_SPI_CRC (0x0128) +#define RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE (0x012A) +#define RADIOLIB_LR11X0_CMD_RESET_STATS (0x0200) +#define RADIOLIB_LR11X0_CMD_GET_STATS (0x0201) +#define RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE (0x0202) +#define RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS (0x0203) +#define RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS (0x0204) +#define RADIOLIB_LR11X0_CMD_GET_RSSI_INST (0x0205) +#define RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD (0x0206) +#define RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK (0x0208) +#define RADIOLIB_LR11X0_CMD_SET_RX (0x0209) +#define RADIOLIB_LR11X0_CMD_SET_TX (0x020A) +#define RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY (0x020B) +#define RADIOLIB_LR11X0_CMD_AUTO_TX_RX (0x020C) +#define RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS (0x020D) +#define RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE (0x020E) +#define RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS (0x020F) +#define RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS (0x0210) +#define RADIOLIB_LR11X0_CMD_SET_TX_PARAMS (0x0211) +#define RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS (0x0212) +#define RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE (0x0213) +#define RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE (0x0214) +#define RADIOLIB_LR11X0_CMD_SET_PA_CONFIG (0x0215) +#define RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0217) +#define RADIOLIB_LR11X0_CMD_SET_CAD (0x0218) +#define RADIOLIB_LR11X0_CMD_SET_TX_CW (0x0219) +#define RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE (0x021A) +#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT (0x021B) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR (0x021C) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR (0x021D) +#define RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT (0x021E) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY (0x021F) +#define RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS (0x0224) +#define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225) +#define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228) +#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B) +#define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C) +#define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D) +#define RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON (0x022E) +#define RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS (0x0230) +#define RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND (0x0231) +#define RADIOLIB_LR11X0_CMD_WIFI_SCAN (0x0300) +#define RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT (0x0301) +#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE (0x0302) +#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT (0x0303) +#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS (0x0305) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS (0x0306) +#define RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS (0x0307) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS (0x0308) +#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS (0x0309) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS (0x030A) +#define RADIOLIB_LR11X0_CMD_WIFI_CFG_TIMESTAMP_AP_PHONE (0x030B) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION (0x0320) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE (0x0400) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE (0x0401) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE (0x0402) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE (0x0403) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION (0x0406) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS (0x0407) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408) +#define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409) +#define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411) +#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414) +#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG (0x0415) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS (0x0416) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F) +#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502) +#define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503) +#define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504) +#define RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC (0x0505) +#define RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC (0x0506) +#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01 (0x0507) +#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT (0x0508) +#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT (0x0509) +#define RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH (0x050A) +#define RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH (0x050B) +#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM (0x050D) +#define RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM (0x050E) +#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE (0x050F) +#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT (0x0510) +#define RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH (0x8000) +#define RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED (0x8003) +#define RADIOLIB_LR11X0_CMD_BOOT_REBOOT (0x8005) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_PIN (0x800B) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI (0x800C) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI (0x800D) + +// LR11X0 register map +#define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414) +#define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054) + +// LR11X0 SPI command variables + +// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION +#define RADIOLIB_LR11X0_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed +#define RADIOLIB_LR11X0_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error +#define RADIOLIB_LR11X0_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed +#define RADIOLIB_LR11X0_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted +#define RADIOLIB_LR11X0_STAT_1_IRQ_INACTIVE (0x00UL << 0) // 0 0 interrupt status: inactive +#define RADIOLIB_LR11X0_STAT_1_IRQ_ACTIVE (0x01UL << 0) // 0 0 at least 1 interrupt active +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_CLEARED (0x00UL << 4) // 7 4 reset status: cleared +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_ANALOG (0x01UL << 4) // 7 4 analog (power on, brown-out) +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_EXTERNAL (0x02UL << 4) // 7 4 NRESET pin +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_SYSTEM (0x03UL << 4) // 7 4 system +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WATCHDOG (0x04UL << 4) // 7 4 watchdog +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WAKEUP (0x05UL << 4) // 7 4 NSS toggling wake-up +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_RTC (0x06UL << 4) // 7 4 realtime clock +#define RADIOLIB_LR11X0_STAT_2_MODE_SLEEP (0x00UL << 1) // 3 1 chip mode: sleep +#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_RC (0x01UL << 1) // 3 1 standby with RC oscillator +#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_OSC (0x02UL << 1) // 3 1 standby with external oscillator +#define RADIOLIB_LR11X0_STAT_2_MODE_FS (0x03UL << 1) // 3 1 frequency synthesis +#define RADIOLIB_LR11X0_STAT_2_MODE_RX (0x04UL << 1) // 3 1 receive +#define RADIOLIB_LR11X0_STAT_2_MODE_TX (0x05UL << 1) // 3 1 transmit +#define RADIOLIB_LR11X0_STAT_2_MODE_WIFI_GNSS (0x06UL << 1) // 3 1 WiFi or GNSS geolocation +#define RADIOLIB_LR11X0_STAT_2_BOOT (0x00UL << 0) // 0 0 code executed from: bootloader +#define RADIOLIB_LR11X0_STAT_2_FLASH (0x01UL << 0) // 0 0 flash + +// RADIOLIB_LR11X0_CMD_WRITE_REG_MEM +#define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes + +// RADIOLIB_LR11X0_CMD_GET_VERSION +#define RADIOLIB_LR11X0_HW_LR1110 (0x01UL << 0) // 7 0 HW version: LR1110 +#define RADIOLIB_LR11X0_HW_LR1120 (0x02UL << 0) // 7 0 LR1120 +#define RADIOLIB_LR11X0_HW_LR1121 (0x03UL << 0) // 7 0 LR1121 +#define RADIOLIB_LR11X0_HW_BOOT (0xDFUL << 0) // 7 0 bootloader mode + +// RADIOLIB_LR11X0_CMD_GET_ERRORS +#define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_HF_RC_CALIB_ERR (0x01UL << 1) // 15 0 high frequency RC not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_ADC_CALIB_ERR (0x01UL << 2) // 15 0 ADC not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_PLL_CALIB_ERR (0x01UL << 3) // 15 0 PLL not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_IMG_CALIB_ERR (0x01UL << 4) // 15 0 image rejection not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR (0x01UL << 5) // 15 0 high frequency oscillator failed to start +#define RADIOLIB_LR11X0_ERROR_STAT_LF_XOSC_START_ERR (0x01UL << 6) // 15 0 low frequency oscillator failed to start +#define RADIOLIB_LR11X0_ERROR_STAT_PLL_LOCK_ERR (0x01UL << 7) // 15 0 PLL failed to lock +#define RADIOLIB_LR11X0_ERROR_STAT_RX_ADC_OFFSET_ERR (0x01UL << 8) // 15 0 ADC offset not calibrated + +// RADIOLIB_LR11X0_CMD_CALIBRATE +#define RADIOLIB_LR11X0_CALIBRATE_PLL_TX (0x01UL << 5) // 5 5 calibrate: Tx PLL +#define RADIOLIB_LR11X0_CALIBRATE_IMG (0x01UL << 4) // 4 4 image rejection +#define RADIOLIB_LR11X0_CALIBRATE_ADC (0x01UL << 3) // 3 3 A/D converter +#define RADIOLIB_LR11X0_CALIBRATE_PLL (0x01UL << 2) // 2 2 PLL +#define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC +#define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC +#define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything + +// RADIOLIB_LR11X0_CMD_SET_REG_MODE +#define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes +#define RADIOLIB_LR11X0_REG_MODE_DC_DC (0x01UL << 0) // 0 0 DC-DC and LDO + +// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH +#define RADIOLIB_LR11X0_RFSW_DIO5_ENABLED (0x01UL << 0) // 4 0 RF switch: DIO5 enabled +#define RADIOLIB_LR11X0_RFSW_DIO5_DISABLED (0x00UL << 0) // 4 0 DIO5 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO6_ENABLED (0x01UL << 1) // 4 0 RF switch: DIO6 enabled +#define RADIOLIB_LR11X0_RFSW_DIO6_DISABLED (0x00UL << 1) // 4 0 DIO6 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO7_ENABLED (0x01UL << 2) // 4 0 RF switch: DIO7 enabled +#define RADIOLIB_LR11X0_RFSW_DIO7_DISABLED (0x00UL << 2) // 4 0 DIO7 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO8_ENABLED (0x01UL << 3) // 4 0 RF switch: DIO8 enabled +#define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled +#define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default) + +// RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted +#define RADIOLIB_LR11X0_IRQ_RX_DONE (0x01UL << 3) // 31 0 packet received +#define RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED (0x01UL << 4) // 31 0 preamble detected +#define RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID (0x01UL << 5) // 31 0 sync word or LoRa header valid +#define RADIOLIB_LR11X0_IRQ_HEADER_ERR (0x01UL << 6) // 31 0 LoRa header CRC error +#define RADIOLIB_LR11X0_IRQ_CRC_ERR (0x01UL << 7) // 31 0 packet CRC error +#define RADIOLIB_LR11X0_IRQ_CAD_DONE (0x01UL << 8) // 31 0 CAD completed +#define RADIOLIB_LR11X0_IRQ_CAD_DETECTED (0x01UL << 9) // 31 0 CAD detected +#define RADIOLIB_LR11X0_IRQ_TIMEOUT (0x01UL << 10) // 31 0 Rx or Tx timeout +#define RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP (0x01UL << 11) // 31 0 FHSS hop +#define RADIOLIB_LR11X0_IRQ_GNSS_DONE (0x01UL << 19) // 31 0 GNSS scan finished +#define RADIOLIB_LR11X0_IRQ_WIFI_DONE (0x01UL << 20) // 31 0 WiFi scan finished +#define RADIOLIB_LR11X0_IRQ_LBD (0x01UL << 21) // 31 0 low battery detected +#define RADIOLIB_LR11X0_IRQ_CMD_ERROR (0x01UL << 22) // 31 0 command error +#define RADIOLIB_LR11X0_IRQ_ERROR (0x01UL << 23) // 31 0 some other error than CMD_ERR +#define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error +#define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error +#define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source) +#define RADIOLIB_LR11X0_IRQ_ALL (0x0BF80FFCUL) // 31 0 all interrupts +#define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts + +// RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK +#define RADIOLIB_LR11X0_LF_CLK_RC (0x00UL << 0) // 1 0 32.768 kHz source: RC oscillator +#define RADIOLIB_LR11X0_LF_CLK_XOSC (0x01UL << 0) // 1 0 crystal oscillator +#define RADIOLIB_LR11X0_LF_CLK_EXT (0x02UL << 0) // 1 0 external signal on DIO11 +#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED (0x00UL << 2) // 2 2 +#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED (0x01UL << 2) // 2 2 + +// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V + +// RADIOLIB_LR11X0_CMD_SET_SLEEP +#define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled +#define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled +#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 0) // 1 1 automated wakeup: disabled +#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 0) // 1 1 enabled + +// RADIOLIB_LR11X0_CMD_SET_STANDBY +#define RADIOLIB_LR11X0_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator +#define RADIOLIB_LR11X0_STANDBY_XOSC (0x00UL << 0) // 7 0 XTAL/TCXO oscillator + +// RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE +#define RADIOLIB_LR11X0_INFO_PAGE (1) + +// RADIOLIB_LR11X0_CMD_GET_CHIP_EUI +#define RADIOLIB_LR11X0_EUI_LEN (8) + +// RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN +#define RADIOLIB_LR11X0_PIN_LEN (4) + +// RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS +#define RADIOLIB_LR11X0_RX_STATUS_ADDR_ERR (0x01UL << 5) // 7 0 Rx status: address filtering error +#define RADIOLIB_LR11X0_RX_STATUS_CRC_ERR (0x01UL << 4) // 7 0 CRC error +#define RADIOLIB_LR11X0_RX_STATUS_LEN_ERR (0x01UL << 3) // 7 0 length filtering error +#define RADIOLIB_LR11X0_RX_STATUS_ABORTED (0x01UL << 2) // 7 0 packet reception aborted +#define RADIOLIB_LR11X0_RX_STATUS_PACKET_RECEIVED (0x01UL << 1) // 7 0 packet received +#define RADIOLIB_LR11X0_RX_STATUS_PACKET_SENT (0x01UL << 0) // 7 0 packet sent + +// RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD +#define RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN (8) + +// RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK +#define RADIOLIB_LR11X0_LORA_PRIVATE_NETWORK (0x00UL << 0) // 7 0 LoRa sync word: private network +#define RADIOLIB_LR11X0_LORA_PUBLIC_NETWORK (0x01UL << 0) // 7 0 public network + +// RADIOLIB_LR11X0_CMD_SET_RX +#define RADIOLIB_LR11X0_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_LR11X0_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode) + +// RADIOLIB_LR11X0_CMD_SET_TX +#define RADIOLIB_LR11X0_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout + +// RADIOLIB_LR11X0_CMD_AUTO_TX_RX +#define RADIOLIB_LR11X0_AUTO_TX_RX_DISABLED (0xFFFFFFUL) // 23 0 disable auto Tx/Rx mode +#define RADIOLIB_LR11X0_AUTO_TX_RX_SKIP_INT (0x000000UL) // 23 0 skip intermediary mode +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_SLEEP (0x00UL << 0) // 1 0 intermediary mode: sleep +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_RC (0x01UL << 0) // 1 0 standby with RC +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis +#define RADIOLIB_LR11X0_AUTO_TX_RX_TIMEOUT_DISABLED (0x000000UL) // 23 0 disable timeout of the second mode + +// RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS +#define RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC (0x00UL << 0) // 7 0 mode to set after CAD: standby with RC +#define RADIOLIB_LR11X0_CAD_EXIT_MODE_RX (0x01UL << 0) // 7 0 receive if activity detected +#define RADIOLIB_LR11X0_CAD_EXIT_MODE_LBT (0x10UL << 0) // 7 0 transmit if no activity detected + +// RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE +#define RADIOLIB_LR11X0_PACKET_TYPE_NONE (0x00UL << 0) // 2 0 packet type: none +#define RADIOLIB_LR11X0_PACKET_TYPE_GFSK (0x01UL << 0) // 2 0 (G)FSK +#define RADIOLIB_LR11X0_PACKET_TYPE_LORA (0x02UL << 0) // 2 0 LoRa +#define RADIOLIB_LR11X0_PACKET_TYPE_SIGFOX (0x03UL << 0) // 2 0 Sigfox +#define RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS (0x04UL << 0) // 2 0 GMSK/LR-FHSS +#define RADIOLIB_LR11X0_PACKET_TYPE_RANGING (0x05UL << 0) // 2 0 ranging +#define RADIOLIB_LR11X0_PACKET_TYPE_BLE (0x06UL << 0) // 2 0 BLE beacon + +// RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_LR11X0_LORA_BW_62_5 (0x03UL << 0) // 7 0 LoRa bandwidth: 62.5 kHz +#define RADIOLIB_LR11X0_LORA_BW_125_0 (0x04UL << 0) // 7 0 125.0 kHz +#define RADIOLIB_LR11X0_LORA_BW_250_0 (0x05UL << 0) // 7 0 250.0 kHz +#define RADIOLIB_LR11X0_LORA_BW_500_0 (0x06UL << 0) // 7 0 500.0 kHz +#define RADIOLIB_LR11X0_LORA_CR_4_5_SHORT (0x01UL << 0) // 7 0 coding rate: 4/5 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_6_SHORT (0x02UL << 0) // 7 0 4/6 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_7_SHORT (0x03UL << 0) // 7 0 4/7 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_8_SHORT (0x04UL << 0) // 7 0 4/8 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_5_LONG (0x05UL << 0) // 7 0 4/5 with long interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_6_LONG (0x06UL << 0) // 7 0 4/6 with long interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_8_LONG (0x07UL << 0) // 7 0 4/8 with long interleaver +#define RADIOLIB_LR11X0_LORA_LDRO_DISABLED (0x00UL << 0) // 7 0 low data rate optimize: disabled +#define RADIOLIB_LR11X0_LORA_LDRO_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_DISABLED (0x00UL << 31) // 31 0 divide bit rate value by 256: disabled +#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_ENABLED (0x01UL << 31) // 31 0 enabled +#define RADIOLIB_LR11X0_GFSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3 (0x08UL << 0) // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5 (0x09UL << 0) // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7 (0x0AUL << 0) // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 Gaussian, BT = 1.0 +#define RADIOLIB_LR11X0_GFSK_SHAPING_RAISED_COSINE_BT_0_7 (0x16UL << 0) // 7 0 raised cosine, BT = 0.7 +#define RADIOLIB_LR11X0_GFSK_RX_BW_4_8 (0x1FUL << 0) // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_5_8 (0x17UL << 0) // 7 0 5.8 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_7_3 (0x0FUL << 0) // 7 0 7.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_9_7 (0x1EUL << 0) // 7 0 9.7 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_11_7 (0x16UL << 0) // 7 0 11.7 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_14_6 (0x0EUL << 0) // 7 0 14.6 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_19_5 (0x1DUL << 0) // 7 0 19.5 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_23_4 (0x15UL << 0) // 7 0 23.4 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_29_3 (0x0DUL << 0) // 7 0 29.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_39_0 (0x1CUL << 0) // 7 0 39.0 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_46_9 (0x14UL << 0) // 7 0 46.9 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_58_6 (0x0CUL << 0) // 7 0 58.6 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_78_2 (0x1BUL << 0) // 7 0 78.2 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_93_8 (0x13UL << 0) // 7 0 93.8 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_117_3 (0x0BUL << 0) // 7 0 117.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_156_2 (0x1AUL << 0) // 7 0 156.2 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_187_2 (0x12UL << 0) // 7 0 187.2 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_234_3 (0x0AUL << 0) // 7 0 234.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (0x8001E848UL) // 31 0 LR FHSS bit rate: 488.28215 bps +#define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0 +#define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7 + +// RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS +#define RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit +#define RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit +#define RADIOLIB_LR11X0_LORA_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length +#define RADIOLIB_LR11X0_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled +#define RADIOLIB_LR11X0_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled +#define RADIOLIB_LR11X0_LORA_IQ_STANDARD (0x00UL << 0) // 7 0 IQ setup: standard +#define RADIOLIB_LR11X0_LORA_IQ_INVERTED (0x01UL << 0) // 7 0 inverted +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED (0x00UL << 0) // 7 0 preamble detector: disabled +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS (0x04UL << 0) // 7 0 8 bits +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS (0x05UL << 0) // 7 0 16 bits +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS (0x06UL << 0) // 7 0 24 bits +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS (0x07UL << 0) // 7 0 32 bits +#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled +#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE (0x01UL << 0) // 7 0 node address +#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast address +#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED (0x00UL << 0) // 7 0 packet length: fixed +#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE (0x01UL << 0) // 7 0 variable +#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE_SX128X (0x02UL << 0) // 7 0 variable, SX128x 9-bit length encoding +#define RADIOLIB_LR11X0_GFSK_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length +#define RADIOLIB_LR11X0_GFSK_CRC_DISABLED (0x01UL << 0) // 7 0 CRC: disabled +#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE (0x00UL << 0) // 7 0 1-byte +#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE (0x02UL << 0) // 7 0 2-byte +#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV (0x04UL << 0) // 7 0 1-byte, inverted +#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV (0x06UL << 0) // 7 0 2-byte, inverted +#define RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED (0x00UL << 0) // 7 0 whitening: disabled +#define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled + +// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS +#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 PA ramp time: 48 us + +// RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC +#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC +#define RADIOLIB_LR11X0_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis + +// RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE +#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default) +#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD +#define RADIOLIB_LR11X0_TIMING_STEP (1.0f/32768.0f) // 23 0 timing step fo delays + +// RADIOLIB_LR11X0_CMD_SET_PA_CONFIG +#define RADIOLIB_LR11X0_PA_SEL_LP (0x00UL << 0) // 7 0 PA select: low power PA +#define RADIOLIB_LR11X0_PA_SEL_HP (0x01UL << 0) // 7 0 high power PA +#define RADIOLIB_LR11X0_PA_SEL_HF (0x02UL << 0) // 7 0 high frequency PA +#define RADIOLIB_LR11X0_PA_SUPPLY_INTERNAL (0x00UL << 0) // 7 0 PA power source: internal +#define RADIOLIB_LR11X0_PA_SUPPLY_VBAT (0x01UL << 0) // 7 0 VBAT (required for >= 14 dBm) + +// RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE +#define RADIOLIB_LR11X0_STOP_ON_SYNC_HEADER (0x00UL << 0) // 0 0 stop timeout on: sync word or header (default) +#define RADIOLIB_LR11X0_STOP_ON_PREAMBLE (0x01UL << 0) // 0 0 preamble + +// RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT +#define RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE (0) // 7 0 ranging result type: distance +#define RADIOLIB_LR11X0_RANGING_RESULT_RSSI (1) // 7 0 RSSI + +// RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED +#define RADIOLIB_LR11X0_RX_BOOSTED_ENABLED (0x01UL << 0) // 0 0 Rx boosted mode: enabled +#define RADIOLIB_LR11X0_RX_BOOSTED_DISABLED (0x00UL << 0) // 0 0 disabled + +// RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD +#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12) +#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PUBLIC (0x34) + +// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME +#define RADIOLIB_LR11X0_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 +#define RADIOLIB_LR11X0_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 +#define RADIOLIB_LR11X0_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 +#define RADIOLIB_LR11X0_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 +#define RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK +#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) +#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) +#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled +#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_LR11X0_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz + +// RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS +#define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled +#define RADIOLIB_LR11X0_LAST_HEADER_CRC_DISABLED (0x00UL << 4) // 4 4 disabled + +// RADIOLIB_LR11X0_CMD_WIFI_SCAN +#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_B (0x01UL << 0) // 7 0 Wi-Fi type to scan: 802.11b +#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_G (0x02UL << 0) // 7 0 802.11g +#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_N (0x03UL << 0) // 7 0 802.11n +#define RADIOLIB_LR11X0_WIFI_SCAN_ALL (0x04UL << 0) // 7 0 all (802.11b first) +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_ONLY (0x01UL << 0) // 7 0 Wi-Fi acquisition mode: beacon only +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_PACKET (0x02UL << 0) // 7 0 beacon and packet +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_TRAFFIC (0x03UL << 0) // 7 0 full traffic +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON (0x04UL << 0) // 7 0 full beacon +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon +#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled +#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled + +// RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS +#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete +#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic + +// RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE +#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS +#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU (0x01UL << 1) // 7 0 BeiDou + +// RADIOLIB_LR11X0_CMD_GNSS_SET_MODE +#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_SCAN (0x00UL << 0) // 7 0 GNSS scanning mode: single/legacy +#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_MULTIPLE (0x03UL << 1) // 7 0 multiple/advanced + +// RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS +#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_ENABLED (0x01UL << 0) // 0 0 GNSS results in NAV message: pseudo-range (in single scan mode) or Doppler information (in multiple scan mode) +#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_DISABLED (0x00UL << 0) // 0 0 not included +#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_ENABLED (0x01UL << 1) // 1 1 Doppler information +#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_DISABLED (0x00UL << 1) // 1 1 not included +#define RADIOLIB_LR11X0_GNSS_NB_SV_ALL (0x00UL << 0) // 7 0 include all detected satellites +#define RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE (0x00UL << 0) // 7 0 reserved, always 0 + +// RADIOLIB_LR11X0_CMD_GNSS_ASSISTED +#define RADIOLIB_LR11X0_GNSS_ASSIST_LOW_POWER (0x00UL << 0) // 7 0 effort mode: low power +#define RADIOLIB_LR11X0_GNSS_ASSIST_BEST_EFFORT (0x01UL << 0) // 7 0 best effort + +// RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_NONE (0x00UL << 0) // 7 4 error code: none +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_OLD (0x01UL << 0) // 7 4 almanac too old +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_CRC (0x02UL << 0) // 7 4 almanac CRC mismatch +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 H +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz + +// RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE +#define RADIOLIB_LR11X0_SV_CONSTELLATION_GPS (0x00UL << 0) // 7 0 GNSS constellation: GPS +#define RADIOLIB_LR11X0_SV_CONSTELLATION_BEIDOU (0x01UL << 0) // 7 0 BeiDou + +// RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE +#define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header +#define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20) + +// RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY +#define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success +#define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed +#define RADIOLIB_LR11X0_CRYPTO_STATUS_INV_KEY_ID (0x03UL << 0) // 7 0 key/parameter source or destination ID error +#define RADIOLIB_LR11X0_CRYPTO_STATUS_BUF_SIZE (0x05UL << 0) // 7 0 data buffer size invalid +#define RADIOLIB_LR11X0_CRYPTO_STATUS_ERROR (0x06UL << 0) // 7 0 generic error + +// RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT +#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_0 (0x00UL << 0) // 7 0 LoRaWAN version: 1.0.x +#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_1 (0x01UL << 0) // 7 0 1.1 + +// LR11X0 SPI register variables + +// RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT +#define RADIOLIB_LR11X0_SF6_SX126X (0x00UL << 18) // 18 18 SF6 mode: SX126x series +#define RADIOLIB_LR11X0_SF6_SX127X (0x01UL << 18) // 18 18 SX127x series + +// RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX +#define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata + + +/*! + \class LR11x0 + \brief +*/ +class LR11x0: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + LR11x0(Module* mod); + + /*! + \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. + */ + bool XTAL; + + /*! + \brief Initialization method for LoRa modem. + \param bw LoRa bandwidth in kHz. + \param sf LoRa spreading factor. + \param cr LoRa coding rate denominator. + \param syncWord 1-byte LoRa sync word. + \param preambleLength LoRa preamble length in symbols + \param tcxoVoltage TCXO reference voltage to be set. + \returns \ref status_codes + */ + int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage); + + /*! + \brief Initialization method for FSK modem. + \param br FSK bit rate in kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. + \param rxBw Receiver bandwidth in kHz. + \param preambleLength FSK preamble length in bits. + \param tcxoVoltage TCXO reference voltage to be set. + \returns \ref status_codes + */ + int16_t beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + \returns \ref status_codes + */ + int16_t reset(); + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len) override; + + /*! + \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR11X0_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_LR11X0_STANDBY_XOSC (32 MHz external crystal oscillator). + \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode, bool wakeup = true); + + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") + or to false to discard current configuration ("cold start"). Defaults to true. + \param sleepTime Sleep duration (enables automatic wakeup), in multiples of 30.52 us. Ignored if set to 0. + \returns \ref status_codes + */ + int16_t sleep(bool retainConfig = true, uint32_t sleepTime = 0); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when DIO1 activates. + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + void clearDio1Action(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction(); + + /*! + \brief Interrupt-driven binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + \param timeout Raw timeout value, expressed as multiples of 1/32.768 kHz (approximately 30.52 us). + Defaults to RADIOLIB_LR11X0_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), + set to RADIOLIB_LR11X0_RX_TIMEOUT_NONE for no timeout (Rx single mode). + If timeout other than infinite is set, signal will be generated on DIO1. + + \param irqFlags Sets the IRQ flags that will trigger DIO1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE. + \param len Only for PhysicalLayer compatibility, not used. + \returns \ref status_codes + */ + int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, size_t len = 0); + + /*! + \brief Reads the current IRQ status. + \returns IRQ status bits + */ + uint32_t getIrqStatus(); + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + // configuration methods + + /*! + \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. + \param bw LoRa bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. + \param sf LoRa spreading factor to be set. + \param legacy Enable legacy mode for SF6 - this allows to communicate with SX127x at SF6. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf, bool legacy = false); + + /*! + \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + \param cr LoRa coding rate denominator to be set. + \param longInterleave Enable long interleaver when set to true. + Note that CR 4/7 is not possible with long interleaver enabled! + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr, bool longInterleave = false); + + /*! + \brief Sets LoRa sync word. + \param syncWord LoRa sync word to be set. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t syncWord); + + /*! + \brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535. + \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK). + \returns \ref status_codes + */ + int16_t setPreambleLength(size_t preambleLength) override; + + /*! + \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration. + \param voltage TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. + Set to 0 to disable TCXO. + NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO). + \param delay TCXO timeout in us. Defaults to 5000 us. + \returns \ref status_codes + */ + int16_t setTCXO(float voltage, uint32_t delay = 5000); + + /*! + \brief Sets CRC configuration. + \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. + \param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC). + \param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC). + \param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC). + \returns \ref status_codes + */ + int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true); + + /*! + \brief Enable/disable inversion of the I and Q signals + \param enable QI inversion enabled (true) or disabled (false); + \returns \ref status_codes + */ + int16_t invertIQ(bool enable) override; + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem. + \returns RSSI of the last received packet in dBm. + */ + float getRSSI(); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. + \returns SNR of the last received packet in dB. + */ + float getSNR(); + + /*! + \brief Gets frequency error of the latest received packet. + \returns Frequency error in Hz. + */ + float getFrequencyError(); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update, uint8_t* offset); + + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len) override; + + /*! + \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. + \returns Effective data rate in bps. + */ + float getDataRate() const; + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod(); + + // LR11x0 SPI command implementations + int16_t writeRegMem32(uint32_t addr, uint32_t* data, size_t len); + int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); + int16_t writeBuffer8(uint8_t* data, size_t len); + int16_t readBuffer8(uint8_t* data, size_t len, size_t offset); + int16_t clearRxBuffer(void); + int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data); + + int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); + int16_t getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor); + int16_t getErrors(uint16_t* err); + int16_t clearErrors(void); + int16_t calibrate(uint8_t params); + int16_t setRegMode(uint8_t mode); + int16_t calibImage(float freq1, float freq2); + int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t gnssCfg, uint8_t wifiCfg); + int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2); + int16_t clearIrq(uint32_t irq); + int16_t configLfClock(uint8_t setup); + int16_t setTcxoMode(uint8_t tune, uint32_t delay); + int16_t reboot(bool stay); + int16_t getVbat(float* vbat); + int16_t getTemp(float* temp); + int16_t setFs(void); + int16_t getRandomNumber(uint32_t* rnd); + int16_t eraseInfoPage(void); + int16_t writeInfoPage(uint16_t addr, uint32_t* data, size_t len); + int16_t readInfoPage(uint16_t addr, uint32_t* data, size_t len); + int16_t getChipEui(uint8_t* eui); + int16_t getSemtechJoinEui(uint8_t* eui); + int16_t deriveRootKeysAndGetPin(uint8_t* pin); + int16_t enableSpiCrc(bool en); + int16_t driveDiosInSleepMode(bool en); + + int16_t resetStats(void); + int16_t getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2); + int16_t getPacketType(uint8_t* type); + int16_t getRxBufferStatus(uint8_t* len, uint8_t* startOffset); + int16_t getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt); + int16_t getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat); + int16_t getRssiInst(float* rssi); + int16_t setGfskSyncWord(uint8_t* sync); + int16_t setLoRaPublicNetwork(bool pub); + int16_t setRx(uint32_t timeout); + int16_t setTx(uint32_t timeout); + int16_t setRfFrequency(uint32_t rfFreq); + int16_t autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout); + int16_t setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout); + int16_t setPacketType(uint8_t type); + int16_t setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); + int16_t setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev); + int16_t setModulationParamsLrFhss(uint32_t br, uint8_t sh); + int16_t setModulationParamsSigfox(uint32_t br, uint8_t sh); + int16_t setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ); + int16_t setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten); + int16_t setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum); + int16_t setTxParams(int8_t pwr, uint8_t ramp); + int16_t setPacketAdrs(uint8_t node, uint8_t broadcast); + int16_t setRxTxFallbackMode(uint8_t mode); + int16_t setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode); + int16_t setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel); + int16_t stopTimeoutOnPreamble(bool stop); + int16_t setCad(void); + int16_t setTxCw(void); + int16_t setTxInfinitePreamble(void); + int16_t setLoRaSynchTimeout(uint8_t symbolNum); + int16_t setRangingAddr(uint32_t addr, uint8_t checkLen); + int16_t setRangingReqAddr(uint32_t addr); + int16_t getRangingResult(uint8_t type, float* res); + int16_t setRangingTxRxDelay(uint32_t delay); + int16_t setGfskCrcParams(uint32_t init, uint32_t poly); + int16_t setGfskWhitParams(uint16_t seed); + int16_t setRxBoosted(bool en); + int16_t setRangingParameter(uint8_t symbolNum); + int16_t setLoRaSyncWord(uint8_t sync); + int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len); + int16_t lrFhssSetSyncWord(uint32_t sync); + int16_t configBleBeacon(uint8_t chan, uint8_t* payload, size_t len); + int16_t getLoRaRxHeaderInfos(uint8_t* info); + int16_t bleBeaconSend(uint8_t chan, uint8_t* payload, size_t len); + + int16_t wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout); + int16_t wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout); + int16_t wifiCountryCode(uint16_t mask, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout); + int16_t wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout); + int16_t wifiGetNbResults(uint8_t* nbResults); + int16_t wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results); + int16_t wifiResetCumulTimings(void); + int16_t wifiReadCumulTimings(uint32_t* detection, uint32_t* capture, uint32_t* demodulation); + int16_t wifiGetNbCountryCodeResults(uint8_t* nbResults); + int16_t wifiReadCountryCodeResults(uint8_t index, uint8_t nbResults, uint8_t* results); + int16_t wifiCfgTimestampAPphone(uint32_t timestamp); + int16_t wifiReadVersion(uint8_t* major, uint8_t* minor); + + int16_t gnssSetConstellationToUse(uint8_t mask); + int16_t gnssReadConstellationToUse(uint8_t* mask); + int16_t gnssSetAlmanacUpdate(uint8_t mask); + int16_t gnssReadAlmanacUpdate(uint8_t* mask); + int16_t gnssReadVersion(uint8_t* fw, uint8_t* almanac); + int16_t gnssReadSupportedConstellations(uint8_t* mask); + int16_t gnssSetMode(uint8_t mode); + int16_t gnssAutonomous(uint32_t gpsTime, uint8_t resMask, uint8_t nbSvMask); + int16_t gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, uint8_t nbSvMask); + int16_t gnssSetAssistancePosition(float lat, float lon); + int16_t gnssReadAssistancePosition(float* lat, float* lon); + int16_t gnssPushSolverMsg(uint8_t* payload, size_t len); + int16_t gnssPushDmMsg(uint8_t* payload, size_t len); + int16_t gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace); + int16_t gnssGetNbSvDetected(uint8_t* nbSv); + int16_t gnssGetSvDetected(uint8_t* svId, uint8_t* snr, uint16_t* doppler, size_t nbSv); + int16_t gnssGetConsumption(uint32_t* cpu, uint32_t* radio); + int16_t gnssGetResultSize(uint16_t* size); + int16_t gnssReadResults(uint8_t* result, uint16_t size); + int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc); + int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac); + int16_t gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); + + int16_t cryptoSetKey(uint8_t keyId, uint8_t* key); + int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key); + int16_t cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, uint8_t* header, uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, uint32_t* mic); + int16_t cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* data, size_t len, bool* result); + int16_t cryptoAesEncrypt01(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoAesEncrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoAesDecrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoStoreToFlash(void); + int16_t cryptoRestoreFromFlash(void); + int16_t cryptoSetParam(uint8_t id, uint32_t value); + int16_t cryptoGetParam(uint8_t id, uint32_t* value); + int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len); + int16_t cryptoCheckEncryptedFirmwareImageResult(bool* result); + + int16_t bootEraseFlash(void); + int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len); + int16_t bootReboot(bool stay); + int16_t bootGetPin(uint8_t* pin); + int16_t bootGetChipEui(uint8_t* eui); + int16_t bootGetJoinEui(uint8_t* eui); + + int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, uint8_t* out = NULL, size_t outLen = 0); + +#if !RADIOLIB_GODMODE + protected: +#endif + uint8_t chipType; + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + // cached LoRa parameters + uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; + uint16_t preambleLengthLoRa = 0; + float bandwidthKhz = 0; + bool ldroAuto = true; + size_t implicitLen = 0; + bool invertIQEnabled = false; + + // cached GFSK parameters + float bitRateKbps = 0; + uint8_t bitRate = 0; + uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; + uint16_t preambleLengthGFSK = 0; + + float dataRateMeasured = 0; + + static int16_t SPIparseStatus(uint8_t in); + static int16_t SPIcheckStatus(Module* mod); + bool findChip(uint8_t ver); + int16_t config(uint8_t modem); + + // common methods to avoid some copy-paste + int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); + int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, size_t len); + int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); +}; + +#endif + +#endif From 23f45153c105c56d7fc3bc550132f998f27f3cbc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 19:28:54 +0100 Subject: [PATCH 0996/1848] [LR11x0] Suppress warnings for unimplemented features --- src/modules/LR11x0/LR11x0.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index a2cfb53d62..9112c46045 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -108,8 +108,15 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); + + // TODO implement GFSK + (void)br; + (void)freqDev; + (void)rxBw; + (void)preambleLength; + (void)tcxoVoltage; - return(RADIOLIB_ERR_NONE); + return(RADIOLIB_ERR_UNSUPPORTED); } int16_t LR11x0::reset() { @@ -260,6 +267,7 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) { this->mod->setRfSwitchState(Module::MODE_IDLE); // TODO this will block BUSY forever + (void)wakeup; /*if(wakeup) { // pull NSS low to wake up this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); @@ -645,6 +653,14 @@ int16_t LR11x0::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED; return(setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled)); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // TODO add GFSK support + (void)initial; + (void)polynomial; + (void)inverted; + return(RADIOLIB_ERR_UNSUPPORTED); + } return(RADIOLIB_ERR_WRONG_MODEM); @@ -1223,6 +1239,7 @@ int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) { int16_t LR11x0::enableSpiCrc(bool en) { // TODO implement this + (void)en; // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected /*RadioLibCRCInstance.size = 8; RadioLibCRCInstance.poly = 0xA6; From f956a66ef28f93e648e519402102daac4a7b7085 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 19:29:12 +0100 Subject: [PATCH 0997/1848] [LR11x0] Fix typos in variable names --- src/modules/LR11x0/LR11x0.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 9112c46045..501594c5d7 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1835,7 +1835,7 @@ int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) { uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; - uint16_t lonRaw = (lat*2048.0f)/180.0f + 0.5f; + uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; uint8_t buff[4] = { (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), @@ -1973,7 +1973,7 @@ int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac) { int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; - uint16_t lonRaw = (lat*2048.0f)/180.0f + 0.5f; + uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; uint8_t reqBuff[9] = { (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), From 7bb747fdba54718d70ab2ca48f604a8d4a278d25 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 19:29:35 +0100 Subject: [PATCH 0998/1848] [LR11x0] Add missing header for non-Arduino paltforms (#679) --- src/modules/LR11x0/LR11x0.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 501594c5d7..b075b1f158 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -4,6 +4,7 @@ #include "../../utils/Cryptography.h" #include +#include #if !RADIOLIB_EXCLUDE_LR11X0 From 4a6e182789924dcb05bcffbc535ef84a3f1b7848 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 20:38:12 +0200 Subject: [PATCH 0999/1848] [LR11x0] Fix virtual method hiding (#679) --- src/modules/LR11x0/LR1110.cpp | 4 ++++ src/modules/LR11x0/LR1110.h | 10 ++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index a540ce5c52..4dbce1b2be 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -48,6 +48,10 @@ int16_t LR1110::setFrequency(float freq, bool calibrate, float band) { return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); } +int16_t LR1110::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { // determine whether to use HP or LP PA and check range accordingly bool useHp = forceHighPower || (power > 14); diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index 636724e6a8..e122f00e8d 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -73,16 +73,22 @@ class LR1110: public LR11x0 { \returns \ref status_codes */ int16_t setFrequency(float freq, bool calibrate, float band = 4); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). \param power Output power to be set in dBm. \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. - Defaults to false. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool forceHighPower = false); + int16_t setOutputPower(int8_t power, bool forceHighPower); #if !RADIOLIB_GODMODE private: From 88e1411399ed0ffea2e821d40bbe06845e8cb0b9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 19:42:14 +0100 Subject: [PATCH 1000/1848] [LR11x0] Fix potential use after free --- src/modules/LR11x0/LR11x0.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index b075b1f158..ef1043fe71 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -945,17 +945,17 @@ int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { #endif int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - RADIOLIB_ASSERT(state); // convert endians - if(data) { + if(data && (state == RADIOLIB_ERR_NONE)) { for(size_t i = 0; i < len; i++) { data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; } } + + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif return(state); } @@ -1202,18 +1202,18 @@ int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) { #endif int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - RADIOLIB_ASSERT(state); // convert endians - if(data) { + if(data && (state == RADIOLIB_ERR_NONE)) { for(size_t i = 0; i < len; i++) { data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; } } + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); } From 4d1157e3a4225c9b572d2085819d53b115dd768e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Apr 2024 19:51:59 +0100 Subject: [PATCH 1001/1848] Add LR11x0 to readme and library tags --- README.md | 1 + idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d33794b37e..004623cf91 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github ### Supported modules: * __CC1101__ FSK radio module * __LLCC68__ LoRa module +* __LR11x0__ series LoRa/GFSK modules (LR1110, LR1120, LR1121) * __nRF24L01__ 2.4 GHz module * __RF69__ FSK/OOK radio module * __RFM2x__ series FSK modules (RFM22, RM23) diff --git a/idf_component.yml b/idf_component.yml index 572ca4d832..2a2ae157dd 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,6 +1,6 @@ version: "6.5.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." -tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan" +tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121" url: "https://github.com/jgromes/RadioLib" repository: "https://github.com/jgromes/RadioLib.git" license: "MIT" diff --git a/library.json b/library.json index 0758385243..3f91e3e963 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "6.5.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", - "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", "repository": { diff --git a/library.properties b/library.properties index 0b435dfc1f..d7abb49501 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=6.5.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library -paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). +paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). category=Communication url=https://github.com/jgromes/RadioLib architectures=* From 6fa4aa3ebbbb332a0f3d3b44b043f5f8f57a3cc5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 19 Apr 2024 20:30:53 +0200 Subject: [PATCH 1002/1848] [LR11x0] Added GFSK modem support (#679) --- .../LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino | 153 ++++++ src/modules/LR11x0/LR11x0.cpp | 449 +++++++++++++++++- src/modules/LR11x0/LR11x0.h | 131 ++++- 3 files changed, 698 insertions(+), 35 deletions(-) create mode 100644 examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino diff --git a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino new file mode 100644 index 0000000000..66e4090d72 --- /dev/null +++ b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino @@ -0,0 +1,153 @@ +/* + RadioLib LR11x0 GFSK Modem Example + + This example shows how to use GFSK modem in LR11x0 chips. + + NOTE: The sketch below is just a guide on how to use + GFSK modem, so this code should not be run directly! + Instead, modify the other examples to use GFSK + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.beginGFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable GFSK) + // radio.beginGFSK() start GFSK modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setBitRate(100.0); + state = radio.setFrequencyDeviation(10.0); + state = radio.setRxBandwidth(250.0); + state = radio.setOutputPower(10.0); + state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.setSyncWord(syncWord, 8); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + // GFSK modem on LR11x0 can handle the sync word setting in bits, not just + // whole bytes. The value used is left-justified. + // This makes same result as radio.setSyncWord(syncWord, 8): + state = radio.setSyncBits(syncWord, 64); + // This will use 0x012 as sync word (12 bits only): + state = radio.setSyncBits(syncWord, 12); + + // GFSK modem allows advanced CRC configuration + // Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted) + // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted) + state = radio.setCRC(2, 0xFFFF, 0x8005, false); + // set CRC length to 0 to disable CRC + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // GFSK modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit GFSK packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR1110] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[LR1110] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[LR1110] Timed out while transmitting!")); + } else { + Serial.println(F("[LR1110] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive GFSK packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR1110] Received packet!")); + Serial.print(F("[LR1110] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[LR1110] Timed out while waiting for packet!")); + } else { + Serial.print(F("[LR1110] Failed to receive packet, code ")); + Serial.println(state); + } + + // GFSK modem has built-in address filtering system + // it can be enabled by setting node address, broadcast + // address, or both + // + // to transmit packet to a particular address, + // use the following methods: + // + // radio.transmit("Hello World!", address); + // radio.startTransmit("Hello World!", address); + + // set node address to 0x02 + state = radio.setNodeAddress(0x02); + // set broadcast address to 0xFF + state = radio.setBroadcastAddress(0xFF); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[LR1110] Unable to set address filter, code ")); + Serial.println(state); + } + + // address filtering can also be disabled + // NOTE: calling this method will also erase previously set + // node and broadcast address + /* + state = radio.disableAddressFiltering(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to remove address filter, code ")); + } + */ +} diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index ef1043fe71..5c05e4c057 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -109,15 +109,48 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); - - // TODO implement GFSK - (void)br; - (void)freqDev; - (void)rxBw; - (void)preambleLength; - (void)tcxoVoltage; - return(RADIOLIB_ERR_UNSUPPORTED); + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(RADIOLIB_LR11X0_PACKET_TYPE_GFSK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x12, 0xAD }; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(RADIOLIB_LR11X0_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + state = setCRC(2); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); } int16_t LR11x0::reset() { @@ -267,12 +300,12 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); - // TODO this will block BUSY forever - (void)wakeup; - /*if(wakeup) { - // pull NSS low to wake up + if(wakeup) { + // pull NSS low for a while to wake up this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - }*/ + this->mod->hal->delay(1); + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + } uint8_t buff[] = { mode }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1)); @@ -577,6 +610,327 @@ int16_t LR11x0::setSyncWord(uint8_t syncWord) { return(setLoRaSyncWord(syncWord)); } +int16_t LR11x0::setBitRate(float br) { + RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set bit rate value + // TODO implement fractional bit rate configuration + this->bitRate = br * 1000.0; + return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t LR11x0::setFrequencyDeviation(float freqDev) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0) { + newFreqDev = 0.6; + } + + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + this->frequencyDev = freqDev * 1000.0; + return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t LR11x0::setRxBandwidth(float rxBw) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation parameters + /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) { + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); + }*/ + + // check allowed receiver bandwidth values + if(fabs(rxBw - 4.8) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8; + } else if(fabs(rxBw - 5.8) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8; + } else if(fabs(rxBw - 7.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3; + } else if(fabs(rxBw - 9.7) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7; + } else if(fabs(rxBw - 11.7) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7; + } else if(fabs(rxBw - 14.6) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6; + } else if(fabs(rxBw - 19.5) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5; + } else if(fabs(rxBw - 23.4) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4; + } else if(fabs(rxBw - 29.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3; + } else if(fabs(rxBw - 39.0) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0; + } else if(fabs(rxBw - 46.9) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9; + } else if(fabs(rxBw - 58.6) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6; + } else if(fabs(rxBw - 78.2) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2; + } else if(fabs(rxBw - 93.8) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8; + } else if(fabs(rxBw - 117.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3; + } else if(fabs(rxBw - 156.2) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2; + } else if(fabs(rxBw - 187.2) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2; + } else if(fabs(rxBw - 234.3) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3; + } else if(fabs(rxBw - 312.0) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0; + } else if(fabs(rxBw - 373.6) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6; + } else if(fabs(rxBw - 467.0) <= 0.001) { + this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0; + } else { + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + } + + // update modulation parameters + return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) { + if((!syncWord) || (!len) || (len > RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update sync word length + this->syncWordLength = len*8; + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // sync word is passed most-significant byte first + uint8_t fullSyncWord[RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN] = { 0 }; + memcpy(fullSyncWord, syncWord, len); + return(setGfskSyncWord(fullSyncWord)); +} + +int16_t LR11x0::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { + if((!syncWord) || (!bitsLen) || (bitsLen > 8*RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + uint8_t bytesLen = bitsLen / 8; + if ((bitsLen % 8) != 0) { + bytesLen++; + } + + return(setSyncWord(syncWord, bytesLen)); +} + +int16_t LR11x0::setNodeAddress(uint8_t nodeAddr) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node only) + this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE; + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // set node address + this->node = nodeAddr; + return(setPacketAdrs(this->node, 0)); +} + +int16_t LR11x0::setBroadcastAddress(uint8_t broadAddr) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node and broadcast) + this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST; + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // set node and broadcast address + return(setPacketAdrs(this->node, broadAddr)); +} + +int16_t LR11x0::disableAddressFiltering() { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // disable address filterin + this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED; + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); +} + +int16_t LR11x0::setDataShaping(uint8_t sh) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_NONE; + break; + case RADIOLIB_SHAPING_0_3: + this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3; + break; + case RADIOLIB_SHAPING_0_5: + this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5; + break; + case RADIOLIB_SHAPING_0_7: + this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7; + break; + case RADIOLIB_SHAPING_1_0: + this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0; + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + // update modulation parameters + return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t LR11x0::setEncoding(uint8_t encoding) { + return(setWhitening(encoding)); +} + +int16_t LR11x0::fixedPacketLengthMode(uint8_t len) { + return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED, len)); +} + +int16_t LR11x0::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE, maxLen)); +} + +int16_t LR11x0::setWhitening(bool enabled, uint16_t initial) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(!enabled) { + // disable whitening + this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED; + + } else { + // enable whitening + this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED; + + // write initial whitening value + state = setGfskWhitParams(initial); + RADIOLIB_ASSERT(state); + } + + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); +} + +int16_t LR11x0::setDataRate(DataRate_t dr) { + // select interpretation based on active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + + if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + } + + return(state); +} + +int16_t LR11x0::checkDataRate(DataRate_t dr) { + // select interpretation based on active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + + if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(RADIOLIB_ERR_UNKNOWN); +} + int16_t LR11x0::setPreambleLength(size_t preambleLength) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -585,6 +939,10 @@ int16_t LR11x0::setPreambleLength(size_t preambleLength) { if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { this->preambleLengthLoRa = preambleLength; return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + this->preambleLengthGFSK = preambleLength; + this->preambleDetLength = RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS; + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } return(RADIOLIB_ERR_WRONG_MODEM); @@ -645,7 +1003,7 @@ int16_t LR11x0::setTCXO(float voltage, uint32_t delay) { return(setTcxoMode(tune, delayValue)); } -int16_t LR11x0::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { +int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); @@ -653,18 +1011,40 @@ int16_t LR11x0::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED; - return(setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled)); + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - // TODO add GFSK support - (void)initial; - (void)polynomial; - (void)inverted; - return(RADIOLIB_ERR_UNSUPPORTED); + // update packet parameters + switch(len) { + case 0: + this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_DISABLED; + break; + case 1: + if(inverted) { + this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV; + } else { + this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE; + } + break; + case 2: + if(inverted) { + this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV; + } else { + this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE; + } + break; + default: + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + state = setGfskCrcParams(initial, polynomial); } - return(RADIOLIB_ERR_WRONG_MODEM); + return(state); } int16_t LR11x0::invertIQ(bool enable) { @@ -793,7 +1173,7 @@ uint32_t LR11x0::getTimeOnAir(size_t len) { return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - return(((uint32_t)len * 8 * 1000) / this->bitRateKbps); + return(((uint32_t)len * 8 * 1000000UL) / this->bitRate); } @@ -911,6 +1291,24 @@ int16_t LR11x0::config(uint8_t modem) { return(state); } +int16_t LR11x0::setPacketMode(uint8_t mode, uint8_t len) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetType = mode; + return(state); +} + Module* LR11x0::getMod() { return(this->mod); } @@ -1311,9 +1709,8 @@ int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rx int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); // pass the replies - // TODO do the value conversion for RSSI (fixed point?) - if(rssiSync) { *rssiSync = (float)buff[0]; } - if(rssiAvg) { *rssiAvg = (float)buff[1]; } + if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; } + if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; } if(rxLen) { *rxLen = buff[2]; } if(stat) { *stat = buff[3]; } @@ -1334,7 +1731,7 @@ int16_t LR11x0::setGfskSyncWord(uint8_t* sync) { if(!sync) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, false, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)); } int16_t LR11x0::setLoRaPublicNetwork(bool pub) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 88c4eee7d0..5bc3dc3df9 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -752,8 +752,121 @@ class LR11x0: public PhysicalLayer { int16_t setSyncWord(uint8_t syncWord); /*! - \brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535. - \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK). + \brief Sets GFSK bit rate. Allowed values range from 0.6 to 300.0 kbps. + \param br FSK bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets GFSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. + \param freqDev GFSK frequency deviation to be set in kHz. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Sets GFSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, + 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. + \param rxBw GFSK receiver bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets GFSK sync word in the form of array of up to 8 bytes. + \param syncWord GFSK sync word to be set. + \param len GFSK sync word length in bytes. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; + + /*! + \brief Sets GFSK sync word in the form of array of up to 8 bytes. + \param syncWord GFSK sync word to be set. + \param bitsLen GFSK sync word length in bits. If length is not divisible by 8, + least significant bits of syncWord will be ignored. + \returns \ref status_codes + */ + int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen); + + /*! + \brief Sets node address. Calling this method will also enable address filtering for node address only. + \param nodeAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setNodeAddress(uint8_t nodeAddr); + + /*! + \brief Sets broadcast address. Calling this method will also enable address + filtering for node and broadcast address. + \param broadAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setBroadcastAddress(uint8_t broadAddr); + + /*! + \brief Disables address filtering. Calling this method will also erase previously set addresses. + \returns \ref status_codes + */ + int16_t disableAddressFiltering(); + + /*! + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. + Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Time-bandwidth product of Gaussian filter to be set. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets transmission encoding. Available in GFSK mode only. Serves only as alias for PhysicalLayer compatibility. + \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Set modem in fixed packet length mode. Available in GFSK mode only. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_LR11X0_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. Available in GFSK mode only. + \param maxLen Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH); + + /*! + \brief Sets GFSK whitening parameters. + \param enabled True = Whitening enabled + \param initial Initial value used for the whitening LFSR in GFSK mode. + By default set to 0x01FF for compatibility with SX127x and LoRaWAN. + \returns \ref status_codes + */ + int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF); + + /*! + \brief Set data. + \param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa). + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Sets preamble length for LoRa or GFSK modem. Allowed values range from 1 to 65535. + \param preambleLength Preamble length to be set in symbols (LoRa) or bits (GFSK). \returns \ref status_codes */ int16_t setPreambleLength(size_t preambleLength) override; @@ -771,12 +884,12 @@ class LR11x0: public PhysicalLayer { /*! \brief Sets CRC configuration. \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. - \param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC). - \param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC). - \param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC). + \param initial Initial CRC value. GFSK only. Defaults to 0x1D0F (CCIT CRC). + \param polynomial Polynomial for CRC calculation. GFSK only. Defaults to 0x1021 (CCIT CRC). + \param inverted Invert CRC bytes. GFSK only. Defaults to true (CCIT CRC). \returns \ref status_codes */ - int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true); + int16_t setCRC(uint8_t len, uint32_t initial = 0x00001D0FUL, uint32_t polynomial = 0x00001021UL, bool inverted = true); /*! \brief Enable/disable inversion of the I and Q signals @@ -995,9 +1108,8 @@ class LR11x0: public PhysicalLayer { bool invertIQEnabled = false; // cached GFSK parameters - float bitRateKbps = 0; - uint8_t bitRate = 0; - uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; + uint32_t bitRate = 0, frequencyDev = 0; + uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0; uint16_t preambleLengthGFSK = 0; float dataRateMeasured = 0; @@ -1006,6 +1118,7 @@ class LR11x0: public PhysicalLayer { static int16_t SPIcheckStatus(Module* mod); bool findChip(uint8_t ver); int16_t config(uint8_t modem); + int16_t setPacketMode(uint8_t mode, uint8_t len); // common methods to avoid some copy-paste int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); From 99d2e6c4520ac9768bf4ed9473862ab5399d3a04 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Apr 2024 18:05:31 +0200 Subject: [PATCH 1003/1848] [LR11x0] Added direct mode support --- .../APRS_Position_LoRa/APRS_Position_LoRa.ino | 1 + examples/AX25/AX25_Frames/AX25_Frames.ino | 1 + examples/AX25/AX25_Transmit/AX25_Transmit.ino | 1 + .../Morse_Transmit_SSB/Morse_Transmit_SSB.ino | 1 + src/modules/LR11x0/LR11x0.cpp | 25 ++++++++++++++++++- src/modules/LR11x0/LR11x0.h | 16 +++++++++++- 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino index 6b3053a1d1..31a2f82652 100644 --- a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino +++ b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino @@ -8,6 +8,7 @@ - SX127x/RFM9x - SX126x/LLCC68 - SX128x + - LR11x0 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index 809d7176c3..8a55be748f 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -12,6 +12,7 @@ - SX126x - nRF24 - Si443x/RFM2x + - LR11x0 Using raw AX.25 frames requires some knowledge of the protocol, refer to diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index 98236d108c..bbefc67c3a 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -12,6 +12,7 @@ - SX126x - nRF24 - Si443x/RFM2x + - LR11x0 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino index 61abde3a51..4b35e77465 100644 --- a/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino +++ b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino @@ -14,6 +14,7 @@ - nRF24 - Si443x/RFM2x - SX128x + - LR11x0 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 5c05e4c057..6272f2d663 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -292,6 +292,29 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { return(readData(data, len)); } +int16_t LR11x0::transmitDirect(uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + int16_t state = RADIOLIB_ERR_NONE; + if(frf != 0) { + state = setRfFrequency(frf); + } + RADIOLIB_ASSERT(state); + + // start transmitting + return(setTxCw()); +} + +int16_t LR11x0::receiveDirect() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // LR11x0 is unable to output received data directly + return(RADIOLIB_ERR_UNKNOWN); +} + int16_t LR11x0::standby() { return(LR11x0::standby(RADIOLIB_LR11X0_STANDBY_RC)); } @@ -643,7 +666,7 @@ int16_t LR11x0::setFrequencyDeviation(float freqDev) { } RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); - this->frequencyDev = freqDev * 1000.0; + this->frequencyDev = newFreqDev * 1000.0; return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 5bc3dc3df9..d9340782bd 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -10,7 +10,7 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" // LR11X0 physical layer properties -#define RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE 0.9536743164 +#define RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE 1.0 #define RADIOLIB_LR11X0_MAX_PACKET_LENGTH 255 #define RADIOLIB_LR11X0_CRYSTAL_FREQ 32.0 #define RADIOLIB_LR11X0_DIV_EXPONENT 25 @@ -606,6 +606,20 @@ class LR11x0: public PhysicalLayer { */ int16_t receive(uint8_t* data, size_t len) override; + /*! + \brief Starts direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX126x series does not support direct mode reception. + Will always return RADIOLIB_ERR_UNKNOWN. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). \returns \ref status_codes From 3c502b9cdfa5f40f0c0554deda798ad9dc9ac957 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Apr 2024 18:05:57 +0200 Subject: [PATCH 1004/1848] [AX25] Fix direct mode start --- src/protocols/AX25/AX25.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 7fe3f4969b..b8605d3279 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -194,12 +194,7 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preL preambleLen = preLen; // configure for direct mode - #if !RADIOLIB_EXCLUDE_AFSK - if(bellModem != nullptr) { - return(phyLayer->startDirect()); - } - #endif - return(RADIOLIB_ERR_NONE); + return(phyLayer->startDirect()); } #if defined(RADIOLIB_BUILD_ARDUINO) From b283c1b1170538ad00234d60c49ccb8aa44521bb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Apr 2024 18:07:27 +0200 Subject: [PATCH 1005/1848] Added LR11x0 to supported protocols --- README.md | 10 +++++----- .../Hellschreiber_Transmit/Hellschreiber_Transmit.ino | 1 + examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 004623cf91..cc9f908895 100644 --- a/README.md +++ b/README.md @@ -30,21 +30,21 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github ### Supported protocols and digital modes: * [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0 and SX128x * [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x * [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x * [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x * [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules: -SX127x, RFM9x, SX126x and SX128x +SX127x, RFM9x, SX126x, LR11x0 and SX128x * NOTE: LoRaWAN support is currently in beta, feedback via [Issues](https://github.com/jgromes/RadioLib/issues) and [Discussions](https://github.com/jgromes/RadioLib/discussions) is appreciated! ### Supported Arduino platforms: diff --git a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino index 8374da597d..258962b60c 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -13,6 +13,7 @@ - nRF24 - Si443x/RFM2x - SX128x + - LR11x0 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index e02ad3ca97..5d3b1387a7 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -13,6 +13,7 @@ - nRF24 - Si443x/RFM2x - SX128x + - LR11x0 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration From 01208574d94f5d54e34979a66472b7e342bae7ca Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Apr 2024 21:29:32 +0200 Subject: [PATCH 1006/1848] [LR11x0] Added CAD support (#679) --- ...x0_Channel_Activity_Detection_Blocking.ino | 75 ++++++++++++ ...0_Channel_Activity_Detection_Interrupt.ino | 110 +++++++++++++++++ src/modules/LR11x0/LR11x0.cpp | 112 +++++++++++++++++- src/modules/LR11x0/LR11x0.h | 40 +++++++ 4 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino create mode 100644 examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino new file mode 100644 index 0000000000..096c160e67 --- /dev/null +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -0,0 +1,75 @@ +/* + RadioLib LR11x0 Blocking Channel Activity Detection Example + + This example uses LR1110 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, LR11x0 can detect any part + of LoRa transmission, not just the preamble. + + Other modules from LR11x0 family can also be used. + + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[LR1110] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 0000000000..41b9c89a2c --- /dev/null +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,110 @@ +/* + RadioLib LR11x0 Channel Activity Detection Example + + This example uses LR1110 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, LR11x0 can detect any part + of LoRa transmission, not just the preamble. + + Other modules from LR11x0 family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[LR1110] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[LR1110] Packet detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[LR1110] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[LR1110] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[LR1110] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6272f2d663..ffae2c469a 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -315,6 +315,24 @@ int16_t LR11x0::receiveDirect() { return(RADIOLIB_ERR_UNKNOWN); } +int16_t LR11x0::scanChannel() { + return(this->scanChannel(RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT)); +} + +int16_t LR11x0::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // set mode to CAD + int state = startChannelScan(symbolNum, detPeak, detMin); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + } + + // check CAD result + return(getChannelScanResult()); +} + int16_t LR11x0::standby() { return(LR11x0::standby(RADIOLIB_LR11X0_STANDBY_RC)); } @@ -539,6 +557,62 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { return(state); } +int16_t LR11x0::startChannelScan() { + return(this->startChannelScan(RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT)); +} + +int16_t LR11x0::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set DIO pin mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE, RADIOLIB_LR11X0_IRQ_NONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // set mode to CAD + return(startCad(symbolNum, detPeak, detMin)); +} + +int16_t LR11x0::getChannelScanResult() { + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check CAD result + uint32_t cadResult = getIrqStatus(); + if(cadResult & RADIOLIB_LR11X0_IRQ_CAD_DETECTED) { + // detected some LoRa activity + return(RADIOLIB_LORA_DETECTED); + } else if(cadResult & RADIOLIB_LR11X0_IRQ_CAD_DONE) { + // channel is free + return(RADIOLIB_CHANNEL_FREE); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + int16_t LR11x0::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -1282,8 +1356,6 @@ int16_t LR11x0::config(uint8_t modem) { state = this->setRxTxFallbackMode(RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC); RADIOLIB_ASSERT(state); - // TODO set some CAD parameters - will be overwritten when calling CAD anyway - // clear IRQ state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE, RADIOLIB_LR11X0_IRQ_NONE); @@ -1332,6 +1404,42 @@ int16_t LR11x0::setPacketMode(uint8_t mode, uint8_t len) { return(state); } +int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // select CAD parameters + // TODO the magic numbers are based on Semtech examples, this is probably suboptimal + uint8_t num = symbolNum; + if(num == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) { + num = 2; + } + + uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 }; + uint8_t peak = detPeak; + if(peak == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) { + peak = detPeakValues[this->spreadingFactor - 5]; + } + + uint8_t min = detMin; + if(min == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) { + min = 10; + } + + // set CAD parameters + // TODO add configurable exit mode and timeout + state = setCadParams(num, peak, min, RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC, 0); + RADIOLIB_ASSERT(state); + + // start CAD + return(setCad()); +} + Module* LR11x0::getMod() { return(this->mod); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index d9340782bd..6955fa79d9 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -312,6 +312,7 @@ #define RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC (0x00UL << 0) // 7 0 mode to set after CAD: standby with RC #define RADIOLIB_LR11X0_CAD_EXIT_MODE_RX (0x01UL << 0) // 7 0 receive if activity detected #define RADIOLIB_LR11X0_CAD_EXIT_MODE_LBT (0x10UL << 0) // 7 0 transmit if no activity detected +#define RADIOLIB_LR11X0_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value // RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE #define RADIOLIB_LR11X0_PACKET_TYPE_NONE (0x00UL << 0) // 2 0 packet type: none @@ -620,6 +621,21 @@ class LR11x0: public PhysicalLayer { */ int16_t receiveDirect() override; + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \returns \ref status_codes + */ + int16_t scanChannel() override; + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \param symbolNum Number of symbols for CAD detection. + \param detPeak Peak value for CAD detection. + \param detMin Minimum value for CAD detection. + \returns \ref status_codes + */ + int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). \returns \ref status_codes @@ -731,6 +747,29 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. + \returns \ref status_codes + */ + int16_t startChannelScan() override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. + \param symbolNum Number of symbols for CAD detection. + \param detPeak Peak value for CAD detection. + \param detMin Minimum value for CAD detection. + \returns \ref status_codes + */ + int16_t startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + + /*! + \brief Read the channel scan result + \returns \ref status_codes + */ + int16_t getChannelScanResult() override; // configuration methods @@ -1133,6 +1172,7 @@ class LR11x0: public PhysicalLayer { bool findChip(uint8_t ver); int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); + int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); // common methods to avoid some copy-paste int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); From 9451f3633259b48ec455d3f9b8a1dcac7dc749ee Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Apr 2024 08:34:00 +0200 Subject: [PATCH 1007/1848] [LR11x0] Use IRQ instead of DIO1 as pin name --- ...1x0_Channel_Activity_Detection_Blocking.ino | 2 +- ...x0_Channel_Activity_Detection_Interrupt.ino | 4 ++-- .../LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino | 2 +- .../LR11x0_Receive_Blocking.ino | 2 +- .../LR11x0_Receive_Interrupt.ino | 2 +- .../LR11x0_Transmit_Blocking.ino | 2 +- .../LR11x0_Transmit_Interrupt.ino | 2 +- src/modules/LR11x0/LR11x0.cpp | 12 ++++++------ src/modules/LR11x0/LR11x0.h | 18 +++++++++--------- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino index 096c160e67..171c87de3f 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -25,7 +25,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index 41b9c89a2c..90f0c8aa4f 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -20,7 +20,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); @@ -45,7 +45,7 @@ void setup() { // set the function that will be called // when LoRa packet or timeout is detected - radio.setDio1Action(setFlag); + radio.setIrqAction(setFlag); // start scanning the channel Serial.print(F("[LR1110] Starting scan for LoRa preamble ... ")); diff --git a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino index 66e4090d72..45dc0507ba 100644 --- a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino +++ b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino @@ -21,7 +21,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino index e29806bd2d..8d0efc9a54 100644 --- a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -30,7 +30,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index 0539104a62..f20f2aafb2 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -26,7 +26,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index 93dab374b4..741102ac24 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -21,7 +21,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 6de582c6a2..e47c68f728 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -22,7 +22,7 @@ // LR1110 has the following connections: // NSS pin: 10 -// DIO1 pin: 2 +// IRQ pin: 2 // NRST pin: 3 // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index ffae2c469a..fb7fdba7d3 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -373,28 +373,28 @@ int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) { return(state); } -void LR11x0::setDio1Action(void (*func)(void)) { +void LR11x0::setIrqAction(void (*func)(void)) { this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); } -void LR11x0::clearDio1Action() { +void LR11x0::clearIrqAction() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); } void LR11x0::setPacketReceivedAction(void (*func)(void)) { - this->setDio1Action(func); + this->setIrqAction(func); } void LR11x0::clearPacketReceivedAction() { - this->clearDio1Action(); + this->clearIrqAction(); } void LR11x0::setPacketSentAction(void (*func)(void)) { - this->setDio1Action(func); + this->setIrqAction(func); } void LR11x0::clearPacketSentAction() { - this->clearDio1Action(); + this->clearIrqAction(); } int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 6955fa79d9..5b04023327 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -663,15 +663,15 @@ class LR11x0: public PhysicalLayer { // interrupt methods /*! - \brief Sets interrupt service routine to call when DIO1 activates. + \brief Sets interrupt service routine to call when IRQ1 activates. \param func ISR to call. */ - void setDio1Action(void (*func)(void)); + void setIrqAction(void (*func)(void)); /*! - \brief Clears interrupt service routine to call when DIO1 activates. + \brief Clears interrupt service routine to call when IRQ1 activates. */ - void clearDio1Action(); + void clearIrqAction(); /*! \brief Sets interrupt service routine to call when a packet is received. @@ -720,13 +720,13 @@ class LR11x0: public PhysicalLayer { int16_t startReceive(); /*! - \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + \brief Interrupt-driven receive method. IRQ1 will be activated when full packet is received. \param timeout Raw timeout value, expressed as multiples of 1/32.768 kHz (approximately 30.52 us). Defaults to RADIOLIB_LR11X0_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to RADIOLIB_LR11X0_RX_TIMEOUT_NONE for no timeout (Rx single mode). - If timeout other than infinite is set, signal will be generated on DIO1. + If timeout other than infinite is set, signal will be generated on IRQ1. - \param irqFlags Sets the IRQ flags that will trigger DIO1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE. + \param irqFlags Sets the IRQ flags that will trigger IRQ1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE. \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ @@ -749,14 +749,14 @@ class LR11x0: public PhysicalLayer { int16_t readData(uint8_t* data, size_t len) override; /*! - \brief Interrupt-driven channel activity detection method. DIO1 will be activated + \brief Interrupt-driven channel activity detection method. IRQ1 will be activated when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. \returns \ref status_codes */ int16_t startChannelScan() override; /*! - \brief Interrupt-driven channel activity detection method. DIO1 will be activated + \brief Interrupt-driven channel activity detection method. IRQ1 will be activated when LoRa preamble is detected, or upon timeout. \param symbolNum Number of symbols for CAD detection. \param detPeak Peak value for CAD detection. From ce4d9aa15010216d7448f19d7d94c128225ea12c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Apr 2024 08:47:27 +0200 Subject: [PATCH 1008/1848] [LR11x0] Fixed LoRa CRC configuration --- src/modules/LR11x0/LR11x0.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index fb7fdba7d3..ba4f02d762 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -71,8 +71,7 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 RADIOLIB_ASSERT(state); // set publicly accessible settings that are not a part of begin method - // TODO looks like CRC does not work for SX127x - state = setCRC(0); + state = setCRC(2); RADIOLIB_ASSERT(state); state = invertIQ(false); @@ -1108,7 +1107,7 @@ int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED; - state = setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled); + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { // update packet parameters @@ -1154,7 +1153,7 @@ int16_t LR11x0::invertIQ(bool enable) { } this->invertIQEnabled = enable; - return(setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled)); + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); } float LR11x0::getRSSI() { From e8a6297c60ba64a64a2402900b3f41b8de154cfd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Apr 2024 15:01:57 +0200 Subject: [PATCH 1009/1848] [LR11x0] Added support for LR-FHSS --- .../LR11x0_LR_FHSS_Modem.ino | 110 +++++++++ keywords.txt | 4 + src/modules/LR11x0/LR1110.cpp | 13 ++ src/modules/LR11x0/LR1110.h | 13 ++ src/modules/LR11x0/LR11x0.cpp | 217 +++++++++++------- src/modules/LR11x0/LR11x0.h | 33 ++- 6 files changed, 298 insertions(+), 92 deletions(-) create mode 100644 examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino new file mode 100644 index 0000000000..a46d8a821e --- /dev/null +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -0,0 +1,110 @@ +/* + RadioLib LR11x0 LR-FHSS Modem Example + + This example shows how to use LR-FHSS modem in LR11x0 chips. + + NOTE: The sketch below is just a guide on how to use + LR-FHSS modem, so this code should not be run directly! + Instead, modify the other examples to use LR-FHSS + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lr-fhss-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.beginLRFHSS(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable LR-FHSS) + // radio.beginLRFHSS() start LR-FHSS modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setLrFhssConfig(RADIOLIB_LR11X0_LR_FHSS_BW_1523_4, // bandwidth + RADIOLIB_LR11X0_LR_FHSS_CR_1_2, // coding rate + 3, // header count + 0x13A); // hopping sequence seed + state = radio.setOutputPower(10.0); + state = radio.setSyncWord(0x12345678); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // LR-FHSS modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit LR-FHSS packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR1110] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[LR1110] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[LR1110] Timed out while transmitting!")); + } else { + Serial.println(F("[LR1110] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive LR-FHSS packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR1110] Received packet!")); + Serial.print(F("[LR1110] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[LR1110] Timed out while waiting for packet!")); + } else { + Serial.print(F("[LR1110] Failed to receive packet, code ")); + Serial.println(state); + } + +} diff --git a/keywords.txt b/keywords.txt index 0ace7c6c92..d160e7820c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -239,6 +239,10 @@ disablePipe KEYWORD2 getStatus KEYWORD2 setAutoAck KEYWORD2 +# LR11x0 +beginLRFHSS KEYWORD2 +setLrFhssConfig KEYWORD2 + # RTTY idle KEYWORD2 byteArr KEYWORD2 diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 4dbce1b2be..729300af14 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -31,6 +31,19 @@ int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_ return(state); } +int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { + // execute common part + int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + return(state); +} + int16_t LR1110::setFrequency(float freq) { return(this->setFrequency(freq, true)); } diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index e122f00e8d..ffcd2e9d33 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -52,6 +52,19 @@ class LR1110: public LR11x0 { \returns \ref status_codes */ int16_t beginGFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6); + + /*! + \brief Initialization method for LR-FHSS modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, int8_t power = 10, float tcxoVoltage = 1.6); // configuration methods diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index ba4f02d762..26d54aef30 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -14,44 +14,8 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, } int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - this->mod->spiConfig.statusPos = 0; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - this->mod->spiConfig.checkStatusCb = SPIcheckStatus; - - // try to find the LR11x0 chip - this will also reset the module at least once - if(!LR11x0::findChip(this->chipType)) { - RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!"); - this->mod->term(); - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0"); - - // set mode to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0) { - state = setTCXO(tcxoVoltage); - RADIOLIB_ASSERT(state); - } - - // configure settings not accessible by API - state = config(RADIOLIB_LR11X0_PACKET_TYPE_LORA); + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -81,42 +45,8 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 } int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - this->mod->spiConfig.statusPos = 0; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - this->mod->spiConfig.checkStatusCb = SPIcheckStatus; - - // try to find the LR11x0 chip - this will also reset the module at least once - if(!LR11x0::findChip(this->chipType)) { - RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!"); - this->mod->term(); - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0"); - - // set mode to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0) { - state = setTCXO(tcxoVoltage); - RADIOLIB_ASSERT(state); - } - - // configure settings not accessible by API - state = config(RADIOLIB_LR11X0_PACKET_TYPE_GFSK); + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -152,6 +82,22 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble return(RADIOLIB_ERR_NONE); } +int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage) { + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setLrFhssConfig(bw, cr); + RADIOLIB_ASSERT(state); + + state = setSyncWord(0x12AD101B); + RADIOLIB_ASSERT(state); + + // set fixed configuration + return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0)); +} + int16_t LR11x0::reset() { // run the reset sequence this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); @@ -185,18 +131,17 @@ int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } - uint32_t timeout = 0; - // get currently active modem uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); + uint32_t timeout = getTimeOnAir(len); if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate timeout (150% of expected time-on-air) - timeout = (getTimeOnAir(len) * 3) / 2; + timeout = (timeout * 3) / 2; - } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + } else if((modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) { // calculate timeout (500% of expected time-on-air) - timeout = getTimeOnAir(len) * 5; + timeout = timeout * 5; } else { return(RADIOLIB_ERR_UNKNOWN); @@ -248,6 +193,13 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { } float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); + + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + size_t maxLen = len; + if(len == 0) { + maxLen = 0xFF; + } + timeout = (uint32_t)(((maxLen * 8.0) / (RADIOLIB_LR11X0_LR_FHSS_BIT_RATE)) * 1000.0 * 5.0); } else { return(RADIOLIB_ERR_UNKNOWN); @@ -417,10 +369,13 @@ int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcTypeLoRa, this->invertIQEnabled); + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); - } else { + + } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { return(RADIOLIB_ERR_UNKNOWN); + } RADIOLIB_ASSERT(state); @@ -428,9 +383,17 @@ int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT, 0); RADIOLIB_ASSERT(state); - // write packet to buffer - state = writeBuffer8(data, len); - RADIOLIB_ASSERT(state); + if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + // in LR-FHSS mode, the packet is built by the device + // TODO add configurable grid step and device offset + state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC, true, this->lrFhssBw, this->lrFhssHopSeq, 0, data, len); + + } else { + // write packet to buffer + state = writeBuffer8(data, len); + RADIOLIB_ASSERT(state); + + } // clear interrupt flags state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); @@ -471,7 +434,9 @@ int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, size_t len) { uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); RADIOLIB_ASSERT(state); - if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { + if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && + (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) && + (modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -519,7 +484,9 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); RADIOLIB_ASSERT(state); - if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { + if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && + (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) && + (modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -659,7 +626,7 @@ int16_t LR11x0::setSpreadingFactor(uint8_t sf, bool legacy) { RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - // enable SF6 legacy mode + // TODO enable SF6 legacy mode if(legacy && (sf == 6)) { //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18); } @@ -702,8 +669,20 @@ int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) { return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } -int16_t LR11x0::setSyncWord(uint8_t syncWord) { - return(setLoRaSyncWord(syncWord)); +int16_t LR11x0::setSyncWord(uint32_t syncWord) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(setLoRaSyncWord(syncWord & 0xFF)); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + return(lrFhssSetSyncWord(syncWord)); + + } + + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t LR11x0::setBitRate(float br) { @@ -1271,6 +1250,9 @@ uint32_t LR11x0::getTimeOnAir(size_t len) { } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { return(((uint32_t)len * 8 * 1000000UL) / this->bitRate); + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + return(((uint32_t)len * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); + } return(0); @@ -1280,6 +1262,65 @@ float LR11x0::getDataRate() const { return(this->dataRateMeasured); } +int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check and cache all parameters + RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE); + this->lrFhssCr = cr; + RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH); + this->lrFhssBw = bw; + RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE); + this->lrFhssHdrCount = hdrCount; + RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING); + this->lrFhssHopSeq = hopSeed; + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.statusPos = 0; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + this->mod->spiConfig.checkStatusCb = SPIcheckStatus; + + // try to find the LR11x0 chip - this will also reset the module at least once + if(!LR11x0::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0"); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + return(config(modem)); +} + int16_t LR11x0::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) { return(RADIOLIB_ERR_SPI_CMD_INVALID); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 5b04023327..63d704149d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -366,7 +366,8 @@ #define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz #define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz #define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (0x8001E848UL) // 31 0 LR FHSS bit rate: 488.28215 bps +#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215) // 31 0 LR FHSS bit rate: 488.28215 bps +#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw #define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0 #define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7 @@ -582,6 +583,15 @@ class LR11x0: public PhysicalLayer { */ int16_t beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage); + /*! + \brief Initialization method for LR-FHSS modem. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. + \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. + \param tcxoVoltage TCXO reference voltage to be set. + \returns \ref status_codes + */ + int16_t beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage); + /*! \brief Reset method. Will reset the chip to the default state using RST pin. \returns \ref status_codes @@ -798,11 +808,11 @@ class LR11x0: public PhysicalLayer { int16_t setCodingRate(uint8_t cr, bool longInterleave = false); /*! - \brief Sets LoRa sync word. - \param syncWord LoRa sync word to be set. + \brief Sets LoRa or LR-FHSS sync word. + \param syncWord LoRa or LR-FHSS sync word to be set. For LoRa, only 8 least significant bits will be used \returns \ref status_codes */ - int16_t setSyncWord(uint8_t syncWord); + int16_t setSyncWord(uint32_t syncWord); /*! \brief Sets GFSK bit rate. Allowed values range from 0.6 to 300.0 kbps. @@ -996,6 +1006,16 @@ class LR11x0: public PhysicalLayer { */ float getDataRate() const; + /*! + \brief Sets LR-FHSS configuration. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. + \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. + \param hdrCount Header packet count, 1 - 4. Defaults to 3. + \param hopSeed 9-bit seed number for PRNG generation of the hopping sequence. Defaults to 0x13A. + \returns \ref status_codes + */ + int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeed = 0x13A); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -1165,8 +1185,13 @@ class LR11x0: public PhysicalLayer { uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0; uint16_t preambleLengthGFSK = 0; + // cached LR-FHSS parameters + uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0; + uint16_t lrFhssHopSeq = 0; + float dataRateMeasured = 0; + int16_t modSetup(float tcxoVoltage, uint8_t modem); static int16_t SPIparseStatus(uint8_t in); static int16_t SPIcheckStatus(Module* mod); bool findChip(uint8_t ver); From 43ca08d8ee6fc0ce60943279e71f110e0f6de428 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Apr 2024 15:24:49 +0200 Subject: [PATCH 1010/1848] [LR11x0] Added LR1120/21 classes --- src/RadioLib.h | 2 + src/modules/LR11x0/LR1110.cpp | 43 ++------------- src/modules/LR11x0/LR1110.h | 16 ------ src/modules/LR11x0/LR1120.cpp | 59 +++++++++++++++++++++ src/modules/LR11x0/LR1120.h | 99 +++++++++++++++++++++++++++++++++++ src/modules/LR11x0/LR1121.cpp | 8 +++ src/modules/LR11x0/LR1121.h | 35 +++++++++++++ src/modules/LR11x0/LR11x0.cpp | 43 +++++++++++++-- src/modules/LR11x0/LR11x0.h | 25 +++++++-- 9 files changed, 268 insertions(+), 62 deletions(-) create mode 100644 src/modules/LR11x0/LR1120.cpp create mode 100644 src/modules/LR11x0/LR1120.h create mode 100644 src/modules/LR11x0/LR1121.cpp create mode 100644 src/modules/LR11x0/LR1121.h diff --git a/src/RadioLib.h b/src/RadioLib.h index 304dae6d90..34b1d90e36 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -69,6 +69,8 @@ #include "modules/CC1101/CC1101.h" #include "modules/LLCC68/LLCC68.h" #include "modules/LR11x0/LR1110.h" +#include "modules/LR11x0/LR1120.h" +#include "modules/LR11x0/LR1121.h" #include "modules/nRF24/nRF24.h" #include "modules/RF69/RF69.h" #include "modules/RFM2x/RFM22.h" diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 729300af14..39f005273b 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -7,40 +7,31 @@ LR1110::LR1110(Module* mod) : LR11x0(mod) { int16_t LR1110::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); return(state); } int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage); + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); return(state); } int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - state = setOutputPower(power); return(state); } @@ -61,32 +52,4 @@ int16_t LR1110::setFrequency(float freq, bool calibrate, float band) { return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); } -int16_t LR1110::setOutputPower(int8_t power) { - return(this->setOutputPower(power, false)); -} - -int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { - // determine whether to use HP or LP PA and check range accordingly - bool useHp = forceHighPower || (power > 14); - if(useHp) { - RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - useHp = true; - - } else { - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - useHp = false; - - } - - // TODO how and when to configure OCP? - - // update PA config - always use VBAT for high-power PA - int16_t state = LR11x0::setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); - RADIOLIB_ASSERT(state); - - // set output power - state = LR11x0::setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); - return(state); -} - #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index ffcd2e9d33..daf54b6f7d 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -86,22 +86,6 @@ class LR1110: public LR11x0 { \returns \ref status_codes */ int16_t setFrequency(float freq, bool calibrate, float band = 4); - - /*! - \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). - \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. - \returns \ref status_codes - */ - int16_t setOutputPower(int8_t power); - - /*! - \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). - \param power Output power to be set in dBm. - \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically - based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. - \returns \ref status_codes - */ - int16_t setOutputPower(int8_t power, bool forceHighPower); #if !RADIOLIB_GODMODE private: diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp new file mode 100644 index 0000000000..b3c0c88eb1 --- /dev/null +++ b/src/modules/LR11x0/LR1120.cpp @@ -0,0 +1,59 @@ +#include "LR1120.h" +#if !RADIOLIB_EXCLUDE_LR11X0 + +LR1120::LR1120(Module* mod) : LR11x0(mod) { + chipType = RADIOLIB_LR11X0_HW_LR1120; +} + +int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { + // execute common part + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + return(state); +} + +int16_t LR1120::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { + // execute common part + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + return(state); +} + +int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { + // execute common part + int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + return(state); +} + +int16_t LR1120::setFrequency(float freq) { + return(this->setFrequency(freq, true)); +} + +int16_t LR1120::setFrequency(float freq, bool calibrate, float band) { + if(!(((freq >= 150.0) && (freq <= 960.0)) || + ((freq >= 1900.0) && (freq <= 2200.0)) || + ((freq >= 2400.0) && (freq <= 2500.0)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + + // calibrate image rejection + if(calibrate) { + int16_t state = LR11x0::calibImage(freq - band, freq + band); + RADIOLIB_ASSERT(state); + } + + // set frequency + return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); +} + +#endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h new file mode 100644 index 0000000000..c7360c7a2f --- /dev/null +++ b/src/modules/LR11x0/LR1120.h @@ -0,0 +1,99 @@ +#if !defined(_RADIOLIB_LR1120_H) +#define _RADIOLIB_LR1120_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +#include "../../Module.h" +#include "LR11x0.h" + +/*! + \class LR1120 + \brief Derived class for %LR1120 modules. +*/ +class LR1120: public LR11x0 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + LR1120(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12). + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6); + + /*! + \brief Initialization method for FSK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t beginGFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6); + + /*! + \brief Initialization method for LR-FHSS modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, int8_t power = 10, float tcxoVoltage = 1.6); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, + 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, + 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + \param freq Carrier frequency to be set in MHz. + \param calibrate Run image calibration. + \param band Half bandwidth for image calibration. For example, + if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate + for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz + \returns \ref status_codes + */ + int16_t setFrequency(float freq, bool calibrate, float band = 4); + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/src/modules/LR11x0/LR1121.cpp b/src/modules/LR11x0/LR1121.cpp new file mode 100644 index 0000000000..14e729201b --- /dev/null +++ b/src/modules/LR11x0/LR1121.cpp @@ -0,0 +1,8 @@ +#include "LR1121.h" +#if !RADIOLIB_EXCLUDE_LR11X0 + +LR1121::LR1121(Module* mod) : LR1120(mod) { + chipType = RADIOLIB_LR11X0_HW_LR1121; +} + +#endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1121.h b/src/modules/LR11x0/LR1121.h new file mode 100644 index 0000000000..183e023a9d --- /dev/null +++ b/src/modules/LR11x0/LR1121.h @@ -0,0 +1,35 @@ +#if !defined(_RADIOLIB_LR1121_H) +#define _RADIOLIB_LR1121_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +#include "../../Module.h" +#include "LR11x0.h" +#include "LR1120.h" + +/*! + \class LR1121 + \brief Derived class for %LR1121 modules. +*/ +class LR1121: public LR1120 { + public: + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + LR1121(Module* mod); + + // TODO this is where overrides to disable GNSS+WiFi scanning methods on LR1121 + // will be put once those are implemented + +#if !RADIOLIB_GODMODE + private: +#endif + +}; + +#endif + +#endif diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 26d54aef30..1ddcbf4783 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -13,7 +13,7 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, this->XTAL = false; } -int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); @@ -30,6 +30,9 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 state = setSyncWord(syncWord); RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -44,7 +47,7 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16 return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); @@ -58,6 +61,9 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble state = setRxBandwidth(rxBw); RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -82,7 +88,7 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage) { +int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS); RADIOLIB_ASSERT(state); @@ -91,6 +97,9 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage) { state = setLrFhssConfig(bw, cr); RADIOLIB_ASSERT(state); + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + state = setSyncWord(0x12AD101B); RADIOLIB_ASSERT(state); @@ -579,6 +588,34 @@ int16_t LR11x0::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } +int16_t LR11x0::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) { + // determine whether to use HP or LP PA and check range accordingly + bool useHp = forceHighPower || (power > 14); + if(useHp) { + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + useHp = true; + + } else { + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + useHp = false; + + } + + // TODO how and when to configure OCP? + + // update PA config - always use VBAT for high-power PA + int16_t state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + return(state); +} + int16_t LR11x0::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 63d704149d..2a09a2974a 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -566,31 +566,34 @@ class LR11x0: public PhysicalLayer { \param sf LoRa spreading factor. \param cr LoRa coding rate denominator. \param syncWord 1-byte LoRa sync word. + \param power Output power in dBm. \param preambleLength LoRa preamble length in symbols \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage); + int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage); /*! \brief Initialization method for FSK modem. \param br FSK bit rate in kbps. \param freqDev Frequency deviation from carrier frequency in kHz. \param rxBw Receiver bandwidth in kHz. + \param power Output power in dBm. \param preambleLength FSK preamble length in bits. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage); + int16_t beginGFSK(float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage); /*! \brief Initialization method for LR-FHSS modem. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. + \param power Output power in dBm. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage); + int16_t beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -782,6 +785,22 @@ class LR11x0: public PhysicalLayer { int16_t getChannelScanResult() override; // configuration methods + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool forceHighPower); /*! \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. From ecfc18c35df19294f7aa19c2b2a598816198e660 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 25 Apr 2024 20:03:06 +0200 Subject: [PATCH 1011/1848] [CC1101] Fix RSSI readout (#1077) --- src/modules/CC1101/CC1101.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f8d2bd5afe..da1fa3759b 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -758,7 +758,7 @@ int16_t CC1101::setOOK(bool enableOOK) { float CC1101::getRSSI() { float rssi; - if (this->directModeEnabled) { + if(!this->directModeEnabled) { if(this->rawRSSI >= 128) { rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0; } else { @@ -766,12 +766,9 @@ float CC1101::getRSSI() { } } else { uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI); - if (rawRssi >= 128) - { + if(rawRssi >= 128) { rssi = ((rawRssi - 256) / 2) - 74; - } - else - { + } else { rssi = (rawRssi / 2) - 74; } } From 205031550b89e5684cb4fffa180fc9bfa900abcf Mon Sep 17 00:00:00 2001 From: Elizabeth Myers Date: Thu, 25 Apr 2024 12:50:58 -0700 Subject: [PATCH 1012/1848] Use RadioLibTime_t (aka unsigned long) when dealing with millis() and micros() (#1075) * Use unsigned long when dealing with millis() and micros(). Although sizeof(uint32_t) == sizeof(unsigned long) on Arduino, this is not the case on 64-bit Linux, where sizeof(unsigned long) == sizeof(uint64_t). Most timestamp arithmetic and comparisons have been left alone, to reduce code churn. This is fine, as uint32_t is perfectly wide to store most timestamp deltas this library will deal with, and C will promote the integer rather than do a narrowing conversion. The real problem arises with narrowing conversions being done by assuming timestamps are 32-bit. No functional changes intended for platforms where sizeof(uint32_t) == sizeof(unsigned long) (so most 8/16/32-bit platforms). Signed-off-by: Elizabeth Myers * Change most timestamps to use RadioLibTime_t. This makes it obvious what is and isn't a timestamp. Not everything has been converted; anything dealing with protocol and chip-level timestamps has been left alone on purpose, to make it clear that these functions do require 32-bit timestamps. No functional changes intended on platforms where sizeof(uint32_t) == sizeof(unsigned long). Signed-off-by: Elizabeth Myers * Use uint32_t internally in getTimeOnAir. We need to not overflow the integers with the shifts and multiplications, so this is correct behaviour. Signed-off-by: Elizabeth Myers --------- Signed-off-by: Elizabeth Myers --- examples/NonArduino/Raspberry/PiHal.h | 10 +++---- extras/test/SX126x/PiHal.h | 14 +++++----- src/ArduinoHal.cpp | 12 ++++----- src/ArduinoHal.h | 12 ++++----- src/BuildOpt.h | 8 +++--- src/Hal.cpp | 2 +- src/Hal.h | 12 ++++----- src/Module.cpp | 10 +++---- src/Module.h | 4 +-- src/TypeDef.h | 15 +++++++++++ src/modules/CC1101/CC1101.cpp | 10 +++---- src/modules/LR11x0/LR11x0.cpp | 21 +++++++-------- src/modules/LR11x0/LR11x0.h | 2 +- src/modules/RF69/RF69.cpp | 8 +++--- src/modules/SX126x/SX126x.cpp | 24 ++++++++--------- src/modules/SX126x/SX126x.h | 4 +-- src/modules/SX127x/SX127x.cpp | 24 ++++++++--------- src/modules/SX127x/SX127x.h | 4 +-- src/modules/SX128x/SX1280.cpp | 2 +- src/modules/SX128x/SX128x.cpp | 12 ++++----- src/modules/SX128x/SX128x.h | 2 +- src/modules/Si443x/Si443x.cpp | 8 +++--- src/protocols/BellModem/BellModem.cpp | 2 +- src/protocols/FSK4/FSK4.cpp | 4 +-- src/protocols/FSK4/FSK4.h | 2 +- src/protocols/Hellschreiber/Hellschreiber.cpp | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 26 +++++++++---------- src/protocols/LoRaWAN/LoRaWAN.h | 22 ++++++++-------- src/protocols/Morse/Morse.h | 4 +-- src/protocols/Pager/Pager.cpp | 6 ++--- src/protocols/Pager/Pager.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 +-- src/protocols/PhysicalLayer/PhysicalLayer.h | 4 +-- src/protocols/RTTY/RTTY.cpp | 6 ++--- src/protocols/RTTY/RTTY.h | 2 +- src/protocols/SSTV/SSTV.cpp | 4 +-- src/protocols/SSTV/SSTV.h | 4 +-- 37 files changed, 165 insertions(+), 149 deletions(-) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 162a223425..5a1b288a6d 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -106,23 +106,23 @@ class PiHal : public RadioLibHal { gpioSetAlertFuncEx(interruptNum, NULL, NULL); } - void delay(unsigned long ms) override { + void delay(RadioLibTime_t ms) override { gpioDelay(ms * 1000); } - void delayMicroseconds(unsigned long us) override { + void delayMicroseconds(RadioLibTime_t us) override { gpioDelay(us); } - unsigned long millis() override { + RadioLibTime_t millis() override { return(gpioTick() / 1000); } - unsigned long micros() override { + RadioLibTime_t micros() override { return(gpioTick()); } - long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override { if(pin == RADIOLIB_NC) { return(0); } diff --git a/extras/test/SX126x/PiHal.h b/extras/test/SX126x/PiHal.h index 9bf4f8f183..40bb5aee52 100644 --- a/extras/test/SX126x/PiHal.h +++ b/extras/test/SX126x/PiHal.h @@ -86,30 +86,30 @@ class PiHal : public RadioLibHal { gpioSetISRFunc(interruptNum, 0, 0, NULL); } - void delay(unsigned long ms) override { + void delay(RadioLibTime_t ms) override { gpioDelay(ms * 1000); } - void delayMicroseconds(unsigned long us) override { + void delayMicroseconds(RadioLibTime_t us) override { gpioDelay(us); } - unsigned long millis() override { + RadioLibTime_t millis() override { return(gpioTick() / 1000); } - unsigned long micros() override { + RadioLibTime_t micros() override { return(gpioTick()); } - long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override { if(pin == RADIOLIB_NC) { return(0); } this->pinMode(pin, PI_INPUT); - uint32_t start = this->micros(); - uint32_t curtick = this->micros(); + RadioLibTime_t start = this->micros(); + RadioLibTime_t curtick = this->micros(); while(this->digitalRead(pin) == state) { if((this->micros() - curtick) > timeout) { diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index 9c5fd571aa..fce0fb1b08 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -53,7 +53,7 @@ void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) { ::detachInterrupt(interruptNum); } -void inline ArduinoHal::delay(unsigned long ms) { +void inline ArduinoHal::delay(RadioLibTime_t ms) { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) ::delay(ms); #else @@ -61,7 +61,7 @@ void inline ArduinoHal::delay(unsigned long ms) { #endif } -void inline ArduinoHal::delayMicroseconds(unsigned long us) { +void inline ArduinoHal::delayMicroseconds(RadioLibTime_t us) { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) ::delayMicroseconds(us); #else @@ -69,7 +69,7 @@ void inline ArduinoHal::delayMicroseconds(unsigned long us) { #endif } -unsigned long inline ArduinoHal::millis() { +RadioLibTime_t inline ArduinoHal::millis() { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) return(::millis()); #else @@ -77,7 +77,7 @@ unsigned long inline ArduinoHal::millis() { #endif } -unsigned long inline ArduinoHal::micros() { +RadioLibTime_t inline ArduinoHal::micros() { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) return(::micros()); #else @@ -85,7 +85,7 @@ unsigned long inline ArduinoHal::micros() { #endif } -long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) { +long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) { if(pin == RADIOLIB_NC) { return 0; } @@ -114,7 +114,7 @@ void inline ArduinoHal::spiEnd() { spi->end(); } -void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { +void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration) { #if !defined(RADIOLIB_TONE_UNSUPPORTED) if(pin == RADIOLIB_NC) { return; diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 2fa8b5d6c9..35a483b2cd 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -40,11 +40,11 @@ class ArduinoHal : public RadioLibHal { uint32_t digitalRead(uint32_t pin) override; void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override; void detachInterrupt(uint32_t interruptNum) override; - void delay(unsigned long ms) override; - void delayMicroseconds(unsigned long us) override; - unsigned long millis() override; - unsigned long micros() override; - long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override; + void delay(RadioLibTime_t ms) override; + void delayMicroseconds(RadioLibTime_t us) override; + RadioLibTime_t millis() override; + RadioLibTime_t micros() override; + long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override; void spiBegin() override; void spiBeginTransaction() override; void spiTransfer(uint8_t* out, size_t len, uint8_t* in) override; @@ -54,7 +54,7 @@ class ArduinoHal : public RadioLibHal { // implementations of virtual RadioLibHal methods void init() override; void term() override; - void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override; + void tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration = 0) override; void noTone(uint32_t pin) override; void yield() override; uint32_t pinToInterrupt(uint32_t pin) override; diff --git a/src/BuildOpt.h b/src/BuildOpt.h index f220e46d59..9d860abe2b 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -1,6 +1,8 @@ #if !defined(_RADIOLIB_BUILD_OPTIONS_H) #define _RADIOLIB_BUILD_OPTIONS_H +#include "TypeDef.h" + /* RadioLib build configuration options */ /* @@ -350,12 +352,12 @@ // ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS! #if defined(millis) #undef millis - inline unsigned long millis() { return((unsigned long)(STCV / 1000)); }; + inline RadioLibTime_t millis() { return((RadioLibTime_t)(STCV / 1000)); }; #endif #if defined(micros) #undef micros - inline unsigned long micros() { return((unsigned long)(STCV)); }; + inline RadioLibTime_t micros() { return((RadioLibTime_t)(STCV)); }; #endif #elif defined(TEENSYDUINO) @@ -574,4 +576,4 @@ #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) -#endif \ No newline at end of file +#endif diff --git a/src/Hal.cpp b/src/Hal.cpp index 1a42aa15a7..acc43bfe7f 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -16,7 +16,7 @@ void RadioLibHal::term() { } -void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { +void RadioLibHal::tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration) { (void)pin; (void)frequency; (void)duration; diff --git a/src/Hal.h b/src/Hal.h index 03bf174cee..291b34735d 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -104,28 +104,28 @@ class RadioLibHal { Must be implemented by the platform-specific hardware abstraction! \param ms Number of milliseconds to wait. */ - virtual void delay(unsigned long ms) = 0; + virtual void delay(RadioLibTime_t ms) = 0; /*! \brief Blocking microsecond wait function. Must be implemented by the platform-specific hardware abstraction! \param us Number of microseconds to wait. */ - virtual void delayMicroseconds(unsigned long us) = 0; + virtual void delayMicroseconds(RadioLibTime_t us) = 0; /*! \brief Get number of milliseconds since start. Must be implemented by the platform-specific hardware abstraction! \returns Number of milliseconds since start. */ - virtual unsigned long millis() = 0; + virtual RadioLibTime_t millis() = 0; /*! \brief Get number of microseconds since start. Must be implemented by the platform-specific hardware abstraction! \returns Number of microseconds since start. */ - virtual unsigned long micros() = 0; + virtual RadioLibTime_t micros() = 0; /*! \brief Measure the length of incoming digital pulse in microseconds. @@ -135,7 +135,7 @@ class RadioLibHal { \param timeout Timeout in microseconds. \returns Pulse length in microseconds, or 0 if the pulse did not start before timeout. */ - virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0; + virtual long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) = 0; /*! \brief SPI initialization method. @@ -188,7 +188,7 @@ class RadioLibHal { \param frequency Frequency of the square wave. \param duration Duration of the tone in ms. When set to 0, the tone will be infinite. */ - virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0); + virtual void tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration = 0); /*! \brief Method to stop producing a tone. diff --git a/src/Module.cpp b/src/Module.cpp index 05de592250..e9b86b416b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -75,7 +75,7 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t #if RADIOLIB_SPI_PARANOID // check register value each millisecond until check interval is reached // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) - uint32_t start = this->hal->micros(); + RadioLibTime_t start = this->hal->micros(); uint8_t readValue = 0x00; while(this->hal->micros() - start < (checkInterval * 1000)) { readValue = SPIreadRegister(reg); @@ -308,7 +308,7 @@ int16_t Module::SPIcheckStream() { return(state); } -int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) { +int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout) { // prepare the buffers size_t buffLen = cmdLen + numBytes; if(!write) { @@ -339,7 +339,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint if(this->gpioPin == RADIOLIB_NC) { this->hal->delay(50); } else { - uint32_t start = this->hal->millis(); + RadioLibTime_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { @@ -366,7 +366,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint this->hal->delay(1); } else { this->hal->delayMicroseconds(1); - uint32_t start = this->hal->millis(); + RadioLibTime_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { @@ -432,7 +432,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint return(state); } -void Module::waitForMicroseconds(uint32_t start, uint32_t len) { +void Module::waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len) { #if RADIOLIB_INTERRUPT_TIMING (void)start; if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) { diff --git a/src/Module.h b/src/Module.h index 630f431b5b..ea48184b05 100644 --- a/src/Module.h +++ b/src/Module.h @@ -371,7 +371,7 @@ class Module { \param timeout GPIO wait period timeout in milliseconds. \returns \ref status_codes */ - int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout); + int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout); // pin number access methods @@ -503,7 +503,7 @@ class Module { \param start Waiting start timestamp, in microseconds. \param len Waiting duration, in microseconds; */ - void waitForMicroseconds(uint32_t start, uint32_t len); + void waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len); /*! \brief Function to reflect bits within a byte. diff --git a/src/TypeDef.h b/src/TypeDef.h index 6cb67247ee..61109d52cf 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -567,4 +567,19 @@ \} */ +/*! + \defgroup typedefs Type aliases used by RadioLib. + + \{ +*/ + +/*! + \brief Type used for durations in RadioLib +*/ +typedef unsigned long RadioLibTime_t; + +/*! + \} +*/ + #endif diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index da1fa3759b..5d8f963b03 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -100,14 +100,14 @@ void CC1101::reset() { int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); + RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission start or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getGpio())) { this->mod->hal->yield(); @@ -133,14 +133,14 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t CC1101::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full max-length packets at current bit rate) - uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); + RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet start or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); @@ -172,7 +172,7 @@ int16_t CC1101::standby() { SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); // wait until idle is reached - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != RADIOLIB_CC1101_MARC_STATE_IDLE) { mod->hal->yield(); if(this->mod->hal->millis() - start > 100) { diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 1ddcbf4783..b44c1bb07d 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -118,7 +118,7 @@ int16_t LR11x0::reset() { this->mod->hal->delay(300); // wait for BUSY to go low - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getGpio())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start >= 3000) { @@ -143,7 +143,7 @@ int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { // get currently active modem uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); - uint32_t timeout = getTimeOnAir(len); + RadioLibTime_t timeout = getTimeOnAir(len); if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate timeout (150% of expected time-on-air) timeout = (timeout * 3) / 2; @@ -163,7 +163,7 @@ int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = this->mod->hal->micros(); + RadioLibTime_t start = this->mod->hal->micros(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->micros() - start > timeout) { @@ -171,7 +171,7 @@ int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_TX_TIMEOUT); } } - uint32_t elapsed = this->mod->hal->micros() - start; + RadioLibTime_t elapsed = this->mod->hal->micros() - start; // update data rate this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0); @@ -184,7 +184,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { int16_t state = standby(); RADIOLIB_ASSERT(state); - uint32_t timeout = 0; + RadioLibTime_t timeout = 0; // get currently active modem uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -192,7 +192,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (uint32_t)(symbolLength * 100.0); + timeout = (RadioLibTime_t)(symbolLength * 100.0); } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) @@ -201,14 +201,14 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { maxLen = 0xFF; } float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; - timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); + timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { size_t maxLen = len; if(len == 0) { maxLen = 0xFF; } - timeout = (uint32_t)(((maxLen * 8.0) / (RADIOLIB_LR11X0_LR_FHSS_BIT_RATE)) * 1000.0 * 5.0); + timeout = (RadioLibTime_t)(((maxLen * 8.0) / (RADIOLIB_LR11X0_LR_FHSS_BIT_RATE)) * 1000.0 * 5.0); } else { return(RADIOLIB_ERR_UNKNOWN); @@ -224,7 +224,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout bool softTimeout = false; - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio @@ -1226,7 +1226,7 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { return((size_t)len); } -uint32_t LR11x0::getTimeOnAir(size_t len) { +RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; getPacketType(&type); @@ -1289,7 +1289,6 @@ uint32_t LR11x0::getTimeOnAir(size_t len) { } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { return(((uint32_t)len * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); - } return(0); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 2a09a2974a..cdee10e533 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1017,7 +1017,7 @@ class LR11x0: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - uint32_t getTimeOnAir(size_t len) override; + RadioLibTime_t getTimeOnAir(size_t len) override; /*! \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 84080f38ac..3044260c9c 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -100,14 +100,14 @@ void RF69::reset() { int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); + RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); @@ -122,14 +122,14 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t RF69::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); + RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1b37d6b506..de010d6859 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -207,7 +207,7 @@ int16_t SX126x::reset(bool verify) { } // set mode to standby - SX126x often refuses first few commands after reset - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -238,7 +238,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // calculate timeout in ms (500% of expected time-on-air) - uint32_t timeout = (getTimeOnAir(len) * 5) / 1000; + RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start transmission @@ -246,7 +246,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { @@ -256,7 +256,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // update data rate - uint32_t elapsed = this->mod->hal->millis() - start; + RadioLibTime_t elapsed = this->mod->hal->millis() - start; this->dataRateMeasured = (len*8.0)/((float)elapsed/1000.0); return(finishTransmit()); @@ -267,14 +267,14 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { int16_t state = standby(); RADIOLIB_ASSERT(state); - uint32_t timeout = 0; + RadioLibTime_t timeout = 0; // get currently active modem uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (uint32_t)(symbolLength * 100.0); + timeout = (RadioLibTime_t)(symbolLength * 100.0); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) @@ -283,7 +283,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { maxLen = 0xFF; } float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; - timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); + timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); } else { return(RADIOLIB_ERR_UNKNOWN); @@ -299,7 +299,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout bool softTimeout = false; - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio @@ -1413,7 +1413,7 @@ int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen)); } -uint32_t SX126x::getTimeOnAir(size_t len) { +RadioLibTime_t SX126x::getTimeOnAir(size_t len) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) { @@ -1444,14 +1444,14 @@ uint32_t SX126x::getTimeOnAir(size_t len) { return((symbolLength_us * nSymbol_x4) / 4); } else { - return((len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); + return(((uint32_t)len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); } } -uint32_t SX126x::calculateRxTimeout(uint32_t timeoutUs) { +RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) { // the timeout value is given in units of 15.625 microseconds // the calling function should provide some extra width, as this number of units is truncated to integer - uint32_t timeout = timeoutUs / 15.625; + RadioLibTime_t timeout = timeoutUs / 15.625; return(timeout); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index ec25fb66bc..f8829b9c26 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -957,14 +957,14 @@ class SX126x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - uint32_t getTimeOnAir(size_t len) override; + RadioLibTime_t getTimeOnAir(size_t len) override; /*! \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) \param timeoutUs Timeout in microseconds to listen for \returns Timeout value in a unit that is specific for the used module */ - uint32_t calculateRxTimeout(uint32_t timeoutUs); + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); /*! \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 98d78394d7..bda0080ad8 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -147,9 +147,9 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); - uint32_t start = 0; - uint32_t timeout = 0; - uint32_t toa = getTimeOnAir(len); + RadioLibTime_t start = 0; + RadioLibTime_t timeout = 0; + RadioLibTime_t toa = getTimeOnAir(len); if(modem == RADIOLIB_SX127X_LORA) { // calculate timeout in ms (150 % of expected time-on-air) timeout = (toa * 1.5) / 1000; @@ -179,7 +179,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // update data rate - uint32_t elapsed = this->mod->hal->millis() - start; + RadioLibTime_t elapsed = this->mod->hal->millis() - start; this->dataRate = (len*8.0)/((float)elapsed/1000.0); return(finishTransmit()); @@ -197,14 +197,14 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout) - uint32_t timeout = 0; + RadioLibTime_t timeout = 0; if(this->mod->getGpio() == RADIOLIB_NC) { float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - timeout = (uint32_t)(symbolLength * 100.0); + timeout = (RadioLibTime_t)(symbolLength * 100.0); } // wait for packet reception or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); @@ -226,14 +226,14 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // calculate timeout in ms (500 % of expected time-on-air) - uint32_t timeout = (getTimeOnAir(len) * 5) / 1000; + RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; // set mode to receive state = startReceive(len, RADIOLIB_SX127X_RX); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { @@ -1244,7 +1244,7 @@ float SX127x::getNumSymbols(size_t len) { return(n_pre + n_pay + 4.25f); } -uint32_t SX127x::getTimeOnAir(size_t len) { +RadioLibTime_t SX127x::getTimeOnAir(size_t len) { // check active modem uint8_t modem = getActiveModem(); if (modem == RADIOLIB_SX127X_LORA) { @@ -1280,12 +1280,12 @@ uint32_t SX127x::getTimeOnAir(size_t len) { return(RADIOLIB_ERR_UNKNOWN); } -uint32_t SX127x::calculateRxTimeout(uint32_t timeoutUs) { +RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) { // the timeout is given as the number of symbols // the calling function should provide some extra width, as this number of symbols is truncated to integer // the order of operators is swapped here to decrease the effects of this truncation error float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - uint32_t numSymbols = (timeoutUs / symbolLength) / 1000; + RadioLibTime_t numSymbols = (timeoutUs / symbolLength) / 1000; return(numSymbols); } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 70713d8891..05edabb0c6 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1055,14 +1055,14 @@ class SX127x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - uint32_t getTimeOnAir(size_t len) override; + RadioLibTime_t getTimeOnAir(size_t len) override; /*! \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) \param timeoutUs Timeout in microseconds to listen for \returns Timeout value in a unit that is specific for the used module */ - uint32_t calculateRxTimeout(uint32_t timeoutUs); + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); /*! \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index b5b30dd09f..7692c0a83d 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -13,7 +13,7 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { // wait until ranging is finished Module* mod = this->getMod(); - uint32_t start = mod->hal->millis(); + RadioLibTime_t start = mod->hal->millis(); while(!mod->hal->digitalRead(mod->getIrq())) { mod->hal->yield(); if(mod->hal->millis() - start > 10000) { diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 45873e5af8..4d79c4ef37 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -281,7 +281,7 @@ int16_t SX128x::reset(bool verify) { } // set mode to standby - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -318,7 +318,7 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // calculate timeout in ms (500% of expected time-on-air) - uint32_t timeout = (getTimeOnAir(len) * 5) / 1000; + RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start transmission @@ -326,7 +326,7 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { @@ -350,7 +350,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // calculate timeout (1000% of expected time-on-air) - uint32_t timeout = getTimeOnAir(len) * 10; + RadioLibTime_t timeout = getTimeOnAir(len) * 10; RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start reception @@ -360,7 +360,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout bool softTimeout = false; - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio @@ -1235,7 +1235,7 @@ size_t SX128x::getPacketLength(bool update) { return((size_t)rxBufStatus[0]); } -uint32_t SX128x::getTimeOnAir(size_t len) { +RadioLibTime_t SX128x::getTimeOnAir(size_t len) { // check active modem uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 1348f3aeda..8c8d30cd64 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -722,7 +722,7 @@ class SX128x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - uint32_t getTimeOnAir(size_t len); + RadioLibTime_t getTimeOnAir(size_t len); /*! \brief Set implicit header mode for future reception/transmission. diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index dcd6375165..f25ac9d6a9 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -73,14 +73,14 @@ void Si443x::reset() { int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) - uint32_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); + RadioLibTime_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { @@ -94,14 +94,14 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t Si443x::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - uint32_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); + RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { if(this->mod->hal->millis() - start > timeout) { standby(); diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp index bab036e99f..a4c6f3e805 100644 --- a/src/protocols/BellModem/BellModem.cpp +++ b/src/protocols/BellModem/BellModem.cpp @@ -70,7 +70,7 @@ size_t BellClient::write(uint8_t b) { // iterate over the bits and set correct frequencies for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); if(b & mask) { this->tone(toneMark, false); } else { diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index f589f4595f..4fd267e66a 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -22,7 +22,7 @@ int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { shiftFreqHz = shift; // calculate duration of 1 bit - bitDuration = (uint32_t)1000000/rate; + bitDuration = (RadioLibTime_t)1000000/rate; // calculate carrier shift shiftFreq = getRawShift(shift); @@ -81,7 +81,7 @@ size_t FSK4Client::write(uint8_t b) { void FSK4Client::tone(uint8_t i) { Module* mod = phyLayer->getMod(); - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); transmitDirect(baseFreq + tones[i], baseFreqHz + tonesHz[i]); mod->waitForMicroseconds(start, bitDuration); } diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index a1e91e3723..e4ff2db347 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -84,7 +84,7 @@ class FSK4Client { uint32_t baseFreq = 0, baseFreqHz = 0; uint32_t shiftFreq = 0, shiftFreqHz = 0; - uint32_t bitDuration = 0; + RadioLibTime_t bitDuration = 0; uint32_t tones[4]; uint32_t tonesHz[4]; diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index f23bc40fa6..eafd25ea34 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -36,7 +36,7 @@ size_t HellClient::printGlyph(uint8_t* buff) { bool transmitting = false; for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { for(int8_t i = RADIOLIB_HELL_FONT_HEIGHT - 1; i >= 0; i--) { - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); if((buff[i] & mask) && (!transmitting)) { transmitting = true; transmitDirect(baseFreq, baseFreqHz); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index bb51ea2419..a80bafd908 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -877,7 +877,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } // if adhering to dutyCycle and the time since last uplink + interval has not elapsed, return an error - if(this->dutyCycleEnabled && this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA) > mod->hal->millis()) { + if(this->dutyCycleEnabled && this->rxDelayStart + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > mod->hal->millis()) { return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); } @@ -1143,7 +1143,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf int16_t LoRaWANNode::downlinkCommon() { Module* mod = this->phyLayer->getMod(); - const uint32_t scanGuard = 10; + const RadioLibTime_t scanGuard = 10; // check if there are any upcoming Rx windows // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 @@ -1181,12 +1181,12 @@ int16_t LoRaWANNode::downlinkCommon() { // calculate the Rx timeout // according to the spec, this must be at least enough time to effectively detect a preamble // but pad it a bit on both sides (start and end) to make sure it is wide enough - uint32_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000; - uint32_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); + RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000; + RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); // wait for the start of the Rx window // the waiting duration is shortened a bit to cover any possible timing errors - uint32_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart); + RadioLibTime_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart); if(waitLen > scanGuard) { waitLen -= scanGuard; } @@ -1942,7 +1942,7 @@ void LoRaWANNode::setADR(bool enable) { this->adrEnabled = enable; } -void LoRaWANNode::setDutyCycle(bool enable, uint32_t msPerHour) { +void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { this->dutyCycleEnabled = enable; if(msPerHour <= 0) { this->dutyCycle = this->band->dutyCycle; @@ -1953,26 +1953,26 @@ void LoRaWANNode::setDutyCycle(bool enable, uint32_t msPerHour) { // given an airtime in milliseconds, calculate the minimum uplink interval // to adhere to a given dutyCycle -uint32_t LoRaWANNode::dutyCycleInterval(uint32_t msPerHour, uint32_t airtime) { +RadioLibTime_t LoRaWANNode::dutyCycleInterval(RadioLibTime_t msPerHour, RadioLibTime_t airtime) { if(msPerHour == 0 || airtime == 0) { return(0); } - uint32_t oneHourInMs = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000; + RadioLibTime_t oneHourInMs = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000; float numPackets = msPerHour / airtime; - uint32_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems + RadioLibTime_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems return(delayMs); } -uint32_t LoRaWANNode::timeUntilUplink() { +RadioLibTime_t LoRaWANNode::timeUntilUplink() { Module* mod = this->phyLayer->getMod(); - uint32_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); + RadioLibTime_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); if(mod->hal->millis() > nextUplink){ return(0); } return(nextUplink - mod->hal->millis() + 1); } -void LoRaWANNode::setDwellTime(bool enable, uint32_t msPerUplink) { +void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { this->dwellTimeEnabledUp = enable; if(msPerUplink <= 0) { this->dwellTimeUp = this->band->dwellTimeUp; @@ -2320,7 +2320,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { if(maxDutyCycle == 0) { this->dutyCycle = this->band->dutyCycle; } else { - this->dutyCycle = (uint32_t)60 * (uint32_t)60 * (uint32_t)1000 / (uint32_t)(1UL << maxDutyCycle); + this->dutyCycle = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000 / (RadioLibTime_t)(1UL << maxDutyCycle); } memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index d2f05e9b93..061a20b2d4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -361,13 +361,13 @@ struct LoRaWANBand_t { int8_t powerNumSteps; /*! \brief Number of milliseconds per hour of allowed Time-on-Air */ - uint32_t dutyCycle; + RadioLibTime_t dutyCycle; /*! \brief Maximum dwell time per uplink message in milliseconds */ - uint32_t dwellTimeUp; + RadioLibTime_t dwellTimeUp; /*! \brief Maximum dwell time per downlink message in milliseconds */ - uint32_t dwellTimeDn; + RadioLibTime_t dwellTimeDn; /*! \brief A set of default uplink (TX) channels for frequency-type bands */ LoRaWANChannel_t txFreqs[3]; @@ -772,7 +772,7 @@ class LoRaWANNode { \param msPerHour The maximum allowed Time-on-Air per hour in milliseconds (default 0 = maximum allowed for configured band). */ - void setDutyCycle(bool enable = true, uint32_t msPerHour = 0); + void setDutyCycle(bool enable = true, RadioLibTime_t msPerHour = 0); /*! \brief Calculate the minimum interval to adhere to a certain dutyCycle. @@ -781,10 +781,10 @@ class LoRaWANNode { \param airtime The airtime of the uplink. \returns Required interval (delay) in milliseconds between consecutive uplinks. */ - uint32_t dutyCycleInterval(uint32_t msPerHour, uint32_t airtime); + RadioLibTime_t dutyCycleInterval(RadioLibTime_t msPerHour, RadioLibTime_t airtime); /*! \brief Returns time in milliseconds until next uplink is available under dutyCycle limits */ - uint32_t timeUntilUplink(); + RadioLibTime_t timeUntilUplink(); /*! \brief Toggle adherence to dwellTime limits to on or off. @@ -792,7 +792,7 @@ class LoRaWANNode { \param msPerUplink The maximum allowed Time-on-Air per uplink in milliseconds (default 0 = maximum allowed for configured band). */ - void setDwellTime(bool enable, uint32_t msPerUplink = 0); + void setDwellTime(bool enable, RadioLibTime_t msPerUplink = 0); /*! \brief Returns the maximum payload given the currently present dwell time limits. @@ -932,16 +932,16 @@ class LoRaWANNode { uint8_t rev = 0; // Time on Air of last uplink - uint32_t lastToA = 0; + RadioLibTime_t lastToA = 0; // timestamp to measure the RX1/2 delay (from uplink end) - uint32_t rxDelayStart = 0; + RadioLibTime_t rxDelayStart = 0; // timestamp when the Rx1/2 windows were closed (timeout or uplink received) - uint32_t rxDelayEnd = 0; + RadioLibTime_t rxDelayEnd = 0; // delays between the uplink and RX1/2 windows - uint32_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; + RadioLibTime_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; // device status - battery level uint8_t battLevel = 0xFF; diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 3edb0beae2..66c39193ae 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -167,9 +167,9 @@ class MorseClient: public RadioLibPrint { // variables to keep decoding state uint32_t signalCounter = 0; - uint32_t signalStart = 0; + RadioLibTime_t signalStart = 0; uint32_t pauseCounter = 0; - uint32_t pauseStart = 0; + RadioLibTime_t pauseStart = 0; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 1db47da619..50151877d0 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -36,7 +36,7 @@ PagerClient::PagerClient(PhysicalLayer* phy) { int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { // calculate duration of 1 bit in us dataRate = (float)speed/1000.0f; - bitDuration = (uint32_t)1000000/speed; + bitDuration = (RadioLibTime_t)1000000/speed; // calculate 24-bit frequency baseFreq = base; @@ -511,7 +511,7 @@ void PagerClient::write(uint32_t codeWord) { Module* mod = phyLayer->getMod(); for(int8_t i = 31; i >= 0; i--) { uint32_t mask = (uint32_t)0x01 << i; - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); // figure out the shift direction - start by assuming the bit is 0 int16_t change = shiftFreq; @@ -532,7 +532,7 @@ void PagerClient::write(uint32_t codeWord) { // this is pretty silly, while(mod->hal->micros() ... ) would be enough // but for some reason, MegaCore throws a linker error on it // "relocation truncated to fit: R_AVR_7_PCREL against `no symbol'" - uint32_t now = mod->hal->micros(); + RadioLibTime_t now = mod->hal->micros(); while(now - start < bitDuration) { now = mod->hal->micros(); } diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index f5cdb81902..1663ae034e 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -182,7 +182,7 @@ class PagerClient { uint32_t baseFreqRaw; uint16_t shiftFreq; uint16_t shiftFreqHz; - uint16_t bitDuration; + RadioLibTime_t bitDuration; uint32_t filterAddr; uint32_t filterMask; uint32_t *filterAddresses; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index a1b51730e6..822cc18a65 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -294,12 +294,12 @@ float PhysicalLayer::getSNR() { return(RADIOLIB_ERR_UNSUPPORTED); } -uint32_t PhysicalLayer::getTimeOnAir(size_t len) { +RadioLibTime_t PhysicalLayer::getTimeOnAir(size_t len) { (void)len; return(0); } -uint32_t PhysicalLayer::calculateRxTimeout(uint32_t timeoutUs) { +RadioLibTime_t PhysicalLayer::calculateRxTimeout(RadioLibTime_t timeoutUs) { (void)timeoutUs; return(0); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index e30329ea19..f27e79ea17 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -335,14 +335,14 @@ class PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - virtual uint32_t getTimeOnAir(size_t len); + virtual RadioLibTime_t getTimeOnAir(size_t len); /*! \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) \param timeoutUs Timeout in microseconds to listen for \returns Timeout value in a unit that is specific for the used module */ - virtual uint32_t calculateRxTimeout(uint32_t timeoutUs); + virtual RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); /*! \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index c823fb280b..17da7d20c1 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -28,7 +28,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc shiftFreqHz = shift; // calculate duration of 1 bit - bitDuration = (uint32_t)1000000/rate; + bitDuration = (RadioLibTime_t)1000000/rate; // calculate module carrier frequency resolution uint32_t step = round(phyLayer->getFreqStep()); @@ -91,14 +91,14 @@ size_t RTTYClient::write(uint8_t b) { void RTTYClient::mark() { Module* mod = phyLayer->getMod(); - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); transmitDirect(baseFreq + shiftFreq, baseFreqHz + shiftFreqHz); mod->waitForMicroseconds(start, bitDuration); } void RTTYClient::space() { Module* mod = phyLayer->getMod(); - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(start, bitDuration); } diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index 4da4ca6316..7ba28214ef 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -71,7 +71,7 @@ class RTTYClient: public RadioLibPrint { uint32_t baseFreq = 0, baseFreqHz = 0; uint32_t shiftFreq = 0, shiftFreqHz = 0; - uint32_t bitDuration = 0; + RadioLibTime_t bitDuration = 0; uint8_t stopBitsNum = 0; void mark(); diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index b06df29753..0543e07f02 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -289,9 +289,9 @@ uint16_t SSTVClient::getPictureHeight() const { return(txMode.height); } -void SSTVClient::tone(float freq, uint32_t len) { +void SSTVClient::tone(float freq, RadioLibTime_t len) { Module* mod = phyLayer->getMod(); - uint32_t start = mod->hal->micros(); + RadioLibTime_t start = mod->hal->micros(); #if !RADIOLIB_EXCLUDE_AFSK if(audioClient != nullptr) { audioClient->tone(freq, false); diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index 986dd0cbbe..9d5811b850 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -54,7 +54,7 @@ struct tone_t { /*! \brief Length of tone in us, set to 0 for picture scan tones. */ - uint32_t len; + RadioLibTime_t len; /*! \brief Frequency of tone in Hz, set to 0 for picture scan tones. @@ -194,7 +194,7 @@ class SSTVClient { SSTVMode_t txMode = Scottie1; bool firstLine = true; - void tone(float freq, uint32_t len = 0); + void tone(float freq, RadioLibTime_t len = 0); }; #endif From 841b283c0f48f5218a28fdefcbd64e41cf00d25b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 26 Apr 2024 07:04:16 +0200 Subject: [PATCH 1013/1848] [LoRaWAN] Use dynamic array instead of VLA --- src/protocols/LoRaWAN/LoRaWAN.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a80bafd908..3922f14562 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1023,7 +1023,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // assume maximum possible buffer size uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; #else - uint8_t foptsBuff[foptsLen]; + uint8_t* foptsBuff = new uint8_t[foptsLen]; #endif uint8_t* foptsPtr = foptsBuff; @@ -1052,6 +1052,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // encrypt it processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + #if !RADIOLIB_STATIC_ONLY + delete[] foptsBuff; + #endif } // set the port From 1b2b8bd67b9c22544be0a6df105c50b01648a7a6 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Wed, 1 May 2024 13:35:22 +0200 Subject: [PATCH 1014/1848] [LoRaWAN] Improve PHY behaviour, update beginABP, bugfixes (#1080) * [LoRaWAN] Add getter for ToA, prevent MAC queue overflow * [LoRaWAN] Permute arguments to beginABP * Implement & split off checkOutputPower * [LoRaWAN] Configure physical layer on each up/downlink * [LoRaWAN] Remove unnecessary dynamic array * [LoRaWAN] Improve downlink handling * Resolve return-warnings in checkOutputPower() * [LoRaWAN] Improve buffer definition * [LoRaWAN] Prevent requesting repeated MAC commands * Update keywords.txt * [CC1101] Resolve unused variable warning * [CC1101] Update checkOutputPower * [SX1278] Fix variable assignment * Update keywords.txt * [CC1101] Added checkOutputPower override for PHY compatibility * [LR11x0] Added checkOutputPower override for PHY compatibility * [SX127x] Added checkOutputPower override for PHY compatibility --------- Co-authored-by: jgromes --- .github/workflows/main.yml | 2 +- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 6 +- keywords.txt | 3 +- src/modules/CC1101/CC1101.cpp | 110 ++++++--- src/modules/CC1101/CC1101.h | 18 ++ src/modules/LR11x0/LR11x0.cpp | 36 ++- src/modules/LR11x0/LR11x0.h | 19 ++ src/modules/SX126x/SX1261.cpp | 14 +- src/modules/SX126x/SX1261.h | 8 + src/modules/SX126x/SX1262.cpp | 14 +- src/modules/SX126x/SX1262.h | 8 + src/modules/SX126x/SX1268.cpp | 14 +- src/modules/SX126x/SX1268.h | 8 + src/modules/SX127x/SX1272.cpp | 31 ++- src/modules/SX127x/SX1272.h | 18 ++ src/modules/SX127x/SX1278.cpp | 43 +++- src/modules/SX127x/SX1278.h | 18 ++ src/modules/SX128x/SX128x.cpp | 13 +- src/modules/SX128x/SX128x.h | 8 + src/protocols/LoRaWAN/LoRaWAN.cpp | 223 +++++++++-------- src/protocols/LoRaWAN/LoRaWAN.h | 224 +++++++++--------- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 6 + src/protocols/PhysicalLayer/PhysicalLayer.h | 8 + 23 files changed, 561 insertions(+), 291 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e7d4cbe3f4..48acb19a94 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -170,7 +170,7 @@ jobs: else # apply special flags for LoRaWAN if [[ ${example} =~ "LoRaWAN" ]]; then - flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_NWKS_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1" + flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1" fi # build sketch diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index 52e39d8e6e..b9de72e7d3 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -12,8 +12,8 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds #define RADIOLIB_LORAWAN_DEV_ADDR 0x------ #endif -#ifndef RADIOLIB_LORAWAN_NWKS_KEY // Replace with your NwkS Key -#define RADIOLIB_LORAWAN_NWKS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#ifndef RADIOLIB_LORAWAN_FNWKSINT_KEY // Replace with your FNwkSInt Key +#define RADIOLIB_LORAWAN_FNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- #endif #ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key #define RADIOLIB_LORAWAN_SNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- @@ -118,7 +118,7 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // copy over the keys in to the something that will not compile if incorrectly formatted uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR; -uint8_t NwkSKey[] = { RADIOLIB_LORAWAN_NWKS_KEY }; +uint8_t NwkSKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY }; uint8_t SNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // Previously sNwkSIntKey uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; diff --git a/keywords.txt b/keywords.txt index d160e7820c..5fbbcbb37a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -127,6 +127,7 @@ setCodingRate KEYWORD2 setFrequency KEYWORD2 setSyncWord KEYWORD2 setOutputPower KEYWORD2 +checkOutputPower KEYWORD2 setCurrentLimit KEYWORD2 setPreambleLength KEYWORD2 setGain KEYWORD2 @@ -328,10 +329,10 @@ timeUntilUplink KEYWORD2 setDwellTime KEYWORD2 maxPayloadDwellTime KEYWORD2 setTxPower KEYWORD2 -setCSMA KEYWORD2 getMacLinkCheckAns KEYWORD2 getMacDeviceTimeAns KEYWORD2 getDevAddr KEYWORD2 +getLastToA KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 5d8f963b03..1da68a02dc 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -560,6 +560,62 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { } int16_t CC1101::setOutputPower(int8_t pwr) { + // check if power value is configurable + uint8_t powerRaw = 0; + int16_t state = checkOutputPower(pwr, NULL, &powerRaw); + RADIOLIB_ASSERT(state); + + // store the value + this->power = pwr; + + if(this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ + // Amplitude modulation: + // PA_TABLE[0] is the power to be used when transmitting a 0 (no power) + // PA_TABLE[1] is the power to be used when transmitting a 1 (full power) + + uint8_t paValues[2] = {0x00, powerRaw}; + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2); + return(RADIOLIB_ERR_NONE); + + } else { + // Freq modulation: + // PA_TABLE[0] is the power to be used when transmitting. + return(SPIsetRegValue(RADIOLIB_CC1101_REG_PATABLE, powerRaw)); + } +} + +int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, NULL)); +} + +int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { + constexpr int8_t allowedPwrs[8] = { -30, -20, -15, -10, 0, 5, 7, 10 }; + + if(clipped) { + if(power <= -30) { + *clipped = -30; + } else if(power >= 10) { + *clipped = 10; + } else { + for(int i = 0; i < 8; i++) { + if(allowedPwrs[i] > power) { + break; + } + *clipped = allowedPwrs[i]; + } + } + } + + // if just a check occurs (and not requesting the raw power value), return now + if(!raw) { + for(int i = 0; i < 8; i++) { + if(allowedPwrs[i] == power) { + return(RADIOLIB_ERR_NONE); + } + } + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + // round to the known frequency settings uint8_t f; if(this->frequency < 374.0) { @@ -586,53 +642,35 @@ int16_t CC1101::setOutputPower(int8_t pwr) { {0xCB, 0xC8, 0xCB, 0xC7}, {0xC2, 0xC0, 0xC2, 0xC0}}; - uint8_t powerRaw; - switch(pwr) { - case -30: - powerRaw = paTable[0][f]; + switch(power) { + case allowedPwrs[0]: // -30 + *raw = paTable[0][f]; break; - case -20: - powerRaw = paTable[1][f]; + case allowedPwrs[1]: // -20 + *raw = paTable[1][f]; break; - case -15: - powerRaw = paTable[2][f]; + case allowedPwrs[2]: // -15 + *raw = paTable[2][f]; break; - case -10: - powerRaw = paTable[3][f]; + case allowedPwrs[3]: // -10 + *raw = paTable[3][f]; break; - case 0: - powerRaw = paTable[4][f]; + case allowedPwrs[4]: // 0 + *raw = paTable[4][f]; break; - case 5: - powerRaw = paTable[5][f]; + case allowedPwrs[5]: // 5 + *raw = paTable[5][f]; break; - case 7: - powerRaw = paTable[6][f]; + case allowedPwrs[6]: // 7 + *raw = paTable[6][f]; break; - case 10: - powerRaw = paTable[7][f]; + case allowedPwrs[7]: // 10 + *raw = paTable[7][f]; break; default: return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } - - // store the value - this->power = pwr; - - if(this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){ - // Amplitude modulation: - // PA_TABLE[0] is the power to be used when transmitting a 0 (no power) - // PA_TABLE[1] is the power to be used when transmitting a 1 (full power) - - uint8_t paValues[2] = {0x00, powerRaw}; - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2); - return(RADIOLIB_ERR_NONE); - - } else { - // Freq modulation: - // PA_TABLE[0] is the power to be used when transmitting. - return(SPIsetRegValue(RADIOLIB_CC1101_REG_PATABLE, powerRaw)); - } + return(RADIOLIB_ERR_NONE); } int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 3619d21846..237e1dcf29 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -774,6 +774,24 @@ class CC1101: public PhysicalLayer { */ int16_t setOutputPower(int8_t pwr); + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param raw Raw internal value. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw); + /*! \brief Sets 16-bit sync word as a two byte value. \param syncH MSB of the sync word. diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index b44c1bb07d..c9244bb894 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -593,22 +593,17 @@ int16_t LR11x0::setOutputPower(int8_t power) { } int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) { + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL, forceHighPower); + RADIOLIB_ASSERT(state); + // determine whether to use HP or LP PA and check range accordingly bool useHp = forceHighPower || (power > 14); - if(useHp) { - RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - useHp = true; - - } else { - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - useHp = false; - } - // TODO how and when to configure OCP? // update PA config - always use VBAT for high-power PA - int16_t state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); + state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); RADIOLIB_ASSERT(state); // set output power @@ -616,6 +611,27 @@ int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) { return(state); } +int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { + if(forceHighPower || (power > 14)) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + return(RADIOLIB_ERR_NONE); +} + int16_t LR11x0::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index cdee10e533..3a100e637f 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -802,6 +802,25 @@ class LR11x0: public PhysicalLayer { */ int16_t setOutputPower(int8_t power, bool forceHighPower); + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, PA will be determined automatically. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); + /*! \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. \param bw LoRa bandwidth to be set in kHz. diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index cabe2b5791..d6a90c3421 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -6,11 +6,13 @@ SX1261::SX1261(Module* mod): SX1262(mod) { } int16_t SX1261::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL); + RADIOLIB_ASSERT(state); // get current OCP configuration uint8_t ocp = 0; - int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); // set PA config @@ -25,4 +27,12 @@ int16_t SX1261::setOutputPower(int8_t power) { return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } +int16_t SX1261::checkOutputPower(int8_t power, int8_t* clipped) { + if(clipped) { + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_NONE); +} + #endif diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 01375d5582..6f40115993 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -34,6 +34,14 @@ class SX1261 : public SX1262 { */ int16_t setOutputPower(int8_t power); + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped); + #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 036cba0ada..232ad63801 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -98,11 +98,13 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) { } int16_t SX1262::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL); + RADIOLIB_ASSERT(state); // get current OCP configuration uint8_t ocp = 0; - int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); // set PA config @@ -117,4 +119,12 @@ int16_t SX1262::setOutputPower(int8_t power) { return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } +int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_NONE); +} + #endif diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index f47b1a8131..ebe8652a50 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -87,6 +87,14 @@ class SX1262: public SX126x { */ virtual int16_t setOutputPower(int8_t power); + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped); + #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 1b63c4d069..c50baaf164 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -93,11 +93,13 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) { } int16_t SX1268::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL); + RADIOLIB_ASSERT(state); // get current OCP configuration uint8_t ocp = 0; - int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); RADIOLIB_ASSERT(state); // set PA config @@ -112,4 +114,12 @@ int16_t SX1268::setOutputPower(int8_t power) { return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } +int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_NONE); +} + #endif diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 04edba39f5..d6f0415e72 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -85,6 +85,14 @@ class SX1268: public SX126x { */ int16_t setOutputPower(int8_t power); + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped); + #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 003a1cc205..6e8b6c0bfb 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -280,15 +280,12 @@ int16_t SX1272::setOutputPower(int8_t power) { } int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { - // check allowed power range - if(useRfo) { - RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - } else { - RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - } + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL, useRfo); + RADIOLIB_ASSERT(state); // set mode to standby - int16_t state = SX127x::standby(); + state = SX127x::standby(); Module* mod = this->getMod(); if(useRfo) { @@ -317,6 +314,26 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { return(state); } +int16_t SX1272::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t SX1272::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) { + // check allowed power range + if(useRfo) { + if(clipped) { + *clipped = RADIOLIB_MAX(-1, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(20, power)); + } + RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + return(RADIOLIB_ERR_NONE); +} + int16_t SX1272::setGain(uint8_t gain) { // check allowed range if(gain > 6) { diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 37e468ee06..0f9a171713 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -206,6 +206,24 @@ class SX1272: public SX127x { */ int16_t setOutputPower(int8_t power, bool useRfo); + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, assumes PA_BOOST pin. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool useRfo); + /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 22c2430384..78251d2456 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -294,19 +294,12 @@ int16_t SX1278::setOutputPower(int8_t power) { } int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { - // check allowed power range - if(useRfo) { - // RFO output - RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - } else { - // PA_BOOST output, check high-power operation - if(power != 20) { - RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - } - } + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL, useRfo); + RADIOLIB_ASSERT(state); // set mode to standby - int16_t state = SX127x::standby(); + state = SX127x::standby(); Module* mod = this->getMod(); if(useRfo) { @@ -342,6 +335,34 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { return(state); } +int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) { + // check allowed power range + if(useRfo) { + // RFO output + if(clipped) { + *clipped = RADIOLIB_MAX(-3, RADIOLIB_MIN(15, power)); + } + RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } else { + // PA_BOOST output, check high-power operation + if(clipped) { + if(power != 20) { + *clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(17, power)); + } else { + *clipped = 20; + } + } + if(power != 20) { + RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + } + return(RADIOLIB_ERR_NONE); +} + int16_t SX1278::setGain(uint8_t gain) { // check allowed range if(gain > 6) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 371b166012..a54623a9ac 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -218,6 +218,24 @@ class SX1278: public SX127x { */ int16_t setOutputPower(int8_t power, bool useRfo); + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, assumes PA_BOOST pin. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool useRfo); + /*! \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended). diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 4d79c4ef37..00f5b5e284 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -765,11 +765,22 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { } int16_t SX128x::setOutputPower(int8_t pwr) { - RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + // check if power value is configurable + int16_t state = checkOutputPower(power, NULL); + RADIOLIB_ASSERT(state); + this->power = pwr + 18; return(setTxParams(this->power)); } +int16_t SX128x::checkOutputPower(int8_t power, int8_t* clipped) { + if(clipped) { + *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, power)); + } + RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_NONE); +} + int16_t SX128x::setPreambleLength(uint32_t preambleLength) { uint8_t modem = getPacketType(); if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 8c8d30cd64..80618d71f4 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -608,6 +608,14 @@ class SX128x: public PhysicalLayer { */ int16_t setOutputPower(int8_t pwr); + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped); + /*! \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC). diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 3922f14562..03d2a7f07f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -241,9 +241,6 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass // copy uplink MAC command queue back in place memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); - state = this->setPhyProperties(); - RADIOLIB_ASSERT(state); - // full session is restored, so set joined flag to whichever mode is restored this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]); @@ -498,16 +495,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // setup all MAC properties to default values this->beginCommon(joinDr); - // set the physical layer configuration - state = this->setPhyProperties(); - RADIOLIB_ASSERT(state); - // select a random pair of Tx/Rx channels state = this->selectChannels(); RADIOLIB_ASSERT(state); - // configure for uplink with default configuration - state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + // set the physical layer configuration for uplink + state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // copy devNonce currently in use @@ -732,7 +725,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force, uint8_t initialDr) { +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force, uint8_t initialDr) { // if not forced and already joined, don't do anything if(!force && this->isJoined()) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active"); @@ -744,7 +737,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, // check if we actually need to restart from a clean session uint16_t checkSum = 0; checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); - checkSum ^= LoRaWANNode::checkSum16(nwkSKey, 16); + checkSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16); checkSum ^= LoRaWANNode::checkSum16(appSKey, 16); if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } @@ -763,12 +756,12 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); - memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); if(fNwkSIntKey) { this->rev = 1; memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } else { - memcpy(this->fNwkSIntKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->fNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); } if(sNwkSIntKey) { memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); @@ -784,10 +777,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, // setup all MAC properties to default values this->beginCommon(initialDr); - // set the physical layer configuration - state = this->setPhyProperties(); - RADIOLIB_ASSERT(state); - // reset all frame counters this->fcntUp = 0; this->aFcntDown = 0; @@ -970,9 +959,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } } - // configure for uplink + // set the physical layer configuration for uplink this->selectChannels(); - state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // if dwell time is imposed, calculated expected time on air and cancel if exceeds @@ -1019,12 +1008,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if we have some MAC commands to append if(foptsLen > 0) { - #if RADIOLIB_STATIC_ONLY // assume maximum possible buffer size uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; - #else - uint8_t* foptsBuff = new uint8_t[foptsLen]; - #endif uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer @@ -1052,9 +1037,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // encrypt it processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); - #if !RADIOLIB_STATIC_ONLY - delete[] foptsBuff; - #endif } // set the port @@ -1146,30 +1128,28 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf int16_t LoRaWANNode::downlinkCommon() { Module* mod = this->phyLayer->getMod(); - const RadioLibTime_t scanGuard = 10; + + // according to the spec, the Rx window must be at least enough time to effectively detect a preamble + // but we pad it a bit on both sides (start and end) to make sure it is wide enough + const RadioLibTime_t scanGuard = 10; // Rx window padding in milliseconds // check if there are any upcoming Rx windows // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 - if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[0] - scanGuard)) { + RadioLibTime_t now = mod->hal->millis(); // Fix the current timestamp to prevent negative delays + if(now > this->rxDelayStart + this->rxDelays[0] - scanGuard) { // if between start of Rx1 and end of Rx2, wait until Rx2 closes - if(mod->hal->millis() - this->rxDelayStart < this->rxDelays[1]) { - mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - mod->hal->millis()); + if(now < this->rxDelayStart + this->rxDelays[1]) { + mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - now); } // update the end timestamp in case user got stuck between uplink and downlink this->rxDelayEnd = mod->hal->millis(); return(RADIOLIB_ERR_NO_RX_WINDOW); } - // configure for downlink - int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); + // set the physical layer configuration for downlink + int16_t state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); RADIOLIB_ASSERT(state); - // downlink messages are sent with inverted IQ - if(!this->FSK) { - state = this->phyLayer->invertIQ(true); - RADIOLIB_ASSERT(state); - } - // create the masks that are required for receiving downlinks uint16_t irqFlags = 0x0000; uint16_t irqMask = 0x0000; @@ -1182,14 +1162,16 @@ int16_t LoRaWANNode::downlinkCommon() { downlinkAction = false; // calculate the Rx timeout - // according to the spec, this must be at least enough time to effectively detect a preamble - // but pad it a bit on both sides (start and end) to make sure it is wide enough RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000; RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); // wait for the start of the Rx window + RadioLibTime_t waitLen = this->rxDelayStart + this->rxDelays[i] - mod->hal->millis(); + // make sure that no underflow occured; if so, clip the delay (although this will likely miss any downlink) + if(waitLen > this->rxDelays[i]) { + waitLen = this->rxDelays[i]; + } // the waiting duration is shortened a bit to cover any possible timing errors - RadioLibTime_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart); if(waitLen > scanGuard) { waitLen -= scanGuard; } @@ -1215,7 +1197,8 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_ASSERT(state); DataRate_t dataRate; - findDataRate(this->rx2.drMax, &dataRate); + state = findDataRate(this->rx2.drMax, &dataRate); + RADIOLIB_ASSERT(state); state = this->phyLayer->setDataRate(dataRate); RADIOLIB_ASSERT(state); } @@ -1687,16 +1670,51 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { return(true); } -int16_t LoRaWANNode::setPhyProperties() { +int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { // set the physical layer configuration - int8_t pwr = this->txPowerMax - this->txPowerCur * 2; - int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(pwr--); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + int16_t state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); + RADIOLIB_ASSERT(state); + + // if this channel is an FSK channel, toggle the FSK switch + if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + this->FSK = true; + } else { + this->FSK = false; } + + int8_t pwr = this->txPowerMax - this->txPowerCur * 2; + + // at this point, assume that Tx power value is already checked, so ignore the return value + (void)this->phyLayer->checkOutputPower(pwr, &pwr); + state = this->phyLayer->setOutputPower(pwr); RADIOLIB_ASSERT(state); + DataRate_t dr; + state = findDataRate(this->dataRates[dir], &dr); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setDataRate(dr); + RADIOLIB_ASSERT(state); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, TX = %d dBm, BW = %6.3f kHz, CR = 4/%d", + dr.lora.spreadingFactor, pwr, dr.lora.bandwidth, dr.lora.codingRate); + + if(this->FSK) { + state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); + } + + // downlink messages are sent with inverted IQ + if(dir == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { + if(!this->FSK) { + state = this->phyLayer->invertIQ(true); + RADIOLIB_ASSERT(state); + } + } + + // this only needs to be done once-ish uint8_t syncWord[3] = { 0 }; uint8_t syncWordLen = 0; size_t preLen = 0; @@ -1987,7 +2005,8 @@ void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { uint8_t LoRaWANNode::maxPayloadDwellTime() { // configure current datarate DataRate_t dr; - findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); + // TODO this may fail horribly? + (void)findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); (void)this->phyLayer->setDataRate(dr); uint8_t minPayLen = 0; uint8_t maxPayLen = 255; @@ -2035,6 +2054,8 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower) { } int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + uint8_t dataRateBand = this->band->dataRates[dr]; if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { @@ -2059,50 +2080,37 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", - dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); } - return(RADIOLIB_ERR_NONE); -} - -int16_t LoRaWANNode::configureChannel(uint8_t dir) { - // set the frequency - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); - int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); - RADIOLIB_ASSERT(state); - - // if this channel is an FSK channel, toggle the FSK switch - if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - this->FSK = true; - } else { - this->FSK = false; - } - - DataRate_t dr; - findDataRate(this->dataRates[dir], &dr); - state = this->phyLayer->setDataRate(dr); - RADIOLIB_ASSERT(state); - - if(this->FSK) { - state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); - } + state = this->phyLayer->checkDataRate(*dataRate); return(state); } -bool LoRaWANNode::sendMacCommandReq(uint8_t cid) { +int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { bool valid = false; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { valid = MacTable[i].user; } } - if(!valid) - return(false); + if(!valid) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("You are not allowed to request this MAC command"); + return(RADIOLIB_ERR_INVALID_CID); + } + + // if there are already 15 MAC bytes in the uplink queue, we can't add a new one + if(this->commandsUp.len + 1 > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The maximum number of FOpts payload was reached"); + return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); + } + if(this->commandsUp.numCommands > RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The RadioLib internal MAC command queue was full"); + return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); + } + + // delete any prior requests for this MAC command, in case this is requested more than once + (void)deleteMacCommand(cid, &this->commandsUp); LoRaWANMacCommand_t cmd = { .cid = cid, @@ -2182,8 +2190,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { int16_t state = RADIOLIB_ERR_UNKNOWN; // get the ADR configuration - // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state - // but we don't bother and try to set each individual command uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; uint8_t txSteps = cmd->payload[0] & 0x0F; bool isInternalTxDr = cmd->payload[3] >> 7; @@ -2193,19 +2199,15 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t nbTrans = cmd->payload[3] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTrans); - // apply the configuration + // try to apply the datarate configuration uint8_t drAck = 0; if(drUp == 0x0F) { // keep the same drAck = 1; - // replace the 'placeholder' with the current actual value for saving - cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); - } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // check if the module supports this data rate DataRate_t dr; - findDataRate(drUp, &dr); - state = this->phyLayer->checkDataRate(dr); + state = findDataRate(drUp, &dr); if(state == RADIOLIB_ERR_NONE) { uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, @@ -2215,6 +2217,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { drAck = 1; } else { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); + drUp = 0x0F; // set value to 'keep the same' } } @@ -2224,25 +2227,20 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { if(txSteps == 0x0F) { pwrAck = 1; - // replace the 'placeholder' with the current actual value for saving - cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; - } else { - int8_t pwr = this->txPowerMax - 2*txSteps; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr); - state = RADIOLIB_ERR_INVALID_OUTPUT_POWER; - while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { - // go from the highest power and lower it until we hit one supported by the module - state = this->phyLayer->setOutputPower(pwr--); - } - // only acknowledge if the requested datarate was succesfully configured - if(state == RADIOLIB_ERR_NONE) { + int8_t power = this->txPowerMax - 2*txSteps; + int8_t powerActual = 0; + state = this->phyLayer->checkOutputPower(power, &powerActual); + // only acknowledge if the radio is able to operate at or below the requested power level + if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { pwrAck = 1; this->txPowerCur = txSteps; + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); + txSteps = 0x0F; // set value to 'keep the same' } } - uint8_t chMaskAck = 1; // only apply channel mask when the RFU bit is not set // (which is only set in internal MAC commands for changing Tx/Dr) @@ -2269,12 +2267,23 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } } - if(nbTrans == 0) { // keep the same - cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; // set current number of retransmissions for saving - } else { + if(nbTrans) { // if there is a value for NbTrans, set this value this->nbTrans = nbTrans; } + // replace 'placeholder' or failed values with the current values for saving + // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state + // but we don't bother and try to set each individual command + if(drUp == 0x0F || !drAck) { + cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + } + if(txSteps == 0x0F || !pwrAck) { + cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; + } + if(nbTrans == 0) { + cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; + } + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte if(isInternalTxDr) { @@ -2801,6 +2810,10 @@ uint64_t LoRaWANNode::getDevAddr() { return(this->devAddr); } +RadioLibTime_t LoRaWANNode::getLastToA() { + return(this->lastToA); +} + // The following function enables LMAC, a CSMA scheme for LoRa as specified // in the LoRa Alliance Technical Recommendation #13. // A user may enable CSMA to provide frames an additional layer of protection from interference. diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 061a20b2d4..9359c2ae28 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -159,6 +159,12 @@ #define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) #define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) +// maximum allowed dwell time on bands that implement dwell time limitations +#define RADIOLIB_LORAWAN_DWELL_TIME (400) + +// unused frame counter value +#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) + // MAC commands #define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) @@ -179,15 +185,6 @@ #define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) #define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) -// maximum allowed dwell time on bands that implement dwell time limitations -#define RADIOLIB_LORAWAN_DWELL_TIME (400) - -// unused LoRaWAN version -#define RADIOLIB_LORAWAN_VERSION_NONE (0xFF) - -// unused frame counter value -#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) - // the length of internal MAC command queue - hopefully this is enough for most use cases #define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) @@ -217,74 +214,109 @@ struct LoRaWANMacSpec_t { const bool user; }; -const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { +constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { { 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting - { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, - { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, - { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, - { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, - { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, - { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } + { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, + { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, + { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, + { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, + { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, + { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } +}; + +/*! + \struct LoRaWANMacCommand_t + \brief Structure to save information about MAC command +*/ +struct LoRaWANMacCommand_t { + /*! \brief The command ID */ + uint8_t cid; + + /*! \brief Payload buffer (5 bytes is the longest possible) */ + uint8_t payload[5]; + + /*! \brief Length of the payload */ + uint8_t len; + + /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ + uint8_t repeat; +}; + +/*! + \struct LoRaWANMacCommandQueue_t + \brief Structure to hold information about a queue of MAC commands +*/ +struct LoRaWANMacCommandQueue_t { + /*! \brief Number of commands in the queue */ + uint8_t numCommands; + + /*! \brief Total length of the queue */ + uint8_t len; + + /*! \brief MAC command buffer */ + LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; }; #define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) enum LoRaWANSchemeBase_t { - RADIOLIB_LORAWAN_NONCES_VERSION = 0x00, // 2 bytes - RADIOLIB_LORAWAN_NONCES_MODE = 0x02, // 2 bytes - RADIOLIB_LORAWAN_NONCES_CLASS = 0x04, // 1 byte - RADIOLIB_LORAWAN_NONCES_PLAN = 0x05, // 1 byte - RADIOLIB_LORAWAN_NONCES_CHECKSUM = 0x06, // 2 bytes - RADIOLIB_LORAWAN_NONCES_DEV_NONCE = 0x08, // 2 bytes - RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = 0x0A, // 3 bytes - RADIOLIB_LORAWAN_NONCES_ACTIVE = 0x0D, // 1 byte - RADIOLIB_LORAWAN_NONCES_SIGNATURE = 0x0E, // 2 bytes - RADIOLIB_LORAWAN_NONCES_BUF_SIZE = 0x10 // = 16 bytes + RADIOLIB_LORAWAN_NONCES_START = 0x00, + RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes + RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes + RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte + RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size }; enum LoRaWANSchemeSession_t { - RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = 0x00, // 16 bytes - RADIOLIB_LORAWAN_SESSION_APP_SKEY = 0x10, // 16 bytes - RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = 0x20, // 16 bytes - RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = 0x30, // 16 bytes - RADIOLIB_LORAWAN_SESSION_DEV_ADDR = 0x40, // 4 bytes - RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = 0x44, // 2 bytes - RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = 0x46, // 4 bytes - RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = 0x4A, // 4 bytes - RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = 0x4E, // 4 bytes - RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = 0x52, // 2 bytes - RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = 0x54, // 2 bytes - RADIOLIB_LORAWAN_SESSION_HOMENET_ID = 0x56, // 4 bytes - RADIOLIB_LORAWAN_SESSION_VERSION = 0x5A, // 1 byte - RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = 0x5B, // 1 byte - RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = 0x5C, // 4 bytes - RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = 0x60, // 1 byte - RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = 0x61, // 1 byte - RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = 0x62, // 1 byte - RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = 0x63, // 1 byte - RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = 0x64, // 3 bytes - RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = 0x67, // 4 bytes - RADIOLIB_LORAWAN_SESSION_PERIODICITY = 0x6B, // 1 byte - RADIOLIB_LORAWAN_SESSION_LAST_TIME = 0x6C, // 4 bytes - RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = 0x70, // 16*8 bytes - RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = 0xF0, // 16*4 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = 0x0130, // 9*8+2 bytes - RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = 0x017A, // 4 bytes - RADIOLIB_LORAWAN_SESSION_ADR_FCNT = 0x017E, // 4 bytes - RADIOLIB_LORAWAN_SESSION_LINK_ADR = 0x0182, // 4 bytes - RADIOLIB_LORAWAN_SESSION_FCNT_UP = 0x0186, // 4 bytes - RADIOLIB_LORAWAN_SESSION_SIGNATURE = 0x018A, // 2 bytes - RADIOLIB_LORAWAN_SESSION_BUF_SIZE = 0x018C // 396 bytes + RADIOLIB_LORAWAN_SESSION_START = 0x00, + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes + RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes + RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes + RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte + RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_LINK_ADR + MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, // 4 bytes + RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size }; /*! @@ -428,38 +460,6 @@ enum LoRaWANBandNum_t { // array of currently supported bands extern const LoRaWANBand_t* LoRaWANBands[]; -/*! - \struct LoRaWANMacCommand_t - \brief Structure to save information about MAC command -*/ -struct LoRaWANMacCommand_t { - /*! \brief The command ID */ - uint8_t cid; - - /*! \brief Payload buffer (5 bytes is the longest possible) */ - uint8_t payload[5]; - - /*! \brief Length of the payload */ - uint8_t len; - - /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ - uint8_t repeat; -}; -/*! - \struct LoRaWANMacCommandQueue_t - \brief Structure to hold information about a queue of MAC commands -*/ -struct LoRaWANMacCommandQueue_t { - /*! \brief Number of commands in the queue */ - uint8_t numCommands; - - /*! \brief Total length of the queue */ - uint8_t len; - - /*! \brief MAC command buffer */ - LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; -}; - /*! \struct LoRaWANEvent_t \brief Structure to save extra information about uplink/downlink event. @@ -567,15 +567,16 @@ class LoRaWANNode { \brief Join network by performing activation by personalization. In this procedure, all necessary configuration must be provided by the user. \param addr Device address. - \param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1). + \param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0. + \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0. + \param nwkSEncKey Pointer to the MAC command network session key [NwkSEncKey] (LoRaWAN 1.1) + or network session AES-128 key [NwkSKey] (LoRaWAN 1.0). \param appSKey Pointer to the application session AES-128 key. - \param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. - \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), unused for LoRaWAN 1.0. \param force Set to true to force a new session, even if one exists. \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \brief Whether there is an ongoing session active */ bool isJoined(); @@ -591,9 +592,9 @@ class LoRaWANNode { Only LinkCheck and DeviceTime are available to the user. Other commands are ignored; duplicate MAC commands are discarded. \param cid ID of the MAC command - \returns Whether or not the MAC command was added to the queue. + \returns \ref status_codes */ - bool sendMacCommandReq(uint8_t cid); + int16_t sendMacCommandReq(uint8_t cid); #if defined(RADIOLIB_BUILD_ARDUINO) /*! @@ -835,6 +836,12 @@ class LoRaWANNode { */ uint64_t getDevAddr(); + /*! + \brief Get the Time-on-air of the last uplink message + \returns (RadioLibTime_t) time-on-air (ToA) of last uplink message + */ + RadioLibTime_t getLastToA(); + #if !RADIOLIB_GODMODE private: #endif @@ -964,7 +971,7 @@ class LoRaWANNode { // configure the common physical layer properties (preamble, sync word etc.) // channels must be configured separately by setupChannelsDyn()! - int16_t setPhyProperties(); + int16_t setPhyProperties(uint8_t dir); // setup uplink/downlink channel data rates and frequencies // for dynamic channels, there is a small set of predefined channels @@ -984,9 +991,6 @@ class LoRaWANNode { // find the first usable data rate for the given band int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); - // configure channel based on cached data rate ID and frequency - int16_t configureChannel(uint8_t dir); - // restore all available channels from persistent storage int16_t restoreChannels(); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 822cc18a65..55e69329d8 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -256,6 +256,12 @@ int16_t PhysicalLayer::setOutputPower(int8_t power) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::checkOutputPower(int8_t power, int8_t* clipped) { + (void)power; + (void)clipped; + return(RADIOLIB_ERR_UNSUPPORTED); +} + int16_t PhysicalLayer::setSyncWord(uint8_t* sync, size_t len) { (void)sync; (void)len; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index f27e79ea17..3d48eda2b1 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -276,6 +276,14 @@ class PhysicalLayer { */ virtual int16_t setOutputPower(int8_t power); + /*! + \brief Check if output power is configurable. Must be implemented in module class if the module supports it. + \param power Output power in dBm. The allowed range depends on the module used. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + virtual int16_t checkOutputPower(int8_t power, int8_t* clipped); + /*! \brief Set sync word. Must be implemented in module class if the module supports it. \param sync Pointer to the sync word. From 2f85326fec622457665858ea60b3f8556ad8097f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 1 May 2024 23:12:05 +1000 Subject: [PATCH 1015/1848] examples/NonArduino/Tock: Support RISC-V and bump libtock-c (#1082) * examples/NonArduino/Tock: Support building for RISC-V Signed-off-by: Alistair Francis * examples/NonArduino/Tock: Update to newer libtock-c Signed-off-by: Alistair Francis --------- Signed-off-by: Alistair Francis --- .github/workflows/main.yml | 2 +- examples/NonArduino/Tock/.gitignore | 2 +- examples/NonArduino/Tock/CMakeLists.txt | 66 ++++++++++++-- examples/NonArduino/Tock/README.md | 6 +- examples/NonArduino/Tock/build.sh | 22 +++-- examples/NonArduino/Tock/libtock-c | 2 +- .../Tock/{tock.cmake => tock-arm.cmake} | 18 +++- examples/NonArduino/Tock/tock-riscv.cmake | 76 ++++++++++++++++ .../Tock/toolchain-arm-none-eabi.cmake | 90 ------------------- src/protocols/FSK4/FSK4.cpp | 1 + 10 files changed, 174 insertions(+), 111 deletions(-) rename examples/NonArduino/Tock/{tock.cmake => tock-arm.cmake} (78%) create mode 100644 examples/NonArduino/Tock/tock-riscv.cmake delete mode 100644 examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 48acb19a94..34f63a7a8d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -226,7 +226,7 @@ jobs: - name: Install dependencies run: | - sudo apt-get install -y gcc-arm-none-eabi + sudo apt-get install -y gcc-arm-none-eabi gcc-riscv64-unknown-elf cargo install elf2tab - name: Build the example diff --git a/examples/NonArduino/Tock/.gitignore b/examples/NonArduino/Tock/.gitignore index bd0079c9ae..3207b65aae 100644 --- a/examples/NonArduino/Tock/.gitignore +++ b/examples/NonArduino/Tock/.gitignore @@ -1,2 +1,2 @@ -build/ +build-* TockApp.tab diff --git a/examples/NonArduino/Tock/CMakeLists.txt b/examples/NonArduino/Tock/CMakeLists.txt index c7aaf866bd..eed0d08629 100644 --- a/examples/NonArduino/Tock/CMakeLists.txt +++ b/examples/NonArduino/Tock/CMakeLists.txt @@ -29,7 +29,11 @@ project(tock-sx1261) set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/userland_generic.ld) -include("tock.cmake") +if (RISCV_BUILD) + include("tock-riscv.cmake") +else() + include("tock-arm.cmake") +endif() # when using debuggers such as gdb, the following line can be used #set(CMAKE_BUILD_TYPE Debug) @@ -43,17 +47,61 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR add_executable(${PROJECT_NAME} main.cpp) # link with RadioLib and libtock-c -target_link_libraries(${PROJECT_NAME} PUBLIC - RadioLib - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libgcc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libstdc++.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libm.a -) +# The build system for libtock-c is a bit odd and the version of libraries +# built changes based on compiler version. +if (RISCV_BUILD) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0") + target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/rv32imc/libtock.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/riscv/lib/gcc/riscv64-unknown-elf/13.2.0/rv32i/ilp32/libgcc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a + ) + + target_include_directories(RadioLib AFTER PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/ + ) + else() + target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/rv32imc/libtock.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/riscv/lib/gcc/riscv64-unknown-elf/10.5.0/rv32i/ilp32/libgcc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a + ) + + target_include_directories(RadioLib AFTER PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/include/ + ) + endif() +else() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0") + target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/arm/lib/gcc/arm-none-eabi/13.2.0/libgcc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/arm/arm-none-eabi/lib/libstdc++.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libm.a + ) + else() + target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/arm/lib/gcc/arm-none-eabi/10.5.0/libgcc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/arm/arm-none-eabi/lib/libstdc++.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libc.a + ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libm.a + ) + endif() +endif() target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c ) diff --git a/examples/NonArduino/Tock/README.md b/examples/NonArduino/Tock/README.md index cd13b6dcd7..77ee19b76d 100644 --- a/examples/NonArduino/Tock/README.md +++ b/examples/NonArduino/Tock/README.md @@ -13,6 +13,10 @@ This has been tested on the but will work on any LoRa compatible Tock board (currently only the expLoRaBLE board). +libtock-c by default is bulit for RISC-V and ARM. RadioLib is also built +for both architectures by default. You can skip the RISC-V RadioLib build +by setting the `SKIP_RISCV` varaible. + The RadioLib example can be built with: ```shell @@ -24,5 +28,5 @@ $ ./build.sh Then in the Tock repo you can flash the kernel and app with: ```shell -$ make flash; APP=RadioLib/examples/NonArduino/Tock/build/tock-sx1261.tbf make flash-app +$ make flash; APP=RadioLib/examples/NonArduino/Tock/build-arm/tock-sx1261.tbf make flash-app ``` diff --git a/examples/NonArduino/Tock/build.sh b/examples/NonArduino/Tock/build.sh index a527bc9df6..cb91a4aedf 100755 --- a/examples/NonArduino/Tock/build.sh +++ b/examples/NonArduino/Tock/build.sh @@ -1,20 +1,30 @@ #!/bin/bash set -e -rm -rf ./build +rm -rf ./build-* -cd libtock-c/libtock +cd libtock-c/examples/cxx_hello make -j4 -cd ../../ +cd ../../../ -mkdir -p build -cd build +mkdir -p build-arm +cd build-arm cmake -G "CodeBlocks - Unix Makefiles" .. make -j4 cd .. +if ! env | grep SKIP_RISCV; then + mkdir -p build-riscv + cd build-riscv + + cmake -G "CodeBlocks - Unix Makefiles" -DRISCV_BUILD=1 .. + make -j4 + + cd .. +fi + elf2tab -n radio-lib --stack 4096 --app-heap 2048 --kernel-heap 2048 \ --kernel-major 2 --kernel-minor 1 \ - -v ./build/tock-sx1261 + -v ./build-arm/tock-sx1261 diff --git a/examples/NonArduino/Tock/libtock-c b/examples/NonArduino/Tock/libtock-c index 1c1f4c0810..44bf89c545 160000 --- a/examples/NonArduino/Tock/libtock-c +++ b/examples/NonArduino/Tock/libtock-c @@ -1 +1 @@ -Subproject commit 1c1f4c0810aa0fbd50aa91a11aaa7c05d2abb1bc +Subproject commit 44bf89c545953d8859faf101d4b4a4b6a151fe6c diff --git a/examples/NonArduino/Tock/tock.cmake b/examples/NonArduino/Tock/tock-arm.cmake similarity index 78% rename from examples/NonArduino/Tock/tock.cmake rename to examples/NonArduino/Tock/tock-arm.cmake index fb3682fc70..f557e2f3f1 100644 --- a/examples/NonArduino/Tock/tock.cmake +++ b/examples/NonArduino/Tock/tock-arm.cmake @@ -25,8 +25,6 @@ # This is copied from https://github.com/Lora-net/LoRaMac-node/pull/1390 # and has been relicensed by the original author -include("toolchain-arm-none-eabi.cmake") - if(NOT DEFINED LINKER_SCRIPT) message(FATAL_ERROR "No linker script defined") endif(NOT DEFINED LINKER_SCRIPT) @@ -40,6 +38,22 @@ set(STACK_SIZE 4096) set(APP_HEAP_SIZE 2048) set(KERNEL_HEAP_SIZE 2048) +set(TOOLCHAIN arm-none-eabi) + +find_program(TOOLCHAIN_PREFIX ${TOOLCHAIN}-gcc NO_CACHE) +get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN_PREFIX} DIRECTORY) + +set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin) +set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include) +set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib) + +#--------------------------------------------------------------------------------------- +# Set compilers +#--------------------------------------------------------------------------------------- +set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "C Compiler") +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++ CACHE INTERNAL "C++ Compiler") +set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "ASM Compiler") + # Object build options set(OBJECT_GEN_FLAGS "-mthumb -g2 -fno-builtin -mcpu=cortex-m4 -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -Wl,--emit-relocs -fPIC -mthumb -mfloat-abi=soft -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -D__TOCK__ -DSVCALL_AS_NORMAL_FUNCTION -DSOFTDEVICE_s130") diff --git a/examples/NonArduino/Tock/tock-riscv.cmake b/examples/NonArduino/Tock/tock-riscv.cmake new file mode 100644 index 0000000000..3d842944df --- /dev/null +++ b/examples/NonArduino/Tock/tock-riscv.cmake @@ -0,0 +1,76 @@ +# Tock target specific CMake file +# +# Licensed under the MIT License +# +# Copyright (c) 2023 Alistair Francis +# +# 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. +# +# This is copied from https://github.com/Lora-net/LoRaMac-node/pull/1390 +# and has been relicensed by the original author + +if(NOT DEFINED LINKER_SCRIPT) +message(FATAL_ERROR "No linker script defined") +endif(NOT DEFINED LINKER_SCRIPT) +message("Linker script: ${LINKER_SCRIPT}") + +#--------------------------------------------------------------------------------------- +# Set compiler/linker flags +#--------------------------------------------------------------------------------------- + +set(STACK_SIZE 4096) +set(APP_HEAP_SIZE 2048) +set(KERNEL_HEAP_SIZE 2048) + +find_program(TOOLCHAIN + NAMES + riscv64-none-elf-gcc + riscv32-none-elf-gcc + riscv64-elf-gcc + riscv32-unknown-elf-gcc + riscv64-unknown-elf-gcc + riscv64-unknown-elf-clang + riscv32-unknown-elf-clang + NO_CACHE) + +get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN} DIRECTORY) + +get_filename_component(TOOLCHAIN ${TOOLCHAIN} NAME) +string(REPLACE "-gcc" "" TOOLCHAIN ${TOOLCHAIN}) + +set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin) +set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include) +set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib) + +#--------------------------------------------------------------------------------------- +# Set compilers +#--------------------------------------------------------------------------------------- +set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "C Compiler") +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++ CACHE INTERNAL "C++ Compiler") +set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "ASM Compiler") + +# Object build options +set(OBJECT_GEN_FLAGS "-march=rv32i -mabi=ilp32 -mcmodel=medlow -g2 -fno-builtin -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-unroll-loops -ffast-math -ftree-vectorize -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -Wl,--emit-relocs -D__TOCK__ -DSVCALL_AS_NORMAL_FUNCTION -DSOFTDEVICE_s130") + +set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options") +set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++20 " CACHE INTERNAL "C++ Compiler options") +set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options") + +# Linker flags +set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections -march=rv32i -mabi=ilp32 -mcmodel=medlow -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Xlinker --defsym=STACK_SIZE=${STACK_SIZE} -Xlinker --defsym=APP_HEAP_SIZE=${APP_HEAP_SIZE} -Xlinker --defsym=KERNEL_HEAP_SIZE=${KERNEL_HEAP_SIZE} -nostdlib -Wl,--start-group" CACHE INTERNAL "Linker options") diff --git a/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake b/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake deleted file mode 100644 index 87a23f6309..0000000000 --- a/examples/NonArduino/Tock/toolchain-arm-none-eabi.cmake +++ /dev/null @@ -1,90 +0,0 @@ -# Arm specific CMake file -# -# This is copied from: -# https://github.com/Lora-net/LoRaMac-node/blob/2bf36bde72f68257eb96b5c00900619546bedca8/cmake/toolchain-arm-none-eabi.cmake -# -# The below file is licensed as Revised BSD License -# See https://github.com/Lora-net/LoRaMac-node/blob/master/LICENSE for details - -## -## ______ _ -## / _____) _ | | -## ( (____ _____ ____ _| |_ _____ ____| |__ -## \____ \| ___ | (_ _) ___ |/ ___) _ \ -## _____) ) ____| | | || |_| ____( (___| | | | -## (______/|_____)_|_|_| \__)_____)\____)_| |_| -## (C)2013-2017 Semtech -## ___ _____ _ ___ _ _____ ___ ___ ___ ___ -## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -## embedded.connectivity.solutions.============== -## -## License: Revised BSD License, see LICENSE.TXT file included in the project -## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech ) -## -## -## CMake arm-none-eabi toolchain file -## - -# Append current directory to CMAKE_MODULE_PATH for making device specific cmake modules visible -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) - -# Target definition -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_SYSTEM_PROCESSOR ARM) - -#--------------------------------------------------------------------------------------- -# Set toolchain paths -#--------------------------------------------------------------------------------------- -set(TOOLCHAIN arm-none-eabi) - -find_program(TOOLCHAIN_PREFIX ${TOOLCHAIN}-gcc NO_CACHE) -get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN_PREFIX} DIRECTORY) - -set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin) -set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include) -set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib) - -# Set system depended extensions -if(WIN32) - set(TOOLCHAIN_EXT ".exe" ) -else() - set(TOOLCHAIN_EXT "" ) -endif() - -# Perform compiler test with static library -set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - -#--------------------------------------------------------------------------------------- -# Preset some general GCC Options -#--------------------------------------------------------------------------------------- - -# Options for DEBUG build -# -Og enables optimizations that do not interfere with debugging -# -g produce debugging information in the operating system's native format -set(CMAKE_C_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C Compiler options for debug build type") -set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C++ Compiler options for debug build type") -set(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "ASM Compiler options for debug build type") -set(CMAKE_EXE_LINKER_FLAGS_DEBUG "" CACHE INTERNAL "Linker options for debug build type") - -# Options for RELEASE build -# -Os Optimize for size. -Os enables all -O2 optimizations -set(CMAKE_C_FLAGS_RELEASE "-Os" CACHE INTERNAL "C Compiler options for release build type") -set(CMAKE_CXX_FLAGS_RELEASE "-Os" CACHE INTERNAL "C++ Compiler options for release build type") -set(CMAKE_ASM_FLAGS_RELEASE "" CACHE INTERNAL "ASM Compiler options for release build type") -set(CMAKE_EXE_LINKER_FLAGS_RELEASE "" CACHE INTERNAL "Linker options for release build type") - -#--------------------------------------------------------------------------------------- -# Set compilers -#--------------------------------------------------------------------------------------- -set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "C Compiler") -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++${TOOLCHAIN_EXT} CACHE INTERNAL "C++ Compiler") -set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "ASM Compiler") - -set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX}/${${TOOLCHAIN}} ${CMAKE_PREFIX_PATH}) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 4fd267e66a..785961dfe1 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -1,4 +1,5 @@ #include "FSK4.h" +#include #include #if !RADIOLIB_EXCLUDE_FSK4 From 05e35407f46c498df305db08781beb030b886f26 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 May 2024 15:14:44 +0200 Subject: [PATCH 1016/1848] [FSK4] Use abs macro instead of abs function --- src/protocols/FSK4/FSK4.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 785961dfe1..7e2d737e81 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -1,5 +1,4 @@ #include "FSK4.h" -#include #include #if !RADIOLIB_EXCLUDE_FSK4 @@ -113,12 +112,12 @@ int32_t FSK4Client::getRawShift(int32_t shift) { int32_t step = round(phyLayer->getFreqStep()); // check minimum shift value - if(abs(shift) < step / 2) { + if(RADIOLIB_ABS(shift) < step / 2) { return(0); } // round shift to multiples of frequency step size - if(abs(shift) % step < (step / 2)) { + if(RADIOLIB_ABS(shift) % step < (step / 2)) { return(shift / step); } if(shift < 0) { From 97adb260cecd4bdcbe5aaaa47196af04fe96bb95 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 May 2024 15:40:08 +0100 Subject: [PATCH 1017/1848] [CI] Enable cppcheck inline suppression and suppres unchecked config --- .github/workflows/cppcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 684e11f9c1..25599005b4 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -24,4 +24,4 @@ jobs: - name: Run cppcheck run: - cppcheck src --enable=all --force + cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked From cb9cb875562f514f00724cfb37d962690db2a337 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 May 2024 15:41:24 +0100 Subject: [PATCH 1018/1848] [HAL] Make ArduinoHal constructor explicit --- src/ArduinoHal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 35a483b2cd..959b9d2295 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -32,7 +32,7 @@ class ArduinoHal : public RadioLibHal { \param spi SPI interface to be used, can also use software SPI implementations. \param spiSettings SPI interface settings. */ - ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); + explicit ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS); // implementations of pure virtual RadioLibHal methods void pinMode(uint32_t pin, uint32_t mode) override; From 809025eba6f5407bd8e921e597706aab71f6bdaa Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 May 2024 15:51:01 +0100 Subject: [PATCH 1019/1848] [Mod] Fix issues from cppcheck scan --- src/Module.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index e9b86b416b..4b4b5d96e9 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -76,13 +76,18 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t // check register value each millisecond until check interval is reached // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) RadioLibTime_t start = this->hal->micros(); + #if RADIOLIB_DEBUG_SPI uint8_t readValue = 0x00; + #endif while(this->hal->micros() - start < (checkInterval * 1000)) { - readValue = SPIreadRegister(reg); - if((readValue & checkMask) == (newValue & checkMask)) { + uint8_t val = SPIreadRegister(reg); + if((val & checkMask) == (newValue & checkMask)) { // check passed, we can stop the loop return(RADIOLIB_ERR_NONE); } + #if RADIOLIB_DEBUG_SPI + readValue = val; + #endif } // check failed, print debug info @@ -309,17 +314,15 @@ int16_t Module::SPIcheckStream() { } int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout) { - // prepare the buffers + // prepare the output buffer size_t buffLen = cmdLen + numBytes; if(!write) { buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8); } #if RADIOLIB_STATIC_ONLY uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; - uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* buffOut = new uint8_t[buffLen]; - uint8_t* buffIn = new uint8_t[buffLen]; #endif uint8_t* buffOutPtr = buffOut; @@ -346,13 +349,19 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; - delete[] buffIn; #endif return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } } + // prepare the input buffer + #if RADIOLIB_STATIC_ONLY + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + // do the transfer this->hal->spiBeginTransaction(); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); @@ -539,7 +548,7 @@ size_t Module::serialPrintf(const char* format, ...) { vsnprintf(buffer, len + 1, format, arg); va_end(arg); } - len = RADIOLIB_DEBUG_PORT.write((const uint8_t*)buffer, len); + len = RADIOLIB_DEBUG_PORT.write(reinterpret_cast(buffer), len); if (buffer != temp) { delete[] buffer; } From 92cb09a9326be193a18ae25aa1a317c0d53d11b3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 May 2024 18:05:16 +0100 Subject: [PATCH 1020/1848] [CC1101] Resolve issues reported by cppcheck --- src/modules/CC1101/CC1101.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 237e1dcf29..0519da9978 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -539,6 +539,7 @@ class CC1101: public PhysicalLayer { \brief Default constructor. \param module Instance of Module that will be used to communicate with the radio. */ + // cppcheck-suppress noExplicitConstructor CC1101(Module* module); // basic methods @@ -660,23 +661,23 @@ class CC1101: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Interrupt-driven binary transmit method. @@ -698,7 +699,7 @@ class CC1101: public PhysicalLayer { \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. @@ -708,7 +709,7 @@ class CC1101: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) override; /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, @@ -728,14 +729,14 @@ class CC1101: public PhysicalLayer { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets bit rate. Allowed values range from 0.025 to 600.0 kbps. \param br Bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Sets receiver bandwidth. Allowed values are 58, 68, 81, 102, 116, 135, 162, @@ -772,7 +773,7 @@ class CC1101: public PhysicalLayer { \param pwr Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t pwr); + int16_t setOutputPower(int8_t pwr) override; /*! \brief Check if output power is configurable. @@ -847,7 +848,7 @@ class CC1101: public PhysicalLayer { In asynchronous direct mode, returns the current RSSI level. \returns RSSI in dBm. */ - float getRSSI(); + float getRSSI() override; /*! \brief Gets LQI (Link Quality Indicator) of the last received packet. @@ -939,7 +940,7 @@ class CC1101: public PhysicalLayer { \brief Get one truly random byte from RSSI noise. \returns TRNG byte. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or @@ -953,13 +954,13 @@ class CC1101: public PhysicalLayer { \brief Set interrupt service routine function to call when data bit is receveid in direct mode. \param func Pointer to interrupt service routine. */ - void setDirectAction(void (*func)(void)); + void setDirectAction(void (*func)(void)) override; /*! \brief Function to read and process data bit in direct reception mode. \param pin Pin on which to read. */ - void readBit(uint32_t pin); + void readBit(uint32_t pin) override; #endif /*! @@ -968,12 +969,12 @@ class CC1101: public PhysicalLayer { \param value The value that indicates which function to place on that pin. See chip datasheet for details. \returns \ref status_codes */ - int16_t setDIOMapping(uint32_t pin, uint32_t value); + int16_t setDIOMapping(uint32_t pin, uint32_t value) override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; // SPI read overrides to set bit for burst write and status registers access int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0); From 7209690bf6aa92fcc6a17e3d08ab486cdbf0ddaa Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 May 2024 19:12:22 +0100 Subject: [PATCH 1021/1848] [Mod] Fixed hexdump not escaping format specifiers --- src/Module.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 4b4b5d96e9..6e907f01bc 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -471,7 +471,7 @@ uint32_t Module::reflect(uint32_t in, uint8_t bits) { void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { - char str[80]; + char str[120]; sprintf(str, "%07" PRIx32 " ", i+offset); size_t line_len = 16; if(rem_len < line_len) { @@ -497,15 +497,21 @@ void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offs } str[56] = '|'; str[57] = ' '; + + // at this point we need to start escaping "%" characters + char* strPtr = &str[58]; for(size_t j = 0; j < line_len; j++) { char c = data[i+j]; if((c < ' ') || (c > '~')) { c = '.'; + } else if(c == '%') { + *strPtr++ = '%'; } - sprintf(&str[58 + j], "%c", c); + sprintf(strPtr++, "%c", c); + } for(size_t j = line_len; j < 16; j++) { - sprintf(&str[58 + j], " "); + sprintf(strPtr++, " "); } if(level) { RADIOLIB_DEBUG_PRINT(level); From 6fe581aea78ee00462022aa2605d8772044813fd Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 3 May 2024 20:54:18 +0100 Subject: [PATCH 1022/1848] Fix minor format warnings --- src/Module.cpp | 2 +- src/modules/SX126x/SX126x.cpp | 4 ++-- src/modules/Si443x/Si443x.cpp | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- src/protocols/Morse/Morse.cpp | 2 +- src/protocols/Pager/Pager.cpp | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 6e907f01bc..7d02d9a08f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -472,7 +472,7 @@ void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offs size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { char str[120]; - sprintf(str, "%07" PRIx32 " ", i+offset); + sprintf(str, "%07" PRIx32 " ", (uint32_t)i+offset); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index de010d6859..105d1fda86 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -638,7 +638,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz); uint32_t sleepPeriod = symbolLength * sleepSymbols; - RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", sleepPeriod); + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", (long unsigned int)sleepPeriod); // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. // the duration is sleepPeriod + 2 * wakePeriod. @@ -649,7 +649,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ uint32_t wakePeriod = RADIOLIB_MAX( (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A) symbolLength * (minSymbols + 1)); //(B) - RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", wakePeriod); + RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", (long unsigned int)wakePeriod); // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < this->tcxoDelay + 1016) { diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index f25ac9d6a9..c6a225afb4 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -771,7 +771,7 @@ int16_t Si443x::updateClockRecovery() { // print that whole mess RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2); - RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain); + RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain); // update oversampling ratio int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 03d2a7f07f..24ea83edd2 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -543,7 +543,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check received length size_t lenRx = this->phyLayer->getPacketLength(true); if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %luB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -1179,7 +1179,7 @@ int16_t LoRaWANNode::downlinkCommon() { // open Rx window by starting receive with specified timeout state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, timeoutHost); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, (int)timeoutHost); // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 90cc2a68b5..b41dae7684 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -104,7 +104,7 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); (*len)++; } else { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("", signalLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("", (long unsigned int)signalLen); } } diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 50151877d0..48edee628f 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -554,7 +554,7 @@ uint32_t PagerClient::read() { codeWord = ~codeWord; } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%lX", codeWord); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%lX", (long unsigned int)codeWord); // TODO BCH error correction here return(codeWord); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 55e69329d8..293402ae32 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -419,7 +419,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { this->syncBuffer <<= 1; this->syncBuffer |= bit; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("S\t%lu", this->syncBuffer); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("S\t%lu", (long unsigned int)this->syncBuffer); if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) { this->gotSync = true; From b675e0c034f9c192dd2f6851cfab31ee36562f96 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 3 May 2024 21:05:44 +0100 Subject: [PATCH 1023/1848] Fix RPi example flags --- examples/NonArduino/Raspberry/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/NonArduino/Raspberry/CMakeLists.txt b/examples/NonArduino/Raspberry/CMakeLists.txt index 79feff1266..c9d47872f1 100644 --- a/examples/NonArduino/Raspberry/CMakeLists.txt +++ b/examples/NonArduino/Raspberry/CMakeLists.txt @@ -18,4 +18,5 @@ add_executable(${PROJECT_NAME} main.cpp) target_link_libraries(${PROJECT_NAME} RadioLib pigpio) # you can also specify RadioLib compile-time flags here -#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE) +#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI) +#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_PORT=stdout) From 639ff001092b7b63c21faef647d2415047562bd9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 3 May 2024 21:28:18 +0100 Subject: [PATCH 1024/1848] [SSTV] Added image converter tool --- extras/SSTV_Image_Converter/.gitignore | 4 ++ extras/SSTV_Image_Converter/ImageConverter.py | 50 ++++++++++++++++++ extras/SSTV_Image_Converter/radiolib.png | Bin 0 -> 63155 bytes 3 files changed, 54 insertions(+) create mode 100644 extras/SSTV_Image_Converter/.gitignore create mode 100755 extras/SSTV_Image_Converter/ImageConverter.py create mode 100644 extras/SSTV_Image_Converter/radiolib.png diff --git a/extras/SSTV_Image_Converter/.gitignore b/extras/SSTV_Image_Converter/.gitignore new file mode 100644 index 0000000000..bb45c8d1ba --- /dev/null +++ b/extras/SSTV_Image_Converter/.gitignore @@ -0,0 +1,4 @@ +# ignore all output files +*.h +*.png +!radiolib.png diff --git a/extras/SSTV_Image_Converter/ImageConverter.py b/extras/SSTV_Image_Converter/ImageConverter.py new file mode 100755 index 0000000000..844446572e --- /dev/null +++ b/extras/SSTV_Image_Converter/ImageConverter.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# -*- encoding: utf-8 -*- + +import argparse +import numpy as np +from PIL import Image +from argparse import RawTextHelpFormatter + +def main(): + parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' + RadioLib image to array conversion tool. + + Input is a PNG image to be transmitted via RadioLib SSTV. + The image must have correct size for the chose SSTV mode! + + Output is a file (by default named "img.h") which can be included and transmitted. + The resulting array will be very large (typically 320 kB), + make sure your platform has sufficient Flash/RAM space. + ''') + parser.add_argument('input', + type=str, + help='Input PNG file') + parser.add_argument('output', + type=str, + nargs='?', + default='img', + help='Output header file') + args = parser.parse_args() + outfile = f'{args.output}.h' + print(f'Converting "{args.input}" to "{outfile}"') + + # open the image as numpy array + img = Image.open(args.input) + arr = np.array(img) + + # open the output file + with open(outfile, 'w') as f: + print(f'const uint32_t img[{arr.shape[0]}][{arr.shape[1]}] = {{', file=f) + for row in arr: + print(' { ', end='', file=f) + for pix in row: + rgb = pix[0] << 16 | pix[1] << 8 | pix[2] + print(hex(rgb), end=', ', file=f) + print(' },', file=f) + print('};', file=f) + + print('Done!') + +if __name__ == "__main__": + main() diff --git a/extras/SSTV_Image_Converter/radiolib.png b/extras/SSTV_Image_Converter/radiolib.png new file mode 100644 index 0000000000000000000000000000000000000000..6a20aa85eb4b80d65d049c9739f834e22c71e930 GIT binary patch literal 63155 zcmV*CKyAN?P)EX>4Tx04R}tkv&MmKpe$iKcpg+4t5afkfAzRC@P|xRIvyaN?V~-2a`*`ph-iL z;^HW{799LotU9+0Yt2!bCV&JIqBE>hzEl0u6Z503ls?%w0>9pG)%m}2IR|cm(1(rs*c}2J!T! zsd3&X4zr3V6Q2{0>vTclN3Kf_zi}?x?B$tZJ(rm$4igLI9+rBTRdj`Tia07OD&>3g z4$GXkI4iXV>)eySFj!PqvRtPbK@v+yAq@c%8mOWM6ERv-*TU+9!bT8Msor{(1|T`6RvB z)uKm0XdAe=?rPE=aJd5vKWU;a+LDi^w^Rb&&*+;9z|bu)u;%pE*~jSvkfW}aZ-9eC zV605p>n`u^@9pj1GoAi^01yds=JS}W3jhEB24YJ`L;(K){{a7>y{D4^000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2j~PG5C93hc4mA403ZNKL_t(|+U%WooK?m7#=q~J zbNB8py%(j4C{k>wV6Pa(lGs~{u_YQ4d(>ZyC9x%@SYnGByJCS96=Mk~N>M~CNE1*x zNQZ?j_nvuwf6Uyrdv{r2>395G3*K_hoSA3d^1RP0s;bm6sv?WcdW))}lKY-~Um>bM zonH+ID%HM>nx7L1YQD!>HtR5w=N@an|1C9CsP#Ix_Mu|dy%x5Sdnt^D+i%tPmq^V; zo_bG7ScJ**|7#oJMlINl-uUW)vhEFB6YLst7vuwBo9A6MFQGp7U-N#X#<$h)u&DRS zsd1qyTOWwz1?s#Dd))`*#$JQCANOBfkM9=Avmk0*c*8E!tr(1}*S~u%P+|t)n7}-mIGt9Hd`d`-8a_w94(QFSGUf5*oZ}qBb0sb0#|A=f$i=glT zx04YTreJfq`#U(`RRcJc`WX?DFGjqDABE-tK@llDUb5# z)@u=L-3RPuu>ey)n%6oKkZOy#K33G`2bTIJVj2!8b(5|hQM;Ay7*p*!6{8ujQ$S6g z^;CTV#iX$@6MVNDctuiUGgp5y^UJTrD-r) z%{nZM!q_w;+=MHfLaJZ~cYLKLmn-cxpq_f-f`KA}s?9J=Bo$`cbO6|paorkRwH@IQ z+YaL51q-k+w#?@7{*x+HRzw6rNGvoUk_Jg(+dV|JV7nFoaGSMUG&lCs@Nvm}f228~i#o1p^9#MX^ADYQWNED;Yj~IIsQtzf7Gvn;?iWpnoq;Jn;k$J?v15;vqtm zbq!hz%xvDZus)wFjBR1BZ_!e?9dgQRRGw_^xl$3NTG^Rul;@o_t4d@8s$WFK0iYzY zHsIS?3%KHn-!Oa55?|?I5DX9@q6|8&Ki6J&1ua`OtuxWKNh%QPHGkVT;BBqJP$wg1eKMx zFn5KqNk;(y8^oKGZHfphn>jkA{`6J}`R{+<=9^h7u~7gTq-%XuEmnj`4avwbWax0F zPMMmnx!zoJocf(@?U@!v0RRhQD;`#a%BqMr-WZN*k+=91B=WB$DiJCc1*{szj2>Ia zBoxLb9XnhS#7Qn`9vfxD;~jN{QS0-2n=Ag8v1n4|WOe0O^H@L|OnZnh2vKFkS6_XD z1kF+7V~%Pv^Jf*rVx8B_gwG}-1pa}fUQ&yVxgl#oaxG%X^G#wvwI11M-G=u>o|r|o z|5nMPkhHmDuig{b>HyGjxVEJQAe(vNR{y=NVXib6)HbQYiNO#cYKes*mC49SDW%JL z)1@7Lfh!U~5C*7%F$Swq763L>7CjwRU)KV!$4_i;3BPU2^xjbXDY(Feu^E=T!CELT ziP3-mUYJ1YxCZ}su^e>L5aIXipGRnA9yB(-4s@V2nr>m?S|Gs8|nnUY5#$ngmF~ zfuqx_YKWVrZJRdSea{^X=-(YN79-+b#?ZUhuAKLya|uHOc|m2vCQA{l(`dtrx~!(S z`@~oXEQl?*q&wIM8*($R@2R}Qn%!G?gDHw2sHPI2Led5-Tegzfvt}VE-FE3htL9Bn z5*T9;4}K|kbVHwa>T|IoC@u*zpe7EGn>TOb-_x)_pNrZqzRm3ObKH;DLd6PHa8iR;I3^Z*NO;IpH>^og0RsyFxJ`nAZf@{_O%l_u%k~jmj15I3!U`mk5feW7 zlt&+Vk_n&9Ad(_PN)ZWAo1|bPY7+J}Y^%CG?Y!>~P%BwkUKf3{ zk)e)}_d7q*G8qU6Z?ZSl@{*VC&^(PEN z(8$LHCHLWJO``B71;NctTit=Yss;nVZN>H7G=Nw8>d*gsDf+L}>OpO&B1a9^RC4iF zRhYM6A&))&EUylE51|CK6fxF|lL}%2tXfvAjhH`wA??~W_vwOsJ&kMLd%j?`pm}D@ zf+PX!1QFB{MUndzFO;fOr|x8$BGt9z^Ci3H%$m#G`Q;$R2uUxzYTVV?7@vGPmrp1B zo)b|R@T#aE61Wl7?Ys?e%fo)KM542Yy>>gblOFbO#3+ z-7KH04~bg|9JpEQ7goS~AB^JW+x~{NC0G0$A2(9dF5I_XQfvc6Xfmc%CQ_Flq8sZureTL^kgBqND-#%Tr|8MuuyLV5Y z0&$j)sI6D?qiidudJo`D85XIJn#;O^>hAwr0$%~$fB$`X^wGQM-KQO5B3~02Wacw6 zEL&E|V~;*bqAEgd>YlSR=$qy~+0G>Tx2Ah30N{3K0XhoH)G5<>^zZ)!je{f*lSGU~ zFoZ_ft50X{yzBSu)Ukt)!5Botbi6OGRih1kt#xARCU+pM2&!?6jT34__pWWZ>yNk4 zeV5i*G04=*pf=>S*FRwVC*wVBCY4Ciyk2>su6QHY!L|Z`;_EnbU-^UAt_z~LS7C9~ zxhU54QV~>4wU?5x5zjvR5;hSMP>vx)O^6y-=GL->;di%PPrEj)oECscx+jMfLnHx_ zWQf1&<8h*fz#0M-42r473tTUqJ?q?1yt+^%V0|tjSf_<+s=cbMJyl--qkgW8Yt5;t z7M;%Sb7boX4I(1rlw!K>+>X2Mx`9TG5~wJu0WLKXk;D>-;gP>TMpi{h>uXbQ;ODlPVHK>V*YU=AJE=7w=>}T`3vdS>3QYg{TV5MBs%ExS6rqaW+;|n8 zI_;F@rslI^6g3t#iWS$=T#bLF34B}W@)30nmJl$3OMs;D(pR5I(pza6TT>C#T6*l( zgBx%BC6LG<5|S>9oABifKL6|s6hk4`yOpf_4SWcNEbtbNg`{F;8}hlD1!j)M{Lb4W zfEX%CUt#O$E+LlVj@h3>4ml8G0>midkKyXoW>ys|hKhh5eioP1 zIAFg$=-G33mkh}XzGR5Vh+)~XRor&#@44>!dzdw66(WtWwg}ZYLJ5yO`6^$3J>5S& z&zU2|5j0*MIZ9u!)CFW(zh$baI$ZUf!_+HhUYv`%aN%NZx#d2ps$xVoPBJP6ZN$9! z72Ni_N4VkFx3GBeGM63CibH9ZJ8W%&K7ID!kb`=9t1}>Nnp&ZvN}2lgbg!(K9Y)A< ziW_u!OYTc3@MEf3#v77w+N=PWHaIjJ1RDrbrGCNVeDB*7LFWvG!PNS4Nes#VXL;AZ zk3;$E6wR$@QxT?2p6Qwjsk-35s5e}a9Dl;Gn4%!_LGSvi8Z>fZ0LxdD@%!KXk^c<) z6d{h! z(n5im-_B;miq#&h9q_1)(lDF)?$xVSlSl+uo29m`1~foSF(XD#;l`WpWaY}$sLgBw z^-9sAA%TXJ#0)2&bc~y;lxT!HuBDieiIXNdO~ZTu=m9!AX;oh{xF(HA@&I7&TF@N; z3^xU}s*nWP&c;_?O?H5$k`ptFY?3~GdOL8+2e2k0iY!k)@ifCnegP8mt1j?$zyU7r z8PKFSM(2+0FkZ&WXy}R6uw>~nhL8N1JMVmeGta!3fBfS`tOgrl^*B@zBRv1y^ZelZ zKje>pxR)_wK4$sKGE5Nj01ToLh9u2fG^V&z!G@Tqm_R{@a!j(1$4}$&zdwcAlogmO zb0s3EReJa7i;-lOb?&Z56+W9V$d(mtk*yz{+w(jlmEn3`=T}m(S`0oF!N&`P@En6~mz^V)+Wo zGta%nGta+4)21PV1|7wq?+s*+UcHDH#}Fb~w{Fb?_uk4qcR#|{UoXenBobtP*O^NJ z&%O92#~*(zeS7!7;8b(8T4h`NjvZ*zrZI~aCA>xNoN>{Bk3ac}C~1kAjdw?L=14Yl zz36to&l;LnSxACxAHD%1LPdEwD^`?wt1ZfG41s<2+MRg3D9g{x-7Ho^MhqW`P=dvR zNg}q$9c)s`kAHj|gN{F%UOjeo%sY+vcJ_QmjULUAA+IxS=2EPU14XXkP>NVhzFc)~ z*t70)Q_?X;5ksUQu6`qA0j9z>^|I&#=S`?J>zy&3b- zCp`W1P(J-^CgQ&b>kuoFBHkSK7JYl|>M25|hUizkIG|JKc6_&Jo^zum726D`tgx(J zT}E;1Mm11tOV+n;jmE*&Y8*8n0B+er@cPDBs=u!xVkg<^%QZ|HO>Ha?iF|>*vw94H zhX+eugh<Tv`HzUaq%k6c|QKXtmXCB z-gWM-=gE~68-94s_c-me6Y1EoEhd1nwdG70_bIQv_7?Aq_>4p{=BXe>o-P+*iTT({ zB_^;~CEaXDHKUl4mRJxW^;eCUu_RrNS_6V0?u%4>yw89}3SyWt?K|$c>j~n2d4eCD zbR?&od;&dt@6Is;598oN`t$L}<9X=8r}%2pB2)vfc^KnguaDre%P*lxX_4!FQfJPbN$!7REe3&(|<}0fUOQ30{6>1TVk*4g&`C=A3g+W&Z>EaoAx8a=-!o81=ze zo_Xq3KKpDAmL!W;tYYQrH8d`bBVzN!29&m~TW9rE2{P?7O{Pq4#G~XrE^)srp=nup>0dPoxR#+NsS^X0RdgRcJpOt`3v`pic4tGGS0~- z9>-C~97)%1I};k1F=GbrzB7UsUVNPuE0aKoYDxO2k2L0g#}b$d_T94^XPt2Z{rc@g z+qSI;45%hacR0`ECTg`KBwd8(8IyR_qnKRk^ijyi;a#~#8VhxBLM$Di`Ti~nTw*fB1d1Nobx ztI)agP6R$CXB@}9_r8GIBJXY{Y2GB{kb?#|7rd73SyBXpUwVS# zk`f{tF>TsZUK#vv{`1<0B%&fLF_6$%Tb{Y2s)Q0F43eC6`ca&G(y{Emdv`)pgh=F6 zRebDDYr7ArW{hSfTT|C+)p!>=qPSS;vD;4c=y3+8opJ)>KN-*97yr$u(UUO}b8JCl zQ0puwAz;SL72I~~6Wo8_)0}_7NgOw5Acq`&00$n_pLuiV(6()>EHJ7LWDx`UA3(h5 zS*ofe-L4Z8@uPEpK$FJBUPWi);J{iXnNZ$&=RN-Rx2KsqZz-yQi>1b@IP{>t{Oo5x zrBCmk7*R}UYTb8RE+Hvfth|3i?^kpkpR9^3wp#g;%DOK=wh=|#4eh?RuJ5weGJE!1 zF8|d{%$d6q8wEM4!GS17Ec^HC$sKpyMC&%q^7^}VKOW7vV7^{;b@^Hzd-Q3ZdHTOt zn_#!y+Vb1qTt&Zq`yxbGf{coDcC1SS5=qPF6DRTSf4$DjLq}jt3^eB78G*5B*FFdW zqA23rGY{kJbIziB*Dl`0wpa{mlFoG{=06kV!~mlResS6Ld^mQ7i^pkz34|jK?!n(4 z_ybDhtUqx@7?KSrDH$qnbyXx_;+Km;+7wtcN{05 zcpTlkcf}aIy0bwg%AI$OP-2XD|0Di*_aiKvzl>O1x!}T6_~DPvrfF#$LqsG&O&?#^ z4H)iOB#DynFz=N+45qCCT3Qa^YCZe<`;*WRzh9izR1cGd#iv0U=v&R5M>Sy{| z-QfL|n+49CmZ^Ct2}39DvAF>dY)*i?p^460->6AgcD&mJVwJTOaOD*@Fy`Z#X*HG1 zI`Q-5=j-&-kKpmuAS5tMzdcatiBM^8pQug{2UU8%+e{goIZg3$_&IeagEcF9lawMTd7 z-DB)4dp})RHQ3 z5A>Cx?{MasKcH8SZW|rh5uAJ4yhT%5v~1>oF6lXYDIG0PLdwf4`Q(%FJoC&8j2Sl# z5l3Tji_JPP^%-nL2qj6YrZKMn_0=4G)ZxU70#6^wWF8g8kW42tB(0*7lGLKc!6EBB zX#8F_ijc^P)Hy3pJy3_C<*>v0v+urp^46R0aPMEAV$~`K5aJU;nbwv{A_0S6ewUYD zd6Uyl8OUj;okE{IdSFbd%qB|HZvcwoF*^=JpBSTZLwDCv+O}m zEv&7y{P)dwxa7hg6}DT$?AV40_Gh11JKD%4XbMJRj2<<{m67G^YmrszWUWOA`112F zNa>nw%sf`t;}daxFjOPg@KTks@+#hb=RGdE=vQ2J`5k;TZa!!uG>QRXy7Vm)MLk6& z6wA>E@4<6V-OCBbA5Cf85J7VIal(V-`viZ6Q>fX@!f;V1&i$qnT#(`SPw%o4v*;bnbDGbtasVIU)3%^6eWHsW>6QfDTcmn3l zou5Ub(mLI#^;-yvjVwyYnu-J;emIIp9(jftGZ&&-gh~;S8Vm^^TT97jWjco#NpjgG zr*QsH&Z9IQ^RyS|7G`HG6eWr*3l}fvtBI3&^Ns)U!KlxP#SITXbT|9;?g)}pC%K1DHzSG4w_0b}Xbtpm5;`CDEd zJcRr2e~HKjs8yeoQH**iuv8jDLS7p-hS%TxkP`+S#JN8_mp%6Afk_+j8Mi*it#!z{ zUK?38!}D9Ya$9Xn5Hqf#B0H9s77)#j3A$3XqIi)j#?OI++L9hxZT=)Tfs^KoIT}f2WyI()V|nzk zXZd{M0*n-)TI`GIQ)(^=*B!%eW)VY73`H@^ZMR*`z+(?53>+avvq;OL5!S-2*>m`8 z!UTqo_<(muO#)&BQi^I*5>*lN=FMlHzPsgAhGaW@=^3e3*srQgpFV>`qKIU&gxB8q zl-J%EL!(A8=!8Q!;;2LE)4Mm#8#ngdEXCCdj$h)4`g9u{+2mD5AdGy{g z^Z;3093vKsA;zFJ4p>>Ir?$!W#b({sn$Ev$Q2?x&1ybp~xq-ys}9K$}-l8u^6$mXj;S{|MY+Cv)?}6nsv0A?CKPw z!UOj|#8c0|OCk}+NPsb|Tv9?4G%8h28n{0PAJ`8o3FlI445N}sN_Z?Wsz?xEfxst; zG!PExe*g#c8_7o>e@&EBj1elzg?|qHkfB3I(zQz~{`%+N)3tL4KW~AnV^%-wVma)H zemwTX9bA9iUCf%j0yP$~86vf$fkeEJO8^AC_S#3h{>Fz48gvLhKK~qc+r3Aw+pnn{ zcT}HKGLJQ=v}@lQF*YqHhOssFl1qdbtf^%0efrR(NnF0Ut?eVCIAyVv<8Jd@FBV-z-8!R2#lydK1 zZ)cBQJu-4od9JH6iumY`#f-5403ZNKL_t)OuSg_IiPTb+Tuq-|T{!Bf{pis(z%oGrIPBlw_!D}s!F?dZ8+_eV|jJxC=`Pjt?_J9MT{|HIQ7(1JrUEg zZPJgoqAlAnG#K^Ng7vikbsM$-GbdoCHrKbDP$8-C$lo95p+|;#T|K|BCGwRY24j>k zW_jqZH#1-e_%u|RGs8|**T*-A;|CTSlT##k) zx%sVLmz}XTtiN}qaU;0+;&VCm)F05YMRQam&n48X!%NcH;HL^`yP0TwdGFT#o3a+OB#|lP?HgEb!Brcn}$5{@E_>iYj-lz2`S6f z*043iI>@jFLK6~Lup}K|rjja}0uST6@Jg)!c;J9tc<7-&IRI4SxqvSAXq^J8$0Na* z5Nnl%%ggwB{t6bZOrkcVZSy$$^lU+kxFOUeNpa#3t`CS1S!Kb3Mf~dWTbMC(5!Plp zim4{60U$Z9aq1ZwiRjp|Dc4+cDTf_)2*t&LJ0Q|Ys+t_Nnw!ss5Ufd(RQT$v>D+L` z?aZ3HI%i!u-e`g|PdSP!e|0I18$pa6hd7XWHKVtd<>V1m>X7EMRwQmVcNk`^XU zoWgs8^ua816o;eP;24x%YMxV)ha;_J+M0uK6sD2?i{V2 zgE1D>Bu5;!7eBl7r}XLD%lp$wmz8!`=@J#G->PIchxcEAAiBme|9s8gz@b^wH|J3wf{B{hE-g2(HWd~-dQwn-q@*Ai%Z1VbY{Lj0Oea0 zsI%@=)w#db58E1|7WHisVr$&r27#1NXXVU;>jBkF)jC zM^h}3Nn%AvTH&2{NAjcdF6D(6-toc*nR?s$uO>$d7Kym@XJ>KDz$4RSWyzx&BUo>( zCVh;~lbVgNY*iUEX3l2u(&etnxrtCo_&p-E;BX$&_c|AE(rYS)%vWcomo_2l$fDW{swAy>}*8Ld| zcGY4-T1&W~W+i}NHDt-+DQ#CY=ir`-~w+10M_flr@$}D z>c42Jxe2mP08BzBG)A3gcaTL5yp~SyC$e=ig7#rd26{ zx(squW4#!D^~)Q1f7EoWCS2?=6plQo2M;{(hgx0Wh$JhPujTtE|Agf$@xl#mevL_D zHNkPm9K!dGKbpRK??JmZEh)wjNh*n=IqtNTD%VPL!3uuzqhGM_yUILW*>cyo(P|)u zVoj7zY8VN?2z~qR#Q)v+EBf@_4WmL-v*}4Kz$WXAr*EtaoMXx9hO4t|>q(G;1(_w#inQ7+3FGlI32$OKr0z*Yl6DMCmRN+s7{dlkEM?&89k;mq!x#o{RF_8vXiO6mmpG|klw&30ExP!-v zn?11+Uwko(pZw%HuDa@cPCfl3;_;Zb1TCU5P=l=zXC=?t(`vwyDwl~|?-w-~6Z#}v zCcL7WaAkigYzm=1sYBv^^VozN-yFFBfVEC+jU&x6_`;)?}1F}JLgUw4fD!Rs@ETW`Jf*1Fyh^Iu%v9iY+Ek;<1Q3Zoi4P z?c0LSGD^CKhy%hXQvUU?HyHZQQCM4oMZEk~K&FY0@os7oF;$#!+(F!U!J<>~Jcqjc}mmg9~)I&*?Z%|uKXg!J2gKWtRS)Tv*)J}7DsoPetk zq}8Y$m>ZTXUrR+4Qqrd*UckqnOk&7C zUnd^Io_p=-DNXnc{kr zZHWc0m8CJzs8I>6TDGXUVM%iKnJ2J&&)p%AoD$NMi|;_t@YTc_s1{?r4wQ)T#i>;w z<#g{7=Zect=IO_8=lyqI;?6sML-+2T5sgw+%C(+`)@si0Az1=Yfx)2nq=Oh@0hnbV9M;}M1&csvNT1~(ruTW zxa8uqTs&2y^jWyxf&R1(q`yB4bLXw((x3ky{~r1VRY^9YVSLKPRmP0{i2MHb0!XO? ze+^xa6piulqk|bYZi26gR)T^)OaTBl0s@)v=>%4+Okiy+4J2S)Lv0nFd+{}vELjGs z7_CnLI0X^nT~13`*;@Ykm;3n3U!NzDEGF`$Y_8m`ZkOoIw?5>HFD4Ud5lI^|cIH=OJ`Z&)#dk2?XbUYn9G{M>gsWQHRh*s^}kqF{U`gR$s z)+SSTnG@y^qn!NxlW5*FbUfb;G?`R|R4!d5a@8y^xPO~XGwMKf=#bY?jd_q)QorhSZ)3du_W%666~M0$1FR#nv~I6hm@{hu8ad8g#uXGI zTmv9Oz`_L!*r{zx*MCDaH~9cQQIR@(d~7CiLFy&Tm+|}G|B2xvrnzjcL|N-LsAV(w zN&pp-k>SFh|C(ctIS^EM`|XchFI!(_5+JA~xcGuI=-8os+O_vl`>fw`Zml(z<4+jK zvgJz|_t8X-Jn}&L57?KkT{}}$90N(XIDD3p3clw^Qk})&Hf7}Uv^K;Vn7?2lUw%1- zZ@!)9TsZ|uAR6%T_^I6Y;6K=>UmyDR?nR3x#l8!gQ+YwG&wz%$z87NNl8QBov){hG z*l*uHTyXJ^m^NiPAB`Qy*sfEL5zgz1ZOEYy8b!^{?ADwqH z_y27O5UWu?UB7i@GooMq`hv77xA63{Z?Jgr3a+{C7qn>Jn3Q3ym^x#CBB|rpkVpuh zjGOEmy}QI)Di-TfBmpBwe@-G{35rafLdI=3s8sbmacy1- zkNWBoBkKEkKzT*PxQ{>O#TWm@=rNxWsd0UUBjbNN;nkX*V1%_v+O}!NMHijJph4fG zW%I@uthc%qOMsOSD}vG7Mn)pOzpfV~P*qk{33Hc}F=uf(E7n@91Pt7(HBCxFiVPTy z9O!#Ni+OXGaPlb^P+1k$$VBJ2_}2ZrjM%irX?$b%1N-;nmfLuqrj_GaEsJ*-`*ls07(EJ}`UlyBA88 z2d|8Brw9Z_=+UhmT{?G4%P?u)YKly!FJDc|H?!t(#jmbs-1s>}Ndq>y0WO!z+Nuq) z$rwTjsWy*loJC^9a@r~1W9OZB%GEOT@uY12n@E6YkyBYlTz_9lASQ_zU*4vYmoq1r zwCq<>L#9oi!&TS(hRd(G!)0!x#$Zca%Yby1LrPuRfW|OV!s2B~?)c+VoPYl1d_3+m zlGfQaRsu&nCRf@klVC9f#C<%>soXRv5_)xP!uR^N zggT5?anhipiG{}N25x>=xFIW8Hbpf|0RZcjd{QEMd#SC`+!)EUc(NV?<#b_1>FRA$lh9n`gzw5WH<5}YvT zn6!?AWVuZF?^`laN_CR+PBGc!#2#x}D~>y7HRPj@KI11p{WTwcG@FP-P&I$6?;mG?*GfC7Iose#s^Uw|ZWz2qp;F zd!M~%(bVwyXP;3~UXDlwM;+dWoBr=A`u9H|(=9Beq@v^~cchCE1g3vIiz~0VnOSqn zu!;wU)JYv=EJeu%qfFP18o{A-zuZ)FoeVwBpzPhJ8y8&gV`4GM(B^8$?B`mBIsGol z7Jv|_))_5B6gEUCAG|k;E3dhWH5J8J8(^bK&`Ojf#wemerc6+S48b^M9s6gmYOpE{ zANdhgQ5D6_+q0rvSzVqW5qY7lFoqFBAYQpfvf2gsgv8op#FROUDQ;9s(=bWf7LAD+ z@xrE3Jw`$E=FRzH!Z_y7Tj}T9I^ughtdNxSze!D{N%i!Q^g2)T0zBVx{J60k(Ek9M zHfxf0W5o-#O1@q(#?rJ|GY&p*f67)ZV%oGBL{T|AwQtP%Kl(mbUU?}kTQ(z|%TdX5 z*fp&Co90}n6Kk1f=_>01!MO{o-j-izg7vHA-qJBZmD*0p?C-K${G_mw$rsruB2krO z`LY$1l$6kKD{{rlj;N~%$_xmOE0^Qh4ZUOSevI0u;gTCRZ~53A*C;! zZ71fdEls-&#u5tL`rBV{^7oH(u_#kbK0R;qCR1n7xq9>M)HPUO+O!#5aM87_EDtb2 z$l0eH%6aFWMyr-B`C{TkuK)ENtXvWJ>#YKfVNKocrZEN^Bsu@mpR@Zu0}!K_$d#@Y z$AlJ5ifGlWgqF=3Q5p|iWs17&wMB@67;k_4HD%?>0o_{ArDF>MlSwv3u{in1p#YyiVv_Vz4D) zQ6UDnX)Hw_z_t-#AQTtJ>9A9Knzw917!zN)VQUZmq(uRQ1q&8()m1k$e_oaAC6O=7 zD82+sU9GK}hy)3&No7In-}Otxkcg_-XWxC&Egd)EQNh|(tGMHL_ffW{F~$U3{fpE1 z^>vrCYu666Xc}_pLHlye)t7k7FJ&3kZ)1j5c=g#AShIYoo1Rz^8kVru7Bg>!@cFC? zMtr`2Q4?n~ZT>P=R9X^&Yn(0`(WXT+Rwv_pICUk%#?N8ls>-yxY_k+&QryZt_t_g0 zL~etrtcQD(Y7gq9#(sR>4{9+8{4>U2tupQFg*xU@qO@;c%AfDKhQZJLiOYX>Iz>gAuEnh$7_Q!fRy;HQzyo^Iu0z{QPu!g3 zNxs+mFKSmc5%Ax){>Q|rixCrY#)$`W-nnN}6vi+b5)dbp7`^-SB$24hai{CLrYuvO zwX4=L>fQem^Y0C9f>09#Y6(;kjkA1h3Df6RGVaR-OqjHoWvdbxg;q`Cgfrp8V?cc5p_P8bu^u;l9s)VqE!1`VNIyQX~qq=8iVUcTAi?-EIZ zwW)tM%=l(8*IoNt7A#my6jkdrSBpC+MxB16Z(5bM*K3={O`S8$mmJ&LB)tj%xIPnQ zb6&Y(SOK;3k1}z&va&VY@%ww2_{CBulxY%qGsU@axCFP{b|uGs?=S}Jvj@NU`A@m{ zf-|YF4VV&OJ?NnQiN!)TB{fNLJ#HU;Vkk)?Sk`j(8K+WYNb}!P@wo36EhG#{t5;{o zrfO>6Ly;uL*9Rvh&XO`=+_V*ZJmoveDiy+j$g4`P zp_B=8*0NyPn!E{>SW&>y#~hB@+G3@($BYp{jdJ{PN6~rb4h-0L*PMp+k{$e3Nn68_ zRVGiJ&n-9K!SWTW*Mp3m6(!c7Q24to0HA2~m$S68Ut7bl>8`)t8CHC^pUf+-<)RQp z0f|J6d+&XS_eM^l%0?vBTa6mzeGE3RsEI%m?Ao;pflo>Vp|VfEy)t03j+5Q#{wclo z*qs0`bea|}uvzZ;27;ckq#C5Fz?YMzF@I?p0SWf++lg-7c6RYCiBPIYN|Hs(SMc}~ zgFynXI<2+(mDxb3s;G6cTv1gOGbT;M8rOyt37is321if>)`MeGVtls-zFkyKNh~BV zZf*jFh+-D6s>thxi;dWO@7_dI5)tIB-Bn3FFU^z-nh;EkAcCWhJdBc(80VaIB7sC$ z34L9SI@N3u)Cg7#)?1>gFz%CS{N>LNQn5AxHbU@o<&}aY9UIJTIiPACHD)vOaI^QZ z@jBt_6FqnFSgn(jp>jm@#8I z^`)7+7?h=R=T3Q&G}<6{o~fn~zWj0`K@h`;GH~Ew#NshWxb~GQlP1sP`s;3H{HNd4 z+G?}Dw$2w5CS;P0*&($oYbevH%?BF9P#iC!aid1WVj-b%7V@H{D~a;;tw!nEtt*(w z_q(;VodkdjH#qTuB!&vkKleoX_Spl7IOf$#-(3i9}aEO2pKOD=w_dSPAsW;bagBzFe zH6gd&b`NjAJ(4L?zv0za{=>cZJ>>zi9>H;xZk<}ws#U9uYewzr#@QZR{h`QrvQy=M z{~PTpM>L{O-`-9XLfmG4;DNt$*4e*g%-9*Im5o|w2AK5aRFdTt^$WP?xYf@2EG;Rb zacP_|fYlXA%9D9@t7+W02?zAs-CNI6i{)c{<~Kj{M~h*K*a>ml2Nzh*+95 zE#@zOxr56uIhA;jM8t`>IHCeEJ)KMtRv)F6&5Zk=c;S(q$+7$98Zn! ziCvS3Tyqg9-FNLmyg23>1JzMxSC{Nl?T1~46kSoCWbWK$s10b=EKa8`JEh&U*|X;H z_*4HTX^WkR>IQ~3Gz)YR<&{*GS5Q)1RG%H0(Jmy_3ppZYl*WxqsVq;jvZ9Jcjbl0Y zsj9@|F}nBY#z&ui?SxG896W(ozBlk74mqSBefsQ9m(DxUxFnttCm_Ix(xzo|etFr2 zoO;^#`E25sO#k{DKKyVZpMO3h`|e0(g&jdV#%;g9kDWWUXTN@Xqc*v|C9hl52teyr zPTZkmfZG}DrFUm!Evr|p;f~+`k>$%>9}7f%z2Wglff)Mq z*#ot{;zDaKz?u|9N8wE-z2Ih@+0TsYwsvhf6%|Qrq_k_(oW_kBr|CSCCQTw~Ln6&q zzTTLb7K|~JmzC9XBPvE978nAP>A$SLX1Tbul(MyzHQdTnSy}h)UA-u-)*2xytRwa$`GF7fkW@Tj=D_1RJ_M8RGo41gfeVa+EXk3R-OQW2 z0L_Z7Ndu@NZv#7OlZ_q10<7DD+3-hGy(frc?I%Gjkp?{Rk7pS7=^UrcVJiH4>UVV8 z)Bxx}7r$?$H1ou95nWZmdRT7?ty?z7P=z5(H#Zj*N8?ce4Sk_}M3s&B@~bJlH~d4s z`eG*g^xK0o&pL(nt($u*s`?RX9k^?NRZB8TUk@|BW1twd$Lb zQ_p@X`Qt@_FW}eE)LP8%n$+VZt_+J7%x3I}cUiMyHM{oe!>)VoO^a6TP!Ytsgh5qg z(w3ofOTFTZP0+e!GsGHv2)E{l3{xi0W6I>Y7-I;E;Npu;(a z$fHj(c*wg>q)R=$Cf$Qsu)c#z%3U{J*kRs+)!cp0pSkl7zoSJ-+<5}2_M>EYsQCn1 zx7gm(2KZd+Uh2_@xB!4#G??qMbgD7lfA2${er6a-j13A#i_Nk|bfeD0Hf`Ft&6JaD z^{D~>-)q)Z^2sOTdFI&{_;|t$CrCiRr(aHC>g37%_0M-xR3vp;nx&sue6D)q^vRpO0GYfnFk z%SNtTvY3bO{xgYH<(Q=M)kl+{_@5kjIOcaG!L}M)r{vWam#x%F3B=-rBtG*OM@C6HST>;t674fiYm^)`7cijE}Q53JEI;1|)lN7H_YK<}0=UbXK zX_8BpPKgx|P`0L$k?#%X$tMRhW!ij@ICv!)ivy|HVXYgp4%F9LtLU1!MjnDMiiBn)M`Pb@}A@jZ?O^i3A_M`#vMy9>Jb__vL_t52eE)`=Pe6(@qvg6A~XKYSOf+Z)u?QT5B39 zq9Olz{R2)oejtY(eh~k8{cS#ehhAo{J^Ql%0sCMi za`O6WY7nN=y+*gQecX^_>IR7cZp(c^8**3zsuGq5?thr2%PUbfoOmqa=ozhAHe*B7 zVY0b%v7#^omP%S>dCshPT=w%Tx&Hs|WAgOxu*9)8@Klegbo@?LsI075XWY{S$`OYj zNT3GerRdQZHgYanMyY1wmYt(bD}DR!L9C=WKS*X_b9vbs1R*j3Rh}2<*d#&`0aL!1 z%u^3N!oz?111ndSrP|SDEM--Si;I0j`}*!y>zhx-`S08Bv1)B4L;mGG0$*1y^*)$W zRVYp;(JI_|_kDb~WQC)~Xt2?9x}%P*VAiV3!E7t;ZvK0D`>p@+&i_8as(29zS-+|9 z|5W4p_g-?zITXcBo&99%I)GFyL10oMPmZ*!PIi9Ckbm*{m$QMmPts&ab>8+wP};X? zO6M+}^46B7R8LT+ySM*-`?z+DfMX?lm78>oYQvKsBB`d2iW=y(=bkyVlRxC zcik21>2pS%;Avp9LIO4-KpFq(6#n<_dp>Dl)1C2*5yH?A2FB|a)@84!QY+T|rOJr+ zKVs^%Z<#oG9+4+UIjQ{m0ifg4`viBFf%JdIf6ILWl2s@HO~DdMpKi7|Tgc#McwZ}wg9P)y+JZ8Q39wXY8c^9IEbsj{-H zl2M~3V1m#G^sT42)O>FF$^cbd>dGQmbsC2#y!6srj2<<%R`K0zdAZG9VX+|~nEl#; zEWqu+j5da3GRd<~KhLU_7WFdu8>%KOKp@b*bu+qk?ZS~q3;^C&cTNqNUPQ@F%mhscrvAXb=DnwanmD@IG7_3-HZ1|PA08yIUyK{e z*fAeFi8Fx~O^Xi;iX5JGI<)!n>6MB**o(%xyma2f6sew zRrQv&vo9n-2m}IQ3Hwe2R6s#TL17&6rwAj+xWIs@ETRrBj0@tpFb)W^D2wbO1j3fE zLs$|Z`<`^VlkRl7yQ=Pe&+m`-y|=2nt2>>LKv3FGf7En$)vbHq_q^vk=Q+{oRgKsyovF<<=RzcFag04HesK{IkYDuJah5m~+ZOX>Ul(6>*rv~tKBER*+~ z#3w#^1Xd&8ROlgCmMLa<1$XCwsg}ChfV2MJDO`Ka4;flN5F-JB5l;EU30!^kh3v80 zXlzjld^finUR2iY1?N82+`56-h$9AjVzoFViDC5vIsDKA*=x!qs%tVJF(#pkh@zt1 zY&_{9*rX#|2xE2_&d+}FU53@?O7|%7AdxuDSjyFC0t^P@aXjlG1Sda+#Kb|&ndhFv z*qwJlRDEyM5U9H!uGQl`OQdAn1Q|C`p{_L%V~NEQt07lY$HXZIGx@-y7&cUChyPCp;a7v z?4cZS*#7Lk$8HQAGMG>WV@PLLGX_39?GTPQbSm@aFJ|`a*O~Fy3q1S$916v#;$}?7 zq}DdB#Ug~>Xk5#()1-^56*sZ%+eug9TvdtLZTDUI^>41?q6@EJ-hu}Io?fRem2#4@ zdnqL;`LfeO#gOe+$Cu7OkDVv&PBD&4CAkASaGcyBT7xKXHnax#&w7U>3r|I4YG*$5f)=HCgSu@f0TXq+1nGl z^&JrI-#<9hw%{9Yl?Zw^g@W68^Z>%TYUL0HQ zyYDF;c;HFmVh4Lq9?z#g^$AY+=!dAO%VJDYW*gp|yO_V+c?W;F^Y65`2cBx7n*tel z?bSIx`!a6AVM`CMK1vR$C`Jv&Yu62}@6QDn{Rby~{G4!#m4AwXy-})N;`sYv;o_+3R&OYy3w6%s9vR-f@?p0JE!F?v|G>F@7 z{XNxT1}m{6CaYBZe7y(23U-{Bvd!o2gLAKQ8Jtl|OiUbjXFF?Hv!;Q0^Oo?ltAE41 z`7LhbOd^c2^cysQlTSO1`cY%3?mv)7GQ` z5<4lQ1&g7OkLc*IUYH>w7DH?@jOiD1?36JC5_Q%c6d{U~^Z(=9On>Yxpy>resqS@xgubMS31`{+cHe`Qu1U7TZCcq5VbgzC6=dFhSGa$s zGS^WgEJh*J5JTu4#hm@5^Kun-7&DT~F8dFxm=fS+i+csaD-m;( zriiAlx7Mq&yDqC}Ob}adH3`<$Z5V3^R0u^GHGBw%9X6FQqlbctFs4YL4#yfaYy>+` z-j}L@^~6RHjR|c`C>9BwM~Wjq2Z%Ko6+|*bHlVctYg+THUf;onwwTBoFyhK$wPa9g za#{M-!@;R^+9ZUt__d#w`}pEkw%l zrOSbLCLJOO#tOz7j0PArSYl#{X>4B4+Y1)5p{;^2HD(2ZV?ynT#@MV2)fi zARs27$iM;B6*q&3uzcBaHntVsv!;Sz$QZ+62T$hTK7R(1C}q#7&N<*nda} zYP-Y$H#e<)e`buXuV`avT-(CiZ_VSNLk=Ja-Nc6}SK|;#)9^FSIF-c<7jgH!PdQRB zk}8b!ltHU1MYSwhv7SYXmow|xSHR?Y-FubDv&o2FU_$23nd|0sQ#p0%^D{|a2V&0$ z46w1Gsc{`I&3=`qpL&-2?|+Jpe9TTe4&#a|E@aO=cSDFA4(KeMD&Er`NxzcxH9J#$ ztO>|iW%;}}xb^x!uyI2xSY_C#5$t`yL5!ccJA;RhLbDlSg+js7m~SJO38<+Gsjkkr zK#8S)|60t(cH(@I!ToD0&N{0a=Dj_iOpx8;M#Gk7T*pWG_NSXjDj4R5^mI*-qIibo%NfqWF8WD#-zELhUQH!r-L8*ls{ zhSv8ZwR{xYhd@#KAEJ)7(iL+wYAJ5qz^(sx9UUzj9TWkqTfU0vf4!SR{8#FS*R$8u z{g^OmGDAj`9+)y}N^| zNx3?BK!zXx=rTr+9_H?m$&~RNOS905n>hL3-~W*{s~h?8Pxd5}-ToRQ|Fjw4`zzb) zjH4ymD9tUc{NWF`u&SZJZ-4s-F8j)zHZB(L(@>5!XRZh`o`N@=_H) zcyB=?Wy!*YJpJSo+Fw;BiCo^7W<0N^0prpfL@rm($+ThEdGABo~LKdc9>%#kD!U@ zLD?aL?Se3DX||#zC1|l!=Y*@Sx|CfePC$$;qfM4uVLD|QRm)?KJ;iN*ei&;FbLPIu zo_p*V zctE;jd^g#aWk#uhXG~Q#OCZS@ovB>@3aA8F3q}L5*3VHp5Z_6L+D_SFAWC&r6{^P1 zG+QrU1>&885@LcVc5kN)LOUYYq6r+x9?sUAEGOhBv!Hnu@q+XnJ&8)<6VKy}8D z4GclxWb`eD=V!jihISv|yaatBErv<>0O}iEo%Oi3WVI&&H4r72iMjgf%h~_H{rwM3 z>gjB(bw_8Sq=aGdqGf#Vik}h38AL3%-F`c}?Qt==z;P?BhDaBDl|HgHIKhcW6 z)9Lf{MeJJMyBPRE6Qu7^k+zNkH{5uK3tkpPv;5$P*YM_B3y4&D#VCZB@jH#?XFtD! z`axNQ$dAN@y^2}7uJAh`fqE}n5yRgfd4e@9%CZ(=QIjx#ZOmJ1ioCfx&-@j67OpO` zsL`^rIizW0mM98&_~FM1q{dNv)KokytP!kHtg%=VF=h81m^g7lIeNFnhkm!Nr5Ngm zjbOs0ov@Oan~UoPYmz@oHz;7;$_C~<_Y4{9gD(L>2wKg$4FPX0EAaAyHfGJ+$dhlj z@YI}Uo}1gu-48t3E$wj)9w#gqm?AY*5&fzK(a4X^g()RvOFp#=@|LTwzLY}_**`6F zl``qC#3Pu<8B%R5@{_BsrFng#Mg(`?^C*iKE@6AOkb5tC(jO>7_xT|SFTMOaufMrE zmAg_aw6+SDUV0VlTH2gjSJ!(Xo-=3!6DYe*n#i@k{sE&$)esmV~8Z7=1BV4(;%oZ%N8$mT7Lu}29*L<@+2{Kq6!Zw8TZNnPHbS}uH*Q{FMr6m zu>(Piy_sEYjl|WN1F4c#c;khc1fDo+jT1buVlgTNYRQpjhXEn`?>v+VBWjs4VI)Sa z&w9ExSzz*{L0o*{Y20?pkGc7lUvbu#PiOeBL5Rk#DrW0W1c}G}f_`-z^pTJ9)ypsE zn^#=I$4@<(QDaB=9I5*ajYY}TRih>~szkk(j7#PeW7TUIx@OD5IkO>(x`18|wyKQhqj!%B_B=()MqwlnD{%1Bu7+PP=HP`$X2OPMsmm&)~y|*V_mJU`M zGUL%%{O-4R`BA_UHmEk>Pk*|Ljje4-J@G*fxNR^%huLT++QR##>m=PV2rcjUxzc0N z(iJ@N=*wU;o`@?c4Z)(^bj!o+xZ@7|%co8u3`u{-bO`_kM?#*k%Q$}V>mTy%Z(YgD zvzPnwIdb<;OCxTTXeygSCrbB;$KjrQ@L>);<~Xtg2Rd~aTy~U`JVOUoGiKNj23BVX zY(yL=Uq1Kq%sKxuHndvj!j=^dIcN`#KKc-*?7bIbcN{||5JI&e7E2K$86+_2^_g-d znZ%$RP>B(1T~L!Eq5*2Hp97975BEzc+rTPe5He)!4h$PRj)RUlmWDN}ng8bN%$_xq z#q*Yukdvwh_T$(SPb3U28prs0y#X_6Fbj z_D_l8EGk8BKOiXydR4R*wg?4}VTRc~(rA6M}+QF;O&*ac!K7`RCwK>D! zfpv@;JeZnXhQQ6WpvGlV`|P(jH~jIJy#3Z9YHD*#+;wM$4z0%|8L$dL93TnTPn?XD zEz34K!R*OUy9rYeUNu0m81X1qDi^QajDu7vK?Y7TUIhk^7(xB0k?eouk*r(2nx@sO zv8s&QX#)KQ4Z^CBQz2Hc)`^r_Yf12^v>H@niZH7PJdM9U{ z^Z%&M<@nnJ4>9YRHxSLG{vBNq-K52pt~n!Mj52kfow?%5OBgX?D5$0ogNrL&SqVyv zW!bU@F1+A-w6;a4lz6D6#=Gle-*fK+9CFw}SdA)lB`S64^&N$Q_fz)x0S%_&J++-s zf{yk)cir)T>pZ5?@ZHe^BRMX)cUuH%Lq z9!4be#@w3@c$*Ux%YX0hciqh=KXMe~#}B8rD!@og#;P+j60fWxCY4^=ai<;FY3FfH z=})~%v>0z1?zW?wLU3bmG1_fyTAv{pBi@5oi3+YpRx1vB(-@6oLh()<*1Fu$>o2N$ z%CE;DlUWCYl##XF6pjtD3>rR$AtQE3A60BiPazQ8I9yQj@^yysO59%Lv4`$=jjD>o zCiR9%0e|_+45mLki)=Pv)tVL{^ivp>Hl|-U-V9wN#z=uro-&QEo_`Jl2Gn{iv`c5! zhJH;(X#icbwu%3|@CsI~D*9{6ciYa6%w(AU=(8+ewu-T1hJLWOw?zOHAj0do(Ac<+Cm)-^8*jYLx~BEy3wewfOkkX$xW@#I5jr{|X3t*WD`IE)V>M>! z;-&oV=U1oGG{(46x=<*(hK^c-Fkr-}k?eiIL5vwUp4fz4fNdd&C7my}HZ`bAO_ZcO zLrcYDAw-$`$_uPovdYCx=`R0}C>@D7YD{BO!8Mu)y$4CssqH*%<1$` zvpD$^A19X$9lx+_{gukzQt52tfOSpHTyn_|nEm<+tj+l5P|$tJ`1dR14KKa$B0G%v zXnMF;6h-LeK;0IeyxT>tvo+LUT(x4~mu&OOPIPezNLIriuKPd!`27NalQ zIxh-$;s&A&8Jy*sYp-JW-MgBJ`-PNb0m1-7B<^KpYA>lWu?dJ&iLA1=rNG*Ctvvty3*7ko z8(6b)18Os68JXkqC6fHcl(0Z&GL)M1Iw>o0>d8UuGSJuuF5_`SJh^9zMw>{EnM~8%V=%d=$@!_=gAq*KSW9< z?{OM%yi}`7xBD(e5e*Pg#*OR8WtU&b-c$C#h|hG%`ZXDKd6vdye*(?xI=J*ZKj7iV z-b5w#;s+U@fk&M>sw#>hAV4{A>NtLN?N7<%x+=z0SpT-WnN>v|;MUsjiF@6a{b8qn zsS1M4QiIt#a#*Tm%=CYN0H}gU5vxjDhv8G7I+LYKHuuOU)-8y#f8R{LgQG z$fQZTU`!&fZYm^qrqgS#Ti48Qe|G~n-1s1YWYb2BgPt77jb{A%vzs3PZ9te&PWj|v z{O84Arz!|i`TJ52RUuZ2Dikf`iQXMIuA2 zp{Hq30{YATyK9py)y+$a2$gg~MUw`VIOUea{X^81iOIysz@bCf` zg`5BUIQ>TK#2yD8N+42ZW9d|B;z%h(N`w$68C0x(k|Kwg8rH8}!T()%y|1`I+ct{iQlLeF)+M7%cbAFltT_Vh-_fcmtt*-uo4Mp$WKL5M z001BWNkl|d^fSjc zcAe&=ap0q53QwpNj4Dg!FJsZ%xoHX7QUzzq@VxXkNo_-^&T;0GoFZeD`&ssuM z3{V^QdJSDmMAxt}Jof0*U6Q-FPa+i`G(rAJzpS-9_UIG-nBFpz^B8Dr7yje?%eeB& zZ}QO-kFC%c>3(us4Z$d*Mi1liE5F0B$34wYul^0omNlaqc;DMigVz;LJ$20hD>1fh z1AqV14V?C+a|mmyeFxHZnq^G}2ogs%ydbKLW9Gj(hrog*L`{qk(Z5a@F=7Zo;2SGR zGE#P(##C}HbHC{R&SjIa!iJ3j?Rmi(OB~0vwRVti+vrB%JV{-xvSQg1ChRqZSSlPd zS}7pLgksP_p1W_piIz3%-g)tm;(dTvcG+pycIv~>dD`;Gg&$t2v>MXOdd z@X{*_P@C&xu~`DGH4#uyCsSlKar%cj>&stE)l;;O5>i^8efttP0$!Ta zz>?JkV&fg(iba0+^Q&oExi;yLplVsSZoN}U)=EkQw%a`sBM`?tbk`lc@zNWckql|K zY9UoG6v1jl|60R2U;Z2)`}m0r=vRvnxuBPDGW|i52s$L$t%zbZ1`T=knHTuZB|lCU~kAwii z{6$MB6fz>vmGlt_F+&H}aL(Cha_sRR;>H_q;m+G1^8{q;n;0Ng=qxlU6|xjt#%^(><0tNa zm_hyeap1J$h{ZVYyxZuMyFlln27$HY+Y^%@ugXG}FjGY~<7ge$TV(cSeOo$jZleK# zDH4TBKFpzX5EGCKgqzCcOJk&$Mog&;PG%9^;IcK!^DoZk;6o1fN3E3}cS?<33NzVPsH<1KSK_{pXloR~Wvh&V6@a^whz>PQllxfrU!kD5Pv5PWZwIwWjjlRk7hgP}!&v)_M z6OR&jW?xUKzLZfSY;OyDGl$|U;%P_8V>^ z)GgUIPEAG#5eZOJ;3FTI%5As&lJm|zi_s&8^>I|uJy#VsRN2(r#((|S&$;}HUtw+F z?L4AI1?$~K;*wD&N zfBGxy))yU+--RAzeO5I4)n%Odh4Z=M@(VfgsKXptSRxVyWvMuw+V;q0rTfA;_}O`;;H z{m`yrm+6CXKCP#md<5V4&+`~uU4^P}^pS_~rL+H&#&rs@sa#%Ymey9~YhV99XZ^oV z^RNH*8Tt>*_KGqj>(r>ED$Lo8Ve0-<*lX{}%zot+Zn^nR9(;Hvp{ep2gz0q3_q5<+ zEP-0Galjon-Aa4gMh-syM6B(+0HqHIR5HdY$U8@u1jHD3kd&EYYsKegI|YGG0ul%z z0TLB?>FFoA?S@+rYg4rx>4tdrwmzI;{fCd=pVL13X(sP6iK-v~Eh1PS_)H%^o}(K* z__v4o{#DnqVS{ygld0a{*4_Mp$*^eQB1VrKn$EF*kO6L$ps^JPs^8soufjjYELyk> zH33k-ludo4rJu(=V_W33Q~!m2)m7fX%rbGeojLvVlll2IcXoS=lx8dts{wNS_PRTH z_PH1N&u@K=-6l-{iJVSJBC@LGeskrdUgscZ5ONvA)T#Th@4kC;*1Uz>bI$|(`HqL! zurZI(Y}s}LHBLf3)obwo9^=YGW8uL&?xkV%8czK583Z-8CD90vdm@I|Wc|#rafz-; z=1;}jfO_Q<44Al+im>+n1k$WD*1)SCE25!msECx2bz_`wr0h7Jfdm6@PQx@D3Oh*stP#eghTkmCr@VA-F73)7|s1TR69uqed_5WKFib&EdQp@O31Nh8oCv)U6N3z4H;jZT^l4|2?s{2@J?I(dK z_A}2y6bsMHdWP?P|0k?k*#VkGHNs6*JHcJb;+7GM#DbFPbQt!vtW1R>FuXkbbz)1( zL)^a0vCh@g)-H#)N&x&vbDR=Fo_p@aUJJe?5edSO#~**3&wTciSRAb+jw~~ueA-JX zZF;Q=>I{f%hO2(~dmfwqBwzp9+3YrHH^gUEnz~W+e!ml46RR!@@z$G*-FTOD=1G+r0*UKG zz)!FKJz*FyZQ3;2+uOPC-ut-s{+U?KxJ|0Pmj|jzCTM_=S+nMH#u?}G)$_l=$)ET* z{rcCDP$f21Uc@QI)*A~6RON&zQzkKG&pkNv%+E1<_Uk06O}YSUDuSjh0bAN-a}F8?(G( ztfrv3-=T$Kj-USYdhWja0lxYlXLHcO2a?Nl-guR|eAd|X^~5(zj7_EoltKM#IQ-E4 zIPCEK`S-6jGk5M=Jo)6)+v`hoIar$^QiB*xU*Fv%Q#M1~xv6yU!Bg3J!UU{FsLi|sI7|tHENj;^ zFmB99HRUcNUt0*p z&$0$CKpHPY6^X$r1nOn)yZFYXucVYj5Bv=+sYIJpj}K4&HW*ZjRL!>Olzm{U*t7sl;4jzD6+Y0C`NyOqbPgV~qRki9TSZ`=xz)rsAswb&U+MtX;dFzyIw~etGTnY}hDRvZ%G2 z%pA*W4aX`_!cf?Cw_O=FXb?vqu@BRqn$J6xtzW%*RjRW6-rHD6??2LQ6Z}4Cg7k35 z8yXr>>jeks8E@-Jr>s09?kir=_4PZe0lT?dA&e;?_Xw6Wf3X(5xG+92$gQxP+y*zN{kKipjjFlTKN0l9_IJIzm2tx9YBE9 zvd(fJaJw|P8;c1npE~6@h7BD`1~}n_V|nc9*HOvRdE~J#*XvE3RGBkpZkZ>G_KHz| zPy%no@^X8>v8u|_B}+@2A}w#W45;nPXRZ7@T80fuNeN1`1`lLFzX5)%t?W`mTmX$Mt5!77(O&45dF{IM5Jrv|0%&R)UsIRk z#FIYEQAZq#D4vL{71~3TeMT>wiZ^%n&v|o7y)-CWVfpH{JpACJT=)AsX=!oIq|$Yi zfA{Tm6HaLuDjz@Pq|{I4sH2Wx;)FjjcixsL*Jv6ES1ezNwVL?i{li0BJ>KiBp$J{k zU!Y4F(uu{dy4~=Px++3j3zuE`L;iaA3&aX)ivII#u2QXK{Mg|vTG{|zXbW92jh^nG z8?HBg*4SlM4)=4i=`KWBkPbfmscC%tRIJVx#`2@?c< zbWT$luD~jRRqng}&pbK(DQ{S$-Y81B^0Kq}_{UF3NA4^ZHR78Vu@i$ZrjsjO3MO;{ zw;axz+zV?;opUMwc{#o*T4r}CV1-4C7W2S;4{-g>53#W=@&-@F=?Z#z8PT3gy^?Nf znQF9vF%}~QF8l6RIr)?m2vIV|5LuII4`*5VbJ{1O0~& zO$pkrQ|mVH!bM9#oQSDth&7R??zpVWDM?!@IT>j$BM!#vT3B(Th9!X>P4P#oiWoy{ zN0HZGdxP8mat{yx{dtN-;}^0?p$Lah_F*F?WxiUBC#V~v9DdM5{@)kRV84B)kQEnH z5eNd{M+o(X}`T`y8d2GL$K2>dOmzkh+ zI?%TJ5_r4*QnyKq#Ue|VtW5c7o5i?KeJ_;#_MXV$haEsR5TZEA9&9f@#P0yn22g`l z%dDAiF>B_P3>sL?zn<|)j+u5e8f?CXv&lK^RuzIu4GN!po;bTYp>36fzC!=vP-tw{S*~K zHU1oMLJ!syu|}~r%kt%`m^t$qZn^b7-kP`CO#^wG0^LGSoX}dVEfNNB^bvb==%M?w z|I~dLztcE^Fer1D>(p{#;?5)a(N&l7<+GRb+;cB6W5!ILnE49Dyd?~CUJw(N>VVdsbHEtA4VvhaL;S8RudVv7<`V+>FqAnX!qXnw^XBjeZ3==vc z<}GbtWkV~4I75d746Gm8g*WK#@tnDfS--BCVT0?yYRV_v8rZKZ!;4ON*#yqlWqqDk zX3yc?dmdo=V=q%E7?c3@=I3e2*@sf5`#w;PIdUJSO*@o>4%(lgLk5z~IAV&+^pniF zyWgdWs|ZDzIAI(Ub{WSfK6Mi7nm6+7%x8J>iD$X@{wKhe4A@I>P3c-%H*O?R80u}U zsVdup8K!Liv%v3XG}K`z#bQK9zDOp_Y}SKuHiT{#IFm6Pe&k^UCg$W*KFnY5nU0ck z#^G3xk8X`?PE?>xS<@yp-$lhKDnI?q0%kt`R){>!hW1ctOc%7%8n#CP=PN%s!LKQC_S~8D%=M4hG zBac4E^hamWuQuf9qYh-sl*#P9&lGmvc^uVM#(4$zF#VvatXaL5muA1lv(LT2BhzQG zYIRGh3E4d{(N3`2h7B$7Pdx~?)dFCp4wse&D7GW~p!-2x+FVwZj*fOuWcA({vdQS@ zk!&}R9|o3hUvv)R#*M`o%Rc+;#X0Ak#Mw=nONQoJE}B6ix@u%~z6JS~Q_ zY+O$@b!1b~)I-gPL9HRS86J4>CI0rnEb3~7<3D^DhaYh$llI!3p+kpZymWzUC?u2# zKLL@5zI#6q=ez6fkygO97A{&^_Sj82bNb*zGdc0Z7diZhsXmZcZw(*}uF10ZgrSTc zS>QLb9(UH1-u}_}W>t_iEMKvLop&6a;+Wm=W>rFsv0^Ej3;`BrBA4+RwwBn~PTtHd z%^R3IXAZNTdx`t+pTV-_Er{f>iPU}iD6AuSCoTqkUS~Ze*g33P*0(Buz4tlpy!RQb zMjU?7B+fneOYF1nWHN>lCaVt5UA$sBH~;BYZo2tFItoqz*WsU4{xg{ha#v;YWGY03 z0^5Tm{+4Hcy1fLz?iVB5kLz9^uG@M)hJZq$P`226Ga>hl4Ye3iLQy_+%oNV}+^Oun z_hdrj!bvu?ob{!DW0zefaNTvc^75<8Nho&^dc$vTMqUX@=&d`3DXFRW`7T=)auPEm zH{fqlB3NYVSlbS_-2DQ#-}^k7Am-o$c4gYMqnJ2xB4c(KM{Qjdp%gJ<3AKa3s;7&% z0WtMHy_Ftstim(Tyj0foGTzZnF(%-WZ~qt9{PJ?9?6n6-l66Dv2#DS-KqMppt-W*Y`I81<4R->=c_VgjysfCNd$h2DEK#XT{3Z%%8V_nNL5< zLyyd&xz%Dc^b+zukf=qp+)pG?{MJo2+cq5pJ@Zi#K*PZ(p;YnA^NV@mix+VD7$hvhAs#X5ECSEE^8Kbf?)Gc1hEso0^S>Lajpl&Y#@cmx{ z3w>V*N|E}()qLofLpWgHDeS%1o{SkYf-obVf+DCD0u`#W0Uti@2o68|Am+R^k5^{D z&RcIT;`!(1vTS)Xo5K<7OIam2n-OFEnJ;cEOI?eRWTr!{AyPv`mIq#H;{G`g5@#M| zrC!s)R%s6(Y&_dE?IWz#CdxS+#nt4{Wy6xPe-s zxjE0*&;JhBT=QS-vF9#cy(OZ6@Ysx5Tzv5_uukCIvEER9rdbHh17`7lR=0;Z1?c(qw7& zV$%;J4B()H_G0oLyE1m%Xa>~}zyt=hE|W8q=m;)RjH#;5vD>Z_$y8T64M7YmSI?kW zd}pOVIYyL7W?3LMO6ZkCA_C$tL!8MH)egqi4T9QQY;`qKl>@3kGDIfBJjw9$my4K} zU!z8f>|6(X?=p}=vFBFI(_fEL4|#x~}z+Q{OC zOL%3$N?uyf!u(dqhgG0eWcwdTICTp7Vmrl-W~8kdZEYsp&7TCCR{bo0>B z7H!j>@VlN{abDfp8uA^6n{TPOmVL1k>KTxux|%nN6wb zlc<7-Y*QFZH_;6JKob953V*Ir?Ay(@#gGT?eV+U8nS~NDd{}?}^^8;a=n2O&cJzo; z5M5EMHLP6Kz~3I4&W$(S#ggUCPSObDO~17dnt>%QWol=mw%fWf>Pobtf!GLz+Wr*! zjU?zd7_AwI&DCMUOe%3;F%G{}pYd3OsKF2rn`&AGUTuTdW*3NFYowpf=jWf0!3mQ*B(lt_V+i4HoO16E;B#8LZ!vp}UKvcg%Op#DCo*H6GmX}@L zUlCL?h-6sP6!Ftv{Fy)g=^n27uZub4fPD$YshG@o{5ih$?VqxyvDGtwGM$8jD;e@g z`9F%+rLj;94K>*Ur+w-qrcBwLrp6Yozy1yuE?)ywldm2O0|pWIA57eTFq*3cQ$vU1 zr+FnkaZ`Ohi}RhO1nj3JpfBasIH{}lY=*I;hLO?O393qG=MNQFwc$OE{{R3W07*na zRCW!bIah+4q#Hdr5w*DTg2pc7X$y5;x zs3RCK0@3jp3P|gE;+C~YQzN;K79@7pCu$LaSQKLwF%TIyRTHGgVC)oTBuHn=Q|-g9 zCBAA&px+k}p)t&#H=k^f;qMR6#%PsOv`!RtO5O&W&OEzigpw*P_d4(Xt~MqsrikgD z|3D9Ln;b!I5rmm+-%5F*oA<6@XlUHXrI-GYn{WIb!|MmIV9{bOyy$y0HVdi&#s|es zoqlm*)Z?cTR1AgCP*nrJ`Pt>{x8D?0V?xPr(BTL0)$je5mo|>Z*5&|1kqk=KWoVrS z-V?Cgl*Zbm`@xdP6NvAKixos-1_u%K1N%AW;~so;-*|nFQ;U&gIzusm<-q-S1@2DZ8 z2QucMU0H2vC=}aZLms=nnU01QSiceNC^{*sME%}-2RnaYOJodcAQROR*gCXdKTQ7- zgrket_5$&SCQS2cvaM^$7TXB5;IdW?5F5INkH$Weqht-Rnd?#ktnkJgbE&DWLp3NX zb;~(SnMnLRAB0&N?lP+*!`MS^)gm4zE&7gn?p1v@>x&1Ar+!HX5oTm zo}e82*9ef%^4ZfrPCj4YlJEXE9Uba%!7?8ZZ?KLQ`OuM5_|7HY;Mdpwf%yxc^5r^U zEnyI_bn!A04q#V^Dzq@x1nip4vmi4V>S~CFKww8w6I(Kc0>urj*yc70YuBTzn=#ED z1hK_S8hT2J3yzUMY%(Ajj4ISAnc4wV4;=-CcG@>K!}>MYmPV?h4yxk3pDz{yuQ(G+ z(5LlWksNOVo_Y2qh7K9#r;Yk1ir>?$x_UZIO-;=v@W^)|^>~ka2jR90f7|c_%C>kv zw~KVkNXf9L87?T7w#>u0^VbP(5fI zL2(0x4QnW_TZy)|Vr-GBxQ)fVyVO>e>l$g6ycpBE%*`l&wPRN0T2khS{r{nHE5Q+eT>JkXhd3Sh>Ch8wM1N zv#Asd8K1_)#`buuZZ4laOsq2DO&h z1Vn)geDSccv{nzGC|UkAV+ltdxQc@&)Dzeu`5?#gjg}kld6}ZALy1b}>piQCQ$F1( zzU(u&E~k2&(hy*C0o9`i5sn&6O@v*BP)X4hpn{*Mh>5W*Ub+eshR(Gu9hE3h zUtdk#z=14YyqrreypoPKydGa%YBXUH0v>zpC2DJb$we1^jgg~9VQn4>YOoT!_f%n3 zLo1CgHWSTXi_I9K0ab*<29O(CPo}PhI1`e0 z^Bv?hprft^Q&&xP+;FOj5yhq!%<|Pl3)c{|v?Eq9)>#rnMu<&9Su{i#tWol{gOS<+ zvuV zUjE;_Zv)?^V6k^C1KeB%NAofS~T ziHt5W9>O@P6}DZb~?oOZBvuf%)>k&5)-U)L{eVE2mH6j59w+zX8>(&BsiC zVF_2<_&jSOH+t4?a?GQK3-4G&m3E*eq|MZz2%*MlVcMHTVq)-Pe1|p;9L*-K%~H41 zNV21bVr!~s&t+&gAx1)KB4Kh+WKhOnH72wH7@N)ryVnd^xL`>)+{uWce(+GP{N7KQ zzi2%YXPh0Su_zI{>^znQi&j!7C_)BnoyW!xU(k4K-mJ#ZFePTXN4fNzb-e1AUO`V+88rp#s>+W& zbqiyYQ@r~h?hA7W(zHoWn30}9-Ed(h)`@vYN;6GQV=+)92D(y88&}c2W)-zk!jugX zOr?g9TaPmhR6QHJlsL=!5lpbvwfrOdd zKx&P4j*&QQeNJIh=E}Xe(Tzy|DxUeQja0jW0*Ub@L=$?Y&XdkNgZ%&8jS$t9eG%;q zEhtzGH=9TrW!Re(=J1_HHQcu*aNR7RMkq2%b=`9MH>_p0ugp~B{bdah?{O;RuAr3H z$qVJo;fw?*RHKY~2&K*MJaXh1;}bKe+J!3Dz}#E`O(fKKL_8Oqx0d(4?|Ozt`gy?% zuEOO7*IoDFXh$0Qf?jE5VNC-gjoiBJ+xJj7Pufytnb$ZJ1%ukH17xcPF@wW6$;gu&yyCo4bY-}6*3-RtHRkXb z?%v(h_8cS0LwmuC$BB>@!JfdIjH%2b%gUsE{mkv(M`i3VMry%)T_vd1h+utG(uo$U zL2ptXcsV{$b|@Yr3F|kkdtf`tQ;Ll~*nmW5MV|-88cqkmMJH_0DSC+UN?Wv)<}Kvt z=?nA#6V-A>Z3k%~9`ph=xnN<^z(=>&U}f1zs?>+q;g)Y=HtWOL6enT#&%~po6xNWa zQniZl1!~K2rb1hYGYGlZC>Q0KAI)t!f&`g&h?5FJkqXIBFT-0mQuI_gAz)`47!5qQ zLKWj3X_3&#!gn_etQsuE&l0@xSRcwtl_2suHa3a#x}*g5El|t^+e%T++OnMYzyDnf z4-Um?3gLw>dLDSsyWagLIG+X6Bhi*~T+3h`hX-!@#vRPnX34s%t?rnQ#^-_1tgK(r zk1@xhIH+q~6TENpO3~Kt=*2{!s@c0ONOME6e~RMhQB1ar(uyIfEBo+WgEYv(`Er&# zvDnqiNLCM1nwlZsc@X#Ay=0R$Y_wj;tx{Mp-jMkc)7b#!_1!QygxSB7(%d9SBM6Xr z+IW90y8gplg$v`NMuV?So7N%52PZ#S==pO>+gH+oTea8$v7<_Qr>T@vUj{!h17L>? z?^NnZEMGB-s>7>8z88Q@!dz;iF7(($aK=z84d7RAqdvHXNt2Q|kN3i-zp|5`dhTVc z@3yEZP|28<5;xua9jr+y7IC&r3%v$SEf^D|n^fmBVH1KuqM+7LbfxrdT}QTJ84ZB~ z#i)`vjc`Q>_09;AG!bx1zn^8OH;}oVcS{zk5yQ^yJLdg?mn`}q*eY7E?W{H2aKm*h z8y$|>Ob9lKalH5?FF?d{-8=s%pwK62GYE#+xjILV9HXy$ZO7fv;8`==P2%@bNI4!u z+lh&v-VQD3qEy7FP&bg6IbJlXyy&u3l)F-H-m#ZY+_@LCato%fi(@6oqGM76hxYZt zd0nJi*CM+QBX{n>jhz5hGH2rSnqoC-%|Ps3YXm5+5g2JSJwv zs*z3bNEfAemW>YoP}pAnz-E9;`%I^f(KImFPm(C!>AZv8!(4F9ohtK?slgjdEvZl& zT!pMUlUli#hDk|Wy=BOA*OcXbANyy1_2tiI?TS7o8_E~Hb{ik~>~`w52UFDNIeQYz zYLk$bvY@A@3eH81xsZ2R4a~7d$&#%ep?B+g$V%isOlkxdwwOJ|In?Iodux%o290A4 z&i02{S=tZ;7&`P16uAGs`y-m`7G!}fj^QudFdHoA6WHigMn(-rBSFq_jyZMcO{3>~MIYaA4F)N3dsu+wW*oMPl1BY|V zI?^*%k{vou?e^`Y`^EufE(KLX)-XWAR3)XfwnVkNhspgrsJKbazi1O@pLr%b@4KIy zzjY_%kzX#447>sA7xI`*NbF@!_8`KNpKrbhd^&I7ef47IEEdIiru> z)SR?I?+Uo@-W{zHb>T_y7z-DkyMgz=?;R{39gG1emYL!~a_}i44kL~qeZlhp;ceG_ z4Cj1@$|&?W@4a_BS3K#`B_K}-xSswj;gXeIeEtCQ*HSz0Xc{xPc7GHv&~4`U$){b! zdR2YbIo&~8E7>QKKFk=&ENmsr{NJ}B+ZiF z(Ld1tsE(?h4uIdMp5OQSzD}S>ce%utP3t&t=w1|qk^G_cUL=e>;Vl@6BAQT3yQyzD zpJHGQg}30EqDP_U6cmR|)O52Pmy{#Uws?KUhcZaT;EcsqyD*hXaDwwbs>x^+7qBEz zCcmBv*@}L8&fJ8Q%ha96sKp65<8dg78mxo5Xz1ykn4@-N0-4RRF2P8KH#yr@c2V_3 zR6}mF0#yNVjL*z+-;RTL^(`gpRtrer{BzfE!w25Mve6Nmn#BvU7)_!#uWc2nSHIx7 z*mB0(-uhAMH4_z}0nI|c&J^5z@2;TkLQrBs4NglWTF@{FUCwgOSp$4ASMuZ2q%{vN zWVbG6rW)G@p-@*iKmJDkvmSON!mCF2W&2qfvOOr^UAZxV8C`f^D0?})R^2t{Uam6U;vt0<2SF_)OI5LNJDGB=Eu zH7PYlNRH1jeRv#Z3Nn`<&QjPA3XGp)&FE;y+eM-m@8skZhmK4kk}aO91Mm6ipL!`H z%SOV8TZ^vKzKG{%Wt&K@3S9ZLr*O%||H7BQeD^#I5Otzd;mcqBRzQN&U`;7aAS7&E z7%!|`H$>Hy$P1-7F-dW70zWoQT6Y0)bwqU>!P{a%fEPRmi-bed)2!?2rlfVemOvVa z3X@Z_1_n#~@+*FljhnY{q@jHFTif}}owF3$kC^(R8CVt= zx`oUtfDvkJ2vFTUNLM#SBv}WP(?yy~*kPR&j0kq5hu*F0@Rbs?5jhkIygL!dBdVA= z!A;hfICu;*;W19YTfA?Uiea3sID)X zyhv7dr{q#&uD6Qz4N_S>NNG059X-L!p)vgN8n&)MHAli^2R@X)K5>XE^VgrdospMc z!RoT1q;TAH@o%^7;h*lA!MNTCN=Qrn1{5>nn7eZ~)4LARvtb35)g$;MWZ>QeS*yBD zX>43hW%VH0j)Tm8`(EVu1Pzn$^>5z7nrB{)8Vize^UdGp*jSB33_L=WW@9{OpR=`1 z`1ku00h@i*$6LvLIsl$zr&+UhEnai1lp+nLSO9J;$P(K8aMgIax($E)(RXvf*;^>9 zqi*5K%g$ic|MzwN@c-48ew&e&zig|FkzgY!Sw_~~izX?BhS_A(qWlCYD6Ap3ipwnh z>sC-*HOh>EJjf!nWCSz{3>dLc%bDJLjQrRfX&xjyy#~69i#JE29>g$gb5{3P@f{Q= zR6U60(1Al36SI>xlvpFMFg@jY-Rs`UM?d;rF4%TX49bg|_br1Sp~!{*`SHKzFaGME z5wezuYtuwXNCIWY2}h3{WBH2FcpY3kKOQF*5y$3AM*oRp*u0FdSc(K@x-E1MQ(iqx zI#H*7;5c)K#-S!i9!3LIpstRzk??o-*4Y1%&vW%<>lw@px9*$fuWp}aiXJjQO}(kF z7=y4kp~TLdlFlfzckZLubAaLXtLR=nN7|oChn^wyY)DupGI6KYG($eBq1t zaB%m2&e^<*J==G1(@nR4lu(^}NRvvP15v@|Et}d-_V;ge^;87ElUanG4uGflv0}wC zMu&Sje%zhxO0?~u(oEY>BmCS?zku`4-ipx%^+XU?VucZ2`ut1yi?4l}8P|1Eh_2Nq zNlK*EE^MWXhS*4s);2Twh_Fha*Vusy%Qmf}Hc(+U%*>NS0(P))j5LbE(Kv97+QCUo zL$E%~z8WoJ`K_%1bet9)_H@*kf& z5mH1|jL+~Y)J)Q94)|8jBD6W`wg{6i4oZ^^PTaYZvE7Fl*u0*~@Bo@xawFtP2-<}; zBxi4=yk-qkcihcazVdBu{^oyxYmoXXhCKYPrdXvt?)b0Cd?3u*Y16u60K*{mAkRdJ@G6=`C zbyW{(a}q%p&Nqt|IIn#3=G%gsqy|Omfb15;oDxR^oZ;xvoL_m(JGlMMyU2?oIOwU5 zip+Iw zM@j1zDQYm4V-HPX4~&r>pCPS>>^{#7_0_$km!3h_lQ&V?FbHWzErl$1Bzc0WK^=G> zlwUN4B5xet1VBoS1d9%nNB5J^f@p}vxRh+tF@Ed4OnmEB(&Hznc*Uq8@s_j*-!a{r zQG4<^q(5~vwe!xzrQMjq;B1)aQL*G=+a`=UWk!a0K=Itc#piBhXmFsV)FbL2al=lV z38axFPkmU)rMB!x=WR%zPyz4~_ zJy8T9bS_(}E&-KGf^iQC-V4Xarg`(5-of_md+;hze#=u788`mpKk<7X`inUBXXD-I z+tP%kch!COZKo*wQnWAt8RklP%@le&|o9NGff zz;or(o=lRYEvnED`{R@az_7#2KWYE}Pn5tHk5?mGe$(bnIA3(G2(+nYt2B~?xxQt% zHQP8*UB+Mj$4+kEd6YUSspc4;GvP~o`rmKoDAf*u$Kp+b?dc`y9i$;?$TU>u`(6Zf zVsDj3sw6{Q44u1~#$YegiI7KPv>L@2B~_>tLSz3?#=g4?cf3wo1L}%Kg7*Uk!3dN% zGsniE3dRe*1Nqh~9N2ddA&tSQhygoTF8=(_zmRIxw9c8vNrnRlXL#cquVv@1eJBae z37`7ZjlBDJK2G6M)CZ+#V-%Y@e&(mIX61_hj)!{ZclR(oHPdpJl9nE#MHEu+SUX$= zX#`_;6K1CiObb+!hN2TS>Hu3E{)^()x5XQm@kYyoF2Gu07TeE~D25d>j>1K#-I z&+_UQU&PjpBh=<{zV!9`_}JGD1T=F|z;$Ux*4Kw-C7i}yUlWOKDJv`9LXisHtA?nq z8D-8GoDsYUsBq9E@K|p!Gj+yy9KcWISZDAG4GFoes6Hr>QUt6Rx~h(~eO*C07*naRGFDZume?#S7Gno z3Eujack+85dOzR%#y7d)!+(WqI_8N3JYpTMdc{lm>7V`Y?B2bXgNIMBSb%qCCTHyU z35NOyT65h^dr&Wm*PKyt987zd%hAM=b(hepA1ww9ftb^kNLv%mqdGwxfF2_Ir83yj%fzcV%y5L8R zTeMk6@dpV(sZU-Dr|-$1J^($!KlHj!IUeM`ug!U z!Fi3nux9)VfiG!#gH$a8>sMljdYLxiCJ#wjBtsh|EfS^=9Hnva1g54WPQu_o9LH^L z{)^k@UTiQ>iiBcKz@>)Ehb#1Ums+%oC5v1PyZ0Q32(oJ%*!Oq}R;?IiaIl{nKJZrF z@SE3DtAo)DyrPnF_uYqh#V@{rqesT^-UJZAhPh!Qj+ejeIlS_fKTlRl*|u#nU;Wx$ zG+RW?W3frb!9$1Gym38E6RGBX-RwiH>`EE-bq*C}tTC;?)5=;1c9|MY?WG8lIy4HH zs$r@blu}$`uxkbxTro)f@HjKOkDxO}Yn-szLv@KGNhbN3r(M8VsmB)u;J9cw2{; z%fC~ujggy1bl|h3PGehv78BhVc;=OtGCVklh{tQwSm{*A>o0{{PC+>~|7njRNb;!m z0GllvmB$X{d8F5~Y1{bZD=v#y)lz$xbmr&@xc$iol>PK?bLLIOF3|0ioCFB5vCqg9L9Qn>SfR7 zHLv+qDrthHVDsh;%2{KRQi5GfVFB zmanf!)3U%)#Ix_!1j(#I(aAb)Yz8x3AP(kILDvp4bjcQaH!nk~DI}renR&&y1QqD- z3K?x9fx@PgHD~q6P$<16$_qA;P=$sVOm5Np#u)qhU1SGO(A~&Le1Ny^`5BmK;?&!Uw1pnxo(#*yF=DKWQp3zNfZu-b!dY2+>J zg{Tkz^cu4)Nm0p=!G2_*4<|ujQ`JQpN_d)PdTtuFTWG~$Sz7f&Pg8kjkUJ28nnGDa~rftjn56h4@yo1mKGqV}na zwxD>$=8DeL@F!+4({(63b0veW8=>d&&7@}x;k!cSYCYISiF@{pGnHgGQ-Ic(l#E-q zAHqlTcWp}$ROUGp)(Pp1V5O!nVi3D15Z6V*YA z#L}1Nh(KYR0Gh+O2IqHB&wkt|Bad=feL4Vk+=5&SbQm5P;OeWNf`|`Os**61b}_qr zBgNqQR(7`-pPav`eaiqxCBfN@^58H@wTIj*UVU5Oi+wLqe4^wPL(dt@sjOSZYzB40 z%_t&>1?!>Q5Ndmla^k*&m|4Np6`T*j@1Y1@Mu{!$N|2#0itaLvG{KRO%;l`@t5Q-Q z3#FxtadL8sW5;F!aYD0 z)l!BP!HU5Eg9CkJsp;5o{^GyiM3KiJDoZ8d#RzAOltEp{v>liRxam66N5`2tHbFiy zOWN?HPDw%`j2Fd8pew0*#4B0uNvG_|QU*E}x|78b7^tx-7&8-z+Ah(7_B7u6Zg4sXG@o(OXIWR_Agjt!) zI0~Cn&0(^uhnZ`hN%jjbXKrX6v(g;~0kv5Hd!G69i&?&6S;unc@djKx7(n-+0N!KS z1AO9}BhBCFLYOc8k!L@HfB1(lQPnC=GiHa@;@6x_!*tU%*Pxyjh%<-}<=x_RJ_I6z zBq`;=K^jRynhRwg=1Ww9M@N&Zg#gu*zKyHNd&?BYhZ30tvC%wIJn4*Mdix>VWCQC2 z?}|8U`!M$T2*j8)L)Bm!APtY?o^I-_=_!+VM{aD#4?TF`P~1n`N8Q5o6wF^nzh%aEPJ7ZVn!vT{ID(OwZIge*6T> zR}RxrE=83MgS`~y7*<1I6K`9J*;;t=xjBl7S(0jrw5N)c(k7`VjKxVf@3{$FXp=kq z)OZT!<_1r}oU<4n=mIIIcl9AF z&Sb`P<1`4KYAk=-OBsYR>L=sJ4?uBQ@J zq9ZfW1j8Nc4fgOX6L;*vO*X(Q9*-K|>X%5{b8(r4MzBS~AhC)fwE{C$N2Y3+T8?qB zvQ%e%Z-rT#kZO*L;Elw<<;8K}@X(C~8Cha>eKffe9$6I_eGhvp@Sw{^(Es zA*MV*Njf|OYGzOl9iHU3-h4gVckaiD($F~+PdQ7u@cc6oY!qJAQ1&8tDRc1H;W!_? zbn{KrGul&TO_E3XFN>ET3D&Hf;{+Y~OoO?@;}nM{NoI1AI3w&NkerqaDNcOrKK#)ss*OPS780^tD6otz8zB9Ommoj>v&{C6VpSNfS}wZi!l2|MZUGJE z@fr%{6!jAyyAt>b&9gM~NR(Fw`g(cc3$9`+?Z&M-i+a`j&G!Y5&V)i!x!alx0oV2z<(wqz>@8Q8QQS4so74+)$#32M!yhEm^qn5i9ypy5&H z<4tt(6TW02HDyVRAc@7MNub6!AA+fRoH{O8(?`Wb$*u+dz4NmB_uO;eLh41F)5R+z zBSU}-pXUvq{N(@Pe|-G^q8fW^BGE6y;hN`8L-%v%o-tng+P84ueY;{KKUfBBJ9leq z;Ej1?M0w`3uB1M^n%RN%)NM5ysxL)Ez08+PE)le=N_l9I+=iXp zOAwv6>Vn|Ac#L@R5+oazVb`w=@>MYw1jcKbn!{S(**El-OF+euCP4l06L zfh@sfDPqk0AY=3RjUdKz)^HiYk@!Hx4!U%%mEae-XYZbUZQw(5yvne0`5;~0-FTqz z!Y4lQzxmMbe+uu)pdN3)TaVg0&wA$hba#dHOV!|=MZIC~zH#30`fJ&>>i|wI9>?nS ztD&V}Y+9g|s$tj8JprtdPOz3GGoH=EWt50~b|C8e=($q(&_^}7VrOz{M<%Epoj_(9 z!CbuAyE8&z!UpA4q41bm0poL+=>qEvjU;8NyG*iiHI=hBpu^qdCBY{_*w$#AHEOXY zbivcd?9;{TQ$)?h+P>qA-+CX}iCIcTnC-P{C~29=w8Geiv#GrNC-{+<{uo`ZIhuI# zwSKw;{vm&~b`e>4bBHKg&fd%==WV8uB#~Coxf$QugN$G*B`O0$IFp3YxyWa7R+}T5 zXe!Kh3#H8~uq%eCTcHpW=1C(bEpw1f)|kEj0L9o$V0viV;C)*^Z^`dzf+02pK20rB z&d}7hZYY&@IecjWL1&J1V~rzmMBbdXA>_jJ%q;);<=cbzZCek}sAI*7LCV!KUJWK6Kt+3npo!Ruf5R`%{WK;eav zWy3g^&zHH<^!2cO^Bdo3P0uX7wuaO+*t)zLCL=Hlrj=wKy@}@@oNDk$(U5uhTF%Vz z3G&0^lxmJlBaxlpL+qm*ntH+JLNe`0rW{#eNKJ``O{jO3DQ{UzdFx7wfdroj#u{wX z#h{H#B7vOe1Uhq=YQZ_f|>?m z!Ze7%bJa60;>~aV4f=b^JoSo8x#5Ouv5AYQamd9A54-jp=gn_=8~YC&X4&Xy=yz(9 z9XqcrxNG+zCdS7*2EagEFIYd?6S!|}=Wad-F1`AN1TLjRa4u*D+NnBohmO-2n}9|U zRk1^mDkNBJ<{|;<^@`>SYN_~y%o!R*f$J*KbH-{a!+p3ovu&F^PzlknIU^l0pjHP$ zQLOV6;;G^Bg=1#tAsX8cAoT{SIcjsPnd0Y`4>DquTIR6Mp3eCm6%@ErlTzB)_|1No zK9K_7yo8V_WZv_vC!fi-&)?0#h9X&xniSKPDf&1I;ggJ{e+Xv`g^#nb0BQ7|HHtA7 zEgQ;fmf`y%^5TtLRx@7K8ZVcoL*m`W!GkY97ffwF<5JGD0^mV6txDDbOBYY z5(f2C16hi7ii^fV(yZ0vMG^!x7NZRW$A%0B`%}DHiliPi_98J@v_NqjIy8n@3(mJZ zcTo$*v3l)F{{7$oi??3;M-+J)NBXiLX=MwpymSlKUHevgsy*S`6VKD1`6NE@fj9G; zZ@huR3#x%y~F=(8S zDZmG`b|5hfl`N?VgmiaS6|=s??A{~f(*;FNRGDdJ@Ipi9O<9{qm^RV-_A-8antX1C z-gV2!`YLRq;G)&t7;5BNCBY$4foQ>Me+W|grvu;*@gp?r4a>TOzkTmdV1WuQ^48k) z(@g9kX|r|_tQHH34KKmWM^q_{1Y&bDC`nu9(Ii9rZW3L&uvy;riB0rSQ5r?T&Z!1p zx%Vjl`=(>u-6$d5Rh%f|^B|{0Ic9bF;$b+X3F?S&{%DzjEG2aX-k9J{($uLBKZKn- zcOsaU*KF&UoaOdgxARZ``~`|!S_;YFu{P&Pmu=;`>#wDMpci9eAdY>`XZ^@i`M?c1 zZ+g=WIA3b&Eur3U=Uw~w{SW>DBO}A?-ZS1ZH)hJfbOmeO;_h za_%i6-Qr~csdLqHuH-%Sg15cx4{$1hmgEJemjC+l?Kl@oN{#7@M(HafhP`|C#lW#} zD#znVRHz!|vQ<6YyF*WA4!5MADvQ@e{7#7`?5JWI1^Mx5bhbfhunVm!XOyS-wR8J< z{@OKk#|<)3MSN)DhWYZ~$fw5OlSr9TvuG`Jk^%Dz*3G?pe zzDT>uZ;Wz&krIp1rG$ohs+6?GnHjw9shio_caV2{=>P{!7r9h0TEnOVNf*x3YD%gF zB0}m5){myK_h)e8qa}dGfG#-ax#gDco_v#Q1}H)wON{5@3(nyB>)*!6z(7zViJrX8 zW@N}tQowWdHCIs-1@Cz0M^Ufw?}GQ1CM{&)FArB~`}XYtm9}ol#$#QWpxCy&jPCSH z0_DS55$)Q9DvI}DoB@~9XdL4Ct1Z8M)!AIoV-Y(;p=FG>0r6GSB3L_F*hZ2zU}yf= zm&_Tln8z2^i(jx39fC6%M#1_zjud_5o|=#DJ@yy{(I1WySiaZDEO<$9Du@<=zJkR? z3qEP19c#R)o7^(9oUYQvq-=y3S(QN|}~EU_V6 zkfLe?RvnjKxQP$^?mHP891KTneA^r1;x{e?Iss#HUi9MU;l1ZQ@BLHqBA(k;?^4?W zpO0mu<*Q%2mDxs(N;#eH1Gd3aC52VXy1|S`HjTEd*_Uo+i+`6aC_@)qRWVp^Nqmh< z%5|>0=3+MXW;lg%(M4euZyK=&C#`ea{7%zsgS3tDXj?X_9X92KhbM?8^IGgGVdPIh zC_p@g2*#a47(_b!yFP;VEiQrdp}t)nCjqbn`SkJ7NYzD+@K&wxU_VDY=d@0W)(zs@ zRe)vbRg(puvxq6I7V|(CT8R@Ri~pW1_zkK{7e!&fw6)ADYPe?GYVJB%<0H4#@KWG? zhHYs|HDB5w7r~fq78&QLLZ$>kV{lIDGh6OVMQUNZY~?B8-gma@}>m&B)MT z%qnH!-O|)MGbOkAELk%xOVwspZ`zMP!Jfp_{-NBfDi4sgJ>29%fOiWF2*InO5wTM#; zolfYyZE2Qf96orcV;jRqFl3~!%9=Ds)wf2`9_r@UdA~|RizJ!hC%062`WZu{+Cgdg zH2UzUm(Y(%094f<+TitIuj}-DpwD`s_cfo3?FZz6><1(Ws&4H~_|Yw;n0d&8?+QvM zg7^mbgo~F~>5`LJzy*>AJ9g|uy)2M{KiRRUH(dAj8@Tbt&yW`m@!FzqES9xGJl;9f z8OFwDc<;M!;B)`_)u_O|@O{$EBwHd9iZvN~ckl0T8lv8x@eC%GE0$#odTrrcJn-gp z(rd55zd4avUV8aj23@@sOTU+U!Bal*Q6%QAwv8{SmDShw%o*a^=Rp;IQVijzQH>fLhL4(L?4t-{?&M>5FWXZgrfqqK7O?u-1OhYr)|0Vz{s?;eydVFbU4+L*5`ywgw(3_$+;` zo^sFJABM*%0zm{$Ue!N#X|cAIHm7J^w40!N51;wWXE`xGiEm1YuyA27T;M0$u@*D@ zI^PH(Tl4hv_HfB%m#}`#YAiufMhT-*ixam1T{xV;`r$rGdYGD-pP-;AjqZiQBv@Bt z^|C>X`lWcG1XY)*xmj-i?rwZjrKaUm95T48p8Hh3^R2r%c6d5YC1}u06yg0J_%mjv z>-@qm{0wPo!sKm0MS}4X1&0qG<=VHtpPRqE59b27ftbLpGX-z@%~$Z*&wi2H?%3b7 zO+nSR`ifuv>dpMhufK}aXr$ppMQjb&i;82-Xo}5ez*MkF5M(F{i}=nGT??emqg;E_ zTQ}$<7%o{>VJP$D-iF?3RNQG%g<3#T2-+S`-RInK>s{P)*S$CwMR6Apv$fTK)3*N! zh_SRJ?^Okx3NQKbm(Wwq0?}Pgp-BBh$sYA#-k0s?cJa`}1NI^H!F4XbzX9;^8w4NC zLos6L?HlCn*Z&b-gV~W+_kij6f~=(3M2^U8`>uYn-CV?AjK?N_&U>zZ9alg9Do{5M zA9v`FsX7p)uP3GKYt*EvyA`=?J_@&rC3ABu8|?0EnjN#K@$m_c9GfFat1VTSrU=} zIyZdq!~EloUjbi<=<-5;OYJc49me{acC7{xi&*8Y*Zuyi3sdp7y_?8S0X@*C(x~FH(v; zN;onKlnv_!dG2$bjm5+a>xl%qJa)%x3;H9zT|HweVWCut)bLV$x&@ETUTzq?M~(kE9qFe z7{X}Q)NDZ`@);MG;x-eKQp%;Py6Lq#f3q$E1i-Lk`%XlXMSQsM`jMe-`uqDxtg?31 zD8K)E@8-%UZNyj?&s~$1XZh4We3AFR??X&XG}yK0IInx%+qh@@@s_Kc;!tsbV_Du^W?dH;E$|xt`vO`~TYDk| zVZoFvQW7W`C|jhQK*>U8kaEIA&67tJpC$!cMHy8}#v#hlwX@X0G6v!|c}0fJG_ zs?lM7_x;!NJMa5_KKJ>XTeYb8P_};NpT2@C40qqXlU;jjQK@+@dW;Cwis6ReeJ4-7 z;?j`EsR2nD9vQ`ZhcQXVOlwaI3D(x%LI!A2g{l;6UDM0A?#w|XIJcNiZ3hYGPaSxV zDQ8HM2DvklmTC)nkX&CZ1Jy!in5_yl7zmkxImazgK?J3CY*KF2GlsLC|?4)T__ zycWm*t7!wOC;o&+Vu`V8@*zmye%cPT|8oVj%c=U;FE66cG3 zym162@j~LmO;GZ49GPtJ_uHp1D2XqTq#0stkZaN)7%IgaBcnYrjwuE%BSb^?H8s7oLx#GjX<5EJ=a8?%KiZ%-o_AE-f$zVAW_pB1Nl3Fu#+^lIzuar&Ih? zjr!OmGM7`5l++4|b?i&}`O^I-zyeDBzP;`@%_74~S25$@079o8wH5$Q+5(Ar-c4=;L?a z|2De2D^aCN@y4Mx8hxwMl%1ZEGJpS_U3_<@8=EUdmc^hW^D;_mIK$K!=*>vAbEFnA z96fRz@6Dq2^?bp%X6@Sf>9p1=6C_c(swuDjl~?e~zw)wBI<`pIky4@_gJb>LA#V7+ z_p*7*M#L!A3P!ZK&x3fZ6*g{Kf0E&T!}i@rnVOnmA@;g(f_TM1H&v-)QJgW+eU2r) zyJi7PJkHdEsX1yVrkOoHLD~pPJu{}t-`qLHtu-Hn2ja-1sG=lo8kruij;B8TDg5Ni zu4Fb-e3FyM42GfuCzK@|QEMDmJn2lHf6eo;qAl-a`5t;}kH`D_(S9VS>R`XGC;4&F z)>sP0ry0EVHNV2wZu$;mV;+&Db$dSG`4Pd1At%F|GD<>bEcI#$>Fb6{SEN5Q$jcQ< z%hvNNzjzg^H;e{vl87p*xcLHIgt`c`#`3RsAK(MuJWf_03^Mo>v6nWV$BDw(eZoK` z!#EcV+ZT7S)UbEYUW~CgKOb0{68EkssFX`fu8&Gn-rtj0L$%r+`6G)n=}_WX11@ib zfGE1)e7C}wdR8o7PP-gqdp1xhRoK6G4=a}sE^0E(f8O#g!}^MH_pH(|g7uwr$>zVH zdBuG+WD>9FT)}j0f~3DhPhW$bQj1?~$Lh>E8@;);Qkq#$TseN#k63o2BXxP$Kwf#}<42_19njKre9G zA+eUnL5ylw4}EN|3>{KDdV2d^w}>Wl18UEY4K-UgY+13W2vVlw6Y9cwh`8B z#jW0qtlP@$`m<@Aa{;|qU5#9D8Rmk^kP9xNIR7HXH*Mpt@mV(ZB#iWABmzPMXFQ2| zta|Fkavb5`ZrR0k|9X(Aq6gLB?`yR{vGc>_gm`q##wyR=(jO(>ea8&&bD#SHx7@NL z3Z(jlrKP~Wy*s$@{B891_0G@y#`3JF!~gvFU-6MY{5#Y)Nz|q#h#D*#VSHkmuYUEb zJo)mA85-;h_MLbHi%Rh6xPSX@{@|m3%8?_}3qhZljSFz`MO!%Y?9H5vIcALE_C4d= zIvzy|ye{o0i?q~!B>uaPeaLwwbc@s+Opi02r5wpKW)B`=Ah(QcqH^B(WM`kt?9edz#0i)yNPOtwdMlK?#bPOpl2Y*7Z+SIOdCKKj z(-t7*3GDc`XxOQvJk}C%lcf_+NS8YZ%olm~*Z03g6G1If0dZ~{_QpSx8Gko5;)T(6~ zi6sXLli)}I#~3M}KRChuiD}B2rEF7FN{p-JXifRX-V^-s7w+ZvzB9+P>%v86w?LOk zn8#Uyhp(6hFF&WBOIHN*p2WK)TtF|vpa1FKuy5~Fke^yIqG#B8m&M+F!e#y?dtk|JytBI7zRv-hZES-m2>8FTgz?R zAK?1?TQt%MoRONqMV!rrzT=R{4^_|_wR=?zqy{rS!NI8se$*J|d-v^Tz;qZM7^GoZ zOp0OL!EKX{&)xL^*Zs#%e$W{sRhUegjE}8GPT$19MHiEvaS9V@hvtq0wCLaj+D(Hu zDVJXIbG-7EFQd_Dgc6-t0-$s^B-JHEZC@0mVg@T#swFUo4uGPw*q3eROBw<>i*ZeS ztC|>CtevQCH#inpXnW|kGIvxA`}R+A)$4wj8^3cGAaoin+=_MB4 z=My@bVto)iZzqC|Hd%eqxiHkC?H$HPcPr2y2hcErRRhlB-4r9X&6<`&Q^VFf_OfS> zBDTepg!hz-du?IfI7FZ+6a3YSHuI#7BXmrI#HBsawSD6gyx@6PaR1g0o;23GmCbM? z1}lbUbCS2e{VJaL#3yj@;Ddbd10UgUK6e9NEgp}@#YvR42nnrr9?z1o^Wa-b|vYOBQ<)6~9 zp)|Q#o7Wc0|NGIsT=Dq>SeMcs2oAN1B+Ah0VPveuvSf;f3|nkV z**R(0Iu+-G7}Qxbmc>|WKrB;MQQKzq#3XXZJxqM_OAOt53&ZI_wmf7VANa*; zXB*G>w=^7@P9u-+c`?{pd&h_2<5ZPZPW^*x^Qc){_yz$`s%D z#%EbRIud%drMwZO2;bc{&eQ+L?RagG8fFH-?D#cA5h@Zkv8+EhY2&TXY>hI!VKtpm zgY_w5nsmeWr05Haia#>5^yFb2--+b@qxl1>qLVmQB&M(uxcK+%+-9(?4_*Tir;c{+}NJib&qW8)KMam` z%P@TMdRRGvryUr@HFN*tCYMJVH3%D73G$&{nP@cF(7B8EoVAQ+oVJlpqSzR2k(gC3 z*1`1waP9zj_{v~p@mf~2D8X<9OI~K*J<30ML2hQNiRZ#|&*ZJY@kn-4M1hFCCFsyj!7Ff9o=Plwgrk42NgGm%(SE8g1LDVuZVQAmIhlBU-#ZL*|3C=@D zEK|nPHa3q@X^a2{5v5>>WfcDBZydym>t@_=F{tT8qJl^k;T7isoxG2t z=G}9tF3^}*F~a@#Z;u&Lt&QQX92jEDn8SD*Tji=1x!PT38cSgc^HB?(CfWZxz8V5eywHhIZ4i{LE8mtzAb4i}>Iw7K?BVfbpb>;uAr#inrjcXUm#FlDrtW$Y31GWt=KE-E>QA$cw6DG6O@iO0-^m zepiV6C0AehN`CoiPY(5KvB23xKEmZ=L%jY?SMtoupBQ%)A6J-(ZeP}+VWuUdmcqt) z&pr3nW*4)p_JF|VwF9x|gB}2pS)X}TI?TS>;#nAOd| zRPuUA<6}X%A7H>62J9ZLK5LApoV1)l=V&K_PkfQ z+a73h;PxHp{thP9g5^24*(TZJH=s71 ze#;;)I%AAg+6nD|5Vbw}^!imp>)2w1*24o>^IPc0fQ#%Emk1-$;boUUhFAXFAS1dD zHG(q@>?zA>ZQ8(OBlOP_lMh}s)|*BCI00uYEltopQ|!NMH*zpYG5Q#DoQ|Klht6HP zF~vkde4Eo&jbaG>yFpZ`SXHY`9BlK$AKp1Dm3c<|Dmm~uybm!*V&}=O2M+SOtKZHi zKKW@5Oibc60L8&c_~a-47jJmudpI!e@-CI2bKAk`M2vgMEG}A%u{p!-x8KXu)Ko4Q zR60)tD=8aSje>POdc4*9H+L^3Wa*JEg@w-w#vLRbnAoTV??HyvM_1Es6(6-+};ys9FFVl_W~cT0B8ijMB%}Pq2q^Gr^;(z`18E* z;xQ6&w3e@A`8lU@u;~Ki#5L**F_rA!P6Q=kYWo2u?%s!)v@ymOqIL6&sYZ9yD@_mQ z3^rK4tbsGo$*i?pu|2TYY`cFu#wK&bfRG7oHicJQ@d8#XAIdBG)dvvlXp;|p>@&Ra zO>gDSd$)4WefM+CTi(To|M;(Iw+B#{#Q38i#T zS2ASU*iH-M2C(Wev}xN0OM&HODU2o63MbOT4PIE(y#XOne|UE!sb5l}rdy~jN=rT3 z2n|jv)$oQFKL+3YHh(MYag7$14&s|34kVK_)drW>NZ^k%7M#%8x}S8{IJV=Xd)2Lo z_j6njstVp9qBNLbLWa3$b%&9rA@$Jo4kxWp&xS|TU_{xvbt}dsHOaXs>7EIpOQ`W% zyQ;yv-uXs;;Zcv^+0S}1S6%h{{Pfms!OE3bi0m4CSG;fJogbmz z(Qx5;r*iGJZ{YNer*YnSXLHS4-pP$O-Vr)ObTTA(v?7u&9+eKMQ?_p3!G`r~awak# z8J`;-4kQgW4G*%eImz7z$MAN#;MDwWiEg7zCVA<*6!``^2xihUarZ9LQ$`qGHO4Z5 zU)$K^inCWUN{D|3l8eZCEhZ2{WY<~Z8$8nCZk^LsG~K%CuIFBgxaqECv2{=S7T}^= zei=uc!^b$7^*$=G8B*g}Z`-`(IgjLd=M3PD#ikakZ4#Zth-1nmIFY~#V-sv!nY?Eg z?Oo%Tjt3u-3k!||#mu3LT`XHpUV+Wq;<_ELT9}{r+;w-a7HuU;CZbrQY}vSykAL(J zdGs&*JQl+lr=P}$Kk^=a;ZbKJVk7HuNNA`U9@sm@-u)@wceCflD%PYt`{|G5Lm#@1 zO{Z_ds%71p6}yO4kogl1DXZ^HKr_*$v zuMaTI1}<6mpU22S+OC1#*QT|78?QL4$;%(IhLx!&)dp>vq0l>L%Ly^lyfHNBuxaH`$rb3a=GAiZ&9?>9X_|*& zB1O|L{o;B2$w%MKS!ZoT=zyfCNm+Z+a^Ca4YkBdDpFq;|1tyw6?i&6-V|wuz>-f!A zy@21l<|>vi9|WdQNr4HLuWItvcfNs_{OS`hORPJ*gUhi(IOq2&uLJVV&K_J0HD{mv0_pjXIpMbVyN|!a2wN_wVACTkc@b zp7B|E?~XJ>(n1pu$AVt+l4gWH)?@(H2SU@Sj^~q~_!OV~pPwU5m61Wq)mOcmXI%Qr zG#d%2Y0*?zZ8`!_|$%hg)Fis#&ip3ZN)`q%MZxbOb$7!$1Ca9oF1 z!?U0JOvcCC{QW=tOVAajK<6UCD)O50+pm2kPkPd0*u7^QV=}cp6Kfb9UWH39dj@yj zv7H-k`1f8nU$Rnk%g=7R3-3Lq;@)~u5^qUuhjTZrW9u{tBkrjcA3{ zOWN{6k{Jh*lDc+Kv`Z~c+gOuz@(zIUSeqi= zVi<_EB-K+2r9?(8iFuHJ{pQ~>IMmD&OT;K=;tZ*sF23=UmQWK{RR9FhOL(&12gh#ACz#lyC0v@?;5aZI&r;Wi0s7~_b zFMo@x-uQmhThIhCj)4KkU;f$q*?i_1c>Ud|F&(9;!7LOY*04z@kpcJAhk(@#Q4Lrb9=EFN#b z`h;}@jy2Neeg;UFHL=T9FtB!nbk~DS?w){lic!V*K+M(c_lZ_rtXY(qY?)YM)aW#E zNrxw{ZF9{FF5=>mVMHfs+axf4iw7KD5^lKRM(8wS%V8S&#oKW6PwrsL=FNz90;z)7 zXmreG{!4C+&ICa7^~4skp6C0XnLu%&N!Wf8WU)-6Pg=iQb1gXmzGgdw@<7TD2Buw+8DKFM_D!ybWWafq%N>hFb2v>)t56 zxsVu76m<7p@SDqxtk${ZVYiZ1Bhw!sE5uf4Bu#c~+ZM=r3blg2YGkT5bliYLVzA6uUlwJD9JJv`>z2{x7#0QMC09&47W1j?ny{^Db3G!#{b zdI#EOY?C2>fwMd!T`~gomEAA~feu8>YAX?6y0m1+Uox;F+aYrFGAGgNr|P$0|PWZXc@F zxI^VaZ1C~Du^#aD+e183$-7fRyKra~91=Kt)MBFI8mf^!+aXP5aQzsg=bj9wkD@~f z#z5kOn37eQ^*)FQNjgMBls7(BdFyjG@sO6F$rKYUC5>z{CTl;`P}=kOCp?zKfH*;X zf>Fzc)niY7~#9l{RnS4w)uqbMZo4xYUOLCPOr1qn%}h_f!Oi#`g?Q8S?^iOZ$&CK==9_QL z*?KYyF<_xXC2;v|TG?ML1Vamcp!(!I0qIu2+^yFduphs+qm2^(eWaGdt z{`lEzdHoYNv(7r&QP|uYN1{`J&^C>HSt@NVe8j_e*SlWB#pj>I+7*UpUHV8q_Oa_& zwR(B1D>O$hhVK|B{jj-BRna@prp~kYSQVXxb`GNL&Jg0MSX!Ds*9OUgqBmB zQ5=FZmPCU@Hq@9HuWA^~$RNY3*Klxn zgp(fJ!RId9z&Win>g85~_FmaDKFMX5y_7wBGwZ8dc4Dxoq?~*1X`Fo8`W&RZYN?l3 zV=GwB1g#E@_rnDCQ+hXd8`-P7pl*!GfgAzvl<$1&-`KJJV7Kx(Qu>QT&OA|0-7v`K zKmWgJCZV8MB{0ia?ZjF_&y5eX`IUb;z@%xBT8oOq*-((3F;@vfI}s8OW_*&Vdv~Dw zCa|4G4)j@@U1}24LQ^NWWJ7~DJ#z~etZoHfYi)JoT#`nM)8Iv7O{U_t6B&Rkopws6 z-C<~WFeHjp@?!hxn?t8(ikNYuIYzNmYZ<1hbXbk!F9|Z&n^T(sJ)$wdu(*QVkkV>^ zX$%HyMC-K4qR2H$YBG~t5$|xeNy|-f-s%C~_L2)Y?`ya5Pqzl4pqz@SKt`Ig(#1A3 zlTo&#r0Ot@26ov9Iywx=0lXaK^r1<{T0%lXT9H1GsO7P9$1Zm6c@WEBPrX6_p+M^J zs#m>)$35<`C3x4KOlSe*B8pd%r=^%*frqLx(YskORrtXBKhCE={YAXb0NUo>zs3V? z-#O0CT{}5>-6{l&7l&2FlZ33U5!R2icz9zU6Plt1tntA*&*TG)rU~mJ; zz5{gj?<4JW@)I{GNQcC9c={3XUyWTnsB zyb7*gCS9KW+Y>q+QneU?Rhp6#GrUzwb%gEPwv(79>I%H1)gX#GPFlO3hI)*qJ*!S@ zviPFX&6s8utJJ%)s#*}iDjduQ`GL)wH^!IB#lJ->r`=I@?%2i2>sD8xBljFm9)v%A z>S_>+7)zpESGj0qqvR|-4FSu_Qmvp6HZ_OP!7_-jEKL#b%319GSk&0yLUIF3QxwHzUw+C+;i8xT=4L7>8jXCF1G1avA}8*$w}iqM|*26^E`62UX2oD zMk{w+@i^l{`HFi)a$^7h6kAC|K~!<5Z}zxs%#t{nb?(gc8d{lGGba<4!Wy2b`C%am zlD-9aY{Dn0v;arq+Zas(D~hC{zE_JxRpo`3O7CJd>hM`1v4W$CQHN1TC7~{ZC?cp= zZo28_*tc8Xdn}@?TQkP;RV#6l1X>133*zWq^Hz%g)~r*b>LizcH&DOY!Jd1MFt;;|%1A!xy|uDS=qm9PdQN>coTiMpqae zmJFTSi7<{E06Z2nNJM-6K0iZpv=qgVg1Mxbc(#wn=!D2x27GxeDq|roEKcc-gSvu) zrm+ststJ%5$u;wihG;dYKs$wR{p*kL-i89=Le?>}7Q7nHI%^XH4THsj+7P^-^;t+y z7(alk{lckO63 zB&aBoalcKI-P6*-D%%aJX}4!OUo=|CArw<2DI9oT*PY3OSKXwly13|^jgw65ETob2~5()7|z&q8hZVY;{};sD@NN0 zDcg7KWOVruK3cTB03*FteGw(8WSyiNjL6bY(|6UF>Q;u2vh5PTOQkn5s>SO4gp)Svu_*swl;it;u>(z(O8iBFV6+Ham4`Xa}n1=B&Bw_0T z^yr4Ak5lh!k=S6MoJBejbb;sOddy+s+-(a4Cbvt~$pOr`kWxByE| zotBKSjMYR6i!xi#ndD(;2~$$Fq#6<%A+uR-ty3e2*Pw8Qpki|n%I%?ofnZ{6&8wDC zfr^z?Jh{T(q~emQDh;OS_yngm(D7?m)V*t+SVTPyBRJ=y2$AiLD`IM(r+cosr5XdW zk`*%IBQQ#jH=pyMO8JtE6{OK&%Ngr<*SoG^(;4eSRZ+D;%j+S}y=g7LBD3>MS?9UL zMD_4mfIUpoHDkawj=V5>Ep51JAOC6ruw0$0s$6yD@A9>;--JsWF;1kYS!i#kOf$0M-#j%!Q_IZgg0O4uJh$;G+qSs!UBy@$dhBE8aB< zu8;5EoD(DZi+YQy@a^yZ2Wcmr29*1w9|Jrdr@sizW|NgG$Jn)N4AwR^PaMU z3KI&<94nuT1yf>dsq68sx=AxwS~C+H^uEs+GwU%*mdgxQ&3r7uSqT{CVnxm1KF)Lw zB7zuY^O+|XRQC>#oa~`|?nq~l=S#A>&}-~lfJb>)Yx&ieJ|D~!N+*`J9E!fe{9ZeB z_j+NIua3>7R?lRP$5_bqX_kzb$9GKkeOba|-p@-M#-_aRMb9Bg`rLl=ad#I3;QJQf zk#~H{P@?dZr(HtFrF{PHzR30+yGc8)OLJ7n>N@93WB^_y6j~P+r0q#A^u|+6*2Y$t zG|3^&(-j%FZvdShHB3jn-?)ik05Y zE@Qv3){-QK&1am<<L5}+H*gzrWT(`U>Pb8G@v+6XKm}GFFRHu$F3snSKr%H!~ zM(X-*rcz@EaSzzTxNDe_)I#~0D05+_?tVaeZyAXdjIo9L=?jI^C*A^@F_bVv7Pw1?)jToju$J;L zxS$(sLx#9Z+$njDT5$oD7H*Y!MaqN)N};t$D?71JvH(H5->rrAt^xoSW?}62EtiM{ zl9semuF~7Gmr;3X!R+a21rsftS=EBjJWi@67QIB%MT*pDnsxn}UMpn=M*Yg3(FJYo zX7ROl50bKlL`{Q>c3<}>-a90-9Q(}#3kJ@k#sTy~rT0^o6db%tv~}$}69vOXyI1h!2Gn_-$wRAlPH#Ko2FVz+{?Ris> z5w(l6IAxB{XI6;pr8Db~BRduq0Q(Ks3%qZUM4%TIP57S@Is3H7LMjzi7d<~M9(|@~ zHbWQG9!JG{##)?9_|v0lY2=!qSVGPaBgfwiF%){o!K}0Q>3t#el); zJq^&}qMn8n+}*hNOs5ApwQNVlS(=odQ(&HvQuesq>>gFdik6&c6!wmvlZ;B#Qtoc) zk}cRwO9QF2cj>g(T(Yz@qxH{@n|)__&MED#WtOw*2)#~zRX}JOl7r%FQH8GPs(YrW zw&P@Znq0{XgZ@D zW1dacDmx5w3btoSkSb?i@jIo^>XeduE3!O#NaXP z-M5dasdg*}@@1LKN-R`*9RF!DhgxEpC|_sgW0}rzw}n{qti6=VSK{A+k>L?muUdgf z8tv4+hjiS!z$MqHe{T%-{En95Z9UOGNpq_G zIlC7s5Gm$o>c${yiD&_g)hN~oR+NWqK9x7W`D!ja|6z#HywfG8`v>aQv(b;kXEQEqWc`Qf7xe+Od>sY)HkEI^oLKy_v6l;}(zv@3oRS zoB^B)k0+CnggUi0Fk)r^gNluo8J4PnQKdkQCjqH_=zQ;&bz?&lK@{El0Dcg6C^V6T*fmpEWF}{%<84;WR z)Jy=p5x)JMAAkn!Ue!(nMu$lJZY2KXrP{GZF-s#!Ny8&c&{#YcPa;0t6S_a*9Y(|J z1|Kz4T>PD!#MH!E$n0DsTAG2*EJehlPWbAVZeY4jxg`O9M#?|=22o~}ss1dsce&X2 zs$T|k%#M%+Mg{eP`Ye7{HDW3;v~IO@{%C?H&Vw@;64Z3?;%9N2r~AEXE&GCnI~~zMujQzPd)(D#?&Tj; zY_uK~vHhiXLc{SE zZ~cTcb-CqI{0gtyYn?=ZG*YUhE1X}KZa+U}1dw9*A&aHOMm>s{Te2BN5K(Lr$VQXI za`DCI@aosRoXux$4DEiRI1^jekeL@-)c5ty^107_fscOl&p2?Pjdx02&PP>yjMy1; zmI|!VWNa~zBn<|K2BIb8b9qNEzNSp23^v((Qd}tbmV|aY zW%A$z-aFLyS|nPyf*!9{dmZC0`wU&-rs?{UnZ9Ve3;u#JCa}bqP`@}hFhH|uQ0>H$ zA?a=$OA!F+?tWV1w4AU22!2MI?WI2It+d4hz}Z1{t~F#eal(q0?@VsYVkDh)j_wBEw*Ze1UNNB4S~uPMBGa$L8IPW^t!UmwQOXiipp`EiQ>Iz_GA+4D9n*E?GAm^*+!4QdN4RQzZue!O7GO%d18;lVyZORD+=z1t z>dT63TH|(?wLj|ZQ<=tfU8v>VyZM>g=TiQg=9(plU_^N7iyqJGe*0CJB#kbzt$Chx zW_Jj!$5}62f#i6<`&Y{`*-n_r~V3XFtZ;bz^Y?*`9g4Pyjqu=4c-PkBAGb^~JA;@qzbD zrV`!L(J3;m10T^NtNBp(eJXYEAU(ixaB>3YJc)6b;v%mQCuFT-)AgBY4~dG$C$Ar7^~$li7#96;yc(5@4gncwmmbZ&1>p0v@x{7Pl2C8bPBYMXdCY*S+{zSYu|b` z!$X4+jHSY?-5nay1vCn-+fbbwxxXWT5yL4hlV+A z<3^T^4q`QkM0ts{Vg4vTuf7XB>pWh}Uf@Lpz&bjt#hewh#EXsr01RZG9LD>wm;hM) zOJH|a@dP3+3#45-{ro`H3UpVuRZstQMHRZr>(UdE@$@DfWX1?Yc63$gxxVa8nUtsE zFj!E*XZ(Oi`+3!nv(mRp4;ug`hYz4?K^ zI=8fXGQ4vT8?WJp)S6%F6^zZS)@$vxR8!H#O*}tN5>-|7*Z~<`%yl!Dxo~0+)4v7% z(I5SBqK-w+0w1X|nEp6S28hlW$XmMC)t`_3(YFBmqd)qiKNj5rj6ygIGZ}l1)sx@Q znUub!w`7jE0VB0q0ZZ0qBBzX>o!NL!$D8;4T==m>kCVsHAM^A)kFpCqH^!2}1edwY z?IkpOW$B*!wBRj^3~ckkU|9h8&3@AT(H{W(Cu6!0_9kT@RR91007*qoM6N<$f~g%K Aj{pDw literal 0 HcmV?d00001 From 43adfee1740c18b53d1576bccb431e1017c22af6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 3 May 2024 22:58:11 +0200 Subject: [PATCH 1025/1848] [LoRaWAN] Shorten LORAWAN to LW --- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 4 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 954 +++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 464 ++++----- src/protocols/LoRaWAN/LoRaWANBands.cpp | 408 ++++---- 4 files changed, 915 insertions(+), 915 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index e7253f2c54..d14daac416 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -111,8 +111,8 @@ void loop() { // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { Serial.println(F("[LoRaWAN] Requesting LinkCheck and DeviceTime")); - node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); - node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); + node.sendMacCommandReq(RADIOLIB_LW_MAC_LINK_CHECK); + node.sendMacCommandReq(RADIOLIB_LW_MAC_DEVICE_TIME); state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails); } else { state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 24ea83edd2..32f61674a0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -45,8 +45,8 @@ void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA } void LoRaWANNode::wipe() { - memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); - memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + memset(this->bufferNonces, 0, RADIOLIB_LW_NONCES_BUF_SIZE); + memset(this->bufferSession, 0, RADIOLIB_LW_SESSION_BUF_SIZE); } uint8_t* LoRaWANNode::getBufferNonces() { @@ -59,14 +59,14 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { return(RADIOLIB_ERR_NONE); } - int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); RADIOLIB_ASSERT(state); // copy the whole buffer over - memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); // revert to inactive as long as no session is restored - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; return(state); } @@ -84,22 +84,22 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { return(RADIOLIB_ERR_NONE); } - int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_SESSION_BUF_SIZE); RADIOLIB_ASSERT(state); // the Nonces buffer holds a checksum signature - compare this to the signature that is in the session buffer - uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); - uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE]); + uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE]); + uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_SESSION_NONCES_SIGNATURE]); if(signatureNonces != signatureInSession) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); return(RADIOLIB_ERR_CHECKSUM_MISMATCH); } // copy the whole buffer over - memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LW_SESSION_BUF_SIZE); // as both the Nonces and session are restored, revert to active session - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; return(state); } @@ -128,65 +128,65 @@ int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) { // if already joined, ignore - if(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE) { + if(this->activeMode != RADIOLIB_LW_MODE_NONE) { return(RADIOLIB_ERR_NONE); } - bool isSameKeys = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == checkSum; - bool isSameMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]) == lwMode; - bool isSameClass = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS]) == lwClass; - bool isSamePlan = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN]) == freqPlan; + bool isSameKeys = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM]) == checkSum; + bool isSameMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE]) == lwMode; + bool isSameClass = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS]) == lwClass; + bool isSamePlan = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN]) == freqPlan; // check if Nonces buffer matches the current configuration if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { // if configuration did not match, discard whatever is currently in the buffers and start fresh RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (checksum: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Nonces buffer:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Clearing buffer and starting fresh"); this->wipe(); return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } - if(lwMode == RADIOLIB_LORAWAN_MODE_OTAA) { + if(lwMode == RADIOLIB_LW_MODE_OTAA) { // Nonces buffer is OK, so we can at least restore Nonces - this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); - this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); + this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE]); + this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], 3); } - // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; - // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { + // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LW_NONCES_VERSION]; + // if (RADIOLIB_LW_NONCES_VERSION_VAL > nvm_table_version) { // // set default values for variables that are new or something // } - if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] == 0) { + if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] == 0) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No active session in progress; please join the network"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE); return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } // pull all authentication keys from persistent storage - this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); - memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR]); + memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); // restore session parameters - this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); + this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); - this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); - this->aFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); - this->nFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); - this->confFcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); - this->confFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); - this->adrFcnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); - this->fcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); + this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID]); + this->aFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN]); + this->nFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN]); + this->confFcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP]); + this->confFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN]); + this->adrFcnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT]); + this->fcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP]); int16_t state = RADIOLIB_ERR_UNKNOWN; // for dynamic bands, first restore the defined channels before restoring ADR - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { // restore the defined channels state = this->restoreChannels(); RADIOLIB_ASSERT(state); @@ -194,74 +194,74 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass // restore the complete MAC state LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, + .cid = RADIOLIB_LW_MAC_TX_PARAM_SETUP, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, + .len = MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn, .repeat = 0, }; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd.len); + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_TX_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cmd.len); + cmd.cid = RADIOLIB_LW_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR], cmd.len); (void)execMacCommand(&cmd); // for fixed bands, first restore ADR, then the defined channels - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + if(this->band->bandType == RADIOLIB_LW_BAND_FIXED) { state = this->restoreChannels(); RADIOLIB_ASSERT(state); } - cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd.len); + cmd.cid = RADIOLIB_LW_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LW_MAC_DUTY_CYCLE].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_DUTY_CYCLE], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LW_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_RX_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd.len); + cmd.cid = RADIOLIB_LW_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_RX_TIMING_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LW_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_ADR_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_ADR_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); // copy uplink MAC command queue back in place - memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); // full session is restored, so set joined flag to whichever mode is restored - this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]); + this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE]); return(state); } int16_t LoRaWANNode::restoreChannels() { // first do the default channels, in case these are not covered by restored channels - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { this->setupChannelsDyn(false); - } else { // RADIOLIB_LORAWAN_BAND_FIXED + } else { // RADIOLIB_LW_BAND_FIXED this->setupChannelsFix(this->subBand); } uint8_t bufferZeroes[5] = { 0 }; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; - LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LW_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn; memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes cmd.repeat = 1; @@ -269,22 +269,22 @@ int16_t LoRaWANNode::restoreChannels() { } } - uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; + uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LW_SESSION_DL_CHANNELS]; - cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; + cmd.cid = RADIOLIB_LW_MAC_DL_CHANNEL; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LW_MAC_DL_CHANNEL].lenDn; memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes (void)execMacCommand(&cmd); } } - } else { // RADIOLIB_LORAWAN_BAND_FIXED - uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + } else { // RADIOLIB_LW_BAND_FIXED + uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LW_MAC_LINK_ADR, .payload = { 0 }, .len = 0, .repeat = 0, @@ -292,7 +292,7 @@ int16_t LoRaWANNode::restoreChannels() { // there are at most 8 channel masks present for(int i = 0; i < 8; i++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); // there COULD, according to spec, be an all zeroes ADR command - meh if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { @@ -312,46 +312,46 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) { memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); uint8_t drUp = 0; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { // if join datarate is user-specified and valid, select that value - if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr != RADIOLIB_LW_DATA_RATE_UNUSED) { if(initialDr >= this->band->txFreqs[0].drMin && initialDr <= this->band->txFreqs[0].drMax) { drUp = initialDr; } else { // if there is no channel that allowed the user-specified datarate, revert to default datarate RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + initialDr = RADIOLIB_LW_DATA_RATE_UNUSED; } } // if there is no (channel that allowed the) user-specified datarate, use a default datarate // we use the floor of the average datarate of the first default channel - if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr == RADIOLIB_LW_DATA_RATE_UNUSED) { drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; } } else { // if the user specified a certain datarate, check if any of the configured channels allows it - if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr != RADIOLIB_LW_DATA_RATE_UNUSED) { uint8_t i = 0; - for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - if(initialDr >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin - && initialDr <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + for(; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { + if(initialDr >= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin + && initialDr <= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax) { break; } } } // if there is no channel that allowed the user-specified datarate, revert to default datarate - if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { + if(i == RADIOLIB_LW_NUM_AVAILABLE_CHANNELS) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + initialDr = RADIOLIB_LW_DATA_RATE_UNUSED; } } // if there is no (channel that allowed the) user-specified datarate, use a default datarate // we use the join-request datarate for one of the available channels - if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(initialDr == RADIOLIB_LW_DATA_RATE_UNUSED) { // randomly select one of 8 or 9 channels and find corresponding datarate uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 @@ -365,9 +365,9 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) { } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LW_MAC_LINK_ADR, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, .repeat = 0, }; cmd.payload[0] = (drUp << 4); // set uplink datarate @@ -375,8 +375,8 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) { cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; + cmd.cid = RADIOLIB_LW_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LW_MAC_DUTY_CYCLE].lenDn; uint8_t maxDCyclePower; switch(this->band->dutyCycle) { case(0): @@ -395,21 +395,21 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) { cmd.payload[0] = maxDCyclePower; (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); + cmd.cid = RADIOLIB_LW_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LW_RX1_DR_OFFSET << 4); cmd.payload[0] |= this->rx2.drMax; // may be set by user, otherwise band's default upon initialization uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); + cmd.cid = RADIOLIB_LW_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LW_RECEIVE_DELAY_1_MS / 1000); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; + cmd.cid = RADIOLIB_LW_MAC_TX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn; cmd.payload[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; cmd.payload[0] |= (this->band->dwellTimeUp > 0 ? 1 : 0) << 4; uint8_t maxEIRPRaw; @@ -436,16 +436,16 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) { cmd.payload[0] |= maxEIRPRaw; (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); - cmd.payload[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + cmd.cid = RADIOLIB_LW_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_ADR_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LW_ADR_ACK_LIMIT_EXP << 4); + cmd.payload[0] |= RADIOLIB_LW_ADR_ACK_DELAY_EXP; (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); - cmd.payload[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; + cmd.cid = RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LW_REJOIN_MAX_TIME_N << 4); + cmd.payload[0] |= RADIOLIB_LW_REJOIN_MAX_COUNT_N; (void)execMacCommand(&cmd); } @@ -468,10 +468,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // if The Force is used, disable the active session; // as a result, restore() will only restore Nonces if they are available, not the session if(force) { - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; } - state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_OTAA, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + state = this->restore(checkSum, RADIOLIB_LW_MODE_OTAA, RADIOLIB_LW_CLASS_A, this->band->bandNum); if(!force) { return(state); @@ -480,7 +480,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe Module* mod = this->phyLayer->getMod(); // setup join-request uplink/downlink frequencies and datarates - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { state = this->setupChannelsDyn(true); } else { state = this->setupChannelsFix(this->subBand); @@ -489,8 +489,8 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // on fixed bands, the join-datarate is specified per specification // therefore, we ignore the value that was specified by the user - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { - joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + if(this->band->bandType == RADIOLIB_LW_BAND_FIXED) { + joinDr = RADIOLIB_LW_DATA_RATE_UNUSED; } // setup all MAC properties to default values this->beginCommon(joinDr); @@ -500,7 +500,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe RADIOLIB_ASSERT(state); // set the physical layer configuration for uplink - state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + state = this->setPhyProperties(RADIOLIB_LW_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // copy devNonce currently in use @@ -508,42 +508,42 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // increment devNonce as we are sending another join-request this->devNonce += 1; - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE], this->devNonce); // build the join-request message - uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; + uint8_t joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN]; // set the packet fields - joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); + joinRequestMsg[0] = RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LW_MHDR_MAJOR_R1; + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS], devEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code - uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); + uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); // send it - state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN); this->rxDelayStart = mod->hal->millis(); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); RADIOLIB_ASSERT(state); // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received - this->rxDelays[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; - this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; + this->rxDelays[0] = RADIOLIB_LW_JOIN_ACCEPT_DELAY_1_MS; + this->rxDelays[1] = RADIOLIB_LW_JOIN_ACCEPT_DELAY_2_MS; // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received state = downlinkCommon(); RADIOLIB_ASSERT(state); // build the buffer for the reply data - uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; + uint8_t joinAcceptMsgEnc[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN]; // check received length size_t lenRx = this->phyLayer->getPacketLength(true); - if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + if((lenRx != RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN, lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -556,24 +556,24 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } // check reply message type - if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + if((joinAcceptMsgEnc[0] & RADIOLIB_LW_MHDR_MTYPE_MASK) != RADIOLIB_LW_MHDR_MTYPE_JOIN_ACCEPT) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LW_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } // decrypt the join accept message // this is done by encrypting again in ECB mode // the first byte is the MAC header which is not encrypted - uint8_t joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; + uint8_t joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN]; joinAcceptMsg[0] = joinAcceptMsgEnc[0]; RadioLibAES128Instance.init(nwkKey); - RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); + RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); // get current JoinNonce from downlink and previous JoinNonce from persistent storage - uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_JOIN_NONCE_POS], 3); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); // JoinNonce received must be greater than the last JoinNonce heard, else error @@ -582,26 +582,26 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } this->joinNonce = joinNonceNew; - this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); - this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); + this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], 3); + this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS]); // check LoRaWAN revision (the MIC verification depends on this) - uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; - this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; + uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_DL_SETTINGS_POS]; + this->rev = (dlSettings & RADIOLIB_LW_JOIN_ACCEPT_R_1_1) >> 7; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN revision: 1.%d", this->rev); // verify MIC if(this->rev == 1) { // 1.1 version, first we need to derive the join accept integrity key uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY; LoRaWANNode::hton(&keyDerivationBuff[1], devEUI); RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey); // prepare the buffer for MIC calculation uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; + micBuff[0] = RADIOLIB_LW_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], joinEUI); LoRaWANNode::hton(&micBuff[9], devNonceUsed); memcpy(&micBuff[11], joinAcceptMsg, lenRx); @@ -619,9 +619,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, + .cid = RADIOLIB_LW_MAC_RX_PARAM_SETUP, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, + .len = MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn, .repeat = 0, }; cmd.payload[0] = dlSettings & 0x7F; @@ -629,68 +629,68 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + cmd.cid = RADIOLIB_LW_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_RX_DELAY_POS]; (void)execMacCommand(&cmd); // in case of dynamic band, setup the default channels first - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { this->setupChannelsDyn(false); } // process CFlist if present - if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { - uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; - memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); + if(lenRx == RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN) { + uint8_t cfList[RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; + memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN); this->processCFList(cfList); } // if no CFList was received, default or subband are already setup so don't need to do anything else // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); // check protocol version (1.0 vs 1.1) if(this->rev == 1) { // 1.1 version, derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey); - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY; + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); // enqueue the RekeyInd MAC command to be sent in the next uplink LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_REKEY, + .cid = RADIOLIB_LW_MAC_REKEY, .payload = { this->rev }, .len = sizeof(uint8_t), - .repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP, + .repeat = 0x01 << RADIOLIB_LW_ADR_ACK_LIMIT_EXP, }; state = pushMacCommand(&cmd, &this->commandsUp); RADIOLIB_ASSERT(state); } else { // 1.0 version, just derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); - keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); @@ -703,24 +703,24 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe this->fcntUp = 0; this->aFcntDown = 0; this->nFcntDown = 0; - this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; - this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntUp = RADIOLIB_LW_FCNT_NONE; + this->confFcntDown = RADIOLIB_LW_FCNT_NONE; this->adrFcnt = 0; // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_OTAA); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_VERSION], RADIOLIB_LW_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_OTAA); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], this->joinNonce, 3); - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; - this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; + this->activeMode = RADIOLIB_LW_MODE_OTAA; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); return(RADIOLIB_ERR_NONE); } @@ -745,10 +745,10 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk // if The Force is used, disable the active session; // as a result, restore() will not restore the session (and there are no Nonces in ABP mode) if(force) { - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; } - state = this->restore(checkSum, RADIOLIB_LORAWAN_MODE_ABP, RADIOLIB_LORAWAN_CLASS_A, this->band->bandNum); + state = this->restore(checkSum, RADIOLIB_LW_MODE_ABP, RADIOLIB_LW_CLASS_A, this->band->bandNum); if(!force) { return(state); @@ -768,7 +768,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk } // setup the uplink/downlink channels and initial datarate - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { this->setupChannelsDyn(); } else { this->setupChannelsFix(this->subBand); @@ -781,61 +781,61 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk this->fcntUp = 0; this->aFcntDown = 0; this->nFcntDown = 0; - this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; - this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntUp = RADIOLIB_LW_FCNT_NONE; + this->confFcntDown = RADIOLIB_LW_FCNT_NONE; this->adrFcnt = 0; // save the activation keys checksum, mode, class, frequency plan - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_ABP); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_VERSION], RADIOLIB_LW_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_ABP); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum); - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; - this->activeMode = RADIOLIB_LORAWAN_MODE_ABP; + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; + this->activeMode = RADIOLIB_LW_MODE_ABP; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); return(RADIOLIB_ERR_NONE); } bool LoRaWANNode::isJoined() { - return(this->activeMode != RADIOLIB_LORAWAN_MODE_NONE); + return(this->activeMode != RADIOLIB_LW_MODE_NONE); } int16_t LoRaWANNode::saveSession() { // store DevAddr and all keys - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); // copy the signature of the Nonces buffer over to the Session buffer - uint16_t noncesSignature = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], noncesSignature); + uint16_t noncesSignature = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE]); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], noncesSignature); // store network parameters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev); // store all frame counters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN], this->aFcntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN], this->nFcntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP], this->confFcntUp); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFcntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFcnt); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN], this->aFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN], this->nFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP], this->confFcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN], this->confFcntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT], this->adrFcnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP], this->fcntUp); // save the current uplink MAC command queue - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LW_SESSION_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_SIGNATURE], signature); return(RADIOLIB_ERR_NONE); } @@ -875,7 +875,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf return(RADIOLIB_ERR_INVALID_PORT); } // port 0 is only allowed for MAC-only payloads - if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if(port == RADIOLIB_LW_FPORT_MAC_COMMAND) { if (!this->isMACPayload) { return(RADIOLIB_ERR_INVALID_PORT); } @@ -887,16 +887,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; - if(this->commandsUp.numCommands > 0 && port != RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if(this->commandsUp.numCommands > 0 && port != RADIOLIB_LW_FPORT_MAC_COMMAND) { // there are, assume the maximum possible FOpts len for buffer allocation foptsLen = this->commandsUp.len; } // check maximum payload len as defined in phy - if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { + if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); // if testing with TS009 specification verification protocol, don't throw error but clip the message - // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; + // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]]; } bool adrAckReq = false; @@ -930,8 +930,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf break; case(2): { // try to decrease the datarate - if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { - if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { + if(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] > 0) { + if(this->setDatarate(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { adrStage = 0; // successfully did some ADR stuff } } @@ -941,7 +941,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } break; case(3): { - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { this->setupChannelsDyn(false); // revert to default frequencies } else { // go back to default selected subband @@ -961,17 +961,17 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // set the physical layer configuration for uplink this->selectChannels(); - state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); + state = this->setPhyProperties(RADIOLIB_LW_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // if dwell time is imposed, calculated expected time on air and cancel if exceeds - if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { + if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LW_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); + size_t uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, foptsLen); #if RADIOLIB_STATIC_ONLY uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -980,36 +980,36 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // set the packet fields if(isConfirmed) { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; + uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] = RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_UP; this->confFcntUp = this->fcntUp; } else { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP; + uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] = RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_UP; } - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] |= RADIOLIB_LORAWAN_MHDR_MAJOR_R1; - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); + uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] |= RADIOLIB_LW_MHDR_MAJOR_R1; + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS], this->devAddr); // length of fopts will be added later - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; + uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] = 0x00; if(this->adrEnabled) { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; + uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ADR_ENABLED; if(adrAckReq) { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ADR_ACK_REQ; } } // if the saved confirm-fcnt is set, set the ACK bit bool isConfirmingDown = false; - if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { + if(this->confFcntDown != RADIOLIB_LW_FCNT_NONE) { isConfirmingDown = true; - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; + uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ACK; } - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fcntUp); + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_FCNT_POS], (uint16_t)this->fcntUp); // check if we have some MAC commands to append if(foptsLen > 0) { // assume maximum possible buffer size - uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; + uint8_t foptsBuff[RADIOLIB_LW_FHDR_FOPTS_MAX_LEN]; uint8_t* foptsPtr = foptsBuff; // append all MAC replies into fopts buffer @@ -1031,41 +1031,41 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } } - uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen); - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= foptsLen; + uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, foptsLen); + uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= foptsLen; // encrypt it - processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x01, true); } // set the port - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] = port; + uplinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] = port; // select encryption key based on the target port uint8_t* encKey = this->appSKey; - if(port == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if(port == RADIOLIB_LW_FPORT_MAC_COMMAND) { encKey = this->nwkSEncKey; } // encrypt the frame payload - processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; - block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; - LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], this->fcntUp); - block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); + block0[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; + block0[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_UPLINK; + LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_FCNT_POS], this->fcntUp); + block0[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); - if(this->confFcntDown != RADIOLIB_LORAWAN_FCNT_NONE) { - LoRaWANNode::hton(&block1[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntDown); + if(this->confFcntDown != RADIOLIB_LW_FCNT_NONE) { + LoRaWANNode::hton(&block1[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntDown); } - block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; - block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; + block1[RADIOLIB_LW_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; + block1[RADIOLIB_LW_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK].idx; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fcntUp); @@ -1091,14 +1091,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } // send it (without the MIC calculation blocks) - state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); + state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LW_FHDR_LEN_START_OFFS); // set the timestamp so that we can measure when to start receiving this->rxDelayStart = mod->hal->millis(); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); // calculate Time on Air of this uplink in milliseconds - this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; + this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LW_FHDR_LEN_START_OFFS) / 1000; #if !RADIOLIB_STATIC_ONLY delete[] uplinkMsg; @@ -1106,14 +1106,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf RADIOLIB_ASSERT(state); // the downlink confirmation was acknowledged, so clear the counter value - this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LW_FCNT_NONE; // pass the extra info if requested if(event) { - event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + event->dir = RADIOLIB_LW_CHANNEL_DIR_UPLINK; event->confirmed = isConfirmed; event->confirming = isConfirmingDown; - event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; event->fcnt = this->fcntUp; @@ -1147,7 +1147,7 @@ int16_t LoRaWANNode::downlinkCommon() { } // set the physical layer configuration for downlink - int16_t state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); + int16_t state = this->setPhyProperties(RADIOLIB_LW_CHANNEL_DIR_DOWNLINK); RADIOLIB_ASSERT(state); // create the masks that are required for receiving downlinks @@ -1280,7 +1280,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a port - if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { + if(downlinkMsgLen < RADIOLIB_LW_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -1295,10 +1295,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // set the MIC calculation block memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); - downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; - downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); + downlinkMsg[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); + downlinkMsg[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_DOWNLINK; + downlinkMsg[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); // read the data state = this->phyLayer->readData(&downlinkMsg[RADIOLIB_AES128_BLOCK_SIZE], downlinkMsgLen); @@ -1316,18 +1316,18 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // get the frame counter and set it to the MIC calculation block - uint16_t fcnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt16); + uint16_t fcnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_FCNT_POS]); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_FCNT_POS], fcnt16); // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fcntUp bool isConfirmingUp = false; - if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK) && (this->rev == 1)) { + if((downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FCTRL_ACK) && (this->rev == 1)) { isConfirmingUp = true; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); } // calculate length of FOpts and payload - uint8_t foptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + uint8_t foptsLen = downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FHDR_FOPTS_LEN_MASK; int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload @@ -1340,7 +1340,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) isAppDownlink = false; } } - else if(downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + else if(downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] == RADIOLIB_LW_FPORT_MAC_COMMAND) { foptsLen = payLen - 1; if(this->rev == 1) { isAppDownlink = false; @@ -1363,7 +1363,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error uint32_t fcnt32 = fcnt16; if(fcntDownPrev > 0) { - if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { + if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LW_MAX_FCNT_GAP)) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1395,13 +1395,13 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) bool isConfirmedDown = false; - if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { + if((downlinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_DOWN) { this->confFcntDown = this->aFcntDown; isConfirmedDown = true; } // check the address - uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); + uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); #if !RADIOLIB_STATIC_ONLY @@ -1414,7 +1414,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) if(foptsLen > 0) { // there are some Fopts, decrypt them #if !RADIOLIB_STATIC_ONLY - uint8_t* fopts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + uint8_t* fopts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LW_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; #else uint8_t fopts[RADIOLIB_STATIC_ARRAY_SIZE]; #endif @@ -1422,11 +1422,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey - if(foptsLen <= RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK) { + if(foptsLen <= RADIOLIB_LW_FHDR_FOPTS_LEN_MASK) { uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, ctrId, true); } else { - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); } bool hasADR = false; @@ -1439,9 +1439,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) while(remLen > 0) { uint8_t cid = *foptsPtr; uint8_t macLen = getMacPayloadLength(cid); - if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + if(cid == RADIOLIB_LW_MAC_LINK_ADR) { // if there was an earlier ADR command but it was not the last, ignore it - if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { + if(hasADR && lastCID != RADIOLIB_LW_MAC_LINK_ADR) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); remLen -= (macLen + 1); foptsPtr += (macLen + 1); @@ -1458,7 +1458,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .cid = cid, .payload = { 0 }, .len = macLen, - .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), + .repeat = (cid == RADIOLIB_LW_MAC_LINK_ADR ? numADR : (uint8_t)0), }; memcpy(cmd.payload, foptsPtr + 1, macLen); @@ -1479,7 +1479,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #endif // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink - if(this->commandsUp.len > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + if(this->commandsUp.len > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { size_t foptsBufSize = this->commandsUp.len; #if RADIOLIB_STATIC_ONLY uint8_t foptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -1511,7 +1511,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) bool prevDC = this->dutyCycleEnabled; this->dutyCycleEnabled = false; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); - state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LW_FPORT_MAC_COMMAND); RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); this->dutyCycleEnabled = prevDC; @@ -1522,7 +1522,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #if RADIOLIB_STATIC_ONLY uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; #else - uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; + uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK]]]; #endif size_t lenDown = 0; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Receiving after MAC-only uplink .. "); @@ -1541,18 +1541,18 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // pass the extra info if requested if(event) { - event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + event->dir = RADIOLIB_LW_CHANNEL_DIR_DOWNLINK; event->confirmed = isConfirmedDown; event->confirming = isConfirmingUp; - event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; + event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; - event->port = isAppDownlink ? downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; + event->port = isAppDownlink ? downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LW_FPORT_MAC_COMMAND; } // process Application payload (if there is any) - if(payLen <= 0 || foptsLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + if(payLen <= 0 || foptsLen > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { // no payload *len = 0; #if !RADIOLIB_STATIC_ONLY @@ -1565,7 +1565,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) *len = payLen - 1; // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; @@ -1678,7 +1678,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { RADIOLIB_ASSERT(state); // if this channel is an FSK channel, toggle the FSK switch - if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LW_DATA_RATE_FSK_50_K) { this->FSK = true; } else { this->FSK = false; @@ -1707,7 +1707,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { } // downlink messages are sent with inverted IQ - if(dir == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { + if(dir == RADIOLIB_LW_CHANNEL_DIR_DOWNLINK) { if(!this->FSK) { state = this->phyLayer->invertIQ(true); RADIOLIB_ASSERT(state); @@ -1719,15 +1719,15 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { uint8_t syncWordLen = 0; size_t preLen = 0; if(this->FSK) { - preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; - syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); - syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); - syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; + preLen = 8*RADIOLIB_LW_GFSK_PREAMBLE_LEN; + syncWord[0] = (uint8_t)(RADIOLIB_LW_GFSK_SYNC_WORD >> 16); + syncWord[1] = (uint8_t)(RADIOLIB_LW_GFSK_SYNC_WORD >> 8); + syncWord[2] = (uint8_t)RADIOLIB_LW_GFSK_SYNC_WORD; syncWordLen = 3; } else { - preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; - syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; + preLen = RADIOLIB_LW_LORA_PREAMBLE_LEN; + syncWord[0] = RADIOLIB_LW_LORA_SYNC_WORD; syncWordLen = 1; } @@ -1745,38 +1745,38 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { size_t num = 0; // copy the default defined channels into the first slots (where Tx = Rx) for(; num < 3 && this->band->txFreqs[num].enabled; num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; } // if we're about to send a join-request, copy the join-request channels to the next slots if(joinRequest) { size_t numJR = 0; for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; } } // clear all remaining channels - for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(; num < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; num++) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LW_CHANNEL_NONE; } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + for (int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMax ); } } @@ -1790,8 +1790,8 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); // clear all existing channels - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LW_CHANNEL_NONE; } // if no subband is selected by user, cycle through banks of 8 using devNonce value @@ -1827,18 +1827,18 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { int16_t LoRaWANNode::processCFList(uint8_t* cfList) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { // retrieve number of existing (default) channels size_t num = 0; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(!this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(!this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { break; } num++; } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, + .cid = RADIOLIB_LW_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0, @@ -1846,19 +1846,19 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { // datarate range for all new channels is equal to the default channels cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; for(uint8_t i = 0; i < 5; i++, num++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; + cmd.len = MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn; cmd.payload[0] = num; memcpy(&cmd.payload[1], &cfList[i*3], 3); (void)execMacCommand(&cmd); } - } else { // RADIOLIB_LORAWAN_BAND_FIXED + } else { // RADIOLIB_LW_BAND_FIXED // complete channel mask received, so clear all existing channels - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LW_CHANNEL_NONE; } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LW_MAC_LINK_ADR, .payload = { 0 }, .len = 0, .repeat = 0, @@ -1867,7 +1867,7 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; cmd.payload[0] = 0xFF; // same datarate and payload memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); // copy mask cmd.payload[3] = chMaskCntl << 4; // set chMaskCntl, set NbTrans = 0 -> keep the same @@ -1882,11 +1882,11 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { int16_t LoRaWANNode::selectChannels() { // figure out which channel IDs are enabled (chMask may have disabled some) and are valid for the current datarate uint8_t numChannels = 0; - uint8_t channelsEnabled[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin - && this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { + uint8_t channelsEnabled[RADIOLIB_LW_NUM_AVAILABLE_CHANNELS]; + for(uint8_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { + if(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin + && this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax) { channelsEnabled[numChannels] = i; numChannels++; } @@ -1898,26 +1898,26 @@ int16_t LoRaWANNode::selectChannels() { } // select a random ID & channel from the list of enabled and possible channels uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; + this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][channelID]; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { // for dynamic bands, the downlink channel is the one matched to the uplink channel - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; + this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][channelID]; - } else { // RADIOLIB_LORAWAN_BAND_FIXED + } else { // RADIOLIB_LW_BAND_FIXED // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels LoRaWANChannel_t channelDn; channelDn.enabled = true; - channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; + channelDn.idx = this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; channelDn.drMin = this->band->rx1Span.drMin; channelDn.drMax = this->band->rx1Span.drMax; - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn; + this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = channelDn; } - uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = drDown; return(RADIOLIB_ERR_NONE); } @@ -1925,8 +1925,8 @@ int16_t LoRaWANNode::selectChannels() { int16_t LoRaWANNode::setDatarate(uint8_t drUp) { // scan through all enabled channels and check if the requested datarate is available bool isValidDR = false; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); + for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i]); if(chnl->enabled) { if(drUp >= chnl->drMin && drUp <= chnl->drMax) { isValidDR = true; @@ -1940,9 +1940,9 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp) { } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LW_MAC_LINK_ADR, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, .repeat = 0, }; cmd.payload[0] = (drUp << 4); @@ -2006,7 +2006,7 @@ uint8_t LoRaWANNode::maxPayloadDwellTime() { // configure current datarate DataRate_t dr; // TODO this may fail horribly? - (void)findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); + (void)findDataRate(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK], &dr); (void)this->phyLayer->setDataRate(dr); uint8_t minPayLen = 0; uint8_t maxPayLen = 255; @@ -2031,12 +2031,12 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower) { // Tx Power is set in steps of two // the selected value is rounded down to nearest multiple of two away from txPowerMax // e.g. on EU868, max is 16; if 13 is selected then we set to 12 - uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM); + uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LW_POWER_STEP_SIZE_DBM); LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, + .cid = RADIOLIB_LW_MAC_LINK_ADR, .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, .repeat = 0, }; cmd.payload[0] = 0xF0; // keep datarate the same @@ -2058,20 +2058,20 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { uint8_t dataRateBand = this->band->dataRates[dr]; - if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { + if(dataRateBand & RADIOLIB_LW_DATA_RATE_FSK_50_K) { dataRate->fsk.bitRate = 50; dataRate->fsk.freqDev = 25; } else { uint8_t bw = dataRateBand & 0x0C; switch(bw) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + case(RADIOLIB_LW_DATA_RATE_BW_125_KHZ): dataRate->lora.bandwidth = 125.0; break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + case(RADIOLIB_LW_DATA_RATE_BW_250_KHZ): dataRate->lora.bandwidth = 250.0; break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + case(RADIOLIB_LW_DATA_RATE_BW_500_KHZ): dataRate->lora.bandwidth = 500.0; break; default: @@ -2089,7 +2089,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { bool valid = false; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { + for(size_t i = 0; i < RADIOLIB_LW_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { valid = MacTable[i].user; } @@ -2100,11 +2100,11 @@ int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { } // if there are already 15 MAC bytes in the uplink queue, we can't add a new one - if(this->commandsUp.len + 1 > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + if(this->commandsUp.len + 1 > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The maximum number of FOpts payload was reached"); return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } - if(this->commandsUp.numCommands > RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { + if(this->commandsUp.numCommands > RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The RadioLib internal MAC command queue was full"); return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } @@ -2123,7 +2123,7 @@ int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { } int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { - if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { + if(queue->numCommands >= RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE) { return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } @@ -2143,11 +2143,11 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que } queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload // move all subsequent commands one forward in the queue - if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { - memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); + if(index < RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE - 1) { + memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); } // set the latest element to all 0 - memset(&queue->commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); + memset(&queue->commands[RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); queue->numCommands--; return(RADIOLIB_ERR_NONE); } @@ -2160,34 +2160,34 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02X", cmd->cid); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); - if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { + if(cmd->cid >= RADIOLIB_LW_MAC_PROPRIETARY) { // TODO call user-provided callback for proprietary MAC commands? return(false); } switch(cmd->cid) { - case(RADIOLIB_LORAWAN_MAC_RESET): { + case(RADIOLIB_LW_MAC_RESET): { // get the server version uint8_t srvVersion = cmd->payload[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command - deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); + deleteMacCommand(RADIOLIB_LW_MAC_RESET, &this->commandsUp); } return(false); } break; - case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + case(RADIOLIB_LW_MAC_LINK_CHECK): { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); // delete any existing response (does nothing if there is none) - deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); + deleteMacCommand(RADIOLIB_LW_MAC_LINK_CHECK, &this->commandsDown); // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; - case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { + case(RADIOLIB_LW_MAC_LINK_ADR): { int16_t state = RADIOLIB_ERR_UNKNOWN; // get the ADR configuration uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; @@ -2204,16 +2204,16 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { if(drUp == 0x0F) { // keep the same drAck = 1; - } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + } else if (this->band->dataRates[drUp] != RADIOLIB_LW_DATA_RATE_UNUSED) { // check if the module supports this data rate DataRate_t dr; state = findDataRate(drUp, &dr); if(state == RADIOLIB_ERR_NONE) { uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMin, + this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] = drUp; + this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = drDown; drAck = 1; } else { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); @@ -2245,22 +2245,22 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // only apply channel mask when the RFU bit is not set // (which is only set in internal MAC commands for changing Tx/Dr) if(!isInternalTxDr) { - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); - } else { // RADIOLIB_LORAWAN_BAND_FIXED + } else { // RADIOLIB_LW_BAND_FIXED if(cmd->repeat == 1) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LW_CHANNEL_NONE; } // clear all previous channel masks - memset(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS], 0, 16*8); + memset(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS], 0, 16*8); } else { // if this is not the first ADR command, clear the ADR response that was in the queue - (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); + (void)deleteMacCommand(RADIOLIB_LW_MAC_LINK_ADR, &this->commandsUp); } chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask); @@ -2275,7 +2275,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state // but we don't bother and try to set each individual command if(drUp == 0x0F || !drAck) { - cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); + cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] << 4); } if(txSteps == 0x0F || !pwrAck) { cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; @@ -2284,10 +2284,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; } - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte if(isInternalTxDr) { - memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, 3); + memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR] + 1, 3); } // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again @@ -2296,24 +2296,24 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } // save to the single ADR MAC location - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); - } else { // RADIOLIB_LORAWAN_BAND_FIXED + } else { // RADIOLIB_LW_BAND_FIXED // save Tx/Dr to the Link ADR position in the session buffer - uint8_t bufTxDr[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + uint8_t bufTxDr[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; bufTxDr[0] = cmd->payload[0]; bufTxDr[3] = 1 << 7; - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR], bufTxDr, cmd->len); // if RFU bit is set, this is just a change in Datarate or TxPower, in which case we don't save the channel masks // if the RFU bit is not set, we must save this channel mask if(!isInternalTxDr) { // save the channel mask to the uplink channels position in session buffer, with Tx and DR set to 'same' cmd->payload[0] = 0xFF; - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving mask to ULChannels[%d]:", (cmd->repeat - 1) * cmd->len); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); } } @@ -2326,7 +2326,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { + case(RADIOLIB_LW_MAC_DUTY_CYCLE): { uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); if(maxDutyCycle == 0) { @@ -2335,13 +2335,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { this->dutyCycle = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000 / (RadioLibTime_t)(1UL << maxDutyCycle); } - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; - case(RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP): { + case(RADIOLIB_LW_MAC_RX_PARAM_SETUP): { // get the configuration this->rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; uint8_t rx1OffsAck = 1; @@ -2355,10 +2355,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t chanAck = 0; if(this->phyLayer->setFrequency(this->rx2.freq) == RADIOLIB_ERR_NONE) { chanAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].freq); } - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); // TODO this should be sent repeatedly until the next downlink cmd->len = 1; @@ -2367,7 +2367,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { + case(RADIOLIB_LW_MAC_DEV_STATUS): { // set the uplink reply RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); cmd->len = 2; @@ -2379,7 +2379,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LORAWAN_MAC_NEW_CHANNEL): { + case(RADIOLIB_LW_MAC_NEW_CHANNEL): { // get the configuration uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); @@ -2390,38 +2390,38 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t newChAck = 0; uint8_t freqAck = 0; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled = true; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq = freq; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].enabled = true; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].freq = freq; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; // downlink channel is identical to uplink channel - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex]; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex]; newChAck = 1; // check if the frequency is possible - if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { + if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { freqAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].freq); } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq:"); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMax, + + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].drMax ); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // send the reply cmd->len = 1; @@ -2431,7 +2431,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LORAWAN_MAC_DL_CHANNEL): { + case(RADIOLIB_LW_MAC_DL_CHANNEL): { // get the configuration uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); @@ -2443,21 +2443,21 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // check if the frequency is possible if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { freqDlAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].freq); } // update the downlink frequency - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq = freq; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq = freq; // check if the corresponding uplink frequency is actually set - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq > 0) { freqUlAck = 1; } } } - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // TODO send this repeatedly until a downlink is received cmd->len = 1; @@ -2467,7 +2467,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { + case(RADIOLIB_LW_MAC_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); @@ -2479,7 +2479,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { this->rxDelays[0] = delay * 1000; this->rxDelays[1] = this->rxDelays[0] + 1000; - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); // send the reply cmd->len = 0; @@ -2488,7 +2488,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP): { + case(RADIOLIB_LW_MAC_TX_PARAM_SETUP): { uint8_t dlDwell = (cmd->payload[0] & 0x20) >> 5; uint8_t ulDwell = (cmd->payload[0] & 0x10) >> 4; uint8_t maxEirpRaw = cmd->payload[0] & 0x0F; @@ -2499,50 +2499,50 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); this->dwellTimeEnabledUp = ulDwell ? true : false; - this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; + this->dwellTimeUp = ulDwell ? RADIOLIB_LW_DWELL_TIME : 0; this->dwellTimeEnabledDn = dlDwell ? true : false; - this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; + this->dwellTimeDn = dlDwell ? RADIOLIB_LW_DWELL_TIME : 0; - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; - case(RADIOLIB_LORAWAN_MAC_REKEY): { + case(RADIOLIB_LW_MAC_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command - deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); + deleteMacCommand(RADIOLIB_LW_MAC_REKEY, &this->commandsUp); } return(false); } break; - case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { + case(RADIOLIB_LW_MAC_ADR_PARAM_SETUP): { this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; this->adrDelayExp = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; - case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + case(RADIOLIB_LW_MAC_DEVICE_TIME): { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); // delete any existing response (does nothing if there is none) - deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); + deleteMacCommand(RADIOLIB_LW_MAC_DEVICE_TIME, &this->commandsDown); // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; - case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { + case(RADIOLIB_LW_MAC_FORCE_REJOIN): { // TODO implement this uint16_t rejoinReq = LoRaWANNode::ntoh(cmd->payload); uint8_t period = (rejoinReq & 0x3800) >> 11; @@ -2557,13 +2557,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(false); } break; - case(RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP): { + case(RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP): { // TODO implement this uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; cmd->payload[0] = (1 << 1) | 1; @@ -2579,42 +2579,42 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskCntl == 0) { // apply the mask by looking at each channel bit if(chMask & (1UL << i)) { // if it should be enabled but is not currently defined, stop immediately - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LW_CHANNEL_INDEX_NONE) { return(false); } - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled = true; } else { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled = false; } } else if(chMaskCntl == 6) { // enable all defined channels - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LW_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled = true; } } } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + for (int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMax ); } } @@ -2627,8 +2627,8 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { // find out how many channels have already been configured uint8_t idx = 0; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { + for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq > 0) { idx++; } } @@ -2646,7 +2646,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; } } @@ -2668,7 +2668,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; } } @@ -2687,7 +2687,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; } // enable single channel from second span uint8_t chNum = 64 + i; @@ -2696,7 +2696,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; } } @@ -2717,16 +2717,16 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; } } } if(this->band->numTxSpans == 2 && chMaskCntl == 7) { // all channels off (clear all channels) - LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl; + LoRaWANChannel_t chnl = RADIOLIB_LW_CHANNEL_NONE; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = chnl; // downlink channels are not defined so don't need to reset } idx = 0; @@ -2741,26 +2741,26 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; } } } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + for (int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMax ); } } @@ -2779,8 +2779,8 @@ uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { } int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { - uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); + uint8_t payload[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + int16_t state = deleteMacCommand(RADIOLIB_LW_LINK_CHECK_REQ, &this->commandsDown, payload); RADIOLIB_ASSERT(state); if(margin) { *margin = payload[0]; } @@ -2790,8 +2790,8 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { } int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { - uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); + uint8_t payload[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + int16_t state = deleteMacCommand(RADIOLIB_LW_MAC_DEVICE_TIME, &this->commandsDown, payload); RADIOLIB_ASSERT(state); if(gpsEpoch) { @@ -2868,11 +2868,11 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out // generate the encryption blocks uint8_t encBuffer[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; uint8_t encBlock[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; - encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS] = ctrId; - encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = dir; - LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fcnt); + encBlock[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_ENC_BLOCK_MAGIC; + encBlock[RADIOLIB_LW_ENC_BLOCK_COUNTER_ID_POS] = ctrId; + encBlock[RADIOLIB_LW_BLOCK_DIR_POS] = dir; + LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_FCNT_POS], fcnt); // now encrypt the input // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext @@ -2880,7 +2880,7 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out for(size_t i = 0; i < numBlocks; i++) { if(counter) { - encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; + encBlock[RADIOLIB_LW_ENC_BLOCK_COUNTER_POS] = i + 1; } // encrypt the buffer diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 9359c2ae28..b79d7931ae 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1,200 +1,200 @@ -#if !defined(_RADIOLIB_LORAWAN_H) && !RADIOLIB_EXCLUDE_LORAWAN -#define _RADIOLIB_LORAWAN_H +#if !defined(_RADIOLIB_LW_H) && !RADIOLIB_EXCLUDE_LORAWAN +#define _RADIOLIB_LW_H #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" #include "../../utils/Cryptography.h" // activation mode -#define RADIOLIB_LORAWAN_MODE_OTAA (0x07AA) -#define RADIOLIB_LORAWAN_MODE_ABP (0x0AB9) -#define RADIOLIB_LORAWAN_MODE_NONE (0x0000) +#define RADIOLIB_LW_MODE_OTAA (0x07AA) +#define RADIOLIB_LW_MODE_ABP (0x0AB9) +#define RADIOLIB_LW_MODE_NONE (0x0000) // operation mode -#define RADIOLIB_LORAWAN_CLASS_A (0x0A) -#define RADIOLIB_LORAWAN_CLASS_B (0x0B) -#define RADIOLIB_LORAWAN_CLASS_C (0x0C) +#define RADIOLIB_LW_CLASS_A (0x0A) +#define RADIOLIB_LW_CLASS_B (0x0B) +#define RADIOLIB_LW_CLASS_C (0x0C) // preamble format -#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) -#define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) -#define RADIOLIB_LORAWAN_GFSK_SYNC_WORD (0xC194C1) -#define RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN (5) +#define RADIOLIB_LW_LORA_SYNC_WORD (0x34) +#define RADIOLIB_LW_LORA_PREAMBLE_LEN (8) +#define RADIOLIB_LW_GFSK_SYNC_WORD (0xC194C1) +#define RADIOLIB_LW_GFSK_PREAMBLE_LEN (5) // MAC header field encoding MSB LSB DESCRIPTION -#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request -#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT (0x01 << 5) // 7 5 join accept -#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP (0x02 << 5) // 7 5 unconfirmed data up -#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_DOWN (0x03 << 5) // 7 5 unconfirmed data down -#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP (0x04 << 5) // 7 5 confirmed data up -#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN (0x05 << 5) // 7 5 confirmed data down -#define RADIOLIB_LORAWAN_MHDR_MTYPE_PROPRIETARY (0x07 << 5) // 7 5 proprietary -#define RADIOLIB_LORAWAN_MHDR_MTYPE_MASK (0x07 << 5) // 7 5 bitmask of all possible options -#define RADIOLIB_LORAWAN_MHDR_MAJOR_R1 (0x00 << 0) // 1 0 major version: LoRaWAN R1 +#define RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request +#define RADIOLIB_LW_MHDR_MTYPE_JOIN_ACCEPT (0x01 << 5) // 7 5 join accept +#define RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_UP (0x02 << 5) // 7 5 unconfirmed data up +#define RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_DOWN (0x03 << 5) // 7 5 unconfirmed data down +#define RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_UP (0x04 << 5) // 7 5 confirmed data up +#define RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_DOWN (0x05 << 5) // 7 5 confirmed data down +#define RADIOLIB_LW_MHDR_MTYPE_PROPRIETARY (0x07 << 5) // 7 5 proprietary +#define RADIOLIB_LW_MHDR_MTYPE_MASK (0x07 << 5) // 7 5 bitmask of all possible options +#define RADIOLIB_LW_MHDR_MAJOR_R1 (0x00 << 0) // 1 0 major version: LoRaWAN R1 // frame control field encoding -#define RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED (0x01 << 7) // 7 7 adaptive data rate: enabled -#define RADIOLIB_LORAWAN_FCTRL_ADR_DISABLED (0x00 << 7) // 7 7 disabled -#define RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ (0x01 << 6) // 6 6 adaptive data rate ACK request -#define RADIOLIB_LORAWAN_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge -#define RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending +#define RADIOLIB_LW_FCTRL_ADR_ENABLED (0x01 << 7) // 7 7 adaptive data rate: enabled +#define RADIOLIB_LW_FCTRL_ADR_DISABLED (0x00 << 7) // 7 7 disabled +#define RADIOLIB_LW_FCTRL_ADR_ACK_REQ (0x01 << 6) // 6 6 adaptive data rate ACK request +#define RADIOLIB_LW_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge +#define RADIOLIB_LW_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending // port field -#define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only -#define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved port values +#define RADIOLIB_LW_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only +#define RADIOLIB_LW_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved port values // MAC commands - only those sent from end-device to gateway -#define RADIOLIB_LORAWAN_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network -#define RADIOLIB_LORAWAN_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change -#define RADIOLIB_LORAWAN_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change -#define RADIOLIB_LORAWAN_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request -#define RADIOLIB_LORAWAN_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information -#define RADIOLIB_LORAWAN_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel -#define RADIOLIB_LORAWAN_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing +#define RADIOLIB_LW_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network +#define RADIOLIB_LW_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change +#define RADIOLIB_LW_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change +#define RADIOLIB_LW_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request +#define RADIOLIB_LW_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information +#define RADIOLIB_LW_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel +#define RADIOLIB_LW_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing -#define RADIOLIB_LORAWAN_NOPTS_LEN (8) +#define RADIOLIB_LW_NOPTS_LEN (8) // data rate encoding -#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps -#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 -#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 -#define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate - -#define RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK (0x00 << 0) -#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0) -#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0) -#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0) -#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) -#define RADIOLIB_LORAWAN_BAND_FIXED (1) -#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) -#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 0) +#define RADIOLIB_LW_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps +#define RADIOLIB_LW_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 +#define RADIOLIB_LW_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 +#define RADIOLIB_LW_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 +#define RADIOLIB_LW_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 +#define RADIOLIB_LW_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 +#define RADIOLIB_LW_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 +#define RADIOLIB_LW_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz +#define RADIOLIB_LW_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz +#define RADIOLIB_LW_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz +#define RADIOLIB_LW_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value +#define RADIOLIB_LW_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 +#define RADIOLIB_LW_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 +#define RADIOLIB_LW_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 +#define RADIOLIB_LW_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 +#define RADIOLIB_LW_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate + +#define RADIOLIB_LW_CHANNEL_DIR_UPLINK (0x00 << 0) +#define RADIOLIB_LW_CHANNEL_DIR_DOWNLINK (0x01 << 0) +#define RADIOLIB_LW_CHANNEL_DIR_BOTH (0x02 << 0) +#define RADIOLIB_LW_CHANNEL_DIR_NONE (0x03 << 0) +#define RADIOLIB_LW_BAND_DYNAMIC (0) +#define RADIOLIB_LW_BAND_FIXED (1) +#define RADIOLIB_LW_CHANNEL_NUM_DATARATES (15) +#define RADIOLIB_LW_CHANNEL_INDEX_NONE (0xFF >> 0) // recommended default settings -#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) -#define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000) -#define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) -#define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384) -#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP (0x06) -#define RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP (0x05) -#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) -#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000) -#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2) -#define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks -#define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented +#define RADIOLIB_LW_RECEIVE_DELAY_1_MS (1000) +#define RADIOLIB_LW_RECEIVE_DELAY_2_MS ((RADIOLIB_LW_RECEIVE_DELAY_1_MS) + 1000) +#define RADIOLIB_LW_RX1_DR_OFFSET (0) +#define RADIOLIB_LW_JOIN_ACCEPT_DELAY_1_MS (5000) +#define RADIOLIB_LW_JOIN_ACCEPT_DELAY_2_MS (6000) +#define RADIOLIB_LW_MAX_FCNT_GAP (16384) +#define RADIOLIB_LW_ADR_ACK_LIMIT_EXP (0x06) +#define RADIOLIB_LW_ADR_ACK_DELAY_EXP (0x05) +#define RADIOLIB_LW_RETRANSMIT_TIMEOUT_MIN_MS (1000) +#define RADIOLIB_LW_RETRANSMIT_TIMEOUT_MAX_MS (3000) +#define RADIOLIB_LW_POWER_STEP_SIZE_DBM (-2) +#define RADIOLIB_LW_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks +#define RADIOLIB_LW_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented // join request message layout -#define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS (9) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS (17) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE (0xFF) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_0 (0x00) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_1 (0x01) -#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_2 (0x02) +#define RADIOLIB_LW_JOIN_REQUEST_LEN (23) +#define RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS (1) +#define RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS (9) +#define RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS (17) +#define RADIOLIB_LW_JOIN_REQUEST_TYPE (0xFF) +#define RADIOLIB_LW_JOIN_REQUEST_TYPE_0 (0x00) +#define RADIOLIB_LW_JOIN_REQUEST_TYPE_1 (0x01) +#define RADIOLIB_LW_JOIN_REQUEST_TYPE_2 (0x02) // join accept message layout -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN (33) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS (1) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS (4) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS (7) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS (4) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS (11) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS (12) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS (12) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS (13) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN (16) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN - 1) +#define RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN (33) +#define RADIOLIB_LW_JOIN_ACCEPT_JOIN_NONCE_POS (1) +#define RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS (4) +#define RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS (7) +#define RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS (4) +#define RADIOLIB_LW_JOIN_ACCEPT_DL_SETTINGS_POS (11) +#define RADIOLIB_LW_JOIN_ACCEPT_RX_DELAY_POS (12) +#define RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS (12) +#define RADIOLIB_LW_JOIN_ACCEPT_CFLIST_POS (13) +#define RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN (16) +#define RADIOLIB_LW_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LW_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN - 1) // join accept message variables -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY (0x01) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY (0x02) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_ENC_KEY (0x05) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY (0x06) +#define RADIOLIB_LW_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 +#define RADIOLIB_LW_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 +#define RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY (0x01) +#define RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY (0x02) +#define RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) +#define RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) +#define RADIOLIB_LW_JOIN_ACCEPT_JS_ENC_KEY (0x05) +#define RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY (0x06) // frame header layout -#define RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS (16) -#define RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 1) -#define RADIOLIB_LORAWAN_FHDR_FCTRL_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 5) -#define RADIOLIB_LORAWAN_FHDR_FCNT_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 6) -#define RADIOLIB_LORAWAN_FHDR_FOPTS_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8) -#define RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK (0x0F) -#define RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN (15) -#define RADIOLIB_LORAWAN_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8 + (FOPTS)) -#define RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 9 + (FOPTS)) -#define RADIOLIB_LORAWAN_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) +#define RADIOLIB_LW_FHDR_LEN_START_OFFS (16) +#define RADIOLIB_LW_FHDR_DEV_ADDR_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 1) +#define RADIOLIB_LW_FHDR_FCTRL_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 5) +#define RADIOLIB_LW_FHDR_FCNT_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 6) +#define RADIOLIB_LW_FHDR_FOPTS_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 8) +#define RADIOLIB_LW_FHDR_FOPTS_LEN_MASK (0x0F) +#define RADIOLIB_LW_FHDR_FOPTS_MAX_LEN (15) +#define RADIOLIB_LW_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LW_FHDR_LEN_START_OFFS + 8 + (FOPTS)) +#define RADIOLIB_LW_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LW_FHDR_LEN_START_OFFS + 9 + (FOPTS)) +#define RADIOLIB_LW_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) // payload encryption/MIC blocks common layout -#define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0) -#define RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS (1) -#define RADIOLIB_LORAWAN_BLOCK_DIR_POS (5) -#define RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS (6) -#define RADIOLIB_LORAWAN_BLOCK_FCNT_POS (10) +#define RADIOLIB_LW_BLOCK_MAGIC_POS (0) +#define RADIOLIB_LW_BLOCK_CONF_FCNT_POS (1) +#define RADIOLIB_LW_BLOCK_DIR_POS (5) +#define RADIOLIB_LW_BLOCK_DEV_ADDR_POS (6) +#define RADIOLIB_LW_BLOCK_FCNT_POS (10) // payload encryption block layout -#define RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC (0x01) -#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS (4) -#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS (15) +#define RADIOLIB_LW_ENC_BLOCK_MAGIC (0x01) +#define RADIOLIB_LW_ENC_BLOCK_COUNTER_ID_POS (4) +#define RADIOLIB_LW_ENC_BLOCK_COUNTER_POS (15) // payload MIC blocks layout -#define RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC (0x49) -#define RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS (15) -#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) -#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) +#define RADIOLIB_LW_MIC_BLOCK_MAGIC (0x49) +#define RADIOLIB_LW_MIC_BLOCK_LEN_POS (15) +#define RADIOLIB_LW_MIC_DATA_RATE_POS (3) +#define RADIOLIB_LW_MIC_CH_INDEX_POS (4) // maximum allowed dwell time on bands that implement dwell time limitations -#define RADIOLIB_LORAWAN_DWELL_TIME (400) +#define RADIOLIB_LW_DWELL_TIME (400) // unused frame counter value -#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) +#define RADIOLIB_LW_FCNT_NONE (0xFFFFFFFF) // MAC commands -#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) - -#define RADIOLIB_LORAWAN_MAC_RESET (0x01) -#define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02) -#define RADIOLIB_LORAWAN_MAC_LINK_ADR (0x03) -#define RADIOLIB_LORAWAN_MAC_DUTY_CYCLE (0x04) -#define RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP (0x05) -#define RADIOLIB_LORAWAN_MAC_DEV_STATUS (0x06) -#define RADIOLIB_LORAWAN_MAC_NEW_CHANNEL (0x07) -#define RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP (0x08) -#define RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP (0x09) -#define RADIOLIB_LORAWAN_MAC_DL_CHANNEL (0x0A) -#define RADIOLIB_LORAWAN_MAC_REKEY (0x0B) -#define RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP (0x0C) -#define RADIOLIB_LORAWAN_MAC_DEVICE_TIME (0x0D) -#define RADIOLIB_LORAWAN_MAC_FORCE_REJOIN (0x0E) -#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) -#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) +#define RADIOLIB_LW_NUM_MAC_COMMANDS (16) + +#define RADIOLIB_LW_MAC_RESET (0x01) +#define RADIOLIB_LW_MAC_LINK_CHECK (0x02) +#define RADIOLIB_LW_MAC_LINK_ADR (0x03) +#define RADIOLIB_LW_MAC_DUTY_CYCLE (0x04) +#define RADIOLIB_LW_MAC_RX_PARAM_SETUP (0x05) +#define RADIOLIB_LW_MAC_DEV_STATUS (0x06) +#define RADIOLIB_LW_MAC_NEW_CHANNEL (0x07) +#define RADIOLIB_LW_MAC_RX_TIMING_SETUP (0x08) +#define RADIOLIB_LW_MAC_TX_PARAM_SETUP (0x09) +#define RADIOLIB_LW_MAC_DL_CHANNEL (0x0A) +#define RADIOLIB_LW_MAC_REKEY (0x0B) +#define RADIOLIB_LW_MAC_ADR_PARAM_SETUP (0x0C) +#define RADIOLIB_LW_MAC_DEVICE_TIME (0x0D) +#define RADIOLIB_LW_MAC_FORCE_REJOIN (0x0E) +#define RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP (0x0F) +#define RADIOLIB_LW_MAC_PROPRIETARY (0x80) // the length of internal MAC command queue - hopefully this is enough for most use cases -#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) +#define RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE (9) // the maximum number of simultaneously available channels -#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) +#define RADIOLIB_LW_NUM_AVAILABLE_CHANNELS (16) // maximum MAC command sizes -#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) -#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) -#define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) +#define RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN (5) +#define RADIOLIB_LW_MAX_MAC_COMMAND_LEN_UP (2) +#define RADIOLIB_LW_MAX_NUM_ADR_COMMANDS (8) /*! \struct LoRaWANMacSpec_t @@ -214,24 +214,24 @@ struct LoRaWANMacSpec_t { const bool user; }; -constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { +constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LW_NUM_MAC_COMMANDS + 1] = { { 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting - { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, - { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, - { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, - { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, - { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, - { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } + { RADIOLIB_LW_MAC_RESET, 1, 1, false }, + { RADIOLIB_LW_MAC_LINK_CHECK, 2, 0, true }, + { RADIOLIB_LW_MAC_LINK_ADR, 4, 1, false }, + { RADIOLIB_LW_MAC_DUTY_CYCLE, 1, 0, false }, + { RADIOLIB_LW_MAC_RX_PARAM_SETUP, 4, 1, false }, + { RADIOLIB_LW_MAC_DEV_STATUS, 0, 2, false }, + { RADIOLIB_LW_MAC_NEW_CHANNEL, 5, 1, false }, + { RADIOLIB_LW_MAC_RX_TIMING_SETUP, 1, 0, false }, + { RADIOLIB_LW_MAC_TX_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LW_MAC_DL_CHANNEL, 4, 1, false }, + { RADIOLIB_LW_MAC_REKEY, 1, 1, false }, + { RADIOLIB_LW_MAC_ADR_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LW_MAC_DEVICE_TIME, 5, 0, true }, + { RADIOLIB_LW_MAC_FORCE_REJOIN, 2, 0, false }, + { RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, + { RADIOLIB_LW_MAC_PROPRIETARY, 5, 0, true } }; /*! @@ -264,59 +264,59 @@ struct LoRaWANMacCommandQueue_t { uint8_t len; /*! \brief MAC command buffer */ - LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; + LoRaWANMacCommand_t commands[RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE]; }; -#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) +#define RADIOLIB_LW_NONCES_VERSION_VAL (0x0001) enum LoRaWANSchemeBase_t { - RADIOLIB_LORAWAN_NONCES_START = 0x00, - RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes - RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte - RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte - RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes - RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte - RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size + RADIOLIB_LW_NONCES_START = 0x00, + RADIOLIB_LW_NONCES_VERSION = RADIOLIB_LW_NONCES_START, // 2 bytes + RADIOLIB_LW_NONCES_MODE = RADIOLIB_LW_NONCES_VERSION + sizeof(uint16_t), // 2 bytes + RADIOLIB_LW_NONCES_CLASS = RADIOLIB_LW_NONCES_MODE + sizeof(uint16_t), // 1 byte + RADIOLIB_LW_NONCES_PLAN = RADIOLIB_LW_NONCES_CLASS + sizeof(uint8_t), // 1 byte + RADIOLIB_LW_NONCES_CHECKSUM = RADIOLIB_LW_NONCES_PLAN + sizeof(uint8_t), // 2 bytes + RADIOLIB_LW_NONCES_DEV_NONCE = RADIOLIB_LW_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes + RADIOLIB_LW_NONCES_JOIN_NONCE = RADIOLIB_LW_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes + RADIOLIB_LW_NONCES_ACTIVE = RADIOLIB_LW_NONCES_JOIN_NONCE + 3, // 1 byte + RADIOLIB_LW_NONCES_SIGNATURE = RADIOLIB_LW_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes + RADIOLIB_LW_NONCES_BUF_SIZE = RADIOLIB_LW_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size }; enum LoRaWANSchemeSession_t { - RADIOLIB_LORAWAN_SESSION_START = 0x00, - RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes - RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes - RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte - RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte - RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn, // 4 bytes - RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes - RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes - RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte - RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes - RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes - RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes - RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_LINK_ADR + MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, // 4 bytes - RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size + RADIOLIB_LW_SESSION_START = 0x00, + RADIOLIB_LW_SESSION_NWK_SENC_KEY = RADIOLIB_LW_SESSION_START, // 16 bytes + RADIOLIB_LW_SESSION_APP_SKEY = RADIOLIB_LW_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LW_SESSION_FNWK_SINT_KEY = RADIOLIB_LW_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LW_SESSION_SNWK_SINT_KEY = RADIOLIB_LW_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LW_SESSION_DEV_ADDR = RADIOLIB_LW_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes + RADIOLIB_LW_SESSION_NONCES_SIGNATURE = RADIOLIB_LW_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes + RADIOLIB_LW_SESSION_A_FCNT_DOWN = RADIOLIB_LW_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes + RADIOLIB_LW_SESSION_CONF_FCNT_UP = RADIOLIB_LW_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LW_SESSION_CONF_FCNT_DOWN = RADIOLIB_LW_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes + RADIOLIB_LW_SESSION_RJ_COUNT0 = RADIOLIB_LW_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes + RADIOLIB_LW_SESSION_RJ_COUNT1 = RADIOLIB_LW_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes + RADIOLIB_LW_SESSION_HOMENET_ID = RADIOLIB_LW_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes + RADIOLIB_LW_SESSION_VERSION = RADIOLIB_LW_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte + RADIOLIB_LW_SESSION_DUTY_CYCLE = RADIOLIB_LW_SESSION_VERSION + sizeof(uint8_t), // 1 byte + RADIOLIB_LW_SESSION_RX_PARAM_SETUP = RADIOLIB_LW_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LW_MAC_DUTY_CYCLE].lenDn, // 4 bytes + RADIOLIB_LW_SESSION_RX_TIMING_SETUP = RADIOLIB_LW_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LW_SESSION_TX_PARAM_SETUP = RADIOLIB_LW_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn, // 1 byte + RADIOLIB_LW_SESSION_ADR_PARAM_SETUP = RADIOLIB_LW_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LW_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LW_SESSION_BEACON_FREQ = RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes + RADIOLIB_LW_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LW_SESSION_BEACON_FREQ + 3, // 4 bytes + RADIOLIB_LW_SESSION_PERIODICITY = RADIOLIB_LW_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte + RADIOLIB_LW_SESSION_LAST_TIME = RADIOLIB_LW_SESSION_PERIODICITY + 1, // 4 bytes + RADIOLIB_LW_SESSION_UL_CHANNELS = RADIOLIB_LW_SESSION_LAST_TIME + 4, // 16*5 bytes + RADIOLIB_LW_SESSION_DL_CHANNELS = RADIOLIB_LW_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes + RADIOLIB_LW_SESSION_MAC_QUEUE_UL = RADIOLIB_LW_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LW_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes + RADIOLIB_LW_SESSION_N_FCNT_DOWN = RADIOLIB_LW_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes + RADIOLIB_LW_SESSION_ADR_FCNT = RADIOLIB_LW_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LW_SESSION_LINK_ADR = RADIOLIB_LW_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes + RADIOLIB_LW_SESSION_FCNT_UP = RADIOLIB_LW_SESSION_LINK_ADR + MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, // 4 bytes + RADIOLIB_LW_SESSION_SIGNATURE = RADIOLIB_LW_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes + RADIOLIB_LW_SESSION_BUF_SIZE = RADIOLIB_LW_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size }; /*! @@ -342,7 +342,7 @@ struct LoRaWANChannel_t { }; // alias for unused channel -#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } +#define RADIOLIB_LW_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LW_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } /*! \struct LoRaWANChannelSpan_t @@ -370,7 +370,7 @@ struct LoRaWANChannelSpan_t { }; // alias for unused channel span -#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } +#define RADIOLIB_LW_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED } /*! \struct LoRaWANBand_t @@ -384,7 +384,7 @@ struct LoRaWANBand_t { uint8_t bandType; /*! \brief Array of allowed maximum payload lengths for each data rate */ - uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; + uint8_t payloadLenMax[RADIOLIB_LW_CHANNEL_NUM_DATARATES]; /*! \brief Maximum allowed output power in this band in dBm */ int8_t powerMax; @@ -423,7 +423,7 @@ struct LoRaWANBand_t { LoRaWANChannel_t rx2; /*! \brief The corresponding datarates, bandwidths and coding rates for DR index */ - uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; + uint8_t dataRates[RADIOLIB_LW_CHANNEL_NUM_DATARATES]; }; // supported bands @@ -455,7 +455,7 @@ enum LoRaWANBandNum_t { }; // provide easy access to the number of currently supported bands -#define RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS (BandLast - BandEU868) +#define RADIOLIB_LW_NUM_SUPPORTED_BANDS (BandLast - BandEU868) // array of currently supported bands extern const LoRaWANBand_t* LoRaWANBands[]; @@ -465,7 +465,7 @@ extern const LoRaWANBand_t* LoRaWANBands[]; \brief Structure to save extra information about uplink/downlink event. */ struct LoRaWANEvent_t { - /*! \brief Event direction, one of RADIOLIB_LORAWAN_CHANNEL_DIR_* */ + /*! \brief Event direction, one of RADIOLIB_LW_CHANNEL_DIR_* */ uint8_t dir; /*! \brief Whether the event is confirmed or not (e.g., confirmed uplink sent by user application) */ @@ -520,7 +520,7 @@ class LoRaWANNode { /*! \brief Returns the pointer to the internal buffer that holds the LW base parameters - \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_NONCES_BUF_SIZE + \returns Pointer to uint8_t array of size RADIOLIB_LW_NONCES_BUF_SIZE */ uint8_t* getBufferNonces(); @@ -533,7 +533,7 @@ class LoRaWANNode { /*! \brief Returns the pointer to the internal buffer that holds the LW session parameters - \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_SESSION_BUF_SIZE + \returns Pointer to uint8_t array of size RADIOLIB_LW_SESSION_BUF_SIZE */ uint8_t* getBufferSession(); @@ -561,7 +561,7 @@ class LoRaWANNode { \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LW_DATA_RATE_UNUSED); /*! \brief Join network by performing activation by personalization. @@ -576,7 +576,7 @@ class LoRaWANNode { \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force = false, uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED); /*! \brief Whether there is an ongoing session active */ bool isJoined(); @@ -853,10 +853,10 @@ class LoRaWANNode { void beginCommon(uint8_t initialDr); // a buffer that holds all LW base parameters that should persist at all times! - uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; + uint8_t bufferNonces[RADIOLIB_LW_NONCES_BUF_SIZE] = { 0 }; // a buffer that holds all LW session parameters that preferably persist, but can be afforded to get lost - uint8_t bufferSession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE] = { 0 }; + uint8_t bufferSession[RADIOLIB_LW_SESSION_BUF_SIZE] = { 0 }; LoRaWANMacCommandQueue_t commandsUp = { .numCommands = 0, @@ -884,23 +884,23 @@ class LoRaWANNode { // session-specific parameters uint32_t homeNetId = 0; - uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; - uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + uint8_t adrLimitExp = RADIOLIB_LW_ADR_ACK_LIMIT_EXP; + uint8_t adrDelayExp = RADIOLIB_LW_ADR_ACK_DELAY_EXP; uint8_t nbTrans = 1; // Number of allowed frame retransmissions uint8_t txPowerCur = 0; uint8_t txPowerMax = 0; uint32_t fcntUp = 0; uint32_t aFcntDown = 0; uint32_t nFcntDown = 0; - uint32_t confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; - uint32_t confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + uint32_t confFcntUp = RADIOLIB_LW_FCNT_NONE; + uint32_t confFcntDown = RADIOLIB_LW_FCNT_NONE; uint32_t adrFcnt = 0; // whether the current configured channel is in FSK mode bool FSK = false; // flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA) - uint16_t activeMode = RADIOLIB_LORAWAN_MODE_NONE; + uint16_t activeMode = RADIOLIB_LW_MODE_NONE; // ADR is enabled by default bool adrEnabled = true; @@ -927,13 +927,13 @@ class LoRaWANNode { uint8_t difsSlots; // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + LoRaWANChannel_t availableChannels[2][RADIOLIB_LW_NUM_AVAILABLE_CHANNELS]; // currently configured channels for TX and RX1 - LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; + LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LW_CHANNEL_NONE, RADIOLIB_LW_CHANNEL_NONE }; // currently configured datarates for TX and RX1 - uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED }; + uint8_t dataRates[2] = { RADIOLIB_LW_DATA_RATE_UNUSED, RADIOLIB_LW_DATA_RATE_UNUSED }; // LoRaWAN revision (1.0 vs 1.1) uint8_t rev = 0; @@ -948,7 +948,7 @@ class LoRaWANNode { RadioLibTime_t rxDelayEnd = 0; // delays between the uplink and RX1/2 windows - RadioLibTime_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; + RadioLibTime_t rxDelays[2] = { RADIOLIB_LW_RECEIVE_DELAY_1_MS, RADIOLIB_LW_RECEIVE_DELAY_2_MS }; // device status - battery level uint8_t battLevel = 0xFF; diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index eaeb0841ab..2c927f3ef6 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -3,7 +3,7 @@ #if !RADIOLIB_EXCLUDE_LORAWAN // array of pointers to currently supported LoRaWAN bands -const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { +const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LW_NUM_SUPPORTED_BANDS] = { &EU868, &US915, &CN780, @@ -17,7 +17,7 @@ const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { const LoRaWANBand_t EU868 = { .bandNum = BandEU868, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .bandType = RADIOLIB_LW_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, @@ -30,55 +30,55 @@ const LoRaWANBand_t EU868 = { { .enabled = true, .idx = 2, .freq = 868.500, .drMin = 0, .drMax = 5}, }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE, + RADIOLIB_LW_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 869.525, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_FSK_50_K, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t US915 = { .bandNum = BandUS915, - .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .bandType = RADIOLIB_LW_BAND_FIXED, .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, - .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeUp = RADIOLIB_LW_DWELL_TIME, .dwellTimeDn = 0, .txFreqs = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 2, .txSpans = { @@ -105,32 +105,32 @@ const LoRaWANBand_t US915 = { .freqStep = 0.600, .drMin = 8, .drMax = 13, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED }, .rx1DataRateBase = 10, .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t CN780 = { .bandNum = BandCN780, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .bandType = RADIOLIB_LW_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, @@ -149,34 +149,34 @@ const LoRaWANBand_t CN780 = { }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE, + RADIOLIB_LW_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 786.000, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_FSK_50_K, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t EU433 = { .bandNum = BandEU433, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .bandType = RADIOLIB_LW_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, @@ -189,40 +189,40 @@ const LoRaWANBand_t EU433 = { { .enabled = true, .idx = 2, .freq = 433.575, .drMin = 0, .drMax = 5}, }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE, + RADIOLIB_LW_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 434.665, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_FSK_50_K, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t AU915 = { .bandNum = BandAU915, - .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .bandType = RADIOLIB_LW_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, @@ -230,14 +230,14 @@ const LoRaWANBand_t AU915 = { .dwellTimeUp = 0, .dwellTimeDn = 0, .txFreqs = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 2, .txSpans = { @@ -264,32 +264,32 @@ const LoRaWANBand_t AU915 = { .freqStep = 0.600, .drMin = 8, .drMax = 13, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED }, .rx1DataRateBase = 8, .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t CN500 = { .bandNum = BandCN500, - .bandType = RADIOLIB_LORAWAN_BAND_FIXED, + .bandType = RADIOLIB_LW_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, .powerNumSteps = 7, @@ -297,14 +297,14 @@ const LoRaWANBand_t CN500 = { .dwellTimeUp = 0, .dwellTimeDn = 0, .txFreqs = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 1, .txSpans = { @@ -316,7 +316,7 @@ const LoRaWANBand_t CN500 = { .drMax = 5, .joinRequestDataRate = 0 }, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE }, .rx1Span = { .numChannels = 48, @@ -324,78 +324,78 @@ const LoRaWANBand_t CN500 = { .freqStep = 0.200, .drMin = 0, .drMax = 5, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED }, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 505.300, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t AS923 = { .bandNum = BandAS923, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .bandType = RADIOLIB_LW_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, - .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, - .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeUp = RADIOLIB_LW_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LW_DWELL_TIME, .txFreqs = { { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE, + RADIOLIB_LW_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 2, .drMax = 2 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_FSK_50_K, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t KR920 = { .bandNum = BandKR920, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .bandType = RADIOLIB_LW_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, .powerNumSteps = 7, @@ -408,40 +408,40 @@ const LoRaWANBand_t KR920 = { { .enabled = true, .idx = 2, .freq = 922.500, .drMin = 0, .drMax = 5} }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE, + RADIOLIB_LW_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 921.900, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; const LoRaWANBand_t IN865 = { .bandNum = BandIN865, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .bandType = RADIOLIB_LW_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, .powerNumSteps = 10, @@ -454,34 +454,34 @@ const LoRaWANBand_t IN865 = { { .enabled = true, .idx = 2, .freq = 865.9850, .drMin = 0, .drMax = 5} }, .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE, + RADIOLIB_LW_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + RADIOLIB_LW_CHANNEL_SPAN_NONE, + RADIOLIB_LW_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 866.550, .drMin = 2, .drMax = 2 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_FSK_50_K, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED, + RADIOLIB_LW_DATA_RATE_UNUSED } }; From 163a4020d26c80fbb3badeefd920a98db93ed2be Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 May 2024 23:18:36 +0200 Subject: [PATCH 1026/1848] [LoRaWAN] Consistent fCnt/fPort casing to match documents --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 2 +- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 8 +- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 6 +- keywords.txt | 8 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 210 +++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 86 +++---- 6 files changed, 160 insertions(+), 160 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 4d12601e30..637efa80b5 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -42,7 +42,7 @@ void setup() { debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); Serial.println(F("Initialise LoRaWAN Network credentials")); - state = node.beginABP(devAddr, NwkSEncKey, AppSKey, NwkSKey, SNwkSIntKey, true); + state = node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey, true); debug(state < RADIOLIB_ERR_NONE, F("Session setup failed"), state, true); Serial.println(F("Ready!\n")); diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index b9de72e7d3..f505800538 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -118,10 +118,10 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // copy over the keys in to the something that will not compile if incorrectly formatted uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR; -uint8_t NwkSKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY }; -uint8_t SNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // Previously sNwkSIntKey -uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey -uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; +uint8_t fNwkSIntKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY }; +uint8_t sNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; +uint8_t nwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; +uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index d14daac416..f45830a199 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -105,7 +105,7 @@ void loop() { uint8_t Port = 10; // Retrieve the last uplink frame counter - uint32_t fcntUp = node.getFcntUp(); + uint32_t fcntUp = node.getFCntUp(); // Send a confirmed uplink every 64th frame // and also request the LinkCheck and DeviceTime MAC commands @@ -159,9 +159,9 @@ void loop() { Serial.print(downlinkDetails.power); Serial.println(F(" dBm")); Serial.print(F("[LoRaWAN] Frame count:\t")); - Serial.println(downlinkDetails.fcnt); + Serial.println(downlinkDetails.fCnt); Serial.print(F("[LoRaWAN] Port:\t\t")); - Serial.println(downlinkDetails.port); + Serial.println(downlinkDetails.fPort); uint8_t margin = 0; uint8_t gwCnt = 0; diff --git a/keywords.txt b/keywords.txt index 5fbbcbb37a..f53f5d1c76 100644 --- a/keywords.txt +++ b/keywords.txt @@ -317,10 +317,10 @@ uplink KEYWORD2 downlink KEYWORD2 sendReceive KEYWORD2 setDeviceStatus KEYWORD2 -getFcntUp KEYWORD2 -getNFcntDown KEYWORD2 -getAFcntDown KEYWORD2 -resetFcntDown KEYWORD2 +getFCntUp KEYWORD2 +getNFCntDown KEYWORD2 +getAFCntDown KEYWORD2 +resetFCntDown KEYWORD2 setDatarate KEYWORD2 setADR KEYWORD2 setDutyCycle KEYWORD2 diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 32f61674a0..9afdd20d27 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -176,12 +176,12 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID]); - this->aFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN]); - this->nFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN]); - this->confFcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP]); - this->confFcntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN]); - this->adrFcnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT]); - this->fcntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP]); + this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN]); + this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN]); + this->confFCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP]); + this->confFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN]); + this->adrFCnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT]); + this->fCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP]); int16_t state = RADIOLIB_ERR_UNKNOWN; @@ -700,12 +700,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } // reset all frame counters - this->fcntUp = 0; - this->aFcntDown = 0; - this->nFcntDown = 0; - this->confFcntUp = RADIOLIB_LW_FCNT_NONE; - this->confFcntDown = RADIOLIB_LW_FCNT_NONE; - this->adrFcnt = 0; + this->fCntUp = 0; + this->aFCntDown = 0; + this->nFCntDown = 0; + this->confFCntUp = RADIOLIB_LW_FCNT_NONE; + this->confFCntDown = RADIOLIB_LW_FCNT_NONE; + this->adrFCnt = 0; // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_VERSION], RADIOLIB_LW_NONCES_VERSION_VAL); @@ -778,12 +778,12 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk this->beginCommon(initialDr); // reset all frame counters - this->fcntUp = 0; - this->aFcntDown = 0; - this->nFcntDown = 0; - this->confFcntUp = RADIOLIB_LW_FCNT_NONE; - this->confFcntDown = RADIOLIB_LW_FCNT_NONE; - this->adrFcnt = 0; + this->fCntUp = 0; + this->aFCntDown = 0; + this->nFCntDown = 0; + this->confFCntUp = RADIOLIB_LW_FCNT_NONE; + this->confFCntDown = RADIOLIB_LW_FCNT_NONE; + this->adrFCnt = 0; // save the activation keys checksum, mode, class, frequency plan LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_VERSION], RADIOLIB_LW_NONCES_VERSION_VAL); @@ -823,12 +823,12 @@ int16_t LoRaWANNode::saveSession() { LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev); // store all frame counters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN], this->aFcntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN], this->nFcntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP], this->confFcntUp); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN], this->confFcntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT], this->adrFcnt); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP], this->fcntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN], this->aFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN], this->nFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP], this->confFCntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN], this->confFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT], this->adrFCnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP], this->fCntUp); // save the current uplink MAC command queue memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); @@ -841,16 +841,16 @@ int16_t LoRaWANNode::saveSession() { } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::uplink(String& str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { - return(this->uplink(str.c_str(), port, isConfirmed, event)); +int16_t LoRaWANNode::uplink(String& str, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { + return(this->uplink(str.c_str(), fPort, isConfirmed, event)); } #endif -int16_t LoRaWANNode::uplink(const char* str, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { - return(this->uplink((uint8_t*)str, strlen(str), port, isConfirmed, event)); +int16_t LoRaWANNode::uplink(const char* str, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { + return(this->uplink((uint8_t*)str, strlen(str), fPort, isConfirmed, event)); } -int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed, LoRaWANEvent_t* event) { +int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { // if not joined, don't do anything if(!this->isJoined()) { return(RADIOLIB_ERR_NETWORK_NOT_JOINED); @@ -870,12 +870,12 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); } - // check destination port - if(port > 0xDF) { + // check destination fPort + if(fPort > 0xDF) { return(RADIOLIB_ERR_INVALID_PORT); } - // port 0 is only allowed for MAC-only payloads - if(port == RADIOLIB_LW_FPORT_MAC_COMMAND) { + // fPort 0 is only allowed for MAC-only payloads + if(fPort == RADIOLIB_LW_FPORT_MAC_COMMAND) { if (!this->isMACPayload) { return(RADIOLIB_ERR_INVALID_PORT); } @@ -887,7 +887,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t foptsLen = 0; - if(this->commandsUp.numCommands > 0 && port != RADIOLIB_LW_FPORT_MAC_COMMAND) { + if(this->commandsUp.numCommands > 0 && fPort != RADIOLIB_LW_FPORT_MAC_COMMAND) { // there are, assume the maximum possible FOpts len for buffer allocation foptsLen = this->commandsUp.len; } @@ -904,12 +904,12 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // check if we need to do ADR stuff uint32_t adrLimit = 0x01 << this->adrLimitExp; uint32_t adrDelay = 0x01 << this->adrDelayExp; - if((this->fcntUp - this->adrFcnt) >= adrLimit) { + if((this->fCntUp - this->adrFCnt) >= adrLimit) { adrAckReq = true; } // if we hit the Limit + Delay, try one of three, in order: // set TxPower to max, set DR to min, enable all default channels - if ((this->fcntUp - this->adrFcnt) == (adrLimit + adrDelay)) { + if ((this->fCntUp - this->adrFCnt) == (adrLimit + adrDelay)) { uint8_t adrStage = 1; while(adrStage != 0) { switch(adrStage) { @@ -955,7 +955,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' - this->adrFcnt += adrDelay; + this->adrFCnt += adrDelay; } } @@ -981,7 +981,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // set the packet fields if(isConfirmed) { uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] = RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_UP; - this->confFcntUp = this->fcntUp; + this->confFCntUp = this->fCntUp; } else { uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] = RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_UP; } @@ -997,14 +997,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf } } - // if the saved confirm-fcnt is set, set the ACK bit + // if the saved confirm-fCnt is set, set the ACK bit bool isConfirmingDown = false; - if(this->confFcntDown != RADIOLIB_LW_FCNT_NONE) { + if(this->confFCntDown != RADIOLIB_LW_FCNT_NONE) { isConfirmingDown = true; uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ACK; } - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_FCNT_POS], (uint16_t)this->fcntUp); + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_FCNT_POS], (uint16_t)this->fCntUp); // check if we have some MAC commands to append if(foptsLen > 0) { @@ -1035,39 +1035,39 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= foptsLen; // encrypt it - processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x01, true); + processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x01, true); } - // set the port - uplinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] = port; + // set the fPort + uplinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] = fPort; - // select encryption key based on the target port + // select encryption key based on the target fPort uint8_t* encKey = this->appSKey; - if(port == RADIOLIB_LW_FPORT_MAC_COMMAND) { + if(fPort == RADIOLIB_LW_FPORT_MAC_COMMAND) { encKey = this->nwkSEncKey; } // encrypt the frame payload - processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x00, true); + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; block0[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; block0[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_UPLINK; LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_FCNT_POS], this->fcntUp); + LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_FCNT_POS], this->fCntUp); block0[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); - if(this->confFcntDown != RADIOLIB_LW_FCNT_NONE) { - LoRaWANNode::hton(&block1[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntDown); + if(this->confFCntDown != RADIOLIB_LW_FCNT_NONE) { + LoRaWANNode::hton(&block1[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntDown); } block1[RADIOLIB_LW_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LW_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK].idx; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fcntUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fCntUp); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -1106,7 +1106,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf RADIOLIB_ASSERT(state); // the downlink confirmation was acknowledged, so clear the counter value - this->confFcntDown = RADIOLIB_LW_FCNT_NONE; + this->confFCntDown = RADIOLIB_LW_FCNT_NONE; // pass the extra info if requested if(event) { @@ -1116,12 +1116,12 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; - event->fcnt = this->fcntUp; - event->port = port; + event->fCnt = this->fCntUp; + event->fPort = fPort; } // increase frame counter by one for the next uplink - this->fcntUp += 1; + this->fCntUp += 1; return(RADIOLIB_ERR_NONE); } @@ -1279,7 +1279,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) size_t downlinkMsgLen = this->phyLayer->getPacketLength(); // check the minimum required frame length - // an extra byte is subtracted because downlink frames may not have a port + // an extra byte is subtracted because downlink frames may not have a fPort if(downlinkMsgLen < RADIOLIB_LW_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); @@ -1316,14 +1316,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // get the frame counter and set it to the MIC calculation block - uint16_t fcnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_FCNT_POS]); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_FCNT_POS], fcnt16); + uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_FCNT_POS]); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_FCNT_POS], fCnt16); - // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fcntUp + // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fCntUp bool isConfirmingUp = false; if((downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FCTRL_ACK) && (this->rev == 1)) { isConfirmingUp = true; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFcntUp); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); } // calculate length of FOpts and payload @@ -1332,7 +1332,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) - // TODO "NFCntDown is used for MAC communication on port 0 and when the FPort field is missing" + // TODO "NFCntDown is used for MAC communication on fPort 0 and when the FPort field is missing" // so what about empty frames for ACK? Per TS008, these should be Application downlinks bool isAppDownlink = true; if(payLen <= 0) { @@ -1347,23 +1347,23 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFcntDown = %d) encoded:", isAppDownlink ? "A" : "N", fcnt16); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFcntDown = %d) encoded:", isAppDownlink ? "A" : "N", fCnt16); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); // check the FcntDown value (Network or Application) - uint32_t fcntDownPrev = 0; + uint32_t fCntDownPrev = 0; if (isAppDownlink) { - fcntDownPrev = this->aFcntDown; + fCntDownPrev = this->aFCntDown; } else { - fcntDownPrev = this->nFcntDown; + fCntDownPrev = this->nFCntDown; } // if this is not the first downlink... // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP - // if that isn't the case and the received fcnt is smaller or equal to the last heard fcnt, then error - uint32_t fcnt32 = fcnt16; - if(fcntDownPrev > 0) { - if((fcnt16 <= fcntDownPrev) && ((0xFFFF - (uint16_t)fcntDownPrev + fcnt16) > RADIOLIB_LW_MAX_FCNT_GAP)) { + // if that isn't the case and the received fCnt is smaller or equal to the last heard fCnt, then error + uint32_t fCnt32 = fCnt16; + if(fCntDownPrev > 0) { + if((fCnt16 <= fCntDownPrev) && ((0xFFFF - (uint16_t)fCntDownPrev + fCnt16) > RADIOLIB_LW_MAX_FCNT_GAP)) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1372,9 +1372,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } else { return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID); } - } else if (fcnt16 <= fcntDownPrev) { - uint16_t msb = (fcntDownPrev >> 16) + 1; // assume a rollover - fcnt32 |= ((uint32_t)msb << 16); // add back the MSB part + } else if (fCnt16 <= fCntDownPrev) { + uint16_t msb = (fCntDownPrev >> 16) + 1; // assume a rollover + fCnt32 |= ((uint32_t)msb << 16); // add back the MSB part } } @@ -1386,17 +1386,17 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) return(RADIOLIB_ERR_CRC_MISMATCH); } - // save current fcnt to respective frame counter + // save current fCnt to respective frame counter if (isAppDownlink) { - this->aFcntDown = fcnt32; + this->aFCntDown = fCnt32; } else { - this->nFcntDown = fcnt32; + this->nFCntDown = fCnt32; } // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) bool isConfirmedDown = false; if((downlinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_DOWN) { - this->confFcntDown = this->aFcntDown; + this->confFCntDown = this->aFCntDown; isConfirmedDown = true; } @@ -1419,14 +1419,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t fopts[RADIOLIB_STATIC_ARRAY_SIZE]; #endif - // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fcnt16 + // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fCnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey if(foptsLen <= RADIOLIB_LW_FHDR_FOPTS_LEN_MASK) { uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, ctrId, true); } else { - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fcnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); } bool hasADR = false; @@ -1536,8 +1536,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } - // a downlink was received, so reset the ADR counter to the last uplink's fcnt - this->adrFcnt = this->getFcntUp(); + // a downlink was received, so reset the ADR counter to the last uplink's fCnt + this->adrFCnt = this->getFCntUp(); // pass the extra info if requested if(event) { @@ -1547,8 +1547,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; - event->fcnt = isAppDownlink ? this->aFcntDown : this->nFcntDown; - event->port = isAppDownlink ? downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LW_FPORT_MAC_COMMAND; + event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; + event->fPort = isAppDownlink ? downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LW_FPORT_MAC_COMMAND; } // process Application payload (if there is any) @@ -1564,8 +1564,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) *len = payLen - 1; - // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fcnt16 - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fcnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fCnt16 + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; @@ -1575,9 +1575,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); + int16_t state = this->uplink(strUp, fPort, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink @@ -1586,9 +1586,9 @@ int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t port, String& strDown, b } #endif -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); + int16_t state = this->uplink(dataUp, lenUp, fPort, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink @@ -1596,9 +1596,9 @@ int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, bo return(state); } -int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(strUp, port, isConfirmed, eventUp); + int16_t state = this->uplink(strUp, fPort, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink @@ -1606,9 +1606,9 @@ int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t port, uint8_t* dataD return(state); } -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // send the uplink - int16_t state = this->uplink(dataUp, lenUp, port, isConfirmed, eventUp); + int16_t state = this->uplink(dataUp, lenUp, fPort, isConfirmed, eventUp); RADIOLIB_ASSERT(state); // wait for the downlink @@ -1621,24 +1621,24 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { } // return Fcnt of last uplink; also return 0 if no uplink occured yet -uint32_t LoRaWANNode::getFcntUp() { - if(this->fcntUp == 0) { +uint32_t LoRaWANNode::getFCntUp() { + if(this->fCntUp == 0) { return(0); } - return(this->fcntUp - 1); + return(this->fCntUp - 1); } -uint32_t LoRaWANNode::getNFcntDown() { - return(this->nFcntDown); +uint32_t LoRaWANNode::getNFCntDown() { + return(this->nFCntDown); } -uint32_t LoRaWANNode::getAFcntDown() { - return(this->aFcntDown); +uint32_t LoRaWANNode::getAFCntDown() { + return(this->aFCntDown); } -void LoRaWANNode::resetFcntDown() { - this->nFcntDown = 0; - this->aFcntDown = 0; +void LoRaWANNode::resetFCntDown() { + this->nFCntDown = 0; + this->aFCntDown = 0; } uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { @@ -2858,7 +2858,7 @@ bool LoRaWANNode::performCAD() { return false; // Channel is free } -void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) { +void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; if(len % RADIOLIB_AES128_BLOCK_SIZE) { @@ -2872,7 +2872,7 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out encBlock[RADIOLIB_LW_ENC_BLOCK_COUNTER_ID_POS] = ctrId; encBlock[RADIOLIB_LW_BLOCK_DIR_POS] = dir; LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_FCNT_POS], fcnt); + LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_FCNT_POS], fCnt); // now encrypt the input // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index b79d7931ae..8c623066e6 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -39,9 +39,9 @@ #define RADIOLIB_LW_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge #define RADIOLIB_LW_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending -// port field +// fPort field #define RADIOLIB_LW_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only -#define RADIOLIB_LW_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved port values +#define RADIOLIB_LW_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved fPort values // MAC commands - only those sent from end-device to gateway #define RADIOLIB_LW_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network @@ -485,10 +485,10 @@ struct LoRaWANEvent_t { int16_t power; /*! \brief The appropriate frame counter - for different events, different frame counters will be reported! */ - uint32_t fcnt; + uint32_t fCnt; /*! \brief Port number */ - uint8_t port; + uint8_t fPort; }; /*! @@ -600,44 +600,44 @@ class LoRaWANNode { /*! \brief Send a message to the server. \param str Address of Arduino String that will be transmitted. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. \param event Pointer to a structure to store extra information about the event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t uplink(String& str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); + int16_t uplink(String& str, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); #endif /*! \brief Send a message to the server. \param str C-string that will be transmitted. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. \param event Pointer to a structure to store extra information about the event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t uplink(const char* str, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); + int16_t uplink(const char* str, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); /*! \brief Send a message to the server. \param data Data to send. \param len Length of the data. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. \param event Pointer to a structure to store extra information about the event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t uplink(uint8_t* data, size_t len, uint8_t port, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); + int16_t uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Wait for downlink from the server in either RX1 or RX2 window. \param str Address of Arduino String to save the received data. \param event Pointer to a structure to store extra information about the event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ int16_t downlink(String& str, LoRaWANEvent_t* event = NULL); @@ -648,7 +648,7 @@ class LoRaWANNode { \param data Buffer to save received data into. \param len Pointer to variable that will be used to save the number of received bytes. \param event Pointer to a structure to store extra information about the event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); @@ -656,7 +656,7 @@ class LoRaWANNode { /*! \brief Wait for downlink, simplified to allow for simpler sendReceive \param event Pointer to a structure to store extra information about the event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ int16_t downlink(LoRaWANEvent_t* event = NULL); @@ -665,62 +665,62 @@ class LoRaWANNode { /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. \param strUp Address of Arduino String that will be transmitted. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param strDown Address of Arduino String to save the received data. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(String& strUp, uint8_t port, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + int16_t sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); #endif /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. \param strUp C-string that will be transmitted. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param dataDown Buffer to save received data into. \param lenDown Pointer to variable that will be used to save the number of received bytes. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(const char* strUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + int16_t sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. \param dataUp Data to send. \param lenUp Length of the data. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param dataDown Buffer to save received data into. \param lenDown Pointer to variable that will be used to save the number of received bytes. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Send a message to the server and wait for a downlink but don't bother the user with downlink contents \param dataUp Data to send. \param lenUp Length of the data. - \param port Port number to send the message to. + \param fPort Port number to send the message to. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event - (port, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns \ref status_codes */ - int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t port = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Set device status. @@ -733,26 +733,26 @@ class LoRaWANNode { \brief Returns the last uplink's frame counter; also 0 if no uplink occured yet. */ - uint32_t getFcntUp(); + uint32_t getFCntUp(); /*! \brief Returns the last network downlink's frame counter; also 0 if no network downlink occured yet. */ - uint32_t getNFcntDown(); + uint32_t getNFCntDown(); /*! \brief Returns the last application downlink's frame counter; also 0 if no application downlink occured yet. */ - uint32_t getAFcntDown(); + uint32_t getAFCntDown(); /*! \brief Reset the downlink frame counters (application and network) This is unsafe and can possibly allow replay attacks using downlinks. It mainly exists as part of the TS009 Specification Verification protocol. */ - void resetFcntDown(); + void resetFCntDown(); /*! \brief Set uplink datarate. This should not be used when ADR is enabled. @@ -889,12 +889,12 @@ class LoRaWANNode { uint8_t nbTrans = 1; // Number of allowed frame retransmissions uint8_t txPowerCur = 0; uint8_t txPowerMax = 0; - uint32_t fcntUp = 0; - uint32_t aFcntDown = 0; - uint32_t nFcntDown = 0; - uint32_t confFcntUp = RADIOLIB_LW_FCNT_NONE; - uint32_t confFcntDown = RADIOLIB_LW_FCNT_NONE; - uint32_t adrFcnt = 0; + uint32_t fCntUp = 0; + uint32_t aFCntDown = 0; + uint32_t nFCntDown = 0; + uint32_t confFCntUp = RADIOLIB_LW_FCNT_NONE; + uint32_t confFCntDown = RADIOLIB_LW_FCNT_NONE; + uint32_t adrFCnt = 0; // whether the current configured channel is in FSK mode bool FSK = false; @@ -1028,7 +1028,7 @@ class LoRaWANNode { bool performCAD(); // function to encrypt and decrypt payloads - void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); + void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum static uint16_t checkSum16(uint8_t *key, uint16_t keyLen); From bbeca9a53edadf3aafb89f531171a5e4a747cb64 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 May 2024 23:21:45 +0200 Subject: [PATCH 1027/1848] [LoRaWAN] Consistent fOpts casing to match documents --- src/protocols/LoRaWAN/LoRaWAN.cpp | 94 +++++++++++++++---------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 9afdd20d27..965c48f972 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -886,10 +886,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon int16_t state = RADIOLIB_ERR_UNKNOWN; // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) - uint8_t foptsLen = 0; + uint8_t fOptsLen = 0; if(this->commandsUp.numCommands > 0 && fPort != RADIOLIB_LW_FPORT_MAC_COMMAND) { // there are, assume the maximum possible FOpts len for buffer allocation - foptsLen = this->commandsUp.len; + fOptsLen = this->commandsUp.len; } // check maximum payload len as defined in phy @@ -965,13 +965,13 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon RADIOLIB_ASSERT(state); // if dwell time is imposed, calculated expected time on air and cancel if exceeds - if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LW_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { + if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LW_FRAME_LEN(len, fOptsLen) - 16)/1000 > this->dwellTimeUp) { return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, foptsLen); + size_t uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, fOptsLen); #if RADIOLIB_STATIC_ONLY uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -988,7 +988,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] |= RADIOLIB_LW_MHDR_MAJOR_R1; LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS], this->devAddr); - // length of fopts will be added later + // length of fOpts will be added later uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] = 0x00; if(this->adrEnabled) { uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ADR_ENABLED; @@ -1007,20 +1007,20 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_FCNT_POS], (uint16_t)this->fCntUp); // check if we have some MAC commands to append - if(foptsLen > 0) { + if(fOptsLen > 0) { // assume maximum possible buffer size - uint8_t foptsBuff[RADIOLIB_LW_FHDR_FOPTS_MAX_LEN]; - uint8_t* foptsPtr = foptsBuff; + uint8_t fOptsBuff[RADIOLIB_LW_FHDR_FOPTS_MAX_LEN]; + uint8_t* fOptsPtr = fOptsBuff; - // append all MAC replies into fopts buffer + // append all MAC replies into fOpts buffer int16_t i = 0; for (; i < this->commandsUp.numCommands; i++) { LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; - memcpy(foptsPtr, &cmd, 1 + cmd.len); - foptsPtr += cmd.len + 1; + memcpy(fOptsPtr, &cmd, 1 + cmd.len); + fOptsPtr += cmd.len + 1; } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsLen); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsLen); // pop the commands from back to front for (; i >= 0; i--) { @@ -1031,16 +1031,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon } } - uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, foptsLen); - uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= foptsLen; + uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, fOptsLen); + uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= fOptsLen; // encrypt it - processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x01, true); + processAES(fOptsBuff, fOptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x01, true); } // set the fPort - uplinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] = fPort; + uplinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)] = fPort; // select encryption key based on the target fPort uint8_t* encKey = this->appSKey; @@ -1049,7 +1049,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon } // encrypt the frame payload - processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x00, true); + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(fOptsLen)], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; @@ -1327,8 +1327,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // calculate length of FOpts and payload - uint8_t foptsLen = downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FHDR_FOPTS_LEN_MASK; - int payLen = downlinkMsgLen - 8 - foptsLen - sizeof(uint32_t); + uint8_t fOptsLen = downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FHDR_FOPTS_LEN_MASK; + int payLen = downlinkMsgLen - 8 - fOptsLen - sizeof(uint32_t); // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) @@ -1340,8 +1340,8 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) isAppDownlink = false; } } - else if(downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] == RADIOLIB_LW_FPORT_MAC_COMMAND) { - foptsLen = payLen - 1; + else if(downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)] == RADIOLIB_LW_FPORT_MAC_COMMAND) { + fOptsLen = payLen - 1; if(this->rev == 1) { isAppDownlink = false; } @@ -1411,22 +1411,22 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // process FOpts (if there are any) - if(foptsLen > 0) { + if(fOptsLen > 0) { // there are some Fopts, decrypt them #if !RADIOLIB_STATIC_ONLY - uint8_t* fopts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LW_FHDR_FOPTS_LEN_MASK, (int)foptsLen)]; + uint8_t* fOpts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LW_FHDR_FOPTS_LEN_MASK, (int)fOptsLen)]; #else - uint8_t fopts[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; #endif // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fCnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey - if(foptsLen <= RADIOLIB_LW_FHDR_FOPTS_LEN_MASK) { + if(fOptsLen <= RADIOLIB_LW_FHDR_FOPTS_LEN_MASK) { uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], (size_t)foptsLen, this->nwkSEncKey, fopts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, ctrId, true); } else { - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(0)], (size_t)foptsLen, this->nwkSEncKey, fopts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); } bool hasADR = false; @@ -1434,17 +1434,17 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t lastCID = 0; // process the MAC command(s) - int8_t remLen = foptsLen; - uint8_t* foptsPtr = fopts; + int8_t remLen = fOptsLen; + uint8_t* fOptsPtr = fOpts; while(remLen > 0) { - uint8_t cid = *foptsPtr; + uint8_t cid = *fOptsPtr; uint8_t macLen = getMacPayloadLength(cid); if(cid == RADIOLIB_LW_MAC_LINK_ADR) { // if there was an earlier ADR command but it was not the last, ignore it if(hasADR && lastCID != RADIOLIB_LW_MAC_LINK_ADR) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); remLen -= (macLen + 1); - foptsPtr += (macLen + 1); + fOptsPtr += (macLen + 1); lastCID = cid; continue; } @@ -1460,7 +1460,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .len = macLen, .repeat = (cid == RADIOLIB_LW_MAC_LINK_ADR ? numADR : (uint8_t)0), }; - memcpy(cmd.payload, foptsPtr + 1, macLen); + memcpy(cmd.payload, fOptsPtr + 1, macLen); // process the MAC command bool sendUp = execMacCommand(&cmd); @@ -1470,32 +1470,32 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // processing succeeded, move in the buffer to the next command remLen -= (macLen + 1); - foptsPtr += (macLen + 1); + fOptsPtr += (macLen + 1); lastCID = cid; } #if !RADIOLIB_STATIC_ONLY - delete[] fopts; + delete[] fOpts; #endif // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { - size_t foptsBufSize = this->commandsUp.len; + size_t fOptsBufSize = this->commandsUp.len; #if RADIOLIB_STATIC_ONLY - uint8_t foptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t fOptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #else - uint8_t* foptsBuff = new uint8_t[foptsBufSize]; + uint8_t* fOptsBuff = new uint8_t[fOptsBufSize]; #endif - uint8_t* foptsPtr = foptsBuff; - // append all MAC replies into fopts buffer + uint8_t* fOptsPtr = fOptsBuff; + // append all MAC replies into fOpts buffer int16_t i = 0; for (; i < this->commandsUp.numCommands; i++) { LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; - memcpy(foptsPtr, &cmd, 1 + cmd.len); - foptsPtr += cmd.len + 1; + memcpy(fOptsPtr, &cmd, 1 + cmd.len); + fOptsPtr += cmd.len + 1; } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(foptsBuff, foptsBufSize); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsBufSize); // pop the commands from back to front for (; i >= 0; i--) { @@ -1511,12 +1511,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) bool prevDC = this->dutyCycleEnabled; this->dutyCycleEnabled = false; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); - state = this->uplink(foptsBuff, foptsBufSize, RADIOLIB_LW_FPORT_MAC_COMMAND); + state = this->uplink(fOptsBuff, fOptsBufSize, RADIOLIB_LW_FPORT_MAC_COMMAND); RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); this->dutyCycleEnabled = prevDC; #if !RADIOLIB_STATIC_ONLY - delete[] foptsBuff; + delete[] fOptsBuff; #endif #if RADIOLIB_STATIC_ONLY @@ -1548,11 +1548,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerCur * 2; event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; - event->fPort = isAppDownlink ? downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(foptsLen)] : RADIOLIB_LW_FPORT_MAC_COMMAND; + event->fPort = isAppDownlink ? downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)] : RADIOLIB_LW_FPORT_MAC_COMMAND; } // process Application payload (if there is any) - if(payLen <= 0 || foptsLen > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { + if(payLen <= 0 || fOptsLen > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { // no payload *len = 0; #if !RADIOLIB_STATIC_ONLY @@ -1565,7 +1565,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) *len = payLen - 1; // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fCnt16 - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(foptsLen)], payLen - 1, this->appSKey, data, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(fOptsLen)], payLen - 1, this->appSKey, data, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; From bb7fffe95dac5277c7a82d3a99d0be3c89a5a3e6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 May 2024 23:26:59 +0200 Subject: [PATCH 1028/1848] [LoRaWAN] Improve readability to better match documentation --- src/protocols/LoRaWAN/LoRaWAN.cpp | 148 +++++++++++++++--------------- src/protocols/LoRaWAN/LoRaWAN.h | 5 +- 2 files changed, 76 insertions(+), 77 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 965c48f972..866ce10988 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -128,7 +128,7 @@ int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) { // if already joined, ignore - if(this->activeMode != RADIOLIB_LW_MODE_NONE) { + if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) { return(RADIOLIB_ERR_NONE); } @@ -241,9 +241,6 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass // copy uplink MAC command queue back in place memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); - // full session is restored, so set joined flag to whichever mode is restored - this->activeMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE]); - return(state); } @@ -716,7 +713,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], this->joinNonce, 3); this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; - this->activeMode = RADIOLIB_LW_MODE_OTAA; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); @@ -793,7 +789,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum); this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; - this->activeMode = RADIOLIB_LW_MODE_ABP; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); @@ -803,7 +798,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk } bool LoRaWANNode::isJoined() { - return(this->activeMode != RADIOLIB_LW_MODE_NONE); + return(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]); } int16_t LoRaWANNode::saveSession() { @@ -915,11 +910,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon switch(adrStage) { case(1): { // if the TxPower field has some offset, remove it and switch to maximum power - if(this->txPowerCur > 0) { + if(this->txPowerSteps > 0) { // set the maximum power supported by both the module and the band state = this->setTxPower(this->txPowerMax); if(state == RADIOLIB_ERR_NONE) { - this->txPowerCur = 0; + this->txPowerSteps = 0; adrStage = 0; // successfully did some ADR stuff } } @@ -1067,7 +1062,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon block1[RADIOLIB_LW_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LW_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK].idx; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FcntUp = %d) decoded:", this->fCntUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %d) decoded:", this->fCntUp); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -1115,7 +1110,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon event->confirming = isConfirmingDown; event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; - event->power = this->txPowerMax - this->txPowerCur * 2; + event->power = this->txPowerMax - this->txPowerSteps * 2; event->fCnt = this->fCntUp; event->fPort = fPort; } @@ -1135,7 +1130,7 @@ int16_t LoRaWANNode::downlinkCommon() { // check if there are any upcoming Rx windows // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 - RadioLibTime_t now = mod->hal->millis(); // Fix the current timestamp to prevent negative delays + RadioLibTime_t now = mod->hal->millis(); // fix the current timestamp to prevent negative delays if(now > this->rxDelayStart + this->rxDelays[0] - scanGuard) { // if between start of Rx1 and end of Rx2, wait until Rx2 closes if(now < this->rxDelayStart + this->rxDelays[1]) { @@ -1293,13 +1288,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t downlinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #endif - // set the MIC calculation block - memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); - downlinkMsg[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); - downlinkMsg[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_DOWNLINK; - downlinkMsg[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); - // read the data state = this->phyLayer->readData(&downlinkMsg[RADIOLIB_AES128_BLOCK_SIZE], downlinkMsgLen); // downlink frames are sent without CRC, which will raise error on SX127x @@ -1315,42 +1303,73 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) return(state); } - // get the frame counter and set it to the MIC calculation block - uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_FCNT_POS]); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_FCNT_POS], fCnt16); + // check the address + uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS]); + if(addr != this->devAddr) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + + // calculate length of FOpts and payload + uint8_t fOptsLen = downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FHDR_FOPTS_LEN_MASK; - // if this downlink is confirming an uplink, its MIC was generated with the least-significant 16 bits of that fCntUp + // check if the ACK bit is set, indicating this frame acknowledges the previous uplink bool isConfirmingUp = false; - if((downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FCTRL_ACK) && (this->rev == 1)) { + if((downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FCTRL_ACK)) { isConfirmingUp = true; + } + + // total - MHDR(1) - DevAddr(4) - FCtrl(1) - FCnt(2) - FOpts - MIC(4) + // potentially also an FPort, but we'll find out soon enough + uint8_t payLen = downlinkMsgLen - 1 - 4 - 1 - 2 - fOptsLen - 4; + + // get the frame counter + uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_FCNT_POS]); + + // set the MIC calculation blocks + memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + downlinkMsg[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; + // if this downlink is confirming an uplink, the MIC was generated with the least-significant 16 bits of that fCntUp + if(isConfirmingUp && (this->rev == 1)) { LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); } - - // calculate length of FOpts and payload - uint8_t fOptsLen = downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FHDR_FOPTS_LEN_MASK; - int payLen = downlinkMsgLen - 8 - fOptsLen - sizeof(uint32_t); - - // in LoRaWAN v1.1, a frame can be a network frame if there is no Application payload - // i.e., no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) - // TODO "NFCntDown is used for MAC communication on fPort 0 and when the FPort field is missing" - // so what about empty frames for ACK? Per TS008, these should be Application downlinks - bool isAppDownlink = true; - if(payLen <= 0) { - if(this->rev == 1) { - isAppDownlink = false; - } + downlinkMsg[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_DOWNLINK; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_FCNT_POS], fCnt16); + downlinkMsg[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); + + // check the MIC + if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_CRC_MISMATCH); + } + + // in LoRaWAN v1.1, a frame is a Network frame if there is no Application payload + // i.e.: either no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) + uint8_t fPort = RADIOLIB_LW_FPORT_MAC_COMMAND; + bool isAppDownlink = false; + if(this->rev == 0) { + isAppDownlink = true; } - else if(downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)] == RADIOLIB_LW_FPORT_MAC_COMMAND) { - fOptsLen = payLen - 1; - if(this->rev == 1) { - isAppDownlink = false; + if(payLen > 0) { + payLen -= 1; // subtract one as fPort is set + fPort = downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)]; + if(fPort > RADIOLIB_LW_FPORT_MAC_COMMAND) { + isAppDownlink = true; + } else { + fOptsLen = payLen; } } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFcntDown = %d) encoded:", isAppDownlink ? "A" : "N", fCnt16); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %d) encoded:", isAppDownlink ? "A" : "N", fCnt16); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); - // check the FcntDown value (Network or Application) + // check the fCntDown value (Network or Application) uint32_t fCntDownPrev = 0; if (isAppDownlink) { fCntDownPrev = this->aFCntDown; @@ -1378,14 +1397,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } } - // check the MIC - if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_CRC_MISMATCH); - } - // save current fCnt to respective frame counter if (isAppDownlink) { this->aFCntDown = fCnt32; @@ -1400,16 +1411,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) isConfirmedDown = true; } - // check the address - uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS]); - if(addr != this->devAddr) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_DOWNLINK_MALFORMED); - } - // process FOpts (if there are any) if(fOptsLen > 0) { // there are some Fopts, decrypt them @@ -1478,7 +1479,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) delete[] fOpts; #endif - // if FOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink + // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(this->commandsUp.len > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { size_t fOptsBufSize = this->commandsUp.len; #if RADIOLIB_STATIC_ONLY @@ -1546,13 +1547,13 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->confirming = isConfirmingUp; event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; - event->power = this->txPowerMax - this->txPowerCur * 2; + event->power = this->txPowerMax - this->txPowerSteps * 2; event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; - event->fPort = isAppDownlink ? downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)] : RADIOLIB_LW_FPORT_MAC_COMMAND; + event->fPort = fPort; } - // process Application payload (if there is any) - if(payLen <= 0 || fOptsLen > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { + // if MAC-only payload, return now + if(fPort == RADIOLIB_LW_FPORT_MAC_COMMAND) { // no payload *len = 0; #if !RADIOLIB_STATIC_ONLY @@ -1562,10 +1563,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) return(RADIOLIB_ERR_NONE); } - *len = payLen - 1; + // process Application payload + *len = payLen; // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fCnt16 - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(fOptsLen)], payLen - 1, this->appSKey, data, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(fOptsLen)], payLen, this->appSKey, data, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; @@ -1620,7 +1622,7 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { this->battLevel = battLevel; } -// return Fcnt of last uplink; also return 0 if no uplink occured yet +// return fCnt of last uplink; also return 0 if no uplink occured yet uint32_t LoRaWANNode::getFCntUp() { if(this->fCntUp == 0) { return(0); @@ -1684,7 +1686,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { this->FSK = false; } - int8_t pwr = this->txPowerMax - this->txPowerCur * 2; + int8_t pwr = this->txPowerMax - this->txPowerSteps * 2; // at this point, assume that Tx power value is already checked, so ignore the return value (void)this->phyLayer->checkOutputPower(pwr, &pwr); @@ -2234,7 +2236,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // only acknowledge if the radio is able to operate at or below the requested power level if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { pwrAck = 1; - this->txPowerCur = txSteps; + this->txPowerSteps = txSteps; } else { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); txSteps = 0x0F; // set value to 'keep the same' @@ -2278,7 +2280,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] << 4); } if(txSteps == 0x0F || !pwrAck) { - cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur; + cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerSteps; } if(nbTrans == 0) { cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 8c623066e6..f16398e4dd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -887,7 +887,7 @@ class LoRaWANNode { uint8_t adrLimitExp = RADIOLIB_LW_ADR_ACK_LIMIT_EXP; uint8_t adrDelayExp = RADIOLIB_LW_ADR_ACK_DELAY_EXP; uint8_t nbTrans = 1; // Number of allowed frame retransmissions - uint8_t txPowerCur = 0; + uint8_t txPowerSteps = 0; uint8_t txPowerMax = 0; uint32_t fCntUp = 0; uint32_t aFCntDown = 0; @@ -899,9 +899,6 @@ class LoRaWANNode { // whether the current configured channel is in FSK mode bool FSK = false; - // flag that shows whether the device is joined and there is an ongoing session (none, ABP or OTAA) - uint16_t activeMode = RADIOLIB_LW_MODE_NONE; - // ADR is enabled by default bool adrEnabled = true; From 86cdefe8a2d8e245f61ee61c718e2db7d6d9d052 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 May 2024 11:35:35 +0200 Subject: [PATCH 1029/1848] [LR11x0] Added support for WiFi scanning --- .../LR11x0_WiFi_Scan_Blocking.ino | 112 +++++++++++ .../LR11x0_WiFi_Scan_Interrupt.ino | 150 +++++++++++++++ keywords.txt | 11 ++ src/TypeDef.h | 7 + src/modules/LR11x0/LR11x0.cpp | 180 ++++++++++++++++-- src/modules/LR11x0/LR11x0.h | 170 ++++++++++++++++- 6 files changed, 616 insertions(+), 14 deletions(-) create mode 100644 examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino create mode 100644 examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino new file mode 100644 index 0000000000..b1643a3397 --- /dev/null +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino @@ -0,0 +1,112 @@ +/* + RadioLib LR11x0 WiFi scan Blocking Example + + This example performs a passive scan of WiFi networks. + The scan shows basic information about the networks, + such as the frequency, country code and SSID. + + Other modules from LR11x0 family can also be used. + + Using blocking scan is not recommended, as depending + on the scan settings, the program may be blocked + for several seconds! Instead, interrupt scan is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---wifi-scan + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[LR1110] Running WiFi scan ... ")); + + // scan all WiFi signals with default scan configuration + uint8_t count = 0; + int state = radio.wifiScan('*', &count); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print the table header + Serial.print(F("[LR1110] Reading ")); + Serial.print(count); + Serial.println(F(" scan results:")); + Serial.println(F(" # | WiFi type\t| Frequency\t| MAC Address\t | Country\t| RSSI [dBm]\t| SSID")); + + // read all results one by one + // this result type contains the most information, including the SSID + LR11x0WifiResultExtended_t result; + for(int i = 0; i < count; i++) { + if(i < 10) { Serial.print(" "); } Serial.print(i); Serial.print(" | "); + state = radio.getWifiScanResult(&result, i); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("Failed to read result, code ")); + Serial.println(state); + continue; + } + + // print the basic information + Serial.print(F("802.11")); Serial.print(result.type); Serial.print("\t| "); + Serial.print(result.channelFreq); Serial.print(" MHz\t| "); + + // print MAC address + for(int j = 0; j < 6; j++) { + if(result.mac[j] < 0x10) { Serial.print("0"); } + Serial.print(result.mac[j], HEX); + if(j < 5) { Serial.print(":"); } + } + Serial.print(" | "); + + // print the two-letter country code + String country = result.countryCode; + Serial.print(country); + Serial.print(" \t| "); + + // print the RSSI + Serial.print(result.rssi); + Serial.print("\t| "); + + // print the network SSID + Serial.println((char*)result.ssid); + + } + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before scanning again + delay(1000); +} diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino new file mode 100644 index 0000000000..bf999ba15d --- /dev/null +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -0,0 +1,150 @@ +/* + RadioLib LR11x0 WiFi scan Interrupt Example + + This example performs a passive scan of WiFi networks. + The scan shows basic information about the networks, + such as the frequency, country code and SSID. + + Other modules from LR11x0 family can also be used. + + Using blocking scan is not recommended, as depending + on the scan settings, the program may be blocked + for several seconds! Instead, interrupt scan is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---wifi-scan + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when WiFi scan is complete + radio.setIrqAction(setFlag); + + // scan all WiFi signals with default scan configuration + Serial.print(F("[LR1110] Starting passive WiFi scan ... ")); + state = radio.startWifiScan('*'); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a scan was completed +volatile bool scanFlag = false; + +// this function is called when a scan is completed +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // scan is complete, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // get the number of scan results + uint8_t count = 0; + Serial.print(F("[LR1110] Reading WiFi scan results ... ")); + int state = radio.getWifiScanResultsCount(&count); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print the table header + Serial.print(F("[LR1110] Reading ")); + Serial.print(count); + Serial.println(F(" scan results:")); + Serial.println(F(" # | WiFi type\t| Frequency\t| MAC Address\t | Country\t| RSSI [dBm]\t| SSID")); + + // read all results one by one + // this result type contains the most information, including the SSID + LR11x0WifiResultExtended_t result; + for(int i = 0; i < count; i++) { + if(i < 10) { Serial.print(" "); } Serial.print(i); Serial.print(" | "); + state = radio.getWifiScanResult(&result, i); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("Failed to read result, code ")); + Serial.println(state); + continue; + } + + // print the basic information + Serial.print(F("802.11")); Serial.print(result.type); Serial.print("\t| "); + Serial.print(result.channelFreq); Serial.print(" MHz\t| "); + + // print MAC address + for(int j = 0; j < 6; j++) { + if(result.mac[j] < 0x10) { Serial.print("0"); } + Serial.print(result.mac[j], HEX); + if(j < 5) { Serial.print(":"); } + } + Serial.print(" | "); + + // print the two-letter country code + String country = result.countryCode; + Serial.print(country); + Serial.print(" \t| "); + + // print the RSSI + Serial.print(result.rssi); + Serial.print("\t| "); + + // print the network SSID + Serial.println((char*)result.ssid); + } + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // start scanning again + Serial.print(F("[LR1110] Starting passive WiFi scan ... ")); + state = radio.startWifiScan('*'); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/keywords.txt b/keywords.txt index f53f5d1c76..fac7aa1ced 100644 --- a/keywords.txt +++ b/keywords.txt @@ -91,6 +91,11 @@ AS923 KEYWORD1 KR920 KEYWORD1 IN865 KEYWORD1 +# LR11x0 scan results +LR11x0WifiResult_t KEYWORD1 +LR11x0WifiResultFull_t KEYWORD1 +LR11x0WifiResultExtended_t KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### @@ -243,6 +248,12 @@ setAutoAck KEYWORD2 # LR11x0 beginLRFHSS KEYWORD2 setLrFhssConfig KEYWORD2 +startWifiScan KEYWORD2 +getWifiScanResultsCount KEYWORD2 +getWifiScanResult KEYWORD2 +wifiScan KEYWORD2 +setWiFiScanAction KEYWORD2 +clearWiFiScanAction KEYWORD2 # RTTY idle KEYWORD2 diff --git a/src/TypeDef.h b/src/TypeDef.h index 61109d52cf..245eb72a4c 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -563,6 +563,13 @@ */ #define RADIOLIB_LORAWAN_NO_DOWNLINK (-1116) +// LR11x0-specific status codes + +/*! + \brief The selected 802.11 WiFi type is invalid. +*/ +#define RADIOLIB_ERR_INVALID_WIFI_TYPE (-1200) + /*! \} */ diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index c9244bb894..3001563cb5 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1335,6 +1335,168 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16 return(RADIOLIB_ERR_NONE); } +int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { + uint8_t type; + switch(wifiType) { + case('b'): + type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_B; + break; + case('g'): + type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_G; + break; + case('n'): + type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_N; + break; + case('*'): + type = RADIOLIB_LR11X0_WIFI_SCAN_ALL; + break; + default: + return(RADIOLIB_ERR_INVALID_WIFI_TYPE); + } + + // go to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // reset cumulative timings + state = wifiResetCumulTimings(); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE, 0); + RADIOLIB_ASSERT(state); + + // start scan with the maximum number of results and abort on timeout + this->wifiScanMode = mode; + state = wifiScan(type, chanMask, this->wifiScanMode, RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS, numScans, timeout, RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED); + return(state); +} + +void LR11x0::setWiFiScanAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void LR11x0::clearWiFiScanAction() { + this->clearIrqAction(); +} + +int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) { + // clear IRQ first, as this is likely to be called right after scan has finished + int16_t state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + uint8_t buff[1] = { 0 }; + state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff)); + + // pass the replies + if(count) { *count = buff[0]; } + + return(state); +} + +int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) { + if(!result) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + // read a single result + uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE; + uint8_t raw[RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN] = { 0 }; + int16_t state = wifiReadResults(index, 1, format, raw); + RADIOLIB_ASSERT(state); + + // parse the information + switch(raw[0] & 0x03) { + case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_B): + result->type = 'b'; + break; + case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_G): + result->type = 'g'; + break; + case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_N): + result->type = 'n'; + break; + } + result->dataRateId = (raw[0] & 0xFC) >> 2; + result->channelFreq = 2407 + (raw[1] & 0x0F)*5; + result->origin = (raw[1] & 0x30) >> 4; + result->ap = (raw[1] & 0x40) != 0; + result->rssi = (float)raw[2] / -2.0f;; + memcpy(result->mac, &raw[3], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + + if(!brief) { + if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) { + LR11x0WifiResultExtended_t* resultExtended = (LR11x0WifiResultExtended_t*)result; + resultExtended->rate = raw[3]; + resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5])); + resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7])); + resultExtended->frameType = raw[9] & 0x03; + resultExtended->frameSubType = (raw[9] & 0x3C) >> 2; + resultExtended->toDistributionSystem = (raw[9] & 0x40) != 0; + resultExtended->fromDistributionSystem = (raw[9] & 0x80) != 0; + memcpy(resultExtended->mac0, &raw[10], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + memcpy(resultExtended->mac, &raw[16], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + memcpy(resultExtended->mac2, &raw[22], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + resultExtended->timestamp = (((uint64_t)raw[28] << 56) | ((uint64_t)raw[29] << 48)) | + (((uint64_t)raw[30] << 40) | ((uint64_t)raw[31] << 32)) | + (((uint64_t)raw[32] << 24) | ((uint64_t)raw[33] << 16)) | + (((uint64_t)raw[34] << 8) | (uint64_t)raw[35]); + resultExtended->periodBeacon = (((uint16_t)raw[36] << 8) | ((uint16_t)raw[37])) * 1024UL; + resultExtended->seqCtrl = (((uint16_t)raw[38] << 8) | ((uint16_t)raw[39])); + memcpy(resultExtended->ssid, &raw[40], RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN); + resultExtended->currentChannel = raw[72]; + memcpy(resultExtended->countryCode, &raw[73], 2); + resultExtended->countryCode[2] = '\0'; + resultExtended->ioReg = raw[75]; + resultExtended->fcsCheckOk = (raw[76] != 0); + resultExtended->phiOffset = (((uint16_t)raw[77] << 8) | ((uint16_t)raw[78])); + return(RADIOLIB_ERR_NONE); + } + + LR11x0WifiResultFull_t* resultFull = (LR11x0WifiResultFull_t*)result; + resultFull->frameType = raw[3] & 0x03; + resultFull->frameSubType = (raw[3] & 0x3C) >> 2; + resultFull->toDistributionSystem = (raw[3] & 0x40) != 0; + resultFull->fromDistributionSystem = (raw[3] & 0x80) != 0; + memcpy(resultFull->mac, &raw[4], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + resultFull->phiOffset = (((uint16_t)raw[10] << 8) | ((uint16_t)raw[11])); + resultFull->timestamp = (((uint64_t)raw[12] << 56) | ((uint64_t)raw[13] << 48)) | + (((uint64_t)raw[14] << 40) | ((uint64_t)raw[15] << 32)) | + (((uint64_t)raw[16] << 24) | ((uint64_t)raw[17] << 16)) | + (((uint64_t)raw[18] << 8) | (uint64_t)raw[19]); + resultFull->periodBeacon = (((uint16_t)raw[20] << 8) | ((uint16_t)raw[21])) * 1024UL; + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { + if(!count) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + // start scan + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start"); + int16_t state = startWifiScan(wifiType, mode, chanMask, numScans, timeout); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout + RadioLibTime_t softTimeout = 30UL * 1000UL; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); + this->standby(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %d ms", this->mod->hal->millis() - start); + + // read number of results + return(getWifiScanResultsCount(count)); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -2282,7 +2444,9 @@ int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t n (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), abortOnTimeout }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN, true, buff, sizeof(buff))); + + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_WIFI_SCAN, buff, sizeof(buff), false, false)); } int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { @@ -2315,19 +2479,9 @@ int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16 return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); } -int16_t LR11x0::wifiGetNbResults(uint8_t* nbResults) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff)); - - // pass the replies - if(nbResults) { *nbResults = buff[0]; } - - return(state); -} - int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) { - uint8_t reqBuff[3] = { index, nbResults, format }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff))); + uint8_t buff[3] = { index, nbResults, format }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN, buff, sizeof(buff))); } int16_t LR11x0::wifiResetCumulTimings(void) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 3a100e637f..53edd721c9 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -472,10 +472,15 @@ #define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon #define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled #define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled +#define RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS (32) // 7 0 maximum possible number of Wi-Fi scan results +#define RADIOLIB_LR11X0_WIFI_ALL_CHANNELS (0x3FFFUL) // 16 0 scan all channels // RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS #define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete #define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic +#define RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN (79) // 7 0 maximum possible Wi-Fi scan size +#define RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN (6) // 7 0 MAC address length in bytes +#define RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN (32) // 7 0 SSID length in bytes // RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE #define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS @@ -536,10 +541,108 @@ // RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX #define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata +/*! + \struct LR11x0WifiResult_t + \brief Structure to save result of passive WiFi scan. + This result only saves the basic information. +*/ +struct LR11x0WifiResult_t { + /*! \brief WiFi (802.11) signal type, 'b', 'n' or 'g' */ + char type; + + /*! \brief Data rate ID holding information about modulation and coding rate. See LR11x0 user manual for details. */ + uint8_t dataRateId; + + /*! \brief Channel frequency in MHz */ + uint16_t channelFreq; + + /*! \brief MAC address origin: from gateway (1), phone (2) or undetermined (3) */ + uint8_t origin; + + /*! \brief Whether this signal was sent by an access point (true) or end device (false) */ + bool ap; + + /*! \brief RSSI in dBm */ + float rssi; + + /*! \brief MAC address */ + uint8_t mac[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; +}; + +/*! + \struct LR11x0WifiResultFull_t + \brief Structure to save result of passive WiFi scan. + This result saves additional information alongside that in LR11x0WifiResult_t. +*/ +struct LR11x0WifiResultFull_t: public LR11x0WifiResult_t { + /*! \brief Frame type. See LR11x0 user manual for details. */ + uint8_t frameType; + + /*! \brief Frame sub type. See LR11x0 user manual for details. */ + uint8_t frameSubType; + + /*! \brief Frame sent from client station to distribution system. */ + bool toDistributionSystem; + + /*! \brief Frame sent from distribution system to client station. */ + bool fromDistributionSystem; + + /*! \brief See LR11x0 user manual for details. */ + uint16_t phiOffset; + + /*! \brief Number of microseconds the AP has been active. */ + uint64_t timestamp; + + /*! \brief Beacon period in microseconds. */ + uint32_t periodBeacon; +}; + +/*! + \struct LR11x0WifiResultExtended_t + \brief Structure to save result of passive WiFi scan. + This result saves additional information alongside that in LR11x0WifiResultFull_t. + Only scans performed with RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON acquisition mode + can yield this result! +*/ +struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t { + /*! \brief Data rate. See LR11x0 user manual for details. */ + uint8_t rate; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint16_t service; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint16_t length; + + /*! \brief MAC address 0 */ + uint8_t mac0[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; + + /*! \brief MAC address 2 */ + uint8_t mac2[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint16_t seqCtrl; + + /*! \brief SSID */ + uint8_t ssid[RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN]; + + /*! \brief WiFi channel number */ + uint8_t currentChannel; + + /*! \brief Two-letter country code (null-terminated string). */ + char countryCode[3]; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint8_t ioReg; + + /*! \brief True if frame check sequences is valid, false otherwise. */ + bool fcsCheckOk; +}; /*! \class LR11x0 - \brief + \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. + This class should not be instantiated directly from user code, only from its derived classes. */ class LR11x0: public PhysicalLayer { public: @@ -1053,6 +1156,69 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeed = 0x13A); + + /*! + \brief Start passive WiFi scan. BUSY pin will be de-activated when the scan is finished. + \param wifiType Type of WiFi (802.11) signals to scan, 'b', 'n', 'g' or '*' for all signals. + \param mode Scan acquisition mode, one of RADIOLIB_LR11X0_WIFI_ACQ_MODE_*. + The type of results available after the scan depends on this mode. + Defaults to RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, which provides the most information. + \param chanMask Bit mask of WiFi channels to scan, defaults to all channels. + More channels leads to longer overall scan duration. + \param numScans Number of scans to perform per each enabled channel. Defaults to 16 scans. + More scans leads to longer overall scan duration. + \param timeout Timeout of each scan in milliseconds. Defaults to 100 ms + Longer timeout leads to longer overall scan duration. + \returns \ref status_codes + */ + int16_t startWifiScan(char wifiType, uint8_t mode = RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, uint16_t chanMask = RADIOLIB_LR11X0_WIFI_ALL_CHANNELS, uint8_t numScans = 16, uint16_t timeout = 100); + + /*! + \brief Sets interrupt service routine to call when a WiFi scan is completed. + \param func ISR to call. + */ + void setWiFiScanAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when a WiFi scan is completed. + */ + void clearWiFiScanAction(); + + /*! + \brief Get number of WiFi scan results after the scan is finished. + \param count Pointer to a variable that will hold the number of scan results. + \returns \ref status_codes + */ + int16_t getWifiScanResultsCount(uint8_t* count); + + /*! + \brief Retrieve passive WiFi scan result. + \param result Pointer to structure to hold the result data. + \param index Result index, starting from 0. The number of scan results can be retrieved by calling getWifiScanResultsCount. + \param brief Whether to only retrieve the results in brief format. If set to false, only information in LR11x0WifiResult_t + will be retrieved. If set to true, information in LR11x0WifiResultFull_t will be retrieved. In addition, if WiFi scan mode + was set to RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, all information in LR11x0WifiResultExtended_t will be retrieved. + \returns \ref status_codes + */ + int16_t getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief = false); + + /*! + \brief Blocking WiFi scan method. Performs a full passive WiFi scan. + This method may block for several seconds! + \param wifiType Type of WiFi (802.11) signals to scan, 'b', 'n', 'g' or '*' for all signals. + \param count Pointer to a variable that will hold the number of scan results. + \param mode Scan acquisition mode, one of RADIOLIB_LR11X0_WIFI_ACQ_MODE_*. + The type of results available after the scan depends on this mode. + Defaults to RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, which provides the most information. + \param chanMask Bit mask of WiFi channels to scan, defaults to all channels. + More channels leads to longer overall scan duration. + \param numScans Number of scans to perform per each enabled channel. Defaults to 16 scans. + More scans leads to longer overall scan duration. + \param timeout Timeout of each scan in milliseconds. Defaults to 100 ms + Longer timeout leads to longer overall scan duration. + \returns \ref status_codes + */ + int16_t wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode = RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, uint16_t chanMask = RADIOLIB_LR11X0_WIFI_ALL_CHANNELS, uint8_t numScans = 16, uint16_t timeout = 100); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -1229,6 +1395,8 @@ class LR11x0: public PhysicalLayer { float dataRateMeasured = 0; + uint8_t wifiScanMode = 0; + int16_t modSetup(float tcxoVoltage, uint8_t modem); static int16_t SPIparseStatus(uint8_t in); static int16_t SPIcheckStatus(Module* mod); From bcd8a05cd49eecb8c54b20f121eab81742ef8b34 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 May 2024 12:42:03 +0100 Subject: [PATCH 1030/1848] [SX128x] Added interface for interrupt-driven CAD (#1085) --- ...x_Channel_Activity_Detection_Interrupt.ino | 108 ++++++++++++++++++ src/modules/SX128x/SX128x.cpp | 81 +++++++------ src/modules/SX128x/SX128x.h | 13 +++ 3 files changed, 169 insertions(+), 33 deletions(-) create mode 100644 examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 0000000000..8daf635792 --- /dev/null +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,108 @@ +/* + RadioLib SX128x Channel Activity Detection Example + + This example uses SX1280 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + + Other modules from SX128x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setDio1Action(setFlag); + + // start scanning the channel + Serial.print(F("[SX1280] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[SX1280] Packet detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[SX1280] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[SX1280] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[SX1280] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 00f5b5e284..0a5333f244 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -411,28 +411,8 @@ int16_t SX128x::receiveDirect() { } int16_t SX128x::scanChannel() { - // check active modem - if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set mode to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set DIO pin mapping - state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE); - RADIOLIB_ASSERT(state); - - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_RX); - // set mode to CAD - state = setCad(); + int16_t state = startChannelScan(); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -441,18 +421,7 @@ int16_t SX128x::scanChannel() { } // check CAD result - uint16_t cadResult = getIrqStatus(); - if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) { - // detected some LoRa activity - clearIrqStatus(); - return(RADIOLIB_LORA_DETECTED); - } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) { - // channel is free - clearIrqStatus(); - return(RADIOLIB_CHANNEL_FREE); - } - - return(RADIOLIB_ERR_UNKNOWN); + return(getChannelScanResult()); } int16_t SX128x::sleep(bool retainConfig) { @@ -664,6 +633,52 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { return(state); } +int16_t SX128x::startChannelScan() { + // check active modem + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO pin mapping + state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set mode to CAD + return(setCad()); +} + +int16_t SX128x::getChannelScanResult() { + // check active modem + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check CAD result + uint16_t cadResult = getIrqStatus(); + int16_t state = RADIOLIB_ERR_UNKNOWN; + if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) { + // detected some LoRa activity + state = RADIOLIB_LORA_DETECTED; + } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) { + // channel is free + state = RADIOLIB_CHANNEL_FREE; + } + + clearIrqStatus(); + return(state); +} + int16_t SX128x::setFrequency(float freq) { RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 80618d71f4..a68f6c5b66 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -568,6 +568,19 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. + \returns \ref status_codes + */ + int16_t startChannelScan() override; + + /*! + \brief Read the channel scan result + \returns \ref status_codes + */ + int16_t getChannelScanResult() override; // configuration methods From 4f1e5c552168b53646b5c0bf9b4b28053ada18ca Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 May 2024 20:42:06 +0200 Subject: [PATCH 1031/1848] [LR11x0] Added LoRa header configuration methods --- src/modules/LR11x0/LR11x0.cpp | 28 ++++++++++++++++++++++++++++ src/modules/LR11x0/LR11x0.h | 14 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 3001563cb5..fa68071b24 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1310,6 +1310,14 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { return(0); } +int16_t LR11x0::implicitHeader(size_t len) { + return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT, len)); +} + +int16_t LR11x0::explicitHeader() { + return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT)); +} + float LR11x0::getDataRate() const { return(this->dataRateMeasured); } @@ -1694,6 +1702,26 @@ int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { return(setCad()); } +int16_t LR11x0::setHeaderType(uint8_t hdrType, size_t len) { + // check active modem + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + state = setPacketParamsLoRa(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + + // update cached value + this->headerType = hdrType; + this->implicitLen = len; + + return(state); +} + Module* LR11x0::getMod() { return(this->mod); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 53edd721c9..42ed4e564e 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1141,6 +1141,19 @@ class LR11x0: public PhysicalLayer { */ RadioLibTime_t getTimeOnAir(size_t len) override; + /*! + \brief Set implicit header mode for future reception/transmission. + \param len Payload length in bytes. + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + \returns \ref status_codes + */ + int16_t explicitHeader(); + /*! \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. \returns Effective data rate in bps. @@ -1404,6 +1417,7 @@ class LR11x0: public PhysicalLayer { int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); // common methods to avoid some copy-paste int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); From 26fb617062c0de233470cbb5d46e97f236324b8b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 May 2024 19:47:09 +0100 Subject: [PATCH 1032/1848] [MOD] Make cmd pointer const --- src/Module.cpp | 2 +- src/Module.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 7d02d9a08f..8a95d52033 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -313,7 +313,7 @@ int16_t Module::SPIcheckStream() { return(state); } -int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout) { +int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout) { // prepare the output buffer size_t buffLen = cmdLen + numBytes; if(!write) { diff --git a/src/Module.h b/src/Module.h index ea48184b05..90de297703 100644 --- a/src/Module.h +++ b/src/Module.h @@ -371,7 +371,7 @@ class Module { \param timeout GPIO wait period timeout in milliseconds. \returns \ref status_codes */ - int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout); + int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout); // pin number access methods From 4f52738ed413080511e28f8c9afe63c0bd88d633 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 May 2024 20:10:46 +0100 Subject: [PATCH 1033/1848] [LLCC68] Fixed issues found by cppcheck --- src/modules/LLCC68/LLCC68.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 3a737060fb..08c52af338 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -21,7 +21,7 @@ class LLCC68: public SX1262 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - LLCC68(Module* mod); + LLCC68(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Initialization method for LoRa modem. From 3b62c88a2e28e3f5bff97867fa64dc71cc57d036 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 May 2024 20:11:02 +0100 Subject: [PATCH 1034/1848] [SX126x] Fixed issues found by cppcheck --- src/modules/SX126x/STM32WLx.cpp | 1 + src/modules/SX126x/STM32WLx.h | 14 ++++++------- src/modules/SX126x/SX1261.h | 6 +++--- src/modules/SX126x/SX1262.h | 8 ++++---- src/modules/SX126x/SX1268.h | 8 ++++---- src/modules/SX126x/SX126x.cpp | 17 ++++++++-------- src/modules/SX126x/SX126x.h | 36 ++++++++++++++++----------------- 7 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 508ea4e591..69515fcfe4 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -87,6 +87,7 @@ int16_t STM32WLx::setOutputPower(int8_t power) { return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } + RADIOLIB_ASSERT(state); // Apply workaround for HP only state = SX126x::fixPaClamping(use_hp); diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index 16c88cc95e..993791aae1 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -39,7 +39,7 @@ class STM32WLx : public SX1262 { \brief Default constructor. \param mod Instance of STM32WLx_Module that will be used to communicate with the radio. */ - STM32WLx(STM32WLx_Module* mod); + STM32WLx(STM32WLx_Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Custom operation modes for STMWLx. @@ -124,34 +124,34 @@ class STM32WLx : public SX1262 { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Sets interrupt service routine to call when a channel scan is finished. \param func ISR to call. */ - void setChannelScanAction(void (*func)(void)); + void setChannelScanAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a channel scan is finished. */ - void clearChannelScanAction(); + void clearChannelScanAction() override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 6f40115993..196cc21bc4 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -25,14 +25,14 @@ class SX1261 : public SX1262 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1261(Module* mod); + SX1261(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Sets output power. Allowed values are in range from -17 to 14 dBm. \param power Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power) override; /*! \brief Check if output power is configurable. @@ -40,7 +40,7 @@ class SX1261 : public SX1262 { \param clipped Clipped output power value to what is possible within the module's range. \returns \ref status_codes */ - int16_t checkOutputPower(int8_t power, int8_t* clipped); + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index ebe8652a50..7ae6789fdd 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -25,7 +25,7 @@ class SX1262: public SX126x { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1262(Module* mod); + SX1262(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -69,7 +69,7 @@ class SX1262: public SX126x { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. @@ -85,7 +85,7 @@ class SX1262: public SX126x { \param power Output power to be set in dBm. \returns \ref status_codes */ - virtual int16_t setOutputPower(int8_t power); + virtual int16_t setOutputPower(int8_t power) override; /*! \brief Check if output power is configurable. @@ -93,7 +93,7 @@ class SX1262: public SX126x { \param clipped Clipped output power value to what is possible within the module's range. \returns \ref status_codes */ - int16_t checkOutputPower(int8_t power, int8_t* clipped); + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index d6f0415e72..503c74e861 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -24,7 +24,7 @@ class SX1268: public SX126x { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1268(Module* mod); + SX1268(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -68,7 +68,7 @@ class SX1268: public SX126x { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. @@ -83,7 +83,7 @@ class SX1268: public SX126x { \param power Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power) override; /*! \brief Check if output power is configurable. @@ -91,7 +91,7 @@ class SX1268: public SX126x { \param clipped Clipped output power value to what is possible within the module's range. \returns \ref status_codes */ - int16_t checkOutputPower(int8_t power, int8_t* clipped); + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 105d1fda86..aca4f15b61 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -76,10 +76,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo RADIOLIB_ASSERT(state); if (useRegulatorLDO) { - state = setRegulatorLDO(); + state = setRegulatorLDO(); } else { - state = setRegulatorDCDC(); + state = setRegulatorDCDC(); } + RADIOLIB_ASSERT(state); // set publicly accessible settings that are not a part of begin method state = setCurrentLimit(60.0); @@ -1577,7 +1578,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) // check the version #if RADIOLIB_DEBUG_BASIC char ver_pre[16]; - this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast(ver_pre)); RADIOLIB_DEBUG_BASIC_PRINTLN("Pre-update version string: %s", ver_pre); #endif @@ -1609,7 +1610,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) // check the version again #if RADIOLIB_DEBUG_BASIC char ver_post[16]; - this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast(ver_post)); RADIOLIB_DEBUG_BASIC_PRINTLN("Post-update version string: %s", ver_post); #endif @@ -1736,7 +1737,7 @@ int16_t SX126x::setRx(uint32_t timeout) { int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { // default CAD parameters are shown in Semtech AN1200.48, page 41. - uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30}; + const uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30}; // CAD parameters aren't available for SF-6. Just to be safe. if(this->spreadingFactor < 7) { @@ -2163,18 +2164,18 @@ bool SX126x::findChip(const char* verStr) { // read the version string char version[16]; - this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version); + this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast(version)); // check version register if(strncmp(verStr, version, 6) == 0) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:"); - RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast(version), 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_BASIC_PRINTLN(); flagFound = true; } else { #if RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_BASIC_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1); - RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast(version), 16, RADIOLIB_SX126X_REG_VERSION_STRING); RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr); #endif this->mod->hal->delay(10); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index f8829b9c26..2bd3a042fa 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -452,7 +452,7 @@ class SX126x: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX126x(Module* mod); + SX126x(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. @@ -586,34 +586,34 @@ class SX126x: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Sets interrupt service routine to call when a channel scan is finished. \param func ISR to call. */ - void setChannelScanAction(void (*func)(void)); + void setChannelScanAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a channel scan is finished. */ - void clearChannelScanAction(); + void clearChannelScanAction() override; /*! \brief Interrupt-driven binary transmit method. @@ -637,7 +637,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. @@ -786,7 +786,7 @@ class SX126x: public PhysicalLayer { \param br FSK bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Set data. @@ -920,7 +920,7 @@ class SX126x: public PhysicalLayer { \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. \returns SNR of the last received packet in dB. */ - float getSNR(); + float getSNR() override; /*! \brief Gets frequency error of the latest received packet. @@ -964,7 +964,7 @@ class SX126x: public PhysicalLayer { \param timeoutUs Timeout in microseconds to listen for \returns Timeout value in a unit that is specific for the used module */ - RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; /*! \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks @@ -972,13 +972,13 @@ class SX126x: public PhysicalLayer { \param irqMask Mask indicating which IRQ triggers a DIO \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) override; /*! \brief Check whether the IRQ bit for RxTimeout is set \returns Whether RxTimeout IRQ is set */ - bool isRxTimeout(); + bool isRxTimeout() override; /*! \brief Set implicit header mode for future reception/transmission. @@ -1040,7 +1040,7 @@ class SX126x: public PhysicalLayer { \brief Get one truly random byte from RSSI noise. \returns TRNG byte. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Enable/disable inversion of the I and Q signals @@ -1054,13 +1054,13 @@ class SX126x: public PhysicalLayer { \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ - void setDirectAction(void (*func)(void)); + void setDirectAction(void (*func)(void)) override; /*! \brief Function to read and process data bit in direct reception mode. \param pin Pin on which to read. */ - void readBit(uint32_t pin); + void readBit(uint32_t pin) override; #endif /*! @@ -1132,7 +1132,7 @@ class SX126x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; // SX126x SPI command implementations int16_t setFs(); @@ -1163,7 +1163,7 @@ class SX126x: public PhysicalLayer { #if !RADIOLIB_GODMODE protected: #endif - const char* chipType; + const char* chipType = NULL; uint8_t bandwidth = 0; // Allow subclasses to define different TX modes From 2c9446ef1e7651f566834304365163c56f04f513 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:50:34 +0200 Subject: [PATCH 1035/1848] [LoRaWAN] Added rx start assert --- src/protocols/LoRaWAN/LoRaWAN.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 866ce10988..7a5bcf4b5d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1174,6 +1174,7 @@ int16_t LoRaWANNode::downlinkCommon() { // open Rx window by starting receive with specified timeout state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); + RADIOLIB_ASSERT(state); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, (int)timeoutHost); // wait for the timeout to complete (and a small additional delay) From 90eca888596c4bb311dd3ccaca526621bc0c27df Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:51:43 +0200 Subject: [PATCH 1036/1848] [LoRaWAN] Use 32-bit IRQ flags --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7a5bcf4b5d..d1fdd42741 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1146,8 +1146,8 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_ASSERT(state); // create the masks that are required for receiving downlinks - uint16_t irqFlags = 0x0000; - uint16_t irqMask = 0x0000; + uint32_t irqFlags = 0; + uint32_t irqMask = 0; this->phyLayer->irqRxDoneRxTimeout(irqFlags, irqMask); this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 293402ae32..f351cb471f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -132,7 +132,7 @@ int16_t PhysicalLayer::startReceive() { return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t PhysicalLayer::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; @@ -310,7 +310,7 @@ RadioLibTime_t PhysicalLayer::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(0); } -int16_t PhysicalLayer::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { +int16_t PhysicalLayer::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { (void)irqFlags; (void)irqMask; return(RADIOLIB_ERR_UNSUPPORTED); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 3d48eda2b1..9b3dc24cac 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -144,7 +144,7 @@ class PhysicalLayer { \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). \returns \ref status_codes */ - virtual int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + virtual int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); /*! \brief Binary receive method. Must be implemented in module class. @@ -358,7 +358,7 @@ class PhysicalLayer { \param irqMask Mask indicating which IRQ triggers a DIO \returns \ref status_codes */ - virtual int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + virtual int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); /*! \brief Check whether the IRQ bit for RxTimeout is set From 2a776f4c094c25c19768c091dacac49c2a74a748 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:52:15 +0200 Subject: [PATCH 1037/1848] [CC1101] Use 32-bit IRQ flags --- src/modules/CC1101/CC1101.cpp | 2 +- src/modules/CC1101/CC1101.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 1da68a02dc..09e07b27b4 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -361,7 +361,7 @@ int16_t CC1101::startReceive() { return(state); } -int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t CC1101::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 0519da9978..e61c5fc437 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -709,7 +709,7 @@ class CC1101: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) override; + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override; /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, From 44afc5a6f56139619403f1285516562c8da6d91e Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:52:31 +0200 Subject: [PATCH 1038/1848] [nRF24] Use 32-bit IRQ flags --- src/modules/nRF24/nRF24.cpp | 2 +- src/modules/nRF24/nRF24.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 0e9d45c19f..f28f757e7c 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -249,7 +249,7 @@ int16_t nRF24::startReceive() { return(state); } -int16_t nRF24::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t nRF24::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index cb63256612..0a0dc1e317 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -327,7 +327,7 @@ class nRF24: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, From be564745966ce4732f9e4b91887e98adf2380fb5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:52:42 +0200 Subject: [PATCH 1039/1848] [RF69] Use 32-bit IRQ flags --- src/modules/RF69/RF69.cpp | 2 +- src/modules/RF69/RF69.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 3044260c9c..5544ad5d30 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -259,7 +259,7 @@ int16_t RF69::startReceive() { return(state); } -int16_t RF69::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t RF69::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 9eda1d886d..40b780766d 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -707,7 +707,7 @@ class RF69: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, From df9e9ee68c392ab6aee51e7f1f09db1c7250156b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:52:51 +0200 Subject: [PATCH 1040/1848] [Si443x] Use 32-bit IRQ flags --- src/modules/Si443x/Si443x.cpp | 2 +- src/modules/Si443x/Si443x.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index c6a225afb4..7812099214 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -300,7 +300,7 @@ int16_t Si443x::startReceive() { return(state); } -int16_t Si443x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t Si443x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 9d6398064a..b8986b652b 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -705,7 +705,7 @@ class Si443x: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, From 8eac3f1bf25e6f78d193b224338baa4684b67c00 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:53:01 +0200 Subject: [PATCH 1041/1848] [SX127x] Use 32-bit IRQ flags --- src/modules/SX127x/SX127x.cpp | 4 ++-- src/modules/SX127x/SX127x.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index bda0080ad8..6c9c659896 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -419,7 +419,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { return(setMode(mode)); } -int16_t SX127x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t SX127x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)irqFlags; (void)irqMask; uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS; @@ -1289,7 +1289,7 @@ RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(numSymbols); } -int16_t SX127x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { +int16_t SX127x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { // IRQ flags/masks are inverted to what seems logical for SX127x (0 being activated, 1 being deactivated) irqFlags = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT; irqMask = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE & RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 05edabb0c6..d9f3f87036 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -832,7 +832,7 @@ class SX127x: public PhysicalLayer { \param len Expected length of packet to be received. Required for LoRa spreading factor 6. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, @@ -1070,7 +1070,7 @@ class SX127x: public PhysicalLayer { \param irqMask Mask indicating which IRQ triggers a DIO \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask); + int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); /*! \brief Check whether the IRQ bit for RxTimeout is set From bfb7c8dd3b477c0efe5fca0a73f9f2b172f19799 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:54:22 +0200 Subject: [PATCH 1042/1848] [SX126x] Use 32-bit IRQ flags --- src/modules/SX126x/SX126x.cpp | 4 ++-- src/modules/SX126x/SX126x.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index aca4f15b61..46a0008fc5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -581,7 +581,7 @@ int16_t SX126x::startReceive() { return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_SX126X_IRQ_RX_DEFAULT, RADIOLIB_SX126X_IRQ_RX_DONE, 0)); } -int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t SX126x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)len; int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); RADIOLIB_ASSERT(state); @@ -1456,7 +1456,7 @@ RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(timeout); } -int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) { +int16_t SX126x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0 return(RADIOLIB_ERR_NONE); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2bd3a042fa..2adcd19234 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -654,7 +654,7 @@ class SX126x: public PhysicalLayer { \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint32_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. @@ -972,7 +972,7 @@ class SX126x: public PhysicalLayer { \param irqMask Mask indicating which IRQ triggers a DIO \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) override; + int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); /*! \brief Check whether the IRQ bit for RxTimeout is set From 8a4514703bbebc06dc2eeb61e7e2487ae5561176 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:54:33 +0200 Subject: [PATCH 1043/1848] [SX128x] Use 32-bit IRQ flags --- src/modules/SX128x/SX128x.cpp | 2 +- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 0a5333f244..098d2f214e 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -557,7 +557,7 @@ int16_t SX128x::startReceive() { return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT, RADIOLIB_SX128X_IRQ_RX_DONE, 0)); } -int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) { +int16_t SX128x::startReceive(uint16_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { (void)len; // check active modem diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index a68f6c5b66..8bc0034665 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -551,7 +551,7 @@ class SX128x: public PhysicalLayer { \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint16_t timeout, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint16_t timeout, uint32_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint32_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); /*! \brief Reads the current IRQ status. From 2f06885f9f219e8f6c90c393a9a84269532bdf5d Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:55:19 +0200 Subject: [PATCH 1044/1848] [SX126x] Remove copypate from setSyncBits --- src/modules/SX126x/SX126x.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 46a0008fc5..17393a1f02 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1174,15 +1174,7 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { bytesLen++; } - // write sync word - int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, bytesLen); - RADIOLIB_ASSERT(state); - - // update packet parameters - this->syncWordLength = bitsLen; - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); - - return(state); + return(setSyncWord(syncWord, bytesLen)); } int16_t SX126x::setNodeAddress(uint8_t nodeAddr) { From c494b983f5f4f38b664ab056b7a2390b4083add0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 14:55:48 +0200 Subject: [PATCH 1045/1848] [LR11x0] Added methods for LoRaWAN compatibility --- src/modules/LR11x0/LR11x0.cpp | 40 ++++++++++++++++++++++++++++++++--- src/modules/LR11x0/LR11x0.h | 30 +++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index fa68071b24..f0db33e211 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -432,10 +432,11 @@ int16_t LR11x0::finishTransmit() { } int16_t LR11x0::startReceive() { - return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE, 0)); + return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE, 0, 0)); } -int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, size_t len) { +int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { + (void)irqMask; (void)len; // check active modem @@ -849,8 +850,16 @@ int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) { uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + return(setSyncWord(syncWord[0])); + + } else if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { return(RADIOLIB_ERR_WRONG_MODEM); + } // update sync word length @@ -1310,6 +1319,31 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { return(0); } +RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) { + // the timeout value is given in units of 30.52 microseconds + // the calling function should provide some extra width, as this number of units is truncated to integer + RadioLibTime_t timeout = timeoutUs / 30.52; + return(timeout); +} + +int16_t LR11x0::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { + irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT; // flags that can appear in the IRQ register + irqMask = irqFlags; // on LR11x0, these are the same + return(RADIOLIB_ERR_NONE); +} + +bool LR11x0::isRxTimeout() { + uint32_t irq = getIrqStatus(); + bool rxTimedOut = irq & RADIOLIB_LR11X0_IRQ_TIMEOUT; + return(rxTimedOut); +} + +uint8_t LR11x0::randomByte() { + uint32_t num = 0; + (void)getRandomNumber(&num); + return((uint8_t)num); +} + int16_t LR11x0::implicitHeader(size_t len) { return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT, len)); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 42ed4e564e..216aa68ed6 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -843,10 +843,11 @@ class LR11x0: public PhysicalLayer { If timeout other than infinite is set, signal will be generated on IRQ1. \param irqFlags Sets the IRQ flags that will trigger IRQ1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE. + \param irqMask Only for PhysicalLayer compatibility, not used. \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, uint32_t irqMask = 0, size_t len = 0); /*! \brief Reads the current IRQ status. @@ -1141,6 +1142,33 @@ class LR11x0: public PhysicalLayer { */ RadioLibTime_t getTimeOnAir(size_t len) override; + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; + + /*! + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks + \param irqFlags The flags for which IRQs must be triggered + \param irqMask Mask indicating which IRQ triggers a DIO + \returns \ref status_codes + */ + int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; + + /*! + \brief Check whether the IRQ bit for RxTimeout is set + \returns Whether RxTimeout IRQ is set + */ + bool isRxTimeout() override; + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte(); + /*! \brief Set implicit header mode for future reception/transmission. \param len Payload length in bytes. From d12e9f11f570b173589df344245c92e8cf370d5e Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 15:29:39 +0200 Subject: [PATCH 1046/1848] [LoRaWAN] Added timeout to downlink wait loop --- src/protocols/LoRaWAN/LoRaWAN.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index d1fdd42741..0636ddd0cd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1214,8 +1214,16 @@ int16_t LoRaWANNode::downlinkCommon() { } // wait for the DIO to fire indicating a downlink is received + now = mod->hal->millis(); + bool downlinkComplete = true; while(!downlinkAction) { mod->hal->yield(); + // this should never happen, but if it does this would be an infinite loop + if(mod->hal->millis() - now > 3000UL) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink missing!"); + downlinkComplete = false; + break; + } } // we have a message, clear actions, go to standby and reset the IQ inversion @@ -1226,7 +1234,11 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_ASSERT(state); } - return(RADIOLIB_ERR_NONE); + if(!downlinkComplete) { + state = RADIOLIB_LORAWAN_NO_DOWNLINK; + } + + return(state); } #if defined(RADIOLIB_BUILD_ARDUINO) From 46e6f7873165a1f9451887e854a645f290f0f164 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 8 May 2024 20:13:57 +0100 Subject: [PATCH 1047/1848] [LR11x0] Fixed inverted deallocation logic --- src/modules/LR11x0/LR11x0.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index f0db33e211..8ad2ccd564 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2019,7 +2019,7 @@ int16_t LR11x0::writeInfoPage(uint16_t addr, uint32_t* data, size_t len) { } int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen); - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif return(state); @@ -2442,7 +2442,7 @@ int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, boo memcpy(&dataBuff[9], payload, len); int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen); - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif return(state); @@ -2493,7 +2493,7 @@ int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, si memcpy(&dataBuff[1], payload, len); int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len); - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif return(state); @@ -2758,7 +2758,7 @@ int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, uint16_t* doppler } } - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif return(state); @@ -2902,7 +2902,7 @@ int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, u memcpy(&reqBuff[1], data, len); int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] reqBuff; #endif @@ -2933,7 +2933,7 @@ int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* dat memcpy(&reqBuff[5], data, len); int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] reqBuff; #endif @@ -3064,7 +3064,7 @@ int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, s } int16_t state = this->SPIcommand(cmd, true, dataBuff, buffLen); - #if RADIOLIB_STATIC_ONLY + #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif return(state); From 4d7c16bd44f791d17e7cc1fbf284ccfeada6d63e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 10 May 2024 20:45:36 +0100 Subject: [PATCH 1048/1848] [RF69] Fixed issues found by cppcheck --- src/modules/RF69/RF69.cpp | 6 +++--- src/modules/RF69/RF69.h | 32 ++++++++++++++++---------------- src/modules/SX123x/SX1231.h | 4 ++-- src/modules/SX123x/SX1233.h | 6 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 5544ad5d30..260962a5eb 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -566,9 +566,9 @@ int16_t RF69::setBitRate(float br) { setMode(RADIOLIB_RF69_STANDBY); // set bit rate - uint16_t bitRate = 32000 / br; - int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + uint16_t bitRateRaw = 32000 / br; + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0); if(state == RADIOLIB_ERR_NONE) { this->bitRate = br; } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 40b780766d..7d77ef66b3 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -488,7 +488,7 @@ class RF69: public PhysicalLayer { \brief Default constructor. \param module Instance of Module that will be used to communicate with the radio. */ - RF69(Module* module); + RF69(Module* module); // cppcheck-suppress noExplicitConstructor // basic methods @@ -538,7 +538,7 @@ class RF69: public PhysicalLayer { \brief Sets the module to sleep mode. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the module to standby mode. @@ -619,23 +619,23 @@ class RF69: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Set interrupt service routine function to call when FIFO is empty. @@ -697,7 +697,7 @@ class RF69: public PhysicalLayer { \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. @@ -707,7 +707,7 @@ class RF69: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override; /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, @@ -727,7 +727,7 @@ class RF69: public PhysicalLayer { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Gets carrier frequency. @@ -741,7 +741,7 @@ class RF69: public PhysicalLayer { \param br Bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Sets receiver bandwidth. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, @@ -944,7 +944,7 @@ class RF69: public PhysicalLayer { \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. \returns Last packet RSSI in dBm. */ - float getRSSI(); + float getRSSI() override; /*! \brief Sets the RSSI value above which the RSSI interrupt is signaled @@ -963,7 +963,7 @@ class RF69: public PhysicalLayer { \brief Get one truly random byte from RSSI noise. \returns TRNG byte. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Read version SPI register. Should return RF69_CHIP_VERSION (0x24) if SX127x is connected and working. @@ -976,13 +976,13 @@ class RF69: public PhysicalLayer { \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ - void setDirectAction(void (*func)(void)); + void setDirectAction(void (*func)(void)) override; /*! \brief Function to read and process data bit in direct reception mode. \param pin Pin on which to read. */ - void readBit(uint32_t pin); + void readBit(uint32_t pin) override; #endif /*! @@ -991,12 +991,12 @@ class RF69: public PhysicalLayer { \param value The value that indicates which function to place on that pin. See chip datasheet for details. \returns \ref status_codes */ - int16_t setDIOMapping(uint32_t pin, uint32_t value); + int16_t setDIOMapping(uint32_t pin, uint32_t value) override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/SX123x/SX1231.h b/src/modules/SX123x/SX1231.h index 569a8403af..6dc3735764 100644 --- a/src/modules/SX123x/SX1231.h +++ b/src/modules/SX123x/SX1231.h @@ -96,7 +96,7 @@ class SX1231: public RF69 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1231(Module* mod); + SX1231(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Initialization method. @@ -111,7 +111,7 @@ class SX1231: public RF69 { int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); #if !RADIOLIB_GODMODE - private: + protected: #endif uint8_t chipRevision = 0; }; diff --git a/src/modules/SX123x/SX1233.h b/src/modules/SX123x/SX1233.h index 029b0cc217..bf9bb1481a 100644 --- a/src/modules/SX123x/SX1233.h +++ b/src/modules/SX123x/SX1233.h @@ -26,7 +26,7 @@ class SX1233: public SX1231 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1233(Module* mod); + SX1233(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Initialization method. @@ -48,12 +48,12 @@ class SX1233: public SX1231 { \param br Bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; #if !RADIOLIB_GODMODE private: #endif - uint8_t chipRevision = 0; + }; #endif From a643d0db7a14ec3c8f69186851521d6674e7d22d Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 10 May 2024 20:45:54 +0100 Subject: [PATCH 1049/1848] [LR11x0] Fixed issues found by cppcheck --- src/modules/LR11x0/LR1110.h | 4 ++-- src/modules/LR11x0/LR1120.h | 4 ++-- src/modules/LR11x0/LR1121.h | 2 +- src/modules/LR11x0/LR11x0.cpp | 25 ++++++++++++++----------- src/modules/LR11x0/LR11x0.h | 26 +++++++++++++------------- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index daf54b6f7d..60040ed0cb 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -18,7 +18,7 @@ class LR1110: public LR11x0 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - LR1110(Module* mod); + LR1110(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -74,7 +74,7 @@ class LR1110: public LR11x0 { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index c7360c7a2f..62045b028d 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -18,7 +18,7 @@ class LR1120: public LR11x0 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - LR1120(Module* mod); + LR1120(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -74,7 +74,7 @@ class LR1120: public LR11x0 { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, diff --git a/src/modules/LR11x0/LR1121.h b/src/modules/LR11x0/LR1121.h index 183e023a9d..2dc0242bda 100644 --- a/src/modules/LR11x0/LR1121.h +++ b/src/modules/LR11x0/LR1121.h @@ -19,7 +19,7 @@ class LR1121: public LR1120 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - LR1121(Module* mod); + LR1121(Module* mod); // cppcheck-suppress noExplicitConstructor // TODO this is where overrides to disable GNSS+WiFi scanning methods on LR1121 // will be put once those are implemented diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 8ad2ccd564..16f0726a6a 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -143,6 +143,7 @@ int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { // get currently active modem uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); + RADIOLIB_ASSERT(state); RadioLibTime_t timeout = getTimeOnAir(len); if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate timeout (150% of expected time-on-air) @@ -189,6 +190,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { // get currently active modem uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); + RADIOLIB_ASSERT(state); if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; @@ -396,6 +398,7 @@ int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // in LR-FHSS mode, the packet is built by the device // TODO add configurable grid step and device offset state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC, true, this->lrFhssBw, this->lrFhssHopSeq, 0, data, len); + RADIOLIB_ASSERT(state); } else { // write packet to buffer @@ -1202,12 +1205,12 @@ float LR11x0::getRSSI() { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - getPacketType(&type); + (void)getPacketType(&type); if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { - getPacketStatusLoRa(&val, NULL, NULL); + (void)getPacketStatusLoRa(&val, NULL, NULL); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - getPacketStatusGFSK(NULL, &val, NULL, NULL); + (void)getPacketStatusGFSK(NULL, &val, NULL, NULL); } @@ -1219,9 +1222,9 @@ float LR11x0::getSNR() { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - getPacketType(&type); + (void)getPacketType(&type); if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { - getPacketStatusLoRa(NULL, &val, NULL); + (void)getPacketStatusLoRa(NULL, &val, NULL); } return(val); @@ -1254,7 +1257,7 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - getPacketType(&type); + (void)getPacketType(&type); if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate number of symbols float N_symbol = 0; @@ -1468,7 +1471,7 @@ int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, boo if(!brief) { if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) { - LR11x0WifiResultExtended_t* resultExtended = (LR11x0WifiResultExtended_t*)result; + LR11x0WifiResultExtended_t* resultExtended = reinterpret_cast(result); resultExtended->rate = raw[3]; resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5])); resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7])); @@ -1495,7 +1498,7 @@ int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, boo return(RADIOLIB_ERR_NONE); } - LR11x0WifiResultFull_t* resultFull = (LR11x0WifiResultFull_t*)result; + LR11x0WifiResultFull_t* resultFull = reinterpret_cast(result); resultFull->frameType = raw[3] & 0x03; resultFull->frameSubType = (raw[3] & 0x3C) >> 2; resultFull->toDistributionSystem = (raw[3] & 0x40) != 0; @@ -1533,7 +1536,7 @@ int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_ return(RADIOLIB_ERR_RX_TIMEOUT); } } - RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %d ms", this->mod->hal->millis() - start); + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); // read number of results return(getWifiScanResultsCount(count)); @@ -1658,7 +1661,7 @@ int16_t LR11x0::config(uint8_t modem) { RADIOLIB_ASSERT(state); // calibrate all blocks - state = this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL); + (void)this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL); // wait for calibration completion this->mod->hal->delay(5); @@ -1716,7 +1719,7 @@ int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { num = 2; } - uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 }; + const uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 }; uint8_t peak = detPeak; if(peak == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) { peak = detPeakValues[this->spreadingFactor - 5]; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 216aa68ed6..0fdabec04c 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -656,7 +656,7 @@ class LR11x0: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - LR11x0(Module* mod); + LR11x0(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. @@ -793,23 +793,23 @@ class LR11x0: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Interrupt-driven binary transmit method. @@ -833,7 +833,7 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method. IRQ1 will be activated when full packet is received. @@ -895,7 +895,7 @@ class LR11x0: public PhysicalLayer { \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power) override; /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). @@ -961,7 +961,7 @@ class LR11x0: public PhysicalLayer { \param br FSK bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Sets GFSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. @@ -1107,13 +1107,13 @@ class LR11x0: public PhysicalLayer { \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem. \returns RSSI of the last received packet in dBm. */ - float getRSSI(); + float getRSSI() override; /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. \returns SNR of the last received packet in dB. */ - float getSNR(); + float getSNR() override; /*! \brief Gets frequency error of the latest received packet. @@ -1167,7 +1167,7 @@ class LR11x0: public PhysicalLayer { \brief Get one truly random byte from RSSI noise. \returns TRNG byte. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Set implicit header mode for future reception/transmission. @@ -1264,7 +1264,7 @@ class LR11x0: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; // LR11x0 SPI command implementations int16_t writeRegMem32(uint32_t addr, uint32_t* data, size_t len); @@ -1410,7 +1410,7 @@ class LR11x0: public PhysicalLayer { #if !RADIOLIB_GODMODE protected: #endif - uint8_t chipType; + uint8_t chipType = 0; #if !RADIOLIB_GODMODE private: From dec7265f7200962eb10589eeebfbed66579481b5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 16:49:29 +0100 Subject: [PATCH 1050/1848] [SX128x] Fixed issues found by cppcheck --- src/modules/SX128x/SX1280.h | 2 +- src/modules/SX128x/SX1281.h | 2 +- src/modules/SX128x/SX1282.h | 2 +- src/modules/SX128x/SX128x.cpp | 6 +++--- src/modules/SX128x/SX128x.h | 38 +++++++++++++++++------------------ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index c798f044a0..e06faec5eb 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -19,7 +19,7 @@ class SX1280: public SX1281 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1280(Module* mod); + SX1280(Module* mod); // cppcheck-suppress noExplicitConstructor /*! \brief Blocking ranging method. diff --git a/src/modules/SX128x/SX1281.h b/src/modules/SX128x/SX1281.h index 3a41b60a61..3d697dad46 100644 --- a/src/modules/SX128x/SX1281.h +++ b/src/modules/SX128x/SX1281.h @@ -18,7 +18,7 @@ class SX1281: public SX128x { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1281(Module* mod); + SX1281(Module* mod); // cppcheck-suppress noExplicitConstructor #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX128x/SX1282.h b/src/modules/SX128x/SX1282.h index 091bf133b5..dc51ba9d86 100644 --- a/src/modules/SX128x/SX1282.h +++ b/src/modules/SX128x/SX1282.h @@ -19,7 +19,7 @@ class SX1282: public SX1280 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX1282(Module* mod); + SX1282(Module* mod); // cppcheck-suppress noExplicitConstructor #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 098d2f214e..25ac0a4351 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -924,13 +924,13 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { } // update modulation parameters - uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0); - if(modIndex > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) { + uint8_t modInd = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0); + if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) { return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); } // update modulation parameters - this->modIndex = modIndex; + this->modIndex = modInd; return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 8bc0034665..32044a6823 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -359,7 +359,7 @@ class SX128x: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX128x(Module* mod); + SX128x(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -455,7 +455,7 @@ class SX128x: public PhysicalLayer { \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. \returns \ref status_codes */ - int16_t scanChannel(); + int16_t scanChannel() override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). @@ -497,23 +497,23 @@ class SX128x: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Interrupt-driven binary transmit method. @@ -537,7 +537,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. @@ -589,7 +589,7 @@ class SX128x: public PhysicalLayer { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets LoRa bandwidth. Allowed values are 203.125, 406.25, 812.5 and 1625.0 kHz. @@ -619,7 +619,7 @@ class SX128x: public PhysicalLayer { \param pwr Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t pwr); + int16_t setOutputPower(int8_t pwr) override; /*! \brief Check if output power is configurable. @@ -627,7 +627,7 @@ class SX128x: public PhysicalLayer { \param clipped Clipped output power value to what is possible within the module's range. \returns \ref status_codes */ - int16_t checkOutputPower(int8_t power, int8_t* clipped); + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; /*! \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. @@ -642,7 +642,7 @@ class SX128x: public PhysicalLayer { \param br FSK/FLRC bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 3200.0 kHz. @@ -717,13 +717,13 @@ class SX128x: public PhysicalLayer { \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. \returns RSSI of the last received packet in dBm. */ - float getRSSI(); + float getRSSI() override; /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa or ranging modem. \returns SNR of the last received packet in dB. */ - float getSNR(); + float getSNR() override; /*! \brief Gets frequency error of the latest received packet. @@ -743,7 +743,7 @@ class SX128x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - RadioLibTime_t getTimeOnAir(size_t len); + RadioLibTime_t getTimeOnAir(size_t len) override; /*! \brief Set implicit header mode for future reception/transmission. @@ -775,33 +775,33 @@ class SX128x: public PhysicalLayer { \brief Dummy random method, to ensure PhysicalLayer compatibility. \returns Always returns 0. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Enable/disable inversion of the I and Q signals \param enable QI inversion enabled (true) or disabled (false); \returns \ref status_codes */ - int16_t invertIQ(bool enable); + int16_t invertIQ(bool enable) override; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Dummy method, to ensure PhysicalLayer compatibility. \param func Ignored. */ - void setDirectAction(void (*func)(void)); + void setDirectAction(void (*func)(void)) override; /*! \brief Dummy method, to ensure PhysicalLayer compatibility. \param pin Ignored. */ - void readBit(uint32_t pin); + void readBit(uint32_t pin) override; #endif #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; // cached LoRa parameters float bandwidthKhz = 0; From c641099e9f1d39b41479492c804890420c589487 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 16:49:51 +0100 Subject: [PATCH 1051/1848] [SX127x] Fixed issues found by cppcheck --- src/modules/SX127x/SX1272.h | 8 +++---- src/modules/SX127x/SX1273.h | 2 +- src/modules/SX127x/SX1276.h | 4 ++-- src/modules/SX127x/SX1277.h | 4 ++-- src/modules/SX127x/SX1278.h | 8 +++---- src/modules/SX127x/SX1279.h | 4 ++-- src/modules/SX127x/SX127x.cpp | 22 ++++++++++++------- src/modules/SX127x/SX127x.h | 40 +++++++++++++++++------------------ 8 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 0f9a171713..292bfd790c 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -100,7 +100,7 @@ class SX1272: public SX127x { \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX1272(Module* mod); + SX1272(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -146,7 +146,7 @@ class SX1272: public SX127x { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets %LoRa link bandwidth. Allowed values are 125, 250 and 500 kHz. Only available in %LoRa mode. @@ -254,7 +254,7 @@ class SX1272: public SX127x { Overload with packet mode enabled for PhysicalLayer compatibility. \returns RSSI value in dBm. */ - float getRSSI(); + float getRSSI() override; /*! \brief Gets recorded signal strength indicator. @@ -311,7 +311,7 @@ class SX1272: public SX127x { int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); int16_t configFSK(); - void errataFix(bool rx); + void errataFix(bool rx) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 610bbccf7e..8e7ab1ca17 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -20,7 +20,7 @@ class SX1273: public SX1272 { \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX1273(Module* mod); + SX1273(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index c15f98128d..89ab9f9ffb 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -20,7 +20,7 @@ class SX1276: public SX1278 { \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX1276(Module* mod); + SX1276(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -61,7 +61,7 @@ class SX1276: public SX1278 { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 1d334cdca1..c7efd95ba9 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -20,7 +20,7 @@ class SX1277: public SX1278 { \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX1277(Module* mod); + SX1277(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -61,7 +61,7 @@ class SX1277: public SX1278 { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode. diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index a54623a9ac..3c2b0088a3 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -111,7 +111,7 @@ class SX1278: public SX127x { \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX1278(Module* mod); + SX1278(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -157,7 +157,7 @@ class SX1278: public SX127x { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode. @@ -266,7 +266,7 @@ class SX1278: public SX127x { Overload with packet mode enabled for PhysicalLayer compatibility. \returns RSSI value in dBm. */ - float getRSSI(); + float getRSSI() override; /*! \brief Gets recorded signal strength indicator. @@ -323,7 +323,7 @@ class SX1278: public SX127x { int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); int16_t configFSK(); - void errataFix(bool rx); + void errataFix(bool rx) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index e802e9c43c..1dceb42309 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -20,7 +20,7 @@ class SX1279: public SX1278 { \brief Default constructor. Called from Arduino sketch when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX1279(Module* mod); + SX1279(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -61,7 +61,7 @@ class SX1279: public SX1278 { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6c9c659896..13096257d2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -905,13 +905,13 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { RADIOLIB_ASSERT(state); // set bit rate - uint16_t bitRate = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br; - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); + uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br; + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0); // set fractional part of bit rate if(!ookEnabled) { - float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRate; + float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRateRaw; uint8_t bitRateFrac = bitRateRem * 16; state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0); } @@ -1335,8 +1335,14 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET); + // calculate the two's complement + uint8_t offsetRaw = RADIOLIB_ABS(offset); + offsetRaw ^= 0x1F; + offsetRaw += 1; + offsetRaw &= 0x1F; + // set new register values - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset << 3, 7, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offsetRaw << 3, 7, 3); state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0); return(state); } @@ -1538,7 +1544,7 @@ int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) { return(state); } -bool SX127x::findChip(uint8_t* vers, uint8_t num) { +bool SX127x::findChip(const uint8_t* vers, uint8_t num) { uint8_t i = 0; bool flagFound = false; while((i < 10) && !flagFound) { @@ -1547,8 +1553,8 @@ bool SX127x::findChip(uint8_t* vers, uint8_t num) { // check version register int16_t version = getChipVersion(); - for(uint8_t i = 0; i < num; i++) { - if(version == vers[i]) { + for(uint8_t j = 0; j < num; j++) { + if(version == vers[j]) { flagFound = true; break; } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index d9f3f87036..4b692667dd 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -594,7 +594,7 @@ class SX127x: public PhysicalLayer { \brief Default constructor. Called internally when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX127x(Module* mod); + SX127x(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -655,7 +655,7 @@ class SX127x: public PhysicalLayer { %Module will wake up automatically when methods like transmit or receive are called. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the %LoRa module to standby. @@ -721,34 +721,34 @@ class SX127x: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Sets interrupt service routine to call when a channel scan is finished. \param func ISR to call. */ - void setChannelScanAction(void (*func)(void)); + void setChannelScanAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a channel scan is finished. */ - void clearChannelScanAction(); + void clearChannelScanAction() override; /*! \brief Set interrupt service routine function to call when FIFO is empty. @@ -810,7 +810,7 @@ class SX127x: public PhysicalLayer { Implemented for compatibility with PhysicalLayer. \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. @@ -832,7 +832,7 @@ class SX127x: public PhysicalLayer { \param len Expected length of packet to be received. Required for LoRa spreading factor 6. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override; /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, @@ -904,7 +904,7 @@ class SX127x: public PhysicalLayer { \brief Gets signal-to-noise ratio of the latest received packet. Only available in LoRa mode. \returns Last packet signal-to-noise ratio (SNR). */ - float getSNR(); + float getSNR() override; /*! \brief Get data rate of the latest transmitted packet. @@ -1062,7 +1062,7 @@ class SX127x: public PhysicalLayer { \param timeoutUs Timeout in microseconds to listen for \returns Timeout value in a unit that is specific for the used module */ - RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; /*! \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks @@ -1070,13 +1070,13 @@ class SX127x: public PhysicalLayer { \param irqMask Mask indicating which IRQ triggers a DIO \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); + int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; /*! \brief Check whether the IRQ bit for RxTimeout is set \returns Whether RxTimeout IRQ is set */ - bool isRxTimeout(); + bool isRxTimeout() override; /*! \brief Enable CRC filtering and generation. @@ -1133,7 +1133,7 @@ class SX127x: public PhysicalLayer { \brief Get one truly random byte from RSSI noise. \returns TRNG byte. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Read version SPI register. Should return SX1278_CHIP_VERSION (0x12) or SX1272_CHIP_VERSION (0x22) if SX127x is connected and working. @@ -1153,13 +1153,13 @@ class SX127x: public PhysicalLayer { \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ - void setDirectAction(void (*func)(void)); + void setDirectAction(void (*func)(void)) override; /*! \brief Function to read and process data bit in direct reception mode. \param pin Pin on which to read. */ - void readBit(uint32_t pin); + void readBit(uint32_t pin) override; #endif /*! @@ -1192,7 +1192,7 @@ class SX127x: public PhysicalLayer { \param value The value that indicates which function to place on that pin. See chip datasheet for details. \returns \ref status_codes */ - int16_t setDIOMapping(uint32_t pin, uint32_t value); + int16_t setDIOMapping(uint32_t pin, uint32_t value) override; /*! \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. @@ -1221,7 +1221,7 @@ class SX127x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; #if !RADIOLIB_GODMODE protected: @@ -1254,7 +1254,7 @@ class SX127x: public PhysicalLayer { int16_t config(); int16_t directMode(); int16_t setPacketMode(uint8_t mode, uint8_t len); - bool findChip(uint8_t* vers, uint8_t num); + bool findChip(const uint8_t* vers, uint8_t num); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); void clearIRQFlags(); From 2f867153f9754ef9eada65bc8862343ab4774a5d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 17:15:25 +0100 Subject: [PATCH 1052/1848] [Si443x] Fixed issues found by cppcheck --- src/modules/Si443x/Si4430.h | 6 +++--- src/modules/Si443x/Si4431.h | 4 ++-- src/modules/Si443x/Si4432.h | 6 +++--- src/modules/Si443x/Si443x.cpp | 10 +++------- src/modules/Si443x/Si443x.h | 28 ++++++++++++++-------------- 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h index 6acac97d18..2d212e058f 100644 --- a/src/modules/Si443x/Si4430.h +++ b/src/modules/Si443x/Si4430.h @@ -21,7 +21,7 @@ class Si4430: public Si4432 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio chip. */ - Si4430(Module* mod); + Si4430(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -44,14 +44,14 @@ class Si4430: public Si4432 { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. \param power Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power) override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h index 8d3d9dd928..a8939ea16a 100644 --- a/src/modules/Si443x/Si4431.h +++ b/src/modules/Si443x/Si4431.h @@ -21,7 +21,7 @@ class Si4431: public Si4432 { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio chip. */ - Si4431(Module* mod); + Si4431(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -44,7 +44,7 @@ class Si4431: public Si4432 { \param power Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power) override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h index b0a8cb877a..f3ac066136 100644 --- a/src/modules/Si443x/Si4432.h +++ b/src/modules/Si443x/Si4432.h @@ -21,7 +21,7 @@ class Si4432: public Si443x { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio chip. */ - Si4432(Module* mod); + Si4432(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -44,14 +44,14 @@ class Si4432: public Si443x { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets output power. Allowed values range from -1 to 20 dBm in 3 dBm steps. \param power Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power) override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 7812099214..7dfd8eb821 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -558,11 +558,11 @@ int16_t Si443x::setEncoding(uint8_t encoding) { /// \todo - add inverted Manchester? switch(encoding) { case RADIOLIB_ENCODING_NRZ: - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_ENCODING_MANCHESTER: - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); case RADIOLIB_ENCODING_WHITENING: - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: return(RADIOLIB_ERR_INVALID_ENCODING); } @@ -577,12 +577,8 @@ int16_t Si443x::setDataShaping(uint8_t sh) { switch(sh) { case RADIOLIB_SHAPING_NONE: return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0)); - case RADIOLIB_SHAPING_0_3: - return(RADIOLIB_ERR_INVALID_ENCODING); case RADIOLIB_SHAPING_0_5: return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_GFSK, 1, 0)); - case RADIOLIB_SHAPING_1_0: - return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0)); default: return(RADIOLIB_ERR_INVALID_ENCODING); } diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index b8986b652b..24f8bb0673 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -564,7 +564,7 @@ class Si443x: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - Si443x(Module* mod); + explicit Si443x(Module* mod); // basic methods @@ -607,7 +607,7 @@ class Si443x: public PhysicalLayer { %Module will wake up automatically when methods like transmit or receive are called. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the module to standby (with XTAL on). @@ -658,23 +658,23 @@ class Si443x: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 64 bytes long. @@ -695,7 +695,7 @@ class Si443x: public PhysicalLayer { \brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received. \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. @@ -705,7 +705,7 @@ class Si443x: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override; /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, @@ -724,7 +724,7 @@ class Si443x: public PhysicalLayer { \param br Bit rate to be set (in kbps). \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Sets FSK frequency deviation from carrier frequency. Allowed values range from 0.625 to 320.0 kHz. @@ -745,7 +745,7 @@ class Si443x: public PhysicalLayer { \param syncWord Pointer to the array of sync word bytes. \param len Sync word length in bytes. */ - int16_t setSyncWord(uint8_t* syncWord, size_t len); + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; /*! \brief Sets preamble length. @@ -787,7 +787,7 @@ class Si443x: public PhysicalLayer { \brief Get one truly random byte from RSSI noise. \returns TRNG byte. */ - uint8_t randomByte(); + uint8_t randomByte() override; /*! \brief Read version SPI register. Should return RADIOLIB_SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working. @@ -800,13 +800,13 @@ class Si443x: public PhysicalLayer { \brief Set interrupt service routine function to call when data bit is received in direct mode. \param func Pointer to interrupt service routine. */ - void setDirectAction(void (*func)(void)); + void setDirectAction(void (*func)(void)) override; /*! \brief Function to read and process data bit in direct reception mode. \param pin Pin on which to read. */ - void readBit(uint32_t pin); + void readBit(uint32_t pin) override; #endif /*! @@ -826,7 +826,7 @@ class Si443x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; #if !RADIOLIB_GODMODE protected: From e35689cbaa41de3ad9355774f1f0a02b2835bfac Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 17:20:19 +0100 Subject: [PATCH 1053/1848] [nRF24] Fixed issues found by cppcheck --- src/modules/nRF24/nRF24.cpp | 10 +++++----- src/modules/nRF24/nRF24.h | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index f28f757e7c..09d8bf0914 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -298,14 +298,14 @@ int16_t nRF24::setBitRate(float br) { RADIOLIB_ASSERT(state); // set data rate - uint16_t dataRate = (uint16_t)br; - if(dataRate == 250) { + uint16_t bitRate = (uint16_t)br; + if(bitRate == 250) { state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5); state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3); - } else if(dataRate == 1000) { + } else if(bitRate == 1000) { state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 5, 5); state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 3, 3); - } else if(dataRate == 2000) { + } else if(bitRate == 2000) { state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 5, 5); state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 3, 3); } else { @@ -313,7 +313,7 @@ int16_t nRF24::setBitRate(float br) { } if(state == RADIOLIB_ERR_NONE) { - this->dataRate = dataRate; + this->dataRate = bitRate; } diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 0a0dc1e317..14d2620973 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -193,7 +193,7 @@ class nRF24: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - nRF24(Module* mod); + nRF24(Module* mod); // cppcheck-suppress noExplicitConstructor // basic methods @@ -215,7 +215,7 @@ class nRF24: public PhysicalLayer { \brief Sets the module to sleep mode. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the module to standby mode. @@ -279,23 +279,23 @@ class nRF24: public PhysicalLayer { \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. */ - void setPacketReceivedAction(void (*func)(void)); + void setPacketReceivedAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is received. */ - void clearPacketReceivedAction(); + void clearPacketReceivedAction() override; /*! \brief Sets interrupt service routine to call when a packet is sent. \param func ISR to call. */ - void setPacketSentAction(void (*func)(void)); + void setPacketSentAction(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when a packet is sent. */ - void clearPacketSentAction(); + void clearPacketSentAction() override; /*! \brief Interrupt-driven binary transmit method. IRQ will be activated when full packet is transmitted. @@ -317,7 +317,7 @@ class nRF24: public PhysicalLayer { \brief Interrupt-driven receive method. IRQ will be activated when full packet is received. \returns \ref status_codes */ - int16_t startReceive(); + int16_t startReceive() override; /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. @@ -327,7 +327,7 @@ class nRF24: public PhysicalLayer { \param len Ignored. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); + int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override; /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, @@ -345,21 +345,21 @@ class nRF24: public PhysicalLayer { \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq) override; /*! \brief Sets bit rate. Allowed values are 2000, 1000 or 250 kbps. \param br Bit rate to be set in kbps. \returns \ref status_codes */ - int16_t setBitRate(float br); + int16_t setBitRate(float br) override; /*! \brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm. \param pwr Output power to be set in dBm. \returns \ref status_codes */ - int16_t setOutputPower(int8_t pwr); + int16_t setOutputPower(int8_t pwr) override; /*! \brief Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes. @@ -468,7 +468,7 @@ class nRF24: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif - Module* getMod(); + Module* getMod() override; void SPIreadRxPayload(uint8_t* data, uint8_t numBytes); void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes); From 3d9815f93d7b36c23fa3c822ed5af8b161b216fb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 17:22:57 +0100 Subject: [PATCH 1054/1848] Use explicit constructors for base classes --- src/modules/LR11x0/LR11x0.h | 2 +- src/modules/SX126x/SX126x.h | 4 ++-- src/modules/SX127x/SX127x.h | 2 +- src/modules/SX128x/SX128x.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 0fdabec04c..e7affc82a4 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -656,7 +656,7 @@ class LR11x0: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - LR11x0(Module* mod); // cppcheck-suppress noExplicitConstructor + explicit LR11x0(Module* mod); /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2adcd19234..8cc3540b82 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -452,7 +452,7 @@ class SX126x: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX126x(Module* mod); // cppcheck-suppress noExplicitConstructor + explicit SX126x(Module* mod); /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. @@ -972,7 +972,7 @@ class SX126x: public PhysicalLayer { \param irqMask Mask indicating which IRQ triggers a DIO \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); + int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; /*! \brief Check whether the IRQ bit for RxTimeout is set diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 4b692667dd..a9711d8194 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -594,7 +594,7 @@ class SX127x: public PhysicalLayer { \brief Default constructor. Called internally when creating new LoRa instance. \param mod Instance of Module that will be used to communicate with the %LoRa chip. */ - SX127x(Module* mod); // cppcheck-suppress noExplicitConstructor + explicit SX127x(Module* mod); // basic methods diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 32044a6823..fd8e2e038c 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -359,7 +359,7 @@ class SX128x: public PhysicalLayer { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - SX128x(Module* mod); // cppcheck-suppress noExplicitConstructor + explicit SX128x(Module* mod); // basic methods From 44b2dcaa15d5c55cf392c7f7d39acbce3a54897b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 17:23:23 +0100 Subject: [PATCH 1055/1848] [CI] Update cppcheck config to unclutter output --- .github/workflows/cppcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 25599005b4..6016de17ea 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -24,4 +24,4 @@ jobs: - name: Run cppcheck run: - cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked + cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked --suppress=unusedFunction From d61589a2c5003941bd48655dceb58d8bc00d916d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:31:01 +0100 Subject: [PATCH 1056/1848] [AFSK] Fixed issues found by cppcheck --- src/protocols/AFSK/AFSK.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index d4ca58d64c..e38b5b769a 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -26,7 +26,7 @@ class AFSKClient { \brief Copy contructor. \param aud Pointer to the AFSKClient instance to copy. */ - AFSKClient(AFSKClient* aud); + explicit AFSKClient(AFSKClient* aud); /*! \brief Initialization method. From ac07269f9749deec550272327dbe6dbfc59672ff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:31:57 +0100 Subject: [PATCH 1057/1848] [APRS] Fixed issues found by cppcheck --- src/protocols/APRS/APRS.cpp | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 55b034d170..5c54b217aa 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -49,22 +49,28 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat #endif // build the info field - if((msg == NULL) && (time == NULL)) { - // no message, no timestamp - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, table, lon, symbol); - } else if((msg != NULL) && (time == NULL)) { - // message, no timestamp - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, table, lon, symbol, msg); - } else if((msg == NULL) && (time != NULL)) { - // timestamp, no message - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, table, lon, symbol); + if(msg != NULL) { + if(time != NULL) { + // timestamp and message + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg); + } else { + // message, no timestamp + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, table, lon, symbol, msg); + } + } else { - // timestamp and message - sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg); + if(time != NULL) { + // timestamp, no message + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, table, lon, symbol); + } else { + // no message, no timestamp + sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, table, lon, symbol); + } + } - info[len] = '\0'; // send the frame + info[len] = '\0'; int16_t state = sendFrame(destCallsign, destSSID, info); #if !RADIOLIB_STATIC_ONLY delete[] info; @@ -244,9 +250,9 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; axClient->getCallsign(srcCallsign); - AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | - RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, - RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); + AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), + RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, + RADIOLIB_AX25_PID_NO_LAYER_3, const_cast(info)); return(axClient->sendFrame(&frameUI)); @@ -256,7 +262,7 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) char* buff = new char[len]; snprintf(buff, len, RADIOLIB_APRS_LORA_HEADER "%s-%d>%s,WIDE%d-%d:%s", this->src, this->id, destCallsign, destSSID, destSSID, info); - int16_t res = this->phyLayer->transmit((uint8_t*)buff, strlen(buff)); + int16_t res = this->phyLayer->transmit(reinterpret_cast(buff), strlen(buff)); delete[] buff; return(res); } From 98bae46c334cf92aec6ac0be6693bfdb695597d9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:32:02 +0100 Subject: [PATCH 1058/1848] [AX25] Fixed issues found by cppcheck --- src/protocols/AX25/AX25.cpp | 66 ++++++++++++++++++++++++++++++++----- src/protocols/AX25/AX25.h | 13 ++++++-- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index b8605d3279..53679049b9 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -8,7 +8,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src } AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info) - : AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, protocolID, (uint8_t*)info, strlen(info)) { + : AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, protocolID, reinterpret_cast(const_cast(info)), strlen(info)) { } @@ -50,8 +50,41 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src } } -AX25Frame::AX25Frame(const AX25Frame& frame) { - *this = frame; +AX25Frame::AX25Frame(const AX25Frame& frame) + : destSSID(frame.destSSID), + srcSSID(frame.srcSSID), + numRepeaters(frame.numRepeaters), + control(frame.control), + protocolID(frame.protocolID), + infoLen(frame.infoLen), + rcvSeqNumber(frame.rcvSeqNumber), + sendSeqNumber(frame.sendSeqNumber) { + strncpy(this->destCallsign, frame.destCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + strncpy(this->srcCallsign, frame.srcCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + + if(frame.infoLen) { + #if !RADIOLIB_STATIC_ONLY + this->info = new uint8_t[frame.infoLen]; + #endif + memcpy(this->info, frame.info, frame.infoLen); + } + + if(frame.numRepeaters) { + #if !RADIOLIB_STATIC_ONLY + this->repeaterCallsigns = new char*[frame.numRepeaters]; + for(uint8_t i = 0; i < frame.numRepeaters; i++) { + this->repeaterCallsigns[i] = new char[strlen(frame.repeaterCallsigns[i]) + 1]; + } + this->repeaterSSIDs = new uint8_t[frame.numRepeaters]; + #endif + + this->numRepeaters = frame.numRepeaters; + for(uint8_t i = 0; i < frame.numRepeaters; i++) { + memcpy(this->repeaterCallsigns[i], frame.repeaterCallsigns[i], strlen(frame.repeaterCallsigns[i])); + this->repeaterCallsigns[i][strlen(frame.repeaterCallsigns[i])] = '\0'; + } + memcpy(this->repeaterSSIDs, frame.repeaterSSIDs, frame.numRepeaters); + } } AX25Frame::~AX25Frame() { @@ -154,17 +187,32 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) { AX25Client::AX25Client(PhysicalLayer* phy) { phyLayer = phy; #if !RADIOLIB_EXCLUDE_AFSK + audio = nullptr; bellModem = nullptr; #endif } #if !RADIOLIB_EXCLUDE_AFSK -AX25Client::AX25Client(AFSKClient* audio) { - phyLayer = audio->phyLayer; - bellModem = new BellClient(audio); +AX25Client::AX25Client(AFSKClient* aud) + : audio(aud) { + phyLayer = this->audio->phyLayer; + bellModem = new BellClient(this->audio); bellModem->setModem(Bell202); } +AX25Client::AX25Client(const AX25Client& ax25) + : phyLayer(ax25.phyLayer), + sourceSSID(ax25.sourceSSID), + preambleLen(ax25.preambleLen) { + strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + #if !RADIOLIB_EXCLUDE_AFSK + if(ax25.bellModem) { + this->audio = ax25.audio; + this->bellModem = new BellClient(ax25.audio); + } + #endif +} + int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) { BellModem_t modem; modem.freqMark = Bell202.freqMark + mark; @@ -205,10 +253,12 @@ int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t dest int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) { // create control field - uint8_t controlField = RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME; + uint8_t controlField = RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME; // build the frame - AX25Frame frame(destCallsign, destSSID, sourceCallsign, sourceSSID, controlField, RADIOLIB_AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str)); + AX25Frame frame(destCallsign, destSSID, sourceCallsign, sourceSSID, controlField, + RADIOLIB_AX25_PID_NO_LAYER_3, + reinterpret_cast(const_cast(str)), strlen(str)); // send Unnumbered Information frame return(sendFrame(&frame)); diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index d1688d9e1a..a34b31731d 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -246,9 +246,15 @@ class AX25Client { #if !RADIOLIB_EXCLUDE_AFSK /*! \brief Constructor for AFSK mode. - \param audio Pointer to the AFSK instance providing audio. + \param aud Pointer to the AFSK instance providing audio. */ - explicit AX25Client(AFSKClient* audio); + explicit AX25Client(AFSKClient* aud); + + /*! + \brief Copy constructor. + \param ax25 AX25Client instance to copy. + */ + AX25Client(const AX25Client& ax25); /*! \brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced @@ -310,10 +316,11 @@ class AX25Client { PhysicalLayer* phyLayer; #if !RADIOLIB_EXCLUDE_AFSK + AFSKClient* audio; BellClient* bellModem; #endif - char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; + char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 }; uint8_t sourceSSID = 0; uint16_t preambleLen = 0; From 914c616c2af560536b36f44be36feed82ff226a4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:32:20 +0100 Subject: [PATCH 1059/1848] [Bell] Fixed issues found by cppcheck --- src/protocols/BellModem/BellModem.cpp | 2 +- src/protocols/BellModem/BellModem.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp index a4c6f3e805..30da937263 100644 --- a/src/protocols/BellModem/BellModem.cpp +++ b/src/protocols/BellModem/BellModem.cpp @@ -58,7 +58,7 @@ size_t BellClient::write(uint8_t b) { uint16_t toneSpace = this->modemType.freqSpace; if(this->reply) { toneMark = this->modemType.freqMarkReply; - toneMark = this->modemType.freqSpaceReply; + toneSpace = this->modemType.freqSpaceReply; } // get the Module pointer to access HAL diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h index 045c2feba6..886e206ea8 100644 --- a/src/protocols/BellModem/BellModem.h +++ b/src/protocols/BellModem/BellModem.h @@ -75,7 +75,7 @@ class BellClient: public AFSKClient, public RadioLibPrint { \brief Audio-client constructor. Can be used when AFSKClient instance already exists. \param aud Audio client to use. */ - BellClient(AFSKClient* aud); + explicit BellClient(AFSKClient* aud); /*! \brief Initialization method. @@ -104,7 +104,7 @@ class BellClient: public AFSKClient, public RadioLibPrint { \param b Byte to write. \returns 1 if the byte was written, 0 otherwise. */ - size_t write(uint8_t b); + size_t write(uint8_t b) override; /*! \brief Set the modem to idle (ready to transmit). @@ -119,7 +119,7 @@ class BellClient: public AFSKClient, public RadioLibPrint { #if !RADIOLIB_GODMODE private: #endif - BellModem_t modemType; + BellModem_t modemType = Bell101; float correction = 1.0; uint16_t toneLen = 0; bool autoStart = true; From 0f0ab73832062b4038f02f52fb00b880207ef756 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:32:32 +0100 Subject: [PATCH 1060/1848] [EXT] Fixed issues found by cppcheck --- src/protocols/ExternalRadio/ExternalRadio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 22a0c41e95..8c5517269d 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -20,7 +20,7 @@ class ExternalRadio: public PhysicalLayer { \brief Default constructor. \param pin Output pin when using direct transmission, defaults to unused pin. */ - ExternalRadio(uint32_t pin = RADIOLIB_NC); + ExternalRadio(uint32_t pin = RADIOLIB_NC); // cppcheck-suppress noExplicitConstructor #endif /*! @@ -28,13 +28,13 @@ class ExternalRadio: public PhysicalLayer { \param hal Pointer to the hardware abstraction layer to use. \param pin Output pin when using direct transmission, defaults to unused pin. */ - ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC); + ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC); // cppcheck-suppress noExplicitConstructor /*! \brief Method to retrieve pointer to the underlying Module instance. \returns Pointer to the Module instance. */ - Module* getMod(); + Module* getMod() override; /*! \brief Dummy implementation overriding PhysicalLayer. @@ -63,7 +63,7 @@ class ExternalRadio: public PhysicalLayer { the output pin will be set to logic high. Otherwise it will be set to logic low. \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; private: Module* mod; From f53d5b90279266e50f4b6197f4be4e7d46c0300c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:32:41 +0100 Subject: [PATCH 1061/1848] [FSK4] Fixed issues found by cppcheck --- src/protocols/FSK4/FSK4.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index e4ff2db347..31df4101c8 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -85,8 +85,8 @@ class FSK4Client { uint32_t baseFreq = 0, baseFreqHz = 0; uint32_t shiftFreq = 0, shiftFreqHz = 0; RadioLibTime_t bitDuration = 0; - uint32_t tones[4]; - uint32_t tonesHz[4]; + uint32_t tones[4] = { 0 }; + uint32_t tonesHz[4] = { 0 }; void tone(uint8_t i); From d779a834a05aa32cf375b84b36a0d7a88b63063f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:32:50 +0100 Subject: [PATCH 1062/1848] [Hell] Fixed issues found by cppcheck --- src/protocols/Hellschreiber/Hellschreiber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 3ee42174d2..0b098da8a6 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -130,7 +130,7 @@ class HellClient: public RadioLibPrint { \param b Byte to write. \returns 1 if the byte was written, 0 otherwise. */ - size_t write(uint8_t b); + size_t write(uint8_t b) override; #if !RADIOLIB_GODMODE private: From 48ed06aa4b4690e976e62aff9381e93b1399252d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:32:57 +0100 Subject: [PATCH 1063/1848] [Morse] Fixed issues found by cppcheck --- src/protocols/Morse/Morse.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 66c39193ae..78d6a91079 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -148,7 +148,7 @@ class MorseClient: public RadioLibPrint { \param b Byte to write. \returns 1 if the byte was written, 0 otherwise. */ - size_t write(uint8_t b); + size_t write(uint8_t b) override; #if !RADIOLIB_GODMODE private: From 89e406775dbfa91d29747edaaeec1ea86656a573 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:33:07 +0100 Subject: [PATCH 1064/1848] [Pager] Fixed issues found by cppcheck --- src/protocols/Pager/Pager.cpp | 9 ++------- src/protocols/Pager/Pager.h | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 48edee628f..e9aa14a479 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -28,9 +28,6 @@ PagerClient::PagerClient(PhysicalLayer* phy) { #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE readBitInstance = phyLayer; #endif - filterNumAddresses = 0; - filterAddresses = NULL; - filterMasks = NULL; } int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shift) { @@ -206,7 +203,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t // in BCD mode, pad the rest of the code word with spaces (0xC) if(encoding == RADIOLIB_PAGER_BCD) { uint8_t numSteps = (symbolPos - RADIOLIB_PAGER_FUNC_BITS_POS + symbolLength)/symbolLength; - for(uint8_t i = 0; i < numSteps; i++) { + for(uint8_t j = 0; j < numSteps; j++) { symbol = encodeBCD(' '); symbol = Module::reflect(symbol, 8); symbol >>= (8 - symbolLength); @@ -397,17 +394,15 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { } // we have the address, start pulling out the message - bool complete = false; size_t decodedBytes = 0; uint32_t prevCw = 0; bool overflow = false; int8_t ovfBits = 0; - while(!complete && phyLayer->available()) { + while(phyLayer->available()) { uint32_t cw = read(); // check if it's the idle code word if(cw == RADIOLIB_PAGER_IDLE_CODE_WORD) { - complete = true; break; } diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 1663ae034e..6963a686a9 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -177,17 +177,17 @@ class PagerClient { #endif PhysicalLayer* phyLayer; - float baseFreq; - float dataRate; - uint32_t baseFreqRaw; - uint16_t shiftFreq; - uint16_t shiftFreqHz; - RadioLibTime_t bitDuration; - uint32_t filterAddr; - uint32_t filterMask; - uint32_t *filterAddresses; - uint32_t *filterMasks; - size_t filterNumAddresses; + float baseFreq = 0; + float dataRate = 0; + uint32_t baseFreqRaw = 0; + uint16_t shiftFreq = 0; + uint16_t shiftFreqHz = 0; + RadioLibTime_t bitDuration = 0; + uint32_t filterAddr = 0; + uint32_t filterMask = 0; + uint32_t *filterAddresses = nullptr; + uint32_t *filterMasks = nullptr; + size_t filterNumAddresses = 0; bool inv = false; void write(uint32_t* data, size_t len); From 909969aa15f131ff50dc5b15dcbd2d2067ef884e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:33:39 +0100 Subject: [PATCH 1065/1848] [Print] Fixed issues found by cppcheck --- src/protocols/Print/ITA2String.cpp | 3 +++ src/protocols/Print/ITA2String.h | 4 ++-- src/protocols/Print/Print.h | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp index 4f2d99a7c7..3999b169d4 100644 --- a/src/protocols/Print/ITA2String.cpp +++ b/src/protocols/Print/ITA2String.cpp @@ -46,6 +46,9 @@ uint8_t* ITA2String::byteArr() { uint8_t* temp = new uint8_t[asciiLen*2 + 1]; #endif + // ensure the minimum possible array size is always initialized + temp[0] = 0; + size_t arrayLen = 0; bool flagFigure = false; for(size_t i = 0; i < asciiLen; i++) { diff --git a/src/protocols/Print/ITA2String.h b/src/protocols/Print/ITA2String.h index 579bb1c48f..05b2e54ace 100644 --- a/src/protocols/Print/ITA2String.h +++ b/src/protocols/Print/ITA2String.h @@ -27,13 +27,13 @@ class ITA2String { \brief Default single-character constructor. \param c ASCII-encoded character to encode as ITA2. */ - ITA2String(char c); + explicit ITA2String(char c); /*! \brief Default string constructor. \param str ASCII-encoded string to encode as ITA2. */ - ITA2String(const char* str); + explicit ITA2String(const char* str); /*! \brief Default destructor. diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index 72ba461501..3645416f9d 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -19,11 +19,11 @@ class RadioLibPrint { virtual size_t write(uint8_t) = 0; size_t write(const char *str) { if (str == NULL) return 0; - return write((const uint8_t *)str, strlen(str)); + return write(reinterpret_cast(str), strlen(str)); } virtual size_t write(const uint8_t *buffer, size_t size); size_t write(const char *buffer, size_t size) { - return write((const uint8_t *)buffer, size); + return write(reinterpret_cast(buffer), size); } size_t print(ITA2String& ita2); @@ -60,7 +60,7 @@ class RadioLibPrint { protected: #endif uint8_t encoding = RADIOLIB_ASCII_EXTENDED; - const char* lineFeed; + const char* lineFeed = "\r\n"; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); From f72f7bd46de0505efcc760cb7876a97ec7387727 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:33:45 +0100 Subject: [PATCH 1066/1848] [RTTTY] Fixed issues found by cppcheck --- src/protocols/RTTY/RTTY.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index 7ba28214ef..1807b36a3f 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -59,7 +59,7 @@ class RTTYClient: public RadioLibPrint { \param b Byte to write. \returns 1 if the byte was written, 0 otherwise. */ - size_t write(uint8_t b); + size_t write(uint8_t b) override; #if !RADIOLIB_GODMODE private: From f0ed8cdf0026e8ee041a96d878c9181ff1fbbdf9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 May 2024 20:34:10 +0100 Subject: [PATCH 1067/1848] [CI] cppcheck do not report progress --- .github/workflows/cppcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 6016de17ea..8f3ec3df76 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -24,4 +24,4 @@ jobs: - name: Run cppcheck run: - cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked --suppress=unusedFunction + cppcheck src --enable=all --force --inline-suppr --quiet --suppress=ConfigurationNotChecked --suppress=unusedFunction From be4ad51330100e7c24bf4436e273de51b129f2ab Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:03:08 +0100 Subject: [PATCH 1068/1848] [LR11x0] Use const pointers where appropriate --- src/modules/LR11x0/LR11x0.cpp | 4 ++-- src/modules/LR11x0/LR11x0.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 16f0726a6a..5c884082d4 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1993,7 +1993,7 @@ int16_t LR11x0::eraseInfoPage(void) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff))); } -int16_t LR11x0::writeInfoPage(uint16_t addr, uint32_t* data, size_t len) { +int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); @@ -3042,7 +3042,7 @@ int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } -int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, size_t len) { +int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len) { // build buffers - later we need to ensure endians are correct, // so there is probably no way to do this without copying buffers and iterating size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index e7affc82a4..fbb83cf39f 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1292,7 +1292,7 @@ class LR11x0: public PhysicalLayer { int16_t setFs(void); int16_t getRandomNumber(uint32_t* rnd); int16_t eraseInfoPage(void); - int16_t writeInfoPage(uint16_t addr, uint32_t* data, size_t len); + int16_t writeInfoPage(uint16_t addr, const uint32_t* data, size_t len); int16_t readInfoPage(uint16_t addr, uint32_t* data, size_t len); int16_t getChipEui(uint8_t* eui); int16_t getSemtechJoinEui(uint8_t* eui); @@ -1449,7 +1449,7 @@ class LR11x0: public PhysicalLayer { // common methods to avoid some copy-paste int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); - int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, size_t len); + int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len); int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); }; From 1dcd61b71dbf271b847fc674692bed26f6a3d7d7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:03:19 +0100 Subject: [PATCH 1069/1848] [SX128x] Use const pointers where appropriate --- src/modules/SX128x/SX128x.cpp | 2 +- src/modules/SX128x/SX128x.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 25ac0a4351..58ba3b29c3 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -964,7 +964,7 @@ int16_t SX128x::setDataShaping(uint8_t sh) { } } -int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { +int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { // check active modem uint8_t modem = getPacketType(); if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index fd8e2e038c..782b95cd14 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -666,7 +666,7 @@ class SX128x: public PhysicalLayer { \param len Sync word length in bytes. \returns \ref status_codes */ - int16_t setSyncWord(uint8_t* syncWord, uint8_t len); + int16_t setSyncWord(const uint8_t* syncWord, uint8_t len); /*! \brief Sets LoRa sync word. From d4e7af836c4441f45d1e7868ffaa06ed5f7fa623 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:03:43 +0100 Subject: [PATCH 1070/1848] [Hell] Fixed issues found by cppcheck --- src/protocols/Hellschreiber/Hellschreiber.cpp | 2 +- src/protocols/Hellschreiber/Hellschreiber.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index eafd25ea34..b79e7a4412 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -30,7 +30,7 @@ int16_t HellClient::begin(float base, float rate) { return(phyLayer->startDirect()); } -size_t HellClient::printGlyph(uint8_t* buff) { +size_t HellClient::printGlyph(const uint8_t* buff) { // print the character Module* mod = phyLayer->getMod(); bool transmitting = false; diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 0b098da8a6..0c266979d7 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -117,7 +117,7 @@ class HellClient: public RadioLibPrint { \param buff Buffer of pixels to send, in a 7x7 pixel array. \returns Always returns the number of printed glyphs (1). */ - size_t printGlyph(uint8_t* buff); + size_t printGlyph(const uint8_t* buff); /*! \brief Invert text color. From a93e7b93de33b462e8fddda96272ba3d69d6322c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:03:53 +0100 Subject: [PATCH 1071/1848] [SSTV] Fixed issues found by cppcheck --- src/protocols/SSTV/SSTV.cpp | 2 +- src/protocols/SSTV/SSTV.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 0543e07f02..9d31e59795 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -246,7 +246,7 @@ void SSTVClient::sendHeader() { this->tone(RADIOLIB_SSTV_TONE_BREAK, RADIOLIB_SSTV_HEADER_BIT_LENGTH); } -void SSTVClient::sendLine(uint32_t* imgLine) { +void SSTVClient::sendLine(const uint32_t* imgLine) { // check first line flag in Scottie modes if(firstLine && ((txMode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { firstLine = false; diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index 9d5811b850..7c0feacd2a 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -174,7 +174,7 @@ class SSTVClient { \param imgLine Image line to send, in 24-bit RGB. It is up to the user to ensure that imgLine has enough pixels to send it in the current SSTV mode. */ - void sendLine(uint32_t* imgLine); + void sendLine(const uint32_t* imgLine); /*! \brief Get picture height of the currently configured SSTV mode. From 356e8c85460dfa9747638719ee80976c2b8d1c9a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:04:09 +0100 Subject: [PATCH 1072/1848] [FEC] Fixed issues found by cppcheck --- src/utils/FEC.cpp | 28 ++++++++++++++++++++++------ src/utils/FEC.h | 25 +++++++++++++++---------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/utils/FEC.cpp b/src/utils/FEC.cpp index 39d7f5d5fe..515014d0ab 100644 --- a/src/utils/FEC.cpp +++ b/src/utils/FEC.cpp @@ -5,6 +5,14 @@ RadioLibBCH::RadioLibBCH() { } +RadioLibBCH::~RadioLibBCH() { + #if !RADIOLIB_STATIC_ONLY + delete[] this->alphaTo; + delete[] this->indexOf; + delete[] this->generator; + #endif +} + /* BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder @@ -116,12 +124,15 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { // Search for roots 1, 2, ..., m-1 in cycle sets int32_t rdncy = 0; #if RADIOLIB_STATIC_ONLY - int32_t min[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + int32_t min[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 }; #else int32_t* min = new int32_t[this->n - this->k + 1]; #endif kaux = 0; + // ensure the first element is always initializer + min[0] = 0; + for(ii = 1; ii <= jj; ii++) { min[kaux] = 0; for(jj = 0; jj < size[ii]; jj++) { @@ -140,12 +151,15 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { int32_t noterms = kaux; #if RADIOLIB_STATIC_ONLY - int32_t zeros[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + int32_t zeros[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 }; #else int32_t* zeros = new int32_t[this->n - this->k + 1]; #endif kaux = 1; + // ensure the first element is always initializer + zeros[1] = 0; + for(ii = 0; ii < noterms; ii++) { for(jj = 0; jj < size[min[ii]]; jj++) { zeros[kaux] = cycle[min[ii]][jj]; @@ -186,9 +200,10 @@ void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) { uint32_t RadioLibBCH::encode(uint32_t dataword) { // we only use the "k" most significant bits #if RADIOLIB_STATIC_ONLY - int32_t data[RADIOLIB_BCH_MAX_K]; + int32_t data[RADIOLIB_BCH_MAX_K] = { 0 }; #else int32_t* data = new int32_t[this->k]; + memset(data, 0, this->k*sizeof(int32_t)); #endif int32_t j1 = 0; for(int32_t i = this->n; i > (this->n - this->k); i--) { @@ -201,11 +216,11 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { // reset the M(x)+r array elements #if RADIOLIB_STATIC_ONLY - int32_t Mr[RADIOLIB_BCH_MAX_N]; + int32_t Mr[RADIOLIB_BCH_MAX_N] = { 0 }; #else int32_t* Mr = new int32_t[this->n]; + memset(Mr, 0x00, this->n*sizeof(int32_t)); #endif - memset(Mr, 0x00, this->n*sizeof(int32_t)); // copy the contents of data into Mr and add the zeros memcpy(Mr, data, this->k*sizeof(int32_t)); @@ -228,9 +243,10 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } #if RADIOLIB_STATIC_ONLY - int32_t bb[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + int32_t bb[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 }; #else int32_t* bb = new int32_t[this->n - this->k + 1]; + memset(bb, 0, (this->n - this->k + 1)*sizeof(int32_t)); #endif j = 0; for(int32_t i = start; i < end; ++i) { diff --git a/src/utils/FEC.h b/src/utils/FEC.h index 0716fe11c7..30ba17ef92 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -30,6 +30,11 @@ class RadioLibBCH { */ RadioLibBCH(); + /*! + \brief Default detructor. + */ + ~RadioLibBCH(); + /*! \brief Initialization method. \param n Code word length in bits, up to 32. @@ -47,19 +52,19 @@ class RadioLibBCH { uint32_t encode(uint32_t dataword); private: - uint8_t n; - uint8_t k; - uint32_t poly; - uint8_t m; + uint8_t n = 0; + uint8_t k = 0; + uint32_t poly = 0; + uint8_t m = 0; #if RADIOLIB_STATIC_ONLY - int32_t alphaTo[RADIOLIB_BCH_MAX_N + 1]; - int32_t indexOf[RADIOLIB_BCH_MAX_N + 1]; - int32_t generator[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1]; + int32_t alphaTo[RADIOLIB_BCH_MAX_N + 1] = { 0 }; + int32_t indexOf[RADIOLIB_BCH_MAX_N + 1] = { 0 }; + int32_t generator[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 }; #else - int32_t* alphaTo; - int32_t* indexOf; - int32_t* generator; + int32_t* alphaTo = nullptr; + int32_t* indexOf = nullptr; + int32_t* generator = nullptr; #endif }; From 330f4e8fe1c72a2bec00171d7a300c7c2092b4cb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:04:19 +0100 Subject: [PATCH 1073/1848] [CRC] Fixed issues found by cppcheck --- src/utils/CRC.cpp | 2 +- src/utils/CRC.h | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/utils/CRC.cpp b/src/utils/CRC.cpp index 4422942b05..ac7fb74f06 100644 --- a/src/utils/CRC.cpp +++ b/src/utils/CRC.cpp @@ -4,7 +4,7 @@ RadioLibCRC::RadioLibCRC() { } -uint32_t RadioLibCRC::checksum(uint8_t* buff, size_t len) { +uint32_t RadioLibCRC::checksum(const uint8_t* buff, size_t len) { uint32_t crc = this->init; size_t pos = 0; for(size_t i = 0; i < 8*len; i++) { diff --git a/src/utils/CRC.h b/src/utils/CRC.h index 124fa49d93..bec3d71037 100644 --- a/src/utils/CRC.h +++ b/src/utils/CRC.h @@ -21,32 +21,32 @@ class RadioLibCRC { /*! \brief CRC size in bits. */ - uint8_t size; + uint8_t size = 8; /*! \brief CRC polynomial. */ - uint32_t poly; + uint32_t poly = 0; /*! \brief Initial value. */ - uint32_t init; + uint32_t init = 0; /*! \brief Final XOR value. */ - uint32_t out; + uint32_t out = 0; /*! \brief Whether to reflect input bytes. */ - bool refIn; + bool refIn = false; /*! \brief Whether to reflect the result. */ - bool refOut; + bool refOut = false; /*! \brief Default constructor. @@ -59,7 +59,7 @@ class RadioLibCRC { \param len Size of the buffer in bytes. \returns The resulting checksum. */ - uint32_t checksum(uint8_t* buff, size_t len); + uint32_t checksum(const uint8_t* buff, size_t len); }; // the global singleton From dd9dc39f69f08ca4fb2f4a843994d8793ae3108d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 12:04:41 +0100 Subject: [PATCH 1074/1848] [Crypto] Fixed issues found by cppcheck --- src/utils/Cryptography.cpp | 10 +++++----- src/utils/Cryptography.h | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp index 16d1c46da9..9411bd1a31 100644 --- a/src/utils/Cryptography.cpp +++ b/src/utils/Cryptography.cpp @@ -82,7 +82,7 @@ void RadioLibAES128::generateCMAC(uint8_t* in, size_t len, uint8_t* cmac) { delete[] buff; } -bool RadioLibAES128::verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac) { +bool RadioLibAES128::verifyCMAC(uint8_t* in, size_t len, const uint8_t* cmac) { uint8_t cmacReal[RADIOLIB_AES128_BLOCK_SIZE]; this->generateCMAC(in, len, cmacReal); for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { @@ -93,7 +93,7 @@ bool RadioLibAES128::verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac) { return(true); } -void RadioLibAES128::keyExpansion(uint8_t* roundKey, uint8_t* key) { +void RadioLibAES128::keyExpansion(uint8_t* roundKey, const uint8_t* key) { uint8_t tmp[4]; // the first round key is the key itself @@ -167,7 +167,7 @@ void RadioLibAES128::rotWord(uint8_t* word) { } } -void RadioLibAES128::addRoundKey(uint8_t round, state_t* state, uint8_t* roundKey) { +void RadioLibAES128::addRoundKey(uint8_t round, state_t* state, const uint8_t* roundKey) { for(size_t row = 0; row < 4; row++) { for(size_t col = 0; col < 4; col++) { (*state)[row][col] ^= roundKey[(round * RADIOLIB_AES128_N_B * 4) + (row * RADIOLIB_AES128_N_B) + col]; @@ -175,13 +175,13 @@ void RadioLibAES128::addRoundKey(uint8_t round, state_t* state, uint8_t* roundKe } } -void RadioLibAES128::blockXor(uint8_t* dst, uint8_t* a, uint8_t* b) { +void RadioLibAES128::blockXor(uint8_t* dst, const uint8_t* a, const uint8_t* b) { for(uint8_t j = 0; j < RADIOLIB_AES128_BLOCK_SIZE; j++) { dst[j] = a[j] ^ b[j]; } } -void RadioLibAES128::blockLeftshift(uint8_t* dst, uint8_t* src) { +void RadioLibAES128::blockLeftshift(uint8_t* dst, const uint8_t* src) { uint8_t ovf = 0x00; for(int8_t i = RADIOLIB_AES128_BLOCK_SIZE - 1; i >= 0; i--) { dst[i] = src[i] << 1; diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index 661996c5fc..dd6644e45c 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -142,23 +142,23 @@ class RadioLibAES128 { \param cmac CMAC to verify. \returns True if valid, false otherwise. */ - bool verifyCMAC(uint8_t* in, size_t len, uint8_t* cmac); + bool verifyCMAC(uint8_t* in, size_t len, const uint8_t* cmac); private: - uint8_t* keyPtr; - uint8_t roundKey[RADIOLIB_AES128_KEY_EXP_SIZE]; + uint8_t* keyPtr = nullptr; + uint8_t roundKey[RADIOLIB_AES128_KEY_EXP_SIZE] = { 0 }; - void keyExpansion(uint8_t* roundKey, uint8_t* key); + void keyExpansion(uint8_t* roundKey, const uint8_t* key); void cipher(state_t* state, uint8_t* roundKey); void decipher(state_t* state, uint8_t* roundKey); void subWord(uint8_t* word); void rotWord(uint8_t* word); - void addRoundKey(uint8_t round, state_t* state, uint8_t* roundKey); + void addRoundKey(uint8_t round, state_t* state, const uint8_t* roundKey); - void blockXor(uint8_t* dst, uint8_t* a, uint8_t* b); - void blockLeftshift(uint8_t* dst, uint8_t* src); + void blockXor(uint8_t* dst, const uint8_t* a, const uint8_t* b); + void blockLeftshift(uint8_t* dst, const uint8_t* src); void generateSubkeys(uint8_t* key1, uint8_t* key2); void subBytes(state_t* state, const uint8_t* box); From f3d358bbe3365fbe32d4537c071b0e6c7f5797d3 Mon Sep 17 00:00:00 2001 From: bkleiner Date: Sun, 12 May 2024 18:58:01 +0200 Subject: [PATCH 1075/1848] LR11x0: fix setDioAsRfSwitch argument count --- src/modules/LR11x0/LR11x0.cpp | 4 ++-- src/modules/LR11x0/LR11x0.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 5c884082d4..9c4c230483 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1914,8 +1914,8 @@ int16_t LR11x0::calibImage(float freq1, float freq2) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff))); } -int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t gnssCfg, uint8_t wifiCfg) { - uint8_t buff[7] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, gnssCfg, wifiCfg }; +int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) { + uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff))); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index fbb83cf39f..bef2e76b44 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1281,7 +1281,7 @@ class LR11x0: public PhysicalLayer { int16_t calibrate(uint8_t params); int16_t setRegMode(uint8_t mode); int16_t calibImage(float freq1, float freq2); - int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t gnssCfg, uint8_t wifiCfg); + int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg); int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2); int16_t clearIrq(uint32_t irq); int16_t configLfClock(uint8_t setup); From e3f851ef6d49c302b83320fad8a1109f836f7f4d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 19:49:28 +0100 Subject: [PATCH 1076/1848] [AX.25] Added assignment operator overload --- src/protocols/AX25/AX25.cpp | 14 ++++++++++++++ src/protocols/AX25/AX25.h | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 53679049b9..7e7d475e58 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -213,6 +213,20 @@ AX25Client::AX25Client(const AX25Client& ax25) #endif } +AX25Client& AX25Client::operator=(const AX25Client& ax25) { + this->phyLayer = ax25.phyLayer; + this->sourceSSID = ax25.sourceSSID; + this->preambleLen = ax25.preambleLen; + strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + #if !RADIOLIB_EXCLUDE_AFSK + if(ax25.bellModem) { + this->audio = ax25.audio; + this->bellModem = new BellClient(ax25.audio); + } + #endif + return(*this); +} + int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) { BellModem_t modem; modem.freqMark = Bell202.freqMark + mark; diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index a34b31731d..3f2583205a 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -255,6 +255,12 @@ class AX25Client { \param ax25 AX25Client instance to copy. */ AX25Client(const AX25Client& ax25); + + /*! + \brief Overload for assignment operator. + \param ax25 rvalue AX25Client. + */ + AX25Client& operator=(const AX25Client& ax25); /*! \brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced From 71ccce4a3d5e780980d669f506220108835c1da4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 19:49:46 +0100 Subject: [PATCH 1077/1848] [EXT] Added assignment operator overload and copy constructor --- src/protocols/ExternalRadio/ExternalRadio.cpp | 21 +++++++++++++++++++ src/protocols/ExternalRadio/ExternalRadio.h | 17 +++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index 0748b4955e..d8c3a5fa46 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -14,6 +14,27 @@ ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer(1, this->prevFrf = 0; } +ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer(1, 0) { + this->prevFrf = ext.prevFrf; + if(ext.mod) { + this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio()); + } +} + +ExternalRadio& ExternalRadio::operator=(const ExternalRadio& ext) { + this->prevFrf = ext.prevFrf; + if(ext.mod) { + this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio()); + } + return(*this); +} + +ExternalRadio::~ExternalRadio() { + if(this->mod) { + delete this->mod; + } +} + Module* ExternalRadio::getMod() { return(mod); } diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 8c5517269d..823674bc42 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -30,6 +30,23 @@ class ExternalRadio: public PhysicalLayer { */ ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC); // cppcheck-suppress noExplicitConstructor + /*! + \brief Copy constructor. + \param ext ExternalRadio instance to copy. + */ + ExternalRadio(const ExternalRadio& ext); + + /*! + \brief Overload for assignment operator. + \param ext rvalue ExternalRadio. + */ + ExternalRadio& operator=(const ExternalRadio& ext); + + /*! + \brief Default destructor. + */ + ~ExternalRadio(); + /*! \brief Method to retrieve pointer to the underlying Module instance. \returns Pointer to the Module instance. From 9e8da7674025ba3066414e22dd10b83b50c0a263 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 May 2024 19:49:56 +0100 Subject: [PATCH 1078/1848] [ITA2] Added assignment operator overload and copy constructor --- src/protocols/Print/ITA2String.cpp | 19 +++++++++++++++++++ src/protocols/Print/ITA2String.h | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp index 3999b169d4..6c67faa541 100644 --- a/src/protocols/Print/ITA2String.cpp +++ b/src/protocols/Print/ITA2String.cpp @@ -20,6 +20,25 @@ ITA2String::ITA2String(const char* str) { ita2Len = 0; } +ITA2String::ITA2String(const ITA2String& ita2) { + this->asciiLen = ita2.asciiLen; + this->ita2Len = ita2.ita2Len; + #if !RADIOLIB_STATIC_ONLY + this->strAscii = new char[asciiLen + 1]; + #endif + strcpy(this->strAscii, ita2.strAscii); +} + +ITA2String& ITA2String::operator=(const ITA2String& ita2) { + this->asciiLen = ita2.asciiLen; + this->ita2Len = ita2.ita2Len; + #if !RADIOLIB_STATIC_ONLY + this->strAscii = new char[asciiLen + 1]; + #endif + strcpy(this->strAscii, ita2.strAscii); + return(*this); +} + ITA2String::~ITA2String() { #if !RADIOLIB_STATIC_ONLY delete[] strAscii; diff --git a/src/protocols/Print/ITA2String.h b/src/protocols/Print/ITA2String.h index 05b2e54ace..70e7b4b0fb 100644 --- a/src/protocols/Print/ITA2String.h +++ b/src/protocols/Print/ITA2String.h @@ -35,6 +35,18 @@ class ITA2String { */ explicit ITA2String(const char* str); + /*! + \brief Copy constructor. + \param ita2 ITA2String instance to copy. + */ + ITA2String(const ITA2String& ita2); + + /*! + \brief Overload for assignment operator. + \param ita2 rvalue ITA2String. + */ + ITA2String& operator=(const ITA2String& ita2); + /*! \brief Default destructor. */ From 58c8d2d1f4ac985e1f34a1fdb809c506c14db6ce Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 13 May 2024 19:45:13 +1000 Subject: [PATCH 1079/1848] examples/NonArduino/Tock: Remove libtock-c submodule Remove the libtock-c submodule to fix https://github.com/jgromes/RadioLib/issues/1091 Signed-off-by: Alistair Francis --- .github/workflows/main.yml | 4 +- examples/NonArduino/Tock/CMakeLists.txt | 52 ++++++++++++------------- examples/NonArduino/Tock/README.md | 4 +- examples/NonArduino/Tock/libtock-c | 1 - 4 files changed, 32 insertions(+), 29 deletions(-) delete mode 160000 examples/NonArduino/Tock/libtock-c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 34f63a7a8d..928541a413 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -232,7 +232,9 @@ jobs: - name: Build the example run: | cd $PWD/examples/NonArduino/Tock - ./build.sh + git clone https://github.com/tock/libtock-c.git + cd libtock-c; git checkout 44bf89c545953d8859faf101d4b4a4b6a151fe6c; cd ../ + LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh rpi-build: runs-on: [self-hosted, ARM64] diff --git a/examples/NonArduino/Tock/CMakeLists.txt b/examples/NonArduino/Tock/CMakeLists.txt index eed0d08629..d298f5774d 100644 --- a/examples/NonArduino/Tock/CMakeLists.txt +++ b/examples/NonArduino/Tock/CMakeLists.txt @@ -27,7 +27,7 @@ cmake_minimum_required(VERSION 3.18) # create the project project(tock-sx1261) -set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/userland_generic.ld) +set(LINKER_SCRIPT $ENV{LIBTOCK_C_DIRECTORY}/userland_generic.ld) if (RISCV_BUILD) include("tock-riscv.cmake") @@ -50,51 +50,51 @@ add_executable(${PROJECT_NAME} main.cpp) # The build system for libtock-c is a bit odd and the version of libraries # built changes based on compiler version. if (RISCV_BUILD) - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0") + if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0") target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/rv32imc/libtock.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/riscv/lib/gcc/riscv64-unknown-elf/13.2.0/rv32i/ilp32/libgcc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/riscv/lib/gcc/riscv64-unknown-elf/13.2.0/rv32i/ilp32/libgcc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a ) target_include_directories(RadioLib AFTER PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/ + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/ ) else() target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/rv32imc/libtock.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/riscv/lib/gcc/riscv64-unknown-elf/10.5.0/rv32i/ilp32/libgcc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/riscv/lib/gcc/riscv64-unknown-elf/10.5.0/rv32i/ilp32/libgcc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a ) target_include_directories(RadioLib AFTER PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/include/ + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/include/ ) endif() else() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0") + if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0") target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/arm/lib/gcc/arm-none-eabi/13.2.0/libgcc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/arm/arm-none-eabi/lib/libstdc++.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libm.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/arm/lib/gcc/arm-none-eabi/13.2.0/libgcc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/arm/arm-none-eabi/lib/libstdc++.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libm.a ) else() target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/arm/lib/gcc/arm-none-eabi/10.5.0/libgcc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/arm/arm-none-eabi/lib/libstdc++.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libc.a - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libm.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/arm/lib/gcc/arm-none-eabi/10.5.0/libgcc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/arm/arm-none-eabi/lib/libstdc++.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libm.a ) endif() endif() @@ -102,7 +102,7 @@ endif() target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ - ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c + $ENV{LIBTOCK_C_DIRECTORY} ) # you can also specify RadioLib compile-time flags here diff --git a/examples/NonArduino/Tock/README.md b/examples/NonArduino/Tock/README.md index 77ee19b76d..05b2e7c5ed 100644 --- a/examples/NonArduino/Tock/README.md +++ b/examples/NonArduino/Tock/README.md @@ -22,7 +22,9 @@ The RadioLib example can be built with: ```shell $ git clone https://github.com/jgromes/RadioLib.git $ cd RadioLib/examples/NonArduino/Tock/ -$ ./build.sh +$ git clone https://github.com/tock/libtock-c.git +$ cd libtock-c; git checkout 44bf89c545953d8859faf101d4b4a4b6a151fe6c; cd ../ +$ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh ``` Then in the Tock repo you can flash the kernel and app with: diff --git a/examples/NonArduino/Tock/libtock-c b/examples/NonArduino/Tock/libtock-c deleted file mode 160000 index 44bf89c545..0000000000 --- a/examples/NonArduino/Tock/libtock-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 44bf89c545953d8859faf101d4b4a4b6a151fe6c From 23dcc4b8b7e29344c3692c4bab8b5db579bdf4cb Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 13 May 2024 12:36:01 +0200 Subject: [PATCH 1080/1848] Remove submodule file --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 7eb86944a2..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "examples/NonArduino/Tock/libtock-c"] - path = examples/NonArduino/Tock/libtock-c - url = https://github.com/tock/libtock-c.git From f12875fac5cb175047a3d4519c416fa9312c2951 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 15 May 2024 19:45:52 +1000 Subject: [PATCH 1081/1848] examples/NonArduino/Tock: Update to the latest libtock-c API Update to use the latest libtock-c functions. Signed-off-by: Alistair Francis --- .github/workflows/main.yml | 2 +- examples/NonArduino/Tock/CMakeLists.txt | 4 +++ examples/NonArduino/Tock/README.md | 2 +- examples/NonArduino/Tock/libtockHal.h | 34 +++++++++++++------------ 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 928541a413..4becc1b73e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -233,7 +233,7 @@ jobs: run: | cd $PWD/examples/NonArduino/Tock git clone https://github.com/tock/libtock-c.git - cd libtock-c; git checkout 44bf89c545953d8859faf101d4b4a4b6a151fe6c; cd ../ + cd libtock-c; git checkout dbee65a56d74b4bad166317f199e80b959f7c82c; cd ../ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh rpi-build: diff --git a/examples/NonArduino/Tock/CMakeLists.txt b/examples/NonArduino/Tock/CMakeLists.txt index d298f5774d..42d6d67447 100644 --- a/examples/NonArduino/Tock/CMakeLists.txt +++ b/examples/NonArduino/Tock/CMakeLists.txt @@ -54,6 +54,7 @@ if (RISCV_BUILD) target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/rv32imc/libtocksync.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/riscv/lib/gcc/riscv64-unknown-elf/13.2.0/rv32i/ilp32/libgcc.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a @@ -67,6 +68,7 @@ if (RISCV_BUILD) target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/rv32imc/libtocksync.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/riscv/lib/gcc/riscv64-unknown-elf/10.5.0/rv32i/ilp32/libgcc.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a @@ -82,6 +84,7 @@ else() target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/cortex-m4/libtocksync.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/arm/lib/gcc/arm-none-eabi/13.2.0/libgcc.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/arm/arm-none-eabi/lib/libstdc++.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libc.a @@ -91,6 +94,7 @@ else() target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/cortex-m4/libtocksync.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/arm/lib/gcc/arm-none-eabi/10.5.0/libgcc.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/arm/arm-none-eabi/lib/libstdc++.a $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libc.a diff --git a/examples/NonArduino/Tock/README.md b/examples/NonArduino/Tock/README.md index 05b2e7c5ed..cae7f38095 100644 --- a/examples/NonArduino/Tock/README.md +++ b/examples/NonArduino/Tock/README.md @@ -23,7 +23,7 @@ The RadioLib example can be built with: $ git clone https://github.com/jgromes/RadioLib.git $ cd RadioLib/examples/NonArduino/Tock/ $ git clone https://github.com/tock/libtock-c.git -$ cd libtock-c; git checkout 44bf89c545953d8859faf101d4b4a4b6a151fe6c; cd ../ +$ cd libtock-c; git checkout dbee65a56d74b4bad166317f199e80b959f7c82c; cd ../ $ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh ``` diff --git a/examples/NonArduino/Tock/libtockHal.h b/examples/NonArduino/Tock/libtockHal.h index 76ed42df14..85c53920cd 100644 --- a/examples/NonArduino/Tock/libtockHal.h +++ b/examples/NonArduino/Tock/libtockHal.h @@ -31,10 +31,12 @@ #include // include all the dependencies -#include "libtock/lora_phy.h" -#include "libtock/gpio.h" -#include "libtock/timer.h" -#include "libtock/read_only_state.h" +#include "libtock/net/lora_phy.h" +#include "libtock/net/syscalls/lora_phy_syscalls.h" +#include "libtock-sync/net/lora_phy.h" +#include "libtock/peripherals/gpio.h" +#include "libtock-sync/services/alarm.h" +#include "libtock/kernel/read_only_state.h" #define RADIO_BUSY 1 #define RADIO_DIO_1 2 @@ -99,9 +101,9 @@ class TockHal : public RadioLibHal { } if (mode == PIN_OUTPUT) { - lora_phy_gpio_enable_output(pin); + libtock_lora_phy_gpio_enable_output(pin); } else if (mode == PIN_INPUT) { - lora_phy_gpio_enable_input(pin, PullDown); + libtock_lora_phy_gpio_enable_input(pin, libtock_pull_down); } } @@ -111,9 +113,9 @@ class TockHal : public RadioLibHal { } if (value) { - lora_phy_gpio_set(pin); + libtock_lora_phy_gpio_set(pin); } else { - lora_phy_gpio_clear(pin); + libtock_lora_phy_gpio_clear(pin); } } @@ -124,7 +126,7 @@ class TockHal : public RadioLibHal { return 0; } - lora_phy_gpio_read(pin, &value); + libtock_lora_phy_gpio_read(pin, &value); return value; } @@ -134,11 +136,11 @@ class TockHal : public RadioLibHal { return; } - lora_phy_gpio_interrupt_callback(lora_phy_gpio_Callback, &interruptCb); + libtock_lora_phy_gpio_command_interrupt_callback(lora_phy_gpio_Callback, &interruptCb); // set GPIO as input and enable interrupts on it - lora_phy_gpio_enable_input(interruptNum, PullDown); - lora_phy_gpio_enable_interrupt(interruptNum, Change); + libtock_lora_phy_gpio_enable_input(interruptNum, libtock_pull_down); + libtock_lora_phy_gpio_enable_interrupt(interruptNum, libtock_change); } void detachInterrupt(uint32_t interruptNum) override { @@ -146,15 +148,15 @@ class TockHal : public RadioLibHal { return; } - lora_phy_gpio_disable_interrupt(interruptNum); + libtock_lora_phy_gpio_disable_interrupt(interruptNum); } void delay(unsigned long ms) override { - delay_ms( ms ); + libtocksync_alarm_delay_ms( ms ); } void delayMicroseconds(unsigned long us) override { - delay_ms( us / 1000 ); + libtocksync_alarm_delay_ms( us / 1000 ); } unsigned long millis() override { @@ -181,7 +183,7 @@ class TockHal : public RadioLibHal { } void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { - lora_phy_read_write_sync((const char*) out, (char*) in, len); + libtocksync_lora_phy_read_write(out, in, len); } void spiEndTransaction() { From b336dd59f942020ca0f7b774a39d4a008de0f417 Mon Sep 17 00:00:00 2001 From: Dominic Moffat Date: Wed, 15 May 2024 17:40:08 +0100 Subject: [PATCH 1082/1848] Fixes overload warning when building with ESP IDF (#1089) * fixes overload * fixes overload * fixes overload warnings in ESP-IDF --- src/modules/LR11x0/LR11x0.cpp | 4 ++++ src/modules/LR11x0/LR11x0.h | 5 ++++- src/modules/SX126x/SX126x.cpp | 5 +++++ src/modules/SX126x/SX126x.h | 3 ++- src/modules/SX128x/SX128x.cpp | 4 ++++ src/modules/SX128x/SX128x.h | 3 ++- 6 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 9c4c230483..c1c4cec1d9 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -314,6 +314,10 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1)); } +int16_t LR11x0::sleep() { + return(LR11x0::sleep(true, 0)); +} + int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index bef2e76b44..2554860562 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -774,7 +774,10 @@ class LR11x0: public PhysicalLayer { \param sleepTime Sleep duration (enables automatic wakeup), in multiples of 30.52 us. Ignored if set to 0. \returns \ref status_codes */ - int16_t sleep(bool retainConfig = true, uint32_t sleepTime = 0); + + int16_t sleep(); + + int16_t sleep(bool retainConfig, uint32_t sleepTime); // interrupt methods diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 17393a1f02..cf07388986 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -442,6 +442,11 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) return(getChannelScanResult()); } + +int16_t SX126x::sleep() { + return(SX126x::sleep(true)); +} + int16_t SX126x::sleep(bool retainConfig) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 8cc3540b82..3fd0a4c128 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -552,7 +552,8 @@ class SX126x: public PhysicalLayer { or to false to discard current configuration ("cold start"). Defaults to true. \returns \ref status_codes */ - int16_t sleep(bool retainConfig = true); + int16_t sleep(); + int16_t sleep(bool retainConfig); /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 58ba3b29c3..a51ae78c2b 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -424,6 +424,10 @@ int16_t SX128x::scanChannel() { return(getChannelScanResult()); } +int16_t SX128x::sleep() { + return(SX128x::sleep(true)); +} + int16_t SX128x::sleep(bool retainConfig) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 782b95cd14..69d8f975da 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -463,7 +463,8 @@ class SX128x: public PhysicalLayer { to discard current configuration and data buffer. Defaults to true. \returns \ref status_codes */ - int16_t sleep(bool retainConfig = true); + int16_t sleep(); + int16_t sleep(bool retainConfig); /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). From 63ef9e09777eefdc6b6242a55f0c55a731f086b6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 15 May 2024 18:43:19 +0200 Subject: [PATCH 1083/1848] Fixup doxygen comments (#1089) --- src/modules/LR11x0/LR11x0.h | 12 ++++++++---- src/modules/SX126x/SX126x.h | 8 +++++++- src/modules/SX128x/SX128x.h | 7 +++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 2554860562..2ba8d269ef 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -766,7 +766,14 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t standby(uint8_t mode, bool wakeup = true); - + + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + Overload with warm start enabled for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t sleep(); + /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") @@ -774,9 +781,6 @@ class LR11x0: public PhysicalLayer { \param sleepTime Sleep duration (enables automatic wakeup), in multiples of 30.52 us. Ignored if set to 0. \returns \ref status_codes */ - - int16_t sleep(); - int16_t sleep(bool retainConfig, uint32_t sleepTime); // interrupt methods diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 3fd0a4c128..e1297adca2 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -545,6 +545,13 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + Overload with warm start enabled for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t sleep(); /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). @@ -552,7 +559,6 @@ class SX126x: public PhysicalLayer { or to false to discard current configuration ("cold start"). Defaults to true. \returns \ref status_codes */ - int16_t sleep(); int16_t sleep(bool retainConfig); /*! diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 69d8f975da..969ab58a14 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -457,6 +457,13 @@ class SX128x: public PhysicalLayer { */ int16_t scanChannel() override; + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + Overload for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t sleep(); + /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). \param retainConfig Set to true to retain configuration and data buffer or to false From f9af9b4d3f31d3f8b0504e45cb78b23abbd5ce3d Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 15 May 2024 18:45:57 +0200 Subject: [PATCH 1084/1848] [SX128x] Fix forgotten sleep --- src/modules/SX128x/SX128x.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 969ab58a14..706cc62713 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -470,7 +470,6 @@ class SX128x: public PhysicalLayer { to discard current configuration and data buffer. Defaults to true. \returns \ref status_codes */ - int16_t sleep(); int16_t sleep(bool retainConfig); /*! From 3b412d75218dafbb0c909a30737120de77d62fda Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 15 May 2024 20:22:30 +0200 Subject: [PATCH 1085/1848] [SX126x] Add rounding when using custom image rejection (#1096) --- src/modules/SX126x/SX126x.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index cf07388986..50eeaca1b5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1848,6 +1848,8 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) { // calculate the calibration coefficients and calibrate image uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) }; + data[0] = (data[0] % 2) ? data[0] : data[0] - 1; + data[1] = (data[1] % 2) ? data[1] : data[1] + 1; return(this->calibrateImage(data)); } From 47f5569e7f5ece58d6730165744ea73305e65c85 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 15 May 2024 21:27:31 +0200 Subject: [PATCH 1086/1848] [LR11x0] Dump FW versions in debug mode --- src/modules/LR11x0/LR11x0.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index c1c4cec1d9..e744249f49 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1638,8 +1638,17 @@ bool LR11x0::findChip(uint8_t ver) { // read the version uint8_t device = 0xFF; - if((this->getVersion(NULL, &device, NULL, NULL) == RADIOLIB_ERR_NONE) && (device == ver)) { + uint8_t major = 0xFF; + uint8_t minor = 0xFF; + if((this->getVersion(NULL, &device, &major, &minor) == RADIOLIB_ERR_NONE) && (device == ver)) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", device); + RADIOLIB_DEBUG_BASIC_PRINTLN("Transceiver FW version: %d.%d", (int)major, (int)minor); + #if RADIOLIB_DEBUG_BASIC + this->wifiReadVersion(&major, &minor); + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)major, (int)minor); + this->gnssReadVersion(&major, &minor); + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)major, (int)minor); + #endif flagFound = true; } else { RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, device); From b5fd75b4dc7e2aee4b82a52e5695fb4a71e37b23 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 May 2024 08:44:50 +0200 Subject: [PATCH 1087/1848] [LR11x0] Implemented v2 GNSS commands --- src/modules/LR11x0/LR11x0.cpp | 208 +++++++++++++++++++++++++++++++++- src/modules/LR11x0/LR11x0.h | 49 +++++++- 2 files changed, 253 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index e744249f49..ceb11c6c91 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2368,7 +2368,7 @@ int16_t LR11x0::setRangingReqAddr(uint32_t addr) { int16_t LR11x0::getRangingResult(uint8_t type, float* res) { uint8_t reqBuff[1] = { type }; uint8_t rplBuff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_NOP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); RADIOLIB_ASSERT(state); if(res) { @@ -2420,6 +2420,22 @@ int16_t LR11x0::setRangingParameter(uint8_t symbolNum) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff))); } +int16_t LR11x0::setRssiCalibration(int8_t* tune, int16_t gainOffset) { + uint8_t buff[11] = { + (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4), + (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4), + (uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4), + (uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4), + (uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4), + (uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4), + (uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4), + (uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4), + (uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4), + (uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff))); +} + int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { uint8_t buff[1] = { sync }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff))); @@ -2837,6 +2853,196 @@ int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t co return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); } +// TODO check version > 02.01 +int16_t LR11x0::gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { + uint8_t buff[3] = { effort, resMask, nbSvMax }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SCAN, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED, false, buff, sizeof(buff)); + + // pass the replies + if(lastScanMode) { *lastScanMode = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) { + uint8_t buff[2] = { effort, opt }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) { + uint8_t buff[12] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_TIME, false, buff, sizeof(buff)); + + // pass the replies + if(err) { *err = buff[0]; } + if(time) { *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; } + if(nbUs) { *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } + if(timeAccuracy) { *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; } + + return(state); +} + +int16_t LR11x0::gnssResetTime(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME, true, NULL, 0)); +} + +int16_t LR11x0::gnssResetPosition(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0)); +} + +int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(status) { *status = (int8_t)buff[0]; } + if(info) { *info = buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) { + uint8_t rplBuff[125] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, 125); + RADIOLIB_ASSERT(state); + + // convert endians + if(timing) { + for(size_t i = 0; i < 31; i++) { + timing[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)]; + } + } + + if(constDemod) { *constDemod = rplBuff[124]; } + + return(state); +} + +int16_t LR11x0::gnssSetTime(uint32_t time, uint16_t accuracy) { + uint8_t buff[6] = { + (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), + (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), + (uint8_t)((accuracy >> 8) & 0xFF), (uint8_t)(accuracy & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_TIME, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt) { + uint8_t buff[18] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES, false, buff, sizeof(buff)); + + // pass the replies + if(error) { *error = buff[0]; } + if(nbSvUsed) { *nbSvUsed = buff[1]; } + if(lat) { + uint16_t latRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; + *lat = ((float)latRaw * 90.0f)/2048.0f; + } + if(lon) { + uint16_t lonRaw = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; + *lon = ((float)lonRaw * 180.0f)/2048.0f; + } + if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } + if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; } + if(latFilt) { + uint16_t latRaw = ((uint16_t)(buff[10]) << 8) | (uint16_t)buff[11]; + *latFilt = ((float)latRaw * 90.0f)/2048.0f; + } + if(lonFilt) { + uint16_t lonRaw = ((uint16_t)(buff[12]) << 8) | (uint16_t)buff[13]; + *lonFilt = ((float)lonRaw * 180.0f)/2048.0f; + } + if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; } + if(xtalFilt) { *xtalFilt = ((uint16_t)(buff[16]) << 8) | (uint16_t)buff[17]; } + + return(state); +} + +int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) { + uint8_t buff[3] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP, false, buff, sizeof(buff)); + + if(delay) { *delay = ((uint32_t)(buff[0]) << 16) | ((uint32_t)(buff[1]) << 8) | (uint32_t)buff[2]; } + + return(state); +} + +int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) { + uint8_t buff[2] = { effort, bitMask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) { + // TODO parse the reply into some structure + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53)); +} + +int16_t LR11x0::gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period) { + uint8_t buff[4] = { bitMask, svType, (uint8_t)((period >> 8) & 0xFF), (uint8_t)(period & 0xFF) }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period) { + uint8_t reqBuff[2] = { bitMask, svType }; + uint8_t rplBuff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(period) { *period = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; } + + return(state); +} + +int16_t LR11x0::gnssConfigDelayResetAP(uint32_t delay) { + uint8_t buff[3] = { (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat) { + uint8_t reqBuff[1] = { bitMask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::gnssReadWNRollover(uint8_t* status, uint8_t* rollover) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WN_ROLLOVER, false, buff, sizeof(buff)); + + if(status) { *status = buff[0]; } + if(rollover) { *rollover = buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) { + uint8_t reqBuff[1] = { bitMask }; + uint8_t rplBuff[5] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(nbVisSat) { *nbVisSat = rplBuff[0]; } + if(timeElapsed) { *timeElapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } + + return(state); +} + +int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1) { + uint8_t reqBuff[1] = { bitMask }; + uint8_t rplBuff[8] = { 0 }; + size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } + if(bitMaskActivated1) { *bitMaskActivated1 = ((uint32_t)(rplBuff[4]) << 24) | ((uint32_t)(rplBuff[5]) << 16) | ((uint32_t)(rplBuff[6]) << 8) | (uint32_t)rplBuff[7]; } + + return(state); +} + int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { if(!key) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 2ba8d269ef..efe4a74927 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -84,6 +84,7 @@ #define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225) #define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227) #define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228) +#define RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION (0x0229) #define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B) #define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C) #define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D) @@ -111,6 +112,10 @@ #define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408) #define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409) #define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A) +#define RADIOLIB_LR11X0_CMD_GNSS_SCAN (0x040B) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E) #define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410) #define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411) #define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414) @@ -119,10 +124,26 @@ #define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417) #define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418) #define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D) -#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E) #define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426) +#define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434) +#define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435) +#define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0455) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457) +#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464) +#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x0465) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_WN_ROLLOVER (0x0467) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469) +#define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472) #define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502) #define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503) #define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504) @@ -147,6 +168,7 @@ // LR11X0 register map #define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414) #define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054) +// TODO add fix for br 600/1200 bps // LR11X0 SPI command variables @@ -1347,6 +1369,7 @@ class LR11x0: public PhysicalLayer { int16_t setGfskWhitParams(uint16_t seed); int16_t setRxBoosted(bool en); int16_t setRangingParameter(uint8_t symbolNum); + int16_t setRssiCalibration(int8_t* tune, int16_t gainOffset); int16_t setLoRaSyncWord(uint8_t sync); int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len); int16_t lrFhssSetSyncWord(uint32_t sync); @@ -1389,6 +1412,26 @@ class LR11x0: public PhysicalLayer { int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc); int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac); int16_t gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); + int16_t gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax); + int16_t gnssReadLastScanModeLaunched(uint8_t* lastScanMode); + int16_t gnssFetchTime(uint8_t effort, uint8_t opt); + int16_t gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy); + int16_t gnssResetTime(void); + int16_t gnssResetPosition(void); + int16_t gnssReadDemodStatus(int8_t* status, uint8_t* info); + int16_t gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod); + int16_t gnssSetTime(uint32_t time, uint16_t accuracy); + int16_t gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt); + int16_t gnssReadDelayResetAP(uint32_t* delay); + int16_t gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask); + int16_t gnssReadAlmanacStatus(uint8_t* status); + int16_t gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period); + int16_t gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period); + int16_t gnssConfigDelayResetAP(uint32_t delay); + int16_t gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat); + int16_t gnssReadWNRollover(uint8_t* status, uint8_t* rollover); + int16_t gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed); + int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1); int16_t cryptoSetKey(uint8_t keyId, uint8_t* key); int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key); From ffbcdd0d57498c360efb0f19646f1452d44c27ca Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 13:55:22 +0200 Subject: [PATCH 1088/1848] [MOD] Move SPI timeout to SPI config struct --- src/Module.cpp | 20 ++++++++++---------- src/Module.h | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 8a95d52033..2dc3797576 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -118,7 +118,7 @@ void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inByte for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } - SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, inBytes, numBytes, true); } } @@ -135,7 +135,7 @@ uint8_t Module::SPIreadRegister(uint32_t reg) { for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } - SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, &resp, 1, true); } return(resp); } @@ -152,7 +152,7 @@ void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } - SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT); + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, data, NULL, numBytes, true); } } @@ -168,7 +168,7 @@ void Module::SPIwriteRegister(uint32_t reg, uint8_t data) { for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) { *(cmdPtr++) = (reg >> 8*i) & 0xFF; } - SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, &data, NULL, 1, true); } } @@ -245,7 +245,7 @@ int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command - int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); + int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio); RADIOLIB_ASSERT(state); #if !RADIOLIB_SPI_PARANOID @@ -273,7 +273,7 @@ int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, boo int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command - int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT); + int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio); RADIOLIB_ASSERT(state); #if !RADIOLIB_SPI_PARANOID @@ -301,7 +301,7 @@ int16_t Module::SPIcheckStream() { for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { *(cmdPtr++) = ( this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] >> 8*i) & 0xFF; } - state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT); + state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true); RADIOLIB_ASSERT(state); // translate to RadioLib status code @@ -313,7 +313,7 @@ int16_t Module::SPIcheckStream() { return(state); } -int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout) { +int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) { // prepare the output buffer size_t buffLen = cmdLen + numBytes; if(!write) { @@ -345,7 +345,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write RadioLibTime_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); - if(this->hal->millis() - start >= timeout) { + if(this->hal->millis() - start >= this->spiConfig.timeout) { RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; @@ -378,7 +378,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write RadioLibTime_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); - if(this->hal->millis() - start >= timeout) { + if(this->hal->millis() - start >= this->spiConfig.timeout) { RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY delete[] buffOut; diff --git a/src/Module.h b/src/Module.h index 90de297703..72cb8e74c8 100644 --- a/src/Module.h +++ b/src/Module.h @@ -18,9 +18,6 @@ */ #define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } -// default timeout for SPI transfers -#define RADIOLIB_MODULE_SPI_TIMEOUT (1000) - /*! \defgroup module_spi_command_pos Position of commands in Module::spiConfig command array. \{ @@ -200,6 +197,9 @@ class Module { /*! \brief Callback for validation SPI status. */ SPIcheckStatusCb_t checkStatusCb; + + /*! \brief Timeout in ms when waiting for GPIO signals. */ + RadioLibTime_t timeout; }; /*! \brief SPI configuration structure. The default configuration corresponds to register-access modules, such as SX127x. */ @@ -211,6 +211,7 @@ class Module { .statusPos = 0, .parseStatusCb = nullptr, .checkStatusCb = nullptr, + .timeout = 1000, }; #if RADIOLIB_INTERRUPT_TIMING @@ -368,10 +369,9 @@ class Module { \param dataIn Data that was transferred from slave to master. \param numBytes Number of bytes to transfer. \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). - \param timeout GPIO wait period timeout in milliseconds. \returns \ref status_codes */ - int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout); + int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio); // pin number access methods From 8f5440e4b5ca52e0d506817db7ecb46fc3f5be97 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 13:55:53 +0200 Subject: [PATCH 1089/1848] [LR11x0] Clarified device macro naming --- src/modules/LR11x0/LR1110.cpp | 2 +- src/modules/LR11x0/LR1120.cpp | 2 +- src/modules/LR11x0/LR1121.cpp | 2 +- src/modules/LR11x0/LR11x0.h | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 39f005273b..77e1a02f78 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -2,7 +2,7 @@ #if !RADIOLIB_EXCLUDE_LR11X0 LR1110::LR1110(Module* mod) : LR11x0(mod) { - chipType = RADIOLIB_LR11X0_HW_LR1110; + chipType = RADIOLIB_LR11X0_DEVICE_LR1110; } int16_t LR1110::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index b3c0c88eb1..a110703631 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -2,7 +2,7 @@ #if !RADIOLIB_EXCLUDE_LR11X0 LR1120::LR1120(Module* mod) : LR11x0(mod) { - chipType = RADIOLIB_LR11X0_HW_LR1120; + chipType = RADIOLIB_LR11X0_DEVICE_LR1120; } int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { diff --git a/src/modules/LR11x0/LR1121.cpp b/src/modules/LR11x0/LR1121.cpp index 14e729201b..6292a3bef5 100644 --- a/src/modules/LR11x0/LR1121.cpp +++ b/src/modules/LR11x0/LR1121.cpp @@ -2,7 +2,7 @@ #if !RADIOLIB_EXCLUDE_LR11X0 LR1121::LR1121(Module* mod) : LR1120(mod) { - chipType = RADIOLIB_LR11X0_HW_LR1121; + chipType = RADIOLIB_LR11X0_DEVICE_LR1121; } #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index efe4a74927..3e3df571d1 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -200,10 +200,10 @@ #define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes // RADIOLIB_LR11X0_CMD_GET_VERSION -#define RADIOLIB_LR11X0_HW_LR1110 (0x01UL << 0) // 7 0 HW version: LR1110 -#define RADIOLIB_LR11X0_HW_LR1120 (0x02UL << 0) // 7 0 LR1120 -#define RADIOLIB_LR11X0_HW_LR1121 (0x03UL << 0) // 7 0 LR1121 -#define RADIOLIB_LR11X0_HW_BOOT (0xDFUL << 0) // 7 0 bootloader mode +#define RADIOLIB_LR11X0_DEVICE_LR1110 (0x01UL << 0) // 7 0 HW device: LR1110 +#define RADIOLIB_LR11X0_DEVICE_LR1120 (0x02UL << 0) // 7 0 LR1120 +#define RADIOLIB_LR11X0_DEVICE_LR1121 (0x03UL << 0) // 7 0 LR1121 +#define RADIOLIB_LR11X0_DEVICE_BOOT (0xDFUL << 0) // 7 0 bootloader mode // RADIOLIB_LR11X0_CMD_GET_ERRORS #define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated From 5e398bd8680a8ed307235f45a273f7202670e41e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 14:55:11 +0200 Subject: [PATCH 1090/1848] [LR11x0] Added firmware update support --- .../LR11x0_Firmware_Update.ino | 132 + keywords.txt | 19 +- src/modules/LR11x0/LR11x0.cpp | 146 +- src/modules/LR11x0/LR11x0.h | 57 +- src/modules/LR11x0/LR11x0_firmware.h | 38 + .../LR11x0/firmware/lr1110_transceiver_0303.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1110_transceiver_0304.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1110_transceiver_0305.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1110_transceiver_0306.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1110_transceiver_0307.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1110_transceiver_0308.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1110_transceiver_0401.h | 7741 +++++++++++++++++ .../LR11x0/firmware/lr1120_transceiver_0101.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1120_transceiver_0102.h | 6890 +++++++++++++++ .../LR11x0/firmware/lr1120_transceiver_0201.h | 7741 +++++++++++++++++ .../LR11x0/firmware/lr1121_transceiver_0102.h | 1921 ++++ .../LR11x0/firmware/lr1121_transceiver_0103.h | 2157 +++++ 17 files changed, 75034 insertions(+), 38 deletions(-) create mode 100644 examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino create mode 100644 src/modules/LR11x0/LR11x0_firmware.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0303.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0304.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0305.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0306.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0307.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0308.h create mode 100644 src/modules/LR11x0/firmware/lr1110_transceiver_0401.h create mode 100644 src/modules/LR11x0/firmware/lr1120_transceiver_0101.h create mode 100644 src/modules/LR11x0/firmware/lr1120_transceiver_0102.h create mode 100644 src/modules/LR11x0/firmware/lr1120_transceiver_0201.h create mode 100644 src/modules/LR11x0/firmware/lr1121_transceiver_0102.h create mode 100644 src/modules/LR11x0/firmware/lr1121_transceiver_0103.h diff --git a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino new file mode 100644 index 0000000000..43e7148ffc --- /dev/null +++ b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino @@ -0,0 +1,132 @@ +/* + RadioLib LR11x0 Firmware Update Example + + This example updates the internal LR1110 firmware. + Newer versions of the firmware introduce fixes + and possibly even new features, so it is recommended + to use the latest available firmware version + when possible. + + Other modules from LR11x0 family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// select the firmware image you want to upload +// WARNING: Make sure you select the correct firmware +// for your device! Uploading incorrect firmware +// (e.g. LR1110 firmware to LR1120 device) +// may damage your hardware! +//#define RADIOLIB_LR1110_FIRMWARE_0303 +//#define RADIOLIB_LR1110_FIRMWARE_0304 +//#define RADIOLIB_LR1110_FIRMWARE_0305 +//#define RADIOLIB_LR1110_FIRMWARE_0306 +//#define RADIOLIB_LR1110_FIRMWARE_0307 +#define RADIOLIB_LR1110_FIRMWARE_0401 +//#define RADIOLIB_LR1120_FIRMWARE_0101 +//#define RADIOLIB_LR1120_FIRMWARE_0102 +//#define RADIOLIB_LR1120_FIRMWARE_0201 +//#define RADIOLIB_LR1121_FIRMWARE_0102 +//#define RADIOLIB_LR1121_FIRMWARE_0103 + +// enable this macro if you want to store the image in host +// MCU RAM instead of Flash. +// NOTE: the firmware images are very large, up to 240 kB! +//#define RADIOLIB_LR1110_FIRMWARE_IN_RAM + +// include the firmware image +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//LR1110 radio = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // print the firmware versions before the update + printVersions(); + + // prompt the user + Serial.println(F("[LR1110] Send any character to start the update")); + while(!Serial.available()) { yield(); } + + // upload update into LR11x0 non-volatile memory + Serial.print(F("[LR1110] Updating firmware, this may take several seconds ... ")); + state = radio.updateFirmware(lr11xx_firmware_image, RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE); + /* + use the following if you enabled RADIOLIB_LR1110_FIRMWARE_IN_RAM + state = radio.updateFirmware(lr11xx_firmware_image, RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE, false); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // print the firmware versions after the update + printVersions(); + +} + +void printVersions() { + LR11x0VersionInfo_t version; + Serial.print(F("[LR1110] Reading firmware versions ... ")); + int16_t state = radio.getVersionInfo(&version); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + Serial.print(F("[LR1110] Device: ")); + Serial.println(version.device); + + Serial.print(F("[LR1110] Base firmware: ")); + Serial.print(version.fwMajor); + Serial.print('.'); + Serial.println(version.fwMinor); + + Serial.print(F("[LR1110] WiFi firmware: ")); + Serial.print(version.fwMajorWiFi); + Serial.print('.'); + Serial.println(version.fwMinorWiFi); + + Serial.print(F("[LR1110] GNSS firmware: ")); + Serial.print(version.fwGNSS); + Serial.print('.'); + Serial.println(version.almanacGNSS); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + + } + +} + +void loop() { + +} diff --git a/keywords.txt b/keywords.txt index fac7aa1ced..c31d269aaf 100644 --- a/keywords.txt +++ b/keywords.txt @@ -91,10 +91,11 @@ AS923 KEYWORD1 KR920 KEYWORD1 IN865 KEYWORD1 -# LR11x0 scan results +# LR11x0 structures LR11x0WifiResult_t KEYWORD1 LR11x0WifiResultFull_t KEYWORD1 LR11x0WifiResultExtended_t KEYWORD1 +LR11x0VersionInfo_t KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -254,6 +255,8 @@ getWifiScanResult KEYWORD2 wifiScan KEYWORD2 setWiFiScanAction KEYWORD2 clearWiFiScanAction KEYWORD2 +getVersionInfo KEYWORD2 +updateFirmware KEYWORD2 # RTTY idle KEYWORD2 @@ -459,3 +462,17 @@ RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 RADIOLIB_LORAWAN_NO_DOWNLINK LITERAL1 + +RADIOLIB_LR1110_FIRMWARE_IN_RAM LITERAL1 +RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LITERAL1 +RADIOLIB_LR1110_FIRMWARE_0303 LITERAL1 +RADIOLIB_LR1110_FIRMWARE_0304 LITERAL1 +RADIOLIB_LR1110_FIRMWARE_0305 LITERAL1 +RADIOLIB_LR1110_FIRMWARE_0306 LITERAL1 +RADIOLIB_LR1110_FIRMWARE_0307 LITERAL1 +RADIOLIB_LR1110_FIRMWARE_0401 LITERAL1 +RADIOLIB_LR1120_FIRMWARE_0101 LITERAL1 +RADIOLIB_LR1120_FIRMWARE_0102 LITERAL1 +RADIOLIB_LR1120_FIRMWARE_0201 LITERAL1 +RADIOLIB_LR1121_FIRMWARE_0102 LITERAL1 +RADIOLIB_LR1121_FIRMWARE_0103 LITERAL1 diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index ceb11c6c91..75cd360b08 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -489,7 +489,7 @@ uint32_t LR11x0::getIrqStatus() { // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes uint8_t buff[6] = { 0 }; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; - mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; return(irq); @@ -1546,6 +1546,78 @@ int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_ return(getWifiScanResultsCount(count)); } +int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) { + if(!info) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + int16_t state = this->getVersion(&info->hardware, &info->device, &info->fwMajor, &info->fwMinor); + RADIOLIB_ASSERT(state); + state = this->wifiReadVersion(&info->fwMajorWiFi, &info->fwMinorWiFi); + RADIOLIB_ASSERT(state); + return(this->gnssReadVersion(&info->fwGNSS, &info->almanacGNSS)); +} + +int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolatile) { + if(!image) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + // put the device to bootloader mode + int16_t state = this->reboot(true); + RADIOLIB_ASSERT(state); + this->mod->hal->delay(500); + + // check we're in bootloader + uint8_t device = 0xFF; + state = this->getVersion(NULL, &device, NULL, NULL); + RADIOLIB_ASSERT(state); + if(device != RADIOLIB_LR11X0_DEVICE_BOOT) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to put device to bootloader mode, %02x != %02x", device, RADIOLIB_LR11X0_DEVICE_BOOT); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + + // erase the image + state = this->bootEraseFlash(); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low + RadioLibTime_t start = this->mod->hal->millis(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start >= 3000) { + RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after erase!"); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } + } + + // upload the new image + const size_t maxLen = 64; + size_t rem = size % maxLen; + size_t numWrites = (rem == 0) ? (size / maxLen) : ((size / maxLen) + 1); + RADIOLIB_DEBUG_BASIC_PRINTLN("Writing image in %lu chunks, last chunk size is %lu words", (unsigned long)numWrites, (unsigned long)rem); + for(size_t i = 0; i < numWrites; i ++) { + uint32_t offset = i * maxLen; + uint32_t len = (i == (numWrites - 1)) ? rem : maxLen; + RADIOLIB_DEBUG_BASIC_PRINTLN("Writing chunk %d at offset %08lx (%u words)", (int)i, (unsigned long)offset, (unsigned int)len); + this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), (uint32_t*)&image[offset], len, nonvolatile); + } + + // kick the device from bootloader + state = this->reset(); + RADIOLIB_ASSERT(state); + + // verify we are no longer in bootloader + state = this->getVersion(NULL, &device, NULL, NULL); + RADIOLIB_ASSERT(state); + if(device == RADIOLIB_LR11X0_DEVICE_BOOT) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to kick device from bootloader mode, %02x == %02x", device, RADIOLIB_LR11X0_DEVICE_BOOT); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + + return(state); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -1601,7 +1673,7 @@ int16_t LR11x0::SPIcheckStatus(Module* mod) { // it also seems to ignore the actual command, and just sending in bunch of NOPs will work uint8_t buff[6] = { 0 }; mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; - int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; RADIOLIB_ASSERT(state); return(LR11x0::SPIparseStatus(buff[0])); @@ -1637,21 +1709,16 @@ bool LR11x0::findChip(uint8_t ver) { reset(); // read the version - uint8_t device = 0xFF; - uint8_t major = 0xFF; - uint8_t minor = 0xFF; - if((this->getVersion(NULL, &device, &major, &minor) == RADIOLIB_ERR_NONE) && (device == ver)) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", device); - RADIOLIB_DEBUG_BASIC_PRINTLN("Transceiver FW version: %d.%d", (int)major, (int)minor); - #if RADIOLIB_DEBUG_BASIC - this->wifiReadVersion(&major, &minor); - RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)major, (int)minor); - this->gnssReadVersion(&major, &minor); - RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)major, (int)minor); - #endif + LR11x0VersionInfo_t info = { 0 }; + int16_t state = getVersionInfo(&info); + if((state == RADIOLIB_ERR_NONE) && (info.device == ver)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device); + RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor); + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi); + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS); flagFound = true; } else { - RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, device); + RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, info.device); RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: 0x%02x", ver); this->mod->hal->delay(10); i++; @@ -1781,7 +1848,7 @@ int16_t LR11x0::writeRegMem32(uint32_t addr, uint32_t* data, size_t len) { if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len)); + return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); } int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { @@ -1874,7 +1941,7 @@ int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { // the status check command doesn't return status in the same place as other read commands // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used // it also seems to ignore the actual command, and just sending in bunch of NOPs will work - int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); // pass the replies if(stat1) { *stat1 = buff[0]; } @@ -1959,8 +2026,8 @@ int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) { } int16_t LR11x0::reboot(bool stay) { - uint8_t buff[1] = { (uint8_t)stay }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_REBOOT, true, buff, sizeof(buff))); + uint8_t buff[1] = { (uint8_t)(stay*3) }; + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false)); } int16_t LR11x0::getVbat(float* vbat) { @@ -2745,7 +2812,7 @@ int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, u // read the result - this requires some magic bytes first, that's why LR11x0::SPIcommand cannot be used uint8_t cmd_buff[3] = { 0x00, 0x02, 0x18 }; uint8_t buff[9] = { 0 }; - state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT); + state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true); // pass the replies if(fwVersion) { *fwVersion = buff[0]; } @@ -3207,13 +3274,12 @@ int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) { return(state); } -int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len) { +int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - - return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len)); + return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); } int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { @@ -3227,12 +3293,20 @@ int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { } int16_t LR11x0::bootEraseFlash(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, true, NULL, 0)); + // erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds + RadioLibTime_t timeout = this->mod->spiConfig.timeout; + this->mod->spiConfig.timeout = 3000; + int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false); + this->mod->spiConfig.timeout = timeout; + return(state); } -int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len) { - RADIOLIB_CHECK_RANGE(len, 1, 32, RADIOLIB_ERR_SPI_CMD_INVALID); - return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len)); +int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); } int16_t LR11x0::bootReboot(bool stay) { @@ -3261,7 +3335,7 @@ int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } -int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len) { +int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { // build buffers - later we need to ensure endians are correct, // so there is probably no way to do this without copying buffers and iterating size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); @@ -3279,13 +3353,19 @@ int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d // convert endians for(size_t i = 0; i < len; i++) { - dataBuff[4 + i] = (uint8_t)((data[i] >> 24) & 0xFF); - dataBuff[5 + i] = (uint8_t)((data[i] >> 16) & 0xFF); - dataBuff[6 + i] = (uint8_t)((data[i] >> 8) & 0xFF); - dataBuff[7 + i] = (uint8_t)(data[i] & 0xFF); + uint32_t bin = 0; + if(nonvolatile) { + bin = RADIOLIB_NONVOLATILE_READ_DWORD(data + i); + } else { + bin = data[i]; + } + dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF); + dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF); + dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF); + dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); } - int16_t state = this->SPIcommand(cmd, true, dataBuff, buffLen); + int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 3e3df571d1..6db2f78302 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -661,6 +661,36 @@ struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t { bool fcsCheckOk; }; +/*! + \struct LR11x0VersionInfo_t + \brief Structure to report information about versions of the LR11x0 hardware and firmware. +*/ +struct LR11x0VersionInfo_t { + /*! \brief Hardware revision. */ + uint8_t hardware; + + /*! \brief Which device this is - one of RADIOLIB_LR11X0_DEVICE_* macros. */ + uint8_t device; + + /*! \brief Major revision of the base firmware. */ + uint8_t fwMajor; + + /*! \brief Minor revision of the base firmware. */ + uint8_t fwMinor; + + /*! \brief Major revision of the WiFi firmware. */ + uint8_t fwMajorWiFi; + + /*! \brief Minor revision of the WiFi firmware. */ + uint8_t fwMinorWiFi; + + /*! \brief Revision of the GNSS firmware. */ + uint8_t fwGNSS; + + /*! \brief Almanac revision of the GNSS firmware. */ + uint8_t almanacGNSS; +}; + /*! \class LR11x0 \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. @@ -1289,7 +1319,26 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode = RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, uint16_t chanMask = RADIOLIB_LR11X0_WIFI_ALL_CHANNELS, uint8_t numScans = 16, uint16_t timeout = 100); - + + /*! + \brief Retrieve LR11x0 hardware, device and firmware version information. + \param info Pointer to LR11x0VersionInfo_t structure to populate. + \returns \ref status_codes + */ + int16_t getVersionInfo(LR11x0VersionInfo_t* info); + + /*! + \brief Method to upload new firmware image to the device. + The device will be automatically erased, a new firmware will be uploaded, + written to flash and executed. + \param image Pointer to the image to upload. + \param size Size of the image in 32-bit words. + \param nonvolatile Set to true when the image is saved in non-volatile memory of the host processor, + or to false when the patch is in its RAM. Defaults to true. + \returns \ref status_codes + */ + int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -1445,11 +1494,11 @@ class LR11x0: public PhysicalLayer { int16_t cryptoRestoreFromFlash(void); int16_t cryptoSetParam(uint8_t id, uint32_t value); int16_t cryptoGetParam(uint8_t id, uint32_t* value); - int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len); + int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile); int16_t cryptoCheckEncryptedFirmwareImageResult(bool* result); int16_t bootEraseFlash(void); - int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len); + int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile); int16_t bootReboot(bool stay); int16_t bootGetPin(uint8_t* pin); int16_t bootGetChipEui(uint8_t* eui); @@ -1499,7 +1548,7 @@ class LR11x0: public PhysicalLayer { // common methods to avoid some copy-paste int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); - int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len); + int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); }; diff --git a/src/modules/LR11x0/LR11x0_firmware.h b/src/modules/LR11x0/LR11x0_firmware.h new file mode 100644 index 0000000000..4fb6774172 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_firmware.h @@ -0,0 +1,38 @@ +#if !defined(_RADIOLIB_LR11X0_FIRMWARE_H) +#define _RADIOLIB_LR11X0_FIRMWARE_H + +#if defined(RADIOLIB_LR1110_FIRMWARE_IN_RAM) + #define RADIOLIB_LR1110_FIRMWARE_ATTR +#else + #define RADIOLIB_LR1110_FIRMWARE_ATTR RADIOLIB_NONVOLATILE +#endif + +#define RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LR11XX_FIRMWARE_IMAGE_SIZE + +#if defined(RADIOLIB_LR1110_FIRMWARE_0303) + #include "firmware/lr1110_transceiver_0303.h" +#elif defined(RADIOLIB_LR1110_FIRMWARE_0304) + #include "firmware/lr1110_transceiver_0304.h" +#elif defined(RADIOLIB_LR1110_FIRMWARE_0305) + #include "firmware/lr1110_transceiver_0305.h" +#elif defined(RADIOLIB_LR1110_FIRMWARE_0306) + #include "firmware/lr1110_transceiver_0306.h" +#elif defined(RADIOLIB_LR1110_FIRMWARE_0307) + #include "firmware/lr1110_transceiver_0307.h" +#elif defined(RADIOLIB_LR1110_FIRMWARE_0401) + #include "firmware/lr1110_transceiver_0401.h" +#elif defined(RADIOLIB_LR1120_FIRMWARE_0101) + #include "firmware/lr1120_transceiver_0101.h" +#elif defined(RADIOLIB_LR1120_FIRMWARE_0102) + #include "firmware/lr1120_transceiver_0102.h" +#elif defined(RADIOLIB_LR1120_FIRMWARE_0201) + #include "firmware/lr1120_transceiver_0201.h" +#elif defined(RADIOLIB_LR1121_FIRMWARE_0102) + #include "firmware/lr1121_transceiver_0102.h" +#elif defined(RADIOLIB_LR1121_FIRMWARE_0103) + #include "firmware/lr1121_transceiver_0103.h" +#else + #error "No LR11x0 firmware image selected!" +#endif + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0303.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0303.h new file mode 100644 index 0000000000..51d364bdc3 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0303.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1110_trx_0303.h + * + * \brief Firmware transceiver version 0x0303 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0303 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0xa2f1e792, 0xec60b0d2, 0x2f4c79bd, 0xb59d7a8c, 0x14d3101c, 0xa9d3df74, 0x905037d5, 0x97ae994d, 0xd913951e, + 0x8b5b5d8f, 0x392ea1b8, 0x8c0038dd, 0xf6ccdade, 0x12d2a72e, 0xf8c1dfe0, 0xe8a1fa5d, 0x041f905d, 0x691b6419, + 0x4a6e504e, 0xd3583f73, 0xe924bb66, 0x0106a58a, 0x2df86736, 0x1a7ecd4f, 0x77cff9c4, 0xabd782fe, 0x87bdc61a, + 0x855e3f53, 0x0e4c0542, 0xb4e5e5da, 0xd5e5a0eb, 0xaf8bbada, 0xf7f0dc56, 0x77ee0752, 0x1e408966, 0x37fe4da4, + 0x6529ff49, 0x5a8b745e, 0x6ed5a98a, 0xa51bcb8b, 0xab1e3acb, 0x44411646, 0x5170e839, 0x4402f918, 0xebb435cb, + 0xe5e86e2d, 0x1cd15086, 0xc6bf5f6c, 0xd163b723, 0x1e1d180d, 0xc490c510, 0xb411c807, 0x92718488, 0x7a5af3d6, + 0x99dab430, 0x2451e112, 0x992b873c, 0xf86ba568, 0x87874e92, 0xd1fd0ee6, 0x87aaf637, 0xee769161, 0xa8b2c6bb, + 0xbc41b12e, 0xe77b4041, 0x8b90dc5f, 0x75604d6a, 0x27672234, 0xebca0f92, 0xffe7e0a4, 0x081689ea, 0xd94a0100, + 0xb1661b44, 0x713c3199, 0xb961ae43, 0x4c1649cd, 0x57158dd9, 0x1a5e14a0, 0x03aa37a4, 0x1c9320ae, 0x0e597604, + 0x3ab23f87, 0x74749a11, 0x302cf4ba, 0x01d70ca3, 0xc426b7ba, 0x6e23598c, 0x1bfeb529, 0x3f2b9923, 0x02e31996, + 0x5f57598e, 0x9f4d54c9, 0xea2da83c, 0xc058081e, 0xed8443db, 0x66bb9356, 0x1c4a1f66, 0xa4ba1024, 0x65b4f352, + 0x867d2825, 0x421a6dbd, 0xf777a43c, 0x3f01c297, 0xa47ada0d, 0xa96baa1d, 0xbb98a5b1, 0x69488492, 0xe64e5105, + 0x7672bdec, 0xd23b2021, 0x3d017425, 0x9086e3ad, 0x67067687, 0xd9cdc631, 0x6a09da82, 0x8809f009, 0x0509105c, + 0x556b49dd, 0x86f47e36, 0x8708909b, 0xdc41cdcc, 0x531bab4f, 0xda055785, 0x64c3451b, 0x5f9e92ff, 0x32ae8baa, + 0x6307b2f8, 0xd0c7d81c, 0xb8896315, 0xadba98f5, 0x0bc1d90b, 0x2812a198, 0x359cdf68, 0x6b08e306, 0x18ad958f, + 0xf2a7c034, 0xa283da35, 0x189136c9, 0xdcd11bba, 0xdcf8345f, 0x0adb9169, 0xc3d89b1c, 0xcf2867dc, 0x7aaaaf0b, + 0xb55d8313, 0x8dfd6628, 0x3f0a8606, 0x2d9fdd01, 0x213f2154, 0x2748dd80, 0x9c8a87c0, 0x680d23ee, 0xc1ff3a51, + 0x2e460adc, 0x3916cdb6, 0xcac3b836, 0x7fe6e1b1, 0xb587d967, 0xee60e14f, 0x90706a05, 0x679c2c50, 0x85f03b65, + 0xb165dace, 0x234c25db, 0xc16c6eeb, 0x484047bc, 0x97ebb738, 0x395e9810, 0x8de806c5, 0xeedf7ca9, 0x1186be82, + 0x39e3a52f, 0xe53307ce, 0x6b7ecea9, 0x443d9e12, 0xb925937e, 0xb8473fd3, 0x41c52a0e, 0x71746b5f, 0xd5f9242a, + 0x60c499a1, 0x41ceb271, 0xb4c50887, 0xedb26142, 0x100ee7da, 0xe8493d21, 0x9d309b3d, 0xd3ac3940, 0x48296648, + 0x59c6df5f, 0xe1b3518e, 0xea802d6d, 0xf7efbac7, 0x2ae8e3fd, 0x3294a6a9, 0xbe164598, 0x493c4318, 0xc857422e, + 0xa827a6f9, 0x74881043, 0x41fb973e, 0x7f63ea77, 0x60dd4ed3, 0xeba17bed, 0xd2da77df, 0x2843053e, 0xe5490c33, + 0x296323df, 0xbb3b2e02, 0xcaaf47fe, 0x1d35f86d, 0x94a70d35, 0xd950391f, 0x618cad1c, 0x65f18682, 0x4bf5cc19, + 0xcc4a36c0, 0x9abe293f, 0x14e81f17, 0x160b678f, 0xd96ee099, 0xa667d863, 0x60991af3, 0xab631bc5, 0x4e451e27, + 0xb915b5ca, 0xa1b13e0d, 0x6385ab5f, 0xe4d2e339, 0x3dac77ec, 0xadb4503c, 0xe78f3249, 0x3686d079, 0x644c71f0, + 0x37365a40, 0xf32bbb7b, 0xc6fefdcd, 0x4dc91a4a, 0x54fbe85f, 0x55874b98, 0x60860db7, 0x1852d70e, 0xbf00b768, + 0x8460786b, 0xf18ba25b, 0x1f63cc33, 0xeb4c757d, 0xfa4d6671, 0xd8f5c03a, 0x30a014b4, 0x06739683, 0x46dbc98f, + 0xba1680f2, 0x2da7d509, 0x7b318804, 0x966cf754, 0x5bc659ee, 0xdc0999d2, 0x83f449af, 0xa7780042, 0x3782fdb3, + 0x62f6cfcb, 0x56d9bde7, 0x8c377468, 0xafd3e898, 0xa8af131d, 0xaa963ece, 0x546f0513, 0xd79555e9, 0x3daa6657, + 0xa9557718, 0x023190ee, 0x933ff800, 0x250931a7, 0x805fe13a, 0xb87984ce, 0x7038ceeb, 0x5fb36274, 0x58a1d5e6, + 0x627d1774, 0x8f81bba6, 0xee91e486, 0x43aefbfb, 0x40aa75ca, 0x3aca62eb, 0x57f72b39, 0xb1940678, 0xc48204aa, + 0x4325edcf, 0xc263d027, 0xe612e727, 0x778ec9a3, 0x558e93e2, 0x988946d6, 0x2d7f3884, 0xf0d10321, 0x9691b540, + 0x1ab5f629, 0xb15ab0d2, 0xc8fb60db, 0xb0f750da, 0x4fdef436, 0x69b9b2ee, 0xb721c3f9, 0x1d8a17f4, 0x2e44f9c6, + 0xea1bb8ef, 0xdbf8592f, 0x1cf0d468, 0xf0b95000, 0xc26f7c6d, 0x5346fbbc, 0x53c7469a, 0x091b4a08, 0xf8e5b89c, + 0xcbca28ec, 0x37307795, 0x3760a805, 0x8b4e896e, 0x5fb6eb55, 0x7d2c01ee, 0x83e23c74, 0xb316bc13, 0x2c00dfe4, + 0x49976b6a, 0x90b96e29, 0xe5de00b2, 0x579e8a4b, 0x1f770a16, 0x51fafca0, 0x99b07f24, 0xd85e2dab, 0x66ab0e5d, + 0x96c65d2f, 0xd9a8e9c1, 0x19dbdd78, 0xfc2af39f, 0x7fa0e749, 0x08a8246d, 0xfcd080df, 0xf4441d95, 0x8041b5b0, + 0x9258f05e, 0xf02b0adf, 0xb4967124, 0x461c810e, 0x35dcf699, 0xf464514a, 0x328107a2, 0xa796f53c, 0xfb0ae68f, + 0x56943f59, 0x3a02ec6b, 0x96c6eee6, 0xbb559cdf, 0x50b90df4, 0x20d3959f, 0x28822ebf, 0xf86d91a0, 0xc1cf28c7, + 0xe6a1ffbd, 0xb3366f4e, 0x4d5ec7cf, 0x04bc54e7, 0xf859e978, 0x9c1dd120, 0x5ceadeb1, 0x84dd54c0, 0x6aee4aab, + 0xee3328d5, 0x28a37db2, 0x1deef60c, 0xb4c677ea, 0x9fb4e638, 0x9c92aaef, 0x4fdcd134, 0xe29bac24, 0x4b8544a4, + 0xa0c73cf8, 0x5de35226, 0xe3814947, 0x434c072f, 0x34db5374, 0xd3353ced, 0x5bf90db5, 0x1372925f, 0x4d27e036, + 0xa049c237, 0x3f2ba2f1, 0xaaa8e748, 0x9947917e, 0x4985aed8, 0x83063d21, 0xa8fbb1e4, 0xb0ca20fc, 0x6d012903, + 0x63fb24a6, 0xbd16810e, 0x4ca8cc50, 0x16b97b3c, 0x54283b9c, 0x90babd64, 0x5e2817df, 0x17bcb710, 0xa3ac19ee, + 0x0e0b6e11, 0x8a7ee2c5, 0x431cfe63, 0xdc663cc2, 0x5c447cb7, 0xdfd79899, 0x8b60290f, 0x5342a0b9, 0x90000c3c, + 0xd9e3326a, 0xb599c7fd, 0x0339b7be, 0x085c158c, 0x2b32e99c, 0x2c71ad59, 0xd01e9c39, 0x1bc138cf, 0x400e5a5f, + 0x517d214e, 0xc45efdc8, 0xdc24975d, 0xe69b3250, 0x9cf77a4d, 0xd282fa63, 0xa6435734, 0xf1c97fba, 0x8d51c565, + 0x166d537c, 0x40f56633, 0xc84b2bd7, 0x134a7757, 0xaebac233, 0x7fdb30fb, 0xb90d3d59, 0xb6b3e8f7, 0x4c0d99e2, + 0x378e1b12, 0x1c1635ab, 0x5c19b03b, 0x515802a0, 0xb287d03e, 0xb9ddd018, 0x27bfec8b, 0x5c8c6d11, 0x0aa97f00, + 0x8b1a72b4, 0x3f1c446a, 0x7174a89f, 0xaec6f96f, 0x28b32bd2, 0xe78646df, 0xb9bd9bd1, 0x74e4ce38, 0xabe71015, + 0xda63ccbe, 0xf9cf6c50, 0x00bf611e, 0xcafffbac, 0x7a70e955, 0xc708e848, 0xf4698d24, 0x37eaa2d4, 0x4d66a7a9, + 0xae3c8185, 0x88a877ba, 0xb909da07, 0x32073885, 0xf9678f20, 0xd0439d3e, 0xe0197406, 0x96f2f0a2, 0x6b9ba6f0, + 0x2fcbc60d, 0xedc09aab, 0xba5d1ccd, 0xd31a8375, 0x5a5328a1, 0x35497a07, 0x8803ff5f, 0x691db55e, 0x0d3b8227, + 0x882da1bf, 0x47e8dc4d, 0x9282cc05, 0xb4f9cda8, 0xe2870388, 0xb5473de4, 0xc55b2ec8, 0xbac29031, 0x14563dfe, + 0x9dd703d2, 0xae4bdab1, 0xda25f17b, 0xfc853822, 0xbd5c9e8f, 0xe710d41f, 0x1d04aee5, 0x1f70811f, 0x9c59a01b, + 0x5e72acc8, 0xfd017acf, 0xb9becbea, 0xcf69fe5e, 0xab00a63f, 0xe738f09f, 0xf12b2b40, 0xf6a0390f, 0x1a27ea5f, + 0x84128938, 0xdca1c746, 0x2005057c, 0x7898c98f, 0x012e165e, 0x36125c9f, 0x62ba3a0b, 0x39d0ad70, 0x1bec20c2, + 0xc3d4f7fb, 0x4b98890f, 0xd750773d, 0xdb6adf08, 0x040214c3, 0xa6d04ee2, 0x842e830f, 0xaf17794a, 0x51d77e5d, + 0x73d20062, 0xd0716f1c, 0x0813aff5, 0x3ef92c49, 0x0a27bade, 0xafa645a1, 0x03fac2b5, 0x8b77ed5f, 0x8c1af056, + 0xe3a408e3, 0xa9606728, 0xdadb8dba, 0x845940dd, 0xf6d425ac, 0x9856a762, 0x19d8c0a7, 0x16afa3d6, 0x99c62451, + 0x44318df2, 0xb4775c2d, 0xc43dd6c2, 0x21bcf6ba, 0x9507fbac, 0xf747cc40, 0x18d6ed0b, 0x63e12c70, 0xa30b11fc, + 0xa14f2c81, 0x8cef81e0, 0x5a6a742d, 0x4643386c, 0x4b2e149f, 0x7828b3b0, 0x7f3f99da, 0xff71a86d, 0xec9df92c, + 0x14d9fbd7, 0x93a17655, 0x12226db0, 0x2a4c9b15, 0x1a0cf06b, 0x9a9e30f5, 0xd286853e, 0x863624c2, 0x99f69fe4, + 0x309537c5, 0xcd25e09f, 0x4acabe15, 0x84b2a32f, 0x8e2dcae7, 0x15c1674f, 0x6eab9d68, 0x2cb7a63d, 0xe3d65116, + 0xd8a4d685, 0x8c51be74, 0x648b2280, 0x6c5e9071, 0xa068f562, 0x6238b396, 0x63378728, 0x8ed172d6, 0xecc187a6, + 0x4ae0e30d, 0x93084922, 0x5921d001, 0x35990ace, 0x09e8078f, 0x8f70135d, 0xd69ba1b2, 0x6a29bce1, 0x4ef3278a, + 0x467b9f4b, 0xc4b5a340, 0xd549c333, 0x550d5751, 0x152825b6, 0xaba86536, 0x3b64415c, 0x057155de, 0x9fcd9020, + 0xc9920a47, 0xbab4f1be, 0x1fef874f, 0x042ee14a, 0x4600f5b4, 0xbea97328, 0x218aed9b, 0x4868c720, 0xf4d2b6ab, + 0x52879602, 0xf1f02233, 0xebef8573, 0xdc3d732c, 0xeb43198f, 0xb4785f56, 0x252d8870, 0x2b805c75, 0xad535a01, + 0xecfa4107, 0xa54cc4a2, 0xd4be3a8c, 0xdaec7e39, 0x65f29d96, 0xc50c14c9, 0x9b65c211, 0xc3773a3f, 0xd125895b, + 0xbd4f2c9a, 0xb9ff346f, 0x7dba36ca, 0xd66623b8, 0x921bf995, 0xca6af719, 0xa1c7fe33, 0x90372e60, 0x730c092c, + 0x37b939f5, 0x881d7b9f, 0x3b61f8a9, 0x65906e0b, 0xb7a69f54, 0x82225062, 0x5c10feb7, 0xacd10957, 0x8254e65e, + 0xca9e0271, 0xda577e14, 0xbed2eb92, 0x56a1a9aa, 0x8ccbf50e, 0x9d6a025d, 0xb1e33c17, 0x2c2f98d4, 0x0df7af83, + 0x39a5ce42, 0xd8542d61, 0x560c3f83, 0x103f94ec, 0x1f5aa708, 0x58a0e811, 0x6e67a9d2, 0xba57b48c, 0xf6b2c93f, + 0xbebe883c, 0x6c758662, 0xcda51ad7, 0x5e0a6c87, 0x8e037d4c, 0xeccbaa77, 0x8dcff88d, 0x66be71c7, 0x07808e96, + 0x7ac232e5, 0x18e1eb19, 0x96f3a9ef, 0xbc41bbdd, 0x7e778e56, 0x20895e51, 0x77b3e537, 0x7c41ae57, 0x6064d069, + 0x7fda9b9f, 0x0b110ee6, 0xef043ad9, 0xda973990, 0xb138574d, 0xd3c5bc47, 0x1102a74b, 0xb1da5e22, 0xdd12a798, + 0xf3d676d5, 0x697846b3, 0x2683b8b8, 0x9938c369, 0x187ffbd6, 0x182eb593, 0xe15ab1ea, 0x2c3c12f4, 0x21f4c858, + 0x02247657, 0xb0843bf8, 0x91ac8c28, 0x6e234042, 0x1ae9de42, 0x7938d39e, 0x750db8d0, 0x3acaf6c0, 0xb3fe07a8, + 0xc4016e09, 0x5365de0f, 0x32b780a8, 0x65e95ee9, 0xa4799e77, 0x485fce1b, 0x54be267b, 0x3bed848c, 0x23a50965, + 0xe0fb0f42, 0x1fa41e98, 0x4bc5bce3, 0x0462baa2, 0x588a2217, 0xb2f59782, 0x50226051, 0x0b702ecf, 0xcdf08e19, + 0x013c6359, 0xa2494009, 0x9b749b49, 0x7c9e8be8, 0x91b1df26, 0x2316fde2, 0xb477adf3, 0x932b0a6b, 0x5a6f42ff, + 0x8962bc78, 0xe0b61013, 0x285e3b70, 0xa219e525, 0x0bee89f0, 0x1a1c8d38, 0x2d4b3ee4, 0xff34df5b, 0xfa20924c, + 0xbd1c97a8, 0x4e689121, 0x16623fdb, 0x20d96de1, 0xe3028cf4, 0x0790b2bf, 0xf362c923, 0xba7bf4cc, 0xe33315a4, + 0x648f685e, 0xfa9a9dbe, 0x321314f5, 0x2ab2471f, 0xf35a0f33, 0xaaffaa25, 0x7b1e035f, 0x2fc178c4, 0xd481f3c4, + 0xa2ab96de, 0xe35e7f74, 0x2106cb58, 0x1c4bf144, 0x817c5455, 0x644f3767, 0xd2c8691a, 0x3722c468, 0x7be39a11, + 0xd332aff4, 0x414d63f7, 0xe8db1e0c, 0x6fb91738, 0x466dacd8, 0x4345d204, 0x8286dea9, 0xac9c54e1, 0x7e80960f, + 0x76d66ec4, 0x38394e0d, 0xaba2a3e3, 0x39426ce0, 0x9106cdab, 0xb3297fa6, 0xe94d15c3, 0x976249ca, 0x1919d3d1, + 0x58c9e15c, 0x21e7e24a, 0xc321a393, 0xb426edbf, 0x81d22f8f, 0x3f9bae0e, 0x79b31e1d, 0x9727fb32, 0x9aeab228, + 0x1f08ecda, 0x41651041, 0x89a17bfa, 0xd11b99f1, 0x54639a5a, 0x862c8f03, 0xebbdd4a4, 0x38a6ef15, 0x723ab840, + 0xa848eab5, 0x732c5154, 0x848e0c75, 0x7a1b0539, 0x4b0560a7, 0x9f344b1a, 0x8feb706d, 0xdfccb24a, 0xb84fc88b, + 0xdd3f143e, 0x7e1e966e, 0x45d1c72c, 0x11c4a3e5, 0x7f54c682, 0x3c45eb30, 0xd05ce6ea, 0x180f6ad7, 0x973a83ed, + 0x1426af5b, 0xda0f801b, 0xa417698d, 0x58713c70, 0x61bc379d, 0x2554fbc8, 0x2b0e650f, 0xd2136a40, 0x1170463e, + 0x09125786, 0xfeba0eb1, 0xba0bc6ed, 0xabc9fd97, 0x3592760d, 0x7e232d88, 0xd03c31d2, 0x1ba223d4, 0x472d8ea0, + 0x0b02d0a6, 0x8eb1d79f, 0x0dc626f7, 0xd2dfd6d9, 0x3c9ac664, 0xe8903d41, 0x31a55152, 0x74f0695e, 0x62cbb4e8, + 0x9c82720f, 0x309dedf3, 0x5c9c033f, 0x4cd0a6b2, 0xb30a0c03, 0x2f6d2389, 0x0b41ea71, 0x5378e51e, 0x7e5165b9, + 0x782eec63, 0xf33e583f, 0x47b94a13, 0xc961ada1, 0xaedb1971, 0xaee5c378, 0x40cc7436, 0x2ddf71d8, 0xfd4606ca, + 0x95b95655, 0xfcc42cbc, 0x2c432fdb, 0xa937b5e1, 0x684826ae, 0xecc10be0, 0x05897355, 0x67c05aa2, 0x41873e67, + 0x24a8e59f, 0xfdb260d2, 0xe6636639, 0xfa12024e, 0xc5128ffb, 0x6c1661ef, 0xa104455a, 0x376be893, 0xff926679, + 0xca8bfca9, 0xc5fef541, 0xbdc19261, 0x67667f26, 0xd557ee49, 0xb62ef3c6, 0xf91b7bc2, 0x7a5c2688, 0xaf5858df, + 0xb9fbaa48, 0xd6621cb4, 0xe5ab4266, 0x7499e3c3, 0x60de331b, 0x6c3c3935, 0x6fbbd175, 0x9e8a7ed7, 0xa87358c7, + 0x5f4413be, 0x9cbc0ff9, 0xf5957734, 0x813b4f0f, 0xdee7e2a8, 0xfcdc3da2, 0xb5535289, 0x0e1e2f8b, 0xd588e676, + 0x48f752d6, 0xfd2bd66e, 0xfd7ddbe5, 0xa9eeabba, 0x7b856dde, 0xd79639b3, 0xf6dce629, 0xa0fd1726, 0xd8d87794, + 0xfb7ee64c, 0x93df1eb6, 0x8d817c6c, 0x9d1e2fef, 0x8d2c4138, 0xc635043b, 0x47d2bd28, 0x66f165fe, 0xd1432b66, + 0xc07ba706, 0x9624e2db, 0xe7ecfabd, 0xc3329a49, 0xc39436de, 0x1f9a8cba, 0x31dcf044, 0x8dfaa8ed, 0x2422d925, + 0x8f3059b1, 0xaea002ab, 0x849e789a, 0x89f8caf8, 0x425e246a, 0xe66b35f2, 0x5e6064e7, 0xe7714077, 0xa3d94fc6, + 0xde312048, 0x40cf40ec, 0x3a1bc47e, 0xb98c0ea8, 0x7140a94d, 0xa9e30d93, 0x2e4a2c7b, 0x13907282, 0x5013f8e9, + 0x7ee127f5, 0x432646fc, 0xe30f496c, 0x014e23f8, 0xef1c2401, 0x9ddba66c, 0x45e07d2f, 0xab207e28, 0xd801dc7e, + 0xdeb46a04, 0x54d0b939, 0x058e5e9c, 0x2a9e61ed, 0x30d3d1a2, 0x5d48af74, 0xeffe1f32, 0x20e99f4c, 0x37f9ec73, + 0xf810c788, 0x979a3655, 0x6bcf86d6, 0xb900a5a7, 0x5a1e7842, 0x7bd03152, 0xaa4c57ca, 0xe965e6d4, 0xd0c25608, + 0x73ebbf19, 0x6d425f22, 0x87cb65aa, 0x424464be, 0xfed8cae0, 0xae36432f, 0x572e37b2, 0x18100f25, 0xdb79eba6, + 0x8ae9c958, 0xeee84ed3, 0x011befaf, 0x18f657a6, 0x3afd3b13, 0xf44bef1b, 0x3224608b, 0xcd51ac7c, 0x0e2d6fb3, + 0xbdb40b8f, 0xd66230bd, 0xeff8042d, 0xb06dfbaf, 0x645ac5e1, 0x48ea08e1, 0x9fd0a520, 0xea58137d, 0xca8ac349, + 0xa9b00056, 0xd36c9597, 0xa4723c71, 0xefb80c5e, 0x6f0c425d, 0x89429338, 0x534f8ee6, 0xae9a8a86, 0x5782d887, + 0xc03914cf, 0xcf0c3e16, 0x82dc02bc, 0xfdab79b8, 0xa9439a47, 0xbfc00927, 0x8c522ff7, 0x141e3a76, 0x3e9bbb63, + 0x533196ae, 0x340e502f, 0xdc7eefa1, 0x1f316202, 0x9280be2a, 0x86d6ff0b, 0xa3019495, 0x5b8a6456, 0xaf900176, + 0xf8a009fc, 0x2ba036c7, 0x3b945055, 0xafa013ec, 0xa7b25241, 0x412a736b, 0x58e31837, 0x385d564b, 0xcdaa6631, + 0xe9e62ccf, 0xbd99ff5e, 0x29ae9dfc, 0x9b79a0b8, 0x99c97ee5, 0xed519b0a, 0x8c19da42, 0xb0773c31, 0x7f523b4e, + 0x75df043d, 0xbe1966d3, 0x4f77c64c, 0x37a74116, 0xe49bbd0b, 0xef070473, 0x43f937c4, 0xf5fcd96c, 0x1248529d, + 0xfec394b7, 0x5d160442, 0x3aaf62de, 0x2ac48e9a, 0x2c57aa74, 0x07ed7612, 0x55679f0e, 0x732a72af, 0x088d7387, + 0x0842f81f, 0xa15c88e8, 0xa15677e6, 0x9dee44ba, 0xd7da772c, 0xc2b15ef1, 0x1b074264, 0x2e66eeb3, 0xeb103ab4, + 0xe5f62909, 0x0d07bec6, 0xabb703d3, 0xc014ca62, 0x315fad6e, 0x95cb798a, 0xb1f58cd1, 0x5a9c713a, 0x6f42fbb3, + 0x4b863b0d, 0xac4ae778, 0xb4782c25, 0xf854a75f, 0xaaec11f4, 0x2ba54970, 0xc5527e7d, 0xa8c8415b, 0x048005c3, + 0x009320bf, 0x964da10b, 0x6f134af5, 0x33d8ef13, 0x78501630, 0xbf9a21ff, 0xd35f8795, 0x04257ac6, 0x04f41a0b, + 0x6fbec5cf, 0x075defd4, 0x0b2d515c, 0x8a37ac7b, 0x2c8c065f, 0x32419392, 0x56fc167a, 0x6728234c, 0x5a849315, + 0xa529b0b1, 0xefe3bdf5, 0xccaeaab5, 0x903692a9, 0x3e330c37, 0x5d4605f1, 0x8cc8d570, 0x7960f0fe, 0x71b94b07, + 0x943e2b69, 0x5cb15358, 0x1d27e8ae, 0x1d7c4f36, 0xbc4ddb72, 0x275287b8, 0x781c489e, 0xc033fbe3, 0x33539d0d, + 0xcf5f6a48, 0xb1e42e6f, 0x1c24ee7a, 0x5f4dc940, 0x9d2d0a75, 0x51b659e2, 0xf7f4be59, 0xe88fe314, 0xc060b6da, + 0x09643f88, 0x3b9efd16, 0x7e6a5983, 0xe1ebafd7, 0xafc5de1e, 0x6b4cf4ee, 0xbf9b1910, 0x79734e49, 0x9cb111b4, + 0xab873347, 0xd9894805, 0xf88b2502, 0x6e967521, 0x8a8ff232, 0x64f36df1, 0x159f185f, 0x08c23b9a, 0xeeba32ed, + 0xd66c91f3, 0xe537a8b5, 0x2935d73f, 0xb56abaa2, 0xc1ea0978, 0xeb0c44d1, 0x047db087, 0x54edcccb, 0xfc92b879, + 0x87921886, 0xa2119edb, 0xc01e0743, 0x2c6d7084, 0x9eb84499, 0x581293e6, 0x7270fcd2, 0xedd67e5b, 0x9e6f2f6a, + 0x045aeaf1, 0x6c238832, 0x903fb176, 0x78f79933, 0x4a148a13, 0x888d05b9, 0xa7728735, 0x5f7b466d, 0x64876361, + 0xd4e6c845, 0x84c60362, 0x8ec594ab, 0x60004289, 0x2d677825, 0x7801b995, 0x26eb1d55, 0x90a8313f, 0x32001fa3, + 0x5b41aa5f, 0x8bf7ba7a, 0x3da16bb5, 0x545eca09, 0xb323e4e3, 0xf9101860, 0x9f0ecfe4, 0xe323e5de, 0x866b13a4, + 0x0a0f83b1, 0x26c4942a, 0x15fa1450, 0x45012b46, 0xe90d9692, 0xa6146bc1, 0x740ac79c, 0xd4e1e53d, 0x647db2ca, + 0xb1c11b93, 0x6a6d1e15, 0x093b8e8f, 0x08e21ad4, 0xedc5a193, 0x36afa420, 0xd2f1ac14, 0x06f5133c, 0xd2309bbe, + 0xe0edf1d5, 0x3c2ab125, 0xaff63cb6, 0x219c4731, 0x3377b176, 0x3c296ec3, 0xf5a5c42a, 0xf5730139, 0x9253cf91, + 0xbc6949d5, 0xbfac48c6, 0x837f0d56, 0x2f34589d, 0x19e31916, 0x92224e1c, 0xe38a5d22, 0x5f2cc6a4, 0x9bd63d80, + 0xf075bf21, 0x93799285, 0x0fd4a5bd, 0x5538e02f, 0xcfa5ecab, 0xfcc68150, 0xb3c88099, 0xc939c172, 0x8180eb02, + 0xaaa994c2, 0x24a1595f, 0x9786eb11, 0xe38cb162, 0x0953be6f, 0xdd251980, 0x45e5022e, 0xba09e07e, 0xdf184402, + 0xa58b278c, 0xd93eb372, 0x308dab5b, 0x7e7c5658, 0x087a8449, 0xeac949fb, 0x6464a6ab, 0xdc5f0900, 0x209528ff, + 0x1907f93f, 0xd9698186, 0x210f4c8b, 0x2ae546c1, 0xf1dc61ae, 0x0af1c35a, 0x16865818, 0xd465b647, 0xa0f132de, + 0x4cf66c18, 0xcace7a93, 0x264a5e25, 0x4ec701b0, 0xe9f99cca, 0x7692ed60, 0x6634fee8, 0xf1c0be9e, 0xdee92136, + 0xff942101, 0xd8fe2af6, 0x0fb2ad96, 0x19ef262c, 0x88db9fdf, 0x9aec23cd, 0x11b6ba42, 0x12ec154c, 0x47974ecf, + 0xff2d9318, 0x206083ef, 0xdfa2f031, 0xdaa5540e, 0x7b556a92, 0x9375f5fd, 0xe9621b54, 0x6905ba0b, 0xc55f61c1, + 0x282fad42, 0x40e40efb, 0x3008680e, 0x85d9bf69, 0xeec78269, 0x4a94ac05, 0x0d808266, 0xe741c63e, 0xaab1ce8b, + 0xe4fae24e, 0xeef20bb3, 0x76a38e2c, 0x310b93e6, 0x1a511eb7, 0x2af0fb36, 0xc7112991, 0x5a86181e, 0x41f0fd0a, + 0x5c8681dd, 0xa0cb685e, 0x8a29cad3, 0x02cfbbef, 0x90bad80b, 0xab19eb26, 0xf742ce43, 0xdcaff573, 0x927d94c9, + 0x9bc84614, 0x215fa96d, 0xb685f930, 0xf0a47be9, 0xd5772b06, 0xba8fb609, 0xf292c903, 0xf5f7593c, 0xf1fae6d7, + 0xd7addf63, 0x7f13355b, 0x363e3b00, 0x30d08db2, 0x7f6d4f48, 0x93ca97fc, 0xed1c02c3, 0x24968aaf, 0xa7944675, + 0x05fd1936, 0x3e4713d9, 0x70854af1, 0xb772cd43, 0x4c9b4144, 0x244cf6ff, 0xb5472db5, 0x4463be12, 0x88b16c87, + 0x0d36feaf, 0x150daa23, 0x4c0b9a4d, 0x2355a8a3, 0x953b41c3, 0x223a67af, 0xfe08b13b, 0x85562b87, 0x24e51d3f, + 0xb87ceaf8, 0x5d315db6, 0xb8deb242, 0x8924677f, 0xb9b564bf, 0xec6c3942, 0xa80cb78b, 0x369c6582, 0xc7b14885, + 0xc46b396a, 0x975d4177, 0xd70ae9df, 0x9b6cbc58, 0x6492f55e, 0x5addc511, 0xb389a968, 0x8befd359, 0xa0048754, + 0x20d7714f, 0xd0d41d24, 0xa72f52ac, 0x77070bd1, 0x6ad01fec, 0x0eaacbbd, 0x0ce184af, 0xdcd6838f, 0x079d9762, + 0x09337400, 0x1d1594c4, 0x6305e588, 0xe9b1cb3f, 0x608d5328, 0x8c594d93, 0x1a8dcfcd, 0x290d31a1, 0x34b3a646, + 0xc117e0c5, 0x7812d3cc, 0x970f4471, 0x46ec5336, 0x5abd2237, 0x6bd7cc35, 0xfced51fb, 0x75aba90a, 0xd77bb957, + 0x9dd9c239, 0x9a6d6625, 0x382adcee, 0x22339e7c, 0x81b2441e, 0x3311ae91, 0xacaaa8fb, 0x0c857457, 0xaa5a35fb, + 0x7be272ea, 0x27715efd, 0x86428950, 0x164ab8e9, 0xdc1c25df, 0x1b6f964c, 0xb9df18c2, 0x1534b47a, 0xecceadbd, + 0x8b10d8d2, 0x6c0ea503, 0xe069608d, 0xfe414764, 0x71e5013e, 0xdec5f40a, 0xfdcf7e43, 0xe18bb49b, 0x56602acd, + 0xbff2df09, 0xadf73781, 0x9a5c6d2f, 0x2d3af6c6, 0x0694cb08, 0xd3d6153b, 0x7fc57981, 0xefa081db, 0x3a1554d1, + 0xef733e2a, 0x45c09d8c, 0xce08ec5c, 0x4de06306, 0x21754e73, 0xa261dddf, 0xee5089cd, 0x3876ddac, 0x9e67bc3a, + 0x2549e3ce, 0x8923ce19, 0x57543510, 0x76fa65a6, 0xfa953921, 0x86999edd, 0xd7debb4d, 0x050c9540, 0xf8d6cda1, + 0x99d00c4f, 0x0d44b312, 0x2f753b88, 0xe6771dd2, 0xec56c663, 0xc86913ca, 0x094151b4, 0x77409dd2, 0xb0ed2ce8, + 0xae96f502, 0xb8ccba09, 0x8e5399dd, 0x25eabc9d, 0x92446123, 0xae9b7b3c, 0x7dd8133d, 0x57edbf0f, 0xca7861f9, + 0xd07dc6ad, 0xcbbacb59, 0x3131f2de, 0x457e439f, 0x47610877, 0x1b5c611a, 0xef2a14fc, 0x5ba2e959, 0xe128d641, + 0xf5093cc1, 0x26b52e30, 0xa2954a82, 0x35449415, 0x4b678280, 0xd79a006c, 0xb6e9398c, 0x9cd9c7cc, 0xe382c4ee, + 0xe9509598, 0x1a94a773, 0x42194789, 0x6f9b1471, 0x57d95f7e, 0x036a26e6, 0x2c043278, 0x64e4b91a, 0x436b1dd3, + 0x492cdab1, 0x7178148b, 0x30ffeabe, 0x2cac4695, 0x556e05a2, 0x97e256e7, 0xf079adff, 0x0e6e88b0, 0xbbe7d6f6, + 0x34e839c8, 0xf179f8b0, 0x78d6120d, 0x4679d3df, 0xbab210ce, 0x173352d0, 0x4e632b91, 0x39d349d6, 0xce27c768, + 0x9413949f, 0x1f3e5b17, 0x451be77e, 0x2f0c053c, 0x4e493416, 0xa2bef0ee, 0xd835153c, 0xadb7fa6d, 0x38ad289f, + 0x7418703f, 0xbc4ac8df, 0x3d5cf2f4, 0xe62686dd, 0x73a9a47d, 0xceb7ac6d, 0x0bec3f8a, 0xf9efacc2, 0x03a080c7, + 0x3bf08c04, 0x77159fa5, 0xea920519, 0xd9ab4071, 0x27f1a005, 0xa9148b9e, 0x6848b1f4, 0x267a0069, 0x39aff125, + 0xe54207d1, 0xf2d99d42, 0x7ce54519, 0x7f757c97, 0x1e47e296, 0xca1d8a88, 0x83cf0aa6, 0x99bbc434, 0x41a1a9a4, + 0xba6b951e, 0x3783d11e, 0x85439d30, 0xabc6a63f, 0x8aabe5da, 0xfc04d4fb, 0x80c4a54a, 0xa25c5861, 0x75fafd6c, + 0x06db4e05, 0x7d5f94b9, 0x86cfab98, 0x2c3f05f7, 0x191ccbaf, 0xf8ff99b0, 0x36af8315, 0x4bf0150f, 0xd231fc1e, + 0x0615e14a, 0x9653d649, 0x04b8508d, 0x7df47fe6, 0x8670e9d3, 0x6508e546, 0xcf11c2a6, 0x9de9492d, 0xe329db52, + 0x25337710, 0xaf068def, 0x95f3ce83, 0xa0ee632e, 0x8d3b39af, 0x34e4a599, 0x03db446d, 0x42978dc8, 0x5add9961, + 0x1e0c5c43, 0xed94a85d, 0x2d2bdfe0, 0x4fba24a6, 0x3254e6e4, 0xeb396149, 0xd35c3b9b, 0xb1678bbb, 0x0113853f, + 0x81c9e644, 0x095420f8, 0x1c0a6028, 0xa39388d4, 0x47ffec13, 0x102ac5ac, 0xa0fe1a56, 0x6844f998, 0x3d31cf2e, + 0xbc6f60b6, 0xc75a0b84, 0x33d05a63, 0x4d44c0c6, 0x26caace6, 0xfdfccaff, 0x98c60d66, 0x2a2c3cea, 0xe2ac2618, + 0x87b39420, 0x8d3edb9c, 0x58ab1706, 0x2431a00c, 0xe3d69802, 0x12d9cb31, 0xceace8eb, 0xa31089ad, 0xa396971d, + 0x189ca147, 0x88acc598, 0x0c3fe7ec, 0x7cea41b7, 0xa9228195, 0xe6e98b8b, 0x08660f19, 0xb641c66c, 0xc121c262, + 0x3e1cf32d, 0xb6d1f8d3, 0x0042fee1, 0xa250ffa3, 0xbcf8945f, 0x9e783781, 0x6153f979, 0x86f485da, 0xa3a56d69, + 0x985bba24, 0x2a24cd4f, 0x3533f9c6, 0x3f7fa40e, 0xbffb48a2, 0xff95f6b2, 0x1531bc35, 0xdbdcbed7, 0xb8a73e56, + 0xe85d2de9, 0xa6338f01, 0x0d0f77a4, 0x9bc57f46, 0x7258edc9, 0xa2bb17da, 0xc5fbfb2a, 0xe764c068, 0xf8b8e506, + 0x2dea1081, 0x31ed83f4, 0x9896f28d, 0xf8dafad6, 0x34a9080c, 0x8e104ff0, 0x5397d7e1, 0x05925153, 0xf1aeb629, + 0x475f098f, 0x5490867c, 0x27601550, 0x6f6735f1, 0x5f523697, 0x7f5204c6, 0x29b9bdff, 0xe880b846, 0x5c9ee6d3, + 0x0ac36735, 0xcfa14980, 0xf526fa2d, 0x4584bcac, 0xd9d600df, 0xabe358e9, 0x8649c22e, 0x897388cb, 0x3c5e5d86, + 0x4b7b3add, 0xeabd2707, 0x9aa6a6d9, 0xd16a3d2b, 0x4455b296, 0x4751f1a6, 0x21f12e8e, 0x1ba57c3e, 0x0c47639e, + 0xedaeeb0a, 0xf287c407, 0x14ea6f6e, 0xe4dade02, 0x43f1c842, 0x9a623652, 0x503b6608, 0x997ea785, 0x68d2b948, + 0x14f163bb, 0x72637f5c, 0xc6c8eda2, 0x224adf0e, 0x0411c0a7, 0x371180b7, 0xd8ea762d, 0x7e05c89f, 0x22f58aa0, + 0xa9ec566d, 0x53dbe83e, 0x9c901f74, 0x34ba04a3, 0x297f8cdb, 0xc9afd783, 0x6371652a, 0xb5a8a34a, 0x465a5f7c, + 0x4cd8a22d, 0x9886427b, 0x23832a26, 0xf1fade4f, 0x843bde94, 0xd219c920, 0xed7f2c38, 0xbc2d1e62, 0x47d7b7fb, + 0x34d5695d, 0xc847862e, 0x13d07961, 0x43e0f644, 0xfe7f5fab, 0xbafd2afb, 0x66aa386b, 0x19aff726, 0x2e5f78f9, + 0x208efe1a, 0x8f3ac6c2, 0x16b90acf, 0x3422b959, 0xee9f1d52, 0xc54d1f2f, 0x580e1ffb, 0xcadca695, 0xfb5f2dcf, + 0x3b71d7d8, 0xc5d46c3a, 0x8a8357a8, 0xb71af956, 0x7308223d, 0xd83f728c, 0x95a181ed, 0xb19c4543, 0xe9292302, + 0x5bdcc86c, 0x2f585dc3, 0xef6085dd, 0x3014d8c2, 0x919e226d, 0xc870f8fe, 0x7134902a, 0xfaac51db, 0x838a3f6b, + 0xfc4b73c7, 0xd958da22, 0x93643d1c, 0xdcfaf222, 0xce9b3ea4, 0x359915dd, 0xc4511ff5, 0x67c1a274, 0x9bbe1d11, + 0xd720f61a, 0x0deb257c, 0x2af62049, 0x388cbbb2, 0x7183bca6, 0x50617c62, 0xd91733fb, 0xa9d36293, 0x81ea8636, + 0x6436b9b2, 0x6756e17c, 0xd0ca9a68, 0x713bd7b3, 0x316fadc2, 0xb5eda4ec, 0x6dc56ea2, 0xaf71890b, 0x59c3abae, + 0x77e818c8, 0xe9a0df8b, 0x063a7552, 0xd7b12833, 0x8f8d2f27, 0x67095082, 0x5db8c396, 0xcc9819a6, 0xdadfdb9b, + 0x3b8037f3, 0x15bcae55, 0x423baf76, 0x04cd0e27, 0x2d2e02f4, 0x9c01391e, 0xa20c5670, 0x59f0b0be, 0x81bd5c70, + 0x68e14d43, 0xec182e2b, 0x5164acf0, 0xfc1d0ef4, 0x483bc418, 0x232df883, 0xa3ab420c, 0xdc7d89d1, 0x2fef04bc, + 0xc5b478dd, 0x0c2571fb, 0x75763a39, 0xce63a2bb, 0xb59bc52b, 0x33b95756, 0x9823c461, 0xe9374aa4, 0xcd451577, + 0x39599d5b, 0xf98840a2, 0x6797d87d, 0x1f033703, 0xdb3a97e2, 0x14f4b246, 0x872ae088, 0xedade45b, 0xe7de89f6, + 0xc338779b, 0xa5e77a8c, 0xb15791f7, 0xe9443fd1, 0x779269f9, 0xa6c84b74, 0xcd26b53a, 0x09cac5ff, 0xcfbd55e4, + 0x1d08647c, 0x4c1f4e80, 0x1ac3a7e3, 0x7ef4504a, 0x7b7036ff, 0xdfc1e594, 0x899629ff, 0xba82e51b, 0x5093e9cd, + 0x40b091f3, 0x56f98258, 0x84d6dd42, 0x0918ef20, 0xcb3af935, 0x90187ef7, 0x13422640, 0x48cf1a34, 0x62f620e6, + 0x0e5d12e7, 0x376b44d3, 0x6caaa457, 0xdfd14160, 0x24e16188, 0x84e5793f, 0x5289425d, 0x9982e479, 0x579c6516, + 0x21720f6f, 0xa0eab846, 0xb77c33c4, 0x9d3b2f0e, 0x88039e21, 0x8bef3ca0, 0x4e3738c6, 0x157c2d85, 0xe77bd57f, + 0x26bb72e6, 0xa2376ac9, 0xd50e0d8b, 0x774ec351, 0xf02ddbeb, 0x954613dc, 0xc9c056af, 0x9775c8d0, 0xe91e7d75, + 0x6f59869c, 0xbb476d23, 0xb8a12d36, 0xd67075e2, 0x7da793ff, 0x52bade64, 0x44b24fbd, 0xb48bd823, 0xdfd212a7, + 0xf8b7dce6, 0x0001f0ca, 0x8b3b3125, 0xa21fa81b, 0xdfa06af0, 0x91848c9f, 0x26f9cb9b, 0x3da0ebdb, 0xfed81365, + 0x997605c0, 0xab3521ce, 0x92ab2453, 0xd89a1f91, 0x7f1bde8f, 0xe5a4027c, 0xb06a5be3, 0xee6de61f, 0x50b4a290, + 0xccef7544, 0x3caddc86, 0xc6ea93ae, 0x8e3bb6b2, 0x15827372, 0x9acccacf, 0x0893f575, 0x78c9e683, 0x9e13876c, + 0x6265857b, 0xe0b2cb8b, 0xb1691027, 0x3321c09e, 0x88f9d6e4, 0xe9b4dfc6, 0x6320e3cf, 0x7ac1d3ae, 0x53bf67c5, + 0x227bb749, 0x5535dbb2, 0x577a8baa, 0x3845ba4f, 0x33306112, 0x9dc31822, 0x9de4ef81, 0x674fc71a, 0xd7e7fc46, + 0x4c0de206, 0x3b4f05cd, 0x4f070c99, 0x3b93c6d2, 0xfe07b005, 0xf9cd8897, 0x25c128aa, 0x4731809d, 0x542b98c6, + 0x4350b20e, 0x601ee434, 0x54a51ad7, 0x25c65100, 0xe63e868f, 0xa5cb0a75, 0xfff06058, 0x5cb361fd, 0x99b9c5ef, + 0xbab79dd4, 0x875bc757, 0x59912ac6, 0x77500303, 0xaa5f7907, 0x36601bee, 0x42d2a70a, 0x367b99e5, 0x16d9b20c, + 0x67d76960, 0xe862e464, 0xe2010f21, 0x62f4ff52, 0xe7dfc909, 0x588fac08, 0xb375241b, 0x18a3991c, 0xcf171edf, + 0xb41ef7bd, 0xab942a82, 0xafccc8b5, 0x2e2e49ab, 0x44799fac, 0x40c6dd8e, 0x8c6100ff, 0x9374db90, 0x7d0160e3, + 0x4796fc0f, 0xa3d1122c, 0x71dc468d, 0x57bd3ecb, 0xf4c57a25, 0xda11307e, 0x1abbfb8d, 0xeb94f65f, 0x8d4912a6, + 0x2477b8ad, 0xa5f6cf9c, 0xc33d8505, 0x73aec6a9, 0x8898cb27, 0x3a5273c6, 0x4f8fe5bc, 0x30d5ffb1, 0xb51622bc, + 0xfcdc8f94, 0xb7e761cb, 0x8cf7e3a0, 0x450e793f, 0x02682a8d, 0x107ef77b, 0x975745f6, 0x7b3ba7a3, 0x5bf49798, + 0x0dc5e478, 0x1c19055f, 0xea7db317, 0x7243ece4, 0xcd3b5970, 0xbd44c0b0, 0x97d83c23, 0xcd0c9fa6, 0x583e7fcc, + 0x7dc410c0, 0x66eb4114, 0xf879e426, 0x6a41315e, 0x73deab1c, 0x80476957, 0x9b2f04d1, 0xeff7cec4, 0x5106cdf8, + 0x8ef6bffa, 0xd5a1c78b, 0xe2c66199, 0x31597b6a, 0x1e5c17f6, 0x0644f075, 0x0891e1f7, 0xb14a96ad, 0x26ce518f, + 0x79989f6c, 0xf4b11bfe, 0x9cf02203, 0xe27a5c28, 0x933963b7, 0x114acff4, 0x65b82502, 0x65b1974d, 0x9c5a740c, + 0x18d2e1eb, 0x9442124a, 0xa6185c85, 0x8ee0010d, 0xb3addf04, 0xf9b9e114, 0x54881b02, 0x0e3f0a4a, 0xe61d6069, + 0xe2e5204a, 0xecc58129, 0xa09767b9, 0x5d9835f7, 0x27e6203b, 0x05462495, 0x330fb190, 0xa96737e9, 0x85b098a1, + 0x1fb02438, 0x32c24545, 0x2dde6d2b, 0x69fbe9f9, 0xefeb3a4d, 0x5b0a0075, 0x3a743772, 0x2d2174c1, 0xf71f4d22, + 0x18bd63cc, 0xd9527403, 0x0846600e, 0xd50d7bec, 0xf55db054, 0xd15bbfda, 0xf77bf2eb, 0x2e1fa425, 0x94aabe6b, + 0x75d80916, 0xcdce7e80, 0x73edf35a, 0xdd1546ca, 0x0036b377, 0xe97d8e56, 0x8b655299, 0xd917628a, 0xfe04e8a1, + 0x646d0997, 0x9d2f0612, 0xcfea6b7e, 0x9699ea5e, 0xabcd4b70, 0x79450e40, 0x9d79473b, 0xee1cea7a, 0xdb898ecf, + 0x4a648351, 0x02c051ca, 0xa52fdce1, 0xf94d9aa6, 0x2ddf77d4, 0xd848502b, 0xd1615de0, 0x8f649e10, 0xbd52ae99, + 0xa3ea09e0, 0xb160d508, 0xca01b0cc, 0x31f3f9ac, 0xc4ed1fed, 0x13fc6f56, 0x11d08133, 0x85f66d61, 0x8c1d56b7, + 0x77c6b288, 0xe30ce294, 0xe89dbecd, 0xcebe6c5e, 0x99a9f7c8, 0x0ffe189f, 0xcdb2eed3, 0xf43e3d86, 0x9e6f27be, + 0x6d490488, 0xcf9bc5a6, 0xfa66d6d7, 0xb862600d, 0x63e5e06e, 0xcead6b25, 0x508e59a3, 0x03e64a45, 0x91c53b9d, + 0x96479008, 0x22c0e180, 0x74e19ea4, 0xcfc834c6, 0x4a7013d3, 0x48e983c8, 0xaa1b7ba3, 0xfd92da49, 0x5e2c62fe, + 0x27ce1de0, 0x493a3fb1, 0x275368fa, 0xea18f1ea, 0x656ff55b, 0xf402bac2, 0xd0986042, 0x75f6b129, 0xfc60047d, + 0x732e53bd, 0xf4ed19ef, 0xc6582a83, 0x70844b1c, 0xf0a60856, 0xb8a39d9a, 0x3e757ea6, 0x9dfddc86, 0xdfc4e6b1, + 0xaaf846ef, 0x8ba6f47c, 0x3462e633, 0x05ab2f53, 0x2d8a9aaf, 0x7545dab2, 0xfcb8ae07, 0xcdbdd5b5, 0xf6e35947, + 0x44f5b513, 0x580ba583, 0x0e950ffd, 0x667cef90, 0xcc142603, 0x06724a76, 0x9d64d455, 0x88fb8539, 0x194c2329, + 0xc66737f5, 0x26865e93, 0xfccda022, 0x96524126, 0x8a47cb99, 0x7d8380dc, 0xf09b62b4, 0x301f9fce, 0x641786fa, + 0x00379657, 0x9335b90a, 0x219411ad, 0x84e6d607, 0x30ffe058, 0x6754eb3b, 0x0ebe7ecc, 0xd18acec6, 0x3b77f180, + 0x69a93ca0, 0x038e53a4, 0xfc3df3ff, 0x5d06724f, 0x4c546858, 0x6011356c, 0x24592b9f, 0x6c6a2d2f, 0x466a7d10, + 0x5f0aa935, 0x11bfb18b, 0x5ae73a85, 0x97fa87a1, 0x654b3f4f, 0xacf89f55, 0x7ec49f58, 0xba051019, 0xaab605a8, + 0xf59d9a67, 0xf2f743cb, 0x4caa45a5, 0xf6a45230, 0x5825b78c, 0x18a779b6, 0x5f3b2cb7, 0x36adc699, 0x9ef87d51, + 0xfd1fc7e6, 0xc4b3a7a7, 0x05103283, 0xa0f2417d, 0xc83a5821, 0x5092ef20, 0xdb6a0396, 0x2d26aac6, 0x91e39fba, + 0xec4d782e, 0x72d9d636, 0x7340d6c8, 0x63159302, 0xdeb1ef96, 0x7e343395, 0x6f87e63c, 0x369a7864, 0xe44c4c28, + 0x76dfb08c, 0xc16e4894, 0xcddf239a, 0xb07a2143, 0x69ca97a4, 0xdd59cfef, 0x5da81309, 0x048984dd, 0x37c03277, + 0x386bd187, 0x3625e105, 0xed27c2af, 0x90aeb2f6, 0xea43e295, 0xfd0aa49a, 0x44e258f4, 0xc3d922fe, 0x3dc8ef88, + 0x8a099346, 0xce02a40e, 0xb89894c7, 0x6222bdbd, 0xc98b1154, 0x0744e308, 0xdaf9be4c, 0xc8eac216, 0xe0136177, + 0x8b208cf8, 0x2ad6f02d, 0x7cb1eae5, 0x69211c49, 0x6449066c, 0xbe45e5b4, 0xba089cc7, 0xe9b4f181, 0x671de55a, + 0x085681be, 0xa30eddbd, 0x53e150ce, 0x3ad9f269, 0xba26064c, 0xf47c3922, 0x73e2d617, 0x07fbf5cf, 0x416ac9a2, + 0x6dbaba25, 0x925fa205, 0xccc20a66, 0x0037f3a6, 0xc4b46a42, 0xbf2274cd, 0x44df190c, 0x5c058733, 0xfbc6e6eb, + 0xad0b48c0, 0x561cb508, 0x081317b5, 0xbe97b921, 0x06bcfd62, 0xb0e89e91, 0xb4274ce9, 0x2604cb25, 0x763c4728, + 0x955a002b, 0x7676c73f, 0x1dd99a0e, 0x76bf5cda, 0xfa55d3af, 0x581996af, 0xaab547e7, 0x916ce971, 0xbd4473cc, + 0xe98657d3, 0x80a6f315, 0xf4b34a8e, 0x37045b33, 0xe28f8074, 0x639f4784, 0xd318c5a3, 0x28e39c17, 0x2923ed79, + 0x298cb454, 0xab57f1d3, 0x464864f4, 0xba0f8d5e, 0x91d2e2e3, 0x9ef7753e, 0x446b7555, 0xd4625ae6, 0x859f0857, + 0x53a38534, 0x5b07b1dd, 0x589b2ee4, 0x51566071, 0xd8071189, 0x76399a53, 0xa1eddcad, 0x187bf35c, 0xf291ffcf, + 0x7db5595b, 0x25dd7aad, 0x2c982c31, 0xb1bb3fb0, 0x6778b266, 0x96b24995, 0x6df1be43, 0x54069d53, 0xdbca6cfe, + 0x86a8a834, 0x6cb9a4a7, 0x9f6d7cf9, 0xef9eae7a, 0xca5f5f95, 0xe2e4853d, 0xb936a248, 0x7b880050, 0x2da0c9c2, + 0x8451b62c, 0x1b153067, 0x4de8a3d3, 0x84d919c0, 0x52ec37fd, 0xf876f3fb, 0x63c49456, 0x84d8c016, 0x4df677e2, + 0x8db2250d, 0x15839773, 0x39970578, 0x61ca2d0f, 0x4a24cb07, 0x772e905e, 0x24c1ab68, 0xf5bc7b43, 0xd59ec0a2, + 0xfe623edb, 0x470e27a1, 0xc9acf9f9, 0x4e94687a, 0xc9133d67, 0xac676920, 0xd4d50b8b, 0x3e783dd9, 0xc2ed241c, + 0xe925ec15, 0x413834bc, 0x4f136c33, 0x56c095a0, 0xd0ceb20f, 0x21ee99f7, 0x0ef35fe7, 0x8f79ac20, 0x94f88f76, + 0xb49c9d2b, 0xe5b3deaf, 0x7625aec9, 0xc681a059, 0x9852b7a7, 0x2daab2f0, 0x0722f458, 0x0667224a, 0x2322cb07, + 0x8fe19730, 0xf1ae4f7e, 0xf205c32a, 0xe77e21d6, 0xeeca7c5e, 0xf45470c5, 0x47f1efa0, 0xcf5c0a77, 0xd97ff803, + 0xce5022dd, 0x774034b8, 0xafe60101, 0x4a137736, 0xfa34c682, 0x30ce1800, 0x24ca987a, 0xb840444f, 0xbb6df699, + 0x60d5554e, 0x2c86fbf6, 0xb8a80735, 0x6c5498c3, 0xa42a8f1d, 0xbd61a219, 0xdd6bda20, 0xa8e63837, 0x293db019, + 0x9b94c561, 0x4d14f86c, 0xc5960df4, 0x2df8d39a, 0x5584232f, 0xc731b875, 0x1ee26789, 0x966a25bd, 0xb6313462, + 0x1e4b551c, 0xad094b58, 0x986b690e, 0x5d34d4f7, 0x5cd5e025, 0xe9779d62, 0xc608f6e7, 0x85a231ce, 0xa197bc66, + 0xf87ed0a1, 0xa3a2579a, 0xa9785832, 0x4b4420be, 0x5b3790d1, 0x66449b76, 0xf20fd119, 0xeed147e9, 0x76802291, + 0x1a2d76cc, 0x7446725f, 0x2753b834, 0x4293325a, 0x3383dfb9, 0xb9dff0ff, 0x72f20ea1, 0x1a533d45, 0x7496bc35, + 0x61317b00, 0x68dd6c4a, 0xaa3e798a, 0x7aee4d54, 0xb8002c77, 0x661ce4a6, 0x848a2869, 0x03e94f36, 0x676259de, + 0x5bcc8950, 0x704ed1ac, 0x028d585f, 0x4604799d, 0x9ccb39cf, 0xce54db89, 0x70a8ccb5, 0xe7a65128, 0xd15542a2, + 0xefa03f71, 0x4c5e9cf3, 0x25b7ff1c, 0xc6ec70de, 0x72b636dd, 0xf3d32f23, 0xdefee595, 0xfee7a79b, 0xe37a9ce0, + 0xdd20064a, 0x7aba0d3a, 0x944001c8, 0x2dc99e3c, 0xffef2402, 0xa0001d73, 0xb7b24ae6, 0x73cc6a4c, 0x0cc1b7f7, + 0x1746040d, 0x2e4d7897, 0xd406f72a, 0x699267b5, 0x124b4070, 0xd49d90b4, 0x3dac83e6, 0x5f4ea2fb, 0x600b82ce, + 0x10f3b517, 0xfe7835f7, 0xdf4d4836, 0xf314e109, 0x907e5a43, 0xc7ed905b, 0x13cffebd, 0x55c95cc8, 0x21029a00, + 0xe618fb0a, 0x5e5b5499, 0x16eb472a, 0x444bfe8f, 0x2d0313df, 0x828727f4, 0x07510708, 0x457fdbdc, 0x4551f3a1, + 0x3f45d2d9, 0x4649d960, 0x86bc72a6, 0x1693b1fc, 0xc8935568, 0xcd65cd54, 0xea5307c0, 0x3fc227af, 0x1dcf079c, + 0xaf0c2f60, 0x4fe458b3, 0xd2e6335c, 0xcb4986c3, 0xd5e84541, 0xd66ee0ce, 0xc0d889bd, 0xa56ba2e1, 0x4c8fa47f, + 0xd71a17ad, 0x90890a3f, 0x98df2751, 0x7e8bee8d, 0x41859fe6, 0x31995943, 0x7729747b, 0xbba6d305, 0xc79430a2, + 0x644aefb2, 0xa20af4ee, 0xd985c9b5, 0xc6b298e8, 0x4e33a1b5, 0x878e63b5, 0x76399194, 0xe5318eac, 0x55428846, + 0x447ceed5, 0xe915215c, 0x1ef379c2, 0x36803651, 0xdcb6d4f9, 0xc76239c7, 0x88a42ecf, 0xfdacc18d, 0x04c32c30, + 0x685bb9e6, 0x560d9c24, 0xb36779cf, 0xb5de4074, 0xdc7a7166, 0x23cba1a2, 0x0ccb27b8, 0x43924623, 0x4f3f5931, + 0xb7a16ab4, 0x6246abd4, 0x1ba20bbb, 0x65112152, 0x8a146362, 0x59d76af7, 0x895f7acf, 0x9fbfb633, 0xc66f27a9, + 0x6333b1f6, 0xe3af977d, 0xc2218901, 0xa80eac46, 0x80366b3f, 0xc226f605, 0xfa9b37a6, 0x85554679, 0x0e2ecfc1, + 0xadc46761, 0x03e8c237, 0x1c81c966, 0x7cc1cc8c, 0x98114ce1, 0x59ff8fe1, 0x7f6052c6, 0xf045c1c1, 0xbcde8a2c, + 0x490a79e6, 0xe636d377, 0x518c76fe, 0xe47bc721, 0x03281af8, 0x5b156775, 0x77d5f505, 0xd1b65775, 0x11f40c51, + 0x2a303b4c, 0x901bea03, 0xb01ce7bf, 0x9e1588dd, 0xe1fc3494, 0xc50bc049, 0x55f59c39, 0x23d4e750, 0xe9dde45e, + 0x3b324e1a, 0x1aca46b4, 0xe5fe024a, 0x04985462, 0xc7ecd03f, 0x042988a4, 0xa2626d03, 0x09a1466c, 0x9ceb972f, + 0x7081fd39, 0x250acdc5, 0xf8f761d2, 0xece5ff99, 0x4277f7f7, 0x4a714329, 0x191e4d4b, 0xaf278f73, 0xf88ce593, + 0xb99ce883, 0x0e03b54b, 0xb9519c2e, 0x0852a2d2, 0xc5181807, 0xe96b33e3, 0x77f61f44, 0xadbb057c, 0x54d5307b, + 0xe7eaedbe, 0xfd1d4513, 0x76579056, 0x6e7b0160, 0xd9965b40, 0x0210c7cb, 0xb872ef3f, 0x642b470e, 0xe00a87b4, + 0x7016b994, 0x2e8e828c, 0xa87ab392, 0xf5107f41, 0x60dd5b01, 0xd760eeed, 0x6fd5db30, 0xba332411, 0x3c80a4a1, + 0x1d540f4f, 0x0dd6fdce, 0x140a148f, 0x18ed38f2, 0xbcbb3f83, 0xfb13ccf6, 0x966d1e22, 0x8bf7d890, 0x720ef69b, + 0x0fc48055, 0x8922fadf, 0x04396a85, 0x19524b76, 0x73491833, 0x85c37bed, 0x255cc1d9, 0xa6caa1a9, 0x31ca0114, + 0x568c06ce, 0x491c4ef0, 0x0fc5f6ea, 0x50fa2447, 0x1940d582, 0x6f83cf46, 0x0d314eef, 0x6c7a7e4b, 0xf68fadaa, + 0x5b56d64c, 0x2aaa4b53, 0xf3fb97d8, 0xc5e2546c, 0x97ac8bda, 0xdd755bc5, 0x8e82edfa, 0x170b65a5, 0x5a454ede, + 0xc65fdd37, 0xb91c94e5, 0x1b720309, 0x3c1d198c, 0x45a57af1, 0xc74c617d, 0x78ac9e9d, 0xc1cb1ed7, 0x75c76c84, + 0xdfcd4459, 0xfe8fa424, 0xe7f6dc16, 0xff2402e2, 0x616d2849, 0x4c5d459c, 0xc47c42bf, 0x569fbe37, 0x679dbf04, + 0x672b3ced, 0x222ef682, 0x5becb1e8, 0x76465788, 0x4e141328, 0xbff541d8, 0x55c7cf51, 0xc446b378, 0x06e07836, + 0x227a75dd, 0x68332f63, 0xa65611be, 0x46ec0789, 0x11b74a48, 0x1a033481, 0x6c097c5f, 0x99bf4fcd, 0x152869b7, + 0x416c6774, 0x5f7a647c, 0xcb07fd3c, 0x3a8f8fd1, 0x359aad26, 0x5121f232, 0x926679ab, 0xa85a04ae, 0xe8377671, + 0xac75de07, 0xcaf1f51c, 0x577a82c3, 0x30334288, 0x73409977, 0x2c8f4e4b, 0x1584a108, 0x907a0c63, 0x42f5a1b9, + 0xa0fd61e1, 0x6b125a9d, 0xbd29bb5b, 0xfe079bf8, 0xccc105f4, 0x2060b06a, 0x11f105e7, 0x3e4b8c11, 0xdb339a40, + 0x44d93f92, 0xb1473290, 0x3d0d93e1, 0xbb0d8df2, 0x76cbcc40, 0xc84a9686, 0xf72c4608, 0x3da33c04, 0x495968a0, + 0x58d53824, 0x9aeb66f7, 0x95de67b4, 0xa3d973fb, 0x655a55dd, 0x8a875e55, 0xf74c858b, 0xa751ce81, 0x43de9d85, + 0xd33b4686, 0xc6fa1785, 0x5870bee7, 0x275258bd, 0xf6cee947, 0x05dac304, 0x05539466, 0x4012b755, 0xd2058abe, + 0xfab6d718, 0xc7ef69d3, 0xd6e260a8, 0xc16babdd, 0x03959a12, 0x791b501e, 0xcb84db3b, 0xcc9dfd64, 0xb16f97f1, + 0xa94f2c2e, 0x2dbebacb, 0x77e7dd87, 0xeb45b671, 0x400b24a0, 0xf74ddd32, 0x96bf8fb8, 0x76f582d8, 0x679c6595, + 0x59152936, 0xf152c73c, 0xd4eb2e48, 0xe55eb254, 0x296a8271, 0x42fbcc01, 0x38fb0ac2, 0x296cf716, 0x2692eeac, + 0xed4cf77a, 0x989bc461, 0x5c3e9d1c, 0xb58ff5d9, 0x931f9ae7, 0x5eeba38a, 0x3dc552a2, 0xa95cf729, 0x3fddbca6, + 0x6811f255, 0xcc20fd7e, 0x17e62117, 0xcdfb4a4b, 0xbbba1f88, 0x898d0cb3, 0x5e2ecaef, 0x42219e73, 0x807b1088, + 0xe0ec5071, 0x15cfb7c2, 0x99593f6d, 0x1d9f3d30, 0x59035c44, 0xc8f03fab, 0xeb5194d3, 0x01c23dea, 0x152d73ea, + 0x18519655, 0xca0867cb, 0x195248f0, 0x683e5138, 0xbf0ac0d4, 0x932f2b38, 0xc139e98d, 0x82416b50, 0x741763c0, + 0x1aed1661, 0xa1907e27, 0x46ea1c68, 0x2abaa414, 0xd999d5c6, 0xa37a15fe, 0xa4884bdb, 0x0b5f51d4, 0xae350551, + 0xd2c5d7d4, 0xc4e4416d, 0x18eb55bb, 0xdfafa2cb, 0x040ee26d, 0x416255b0, 0xece61d6f, 0x9cc46216, 0xcb3465e7, + 0xba1cdae4, 0x944e9643, 0xe88825f5, 0x84842a9c, 0xe9ac749e, 0xb15756a3, 0x65031d34, 0x221c8118, 0x08d6b52e, + 0xf0199c8f, 0xcb8d17de, 0xa6cf73d2, 0xea130896, 0xde65e3c7, 0x72a0bd62, 0x268cee9f, 0x7c9ab4a1, 0xd7e4fe29, + 0x226861b1, 0x77883663, 0x370e8595, 0xa6558cb3, 0xb747a4c6, 0x5e099e7e, 0xdcb0c748, 0x527b8918, 0xe8afc28c, + 0xe0b3228d, 0xf9de302a, 0x3be5b577, 0x6c8a0771, 0xfd5c0d41, 0x1ed4a56f, 0x2f8da312, 0x5369191e, 0xdbaba732, + 0x48ffd71f, 0xb7b916aa, 0xfdb3331b, 0xad35a556, 0xd86561ca, 0x038e8dc5, 0x6ea5e820, 0x55da4157, 0xdd3baadc, + 0xe5cd0baa, 0xcd321d9e, 0x0f924dd9, 0xb8063c28, 0xd219e4ed, 0xc370f585, 0xb0db9956, 0x6b446c60, 0x084d0f3e, + 0xf309e662, 0x914cc7a4, 0xc9c33d48, 0xb9ba3f36, 0x7b529c0b, 0x920a9371, 0x05ee9154, 0x83f88ac3, 0x1500845d, + 0xeaeecf62, 0xdeb6a235, 0x4592a8ce, 0x45ac16a1, 0x23a02311, 0x9dbac60e, 0x56039f4e, 0x1f535a3f, 0x7a8f8ac6, + 0x98b688cb, 0xf4a6379b, 0x6e0e5809, 0xb270e030, 0x6dcfd7a9, 0x580cf47f, 0x921021b6, 0x82961a67, 0x5928a7cf, + 0x53b0cdf9, 0x57135bd0, 0x3e9f99b5, 0xc9156dbd, 0x0550a1f4, 0x18683951, 0x324d0cfa, 0xdfbdab6f, 0xedc6bdde, + 0x60c73f80, 0x93d24e6a, 0x49799724, 0x45c81f12, 0x80336ad9, 0xa15a88c6, 0xdfb4daef, 0x2f346820, 0x01b85e39, + 0x84e3579b, 0x7dc416b1, 0xc324e67c, 0xdc156487, 0x5e2d6d1f, 0x55e2b486, 0x435b088a, 0x3f532c71, 0xf388b1f4, + 0x883cf59f, 0xd9285c40, 0x42b45fb2, 0x685a8b4a, 0x647d8883, 0x96c8152a, 0x67a8ce9a, 0x667698dd, 0x0c480203, + 0xcf97081e, 0x986a6806, 0x3346bd7a, 0x62600b91, 0x0944fb5a, 0xa75e7448, 0x5aaf2d26, 0x564c395f, 0x5b9b4142, + 0xd8437f41, 0x574abdf7, 0x8440407a, 0x52606baf, 0x5839b346, 0xa0da9411, 0x8ed0fd67, 0x270cb7ce, 0x2cd2d0af, + 0x4173d203, 0xe59d8165, 0xf1ba778a, 0x4018c7fb, 0xd55fe90b, 0xf064e483, 0xda48f825, 0x36439dcd, 0xeee3957a, + 0x84042281, 0xead81e00, 0x320bde4f, 0x7a942f79, 0xe24593d9, 0x039167c2, 0x558de9c9, 0xc60da037, 0xe47c229b, + 0x093afcad, 0xd4d4c222, 0x1966ccb3, 0xe09c0133, 0x5f491bd0, 0xe7337260, 0x1b5c284c, 0xf638d8f0, 0x0ca47803, + 0x9e852dc8, 0x07610fb4, 0xe234a8de, 0x50d89522, 0x8d08258f, 0x81d239f1, 0xf1a6f390, 0x8c2bb8c4, 0xcbb64a13, + 0x41ddc9e3, 0xf541b52a, 0x538f0b1d, 0x8095404f, 0x1275df2f, 0x288de0b6, 0x18c1a541, 0x9b819cb5, 0xb6bd13b0, + 0x180f6eaa, 0xc06c6730, 0x4885b53c, 0xdd1424c2, 0xd970cafd, 0xe5b10852, 0xdcc628a7, 0xfe6293ed, 0x04f8b1e1, + 0x76a99810, 0xf5ad9f3a, 0x2cd476a5, 0xb4cb9935, 0x762ee94a, 0xbaa4f420, 0xd5176bb1, 0xb707fafe, 0xcc82eab7, + 0x80dce556, 0xbc01e8a4, 0x6e8260af, 0x4d91a421, 0x6321e286, 0x4900fbb2, 0x8919a21f, 0x70574cc2, 0x830ba017, + 0x998c6fb8, 0x35bfab0c, 0xe1c1fcac, 0xe2ff010f, 0x1bd4ec63, 0x8b8fe8c9, 0x548a08c3, 0x89047134, 0x828ca5a1, + 0x49c112ed, 0x68bd45a2, 0x121d5d96, 0x9558dcfc, 0xbc592b78, 0x7c7250e9, 0x952fffab, 0x960a6da0, 0x16a53dbb, + 0xbae639f0, 0x02d8ea6b, 0xeb1889d0, 0x36e24a89, 0x3243bc82, 0xfc524aa8, 0x6b5e410a, 0xd769295b, 0xc43c7db5, + 0x2942d7a2, 0xd619b041, 0xc156087a, 0xf0d4e4aa, 0xc4a29ea4, 0x212b4da2, 0x1543b835, 0xdb39ac42, 0xfc453346, + 0xf301ead4, 0xdd56b5f8, 0x75ec7fb7, 0xb25ebe40, 0xf6c9d10a, 0x154daf93, 0x6c6bb928, 0xa460c307, 0x613cdc39, + 0x29ba3ba4, 0xe34dae32, 0xbb763533, 0xb6c33e87, 0x1e018e88, 0xd444bd8b, 0x880e6baa, 0xb912dd32, 0xd3bdac5c, + 0xf803a119, 0x6b939d6c, 0x5e88d752, 0xbd1024ba, 0xc1926c6c, 0xf32d652a, 0x5c335636, 0x7f0dc2d2, 0xbe53db28, + 0x04056293, 0x2345bb76, 0x27b25594, 0xddb2e8fc, 0x0207903d, 0x528ec447, 0x2425b4ac, 0xcdd314ff, 0x06752b26, + 0x1a6829e6, 0xa6a85e11, 0x95d704ac, 0x02eca6ff, 0x2e99b8ed, 0xd0880328, 0xc28cf4b8, 0xed0ec9d3, 0xdf811675, + 0xb9f3b6d2, 0x80a027c9, 0x1327556f, 0x5a3a0b9a, 0x56dec7ad, 0x8aa173f1, 0x508b5245, 0x885ca5b7, 0xbdceae5a, + 0x36184146, 0xfc6d5e01, 0xb0d7dfe8, 0x17d49bb1, 0xbf9e4364, 0x8253685c, 0xdbdfa57d, 0x1c2b0a3f, 0x4fbce334, + 0x21474601, 0x0322fca5, 0x0290b938, 0x8a8518ee, 0x99db93ee, 0x0886d85f, 0x04177563, 0x446560e2, 0x41c35fba, + 0xa87a4dc9, 0xaf19169d, 0x2638237b, 0x636510a2, 0x5add9df8, 0x4c150f6b, 0xaac9c221, 0x0a8a8c07, 0x65a70881, + 0xd115148b, 0x2ee3db99, 0xf2b5d3fb, 0x87835a0a, 0x0dd0edd3, 0xe5d832aa, 0xc6d41dbc, 0xf8020c7d, 0xb137e775, + 0x837c2c0c, 0xf6b77c9f, 0x8dd2c3fb, 0xf7ffbfd0, 0xb651c913, 0x8a91b65c, 0xe07a3d79, 0x956cd62d, 0xa5f6d0fa, + 0xe09ea614, 0x22fa6128, 0xc36f4627, 0xbd0b26ed, 0x360e2fb8, 0xf730328d, 0xe8f7d0ff, 0xfeea8bbd, 0x447bfcd2, + 0xdd23e2e9, 0x6cad47b6, 0xd2c46b5a, 0xc4e8ea5e, 0x4f4234b6, 0xff9e92f9, 0x7d0a39d4, 0xa579f87a, 0x8aca8af7, + 0x25e787b1, 0x93161553, 0xec263537, 0xb1e4fc67, 0x4bdf9712, 0x6e74b797, 0xf6d79e0e, 0x9b38d766, 0x423c1028, + 0x7e89da44, 0x7655dd96, 0xa53303a8, 0x145e3f14, 0x7e7fdaf7, 0xc0d6c66f, 0x0de168fc, 0x3a45d3f9, 0xb57828f8, + 0xb9e5f18a, 0x06e9f1a5, 0xcd50f872, 0x1640f498, 0x4493f44e, 0xc5821511, 0xdc85214a, 0xdf6ba78e, 0x9bf7f626, + 0xaeb1238d, 0x058ad60d, 0xcb093917, 0xc2ce900c, 0xe862073a, 0xf984be1f, 0x1e798b2a, 0x1b4732c5, 0x6fa2f4fc, + 0xdaa574c1, 0x63c93514, 0x4da5cabc, 0x3403d945, 0x78608c70, 0x7ca63b80, 0x60b63d70, 0x19c6a2a2, 0x4d51fd04, + 0x9d308a03, 0x73a0c7d5, 0x035c650a, 0x6775bedd, 0x84f0ba06, 0x8d5e8526, 0xda0bab7a, 0x02c52390, 0x1d0cb7d5, + 0x2ddb26eb, 0x1c722f0d, 0x550c52f4, 0x880b6797, 0x35125e44, 0xa469b6ca, 0x2cb0e705, 0xbf0b2405, 0xc862b675, + 0x1aaee946, 0x4123f08c, 0x502c1c12, 0xe957058f, 0xf196379a, 0x641d375d, 0x4df52ea7, 0x4ec848a8, 0x78fd9577, + 0x86baea7f, 0x38f37413, 0x7a4749d3, 0x8837cdfa, 0xd43949f2, 0xb87a1556, 0x369f4a2a, 0x95b7c217, 0xd4d14595, + 0xa9af1fa3, 0xc8d15e07, 0x6c840b77, 0x56311ec4, 0xd33df02f, 0x3c324131, 0x8d2a4262, 0x07796caa, 0x970aef79, + 0x18b90d09, 0x281f5287, 0x9c22bf7b, 0x8d1f9d10, 0x48fd3435, 0x171edd68, 0xda6c9960, 0xcaa3f109, 0x0834f89b, + 0x11784331, 0x83189f50, 0x311f6229, 0x15e00039, 0x32e32809, 0x4248bc5f, 0xe06efb48, 0x2cce5b28, 0x7f670b18, + 0x1546d316, 0x84ccbf06, 0x9cc40006, 0x2ff6d579, 0x6cba4977, 0x4f980e12, 0x3d3d9fe1, 0x03b5e68d, 0xed08a927, + 0x255a154b, 0x093af873, 0xf2078593, 0x2c3c5e54, 0x68656d31, 0xfd9303d8, 0x202172da, 0x92d40b27, 0xee5a303e, + 0x98bed4dd, 0xb2645349, 0xc8b94d55, 0xcbb91c13, 0x1d5bc01f, 0xf3efa7a1, 0xa1000ef6, 0x5429b31c, 0x29d1cfaf, + 0xa3ef248e, 0xa083c308, 0x4be1127d, 0xb80c60e3, 0xe69d5075, 0xcad1d842, 0xd94d7035, 0xfc6c418a, 0x7854dace, + 0xb8196197, 0x46792032, 0xa52b44cb, 0xda90a819, 0xce1e8242, 0x2e6077ae, 0xe1ab2127, 0xbe5fbb14, 0x86b98ac2, + 0x8d1a2b04, 0x885f6985, 0x676b6746, 0x7b710aa6, 0x3232a991, 0x37b01379, 0x0772cbc8, 0x2dccf2ed, 0x00a87d41, + 0xb5270b51, 0x55792395, 0x5df29f42, 0x4362eb66, 0xc2929985, 0x9bd3a8f5, 0x61659467, 0x63cf4aeb, 0x3b1672ef, + 0x33829994, 0xa1f4a680, 0x7a02a021, 0xf1562194, 0x4484d3ab, 0xf2ee5e6e, 0xb1dd4379, 0x9f1899ab, 0x18e18349, + 0xc3ea07d6, 0xb02b037f, 0x678f9a04, 0xb71cc825, 0x842cf123, 0x40f5047c, 0xa25ee403, 0xc37bfac7, 0xf1f7ea76, + 0x7e9a8186, 0x306bc178, 0xc53dbc7c, 0x40ec33d5, 0xfc489c86, 0x06be2ad6, 0x82f085fd, 0xd22abe1f, 0x61f838e2, + 0x3df6e91d, 0xde42e25c, 0x59c896d3, 0x8d2b83b4, 0x89f4a0d5, 0x3df545d2, 0xfe9af4ec, 0xf131c5d1, 0x26a46eb0, + 0x0907bfee, 0x1cc16ce9, 0x1aad3129, 0xcb3269ed, 0x1aabc80b, 0xdb903ec1, 0x510941a7, 0xe240dab9, 0xf8ddc6d1, + 0x9c544028, 0xf6cd99cb, 0x602399c1, 0x774cffce, 0xf5ae4884, 0x9f198e8e, 0x1124b4c3, 0xc6cfdf38, 0x62eb1561, + 0x50721b0e, 0xa00b97f1, 0x13c7a372, 0xaa714515, 0x78e5ac0e, 0x7591a2ca, 0xd54fdb3e, 0x68ef109c, 0x9e0294b5, + 0x4b58bfce, 0xe8a13490, 0x1c60ea6e, 0xefae38d9, 0xea12df67, 0x6cb4acf7, 0x39421326, 0xd03acbef, 0x1b31daa3, + 0x3c8c7d17, 0xc7e2da2f, 0x87e9fc12, 0x2b82d7d8, 0xeaf55736, 0x9a9185ac, 0x7ca996c2, 0xdd903a4d, 0x91c0e018, + 0xb1261b81, 0xccfdbcd6, 0xc21ae92c, 0xe82f35fa, 0x80195dba, 0x40aa3e53, 0x1e7ef293, 0xd6e3c02b, 0x196b30df, + 0x0cb233c3, 0xe033adc4, 0x7f4b73b5, 0x415fc34d, 0x9386826d, 0xbaf3a63c, 0x98f4d518, 0x3f60ae81, 0x68785e4d, + 0x34864b47, 0x7561efcc, 0xfa0816e8, 0xd386fc29, 0x6c35f11b, 0xffdcad58, 0x251b031c, 0xb9b98c78, 0xe7962143, + 0x8eb84172, 0x772c5e2d, 0x1ebb377e, 0x7c8ec878, 0x31b13c3c, 0x3c86d8f9, 0x3934c941, 0xe06a60bb, 0xb724d930, + 0xf73f6a3a, 0x459f287a, 0x0606d556, 0x0d9325f8, 0x55dc3b10, 0x2ef46f6a, 0xce71c329, 0xb4f73382, 0x5b38997d, + 0x41a0fed8, 0x3d11de2f, 0x24ced0fd, 0x142b84d5, 0x1f476273, 0xf29f2c24, 0x7942c6bd, 0x2ab61596, 0xf0ab7a01, + 0xe388b637, 0xb6c83933, 0xff0f45bd, 0x87417ec6, 0x2459973a, 0x23dad7f7, 0x167b2b59, 0xbfbfca3c, 0xa5d765c9, + 0x5d2d8a1f, 0xd5685929, 0x580613d2, 0x702924d2, 0x8e4ac728, 0xb96a4a76, 0x0c91901d, 0x841d4e42, 0xb83698cc, + 0xb204e1db, 0xebe223ca, 0x6fe64b52, 0x46e6ebda, 0x1573338d, 0xffe890a6, 0xa67cb736, 0xbbb8ac9e, 0xc206e97f, + 0x309082e6, 0x473d32d7, 0x34f3aed6, 0xcf9fedc7, 0x482a00be, 0x01cf25cb, 0xfb38d911, 0xec647672, 0x16055748, + 0x37eb42af, 0xd20332b9, 0x3b4a49ed, 0x29d6a173, 0xfd925c3e, 0x79662740, 0x5eb6203b, 0x20ec5b71, 0xb0643bcd, + 0x62aa13a0, 0x8fdf53e6, 0x6b65c910, 0xcaf78373, 0x603de63d, 0xed5e120b, 0x57aa7473, 0xd204fac6, 0x813ac671, + 0x33a4c27b, 0xb9b1646b, 0xa6a90cc3, 0x0289a8c9, 0x8e6ad9aa, 0xb4c39528, 0x80c18f2d, 0x5e12665e, 0xb1c85947, + 0x8dd0ba18, 0xb880b49f, 0x76605765, 0x394ec7c7, 0xd86ead65, 0x9731f4b3, 0x7ca4e77e, 0x5d3576ac, 0xfc0c148a, + 0x8fd74fff, 0x5f178910, 0x9bf61ee1, 0x7f03b277, 0x05c0ee40, 0x0369f851, 0x9a59935d, 0x6f84748c, 0x79d77b8b, + 0xa62a5308, 0xcd2fc7f9, 0x611b0063, 0xea06b0ea, 0x69078de8, 0x7426ac91, 0x524d0431, 0xe62a12e0, 0xa52a0d50, + 0xed735699, 0xf751c36e, 0x868b00e2, 0xc8399361, 0x4081c838, 0xabe50e4f, 0x826e1aa9, 0x573e132c, 0x82489ab7, + 0x3f2caef9, 0x559884a6, 0xac6dbd33, 0x40cf7e91, 0xeb289a26, 0xa707d299, 0x7fc8a1e8, 0x191dfbc7, 0x0e828f4a, + 0x0ee94710, 0x90095ca8, 0x90631c04, 0x223b7fe0, 0xc49dfc5a, 0x3b75f36b, 0xb98e602e, 0xef08919f, 0x70e6647b, + 0x5c876f26, 0xf1f7b1eb, 0x0e269819, 0xb9e81637, 0x91fd9efc, 0x38a3bc17, 0x9137aaf5, 0x1c0566a8, 0xfb2289d6, + 0x6b80c972, 0xb5694b4e, 0xe09ee27a, 0x9b91c3e8, 0xb1747583, 0x46c1d3ef, 0xd1ff5f47, 0xa13b29fb, 0xfab11688, + 0x6630a00a, 0x3e2ddff3, 0xe503ca47, 0x06b1d7ac, 0x13beec1a, 0xffde3739, 0x6fd86aa5, 0x9afe74ba, 0x5a9f1bcb, + 0x4ea2aa10, 0xb5a847ce, 0xaeaec82f, 0x8ef8c859, 0xe3b8370e, 0x89c65f99, 0xcf30eca4, 0x5ff31926, 0x184cc410, + 0x4566c785, 0x463a49e0, 0x5ab92f10, 0xfde1cf1c, 0x0a6afd76, 0xc8802225, 0x443ff595, 0x5c55959f, 0x8f2cb458, + 0x192959e9, 0x7cb2d923, 0xfcef9b61, 0x6cb016ac, 0x2913ef30, 0xa2d3d14d, 0x57c4bafb, 0xb6a703d3, 0x4d74c7dd, + 0x83f75434, 0xca6a3046, 0xf8da31c3, 0x9b55b161, 0x974e1247, 0x2cec6a0a, 0x96d1be36, 0x89cb9098, 0xa4d13610, + 0x2eda8153, 0xec4647bc, 0x320bb382, 0x8d52cc23, 0x088a07ef, 0xfbedb67e, 0x3a457ceb, 0x31e0061a, 0x22f3ec1c, + 0x3132e6ec, 0x7ab27e04, 0xd6a415f1, 0x262718d2, 0x05c05a16, 0xdd157dbf, 0x07d533a9, 0xa3d04218, 0x1ad18688, + 0x64fdf9c1, 0xfb3ff60f, 0xd7db16a3, 0x5f7833d7, 0xf5b82d37, 0xbcf44365, 0x11f14235, 0x31f42ebd, 0x4f81d6e4, + 0xb908ae62, 0x6392e51e, 0x0212097a, 0x5497bc3d, 0xd44602b3, 0x8b5bbbaa, 0x1241a95c, 0xa039c247, 0xe7ab98d6, + 0x27d02371, 0x701a1128, 0xb0faeb9f, 0x2dfe96e9, 0xdbe557ad, 0xf7b13fd1, 0xdff2b6fa, 0x4a914bf4, 0x529a11eb, + 0x20a0f089, 0x5685ff86, 0xf95fdca5, 0xfe105008, 0x9cac819d, 0x3c69e24a, 0x338043e9, 0x3ea3a25d, 0xb75ed306, + 0xba2176d9, 0x7394bb35, 0x3424ebec, 0x8fde806d, 0x09ed7d5c, 0xa751d757, 0xf110dc9b, 0x75da508d, 0xc9d426a3, + 0x67550267, 0x6dd49d9e, 0xbcc659de, 0xa0888090, 0xdc7f1e6d, 0xc663dc07, 0x6bd4be60, 0x770d13bb, 0x751dbd0a, + 0x30436948, 0x693e0ac8, 0x62f9c443, 0x6f752082, 0x8f226efb, 0x9d6d2759, 0x9b2d64e3, 0xea17507a, 0x38116209, + 0x89edae81, 0xb4720cdc, 0x28cc1be8, 0x99df2604, 0x722b3db9, 0xa5c4f8f1, 0x68b09419, 0xb1ec6d0f, 0x383ecd69, + 0xeaebb56f, 0xafeb09b0, 0xf2d224aa, 0xff36843a, 0x14236fe4, 0xfc45d0e9, 0x07671c58, 0x15ae9e25, 0x0b2e4107, + 0x3bef27fa, 0xd283056d, 0x20060ccd, 0xe4f804ba, 0xe1e5a3a1, 0x6e07c46f, 0x96ec862c, 0x671d17ef, 0xf3fbed96, + 0x0f117a82, 0x19576e98, 0xde05549b, 0x67684a16, 0xe104e3ae, 0x68c55091, 0x46432889, 0xb48f07bb, 0x1e6b5126, + 0x6e737f1a, 0x63f92203, 0x49a4ddbf, 0xb3426735, 0x38da0655, 0x7d1dbeb2, 0x24c89d5d, 0xd80fbcda, 0xc9737601, + 0x72f93860, 0x93cc6fae, 0x3c69cdd4, 0x2d692387, 0x14b3c09b, 0x6b62965c, 0xa79cbd6a, 0xba33d564, 0x944079b4, + 0xd4af758d, 0x45977269, 0x88d7bbed, 0x2b844e1d, 0x8045160f, 0xd16ca58f, 0x0d13038f, 0x272305f8, 0xab3d7f0b, + 0x46a195ae, 0xf9464f5c, 0x6ccf5b91, 0x53064720, 0xdb737153, 0xd26d900f, 0x5405f715, 0x9e115929, 0x7bfd3f46, + 0x9cdf6ad5, 0x56ded00a, 0x771f5041, 0xfec3d559, 0xda9c0401, 0xfb0199c3, 0x25749657, 0x00d18ff2, 0x7cea90c7, + 0xea7bc7cd, 0x33f72d01, 0x9926ac58, 0xe73f6bd3, 0xabb74987, 0xde409021, 0xa0d0ef91, 0x0698c526, 0x5df0cc09, + 0xa67feb25, 0x81283716, 0x02a5782e, 0xad7009de, 0x349b72e5, 0xd2ce4ee0, 0xc01e3293, 0x2c8520fc, 0xe9ce7c69, + 0x8e383fce, 0x0fb8f35b, 0x886e3bb0, 0x1ca540fe, 0x3e6c1862, 0x6a9dfc8e, 0x7441c09a, 0x85056831, 0x208c8d2a, + 0x0da71acf, 0xc802cadf, 0x58211986, 0x3b969b3f, 0x1e87e4bf, 0x68c6194a, 0xc6447c2a, 0xe119b9d8, 0xe1c9895a, + 0x0f0d6a7d, 0x55c37124, 0x4ee6e8de, 0xee7d0978, 0x4c63818d, 0x26b9b808, 0x147e82f0, 0x4c9e6e89, 0xde1079e7, + 0x60a8bc69, 0xa388f8bc, 0x9ac9e114, 0xb765fe39, 0xf04909e6, 0xb90eba5b, 0x1b221695, 0xec4a0cec, 0x0913789e, + 0xfac1eeff, 0x69015a6b, 0xaf657e48, 0x7fec9005, 0xb9145336, 0xb05c4801, 0x43148336, 0x8be192f2, 0xf557a4d7, + 0x417d121f, 0xd299f1f9, 0x89ad0b3e, 0x66b0c5dd, 0xa2e5a94d, 0x0818d1e4, 0x45a89524, 0x196565d0, 0x8ee1e222, + 0x0af904ca, 0xffda83b3, 0xbbf17619, 0xa95de5e9, 0xedc07e93, 0x0fc5c921, 0x5df3261c, 0x1b67bb38, 0x2ed9a3c4, + 0x2d1ef4fc, 0x2154f998, 0x21392ecf, 0x9430ca29, 0xcf5845a1, 0xd0974095, 0xf966e593, 0x6b33ff4a, 0x9d4866c0, + 0x9c17305d, 0x8bdf58b0, 0xa60ad0b2, 0xfb69a460, 0x7c908929, 0x8c7a3d77, 0x7fde3b24, 0x1622a82c, 0x3989dbdd, + 0x9fc8481f, 0x7c8be975, 0xb08232ba, 0xa1369a8c, 0x0da03549, 0xd9d8054a, 0xf9275d93, 0x023a280d, 0x9eb2d37e, + 0xfc344100, 0xf407df3e, 0xd64bb865, 0x0fdaf989, 0x5a3a5a8a, 0xff1e0c57, 0xd6b4e33b, 0x7dc63824, 0x3b56789e, + 0x40c5992b, 0x2c44f00c, 0x063b257b, 0x25a066b2, 0x57acf21c, 0xc8e27d2e, 0xeeb280d5, 0x99bb0ebb, 0xc52d31b0, + 0xa5d91aba, 0xe3c6302f, 0xad52c517, 0xaba28d1a, 0x84aa6910, 0x0a0b3157, 0x06e50bc6, 0xe8b41a47, 0xff9c29ed, + 0x3f6c657d, 0xdd76ba80, 0x8c947310, 0x6715bd2f, 0x52b3dc05, 0x94c0bc23, 0xc03a4377, 0xaea6b8c4, 0x82076bbc, + 0xedbbe44a, 0xea94b7e8, 0x7fd4ad27, 0x3d6b5fe0, 0x3855b15d, 0x3c57e280, 0xc21cf78f, 0xc139ad75, 0xd86a7c35, + 0x388997b7, 0xc57c9687, 0x251b3279, 0x5205e3da, 0x59729e56, 0xa2ed850b, 0x72c0d236, 0xcccc155a, 0xb6ff5209, + 0xe5ee3c74, 0x6ee6885f, 0xbc4a1ae4, 0xf0a8fbdc, 0x6d57aa28, 0xb35bc407, 0xe71c7684, 0xc9334f40, 0xdd902e8c, + 0x6f9c2f51, 0x70653e5f, 0xe6c954f7, 0x460a435e, 0x0ebebc09, 0xd6c343af, 0xf9175e0c, 0xae3be954, 0x07320165, + 0x2bd21c1c, 0xabb7ebbd, 0xaf900f59, 0xd854462b, 0x80944c9b, 0x5a0c43ad, 0x939dd69b, 0x0b93a9af, 0xbde0b729, + 0xd3dee079, 0x46801676, 0x12ee67e3, 0x21f8e444, 0x670c23fa, 0xec752ce5, 0x68514b28, 0xff224fae, 0x60114d3b, + 0x0bdd0346, 0x184a8c59, 0x3365d750, 0x876638f3, 0xd9c2ce12, 0x64453092, 0x3b063a3e, 0x41378f64, 0x77e72299, + 0x87e22f57, 0x4e8bc5e7, 0x4fb54db6, 0x91da1b7f, 0x96a9d0d4, 0xfbdaff9b, 0xacf07466, 0x1c8fbf90, 0xaefc3ce1, + 0x584819ee, 0x3b3702ba, 0x170f5c50, 0x35e37c93, 0x22583563, 0x550a8e79, 0x4405ac92, 0x70908639, 0x53bc2933, + 0x977d6b46, 0x184f07fc, 0xca8f4685, 0x0e819b47, 0x55c3b689, 0xf60b4290, 0xc0e97d28, 0x68557fcf, 0x9dd5b4a9, + 0x5fde6cdd, 0xedbc7d2c, 0xfd6b3f01, 0x301aa766, 0xc6f04a16, 0xbff11963, 0x09264da6, 0xb0060997, 0x82e8dd81, + 0xac429be7, 0x324689ee, 0xfc973a15, 0x6be34e51, 0xf8b77ff6, 0x283eb8c9, 0xa752c890, 0x988db10a, 0xaad03941, + 0x80471394, 0x1a7216e6, 0x56206974, 0xdc0a8e52, 0x85cb7069, 0x98c94547, 0x58ba6660, 0xa7db227a, 0x56d4662f, + 0x85c1e831, 0x2a1ac86c, 0x8ab5a746, 0x5ae9a679, 0x7aa59f5d, 0x52da7b7e, 0x65ca64bf, 0x7377b7b6, 0x7ab0aa62, + 0xa87d9117, 0x8b27973e, 0x9dafcd51, 0xd89ddcde, 0x27758969, 0x73887c67, 0xb48e7faa, 0xf835e662, 0x53a1f82a, + 0xd7f4d03b, 0xfe0acc09, 0xe7e0ca17, 0xf3572e31, 0x1be1cd71, 0x0f2fba25, 0x3084a3aa, 0xd3cbbb55, 0x572d9cc7, + 0xe1e7cb5b, 0x1f4ef55c, 0x13519ef4, 0xc55a0164, 0x2396d752, 0x8f4f1a64, 0xd67a047f, 0xf0765b5c, 0xb87611ec, + 0x46c4c0fd, 0xe7f20563, 0x1dc10ea2, 0x10b532bb, 0xc8394cd5, 0x522921c8, 0x0990738f, 0xe071fa15, 0xcff8c6ab, + 0x084ce593, 0xab684442, 0x0f2d4bca, 0xe07cae11, 0xda91c03f, 0xd5da5092, 0x8cce135d, 0xb2172deb, 0xd37fe2a8, + 0x32f72cf0, 0x0225e786, 0x940fc51d, 0x6e978876, 0xc70b1cc8, 0xc716d96b, 0xc13d7011, 0x3b6ea410, 0x70cffb0d, + 0xdf0daede, 0x9081eb75, 0x2566a046, 0x3b3e468c, 0xbb6bd632, 0xe47a0b0c, 0xe95045f0, 0xb113449c, 0x3bae53aa, + 0x059c6588, 0xa91ca3a9, 0x9bba4632, 0x00571031, 0x51525044, 0x9f3b8b40, 0x01c00d64, 0xa6f93fc9, 0x6ccd33a0, + 0xc8d4724a, 0xf42061dd, 0x8d1150ee, 0xdc2398f3, 0x55d93313, 0x4eb36224, 0xcc05f106, 0x219eeac4, 0xfe410b38, + 0x5eb769a0, 0x530a9e9d, 0xa8968e61, 0x53cb22dd, 0x9f260e5b, 0x0f2423b0, 0xf9cf62b2, 0xb9bfb2b8, 0xbb2fa500, + 0xeb084433, 0xfc1ab64b, 0xaa85e625, 0x5deb8378, 0x162dbad3, 0xc456eac1, 0x110ffdee, 0x5e2ac0dd, 0xe5646c87, + 0x6a27b341, 0xec2bb3a7, 0x91c384f7, 0xf6d388db, 0xc1430869, 0x6e9b06d9, 0x7ce0a4bf, 0xf5bd21e7, 0x8c67e597, + 0x4ff94ade, 0x12dca32e, 0xe65c28d7, 0x5b3136e8, 0x9ffb9ada, 0x922199e8, 0x712960b8, 0x52040b98, 0x05af87b9, + 0x46557b6f, 0x8197abc2, 0xcbbafd9c, 0xe18e363e, 0x04346a8b, 0x3ab46ac4, 0x7ad36114, 0xecde0496, 0xe3dab193, + 0x7daa279b, 0x9190e8f2, 0x2ad235c3, 0x0a3316b8, 0xbb4aac84, 0x6c2b21f2, 0xf8f970e3, 0x5f688d9a, 0x1fb145b8, + 0x89cffdc3, 0xe4602790, 0x635d7757, 0x6cd71a01, 0x0160160a, 0x509d8c84, 0xa3667c9a, 0xdd6edabe, 0xde21951b, + 0x8e7b8659, 0x7833b908, 0x36f49078, 0xbfa31dbd, 0xb921eb12, 0xfdf5f597, 0x3ddcb5d7, 0x2826e8dd, 0x9c5b978c, + 0xe08cffec, 0x69b32427, 0x806c0cd6, 0x6ae90c9c, 0x36e605e9, 0x11fdc104, 0x72635af3, 0x92b21e4b, 0x2b24d013, + 0x66d7a69b, 0x9210102d, 0xfb036c86, 0x6eb3f838, 0x7764f948, 0x4e09c57a, 0x63401ecd, 0x4c2b4920, 0x8bf6f533, + 0xe4936a7b, 0x5c7558e5, 0xb6d50192, 0xd3dc0507, 0x27c0bb64, 0xecc5e68b, 0xd1fe749e, 0xa806bf5e, 0x079cf891, + 0xd9df167b, 0x642a8edf, 0x8d5812c2, 0x5993530e, 0xd13af2b0, 0xe06589ea, 0xeb78438d, 0x80501eb8, 0x668bcbe7, + 0x9bef8436, 0x751f696e, 0xad496b78, 0x73bd11cf, 0x1dd552ba, 0xd1658317, 0x4cefcff0, 0xeb16735c, 0xcb1bdd7b, + 0x9c4d4563, 0x22f80031, 0xe8e5eee8, 0x6a22de2d, 0x0426f1e9, 0x0fe6a9ce, 0xfebc998d, 0x9980b9b0, 0xb45b3089, + 0xb6d8e361, 0xf93e3967, 0xef40959c, 0x323d6a7d, 0x089b9fe5, 0x9c55017c, 0x7e8adbe6, 0x7386245b, 0x5ea8dd88, + 0xd17826a6, 0xbf1297c8, 0x704a52f0, 0xd9097495, 0x3cbb55d4, 0x616a935c, 0x6a220d74, 0xfe34cd55, 0x4b26bcdb, + 0xcbc6b251, 0xfa4064a3, 0x480a9e37, 0x7d416760, 0x693bef58, 0x989e814e, 0xa4b715ac, 0x91465ecd, 0x955f0582, + 0xc3ff167b, 0x9bb13ee4, 0x23b6a9b6, 0x61b7c635, 0x07bf8bca, 0x1240591a, 0x4e81ab64, 0xa8766a3b, 0x6b6eec5d, + 0x904f9509, 0xdd7cf06b, 0xb7b5ab24, 0x9afb41d5, 0x0f9105d8, 0x28a67b4d, 0x1f59da57, 0x5027ceef, 0xba9e4be6, + 0x14633a45, 0xa32a93aa, 0x7d4d7577, 0x623bd103, 0x260280fb, 0x66ddbbda, 0x2606bf1b, 0x418cb993, 0x570e5e41, + 0x3b108d9e, 0x474b48cd, 0x35e6360f, 0x7f7b8542, 0xc7c9ce85, 0x0a3da775, 0x0778b6a4, 0x08afa7a4, 0x2c8d5b8d, + 0xede26ea8, 0xe2ada9d7, 0x1f42f4bc, 0x01fb7fd1, 0x93c2aae0, 0x7a6f848a, 0xe52afd36, 0x05a2cf81, 0x126541bb, + 0x9969c9e5, 0x35568166, 0xe50ba86c, 0xb5f078e1, 0xc64127bc, 0xef9750ac, 0xdb967b49, 0xe22b3bb6, 0x209df106, + 0x6e853732, 0xee2c4bce, 0x7e2624b0, 0x5857adc1, 0x51aca89e, 0xc50f772a, 0x000075f4, 0x2ee45157, 0x81a27e57, + 0x4ac40290, 0xb96fb449, 0x7a573f19, 0xbbceb5a6, 0xe7f54371, 0x4c421a79, 0xa8cad4af, 0x9934d00b, 0xae701a34, + 0x67678d06, 0xa305d95e, 0x6b13a99c, 0xa803ea1a, 0x7d65f049, 0xf71f0428, 0x3db999b3, 0x7c9d8e94, 0x57c22671, + 0x869230b7, 0x8f7509bf, 0x51471aae, 0x124d7261, 0x0b54a0b0, 0x090784dd, 0x0805b698, 0xaeb744f8, 0x34b80123, + 0x22002e00, 0x4073b924, 0xb5a7bceb, 0xdc5ef6c5, 0x112b3e86, 0xd8709b4b, 0xcbccc455, 0x5c4e6f51, 0x3792a5b3, + 0x2c7653d0, 0x294afc62, 0x2ee605a5, 0x1b8c6458, 0xfd42ce93, 0x094e3b82, 0x9b4974ce, 0xd9c76999, 0xd67c4000, + 0x0d1eb99a, 0x1f502b19, 0xf83a66c9, 0x4c1c62c9, 0xdd199797, 0x67511ae5, 0x70be7e31, 0x5fb595f3, 0x815d00e4, + 0x05ae26f4, 0x1a7f8345, 0x5314af59, 0xe1c05a62, 0xad234059, 0xbee192de, 0x6bfb4c20, 0x25211238, 0xb26c6918, + 0xb263dbee, 0x60d19f62, 0x8edfb109, 0xea5dd2b5, 0xe39ba1c1, 0x5ee19dce, 0xef576fdc, 0xbf8b0def, 0x10e33fa9, + 0x7bdb3032, 0x4db6c547, 0x21995993, 0xabaee60f, 0x0f97c2de, 0x0101f66b, 0x098a967a, 0xb651e9c7, 0x31a8ba04, + 0xf4fda6dc, 0xf04ce1e4, 0xd863b4c1, 0x912b0b72, 0xbdd5c2a7, 0xd440e700, 0xd2bccbed, 0x69e8ec3e, 0xa0bd4921, + 0xd0f124eb, 0xd9e9265c, 0xee5c83a1, 0xcbe28361, 0x836bb128, 0x792f5d01, 0x16dbe799, 0x21455daf, 0xee3fb795, + 0x0a4bf689, 0x6426db75, 0x56aead6f, 0xf3054fdf, 0x2b7f0a79, 0x1e6239c4, 0xb1aa0b91, 0x7436a735, 0xf7e231e3, + 0x5bb13809, 0xe20de812, 0xbd3d112a, 0xb8f2d3ae, 0xc94f5ce6, 0x909ba179, 0xb4733d65, 0xa69ae161, 0xf7acf0bd, + 0x5d5a17d6, 0x5a557da1, 0xf2c10409, 0x35d669b6, 0xa784e254, 0x1d5b7d50, 0x08afb589, 0x3c4f4a60, 0xbd04e67f, + 0x7cb24aa2, 0x253a87bb, 0xdb207883, 0xe1a25bd6, 0x5f55a892, 0x4d74c94c, 0x4f830de9, 0xd8e7b9a5, 0x353383f9, + 0x528db28c, 0x131468b8, 0x7da54a47, 0x5f9c9f69, 0xbca56a43, 0xe61a59b4, 0x0cf133a1, 0x4a33be2f, 0xfcb186a9, + 0x8e7a43e5, 0xe3e29956, 0x20782ce5, 0xfd737d6b, 0xedff8f0b, 0xc0d960ca, 0x02989891, 0xac15a7a3, 0xd4191067, + 0x81fac482, 0x0bacccf5, 0xd0e4d9b2, 0x442e13e6, 0x8b207c15, 0x706e0d5d, 0x1ca60eb5, 0x400596eb, 0x0e12ddeb, + 0xd29ed3c9, 0xeedcde90, 0x4e8926ef, 0xa09ad640, 0xada0635b, 0xda1168b9, 0xc9cff2a9, 0xdbac307f, 0x2ddbd441, + 0x5d489a01, 0x7f9d76fd, 0x8385d442, 0xffb552f3, 0xeab48c06, 0xa296d2bd, 0x9a9a08cc, 0x8d83dbb0, 0x431244b7, + 0x8a84b76a, 0xa98ccfea, 0xd8741a82, 0x3e26dbfe, 0xf12a8fe5, 0x7266cfec, 0x47a88086, 0x1074c476, 0x54bff884, + 0x47181efb, 0xc6d60580, 0xdc06b721, 0x0ed6e55d, 0x482ef79b, 0x77ff5ebe, 0xd4a98da4, 0xef0c8abd, 0x273ac15e, + 0x8f2abd7a, 0x30bda08a, 0x51783f4f, 0xbb7b351e, 0x09ab542e, 0xb617027c, 0x280fdab7, 0x9a54eb1d, 0x31d07c22, + 0x4a0440aa, 0xf2e8ccbb, 0x193d26d7, 0x766e8d6a, 0x7aa39d6a, 0x6d666141, 0x707fa0a0, 0x0f9ac9f7, 0x2bf5b1ea, + 0xabe25f08, 0x3ccde16c, 0x2d428885, 0x1cb0eb0b, 0xd58e258b, 0x6e35a519, 0xcb2afce4, 0x36d9d434, 0x9aadfa12, + 0xbd85fa58, 0x8a08207b, 0xe423bc2b, 0xeb7fd238, 0x67efcf59, 0xfe7bf6ff, 0x80d2c881, 0x13bfc5ff, 0x4c4eb261, + 0x86c8a5f4, 0x93f13d2b, 0x15638ae2, 0x23b789ce, 0xe460170d, 0xe90d143d, 0xa036b766, 0xfb2cceb3, 0x009b4c44, + 0x9242c06a, 0xaa1b44c0, 0x1ae1f6e9, 0xd6198776, 0x645158cd, 0x8735f728, 0x2fe9dc58, 0x53a02244, 0x7c759ffb, + 0xd6c7b037, 0x83326d5d, 0xee37b865, 0xfb8ea76d, 0x30fc2e29, 0x4bf536fe, 0x7da5fd79, 0x875bbe87, 0xc293ed3f, + 0xa8629c31, 0xea65702f, 0xcb61775d, 0x70b65196, 0xd68b755e, 0x4013d278, 0x7b14dbab, 0x29367063, 0x86ebdae4, + 0x78903713, 0x3ac6974f, 0xb39d9529, 0x4803e035, 0x5c3493fb, 0xd2221619, 0x6354c340, 0x5542dbf6, 0xf8e27b50, + 0x554beca5, 0x60ddd465, 0x3d5fcf57, 0x417387ff, 0x52f6c25d, 0x6d7ca604, 0x562aad94, 0x10b3dd77, 0xa280bc76, + 0x1f6e81f2, 0x0161c5f0, 0x7d0f220a, 0xdf7a47a6, 0x14011e8d, 0x4c93b235, 0x8acb0c71, 0x8265e809, 0xac37c90e, + 0x24a5368a, 0xed6a59ea, 0xe85ca83f, 0xcd20e0d1, 0xe3248c79, 0x5ea77f8d, 0x26469dfb, 0x293d5e7c, 0xf18b5c60, + 0xf2eb5510, 0x94e5e5a2, 0xfae30c03, 0xb8644e49, 0x3548f195, 0xc976a49e, 0x7ecfc2d5, 0x026238da, 0xa7b33987, + 0xb23939ec, 0x5eae9c91, 0xee789c6d, 0xdad36c65, 0x20159969, 0xa7a8b74b, 0xb6b47115, 0xccdd6b3a, 0x110bcaae, + 0x3af5f36f, 0xc579aaac, 0x24188656, 0xc185cfb6, 0xa9d26812, 0xabd3d96c, 0xc7f1b212, 0x8276b997, 0xe2f7f9e2, + 0x3c6aacae, 0xe58ddcb6, 0xdd2d197a, 0x982e4724, 0x3c44cb75, 0xa477230c, 0xf6b59ad4, 0x3f0305f0, 0xc2e93a06, + 0x3e302f8b, 0x373b0441, 0x65a283a5, 0xeaa79ab1, 0x05e84d35, 0x206d4ee6, 0xce7d8518, 0x18482315, 0x93fcee48, + 0x4f6b0f77, 0xf1766c20, 0xfc0770ea, 0x00bbecd4, 0x5be98864, 0x981749ad, 0xa36f271e, 0xd7f62581, 0x6d8ef24e, + 0x83c89dd5, 0xcef84c53, 0x0c497b47, 0xe25edb54, 0xaf52aaad, 0x04d76564, 0xb6ae4c07, 0x9b8e1c54, 0x4f116fd1, + 0xdd8719ef, 0x0a6a29d1, 0x05128fd0, 0xafc7f8c1, 0x33127ad1, 0xaefea3b5, 0xcc2c87f9, 0x1a6c5b24, 0x39454f17, + 0x71d521da, 0x49b88457, 0x7fceda12, 0x3b8b6a40, 0xa1534357, 0xfd41fa42, 0x297cccd2, 0xfc7d1e8e, 0x1d118e79, + 0xc2388c99, 0x8b47c5f7, 0x631851d7, 0x8d102966, 0xf6655946, 0x0e3911bb, 0x23a5419b, 0x778c0772, 0xa7a0dd24, + 0x4c57edb6, 0xab69a756, 0x17f75519, 0x5598e86a, 0x47c85ad3, 0x4ac76744, 0x642bbac2, 0x9c632c3c, 0x642bf391, + 0xf5cf01d0, 0x82efeffe, 0xe207e497, 0x09d1140f, 0x102cfe19, 0x288d7599, 0xce940b76, 0x4d0b1b57, 0x6b566fcf, + 0xebfa3acb, 0x31a41698, 0xf6b0e7bd, 0xf426590c, 0x3f1ecdea, 0x426c5dfe, 0xcd610287, 0x31aed188, 0x0509246a, + 0xc69810a1, 0x3766f3c3, 0x162d5e38, 0x232ca329, 0x2f2853cc, 0x698089ba, 0x74018ed3, 0x71161416, 0x7fab2140, + 0xff521fce, 0xdfed7bf4, 0x316a6eb4, 0x40b3177f, 0x30832d95, 0x9f4f8b50, 0x6ee7c668, 0x13f07e4b, 0x983d65c2, + 0x92951eba, 0x934fad0d, 0x385a6c35, 0x0041bdf9, 0x84be46a9, 0x02bccccb, 0xfa0c021a, 0x62eaa837, 0xb2879a91, + 0xc13305dc, 0x28e4486d, 0xbdde91ed, 0x9d677b02, 0x0bc3a2d4, 0x16222a3e, 0xb8914561, 0x12296aaa, 0x8143e33d, + 0x1e17571d, 0x89ba52f1, 0x192a25fd, 0xb25cbea5, 0xc8f82c71, 0x73022fcc, 0x1105e6e5, 0x9bcb664f, 0x92de86b4, + 0x13ed043a, 0x42ef178c, 0x5663ee2d, 0xb3f5154f, 0x396b8c68, 0x17807c4d, 0x29bdd85c, 0xb7a5a9f6, 0x38f5279f, + 0xcfa03fd1, 0xa721088c, 0x7881e852, 0x38143666, 0x58578393, 0xbf90c9c7, 0xb65d30a5, 0x76d5c01e, 0x7c43bec5, + 0x4964e0d6, 0x7f2d75f8, 0x87c8f3cc, 0x8ed3629d, 0x54eb6a02, 0x120d5d64, 0xa094a549, 0x83dc4562, 0xfa0f59ac, + 0xddcf1470, 0x0edd4c46, 0x7022b535, 0x9aaa4751, 0x84ac5498, 0xe4a0061c, 0x8c090483, 0xe5f5fd09, 0xfb767c67, + 0x84d4f421, 0xfcc34700, 0x376d42a0, 0xe15209b4, 0x17e22895, 0xe2a549a4, 0x05b808a1, 0x77421242, 0xcce7ccc5, + 0xbee9ec7a, 0xa7ef600f, 0xbc725bac, 0xcfa69a97, 0x1c2c7b2a, 0x2eb2cf37, 0x0aa60be9, 0xaf2570c9, 0x181ac7a8, + 0x99216e3c, 0x84572079, 0xb8215bd8, 0x05724a35, 0x68b667fb, 0x0e8c5758, 0x96841f6c, 0xce41396a, 0x34530e75, + 0xc3c5b81d, 0xebebf042, 0x3efb4ab5, 0x5c2273d0, 0x55ef86af, 0xaa6c0a56, 0x468163f5, 0x66024f1a, 0x4b47a286, + 0xaf690304, 0x893f105c, 0x091c1079, 0xd44aae30, 0x671d12d4, 0x7fd3b600, 0x4221ed3e, 0x32f9fc83, 0x0f14970e, + 0x65392770, 0x3b7dc1ab, 0x13e40162, 0x02d535af, 0x6c913cc4, 0xad409385, 0x306baf96, 0xda60797b, 0xeaaeaca3, + 0xa72aa924, 0x1eb6d635, 0x4e08044f, 0x43a793ca, 0xcd86cc6c, 0xc2c55c63, 0xc6a41da3, 0x83c0fe16, 0xcc8419f9, + 0x5ed5dc87, 0xdf00a0a2, 0xcee9570a, 0xdc294c2d, 0xef50eff0, 0x65c31533, 0x949b1543, 0x0ea0072b, 0xd6b17467, + 0x796c8537, 0x609ebf26, 0x8e78d625, 0xc62638e7, 0x67cd0248, 0xc00d5245, 0x410a7c9e, 0x00c2ffad, 0xa92668a2, + 0x39e6338c, 0x2152b43c, 0xadf9f988, 0x47b4ec4e, 0xc038cd28, 0x77f6450f, 0x0956e746, 0xa12aeec5, 0xd6700057, + 0xd6fa7227, 0x6b4e1709, 0x94d9ea27, 0x7744e9a7, 0xf1f13a77, 0x1f56c5fb, 0x779df7ee, 0xecef2eed, 0x254e32d3, + 0xfc01111a, 0x91f59e2a, 0x69720432, 0xd5ac8859, 0x82655118, 0x3f432e0d, 0x9184f4a6, 0x53a88209, 0x264f28f8, + 0x53125d6e, 0x5e4727a3, 0x36cd0793, 0xa0898d72, 0xd33ba3f7, 0x3a38ee4c, 0x407cfae3, 0x3a43b5cd, 0x1c935f26, + 0x75b7748c, 0xf706ac23, 0x47c8b15e, 0xf1f46a61, 0xe83e0eef, 0xe6d35414, 0x5ec7f5a4, 0xde0134d3, 0x1d784978, + 0x1b6d43ea, 0x7ae9204f, 0xabfb3615, 0xa240f9f8, 0x1559bec4, 0x715b6004, 0x5b016446, 0x941be2e7, 0x5c683507, + 0x84f66773, 0x1b22ccdb, 0xa2e6235a, 0x5e790421, 0xc512eade, 0xbc3c10c5, 0x5ca2c337, 0xc3419582, 0x794f7ca2, + 0x1af28d06, 0x94b107c5, 0x38a5b554, 0x9fb20c5c, 0x6513f746, 0x19c5892c, 0xd253cc37, 0x410c3617, 0x6ba45214, + 0x2334398c, 0x490c4ff6, 0x24ea054f, 0xeb3c8cf1, 0xd532ced7, 0x1857e1b1, 0x07261522, 0xdb21381b, 0x410e280c, + 0x0d363d38, 0x482dbd5b, 0x4c0d1aec, 0xe9601488, 0x466549ba, 0xf1062d05, 0xe16eb6e3, 0x48d1776a, 0xbe74e99a, + 0xa9010960, 0xbedde51e, 0xd94d3547, 0x36bf4bf7, 0x8189b449, 0x96c49ad0, 0xc6c18b56, 0x07385299, 0xd91671d6, + 0xe136adee, 0xc70e53ee, 0x5984d884, 0xc44f6eb2, 0xd0a9f323, 0xfc1ac8db, 0x23bec6fd, 0x549b76a7, 0x6b253533, + 0x1da97f63, 0xae04afbc, 0xa005ddc9, 0xe6d5d8d3, 0x39191db3, 0x400e2498, 0xbdbd77c7, 0xb8300c1b, 0x3a4d0097, + 0xac71aa8f, 0xa81a5474, 0x12cdce9d, 0x31d069f1, 0x6a128cb4, 0x548c830a, 0xabbf868a, 0x9c1445d9, 0x6d546d1d, + 0x187e0dc8, 0xc00f5e2b, 0x2f7024cd, 0xfddbce45, 0xa916130b, 0xb536692a, 0xc29982cf, 0x4daeafa2, 0xc6e8e03c, + 0x0f630f3a, 0xd2fa602e, 0x19ba4e7e, 0x8080f672, 0xde98b190, 0x9d002856, 0x3ccc3985, 0xf67a3f79, 0x615fb74d, + 0xcffe1b3b, 0xa23c94d8, 0xfb36407d, 0xf8f6b3a0, 0xe3b5d0c3, 0x8c776fd3, 0x66b1553a, 0x61bc0a41, 0x17c0785a, + 0x20425f8c, 0x7d8fc087, 0xb92fb9db, 0x007bf51d, 0xa0e89cb3, 0x3d614279, 0x59353c2d, 0xa21191f6, 0x9caa92be, + 0xa6402b16, 0x553f991e, 0xfb42817a, 0xbc28db5c, 0x31c22f8b, 0x5cbaddc6, 0x3ae05f18, 0x344cd6c1, 0x06f8847c, + 0x3d6f7d5f, 0xb4482281, 0x5460eec9, 0x4c672bac, 0xaeebd39a, 0x96ca2494, 0x51381e18, 0xd0189769, 0xb37b43f0, + 0xbca320d0, 0x3cca349f, 0xc0a722a2, 0x235de8f7, 0xc1e1b1bc, 0x33de9bf5, 0xbe73e187, 0xa9665788, 0x6fbe6b7f, + 0xf05a1ce1, 0x9f50f119, 0x4fff548f, 0xdf7f7d53, 0xd3c244af, 0x86197c40, 0xaeaa2ba6, 0x2c5dcf52, 0xabb9a609, + 0x1034473e, 0xff436c5d, 0x764dfeec, 0x46631fac, 0xf5ea3d7f, 0x9d699f22, 0x9d709c3c, 0x56e767e1, 0x6714d9d2, + 0xe39c6bb5, 0x7efa5dfd, 0xc9d3f0a3, 0x75e71c81, 0x3eecfe81, 0x9f17888b, 0x598ba8c7, 0xc40de4bc, 0x8cb42ce8, + 0x70e12492, 0x3ad6262f, 0xee85ef2b, 0xc44fad60, 0xccff2509, 0x6578a12d, 0x90778062, 0x8a88287b, 0xdb422b12, + 0xbcd0fde7, 0x546277ea, 0x1e1ff060, 0x4562b517, 0xe6cc9b82, 0x1ba032f5, 0x7bb43cfa, 0x5588f30d, 0x5859a2dc, + 0x67feec8a, 0xe88f0037, 0xd062ae19, 0x1dcf9b05, 0x1cf4cde4, 0x33929dee, 0x0239bc36, 0x66705215, 0xfc15f988, + 0x972729e8, 0x12d191ac, 0x62de0558, 0xccafee97, 0xf7a028b2, 0xc974bf90, 0x6ffcef2e, 0x847a462b, 0x25a44e45, + 0x21cfd3b8, 0xd2e2ac72, 0x4136bc9b, 0x531dde91, 0xe92fc324, 0x68415fe1, 0x4297dd4d, 0x9b383502, 0xdd777c0d, + 0xdabe77ca, 0xe199ea36, 0xdd4b78d7, 0x28aa2041, 0x0b25be8d, 0x9faa9f36, 0xcb60d733, 0xc4302b14, 0x512fb251, + 0x8bfef72c, 0x4004e91b, 0x6a66ac64, 0x8188af3a, 0x5f2426f2, 0x4373e1d1, 0xebb0490e, 0x93e63dd8, 0x5fe714df, + 0x32dffb79, 0x3c9b5121, 0xd177f418, 0xfa087345, 0xbf24a76c, 0x7027de36, 0x0b8af851, 0x552b78c0, 0x4a48b99e, + 0xecd31c06, 0xef584a8f, 0x16ce40c3, 0xde8779c2, 0xcca7207d, 0xf3b06340, 0x4dfd0f0e, 0x49e2013d, 0x91b85788, + 0xe05f62cf, 0x7732fd2c, 0x68b3a099, 0x6524f629, 0x3cae0c02, 0x26a83cdc, 0x252abbbe, 0x8e4097d6, 0x60f331e0, + 0xabd9be6f, 0x2d92a83a, 0xad68bd1e, 0xbed992c3, 0x937965fc, 0x511fc151, 0xbfeeddcb, 0xcc1e554b, 0xf820afa3, + 0x56ceeadc, 0xdbe4646c, 0xf585146d, 0xdf5bf9f8, 0x1b791839, 0xa9ed3501, 0x3883c39e, 0xcf209514, 0x7913a5d6, + 0x41918174, 0x9b2ba5af, 0x6794f9d8, 0x13c953ca, 0xa76b9fe4, 0xab138280, 0xe1e67bac, 0xe5d32652, 0xb180df22, + 0x7edb9b39, 0x84b19156, 0xbb6f274f, 0xa31022de, 0x5569ff2a, 0x8166b694, 0x30daa0bb, 0xd1091c34, 0xbe255d61, + 0x4bce1dcc, 0xa07ccfe0, 0xa3c70b8e, 0x8927d22c, 0xfa5fe745, 0x41710b60, 0x468b0c87, 0x11b3e497, 0xefa7b6b5, + 0x11ad9c33, 0xb2ceca68, 0xac14cbf2, 0x94c023a8, 0xe420b05b, 0xb4cdbb33, 0x87eaa471, 0x28bb3634, 0x34f77809, + 0x8a704d07, 0x21936b0b, 0xd2c6040f, 0x0e1cdc2e, 0x07bb1e44, 0xbc70b61c, 0x20b7441d, 0x8fe9e772, 0x7f1ffe56, + 0x3a554b62, 0x6f6a82df, 0x3f87959e, 0x7e3c8af7, 0x8d4a2cce, 0x1c5111cf, 0x47f30999, 0xdda6454e, 0x4420f868, + 0x877a7a31, 0xd062c181, 0xfe389618, 0xfe802340, 0xd0880bf8, 0x84295460, 0x3a8034f7, 0x6a77830e, 0x6e7568d5, + 0xa12ee93c, 0x5f7db5f8, 0xebee5074, 0x27b141e1, 0x9f5936c4, 0xad3bf7c3, 0xb6a51d8c, 0xd3d5942a, 0xcbf6fc5d, + 0x8e92f242, 0xa5185202, 0x0deecb70, 0x6a725114, 0x2b2262d9, 0x2ca692a5, 0xe81baa71, 0xbf0a5274, 0x4153073f, + 0xd3b7bb2e, 0x8471dea1, 0xc0fb74aa, 0x273d8627, 0x9cef8182, 0x3c078b1e, 0xda25cbae, 0x0d36b4b0, 0x0dd2fb02, + 0xa37a7567, 0x69603141, 0x6487bc95, 0x74681252, 0xbe1f021c, 0x06f6e7b3, 0x29eb6ead, 0x2c5beb3c, 0x5d31ff69, + 0x4e1bbe4a, 0x8c98844f, 0x8a554e40, 0xb180ec76, 0xe2b7e5f8, 0x8b2524a6, 0x6c1121e5, 0xe907dca4, 0x8b94ee28, + 0x935b6147, 0x3a5785bc, 0x63f2b67e, 0xd4e56b0f, 0x0ac0472d, 0x70fba9cd, 0x58cc8b43, 0xdd3ca0c0, 0x5df4b674, + 0xd15ce0aa, 0x5d030f64, 0x8cc01fb1, 0x215cdae5, 0xfd88cfbb, 0x3c215b60, 0x58d0de46, 0x7e824256, 0x2e6ab834, + 0xec8928ae, 0x839a644d, 0x8153ba02, 0x6dc0204d, 0xed57d00e, 0x7eb00c70, 0x0461678b, 0xc35bb42c, 0x2dd8ecae, + 0x04dbb26d, 0x4f2c20d0, 0x58f785d5, 0x6e36f057, 0x68393f3f, 0x0332fdd4, 0xa30ad902, 0x7e36d4de, 0x367cb673, + 0x9cf2b835, 0x2cb337d2, 0x9ba8e640, 0xc7de5e20, 0xcd442d66, 0x748e625d, 0x0b3586b9, 0x45c1f328, 0xecf54109, + 0x3d988f68, 0x0cdae279, 0x6593989a, 0x0fc50e4c, 0xd480bd43, 0x912fad19, 0x6ebdb509, 0x0736a2fc, 0x04e63f10, + 0x5e91bdbe, 0x308c6f8e, 0xa26cf4bc, 0xdf82b38a, 0x1339d08c, 0xf7730a63, 0xb9e53c96, 0xf1491e6a, 0xe5dc6961, + 0x9b26c959, 0x7166864c, 0xb9afc990, 0x36c88ccd, 0xfb6db299, 0x88d47cea, 0x9e8ece2c, 0x3deb7e71, 0xfc5392a9, + 0xf1c16560, 0x2372a759, 0xc7f11f1f, 0xd5c51b62, 0xa7d424bc, 0x78a6b391, 0xe27ab7f4, 0x009fda7f, 0xa48c8cdb, + 0xdb840434, 0xbc452244, 0x1b0e4068, 0xe6231838, 0x0663a5cd, 0xc33d62f1, 0x8e906007, 0x4ff6211d, 0xab660a61, + 0x4c68e552, 0xf2d36a60, 0x5bfa5e9b, 0x5f7c9130, 0x0d6fbb6d, 0x68cc5bb6, 0x6e3f42a4, 0xe8625f86, 0xc9f191ad, + 0xaf5b327f, 0xae5aa16d, 0xe61b712e, 0xf7e20980, 0x94d339c5, 0x4a7e42e8, 0x1a9b24b0, 0x4dcc3b56, 0xfbf4cc4d, + 0x42fc7a1c, 0xb8236360, 0x976ae771, 0x982ef1ed, 0xda2b4086, 0x3a862ee1, 0xf9df2509, 0xa76589de, 0xf53a03ae, + 0x1a898c13, 0xb5684cbd, 0x57e2cae7, 0xcb4e2867, 0x6f89a894, 0xc7feef41, 0x3951a1a5, 0x9c1104cc, 0x9c840362, + 0x81fb2586, 0x1e2097da, 0x92e304f2, 0x4e4b1407, 0xbda80db3, 0x1be38353, 0xd2d0858a, 0x63ffae9f, 0xce436af7, + 0x6c3b08ea, 0xa68d84a6, 0x2fc0ecda, 0xb71fb307, 0x240e2f4e, 0xbe36e478, 0x4419740d, 0x512b5f5f, 0x266582a9, + 0xa9935417, 0xda8d8d30, 0xf2e2b956, 0x64294961, 0x92ed02e1, 0xfab85c90, 0x48de8be9, 0x5302f22d, 0xc2a1fdba, + 0x8ceb6b5d, 0x9a5092ea, 0x2118eeeb, 0x6ca16971, 0x2ac75954, 0x0b7d8064, 0x2f76cc02, 0x30359be2, 0x5cb900a0, + 0xe6f93e1a, 0x11da0bf3, 0xd3fcceb9, 0x8577c485, 0xde5d9b35, 0x25cb3da7, 0xb93c078b, 0x173eb9b0, 0x5fa3ce0a, + 0x9703def9, 0x2037b85b, 0xfcd70637, 0xa9dfddf6, 0x81de459e, 0x61196cff, 0xc25dc53e, 0x92322074, 0x0410a92b, + 0xf8070fe7, 0xd146a668, 0xf9c81a05, 0x897dfb92, 0x68e5b3c6, 0x1b853d32, 0x6aa981d0, 0x51042921, 0x2c345385, + 0xd5ba405c, 0xe6dca4c6, 0xc3ddf67c, 0xa0db578d, 0x6744d50a, 0x7f34b1a5, 0x536df3cd, 0x1b617aa4, 0xd3a0242f, + 0xe99a4183, 0xb9186a71, 0xb24c0044, 0xae94bd4d, 0xbb56198e, 0xd66d8c7d, 0xb494af4a, 0xa403683e, 0x992e4e83, + 0x20052de0, 0xd14f1336, 0xbc79e259, 0xab6a2afd, 0xb2c4b40c, 0xa8cf1c8d, 0x119daf0b, 0x3834c5ea, 0xcea37eaa, + 0x0df01679, 0xb7f58aa3, 0x3dfa14f9, 0x7d2c006d, 0xf42b1937, 0x388547e1, 0x513fca2b, 0xf292159b, 0xbbe901d0, + 0x4159e52e, 0xffa66b40, 0xa49d5144, 0x76bb1b8b, 0xaf7c3efb, 0xc3972587, 0x7a7aadbb, 0xf2d553ee, 0xc0edaaa2, + 0xd9377941, 0x1fde3ae6, 0x875814c2, 0x4bbab1be, 0x5481ea49, 0xcd0d5c1f, 0x0ff8c7d8, 0x86769af7, 0xcd13dc83, + 0x62443444, 0xdff2a43f, 0x274e7383, 0xf51b5b23, 0xe77bb7e5, 0x8a395416, 0x790cf04b, 0xf9cf3346, 0x29a369be, + 0xf64c68ab, 0x2d2acf10, 0xf53c6153, 0x960653a1, 0x13d5e88a, 0x8ee43d72, 0xb4cb60b8, 0xbe26129c, 0x17515134, + 0xc6bd1236, 0x2d9160f7, 0x957b99db, 0x7fd7d11f, 0x350e7c2f, 0x4143c419, 0xf2af71b4, 0x8cbb243c, 0xfd8cd244, + 0x606567b7, 0x0a40791f, 0xf58efa6e, 0x2d84ed89, 0xa31880aa, 0x32444b64, 0x34363138, 0xd5c00414, 0x8a965abf, + 0x10fb3ae5, 0xb4ac1379, 0x00fe2192, 0x5073ba78, 0xa31caa8b, 0x7f11d691, 0x8c59d160, 0xcbd00080, 0xe2177821, + 0x66ebbd4b, 0x4390db76, 0xb89c9b0f, 0xd310ed8f, 0xf83d0032, 0x38f58a5c, 0xcbe60f9b, 0x7b78636c, 0xb7887e97, + 0x0c4837f9, 0xc0ed1fbc, 0xd28e6c8c, 0x81ea5700, 0x60aecf73, 0x26325203, 0x66808d6f, 0xfc293e4f, 0xbea1f083, + 0x4025e01c, 0xba41e2f2, 0x5eac5bd0, 0xdf24ecd6, 0x4f14fcf0, 0xfcd34168, 0x0958dea8, 0x3610366b, 0x0f626000, + 0xe8377889, 0xda1538aa, 0x7f52c4e6, 0x084ba63b, 0xa17071bf, 0x5f400e2e, 0x8c6c7635, 0xac356e91, 0xd6fac2c9, + 0xabd447c9, 0xc5cf869d, 0x0bcd2167, 0x5caf5675, 0x502ba1a7, 0x2b204d04, 0x6ab4ed05, 0x94b99fec, 0xfc73c6ef, + 0x0fdae0a3, 0x00aaebac, 0x7bee1c65, 0xe3a28bc9, 0xa8f5c2bb, 0x802435dd, 0x13134df4, 0x13f0fef4, 0x294f501f, + 0x7c66201f, 0xc6d765ac, 0x3aef0e50, 0x696d46a8, 0x26b5dac7, 0x64c5b350, 0x41da13c7, 0xd5d5d14c, 0x43ddfa2f, + 0x63a8ed28, 0x34f18b42, 0x8884a44c, 0x6d3a81f4, 0xdcd8b543, 0x6ba26b21, 0xa61407ec, 0xc3865bd2, 0x651a6bc6, + 0xb4a2d56e, 0xf85b9c63, 0xfe3a1a0b, 0x3b1691a1, 0x1da1fd91, 0xde880848, 0x4a9736ec, 0x7d452cfe, 0x3bc71d72, + 0xd1a0b10b, 0x90536dc4, 0xabadaab0, 0xc72111b6, 0x6e68153a, 0x72629cb2, 0x62d0fae8, 0xce3b3076, 0xa55e508f, + 0xc06ea155, 0x2fe15a29, 0xeff36683, 0x85bc4722, 0xecb274f0, 0x7533ef37, 0x45286a65, 0xcd144ad1, 0x68762225, + 0x717fbecc, 0x47d6f8cd, 0xda961387, 0x513ece3e, 0x6ad01174, 0x6ee8f0ba, 0x57a6304b, 0xf69e6f11, 0x2e870d48, + 0x881803aa, 0xc5c08a4b, 0x1fd77a5d, 0xc8f82f78, 0xc7728bcb, 0xba5541e9, 0x7d868b25, 0x17fc9959, 0x880b8eb0, + 0x7e87331b, 0xa48ba073, 0xca8cd493, 0x96299807, 0xa8a4f9c8, 0x4664a67e, 0xdade27bc, 0xdb1e9c33, 0x76ed8cb3, + 0x4f608f0f, 0x3153c8cd, 0x8ca47446, 0xa1f7f202, 0x5f813387, 0xed3a6d46, 0x5a6ad5af, 0xf8d9f8ba, 0x17fc40bc, + 0xc568a9d0, 0xa9ddcc8d, 0x10fc6ea2, 0xffe598fc, 0xfeb54c8e, 0xcdb29d21, 0x5e024dc3, 0xdff31c40, 0xb1cd4d30, + 0xb34b9eda, 0x18b5ed08, 0x1885dd75, 0x4e487e5a, 0x7bad602c, 0xd5aa0ae1, 0xa7be42b9, 0x3c8ff421, 0x8c83b44f, + 0x881b006b, 0xdb64c008, 0xa035d705, 0x7f22353e, 0x039b43af, 0x524afc66, 0xc13ae52c, 0x4ca17a1c, 0x22e453fd, + 0x23a336c8, 0xa8fef3fd, 0xde37d105, 0x2fb10fd2, 0x96a6445b, 0xb1636d86, 0x6a8329bd, 0xd935b15b, 0xdc412e80, + 0x49ce763a, 0x4cb8ec10, 0x907a6533, 0x24371059, 0xc3386a0a, 0xd8eaedc6, 0xbca4a371, 0x83647858, 0xb6fc7a7a, + 0xd95e72fa, 0x8b8109e5, 0x4ce50f45, 0xab028eb8, 0x8860c852, 0x1b00de42, 0x72ff9e1f, 0x2c858f4c, 0x9e5fdd64, + 0xa04ce7cd, 0x4efe1caa, 0x88e5f15d, 0x9fbe0814, 0x3e31f3e4, 0x9040aaec, 0x9161b4aa, 0xd5465d6e, 0x55c0dcd7, + 0x4262d7f3, 0x33a2e513, 0x589a4791, 0x3005cc86, 0x98cc411b, 0x16aae0ba, 0xb30290b0, 0x5649647d, 0x681ae50b, + 0xf52fb318, 0xee82fccb, 0x53aaaafe, 0x7f33ded0, 0x99f4fb4c, 0xc1c428ba, 0xa086d2ea, 0x425fb255, 0xeb2c8a7a, + 0x10206f4a, 0x6e7f958d, 0x7e3c19c9, 0x5285b44e, 0x8dd80ba0, 0x2e7d612f, 0x0d8c5127, 0xeaf35cf3, 0x4c674ae7, + 0xb747cdeb, 0xa9b20fd9, 0xc5a8d5f1, 0x295e2a4e, 0x77869a6d, 0x41f2b918, 0x38c84978, 0xeaf3ad14, 0xdc7d73ea, + 0x10dcfef5, 0xda1a0e7a, 0x7b3b283b, 0x22fc62a6, 0x9cfcad8c, 0xa4f3160a, 0x6e1f3a69, 0xac9a1db4, 0x1448f83a, + 0x1f10a23b, 0x33228623, 0x3877f8f2, 0x477991df, 0xb5ed3961, 0x2b69d7cf, 0x05ed0164, 0x0032e84d, 0xb45b4dba, + 0xa98adf21, 0xf0286642, 0xbbb84841, 0x3186c0c9, 0x2e47655b, 0xe8cc7422, 0x971fe1fb, 0xfdae97cf, 0xbd237e4e, + 0xf159c201, 0x3997def1, 0x72819035, 0x5675c6d2, 0xb6d30cd1, 0xcc98761a, 0x16fb5d5e, 0x615b3d38, 0x967ac930, + 0xe2e9b205, 0x3dd08d71, 0x281861d8, 0x6cacf0e8, 0xe08775e4, 0x4ccbf565, 0x62f870e6, 0x5ced3611, 0xc0b3b941, + 0x720a06ca, 0x045bc73d, 0x6da3c644, 0x56003951, 0xa0a1d982, 0x3ba46b14, 0xfab22586, 0x23a70cc0, 0x1ef2029e, + 0xaf6cd84d, 0x1febba8c, 0x01b9ee12, 0x2e93de92, 0x8a0d0836, 0x9d91eecb, 0x4f9f6753, 0x69dff907, 0x981cc6d0, + 0x8776f0d7, 0x55131fb3, 0x1dddad0b, 0xeeba01c4, 0x8d1391b6, 0x12f79ef1, 0xf08c3467, 0xfe8fd5f3, 0xdc604e41, + 0x335fbcb1, 0x96064f25, 0x1ed738d3, 0xa498d70d, 0x017a6bcb, 0x705fb289, 0xe319b877, 0xb41820a1, 0xee5b9192, + 0xbcc4fcd5, 0xba7b47d5, 0xc9ae0817, 0x6b330ebe, 0x411df29f, 0x00a2862e, 0x7d164f47, 0x9ba3dadf, 0xdaf70e26, + 0x8678f921, 0x676b4f72, 0x0d33b085, 0x6f702736, 0x1ff37847, 0x039f7549, 0x91199e49, 0x7b4dfbf4, 0xb10cb15a, + 0x48cbb76f, 0x72952a75, 0xffe89814, 0xceecff28, 0x92d23929, 0x4272189e, 0x34117fdf, 0xd4af4d45, 0xc3243f2f, + 0x05864a7f, 0x910f9c8c, 0x4b7a49d0, 0x395bc8a1, 0x3cffda03, 0x782ad14a, 0x5b73e0cf, 0x146ad5c4, 0xd5c8582c, + 0x1e54209b, 0x85fca287, 0x9cfe9380, 0x85fcde48, 0x8a1b3700, 0xf1b3ff95, 0xf801101f, 0xfea591ac, 0x478b010c, + 0xe882ad10, 0x0bdaa11c, 0xfb2502b7, 0xcc446222, 0x2ab6036f, 0xe7e73012, 0x2645349c, 0xdbd68825, 0xbbd0062c, + 0x6bf996e1, 0x89bc8788, 0xb89cd6fd, 0x19e5c3be, 0xa014c7b7, 0x5babbc54, 0x0edb4f20, 0x76017fcd, 0x6cddf2fc, + 0xa8cc771b, 0xeefd31ba, 0xa2c6193f, 0xb5dd844a, 0xac361053, 0x457f96d0, 0x7ed68d6f, 0x77e585eb, 0xb3b69b94, + 0xa589362b, 0x26302453, 0x879cfda3, 0x4e4ed67f, 0x1d433e3b, 0x6bcccfa9, 0xcda5c3ef, 0x6bb6dbe7, 0x51b840d7, + 0x97a90328, 0xb7b6b905, 0x6753aed6, 0xe77d69aa, 0xbe7cd003, 0x2c93d682, 0x49b905f5, 0x23366c16, 0x935e2169, + 0xd6b04e97, 0x351f56d3, 0x59a5eab4, 0xf01a7468, 0x9d24cebb, 0x0e32cd3f, 0xe91bdb73, 0x76ff5b9d, 0xf8f776a0, + 0x06ea75ab, 0x8de60ea3, 0xf6c23156, 0x3f1a0dc3, 0xdcb46183, 0xa9607c17, 0x41e734f1, 0x759d44e1, 0x76be54b4, + 0xf7a77260, 0x46a33e7f, 0xb668f7c8, 0x2b80f575, 0xa2b0a457, 0x4b784dad, 0xb95fea6e, 0x43e5c605, 0x88c3ed17, + 0xa964e452, 0x74a0819e, 0x8448d532, 0xbe82110a, 0x42e4a839, 0x289b7354, 0xcd5785ef, 0xd4def7fa, 0x8868260b, + 0x1193618f, 0xf8f0620b, 0xc74092b8, 0xf80dee4a, 0xf92ee3bb, 0xe9aa9e5d, 0xbbee0a6f, 0x80789b4f, 0xa6253e45, + 0x87530b4e, 0x7c583e78, 0x6d9caf63, 0xe48dc4c0, 0x26f10069, 0x7b7cc34e, 0xcc940ed9, 0xcbb78682, 0xd9359294, + 0xf7c35bd2, 0xa34637d5, 0xd42a570d, 0x692d9fc7, 0x4f1ee242, 0x05ab59b4, 0xb2a0ce62, 0x220eefc6, 0xf62a3c0d, + 0xc1c64699, 0x2b617954, 0xa5e87011, 0x42e59d65, 0x477621a2, 0xe8c724fc, 0xe5c5fa4c, 0x9d21fc8c, 0xcc5f183b, + 0x667af86f, 0x91e9589f, 0x9d14baed, 0xf22db9e6, 0x6121820b, 0xa7ff5652, 0x9e2c553a, 0x0b777a89, 0xeb996128, + 0x1a2d6d1c, 0xe3ba4c16, 0x0260f928, 0x376af2c8, 0xd8017716, 0x8fec64d1, 0xb885228f, 0xdc27f92b, 0x0859fd8b, + 0xb1babe3a, 0x944068bb, 0xe4411254, 0x12d63c2a, 0x50fc4c40, 0x7cd9c64a, 0xb9f42fcc, 0x7ffce0a7, 0x731eb803, + 0xf7ea3608, 0xeabdf32c, 0xbdc7ae44, 0x83816e3b, 0x042c0e13, 0xce43829d, 0xcb6855a1, 0x71c87cf8, 0xfb9c1c45, + 0x90d7fb69, 0x3ec97554, 0x56abc114, 0x7f4f9ca1, 0xb5d74201, 0xdf994327, 0x63c435c6, 0xb7b411c7, 0x143cf773, + 0x367022a5, 0x40b3e33b, 0xaf7dfca8, 0xc484b81a, 0x0d4cef28, 0x2e1743b8, 0xf1e53c62, 0x8550e595, 0x6a2bd215, + 0xc2718b17, 0x99880aa6, 0xf4fb207b, 0xf770fc97, 0xe07dbafd, 0xc8ba6a35, 0xc60cf4cf, 0xd8a00837, 0xd56edce6, + 0x3bbf5a51, 0xe0746567, 0x3441d400, 0xcfd471fd, 0xbe6dc416, 0xd725ffe9, 0x4f1e35d4, 0xb7baf236, 0x4cf032c5, + 0x34fafa0e, 0xda6aa0fd, 0x975491af, 0xd17e5e55, 0x61f708fb, 0x49f9c270, 0x15aa4f63, 0xc4782a3b, 0x339f73b1, + 0xb4403ffc, 0xa81a7184, 0x23d70e19, 0xa8c240e8, 0x60078bb6, 0x50e36841, 0xadfef909, 0xa71d7e44, 0x524f115d, + 0xbf2fca16, 0x4c3f5938, 0x07e9bc3a, 0xe422c1a4, 0xc8d8cac0, 0xeaef7dbf, 0xca8714de, 0xddcbd550, 0x2bda8414, + 0x328c2397, 0xc49a24cc, 0x80c4e98e, 0xac9bbb2a, 0x80caf4c9, 0x0da75fcf, 0xd907945e, 0xd03a1775, 0xf6356c3b, + 0x956ab06d, 0x2b7edf9d, 0xec0e465a, 0xe2239f42, 0x02b8db2c, 0x3ead2a3f, 0xbe56cb2c, 0x9e7ebbf5, 0x06823080, + 0xa23a98ab, 0xb9a02b7d, 0x6891aa00, 0xe4f3926a, 0xae0e148a, 0xce0b4669, 0xbdfc3d41, 0x251ef19c, 0xcef27a9b, + 0x220f28ff, 0xe0ad7bf1, 0xdaedb52f, 0xc4f46608, 0x82a72b5e, 0xe64a8cf5, 0xf7393d37, 0x1d2472b6, 0x37613eea, + 0x8f4bab38, 0x5f75a39b, 0xece81a83, 0x1ff0d23d, 0xce64bdbe, 0x6db538a7, 0x12b1194e, 0x7f5c27bb, 0x576f2923, + 0x3c292124, 0xd4f5ef28, 0x38455b93, 0x8b11d9f1, 0x295a3b8e, 0xd8d34a9e, 0xe62ad9e1, 0x1724f9f7, 0x042200de, + 0x601c6815, 0xe5d3d709, 0x54c98069, 0x8aae8489, 0x76f05808, 0x8d129e1a, 0x1bdd2753, 0xbaf1d861, 0x4c77faed, + 0x84bf58d1, 0xdceffdc1, 0xbd69f03e, 0x855a416e, 0x8a36cc6f, 0x9afe54f4, 0x619c999c, 0x39c03e7c, 0x23219603, + 0xf4661c06, 0x039e7669, 0x26908659, 0xb3c62532, 0xbde4b378, 0x3a93a8ce, 0x5516cc44, 0x67b65f2e, 0x88805a5e, + 0xaf50e840, 0xcaf545b1, 0xc2df3cd2, 0x7d533053, 0x1d9e235f, 0xfeb6552c, 0xa997a1b0, 0x1aa0c4fa, 0x6d70d98f, + 0xfa3d009a, 0xf248c54e, 0xdfd7e2de, 0xd6a475d9, 0x839bb1ed, 0xf0a4b050, 0x28347bf9, 0xc2877f33, 0xe021e049, + 0x8a7d39c7, 0x8be2e54c, 0x7fc08362, 0x70d98978, 0xc0c719eb, 0x772ccf37, 0xa3072d97, 0xdf295109, 0x83e71a8b, + 0xd24dc886, 0x017622ff, 0x6e19d1a3, 0xc84226a6, 0xaef8fa00, 0xa2296496, 0x7f54a948, 0x1f161380, 0x42c09452, + 0x4b279c7b, 0xeb0bb4af, 0x2db2fa49, 0x75170d4a, 0xca4c7d37, 0xbbb4601a, 0x21269205, 0x0039fa4b, 0xe630bc69, + 0x67bedd88, 0x08d5608f, 0x168999a3, 0x6ce602e6, 0x90f087ed, 0xdbb110b7, 0x1defb665, 0xaff05121, 0x08d48a91, + 0x660fa547, 0x96e96d0a, 0x31daba2f, 0x5bd3ec03, 0x8007d282, 0x513b5687, 0xb90ff3d0, 0xe37211ce, 0xe5c17fd5, + 0x9662cb04, 0x491f3d3b, 0xa5973439, 0xdc6435a4, 0x9d0e8f7d, 0xd98541e0, 0xfda10ea9, 0x2cd27fa4, 0x94900fa0, + 0x6589ae14, 0xaed762f3, 0x96300ff0, 0xca616426, 0x97ceb72a, 0x2a4ff443, 0xec1c94bd, 0x0548e056, 0xeab4bf58, + 0x73e1ca5c, 0x4ca96202, 0x0fbfb151, 0x74945f9e, 0x6c55db77, 0xcdd41195, 0x17630353, 0x2bf0ed6e, 0xd81580bf, + 0x2366913f, 0xfc4f34c0, 0x9a0cbaae, 0x18857f34, 0xd8177b6e, 0x14ee9c6a, 0xba239b68, 0xf131418a, 0x425a0548, + 0x12969bcf, 0xf33b21a8, 0x884436b5, 0x854e16ea, 0xd6897209, 0xb40f250b, 0x821a84a6, 0x2d11f543, 0xcfc8a3af, + 0x53c89401, 0x95af7a8b, 0x38e8f0bc, 0xa7cdeef9, 0xca6110d8, 0xd0927c35, 0x02c1208b, 0x02b2c660, 0x68874739, + 0xb0d7d41e, 0x7c68f97d, 0x8db9a469, 0x2895d1f3, 0x0eb42058, 0xf5dccd3a, 0xbb41c677, 0xf28b4517, 0xb0e277d7, + 0xaa7610e8, 0x883d5856, 0x35812db7, 0x918bd4a7, 0x65c94a58, 0x13a2e26b, 0x55ec0d68, 0x597ca52a, 0xee144d70, + 0xaf4e709a, 0xca97e0fd, 0x4fe068f3, 0x3a82370e, 0xfabd232e, 0x8749b7c4, 0x5ba05c70, 0x3a839b93, 0x32eaee80, + 0xfe650506, 0x83e51522, 0xf6a80b59, 0x19dea0dd, 0x715110d8, 0xbab489c4, 0x0b7d06f8, 0x696f09b3, 0xfed6154d, + 0xb7398734, 0xe6b6bb19, 0x7248d12d, 0x72d1121c, 0x79a6881f, 0x01553d28, 0x8fca0dc0, 0x936b7c64, 0xa803e1d7, + 0xf27687f8, 0x113cbebf, 0x1aa77da0, 0xe75bb9a8, 0xcb8960b3, 0x35938b1b, 0x3d629651, 0x03e9c140, 0x09cb597c, + 0x140a21c6, 0x16c54e50, 0xddb25d0b, 0x8eeefffa, 0x6d2a3f3c, 0x76b04ef6, 0x12cd52c4, 0x851a062f, 0x51d1d3d0, + 0xa87be5f1, 0x4960fc54, 0x161ce4d5, 0xf4472b9c, 0xd42f4557, 0x78917e8a, 0xb861a0f0, 0x3c6f54a6, 0x8c6f1b46, + 0xffa7a8cd, 0x2f75e23c, 0x66f997b8, 0x92383f09, 0xd7c5401e, 0xed6b4519, 0xc10870c9, 0x18cccae8, 0xf1cb1320, + 0xc8f3a34b, 0xeedb5f8f, 0x3e3e785b, 0x0a64a017, 0x66c1bc3d, 0x0b7a09c3, 0x09f31348, 0xd18ab0fd, 0x4b8cf316, + 0x5816cbc8, 0x84d00be6, 0x1a009e1b, 0xb4db3886, 0x3b4900ef, 0xd15167a6, 0x1fd6d621, 0xc8c99d70, 0x20941569, + 0x6b0ed1b8, 0xe30c31db, 0x410fd68f, 0x5913559a, 0x1d961a24, 0x9a79c399, 0xf87db5c6, 0x8c5e1115, 0xc96475dc, + 0xe7431697, 0x6246895d, 0x9a9c5458, 0xb24d7adb, 0xd74c7703, 0xb7181914, 0x9fa8d2b8, 0x22bba748, 0xa197d8cf, + 0xe6c22640, 0x2f2c3082, 0x5213030b, 0xc1d0ca2f, 0x59f32b0c, 0xea5b6218, 0x6b3ad4cf, 0x9d6f83ee, 0xdc86b837, + 0x31bf3221, 0x900ce1ae, 0x1cba1bcb, 0x9656549c, 0xa85abb15, 0x9e324400, 0xa8e7b836, 0x58ae1ca8, 0x4b4a00e0, + 0xefde5706, 0xfbc7cd5b, 0xf2999836, 0x8823bbaa, 0xc1eb004f, 0x975db88c, 0x7809ece5, 0x07d7a0ea, 0x459e53de, + 0x0ec0a556, 0xb4f9a2ca, 0x97e7959b, 0xfc0fdc55, 0xb051a457, 0xd46c5c5c, 0x1032b7fe, 0x23f8e52a, 0x7b506afe, + 0x07215fb8, 0xe4cb3ea5, 0xc8dd0590, 0x599c6faf, 0x074e36bb, 0x2c52c5d1, 0x1d5eddcc, 0x76b0a189, 0x6759037b, + 0xbdf98d41, 0x2745def6, 0xa6ebcdca, 0xef2e3287, 0x4d28a6c5, 0xd27607e8, 0xcf2d4683, 0x181051c9, 0x62be4771, + 0x741cf26a, 0x0255b2d3, 0xb2031ad5, 0x0d597cfb, 0xcafb37a6, 0xbb1443f7, 0x091a9e04, 0x379f63d3, 0xfa1afd3c, + 0x7599e079, 0x4f64b9d5, 0x876fe3c9, 0x9d592ab0, 0x63592be3, 0x3b912ced, 0xada3e850, 0x5e57ebda, 0xf4b46486, + 0xd2cecff5, 0x2b25e290, 0x22c8c016, 0x44d3a298, 0x9bb6d2ef, 0xed5794c9, 0x1c8cb21f, 0x5469b29e, 0xe7b40204, + 0x83132c48, 0x51e0ecbe, 0xef66616e, 0x9f12bb53, 0x11809130, 0x5475257b, 0x821c9d4a, 0xdafde4d6, 0x9fa066a4, + 0x025a341d, 0xbc111760, 0x4d20a373, 0x9256dbb4, 0xe11f9ee6, 0xa08c6679, 0x26071072, 0x1b6cef59, 0x71d9694d, + 0xac469907, 0x80768ecb, 0x5b6899fd, 0xe6f46dd8, 0x3046c0fc, 0x763e4500, 0xb324b683, 0x6a1b4311, 0x400b06a7, + 0xeddc0c37, 0xad0907e9, 0x9390136a, 0x7e9e120a, 0x9eabf101, 0x67a927f6, 0x1b9bfd2f, 0xd9750a44, 0xb336067a, + 0x1dff521a, 0x029eff53, 0xc3f7a3fd, 0x145b6e87, 0x08c058ba, 0xa0bb4b51, 0x7211947a, 0x102ea130, 0xd6c96559, + 0xe8d95ff3, 0x9f6b57a0, 0x2c9fe595, 0xffc77a2c, 0x575fa91e, 0x29ca16a2, 0x8f10f6a8, 0xd9386eb1, 0xa6f543f1, + 0x2679b2d3, 0x1a978fa7, 0x46168b9a, 0xad87068e, 0x66f218dc, 0x4e8ae8cf, 0x2221345e, 0xc493565c, 0x2a63f423, + 0x3da262ac, 0xe187c144, 0x4395a6f6, 0x476fcb63, 0xdf172a1e, 0xccb1056b, 0xcff8bcfb, 0xbecb9c05, 0x613acfae, + 0x0d062407, 0x8a23800f, 0xc0fe5e28, 0xe9b77b1b, 0x53e06b14, 0xec5a8ae5, 0x10a22c86, 0xa76e98cd, 0x0f2ce313, + 0x7248e5eb, 0x2bc7439f, 0xa5e3b557, 0x70e33ff0, 0x4e4a3660, 0x0076459a, 0x811553c6, 0xd852de32, 0x88b64efd, + 0xc356dcb9, 0x88bb6231, 0xbd171f9c, 0x3db3bc88, 0x9f169a52, 0x99e01858, 0x58ba60be, 0x37ae90ca, 0x7211ab5d, + 0x9e63aeaa, 0xa9575fdb, 0x1b92d01a, 0x993d905c, 0x7edb7246, 0x514258d9, 0xe987c1c1, 0x6ffaf618, 0x5c6cb7b4, + 0x3cf57dcf, 0x9231be85, 0x7e762d82, 0x61deee92, 0x92d5fb80, 0xa7b17fca, 0xcb25a06b, 0xbe83ade4, 0xfbec0530, + 0x3d245935, 0xf8381a78, 0x4deed623, 0x2ae21407, 0xcb652660, 0xa62200bf, 0x00ed0e12, 0x1245e0c9, 0x6b19a7f9, + 0x971ed79d, 0xcf29709e, 0x884a9cd0, 0x543df22f, 0x1623c6da, 0xe2e7b5bd, 0xb23a5b3b, 0x89adbdcb, 0x325d14fb, + 0x9223b299, 0xeebc2b7b, 0x2b100f19, 0xe43a1cd6, 0xa78dc4f0, 0x3728b614, 0xb950149d, 0x03a5e782, 0xc11b340a, + 0xfa8f472d, 0x6fe9e795, 0x70cafc29, 0xbb93f598, 0x339cf53c, 0x8552881c, 0x3709afcd, 0xa5681409, 0x0533a98b, + 0xb6c8d687, 0xf6329a80, 0x32569208, 0x3136d096, 0x29899c80, 0x9228ca1e, 0xd5cf06bc, 0xe8338c59, 0x797466a5, + 0xb06fd81f, 0x02674198, 0x23446a54, 0x492d6002, 0xad9c5969, 0xd2c7012c, 0xb4a6f3bd, 0xa5883829, 0xd7df256c, + 0xf37de880, 0xad2d90fa, 0xe17e55a4, 0xbe367850, 0x96d672cd, 0xd370fb72, 0xb553edaf, 0xae28bf38, 0x28f2c2a7, + 0xdf6ed26a, 0xfec3feeb, 0x767aeed4, 0x0c2d8e54, 0xeb422375, 0xd8d40e7c, 0x1f9f3e98, 0x28a5a44b, 0x0f6157bd, + 0x9d473df1, 0xc7a5b2cf, 0x32a2f064, 0xa201b2f9, 0xa4101ed2, 0x8fd12c3c, 0x1daedac3, 0xed6fceac, 0x727ed259, + 0x406975ce, 0xf4d63e6d, 0x4337208d, 0x7fc81fb3, 0x83a8ac8c, 0x409a2b5a, 0xf09e8ce6, 0x137ac8c7, 0x03f3bb8d, + 0x90d151a3, 0x541f9da8, 0xca52b020, 0xd73199b8, 0x28a8373a, 0x9d078729, 0x5ddced25, 0x116f310a, 0x3fa0d39c, + 0xd55cde7a, 0x530a5a79, 0xa7c85901, 0x51e3a87f, 0xa750d345, 0x78a4a045, 0xa48ea865, 0xe6763bc4, 0xb8188144, + 0xb8aa8492, 0xda73a48e, 0x3d86e10d, 0x84628a7a, 0x48b815ee, 0x15113ea4, 0x19c1974f, 0x6ac7d296, 0xad1c9e81, + 0xab6bba79, 0xdd57a3bf, 0xfdcc4d40, 0x395b1659, 0xad0788e6, 0xdd47a6c8, 0x6d0a723d, 0xf934729f, 0xeee540b6, + 0x903f744b, 0xa0351454, 0x58b14bac, 0xdf6b4dad, 0xda97054d, 0xa012f3ae, 0x5145ee2e, 0xffe65101, 0x8cb53ab0, + 0x20af3af4, 0x8b21d273, 0xe913d796, 0xec80e550, 0xa51eb913, 0x3b6dc43a, 0xc4d7c771, 0x5269365d, 0xd464d3ec, + 0x47a147fa, 0x99a9e453, 0xacc866b5, 0xbd5ff8ea, 0x978f8504, 0x455824b8, 0xf6bff662, 0x94d9035f, 0x8fae7dca, + 0x725c5180, 0x7f29f247, 0x1b559c7e, 0xcad7a52f, 0x1e96f38f, 0xac25b5ef, 0x1af6d27a, 0xd53672d5, 0x0038e9a6, + 0x358eefd8, 0xbec81d1c, 0xb7d45036, 0x08a6dac1, 0xb4ee5e9b, 0x43e53c04, 0xdf394d86, 0x7b8e2f14, 0xa2e39449, + 0xb13abc2c, 0x79708c02, 0xe8152f03, 0x88d7da6b, 0xf01e562a, 0x1edea81c, 0x34b9ef4f, 0xb9a12988, 0x004f2230, + 0x23fd6aa2, 0xd22fda2b, 0x453f1345, 0x4fb5e536, 0x0d957702, 0x02c1670e, 0x71922844, 0x0b85a07f, 0x0c16f969, + 0x26e625b3, 0xa378ae45, 0x2b33575f, 0xcae30c81, 0xec5f87d7, 0xe884b672, 0x9a677aae, 0xbb583481, 0xe88bd121, + 0xaa70aec2, 0x8effc2e7, 0x03db9ed0, 0xe6029a94, 0x77b34479, 0xaed338de, 0xcee98414, 0x28b7b8eb, 0x1a22ebbd, + 0xb0705c49, 0x6aa5924a, 0xa1cf2852, 0x6c86a62a, 0x524a43a9, 0x53c8edff, 0x8b9a3b81, 0xc46500e4, 0x80917426, + 0xe0dbd33a, 0xfab5fc49, 0x62c7bcbf, 0x3d326937, 0x48edf35a, 0xfebb46b7, 0xd525845c, 0x9406b34e, 0x8c8135d3, + 0xf47ff4e1, 0x364d49c0, 0xdc81f557, 0x93bcb1b6, 0x5a56cec0, 0xc1fe065e, 0xd3e4c507, 0x74d4640f, 0xbea8ec9c, + 0xb1ae56c7, 0x5df7247d, 0x1fdb3195, 0x13bfe640, 0x7497663f, 0x31dc136f, 0x694ef5d4, 0x0b0af59a, 0xde213d3a, + 0x050874b7, 0xe6c34313, 0x2ec535f4, 0xd28f4213, 0xa27107e7, 0xce775ea6, 0x564eec70, 0x37fa3758, 0x09c48cc7, + 0xf4da0509, 0xef136d15, 0x54ecfd9c, 0x2fbcf092, 0x44ab490a, 0xac540639, 0x7015f6d1, 0xee0f2a35, 0xecc45c55, + 0x133c322d, 0x01638466, 0x35ae3d0d, 0xc896ff68, 0x591f50ab, 0xb5463956, 0x200d2c83, 0x6835f7ec, 0xb29453c1, + 0xf394b218, 0xcea43cca, 0xc9f4d623, 0xf89802f5, 0x1d7633d4, 0xe14d2e96, 0xe2afac9f, 0x480ea72d, 0x3233c75f, + 0x4127900e, 0x117441f2, 0x25cb24ed, 0xd1b3d812, 0x24c3ea5b, 0x9e8be1ff, 0x1fd8f414, 0xba890eea, 0xc3c5ef88, + 0xbe30290b, 0x38537653, 0xe23af2bf, 0x485fbd45, 0xcc0543b7, 0x365dd82a, 0x601de269, 0xbdfd19cc, 0xba80ef49, + 0x172e2120, 0xe6eace29, 0x5ddecae7, 0xdfddd708, 0x95e1ae1e, 0xf8ebf847, 0xb4ae2391, 0x92022c90, 0x8b0f3dcc, + 0xb87f47d4, 0xccf1d261, 0xce7e8008, 0x80ea3bf1, 0xcc71d4b9, 0x22ed8d81, 0x4ed8cf00, 0x7dbdaa28, 0x9883bfda, + 0xca7cdbb9, 0x82d78704, 0x4c842463, 0x6344bbb2, 0xecb14a99, 0x6857d65d, 0xbe62aff1, 0xa4686f8a, 0xcd41828b, + 0x178979c6, 0xae8556bb, 0xf8217412, 0x0625e539, 0x496a7d88, 0x11d3eecd, 0x849c14ef, 0x608046ef, 0xef80350c, + 0x278f8969, 0x355284fe, 0x03a05ace, 0xa874ad07, 0xc7a887c9, 0x8e69a0e8, 0xc63c2aee, 0x7934185d, 0xa16ed8d7, + 0x38ca712a, 0x0ef6eaef, 0x91b50bb1, 0xcf2d2825, 0xab1da946, 0x3c39edae, 0x670b336d, 0x38c3eda6, 0xcdc25dac, + 0x26f5df8d, 0x267eea6d, 0xac06250e, 0xded7c7ae, 0xc072cbc5, 0x92c8df08, 0x77435752, 0xfae6a1e7, 0x8db46ab5, + 0x07f229cb, 0x4da73680, 0x5058c636, 0xa72dcedc, 0xec1c4b7e, 0x29a27482, 0x3c545a8d, 0xb24d1ff1, 0xc5f53234, + 0xc67c2efc, 0x1a831c01, 0xaca8fb4e, 0x3a1b4d59, 0x6c0557ed, 0x7a2563f2, 0xb1fdec37, 0xe8a54ae4, 0x344d05aa, + 0xc11db1d5, 0xad9389a2, 0x3d974741, 0xf6edfc14, 0xc10a2b7e, 0x297c3aa7, 0x0830b8b2, 0x5528334a, 0x71765f91, + 0x08886e7d, 0x1ce2573c, 0x1136d463, 0x8ec51242, 0x12a0553f, 0x6b773cbc, 0x7858cf7b, 0x31592f83, 0xdb52cd14, + 0x76589e70, 0x3a4cd039, 0x99a6a83a, 0xc8f968ef, 0xecc4a60a, 0x43e2bd0c, 0xf92d53d0, 0x1a5c1dd4, 0x509b3bc4, + 0xcc4fad1e, 0x952a2a74, 0x9be97b10, 0xb59f2ef6, 0x0de926be, 0xbb6ce777, 0xe1956b4b, 0x9a07f9f0, 0xfb13ab41, + 0x11db0db4, 0x8f3b9ffd, 0x0be6d62d, 0x9cca9d37, 0xffabb68a, 0x5ccb7559, 0x7ca6ca8a, 0x4f521589, 0xb6674a83, + 0x847dfb09, 0x9862b96b, 0xa6a5d6d1, 0x0a7c2c9d, 0xfba13a42, 0x5f1fbe1d, 0xb6f2b856, 0x2b5ea303, 0x8b7a6c61, + 0xac8b6c57, 0x9bb8298e, 0xd2ee3128, 0xc8778942, 0x53ce29ec, 0x46e2ad6f, 0x05504f67, 0x5510ed53, 0x16340fac, + 0xaf9c3b8d, 0x407d7004, 0x3667c720, 0x8e6171f4, 0x57cc8f5b, 0x46714457, 0xc2a46184, 0x17bf0a10, 0x145f79e1, + 0x858cc78d, 0x1c1d4050, 0x3df6868a, 0x798944f9, 0x38587430, 0x8c0c04b8, 0xc98a739b, 0x8ce99782, 0x77d51a2b, + 0xf3257edc, 0x330abe52, 0x43229766, 0xefd65294, 0xcde3b806, 0x28f92b0c, 0x808beee2, 0xe74a843c, 0x4572dfd1, + 0xb83c83be, 0x4c9a0661, 0x4d7d2cc5, 0x0436098c, 0xf95da1f3, 0x81de52ca, 0x3fab8395, 0x9da4ab06, 0x5a22317d, + 0xd926cf2f, 0x01445c28, 0xbae835b1, 0x0dfe0523, 0xa3bbb747, 0x5471e56c, 0x6abbd98b, 0x4e25b624, 0xc1210152, + 0xdf5d55cb, 0x43a2227c, 0xe9a660d5, 0x6faf20d7, 0xcefd61c8, 0x27467f32, 0xbdc3a81d, 0x7472b936, 0x279fd9d0, + 0xb185f0a4, 0xc946383b, 0x3cc78c7c, 0x27a73dca, 0x51de7ff2, 0x6a1b9f49, 0x4d131e3c, 0x1cc87690, 0xd3a572ac, + 0x7a205196, 0x592f3856, 0x1ebe04b2, 0x8c316ad2, 0x0841b376, 0x6de55429, 0x061918ef, 0x56b20b36, 0x2ef2c61f, + 0x197d8d8f, 0x93a0100e, 0x3ae5cc29, 0x95a4f6dd, 0x9dc46999, 0x1f56f59e, 0x9d317589, 0xd83ab6c5, 0x9184ded7, + 0xf859634d, 0x61953a23, 0x129c58d4, 0xbbf33e66, 0x14e02fd6, 0x3575b153, 0x7f3394e9, 0x26c4abed, 0xf053ab8a, + 0xd01fea52, 0x8052535e, 0x012634d3, 0x3edddb7f, 0x3eaebff8, 0x5674b539, 0xfe4dbe7d, 0xff7c804e, 0xcdf55bd3, + 0x3c6e1242, 0x1a89363f, 0x06e4428c, 0x9801d99e, 0x6facd82a, 0x9e3e5f38, 0x08c7bcd6, 0x10648d5b, 0xae104c1f, + 0x6a6a6e21, 0x7f02c98a, 0x0bb7ef4b, 0xc09dee56, 0x2c89aa41, 0xddc03328, 0x5b3ae113, 0x8eb758cc, 0x90ea2d7f, + 0xab81e441, 0x11cfd9ac, 0xa25f2e47, 0x85235f19, 0x2249f46c, 0xfaae61b1, 0x535a0de4, 0x0389274a, 0x16ffed21, + 0x397e76a1, 0xab46d702, 0x67f5c080, 0xeb0f8622, 0x5c06a01f, 0x2eb84e3c, 0x5b70c627, 0xeb405923, 0x3bcb31b4, + 0x85638029, 0x0ab9937a, 0x9004889d, 0x540aab5a, 0x6b0c6006, 0xc0c7948c, 0xe5c34261, 0x4a799b87, 0x282ca86a, + 0xeda43ae3, 0x92d0d821, 0x8b2476a8, 0x97e0e182, 0xbb8a5944, 0x7e40fb48, 0xb0ebe010, 0x7ea19e81, 0x29ce5618, + 0xbedc3f8c, 0x7411e8ee, 0x089d140d, 0x40a80a6a, 0x7d111081, 0x7eb46c0a, 0x2f8d8619, 0xe35a97ea, 0x4c365d38, + 0xde7829ff, 0xaef83c44, 0x2e4d47fe, 0xab44b434, 0x149f7706, 0xf67850e4, 0x162f295b, 0x1dfcae00, 0xe58a80a7, + 0x771155bd, 0x4934cf4a, 0x85330b8d, 0x82d61ff8, 0x561cb8d0, 0x20424a53, 0x12fa43c8, 0x7609a879, 0xb4a85db4, + 0x3c7f7a26, 0xa1a67b20, 0xc303c0d1, 0x82360fab, 0x49fbbb72, 0x3dce6961, 0xc054cc30, 0xef782955, 0x6204b82c, + 0xd611920f, 0x3ea63388, 0x370f555b, 0xb03e389d, 0xce6d79fd, 0xdd7d8857, 0xeb1e9cfb, 0x449e6d7e, 0x6bebb990, + 0xeb718581, 0x3902ebc8, 0x4bbd2af7, 0x2351422d, 0x3dd64a05, 0xaf377141, 0x69936521, 0x1a6a5165, 0x0ef8f20b, + 0xe320fc43, 0xffacada3, 0x0ac23194, 0xe7536678, 0xd6708606, 0x2aa02255, 0x1dcfaff4, 0x29539fe6, 0x82ad3dcb, + 0xcaad3de6, 0x0e982b90, 0x7520a334, 0x82d9b1bd, 0x0eb3175b, 0x77b17f07, 0x108d8106, 0x7272bd29, 0x53a23559, + 0xf4a9f8c8, 0x2c15619c, 0x3028b98f, 0x6a0b6bee, 0xed6f5ceb, 0x55b7de82, 0x92c1e897, 0x35dda81c, 0xde5d336a, + 0xa0192396, 0x07346098, 0x04971d6e, 0x605b58a1, 0x9e9a65c9, 0x0e56309f, 0xa41db08a, 0x0771603e, 0xb3a68e04, + 0x94254a6d, 0x3c3ecc70, 0x9fa30e5d, 0x73e3ed87, 0x3067d8ec, 0x22e2d026, 0x0e70794c, 0x0ff16c20, 0xad6be4a8, + 0x684aafe0, 0xeffc755b, 0xcf032c71, 0x5520d1e7, 0x20c1a423, 0xc0277bbb, 0x9ca8c3d7, 0xa541d63f, 0x9e6a90bc, + 0x3639325c, 0x4c8c3480, 0xb79eba1e, 0xecd4f638, 0x4a6d677d, 0x710cb390, 0xedca21df, 0x0e9c8bce, 0xe4c66410, + 0x90ab8d60, 0xe029b8aa, 0x7730726d, 0x5c76979a, 0x5db9bd80, 0xcabf11e4, 0xb8691e13, 0x30b0310b, 0xf7816906, + 0xc4435e28, 0x968bc389, 0x96e6894c, 0x3ae32432, 0x07c1afdf, 0x239c0ad2, 0xaed7d898, 0x42d8c4c5, 0xf21263e9, + 0x6cfb52e8, 0x22e5e556, 0xb812e4f5, 0x3c4e0eef, 0x973af9d2, 0x8458ae91, 0xcdf7d85d, 0xbb079212, 0x756d0e7c, + 0xd6ccac2a, 0xfa422c5c, 0xb275e839, 0xb9de2dea, 0xd6c0b413, 0x85915b2e, 0x5ec8688c, 0x81e92b19, 0x9ca85dc8, + 0x2a6dc5ae, 0x9b17b05e, 0x389b12f7, 0xe778c7cf, 0x3a6d9221, 0xcc51b60c, 0x83e4dbcd, 0x8211aa18, 0x5f82eb77, + 0xc2c805b7, 0x9fbafc3a, 0x45664653, 0x4855cdb7, 0xb3f7211b, 0x2aa8757c, 0x063ac494, 0x8b809001, 0x1ac40e26, + 0x0a0dd4aa, 0xade46e52, 0x060b9327, 0x7c3cc1d1, 0x760469aa, 0x615bb404, 0x0e40db93, 0xd88f8cfe, 0x2b247fde, + 0xc90b4e9e, 0x23c3542b, 0x0f8b180a, 0xd79ca325, 0x2a1ab524, 0x638f7736, 0xadf4886a, 0x5d55f165, 0x8bbfceb9, + 0x7df6bb90, 0x8f4afba0, 0x060a8222, 0x39285d7f, 0x1b93c90b, 0x228dcbe8, 0xdcf7e752, 0x90e6c2a0, 0x35928060, + 0x3294c877, 0xa09ca7c6, 0x9ecd50a9, 0x4e0151c2, 0x8d73ad64, 0xfee6a43f, 0x5268d243, 0xdc139246, 0x47c6c0e3, + 0x944d1200, 0x2c467976, 0x91713893, 0xba878b7f, 0xf2e59dae, 0x36de733f, 0x27ed56ca, 0x656a684d, 0xbd50feaf, + 0xeb697528, 0x1383f93f, 0x569d5753, 0x3196a4ab, 0x5859d6bc, 0x7ada39da, 0x3ecf9192, 0x67010f87, 0x9152e1ac, + 0xaa2c6655, 0xe24945a6, 0x47e025c5, 0xff656836, 0xb257873a, 0xaf604652, 0xbc891b6a, 0xdb6be552, 0x6bd0c596, + 0x9d393b68, 0x68999cb6, 0xbfea5c67, 0x2505cb3f, 0xd374de46, 0xb6710303, 0x602e5555, 0x00544b95, 0x872b0991, + 0x929955dd, 0xe08636e8, 0x33fd2f6e, 0x3f164c1e, 0x5c514e29, 0x39ea3bf3, 0x7bc5e929, 0x2ec6dfdc, 0x6d292d69, + 0x980f7ad3, 0x1fd1376d, 0x300ddbaa, 0xea9519b4, 0xabfa5201, 0x36c34e3a, 0x17a70e61, 0x52a3a905, 0xf5ee4892, + 0x5df17650, 0x26952ff9, 0x9d8b4b6f, 0x1f122990, 0xcf52561c, 0x4e883dcc, 0xd929d4df, 0x31ba093f, 0x970f2d2b, + 0x8757bbaf, 0x4cc2b11e, 0x26921335, 0x4e4496cf, 0xde3a0e81, 0x1b84a26c, 0xbcd7739a, 0x8a349677, 0x7c56464a, + 0xad904ed8, 0x5b927a4d, 0xdeaebcfd, 0xe9dba588, 0x740c1f47, 0x3586c1b0, 0x2dafb567, 0x58aa7420, 0xc314b3b2, + 0xae044173, 0x0520ef6e, 0x9362c12a, 0xb8671055, 0xc335daff, 0x6ad01cd9, 0xaec994ab, 0xaeb6e1a8, 0x4b4c5685, + 0x4b8a9d98, 0x2ce32d6b, 0x5b98c190, 0xe7134034, 0x3e91edaa, 0x4e992be4, 0x8ff9b66b, 0x9adc05a5, 0x2e02f92e, + 0xd00de4f9, 0xa179cd04, 0x2a4b0bb6, 0xde19b563, 0x40d4a1c2, 0xa23fbe41, 0xe67d0a31, 0xa31ffd3c, 0x47d1c135, + 0x0b34d262, 0x0750a490, 0xa9c43c19, 0x9096f997, 0x959801c0, 0xa4697e57, 0x0ecd28f4, 0xc993c42c, 0xea12eea0, + 0x282ad1c6, 0x07ceebb2, 0x9b5601d0, 0x90edef1b, 0x01fa5e95, 0x1c01e27e, 0xe7e2a744, 0x0389de74, 0x90e55ffc, + 0x88db7da2, 0x27e68258, 0x5ae9e11f, 0x8935ce41, 0x62524042, 0x7c7d8efb, 0x77dc04e6, 0xcbc0f6b7, 0x295f78b5, + 0x81a41a51, 0xa74591a8, 0x5bc9e81e, 0xa00634d1, 0xe68ebcd9, 0xc1b388e7, 0x7beec5fd, 0x5aada265, 0xbada214c, + 0x78b0df69, 0x903a0c61, 0x2c1f9fbf, 0xdd649220, 0x18a2be2c, 0xb28d3881, 0xc5dddd43, 0x133753a8, 0x03189453, + 0xd98f2db7, 0xf3e25cca, 0xe9e51ce6, 0x166af1b2, 0xc90ec16d, 0x50ec9ad7, 0xc0f0c092, 0xdf474beb, 0xe435b611, + 0xf4eda995, 0xce99174f, 0xec909c26, 0x3ef8f879, 0x6cbed0e6, 0x0e7b047e, 0xcd326e76, 0xbc120e93, 0x98611472, + 0x55551e00, 0x08be0849, 0xed5b8adc, 0x462d8da8, 0x090a3693, 0x38c48599, 0x213c26b3, 0x45d96a13, 0xe85d1a8c, + 0x71c0b105, 0x1b70428a, 0x76d2d705, 0xaf3be722, 0xb1701d56, 0x03fe1114, 0x61e81751, 0x5c502477, 0xc36fd671, + 0x3d015620, 0x2c8f4382, 0xc6e3d8a4, 0x54814a70, 0xf9463fa9, 0x1c952d43, 0x0d2806b5, 0xc8eeac28, 0xc975ebb0, + 0x9dbca1c9, 0x6e875e5c, 0xa64e17e5, 0x43632ef5, 0xa35b843a, 0x26180c72, 0x0e78fb71, 0x3bd16f85, 0x34d40bba, + 0x0a31539b, 0xfd71aa27, 0x6d43099e, 0xe0be740a, 0x6fae30bb, 0x571805c9, 0xe7b57b0a, 0x637cdfc8, 0x11576b28, + 0x03b0d16f, 0x29546cc9, 0x1df5e764, 0xd19264e0, 0xe30ba1ed, 0xc4ac4b34, 0xfdaa9e20, 0x26833b2e, 0xd3e53d12, + 0x66dafd8f, 0xac7809cd, 0xe9b6d700, 0xde2020aa, 0xa14aad42, 0xd4f0e3c2, 0xe8e7cb09, 0x9b16dc32, 0x62019352, + 0xeaa749ba, 0xc6d64aa5, 0xca651d2a, 0x2eec85c3, 0x605aa7d6, 0xff88ceba, 0x777f5f25, 0xe20ca4f9, 0x03a46d2b, + 0x0852664d, 0x80c2b35c, 0x3dfcd37b, 0x1de68afb, 0xd78bbe11, 0xca2164a0, 0xca3d6f0b, 0xf05893b3, 0xd22d5e67, + 0x2447aeea, 0xcb47e4fa, 0x661fa42d, 0x0deb1ccb, 0x8f1e0b61, 0xb4ce55af, 0x07c3e4e4, 0xcc262dc6, 0x72064b77, + 0xae4b6a68, 0xa0af4d27, 0x5f58ea08, 0x2ac40671, 0x27458225, 0x8d31b2ad, 0xecd2ce0f, 0x92fedc1c, 0xb3029fde, + 0xdc60422c, 0x077a7dc6, 0xf7ca286e, 0x86f6f64c, 0x3190c41f, 0x9ea0164e, 0x24911512, 0x5b376889, 0x16a10c70, + 0x87dafeba, 0xdeb72a5c, 0xcfbb3199, 0x472b7cd0, 0xe58d9c95, 0x0b8cbc31, 0x5cbc3f36, 0xafe9b5a2, 0xc82e7455, + 0x768c9dd1, 0xf88361c0, 0x8e6bd269, 0x6f67f841, 0x7b8844b5, 0x2186cf76, 0x17634f58, 0x6ed7185f, 0x18adc750, + 0x820bd17b, 0x1b595a49, 0x90220954, 0x4bccc6fb, 0x2501b304, 0x06a35132, 0xb6ac38b6, 0x6633eeff, 0x0fcba745, + 0xf2eacd2a, 0x43bc5289, 0xf6a0cf66, 0xb648fb0e, 0x55fd8327, 0xbcc9da4e, 0x10bd0700, 0x0ec1ea52, 0x149d27a3, + 0xe1bed872, 0xac6f26ce, 0xfc6a94e7, 0xf4402a26, 0xdec1ed66, 0x2adafb3a, 0x3c740af7, 0x2e2c0b73, 0xbf273f75, + 0xd4e34584, 0xaa1f0176, 0x17cd9d53, 0x83b39546, 0x7e2288af, 0xf5e8b251, 0xf9e9a36b, 0x0854688b, 0xa9da844b, + 0xe2ea41a4, 0x6c16afb1, 0xb91698a3, 0xdae4c7b7, 0xcd8693fa, 0xd4f9e8bf, 0x5c08f326, 0x1eb8a700, 0xf9269fdf, + 0x72ca1506, 0x6f3d8c26, 0x95d1b5a3, 0xe4092d93, 0x0fda91cf, 0xef25b44c, 0x93a14264, 0x3c6b11e0, 0xffcc5b02, + 0x2246e553, 0xb369b5f3, 0x92281e1b, 0x81d766f8, 0x2b679d4d, 0xd61ac240, 0xa047eefc, 0xef06aef2, 0x75c0f372, + 0x715cabdf, 0xe8743733, 0x1984e662, 0xd5c00f6d, 0x8666f59d, 0xbc2eedb5, 0x19582b5c, 0x35bd3665, 0xb5a8577e, + 0x6e183d57, 0xac40c2ba, 0x07930a32, 0x22fc621b, 0x097b159e, 0xc5df9e97, 0xb44118a1, 0x30207fce, 0x6c3e783f, + 0x91d2cdbf, 0xffc2a028, 0x969ff841, 0x42873cd3, 0x8ad49d8f, 0xa9dc6191, 0x58c0b089, 0x010bd9d0, 0xdb223287, + 0x2dba1d67, 0x0b2816ee, 0x30b98c92, 0x7cb7aa9c, 0x612673a5, 0x3be6abbd, 0xe598c417, 0xf0f59dc2, 0xb362cfe4, + 0xa9a287b3, 0xf4d4ae02, 0x669b6990, 0xb716d2cb, 0xcfb9e249, 0x24a8d7a8, 0x6097ad8a, 0x40b2ee01, 0x62913795, + 0x780613fb, 0xaeb90898, 0x55519efe, 0x319909e3, 0x5575be7a, 0xa640e750, 0xc882f97f, 0xd271dd28, 0x1f671b53, + 0x04fc742d, 0x92d67894, 0x0a66da9c, 0xc425e86b, 0x7e303458, 0xd0be6ff0, 0x2134606a, 0x5d059230, 0xc4622765, + 0x76dbdd95, 0xf8c5ddc4, 0xa354af0e, 0x9ab8530b, 0xa00aa35b, 0x3a842918, 0x1db1617b, 0x2caf6ad3, 0xeccfa31c, + 0x47d9525d, 0xd69faab7, 0x6c555ff7, 0x2d095b50, 0xda01d668, 0x7bb915ca, 0x35664c45, 0x0bb118e5, 0x858fd0a4, + 0xac7ec342, 0x4449215e, 0x0c0f1e9e, 0xd802b934, 0xba299385, 0x59954c65, 0xf6ad168c, 0x9f0692b9, 0x0ea7078d, + 0xd81b1cef, 0x606c5ebb, 0x31d9d171, 0xaeb5a5c1, 0xf8409a4d, 0x72251fe2, 0xa0766b1a, 0x0da6c1c7, 0x24d51f48, + 0xc4749aa9, 0xd5776ce2, 0xac1c6d3f, 0x96f111ec, 0x0f52cb7d, 0x1db35aea, 0x883c3d54, 0xbf78f9f6, 0x6f3d892a, + 0x31af2764, 0xd1b89708, 0xd5e3702a, 0xf40e755a, 0x6bdcb7eb, 0x92f616a2, 0xe8111e86, 0x1184823f, 0x71985461, + 0x5fe40173, 0xd4ace5ab, 0xe810bde5, 0xf58d22cd, 0xf3d6842c, 0x71a4573c, 0xd8e26942, 0xf75773f5, 0xee325bc8, + 0xc580a46e, 0xfba2f0a8, 0x3b4c2301, 0x61f3cd4b, 0x5a3b4d58, 0x3a3b51af, 0xe7e57c64, 0x1831533e, 0x210a6b62, + 0x6bb2e47b, 0xa5846879, 0xe38aafdc, 0xbe9069fb, 0x7418467d, 0x2d0c7f18, 0xd8982265, 0xd206ec53, 0xff91c632, + 0x458a00c3, 0xd4ba69cb, 0xec84f9de, 0x85f82c61, 0x38e1ceb3, 0x1040decf, 0xc132f4e5, 0x601d567b, 0x455afbcb, + 0x401e21bc, 0x26c37519, 0x08863c5e, 0x9542e46c, 0x00f7ded6, 0x76003c85, 0x654f2bd2, 0xaecbbc37, 0xec3c7d0f, + 0x5f4281df, 0xaf9909bd, 0x5053c5a4, 0xa187ea01, 0x0d5b5ac6, 0xa5b511fa, 0xc183fb4e, 0x8d1f475d, 0x12b6ba21, + 0x0e37aa5d, 0x68269d68, 0xd0c355e6, 0x7c8cc9e1, 0xa2f0f5a4, 0x5c227574, 0x4d14148a, 0x2773ff78, 0xdf340278, + 0xd83f52b8, 0xd50b7d30, 0x6f2e6d3a, 0x2b483942, 0xede1c291, 0x79051cdb, 0x009a6252, 0x6cb0875b, 0xc980bc84, + 0x4a703060, 0x1bce31c3, 0x2ec25db7, 0xfff7c414, 0x2d12df83, 0xb8285840, 0xb2f74640, 0x521a322c, 0x8473708a, + 0xf8529e6a, 0xc83dc387, 0xad7e8ef5, 0x9c42662d, 0xae47700d, 0xe3ef57ed, 0xf809c62f, 0x336fe523, 0xaf86300b, + 0xc013bfd5, 0xd9a1558e, 0x7b91f83b, 0xda244a83, 0x764d4136, 0x8301f9e0, 0x868315dd, 0xce0ab445, 0x1e6544b2, + 0x847456e6, 0xad34d3d5, 0x5d30c72e, 0xdf1a4247, 0xda69995d, 0x507a14c0, 0x1439c8d8, 0xe91012ed, 0xb583056d, + 0xc09db61c, 0x4afba039, 0xcb75cf7a, 0xb17ac11f, 0xea802eb3, 0x1e0aa8ae, 0x4254410f, 0x1b580886, 0xd919dd1b, + 0x1dd64ec9, 0x0e6b7fc6, 0x5894b6a7, 0xf3035858, 0xb2daa1fb, 0xa4830790, 0x1da8d481, 0xa6e01805, 0x9d366612, + 0xd5604f3d, 0x5e8184dc, 0x1a573d0e, 0x42377647, 0x419d5829, 0x949d7751, 0xd9bd67e6, 0xfa476a4e, 0xf287484a, + 0x46ca88e5, 0xe122a64b, 0x53176742, 0xb14a4049, 0x70d4a0df, 0xae40238a, 0xa4378b18, 0x622280f2, 0x2f6463da, + 0xc5cfa4f7, 0xa6eb715e, 0xbb5cf6ff, 0xa0a6bf16, 0xc06310ba, 0x1a0c6419, 0xcf02b491, 0x1f4a5166, 0xfe658105, + 0xd6277996, 0xf77cc377, 0xbe42f6a9, 0xfb32c9c9, 0x6f279199, 0x558c366f, 0x4fad74c1, 0xb3b6931d, 0x194f8fb5, + 0x082fac1a, 0xa65e29ea, 0xfa0285c3, 0x8529ca7a, 0x0bc8957c, 0xba830359, 0x9e14bba1, 0x9fdf852d, 0xd172a2ad, + 0x1f437b51, 0x973e939a, 0x0529ed9c, 0xba0a336a, 0x6c915441, 0x0e4eb44e, 0xf2a02864, 0x6f38d0f2, 0x7c604389, + 0x0ba11be4, 0xd0887d25, 0xa360aa8a, 0x24862200, 0x2d292741, 0x09887390, 0x46f22286, 0xd5a4ebd6, 0xe5318b89, + 0x1865e950, 0x9fe0601f, 0x54fdba6b, 0x478c44e5, 0x740434c3, 0x1de28af4, 0x13a6fb6a, 0xeb39c636, 0xf316f18e, + 0xc15e7903, 0x2bd25cb9, 0xc217205c, 0xb7904223, 0x5b918ec1, 0x8b34dd09, 0x22269af1, 0x258b7d0c, 0x2219fe07, + 0xca294c14, 0x2dad3ec9, 0xc6ceeb2b, 0x7eb5b520, 0x43f3866b, 0x236d5029, 0x02127eff, 0x9675adcc, 0x15d1b05e, + 0x29714f55, 0x2bf3c269, 0xa23d82c6, 0x2468d580, 0x20210763, 0x37e545c7, 0xe149c5d1, 0xbb758977, 0xf63bcc54, + 0xcf67a94f, 0x8100abe6, 0xc8eb1e42, 0xb3917737, 0x21d9ce34, 0xb2fac94e, 0xf313d7ce, 0xa6a29910, 0x798aceba, + 0xce80cc53, 0x8bd3b651, 0x05ca87bf, 0xbac697f0, 0x7a5ee286, 0xe5778b7b, 0x5a5a0ae9, 0x4b820466, 0x0a401883, + 0x90bc0f00, 0xb06aae40, 0xe665887b, 0x9ea6ef01, 0x4ddf6a75, 0xbada72ce, 0x30865362, 0x61a08dae, 0xb3a30916, + 0x5054908e, 0xa85045d4, 0x0ff340c7, 0x04fbd6b5, 0xcbef852f, 0xf2f77b26, 0xf2c7db2e, 0x7173fb17, 0x887acb51, + 0x623808d1, 0x7fba9f1c, 0xeffb7d1a, 0x8681ef52, 0xf4fec47d, 0x320427c0, 0xfe4f29d7, 0xd45cc974, 0x3e5a129e, + 0x7419c8a5, 0xe7373edc, 0x64497c88, 0xb0fa0bc0, 0x98821b6a, 0x734df033, 0xdc3f4081, 0x0e1fd6e9, 0x995e9021, + 0xc5f9a5c3, 0x8c209683, 0x14e17375, 0x4452c551, 0xe1df2024, 0x45f8b48c, 0xe371ec16, 0xefda5ba7, 0x725aaa5f, + 0x9b6831a3, 0xcee3b2a2, 0xe9d0c61b, 0x8878b826, 0xc2e6294b, 0x6871575b, 0x60ae2f6c, 0xf50e86df, 0x1fbbce98, + 0x1eaf12c0, 0x5fe661ff, 0xea0a1888, 0xc560e5af, 0x4ddb5a60, 0x7668ca6b, 0x22cb148f, 0x16c3b450, 0x3df0e8a0, + 0x202a6e26, 0x1024b4d3, 0x56fcd3b6, 0xdabb39be, 0xc2b879d8, 0xc967d1d2, 0x59144aa4, 0x60a6b847, 0x36909feb, + 0x1cd80451, 0xdb072a3e, 0x75a80f3e, 0xa5b5c3aa, 0xdb09eec3, 0x17dcdeec, 0xbf617af2, 0x26f3bd64, 0x7a473b91, + 0x381a5233, 0x161875c9, 0xbda70d69, 0xc4848514, 0x93ac2d13, 0x414a1f78, 0x86090d38, 0x9b5691b2, 0x5457b32b, + 0xbebad48a, 0x28fb72b4, 0xa4680f33, 0x65cbe405, 0xad13a766, 0x07cfb5a5, 0xb56494ea, 0x32032481, 0xbe25b1e5, + 0xc07cdbe8, 0xe6ebbd6d, 0x8bf2362b, 0x454ed80e, 0xf5faae56, 0xc6144bcb, 0x1ecfdf89, 0x4a3c6fe0, 0x4a443d6d, + 0xd0789617, 0x241b75b1, 0x9bcdedb9, 0x37dcbc45, 0x6065808d, 0x4c3128ae, 0xc08e541b, 0xb1aeb3f8, 0xdf10d258, + 0x3b645717, 0x1408be98, 0xc554d80f, 0xbd8cafd8, 0xc7459f21, 0x49f067ed, 0x4e7e41dc, 0x5aca534a, 0xd5fe8dda, + 0x61c757f4, 0xd82a48f7, 0x22b667fa, 0x67ca6243, 0x12a42d11, 0xab1c5817, 0x9062867a, 0x0881d1b9, 0x2f64ecbd, + 0x681f7175, 0x83e5d609, 0x446f0c5b, 0x60c04f8d, 0x46140225, 0x538f1e8c, 0x73cd2c1b, 0x0372fb30, 0xc1f09d99, + 0xa9128c91, 0x4056fd2f, 0x74c8cbd6, 0x91618c0e, 0x7627504b, 0x9a516850, 0xd4ed6859, 0xe8d9ca7a, 0xc19e9864, + 0x1c0e6ff4, 0x94953309, 0x364d2919, 0xcbcd8b58, 0x353135f0, 0x78cbfa04, 0x21ef52e7, 0xdeaa58b2, 0x30626569, + 0x5e70074c, 0x6207916e, 0x97355caf, 0xa9a9b13c, 0x5a9fa630, 0x66916997, 0x27d67978, 0xcae436c8, 0x0d729c47, + 0x555ee737, 0x1d5e63e3, 0x98033a09, 0x8fd052d3, 0xa5d2f615, 0x2ed82d58, 0xe23e4478, 0x767139cd, 0x07b1f47a, + 0x6b78a1db, 0x3bacee0d, 0xd7b4290d, 0x84797e02, 0xc1c6f7dc, 0x51bb41e6, 0x29f607ac, 0x0d56c058, 0x935601cb, + 0x232f61bb, 0x17da6db2, 0x62ac2a07, 0x9c451bf2, 0x6bf38f24, 0x7934982f, 0x421fcb47, 0x4ff4ff03, 0xc2731398, + 0xc14524a5, 0xd079ab60, 0xcfeed0d8, 0x7dec8b92, 0xaf54cbe2, 0x5413ad7e, 0xfe64c3e0, 0xede2be9f, 0x2bd4090f, + 0x992e94f4, 0x0eb26cf5, 0x537ae38f, 0xe0d4363c, 0x25e5324f, 0xb4185d90, 0xd9fb9288, 0x4030af51, 0x1d4a0a6b, + 0x8e373237, 0x3c6782e5, 0x19c699d7, 0xe005dbf0, 0x2ef49ee7, 0xe4c3a7e9, 0xa23fbf69, 0x6c63c496, 0xd7f81dde, + 0x393ba9d0, 0x92b3c24a, 0x75cf2b44, 0x98520f5c, 0x56249beb, 0x28ad1d2f, 0xd16ee545, 0x7e91d09f, 0x0bc2df71, + 0xbabb54cd, 0xe4205c2d, 0x873ac5bf, 0x646d723e, 0xecd14965, 0xe1159698, 0xe9cf0856, 0x713acab2, 0x4bf0a12f, + 0x90ee3a5c, 0x0a0ba5b5, 0xb3c0948d, 0x1607c839, 0xdc3cd425, 0x57fd97df, 0x4913a9f6, 0xbd917ad8, 0x7d14b03d, + 0xdd310232, 0x2df03d1e, 0xa500f653, 0xd9b04b9e, 0x6227b518, 0xd2e58b6f, 0x17f1263e, 0xb5c832d4, 0x382104f8, + 0x8ba8b319, 0xc5d6b5d2, 0x3cb07f68, 0x248b5941, 0x3acd7623, 0xb31c08d6, 0x9ade7ca3, 0x00833426, 0x09206716, + 0xd7ece51d, 0x71ac5d9c, 0x2fadc379, 0xbcf45822, 0x581c0884, 0x085e3f9d, 0x2351d1fe, 0x264ce9d5, 0x6cae2414, + 0xdcbed996, 0xa6c6b704, 0x0a8b424a, 0x0138442d, 0x9fbbc4ff, 0x4f28f496, 0x23f665e3, 0x4c899ec0, 0xfc723c08, + 0x5bf0714b, 0x07bfc6ba, 0xc88225f4, 0x72f025a9, 0xa2c8d540, 0xf8db051f, 0x0a80369d, 0x2c9a814f, 0xfd5d71ee, + 0x799d7ff1, 0x1cba6f5c, 0xeeb99446, 0xfdd335eb, 0x1603e0f3, 0x1215d9ae, 0xca6a7519, 0x09e98f3d, 0x6436874c, + 0x28b013cf, 0x1c4282ac, 0x37455dcd, 0xa7622873, 0xcc6666c5, 0x96b8a020, 0x5d098c6c, 0x2383011e, 0xe251f6a8, + 0xd2d51cc2, 0xf1ba3046, 0x339b3bdd, 0xb5794dfb, 0xa7757409, 0x8200b8ed, 0x4d20970b, 0x4afcfb3c, 0x85f0c8f7, + 0xd0186053, 0x6e24acdf, 0xb371fa20, 0x92155046, 0x8e5dbd9b, 0x24416ed5, 0xe1453a66, 0xaebe6b0c, 0x616ad240, + 0xfa0d0bca, 0xec95e146, 0x0f147513, 0x843da85b, 0xeb858e87, 0xb38b0f82, 0x7ddec307, 0xce52d90c, 0x1b0012e7, + 0x837eef6f, 0x04739d4c, 0xe0b50923, 0x61849a2e, 0xad4b3f10, 0x242fb231, 0xef85dc36, 0x96b93d70, 0x790d819c, + 0x51d25726, 0x32275e9b, 0x08e400a0, 0x6b7dda3b, 0xcfd0dc33, 0x7cf380a6, 0xea2d0b1d, 0x73f34c76, 0xb64afb26, + 0x67c7ba8f, 0x82d885cc, 0x151bc4b2, 0x9d5c9afd, 0xb9c70dd4, 0x42e8b19b, 0x1d23357a, 0xd9e3e167, 0x2b9a1f14, + 0x3a3ef500, 0x41305354, 0x67d4fa6a, 0xee6de277, 0xf2e7215d, 0x35fc9fda, 0x1436d530, 0xc41bd3db, 0x9a1946bf, + 0xb0d04809, 0xc2244c65, 0xb9a21c47, 0x1ef91468, 0x0b5c4d08, 0x43ce78b1, 0x6f68a430, 0xafb8b05d, 0x9e25ddef, + 0xb7325b9b, 0xd05d1c34, 0xe52553d0, 0x9e503362, 0xa533c8db, 0xb2da6a91, 0x34fae5bd, 0xfd3ae53a, 0xc9b3d82f, + 0xe5171937, 0x28903576, 0xafe57a6f, 0x97b02f89, 0x27dc0f96, 0xdfa68eb4, 0x61749dac, 0xb4c0dcf5, 0xd5738381, + 0x9585f7ad, 0x67e3fd00, 0x83f3c42f, 0xafc7b8a8, 0x0f024346, 0x7fca6aac, 0x8cb475c5, 0xe8f3c8a7, 0xde0ea927, + 0x621e017c, 0x01463008, 0x1c65c1f3, 0x68731248, 0x1c8ed1d3, 0x6181beb6, 0x920afb38, 0xa91c06e5, 0xb65211fc, + 0x4e8176f9, 0x8679fdd3, 0x2b098c0f, 0xe9807e4b, 0xceca7af4, 0xcdc32ae0, 0x30087881, 0x4b9f31b0, 0xb927372d, + 0xbb43f612, 0xe1b74801, 0x397a1092, 0x3ae5b5ac, 0x94d88b05, 0x4691e8a7, 0x3f5c860e, 0xb7176b40, 0xceb03f7f, + 0x4a22e5d6, 0xd5ab4e25, 0x530af50a, 0xace501cb, 0x0ec7115b, 0x8546ac3a, 0xb91bb9f6, 0x9990a4a2, 0x2655bfa3, + 0x7e55ccc9, 0xf9916eef, 0x621c9b75, 0x42e6e9d9, 0x0fb40dd6, 0x1075f67b, 0x93c82bb6, 0xf93d1bf6, 0xd1e78d63, + 0x2fb2e9c1, 0xe0a1faa1, 0xeb57e22f, 0x0e35a177, 0xdaabd976, 0x7958323b, 0x6eb640c2, 0x98d1e3f0, 0xebc16254, + 0x90a263c5, 0x77caaf45, 0x2c0e863b, 0xc78c0559, 0x3f0fe1d2, 0x95e8a7dc, 0xb8086b42, 0xe30c905f, 0x7a632885, + 0x37fb84ee, 0xaf445f57, 0xbcfe9d07, 0xa5fed195, 0xe8c4277e, 0x0e9a4a7f, 0x745c75f6, 0x1c8627b4, 0x51462132, + 0xbfb5c95d, 0x495a3f41, 0x8c2da301, 0xd9465717, 0x251df409, 0x62e522c7, 0x9eef7626, 0x926bcc85, 0x71bfcc99, + 0xde563858, 0x124a378e, 0xa6db9275, 0x3bb94464, 0x4e17846b, 0xa2124811, 0xc65ee652, 0x3a09f327, 0x1954715d, + 0x34f20bd5, 0x34035a26, 0x439f90bf, 0xe5d9b20d, 0x5a1cf6ce, 0x4e7e25e8, 0xf08e04b8, 0xf500f055, 0xe65890ec, + 0x95f69d23, 0x9b2ba789, 0x630984ea, 0x7f2c6806, 0x2a817649, 0x4d9a6804, 0x09d69c30, 0x00670109, 0xac0f8b08, + 0x55e48a3d, 0x6bb3146b, 0x0bc66fde, 0xe1790989, 0xb6f87fe0, 0x9dd69152, 0xb45f82e8, 0x274a4082, 0x0f848ad2, + 0x4bfbb1ed, 0x8be2dec6, 0x602e9aa9, 0xca7004d3, 0x7718565b, 0x9b4da9a8, 0x4096716a, 0xe8eeaf0a, 0x9d0cb6b8, + 0x391f52bc, 0xd504731f, 0x648c4f61, 0xda47beec, 0x2b5331ff, 0x1b84218b, 0xf7a2e0cb, 0xd55548e6, 0x1f8625da, + 0xb7409d02, 0x9fd01eee, 0x3607a5f0, 0x63c50494, 0x770ec729, 0x6f84b8fa, 0x61435ed7, 0x93bc481a, 0xebb35b6f, + 0x62f91081, 0xb6f8949f, 0xe404cb29, 0xc1f0439d, 0x26066889, 0xda295ed9, 0x5088db4c, 0xbcb92d7c, 0x4a2308c1, + 0xa3d7c704, 0x97492dad, 0x5e4dbd9a, 0x4289a957, 0xa7a49346, 0x0cdbe4c2, 0x08d0e771, 0x247b12dd, 0x4d7e76a9, + 0x1242e79f, 0x19760518, 0xc562e891, 0x283a66ea, 0x75562bf5, 0xd79b11d3, 0x5886ece9, 0xcb2b1377, 0x4f394531, + 0x64ed5a35, 0x798c9649, 0x7378b9b1, 0x2aa59437, 0x04bc4578, 0x22cfd6bf, 0xda3c1916, 0x28007407, 0x1cc1805a, + 0xba4407b0, 0x8171cf7f, 0x4d56780e, 0xf52b2310, 0x7396f4d8, 0xbac3a8f8, 0x216c5c41, 0x45d8fbb4, 0xd9819103, + 0x87eaa80b, 0x7b532c3a, 0xe3ee17c2, 0x946f324f, 0xeb705ce8, 0x13e01ac6, 0x6bd824c4, 0x585b9dc7, 0x3dbcfb44, + 0xe0134569, 0xbef15099, 0xbebc6cdd, 0x149cb5a4, 0x5f32594d, 0x41452542, 0x38229627, 0x59255158, 0x6752a907, + 0x320baa0f, 0xdbf33800, 0xd4f885f5, 0x7997669e, 0x031f3ed6, 0x9a20170c, 0xc86323da, 0x775461c1, 0x6a1aaa8a, + 0xa7dbeb77, 0x73013ef7, 0x0c96effb, 0x7e82d22a, 0x111febf0, 0x5220fdb3, 0x73cd23bb, 0xae95c5d1, 0x74ec7613, + 0x2c99805b, 0xb62bd341, 0x09e6f223, 0x1fad6ab8, 0xc71890a8, 0x02616e78, 0x6ea93daf, 0x54b9210b, 0xaa12c4e9, + 0xb8dc20ce, 0xf2a31a48, 0x648509de, 0x76f2e39f, 0x8b681d6f, 0x07ddd293, 0x73e99921, 0xc10c54c6, 0xce9322d6, + 0xa7beedef, 0xfe6e463b, 0x04911909, 0xdd6be0b8, 0x9c371b97, 0x95b8c641, 0xf31005c6, 0xed4809e8, 0xcb34ab42, + 0xdeab831c, 0x1beb14bb, 0xd26493df, 0x18e24e76, 0xf9cd7ea9, 0x834c60dd, 0x8708de26, 0xfe7ac111, 0x1c303ebe, + 0x7bea312c, 0x37c7dfe6, 0x5fc03752, 0x46685c81, 0x55028930, 0xb8214009, 0x81bff59c, 0xe50b5980, 0x3a323308, + 0x4102d45b, 0xf5aa25e7, 0x2a4998b5, 0x6717cc31, 0xd53f7cd4, 0xfaf84bba, 0x2d5cbe62, 0xb21ddd50, 0xe7cd5a08, + 0x7b5c156e, 0xf84a7a6e, 0x87416468, 0x16e06b32, 0xb8fea4d5, 0xc7f2ae31, 0xa8483606, 0xc84b6f08, 0x70e6dba0, + 0xb3d62443, 0xd56e595c, 0x3b6f401f, 0x5d2b4386, 0x51f4f5b8, 0x3702ce71, 0x04b7d42e, 0xcd33a43c, 0x2c782000, + 0x5d9d54b5, 0x84a4d566, 0xf9e3b827, 0xfc17e910, 0x9cd8f204, 0x161e3b1b, 0x96f718df, 0x39b88be8, 0xf853d47c, + 0xd7de8f1b, 0x534a0689, 0xc6b79f8b, 0xe882c4f4, 0xe4b22d44, 0xb72137a1, 0x45ef306c, 0xbfde07bd, 0xf21a7a0a, + 0x6d7e00c7, 0xb7282ecc, 0xe6d5ce5b, 0x51d601cf, 0x4b411936, 0xd02fb82e, 0xa5795764, 0x1e68f2dc, 0x29425402, + 0xd47c364d, 0x7b70c84d, 0x4de630d7, 0xd653e63a, 0x76eceedb, 0x59d06c4b, 0xc62f63bf, 0x6d0973a8, 0x44b49ba9, + 0xfe946b52, 0x6dcb24e2, 0x42177893, 0x0274ab78, 0xd68a12fc, 0x6075ceb0, 0x689627aa, 0x886e6db9, 0x8be37538, + 0xedec2377, 0xc0749894, 0xd4b97e82, 0x7b2d2b00, 0xde6d8705, 0x238978a4, 0x7624ec09, 0x9ce4c727, 0x72641c31, + 0x6e9e9eb7, 0x6a2f074b, 0x82a4ecff, 0x54f582ab, 0xc831b340, 0x61f8f577, 0x9a84d6f9, 0x7cdeb01c, 0x87f1fea9, + 0x08edf15d, 0xac44745c, 0xaf06e644, 0x5d8f7689, 0xce9941b5, 0xca4dcce6, 0x67f1c5a2, 0xb4f82c14, 0x0c0aeca3, + 0x14594e8e, 0x040e91fc, 0xe65277a2, 0x8a95b5e7, 0xf68782d1, 0x1dafd468, 0x6a017efc, 0xb5051571, 0xb3198826, + 0x6e07e799, 0xae3134e7, 0x457fc904, 0x28aa9cd1, 0x85578b1e, 0x658dd06d, 0x3e055840, 0x366f5025, 0x517a1be7, + 0x4df87eaa, 0x7a933607, 0xd0dce520, 0x1d2e35bc, 0xe2b34204, 0xb734878b, 0x45be4967, 0x4210ad6a, 0xa58438f6, + 0x392494a9, 0x7aa70bca, 0x7d9b22d9, 0x2c687d06, 0x619ad4d3, 0xf248c72a, 0x57412bda, 0x5b26bfb8, 0xf5b50a0d, + 0xbcb1d602, 0x42ca7545, 0x24103f59, 0x149c8024, 0x5ba49c6e, 0x51394320, 0x23cb5876, 0xc53cdc00, 0xf2787129, + 0x3f48e05f, 0xce816d83, 0x1802bfd7, 0x469e0b9f, 0x6f957899, 0x99776464, 0x43da6182, 0xfd871f76, 0xbb0369b1, + 0x8d40b748, 0x597eb81d, 0x8e576dba, 0xe0e2cc7e, 0xc9a0ba94, 0xabdf3678, 0x1e8a5496, 0xaa12ad78, 0x5f80ba05, + 0xa6d99ba2, 0x928b50dd, 0x6ed75abc, 0xc89e6af7, 0xd23447c1, 0x4fca06b9, 0xe6fa3670, 0x4f4392fb, 0xf640f20b, + 0x750594a5, 0x065bf3c0, 0x523ddb01, 0xa7158f3b, 0xd656f44d, 0x88970cb7, 0x8bd02617, 0xfb208133, 0xbd4f613f, + 0xae34e92c, 0x35e7a24e, 0x7fb9a796, 0x7fd76ca3, 0xed0baa74, 0x6a459e4c, 0xfdd19d9e, 0x97d98aa9, 0x76113157, + 0x151a793f, 0x4a210a8b, 0x30d48c6f, 0x2576be39, 0x9ffdc206, 0xa9f824e5, 0x34235442, 0x879246d8, 0xc3a9c62f, + 0x45883b6c, 0xe16c035b, 0xb8260af2, 0x16b77f1c, 0xa8e8c787, 0x36fe068e, 0x0e5d39ae, 0xa83a2995, 0x840abbbf, + 0x44686a14, 0x7c8ff86c, 0xc1f4d228, 0x85de0b59, 0x91aee14d, 0x91c39e1f, 0xcb300473, 0x1ea53c3b, 0x236f8b5b, + 0xb7630951, 0xd5b71d65, 0xa6e9c341, 0x57b63f76, 0xc4a8907b, 0x4dfdd1cc, 0x66a30b94, 0xeddc492e, 0x4a819531, + 0xfc48ef91, 0xa3175031, 0xdf500b6d, 0x3539664a, 0xdca7ca62, 0x0f393067, 0xab2cbf1c, 0x644f9eef, 0xdc547918, + 0xdaff91d6, 0xfb75e7cf, 0xcdf2f375, 0xc2c735bd, 0xe1546aa5, 0xd37bf765, 0x75a3d612, 0xd0415cd1, 0x11282aa7, + 0x22bdac39, 0x703b1aa8, 0x990bb07d, 0xbd3d05d9, 0xa72d076c, 0xf1452bfe, 0xe0ce7394, 0x7406f706, 0xf2e0a051, + 0x2dc35fbd, 0xe18e33fa, 0x863bbda5, 0xf3764862, 0x10eef7de, 0x16295fc1, 0xa903f6c4, 0x54828019, 0x572ca805, + 0xc1d6f1aa, 0x08ab7600, 0x4a2e46cd, 0x54202869, 0x449eb8ca, 0xdc39d895, 0x922b12ab, 0xdac2d95a, 0x2f59886e, + 0xb0421026, 0xea80711b, 0x4cc476c1, 0xbdba4bcb, 0x9552abde, 0x073014cd, 0x289348c2, 0xe6716ae7, 0x79600f78, + 0x51710fbb, 0x73a4c2e7, 0x108742ca, 0x1b898b6a, 0x617929d0, 0x7746bb97, 0xdcf7d63f, 0x501d7f26, 0xc06cf2b2, + 0x8cbeea43, 0xd7797b6f, 0x6f64fe7e, 0xb288eb7d, 0x9e022db0, 0x4daae668, 0x573533f4, 0x85bcb67d, 0xad5e2102, + 0xedf7b3a4, 0xc478feed, 0xe7e2d5e7, 0x28dc49a6, 0x0ba42433, 0xf6185e14, 0x1adaf5bb, 0xc14a3173, 0x8418db5e, + 0x0767efcb, 0x7ad5b961, 0x97b3b3de, 0x466f8f1f, 0xedf83b18, 0xf11dbb98, 0xf8bacad2, 0xf7561989, 0x75961c6f, + 0x2c0410ef, 0x7a4a37bc, 0x973328ba, 0x613873ea, 0x58339574, 0xaf8ffa23, 0xa8c90235, 0xef0100f4, 0xa245580c, + 0x9aecbde6, 0x55cdc914, 0x9309e1ed, 0x9af47a15, 0xc3190549, 0x3cae8083, 0x8448a34e, 0xcbcdfc19, 0x48c3bcf0, + 0x898e4416, 0xd1b5301a, 0x04dd5b92, 0x6c411e20, 0x37ab5f4c, 0x177efa32, 0x4ca68643, 0x73f6c054, 0xda12ba59, + 0x880bdfb3, 0x029dd6c2, 0x903feb6e, 0xa36bcbbc, 0x3ff92205, 0x77b84edd, 0x6cf84679, 0xa4289e22, 0xa233dada, + 0x0f5a31ec, 0xdcc8427a, 0x9df02ca4, 0xf3535c6d, 0x4be4945e, 0x2fb157c4, 0x95050145, 0xaf11a47d, 0x13e1cc08, + 0x43d9d48a, 0x0a54704a, 0xda025e4a, 0x3e993c80, 0x51a41e56, 0xf74f69fd, 0x409a6281, 0xc3fa0773, 0xcde0e052, + 0x9ed1037c, 0x342d8641, 0x4fe743f8, 0xf09d68bf, 0x54f9fe5f, 0xbe1a3987, 0x035ff3be, 0x265592aa, 0x3621df08, + 0x97acf1df, 0x318a1d44, 0x5b2f244d, 0x242c9eec, 0xe6a22b0d, 0x3ba63ad4, 0x313613fe, 0x206b149a, 0x11e29871, + 0x9119526f, 0xde0272c8, 0x036aae9f, 0x85fbf746, 0xbf0f3c10, 0x2d06c38c, 0x1d7c5e29, 0xe5261c5b, 0x41c0bce7, + 0x4cf54156, 0xb8428f31, 0xb327f244, 0xb6db3ac6, 0xf6c7b65a, 0xe9896df1, 0x7139adb8, 0x650056e0, 0x1c1d717e, + 0x270bd0ab, 0x399f2267, 0x97d1b554, 0x555c7909, 0x19a5f602, 0x0e184b28, 0xb6227e4d, 0xa9601068, 0x490e8f5b, + 0x1c6c4f21, 0x10f2a09e, 0xcf2e147e, 0xcea6dd3e, 0x02fa3102, 0x639b5d41, 0xf776bd30, 0xfcc39415, 0x760006b8, + 0xc134667e, 0x4eb5a214, 0x3ee93b2b, 0xf2fb5381, 0xe822d7a3, 0x233ac214, 0xdcf0c17b, 0x204058bf, 0x234d95b8, + 0x770683c6, 0xda280e98, 0xe7441108, 0xd3a464c1, 0xa625334c, 0x2abeeb80, 0xa3e67505, 0xa0d74ca9, 0x0a08edf4, + 0x5b4ad0e7, 0x486e6bc7, 0x986ef275, 0xfed62589, 0x84b581c8, 0x8c339f45, 0x6629de5e, 0x82ebc703, 0xb821a539, + 0x550bb09d, 0xd8afd883, 0x0e024363, 0x73db6bf4, 0xefb331d1, 0xb7e7ec6c, 0x948134ca, 0x7ee12906, 0x21ce4848, + 0xa0834f16, 0x9a0ac135, 0xbe23a0b0, 0x17d29592, 0x3bf5d3ca, 0x56708ae3, 0x26ded4ac, 0x78f8fb03, 0xf406b63d, + 0x44450cb2, 0x6a65ea41, 0x35dedef9, 0x96352378, 0x19a77c97, 0xa413f9d9, 0x74865c00, 0xd6844cb6, 0xcbd1ed1b, + 0x9c63a930, 0x7d8e2be4, 0x07189529, 0x9b06efc4, 0x0324e92a, 0xb6ff0a5b, 0xda31e03f, 0xd05d3572, 0x8a5b0b12, + 0x6c6cf424, 0x2fb06ccf, 0xfaf1da99, 0x403b95c9, 0xbc392c38, 0x12e6ee82, 0x79afc95d, 0xb2276127, 0xb893b6ae, + 0xd1283b1e, 0x269428d8, 0xf42dea03, 0x2e416681, 0xce2b5e2c, 0x8a975610, 0xe692643d, 0x632c28a5, 0xc1217b01, + 0xc7034000, 0xd7576a16, 0x45724013, 0x9bfb8e28, 0xa5bdc669, 0x5aa1303c, 0x17c2d53d, 0x96b02e65, 0xfacdaa35, + 0xff221ba8, 0x6a51d61b, 0x7fa03a71, 0x69cbe134, 0x43a38ce9, 0x23162922, 0xff5a6075, 0x87ba4dae, 0xdaa79bf4, + 0x29607ec1, 0x1955300b, 0x1d82e7c3, 0x1fc32ef8, 0x74703561, 0xa339d713, 0x4531e0bb, 0x67e4a26d, 0x0623d819, + 0x38779bd0, 0x1c471888, 0x3b41cd16, 0x9b83c8f6, 0xa7002976, 0xa907d100, 0xd6e3f9ae, 0x37d93a53, 0xf71cbff4, + 0xc9a8c5c2, 0xe8787356, 0x77fa44c7, 0x17d1a7aa, 0xc01a4374, 0xe8261baa, 0x0a427670, 0x6fe37158, 0xe4a00f80, + 0x8ba029a2, 0x54cc9f64, 0x1853ac3b, 0x0b715fb4, 0x01a30321, 0x6243e0b8, 0x4c7bd414, 0x9308ecf6, 0x919c69f0, + 0x7c86d2dd, 0x71e92c87, 0x048deb3f, 0x7a00f27a, 0x3df9cd41, 0xe4e5771c, 0x2fbf9de1, 0x7053dd8e, 0x98db965c, + 0x530501fc, 0x0fd24483, 0x4b595652, 0x3ed53431, 0x3e3d0e83, 0xfb5a106a, 0xef0a677e, 0x62cf0084, 0xba9e6044, + 0x53caec6f, 0x093d50be, 0xfb6f5160, 0x92412da1, 0x420a7c6a, 0xde85dcc4, 0xf70f0641, 0x94753c11, 0xcab35b6a, + 0x980d74ca, 0x71f2446b, 0x680574b8, 0xd5b9ee62, 0x9509fa32, 0x61777003, 0x12cf2eb7, 0x439b0b07, 0x5fc3cbaf, + 0xa7b9a7e7, 0x55981218, 0x735cf432, 0x2e57181f, 0x9fc78e09, 0x7d49b1c9, 0x3589b29e, 0x27b7532d, 0x4bab4014, + 0x280578bf, 0xd12c443d, 0xdf875da3, 0x06cab71d, 0x2bb894f3, 0x21b1ac3a, 0x70dad2b5, 0x7d1f8e2e, 0xac19f0cb, + 0x1fd7ca6b, 0x69decb0b, 0x47f38e0a, 0x56d666fa, 0xca094c23, 0x96965b63, 0x3469464e, 0x89e844de, 0x28812eaf, + 0xb6e8c3f0, 0xe6949e0b, 0x82a5ae26, 0x5911f525, 0x323148ab, 0x17be1f8c, 0x96ff61ce, 0xb0410154, 0x5dbf636d, + 0x4c7d41bc, 0xfded8c48, 0x3b4e1144, 0x2e3ce7c4, 0x7437abdb, 0x84d27c1f, 0x4546a73b, 0x682ee026, 0xc9eb254c, + 0x7553340a, 0x96030d65, 0x1f6ae910, 0xb17e5916, 0xfb174bdd, 0x57dd93db, 0x725feb61, 0xfd59c780, 0x18c488e1, + 0x3dd083e1, 0xfe0d86cd, 0x2fd1075b, 0x96680329, 0x81167e94, 0x7606c01e, 0x6955a2e4, 0x4f8ccc8c, 0x0cf53c97, + 0xd8c557c9, 0x43aec94b, 0x3c2231bc, 0xcb286995, 0x124d8331, 0x09a9346d, 0xbc0c211d, 0x56747f84, 0x2be14a88, + 0xf33dd603, 0xd87b39c6, 0xa83deb1b, 0x8145ba12, 0x45105e6d, 0x4ee9b7b5, 0xae1210cd, 0x613192d0, 0x7bfcb0d8, + 0xe3d4593a, 0x66aba9e7, 0xc6c381f5, 0xc8fe58f7, 0xf1c61097, 0x1e082632, 0x4e626f6c, 0x2fc0f5a6, 0x36e7b020, + 0x7c62138a, 0xd14958bc, 0x09eb3500, 0x5d907e53, 0xd1a93634, 0xe0bc52bd, 0x87a21e37, 0x5af1f5d3, 0x2e4eb39e, + 0x96f0d979, 0x2145be15, 0x7556c95a, 0x31728488, 0xa7c5c9f3, 0x5ec53b3c, 0x42e35caa, 0x850e297c, 0xa42673e4, + 0x51e8df79, 0x11265de2, 0x5e56d8e4, 0x732e8c38, 0xcfcbaea3, 0xf58da9fd, 0x5ba2d32e, 0x3a1cb65a, 0x6a70de67, + 0x19fe5797, 0xbd02f267, 0x39404a08, 0x8a224ceb, 0x9661a674, 0xb2920359, 0x998c77c6, 0x18133bbc, 0x22d91edb, + 0xb81717fe, 0xde9ffd3f, 0x24a3198d, 0xe8c2fbac, 0x3f644673, 0xda5fb5e8, 0x942e0b2c, 0x787ecd71, 0xc84f8b53, + 0x9655e771, 0x187771c2, 0xff785b8f, 0x0a78daff, 0xe21bce57, 0x1a2fab98, 0xe557468b, 0xe4771d8f, 0x545577a3, + 0x9da7be30, 0xf366dd5f, 0x32aadb80, 0xeab85522, 0xc1e10601, 0x5449e8df, 0x1c4ab4ef, 0x077fabcc, 0xf7ae9371, + 0x23c31787, 0x26950508, 0x03fb42aa, 0x88e3fb90, 0xa9c5d3ee, 0xaeda6fa0, 0x339d8227, 0x48c754c5, 0x443110e5, + 0x3eda94b6, 0xe5d79c6c, 0xa5cf46b5, 0x0dd5cb81, 0x02d11b44, 0xb73fb708, 0x49b6ca8d, 0x4be5bbff, 0x3d88da9c, + 0x95a027c8, 0x7e42adcb, 0x2ff8782b, 0x65b1ab3a, 0x198ec679, 0x81bf88be, 0x931824fa, 0x1a6062f5, 0xfbd4b852, + 0x3d3e08ec, 0xb79db7c7, 0x26857fc0, 0x979aaa53, 0xfd392bb1, 0x849f5e71, 0x2fe0c8c7, 0x365e00a4, 0x68add0fa, + 0x5c2c971b, 0x1569ee4e, 0x65712858, 0xf04a68fe, 0x1b5e8a51, 0xca9191f8, 0x0001b9a7, 0xca11f853, 0x368d65c6, + 0x6826d9db, 0x44fb461a, 0x2945de8b, 0x00730278, 0x4cbee48f, 0xaafe280a, 0xc3f59812, 0x74dc5849, 0x7f54202b, + 0x22e9963c, 0x207f09b6, 0xbcb21a6d, 0x66903a90, 0x35f2db15, 0x450cf456, 0x30bc78a2, 0xf5e996d2, 0x23b87654, + 0x64db182d, 0x4e8d123e, 0xbcbedec8, 0x0227ea23, 0xc3c5d1e8, 0xd634aeac, 0xba16c013, 0x40f43168, 0x5fbb274a, + 0xd50fc5a4, 0xe0a5caa6, 0x6d9ad123, 0x46125e83, 0xc304a6ce, 0x2549371c, 0x5b30ba88, 0xe497abec, 0x6fafab39, + 0xfe2c1d43, 0x56ddfeac, 0x36780455, 0xd824b228, 0x299ff55b, 0xd79b5567, 0xb09ceeb8, 0xbb7ca9c8, 0x92858cf2, + 0xff110427, 0x5482727c, 0x351f4f07, 0x93740aa9, 0x9b1b72bb, 0xae2269df, 0x66247513, 0x61a4e2b0, 0xd472fde7, + 0x1157f09a, 0xa84a4f0b, 0x876601b7, 0x7a4c4953, 0xd01ca715, 0x771cd9dc, 0xf0e20268, 0x55c311a7, 0xbbbc5321, + 0x367841be, 0x833e4e89, 0x02e1d55f, 0x12030d48, 0x704184e5, 0x4d6548cc, 0xa285d912, 0x5238d8f5, 0x6e7979ed, + 0xbf93d6d5, 0x7f674e45, 0xc3145a03, 0x9f4066a2, 0x3188ad97, 0x1dbcd251, 0x966f5dd0, 0x2de092af, 0xee1d0ddb, + 0xed869850, 0x00e2aef4, 0x11a10d61, 0x7a1938f1, 0x8b807455, 0xc75292a2, 0x8499f4e8, 0x6c5a864e, 0x0b9b9fd7, + 0xca18ac93, 0x7fdd9537, 0x724fee13, 0x0d3f9560, 0xec3cca11, 0x2ee6dd9c, 0x6c0a9fb0, 0x304e4ce9, 0x942087e8, + 0x5ee9e2ac, 0x9602834e, 0xc72e5a0c, 0xd4161dec, 0xfefa896d, 0x4eb4087d, 0xbc17d321, 0xd25ff9d8, 0x892a5690, + 0x326e016a, 0xa3f047dd, 0x8912c19c, 0x0135bd5a, 0x27b4848f, 0x7d66ccaf, 0x6bbe50e4, 0x067861a6, 0x211e16b7, + 0x260a2710, 0x75897839, 0xb94956d9, 0x5eecb5fb, 0x3d1b8795, 0x72bdfe75, 0x12c164e4, 0x6b5a896a, 0xb079c86e, + 0x179dd884, 0x93e72e9b, 0x0c7a613a, 0x039b5b7c, 0xe7c2f320, 0x87623bf4, 0xda924d2b, 0xc1738371, 0x057505f0, + 0x61a96bd0, 0x5739ed57, 0xae159cf6, 0x172c12f8, 0x78ba38b3, 0x0d7cca6e, 0x3343780e, 0x492ca578, 0xc846561d, + 0xb3287c4b, 0xda6a9d62, 0x4ac9447c, 0x010007fd, 0xc758c0f4, 0x5b2fc76f, 0x0aa22127, 0x717106bb, 0x6bed8981, + 0x45cca516, 0x84b81506, 0x1a45b6f0, 0xa04ecbd2, 0x2cb5f6d8, 0x09f46217, 0x21f06718, 0xda0912b2, 0xdaaee05b, + 0x2021d5d0, 0xdad8113a, 0xfb43754b, 0xc8931f2c, 0x163199cb, 0x9d719abb, 0x7091f534, 0xb9cea874, 0x63900d78, + 0xae9637bc, 0xb07d2a39, 0xb4f30ffa, 0x49a5cecf, 0x82852f20, 0x60f8455d, 0x66b08979, 0x4ffaf7ea, 0x3948648d, + 0x39e8f712, 0xaaef467b, 0x728416df, 0xb9b53ff4, 0xdae9e07d, 0x210588a7, 0xbe22cef4, 0xb71b6f81, 0x2b09b029, + 0xdcc18c16, 0xd844b476, 0xecce82b0, 0xcf8de3fc, 0x1ddce633, 0x84c4cb01, 0x2c54e185, 0x17b23601, 0xc9e78f26, + 0x0cf34e91, 0xc7d328d7, 0x07edd4a5, 0x001c96b6, 0x18716e43, 0xaba7a82b, 0xf469a25d, 0xb63c3c56, 0x34ddc5e8, + 0x29596cff, 0x77cc4436, 0xc566f776, 0x7f559210, 0x5414a3d1, 0x371aeba9, 0xdd704b80, 0x068d5cb6, 0xa275581c, + 0x5c04a32c, 0x9e85e4a9, 0xf0be43c3, 0x5eeefb7a, 0xe67d531f, 0xe6e2dad7, 0x7c31041b, 0xc5b20b0e, 0xdac699ba, + 0x0ba3b409, 0x71ac895e, 0xf17b9e4d, 0x888f02c7, 0xd7e01d60, 0xe52ebafd, 0x020b1548, 0x05cfc8e2, 0xa2d1bb11, + 0xb58eed8c, 0x9d0e05cf, 0x0e2553a0, 0xc424fab0, 0xcacff048, 0x9db57ca4, 0x74b95fd9, 0x262c26c1, 0x930642ef, + 0x0b08ecf1, 0x5b731fd6, 0xd3d464f7, 0xeef7ad52, 0x0a80a8d5, 0xcb88a04a, 0x92378a58, 0x59ce512d, 0x78d95707, + 0xe646e94d, 0xd09eb4d4, 0xe733c9cd, 0x99d5e243, 0x5f12c955, 0x987ab2d6, 0xffc2d920, 0xb7cbf209, 0xe267b8f1, + 0x95835b29, 0x902fa2c3, 0xd898f679, 0x99d02d57, 0x59869838, 0x577908f8, 0xd8f62839, 0xa8ffc982, 0x02b13fba, + 0x4cecedbf, 0x48f2a668, 0x86631357, 0xb919c0f0, 0x237a9bc0, 0x133fce48, 0xb69651b1, 0x48aadd4f, 0x1db7bfa2, + 0x6c65d6bc, 0xebbca4de, 0xa6eaf172, 0xaddad9cb, 0x3180cf57, 0x50e12e0d, 0xc3f50599, 0xb974993b, 0x665741c3, + 0xfaea307a, 0xb9b4d9cf, 0xb7917e2d, 0x19242578, 0xc682bbdb, 0x15cc17f9, 0xe0323a71, 0x1d3a743e, 0xb281866a, + 0x81fac62f, 0x6f1ec083, 0xf025c80c, 0xb32a6511, 0x8454f94f, 0x1ab34674, 0xe424262b, 0x677df49a, 0x62acf2b5, + 0x30cb367c, 0x50020186, 0x98b472e8, 0x173f0727, 0x9636699c, 0x5148b56e, 0xc1b40848, 0x30a16df4, 0x52116864, + 0x40481603, 0x5283269a, 0xab2903f0, 0x524409d9, 0x293f8e06, 0x911689b1, 0x9f279a37, 0x61780ad0, 0xe75a920d, + 0x412a0a33, 0x3e38ea14, 0x3c9f860d, 0x2a84fffe, 0xdebe460b, 0x3b13365e, 0x7dfc0471, 0x1441bcc5, 0xb2c8d2d4, + 0x47b8afcd, 0x99ce6d2f, 0xb9b1c88b, 0xef8883db, 0x99cb41a6, 0x2bb2bff2, 0xa7c28404, 0xeb1de0e2, 0x0cdaa088, + 0x49686cdf, 0x46f12783, 0x7395d241, 0x29476151, 0x7cce0eb0, 0xfccde8ac, 0x908bfc79, 0x18bf8d04, 0x3ed47427, + 0xa1cb009e, 0xcb5ba660, 0x67e83b14, 0x3f3bd827, 0xbfc32618, 0xe804f37c, 0xd9617903, 0x7d83944a, 0x77051bcb, + 0xd92c0294, 0x76b75cf7, 0x7d51a5ca, 0x99c99c85, 0x4cd19cde, 0x5d9ffd86, 0x1cae417f, 0x39d72038, 0x509f13f8, + 0xfd010aa7, 0x8dfc50a5, 0x89a9c8a7, 0xe7e66ea7, 0x2776dbf1, 0x31e2e5aa, 0x824f3394, 0xe9457df1, 0x8350b9c5, + 0xf415766d, 0xa286730e, 0x80e44538, 0xde08bb2b, 0x87462017, 0x21c816c5, 0xee5a7ca2, 0xf2ee268f, 0x89b05cfc, + 0x6423bfdf, 0xeb025429, 0x6cee1c32, 0xcb5ab7d0, 0x73ab8dcb, 0x09a38978, 0x48791001, 0xff8bc1a2, 0xdab4993b, + 0x3d54c46f, 0xb02ca784, 0x53d7da3d, 0x464915a4, 0x83028e9a, 0x7e9d92a6, 0xd5cc914a, 0x14a1c1a1, 0x1d7754ab, + 0x67258202, 0x79ad3db0, 0xd918e6a9, 0x23a2438e, 0xbd567864, 0x7615c297, 0xb9ad714e, 0xb663a501, 0xe392e9d7, + 0x55c9e0f8, 0x5075d88f, 0xc74ce71e, 0x3eace507, 0x0d5ebbb5, 0xc3a2cc0e, 0x1c0ca3b3, 0x5ee76b64, 0x3fe0aaf5, + 0xedacab9c, 0xedaea527, 0xb2c1cf3d, 0x9bb7cc7f, 0x4538be0e, 0x2d7f3751, 0x57b9efff, 0xda5a657e, 0x1312ec7e, + 0x20315c53, 0xe4465db1, 0x80dde11b, 0x89e19ed0, 0x5ba2c840, 0x79eb6e95, 0x550c1eb2, 0x70012ebe, 0x67d48cd9, + 0x9aed9b66, 0xb618be3f, 0x875e1bfb, 0x300fa05a, 0xeb2adbcd, 0x10918574, 0xcffd480c, 0x03ff2dd0, 0x4ded7d82, + 0x0c9e530d, 0x1863f55d, 0xdf55cfb1, 0x95d0a52d, 0x08068dfe, 0xbe17f6b6, 0x9694e5aa, 0xbbcaa565, 0x432eada6, + 0x4fbe31d6, 0x99ff837f, 0x22de0d19, 0x2c770ec6, 0xdceb1fc0, 0x24093d5c, 0x6b8572f1, 0xdb5fb58f, 0xc84b5034, + 0x0b9ce5fa, 0x70cac36e, 0x24d0cecb, 0x676cc5a3, 0x1b230cd2, 0x643fc035, 0xb6787bb9, 0x0f6e69cc, 0x4ee9926b, + 0xbc807d53, 0x6a3af00c, 0x24e1180c, 0x8d17c27e, 0xd74cd3ec, 0xaebd5b2b, 0xc186ca83, 0xdae70d74, 0x0719eb07, + 0xbb114303, 0xdba46d7f, 0x8557c856, 0x1ecdad80, 0xd581fce5, 0xcf521709, 0x24494a4d, 0xdfd6338a, 0x878da3e9, + 0xafd36e78, 0x0b61c39f, 0xc4c134a7, 0x1c408a04, 0x1dfdb320, 0x0031ae29, 0x5a79252d, 0x9a5f97e8, 0x045a5131, + 0xfb893c0e, 0xb5c514f0, 0xe01d56c2, 0x748ebc6a, 0x2fc09520, 0x70a69b03, 0x1d9303e1, 0x25c0bd65, 0x8f13c393, + 0x959691d0, 0xc1e4ed77, 0x45bc4b97, 0x80a1c7f2, 0xd2d5f3e9, 0xa4e10d95, 0x2c8dffd3, 0x2fa5c9eb, 0x70c8d4ea, + 0x96d9bb7a, 0x67f4681e, 0xa517bfd0, 0xdedaa3f4, 0x04373fc4, 0xed72ddeb, 0xb6a4f71b, 0x18f65551, 0x7a7b118a, + 0x032c6818, 0x53bf686b, 0x179be997, 0x067731cc, 0x9c3d359a, 0x7ffe2f9b, 0xbddef1d0, 0xdaae6f17, 0x0ce77f2a, + 0x0684c2f9, 0x9e702130, 0xef16efd8, 0x5f60eb2a, 0xef417b3b, 0x6979d4e1, 0x51b36ec5, 0x6d756b3d, 0xa2834d14, + 0xdbe64c1f, 0x83bc3f8f, 0x9fba3950, 0x937ac31d, 0x4beb2560, 0x1ad7921e, 0x175a8863, 0x2c4e726f, 0x8424218a, + 0xe2a98b87, 0x5dca9bb4, 0xf731631d, 0xc64ed070, 0x85d59b38, 0x8b95ab64, 0x3628d8d8, 0x2458fe28, 0x2ebb55c9, + 0x23fe59ce, 0xda82feab, 0xfa14f80e, 0x1b2750aa, 0x67c86ba1, 0x27e020eb, 0xe209d58c, 0x79fae0c2, 0xb6d49ea2, + 0xbcd013ff, 0x440595e6, 0xc5e94d4b, 0xa8350eef, 0x2966103b, 0x4eca44e0, 0x6c0c9cd7, 0x5e10d08e, 0xa9043568, + 0x614555b2, 0x4ef4a1f2, 0xc54de38f, 0x9e56d486, 0xaf9f1cd0, 0x1c070d1e, 0xe862ed04, 0xce2e31ec, 0xec88890f, + 0x207dca90, 0x29597b6c, 0xa602d321, 0xe43bfed1, 0x391d631c, 0x0d1c1e9d, 0x1c544c8a, 0xae7f1c7b, 0x0a354583, + 0xc195efa3, 0x9d0b6f25, 0x147981a2, 0xd45799ac, 0x3b88121e, 0xbeda2b68, 0x45868327, 0x56fe682d, 0x3abd7ef2, + 0xf86cfe78, 0x9de28522, 0x8782f1f0, 0xaa64def1, 0xd40e0d9f, 0x67ccfa25, 0x91488775, 0xc6beef52, 0x8131384a, + 0xa2b1af53, 0xcae0b49d, 0xb172ca9c, 0xab6cbfb7, 0x6c903749, 0x90cd4042, 0xb37a5e57, 0x63772895, 0x43e6c734, + 0xd15cb73d, 0xe718945e, 0x343eb540, 0x4f085e8c, 0x092bc1e3, 0x68cdfbdc, 0xef058ead, 0xb678b233, 0x3f1303fa, + 0x84de53e2, 0xa91526b1, 0xea19edfd, 0x64fb642f, 0x971ac002, 0x765b1715, 0xdc4f59a5, 0x54157806, 0xb4a5e804, + 0x17f18c05, 0xea027576, 0xafea24ba, 0xcbeb1256, 0x9e2dd77f, 0xb13c5715, 0xce38a005, 0xa6f638e6, 0xfb0d2842, + 0xaee7177b, 0xecb7a296, 0x0bf6e4c7, 0xaa8984dd, 0x0ed00439, 0xa4ec1d32, 0x1c4fadc9, 0x1249e187, 0x77d5abcd, + 0x73a19598, 0x0a18f350, 0xc0fbff6d, 0xdc20566d, 0x1d4745cc, 0x6c542109, 0x989b0b71, 0xdbfc2030, 0x97ae24ac, + 0xc5ce3ada, 0xef2fa576, 0x51b672cf, 0xf7a3e777, 0x64a744c1, 0x6f91be2d, 0xf2e24803, 0xbcf9253d, 0xbfae08ed, + 0xe576ed93, 0x3106b620, 0x81d277b9, 0x7cf63f2f, 0x6e138924, 0x83e03987, 0xfabf0b13, 0x5478afde, 0x3fdaa6ce, + 0x5724221c, 0x872f5b14, 0x68da2216, 0x268c9506, 0x2fa0a582, 0xd7d4c5c4, 0x6ffb683b, 0x78c43fdf, 0xc742231d, + 0x9bd7f980, 0xa2fe6599, 0x999ac1b2, 0x08c79086, 0xec9916a1, 0x7f21d299, 0xca91b844, 0x7b9f21c9, 0xe304adf6, + 0xb9ebd108, 0xbf670639, 0xe0841aa5, 0x221dc7c7, 0x8b3434db, 0xc44fccc6, 0x620a992c, 0x168bc04b, 0x213f4e00, + 0x9ad1bf22, 0x1942d8a4, 0x2bc0d903, 0x0ab88f9d, 0x2c287768, 0x7968140c, 0x29033052, 0xd41fd54c, 0x2c2dddc4, + 0x8b54fe91, 0x5f265abb, 0x41bd3d79, 0xa7557928, 0xff62c463, 0x56e8db1e, 0x1a00fe5b, 0x5ba461a3, 0x4e6f0733, + 0xb295613e, 0x74f80403, 0xd59691be, 0x35b8ca39, 0xe9c8cc16, 0x583bfd91, 0x363b36c8, 0xbef81efd, 0xff43b803, + 0xc4c25446, 0x7f246390, 0xa956b762, 0x405d71bc, 0x0fd4f146, 0xfc2e0de3, 0x6c17928c, 0x3d6808bb, 0x323ae7e0, + 0xa830ca45, 0xd3171902, 0x7a2bfdf6, 0xb2a544df, 0xd65e79d1, 0xf13bb6b8, 0xad48e343, 0xa928fcab, 0x9b7f1768, + 0x3de99e78, 0xe86e6037, 0x684ff1ae, 0x4b3a9e9c, 0x507a6e06, 0x6ce2a868, 0xc725b191, 0x0b7a79db, 0x9bd666df, + 0x7fc1fcd7, 0x3eb73e50, 0xf6a95ab2, 0xac7b6643, 0xed1e2ec7, 0x7240d065, 0x00f2b23d, 0x3d358aed, 0xe38678d2, + 0x7210d200, 0x86dbeba4, 0xa60afa21, 0xa8db2f3d, 0x7398fbf2, 0xde5af42b, 0x5440cc39, 0x243766d3, 0x18718568, + 0x60a73b07, 0xb8d32312, 0xcc738932, 0xfbcad832, 0xa30420bb, 0x5393d3f3, 0x420ed34e, 0x5312774d, 0xa1ddba06, + 0xbe941d20, 0xbab575da, 0xe07904ae, 0x6fc775c6, 0xd8c1cfcb, 0xac2d5bcb, 0x55005bc2, 0xd325f697, 0xb206e3a9, + 0xbab56006, 0xc1c7cc63, 0x7681f404, 0x867b75e0, 0x36530d19, 0x0ed6c95d, 0xe678ee0d, 0x475b96d4, 0x83de245c, + 0x4943a6da, 0x81e7a651, 0x8e30ffdf, 0x0872eb35, 0x1f45a75e, 0xabf66352, 0x57387b0e, 0x9813e24f, 0xfaee23e6, + 0xb1f22bc3, 0x727961e2, 0xc8a213f8, 0xde4fd262, 0x45731e0c, 0x8c97a630, 0xfb228689, 0x25d9cff6, 0x0bac4ce7, + 0xbc1b2b85, 0x2d8fc167, 0x074fead1, 0x9e5b46c7, 0xdd1e38fd, 0xb1e0b33d, 0x60619ce6, 0xa409fdd6, 0x70a8e035, + 0x0b34acce, 0xb72951d6, 0xdb00e3d7, 0x6ae35052, 0x40f3e549, 0x495f9275, 0x4455255b, 0xe2c28688, 0x69e87d54, + 0xc0defdd6, 0x87700811, 0xebbe376d, 0x7571a815, 0x816ca0c7, 0x8e3214b9, 0x44afb972, 0x879fa803, 0x2dad6692, + 0x4341013e, 0x7b4be59d, 0xd67455a3, 0x15667c11, 0xe8154fd5, 0xf6293f4a, 0x29536d6b, 0x05b79ed3, 0x6ca2d0d8, + 0x3f405832, 0x6479e89a, 0x7738bb1c, 0xaa19c354, 0x020aad15, 0xda13e224, 0xfd0698e6, 0x61cb8909, 0xb0db996c, + 0xc48426de, 0x94a811e9, 0xca0213d9, 0xd0e5d15b, 0x7bf3a90c, 0x217631ea, 0xe8b2ff2c, 0xd0cb2da7, 0x1fbf9001, + 0xc6a1228f, 0xb288fa42, 0x610218fe, 0xb634e46c, 0x7c72c592, 0xd760352e, 0xe4f3093a, 0x99128cff, 0xfe195d53, + 0x0220d89c, 0xe1c70df4, 0xeea9c10d, 0x257a9b74, 0xc2ccb1d8, 0x83902e43, 0x1a982370, 0xd772f8df, 0x49dffd06, + 0xb984a65f, 0xb858bdf6, 0xdd6fa3f9, 0x92c18af6, 0xc18fcfee, 0x1297c435, 0x736c9fd5, 0x5019763d, 0x35da5fc1, + 0xaf623d26, 0x037e2180, 0x09259e4f, 0xc4a7d275, 0xc3703b22, 0xab06a204, 0xf03139cc, 0x64a4cb90, 0x4c7dcdf6, + 0x00a4ecfd, 0xc0602f24, 0x1fb782dc, 0x29710402, 0x88b97518, 0x16afb9f0, 0x2a664589, 0x0cf03b03, 0x5a4168c9, + 0xa1fe76f8, 0x9c56152c, 0x73b21779, 0xae15cf3c, 0x02ab9ed9, 0x734d5ed8, 0xa00d3352, 0x341b30ca, 0x27575760, + 0xad20e244, 0xf091978d, 0xe143b11e, 0xd2276b98, 0xf6d314d0, 0xb164bbbd, 0xd8d45e28, 0xab83971a, 0x6008cce7, + 0xa8206b79, 0xa39c7ef6, 0x3b1c22c3, 0x7e1724d4, 0x17771ab7, 0xd0779978, 0x3b9955ef, 0x43e56b78, 0x4d9e79a2, + 0xea358b26, 0xeb86a74a, 0xdac7d309, 0x06aa9ef5, 0x7af78bb1, 0x00d50598, 0x2162ad8f, 0x0334ddae, 0x9556307b, + 0x9fcaf152, 0xc3d25a86, 0xf380d197, 0xb7f73e87, 0x532dd3f0, 0xbcf2dd56, 0x6b24629b, 0x8ac60697, 0x1b061281, + 0x770157ea, 0x63e51be8, 0xa9988a1f, 0x9b3c1ad6, 0x29e2c1b2, 0x4ffef4ec, 0x3b90c1c0, 0xd6214e3b, 0x80266b0f, + 0x549c3185, 0x1fab98f3, 0xe2f9eb92, 0xcb5c18fe, 0x747f1715, 0xc2fa4cfc, 0xfa915872, 0xa0f75794, 0x93f5f643, + 0x8f719062, 0xf6364e74, 0x4a110e58, 0x240acc6c, 0x89da12dc, 0x46f5702d, 0x6c6e0bdb, 0x4208f412, 0x699856f4, + 0x6fe6c9a5, 0x5a57a3b2, 0x5e393fde, 0xc6461e2f, 0xe542b24f, 0x448ae761, 0x7ccdc1ba, 0x650dcaac, 0xba7f2e0b, + 0x8d088408, 0x357dfeb3, 0x314f62ef, 0xf2f56b6b, 0x6e0e5938, 0xb07163e5, 0x8602b715, 0xd22fe53f, 0x01194a2d, + 0x0db7e7c8, 0x7d447533, 0x4efab609, 0x72e77d92, 0xcccf22e8, 0xae0feb38, 0xb9ac1d42, 0x59e56c67, 0x8e80b84d, + 0xd44c03cc, 0x0bcf65d2, 0xdedf9b03, 0x61d15a2f, 0xeb1d6c64, 0x1a5da54a, 0x5265d228, 0x292f3d80, 0x9ea53c21, + 0x25e34a68, 0xda94c6e6, 0x3ba04785, 0x7d7de927, 0x43e251c1, 0xc0850581, 0x541d4af3, 0x3228931b, 0x5f051ca5, + 0x60860aa8, 0x11dcc078, 0x956eb576, 0x48e5df01, 0x68853d66, 0x64c4a76c, 0x3b9df131, 0x8f9089a9, 0xb6044564, + 0x326195ae, 0x0e0d9c07, 0xc47838a2, 0xd4fc812e, 0x8f4251b5, 0x37d99c1b, 0x4e7566a9, 0xb2dd162c, 0x310b3b21, + 0x73509b7e, 0xb86019da, 0x6c84afee, 0xe30f3706, 0x52e5b81c, 0x7a208853, 0x88217d10, 0x796c9476, 0x9f7e8f55, + 0xc7ee3278, 0xa40e7911, 0x0ad3885a, 0xcee821c3, 0x32f5a83e, 0x285055f0, 0xfdc96a4b, 0x66b77294, 0x29cb69af, + 0x5b9865ab, 0x66e82e57, 0x67c337e4, 0x24c74261, 0xb66471fb, 0x49306199, 0x8b5f21dc, 0x27799498, 0x0d34fa5f, + 0xfac5bd9f, 0x67c2b1ce, 0x6ae09947, 0xefa7587a, 0xe244341a, 0x901c76ae, 0xc9ff2834, 0x7bd835ae, 0x20db9504, + 0x53f92509, 0x6c8447e1, 0x2a718658, 0x4d30ed47, 0xf817d6db, 0x015b088d, 0xa376fc85, 0xf19a8445, 0x1ca3030a, + 0x1ce125e7, 0x9bbd4b1d, 0x16e646f4, 0xd0a1387e, 0x02eb3ce0, 0x1a4287b9, 0x4e5107ea, 0xee7575ed, 0xe228e9ab, + 0x7570f23e, 0xa85c5e50, 0xab15b90a, 0xe8ddbbd5, 0x452465ad, 0x72d22f20, 0x6e6dd7a9, 0x3bf7b7f0, 0x14e6a660, + 0x119b5e46, 0xc8e1ec47, 0xdbd7afae, 0x4b21ca39, 0xfb252c29, 0xe7260980, 0xf6f31a66, 0xbaf1af8a, 0x6569a425, + 0xf830062d, 0xfc9778a3, 0x2de59403, 0x3913e079, 0x55c61ff1, 0xb3840514, 0xd75f6937, 0xd969e5a3, 0xf953ed68, + 0x77c53b9e, 0x053ef43f, 0x0e226ea9, 0x80b15d99, 0x83f5fc33, 0xcc0cbcfb, 0x6fb96150, 0xea628f97, 0x0d1edf6c, + 0xa8c2b2b0, 0xc6ad2b3e, 0xd4279ae2, 0xe2cc7893, 0xc87337ab, 0xe131c72b, 0xf14d8ccd, 0x6df325a0, 0x104a8bd6, + 0xe6e34c03, 0x569264ee, 0x5ffb4304, 0x12b5260f, 0xfbbb86b2, 0xf8b152c9, 0x444c3e39, 0xcc420c12, 0x19e7fe72, + 0xbbfead37, 0x8eadf13c, 0x28c5df57, 0xd766b434, 0xea50c301, 0x7afb4537, 0x1d4d7d62, 0x39d062f3, 0x2e1447fb, + 0x78b1c421, 0x8eb71fb5, 0x8498fc48, 0x646f645a, 0x2000691d, 0xb006f810, 0x0fb68773, 0x6d4811aa, 0xeae3fdd6, + 0x7cc362ef, 0x80d9ca27, 0xf5cc11db, 0xeb35719f, 0x11259ecc, 0x0dcee9df, 0xf3cbf1fe, 0xd37f81a3, 0x4502a66b, + 0x139a2cdd, 0x2ce2ebaa, 0xb1fa93b1, 0xcfbccee5, 0xa52b72cd, 0xad037015, 0x60cf948e, 0xeaf9de4b, 0x139e762e, + 0x19c86f51, 0xe0ec61d2, 0x18457229, 0x1a410f50, 0x3df38908, 0xa92b79f9, 0x69fc5971, 0x38c55b51, 0x7110205b, + 0xa4c3c907, 0x1d8545e1, 0xe5491565, 0x8a554fa0, 0x122ccf1c, 0x0e872d9a, 0xb36c3c88, 0x424e271f, 0xba9603f4, + 0x85d0a181, 0x37241438, 0x05d742fa, 0xa896c370, 0xf8355b34, 0x3f9e6e46, 0xc08922d9, 0x1b733369, 0x8e4b7d1c, + 0x53f1e781, 0x682093ce, 0x7b5ab514, 0xd11276b3, 0x0162eb0d, 0xd5d6fcf9, 0xf0b8bb25, 0xbb86e959, 0x2b89625b, + 0x9873474e, 0x95faa1d7, 0x0b857256, 0xe7512762, 0x2e32165a, 0xb1a39d34, 0xcba240d8, 0xfbb37ee8, 0x19758eac, + 0x61efcc62, 0x2dd8ba0c, 0x3e583a65, 0x0d50b31b, 0xbc9b5204, 0xbf742ae6, 0xf424e0c3, 0x60635992, 0xd3385a3c, + 0x27079318, 0xe761f6dd, 0x8c3f4fc0, 0xcf5ae77c, 0xc36d977f, 0xb06f3fb1, 0x6c80a4f2, 0x3bd8634a, 0x42b73014, + 0xf3d7fba3, 0xb3ca3600, 0x8ecacfaa, 0xc249017c, 0x3f3f59cc, 0x99234862, 0x3260836b, 0xec9b67fd, 0xcbd694f3, + 0xe1a88513, 0xd061b97b, 0x6b170672, 0xcff63153, 0x13b60ae4, 0x6cfb6b74, 0x46fc6be5, 0x044615a4, 0xe6348ddf, + 0x81b4a750, 0x4c37c663, 0xfafbf15e, 0x1a13ba3b, 0x204727e9, 0x7c51e8cc, 0xd85c8602, 0x42966d78, 0xceab568c, + 0x53be3abf, 0x080a1e91, 0x817087f7, 0x287012d1, 0xa39484db, 0x489d8bac, 0xc5445935, 0xc8f27ab7, 0x03df0b93, + 0x2ebe9d48, 0x4d8415ce, 0x40c2c969, 0x0628e33e, 0xf49aa3c4, 0x7d879f05, 0x88e88a12, 0x5dc1955e, 0xe0c1b737, + 0x59fcdc7a, 0x52d333ad, 0xd20a8fc7, 0x76c48ec2, 0xdfd02ee8, 0x072f0e9a, 0x6a47c2d2, 0x3feaadc7, 0x003fa791, + 0x138b4d59, 0x7ccba2c0, 0xb3bb9f5c, 0x66a1426a, 0x1593c2af, 0xb62a02ef, 0xf70d3c4d, 0xb71fa66a, 0x4ddf0601, + 0xc0e6304d, 0xb9a2bd1c, 0x406fa661, 0xb7a58a05, 0xf0d24c70, 0xb8d88109, 0x79469c45, 0xa9ea34fa, 0x7da16fa6, + 0x2856194f, 0xc26b2993, 0xddc39a54, 0x6bfe4bf2, 0x0877ae0b, 0x6ddfa393, 0xb1f1eb8d, 0xe7f8b9ce, 0x8e1e0a79, + 0xbfabe481, 0xa6b4e39c, 0xcca1b144, 0x091088c4, 0xb02b2939, 0xf42397bc, 0x0912780b, 0xd66c27a4, 0xa4598cd9, + 0xeec9f01e, 0x5479b76a, 0x4769dd1a, 0xed4b47ef, 0x17e0fd02, 0xced0af97, 0x68c7900a, 0x354110a1, 0xe2704eb1, + 0x50194d02, 0xb4662c70, 0x2fc11bed, 0x28577453, 0x3e6e0666, 0xe8277836, 0x9c93455f, 0x0d12c446, 0x84eefae7, + 0x315bad2e, 0x2c81f9fd, 0x8c6099ea, 0xb906b618, 0x1639cd68, 0x55328631, 0x12884498, 0x19f5eb1e, 0x53e91051, + 0xbdb5c72f, 0xf4d9003b, 0x55351372, 0x1ac16a79, 0xb2f044dc, 0x051aa606, 0xa16c136d, 0xf333e6d7, 0xa6e85492, + 0x37e46218, 0xacafe8af, 0x8970486c, 0x9a9e8666, 0x3e86f2a5, 0xb7c0af33, 0xa6642637, 0x6ae28a4c, 0x44abd2b2, + 0xf459e668, 0x357cd7c8, 0x059608fe, 0x5bef967e, 0x38e5718e, 0xf65cbdd4, 0x757a6356, 0xd3c6e4c5, 0x90d5f70d, + 0x57266062, 0xdc136ce4, 0xe5ca07c1, 0x1cbd4493, 0xcbe7bf48, 0xfa8d006b, 0xa59b34ef, 0xb3e4c519, 0x3cbad72a, + 0xf466d981, 0x9078de5e, 0x4365174e, 0x722e8571, 0xb33f8cad, 0xb58954e3, 0x87f40d20, 0xff6d98ea, 0x50d2c895, + 0xfae86752, 0x56293094, 0xa52b9057, 0xd8054f1c, 0x80503a42, 0x52bce6bf, 0xf61bfa18, 0x5ffe3503, 0xc88b3ffa, + 0x4e934aca, 0xfb030207, 0xc63cacc3, 0xc19a87db, 0x3d4bbbb9, 0xccac098d, 0xd05fb742, 0x61ddf29f, 0x5fb2ce8d, + 0x4653004c, 0xe4854de1, 0xbd47ba62, 0xa1bccfe6, 0x997d3b6d, 0x3fdf9e0e, 0x004d7b20, 0xbbf5558b, 0x92b2f912, + 0x9eb92fe3, 0x6d6a89f9, 0x9f3ea1af, 0xc3c4d20c, 0x11e5de4f, 0x213c5d6c, 0x149c3e27, 0xa422b1f9, 0x802ebab0, + 0xcc75ae9e, 0xc2f77201, 0xb139363c, 0x2c7cabbc, 0x9a02a1c2, 0x083fd582, 0x2e475cbe, 0xeb9a3adf, 0x1fe02d05, + 0x25f1b0f4, 0xc33a1ce4, 0x765ba6fe, 0xa31c61fa, 0x4bf7199d, 0xa979d6c6, 0x4da2796d, 0x481f91e0, 0xd58b1b50, + 0x23cb4936, 0xf3afd24f, 0x19df5bc7, 0x281bb2c8, 0xdd07a83b, 0x67f8a82b, 0x65986dc2, 0x64f16ca9, 0xad294ce5, + 0x832b6ce2, 0x3196af9f, 0xedc6df21, 0x4e5b27cd, 0x6ed7f47f, 0x5da94495, 0x106d30be, 0x269e90ab, 0xd0853b8c, + 0x2ea93045, 0xe808eb3a, 0x0bafddd8, 0xed0cc435, 0x9ee65017, 0xde82610f, 0xc8ba8348, 0x0fecdfc9, 0x1a9e5e19, + 0x596fdd15, 0xc68044ad, 0xdd984465, 0xc55744c2, 0x37bdcb64, 0x637b41eb, 0xcce49935, 0x9906bedd, 0xd3c5e188, + 0x55510080, 0x96850033, 0xeea47cc8, 0xde5c2f67, 0x8d387cb6, 0x203971fd, 0xbf9a4436, 0x1210cbaf, 0xe40c82d9, + 0x7262957b, 0xa33dcd5a, 0x0909f069, 0x07beecb9, 0xf0783b5d, 0x3c91197d, 0xdfebfc97, 0xbe6cd740, 0xa6a54069, + 0x529b32ce, 0xb22759f5, 0xce3ddd82, 0x625f1cb3, 0xe6d8ba44, 0x98aa05bf, 0x77d0e9ea, 0xebe9d1fb, 0xac5c80fb, + 0x5b83e624, 0xb6cb9669, 0xd79045f4, 0x6af10218, 0xa3dfb8df, 0xf15febf1, 0xf90c8bd1, 0x348dd6c6, 0xadc20989, + 0x36bfbc48, 0xad2d7748, 0x63ecef63, 0x592abc04, 0x75065fc6, 0x6fe73a62, 0xf30a33f6, 0xa05d9dd5, 0x50fff46e, + 0x92d8700f, 0x40094402, 0xaca5c27a, 0x0d2b3b2c, 0x145c82a6, 0xf3246d4b, 0x85d945e5, 0x08c77fff, 0x0d94b974, + 0xb851c7d8, 0x0e94549f, 0x6b853ae2, 0x32de3f92, 0x75f1192c, 0xcbaf2c9e, 0x64f3fef0, 0x8af4af60, 0x31a8b804, + 0x5b757cd4, 0xb86b7b96, 0xaed98e61, 0xcf1be96b, 0x540b9cd8, 0x47a96ac3, 0xadd524a5, 0x0cc9c862, 0x566129d6, + 0xf2194572, 0x55aae157, 0x54f8b528, 0x7014a6cd, 0x0b10eb93, 0x1faff989, 0x1495f342, 0x66c930ff, 0x7f0af5d0, + 0xc49f4ea8, 0x389023ba, 0xe84feaed, 0x043a5e93, 0x9615870c, 0xb1ea3c98, 0xb40e198b, 0x0953f612, 0x6890f6e4, + 0x5de07c46, 0x197dacd9, 0xf9bb893d, 0x51205b65, 0xb7aa1b29, 0x56be38c7, 0x79b49a3f, 0xb036ca9f, 0xd4245ecc, + 0xc705780c, 0x00afa694, 0xe4811f47, 0xb3a4100b, 0x5846332a, 0x194929be, 0xc9422728, 0x526b2da2, 0xe1c2a58a, + 0x5e6caaa8, 0xb1eac588, 0xa19a0f11, 0xa24f1d26, 0x7dfa1310, 0xa61e408e, 0xc2bc0124, 0x2b1d0de5, 0x9f12ee7d, + 0xe12d1f3e, 0xe7d35dfc, 0x96f23821, 0xa16c2a22, 0x9f377bb7, 0x435de2c4, 0xa1cbd47e, 0x0a075ec4, 0xf6575d66, + 0x313f2696, 0xd8af9a3b, 0x03a08512, 0x91d679de, 0x73c58414, 0xfdb37254, 0xd8a4a935, 0xa8236a93, 0x2bd4b093, + 0xe240f9ad, 0x5aa5a541, 0x57ed526f, 0x75a2a25b, 0xee1e763d, 0x21c9738d, 0xb1b0548d, 0xebb31de5, 0x82b687c9, + 0xc49cd4da, 0xcc634d0c, 0x678eb186, 0xb6a3814f, 0x0de7be9d, 0xd2f71f23, 0x7ef052f0, 0xd40fc98d, 0x37572021, + 0x500c9651, 0x69d47166, 0x0f9d7f80, 0x76b50b7c, 0xde50275e, 0x269ea714, 0xb597db66, 0x4d211001, 0x60021f17, + 0x5c2d5122, 0xc60141e6, 0x7b94d0bb, 0x82b47215, 0x5a986cbe, 0x828aa69f, 0xc4573680, 0xa58a5865, 0xd2ec3546, + 0xf3eb9cc8, 0x991f38a5, 0xf21318d9, 0x4a948f95, 0x336323ec, 0x64d24f0f, 0x69703078, 0xba4e8a12, 0x6486ad0e, + 0x0fb7c7c9, 0xe22c9c36, 0x45a8cb08, 0x5007f3ca, 0x14d32516, 0xf07c2a96, 0x9e75869a, 0x1852f545, 0x61828cb4, + 0x81a60508, 0xcba4c5bd, 0x5971381d, 0xef5b5f6e, 0xd4b8b11d, 0x0b8ea6be, 0xfc91ef05, 0x0c2ba385, 0x1614b191, + 0x1a3b7031, 0x1e0a688c, 0xed748409, 0xc03e06e3, 0x66c8f4e7, 0xab5a70ae, 0x64c8457a, 0x865399c7, 0xf8f86f4f, + 0x11225184, 0x75cde469, 0x3ef90217, 0xd24e9a8d, 0x99d7e6c2, 0xd5d2bbfc, 0x7670121e, 0xbf74b10c, 0xca20ed58, + 0x823e2097, 0xa7003131, 0x2989a843, 0xadc3abba, 0x514279ee, 0xacda88f6, 0x7349d72b, 0x8af39a3b, 0x42a3255c, + 0xa822e377, 0xfc3f4433, 0xe0bbac6e, 0x2725e2ea, 0x86c9b7a4, 0x449677f3, 0x10b54a75, 0x6086c908, 0xb7752593, + 0xe6ae5a2a, 0x28ea9514, 0x969bc343, 0xb710b7bb, 0x8cb47827, 0xaeec14b5, 0x280a4f80, 0x465c13cf, 0xdd6c48e9, + 0x4ee57cf6, 0xefbe750b, 0xedd6acf2, 0x24d3a03f, 0x946e2892, 0x0e1ce6b8, 0x6ad3223e, 0xf1cbe338, 0xc029ef9c, + 0xc7433be3, 0xd2a87e79, 0x3c7fc4e5, 0x5ceb7bab, 0x90bcdcc8, 0x2ed9150f, 0x1acfefc0, 0xa9b27898, 0xca466979, + 0x0a70d7de, 0x5dde2eb7, 0xfd7ae28e, 0xdf125465, 0x4ba7b89b, 0x82db6928, 0x850642e1, 0x3e537a18, 0x1d1df807, + 0x86500fc8, 0x533e8268, 0x20d65657, 0x17ccb146, 0x1004dfe0, 0x1343e84c, 0xe701cd9e, 0x53fcfdee, 0x48b09d7b, + 0x37ba4895, 0x6ec29c3c, 0x2bf7c6bb, 0x80eef420, 0x1cf14793, 0x9cb6e55a, 0xe6be10ac, 0x36180d32, 0x148be4cb, + 0xa2c0e2bc, 0x6fcbb723, 0x8e5dbf5c, 0x0cded23f, 0x41cdd5f4, 0x4fdd47c5, 0x7c3287ac, 0xa125e454, 0x5af5aa18, + 0xb90bac3f, 0x69601a7c, 0x029302b1, 0x6817908d, 0x76acd61c, 0xf97f98a4, 0x5745df2d, 0xe5d17ef7, 0x56f33c01, + 0x16bf24f9, 0xd4aa414f, 0x536befda, 0xa82a529f, 0x6c0cc969, 0x8fb625c5, 0xca443484, 0xad35ada7, 0x9f39ab3b, + 0x32e858fd, 0x05bc9234, 0xe15c521f, 0x4f995542, 0xc74d6a9f, 0xa8a85bcd, 0x689b5bbd, 0xf64174e2, 0x187883b9, + 0xf175b19d, 0x7d0f7eab, 0xa1142fbd, 0xbc4751a1, 0xd15f26a9, 0xf2d12a03, 0x41c18eb2, 0x9b7016bf, 0x275c6c63, + 0x66197177, 0x47e47ab9, 0x7507f297, 0xc2c12005, 0x3d6d0ae5, 0x7c21323e, 0xd6a3f084, 0x30200fc5, 0xee4af17d, + 0xc43d9bb6, 0xd0e1b9f4, 0x5076b364, 0x4368786b, 0xbb47b5fe, 0x873d6c52, 0x8c7aae1e, 0xe6c16974, 0x132c5a2a, + 0x92c65faf, 0x26ced38a, 0x3c64b905, 0xe25fbaaf, 0x88481cdb, 0x16947554, 0x312ccd78, 0xb9e9d709, 0x45e20cdc, + 0x43a9c288, 0x042e03f9, 0x56060b7c, 0xae6cf39c, 0x4f39da68, 0xd572966b, 0xca8b9c15, 0x27aaf4a8, 0x84c7418b, + 0xaec3aa41, 0x937e4305, 0x6ff06915, 0x0a8c3208, 0x5fd73063, 0x3a10e177, 0x9f0f4d83, 0xf530a555, 0x6494117b, + 0xa8c09872, 0xff1b2cf2, 0xe8008284, 0xd3dd306b, 0x19e2116a, 0x41a2b7a2, 0x91a7c571, 0x7ae5dd92, 0x38abaa3d, + 0x4bad2521, 0x9acb1d1f, 0x83d65efc, 0x3ee2d561, 0x8a8f81d8, 0x1bdbe03b, 0x35e58035, 0x180de946, 0x3837ffc1, + 0xc174cc5a, 0x3987d8b0, 0x786ff33d, 0xb8fbd149, 0x17421cd7, 0xa29d411b, 0xa7efa64a, 0xf9d7c908, 0x90aa60b0, + 0x7c1e56b5, 0xf5550d2b, 0xd944c5cf, 0x9691f5da, 0x2043f3f6, 0x1227385a, 0xabdc0677, 0x767de6cc, 0xef82216c, + 0x2647ff95, 0x4ac324f4, 0x1c93a246, 0x17f25247, 0xb5a1eb8d, 0xe7134b43, 0x14c090f0, 0x5d8e5861, 0x81d5e3e3, + 0xcdc82cf1, 0x8b0ea3eb, 0xce8ecb4e, 0x77033cc0, 0xdfe39b48, 0xbc8b0b27, 0x258a8e2e, 0xcd1a64e3, 0xcb56abbb, + 0x5498c41d, 0xa0fd3a3b, 0x083f6c1f, 0x708a8f2e, 0xe19b81e5, 0xb2eb1e88, 0xf82bf0e3, 0x4230d06f, 0x9ab979a9, + 0xf74e450c, 0x556f2668, 0x0c4c8773, 0xc0948680, 0xecd72156, 0x12058729, 0x55db1f1d, 0x9e617ea6, 0x38131d63, + 0x46d0563a, 0x66625691, 0x456a1eed, 0x025e2c8e, 0xf9f95662, 0x03d7e039, 0x798a0e63, 0x928d4654, 0x935d915d, + 0xeafda96e, 0x946ba94f, 0x23b13ae3, 0x37ae2e99, 0x3450067a, 0xe33b6fa1, 0x7014fc36, 0x73b5a06b, 0xdc12d191, + 0x5d814f68, 0x4ec5dbe0, 0x88aa2773, 0x60f16747, 0xef0c4f93, 0xbed0aa98, 0xa866b890, 0xdbd1c080, 0xde899eed, + 0xe9c4110c, 0x6da3488e, 0x45de6d9c, 0xeb977208, 0x543584b4, 0xcf8ec1eb, 0xdc29f846, 0xbe33d118, 0x860334c1, + 0xee88a7c6, 0x7b32d0f2, 0xaa6fdd68, 0x95b24b87, 0x66a12e73, 0xf9977073, 0x0c157259, 0xf17a11e0, 0xc409b8ae, + 0x52539590, 0x9ff8ff31, 0xd5e3d7ed, 0x6307cd70, 0x6caa1262, 0xc660cf76, 0x5feca497, 0x5ef8b5c2, 0x602744a1, + 0x291b25fa, 0x25e6fb58, 0xb4619f0a, 0x3227018c, 0x52e5adde, 0x839f1490, 0xfcdd3105, 0x4c866df9, 0x020ea75f, + 0x694367e5, 0x2e45a662, 0xafb6bf7f, 0x7cb56818, 0x97cc1c63, 0x63226e38, 0x427f1263, 0xf4260217, 0x61704703, + 0x230cd88b, 0x861e8fbf, 0x0b13a1d3, 0xa43cb3da, 0x7fff8a9b, 0x99d5669e, 0x19e3a3b0, 0xb27c5b85, 0x022ec567, + 0x324299eb, 0xa2fb5298, 0xee5869b5, 0x5abe0429, 0xb360dbde, 0x5ee7ad63, 0x40a94105, 0x98fe6ffa, 0x97a9ede1, + 0x0dd5c06c, 0x28e16597, 0x363172e9, 0xb93da351, 0x449dc350, 0xe763bfd6, 0x42b256b6, 0xd68a6fbb, 0x4840d204, + 0xb9c62c91, 0xee69df67, 0xee36a199, 0x044799c6, 0x586f745a, 0x51c90552, 0x4b682fb6, 0x7f8b7011, 0x0f9e4385, + 0xafecefe9, 0x7aef7b13, 0xef2921ef, 0xbba32f38, 0xa3d3e9be, 0x0b17749a, 0xb3502510, 0x2432d71b, 0x98acb367, + 0x8596adf1, 0x2b34ef89, 0x2f6a0b55, 0xdfa5865a, 0xb83cac30, 0x6443b9d0, 0x73cd6e7d, 0xc59a647a, 0xc41363ea, + 0x161d25f7, 0xcf5955d1, 0x07b4ec79, 0x070ff6f1, 0x3c852a71, 0xf2613272, 0x66905eae, 0xd6cff6e5, 0x28e3df39, + 0x350a013f, 0x6122edeb, 0xfca08fef, 0x93f2921b, 0xc70b2d45, 0xa333d270, 0xcd587982, 0x60638bde, 0x6c087364, + 0x981c9999, 0x7180623e, 0x214c265d, 0x71cae463, 0xd493f994, 0xd039973c, 0x2669d5a4, 0xc9bbb8f1, 0xd7c782ad, + 0x7ea7bae7, 0x01c8d9e1, 0x9ce7efce, 0xf9547a77, 0x0e6cdd1a, 0x21ff3de9, 0x2d8c40b1, 0x1f496f0a, 0xe580ec91, + 0xa0c48b91, 0xdf433c5a, 0xc08b4b4c, 0x12387f95, 0x6fe5cd37, 0x3c9324a3, 0x8087e922, 0xdd057c5c, 0x6300919e, + 0xe8bd3650, 0x029109c8, 0x3d900d0f, 0x2049b2cd, 0xb4957c5a, 0x1942f3c2, 0xc25fac50, 0xafdc88aa, 0x7d4d349f, + 0x536a9349, 0xf254317d, 0x72fbec89, 0x9edfdabd, 0x83f2f784, 0x18b57d0d, 0x0c3337d3, 0xa8384cc4, 0x12574a3c, + 0xc5237119, 0xa3d6b273, 0x040c9683, 0x27092f72, 0x5cc0e649, 0x23d3ba06, 0x6318d4df, 0x476d7363, 0x5cec614d, + 0x6a02b82a, 0xd4e21389, 0x62e5cffe, 0x82550bc9, 0xf9d6cf8d, 0x95367056, 0xda8165c0, 0x18fa2709, 0xa4bf2be7, + 0x90ee48c8, 0x201ed9bb, 0xcf478418, 0xbb0b3476, 0x0f33f5af, 0x32df34df, 0x6047b529, 0x6d696191, 0x48da6e3f, + 0xbaf5f4d1, 0xd3d1d274, 0xbf3687d8, 0x822c01ee, 0xcd76f51f, 0xa1da6125, 0x3e57dc81, 0x19709efe, 0x77b4d91e, + 0xea8199ac, 0xad2ebb63, 0x3911183c, 0x6c4209d7, 0xbc313b16, 0x0bf5a4e8, 0x99c450b5, 0x47c23712, 0x5ccb03e4, + 0xc8425f29, 0x439e3c13, 0x73b0ac35, 0x97252567, 0xa8de168b, 0x64e43842, 0xd08ab7cb, 0xa54579c4, 0x60b3a926, + 0x6802241b, 0x1e649795, 0x60fff9e1, 0x14f4ac63, 0xe1302773, 0x79196379, 0x8498adac, 0x5798b6d3, 0xc59d2823, + 0xa1dfa881, 0x7f196969, 0xdc838d10, 0xd0e1047a, 0xddfedb23, 0xe9798b3f, 0xa72ab754, 0x6e9a4fb7, 0x1c976d6a, + 0xf51b92ee, 0xd2cce4c4, 0x5efc856c, 0x0ea6a0d1, 0x06797e29, 0xef289507, 0x3d629e34, 0x3fc44267, 0x1977d893, + 0x4ef3d289, 0xea0747f7, 0xfb4d3a26, 0xa94b7a28, 0xc7a6e63b, 0x56050919, 0x09220694, 0xc62abf72, 0xd4bef450, + 0x86668ccc, 0x8634720b, 0xcabf3609, 0xe64ca659, 0x5e30b443, 0x972d2aaf, 0xc1788fee, 0x665a1857, 0xb61dfbd8, + 0x626e5d4d, 0x2313782d, 0xa868fc72, 0xa6d5c03a, 0xa68ad04c, 0x1cfeeb80, 0x98d14df8, 0x971f7e4d, 0x9af01d1c, + 0xc8f5ecd5, 0xbe1571dc, 0x9f0fbf25, 0x73ad1bf3, 0xd39a7d57, 0x6eddbcae, 0x0148b8b4, 0xa6b0c70f, 0xc9b5cd27, + 0x355c632a, 0x6deb63b5, 0xfdd54c0b, 0xc24761b5, 0xb4f29f0b, 0xbb7f4163, 0x9c5f6fb8, 0x0105f2cc, 0xf46833a9, + 0x2b4c6951, 0xc604e66b, 0x5499a5be, 0x067ffb8d, 0x1b273132, 0x777fd1ab, 0xd5ae57fa, 0xb8e16664, 0xf202b5b3, + 0x756cb63a, 0xfcf9a190, 0x93db784d, 0x3d9d2fac, 0xf770551d, 0x0587e537, 0xe1311fb9, 0x86599b93, 0x124642f9, + 0x12e9209c, 0x7bb997fa, 0x4059d151, 0x7fa49430, 0x95eb7034, 0x9511bf65, 0x7ab77403, 0x9ea4b7a8, 0xa9b3320b, + 0xe2da73b7, 0x38f59699, 0x50f11890, 0x726fadc5, 0xb1c51f15, 0xf13dadfa, 0xc7437770, 0xa7538ff9, 0xf7657c7a, + 0xaecd81bb, 0xd51493ca, 0xc6ff0344, 0x24841dea, 0x250a5bfb, 0xa89d9209, 0x5409f6b3, 0x08b68396, 0x55663d11, + 0x75019d99, 0xb0ee43ee, 0xa1ca0c6d, 0xc53a3c71, 0x7a2406bf, 0xe533ec4f, 0x8a3f1cd8, 0xe9949206, 0x32daa986, + 0x55ef22f2, 0x09f97c96, 0xb37a640f, 0xbeb433c2, 0x06e13d7b, 0xb44c3c87, 0x53973dbc, 0xe0fe51ef, 0xd7c9394a, + 0xec7d1842, 0x92ab4e1d, 0xe45033e6, 0xf5fadc27, 0xd8279409, 0xac6fa756, 0x7bf0e169, 0x90bf831b, 0xe188cfa0, + 0xa97fbfa9, 0x525e91c1, 0xde9eacc1, 0xaffacf76, 0xa2746ea5, 0x294e8a8f, 0xe28ec618, 0xcea94357, 0xc90c762f, + 0x1a823364, 0x90347d27, 0x20141ead, 0xa4f88db4, 0x701e9576, 0x079f6225, 0x5a9efd11, 0x70d41280, 0xaa52888c, + 0x9b7ea52a, 0x86e4e80d, 0x0bac3a4c, 0xaeb43132, 0x566caf1c, 0xb8773369, 0x0e76d26c, 0xaddea518, 0x061800c1, + 0x5bcd4ab2, 0x3a7fe0f9, 0xb2290ccc, 0x64fbc610, 0x6ee5de5f, 0xb9ef8d3b, 0xb11b1991, 0x23ad43f4, 0x89a2ed78, + 0x6baa0ce0, 0xa8b4b148, 0x571c1891, 0x66073b6d, 0x6b9f4093, 0x7584bdb0, 0x9d85a37c, 0x816c36df, 0x49d16d90, + 0xd88ca933, 0xbaed7955, 0xba93bcfd, 0x977d1fbb, 0x95043c47, 0x291064b9, 0xd032f0df, 0xc7235b69, 0x2e23aac1, + 0x84e9ef7b, 0x9f8196bd, 0x2c628ab4, 0x65580065, 0x6d3a51ee, 0x9df6923e, 0xa2b72dd5, 0x36049f3c, 0xb4f3f99f, + 0x925ddce9, 0x0a732105, 0x1a6062e1, 0x17523c30, 0x69bb5a88, 0x42847c60, 0xeabf1739, 0x2163c800, 0x7289f3f0, + 0x50215f88, 0xdd77078c, 0x37b5dd39, 0x28e2a896, 0x9ba1db40, 0xbe835422, 0xa4e6ad6f, 0x68f6c92b, 0x89e4a03a, + 0x8325a989, 0x925d0035, 0xad939b34, 0xe0628c6d, 0x892925ed, 0xc59132a9, 0xe5852650, 0x180152b3, 0xc68ad34c, + 0xdc107ef6, 0xc93b147e, 0xfe694bd3, 0x59e7b3fd, 0x743300d0, 0x3caac322, 0x5d90cd2c, 0x55c51ab6, 0x4ef57865, + 0xef63bcbe, 0x92242df8, 0x623ee498, 0xab6fa1b6, 0x7165fc34, 0xdc6b1596, 0xce195690, 0x8cc77be9, 0x080a76fb, + 0xb83d943f, 0x36008ddb, 0xf569ae02, 0xe0940ddc, 0xe8a9c8c1, 0x702242ea, 0x848491e5, 0x5fd59ced, 0xdaa6fd17, + 0xa5b753c2, 0x334ce119, 0xb4c55bf7, 0x1cde5aa0, 0x197b10ff, 0x30267e52, 0x65962e49, 0x0972f741, 0xa134b5eb, + 0xd6426914, 0xe25f8a49, 0xcf62f7a7, 0xb0770ffc, 0xa88a262a, 0x0c99b022, 0x99ef4441, 0xd0f758e8, 0x4e00a7c7, + 0xbd218f8a, 0xd7373bc0, 0xcf686624, 0x96f85998, 0x3f2c6709, 0xff3999f8, 0xc631484a, 0xfc7edb37, 0xf9fe4952, + 0x69240c06, 0xcdcff4fa, 0x39654590, 0x739244e9, 0x6b53162d, 0x34a6748a, 0xc372174d, 0xba819093, 0xed61ad30, + 0x2f968cd2, 0x0cf04800, 0xcd9df9a1, 0x89977b15, 0xd4a7ffba, 0x6dc694c7, 0x4d359bfc, 0xa696db87, 0xc457df90, + 0xfdcf716f, 0xf0b700c5, 0x301ce6e7, 0x4e66c802, 0xded6ed46, 0x6e9688a7, 0x001824c3, 0x593f5c50, 0xa96fa4a4, + 0x2094f9ee, 0x3b0bcb8d, 0x97c7a80d, 0xf2cd2a35, 0x5826633f, 0x77b6cc55, 0x14a37fba, 0x6ba90bc2, 0x77c8df86, + 0x4802f5b8, 0x94278603, 0xb0b91666, 0x9ed4c906, 0xd78f192c, 0x1ce17d7f, 0x2f2d9e7b, 0x1ed21268, 0x35139809, + 0x4899c2c1, 0x8ea6f0c3, 0x06748d42, 0x065421f0, 0x157da5f8, 0x883ac2bf, 0x2cacb1e7, 0x8779fc91, 0x1ced4a50, + 0xa7803014, 0xeaf73564, 0x7a03c991, 0xd4637e32, 0x5881de9a, 0x5362ed93, 0x381c9c0d, 0x9f0bb514, 0x722a15e8, + 0xe5e6e29d, 0x14f8b2ef, 0x41f87018, 0xcc515b33, 0x0e9eb68f, 0x64b95f62, 0x11372efe, 0x1d078b13, 0xf59a32e2, + 0xb7b225ef, 0x95559f44, 0xe5653a3c, 0x349d70c4, 0x1a2e6a61, 0x59c7c982, 0x00e871d7, 0xdd1e79c4, 0x1f19792d, + 0xe5fd9f4c, 0x94ad9a12, 0xfe3e15af, 0x6c7e8fa7, 0x042bb03c, 0x665326a9, 0x6b443f17, 0xbfba26f6, 0x4a3d2d10, + 0x18616297, 0x500f389b, 0x4e560929, 0x5c928ba7, 0x39c7e7dc, 0x4f558e5d, 0x57027cb8, 0xa1941ab5, 0x08e4bb59, + 0xac2bafa6, 0xe6372734, 0xf1bf89ca, 0xcb3f719b, 0x1e1dd4a5, 0x4590a6f0, 0x1d9a8cd8, 0xc0f3639c, 0xc098bc9d, + 0x55b32022, 0x99fd4b2b, 0x355f95b2, 0xea803d27, 0xf1c9ac76, 0x811fd3bb, 0x9e728560, 0x95913ca2, 0x496abbdd, + 0x01eb4918, 0x773a4fe0, 0x9dd0bced, 0xfebb9ae3, 0x6988a46f, 0x9a5c3524, 0xc1d68945, 0x7d186859, 0x4536b37b, + 0x711d6234, 0x887d5600, 0x21a20170, 0xc1957ad4, 0x89cab3c9, 0xe57a102a, 0x8cc5d513, 0x0133695e, 0xd8c7c0ec, + 0x316eb725, 0x65be451e, 0x4ed435c5, 0x25c2e1fa, 0x33ab2d24, 0x8d3ba22a, 0xda88d30e, 0x355a8097, 0x67955cdd, + 0xa9c32ad0, 0xe9d2bf31, 0x99d76d1a, 0xa02dcadb, 0x15c0f7d6, 0xf5015161, 0x32da7432, 0x3ca6f60c, 0x9924bd36, + 0x0deefc2d, 0x23d61078, 0xc3a00610, 0xcfce5e8a, 0xd732b7ed, 0x92439665, 0x08f32a66, 0xc2c36ae8, 0x6223f928, + 0xeb36c85b, 0xf986cddd, 0xb7119793, 0x9db5ba49, 0x5bdc193a, 0x4a6fe2ea, 0x6a3b7e02, 0x2b8a2898, 0xa00b25d5, + 0x2acbd290, 0x41884827, 0xf1cbb1fe, 0x25b66b86, 0x78da29bf, 0xd9b200ef, 0xf36c9ae7, 0xf696ddd4, 0xb4da483f, + 0x155d5330, 0xd59fd8f8, 0x19eb2e6e, 0xaec1dbcb, 0xe1a7d32f, 0x0bfb8cc1, 0x16278d80, 0x8c080d66, 0x391c117c, + 0x68bbbbbb, 0x03c464a4, 0xf3672002, 0x45aed188, 0xfcc938f5, 0xb5b251b1, 0x7aa958f4, 0x4a36b793, 0x585711b9, + 0xca87e246, 0x921b136a, 0x45b19ae8, 0x77445805, 0xa890e560, 0xdcfca8b7, 0x11b2ab7c, 0x97024105, 0x435f599f, + 0xc38a3a28, 0x73fc398d, 0x0260738b, 0xded86079, 0xf20e84fa, 0x6a9d46c0, 0x4686b70f, 0xd40bd4fd, 0xfd48c32f, + 0x49b225b4, 0xa5a2bbad, 0x95430b7d, 0x7cff0374, 0xcea99a16, 0x68e9b31c, 0x01d8bdd1, 0xa8a8b13c, 0xe287604f, + 0xac8b9734, 0xac1148a1, 0x9e6a52d6, 0x6da49af2, 0x74e0186a, 0xb9ef24c1, 0xa506fbb7, 0xbe9f09f7, 0x1b96f555, + 0x69341999, 0xcfdc51f2, 0x694e64f6, 0x420b9819, 0xac41730e, 0x6f884808, 0x8dba9f63, 0xe50b0cf4, 0x0884f0a8, + 0xad1adfbd, 0xad12b1f4, 0x72f6a1fa, 0x49d370aa, 0xd916a67d, 0xbd9d4fd1, 0x6d80b46f, 0x622ed8f2, 0xbc2e5628, + 0xe8476160, 0xcbaf3e1e, 0x97ae265d, 0x0365a7b4, 0x29390e03, 0xb5ba4198, 0xf20d7cbb, 0x1b6201f3, 0x559634ce, + 0x0f8a4e90, 0x492e101e, 0xec702dfe, 0x28272f11, 0x46cb8261, 0x0bc32041, 0x403fe392, 0x994d4d6e, 0x71bbbbb3, + 0x8ff2f418, 0xb2c766d4, 0x5fa428e9, 0x141afe2e, 0xd57ac4d5, 0xc838d3e8, 0xb23d96fc, 0x1c65ed9a, 0xef950cdc, + 0x62905f52, 0xd68bfaa8, 0xd62d09d9, 0x104893a7, 0x5845bc12, 0x01d30645, 0x13e04341, 0x0e9ca5b8, 0xabc30492, + 0x18ad639a, 0x10476562, 0x9c9c7588, 0xcbbd6e50, 0x9cd87d2f, 0x3a9cc243, 0xd0ecd5a9, 0x917c3ab3, 0xa2b2a11c, + 0x338930d0, 0xde8461f9, 0x9bab6e7d, 0x625b75ef, 0x96e7751b, 0x85579208, 0x48c084ec, 0xe6a0a31c, 0x366dbcae, + 0x398bf125, 0xcac5dba5, 0xe56cc9c9, 0x550351b9, 0x4ff51a02, 0x7a031b8f, 0xa11b6c52, 0x722ff5a5, 0x1d939863, + 0x19f1f76f, 0x78b8bfd9, 0x86efc05b, 0x797d8c9f, 0x2c20380a, 0xc9d9c1f2, 0xcd8df05f, 0x1e924364, 0xa66ccfc0, + 0x17aa8f40, 0xbdea9cef, 0xda76a7d3, 0xc035824f, 0x0d52e478, 0x49a34da9, 0xa8556548, 0x201490b1, 0x80ff4e9e, + 0xa41a4c61, 0x28b494e1, 0x45fd50a5, 0xc00eab5d, 0xfffd3778, 0x8135a21b, 0x1377060a, 0xefc58ccd, 0xa0a72db2, + 0xd1f155e6, 0x94b6634f, 0x1c28b46a, 0xa43d5981, 0x680dfda3, 0xd154b093, 0xa75846cb, 0xdf994974, 0x57f1f742, + 0x32792cb8, 0x7d74bb8a, 0x80c686e1, 0xf413afbb, 0xf9c5d1c4, 0xbbd1e056, 0x975c77ba, 0x15813012, 0xbe998efb, + 0x54535744, 0x5c108267, 0xac2417cf, 0x3babad07, 0xa81dfa07, 0x787b01e8, 0x8a729310, 0x59f9b724, 0xe2b6aa59, + 0x1b7efb4d, 0xf05cc54a, 0x1d28c729, 0x321bcf2d, 0x582473b7, 0x7394ea36, 0x820ea8f3, 0xc1217361, 0x09713037, + 0x636f493e, 0x007499b6, 0xacee3bf0, 0xa4ab3775, 0xe1f1cd55, 0xf90aacd0, 0xcf1aa0f2, 0xc87e5a7b, 0xd9749e71, + 0x9a8e70c1, 0xb4f2c576, 0x08d283a8, 0xfaeff5cf, 0x18deb802, 0x0681f43c, 0x0ec2644a, 0xfc2db829, 0x3a294b94, + 0x7b8b87a3, 0x2c87b7c1, 0x3dc26ed1, 0x63677bc9, 0x3e80dd2f, 0x9ddd0896, 0xa1e64c71, 0x2fd9a6cc, 0xe01f1b3e, + 0x7b7eeafa, 0x7764c425, 0x2228cee5, 0xe7b2cc64, 0xc5bc9504, 0xba7c5b39, 0x823cb41e, 0x9fa23112, 0xdbe8aace, + 0x80cad5b7, 0x73374c38, 0x09b308bf, 0x8fcf55cb, 0x3eedd642, 0x41bd1638, 0x6c78178c, 0x803968b9, 0x9699e258, + 0x3d99e084, 0xbf996b9d, 0x1378dea3, 0x55ea184e, 0xc4564f6b, 0x88a2f485, 0xf8a727a4, 0x42dd266d, 0x5326d0fa, + 0xb212e46d, 0x2cdc5ea6, 0x933a9cbc, 0xd2222e4f, 0x642b8ea5, 0xdefcd8a0, 0x7aa26a09, 0x1dd18c1d, 0xdf1c5b00, + 0x5d9bbaee, 0x30c1bdc6, 0x5b99553b, 0x50e520c7, 0xb520e793, 0x90c14298, 0xd9b66c23, 0x5e09c653, 0x29a87af6, + 0x25c44499, 0xb05ad227, 0x3335cbf2, 0x7553c4e3, 0xe78a2966, 0xa1c6698b, 0x64a2a733, 0x5ac87772, 0xfda0bf7b, + 0x8b04fcf9, 0xa3ecc788, 0x482ebefe, 0x460f34b9, 0x52857507, 0x0bf5c058, 0x3033244b, 0xbe9ea897, 0x5c63073f, + 0xec31407f, 0x919169f8, 0xda4b3dad, 0x73104290, 0xddd12966, 0x1da4e765, 0x61e71458, 0xea16049a, 0x7f2c3813, + 0x9d80486f, 0x0c312741, 0xd003f267, 0xd4de5a4f, 0x81f6e3df, 0x79e2558d, 0xc2799ee7, 0x13a9cfbe, 0xd49e92aa, + 0x7646980a, 0x5b2a9f3d, 0x8bf057ee, 0xb8d360e4, 0xcdfdda9d, 0x48668594, 0x552b7d25, 0xf1a44eae, 0x9d64b2a4, + 0x0b9dee8f, 0xa81a48f7, 0x051fb503, 0x58d62b24, 0x4af4d0b9, 0x27df4a95, 0xa498a4c2, 0x70ec222c, 0x78a95b9a, + 0x99408643, 0xbfc9eb0b, 0x769b31dd, 0x3a13ea99, 0xf1d4923c, 0xc5f13462, 0x780e83d1, 0xfbf8b981, 0x16c05f2c, + 0x7f718a89, 0x98fe7455, 0x27faaf62, 0xf4d54bff, 0x23ef6aae, 0x1f476058, 0x8d2d4dc8, 0x8a2effc5, 0x664f005e, + 0x438088a3, 0xa3e58980, 0xbd49c491, 0x4570e043, 0x9e896916, 0xc51a182f, 0xb0014647, 0x58f77880, 0x633ad150, + 0xacf9b536, 0xf1616cb8, 0x34bf7f25, 0xdf2ea8ff, 0x2c643b43, 0x434a48d9, 0xb9301d00, 0x1fd4eb57, 0xb7539df2, + 0x20ecc9f4, 0x4f949d8f, 0xd3c76fb9, 0x3990950f, 0xa8a9e285, 0x3a8e14f5, 0x6640994b, 0x77b9dc8b, 0x5a36847c, + 0xf524f9dc, 0x097d6da9, 0x91ca4b6b, 0xaeeda057, 0x29f9994a, 0x9ed81712, 0x86f40331, 0x7105c98f, 0x01d40f5f, + 0xcb3b7dd3, 0x12c2776f, 0xc9a35081, 0x22eec1ba, 0x851814f2, 0x6ae56bc7, 0x1d584e2b, 0x66deac06, 0x43f48737, + 0x056dca22, 0x36c0415a, 0x516d6ecd, 0xaa48f3e4, 0x0f5d3e20, 0xdb311219, 0x26b0059e, 0x5186f3ec, 0x7b17e11d, + 0x7a471ac8, 0x146b15ff, 0x745aad0d, 0xcd7eb039, 0xa7f32766, 0x8f205430, 0xa9a3e532, 0xdcb892f8, 0xdb01f76a, + 0xa4de1252, 0x451dee12, 0x60cf949c, 0x30f02285, 0xc3358d83, 0x14620232, 0xf1865eaa, 0x9dfea45e, 0x02db1b37, + 0xf8bebc9e, 0x67c4dd2d, 0x5c60ff6a, 0x8a54cd9b, 0x73f6d63d, 0x0cb5348d, 0xd4de588f, 0x48c98d60, 0xc5e8a755, + 0x62510ede, 0x10158e2f, 0x0b662dbd, 0x8688bed1, 0xb81be10c, 0x2799fb1f, 0x510f9778, 0x2d7a5787, 0x3bb25bb2, + 0xce52a408, 0xed96bd8a, 0xb826d592, 0x5adcd580, 0x9d6b2cfc, 0xabb34b18, 0x929aa582, 0x3aa821ad, 0x601684e7, + 0x1978137b, 0x9276c03e, 0x465a3566, 0xced6eda4, 0x488efec3, 0x8222679d, 0x49060bf7, 0xd94f0b9d, 0x3eea15e5, + 0xc6524a77, 0x5120006a, 0x3c14f579, 0x998446c6, 0xf62b319b, 0x12802e81, 0xf7f96edd, 0x78365a77, 0x52b816fe, + 0xeac8d602, 0xdedfe87e, 0xc46eb35f, 0x7125c895, 0x4d52da03, 0xf69d3bcc, 0x34c449e0, 0xf7c02a36, 0x211998e7, + 0x45aef6cd, 0xcb0d2c65, 0xe642be04, 0x644f2048, 0x5b879c5d, 0xbd3b7671, 0x920ce6f7, 0x50f69ecd, 0x8659be0b, + 0x67aff85c, 0x8e261388, 0x49905233, 0xa7ac3785, 0x7252a651, 0xdbedd961, 0xe21026bf, 0xc7fe3c28, 0xe5f58601, + 0x071bd15b, 0xbf9ba0d8, 0xf8dc3613, 0x756e4ce0, 0xcd7e2994, 0x134d126a, 0x31957df1, 0x04ff51fc, 0x8ec172fe, + 0x5ba47c67, 0xd4a73524, 0x733225b7, 0xdc0109d8, 0xa3c7ecca, 0x81ab6d84, 0xca481d00, 0x2614e54c, 0xd8836a0e, + 0xf797e798, 0x52f35e17, 0x05eeec7f, 0x54e6ff3c, 0x4fb13748, 0xd6e63d3f, 0x83384753, 0xedaa4774, 0xf77b4fe4, + 0x3283b7f8, 0x1b36a29b, 0xa27022b4, 0x13193991, 0x8692498c, 0xedb89af8, 0xc78a1454, 0x4cc8e1e4, 0x3ed0c90d, + 0x7bb0d895, 0xe26da189, 0x8b14c114, 0x88fa5d8b, 0xab58b9ff, 0x255e4dee, 0xc783c3f6, 0xa1bde3d7, 0x1641651a, + 0xc17ac9a3, 0xd78b6981, 0x89c568c7, 0xd8b37a96, 0xa691f35f, 0x4f45f0c9, 0x4f6411ea, 0x559a3690, 0x279220a6, + 0xb8c6e709, 0x28df7e2f, 0x904b69d0, 0x414cf639, 0x2e5b473d, 0x0bb171ad, 0xebff136d, 0x7c99860b, 0x9e62fc80, + 0xe3047406, 0xdacc65b3, 0x6f07fe32, 0x64d93521, 0x051f5f25, 0x95bbb93a, 0xb606a1bc, 0xaca2b051, 0x2c38b23e, + 0x50a00bbf, 0xec1f6a53, 0xa4b5949f, 0x20110fae, 0xc8b78914, 0x3799e053, 0x1478adb4, 0x98336f7b, 0xefb0cb97, + 0x86d86064, 0xb3a28dcf, 0xa6b07d15, 0xa18e6b2e, 0x60d72e75, 0xc09a2bdc, 0x0b1ae121, 0xc343ce4a, 0xc4fdfb44, + 0xe936a636, 0x8942c979, 0x0ed86bdd, 0xfea51459, 0xd3b4f028, 0xdc53e391, 0xf6eb9d33, 0xec5c45ea, 0xbce34480, + 0x6d4b6220, 0x037d50ed, 0x66488308, 0xe9ee8c1e, 0xec649887, 0x74a79f87, 0xc498ab0a, 0xf55f65c7, 0x808f6d68, + 0xf1af687a, 0x4dfda615, 0x9e3bce5c, 0x43e682cc, 0x5e317f6b, 0xee25d4f1, 0x6931f8cc, 0x4dfb777f, 0xee055d49, + 0x618c7e9e, 0xaed7bdcc, 0x1fd7d0b7, 0x9e0f912a, 0xdd1e3ca2, 0x53743d60, 0x58a59af8, 0x1bce2187, 0xf56593a9, + 0xd411eebb, 0x88036b67, 0x943ba760, 0x4ce22154, 0x995cf282, 0x9d2da6aa, 0x7c8ad72f, 0x2a22df50, 0x168205d7, + 0xf062b32d, 0x3331eab9, 0xa8f442f2, 0x2b7429da, 0x109d7b42, 0xffabc479, 0x3b40618f, 0x52d31552, 0x83c8ba9d, + 0x7bce02f4, 0x43446990, 0x74e218fd, 0x5fc6c04d, 0x5dc9201f, 0x59bbb3ee, 0xb6539fde, 0x3682542a, 0x6c9e66fb, + 0xeec66c6b, 0xf2e49796, 0x30995e43, 0x16822681, 0x86eb7302, 0x4bb517f4, 0x53602d6d, 0x1c80f0b7, 0xddcf45f6, + 0x866035b6, 0x080d3370, 0x0cb7eeaf, 0x6e77b71f, 0xdb46cceb, 0xf866e9d6, 0x15bf1a8c, 0xc555bd6d, 0x2c776b9a, + 0x1ea77145, 0x23b18cc5, 0xad31426d, 0x4875abc6, 0x6c687590, 0x23d13b12, 0x0ebb777e, 0x1932d3e7, 0x61c9dacc, + 0x51a1a78c, 0xb8fad0a9, 0xcda06317, 0x83c1c9cb, 0x41317059, 0x40358b62, 0xdecc7605, 0x2020c996, 0xa526db1e, + 0xdc5cebd3, 0xff59e42a, 0x833263d5, 0xd28b694b, 0x605303a5, 0x0823d672, 0x81b8f38f, 0x7d696d66, 0x664ff5ce, + 0xe3c3216c, 0x289c1ecc, 0x1cdc7729, 0xf25a271b, 0x4c53e9ac, 0x5708b346, 0x25eaf887, 0x513c41c8, 0x0a7c739c, + 0x6cefb52a, 0x939c1d4d, 0xb406da10, 0x789b75a2, 0xe1184344, 0x78ed77ed, 0x9287aac9, 0x0b12d792, 0xb6fa376e, + 0xeb06250d, 0x88bf0d91, 0x4c439112, 0x69445419, 0x15a25489, 0xa23603b7, 0x0d424c6b, 0x7a68eb5c, 0xd8176c4e, + 0x3926605f, 0x9659e5b8, 0x0c7325d5, 0xb5501ca5, 0x3bfc5e7a, 0x7cbd0d92, 0xb2a42581, 0xa18981a7, 0xb44d99f8, + 0x43ab6046, 0xad1373b1, 0x3996baa2, 0x80580eb6, 0x7fdb1c61, 0x7c6999f5, 0x77cf069f, 0x11136ab9, 0x67e0e354, + 0x26dffa31, 0x7918e19d, 0xf7d96fbe, 0xb6c25fb1, 0x46a2a855, 0xf2530332, 0xf70b0a37, 0xcce7a21d, 0xf9019a7c, + 0x27632538, 0xa83a2db8, 0x3000cbe1, 0xfacab9fe, 0xf4ea9c2c, 0x87441c95, 0xf25d57b8, 0xda95ecc7, 0x2bc3301d, + 0xbe4d39ee, 0x3501fd2e, 0xabde6e79, 0x777996b6, 0xc92efaaf, 0x4d174241, 0xc224ae51, 0x0b6dbbd9, 0x82015dc1, + 0xf6d30a70, 0xc3d3173b, 0x5743a4a8, 0x614ae082, 0xbcef2145, 0xbd0a51c0, 0x579c964b, 0x0a6cc0cf, 0xc72dc6d3, + 0x441d7076, 0x93e62c9d, 0x14a2b7b5, 0x6f4ce676, 0xf8615c15, 0x93416a7b, 0xd483d15c, 0x618ef7fe, 0x82c01366, + 0x0ec9f5ca, 0x4883aba1, 0xbbff83d4, 0xc5816d90, 0x2e52f164, 0x45960e60, 0x85406392, 0x48b110c9, 0xa85dcdc5, + 0x0ba58a7f, 0xc6a1c66d, 0x8e5300f7, 0xa1f7f62e, 0xe1b96916, 0x364663f2, 0xd44a7844, 0x0e235e8a, 0xf0cce563, + 0xe2cb27f9, 0xc363cbe7, 0x9a51f4ce, 0x2094f47b, 0x4ca485f0, 0xb828ff88, 0x0ee26807, 0x873c89da, 0x6523eb26, + 0xd3c45fe7, 0x9ebb6a18, 0xb3298e9d, 0xf4d955b3, 0x39999cf1, 0x669540c5, 0x2918f782, 0x0c8b414d, 0x3de25bab, + 0xe68ebfc2, 0x4dce4c99, 0x33437ca8, 0x0344609a, 0xc4280451, 0x615035a1, 0xbc98283d, 0x42f33099, 0x1a261fa2, + 0x8f956da4, 0x67a7bd9d, 0xf070487c, 0x23b57fc5, 0xbbb11166, 0x771f6f4a, 0x42f3230f, 0x39a6e0e0, 0x72b10cef, + 0x5fec17f9, 0x59b3bff2, 0x82e6c2d2, 0x1c7b3e0b, 0x06cd7f0b, 0x6d737016, 0xcd3b804b, 0xcc1b8a1b, 0x3614ae9a, + 0xd16e1c26, 0x76fda834, 0x779e9db3, 0x42cfb71b, 0x83b0eed0, 0x3b28b3c4, 0xc1c34fc8, 0x98f271cb, 0xa46384ac, + 0x14a05fc1, 0xdd739d9d, 0x11555c86, 0x557113d1, 0xdb4707fd, 0x6d967203, 0x5a65e033, 0xefabd855, 0xf81af303, + 0xe8f776c3, 0x5b00f8d2, 0x3ec7becf, 0xeb9dc95f, 0xf047d33e, 0x8a4ab91a, 0xf4b2a94d, 0xdf512749, 0xcece0f1e, + 0x1e359c39, 0xbd1bcd07, 0x381f2986, 0x9a4bf0a7, 0x3101daa0, 0x35a1be71, 0x000eeb95, 0x26705de9, 0xd4914d75, + 0x38f08e23, 0xbae347ad, 0x0c05d49c, 0x249ebf23, 0x935d28fd, 0x1b6d392d, 0x357d55e5, 0x26b890b5, 0x27c3c25b, + 0x08245f0f, 0xb82b4453, 0x103ca1ee, 0xdc57f827, 0x987e2aad, 0x9dc59066, 0x004bbd5b, 0x1ea51cb2, 0x9b3b090a, + 0x6edc139f, 0xc6237d07, 0x1951c72d, 0x8e666a5d, 0xba4fcdee, 0x83892681, 0x0efb9452, 0xfcb2fe74, 0x3f2eb6f6, + 0xbcc63ce1, 0x977c07e4, 0x19896f3c, 0xd0ead99b, 0x45cfc381, 0xa4bd415f, 0xa8398ec9, 0xb7c0003f, 0x4f39d2dc, + 0x46a25943, 0xa6d70a93, 0xa059d223, 0x760aa5d3, 0x9e4ec45c, 0x2499d89e, 0x0f7cbd91, 0xf013d104, 0xadaba1ae, + 0x8845c20e, 0x909ae4e1, 0x3c392ff2, 0x426033f5, 0x62eaaca7, 0x43220ce0, 0xdd7fb4f3, 0x772f0471, 0x80e27ea2, + 0x087c8bc5, 0x791dccbd, 0x7be42170, 0x2ec3a1e2, 0x92287fbf, 0x14a6e8d2, 0xd02c0579, 0x0bd7684f, 0xf4b1be9e, + 0xd06ee67d, 0xda1c6c05, 0x2f91884d, 0xffa3659e, 0x0a98e96c, 0xe611045f, 0xe84cfbea, 0x79183b31, 0x850d96db, + 0xee21e744, 0x27c67fdd, 0xd5a07095, 0xda2be062, 0x2bc1409e, 0x66b9a7b9, 0x2427f195, 0x230a4de2, 0x9670728a, + 0x62ea4307, 0x642ded24, 0x0e1b717f, 0xe3623647, 0x36a58508, 0xec876b74, 0x97d2d6d3, 0x6fdb16a7, 0xd5d80120, + 0xb14511bf, 0xa9d6a848, 0x2e286f60, 0x5fcd3f28, 0xefaf8673, 0x825f237d, 0xa3381b29, 0x2291b6ba, 0x0532c387, + 0xb1bec930, 0x2fdd4072, 0x966ca556, 0xbcacc239, 0x92f6fcfd, 0xfa60791d, 0x883703fd, 0xa622822b, 0x5689c183, + 0x9c196a80, 0x3e956f4f, 0xc26b8700, 0x6c5f1766, 0xc8c56bf8, 0x398b9423, 0x7ac59ba0, 0x48e04f03, 0x2bf7776d, + 0x8f454a96, 0xdc464ad6, 0x9fdd708d, 0x012826d5, 0x157a2990, 0x286c56cc, 0x6845b0dd, 0x9d71b7f4, 0x893fbac0, + 0x11e2f94a, 0xfdf9acd9, 0x6d352c80, 0xd56c7a04, 0x05d3a9d4, 0xfbc6593f, 0x46ca30f8, 0x9e2d89e6, 0x4c685c59, + 0xcabe5d86, 0x2e4ad4c1, 0x09f131f7, 0xfab8fd66, 0x4dc55daf, 0x973b4225, 0x60d266fe, 0x046b9bc1, 0x78c11599, + 0x3cd41583, 0x1d322671, 0x30f17c05, 0x2b5d0263, 0x45f0c0f4, 0xede45ed4, 0x0b166639, 0x6787f5df, 0x07a0ef3f, + 0xb4488723, 0x6b9042bf, 0x15fcb7ba, 0x749c89bb, 0x8c75f29f, 0xe0940f69, 0x893cf9a0, 0x45e5f45d, 0xddc3bc7d, + 0xd796914c, 0xf5743444, 0xe6f9d705, 0x9a770451, 0x51f0c1ab, 0xbd51f5f8, 0x63352e07, 0x054cd923, 0x2cb0f123, + 0x7da8300c, 0xc0a1c420, 0x03947c79, 0xb1d8eb42, 0x7900379c, 0x2f031ac9, 0x9cb4f474, 0xdf10ce24, 0x5a6510b5, + 0x46b0aa9d, 0x7a34bb07, 0xf8ac2eb5, 0x319cf430, 0xf7362b44, 0x0fa6239a, 0x68d40751, 0x6c861672, 0x1fe11832, + 0xf39e02d0, 0x5a236651, 0x9650495b, 0xdadca2a9, 0x047e857f, 0xbe437fc0, 0x9886a945, 0x6194116d, 0x0a971099, + 0x043f4293, 0x97f8f4c7, 0x2ee0c0d9, 0x7f8acc59, 0xbcde57a4, 0x31998932, 0xd9a6972f, 0x874480a6, 0x9150d2e0, + 0xe8ca5dd4, 0xbb1d1871, 0x8dc8905a, 0x863380a2, 0xcc4329fb, 0x562443f9, 0x45a24ba0, 0xae7ecdf4, 0x0ca4fda3, + 0xc0eb4a3a, 0x63610c1c, 0xa568d03c, 0xf8140538, 0x86212ad9, 0xba6bdb61, 0xd6a27b40, 0x5ce5706d, 0x95d6d89a, + 0x4304fc48, 0x9a29ba8a, 0x01284161, 0x5194abff, 0xa1ff1ade, 0x5a26b12d, 0xb08fba1b, 0x793bec67, 0x06950dbc, + 0x9b97b023, 0x636b3e09, 0xa03022de, 0x6b75fccd, 0xab580ae3, 0xe8178504, 0x49cbebb4, 0xad724ea1, 0xb0f80ba7, + 0x092d0156, 0x177e6c3d, 0xf0ecf08e, 0x199a58ea, 0xf33f2f1d, 0x1fbd26be, 0x16031e79, 0x4287e0f1, 0xffc18d0b, + 0x96171341, 0xd465976e, 0xd64d28ac, 0x0eb9dfaf, 0xe3fc76f8, 0xcae9c384, 0xd2b8632c, 0xa60a18e5, 0xbfa9a163, + 0x7949ff2f, 0xd850c950, 0x0fb55763, 0x40c61a7d, 0x66ad6eec, 0xecaa4617, 0x1d92cf6a, 0x3f8000b0, 0xe1734d4c, + 0x3df056e5, 0x1e4d0a4a, 0xbe457ac8, 0xe2256082, 0x55c328ff, 0x11782ec5, 0xc7bd7849, 0xb3a6c57a, 0x6dd5069f, + 0x27ee35b4, 0xc2fe1270, 0xc1e1a467, 0xd6b564cd, 0xac2ff97d, 0x60d235d8, 0x7b823e4c, 0x821bf57f, 0xec480b63, + 0x1090f0e6, 0x313e7f19, 0x226cfae9, 0x3d9b3174, 0x6ca10af0, 0x559fea46, 0x4cd7ce01, 0x167ba220, 0xafe6bf4f, + 0xeab1f146, 0x81df3f10, 0xc794e175, 0x010f6c96, 0x288c3629, 0x59b69cb8, 0xea0fbc23, 0x6cce1f94, 0xa195e8fd, + 0x8e4390c8, 0xc2b49c71, 0x60de3a30, 0x3821defe, 0x0d62ee3a, 0xc75b4098, 0x06c6fcbb, 0x0a37c1ac, 0xcdcff1e9, + 0x8d50117c, 0x6c348949, 0x2a395ab9, 0xd4affb04, 0x0f27a1ab, 0x856cdc11, 0xa3ef76d5, 0x0d7d98c1, 0x5ec8f319, + 0x4bb0ccca, 0xf525731b, 0xedf753ea, 0x9898e74c, 0x290037e7, 0x42c3b978, 0xaa20a7dd, 0x0ddc5fbc, 0x066b1f91, + 0x476711ec, 0x765cfbc5, 0x6a171e40, 0xbd56dd07, 0xda91903a, 0x0fc87db9, 0x5be7c6e3, 0xa23cf93d, 0x74f9b9bd, + 0x1c871072, 0xa11ce41f, 0x0134d58d, 0x4d96f592, 0xb22d512d, 0xd52f7ce2, 0xecad8e72, 0xfb72b6bf, 0x2740081e, + 0xc0208556, 0xdf3b29c6, 0x8cbfb780, 0x3f37e64f, 0x5ebef626, 0xe9a5d14f, 0x6b7bbc56, 0x81879327, 0x35de43a3, + 0x1f410c0e, 0x70e95976, 0xf865ec86, 0x83ec5a5e, 0x65a90fae, 0xbc4735f2, 0x925b3c69, 0x10e002f8, 0x5430266a, + 0x4c53c591, 0x8f52ea33, 0x8c3bc9f2, 0x97b089a6, 0xd4ad6dd8, 0x533a746d, 0xbcdaadc3, 0x48bb3824, 0xa5fbb8c4, + 0xb8aaaa0f, 0x1c415c4b, 0x3cca69d4, 0x82b90842, 0x775c2596, 0xe5a52bde, 0x442a943e, 0x97b1ec2a, 0xee6ff4e7, + 0x9e568955, 0xcb5ec8fe, 0x6c3651e9, 0xffe3a8a6, 0x48882d28, 0x2db795a9, 0x36977b58, 0xf1db25aa, 0x560ec76e, + 0x606c3afe, 0xb65c23a6, 0xa2857d5b, 0x0cebfb96, 0xf7492fc9, 0xbf43f0cf, 0xb3794d30, 0xc9cceff1, 0xf4f80d42, + 0xd82003fb, 0xbbd8a871, 0xa77776aa, 0x2e8abc91, 0x7ad9cc40, 0x02ee8a4a, 0xd099d01d, 0x75f9f699, 0xa281832e, + 0xc4a405a2, 0xdf282543, 0xfbaeddee, 0x06eb7bf2, 0x87c87be5, 0xf41c3030, 0x769e35a8, 0xa4f17a93, 0x63883c25, + 0x93b21f2f, 0x518851bb, 0x1783afee, 0x8bf19b4e, 0xf8c33eb7, 0xb5e4035f, 0x3d99b075, 0x6da64133, 0xae9f8000, + 0x1a0946ff, 0x36ffa534, 0xe9404dd5, 0xd5814f46, 0x18e9aa2c, 0xd9e55f60, 0x0ab25a7d, 0x3480863d, 0xa5d7ae34, + 0xf652f4d8, 0xd76b8882, 0x6ce321b1, 0x1efb49d8, 0xc9c9a254, 0x5b0e7ea7, 0xce07b49f, 0xcbb32aff, 0x3ff60673, + 0xd76a8f0f, 0x475dfabf, 0x08b2a7a8, 0xef5a9d05, 0x4f8084bd, 0x81d31f25, 0xe4af7ac0, 0xd0aff4dd, 0x5571edb1, + 0xb38e0d2c, 0x08856003, 0xb3b88f5e, 0x5d9435c3, 0x7fbe6a41, 0x3f296926, 0x4f757d2a, 0x9a545dd4, 0x208007fe, + 0xe8b26164, 0xae08f1bb, 0x22b4f220, 0x819f435f, 0x6cf00ff5, 0x7f644ed9, 0x77185705, 0xc23970be, 0x46f2f4c8, + 0x7e395fe7, 0x1f91edf8, 0xde81840f, 0x058e3971, 0x39812341, 0xcf8aa2e4, 0x77294d7b, 0x83d5d057, 0x87b24fd6, + 0xee3507b0, 0x7bb86170, 0x012ddb5a, 0x1c7c2ba7, 0xe0ca9ae3, 0x2577937e, 0xa0c6284e, 0x2036c3c0, 0x48e4f662, + 0x621719bd, 0xb6ea8784, 0x017bb088, 0x258dff4e, 0x995ab843, 0x9dd47fac, 0x9ec38755, 0xe339e796, 0xe94e942e, + 0x1d54a42b, 0xdd740fba, 0xa71624c8, 0xd286c9d4, 0x02eea51a, 0x70ae7113, 0xb58e0bc9, 0xaa5378d5, 0x9d9e77d6, + 0xda92c4ed, 0x786b9b87, 0xdcebac5f, 0x60058baf, 0xc0809fee, 0xa9ce83a2, 0xdeb684f8, 0x1cb8fb2d, 0x330227b1, + 0x0dae1eda, 0x0f0c4f5c, 0xbe35c1eb, 0x76d0d7f1, 0x9cd6aa46, 0x82bec3d4, 0x3f5fd8d1, 0x7af98c84, 0xa6647cb2, + 0xa19587e7, 0x9a539b6e, 0x6e84d2b9, 0x35c28af9, 0xcf2a25ae, 0xa66d1596, 0x7e7a05f4, 0x678c31fd, 0x15c11fd2, + 0xaf1daaab, 0x1fafbfe1, 0x9b97ae35, 0x86c3a9ec, 0x0a43de5a, 0x1eb2bff8, 0x6ace500e, 0xa6e6c12c, 0x9d3616b5, + 0xa76a1357, 0x15d48739, 0x0cac0d4c, 0x57064153, 0x1ccf21c0, 0x5972fcd6, 0x652adf18, 0x758ea6c0, 0xf87f0f39, + 0x3336a6df, 0x77e55714, 0xa2a09498, 0x2de53db1, 0xff53cf43, 0x3416de64, 0x68c9092d, 0x6978b202, 0xeb35986b, + 0x13820751, 0x9b4ce0e5, 0x2ce8e088, 0xb31d023a, 0x48ac853d, 0x9e46da55, 0xb0db5861, 0x5cfd4834, 0xe04cf7a5, + 0x3deade06, 0x47645545, 0xe3e14b83, 0x5224d3fe, 0x76f7f79e, 0x1f606ba5, 0xbcc7d8c0, 0xdbf39a1a, 0x9a754b89, + 0x670db66c, 0x36cb62fb, 0x50e67933, 0x0b56444a, 0xe2074e71, 0x16af777b, 0x64ab726d, 0x14326ea0, 0xbfe4c41e, + 0xb5751555, 0x30823ac9, 0xf3bfc862, 0x47ae5045, 0xea0a74b9, 0x1028db88, 0xcc5fb22a, 0x782a6154, 0x68d45460, + 0xbff4eb70, 0x41333642, 0x3dd912b2, 0x2d77bf00, 0x73183be9, 0x6e4322ff, 0xfc73b02f, 0xc483fe54, 0x9082d7f8, + 0x919de582, 0xb40b4dad, 0x915c835a, 0xc0d2b7fa, 0x8ecce28a, 0x23aa8eaf, 0xc7f5a003, 0x664467bc, 0xad8c81d4, + 0xb7cadfa5, 0x81772c98, 0xc99202ce, 0xe9592155, 0x504b04f2, 0xb2ba3201, 0xab2da225, 0xb9f4299f, 0xadefdda2, + 0xd4c8ab53, 0x02a5c180, 0x025c417b, 0x34882cc9, 0xd0bbf6e0, 0x76996755, 0x919f41a5, 0xa8bf1f0e, 0x9e645f86, + 0x0d75171f, 0x9238ed63, 0x53062e7d, 0x92eb7786, 0xc1a8891b, 0x5a92aec7, 0xc32704af, 0xcf4d18f9, 0x58699d2e, + 0xb48e0534, 0xbbdbbe25, 0x0fc34ead, 0x98693359, 0x41b21321, 0xdd866886, 0x5a47b4a4, 0xf6e7290f, 0x6aa6d6e0, + 0x13e2ccc8, 0x7d31e135, 0x0f18b17b, 0x3056f1f2, 0xd2be282a, 0xa9bffe19, 0x72e4b7c4, 0x1913474d, 0x026ab003, + 0x60b3798f, 0xb317e6fd, 0x394f4695, 0x66062af5, 0xadd30aaf, 0x51a2be15, 0xdcb4b3ae, 0xffa7729b, 0x05e657bd, + 0xda069bdd, 0xf7ea1ef4, 0xcbe61a44, 0xa0c02913, 0x3e286b6f, 0xa01177a0, 0xa8795598, 0x9574cbcc, 0x7226583d, + 0x7202488f, 0xfdfe7769, 0x91bab26f, 0x3457e7e4, 0x7e97b5e2, 0x18369632, 0xb0ab9189, 0x674f0a2b, 0x45e58c22, + 0xd027bacf, 0x8b612f0f, 0xa2b86fd8, 0x5ebc59c2, 0x6d5b3379, 0xa443bb8f, 0x9b8b397c, 0x17e4c52b, 0x6a52e435, + 0x25cff4bb, 0x1ca6c588, 0x7ca7c7a7, 0x22cb8b10, 0x00c400f6, 0xf3ca8ce0, 0x6e79c472, 0xcca729a1, 0xaf5efab8, + 0x60954e02, 0xc73a64b1, 0x520b03dd, 0x23fed52c, 0xae3ad3c2, 0x2a2acb76, 0x07eefe56, 0x9fc675ab, 0x025fc7e9, + 0x3a5aa9c8, 0x93950ea3, 0x1a23ffa1, 0xe735485f, 0xd759e66e, 0xc2a8a5d2, 0x973dc4f5, 0x90cceed4, 0xa5d81e84, + 0x1cacc1b7, 0x1444d80e, 0x17ec070f, 0xc1c506b7, 0xd095b16f, 0xb227ab22, 0x221f4518, 0xf64d0223, 0xe5e18540, + 0x0801e2be, 0x4383780d, 0x179ef686, 0x678480f5, 0xa0f71479, 0x307f971a, 0x0516c371, 0x3a5f700b, 0x6c346565, + 0xba6bc53f, 0xc0346d94, 0xd6d39ee3, 0xe4724725, 0x2a7ca73f, 0x1b4df43c, 0x2f538ebf, 0xa63f896b, 0x98ec5b01, + 0x1a99d11a, 0x8b15e6cf, 0x5159c42f, 0x8a99f6bf, 0x0e17060b, 0xf2ab6bee, 0xef379501, 0xe4e4ff02, 0x6ae8fcb3, + 0x9149b516, 0x963a9e75, 0x83c381fc, 0xcb12e0d2, 0xb6efd7ba, 0x15e38ca0, 0x75f4a25e, 0xa87aefb5, 0x9550c0c3, + 0x5c5586e9, 0x83665991, 0x695350e6, 0x79d802b6, 0xbe67f6ae, 0x337b4858, 0x8814bb34, 0x974fdf99, 0x7c0fa5e4, + 0x4a5d9a4a, 0xf0867a05, 0x89688003, 0xcd1d382e, 0x073a596a, 0xebb20ac6, 0x0de66360, 0xc0ccf023, 0x4d74cebb, + 0xee80bc40, 0xc61accd6, 0x7d017268, 0x1ee23b7a, 0x3418c1ca, 0x267c900a, 0x660c616f, 0xaa6b1c12, 0xfd6131d8, + 0x07ad755a, 0xe64cf4fd, 0xe63a3d20, 0x9abddd80, 0x8de38251, 0x60605310, 0x4117ce30, 0x70e5ab83, 0xb7ddfa8b, + 0xd11561b0, 0xfbd26ab0, 0xdc0267ec, 0x3d083f18, 0x6409f52c, 0x02f8a62d, 0x7873eea3, 0x5d1ab6fe, 0x0d13cc8e, + 0xf8bbe8d1, 0xa6b12759, 0x4e189146, 0x07122e61, 0xc359f240, 0x76d778de, 0x5bb09c47, 0x9033b7b8, 0x71f28e76, + 0xff1acd7d, 0x0f9d7aa5, 0x108da965, 0xcd868b89, 0x0a336200, 0xbcf7a1a8, 0x34a6f5b7, 0xf5dcc57a, 0x6089c8ce, + 0xf0796b1e, 0xcbf7843c, 0xb9842ab5, 0x6b3bfb2d, 0x0cbdcc43, 0x390fd209, 0xf39ea3ff, 0x1fe10601, 0xabe92710, + 0x790ce884, 0x221faf1f, 0x666edce2, 0x5bd3053f, 0xe1445b19, 0x589ae168, 0x27678200, 0x9fdb5ff9, 0x60459c07, + 0xf8b4f4c8, 0x388e45ad, 0x52271b70, 0xe36e3adf, 0xb42e9339, 0x9059a7e0, 0x32373e18, 0x342f144b, 0x578c31bc, + 0xb1e6a0e7, 0x17c9c586, 0xa53a4869, 0x92104bcb, 0xd33cdb14, 0xfc94f4e1, 0x51dd981b, 0xf118cc21, 0xc0c1d004, + 0x76263ea8, 0xfffd6500, 0xad0027e7, 0xdccaef6c, 0x8879a0dd, 0xe6ad0570, 0x98ec2faa, 0xc15b22ba, 0x55149f18, + 0x6f85773c, 0x28ced529, 0xbaff30a9, 0x74c242f1, 0xae8d5ba6, 0x3bf1bdba, 0xfd534019, 0xaf42b0a8, 0x8d1d62d9, + 0xd446610d, 0x0ed6558c, 0xb8d1817e, 0xe36c68f5, 0x20d7a971, 0xb3d6763e, 0xd7d4c347, 0x5a809d98, 0x5491112f, + 0x06b3ffd1, 0x50643fe0, 0x786118f9, 0x412cbf24, 0x2f7345ed, 0xda4021b9, 0xb78e8585, 0xec0cdad8, 0xe049f84e, + 0xf1687d08, 0x4d2dbdb8, 0xc1d796b1, 0xacc8da99, 0x3a62e22d, 0x56cb4400, 0x95a92b2b, 0x9588860a, 0xb1df406c, + 0x124120fe, 0x748cf908, 0x1e297ed0, 0x337d0990, 0x80c1da1d, 0xfa497949, 0xb75efdbe, 0xf88c5396, 0xb58cbc61, + 0x80e72ce9, 0xefbc725e, 0x7921d697, 0x2802e3dd, 0x2e3e31ad, 0x5a0c6138, 0x852ad4cb, 0x0a6c583e, 0x5b42b51b, + 0xfed9b550, 0xc4c85775, 0x205db5c6, 0x28e00dca, 0xab8b856e, 0xef1f3ca0, 0x8a91ee7b, 0xa3642651, 0x448a2d12, + 0xecc5dd97, 0xd6381ede, 0x36cfff69, 0xd3314957, 0x29772690, 0xc2a130e9, 0xf1b1bb4d, 0x493479db, 0xb25778bf, + 0xa39837ea, 0x5cbbe4ac, 0xe8920e60, 0xb86fcedd, 0xccd06859, 0x3e0f2956, 0xaf8f1c80, 0x257962f7, 0xf67c91f8, + 0x899e0780, 0x639e9de1, 0x669cab80, 0x2ecc7be1, 0xfa47bfe5, 0xebbd3e5d, 0x4fb3d76a, 0x773bd2dd, 0xbbdba49a, + 0xb3022168, 0xcb3b9705, 0x5139d7db, 0xb4799d8f, 0xd6c9b1b7, 0xf8fa606c, 0x48f932fc, 0x7ed67624, 0x657b3d60, + 0x09d5e091, 0xfc1e35a3, 0x3c116ca3, 0x738c2378, 0x6bba2836, 0xa520079c, 0xf975dcc4, 0xda1bfed0, 0xe23e449b, + 0x1ab8d7f2, 0x8d70a526, 0x027fe629, 0xe27bd993, 0x43c60b80, 0xc30bc506, 0x4c86aab3, 0x8a407f93, 0x1b2dcb55, + 0x370cf740, 0xa8bd17a2, 0x60a00ea1, 0x6111132d, 0xf30b6f7a, 0xc704c747, 0xb0f8d384, 0xf40a14ba, 0xf2fa4a9f, + 0x6a669cdf, 0x13c8514f, 0xe2e15f47, 0x46586d66, 0xabb2ffb5, 0xfbc2ecf5, 0xb85803cc, 0x64d36688, 0xef92ac8d, + 0xc45332eb, 0xf2fbf6ac, 0x4fabeace, 0x43c597d7, 0x00190905, 0x87e596b6, 0x3274f721, 0x0a979ba7, 0x7a3bcd62, + 0xd557b9a9, 0x6f494eb2, 0x72f08d04, 0x67fb4f76, 0xd9a3a67d, 0xb8f1bcec, 0x701bd1aa, 0x30206f96, 0xbbd8241e, + 0x1e534463, 0x510581b4, 0xc9fcbae8, 0x1df653ad, 0x1236d2b9, 0xe063c7b6, 0x64196b64, 0xd2b3f6fb, 0x2c11816a, + 0xeea2ec5f, 0x4c39dc41, 0x727c6eee, 0x2fb23155, 0xb840b8ac, 0x3a8c0114, 0x14a75660, 0xf1e82fb1, 0x6e7ec278, + 0x16a07584, 0xbca0a8a3, 0x3a93bf1c, 0x71643b30, 0xbb23d57a, 0x9fcc0c2f, 0xd7ba9a11, 0x276c16f2, 0xcd05fefb, + 0x794db502, 0x9206c66f, 0xe7d41ccd, 0xb0f65ffe, 0x94873d86, 0x257f85a9, 0x566ea46b, 0x88addbe5, 0x846409d1, + 0x617afd84, 0x8959c726, 0xd55161a9, 0xf7c2733a, 0xad9bbf90, 0xc166c26c, 0x1b898ecb, 0xbbd273b0, 0x5286ae4a, + 0xf3c55dac, 0xaa7dc527, 0x884e0987, 0xc0ba016b, 0xb2090c32, 0xaf5dfcc5, 0xe32f1505, 0xba9e6fd7, 0x907055ff, + 0x5294a7c1, 0x6a64cdf7, 0xca45ccb3, 0x3ea5a4c1, 0x36bc14c3, 0xed71c40f, 0xe84b8e8d, 0xee6c964a, 0xe78d5d7a, + 0xa5dc4264, 0xcb44fc5a, 0xc5e7752c, 0xfbd148fe, 0x0129de79, 0x9f6853e3, 0xbac0d75a, 0xc019d166, 0x2241dd93, + 0x7814c8f8, 0xcc022628, 0x656bb6b5, 0x3ef8a3a2, 0x300351d9, 0x26ccd278, 0x55cb927b, 0xc24ef3fb, 0xa9ae68e7, + 0xd7516fd9, 0xcc838aff, 0xd6766592, 0x31fbab7a, 0x6781281e, 0x1c94d598, 0x5b86f426, 0xf94354b7, 0x5ae0bec8, + 0x4f62c7f1, 0xed56ff12, 0xbb33b1ac, 0xb9cd0acc, 0x6312f654, 0xc569d605, 0x00a6cdf5, 0xe1bf89ca, 0xdb3b162c, + 0x92f83ff3, 0x6bc5be4e, 0xc7d2d184, 0x6ed1d93d, 0x589e9dd6, 0x60ea5f6b, 0x6cccea46, 0x998614ae, 0x45a69b6a, + 0x0231faa6, 0x2567bbef, 0x21ffc3ab, 0xe6266c4f, 0x365f5bb7, 0x2c199234, 0xccb89be3, 0x79f14a2a, 0xcadc3d56, + 0x10efdac2, 0x4077dcc1, 0xd32acbe1, 0x9d2e46c5, 0x8f2ba06d, 0x53a9b37e, 0xcd025979, 0xdcda1cad, 0x78d15a0b, + 0x77fe5b43, 0xf52d768a, 0x71ad27d2, 0x06094eb1, 0xeb65771b, 0xc8733df1, 0xe6e853c3, 0x5f5259e5, 0xcfbe65b3, + 0x3ebdb0e5, 0x10830a50, 0x63d5bf5b, 0xff64f4ca, 0xd12f8ba8, 0x1a247f59, 0x63abe622, 0x9f50c4c3, 0x23a7e72f, + 0x9eaccd86, 0xc6427d4e, 0x5cc56a46, 0xa0c18932, 0x07f14eff, 0xd281240f, 0x1b060eaf, 0x55f34edd, 0x502b7c6f, + 0xce5f1ca6, 0x12d2a3be, 0xa52b4d8c, 0xd0db712f, 0x169d0d4b, 0x36824558, 0x3aaa448f, 0x5c97de26, 0x123e9005, + 0x4dc04ee0, 0x32ef1fe4, 0xaaf35666, 0x7f66089f, 0xd7e3b697, 0x5167f56f, 0xdd3607e8, 0x7509f46e, 0x336e4472, + 0x0b5d2d3c, 0x90ac28fb, 0x4d7341c8, 0xcc043b35, 0x05a24c3f, 0xf4087742, 0x2d1d9495, 0xf1f9744b, 0xae4d50aa, + 0xd9175480, 0x964be744, 0x9622a893, 0x5a55909e, 0x6b7fcb40, 0xe8b5cc30, 0x3fc5c263, 0x99b7e1ce, 0x3941a09c, + 0xf8e0ef15, 0xb90c13fc, 0x9d36eb9e, 0x6e351af3, 0xcab13fd2, 0x8cf12dba, 0x695a93c0, 0x4cd54eb7, 0xd1d8aca4, + 0x68683f25, 0xd486d927, 0xcc7d4f17, 0x4dab1c20, 0x254855f2, 0xd98da09a, 0xbaffd807, 0xeda2f8b6, 0x66cd8259, + 0x758f8547, 0x564f7fca, 0x48ad0558, 0x701385cb, 0xab3d03a0, 0xf0564e79, 0x0076c294, 0x18281720, 0x99aa4d25, + 0x983732f5, 0x67b66f1c, 0x78dd7323, 0x7b2382db, 0x4565da6f, 0x93c88bd7, 0x37edce41, 0x7f7635a4, 0x242a3343, + 0xbb50331b, 0x48bf0934, 0x5bc2cd18, 0x0d806e68, 0x6ffcb305, 0x3813f02e, 0x4d596ab7, 0xda58ff37, 0xd3cb0080, + 0xb3850ebf, 0x6250a786, 0x005be16e, 0x618dfb04, 0x9ff00de3, 0x92b4cb8c, 0xd54b49c1, 0x20f642d8, 0xde6df33c, + 0x14d6d4bb, 0xbe82deb2, 0x9e395341, 0x5ec4b7af, 0x6c000029, 0x94c2733a, 0xb10f325b, 0xa6f1d5ee, 0xc26d0e72, + 0x97e4441d, 0xebf435bd, 0xc8455df9, 0x7587e934, 0x6ca676ba, 0x3268ae25, 0xa347a140, 0x5c7c80c6, 0xea7b7899, + 0x6ef704a6, 0x90d82598, 0x0e8a0723, 0xec6fa5cb, 0x1ca4b73c, 0x6a158c4c, 0x62dc206e, 0xc57ada0d, 0xd3c8c1e0, + 0x0e535d47, 0x0da951ac, 0x96b294de, 0x9b919db7, 0xe88e0ce2, 0xb471fbb1, 0x728f9bdb, 0x7c8d2b88, 0x95572561, + 0xbd912be0, 0x85979980, 0x518784dd, 0x76cd4769, 0x9a2190df, 0xe4328f4a, 0xaedaed56, 0x58462c7d, 0x2324331e, + 0xf89b0dc7, 0xca6efe03, 0x0e587950, 0x501e956e, 0x1928f92d, 0xaa59bf23, 0xf96eefe0, 0x612deae1, 0xff49d1fa, + 0x6b02c98c, 0x17a4a99a, 0xd8a3883b, 0xda209fbf, 0xfb658385, 0x13570972, 0x8ea0277b, 0xd8a26de6, 0x2aeedf08, + 0x058c6191, 0xad97a306, 0x6de55c7b, 0x67366749, 0x4fe986e2, 0xce96e59a, 0x82e7d4dd, 0x1bc7f4c4, 0x7640850e, + 0x8b0589f3, 0x166fa582, 0x17d0ae6a, 0xb85ec6d9, 0x0b6f4d47, 0x4463bc77, 0x0232c7d9, 0x2d2f785b, 0x8cfdc733, + 0x1a2db6ab, 0x3235e2be, 0xe7533409, 0xe5c8f74f, 0xc576e079, 0xaca48e60, 0x2d8384df, 0xaf824111, 0x4a51e424, + 0xc8d9c823, 0x22f980fd, 0x767cbf54, 0xcb3b0d62, 0xda88fda2, 0x0ae94a97, 0xaab93d3b, 0xe12e7041, 0x08e791e9, + 0x872b42e5, 0x2c0766f2, 0x08ec1cd4, 0x226078a9, 0x8fc64456, 0xf3c2e96f, 0xf960a2da, 0xb6b6c3a8, 0x5359740f, + 0x668333cf, 0xed694df5, 0x7ccc857f, 0x83dd114f, 0x88726d37, 0x09e8e326, 0x067aaf56, 0x3a5eb358, 0xce4d76a4, + 0xe3a49774, 0xf335130b, 0x3a1adb35, 0x650ecc84, 0xcda61b5a, 0xd9c0b847, 0x1705cfc4, 0x9b50e217, 0x80bfc4df, + 0x524f119c, 0x424fdfa8, 0x4586f24f, 0x53a35620, 0xc05bdd4b, 0x532339eb, 0xcc4b7afa, 0x8dbc88e0, 0xc0d925b1, + 0xc0f0c985, 0x174b1cf0, 0xe435fd14, 0xddbce9ff, 0x4a721879, 0x8e0f4293, 0xf3604b0a, 0xf08613ca, 0x8d3e5b61, + 0x839d65c5, 0x1d9eead6, 0xfaa48941, 0x462c38b9, 0xb3e12a4e, 0x8149db7f, 0x4d9c83f4, 0x84dfd3a5, 0xc09e27aa, + 0xd02d29ea, 0xd4a7af8e, 0x6a16a169, 0x22257561, 0xd446bcb2, 0x0fc641ab, 0xcc1a6e4c, 0x8dee3d16, 0x63da8a9c, + 0x7d312bc3, 0xbafefc35, 0x3e5ee30f, 0x3a00fae3, 0xbd92d1f0, 0xa543db66, 0x23fcd321, 0x0f4d68d2, 0xfc2ce9f8, + 0x4c8ac18d, 0xe3d316d2, 0xe5c6ec49, 0xaa695f17, 0xbfbdf9e9, 0x68bfab21, 0xb7a2c686, 0xfea7af73, 0x1883195b, + 0x09d63165, 0x8fc9bf1a, 0x5f8deaac, 0xd2aaa29c, 0xc76218d5, 0x6d9b866e, 0x23d78864, 0x090c3fdb, 0x8346f2c5, + 0x2f799d52, 0x432e6ce9, 0x6bb043cb, 0x498f1dee, 0xff1f6896, 0xeddf5a8b, 0x5e523af5, 0x578cff0a, 0x71a096ff, + 0x92f28213, 0x57e7d0c3, 0x25b78cd6, 0x1c2f7293, 0x90712d0f, 0x3f24fd1e, 0xd05e11b8, 0x6fdcf762, 0x1eaa7666, + 0x0ddd057d, 0xc5aafd86, 0x53634e10, 0xa20ae01e, 0x9e8bdcc2, 0x16e354b0, 0x25eab6ab, 0xeeea7050, 0x63c52292, + 0x4f3a3bc4, 0x3a3ac749, 0x6ebf9db3, 0x2ac27bcb, 0x666a01ab, 0x5802fd8b, 0x19b32449, 0x068b40e6, 0x6141148c, + 0x4aa89d93, 0x79ab1c15, 0x6b672a23, 0xb406bd9f, 0xf3cec976, 0x9dcf1e3a, 0x612c64b1, 0xa71ef5ba, 0x480bdf5a, + 0x7d774261, 0x543b3602, 0x5ff35161, 0x7e3ec540, 0x8da843b6, 0x25562ae8, 0xb4a0ff89, 0x2ad1f8db, 0x56c16909, + 0xa6d73466, 0x72fa752e, 0xfc366841, 0x5273b475, 0xab746730, 0x2884ea7a, 0xbc1e68d7, 0xa82b80f6, 0xf3b2a0e8, + 0xd09306a6, 0x1a318119, 0x546391f0, 0x83ac77e6, 0xd79df0df, 0xe26eac46, 0x8004d20f, 0x70f84d47, 0x1821774d, + 0xc9549771, 0xd787f58a, 0x1cc93238, 0x8aece08a, 0xa76f3b75, 0x64a968b2, 0x211fa431, 0x354fdfd9, 0x19f024c7, + 0xd2bc7ad2, 0x90047cac, 0xc4b2945e, 0xf2836676, 0x4a377117, 0x6593e0b7, 0xfa071656, 0x50bcdf04, 0xe5940056, + 0x5cb80f68, 0x0c7fbe5e, 0x26c1e7e2, 0x5b65d892, 0x1c8c5b8a, 0x1141f452, 0xf8182539, 0x162b1bf4, 0xdcd422de, + 0xd72f5d90, 0xe4670ca2, 0x7779a911, 0x4c986f2c, 0xf669cffe, 0xf738ee50, 0x3a70ef15, 0x461dc802, 0x3c407ea9, + 0xd4e9c5ca, 0x8d8ecac9, 0x584026c1, 0xdffcde66, 0x7ff11df6, 0x0c7e5f20, 0xd3145e01, 0xf442143d, 0x7a5dede6, + 0xe39fedb2, 0x13199777, 0x02367aea, 0xd20fbf2b, 0x9b1fd59f, 0xa51468be, 0x9767cfa9, 0x8cd7761c, 0x31a6c492, + 0x55815f40, 0x3df398e7, 0x0862b169, 0x5170a953, 0x46a8fdc3, 0xf05c02ed, 0x3fb9d6e0, 0xccf8d65e, 0xe4f0a814, + 0x4946d605, 0x16b0c385, 0xe758a9ec, 0x36f8b80e, 0xcda37310, 0xca01cbbe, 0x7326b272, 0xaca1c8b8, 0x7074cae8, + 0xece52a1b, 0xa80536b5, 0x7f40cc04, 0x99cfc4b1, 0x7980d542, 0x03b57586, 0x5a08422a, 0x534b5bb6, 0x8a3c944b, + 0x1e36bff4, 0x36efd30d, 0x794c465f, 0xd6af35aa, 0x9b2ade88, 0xdbc3c6be, 0x025aadad, 0x173e4556, 0x6892d151, + 0x9d5073b7, 0x0dcfb4b4, 0x007e54e0, 0x5f840197, 0xff86e03b, 0x960855e4, 0x48c15b9c, 0xa6a32f19, 0xc5bf27a7, + 0x999b0bcb, 0x6144dbfc, 0x500c9d36, 0x1cec8cab, 0xd307e044, 0x5be6b650, 0x1d1b7a14, 0x60c836ea, 0x064340c1, + 0x8bc46799, 0xdbfe7483, 0xe0d50909, 0xcc62f2ad, 0x7986cce9, 0x84349d39, 0xa5ed860c, 0x15e8345f, 0x2633761d, + 0x5be7733a, 0x49c63063, 0x7d5486be, 0x804ad742, 0x368826db, 0x127b6b7f, 0xf51ffe09, 0x43958ac6, 0x82e32fdd, + 0x28326403, 0xc8995b16, 0xb822d634, 0x522ca507, 0x17fcb904, 0x8147c863, 0x62de585c, 0x22898a49, 0x81215c38, + 0xf8610266, 0x2328d7df, 0x74fe5d4b, 0x1b82a618, 0xf48436f5, 0xad3efadb, 0x67d0849d, 0x1f057b61, 0x967cb1e6, + 0x5a5aa865, 0xa2298272, 0xdf895e32, 0xfdc80534, 0x44ddd3f6, 0xe899ea5d, 0x1d24dfab, 0xc170c6b0, 0xb2e47474, + 0xa382eda7, 0x18bc3139, 0x289c8743, 0x52b2d4a3, 0x35e42d79, 0xecd9fe94, 0x543c533d, 0xf6c0c562, 0x6ea2a28c, + 0xd75e5031, 0xfa7985af, 0x3399bae5, 0xc92ebc24, 0xe174f200, 0x21a246fb, 0xb69895d6, 0x29996efd, 0x4831938f, + 0x5fd4b2c0, 0xf7ff3740, 0x6167abc3, 0x2f901191, 0x726a4820, 0x65a1ec1e, 0x398c4554, 0x4246d202, 0x282ced03, + 0x9a1fe3c6, 0xb677b82b, 0x643837e0, 0xd28e544b, 0xde9c6e1d, 0x053bb19b, 0xb566e21c, 0x4a6a6396, 0xce5cacb6, + 0x53bfa4b5, 0x6596083e, 0x2a0c2650, 0xbdd9fa0a, 0x637fa844, 0x26e0e6f0, 0xa52d802f, 0xc2bf3e25, 0x7149db08, + 0x6ed1c99f, 0xa4baf79e, 0x63811b8b, 0xa6e2b885, 0x4afdb021, 0xf7d32a36, 0x6c7eb659, 0xfb6d5b2c, 0xec870e35, + 0x0b89072f, 0xb117382f, 0xd9c1c0a5, 0xc3949c1e, 0x67f0fbb9, 0x75e016b4, 0xe50cdd02, 0x2c9ccccb, 0x7c70752a, + 0xb440ce9c, 0x5c15b4e0, 0x0fc243f4, 0x710c056b, 0x4ec8553e, 0x87c511b8, 0x286f7aa0, 0xa62aeb41, 0x33475718, + 0x240467df, 0x9751ca96, 0x41b869ac, 0x2e8bdcbc, 0x0765cf4c, 0x8f4941c2, 0x42d37365, 0x905482d8, 0x5808eb9c, + 0xf03870ac, 0x1c82b526, 0xea1ef0de, 0x5ee9cc48, 0xd3b07e3d, 0xfae33c17, 0xa22eaad9, 0xef7ec4ad, 0x33efcd0e, + 0xa2f4e708, 0xe6b43ffe, 0x6beac60d, 0x3209ee9f, 0x21693c3b, 0x21f9a720, 0xb7e279b8, 0x51b69268, 0x1cf35379, + 0xd32a052c, 0xbba6ba01, 0x6ac1f4b2, 0xa61f0f6f, 0x5bff78ce, 0x8bf26f50, 0x3e62d29c, 0x19dfaef9, 0x60aef221, + 0x39f15487, 0x369b32a9, 0x6d45cf75, 0x57170fed, 0x5283d4f7, 0x178a890f, 0x40580b61, 0x5e5d6d3d, 0xaf9fefa6, + 0x2f02fd40, 0x675f5d4d, 0x5aa11433, 0x95fafafb, 0x5d73cee4, 0x6af41c0c, 0xb89a1f37, 0xff434e0a, 0x183a4901, + 0xaa92cafa, 0x6a846b8e, 0x7d93ff89, 0x579cacd1, 0x13dfba6e, 0x5f441fb7, 0xdc62b47b, 0xbc63bb2f, 0xa5ae9cb2, + 0xfe220a9d, 0x2369f367, 0xbf0464fa, 0x15252fd9, 0x433616a6, 0x30b33d3b, 0x4f9c82ee, 0x1ae2eb9f, 0x1f8ddf72, + 0xfc73bb26, 0xc22d2209, 0x667e8e05, 0xe06d7671, 0xac58647c, 0xf77c7912, 0x6dde1b5b, 0x30812da1, 0xe3406289, + 0x511c77d4, 0x31a008d4, 0xe84d036a, 0x21493c15, 0x37d1f048, 0x3bcd8a93, 0xd6c6e6b7, 0x63002d2b, 0x025d4a19, + 0xa2abdfd5, 0xf0d27bf9, 0x2007a914, 0xc139d81c, 0xd998d591, 0x08773037, 0x0ca3ff0e, 0x3519b72e, 0x53d6cba8, + 0xb781a628, 0x5580a4ae, 0xc1226401, 0x3dcdd36c, 0xeca76133, 0xbb2b48e2, 0xf06399b2, 0x635bdc80, 0xd68c8d93, + 0x74d60825, 0x1dad6544, 0xf43d58b0, 0xc1beda6a, 0x65a87234, 0xd71ee450, 0xe5d709d8, 0x58602595, 0x6ee90422, + 0x1ebaae2a, 0x100a14b5, 0xa424c10f, 0x9cfd51c0, 0x0f87835e, 0x3c09e54f, 0x6271d1a9, 0x291e9ec8, 0xe6399311, + 0x4a09198c, 0xd63a6360, 0xe8fb82a9, 0x75f7a769, 0xa17b4f78, 0x6390045f, 0x933724ae, 0x790fde5c, 0x03d27873, + 0x73061482, 0x512f289d, 0x6643d5cf, 0xc4baa7f9, 0xc593d257, 0xcc1b3148, 0xcea92419, 0xd75de472, 0x7f096ea9, + 0x279154cc, 0x7d8ae218, 0xe04b59d7, 0x78dc1da2, 0xc3b6501c, 0x6e47503b, 0xed8d047b, 0xd8469369, 0xa36b118c, + 0x9f209e16, 0xe8b78d71, 0x7a802b1c, 0x0439c910, 0xcba62cfb, 0x0343b08e, 0xdc67d2bd, 0x263af3c9, 0x4fdea64c, + 0x8150697b, 0x7c427807, 0x4324d02b, 0x9d406f2b, 0xcff1aeaa, 0x74268b68, 0x336c40f5, 0xbf7de9ce, 0xcaa4c0ba, + 0x975e869c, 0x5b654f5e, 0x930e33e5, 0x681fd83b, 0x1646227e, 0x502069a9, 0xb1a2153b, 0x5b5617d3, 0xccbc0782, + 0x8898f8ff, 0x3f0f783d, 0x4a543527, 0x44ac5939, 0xd7ddc344, 0x99d2ed42, 0xe185043f, 0xba50223f, 0xb3bf37e3, + 0x5335de9e, 0x4677a42e, 0x1c05a1ac, 0x2db1fa8b, 0x2b337a21, 0x082c15bc, 0x5e30cd5f, 0x36024b40, 0x1b496b65, + 0x985bc813, 0x41192a6b, 0x3ec488d6, 0xdc02a1aa, 0x67ee108f, 0x4dc011d7, 0x2cc68ca9, 0xce7c0013, 0x6f36aa77, + 0xf4405fbb, 0x7a5aba4e, 0x0b735bab, 0xd6254b7c, 0xa94f53bc, 0xd4687c5a, 0x5c774a86, 0xfb6198fa, 0xdc1f4083, + 0x2b70f10d, 0x43c04933, 0x91b5c909, 0xe8448dfc, 0x901b7f9c, 0xa2b5f4d0, 0xabaf3138, 0x9444f5f0, 0xcb45d07a, + 0x25152809, 0xa61e72c3, 0x8faf40b6, 0x351cc3c9, 0x4a38c5fa, 0xdc2f3082, 0xb99eee2b, 0xdecee423, 0xf28e370d, + 0x9d97408a, 0x28e5f2db, 0x4427a273, 0xd9ee35cc, 0x92efe885, 0x1a296b7e, 0x70613a3e, 0x099e597b, 0xba702925, + 0xc1cade67, 0x6e32ff46, 0xeedc5cd7, 0x3b8b16b0, 0xc4657d14, 0x6a7b64b7, 0xe3a31b9a, 0xb7ef4304, 0xcf41b367, + 0xc969d5bf, 0x5cad047b, 0x6ea88ea3, 0x35d496bb, 0x37d631d3, 0x35d5b398, 0x265c8547, 0xea569408, 0x50c5c00b, + 0x81cbb444, 0x64ee7096, 0x74121397, 0x044efe06, 0x6e6a29af, 0x829a6ecf, 0x494e9e32, 0xf06e3cba, 0xa49e3978, + 0xaf5b9bab, 0x890a4d34, 0xd00b72fc, 0xa7643b70, 0xa76e3fcb, 0x473e8c59, 0x38078e66, 0x4903e99b, 0x01855e2f, + 0xd74a85fe, 0x6badb206, 0xb66a3b54, 0xca84d6c5, 0xb958026f, 0xa55dcd2d, 0x37d3d443, 0xabd2dd5d, 0xb2f7f0c5, + 0xe1cf1838, 0xacf5dd61, 0x08e3e529, 0xd7221e21, 0x271d6948, 0x00b78d3e, 0xef916199, 0xaf548c3c, 0x6d1af9f0, + 0xe382b5fd, 0x7cc7ee32, 0x23a0e1fc, 0x78ecdc28, 0x6a26a19f, 0xa12f8d91, 0x7fa8cacb, 0xabd3d8af, 0xbda30405, + 0x143c77f1, 0x8359adf1, 0x139200fc, 0xcec18ab8, 0x1f231ee5, 0xa0e5ad8c, 0xf64b290e, 0xfe008149, 0x4221b586, + 0xd4d022d5, 0x2900011d, 0x535be448, 0x1926c227, 0xf2cf10b0, 0x47139b14, 0x0480e0c4, 0xdf2fe723, 0x1c7d80ce, + 0x1d2b7203, 0xef82da1d, 0x26a9431b, 0xc79e2b00, 0x6d3fa4f3, 0x7ac47629, 0x65a913c7, 0x520bf0cf, 0xc848797a, + 0xdfeff831, 0xf1c98142, 0xbf36c2ff, 0xaf8f9f9e, 0xee4aa687, 0x3b3ffe52, 0x5311601c, 0x5f2ca1aa, 0x6d06585d, + 0xfc9b45c4, 0xc93dd94a, 0xd019defe, 0x7c801a10, 0xef369268, 0x0f3a39e3, 0xe155025c, 0xcc2f6a63, 0x467cecfd, + 0x93186223, 0x4392b8ab, 0x74a0fbac, 0x225ef88d, 0x0d141746, 0x61fb92c0, 0xc5c1e5a4, 0x00203e72, 0xf30907a0, + 0xf1127d7c, 0x9b371a74, 0x77e1855e, 0xa7c8776b, 0xdc28d009, 0xbe885d93, 0x7d9c313d, 0x406f42b3, 0x4d63c43b, + 0xa94e4851, 0x4eeb3597, 0xe5c3dbd1, 0xe075165e, 0xb29f6c06, 0xb3f64b4b, 0xcf055ca4, 0x1a307950, 0xc542b5cc, + 0x8a61913c, 0xd82122b7, 0x6ebfe91a, 0x9a333222, 0x94463966, 0x938ce4b7, 0xbb128bb0, 0xe70367a3, 0xe4c08b77, + 0x6e02a710, 0x18170fe6, 0xe9f7460a, 0xf1a205a4, 0x91bd94f8, 0x49db6631, 0x60a84bb1, 0x2b2d9234, 0xb7b903fb, + 0xc3bd18ee, 0x48e3b4eb, 0x6e998736, 0x613166b3, 0x7b478fe9, 0xc534588c, 0xbc90f133, 0xac80fabf, 0xcd4e9c40, + 0x37ff8469, 0x2f29cb7b, 0xcd0a87ab, 0x3d9ec4c0, 0x17669ea6, 0xf0da5228, 0x1e00fbad, 0x2e5ddfd4, 0xe034a88b, + 0xa67a8ec7, 0x5b8c7a91, 0x9eba6520, 0xf3ef3ee2, 0x844d5eef, 0xd94a0152, 0x81677ae8, 0xa3ea1f85, 0x71d7645a, + 0x6462f6dc, 0xd88a10e2, 0xfee178dd, 0x66453bad, 0x891a07ce, 0x97cda1b2, 0xbbd887b4, 0x9d18d5e0, 0x9a2674fc, + 0x718b537a, 0x2eb3ac96, 0x2d9129e1, 0x7d1f9727, 0xcead56a7, 0xf586c3ac, 0x13f653a8, 0x0c7a014a, 0x324bf256, + 0x98c343ec, 0x41406249, 0x506d291b, 0x1b8fd32c, 0xa1f1caa2, 0x48cb02ea, 0xddb07954, 0xdd4f602b, 0x664a2478, + 0x053d672c, 0x2ab7b68e, 0xf7912923, 0xe05147e7, 0x4cc0434e, 0xfb7e9ee2, 0x12fb0aa3, 0x2f2768d3, 0x67345641, + 0x0b299ea4, 0xc1e478f4, 0xff15dbf0, 0x43472411, 0xd70de8c6, 0x4dede6a8, 0x53f2ffbe, 0xf1ef9cac, 0x4e234396, + 0x8f8f046f, 0x01610a6c, 0xeb08e820, 0xfdfcd206, 0x5d993cd8, 0xf9303be9, 0x01cc1948, 0x2dc5b442, 0x79bf9105, + 0x152c7651, 0x2bf6f9ae, 0xd2f1d690, 0x12942e61, 0xa31445db, 0x8cbc10ef, 0xd53fb0c6, 0x54231c86, 0xa2cfef65, + 0x89f6c8a5, 0xc384796d, 0x8556b3e9, 0x0e315146, 0x49749ed7, 0x338c16b0, 0xb538c27f, 0xcfb742b9, 0x787dc7d8, + 0x864803f6, 0x7e189c54, 0x4bf42d77, 0x9e4711ab, 0x88f70bd2, 0x9ef93df2, 0x6b3c49db, 0x322cdfd4, 0x43bc6f72, + 0x23b95aae, 0x5bf326f3, 0x4151f903, 0xc817bb7e, 0xe4fa1b8e, 0x5156fe25, 0x414edfce, 0xefb19b1b, 0x4f375681, + 0x733ba528, 0xd841ce79, 0xbab3ad70, 0x894ac491, 0xbfe089b0, 0x69758db1, 0x6b3bb5d8, 0x5100d2bf, 0x7eb76aaf, + 0x5a92e40e, 0x0f562a2f, 0x55dc1f2a, 0xf105658f, 0x959bd54e, 0x0fecd8b8, 0x0b312df8, 0x4697423f, 0x96192503, + 0x6e4ba34f, 0xa2823a4f, 0x11335a25, 0x83e6f69c, 0x44911506, 0x3a1441a0, 0x9a15fa73, 0xdecefc50, 0xbc80a241, + 0x57a0230d, 0x433edc95, 0x345f18b4, 0x42edd4e6, 0xcd36acdf, 0x393f9b29, 0x1ebcf519, 0xcd8730ca, 0xd5e776ae, + 0x0ea9b8aa, 0xb7c2aeb1, 0xb67fb573, 0xa201cad5, 0xb2b0abd1, 0xe3f61892, 0xf12f2c0f, 0x04c0ebf5, 0x94c87bfe, + 0x92cfd559, 0x06bcbcf7, 0x7c7bba0e, 0x2332f2fb, 0xca767a5a, 0x7839cb34, 0x05f6a057, 0x0753b98b, 0xd2bd33f7, + 0xaf4d9759, 0x20a4f962, 0xdfecb3fb, 0x1b9cd04c, 0x34037a6a, 0x7ca4be1b, 0x3893c42c, 0x580cd15d, 0x9e7f5cff, + 0x5d862bb7, 0x11819e49, 0xf41c7bf7, 0x0515e3c6, 0x84baabb7, 0x56d1a429, 0xc2add6c2, 0xc04e4a66, 0x95c5c44b, + 0x290427ca, 0x66b5d7c2, 0x2570c2f6, 0xed6d1db2, 0x510aeca2, 0x8a27a376, 0x7a6cad61, 0xb67f406c, 0x948e9dae, + 0xb22c7ffd, 0x010b1cc7, 0xc38f0523, 0xb3e30ae7, 0x311e4a76, 0x5144ac67, 0xa35130fd, 0x12721a1a, 0x6256159d, + 0x0e09c769, 0x1e217f5b, 0xa535af02, 0x53719f2b, 0x3ad1bf41, 0x2aad8a59, 0x1cf22c42, 0x92e19b07, 0x7afdff9d, + 0xd584ab24, 0xef6bd9ba, 0x642d1841, 0x5824f97f, 0x61e690ed, 0x84d5b855, 0xe4d84846, 0xfd2928c2, 0xf7d7eec0, + 0x0af2ebbb, 0xee4b55ca, 0xf2e856dd, 0x1476e046, 0x797e29ed, 0x0331a914, 0x6af05dda, 0xd623f4b6, 0x4ef4a547, + 0x9bb046e7, 0xb4fc14ac, 0xfba13ece, 0xbd63d84a, 0x133663e8, 0xd510c560, 0x5681d1e4, 0xc8c286bd, 0xf2ab2ed6, + 0x9809ad3b, 0xd5200ea3, 0xb17d2a18, 0xc8e9eeeb, 0x09e6b9ff, 0x19dbb263, 0x407bb151, 0xd8668057, 0x411edc01, + 0xa0370b7d, 0x46b38c6a, 0x932dc316, 0xe299bb21, 0x4123a141, 0x2b087ad2, 0x693f173d, 0xc1992cb6, 0x11eff143, + 0x0420a685, 0xa78bb24f, 0xeb5ccf34, 0x0d77d397, 0xb5904011, 0x63599d89, 0xc7a08d64, 0xceec8b36, 0xd1ccac4a, + 0x415b48cb, 0x0e36fa71, 0x8999ee5d, 0x36a75b3c, 0x93846e90, 0xb37659ac, 0xe1514dbc, 0xcbefabef, 0x52d740c9, + 0xd30c0f30, 0xbb68789e, 0xbcb44940, 0xf0e648ee, 0xd6bb5cd4, 0x033f36d5, 0xabfc0511, 0x8e848ae3, 0x7d38e8ab, + 0x903974a9, 0xc2aa758c, 0x463025d6, 0x3829ab34, 0x63c75908, 0xc2711f00, 0x2c97eb33, 0xd63ef30b, 0xff2f7d52, + 0xffacccf9, 0x835ed08b, 0x1ec1155e, 0xcd69ab8b, 0x40f0eece, 0xd0d4fbf4, 0xd7c56a1d, 0x9dddff3e, 0xbba5c033, + 0xbada48b3, 0x1c35f9c4, 0x3aa6df9d, 0xd718bfa2, 0x82987680, 0x7413f4ae, 0x1343c163, 0xb6cffed3, 0xe5499648, + 0x6882482f, 0x4f3b7465, 0x2a91976e, 0x74ff7b38, 0xe23943d0, 0xf4377d29, 0xc0ef7425, 0x93f28b5e, 0xeaa05549, + 0xe62a50a1, 0xdb802193, 0x8700866b, 0x8986a81a, 0x717294f0, 0xfe631a07, 0x863760c6, 0xad8691f2, 0xaaea31a9, + 0x081fde0b, 0xa684f695, 0x392fde87, 0x4c71069e, 0x815de271, 0x5e2d3e71, 0xdedd1f21, 0xe287f61f, 0xff67769b, + 0x3fc6ba67, 0xfaff9b1c, 0x378ff163, 0xa35e4175, 0x2316a383, 0x586e41c0, 0xe29db65b, 0x592f831f, 0x188ce642, + 0x9a78083c, 0xced4da27, 0x32eaec21, 0x40412b11, 0x2cbd805a, 0xd148877b, 0x8a253814, 0x6bade93b, 0xe17b1405, + 0xd4f8d0d0, 0x99d54135, 0x3131c956, 0xe41c76cf, 0x087a3bd8, 0x78d5e539, 0x8954b9eb, 0x19618330, 0xf61be3d3, + 0x30129207, 0xa4b16ff6, 0x2ef0f63f, 0x9a3911ef, 0x72b80ede, 0x74fc71b5, 0x953a5d05, 0xcf237642, 0xa5db6cb2, + 0x0cf63d3d, 0xc7a8ba53, 0x13b1d5ff, 0x37a60c2c, 0xecb81a3d, 0xea903d5c, 0xd513ef7d, 0xea12eca6, 0xd982ac17, + 0x3542c76d, 0xfd93a21b, 0xb9f5b7a0, 0xc037ea35, 0xdbdd07d0, 0xf2d71f19, 0xa6f07d9b, 0x91a4b700, 0xc868b564, + 0x3bc599b2, 0xb5d56cf0, 0xa84de55d, 0x86e13f13, 0x5b13f09a, 0x5ffffdb6, 0xb15f405f, 0x06c206be, 0x20abac78, + 0x8310dfe1, 0xb5694dca, 0x0a5098d5, 0xf34db9ae, 0x6072d05b, 0x0d50c9c4, 0x854f0274, 0xe8d47648, 0xb53870b7, + 0xe7d706f5, 0x5a4e8931, 0xbd491309, 0xfd611608, 0xad82c055, 0xaecca462, 0x2dedb2cb, 0xe6d4a0e9, 0xb032d85b, + 0x6a96d877, 0xd02b6514, 0xf0347b0c, 0xb6f29575, 0x10f8d1a9, 0xbce82044, 0x88174b26, 0xd5a009b1, 0x04428eda, + 0x2363d4b1, 0xa5965b67, 0xe7e23fda, 0xfef14885, 0xcd955671, 0x8124d871, 0xadd217da, 0x48f5db47, 0x8e6a0ca0, + 0x2c6d6322, 0x24e553af, 0x07f238a6, 0xfe3ac9c7, 0xfafd3738, 0x65844977, 0x2c5bb538, 0x2479fc9d, 0x917e1186, + 0xf6a8095d, 0xf2041677, 0xfa932df2, 0x7c1cc60a, 0x5fde3343, 0x78ac8e06, 0xf8415917, 0x7bb4f20b, 0x2e217e6f, + 0xfea8a676, 0x8ae33547, 0x551a5016, 0x73375a01, 0xb68531f0, 0xe1e63ddb, 0xe2f3571d, 0x205f3651, 0x0c25f4b5, + 0x5f3bbc98, 0xd719612f, 0xa2b3846b, 0xc9ddfb65, 0x13769859, 0xd047f330, 0xd0013e6f, 0x5ba4408e, 0xdff50177, + 0xd43bfd60, 0x5c843a25, 0x7f9e433e, 0xb0e097c0, 0x96d97e96, 0x9abc0f11, 0x18330bf4, 0x6b56391c, 0xee56fa35, + 0x4d67e59a, 0x309814ac, 0x81c82557, 0xa40fadbf, 0xcd8e771b, 0x1c466a8c, 0x3ebd7827, 0x613e6e35, 0x72675c02, + 0x40d36730, 0x64bd1e00, 0x5c2f3159, 0x211ae819, 0xd1cd3668, 0xf05862da, 0x773a5724, 0x49c476a0, 0xbc907189, + 0x3e9fecfe, 0x4b3464e7, 0xab05ca01, 0x6a0ffd7b, 0x9d855194, 0xc873d4db, 0x01e1881e, 0x9a828db4, 0x8fe195a7, + 0x71d63c30, 0x00eb3624, 0xd2f733e9, 0x8f615735, 0x3714de7b, 0x917eb8e7, 0x17478151, 0x002bc761, 0xbccb510f, + 0x3a1d8dba, 0x0bd8a7af, 0xcca7334b, 0x2d8d4859, 0x9af03142, 0xb4102eed, 0x86d20766, 0x54924cf0, 0xccc7e9d6, + 0x4619f48a, 0x76c9a070, 0x0ac0ccd9, 0x68219377, 0xab9f54df, 0x90b8db23, 0xb9730471, 0xdc1fd9f7, 0x564439a1, + 0x6347a739, 0x4695cd99, 0x7b768ed3, 0x23f7c85a, 0xa77aca7b, 0x2d2b07f8, 0x8e02cf73, 0xf406427b, 0x44785aea, + 0x1e2e3c7f, 0x26ffc828, 0xe4f16454, 0x42b07ae7, 0xf67b6efb, 0xd9bb7386, 0xb5746cfc, 0x942815fd, 0x2c1adeae, + 0x914cbd89, 0x1ad515d9, 0x451cc8f2, 0x9ea455d5, 0xf322143a, 0x1b9dea21, 0xa1d5aa0b, 0x38220f03, 0x550db9c2, + 0xad99e7f4, 0x067a01e3, 0x2bdb733d, 0x18a04e93, 0x9d65e8c8, 0xb3221ed4, 0xa849bb78, 0x27ae6aa5, 0x1c308213, + 0x1ef68f73, 0xb636240f, 0xd98eb6c6, 0xad1c57da, 0xf85e395b, 0x2b2582e6, 0x895a8440, 0x2f40f4ac, 0x54c4248f, + 0x60b7143d, 0xd73d9d5f, 0x434b83b7, 0x07ad02e2, 0x77878890, 0xa31558cd, 0x19202085, 0xc1d92bc7, 0x66c947a3, + 0xd54da9ce, 0x38382261, 0xd2a6c023, 0x074d4bcc, 0xbfa42213, 0x73023f41, 0x0e521e5b, 0x008ed21f, 0xa0a87217, + 0x97aab493, 0x73f37277, 0x9b4b5ce7, 0x0fa26c3c, 0x6a7748c6, 0x1861a29b, 0xad15141b, 0x33dd1899, 0x9f3c2512, + 0x025f14dd, 0x6d1b8320, 0x4d362d73, 0x1c67e165, 0xa6ce6185, 0x3e1eb6af, 0xc193dce3, 0x9a916924, 0xfdc611ca, + 0x29855337, 0xc5da9e74, 0x96b830d9, 0xc3ee10ba, 0x2590f20f, 0xc1a7fd51, 0x94ec244c, 0x420ecd58, 0x5b415052, + 0xdf0d3f35, 0x4281a6a8, 0x8469ba08, 0xebcb504a, 0x5c4d0d88, 0x913cfa33, 0xfe6849a7, 0x949dc60c, 0xef3095df, + 0x27f40054, 0x9b71183c, 0xfeed91af, 0xf348dd2f, 0x7aa86c07, 0xd63aafc5, 0xeda5d49a, 0x43c76350, 0x81803d25, + 0xbcb12a7c, 0x6ce8549a, 0xdf28b50e, 0x6e62fc12, 0xf2ff0287, 0x9022af06, 0xd9e79d40, 0xa0848d85, 0x5786add6, + 0xa84f961f, 0x04c3e0bd, 0x25413ef9, 0x80ef0718, 0x134c1ae7, 0x59fa3c2a, 0xdfe05870, 0xeef154c6, 0x4b8cf6c4, + 0x145711da, 0xe176f846, 0xc75ae71d, 0x8faa5384, 0xb6daae6d, 0x1ee3de36, 0xd738c001, 0x575661d4, 0x38033921, + 0x6e39b430, 0x7df37a12, 0x673f5899, 0xeb183439, 0x945d49dd, 0xd625382f, 0x036f3a92, 0x99cff03c, 0x00ad6f05, + 0x7f978c5e, 0x6de09dc0, 0xa5f774cc, 0x66401aca, 0x6700e8b1, 0xc4c7665c, 0x606348a9, 0xdbbb147c, 0x8b0a100d, + 0xe5329c56, 0x4f15bde7, 0xb3aaf10c, 0x4dccf2e2, 0xb82b4391, 0x1e3fe17a, 0xa38c6bfd, 0xd3f9901b, 0x67e4eed6, + 0x54aa81d3, 0x12ca05db, 0xc5b2c8cd, 0x66971804, 0x1dd12404, 0xf44a0496, 0xc5a07adf, 0xfefd5dde, 0x54b2282e, + 0xdeaf0a2b, 0x4618856c, 0x66e765cd, 0xf662b11e, 0xc4f38021, 0x8c3a67d2, 0x6a70719f, 0xe04ceb92, 0x411fa36c, + 0x57240aba, 0xded2e3a4, 0xfee5387e, 0xd3be6f89, 0x8e2af3a0, 0x1394fb4a, 0xad87877a, 0x0c6d0f8f, 0xf557e47a, + 0x9535da92, 0x36a51115, 0x0643d157, 0x1a426da0, 0xdaf862cc, 0x20e924c3, 0x3a4887e7, 0x5c552d4c, 0x9dc4b80b, + 0x00033e6a, 0xe656179d, 0xcecaccb7, 0xc4492ad0, 0xd038c756, 0xb1d02b09, 0x3041548a, 0x929625e8, 0x55f8caca, + 0xfc4ed341, 0x99f0f380, 0x5070035f, 0x5f1ff4b5, 0xa0ddd3c8, 0x8058d715, 0x412bd6b2, 0xc9499bab, 0xd7e67fde, + 0x102e17f5, 0x3b5ca0ed, 0x5d45d0f0, 0x212e600b, 0x05c844c6, 0xee149ddc, 0xc8877e0f, 0x1d1f8241, 0x7d39e955, + 0x625d7b3c, 0x53d23bff, 0x5643cd65, 0xbc598316, 0xba8f828f, 0x2799e2e7, 0x9ce6ab4e, 0x8f917789, 0xf0c61dc6, + 0x8f85259d, 0x70ea657b, 0x154ec2e3, 0x5167055e, 0xb576b8c2, 0x0498b207, 0xfcc47a59, 0x3dd0de73, 0x99647141, + 0xdb9f44f7, 0xc0495b22, 0x1e0b765c, 0x60bbb0a9, 0xd39facc3, 0x220f5da9, 0xab024e38, 0x4b8cd216, 0x40510a4c, + 0x623b1343, 0x1332d579, 0xa84507a1, 0x7734213b, 0x0ee50269, 0x9728b46b, 0xb1887d1d, 0x245ab228, 0xd63fbb8e, + 0x8122077f, 0x4d187c8b, 0xb601b76b, 0x6cfec75d, 0x901aba24, 0x383c240f, 0x387f2899, 0x25ac4f5f, 0x3a0e807d, + 0x013d70d1, 0x9153771e, 0xabdfc609, 0x36a9d265, 0x40dd1d3e, 0xb6f6625c, 0xfc932abf, 0x557d1f79, 0xd2167f95, + 0xe9debe18, 0xd933cc03, 0x8ff6ecbb, 0xbbc47bd8, 0x2ad7f2f9, 0xcc5995e8, 0x878d182e, 0xcedb24a5, 0x7bd71832, + 0x8716c1d8, 0x00218a4f, 0xa2958537, 0x59c7e471, 0xb4985e2a, 0xed29694f, 0xdb16546f, 0x59e7c3ae, 0xc91d6509, + 0x83e4c2ff, 0x551fd93c, 0x15e4e3aa, 0x65d7e4cf, 0x8ea23e02, 0x6f37afb6, 0x217913b4, 0x882a87be, 0xcf5e3c1b, + 0xdae51d5f, 0xf405c4fb, 0x027aed24, 0xfa23cbc3, 0x67bc8b3e, 0xd5b43e96, 0xabf38c08, 0x6d2ebc81, 0xeecc61d3, + 0xc65edf9c, 0xf750ce85, 0xaee941ae, 0x1be065de, 0x9450a316, 0x0bf47b7f, 0xcc538447, 0xca72e34d, 0x0d4f5122, + 0xd072daa8, 0x95df029b, 0x91b29773, 0x5d87d267, 0x9d966c74, 0x0d88e70c, 0x70556ae1, 0xd1e3ec4f, 0xd044ad57, + 0x0d2a2c03, 0x19dfd2de, 0x4b4f2f6b, 0x38cd48f2, 0xb559a093, 0xf10d9c31, 0xe3fbd1af, 0x29fa07d6, 0x431f417c, + 0x47a7dc1b, 0x216750b6, 0x699eee78, 0x3465b9aa, 0x60a26007, 0x07dad5f1, 0x40cdb64b, 0xd72c1aeb, 0x793505aa, + 0x7ca88a65, 0xccf59946, 0x87b51abe, 0x3c911d62, 0x670ccda8, 0x57447c99, 0xda566aaf, 0xbb6f911e, 0x5885a539, + 0x5dfea92e, 0xb2b397ed, 0xbd3ccc5f, 0x9fe29a3f, 0xd6d083b7, 0x7276fd5f, 0xbf9e8069, 0x51598a19, 0xf696ebb6, + 0xec033691, 0x05ccff2d, 0xed58a9b1, 0x75e5441d, 0x270af704, 0xfd49986b, 0xaa18eda1, 0x1e8f57fc, 0x4b1f10df, + 0x8d278e75, 0xa48bd841, 0x775de1a7, 0xf2f821d7, 0x1adc92e1, 0xd384787c, 0xa7a51d64, 0xccb7ceed, 0x24b64838, + 0xe4703c9c, 0x30296b01, 0x16652299, 0x2fc76e73, 0xbf4e3c92, 0xeb8a233e, 0x039b24f4, 0x1210e114, 0xef78436c, + 0x16385609, 0x7443512e, 0x3b97277c, 0xef9216cd, 0xabadf4cc, 0xa53f7b32, 0x414a2a6a, 0xd9b2b285, 0x6665479a, + 0x935d4294, 0x4960c0ee, 0xa10a8663, 0x02e387d6, 0xffacd74b, 0x92e3f3ef, 0x3278f21f, 0x841952c9, 0x13a664b1, + 0x55cb9980, 0xbf2aa5c2, 0x82ef3a35, 0x4e908c04, 0x034ffe8d, 0xd2935eef, 0x2c768087, 0x1834d504, 0xb7c23029, + 0x6614ca94, 0x0098ad74, 0x3d121993, 0x50db609f, 0x28d832ab, 0xa6e01ab1, 0xe28ce775, 0x5713955b, 0x110e1c53, + 0x08c41317, 0x1479011d, 0x4379e0b5, 0x3c947395, 0xbbae2a7e, 0xca8fd000, 0xd1c83a18, 0xfcbd4826, 0x0cb2a118, + 0x31040009, 0xe58a2911, 0x66a79b59, 0xfdd3020b, 0x47a566c1, 0x913e0a2e, 0xdebac8e8, 0x2f7edd1d, 0x803f86dd, + 0x89c043db, 0xf1c2b7ed, 0xe22d81ba, 0xec122038, 0xa44c385c, 0x8c1b657c, 0x16cc0aad, 0x6ff42234, 0x333ac1ca, + 0xe0a652c4, 0xd62d9b70, 0xcda97f86, 0xe2959f7c, 0xd52fe6ca, 0x1a579ec9, 0xd101cea7, 0xc7815439, 0x135d461e, + 0x91dd99cc, 0xdd86bfb0, 0x9009f6b4, 0x8d65c91d, 0x52a2e2ec, 0x060d77c0, 0x433769eb, 0xd91ec99f, 0x23a69694, + 0x8cf7c226, 0x71cd18f3, 0x4e947ac3, 0xc616528c, 0x9d7f1548, 0x1ed8a3e5, 0x0b3163fb, 0x970e5c53, 0x1de0863f, + 0x87d3f182, 0xf9e6b92b, 0x3da847fb, 0x8cd894c1, 0x002fabe2, 0x472eaddc, 0x462c613a, 0x6a14a2c3, 0x82f3dbe3, + 0x7176ffca, 0x3920c874, 0x13d5b9d5, 0xd9c6f21c, 0x2d92ae51, 0x50cda9a2, 0x5d42a396, 0xeb00358d, 0x6374d314, + 0xa61fb8d6, 0xce74f34a, 0x3fbd8e8d, 0x8664ad26, 0xe3435471, 0xc06c1bf8, 0x4ed568a8, 0x80e2a528, 0x2c17bd30, + 0x3c66d669, 0x4af7169d, 0x2a064e6e, 0xac27904a, 0x1ffbb5af, 0x05a601fe, 0xcdb48c9e, 0xa7c98585, 0x39e68884, + 0x4aa90110, 0xc58552e7, 0x9c7005e0, 0xaab141b4, 0x923bc7dc, 0xe96aa487, 0x3244be15, 0x710d8a9d, 0x9fdc4110, + 0xd2899fbd, 0xcba9ee62, 0x3a7b7240, 0x9b708db6, 0x3bfc6c0f, 0x354fff31, 0x8c914cd2, 0xaff8b11e, 0x30f016e0, + 0x257bc257, 0xea6b0ec6, 0xc983d058, 0x2883114d, 0x9bdaa38a, 0xeaa99913, 0x406aec8a, 0x6fd3f67d, 0xa6f88082, + 0x2ea3ccfe, 0x093d1e22, 0x48d36119, 0xfcb5d7ed, 0x42c2908a, 0xed49f078, 0x1b6359d0, 0x612fde7b, 0xf342c92c, + 0x85cecbb7, 0x94cd1f08, 0xcdfbb2ac, 0xf9c3f8ae, 0x1eb48000, 0x4b0dd149, 0x91b2bb65, 0xd303eb83, 0x294bb043, + 0x347209f6, 0x27e87e5e, 0x9b6cadad, 0x7393dfd0, 0x11f9d332, 0x2aa8a1de, 0x66902f1c, 0xd3ca281f, 0x026d6a82, + 0x7a5f4827, 0xb6f1b88e, 0x101438d6, 0xb596defc, 0xe78b6a75, 0x5d1b0215, 0x82ad206a, 0xcd4d1155, 0xf543ecd1, + 0xffb3d2cc, 0x3e7cb933, 0x613152b6, 0x272adbbc, 0xfb04b21d, 0xf7c6564b, 0x95186c80, 0x12da81c1, 0x80265d69, + 0xe7a00153, 0xc88c8be8, 0xb77d9fe7, 0x2f73ba16, 0x0d21b608, 0x4230f89c, 0x8fcc3363, 0x223c6db6, 0x2db46b71, + 0xa2fb438f, 0x0e235e7c, 0x1920f63b, 0xc052a8ba, 0x608aaf96, 0x4a2570e7, 0xd823d296, 0xdf78bad4, 0x74bb3630, + 0xde4db338, 0x384ee55f, 0x49d75187, 0x24933415, 0x456104b3, 0x9cdbcb90, 0x855e916f, 0xd160657a, 0x3dde906e, + 0x0ce44b7b, 0x1d13adb8, 0x00c5896a, 0xb7679c97, 0xd32158f2, 0xf65f6d2e, 0x9fddaafc, 0xc138e34f, 0x8216ab5f, + 0x427cc475, 0x65f2126f, 0x0c879952, 0xc07a6fa5, 0x6c26ae1c, 0xaa347414, 0x52f0ce69, 0x139839ef, 0x4ee5a661, + 0xfd49125a, 0xe60019b3, 0x3e529800, 0x6a859245, 0xf52653a2, 0xb252adc5, 0x25de656f, 0x7b00ab06, 0x782b2579, + 0xcad5455c, 0xce75772c, 0x503163b8, 0x22f41840, 0x75690960, 0x33b69fa3, 0x5af6d995, 0x4ee41770, 0xd1175829, + 0xab3802d5, 0x94ab42d9, 0xe125f07f, 0x2f6a24eb, 0xf77c5877, 0x58f100e7, 0xc91a599a, 0x94f19e00, 0xe6f6b6b8, + 0x9d1da3d6, 0xdceb53cf, 0xffc1af0d, 0x02c8e39c, 0xc962acd0, 0xa0f31267, 0x8af524c7, 0xfeaec9c0, 0xdd9d060b, + 0xeb57fd68, 0xf86ea11f, 0x52a32221, 0x694c217a, 0xe684d100, 0x913504fd, 0x23c16a5b, 0xc6fc1611, 0x4dbcc5d0, + 0x130c811c, 0x06acf2ed, 0x549cfca5, 0xfc255c60, 0x6f0fa1a7, 0xd792a745, 0x0a6a411b, 0xc4fdcfc7, 0xa8b19c66, + 0x7a9f3d25, 0xfd9a264c, 0x090e1a4c, 0x50b8f133, 0x2a434227, 0x7fd79e9a, 0x7fe8e82f, 0xa56d9d1a, 0x2463b5dd, + 0xf0e7b5fb, 0x0cbf1f95, 0x428c3ccb, 0xa58cf9c8, 0xbb870516, 0x9ea2ee26, 0xeb537b05, 0x5c1c8522, 0x01909276, + 0xfc900d6e, 0xa7ae88a8, 0xac76d6fc, 0xc0fc880b, 0x7691b2e4, 0xc765c6c1, 0xe74b53c1, 0x2d1e938e, 0x996e479d, + 0x602f4b8b, 0x2e0a2aa0, 0xd888ac53, 0xc8c11cdb, 0x4290fed4, 0xfd0ff1c6, 0xdfc6040d, 0xe11f703d, 0xca530fbd, + 0x4d4aed6c, 0x3e7e435e, 0x2fed42dc, 0xbacf0e75, 0xa4c1bcfa, 0x9b146fc1, 0xf1d7a189, 0x45f4c4c2, 0xb2d36b37, + 0x9f0a3b22, 0xdb3fbb2d, 0xc094bf62, 0xad0169ec, 0xae1c7501, 0xd28b7d1a, 0x3bfaeee6, 0xbb4f1995, 0x886b565c, + 0x01072681, 0x5b8df9b5, 0xeae8a977, 0x261f27a1, 0x520edc70, 0x83f0d854, 0xb3bc1fbd, 0x8d71bf7c, 0xa90bf9e7, + 0x5255b4f6, 0x4daacce0, 0xa7120cab, 0x9b252578, 0x23697f06, 0x25deb4b9, 0xdec70c0a, 0x9a08ef1e, 0xcc686a34, + 0xeaac8c92, 0x4d67b5e1, 0x72be7e4e, 0x41937b5e, 0x2b731908, 0xa5e434b4, 0x75f6c6db, 0xb8333080, 0xfbe58877, + 0x6423e0be, 0x25d56bcc, 0xc8e8465f, 0x46910d8e, 0xbf8a870e, 0x4ab65164, 0xa93a2fdb, 0x3eec77a8, 0xc2d6651b, + 0x9d7947d4, 0x75c59d9a, 0x0a3c0699, 0xa9aad44f, 0x0382902c, 0xa401167c, 0x556c7bf8, 0xc227b862, 0x4d558552, + 0xbea3a0ed, 0xd1a4dc04, 0x0b9ee029, 0x81150631, 0xe09917bc, 0xa29e00c8, 0xc5208127, 0xaba3a2fd, 0xdf70cb68, + 0x91590e92, 0x9f5a6f10, 0x02a1455b, 0x0b13b8cd, 0x2576fbe4, 0x39d84cb0, 0x5e918274, 0x2c6e6899, 0x9e4a490a, + 0xb9601a28, 0xb333e137, 0xf3905f5c, 0x97b740e9, 0x1bd329a6, 0xddc232e7, 0x3bf74592, 0x8a0206b3, 0x61aa950c, + 0xa3a9f505, 0x8ced83b3, 0x10e745bf, 0x2ba1a7c1, 0x0610d331, 0x46136f57, 0x6add69bb, 0xa366631d, 0xed1f5d54, + 0x131f254d, 0x8462ed74, 0x0886e21a, 0x9cbcdc03, 0xc8b8826a, 0xce5065d5, 0xcae7ca00, 0x3b5a1ebc, 0xee039481, + 0x4d8feee5, 0x0f662259, 0x9f6b57e4, 0xa4e046ca, 0x28e39467, 0xce4f1d4f, 0x851561e1, 0xb8b93617, 0x2847bd83, + 0x791095d6, 0x65419a09, 0x0c86b978, 0x6e0c8362, 0xc9b6c297, 0x18286b78, 0x191dfaf5, 0x53087289, 0x95c50d43, + 0xf26e0f59, 0x08493f83, 0xa8a01829, 0xcec89bbf, 0xe9ed2dae, 0xe1e0ef9d, 0xcf89e2e2, 0xa39fe908, 0xb6f7b1b2, + 0xebda886b, 0x9551c988, 0xd913216b, 0xa092ad33, 0x3acef5d8, 0xbf2c4646, 0x021c467d, 0x68a79d2f, 0x0636277e, + 0x1171b11c, 0x9c3a6432, 0x79998b82, 0x4e134511, 0x7e2792c7, 0x6c482749, 0x79185519, 0x33cef80a, 0x034536f0, + 0xdec5b827, 0x3ab32997, 0xf097f1de, 0xf2114100, 0x7c04baeb, 0x4397fd81, 0xd4501205, 0xe5abc95f, 0xbf879685, + 0xe3c67a7f, 0x24045747, 0xd5554e9c, 0x9a853779, 0x16a1dc10, 0x51e4fd1c, 0x62e893e9, 0xa6d0b523, 0x2b2b24a2, + 0x326821e0, 0x44a7f2c9, 0xda728bab, 0x7218ca3f, 0x7b44336c, 0x220fa55e, 0xee04f2bb, 0x008cdcfc, 0x20d3c37f, + 0x5e173a7a, 0x271b0a6a, 0xeb34010f, 0x91241c7d, 0x3ae640e9, 0x959c2215, 0x8b2145e9, 0x21fbcc3e, 0xf8adfb98, + 0xc010de02, 0xee3882e9, 0x01683466, 0x21ec8fd1, 0xc536a4d2, 0xd3d40a8d, 0x4e5700a1, 0xa8174eee, 0xcf6ee584, + 0xdeb76b6d, 0x821e71eb, 0x4e302d0e, 0x883daf98, 0x9f925edc, 0x65f9af15, 0x56e7688d, 0xc1619b06, 0x7cd50c3d, + 0x11036f80, 0x3bf8c126, 0x0643834f, 0x89a86bf4, 0x00ae3a9e, 0xc0fb92bc, 0x71ac6712, 0x61abb62e, 0xfab4ea44, + 0xad8c5e30, 0xeac65a8e, 0xeb478b9e, 0x6ee43428, 0x036e419d, 0x35f2150e, 0x424577cc, 0x36369304, 0xab441f3e, + 0x17da5c68, 0x0ef7a543, 0x4001becf, 0x2d8736bb, 0xc126ae19, 0x843b55bd, 0x0b82cb7e, 0xbffb26b2, 0xd0cb1418, + 0x7aadfc0c, 0xc3056085, 0x2b523296, 0x983fcdad, 0x6155d935, 0x73b32ce9, 0xe6eebbe0, 0xa7897f50, 0xa794dc0f, + 0x2ce7871c, 0x5b078fb9, 0xe31d2fed, 0xa9cf1e3b, 0x0a24cdd9, 0x4592b7d4, 0x3ac0c2ea, 0xc59a748b, 0x19f839df, + 0x9a5b5098, 0xe60c3cb4, 0x2cd43ba2, 0x09b82162, 0xdf83fec3, 0xa82f214a, 0x3d98437e, 0x323aacf1, 0xb76bb01e, + 0xc372092d, 0x0d8f3a96, 0x71920adb, 0x625d7e42, 0xfa3d30cc, 0x713701a4, 0x2b79e695, 0xa4bd8615, 0xd1a16e46, + 0xd172246e, 0x4aa766ac, 0xd3cfdbfc, 0xaa14d382, 0xa6f1c231, 0x329670ae, 0x0e3706f1, 0x09770ffd, 0xbb1e29b5, + 0x352f37e4, 0x3a9d37b0, 0x85e9b68e, 0x6048ab61, 0x34deb69c, 0x5c9c1b19, 0x37a51d89, 0x14b76b3a, 0x7cd247ca, + 0xa4b95e00, 0xc2a80527, 0xf1a347a0, 0x8ba35801, 0x412b08ac, 0x6bdf062e, 0xfe4c28ca, 0x82a775a0, 0xe41c8ed0, + 0xf65fed0f, 0xed1a9293, 0x869b8ba9, 0xa36e3915, 0x7a9741a1, 0xa743f8d5, 0x1043ee4b, 0xeca9d85a, 0xf849da49, + 0xba3ac8af, 0xc1bf633d, 0x7c58b83b, 0x111f7b27, 0x6f686a18, 0x58ff43ba, 0x280a6ef5, 0x6616c4af, 0x1cd0682b, + 0x94f66523, 0x33dbda37, 0xae162bd0, 0xcc8a3e26, 0x7b54c505, 0xe3b59539, 0x84172842, 0xb962d09d, 0x8bccdea6, + 0x1de01bac, 0xdcc48c07, 0x4f8a1ba8, 0xb5a91cc5, 0xbd719b2f, 0x170a8705, 0x6289f68c, 0x8da670ad, 0x418c783c, + 0x511066ff, 0x044b5060, 0x6342bfe2, 0x040666b3, 0xc85da1f3, 0x35371020, 0xb9deafa2, 0xee1dcd76, 0xfb3de520, + 0x8d715800, 0xe20d77eb, 0x9a98123d, 0x6d0155c3, 0xbc2c689d, 0xe7341f25, 0x38d1032e, 0x81ebde58, 0x91c3f650, + 0x17a07d4d, 0x34e0daaf, 0x3f6bdacb, 0x20b86142, 0x378d7e83, 0xa99c5bab, 0x928cfedc, 0xabe75cb9, 0x54fdf89b, + 0x448a4e92, 0x3a1c1171, 0xbff23ada, 0x579e7d1c, 0x9bc834d8, 0x287a9511, 0xedc99ac6, 0xdbf919b5, 0x001fad50, + 0xb49a8325, 0x41161e7e, 0x5a882406, 0xb690551e, 0x4b103165, 0xf0de7739, 0x47000431, 0xfe61316e, 0x7d6f8e7d, + 0x6e3549e6, 0x80703e5e, 0xdc4d43bd, 0x085a1db0, 0x27fc4541, 0x40339dc3, 0x2022b696, 0x545ca410, 0x9a448d0f, + 0x384520a5, 0xdc0c5c72, 0x5e3be43b, 0x651ed6eb, 0x2c2f8358, 0xf804c91d, 0x79ae5dde, 0x240bef74, 0xd16e7789, + 0xf180b4fa, 0x2d256dc3, 0x4f02d91f, 0xa5231310, 0x12d0b3e9, 0xefa6b792, 0xf8a2a3ec, 0x317ce8df, 0x2bad2041, + 0x1795c0eb, 0x3d3a7ad5, 0x59094595, 0xb7250157, 0xbc9850b1, 0x2137fec5, 0x8b1fc000, 0x081a5ebb, 0xe2e0e7bf, + 0x87e3bc35, 0x38b25b3c, 0x59d66c6b, 0x6351888d, 0x41f8f816, 0x48dd7f87, 0x7fe5687d, 0x90e265f4, 0xa0c63364, + 0x7a23ba93, 0x1b24e9d7, 0xb6e2a462, 0x3b713465, 0xba9fd33b, 0x2d7a9b22, 0x6ca25095, 0xfd2bd191, 0x7e7957b5, + 0x0e8ffa82, 0x5b49200a, 0x906a564f, 0x81bfd847, 0x605bfd67, 0x921e00f3, 0xeb72de40, 0x9b1b78c9, 0x0f8f7d26, + 0xb040ad47, 0x3e57141d, 0x7861e954, 0x6425c32d, 0xa38f5c1c, 0x4884d7ac, 0x3274f33d, 0x0688c3d1, 0xaffae1e8, + 0x09e3b8f5, 0x1758dd4c, 0xaec2ba18, 0x4048d573, 0xe67bcf8f, 0x52be9eab, 0xd3a6c056, 0xa0296453, 0x157409e3, + 0xe7157b1a, 0x501a720a, 0x6fa77610, 0xf77412b0, 0xe4df78ec, 0xa4be1ac2, 0x143de562, 0x4b89fc11, 0x2934bc90, + 0x0d3534aa, 0xab0774d0, 0x89d65378, 0x40a68dd3, 0x7c598430, 0xd3e2bc11, 0x15fa3d87, 0x6bb0d9cc, 0xfac4bb1b, + 0x42ada071, 0x64f28d4e, 0x867f5501, 0xb29fe1a0, 0x46cfcd5a, 0x3f279b5a, 0x7f27eb66, 0xdba29701, 0x68633d4b, + 0x7f33c4a5, 0x78f081bc, 0x39839914, 0x83694c18, 0x3c339aad, 0x6b2e903c, 0xe7463857, 0xfdd59215, 0x57871616, + 0xdf092bdb, 0xc9bfe2a2, 0x1d20ff90, 0xb46a7c12, 0x3510a80c, 0x53cb1d3d, 0x3a63a96a, 0x514d1a29, 0x4374e87b, + 0x79f74b5b, 0x95d53910, 0x7884137b, 0x4546a1ca, 0x00ca97d1, 0x4c54b8ff, 0x1cd9ab9d, 0xa72c428c, 0x1d07c2e3, + 0x802dcc91, 0x43943939, 0xbf6c49de, 0xb97d7a1b, 0xf306b272, 0x15aabb4b, 0xa1bfcfc0, 0xb82d27b0, 0x089533f9, + 0x74a9faab, 0x54d8deb0, 0x033851c6, 0x4079126a, 0x80b2a0ba, 0x62814d76, 0xb3946c51, 0xa35e8536, 0x38bfc53b, + 0x71754816, 0x1da580d9, 0x6f6a7dc1, 0xd9a8bceb, 0x2a0377ae, 0x3bf8e7bc, 0x2198353d, 0x261b4699, 0xf4fa480f, + 0xbec620d2, 0x50988b0c, 0xc5bc540a, 0x52c14723, 0xe6a60acc, 0x658f63a5, 0x28de067b, 0x23bc83b1, 0xb5dcd837, + 0x3a9ca627, 0xdec80222, 0x5de26be2, 0xf04f11be, 0x076cadc0, 0xece5eb6c, 0x879726b7, 0x4c21be7e, 0x56a6ecb5, + 0xa8f9ce91, 0x7ee44188, 0x0c3a60dc, 0x7772ecd5, 0x8cc7730c, 0x743a4056, 0xdf7dcd11, 0x6f9b64a9, 0xf8d8b525, + 0x75f27788, 0x0399dfb5, 0x8affce98, 0xf91bde60, 0x779bfb0d, 0x3efe8722, 0xcfc27566, 0xa2f031f7, 0xbbb41da9, + 0xad643b74, 0xfbc3fdaa, 0x956edd9b, 0x81a9513a, 0x5edab30f, 0xe4e41332, 0xcb7c9673, 0x1a09a2f5, 0x298171c7, + 0x5085427f, 0x34db8437, 0x9eaaec1c, 0xcf4a03ab, 0x3cf2768b, 0x47f21ee1, 0xba929113, 0x536adc44, 0xe453e396, + 0x89c0872f, 0xd6f29d90, 0x034f8ed2, 0x8214df2b, 0x39d3dccb, 0xa340f0ab, 0x79ff6b96, 0x1ae8a4d0, 0x5b7eb213, + 0xc511565c, 0x052ef08b, 0x15992bc5, 0x749eae1b, 0x28a730dd, 0x786d3560, 0x1928cfc4, 0x6d4fe638, 0xe8d665ca, + 0x4d9153fd, 0x25990c11, 0xec077564, 0x7e70d8e8, 0x157caa73, 0xd4db9d1a, 0x8e90197c, 0x8004801e, 0xb388f597, + 0x39fd899f, 0xcf3f704e, 0x37983db7, 0x9e2ddd75, 0xf7437463, 0x28b4bbfd, 0x82108256, 0x8d434f39, 0xd81c3a82, + 0x53fe682d, 0x881ee0f6, 0x1395bdfd, 0xe0ad2b9f, 0x94165f72, 0x26f32b06, 0x8b7de8d2, 0x0bca4ac7, 0x147eb0b0, + 0x86b7def7, 0x49d10c37, 0xba102dbf, 0xc87a9c73, 0x9e182303, 0xcb14ce01, 0x9f8f6760, 0x3b968c7c, 0x94408ae1, + 0x86acd4bb, 0x4eaf8388, 0xcba4f62c, 0x61cf27b3, 0x7571f168, 0x3570b106, 0x4069011a, 0x5a239304, 0x77cca182, + 0x356f9057, 0x6c89d7f2, 0xbdebd5af, 0xa0f34c4c, 0x3002bf3d, 0x9b69dbf7, 0x8cb03434, 0x45b66e2e, 0xb38dfb4d, + 0xf6ace580, 0x1c22006e, 0xcf4eec6f, 0xcca0216d, 0xdf6c5211, 0xd7ace7b1, 0x6236d6a1, 0x155c9115, 0x1f5a40d2, + 0xe6e296b9, 0x15beccea, 0x3473ea21, 0x55b2d377, 0x35712f9d, 0xb6230554, 0xbf7ef7cc, 0xa9b5a75c, 0x322786e1, + 0xb37cbfcd, 0xddc6b4dc, 0x3150e017, 0xd617a5cf, 0x9f8f0ad8, 0x73e5ea41, 0xca98db1e, 0x2ecdc7cf, 0x328eaec0, + 0x76fa8361, 0x8ba446bc, 0xe2f1d2d8, 0xbfdd0ee5, 0x714f9f77, 0xa8a28b14, 0xe5b1936a, 0x8f9b3aa0, 0x24c17b16, + 0x6a87d9a3, 0x7cc90e42, 0x6501193a, 0x588c7606, 0xe31982f5, 0x151f2f00, 0x3bcfdcba, 0x621f5e2c, 0x7cd21793, + 0x40fd7df3, 0x986d48b5, 0x0a117589, 0xa6ff6023, 0x690f35b3, 0xf0408edb, 0x54197035, 0xc97938dc, 0x542ec448, + 0x10cb49b1, 0xffac933c, 0xb5250b59, 0xe1ff8ef6, 0x1f5b3297, 0x574bbc09, 0xc4c38b0b, 0x1fb013c6, 0xe7436137, + 0xe7dfd0b0, 0xbb88b36b, 0x3daa7de7, 0x303bb769, 0x737646d4, 0x68b57ac0, 0x294fcbdc, 0xe8fc47cc, 0xe1deb92c, + 0xabb71b2b, 0xf61e553e, 0xcf4a53b7, 0xe30edd93, 0x5f7f9aa4, 0xbce757d8, 0xbd0e3b4a, 0xe082abf3, 0xc2b73a4b, + 0xbb7253c8, 0x0f23f76f, 0x9e2925b9, 0x13d622df, 0x502fb760, 0xbd518277, 0x14660c6e, 0x9315ed1c, 0x8713a582, + 0x4c3e3468, 0x10e11cd3, 0x2547a659, 0x9e5f9856, 0xa8ab9cde, 0x63b49835, 0x647cffdf, 0xbabcb231, 0x6a09c8ee, + 0x03c3c4b4, 0xee5ca2e1, 0xf8a0992d, 0xb0f58e81, 0x37bed3e0, 0x13c4e463, 0x656dd1f8, 0x532a0b77, 0xa02db892, + 0x4c664d8c, 0xb0936301, 0xe2383281, 0x7cf2437d, 0x999b6933, 0x2a2d8121, 0x4656f140, 0x8321d4c7, 0xeef4b9ee, + 0xbfa20bb8, 0x76930d94, 0xa904f8c1, 0x419d9c1d, 0x106646cf, 0xa0b97428, 0xc1fcc8df, 0x6485aab2, 0x6b3cabcd, + 0x5328b594, 0xdb0927f7, 0x1a5a9d6a, 0x1ce2d2fb, 0xe461f5c3, 0xa35e3cba, 0x2df92667, 0x59e13bd4, 0x5ad96930, + 0x56eea0b6, 0x57e19c14, 0x9d1211b3, 0xc63fdcd3, 0xf52ed0d8, 0x77005ec8, 0x95fd79e2, 0x5861c01c, 0x9d4f4d1b, + 0xae05e25e, 0xd544d07b, 0x5321a43b, 0x57453d1c, 0x00994723, 0x0faed8c0, 0x01f1e200, 0x7a1d49e0, 0xe33d9047, + 0xf4866bec, 0x82512203, 0x9b122a29, 0x51c0c027, 0xdf742e26, 0x01191e88, 0x8dcfdaa4, 0xcfe550b4, 0x2307dfd0, + 0x2b872b42, 0x34763ea1, 0x9fa87cde, 0x42f352fd, 0x568ee8e8, 0x380d4a92, 0x138932b0, 0x69973d9d, 0xa3d7b690, + 0x4f866bf3, 0xb328fd40, 0x5012187f, 0x46faf974, 0x9de2164b, 0x8f870235, 0x998d1a0c, 0x56e467d9, 0xf5793d9f, + 0x7ac568b4, 0x7f47f196, 0x8523660c, 0xb46a5445, 0x8439bec4, 0xe4f54bf1, 0x58c4d3c9, 0xc35ff1cb, 0x497e4dc8, + 0x3fd6c0bf, 0xb4fd46d3, 0x3623c6f5, 0x826c8c27, 0x87a5fe56, 0x7d809179, 0xfe71c282, 0x483225c5, 0x70590596, + 0x7e870709, 0x94f134b9, 0x57b21d7c, 0x4e6e6744, 0x5cfd71b6, 0x6b0864fa, 0xb154f678, 0xe4fe5aa2, 0xa4137c3b, + 0x78a6abee, 0x3f5eff71, 0xbdb7ca6c, 0x21b41a26, 0xfb7048ae, 0x8b202130, 0x0a8133e1, 0xcb6b71c6, 0x54f0073b, + 0xe8ac5820, 0x2568448b, 0x6f1f989b, 0xab786734, 0x8f8ece19, 0x352ea7f1, 0xa60f5372, 0x2e02840c, 0xd7554c11, + 0x2eba55dc, 0xc3264944, 0x33cfd090, 0x450f779c, 0xa4b807a2, 0x75bd2f6b, 0x081f0d8f, 0xa51867f7, 0x4666f47d, + 0x81f10fd3, 0xa3f54006, 0xbd2f4a88, 0xdde2e606, 0x87bdf378, 0x18cc5fab, 0x2ae66051, 0x8b471c27, 0x6c770dfb, + 0x336a9d34, 0xd95e7ce9, 0x3b674cd1, 0x773eb7de, 0x9e6fc06f, 0xa759dc74, 0xbde881b8, 0x16099456, 0xfa9bc4a4, + 0xe7d1fb75, 0x9811c577, 0x3c2bb79b, 0x0db97fa7, 0xdfc24c36, 0x1ecd7ba4, 0xeeb83c37, 0x883f995f, 0x827296aa, + 0xfff5e8a7, 0xf63cdca4, 0x8f24f294, 0xdefc25d6, 0x986849b7, 0xbef4d617, 0xad814480, 0xd8bf9f8d, 0x60ce38a3, + 0x422c67a0, 0x4dcda535, 0x517e0732, 0x9ba0ad4c, 0x7daff3d9, 0x580dd519, 0xfca6bc05, 0x2d48ba93, 0x20edf2a3, + 0x5eb16d35, 0x02a3b82f, 0x6b54c92e, 0xa7201e1e, 0x5c04829c, 0x81fc1e33, 0xba122316, 0x841fbbcb, 0x89dbeb99, + 0x64a11d80, 0x877325ba, 0xf6b90424, 0xdcd5463e, 0x3760f9c2, 0xc5cdf9af, 0xaff60033, 0xcbc1e1fe, 0xd2e162ae, + 0x9bb003dd, 0x903403ae, 0x11e57c0c, 0x8212eb14, 0x000942e6, 0xd163c90f, 0x5d4040f3, 0xee8faac5, 0xc8962d23, + 0x7657cdf0, 0xaecc03ba, 0x126620b4, 0x95a138ff, 0x1cf89368, 0x66f5ec10, 0x02914e73, 0xce18410d, 0x23c11fff, + 0xeefbe25d, 0x3b9be509, 0xfc93c4fa, 0xb12b40d7, 0x36d7c6b8, 0x89600238, 0x66f45061, 0x496664de, 0x400c40d3, + 0x0ca1158e, 0x4767fc8e, 0x6bd4c21f, 0x416caa58, 0x4eaacb8e, 0x8f66bcf7, 0x00cf1bcc, 0x5ac58886, 0x94952838, + 0xc4e81b0c, 0x67d2dfb0, 0xb6e1fcc5, 0x90e77505, 0x773afaa7, 0x8bbe7a37, 0x9db8e301, 0xefa587e4, 0x2249b08e, + 0xee0ca985, 0x529a1aee, 0xd0d4616f, 0x5e3926d8, 0x05eaaba0, 0x0d889e0a, 0x13e8f777, 0xd1aba746, 0x1ab78a57, + 0x1ced3317, 0x654c1681, 0x0dbe8e15, 0xc7960e6c, 0x3d376028, 0x68448871, 0xe96dd459, 0xbdddc955, 0xb0f3f182, + 0x213309a2, 0xff98d21f, 0xb4ac4e2e, 0x78ad4e3f, 0x215ab51a, 0x4933273e, 0x42ecc0e1, 0xfb4d0964, 0x5804331a, + 0x009ceca7, 0x116cdc97, 0xa529c1ab, 0x44ee34ad, 0x4cb40d7a, 0xf56899f2, 0x4d528d0a, 0x00792e44, 0xc6dd866d, + 0x8030869f, 0xf4d781d2, 0x5fc56c33, 0xc5a464d0, 0xb5ad03ef, 0xd38b3921, 0x2a2a07c3, 0x8737b8eb, 0xf0a92558, + 0xa5955b4d, 0xf9dda607, 0x842319e4, 0x8fb3430e, 0xc6ebfa1f, 0x9c2fc914, 0xf820247e, 0x22eb41dc, 0xa7d6ccdf, + 0x7986f58e, 0x00f9e5ff, 0x2714e5b5, 0xcb04fc05, 0xc2296ced, 0xa675cc03, 0x7dd55e17, 0xbe892ffb, 0x9f5bf01f, + 0x7c220b2c, 0xfa7ea4c3, 0x3ee0c013, 0x89bcfa87, 0xe6afae3b, 0x74f279ed, 0x6d1ea0bd, 0xa767c1f6, 0x3b90f7da, + 0x3ccef00c, 0xe3b28b30, 0x660291c3, 0xbea2277e, 0x2ba5f280, 0x87206f25, 0x42f2755f, 0xe15c5962, 0x4ee3bea2, + 0xc503a522, 0xc3d8070a, 0x33f741a7, 0xec8f6e0e, 0x9bf6a82b, 0xfbad802e, 0xc60019be, 0xcb10ab9a, 0xd7f355e5, + 0x62ff8f5a, 0x640c57c3, 0xbfe1922a, 0xccc751b8, 0x19e1e940, 0x174685e8, 0x1001472b, 0xd9caf4f7, 0x13de7097, + 0xfbd3a925, 0xab9fb795, 0xb270b80f, 0x3dfd0c50, 0xb6ac0317, 0x6fcf1f64, 0x69d006a0, 0x9ae48775, 0xcdb20cf7, + 0xa18d8b2e, 0xcdf19cd9, 0x280e2948, 0x975e9f7f, 0x374bc1d9, 0x5585bdf2, 0x46fc683c, 0x48479dd0, 0x739d61af, + 0xeb218c27, 0x0596fb80, 0xbf479561, 0xb4e072d2, 0xa943fc21, 0xb31974f3, 0x39291e51, 0x8c0ba81e, 0xe3ef4dd9, + 0x420ab4e4, 0x5b7b3e3f, 0xc29a5113, 0xf00e4087, 0x2c1da82c, 0x81ac4031, 0x0774606d, 0xd82e45e7, 0x095dde3b, + 0xbf5f3f93, 0x882a4e1a, 0x3f3e5519, 0x18f99e06, 0xda4adeef, 0xc2ce4716, 0x228a6916, 0xd70b4974, 0x5bf9bc10, + 0x767434b7, 0x102c332d, 0x946975da, 0x0d13342d, 0xa0364396, 0xc26d4928, 0xb8a6d7e6, 0x3fe1dd75, 0xb1f591a7, + 0x9f9a73fb, 0x4a00ce07, 0xc51bbc92, 0xa69fcc2c, 0xe521838d, 0xc31373ca, 0x861dcb48, 0xd78241b7, 0xe437a91d, + 0x6a0e64db, 0x7e69d90c, 0x7209c2d5, 0xd13cfe96, 0xb481fcb1, 0xb81ae8dc, 0xbce62fee, 0x31232e2f, 0xfa229700, + 0x2f9815c6, 0x28d37c29, 0xed5e2ad1, 0x1007c83d, 0x0a258ba8, 0x916baa29, 0xc9a05ef2, 0x0046b5f9, 0x2b9fb446, + 0x447da012, 0x850cab56, 0x0c21b2a4, 0x5098dfb0, 0x7be6340f, 0x5f0a9006, 0xcb18e546, 0xb1ba9683, 0xa7dc9695, + 0x5a883df7, 0x8c2d2562, 0x68ed6850, 0x86499dec, 0xde1baac2, 0x867fb2fc, 0xf5bcda62, 0x370db427, 0xd871430f, + 0x683521b3, 0x5607890a, 0x46287f97, 0xcad5d79d, 0x71d49b49, 0xe4b82987, 0xa05d8425, 0xe7b50529, 0x79207699, + 0xa2940718, 0x44abb839, 0xb4406b18, 0x461988f2, 0xf0e641fa, 0x421a3a3a, 0x8a16ee5a, 0xcc386f14, 0x837174ec, + 0x16f4f524, 0xa14dc7f9, 0x87350de9, 0x4bde83e5, 0x6dcc0e2c, 0xb7c22bb6, 0x7661946b, 0x4337bcba, 0x11a2d49d, + 0x4f3b73c1, 0xe0603966, 0x76fd8a0c, 0x893baade, 0x9b6d85fb, 0xbe1654fb, 0x5a810f3e, 0xc74b1bbb, 0x10acc5c4, + 0x7cf4fc2e, 0x50418478, 0x7cc14a5f, 0xa48d3e33, 0x6c477207, 0x16ca20ee, 0xb550d096, 0x7e29d774, 0xdf639eb2, + 0x05802fa7, 0x50bf5a13, 0xd529433c, 0x4461df2c, 0x02b62f1b, 0x335f8640, 0x337ef6cb, 0x135f880b, 0x04067e9f, + 0x33c126af, 0xb2fa9ea8, 0x3dedaee5, 0x07a224ed, 0x17ecf240, 0xb28e7490, 0x1731d189, 0xf17c3aff, 0x61a67ab5, + 0x8c51cb81, 0xd27fa0d4, 0x10f6360e, 0x79e46486, 0x56c4b89d, 0xeb7f06c4, 0x9b3979df, 0x453f4fc2, 0x3aee7159, + 0x297c3f38, 0xa82dc9f2, 0xc48ff51c, 0x983e5397, 0x3f970a2d, 0xc1eb78d4, 0xa3aba5bf, 0x7924cedb, 0x50d57f57, + 0xf7cb4073, 0x3a306c9d, 0x40b99cc6, 0x624c5d8e, 0xf2dcf5b4, 0x8b4498d2, 0xa4586aa7, 0x84300050, 0xae4a3da6, + 0x02771885, 0xf47f613f, 0x4edf8dad, 0xdfb6f38d, 0xb1fb2293, 0xc0b3da18, 0xbe8b6540, 0x2cf053f5, 0x4a9d132b, + 0x789d725f, 0x577fbc42, 0x4eb81eb0, 0x5415dbad, 0xbb30ba8e, 0x773019d6, 0x9f131671, 0xc423efdb, 0x3b6021b6, + 0xc4e75882, 0x4d905ff0, 0x55882d7e, 0xe9652fb5, 0xd6cf4dbd, 0x057a928d, 0x796d6993, 0xbd2be473, 0x0ec7e1fa, + 0x44b27f40, 0x860c1392, 0x032c4042, 0x4c56350e, 0x1d23dae6, 0x9ce61650, 0x03066dc2, 0x222a9e57, 0xc3dda709, + 0x70f098c3, 0x3e6b2811, 0x9a2dda8c, 0xfe5b0faa, 0xb258fd31, 0xc03d8d38, 0xa60e22e9, 0xa83ed50b, 0x1968afe5, + 0x52a3f29f, 0x48c84e22, 0x41c62418, 0x3b98673f, 0xc81b0721, 0x49aa616f, 0xa0ce2b47, 0x8d972589, 0xf50bd2b4, + 0xba79e882, 0x009365d7, 0x555ce393, 0xd29cd491, 0x7486a17e, 0xee401352, 0x726cb26e, 0x0326ae3c, 0x6c2ee93c, + 0x16b25bfb, 0xfdb098c9, 0x06484a1d, 0x29a396c8, 0xd3fadddb, 0xb1218611, 0x8d167c14, 0xe9ee749b, 0x811c4ea8, + 0xe405e63d, 0x1f6516e4, 0xdf7dcdb9, 0x9ea7123e, 0xe82e818b, 0x813f23f3, 0x6039cae4, 0xd3039ae8, 0x6bb41ebe, + 0xa1bf7f30, 0x227a9da1, 0x0e3fcc73, 0x8946cbc2, 0xe0ea188f, 0x4d1ef296, 0x534094d6, 0x50883402, 0x14c78f56, + 0x3d62e3c0, 0xbe5c2aa9, 0xf7487152, 0x40f12b73, 0x833629cf, 0xf68c8c9e, 0xf072209d, 0x6954908a, 0x96acf0a5, + 0xc65a4afa, 0x02f6a42a, 0x7182f731, 0x026a44ff, 0x1cdf1b11, 0xc96901c8, 0x4979b485, 0x28818655, 0xdf800a91, + 0x0309c62a, 0x318e3bfa, 0xed54362e, 0xe81fcab8, 0x03630c95, 0x1d86a570, 0x27890130, 0x2bd91c7e, 0x77502eb3, + 0x47ec8052, 0x738bbbd9, 0xa9deef47, 0xb5623fe7, 0xdd3bb85d, 0x5bd25848, 0x76c57360, 0x2a64198b, 0xbc16c98d, + 0xfbb96eb6, 0x6c658248, 0xf7d0f14c, 0x946770ef, 0xd5e066fb, 0xc4c5e80e, 0x283b5633, 0xe7546431, 0xaa877156, + 0x89a0396f, 0xf42b67a1, 0x9a4eddf1, 0xfcec771b, 0xc1210187, 0xf10e715f, 0x4fa719a6, 0x30c9043b, 0xd096ef40, + 0x2be4f33b, 0xe9503164, 0x4e84f5bd, 0xba5b71c4, 0xe56c6d14, 0x731e1f67, 0xc8a0a306, 0xe2e93420, 0xb71cf3dd, + 0x5b58a24d, 0x028502d8, 0xf9aeb139, 0x1905b902, 0x1f5e24bd, 0x7ad5d91b, 0xac1f959b, 0x2fc92e76, 0x797b7d5c, + 0x9d502591, 0x38a94f61, 0x7651684f, 0x4a6c215d, 0x3c42b7b8, 0xbc6c6d25, 0xe394c313, 0x4b2f2f9f, 0xa8efa4cf, + 0x4644c616, 0x7bfca275, 0x8021c70e, 0x0dbf9ab1, 0x82de59b0, 0xeabd1c0a, 0xdc4b80d9, 0x2b216bae, 0xc452cb5a, + 0x274b3128, 0xdf015b95, 0x870e795a, 0xbb0b375f, 0x489bee96, 0x808dff8c, 0x8cfca44e, 0xdd18dfa2, 0x75baa7d1, + 0xc0343334, 0x8d90fe4f, 0x9b0ef97a, 0x2fdf2489, 0x188a053c, 0x862686d0, 0x731ee293, 0x37413691, 0xa76e443d, + 0x0c2ca0dd, 0x368f1784, 0x4a3300bd, 0x27589d1b, 0xbd79e458, 0x3b58972e, 0x3fefebd3, 0x5ad29e8e, 0x6816dd49, + 0xbdeaf199, 0x44c6287b, 0x141e04a9, 0x440e1722, 0x355d8f94, 0x6d76a954, 0x3a830f3d, 0x75784468, 0x57caf0c6, + 0x77ba0b87, 0x0df8cd1f, 0xa9af2dac, 0x66a6b98c, 0x7ca4e068, 0x10852429, 0xc80b9a47, 0xe77fe501, 0xff9b698d, + 0x2e38e82a, 0x8d6ceb87, 0x43d3d4ef, 0x922e9309, 0x7fc644a6, 0x3bb8971a, 0x032d3712, 0xfccc8b29, 0xf2e3c8e4, + 0x733bc979, 0x4c159d1a, 0x4e7f349e, 0x005a10ea, 0xe4e51fa8, 0x40c6cb9a, 0x97ee7f65, 0xc6c807e4, 0xa83dfaae, + 0xcf4a9a28, 0x16c59535, 0x235d2a70, 0x30aa0323, 0xc8aaea45, 0xf2fe1ef2, 0xcf8e432a, 0x08241b9a, 0x6fb85d2d, + 0xf746a254, 0x69aa2417, 0x42c16e09, 0x4d68ede7, 0xaf0d6e19, 0xa01f8ee4, 0x8b0b1d0b, 0x6962f879, 0x14ca0576, + 0x85c2ed8d, 0x5755567f, 0x4ab2fde2, 0x50e6765e, 0x9ab7564a, 0x9f140b07, 0x36de7fe9, 0x1567d984, 0x7fdf6f96, + 0x21ed6386, 0x32e2df3e, 0x21f20912, 0xedddd4b3, 0x6fd76907, 0x22015c9b, 0xea6cce4c, 0xc32b482d, 0x60fc2778, + 0x9c269317, 0x6d7befae, 0xbc9440fc, 0x4a9641ee, 0xc9171b91, 0x5386bbe2, 0xeaeb2eb7, 0x66c41f2f, 0xaa8e3aea, + 0x95b17ff3, 0x33dc5a13, 0xbe482f25, 0xa019e28e, 0x8c22caa4, 0x5c4aa555, 0x573d264c, 0xc02c5806, 0x63245858, + 0x5448935a, 0x13463f6a, 0x9899d3a3, 0x0dc79de8, 0x45bb9bd5, 0xbd32b378, 0x25ed91a3, 0xde274218, 0x5dc3c003, + 0x80e73834, 0xe6e0b485, 0xd43510d9, 0xcf7d9e3c, 0xd67788be, 0xc64b8791, 0x5a60287e, 0x9c3393f2, 0x27f14a3a, + 0xfb87c284, 0x9fa6cd87, 0xa5a4b1ad, 0xe9bee86f, 0x1c958fcf, 0x173088a1, 0x845aea45, 0xceb69367, 0x68719c8b, + 0xe67e9b48, 0x5c1a8220, 0xde3e373b, 0xccf4d451, 0xad6ea4f3, 0xa59a0a63, 0xf781f5ed, 0x99e91f2d, 0x9a92c0f5, + 0xf7864bc5, 0x73bdf7db, 0xdfd09d41, 0x10f207cc, 0xff15f9da, 0x3f936325, 0x87c7c90b, 0x527568c5, 0x5777c7c6, + 0xfa405b79, 0xa452c1d7, 0x7f5f0afc, 0xaa75d97c, 0x1f83adef, 0x7f21b459, 0x62d8baf0, 0xdc0b5819, 0x27a456b5, + 0xfab96214, 0xfa5bd6cb, 0xa8cd6221, 0xd1443ddc, 0x8ba0b519, 0xc3f8702b, 0x5d354660, 0x3f8c78a4, 0xdbd84172, + 0xa82f321f, 0x72d0a7bc, 0x4c04f736, 0x2d11c63f, 0x90de6f82, 0x834cb872, 0xcedf1b57, 0x8d41d034, 0x5bd96fd0, + 0x058d68ce, 0x8864dcc5, 0x5d77d62b, 0x18157336, 0xa16ad0af, 0x8d542f67, 0xc40ffef6, 0x1172d0c3, 0xce15536f, + 0xf6064d56, 0xadd65c33, 0x5c838b6a, 0x983feac6, 0xe9c1b798, 0x67f46cf4, 0x6e00144c, 0x613a6a5f, 0x1d12cb3c, + 0xefbc1469, 0x601eb6ee, 0xaf5443f9, 0x8a9d2d73, 0xcc9f70a5, 0xb341b06a, 0x204e08f8, 0xeff3c3a5, 0x732c36cc, + 0x96856784, 0xf4c1803a, 0x2cf2e04b, 0xd92c6ee8, 0x501ec6c0, 0xd9b514bb, 0xa252bce3, 0xca383642, 0x86ebb6ba, + 0x99e94d62, 0x473c9116, 0x32cfb4b5, 0xc5552efc, 0x8d7ced1c, 0x9fc40eee, 0xa3689c73, 0x34e021d5, 0x4b3c8399, + 0x0b926d2d, 0x5def2ebe, 0xe142d295, 0xed79b7fb, 0x6398eee6, 0x22c3d21b, 0xea67c42d, 0x7215bfe8, 0x518a15ce, + 0xec72cb93, 0x3918f8ee, 0x949aab8f, 0xebc0b460, 0xca3e3e96, 0xaa0b97bb, 0x56ebaa16, 0xc36b7353, 0xb3fceee8, + 0x131ebc72, 0x92ef38d4, 0x1155eeed, 0xc8eafbb7, 0xc5ef3cd5, 0xd85bf1ef, 0x680213f5, 0xd6d24135, 0xb6a93aa3, + 0x45c86590, 0x741f9d36, 0x24b8ff55, 0xb8b5fccf, 0xd92e0237, 0xefd3bdd8, 0xc13b0c59, 0x156dcd14, 0xf551f24f, + 0x629b0bd7, 0x3e670b37, 0x5656d602, 0x314f09a8, 0x2c1ca636, 0xedea6960, 0xdc7c7904, 0x67ffc00c, 0x2aebdb02, + 0x8b180dea, 0x7b98578c, 0x4e09fb53, 0x0dc87f95, 0x9bbb1615, 0xd5e8a85e, 0x23f66663, 0x693881a5, 0xe9709c2c, + 0x8b40f368, 0x276cc866, 0x248db8e3, 0x77a3f1f5, 0x27b60862, 0x9807d715, 0x09a2c249, 0x92f6e646, 0xc34e5eca, + 0x6cb9f410, 0x4cc12bee, 0x6564b09c, 0x137d240c, 0xb177f93f, 0x9f4f8653, 0x683fcbbf, 0xebe65411, 0x713a76b4, + 0x0c30e799, 0x94ddda00, 0xc371df4f, 0x2fb43f97, 0xc2db8a5f, 0x95475ab8, 0xba64e9a9, 0x738fb605, 0x19aa7b88, + 0xd28e60fa, 0x5e455f85, 0x2bf6ad79, 0x364e32e8, 0x05c6f2cb, 0x9ee2fee6, 0x34a45300, 0xc4c9a247, 0xe9122471, + 0xe08fbc43, 0xc104d191, 0xbbc4a9cf, 0x64a3fade, 0x8bd2769f, 0x97765546, 0xcce995cc, 0x294705ba, 0x4b693806, + 0x1e7d3e33, 0x2cca51bf, 0x2e503889, 0xf2c63dc8, 0x243a96ae, 0xe2a57059, 0x4d2c1ead, 0x65a9d4ae, 0x7da24fc7, + 0x30b84403, 0x0a2991da, 0xf292bba6, 0xc38498b2, 0xe4828db0, 0x484b9d91, 0x43ef63e1, 0xe027272e, 0x5c769841, + 0xf51a7b60, 0xcc86dd9f, 0x43f877c5, 0x8f7b4cd9, 0xe76781db, 0x9a335e85, 0x851b128d, 0xb28cf053, 0x6e03c72e, + 0xcc6a0a86, 0x85a1a724, 0x94bfdaaf, 0xc93ab562, 0xbf2e5746, 0x14063107, 0xecfeb9e1, 0x4742b8f3, 0xa55045bb, + 0x5535d606, 0xec6ee716, 0x33dcda1d, 0xb23a3fa9, 0xe4eb7260, 0xe44ad0a5, 0x9cdabe68, 0x2f629a52, 0x5c27f558, + 0x3eb3ce38, 0x13106911, 0xf5bc56cf, 0x2e4656af, 0x532b43cf, 0x29a75615, 0x3211ab33, 0x6a29c931, 0xdfe6fa39, + 0xfdcc6ecd, 0xf346f762, 0xbf661953, 0xfb88bb4a, 0x693890ba, 0xed7b6a80, 0xe76f831f, 0xc9467fee, 0x85ef1f55, + 0x9db05a80, 0x7438d134, 0x42123b2f, 0x6850eb25, 0x8838b1d8, 0x81cf621a, 0xd2538db6, 0x866b5e4e, 0xd6043f3f, + 0x40fb1c43, 0x9a60109f, 0xf1f322b0, 0x8819a0bb, 0x99ef4e07, 0xd470dab2, 0x74f46690, 0x744d6d9b, 0x21da926d, + 0x6185ea95, 0x6bfcd3d1, 0x897b2251, 0x4392ad0c, 0x7e1149c3, 0x532ea11a, 0x741ccfc3, 0xdea17c75, 0xa8711d1a, + 0x3bc256ff, 0xfb32a757, 0x017499ef, 0xe609ed1b, 0x38a01d2b, 0x941a1a6d, 0xec52cff9, 0x6f3ced55, 0x36930e44, + 0xb2b58643, 0x7e7337a5, 0xcb90072a, 0xb921d868, 0x25c9ca3e, 0x3f598d8a, 0x4786ec30, 0x293605bf, 0x42cf9836, + 0x9636c929, 0xcd0af179, 0x473c0f81, 0x4df6b580, 0xb5f5dcdb, 0xd02af88f, 0x42969dcd, 0x73f315fb, 0x62ed113b, + 0x4d7201e0, 0x66210f90, 0xdffc09e6, 0x9fba397d, 0x0b92e5c8, 0x81af8896, 0x9f16f251, 0x08e578bf, 0x76a6100c, + 0x378bff82, 0xdba9c0e8, 0xb0257178, 0x4c5e132f, 0xc8d73641, 0x7e73be9b, 0x11df105c, 0xd21691f4, 0x4c55a8db, + 0xd35b7bc9, 0xf04ef8b1, 0xb9575306, 0xe7b62a94, 0x9df88035, 0xb60b6a46, 0xfeaedb14, 0xe1568b6d, 0xe7e89ef4, + 0x53c3caf8, 0x6f83d068, 0x67c0c139, 0xe55b5102, 0x333d221d, 0x2be97c11, 0xd810e342, 0x3ccd90fe, 0x25a81a91, + 0xb8312791, 0x24a7cdcf, 0x985735df, 0xa81371a4, 0xa433d250, 0xced22053, 0x97a6c22e, 0x83120f10, 0x88bd706c, + 0x8f848eb8, 0xd104d08f, 0x04401bae, 0xf9eabe3f, 0x91675580, 0x163255f1, 0xd90720da, 0xd40c229a, 0x3d028cd6, + 0xee7cd938, 0xe5fb2298, 0x370a83db, 0x6528b529, 0xded4c6fc, 0xe6d12a89, 0x55739b2f, 0x7d25b0ac, 0x60886477, + 0xb4a2efaa, 0x9fb74a61, 0x6fdd3bae, 0x6d71f0e4, 0xd9179b21, 0x9455b9d1, 0xd78eb728, 0xa0953589, 0x53bd02f0, + 0x8491addd, 0x2e3cf028, 0xbc426c7d, 0xed23db10, 0x012fb66b, 0xb1b7b003, 0x0923fa70, 0xa354a12c, 0xdd6b3d1c, + 0x2c4908ad, 0xcbb49bae, 0x917683de, 0x601c34ec, 0x5ecab4c3, 0x2045dcc8, 0xbfee104c, 0x04514c05, 0x2fe8f23a, + 0xba12a2c8, 0x7fbcda6f, 0x65e90875, 0xec8d14bf, 0x4246a805, 0x5d982671, 0x5078cbcd, 0x2669859a, 0x403c8daa, + 0x20c69f39, 0x0d812139, 0xece11f11, 0x4b849d08, 0xfe1af259, 0x572637f0, 0x571a77bc, 0xf2dd2cf2, 0x1ebee4df, + 0xb4921485, 0xee4af96e, 0xad06e68c, 0x2e0de4f2, 0xc13d6aa2, 0x9da609c7, 0xa8367dc6, 0xe5af9ed5, 0xa3990c2f, + 0x202565a2, 0x5a4d9015, 0x6ba7d9ce, 0x136e534c, 0xc9bca8d9, 0xfaeaa974, 0x8fd2cdea, 0x3e3575ff, 0xdf1b93ef, + 0xd136769b, 0xb41c58e4, 0xdaef864f, 0x5e138ec2, 0x109a1fdd, 0x730c72fe, 0x2c695ebb, 0x91d082f8, 0xa4c63379, + 0x63e3b1c0, 0x38ff7a53, 0x26cd238a, 0x77f94d7a, 0x404b56f2, 0x343359ce, 0x5529106e, 0x557281e2, 0x5c9e1e95, + 0xd8b1ef48, 0xd802b421, 0x782ab70e, 0xde8320f7, 0xdd3872ca, 0x98655421, 0xa7f3c55d, 0xa7817a6d, 0xbfa69261, + 0x093f5a46, 0x33a72f5a, 0x705ce47e, 0x632fb290, 0x1ea00409, 0xacfd3aa4, 0xe66a7de8, 0xff3ae44d, 0x306741fc, + 0x3737e09f, 0x9e55b731, 0xdc1ccd4a, 0x285faab0, 0xa01555a3, 0xa599ee0f, 0xa20d89f7, 0x78ddfc99, 0x49405795, + 0x3fd69571, 0x2f1f1d95, 0xd5bcd11a, 0xb7de358d, 0xd63f5557, 0xd2a91060, 0x77864997, 0xdaa67183, 0x243234d5, + 0xa70ba3ec, 0xd7896237, 0x7ab946e2, 0x8d99681a, 0x14a376fa, 0xa149aeb4, 0x5cc7f125, 0x1accedff, 0x36dfabf8, + 0x7ed5fbb3, 0x21fd127a, 0xbb1dd116, 0xf383593a, 0xbbfb3972, 0xb458990f, 0x8da036d2, 0x82efd958, 0x9dcc7ff3, + 0xfe1c352e, 0x9e67a930, 0xc55eb3d0, 0x62277b3a, 0x73ef4e52, 0x7fc1fe37, 0x98a90b71, 0xa0db94b5, 0xf35bcc4a, + 0x5c69a555, 0x31b183ef, 0x3e3dae86, 0x8d4134cc, 0xe8a2e585, 0xa74fef0d, 0x56b3f4c5, 0xdf21d9e4, 0x8ad6c0d7, + 0xbf183ba0, 0xd9407f1e, 0xadc1ef4b, 0x94470433, 0xe1423d7d, 0x966a2d40, 0x4d7b8c43, 0x703974d7, 0x019eb11e, + 0x61d104fa, 0x7b102e4f, 0xb3fc8d5d, 0x787722ef, 0xd87c6204, 0x8a2e444c, 0xb1fad55f, 0x17e8c55d, 0xa33255fc, + 0x75b9e1ca, 0xa58d2160, 0xa17edfce, 0xa22fb194, 0x0a180d51, 0x39a60115, 0x1466dab8, 0x6023de4d, 0x0986d0da, + 0xd28a8591, 0xd94a6278, 0xff0d5ea5, 0xcb9b1edb, 0xeb3218a8, 0x02dacf2b, 0x1ae188ae, 0x40c381f8, 0x8ad9d20b, + 0x2645093c, 0x8f772073, 0xa129a647, 0xd6cfe0c8, 0x7c12cdec, 0xe85b780f, 0xfb2eb3f6, 0xbcd665f9, 0x9ae94300, + 0xba264c61, 0x6ee7c582, 0x2e42d48d, 0x44a47860, 0x7fc4b884, 0x32d9802d, 0x4eeb969a, 0xafb874c8, 0x483256f9, + 0x69492c32, 0xc66daf79, 0x93acb06c, 0x324b132a, 0x6f37531d, 0x86317836, 0x704a45cb, 0xfa857939, 0xe14d04cb, + 0xd28dd39a, 0xbf6e0ffb, 0x786f5140, 0xd615c680, 0x059efd30, 0x4c7cc977, 0x0642dc39, 0x13847064, 0x3d99ab15, + 0x29011086, 0x6baadf67, 0x8aa52f47, 0x1aeb1335, 0x2ae35bed, 0xd01273d3, 0x80785e9d, 0xe9841109, 0x7f6cacd0, + 0x45d632a9, 0x940c7a61, 0x3038a0ff, 0xfb964da4, 0x637f6dc7, 0x48048ad6, 0x27412fec, 0x624c00b1, 0x7afa704a, + 0x2ba8b1d3, 0xbb977dcb, 0xb4fb234c, 0xdfe803b1, 0xaed10c83, 0x34a26513, 0xf48c6410, 0x8b95cf3c, 0x9d2acedb, + 0x29579e78, 0x7c54ea3d, 0x51e49352, 0xbcab2e6d, 0xc214ac11, 0xa167d26f, 0xfa2fd817, 0xf3ff5f6d, 0xc01e03c1, + 0x1fe555ed, 0x39bd5d0b, 0xfa9432f7, 0x779f3e6a, 0x16fe37a0, 0x27ea0bd0, 0xfb2ffd56, 0x8b931f33, 0x04583fac, + 0x3ee52f77, 0x677009c3, 0x97cfd723, 0x5ba3cf25, 0x391d5f3f, 0x8c7e6a2d, 0x0183a7b6, 0xda97ef3b, 0x7b353f6c, + 0xfed4d4d3, 0x15836ea5, 0x083f4511, 0x13df19cd, 0x364adb15, 0xb6b30faa, 0xbeaac52b, 0x7ac78d12, 0xe926e954, + 0x4ae58ee8, 0x7df6945a, 0xaf8785aa, 0x3a758948, 0xd2dc7ab0, 0xdf13668e, 0xe3002465, 0xc18dd199, 0xdd2466a6, + 0x7b8c36f8, 0x77be5989, 0x9e4b0e2c, 0x8df31833, 0x4a1ccba2, 0x497db59f, 0xed7c1cf0, 0x1692b5ea, 0x84dde780, + 0xb3b8d44a, 0xff727818, 0x26e46755, 0x70e5340e, 0xc52b7ab3, 0xa02409fc, 0x9aa6576d, 0x30f40103, 0x274a6036, + 0xf0114876, 0x7582eebb, 0x0c9af601, 0x77c74e46, 0x5d440aa9, 0x8e7849d9, 0x9acd5c22, 0xe1f58fdd, 0x04e5c2ed, + 0xbd34e5be, 0x92db4161, 0x4aca616a, 0x6d59a348, 0xf9e7d397, 0xcebcbad9, 0x355a3ea9, 0x4081a863, 0x54c6029e, + 0x1d8ff150, 0x7d13834f, 0x89221bee, 0x03f9a3ee, 0x3fea79d6, 0xf0c0e886, 0xc0424d78, 0xc98e3003, 0xaf0e645b, + 0xa5a87a2b, 0x4d22fcb1, 0xcf0efcb3, 0x8aaf83b4, 0xfaf5fe1f, 0xe48695ff, 0x4b3c66cd, 0x5649ca7a, 0x02c1b8a3, + 0x2fd7fa6f, 0xa5c5e8f1, 0x6fca8a65, 0xfbd7791c, 0x734a92e6, 0xd81c9d71, 0x778adeee, 0x131a8d16, 0xef1900a3, + 0x0c73a2b2, 0x84232906, 0xc6af6099, 0x509330b5, 0xb1a59a9b, 0xc6b3b39c, 0xb8ce1966, 0x03651832, 0x7243faf2, + 0x8d2637e5, 0x737d005b, 0x9c576274, 0xfcd16d10, 0xa0ef4cde, 0xe7f1bf42, 0xec75ea18, 0x65ac6c2a, 0xb3ed79ef, + 0x8e68f9bd, 0xa18d56b0, 0xd3b7a748, 0x2c720e94, 0x52d61700, 0x07550a47, 0x43fa89bd, 0x8883cad1, 0x178a89fd, + 0xef4cd607, 0x0cf7b4d0, 0x6c3237d8, 0xc2a05833, 0xde6d4d98, 0x32c10d95, 0x1da3e021, 0xd491f00b, 0x21a38d23, + 0xa791f2cc, 0x1980344c, 0xa98704e8, 0xa0863be0, 0x57ec7009, 0xfc587739, 0x315d84e7, 0xa14f17b7, 0x1421eb1b, + 0xfe8b6305, 0x53f51b9f, 0xcd5552de, 0x191715c3, 0xe75dfc5a, 0xf22848b2, 0xce692ccd, 0x0314fc4d, 0xdd1ecebd, + 0x08f8014c, 0x7b02028d, 0xf0244d68, 0x422578e4, 0x4c1122ae, 0xf6be9020, 0x173d57a1, 0xd51061c2, 0xa454b7cc, + 0x5e69b6c0, 0xa24d8d56, 0x99bd682a, 0x7b67994b, 0xa9779617, 0x7dab6c5c, 0xece1df23, 0xe1ff5059, 0xf306a5dd, + 0x96747a74, 0x1f7b1ee3, 0xc34f0693, 0x2eddeee3, 0x24ff9c67, 0x1b829074, 0x7f53702d, 0x989698f5, 0x38064081, + 0xb686cfc8, 0x388b737c, 0x306d292e, 0x08ca7ce0, 0x5d697079, 0xe3698bd9, 0xc9486391, 0xd7f807bc, 0x324933ed, + 0xdc26bd7a, 0xb0f3d2d4, 0xd2e20f57, 0x8fc91c82, 0x8aebf68c, 0x6e4b35a1, 0x07181917, 0xc0c4f3a8, 0xcd40a55c, + 0xe8c98bf3, 0xe857564d, 0x1d5a65f3, 0xc7b752fb, 0xbece8003, 0x24ef3b76, 0xc968ccea, 0x3b9f41a9, 0xc14dbf9a, + 0x31f39157, 0x230f51dc, 0x61992444, 0xa86f2916, 0xbf570c07, 0x187079fa, 0xdd5978ee, 0x2e4537cb, 0x785b96d7, + 0x241992a2, 0x91afdd42, 0xd28dff33, 0x3105b4e7, 0xff6fd76a, 0xa43cc74c, 0x628ead72, 0x54b3ab7f, 0x9e088a37, + 0x015b608d, 0x10620098, 0xd1cb99c5, 0x26e6df07, 0xbc15a35f, 0xd477f7bb, 0xd763f888, 0xd55971d6, 0xd72c33e5, + 0xca9bc527, 0x84779140, 0x49684eb1, 0x9e85872d, 0x2cd03a4f, 0xb5685c57, 0xede97c64, 0x9f19d248, 0xf0faf52d, + 0x9a561b03, 0x0aa7eb79, 0x77d34609, 0x95c7b4cc, 0x996c8303, 0x35c4e538, 0x89be5b9e, 0xa33ca4c9, 0x1be132f2, + 0x9b0f8ac9, 0xcfaa1ca9, 0xeadf5389, 0xef8f4e0e, 0x58fc091f, 0xbbd46cf2, 0x3a9b0a2a, 0x2d666945, 0x240ba71e, + 0x697bd3ac, 0xf7487a6b, 0x3d23a3af, 0x06d094d0, 0x32badf58, 0x04f5e593, 0xd0b1ae94, 0xbe663928, 0x0a2006dc, + 0xc43d4754, 0x1395c06a, 0x917f5337, 0x1ecd6403, 0x8ed2cb97, 0x364d3068, 0xd20a59f8, 0xa839cfa9, 0x6f635b30, + 0xcb0249e0, 0x108b443f, 0x919e0892, 0x6619b284, 0xcdeb9f29, 0x5453a089, 0x43735c2d, 0x6e55ba5b, 0xe2af6609, + 0x901f0b27, 0x8653141a, 0xfbe25459, 0x1c147551, 0x8c7d4d99, 0x5ad3b1fd, 0xf49dc765, 0xe5d9294c, 0x8c57a64b, + 0x5893f9b6, 0x65f04e76, 0x99de2811, 0xde7af764, 0xd6fe671f, 0xe337ef2b, 0x7601b52e, 0xe541c6a7, 0x99dc38a8, + 0x3cc83a3e, 0x5d58ab22, 0x2141ffcb, 0x754bb65c, 0x9ba5a4e3, 0x210b25a9, 0x237aae46, 0xfccc104a, 0x3eff7b3b, + 0x99dc3cad, 0x13986431, 0x695e19cd, 0xab190a93, 0xdb189889, 0xe9cb6a4b, 0xfe3e47b5, 0x07b1532b, 0xfea747c8, + 0xcb23b6e7, 0xc1ec4bcb, 0x014bcb30, 0x89d447a9, 0xddc13a3a, 0x76e05c6f, 0x511d9eff, 0x3b181ffb, 0x4e8b5149, + 0x85f46636, 0x1b167b38, 0x6265c571, 0x05629f80, 0x92e045da, 0x802f708e, 0x28b5d207, 0xbaacf448, 0xceaf4080, + 0xe3c3aec9, 0x8e0caa54, 0xbb2b3747, 0x1cce348a, 0x13d5c38c, 0x18aa85bb, 0x4dbce0d3, 0x77a3537c, 0xfda15c6c, + 0xd594272a, 0xb1430642, 0xbb4a138a, 0x707365dc, 0x6d188486, 0xc1fde91b, 0xa624c0b7, 0xcd948d4d, 0xfa307b22, + 0xdfe4a8e3, 0x22509e8b, 0xd85e7d61, 0xea5a9309, 0x8d2c53ab, 0x2aec10f0, 0x667b4ec9, 0x493b0d17, 0xbc0b7dd5, + 0xaea7b78e, 0x5df83eea, 0x22425e89, 0x9d50debd, 0xf36fb3a1, 0x42aa37c9, 0x984bb542, 0x56201e1b, 0xd6921a8d, + 0xb5323c4d, 0x37238bd3, 0xe4cd728a, 0xb5ce8772, 0x3944bb33, 0xb8c0f194, 0x651dfed2, 0x1441dadd, 0xc80ca051, + 0x65039053, 0x684f7887, 0x1d5e40d3, 0x1ba252dc, 0x27054d15, 0xda89e244, 0x90969d64, 0x2215b36f, 0xf6da8064, + 0x3d8bd037, 0x6211428e, 0x59de8c09, 0x682faf42, 0x53f59cf8, 0x818e45e2, 0x172827b9, 0xc4629584, 0x231d54ba, + 0x4c0a7bbe, 0x5d4b1ee5, 0xe28100c8, 0x90cae8e3, 0xf62077ea, 0x39ef1e38, 0x8bc709b7, 0x0a09c0e3, 0xbfc7a0d5, + 0xe3765e12, 0xaf549bf7, 0x93e54fdd, 0x9f21e7e4, 0x0ab149f0, 0x11db6379, 0x7a4393e1, 0x4f78e797, 0xb6bbd381, + 0x9c1c7529, 0x7de1850f, 0xd2525c1e, 0x1865dc6b, 0x07f4fed0, 0x57e37bfb, 0x90014993, 0x8e8a1f46, 0xaa50a169, + 0x0a76040c, 0xec8b7c69, 0xc20a9d23, 0x70509f67, 0x0246de91, 0x1f95f262, 0xadf7cea2, 0x575f65bf, 0xc1fbf5a0, + 0x26cd077b, 0x1dce24fb, 0x4ba0a0ac, 0xb8464438, 0xed8fd038, 0x6bd268e6, 0xa3d018bb, 0x7d959cb4, 0xbff25414, + 0x6c9afc1e, 0xce12bc51, 0x634efbf5, 0x4e2c9c83, 0x728fbbf1, 0x84fc3403, 0xefc6d466, 0xaa2b5419, 0x11397797, + 0xec1433be, 0x777dd725, 0xf9c5bb4c, 0x7e3a860b, 0xce031188, 0x2b317bdc, 0xc24f45b9, 0x8b75384f, 0xc74dde93, + 0xd8c2799e, 0xb6a052cf, 0x83e8edfe, 0xe1cc60da, 0xd52b95e0, 0x972c2c52, 0xe7dfc826, 0xb92f76a4, 0x939c4627, + 0x3163f81a, 0xfbfde0a6, 0x641de0e4, 0x3ff4df85, 0xe16ee2a9, 0x46ce68fd, 0xf609df22, 0x9bc6052a, 0xb5ac6978, + 0x61467d6d, 0x23c8930e, 0x2cc693cb, 0x644688d3, 0x86c6dde7, 0x0a235a04, 0xbe7f6feb, 0x81eb2069, 0x7cd4877c, + 0x9e3d3cb0, 0xae30cf57, 0x2a3d6283, 0xd2d5858d, 0xe3a5bfd4, 0x1aaaba81, 0x021f41e8, 0x22880044, 0xa1d76ca9, + 0x0e243896, 0x0edc3157, 0xb7716ea2, 0x114ef14c, 0xf1f56b06, 0x52489a5b, 0x73d98cad, 0x080ebef7, 0x6f9ddf79, + 0xf2e54566, 0x52c029ce, 0xdc2a2c60, 0x0ada48b0, 0x952d5c27, 0x076d1622, 0xc35a8fbc, 0xc814bf12, 0x493bcc1b, + 0xdf293da4, 0x18bfba62, 0xf007d5f1, 0xd1fd65e0, 0x7b62c50d, 0x3e2375db, 0x0eabd63b, 0xd8df8fe5, 0x1a006bb5, + 0xabf0abad, 0x35ecc9c7, 0x530deeef, 0x59824414, 0xa20bbb7d, 0x485b5ce5, 0x6097cf07, 0xee162b69, 0x1aa84ade, + 0xae749057, 0xc3ac113d, 0xc41c90f2, 0x8d2f22a3, 0xbf56148c, 0x3212cc1a, 0xd77a1406, 0x438fcc90, 0xc26b7be0, + 0xf91d95ed, 0xa38e695f, 0x36bed65e, 0x0c7135da, 0x5ea67e50, 0x3a1dc857, 0xa4645926, 0x6b767000, 0x27ef717f, + 0x0654541d, 0xd71d48df, 0xa826c3be, 0x6c28769a, 0xd285877d, 0xf5ff51ba, 0x6ceca96c, 0xe3831600, 0x66949b59, + 0x9c95b78f, 0x7cac5477, 0x40d3e87f, 0x414df07a, 0xdec57e67, 0x9ff95bf8, 0xa24d0426, 0xe5406b44, 0x2eba63c7, + 0xb6440bae, 0x0d989ce0, 0x7200dfda, 0x5a8a3c7d, 0x0859d232, 0xbc37b75e, 0x88bbb64c, 0xb5491e8f, 0x0c7dd978, + 0xaaca4e5c, 0x0854c0e8, 0x2789fcf2, 0xbf02f9cf, 0x27431894, 0xb0b942a1, 0xfa24db69, 0x6853c236, 0x179fdaeb, + 0xbcf6748e, 0x91807d28, 0x28087fa8, 0x0b108eb4, 0x79b718dd, 0x5cde2a5f, 0x818e8f0a, 0x14f03dc2, 0xaf16ec81, + 0x86d10e4f, 0xd1aa32fa, 0x7da098b5, 0x5b930afe, 0x0726ab65, 0x3002f86b, 0xe6263f5f, 0x3416af15, 0x5b12efad, + 0x70b0283b, 0xebc16579, 0xb5ef2a60, 0x370741d0, 0x4f60d096, 0xccf55bee, 0x6f4dede2, 0x9cf0975e, 0xc5068c48, + 0x13af16a6, 0xe0de78ea, 0xf407c70c, 0x821c6512, 0xf0ad6aaa, 0x8760ac9b, 0x46fd0227, 0x56133d93, 0xf76f6527, + 0x1e5fb025, 0xa62b396f, 0xe8088809, 0xd84f2f4d, 0xf7bd238f, 0xc894db58, 0x042aa52d, 0xbffcda17, 0xd614026d, + 0x4f080f2c, 0x898ab189, 0x397dd867, 0xabffa6cc, 0x9defc1e5, 0x6bec551e, 0x0c3b4f29, 0x7ab88898, 0xfa8a67b8, + 0x7b168330, 0xfee48eb6, 0xe1a38b6f, 0x7ad34ede, 0x748c34eb, 0x6fc6e856, 0xb9095b33, 0xf6a79cf2, 0xba08fcb4, + 0x23d4ec4e, 0xd46d654b, 0xc76b425a, 0xbe8137df, 0x56d6b4b6, 0x0cfe84ea, 0x2a95824f, 0x1dbf6968, 0x6168869b, + 0x54e297db, 0xe50562a6, 0x7dc66e1d, 0x75d8c17d, 0x10ec7ba7, 0xd414aa03, 0xcd73a957, 0x3c26b1a7, 0x06386429, + 0x324d0cff, 0x7040b97b, 0x673d1091, 0x193922cf, 0x8765068b, 0x7b1c7ae0, 0xe4b8338d, 0x19e1386c, 0xb20e74d2, + 0x713d850f, 0x532fe756, 0x726d19e1, 0x68edbbf3, 0xa4594cf3, 0x16e375ea, 0x908a1c05, 0x363f9daf, 0x66107799, + 0xf6ae637d, 0x606bbeda, 0xf34ce0c1, 0x7f2eb3e6, 0x7d610fca, 0xcdecb59e, 0x47675f0b, 0x6dee0fc5, 0xb6e063c9, + 0x4bc62b3e, 0x2e748a95, 0xe78e2a59, 0x18f9e010, 0xed9b395f, 0x5591d21d, 0x54370b5a, 0x143bf4d5, 0x613487fb, + 0x708df13e, 0x81ef18a2, 0xaa45b889, 0xd5bc6503, 0x2c339ba9, 0x46318fcf, 0xdc45bd6a, 0xd97fdc9b, 0xba6efb67, + 0x1bee2714, 0x8f88b386, 0x3caf8750, 0x7b6a2b1d, 0x18cf4747, 0x7ea8be50, 0xa07e600a, 0x665db626, 0x706b0bea, + 0x46a01ef1, 0x19dd74fd, 0xc41aa6ae, 0x919ec31f, 0x185bc7e3, 0x33cf1fd7, 0xd4545410, 0x2ea54eeb, 0xfa571244, + 0x5deae854, 0xa4565eaf, 0x01084cd7, 0xcc1cd9e3, 0x0bd1fc1a, 0x6c774868, 0x03192e52, 0xab053ff3, 0xd046173b, + 0xdbce17aa, 0xe18b45d0, 0x895c3cde, 0x53047908, 0x9473d3a2, 0xaf5a3e70, 0x68bf7703, 0x68417128, 0xa42034a0, + 0xbbf2a9e6, 0x61f38e27, 0x9577d297, 0x40e69e19, 0xf66370c0, 0xd2cd7a1a, 0xdf7f2a4c, 0x44822951, 0x45bf4c30, + 0x6b0c09e1, 0x2a941988, 0xad5d4859, 0xc6ba7bd3, 0x41f9e3d3, 0x25e20fca, 0xe5ca2ac0, 0x05dc8bb2, 0xedb45537, + 0x24d1d0e2, 0x6bb5140a, 0x38a363e3, 0x8fb98310, 0x2417c11b, 0x3a6400ef, 0x8adeb1fb, 0x0d8bd667, 0x2671ae1a, + 0x56048300, 0x94bef147, 0xe0ec421b, 0x99fb0fbf, 0x994c4fce, 0x0d73b988, 0xb346e3a5, 0x0af71c39, 0x131fef40, + 0x7b9b09c0, 0xff0afd87, 0x60a95ece, 0xc27bd032, 0x4a05394b, 0x0921620b, 0xf86a9a5b, 0x9208e040, 0xdcd039be, + 0x80143bf4, 0xefe24de2, 0x8528e432, 0xb1ff4e19, 0xb2c0448e, 0xfd963a5f, 0x29ce69b0, 0xff1a6073, 0x287d5d21, + 0xe69ba160, 0x58443f16, 0x204a67a1, 0xbf913398, 0x0a037c04, 0xd13cf36c, 0x4ddd6ef4, 0xe97cf5ac, 0x02b7271b, + 0x11531069, 0x9d5b0589, 0xf757a4cc, 0x4095f34d, 0xf22e577d, 0x92f74aeb, 0xd634621a, 0x59c08274, 0x32b3e64a, + 0x3712fee7, 0x2cd2738b, 0x444b7814, 0x70b013fc, 0x77677392, 0x94408ba7, 0x996bb3df, 0xbb7f2cb6, 0x28fe7515, + 0x2615f66d, 0x4a1fb82b, 0xffdbc436, 0x6a65177e, 0x35a823c4, 0xbc7bc6fb, 0xd21149c1, 0xc3deddfc, 0xe78e6a08, + 0x725d924d, 0x1d33aeaa, 0x96cc88a8, 0x02d7c5a5, 0x30ad5bcd, 0x028f312a, 0xf8fed729, 0x43680873, 0x017712cd, + 0x16ae32ed, 0xcde4aa12, 0x898402b9, 0x43f92108, 0xb28fabe0, 0xeeea4045, 0x9d86a35b, 0x3e825d70, 0x70a1ddde, + 0xa6c43063, 0x210b34ce, 0xd960225a, 0x99f77981, 0xce52c06f, 0x23721d44, 0x8029ee3d, 0x11c93d3f, 0x9038062c, + 0xe58104c4, 0xa8e03f38, 0x0a3b9530, 0x8d1f44bb, 0x9cc89e95, 0xbd9451e8, 0x5809e714, 0x5b135512, 0x65b665e6, + 0x9eb5fbe7, 0x0837ce8f, 0xe351fac6, 0xcd98cdd3, 0xfcb53540, 0x666e59f2, 0xa94c8cf4, 0x1888a08d, 0x4bf15af0, + 0x4dc02c7a, 0x41013b3d, 0x3fa12863, 0xd7893647, 0x91c04492, 0xb97734f3, 0xe9fdd56e, 0x4c688b6d, 0xedec17e0, + 0x51144422, 0x8afb4327, 0x20901657, 0x01164837, 0xd483ed5d, 0xb8afaecb, 0x4ab2c0c3, 0x6b8fcbe0, 0x8676ee01, + 0xdf6fcfee, 0x21376554, 0xbfeab559, 0x1fd7e1bc, 0x9a560779, 0x41cf533c, 0xb188f844, 0xe5b95dd9, 0xc0c302a4, + 0x642e0d05, 0x4b4f3842, 0x215ca29d, 0xccbb0e64, 0xa0702512, 0xd2aa670f, 0x8cfd2836, 0x62cdc252, 0xf49846a9, + 0x02cfd9b7, 0xb41942c9, 0x9aa0159b, 0x96305e7c, 0xacfee77d, 0x19f86367, 0x76929d96, 0x11131ace, 0x0d118872, + 0xbfebc111, 0x81dff13d, 0xe25dab6c, 0x6db94fdd, 0x15834231, 0xf13bbabd, 0x2dadcb1a, 0x1f93b2aa, 0x7416e46a, + 0x61b7b29c, 0x1a600d7c, 0x9f552432, 0x4f335293, 0x2a0b7347, 0xfe046339, 0xa5829489, 0x16272eb0, 0xd3bf1f90, + 0x2d22d03f, 0x7f54e24d, 0xa4c547e8, 0x2680d97d, 0x31b9b230, 0xf89df537, 0xc663eb9b, 0x1205aaeb, 0xf39b61ca, + 0x3304d61c, 0xca52f3f4, 0x632fb7ad, 0x4f3248e6, 0x1dbf3c4f, 0x86e4b2d5, 0x3946b19f, 0xa621cb7c, 0xccb810ab, + 0xf3766df0, 0x728e5641, 0x51d6b168, 0x17ced495, 0xd123b4b2, 0xe9aa81c3, 0x11c47595, 0x4b117f0b, 0x0e51c56b, + 0x7f04ddb3, 0xa24ec288, 0x06fbce19, 0x05945116, 0xc1edf986, 0xdec73a03, 0xad63ccff, 0x924136cf, 0xf646421d, + 0x2e357eb8, 0x6c9fb629, 0xa3fc43b6, 0xe0797a79, 0xc5c4caa5, 0x990af6a5, 0x28f5eb84, 0x5cf3e636, 0xd916d920, + 0xbbf1f991, 0x3e171397, 0xc44a2d59, 0x49e1a66d, 0x7ba63833, 0x7d872e1e, 0x6a906293, 0x3f0be07b, 0xe7857952, + 0x328d8038, 0x62a2cc80, 0x46546fec, 0xb67d05c0, 0xc8081d16, 0x6e0b606c, 0xe0d96bed, 0x8c4f7d00, 0x9276e955, + 0x8068d081, 0xf5bf687e, 0x53a8d61f, 0x2c386123, 0xef5a3547, 0xc3a7026d, 0x3fd1d250, 0x0d07a751, 0xc3d8a69a, + 0x9b36186c, 0x7c68fcee, 0x09496910, 0x3d549f7d, 0xdb7dad9f, 0x79fd5789, 0xee2a0d93, 0xb3b413fd, 0x7e146a04, + 0xe1125285, 0x4417484b, 0x54a89b6f, 0x435ddb70, 0xa0374c55, 0x88ec7aa7, 0x0be9b61e, 0x9461ea96, 0xa7a424b0, + 0x3f973cbe, 0x31609fa6, 0x41b65a39, 0xfc9dbdbe, 0x5367447d, 0x9c7aadfe, 0x8c86f13c, 0x12bac66b, 0x11f1028f, + 0x498bea6c, 0x2db2a57a, 0x7e46fec0, 0x34209984, 0x79969115, 0x09e43d8e, 0x675f925a, 0x68876be5, 0x723cb319, + 0x2bd7d2df, 0x6f86f674, 0x18541976, 0xc6e3d069, 0x72f003a2, 0xa6baf717, 0x9734eb9a, 0x7a42759f, 0x09c1bfe8, + 0xb66b8530, 0xde67787e, 0xcee3e471, 0xab9a9ef6, 0xe6562370, 0x39ba8af1, 0x8b165732, 0xba9452d5, 0xc672d457, + 0x0cec762a, 0x2ff50319, 0xc621f055, 0x430d4031, 0xc01edcec, 0x94902dc2, 0xf7176cb5, 0xca3cc29f, 0xeb1e60f9, + 0x2d81a9eb, 0xfa5c5301, 0x995e2e5d, 0x86a0a8d0, 0x3742e826, 0xdd9b1fcb, 0xa071c1ab, 0xe31339c0, 0xbfe64274, + 0x73913329, 0xc04b06cd, 0xda1158a7, 0xed60de44, 0x24f14017, 0x96ad075a, 0x53aaa7a9, 0xab1db897, 0x1222c53e, + 0x066a0102, 0xaddc4842, 0x24fb8d02, 0xa05815e3, 0x84d7d335, 0xe0fe5c63, 0x6c598fe9, 0x84cc1866, 0xe78709a7, + 0x8f8c4f01, 0xf85777bb, 0x716d49de, 0x3a9a1168, 0x39812358, 0xf64f96fe, 0x7a7a5f9c, 0x2467ee59, 0x4d00fa90, + 0xc2aaad8e, 0x6ad12050, 0xadc07f37, 0xcc691453, 0xd82a4a48, 0xde1efe74, 0xcd227274, 0x9db7fec0, 0xbad77a27, + 0x96b8a4b2, 0x738c702f, 0x7b2554b6, 0x66929c35, 0x007f8c02, 0xe639eac0, 0x2e43c57f, 0xa555d042, 0x10588c63, + 0xc95e6972, 0xbafc5e8f, 0xb616c289, 0x07279156, 0x8fee083f, 0x205b5389, 0x53218369, 0xf3fe861c, 0xd3a558ea, + 0x7668c7a5, 0x39c53157, 0xa378cb7a, 0xcd77982b, 0x34695d5b, 0x1fbdf7cc, 0x2cc9a1a2, 0x2f33e9b9, 0x99dc115f, + 0x97a71138, 0xe523da2a, 0x5111a018, 0x993836e1, 0xe15fab3d, 0x93431716, 0xe58d3aab, 0xf4deee56, 0x842cb414, + 0x56917e67, 0xf658a108, 0x1a6f5ce4, 0x39e9801b, 0x00aef8ca, 0x3ad5f69f, 0x6d082a5b, 0x1d9eff45, 0x0db4f876, + 0xaf6b0d1d, 0xbd3a1e57, 0xec4e0fa2, 0x38f682e0, 0xeb83540b, 0xde7b08db, 0x29c67859, 0x3d642721, 0x5426d73d, + 0x744c7114, 0xa63cf192, 0xf8c478fd, 0xae516276, 0x55f62da9, 0x7d308a89, 0xcd79534d, 0xcc421bed, 0x21377524, + 0x90cb2106, 0xe2b04e45, 0xd9d6cc56, 0xc782f52a, 0x18c419a0, 0x5ae5eabf, 0xdf390aa1, 0x1a621e15, 0xdbaa3dec, + 0x857248c3, 0x70f37afc, 0xb94795d1, 0x2c794a85, 0x7a1d84e2, 0x674782ce, 0xd87c9790, 0xacae887e, 0xc200ff5e, + 0x7bf6e746, 0x66cfed52, 0x530b30e5, 0xb918208e, 0xb9173492, 0x47668480, 0x6d04afb7, 0x1a497459, 0x108458ed, + 0x4e2fb89a, 0xb73174a0, 0xaa93dc5c, 0xc17881aa, 0xe9ac282c, 0x54d6a5d9, 0x2a9caf53, 0xde162674, 0x09a73959, + 0x866e3e0b, 0xe286a044, 0xca3a42ff, 0x5640a96c, 0x46675a0c, 0x20341b57, 0xe5a504f5, 0x013b737b, 0x25c8909f, + 0x5992ff18, 0x2aaca270, 0xc4354985, 0xa4fd5999, 0x4f049c97, 0x4c53f0ac, 0x7e5167ff, 0x2ebadf68, 0x5e2831a4, + 0x104ad3b4, 0xb8bee2f5, 0x425c3b46, 0x58a0c8b1, 0x8ab65fa0, 0xfb4e5384, 0x6f83905a, 0x8267ddea, 0x92bc86e2, + 0x267c6796, 0xa7735492, 0x68965929, 0xbc8d89f9, 0xbca5a7ae, 0xa51e1726, 0xebab776e, 0x9f281fa7, 0xa216184a, + 0x40a38b35, 0xa92f324e, 0x96a81133, 0x7cae9e7b, 0x35fceec6, 0xf7b64441, 0xd44f5d7a, 0x4ef26132, 0x1ea97da5, + 0xfcb3db5a, 0x6adc06ee, 0xd875b402, 0xd42eca28, 0xc2c540c6, 0x6331a602, 0x55241aa8, 0x04912a01, 0xf0b0fbd9, + 0x2ea7aae0, 0x1da71484, 0xf6ba2609, 0xb5a6db36, 0xcf668ceb, 0x714d56a1, 0x39e7eb76, 0x245a499f, 0x5624e026, + 0x798616cd, 0x55c12436, 0xa05bcd78, 0x001d4134, 0x3ae48b0c, 0xdf6d2641, 0xd8bebb51, 0x57d1cd93, 0x4fe3396d, + 0x488d9e48, 0x3c3b3b4d, 0x26896696, 0x34bf58c8, 0x692461f7, 0xd43e7837, 0x75981d87, 0xded6dac6, 0x4757eb9a, + 0x277ea8f9, 0x2bc12df4, 0xe5a7932e, 0x85323ad9, 0xd834a876, 0x62fb818d, 0xacc3846f, 0xa85bd2d9, 0xc16a4adc, + 0x8eeea97b, 0xed80956f, 0xf1a0c1dd, 0xd9ad6b41, 0xcd4425aa, 0xc6914e59, 0x209e3df5, 0x019f19c8, 0x75fb3b31, + 0xcf553d73, 0x6e3927b3, 0xa1f4cc46, 0xe5486239, 0x2e590015, 0x57b811f7, 0x64c09221, 0xcc4358b0, 0x5d4c3f14, + 0xf27c0cc9, 0xb66e3e73, 0x3b4edc0e, 0x9b17a28f, 0xefb23682, 0x78bc842a, 0x599695e2, 0xb2f8afba, 0xe254d524, + 0xde025443, 0xe54491de, 0x489d6c75, 0x5224a7e7, 0xd517a847, 0xea7668b7, 0x0391e751, 0x93f49c2b, 0x0d40a7ba, + 0x5061befa, 0x5c0e81d7, 0x3f012512, 0x6e79effb, 0x0ab6e3ca, 0x0cbd7b25, 0xf3ecd1e8, 0xb6948171, 0x70db9c4a, + 0x8985500a, 0x828fb71e, 0x85488bc8, 0x9c1df49f, 0xe1d4892d, 0x97932aed, 0xe3387517, 0x8fd9dfac, 0x0d4232ee, + 0xda380412, 0x9d1a172f, 0x2597b404, 0xb7ae197c, 0xe4202ab9, 0x9b52c417, 0x2eaa9b46, 0x60692c7c, 0x0dbd2623, + 0x3526fb0c, 0xea6454d0, 0x33a7cbd6, 0x663c3d9f, 0x9d01904c, 0xb5e24453, 0x6164df4a, 0x98b98b8d, 0xecfc4326, + 0x6772c798, 0x520ab012, 0xf7d01107, 0x096b1353, 0x93464410, 0xb0de2302, 0x87b72cb9, 0xf8e9e6c3, 0x564f25ba, + 0x7b495cdf, 0xd8429c4e, 0x06b12722, 0xbfc49b02, 0x5e3d50f7, 0xe30f1853, 0x95b06668, 0x1b312e8f, 0x691f8ffa, + 0x16df10e4, 0x397d732f, 0xe311be46, 0x47a7b025, 0x7a5327fe, 0x0556613b, 0x75d66d33, 0xe53e394b, 0x565abdf8, + 0x51978880, 0xc048f9c2, 0x55184fd9, 0xf0e6d26a, 0x998cf881, 0x0283d3a7, 0xe6f368c5, 0xc7ea7df7, 0x177f852d, + 0xf7474edf, 0x7850bd6e, 0xf117d814, 0xd5d78b76, 0x43ee0cbf, 0x13f4f40c, 0x6f682564, 0x08427b9d, 0x22396987, + 0x007f971b, 0x3f50e7d6, 0x2c0da579, 0x45e40350, 0x6927ae9b, 0x6f183c26, 0x852b6a4a, 0x93155d7f, 0x75ca5e18, + 0x69d37b07, 0x6106e79e, 0x6543ed51, 0xb5a96a95, 0x5c72b11f, 0x1d4e7a49, 0x5d76bad2, 0x201f35b3, 0x9b83db0d, + 0x6c8251b8, 0x86b64cac, 0x8190c20e, 0x12ecfe49, 0xe779d500, 0xfdea9e98, 0x0b05b2a3, 0xabe1bcd0, 0x17539c7d, + 0x7aabd1ce, 0xb906e6de, 0xb876b650, 0x3b3a66b6, 0x9ee519f7, 0xbae6d206, 0x130b7e2c, 0xc9946f1c, 0x034e004a, + 0x59cf7a54, 0xb0abdf75, 0xf1ac554f, 0x1c5a04c2, 0x8ea41061, 0x4cbb13e7, 0x5f72b88b, 0x2142a29d, 0xba16dc6f, + 0x88452362, 0xab6e9c91, 0x8ce8900e, 0x209ac6dd, 0x02c8f44a, 0x63cfd8ac, 0xd86655a5, 0x3791266f, 0xf1b29720, + 0xc530eb83, 0x7a7be343, 0xeaa3e48e, 0x8192d6dd, 0xc7228837, 0x18942d58, 0xf92a67a4, 0x41c3869c, 0xcfbef01b, + 0xb624d04f, 0x02e02f91, 0x97402d4c, 0x286312aa, 0xe25287db, 0xf68dcd60, 0x8a3861d1, 0x661acdf5, 0x374d07b1, + 0xb9e47882, 0x2f730fd7, 0x518177b9, 0xd6b66eb6, 0x74b1b6be, 0x36cba3c4, 0xc4cd0e20, 0x49f0b8dd, 0xbdc8ef0f, + 0x9655bd25, 0x87cf4e5b, 0x6001c2bd, 0xcad0341f, 0xe48d1251, 0x5f1f8f36, 0xbf103400, 0x2e358bca, 0x617b8538, + 0x0cb25295, 0xa2a7fb92, 0xe2463ada, 0x3751d732, 0xde0df36b, 0x7d8810a4, 0x869216a2, 0xa14cdb4c, 0x6b66d44e, + 0x3d0c691d, 0x5b545f79, 0x9b4a7682, 0x23b4ae0c, 0x77d32492, 0x278345af, 0x33f1d574, 0x057774c5, 0xd9d64871, + 0x00fc969f, 0xefcab559, 0x529ec56f, 0xa448f0b5, 0xb889dd89, 0xdd11b355, 0xbac5a722, 0x1132c33f, 0xce5a9ea4, + 0xdcce058e, 0x4f7faaef, 0x4689a0c6, 0x4d5ff408, 0x8fff1ca9, 0xb5ddc051, 0xf24f488e, 0x8842f733, 0xc6750234, + 0x64868166, 0x92efb5da, 0x5112558f, 0xc5fa3cd2, 0x0a2dfaee, 0xc95f6218, 0x32b30bf7, 0xff9e6389, 0xff8e9227, + 0x179499ba, 0x3a073dd1, 0xcc95a21d, 0xf4849a70, 0x88ac2dbe, 0xeca382d8, 0x6903f884, 0x7562c684, 0x67901a96, + 0x56d609cb, 0x92a99e56, 0x3cb23018, 0x5f7f3b22, 0xa7652d0b, 0x344345c8, 0xa6e42bbc, 0xd6e439b6, 0xa14c8fad, + 0x771b9775, 0x02f3ec22, 0xf3b792e2, 0x11cd5432, 0x777e2b82, 0x0c2dcc10, 0x46fd4c5e, 0x3cafdcf0, 0x6c6f53b9, + 0x908e3922, 0x4f1f5e8b, 0xd227f329, 0x725fb0eb, 0x9c65ef62, 0x26a31395, 0xc1a58d06, 0xc2aedf30, 0x7c58da66, + 0xe192a0cd, 0x7afa6bad, 0xa4f166e1, 0x50b42eb5, 0x4767afda, 0x8b27c6d4, 0xfa99ef93, 0xe0c1f610, 0x9b4ee209, + 0xd7d04b9c, 0x856421da, 0x02ca4570, 0x416b652d, 0xe42c5ddd, 0x37b03ad1, 0x8b96a71b, 0xb3445a1a, 0x39dfa79a, + 0x6d4f30cc, 0xc71e748b, 0x571ed8e5, 0x13c9a314, 0x8bedbfea, 0x79af3cf3, 0x6ec858ac, 0x5f905422, 0x63e6fc99, + 0x8c574241, 0xe58b5fd7, 0xd8f8fff2, 0x3a20108b, 0x1e3188c6, 0x2fe4c407, 0x583a849f, 0x1f64891f, 0x4ce011cf, + 0xe704a4c8, 0x45aee7b5, 0x11cbec54, 0xeed87d97, 0xae8d92f4, 0xfb872a94, 0x8bd555ad, 0x6035d007, 0xb0f54929, + 0x2e1866ea, 0x0efb20ad, 0xd3c310b6, 0x5e66d81b, 0xf208ffb2, 0x5c65408e, 0xeab1a6a3, 0x4ad938ae, 0x8f56521a, + 0x9e6292e2, 0xdf208c77, 0x7b51e545, 0x646e979a, 0xbfb70328, 0x0ba2ed9b, 0x2eb59916, 0x9ddd4faa, 0x90ad663b, + 0x3308cad7, 0x3c8e3c8f, 0xdfbc3edc, 0x70c9d788, 0xdb97d5d4, 0x720bb861, 0xa8da152d, 0x1b800c7b, 0x94c9aa4b, + 0x1d86c4fc, 0x94577838, 0x873d2d31, 0x30400d82, 0xd9331a0b, 0x98e77dec, 0xd3b620d7, 0x9328ca33, 0x07f5ccb2, + 0xe52e5ec8, 0x33f343cc, 0x4a46bd19, 0x21a72659, 0xbaaeb776, 0x05c34028, 0xafbf862b, 0x177b051d, 0x2f720a03, + 0x01e9938f, 0xe0b32d31, 0xf90e8062, 0xe697b9ea, 0x5426c393, 0x233c73d6, 0x1610be40, 0x74aadcd3, 0x0467879c, + 0x4835fcdf, 0x0317a131, 0xf7f85c29, 0x1d23b66e, 0xae29a7b9, 0xc3596064, 0xb95ca2d3, 0xf658c502, 0x38662812, + 0xd61233f0, 0x214965b0, 0x0ea50e54, 0xfddd7a3d, 0x1847977c, 0x37bf6ac3, 0x0ad3067a, 0x9087ec73, 0x61e710c2, + 0xcf8413d4, 0x617f1550, 0x236594eb, 0x60ae104f, 0x89f6cbae, 0x659fbb16, 0xaf652745, 0xe9cab32c, 0x26ea2787, + 0x1fdec000, 0x4c7d96ee, 0xf1254ffa, 0xdbf18b40, 0xbe31e293, 0x6aa6085a, 0x125b5ad0, 0xc5eeff7b, 0x47d0cb7e, + 0xfc413c9f, 0xf74201d6, 0x2a59b726, 0xb98010d2, 0xa0f59645, 0xceb6d112, 0xab67e831, 0x5836a165, 0x0a7ba9d9, + 0x66570599, 0x04db32a8, 0x8140c2ea, 0x115d5b16, 0xc554d73f, 0xb543540b, 0x029b7115, 0x2f563497, 0x01e39e94, + 0xdc22cdc9, 0x3a2dbe80, 0xf9f4ca34, 0xe9b696d2, 0xf8a7a16a, 0x7860f989, 0x414f7d07, 0x3756946e, 0x8658947e, + 0xa755d581, 0x24c35962, 0x3394e441, 0x4cbb5a0f, 0xe1b03dee, 0x3dc3c6f7, 0x65e784af, 0xc48a4a48, 0x1b69de9d, + 0x36297c3b, 0x47a0f11a, 0x028602d0, 0x9124fedb, 0x3bec36d4, 0x7de337a7, 0x1b162777, 0x726686f7, 0x6a506c30, + 0xdcb20bf9, 0x430f8ff0, 0x9f89a6bc, 0x8bba6f34, 0x3331f731, 0xbec13a80, 0xfe54ae9f, 0xcfbe6e56, 0x2bee2722, + 0xe46a2a51, 0x9a097218, 0x996f304e, 0x87078c7e, 0x86d27344, 0x684a31aa, 0xa43e1e2f, 0xb041e456, 0x1135f2fa, + 0x1ec78f85, 0xd7d54133, 0x65e9068b, 0xbb83826c, 0x9bb63afb, 0x88b6b2cc, 0xda324fb5, 0x9d183148, 0xda2dcabe, + 0xdfca4f73, 0xd4ed52ad, 0xc8895fe2, 0x160e36d3, 0x7fe226ef, 0x2f75f335, 0x669791d4, 0x744b91c0, 0x8dd69be5, + 0xfa1b53b3, 0x47857258, 0x9e5e9e6c, 0x5d40df93, 0xe4f27019, 0xa709cbd1, 0x8230f248, 0xcc8c2fe9, 0xf392190c, + 0x6107c38a, 0x3b64f41e, 0x4099498d, 0x4245381b, 0x61da1d79, 0xa6275699, 0xadc96727, 0xd1a8b0df, 0xde22239a, + 0x1663ab1a, 0x537ce950, 0xdbe29c8d, 0xd190fa72, 0xf3030a76, 0x7e2da46e, 0xc46bf9df, 0x8fc95f9a, 0x9f67bd51, + 0xa8924130, 0xdff5b23b, 0x020de032, 0x665e7929, 0x652bc346, 0x96ef14c7, 0x0d7d9ed7, 0x8380d5db, 0xb4413c81, + 0x7c0d36dc, 0x4c65e33a, 0x9e5311ca, 0x02c95fa8, 0x0bc314d5, 0x186871d4, 0x7ac96ba6, 0xf5269534, 0xdbb7bab0, + 0x455b060d, 0xed347b3e, 0xca5faee3, 0x5dcfb0e7, 0x8f9f0974, 0xf5c85bfb, 0x5620c545, 0x213341c2, 0x9ff3e5bb, + 0x6bbc5d07, 0x997f5f3b, 0x63125140, 0x6120fdb7, 0xd4bb4daa, 0x32daeb08, 0xb3dd3490, 0x5eafb338, 0x5f8ed94a, + 0xe7d289fe, 0x78208d59, 0xa8aced83, 0x62174cff, 0xbc47a62d, 0xba5afd92, 0x0661d23a, 0x5c7633ac, 0x33b7eb02, + 0xdeacded7, 0xe97b747f, 0xa1cb270d, 0x266d70c1, 0x8c91b8be, 0xf5e4e047, 0x8c98e431, 0x3b0007fd, 0x7f0d2008, + 0x03a30d8b, 0xd4e29d6a, 0xa4a1f089, 0x11dbd381, 0x3c31f107, 0x2ac3b1b7, 0x61a4ae11, 0x5a6ab098, 0xc4b5f7ad, + 0x91a9db39, 0x201fc027, 0x76974a12, 0x4957ba01, 0x5fc07ac1, 0x7f82638a, 0x3f87793c, 0xc9a0a0d8, 0x33540171, + 0x2801fb3e, 0x0454e62a, 0xce754924, 0xc071c198, 0xb7539e54, 0xdcdcbc47, 0x30574f98, 0xd043c0e7, 0xb66766f4, + 0x98f4f780, 0xbe48047d, 0x5b4a9805, 0xa76f6611, 0xa2dd7478, 0x9e37a597, 0x03b2a709, 0xe677496b, 0x4a0a13c3, + 0x8ad121f9, 0xa2e39b5b, 0x3b8fa494, 0xa21548d5, 0x23245247, 0x3b74acb0, 0xe8a15c0b, 0xad8d60f3, 0x63c49d66, + 0x88050c14, 0x7f09d87c, 0x503c5581, 0xcd3b68e9, 0xbc3aea6a, 0xc77ca4ac, 0xc155197a, 0xbd0a569a, 0x8e0ffd4d, + 0x64902f92, 0x724a1e56, 0x2717e23a, 0x340a6de2, 0xdd82a368, 0xcb5ccfee, 0xd2189a37, 0x188b3518, 0x8e003cf1, + 0x841648f9, 0xeb12b781, 0x2c11f81d, 0xa9a2faaf, 0xc43f7a0c, 0x540cf73a, 0xec81ac3b, 0xd84f8d79, 0xd1ebac78, + 0xd643f821, 0x38ee1713, 0x56fc88d4, 0x62e0fe7e, 0xb5e965df, 0x18c34010, 0x0a6d11ee, 0x3ab3f7f5, 0xc0559b66, + 0xf87c664b, 0x3f4f2523, 0xcbfe20e1, 0x90504b26, 0x2fea541a, 0xda77c81e, 0xe9d611be, 0x5cddf9fa, 0x7057255f, + 0xb786c889, 0x617ab408, 0xb4b568d7, 0x52954fd8, 0xb790b151, 0x111acc71, 0x52b23c42, 0xca80dd72, 0x8108cf83, + 0x44bb3dcb, 0x7bdb678f, 0x3b71166c, 0x56c6edc9, 0x682d1c1d, 0xd55da616, 0x798066cb, 0x95b4088e, 0x58519cb9, + 0xcf428d26, 0x7ff7a31f, 0x876a02a4, 0x424d42ae, 0x8af54128, 0x2352e1ad, 0x7c2b14fb, 0xe36cac1f, 0x6ebf308a, + 0xc9b80e19, 0x1def2118, 0x336f2e29, 0x64bbe746, 0x3f4ba11c, 0x6cef2e48, 0x78e62e96, 0x1ddca787, 0x93912f32, + 0x90851f24, 0x4ba61d2c, 0x5da0b608, 0x833c7317, 0x8c887c58, 0x908532a1, 0x5cdb4e89, 0x5e2ce665, 0xfd219d3d, + 0x103a44fd, 0xaf987fbf, 0xac5d8519, 0x97a0cde8, 0x6c748374, 0x97c1e501, 0x7ae35725, 0x9963a968, 0xee89468b, + 0xff062acd, 0xabe1e56b, 0x1bf6f44c, 0xe3101b5a, 0xb4669b97, 0xc9ff1810, 0x59cef704, 0x01556fcf, 0x34046444, + 0x4a88bf0d, 0x7bd657ba, 0x4f0c3009, 0xfef65aac, 0x9671cb84, 0xa623aade, 0x228f7e68, 0xa4b956a6, 0xf5076f9a, + 0x43539f86, 0x73a8d953, 0x50618454, 0x96d224b2, 0x0654d575, 0x00a77dde, 0x568d5067, 0xcbfb9820, 0x782af4cc, + 0xded70bde, 0x25161192, 0x93146b25, 0x1e248d09, 0xf6368422, 0xa7c71423, 0x53e4c609, 0xbadb0f30, 0x7bc99f50, + 0xf01a04c1, 0x43276ab7, 0x61a29198, 0x65dee34d, 0x9f5a968b, 0x708f87c2, 0xc243e442, 0x0ffc2878, 0xe3f7ec21, + 0xec1e8846, 0x881ddeb3, 0xb64e2f31, 0xac3bc8a1, 0x95d26aa1, 0x3c827205, 0x032c3cc3, 0x373c2799, 0x78e3ce84, + 0x5ff6bb97, 0x9b80c5a2, 0xf722c348, 0xaeabeb8a, 0x0c1dfe34, 0x5636a0b8, 0xf0402a13, 0xd461fa31, 0xf84bb897, + 0x77e47383, 0x88358a22, 0x41937b1e, 0x2da3f169, 0x5f989055, 0x50656bc8, 0xebc20463, 0x2c830f25, 0xb9200f17, + 0x784f728f, 0xf4b0f8bd, 0x524db953, 0x125b2be2, 0x0c793621, 0x47f911dd, 0xb7aeb33a, 0x6bf3ebc2, 0x09225cd5, + 0xcebf04b7, 0xc9c7dfce, 0x699bcfc4, 0x53d62a8d, 0x8b6593dc, 0xed3e8fa6, 0xef7025be, 0x76a74ea6, 0xd2fe365f, + 0x4152be87, 0x31a5bc1a, 0xf2d71f12, 0xc2130072, 0xe74e8b47, 0x911910ba, 0xc952cab4, 0x5de00520, 0x4da51622, + 0x0bc80964, 0x30427f77, 0x2ee5b9d6, 0xaec90ed4, 0xfcaf3123, 0x3ec577b4, 0xf855acb7, 0x7f9e67c8, 0x8706a63c, + 0xe682e083, 0xf7cff5a8, 0x8edcc201, 0x3a4da171, 0x02cd37ce, 0xcf4bb417, 0x32ddf93a, 0x5114a6c8, 0x1eba4da5, + 0x89004ce6, 0x4c1b3773, 0x199c5d6e, 0x35cdc418, 0xf1d834dd, 0x31ceadd7, 0xd9c7190f, 0x29b0d157, 0x1742f8a9, + 0x9be16d95, 0x20eecde6, 0xf3489ac5, 0x41330e0d, 0xa97290d2, 0xba9b0b26, 0xb9b74e08, 0x07e5ce63, 0x060f77ea, + 0x55cbf8f0, 0x6ad35afa, 0x3e4ed10a, 0x5a3732f3, 0x447427c9, 0x7bd1ca41, 0xb2a1c347, 0x493b3cc2, 0x5fb5f22d, + 0xf81649b3, 0x26eeaee0, 0x8015870a, 0x27caf072, 0x26814739, 0xa4cf9fbf, 0xe4dae0c5, 0x070f250e, 0x6b65c3b6, + 0x59e2b90f, 0xa08e2839, 0xf376c02c, 0xc8b88dfd, 0x27b96575, 0x8296856d, 0x26e0a26f, 0x4d0f64a6, 0x606905fe, + 0x64039a3f, 0xc4aee5cc, 0xe821384a, 0xc9d95720, 0xe74295ca, 0x98bf5527, 0x9427d6b6, 0xafa6a802, 0x550e3faa, + 0x0794b75c, 0xd9e27ee6, 0x3d42ced7, 0x3a2dd314, 0xfb6d9d20, 0x28f0e6ba, 0x4e6ad441, 0x22ac5ad8, 0xfbf49355, + 0x97c4252e, 0xa3cee552, 0xa7c1d2ae, 0x7c2412c3, 0x3fce8aa3, 0x1033b81a, 0xb82e9bd6, 0x35d1e094, 0x811abbc4, + 0xf5cd7a9e, 0x8c639b0f, 0x0053a33d, 0x4e5ed3da, 0xdb7c428c, 0xcef56724, 0x983be3c2, 0x0e4a4986, 0x579386be, + 0x1b7f0a23, 0x1864ad10, 0xe04f3121, 0xa8e791ae, 0x713552f7, 0xd48d0959, 0x9a658470, 0x941f81e4, 0x54a55ad2, + 0xf525bdb0, 0x09a01a99, 0xcffa95c2, 0xad9c0967, 0x09353e8e, 0xf534d164, 0xfae0e519, 0xbcf2a0eb, 0xbcfa6686, + 0xebe27c43, 0xc0eedce7, 0xba2e0092, 0x22d573f2, 0x289c6bed, 0xdfde9289, 0x14b1b6a1, 0xf0156b05, 0xea13f8c7, + 0x8843b20e, 0x06defbf9, 0xf3810560, 0x74c2c5dc, 0x94a20916, 0xc525663f, 0x2afa3c28, 0x53c61afa, 0xe343be72, + 0x8b41bde6, 0x4ceba978, 0x4a11b0f0, 0x176336fe, 0x2ca5d87b, 0x7f4a4e1d, 0x3b29b59a, 0xf6724b53, 0xef70f434, + 0xade9a086, 0xf64cab61, 0x3f310201, 0x87fda615, 0x1d9beb58, 0x5a9b468b, 0xdbcf045a, 0x5c8b1217, 0x95705a79, + 0x46592b7e, 0x6ee7a5dd, 0x1147cd13, 0xe86163ea, 0x3fc6f6aa, 0xfd068d2f, 0x6eb0677e, 0xcf8a506a, 0x19f1f073, + 0x3fdaf3f5, 0xa3d7ca4f, 0x9e3d55cd, 0x29d0c0ef, 0xeee7546b, 0x8509afda, 0xb6e6e604, 0x1b1b0833, 0xb803f3ac, + 0xe8d11cdb, 0x9ead731a, 0x6dc1c9c5, 0x4d8258d7, 0x80d923a9, 0x1825370f, 0xf0a96651, 0x2a23a7b5, 0x649eccd7, + 0xe78544a3, 0x6d485079, 0xe1f9904f, 0x2107b329, 0x3b8dda12, 0x44a8f9c4, 0x97d721b5, 0xfd0abe7a, 0xe0b2a57e, + 0x505eb1b7, 0x3dd453b2, 0xc1053542, 0x52d47fa8, 0xc8f56d08, 0x20e0c824, 0x3c87c5c3, 0xdab4ae63, 0x516f7121, + 0x1f3454e9, 0xb31ea11c, 0xcbbb9046, 0xdd6b3028, 0xc3ce5219, 0x1b83e1a3, 0x46327e63, 0x784fc309, 0x2c9baedc, + 0x6ecf8b70, 0xb77e6a73, 0xc02ff749, 0x65819814, 0x93399618, 0x4927270e, 0xa766c643, 0xdf0ad0b6, 0x1b6b6119, + 0x666cdcf2, 0x43606ae0, 0xd6a68954, 0x5f40cf93, 0x4de08825, 0xfc5b1a45, 0x696c2030, 0x1ea39efd, 0xa49f63f2, + 0x10bac2d0, 0x624f2264, 0xdc6a9c6d, 0x9252666e, 0x4e69b80f, 0x2cfaa1e1, 0x4dabc549, 0xd52d96c7, 0x637b9f09, + 0xc8602cf7, 0xb416b89d, 0x6aec7704, 0xd05e4555, 0x6614d7d5, 0x680572f5, 0xd68479f2, 0x8aa0f2f4, 0x6d596354, + 0x6edc90f8, 0x8e33fbf0, 0x1e736ed8, 0xc45c715d, 0xb734379f, 0x5ad21e4f, 0x289988e3, 0x9d41b0d5, 0x57910dbd, + 0x3991a409, 0x064715c2, 0x29d9281a, 0x997e740a, 0xc558fd95, 0x15ef7ed0, 0xc144b0ea, 0x006d66d9, 0x2154e606, + 0x0d495689, 0x97b9dcd9, 0xad70bfdf, 0xf401769e, 0xf7bbbf92, 0xebbbb98a, 0x19437870, 0xa58be5fb, 0x0afb4298, + 0xb41922ed, 0x95bb1361, 0x7c39592e, 0x88c1b6ad, 0x6e140218, 0x9634f2ed, 0x059770fb, 0x66c8c479, 0x38de28b7, + 0x10bb7e9e, 0x3ae65a01, 0x4c9f7de6, 0x399ab361, 0x125024ab, 0x75ee8b48, 0x38cec998, 0x03bbba46, 0xe3eaa0c0, + 0xcb00f608, 0x0944595b, 0x1a8ff2c8, 0xd6a093ab, 0x346a9034, 0xe526f17a, 0x43357f47, 0x8d0d6c9d, 0xbfb4418e, + 0xba16532a, 0x436f42f3, 0x7925d9a4, 0xea559bbb, 0x3c4e3950, 0xbde9661c, 0xf492106f, 0x072a746a, 0xe7517443, + 0x5c5071f5, 0xf79cce98, 0x17180ce2, 0x40139d36, 0xcfde5e54, 0xdf6e8016, 0x036ac476, 0x2778fb0b, 0x51802cb7, + 0x4083a7d5, 0xfc41106f, 0x74197e98, 0x04c2372d, 0xaf81574f, 0x7c6bc408, 0xbc3d49ec, 0xcf864c2b, 0x84611a09, + 0xb8fcfeea, 0x3fe5a5b9, 0xa824c835, 0x0e17e837, 0x4c02013d, 0xf709d85b, 0xa6d92206, 0x259f0631, 0xc2078f8b, + 0x2078a027, 0xc3ab44b5, 0xf829ea87, 0x72e5ab5b, 0xb2abd1fb, 0x48a91292, 0xfb2025e6, 0x84eb159c, 0x1b07e2de, + 0x1e1481d2, 0x49b89fcd, 0x492b9600, 0xd0c97193, 0x226ae814, 0xbe455dad, 0x1fb18101, 0x7116d2e5, 0x0ba937d8, + 0x0701ec74, 0x7d09aa39, 0x7d65a6a6, 0x3aaa2417, 0x95d95f0e, 0xeaa307dc, 0xd996aabb, 0x76799907, 0xc1f7ecd9, + 0x7d9ae87c, 0x1f060802, 0xc6b3895c, 0xa54f3e09, 0xd75a3519, 0x17451acc, 0x0eae156f, 0xc626b814, 0x173b298d, + 0xfd423236, 0xfe96ab18, 0x612780c5, 0x6553f2ac, 0xe2aefbe0, 0xa5710b36, 0x0ed9a510, 0x64b75447, 0x8f0f6841, + 0x569882ee, 0xc4d56d42, 0x2dce57a6, 0x2704563e, 0x922d1fa5, 0x924c36ed, 0x8a03599c, 0x268cd366, 0xf2cd85e2, + 0x5619f5b5, 0x73e6db0f, 0xe657d82f, 0x09f5a832, 0xe38c3da2, 0x13a90d29, 0x9f6acb32, 0x1b23eb06, 0xcb8057cc, + 0xca88d0ac, 0xc60ec845, 0x72ab98dc, 0x40d92c3b, 0x73d02395, 0xaf4d786f, 0x68619a59, 0xf29ed981, 0x06f8ecad, + 0xe5bb7c14, 0x6b01b9d7, 0x372a1daa, 0xc20d035f, 0xaa4b3664, 0x42bfbca2, 0xf0806add, 0x5a742dd4, 0x9f41b1a4, + 0x120582bf, 0xb760ac93, 0x77f35060, 0x7540549d, 0x1a3680d9, 0x425cc9fa, 0x3d8440fe, 0xf30cbe30, 0xcbb2e9dd, + 0x152bb087, 0xae686c1b, 0xedf8b073, 0x3c1edae9, 0xc908e933, 0xb2c16d1d, 0xd1d0e545, 0xe949ae22, 0xddd6249f, + 0xcfb4dbe4, 0xa34223af, 0x11ea6282, 0x3adebc41, 0xf2c5b7fd, 0x452baf73, 0x414bee3f, 0x56b1fb22, 0xe3d8ad26, + 0xe72bef0d, 0xe7cd2707, 0x5774382c, 0x42c54f34, 0xc5181457, 0x0e923cff, 0x8b196824, 0x2ff5b4a0, 0x031036a2, + 0x45bde36f, 0xfdee52c6, 0xf9095613, 0x3fb67bee, 0xbe6465ea, 0x0ba8a760, 0xf7a9d93e, 0x4bda4336, 0xf5770601, + 0x16f69cdc, 0xc378d999, 0xc61280a2, 0x7270c155, 0xabea3578, 0x44684814, 0xd5470471, 0x27eb9d69, 0xbd086a49, + 0x2e22e7a0, 0x56e2e69e, 0x80f8c059, 0xd91c2295, 0xbf07eef7, 0x496557da, 0x4d167e8e, 0xeda5f32b, 0x3b4317f9, + 0x30d47f36, 0x6e76b628, 0x3a796994, 0x8cc516f4, 0x1ae1a914, 0xe3e7af6d, 0xdf5801c8, 0x7f29e222, 0x739c8473, + 0x9d26e2f2, 0x62ab6f03, 0x2ee83261, 0x445a3b4f, 0x7e3dd463, 0x227f085d, 0x6c6ebe93, 0x7c611bf4, 0xbeff367b, + 0x92cd4d4f, 0x86631148, 0x6b5b5638, 0xcb5ecb89, 0xee365ff3, 0x84f98343, 0x8fb32d96, 0x6b0d5542, 0xeedfe4eb, + 0x26e42725, 0xd2ebe8bc, 0x8ebc7f4d, 0x7f6b3fdf, 0x74197d5e, 0x273896a6, 0xf2cc9064, 0x29f327bb, 0xbd68cf1e, + 0xe47c78aa, 0xd4888df6, 0xeee8aef7, 0x7f1c97cb, 0xc576dbe0, 0x9b7161c7, 0xf5a0beb3, 0x356130c3, 0x5a7bcb3f, + 0xbb20c75f, 0x4fe11ad8, 0xa47aa7d9, 0x673398ef, 0xe03a56a7, 0x4e8782d3, 0xa913ee9f, 0x5b07febe, 0x12bb3901, + 0x621176d0, 0xb54908be, 0xf294c0ed, 0x44f3752a, 0x8e057265, 0x9657cdbd, 0xee5249d1, 0xd499bfde, 0x6e77df21, + 0x8844e3c9, 0xe5952548, 0x3f518316, 0x78dbfe26, 0xf02bb8c7, 0x45dd5ef5, 0x47e90382, 0x2b0eb494, 0x7120ce12, + 0x08d479c4, 0xe2545e6b, 0xdd58caaf, 0xb6a1a891, 0xb0a97448, 0x1b43e248, 0xf014a1c0, 0x1a2af9c1, 0x8c5cb90c, + 0xd3a8dc8b, 0x3189cfca, 0x3adf4165, 0xdbf9bbab, 0x88231419, 0xc14449d7, 0x6f98751d, 0x31ee3dbd, 0xec396c31, + 0x808050d2, 0x87639543, 0x97cac2b3, 0x471fccdb, 0xcc78784c, 0x053b548a, 0xf6387052, 0x1bc3512f, 0x701e1a4e, + 0x0e352e50, 0x79f42697, 0xa55059fc, 0xb75818d1, 0x33e8bcc8, 0x9e67b847, 0xd125c31a, 0x4e903526, 0xdb68fad5, + 0xbbd8a22b, 0x7832fe84, 0xad7d83b5, 0x1e0a7cd2, 0xee8ff2de, 0x6137c620, 0x2f2baf3d, 0x9085ecae, 0x865c683a, + 0xfa796bdc, 0x7ddd8d3c, 0x824ce956, 0xa8a9db1d, 0x82bda604, 0x1419efc1, 0x70f90c75, 0xb7e42ac1, 0xcf25e006, + 0xc7d5a035, 0x9fbd6d69, 0x7122e4f2, 0x3e43a839, 0xaacea12d, 0x6f597ebf, 0xc393f0ad, 0x07285e7c, 0x436dc54d, + 0x722fc683, 0x99470f24, 0xb144f666, 0x92847a8f, 0x82c8555a, 0x5f9265ec, 0xba579bf9, 0x5094d996, 0x728ba9f8, + 0xab3d85b0, 0xb0e557a0, 0xec0ca744, 0xa8c05ca6, 0x95f45040, 0x476f383d, 0x76317315, 0x0ed3aa84, 0x786566bf, + 0xa6035707, 0xb7cc328f, 0x962f91fb, 0x40904e19, 0xc6457788, 0x620087e9, 0x5f4542a8, 0xe32e265f, 0x456fb6d8, + 0x16360543, 0xcfdca45d, 0xa707f724, 0x8c516b11, 0x6f090b87, 0x2b07dd08, 0x3221cfa3, 0x75a93073, 0x98fef37d, + 0xbd52bc06, 0x91377ab0, 0xc234a244, 0x4c954a4c, 0x052d0f3b, 0x6f294ea8, 0xa5f7fdd6, 0x8b7e6651, 0xa0ab03d1, + 0xe5383372, 0xb69fddf9, 0x29db50ca, 0x5a37b2db, 0x20308525, 0x7c102add, 0xcd2c99ee, 0x0524ac7c, 0x1065459d, + 0xb2531e8e, 0xd323003e, 0x616f5e00, 0xe90449e4, 0xda44cc72, 0xada1d5cb, 0x1ec3936e, 0x69170e95, 0x55040c9d, + 0xf1df6b16, 0x76f29a5d, 0x6b824dc6, 0x0c6a8991, 0x8e54694c, 0x7588babb, 0xc9247c37, 0x1e225916, 0xdd3fd939, + 0xae1ae7ee, 0x64d9e0a6, 0x630e1fa4, 0xed585db5, 0xedada0f0, 0x6570edf9, 0xb9097f10, 0x4de56161, 0x03f4515a, + 0x36f46d12, 0xacb92848, 0x8e97ff6e, 0x11278c92, 0xa3f02f37, 0xd08bdbd1, 0x2970cca5, 0xe4ad769f, 0x56f6c389, + 0xe1e70844, 0xc3f5d5e7, 0x10dc3a56, 0x0bfbb7ae, 0x419ea58d, 0xb597ebab, 0x8a02772d, 0x92d7dea2, 0xaebcee72, + 0xd7a97e43, 0x9d6253ec, 0xbb36c725, 0x2302bd2e, 0x4b709cae, 0xdb032424, 0x04abc7bd, 0x26801172, 0x5fa44c98, + 0x3b9392bf, 0x69c65530, 0xdfa904fe, 0x22a88a26, 0x73d3940a, 0xa11849db, 0x199dfe51, 0x93a5d5d9, 0x93b5fa51, + 0x97a85091, 0x5ac03b0b, 0x5bc66feb, 0xc124abb3, 0xe66f0727, 0x48836aae, 0x5b40469e, 0x609dbd51, 0x6b0eeeda, + 0xd22755ce, 0x9cfdaffa, 0x9bb1e133, 0xa78b6ec2, 0xdd77c40f, 0x92546b27, 0xa9af3e85, 0x036f0707, 0x4d34159b, + 0x9e40fb98, 0xec3f3515, 0xfe4ed20e, 0x8fdea02a, 0xdc916d27, 0xf9a3c2b0, 0xf44de11a, 0x557472cd, 0x7c3f2f52, + 0x7c2568df, 0x8f202719, 0x399cd15b, 0xdcb31634, 0x2ab285c2, 0xbe21bef1, 0x8288b42d, 0xb0e36253, 0xbdb0a9e7, + 0x73ef7e1c, 0x5d94d2b2, 0x193f2387, 0x6b93f183, 0x3c5ab5b4, 0x8678f90b, 0x21024769, 0x5b4aa837, 0x2f28ba3b, + 0x96e3973d, 0x6f5c053f, 0x4e41018c, 0x1536eb26, 0x70c51812, 0x165ea757, 0x33c2ee04, 0x0836ce4e, 0x2e449c00, + 0x7e0d107c, 0xce903f97, 0x0479c0ea, 0x718bfc53, 0x3cfb3199, 0x6fd3215e, 0x5d0186d3, 0x12a0f355, 0x66451e9e, + 0x6f3e3438, 0x6c36ecdd, 0xbdde7886, 0x0d79f58b, 0x67a2eb5a, 0x250b1530, 0x57a2759f, 0x7351498c, 0x1bbcccc4, + 0xc50cf0d7, 0xd2292b31, 0x1da102ec, 0x2dcd6d17, 0xb155afce, 0xea937fbf, 0x949033cf, 0x7a4b469d, 0x08a843cd, + 0x864bf085, 0x2d2e60ed, 0xf903965a, 0xb1b84475, 0x7caaaf81, 0x0e9a3ba4, 0x95682f99, 0xee30755a, 0x9d2b39b2, + 0xb9b7a8fd, 0x5b84fd0e, 0xf2d14cf4, 0x25200910, 0x36e229a8, 0xd40f91c4, 0xff3eb310, 0xa9646652, 0x8f3cfe1e, + 0x1ec4a6f7, 0x3f123be6, 0xa091c31d, 0xd2058374, 0x6ad8ed0c, 0x9221a765, 0xe215ebd5, 0x74f81981, 0x40ae34eb, + 0x51eea14a, 0x4a031e0b, 0x74a9b1fb, 0x12d0af67, 0xc79c0182, 0x9665e703, 0xdea58fde, 0xa2fe13db, 0x634310a8, + 0x51c64008, 0x9a656082, 0x78eb8ae4, 0xc76bbb63, 0x9d1ac0b3, 0x32e5afcc, 0xa4462bdb, 0xe1811657, 0x064b6a4d, + 0x17e7cb17, 0xb8f6483b, 0xe31d5356, 0x5067a6c2, 0x30d59fb7, 0xeb2af55c, 0x7470999e, 0x08e6ebfc, 0x5dfd295f, + 0xbb1d3954, 0x66131091, 0x38c916c9, 0xf88687bc, 0xc1a76df3, 0x5dbbcb55, 0x5dc241c9, 0xa13a59b3, 0x8efa0592, + 0xbcf5d63d, 0xf4cbea70, 0xb0fb1996, 0xa5c3c86f, 0x8dde351c, 0xdb13e971, 0x08c240ff, 0x35f74da8, 0x7c7246f2, + 0x12d443e9, 0xf6fb89d9, 0x4b76e6db, 0xd358a81f, 0xd544d084, 0x2926736d, 0xa977c51b, 0xf1a20d31, 0x20ddb5f8, + 0x8785bc58, 0x0a4724e4, 0xd19b46ad, 0x022a04ed, 0xcf1f38e6, 0xbb6d6829, 0x7b7aba3e, 0x393108b9, 0xd833a1cd, + 0xac587140, 0x4292f92d, 0xccd23b46, 0x9cd276ce, 0x59a25f25, 0x0c06c26b, 0xd9d72034, 0xb2ca03e0, 0x575fd8c5, + 0x4402780d, 0x23b3d06a, 0x04b47df9, 0x898c8faf, 0xf3fc40bb, 0x2ce2f5dd, 0xa7062fa6, 0xd3916e76, 0x6f798f89, + 0xa9903a1b, 0x8d98d3d5, 0xc48e8725, 0x8e7796d1, 0xc8332c6d, 0xf34509ec, 0x24a03dd4, 0x5ccb6ed6, 0x3e7411cc, + 0xfb307540, 0x531e636a, 0xce85d5a2, 0x0191249a, 0x8fb41e36, 0x5bf0c2f1, 0xe3cf6dee, 0x41df9acd, 0x9263cf76, + 0x65e69df8, 0x6b4385b8, 0x2a84bd15, 0x70dbb2c7, 0x2003f1cc, 0x8caaa4e0, 0x8526e50b, 0x9d8bf3b8, 0x0738e40f, + 0x8a84784f, 0xa7ebe689, 0x77f37e28, 0x0242ad50, 0x28714f07, 0x8f31e568, 0xa6c749e7, 0x5d3cbcab, 0xe14fcdf8, + 0x2e762fd0, 0x955e68b6, 0x1e674f59, 0xec4f53a5, 0x6babca1c, 0x60b1d90a, 0xc904453b, 0x920fcca3, 0x7a4c4a38, + 0xd542766a, 0xefb3ad6f, 0x9cc1f05b, 0x4fdc48f4, 0xfea5ec4d, 0xbc832850, 0x542388b7, 0xc73244fe, 0xbace286e, + 0x9f0998a6, 0x014573b8, 0x2054927d, 0xd6501e0d, 0x113a6379, 0xc0e2dd22, 0xec647c8c, 0xdb1b306d, 0x8c9f54d8, + 0xc8dd5551, 0x864057da, 0xe5bb0e7c, 0x70526d27, 0xc95a1ba6, 0x3980d759, 0xddb6bc18, 0xa2b3663f, 0xf67acd3e, + 0xaba8c13a, 0x603cad93, 0x680eb7f2, 0xc480319e, 0x1a6919b5, 0xd21d89d2, 0x9d9d8652, 0x855f672e, 0x1c639e9e, + 0xba5ac5fe, 0x39dbba5e, 0xcc333e24, 0x6944f582, 0xd8a4902f, 0x6f8332b3, 0xf7806363, 0x31eb56e0, 0xecd0f5b0, + 0x7df3e01c, 0x98d5e763, 0x0a3f6ae4, 0xa29d449b, 0x5cd59da3, 0x642bc5eb, 0x48aadc04, 0xd3027b97, 0x9beb4b25, + 0x7d9c90a5, 0x7df398fe, 0x7fc308de, 0xd47cd443, 0x9036f2a2, 0x76c0ae27, 0xeb21d09f, 0x17b70ed3, 0xe961edb0, + 0x88899dd4, 0xd21c3098, 0x911d22e7, 0xa7f7ce77, 0xa1c42658, 0x9aec8123, 0x46b9bc7a, 0xd6b4bf83, 0xc000705a, + 0x44eb6be9, 0x48b0a6ab, 0xcad2754f, 0x3bef7feb, 0x34f918a4, 0x1532838c, 0x727d7deb, 0xfe7b25b9, 0x8f1c5968, + 0xc157a5ac, 0xfa3bc6f3, 0x7895db45, 0xa0f8861f, 0x7cdcb522, 0xff6995b8, 0x2dc82c8a, 0xe919a66e, 0xb071155a, + 0x798e5996, 0x4e5c3a9e, 0x63283ebc, 0xbef3b5b6, 0x231ead5f, 0xc40123f3, 0x6cf8f805, 0xdab1f191, 0xd8f5e271, + 0x3cf1df33, 0xce704797, 0x2f141b72, 0x3f82ad66, 0xe8432e10, 0x990824de, 0xa3418ecd, 0xaee874c0, 0x7b3543cf, + 0x0a5921e6, 0x67ab5547, 0x35d9d1be, 0xa1d98038, 0xb9b9764c, 0x525e6c3c, 0xf370b872, 0x528627a1, 0x7fc0dd54, + 0x9c7e6c8b, 0x9108d3d3, 0xde9b1309, 0xbe70f476, 0xba2a3bf2, 0x6060c949, 0x32d524e9, 0xb9bb96e6, 0x026d5520, + 0x8292a5fd, 0x66adaa84, 0xfb0f4882, 0xf51d475c, 0x2281a06e, 0xcf777bf8, 0x21ccfb4f, 0x3f8297dd, 0x53b71004, + 0x3c5ac66c, 0xc4bb5fcb, 0x59aa7cc7, 0x446dd024, 0x62257d7e, 0xa2cc8052, 0x1840d81b, 0xc69d2b61, 0x67389df3, + 0xec7ce4aa, 0xccc1e883, 0xfa683d7c, 0xa0e58975, 0xf757680a, 0xd920fb5d, 0xaa4e7cf1, 0x06f7b75b, 0x0036c2f5, + 0x10abdf6b, 0xa8a12158, 0x4a587135, 0x31afc344, 0xfc2695c3, 0xcfacc2ba, 0x00edb3cd, 0x9ac7fe21, 0x88d063b7, + 0x06f8e913, 0x80809584, 0x04fd9c29, 0x4fd5edc4, 0x7314ef1a, 0x0e0e59c9, 0xbe12a848, 0x32788706, 0x95e97387, + 0xbb2757ca, 0xa0605d75, 0x80eb139f, 0xab27f542, 0xd6a108c6, 0x1b551423, 0x3847a8ee, 0x4b152964, 0x65e24d77, + 0x85bbe801, 0x3cc9c82f, 0x8e852c02, 0x0e5328b5, 0x745d8037, 0x2d4e10a5, 0x9a554b9c, 0x10353775, 0x86ed4a95, + 0x4f898d1b, 0x7f098dfd, 0x4f18dc99, 0x80aea336, 0x02228603, 0x94b8141b, 0x59c2b295, 0x6d6c5730, 0xc8e0cd37, + 0xa074d70c, 0x34faaa12, 0x8c26e8c8, 0xacaee10e, 0x84270171, 0x899cab58, 0x86a7fe0c, 0x1aedec37, 0xc890518e, + 0x97867443, 0x3db56e92, 0x17e1867a, 0x54b691ce, 0x4de1dd00, 0xfd44b556, 0x07686e6a, 0x31b371c7, 0x97c60ae3, + 0xf475d032, 0x24615368, 0x6da45d71, 0xbad5fd96, 0x0a373702, 0x26856fbf, 0xdfac7f37, 0xdc92f858, 0x5cd99e8e, + 0xef5a8b3e, 0xbd40f8f7, 0xb95ee6ed, 0xd29b0c90, 0xaf378ec9, 0xe12fbf55, 0xce7a828d, 0x1ce0c42a, 0x6d55ca83, + 0x23b9ec5f, 0x1e92721e, 0x4427930d, 0xe64c6e25, 0xa26ced18, 0x68a5a8ae, 0xcde745dd, 0x89f7d651, 0x0cf0b5b1, + 0xfdd6838b, 0x02db3e2e, 0x5963147e, 0xdd394747, 0x7ad6e12d, 0x036c005b, 0x5f5deb72, 0x1792cacc, 0xa4a70c11, + 0xea60f625, 0xe6eebe3a, 0x44a86d7d, 0x18f4a02c, 0x997ba732, 0xa8b82327, 0x1fd6b5c3, 0x161d5492, 0x5d636812, + 0x3a386476, 0x05049393, 0xdf4e617d, 0x38664eda, 0xebcffa60, 0xbf65a689, 0x210882be, 0x8bd4f5f4, 0xd9d58d4c, + 0x984809bd, 0xd32feb3d, 0x134ede60, 0x2c440c04, 0x9881e80d, 0xc9ea1be3, 0x1c76ee22, 0xf386c621, 0x29dc9a28, + 0xd01603c8, 0x4e9bdfd0, 0x67789c0b, 0xc48a4f2c, 0x8af1ada6, 0x3daeb869, 0xd5e0e541, 0xa5e668e7, 0x6c3181e4, + 0x0ee1019e, 0x1e8cc67d, 0xa71e540e, 0xd12f2335, 0xf3c46547, 0x0b61edfe, 0x4ec0eb85, 0xa85c8e8b, 0xe9e79983, + 0x018c3213, 0xb8fd4e40, 0xd9e69df3, 0x75da9b97, 0xb3b9802d, 0xf9ee6683, 0x909bbee3, 0x62a0f59a, 0x3b1e13af, + 0xdb497568, 0x195be935, 0xdfaab4fe, 0x13cae585, 0xeff3dc79, 0x9d5befe2, 0xc95a339b, 0x0e8a2e55, 0xe05dafd6, + 0x9fa6cb8d, 0x50645a58, 0x7131e379, 0x263beda5, 0xdd1c371e, 0x4e8033c5, 0x65559f9f, 0x4d3f9885, 0xa8f54940, + 0x505d3914, 0x80c10c3c, 0x9130a202, 0xd767f218, 0x79c70bb9, 0xe60fa4be, 0xf8f09ce3, 0x7c44e14d, 0xe7287f06, + 0x91b02282, 0xa45c5a07, 0x67b3518d, 0x98b1df39, 0xeb70921a, 0x82cd3f53, 0x74c85cca, 0xb560ac89, 0xeeae1dd5, + 0xc2a6d156, 0x4bc21405, 0xeca417eb, 0x14b42e82, 0x4e52ea0f, 0x422e20d6, 0x691c1e6d, 0x4ab1176d, 0x5113f226, + 0xf434ee42, 0x5f7700c0, 0xcae7d07d, 0x4028807d, 0x06e960d5, 0x4ae651ce, 0x762b6a2b, 0x1da64ca1, 0xd699a10a, + 0xf7088c9d, 0x257f3a34, 0x33fb63b6, 0xb58ef078, 0x79afd07b, 0x5a5d7687, 0xf59c285a, 0xe935b34c, 0xe20d2821, + 0x9d3e7f4a, 0x930092b7, 0x024db645, 0xed772888, 0xded9a029, 0xfd344acf, 0x35f51f60, 0xc6d5ed16, 0x40b419df, + 0xb50d45e6, 0xe76aa41b, 0xa73494eb, 0x94046e7d, 0x7beb3505, 0xfc356c1e, 0xf907bab0, 0xb1fc57a7, 0x341c6648, + 0x2248fb81, 0x8230dd69, 0xa0757207, 0x8d592f8c, 0x59973dec, 0x1a5fc22a, 0x98113a5f, 0x8d6e8b45, 0xc1b0c79d, + 0xb1332f3c, 0x94ea0422, 0x98e5125f, 0x811c77a7, 0x76c7b885, 0x79845693, 0xaef9a367, 0xad9a70c9, 0x1c40d7bb, + 0x861d7724, 0x2f7a566b, 0x63861983, 0x370786c1, 0x1fa14b30, 0x08a174ee, 0x9f6521ff, 0x3496e246, 0x45583703, + 0xf2767019, 0x7f7e88e4, 0x324edeff, 0xcde2c012, 0x73e8a30e, 0x3541896d, 0x94958cd1, 0x2e233df4, 0xb29173db, + 0xa609c0d7, 0x45628973, 0x95c99217, 0xa1867bfc, 0x71882e2e, 0x4c86a93b, 0x4536af01, 0xe22fe5ff, 0xd0bfdaf5, + 0x88c8cec3, 0x04b6b19c, 0x3adb0902, 0x902c2d95, 0x5a7b7875, 0xe2c9d6bb, 0x1e82b985, 0xc7500fb3, 0xfcc96f85, + 0x3da015ab, 0xfce1189f, 0x0aa130c6, 0xeda5553c, 0x7b8254cc, 0xdcbb9299, 0xd0fd6f67, 0xa049bfee, 0x47a47f8f, + 0xfb86ed08, 0x38ea3e69, 0x3688c3ad, 0x334f2d60, 0xd0521a37, 0xe89c6d85, 0xa34bf31b, 0xc2e3114b, 0xae49fa6a, + 0xaf5a8883, 0x3a55afc0, 0x75524da6, 0x6db01994, 0x745ac682, 0xf2f369fa, 0x65063eb1, 0x485c2733, 0x4547d9a6, + 0x95fc7816, 0x7070d700, 0x3eab1175, 0xf59bd1bd, 0x1bcedbde, 0x2a1d2e53, 0xb5eb3120, 0xb6707188, 0x5aeeb76c, + 0x4877e634, 0xa9dedad3, 0x19879f29, 0xc90ffb7b, 0x4c71512e, 0x9d732f55, 0x6d65064f, 0x71e0f0ce, 0x9ddde721, + 0x7cf4704f, 0xdb7cfe68, 0x2f4c8d1d, 0x31a12e69, 0x0da33b1d, 0x84812003, 0x6a3fefc4, 0x50859ddc, 0x475a4117, + 0x7589eda5, 0xdfc2e04f, 0xe36af60a, 0xac9bfdbe, 0x13b667a1, 0x8af6a3a9, 0x3814167e, 0xd0fba79e, 0xd6d63b79, + 0x3fd2e2ff, 0xad0e0c04, 0x7c6ae49e, 0x6cf93eaf, 0x27764da9, 0xef59746d, 0x6e982527, 0x0105bca9, 0xd4b7da9f, + 0x38e7601a, 0xbd24516a, 0xb4b6b113, 0xe84e9d03, 0x214b3c46, 0x0414d245, 0x6213f418, 0x0b8ada13, 0xb50c4997, + 0x56fe4e98, 0xf8535775, 0xf4a1b671, 0x057cc1e8, 0x852ecfd6, 0x87508343, 0x7514a0bd, 0x636e6e46, 0x9439108c, + 0xfe36a929, 0xebbea85d, 0x4ce86ea9, 0xfacb5e29, 0x2093bded, 0x768d092c, 0xe6d2b01d, 0x78b826fd, 0x99c031d4, + 0x7fe957be, 0x3abf998e, 0xc94b819a, 0x02bcbd15, 0x9476e6e6, 0xb2278f50, 0x9539c28e, 0xc15c2282, 0xc4258ae2, + 0x30af1bc1, 0x12e2aff4, 0xbb00583f, 0x250c56ff, 0x66bce7f5, 0x40bedb49, 0x6ca53deb, 0x50e5fdb6, 0x23093ba8, + 0xb845c0d4, 0xe5d4aece, 0xc9438681, 0x7ba8032c, 0xa0515b0f, 0x3eda979c, 0xa2c3fea1, 0x4ef3c7fa, 0x9db34fdf, + 0x6e1011b1, 0x129a7979, 0x9c63c783, 0x87acf0ea, 0x6579ef17, 0xfef30b6e, 0x0c98e92c, 0xcc2f1aeb, 0x870cdad6, + 0xf20f08c2, 0xe7cdc851, 0x4500c67e, 0x48f2011d, 0xd5abfbd3, 0x556a7213, 0xef2bfa01, 0x4d125c92, 0xd75e9ff1, + 0xcce2ad2a, 0x58db1425, 0x251bcb91, 0xc0630b10, 0x0e0029cf, 0xa62233ec, 0xdb52b062, 0x31901fa1, 0x1b56ab3f, + 0x66f45ff4, 0x77070b5b, 0x165c7a86, 0xc5f414ac, 0x8abd0c3f, 0x600d4e5e, 0x2563e4ce, 0x8d0fcfec, 0xca1a41ad, + 0x8b6cd106, 0x1c20ce8c, 0xccd34523, 0xa83dd98b, 0x798ff3d4, 0xb0b37297, 0x227e7c95, 0x42758927, 0xe1ac3527, + 0x479170b8, 0xcd1a0a76, 0xd1f77c26, 0xc3311f34, 0xc5d9a643, 0xb13672e8, 0x922f3a7d, 0xed4e7387, 0xde73a2bc, + 0xe5e190a9, 0xa10a32bf, 0xe4192b96, 0x212ef64e, 0x108cc3a6, 0x67821a6d, 0xd1550c3e, 0xcf024963, 0xf4513615, + 0x1b74cf8a, 0x486d98ba, 0x49207885, 0x712a1b70, 0x14d706b0, 0x33b9a09a, 0xaba1b60e, 0x527dd8c4, 0x86098152, + 0x4f6ca9b0, 0x5bb26799, 0xaa5b1290, 0x4546e7b2, 0xd6e6886f, 0x755fd389, 0x50a406a8, 0xe0464320, 0x171fe1d2, + 0x5440ad74, 0x38ac413b, 0x050a77b1, 0xc4fab17e, 0x6c4780c4, 0xd0325117, 0x07818452, 0xcda102c3, 0x91c15b39, + 0x3b8f1a3b, 0xd220f70e, 0x1f054057, 0x1ad4a053, 0xd817300a, 0x2b5dcb09, 0x1bc8caa8, 0x7e922713, 0xfbafab34, + 0x3048e7c3, 0x661cbfe2, 0xe6711912, 0xdbb5bf5b, 0xb17a5eed, 0xc72acdf7, 0x5804f6f7, 0x63f58495, 0x95bf7a1b, + 0xb3b8f427, 0x1e6b9e82, 0x84994b57, 0xd5f5f8f5, 0x769e176c, 0x06fbfeac, 0x5e255376, 0xc023ef41, 0x146e50b5, + 0xda1f7157, 0xd8606040, 0xbbb0b76e, 0xdc7a1537, 0xdc785ac1, 0xa5cc03d6, 0xdc8dd8e4, 0xa52704fa, 0xe8b30bd9, + 0x1ff61456, 0x64e6742d, 0xfcc8c364, 0x92ca69d8, 0xf9543362, 0x889c0be4, 0x6dc19379, 0xb31c5821, 0x13a66f67, + 0x6e881766, 0x027d9802, 0x8a538c1a, 0x7f3c68fb, 0x8e7f034c, 0x48ac73b4, 0x0a2a715d, 0xfdd9f82b, 0x6698f6c4, + 0x23399bfc, 0x75994d29, 0xdf66b636, 0xf3e150d0, 0x4aabba59, 0x653ba836, 0x46ca5b19, 0x2f0be18d, 0xe6decac8, + 0x715a8403, 0x48533c31, 0x5f8dc44e, 0xf1ee4e83, 0xbe7a39d4, 0x2195fac0, 0xe1e4eb13, 0xb3370c25, 0x9fe47cf4, + 0xf570c53a, 0xede20de3, 0x7e57d214, 0x239ee426, 0xda967093, 0xd32085aa, 0xeedd3cd6, 0x979246e7, 0xab4a0936, + 0x84da95bb, 0x55529838, 0x45ac1e18, 0x8cdbdf6b, 0x4f27357e, 0x213a65a6, 0x981b8162, 0x04a7d350, 0x8b94dfeb, + 0x3895a6c1, 0xbd445d2c, 0x649bdc1a, 0xb0df242e, 0x0e25e48a, 0x18cfc879, 0xd9a56067, 0x1b1446cd, 0x0d695e24, + 0xbeeac25b, 0x82335621, 0x3f7f07dc, 0xa30f6c26, 0x0c4ad0d2, 0xd4ecb866, 0xca143c4c, 0xd6998bcf, 0x844d2004, + 0x095e7492, 0x5b6a1a88, 0x26a9e04c, 0xd95680d1, 0x2979baed, 0x1d264f2c, 0x349cb550, 0xd88f0c1f, 0x8791af7b, + 0x44a24835, 0x65526831, 0xa6456fe3, 0xcb1f056f, 0x7831a707, 0x0a4304ff, 0x3aba235e, 0x60867939, 0x5fcd5dc9, + 0xe17a834f, 0x629c2098, 0xf22c1eea, 0x0daa20bf, 0xa329031c, 0xd797d690, 0x239ed54e, 0x9cde16f2, 0xaa0ae9ea, + 0x212a4797, 0x80d9cb1a, 0x7aef4da4, 0x7caf7a1a, 0x510739c5, 0x86cc42e0, 0x9390989d, 0xed0547a5, 0x7ff28211, + 0x077ce4a5, 0xddf7fd3f, 0x0ab5de8f, 0x2b3cd257, 0xdcf4282b, 0xb3e04148, 0x5d4ae67b, 0x3131c1d9, 0x5626bd48, + 0xe040740b, 0xb51c5ba4, 0xf948f6ff, 0x3a66c6ea, 0xe689f4f7, 0xa6f6c362, 0x99f3c3d4, 0xb181dd08, 0x6077b067, + 0x8890deb8, 0xa8d76010, 0x340eaccf, 0x7d7c3bfa, 0xe691789d, 0x1e3f5bca, 0x51a59692, 0x5cbb94c1, 0xc0634489, + 0xad5b60a7, 0x036e227a, 0xb960158e, 0xa2b4d640, 0x5bdca035, 0x164eb082, 0xe11c08f6, 0xa62707d7, 0xd7821e1e, + 0x78a79f40, 0xd20e9a25, 0x7805194b, 0xe4ec9aba, 0x68dd8f59, 0x2520baa5, 0x9a768b0b, 0x0c647b08, 0xf64bd122, + 0xb0d68024, 0xbf3238e0, 0x48c18dab, 0x6516fdd9, 0x3658623b, 0xfe679a40, 0xa5ce4e52, 0x57d443ba, 0xe799ad60, + 0xa43881a0, 0x6454cc59, 0xe11d4176, 0x82514bdd, 0x9d9526cc, 0xbbae633a, 0xbe20c225, 0xa5a9e35f, 0x41543038, + 0xc7c11184, 0x06e940ab, 0xc599ad4e, 0x6f680822, 0xf760f0ee, 0xbf6daf55, 0x9866cc0e, 0xb4c9bebd, 0xc524b72f, + 0x1b4638d1, 0x491ab4c4, 0xcfe6c3ef, 0xe6efe9d1, 0x13c6d6dc, 0x4032a0dc, 0x8e04bedc, 0xeefe2668, 0xf35da8c5, + 0x2358f985, 0x9f8353a6, 0x7162080a, 0x689900cd, 0x56184435, 0xffcf9c25, 0xd81198d6, 0x8059d834, 0x647b6012, + 0xbd1cc2a0, 0x96badb96, 0xd60e38da, 0x5d80ec01, 0xf862957a, 0xec3cc136, 0x38a2f404, 0x1d53410c, 0x50233686, + 0xee8f7e4e, 0x4772e09a, 0xd90e93f3, 0xeefc438a, 0x5eb08114, 0x34b61c3d, 0x5eb9900b, 0x50784074, 0x570c903f, + 0xa248772f, 0x5ed61d45, 0x23a42e83, 0x960a8714, 0x72f51568, 0x651f0d09, 0xe7048752, 0xd8eebe19, 0x5537808c, + 0xc1600360, 0xd6d8f43f, 0x7a8a357e, 0xcc872ae1, 0x34c56d8a, 0xd7fd3c92, 0x8329d748, 0xc9caf9d9, 0x339cd18e, + 0xaad85602, 0x52595883, 0x2dd5714b, 0x137c3f0f, 0x76df458a, 0xb90a0b0a, 0xcc6d1c36, 0xa09b1706, 0x9e1aedf8, + 0x234a3f19, 0x066fca9a, 0x7a78eb75, 0x35522332, 0x7a883cf0, 0x0de57ff4, 0x364d03fb, 0x17ed5725, 0xf752f673, + 0x33b47850, 0xf92c786d, 0xcfbd8bae, 0x6a8f7b5c, 0x318395dd, 0x296e87ec, 0x41d8b495, 0x066160e0, 0x2e067f72, + 0x6298b1eb, 0x6d93d9fb, 0xf5ab5440, 0x288ee33a, 0xf7f8e31d, 0x485e66e0, 0xea165f38, 0xc38bff0e, 0x49674256, + 0x25454ab6, 0x65f9f8ae, 0x6c8efeb3, 0xe83596d8, 0x66472fe6, 0x32d7aeed, 0xad8c6229, 0xdfd7c45c, 0x54144e3e, + 0x6b82d5e0, 0x403cf5f8, 0x162b2343, 0x95739f0d, 0x9ab3d633, 0x9023551e, 0xeb9a236f, 0x675156f3, 0x7471053d, + 0x5d67d8e1, 0x9e24c5ef, 0x0f3516ba, 0x39824a3e, 0xc229815f, 0x818c1807, 0xd9f6bb49, 0xaf37800c, 0x11ae40da, + 0xb4be48b9, 0x66b76ddb, 0x5912b906, 0x95298d40, 0xcda26115, 0x40b2dd2b, 0xc3237d26, 0x0f15d274, 0x60a106b7, + 0x3ee14aca, 0x5d3a21f9, 0x5763151c, 0xea5cbee8, 0x0635c255, 0xa4da3671, 0x58b90da2, 0x54b7ea85, 0x03f29b72, + 0xc4d477c2, 0x8fb8857e, 0x9be1f6f5, 0xbf097b01, 0x84507e31, 0xe7428f13, 0x03d347a7, 0x8c580f2f, 0x5438b16e, + 0xff9defd5, 0x0337ea8b, 0x9d0545a0, 0xd4d84543, 0xcaa0339b, 0x18d7b402, 0x0f789458, 0x3b4c53cd, 0xc1f0d828, + 0x4e51f006, 0x1c5ffcc4, 0x970b3048, 0x478da646, 0x9d6c002b, 0x8ed08b38, 0x5465056b, 0x694f334c, 0xce04456a, + 0x7118b82b, 0xcaab9699, 0x5a292c2f, 0x34ab184e, 0x0d923a1a, 0xdeb68fce, 0xb8f335fb, 0x0f0941a9, 0x18cf85e5, + 0x175e7ff4, 0x86bf0011, 0x27d6a3f4, 0x4f222cbd, 0x92a008df, 0x5ac3d031, 0x8227745e, 0xcba9f434, 0x6184e6d2, + 0x8807b949, 0x54624503, 0x129d7f87, 0xfb1791f7, 0x8428c601, 0x6fed5bea, 0x74fd65b5, 0xdffd6849, 0x2932227a, + 0xa4ce9e0e, 0xc7dff1f9, 0x951d1bdb, 0xa8e4b21b, 0x757f1b61, 0xef26cdae, 0xf6e62355, 0xb27f5aa1, 0x2a9b7712, + 0x0783ce3a, 0xa1d74b7a, 0xa54e07c8, 0x2d76ee59, 0x830bc785, 0x34ed40be, 0xc52341f0, 0xe308b649, 0x50ddfab1, + 0xc3fa71a5, 0x6cb96f32, 0x7e13b186, 0x668fc923, 0x5de4f6c6, 0x535dab4e, 0x922f75a4, 0xf2fd87e8, 0x93e48e08, + 0x4416962a, 0x1be6f81c, 0x69322f2c, 0x89411037, 0xfe15fa9a, 0x3ff80310, 0x4f5fe560, 0xb5a7d6ab, 0xfd23ca7a, + 0xf0f4711c, 0x59b6328f, 0x3ac13f6d, 0x0fb8e68b, 0xf83f2566, 0xe57f796f, 0x0bbb37fd, 0xe42d2cd5, 0xd93c1928, + 0xd76a3f46, 0xff800452, 0x27e2232c, 0xa499f5e6, 0x004a7297, 0x733ab939, 0xde7887d3, 0xda51f004, 0x0cf743cc, + 0x912b8b2e, 0xde1449f6, 0x79bacbc7, 0x714fb39c, 0x9b7d69d8, 0x7c9bf77a, 0x3b4a8fb8, 0xe2f84366, 0xa9764bff, + 0xddca0c26, 0x376fa0d6, 0x754a026d, 0x83c6cb62, 0x1fd288e3, 0x8e03bfbf, 0x035d314c, 0x2e3a002f, 0xcf7c487e, + 0x0b430af2, 0xdb8b31b3, 0xc80b77e3, 0xe9f51cd4, 0x96db2770, 0x29bd675f, 0x97c8ec6c, 0xfc69ea42, 0x5e262d6e, + 0x12b090ed, 0xab2713fa, 0x5395b083, 0xc55486b9, 0x4e393a2c, 0x0a01b804, 0xa75d7055, 0xb1e72bdd, 0x16bc9e58, + 0x0239875a, 0x90e6416a, 0x9720a8ff, 0x0fc28ea4, 0x11b90a9e, 0x625fc3f1, 0x9e1d1d0f, 0x2c9fa964, 0xc5146e15, + 0x62c51fdd, 0x245dfd80, 0xbdbb74b8, 0x3819f781, 0xcfaebb24, 0xbba731fe, 0xed814a61, 0xd0f54c3c, 0x9222c12a, + 0xf5a59200, 0x99f3328b, 0xb2ee1129, 0x462fd15e, 0xcf9bcbcf, 0xa9166704, 0xdf1fe96a, 0x1084dda6, 0x53ddbfb6, + 0xeda74a6a, 0x96478b29, 0x5d0d857d, 0x4ca8aff2, 0xbca6f102, 0xb2de592e, 0x13b9d756, 0x0e423870, 0xa3f17f3c, + 0x3255f2ca, 0xd43f075b, 0x5bb48d54, 0xe68a5db9, 0xb2cc79d1, 0x0407997f, 0xf094d077, 0xdf80a87c, 0xedd3d122, + 0x0bdda8a3, 0x82593ac4, 0x0c077464, 0xb91efb84, 0x878069a9, 0x505ce013, 0xc46aa941, 0x5ecd0f47, 0x614e5b58, + 0xe246d338, 0x7b67e157, 0x72d7ee34, 0xefd0134c, 0x7f0e6baa, 0x7a1fa07c, 0x8790b342, 0xb84623f4, 0x4cbe001e, + 0x73679129, 0xb29d1b2b, 0x67aa5534, 0x9f73cf73, 0xa248d8f5, 0x5672e11b, 0x79313ed6, 0xb93fc4fa, 0xef71b9a5, + 0x32d8d1f6, 0x8a600282, 0x72e5027c, 0x41aa6b77, 0x462ad16a, 0x6951b718, 0x546c691c, 0x32328985, 0x63e6281d, + 0x2bb64ac8, 0x90f4e993, 0xb3c94a11, 0x9f534d13, 0x16bcb5a0, 0xf3a6d00a, 0xf810dc33, 0xfc39a6d6, 0x7c9a28ca, + 0x3832af63, 0x865e61db, 0xdb0bb2c2, 0xa822f2de, 0xff413716, 0xde82b74c, 0x488eeeda, 0xf211e411, 0xe8411860, + 0x0d96346e, 0x3b81169f, 0xf851f09d, 0x96dbd534, 0x25335444, 0xbc0d4a5c, 0x43efa3fa, 0xc075d5f4, 0x4b996517, + 0x05cd3f05, 0x40a8cb3f, 0x9943239e, 0xe0cdbde3, 0x62ef2636, 0xb87d8629, 0x1d96bb15, 0x46563efd, 0x9aace906, + 0x8d653194, 0xc36a6eb6, 0x5176f536, 0x48db67ba, 0xe3de51fb, 0x89b89e33, 0xef7ce32f, 0x01336fd0, 0x02421142, + 0xbd3ddfb1, 0xc06162c6, 0x0701f429, 0xcb31869b, 0x0d8db23f, 0xaebde12a, 0xeadba54a, 0x44edeb91, 0x44b690fb, + 0xe7a8583a, 0x9685ef57, 0x8c20f754, 0x93f14b90, 0x6abc2955, 0x9fdce95f, 0x3b756f0e, 0x00d7b33a, 0x3554688a, + 0x17f02055, 0x2de8ec82, 0x8a16d838, 0xdd01bf11, 0xb724091e, 0x078eeca9, 0x5f5f9c4e, 0xefc87f71, 0x8cde2436, + 0xdb1952f9, 0xca45d147, 0x04e64d1d, 0x9dbf08c0, 0xbf4a58d7, 0x2703211e, 0xc9fa8669, 0xf434e3d9, 0x72a59050, + 0xf5f61133, 0x523542f1, 0x2739ea3a, 0x44a7f5ef, 0x6ac90a82, 0x905132bf, 0x4916d330, 0x04affa22, 0x6d88d752, + 0xc276cff3, 0xc25e0a00, 0x265792e6, 0xa4d0fd1e, 0xb7f089c3, 0x19267482, 0x466f6557, 0x430d0eda, 0x7c5eab4b, + 0xfef199dd, 0x6b2c8c88, 0x7c4fcab0, 0xfc28e480, 0xeeca067e, 0xff64b9a4, 0x91cd7a06, 0x4a64164c, 0x20e46a31, + 0xa579377d, 0x66745ee9, 0x1603552a, 0xc399efb1, 0x19b06e06, 0xedc7d4e5, 0xec4d6b3f, 0x5ffdcb09, 0xfd42e582, + 0x02b540a7, 0x93ec4e02, 0x27d6647a, 0xc2c0292b, 0x7106a143, 0x320fde19, 0xe97bbd87, 0x37cd20b2, 0x2e5a3031, + 0x02d66590, 0xa340d913, 0x91f91d97, 0x3c72872d, 0x97d1def1, 0x8542d619, 0x848288a7, 0x529f2538, 0x3ebab349, + 0xde4d4c8e, 0x4e5e4700, 0xc1f74258, 0x27c69e3e, 0x3bd6b2ff, 0x5f3bf7f9, 0x58aa7fe6, 0x85981baa, 0x6b5dc870, + 0xdc4785c7, 0x89769f7e, 0x6b0ad816, 0xe4f9eab2, 0x7d086bf3, 0x1b78797f, 0x665c6dca, 0xac985904, 0x81852fe8, + 0xeff534a2, 0x0ef40080, 0xd81b3bf5, 0xc6eaf0de, 0x5d3ea612, 0x43b13baa, 0xab3b9e4e, 0x8bb40373, 0xaa95cad8, + 0xeac4aeee, 0x8fec37c5, 0x7ad5890a, 0x9c5a2e13, 0x0ea8cc69, 0xca52e1f6, 0x5e01908f, 0xd08f2234, 0x82a16e0c, + 0x07ce521c, 0x6f19dae4, 0xf3482f66, 0xe6962dff, 0xc274ad61, 0x6c9a2843, 0x1cf8235e, 0x31b7c95d, 0x04d4d484, + 0xf3f5ec98, 0xc88cbc8e, 0xe40b2390, 0xa705d4af, 0x947266d2, 0x1251cf31, 0x61ac06e5, 0x1bc3307d, 0xb7d3d64b, + 0x25ffb074, 0xa8533e68, 0x6471e623, 0x41438da8, 0xb2428217, 0xf5c4b0cd, 0x42271e01, 0xcb6a4dad, 0x57eac019, + 0x1dda7fcd, 0x3960c3ad, 0xe0fc2266, 0x2553b803, 0xc1522f1b, 0x72445b35, 0xfb556514, 0xd11d39d3, 0x3431f882, + 0x3937e067, 0x83945b8b, 0x728dfd30, 0x9af71f6e, 0xfd738cc2, 0xe3a185ab, 0x16d96b54, 0xb846cba0, 0xea5dbdac, + 0xaa9ac0ed, 0xcb47aa2e, 0xb5285b95, 0xbee7cf0f, 0x89f23c8d, 0x3d49220a, 0x91ce340e, 0x0538936c, 0x96b8ae9e, + 0xef5972f7, 0x790e99e1, 0xfc6c2650, 0x40487dc5, 0x8ca8b845, 0x8dcf991e, 0xbb1cd117, 0xd85678a8, 0x64baf88a, + 0xbf1bb661, 0x8e01bb1e, 0xfedbbd9d, 0xce99b1ab, 0x6e7f1e66, 0xeafbfd88, 0x2564f84c, 0x13c3195b, 0x80a4a98a, + 0x40c40960, 0x10eee03a, 0xceb8f92e, 0x78341442, 0xf3c916d7, 0x6fd9b14d, 0x4b832f40, 0x98238a2d, 0x05983e5b, + 0x15926463, 0xc83805c1, 0x44e1cec3, 0xd69dd4d2, 0x4740c1c0, 0x098dc222, 0x99397cee, 0xee934846, 0xa5bb9440, + 0xed5a0d2c, 0x9389b857, 0x9e3f4231, 0xf35ef3ca, 0xcf4bb88c, 0xe3373354, 0x83433d0c, 0x92665533, 0xe6745c7a, + 0xbd1c5373, 0x2250e104, 0xbc607201, 0x5ee367c4, 0x3f1f63e1, 0xdf9ff104, 0x97e5e5c2, 0xb78a6a46, 0xe576952d, + 0xdfaadada, 0xd5cd701f, 0xf90b7daf, 0x56ced538, 0xd43d09ba, 0x07090767, 0xd35ff16d, 0x1015907c, 0x2722dd28, + 0x7f46a4eb, 0x5e6c5ffc, 0x09d5d742, 0x8b3b51da, 0x815432b5, 0x3a73d932, 0x395d47c4, 0xbbf8a600, 0x6b584f1c, + 0xbf193b07, 0xdfd628c8, 0x3d252b5a, 0x60681b64, 0x30680145, 0x428fac8e, 0x678b3f57, 0x9850dbee, 0x35ec703d, + 0x51e75bac, 0xd5381086, 0x1bf4a1c8, 0xd117d819, 0x718d1f68, 0xad6997f6, 0x29810407, 0x2c738e7b, 0xa9810cc0, + 0x1f9c9687, 0x2b0d0b54, 0xb16e9c3b, 0x4499b4df, 0x5a4da013, 0x78b22312, 0x418aa80e, 0x767f7cdd, 0x26565543, + 0x4167b4ee, 0x818f7172, 0x484354bf, 0x949759b9, 0x76c7267e, 0xda0593f5, 0x9e660906, 0xc06ec26c, 0xb98a0293, + 0x67eab09b, 0x399bc025, 0x6dc5936e, 0xa544c565, 0x2f6fd454, 0x53bf444a, 0x35d817e8, 0x85c45fca, 0x1e969385, + 0x669d2645, 0xf563ccd7, 0xd6ffa37e, 0x7fe09af8, 0x3fdbb79b, 0x9c0e4c07, 0x8d7a92dd, 0xdaac65ea, 0x45430167, + 0x5e1ba6b0, 0x99c375ba, 0x4ada3066, 0x0ddde754, 0x4d2c59df, 0x85498d70, 0x532ecd43, 0x891922e6, 0x237c3187, + 0x78669134, 0x2bbf97f1, 0xc916e811, 0x1bc96fba, 0x8e8bb660, 0x38d7b811, 0xf2c935cb, 0xdb82421a, 0xcc65c621, + 0x0e691e94, 0x0563a6c2, 0xbb5fa8ce, 0x4f0ed2e3, 0x27c19053, 0x63aabba3, 0x6cbcfee6, 0x4c2b9951, 0xfcd66b84, + 0xb2abf6aa, 0xb3ef20c3, 0xfffdb5bd, 0x7268b79d, 0x0f1a0694, 0x6437b1cc, 0x432d98ba, 0x0a1ad348, 0x11ae615c, + 0xcb978fe8, 0xd3e0255d, 0xfffd3419, 0x60255d24, 0x778befbf, 0xd2a0e724, 0xad69d973, 0xe2e7d366, 0x851514bb, + 0xe4de56cb, 0x84a18440, 0x60d71e1b, 0xe06399d6, 0x7f125006, 0x56869ced, 0x3a50a06a, 0x85f92c7a, 0x0d92f565, + 0x9086595e, 0x0c13dca5, 0x6d699107, 0xb44416c9, 0x4f17bd8d, 0xb6a1e805, 0x0a16146d, 0x79e20b8e, 0xc2c399d7, + 0x21694c6e, 0x14410a29, 0xcc27b347, 0x9af3d094, 0x1f6536ee, 0x2ae97d9e, 0x2971f981, 0x43fd1182, 0x72b0e00a, + 0x7c48b2fb, 0x9cbb099e, 0xf086114d, 0xdc5ee75a, 0x15d0a6c8, 0x5397cb62, 0x42bdf5c4, 0xdce80a10, 0x7cad4c9f, + 0x222098dc, 0x3a45723d, 0x4e69629b, 0xa962f04b, 0xc19cff43, 0x821a3d5d, 0x35611130, 0x99cf450c, 0x87c85e31, + 0xfffbe5a4, 0xca326d4a, 0x13b74212, 0x5fd2282a, 0x13c4f403, 0xb136dd07, 0xf0905aec, 0x6eda0dc8, 0xa5a72620, + 0x390d6099, 0x80dca451, 0x5a85ca19, 0x015e2598, 0x2e0c2460, 0xb2e036e0, 0xbc068933, 0xd5847cd4, 0xe1c48716, + 0x23326329, 0x1bb7c4b6, 0x7b73d6a2, 0x5c606883, 0x6399247c, 0xf6811c4a, 0x4e764d09, 0x43e6815c, 0x40dff6a7, + 0x525a29ea, 0xa3e0f8f1, 0x49cedf3d, 0x9d9d552b, 0xfa9415c3, 0x3dfc5fed, 0xcf886791, 0xd37530d2, 0xdf9a885f, + 0x4b7d6b21, 0x00d189c5, 0x17c125ae, 0xaf1118af, 0xea6fa5f1, 0x1cdd1b85, 0xf9e705ab, 0xbc21b058, 0xac0009f2, + 0xafaba357, 0xb733a092, 0x4eca8cab, 0xcab5ece4, 0x0758dd1a, 0xbcb80e28, 0x855618ae, 0xe4cab6c7, 0xdf0c29a4, + 0xf1768d6d, 0x45133e85, 0x9e1b45f0, 0x8dfb8e44, 0x1419fd98, 0x83acc465, 0x9d8c9952, 0x4ac02621, 0xd8f58f51, + 0x234db85a, 0x12a896f3, 0xf0911a80, 0xc72b31b2, 0x6f6b6ed5, 0x839101cb, 0xa5eb6d82, 0x2a195abc, 0x0ac4e6c0, + 0xffc0697c, 0x28b793ed, 0xd9dbdff1, 0x7508a2eb, 0xce2a9e70, 0x99e09516, 0xebc2573d, 0xa35be44c, 0x2092d3ef, + 0xad8e489e, 0x1906bec2, 0xdda0ebb3, 0x7f0685d8, 0x8037cf1d, 0x739806b9, 0x7b4d0605, 0xd7f01853, 0xb44223a8, + 0x79da67a2, 0x2f214c72, 0x2097d9e8, 0x43a54284, 0x2a4ad41e, 0x14957b31, 0x02abb40d, 0xe790d859, 0x8a23ab9a, + 0xada75e46, 0x0eb82d88, 0x8a9583cc, 0x1a346ab2, 0x724ea7ef, 0x15147726, 0xda81ef05, 0xf20f314f, 0xc96a9a39, + 0x3487acab, 0x07e85015, 0x0dce75db, 0xd4557262, 0x821ceaa5, 0xafb745f3, 0x5811cafd, 0x7bf6f772, 0xf2774d40, + 0x48bae404, 0x5dacbd8b, 0x3831ff40, 0x780305ab, 0xa8451a8e, 0x3f511ff9, 0x269b5dff, 0x1c94c570, 0x8753c2e0, + 0x4ae818ae, 0xcbeb10b8, 0xc4da8e99, 0x365f50af, 0x706d3fd1, 0x79a16220, 0xc9e8dbf5, 0xf6536754, 0x56e66b93, + 0x8dee7f54, 0xe078f23e, 0x4a156adb, 0x331e624b, 0xf94e56a5, 0x5d53443b, 0xb5d39a8c, 0x893714dd, 0xab3d767c, + 0x7d749e0e, 0x636ec97f, 0x9cc65cc8, 0xd186d607, 0x148af2bf, 0x3ccad08f, 0x088f5b9b, 0xcc2bb54c, 0xc53d8b7a, + 0x25e93ff4, 0x10db70dc, 0xe21320cb, 0x3da22392, 0x532482d9, 0xb03791d2, 0xdd818145, 0xd3fe98fc, 0xea7fd4ce, + 0x448ba38f, 0x75303bf4, 0x70938a8e, 0x8341f791, 0xc44231e0, 0xee83ea00, 0x75578d8a, 0x880feaed, 0xfcf34f39, + 0x8b11276c, 0x423edab4, 0x68d6a3c5, 0x5242bd40, 0xdd9266a0, 0xe07ca4ce, 0x6e91bbe4, 0x0fb616a9, 0xc66b4f67, + 0x61d17e65, 0xab665ee8, 0x64113bce, 0x95b44dc4, 0xe1c141eb, 0xac26f9b6, 0x607a0da5, 0xa2133b21, 0x85f8e104, + 0x074f5c46, 0xb2fb07b9, 0x09056a1e, 0x528a8492, 0xb7c31627, 0xc8b1ac4a, 0x9db2c899, 0xf0f96866, 0xf8116ac0, + 0x7201b71a, 0xfd1367ac, 0x8529a44c, 0x1d205e8e, 0x221936e6, 0x1ce8b1f5, 0xe86f8cd5, 0x5c41fbc2, 0xc663beb9, + 0xe5ad1b12, 0x96d272e4, 0x932c3daf, 0xe6bacd50, 0x778ecf42, 0x3067deb2, 0x1d713676, 0xbd825b80, 0xa1208b4f, + 0xda0acc10, 0x3916159f, 0xeb351322, 0x7ec8022c, 0x0befc5c8, 0x136dc6cb, 0x1c9f7b9f, 0xebf4e1f2, 0xa3f20a95, + 0x8beb4a08, 0x865167c7, 0x0d696452, 0xcbdb42f5, 0x6d21cd1e, 0xcfd87676, 0xce6c4cad, 0x242d12d6, 0x7602a4f9, + 0xe3185986, 0x93b5f46b, 0xb0172850, 0xc78f1629, 0x196c2886, 0xd17f2eb9, 0x344fa3da, 0x77263268, 0x56f42cae, + 0x322b822b, 0x5d5d2526, 0x87d2a7f9, 0x00ee5d75, 0x2f01265f, 0x079f6723, 0x763c16db, 0x2525d3e2, 0xa8cac761, + 0xe638c99d, 0xe5c43439, 0xbfd0fec7, 0x095f97b3, 0x3bcd4a3d, 0xd21ac13e, 0xfda59b60, 0x549eeaaa, 0x1cf67fef, + 0xf792791c, 0x93d86fe9, 0x80923260, 0x9f14707d, 0x3266bd17, 0xeab35388, 0x276b01ae, 0x304edc0c, 0xc5784b82, + 0xf476c9ae, 0x5b4ca628, 0xcffa3abc, 0x53e6468d, 0xc01953f5, 0x8a9c4fd4, 0x7073c016, 0x644b45f2, 0x5b72287f, + 0xd3644363, 0x53a2d041, 0xaba8809a, 0x975c74c3, 0x86afba6a, 0x229cd279, 0x9551ce8f, 0x7816b641, 0xbbc86446, + 0xaef934d6, 0xc2efba81, 0xdbdc712d, 0x5dc2b286, 0xf47e2f18, 0x07411f40, 0x86c51732, 0x74f95bb9, 0x630dc721, + 0xe9da614e, 0x529d9721, 0x1a80391e, 0xb086c126, 0xb678d40e, 0x9c821797, 0x94f66ca4, 0x12aedeb5, 0xbf140eaa, + 0x8994e7a1, 0xfaf22aa6, 0x5d2d11d1, 0x96741ae7, 0xa12b85b0, 0xe43c03c2, 0x897b237e, 0xc0a2f42f, 0x44462d1b, + 0x6154a31f, 0x091d7e11, 0x978d2233, 0x1a360101, 0x269581ad, 0xbd35320d, 0xc3ec8cb9, 0x960aee4b, 0xc2e78f69, + 0x64922b0b, 0x65038474, 0xf0a339b2, 0xd1cbce35, 0x18671c04, 0x052e8b7f, 0x7bab9030, 0xa270323b, 0x06cde4ae, + 0x8a56f1c9, 0x40d03315, 0x1f3b2b6d, 0xbb1c8b01, 0x241a7c6f, 0x6840caf2, 0x6999dd7a, 0x2a635cd6, 0x2494abec, + 0xde228d19, 0xc9ac5248, 0x0f6c93c7, 0xeef78a39, 0x3e13358e, 0x7b19705f, 0x11375639, 0x4ce3ad44, 0x6c4dbcc3, + 0x9d97f227, 0x7017b340, 0x4f4e66fc, 0xf5052833, 0xd7868f68, 0xca3ba6a6, 0xd4cdf145, 0xfb7f61dd, 0x708e04d2, + 0x9da2aab6, 0xcf9ec21f, 0x43f7eefa, 0x1d5dd8a7, 0xa8265404, 0x1b37dfa3, 0xbb89be51, 0x15dcc6a1, 0x9653ee7d, + 0x16175fc3, 0x7f1e08fb, 0xa5deb663, 0x96c10466, 0xd260586d, 0x8e5e8e0c, 0x12758a3e, 0x399290cb, 0x900ae3c9, + 0xfc04ff8c, 0x4d364a65, 0xf6d61f62, 0xfc6ea076, 0xf1ee7918, 0x831a020c, 0x470b3a47, 0x81063594, 0x3a914bbb, + 0x4d0ed3bd, 0x997c2234, 0xb10a5941, 0x06396ff6, 0x452c43cd, 0x3db260c1, 0x7045919a, 0x3f19fabe, 0x4332b406, + 0xdbc8f0b6, 0xc45374e1, 0x732e5944, 0x11eba353, 0x1bf635d1, 0x5783398c, 0x223859ab, 0xc2f6a204, 0x9bb15c48, + 0x1edb72c1, 0xebe55f80, 0xe478b531, 0x38faba74, 0x694a621c, 0x89b905fd, 0x47d1cf48, 0xfc2ac0e7, 0xb3d7660a, + 0xc24a1c56, 0x6162e53e, 0x8f3ff2c4, 0x66cb386f, 0x78f6679d, 0x37e1635d, 0x730c56bd, 0x2af09ef5, 0xac90348b, + 0x7f9ed924, 0xa6c96486, 0xc9b1918e, 0x16b67a1c, 0x0f22accc, 0x3c4194e4, 0xc902ba6c, 0xc5bb2680, 0xbd24a046, + 0xb89a3898, 0x0ce0db63, 0xcc09b6bf, 0xbec5a310, 0x91793d12, 0x6aae0704, 0x6efb3860, 0x2c3990e9, 0x6cb5dbcc, + 0xe6fb407b, 0xeaef8c9b, 0x367b88ed, 0x307da603, 0x9d9a0bfc, 0xb81e3af8, 0x5171348b, 0xff815d02, 0x18b3ad8b, + 0x8f63c831, 0x9f0146da, 0x3255c1f3, 0x80afee3b, 0xa7f31942, 0x5bbed8d8, 0xbfb63324, 0xebb57d03, 0x4061cc96, + 0x0c70c61a, 0x3976f6ca, 0x027f848c, 0x991d3c6f, 0xbba338d4, 0x0550d59e, 0x0ff1b479, 0x47e3f8cc, 0x78f48e5b, + 0xe55231da, 0x43b1be0e, 0x3e025ee4, 0x33dcdc85, 0x55d4e1df, 0x5f1dca35, 0xf9e67681, 0x3f8ebc8a, 0x950439fa, + 0xb3a42b3d, 0x54bea603, 0xefdcede1, 0x334fdb84, 0x9cc7c29f, 0x0b2c8a85, 0x0cbdfedc, 0x387cf025, 0x74cee57d, + 0x97976455, 0xa32b8393, 0x05397ef7, 0x243f3c15, 0xd67c2f9e, 0x5a3321b5, 0x5422f010, 0xa478eca7, 0x39b98ae2, + 0x22d6629c, 0xc44e18b5, 0x0f5bc7e8, 0x2f1fa796, 0x7f8e9f72, 0xfcaa24f8, 0x928d90c1, 0x104c5560, 0xdcce3801, + 0x8dd29682, 0x7e2e6d06, 0xea1c337e, 0xbf228286, 0x8d2eed71, 0x218a32fe, 0x79ebc05d, 0x344f2e59, 0x8e52d532, + 0x0c3ea5af, 0xbd317c6a, 0x9482d509, 0x286d4e0e, 0xd9b73024, 0x632546f8, 0x47ad801a, 0xf860f60c, 0x01ad0228, + 0xfb019589, 0xb4dec453, 0x9d9d6560, 0x528fdcb0, 0x4355352b, 0x86719bbb, 0xe824cb07, 0xc4034b6b, 0x7ad32756, + 0x6979b957, 0x89087f99, 0x72c93f6b, 0x63f7ae3f, 0xd64c6816, 0x9d170a25, 0xe8ebce5c, 0xe4f732e2, 0x87721fbd, + 0x3f8bccd8, 0xdb71bbdb, 0x4024d112, 0x796e3246, 0x1626812e, 0xe43f78c9, 0x39145293, 0xb8521c29, 0x9cd0768a, + 0xfbf1128e, 0xaec6133d, 0xcc0ea4a4, 0xf26df29c, 0xfee45908, 0xe2eb7113, 0x87b5d88f, 0x2eb3dc62, 0xbc4676ca, + 0xbfc95d4f, 0x3aaf9dfb, 0xae26742f, 0xa976ef0a, 0x500e4811, 0x7d7871ec, 0x875608bf, 0x4749a3a5, 0x81ba03ab, + 0xce93ef54, 0x4952ab71, 0x7e3c7872, 0x1e4907c3, 0x0fc420c9, 0xb1f8a1e0, 0x557da8a0, 0x982c59a4, 0xcb16805d, + 0x56662dbe, 0x867b9e76, 0x2dca9e3f, 0x1162d595, 0x1185630a, 0xaa34fc75, 0xede4ceda, 0xd63417f3, 0x7c735726, + 0xbf91d6a0, 0xf3bf97d5, 0x97b89d40, 0x78318b5a, 0x947f4910, 0x75360edc, 0x1eb36af8, 0x25dfc1cf, 0xa923a964, + 0xa35e81f3, 0x66d04ffd, 0x5dba00b5, 0xd2cff4c5, 0x9b66eaa4, 0xd8831513, 0x2f66214a, 0x34acfd9f, 0x7183413d, + 0xf8f1a44e, 0x841378b3, 0xc26055e9, 0xa88c59c2, 0x68b28dff, 0x6d53184f, 0x6bcfed50, 0x17bf8ce4, 0x82a439c7, + 0xdff9a9f1, 0xa65d1f9d, 0x938fdfd0, 0x58e9e1f6, 0x99aed4a7, 0xc81fde04, 0x12cca217, 0xb4f8d9c9, 0x4e1b56db, + 0x3b49387e, 0xbe992ce6, 0xa7322192, 0x40b04d6f, 0x4ebb4795, 0x3d6eb11c, 0xa5b8aa6e, 0x982beb31, 0x71f86588, + 0xfc4e16ca, 0xb7f34185, 0xb2d94e37, 0x390482eb, 0x2d923ce8, 0xfcf68db4, 0xb48039c0, 0x6e6762f8, 0x12874935, + 0x40526ef8, 0x675c2a34, 0x0b986e62, 0xcb92a3c7, 0x69b9dcd8, 0x76776712, 0xb4a4a2ab, 0xfb52dda9, 0xa2d30a47, + 0x0aea9c1c, 0x3a9fe084, 0xb71f7858, 0x172d0fed, 0xa59f6b52, 0xe9827d63, 0x42328b0d, 0xba55f471, 0x5bbfac26, + 0x4428a223, 0x1d639d12, 0x081bc9b2, 0xbf59d535, 0x1a3df817, 0x5f4c6b32, 0x1839909e, 0xb614a5da, 0xabb55b44, + 0x207a755f, 0x2794c8df, 0x30c564ff, 0x80e522c8, 0x019d1938, 0x145e73d8, 0x74acd93a, 0xb9685203, 0xe72699d8, + 0x08b40318, 0x0232931c, 0x15af8ecb, 0x90afc5e2, 0x292194bf, 0x4c54ddcc, 0x26ee3d7b, 0x36427a05, 0x1ad9f938, + 0xd3232b0d, 0x6c047a6a, 0x429cb0ac, 0x5930eff7, 0x9902c94d, 0x8b3de51f, 0xbd36a967, 0xd57a5031, 0xdf16e13c, + 0x3312e33d, 0x75a6d6e3, 0x231dcaa8, 0x2d896be9, 0xf2132e3e, 0x7b589277, 0x2003d98b, 0x1a63d0fc, 0xbaf633ed, + 0x5319148f, 0xe3ef1f9d, 0x275b2db3, 0xb46de902, 0x38f68037, 0x3ad42665, 0xba0513b5, 0x91b2fc0e, 0x61d635ef, + 0x495585ef, 0x83aabd13, 0xc2738510, 0x8c9b0e67, 0x5ee5ab83, 0x4eb4ab57, 0x26154b70, 0xdd769980, 0x2635ce4e, + 0x3dd1d561, 0x1411c3d8, 0x76186156, 0xb09655fd, 0x84fb1e48, 0xdb872997, 0xece7782d, 0xaf8db55a, 0x828a7fa9, + 0x2b8ff56a, 0x8eb92456, 0xffc74daa, 0xcf97f18f, 0x68d1af71, 0xd51d552f, 0xbef46da1, 0x85a5b632, 0x826308ff, + 0x9d50c5a1, 0x1cd4413b, 0xd2e74b61, 0x7fbc690c, 0xfc31605f, 0xab4b6805, 0xce37d5d8, 0xc61a115e, 0x73a36c87, + 0x7689874a, 0x788a336b, 0xc1380606, 0x905949e7, 0xede4d213, 0xe5f8b813, 0xba94c08f, 0x63af9e3d, 0x180bacc8, + 0x8c541bd8, 0x6caca03d, 0x6b756deb, 0x197fa705, 0x1f104758, 0x13b9932c, 0x10246ae4, 0x3378ad60, 0xe831ed93, + 0x03590d90, 0x982388aa, 0xd6ff0e00, 0x19952581, 0x18b04b52, 0xee04de9b, 0x5de2cd78, 0x22687d06, 0xbc4da545, + 0x795300f4, 0x60eac615, 0xc2736fb4, 0xf206fa9b, 0x89ad7e06, 0x2d0a5d75, 0xffd07adb, 0x164b8a3a, 0xd03024ec, + 0xaa3442d7, 0xf8d31669, 0xfc473247, 0xc079b52f, 0xc6f7e265, 0x466cf90c, 0xb0b6d1cb, 0xaa92b790, 0x6fc03ef2, + 0xe84e0793, 0x8335c80a, 0xad45885d, 0xe5aa9ef8, 0xa3af0a20, 0x75ed64b3, 0x28c14925, 0x5b412703, 0x01e93fd4, + 0x4045f4f6, 0xd06a1207, 0xa7ed4dec, 0x33e3204d, 0x51cd8571, 0x434c1176, 0x2b736e34, 0xd0cf3935, 0x2d655891, + 0x6b45d198, 0x5062b2c4, 0xbbd29dfb, 0xcd3185a0, 0xc447db4a, 0x1396c28a, 0x9cb98966, 0xf5d2de40, 0x50ed3ad9, + 0x7f837d53, 0x5b56d459, 0x2c955a29, 0x6dab9a45, 0x34e231fd, 0x3ce8bfbd, 0x38c68409, 0x6a72b588, 0xa39552b7, + 0x69a4a826, 0x08ced9b8, 0xb3b6e6d1, 0xcf5bcb29, 0x3525f650, 0xfe10d546, 0xbae4fe6a, 0x31d5447b, 0xe545d2d3, + 0x7777f646, 0x455185a4, 0x2d7dd102, 0x0f933d6a, 0x9702a169, 0x4f80e74f, 0xd94a8e15, 0x25397453, 0x2b14d8c5, + 0x7d245741, 0x9700b488, 0x6e412a0a, 0xc3e56ba6, 0x09870c8d, 0x33174d5f, 0xea318f03, 0xe0a4fe9f, 0x49a49f2d, + 0x4f39e698, 0x5af78716, 0x0478a38b, 0x87653cda, 0x6adf1335, 0xf84e8d9f, 0x7016ebdf, 0xb515c84f, 0x0b7f7046, + 0x42a1c1ab, 0x5bd98f11, 0x64dfef12, 0x0ba72040, 0x6145648f, 0xec5b8f82, 0xe6330f08, 0xdb7700ac, 0xc4ed421f, + 0x6c74c709, 0x6b591284, 0x3939f0fc, 0xed1da7ca, 0xea39e52c, 0x11064f2a, 0xc4c77627, 0xc0d65f1e, 0xe22125e4, + 0xd763744c, 0x859efe07, 0xde219e79, 0xac239437, 0xabda9dbc, 0x1c566f88, 0xd55d5648, 0xc56e7d44, 0x8eb8f417, + 0xc9e32cdb, 0x97d06a13, 0x37e4a05e, 0xfa63a046, 0x623f5451, 0xaa5dc56d, 0x701e8b2c, 0x3cfa7146, 0xa7bcb13a, + 0x3413e7c1, 0xbac40f94, 0xef46f934, 0xe5da2aa7, 0x657a68cd, 0xe90ecb22, 0x7eb76cbe, 0xad0576ad, 0xcab555c4, + 0x361f6e95, 0xdfda539a, 0x331acbf5, 0x85799bca, 0xfd575457, 0x64702fb1, 0x22052881, 0x86ac2f3d, 0xd5f099c4, + 0xc46bd456, 0x3facf3d3, 0x04891a0a, 0x7342a8ba, 0xcbdefb41, 0x12a5ef85, 0x80cf860f, 0x09305e8e, 0xb21edf21, + 0xb0640816, 0x25441997, 0xda000f55, 0x14b7654a, 0xcc9ef28b, 0x12da70de, 0x52733527, 0x3ba0b99b, 0xcadfef5d, + 0x457bcf0a, 0x64980852, 0x2489ffa5, 0x45f53ea6, 0x33b67ac6, 0xfceb1f2b, 0x22a175c9, 0x9139f325, 0x5bc2651d, + 0xf4ba15c6, 0x5f606576, 0x0ceb8eab, 0x18c72537, 0x667e9234, 0xbbb014be, 0x339c41c9, 0x4cb2c123, 0xfde83c16, + 0xf32d0f50, 0x2f42481b, 0x17654cba, 0xf44f0974, 0x284f7c10, 0x70924737, 0x905a4c8c, 0x8f6510b8, 0x3ee48960, + 0x93dd2b1b, 0xfd8ecf4d, 0xa7498dc7, 0x249f6bfe, 0xab883af9, 0x1f1bb209, 0xd52efaa6, 0x3991d112, 0xc6c916e2, + 0xccf9b4da, 0x281bff96, 0xf89cc2f9, 0xfdb9d1dc, 0x41108a37, 0xbb08d130, 0xb9ad61d9, 0xae360db0, 0x954fc155, + 0x11df6f7e, 0x56657088, 0x7dc6d4de, 0x528d40c8, 0x1e0b672f, 0xe991e967, 0xd6927345, 0xf230d0a1, 0xee6e2668, + 0x30203566, 0xf668242e, 0x5f5561fa, 0x877a602f, 0x921d279d, 0x28301207, 0xfd06c31d, 0xc5c842d7, 0x4f4239a7, + 0x26ba5839, 0xf4a2ee2b, 0x7c36a639, 0x048ccf6d, 0x00ad4d3e, 0x958a7f25, 0xdd989915, 0x1a0be2e6, 0x2c810791, + 0xf48ceba2, 0x32a48243, 0x7c128b4b, 0x288416dc, 0x7d6cc25a, 0x57f8af06, 0x0bcd1a90, 0x534b3005, 0x1b6d43ed, + 0xb5871c4c, 0xe06bfca9, 0x8a96d2ff, 0x32957551, 0xfa86db14, 0xcdcbb758, 0xc7829d05, 0xd0ad3735, 0x25997a8f, + 0x030dbf19, 0x40649710, 0xa39aa1c2, 0xbefae9f9, 0xb0c2fff8, 0xf71bd68c, 0x112ebe77, 0xed62b6cd, 0x9125eefd, + 0x986e97b5, 0x661b84b8, 0x787e8afa, 0x7e8175f0, 0x0e515f5d, 0x92d9f0ea, 0x57554bda, 0xfed1b483, 0x6e20b01f, + 0xf70005af, 0x791f2a60, 0xc8f70519, 0xf5e971bf, 0x255b79ee, 0x5a8c1fe2, 0xcc0aab2b, 0xd50cc617, 0xd252fe78, + 0x3907a127, 0xcf02fc96, 0x9dd562b1, 0x90695f7a, 0x7290b1fb, 0xd6e95bc5, 0xd937ac19, 0x65cb9cb7, 0x71f70736, + 0x5ca3eedd, 0x3036cdc3, 0x6bd1d8ab, 0x956ce9d6, 0x11e7e0f7, 0xfbd898e4, 0x26f517e9, 0xd00e5f0b, 0x44687975, + 0x7adc286f, 0x008ac7f7, 0x10b38b28, 0xe42d3d65, 0xd0c5654b, 0x1e59aac3, 0xfa997730, 0x287c099e, 0xc9745d06, + 0x7dc44bd0, 0x7695553d, 0x1ef56935, 0x025e8ea1, 0x8c116111, 0x646cd414, 0x67a6915f, 0xc26bb997, 0x0e16251c, + 0x00e3a37d, 0x557ffec7, 0xaa2c7696, 0x42e671fb, 0x3c612a57, 0xc3942b79, 0xf267e216, 0xb92842fb, 0x4281d621, + 0x52f86cc5, 0x3f6a53de, 0xbd5118ff, 0xeed332a2, 0xafcb29aa, 0x36776c3d, 0x1dc973dc, 0xfa23af80, 0x5bca524c, + 0xb311d1fa, 0xd4fdce65, 0x3ae26c7c, 0x4111dbb4, 0x2a482468, 0xe5ea0088, 0x49a971dc, 0x83b51b07, 0x3d62b738, + 0xfbe9200a, 0xaf615c27, 0x26143d66, 0x56ce0d28, 0x2adbeb99, 0x2ceab7d5, 0x8a5c5c1d, 0x1297858a, 0x838060e8, + 0xfc9a84bd, 0xf77cb53e, 0x02d8311c, 0x5431fc13, 0x07653a0e, 0x0f0a0abf, 0xe8fe6491, 0x28bfffaf, 0x353b67ac, + 0x1096adc4, 0x5152f27d, 0xa5742c11, 0x7e03d82a, 0xcb6fb5c9, 0x39e8a994, 0xea61e37b, 0x972f5cbe, 0x27e065ca, + 0xbfb4e825, 0x3b46ca6f, 0x99d26576, 0x0df51e7d, 0x5cc9c893, 0xb3e652e7, 0x0998f9be, 0xf602f41a, 0x53d74e1b, + 0x865952b4, 0xd2aa0d37, 0x4beb5e77, 0x8ba6f12c, 0xe5d722ee, 0xbb3f788e, 0x7dd1d6c3, 0x600782d8, 0x4f4159e1, + 0xd0fa8a1c, 0x0758ab0a, 0xc7c6f689, 0xa9cd78c4, 0xa7ec4f51, 0xfba9ccbc, 0x76ed911e, 0x315aad78, 0xbd3aa414, + 0xefbcf5e7, 0x4ba5354c, 0xd676271b, 0x56bebbe5, 0x8c197625, 0x609784b9, 0xbd933980, 0xa3100d26, 0x361d0de3, + 0xfa2ffb71, 0x235c5a58, 0x76ba2f7c, 0xaf3c95c3, 0xa26869d4, 0x66b26c41, 0x00a537ef, 0xef7a9087, 0x48e47ffd, + 0xd023d976, 0x198f658e, 0xb25fe94f, 0xde079458, 0xc6a0b45f, 0x290a2d40, 0xe8986ed3, 0x575696ec, 0x9f6ad13f, + 0x667982d4, 0x1060b6ad, 0x53cc6708, 0xb61f058d, 0x27092503, 0x6dd18db4, 0x310a2c6f, 0x4619ceb2, 0xc5fb1497, + 0x11f4782c, 0xad8c416a, 0x36418ffb, 0x03545316, 0x74a69f2e, 0xe32837f7, 0xa94cee9d, 0xbb3d43bc, 0x92475b19, + 0xa920490a, 0x0c3d8c19, 0x11e16c1a, 0x652aeb6f, 0x7c0abea2, 0x970fe835, 0x130ee830, 0x19c8ed16, 0xd6935e03, + 0xe8e98ba0, 0xada40309, 0xcab6b853, 0xf476542f, 0xdcc765a3, 0xba05cdca, 0x1f6ed42a, 0x6c82a841, 0xe9935541, + 0xcf80b83f, 0x7919b426, 0x49b7b80e, 0x8415488e, 0xe7b85de6, 0xb669f3f9, 0x3127cbec, 0xb9073778, 0x1de1bab3, + 0x49d1f950, 0x601eeb43, 0x42071238, 0x63122409, 0x3619c39b, 0xa6a0a9c6, 0x168ab88a, 0x5c3ae927, 0x8ecb0e89, + 0x1d3fea4f, 0x4f8bbdcc, 0xc35b71cd, 0x37b72b9c, 0x0d85bbd0, 0x98a4562b, 0xdd0f4ac1, 0xf44d3cd6, 0x703ba97e, + 0x78b9b089, 0xef7515e1, 0x11b72731, 0x0cb7a29a, 0xb3cf8de9, 0x6c319458, 0xe945e25e, 0x4653a61c, 0xc326864e, + 0x3ef3212b, 0xd77fae6d, 0x8dced78d, 0x19b58bdd, 0x37406e28, 0xec7ccc81, 0x6f9e346a, 0xdb3da220, 0xa666e1d7, + 0x94986d4e, 0x4691b617, 0xd7caec67, 0x1c8c589a, 0xe74d70d6, 0xe5c6cc98, 0x1186258b, 0x6f879e30, 0xeedf127d, + 0x1dd20d76, 0xcf620062, 0x77719cd4, 0x0e478d9b, 0xafc4bd1a, 0xeb639051, 0x62d8c0ff, 0x4bd68c0b, 0x14859d3d, + 0x188626cf, 0xc0528085, 0xabb4570e, 0xc91b345d, 0xbea82b8a, 0xcf6748ec, 0xd140f069, 0x34dd119e, 0x60531677, + 0x33b9c1fa, 0x401638d8, 0x74a180e3, 0x030469a7, 0x659a3de1, 0x86a7fa22, 0x05edbe75, 0x82d040f4, 0x2a0a9ffb, + 0x15f53c7b, 0x193a153e, 0x88b13038, 0x328162cc, 0xcc1f0d59, 0xce7b96e1, 0xe9612c30, 0xbaab9eda, 0x55d29465, + 0x365ab4e3, 0x48bda65c, 0x251143c3, 0xe1926470, 0x57d0928c, 0x7abe1346, 0xfb551a8c, 0x60de4a07, 0xc0daaaa9, + 0x6c0b3a5e, 0xa2e65319, 0x4f69a1a1, 0x6b2f173e, 0x751ad062, 0xe1da065a, 0x293ee461, 0x957e3378, 0x39e3f531, + 0x86773285, 0xebe8227f, 0x653f4cd7, 0x5f9c8975, 0x6b705657, 0x5fd86eca, 0x66508214, 0xdef60ee4, 0xa1b5fdca, + 0xd31776c6, 0x819b4fc2, 0x5921cef4, 0x9c7e31b7, 0x944b4ee0, 0x7b136001, 0xba2b0929, 0x84554928, 0x713afc75, + 0xf18327ce, 0xef3ba7c5, 0x7df9e305, 0x3fdbd0bd, 0x930d70f6, 0xdc4ef836, 0x88ae0728, 0x91ccca4c, 0x34aff844, + 0x65f25af3, 0x893643e5, 0x9dbbfd41, 0xbbc42bd6, 0x19ec8f6d, 0xf7424770, 0x882cd85a, 0x019ceffe, 0x6055a40e, + 0x2326e260, 0x2b29199b, 0xbc8f52f3, 0xef4a62f2, 0x8cf442a2, 0x2c78d4d7, 0xe61a3c51, 0xc10ec47a, 0x0074b329, + 0x28420cba, 0xf4743dea, 0x9e60858a, 0x7f948826, 0xe58919a4, 0xb9b2f1e4, 0x0853a67b, 0x7e69a03d, 0x95e419aa, + 0x7e16cae5, 0x7364e7f9, 0x0705a929, 0xb2f6ed86, 0x57a0be58, 0xa0f99893, 0xa007fa5d, 0xeeed039b, 0x1246ebe3, + 0x9e779734, 0x97893ad3, 0xf5b01791, 0x15f4eb3e, 0xd1a48d99, 0x58b0f961, 0xba6c6b16, 0x72af476e, 0xcdca40e5, + 0x8add3642, 0x26981672, 0x1619abb9, 0xb3a6a248, 0xc4fb13ab, 0x888ddb58, 0x9dca96bc, 0xb496cc42, 0x0015df8d, + 0xf2029fea, 0xdfea5fea, 0x6cdf2252, 0xac67deb1, 0x46484a89, 0x4542c357, 0xb1e06bc0, 0x91ee558d, 0x998dd7b3, + 0x7f18a4b7, 0xe618f09c, 0x8e80ce63, 0xfbf1f40d, 0xd3a6739b, 0xa4f1022d, 0x5ddb4a64, 0x9b3e49a4, 0x3cd1d79d, + 0xebc4a2fe, 0x423769d7, 0x45cb668b, 0x6396ad12, 0xf5aa4771, 0xae733a74, 0xa8fa338b, 0x490cb92c, 0x5c8901eb, + 0x28f525e1, 0x6a2f6ef9, 0x3b68fbae, 0xe620fc4a, 0x03461f14, 0x49aead09, 0x92fed876, 0x0837b5ee, 0x281a3373, + 0x45d48e93, 0x0628744d, 0x96aeca44, 0x49215cd6, 0x561d3535, 0x7c4077bb, 0xc95846a7, 0xfe37bf62, 0x1919dd81, + 0xd6472b16, 0xd9fe6086, 0x8f972eb9, 0xc6305de8, 0x3fa046d8, 0xabe9cc56, 0x2c13530d, 0xcc9daba7, 0xf940c35a, + 0xa7051bb6, 0xf2dfbd3b, 0x5ee69a4d, 0xdd86f4f8, 0x8425f169, 0x07a2d73a, 0x2906dc6d, 0x570604cf, 0x4826673d, + 0x5c0a6f33, 0x69ebd92f, 0x51030af2, 0x6b7523f5, 0x3958bef7, 0xf1b2d0fb, 0x5aaf8146, 0xd551bf2f, 0x72fdd895, + 0xf4b538eb, 0x143c5f9a, 0x3d3b25e5, 0xf722e3e4, 0x38f0ab17, 0xdbab7a62, 0x6ba81927, 0x8a5a4f28, 0xda987c4d, + 0xa4ecce65, 0x3ed8ddcb, 0x234c5e1e, 0x503ca5ee, 0xfeeb61b3, 0xf89ce25f, 0x9d11a11b, 0x42973c84, 0xbcdd56f2, + 0x7b79e2df, 0x923594b0, 0x65e5fd4c, 0x94d2be85, 0xeeadd23b, 0xbbcc0f9b, 0x0f78390b, 0x4e7a548e, 0xa3c8d489, + 0xd7d336d4, 0x23a21948, 0x8c96787a, 0x24a2eed4, 0xeb55ba3d, 0xb8b1f7a8, 0x5d0f9606, 0x57b21bf2, 0x043e0d13, + 0xeecbf2cb, 0x16ab95f1, 0x088cde5f, 0x41e67e5f, 0x49a63cfe, 0x0d5ef42a, 0xd30d10ff, 0xf0e22431, 0x8b59082b, + 0x72d14bca, 0xb87945b8, 0xe7feb044, 0x5bf6676f, 0x31f3b78e, 0x867e9508, 0x445e667a, 0x6e8b24a4, 0xc0ca8426, + 0x5a9d1b84, 0x0d77dc57, 0x5a9d8d96, 0xb29dd5dc, 0xbbf53242, 0xc8800d78, 0xa6f26a2c, 0x4788b336, 0xd517874f, + 0xc1f3c92b, 0x49833672, 0x8b8f9eb6, 0x26c81964, 0x1ef5be19, 0x12d2956f, 0x08f6beef, 0x980fb2f5, 0x6b23d862, + 0xb6489dc2, 0x40988eff, 0x58614d27, 0x59abfec1, 0x44b7b501, 0x3bdea544, 0x59e86932, 0xa7ea0c2f, 0x5865c8bf, + 0x43041641, 0x4caaafca, 0x64f61d65, 0x4b6ce642, 0xb5c8f005, 0x25d795cc, 0xe6427398, 0x59522c78, 0xd4a9245c, + 0x44ec2de2, 0x35a0442f, 0x7b904b7e, 0x1819d5c8, 0x14af01f7, 0x40876481, 0x2b5384f9, 0x2b996de1, 0x49b6208b, + 0xc4fea056, 0x9922a8b4, 0x0372cb96, 0xcf26c612, 0x136fc51e, 0x5349ba25, 0x4637cb73, 0x61744343, 0x4f6c56e1, + 0xa03d543a, 0x0015510c, 0x3cf99404, 0xb0890fe1, 0xa2efcb5e, 0xfc35fe07, 0x34064467, 0x48e67fe4, 0xa873aff0, + 0xd8002f75, 0x6678f9fe, 0x2ee135cf, 0xab9a7831, 0xbe4a5f64, 0xad1467b3, 0xa9b13e47, 0x267c9130, 0xec8692f0, + 0x39678136, 0x4bfa8fd3, 0x0319f3a4, 0xc62d2f8a, 0xa0979fce, 0x4a2b0bbc, 0x2e17cd55, 0x04a1df99, 0x730808a3, + 0x6132fc95, 0x2c39535e, 0x306c17c5, 0x92ea8014, 0x794530fc, 0x1966378f, 0xc2340ec7, 0x3a1ead56, 0x89362fcf, + 0x0cf21073, 0x51695acd, 0x641c57c4, 0x917089dc, 0x33aa5d56, 0xeec75f77, 0x4fea2e83, 0xf7cd49f5, 0x47a7ab69, + 0xc6f98ace, 0x0ee748a8, 0xe5d4dfd0, 0x07f17410, 0xc6a55a22, 0x32622dd5, 0x7dcc6028, 0x84108cd9, 0x9f719bdf, + 0xb72a63b6, 0xab9c8cbc, 0x96937897, 0x3d8bf04a, 0x605322b9, 0xbcf70b6c, 0xebee0446, 0x059568ae, 0x7beb344b, + 0x02938592, 0x075373f1, 0x9bd25b54, 0x16955153, 0x319d1207, 0xe6f99101, 0x125632fe, 0x278ac28c, 0x985ad554, + 0x50f87923, 0x55858abf, 0x8c5c5433, 0xd488444d, 0xe122a73f, 0xf4864d4f, 0xe7843bcd, 0xfc4c04e1, 0x8e316f01, + 0x713561ab, 0x0e5023a0, 0xa9eed41f, 0xd893b700, 0xbcb0dcc3, 0xb94bb47f, 0xa9f5d7c3, 0x2136c26a, 0x590ebb38, + 0x9917e994, 0xc3e4556b, 0x4ab41e4b, 0x34b7a3a5, 0x923b0ade, 0x6c57c831, 0xa0cb271d, 0x0d4dd825, 0xb252462e, + 0x38588116, 0x3a1e9ef6, 0xed1aace9, 0x3a365c5a, 0xc1b52450, 0x7c01e425, 0x4f86d797, 0x32aa7dab, 0xe5f49a97, + 0x305ed027, 0xb352adf0, 0xd4d4c58c, 0x6b8dd683, 0x1ef564ef, 0xf85d5656, 0x5912703e, 0x7ee3b7bd, 0xcfa0b227, + 0x9758dd3c, 0x95ae08ad, 0x1c99637a, 0x60b4c1d7, 0x9e05ad4c, 0xb830b773, 0xe8cb577f, 0xeb700aa4, 0xa7ce95fa, + 0x919b3ac9, 0x7027f751, 0xc7279a0e, 0x116d0873, 0x87e89714, 0xc0ce4125, 0xd066a1c7, 0x806c5edf, 0x7b9e63d1, + 0x0f808528, 0x2bd176bd, 0xf410b805, 0xcb8aae6d, 0x522be2f6, 0xe22c2a24, 0x75ff49a1, 0x6b1ec1bf, 0xfa87d2f0, + 0x9a8a0bd6, 0x0fba9761, 0xba42201d, 0xbc4ccf54, 0x750a563d, 0xde919116, 0x686f3dbc, 0x1259b659, 0xc3857ab5, + 0xce9f6fa9, 0xc82cbf41, 0xb466c079, 0x0980c9c3, 0xcc5c9eb6, 0xe0af7b80, 0xb0e36d4e, 0x1fc2f00a, 0x5f294fe5, + 0x813537e7, 0x0cf1e3b1, 0x66d2f119, 0xd40d9172, 0x5522d123, 0x21f3b62c, 0xa41965b6, 0x77f61130, 0x6f67a8b5, + 0xc4c58fef, 0xb9119aba, 0x1c2fbe2c, 0xc9910c0d, 0xacc1a127, 0x54cfcdda, 0x3b9e70d6, 0x75d62c95, 0xec42d7d3, + 0x7172647b, 0x491e5603, 0xfb0e911f, 0x37c707e7, 0xb8d9a76d, 0x662d9092, 0x58dbca1e, 0x5b262d17, 0xbd9ac9d9, + 0x634b2a06, 0x421b108c, 0xe5e7ff6c, 0x4f8564ee, 0xbfd6d17a, 0x26c9e397, 0xbe0b6e2d, 0x09853310, 0x71bba4d9, + 0x12ef3086, 0x98208dde, 0xc232451a, 0x647496ed, 0x1381c00b, 0x8f1c75a1, 0x1885f2f3, 0x353c91ca, 0x5467aeb8, + 0xf14af1f2, 0x26a96f79, 0xbca40aee, 0xcba116d1, 0xff27a4cc, 0x3508cf15, 0xe72f4725, 0x35dfbcde, 0x91567aaa, + 0xeb4c6c43, 0x9c3ec029, 0x518a4691, 0x423ae11c, 0xf22551ec, 0x033df2f2, 0x7e32c5cd, 0xdf549230, 0x6ac1b943, + 0xcd480ee5, 0x661149e6, 0x6fb8719a, 0x2cb3eee9, 0x317d0387, 0x56910b58, 0xdb052d90, 0x8a8a7b84, 0x44180d75, + 0x44d6cec0, 0xf48e40a5, 0xb5491e25, 0x5b9c2fd4, 0xe2d3a585, 0x653f14c8, 0x1cae9b5b, 0x791a5313, 0xf82dd221, + 0x232e0da7, 0x2de6e9c8, 0x4462526e, 0x5b0004f5, 0x91bc8a7d, 0xac1df247, 0xff49be34, 0x0c816264, 0xb741ce24, + 0x33890b2b, 0x8c28739c, 0x72bdd4e2, 0x0ebac520, 0x74eaf046, 0xf3ec10c7, 0xcb5abb97, 0x10cb851f, 0x16ac9831, + 0xcdc51b32, 0x9cf91827, 0x047e3670, 0x899df828, 0x1c87e054, 0x0cbc8f5d, 0xe0beba9e, 0x7ddfb5cc, 0x9295f370, + 0x2ff63483, 0xe3590804, 0x303954a3, 0x915f3799, 0xbda13bcc, 0x20c7c21b, 0xeda34088, 0x18020d32, 0x010d1c7b, + 0xf4dce099, 0x976506d1, 0x5c303e9d, 0x4faf63f8, 0xeb8be096, 0xc9f2068a, 0x615730f7, 0xbb9de7cb, 0x80cca466, + 0xe3f307d5, 0x0d01cf71, 0x77aad343, 0xb81b65fb, 0x420b0fce, 0xa01321c0, 0x7989d379, 0x2a6f8797, 0xda2cb9a3, + 0x2ecc83cd, 0xd616ae34, 0x154deb40, 0xc7477309, 0x3f15507a, 0x21e75547, 0x3e30b629, 0x42be8e9c, 0xf605aad9, + 0xc8cbb8e6, 0xf15801a5, 0x7c3ce527, 0x33fd70be, 0xf6d81373, 0xf564acc9, 0x6fd2c231, 0xa7d61b83, 0xdbeae1cd, + 0x9a029f35, 0xb3f3c23c, 0xd686beb4, 0xe34ab9c8, 0x2103c949, 0xb99184cf, 0xaf7cfa5c, 0x5ba00a72, 0x04c5fcd8, + 0xe8ca75f5, 0xfd54fb9f, 0xcd6fe7cd, 0x874543d3, 0x82e55daa, 0x7f8e27c6, 0x69782a77, 0xefbf57a3, 0x1ee48651, + 0x0e82e8f0, 0x92ef6f17, 0x3455330f, 0x4d3e90da, 0x1f7fc702, 0x5386d0d6, 0x9482d69f, 0x73392806, 0x0079346f, + 0x92891d28, 0x1827e1e7, 0x48bd224a, 0x9afee970, 0x5e0b92fe, 0xf4436c7e, 0x777f8928, 0x584d7202, 0x6d2519ad, + 0x5eb51155, 0x0affe539, 0x5f9596ee, 0xc4dfb745, 0xa95096da, 0x33042dd2, 0x01035b70, 0xc696ac29, 0xd41ea551, + 0x0015aa7b, 0x6d0ab922, 0x711e24f8, 0xfd796df7, 0xb4fd66e3, 0x75e9a995, 0x0318fc11, 0x950917b0, 0x9a22ea5c, + 0x850cfb95, 0x8aaae5b9, 0x9a50eb0a, 0xb313d968, 0x208a8036, 0x1c177530, 0x2c824941, 0x62f43803, 0xdf47cf10, + 0x7ccac769, 0x03760806, 0xd9a1ef63, 0xebf1e166, 0x1df3d5f6, 0x7522d0b4, 0x4a071a08, 0xe16256ee, 0x8eed924c, + 0x760d60a7, 0xebf2e9e2, 0x8091c61d, 0x48fc7967, 0x5b901999, 0xb6dc1456, 0x8c5d3ba7, 0xc830cafb, 0xcca7a564, + 0xdc307ef8, 0xe8980f3d, 0x2f685ddf, 0x62f851bd, 0x2b5171d7, 0x681b6f24, 0xaa806b26, 0xb926693a, 0x19e59528, + 0x18f35a54, 0xe91096ed, 0xa55ac01c, 0x62cd7fc4, 0x01649cde, 0x6efcda78, 0x1be82cfa, 0x0ea912ce, 0x47f17350, + 0xf8dac248, 0x70c5d10b, 0x1b1116dc, 0x3ce00883, 0xac7bd519, 0x22e9aa26, 0xd454c574, 0x7690bdec, 0xf4a15d6d, + 0xa5ae5d74, 0x069e1b93, 0x45b2b296, 0xfad008b0, 0xb2ba99dd, 0x04abf88b, 0x4515b8a8, 0x6f02609c, 0xbd576c0e, + 0x31080bd2, 0xd911d08f, 0xee4d0a87, 0x807f122a, 0x98e8a670, 0xf1a7655b, 0xa6f1405f, 0x4c1976d3, 0xaf928e10, + 0xdff2e8a7, 0x941f22e0, 0x1e4ca80b, 0x4b4b5315, 0xde978465, 0x8f8a2897, 0x3bff1961, 0x398a6a86, 0xf8e375e1, + 0x7e88c4f4, 0x6af87660, 0x6d45e033, 0x40eb6472, 0x04226e88, 0xd4452791, 0xe2576b3e, 0xc60a1251, 0xa90a237a, + 0xb6100fc2, 0xdf996a31, 0x740c3767, 0xa4aca925, 0x6bb881b9, 0xa47d431c, 0x47bc0d82, 0x6e715d50, 0x5762325b, + 0x91f50daf, 0x3a6bdbfe, 0xef5e5140, 0xd010a222, 0xe8eee893, 0xf56ecff8, 0xa2ef9f5a, 0xfd597d6c, 0xddec7070, + 0x4b88ef88, 0xd550b145, 0x539b184e, 0xf505b0e3, 0x8f079372, 0x183c8bee, 0xcd53dbf3, 0x9f9ebe3b, 0x10585ac4, + 0xb11af1fa, 0xfe974bd8, 0x265069f1, 0x70c53e24, 0x8489f896, 0x8386e5d0, 0x2f3fb192, 0xcb3ef6ba, 0xdaeb3e03, + 0x7fd112b0, 0xcad959f4, 0x8f894079, 0x5e03c223, 0xfdab85e9, 0x5b173708, 0xa3fc6b8c, 0xccf3a3a6, 0x7e858cb0, + 0xbe98ef92, 0x5c0c4432, 0x3dc193fe, 0x2614ffdd, 0x9d603b5a, 0xc3c60d71, 0x24ad3867, 0x44600c84, 0x3e733ce9, + 0xfa5e405d, 0x148b4da1, 0x99a8f82e, 0x912c3d8b, 0x4a142082, 0xfeb219fd, 0xc42e2013, 0x16d7eb59, 0x9edad04c, + 0x955c16d2, 0xf86c2442, 0xe0bc483c, 0x950a19f8, 0xdf4d0de7, 0x9caa583f, 0x7603030d, 0x29870653, 0x31de0d9f, + 0x2e657552, 0x0310a69d, 0x1ce544ad, 0x55e50d71, 0xbd5d67b7, 0x7a838e94, 0x4a2b84fe, 0xecf12823, 0x92cef26f, + 0x39bcfc25, 0xe18a6da2, 0x7a11ada4, 0x239a7b0f, 0x2034631c, 0x751e4577, 0x7c014d08, 0x0bffa789, 0xe3741578, + 0x3c8cb5f1, 0xf7d3e725, 0xde72b03a, 0x73136b92, 0xcc4980c5, 0x009c7ea5, 0x786b8b2e, 0xdd035b63, 0xd9905f10, + 0x6c4d8a3c, 0x9fba2d84, 0xdb81d272, 0xe3e164ce, 0xdec85391, 0xb50dd572, 0x36259e97, 0x634555e7, 0xaa1bdb39, + 0x0db01bd3, 0xfe18ea36, 0x32c2cd90, 0x107af768, 0x32e2aefa, 0xf8d6860b, 0xc55a6ad7, 0x467ba9f0, 0xe19c5224, + 0x418bd445, 0x3111bd7d, 0xa55a3f62, 0x4a58405d, 0x8196c495, 0x41aff8b8, 0x0f361af2, 0xc08cb3c0, 0x0e68fa29, + 0xfe4629d9, 0x53ce2e77, 0x857351ea, 0x2b39b68b, 0xa1bee650, 0x45dcbf67, 0xc22b524c, 0xc7b5679a, 0xd6362893, + 0xf752d3db, 0x59e2c6d2, 0xbc698869, 0x13e65375, 0x456dc7ab, 0xcdea44d0, 0x4f347f2e, 0x6ba1056a, 0x4ece8093, + 0x4200ea92, 0xe936dbb9, 0xd91c3699, 0xb203eb0d, 0xa5721940, 0xe42a6cbe, 0x6cce82fb, 0x728e5eaa, 0x74bf52a2, + 0xd5ae8d02, 0xf40a7950, 0x883ad074, 0x2f04717d, 0x4faf1338, 0x2034e5cf, 0x328d998a, 0x8723f6b6, 0xd1b218cf, + 0x99369b1b, 0x2605f1c3, 0x360fe202, 0x81b36979, 0xca83ebeb, 0xadef7509, 0x2eb1c9ad, 0xb4792409, 0x67cb253c, + 0x0935bd09, 0x719143ab, 0x7b65dcc3, 0xe1f03e4c, 0xca0cce47, 0x5df6e3f4, 0x257bc972, 0x07937504, 0x93704703, + 0xd9e0c15d, 0x852d7798, 0x3026606e, 0xf1b90771, 0x572671e9, 0xd4fde61a, 0x6e12ceab, 0x00a14edb, 0xc35b802a, + 0xa37964fe, 0xfd919832, 0x096c80e4, 0x7cee101d, 0x4b32a657, 0xfa7f89e4, 0xb96f3941, 0x6a44f6e0, 0x0366771a, + 0x43531956, 0x46403c7c, 0x6e946a2d, 0xad53c5c2, 0x7ff0eeac, 0xeb06abe2, 0x30abc618, 0x84534723, 0x9db05fe8, + 0x62a62389, 0xf942860f, 0xa24f3211, 0xa3f2f018, 0xc3bd041c, 0xede9f4bd, 0xb0279f88, 0x4edd9162, 0x120a02eb, + 0x2db50447, 0x5846a35b, 0x52fc0813, 0x403dc372, 0xf9c906e1, 0xc78a51be, 0x281e07c3, 0x6093a16d, 0x9ea6e24d, + 0xdd3c0690, 0x6859c1df, 0x85663397, 0x523314b4, 0xb79769e3, 0x50e0a799, 0xc81e4e2b, 0xf43b80bf, 0x59eba338, + 0x8a94f6dd, 0xbacd59e7, 0x15fe94fe, 0x08edb7f3, 0x948401b0, 0xc5228032, 0xd723def3, 0x65602743, 0x5b161601, + 0x9d2dfe87, 0xb1af33ed, 0xf1217352, 0x744bc004, 0xc08cd16f, 0x9be07c22, 0xbeb6f9ff, 0x9684adff, 0x0054af49, + 0x73ac12e7, 0x54079618, 0x3d9e6848, 0x3f4bd6a7, 0x063ec26e, 0x95b616aa, 0x54493418, 0x5131aaa3, 0x9e995ab9, + 0xedc6a8e8, 0x7c512848, 0xa018da3a, 0xe7786ac9, 0xb8e22b03, 0x546f2173, 0x46a608c9, 0xf565dd67, 0x486fd760, + 0xff325600, 0x7afd002a, 0x7bbec91d, 0xa867a78e, 0x03eb79eb, 0xd943e544, 0x0ec8f7d2, 0x42f88f9c, 0x4c5bfdd7, + 0x807f82b7, 0x56963a29, 0xdcfc3d03, 0xaab84f2e, 0xbe634431, 0x8621c14a, 0xe6aa66e9, 0xcef8b773, 0x46393798, + 0x232c629f, 0xca0faaad, 0xbf1680d6, 0xdc1fe1ae, 0xf823e674, 0x4de1f7c6, 0x7fcf7c72, 0xd00042e6, 0xff626944, + 0x88a0f76c, 0x71d28276, 0xc3dde86c, 0xd20b306e, 0x497d4b6d, 0x3c935219, 0x401bf629, 0xfeabadb1, 0x7d000078, + 0x3a8bcadb, 0xa84aac5a, 0xf0d77f0f, 0xc070e843, 0x5d278ab5, 0x793c5e85, 0x4ee2a493, 0x9a1ac31e, 0x0c3de9ae, + 0x1a6cd8f0, 0x9c4b2855, 0x779b5842, 0xd572fcb5, 0x605e1ae2, 0x1dae17b2, 0x7fe50d5c, 0x4f4b96b6, 0x957fec94, + 0xf0ac6216, 0x68af7ccb, 0x2bc1d950, 0xc01b2743, 0x4dabc3fe, 0xce7a0824, 0x984127e5, 0xfeec5ed8, 0x363b1a8d, + 0x3fe08f94, 0xd385fe9e, 0x9dea30b6, 0xec786f5b, 0x7169a661, 0x86140d6b, 0x248303e7, 0x07196cdf, 0xbdd42ad9, + 0x8f3e3194, 0x6d094d00, 0xb8f85017, 0xa7eae299, 0x8626ec31, 0x2828a401, 0x3b7f5a6c, 0x2ff59efa, 0xfa1ff67f, + 0x1fd2b67e, 0x4e355bfc, 0xac18f89b, 0xf2d4b043, 0x96eb6ff1, 0xf419a2a9, 0xceaf86e4, 0xf76dbd01, 0xcc4b18d6, + 0xa5ffd6c5, 0x88a622bb, 0x98fc75d6, 0x5d8624d6, 0x76053798, 0xb3010aab, 0x3caf985e, 0xfc11aad4, 0xb1ba8822, + 0xb5bc3916, 0xfacdd3b0, 0x3c4abb73, 0x0bd6ff71, 0x8a303f2e, 0x536f0884, 0x438c49fc, 0xb306f53c, 0x3023c96b, + 0x30de2022, 0x2eb21eac, 0x7c8b7d87, 0x20c66258, 0xb59db5ac, 0x9e0b493d, 0xcdc91a4b, 0x2b3461a9, 0x94857681, + 0x26bbae49, 0x2d16811f, 0x0dbfe200, 0x0876752c, 0xa30d1871, 0x90773ce7, 0x31d02ba4, 0xd1ddb8e0, 0x66e7c6e0, + 0xc5f4ac88, 0x89fdf5ad, 0xcee1b5e1, 0x7a9770d6, 0x82a94fba, 0xdc1f8350, 0x15d0c74f, 0x984c25c0, 0x16fd190d, + 0xd64d4ef2, 0xad068826, 0xced26c1d, 0x4e5f8e1e, 0x533d95fc, 0x26290c62, 0x91ceaaaf, 0x79a81e94, 0xcd3cc746, + 0x63277259, 0xea0a8c0b, 0xb9c32de9, 0xebe1001f, 0x99eb6385, 0x05abaa01, 0xd1d1e4bb, 0x281655b1, 0x40380c01, + 0x4064219a, 0x47794198, 0x2c927663, 0x77fd0b92, 0x8c2aacfc, 0x7931f590, 0x85dabb7c, 0x7057c137, 0x2f73a1bf, + 0xd9359138, 0x1281249b, 0x91575db4, 0xd8b71ebc, 0xc2d8a818, 0x1f249f05, 0xd9454c3f, 0x9d374f56, 0xa241a518, + 0xeb26b027, 0x15594b0c, 0xa9b8822c, 0x984d97fa, 0xfdcc2086, 0xc6c97fb1, 0xe72f6efd, 0x2a5c8855, 0xdfffecd5, + 0x1cca1864, 0x0c0b140d, 0x91017c4a, 0xb81b105c, 0xf9da6af1, 0xc5c6051d, 0xe11ad958, 0x419cb5ee, 0xfe5cb5f0, + 0xc637fcf1, 0x187b4210, 0x3d33b093, 0x97efae64, 0x08ab39b0, 0x372f67c5, 0x2dda878a, 0x09bed096, 0x4176edee, + 0xda227f69, 0x1a03e7a7, 0xab7ab077, 0xcb60b5aa, 0xe91a8938, 0xba3ccb7f, 0xa713bebe, 0xdd0cb12a, 0x1a111bc0, + 0xba90bf26, 0x7d7516a1, 0x7de30208, 0x5a20212d, 0x8fba8ef5, 0x5296d0dd, 0x92b1865b, 0xcb43f24d, 0x039d6757, + 0x9a149bfd, 0xce6475f0, 0xbee6dec2, 0x9440a8bb, 0x89de870a, 0x40b2fc22, 0xfb3d0c31, 0xe6ff3463, 0x478bfcaf, + 0x94bf8229, 0x12fd0f2e, 0xe106c393, 0x7090115e, 0x7dafc041, 0x2a893a9f, 0xd1ca60a0, 0xc1f79acc, 0xfb0acdf2, + 0x0cf939aa, 0xc35a62fd, 0xceaaa2df, 0x16550161, 0x79abdec6, 0xc5acddb6, 0x49cd381b, 0xe1dda68a, 0x2eb54da5, + 0xd4377147, 0xdd9a4d69, 0x18d9be41, 0x2dfcdd5f, 0x3515043e, 0x4a1342d6, 0xa1a22f3d, 0x6ba65587, 0xf29f7a3e, + 0xa177010f, 0xdb195154, 0xaaa8f167, 0xe3b1fc98, 0x863b8a24, 0x74ad13ba, 0xa66b4dad, 0xa10fc761, 0x63251ad2, + 0x553adc72, 0x4f8f3b3a, 0x1bb337be, 0x59e2e0f8, 0x4e1bb95b, 0xab3b0459, 0xc29d483d, 0x0efcb27c, 0x61817f6a, + 0xd5b152fd, 0xb844b204, 0x1e7ee5fb, 0xdaf28ddc, 0xa0e2d6ff, 0xbd3f3084, 0xd63111ee, 0x8993a9cc, 0xb4c529fa, + 0xfe37a407, 0xf2014141, 0xec952a70, 0x45acd70c, 0x4595ff33, 0xa77155c2, 0x0b0b1fb3, 0x15a5913e, 0xa84c3727, + 0xd0769395, 0x08291928, 0x3b4a81df, 0x2babc085, 0x3535681a, 0x3e5538b8, 0x38f63e38, 0xc4f028fd, 0x27f8c841, + 0x6087f24b, 0x9e4c54fd, 0xbc05e46b, 0xbae03fad, 0x69bae42d, 0x8f61eca9, 0x6392905a, 0x7e65c57d, 0xbf2df519, + 0xf7983a31, 0xeb873b8d, 0x86787412, 0xdd76176b, 0xc5b666b4, 0xdef0d543, 0x31ce1977, 0x61e33fd4, 0xfe6a62fb, + 0xd6469c56, 0x81b32c56, 0x58763c23, 0xe4d2abf7, 0xe0298b2e, 0x89de9e03, 0xd1d11412, 0x3fa0828c, 0x6661d61c, + 0xba35c39c, 0xa6d32b9c, 0xa3529b32, 0x04b9557a, 0xd1d8437c, 0xb74d2fad, 0x2f6ea018, 0xea5032d8, 0x7fa27763, + 0xac1921c0, 0xfbdb0be5, 0x270f959e, 0x48c329a7, 0x76cc99f8, 0xba34d2fb, 0xb6e2a127, 0x5346d9a5, 0x4d66d266, + 0xecf22507, 0x34a04659, 0xefb677c9, 0xe6245324, 0x6f2fc1bd, 0x027a7402, 0x03c7bbcf, 0x0c5e5844, 0xe742f6e6, + 0x2c256e2c, 0xca7cffe5, 0xff4cb55a, 0xd00ee361, 0x1bf3a425, 0x1e7584b0, 0xaaac1c7b, 0xbf7d9f32, 0x2fda8059, + 0x1d88cd28, 0xaa5e73ea, 0x7031bb5e, 0x88bb8e2b, 0xa1c5bea9, 0x7c526a27, 0x32343e06, 0x83cdcc72, 0xc1f2dd06, + 0xe5f6b38a, 0xda701896, 0x837e0a5b, 0x43d1308b, 0xbd22b8d6, 0x0c3d8ff4, 0xbf6d3665, 0x63965be4, 0xf4937593, + 0xe0df2d7d, 0x81ab7250, 0xe4035b91, 0x2ea9f162, 0x1db95b2e, 0xefa514f9, 0x17e6d796, 0x5a6085e9, 0x94deb413, + 0x9b184c15, 0xb370f926, 0x4a24578a, 0xbcbab222, 0xb8d449d2, 0x423e7b55, 0x2735c3f1, 0x10b7e3a6, 0x654e8c8e, + 0x3f2cbd36, 0xdea0e487, 0xddd9a852, 0x9e0370dd, 0xb0e50e94, 0xc03de49d, 0x0a9ec77b, 0x38a1c1ac, 0xf3d20443, + 0xbefab460, 0xd65dd265, 0x130bdac5, 0x31bd6e9d, 0x1c2e692d, 0x283919a0, 0xd09e8bcb, 0x8d980075, 0x1f3ef872, + 0xf6e2152d, 0xff7ae774, 0x518518cc, 0x71fba614, 0x86cb2c3f, 0xaf52c875, 0x402c146b, 0x411ffd2f, 0x61834ead, + 0xe6d76a30, 0x69d3c7a9, 0xf4ddc31e, 0xb397cfae, 0x7f9ebd41, 0x07ab9e13, 0x4359d2bd, 0x5dc41dbb, 0xfd2e7b8e, + 0xb62270b1, 0x8d13ed33, 0xbe5dc511, 0xedfa8d59, 0x17823f69, 0xad91b1e1, 0xef19184b, 0x49731b25, 0xa0b2bc04, + 0x1931541a, 0x1e91ff20, 0xf4101a41, 0x844648a6, 0x0a6ae4ae, 0x95e3c80a, 0x3c0ea6b0, 0x89554402, 0xd7d40d86, + 0x3d072dc4, 0x0cfccfa8, 0xd016f7cd, 0x64a13d1b, 0x5bad7431, 0xd4e86129, 0x5a70dec8, 0xf32621cb, 0x1e284590, + 0xe53e5694, 0x71e481bc, 0x917e79b1, 0xbd64eb70, 0x00eb71f6, 0x25156484, 0x616dbba8, 0x4cefdaa2, 0x4efbffe5, + 0x9b8a3f09, 0xe7764012, 0x8c49b27e, 0xb846eba8, 0x0eaf31ff, 0xb499122f, 0xc50b1c2f, 0x2e4afcf1, 0x2647afd8, + 0x11ca93ee, 0xc7356788, 0x3a7a1b83, 0x34beb641, 0x454fe56a, 0x62d60a13, 0x71470310, 0xc282ab37, 0xf2058f2e, + 0x13b8500b, 0x6e88b1ae, 0xa98c2fda, 0x3760c873, 0x4f61c69f, 0xbbf99305, 0x7e635e80, 0x5be96b8b, 0x90598d8a, + 0x628d13c6, 0x5c75035c, 0x0afca5d8, 0x39aa6d80, 0x4d7b9604, 0xdbdc1286, 0xf931c97e, 0xe94f1703, 0x5d47d9f8, + 0x1a757c00, 0xb4fc4ba4, 0xee402fdc, 0xce9343eb, 0xf5b604e1, 0x6d4a1f4d, 0xc9b96d1b, 0xa1782284, 0xd76ad1cb, + 0xdb80ac58, 0xe8dddff4, 0xa29bf6e4, 0x8d61e74d, 0xf2a7574d, 0x96f8bcce, 0x1c836244, 0x5b890733, 0x7b33fb7e, + 0x1125a810, 0x96e9c603, 0xeb37477b, 0x66a3bc56, 0x36386c55, 0x7e5b075e, 0xead94d5b, 0xb2aff755, 0x0553c291, + 0x6339fff9, 0x88fa7bd7, 0x30fdd77b, 0x444b340f, 0xbc28f694, 0xdcfdd054, 0xeb7b3bbd, 0xf8ba62e0, 0x273f05bd, + 0xabc2266c, 0x69e2d855, 0x0d0910fc, 0x573f3607, 0x0d1a8193, 0x66fa736d, 0xe425a074, 0xb7dac4f3, 0xbea80809, + 0x2d7e0019, 0x6e15e47c, 0x8c2afb3f, 0xb08c40a0, 0xcbda7756, 0x8907499f, 0xebaffee6, 0xe808c020, 0x38a07394, + 0x3e64eb7e, 0x4c02bdf1, 0xe40c289c, 0xf35003f3, 0xe983da6c, 0xd472a648, 0x610e632a, 0x3dba82e4, 0xc2348b01, + 0x8d0ca2f1, 0x53cd1faa, 0x3249efc3, 0x84354bb2, 0xc4d077cd, 0xd3bcc732, 0x23e2ba2c, 0x7ef7920f, 0x31a86e22, + 0x9112b6a9, 0x35d83040, 0xf8ecdeb4, 0xee8130da, 0x337c9197, 0xbc714e71, 0xb32baefe, 0x55b5f2cf, 0xcb009de8, + 0xda9be79a, 0xc6e8a1a8, 0x7039ff9c, 0xad3fe5be, 0xa3063042, 0x0d0dc8b3, 0x73435211, 0x6a49c9b1, 0x2c95424c, + 0x91e9d213, 0x0cc4f221, 0x2da7bbcd, 0xc5484865, 0x89f29063, 0x3a34675d, 0xd2399c11, 0x93d3203e, 0xf622e7dd, + 0x07b850b2, 0x021fa559, 0x12da57ad, 0xadd0bed3, 0x19ff5dc3, 0x6e4a13d3, 0xbcb6b527, 0x6a706222, 0xc271d49f, + 0xea3f83c3, 0x9a8d421f, 0xb94c2218, 0xe260cab8, 0x6dfaa189, 0x52e8e44d, 0xa29d31ec, 0xc847346b, 0x582c1660, + 0x2ea6f8c5, 0x35b5a980, 0x9ebd8e47, 0x5f76d230, 0x74ef0f3d, 0x610efdff, 0x3883369d, 0xc895bb94, 0xba2dc616, + 0xc294881a, 0xcb0f025c, 0x3cdcf051, 0x0f196095, 0x27adfa89, 0xb722fffc, 0x0b743d59, 0x27f388e3, 0x3f2320fa, + 0xf034985d, 0x1310f7d7, 0xf466ccdd, 0x26b9b124, 0xa1ad2194, 0x903c5911, 0x704baae9, 0xb6934209, 0x96d87ab3, + 0xc16e891e, 0x9b924917, 0x80d9a83d, 0xbcb188de, 0x18833632, 0x913d4a18, 0x7918d1d2, 0xc9e01487, 0xbe55069b, + 0x06ab0e59, 0xc1444bc9, 0x12d38176, 0x786b439f, 0xafaa2dae, 0xb66b6e32, 0xa00245e8, 0x0f567baf, 0x27d63fbc, + 0x3582e82e, 0xe30e5ad6, 0xb1a080c7, 0x8bbad1fe, 0x7803e18b, 0x46b9c593, 0xec0bf392, 0xda18ba11, 0xb8abf68a, + 0xd75a1173, 0x7ff1852c, 0xc0f5d3e1, 0x2c91c17b, 0x7151245a, 0x6dc0e0d6, 0xffddc8cc, 0x4cdc4ab5, 0xf04bdaf5, + 0xa4551a91, 0x57ed1976, 0xedb51e5d, 0x4fc1ffa9, 0xee29aaa4, 0x6ed62a0f, 0x520efbce, 0x009abfc3, 0xe855a69d, + 0x1f72c447, 0x401102a2, 0x3b062edc, 0xc0963e75, 0x69f65689, 0xf5a70865, 0xf1c23b58, 0x28355500, 0x8368b642, + 0x08226438, 0xb1edb7f9, 0xe4d8aa89, 0x99b6d9ce, 0x044d9801, 0x272b5a6a, 0x49c87a89, 0x85cf58c7, 0x89f22bc7, + 0x505d9087, 0x5d12d90c, 0x6b76cdf4, 0x17e6350c, 0xc7d1cf5f, 0x89dd3661, 0x6f5a51ab, 0xf4e7d404, 0x0fb92594, + 0x31708c1f, 0xcdbccf62, 0x73634039, 0x43fc0f67, 0xa76ca4a0, 0x54852e47, 0x2135c923, 0x3f1e499d, 0x9db74184, + 0xa06edddb, 0x12e6a05f, 0x08d89ab9, 0x3031ab13, 0x09aa31b0, 0xe0b55d02, 0x0241c259, 0x9c19005b, 0x269b5734, + 0x521384d7, 0x9fe517b4, 0xfdbb4d7c, 0x466f49f6, 0x4209ca40, 0xb5d42f48, 0x41a651d2, 0x0ac1c8c7, 0x17970c73, + 0x6e3a9fc7, 0x098c83b4, 0xe1596b91, 0x9301f432, 0x2cccc769, 0x5335d698, 0xab541df5, 0x2b676854, 0x384149ac, + 0x1e8d8e1e, 0x9348bce3, 0x42e05ad4, 0xde6efe89, 0xfab792ad, 0x9da42084, 0xa0a01d0f, 0x4094a329, 0x227cffa0, + 0x5aca49d2, 0xcb3bc36c, 0x6d876558, 0x6e7277ea, 0x2ab75c77, 0x3a357025, 0x021cca9f, 0xb530c505, 0x9c0972cc, + 0x090754e8, 0xb33dd8f7, 0xaf530555, 0xab863a54, 0xf10aeda8, 0x1a11020c, 0xd5ac17fd, 0xddf1107f, 0x68a3c712, + 0x104bad9f, 0x2d6ba656, 0x853d4abb, 0x1f4b3f99, 0x2e9cb659, 0x93c726f1, 0x6c912ddd, 0xc906c6d9, 0xb438dfd1, + 0x5644c32e, 0x44864220, 0xb72b8e99, 0x9b2b9551, 0xdfd7043e, 0xcb9dd008, 0x2f8d83b2, 0x3e585ee6, 0xab5c93c4, + 0x33d867c4, 0x94da268f, 0x8ef1d1b2, 0x1aaf5a06, 0xb43cbc5b, 0xd245764b, 0x197285bb, 0x6bc66950, 0xdac74208, + 0x3908135d, 0xc5fbcde2, 0xfe13c993, 0xfecaeb83, 0xad07bdbb, 0x597e8e09, 0x4e80cf31, 0x90c1681e, 0x83ab45f9, + 0xcb6f747b, 0xecb0c2b4, 0x5eed8202, 0x05bcd863, 0xc9720178, 0x76d9c353, 0x44776a51, 0x41884871, 0xbfce103c, + 0x179adaac, 0xbbc26620, 0xfa997827, 0x2de80cfb, 0x1ce11f20, 0x441d4737, 0x10fd09a9, 0xbdb79824, 0xd4e48d66, + 0x46befb5c, 0x064f7749, 0x021a80f7, 0x93499197, 0xa3057088, 0xd9400575, 0x9b1e90ab, 0xdc57044c, 0x313b3044, + 0xc7738429, 0x27c0284c, 0x3e8e1e4f, 0xc488fbe6, 0x1f3e9466, 0xb73414c0, 0x506ec189, 0x250a3a42, 0x143093ba, + 0x8652f5f2, 0x2c443b8e, 0x2641fe92, 0x0d9cbd36, 0xf760ebc7, 0xbc422e9f, 0xac254fb2, 0x3f656327, 0x224e4d82, + 0x64fadd3b, 0x50c24fe2, 0x02ac5c59, 0x31221d64, 0xfadff4f4, 0x1e5cc89d, 0x2abf46c2, 0x9821e574, 0xb4a6f74f, + 0x87d1529b, 0x3837821f, 0x4ae4b815, 0x8b391ee8, 0xa75745dd, 0x8aa2b476, 0x376b46c5, 0x99f56f9d, 0x3547ecd4, + 0xd614e2f0, 0x81a08445, 0x44ea1262, 0xc32e9a29, 0x05a3112d, 0x419ef228, 0xe7808351, 0xa7bfa62a, 0xfd666926, + 0x9a255360, 0x0d2086d6, 0x434f6aac, 0x9b10ac90, 0xfc989361, 0xba1f2c42, 0x9832e790, 0x51d467c0, 0x0550ea9b, + 0x898cf235, 0x4b73f6fa, 0x1376743f, 0x25cdd9fc, 0x451287a7, 0x87681931, 0x6b694887, 0x2092fabe, 0xcaea03d6, + 0x8efe1739, 0x76005a38, 0x0db719ce, 0xca8a70e3, 0x5515eb91, 0x5a8ea242, 0xf81dbfeb, 0x78f3ea80, 0xe635be67, + 0x81415517, 0x71296b0b, 0x687c2935, 0x91ed32de, 0x32f40adb, 0x47aa0663, 0x80f98c42, 0x78cb3af3, 0xb7cabf70, + 0x68cf8f53, 0x18bb5494, 0x8b226af2, 0xe0e24106, 0x5c5e64bf, 0xcca91808, 0xd29cdb86, 0xecca2a0f, 0x1efa8277, + 0x07faa9e7, 0xf0ae8c54, 0x37dc30f8, 0x9292e8e3, 0x271e0bac, 0xbfde4a9a, 0x08ad8118, 0x9af65946, 0xdb2d94bb, + 0x007f9cfa, 0x19180e48, 0x1953c660, 0xa5e8ced9, 0x01e8c676, 0x76da29fa, 0x6664d05e, 0x20521549, 0xd829af64, + 0xe674c5b7, 0x5ae567c1, 0xed590a14, 0xbfeef006, 0x9ebf65c5, 0xe5583ba1, 0x40db8f15, 0xf4eb7b10, 0x48778602, + 0x5147b3cf, 0x436d006c, 0x3983d249, 0x9cb90387, 0xbf3c3e66, 0xe1a55415, 0xd24e66e9, 0xdaea1266, 0x57ebf16b, + 0xdcf71aae, 0x8a145f24, 0x2ea9aa7d, 0x558f8d56, 0x73ff5bbd, 0xad7e33e1, 0xb42a9996, 0x6fd50777, 0x938ca22a, + 0x44aff91c, 0x1eb6959c, 0x0f255eaa, 0x0d4adcbc, 0x5993e247, 0x55ed7013, 0x09f2741a, 0xa3be9179, 0x1624242c, + 0x3607b59f, 0xc1f69fe2, 0x313597e4, 0x28636b4b, 0x24e1d947, 0x8da00594, 0x637fbf48, 0x59f9743b, 0xed840d7c, + 0x7d57348a, 0x61d07653, 0x3e6c6946, 0xa717d116, 0xb60247d8, 0x6996ce56, 0x9287d2c5, 0x81a2aabd, 0x58f79064, + 0xfdfa191f, 0x6a1d5427, 0xcb3ec5b5, 0xd64b678e, 0xb633486d, 0xbe9adf37, 0x96fc2b3a, 0xe05a3010, 0x61e56323, + 0x5fe4cfae, 0x02f9adb0, 0xc6d1ae86, 0x7e514c55, 0x42e5b49b, 0x1a0fd192, 0xf375faeb, 0x744df908, 0x9b2e3fc7, + 0x05219c5e, 0xb9123045, 0x6ab2a272, 0x3b4360ad, 0xf2696cdb, 0x22873f07, 0x014eaf66, 0x663693f7, 0x9b25e888, + 0x9a0c2eea, 0xbf970d1b, 0x3b2fcad8, 0x94ba0066, 0xd5fa4381, 0x2fbe155d, 0xc14c935d, 0x1ac416b5, 0xdf5eeff4, + 0x4904deb1, 0x2667acdc, 0x8a343a0a, 0x5844667d, 0xfccc22eb, 0x532f311c, 0x4fcb3d42, 0x8acc4810, 0x0ce59e1a, + 0x896e397b, 0x956b1220, 0xfbb5cb33, 0x52740a65, 0xf747a183, 0xed8b3efd, 0x1fce60de, 0x3c71aa11, 0xcc7af74a, + 0x4d6c4a06, 0xe77b5659, 0x0c9ebe57, 0x2b28ca7a, 0x29e289f5, 0xe923573d, 0xc9d20222, 0x9a339943, 0x1f2ce54f, + 0xbcbc4347, 0x5b290044, 0x2365fe58, 0xd40be101, 0x41f47590, 0x4b40d226, 0xd225a8e7, 0x52c68f37, 0x9033b619, + 0xaf77a511, 0x226de7e1, 0x5b8b5c92, 0xbb5d0752, 0x22aa9239, 0x70d52605, 0xbb6dd446, 0x66abafc6, 0xe80ff4ed, + 0x07e0b786, 0x1fb15b27, 0xf0364c9c, 0x7525bf42, 0x9ede2822, 0x0edc05f7, 0x27b0df83, 0x67fb6fa1, 0xe6dc2f54, + 0xc901c0d9, 0xb2826a05, 0x69b245a5, 0x3bfb54bd, 0xc44ccfc8, 0x372cd712, 0x41cc0270, 0x8e0c9e7c, 0x92b18754, + 0x7742b970, 0x35031cd6, 0xba2f02ec, 0xff45abd1, 0x1ec6bd03, 0x624b366b, 0x4b6de80d, 0x25c3a7d5, 0x2f4d0c23, + 0xf670d8e0, 0xc2a23d62, 0xee0e876e, 0xc7f317c3, 0x1fd9356c, 0xf7eca713, 0xfaa37867, 0xc6c010e8, 0x893fb363, + 0x9768d6f7, 0x7be78db3, 0xb68b2f23, 0xf2c3dad5, 0x75c09c20, 0x16dc68b0, 0x462b8060, 0x76fd56e3, 0x81076ada, + 0x51343cb1, 0x65c154bf, 0x43235e83, 0x28e3fdee, 0xdf05a64a, 0xefc055c8, 0xf45b3a33, 0x3103a3f5, 0x19a44828, + 0x01dbc5f7, 0x03878023, 0x21a7a0bc, 0x32c6c0a2, 0x75763f50, 0x463efd31, 0xbfd99781, 0x2d395eda, 0x0cc94956, + 0xfd8b0d4f, 0xed2363c8, 0x538a20df, 0x6d864527, 0x035a8b6e, 0x7af2f7ee, 0x61f9637f, 0x0657d061, 0x13043921, + 0x8cdcf254, 0xe44b047a, 0x208fdd7f, 0x86f85d54, 0x76a37e31, 0x9c1454cc, 0x7769f2c8, 0x2f42726e, 0x286022e2, + 0x30b792b1, 0x6ce755f8, 0x699604ca, 0x3006d382, 0x7639db93, 0xe60a25e2, 0x8f072404, 0xf0b0ef4a, 0x542bf694, + 0x834d1143, 0x0dbf82c0, 0x2500143b, 0x3e84f3d2, 0x0825131c, 0xbc06420a, 0x326d19f8, 0x0e87c14d, 0x2d816ce2, + 0xd581004d, 0xf9cca66f, 0x7513d434, 0xdb31b06f, 0x44c8ab77, 0x84aa4ddd, 0x1dc25849, 0xbe663c8b, 0x4fed64a4, + 0x81e763a5, 0x1a032b77, 0x0c447105, 0x26d9cf57, 0x6f3bb80a, 0x5ca07e17, 0x9d10c737, 0xb9cf784e, 0xa9fceeba, + 0xd8b5802c, 0x72c15484, 0x078b627a, 0xdcfadbd8, 0x1477bd38, 0xdbcd9075, 0xf958b07e, 0x0584df63, 0xfe625a42, + 0x5b22cc2c, 0x37650275, 0xc450f0d5, 0x0a1f8aba, 0xb646591e, 0x849084d5, 0xb61caf34, 0x62135251, 0x8a3c4062, + 0x34a69d76, 0x75e738e0, 0x44ed6194, 0xae554f11, 0x2e177c91, 0xcfdf997d, 0x9e4ebeb9, 0xc586c487, 0xac815956, + 0xf5bc680e, 0xc9715662, 0x4becbe67, 0x9a744a8d, 0x6c30f248, 0xa6104ebb, 0x42c6cf73, 0xeb66d23b, 0xbe93b600, + 0xa88b91ca, 0xf3645ba2, 0x8aeaa883, 0x33a63bb4, 0x9af564d6, 0x2b8f80d3, 0x1956c20d, 0x4675db32, 0x0e62e9da, + 0xe7f408af, 0xb85399fa, 0x09998571, 0xb9061b9c, 0xa1a31a2f, 0x626ba783, 0x1ee9592e, 0x8260a2d2, 0xed436b1d, + 0x75a60c4f, 0x77d0278d, 0x3a974f32, 0x282115f1, 0xc1fc1918, 0x34c3aa26, 0xdf626dbb, 0xa6f8e2ff, 0x557029ef, + 0xe7a95f37, 0xabbe6ed7, 0x60cc6191, 0x74bf099e, 0x37fc06e3, 0xc1b1d3bc, 0x51c53c17, 0xcd2943f7, 0x0b7a29ad, + 0x5dd376f5, 0x75d38d80, 0xdabfccc0, 0x1da341f3, 0x4033ca32, 0x539476a9, 0xe55a4c71, 0xacfe975d, 0x51cc41a9, + 0xacb67c49, 0x9b304a14, 0x67fb95b9, 0xba5f2be9, 0x8527c409, 0x1ce183bb, 0xd77d2e5b, 0x74fe7f48, 0x6e823647, + 0x0067dfea, 0x2cb84fda, 0x84a5c759, 0x76ff064b, 0xc34061ce, 0xc17f1675, 0x58b0c75d, 0xc17e97b2, 0x1acc9a48, + 0x1605bc50, 0x155b5698, 0x80b77120, 0xc14542c4, 0x4426d8a0, 0x6b272068, 0xc9bea571, 0x1227b3a0, 0x61a2a2d1, + 0x35dc54fc, 0x1ecd3b90, 0x652d8d8a, 0x5f6bd317, 0xa4905314, 0x9e081ea2, 0x877c74cc, 0xf7121fd7, 0x2ea65bbb, + 0x44b945cd, 0xce8db58c, 0x63c228b7, 0xccfa669a, 0x1dce2cda, 0xce6f6527, 0x9b67b3f0, 0x9b7ec02e, 0x5760d2f9, + 0x0510cff6, 0x9baf7145, 0xb1bab5a4, 0x7a601afc, 0x1c34da97, 0x90373f20, 0xe12a2b2d, 0x8a7aa31c, 0x8ec98b3c, + 0x0dc3f75c, 0xc8f3ba9b, 0x376d0377, 0x54350d1f, 0x02ab05e2, 0x43c3a11b, 0x9c9c5153, 0xfec077cf, 0xa623103f, + 0xbd39eb64, 0x25213239, 0xd08e627e, 0xdfe4c039, 0xfb05c193, 0x4a1101df, 0x9f1ecdd5, 0x37ed140f, 0xfe73b066, + 0x629a03ed, 0x48d26f76, 0x8e492efb, 0x05f93c0f, 0xf576a278, 0x61082f24, 0xefbd5673, 0xf9bd0df7, 0x2b962a9a, + 0x5636f408, 0xb7f35333, 0xebcf9821, 0xbc619be2, 0x3914792b, 0x2cef9d0e, 0xce8bc866, 0xdd2fd821, 0xbff9fab2, + 0x8366a007, 0x15ac2e60, 0xbddc3fe6, 0xa911cab5, 0xc772c323, 0x026fb517, 0xd728126f, 0xc65fb8dc, 0xd0724411, + 0x28138150, 0xf0d44913, 0xcda6b2a2, 0x4c90bc3c, 0xbe7d6444, 0x40d8ee07, 0x6a0f1c06, 0x5f1e01a9, 0x8572b092, + 0x02d846d0, 0x259ae394, 0x71621652, 0xfb8f3850, 0x1a25b144, 0xf13c819a, 0x5ad21dbb, 0xd8cdd3d3, 0x9bab89ac, + 0x3cadf5f1, 0x653ce0e0, 0x2a805484, 0xc8e527de, 0xdd2e6746, 0x99207960, 0x56ad944c, 0x55dc8f40, 0xe01f6bcc, + 0x35d7abd3, 0x79e67ffb, 0x7bc67e9d, 0x1e4f4af1, 0x8e663609, 0x2f8ea0db, 0xdb76fb75, 0xde6ec338, 0x441c2d82, + 0x27499d54, 0xace77ea4, 0xd4ca84ac, 0xa79fa5b2, 0x2bc4593e, 0x9dd1b08a, 0xed7c9851, 0xc4b8740e, 0x7ed4951e, + 0xb4345022, 0xf01ab72c, 0x370b002d, 0xf77b42ab, 0xf31a6292, 0xcd1ba090, 0x5cc92933, 0xf0a19bbb, 0x8da7852d, + 0xe04f4d40, 0x8bb9c5d8, 0x0abf7170, 0x456c0223, 0x22bd48fc, 0x4f6bb02f, 0x2cf25014, 0xc04319dd, 0xec1902ff, + 0xc5910d2a, 0xc98a6b2a, 0xd4b3b783, 0x0f5859b2, 0xa0b064f1, 0x5b06bb8b, 0x3c2ea9c1, 0x22984050, 0x7060a2df, + 0x81059d5a, 0x9439a699, 0x0b947505, 0x232df09d, 0x900426a8, 0x1a95d021, 0xf9308a3a, 0xbe3dd7d7, 0x41d772b5, + 0x60bd5520, 0x8d280180, 0x443face0, 0x31fbdb5e, 0x8824a794, 0x3bb965d9, 0x205a6e8b, 0x93e73943, 0x17a813ae, + 0x59dfb0bd, 0xfb72a0fd, 0xca6d5e3d, 0x4e1976ef, 0x1645131f, 0x2dc758fa, 0xbd899943, 0xff44e07b, 0xe38c6b17, + 0x9403d0a3, 0x3eab5ee6, 0xe9b4be25, 0x3961db57, 0x67bed90d, 0xd10de614, 0x1b3e2374, 0xf983c67c, 0x3b964c5f, + 0xffa513a0, 0x09cd68ad, 0xcfedb51e, 0xaaeb958e, 0xcc92c79a, 0xc8cfb431, 0x5d6cb833, 0xe7684b5c, 0x3ebc7937, + 0x6f45f740, 0x3ae5584a, 0x0307eae4, 0x1de8ebfe, 0xaeb8246c, 0x280641d1, 0x74cc32cf, 0xedb56ff9, 0xe2006b33, + 0x0cb9c21e, 0x7e4caea4, 0x3a760d00, 0x6a095b62, 0x21e18305, 0xe4fde03c, 0xa80f8fa4, 0x1db257e4, 0xa9f19559, + 0xecc2fa68, 0x185c9ad0, 0x15bda7e6, 0x6cc00bd2, 0x52dce410, 0x14d230f9, 0x1893981b, 0x03844b84, 0xd59c791f, + 0xc6e4a5d5, 0xc8ba16e8, 0x353d3463, 0x78968fe7, 0x92badd56, 0x03d3d183, 0x1bed66ae, 0xfcca3d90, 0x0389483c, + 0xae5848d9, 0x5f2d965e, 0x9e4c7adb, 0x5e1ed6a0, 0xaa3532ea, 0xc3df999a, 0xa0ebd17f, 0xc84b0283, 0x36db1d24, + 0xad2d4a44, 0x98522018, 0xfe54dbe6, 0x548b84b7, 0x9e7df1ea, 0x1f45071c, 0xb5301cc0, 0x9d71827d, 0xf5f90ac3, + 0x3c4906b6, 0x0cde300e, 0x6107874c, 0x2add8d94, 0x50a188ec, 0x5d9fcedf, 0x5c312927, 0x4757ef63, 0x290cd8d7, + 0x629a45b5, 0xe2a7987b, 0xdaa3e732, 0xdebd696f, 0x2e5b12f5, 0x39bf73a9, 0xf62a12ba, 0x358138e0, 0x8215e9f0, + 0xee73f63f, 0x9d570189, 0x5c7e5b23, 0x9bbeabf4, 0xa1357081, 0x85aa4cbe, 0x8b2897a5, 0xaa38b33e, 0x12f27d3e, + 0x31a58596, 0xc680802c, 0x62c27e58, 0xc5ebbfd2, 0x9365a6c9, 0x8f7169a0, 0x48016a66, 0x7ab10fc4, 0xf1120775, + 0x6bea072e, 0x01cae4ac, 0x19428199, 0xcce5e0fa, 0x06c7f7aa, 0xd7e013a5, 0x1c23ff68, 0x5da8c8d3, 0x39fa89dc, + 0xb26d3a88, 0x8bb287fe, 0x3f02876e, 0xf464e2ab, 0xdab1f883, 0xba29605b, 0x3b8dd77e, 0x837b6543, 0x447dd66b, + 0x66f3cee5, 0x541fc77f, 0x531669d7, 0x1b2371a2, 0xc26f95e1, 0xead4d41c, 0x0150c1ec, 0xec171306, 0x10530c35, + 0x84bc1596, 0x4a87e243, 0x2e13d2de, 0xaa140172, 0x80e494cc, 0x3e9efb61, 0x5a52d29a, 0x1a8f27e1, 0xd26f6932, + 0x8e72d0cb, 0x4fbcfcef, 0x80289af5, 0xe98bfe4b, 0xa9a761c4, 0x69feee99, 0x04fd612b, 0xbc6d9ed8, 0x1b456f17, + 0x324b37fd, 0x4c684d8e, 0xe72cac40, 0x2abdd76f, 0x85c9d723, 0xc7f7cd5d, 0x57d5d157, 0xff8605d5, 0x41eb4138, + 0xbb63e284, 0x49ce81b5, 0x1575cb37, 0xbf7209b2, 0x3c7e3297, 0xdb6dfddd, 0xe8d808ed, 0x5827112b, 0x5fe174c7, + 0x42b84022, 0xab5fd01e, 0x6913ba4f, 0xb0487529, 0xd08298f4, 0xd0e30ecb, 0x5e069d7e, 0xfe606f5c, 0x366912fa, + 0xc40b80ff, 0xdef8a8b3, 0xb7ab6d3b, 0x7b696027, 0xdff13dca, 0x630df239, 0xfec5ba2d, 0xf3153b4c, 0x51fec5a4, + 0x14c0fde9, 0x907495bc, 0x56523311, 0x03da202e, 0x4f9d0805, 0x1c2f7cd1, 0x86bfe397, 0x6be1633b, 0xc117b6b1, + 0x6fee65ed, 0x55bc7855, 0x861ba647, 0x7ace172d, 0x4499a4c9, 0xbcb78f72, 0x1200a67b, 0x706ff735, 0x17ce710a, + 0xcec1fae8, 0xbdb6a2f2, 0x16bbba34, 0x5d5f1c2a, 0xcabfaeed, 0x533f6f31, 0x80fdeb4d, 0x4d0df29c, 0x1e193336, + 0x5e9d9cf8, 0xf197987e, 0x280b433c, 0x50497345, 0xfa24bb51, 0xc7cce7f1, 0x3bdb4fd8, 0x59a17210, 0x6c204d13, + 0x5cebb3ca, 0xd93ce5e5, 0x8f0011af, 0xe2db81e2, 0x1ab5afd9, 0x8666095e, 0x6f34f27c, 0xb288338e, 0xecedcb1d, + 0xa9f3f5de, 0xc6c2ac9b, 0x2761758b, 0x9430a7af, 0x18bfb084, 0x215c8116, 0x3eaeaf50, 0x0c15b2f4, 0x8cf5c993, + 0x8c82938c, 0x15d8d231, 0xde908e3b, 0x3943d985, 0xbb98c024, 0x2f63b5be, 0xe5142c6f, 0xda7af814, 0x7a64d242, + 0x4e82f078, 0x3745c70d, 0x5005d55e, 0x407235d9, 0x8d29fd04, 0xb6d7c337, 0x3bf974ec, 0x1f24e907, 0x214baf6c, + 0x1037ec5a, 0xca1aad03, 0x30ff846f, 0xac292e83, 0x2c8d3719, 0x027b40f1, 0xfc8692c1, 0xd943f371, 0xe62b99a9, + 0x89103303, 0x753cd605, 0x02f91d0b, 0x55597662, 0xd97dcdf5, 0x9df93e72, 0x01dd270f, 0x208812e7, 0x20a6bc40, + 0x45c3ae7b, 0x0669560d, 0x5965729d, 0xbba85f97, 0x4c0d4250, 0x987454ac, 0x308ed9e8, 0x349be799, 0x4297a05e, + 0x0dc0c1e9, 0xf90710f8, 0xdbc7ced0, 0xe6cebd6d, 0x6613ce26, 0xfdf67621, 0x6470ba33, 0x32b4300a, 0xc588dd91, + 0xbcb57af8, 0x2fd074ed, 0xe8e970f0, 0x6c733d83, 0xcf43e746, 0x9335944a, 0x31a2c2e3, 0xa46b0f3a, 0xd7e1220a, + 0x9e9e4897, 0xef56f474, 0x73cbf6ee, 0x47e2bee5, 0x4057c3f3, 0xe01e9c59, 0x40c6d191, 0x7a92e840, 0x518ee960, + 0x8894a937, 0x37d21904, 0xedbc6002, 0xbd14d549, 0xf6a5c4ad, 0xa91fdada, 0xb64f677f, 0x85d57b79, 0x98804062, + 0xcfb8c06d, 0xe40cf91d, 0xa759cf7e, 0x36eb463f, 0x13a39421, 0x04224143, 0x2a26f1d5, 0x48526286, 0xe7f7b453, + 0xc6e73fd6, 0x7c7d3115, 0x9cc78d84, 0x284e7251, 0x2b668a96, 0xb281cba0, 0xba021a81, 0x88c6a74f, 0xe434657d, + 0x9433e77a, 0xac1d9509, 0xcc5cd000, 0x7fe29d47, 0x76af7988, 0x58628ce3, 0x4be5eb7b, 0xf38f4c39, 0xeb994442, + 0x78acfe04, 0x1fba54de, 0xc81a4ffe, 0x4ac7502f, 0xea9c17f4, 0xb3ff9137, 0x6547717c, 0x34d25a08, 0xb7c4ce21, + 0xfd412e59, 0x9f50062e, 0x3e7bf432, 0x1bdd7980, 0xc1c4d686, 0x82badb7c, 0x98e8780d, 0x363c8450, 0x863711c2, + 0xce015f2d, 0xa5eb0b5e, 0x3534b30d, 0xaa869ccb, 0x1a4ba363, 0xdc78780e, 0xd522bbbe, 0xaf0fb006, 0xa9e8f843, + 0x21214053, 0x4ff0617d, 0xa625664c, 0x7c3798c1, 0x7731698f, 0x0ea7cc90, 0xa1d37c6e, 0x8d6ffc3f, 0x0056be4a, + 0x8219c2a0, 0xb36e2cfd, 0x71756318, 0x1375d9dd, 0xd55c5ee7, 0xe73e9bcd, 0x04748924, 0xe7546b43, 0xb67fb1e5, + 0xf0bf86e6, 0xffaa7c26, 0x6c7cf370, 0x0db5a34d, 0x5095b158, 0x6471587b, 0xdbbb0501, 0xd80c8161, 0x58022e71, + 0x6ea37dac, 0x3ce20982, 0x9b046d9c, 0xaa0ca54e, 0x65ab457a, 0x01edc891, 0x82b7b1e8, 0xe899bf4f, 0xa46256ac, + 0x864804a2, 0xb54f9bbb, 0x62ad20d6, 0xc016e260, 0x9948be6c, 0x5cc33427, 0x138e5bec, 0xfdc8c778, 0x3c3e49e8, + 0xee0d3d1b, 0xf729a2a1, 0x1c28f9a8, 0xd6c4f824, 0xe2ece335, 0x9ac6fb34, 0xa81bdfb9, 0x569968ab, 0xcf2b106d, + 0x5e0c5e93, 0x85ec5f34, 0x38ecee80, 0xeda160d1, 0x4b325b7f, 0x0953a399, 0xbc128bf7, 0x461bd605, 0x0b186756, + 0xccb7916c, 0x0478717d, 0x1d720b4a, 0xcdf3752c, 0xd9509c39, 0x68d1cff0, 0x2828baac, 0xb79f0e5c, 0x428e3d13, + 0x4c6aade3, 0x1928f944, 0x6fc9096f, 0x6616d268, 0x6c1d3b15, 0xfe08ac47, 0xe5907684, 0xba5c4629, 0x05f1063b, + 0x941d36cd, 0x7d37add7, 0x46c63ead, 0xe5b4e113, 0x3c9fdf2e, 0x53bf4d64, 0x90f38b3c, 0xaeb21147, 0xaea9b303, + 0x84f64edc, 0xc75ad8fe, 0x414034ed, 0x74113ced, 0xb6606f18, 0x962b69df, 0xff14174a, 0x862646d1, 0xf1127a1f, + 0x518f9330, 0xc00da4ee, 0x9ddfb276, 0x0c1f21da, 0x47d9212b, 0x4cb043de, 0x0710a861, 0xd01fc570, 0xdefe3c2b, + 0x02addd25, 0x67d9b81b, 0xfafeebc7, 0xdf450d20, 0x687cd50e, 0xd69d5173, 0xe089e2c2, 0x918f53bb, 0x5e9a1a84, + 0x7c29c853, 0x85d57c06, 0xfa90d299, 0x29a13567, 0x4676c51b, 0x8e67b039, 0xc3e19112, 0x4346d661, 0xf41eabc6, + 0xfea6acd2, 0xfd4a6742, 0x571e437e, 0x2199dcd8, 0x7a9b0c13, 0x5b12c7f9, 0x526a2dba, 0x2f953632, 0x3223eab1, + 0x1eb33af4, 0xbfa32f9b, 0x61bd8b3d, 0x2b5fec2a, 0xc364bc99, 0x909e060f, 0x2f83acdb, 0x1cb53917, 0xc39030b2, + 0xec09bf10, 0x08449fa8, 0x1c5db53f, 0x3f6fa7d1, 0xee0afaec, 0x5055111d, 0x245ff035, 0x7f82d454, 0x49e87a86, + 0xf1619cb0, 0xf676d272, 0x8c4082c0, 0x16544163, 0x2f94b169, 0xf648cbdf, 0xac4be849, 0x22df1b85, 0x488e0748, + 0x85b8a40f, 0x3b17cebe, 0xde4cd2ac, 0x2b6847a8, 0xb1971406, 0x233328dc, 0x460c57a8, 0x4a066f30, 0x513871bb, + 0x1610174a, 0x338e8de8, 0x2860e142, 0x5991198f, 0x30be7647, 0x5418211d, 0xd55de246, 0x52330ae3, 0x96b910c1, + 0x46e610c0, 0x138e6a61, 0xd781a18c, 0x88b2180e, 0xb4bb85e4, 0xe421c648, 0xbb59bd18, 0xa4e7a9bc, 0x49d417fd, + 0x3aeede0d, 0x47830a0f, 0xf6292b56, 0xf5e4035d, 0x8e6705d5, 0x5d250a5f, 0x52a0d361, 0x118bbf48, 0xb1c2acca, + 0x58b3a0c1, 0x8f7ee63c, 0x4c13781b, 0x6ceeacac, 0xc24b842a, 0xd3bd9865, 0x2cee545c, 0x4bbb291e, 0x0d968e81, + 0x77df63ee, 0xdccf62b7, 0xb4b69e97, 0x97a3e7d1, 0xdc744216, 0x66d475a3, 0x33b0609f, 0xd15fc14d, 0x75d5fd20, + 0x95493247, 0x1fca23f7, 0x030df81f, 0x9253e532, 0x71884c64, 0x4e60be59, 0xc3863df8, 0x4bcfffe1, 0x912000b2, + 0x7e30def1, 0x4ca169b7, 0x8569702e, 0x705e7322, 0x9f07855e, 0x1a15c57f, 0xdb2bc39d, 0x081eae02, 0xf8262f9c, + 0xf64836fe, 0xdb3b5fa5, 0xe4c166eb, 0xde4e627d, 0xda968c26, 0xc45495a7, 0x342950df, 0x4f6a7cba, 0x7a0a1718, + 0xf5b62f02, 0x5baa8afc, 0x7a988422, 0x11eb8d87, 0x7ecbf38b, 0x5b73ab10, 0x2b1c6b74, 0xa4bd6eea, 0xb707d1ed, + 0x2ae14d84, 0x768cb140, 0x9a088fd7, 0x1329d235, 0x554f332b, 0xc95f1cd9, 0x9e52d323, 0xc194c55b, 0x1773c3e6, + 0x1b903c7c, 0xbfb03984, 0x9a8f0aa3, 0x3a99bce5, 0xdd31803b, 0x5fd577ac, 0xd206e047, 0x11137d46, 0x89e3cf94, + 0x35d38a94, 0xd4bf1cea, 0x336ce3d1, 0x0db1da0c, 0xdd18ab00, 0xa73cf4f0, 0x2587eb7c, 0x3b3955f0, 0xc32bcf79, + 0x0be43e82, 0x2c3287d2, 0x70078a44, 0xcde761ff, 0xe0e89f64, 0x9b1e6344, 0x823caa0f, 0xa58b019c, 0x155597cd, + 0xf0dbf5cc, 0x53710d76, 0x145b5f83, 0xd33f2342, 0x87c48cc4, 0x0d42c9d9, 0x541a15f5, 0x718bdd36, 0x85a46932, + 0x9a1339f3, 0x327b2839, 0xa4892b53, 0xf67fdf51, 0xf67c3e10, 0xbe489b15, 0x9b1bcf9a, 0x48352153, 0x61f090b1, + 0xea3a338b, 0x88b49490, 0x61545154, 0xf4f2da82, 0x5d3d3c77, 0xcf343562, 0xcd3c036d, 0x258c284f, 0xde92b7e3, + 0xe3d1cbef, 0xe40670ce, 0xbf848ef9, 0x0100c01a, 0x5aa9633e, 0xb9faed69, 0xbafa3ed9, 0x137707b2, 0x5ec6a16c, + 0xcca4519b, 0x26289c00, 0xd76ea72a, 0xa095f1be, 0x24c5b21d, 0xee00b9bd, 0xe17193c2, 0x3f085418, 0x9489517a, + 0x1b07b2b2, 0x6b1d549e, 0xa32e4910, 0x843175ff, 0x1e9fe0d5, 0x1479b16d, 0xb7d155fb, 0x4d5bf399, 0x69d7090d, + 0x98b20dad, 0x82be8fc1, 0x586e9942, 0xbbc361dc, 0x70354a76, 0x6af5b9d9, 0x10b3c35f, 0xa1147ea9, 0x15a75c7e, + 0x8eaa7c7b, 0xb29ae874, 0x9eb87a16, 0x9653e10a, 0xd69e9804, 0xecb2741a, 0x7e46a8f8, 0xc41450d1, 0x06261044, + 0x23351b2a, 0x193f9d17, 0x3c3a8081, 0xf07aac0c, 0x085b5599, 0x164db796, 0xa928b030, 0xffecca86, 0xd3128ffe, + 0x95616382, 0xffb4fc2e, 0x966101ad, 0xf8a6e09e, 0x03c563cf, 0xb3f82954, 0x13f745b2, 0x6be1410c, 0x7db6a207, + 0xad35f3e7, 0xd0aa48f1, 0xdbe82330, 0xe59d944b, 0x66aaefc0, 0xa1242a5b, 0xad190954, 0x403cd3a1, 0x60c14f33, + 0x868d2f38, 0x06597f1f, 0x27762dab, 0xf58dc94a, 0x3b2a651d, 0x39132995, 0xb29367bd, 0xd927e230, 0x16ce56be, + 0x223b59c2, 0x614d8dbd, 0x9b93e688, 0xc35adef3, 0xef929d2f, 0xe7121520, 0xed5e50d0, 0xe35ba33e, 0xd440aad1, + 0x4b909c93, 0x17236a59, 0x35fea5d7, 0x06d51642, 0xaa67770c, 0xc114c5c9, 0x89be4512, 0xedcbd823, 0xb213eb1b, + 0xa1482d6f, 0x82ea4a6d, 0xb5b9ed4a, 0xa51a75ba, 0x52d7018b, 0xa091a805, 0xc713aa82, 0x0f768401, 0x5a5eadb1, + 0xeac294ef, 0x45f0ec10, 0x376ac3b2, 0xcd4bbab8, 0x246003ae, 0x5c57d0f9, 0xaf5a11e5, 0xbf6b8551, 0x310c2542, + 0x4fd03b3d, 0x826723f3, 0x1f514adb, 0xd0764d6b, 0x90149eed, 0x83e019cf, 0x51f7a2e5, 0xa5b3bf3b, 0x6e8b0f42, + 0xc3a9a32b, 0x629095e6, 0x8896b470, 0xcd9f33d9, 0x1a8d9de6, 0x062f4138, 0xdbd25e52, 0xe54ebb0b, 0x1c17f087, + 0x88dda4f7, 0x7fc7b9a2, 0xcd1951cf, 0x7f7e1372, 0xe0abcfd0, 0x9405e94e, 0x9e35bb88, 0x80eef997, 0xe65e196d, + 0x9c5c1051, 0x8317bf58, 0xcd98a3d3, 0x3e0de339, 0xd92b96f8, 0x7a8e987c, 0x1c480d05, 0x7805a8c2, 0xcde5be1b, + 0x419b9b48, 0x8074992b, 0x641ab52f, 0x299c92b7, 0x6dbfd09f, 0xf2ac4741, 0xcc40ee7c, 0xabab8e72, 0x78069112, + 0x3a973f03, 0x05569a08, 0x930f1cc4, 0xd6b5a41b, 0x6debc057, 0x08ef17a0, 0xf94a52a6, 0xff34fa4b, 0x64109285, + 0x677a2f75, 0x96097870, 0x1c6b18da, 0x67cce8a4, 0x65794368, 0x7df3bc7f, 0x16610783, 0xa33440af, 0xc0d028f3, + 0x22437936, 0x4deff923, 0x1ee55922, 0x11d953ce, 0x6f382ccc, 0x336b4f58, 0x8569b907, 0xe30dd05c, 0x903a331f, + 0xff14de1e, 0x043dc6c7, 0x52791abf, 0xe59a3949, 0x637edaf1, 0x2158ff89, 0xe937b0d3, 0xc960e402, 0x01b9f5d6, + 0x22562a2c, 0x385a7dd5, 0xe3895dd9, 0x18484302, 0x8a27de4b, 0xaf049328, 0xf8a85d18, 0x99581c5b, 0x7bc9bd0e, + 0x7a52a98e, 0xcae2672b, 0x8643ad35, 0xbfe0a9ee, 0x5db1ad7e, 0x73cc2431, 0x98fa4beb, 0x669c16ba, 0x81e1fa5e, + 0x14041a98, 0x47ac4ff1, 0xb231db50, 0x1950885a, 0x03bcc616, 0x212525ed, 0xe632cd64, 0x932c8afd, 0xe3415645, + 0x538ed180, 0x5dc826d1, 0xf1ac2c06, 0xbfe68c08, 0x8af39753, 0xede06afa, 0x6cf80bc7, 0x99e7bc0b, 0xebcdba58, + 0xb5853411, 0x20152d41, 0x0b64e140, 0x9ed14a3b, 0xa3f7f540, 0xacaaab21, 0x7a4dc6b9, 0x25ff8119, 0x1651df04, + 0x5b85b485, 0x71bc03b0, 0xce57c484, 0x9a2693e2, 0x19408a0a, 0xa9e728fe, 0xbc66bc52, 0x439bbc94, 0xcf7b85e0, + 0xcc74bdc4, 0x68f98f9d, 0xbe7b6133, 0xff82b22f, 0x10efb421, 0x670c1687, 0xab1fae7a, 0x2610df07, 0x8debbdd5, + 0x6a1d57e3, 0xf6404051, 0xcea0e3e0, 0x80550e99, 0xc6eef0e5, 0x6a070794, 0x21e6bd89, 0x7caf31b2, 0x400cc8f0, + 0x9a4c238c, 0x21f5fc2b, 0x1f4a9719, 0x2c6371cf, 0x5874376e, 0x1d4f06fd, 0xed623cda, 0x484e3bf0, 0xc63a0f90, + 0x1b9d03f9, 0xd1eb4f50, 0x901062c7, 0xb89e3375, 0xd5e15e71, 0x653b1895, 0xde196995, 0xe6371ce8, 0xf34d7fae, + 0x1fa1f4e2, 0x1598ea21, 0xeeaa5579, 0x68dc426f, 0x46b101e8, 0xef7035fc, 0x57212d04, 0xd485513e, 0xf84632da, + 0xbd4fef6f, 0x3d0c1e6b, 0x0852ad8b, 0xf06695a3, 0xc5580221, 0x6c968ca8, 0x66b62521, 0x31f70f02, 0x2d7ac1d0, + 0x1247f2c4, 0xe0d92098, 0x12ae709c, 0x7fb2ebcd, 0x5efdc58e, 0xfd39395f, 0x818aa696, 0x0767b473, 0x5cc84788, + 0x2a2f8884, 0x31ca137e, 0xc3576733, 0xf7e672e7, 0xb8360366, 0xa114f6f8, 0x7ff4b68a, 0xe925594d, 0xb0db47aa, + 0x155960fe, 0xc143f338, 0x26ee2096, 0x2d5e2447, 0x6a040cff, 0xed511bf1, 0x2e1e800c, 0x396107d2, 0x17879003, + 0x8687e685, 0x79b0ea19, 0x59c5fa0d, 0x83a50252, 0xcdf6e1c4, 0xd9aff215, 0x6e111619, 0x08c42232, 0x0a3b70bb, + 0x74cb9a3e, 0x9e8a80c7, 0x7373feb8, 0x3fd0146d, 0x5bfbd9ba, 0x27a83446, 0x2d7e0320, 0x870ef80f, 0x8b66c058, + 0xd8008d5a, 0x8f371911, 0xc53b8dd9, 0xfd3320fd, 0x3f24d12a, 0x0d67164c, 0x6d787255, 0x8199b149, 0xecbde190, + 0x2e87c592, 0x5283a964, 0x300e5a46, 0x19a7a3cd, 0x5bb81484, 0xacdf7115, 0xc6f824d9, 0xa57793ff, 0x3f0bea24, + 0x6c39282c, 0x8d3ede35, 0x4a96c855, 0xfe7fd84e, 0xc1d409cd, 0x98f7bcaf, 0x13feb367, 0xb02a1b1c, 0x947fa06f, + 0xf853d0ec, 0xe7351eb2, 0x0775f61e, 0x296276ac, 0xcb70e7a5, 0xf1869ce5, 0x9e3aa0cf, 0x29ee3167, 0x9fbc57cb, + 0xc1a756d5, 0xbcc3c510, 0xafed0e9c, 0xf8613a8a, 0x03db8d8e, 0x5f3019f6, 0x0a51435e, 0x281b7098, 0xcfc545e5, + 0xc2e4f13b, 0x320e815c, 0x7b47f201, 0x92374a29, 0xe8c6be32, 0xf591c0dd, 0xe9f2f4c2, 0x5134fe4b, 0x9972bc99, + 0x9fd78b07, 0x76190584, 0xeccd135e, 0x49efbe8f, 0x6fce3fca, 0x60d55e9d, 0x94aea05f, 0x660502cc, 0xf1bb6d93, + 0x1109248b, 0x33fb1a16, 0x10334e88, 0x2744f659, 0x1663b335, 0x44bd7404, 0x26084e49, 0xa498383a, 0x2ae0ac0e, + 0xfd19096d, 0x226073c0, 0xacfa67b5, 0x4659a398, 0xae1535e0, 0xe84e1b6f, 0x44b75e50, 0xa0e6f8c1, 0xaeff2609, + 0xfd4d38e1, 0xd2f48f74, 0xd7961131, 0x6cd56a77, 0x6224d1ac, 0x070a4507, 0xa3c52253, 0x467c060d, 0x2e1997ac, + 0x3acbbbb3, 0xe7673476, 0x47503b68, 0x73c76c25, 0xb9773896, 0x07d6b4d9, 0x28acca37, 0xf3589b9e, 0x1ad66cff, + 0x1f196621, 0x695a0925, 0x976eda1e, 0x8c15e146, 0x09d8aff8, 0x610045c9, 0xaf0f47ec, 0xa1a8eda9, 0x7f7cb1ec, + 0xad90e0be, 0xbe6bb21e, 0x6b5e0916, 0x52fc6e03, 0x234304d6, 0x14adf6c1, 0xd73eefbf, 0x61638849, 0x43836db9, + 0xd3691800, 0x09161dd5, 0xb1153f3d, 0x7294a323, 0x1567debf, 0xf721e058, 0x55a988f1, 0x46c6ddc9, 0xd326c45e, + 0x90ac0cb3, 0xe6c03fa1, 0x6004a8a3, 0x19b47377, 0x4563926c, 0xbee006d2, 0xc12b734a, 0x908b26e5, 0x1d16786e, + 0x59870fd4, 0x34486797, 0x87ba242e, 0x3660c52d, 0xdbd2c715, 0x3796fa44, 0x3b37913d, 0x0039ea70, 0xa392ea43, + 0xe75cae75, 0xcbacd0fe, 0x9f7e818c, 0xdfba2dbc, 0x1ee34539, 0xf2b29d78, 0x22c97672, 0x18eba901, 0x1c1da401, + 0x3600e883, 0xeded917d, 0xcbe40eb7, 0x5661a82d, 0xe89ec919, 0x22fb7c9d, 0xbfea947a, 0xaec826e2, 0x269805de, + 0x36309f6a, 0xeb4838b4, 0xd88745ea, 0x3d70d68c, 0xa3d748cb, 0xae4daaf4, 0x46264d62, 0xaedff63b, 0x32b498f4, + 0x4dd52311, 0x8655f4b8, 0xe461d742, 0x1bbc0be5, 0x4246266b, 0xad5917c8, 0x10373a77, 0xe713f725, 0x72fd1a86, + 0xd0b4ceb2, 0xa354704c, 0xa07fa02c, 0xce127694, 0xbb584b5e, 0x6289e380, 0x720df029, 0xf06453f9, 0xe2640e7f, + 0x44fd0e85, 0x4fde001d, 0x1c4f51d0, 0xf09291cd, 0xf47e14ba, 0x5d355039, 0x2b21ae21, 0xac210f9d, 0x6e39b975, + 0x571f826b, 0x095db4d4, 0x362b888c, 0x24a68808, 0x421f33ae, 0x85607918, 0x6445c51a, 0xdd70da1f, 0x4cbedb60, + 0x4541e2d6, 0x58c619d1, 0x487641a2, 0x1169f90a, 0xdd888c66, 0xa8652a37, 0x880c7c3c, 0x7b9317af, 0x208573eb, + 0x46092b64, 0x03af0e82, 0x9cecffac, 0xa0d7478f, 0x9fa2ba8c, 0x1ca35d14, 0xf8dfeac6, 0xfcfa3c2a, 0xf4ff75df, + 0x6322a7a7, 0x9920140b, 0xb3686793, 0x1892e91b, 0x960826aa, 0x5dafc93a, 0xba378c3d, 0x4a7463f9, 0xe4ef3d18, + 0x39cc6eed, 0xc80546ae, 0x827c68bd, 0xd769e117, 0x5d8799e6, 0x849c33a0, 0x87c69df6, 0xf48ae38d, 0x1919ba38, + 0x7d811b7a, 0x48ea0c7a, 0xc3987ae1, 0xa11e78e1, 0xb7fad93b, 0x56a4151c, 0x4afa5d42, 0x01372462, 0x2b3a132b, + 0x8ad8e015, 0x084120a8, 0x15c0b094, 0xd6a32316, 0x1b09f48a, 0x5c047a93, 0xcf84e27b, 0x02769cc6, 0x7fec6f85, + 0xe73de13b, 0x489eaa05, 0x8e591294, 0x8a0657b6, 0x73f5abff, 0x3079898c, 0xbdd6deee, 0xb9ec5241, 0xe18c94d2, + 0x21f31f6a, 0xa586a70b, 0xb7ae0ff9, 0x698b1937, 0x2dd0e7f1, 0x03910259, 0xec9139d9, 0x9a2c2c3e, 0xeefdf274, + 0xc2186994, 0x1be87bce, 0xf382b735, 0xa69cfc80, 0x78969176, 0x5d918103, 0x73630b08, 0xd77a6eb5, 0x2f2b5d3c, + 0xa6218e47, 0xdadb1cb0, 0xd5b2efd3, 0x2725ecdd, 0x4285e4a2, 0x96c1849a, 0x703c4c47, 0xe9b8ddba, 0x6a0d3bc6, + 0xd95e5f16, 0x6e686834, 0x3b36d495, 0xcf77c713, 0x2c0d9e50, 0x7335ce96, 0x0df45e78, 0xb9d335aa, 0xb7624c85, + 0x60a375aa, 0x56c30fba, 0xb413c238, 0xcb21f87b, 0x04299e2f, 0xbdc6834c, 0x7c9f4367, 0x7591eaaf, 0x261703c0, + 0x8b32079c, 0x0565857b, 0x076956c9, 0x5b08cb4e, 0xc541dd42, 0x74afa5ff, 0x2c7179f5, 0xbcec5dec, 0x01e3f285, + 0x92b0e2b2, 0xd35d5518, 0x9d8fec2d, 0x8a4f244d, 0xdf2f617e, 0x600fc0e5, 0x4454d3e7, 0x1b2151a9, 0xe2bf4585, + 0x83c09ab1, 0x5332f11b, 0x33aa7d2b, 0x004ebdfd, 0xbad92e64, 0xd09732e0, 0x09ea7f7a, 0xf7529914, 0x815d8c57, + 0x9f487334, 0xb912c151, 0xaa7b561f, 0x8a44a637, 0x2eaa1874, 0x4a7998b5, 0x10bb0260, 0xb2916571, 0x2c72d209, + 0xea7136a0, 0xc78afa3e, 0x6b9f9302, 0x0ab8c607, 0xf0d3f807, 0x0a7e438e, 0xfb3a50f9, 0x7da2305e, 0x375adb47, + 0x3e8c85f4, 0xa2ae4887, 0xdf19492e, 0x933440d4, 0xb12fb3bd, 0xd2af3638, 0xbfba92f9, 0xc43d2e2f, 0x0773e346, + 0xadd9b420, 0x95f661a6, 0xe505e9e6, 0x5329e7aa, 0x335952b4, 0x7107e786, 0x46c4d261, 0x9d3719fb, 0x8974e2fc, + 0x64016341, 0x4a386676, 0x4c3400e2, 0x242e8801, 0xc5345ee9, 0xc7bafbbf, 0x16aeca77, 0x3a3b04f9, 0x14bbaf30, + 0x51c5500c, 0xdcbc7fc5, 0x6d5ce2d3, 0x103592ad, 0x42813ded, 0x1b9d836c, 0xd0dd060b, 0x958b1899, 0x09a4eee2, + 0x7e707ca3, 0xca86bf44, 0x09e08e90, 0x0dea4a39, 0x2432c303, 0x22e8e704, 0x616708da, 0x5b277077, 0x6b010faf, + 0x60344e01, 0xa8757fc8, 0x94d9e9b1, 0xb50baa7b, 0x936a3775, 0x4d8091e3, 0xfb7153e5, 0x95768330, 0xf1547ae3, + 0x04cd3b0c, 0xd8334f0a, 0xee4ac25f, 0xf92bb145, 0x2a574478, 0xba8526d5, 0xe646feec, 0x5ea5574d, 0xf85974ad, + 0xe2be42ae, 0x957c2e4f, 0x7c166e8a, 0x2b1cab87, 0x0e227b37, 0xdb14380c, 0xe7e696b8, 0x85bb89ea, 0x93b21a1d, + 0x1bbee909, 0x04012031, 0x42a557eb, 0x6d490229, 0x44267141, 0x47492b90, 0x15003831, 0x9bc4ef99, 0xd1ff5536, + 0xdd47eaf0, 0x57b1a31e, 0x0fff603b, 0xf569cebe, 0xb4514356, 0xa710410d, 0x639e2deb, 0x16d0ea2c, 0xf3d5b8ff, + 0xc8f15281, 0x212fa30a, 0xa1f90795, 0x8c5939ce, 0xb983cf32, 0x5ecb7e4c, 0x3f14b32c, 0x3dc80c3f, 0x43977205, + 0x4e35de3c, 0x8b567153, 0x796f6505, 0xc8de53e5, 0x495feb0f, 0x8cab29c7, 0x79b4c7c7, 0x53a0ffb2, 0xe674a82d, + 0xb3bc2eda, 0x233d9391, 0x7ac7cdb5, 0xe251210d, 0xea9b73ee, 0x286a37d2, 0x67a4db08, 0xb91d805e, 0x1642f33c, + 0xeea404e7, 0x7b7478ed, 0x8f2218a8, 0x089dbdf6, 0x937dc923, 0x4bc2c2f8, 0x95a99148, 0xf631cf0a, 0xd3a8cac3, + 0xb87caeec, 0xa1e7b1d3, 0xd51e9aa5, 0xb9f2c11a, 0xfebb91bf, 0x305c63a7, 0x0f2fd1c2, 0x490bfd5b, 0xa0488d7a, + 0x0262ffa9, 0x54d824e0, 0xf03f54f3, 0xdae11305, 0xa6f2bb93, 0x03f380c6, 0xc9c2dbcf, 0x5b9eb6c5, 0xe69974e5, + 0x66cd1984, 0x8472744b, 0x0877f427, 0x114f5458, 0xf723032b, 0x026da675, 0x955f8453, 0xb3c59a3e, 0xd8a483e0, + 0xba63153a, 0x44aa93a6, 0xf7fa8657, 0x8f0f5f02, 0x4b6c221d, 0x4cf548f7, 0xb310a937, 0xcb18db72, 0x9f2fe981, + 0xcb048ffb, 0xde0dc29a, 0xc9ccbcb9, 0x788984ac, 0x9a2b97a9, 0x0961b1e9, 0x2b162c21, 0xd131b1b3, 0xf73cfcdf, + 0xbd92f198, 0xebb5c86b, 0xee7de661, 0x987f5a1c, 0xe334ec83, 0xc92b9ee3, 0x1b7967e8, 0x59d41431, 0x43b7fa72, + 0x4ab866f5, 0xca8658b3, 0x60ad7252, 0x9b348dc8, 0x91175d51, 0xef948ee7, 0xfca3ea55, 0x8d35d797, 0x19a337a9, + 0x4c65ac1f, 0x33de6e9c, 0xb20b7385, 0x103a07a1, 0x7b83349b, 0xc4bb4734, 0x7a7992e8, 0x1bb35312, 0x8563942f, + 0x619c9c85, 0x8c3c0be8, 0x5f15a787, 0x6a08d49c, 0x7e79ba92, 0xc934f560, 0x0de3ab23, 0xd07fa2a7, 0xdf0e6890, + 0xe4f424d2, 0xb2a3d551, 0xb63b4c88, 0x9d0410e4, 0x57435879, 0xb8c847e3, 0x618dca61, 0x5597dedb, 0xa850f89b, + 0xc24eee91, 0xa9c55e9e, 0x62e49103, 0x73028847, 0x9008043a, 0x5dcfe8a5, 0xba972981, 0xb6971cbd, 0x24b648f8, + 0xb2fe6e39, 0xf33f46f6, 0xd458e108, 0xcdba4023, 0x73989da8, 0x98323893, 0x03e1b5da, 0x5f141363, 0x7e4b2ea4, + 0xff9e2fe2, 0x2e7e2c27, 0x5fa8ce94, 0x7500c393, 0x2b095536, 0xd7adb8b2, 0x0d8ee53c, 0x1b07a885, 0x4cd13366, + 0x9e8bba40, 0xdc13c212, 0x4de5af78, 0x39c6981d, 0x25fb695a, 0x9a16af95, 0xc07597e2, 0x0c47c3af, 0xf6ab6e47, + 0x20d01a80, 0xdd95effa, 0x4797e929, 0xabf70bff, 0x7bdbdd4d, 0xf8c68947, 0x69f5ab80, 0xa81ddc45, 0xafdf42df, + 0x4217a029, 0xb5cad5d8, 0x43a6cdb3, 0xfbd6c787, 0x914c99ac, 0x159bf2ef, 0x0583958a, 0xa724072c, 0x45879914, + 0x210de3ad, 0xd9b1c89b, 0x41c95306, 0x0335e346, 0xc2b72414, 0x35df8a99, 0xd627f5fb, 0xc59dd175, 0xa3ea6b8c, + 0xf918325e, 0x2142bbed, 0xd44a8761, 0x17543092, 0x9f0cd195, 0x72998655, 0x539cecb9, 0xad3b89f3, 0x0960c27d, + 0xe1ff0c8f, 0x35b8ad30, 0x25ceb313, 0xc837cc84, 0x77e45a8d, 0x312e63d1, 0xe9754c5a, 0x44059aca, 0x9c4af593, + 0x1545288f, 0x243119ba, 0x426b9b71, 0x9aab3011, 0x64b5d6f4, 0x71bfe45f, 0xc4759a03, 0x33988b27, 0x8bfc4a16, + 0x555f1c69, 0x8d433dbf, 0x97939063, 0x536b76db, 0x48a4689b, 0xa4238b44, 0xff322fdf, 0xf1c311f1, 0x7b78daaa, + 0x1124781a, 0xbfe1c87e, 0x17102326, 0xe8427fa9, 0xf4211132, 0x385e5ec5, 0xf0510dea, 0xd64977af, 0x49e91cb7, + 0xd13c70eb, 0x59779bb8, 0x6b60f144, 0xd3eaa87a, 0x839007d6, 0x58133301, 0x046ef57f, 0x426ce126, 0x4b8bacaa, + 0x2fff679d, 0x0f316c2a, 0x6b1ce83e, 0x8b65cfb4, 0xf44b4f7e, 0x7c8a1966, 0x2cfdfe8f, 0x329ab488, 0x3eb3d696, + 0xdf373188, 0x81a04caf, 0x8b3a2a72, 0xeecf542a, 0x0f29ac94, 0xdd62e195, 0xbc6eea91, 0x39355bd0, 0x12d07ff8, + 0xaa297cec, 0xe9908e11, 0x7ca85dc7, 0xfc55ef42, 0x9d187d48, 0x789909ec, 0xde6694e4, 0xcec0d211, 0x449e688b, + 0x4724b598, 0xa082f2be, 0x80f2d1bc, 0x2d6f7d47, 0xa78a2c48, 0x02ca1c5f, 0x7eec9d60, 0x2859ce34, 0x9e92e917, + 0x97a97709, 0x06ac4616, 0x5715a2c1, 0x60c33002, 0x377b78b1, 0xa694e224, 0xe41a6833, 0x61d875c5, 0xcba7a2e4, + 0xec7c6426, 0xb2b00e4d, 0xd703ff1c, 0x400143cc, 0x2ab399d3, 0x840ae344, 0x39c71a07, 0x5a9b4a8f, 0x2aef9b6b, + 0xadb0c881, 0x67dc2bf2, 0x7bb358d6, 0xe1891ea8, 0x370b8c23, 0x4fd6f6d5, 0x0e1bc2a5, 0xfd955f50, 0x17878cf1, + 0x1722cdbd, 0x32026ae3, 0x0592bb94, 0x4dcba616, 0x91bc2a85, 0xf16bc70b, 0xd28c9e98, 0xe04e076b, 0x3f1f5bd3, + 0xacf3c85a, 0x9402528c, 0x5bc3030d, 0xab9b9a49, 0x7caf7371, 0x3af129d1, 0xc5e53575, 0x28385041, 0x1009d459, + 0xfc2a517b, 0x34157dfa, 0x3871137b, 0xb41ae34e, 0xc2a8b852, 0x49a3d81d, 0x641d788f, 0x87ba4a77, 0x87b12bd7, + 0x84190a97, 0xf62bb800, 0xd4927c7a, 0x85cec5a7, 0x111d58b9, 0x181004fa, 0xf0d31589, 0x01afaa39, 0xf78a8edf, + 0x76bb101b, 0xd39a6d7e, 0x599c0129, 0x01df95aa, 0x6476e519, 0xdbc6cb38, 0x686878ad, 0x01eb54ad, 0x294633e9, + 0x181e893d, 0xc7b71be4, 0xbcd982d9, 0xec6eacc0, 0x47e64984, 0x5d5445aa, 0xafd2a8d0, 0x7acd1fe6, 0xbad9cad3, + 0x22f67c0d, 0x4da096f5, 0x57d574dd, 0x6e90dbce, 0x3935aae6, 0xf9ab7778, 0xf656acc2, 0x2a1304f1, 0x99dcf69c, + 0xe6a540e5, 0x6bdc7201, 0x2dcb5235, 0x654948b3, 0x13a727d4, 0x30dff33e, 0x713a54e5, 0x567a9ffd, 0x4c732841, + 0xb4fe9a27, 0x714cf344, 0x6554dccd, 0x9b909dae, 0x9be99fdd, 0xc4074772, 0x1c97bc2d, 0x02b0b06d, 0x3d93975a, + 0x7f52ba1b, 0xf0d4129b, 0x53470ae4, 0x040a33e4, 0x3e8ac85b, 0xb21e2c1a, 0xdbe1c4d7, 0x22361a77, 0xd9daf151, + 0x729ff2fb, 0x1bed36b2, 0xf31459e7, 0x4a969039, 0x6a548b69, 0x10b34834, 0xc205b51a, 0x03f117c9, 0x71a0f6ed, + 0xc6cc8cdf, 0x74cca073, 0x87b59a6f, 0x3c705618, 0x17704c1e, 0xb536810e, 0x5126e138, 0x0b8b1d71, 0x210c8a75, + 0x47401180, 0xd8168e22, 0xd83a3f82, 0xd8303355, 0x9d030096, 0xece1425f, 0x0b6aab00, 0x50c2aa9a, 0x8f63d0d2, + 0xbd095fff, 0xadb30df9, 0x2133d717, 0xe24b0cc9, 0x1ab47f74, 0xd856ecf4, 0xa0affe33, 0xe934cbcb, 0xd63f2452, + 0x6aaaf6a1, 0x658ff37f, 0x25622d12, 0x42192927, 0xcedb01ff, 0xf8a0faa7, 0x1ae722d9, 0x1a95e80c, 0x0683c243, + 0x1935fab5, 0x6eba9687, 0xcead47cd, 0x5d47c61f, 0x7670576a, 0xf7b0fa87, 0x1833d959, 0xa64f4102, 0x41fe9ec3, + 0x451b0a50, 0xab8bdffa, 0x15597a0d, 0x83deb113, 0x11c9f955, 0x551dfe7d, 0xa1fc09e9, 0xf44e1dd1, 0x1a6fd05f, + 0x38a865a9, 0x814f4409, 0x233f74ac, 0x850dc9b2, 0x5c8fde34, 0xdda32282, 0x3867ff8e, 0x9f1690f0, 0x7aa7a7b8, + 0xa4aa7845, 0x53a7d6fa, 0xb75f5b1d, 0x625bb100, 0x3c79e394, 0xa339a9e8, 0x9d789178, 0x7c741a66, 0xd2377cde, + 0xa23e16f1, 0xf6dd5a8c, 0xb1524d28, 0x2fa5ef01, 0x73f9a1fe, 0x64c68602, 0x7a8e51c8, 0x46867558, 0xa38a3078, + 0x6470abb2, 0xca2c8be1, 0x89064e0c, 0xdf853717, 0xd31059e5, 0x83d48889, 0xac51d6e8, 0x8c92a2ba, 0x21c476fb, + 0x1142bc33, 0x5e3bc7d8, 0xa3ff2bb0, 0x3e5f2a69, 0x88bad5d0, 0x514368ce, 0x73e3b13c, 0x55cc6a61, 0x8c8336d6, + 0xb61c3442, 0x3fc6aaef, 0xb371d342, 0xd891c604, 0xd4005821, 0x155e021a, 0x05001b38, 0xde53dddd, 0xbccda9a3, + 0xcc7ef72a, 0x1ce08738, 0x3205495c, 0x5797b855, 0x816c06d0, 0x9349ccd2, 0x4487394c, 0xe0923a82, 0x1a8732de, + 0x813249ce, 0x2c091c4a, 0x5e3690a2, 0x668d76d6, 0x1f0c3012, 0x8d057d91, 0xddbe207b, 0x758cf572, 0x9f5fe033, + 0x4716cc46, 0x79bd903e, 0xe168646c, 0xdcf8e84b, 0xa2e1e3a2, 0xc3396fcc, 0xbd5e7415, 0xfb97f1ce, 0x60dcefd2, + 0xde55fbbc, 0xe4e8acef, 0xc41f5286, 0xf7f38c08, 0x25756812, 0x0bf80276, 0xea8a0255, 0xcc0096b8, 0x19549b74, + 0xb3817237, 0xce5f24b0, 0xef42db1e, 0x9058a60b, 0xbbd696fe, 0x85247437, 0x5537cbdd, 0xce93f7a1, 0x57edd261, + 0x1054e3dc, 0x82313922, 0x889864a1, 0xfcdb647a, 0x930bafa2, 0x60177960, 0x3e1eb3a8, 0x44490e03, 0xcbe3edef, + 0xa28bbf0f, 0x9a369c68, 0xe85177b9, 0xf2211374, 0x96b24108, 0x54c6e2d5, 0xa15e4ce5, 0x9bd7b256, 0x0efa953c, + 0x1021b207, 0xacbe9bfa, 0x89637301, 0xb49777df, 0xdc3046cc, 0x0f2441e1, 0xd6cfff9a, 0xf17ced6a, 0x9c07e2bc, + 0x9035d35f, 0x4330a9c9, 0x3ffd443f, 0xe721c631, 0xbcb449d4, 0xc038912a, 0x33728283, 0xa2f1f51a, 0xe664fc73, + 0x1e4e0cc5, 0xd6e96a23, 0x57e2df5c, 0xd214f1ce, 0xe59c7461, 0x8393bb73, 0x588bb469, 0xcb48775c, 0x824ae1f1, + 0x90fa5fbc, 0x76bc3db2, 0xe40bfd3a, 0x5e29ab1c, 0x66121505, 0x138bf87e, 0x80dffd91, 0xce78931d, 0x6d2f1aba, + 0x1baa5797, 0x1e382340, 0x326b13b2, 0x1717952f, 0x2555451a, 0x92ea10e4, 0x921abe29, 0x904de17e, 0xcd2acd15, + 0x661cdf3f, 0x57697faa, 0xcaeebfb4, 0x1bfdd7e8, 0x621cad15, 0x96800389, 0xe9b62fea, 0x4770c8d0, 0x69d5ac7d, + 0x8cec75c8, 0x8cd42105, 0xe3a6434f, 0xa7474ca9, 0x64cb08a6, 0xb40a0b29, 0x1cbcf0e5, 0x7501df26, 0xb742e814, + 0x47f3d68d, 0x36b7f94a, 0x8b6d236c, 0x026472f3, 0x081017b3, 0x193e3776, 0x40b750cc, 0x711cf6c9, 0xa1cdb8b2, + 0x82f30d7f, 0xf155d303, 0xdb0e831f, 0x0c250b8d, 0xa09040bc, 0xae3924b2, 0x72747979, 0x86b04960, 0xddeae3bc, + 0x940325b1, 0x4748dad5, 0xbef90eb2, 0x65e2fa84, 0x55765683, 0x6e98c9d1, 0x4bb25007, 0x0972cfc6, 0x7f10a3b3, + 0xb5e0115d, 0x35c39c29, 0xb157f229, 0xba6ffe9e, 0xd211f243, 0x6e4bc971, 0xb1eada18, 0x5765a9cb, 0x247331a3, + 0x11b051af, 0xfa0e0e9b, 0x1e576e1e, 0x06c70b66, 0x68f1fc4a, 0xb857676e, 0x8a38caa6, 0x84b9e570, 0x6ae96cc7, + 0x707d276f, 0x7419e722, 0xa8f8dfdd, 0xcd243da2, 0x2eacc2ac, 0xc83543a9, 0xb30c2b0d, 0x4e64712f, 0x40855a8f, + 0x3cf4a945, 0x3103881b, 0x1309fa99, 0x1965fb2e, 0x04d479f5, 0x2d9ef8de, 0x185bcba9, 0x8f932b8f, 0xa97d6681, + 0x3855e277, 0xb9505008, 0x9989fcaa, 0x54abfcd3, 0x088d4d70, 0xa2341b7f, 0x9611ed1e, 0x9e9c0986, 0x92715284, + 0xe87abcb8, 0x41e4a067, 0xfdedd7a9, 0x9f9689f0, 0x2eaf6c66, 0x8240579c, 0x53d61982, 0xd802d1bf, 0xa387b8fd, + 0x66b47322, 0x866061b1, 0xa7aac97a, 0xe83f4ab2, 0x399dc825, 0xd9cdff4d, 0x3b2081d2, 0xa3a940c7, 0xd7e75a41, + 0x7a1ec503, 0x75a475fa, 0xc9f9bcae, 0xc983215f, 0x1fbe9f28, 0x3ea2c115, 0xb7ce6cdb, 0xf312173a, 0xd587b8a2, + 0x9a693622, 0x18069d7b, 0x94095807, 0xd3752cc3, 0xb6fb36ec, 0x968bb6c2, 0xd250959a, 0x62f22924, 0x1964f21e, + 0x3d00a3dc, 0x8360f73a, 0xff3adfc6, 0x985963eb, 0x2a5c9bc2, 0x8d785021, 0xe9cb6795, 0xf249a9b9, 0xcc5cb20c, + 0x7b83cf2d, 0x1ea6c146, 0xbead215f, 0x6d27497d, 0x3d5561fe, 0x9957bf7c, 0x8a6444b3, 0xf6ae3c02, 0xb7fce2b3, + 0xb6d599b4, 0xfe264e55, 0xf05b28c5, 0x7773f900, 0xa4d8e196, 0x2bbf3561, 0x1f050f62, 0x36691bfe, 0x22bebf76, + 0xbb239303, 0x255fdcdc, 0xa757d2c8, 0xfb80a5d9, 0x61b1b30f, 0xbddd478c, 0x71b0b174, 0x05667240, 0x3c6ec900, + 0x4917cff3, 0x0fdaf1af, 0x505dc6fb, 0x2ac166d9, 0xcf1a713d, 0x44f41c94, 0x5c43eb37, 0xbf44de18, 0x58f0d592, + 0x2712e8c4, 0xa33a2400, 0xf9582117, 0x5bdab76f, 0xda486290, 0x06a0a322, 0x5c763275, 0x28166776, 0xfdce0f54, + 0xf1b4da7d, 0xf4045e71, 0x7d5cb1ae, 0xd90b2f7c, 0x4bec8141, 0x7046e75a, 0x9a3df9b5, 0x027671fe, 0xccfdc3ff, + 0x703a7af7, 0xcd558c45, 0xbdcfa0cb, 0x529e7353, 0x062c7a34, 0xeb4ffcd5, 0x30ac4b49, 0xa047578e, 0x62a44077, + 0x381894c1, 0xfd3d9527, 0xba77a878, 0x01131f21, 0x7cf47cbe, 0xb6e9df4d, 0x5d9f1d8c, 0x2f6a40f1, 0xdb2c8226, + 0xe7a23cf3, 0x3c0668df, 0xa35b67cc, 0x3828b198, 0x1a7c8bfa, 0xd6a6a411, 0xd72508ee, 0x8af20ef3, 0xf1d764b3, + 0x5afb8e37, 0x2261e42f, 0xab1f6dca, 0xb512d07c, 0x6ccdbc80, 0x52daeea8, 0x5f7f9f2d, 0xc922c5a2, 0x4b94fb99, + 0x9ff66429, 0xf555f99c, 0x9aa90453, 0x64de48ee, 0x5c62427e, 0x86778bf3, 0xd9f3dfc1, 0x292798cc, 0x8afdda46, + 0x801ba435, 0x7efa9cb1, 0x15e7bf3f, 0xfbcbcb82, 0xdc050980, 0xf5b3c6e5, 0x5533cb5b, 0x05217bc6, 0x2a80cf96, + 0x938eb31b, 0x1ce70a38, 0x523ccfcf, 0x32d29700, 0x6c8efb6e, 0x6ff066cc, 0x707a6c0f, 0xc51ec885, 0xd0ba5beb, + 0x1fb14547, 0x2b24970c, 0xcc69b407, 0xc7be4eac, 0x098ffdcd, 0x7b6f4c64, 0x4b81475e, 0x61645020, 0x160c881d, + 0xf8a698ff, 0xba6115f8, 0xa25475ec, 0x512103ac, 0x29d3a7ed, 0x8bfda029, 0x39243f7d, 0x1051a710, 0x28a91377, + 0xf8a2e1d0, 0x34062d46, 0xc96dafce, 0xdafa7986, 0xebc187ca, 0x1096eeae, 0x23f8c265, 0x510aada4, 0xa48fb610, + 0x72a23360, 0xacd48276, 0x5065f5ed, 0x7832bc5d, 0x873d63e1, 0xb7c46598, 0x0423127f, 0x00d62a6d, 0xddb3e536, + 0x09392294, 0x7b55fc4a, 0x46d2f5cb, 0x9de64fa8, 0x51ad0bb3, 0x74604e1f, 0x2999ba28, 0x0e1e2214, 0x528a73ce, + 0x7cfdf37a, 0x903a6232, 0xc5766bdd, 0x536e3d79, 0x57a366d2, 0xab137337, 0xf8becdef, 0xd7679add, 0x578dffa7, + 0x3a82fe73, 0x525b6a2b, 0xbabf771d, 0x9a0f32f7, 0xecbc32be, 0x67131d9e, 0x3c831f55, 0x67ecd871, 0xe56d7d30, + 0xd5264031, 0x61e1854e, 0xb946eb62, 0x7e30d55d, 0xb491c734, 0x7581341b, 0x80817929, 0xa87cd749, 0xd08f9c90, + 0x691a1302, 0xbccebf6c, 0xbf3f70b3, 0x92961c65, 0xac57a6c1, 0x6a668dce, 0x07e2e9cf, 0x80e63cf5, 0xe4fa9922, + 0x3a786111, 0xf5af1bdd, 0x4bae8a6b, 0x4efd113c, 0x0cce8136, 0x43de22df, 0xfb36219e, 0x30a44db8, 0xbe14aee2, + 0x1423e880, 0xdd28df91, 0x78317dc1, 0xba4bdfdd, 0xc9cf59ca, 0xee7dddc4, 0xc70018fd, 0x78c70e60, 0xd5e16e1f, + 0xb1d88d0d, 0x15ca14df, 0xa75d2e2d, 0xa6d8a437, 0x2f2fee3b, 0xb090d087, 0x39b60753, 0x69998a07, 0x357e93bf, + 0xbda40a0e, 0xc3455f02, 0xd07e1de9, 0xe9876adc, 0xfdee66ee, 0x67613aaf, 0x33d37e27, 0x64223f4e, 0xf482652a, + 0x789d4889, 0x44c0f6dd, 0x2d0b1d53, 0xc9660d17, 0xc517bde0, 0xe6586bff, 0x9a2cfea7, 0xdd42b74b, 0x1d45d9d1, + 0xf9c75a88, 0xb84ab30e, 0xee45a64a, 0x38fb6f5d, 0xb785a299, 0x71e29e82, 0xce0e7f12, 0xd4b24301, 0x8b43c398, + 0x1a1be6ae, 0x49be7922, 0x9aff48a2, 0xf7dd58dd, 0x2d5f53d7, 0x4ad29cce, 0x85bdd745, 0x3f27d01f, 0xba6d8dba, + 0xddf24389, 0xcbc45d0e, 0xed53a439, 0xb44312ca, 0x2d903af7, 0xc932415f, 0x304e3260, 0x0453fb69, 0x0006aedd, + 0xa3db78eb, 0xbc4576f7, 0xd8fc4e5c, 0xbbacf5e7, 0x278381e8, 0xbafbe5c4, 0xf059bb3f, 0x3a38e669, 0xdb0a6385, + 0x848f1862, 0xa658fcf5, 0xfac6fc1f, 0x90b1e37d, 0x965e4da4, 0x6aab91ee, 0x86e7fd0c, 0xad7c84a8, 0x6f892c58, + 0xebdb5d1e, 0xa1e5afa5, 0x2a0bf8d7, 0x141b7243, 0x0ed22f2f, 0x02e1bddc, 0xd6e1e015, 0x5c770f6b, 0xa79873b8, + 0xb586d5ef, 0x3d9e3b5b, 0x1cd32f6b, 0xce4d5e21, 0xb22b5493, 0x1b4abdce, 0x96851edc, 0x45c01ee5, 0x609e4a44, + 0x0487b5d7, 0xcb62c334, 0xcd74f2fa, 0xfa3cf3f8, 0xc34f4140, 0xc96e2c63, 0x56b15813, 0xbec1c6ee, 0xcb1565ce, + 0xcff63e04, 0x706e279a, 0x8b3e46af, 0x769248ff, 0x8bc1e4b4, 0xb34c8cd9, 0xd20d4ecc, 0xdb1a04b7, 0x500005dd, + 0x3e0ee0fa, 0x76b9de0f, 0xb293b17f, 0xce6d57a6, 0x063865b6, 0x2a38bc6f, 0x982c8725, 0x98ad64cd, 0xbecd10a6, + 0x5eddf237, 0x5af798f1, 0xccb1dec7, 0x3d4865a4, 0xa0ccf884, 0x7c605769, 0x4b1837c8, 0x1262b23a, 0xd08a43bc, + 0x65ec3427, 0x202d71ac, 0x0401b77a, 0xc0b9b09e, 0x5ea83bd7, 0x1e3c463b, 0x1bb173c9, 0x95b437d6, 0xea042e7c, + 0xd5977496, 0x56420ff7, 0x6b8e172d, 0x619f39a5, 0x9912a2c7, 0xd53a0665, 0xfcffbc42, 0xdb16703f, 0xde42bd0f, + 0x67d5ca5a, 0x57bf00ec, 0x51872b24, 0x67787656, 0xbedab6c0, 0xdb78fb87, 0xaa4665f8, 0x30b493a3, 0x1f633c08, + 0xc9bcec0e, 0x6f432dd3, 0xcc24aa5e, 0x44664b8e, 0xf5b997a7, 0xaa3ca9eb, 0xcbfc3029, 0x5f15d227, 0xe0360c36, + 0xe89cf700, 0x97f16597, 0xe02aeba9, 0x4e4920ff, 0x21c2446d, 0x99c7da3e, 0xfd3fed83, 0xa0fa9e3e, 0x47c193d5, + 0x9d41ed6e, 0xeb346eac, 0xb407aae4, 0x18485590, 0x5006e69f, 0xc702db59, 0xd4a4d6c7, 0x9b4ff732, 0xa5920a73, + 0x3d874683, 0x03369cc8, 0x889ffebd, 0x242c0191, 0x1a018d0b, 0xdb49665e, 0x131118cf, 0x69d5c948, 0xbd42b06c, + 0xf45c2501, 0x5394f279, 0xe023554a, 0x32965275, 0x6bb35b58, 0x92cfe877, 0x363fc32d, 0x35ab9f9f, 0x8fcac887, + 0x6ede8ddc, 0xa672991e, 0xa3da3d1d, 0x5524a964, 0x6f4d3a4e, 0xf57f2f76, 0x7e6d4c26, 0x11845b67, 0x6a24443b, + 0xb25195da, 0x446f8d34, 0x87a49017, 0x6d8023fb, 0x588e1a14, 0x7433c8e5, 0xfa5bf83e, 0xab34c428, 0x16ef933c, + 0xec14c4d7, 0xa4d8c216, 0xe99f4824, 0x30b34a76, 0x75a4de4d, 0x0d337752, 0x1fde3bf8, 0x16819d2d, 0x86f30856, + 0x582207ef, 0x6f394269, 0x3a70476a, 0xf18f5b1a, 0xdc094977, 0xbd7ee0be, 0x6a43957a, 0x1ac25676, 0x5e67a22e, + 0x2fdfe1fc, 0x1f184e4d, 0xfee151e8, 0x28120609, 0x27c27e52, 0x16e0e6b1, 0xe9b8959e, 0x50fe0eb3, 0x98963997, + 0x3835fb41, 0x0abfb165, 0xc9a372f4, 0xee2def02, 0x57c660ab, 0xf33280dd, 0x8082dfb0, 0xc424a1f8, 0x2823a654, + 0x54d2fb38, 0xf8db8570, 0x94b0eb6e, 0x78163d2a, 0xffe02f6c, 0xa6aabe43, 0xa2809f7b, 0xbdf0d0ab, 0x800c32cb, + 0x54e39b78, 0xc44cd339, 0x868d8b61, 0x6bdfa104, 0x2cc3088f, 0x928b6cc7, 0x5f23b133, 0x2f5e8b65, 0x3a97ad76, + 0x05ca221a, 0x07e8a798, 0x85aadb0d, 0x4130a4dd, 0xf571abf7, 0x98086aeb, 0x54018e01, 0xa8969b11, 0x25039808, + 0x088a5c12, 0xdf549b9e, 0xc54571ff, 0xc701c434, 0x9d60dad1, 0x1b13015c, 0xf4eaa06e, 0x0d5382b7, 0x1cfc6c50, + 0x6d188521, 0x6375950c, 0x70dfa08d, 0x31cd1e0b, 0xb3641da2, 0x4d1e4508, 0x70fda500, 0x275c689e, 0x34c20dad, + 0x608a07c7, 0x96a85c6b, 0xf7c96458, 0x4d988839, 0x320cd3e1, 0x2222439c, 0xaa2dac60, 0x59bc21ba, 0xd757deb7, + 0x124aa7b8, 0x035d6248, 0x19b28400, 0x3e76aff7, 0x221ca0b3, 0x01fafaf0, 0xf72f3ac7, 0x6f03188d, 0x044352be, + 0x1e82d42a, 0x2e38357c, 0x3236b011, 0xb35fa643, 0xdb31b48c, 0xb73ba985, 0x9b57b516, 0x7692c6c3, 0x4af8e384, + 0x4655449d, 0xa83a926d, 0xd1ac8045, 0x86e19c86, 0x8f2a4ea0, 0xfdf145e5, 0x14887130, 0x23715211, 0x22889e06, + 0x27796a43, 0xba715854, 0x30e8a094, 0x6b511917, 0x7c15aebb, 0xdb5fbac4, 0x31fc5dea, 0xd7c1bb46, 0x03ff167f, + 0x7b4f2233, 0x2e1eaea4, 0xad2452f7, 0xe7f9e15e, 0xcb78f28b, 0x07c6439f, 0x692d6d9b, 0xfaa13447, 0xc5d907eb, + 0x30a5670c, 0xb51148c6, 0x238d9ae3, 0x86e358f9, 0x6d708b31, 0xfb467cec, 0x915318c5, 0x28525f09, 0x3a91dbf6, + 0x57884beb, 0x981819eb, 0xd72a0bf7, 0x610c8346, 0x02a72fb9, 0xf0bc8d87, 0x93d8e400, 0x6fb3a739, 0x37d5d55d, + 0x6c32423f, 0xa8883306, 0xa63364c5, 0xe6b9677a, 0x73bcffb7, 0xa9b9704e, 0x99e3481c, 0x146ecfa8, 0x783a464f, + 0x2a7ce9cf, 0x133eb981, 0x7ad2b2cf, 0xc28e0cc1, 0xc12a5922, 0x0bf620d3, 0x30803ab3, 0x984be0ef, 0xd2a6f095, + 0x9f60b9f4, 0xfeb392d2, 0x9428ed23, 0xb950cac6, 0x98b07963, 0x869496b7, 0x9ec3bd16, 0x0e965a87, 0xd487995b, + 0x6a12dfea, 0xfdf152c9, 0xffd666d8, 0xbc6481af, 0x0fb65eb7, 0x107a134e, 0x28a2c3f8, 0xc3934940, 0x77d985bd, + 0x1222488d, 0x98f405e9, 0x26d5bf6a, 0x32d23c2b, 0xefdbe793, 0x54ae48d5, 0xf451d443, 0x3330c470, 0x4b6803bb, + 0xa4fb7320, 0x8b8c1266, 0x8931f926, 0x62fa8fc8, 0x550cef49, 0xf22982b4, 0xdffdeae5, 0x693cecd3, 0xb00c6092, + 0xcbe96dfa, 0xbb4d56a6, 0x7eb8be25, 0xc23ec9fd, 0xa0384146, 0xf83cb5fb, 0xdf3c6d14, 0x662cf0db, 0x6e68bb24, + 0xefef980a, 0x3e962722, 0xf1823ea9, 0xc025e6c0, 0xf1b4eff3, 0xba4cbf50, 0xba84af8f, 0xff6e30ab, 0x1dfb34a5, + 0x540f5644, 0x35fb8064, 0x573aaf77, 0x46ef33b6, 0x674512ee, 0xd1666dab, 0xf753ca96, 0xb7b08b16, 0x2100bdd4, + 0x3838f398, 0x1696967f, 0x9a763bb7, 0xc0cec5c5, 0x27aae38c, 0x0592b582, 0x887464ed, 0x69c8b4bf, 0x3f3375ea, + 0x197f206d, 0x467b38c8, 0x47eb4c28, 0xaddfa931, 0xca653e3d, 0x16b56c0c, 0x2db228b3, 0xe72e28e3, 0xcb6662f3, + 0xd61f8f29, 0x43183bd6, 0x1c7c2e18, 0x30c679cf, 0xe180e446, 0xd126a6a7, 0xaa1512e6, 0xff3c0dab, 0x5e12a208, + 0xa8fc4db2, 0x7d08d980, 0x8491fad0, 0x96420b5c, 0x8364f0fe, 0x3097569b, 0x8880571d, 0xf0bdb3b2, 0x341d9aeb, + 0xc45ec9f2, 0x37471d39, 0xdbc4aa3d, 0x904864be, 0xfe8fa2f9, 0xc325e5c9, 0xdf7dd751, 0xedf5753a, 0x60f6e03b, + 0x57f4b56e, 0x82a8ee72, 0x5a400a96, 0x23b315d9, 0x26c971d7, 0xcfed740f, 0x03831ab4, 0x2d103152, 0xbbb482cc, + 0x50ec8e63, 0x72a6d041, 0x198707ee, 0x0d9e9776, 0x1ba8cc5b, 0x90f560ed, 0x976ef175, 0xc33287b8, 0xf3da47fd, + 0x287a112e, 0xa886746d, 0x6e4262f5, 0x23ff7bc5, 0x51cb7067, 0x7da4fbda, 0x4e133f36, 0x25cf88a6, 0xc506fd14, + 0x9a5204c2, 0x4105e72e, 0xb6ee4aad, 0x22146354, 0x1da611e4, 0x0e4c7087, 0xd938079a, 0x7dcfb6d8, 0x4c07c73d, + 0x99d0d95d, 0x3c56c850, 0x285406aa, 0x946e2814, 0x52fa818e, 0xbec141a3, 0xd7677ad3, 0x8a921246, 0xd6c63f68, + 0x14c787c9, 0x2e396b1d, 0x1c4898bb, 0x92a09de3, 0x2df9c5f1, 0xf2a0647a, 0xc4c92daa, 0x487acc4f, 0x310415e6, + 0xe9abf3a7, 0xaadea7b2, 0x40fadf7a, 0x2a69e6a7, 0x735b9d37, 0x8ccb8ab9, 0x77308a64, 0x7f15f6b0, 0x67f92c4a, + 0x1f76769e, 0x540cd0bb, 0x3d0eb7f6, 0xc27948df, 0x255fa3a7, 0x571dfd7c, 0x7e24a022, 0x56341b12, 0x052cef70, + 0xaabb8e59, 0x13578b54, 0xdd559ef3, 0x81499ace, 0x4c8a3f6f, 0x5e778262, 0xd0873502, 0xd1770f4e, 0xf090013c, + 0x03d5b048, 0x1fd3d0a5, 0xdf48788f, 0xe564bbce, 0xad52c10f, 0xad84a40b, 0x7fe83fec, 0xd620786d, 0xcfbb01fc, + 0xf8096a03, 0xdd000a68, 0xd5d5bc53, 0xac393f4c, 0x3a0740a3, 0x1a8d0c63, 0x8e230f06, 0x157274fb, 0x18da99ba, + 0x70bd7cc5, 0xb6f836e7, 0x416cdc87, 0x9d87c0b4, 0x33b6bc80, 0x96b04d03, 0x78debb9d, 0xca4295eb, 0xa81091f2, + 0xa19e6b31, 0x91e13a2b, 0x3e6411ba, 0xe83fe8ae, 0xfe9875a9, 0x4eb8ec92, 0x30535375, 0x72100cb8, 0x58ba5b3c, + 0x846fcfab, 0x5b046bd2, 0x7959de12, 0x2c7b63d4, 0x840d7ace, 0x1345e7d0, 0x25affc6d, 0xdd4a8c02, 0xcdbac355, + 0xcd5bc582, 0x0e0ff05f, 0xb7ce9b6d, 0xba1d3dee, 0xfa4e7f93, 0x509f800d, 0xbb2b45ac, 0x53501a59, 0x1ff3bd3a, + 0x826d150a, 0xa9af2196, 0x1fd52d89, 0x2fdf1b3e, 0xc2af6e12, 0x51a3b051, 0xc0d91fc4, 0x3bb9faa8, 0x4b74211b, + 0x2c1a1fe4, 0xe62a6a37, 0xe6921703, 0x4e79b332, 0x6413d247, 0x18a5d66a, 0xcf595054, 0x92cb65a6, 0x60bece79, + 0x3e7a7b0c, 0x1cf1a6c8, 0x288145d6, 0x43b46959, 0x05b4b697, 0x5f6da8ad, 0x9071b036, 0x5b736297, 0xc96a49a4, + 0x0734ef15, 0x7063a43c, 0x0d587f68, 0xd2a529a2, 0x29c18ace, 0xa5b957f6, 0x9bde23ff, 0x91d9b114, 0x840b4d32, + 0x139ce19e, 0x5ab873be, 0xc267f78c, 0x57015155, 0x7da51bac, 0xf36fd279, 0x3dc220ef, 0x9bc8bf21, 0xe311d1bf, + 0x24203603, 0x0dc3808a, 0xaa92ff1c, 0xe33615f4, 0xacb8b473, 0x08a0146c, 0x2f7ecbb4, 0x6e0e2758, 0xc4e197d2, + 0xa5c66311, 0xbc6f767c, 0x6f6003ec, 0xd6acd66d, 0xbafa470c, 0x6799c043, 0xed2230f9, 0x3d92413b, 0x6dee5034, + 0xe1ec6f28, 0xceae00ad, 0xd635a1e4, 0x06856372, 0x3ff42404, 0xb36e8c72, 0x80656e6d, 0x61cdbcb6, 0xa564529e, + 0x29b0e7ef, 0x9007c241, 0x933f5698, 0x57400149, 0x4132a541, 0x64acd452, 0xb6febfde, 0xb66fd7af, 0x272d8abd, + 0x690a7c6a, 0xa73c3fe2, 0x585e2d4a, 0xa890c261, 0x8d324d94, 0x4fb1d16d, 0xcdd59b60, 0x0f911ff8, 0x00278566, + 0x2cc068c2, 0xded51a40, 0xb4645cec, 0xcb67830a, 0x9f0d1c8b, 0x4adc6b55, 0x46df6823, 0x722c080f, 0x2c439511, + 0x421bba78, 0x780442eb, 0xb4ba4b43, 0xe951b517, 0xf8439389, 0x225e01c1, 0xe265dca4, 0x5f67f0f2, 0x39d5cc53, + 0x7bbbac21, 0xc259756f, 0xe4e4a2b8, 0xf1dff6b9, 0x88c6696e, 0xf48620ab, 0x486af401, 0xcd981bf9, 0xdf51d6b1, + 0x47b789c4, 0x013c5788, 0xc5fde46c, 0xf49ad951, 0x18049b33, 0xb641ba1f, 0xf1ceb9a6, 0x25629137, 0xf24e4e9b, + 0xb7169038, 0xd99ea0d2, 0xcad3f210, 0x78089ecd, 0x0e896747, 0x0a6d9db2, 0x033d9efc, 0xfbd79857, 0xde87727c, + 0xed49b5e2, 0x513a0185, 0xa2740f89, 0x2d1c897c, 0xa6dcf4d1, 0xc0693282, 0x4f062ca3, 0x342dfbb7, 0x4e19c823, + 0x5cc31e19, 0x70e0dba6, 0xa61fcc73, 0x147775b4, 0x464f623a, 0xd58bc650, 0xa1b00c21, 0x53d4b7b0, 0x442ddf44, + 0x9c653b80, 0x6dfcb019, 0xdaa90104, 0x74cc1027, 0xf2b235ca, 0xfce1898a, 0xa79da487, 0xde7355fa, 0xcb0bbf1b, + 0xff53e96f, 0xaa5aef69, 0x939b0e66, 0x17a3ce1b, 0x614d3204, 0xfd0ce13c, 0x6815af1a, 0x36ee676e, 0xd83f9bf3, + 0x1ca45194, 0x5407e7eb, 0x5735e6cc, 0xedf7b16b, 0xca8de232, 0x541098d7, 0x51c3f2e3, 0xeb3609fc, 0xa24defc7, + 0x2dd070fb, 0x6d86f443, 0x92ec86af, 0xcf24d3b3, 0xa565b83f, 0x7cc480bf, 0x134d70b0, 0xc140907d, 0x5fe205aa, + 0xce02b561, 0x9180e033, 0xbf92d46c, 0x9a6d3edd, 0x01feaef3, 0x17f10fc1, 0xb064233c, 0x89e90d53, 0xf83f7933, + 0x133bc023, 0x5a54d221, 0x5a13409b, 0x95eec9ce, 0x38aea10a, 0x3822db3f, 0x9406bee0, 0x241eb602, 0x97c5bb1e, + 0x43afdc3b, 0xd361ac99, 0x485f9c76, 0x4962fe46, 0x670cb456, 0x84776bba, 0x183a541a, 0xf63b0ce1, 0x5d2f4991, + 0x85bbdd8d, 0xe3914b67, 0x20bb32ab, 0x346f911e, 0xf3a15da4, 0x618ed3ea, 0x963ae568, 0xd31ce591, 0x99e6ac77, + 0xe63dae66, 0x7d6f8834, 0x3877d5c1, 0x69461edf, 0x7bb682ed, 0x8c4bfa1c, 0x8a455bb7, 0xb59dba66, 0x4a8d79d4, + 0xf3891f97, 0xdeb5a0ea, 0xf56d0e76, 0x7c104ac0, 0x69ba1470, 0x7dee56b2, 0xe63988ce, 0x6b99d274, 0x0d9f95cc, + 0x678733ed, 0x0e0081a1, 0x41610187, 0x00f5b08b, 0x2c1489d1, 0x1ab2fd40, 0x0e41cd4d, 0x2fd7f3e7, 0x47eff72e, + 0x1dfed416, 0x3e4d628b, 0x8c8a6f10, 0x9d63eb7c, 0xcbf6714e, 0xda5900e6, 0x4c5e8d2d, 0x7b8e4883, 0xce19cd71, + 0xb3ec02a4, 0xc1b27671, 0x8772b853, 0x44ca2ae1, 0x809fe79f, 0xc29f5798, 0xa6a07cff, 0x926eae28, 0xc58c2196, + 0xdf1e5e1c, 0xc4f2d3dc, 0x6d941766, 0xfb0df65b, 0x9c857c6c, 0x8984dea5, 0x01f8f812, 0x3389607b, 0xc8cbd778, + 0x69a7c701, 0xcbd88799, 0xb59447cc, 0x67af2bf9, 0x57da62dd, 0x28e81e68, 0xee474eab, 0x646bcb27, 0x0cd7a59f, + 0x662becc3, 0x125da74e, 0x6e247906, 0xdd3e573d, 0xebad7bd3, 0x7470ec93, 0x161d4d5f, 0x06cfc6a2, 0xd95d9fc9, + 0x66f7def7, 0x8da76f98, 0x2899fdac, 0x9bf97980, 0x69716e95, 0x6021e052, 0x7067438b, 0xe47898f9, 0x69492835, + 0x2169ccc8, 0x396ade1a, 0x2a611c93, 0xa2c11f2f, 0x0237e337, 0x8ecf65e4, 0x4b73a92d, 0x0bb2315e, 0xdbeb52e8, + 0xa473e024, 0xf8c3f7b5, 0xc0efd349, 0x6eb048ca, 0x93fedbf6, 0xaaf1d4d2, 0xb6c1de9f, 0xed2b2583, 0x78fb6e2e, + 0x6e096046, 0x9485bb71, 0x6b9e3c02, 0x3620ec65, 0xec62aecb, 0xf8ba9f83, 0xe6dbb39e, 0x8448c5b7, 0x83c00808, + 0xcd2e67cd, 0x48118471, 0x4b30fb03, 0xd6bba86c, 0x46101305, 0xd9f74152, 0x6e874c47, 0x74abacb9, 0xe4a35e7c, + 0xbc4cc8e3, 0x93283024, 0x2075a544, 0xf6d8f72d, 0x41bc27d5, 0x1caf5a42, 0x7deb9411, 0xa3836269, 0xa7e96d0c, + 0x3cf54839, 0xebde9312, 0x87ee84b9, 0xe551d73d, 0x45b95bba, 0xb47bc153, 0x79d699b8, 0x846c2c27, 0x3c675a14, + 0x5b8827f6, 0xb47343f5, 0xf8592e36, 0x880f4dc9, 0x8a9010d8, 0x8ae08f07, 0x8ffcb35f, 0xf68f4c64, 0x1c719c7a, + 0xffac0cf5, 0xff93493d, 0x3520a957, 0x23bdeb37, 0x2d3c9a73, 0x0dd6abc7, 0x5a233c0c, 0x8e093516, 0xabcdade0, + 0x0b986268, 0x783fe373, 0x68432ec7, 0x3c846f9a, 0x8515069f, 0xdb1bd853, 0x40d39422, 0x0c5d69d1, 0x4a5c384f, + 0x07481ec7, 0xf6f87b3e, 0xf029a12b, 0xc51fdfb1, 0xc39c1231, 0xb7332618, 0xb79772cc, 0x3a18c470, 0x9e284583, + 0x2b5ff755, 0x37155ac9, 0xe4b48dca, 0x1e03eaf2, 0x7e5c2817, 0xd5f4e261, 0x3a3eb180, 0x991b93a9, 0xc5778b89, + 0xfdf34e71, 0x866b6097, 0x261a7ea2, 0x74fb0e6b, 0xbcd7467f, 0x241c96db, 0x34a9dc1f, 0x90626715, 0x6d4b2073, + 0x922b240a, 0x97f7e47e, 0xc16c48d3, 0xad8ce40c, 0x3a1c2e4b, 0x45a8fb42, 0x63d97b61, 0x18718a66, 0xc2dbbce9, + 0x84900b47, 0xad5411c1, 0xab67a162, 0xd6068afc, 0xbcb5e3c7, 0x9a014a93, 0xd95ddef6, 0xc27a15f8, 0x4b53e3c8, + 0x43eddf47, 0x79eba6bd, 0x39638fa5, 0x1fa21b9a, 0x4133f1cd, 0xe0f5c79f, 0x00f065be, 0x1e598f4f, 0x1748ac4f, + 0xee3f3a36, 0xa2677cc3, 0x6203906b, 0x04abc7c3, 0x5634a29b, 0xfded33be, 0x4852b386, 0x70fbd438, 0x04db96f1, + 0xbae7110e, 0xb5b43274, 0xbcc46d35, 0xad51f2e4, 0xebc79404, 0xb58839fe, 0xd3783a6f, 0xf29c2e5a, 0xa91be6f5, + 0x2a6fa12d, 0x00d9fcd9, 0x43a7069d, 0xb112703f, 0x2a210b24, 0xdb31cdb8, 0xdff22a14, 0x0fa21aa0, 0x2be2e435, + 0xa92a8889, 0xa1db2833, 0xf8323268, 0x2f61e2ef, 0x97010790, 0x351b2cd4, 0x1aba9378, 0xb5b160c1, 0x9b543711, + 0x6bdfceb9, 0x5f2a1478, 0x7f5351de, 0xf950be42, 0x45bd2872, 0x3f8f485d, 0x84292b8a, 0xf62905e5, 0x8b587ff1, + 0x3b56ee26, 0x0a1f87b6, 0x3d858662, 0x9057dc37, 0xa4bbe4a2, 0x4c2bd463, 0x9064d9f9, 0x75915409, 0xb84c3491, + 0xf1d9bb6c, 0xb180033a, 0xab51cf33, 0x958e5078, 0x2bc7766b, 0xb8aaf368, 0x58b5d40b, 0xecc11a1d, 0x6b2e6d6b, + 0xc1360df6, 0xa1d31ca4, 0x94cf99f3, 0x3f8bb3f9, 0x25f74b7a, 0x897a7273, 0x9dbd7877, 0xb9bae8ff, 0x0cd5f065, + 0x465217a1, 0xbbb13fd0, 0x27eb978f, 0x51ac8ddb, 0x23aac249, 0xce1c9de7, 0x6f970a6b, 0x645043fe, 0x73cb732e, + 0xcc1f4371, 0xd06a3883, 0x341a2c06, 0xf4a6964c, 0xaf9bd898, 0x0bb847f9, 0x3253aa72, 0x9a186b35, 0xcf6a85f9, + 0x936acda6, 0x6d868f14, 0xbf6b0657, 0xc7464ebc, 0x6d790648, 0xf572b8e9, 0x5451eb6b, 0xfbcb7df9, 0x5decb402, + 0xe129fe17, 0xc58b1bca, 0x6c7b75f3, 0x91f3f561, 0x436769e8, 0x9a65f744, 0xc7af86b5, 0x0c0a683c, 0x3202b575, + 0x37d56f9c, 0x815b8806, 0x2f5074bd, 0x5a7329af, 0x6a478370, 0xf5fa49fe, 0x64235106, 0x324bc987, 0x226ef7dc, + 0x60bc2720, 0x60197f08, 0xddd789fa, 0xf6ad35c6, 0xa306a84c, 0x177de967, 0x4668a4af, 0xcb44d995, 0x80d567d8, + 0x19de3555, 0x68db619f, 0xd464663f, 0x3ab02057, 0xee17d22a, 0x15aea33f, 0xca22cf58, 0x0577f9bf, 0xb24f7e9e, + 0x67157664, 0x8cd767e9, 0x35147706, 0x5c01b4e6, 0x7cae5880, 0x51b52a33, 0x0abaa986, 0xfda92300, 0x491ca071, + 0x25cddca7, 0x20dd858b, 0xbc671d2a, 0x71fed206, 0xd95ab111, 0x9c4aeea4, 0xc436aff0, 0x724ca8da, 0xc26081ab, + 0x2cf41839, 0xc830cfcf, 0x68b1fe67, 0x7a24389e, 0x60e1d9ae, 0xb1684bd0, 0x98f98641, 0x47103a99, 0x75215837, + 0x16d32896, 0x86d22eed, 0xb3733925, 0x963c57df, 0xcf7ad140, 0x37f692a9, 0xe930a14f, 0xd4e6493c, 0x44e6e606, + 0x3041a020, 0x23a7a8fb, 0x3975da9a, 0xa2891914, 0x27b7142d, 0x9f9b2dcb, 0xa7924809, 0x3d96f24f, 0xefe3d10a, + 0x16a6847a, 0x1934753e, 0x7533ca18, 0xc214f757, 0x13ffec64, 0xc446ef11, 0x3e3bab0a, 0x67eda8b0, 0x34977a09, + 0x9b7d871a, 0x7198f812, 0xc52aa9bd, 0x28b89ba6, 0xd202ebde, 0x40da768e, 0x5b96a704, 0x8021d717, 0x182f1ee7, + 0x2c0e3b26, 0x83aab449, 0x316841f8, 0x13b60fd4, 0xb675a9b5, 0x76dafbe4, 0x5126202f, 0x9a2add97, 0x0f2fe45f, + 0xdee0063b, 0x3fdad1bc, 0xbb6940d4, 0x972979b1, 0x65e4d7c2, 0x98fb9a61, 0x21ea5ff6, 0xa6c7e4b2, 0x12f55a30, + 0xf027ec38, 0xfcacd75e, 0x984fc764, 0x9d988608, 0x5e2ad22d, 0x1472ac7e, 0xee63bb08, 0x5ea735a1, 0x38416c19, + 0xe9bd0c11, 0xe34fb9b8, 0xc0a58c11, 0xd72bb6a9, 0xb37c6d5d, 0x01ce9dfa, 0x9d42d413, 0x2a5449f9, 0x303d42c6, + 0xde2e7473, 0x81138ce0, 0xd4ced813, 0x90b227eb, 0xecface2f, 0x1976c2ce, 0xb1f46c1d, 0xbb20ea34, 0x8044ef6a, + 0x663ce725, 0x5e023bee, 0x1019e88a, 0xe169528b, 0xea9871a7, 0x8cd0182c, 0xe6c65a6e, 0xc5844a86, 0xfb905280, + 0x493d9eff, 0xcdeb7edd, 0x49f565c8, 0x35382efe, 0x41c6012f, 0x7522ed61, 0x4a89b0cd, 0xe83f020f, 0x0f1b38c4, + 0x4fe14430, 0x412af93f, 0x370bf679, 0x9042f940, 0x1918cd59, 0x41dce0e8, 0xff0bb832, 0xd9eda2d6, 0x8617296d, + 0x902c9ba0, 0x0a202f7f, 0xed98df0d, 0x1e902f3d, 0x2da3555e, 0xb9669907, 0x2379fcbf, 0xd4036ae5, 0x8020d62e, + 0x592cc4ac, 0xb0a923ff, 0xc7562521, 0x95e3c292, 0xe5bb74ba, 0x548c6a4f, 0xe21924d8, 0xfc9685fd, 0x3868f96b, + 0x596d8ff2, 0x2b4c5e02, 0x8a4e6b0d, 0x46d08eb1, 0xe2e1f681, 0xa7c4f867, 0x9795cf1d, 0x3ebe728a, 0x8b7791fd, + 0x4f07afc3, 0x5e7c63fd, 0x5b594d17, 0x766f7e11, 0xdfbb14ae, 0xe4b6d655, 0x8ce030eb, 0xd933c905, 0x6bbbbcca, + 0xe15c3b24, 0x90f3418c, 0x1bfcea28, 0xc2d6ea4e, 0x2ee27e66, 0x5aad2481, 0xc3b155d6, 0xcbe9ebaa, 0xb81a406c, + 0x2353a3ad, 0x8e775572, 0x87f83685, 0xe8ec97c5, 0x21984153, 0x0e28f736, 0x820c9f10, 0x25a1528f, 0x63402342, + 0x10496937, 0xeeca0836, 0x915e111d, 0xafeffb11, 0x530612fa, 0xedd15aaa, 0xb59cfddc, 0x782cc7d8, 0xc0b5329b, + 0xb465bff0, 0x34be34f8, 0x7e7ece9c, 0xe08bd18b, 0x8a7c5b72, 0xdada7e60, 0x36823912, 0xe8ed41e5, 0xd09bb38e, + 0x33c5937f, 0x328f1ca8, 0xaa18cbae, 0x4f86c09c, 0x0b6b2909, 0x8998c4d5, 0x89e616a1, 0x800df259, 0xc1a73795, + 0xcc0910e7, 0xc5e0a9bc, 0xaf877376, 0xd34e7254, 0xf6c7d3d0, 0x27345fe7, 0xe7d414a6, 0x773765c1, 0xc8ecb2b0, + 0xa6db3013, 0xfdff4157, 0xeb31780c, 0xab0e4ba8, 0xceacd38c, 0xceaafe35, 0x12e44493, 0x5ff93d1d, 0xe6bf0cdf, + 0xab34c58b, 0x378ffd2e, 0x937e163a, 0xb36839a8, 0x9c3c50e2, 0x20fc0d28, 0x62a58bbf, 0xc38d1bd3, 0xea888a32, + 0x4b70dfac, 0x7aa1a816, 0x3e615fb2, 0xdba79778, 0x86d09602, 0xdcdedc98, 0x11696ea8, 0xb2125b5f, 0x7eb2ddbe, + 0x22c7d9b0, 0x13ccc824, 0xf5fcdbcf, 0x5f54946d, 0x0d22b2d4, 0xdc408fcc, 0x652cb755, 0xb3a5893b, 0x3e2474b0, + 0x3c59a7af, 0x4f98c0e8, 0x78a02a50, 0x8b77a9a1, 0xd971083f, 0xf1165872, 0xb7952d57, 0x1fcc00ff, 0x0e295263, + 0x4b3945b9, 0xaab55a05, 0x450ceb72, 0xe108b10d, 0xb8f7501e, 0x609a7736, 0xa468dac9, 0xb271c715, 0xa78940c0, + 0xee9e1501, 0xfd725075, 0x3f8cc298, 0x624f199e, 0x8225abbf, 0x072317e2, 0x3fc85d9a, 0x8b2d69d5, 0x51a45f17, + 0x24f140ff, 0x711388f2, 0x402106cf, 0xddaf9e7c, 0xea24a3c2, 0x9782c0aa, 0x475f0eec, 0xecb4d815, 0x0d751830, + 0x71097e32, 0x562720d4, 0x406c8c49, 0x657306dc, 0x1065e1a5, 0xe3741047, 0xaddf4d21, 0x42e1b893, 0x9408f436, + 0x2bdfcb85, 0xb64fc944, 0x2b9d4f7f, 0xc0964a86, 0x0cc4c04b, 0x5626602f, 0xe7f3a9a0, 0xe064e6b3, 0x78f25f9c, + 0x39c0a5b9, 0x5faffa41, 0x9670c8f2, 0x0d791a92, 0x896e5a6f, 0x58488912, 0x46495aa8, 0x71cfc972, 0x2b522db3, + 0x7d18b448, 0x0202fa2f, 0x7d12746b, 0xed73e2ee, 0x8f1a5d66, 0xbb6bca21, 0x1f01ff1d, 0x7ca6f0aa, 0x534b1f85, + 0x64363904, 0xf79763f1, 0xb4962cfb, 0xb78333d4, 0x940a351b, 0xad77b741, 0xab9284ec, 0x50e4ab45, 0xa604108f, + 0xb8d2e539, 0x59f2b300, 0xb36b88f5, 0x85479c0b, 0x01cbec7b, 0xb463a691, 0x218b99ac, 0x145197b9, 0x4df15246, + 0x654f3074, 0x50fd066a, 0x121bde65, 0xa4f91f33, 0x253ae180, 0xb10f21e6, 0xa7b19c21, 0xdbc76fd7, 0xfbde318e, + 0x2b1f537b, 0xd45c7625, 0x5d15b8a2, 0x51640075, 0x0f2dabf9, 0xd64849f0, 0x22b7d9dc, 0x04d675c0, 0x93c7e330, + 0xb6b04e1e, 0x18b676ce, 0x0613791e, 0xe495d79c, 0x3732828c, 0x39bd8cee, 0x3865af6b, 0x09c92367, 0x450fe55a, + 0xb52a477a, 0xd6935ee2, 0x821710c7, 0x157a0420, 0xa6ecc405, 0x85396fb3, 0x149fa01a, 0x760be820, 0xfda404e5, + 0xb7956408, 0xef9cbf18, 0x1abd3f31, 0x3e1d2608, 0x1d47dbe3, 0x0c8ab7ad, 0xce8f2f4f, 0x81db979a, 0x62135d1c, + 0x9fba22b0, 0x255d0948, 0x81b57892, 0x5b9eed87, 0xb7b117ec, 0x541734db, 0xa93c6a91, 0xf87f1d4a, 0x2f9d51b6, + 0x5dc76147, 0x6dcbd4f5, 0xe8ea0321, 0xe84736fd, 0x886f9e43, 0x45e7ad10, 0xb679ca10, 0xb097a2cc, 0xd213265d, + 0x0cf60689, 0xaa52c0f9, 0xdbefc028, 0x293d79a8, 0x4b22c969, 0x049c15bc, 0xb5fb0cd7, 0x74e3afab, 0x0bcc5f5c, + 0xab914cc4, 0x17a23137, 0x649ac530, 0x026ca676, 0xa8d043ba, 0x5cbe0dfa, 0xed29455d, 0x22806b59, 0xa93465f0, + 0xa2bf4765, 0xa4aefc44, 0x869c1b46, 0x167c24e6, 0x38829c20, 0x26a6de3a, 0x660daaa7, 0x67a42c51, 0x577cdfc4, + 0x313166fe, 0xbf03a18b, 0x02f37f21, 0xb6ed477d, 0x93a38f0e, 0x392ee192, 0xd00fcc8d, 0xd891db6d, 0xe6e06cc2, + 0x0e1445fd, 0x6e8f6cb2, 0xfc73bdb9, 0xb6f137b8, 0x45145637, 0x1bd78ff8, 0x68cde174, 0xc584f7ce, 0x4c008c0d, + 0xd9875ff6, 0x1b7d5d6e, 0xb8f23677, 0x4dcd81d9, 0xef57bb14, 0x427e1d43, 0x8e4a0ef4, 0xea350090, 0x9fc57886, + 0xe8afd32a, 0x634fe49f, 0x0d06c682, 0x92dc20f5, 0xe3f1d3ea, 0xade50ef7, 0x41ff4980, 0xf9eb0867, 0x919b3724, + 0x1c2cfd98, 0x35332f64, 0xb5d2b7fa, 0x06bea3f3, 0x3a1587fc, 0x38d5fc19, 0xea47a2f0, 0xf24f8541, 0x58483827, + 0x13e65802, 0xfc381f31, 0x0589ce8c, 0xc4a5aa58, 0xb9ac489a, 0x9ffd9fd8, 0x0e8472bd, 0x09515fb1, 0x2afe112b, + 0x2e995738, 0x70ad8c04, 0xa2271f5f, 0xdf05717e, 0x06bcb3ab, 0x7aa4ae7b, 0x92f28235, 0xcb0e2076, 0xa3491a82, + 0x64f246b3, 0x791771f4, 0x64c2ebd3, 0x2eb432a7, 0x392296b9, 0xff239c33, 0xc230f182, 0xc6792564, 0xe9229518, + 0x6aca1cdf, 0xab316e47, 0x2169cd5c, 0x5a0d2002, 0x01a99477, 0xcea3b564, 0x72f62a86, 0xba5c81bc, 0x4694b048, + 0x403a40ad, 0xed5e2eb1, 0xca600a49, 0xa1f93553, 0xae21f332, 0x528df2bc, 0x6677de98, 0x52c39e96, 0x9e195130, + 0x0cbdb3dc, 0xd3e0ecb8, 0x636ac015, 0x5dbba121, 0xd3de356c, 0x3743ee32, 0x3a08b0dc, 0x2f7754c8, 0x6115f29e, + 0x38c0d171, 0x328fb3d8, 0x4b2825e8, 0x1d1797cd, 0x08e9b22c, 0x6a811292, 0xc8cd4a6f, 0x794c4df8, 0x89f5e291, + 0x8fd3e838, 0xb3e91a0e, 0x6c532d45, 0x52e2e1e3, 0xf5f73a48, 0x37a9173e, 0x7c89c7c5, 0xb502a60f, 0xa7b9a9b1, + 0x0446039f, 0x0ae6dfc7, 0x68f3cff5, 0x914c9300, 0x54c1d026, 0xb7e67eac, 0xf79b2e41, 0x946d2e5d, 0xf876427d, + 0xdcee267c, 0xfafb8968, 0xec45b5f9, 0x36fcdd4d, 0x736ad395, 0xe307bf2d, 0xbe21e874, 0xbf5e1532, 0x2c2b74da, + 0xa08885a3, 0xfb155b15, 0x413e4a7c, 0x2249f720, 0x7910875d, 0x1cc28390, 0xa0a64d67, 0x97dfbbd9, 0xf8ab2503, + 0x5fd669b7, 0xf72e8b03, 0xe6099308, 0xfa1da957, 0x3557b247, 0x28ed15f1, 0x5f2b0b38, 0x60e3e76b, 0xb79b4f89, + 0x288a87d8, 0xda9544bc, 0xfb52c6e4, 0xa03a06d8, 0xc09361cf, 0xf46db164, 0x3b2dc597, 0x4846c497, 0x2b1b2fc1, + 0x1bea8df5, 0xc5091aa6, 0xdc98ae47, 0xdc02b2fe, 0x6c6fad30, 0xaba0e8d4, 0x8f3a105a, 0xee349c46, 0x47ec61f7, + 0xf70b09b7, 0x0351bceb, 0x3303c966, 0x55104394, 0x2efcee12, 0xe2a7e8ed, 0xcc95afe8, 0x47823162, 0xf594498e, + 0x3897f68d, 0x5674dd82, 0x4189f1c9, 0x933fcbd8, 0x44b19e24, 0xe67722d6, 0xc3213d17, 0xffc16c89, 0x2619cc8a, + 0xec7a2716, 0x177af7e7, 0x3a27ef1b, 0x198dd872, 0xb62fe227, 0x212751ed, 0x4c7b84ac, 0xce71f941, 0x58a9e477, + 0x9ac92fd3, 0xccd72f3a, 0xd495648a, 0xa2fb305c, 0xa0573aac, 0x5b69cbcd, 0xc513abc3, 0xb9a2c6db, 0xf1bbe3e3, + 0xd0a057dc, 0xe6c78007, 0x6d4b10e7, 0x05002437, 0xb5b77e59, 0xd96a6c26, 0x5db8fba0, 0xe44a32d5, 0x9515f703, + 0xcf3758ed, 0xe0ecfe3d, 0xf4915c06, 0xb86b0af1, 0x88216012, 0x00d46730, 0x9556cbd3, 0x7654da0d, 0x8a6bf558, + 0x9a513123, 0x5be279bb, 0x1e76b8f9, 0x527035b1, 0xa4c90a89, 0x6a41b51e, 0xce93cd92, 0x4dbb635b, 0xc9664138, + 0xa92d14ed, 0xe0d8653e, 0x1c33b4d4, 0x61b91f14, 0x23ef299a, 0x9c91ce7d, 0xc449bad4, 0x2a935a89, 0xf0019f1b, + 0x3dad3cf2, 0x9de7490d, 0xa4e202d7, 0x8a7b2b70, 0x7fe40f98, 0x313837c4, 0x9cfc9003, 0x8a78fd10, 0xdb99e2c5, + 0x37ca576e, 0xcee2d57b, 0x8e36dda4, 0x1ec9f872, 0xc94db413, 0x550ce06c, 0x5f599369, 0xb654d414, 0x9a48ca25, + 0xaaf6d375, 0xb09f53cc, 0x0d902335, 0xb7cc500f, 0xe7e6f101, 0x8ee2038b, 0x773f6f2a, 0x16170d3d, 0xfde786c9, + 0xf7191c28, 0xa70a4431, 0xaf7100d8, 0x776bb4c7, 0x2f77cd4b, 0xb852fac3, 0x0e655e4c, 0xdf9bf935, 0x17a097de, + 0x24291557, 0x666610b8, 0x13fc3e78, 0x8d31ec43, 0x892ef373, 0x60bca2aa, 0x2d5cf840, 0x2240d74e, 0x4671467f, + 0x9166ef6e, 0xb28b2ab9, 0xb7f4c3f5, 0x3c5c8397, 0x22972516, 0x047b66ca, 0x8cb59ea4, 0x7fcdc877, 0xefe15c41, + 0x4b454373, 0xaf9de36e, 0x84196bdb, 0x9aebd2f5, 0xfb40e761, 0xcc62040f, 0xbf1822b8, 0x692197bc, 0x95510473, + 0xe43bfe6d, 0xea011d28, 0xe12828d5, 0x8886bc51, 0xfe21c3c1, 0xf053a207, 0x12d09ad7, 0x98992fa6, 0x38357e3d, + 0x970c3982, 0xb6666cdd, 0x2ba543dd, 0x57c31b07, 0xd71ed79c, 0x0676abe8, 0x9259880c, 0x8aa55163, 0x626c6971, + 0xbdf9329b, 0xc0ea46cc, 0x751e8146, 0x5f62635b, 0xa9c18631, 0x207e4a7e, 0x341894d4, 0x41e7ba37, 0x14752817, + 0x67d616ae, 0x85fedd68, 0xe66f3e66, 0xd049ef29, 0x446a834d, 0xed52aa3d, 0x829845fc, 0x3d73ffa1, 0x12ab288d, + 0x62c5e930, 0x8a7d72db, 0xec1acb99, 0x1973601a, 0xee419e1e, 0xc802fd72, 0x8bc0bdfe, 0x2693a6de, 0x516d969f, + 0x3ee0e70b, 0x84557cf9, 0x1252d8fc, 0xc0a1e4eb, 0x3f5d18eb, 0xab656669, 0x59eda8da, 0x0602afc8, 0xf0f59d26, + 0x4a9cc948, 0xc15df9c1, 0x8517cb7d, 0xac35a82a, 0x40e5e7b0, 0x82be5fa3, 0x2967256e, 0x154683c5, 0x328336d7, + 0x8ee13d01, 0x054a77f9, 0xdc8dfa8e, 0x9314e2d9, 0x1d11bc67, 0x37adeeb6, 0xb37a3970, 0xdef88bea, 0x5a3fb546, + 0xeec864e9, 0x69079a52, 0x5b6c281d, 0x652b5fa8, 0x41b54190, 0x6ada62c9, 0x57d6503b, 0xd5fa054e, 0x340f6528, + 0xebde75b9, 0x514db0b3, 0x968af532, 0x8e39da98, 0xb32013e7, 0xa1ae07d6, 0x6974ac93, 0xdaf12ac7, 0xda9b2fd9, + 0xe7c82620, 0xf342a768, 0x42f37a37, 0xf708bb3e, 0x03746d89, 0x43ccbdb6, 0xb8a4f174, 0x26185dc6, 0xc33f1daf, + 0xf4e383b1, 0xc163532f, 0x89b644d2, 0xfd4c42c5, 0x6f5ab915, 0x41e01797, 0x70c08533, 0x7d1708b1, 0x06d8ff40, + 0xac9fced0, 0xa4692cbd, 0x06cd7616, 0x15a09a4f, 0x6f4cf990, 0x9ade62ba, 0xef0a55cd, 0xe65f512d, 0x14a9a6cc, + 0x864d2457, 0x2c92d696, 0x826f3cd5, 0x8538e4e7, 0x623d178b, 0x7bfd4c40, 0x0b1f6ec9, 0x4859af36, 0x3b440073, + 0xadc72b87, 0x6ce7c1f7, 0xf469f24c, 0xd7a7339f, 0x7beed0c1, 0xea578fb1, 0xd3351d5f, 0xec52d415, 0x7a22659a, + 0xe7f874fb, 0x2af25aca, 0x49162db1, 0x73c04f18, 0x23e4d68c, 0x7511ab18, 0xc0457bfd, 0x64b4c8db, 0xbae9d6a5, + 0x64a2e02d, 0xc323bd4b, 0x3f1ba565, 0xa1e0aa42, 0x572fc54b, 0x29be698b, 0x515ab560, 0x824faac3, 0x6757561a, + 0x66d51d64, 0xf6d49c2a, 0xfae4e68d, 0x6f60e468, 0x3ce2fdbe, 0x0c2cb965, 0x4abce6a3, 0x4b914c4d, 0xf1bd3d95, + 0x600bbb67, 0xd7d7a2c0, 0x6dd831c6, 0xff9fa011, 0xaabd4736, 0x512923d7, 0x430cebf3, 0xcd0cff4d, 0x34247a9a, + 0x2ff954a7, 0x351072ec, 0xc9ce8403, 0x927bdfb4, 0x49e69ef2, 0xa0259da6, 0x0a2ea644, 0x3891d9d4, 0xeed9a3af, + 0xd26a515c, 0xdee23958, 0x64c18674, 0xca7ed465, 0x8c248ed1, 0x68e11b76, 0xa4740df2, 0x3ce842b7, 0x29b073ef, + 0x2d0a2c87, 0x5594252a, 0x84dd4a70, 0x7566188c, 0x96a6104f, 0xa5ff721d, 0x7e480c35, 0xf520a9c5, 0x0b135ddc, + 0x13aa422f, 0x4bf3f455, 0x2cb5fad9, 0x6618df74, 0x50c96384, 0x39bb08e2, 0x29365842, 0xbc770a9c, 0xf0b1f6c5, + 0x87fedb92, 0x36cab353, 0x18b38d9f, 0xa3c773e7, 0x26243ae8, 0x52634b5d, 0x095dff58, 0x4b3fefd1, 0x38c35516, + 0x8a5527c8, 0xc0e91fb9, 0x617a6a82, 0xc78aca6e, 0x4e141cc7, 0x8551b2e5, 0x3f3e2d83, 0x04ae9b8b, 0xdfb93fe0, + 0x935e97dd, 0x5d0067ab, 0x0809c94e, 0x6cf610c1, 0x081e1c38, 0x62bad1e8, 0x01eb3a5f, 0x932dd4bb, 0xe93765ba, + 0x5feaf2d5, 0xd9f2a81d, 0xce1bbf0c, 0x25801f6e, 0x6e9fe3b8, 0xf7127f79, 0x716cc5de, 0xcdce8875, 0xf7be5d83, + 0x834e6d41, 0x7e9f5733, 0xbf9475cd, 0x43e1428f, 0x38a91315, 0x5180e8bb, 0xa93f8820, 0xa8147621, 0x7849f87b, + 0x46925db8, 0x8cb7e319, 0x612ddba0, 0x001e9b68, 0xf6421358, 0x7a99f170, 0xf10114d9, 0x95214251, 0x497a84cb, + 0xe66ccb41, 0xdb3801b8, 0x81700b0c, 0x791906b2, 0xe9f66e65, 0xa94ec529, 0x9b8bd75b, 0x7e3822c5, 0xfb3bfef8, + 0x026e0ea5, 0xbcda7bcf, 0x76e0eab1, 0x34abbadc, 0xb6bd906b, 0xd563254f, 0x2b1564e9, 0xd7f96d1a, 0x1604e23e, + 0x3d7f6b19, 0x2823f4ae, 0x91803bba, 0x1feb466c, 0x8e29abad, 0xa6fb051b, 0xc9329b3c, 0x397dc74f, 0x834e3d39, + 0x24c8b1c4, 0xe9218760, 0x7f51f92d, 0xdc665094, 0x594c60e3, 0x2b9087f2, 0xbb530e3d, 0xd8e2532f, 0xe70dec8b, + 0x9d5b02e7, 0x4f33f940, 0x6dcabbf9, 0x97c59fbc, 0xb80dd7b6, 0x10cb7031, 0xd8a4e531, 0xb3d9cf49, 0xe770aef7, + 0xf8daf624, 0x0f4edd8c, 0x047dc4af, 0xcd45cb9c, 0x7742b064, 0x120b1d79, 0x57f7b75e, 0x5aca1b64, 0xf6261613, + 0xab7f40fb, 0xedd3ace5, 0xaa108e88, 0xa4fef4b9, 0x3d207fd9, 0x139afff3, 0x3130ff6e, 0x90d446fa, 0xc88b5c48, + 0x4eee411f, 0x62160986, 0x86794000, 0x6766ebfd, 0x8aca1dee, 0xf35657de, 0x70499e2e, 0xb5fcb374, 0x02e6865a, + 0x9b447167, 0x003b86ff, 0xe94c2dd5, 0x7eee204e, 0x67d81617, 0x22084679, 0xf4fed369, 0xc32fa73e, 0x9c5cf1bf, + 0x90a4e7fd, 0x9283b75d, 0xbf361afe, 0x7eee61e1, 0x2afdb7a3, 0x7549a3f2, 0xe09325ed, 0xa9ca9a43, 0x7fda3f9a, + 0x5fde4f09, 0x0aab6e7f, 0x033ff31f, 0xe9af8f9f, 0x89917b90, 0x7c336df1, 0xbe61ec5e, 0x9dfbb352, 0x874a84e8, + 0x4a95c8eb, 0x32fa449f, 0x109c2845, 0x8a1b4f1c, 0x20ad6447, 0xf036d24c, 0xac0dbbc3, 0xf5c4fb49, 0xa041a18c, + 0x79a3583c, 0x52ed9c8d, 0xf8dd6ea7, 0x8b49e8b6, 0xf485bd2e, 0x58589789, 0xfd2a66fa, 0x4600ef3c, 0x6c420c18, + 0x10cec589, 0xd128967a, 0x41012023, 0xaf36dfad, 0x5516fb00, 0x64f47b56, 0xd9de40e0, 0xbc86d296, 0xa671bdf9, + 0xfef3634d, 0x00e47de7, 0x146c67be, 0x5d7bdc45, 0xe41bc908, 0x30f5f3e8, 0xc2cb4fc0, 0x462e390d, 0x47f44cdf, + 0x5e2bd117, 0xe2d32da4, 0xeb1186fd, 0x663e9b71, 0x925a7173, 0xb2dddd4e, 0x741387c5, 0xea3c7e65, 0xecfd6fac, + 0xdf6ba372, 0x8b1054a1, 0x8fef9277, 0x26e0373d, 0x771bd852, 0x607c92e5, 0x2a5712fd, 0xec0adb22, 0x0bfc6271, + 0x5a357fcc, 0xda2a7ad1, 0x5c8d6a44, 0xb6e3a28e, 0x827b0ab1, 0xd1ac89f9, 0xa18fae7c, 0x239ce775, 0xf07a8e9d, + 0x9ca0d430, 0x1127d243, 0x5fcc0cc0, 0xba902cbc, 0xa08ea038, 0xb82b6c3c, 0xe6ffe2fe, 0x7ff9c902, 0x0e0551e4, + 0x8a875c7c, 0x773f0c91, 0x504ee699, 0xc38db733, 0xd81b93e1, 0xa9e0cfa0, 0xaeb53e21, 0xd6ba08ac, 0x1abf6422, + 0xa0a24e53, 0x2264ceeb, 0x196d5e79, 0xb1d4a626, 0x4964ec2a, 0x79b37f12, 0xeb25dc26, 0x537cb2b6, 0x3a2b89ce, + 0x1b270d37, 0x08e65679, 0xe3a2d634, 0x94db7688, 0xbaef682c, 0x4b674253, 0xfa7bb5b6, 0x2ff2954a, 0x3fda8edb, + 0xabc2f7f1, 0x9943d9dd, 0x23630ebb, 0xada84553, 0x2253c288, 0x5e9d4fbf, 0x755b27e6, 0xcf618daf, 0xb1e89948, + 0xd04b5825, 0x3da39f52, 0x4dc5aab3, 0x3e876497, 0x4664d2c2, 0x11cb933f, 0xbd7a4323, 0x18277384, 0x88fea815, + 0xeb6a2785, 0x218aab6c, 0xa0bc46ff, 0x74843e02, 0x095ee4ee, 0x2a256c7c, 0x12e6b620, 0x8b22a80b, 0x25ab0e1d, + 0xef0fe0c8, 0x339eeb4c, 0x3af729bb, 0x16c971f0, 0x8128c8ac, 0x05aac8e1, 0x5f2fbea0, 0x698d106f, 0x1e754ab8, + 0xa5805ede, 0x2c8939bc, 0xc7f6c34f, 0x918a86f2, 0xbf42c1c6, 0x873e997c, 0x58be5197, 0xe3aa0a26, 0xb1ff58a8, + 0x9f3aecbb, 0xa0dafc2a, 0x3157cea1, 0x87331abf, 0x2d9e482a, 0x5d463f47, 0xb1ae224c, 0x34d06e0b, 0x6d4c3509, + 0xeb2724f7, 0xe66953fe, 0x505a3ad2, 0x33af63d8, 0x8ec1aac4, 0xa47385d1, 0x694edcf7, 0x78152178, 0x437103d5, + 0x4c3887d6, 0x4b567cdf, 0x5cef27b4, 0xa38b39c7, 0x1f22d6f6, 0x5121c187, 0x58a96758, 0x245d547f, 0xbf43c664, + 0x1a533907, 0x89274d3a, 0xe49d4e09, 0x2c04dc3d, 0x8144a12d, 0x943c1e35, 0x818764bd, 0xb7f0c47f, 0xa7507908, + 0x73b9ea7b, 0x3fa1ebca, 0xe843a599, 0x881bfdc2, 0xadc5a09c, 0xf3cbb29d, 0xb182ba84, 0xf69d19db, 0x850fc7d2, + 0x37bbb63c, 0x77fef4c2, 0x9d41a9a4, 0xb8c86cde, 0x53aff106, 0x9f909e9a, 0x7f597dc6, 0xe585f72d, 0xbb5d07eb, + 0xe4b7848b, 0x2efe0de9, 0x901bcb33, 0x45f214b2, 0x00ed2241, 0x3d96f08d, 0xce4547a8, 0xbaecd859, 0x74f3c583, + 0x062b4771, 0xdcc4f4e2, 0xd4466f17, 0xe43d50f2, 0x28210a78, 0x13d9d2b4, 0x6e6e6afd, 0x0018dab6, 0x288eac9c, + 0x757c872c, 0xeee675a4, 0x1c8cd5f6, 0x1c4687c5, 0xc606f1eb, 0x4e334f2d, 0x4956c9c8, 0xb25d635c, 0xf483855a, + 0xac0afa69, 0xbaacd825, 0x6de3ace6, 0xfe3944b2, 0x2663461d, 0x5d37e3d5, 0x1e078e1b, 0x9a88bd2b, 0x5cd42fea, + 0xe0b0d1f6, 0x330b2f24, 0x6ee41ef9, 0x063e2729, 0x381f0641, 0x7f09b2e2, 0xf7bad7ce, 0xc19f095f, 0xcde8118c, + 0x951a0a5e, 0xcb9bf837, 0xb8e4cbe1, 0x7d6d2656, 0x4d2c88c3, 0xa6a92f8d, 0xb4d5bfc8, 0x04e42019, 0x52d2c865, + 0x17c7d0e0, 0xe0f22c7c, 0x56c8f886, 0x4c6b65e7, 0x886ec848, 0xb09c6d89, 0x7eb9b8a6, 0x415b8c37, 0x61583ac1, + 0xaea9138c, 0x96959aef, 0xc5006775, 0xf0589494, 0x6b184329, 0x7603c2cd, 0x89ef9bad, 0xdb43e967, 0x858e8ad9, + 0x5724c21c, 0xbde9109a, 0x9208c775, 0xe7f7b9b6, 0x0f1c3915, 0xcbfce177, 0xec001464, 0x639ca4f7, 0x795c29b9, + 0xebaad556, 0x86911d0c, 0x3eeaa8a3, 0x1b42f8ff, 0x1356d98e, 0x6f52283d, 0x373d551a, 0x3f887bf1, 0x23d94215, + 0xa0ad7b64, 0x99185b91, 0xa375a1d5, 0x87f4b2bc, 0x2c77ef9e, 0xa20d2e78, 0xb2da30ae, 0xd7624bb4, 0xe6c80338, + 0xd74f006b, 0xe4dc154b, 0xd3215f98, 0x3cef2210, 0x282c4de8, 0x908cc735, 0x2501032e, 0x35e0d38a, 0x71f1906b, + 0xd00c3646, 0xbfd57d85, 0xe277e9a1, 0x8bb59a7f, 0x29a9211e, 0x79ecd0a7, 0x73fce84e, 0xf7a111c0, 0xd4dcc9e0, + 0x5788257a, 0x94d75904, 0xe0018996, 0x7fd14d01, 0xe4472702, 0x494d39f1, 0x1165187f, 0x3e86f031, 0xd78caf2c, + 0x0d35875d, 0x80714537, 0xe3f5dbc9, 0xe21bdf18, 0x87668771, 0x8214f18d, 0x61484345, 0x365f6568, 0xedc7d701, + 0x702f42c6, 0x46e52880, 0x9a34f0b6, 0x58f7ad41, 0xe9dbad6c, 0x1131a56c, 0xc8c62bf7, 0xd3b86c43, 0xedeeacbc, + 0xd548a9ba, 0xfe65996a, 0x1cd38288, 0x22c06682, 0x0741f7d3, 0x76b06110, 0xc4847226, 0xb92624ec, 0xfd5f4c69, + 0x6dcbf1c1, 0x74d9d587, 0x282315c5, 0x73b80ee0, 0x79c641c1, 0x1b6a75da, 0x8ea80c2d, 0x789c55c3, 0x6e438329, + 0xdf7f9ad1, 0x0534f6fa, 0x982db703, 0x920b07c6, 0xf381f7bf, 0x65dff83d, 0x585dce1b, 0x3dcf7493, 0xb45ba84b, + 0xa1b5c716, 0x4d8fcbb8, 0xd1b67e4b, 0x70fb13e7, 0xfd3f33a1, 0xf925dc55, 0x2074b179, 0xb6fc6b3d, 0x665b95b9, + 0x8a18ac0f, 0xe65ff044, 0x918752e9, 0x09181724, 0xe016c144, 0xb460349d, 0xdfbc7486, 0xbfe0b4a1, 0x87d426f7, + 0x7baaa3af, 0x3eb8ef84, 0x54619fa7, 0x2357a6a7, 0x3f5af2a8, 0x66546bbd, 0xd2e5fa66, 0x631cde90, 0x57d904ce, + 0x7a63b845, 0x5edfdccb, 0x389b9dc9, 0x12845a1c, 0x2d7c95c0, 0xc5a84057, 0xa2089844, 0xbfcaff27, 0x0982da0f, + 0x2fc76c10, 0xf8134856, 0x24fbae44, 0x33a769f2, 0xa7c17dec, 0x0ee5cf84, 0x57537b74, 0xbb1b48c3, 0x3c4b57ea, + 0x99d0e85e, 0x22e4c073, 0x9e9a9628, 0x678e08b6, 0x4e6b0738, 0xa4baf678, 0x0c452b80, 0xece14c65, 0x52e2d419, + 0x70241e22, 0xf2133310, 0x3b67d6ff, 0xc348243f, 0xa2166dfc, 0x478e801c, 0xc01a2b47, 0xa0acb55e, 0x7eb5c8b2, + 0xce413ca9, 0xc365315d, 0xf1f06f60, 0xb72a1665, 0x23fa9dae, 0xf07ba472, 0x4dab06e7, 0xad70b929, 0xe8e15382, + 0xf3d806fd, 0x5c0d6243, 0x9e6e09a5, 0x4b2e1ea4, 0xd06bea34, 0x26d90fdc, 0xe0a026b3, 0x64fadb39, 0xfef109de, + 0xf7f5d089, 0x75610534, 0xab987a67, 0xcb1a7f6e, 0x5309d8dd, 0x03ecc23b, 0x7b0e9f70, 0xbd8ce8fe, 0x8cdb6889, + 0xc694ebba, 0x5e7d56b6, 0xa9d1b3c3, 0xb0e54f94, 0x75702294, 0x520b350b, 0xec6c3308, 0x69efaf4f, 0x7db1f1c8, + 0x867dab6b, 0x02fa9b64, 0x0486542c, 0x3c8ffa13, 0xaaa6cdc3, 0x94a85190, 0x5cb8ff4c, 0x1ad16742, 0xb7dd087b, + 0x895e1853, 0xdfa300f0, 0xde0816e3, 0x51d4bc39, 0x42db07e8, 0x8e38c787, 0x3d120831, 0xb1c45140, 0xe86fb2e3, + 0xd91d97d6, 0xb9201882, 0x35d934ec, 0x9e3864ae, 0x5669f44c, 0x729e4097, 0xfb70bb2d, 0xf6e82a80, 0x69102041, + 0x8d970131, 0x9c6ec3fc, 0x55414f75, 0x81cc6f0e, 0xf55467c8, 0x237090d6, 0xd6c17104, 0x22e85f64, 0x80e54958, + 0x72c88314, 0xaf38d8c8, 0x59a549a7, 0xed461130, 0xec01d237, 0xa164c770, 0xaafff3ee, 0xd1d38cd9, 0x15d6406c, + 0xdbcb3278, 0x2fb80e05, 0x2b92a1fc, 0x7a8a2f8b, 0x863bc38e, 0x750bc533, 0xf05030d7, 0x4c963597, 0x22828d28, + 0xa530f4e5, 0xfe56c11d, 0x9f331644, 0xcc55f03d, 0xb648b85d, 0x507c46f6, 0xfd1ec2e4, 0xa46166aa, 0xb5a7bbe1, + 0x9e7b227d, 0x0c6e87f0, 0xc951c36c, 0x2a759ca3, 0xd392659c, 0xf0cc3ecf, 0xe2a3a25d, 0x753cbbe4, 0x64cd6030, + 0x9d95b770, 0x5561dfa6, 0xbad48511, 0x52dd3fe2, 0x83089103, 0x5c56fd33, 0x41d6ec24, 0x9701e6e8, 0x188316db, + 0x6a35df86, 0x3c2b5014, 0x00fb3780, 0xa4cb2777, 0x28dcb364, 0x6e785db9, 0x0552e74d, 0x5e13f9c5, 0xccb5437f, + 0x3596d6cc, 0x5a5abb37, 0x4ddff1e1, 0x2e49421c, 0x792d7d59, 0x1658fe9c, 0x12edf351, 0x7485c25c, 0x6dc7e402, + 0xa0cef01b, 0x3d4f115e, 0x793ba937, 0x6168ecce, 0x5e4e5e73, 0x33fadbeb, 0xf6bbb231, 0x8434fa13, 0x233e953e, + 0xf74af074, 0x0a2cec34, 0xe6019d9a, 0xfc38bc15, 0xa8e1c654, 0x988db951, 0xa362c104, 0x5976234b, 0x197ff2b4, + 0x28081f8b, 0xa54effd8, 0x112daef2, 0xa3347a89, 0x933e973e, 0x7329c0f1, 0xc8e6a7b7, 0xd3321fe7, 0xa01f1eff, + 0xb98b704e, 0xbd809b91, 0x4a4f442d, 0xf3e62bb2, 0x6a60722c, 0xc4f7e65a, 0x03b316ba, 0x44ca9479, 0xc4b7b258, + 0xf7774824, 0x0b716653, 0x713e31f2, 0xd474c802, 0xab89f1e3, 0x19a40c6d, 0x568fa40a, 0x976761f2, 0x7d6b8f38, + 0xf4af5730, 0x0c766bb1, 0xadc9e03c, 0x7cda91bc, 0xda29b36e, 0x5d0dec1f, 0x7cc9e527, 0x8e47df0f, 0x5707c9c4, + 0xfe856f15, 0x9191a666, 0x0322357b, 0x9b04506e, 0x6e389c72, 0x43d7a096, 0x86457a5e, 0x8b97c4be, 0x5237e9be, + 0xb134e5af, 0x6f7fdaf7, 0x1ff1b10b, 0xc4658d73, 0xf377b1db, 0xbeca46f3, 0x4614847d, 0x3625ecc3, 0x7d1523b4, + 0x1879af4d, 0x37507d15, 0x1ed932c5, 0x431f5ea3, 0xb4181561, 0x056a4eed, 0x65fa0381, 0xc9d72b85, 0x76a55160, + 0x4bb67fe8, 0xebb23952, 0x7d84218a, 0xdee2da66, 0x1b1c361d, 0x26de5b0c, 0xe6b198a7, 0x1b808be5, 0xc3cda3b8, + 0xb3c41531, 0xdbcadfd4, 0xdd19656a, 0xf7131673, 0x1f87732c, 0x479212d1, 0x77949289, 0xa62e8a85, 0x672af91c, + 0x8ce44bc5, 0x7662cb49, 0x3d1ec754, 0x5719cf80, 0x8ffd9996, 0x0f9cbeb9, 0x33bd8096, 0x7fb0a557, 0xc7107ed9, + 0x0d9f6575, 0x33bc0899, 0x0683d34e, 0x8d66ff67, 0x69c93ff6, 0xf1dd39e3, 0xd42c1253, 0x64718172, 0x7128639c, + 0xfb5311fe, 0x732e0fed, 0xbc425d3f, 0x5367d1ed, 0xae92f712, 0x01e400ef, 0x3f9871d8, 0x299f31f6, 0xd00a1760, + 0x6de9ddc5, 0x85f83625, 0x19e2f7d2, 0xe2640230, 0x38e60a85, 0xc556c0f8, 0x2483cc25, 0x65f73f14, 0x43ee09e3, + 0x53bc0395, 0xdb98ceec, 0x6833ded5, 0x0fcda82c, 0xc2d2ed99, 0x7f805fbb, 0xd6983f7b, 0x846c14cc, 0x801a2b80, + 0xa6663b4d, 0x46d92db4, 0x248685ea, 0x07da45e9, 0x5545292f, 0x7fc5c7ab, 0x38b53158, 0xaf78896e, 0xb5c13cc6, + 0x15762d2a, 0xe3fefb16, 0xfba2cfb3, 0xd17c0155, 0x45c8983e, 0xbd2479f6, 0xbe6541a0, 0xad375200, 0xe13fd087, + 0xfd23d06f, 0x33764aaf, 0x4a9901cb, 0x12e36380, 0xdd0d9584, 0xeb20eade, 0x68eee3b1, 0xdfcf356a, 0x8eb23907, + 0x03f276e7, 0x673836bf, 0xa977a014, 0x1dbe3e0c, 0x4ef02490, 0x6be57d22, 0x4a8d19a2, 0xcd708700, 0x175739d5, + 0x44902716, 0x3dad09c5, 0xad622923, 0x80485a7a, 0xea394645, 0x486d9da5, 0xd08479d7, 0x7ba9b2df, 0x9a38af9b, + 0x47d29219, 0x2dfc3851, 0xf2fd4e2a, 0x5f28ce9f, 0x18736a3a, 0xe8367aa3, 0xa25993fb, 0x633ec90d, 0x2f1607cf, + 0x383dafbd, 0x5cf7e74d, 0x62ff2f96, 0xa9e83e77, 0x0582697d, 0xf4f06fdd, 0x11905275, 0x3baff5de, 0x4c432aca, + 0x11415fbb, 0x5dfd3ef3, 0xfc193cf0, 0xc2b7700d, 0x6428c8c3, 0x1ff791a4, 0x6f273d41, 0xad75a85c, 0x741a6ebe, + 0x2ac5f203, 0x39ff7d3b, 0xbe056b29, 0xffd6798b, 0xcc6e93cb, 0xcf971f63, 0x290ddf50, 0x5fb5bf16, 0x367913ce, + 0xb3a5e0a7, 0x05a606ae, 0xf1d6c152, 0xa0e78f79, 0x7a118493, 0x4f6df83a, 0xc50c49dc, 0xdbb11418, 0x05485514, + 0xb68b0617, 0xecd1711f, 0xd2deafe2, 0xe7d5161e, 0xde4b7420, 0x696e7013, 0x781a5340, 0x831c653d, 0x950b8963, + 0xf876cee5, 0x92d0555d, 0x216616a5, 0xd363af6e, 0xe5e42293, 0x7e5432b7, 0xe522a9aa, 0xd6ed74a4, 0xa3fc70f9, + 0xc964c5d8, 0x14b1a001, 0x552ce9fc, 0xf2a4699b, 0x8b44956f, 0xb41fdda9, 0x30471445, 0x0cc9831d, 0x4a273803, + 0x4b4e2433, 0xf679b6e1, 0xd90eaea8, 0x9eef5982, 0x13913c7c, 0x0df05d89, 0xd7e6c197, 0x7b4a5697, 0x67a0160b, + 0x7f1f7254, 0x9500279c, 0xbaf8afb7, 0xbf57730e, 0xa0d5821e, 0xd49d5a51, 0x0198b143, 0xe38b2176, 0x59b767a1, + 0x8202253f, 0x4b926c91, 0x7b49e2fd, 0xe059bfe7, 0xeb855704, 0x817cd133, 0xd001ef95, 0x6bc6b50c, 0x58a3bcef, + 0x9dc7b03b, 0xa21511d4, 0x8cab6780, 0xe15dee57, 0xb4b2a776, 0x8d7a18c3, 0x96139aeb, 0xa36d57ab, 0x3e6b9bef, + 0x78b6910e, 0x2a22f148, 0xf5928a4b, 0x74de62fa, 0xd2c12951, 0x18494bc1, 0xc4563ec2, 0xa44d2052, 0x51ca012f, + 0x57da37c5, 0x6ba75a92, 0xefedaf56, 0x8b395b37, 0x1f2249c0, 0xc3b4b3dd, 0x378ddb72, 0x5ad387df, 0x2ae86339, + 0x1eb4917e, 0x0cdc48e2, 0x303c30e8, 0x70c82d90, 0x30e4346d, 0x003b6837, 0x7b16741e, 0xf29def62, 0xfce6e573, + 0x92f502a9, 0xb8a6a990, 0xe2b6ad07, 0x3510f797, 0x43b519d2, 0x6cbba8aa, 0x98389e8c, 0x6fc0a781, 0x01cdd630, + 0x550f8471, 0x9aeb0a6d, 0xf1858735, 0xa81127c6, 0x84d76970, 0xfc6de9d6, 0x526c667e, 0xdd1662c2, 0x60fa6220, + 0xad474748, 0xc13be8b7, 0xc1fcf12c, 0x78297863, 0xefd30fba, 0x3fb53e6e, 0xc840535b, 0x1ed3b79c, 0xcb407887, + 0x58ed6ce6, 0xdda583ab, 0xb4dbd8e2, 0x0b54420c, 0x0eb91a9b, 0x6e66de64, 0xed3f3c79, 0xdbac5a9c, 0x9501921e, + 0xa11c05b8, 0x90a5eafc, 0x9d376a6f, 0x5d3749c7, 0xd2338caf, 0x68390f3e, 0xbab36b63, 0x028713d5, 0x7cd63fe3, + 0x7f451c51, 0xba68428d, 0x0a4e84e6, 0x733f5219, 0xcbf14d8a, 0xa56492ff, 0x0a8fcd56, 0xd56487ac, 0x8524d84a, + 0xf3fb3800, 0x73b8168e, 0x132b05da, 0x9ddbcdcd, 0x89155ad9, 0x648a313b, 0x53f8aed1, 0x6a1ba35a, 0x016decab, + 0xc3e164d7, 0x88c36822, 0x9c391d36, 0x3e9691c9, 0x0fdb6104, 0x9379cda1, 0x6e4c5190, 0xd37ff0c3, 0xecbcd5bf, + 0x2c006a06, 0x27c0b33f, 0x19ae4c9e, 0xfebf753f, 0x1439e7fb, 0xbfcce61a, 0x9aad485c, 0xcd79fb2b, 0xd659c786, + 0x5cf7aedb, 0x63ced1a5, 0x59d62f1f, 0xb69e6f9e, 0x777cd16a, 0x32324346, 0xb4fa7897, 0x538be394, 0xb13d8737, + 0xc988d64c, 0xa1b0a07b, 0x1a1fb9e4, 0xcbb1fc1e, 0x8d0b3c60, 0x91c540fb, 0x0afb4536, 0x5b53e69e, 0x87908ead, + 0xe946463b, 0x33b146f0, 0x4676f1f7, 0xf9076ccb, 0xd1c7dac4, 0xccf82253, 0xe9373083, 0xc93619a4, 0xdb9e0fbd, + 0x38bb52f4, 0x860fbe63, 0x408a0128, 0x38d72c6f, 0xeccc4387, 0x8b09bc6e, 0xe29c73f3, 0xb69fc52c, 0xe11ce470, + 0xf71f2ae2, 0x89f19697, 0x71baf433, 0x3f368c57, 0xec8b4221, 0x5f11b2c8, 0xe9af0467, 0xd929f410, 0x8bf15900, + 0x9181cfb2, 0x5d89ad1c, 0x5cebacd8, 0xad6aedf4, 0xaac6d7cd, 0x3f7de0c1, 0x2253c30a, 0xd3a5b514, 0x9dedc635, + 0x3cf7f991, 0x9f90f09b, 0x1074f826, 0xe3cb630d, 0xe76ff527, 0xcc02e964, 0x5a325892, 0x0de4b6c5, 0xd6e0cfee, + 0x3246327c, 0x208596d3, 0x8706f335, 0x6bd96a34, 0x59566a65, 0x10299e64, 0xde12fc29, 0xfe8edc8b, 0x441585e7, + 0xf75ac94a, 0x3013043e, 0xcd09d4ac, 0x05ef90a4, 0xc3f4ffa2, 0xfea81602, 0xdf87848b, 0x74b88809, 0x629cfe46, + 0x52119433, 0xb160cf47, 0x1dc14d96, 0x903fe521, 0x8add9853, 0x6b6987d9, 0xa4e0264f, 0x18aa4f5a, 0x0f925972, + 0xefbd1bc4, 0x8fbf061a, 0x736a447a, 0xe5c64d70, 0xd69d4523, 0xd0b96b41, 0x18c8bc53, 0xd5a28bb1, 0x4979a854, + 0x7f4ccd1a, 0x855a6dfc, 0x2a15e39d, 0xb6086da9, 0x5a16ae26, 0x5aad5615, 0xd1cd2631, 0xd529fef8, 0x652d1a9e, + 0xa9fd1595, 0x7831bc22, 0xd2e1c199, 0xf11b3c64, 0x55f838cb, 0xddde80a2, 0xaa9016c3, 0x61ebca30, 0x81928da4, + 0xcb50fb15, 0x3ad1194f, 0xed734bb6, 0xd3ac70c4, 0xf67bbae2, 0x006f5ae7, 0x39bcd04c, 0xf535f0ce, 0x89650392, + 0x257a52dd, 0xc1af2125, 0x21a99ea9, 0xf1580545, 0x4f7d6e2b, 0x978e4afa, 0x8e5ddd9d, 0x9933e44a, 0x3e16f068, + 0x4663ecc3, 0x107bf2f6, 0xd8671a62, 0xfc749f93, 0xd400b4de, 0xce22c8b1, 0x451a907d, 0x5c8d5be9, 0x69a6a902, + 0x3d95963e, 0x69c8041d, 0xa3da3c76, 0x904ea4e3, 0x5ac07038, 0x3d8b0ea9, 0x35718b18, 0xabe7f1a1, 0xf40f33c1, + 0x111828a3, 0x80bbd846, 0x52d60086, 0x77a0999c, 0x75a8fbda, 0xe91a3375, 0x0ca3c22d, 0x8d814383, 0x3043ee3d, + 0xfe2a9bd8, 0xd8ddeedd, 0x586d8a15, 0x28584a1d, 0xb23a3ea1, 0xecdf8d57, 0xe43ce264, 0xea5be807, 0x4a59536a, + 0x47d37452, 0x221f56ef, 0x26e2a6f6, 0x5247a38b, 0xef041518, 0xebc8a600, 0xfb9f4883, 0xbc5bdaa5, 0x9eed1f33, + 0xdcc38da1, 0xa23a13ed, 0xdc5c360e, 0xf7dcd60d, 0x5b36dbfd, 0xfe525403, 0xec4bc871, 0x80c88efd, 0x432ba722, + 0x11830573, 0xe89bf1a8, 0xf4effdfd, 0x689e0cd0, 0x6cb3b854, 0x012cc8f5, 0x28e07e11, 0xb6966fc4, 0x88cd0e14, + 0x9c4098ea, 0x05a98fe5, 0x9aa665ca, 0xb31d863a, 0x13a9c117, 0x9b606711, 0x0581302c, 0x852387eb, 0xac33bb91, + 0x4dd4f240, 0x4c5d9e34, 0x8d9fc297, 0x2c9c1dc2, 0x03d0de5b, 0xc4fb057d, 0xd95b2317, 0xf7604f10, 0xbd4aea46, + 0xcf0b6a25, 0xf3ea9ac4, 0x0c1ba822, 0x67bc4508, 0x2f6f80d3, 0xf3d6e557, 0x2ae09b11, 0x599848ee, 0xdce0f251, + 0x8b391458, 0x9465130a, 0x51728625, 0x152b6e26, 0x88480e14, 0xf2444b00, 0xb500818d, 0x95c690cc, 0x90a4f97e, + 0x2c9a35f9, 0xb331bbf4, 0xa5787876, 0x2763523a, 0x8b3fbdb3, 0xd36ed5ea, 0x7bf65f61, 0xfabb0a7e, 0x9c16fdd9, + 0x001ac402, 0x4f3a5c1b, 0x1b4a1e96, 0xd05fde85, 0x42259641, 0x0aa58350, 0xfd814c32, 0x883d61b3, 0xbdfcec56, + 0x42feb0b6, 0x23f31d94, 0xccc0e470, 0x06eec3cf, 0x2d7efe5a, 0xa3eb0ee9, 0x027a8029, 0x5b52bc45, 0x3ac2190f, + 0xcaae2140, 0xf25ca322, 0xc4fc766b, 0x220634ee, 0xdf60b7ca, 0x7a7f7417, 0x6411d4d0, 0xe4b3db45, 0xdd9bd269, + 0x6e165565, 0x6ea07055, 0x57bcb761, 0x736c57c4, 0x18cf5d14, 0x788e9871, 0xa36acf3f, 0x2a6b0877, 0x98ccf3ee, + 0x2329f53a, 0x957622a1, 0x79c61871, 0xd9bdb698, 0x9d49d202, 0x12df54a8, 0xe42a0c84, 0x4824ba5c, 0x79b8629e, + 0xad877be3, 0x6bd3ab44, 0x3b9bc76d, 0x12abbfd8, 0x6eebcb3a, 0x04fc70c9, 0x29017f53, 0x09c0013c, 0xc9b8752a, + 0x41a3fff0, 0x88d8f938, 0xec7b9dd5, 0xec8e476e, 0x9e8d449d, 0x1c4b0787, 0xb148a4f8, 0x8dbf4b7e, 0xe860f97f, + 0xcd810804, 0xe2769401, 0x5e5254c7, 0x0af5c85e, 0x8e02b2c0, 0xef43a981, 0x3b48369b, 0xb3816603, 0x5986d3cd, + 0x09263fe3, 0xe099a470, 0xee97c674, 0x911cbefc, 0x10b3d54d, 0x4a4e4103, 0xf3a61646, 0xa4d72df5, 0x0b9c8a72, + 0x94903218, 0x7b1a983c, 0xa807d813, 0xd5ccd3bf, 0xb1fe907d, 0x2f3dc937, 0x4b4cd2e6, 0xe019692c, 0x85e0e816, + 0x9c96c28b, 0x55b5e093, 0xf0e48ee3, 0x9a12c25f, 0x3f99f997, 0x1373617e, 0x69d8db06, 0x64e69ccd, 0x6bfee7d7, + 0xd58eb269, 0x54f5eb81, 0xb881db80, 0x7fe196cf, 0xfe2a4c44, 0x4b2c1f04, 0x3b80cfff, 0x566840a8, 0x0eaf1977, + 0xe1e09984, 0x610f3d0b, 0x4f8c57bf, 0xc4deb0bd, 0xa99e2974, 0xdde05dcc, 0xe672cd52, 0x0217502f, 0xb677038c, + 0x7a702ee4, 0x6d105ec7, 0xf0d6c3f8, 0x8b821ee1, 0xca689615, 0xee07bbf6, 0x3a02481f, 0xff71cc68, 0x4de63c23, + 0xb6b47412, 0xa228bb50, 0x6115c6db, 0x2f10e9c2, 0x9cb0aa20, 0xf93c0e77, 0x55c343fb, 0xe7fd786b, 0xc4682bc6, + 0x5d63693b, 0x8681dcda, 0x56e2c494, 0xc635e008, 0x2bff7de0, 0x6e894c8e, 0x0fccf3a2, 0x53217a8e, 0x0df8d352, + 0xdf66fa2c, 0x8d6946cc, 0xce96cf58, 0x93bc4f94, 0x58d899f9, 0xccec2622, 0x029fbf47, 0x64a67ab4, 0x3f7cc1e4, + 0x71b24bd6, 0xb5d7a389, 0x1bdae8fa, 0x7c560bda, 0xb9040eb8, 0x14cf6fd7, 0x0bf5418e, 0x068d2494, 0xb127dc21, + 0xb9ad69a2, 0xac1211aa, 0xc50770da, 0x90d31245, 0x60f6ebe6, 0x7fa9d18c, 0xe1cf6f56, 0x4a4fb6f3, 0xcdbaf791, + 0x71080ffb, 0xf7bf5b8f, 0x8d839eff, 0xfaa633e7, 0x987b68f7, 0x6176bd3b, 0xbafbdaa2, 0xdaf26954, 0x54b7c72e, + 0xdbe96d5e, 0x2801e919, 0xf3cad7f5, 0xeb994e8f, 0x60bd9068, 0x5b8c2771, 0x198ec8b6, 0xee0af1ab, 0x1d560f6e, + 0x1fc96a3f, 0x8fb52c5d, 0x5203f999, 0xf0670191, 0x4e0294ee, 0xbaf517ae, 0xee1fd8d5, 0x0c2dba8a, 0x500a445b, + 0x2104456d, 0x32e0f4fb, 0x8a993ff6, 0x33776dfc, 0xc06df522, 0x8aa1e66a, 0x5cf3eec5, 0xe568ce47, 0xba0fe303, + 0x20113788, 0x00b8dc01, 0xcf45867e, 0xd4f1e3a3, 0x64ff4393, 0xb942eb04, 0x3d8de306, 0x65055e65, 0x5bffd425, + 0x87743bc2, 0x2fe45d8b, 0x0b792a66, 0x2b192f35, 0x3ea4f933, 0x0c147d9f, 0xe83d7e49, 0xd61fd76e, 0xf085a1d8, + 0x5a872531, 0xf74768d7, 0xa926a611, 0xbabd22c2, 0xacd64924, 0x51c14f91, 0x3b02dda5, 0x1cd7de5b, 0xa4f4c299, + 0x3e388da9, 0xa72db7ef, 0x764ce09d, 0x538e0a50, 0x9185d4ce, 0x592dc151, 0x659e2c82, 0xbd6e5822, 0x05f28dac, + 0xe681b05c, 0xafc98725, 0x4e47c152, 0xe56584d4, 0x8173712a, 0x5fc39712, 0x8fd7aafc, 0x75bbe42c, 0x00c4d84c, + 0xf4b2c3c2, 0xb6875d74, 0x9a5de6b7, 0xe8a79b23, 0x872225e6, 0xe29ab28a, 0x9bd67d15, 0x587ed6e2, 0x235e6740, + 0x86f7a25c, 0xa1575114, 0xac71b15c, 0x9d2d1ed9, 0x5afb5cdf, 0x383e34b3, 0xe8a8a8c9, 0xd53f7be5, 0xeec6808c, + 0x97742549, 0x388950e0, 0x5392c63e, 0x4ab58d87, 0xc63e09cf, 0xb2f39fb3, 0xa5dc3e6b, 0x43cc93da, 0x74c7d11e, + 0xce75aee9, 0x95886654, 0x1719d60f, 0xa2e16eea, 0x134273be, 0x04584455, 0x6cffbf88, 0x35eb86b1, 0x72e54c02, + 0x3408ef39, 0x315148bb, 0x8ea7f91b, 0xbf1e0971, 0xdfee2f60, 0x125c170d, 0xf92b98ab, 0x79d442ce, 0x57a6ec3a, + 0xd8ad6c84, 0xd7baaf24, 0xdf57aaa1, 0xd2c98a74, 0xe519fb58, 0x6a471781, 0x19037eb0, 0xd4766bbd, 0x197de665, + 0x6e2b9b9d, 0x98388786, 0x1d377331, 0x3d81f762, 0xa927411f, 0xce9adcab, 0x24aad574, 0x40d1253b, 0x7c7b4609, + 0xc736178a, 0xdb252f1f, 0x4a0ac985, 0xb16d7a72, 0x38ce2aff, 0x06a46043, 0x87479e5a, 0x10e0be3f, 0x8572e323, + 0x151b0201, 0x4304ab77, 0x5ffbacf0, 0x41d80d68, 0xa110c200, 0xc7693eab, 0x5abfd049, 0xb85d8a96, 0x6c0ffaf5, + 0xf5b333ee, 0x2adf05c3, 0x02826233, 0x33cabc65, 0x73e455cc, 0x427c2f8c, 0x8b99f9ef, 0xaab267a3, 0x6d150890, + 0x8e8ce683, 0x6e4271c9, 0x8ca4edb5, 0x5275b7f3, 0x556c038a, 0x2d185286, 0x173f5470, 0xaae3ae97, 0x1f812b5a, + 0x07934a1b, 0x32c24d6f, 0x6fc06777, 0x3edad111, 0x0e367746, 0xdef0e8d2, 0x6549f521, 0xaad2256d, 0x8d1f3677, + 0x7fc216bf, 0x621967ca, 0x683fad42, 0xaf662f17, 0x3c49c21b, 0x58fe2dfd, 0xc46bf23f, 0x32012fe7, 0xa7cd94a6, + 0xcf81799e, 0x8e12f458, 0x4874b423, 0x09c8e5aa, 0xc109a1f8, 0x36299867, 0x038c4411, 0x58181c79, 0xf7894990, + 0xe52c59ce, 0x82efdec0, 0x0f25e9ef, 0x1673c6a2, 0x1aee450f, 0x04f5e424, 0x0586453c, 0x0ac91962, 0x58b63278, + 0x8818efc0, 0x524d2100, 0xd214e60b, 0x4e776611, 0x48928d68, 0x7fc2751b, 0x7a59ef43, 0xc1bb46fc, 0x28f4a580, + 0x24be3c9d, 0xebde6315, 0x076b1536, 0x34cbecba, 0x761a3eb1, 0x9866afae, 0xc9b05700, 0x7da9dbd8, 0x365c2c05, + 0xfe380c05, 0xc8933818, 0x95d3553a, 0x9cb62aa7, 0x9401bc02, 0x177b4d72, 0x01de3284, 0x9823f23f, 0x3c8fd8b9, + 0x4b595f2e, 0x2b50b862, 0xa976a794, 0x1302e145, 0x008d7485, 0x388b99b2, 0xfaa51b26, 0x93c67b73, 0x8edef0c2, + 0xcf22294d, 0xd630adb4, 0x345d8f77, 0x25d91edb, 0xc97025fb, 0x0224a6d8, 0x3be810d7, 0xb21e80e1, 0x44bdd4ec, + 0x621c4c6e, 0x7f9d09c9, 0x65aa0485, 0x02ad877d, 0x4b7c428f, 0xcf925121, 0xa917feb1, 0x7824eb40, 0xd9316f39, + 0xef5bf325, 0xcaf34d39, 0xd664a502, 0xc1b15a1e, 0x798cb6fd, 0xa6e4cb78, 0xa311a050, 0x17b303d7, 0xf161075f, + 0x01f2b1ba, 0x9ca842d3, 0xadebaeee, 0xafb4d149, 0x56841ab7, 0x5ea09bed, 0xbd21c31d, 0xb56177cc, 0xebd7e273, + 0x016ab0e9, 0xc10cec0e, 0xc53da752, 0xa2b76713, 0x52971ac5, 0xcd6d555f, 0xc027826e, 0xa6ed0a97, 0xc3a9601e, + 0x6e748860, 0x8c7a4893, 0x327a3988, 0xc500b0b8, 0xb70fa65d, 0xaa798421, 0x065451fb, 0xc95f354a, 0x3b34dd86, + 0x660afc82, 0x6a38eafa, 0x7b1b5816, 0x8985ea38, 0xf9ed0382, 0x405fae7a, 0x57d0bb6d, 0xeb7a162a, 0xfb04ede4, + 0xcbaa84b4, 0x75cb193c, 0x3631c9b0, 0xd70314a3, 0xae17352d, 0x1a4cb7e4, 0xb2a64e47, 0xd9eca422, 0x47e332a0, + 0x756f6606, 0x7f2d7c46, 0xed1270de, 0x7dbbbf39, 0x28548193, 0x0007da7f, 0xf054f945, 0x7d33b17e, 0x09f6319f, + 0x55f597c9, 0x68300e6e, 0x65232982, 0x86412b24, 0x565ba023, 0xa40fd03b, 0x6f1312c0, 0x6a58df06, 0xbe018619, + 0x28b95b08, 0x375b14bb, 0x29fbfe69, 0xf156137f, 0x33626409, 0xf670b053, 0xaa628c43, 0x54d82103, 0xd0c9a62c, + 0xb40800a5, 0x91267b72, 0x54bf9d86, 0x542cd55d, 0xa95510a0, 0xf66056fd, 0xf7c932d6, 0x361c9942, 0xa31ec9ac, + 0x8fde20ac, 0xbc3bf028, 0xee99720c, 0x41267162, 0x0e215ea7, 0x1b0f5535, 0xfefce9ee, 0x063e7e9d, 0x9fdfd275, + 0xf49adb42, 0xa6bd7bb6, 0x2500e742, 0xe4071c42, 0xdcad699e, 0x0dca0ba8, 0xaff8c2ad, 0xa35466ca, 0x353ad62a, + 0xdda0b4a0, 0xb6fb061f, 0x9b3768cc, 0x0b72975b, 0x6af9c51e, 0x9b37b8f8, 0xd3b3050d, 0x38dc52fa, 0xb59d59e9, + 0x09b0d996, 0xac5af6a5, 0xcbf2a7b0, 0x1ba59634, 0x7622adb1, 0x7936908f, 0x9d9f08ce, 0x1d1bfe42, 0xa07a1bbd, + 0x974df748, 0x2aa40552, 0xeb2c4c5e, 0x92da59ad, 0x32e62db4, 0x7167558a, 0x7da444b1, 0x6df0c13d, 0x9c3dc210, + 0x011a6539, 0xbd3d7dbf, 0x2106712c, 0x4637333c, 0x98146a55, 0xf3e88de5, 0x2620e871, 0xe2623683, 0xd659540f, + 0xacca3273, 0xcb842ba6, 0x17bb4b08, 0xa82e4ebb, 0x5cb29518, 0x7efe856c, 0x1ff5b8e3, 0x6d8977ef, 0xa2769c06, + 0xad129cb6, 0x55ef45eb, 0x84c8f930, 0xf375dcea, 0xcfbc7d93, 0xb528142c, 0x48b4d650, 0x7f4cc641, 0x1f8911fe, + 0xeef129c4, 0x4b6a829e, 0xf1dd66fb, 0x6a5a1d22, 0x1c5044e1, 0x28927c58, 0x4c27d76d, 0x6a2afa43, 0xe188c19f, + 0x5760ce8e, 0xee316d2e, 0xf7d74698, 0x3089392b, 0x280dc1bd, 0xebc91c92, 0x6670d285, 0xdb6d241b, 0x9746e3fa, + 0xcb7eaf17, 0x732581a0, 0xa72bd3d8, 0x2123b2f1, 0x8864df89, 0x46817569, 0xfa3f3015, 0xc4706a0c, 0x164cd3de, + 0x38fddfd9, 0x5af4116a, 0x7c960ac7, 0xa375d491, 0xa495d42c, 0xf78942ea, 0x7c855e14, 0xeabc0da5, 0x6c6cfd6b, + 0x4ac38e64, 0x25e1c8f2, 0xd7614c06, 0xa14db354, 0xa5a91c6e, 0xe15444eb, 0x86fbe67c, 0xe7415575, 0xf1f893e4, + 0x221ecfd8, 0x73f8fb76, 0x77bf4b57, 0xd0c09b9e, 0xff082bd7, 0xc6985f6c, 0xde89130f, 0x59593a54, 0x059ef989, + 0xaf0c7dee, 0xab066bd5, 0x51bb1117, 0xd7e2bda1, 0xc9f92e43, 0xf526283e, 0x9a3891f2, 0x9dfcbe6f, 0x2b8fdff8, + 0x84cb7407, 0x8ec21916, 0x20ced12b, 0x61991ca8, 0xbaefb21d, 0x9f8aeb72, 0x1a5ccb08, 0xee7f9f13, 0xa10f5d57, + 0x7ab9b574, 0xd7f67998, 0x75c60bcb, 0xaac94aa0, 0xd44e07f4, 0x50d0d6bf, 0x3a2abb4b, 0x7a39dfcf, 0xb82aa092, + 0xebf5adad, 0x2857ab3a, 0xce01516f, 0x7349e133, 0x631713b6, 0xdf56a454, 0x5a12fef6, 0x74a5d97a, 0xc80ece35, + 0xec3c63d5, 0xc0280755, 0x758673fe, 0xe6992789, 0x9e6e39f1, 0x906619b7, 0x3ff30dcb, 0x997dbf7c, 0x9b3fc571, + 0xec0b8040, 0xd470883f, 0x05a183b7, 0x6a0eb9e8, 0x2ea81f57, 0xf42896fe, 0x1ab0dfd7, 0x1daace37, 0x2b929d24, + 0x5f60660c, 0x5e46053b, 0xf5cdeb2a, 0x6b82dfc3, 0x56ec3129, 0x059b5cef, 0xd61f6d4d, 0x98eaa5e3, 0xdaf39f9d, + 0xb77996f7, 0x114b1d8b, 0xbf6c54ea, 0x8a8f347d, 0x9ad34f9a, 0x4ea98eb7, 0x90a14fd2, 0x8ca1a477, 0x9a887692, + 0x3dbdd2d3, 0x5f2b2b52, 0x82a948d3, 0x7060e693, 0x65a70f09, 0x529d2bc3, 0x886cda7e, 0x80ead8a9, 0xd33baa37, + 0x68d51cfe, 0x6063ff35, 0x79cdcba0, 0x8ac31d6a, 0xcd9cf847, 0x69973bc8, 0x120aa2e1, 0x05de0006, 0x8afb06e9, + 0xb807ec36, 0x5f0a4a5c, 0xf26ca52f, 0x7417f749, 0xe1dbb2ab, 0x77b78c2c, 0x7c22cc0d, 0x971acfad, 0xb79235de, + 0xc47fc772, 0x6c0e929d, 0xcb26352e, 0xc8963c1e, 0xe3922567, 0xaec94100, 0x2f5d642e, 0x4d2c6699, 0xff0fe44c, + 0x24aec578, 0x31650d1e, 0x8e115e87, 0x027c6304, 0x78ef12d5, 0x50b73750, 0xa1e2eb71, 0x3da3d036, 0xe4863c61, + 0x58373abc, 0xae8ebab5, 0x21184c13, 0xc6abc3f8, 0x1edb47dc, 0x283176f7, 0x4dd1adcf, 0x945e17c3, 0x16aa56c4, + 0xfc1a1ac0, 0x364827cc, 0x618bfe96, 0x39b45038, 0xa90e5824, 0x6ad96187, 0x21ae9569, 0x2d669ccf, 0x0f80766d, + 0x6f5f073e, 0x5edbbe3e, 0xa40f6954, 0x290bb446, 0x3d50f2da, 0x59d9b3ba, 0xf9b27412, 0x838e3d3f, 0x784954ba, + 0xa25765d3, 0xbdd52c0b, 0x31a894d9, 0xae62f74c, 0x937a3663, 0x69956113, 0x54a6e604, 0x62a64d35, 0x8ee01eb9, + 0x37eb8946, 0xa4d0f7c6, 0x01181eb4, 0x3076c239, 0xf7f61ce5, 0xf9904b82, 0xced2f109, 0x6fdb6e20, 0x66aa8a5b, + 0x3114f821, 0xe96de9c7, 0xed0d6b05, 0x383eaab2, 0xc6651983, 0x59ead8b9, 0x2c263820, 0x45a54757, 0x6bd2b929, + 0x13e76c66, 0x338ddfc2, 0x16575e86, 0x79f32b66, 0x4ebe30bf, 0x2d8d9858, 0xc8c50b91, 0x12cbba59, 0x4157f396, + 0x49c2e160, 0xcbf43e05, 0x1ec4b19a, 0x17fa3d2c, 0x855700e6, 0x8d2038b4, 0x820b878a, 0xdf9f4b84, 0x72e988f5, + 0x33ae49c4, 0xfb76bd88, 0x9f31f524, 0xc6c7af10, 0x92a51da6, 0x0e926b4c, 0x2ff7d1d9, 0xc409bf4b, 0xe107032b, + 0x615c45a0, 0x1be08e16, 0xf7b0342d, 0xc7b32522, 0x1497bafa, 0xa9108721, 0x4ff1e0f7, 0xb555c2fe, 0xe550c267, + 0x10e37cb9, 0xd1d1c67b, 0xff33b14b, 0x28482a5a, 0x588d3a08, 0x55ef0f0c, 0xa48a00b5, 0xfa6b5749, 0xd84a19b8, + 0x787dc879, 0xd9ee7af9, 0x8c26c8c8, 0x37a3f3e6, 0xbc311cbf, 0x569a4bfa, 0x95280bf4, 0xf3448728, 0xa64eb16b, + 0x6bb02747, 0x4526d7f8, 0x796c238a, 0x673a719c, 0x29c4904a, 0x19dfde36, 0x5beeadd6, 0x1ae3ac48, 0x19b325f2, + 0xeb7c7d83, 0x8874a235, 0xda4dccb6, 0x03edd6f4, 0x8825d82f, 0x5cc8afe2, 0x6e6f2ec5, 0x5a81f344, 0x0c775592, + 0xeec83dde, 0xaf7f0b13, 0xabe6cf6d, 0xea8a97bc, 0xb962943f, 0x04435c05, 0xc333a69b, 0xf365ab1b, 0x64eea42c, + 0x0b5f3948, 0x4970327e, 0x05a5bfc2, 0x1f2c748f, 0xbe284276, 0xaa496d36, 0x81250c64, 0x2d46ad31, 0xab3db043, + 0x22f3b1fc, 0x32b4922c, 0x5438ce5d, 0xad75f6de, 0x3847bffe, 0x8f06f673, 0x507bdf73, 0xa24c84ef, 0x1afbf86a, + 0x60639f71, 0x9096e428, 0x6005b737, 0x45957c30, 0x1f11bde8, 0xc8be913c, 0x0270441d, 0x8dc754ea, 0x3b09cf15, + 0x7cb47e05, 0x4af693c2, 0x22ec3c91, 0x94eb5d19, 0x85f84d36, 0xc7ef2802, 0x63b3b4da, 0xb3a35820, 0xf1c08a68, + 0x4990e217, 0xc74ca24e, 0x43df2618, 0xb7198d96, 0xe718aa3d, 0xd5b0bf0b, 0x72906627, 0xb8b5fed5, 0xd123ae8a, + 0x6480e27b, 0x3c9a5e7c, 0x581e6856, 0xf4ffb39f, 0xf029def6, 0xc4a4202e, 0xc56fba84, 0x7a047e1e, 0x64d6b427, + 0xe8691d6a, 0x91797666, 0x769f0180, 0xb323a11a, 0x06eabbb1, 0x9b1a4611, 0xe2fda75d, 0x98063114, 0xca4b6b40, + 0x3067d99e, 0x643d7b3c, 0x85915615, 0x89f298c8, 0x54c534a4, 0xafbbfaeb, 0xa3dd86e8, 0xe816a5e1, 0x3057ea4d, + 0xd3892135, 0xe06731de, 0x7e216312, 0x6514bdf3, 0xb2586071, 0xe2154917, 0x1e7b1fe2, 0x1fd8bb64, 0x9a025e5f, + 0xc0dc0208, 0x0906b5b6, 0xfa4760b7, 0x493baf23, 0x5f6b48b6, 0x095d02a5, 0xbae604db, 0x8a7a2b6d, 0x59992b90, + 0xf14b3e25, 0xf133ad5e, 0x67d00248, 0x0ec0b465, 0xcf47739e, 0xd6aa03df, 0x756de93e, 0x156e60c7, 0x3594045b, + 0xe8911144, 0x84345d17, 0xcdeb90cb, 0x185bd7ab, 0x7dcfb04c, 0xa6998c88, 0x4d967c19, 0x90e8de50, 0x740dcb86, + 0xd91ea706, 0xf9bae20a, 0x7a7177d2, 0x1aeff9fe, 0x462c18ce, 0x7e347a39, 0xfeebf9b0, 0x1f90240c, 0x8dc1aedd, + 0xdb5ebef8, 0x71a41dc1, 0x98140b1f, 0x18930056, 0x2830d877, 0xbdd05a92, 0xc1df18fb, 0x55d01a6d, 0x366cd6a7, + 0x0ed0f159, 0x0b4982a0, 0xa486c962, 0x6071869a, 0xa2f5dbe9, 0x154f1256, 0x3c399d4f, 0x18dbb932, 0x7ff799ed, + 0x1c384d6f, 0x62d62501, 0x1e1276d7, 0xc5f5996a, 0xc6d24b1a, 0x2ee06497, 0x91403cf3, 0xb43dad3c, 0x8fd1eb67, + 0x7024c499, 0x103fd7dd, 0xc4e8d5c6, 0xa8e9d62c, 0x4d0a7985, 0x054ea663, 0x1ce0f88c, 0xcfcd3f63, 0x6216c475, + 0xde6425cb, 0x3dd542e3, 0x537b9cf2, 0x7c9f8baf, 0x542a386f, 0x5a26209d, 0x08bf57cf, 0xc1fc1145, 0x1a8f3d6e, + 0xf7014c13, 0x5bc4762f, 0x06641ca0, 0xc3d377aa, 0xfc2d6073, 0x2fe52f0a, 0x36b608c1, 0xf4a2ba43, 0xfde3a7fc, + 0x8d6db93a, 0xfce8dfdd, 0xac431533, 0xca2f1a4b, 0xcf19bc68, 0x69b56c31, 0x167f7766, 0xa970f1e0, 0x844d0e11, + 0x27deba29, 0xf01966b4, 0xfeb10469, 0xe1d4c8dd, 0x30432ddf, 0xaefc6caa, 0xbb80a82d, 0x4732e27a, 0x9d41f4e7, + 0x3f68158b, 0x26b70cc0, 0x4674600e, 0x211b8298, 0xe6f9cd2e, 0x79af2e5d, 0xd18df77a, 0x6712b9b6, 0xe9df4b5d, + 0xef3094b6, 0x6b54054a, 0x07c848a3, 0x32f2105a, 0x1b852e2a, 0x81642b93, 0xb97ff3b6, 0x89604d89, 0x66163d93, + 0xfdc9fcbc, 0x105dbe94, 0x4beaf313, 0x45341697, 0x9c901098, 0xe5e0beeb, 0x1202fab9, 0xf7c597f6, 0x4a15de10, + 0xccdd5c75, 0xa719b88c, 0x1ea51eee, 0x4ff441af, 0x4110b56e, 0x091cf07b, 0xfa9de5f3, 0x5c75bb58, 0x24d53839, + 0xe5be7014, 0x0c3bb6ef, 0x1e36881b, 0x2dd65bee, 0xb4d0f27f, 0x78b8a406, 0x2c7db60b, 0xf784d157, 0x6e7adc09, + 0x85ca5422, 0xde6fae2b, 0xaf07fc1f, 0x179b29a7, 0x3dd06bdf, 0x695a54df, 0x49b936bc, 0xb0b0d16a, 0xaf933c3a, + 0xb60bbd89, 0x04ad0aee, 0xb8849ecc, 0x2fdf0cbb, 0xb9b29107, 0x86b50346, 0xf2662c05, 0x17ec55dd, 0x6fb06cdc, + 0x850db92c, 0xe7eb27a5, 0x2bf9c578, 0x8ef1bdd0, 0x1c60f2b7, 0x7ae31f77, 0x20e10dab, 0xbbeab1a5, 0xea5c0631, + 0x23e95867, 0xc790ecbb, 0x20834736, 0x5bda1d86, 0x186ee809, 0x1442e07d, 0x84785ca6, 0xffb30919, 0xab6b9147, + 0x80059d41, 0x35f3e8d7, 0xae8b7bc9, 0x3186a6ae, 0xffa29cff, 0xcf2d8c8f, 0x34a31f3b, 0xae337a42, 0xc94664c4, + 0x7f3e824c, 0xf800e39c, 0x6dc1ca28, 0xf905f1f7, 0x451ee635, 0xbb4deeec, 0x0de15313, 0x13c82140, 0x53e7c7a7, + 0x3ad4fcf5, 0xb86b36b5, 0xcf6386fd, 0x95d8c099, 0x29701daf, 0x6a59d401, 0x4d23a782, 0x6ed76b41, 0x061ad9cc, + 0x58d7b7f9, 0x6b08adb3, 0xc6e8f125, 0xa1208fd0, 0xe1092ab8, 0xdb898205, 0x453a8c29, 0xe7993050, 0xee5cef87, + 0xde1d3c32, 0x2b3fd901, 0xd7f9db79, 0x687f171c, 0x7ae787db, 0x2b6ab3b5, 0xb345e9d3, 0x9250cd50, 0x2109707e, + 0xda4cdc53, 0xe81f1ddd, 0xfd39c2b4, 0xef3359c5, 0x147a4fd1, 0x16c6abe7, 0x4fc355aa, 0xaa8ff398, 0x41da204b, + 0x461c51a9, 0xa3f402dd, 0x3c3fcab6, 0x26e4eda8, 0x913fa9d9, 0xae1f505b, 0x6f6500cc, 0x209e35b7, 0x0726ad4e, + 0x5e7615bc, 0xd5555b8b, 0x312a91c9, 0x44c95697, 0xe21acd23, 0xb28c7bdb, 0xabf4411c, 0x6459461e, 0x4bfaa9cc, + 0xfc6b5c1f, 0xc88ecf64, 0x10df60f6, 0x8a892155, 0xa95e5afe, 0x8361790e, 0x321bed0c, 0x0dd1aa4b, 0x62dfd4ed, + 0xc99ba861, 0x138fd8f7, 0x55b82739, 0x92fe21ff, 0x8e219180, 0x223c381d, 0x591846be, 0x966631ad, 0x262ba357, + 0xc72ce75c, 0xeef18be3, 0xd732ab4d, 0x06402cd0, 0x75f2f89c, 0x305ecbd2, 0x53f8aeb5, 0x29c74bd5, 0x5ea53a70, + 0x8de506d5, 0xbaf6b7cb, 0x2725a806, 0xf85ddfff, 0xf8dc5ee1, 0x9437b584, 0xf894930f, 0xf7c3c059, 0xef438ffd, + 0xe9a85003, 0xb078fa9f, 0xae32c966, 0x370f8c90, 0x1155b197, 0x28170a3f, 0xe090d702, 0xa5b7defb, 0xef990194, + 0x0fee8e68, 0x611b0bdd, 0x3e2148db, 0x47aaf9f4, 0x5ec75788, 0xbd6225fe, 0x007fa93e, 0xb0bdb154, 0x0800f099, + 0x8c827d55, 0xa42292a6, 0x821c1f6b, 0x8ffe23de, 0xe4769d6f, 0x8285f12a, 0x8191255c, 0xe7a5c1bd, 0x23552eef, + 0xd2b3eac5, 0xfc2472f7, 0xeb488cd8, 0x657ab276, 0x0ebb7343, 0xbd427eb8, 0xd1281a61, 0xba88d206, 0xe825c1e8, + 0x55441f23, 0xd79d80d3, 0x1c6a794f, 0xc134dd90, 0xb1d33c1e, 0x23fa70fd, 0xd5539433, 0xc3192402, 0xf4162aad, + 0x711c238f, 0x1f2bc64a, 0xe3be280a, 0x53e67bb0, 0xdfc59293, 0x0aa6a81e, 0xc6a8ae63, 0xa718cf39, 0xa955f16a, + 0x70960f64, 0xd1f391c5, 0x2c9da564, 0xd8088a1d, 0x885ab5c9, 0xe280c01b, 0xe5d7c60a, 0x27b55ddc, 0x52119ba5, + 0x15b70a5a, 0x01564a0f, 0xad14ae2e, 0xee27bceb, 0x55da552d, 0x4fe030b6, 0x118c75f8, 0x000237ce, 0x3fed31de, + 0xecb71cdc, 0x4b04ad5b, 0x5fd87442, 0x8208395b, 0x8e8cce02, 0x4044c90c, 0x2e0bb817, 0x00fc5d01, 0xc97910ff, + 0xf4a487ce, 0x05b1f379, 0x883ad627, 0x4083caa1, 0xd92c2590, 0x7dbd514e, 0x3f5462fa, 0x2c116a43, 0x1af36fd0, + 0xa9b7dbd5, 0x24f1d1e7, 0xf573021c, 0x0cd4d688, 0x8424ae7f, 0xbbf4fd3f, 0xd4d89dec, 0x87fc1bd6, 0xde1111ef, + 0xf4be1537, 0xd8cfab49, 0xc6ddf273, 0x9afaad9c, 0x087d6c28, 0xbd919fd3, 0xe550aaa5, 0xdfcede1e, 0x852619e8, + 0xd92e09f3, 0x550be45e, 0x5cefec47, 0x3d7e2122, 0x258f5f8f, 0xe547e878, 0xbf0e1587, 0xd11fa343, 0x52f88456, + 0xeb67fe8c, 0xa1fd81c9, 0x86dbf53d, 0x85061cc4, 0x4afbf791, 0xc4ab33ee, 0xf24bcc2d, 0x5e600630, 0xdc3478a6, + 0x7aceb07a, 0x0aa0b627, 0x9710eb2f, 0xd76c9d82, 0xabb4f324, 0xf61aa395, 0xef0bbd50, 0x5ab5d94f, 0xd1654b44, + 0x88a3f419, 0x347c632f, 0xc2887349, 0xf0793b4a, 0x6adead9b, 0x63c894eb, 0x90c276ae, 0xab5de551, 0x8f698b13, + 0xfa8a38cb, 0xcb393e14, 0x7c524ada, 0xe8205c53, 0xf5b1f0f1, 0xb7b39325, 0x0c5181a5, 0xca49532e, 0x627bacb9, + 0x1999503f, 0xbe101446, 0x8e8bb4e0, 0x853325a0, 0x142bbfb6, 0x2d149bc8, 0xb60cfaaa, 0xc34a2412, 0x2805ac99, + 0x3a9a3eb4, 0xf1deb75f, 0x10dd621c, 0xf47b5380, 0xa4355783, 0xabf325c8, 0x9521393a, 0x5fe47161, 0xb523df05, + 0x49f9dd75, 0xa48b9510, 0xc39ec74b, 0x1a011dd3, 0xebf0fab8, 0xcec442a9, 0x85620b40, 0xab3e169e, 0xacd54143, + 0x0a710eb4, 0x892b2712, 0x529aae7b, 0xd85da7b3, 0xcbc863e4, 0x300a8e5c, 0x965f32f7, 0xe499afbe, 0xd52c40cf, + 0xe30e8626, 0x7782a41e, 0x8f65dd88, 0x9dd05ad5, 0x3c301ae7, 0xac5d9ef0, 0x63185e14, 0x1b768da5, 0xea12c8c3, + 0xbdb24d8f, 0x60852f0d, 0xd1339f46, 0xb2c038e6, 0x45b572a6, 0x4e10f8cc, 0xaf0c5d7b, 0xefc242d4, 0x1032825a, + 0xa6f0c49a, 0xc761c488, 0x2d745c45, 0x13dcb738, 0x912383aa, 0x009ea0ba, 0x1222c236, 0x27279868, 0xf34844aa, + 0xc85b3f76, 0xff6172f4, 0xce56a06c, 0x5ea4acb8, 0x360cc7c1, 0x234bbb7e, 0x559f19f3, 0xc37e50a2, 0xcc9d1125, + 0xe794c8c3, 0x41da9266, 0x4f170068, 0x07779e60, 0x1168a1c4, 0xa0f22688, 0x1affc7bc, 0xe69c03b0, 0x54bc94a4, + 0xeb40292f, 0xa4ae6f9c, 0xc8ac3e65, 0x1fab7094, 0xe1d2b682, 0x40e69331, 0xc5c84df3, 0xeb30da5d, 0x55e372b8, + 0xe5284435, 0xf70f227f, 0x41b7cb0f, 0x527e5773, 0xa6f776f0, 0x60c802ec, 0x7bd01029, 0x5632d5ce, 0xae8a823d, + 0xe81ff719, 0x4b2de049, 0x32a5745a, 0xf35be58e, 0x0a500276, 0x98f2e604, 0x9c48b5ea, 0x3d704c2f, 0x0d2cb538, + 0x6a3a95dc, 0x05f35a72, 0x35fc685a, 0x600919bc, 0xd849cb39, 0x5eb3f4ee, 0xcb93d677, 0xa308f4f9, 0xb147d5ce, + 0xc8a5229f, 0xb94f1c07, 0xc0f65a4a, 0x4aa9897e, 0x3cedbf10, 0x722a34ac, 0x2cddc8e2, 0x1d49d6cf, 0x0b9ec2d9, + 0x1ab0c95d, 0xcf4ca7d4, 0x8ab76fc7, 0x8a7fa145, 0x65ff5598, 0xf0eec51a, 0x245a42df, 0x2b246abb, 0xb1e98aae, + 0x248ffa2e, 0xda2fada2, 0x2801c48c, 0x298e118c, 0xc0db90db, 0xfd861c61, 0xb649b259, 0xcdcbf9dd, 0xd68b9f4f, + 0x45fa2e3b, 0xe302a0b8, 0x0a0be730, 0x5c35f276, 0x095f8b31, 0x1b66ca33, 0x96f9326a, 0x0f55b108, 0x5c315e98, + 0x8c52c994, 0x8a0c2913, 0x89cd4f64, 0x58ab8a9f, 0x03668e3f, 0x8cf56966, 0xac901f87, 0xa2017d36, 0xa070fb71, + 0x6908cdba, 0x6cf9304d, 0xa97fa1fc, 0x343154c9, 0x2aab7b3f, 0x49335ed8, 0x474e87ce, 0x2b93714a, 0xaf4234e1, + 0x22c2d857, 0x184103fb, 0xd2b0a2a6, 0x856f8936, 0xeb493eb2, 0x2187135c, 0xf3190685, 0xab1355a5, 0x772bed5d, + 0x53ec1b25, 0x973f15dd, 0xb45064d9, 0x074bb64d, 0x09bce6c7, 0x41ebf0ed, 0x980b7d0d, 0xbfe51a50, 0xea72d1ef, + 0xf0b4a5da, 0xf8a5b268, 0x71c360bd, 0xd036c6b2, 0xbce1cd27, 0x76ebfdcb, 0x53c3d1ed, 0x28e7a3a3, 0xe38c41c9, + 0x30aea7e1, 0x27eff880, 0x2133bf86, 0x6c0fa46d, 0xd0ade0c9, 0x37fe2b9a, 0x2136dd29, 0x7539036f, 0x2c50c123, + 0xc7abe070, 0x790de58b, 0x41aebc47, 0x2593bc4d, 0x0c098f6a, 0x95f6d29e, 0x0ea24169, 0xb19495a8, 0x5c57792d, + 0x0b07b5b9, 0xd73def5c, 0xaf1eb1e4, 0x643d8a30, 0x034f2b62, 0xc3c53ec5, 0x763c39f0, 0x98f9125a, 0x0baa8cc6, + 0xcbe5b2cd, 0x4ea84ab6, 0x8f9b2822, 0x71b80da6, 0x4e9ab15d, 0x57e5a13e, 0xa914abe5, 0x78a4aebb, 0xdd5fab55, + 0xcebd375f, 0x2f891c0c, 0x4ba7d8e5, 0x569f4853, 0xe5bbccc9, 0x4fd03fac, 0x40a0258d, 0x39d7753f, 0x8fc79dfe, + 0x3cd3d186, 0xbb4a93b3, 0xe0f474ed, 0x680f1268, 0xd8a69c7a, 0x0f07ecfb, 0xc97a4f3a, 0x772655c2, 0xe7a07907, + 0x6f37f560, 0x66178302, 0xe4bb8df9, 0x160e21dd, 0x8296a714, 0xc9716bed, 0x292d9e08, 0xdfa3f2b2, 0x1072856f, + 0xd77bdfcc, 0x8011ec70, 0x1e8539a0, 0x216bdacf, 0x293740b4, 0x2556e26b, 0x337a9a50, 0x6edea985, 0x9ca079e5, + 0xc6cf8e8d, 0x7cf25744, 0xe5a74391, 0x98a7d938, 0x8a8d1bcd, 0x3e5e8a1a, 0x7a122bba, 0x7633acd9, 0x4ed8dabd, + 0x3bc2db6f, 0xd8a27cac, 0x480cca19, 0x132740df, 0x73772b9f, 0xb62876cf, 0x3675cbf5, 0xeb602a9b, 0x29a1a0df, + 0xc83f9bbe, 0x3f2d4ea0, 0x8f3dc116, 0x9b956f47, 0x7ab5f902, 0xf5f0602d, 0xfa716615, 0xdb2f7f8b, 0x1918dda5, + 0x41041ec9, 0x7c0defa6, 0x955a5ecf, 0x683c27a3, 0xf9430aac, 0xa657d34c, 0x43247570, 0x9dd84614, 0xa482e9d6, + 0x6f9fe14a, 0xcd1c7b6d, 0xfee251fb, 0x58d36a65, 0x3a7ae1d4, 0x455d8c35, 0xc5105dec, 0xe7d98088, 0xf274afea, + 0x2e51b5c8, 0xb896cd30, 0x2987a444, 0xacdf638c, 0x74b53062, 0x9d39aec4, 0x80ce3bce, 0xce24e2d1, 0x02c687d9, + 0x181712f3, 0x116c08ca, 0x17ff4bd6, 0xfee975ab, 0x2a6f349d, 0xcf968f94, 0xe098fc6c, 0x8bad1fbb, 0x2231d738, + 0xcf16fb27, 0x1728be28, 0x4a48bcd7, 0x88647f1b, 0x3f4fba67, 0xabb87917, 0x0f1dee0e, 0xc3c712fa, 0x122f371a, + 0xb6389d37, 0xe41455f7, 0xe6ae238e, 0x1333e4af, 0xcd865357, 0xcfa3c660, 0x60d65309, 0x942c0d7e, 0xbae42e64, + 0x28892381, 0x64e57f12, 0xecd5cce7, 0xa76106f5, 0x15ac55a3, 0x106e2605, 0xbec414b3, 0x41688c09, 0x7ff64315, + 0x13d76069, 0xededdaa0, 0xc4da3d7a, 0xa9be6c92, 0x5ac18775, 0x3def288a, 0xc201d03f, 0x87bd1187, 0x62a7aabd, + 0x58aceda8, 0x38a9bb03, 0xafd58043, 0x9232c9ca, 0xf8959f01, 0xedb5ce58, 0xafbcb4e0, 0x37940137, 0xb8c55f2a, + 0x08b65c76, 0x2f507735, 0x8d74a277, 0x9c5ec9b7, 0xdce24d11, 0x7fc0a424, 0x565f77aa, 0x6fe4bd07, 0x91862e71, + 0x8a29c8cd, 0xa6471111, 0xc66adf54, 0x4b509d3b, 0x4043c0e3, 0x1a687576, 0x60732aee, 0xe2d95778, 0x7777124d, + 0xaa74dce1, 0x6a9f65d3, 0x17ca1e40, 0x3a9147b0, 0xee44e498, 0xd84a4219, 0x470d2884, 0xddf927c0, 0x1bb020cd, + 0x03a1ed2a, 0xbf367104, 0x1aa67c89, 0xb3419f6e, 0x82963512, 0x2315dc3b, 0x0e87faf8, 0x5645c779, 0x245c0990, + 0x64a682c0, 0x60e27ee2, 0xfaeb1bb3, 0x004cbdf3, 0x208ee312, 0x78b4523d, 0x72e93cf8, 0xc038d82d, 0x10dc3763, + 0x327d13f3, 0xc7d43793, 0xaf2cee08, 0xdfcf5c6d, 0x5c3e4600, 0xb480a1f8, 0x8c8720b4, 0x381970ad, 0x1e3b7d64, + 0x3bdc7671, 0xb9ac2e65, 0x0a37dc38, 0xd3416a81, 0xa35af0bb, 0x41db5f96, 0x7cb0fc8a, 0xd8b85421, 0xcde16d07, + 0xc3bc629a, 0x6c9fcfbc, 0x0a5a96d2, 0xeef6a62c, 0x4f9b82ae, 0x2009420f, 0x852c518b, 0x2bb55e67, 0x75ea1f94, + 0x76f23958, 0xa60e27fe, 0xab0b968b, 0x7030743e, 0xe8c9735c, 0x45a84886, 0xaf01f094, 0x3323c00f, 0x6ece659b, + 0x0ec32299, 0xa5a4d21d, 0xbb1159b0, 0x22f27801, 0x60dcc7bd, 0x8aa09754, 0x364d0048, 0xe6ad5997, 0x43621a31, + 0x5c27b5b9, 0x35e6449f, 0x75f52e91, 0x7298c097, 0x3963ffad, 0x36c07d65, 0xc9a269d1, 0x52ad7fa4, 0xde703641, + 0x4150ce30, 0xc064ffc7, 0x1c097dec, 0x8d867cf6, 0xfcec7e74, 0x1fc77ee2, 0x8aee055c, 0x791adc45, 0xa4a487c9, + 0x798a9e12, 0x10769c1f, 0xc80ff1f5, 0x5627e6c1, 0xc7c92a87, 0x5732811a, 0x6ceaf366, 0xa4fd75a3, 0x46324350, + 0x41a704dc, 0xb988e7d4, 0x544fd00d, 0xdc667e92, 0xae5f0988, 0xf3e4d4b0, 0x3619c4b2, 0x7d0e035f, 0x6df1a344, + 0xffe5053d, 0xd43f6770, 0x5be50fdf, 0xf6f108ca, 0xcbcea40a, 0xd4ed185e, 0x8b85186b, 0xd743805e, 0x04986cb9, + 0xabfdef17, 0xfd352402, 0x549ba732, 0xa7cf40a0, 0xad04a473, 0x3b748253, 0xca76c553, 0x0bcdd8a3, 0xc3f54cd8, + 0x03da3799, 0x675bb3b1, 0x51ab3edb, 0x548a770c, 0x7fcc4866, 0xfe234b4b, 0xb5cbeeaa, 0x3f607b5b, 0x92c00982, + 0x1ade2512, 0x08400769, 0x917aa784, 0xd3030e90, 0xd29a876f, 0x993dd87b, 0x708d42b7, 0x0a6526a4, 0xe7624366, + 0x0fa4f1b6, 0xbc3ea88b, 0xffeed142, 0xc36b668d, 0xe81dab81, 0xbf7bd5df, 0x74cd7991, 0xca8b2b4b, 0xb6639453, + 0xd3f53bb0, 0x83dc4cc5, 0x4d856cb6, 0xa5395eb6, 0x7098f8c5, 0x21de9d35, 0x8e8d8f2a, 0x2f6c3c62, 0x4a6fd9b2, + 0xc21cd3f9, 0xe9ffbf09, 0xe9333ef1, 0x952c44aa, 0xf86e8ebb, 0x4e9b2a63, 0xc60500ee, 0x9b3abf67, 0xef59c650, + 0xc79dfb9a, 0xcb9fd1ed, 0xeed13229, 0x16ceba29, 0x6dbd7eab, 0x9e30b1bb, 0xbf388ddb, 0xfb2d21bf, 0x01ecda1f, + 0x0db77c4c, 0x78d3889a, 0x9016158a, 0xe92e66ba, 0x4cf1791c, 0xd9838318, 0xbd37de7a, 0xbb32e82b, 0xe34ddc1c, + 0x416e34b2, 0x4e447847, 0x73d409cf, 0x058e846b, 0x5ea81a48, 0x89a3d086, 0x362a628e, 0x5dc6e8f7, 0x867ab419, + 0xef5eed76, 0xcba561ed, 0x04fe7f7e, 0x82efbe4f, 0xbf8e3b2c, 0x0663de9b, 0x881eb49b, 0xaa5ef5ae, 0x93316894, + 0xe2fb39af, 0x6709722d, 0xec9311af, 0x17faf0e1, 0x792569b7, 0xc7e89dd5, 0x914eccf0, 0x2f0aedd0, 0x1f58db1b, + 0xfddeb1a1, 0x6511dd65, 0x788d51e7, 0xdb301da1, 0xeaa45b94, 0x08c7ba7f, 0x0ba6065a, 0x590db37c, 0x039b2f5e, + 0xe16ce91d, 0x6e20a3ce, 0x48c29eff, 0x44f6fc19, 0x3550410e, 0xdd87e307, 0xf3459229, 0x751a4d57, 0xdf1979fc, + 0xfb93c67c, 0x458d57df, 0xf1b41b63, 0xe99b740b, 0x36116364, 0x6b117a6f, 0xc7cc2bcc, 0x2699494e, 0xf5f7b76a, + 0x41e24d68, 0xb2136413, 0xecc03f3b, 0xcba70813, 0xc83db23d, 0x0bfe8fc2, 0x2929fa97, 0x0a2966d0, 0xc6fa0200, + 0x5244b400, 0x996c54fd, 0xf496c36c, 0x50d7ad28, 0x06a90984, 0x9b212d75, 0x6ab265d3, 0xf8a13d2d, 0xa7027307, + 0x358c3e9c, 0x10e943b1, 0x44fa447c, 0xb5eabef2, 0xee69881d, 0x7cc0104e, 0x098a2c8b, 0xd4f23a52, 0x298ec189, + 0x48ad58f8, 0x2a785611, 0x6a04c0b1, 0xe84ca848, 0xe7409f61, 0x65bbbf54, 0x890a05d5, 0xaf4ca581, 0xa642581f, + 0x40b32488, 0x7d1e9574, 0x4a6dd3ec, 0x333557e8, 0x1662f124, 0x7c41d843, 0x9c4a44d2, 0x0990c253, 0xd6fcc764, + 0x13776b37, 0x20ac9c70, 0x4173e2be, 0xdf428cd4, 0xc2f0c22a, 0xf72b42c0, 0x5eff8487, 0xb219055a, 0x973facd2, + 0x6ec5b91e, 0xe49dd01d, 0xecaf1cc6, 0x71ad5c43, 0xddc5587e, 0x500a4796, 0x656d61f7, 0x1fc2c1be, 0x91de7bf4, + 0x3d33f8a6, 0xa50b7c45, 0x4ac70f2c, 0x2e6768f9, 0x111d8a3d, 0x60ba9bb6, 0xdcbcc701, 0xfce84f92, 0xc1904624, + 0xe8e6ab88, 0x3f998292, 0x73265e3f, 0xd3ea52eb, 0x43d171e1, 0xada0db33, 0x7c18f8f5, 0xd7566ae4, 0x92131f88, + 0xe6ebb8ae, 0x08cc27a7, 0x82d2a8d6, 0xac09300e, 0xb0aa010b, 0xd4e5d45e, 0xa88974a0, 0x3def4b92, 0x6e4e5161, + 0xc7bf6b0b, 0x2b1380ef, 0xc15ac524, 0x738e4527, 0xc2fd6378, 0xb5391f64, 0xd03118c9, 0x2664f30f, 0x3b6e265f, + 0xf48b9f1e, 0xd899d201, 0xb6f208dd, 0x12e93551, 0x8d6b4692, 0x1b156d60, 0x0cf102e3, 0x9967e6d0, 0x9e9bdbbb, + 0x249b7970, 0x9f8caf91, 0x9495c359, 0x362c76e1, 0x963c808f, 0x75d7d73f, 0x23b2169c, 0xa103c225, 0x1fc4d7f2, + 0xa3565fce, 0x871870bb, 0x411c380d, 0x780e55f4, 0x5cb9388e, 0xf8d6b4e2, 0x7e0e47d3, 0x141cb279, 0xf9c5055c, + 0xbcfe13e9, 0xbab409af, 0x3a4d15cc, 0xac7255df, 0xd4eefb62, 0xde66b55a, 0x7bca0041, 0x562c87e0, 0xe7002bfb, + 0x357e40a0, 0xb7d8b962, 0xb83d4ded, 0x00194c27, 0x82d1b237, 0xc81557e2, 0xc2632e0a, 0x24f3fce8, 0x07fd5847, + 0x886b19a2, 0xc857131f, 0x4ad7916f, 0xff5dbc17, 0xe74e3ed5, 0xb26e8f97, 0xd2e7eebb, 0x8f42f846, 0x6ec96e84, + 0xfa9932a9, 0x06d05715, 0xa1604e73, 0x1b14a39d, 0x33ca25e9, 0xff31329f, 0x0cda85f3, 0xa7f846b9, 0x5c58afbb, + 0x581cc45c, 0xea7336f8, 0xd633d358, 0x73c57876, 0xfb4153fa, 0x36274fd0, 0xf4e90a2f, 0xd464d538, 0x6ece1d89, + 0xbe0e7dbd, 0x543dcff1, 0x2924faea, 0xe166a6af, 0x6c6e7504, 0xd0cbd2b6, 0x94eed46e, 0xf45582ef, 0x95c8d03a, + 0x4ab50a74, 0x0f3192cf, 0x3e34dcbf, 0x5ad3af5b, 0x2c4fe11b, 0x925d1f53, 0x9f0212d0, 0x45b697ee, 0xffc6f407, + 0x51f52d7d, 0x35178302, 0xdba51b6e, 0x344210d8, 0xd0987466, 0xd37bc8bc, 0x58e94cc1, 0x1432adcc, 0xfb3a6dec, + 0x62e9cfb3, 0x644e6dc9, 0xe4f4f969, 0x633d431b, 0xc873e508, 0xbb1ef11f, 0x78eab327, 0x4d568b48, 0xd9e887c3, + 0xee85ccae, 0xd7313e47, 0xf54e989a, 0x846fdd9d, 0x3111fc74, 0xf700fd5a, 0x3e6e6e62, 0xa69ff784, 0x461dc232, + 0x1f3eba68, 0x96b06336, 0x7f3851f3, 0x82fb9a22, 0xfa185769, 0xc9019ea6, 0xb6855b7a, 0xa0124413, 0x52472798, + 0xebebf150, 0x4164d681, 0x80245e84, 0xdf4a9bb2, 0xe1f83a5c, 0x717717a7, 0xfdff2a57, 0x353a483c, 0xa60bf7c6, + 0x38cc499a, 0x799b9103, 0x15ebebc1, 0x1cd6eaa3, 0x9d16b914, 0x642048d4, 0x5393e41c, 0xbf094edd, 0xf343db6a, + 0x6354a005, 0x08a8ce66, 0x982b900b, 0x0fb83a0c, 0x760c0d0f, 0xdc41f3b0, 0x57ad31a7, 0xcc01746a, 0xa78eb5c8, + 0x1ada474f, 0xdce3c510, 0xa5f702a7, 0x26f506fd, 0xa7e501c9, 0x3a3bac58, 0xbc767f8c, 0xd79df235, 0xebba1258, + 0xf1363234, 0x59c71b2b, 0xdca6cbab, 0x2776a343, 0xa2c2ef9e, 0x8909df70, 0x7dc5ed95, 0x0a6a4808, 0x794858cc, + 0x82b15100, 0x92c43396, 0x038147a0, 0x0d60a0a5, 0x2a5b4da4, 0x21c553da, 0x45e925df, 0x0fb7b594, 0x470e00c5, + 0x48814b20, 0x123a920f, 0x91729c4c, 0x5b089971, 0x61345954, 0x7d4c1a26, 0x2f45401b, 0x73c13bc6, 0xa16ac93e, + 0x2bbc03b5, 0xc03fb187, 0xcbba9aa8, 0x6e670bfc, 0xf441a81c, 0x187bdfef, 0xbcedc2fd, 0xd4a94959, 0xd74a2c64, + 0x99415517, 0x89cef233, 0xc5838e08, 0x84c7a707, 0x102f7590, 0x0e9f9f91, 0x69542a5e, 0x8a86cd12, 0x3ba7c8af, + 0xb05153f3, 0xeb7e8f50, 0xa2c57982, 0x8a0937c4, 0x2239e86b, 0x58878055, 0xfc8c49f1, 0x6820d725, 0x90f0b129, + 0x42a03bd4, 0x06425d57, 0xca5b855d, 0x967089b2, 0xfc488cb7, 0x3dfb4808, 0x10631890, 0xdc3bdf47, 0x07c3f5c3, + 0x0352a6df, 0xe3059e6f, 0xd43371d5, 0xd953225e, 0xc8f72760, 0x9d11cd98, 0x9422fa14, 0x070b9203, 0x2aedac7b, + 0xcbdf27c6, 0x24407d09, 0x4c3eae14, 0x093ca90f, 0xa5975d52, 0x096f52a8, 0x05bc51a9, 0x89c0dfdd, 0x92035b5f, + 0x21795e60, 0xb2b19067, 0x7fda7514, 0xab617853, 0x82d514b5, 0xdf6882f5, 0xca7017c0, 0x3a5b73d6, 0x67f49653, + 0x18f2b69d, 0x1b34c313, 0x5d95aee2, 0x5c3f7c69, 0x36840c6a, 0xe0ed9fed, 0x7d4533be, 0x59758485, 0x94caf36a, + 0xc53ac699, 0xc9812c63, 0xbd9b19b6, 0x250e7f1b, 0x159962fc, 0xb301dc06, 0x0ae35fc6, 0xf47a9ed9, 0x651f2ee8, + 0x2cbc082e, 0x02eb89a2, 0xc187a96f, 0x5ee48156, 0x52e2dc8d, 0x2de7cca4, 0xa3353b42, 0x3faba1bb, 0x45c39e3a, + 0xae64296a, 0x56231cd2, 0xb45469bb, 0xfea36df4, 0xb9d3e9f6, 0xc2bab5fd, 0x63f36c27, 0x8e5d33ea, 0xc466cbb7, + 0x64026bb8, 0x1993a4ab, 0x0e4f7234, 0x133af62a, 0xc50ed6f8, 0xf96161dc, 0x630ef4c6, 0x5610e5fb, 0xec534516, + 0xe18ca6e9, 0xdbe6bed1, 0xa689cfb9, 0x6adaf09f, 0xe916b473, 0xd61a57a8, 0x3f760fbf, 0xd3197eba, 0xaadd260e, + 0x077db9bd, 0x70f50f2d, 0x1ae39a20, 0xda74faef, 0x0fa81563, 0x3631156b, 0x4ceb4ce8, 0x3d8b1ff2, 0x4b8ededc, + 0x9bdb537c, 0xd8d3878d, 0xf39366a8, 0x1548d2e9, 0x4788e23d, 0xe82fc426, 0xb593a1ec, 0x810ff8d5, 0x97f6e7fd, + 0x76d0824b, 0x7e943ffa, 0x9b059955, 0xd35efb2a, 0xb6c7f5e7, 0x1da60bbf, 0x12bf99ae, 0x2f46483b, 0x2c6be422, + 0xdae6906b, 0xa1b671f2, 0x1bb67f02, 0xf72d55fb, 0x20dd5a23, 0xf37e3f6c, 0x6adfc426, 0x5d15b7aa, 0x282670d3, + 0xdd6063b1, 0xd3340f57, 0x197845a2, 0x929f21af, 0x03bb2363, 0x78a0a278, 0xaba42d72, 0xbaa7c147, 0xc850fd96, + 0xf0b4c61e, 0x5ea22585, 0xaab041e9, 0xccd94587, 0x0b3c08bf, 0xeccfbca9, 0x9c3ea745, 0xd462bf9a, 0x7f33425a, + 0x4e561d82, 0xede1998d, 0xfb68d123, 0x4a711e31, 0x17521b3d, 0x364388cd, 0x93ae0642, 0x161c983e, 0x2a247c3e, + 0xdb0b4d5a, 0x2d85f3ce, 0x1517d205, 0x060f54e6, 0xcd2476d1, 0xf4931a5a, 0x3d0b54e9, 0xf677384a, 0x42b8d276, + 0xbb05d647, 0x8b2b7b74, 0x589bf1ab, 0x27c6793e, 0xdb050df9, 0x179c343c, 0x7dadda75, 0xf3d43ec6, 0x8d3ffb79, + 0x206c4e77, 0xb27921b2, 0xfe6a835e, 0xc2b9ac09, 0x23125041, 0x19ac6f8d, 0xfb9694ce, 0x99f86762, 0x0630a7d0, + 0xa25470dd, 0xc0750476, 0x3150db40, 0xa29c4315, 0x6408a3ea, 0xb8375111, 0x8d667a1d, 0x1fff4a85, 0x8f0df051, + 0x227d2e43, 0xfc0644ab, 0x0197dbda, 0x02035e99, 0x374d408a, 0x385715da, 0x2479ea01, 0xa3a6a0e2, 0xe7756ea2, + 0x3f08251b, 0x2489a3fa, 0xef2eb0a1, 0x762a0306, 0x7673a32d, 0x18be9b18, 0xae784e98, 0xc0377cdc, 0x2df93fe0, + 0xc6ed4f87, 0x072516c5, 0x4e97dd1f, 0x1b1fd6b5, 0x5bef1685, 0x7d1a251e, 0x5cd963e1, 0xdc845c88, 0x80eb6d60, + 0x8bc21434, 0x43de5dc2, 0x8bb164de, 0xcaee4a8c, 0x71a51f14, 0x3cb16e6e, 0xac3c8f8f, 0xdf770de8, 0xee2e071e, + 0xde75c0a9, 0x2b4f4535, 0x2a521ba2, 0xdadb2e07, 0x31705818, 0xd38a0e1e, 0xb90ee61a, 0x451dc6b3, 0x476a0c3d, + 0xbe5eec2e, 0x3698e31d, 0xe58b79fd, 0x1edf3549, 0xf2a88aa2, 0x0d14c828, 0x728431bc, 0x4f9c0b62, 0xf7eaa5da, + 0x2b7c410c, 0xbe4f798b, 0x00b9bbc8, 0x6a456fba, 0xb083d850, 0xbbafe1a8, 0x0efaea46, 0xbe314f5e, 0xd4911e6d, + 0xbebceb98, 0x4cb7e58f, 0x37a5ee9a, 0x2bb8b0e5, 0xbd931e58, 0x61616d6e, 0x4f8a2907, 0x7f6f4473, 0xf8a51443, + 0x6fb55661, 0x36a52fb0, 0x297a5427, 0x5c7f7865, 0xc70c2461, 0x7c6b8f9c, 0x800d18c6, 0xe65a6f80, 0xde62b49a, + 0x331d21f2, 0xd30cfdd0, 0x7f745b66, 0x3c5b0cdf, 0x5d991d31, 0xe884f3d5, 0x5c60a958, 0x54396ef6, 0x5cc8340d, + 0xc49996ef, 0x2dafbebf, 0xe9cc2608, 0x9b070700, 0x0e28c66a, 0x8833e7de, 0x117d60f2, 0x132ff50b, 0xc0513bbb, + 0x23b07849, 0x6d695504, 0xc608c539, 0x3666138e, 0x5614e20e, 0x31f8e8fd, 0x423de1cd, 0x93fbc79c, 0xc0b1a6a8, + 0xa8c20b30, 0xafca0b25, 0x0a070ba5, 0xdd5368a1, 0x60956daf, 0x11fb2c84, 0xc97bff59, 0x48d0d826, 0x51c12bc7, + 0xcd5be138, 0xa9ff8254, 0x971d8c43, 0xc57e2ac8, 0xdee373b9, 0x8cbc22d8, 0x964a8f39, 0x8ded0406, 0x575afec3, + 0x04fadebe, 0x0845fb83, 0x5d2834d4, 0x25f55424, 0xe861242e, 0xf7a9ee4a, 0x46baee50, 0x8f6ad63d, 0xee129a1e, + 0x8c65e018, 0x383ca901, 0x222bd9e2, 0x3861600e, 0xfb555430, 0x060004f0, 0x1b276307, 0xaf17d9a1, 0xd36ea467, + 0x82df55b1, 0xd5e60611, 0x0a0afb85, 0x3d6cc7a4, 0x53d65de9, 0x4505f3fa, 0xded43692, 0x0120f67e, 0x7a6f2335, + 0x246b3c14, 0x794b852a, 0x9577ebb9, 0x38103617, 0x4f26f173, 0x836e830c, 0x68bbe218, 0x204382f4, 0x715e6b13, + 0x081f0fc3, 0xec11ee50, 0x31e4053d, 0x0e8e1d5b, 0x11471422, 0x38e881ce, 0x1615dec6, 0xd51a7a54, 0xbdae8b21, + 0x14c69b70, 0x143a2c9f, 0x0493d82e, 0x7935a6d6, 0xf207de04, 0x90d31bd1, 0x83ef758a, 0xc41fb1fe, 0x383477ec, + 0x1ba45c15, 0x6b5e7794, 0xb00fe318, 0x6f0976f0, 0xb4860dd4, 0x6765b74b, 0x367195fd, 0xe9fbb2dc, 0x088b138c, + 0x11c67758, 0xe9f9616c, 0x8e695a65, 0xf629e797, 0xa3e2a48e, 0xf7e27ced, 0x1e42e16b, 0xc7b4d225, 0x1a140e84, + 0x9c6cdd4d, 0xe342943b, 0x412d7d41, 0x3e906b4c, 0xd5b9d8e8, 0x9ce68469, 0x70641bea, 0x047b4247, 0x33ea7649, + 0x0fae3f81, 0xf06ff2ab, 0x152d8db9, 0xa594b060, 0x58bc11c6, 0x484dfae8, 0x78b1c5e1, 0xb929b5b2, 0x0b20e7d8, + 0xd6da9d2b, 0x504dfc18, 0x50075d38, 0xc49ecc5f, 0x02d29a61, 0x9e6cf881, 0xa6dbf2cc, 0x2d2284a9, 0x453d911e, + 0x305f28d9, 0xf9645fea, 0xa076093e, 0x4adb42f5, 0xb9cd80c4, 0x0e334cd0, 0xc5927fac, 0x3e0190b7, 0xee7f3610, + 0x9b1e4479, 0x01ef8a0a, 0x91a6f600, 0x0a409897, 0x03883c82, 0x41d7cdae, 0x1acfc18b, 0x4162579d, 0xd806c54e, + 0x96927754, 0x47e0f1a3, 0x03d71bee, 0xda5659ff, 0xcd84a0cb, 0x8bdeead8, 0xc3384a49, 0x7232985c, 0x132cf493, + 0xd7336bea, 0x4c381129, 0x13f9d03c, 0x8859ab94, 0x2914eb19, 0x6e2101b7, 0xf8fa5234, 0x0109948c, 0x33cbff14, + 0xe13f1b9b, 0x4973b4fb, 0xf9e65e82, 0x21734988, 0x58736a63, 0x66b8f572, 0xf7e2f1e6, 0xbed7bcf9, 0x53f854ea, + 0x8c3de0e4, 0xd087d893, 0x8362f52d, 0x515d1aea, 0x2f5b789e, 0x469559a5, 0x5ea4f9a2, 0x48e68949, 0xde26caf7, + 0x95d9f30f, 0xf8a4cc56, 0x9686c743, 0x2265875a, 0xbe3e529e, 0x31238f57, 0xc47775fe, 0xa12a9bfa, 0x75dfb370, + 0xc9fff498, 0xa824792a, 0xcbf827d5, 0x8c27ec36, 0xdb6a632b, 0x7ef8e45e, 0x299611a6, 0x63e1e1ee, 0xb53a4fbd, + 0xac4d1fe8, 0x38a8aec1, 0x67d06fd4, 0xe9cae89c, 0x114a9d81, 0x435db7cf, 0xb8266234, 0x8db7db70, 0x25c5590d, + 0x1ccd8b58, 0x586e267f, 0xec8b3ad2, 0x0b8d9f4a, 0x95d300bc, 0xe2c140d0, 0xb2580c6d, 0x0de8c664, 0x3a19a374, + 0x56255c12, 0x72635c1e, 0x4ab5a507, 0x49f14e22, 0x9f6fadc3, 0xaa23d299, 0x809c6d31, 0x1d390fe9, 0x31431a93, + 0x9312a323, 0x3a70ee30, 0x5e01c59a, 0x75570b79, 0x62cdaf18, 0x43868f0c, 0x887a4c4a, 0x110688df, 0x23bfdd77, + 0x0c9b451c, 0xfbedfcf5, 0xa3cf38d9, 0xc921f057, 0x94e53897, 0x147748eb, 0xccb9448a, 0x969405b8, 0xfae837b5, + 0x228139e4, 0x8bd48f8f, 0x4835be26, 0xa888ffd8, 0x5e4aa456, 0xae2fe4a9, 0x45b4102e, 0xce2c37e9, 0xedf7c0fe, + 0xaa28a0d5, 0xee106238, 0x6c5b6a80, 0x7b43725b, 0x6b97f1dd, 0x4fb89c11, 0x9751197f, 0xa5c6c86c, 0xc3ad52da, + 0x43767ba6, 0x0195e37a, 0x198904e2, 0x49bd6b51, 0x5d98db66, 0x483a1d87, 0x64f2055f, 0xeca47db3, 0x1ef51e90, + 0x3cb7ae5f, 0xe929c878, 0x78e54bb2, 0x74373cb1, 0xdffc02da, 0x864fe79b, 0x97a4e591, 0xe084fe8b, 0xea4b9c26, + 0xcd2e6be8, 0x7f3e734c, 0xc1c37269, 0xe5852fba, 0x88c32e05, 0xb8f4aecb, 0x025d0537, 0xa6c0160e, 0x9eb5c0f7, + 0xaa149c2e, 0xaaa3a2b0, 0x1b6e3d10, 0xa7652bfc, 0x3e387531, 0xb14b9d48, 0x61073f1d, 0x94358884, 0x402e0035, + 0x69d9fbd3, 0x02553f63, 0x15ba70bd, 0x4150e84d, 0x42ae282f, 0xe9c02de6, 0xbc76fb00, 0x85a07b5b, 0x80e0425b, + 0x5b7e2c82, 0x26d513a2, 0x55bb8771, 0xdd0f3780, 0x11c0848f, 0xe218ecbd, 0x351832cf, 0x1c7128fe, 0x06b07fc9, + 0xdd4200ba, 0x41cfc63c, 0x5366c5db, 0x69ae6852, 0x31da42af, 0x6008781e, 0x1bcb002b, 0x252bf851, 0xbc66eff9, + 0xfd91a3b6, 0x8f5c975e, 0x27736147, 0xbd8b9f9b, 0x50a17ffc, 0xf2ba9aad, 0xb37c891c, 0x9243327f, 0xe8707b03, + 0x41f332ed, 0x6b801f77, 0xcf10296f, 0xd3d5c9a3, 0x34dbdbb2, 0x1f43995e, 0x8c4293e1, 0x78e104b7, 0x455e6879, + 0x393ef867, 0xe318e434, 0xa1a43b72, 0x10008ff0, 0xa7a32dc1, 0x0e741638, 0xc082bd83, 0x6d719f28, 0x4506f38b, + 0xa168757d, 0xe714e389, 0x98393ec7, 0xcddd5ed7, 0x2af43f22, 0x67c92306, 0x5ecb50b6, 0x5fc4a2a1, 0x313055b8, + 0xb922a75b, 0x1457be46, 0xf3f3a0e8, 0x702a9fc6, 0xbddea36d, 0xa04fd653, 0x02d642e0, 0x1ec65aac, 0x6d9a02dc, + 0x0f4f1abf, 0xd4848b4e, 0x629bf8e5, 0x3b4c6735, 0x2262e508, 0x2fafc670, 0x5335159f, 0x07f94daf, 0x18f0f2b8, + 0xe8e1166c, 0x6b387c14, 0xce91e8e2, 0x1529cbec, 0xad206182, 0x7118eede, 0x9d8ec396, 0xa38748bc, 0xc2d1b307, + 0xb57d0661, 0x532a01b4, 0xd74157d8, 0x48cb499a, 0x7113d8f5, 0x534f7934, 0x7d5eed98, 0x918f7506, 0x5037aa91, + 0x04b82887, 0xb4cfe444, 0x8b445c05, 0xcefee305, 0xc1c47ef9, 0x49e32b7e, 0x72a27f12, 0x3d2ae755, 0x9c48c1ba, + 0xd7f4562c, 0x767c9470, 0x6276bbf9, 0x3bd2191a, 0x663b2a2d, 0xb9112e73, 0x9c2e867d, 0xb10f724b, 0xbfb7a479, + 0xe45cab8d, 0xaa87dbd5, 0x80b6f815, 0x5fd3d5cb, 0x6212436a, 0xf9dc1bb8, 0x5d5a6ecb, 0x9ce99272, 0x22cd20fc, + 0x8eb8cdcd, 0xcd06c379, 0xc816a873, 0xd8268173, 0xd182e8bf, 0xb6fc8da4, 0x64fe6b92, 0x360c5bc2, 0x53ae3976, + 0x755c687f, 0xa049642d, 0x13cd74b8, 0x9afbe461, 0x6d4fa9a5, 0x211ddfe4, 0x26d3edec, 0x85808142, 0xc2ae2069, + 0x22f4a3a6, 0xfc67e9b7, 0x1e0eddd1, 0x1b561528, 0x3ef5a486, 0x710dce3b, 0x3a67a57d, 0x60a7b68a, 0x991d2151, + 0x80d02f44, 0xdc426a40, 0xc434a75a, 0x620bb009, 0x456a243c, 0xea6a4fc4, 0x162ec1cf, 0x0a2d4a59, 0x0e6a5753, + 0x887cebe5, 0x2db47ef0, 0x6f05e1df, 0x72ff76b1, 0xfb856216, 0xa9f42d75, 0x63834267, 0x03a47d4f, 0x88ec6767, + 0xba1af85b, 0xbfcf064a, 0x0dad1195, 0xb0a30828, 0x17f2a959, 0x209eb76f, 0xb701a204, 0xd5b90a64, 0x52ca8b80, + 0xd9307517, 0x7b330d5a, 0x46ed5048, 0xc16e5b28, 0xf1547d0f, 0x290dc255, 0x3b25ea0f, 0x6f6b3235, 0xee550991, + 0xb7819876, 0xa8829c4a, 0x819270c4, 0xdb65000f, 0xbc9dc7ef, 0x98681e71, 0xe16f17d4, 0xa8831144, 0xb984e949, + 0xdd82afa4, 0xc1981673, 0xb07ce292, 0x796d815a, 0x236ed4b4, 0x65d84f79, 0x34a890e2, 0x64cb321e, 0xa5dd84d0, + 0xd27836fc, 0xd2edbbb1, 0xdd8e942e, 0x50b0d814, 0x82f01005, 0x462cfe4e, 0x3cd7dcdf, 0x3b1ae1d8, 0x16d66155, + 0x39c2e082, 0x69f9e3f9, 0xa78bf6ce, 0xccad4e90, 0x150014c6, 0x217a40f4, 0xae66969e, 0xcb745761, 0x3e346f7b, + 0x10249757, 0xb42198e4, 0xa99ed521, 0x0bdba774, 0x1f2e39b4, 0xd131a8da, 0x42b332ec, 0xde572912, 0x4f84d9d2, + 0xd8308b26, 0xb33f0803, 0x2826ecca, 0xbff318b6, 0xf5914ede, 0x28e3013e, 0xbe6be347, 0x229f6657, 0xe70aadc3, + 0x972b4d83, 0x2c5ef704, 0xdda9d52e, 0xdd4bdf7a, 0x7568a5d5, 0x6585c977, 0x0ef32a06, 0x776b91bd, 0xe037aa0e, + 0x01031531, 0xbceaddc6, 0xb2b8eb20, 0x7281fa3d, 0x72b05f28, 0xedb11820, 0x115d73e1, 0x14b9e31a, 0x4f6f38fa, + 0x979eb97d, 0x2dac21bc, 0xca4f6357, 0xcdf60102, 0xa2723aae, 0xff8932d6, 0xa2c64b68, 0x0a8353aa, 0x080bf917, + 0xb8998cb2, 0x904dcedc, 0x3e5000f0, 0x94f61eff, 0x55a4574a, 0x60f731d9, 0x08e50977, 0xd7a9ccfe, 0x341ee8f4, + 0x7376d160, 0x90840294, 0x5da53e1d, 0x78651620, 0x833e7a15, 0x578ac7b6, 0xc1c50bd0, 0x43d5d344, 0x2c40c669, + 0xe762915e, 0xa00563c9, 0x91948e3d, 0x85685f76, 0x9a79adf9, 0x176b8dcb, 0x79fa10d3, 0xb46f2b56, 0x9fa1e213, + 0x8b304d8a, 0xc514f7a4, 0xe36b2ecd, 0xeb78f2f6, 0x82a55918, 0xa80e0af9, 0x5aba0959, 0x3c986e82, 0x65350c39, + 0xb4305070, 0x363893d2, 0x13e0a786, 0xc2855fa8, 0x294e4aa4, 0x7a2b68d6, 0xbbaa17d7, 0x10e46a6f, 0xc11ef981, + 0x0b1df508, 0xe31dd64c, 0x64907765, 0x8f61b3fa, 0x1acd7a41, 0xf90a4c69, 0xb49aeda5, 0x87d50fbd, 0xe7799330, + 0x91c2b67a, 0x9a1005c0, 0x729f1ef8, 0xd6855261, 0xe5a331be, 0x72b0cf6a, 0x8999323c, 0xdd6e3654, 0x0538d9e8, + 0xf5835422, 0xec6a2fba, 0x20bd6c46, 0xfe2b07fb, 0x70b96aa7, 0x03178838, 0xebbf4216, 0x4ea3a481, 0x43ee4ac4, + 0x2f165f8f, 0x5d69f4f8, 0x76058f1e, 0x320a10fc, 0xb39c9e14, 0xdd7f12c5, 0x74866c6a, 0xa073d219, 0x7386cf4e, + 0xe31a0b48, 0x34253b95, 0xc761b4bd, 0x698386a8, 0x2afa817e, 0x789e867f, 0x3db94cfd, 0x976f03d3, 0x49305303, + 0x6ca6a0c4, 0xf97cef8b, 0x25d90d4a, 0x485ee24a, 0xa8395e25, 0x8efc6b7c, 0xaeef1282, 0x3f7bc07c, 0x34dfec82, + 0x78581d17, 0xcd682b38, 0x5165169d, 0x7c1b3b34, 0x8cd1178b, 0xbfe682a7, 0x16ac6a25, 0x06f9c5ca, 0xbb5861e2, + 0x8bd0a49c, 0xa444fa2f, 0x21ae744b, 0x487c904f, 0xf2180d5b, 0x04f0c351, 0xc5889628, 0x664a294b, 0x516cc6e7, + 0x9354a69c, 0xbd25815a, 0x1e5f126f, 0xbed906e5, 0x4b363590, 0x467ed2ce, 0x6b9936ee, 0x2a0ee7d0, 0x83e25713, + 0x8ea95c65, 0x83607524, 0x4cc421a8, 0xc1966976, 0x2bfa27be, 0x999dd9aa, 0x301f40d9, 0xd2acf78e, 0x695942a2, + 0x9f6c6e3f, 0x225c6487, 0x40f966e8, 0x5f9c9d5b, 0xacd213b2, 0x8d706dad, 0x4ce676cb, 0x340d9ba3, 0x9211570c, + 0x8c1de362, 0xeb6f63e3, 0x6876ee1f, 0xa7f2d84a, 0xe309be39, 0x73ee3b5a, 0x9e3342ec, 0xf8d5826b, 0x4d895207, + 0x66e81769, 0x5f002888, 0x2cb86d3e, 0x9c3b1401, 0x6e33b366, 0xac2d6088, 0x9e397874, 0xcdb4c47b, 0x3efabb35, + 0xe8c3c6e3, 0xb1b77c08, 0xebdcc3e7, 0x5c8767ed, 0xac8d65ca, 0xab366113, 0xb0f3bdd6, 0xaa43703f, 0x0701c871, + 0xa40787f3, 0x813acb3d, 0x57588074, 0xc34f5871, 0xdf1a9291, 0xf5f78ad9, 0x136df529, 0x27578390, 0x5d8f6e35, + 0xb33bfafc, 0x64f4f694, 0xa8593c49, 0xa2047cfa, 0x41e203c2, 0x7ad66e21, 0x3090484c, 0xbcb256e6, 0x5b7eaf3c, + 0x349982dd, 0x48bff301, 0x1197db82, 0xf61d075a, 0xcaca34a4, 0x635d280a, 0x3fbf8ff1, 0xc1cf855c, 0x049a4741, + 0x6bd22ae5, 0x26c30aeb, 0xeb8e94fd, 0x8319dfd5, 0xe62db165, 0x8ce98854, 0xca64df82, 0x2bfde0f8, 0x6daf3644, + 0xc0272726, 0x2a2ac1e2, 0xfebb23ba, 0xc9fd98b1, 0x6b1c83ce, 0x45dfb8f5, 0x7ee1c674, 0x5bad5360, 0xd651c07a, + 0x168fe083, 0x5d1a686b, 0xdcafb882, 0x12a09440, 0xff9a2f25, 0x855b643f, 0x4ed6a2a8, 0x86b09c48, 0xf2457c15, + 0x3f056a43, 0x6cf0421d, 0xe3bf2b68, 0x205cb6e6, 0x02563c03, 0xce4eff80, 0x5188d9f2, 0x163d1a51, 0xb66069a6, + 0x82d9d066, 0xe86beb92, 0x7783e5df, 0xf7915148, 0x260c6df2, 0x086df988, 0x9e855d6a, 0xb6feff77, 0x126c0813, + 0x5854732f, 0x35214dfa, 0xd41bebd5, 0x9d0297c5, 0xb33ca6cb, 0xff03450d, 0x57237895, 0xab66f46d, 0xe1399dc7, + 0x96d3446d, 0x97fe6b90, 0x27e4393e, 0xbce5385f, 0x0db5a7bb, 0x3d5b3068, 0x2abcfd44, 0x5756630b, 0x85a06561, + 0xb28d66ec, 0x49acc32c, 0xb6eb197a, 0x12d2a545, 0xfa45a68d, 0xe4bcec5f, 0xfef4bc30, 0x8c47785e, 0x60eae614, + 0x9e43086a, 0x1c9549f7, 0x310244f8, 0x9dfb3114, 0xbbb8cfee, 0x8bcc04cc, 0x0873db76, 0x87cc091a, 0x73933f3a, + 0xb20ae5b1, 0x70adda8c, 0xc8d35045, 0x45b3ea2e, 0x9cd656d1, 0x465868b5, 0x664a5b58, 0x63834437, 0x1eb75b57, + 0x3e7885a9, 0x9681cca8, 0xf1ac61e5, 0x852502e8, 0x24dd08f5, 0xedd04c2e, 0x33abf8f0, 0x7c185aed, 0x78fde8fb, + 0x69a5eea2, 0x852eb023, 0x14e26a97, 0x86813a17, 0x2066db6e, 0x1f580f56, 0x8cebd2ee, 0xf4b6458a, 0x38c1d2be, + 0xdd58af92, 0xff64113d, 0x4270e400, 0x10b332c0, 0xf1b860e7, 0x5107af54, 0xd4dacd02, 0x2cc4c9c2, 0xa94f6633, + 0x52a4582c, 0x9e00dc5d, 0xc503a7e6, 0xeda40f8d, 0x361a2771, 0xdb40ad1c, 0x5ba5d1d2, 0x830c9c3f, 0xfe6c8e00, + 0x03180180, 0xb205b5fa, 0x1f58deb7, 0x1ebfda34, 0x0f511fb4, 0xb94aa5ba, 0x158fe693, 0x0538f46d, 0x6595aa7f, + 0xd9fc9f94, 0x2d50c6b6, 0x22d6d4c8, 0xc4993b8e, 0xce267f3e, 0xe49da915, 0x48aa416f, 0xb699af46, 0x41c14d48, + 0x8517e36c, 0x6b9ee45f, 0xc341ab6a, 0x9c75aae0, 0x6185c8b6, 0x899e28d5, 0xe1e32fdc, 0xf879e7cb, 0xc1e1f9e9, + 0x1dff97e1, 0x52627754, 0xbe93cebd, 0x99d5a97a, 0x7efd7416, 0x76f0ce2d, 0x38b5e713, 0xb9763712, 0x1841711e, + 0x3655ee82, 0x50784540, 0x44640fd8, 0x77014790, 0x2b977f69, 0x1ee46223, 0x21b81c34, 0x66b80c97, 0x8d4c79fd, + 0xe8413fe3, 0x307b41a9, 0xbdb68497, 0x0052ef4f, 0x4ee15383, 0x1a1c7843, 0xb97a08bb, 0xce0fdc48, 0x51e4a30c, + 0xdd1bd85f, 0xd04f8ea5, 0xac68628f, 0x1f45410e, 0x7de0ea39, 0xf49b7af7, 0x3a58c1f3, 0xfeb1114e, 0xbf36fc12, + 0xea79cbeb, 0xd8ce24fc, 0x96280504, 0xa327f81b, 0xa07d7d84, 0xe8e2374f, 0x48f69ea1, 0x24e339c5, 0x10e98449, + 0x553c0604, 0x600f56a3, 0xb7b6c2b1, 0xf90769e0, 0x17da125c, 0x0a26de95, 0x382c72e8, 0x1c3d9ac5, 0x929fd1c2, + 0xa36ba469, 0x5678bb2d, 0xec8e1003, 0x834ecb0a, 0x2698ae7c, 0xda56d33f, 0xeb608b62, 0x633ce505, 0xae90e48c, + 0xe4b52bb3, 0x39af45d9, 0xd4548a67, 0x16636ce6, 0x46a4efde, 0xcc9aa266, 0x7914204f, 0x2ff54e92, 0xab896693, + 0x8850cb7d, 0xc5254447, 0x3301f470, 0x92316f83, 0x0fd62f9c, 0x71c6201e, 0xe3c766db, 0x1ab04ae5, 0x5a971fe5, + 0x110486a3, 0xc922af77, 0x94921c18, 0x0f29e5b0, 0xba0ca2fc, 0xe141bb95, 0x20fa42d9, 0x00329281, 0x5e187afe, + 0x01d9ef27, 0xc154730b, 0x898b2d55, 0xdb9aa0d4, 0x8489eee4, 0x4568198d, 0x6e8f8981, 0x516f6d14, 0x44cb6c94, + 0x16f9e75e, 0x0141b1ed, 0xdbf8d25f, 0x90483557, 0x1ffa424d, 0x1acb40f1, 0x1aa605e2, 0x54a3fc81, 0x7ae3ee50, + 0xee81f579, 0x51e87982, 0x3650d944, 0x4a238239, 0xeafa36da, 0xfb35eca6, 0x30415e3d, 0x0c14fe05, 0xcf9bed3a, + 0x2324c8f3, 0x19ff4c41, 0x4aeda85d, 0x5e55d085, 0x6f6b351a, 0x686e4ca8, 0x59f328c6, 0x5a4c8cd2, 0x60f219dc, + 0xfd24e82d, 0xbedb9ef9, 0x719c154f, 0x16930d74, 0xa470eaaf, 0xd8afda1a, 0x7e758d3e, 0x6f07210f, 0x0787fd5e, + 0x633984c8, 0x2c250988, 0xf46f0c84, 0xe2f7d88d, 0xccb2044b, 0xa78b8c3a, 0x985cd523, 0x89b27fff, 0x82edbf66, + 0x0a008cce, 0x6d85d876, 0x5d6cdebc, 0xfd532403, 0xb8f63b48, 0x33d427a3, 0x7faf32f0, 0x505e11ab, 0x622eb896, + 0xb083080a, 0x17502d5f, 0x549da193, 0xfdc39f4f, 0x4646abb0, 0x9de5bfda, 0x8114e7e0, 0x2a649f36, 0x280e7f23, + 0x1c320a06, 0xfee25a91, 0x6b515849, 0xc8cfb5d9, 0x61a1e4ba, 0x326c7c34, 0x567ccf46, 0x3a3a3afb, 0x62e2496d, + 0xade91fcf, 0xbfd04af6, 0x7c97915d, 0xdb15d3bd, 0x6ef2e433, 0x1db3ccef, 0x1095bcaa, 0x7d339e39, 0x74ef4a9a, + 0x4a071135, 0xfa9fdaeb, 0xb0c3b8d6, 0xbbfc4443, 0x55292e0b, 0x27815d65, 0x5d8909aa, 0x92f9fde0, 0x94bd83d9, + 0x5e813fb3, 0x50360c19, 0xe1c51bf9, 0x022094bc, 0x80de88e9, 0x3461b931, 0x79e93ea4, 0x6fbc472d, 0xac23b01c, + 0x74b8322c, 0xe508fbde, 0x30496fb3, 0x3f3aadda, 0x2a89ecb1, 0x710289b0, 0xab2cfa2a, 0x1cbdeaaa, 0xc00da29e, + 0x3f0505b2, 0xa5780fa2, 0xaa4faab7, 0x36e831ea, 0x54ab3d95, 0xeb7fbae1, 0x68e60515, 0xfd85972e, 0xf2fd7c44, + 0x421af922, 0xacd1ae61, 0xbfd06b3e, 0x751bc195, 0x833c2f69, 0x27eaf425, 0xdc171d08, 0x73e63fcd, 0x84e5590c, + 0x8a81b05f, 0xb0f145bf, 0x5493244c, 0xdc6eeac0, 0xb9eadf09, 0x0787fde6, 0x00a4b1f3, 0xdf0c9b47, 0x62381e84, + 0x5e6efe1e, 0xe3d8018e, 0xe0c1bba2, 0xd870ed6b, 0x3f3c1cf4, 0xdd426ad5, 0xa8dba640, 0x6a246bd6, 0x6009c705, + 0x13595a8b, 0xfd647182, 0x89af65f1, 0xea82dbad, 0xfdde527f, 0x950559a3, 0x28bdb88a, 0xbf9b9f74, 0x0f6089bc, + 0x29b93b7e, 0x87aff772, 0x3b4f8e2b, 0x06983e07, 0x492678e3, 0x0f9ab636, 0x866a26d0, 0xe5a852d5, 0x5cfe0799, + 0xb45c2b29, 0xe188ddc8, 0xcc1c3707, 0x4d853e58, 0x41d04b95, 0x1794c642, 0xdcec844c, 0x67d6b3de, 0x94c348f0, + 0xc7bd7b15, 0x138d1790, 0xf375f80f, 0x38db179d, 0xdae1a67c, 0x501dc4a2, 0x06c95d65, 0xbcf9e5df, 0x70f9f847, + 0x951b1502, 0x1ec3a22b, 0x21df9a8e, 0x0f1eef4a, 0xfd9fbd8e, 0x073b8c09, 0x2023cc76, 0xdfd043a5, 0xa275dbb6, + 0xd60b28e7, 0x9b63c44f, 0xeee910ec, 0xb1f2b1d9, 0xe6144770, 0xb3e11180, 0x21cbbe2f, 0x3193d55c, 0xd31fb380, + 0x9e11b66a, 0xde4585d0, 0x90f64080, 0x8ab707dc, 0xb34e650f, 0x41941775, 0x99f294b8, 0x56c9b2ce, 0x60a0ba9f, + 0x5dadd544, 0x616dfebe, 0x8d8dfcbb, 0x00f08c40, 0x28d4cbd9, 0x3327974d, 0x478f767e, 0xfd032b29, 0xc73a8481, + 0xeb87dab0, 0xbe6cee43, 0xcf7f5043, 0xe4aebba5, 0x2af628cd, 0x1156c17c, 0x550769c3, 0x6f395872, 0x8da396ca, + 0x99ed1c2f, 0x2c4add06, 0x6e638fdc, 0x186bd82b, 0x734f1f46, 0x09e21fbc, 0xded3bd9e, 0x29d48740, 0x4c114f60, + 0xdf3af551, 0xa574bab8, 0x4b8850be, 0xc1a627f6, 0x51a8d952, 0x05fe651a, 0x5d733340, 0x2573d98c, 0xb2585917, + 0x41fcfccd, 0x60728af1, 0x4321fcf7, 0xb83cb3f0, 0x52b529e1, 0x0f95bd43, 0x9701d635, 0x28334505, 0xb939a2d6, + 0xea9bb165, 0xa8a975d5, 0x9c4b6d10, 0x0798e67f, 0x4e7c88af, 0x17a5f8bf, 0xbb5cc6d6, 0x584b50e2, 0x22e27771, + 0x5ff36d91, 0xa2f3ec78, 0xb6dd2e1d, 0xc9cacc4f, 0x3ef599c2, 0x8f772009, 0x178fe030, 0xb02e43d7, 0x90cf482a, + 0xd2a1bf1e, 0x4336d79d, 0xa95087e3, 0x09695c79, 0xc4ef8a72, 0x3e4c83c4, 0x3c4b8e4d, 0x103dbf18, 0x1844479b, + 0x3a0c16cb, 0x17f5bbee, 0x12bdca3c, 0x456c60c1, 0x6a52880a, 0x4db40225, 0x896e0c06, 0x3dced77f, 0x92d0be44, + 0x1e0ab1f1, 0x00e426a2, 0x46100370, 0x0f814b96, 0x0103deff, 0x8bb5a0ce, 0x62f6ea00, 0x240c0b90, 0x98d15278, + 0x855d8486, 0x244c3557, 0x7e303520, 0x09ff6b6d, 0x77763ae1, 0xe313feb9, 0x74d9b9d4, 0x1ed020be, 0x9e065b5b, + 0x7165612f, 0xc340e17a, 0x81592aab, 0x618f596c, 0x12830c7c, 0xfd7ee4e4, 0x9482ff2a, 0x849edf97, 0xb296cc0d, + 0x6b0dfe42, 0x40d300cb, 0x545b99b5, 0x89a37c67, 0x54c080d5, 0xac66f2ed, 0xcc46057f, 0x946155f8, 0x53b98525, + 0x3bce0c08, 0x56cb8b92, 0x1271327f, 0xcb1fe56f, 0x445ad7ef, 0x46bba6ae, 0x224b5e71, 0xade47b62, 0xb82f45a5, + 0xf891a76e, 0x759d9e4f, 0xd3e834d2, 0xc09bc3b8, 0xe853b05c, 0xa4b05c95, 0x7703dd70, 0x4b2a0fe2, 0x2189cff0, + 0xb97a5ab4, 0xd7e93397, 0xd76f9e91, 0xb45b4b75, 0x284fc8fc, 0xc0c34ea9, 0x874157da, 0x7adc9e52, 0x28b66e51, + 0xbc3628fe, 0x56c737b8, 0x47196c83, 0xa1ba8007, 0x4089769d, 0x196e78d1, 0x8e68384e, 0xc93047de, 0x4b078c23, + 0x311e639d, 0x508dfc84, 0xe2a8a661, 0x6327ee0b, 0xa3ee31f6, 0xee4b44e9, 0x560b0bec, 0xb148c118, 0xd720a970, + 0x9d14318c, 0x459da185, 0x700f14b0, 0xf4773f02, 0x27be3fd9, 0x36f7e4a3, 0xc3221c23, 0x855595ba, 0xa0f699e3, + 0x82484047, 0x0d420e54, 0x02a0b8d0, 0x2ee321bd, 0x2a7833be, 0xb88fc5ea, 0x4b801193, 0x4dc476aa, 0xe419d356, + 0x6980612d, 0x87761cdf, 0xb8a54599, 0xd27c310b, 0xdd3e8257, 0x362e0ecb, 0xe1c18b27, 0x94564e21, 0xce9a8323, + 0xd773b39f, 0x81154ea0, 0xb5a4bbcc, 0x4c5c7538, 0x8866e5f4, 0x8193dcd9, 0xb738f020, 0x2d5765bd, 0xd428c23c, + 0x7436c79e, 0xa35f917b, 0xa8f6ea36, 0x019fe521, 0x8e5d7d45, 0x8ae2b3fa, 0xbb3065c5, 0x57d44328, 0xca610111, + 0xef9aa513, 0x9156c9e4, 0x5f7f9932, 0xd3bad6c7, 0xfc6e03b0, 0xfdb81521, 0x108df628, 0xf11bac9a, 0x50372e13, + 0xe0a7d439, 0x723ae5ee, 0x79a2cf6d, 0x3b4f2c98, 0x1ebfce31, 0xe890c995, 0x0c9a1cf2, 0xe321ef1e, 0x5a13476d, + 0x06bac18b, 0x99b8b937, 0xad85fb6b, 0xac3bf8ee, 0x919305b7, 0x6d5ac568, 0x04ac6563, 0xbe175f59, 0x12b73c28, + 0x95519f5b, 0xe35c5461, 0x860e06ad, 0xaaba275a, 0x2d81ba09, 0x4806639a, 0x94634e17, 0xbe439e49, 0xffc03e4c, + 0x29112239, 0x36474e2c, 0x8c892f98, 0x84584919, 0x6a3fe569, 0xf4a94a64, 0xd52f4494, 0x7376a768, 0xfe466a0b, + 0x3f43c596, 0x6499eb61, 0x382194f8, 0x935e786e, 0xf35f3c89, 0xf84aaea9, 0x2b9062f4, 0x770912c6, 0x9bf002c7, + 0x34ad24f9, 0x126bbb8a, 0xf7a9427c, 0xf8f05e14, 0x7644be73, 0x7f0fa09e, 0x6996fb50, 0xd06bd1c8, 0x54aee370, + 0x0c137ae7, 0xfdf4993f, 0x1861213f, 0x167ad064, 0xd4d77da4, 0x81332d65, 0x6df99142, 0xc14d0f85, 0x6ba972a8, + 0x7b33250e, 0xe745626a, 0x65edf75b, 0x747e9187, 0x2ca32d0e, 0x16792223, 0xbe3ea73e, 0x8faf21b6, 0xcb2d56a0, + 0x04b08b77, 0xe746c8ae, 0x95fde776, 0xa022e4a7, 0xcbcd21fb, 0x668ce377, 0x640bbb78, 0x9fa8de9b, 0xc38759e7, + 0x15702e69, 0x4848119f, 0x3bdfc55a, 0xf6b653c8, 0x44b7fdbd, 0xefff5101, 0x29d2a144, 0xe6e6e1f2, 0x3b16660d, + 0xe044a036, 0xa2d49a7e, 0x02e053c8, 0x18daa6d3, 0xdb6ccebd, 0xbb83e6f1, 0x99480a07, 0x35164442, 0xe137b81d, + 0x0c6f6e5c, 0x6fd07def, 0x2cdac27a, 0x83796bf1, 0xdffe8ce5, 0xa1dd233d, 0xd35ff065, 0x0dc62861, 0x254c42e3, + 0xaabcc142, 0xbf49b2da, 0xcc7f7f28, 0x74f5fc1d, 0x086b66d6, 0x2bd9719a, 0xf714aa1e, 0x4336a82c, 0x20a81c25, + 0x73253af0, 0xf7165c8a, 0x85d4e38f, 0x3eb6f500, 0x67e4fa9f, 0x2ac17082, 0x1e97f7ff, 0x09ee0f5e, 0x845b4b4d, + 0x3e9de8d2, 0xb2458c81, 0x45fae64f, 0x7b4fcf97, 0x4c882263, 0x189d91da, 0x58b90c52, 0xe2657f19, 0xab249e46, + 0x55cbd37e, 0x5af1b176, 0x6ad483e2, 0x0911b70f, 0xf7eea858, 0xbce59e74, 0x0c250278, 0xd68a7153, 0x3545a042, + 0x6e8b9ec3, 0xbeebe7c1, 0x1d851cbc, 0x08bc1bdf, 0x23ee5ab8, 0xd9739a26, 0xc8544fa1, 0x32ec8084, 0x518314fb, + 0x42753d6f, 0x78687672, 0x0cf7473f, 0x5139caa2, 0xa707502d, 0x4198671c, 0x91071607, 0x2f66a100, 0x120b34ba, + 0xb02ef191, 0xddff519b, 0x33f19905, 0xf9d6d04d, 0xb445d731, 0x2162992b, 0x0d33c31b, 0xb3c962c8, 0x3352b959, + 0xc925e98a, 0x423f1e73, 0x6a2aca8d, 0x434b985e, 0xdf086fdb, 0x119927de, 0x68a5f5dc, 0x56374f2c, 0xe15ea35a, + 0x5a54f121, 0xeb2eb3a6, 0xef1cfabc, 0xb41446cc, 0xcb960eaf, 0x8c9c70e2, 0x7caeda10, 0x56603b40, 0xf54fc113, + 0x0072426b, 0x2054bb30, 0x856ea624, 0xed026af5, 0xe15cd75c, 0x6602cc16, 0x15108397, 0x9f6104c9, 0x7c21b830, + 0xca70e02c, 0x898e3c0f, 0x4d7ea158, 0x46956132, 0x440346fc, 0x2855fb13, 0x7bdfed8c, 0xd6aeb407, 0xbf4b6904, + 0x1ff29ac3, 0x5acccbae, 0xd3a707c2, 0x05a72a97, 0x2b615aef, 0x97bb44a3, 0x2ab9d54b, 0x92095a76, 0x00549d87, + 0x1c89b76b, 0x7968aaa8, 0xebec2667, 0xb3991d77, 0x33ecb15f, 0x8da71b60, 0x08c584fb, 0x291669e1, 0x12ae75a8, + 0x34922488, 0x28972c00, 0xbe009fe7, 0xc860dbb0, 0xcb329ab2, 0x2bf6459b, 0xa694da84, 0xf03e1b38, 0xabe99351, + 0x245bb762, 0xd184b064, 0x40666c34, 0x6fa452d7, 0x46347edb, 0xa21485c0, 0x1762b3bf, 0x7c134595, 0xcc734696, + 0x938ba354, 0xe82d8eae, 0xbccbb220, 0x26cf3c78, 0x62982be2, 0xd7360111, 0xe1a41a20, 0x8190b070, 0x3c17083a, + 0x15f4ff2e, 0x129e48a1, 0x90f5569e, 0x9316d22e, 0xd1a1dc3f, 0xa7c3a1e7, 0x1844646b, 0xf126c088, 0xb92d64ac, + 0xb1851875, 0x499bf22d, 0x83654740, 0x090f8f5a, 0x4a6a3736, 0x52e410b6, 0x4a483098, 0xeb9d5c75, 0x8c63deaf, + 0x215a5b4b, 0xba027d6f, 0xa217dfb3, 0xb5051f9b, 0xea333c59, 0x73272bea, 0x43628ec3, 0xe4fbf9f5, 0x0e88dd83, + 0x8d4cd0b9, 0x460aee76, 0xcf418eea, 0x1fca5b90, 0x3c146377, 0xef892d33, 0xf257cbaf, 0xc3ea7c3a, 0x57cc7443, + 0x6c0b7268, 0x347bfad8, 0xe4f3c44d, 0x8becfeaa, 0xcf78f323, 0xc3328680, 0xf5a6897f, 0x62761f0f, 0xf014fc56, + 0x156f0caa, 0xa0039c04, 0x605585a6, 0xe15a935d, 0x17c44285, 0xa31d5f43, 0x676881bc, 0xd8fd466f, 0xd5d12e42, + 0x008cbe94, 0x4c21a008, 0x81771dd5, 0x0efc0ac9, 0x71f75deb, 0xe13b3646, 0x24460caa, 0xcb072da5, 0x9d000efa, + 0x930414c9, 0x82869178, 0xe4e70e4b, 0x35f957d2, 0x59968a10, 0x40eeab4e, 0x77056533, 0xa14c1e21, 0x2cfdb3f2, + 0x5b8eb22f, 0xca63b122, 0x473b7f7c, 0xa78b6e5b, 0x4f39456c, 0x4f5e2a40, 0xcbdd3cb6, 0xab494d35, 0x1608f79b, + 0xdf17cb9e, 0x2a72fee6, 0xb3ddb19f, 0x2f8ce028, 0x9e3875e3, 0x35856649, 0x1fee936d, 0xa4d30fc4, 0x4fd33cad, + 0xb859a3b7, 0x07c345e5, 0x2e7a33cd, 0x96dce6be, 0xfb8f80f5, 0x3f2c7825, 0x447932fc, 0xe0cf5bd9, 0xcb1eb481, + 0xb364ad08, 0x11add043, 0x899d5feb, 0xcaf7acf2, 0x4c60863d, 0xe972d2ca, 0x5d5309cb, 0xe00bc106, 0xadded3c9, + 0x013ec71e, 0xcd7b128a, 0x09bb3dea, 0xbd8f1557, 0x7d626905, 0x9d3bf11e, 0x61823030, 0x4ac03a78, 0xa7a95ebd, + 0xb19b7cf8, 0x22ef4a0d, 0x9dbd5074, 0x03a9f6a7, 0x5d84bcf6, 0xe035f137, 0x37f6899f, 0x2142ce75, 0x27c38d2f, + 0x2fa977a7, 0x04c5f2b2, 0x3bcb1294, 0x3e63c29e, 0xfc6de833, 0xa446a49c, 0x7220209f, 0xdd298b25, 0x133e076a, + 0xd43adc78, 0xc8b91bac, 0x054a5382, 0x988b8fee, 0xe5294904, 0xd4d98fd8, 0xab0d74b3, 0x4e906e2f, 0x8905b763, + 0xabeb0a37, 0x4827b9dd, 0x4f60403a, 0xa87bb2dd, 0x1bc70f80, 0xe2e02d52, 0x0295e29c, 0x026a9dfa, 0x3fc84a6f, + 0x558bf2b9, 0xc2aa3ac4, 0xd8029909, 0x6dd8c42a, 0xb9a08cc4, 0x666401c2, 0x9ebbd1ce, 0x173e3fb1, 0x5d7f50bc, + 0xee5eb160, 0x3b57a91a, 0xfac4a69e, 0x529ed02b, 0x82fdf936, 0xd2d01c50, 0x963ec871, 0x28aa2df1, 0x1f86013b, + 0x2b5c6e6c, 0x7f59d23b, 0x75e4532a, 0x263e0305, 0x7488d449, 0xae7fc048, 0x52cc1509, 0x60c8fa5c, 0x64eedba1, + 0x4c210d5a, 0x6032265d, 0xa5089bb5, 0x81de4a49, 0x71c3f694, 0xb790927e, 0xea872af4, 0x03ee5625, 0xd46ebc13, + 0xa2bfb894, 0xaf837881, 0x929cec80, 0x4f99adff, 0x7100f15d, 0x78bb3561, 0xf7eba3e5, 0x63469cdc, 0xd68ff7cf, + 0x3b53194f, 0x20e546ac, 0x93b58b77, 0x8f8c1eaf, 0x3897cea2, 0xb8f787a4, 0x5632ba77, 0xf06be054, 0xb8e9b17d, + 0x761e1501, 0x717ea526, 0x5689ea06, 0x34e4096f, 0x72dd2fb2, 0xb30e74c7, 0x9da6475e, 0x638a3da1, 0x00c02b8b, + 0x0445c416, 0xe2bf3690, 0x219c8790, 0x68d933d1, 0xf7bb5644, 0x934d80d4, 0x5b817c7b, 0xd25f0a11, 0xa3962213, + 0x107aec6c, 0x46430d61, 0x704d53bb, 0x97611adc, 0x3b95047b, 0x40480fef, 0xc5074810, 0x281b5f42, 0xe29ab722, + 0x6c04330a, 0x88d6e46f, 0xc8b3dc00, 0x0ab309cc, 0xbb70c098, 0x3797ac8f, 0xa00d9fef, 0x3a312f23, 0x5f940a88, + 0xa662ef9b, 0x7e631b1e, 0x2be896de, 0xdf051689, 0x4eabaf6f, 0x50c29ab1, 0x2fd36498, 0x7321465d, 0x779092a9, + 0x7d1bc0eb, 0xb0e0c048, 0xa30c168e, 0x62948618, 0x8eb32d1f, 0x54339573, 0x16add833, 0x5e9f6469, 0xac6e238d, + 0x6137d5da, 0x386fa1de, 0x0fea1fe9, 0x26f32840, 0x0ead7e81, 0x25e83b3c, 0xd142eed0, 0x1d093d93, 0x001d6e40, + 0x9413f02a, 0x78538ca4, 0xf3969e2d, 0x0ed226b7, 0x27fa1fca, 0x59b21f38, 0x561ceeff, 0xf27459b7, 0x23ab369e, + 0x705ef9ff, 0xab3443bb, 0x399f4ff6, 0x073537a1, 0x996c424b, 0x79273f58, 0x78e556b9, 0x7657b724, 0x5ecac70c, + 0x15a80c47, 0x100e407d, 0x4deff9fb, 0xdef4178e, 0x1c9a9fb6, 0x09225611, 0x6d5c36d0, 0x22795d60, 0x190a12e5, + 0x59a7fd86, 0xff805e35, 0x9e16c728, 0xf13a8905, 0x917fe215, 0x2ab9d29b, 0x29cd64cd, 0x2215054b, 0x53482e66, + 0xa5dadf5a, 0xc6ab571d, 0xd01eec14, 0xaf3970e4, 0x8880ea0b, 0x6972e2a8, 0x410f9010, 0x2a7b6f3b, 0xca5ab660, + 0xde46b421, 0xe1d38c9a, 0x281dd413, 0x549423de, 0x67068dff, 0x80799d82, 0xe9b43061, 0x85a6ae3f, 0xd52c15c8, + 0xa151caa3, 0x85abf9c7, 0xa3286b69, 0x46e72c63, 0x61dc4dc5, 0x765cd987, 0x3b2f6a4d, 0x288dd8b9, 0x3cc2f00f, + 0x623a633d, 0x4157488e, 0xe9a1123c, 0x1f56b31e, 0x5f953e72, 0x379a457b, 0xd69c5ba7, 0x793b9c44, 0x7db21a03, + 0x7e26fbe1, 0x6c6459b1, 0xf290311c, 0xb75dcd6f, 0x674eaab1, 0xe315c621, 0xb0c4d3bf, 0x8b390ae5, 0x58a45ad9, + 0xbb235473, 0xca06986b, 0x70383310, 0x1e43aa1a, 0x69ed4c1e, 0xb4e959ec, 0x5bdad7f0, 0xf1dc9ef1, 0x8a9a00b4, + 0x6753077c, 0x84a3f507, 0xad9fa17c, 0xc762590c, 0x8c53b8cc, 0xe6a6b2d2, 0xdb7fe036, 0xa0aa2535, 0x2f835cbb, + 0x4d9de32c, 0x38aba862, 0x667dba6f, 0xb72745e5, 0xbafd3e73, 0x74be7631, 0x29802460, 0x4ac1ee9d, 0x4dc0b261, + 0xaf8eb254, 0x8a568baf, 0x3f9238fb, 0x1037dba0, 0xcf1bb4e1, 0xf814a00c, 0xe79b25de, 0x4e1690b4, 0xa2cc055d, + 0x825bd2a9, 0x61b804f9, 0x20e78755, 0xaae5b788, 0x9190fdfc, 0x327c0619, 0xb911863a, 0xe1954df3, 0x85ead3a0, + 0x9526bc1c, 0x5b97dd1a, 0xff54c4af, 0xe1ee0df3, 0x98c3d63b, 0x21131bff, 0x69abd865, 0xa79b9457, 0x28d91e84, + 0x8f886b6f, 0x595fc0e6, 0x557e8953, 0xfd11523c, 0xfe00cfcf, 0x9de127a1, 0xd7ff9684, 0x049e233e, 0x0e0b05a1, + 0xd72df1b7, 0xb869ce93, 0xfde87f13, 0x3879980a, 0x0cbfe804, 0xbe8a543a, 0xdcab7fce, 0x821de8b6, 0xd3a2d9ee, + 0xe5029ef1, 0x2de1c2c8, 0xc8596e22, 0xa0ad870d, 0x1278dd2b, 0x8b2fe304, 0xf31b3868, 0x8910b436, 0x86f3503d, + 0xaa24b38d, 0x8dc6efb3, 0xb13f02ae, 0x00910de6, 0x331e2a36, 0xc127aada, 0x85f63a61, 0x6bf41b7e, 0x99baedb7, + 0x42127bff, 0xbcb05aa3, 0xcacd6298, 0xb30eda96, 0xc57462ad, 0x0000f810, 0xb90aea15, 0xe4da6c0e, 0xe789517c, + 0x4aaf722f, 0xc7d084cb, 0x6b24fbc3, 0x657c2846, 0x310440ab, 0xb7ca8010, 0xc10488d5, 0x6ec93859, 0x79a2cfe3, + 0x3785c849, 0xa4ae625b, 0x7625270a, 0xb2036af2, 0x7ec6c9c5, 0xfb239c16, 0x8760e214, 0xbb2d3737, 0x98962f45, + 0x8f3cbc33, 0xcd902dda, 0x7ad836f6, 0x828b39e1, 0xf011be56, 0xaacacfb0, 0x31824ba6, 0xc8b74b1f, 0xbc373132, + 0x0c0851a7, 0xa5c678ea, 0x2f58b4b5, 0x786c4aca, 0xa88af2ef, 0x6913c30c, 0xf8816dc5, 0xc26ea991, 0x107fce96, + 0x5cdb4a20, 0x74881af3, 0x443f162b, 0xf399d97f, 0xe1cecaf3, 0x4bdb21d0, 0x436e86f3, 0xf7f2870a, 0x3c8ad977, + 0xb254b087, 0x3f0649c3, 0x579f1fc1, 0xe2091096, 0x03e9c023, 0x4cdcc167, 0x2d864ff9, 0x34cd192a, 0x129587ec, + 0xcb69f627, 0x46704310, 0x7db380ab, 0x6d14d6ec, 0xe5355171, 0xd0f88948, 0x83713be4, 0x2947fa06, 0x824f29ce, + 0x6e099c4e, 0x1a6a3276, 0x55c4d1f1, 0xbb278b18, 0x5d0e5be6, 0xa374ef1c, 0x67b5c3ba, 0x408e0f79, 0x716aae17, + 0x4a3cd9cc, 0x62c76ccb, 0x4d41242f, 0xa95f62c6, 0x420d36e4, 0xa2cb6400, 0xf02fed9b, 0x90c4130e, 0xef07bf97, + 0x70b96ce9, 0x3b4fa0d6, 0x04b306bd, 0x4e956a2a, 0xcd604df4, 0x747361c8, 0x1683506b, 0xb8734e33, 0xc25da1ee, + 0x331e4e67, 0x81795d7f, 0xf76badc0, 0x1cb26330, 0xcc30e42f, 0x0cbc1b63, 0x7e6f038f, 0xed3ab90f, 0xc4012e6f, + 0xbf3f6506, 0xdd157523, 0xcc47c2da, 0xf7de8ede, 0x4cf48c05, 0xf1f85f52, 0xc72d8572, 0x539ea7d5, 0x4a30d007, + 0x73cadcd3, 0x909d65bf, 0x4f10649b, 0x112a8bba, 0xbda8c100, 0x5869e729, 0x759a04f8, 0x7648b7cb, 0x93e4cb45, + 0x416f3c25, 0x9e57d235, 0x00074646, 0x2a64688d, 0x8e0ec581, 0xcbee1628, 0x997710f1, 0x18e42a27, 0x41747d7f, + 0xd2d63ac8, 0x00a0015f, 0xbd00639f, 0xdf36d6fc, 0x92d39731, 0xee4535e0, 0xfde42613, 0x095c8146, 0x2f7eb8b9, + 0x7ecd863b, 0xfe0cc915, 0xbc2e91f1, 0x55bcbc57, 0xf79bbdb6, 0xd5ae7a4c, 0xc7402e29, 0x9c3899fa, 0xc35935a5, + 0x7b3060bf, 0x5bda00e0, 0x0cf15088, 0x8aa26d6f, 0xe7230843, 0x2e7c6e16, 0xd993779b, 0x4a91c23f, 0x3ba33015, + 0xf2a352c0, 0x8106f521, 0xfe9f5a81, 0xce27aacb, 0xb76ef668, 0x084fc7fb, 0x6b2b43d4, 0x926676a3, 0x5f7c3445, + 0xfb84f397, 0x3e3fed78, 0x6afcbdad, 0x46ea39fe, 0x91cc7c43, 0x4634b52e, 0x726d2433, 0x6a957300, 0x0fcb8ad9, + 0xf93b029a, 0x0ae055e5, 0x3efe6a01, 0xaf157c53, 0x36805ee6, 0x6d2dc1b1, 0x6c13fd7f, 0xd0555dc7, 0x99e1d986, + 0x6fe1748b, 0xff26f34e, 0xf1751ccf, 0xba08fe66, 0xe1796dfe, 0x0ce1bcca, 0x5ddd56b2, 0x96b091a0, 0x707ec3a5, + 0xf189989f, 0x5ca4bfcc, 0xd86ea6e7, 0x5e8c49b9, 0x98bbd4df, 0x1199bbd0, 0xc797230f, 0x7436e7f3, 0x1056928e, + 0xbd07b41d, 0xb1d8f709, 0xde604bff, 0xd44d5895, 0xacdfb788, 0x05a6b8af, 0x858e98ed, 0xa606f96b, 0x3e5acba8, + 0x019f97bc, 0xbf206cd7, 0xc63965f5, 0xbb62b22b, 0x466ed9c6, 0xc622f547, 0x3a30e150, 0x545aec3e, 0x2bcfb663, + 0xe29dc831, 0x98cb07bd, 0xd027cacf, 0xb3d57819, 0x8adde998, 0xa34a540e, 0x887912be, 0x703c5272, 0x46a99c28, + 0x9981cbca, 0x58d42f57, 0x9a22a218, 0x6dafb200, 0xd2649529, 0x290a7644, 0x3fd0a543, 0x68115537, 0x5aace3b0, + 0xd934e7ae, 0xa299e386, 0x300c4941, 0x9d3b392b, 0xc11de95f, 0x97bfe132, 0x69908cbe, 0x594442ac, 0x6f30c22a, + 0xcc606503, 0x4daf80b1, 0x4cfe0f13, 0x64b00cfa, 0x8903010c, 0x500e7c5c, 0x3e7698e8, 0xb55fa5a1, 0xca456e47, + 0xa9cfa012, 0x796e14a3, 0xfc93e566, 0xc0b32e48, 0x6e65fc08, 0x06cc7014, 0x23973d55, 0xa898e29e, 0xc1373148, + 0x8c00ecd5, 0x0fdcc9d2, 0x8f79e5d6, 0x9be8f61b, 0x82d4f95a, 0x01316674, 0x6c6fbedc, 0x224c6132, 0xb884a774, + 0x34cd6d53, 0x089c5de0, 0xc99c8ee3, 0x541344d5, 0x4193577b, 0x9df76be6, 0xcd776af7, 0x1f7abf59, 0x2ac2fcb3, + 0xa0092340, 0x136c7fe3, 0x2d27f8b7, 0x99c316c9, 0xe52608b9, 0x012da63c, 0xc1e52d9e, 0x4bd543c6, 0xff42b5d9, + 0x3655611b, 0xa3f6a19b, 0x4750bdfc, 0x3819ab72, 0x016d89bf, 0x804fd45e, 0x84f72d31, 0x66e6f54f, 0x77462cf2, + 0x53ae87ee, 0xc1c6b2ab, 0x94ca4bd2, 0x582f0ac0, 0xebeaf5a7, 0xa6d4c76d, 0x570059e9, 0x002a69c7, 0x04415381, + 0xd3bc91af, 0x3cb1e35d, 0x79ae17e8, 0x2068d26f, 0x54259f7b, 0xf0f5ac3d, 0x5816df37, 0x514124b2, 0x40aa6e42, + 0x7707cd13, 0xa3a6440c, 0x7e424cc7, 0x4edb288e, 0x6a1d09fd, 0x1c8d9bb4, 0x9f39bc32, 0x2edc175f, 0x7e086ce3, + 0xade58356, 0xc1d2ff58, 0xe0004633, 0x9fdd579f, 0x5378b1f2, 0x55ea3746, 0x595ee473, 0x4ce90fa5, 0xd4f4c9b9, + 0xc91007cc, 0xbe24011e, 0x92783051, 0x8470eaec, 0x257e274e, 0x6452c12a, 0x37697f0b, 0x0190a715, 0x38f0385a, + 0x2758799e, 0x21bb5ad0, 0x0204db61, 0x29e9b7df, 0x6679b8d5, 0x20a57e63, 0xca52c6d7, 0x2947c6f7, 0x9ef61745, + 0xc60e1c95, 0x09da979d, 0xd6e10ae9, 0xbba53c95, 0xffd8a4b4, 0xe6f0cd59, 0x6c3011e6, 0x4a3ea3fb, 0xf3312ed0, + 0xecb40a7a, 0xe33b024c, 0xf8d02751, 0xbd664e6f, 0xbac2ba1d, 0xde9748cb, 0xe209f791, 0xb40a7637, 0x26d9326e, + 0xaea28473, 0x477977b3, 0x07855bb0, 0x9b9348b5, 0x200342a5, 0x8b654e27, 0xd8a971a9, 0x6ec71b95, 0x89960b4d, + 0xcb5b2949, 0xe6e17c0a, 0xcdf5df0c, 0xdda3b55d, 0xfffe67fb, 0xdab817be, 0xd793be18, 0xf2f6e820, 0xa85e8b34, + 0x2ae673f9, 0xcde2dbe4, 0x5b137c0f, 0x5733a024, 0x41efbc6a, 0xae8322b6, 0x5dc3318a, 0xfabb9fa9, 0x40504be6, + 0x5e78503d, 0x1f8449c5, 0xfae794ce, 0x884ce8b6, 0xd4b20c50, 0xca06399b, 0x1620324b, 0xf8cb6897, 0xd28bf3f5, + 0x33083be0, 0x6c84e5a1, 0x29baa33d, 0xf329be6c, 0x3a2dc514, 0x7b245d20, 0x5a8c1c6c, 0xe0dd5c02, 0x6aa9d468, + 0xe7248534, 0x04eab216, 0xe3d28692, 0x98678809, 0xef5154a8, 0x081921fe, 0xdf9adcdf, 0x0da388cc, 0x34413af7, + 0x853f1d7c, 0x95c34a72, 0xf5ef261c, 0x78b5bc2f, 0x0c7bd4eb, 0xa43ff9fe, 0x9a6ba472, 0x8496966a, 0xfe33af6e, + 0x394a2291, 0xaee5cb55, 0xac065493, 0x6b14fdb6, 0xf9e1aea5, 0x7dd5eefb, 0x5ef905d9, 0xd62d02b8, 0xe39eac2a, + 0x7ffb8e5b, 0xe1786c98, 0x16c42a62, 0xdc794803, 0xe7fcfe72, 0x9a245ef2, 0x244d7283, 0x17753d9c, 0x8f71b886, + 0xa9551df4, 0x1ccc5f71, 0x72d1c74c, 0xc011e483, 0xf35648b5, 0x3448ae00, 0x2a76f536, 0x780ab9be, 0xc7c1afa5, + 0xbc734e00, 0x5659d24e, 0x5830149b, 0xa686aa68, 0xd76136cc, 0x8fba4d94, 0x6c6e87fd, 0x90991fe6, 0xb1914ab3, + 0xfa513bce, 0x50ea5395, 0xccf386a4, 0x79e92c6f, 0xe9fed068, 0x0888e183, 0x7a842ae1, 0x4adbec45, 0x9f26a418, + 0x5328a3f2, 0xc38a2fa3, 0x9654b7fd, 0x80fab427, 0x9d23a127, 0x77507416, 0x23b3cfc2, 0xd61d8e3e, 0xf93c6a95, + 0xd0802b72, 0xbedd8458, 0x043240ee, 0x8a57f10c, 0x5cf44d9b, 0xb475c026, 0x26a851e0, 0x45f9ba28, 0x27635d32, + 0x43a2378c, 0x08666fb6, 0xcef6a4d2, 0x48a62c4d, 0x8d7a591a, 0x60a81f87, 0x8e6686f7, 0xdeca4f93, 0xeb9c5ac0, + 0x9e17746a, 0xd9aa489c, 0x4c88c2eb, 0x7c4e9f00, 0x0d075baa, 0xb60ca592, 0xe801bfbc, 0x6e9bdf1a, 0x9278b457, + 0x76da6778, 0x552d1e71, 0xc1d112bf, 0x5491f4fb, 0xc9ccaf00, 0xfe39187d, 0xdd4f7ada, 0x1c524432, 0x21cc00f5, + 0xf7cf51ae, 0x00ab3d5a, 0x3fa13bd7, 0xbdbd8b57, 0x5f854d57, 0x198a09fb, 0x83924282, 0xa4889afb, 0x66634c39, + 0x487aebda, 0xdb0c2e4e, 0x046a584b, 0x7b654c18, 0x1c9ad91c, 0xc0410fb7, 0x6df5c3f1, 0xc2e8a12b, 0xfca1b197, + 0x341371e7, 0x8e68e0c8, 0x8478ff17, 0x9831810c, 0x331fb87d, 0xd33d9ab6, 0x8b0992f4, 0xd4ff981a, 0x35aeebc4, + 0x02faab01, 0x025fe439, 0x468de94a, 0xc96bb89b, 0x668f9b21, 0x08f3dea4, 0x0f979013, 0x5b660b18, 0x595cb747, + 0x60ad8dcd, 0x423292ad, 0xaeb729db, 0xc12b0594, 0x4bc4332b, 0xe815d7a0, 0xfce09a5c, 0xb360ee12, 0xba33fd69, + 0x364fcb74, 0x98d76a4e, 0xed087760, 0x076a9462, 0x936dbf46, 0xa594f35e, 0x027cc496, 0xfd912c26, 0xf51d30cb, + 0x728cad7e, 0xc0beb598, 0xad2a141d, 0xf3fe82f5, 0xffeae1fa, 0xaf90dd1e, 0x776f6594, 0x428b10b8, 0xeb59e866, + 0xdd5d4ab4, 0xc00e5a7b, 0x4b622363, 0x65a56724, 0x8c9ad0d8, 0x0b2d4fb0, 0xff0430ae, 0xc9eb1d11, 0xa955d7ea, + 0xb387fd8b, 0x20f9f982, 0x8bcc13fe, 0xf03617b8, 0xa0a033c3, 0x8986a2aa, 0xfc21d7ae, 0xc3946d52, 0xeba8cb6b, + 0x2366e3d7, 0x19fa3077, 0x4819aeda, 0xbfd13d3f, 0x8eca1777, 0xc407c806, 0x130acbf2, 0xfd540eea, 0xb772e0fe, + 0xb4fd3ab4, 0xde9d78a8, 0x9025f571, 0x5df3bdb1, 0x55ffa8cf, 0x8388b55c, 0x34b414d6, 0xef49cfde, 0xcaea8132, + 0xb6dc28ad, 0x0b4685eb, 0xbfcc917b, 0xb4b6ee60, 0x2088b718, 0x326309d2, 0x5a190583, 0x243e90b9, 0x4335d0aa, + 0xc44a3960, 0xf5bf9b8c, 0x1f38a79f, 0x619081f9, 0xb8552ad0, 0x7cc5542b, 0x89463411, 0x6dc8412e, 0x2a903d6e, + 0x75bd87d7, 0xfdfc1ae9, 0xb3e48c7e, 0x78fb23f2, 0xa0ac69c2, 0x4ca354c3, 0xec3e985b, 0xd4e7bf22, 0xd50c5bb0, + 0x4d36ce3b, 0x1803f721, 0x16ca20d7, 0x03fab200, 0x95ff869f, 0x9b5d5040, 0xff9ec603, 0x3c0a7a8d, 0x4268a563, + 0xe5b6e5c6, 0x6228d6de, 0x64d0a047, 0xcede6991, 0xe16081d2, 0x096eff0a, 0x997a9a93, 0xfbe41c80, 0x7363bdd6, + 0x2458cea8, 0x261c7d39, 0x61b67544, 0x8898abe6, 0x56a45de6, 0x8da1e9fa, 0xd8a0283b, 0xfe3ee365, 0xdcb4a2aa, + 0x7f0a0bea, 0x8cb9c8ca, 0xb1373648, 0x8c4155d2, 0x26e40a59, 0xd589a0a9, 0xff91ed05, 0x901a4d08, 0xbeaad77b, + 0x6c9f614c, 0xd8bd7c1a, 0x019610f1, 0x2bda4cfa, 0x449c6d93, 0xf9955e9f, 0x2d55dd24, 0x953a4e47, 0x6574801a, + 0xb8607e2d, 0xf35304fe, 0xc0ba475d, 0x8a6986a7, 0x82698fdc, 0xe491c254, 0x63cb5a0f, 0xe06970b7, 0x946598f9, + 0x0833668a, 0xb9e2b41a, 0x7d31e2b0, 0xaf557ad7, 0x794c30a6, 0xafadd40b, 0x5de10ff5, 0xbb2fbb89, 0x5a3c0bf0, + 0x60af66a8, 0x7b18f211, 0x53b2fa2d, 0x3f62e50a, 0xf6b78cfa, 0x3d161896, 0xbe6b2fd0, 0x36e2c59f, 0xc27df60f, + 0xcaaaa3a9, 0x33cd8032, 0x96d38de4, 0x17102a67, 0x48a205f0, 0xa9710432, 0x4194d05e, 0xcbe24f02, 0x77154eb3, + 0x91f17db6, 0x7c8d49d4, 0x81768353, 0x837c6d4e, 0x178bd224, 0xd693706d, 0x36140e5f, 0xbccbef4f, 0x1c7bfe48, + 0xa623f628, 0x9b84d7d2, 0xd3c96ad7, 0xa9727848, 0x82e163b1, 0x169dd795, 0x263a5a52, 0x3afe3612, 0x8195b205, + 0x604ae131, 0x9d42bd1b, 0x8b507658, 0x482c33df, 0xb80f0afc, 0xf338efd6, 0x8ca957df, 0xa9541798, 0x1620544b, + 0x23e64a64, 0x9bde229d, 0xc3b784bf, 0x44af6fa8, 0x6d8b49eb, 0x92ab02e8, 0x4b8a9e77, 0x421ca1e3, 0x5dba6d8d, + 0xabc7131e, 0x29a95ca5, 0x8ba983cb, 0x5800200f, 0x58bc17d3, 0xc0ea7ab5, 0x9bae5182, 0x59e43819, 0x9f244e94, + 0xdf7a3bc1, 0xc0223d52, 0x82510605, 0xaef06d4d, 0x5786e3fe, 0x41a1ec01, 0xe171d3dc, 0xb362094b, 0xc8298754, + 0x651c9528, 0xbb7d00ae, 0x019e3325, 0xee858a12, 0xa1a0bfd9, 0xee27c1f5, 0xd653bcdc, 0x211403c3, 0x079bada0, + 0x46439a99, 0x9acc4277, 0xd327c3f5, 0xfc2e6a1d, 0x862e4d61, 0x910d69ae, 0x62bf9867, 0x782f1bb8, 0x52198b06, + 0x3a8d76dc, 0x836aaf76, 0x19eca3d9, 0x23d594b8, 0x970e00d6, 0x3a446512, 0x27bebb5f, 0x5285a81b, 0x6a95d862, + 0xeaf6c873, 0x0ee2354e, 0x587cbf64, 0x7b6caa3c, 0xee483ba2, 0xe875c7cb, 0xb898a453, 0xf02578e6, 0x22db698e, + 0x3c2c0c5b, 0xcddc3205, 0xe09dab81, 0xe27d8fae, 0x6ef9597a, 0xd6cd9be5, 0x8a2aab27, 0x49d9ff8c, 0xc7fceec2, + 0x97b6becd, 0xa09d0a71, 0xc8aab4ff, 0xef7703b7, 0x06bd3833, 0xda7f1ce4, 0x2caf0dc4, 0x75dc9e9a, 0x10945f8d, + 0xc3f74196, 0xf674b690, 0xc1efa181, 0x2504e3fc, 0x9759b7d8, 0x6b3f9322, 0xd66b3014, 0x2da12313, 0x427ee85c, + 0x181eb9c5, 0x6537a2d6, 0x54a02b6f, 0xce3fe53c, 0xc8aecaa9, 0xf7cd3373, 0xa203350b, 0x6865a6cb, 0xc21a05fe, + 0xd035c3fb, 0x0b8a6dc4, 0x0eca2260, 0x6cd388eb, 0xd5a770d1, 0xb4813ab9, 0x544e3fc7, 0x77e9116c, 0x2443537a, + 0x697be6f1, 0xb58fe59a, 0xba805f5e, 0x4f108a8a, 0x048d2971, 0x55445b2e, 0xf2087b88, 0x9c04f505, 0xa9df0d4c, + 0xa75c013b, 0x08a917e3, 0x7fa0e91e, 0x45036574, 0x71be7b77, 0xa4774bf5, 0x01cb9d3b, 0xf575381c, 0x958ff009, + 0xc925cb68, 0x476b6481, 0xc684baf5, 0x09cd5818, 0x7788a0c6, 0x38594aaf, 0x32e435a1, 0x5d59c313, 0x96450478, + 0x637c6a8a, 0x482655b9, 0x4a587a01, 0x79ee4a75, 0x25a41e92, 0x832b9ba6, 0xa09caa88, 0x48813f1a, 0x6b80d4df, + 0x03d4d56a, 0xcc88a276, 0x17c8c243, 0x42db018c, 0x1cfe5a36, 0x765ad693, 0x59915fc9, 0x9ee882f1, 0x7bd39b7f, + 0x4a6094e1, 0x857423c3, 0x4870727c, 0x53021f4c, 0x19e3ebb1, 0xaa60b042, 0x25a938ad, 0x9ad8cda7, 0xe3cc297d, + 0x5d17b110, 0x48be6a11, 0xad30ce6b, 0x18b7f1a1, 0xc7eb65a9, 0x911d5bc1, 0x64abdef8, 0x9cd3e72b, 0x649f4fcb, + 0xa375f8cc, 0xc809454f, 0x5462aa59, 0x36af6d7b, 0xc7d09503, 0x55ca24c0, 0x4da4ffaa, 0x6e38071f, 0xfe38777e, + 0x33fe08c2, 0xe7bd5784, 0xc128a524, 0x8fe22006, 0x0fc9ad88, 0x147c4675, 0xe53caccc, 0x8b5501e6, 0x8a65e44d, + 0x906ca59e, 0x545b5567, 0xdf4adae8, 0xaa323bda, 0x16c97196, 0x2b3eba34, 0x642bd74d, 0x5078f357, 0xef267b57, + 0x8b71844d, 0x9040cbc9, 0x5bcd6210, 0x21d39887, 0xd10b9076, 0xfb031697, 0xe9159df0, 0xdcba4e61, 0xad577c6a, + 0xd041f197, 0xe62615b9, 0x4a4d1f3e, 0x48971950, 0x82fb7f7c, 0x97227ea4, 0xafb11e11, 0x3f8f5552, 0x86989167, + 0x11deea5f, 0x69bf62ab, 0x724a046e, 0xa9a832df, 0x71f2d46e, 0x6a8adddf, 0x9da5e2ee, 0xf966ae0d, 0x1f0cfcd1, + 0x5f234afd, 0xd1eb2f02, 0xb7d05772, 0x9df64dfe, 0x001a0c39, 0x71242a33, 0xf872914b, 0x7db2583c, 0xc6e433d0, + 0xd5aad7a3, 0x17592725, 0xa1b82de1, 0x975256b4, 0x0666a508, 0x5b9c73b9, 0x69ecf902, 0x59e66991, 0xd5e147d0, + 0x224d3cf1, 0x7b756eb4, 0x6d94a577, 0x389f0917, 0x26fb7d10, 0x5e993fb4, 0xa6f44ed2, 0x633bcc44, 0x32bff2c7, + 0x071e0608, 0xdecc9856, 0x382516d8, 0xdb2df58a, 0x11253d1f, 0x867ee7c1, 0x050bafb3, 0x5adec34b, 0xee52d8ba, + 0x8834ea7e, 0x1144833a, 0x43d75477, 0xd78ab886, 0xaaaeedbc, 0x3191ae6d, 0x1c4546e1, 0xad66ee58, 0xe7134eb5, + 0xc5a2662e, 0xba8b7ecf, 0xe321b5be, 0xea8057f8, 0xdec53641, 0x59388a81, 0x45a44976, 0x328ae563, 0x92cabad9, + 0x08cc9643, 0x1713ecb0, 0x015c00de, 0x1931171b, 0x0d43fd76, 0x7a164ba9, 0xad8ae938, 0xab4cafe3, 0xfbea8dac, + 0xbaca01e5, 0xd633cc86, 0x3086b058, 0xe4bff625, 0x86485c15, 0xfeb45a22, 0x62a300be, 0x702944c9, 0xb363c368, + 0xf06a57a3, 0xc8bf0198, 0x08d8a63c, 0x6568e657, 0xc91b502b, 0xd8f91478, 0x8b7d1119, 0x0adc462b, 0x786d154e, + 0x6cbef550, 0x2d8fb089, 0x9b0277aa, 0xdf285d5f, 0x314f0846, 0x6641810e, 0x53a483fe, 0xcdcf6ecc, 0x52151038, + 0xaad33090, 0xf6bebf0d, 0xb68ca3c1, 0x287d591a, 0xcf54e20d, 0x20b29f23, 0x02f318ca, 0xd2bfd4e0, 0x4b017018, + 0x28b2ddb7, 0x3b83bd18, 0x9e845b27, 0x98e2ba88, 0xbd71adbc, 0xab7e57b3, 0x51b6e992, 0xf1c23241, 0x7dea800c, + 0x2c0bffd3, 0x54537a49, 0x057bb9bb, 0x90741a3e, 0x0357458d, 0xdad49ce8, 0xa3f04917, 0x8226d079, 0x745d9ce5, + 0x9939fb8e, 0x8d0e9476, 0xa5747514, 0x0e5cfbf6, 0xfc30e6ac, 0xac2917dc, 0x86138f38, 0x12395ab7, 0x64279cf8, + 0xac434024, 0x3b7f2688, 0x1dc88420, 0xac0bd74c, 0x1d204878, 0x2fc7a5b6, 0x2c844712, 0xfd6f1ad3, 0x91b159f8, + 0x663f33a5, 0x58f8f0f8, 0x8529daf1, 0x01975f67, 0x7f76e990, 0xcade9c33, 0x6e06cf85, 0x22900545, 0xd3ed3f49, + 0x2321ac3a, 0x1a2080ec, 0x787e7310, 0xf4973df4, 0xa4938b04, 0xecd67d31, 0x967995f1, 0x37119160, 0xaf2b21aa, + 0xa74c1c6c, 0xdbe6d33c, 0x1431f7e4, 0x0a687254, 0xe7d42151, 0x77fd4342, 0xe568c45f, 0xd26b3ba1, 0xcf20baef, + 0x36c248e0, 0xa3664211, 0xa1886c7c, 0xa5b0a228, 0xe1843e07, 0x61b48116, 0xfa350bbe, 0x4dd62f14, 0x77c39d48, + 0x394bb121, 0x93806f37, 0xcd52ed28, 0xbf552076, 0x0dcba7fe, 0x9ec24712, 0x587f315f, 0x82431333, 0xc8e43671, + 0x17797fe0, 0xa33c4233, 0xc6ebf1ab, 0x16dfd2a4, 0x3e57a8d0, 0x010e44eb, 0x329f8a0e, 0xeef18a0d, 0x3074dc17, + 0xbf9799ac, 0xb6bb6cda, 0x28302d6a, 0x1e0e58d7, 0x508e3c3f, 0xf1180922, 0x2d598053, 0x72943312, 0x9e213820, + 0xbc98e40b, 0x5df6ebc4, 0x3d9dbf4b, 0x13b1447c, 0x684bc7e5, 0xf8458dda, 0x3cdde832, 0x9177061f, 0xa20754d1, + 0x4fd67b16, 0xfd1a899c, 0x075cecf7, 0x6d8683f8, 0xa047e77a, 0x8203f913, 0x946ff0ba, 0x626ab3bd, 0x53759ac9, + 0xaa42e1dc, 0xa2d748dc, 0x89fbea38, 0x331ab290, 0x77163928, 0xc1ae318c, 0xfa62c1a6, 0x6f3c50fe, 0x40d4aab9, + 0x083845a8, 0x3d3ed2f7, 0x5e0f4bcd, 0xc46c9f75, 0xfd3f87cc, 0xa659afee, 0x4c3c6ad7, 0x982d0a33, 0xb3a3e496, + 0x36814abc, 0xe06069f0, 0x1c85c641, 0xeae6a90b, 0xe443c769, 0x3cfb1a88, 0x0897162c, 0x3a806678, 0x3551f462, + 0x214da206, 0x52d4eac5, 0xacd5f275, 0x122da4db, 0x2d94e7ae, 0x377a7631, 0xea4e2f89, 0x7d129682, 0x9d96a136, + 0x6dc17142, 0x6ae38beb, 0x5590d450, 0x9824043e, 0x785b379f, 0xf643828f, 0x00c94792, 0x24a6ed6a, 0x12fbddf4, + 0x1c5c7ac5, 0x9df7848c, 0x2a4a65a9, 0x236c1f7a, 0xa82fc8ff, 0x9bb84549, 0x5473a8b3, 0x766e664f, 0xaa8b4490, + 0x1658359b, 0x40595ca5, 0x74efb58a, 0x9f1181f1, 0xf3b48064, 0x968defb1, 0x452ff4d5, 0xce1a6bed, 0x8f562cc5, + 0x92ae8c5a, 0x0bbdec43, 0x425b3829, 0xf3ed32d7, 0x320921e6, 0x81b9be73, 0x94b15155, 0x37b2f247, 0xe1a79e12, + 0x0d2e2a48, 0x6b92e521, 0xc93f627a, 0x203ab44f, 0xaea30597, 0xeb8767b8, 0x3e890ff9, 0xadce71ff, 0xefa8f66f, + 0x01e4712c, 0xd89a8163, 0x8d44316a, 0x2c677da2, 0x48e9963e, 0x4cef5d34, 0x726d3d00, 0x7ba89634, 0x1f88d39c, + 0xa664f5c9, 0x42b33b6f, 0xf26e2327, 0x16c0b52b, 0x42cb8551, 0xc426c72b, 0x3c4216f9, 0x5660ff8e, 0xb4a5dd23, + 0x32850286, 0xaf0d6fdc, 0xbddc48a7, 0x9cd75057, 0x7aa08b2c, 0xd1264ce6, 0xe7dbbfae, 0x562ce996, 0xda4abde1, + 0x68094ddc, 0x278047f5, 0xf056828a, 0xf290abbd, 0xba5fac0d, 0x1fdf6096, 0xc114f5ba, 0xf8f33cde, 0x6f06141e, + 0xec750405, 0x31fc0a6d, 0x27754753, 0xe570c393, 0x843824c5, 0x028a44b1, 0x4f853b48, 0xf6b01638, 0x826b08f6, + 0xbb5d75c3, 0x7f08d801, 0x7a867293, 0x0bd6ccfe, 0xc9b39995, 0x894b18da, 0x375a3621, 0xdf71cfa4, 0x3022c7c6, + 0x0890044e, 0x715de1d3, 0x39716765, 0xd6ff9d83, 0x52c802cf, 0x07068eff, 0xdcac2fc8, 0x97b9153b, 0x5e32f0bf, + 0xd814202b, 0x9b8bd222, 0x0298283d, 0x4daa0605, 0xf85fc016, 0x033c19b9, 0xc1baa0a9, 0xb773f30b, 0x680753fa, + 0x9cfce6e4, 0x6ac777e2, 0xb6d3c8ee, 0xcd75de26, 0x1a0fd769, 0xb758a070, 0xdc48509a, 0x66ad08f6, 0x52da4029, + 0x204ff0be, 0xc30a7a48, 0xabb2c257, 0x0ee0d6c0, 0x70cf9b55, 0x632c5d17, 0xd3c454d7, 0x06326cf6, 0x988ef7e0, + 0xff18498e, 0xcdb7dcfa, 0xa6689a76, 0xab27aa5c, 0xd239e915, 0xa035e950, 0xe5ea6819, 0x5436ac84, 0x4c3e0dc5, + 0x99b85913, 0xc7dc5869, 0xfd8e7ab2, 0xb04df0a3, 0xecb5235f, 0x2c6157d2, 0x09454836, 0x66ceb009, 0xa95e3269, + 0xc3b775d5, 0x6c13289e, 0x61e9122f, 0x30edbccc, 0x0a78f2d3, 0xa9ea4605, 0x6159a2bc, 0xe227d213, 0x09600a2a, + 0x4506e7ab, 0x9a07646e, 0x67239de3, 0xefefce3f, 0x4d705a98, 0xc559bf63, 0xc9b1064d, 0x0dbfdfc5, 0xfe11707c, + 0xec566451, 0x61c4e18c, 0x0a20c789, 0x0d9a8f72, 0x3f5a4dd3, 0x92dc475e, 0xcf472df1, 0x2c77d3bb, 0x6f35d7fb, + 0xb598df01, 0x3fcbfb0f, 0x4063839c, 0x9fe240a2, 0x9641423e, 0xcc11c09b, 0x29fb2b70, 0x036cce82, 0x33abc5ba, + 0xe6b9ba2f, 0x2afff9a0, 0x1234aa01, 0x23c7e47f, 0x5aec204d, 0x2d1d5ae3, 0x2411a1d0, 0x027c12dd, 0x9fbe4250, + 0xc485815e, 0xc4758ec7, 0x67ff1e19, 0x66810e63, 0x29ab50d7, 0x3921f3de, 0x50b8750f, 0x2cdeefac, 0x484ba69d, + 0x7f553f7c, 0xea5ebcaa, 0x6109dbee, 0x91f49212, 0x6ac504d4, 0x9a544f93, 0x303347fb, 0x2292d761, 0x8a18d2d1, + 0x13ff1bb7, 0x630d12ae, 0xc4852638, 0x3f024964, 0x912059aa, 0xa4061fc4, 0x3e832e17, 0xec8c3794, 0x466e4c15, + 0x92b6a8cf, 0xd223895f, 0xff2a812a, 0xdc82c652, 0xacafa892, 0x8511d0c3, 0x3227be88, 0xe22b49a8, 0xffedd492, + 0xe95c4664, 0xa57e4bd3, 0xd50db9b9, 0x3dbd0706, 0x2b8f3bcd, 0x1de8d0c6, 0x13a60678, 0x4b5536d6, 0x03d59eb1, + 0xcc005978, 0x17f1ffd2, 0x93f83426, 0x5c5c0a18, 0xcb8eef1c, 0x3653f2d3, 0xfcdb4784, 0x5fd953f5, 0x7cb69197, + 0x3afaba98, 0x95bbd675, 0xcaf840ae, 0x52cc687b, 0xe97efb30, 0xbd97ff93, 0x1596e86a, 0xd0991621, 0x6d6a709c, + 0xa3bac6b3, 0xe80d33c7, 0x6e395bd8, 0x05c517b7, 0x21e814d1, 0x77b1d0b4, 0xbc00a76a, 0x6bdad7f9, 0x1db9592a, + 0xa2472d6e, 0xc38305af, 0x03718e07, 0x6093c8e5, 0x8f917e97, 0x7b528076, 0x975a9366, 0xa6116b3d, 0xe9ad5f56, + 0x283bb1fc, 0x3ed7a6c9, 0x61337751, 0xdf201fb8, 0xb95ba0c9, 0x981cae76, 0x99b71f74, 0xb519d56d, 0x14b4a698, + 0x75a5ace2, 0x80c17e5e, 0xbe34997f, 0x77a95aaa, 0x419fe0f7, 0x528b0854, 0x7657817b, 0x04276f36, 0x5b46ee5a, + 0x07a1a0ca, 0x42b6691c, 0xb5d420b2, 0xf3a94131, 0xa8c48d6f, 0xe60c7a0b, 0xedf60dd6, 0x7bb9d419, 0x2bc99fce, + 0x35c3fe41, 0x4a74587e, 0x14333fc7, 0x79c72bc8, 0x6d33522a, 0xf1edc987, 0x7294aff5, 0xb149ef91, 0x611ede2e, + 0x50e6ba45, 0xf9667059, 0xe50b1a65, 0xbd33d589, 0x06fb167f, 0xcd740306, 0x96ccc844, 0xaad0dda9, 0xaa94d676, + 0x376db484, 0x5b9c2684, 0xfd7c732c, 0xf00e4013, 0x8d458102, 0x7c9525d9, 0x98bdaf55, 0x92ed6c37, 0x07cd935a, + 0x6f7c3c11, 0xf1949a41, 0xe9275dd7, 0xd7c201bb, 0xe96c92bd, 0x3115fb49, 0x5ecf4503, 0xcc799c55, 0xcf96f835, + 0x56968134, 0x6f36faca, 0x0020ec90, 0xf143d870, 0x37422e87, 0x8421c8eb, 0x6b73fa2e, 0xb4b39ce8, 0x6417162b, + 0x82a66790, 0x829de47b, 0x4f78615d, 0xcc1e6776, 0xa52c3c00, 0x756acafc, 0x709c3c1c, 0xb0fd499d, 0x2c0147bb, + 0x410e20d0, 0x87cb0d75, 0xcc5df9b1, 0x41e85c06, 0x6e4c8bed, 0xdb34a9b3, 0x34081ba8, 0x486dd031, 0x7379e8b6, + 0xe8032c1d, 0xbb0f49b7, 0xb42e5eda, 0xe3b11b9d, 0x86a23722, 0x5f24e4f4, 0x9a4b9b02, 0x60b23bf3, 0x271cefbe, + 0xc53d0c9d, 0x1215fa55, 0xb86f8eac, 0x117bc875, 0xab84c7f8, 0xa9639384, 0xf01a23d4, 0x833197a7, 0xa8b3d066, + 0x74f59250, 0x24b41693, 0x542af221, 0x85f40751, 0x11ec89c5, 0x2d58ee82, 0x9c0aa853, 0x7d87f011, 0x109c87e8, + 0xc01b5f6c, 0xaf4c46d1, 0xf4e3c7f1, 0x18ce88ae, 0x9c5ad16b, 0xa771c808, 0x462ba05e, 0x55465949, 0x250e3d79, + 0x900ec7dc, 0xbc1d0937, 0x471e588f, 0xbb6fe8c0, 0xfff994a1, 0x1a5a1a77, 0x19078d68, 0xdebbe49e, 0x3c384398, + 0xd5584fbb, 0xdc8a596a, 0xe982d19c, 0x8fc6b84e, 0x76dd1c34, 0x8524774f, 0x03c60b92, 0x44bd44a3, 0x05705663, + 0xeefa93a0, 0x4f703594, 0x29ae3861, 0xf125f91a, 0xdcbe8359, 0xa2e600ab, 0xe3ace68d, 0xd9a7f1b1, 0xdb111f33, + 0x47a5f8b7, 0x763f30e7, 0x6c5f4c62, 0xe5d54972, 0x044d501b, 0xff6101b2, 0x316c12fa, 0x9e875fb3, 0xba37cdfb, + 0x766a9906, 0x9b06b7b6, 0x2e34f939, 0x51e63077, 0xb07eea0a, 0xe039ab96, 0x87359705, 0x57034038, 0x4546df7b, + 0xb41cb0ac, 0xc3076708, 0x1a291774, 0xf369a384, 0x754a0b0a, 0x1205df9b, 0x23ce463b, 0xb6299dc3, 0x068d5887, + 0x2673bdbd, 0xcb157d1b, 0x3c46664a, 0x6c669635, 0x7f4301b7, 0x589039c3, 0x80c88fa9, 0x5b7ce6bb, 0x3d201ae1, + 0xc2c2c622, 0xd6feaa39, 0x896c17bd, 0xf9530708, 0x29a3933c, 0x5deae7f9, 0xc76b7423, 0x9c22eba3, 0xac39f289, + 0x3cd30a76, 0x3e78d670, 0x336cfd97, 0x7f5cbcab, 0x5bb47160, 0x992e7033, 0xde8c01a5, 0xf8318d40, 0xbb544a78, + 0x3b3bb689, 0xceb2d7b1, 0x9a5f28d7, 0x95db9aff, 0xda1e6063, 0x368d8655, 0xe6dc6f81, 0xb376821e, 0x2f3e8f09, + 0x864eb2c0, 0xd7d25f1b, 0x4c503450, 0x164b43f0, 0xbfb4af88, 0xdcee0c66, 0xf87fff78, 0xa5b3a3ae, 0x116ea466, + 0x017b6863, 0xaa35936d, 0x0d5ec6c8, 0x3ddaba39, 0x8ede63be, 0x345e92ba, 0xf6cc46fa, 0xa9b5acf6, 0x88bfc7fd, + 0xd18ccba7, 0x7b0fb31d, 0xb8a59811, 0xe6e64959, 0xd7e14a41, 0x4e2d37ad, 0xe21f5d13, 0x85720214, 0xb30ea6fa, + 0xf49962e9, 0x70302935, 0x971c9b36, 0x30d9ef5a, 0x2b333e67, 0x6f7ea81d, 0x7a52a15c, 0xcd5fa387, 0xc2f65382, + 0x777701f7, 0x94139704, 0xff26c3d7, 0x327a1ac3, 0xe6cb5a79, 0x581d9540, 0x7cc61fd0, 0x1ec55c50, 0x95619a89, + 0xb2d2accb, 0x730dafc3, 0x35300b9f, 0x0a35b6a5, 0x455d39e0, 0xaf8928a8, 0xd629d939, 0x00bb3e68, 0x2d4a7b57, + 0x1a2b1b49, 0xd59c1ba5, 0x19310c06, 0xb83914bf, 0x4bbc6125, 0xf5cedda2, 0x53455881, 0xac3d386f, 0xfa5ed805, + 0xed2d079b, 0xee74fed5, 0x75e457bb, 0xaa8acd28, 0xcf63c8bd, 0xe39b9099, 0x33ec7026, 0xd37c51ab, 0x08fdb923, + 0x8968746a, 0xd5094af5, 0x2c0a9fef, 0x71a41e91, 0xa373f6ca, 0x907f9ed9, 0x66315f8a, 0x3bc1819e, 0x64cbbb9b, + 0xc1e27821, 0x0470c0dd, 0x0662a73f, 0xcf952e40, 0x0a444a61, 0x1a44bad9, 0x37eeefe8, 0x99546ac9, 0x872503ce, + 0xf9f74048, 0xc8ad2c52, 0xe85aaf72, 0xdb2ca953, 0xbdb10c40, 0x9994cec0, 0x928741b3, 0x90eca091, 0xf786c41a, + 0x9a3c58db, 0x8071d855, 0x8cf8214f, 0xc169ab10, 0x847d4d3c, 0x06386283, 0x68a281b3, 0x5081e84a, 0x5b9a6869, + 0xa4744714, 0x08fce447, 0xf32f7f63, 0x0e21ad98, 0x07dcb018, 0xd88ddfe5, 0xd7f34d47, 0x658379d5, 0xc46727ca, + 0x99e880ad, 0xbcaed140, 0x1b4ee3da, 0xaba697ab, 0x8a962a40, 0x1dbe5adb, 0xac320e47, 0xeea1b7ba, 0xe35e79a5, + 0x8b2daaee, 0x107b8d89, 0xd2c56655, 0x9be96900, 0xb1af22ed, 0x3bcfa3b5, 0x6f623ad6, 0xca89a45d, 0x690c86ac, + 0x200ad0a9, 0x7c71aae4, 0x9003b21b, 0xaa11e5d4, 0x209d374b, 0x03f33835, 0x0178d212, 0x2011c462, 0xc8d0de56, + 0x4a605a09, 0x850e9d26, 0xeb4c0ce3, 0xcefbeb28, 0x05dfa80d, 0x6746ecbe, 0xfbc09d3d, 0x874d6235, 0x8c1b90b5, + 0x241da0a0, 0x44391fa9, 0x5ee9e531, 0xa3bda881, 0x50b7a875, 0x9ed444b8, 0xad8b209c, 0x3b18f372, 0x8c738565, + 0x4d9b59e3, 0xa940651d, 0x4649604b, 0x2a842a17, 0xe44c8810, 0x9f8cce9f, 0x9a8589c2, 0x1319fde5, 0x1f13ca75, + 0x1650a6c2, 0x6d147823, 0xbab0d4b7, 0xc2c50f4e, 0xa82cfe26, 0xd7ab2755, 0x1f83311c, 0xa7717ece, 0x9d2da803, + 0xbf83f1a4, 0x7f35d12f, 0xe2f05b8e, 0x458242d8, 0x0695b162, 0xef12b349, 0x66fbc114, 0x5906a71e, 0x6a3a49e6, + 0x19a65780, 0x14a1d541, 0x6240bc3c, 0x562c8ea4, 0x481c313a, 0x8e0eb416, 0xf0c13e3c, 0x8ef975b7, 0x9d90b557, + 0x6bf20ed8, 0xc57058a7, 0xa5d27ceb, 0x7feeaf61, 0x3b5e6e12, 0x31727ff2, 0x8f62dbf3, 0xa685657b, 0x22bb8e97, + 0x9244a792, 0x85974138, 0xf7702b8d, 0x80bb945f, 0x2a34e810, 0x16b1cd91, 0x98a19c4c, 0x6cfd58f4, 0xbfd9ff86, + 0x2920b0a9, 0x6295bc40, 0x8d56be55, 0xc70ffb9d, 0x52001dd5, 0x41fde338, 0xd28ac441, 0xf567d542, 0x1e4b8d71, + 0x00e4ce94, 0xcd12e22e, 0xc04bed80, 0x6c8b50a3, 0x8f425362, 0xafa819c6, 0x5d99526f, 0x97507877, 0x902e6e2d, + 0x10cf7091, 0xf09b19a8, 0x9c43ba7b, 0xf290e6a1, 0xfc62054b, 0xeb85a5da, 0x9244a6c8, 0x961c3339, 0x685538b1, + 0xaa49913d, 0xc250f643, 0xac0cdd3c, 0x220c26df, 0xd3dbbbc7, 0x8b9bd927, 0xed58f0c6, 0xf1f8045a, 0xe13380f7, + 0xa1246b04, 0x4e5fa7eb, 0xe2430a57, 0xee8a3075, 0x10445e8a, 0x18cef242, 0x0cf70b7d, 0xd10206ae, 0x7e2597d6, + 0xa12c9d6b, 0x028dc8f5, 0xe42c320b, 0xc1efc2b5, 0xae4abc3b, 0xaaa9f9c8, 0x509d0776, 0x2cb41148, 0xa2400f97, + 0x2541421b, 0x2b949a50, 0x60e1fa2d, 0x4efedd28, 0x1d0cf7a6, 0xf3ef9a54, 0xc89c32c8, 0xbd652d6d, 0x8e788d80, + 0x9a2ed6b5, 0x113ab17c, 0x93b8931b, 0xa47b46fe, 0x0d4c115a, 0x91dedc9b, 0xc3d57b98, 0xb1d5664e, 0xf8b479ae, + 0xa6041b67, 0xc3b567c4, 0x7f93ce49, 0x8baa7eea, 0xf8485993, 0x17675dd4, 0xe472419c, 0xf59e1a18, 0x75ec1552, + 0x989576fe, 0xa686b795, 0x2cfd2ab7, 0xdcf6379b, 0x9d8112a8, 0x2f005587, 0x1fa5427f, 0x0890ca24, 0x6ac483b4, + 0x3c460b5f, 0xa4f7fbc7, 0xf8a9ddf3, 0x387aae50, 0xe2ae7656, 0xb47b011d, 0x0abb9193, 0x556a155d, 0xc1f630eb, + 0xb3fa713e, 0x0bdac8c3, 0x36718bff, 0x35e8419d, 0x7f2e0e44, 0xb879e4f6, 0xbddccce5, 0x9cb8728a, 0x64f42385, + 0xe7b52f16, 0x3eff565e, 0x5b76b7b3, 0x5fe6db9e, 0x9ecf08dc, 0x8e7bf9df, 0x826f52bb, 0x0d60f28d, 0x7ca53a04, + 0x08236fe5, 0x548d90a9, 0x5d3696c1, 0xca5452ae, 0xa7a82707, 0x91452d8e, 0x00f707ca, 0xbf66e40a, 0x90574a08, + 0x001922f9, 0x924a99f7, 0x86c8eb67, 0x062129c8, 0x73dbbecd, 0x14bbc6c8, 0x0a9bbb69, 0x6a37ca9b, 0xba3a092f, + 0x62956e5a, 0xd273b513, 0xf484d694, 0xd1bc0a26, 0x33b3cedc, 0xaa002a18, 0xbaa0c329, 0x941f9974, 0xcebb6d55, + 0x7f5e8fa9, 0x0b6963e8, 0x8aa9e6a3, 0x828c0dd1, 0x12321b13, 0xa3382c67, 0x89375b05, 0x50604f1c, 0x49528cee, + 0x21adf9e7, 0x603d94a6, 0xedf8f453, 0x3ea2fcee, 0xcbcd8961, 0xe3a262ca, 0xc04dd1de, 0xe7f958e8, 0xe3975aa3, + 0x130e3350, 0xb7e521de, 0x81da5d83, 0xe38e55c4, 0x42f9cb5c, 0x3fd05997, 0xef87198e, 0xa2ead839, 0x5c21e1a7, + 0xbf8275d3, 0xf88cd343, 0xb55a1c68, 0x2a2c62f3, 0xcfc827ec, 0xf648d67b, 0x6027d8bf, 0xc4c2a85f, 0x62a79771, + 0x6016e168, 0x8e903ed0, 0xae62f0ca, 0xade06be9, 0xb6fa0b89, 0x0dd5d66c, 0x202ec05c, 0xcf9cdacf, 0x087c2911, + 0x6c55c669, 0xc9e2de32, 0x5e5f4851, 0x22cbbfb7, 0x91901b02, 0x63a06dec, 0x29d8ab4f, 0x1e641288, 0x835581ed, + 0xa6d293e8, 0x3ce7de58, 0xcc35d6e6, 0x7ce7f218, 0x8e7543b8, 0x52001724, 0x3370db5e, 0xe7de4f2a, 0x00de7cfb, + 0xfec11df9, 0x6ad0b8df, 0x57442f83, 0x421bda93, 0x3e62571d, 0x1efeb4aa, 0xfdb8edab, 0xd269a93c, 0xa935a7d8, + 0xf6934ab2, 0x474c8d34, 0x04fa4751, 0x17ac1286, 0x8faf0d67, 0x270d500f, 0xa601dc1a, 0x7ace146b, 0xe3e6bfcb, + 0xa29cc42f, 0xfdb82472, 0xfee652e3, 0xa4e4c7fd, 0x91d75fe6, 0xab8baab1, 0xb3a51e4f, 0x07353a3d, 0x92e3b257, + 0xe7737dc2, 0xfba948e3, 0x2667379a, 0xaed2008b, 0xc6c485c9, 0x3dea0291, 0xb27c624b, 0x1265f04d, 0x7c53a5bf, + 0x781d0e27, 0xe05081c0, 0x8a7d60f5, 0x87b4497d, 0x75684c8d, 0x331a9e94, 0x6dc4d90a, 0x4a9ad248, 0xc430067a, + 0x4da7c7b5, 0x74cbee2f, 0xd70117bb, 0x3ca0bfda, 0xc6ba1bb8, 0xe22903f9, 0x8d0e6347, 0xe2bc6557, 0xc0dc5806, + 0xd722b793, 0xa1b5efeb, 0x1176a2be, 0xd8dce7f7, 0xe0630962, 0x1a3972c8, 0x3ce48cfa, 0x2f58437a, 0xc1df23dc, + 0x4eb14a23, 0x581046d1, 0x6bca5842, 0x0f274783, 0x8b0f0a61, 0xdbab7c47, 0x2a217351, 0x85f98334, 0x6cf0e3ad, + 0x03b27948, 0x202e45b0, 0x3f17e552, 0xed9d26e4, 0xb05d64cf, 0x36729714, 0x216c6fd0, 0x77c9c4f8, 0x80b664c8, + 0x25b502da, 0x5a26cf17, 0xb83afca3, 0x500937e2, 0xb380f2b8, 0x062360b6, 0x8477f313, 0x086a712a, 0xf24e6c2a, + 0x9de2664d, 0xf5f66442, 0xb3ebff8a, 0x8fab8041, 0xf0656b6d, 0x3116bafb, 0xe1729ed7, 0xc43c9923, 0x96903da1, + 0x4656433c, 0xdd07bdcd, 0x54e0d174, 0x66d2c84c, 0xd05a4757, 0xf4a49f1f, 0x322828ac, 0xac747805, 0x21d67968, + 0x20f1c0ed, 0x9a77e36b, 0xa08f0394, 0x4cfe743e, 0x52df135a, 0xc58dbaa7, 0x42c82d12, 0xfafbde23, 0x56ff5b92, + 0x5da40d28, 0x917128bb, 0x85e8bb54, 0x650a9a28, 0x796fabfe, 0x068ca6ba, 0x52e64205, 0xb5f50432, 0x123fc94e, + 0x54f3154f, 0xc033c71a, 0xa5927426, 0x4dbb0db9, 0xd47b1e7d, 0xa353b605, 0x94aaa996, 0x15ba75d9, 0xd9e7d603, + 0x7f0773be, 0x82bc4c73, 0xa981ec0e, 0xc7f25b15, 0x3e370aa3, 0xfe97775b, 0x86d10134, 0xfbaa7ff1, 0x971c87b8, + 0x52b0db39, 0x38a25971, 0xd9b13564, 0x2578fc47, 0x8068ece0, 0x60a14ce7, 0x1365e025, 0x15c895b6, 0x0df87889, + 0x68d99118, 0x6b5fef7a, 0x603f4eed, 0x87e26338, 0x5698bf12, 0x2b808347, 0xeb0f4657, 0xc7728d1b, 0xffbf1620, + 0xc7bd9e92, 0xc656b42a, 0x56061729, 0x8232d6f3, 0x416ccd13, 0x304b1f7c, 0xaa92590e, 0xba6aa49f, 0x526804de, + 0xae14f2de, 0xe930abef, 0x091d51f8, 0x072dda2c, 0x7a525463, 0x99bb94cd, 0xf758fc8a, 0x7950aad4, 0xa55d2ff0, + 0xd88133d1, 0x775f26d8, 0x23f3bcbe, 0xa5fd1c4a, 0x745ed83c, 0x327c39af, 0xbcb4bbcc, 0x1f76285a, 0x730ba40c, + 0x98409a71, 0xb03ec802, 0xb192760c, 0xbe78cd65, 0x3afc5751, 0x2e0dd937, 0x69642d24, 0x1b9143fb, 0xe82ff8d1, + 0x3e5e7d7e, 0x5d1426ca, 0x6b51334e, 0x37e6694f, 0x5493496a, 0x2e00c1e5, 0x500a81dd, 0x8576a65b, 0x9c858b7e, + 0x0a2f60fb, 0x8295ad5e, 0x3c85c517, 0x62fdea87, 0x7b8728dd, 0xcbe466ec, 0x72cca803, 0xfd3fa6d6, 0x0d65ef70, + 0xb5bd47ab, 0xa20767f9, 0xcc1afbf5, 0xb6d872ce, 0x5500ce2b, 0xa0d37e15, 0x8449a9da, 0x663a6917, 0xf2acbc9f, + 0x8dc35e60, 0x48bece69, 0x0f4bc104, 0xc92399ef, 0x794ec4aa, 0x87920c62, 0x3aa72f4e, 0x3da09042, 0x70737f97, + 0x61392cd5, 0x6a08a7eb, 0x91b24f2d, 0x4c9b17e6, 0x91884bcc, 0xdb2dc676, 0xf72455dc, 0x00112ded, 0x5b22efb7, + 0xa1091da1, 0xf8dbf24b, 0x7c050165, 0xc17f46d6, 0x049d5aad, 0x69776fa1, 0x0f406928, 0x7d5ee1a3, 0x10674d6c, + 0x8a36a9dd, 0xdfa11ea1, 0xcd66273f, 0x4d3e0dba, 0x2326be10, 0x8085b7eb, 0x86a5815a, 0xd6a9c078, 0x1dd6862a, + 0x96e28abc, 0x5997e120, 0x0c7007d9, 0x20e8d00d, 0x4b62fbe9, 0x50db5e9d, 0x4293ec2f, 0xc7f5a5dc, 0x30b62657, + 0x06562d55, 0x34d8345a, 0xd9ca6047, 0x202b2d18, 0xb7410d54, 0xd35590d4, 0xd9624e4f, 0x566086d9, 0x0ba98c0d, + 0x2d257cee, 0xdcbe826e, 0x3d513172, 0x87d29463, 0x25fb0816, 0xc51ed43c, 0x0213fc75, 0x0b95c35a, 0x678f9b00, + 0x5be955ed, 0x5b6098f2, 0xdafd1e44, 0x59e46644, 0x6631c795, 0x50f1cb7f, 0x92ae3940, 0xd4a0c285, 0x331496de, + 0x25bd034a, 0x3403aa9a, 0xdab1f36b, 0x86244de3, 0x185479ef, 0x6c25690f, 0xff4fd030, 0xc6932604, 0x9413d0c2, + 0x8af7de85, 0xaa38f331, 0x92ba15d6, 0xa099289f, 0x4cc0d1bc, 0xf202c735, 0xf0fd83db, 0x249c8297, 0x1bc35380, + 0xdf7c5abc, 0x6c2b938a, 0x48e73367, 0xb41d631c, 0xe5e28bd9, 0xa32b69b9, 0x93455c9f, 0x28ffa910, 0x61a2723c, + 0x5c21874f, 0xc1fcd3f2, 0xc93e46d1, 0xba2f23e6, 0x93069692, 0x233feb4d, 0x93fe10ec, 0x93b4dbd8, 0xcb13fcee, + 0xd23a5561, 0x2040fc3f, 0xf2965d2b, 0x0daa85e6, 0x8e6d5367, 0x591f60f1, 0xa2a6e885, 0xccf8f351, 0xd5537b8a, + 0x73115ca0, 0x4dc37ad7, 0xc407dfeb, 0x2ce44337, 0x2e399f8c, 0x17b8600b, 0xca751762, 0xeef04ebe, 0x8de2d0f3, + 0x68dc3749, 0xf15cb787, 0xaa0a7d60, 0xe04c8111, 0x1857e9cb, 0xb3cef2a6, 0x788c5712, 0x860aee8a, 0x6cf9eaaa, + 0xcdc175a9, 0x89023422, 0xac154f70, 0xbb7cf95e, 0x91df0065, 0x7fbbb3fb, 0xa909e9fa, 0xdc255354, 0xe9e813fd, + 0x7b4ccba6, 0x88cf4673, 0x9ffeaf5d, 0xb4c278a9, 0x11499716, 0x20ef76e1, 0xea7ecacb, 0x91c9a531, 0x38564ff7, + 0x47801c18, 0x0b8efe6b, 0xeb9c4cb8, 0x7dec3153, 0x8fdb61da, 0x92297af8, 0x234a6206, 0xed8cee8b, 0xd7b486e2, + 0x42d7f907, 0x758cd5f8, 0x38203642, 0x3f532cf9, 0xdff762da, 0x9f8de753, 0x9591b254, 0xe0489800, 0x4f7afcd5, + 0x24b333ea, 0xcc4ba603, 0x61df97e2, 0x489efd76, 0x911cb2e6, 0x5c318445, 0xe2300016, 0xd2aced5b, 0x8ff2a279, + 0x97327977, 0x5e9900e3, 0xd8f78a51, 0x2f803376, 0x1e34f69c, 0xcccd8e28, 0xf6054c69, 0x0f799374, 0x164ad9d3, + 0xb84d7609, 0xd79412e9, 0x79a66e79, 0xf5e182f0, 0xf61f8802, 0x2133a1bb, 0x86716e15, 0x97a362f5, 0xba38f4d1, + 0x45d08d2b, 0x2dc575de, 0xdb5a5685, 0x2df310cd, 0x206817e8, 0xc235d476, 0x31fe3c2f, 0x1ec63d06, 0xb8dbb83d, + 0x7d1da0e3, 0xdc66bb4f, 0x1a3d8261, 0xb0f4609b, 0x170e887c, 0x75e38f69, 0x85e8eb84, 0xc4561588, 0x3e5b1e8c, + 0xc569e183, 0xf9518837, 0xddd3252e, 0x2b69d3e6, 0xbbb800b7, 0x7f638447, 0x7391e512, 0x095ac164, 0x0a37022e, + 0x6dbbd988, 0xce766853, 0xbcae3c71, 0x7c5aef14, 0x0a4dec81, 0xbe319e6b, 0x70e93b57, 0xecaa19b2, 0xe92515a8, + 0x84ad2590, 0x8be921d0, 0x048b33fc, 0x11e07ed2, 0x7d2e317a, 0x9598dca6, 0x9565a3db, 0x9327213a, 0x9c928bb5, + 0x55ab369d, 0x6cb26159, 0x000403f1, 0x36f44523, 0x5f504ed9, 0x23fc15ce, 0xf4d0ac67, 0xc8c77bdf, 0xd19557d0, + 0xd258ba14, 0x86c21239, 0xafb457aa, 0x199c8bee, 0x8c561ace, 0xa1c418a7, 0x86d99486, 0xef27830c, 0x82a1af69, + 0xdafafb65, 0xae0c1f86, 0x741dcc95, 0xa627958b, 0x9bbbf2dc, 0x42e404f6, 0x3239059b, 0x8edc3c2d, 0x69595fef, + 0x6ebe4fb7, 0xf42d178d, 0x1f50ed8a, 0x3c6539a6, 0x0915dc53, 0x3fbf596c, 0xd580bdc0, 0x2c471fed, 0x35ae81ae, + 0xf6bc92b9, 0xd8280705, 0xb7dbd1e4, 0x09dff5cd, 0xb8328cf1, 0x13a68c38, 0x4558531d, 0x9569fdb0, 0x2c4110dd, + 0xd646639e, 0xadfc682f, 0x4a4677e4, 0xa6ed83af, 0x93cdc02e, 0xfb9193e6, 0x90d91551, 0x42f61f5f, 0x08b443a1, + 0x93371dc6, 0xef96979d, 0x944ae7a6, 0x533dfc02, 0x48db7b54, 0x553b4f34, 0x9fa15cd3, 0xa0a06bc3, 0xece437bc, + 0x02a1bc17, 0xad80268b, 0xec24b4eb, 0xa8a36d2f, 0x21b57de1, 0x1e67865f, 0x9d465739, 0xc90d166a, 0x94f0ff08, + 0xf4cb2291, 0x9a0098ee, 0xd6cb767d, 0x48e4cc0e, 0xd9b5ec8d, 0x08b5465f, 0x6922dd21, 0x66379a16, 0x2f52aa59, + 0x1a4b4195, 0x403d1277, 0xcaa92812, 0xa6544a0d, 0x563c9958, 0xc72880c9, 0x48ec7cc4, 0xd3e04e42, 0x8b674f81, + 0x6430c326, 0xea0a140c, 0xbb5a2c9d, 0x223d5916, 0x27fc533c, 0x260c87b8, 0x27410586, 0xbedc4c92, 0x82b8b661, + 0x1900d92c, 0x1cae550d, 0x271f2b32, 0x58020629, 0xd28a2adc, 0x93371741, 0x3b41c570, 0xd1de935d, 0x1a447085, + 0xf8fb1c54, 0xba890862, 0xd8f67915, 0xee13a722, 0x449e2253, 0xd6d771e0, 0x63cc8f70, 0x31f9b3ab, 0xa6e60c7a, + 0xe18c9c4b, 0x93026b82, 0xbcb8081d, 0xcfb65252, 0xa13706e0, 0xcb2e549e, 0x97c814e0, 0xd568690f, 0x8b75dad6, + 0x6f4437c9, 0x67d5287e, 0xd3ae48bd, 0xb9ba74bb, 0xcd9920db, 0xa159847b, 0x1abba2a7, 0xb16cfe40, 0xb4d3864e, + 0xb5a851a4, 0x48b6a699, 0x03ddee8c, 0x21be9349, 0x2b526ace, 0x350ed81c, 0x01ed63c6, 0x00518b70, 0x4a80aa72, + 0x259b06a6, 0x8763f8e9, 0x54712638, 0x7dbbc4a9, 0x9df29a1d, 0xacc30ce7, 0xb8120313, 0x3fd1d3f2, 0x0f4797b2, + 0xdd212e23, 0x3aa38ee6, 0x2537a2ef, 0x41b64ae9, 0x360e8040, 0x7ea21584, 0x56cb8260, 0x2a03b9a9, 0x2a5b7df1, + 0x88b25cfc, 0x3dadd4ed, 0x3ab16aba, 0xfc87b153, 0xbeca5f8d, 0x3a7bfe8f, 0x039de011, 0x39e1bd18, 0x682a0d90, + 0x8804c99c, 0x0af59265, 0xcd9f2a7a, 0x2111820f, 0x14a90b35, 0x0b05f75a, 0xb2676183, 0xec589d07, 0x02e2f675, + 0xb03923e7, 0x370707c1, 0x88882c3e, 0x5e75164a, 0xd5ea866e, 0xed0f9ee7, 0xe79a5e63, 0x63e44e74, 0x11a2d110, + 0x5590e3af, 0x1165fc13, 0xaa3e2fab, 0x7ff5089e, 0x179b529a, 0x3179ee91, 0xdbfebe6f, 0x7550ad5f, 0xf0700da7, + 0x94dbf47f, 0x0230f67e, 0xb50478be, 0xc3502edb, 0xbe30cec0, 0xe06f86d2, 0x3396792c, 0x12647d46, 0xa5d05fca, + 0x3543f339, 0x962fc905, 0x95bcf180, 0x08b441e2, 0x7b57ee3a, 0x616f3b73, 0x2a9d5308, 0x8fa75091, 0xd093a54e, + 0xa4be7923, 0xe5312011, 0x924a1352, 0x4aa99a9c, 0xd3ff81c7, 0x023f484a, 0x530187e7, 0x9d0246aa, 0xdcd7a4b4, + 0x6c5d80ac, 0x24c15fc8, 0x7272d96e, 0x5b5a4f64, 0xa9f416cd, 0xbc8ed6dc, 0x6833e0e8, 0xca0bab76, 0xeeb3bc60, + 0xdcdd0bd3, 0x22275f7d, 0xf2a8a6a5, 0xbc88462e, 0x6f4ef7f1, 0xf02ca895, 0x2c8b8990, 0x3195f153, 0x179ecaed, + 0xc420c7f6, 0xae35cdea, 0x0d5e4b56, 0x79ac7711, 0x573c0fb0, 0x084b1a2d, 0xa22528ec, 0x45b3aa7b, 0xd5487182, + 0x29dae54d, 0xada9c4b2, 0x25cac571, 0x61925906, 0x1caf9f1b, 0x46d46e05, 0xb1b6a775, 0xe6de96e2, 0x26f49aa5, + 0x52f4f210, 0xb1a0cc05, 0xe4ac95d2, 0x9d147e51, 0x437fecaa, 0xc3fe8c63, 0x064f6bc4, 0xb9d820ef, 0x931f141b, + 0x21d4f6e6, 0xac361392, 0x65d39ceb, 0x207e6f71, 0x24eb97f5, 0x741f0c79, 0x642fdbba, 0x70f4ebd9, 0x57a98d3c, + 0xb5ef06e3, 0xe2d57b49, 0x781a7367, 0x4aa06e71, 0x56fd3ee2, 0xa2b59931, 0x365116a0, 0xa3319448, 0x4059dafd, + 0xff8a2cbf, 0x0b8bfe6d, 0x65342f9d, 0x780bb252, 0x7a154a00, 0xae6ef380, 0x87697686, 0x01ad6d3d, 0x05926888, + 0xbf6ee225, 0x265f84b0, 0x12306a19, 0xecca09d7, 0x74520cc1, 0x563febc3, 0xa63c7bb3, 0x9f6544e2, 0x12b8b600, + 0xfe732cd3, 0xdd26d7f8, 0x83265586, 0x84df6807, 0xbff87670, 0xd8794e4d, 0xbc19f150, 0x3f8e61ac, 0x49fdceec, + 0x902b2ef6, 0x24c38e4a, 0x101dd0be, 0x99cd6c13, 0x481fc741, 0x82183ef7, 0x35cb76b8, 0x1fd1a656, 0xb5e46bae, + 0xbb89f5f4, 0x2f2b3911, 0x8a432c62, 0x9cbd050b, 0xfbc9066a, 0x2f38d4ba, 0x84cd912b, 0xa4d84fce, 0x2cf05ff0, + 0x829687bd, 0x899e8ae5, 0x27475cf3, 0xcd1758dc, 0xce35ecf5, 0xa7ef4c62, 0x86f06007, 0x2b8605d7, 0xcf6c7b57, + 0xe22d05d3, 0xe80a1e3d, 0x1911bd49, 0xb56ab843, 0xda834198, 0x7497e924, 0x99abbaad, 0x059cbaa2, 0x6d0367aa, + 0xce047282, 0x0dd67cd3, 0x432192a2, 0xeb52bcb8, 0x54e2c65d, 0xc743bdee, 0x95b2359b, 0xfa47c24d, 0x1322072a, + 0xc39a1646, 0x61009aee, 0x478aa97b, 0x06c04542, 0xbd5c0151, 0x7c8cc9b3, 0xf6fa3863, 0x07d56680, 0x1edbcd7d, + 0x1d6232be, 0xcedf46c5, 0x34249f0c, 0xd78d9cf0, 0xb45e26e5, 0x494b5140, 0xac08bb9d, 0x3c25d8fe, 0xcaa838c7, + 0x07703e78, 0xf3a23eb4, 0x50028c28, 0x3711e5e5, 0x2ae5e22a, 0x5a040c04, 0x1bddeb1e, 0x5ecfe949, 0x8c1ecc73, + 0xc4c4b291, 0x2ce6c4c2, 0xf63a7992, 0x32bd6fcb, 0xf3a4f1ae, 0xce78225d, 0xa6b13fa6, 0x2fbce716, 0xd7444e8e, + 0x11e8f5d1, 0x3c6a1020, 0x084f0c4a, 0x3e06e786, 0x94fdb81b, 0x2036b031, 0x0c686afa, 0x0d4037a3, 0xc8948656, + 0x5057b039, 0xffb9e6e0, 0xac681fc1, 0xb2ed9467, 0x5bb66ba0, 0xade77074, 0xd3f4c0ad, 0x5df6ce4e, 0x110a8b64, + 0x810d4d72, 0x5ae78216, 0xf8055489, 0xa6581b04, 0x42548116, 0xbe56fc11, 0x4a7805fc, 0xc542a96c, 0x5947ea7a, + 0xdf1114e5, 0x1a9212cf, 0x01b1b2ec, 0xd12f0eb7, 0x46c0771b, 0x30e38601, 0xd8161954, 0x408bc929, 0xcd809f78, + 0xd29ae77f, 0xa9b926b6, 0x34043551, 0xd2fb5680, 0x50be12a2, 0x65451b50, 0x82db6a16, 0x5a020499, 0xfa9b9f88, + 0x0b8627ea, 0xd8b5d8b1, 0xa5529cd2, 0xa0127182, 0xc56ab717, 0x1cf730eb, 0x65419de4, 0xc1838767, 0xc8a85ff6, + 0xc2b5d569, 0x48346010, 0xeee24b63, 0x5b6a6b76, 0x414d17bc, 0x9e11b76d, 0x2d2570f6, 0x26a23051, 0xe0852a6c, + 0xfff5a07a, 0x8811161c, 0x1a075814, 0xfbc480ce, 0x9e3d7b70, 0x898d7192, 0x9334e0ca, 0x85de6f33, 0xb16d5a51, + 0x422418c1, 0x15220d3b, 0x1d5c7552, 0x456d9187, 0xde232186, 0xe1a8f833, 0x595e5bb3, 0xb8c36f2d, 0x4f987a8d, + 0xbe49ffb8, 0xab657853, 0x40a0c522, 0xf7710476, 0xf859a458, 0x491e7e8d, 0x1b9d4f75, 0xb5c9affd, 0x47c51e4d, + 0x9b3a7405, 0x132572dd, 0xda5d006a, 0x2bc721c5, 0x675a11ce, 0xf2c7ec9e, 0x44919b2e, 0x626a9396, 0x9fd165ed, + 0x5b265cea, 0x26cce398, 0x952ca1fa, 0x86be4d62, 0x751f350f, 0x6a6816ad, 0xb99d2576, 0x2f3214a6, 0x9a150127, + 0x1112c340, 0x0b925422, 0xafdfc749, 0x804c7ef2, 0xea06f047, 0xb2e2a76a, 0x3a7e9625, 0xb9f967be, 0xac44a38d, + 0xee5774aa, 0x049ad3ce, 0xd19a60e4, 0x89e7577b, 0x06e4cfc0, 0x5024a761, 0x6cffbed6, 0x8a47bc4c, 0x00d33a02, + 0x46e39ad3, 0x82b267a2, 0xf35e6f09, 0xdaeeb428, 0xfc46ee2d, 0x9b200b4c, 0x95a2274c, 0x9d53abb6, 0x0fad0e9b, + 0x408e5a83, 0x90a374ba, 0xd84bdcdd, 0xde97dcf6, 0x6a4ab283, 0xfc3f4337, 0xb9c17af5, 0x4084870c, 0xba5e3aa2, + 0x0663801e, 0xff6a506e, 0x88b4c458, 0x6da3a9f5, 0x5d37be6e, 0x684efc43, 0xf1cc6a2d, 0xeaf0c28e, 0xf2b5e145, + 0x788e7680, 0x36973c9e, 0xa4e2768b, 0xdf98ef55, 0x95d04b68, 0x48ae2d49, 0xe3342c4d, 0xaf94c102, 0x63884388, + 0x5fdd623b, 0x0dff7067, 0xa5595ba0, 0xa3217c54, 0x77068320, 0x6710279f, 0xbcedc90f, 0x774e5c10, 0x51f57570, + 0x34a44355, 0xc3d786bb, 0xb10b88eb, 0xa0622124, 0xfb3e4514, 0xcaebfcef, 0x4ee7accd, 0xde30e974, 0x3cd1e648, + 0x93eee67b, 0xf0b8042e, 0x18f5e188, 0x7b21094a, 0x6587fc96, 0x6952aae6, 0x4ce7bcfb, 0x55c7b693, 0x1ff35b4c, + 0x320c1223, 0xe0a1cc8a, 0xb58afd7a, 0x237244f4, 0x9e9862ac, 0x275294fb, 0xaee39fda, 0x7486e721, 0xfd05140c, + 0x1b160fc3, 0x781eeadf, 0x514fbb57, 0x48bdd246, 0x7220145f, 0x74c224b0, 0xeea9db1a, 0x42c7a5c2, 0xde5473df, + 0x79d441f8, 0x8dc4e95e, 0x2b6cb258, 0x5e7ea791, 0x889206b2, 0x32b4a9c8, 0x1773aefc, 0x9bfa06cc, 0x8058374a, + 0x710fb5a2, 0xdd7e5f50, 0x595b45a1, 0x63831d0c, 0x3c5eab6d, 0x1e643b4a, 0xe7b05527, 0x4ce19761, 0x6bd9ec95, + 0xd5cf03a2, 0x2da61dc7, 0x40903b6e, 0x3457c802, 0x4be7540a, 0x2d385d6f, 0xe190e82e, 0xc6066c7b, 0xbd74c362, + 0x01bfc7a8, 0xdc9bfdf1, 0x5ceff0bf, 0x255d62bd, 0x9f7e71eb, 0xb29f1677, 0xbe261432, 0xe472c406, 0xf810d816, + 0x74b90c76, 0x3e3cddb1, 0xa7321d66, 0x1059da4b, 0x27353b1d, 0x084c4605, 0x4ddd1b3e, 0x6e0c0fe6, 0x29e7fe4b, + 0x051f14c6, 0xbbac03e8, 0xbcd07065, 0x4d6b6248, 0x409f8270, 0x9150fb5b, 0x338d9597, 0xeeb954fe, 0xc764666c, + 0x6b74fd87, 0xcce418d8, 0xc5cbcf8d, 0xafbb0b46, 0x2c5ffc17, 0xd54d5177, 0x794304a5, 0x9a48d736, 0x86b34679, + 0x431c2a15, 0x9aef854d, 0xd6544840, 0xa197ffa6, 0x7b70d13f, 0xe0bf3701, 0xeb5674c9, 0x8c4070bd, 0xbad89407, + 0x4de56223, 0x50b8ece0, 0x315351cc, 0xe1146304, 0x6474a828, 0x76be4e2e, 0xdd8566f9, 0x2afad76e, 0x6bf8b426, + 0x327d9e6b, 0x92375249, 0xaad9e218, 0xe50d429f, 0xdc4adb54, 0x2e6ddd76, 0x8960e9af, 0x4a24afb3, 0xcc4a5adb, + 0x1cdea009, 0x23070d5c, 0x761e4271, 0xd58185d3, 0xa405f8ac, 0x7c276412, 0x3f8bfc53, 0x233b3d14, 0x15c59283, + 0xa2b36815, 0x355ec54f, 0x2a0886e0, 0x2791ef9e, 0x317a327c, 0xb467950e, 0x8b4bc99c, 0x5ebd0767, 0x30282c67, + 0x37422a8e, 0x1c1a7389, 0x2c1fc0bd, 0x242be654, 0x1366bf36, 0x72e8399a, 0x57675864, 0x36aa608c, 0x06b3e973, + 0x855b3063, 0x2cc25698, 0x30b01aef, 0x028f9ff8, 0x9f499388, 0x1c211376, 0xb9d05aae, 0x3285d55e, 0x7194a5c5, + 0xa59e97bf, 0xc8b95d6f, 0x4fdc53ec, 0xa310d354, 0xf8f77408, 0x4692fc1e, 0xc255a69c, 0x5cdc9711, 0xff7af327, + 0x944ed487, 0x0ea3cb75, 0xd11eb3fc, 0xea33dbc1, 0x3a4e1049, 0x0f29ef9b, 0x2f252dd6, 0x7961b716, 0x2d52610e, + 0xa8dbded9, 0xa8458833, 0x2d6f6300, 0xb4dbd718, 0xe26d05f3, 0xddb62c95, 0x4f09d53d, 0xcd4ef484, 0xb4902169, + 0x398963a1, 0x8039d0e3, 0xa699ddbb, 0x9a4c7d61, 0xe9cb7f0d, 0xaf2aeca2, 0xee258866, 0x4748c32a, 0x02868672, + 0xe73ccf6c, 0x43414473, 0x17ed8d2e, 0xcc2137ac, 0x56d97dd0, 0xc334fd9d, 0x28ab3dde, 0x32a5e8d6, 0x40c7b07b, + 0x6905393c, 0xaad86b86, 0x84ff3b56, 0xbcb66b62, 0x1f8d3561, 0xf2d75a0e, 0xb90447c1, 0x08911881, 0xd7519cc7, + 0xead5ca45, 0x3314ef86, 0xdeacf62f, 0xbdd0cfa7, 0x66e43c28, 0x12d5051c, 0xade5804b, 0x5276c587, 0x039e8846, + 0x0fd5f96c, 0x648a584e, 0x8fa5a2a0, 0xfe7ab35f, 0x3b15c7cf, 0x7c37cc2f, 0x2df17f56, 0x08f0ae17, 0x76e33606, + 0x832beff3, 0xe4be8344, 0xcbe48e8b, 0x4bc458e4, 0x7a8d463d, 0x192eec15, 0xac520d17, 0x251a17f2, 0x72bfdc5a, + 0xfe77d3f9, 0x7ace7dbc, 0xd6b8b804, 0x42797bcf, 0x7d44da2c, 0xe6d29184, 0xe2f1b47e, 0x7929a8d7, 0x8bcdab5e, + 0x0415d7d2, 0xd0e1cc58, 0xeb48f3e0, 0xa6a14e26, 0x299d2881, 0x5cdd9f0c, 0xb95e07e3, 0x480cd471, 0x48f5a9d5, + 0x88608b57, 0x9b608746, 0x2c6047eb, 0x07eb6c0f, 0x438fa2e3, 0x5be69b33, 0x72b2b2ed, 0x310ed823, 0x0f821ed3, + 0xd219c9e5, 0x855c0a18, 0x7af0bdc9, 0x8334849d, 0x8d6d440a, 0x66342c95, 0xb5b0bc8d, 0x6d609005, 0x2b92b97d, + 0x6a4f5e28, 0xa629e728, 0x6af64954, 0xae737e56, 0x5577b158, 0x2c3b9ac8, 0xa1791f69, 0x7cc6be57, 0xf9b86b2c, + 0x05569087, 0xf941c582, 0xcdd05f76, 0x3475b09e, 0x9315f1c9, 0xbfb2ddb1, 0x27eb8ef2, 0xdf4afe19, 0x71a46fd2, + 0x0b4c648b, 0x89fa97cd, 0x09908bee, 0xb6826440, 0xb5fd0660, 0xb2bb5489, 0x7ddb5eb1, 0xd8192fbf, 0x99b6937c, + 0x0d13699f, 0x266e826a, 0xc3e74434, 0x9220a006, 0x558a93f2, 0x150d9202, 0x190943b3, 0x1dafcf11, 0x89f41eeb, + 0x5dcf61fb, 0x1974e674, 0x69f10a08, 0x9af138bb, 0x6f2e8fa9, 0xcb6f110f, 0xc3752f51, 0x1fbc3001, 0xeb6aa4a0, + 0xa3bad8b1, 0xa465c0c4, 0x6bde35c2, 0xbb77f0fb, 0xc55c0350, 0xc5224198, 0xd63cd846, 0xf07cc6e2, 0xa388d467, + 0xf02cd48c, 0x587a159e, 0xb4268b1c, 0x6995d86a, 0x96a64ee9, 0x6dbb22bb, 0x9a0636cf, 0x26ee3225, 0xa16732f7, + 0x88b0e918, 0xd8aade59, 0x856762fb, 0x5f6e63ac, 0x92e233ff, 0x0b531ed3, 0x9a8cfa6a, 0x53b3be76, 0xe1c80acc, + 0x75b82f2e, 0xb1adaf98, 0xe76018c8, 0x920a94b6, 0x1aee0b48, 0xa951a8e9, 0xe5fc868d, 0x072f55c6, 0x23ae35a3, + 0x3512d9b6, 0x8ec5dab7, 0xccf92ee9, 0xd02bb9a4, 0x0f1608cf, 0x8db82f1d, 0x053728c0, 0xed7abf92, 0xa13e3144, + 0xe558fc04, 0x3df2b309, 0xe792e9ca, 0xac985393, 0x0afd8dff, 0x86d56f65, 0xaad51823, 0x2ef669e4, 0x012cdbe8, + 0x719dadc4, 0x474c4326, 0x648a7de5, 0x763548e9, 0xe2273c34, 0x58987641, 0xcec0ca3f, 0xf2cba75d, 0xd637b1d5, + 0xd58e8833, 0x08dcc16c, 0x3fdf11f4, 0x76bacd97, 0xf0a58787, 0xc197198c, 0x8a11f6af, 0x2f3e6859, 0x8ce7322e, + 0x91ece500, 0x8a9ca749, 0xe59622c1, 0x05f574fb, 0xd1969d64, 0x69a72f1f, 0x06090b51, 0x0cac305f, 0x7cc987ad, + 0x04da4997, 0x5576b5cb, 0x859c8ee4, 0x1e7eaa08, 0x16c0a9a7, 0x4fbe8a0c, 0x13b62e78, 0xee63e4d1, 0xfa55aa0e, + 0x05b83a34, 0xf31e0b9a, 0x8b512efb, 0xf1ac8668, 0xc425216b, 0x73cb93b8, 0x0e26b272, 0x8fac8955, 0xb8fe4374, + 0xcc101d6f, 0xae78b24a, 0x4501e888, 0x8a568802, 0xbadb9662, 0x23464924, 0x5f0687ed, 0xb72abf06, 0x38fd1def, + 0x45b3c778, 0x2ee0c167, 0xae8a0325, 0x3ec44d27, 0x1d762262, 0x9857ebaf, 0x7686bd44, 0x106068fd, 0x1342c1c3, + 0x39126f3f, 0xc0d59583, 0x518ab36e, 0xff4fb536, 0x4c947dbb, 0xe971607e, 0xc1a3b30a, 0xe46fd0f3, 0x22b2300e, + 0x0fdc252d, 0x3f93e617, 0xa17f3ff5, 0x07d3f2b4, 0x88a22c18, 0x4484bd93, 0xe2352147, 0x425d8434, 0x8557f5f8, + 0xf7b03565, 0xf77724d3, 0x7f7c3520, 0x89a8d1f9, 0xe2775a3b, 0x80276e89, 0xfe782431, 0x8b0b36b4, 0x52803dc6, + 0x2b295093, 0xdfd8788b, 0x76b31f00, 0x190f23fa, 0x62e02d40, 0xd41ccf50, 0xb8a759cd, 0x5a1fd7f2, 0x70587e1f, + 0x421cc34a, 0xa87d456a, 0x430a57dd, 0x97c2effb, 0xa067b324, 0x19a290af, 0xd17c3e58, 0xb1f8c324, 0x7122b845, + 0x014c4691, 0x9d21bff9, 0x88e296e8, 0x71904652, 0xc98a78d3, 0xf2dfa5b1, 0x5aa4c976, 0xf7328e6e, 0x522ccd1c, + 0x13282c62, 0x9b3b1085, 0xa7d36127, 0xb430a245, 0x3c4e8a82, 0x5e4fce80, 0x7cb9ab69, 0x6d68b05c, 0xc29fce36, + 0x69ebb6d6, 0x82026956, 0x48ee0110, 0x043749df, 0xe13d14f2, 0x30ea0039, 0x0618ffcb, 0xdfb99727, 0x335a5d86, + 0x0214c2f7, 0xda8e4db5, 0x28fa7f7a, 0xbfb519af, 0xa4af40cb, 0xaae47da2, 0xcffb3857, 0x7c615aab, 0xed88d73f, + 0x93f711f0, 0xef66ecba, 0xfc7098e8, 0xdcb1eaca, 0xd8acafdf, 0xad518adf, 0x5bae53f8, 0x152c799d, 0xd0dbc666, + 0x0e5c6e8b, 0xfc8b87d8, 0xe689933b, 0x57eddbbc, 0xf8276e1f, 0xc7029b4b, 0xdf0a3154, 0xc771d9a5, 0xa4f9275c, + 0xb20775e4, 0xc249a4fb, 0xa797d9a5, 0x7480be23, 0xa14d4411, 0x1fe4cafc, 0xbc40f499, 0x2a2a3ec7, 0x889abac8, + 0xcd657ff5, 0x93199e56, 0x329a49d4, 0x1ea328e1, 0x6e0ce2f6, 0xd0a13c8f, 0xe78cca24, 0x2583fde5, 0xfacd875b, + 0x5d94bdfb, 0x962b9d7d, 0x85d667cf, 0x62092a4f, 0x2e59bbc8, 0x632f32b3, 0x3b8a6fc0, 0x7657f14d, 0x321f6488, + 0xe4954fd4, 0x68ae22af, 0xcbe98dcd, 0x39487c31, 0xeca007f0, 0xe31b1dad, 0x34297c7a, 0x3012b220, 0x4ca4f159, + 0xbcbe5e46, 0x43a3c7c8, 0x6a0c3de0, 0xbc832eba, 0xa1d4a52b, 0x2525f987, 0x62fc5791, 0xc72ef9ca, 0x3fc020ab, + 0xa394d7b8, 0xc17a1b34, 0x4bebfa0f, 0x38a7c1e3, 0x3774ebfb, 0xe0d6e78b, 0x6e573224, 0x34cf5baa, 0x832be8a7, + 0x62669f03, 0x9fb16cf9, 0xdfd3f0de, 0x3fa1f874, 0x19986cf4, 0xcebd98f6, 0xe4293a78, 0x0c7ea664, 0x2431da91, + 0x103fb2ed, 0x0e3cdf80, 0x0627696b, 0x8fd6e3f6, 0xcabdb1e4, 0xbb72ab32, 0x96bf9277, 0xccc0941f, 0x7eb144d9, + 0xd0557605, 0xa204e602, 0xb96f9141, 0xc9ced197, 0x9dad1d00, 0xfac419fb, 0xf53eda88, 0xd2cd279f, 0xfd1483c7, + 0x9219ca86, 0x335bb08a, 0xd058a8ea, 0x05285b66, 0x528bd19e, 0x95ac5431, 0xb192c529, 0x9a7d6d62, 0x1b554e9c, + 0x67920f7a, 0x6edaf80f, 0x66ef5615, 0x32cd80d6, 0xbe68ff1d, 0xe4fdb5b0, 0x3b80c86d, 0x3e8b5f63, 0xeb1bc898, + 0xa47618e3, 0xd54024aa, 0xd6c4648c, 0x8b5fc8c0, 0x90741240, 0xd5733a1d, 0x0d040d49, 0x90a1f9a7, 0xae10a3ac, + 0xde8fa914, 0x35337d58, 0x1eac2bf2, 0x893c2c83, 0x705327ff, 0xc77bf252, 0xffcd8036, 0xf10f86d2, 0xa53220a2, + 0x37a746c5, 0x1d7795c8, 0x6b0325c6, 0xf20eb5d0, 0x6ea8f146, 0xc67222d2, 0x40d8aff4, 0x7d73ac4c, 0x6a0ce05e, + 0xd7f25aac, 0xa327d7f9, 0x99cf76e4, 0x2aa02ab2, 0x4841e140, 0x254604cb, 0xd0e5ea23, 0x46edbd18, 0x4c391a17, + 0xec395245, 0x7760763e, 0x9764b2a3, 0x7181c5e4, 0x0c28d20c, 0x48763411, 0x4b6f2f9d, 0x1a5e03f6, 0xd33fa700, + 0x22036b54, 0x448cf9f5, 0x77873138, 0x92e682b0, 0xf57fcad0, 0x75a2f463, 0x5538e33d, 0x50de977b, 0xbe0ef22e, + 0x5b071e47, 0x9f4ecd0c, 0x50d9192a, 0xacc5c3cb, 0x20dab14a, 0xfc7516af, 0xb24b3001, 0xe5240b7e, 0xe9ca42d9, + 0x05c36af7, 0xf21f65c7, 0x61e2f1d1, 0x0c68f408, 0x9496fc8f, 0x77e91fb5, 0xe042eda7, 0x144251ad, 0xc7c1c248, + 0x9d79a630, 0x76b209ac, 0x58989e91, 0xf32d9c7b, 0x65d26f81, 0xd532a614, 0x517fa07f, 0xbbdfa9fa, 0x638aa012, + 0xa7716513, 0xb1cad7b8, 0x6f5d6d99, 0xe8016bde, 0xd8731ee8, 0xcee12c83, 0x683d3685, 0x4af58943, 0x7877b5f0, + 0xf3e3dc42, 0xfe144468, 0x4bdf7b18, 0x48b7f9c1, 0x667948c4, 0x158f9a51, 0x96a2e43d, 0xb51ad49a, 0x1bea6c86, + 0xfffe6004, 0x38cf9620, 0xa9a7cbd0, 0x51e8d293, 0x56f11ef0, 0x70c3268e, 0x878fe552, 0x7868f891, 0x211256f5, + 0x51734062, 0xc37e5e6e, 0x3b278249, 0x462d639c, 0xe7fc54a6, 0xb9aa0bdb, 0x2b5671fb, 0xa6ced401, 0x944c6095, + 0x7cfede9c, 0xca00df0d, 0x41c53ba0, 0xbfd50d55, 0xbf2ecbd4, 0x487ca3dd, 0x21607e7e, 0xd9ab1ef6, 0xe628c2be, + 0x7896bdb0, 0x17677207, 0xc2a84511, 0x4762e1a0, 0xd2a46f82, 0xdf134e20, 0xb6c57018, 0x48d7067a, 0xaca46214, + 0x84747519, 0xd38d3d90, 0x4aefde2c, 0x62e20792, 0x9e14d66d, 0x125f0daf, 0x0bc0f929, 0x505471f7, 0xe5b4f97d, + 0xbdb2797c, 0x713c086a, 0x76b5bc78, 0xd4c16c8c, 0x03eb8787, 0x3b14e5be, 0xbb5ce24b, 0xa1be371d, 0xa7432dec, + 0xdbf07011, 0xf88753ff, 0x006f1ca8, 0xacf320ee, 0x6bf1c9f5, 0x8bc16a8c, 0xecc8bb50, 0xfc5ec35a, 0x230695b1, + 0x56486b01, 0xbb47227f, 0xe1dafad7, 0x40672686, 0x8909846b, 0xf99980b7, 0x26189ee9, 0x1383eacb, 0x3736506a, + 0x2d247c6b, 0x8bc8325e, 0x7928246e, 0x3e0b71f0, 0x68c860ea, 0x11716b60, 0x4b876a11, 0x8a19ad3a, 0xb9b20e02, + 0x77b7b5b8, 0xb36bd02d, 0x4cec70d1, 0x73aacca1, 0x4b1d2ca1, 0xb58d7691, 0x8b4c3f52, 0xf1c3bd58, 0xb33098da, + 0xc2a2241d, 0x04cb382c, 0x80d4c1d7, 0x088a2c01, 0x24470574, 0xb119de03, 0xfa869fa9, 0xff0646bd, 0x7acac8bf, + 0x64666d62, 0xf8eef6ff, 0x0239de47, 0x5ab1159b, 0xf284e766, 0x3f06a7ef, 0x85a2aa24, 0x08add9d0, 0xf0479060, + 0xbf124fea, 0x6c78b096, 0x077d1741, 0x22959943, 0x9c9f74a8, 0x2f8b1670, 0x84e43037, 0x414e0629, 0xfab9b57c, + 0x1af8bf6b, 0xfb3cd9e2, 0x208fef77, 0xbe4cd23e, 0xc8dc2155, 0x2340041e, 0x213581ba, 0x06f9d04a, 0xb1eed558, + 0xb39dacb6, 0x93babc57, 0xb32b4992, 0xe9f98f2a, 0x2de6a463, 0x0802d307, 0x18a5cf21, 0x38d09e65, 0x6486d6b5, + 0xdf3eb868, 0x14b42b99, 0x5dee5b45, 0x640d7e72, 0xc4a086d0, 0x3de1fa09, 0xc30c20f5, 0x8c5d5a71, 0x18aaff49, + 0xe588d7ca, 0xbaaab89c, 0x395688a9, 0xa67012d3, 0x2e7532fc, 0x56e648d9, 0x3c91b5d2, 0xc38f1a3e, 0x66bee8b7, + 0x34343a99, 0xc33f49d3, 0x117e4ca6, 0xb8d9947d, 0x2d88cecd, 0x78437860, 0xce5c61d5, 0xdeee78e2, 0x0232d685, + 0x52922b45, 0xaa3718a4, 0xa8fd8e7d, 0x9e057d1a, 0x5b295114, 0xa6f32e3b, 0x26b54ce2, 0x4e13ac09, 0x2fa0433e, + 0x582c3973, 0x38ee9053, 0x2729fc28, 0xf5e38da4, 0x59e22f2a, 0x90cd9452, 0x2548be3e, 0x647e8248, 0x136cfe9e, + 0x74a23ca0, 0xc2d8ba26, 0x9038f371, 0x41ff7a82, 0x6957bd41, 0xea709ba0, 0x02bd2293, 0x83aeaa99, 0x8e54e8df, + 0xf7b7c871, 0x394c8a4a, 0xffd22a6a, 0x29377ffe, 0x8137c563, 0x212cd94f, 0x7e7242e4, 0xc1d9c7d2, 0x7f9d45ff, + 0x586008e7, 0x300b3ae3, 0xdc85d2a2, 0x76f8fd12, 0x9c4be539, 0xef03472a, 0x20801e55, 0x8a62f076, 0x90849376, + 0xcc24203a, 0xf2aee89a, 0xa5b38cd2, 0xf7ebe7ca, 0x9fca59d2, 0xfee83ba7, 0x5621ee10, 0xcfa90d72, 0x9f1399d0, + 0xc3e39695, 0x75780e08, 0xcac73d45, 0x9d3f2f8b, 0x221a2daa, 0xe182a8d1, 0xf9181e71, 0x50f204eb, 0x2eab3c2c, + 0x63d1ad07, 0xc9ed328a, 0x983e7b57, 0x083d63c4, 0x4f734d4c, 0xb67616be, 0xf930ba4c, 0xb330bc03, 0xa3f06757, + 0x0c41ccdf, 0x5fb6ee40, 0xb112dd3e, 0x83f11b36, 0xe7784f6e, 0xfa80e3c6, 0x35f1bc74, 0x50090492, 0x1265188f, + 0x6e9fa755, 0x6f4d51f7, 0x66374be7, 0xb6199976, 0x1281ae6b, 0x20372345, 0x1b017a74, 0x082ae93e, 0xe9795454, + 0x026fd2e2, 0xfbb89142, 0xa30deb68, 0x75e7640f, 0xbe3db876, 0x4fc1122a, 0xba27bf37, 0x9ef845ae, 0x853d7e60, + 0x914d93f7, 0x69432a66, 0x7b3eae69, 0xd7335c37, 0x68971616, 0x10e12558, 0x90cf62a1, 0xd7ba05ca, 0x8dbcc199, + 0x7e2dceda, 0xc1b947b0, 0xb86f4a27, 0xa6c64859, 0x9e95f740, 0xc81e6909, 0x8cf1b1d5, 0x57d28ab0, 0xbea22f13, + 0xe014ee63, 0x5ea75e8f, 0x0dc510df, 0x3d866549, 0x86517f1c, 0xa9684d17, 0x1098542a, 0xcd643137, 0xe8b0a671, + 0xf4ef4c86, 0x27c0653e, 0x6a9c70b4, 0xb29940c3, 0xed3b07c1, 0xc3a0f727, 0x2a309702, 0xaf455416, 0x0190715e, + 0x09038fa3, 0xaef3afa9, 0xc8163469, 0x3917e195, 0x60324de9, 0x2fab179e, 0xf4bd0fe1, 0x950ed058, 0x0d24bdee, + 0x09bb1b7b, 0xf9152f8d, 0x47bae1b2, 0x64e6d9da, 0xb06a2f52, 0xea3afa70, 0xf220532e, 0x0aca8ab7, 0x7336a4ea, + 0xfe14ef52, 0x3b3ff33b, 0x7d096ffe, 0x082ffbb7, 0x1be9e875, 0x5a5dd60d, 0x60977044, 0xec563b18, 0xa54a3179, + 0xa30a9638, 0xe98940e2, 0xde482099, 0x4f576e7e, 0xfb123ed9, 0x1bef977c, 0x8d8c658f, 0xb588b770, 0x3c8a9130, + 0x03eb0950, 0xf250ac1e, 0x9d410ec7, 0x6379d966, 0xb76e2279, 0x4748fe57, 0x8757ca64, 0x92d5f5dd, 0x7f69b318, + 0x3ae90dbd, 0xc1a7f38e, 0x0e959ac7, 0xc3127799, 0x557ec15b, 0x87cd1197, 0x5477c323, 0x13e1a6da, 0x81f27e17, + 0xfb8c9c60, 0x462d297e, 0xca76c9a0, 0x3a7bf8ee, 0x833c2acc, 0x6df6fd09, 0x0def8af7, 0x56a87536, 0x4028ca4c, + 0xc611bf05, 0xd8d3ddfa, 0x769ac429, 0xe119afa7, 0x51c1a656, 0x613954b8, 0x3e1e4575, 0x274f05df, 0xa9b0d89b, + 0x4637073d, 0xe1dc3bb3, 0x2b38e1d4, 0x97c64361, 0x8cbe01ec, 0xba5326f9, 0x2b79bae2, 0xc2d36094, 0x9493f2ca, + 0x88c1c20e, 0x857c2749, 0x6f4e1712, 0x66142e04, 0x5dcccaec, 0xe7cd073b, 0x22943f12, 0xcaea134f, 0xfe335ec7, + 0x47e26af9, 0x045213d5, 0x5d1820ff, 0x4d2157ac, 0x7da3fa03, 0x4542eec7, 0x369b5aef, 0x88b41e11, 0xb4c81bf6, + 0x76bb589d, 0xd705fbc0, 0x4b2bd5cf, 0xe7b033ff, 0x402123c3, 0x8e705b79, 0x7adf93dd, 0xe168e4b8, 0x7a312743, + 0xfcf94e59, 0x9658629c, 0xc39ab1c4, 0xe8e83428, 0x26daf3ce, 0x9e3dd308, 0xaf4c7df1, 0xbe4021aa, 0x352d8c82, + 0x32a8f69c, 0x740a2962, 0xec560434, 0x83924a0b, 0xa137fdcc, 0x9ed79c12, 0xd38117e5, 0x5829b3b1, 0xf95e1561, + 0x8ac5ae33, 0xe529b6ea, 0x984494d0, 0xbed83bdd, 0x7ae8406b, 0x0b932d11, 0x17e06ae7, 0x28169860, 0xc6b6f9f4, + 0xaecf55ba, 0x95763bc9, 0xab2b805b, 0x2a30710c, 0x817c833f, 0x03d1596b, 0x5bee8cc1, 0xea9f7ebb, 0x57e5950d, + 0xb670ecac, 0x2cc81011, 0x6da0bcbf, 0x8a557783, 0x3e328d13, 0xf7dd225f, 0xcef189bb, 0x0776ca2d, 0x2f01b2fb, + 0x3c4f93fa, 0xe630030e, 0x97efc7c0, 0xb18df001, 0x2fb0ce41, 0xae4a50b7, 0xd9fb5ecc, 0x92209419, 0xdd38d1e7, + 0x500956f4, 0xd4a70f63, 0x5d7c9ace, 0x651ec63b, 0x6ae33489, 0xdc548261, 0xcd8f9a0e, 0x0e7c1e0b, 0x7f3f529e, + 0x68eee0b0, 0xa01a590a, 0xf0bafcd2, 0xa3148e02, 0xd9a0626f, 0x4ef7da9b, 0xa06c3e97, 0xd4795a28, 0x8659b9e3, + 0x531da00f, 0x6f39782d, 0xc759e39c, 0x09d23cf2, 0xb79d7879, 0xffe0a47d, 0x0e71b788, 0xa096f563, 0xe67bb1a5, + 0x78ee3262, 0xd9df609b, 0x8095a896, 0xbfb766a8, 0x8bfda125, 0x7c7c88ff, 0x9530d321, 0x8eec92dc, 0xa279f7b7, + 0x27c10ff0, 0x3ec34751, 0x7101d3b9, 0xc3020b3e, 0x06627708, 0x95f08026, 0x7e5c282d, 0xc195442f, 0x647b6bdb, + 0xfb96bbb3, 0xefe4aac1, 0xbed5d875, 0xcec7bd9d, 0x4450857a, 0xcef6f7f0, 0x1ba66da6, 0xc9e37dd6, 0x8b255f66, + 0xd8c751c6, 0x3fde1dcf, 0x1863cb3e, 0x53dacc11, 0xf95a171d, 0x10e900f0, 0xb9e37c52, 0x9c9ca3f7, 0x5455b910, + 0x8664d457, 0xb20cfb05, 0xd9cf9783, 0xb4c8334d, 0x9d0bca9c, 0x513211de, 0x9a397e5f, 0x24be6d0c, 0xa06afb1f, + 0xf5623dda, 0x803e5992, 0x92a9a61e, 0x5e31dca5, 0x28b37e1d, 0xf29f7ae7, 0x99b5c35e, 0x2c527c6c, 0x13638b61, + 0xd0754868, 0x45ca8bf7, 0x26c17032, 0x593cc220, 0x3055ef42, 0x4bbcb58e, 0xe4304ed3, 0x61c4523e, 0x570e98b7, + 0x586661b3, 0xde5ac3af, 0xb640c7b2, 0xa50c8a6a, 0x3ca74a4b, 0x9cb22d16, 0xe789867b, 0xb719d1eb, 0xff192bca, + 0xe63a7aff, 0xad563bf1, 0xc9f904e7, 0x2285faa9, 0xa7998eb1, 0x1987d0f5, 0xc630f2d2, 0x364e2fe6, 0x1fce4f03, + 0x57d405b5, 0x3279a0f2, 0xc7573bac, 0x4243c194, 0xf7c03986, 0x2a0f1aa3, 0x71f2f3f1, 0x5c02e585, 0x91f67388, + 0x48172335, 0x86cd0048, 0x7d92296e, 0x11a45cb2, 0x760082eb, 0xb55bc810, 0x9cb91c40, 0xce7f0a87, 0x77537e73, + 0x7e2924c0, 0xe2aa6d29, 0x04ee0ed1, 0x3c89a44b, 0x6db2daff, 0x6fdca923, 0x3749bb83, 0xd73d2e37, 0xc7d45a9f, + 0xdd3edde6, 0x7fe60f00, 0x17354a42, 0xd727ea3e, 0xdd9a3fae, 0x4a5448ec, 0xa3fd1c2e, 0xd51b9212, 0x54064ce3, + 0x393f0fb3, 0x8871ac38, 0x4ec8448b, 0x28fa41d3, 0x41c6c7da, 0x47214b30, 0x545ac071, 0x8b26ba9c, 0xd737a103, + 0xb36f1d9b, 0xc5061fba, 0x252f9679, 0xad339f0e, 0xce26729e, 0x8f0e3448, 0x473c113c, 0xd7b06762, 0x4dda0fae, + 0xbef9414e, 0xf728b570, 0x54898c76, 0xb49a748a, 0x9ae7fc59, 0x353eed81, 0x8562d18f, 0x7333fcb3, 0x1f458dca, + 0xe8e1b271, 0x792911a7, 0xaeab5f6e, 0xe0852fbf, 0x5fad0a36, 0xffceb9fa, 0xdb0f250a, 0x50098eb5, 0x3b47c4f3, + 0x8b3cc760, 0x10e8d3f9, 0xb1484f3b, 0xabcd56a5, 0x729aec1a, 0xbe0786b8, 0xcd9e2949, 0xdbed77a6, 0xa137c99a, + 0x93145796, 0xecc5aa3b, 0x64cb2972, 0x830cf577, 0x47b52d5e, 0x712ffb23, 0xb0a48e59, 0x34b4b06a, 0x5a404d43, + 0xcad9ce33, 0xb63f8d3f, 0x340ec3fd, 0xb5973a4d, 0xadb894ae, 0x19d0d4e6, 0xe61b13f3, 0x9ebb630d, 0x2e0df2a5, + 0xf24724c9, 0xabd2beee, 0xe006b59b, 0xc97656d9, 0x852128cc, 0xcfe49986, 0x703ccf52, 0x73f73df8, 0x34cf0007, + 0xaa1273b2, 0xce30890d, 0xc1c089a2, 0xc86a62e5, 0x5b225e8e, 0xb0b06405, 0x24755fbc, 0x30ddef34, 0x401a4708, + 0x98de766d, 0x3c6a133d, 0xf4b8165a, 0x0c32e1a5, 0xb014b8fa, 0x6882ae80, 0xa3d6bd8f, 0xff0a4e8b, 0x507162fb, + 0x00da2217, 0xab96c328, 0xf8bfb2cf, 0x1e49053e, 0x3327bc6f, 0xb5c3368a, 0xba97922f, 0x76abe68d, 0x7781c30f, + 0x9d2df558, 0x4f47249a, 0xf4a3eb32, 0xd836460f, 0xb22468dd, 0xbfe9aba1, 0xb9a9c2af, 0x3977ae67, 0x8ff23abc, + 0x40867314, 0x60b862a4, 0x6b4d2bee, 0x146a7167, 0x1d11cefd, 0x03cbad3a, 0xb4fbd77c, 0x0b71a3dc, 0xd785a414, + 0xa642d656, 0xbe57a080, 0x2cb6ce84, 0x2df8a81d, 0xa0729db7, 0x61c06bb7, 0x8e7c938f, 0x339a1cd5, 0x2ba95dd8, + 0x12a0c00c, 0x5d9ce822, 0x907fad77, 0xee060df1, 0xf9b518df, 0xad9d6d74, 0x17056d9e, 0xa8d2c6c5, 0xaf298a59, + 0xfb2629a6, 0xe149b17a, 0x95d2638e, 0xdf48c44f, 0x6f3abd21, 0x5dbc6993, 0x65530e2f, 0xae423500, 0xc4fbbfeb, + 0xfdd7e176, 0xf39f7468, 0x24900562, 0xc1bca88f, 0x4541c5dd, 0xc434064c, 0x87a08336, 0xc908ef97, 0x7e18c2ee, + 0xf1064e71, 0xa7642622, 0x82b8dc03, 0x7f388420, 0x6e6ac701, 0xaa5a16f0, 0x191f3e8d, 0xac9f33a0, 0x1839bf93, + 0x2d5b93b0, 0xac780d96, 0xf48c29e7, 0x79d71ab0, 0x116abd19, 0x8ce67275, 0x0969e901, 0x7ffc3f3d, 0xd61997fc, + 0x7d6328e8, 0x5a16fe0b, 0xa8a3e303, 0x85454aa4, 0xa0471323, 0xe791cb15, 0x6042580e, 0x515abe54, 0xf6a7808d, + 0xd5e771c4, 0x3d07d8a2, 0xdf406248, 0x8da133db, 0xac1892fa, 0x4e8ea890, 0xdbe250c8, 0x1d68caa2, 0x410da178, + 0x3ddacf39, 0x6f81f884, 0xac4a35a1, 0xd84581db, 0xc11be06c, 0xc5f9ecad, 0x1796f0c2, 0x695e40c8, 0x2ca53370, + 0x5693a631, 0x95790b24, 0x964ed2e0, 0x69c51c05, 0x8080dd79, 0x22fc0afa, 0x4f741bc5, 0x1002a92b, 0xb86f4614, + 0xa6e12851, 0x3350c9e7, 0x8a2f2ec9, 0x41c2eaed, 0x07df9d63, 0x447dc144, 0x091c67cb, 0x68e6b110, 0xb702e318, + 0x7eda598b, 0xe191a7c1, 0x4e0ba090, 0x75dcbe98, 0x90b00f04, 0x5b267231, 0xb27f52bf, 0xaf5b2802, 0x38757069, + 0xbaeac964, 0x0b10c27d, 0x5cda3726, 0x8f35cf76, 0x215e5079, 0xf3519ae7, 0x95024bc4, 0x7c35bc04, 0xdcb471fb, + 0xcead1178, 0x285186eb, 0x2434b931, 0x2b55a005, 0xe1962385, 0x2b5ab2ea, 0xfe06bb1c, 0xc116fc54, 0x4821e49d, + 0x1a424cbf, 0x7e572350, 0x757f142a, 0x285973b9, 0xafe7ba16, 0x2f3a73f1, 0x1cde0d33, 0xb945b34c, 0xf6f935ee, + 0x9c6dbe53, 0x4ef886d4, 0xb76cd53f, 0x83be1a04, 0x434e652b, 0x507315da, 0xc4c3d7cc, 0x7bcd6606, 0x434f9fca, + 0x0fe00b49, 0x2a397256, 0xbb52ec89, 0x5c3d05b2, 0x0ab55cf8, 0x03aeaa5f, 0x15da750e, 0x6db7d469, 0x5434248c, + 0x63685c91, 0x900db82d, 0xc8af93a3, 0xc0fac972, 0xd0bcacb4, 0xf06f8360, 0x92b04ce2, 0xf8c6e72d, 0x45997f9f, + 0x4491c99d, 0xc19e0ba6, 0xb3d4efba, 0x7002dc17, 0x5e2e38c8, 0x5e1cdd37, 0x27f96147, 0xb495533f, 0x26449ce3, + 0xfa399425, 0xcf6613e9, 0xc7812398, 0x7bc31d1a, 0xb4a8d5b3, 0x679a2a6d, 0x59c203e2, 0x918147e6, 0x07194fb1, + 0x45f5ac03, 0xc7d5ab8b, 0x63d5f0e4, 0xe6ddf8a7, 0xc77844b7, 0x5aed261d, 0x5fcc4142, 0x75535136, 0xda518c86, + 0x7f0cee9b, 0x951972ec, 0x6a76cb7d, 0x9f5a7760, 0x95ab9216, 0x1e9325dd, 0x8907f8d9, 0xfe8c4fd5, 0xb94faea4, + 0x88afdce8, 0x46376e9d, 0xfe22f3fc, 0x97ea0636, 0xb4ecc54b, 0x738e8f53, 0xd1cacc53, 0x82485ff6, 0x59b7a122, + 0x5bf91593, 0x2f63a0b7, 0x0db68f3c, 0xa3eba1d6, 0x2454568d, 0x690dadf1, 0xda5a560c, 0x13d74317, 0x1d48f01a, + 0xabd3f13b, 0x2834c90d, 0x689e8a2f, 0xa75c2e69, 0x874bb412, 0xfe0e2db3, 0x24d2ee29, 0x9c9ca377, 0x8c5a92b6, + 0x7fa0aa41, 0x5a5f8651, 0x427b1e77, 0x540bb8eb, 0x073a8399, 0xed530c8a, 0x5fed09f0, 0x056b70f2, 0x13b34405, + 0x2a0fad6f, 0x0f362ee9, 0x5d37cb7f, 0x96a64c25, 0xa12922ab, 0x55a6a7b2, 0xe0d5f513, 0x7bd6725f, 0xbfd66228, + 0xcb7df5eb, 0x3e0f4b6f, 0xde596a0f, 0x5e757eb1, 0x6498ae24, 0x52653a62, 0xe9098346, 0xdaa176e3, 0x56fff30a, + 0x7c213b78, 0xc8cd1384, 0x8ff4aebd, 0x7bba66b0, 0xf5ed1cbc, 0xd3d22009, 0x294dd44f, 0x038ddda6, 0x72f5aee5, + 0x3a276c32, 0xd0084b64, 0xa7f1bfd1, 0x6701df88, 0xe78b8d58, 0xbb9166f2, 0x050343d6, 0xdcd9067d, 0x5c32b140, + 0xf170dd4c, 0x3148758d, 0xa74812bd, 0x12880609, 0x16bfda6b, 0x03a8b6f5, 0x9bbdedb3, 0x81dd9dad, 0x76b890cc, + 0x72edd190, 0x5e898110, 0xa85da601, 0xd6900d35, 0x3df2b422, 0xa6fe05a6, 0xb49972b7, 0x5fb262c4, 0xb7c981a8, + 0x0d604346, 0x49270e0e, 0xb5f4818b, 0x3c76e043, 0x929e75cd, 0xe96fba3d, 0xe4b7c54f, 0xec4847f4, 0x6895fa0a, + 0x06a1c192, 0x88850792, 0x6baf6989, 0xdef242d9, 0x60d278fd, 0xb3c77d6d, 0x520f6e60, 0xe65a3bc6, 0x208e8332, + 0x6c615065, 0x035c744b, 0xa8fda3be, 0x3183366b, 0x5eec7c60, 0x39940dfe, 0x17149bbb, 0x86ea7cb6, 0xdb764de4, + 0xe3753fad, 0x6985ff79, 0xf0b5c03c, 0x80475416, 0x9675d549, 0xcb1000af, 0x13e356f6, 0xe2d85167, 0x060c9b4f, + 0x35ebefb2, 0x41796049, 0xa35c6138, 0xc094b827, 0x00307b2f, 0xeabe88d7, 0x4e1656f8, 0x89252918, 0x8fe3e9cd, + 0xa1e88413, 0xfe4206bc, 0x3dea97ad, 0x166d7a76, 0x0166c4a8, 0x2ffa33b8, 0x8744ff76, 0xe4714f2f, 0x9c73b00e, + 0x2fa841fe, 0x07d6d256, 0xf644d0eb, 0x37e8b58e, 0x9027775c, 0x4297fa7c, 0xe98defc7, 0xc51d57ab, 0xad88b4c5, + 0x0761e98d, 0x1e76968c, 0xd025e7e3, 0x79acecbf, 0x2c963fe9, 0x86590b6f, 0xf1096b77, 0x3fe5bc22, 0xef4740f4, + 0x65e4c61f, 0x4a83fffb, 0x53e48e20, 0x3ad102d9, 0x0fb84377, 0x7cba70f6, 0x217a46a3, 0x5443e39a, 0x77b4da59, + 0xfc174021, 0x97959708, 0x852d8afb, 0xa0b36396, 0x570ddb05, 0x284f80b5, 0x502b765b, 0xe84942cc, 0xb770eff9, + 0x6263002a, 0x80019b3f, 0x8cd1ee55, 0x424743d3, 0x2a370b17, 0xa769a94b, 0x7e6503c8, 0x6faf16ce, 0x0891a5bd, + 0x76c25cf2, 0xb468c723, 0xc874162b, 0xf3f7adeb, 0xa9d4c762, 0x9041812b, 0x8fda1bce, 0xcd89bd43, 0x2b4bb46d, + 0x157a9882, 0x7627d408, 0x33e6d895, 0x8f16b4b0, 0x8e1abd26, 0x9f7884e2, 0x7402a8ad, 0xbbb1c7a3, 0xd52e335c, + 0x6f6d18ee, 0xcb6c4b76, 0xb896a407, 0x4538f24f, 0x1f838f07, 0x188f769a, 0x18277848, 0x5e478e03, 0x38533ce2, + 0x74235049, 0xc9eeb7ae, 0x46c4dba0, 0x67093799, 0x9d021c97, 0xe97d67b3, 0x499b43de, 0x25555bb4, 0xda4407eb, + 0x1711816c, 0xf7430816, 0x02460f86, 0x588ca372, 0x4057ecbc, 0xc5095f90, 0x4698e4d6, 0xb5c8f839, 0xf9821ce8, + 0xb57e6ebf, 0x8c254eb0, 0xcd35cd50, 0x67d2be0b, 0x206e16c6, 0xe18770db, 0x2d30c278, 0x4b94e366, 0x51e95ddf, + 0x9a9508c7, 0x379712c4, 0x6f35822e, 0xa4e61552, 0xe1b8b40d, 0xb7c6374e, 0x5af190b8, 0xbd205771, 0xfdc8d9cb, + 0xd29ceade, 0x7792e889, 0xb4d1666c, 0xb5c2ea95, 0xf1363c48, 0x7fd2dba1, 0x7275cccd, 0x23392ec9, 0x060722b1, + 0xc4897c7e, 0x4e0b2580, 0x3cfd7a73, 0xd5a3e393, 0x4fd3357a, 0xaa1f4ade, 0x032583aa, 0x3a3a6baf, 0xb4aa9f25, + 0xc774cf39, 0x41f64470, 0x2947bb9d, 0xeee13965, 0xb735b2df, 0xa9dca530, 0xd851c4b5, 0x28d3e731, 0xfbc11c2c, + 0x7151bcff, 0x64f06d6d, 0x8975a820, 0x028e41c5, 0x5e2f5388, 0x46ceac10, 0x4ee03105, 0xb1759a7e, 0x4db352c5, + 0xa7894144, 0xe2b84fe2, 0x2ee2c5a1, 0xb3cbef83, 0xda82d611, 0x74e22450, 0x62f576f3, 0xba477c46, 0xcbe5310d, + 0x9d7be74c, 0xa34f9fef, 0xb5a9b9a0, 0x5ceb06f3, 0x4174dc19, 0x934bb2cb, 0xb1928eaa, 0x1013e84a, 0xcca6eda1, + 0xfa789d18, 0x0c47e422, 0xd76ea934, 0xe877c68b, 0xe20278cf, 0x8d2f4cb2, 0x6479b8a1, 0x970d9518, 0x940fa1c2, + 0xd204b879, 0xb2854d20, 0xcd189c07, 0x09f2db8f, 0xced16026, 0x45c1c2e1, 0xd9d166dc, 0xffeea3ca, 0x49a7df1d, + 0x410c1b21, 0xd6b1ef63, 0x6c3b31ee, 0x9263442b, 0x4d3ceedd, 0x017fcbd3, 0xac20cc14, 0xb85b39dd, 0xbffa17c9, + 0xdeb565b9, 0xe2201509, 0x4df46247, 0x0b17c39d, 0x9f1cbd5f, 0x301dc9fd, 0xa8104206, 0x71f76596, 0xb67fe62f, + 0x824e1e29, 0x245690ed, 0x4f182b33, 0xbe9d503a, 0xe20a96b8, 0x06262410, 0xb2ec6954, 0x613c52a1, 0x576d7565, + 0xa25aac1d, 0xfeb8651c, 0x067e20f1, 0x539f702c, 0xa23ee4c6, 0xed7772da, 0x15bf3d70, 0x7f87156f, 0x6e454e7c, + 0x5815dc60, 0xa1c036fd, 0x2fadebab, 0x355ccc39, 0xa706ca41, 0x82a27870, 0xcd750e0e, 0x3d7f50e6, 0x2b678d4a, + 0x438317ba, 0x45f16d18, 0xdc901e53, 0x28b79531, 0x812530ca, 0x5ec13d16, 0x71a0a1a0, 0xba3e3342, 0x7037876b, + 0xfe78f808, 0x7e397e1a, 0x75707e0b, 0x13fd5f94, 0x4a6197bc, 0x08a6caa7, 0xbb2e5048, 0x954e7d5b, 0x67a63a74, + 0xd6a41140, 0x6c213a3e, 0xa20e8194, 0x33d0592e, 0xdd80bdc0, 0x47189906, 0xe4ea25fb, 0xcfb1f5c4, 0x10053631, + 0x55682878, 0x3cc9666e, 0xbf0f946a, 0x50af4034, 0xa0b561c7, 0x4caed1f4, 0xe94d38f1, 0xea42590e, 0x62d45a14, + 0x53213783, 0x3799b63b, 0x6d8f019e, 0x1eb48ccc, 0x5344aaa9, 0x7cbe56ee, 0xb9def1bf, 0xce8adec5, 0x33952056, + 0xc6d039c5, 0x053788f9, 0x8d74bca8, 0xbe7d5498, 0x61f005ec, 0xacb65510, 0x71f5a600, 0xa2ce6bad, 0xef2ad802, + 0x7637ddbd, 0x7ea44ce4, 0x935ec57c, 0x57b3e97a, 0xbaaf3010, 0x4e032e5d, 0x2c693263, 0x04c7c32a, 0xb6125053, + 0x75279d04, 0x4a3a3eee, 0x46e73f11, 0xce9988b0, 0xc302a9bc, 0x761fa8a4, 0x36d6a576, 0x3d206445, 0x04470c3f, + 0x1fd35239, 0xfda86395, 0xc3550b4d, 0x9f0c82a2, 0xb08c6d4b, 0xffe45631, 0xd25be98d, 0x1dcd79bd, 0x7bd8a6bf, + 0x2dae31e4, 0xeaed9636, 0x4d460cb7, 0xecfe1caa, 0xdd19505f, 0xe3bbab42, 0xeee08bb8, 0x912f2fec, 0xad448715, + 0xee58053e, 0xbce42f63, 0x852e30d2, 0xf9fa26a5, 0x4f65e06c, 0x731820f2, 0x0a79ddd2, 0x9e3b2675, 0xcb79db88, + 0x0f0060e8, 0x10d581ac, 0x434f9dfb, 0xd4452125, 0x765cca18, 0x20991c1b, 0x64a2c706, 0x2861e1a7, 0x9fe2701c, + 0x0ed3e9fb, 0xf406607b, 0xf5d4243a, 0x657eab08, 0x064dc48f, 0x2d128d9d, 0xbd0c298e, 0xd8dbd748, 0x1fdb387b, + 0x516e94f8, 0xfd0a6fe9, 0xa94d19c6, 0x8e498adc, 0xbd6c825a, 0x134917b0, 0x134ec430, 0x4a9e0cd5, 0xf159065e, + 0x457fb84d, 0x5337fba6, 0xc998b80d, 0x07c4b5ac, 0x10a5bab5, 0xcd8e4ee6, 0xef7d11c4, 0xa6c718cc, 0xe6aa258f, + 0xc4cccc3a, 0xd070fa2c, 0x63faf703, 0x9c0e11ac, 0x48fb56ec, 0x96c8aec1, 0xbf4d2a0d, 0xe468016a, 0x075ba1ba, + 0xedb5a7b1, 0x2cf56a62, 0x830abda7, 0xe1d3edcf, 0x4c2875bd, 0x4a7d98b4, 0x944f9948, 0xa4350e27, 0xe117ea0e, + 0xd172a256, 0xa7a17765, 0x52cee3f8, 0x0b412173, 0xb0aef278, 0x9f6a61f3, 0xf4bd0703, 0xec8ea5b3, 0x036d757e, + 0xa1ee0704, 0x292c823c, 0x005ab03a, 0x335935f2, 0x3bbd1c6d, 0xc08ec8f6, 0x98274126, 0xda1f4cd9, 0xfb401254, + 0xf73ae989, 0x9f949746, 0x4d64d501, 0x42b442b3, 0xcdfa9486, 0x46edfd40, 0x11ea21f8, 0xf20f5702, 0x0e65d9e3, + 0xf42a75ae, 0x9e9e538e, 0x803139de, 0x523d13ac, 0x13474513, 0x0c4f75ec, 0x27cc5ceb, 0x9c4bed26, 0x72531372, + 0x253facf6, 0x03690ee7, 0x8add4d17, 0x022607cf, 0x13eb99f6, 0x931f551c, 0x0b92ba36, 0x7351b37b, 0x148d5c07, + 0xa82dace4, 0x785c35dc, 0xaf750929, 0xb1443ac4, 0xdd1138dc, 0x92b0e180, 0x23abb58c, 0x0fd6954f, 0xb280a525, + 0xcee20bad, 0x58a7a953, 0x801bfcd5, 0x89232d83, 0xf19f9246, 0xb9b30b06, 0x4a05e2db, 0x76ec7feb, 0x879b750c, + 0xd5a3822e, 0x5233d7c3, 0x274ea04a, 0xd049653b, 0xc414a978, 0x7e93cf25, 0x419d5e82, 0x64a53fcc, 0x8ba3ff5b, + 0x9c887e7c, 0x792e2f70, 0xdcdf2c86, 0xcaa1e232, 0x2bf1a2cd, 0xce230f03, 0x218620e2, 0xee98fbdf, 0x87897d24, + 0x4c231931, 0xa17eb4c4, 0x0ec82763, 0x13b35883, 0xc23154db, 0x1e6a4634, 0x382afcf0, 0xb0357dd0, 0xadcd430e, + 0x63de2d05, 0x12e666b4, 0x09a958af, 0x03223fbb, 0xd6345ee4, 0x74d402f5, 0x237119ac, 0x1088c309, 0x700e776e, + 0x89f6df8b, 0xdd38d1e6, 0xeacf7c78, 0x766765aa, 0xbab0ec8e, 0xa2c70075, 0xd0393f4a, 0xfb880b1d, 0x61daf25d, + 0xdf66895a, 0x9aa37207, 0x4537b368, 0x6b6ce888, 0xab03d5a2, 0x7f64674f, 0xb52f38fa, 0xcf85d1bd, 0x702f88ea, + 0xbc4174bd, 0x186dfdee, 0x0e342ba4, 0xc045ff3a, 0x89fee3b1, 0x726e76fc, 0x6739292d, 0x9e047545, 0x7ed94b4e, + 0xf3d89bef, 0x209b2fd6, 0xba20fa41, 0xd851ac74, 0x28da267a, 0xef98dd93, 0x991debfc, 0xaf3d80a8, 0x90a437e4, + 0x0a71f5c8, 0xe4313d6e, 0xc089db82, 0xb02a80fb, 0x5726a5a2, 0x1fb9c1b0, 0xa7b21d79, 0x81ef8c24, 0x27293fc5, + 0x50ef1876, 0x61d35b77, 0xfd589d91, 0xb3d05c3c, 0x8062a647, 0xfbfd65d1, 0x00cee376, 0x35cc46c6, 0x9d0a4aa9, + 0x1f113bf0, 0x6c544b1a, 0x6075b43a, 0xaa914d12, 0x00edf7d5, 0x25427b04, 0xf3850b61, 0xf8eb7f66, 0xb783d7ff, + 0xd245d633, 0xe7dd690e, 0x63c2885f, 0x08fce9ab, 0x50392363, 0xd814fb3e, 0x31daf81d, 0x2d2c5186, 0xfc3cf64a, + 0xf60eabe8, 0xcedcde29, 0xf4648b21, 0x9661e8a4, 0x7629831a, 0x6a21888a, 0xd58c4dab, 0x58a03532, 0xbd3f5e8e, + 0xdcb9e023, 0x8b8148a4, 0xea56b89b, 0xe31bdc66, 0x70b8ab0d, 0x46d1b3bd, 0x43c86012, 0x304b84c6, 0x7646318e, + 0x6b6df343, 0x55047b56, 0xe4eb178a, 0x2740d414, 0x2f062c6c, 0x2bb87ab3, 0xbbe46759, 0x604592fd, 0x28034951, + 0x5a41d5b0, 0xab3cda0a, 0xec016b00, 0x7892a766, 0x69a55747, 0x5efc7560, 0xddc2a900, 0x22eb94af, 0xe60437d1, + 0xee44e8d3, 0xf371cc73, 0x4e5e6e7b, 0xdbcc442f, 0xbb2f778a, 0xc6d98bd7, 0x18538d40, 0xc979f0e9, 0x4f4be0dc, + 0xa638a6cb, 0x5d0983f6, 0x3e3bb206, 0x571d88fb, 0x241c6359, 0xad67b501, 0xb6253cd2, 0x79c59d55, 0xafd3041d, + 0xa62d0004, 0x939d6fb7, 0x92955860, 0x922f19bf, 0x031a3537, 0xddbb38eb, 0xdee7d821, 0x0207fc68, 0xed548b3b, + 0x70886283, 0x79e8ae43, 0x367892f5, 0x871499e9, 0x27cd4b86, 0xec865f04, 0x7ff18368, 0xe629f3aa, 0x624fc9d6, + 0x938a106c, 0x6d8a7a9e, 0x8c804933, 0x3eb5d6f5, 0x536d60a2, 0xc850fc9f, 0x27332521, 0x4c30fb35, 0xb3387981, + 0xc81f3618, 0x6d1dbdb0, 0x2fa4e5aa, 0x3c182f7f, 0xce06706f, 0xa6f76bf5, 0xb8accd9f, 0x859b6f01, 0xd172b494, + 0x172f34c2, 0x846b960c, 0xa75fb178, 0xd6a4d265, 0xa1821835, 0xb6983095, 0x4be9130c, 0xb56711c4, 0xc5f76010, + 0xdd2010a5, 0x8e85fc3e, 0xf5002fe6, 0xb5fcd270, 0xcde65a92, 0xf4f7ebaa, 0xa5171728, 0x596ed1b4, 0x8fe0487e, + 0xb3a452ed, 0x7be9762a, 0x937f6834, 0xb7ccb972, 0x33e38e1b, 0xc4b79540, 0x8d6936aa, 0xb7f57e24, 0x9142146f, + 0xc0aad048, 0x355f47c1, 0x94d67bef, 0x3f5f66f3, 0xa06f3bc5, 0xca821f31, 0xa3d1b427, 0xe09286e0, 0xfbb49e9d, + 0x22cd5984, 0xde3fbaa9, 0xf1228b0a, 0x109a0b9f, 0x7548c33b, 0xe941dbb2, 0x93f95e81, 0xab081a96, 0xdf747884, + 0x45ed0016, 0xbdb948f9, 0x52666432, 0x2294a781, 0x66b25bb4, 0x2335dca4, 0xc636dc96, 0x766687f4, 0x8273259d, + 0x856f58b2, 0xc5311f4e, 0xfa666467, 0xdaaee17d, 0xf5d22468, 0xb94d77e5, 0xe3ccd5cf, 0xf71ff3d5, 0x059c47e0, + 0xa2677a6e, 0x3690bf4a, 0xf7915003, 0x836ffa5f, 0x8a3df18d, 0x838d8411, 0xb6b54740, 0x5b2ba5a0, 0x2d8db59f, + 0x745bf9cd, 0xec9e0e62, 0x8bb57884, 0x5b5f6d82, 0x44be8f59, 0xe3ed39bb, 0x4ef5119d, 0x10c90758, 0x4c3de02e, + 0xcc0dcdcd, 0xae35ebaa, 0x8b079813, 0x707f4cd4, 0xb28ee485, 0x868e1475, 0x98dd2c9f, 0xbf7e4f5b, 0x2f2378c2, + 0x7e997fca, 0x0ae36578, 0x0714380e, 0xf942af1a, 0xdc924a4c, 0xd462660f, 0x73b985b2, 0xb3443ec0, 0xa79c0a43, + 0x74a7a67a, 0xd1d2f722, 0x3e9d04ee, 0x9a4e1195, 0x626273ff, 0xd2403034, 0xc4a06a7b, 0x59830abf, 0xe25c52c7, + 0x835a60fc, 0x74890b67, 0xba57e1c8, 0x16fd9a93, 0x318964d9, 0x73f3c4e9, 0xc8dcb69f, 0x6b19cc12, 0x848795bf, + 0x35bb1c1a, 0x1e328ed7, 0xb0f9eecf, 0xfcf7d0ef, 0x18084914, 0x41866a66, 0x9a53ef73, 0xc80279e4, 0xfaf76d6b, + 0x6bfc3811, 0x806e5e41, 0x939565a3, 0xb3aac7da, 0x8c29ef06, 0x40ee7f8e, 0x158b6c83, 0xff4fde31, 0xeb907b6b, + 0x1cae2e23, 0x0f2ee3c6, 0xb1695a77, 0x7347da79, 0x16ffd074, 0x4ac8b21e, 0xa36836e4, 0x96d832f1, 0x4f52a03b, + 0x87320d38, 0x4a9b3d5c, 0x96156427, 0xe0010793, 0xca4bb547, 0xa85f29a8, 0x85ee6d70, 0x507197f5, 0xc5727a49, + 0x1ca129bb, 0x87b85090, 0xa54860cf, 0x26e5a790, 0xd4b4c87c, 0x32a58dd1, 0xda70783c, 0x6331fe08, 0x6d5cf3c2, + 0x5ea90f67, 0x7b234c8d, 0x82709b2f, 0x6aae16ed, 0xfe8fb430, 0x91aae7a4, 0xa89c8475, 0x9ee038e1, 0x46752770, + 0x607bc2b7, 0x5a43428f, 0x22c889f2, 0xbab3c6ee, 0x0fac61b3, 0x75dffa55, 0x23d02d78, 0x9e425bb5, 0x59b2e2a7, + 0x9840368d, 0x0d7daf83, 0x5038f381, 0x1a2ca12e, 0xb796b6c2, 0xa8f2aaec, 0x08085d45, 0xe666f976, 0xd77c5ea8, + 0xfaa8692e, 0x89b8d180, 0xe3c2705f, 0x16234e9e, 0xcd4e4fc6, 0x870800df, 0xd723a9ec, 0x93aa6197, 0xccb05bc4, + 0xecf009cf, 0x228d7786, 0xcb35fff7, 0xe9dfde8f, 0xaa78f2a8, 0x3bdc97dd, 0xb0e60ac5, 0x8a238fa6, 0xb42b36b0, + 0xd0948639, 0x103bc6e0, 0xb9c624a2, 0x9ac7ee52, 0xe1bb553d, 0x25ba0f2d, 0xec5a50f0, 0x525071c7, 0x32ae5317, + 0x3664176c, 0xfd6e1cea, 0x40da8e5a, 0xfa450d23, 0x75246f3e, 0x2929379d, 0x8e9b60ce, 0xc0bbf00c, 0x2f72727b, + 0xe43257a4, 0x59a0fd18, 0x3a0585aa, 0x14ffc421, 0xa4ac0cad, 0x20346223, 0xac05560e, 0x3260af53, 0x4f0f2911, + 0xb7f749b1, 0x8dcbfebb, 0x6ed1040a, 0x9cf320de, 0xf91b5c8c, 0xe75e20c3, 0x167f9681, 0x6d2bc888, 0xc4fd3e7e, + 0xa6d9b333, 0xa4335f14, 0x6e3a8d38, 0x29812b76, 0x5f52e568, 0x8a9c434a, 0xde78bff1, 0x29a8e2fe, 0x1d19a3dc, + 0x79913344, 0xbb8e2c30, 0x7c5008e1, 0xffdcb3ba, 0x8d89d735, 0x08916038, 0xc72a7f5f, 0xbcc988f6, 0xd5eee570, + 0xec92250c, 0x5a7c4a47, 0x6d2e33a3, 0x24cb0d60, 0xf70685c8, 0xa3c806a0, 0xbdfae84b, 0xa4a67943, 0xe9b91b21, + 0x9e013594, 0xa81e232d, 0xe8e588ad, 0x775119cd, 0xcf750bda, 0x0ece7f14, 0x175b7be9, 0xf32b1a39, 0xc463947a, + 0x3edfb896, 0x0bfb16d6, 0xaf65c608, 0xdc641073, 0x0f7eac7c, 0xd323ac96, 0x4274a6eb, 0xb4292188, 0x5c04680f, + 0x2d95a695, 0xf4c315b7, 0x3316c523, 0x115295a4, 0xc9d3a324, 0x9b7ef8ea, 0xd92832f6, 0x57361199, 0xc0aeaf06, + 0x84240756, 0x603a8729, 0xbdb675e5, 0xb5ee6993, 0xaa403ec0, 0x389ab29a, 0x0479b39a, 0x0c17e0ac, 0x06d9f9db, + 0x8153fc3f, 0xc6f01456, 0x4fcc2b64, 0xee3c4364, 0x592f68c6, 0x63033033, 0x468cb226, 0x98df9e53, 0xff5036ab, + 0x1c0261cf, 0xd05d7071, 0x44465e19, 0x218ddb59, 0x77c47d9c, 0x9c69cb51, 0x1d2d5bfd, 0xbaeae40d, 0x5ea9b1e4, + 0xcf79acb9, 0xdfbecf79, 0x41fcebcb, 0x80dac72e, 0x2c7c1d77, 0x7ecee1f2, 0x72f4ac6c, 0x0b6a4925, 0x8467441f, + 0x14086e24, 0xe4d38856, 0x39702da0, 0xb8d98fef, 0xb98c2fc4, 0xa8e8edbd, 0x7eff0e27, 0xff3961f2, 0xbc14a79b, + 0x1ade7ff7, 0xf7132d2c, 0xb4416c2d, 0x1391c607, 0x233504bc, 0xc101cf9e, 0x576cc7c0, 0xb4fd6643, 0x5b3022fd, + 0xbf7d2f89, 0xddad1e2c, 0x282c78b4, 0x379a1549, 0x829e057d, 0x0572624e, 0x82317a72, 0x30903914, 0x5f9a21d0, + 0x6a4a1f7e, 0xca77d649, 0xd3418bc3, 0x2f29ee21, 0x9b4cafc7, 0x9e341421, 0x37d49fa7, 0xb84eaafd, 0xfd0a27ae, + 0xc4164067, 0x45dc9bed, 0x9eae801f, 0x5ff14c89, 0x545d3e16, 0x9a50bff8, 0xa4b473df, 0x5ba988f6, 0x1cbade3e, + 0x842b2979, 0x9f8e6bf9, 0x4a9985d4, 0xc20fced3, 0x606207c5, 0x0ffa2256, 0xfb44070d, 0x9b0cec7f, 0x4c1e5290, + 0x732e376d, 0x9d57ab15, 0x82965f34, 0x547e001b, 0x423c95ee, 0x87af89c8, 0xeaf9f712, 0x73850839, 0x55806767, + 0xb7c8377c, 0x29e7e714, 0x0516ad4d, 0xc40e9db2, 0x6bfd6dc6, 0x3a673e44, 0x2230a6b4, 0x66252f81, 0xdf4c86a0, + 0xecf42312, 0x5c589a47, 0xbbada40b, 0xfff3876c, 0xbb138b23, 0x979443c6, 0x6d5f1657, 0xda42d439, 0xc07f15dd, + 0xc363ddb9, 0xd33ff22c, 0xf9937c80, 0x38b30d82, 0xa1db1672, 0x2b3eac71, 0x67b4a8c6, 0xd1c19faa, 0x69cfc6ca, + 0x8c3026e7, 0xa188d3d8, 0xa892578e, 0x2161b6a0, 0x50c75ff5, 0xbb382b9e, 0xd22734e0, 0x71a2c96a, 0x80064848, + 0x62541ad0, 0xc59933ca, 0x3802e3a2, 0x7ffebca5, 0xc42fe47c, 0x1f9b0e66, 0x9e467753, 0x3bbaa10c, 0x9e376c80, + 0xc50a17f2, 0xa004f8d3, 0xccf4612c, 0xdcd3fac3, 0xb3404869, 0xcce5465b, 0xf5a8e022, 0x8d65bfbe, 0xc20cf2dc, + 0x4b06c247, 0xa1233135, 0x7e714e25, 0x88c8d7ff, 0x3e1bf788, 0x1256e988, 0x0f1ee492, 0x1ab61db0, 0x7703de3d, + 0x8b06d9e9, 0x56f112cd, 0x9c92dc4d, 0xab4f9bf6, 0x5badc60a, 0x36d9c113, 0x538b686a, 0xcbf9fb04, 0x25486110, + 0xe8164d57, 0xb6399585, 0x0dd561d0, 0x390e448f, 0xbd2738bd, 0x3a6bd084, 0x6e6fd2ce, 0x33eb46dc, 0x9851d49f, + 0x7e8956f2, 0x8a7133d2, 0xcb330bbb, 0xdf5452f4, 0x5cce6b37, 0x192223b5, 0x037890d7, 0x6839bce1, 0xe26e7626, + 0x842a705f, 0x623c3d5b, 0x367124b5, 0xc933a1f6, 0x263a7c9c, 0xe431756d, 0x586b640a, 0xeeadc0f0, 0x8a486fe4, + 0x74a0cc95, 0x94bcd961, 0x587a22d9, 0xf7ea06f6, 0xfdf978a0, 0x779979d1, 0xc667caa9, 0x0d223ca3, 0x31fa3620, + 0xeeeb21ce, 0xcc59875c, 0x0b36e640, 0x13f41cab, 0x58bad0b4, 0xe17f8eae, 0x44385a31, 0x8cba2cf5, 0x6814bf57, + 0xb5024a07, 0x0ae63377, 0x07dc4e7b, 0x28611a81, 0x4bad52c7, 0xe960870e, 0x7d4eab49, 0xe15b0826, 0xd4f5173d, + 0x6477ae2d, 0x419e522c, 0xa0d4c196, 0xec5c0366, 0x1450a111, 0x7fd76067, 0xd733a95a, 0xde2d316c, 0xb129c365, + 0x82326406, 0x86f2aac0, 0xa4b44353, 0x55485008, 0x60787fd6, 0x34022e64, 0x24ad19bd, 0x7533b42a, 0x2f3004ea, + 0xb3e2880e, 0xf34f6bdb, 0x31482889, 0x1cb00ae2, 0x60bf8565, 0x91a44186, 0x4d8cc0f0, 0xb42fae44, 0x71a5b90b, + 0xc9b216c8, 0x14f2b0aa, 0x2538a209, 0xeaa5d60f, 0x1dcd1483, 0x634dbd70, 0x05b036e2, 0x9e732c4f, 0xda05f6cf, + 0xa43365f2, 0xa1707719, 0x3d3ce930, 0xdaa201f0, 0x260142c3, 0xd5f2eaec, 0x26fc10a7, 0xc10f044d, 0x64b4b7e0, + 0x8b092cd1, 0xc5895c41, 0x5000db1f, 0xdf42aa2e, 0x92bffd69, 0x2b6f4b10, 0xfab8fe75, 0x8aabc5f6, 0x6fcf6030, + 0x1d5eb255, 0xc92d1a42, 0x05af67c1, 0x0df3fa0b, 0x1e041187, 0x1cdca169, 0x708bb289, 0x23adeaf5, 0x51b310ed, + 0x5979e282, 0x8acacecd, 0x53edb1ba, 0x5d1b0d71, 0x66fa8b64, 0xca50c67f, 0x6d9a8c51, 0x9bee1f78, 0xa07140b1, + 0x0ff494ac, 0xcffe116b, 0xf83e53f8, 0x11dc38b4, 0xfc0dbcb2, 0xd24d8174, 0x2a655ff1, 0x70f43419, 0x57e3aa8a, + 0x53da271d, 0x1a8b093c, 0x97434db6, 0xe40dffb2, 0x4b483d24, 0x70b51f05, 0x3d25e3cf, 0xe9472a16, 0xab88c55b, + 0x9ed43be3, 0x88d16f4f, 0x3a6b03a8, 0xadba6e7d, 0xd020f1c3, 0xb91e3ba8, 0x80f70de7, 0x2ee87a08, 0x528bcfa9, + 0xbb8d139e, 0xe44eb0fa, 0x3407e146, 0xeab0939f, 0x67bcb76b, 0x126663fe, 0x29682343, 0xa3edf195, 0x9d03ed8c, + 0xa710d32c, 0x0aba1ed8, 0x1f896dec, 0x8087b0a7, 0x15d60007, 0xd5ea6a47, 0x29fa3111, 0xf40375b8, 0x1b9f8988, + 0xc80c56d2, 0x39094020, 0x55b2d0bd, 0x1806b1e7, 0xc60ede03, 0x2e1de5d5, 0x11ca6ff1, 0xe6a5afb8, 0xe522f2e4, + 0x5df4d01f, 0x8e995072, 0xafb69320, 0x52468837, 0xbf4f5fdb, 0x33576ede, 0xad1d994e, 0xe953b081, 0xed2d5aa9, + 0xe89caa77, 0x86a00626, 0x084613b0, 0xc421434c, 0x97feb9b0, 0xadb154a2, 0x75f69eab, 0x874bf2ff, 0x3a0aff49, + 0xfd987a4e, 0x0d18b1b8, 0xb43c6d89, 0x15ce6556, 0xe1225c5d, 0x66de985e, 0x3d2038e3, 0xcd8bcb36, 0x3ada39ef, + 0xf3292eb6, 0x31c80d29, 0x7acfdcd7, 0xab0e8543, 0x9d789e8f, 0x3ef02323, 0xa0369754, 0xfa7f57cc, 0xef623b13, + 0x0698b8ed, 0x7b35142f, 0x8951cf78, 0x34d67a2c, 0xa5170445, 0xbe7c7d09, 0xf63ea350, 0xa4610859, 0x3002c035, + 0x0e30abac, 0xebc2a1df, 0x565ec8c8, 0xe1f78a5f, 0x5eaab708, 0x577dda71, 0x1b21ae97, 0x67d33082, 0x731e1b8e, + 0x9fa4834d, 0x20332fe1, 0x2871ea13, 0xb2506147, 0x3d216fb5, 0xf38852f0, 0x2abac208, 0x47dd73a4, 0x97f5fe0d, + 0xcadf83a4, 0xd2b1e702, 0x11e3c2f0, 0x2319d4ea, 0x7631adb1, 0xdf082a70, 0x030998f7, 0xd19d73f3, 0xbae361de, + 0xa37ca9b0, 0x65dde843, 0x82339586, 0x44191089, 0x83ef815d, 0x6c404b60, 0x69f747ae, 0x2c75627a, 0x6a3d8a76, + 0x54d03afe, 0x0e702436, 0x87618700, 0xa92f594a, 0x785dbcc3, 0x9c762f33, 0x8a35d8b7, 0x8b68856b, 0xf7a72986, + 0x3412720e, 0x4ae419cd, 0x8a7fde4a, 0xefcf02d0, 0x47c51b4e, 0x7e097801, 0x4e5e538f, 0x42ee1e3c, 0x79e9735a, + 0x84ec1d4c, 0xf492ec1d, 0x1e394b3b, 0x5a1df63e, 0xcf41e103, 0x3f424d54, 0x4ae3c55b, 0x3b4bcf51, 0xe006bc85, + 0x6a882dae, 0x07c807ec, 0x8ecd3f6b, 0x510ebde5, 0x40e8ea11, 0x1a947e6b, 0xd829138c, 0x10152437, 0x2867e431, + 0x1ffbab56, 0x12aa1847, 0xc00c7371, 0x46c55518, 0x42d66f3d, 0x7397b1bc, 0xa51db72f, 0x620cd3af, 0xcc51ea2c, + 0xf910d205, 0x325024a8, 0xbedab9f6, 0x847b597e, 0x53153261, 0xf5d301f2, 0x8b30f7b3, 0x967ec7ec, 0x9cc462fd, + 0xcfb4b559, 0x2f0b9835, 0x63d53406, 0x19bf36c7, 0x933e43b2, 0x5b494147, 0xa3f63023, 0x3b64fb54, 0x56787769, + 0x2f1a4f27, 0x07dfeb95, 0x0789b310, 0x3519475b, 0x35bdb28f, 0x4b8f549c, 0xed8b9634, 0x12dfade5, 0x3e484f1b, + 0xee53f86a, 0x7fdedc44, 0xef45cf13, 0xf836a949, 0x0c90b222, 0xca47a7ca, 0x0ab61bae, 0xfdd2ff22, 0x986391db, + 0x02df7ced, 0x58ee6dd1, 0x6ca7e8f4, 0xbf22b223, 0x20909a6b, 0x97bd3ca2, 0x39df16e5, 0x8ae78f74, 0xe326f58c, + 0x794cb404, 0xc1892f8f, 0x322ba43e, 0x205e982e, 0x6c87f5b8, 0x53979612, 0xa16b852f, 0xb8366878, 0x20e9894a, + 0xbe482ca7, 0x4e6e7478, 0x1def935f, 0x765b562d, 0x52f3fce8, 0xc657f8a4, 0xb48f2264, 0x3f208672, 0xa169ae61, + 0xc02164d2, 0x4b94daae, 0x02edafbb, 0xfbd26497, 0x20d9a57d, 0xe1509bf0, 0x451d06e4, 0xc3f102b6, 0xd811cf88, + 0xc3c22be1, 0x256a84bc, 0x10ed841e, 0xe1253333, 0x8ebc1154, 0xc0fe3ec9, 0x261a0cd5, 0x03294586, 0x75e0cd97, + 0x0f46cdfa, 0x84e83ae6, 0x5f54b283, 0x68d913df, 0xcd12c142, 0xe8e9a925, 0xf40818f7, 0x6aa14985, 0xd2975ab8, + 0xf30b256c, 0x04636e74, 0xd738d3dc, 0x73ad7d46, 0x14de12b6, 0x9efe7bdc, 0x525c546a, 0xd5090040, 0xd7bc9785, + 0x572aa464, 0xe8654954, 0xb0c9dce3, 0x48d2e36a, 0x24803cac, 0x989995fd, 0x4d65a34e, 0x3b36f8e1, 0x27703d73, + 0x6504a0cb, 0x587f566e, 0xe067e6e3, 0xd3ce0f64, 0xfd482ad5, 0x449ba984, 0x2d536a80, 0x95f4e22b, 0x36d842c6, + 0x4412332a, 0xa86fb1c5, 0xea6db14f, 0xed0f3b73, 0x7e709a37, 0xaf0ee520, 0x9f9b3aed, 0x9cd9a8a7, 0xd171ab41, + 0xc666a9dd, 0x1b277af0, 0x918debf4, 0x7292386b, 0x0e0407cc, 0x84451046, 0xdf657582, 0x0b1c6750, 0x08f035a1, + 0x600f7988, 0xe7a3a047, 0x86f28e02, 0x73cd2126, 0x3dfeb7d2, 0x6547f858, 0xcca05932, 0x34e98328, 0x89f8ae79, + 0xcfbfcfd7, 0x0a011590, 0x77e0197d, 0x76fd8545, 0x10539b9c, 0x52438e43, 0x3abedbf8, 0x2098b213, 0xd582ba3a, + 0x01117b14, 0x4263361d, 0xaa6ea4a1, 0x03b3682a, 0x84f77bbf, 0x0edd1c00, 0x600a11eb, 0xd43dab62, 0xde64a3a0, + 0x4caad086, 0x5ef5336d, 0x4aa8fa05, 0x40992438, 0xac9c940b, 0xb3d53891, 0x19906f9a, 0x6408f173, 0x662b327b, + 0x4fda62b3, 0xe9600181, 0x518a6df6, 0x85c58453, 0xbb5192ac, 0xe63856eb, 0xa6ed1cdc, 0x20602989, 0x393a61af, + 0xf5579ef4, 0xe20bc1c9, 0x5ad4e14c, 0x198b990c, 0x9c52011d, 0x16e5fbfc, 0xfea51813, 0xc3f90250, 0x571a693c, + 0xbcfed06c, 0xb2f26451, 0x4d8b2cd0, 0x00dbbdc6, 0x85202d13, 0xb810d5ab, 0xb5ba9640, 0x9fa07308, 0x4ac0af6b, + 0xff4c2c24, 0xd09daa0d, 0x9044ab06, 0x964d4175, 0x88f556c7, 0x656e31f2, 0xe0087fe8, 0xc432b408, 0x2ede3bd6, + 0x61c48166, 0x528a872d, 0x8e899bd2, 0xd00d72c5, 0xbf3115d5, 0x67f99831, 0x8cc78a29, 0xecf09b29, 0x217e765b, + 0x270c9319, 0x11837a57, 0x1fc7632f, 0xfe2e7a9e, 0x86cfdffe, 0x70c92ffc, 0x6b441d92, 0x0544e9b8, 0x66a6c138, + 0xac2657c6, 0x3b3cfa95, 0x1b643440, 0x2ac617b8, 0x1bd24ba1, 0xcd53149c, 0x6bedfd32, 0xcaea4f5f, 0xe0f2d53a, + 0x32222cce, 0x62f04f78, 0x281c4aea, 0x92f1d746, 0xddd30925, 0xbce5006b, 0x1964137d, 0x2f339eff, 0x073b06b9, + 0x3806fabd, 0x7cfdd1de, 0x8ea92392, 0xca2bf0c7, 0x6f19258a, 0xf3dfff39, 0x838e7d04, 0x21ee01b5, 0x4f79ad31, + 0xc81dec10, 0x8a021570, 0x032740a9, 0x671404de, 0x64b4f318, 0xe425749a, 0xb9f196ad, 0x752ca164, 0x55918347, + 0xfb3cbd07, 0x4a250a48, 0xf90af985, 0xdf827279, 0x1ff54a6d, 0x73a2e24d, 0x9d8a17a6, 0x22953d50, 0x9ec66708, + 0x21716936, 0x9ff27cd4, 0x66cabc9a, 0x7b15b7f9, 0xafa68161, 0x63ea3760, 0xef7e1f6d, 0x733d72dc, 0xebc902dc, + 0xaa8ecd95, 0xc633714b, 0x77cc13b6, 0x997bfd96, 0x289ab7ca, 0xeba7a264, 0xfd5c5651, 0xc3411a5b, 0x5d834ba4, + 0xd8bf1606, 0xdb24fb68, 0x1b3b9b6b, 0x80bb8791, 0x3f087e8e, 0x41c60f54, 0xe00c8f0a, 0x325554ec, 0xd1a0e434, + 0x4544b041, 0x9c42a29e, 0xb11832d1, 0x5af8ea30, 0xf9a79ab1, 0xb003d5a3, 0x942ca953, 0x582c8920, 0x2db624e1, + 0xe1424060, 0x412a9157, 0xc18d9a94, 0x68a427e4, 0x21cad876, 0xba1be04a, 0xd1ef84a9, 0x08988413, 0xe359ea1f, + 0x4cfe8dbe, 0x59863e1e, 0xf8327125, 0xd9f1753d, 0x77b4a25a, 0xf8b114c3, 0xf4259e25, 0x3d952dfe, 0xa0191376, + 0xe09dcb7f, 0xb761cbca, 0xfede9076, 0xb1404d99, 0xe1fc4db2, 0x00f50f6f, 0x7ae04d6c, 0xb339f845, 0x8ed71398, + 0x3a737281, 0xd04cef9f, 0x57a1615c, 0xef045732, 0x04503c6b, 0xddac7645, 0xa8f9f113, 0x61ef0675, 0xd21eb19a, + 0x0c4d93f9, 0xa485da9c, 0xf2ce65dd, 0xf2245f2d, 0x92090dc0, 0x72d599bb, 0x286d1e79, 0xad640608, 0xc7acf68d, + 0xeda7eb5d, 0x950e6744, 0x3922089f, 0x7b3037f8, 0x9e11b096, 0x7a46bb38, 0x1a15acac, 0x35902c06, 0xcc114eb1, + 0x81e319c8, 0x84c439d1, 0xafc550bf, 0xdc85cf14, 0x696e8ab8, 0x0a2ca729, 0x47c2502e, 0x8cf7732d, 0xb7589765, + 0x076ee187, 0xc4e26443, 0xe1c28f20, 0x8e01fc17, 0x97d32480, 0xcabb61d7, 0x82130285, 0x05aa1ce2, 0x6fd4ffdb, + 0x679b3fe6, 0x3454908f, 0x471e3edc, 0x36336495, 0x0a4739a7, 0x67cbf051, 0x6af0d047, 0x7da98fbb, 0x66174df0, + 0x8f75cbfa, 0xb42d0bca, 0xadceb870, 0x049a5a91, 0xa70439f1, 0xbe5b57ac, 0x856f0055, 0x07805fcc, 0xff4a7940, + 0xba3dd26e, 0xcbe3efbb, 0x90fd3ca6, 0xef180cad, 0xd49a2fe1, 0xeac70e33, 0x47640130, 0xc80fbcfd, 0x60d37b9a, + 0x66157a7f, 0x33b6be90, 0x9b7f1b83, 0x896fbe7d, 0x638886f4, 0x39b0322c, 0x37dcee0c, 0x54771a0c, 0xba7dd17e, + 0x19846706, 0xc08e1d00, 0xe17af913, 0x3221206b, 0x4eab89c7, 0xe589fd1f, 0x42b34450, 0x7fe711da, 0x7d235a38, + 0xbd725ee7, 0x8abcfd6f, 0xff5eb551, 0xdefdf921, 0x11c61d72, 0xc184d800, 0xe0f21ede, 0xbca2053c, 0xd7cce490, + 0x477fd3a2, 0xfef06802, 0xe205b0a1, 0x6796703a, 0x55a826c0, 0x91f7cd58, 0x28fe3da1, 0x68d27f1e, 0xa154309a, + 0xbd85d001, 0x4676e242, 0x2a4df060, 0x48767dfa, 0x7ba2eebf, 0xc3477ae5, 0xaf147174, 0x91fba18a, 0x2784b532, + 0x753a8929, 0xef7923b6, 0x840468d0, 0xee3c5ecc, 0xb98a6df0, 0x6b1977af, 0x59d7d858, 0x044e36dd, 0xc6441e11, + 0x5ab4eb9a, 0xd6954d71, 0xdbeb3110, 0x2ee22ed4, 0x3b09d65e, 0x226ceb8b, 0xf27a3424, 0x09bf27c5, 0xb1c9aac3, + 0x2db6a327, 0x3e15b3f9, 0xaab2e756, 0xd553ed67, 0xb694dba3, 0xee34f592, 0x23381868, 0xbb0d2b4f, 0x20a3cbf8, + 0x31daf122, 0xaf83621e, 0x3f6e3ade, 0x4475370b, 0xd12ddb85, 0x7bb94e5a, 0x970544bf, 0x471571f7, 0x8eecabd5, + 0x448e570b, 0x7e811c48, 0x76705125, 0xf4d7ef8e, 0xdbfa0a3c, 0x9871cfe6, 0xb9f13da2, 0xd06ce447, 0x9bc03f0d, + 0x34a34a38, 0x4b125fda, 0xbcc405cf, 0x3086bfd3, 0xf402de74, 0x693de838, 0x390fb739, 0x0304de02, 0xee05c928, + 0xb9b2b7c5, 0xe8692942, 0xfcff3148, 0xe8b6a95a, 0xba8439a4, 0x94e0ab9d, 0x2b67abe7, 0xf6b887ac, 0xd51d90fc, + 0x0cfe4129, 0x08bedd8f, 0x20aca1e2, 0x2d97f7dc, 0x768baf2c, 0xe070c4cf, 0x887b630a, 0x39226ce3, 0x223d3135, + 0x67087ecc, 0xde71591e, 0x9f449967, 0xe29397da, 0x4c86b95b, 0x9d0e9d46, 0xfd45a499, 0x8dff712c, 0x4b9efb11, + 0x8a7666bd, 0xb34bbc1a, 0xb8edc228, 0xd40a8ef0, 0x1c258871, 0x694cc695, 0x7f4ae6c1, 0x05798857, 0x0b2b387d, + 0xa3eb06f6, 0x26938660, 0xe6be3e7a, 0x9f04da64, 0x280c94cc, 0x88ba3c14, 0xf1eb649e, 0x1fb22abc, 0x3068af2e, + 0xd508d5f7, 0x456a7c1e, 0x755ccda5, 0xab47dfee, 0x37baae20, 0x522d9457, 0xd3bf8559, 0x557a5787, 0x54f484d2, + 0x834f0bf6, 0x90f10bec, 0xc89437f7, 0x40f24d50, 0x7da6c287, 0x85d4673e, 0xf5ef574a, 0x603ad149, 0x776d52f6, + 0xd5ff1c6f, 0x0b6ae110, 0x7f8e75bd, 0x29f34d63, 0x1a591451, 0xb158e06a, 0xb3cbde06, 0x5efa86f8, 0xb750b02e, + 0xa1d7d275, 0x928f8907, 0x7c1a228e, 0x59337335, 0xf7b7d508, 0x0ccea95f, 0xa3425d64, 0xdca257c0, 0xc43ca2f4, + 0xc65aaf40, 0xfee70d4f, 0x2e4112db, 0xbb52a3fd, 0x617d350f, 0x0235fb8d, 0x2738b3a4, 0x94e0034f, 0x57b28e1d, + 0x1eb54cc6, 0xec150a15, 0x4129a4ba, 0xa4e0a2df, 0x9c47a5ed, 0x8d963a28, 0x9b51b089, 0xcdd65aae, 0xc4bc26f6, + 0xeab4f15f, 0xc03f5105, 0xbbf8d7a1, 0xbbedb86b, 0x4ff3abf6, 0x4cf91f47, 0x81e3468b, 0x0203924a, 0x1280b5c1, + 0xfbeafea1, 0xa515e378, 0xa0af03eb, 0xc8ef5d11, 0x0bb01526, 0xae116bd4, 0xfec987bf, 0x455b2152, 0xa573f4cf, + 0xf7080fa4, 0x5186a1df, 0xb680ffe9, 0x18dac264, 0x3fc55505, 0xadc52c04, 0xab52b9a3, 0xb43d0280, 0xbbce7dc7, + 0x85a91ee6, 0x71ef84de, 0x4c0fd9fd, 0x3096c86f, 0x4804c9b7, 0x8c3e5aad, 0xdf5ba9cc, 0x6a8d1d59, 0x17525e19, + 0x85a919f9, 0xe8d2ae05, 0x4fd7bc70, 0x25fb552a, 0x17ed91e4, 0xb1fcf491, 0xd207fadf, 0x987b012a, 0x7570c3e8, + 0x4ab8eee5, 0x120b730d, 0x6ed38b5d, 0xb957464f, 0xd5d803dd, 0xf6b76176, 0x9d5f8513, 0x9a7ebda1, 0x5f4c70cf, + 0x25c56da4, 0x6dc8a442, 0x5eff37d7, 0x509f5861, 0x786958c1, 0x0dd17bda, 0x927069bb, 0xec2889c8, 0xb747b354, + 0x3504c4f1, 0x94258395, 0x05836f5e, 0x12068054, 0x42751853, 0x05859782, 0x784882ad, 0xc3988e94, 0x20c7eb21, + 0x6f5d9be5, 0x23840867, 0xfc160e47, 0xbb3bfe14, 0x2497e7ee, 0x42e5f8c2, 0xbdb0d262, 0x97d52dd1, 0x512c6081, + 0xf2beb1b9, 0xdab5a157, 0x9a86a417, 0x1f9a1932, 0xcf9da6e5, 0xf82d53a0, 0x2b0baa7e, 0x2327b4a2, 0xd71a161a, + 0xdf403475, 0x948bfb49, 0x24fc9862, 0x225123cf, 0xced76b57, 0x755bc1ec, 0xd0a2dc53, 0x64bfa749, 0xeca16661, + 0x61183c53, 0xcbbf1397, 0x49c5459a, 0x18e394b2, 0x1be4f48c, 0xf7d8ec91, 0xd81fc5c6, 0xcdb1c20b, 0xfe3c90b0, + 0x4b836637, 0x556781e5, 0x5af18ba0, 0xf0e454e4, 0x79278ba0, 0xe0c76baf, 0xb36c577e, 0xa23b9489, 0x11305ed4, + 0x1b2cf419, 0x250a4de5, 0xe5cf8de5, 0xc5aba253, 0xaba81623, 0xbf255563, 0x5956abd8, 0x54354af8, 0xae4ae23e, + 0x138d859c, 0xb6ab68ea, 0x28c55e2c, 0x5dc5e110, 0xb467d47c, 0xc3cc8685, 0xe1566c24, 0x322c8890, 0x677857fe, + 0xfe8eb38f, 0x0b61ea66, 0xddd1b4ca, 0x6f1cbf51, 0x44f08357, 0xcbe21396, 0x744fe8b9, 0x143b958b, 0xab05e6fe, + 0x3c54dcd1, 0xa5b694a5, 0x0030a4b7, 0x254a05bb, 0x4214883d, 0xd53902f1, 0xcc0e599a, 0x22298028, 0xa55470d9, + 0xbee9ff6c, 0xaf1e2a5e, 0x0f69d102, 0xfc02aa22, 0x19f1d3c7, 0xb6aa4ebe, 0xf1751cec, 0x8a0ae852, 0xd180a904, + 0xad8605a1, 0xb5f57878, 0x6b6db0ed, 0xaaf42553, 0x64f45bb7, 0x9ff787a7, 0x84e527c0, 0xb2839040, 0x4f044fec, + 0x14cbd950, 0x522ae19f, 0x0030916b, 0x517635ca, 0xc3a74420, 0xf13d6a0e, 0xeadd4b6e, 0x8e20585b, 0x0b36ab20, + 0x5f6b6be3, 0x6126831b, 0xdf84a59f, 0x4dd6380d, 0xb77899f2, 0xbb5e5703, 0xf2086ddc, 0x6532cc3a, 0xdb8aa73e, + 0x6570ee92, 0xf32f68c8, 0x019ddfdf, 0xa57896e4, 0xc10e0c77, 0xe3f15ffe, 0x900e26cc, 0x3cd78e47, 0x14354762, + 0x9d6a699a, 0x3ab5c295, 0x15bd0b3f, 0x751f7fab, 0x134faaa0, 0x70e112a9, 0xad293978, 0xdf35c6f2, 0x4ba653e2, + 0xc4fefeb4, 0x5b4e5baf, 0xefb1d2dd, 0xf79e0d2b, 0xbc488b42, 0xe7f21b7d, 0x5aa9157d, 0x6b86dec9, 0x835312f6, + 0x6adf72e9, 0xf613d479, 0xa2379126, 0xefe91cb2, 0x124d80d8, 0xf810e5b7, 0xa9780fd0, 0x15f06bb7, 0x50145248, + 0x502c59c2, 0xc8271ed4, 0x718152d3, 0xb138b95b, 0xfb031cf7, 0x5c4d4895, 0x7aa222ac, 0x566cacfc, 0x3283df05, + 0xe3b5f754, 0x91288231, 0xeb9b4a58, 0x3ab36dfe, 0xae69ec8f, 0xf9e33e4e, 0xbe85bb36, 0x870dca46, 0x7154ead6, + 0x6c3d6885, 0xde765276, 0x09309ecf, 0x5d1c9e35, 0x7cd844a9, 0xa1252152, 0x9967ff0d, 0xa792dde0, 0x2b5e20c1, + 0xebccd1cb, 0x3ceb2b15, 0x49538aae, 0xc1ae7073, 0x10ea8682, 0x6afbba45, 0xe0973996, 0xda059f47, 0xc5fdac19, + 0x7f0f74b3, 0x424d8f46, 0xfd844473, 0x2a8aebd0, 0x69dc3074, 0x86fe309d, 0x55c9310e, 0x0d7f978c, 0xc6dbee41, + 0x19c6edb1, 0x95c916c1, 0x77110905, 0x17deb9f5, 0x8bd33b28, 0xb483f91c, 0x1121b3cc, 0xf6233cb6, 0xef243748, + 0x9271a226, 0x01d89f4a, 0x2338f83f, 0x215fdd9c, 0xc62470c2, 0x6159032f, 0x7c523bea, 0x1d80e70b, 0x49d67bf1, + 0xbf6fd8c2, 0x6555f052, 0x224ac6ca, 0x1095a7fa, 0xf4161b64, 0xd3023679, 0x97f93cf6, 0xe8d0a971, 0x7355a50a, + 0xed4a763f, 0x977bffbc, 0xde073c28, 0x52826765, 0x97e44e42, 0xaed68ae8, 0x8ace251f, 0x71edc9de, 0x16cab2c1, + 0x96eddbcc, 0xfb734d47, 0x71480c74, 0x84b94b94, 0x6c236c04, 0x4d0c3de6, 0xb562e004, 0x3a986190, 0xadc294cd, + 0x3b006f5a, 0x2146b5c3, 0x196571c0, 0xdc6552e2, 0xfa52b97f, 0x11f974b4, 0x7b966641, 0x23f081fa, 0xae22a48c, + 0x056ebc03, 0x5dbb6742, 0x273b0378, 0x19f09b75, 0x35fc426a, 0x16c0e434, 0x97eb86cb, 0x323f6f61, 0x077820d4, + 0x2ae697d9, 0x2dca47ac, 0xe4b2af3d, 0xb53f500f, 0x7f8e17d1, 0xdcda13a7, 0xc531b97e, 0xdca522c0, 0x226ed058, + 0x90551792, 0x175e9a12, 0x53d3838c, 0x12f4451f, 0x738d2aea, 0xeb18a832, 0x5646355b, 0x8695d90d, 0x2a87de20, + 0x237b5c4d, 0x7d56d740, 0x8696dd8f, 0x0eee469e, 0x0477d2be, 0x76420bfe, 0xbfc3c534, 0x2d734253, 0x14749579, + 0x33a47713, 0xf58375b0, 0x9db44d59, 0x5dd5a550, 0x9594103c, 0x672172b6, 0x9721a601, 0xf22bce5d, 0xc6078ab6, + 0xc214a017, 0x7d2bcd16, 0x4461cdaa, 0xe9fcccc3, 0x9dd03af7, 0x00d0ab31, 0x4044ba0f, 0x079023d6, 0x3356d18f, + 0x07f4cc75, 0x8a15eaca, 0xd7e93425, 0x8f749cb9, 0x7f0da3b7, 0x927a943d, 0x23258aa0, 0xe65189c4, 0x1a97f8e7, + 0xbc772ba8, 0xec579f52, 0x31bca957, 0x0ff87e8a, 0xdba76ad6, 0x98d22cb6, 0xc20f56e0, 0xa647618b, 0xfcafe613, + 0x0b792c28, 0xd0d3d611, 0xb0206927, 0x91bee8e4, 0xe275c131, 0x5eb76a17, 0xb3aa5551, 0xd2709740, 0xbd98bfa9, + 0x82d101bb, 0x17ec637e, 0xa1f440a2, 0x4e8ba3f9, 0x22e2e36d, 0xca6a319d, 0xfbb6696c, 0x14137e4b, 0xfd07b93a, + 0x88187f43, 0xe25ec3c6, 0xeed94802, 0xd3cc9ee2, 0xbf24a2cb, 0x6a135c35, 0x0e03b434, 0x4ec89ccd, 0x6ea06429, + 0xd48a5822, 0x10189fcd, 0x4d8f8ce1, 0x1fb21f86, 0xdd542d32, 0x944bd3ec, 0x6df5785b, 0x588b4182, 0xf9fd1d64, + 0x94ff2b13, 0xd01c64b0, 0x02e8d32f, 0xfb51a649, 0x675b91f2, 0xe468ebcd, 0x0b78ef1b, 0x32bd69e0, 0x977084b2, + 0xedee1dc9, 0x54a06b39, 0xb4c0719d, 0x8b8f4989, 0x608d4eaa, 0x034e4683, 0xb2558cd0, 0x4feb8c0d, 0xc6a764c6, + 0x97c6225f, 0xb90e31e6, 0xcb6f3bcb, 0x29c445da, 0xf445a686, 0x83fdbecc, 0xd968f247, 0x868d2474, 0x9bd3cb08, + 0xa0f84f35, 0x91e211ad, 0x93a8c50a, 0x44a68fa8, 0x05aa1550, 0x1fe3a0b7, 0xe31f0d49, 0x6b7586d5, 0xb259cc82, + 0xf4c1cb1f, 0x942452d9, 0x4ea1beab, 0xa47b1a74, 0x7d1f64d5, 0x4afff063, 0x8533476d, 0x57313806, 0xf63d7c84, + 0xe3b34678, 0x8d5f885a, 0x4b28b571, 0xf975ed59, 0x895c16da, 0x30c3bc0c, 0x8ebbba49, 0x212ec712, 0x189c94ef, + 0xe2de388d, 0x12b13ee8, 0xed353d9e, 0xb62fedf6, 0x1c0c0536, 0x77d7ab11, 0x25b7c9ae, 0x69b40dc5, 0x5bf65ca2, + 0x8e4af743, 0xdee6c528, 0xd9c226e8, 0xddeb659c, 0xfbd87368, 0x0a0c0944, 0x2e1dcc24, 0xd1d71331, 0x6ca6d66d, + 0x9aa7ed35, 0x89f4b92e, 0xebe97071, 0x14f55b49, 0x4bad0750, 0xe692d6b0, 0xe51f95c9, 0xbd618500, 0x0230a9eb, + 0x3b6ee594, 0xba3212db, 0x96e1dc9e, 0xb6a8ed36, 0x0e939743, 0x52fad7e9, 0x3ce8c1b0, 0x31d9ba70, 0x6f0cde45, + 0x162f7ba0, 0x694fcbd7, 0x06d9a23b, 0xecffd9c6, 0xa0ac4b0a, 0x6004d03f, 0x8a6d36d8, 0xa616d57d, 0x9ea25802, + 0x65fe2b0e, 0x0f2c1340, 0xba689a69, 0x03c0caba, 0xc2c2867c, 0x74508495, 0x5d7e5ff7, 0x5f44a6ee, 0xe05a8d92, + 0x20641689, 0x7cefbb52, 0xb3abf4b1, 0x68258b5d, 0xfcab5325, 0x9d01fb49, 0x883ff097, 0xda553543, 0x3a09bd66, + 0x9ec26962, 0x12316d11, 0x9bafc881, 0x453c698c, 0x5b1d47c8, 0x707bf851, 0x7bd92353, 0x8179137d, 0xd6d03391, + 0xd490037d, 0x9265db64, 0x28e997af, 0xa742c9ab, 0xfbc8f9ee, 0x1976804e, 0xd7532d61, 0x0f81c023, 0x53457024, + 0x95ebafb7, 0xa5e16160, 0x7cfb5806, 0x73eaff15, 0x934d782b, 0x0ea9c60e, 0xa1e6b17c, 0x3231b481, 0xdb2f5923, + 0x23207cae, 0x8d5f5867, 0xa2165d07, 0xb312e6ca, 0xfa28b7d8, 0x0bdb5355, 0x73c38cf3, 0x95ed4789, 0x26e8d8af, + 0x38e0e6c3, 0xb7e8cb7e, 0x0cfeeefd, 0xbc8ea901, 0x0030d958, 0xd0d597d2, 0xfcad5b25, 0x5d950693, 0x131f4e81, + 0x421fb3dd, 0x723a94b2, 0x13d1549d, 0x5eff5c43, 0xc7199ac4, 0x06be9094, 0x1345abea, 0x6cecd91d, 0xfc78a14c, + 0x39b505d3, 0x55f77bfc, 0x2f4c8894, 0x00d9ca3b, 0x588a852b, 0x54232571, 0xfa1d3614, 0xce893159, 0xa7eb369c, + 0x1720d0b3, 0xc7493369, 0xe6d03427, 0x7ac9cd9d, 0x225b4f73, 0x4e5c46e3, 0x0326de68, 0x398bd1f6, 0xfd8ae901, + 0xcc027be3, 0xdbd37a6f, 0x1187778e, 0xb80e1e44, 0x3bac8341, 0x4045becd, 0x83678105, 0x361d5b98, 0xc041b4ab, + 0x0ff20c75, 0x6d85769e, 0xcfdf8eba, 0x66ede2b8, 0x7546fabc, 0x31a585d8, 0xd95d8b6c, 0xcd820ba4, 0x17e5f470, + 0x74ebec06, 0x24c2c8ac, 0x58a8324d, 0x88d28336, 0x1d2cb81e, 0xa3737889, 0x83cb6246, 0xb4870a7b, 0x40e7ce15, + 0xe6c2d647, 0x7ce1cda2, 0xf519577e, 0xeb98139a, 0xb188dbcf, 0x410a8fef, 0xb32c0ac0, 0x26934fb0, 0xfe6bb85b, + 0xe6e7e321, 0xfe3815cb, 0x39891e92, 0x9ea928a0, 0x808848c2, 0xaef16ded, 0xf3f5d35d, 0x3f4d699e, 0x61750dc2, + 0xfc61f29b, 0x16949d63, 0xad27b6ae, 0xe7f80937, 0x8d2ccdd7, 0xf0c5575e, 0x27ec8ca0, 0x76f87a58, 0xb4acd187, + 0xbc6eca0c, 0xcdd03f43, 0x1636010f, 0x7c569d41, 0xcf6720a5, 0x5a1e05d3, 0xc88dbbac, 0x537ceaf9, 0xd2d1567c, + 0x471cf798, 0xfc4ea62a, 0x40085c14, 0x8a2f153b, 0xd340d9a4, 0x5e62d588, 0x0b4cbbc4, 0x2af9446b, 0x74a4ec51, + 0x0b60cb45, 0x2880985a, 0x98b7ca90, 0x84884828, 0xd8b729c2, 0x160cf0e2, 0x8b9e0a33, 0xd528ff1c, 0xf3713f27, + 0x53789656, 0xfd8d1603, 0xf199d50d, 0xd76ef7f1, 0x1cd59be4, 0xc1f5f721, 0xc299c87e, 0x9f0378aa, 0x112cfe71, + 0xb0bdbdf6, 0x20e7ea47, 0x0a04f32a, 0xe613f10c, 0x277b4935, 0xb8752a42, 0x456313a4, 0xd7091a19, 0x15c24e40, + 0xb2218afa, 0x1c6fa453, 0x4333f97b, 0x8143703d, 0x4205ffdb, 0xf53435cb, 0x90f06e14, 0x125e7710, 0x3e8b817b, + 0x4efc46c7, 0x220aca2c, 0x29ad3364, 0x209d4a4a, 0xe5fb6179, 0xa2cff83c, 0xdf718e93, 0x8c81498d, 0xaa8486b3, + 0x308de16e, 0x844c793a, 0x7e1e2d40, 0xee069493, 0xa1cc8fcb, 0x21612b7b, 0x9294c821, 0xc640f204, 0x3531fdf6, + 0x2787b76d, 0x98432667, 0x27de809e, 0x71e85079, 0xa68d1b3f, 0xcd155b42, 0xfd2ce635, 0xf85224f4, 0xb3cee050, + 0x45447425, 0xa3bcc3f6, 0x7b391115, 0x6c83c7ef, 0xb372e7b8, 0x6b624482, 0xc9a8beec, 0xcd430082, 0xf1eb550d, + 0xee59781d, 0xd0588afd, 0xf799e61e, 0x54b9434e, 0xdc85c5a8, 0x18dfdd47, 0x128a80f3, 0xdccf26be, 0xeb845176, + 0x93b7d3b8, 0xc4ab1f61, 0x9aa83897, 0x581681f5, 0xf71d557c, 0xcbf9bb05, 0xa1d5817f, 0x1a32e7f3, 0x6af2c6e2, + 0xe69f42d7, 0x2bdef124, 0x17477b10, 0x8daf1655, 0xb66c34c9, 0xd7581a72, 0x136ce945, 0x20d22044, 0xf7b3ce34, + 0xd09db28c, 0xabf654e2, 0xc7bcb6bd, 0x3d3d6f97, 0x42200aaa, 0x6d1f91e3, 0xf184c3d4, 0x89833d4b, 0x28e6804d, + 0x1621d342, 0x2a4bad38, 0x11f41b4b, 0x8fe52cd3, 0x4fa4225b, 0x4ccea7e4, 0x3dd43888, 0x56f9f22e, 0xf3bf36ea, + 0x7838d875, 0xc2ab6978, 0x62b79fa5, 0x04409b8e, 0x8c416081, 0x07aeaecc, 0x2f239e11, 0x84545410, 0x5211d675, + 0x364eb6bc, 0xb789ea7c, 0x9fe64366, 0xf90b449e, 0x062481dc, 0xdf347d37, 0x7dd71cb3, 0xc451d00a, 0xc04dbadf, + 0x18c3df35, 0xdf32c4e8, 0x570372ee, 0xeb5bb1df, 0xbbae95e5, 0x77e7e52b, 0x059718fc, 0x71c41a94, 0x3fcd86e2, + 0x3972c4b6, 0x6de00867, 0xecd860d6, 0x5b4fa575, 0x64fe7e9b, 0xbc2421ee, 0x1b272e20, 0x81f55f73, 0xa4ec1311, + 0xc0c1ca2d, 0x9c11979a, 0x2dc5ab1a, 0x79905742, 0x13b3c373, 0xe4f47f7a, 0x594faf39, 0xa7d76a91, 0xc9c8091d, + 0xf2e79d66, 0xe0909c89, 0x8a05d398, 0x4a52b86f, 0x35fc9e62, 0xca009dfd, 0x2a5f31c0, 0xaa19da7c, 0x9da05481, + 0xf6a03189, 0x12f8c923, 0x36527327, 0x181d6027, 0x775fe5e4, 0x4bf77ef2, 0x2500da96, 0x6be8464f, 0xdac0173a, + 0xf771709c, 0x6e73f62b, 0x25583611, 0x5416bb9b, 0xb8092dfd, 0x72d102a2, 0x8bc34b1b, 0x51c8ca6f, 0x3078be98, + 0x85efe4bb, 0x4d023799, 0x696001e1, 0x45925265, 0xdf08155e, 0xd72f8eea, 0xb9d47b44, 0xcd095557, 0xb762d1d6, + 0x9c514142, 0xcad5396d, 0x744f3676, 0xe7dc649a, 0x6c43812a, 0x801df11e, 0x21421cfd, 0x464353ec, 0xf12a5ced, + 0x0e66b69a, 0x5b1e2274, 0xc52a3263, 0xc1b5f6e9, 0x449fb2b4, 0x832ba657, 0x6462b723, 0xf203e9b0, 0xfcf70f45, + 0x08ba5c5d, 0xcb96b4a0, 0x5985a570, 0x3744a5d8, 0x8f3e40dc, 0x8aee405d, 0xefab98e8, 0xaad27da9, 0xbb608302, + 0x770bdaf0, 0xe5a4c61d, 0x29e211bc, 0xf276b5b9, 0x0570c799, 0x321e508e, 0xdd1abc1a, 0xc8346064, 0x1b803a8c, + 0x9f44ab31, 0x58c83412, 0xcd859c18, 0xb82f1a9a, 0xb2e21376, 0x46a001ec, 0xccc78404, 0x75306cc2, 0x19abe50d, + 0xabcdd001, 0x933ae5ee, 0x29173e05, 0x7f27199a, 0x8b1456ac, 0xcf4fd945, 0xc769ab6f, 0x4125d2e1, 0x8ce679f3, + 0x24440b14, 0xeaa8742d, 0x743fb658, 0x095ac15b, 0x581d1bea, 0x92bd1033, 0x79a1da49, 0x424646c0, 0xe0347bc9, + 0x7dcf0021, 0xb421b43a, 0xc8be6615, 0x652f8cd9, 0x46cb3782, 0xf3bab7a4, 0xa2839090, 0x34c2785b, 0x705fa7a4, + 0xaa1d7083, 0xc732c292, 0x1fef7f0d, 0x474c09aa, 0x4a0355d2, 0xca029351, 0xceca09e4, 0xd8e3ab36, 0xe71efe2d, + 0x37666710, 0x4f32e5be, 0x65345af7, 0x47352116, 0x23535b8c, 0x57927b0b, 0x3e1a39b7, 0xbbcae9b6, 0x45b7e2b1, + 0xc8e2ee92, 0xb937c795, 0x83a0da63, 0x5f560ba0, 0x695dd28a, 0xcb6adf60, 0xfd5036ba, 0x154daa33, 0x15c39118, + 0xa77278bb, 0xe538e188, 0xe6b717b9, 0x11c3b802, 0xfa91bc78, 0x3bd5c85e, 0x089bef8a, 0x2263562a, 0xda4e7b59, + 0xe1698e2a, 0xed472ee2, 0x85268f92, 0x36ae9c0c, 0x2e31b796, 0x47d96081, 0x162c6c0d, 0xf9fe6fc6, 0xb2f21cba, + 0x083b64ac, 0x26991fae, 0x021480da, 0x0a9be338, 0x0cb597d1, 0xf82bdb93, 0x99674c09, 0xc2ef2ee3, 0xea6b9298, + 0x287626c3, 0xceaf5b22, 0xf33625a1, 0xb60b2bfb, 0xd85c6ca5, 0x6a19e7a7, 0x82a3f0ee, 0x089f85b9, 0x97df6de9, + 0x44bdbf1a, 0xa2a96965, 0x7078e4cf, 0x1b2ad738, 0xb4fff8d0, 0xbdff601d, 0x0dac0408, 0x9f9d3f76, 0x9f14276d, + 0x17cf39fa, 0x29228766, 0x52f50e91, 0x9fa7cb0d, 0xe8ae194b, 0xbbf7c1e8, 0x4f4a30ff, 0x8af60b3e, 0x7cd1292d, + 0x33f0c0ed, 0x5f55860f, 0x66dc282f, 0xe8377ef8, 0x5909fddb, 0xdc216942, 0x293b713f, 0xc7ee7977, 0xcac17ff5, + 0xd161ebf6, 0x287e4467, 0x665c78e6, 0xcf99a6e1, 0xd5cc878c, 0xfe8e30db, 0xfd8c31ac, 0x21e6ba64, 0xe59f64ef, + 0x4967b191, 0xb16b7f1c, 0xfa850359, 0xf8cad6e8, 0xec8d08e6, 0x59c82330, 0x86627afd, 0x28e9daab, 0x67d52436, + 0xe2ac95d8, 0xb9015a43, 0x15e80aa0, 0x29721ef6, 0x9677b030, 0x35940848, 0xd63e8c9d, 0x351a0313, 0x7f8fc681, + 0x34e57823, 0x52515564, 0xd834ebbe, 0x8dfa3ce5, 0x6f572947, 0x2f174c8c, 0xd7e919a5, 0xd0d970c8, 0x4fe42fa9, + 0x3214e3e4, 0xd8936f03, 0xd38db567, 0x7c29cb4f, 0xf6257d39, 0x5c065baf, 0xefe6255e, 0x88da2ce9, 0x2e16ec46, + 0xfcef6a1d, 0xe1b02b8a, 0x971e3d83, 0x340ae725, 0xdcd77616, 0x836a6d55, 0xba478746, 0x2abede00, 0xccb94c2e, + 0xd010d04e, 0x154f28db, 0x5461fba8, 0x09666baa, 0x697fae45, 0x1dcff8e9, 0x46b154a3, 0xc7c91ab9, 0xa467715c, + 0x0aa020a4, 0xd075bd9a, 0x7ad8a641, 0x11a9eaa8, 0x6f298a1c, 0xc7303180, 0x4638c946, 0x2e64814f, 0x07937bef, + 0x9b4324a5, 0x8ea76d5c, 0x686e667e, 0xbd83ce6b, 0x394931f1, 0x447a1bfe, 0xa4cc4f0b, 0x72762bd6, 0x4bc9b299, + 0xc21a7c63, 0x025a37b9, 0x7712637c, 0xae402638, 0xed12169c, 0x515e1324, 0xad388867, 0x13c01940, 0x97fea327, + 0x27a09be5, 0xd1a52c37, 0x656fa21f, 0x4ddd40c6, 0xa7c66fe6, 0x1ab2dfd3, 0xd19cb225, 0x1489b389, 0x8f9ae842, + 0xd3da037f, 0x43dfe8c3, 0x1beff226, 0x73a4b143, 0x724052c3, 0xea9b1b0c, 0x133567f0, 0x6dfc58b4, 0x4f78cdc2, + 0x63b217e6, 0x62e2ac32, 0x433ce2cf, 0xcfa7487f, 0x8facf052, 0x8ce4b2b1, 0x6225f7f7, 0x2ab1dabc, 0x1c80bec1, + 0x06eab75e, 0xa586df6e, 0x5bbca8c6, 0x7e10bf8f, 0xf49d5d5c, 0x7b7aa072, 0x66fd9972, 0x4722d3c9, 0x20628631, + 0x920d6e22, 0x337e7dca, 0xd65f451a, 0x6d6eee04, 0x5ad86d55, 0xbde011ce, 0x237b3f36, 0x1ce3c964, 0xe4332869, + 0x5724a4b7, 0x3705a9d6, 0xe7b47b21, 0x8193189a, 0xe9b47c7c, 0xe53d7a0c, 0x93bf2297, 0xb28934af, 0x0eaaac60, + 0x77dcc6ef, 0x11a20fe5, 0xc5eb96b4, 0x5c74927b, 0xe8f4bf26, 0xbb61eafd, 0xe7b74a40, 0x70e588c0, 0xdd3a5f89, + 0x5e69cc54, 0x0f960107, 0xfab1aef0, 0x3e58b1be, 0x87041330, 0xd9e580ef, 0x6f7b3f5f, 0x8d53c2aa, 0x9bfa66eb, + 0x1013d5df, 0x3c4bf1fc, 0xf9a53973, 0x08f1ce49, 0x7f28caa1, 0x56c89ae9, 0x9ec6fa3c, 0x2b28bfef, 0x0b331f11, + 0xd94e1c15, 0x8fe4fe9c, 0xa4879d84, 0x438d0cfc, 0xb6704b5f, 0xfb11ec4f, 0xbb1fa27d, 0xa12406b7, 0x56298c96, + 0x039b145a, 0x8b487338, 0x463c19db, 0x486fe798, 0xe17047d7, 0xc6cb4de7, 0xc17283a2, 0xe8ec6d09, 0x62b52ebd, + 0xfe922652, 0xed1e72f4, 0x56e9d697, 0x6cb2467a, 0xde8dd18f, 0x8d552a2b, 0x1adbe5f8, 0xf5a4684e, 0xb9b87bcb, + 0xe3b63b5a, 0x7dc9e5b3, 0x18c04264, 0xd05db611, 0xc1123931, 0x554c7bfc, 0xb3354e70, 0x15b2bdc0, 0xc13c90de, + 0xb3f9212c, 0x05065064, 0x6f7e4f6a, 0xb230a8ac, 0xafc06196, 0x626578fc, 0x8eaad2c9, 0x5e6012ab, 0x730bdac3, + 0xd7f3e9aa, 0xe2a846e6, 0x776481ed, 0x735e3ebd, 0x77db7192, 0x1b15cd0e, 0xc933cabf, 0xe1b6c906, 0x548c2da0, + 0x8f9363e9, 0x11e6504f, 0x6ef19803, 0x36d2071c, 0xce0966c3, 0x7e811f35, 0x3f87fb13, 0x97771c4b, 0xfc26f57f, + 0xbd0346f0, 0xe839a13d, 0xb5377036, 0x8e0ddee3, 0xa8b416a2, 0x62318f05, 0x08cae41d, 0xe5f2121f, 0x52939d59, + 0x03b33031, 0x8f8ae94a, 0x0184ff8b, 0xac95d623, 0xa181aeee, 0x1a453685, 0x00f0f333, 0x64c25b6a, 0x99259e86, + 0xf5e9fabc, 0x1b1e70d8, 0xd36ad6d7, 0x2063ff61, 0xb111138e, 0x13dbc2cf, 0xfeeb74ce, 0x33b41811, 0x894f12f3, + 0x7952a307, 0xf1abd6ce, 0x4a039bef, 0x8f4cc102, 0x91f47356, 0x7c753fef, 0x0cbe1c94, 0x00493d48, 0x497235b8, + 0x4d85f089, 0x0032a4be, 0x796b81fa, 0x3f235021, 0xab5b18fe, 0xd3cbe040, 0xf87a0217, 0xd3d3dc53, 0x21f9ddc7, + 0xca7ac635, 0xdbd25553, 0x8c958d7e, 0x15cedd71, 0xa9793024, 0x12509b48, 0x888cb7b2, 0x1cd9acae, 0x274e2982, + 0x333b496c, 0xdd64d085, 0x929fc5c7, 0x8f7ffc45, 0x5afddcda, 0x9ecb7fae, 0x09cbfc8a, 0xb6e32db9, 0xdb622118, + 0x444dd377, 0xb3b6a34b, 0xc8857faa, 0x6ced7f5f, 0xbade9c5b, 0x5ddbab3f, 0xeeb6dd39, 0xdd6629cf, 0xeb726db6, + 0x549a94f1, 0x63d3a647, 0xe61454b1, 0x21bbddb4, 0xde185688, 0xd848c30f, 0x61b2e6d5, 0x8fa92e76, 0x4a12dbc4, + 0x7f3f5c5b, 0xd35a7bb7, 0x80b83b62, 0x487f14df, 0xbd768ef6, 0x251b9eb6, 0x88566ac5, 0x951500b3, 0x4897da96, + 0x809c2d56, 0xc76b88b9, 0xef2d6ccc, 0x0170c749, 0xae9c7dea, 0xd1575d93, 0x02a099c5, 0x58e6b760, 0xd3219757, + 0x9cdb4ee1, 0xf0f0ec22, 0x280ee29d, 0xfcfdcba4, 0x91f237bc, 0x85349612, 0x1fd38aee, 0xe3792055, 0x204bce7e, + 0x2f50b539, 0xa2082d5d, 0x68128731, 0x84e1a93e, 0x78e48d85, 0xf9dd0570, 0x59f0681b, 0xa1284be1, 0x543cb643, + 0xa7462589, 0x19905dc2, 0xe20a0cac, 0xcfb815cd, 0x62010ea7, 0x603a5d9a, 0x4dfc7b67, 0xc6104ff2, 0x628835cf, + 0x1ae664b9, 0xbf2529f4, 0xf7b64a26, 0xfaae18ac, 0x6a07d075, 0xf6396e8e, 0xf3181ce8, 0x1f66f06e, 0xbc3d791e, + 0xe68b4cac, 0x6a328b68, 0xcbebfa49, 0xd7f8cf70, 0x094bca45, 0x346edc19, 0xf291b889, 0x2fbcc4d8, 0x4355da3c, + 0x050b9863, 0x430de159, 0x1783245e, 0xc9fb02d2, 0x37dd8ac3, 0xc9ff15e6, 0x04d8b7e2, 0x9a6e011b, 0xd535cee2, + 0x58b189dd, 0x555b6be9, 0xf4163d2b, 0x7f1fc2f1, 0x2d915c6a, 0x1c454c6d, 0x722f0dd6, 0x5084c3fe, 0x95cfe57a, + 0xf43ccc64, 0x4aea8c07, 0x0efe38ee, 0x395629a0, 0xeb481b9d, 0xcff69b54, 0xf55b121e, 0x842542cc, 0x5d947fcd, + 0x10d8fba1, 0xdfe72d91, 0x4ba9e691, 0x2829eafe, 0xe1c7a58b, 0x91d1c5d8, 0x334c1a76, 0xfd8a76b3, 0x098aaa29, + 0x7208b0a7, 0xd218c592, 0x4391c86d, 0x5492be67, 0xfac44e7b, 0x4a87c6ab, 0x9f57521e, 0x6079edfa, 0xc0eecba8, + 0x8ea4658b, 0x9826afe7, 0x16a739fd, 0x323364f5, 0xdbcf0f8b, 0xbab72a26, 0x72e88b4e, 0xcfcf322d, 0x77b781fa, + 0xf7914ec6, 0x13d21517, 0xa680ed44, 0x36b0f5eb, 0x4c9db0c8, 0xdbcc6d16, 0xf53ddcd1, 0x7208d83a, 0x13f086dd, + 0x2ee7684d, 0x73e98701, 0x8aa905c5, 0x82ea2156, 0xe3081ae4, 0xde619f03, 0xa371e0f5, 0x64bd7d0d, 0x18d5d09b, + 0xbbbc7c03, 0xe6a09c22, 0xf8ca08e6, 0x67c06127, 0x4d8b9f91, 0xa3907d27, 0x85fcde07, 0x7673f42f, 0x9c73bc59, + 0x0bf57423, 0xd36d6041, 0x1ba9a920, 0x5bf62d1f, 0xd1b43b6d, 0xc0f66b26, 0xbf91a7e1, 0x3d8cf29e, 0x662919ab, + 0xba5cfad7, 0x1b36a896, 0xfa65809d, 0x251a3cea, 0x8404698d, 0x0b369623, 0x8e1f646a, 0x724c6598, 0xb3fac1ac, + 0xbcded676, 0x0231d169, 0x6282bd49, 0x4a4d72c0, 0x5b83671b, 0xc0520cfa, 0x97e95cea, 0xd46c9aa1, 0x24f1022c, + 0x3bdd4e67, 0xd992e377, 0x42022263, 0x1745f402, 0x0630362a, 0xcbdbb2fc, 0x241c8bdd, 0x69a394fd, 0xfd00d732, + 0x12b58f8d, 0x15930aab, 0x3f84b134, 0x1bc70718, 0x36a6ee7d, 0x0cab7f94, 0x37a5016a, 0x0f8d4c24, 0x605bbf2b, + 0x07dced77, 0x63df0a1d, 0x5de1ab4c, 0xbde15af7, 0x45740088, 0x6a764623, 0xeb2d907a, 0xdba11b38, 0xcc2c9adc, + 0xac5406e4, 0x98e56b32, 0x6c1ba4c7, 0xd1aa0d23, 0x369f05b2, 0xc0b39e86, 0xe4e57dd7, 0x1d07cba8, 0xa7d2fe35, + 0x3402689f, 0x6e19bafa, 0x95a60808, 0x1d950f67, 0x0566e996, 0x10bff093, 0x79bd02c4, 0x5efdfec0, 0x5f720f43, + 0x32905ff8, 0x46b5e254, 0x331095d5, 0xec2a57b8, 0x8d01738b, 0x76a4456b, 0xfeee7136, 0x47bf7fcb, 0xb8ff6125, + 0x982ce0fb, 0x44bbacf5, 0x455c045c, 0xf3bfee37, 0xe640b4ac, 0x5876a207, 0xb094f750, 0x700280f7, 0xcd4e5aaa, + 0x192d32c1, 0x7b88271e, 0x1809ebaf, 0x6d2d1180, 0x29033f92, 0x94f9d2a2, 0x2c4fc7d7, 0x68a6a4d9, 0x0cbc4252, + 0xb630c039, 0x4792c6ce, 0xaec12f46, 0xe19e655e, 0x50b8f263, 0x12924b43, 0x1b1c3fbc, 0x56fd78d9, 0xce4f9c6f, + 0xc97d3a72, 0x57164293, 0x383349e6, 0x4da649c4, 0xa9b07b93, 0x002f0215, 0x8667924d, 0x9678fe5c, 0x5863f10f, + 0x3dac9893, 0x333f3965, 0x1b97f6d9, 0xfc1bd6e3, 0x2f6d4ed4, 0x5ed2146a, 0xc2869c7b, 0xdc8517ee, 0xd93174dc, + 0x7251189a, 0x61a47cf2, 0x1f13f6bf, 0xd60de9d9, 0x8057d6a8, 0x256ea754, 0x76f4c1f6, 0xc226d0f1, 0x348dcd66, + 0xc2c16483, 0x4bccf223, 0x65932c09, 0xf921c760, 0x9701f9c2, 0x6ed64405, 0xc1be4cd9, 0x0482fcaf, 0x67730fd5, + 0x888e7491, 0xed718690, 0x30910aae, 0x096f2b8d, 0x6bbc1aba, 0x306b570c, 0x571efe8f, 0x093d6c01, 0xaccb915b, + 0x99dc5a09, 0xb52f70b8, 0x7648f1c6, 0x2b04e824, 0x2ca77886, 0xbc686f14, 0x8dd47cf9, 0xc5b455a2, 0x6b54c4ff, + 0x435822b0, 0xb363f3f1, 0xaa7b2fe1, 0x183e0d79, 0xbd217836, 0x860a657a, 0xcfaaba5d, 0x4921caf7, 0xe04077cd, + 0x05e08eb0, 0xa1fcef95, 0x5234139c, 0xf7b84530, 0xbd952da6, 0xff58d551, 0x6206e740, 0x22ab63a9, 0x0779e9c3, + 0xfe004d07, 0xa3d3d042, 0x9b676242, 0xbaa2389e, 0xd970c818, 0x5f83ef64, 0x0de0a7d7, 0x0ef6c037, 0x9d4699ac, + 0x5a767b89, 0xaf183388, 0x57f6c505, 0xdf5a7e40, 0xcf9114be, 0x53865a32, 0x15c54f5c, 0x63e27f0c, 0x3de9d1e7, + 0x93eabb84, 0x5b39b8e7, 0x0dfb7aa9, 0xf9c76d31, 0x2a5cf2ef, 0xbe732937, 0xccc6096e, 0x0638b3e4, 0x8d566db0, + 0xd8e9772d, 0x6c382968, 0x4ecb0f98, 0x06523de9, 0xf5244029, 0xac495b9d, 0xa0f71785, 0xa14bbab2, 0x7c350e40, + 0xd1899b1d, 0x9bf2be21, 0x6bfcf76c, 0xe89ba755, 0x4b539ec2, 0x4782b7f8, 0x35bad3e0, 0x0d2afdde, 0xe6e0e887, + 0xd904a9bd, 0x587b79dd, 0x28068eec, 0xf2636924, 0x16b120e2, 0x7a4f8ed3, 0x98c66e8b, 0x760ce279, 0x9cab4acd, + 0x5c98476b, 0x2e6c8733, 0x77363f05, 0x77b4320b, 0xe709738a, 0x6f8e6555, 0x43977b55, 0x5fd66d5d, 0xbacbbacf, + 0x3a01488b, 0x1f7fa3db, 0x1f5c74c7, 0xa2280cb7, 0x6dc23df1, 0x76188040, 0xb7520e98, 0x27f609b1, 0x8464a1f2, + 0x390f131e, 0x00aba320, 0x6993b755, 0xf835e9f5, 0xafb233f4, 0xcb2df6d2, 0xdff73539, 0x4a043a50, 0xab604522, + 0xbd29217d, 0xaa1fd306, 0x25aa3034, 0x8fbe28f0, 0x7b98ce11, 0x2f24af1a, 0x14684ae4, 0x6b25d5ee, 0x34da8373, + 0xf06d6d3c, 0x777e6d18, 0x6ba5eced, 0xc0a4b5a6, 0x5ab0abcc, 0xaf440cf5, 0x896a2d85, 0xe3b11137, 0x77aabcdf, + 0x7bdbb646, 0xc9b9078a, 0xf31e1cc8, 0xdd7d4665, 0x527ff25c, 0x8793d647, 0xaca83a8d, 0x3685ca40, 0x93f8fc43, + 0x2913341d, 0xc7960568, 0x3233122d, 0x808b98d3, 0xd720b914, 0x69ae737f, 0xf87c6d2e, 0x80a2c7fd, 0x0608f2f0, + 0x3680e884, 0x29f6cd01, 0x56187725, 0x2085187b, 0x8913383e, 0x395c450b, 0xf3fc52a2, 0x2e7f27b8, 0x696c019b, + 0xa364bd1a, 0x10f05fd6, 0x728c9fd8, 0x5f06f31d, 0x5d007555, 0xe73ce03a, 0xc4d2a5ee, 0x34be22c8, 0xfad15aba, + 0x168dbf55, 0xa7955245, 0x06c58db6, 0x54e35ce4, 0x73d18f16, 0x04c1bc42, 0x7dc7dd93, 0xd3b72b0a, 0xe6da13c3, + 0x61d6629c, 0x9df21798, 0x23b22f09, 0xb25cf714, 0xb5a08a85, 0xceedb3d5, 0x90e1fe76, 0x8f3f977b, 0x4f700f1e, + 0x80b65b93, 0x9032a160, 0x706224ed, 0xd638c829, 0x8ab32fe4, 0x9b2780d5, 0xcd623098, 0x9755b4b4, 0x9b89c326, + 0x1c85ceb3, 0x32690907, 0x4e3f4733, 0x6f9b9419, 0x4452df1c, 0xfeb4a8cc, 0x50b3656c, 0x0ace5d73, 0x4dab0009, + 0x256dafc4, 0x11625c41, 0x62240a7c, 0xd43cf11a, 0x235e46e6, 0xcce2f4d6, 0x393b77cf, 0x75352a0a, 0xd1461009, + 0x1aee3a6c, 0x6a83821b, 0x486e05f2, 0xc0077ce1, 0x358b6eb1, 0x1371de27, 0xe9420465, 0x6f347ab4, 0xb689fe0b, + 0x8900ad40, 0xe69baec0, 0xf5fbce45, 0xb0122907, 0x4a82560d, 0x84466f4a, 0x4d54d218, 0x0be145ac, 0x131c6b08, + 0xd7e7dcd4, 0x97ffa9bc, 0x4f047a8c, 0x61c20927, 0xd3cde6c6, 0x2f5a4c16, 0xfd49d8fb, 0x31e6a7f6, 0xc62338a7, + 0x68f1678d, 0x27f0bc46, 0xffff55f7, 0x9f382989, 0xef167545, 0xd06393e6, 0xbc6044f2, 0xf2f0c6ce, 0x0ccdd603, + 0x734ae2ec, 0xc0cb2665, 0x043d24aa, 0x8d111b0d, 0x5b70c59c, 0x244c1bd0, 0x6fb1651b, 0xcf4a6e14, 0xdfe8c3ad, + 0x77d4003b, 0x1b08fe4c, 0xffe8c8d9, 0xe67c2e47, 0x4caaf841, 0xb19d3c19, 0x5079d2e7, 0x8ca67dde, 0xe3e4abc6, + 0x097eb1e8, 0x2d42c7f6, 0x3b880c66, 0xb0b6d2d0, 0xf69c1128, 0x7e6c20d6, 0x9d9ba33f, 0x83215307, 0x0a3128ad, + 0x4b4d3793, 0x3eda96eb, 0x4f7efc95, 0x57a11fee, 0x6995eccc, 0x162176a7, 0xd5a2e081, 0x25f43607, 0x0575208c, + 0x18316235, 0x829129c5, 0x30426a56, 0x54c377e7, 0xf992eca4, 0x9d82b911, 0x54cc5f04, 0xe57f8aa3, 0x15edafb3, + 0xa5f5e6c3, 0xd829b472, 0x9123bb6f, 0xa62401de, 0xb053f3e1, 0xd7939a11, 0x4570e3c8, 0xd391f5e8, 0x981a12c0, + 0xe745a6a4, 0x81a5b292, 0x81bc0fa2, 0xf9352ba7, 0x0e1c814c, 0x6a8feda7, 0x8135d245, 0x3a984091, 0xa0e3b97c, + 0xe8599d14, 0xc17f5d04, 0x2c6b12a4, 0x28f9a8ec, 0x956ace3a, 0x27c6589b, 0xe91ca2ff, 0xcee36546, 0xf15bda0f, + 0x9b049dee, 0xfc7cd73e, 0x3051ea52, 0x611eb7bc, 0xcba646f0, 0x3ee641dd, 0x42e7df65, 0xe67249fd, 0x0b62755d, + 0xec6db8f8, 0xc8ff8e54, 0x51fa22cd, 0xad65640a, 0x4da042c2, 0x27fe1b46, 0xe3b9b3a8, 0x8b6df453, 0xd76421e0, + 0x294c74dc, 0x686d33b2, 0xb886e4fa, 0xbdc7ecf2, 0x83794449, 0xf23df42d, 0x202162d1, 0x0d3b3f9c, 0x0fa19e61, + 0x5c944e6a, 0x26b39ffd, 0xbd40f07c, 0x8336c878, 0xf599c93e, 0x8049a9fc, 0xdb9cf234, 0xe3bceca3, 0xe89c769e, + 0xc05e6cb7, 0x5761469b, 0x0842d337, 0x8e5d9c69, 0x595e54d5, 0x714c2d52, 0xda4de357, 0x19d57c12, 0x22f7c405, + 0x8ff37ef9, 0xe59177bd, 0xf40e536c, 0x23b55ca1, 0x670feea4, 0x3b421cbf, 0x80d739cf, 0x1ee8e70f, 0x2c7f8446, + 0xebb55379, 0x5e23760e, 0x2d16d0f9, 0x910274af, 0x3d2fc1c8, 0xcc966ef0, 0x59a197ed, 0xad1065ba, 0xe990ed8e, + 0x55635305, 0x1391af25, 0x247c9058, 0xa4277895, 0xd09bff24, 0x74d9fd5b, 0xf71968b6, 0xaf7b67b6, 0xd0af1523, + 0x3e1c5fc9, 0x00074d21, 0x1451a29c, 0x8a97badf, 0x1bf52541, 0xfdb6dc9e, 0x663a168b, 0xe330a63c, 0x4729420b, + 0xb48957b7, 0xddf6ecc9, 0x4167cab3, 0x8443341c, 0x86aa4cf5, 0x0bbab5de, 0x3ce045c7, 0x6073da9b, 0xc6b96522, + 0x8857c91e, 0xa292b74a, 0xd83ff830, 0x169065e7, 0x82177a3b, 0x959c44f6, 0x265801e5, 0xa8dbf934, 0xb26ff68f, + 0x434975ad, 0xe304bfc5, 0x9f549db9, 0xd27467e5, 0x63816690, 0xeee0e9df, 0xe3764d51, 0x6844089a, 0x2ba9d850, + 0x90d8241f, 0x09bdb75b, 0xeb81562d, 0xbbd0488c, 0x00909f5e, 0x6520ce8a, 0x6db18f5a, 0x0d557742, 0x0044a56e, + 0xe10a79d6, 0xc69ecf9e, 0x0dcfa2a1, 0x7312db05, 0x9651604e, 0x21853664, 0x071959b3, 0xb8b0cb77, 0x406aa1bf, + 0x82d67db0, 0x9352b085, 0x5f36947f, 0xc5c4e62d, 0x1d92307c, 0x28c48035, 0xc0aebfaf, 0x2542b54d, 0xa79d97d7, + 0x54f13fdd, 0xb77054b4, 0xaa461fca, 0x9cd31ef9, 0x38be28a0, 0xd20dc1c2, 0x97be4d9a, 0xfea59699, 0x0c2c6655, + 0x931e9216, 0xec24eeba, 0x264ef044, 0xfa68f997, 0x917a8cc0, 0x47fe0320, 0x9c27e047, 0xa0e383d4, 0xa7a93e3d, + 0xd4b4d4e6, 0x8c78cb6e, 0xcf1172b2, 0x9e53324d, 0xde3fc35e, 0xbd6168a9, 0xa4ed6dd2, 0x40a005e5, 0xea97a1bb, + 0x5197e999, 0xf971e729, 0x6eb6e6c6, 0xf2186f26, 0x956be1c0, 0x198ae0c9, 0xf8837133, 0xc5345061, 0x71523372, + 0x2c740bb8, 0x6382559a, 0x956212c7, 0x09b22bf4, 0x88915936, 0x9e24e4b5, 0x9966e99e, 0x9b23f80e, 0x07ff318a, + 0xd8ef7cb9, 0x986eedaf, 0x10ef8dd3, 0x0cff9089, 0x1f257edb, 0x2c237e15, 0x6a7995fd, 0xc43d4d42, 0x138ad595, + 0x8ffdcb40, 0x55aa67a8, 0x467f1381, 0xe66e83e1, 0xc145d848, 0x34872eb9, 0x3b90edc5, 0x4fd6fcb3, 0x5d3e5045, + 0xbe079412, 0xc5479a0d, 0x79b05534, 0x747e76d8, 0x31e925df, 0xa87e3525, 0xc4414a25, 0x41ef729d, 0xd230ac7f, + 0xbc9ec796, 0xb4727881, 0xc82bf346, 0x78ed3d54, 0x9e32c423, 0x9e1a8127, 0xb9fc08cb, 0xd1348fae, 0x9989f1f6, + 0x5119fa9b, 0x271e6a6f, 0xb501d9f6, 0xbdae23db, 0x02737f5c, 0xc6972fcb, 0xea2252d4, 0x6f02751c, 0xb4a2e2af, + 0x96ec2c6b, 0x0dcb5ea2, 0x11a521d0, 0xa0bea2b1, 0xaa5fbc07, 0xb2b9a6d7, 0xe74ec9d6, 0x101a5a17, 0x0e00bd11, + 0xe18da710, 0x38e34672, 0x344427bd, 0x09b07dee, 0xd9ee80b3, 0x1710f3f4, 0x137cefac, 0x3caddfd0, 0x12fb7527, + 0x4d1e089b, 0xf257478b, 0x1de88770, 0x17626deb, 0x137dda4f, 0x491be67d, 0xac4018ac, 0x44e904fa, 0x71dd7582, + 0xedee4aae, 0x517c902f, 0x722cad2d, 0xaa77d80d, 0x94f732ac, 0x94a66b9e, 0xa815604f, 0xc1095b01, 0x3ccf402e, + 0x3c4ad225, 0x610c054d, 0x5da0f8f0, 0x718b0069, 0x19697713, 0x310bbf3d, 0x2b026413, 0x87ca982e, 0x3c51d3b3, + 0x1c28462f, 0xd9e076de, 0x0a8de2f8, 0x398b5fb2, 0x5e205feb, 0x7f97dc47, 0xf15aea65, 0xf777f2f2, 0xe1cf4860, + 0x50c4825f, 0x775bc143, 0x591b99d9, 0xfe3b3b04, 0xe2b53ee8, 0x84f9c3d0, 0x67879577, 0xd683455c, 0x6311006e, + 0x35874796, 0x260ea5c7, 0x279ee8de, 0x4c260a82, 0xf93c65b0, 0x00a93a7b, 0x9e39c181, 0x73207992, 0x49f84f5c, + 0x0c427642, 0x4a5e3bfa, 0x665e3fec, 0x4a2116f1, 0xb25f4f47, 0xc7187265, 0xbb9976fd, 0x4b5fc70d, 0xaa1ab35c, + 0xc935f9af, 0xeccd4c01, 0x62ab2f83, 0x5d4ab686, 0x429c5981, 0xdcc8ce86, 0x7da2c94b, 0x0bd1f284, 0xe3bd78e5, + 0x1de8f2b9, 0x2ce64b0f, 0x4940c79c, 0xbbcd761a, 0x282e241c, 0xe4b22c83, 0x60fce126, 0x36d207f9, 0x57f8f5b8, + 0xc908ced2, 0xf13f7684, 0x1c16daa9, 0x7881b0dc, 0xcffb4887, 0xeb23ffee, 0x04741745, 0x1a8b440e, 0x2a279e5f, + 0xe8b87ac2, 0x48514447, 0x1faa4cb6, 0x337e3bea, 0x00a0ca68, 0x84c88fc7, 0x58446190, 0x1e1a3f57, 0xce1bbacc, + 0xfea594f0, 0x947acd59, 0x6bafa9e9, 0x6965a3eb, 0x0fc46b0f, 0xe0a8aacf, 0x226a56e5, 0xb202ee77, 0x4f0caba7, + 0x5e9de277, 0x640f1ecf, 0xd758cc98, 0x0f81e2a7, 0xb38f4ac5, 0xd4bb4163, 0x74ed4c82, 0x129beb1d, 0x161cb722, + 0x8e6dced4, 0x2d8a7243, 0xc8e2801a, 0xce153026, 0x5a1d6568, 0x47e1fea1, 0x3bb72b5d, 0xd7040b68, 0xd17c139d, + 0xc1d56ac6, 0x3363dd8a, 0xdc5710b7, 0x7711511e, 0x9cbfe5cb, 0x1d42a34b, 0xc2fab8e5, 0x7c865f6f, 0x0213204b, + 0xfe308333, 0xfb997712, 0xb579ebcb, 0x49c2f396, 0x1bc98a4b, 0xc94935eb, 0x9b84ef17, 0x868bcf75, 0x24012c26, + 0x668f494c, 0x178b9f6a, 0x6140ace4, 0xcb569d9e, 0x082b6dfa, 0xa6b491db, 0x686060ea, 0xc7a149cd, 0xa1496e1c, + 0x7d0011c2, 0xdf3a1f77, 0x658df68d, 0xfec13283, 0x1cd3a05d, 0x6946f477, 0x0cd81f71, 0xdd3238a8, 0x35468f1b, + 0xd09e5e9a, 0x1cd493cc, 0x43c1573f, 0xe020d0e7, 0x6ea79977, 0x77f41bd3, 0xfc6ab36e, 0x1e5b967a, 0x29002d46, + 0x2997ad7c, 0xa36e36ff, 0x6112f679, 0x77b14bd1, 0x137c351b, 0x50985769, 0xfa014f42, 0x581afa04, 0x85e7efab, + 0xb9dad285, 0x864c3b89, 0x5c94964a, 0x578ad33b, 0xa310f863, 0x2b7634b2, 0x63da4928, 0xf5bc388c, 0xc2575509, + 0x221d2fb3, 0x148a2035, 0x9e4eb9d8, 0xc191f057, 0xb2a3325a, 0xbd3e5a38, 0x2427389a, 0x6fd8159b, 0x83ee446d, + 0xce92ea15, 0x7d73f141, 0x57d842e7, 0x85767cd6, 0x73942fe5, 0x966bb3f6, 0xd6713857, 0xa87d1855, 0xf6f8377c, + 0xb499e6a3, 0x669a2a74, 0xcff0f256, 0xb31987b0, 0x3ecc16b2, 0x9002b65e, 0xa30d7242, 0x7f6d8394, 0xc873be87, + 0x9ecf884d, 0x0f809a60, 0x2b06a94a, 0x581c4628, 0xa37088e2, 0xd64a063e, 0xfa366d59, 0x3dbfb501, 0x81b3934c, + 0xe11b4d16, 0x98981945, 0x851d93ce, 0x4e5f73b0, 0x8713cc4a, 0x990c3e88, 0x3f10dde9, 0x2c741b6e, 0x16ca9e62, + 0x8a9574c9, 0x5fddd704, 0x91e0f946, 0xe145b261, 0xd6c8e914, 0xd46a195e, 0x836f2b84, 0x888488f9, 0xa0171075, + 0x5b68e624, 0x69bf7207, 0x97f89c5f, 0xf68bf78b, 0x0e48fcd1, 0xeb49a381, 0xe04b4e48, 0x6c2b4749, 0xa84a84e1, + 0xe7359ec5, 0x651a830b, 0x9d95b25b, 0x65d139ac, 0xd452f94f, 0x28f3612c, 0x61c87396, 0xe429effe, 0x3ea8483a, + 0xac2bf450, 0x450615bd, 0xeb94bf71, 0xa759a259, 0x418fadc4, 0x59734a93, 0x7a47a6f9, 0xe1652560, 0x5afb7d14, + 0xcca9ac68, 0x3516a22b, 0x28d369f3, 0x5d6ea00c, 0xa7c9c0ad, 0x137b9fb3, 0x2c7137c7, 0x733a939e, 0x29a50a01, + 0x3fa44daa, 0x7160a761, 0xac698f11, 0x1653e030, 0x12d99a27, 0x07a9f12d, 0x45df07e3, 0x010fc0fe, 0xfbc7b3da, + 0x6d1e6dad, 0xf992a21f, 0x52f3d632, 0x909eed95, 0xb27215d1, 0x732961e8, 0xdcd541b0, 0x28c21d54, 0x0df2b4ac, + 0xac33143e, 0xa9ea0eaa, 0xcdfa2588, 0xc927571c, 0xca35f8ca, 0xc840a0fc, 0x55b4b757, 0x9434bd7a, 0x2e1ac1e8, + 0x0a9b1162, 0x8aca7625, 0x034f9307, 0x0491ef04, 0x785d0c72, 0x73b299f7, 0xd17861e0, 0x4323eaa2, 0xd7e0aca2, + 0xf989705f, 0xc4f09bb5, 0x99fd7f86, 0x271c30d1, 0x27e92bd2, 0x7286960a, 0x255036df, 0x941e2779, 0xdb8eae4e, + 0xf6adff46, 0x2b49ac54, 0x0a1cef40, 0x1f28d624, 0x8d6162c8, 0xf080d22e, 0xb6bb18f2, 0xa880e3dd, 0xa78846fe, + 0x4d2fa3ed, 0x05378029, 0xc49b8f5b, 0x2905cb26, 0xd3aeb39a, 0x1629690b, 0xdd1757eb, 0x2ff1f673, 0x9a688a6c, + 0x1d4d24c1, 0xc9742446, 0xabda29b1, 0xcdaec5b7, 0x295c0d7e, 0xd90ff9d0, 0x978d435d, 0xaf68329f, 0x38bed6ce, + 0xcff29244, 0xd79a356e, 0x5910c2a9, 0x77e55bd1, 0x505f5a79, 0xd26d9743, 0xe070d255, 0x4e577e72, 0x68f33845, + 0xc18b2566, 0xa83308d5, 0x022b9e46, 0x2b6f4a24, 0x6c7dfc72, 0xf76630f7, 0xb12f83b8, 0xfbc91237, 0xab95158e, + 0xf8aa7ac5, 0xd76a5eba, 0x891fbec4, 0xe1cde14e, 0xf5fd0124, 0x123ce625, 0xb2e43de0, 0x65626d23, 0x3333eaf7, + 0x1f29e299, 0xd6b24c0c, 0x6a6481f5, 0xeb4ad807, 0xd7a16f02, 0x9655eb0b, 0xc22d345c, 0x3bec5fa5, 0xd22848fb, + 0xb9117606, 0x99d8de15, 0xf58f6e56, 0x7533b564, 0x90ad90f7, 0xa114cff1, 0x7fd502b8, 0xac5a34e0, 0x76e2b46e, + 0x3e106b77, 0x01e92323, 0x556d779a, 0x18b1a5ad, 0x2d9d2887, 0x54e1bd94, 0x9994a582, 0x59cf2080, 0xe17b5ab2, + 0xcb1f04ed, 0xd42fe908, 0xcd00aec8, 0x820a5c05, 0x229bee59, 0xc8446595, 0xc9dd9716, 0xdbb9653d, 0xd55f6f4c, + 0x2183da6c, 0xf615fa3d, 0x88b43107, 0x85f645a8, 0x3436b234, 0x7e553a12, 0x2cef38fa, 0xa738eed6, 0x011e4dd9, + 0x915ccf5f, 0x20b174c9, 0x25215972, 0x30b7a4cd, 0x2129f05c, 0x29ea8163, 0x13f81c91, 0x9045309b, 0x2064548b, + 0xf91efa18, 0x579d0262, 0x24c3d838, 0x8b3be565, 0x553939e8, 0x31d0c06b, 0xd314be9d, 0xb6c246d2, 0x114f9e12, + 0x1d8c0eef, 0x57c98e18, 0x50116040, 0x0778bbf1, 0x30d91dd9, 0x948b14f4, 0x1cd63672, 0xd72dbc14, 0x72c165f4, + 0xadfd0381, 0xdfee0594, 0xfd8f9a78, 0x29cf2f71, 0xe25469be, 0xec88ecda, 0xaeda0c7c, 0xa4b9957f, 0x5dc1a43f, + 0x3a77b4e7, 0x62ad807f, 0x04a337ea, 0x9b506605, 0x0379c816, 0xdb7feb21, 0x9702e194, 0x50f3c880, 0x437398f9, + 0xdb172038, 0x19658647, 0x0cad25c4, 0xdac606c6, 0xb84181d5, 0xb0dd73f1, 0x19065c8a, 0x51f1f7f8, 0xbee06590, + 0xc89c841d, 0x0c5e131e, 0x35468f66, 0x99cb53ce, 0x406283a7, 0xb2452b5a, 0xc707ab70, 0x74fe1adf, 0xa0e5107d, + 0x9c00f3bc, 0x24396759, 0xa768b114, 0x5f43e28f, 0x81aa7895, 0x66a389d3, 0xb6fceb34, 0x04ce34fe, 0x3f3905e3, + 0x5b1cfb92, 0x60cb41c7, 0x737fb221, 0x2a083549, 0xbb8d21a2, 0x1cdf9641, 0x79f3099d, 0xb43db075, 0x7ea7dedf, + 0x715888e7, 0xd1e4685a, 0x7287bcf9, 0xccdd9a60, 0xbccecffa, 0xbafb6e86, 0xf14a9b3e, 0x61e07c8e, 0x82918d5e, + 0xeb7d33b8, 0xd556421c, 0x15973a1b, 0xb90c91db, 0xa28faa1e, 0xc75b5121, 0x22dd0094, 0xa1b18fde, 0xc31376fa, + 0x05ca884a, 0xa5ebb379, 0xf63ac40b, 0x8466e9df, 0x40fbe81e, 0xe48eee20, 0x439b3381, 0x49b7ba18, 0x4219a400, + 0x5b54e97f, 0x1f080608, 0x72f70697, 0xead22ab7, 0xc8882403, 0x4a225667, 0x6fed4907, 0x9cc37375, 0xcba56457, + 0x94f85aaf, 0x9530fa6a, 0x3c478d49, 0xbc802dbc, 0x128a1538, 0xfc7e6e7e, 0x56baafa0, 0xeee4137d, 0xe0eaba4b, + 0xf64fcc01, 0x42bcc451, 0x31d11845, 0x3eec0754, 0x14e34422, 0xcf9564f1, 0x14c28626, 0x4c0d2afc, 0x3b7ac641, + 0x2e20cbae, 0xf977574e, 0xad3d0f5c, 0xdaa9c35e, 0x2f2e7b3f, 0x887c91b9, 0xf719e901, 0xd9376c89, 0x08adaa13, + 0xac741cdf, 0x8649efca, 0x8ba0702a, 0xcd6aaa37, 0x2e79f9d9, 0x1b8fbe04, 0xf6749bcf, 0xc5cc75fd, 0xb26605dc, + 0x84c6a553, 0x0c7e811d, 0x4b8181fd, 0x2674568f, 0x94896210, 0x0d6e87a6, 0xe0480f9e, 0xaf0b04f0, 0xaacd4ccc, + 0x18cec985, 0x20969a9e, 0xb190cf4a, 0x7add1f18, 0xc036fbee, 0x4245caff, 0xc344905f, 0x1dfe6053, 0xbf0601c0, + 0xa44ace0a, 0xab6273c9, 0xf2a88c45, 0xd23b8264, 0x34c2ec26, 0xce570e10, 0x0e4630bd, 0xe3eb4789, 0xf665b661, + 0xe057977b, 0xaa193923, 0x3017954f, 0x7a711b1e, 0x20583480, 0x2532da05, 0xad78e090, 0x3667ca4c, 0x066b7657, + 0x2567444b, 0x194ec9e0, 0x2edb827f, 0xb1401823, 0xc26cd9ff, 0x6fd7f641, 0x39d2f320, 0x0f0fe22a, 0x742dfee5, + 0x1ad7277d, 0x6f766d1b, 0xcc88dedf, 0xfa95ff25, 0x67c42dd6, 0x66e510f5, 0x6ed71be4, 0xf265a559, 0x8997aab8, + 0x4a86abbe, 0x4f047175, 0x59b00f4a, 0x82ba7234, 0xd3a81753, 0xac92292b, 0xe3fd3b24, 0xf6b2c4a0, 0x4c596b11, + 0x3f742cd1, 0xbb15f74e, 0x56eea259, 0x8b79eb9c, 0xf1de113d, 0x1c3d3dbe, 0xca8ef39f, 0x61b6293a, 0x4e4b74c7, + 0x319bcb75, 0xf2e48f4b, 0xdb0c8439, 0x285a9edc, 0x97f4e07c, 0xea8c9801, 0xd84438c9, 0xc2def1ce, 0x99f34b3d, + 0xbb37d944, 0xd632c6d3, 0x28044d93, 0xe200c371, 0xaa8479c1, 0xa188b88a, 0x4b2dbfea, 0xb8e34345, 0x8db34bce, + 0x329595cb, 0x2905e1bf, 0x007235a3, 0x2a2acf97, 0x0a3171de, 0x3669135e, 0x987358ce, 0x8d692801, 0x8bd03049, + 0x82a3cecf, 0xbe44d6c5, 0xceb2802e, 0x165d24db, 0x51c801b8, 0x6b84e02c, 0x13261123, 0x46a3ab66, 0xdc50a6f7, + 0x7c4e95cb, 0xc7a14e17, 0xa03965bd, 0x7fb68aec, 0x2f268d3e, 0xcd6f095b, 0x4ced2018, 0x7b7c3c76, 0x36e8a0c4, + 0xa53067cd, 0x9469b12f, 0x86ffd9c7, 0x909e84cf, 0x591fb34d, 0xcbec6274, 0x014513ba, 0x3b5ab3a3, 0x1e0ff7a6, + 0xf99c8df9, 0x41ea2e46, 0xa8124a99, 0x9a61e6c9, 0xd0b0f054, 0xf711d3c5, 0x6214952f, 0xc7bef68a, 0x627ad183, + 0xb624fcaf, 0x63db7bec, 0xc5c62329, 0x718a79a4, 0x4786d2d5, 0xd198f724, 0x92577935, 0xd9905b94, 0xb9ba3a88, + 0xa9acd4ee, 0x51ce62c6, 0x2c8c5296, 0x108c38ac, 0x26a82778, 0x27100ed6, 0xc5e83fd7, 0x2a86e960, 0x411cb773, + 0x5593844a, 0x82586d69, 0x63b05c37, 0x0fd2b681, 0x4de2d032, 0xd40b3d86, 0x1ce8e784, 0x93ed3415, 0x04bb6556, + 0xdf10fdcd, 0x7fbc8586, 0x1d9a55e2, 0xe48c898c, 0x89a26ac2, 0xd598f771, 0x89e57236, 0x472d887c, 0x01757ad2, + 0xe98aea11, 0xea51243d, 0x26ccb359, 0xd7ad5777, 0x856017b1, 0xdbdd8f54, 0x5fd25865, 0xff70f445, 0x5e678fc1, + 0x9143078d, 0xd1001d25, 0x5fb99d91, 0xebdb4a7e, 0x299eed15, 0xf804a8e1, 0x0060b0ce, 0xc8826df4, 0x64fdc4bd, + 0xa20a85a9, 0xabe218a0, 0xbaeb1d06, 0x97454c3a, 0xe73584b3, 0x2ed4d6d0, 0x075bbe2f, 0x2b066332, 0x5057711d, + 0x3ea562de, 0x12f19209, 0xddebb68d, 0x9d86f1c3, 0xe67b0ad3, 0x483837a4, 0x8e24bbc2, 0x821478a1, 0x4504b886, + 0x8581b62a, 0x2602bcd1, 0x22767bf5, 0x3f38761c, 0xd36c62ef, 0x59a75948, 0x5c8770ab, 0xd8c91bae, 0xd58cd2a2, + 0x1f516691, 0xcf073d87, 0xda7b5736, 0x815e48e4, 0xae93d68d, 0x06dda188, 0x31e9a44b, 0x5d2b4be9, 0x59fb358b, + 0xb7651551, 0x25516ad9, 0x5c6db49e, 0x6f313106, 0x2ee99099, 0xb77931d6, 0xac758546, 0x04a8349e, 0xd42ff0ca, + 0x5ac6ca2d, 0x6009589f, 0x4822185c, 0xa06f4d80, 0x4bfec3f2, 0xacd318bb, 0x4e192596, 0x6714b64f, 0xf9825e58, + 0xfe638a1c, 0x5330cd6d, 0x7ffabff3, 0x70e1a4b2, 0x611c1d6a, 0xb89a15fe, 0x5694fa37, 0x4a2ada65, 0x696bb9d0, + 0x1cd3f89b, 0xaeb299d4, 0x7c9a6264, 0xe34b24e8, 0xef82fd0a, 0x37d159b0, 0xbb7e06e7, 0x0331a8b3, 0x154efd07, + 0x11f499e1, 0xb2c94bb2, 0xf2651a86, 0x12263988, 0x628934c1, 0x5f2f7a3a, 0x9a188b7e, 0x18eef4b4, 0xf772ac27, + 0xcb3642ea, 0x85647a9c, 0x92d99844, 0x6243dab1, 0xdb2cc472, 0x5af6e61d, 0x0879293a, 0x289022b7, 0x775dfbd5, + 0x2c88d058, 0x303864d9, 0x31cd279e, 0x99109b7a, 0xe9dbbc82, 0xd9f20e02, 0x35a3f5c8, 0x89bcec41, 0xf9b8e1b5, + 0x7ba2247b, 0x6c36b6c0, 0xff4684a9, 0x20e180d1, 0x1a26f5af, 0x3f029167, 0xc6286578, 0xea671668, 0x7dace0b1, + 0x9fbac223, 0x07bbed79, 0xa5265f64, 0xc9484628, 0xece44e21, 0xdf2b347c, 0x5d82bffc, 0xfd955ff3, 0x4e7ef717, + 0x9d3fe9f9, 0x7f32f83c, 0xf00c221c, 0xb4fd09d2, 0x67a02906, 0x777164a8, 0x32d47c14, 0x63a69faf, 0xd284948d, + 0x0afc1749, 0xf938e7f7, 0xde2679f1, 0x168f8dfd, 0x4783b9d4, 0xf2e3b92f, 0x35006c0d, 0xef93e013, 0x82259e83, + 0x82f4ca07, 0x4e3a1329, 0x2a443a9f, 0xd9353c37, 0xb2379bf8, 0x77bf23d4, 0x566e873d, 0x1bba9d69, 0x39764f4a, + 0xccb87f8b, 0x14e2c0b6, 0x7d0f1de4, 0x0ef8d912, 0xbb53ab97, 0x47669e07, 0xea29ce01, 0x43a79faf, 0xaed6704c, + 0x64868c06, 0xbd82b7ad, 0x629a3f4e, 0x5afa0b51, 0x4ab84053, 0x1a7194be, 0x1b0a8b74, 0xa9d72c5a, 0x75a2e829, + 0x0f9c49b7, 0x44321f10, 0xd37cfe07, 0xc5033924, 0x1f05eea4, 0x171aee5f, 0x549d29e3, 0x4169e2f0, 0x50042885, + 0xbc246839, 0x38873ef7, 0x70e71270, 0x2c89bee7, 0x0b0717c6, 0xe4fce65c, 0x4f759dd4, 0x646cef04, 0x3b91f684, + 0x3a3cb522, 0x52ee1abf, 0xbcdd918c, 0x9b47ceb4, 0xdedf4465, 0x0581d548, 0x04f6a22a, 0x7e3ac534, 0x1ace5460, + 0x292e9b3c, 0x888a7ecc, 0x111bd10f, 0x99a6c0d0, 0x37cdb16c, 0x8b7a4425, 0x4bb67439, 0xc6ff1f52, 0xcdbb6907, + 0xfb2c5f71, 0x3b950fa1, 0x0c2d4968, 0xd22eaf28, 0xa64eea0e, 0xe8f970f3, 0x7fd2e257, 0xb715cde4, 0x7dd46897, + 0xf8289696, 0xbf8a043e, 0x4afa1921, 0x79282c60, 0x23f8c563, 0xac172d8e, 0x400bd37f, 0x9aac6ca3, 0xadff1bf1, + 0xe38bacf5, 0x87996d7a, 0x54a2cec0, 0x2726dcf4, 0x17c7c9d3, 0xe67e7b39, 0x33663023, 0x538177a8, 0xdd0a4e50, + 0x1236c4fd, 0xd2e3dc27, 0xf03115e3, 0x7e2023b1, 0x2f7776f3, 0x43eace5c, 0x4cb71de9, 0x3a578723, 0x96330541, + 0xd66d57a2, 0x79f5e600, 0x1b0bb439, 0x1fed0086, 0x48b9e355, 0xeb8e91f7, 0xabde5122, 0xac4ef5f8, 0xc4594b5b, + 0xae8b0108, 0x9a83c393, 0xc13dce78, 0x86e71171, 0x1ae2b8b9, 0xd99d9607, 0x4632f1c9, 0x43f4892f, 0x96dc92bc, + 0x9c0da8f2, 0xeb8b79f9, 0x4207a730, 0x5b41afb7, 0x52fac629, 0xa78fa6bc, 0x0b43422a, 0xdd67e117, 0xcd3887eb, + 0x40f6f403, 0xbf52d1f6, 0xcd3fde6e, 0x6e201eb3, 0x62038e71, 0x2e4a0950, 0x34794045, 0x66261bf5, 0x91428efc, + 0x8d7d1036, 0x2b72f182, 0xa66c5063, 0xdea7bca6, 0xc8035e3e, 0x06faa4a1, 0x26722e5a, 0x082c86c4, 0x2a20a5d1, + 0xcece0551, 0x843be80b, 0x6a17fac9, 0x2caaaf1a, 0xdd865166, 0xb33d96c9, 0x536f1d97, 0x4763c816, 0x165d9809, + 0x3ad92896, 0x018e14be, 0xe31a780c, 0xe206ea16, 0xb1d37e70, 0x125e4b64, 0xd825cc67, 0x0b065f7d, 0x4e6b7e9d, + 0x4c6a5492, 0xca0726b6, 0x49c15c6a, 0x51402531, 0x803e3a93, 0x786e0349, 0x090fdaef, 0xe5491043, 0x75afc300, + 0x71a6bc29, 0x65efd0e0, 0xa15d5345, 0xfb744e2e, 0xc13dab30, 0x23a06cac, 0x359fe5fa, 0xa9e0d9e8, 0xbc01ce45, + 0xdf7e16a9, 0x5340688c, 0xdd4fe1b6, 0x4ca4ee01, 0xe2dec18a, 0x41caa48d, 0xdd0032ba, 0x71014307, 0xe07bdeb1, + 0x291c3ba6, 0x12620de2, 0x3d5a6519, 0x2343bc8c, 0x7a8c0e28, 0xf2b6e2ff, 0x479e66ee, 0x9a0025b8, 0x77fafe4f, + 0x01a4eba7, 0xc6faa1db, 0xbd4f4ffd, 0xd937e0f9, 0xfdf68d03, 0x1061f0ea, 0x6c8be0ba, 0xeed88a46, 0xa8b9b97a, + 0x2760b9bb, 0x322b6aa0, 0x48052305, 0x7580cc1d, 0xfd19f871, 0xc52bbc84, 0x127ee0d6, 0x2144e28a, 0x9f448e8f, + 0x9b5343ea, 0xa70a7097, 0x5d38cf2f, 0x2d03e9ae, 0x0bb96210, 0xdef9d77e, 0x2b49e626, 0x4fbd0cdc, 0x7eb0a5c9, + 0x6d03d59d, 0xc25d0147, 0x4697a2c0, 0x7cdece15, 0x782ee508, 0xb939f2c5, 0x9e981855, 0x6aca0cad, 0x336cce92, + 0xf030ed89, 0x8cafa7c1, 0xf858c121, 0x2caf1b16, 0xe2dbb97d, 0x6031008a, 0xbb42b6eb, 0x59847b8e, 0xb7debb32, + 0x2c12f199, 0x9a4c7332, 0xfe985aea, 0xc037cbf8, 0x1e33b2d5, 0xc594a03f, 0x641f9d99, 0x7db1568b, 0xa5c947b2, + 0x23b12c1b, 0xbe44d91e, 0xc04a8000, 0x1659ca3f, 0xd8b46e15, 0x068c9405, 0x209dc7ee, 0x4ed8962a, 0x4f8dd62f, + 0x2ede1fc4, 0x244f61de, 0x83daffb3, 0x2b28d968, 0x38dd7b55, 0xd0e6cd0c, 0x1172da17, 0x41f64cbe, 0x3f500d0a, + 0xeaeebf8b, 0x4f80bcf6, 0x29d9172b, 0x2af6b598, 0xe3a18caf, 0x3dfd77e6, 0xa0d941a0, 0xa3fd9f0e, 0xd6dfd70c, + 0x5c3f81b3, 0x3d644f24, 0x60082d32, 0x5d4c0676, 0x3afffe89, 0xc80b5547, 0x9d943943, 0x424430a2, 0xb3a4e5c4, + 0xf5bb2144, 0x1084d92d, 0x7ea3e332, 0x38898888, 0x20cbca4d, 0x18981394, 0x1a26b427, 0x3c5e8685, 0x24715561, + 0x1a295c97, 0x1728a499, 0x1b6bfa0e, 0x1bca92d4, 0xa8fa7663, 0x717bec98, 0xc4853dbd, 0xd66347bd, 0x6463e22c, + 0x7a4285c3, 0xc1e2a6d8, 0x2a0bd15b, 0xee10dd49, 0x778cb87f, 0xeb947afc, 0x1e4b04b1, 0xd266e525, 0x8f135d6b, + 0x19dca368, 0x35abe51d, 0x5d573ee3, 0xfa87b390, 0xece24f0d, 0x3f4dfd79, 0x3a142d98, 0x3ce76539, 0x7987ae45, + 0x1a617d01, 0xf9eb0345, 0x80cd6931, 0xcfc2e446, 0x6f7d679e, 0xd74de4fc, 0xb660598f, 0x02301c57, 0x3dce6e80, + 0x65ddbd03, 0x87cfb833, 0x09e5b257, 0x4c501c23, 0x2b28ac94, 0x285b2e98, 0xc6e0c877, 0x76050f1c, 0xe0072456, + 0x3425366c, 0xc63cc4d6, 0x4d17229f, 0x1f0a4b09, 0x9c7d5a73, 0xf4824cc1, 0x54081524, 0x568fa70a, 0x96635ff8, + 0x334a7f1e, 0xab1e2a6f, 0x8670c1a9, 0x1192fb9c, 0x0ef31f27, 0x48c7c3b5, 0xa5d44259, 0x011ecaed, 0x570ed039, + 0x683d1c5d, 0x7ba418f5, 0x81c26577, 0x6df4b105, 0x242fad3d, 0xcf156af5, 0xfb93105f, 0xa98747d6, 0x9d0f32a6, + 0xbe5f648e, 0x2c9ab4d0, 0x104aa52e, 0x5ccd3fd2, 0x2f59ffed, 0x5611296a, 0x1d66712d, 0x03bac541, 0xaa365585, + 0xc47c8c84, 0xdda5852e, 0x927ed385, 0xadaacd30, 0x4bd93d89, 0x44542438, 0x26f49cf0, 0x217837d6, 0x7921ff3e, + 0xa3015037, 0xeeda0115, 0x2d21c8d0, 0x1a111c99, 0xf9ff1a25, 0xd5d404fd, 0x36e4bd8e, 0x075907a3, 0x540a2cd9, + 0xdd1fce2b, 0x8a88a2bf, 0xf8c1bf16, 0x189c5844, 0xf2020a2e, 0x04b5c0e3, 0x3e574918, 0x3d1dda73, 0xe518d1a1, + 0xc043786e, 0x323a26b2, 0xcec1b5d3, 0x65d87d34, 0x1e7d2702, 0x905dd1bd, 0xa8395ee5, 0x249a5ee7, 0x4fd5e4a2, + 0x0d89e747, 0x56d0b3bf, 0x1e52255c, 0x374a0d96, 0x20715cc4, 0xb7100457, 0x32523fbf, 0x4b4ee063, 0xab73fb91, + 0x24760e62, 0x340091a8, 0x272a129c, 0x03493240, 0xc9d1c52b, 0x40cfb5f9, 0x41bcd22f, 0x23454170, 0x6565c3e2, + 0x177de95c, 0x930d9d2a, 0xca789491, 0x5427787a, 0x7c483e30, 0xb4b4bc0c, 0xe539b3a1, 0x6fc8e8ec, 0xf027efd5, + 0x55975b0e, 0x7ebb63e5, 0xa56acbc4, 0x18278a25, 0xa6f6a9e5, 0xbe14dfdc, 0xd2065f4e, 0x3de7c689, 0x2bc9ced2, + 0x2e5b5983, 0xafbdc2cc, 0xb03596bf, 0x40916d4d, 0xc83a5411, 0xa8c2da53, 0xe6f73f3f, 0xea89ced3, 0xf55dba4a, + 0x1ee6bbb8, 0x0a9892a7, 0xd56006f2, 0xec138a8d, 0xd01d7ed0, 0x1e4ea83d, 0x8be0c1d9, 0xcfa0b005, 0xf532b9f0, + 0x80563984, 0xb3a59038, 0xb23e08cd, 0xa5a470be, 0x4bba6dca, 0x1dd6348f, 0x1c49403b, 0xa1853f27, 0xb7b99d57, + 0x81160a99, 0xe9ea5ec5, 0x08e38190, 0x8ef5f4f6, 0xa8295bee, 0x3011a30f, 0xdd3e6935, 0xb58906e2, 0xd78aa7e2, + 0x4f823fec, 0xb2ad6be8, 0x3873af4e, 0xe489245f, 0x4c7c95d7, 0x64e3e4ce, 0x8f812234, 0xe34e2e8b, 0xb8e0690c, + 0xf93594c2, 0x7c247776, 0x4663978c, 0xdca98fa6, 0xf4fbad3a, 0x3bf1d597, 0x8859952f, 0xf9b7f6ed, 0xb2a31f3a, + 0xb4b93325, 0x379f5037, 0xb905c1bd, 0x19c30685, 0x24e4a7bc, 0x6bf23fa1, 0x95c1100b, 0x519048b7, 0xace71e73, + 0x3a79dabe, 0x2e28741e, 0x81c69dea, 0x21d4fb3c, 0xa0e6f814, 0x24b96f4d, 0xb987ddb7, 0xe7ee4975, 0xc6581e75, + 0x1b9f5be5, 0x45d5c546, 0xb8249841, 0x30c5b565, 0x1cc86c3a, 0x5337600b, 0x83784964, 0x513d5024, 0xbe69f80a, + 0x79790f15, 0x5223ac8b, 0x9f14b51a, 0x6d0a302e, 0x3a403446, 0x5db50618, 0x261660c7, 0xe6f00b11, 0x3977e572, + 0x06d23287, 0xe87aa100, 0x7653d8a2, 0x8ad07029, 0xdc0f04ae, 0x3edec3be, 0x56048113, 0x6f234b20, 0x5e87f1e3, + 0xc782d926, 0x0c265d6a, 0x72d032b6, 0xdd15a724, 0x1c1d52f3, 0xe367698e, 0x4294ef0e, 0x4143e789, 0xe82ee7f3, + 0x212fc9e6, 0x1ad603c5, 0x0f20a3d1, 0x61e50210, 0x0fdc8bcf, 0x5932a583, 0xf1b56bf8, 0x5bb67d8b, 0x8ba45140, + 0x6ee508d9, 0x7fd68f47, 0x23a808c0, 0x4a168099, 0x58e53eea, 0x703eaf95, 0x3ef2658f, 0xade384a4, 0x6138e01c, + 0x4a15a496, 0xd29305a0, 0x9f21018c, 0x93cfb677, 0x662c1ec0, 0x7cd8b90d, 0xfd9af42f, 0xb2248ee2, 0x0e9d53d3, + 0xb0367499, 0xdee4eb92, 0x60e27ac0, 0x815cd91a, 0x8ae80ac4, 0x5ef42cd6, 0x60b28a74, 0x86a6a326, 0x271f96ac, + 0x185b53fb, 0xbb329cdc, 0x75bbb1f3, 0x7a70adae, 0xfca41b74, 0x7a9f7778, 0x3fcd20dc, 0x6bcb966d, 0xae0b1f48, + 0x9c11bb2e, 0x45a6aa0d, 0xb6bb0544, 0x50ea381d, 0xadd09811, 0x34f6f98f, 0x050828cb, 0x15ea3717, 0x424faca8, + 0x0a07673b, 0x449b2062, 0xd7ee65cd, 0x41d2381c, 0x0343e106, 0xeb9f6633, 0xb38be08a, 0x2af63bf3, 0xded57c0f, + 0x24951246, 0xadf66c46, 0xdd2b97d3, 0x0b31f6e3, 0x3fe85ce2, 0x02a157bd, 0x7125b2a6, 0xa8ed921b, 0x8fe635b7, + 0x5675e045, 0xb2484af8, 0x309db473, 0x2d593fe3, 0xfd18c533, 0x5ccbabab, 0x816d939b, 0x3a8d7d2a, 0x18a1046f, + 0xa70f7f07, 0x8ebfd848, 0xdb04cb5d, 0x18679d68, 0xa7c46dc3, 0xaa43d48a, 0x76f0ea38, 0x9f00b75f, 0x4d93ab58, + 0x97a11726, 0x7279dac2, 0xdf4d15da, 0x46713ffc, 0x772e838e, 0x6a741427, 0xea4d6225, 0xbc28a5f2, 0x020c9ed6, + 0x3340a141, 0x1b49858f, 0x0c1a5bbb, 0xc79c5877, 0xe9c40b9f, 0x7c8087ec, 0x50fa6e2a, 0xd71d3ba2, 0x3612d60e, + 0xb32edccb, 0xde625545, 0x9dd1884f, 0x32cdc3b5, 0xec61ac1f, 0xfebd821c, 0x7a172cb5, 0x6e7f9bcb, 0xf45be6f5, + 0x5db0286c, 0x775a8031, 0xfe341cec, 0xcfe4063e, 0x38beb50a, 0x8419ce45, 0x17123771, 0x8400db40, 0xc3efbead, + 0x8f5b9513, 0x95344c32, 0xc6dccf4d, 0xa921693f, 0x7050fef3, 0xc49e00e2, 0xc9f5c993, 0xb5ced0e8, 0xac6ba2e6, + 0xf267773d, 0x63c05f7e, 0xe0ee9f17, 0x2245f10c, 0x829b5bdf, 0x8bc83629, 0x1d3e6a58, 0x1494f0f8, 0xdbea3303, + 0xa0a6cf33, 0x4160089a, 0x74a2d125, 0x52bb0fb0, 0x4c870caa, 0x251d0e27, 0x77785b1f, 0xf170652d, 0x24354645, + 0xb35d8108, 0xc6634f94, 0x7682e399, 0xe2d57a0a, 0x98839a66, 0xa12f68be, 0x88e9a2b7, 0xd9f0f4d5, 0x4bcb26f4, + 0x094c9319, 0x97a12c3d, 0x948b809a, 0x17831f90, 0x7296b7b4, 0xf5e22d34, 0x8108ee08, 0x58283fa2, 0x3f85f63c, + 0x78848d7c, 0x62926dac, 0xa4d6bf26, 0x41de0d3d, 0x8ed651f9, 0x89cf3df5, 0x492f7e33, 0x2065bf13, 0x3dd3439f, + 0x8366c69d, 0xc03505e7, 0x07afc857, 0xcd19bf4c, 0xe95ffcbd, 0x5139567a, 0x52bef3c6, 0x5f9dd084, 0xb5768d78, + 0xf1f4149d, 0x666fc892, 0x932c27d7, 0xec5ff1bc, 0x50d6bac3, 0xbe1aed17, 0xa34e01b8, 0x4aaef768, 0xf3448a73, + 0x55c860bf, 0x106f33c7, 0x48da17d2, 0xd9df6c2f, 0x70b625b6, 0xf9959a38, 0xb47b0ebc, 0x25200988, 0x29d0c4da, + 0x819c572a, 0x2b5100fc, 0xcb44efbd, 0x38693bf2, 0xd4701a28, 0xa6cb31f6, 0x5e048628, 0xfb20df8b, 0x451f55e6, + 0xb1fa0194, 0x5c5632ec, 0xe164d3c0, 0xa91ce4b3, 0x4268adfb, 0x5dd8d8db, 0xf4bdc713, 0x08b68c32, 0x858a64c6, + 0x0f3a6c8a, 0xd31d93ec, 0x33a2ffb5, 0xdd5a453c, 0xfd5ea415, 0x1c7ec15b, 0xa3146722, 0x7b74e9c7, 0x9f3ca02d, + 0x1014cee2, 0x3050bf74, 0x051aa679, 0xa05b36fa, 0x4fca0622, 0x6d4f3eb8, 0xc6fa90e4, 0x06a9e646, 0x1d2378cf, + 0x4d9117a4, 0x684e320e, 0x21be1a49, 0x7c268ab3, 0x7901e6bf, 0x6158ec15, 0x32a261bc, 0xdb41b0fe, 0xb68ff7db, + 0x51420568, 0x51269cab, 0x45553971, 0x3cfc4ab5, 0xe0968f5a, 0xfda23f36, 0x478abac8, 0x4fe0b545, 0x470471f5, + 0x24b1ec26, 0x41a00925, 0xd85e79fe, 0x108eb2c5, 0x964de8ff, 0xcffe493d, 0x417eeabe, 0x8c48badf, 0x2203ad1a, + 0xbc9d7ebc, 0x469a811c, 0xfda71c4c, 0xeb617574, 0x778fa89d, 0x6404ca45, 0xea7eb4e2, 0x75011f37, 0x259f9823, + 0xa95eb2b5, 0x200166d7, 0x929b967b, 0x3dbc6c8b, 0x887e3bbc, 0x0e91ac6b, 0xc927b046, 0xc3a82d99, 0x14a19cc6, + 0x648cc1c3, 0x545c6e37, 0x8c89cbed, 0xec54264c, 0x6cbedefa, 0x6431e9ad, 0x9af873f3, 0x1afa08bf, 0x516852a7, + 0xa7baf26b, 0xc4d35289, 0x3650dc4e, 0x6c83c079, 0x46f19780, 0x2716adcd, 0x268bc16d, 0xd765b804, 0xc4c7d8d3, + 0x6fbbed76, 0xaead230c, 0x2fcd30ff, 0x920d1001, 0xcb199b70, 0x8279380a, 0x8f1e5676, 0x691aee5d, 0x023367a8, + 0x40ce04cf, 0x80b28330, 0xecec8f0e, 0x6ddca04f, 0x1b026ee9, 0x8633dded, 0x503fb2e2, 0x7bc3dea4, 0xc981b9f9, + 0xa38bab35, 0x7bb8521d, 0x6077d00a, 0x1e70f876, 0x445ec589, 0x14eab75b, 0x150140a3, 0x9360a30f, 0xbf687993, + 0x7bfbddbd, 0x634eb082, 0x5ab9a810, 0x98e6eb0e, 0x2df7b610, 0xf434274a, 0x7e1daaac, 0x58fde125, 0x381f1a3b, + 0xddaf7c09, 0x7d1b2c52, 0x929c5f34, 0xc69398aa, 0xb53fb5a1, 0x918b135c, 0xaf8f7f25, 0xef3476ce, 0xafb1afaf, + 0xe5596068, 0x200697de, 0x33be5fc7, 0xa145571b, 0x2c6d26ed, 0x535de201, 0x9e813ece, 0x9128fffc, 0x77d1ad44, + 0x9befde34, 0xea4b41dd, 0xba7a4913, 0x21e95de8, 0x1e96f7ec, 0x9eec5aa6, 0xe07ae5c8, 0x658d87e2, 0x3d4660de, + 0x6265ab64, 0x9ff7f78f, 0x4820939a, 0x08fc266d, 0x462eec75, 0x08fc11f2, 0x7af25830, 0x6ac78ee5, 0xc041f5ae, + 0x69c84975, 0xc51efc7c, 0xc8281c6f, 0x26ade9c0, 0xa6242968, 0x5f10dc76, 0x1db88c5d, 0xff7d9f17, 0x65bbfbca, + 0xd2805666, 0x432e4d9b, 0x8381d503, 0xa76ddbef, 0xdb1964ee, 0x4c029133, 0xd695f2fe, 0xae161af9, 0xc50e05cc, + 0x75c8ed93, 0xe3437ad5, 0x08ae7237, 0xf9675c60, 0x8fe0e99f, 0xcadf4be7, 0x3ebf7612, 0x3550d3db, 0xc7c83ef8, + 0x7c1e1759, 0x00dbc66b, 0x5cbac9d2, 0x3597b922, 0x1e1e3355, 0x10d99744, 0x3f9ea0f7, 0x4ab57ad5, 0xa881ac18, + 0x10e0d659, 0x24ae9767, 0x1c38f619, 0x39aa2d20, 0xf4fd7219, 0x7155a3ff, 0xce8d6dee, 0x4f475409, 0x16f7efc6, + 0x0185c15f, 0x935ecca0, 0x4cf071ef, 0xf3af7b49, 0x70c86b7e, 0x41775d25, 0x5a37ca16, 0x008daef3, 0x5100a039, + 0x2fd53c38, 0x78eaf679, 0x8351fd1e, 0xd7bfe854, 0xac9207b9, 0x87b05ff2, 0xc6f31901, 0xa50f7afc, 0xffde3ca6, + 0xde079fe7, 0xaee223e5, 0x6e23524f, 0x84951bd9, 0x8c64c52c, 0x66774c4a, 0x4925b493, 0xe4b81421, 0x6b0e1383, + 0x3a81a959, 0x284861cc, 0xf4fa345a, 0x5d4d1245, 0xffc68fcb, 0x4e6facdc, 0x188ac395, 0x19b13157, 0xd876951e, + 0xdd995ca1, 0x76549427, 0x2b0b5610, 0x2c1ca852, 0x919a1742, 0x77df8800, 0x7286f2ea, 0x1f4c4b2e, 0xfc014ac7, + 0x2221d628, 0x4200b9d1, 0xa699d550, 0xdecc521e, 0x920481d9, 0xdade7765, 0x75864446, 0x3e6d147a, 0xfe124883, + 0x147d8f51, 0x8de7a9d5, 0x1efccd37, 0x30e0c188, 0x9fd328b7, 0x7e6f8ca4, 0x6ce9253e, 0xe3e20b27, 0x4737676c, + 0x9ea8c3bb, 0x66ac3dcc, 0xc12f6e8e, 0xdb83bd19, 0x77002024, 0x1383a74d, 0x833a1e0b, 0x9f747ade, 0x5d842867, + 0x8a651fe6, 0x660bf5b4, 0x6126caa4, 0xd288949c, 0x0a375ccc, 0xecefdc8c, 0xb86eafbf, 0x72a24aa5, 0x3e0cbdbc, + 0x203f0ff8, 0x6d34682f, 0xfb360c80, 0xad7de30e, 0xbd6469c7, 0xc99281c3, 0x83749f4e, 0x6dd204ed, 0x22df29fe, + 0x3a760d8f, 0xc1d29859, 0xc6f41bcf, 0x426e8dd5, 0x0a78dd67, 0x5697b4cc, 0x54464f5c, 0x4b794a08, 0x629cd208, + 0xba6e9f7e, 0xe45f8d89, 0xaa9990e8, 0x65362efe, 0xb4b0d1a4, 0x4e94c74b, 0xbe4d4b69, 0x80329293, 0x669848a7, + 0xd48f3bae, 0xa2e33679, 0xeeb4e514, 0x1370c897, 0xd5c02f6e, 0xefcb0f04, 0xec9bb166, 0x3f7387fd, 0x0cb5e0d0, + 0xa4e48913, 0x7d21a83c, 0x479b2298, 0xe21c68e1, 0xc4754c09, 0xc712fe03, 0xa06792bc, 0x91b0647c, 0x2917b0b1, + 0xba84f212, 0xfdd43daf, 0x05978ba0, 0x1ba0a877, 0x59295846, 0xf5eb7c20, 0x27f89e64, 0x9b704292, 0x7fe3bc7a, + 0xd64ec3bb, 0x591e3eb7, 0xba4bf60f, 0xa0b4812f, 0xeacdbe70, 0x35eced66, 0xb786faf5, 0x116de8e7, 0x5ffc5824, + 0xdb2b200a, 0xc73fc05c, 0xd6bcaaae, 0x0b4bbf04, 0x788a06ff, 0x63e7a530, 0x6cd36863, 0xd99977df, 0x4a99afd8, + 0x41f3190b, 0x083e4441, 0x4ba88689, 0xfa0ef62d, 0xd9bccb42, 0xfc0797f7, 0xb3dc581d, 0x4cb1892b, 0x2f7e1498, + 0xcd9215ff, 0x79ae278f, 0x59838b3d, 0x7b1737e0, 0x54244f7f, 0xb72a52bc, 0x2372985a, 0x12241d53, 0x6adc8539, + 0x9711abd0, 0xd8b24f36, 0x01980a3a, 0xd8b59f84, 0x75086d69, 0x62b3966c, 0xd01343a6, 0x6eca5c0d, 0x549577f5, + 0xbe111715, 0xd701d42a, 0x05a1bdb0, 0xf278ef4c, 0xae31e504, 0x6ed7bdee, 0xbf4c349f, 0xa74eb3ea, 0xb71274f9, + 0x91a56ca9, 0xbec35738, 0x9739f40b, 0xc005cbfa, 0x82cd5983, 0xee0cf47f, 0x4469cf1d, 0xd2aef6dd, 0xbcd7b016, + 0x986e82fe, 0xfd978861, 0x10c210d2, 0xfcbef2c6, 0x64f9f6ed, 0x15328bf5, 0xd9e50897, 0x457abbdf, 0xc85b4203, + 0x159cdf7d, 0x6fe38deb, 0xbba6e24c, 0x08771461, 0xbefdd29e, 0x5ca06667, 0xcefecb37, 0xc90661ad, 0x5e14f4dc, + 0x74f49c9f, 0xda7c7d89, 0xc54fb68b, 0x043b3db6, 0x4c577d46, 0x5785334c, 0x52fc2178, 0x9a0c4c9d, 0x22a6fb86, + 0x6762809a, 0x916c206c, 0x0be02f2c, 0x0dd94a9f, 0x66ecef06, 0x59a72d52, 0x4d3ddceb, 0x24c99b74, 0xec1bd3ed, + 0x280e6a89, 0x3fde1fe8, 0xc841196e, 0xdcb4ae66, 0x20e61c69, 0x226a87cf, 0x4ab88f39, 0xcdb51598, 0x1007a046, + 0x500958da, 0x46dd3be3, 0x7e9e433a, 0x973e279c, 0x35d9cf50, 0xeb26cffe, 0xc471c52c, 0x039ce931, 0xe0f97b52, + 0x4360a983, 0xf5ce202b, 0x21200db2, 0x32aade18, 0x53afc633, 0x2469d2f5, 0x89d24d88, 0x3bbb8c80, 0xa791e6b9, + 0xbec46474, 0x70f70413, 0x6ffd6368, 0x3c16cf1c, 0x41d2c391, 0x470bbd7a, 0x5f32bbcb, 0xd56672f5, 0x0199fcb1, + 0x21d9bf1a, 0xd03cf321, 0x1369cff2, 0x0ef098db, 0x00eedf16, 0x2e133a49, 0xd7b7de5f, 0xe2eb3b2c, 0xf4519b3a, + 0x0c62b78c, 0x9464783e, 0xdf71e28e, 0xd6bb3b8c, 0xb36cf127, 0xdf5ab111, 0xd0ef39ea, 0xa5721896, 0x3a8b8e81, + 0xa77fc3c0, 0x3eaa5f4e, 0xbf5566ce, 0x95b6d489, 0x24246e76, 0x3bc2d37a, 0xbcdf8d25, 0x3ebe7a59, 0x7f610c91, + 0x7736bcdd, 0x75bc2424, 0x85c70d05, 0xbeb7ba24, 0x4423de3b, 0x228f9f73, 0x7c01c1bf, 0x9f0d29a4, 0x61a80872, + 0x3ec5601f, 0x27ba04c4, 0xd7a5024e, 0x71452235, 0xfb211dc9, 0x61aa93d6, 0xbf25696f, 0x22b2f2a2, 0x969488a2, + 0x82dff5ba, 0xcfe623fd, 0x88329b88, 0x4cccb4ba, 0xb76482cc, 0xe5023477, 0xa46a3894, 0xbe7c5404, 0xd1fd3901, + 0xe6bbe2ce, 0x0c4f1b4f, 0xacc9b278, 0x3db561f4, 0x332dc3b6, 0xf38df13c, 0xeae891c4, 0x8f00c6d3, 0x778f1d35, + 0x99846b91, 0x5f3096ff, 0x4a87ec24, 0x7c7c7bfa, 0x47ee71c1, 0xb372259f, 0x572c7bbb, 0x9fac8e01, 0xbc3e5e7b, + 0x0a98ad4a, 0x8724098b, 0xb65b4238, 0x08816daf, 0x0ba64183, 0x50cc14e1, 0x42895df2, 0x8858e739, 0xcbe17ba9, + 0x1b74d24f, 0x4402d400, 0x5cc6ed20, 0x279a68ce, 0x7127622f, 0xb430e865, 0xe15ef496, 0x0ebe1de7, 0xd28793ef, + 0x1e95ce31, 0x753f0cb8, 0x9bdb6bfd, 0x5ecc4ba1, 0xf4421461, 0xadf6bdfd, 0xc01bd28e, 0x4419125c, 0x2d7d94e3, + 0x5073c54a, 0x96aeece3, 0x840a2b99, 0xb24aa255, 0x38345e2f, 0xf34125d6, 0xc761e37c, 0xb5ef96ce, 0x11d2d1fa, + 0xad59d51b, 0x360870ab, 0xbfcdf45d, 0x480e2047, 0x0dfda9b9, 0xdae944f9, 0x6f03ee85, 0x3b6f8dec, 0xed9fd4ce, + 0x2cfd70f7, 0xcb88d469, 0x5935984e, 0xa8d78801, 0x341df785, 0x020e6c47, 0x65f12cef, 0xdec04f23, 0x03e3fe4e, + 0xdd3008ff, 0xada46c49, 0x85e22f56, 0x278bb9f1, 0xfdcaa6b5, 0xaf47c5c9, 0x01381941, 0x3f60c1f6, 0x67f8da0e, + 0xa5939439, 0x4c0f815f, 0x2a17adbe, 0xed844395, 0xf2574d5b, 0x55e0b113, 0xdc8a1aef, 0x7ec73cd1, 0xb4d868e0, + 0x56f54288, 0x636cab2a, 0x5b33eb1b, 0x1a4f3fda, 0x613a2cb4, 0x5fac0fc4, 0x082f9f9a, 0xddea4a23, 0xc1484a94, + 0xa75a8bf9, 0x5575b1b5, 0x895bf61b, 0x7e3d5b23, 0x0c504c94, 0x8f7002be, 0xbb91b010, 0xe0c0e536, 0xdb74aee7, + 0xb1364dd8, 0x2d7610bc, 0xf0b00272, 0xa69f0300, 0x66e18979, 0x3268085a, 0x4efa9e50, 0xd084d664, 0x360f51fb, + 0x6b7a7c30, 0x2784ab4e, 0x3783c57e, 0xccf4e91d, 0x53b8639e, 0x194c94c8, 0xfe9f1f85, 0x2c3fd121, 0x5f61d770, + 0x5eae06a4, 0x58696c5a, 0xfc6871d1, 0x190701f4, 0x6ea70120, 0x1aabebf6, 0x634f5197, 0xee0233f9, 0xa86fec8c, + 0xf8b401e5, 0x3d41f088, 0xd040ff28, 0x35e174dd, 0x5e62e392, 0x7298867f, 0x4a0141f9, 0x16af8a83, 0xe79ade31, + 0x600f270d, 0xfba0bc80, 0x963ef16f, 0x1d356ea0, 0xfecd8e0f, 0xbe48905f, 0x4e444b91, 0xb00ddb84, 0x50dc11cc, + 0x66dbbdc1, 0x9b70316c, 0xaa65c3cd, 0xe4c95a37, 0x16807f45, 0x1c780fdb, 0xe48d9478, 0x551787d5, 0x5a9f9918, + 0x73d898a7, 0xdfadd8fd, 0x1929933e, 0x68ba46fe, 0x20216b46, 0x8ed90a4c, 0x468398db, 0x3d7c8352, 0x1791921e, + 0xbb5f1e08, 0x7e566151, 0x1c65b9ce, 0xd9a2f352, 0x81d68bd6, 0x80c980f5, 0xc9fd0a8f, 0x536fc6a3, 0x9e9d42bf, + 0x82fa063e, 0xcb52fabb, 0x07be95ad, 0x4677fb89, 0x3e6ce045, 0xa3b66e20, 0xc5061497, 0xffd971db, 0x5f535bc4, + 0x8c327bdf, 0xb1bc1ead, 0xea9cbf9d, 0xcdab1f9a, 0x76b2d7f2, 0xc3c2c476, 0xbffc7ea3, 0x0f2a9fdc, 0x33a14617, + 0x3fd9bb97, 0x07a1f3d9, 0xec3fabfb, 0xa9ff2d22, 0xf777121f, 0xa64456f4, 0xf7d1bd52, 0x411f3c98, 0x0f55fb48, + 0x053eacbb, 0x700c0ed5, 0x83b963ba, 0x97cd7698, 0x6f220158, 0xca43ce0d, 0x6b29fdf8, 0x60f1b4c6, 0xd547b235, + 0x0358ad8d, 0x7ebe869c, 0x5af8778e, 0xe2fbc986, 0xbd1c082f, 0xcd059775, 0x3cabcfda, 0xe2376984, 0x4747e9a9, + 0xd2373caf, 0xf6a5860b, 0xdfa4021d, 0x69ad5b16, 0x2284c521, 0x59d71496, 0x5f9c7000, 0x0c3b6c91, 0xbb9b4879, + 0x97582d54, 0xe0724668, 0xe2aeaa4c, 0x331f51b8, 0x6e2ca429, 0xc016e51e, 0x1c42d62f, 0x8b48d470, 0x271ae05f, + 0x5d90e07d, 0xf8785c52, 0x19a9c1e3, 0x02c97c1f, 0xb78faa43, 0xfbaeb138, 0x10586a10, 0x7dd1bd14, 0x91638d23, + 0xce1b1a7f, 0x30090d9c, 0xfff154b9, 0xdbd388e6, 0xa7ed52f9, 0x7bd0a9f0, 0x413dc608, 0x23475b4c, 0x3c79bb08, + 0x541906c3, 0xc25bfe53, 0x8cb22920, 0x396c9527, 0xc6e96e6d, 0xb1d78e9b, 0x978fb498, 0x36cd5f22, 0xac668ac5, + 0x54dafbfd, 0x593de62e, 0x2e42e635, 0xa881013f, 0xc094af28, 0x0efb8375, 0x11dab52e, 0x2540ed9b, 0xa68eded8, + 0x7abc5440, 0xde98a988, 0x9002bb36, 0xd84f6337, 0x75555601, 0x34586498, 0xd4dc0ef8, 0x7dd5914f, 0x8d99d5ed, + 0x4610e1a5, 0x270a8dec, 0x20dcbc37, 0x573da163, 0xc3de4fdd, 0xfed241c7, 0x5f702fdd, 0x69ef7655, 0x13a1d8ef, + 0xd3b95e3c, 0x1a5980fe, 0xb5319513, 0x9db66136, 0x5087d029, 0xfc5ee0b9, 0x3885f5f5, 0x434657f5, 0x3a93e272, + 0xd9352c83, 0x210a7dac, 0xc94a6161, 0xbecaaf13, 0xa203a2cb, 0xe4b7956e, 0x33a795ae, 0x3013f92d, 0x7017b2a2, + 0xe9648991, 0xf666727d, 0x87254196, 0x425e6c0d, 0xdd6921f2, 0xbaab70e6, 0x1950b964, 0xef38459c, 0xecc8dda3, + 0x0359da52, 0xbf0ea2f3, 0x26562873, 0x4b0c4eae, 0x3d39b42b, 0x24a24dcf, 0x6826ec80, 0xe6bcad15, 0xc709b4f6, + 0xea460683, 0x36d625ce, 0x8b397fe0, 0xa70fb52e, 0x3ae36977, 0x29420efc, 0x1ffe2ef9, 0x0b13fbc7, 0x8fa3efe6, + 0xff39eb23, 0x382bc4aa, 0xe4e01cac, 0x4d5a36ee, 0x65bf006b, 0xfcd44bca, 0x6a8977a0, 0xae97ebc1, 0xe198ac4a, + 0x6bf55534, 0x24b14646, 0xeccede04, 0x08196645, 0xf2ff38c2, 0x53c7ad99, 0x479f18f5, 0x9b838364, 0xa64bc511, + 0x60774fb5, 0x3b3d8676, 0x0450870f, 0x52c34a1d, 0x3291a5ff, 0x6fc88003, 0xe66014ce, 0x89952b9b, 0x926d28e7, + 0x97d1b86f, 0x27934ecb, 0x2bf47143, 0x6de7089a, 0x5069cdad, 0x0d9f31ed, 0x823b462d, 0x4ac4a013, 0x0b1c265b, + 0x67ff50eb, 0xf7ba8947, 0xedca75f0, 0x2c1562a0, 0x01b333b9, 0x5c229bb2, 0xd9438eb6, 0xebbb298a, 0x83f5346f, + 0x2ca83009, 0xcd6d1575, 0x1d869607, 0xc5844af1, 0xfb1d13bc, 0x0a923b7d, 0x543d836d, 0xce7b47c3, 0x09325077, + 0xddc69fc5, 0xa84fac2e, 0xf1a34dad, 0x037b9aa5, 0x1abb9cb8, 0x9373b949, 0xb990b1c8, 0xa578cf79, 0xe4dcc060, + 0x66c03367, 0xd9be1315, 0x4d555340, 0x11929d56, 0xaef2901c, 0xc57fdc57, 0xb93b1dda, 0x803acd41, 0x0a9d1d5c, + 0xace3a189, 0xb301b223, 0x1bcdef5c, 0xb1e320cc, 0x23f223e8, 0xfd7492d0, 0x8d2de4f2, 0xc9c5a5d7, 0x649a3287, + 0xf215a122, 0xe08f3ffe, 0x65653b50, 0x941fd735, 0xb3d79d1f, 0x7070d2b9, 0x70ce8d7b, 0x67889ef8, 0x9bdc7d28, + 0xcaf4f4f6, 0x05fef23c, 0x48b7dc57, 0x8bd7fa12, 0xa52c4ef4, 0x89a79b8a, 0x3ba605e2, 0xc819c385, 0x9e9f9104, + 0x8d5bcbf2, 0xe4fdf73b, 0x0643276f, 0x790eacaa, 0x13a90024, 0x3f1f28f3, 0xd8bd6ef8, 0xd8f910d2, 0x00c6be15, + 0xe06016f5, 0xaa221402, 0xa029ff77, 0x7817ba1a, 0xf9ed2c16, 0xe0971174, 0x3e7e3b5c, 0x60cdf284, 0xef759e55, + 0x4020458b, 0x182d9540, 0x85a32cab, 0x7be4e579, 0x1ea122b0, 0xd350c4b4, 0x8d44340b, 0xed086e64, 0xd411bff3, + 0xc08503e4, 0x032a0396, 0xd221159c, 0x6f7d68ed, 0x895a623a, 0x0909a5bb, 0xbee06f06, 0xb690e2fc, 0xdbd5cebc, + 0x265deef0, 0x6f2bf00f, 0xacef4f16, 0x09f65401, 0x1aadd1d7, 0x53ae0c18, 0xde0b4424, 0x936b315e, 0x712cb052, + 0xef49abac, 0xa3f4b791, 0xadbf41e5, 0xfaa53a83, 0x15f0595d, 0xd9e2cbb5, 0x6db0d781, 0x08a045f5, 0x34d4343f, + 0xe01bb483, 0x4a069213, 0xf5fbc43e, 0x23769f5e, 0xb305d49f, 0x4afef682, 0x3e557f40, 0xc8f8b987, 0xbe8d4db9, + 0x39704de6, 0x08cacb6d, 0x97c3c23a, 0xfab89da9, 0xe5dffd65, 0x5d11ab26, 0x5985d8b0, 0x8b6f15cd, 0x3731a369, + 0x9e616045, 0xbb07df01, 0x7d63bf86, 0xe457c930, 0x8f322cf0, 0xad0245b8, 0x5ff2b4dd, 0xc61bbdfd, 0x6242de03, + 0xe5b42446, 0xe03362fa, 0x7847fb04, 0x5afb1e6d, 0x0a072803, 0x0d48fc22, 0xa63c500f, 0x6fb7c6c8, 0x539ac025, + 0x55bdd19f, 0xb9b74278, 0x2e29de06, 0x9e71e2c2, 0x3619ca29, 0x8590bc96, 0xa7de08fe, 0x2b6f54cb, 0x34504373, + 0xe5ac41d7, 0x764b6ea5, 0x0418a0dd, 0x886cfe9a, 0xad5e90c5, 0xa87ae68a, 0xfaea2295, 0x70bda1ae, 0x24b9d102, + 0xa05d8bfc, 0x67c23eca, 0x1f9aee2e, 0xb6360e7f, 0x2676e750, 0x62fc7ced, 0xed7e3ed7, 0x61b5e969, 0xa6643ef2, + 0x13f78cec, 0x55d5c9e3, 0x7d0e1837, 0xd73509ce, 0x9ef54531, 0x53c616e0, 0x8debd429, 0x2de3ea22, 0xc498e68e, + 0x7287080e, 0x9aeac5da, 0x6edd1a1e, 0x1d6ec11b, 0x6314a901, 0xaaa84229, 0xb134b896, 0xc9d9f8d9, 0x8ff53af4, + 0xc8bc481b, 0x13ec8911, 0x4236d4eb, 0x975e841d, 0x531f9933, 0xad8706a6, 0x219544fb, 0x1c8dee20, 0x933c2bab, + 0x181b672e, 0xf9720f21, 0xbbe02e5b, 0xf28d5c07, 0x75c60f36, 0x756f764b, 0xb3c19956, 0xa48053d2, 0x14c8d0a9, + 0x3f541528, 0xe08a771e, 0xaa208bd3, 0x48aafb11, 0xb5a34887, 0xed4968af, 0xaf4a2979, 0x6d12f3d2, 0x7bf15781, + 0x3d861eb2, 0xc8d093b5, 0xd4af20f4, 0x8f8bec35, 0x61b78976, 0x6bd7c5e8, 0x1ecf4478, 0x89f76893, 0xdd7fc4f6, + 0x9575c902, 0x353cbd32, 0x122f2f2c, 0x12799078, 0xe115b5b6, 0x300ba238, 0x9641654f, 0x269c8c41, 0x1ba8dfaf, + 0xb58b6115, 0xccf81b09, 0xc484018e, 0x53e7f876, 0x33cb516d, 0xa598cd85, 0x96ff6cef, 0x6a01be51, 0x7e6da28e, + 0xec588f84, 0x50a23131, 0x4705dbea, 0xe4130e37, 0x844f43c1, 0x94a5d756, 0xb28a947b, 0x46b9b710, 0x812b8c04, + 0x08665e95, 0x0bbe6687, 0x3f5db4a7, 0x0d9d6564, 0xb2cd24fe, 0x435c572e, 0x738a8784, 0x734885a8, 0x7ea18bd1, + 0x76536b62, 0xf0b48e79, 0x60e8a486, 0x3a97dac8, 0xc8115663, 0x549d5228, 0x93664af2, 0x4170d3a6, 0x51cc64a3, + 0x47e50f43, 0xfd089994, 0xa7bf3669, 0x27c86218, 0xa2247c34, 0xcb0d4c98, 0xb942ea24, 0x7dafaf03, 0x39c8b291, + 0xa4dae21e, 0xeaff9c6c, 0x9fbe9c1e, 0x5beed636, 0x458721c7, 0x7897d79a, 0x8997ede2, 0x23408af9, 0xa16a6a89, + 0xf0d8d1fc, 0x88e265c8, 0xac9199f1, 0x51a39e4b, 0xe4445e46, 0xec2efde1, 0xd7d72398, 0xed2268b9, 0xbf073032, + 0xb7a5df43, 0x2bfcd0cb, 0x9b0125be, 0x71f9f9c9, 0xcc8182f9, 0xc8df86f3, 0x602761aa, 0x90657a06, 0x6ebd28ae, + 0xafaf29c9, 0xe34694ba, 0x61b2e8c5, 0xce4e7924, 0x657e0afd, 0x763e45fc, 0xc919161d, 0x7901c017, 0x9c411a6e, + 0x4f992658, 0x8dbac46a, 0x6aeec55e, 0x890995f8, 0x6dbf896e, 0xef063d70, 0x6e43a93e, 0x463ccd4b, 0x930b8bf5, + 0xbd0c9edb, 0x1a4f00f2, 0xdad07157, 0x4a53d6f2, 0x4507bdeb, 0x1d66ae55, 0x65cd467d, 0x4457ea6c, 0x7b63a40d, + 0xcc988b9a, 0xc92f1255, 0xb3620de4, 0x20af699c, 0x2d57af04, 0xb8cebe99, 0xca3386c4, 0xcb7064af, 0x250f7d6d, + 0x89daab04, 0x1fd4df63, 0x03cc955a, 0xe7b65b0b, 0x9f308231, 0xfdee35d5, 0x67952ae1, 0xef57ba35, 0x26debae3, + 0x278a27c4, 0xaedad107, 0x029afec4, 0x06be2547, 0x03ccdd16, 0x4ae9edf4, 0x164dc66d, 0x72808858, 0x8266b490, + 0x6371d8da, 0xbbba9710, 0x3a2f8a5e, 0xb7226451, 0xec0e3241, 0x0c013c22, 0xb7635ba2, 0xdb206d85, 0x939de79f, + 0x7b6dd4c8, 0xda7ff402, 0x1a13e32d, 0x304084dc, 0x23b85ad0, 0x2c06c157, 0x1687aca6, 0x865b43ed, 0x7861b813, + 0xb846e388, 0x4ad13c16, 0xb35e3b7e, 0x932870f0, 0xcf4d8779, 0x9bbec694, 0x9544d55b, 0x32d4cfff, 0x151ead2b, + 0x81f3ddf6, 0x4b2f74df, 0xcced2f0a, 0x3ae10a3f, 0x24172442, 0x64b7d114, 0x3ec4d54e, 0xc5e4755f, 0x439b8713, + 0xeb061e09, 0x7a125e49, 0x5df86019, 0x8ff08119, 0x8ebed408, 0x14ff71aa, 0x5424b7b5, 0xa7b754a5, 0x7036b5bd, + 0x75762122, 0x7f42117e, 0x2615c731, 0x4312c4bb, 0xdecee840, 0xedb3e8c9, 0xc3002ec4, 0xac55da69, 0xbd0cf99e, + 0x3e6601cb, 0x47a1a5a2, 0x3576086c, 0x8c625563, 0x06f203b1, 0x314c44c5, 0x9376844d, 0xa30e3fc8, 0xb7607bb6, + 0x2770d2f0, 0x2ed305f8, 0x9c508944, 0x2d28428b, 0xf5791986, 0x0bea0854, 0xe87682a7, 0x8dcdd57b, 0x3c5f7f62, + 0xe2c34ed9, 0x88b943bd, 0x3c526f89, 0xe0a81f06, 0xee7ea8e1, 0x92cfbd53, 0x95106aa8, 0x8d90cd5b, 0x1ba728f1, + 0x9bc67c35, 0x2899f904, 0xa6c6e5e1, 0x226bc9c3, 0x65abe7b1, 0xdce035f6, 0xd2b61238, 0x02e6e2cf, 0x54c12fec, + 0xc161dbf5, 0x859f2828, 0x8c5b9e79, 0xa5df359d, 0xef3f1b55, 0xf8d268d0, 0x7d95c48a, 0xb830f34a, 0xccac243b, + 0x077e7db4, 0x7337f267, 0xffad979b, 0xcf02dbb1, 0x47df9fcd, 0x7463edc0, 0x1709b4a4, 0x133ae09e, 0x18814e26, + 0xda936a79, 0x1c8ebcf2, 0x62817a87, 0xcddbaab2, 0x9bda2a82, 0xbfb6cd6e, 0x9fa115e6, 0x962464f9, 0xeab20517, + 0x9afbcac0, 0x9a3a3d63, 0xfc4353c6, 0x146c20e4, 0x8c077d7d, 0xda9010c3, 0xd0c019d5, 0x90389132, 0xd302a79c, + 0x9cd86849, 0x7c1dcb97, 0xa3c7f285, 0xc08b956d, 0x071dae19, 0x98c219da, 0x8f390315, 0xb646c1fc, 0x868b6c62, + 0x55ac5af1, 0x7cf83310, 0xd20483db, 0x96d87f7b, 0x1fce67a7, 0x1c1a1047, 0xd88e0c66, 0xbd1c41a0, 0x52f19184, + 0xcc52d74c, 0xbaaad1b7, 0x3b6a80b9, 0x8d9e2df3, 0x430b51d0, 0xcc687781, 0xc5ca82e5, 0xa42c7fc6, 0xc2f54339, + 0x28290fc9, 0x8d336d6e, 0xb6d9870c, 0xe855c5e3, 0xb9833e86, 0xf2b92f79, 0xf6471c7a, 0x33d180c4, 0x0905c92e, + 0xb2717f66, 0x3ef96242, 0xe260069e, 0xc8dcaca2, 0x8d93c38a, 0x065984d1, 0x8d4b8cd2, 0x71796a14, 0xa0a27951, + 0xb75c9090, 0xdf711621, 0xe35f81fa, 0xd2b3e4fa, 0x3a0c98e3, 0x0137e6ee, 0x62b63d61, 0xc45ac451, 0x3e477607, + 0xf1aedf18, 0x71141b4b, 0x9a3423c2, 0x0d12214b, 0xf20b8ea7, 0x5c3acde1, 0x912d82b8, 0xcf25a406, 0xfed72e8f, + 0xdf34f620, 0x3bb37f5e, 0xc0d4c85f, 0x22da59d9, 0xed835c03, 0x2215e8ba, 0x4269e829, 0x734232b0, 0xd812550d, + 0xe5fdef06, 0x3adc21a2, 0x03061a83, 0xe0d6b05f, 0x6a50fa60, 0x44aebdca, 0x6a90c92e, 0xea62fbef, 0xa5a19b7e, + 0x53b661d2, 0x2b72b7d5, 0x33217196, 0x76836928, 0x7be63aa0, 0x0f32c773, 0xc868ba8c, 0x02f3820d, 0x8e597e57, + 0x3176f661, 0x9cf5da78, 0xacc37217, 0x1ee68b5c, 0xab67e331, 0xcaa6630b, 0xf0370aac, 0xe91fc5cb, 0x310772de, + 0x631a911c, 0xa8edcaf1, 0xbdfdca5b, 0xe1b183d0, 0x522cdb46, 0xba6f3bca, 0x43d88a3a, 0xae8c81ad, 0x9e747a46, + 0x8d7a6c19, 0x90b234be, 0x62d34c63, 0x46c5166a, 0x39e2f1f8, 0xef97420c, 0xa6ebb2dd, 0x9288a17c, 0xb72f690f, + 0x4e841141, 0xc1445f84, 0x4b9a5daf, 0x2fd649cc, 0x66cf10ec, 0x995d5f95, 0x8c432bca, 0xcb0f1e0f, 0x99f04a1b, + 0x5cf2a0d0, 0x6993d144, 0x661f1e8f, 0x00e76b6a, 0x5dc38c0f, 0x7a17eb6d, 0x1998abeb, 0xd390a265, 0x101fe557, + 0xc371a6f9, 0x1e709856, 0xffabf7fe, 0xa3a9973f, 0x9c2ff899, 0xd8fcbc58, 0x79f04a2c, 0x2d54529f, 0xd5bc8517, + 0x0aa0a55f, 0x81bc1318, 0xf4e78334, 0xdc842b6e, 0x481c2b2d, 0x3cbea61c, 0xc4f8a9e8, 0x7dcabc71, 0x2e0e55d9, + 0xe573c5b4, 0xe1497518, 0x0dc84dcc, 0xe4f638f5, 0x36daa4ec, 0x744f9ff2, 0x50399ac8, 0xe662c96b, 0x0d4277e6, + 0xb0aa3558, 0x946ac393, 0xe17956b9, 0xecae1d0c, 0x391bea36, 0xe4c13366, 0xe348641a, 0x8daca675, 0x8e332d8e, + 0xd4bd9f85, 0xeaa71224, 0x8a3900ff, 0x30c61fe0, 0x4895d297, 0x27affdca, 0xc20c585a, 0x4303af42, 0x927acc3b, + 0x67376595, 0xa084f3be, 0x012907c4, 0x6f9a6af7, 0xc6633020, 0x1e2bc30b, 0xa63a1196, 0x42fd5522, 0xae73ff91, + 0x8755dbef, 0x4d8ac1dd, 0xf597c119, 0x27dfc56a, 0x0fb9fd18, 0xbac68ef1, 0xd6afed34, 0xa1b3cd74, 0x6fb33ab0, + 0x5c72454b, 0x5b8405b7, 0xafbcd4ec, 0x3a2e13b5, 0xa62a1f85, 0x98364004, 0x42924ed2, 0x5d7408f3, 0x772904c1, + 0x6fbcd820, 0xc3e94414, 0x1bdef62e, 0x6b245e4d, 0xfd559621, 0x3bbbdfa5, 0xaa256463, 0x6647ad25, 0x32486223, + 0x2ca43110, 0x3c42f050, 0x47bbcf2c, 0xb57b58cf, 0xed935219, 0x938ce832, 0x6eceb9ed, 0xecab65fc, 0x97089e33, + 0xd969c2d0, 0x50a6e5c6, 0xb1a71397, 0x8dd5c98c, 0xd7e52947, 0xa11fb664, 0x99970615, 0xfd2bee29, 0xf7a61839, + 0x46499e62, 0xa4399d84, 0x0b381a1f, 0xba020db1, 0x3c785925, 0xfaf8c847, 0x541c0e12, 0x805d14e2, 0xe1850c30, + 0xe08f66bd, 0x8ce1bd61, 0x6cad310c, 0x682fcc5c, 0x085cc6f6, 0xaaae460b, 0x2c514000, 0x59d01f17, 0x2ac9a26c, + 0x5a55aa76, 0x4f4733ef, 0x47fef406, 0x41aee863, 0xe75f6460, 0xb5a56e9f, 0x8f4053cb, 0x9ad2c925, 0x98ac87b9, + 0xf0515544, 0x6a9dcc32, 0x7586c933, 0x78211f03, 0xd1a314f4, 0x502a63c1, 0xbec4c465, 0xba90179f, 0xada6268b, + 0x609c949c, 0x6c8a3427, 0xef0e1720, 0x41083b9b, 0x8f3da87a, 0x32154fd2, 0x0f1b1377, 0xce945662, 0x1a5406ef, + 0xcc26381f, 0x174371fe, 0x3d3dd5d6, 0x53ca96e9, 0xc5c50797, 0xd3b387f3, 0xe3d743dc, 0xce7ceb6d, 0x08c27668, + 0x04879d01, 0x460ae430, 0xb8cba93f, 0x3ec26cf3, 0x93c36450, 0x3e72f2c6, 0x71d57414, 0x21997e1b, 0xa08e2d17, + 0xcb4a439e, 0x3c705d2d, 0x3decb54a, 0x0374c52f, 0xbd2843d0, 0x2f176563, 0xce9069c2, 0x38399d82, 0x322adbd6, + 0x69d4b869, 0x29e62ca4, 0x7e7546f2, 0x55d9e41a, 0x9a19b073, 0x9395d32d, 0xaa711c2d, 0xfeee413e, 0xeaa8837f, + 0xa2a5f124, 0x76f65a42, 0x8f408ecf, 0x4ee995a0, 0xd50e0c2b, 0xb5d1912c, 0xa7546e5b, 0x68a35392, 0x590892ce, + 0xe7366e53, 0x8bbe0891, 0x98ef078d, 0x13d0d191, 0x65beb278, 0xf3670a91, 0x2c79024e, 0x136d4540, 0xf8245491, + 0xb948f4ba, 0x30f899e9, 0x5728c3e7, 0x7ef7d995, 0x30f77053, 0x0558febc, 0x242508fe, 0x99cf48fd, 0x66eaa7c7, + 0xedfa9de6, 0x7e0f5c18, 0x5d771121, 0xf5b82db7, 0xa0e429d7, 0x70cd4549, 0x0f3cbef2, 0x69bf8f0d, 0xf47dbf57, + 0x0ca3b928, 0xdc560291, 0xf93603c0, 0x93c6efc3, 0xa160327b, 0x500a3212, 0xca026269, 0x2baf86d7, 0x57373a10, + 0x43347c1a, 0xcc8f56ff, 0xf25f5b6b, 0x8593adae, 0x66dc339d, 0xc774fb14, 0xe5adced6, 0x287bda99, 0x0daaca38, + 0xe68cabe0, 0x379669af, 0x7d7e3878, 0x644a6fd8, 0x30d4c6d3, 0x0330d2a7, 0x60d6389c, 0xabaa502f, 0xa9a9a9e6, + 0x332d8753, 0x9d1eca94, 0xae9193f4, 0xde8cb580, 0x8908e402, 0xe51ffb64, 0x999c63b3, 0xfd617497, 0x05d4adb8, + 0xf9e9031f, 0x0f96d9b1, 0x1efedd55, 0x3539e07d, 0x02ca7918, 0x70bf53af, 0x55c1ea4a, 0xebbd6c23, 0xb0e7c56c, + 0x02407354, 0xd59fae07, 0x9a0e7707, 0x9faee3a4, 0xa9a04740, 0x398df47b, 0x458b95d6, 0xba7d39c7, 0x69b21e3d, + 0x7bd6b6a1, 0xba9ed5c1, 0x3de36cf2, 0x270da498, 0x362c08fc, 0x5e93cb4b, 0x1b874657, 0x54af067d, 0x80cf8b84, + 0x07b3f079, 0x8b78f266, 0x8060fb46, 0xd7138fc1, 0x3dcb1225, 0x74276fe1, 0x35c7ee86, 0x48a58acf, 0x9d4b83ce, + 0x95a15bfd, 0x0d70463d, 0x8daf6d69, 0xaccf4cb0, 0xac6524d4, 0xf01d5696, 0xfef5ad3b, 0x67b3f590, 0x527ca541, + 0xd7154d88, 0xb317fda7, 0x144e5da6, 0xeb9d8888, 0x0b87d22d, 0xa5a25056, 0x550f41e1, 0x13f14b96, 0xdadfd378, + 0xb461c309, 0xce54ef09, 0x628bdf09, 0x1a9fce69, 0x0e31aeb2, 0xa8e6ddd5, 0x9dffea7b, 0x67f2503d, 0xf0998fd3, + 0x53334557, 0x766875ad, 0xf6c524f3, 0x100418c6, 0x80c9fec8, 0xb89acab6, 0x6dd3b788, 0x63e733c5, 0x3873c22f, + 0xa9e3453a, 0x2593fb95, 0x35434968, 0x078da9a4, 0x777320c1, 0xa8f666d8, 0x89cdf324, 0xa0ff45e0, 0x5f2ff9cf, + 0x1669d4e0, 0xaac4d8f8, 0xf9c4427d, 0x925bb311, 0xd125e6db, 0x61077e1b, 0xce1a8041, 0xf42b2418, 0x19819557, + 0x67ca9f2e, 0xdc7efcee, 0x5fafee2b, 0x30e38299, 0x68b11bc4, 0xc87c629a, 0x7cfa493d, 0x2f92c9b8, 0x41874919, + 0x3c5daf5a, 0x321ae89e, 0x35ffd898, 0x5737a9d1, 0xb7e5a503, 0x584a71f3, 0x00f5efe4, 0x7a6856c5, 0x243a8b26, + 0x7e38efe7, 0x8f4cd2c8, 0x5d5c4dc0, 0x49eb0096, 0x717d2e06, 0x0f94759c, 0xc76b5fcb, 0x5e87c011, 0x65b39b41, + 0xbbe46cee, 0x10e6bd8e, 0x36cc3c7c, 0x0edf2409, 0xdfc45c97, 0x7f864545, 0x83531e05, 0x9dcda3d5, 0xfd139fb9, + 0xdba826de, 0xff22c1a3, 0x19037270, 0x3992d5d2, 0x88d0f8bf, 0xdb122b56, 0x0b3dfbfa, 0xc4f12a82, 0x6ab6213d, + 0xdcc4a566, 0x53211da4, 0x8d77d985, 0xd22fab5e, 0x0f795422, 0x3b23a060, 0xebb827f8, 0xb7741643, 0x69b44698, + 0x61ac5fa1, 0x63fc078f, 0xcda4ef6e, 0x6e36ec63, 0x5d978c8c, 0xc5b4aebf, 0xc978b1b0, 0x5b324351, 0x77c96f8e, + 0x890f275e, 0x3bfc5cd8, 0xf34b64df, 0x79e4e6df, 0xc515c0e6, 0xd3f87c5b, 0xadbd2a2c, 0xfca4f093, 0xba468fd8, + 0x793049f2, 0x0b2b3f36, 0x55e5064a, 0x5e6d414e, 0x571258e9, 0x2e8c19ba, 0xeccae93f, 0x70c7da5a, 0x323c636e, + 0xa392dc4c, 0xe1502de0, 0xa659424e, 0x075f3a8c, 0x079bfbab, 0xd139f9ee, 0xc9a3f3a4, 0x3ef73e49, 0x65f8882a, + 0x5c11b2e9, 0xd3c4a12c, 0x7182b037, 0xa9b045db, 0xf3d41e88, 0xfd646014, 0xce405494, 0x14a1c02c, 0x57f9706e, + 0xfe4cdd78, 0xdb1a56df, 0x8ba2dad3, 0xf87a02c3, 0xf1602e0d, 0xa6da06bf, 0x68b73af0, 0x07edfea1, 0x54ac362e, + 0x0b7fa743, 0x201bc12f, 0xa0ef68fe, 0xffd595fb, 0xc39a7b80, 0xe92dc372, 0xca2f3014, 0xce25d36a, 0x3bee1fad, + 0x433b899e, 0xbd03c34c, 0xaa20d8b8, 0xfa3cc39a, 0xaa186323, 0x045e2540, 0x8d51a03c, 0x89f1ebed, 0x926f12dc, + 0x6af80481, 0x2e5d4106, 0xda3cd6ac, 0x35aa0c22, 0xa2a9cd33, 0xbfb9f59d, 0xe5be7a26, 0xa89f9b56, 0xdb7d24c2, + 0x08e72259, 0xb8b587b4, 0x009952f1, 0x0c84cc70, 0x7543c48f, 0x005db3ac, 0x05bc0456, 0x5936869e, 0x6480184c, + 0x4294cffd, 0x6a13da09, 0xd0eac4a4, 0x472019c0, 0x1494d5c2, 0x6dfac15d, 0x77fb0907, 0x33ce55bf, 0x71bacd0d, + 0xcefd40ee, 0x5ae526fa, 0x7e41274c, 0x4bc718a7, 0x081247a9, 0xe6d4c22b, 0xa71410ec, 0x58b5060b, 0xc634d6ec, + 0x3415cdcf, 0x03d92ee6, 0xf8232ba0, 0xd7103111, 0x64521d81, 0xf211fe73, 0x59eddb7f, 0xba6c9a2b, 0x96745125, + 0x77f0e1e8, 0xea9511bd, 0x92cc0877, 0x81b9f02b, 0xc773ce5a, 0xde35c3ca, 0x312875c3, 0x4a644e84, 0x252a2ec9, + 0x8c68f47b, 0x01458907, 0xece5b212, 0x734c0e70, 0x58d790dd, 0xfee2af0c, 0xb83b5f7f, 0x5686bc3b, 0xa7cc4bc7, + 0xbb1d7b0a, 0x958443d6, 0x6640f243, 0x62199cff, 0x85675fba, 0xb7f57540, 0x71e34984, 0x0070d744, 0xc02eddd6, + 0x3801294e, 0x56f82390, 0xcf79ccce, 0xba804b2c, 0x67d04ffa, 0x4d0803ac, 0xc242923b, 0xd5b9ce87, 0x189f92ff, + 0xea7c501e, 0xe9424eac, 0x032aac5a, 0xf7e28b79, 0x2bcf9320, 0x41c117d3, 0xc9c5af5b, 0x611e333c, 0x58577ce9, + 0xed7ffd48, 0x65932ee0, 0xea38375b, 0xb62524cb, 0xa25b2a9e, 0xbcbcb236, 0x2829739f, 0xa726279b, 0x3a2a7cbb, + 0xf1f88c4a, 0x56a64009, 0x7ff05aad, 0xc5abfdbf, 0xf3077f31, 0x897a4f06, 0xe92cb0b6, 0x42e9c786, 0x87e24ce9, + 0xb5543f1d, 0xbd252e8e, 0xb73517e3, 0x27b5dda4, 0xd117e2c8, 0x97a5c47a, 0xf7067bb8, 0x5aa55e69, 0xa7a78e9b, + 0x79be586b, 0x44eb3feb, 0xf3d241d5, 0x1c8d504a, 0x01517b07, 0xfe7bb97d, 0xf52d07de, 0x05bda0c8, 0xbd598dd4, + 0xf03f8006, 0x8c190fc3, 0x008f5d78, 0x2ec70ff0, 0x19654336, 0x61be7850, 0xe2468138, 0xba64722f, 0x8d2b10c8, + 0xe350a236, 0x283bffc5, 0x4f1aed79, 0x5a1beab9, 0x30befbbd, 0x76f3e0a9, 0xd61534d7, 0xcbe36646, 0xb18133de, + 0x98f9c740, 0x430faf4a, 0xfbb70b73, 0x22e48a81, 0x43e6b117, 0x25c243ec, 0x9bbcc190, 0x301a5d67, 0x31d9b732, + 0x01085dd0, 0xca552431, 0xeb4ecf90, 0xef6d2902, 0x63a0950c, 0x6ffdda48, 0x7ae9ba90, 0xa2cd32dd, 0x145cd7cf, + 0xc3890c9a, 0x90bce844, 0xd94e2c3b, 0x533b0551, 0x9884ca03, 0x9e13bff7, 0xc6714b8b, 0x27ed409a, 0x79525871, + 0x42fbdac1, 0xafeaa2c7, 0xe18b6932, 0x4f7d1848, 0x43b37157, 0x5d8af7b2, 0x12540d78, 0x42580dbb, 0x241fd38a, + 0xa7eb52be, 0x0ea95b6d, 0x180a1d48, 0xf1f71cd6, 0xa39eae8e, 0x3da412be, 0x399453f7, 0x7da7769c, 0x4fc32641, + 0xd0b72ece, 0x2a979f87, 0x183878fa, 0x9346bd51, 0x73c836cb, 0xa2817a46, 0xcb380df6, 0x6b37c4c4, 0x2c1e645d, + 0xd800a51f, 0xbabad700, 0xd0c7ef72, 0xba62c9d9, 0xb4def6f9, 0x596bbb6d, 0xeb95046a, 0x330ddf2a, 0x44cff86e, + 0x2b8a527f, 0x34414075, 0xc5770753, 0x04bf64ac, 0x27295346, 0xa493d709, 0x17cc179a, 0x9d25b924, 0x9862b7f3, + 0x503449e3, 0xe9363f9a, 0x44ca2b63, 0xc7578ccf, 0x64a27ac5, 0x84bd8fc5, 0x7d44f1cf, 0xe15e48fd, 0xc5b36a9e, + 0x4875d366, 0xb1633ead, 0x8111fc14, 0x7aacd415, 0x74b9af32, 0x1d011f48, 0x829e131d, 0xcb782946, 0xb71876b6, + 0x0b3659ce, 0xc59140db, 0x5b746547, 0xe4b6b46d, 0x01951b9f, 0xde2c23e4, 0xf6cb80fa, 0x424e7298, 0x66fee481, + 0x20cd804e, 0x86f9b360, 0x14099e53, 0x5081dc5b, 0x70b0bd0d, 0x5c1401c7, 0x6dc8868a, 0xd14e87ec, 0x6127347e, + 0xfe3bc4d8, 0x6bef8539, 0x7c3194c3, 0x223c894f, 0x6714f56a, 0x96ec4886, 0xc5acd0c0, 0xb2c96584, 0x343d7fa6, + 0x6ba99556, 0xcbb48bf2, 0xfc2c3485, 0x80800778, 0xeba7b9d3, 0x3a30afde, 0x465fa90e, 0x6714944a, 0x76baacdf, + 0x02db6595, 0x2fe3547f, 0x3729e399, 0x74ad8d35, 0xe3a4a4e0, 0xf7bd8637, 0x94186302, 0xcef60cd1, 0xd8b7726e, + 0xfad26c8f, 0x3902e352, 0x8ea8871e, 0xc36025cb, 0xf184381e, 0x52dc7ce1, 0xa38666f1, 0x505d087e, 0x603df3ca, + 0x2bdb04e7, 0x8b893469, 0xbe782803, 0x932ebe4b, 0x36522dab, 0xc4aa2ec9, 0x52b8a65d, 0x4c30f589, 0xac7a822b, + 0x40f2088e, 0x1cb45840, 0xe5ca6ceb, 0xf48505eb, 0x945a3b66, 0x3f1d898a, 0xa04c1ed2, 0xc0273a53, 0x30412cb8, + 0x3d859e0f, 0xc226c7b0, 0x4311c779, 0xc33fc307, 0x6aaca797, 0x2df26dfc, 0xb4f11d81, 0xd350dab7, 0x6557c420, + 0x408cf507, 0x5a7a947b, 0x25c74896, 0x7c1df36e, 0x5984d0ee, 0xe536f4f4, 0x13eb0805, 0xa3a615e4, 0xdb411d92, + 0x8c4f5240, 0xb3fb0835, 0x81889744, 0x8b9d9def, 0xbf97acf7, 0xf493f3bd, 0xeb436ad7, 0x52e2d93f, 0x6d5dc7d2, + 0xc1d3136b, 0x3e239a15, 0x82b8c9f2, 0xee96fbd6, 0xc8a28b6a, 0x8ae80e6a, 0x481440ad, 0xa72e2ce6, 0x3c9b9a42, + 0xaa4e92a0, 0x7f5881d7, 0x59921f42, 0x88054d10, 0x2d22f63a, 0x6cf2fc6e, 0x3f289a63, 0x23e3c778, 0xa55309b9, + 0x7e1e80b7, 0xc14f8a9d, 0x6b93b377, 0x42102ef0, 0xe11ab68a, 0x4f5a44bc, 0xc0d303d2, 0x32c34126, 0x82e6f213, + 0x6ea3864a, 0x595c7a93, 0x9e6bed13, 0x87a7edc6, 0xa1a4c120, 0xcbf5e0f6, 0x14c6200d, 0x1bc1adec, 0xe3892e40, + 0x1e33ef6d, 0xe0b68e6f, 0x7d59c3a5, 0x42427f62, 0xa008c84e, 0x7e98291b, 0x4af91dc3, 0x73646ce8, 0x5eba2140, + 0xa9492bae, 0x8c977ffd, 0x45d2675f, 0x557bd37a, 0x2fcef0e9, 0xfb2a6782, 0x46ab030f, 0x609e9951, 0xc94ab1ec, + 0x303dc8d2, 0x02b26212, 0x68668e2c, 0xfadccb3d, 0xe697ec13, 0x587f1601, 0xdf797b6d, 0xf2f4b47e, 0xeb6f86f1, + 0xc8efaf00, 0xcb223019, 0xb2aa9844, 0xf715c5aa, 0x72370ce1, 0xbb739aa5, 0x590dcfd0, 0xd6ceb05f, 0xc35a02aa, + 0x60b742cc, 0xd47bb27d, 0x1dfac348, 0x68260cad, 0x38475e6f, 0xfd848892, 0x7d77d6d9, 0xe47d6217, 0x497765c3, + 0xdd9626ca, 0x98db9723, 0xe0a7bc61, 0x0a85edd3, 0xaf1cf078, 0xf583fdd1, 0x82a2332a, 0xc4cba90a, 0xcd39214c, + 0x725e7acb, 0xeb1f3e26, 0x8c4cf67d, 0x928b6b63, 0xd598001b, 0xc3f0a119, 0x58ad5da6, 0x75f463da, 0x588dfcee, + 0x295d78a2, 0xd7a2a6b5, 0x05f5a03c, 0xf79886a0, 0x76afdd47, 0x00a00138, 0xfe1774f5, 0xbc2fea14, 0x71480902, + 0x4f4fa2cb, 0x37983d13, 0x7f04fb43, 0x6f39745d, 0x23ee578b, 0x07dd1931, 0x64c5589d, 0xfeff2b8f, 0x09216836, + 0x420adb24, 0x0035d31e, 0x960df348, 0xf5f735ca, 0x4b12a919, 0xcd0040b7, 0xbdec818e, 0x2a271163, 0x5625fbb4, + 0xfedf55ca, 0x02110730, 0x58b8ea9b, 0x3bacbdc8, 0x1b16fb3a, 0x1857ce56, 0xf25f967f, 0x091accc4, 0xcd07de20, + 0x1a7ea4de, 0x609269bb, 0x7860286a, 0x6fb0e4e6, 0x7bbb4ebe, 0xdcd94aed, 0x88a9d6e4, 0x492127e8, 0x3117c592, + 0x8d0eba94, 0x46c6b2ae, 0x39510967, 0x9007f1e7, 0xb8a62f85, 0x01f438d6, 0x8090c0d2, 0x2bc62709, 0xbef651be, + 0x286a7d0f, 0xc09430b2, 0x8accaf11, 0xa9c37371, 0xb5949e5f, 0x0fcc3673, 0xc9380994, 0x0b4fbefb, 0x7d94b97f, + 0x7de2a330, 0xbf03ad13, 0xd74013a1, 0xc4f3b335, 0x1d52840d, 0x078f85fe, 0xa31e39ea, 0x5f3e907c, 0x60c8d9a7, + 0x1e277a26, 0x92602c70, 0x0b426392, 0x74d41e5d, 0x3627b418, 0x328d13b3, 0xb8432ed1, 0xe2d0806b, 0xeddaed1e, + 0x46a02c71, 0x29a321c5, 0x3cd7d6d3, 0x85eb09c9, 0x9a551c03, 0xc604c8a3, 0x6d7a8bb9, 0x83cf4754, 0x486339a8, + 0xb93b2323, 0xd98c5613, 0x9acbc531, 0xe66667bf, 0xbf54e54a, 0xdd75d492, 0x961e3775, 0xad9eafea, 0xd75dcd60, + 0xdd3f7db5, 0xf9a3b21b, 0xdec730b6, 0x0851f2d7, 0xd2e4fef7, 0x658504b5, 0xa6893bbf, 0x3bf3a5f5, 0xdf6e28fe, + 0xe16793b8, 0xe0bf5fa7, 0x57c8051c, 0xdc8c315f, 0x80d45439, 0x08a7a04f, 0x0122c8f4, 0xadde44af, 0x9aca2f84, + 0xa96af956, 0xf66aaa98, 0x87c82e86, 0xdc69b199, 0x5cee8cb5, 0xb2edb201, 0xff54fc91, 0xf3368031, 0xc0b39823, + 0x3c2675bd, 0xcf534c28, 0x44cdb9d6, 0xd892ea9b, 0x492724d7, 0x651ea225, 0xf9f72c77, 0x1daa5e90, 0x715408f7, + 0x2a69da36, 0x4a59619b, 0x01dcb4e0, 0x0601e096, 0x3488e54b, 0x75ee353d, 0x82b7ae78, 0xc47d12ee, 0x529d06f8, + 0x92d07f88, 0x7f471b6e, 0x3bbeab7a, 0x39807db2, 0x94824e9d, 0xc9e94219, 0x7a3168a8, 0xab4313bc, 0x9afb8e29, + 0x2e95885e, 0x5d9daf0b, 0x76e5018c, 0x19d96bd7, 0xf751a9af, 0x38f5a1f1, 0x85631108, 0x02b0ae01, 0x244a913a, + 0x4dc6c8d3, 0xaa8eef4f, 0xb44c077f, 0x824a1b79, 0xe35888ac, 0x7d86534d, 0xe52cf404, 0x6fdd7abe, 0xbee2d249, + 0x76299fe3, 0x35e3a244, 0x2383a89f, 0x46c4aff1, 0x09cad952, 0xe72dede0, 0x67e924d1, 0x223eb1be, 0x65d754d4, + 0xb0234f76, 0xe8a649d1, 0x55a8af30, 0xd2426b91, 0x8f97117d, 0x3d0173ef, 0xd84e4dc4, 0xb1b3dd05, 0x6fb4e710, + 0xad02ba62, 0x3ca1b057, 0x7018bbb3, 0xcf40c44d, 0xcbfb4410, 0x3ca5bbb5, 0xeee5651f, 0x0e161659, 0x0090cc4a, + 0xd351072f, 0xddad1cb8, 0xe8601d2e, 0xc05aa289, 0x5922ff92, 0xa6655b9b, 0x5fe4a1cd, 0x4aaeec06, 0x3131b354, + 0x41ae8051, 0x5e3eebda, 0x61bc03fc, 0xd42b009b, 0x6dde50c1, 0x678dd67b, 0x501627a0, 0x84921239, 0xd0d781d4, + 0x3ab98a50, 0xf29392a7, 0x5971cc93, 0xc6b5b8a4, 0xfb185003, 0x5b323513, 0x03196ec7, 0x45623f7d, 0x2b37ab87, + 0x2debf459, 0x2977860b, 0x46cbdb58, 0x5ce8cc8c, 0xaec790c8, 0x736f312e, 0x0a63aecf, 0x9e33da67, 0x3b9ff724, + 0x6f915be4, 0xcb734fce, 0xf1543239, 0xfd18d1b9, 0xf7162e81, 0xb3a90c76, 0xad917a9e, 0x1562501e, 0x5a9f9c5d, + 0x3104f1b7, 0x019cddbb, 0x8c287d17, 0xad617f99, 0xfa88b38e, 0x8b6c609d, 0x56c40754, 0xfa10401e, 0x85a69a6c, + 0x60392124, 0xc02ef463, 0x78c2416c, 0xa73f384c, 0x58dc6105, 0xf26a22d2, 0xb05b6619, 0x15cd1ff9, 0x03096d0e, + 0x3195c0ce, 0x89a0d56a, 0x4c4d269b, 0xdfc82745, 0x918b8495, 0xecc84bbe, 0x905d547c, 0xa2ed6362, 0xc2cee5ed, + 0x30216b6d, 0xd18e5124, 0xf4c6ab8b, 0xa9a327a5, 0xaca23b9e, 0x29fbd7ee, 0x175764da, 0x86efc26c, 0x825de26c, + 0x1c4fe78d, 0x283ce248, 0x4ac10c0c, 0x50bbf3fb, 0x029f6275, 0xe4fa99bf, 0x03e447f9, 0xb58fe8c4, 0xd3ff4b84, + 0x62ceb07a, 0x154821ec, 0x57acf840, 0x820ebc15, 0xdc3634b3, 0x5ded71c6, 0x50b7c917, 0xf45c8e44, 0xfa3d34f6, + 0xac3f72ec, 0x8cddaeba, 0x9fd76792, 0xe8f631cf, 0xec652ab1, 0x4f77b310, 0x8731f203, 0x9b1ca4d4, 0x66bc06b6, + 0xd7bf2a9f, 0xe85e9a7a, 0x3c4b23d9, 0x500c633c, 0xae4c3699, 0xcf603f66, 0x5516d253, 0xce9cb03d, 0x4e4e94ad, + 0x9a6c97c8, 0xf64195a2, 0x4654bfaa, 0xfafcb9b6, 0x19d8950e, 0x5b1e76db, 0xbd65ed3c, 0x9a7c9495, 0x6ae08520, + 0xc5e76655, 0xb8283a1b, 0xa99506f4, 0x9bad69ac, 0x88bd2344, 0xec8462d7, 0x2138c82b, 0xe481c196, 0xfd3f41cf, + 0xe94bae66, 0x5bcb5b13, 0x2898f120, 0x53bfc982, 0x08f986e4, 0xae207148, 0xc22bfc08, 0x8a5020ce, 0x9b58ea3e, + 0x6f72422e, 0xbbe61f89, 0x858581f6, 0xc7b1c6e9, 0x469fb2a8, 0xb4610534, 0x9d58f6fe, 0x26bf4649, 0xf315de28, + 0xcec0f753, 0xeab9d8cb, 0x080fef72, 0x3aeaa30b, 0x66d795c5, 0x4bfdeef1, 0xfc91af88, 0x39416dfd, 0x5bbf1404, + 0x42a017df, 0x68ed4aab, 0xe62ab313, 0x9e9225ef, 0x43f8c595, 0x23287a84, 0xa2eb5953, 0xb8127b33, 0xe77a570a, + 0xa44386f7, 0x29d11f1e, 0x9c790194, 0x3b591abd, 0xca34f643, 0x6d19bba4, 0x375d77f1, 0x0b251032, 0x1b9cad58, + 0x07f75a65, 0xe350bde0, 0x330d51db, 0x9ac02a7a, 0x93850dc4, 0x1c4e38c4, 0x4df16ab4, 0x4d0539b4, 0xbcd073a7, + 0xdedb7462, 0x9a1735f2, 0x3a270ddf, 0x6e84f448, 0xd43ff76b, 0x6c223839, 0xc0146552, 0xc26d2da5, 0x391cd6b5, + 0x366b271f, 0x5c7f49fa, 0x1535d991, 0x7b99ed3f, 0x1268bf4a, 0x8feb08f2, 0xb3147781, 0x73eef8ec, 0x9a3baa11, + 0x471b3d3e, 0x28e15300, 0x2cd29643, 0x7869b033, 0x8ee2e423, 0xeba17e0d, 0x1147e107, 0x10cd31dd, 0xf62b8269, + 0x770ed913, 0x37c9e6bd, 0x71d5a928, 0x534e3ef1, 0xac6f4f8e, 0x12e4986c, 0x0e980054, 0xd82a7b68, 0xa8b65319, + 0x0d789d69, 0x04ee8210, 0x5240cec3, 0x44cdf9eb, 0x3e9be0fc, 0x5b4a29f9, 0x63feb3f8, 0x9cfb2a6d, 0x8511a2af, + 0xa70f0dda, 0x3874ca42, 0x8c1e33ec, 0x5c198862, 0x5d3d2126, 0xca76ab0f, 0x4bcf0901, 0x34634fed, 0x5f2f50d0, + 0x0a62a4c8, 0xfa3f8f9a, 0x6838c4fa, 0x45bcf291, 0x33420971, 0x3b19032f, 0x5a78ab1b, 0x8a2a2d9c, 0xf6e42092, + 0xe932953d, 0x21440e30, 0xc80d9ac9, 0xf4e21c8b, 0x2e304404, 0xb0d8a528, 0x502ec2e0, 0xae02393c, 0x1a7f6fd3, + 0x284f7eae, 0x472e20b4, 0x566fd29b, 0x266e4ffb, 0x094113e4, 0xf89aa4fb, 0x4831b50b, 0xb10d2943, 0xdaaef780, + 0xbc6bddac, 0xb10a66e1, 0x1b4323d0, 0x4709e2e1, 0xb1c94599, 0x7602fe88, 0x6828bd9f, 0x9fe233f5, 0xe500a509, + 0xa3d5179b, 0x6781be15, 0x198b1ac4, 0xbb8d607b, 0x59c3b2c9, 0x640974e5, 0x1bec4641, 0x57bfbe8a, 0xb8ee6496, + 0xa70dc9fd, 0x2d2ef7fe, 0xc8f33ebb, 0x7354232d, 0xb499006a, 0x4753f8cf, 0xbf47144a, 0x15b0f955, 0x08c4d36b, + 0x8f24c18d, 0x86c613b7, 0xee941bc9, 0xe5a4e391, 0x4c14ca0e, 0x5760ddf4, 0xb79cf32b, 0xd3815126, 0xe07e1924, + 0xd7d8b2f7, 0xa607b6b8, 0x8644e7bc, 0xa2df704e, 0x12ef3958, 0xc6fdab8b, 0xeae25855, 0xa19cd609, 0x514b1c09, + 0x51f9fd39, 0xbc71de26, 0xc7be4c41, 0x99a05417, 0xbe634f4a, 0x615edc1b, 0x89f5df75, 0xd933cc15, 0xeda34c06, + 0xf83f96b8, 0x3a28e253, 0xd4d65669, 0x599587c6, 0xdb59fc44, 0xf610a652, 0x5ca01eba, 0x12c68171, 0x504165ce, + 0x1034ca59, 0x69a94ef8, 0xe810b073, 0x3d832886, 0x516e34aa, 0xd729fa0a, 0xe22f63aa, 0xae8bcb90, 0xf4965962, + 0x1750148f, 0x649c4ff7, 0x4417a2ae, 0x574d8c5d, 0xee6368e4, 0x251f2f44, 0x77e9bb1d, 0x4801f2b1, 0x077c927c, + 0x77bda395, 0xb08a6b4c, 0x6c52e0ca, 0x60e769d9, 0xf619855e, 0x7c7652a6, 0xc47a2d6e, 0xf04f973a, 0x9f572aad, + 0xedc49347, 0x8eeea5fa, 0xcfc7b7d5, 0x18d29c3d, 0xfdfdf3c9, 0xd209381c, 0xddfc4ee5, 0x1585dfe1, 0x2859f52c, + 0xd70869fd, 0xd6d6a175, 0xdfe4dec4, 0x0a21b1b5, 0xcfae9b8d, 0x921eb7ad, 0xc9020997, 0x73b44e46, 0xa3bce24a, + 0x3bbbb9b8, 0x4ea918e2, 0x16288893, 0xec331eaa, 0x3ddeea11, 0x6b22a45a, 0x178f2200, 0x543fbbbb, 0x90c223ba, + 0xc167a255, 0x968b52c7, 0x237b45f4, 0x39c9679a, 0x12d07be7, 0xcff443f2, 0x3de08c70, 0xf9eb46bf, 0xecd3696f, + 0xccdd0312, 0x510fd99c, 0x7b075ce5, 0xf2d5972c, 0x13b1a565, 0x647f4407, 0x3dda1c52, 0x0db195b0, 0x2b2f8eff, + 0xfa137377, 0x6caedd85, 0x8fe097e1, 0x10ac8564, 0x72981d2a, 0x08801390, 0x0e3f1ef3, 0x7108f544, 0x6633d426, + 0xc4bd651b, 0x7d06da4d, 0xbc1d9a63, 0x90a067d5, 0x9a7df559, 0x1d0a11b7, 0x1e5da7f3, 0x29fc2c9b, 0xaf70f7dc, + 0xe41b41fd, 0xab9624c3, 0x5d75b435, 0x002621ae, 0x7a9b9919, 0xa33b4861, 0x27d3f2cc, 0x9dd5a907, 0x065640c3, + 0x07086a7c, 0x6ad3c7e8, 0xda61d0fd, 0x997065cc, 0x7ef2b121, 0xeb787574, 0x4d335fd6, 0x32924acd, 0x7a9b34e4, + 0xb141aab8, 0x142c608c, 0x6da52db7, 0x38f48141, 0x3e8c6aa0, 0xb8096c4f, 0x7b861d61, 0xa60fd6b3, 0xc64e4612, + 0x0df0efb5, 0x82a2098c, 0xf58f70cf, 0x090f9316, 0x7adc0c57, 0x89c80d7a, 0x98379e82, 0x07627449, 0xba249bde, + 0xe4071277, 0x335b6e37, 0x10197c05, 0x9806fcf3, 0xd419c50c, 0xa924d154, 0x686a0968, 0x1d4b2dce, 0x5f21ba32, + 0x22a288ce, 0xd46494a9, 0xcacd96f7, 0xd4fb0ef8, 0xb52990ff, 0x4328b4a4, 0xd53e43d5, 0xe17e01ab, 0x22c5f729, + 0xee0e806e, 0xaea91ce4, 0xc9368cf1, 0x3298a441, 0xada607d5, 0x0ce64ea4, 0xb039ee8a, 0xc624916d, 0xce3cb963, + 0x6a21afd7, 0x8bf96410, 0x4618d43b, 0x7def1c9e, 0xcbec3e7e, 0x2fd1e025, 0x87d93d6b, 0x0ff5f5d8, 0x7c21d0d1, + 0xf5ec1657, 0xf4c2190b, 0x2eb3b608, 0x08745f07, 0x6ebf3462, 0xe421705c, 0xe86372f3, 0x49adf1da, 0x5aecc162, + 0x671d0028, 0x1ebbda45, 0xd6d010cc, 0xf5395b97, 0x21df6419, 0x2d4b3d3a, 0x6ad03908, 0x81931219, 0xff65858c, + 0x8e78697d, 0xa9ff5ca6, 0xf2e609c5, 0xccf21be7, 0x83966dfd, 0x8a3cc868, 0x39233e2a, 0xc8902098, 0x69c98dca, + 0xe3ef8e7c, 0xa163b614, 0x14d2a62a, 0xc2c5c281, 0x6cc9b9d8, 0x1062064c, 0x6040cfcc, 0xf92fc8f3, 0xb802811e, + 0xdf2af1db, 0xe8e6f840, 0x1f4ca9cf, 0x6ba56df1, 0xd0ca8462, 0xe37139a6, 0x2fa37f0e, 0x522fb55f, 0xf73269ef, + 0x0a3d8ca8, 0xf16a0a01, 0x1802107c, 0xb4439056, 0x4b0a451d, 0x89ea2c4c, 0xa129618b, 0xceebbdb8, 0x4538462f, + 0x0f0245f3, 0xba48bd00, 0xc35b8aec, 0x87486b26, 0x046413a7, 0x82f0e45f, 0x030c82f6, 0xc8863f3b, 0x5e477d1d, + 0x9c146856, 0x13e2206d, 0x13bf11d4, 0x2be3908f, 0x7a4a1945, 0x1ac7ca96, 0x0c83535e, 0x7390f976, 0x2f2daefb, + 0xf0d7a92d, 0x9fb3f3c2, 0xe1c6de32, 0x834e151b, 0x69ae51f8, 0x4ced1563, 0xec6fb8a2, 0xff68a14c, 0xdc0bf8fb, + 0x01e1bd7b, 0xbc687394, 0x40c2f545, 0xe8af3002, 0xd37a3c35, 0xe7ab8da4, 0xd2096256, 0x838d60da, 0x5e44811f, + 0xe67a6484, 0x272eba23, 0x34568289, 0xe665c623, 0x28e32ebb, 0x380e31e2, 0xec66fa5f, 0x9326ce9d, 0x5d566645, + 0xe60c3eb5, 0x521e1756, 0x5480e735, 0x07b7f520, 0x344470f7, 0xbad01966, 0x435288a1, 0x1b8e3bd3, 0x840bfffc, + 0x06e4073f, 0x5ab23cde, 0xdb0482be, 0xf53e30d1, 0x51d5640e, 0xb5572dcb, 0xad565df8, 0xe60e26c9, 0x03368102, + 0x239bd1df, 0x80cff272, 0x9640352c, 0xa13d9d05, 0xf2e59975, 0x6eb89c1a, 0x081fc914, 0x5fd76af5, 0xb420cc67, + 0xd3941e78, 0x1ad61f76, 0x8fc02d0e, 0xece7be6e, 0x7e13393c, 0xeea6da04, 0xa4a3d76e, 0x3648ad17, 0x8aef288e, + 0xa1ce51e4, 0x64a93a93, 0xfd2f5089, 0x599bac3a, 0x8d3a0170, 0xf8b3cd30, 0x89ab7843, 0x1d3e5db8, 0x06cbb16a, + 0xd28952d2, 0xca284893, 0x8fd1a1e1, 0xecc8aa4d, 0x465de563, 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, + 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, + 0x9e794663, 0xecda4063, 0x4f3c615e, 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, + 0x5bee2390, 0x5bb0ac2d, 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, + 0xcbc03381, 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, 0x5e365ae5, + 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, 0x1da22f3d, 0xbde1988d, + 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, 0xc654b0f4, 0xb3c61edb, 0x34380acf, + 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, + 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, + 0x6ca12b76, 0xca9e521a, 0x3de6ed99, 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, + 0xe3860943, 0xf1f3f4e7, 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, + 0x401dd9b2, 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, 0x9c7c7cab, + 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, 0x68fd2cdb, 0x5b325dc5, + 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, 0xdfeceee9, 0xeff255fc, 0xfc97bd59, + 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, + 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, + 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, + 0x19026be2, 0x106a090e, 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, + 0xfd1119a3, 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, 0x2e43d2db, + 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, 0x24996054, 0xe5fd7518, + 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, 0x19490a6e, 0xbfcc1617, 0x967882fc, + 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, + 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, + 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, + 0x071ae0e6, 0xc3c8d053, 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, + 0x3678e185, 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, 0xb67c5819, + 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, 0xc2222ef2, 0x5a046246, + 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, 0x54a3bc82, 0x5706694c, 0x4664f6db, + 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, + 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, + 0xce8f27be, 0x5a559021, 0x9b1740dd, 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, + 0xe9952168, 0xdc81cac7, 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, + 0xb58b5c72, 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, 0xd99e6ac7, + 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, 0x3635a87c, 0xcee78062, + 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, + 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, + 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, + 0x384ad656, 0x9d824935, 0xec915f03, 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, + 0x4064fbb5, 0x66ad961a, 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, + 0xdbe24543, 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, 0xcadaf946, + 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, 0x628675d3, 0x6b1d569f, + 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, + 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, + 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, + 0x8d3c9334, 0xe5c6c529, 0x20e898db, 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, + 0x0d748033, 0xecc5393a, 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, + 0xf35661c3, 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, 0x5d2efdf7, + 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, 0x69c800e0, 0x5d310e80, + 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, 0xe9811969, 0xc08a7628, 0xe5e44555, + 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, + 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, + 0x80082d96, 0xb5a06d54, 0x1612537d, 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, + 0xf2fac0cc, 0x737aeb61, 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, + 0xaa36609d, 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, 0x0c2f32bc, + 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, 0x6a6777dd, 0xa7029cb3, + 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, 0x59ebc41f, 0x7e55932d, 0xcf78bead, + 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, + 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, + 0xc99944ec, 0x5289e5ff, 0xd64dd767, 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, + 0x4cf9307b, 0x1b6533fa, 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, + 0xe854ce92, 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, 0x408694a5, + 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, 0x24ed6723, 0x0c24fa00, + 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, 0x7db55eaf, 0x0fa8aabb, 0x0e942194, + 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, + 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, + 0x0350d608, 0x54e77f30, 0x866c2575, 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, + 0x3bf7c1bd, 0x5762abb7, 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, + 0xa9a36bdc, 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, 0x5b171723, + 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, 0xe66188ab, 0x4d2b635b, + 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, + 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, + 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, + 0xa31e8408, 0xac80b477, 0x7e7ddefc, 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, + 0x22eb7378, 0x08773858, 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, + 0x65c5fac3, 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, 0x7b9de18a, + 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, 0x804275c8, 0x6ff502be, + 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, 0xf65056f7, 0x18393ab3, 0xbf8c8b96, + 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, + 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, + 0x9685fd96, 0xc354066f, 0x9cdbc452, 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, + 0x328dfdbe, 0x7d168a67, 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, + 0x5fd2e5d7, 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, 0x3fb91263, + 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, 0xca097d3e, 0xa90c478f, + 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, + 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, + 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, + 0x4b823e48, 0x581b2420, 0x4ff2d70c, 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, + 0x476626bc, 0xad5c9d4c, 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, + 0x766880ca, 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, 0x89eac33c, + 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, 0x4eb31945, 0xf2c5d93b, + 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, 0x793fdc45, 0x519a1c15, 0xe31ee96d, + 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, + 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, + 0xd036e501, 0x0cb814a8, 0x06b9ab5d, 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, + 0x9284b162, 0x2cd5b7ab, 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, + 0x6ba484fe, 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, 0xdd4c9f22, + 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, 0x7143f3bb, 0x540b1347, + 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, 0xb2874627, 0x7f0c9a4a, 0xf8106eae, + 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, + 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, + 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, + 0x15aa0461, 0x1bc775e8, 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, + 0x68377d59, 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, 0x90689424, + 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, 0x362b4809, 0xec92588b, + 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, 0x32a14d01, 0xf4f6fec4, 0xada9360c, + 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, + 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, + 0x86428407, 0x45d6c023, 0xc77ebdeb, 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, + 0xf8198b68, 0x881246e7, 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, + 0x9e82681e, 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, 0x2d42e033, + 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, 0x0d1c971e, 0xe7795114, + 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, 0xb31d23cd, 0x8102d36d, 0x51aeed2d, + 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, + 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, + 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, + 0xbd3d8fa0, 0xe798d010, 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, + 0xa956eb79, 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, 0x723065f1, + 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, 0xac794782, 0x002064e9, + 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, 0x344f1195, 0xa7181920, 0xd05fcfd2, + 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, + 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, + 0xb75639f1, 0xadc76771, 0xd3543fd5, 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, + 0x6c95fd6a, 0xc3bb4a03, 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, + 0x045c945f, 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, 0x5acd89f8, + 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, 0x353f926c, 0xe3471231, + 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, 0xd16e5090, 0x9eff66f3, 0xa35ee078, + 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, + 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, + 0xc4062fef, 0x2bd3b757, 0xcbd45594, 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, + 0x2857a67c, 0xce5b2c90, 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, + 0xcd439cd3, 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, 0xbb20e7d2, + 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, 0xee542f36, 0xb0807f6e, + 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, 0x5104928d, 0x047c150a, 0x328cc000, + 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, + 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, + 0xcd61b411, 0xfddd923d, 0x638d0e61, 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, + 0x6bef47aa, 0xf460b130, 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, + 0xdfe4f729, 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, 0x55d094ff, + 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, 0x3161690b, 0x3ffa1fcd, + 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, 0x8a41bcac, 0x38d2f20e, 0x9aac541c, + 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, + 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, + 0x54705c7e, 0xba150347, 0xa80514ec, 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, + 0x7ce59906, 0x577da8f1, 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, + 0xd28382ff, 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, 0xb7bc9a79, + 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, 0xcc0be43f, 0xa606a522, + 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, 0xea4a38b5, 0x76901b4b, 0xe2583ac7, + 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, + 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, + 0x0cfe6db5, 0x5accdc39, 0x3377eaed, 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, + 0xc8bd6a8f, 0x625a6215, 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, + 0xae81db75, 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, 0xfee25664, + 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, 0x8bb3653b, 0x026eedbb, + 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, 0xb5bcee42, 0x6db10b43, 0x9fec55e3, + 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, + 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, + 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, + 0x429e2dc7, 0xc309b30a, 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, + 0x7874b53c, 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, 0xb92b80c7, + 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, 0x3326a1a1, 0x78b01e6e, + 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, + 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, + 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, + 0xc687b587, 0x383f7c40, 0x54830d04, 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, + 0xbf32f0c7, 0x2a796a67, 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, + 0xfd0367d1, 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, 0xc0e35390, + 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, 0xa32b3c81, 0x1d02d66b, + 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, 0x456c5876, 0x4c7a1f7d, 0x8210e535, + 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, + 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, + 0x03826132, 0xf505a1c5, 0x5536b8f5, 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, + 0x743d2b0d, 0xa82aed8d, 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, + 0xafef4d80, 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, 0x6b311848, + 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, 0x129d80fd, 0x18982768, + 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, + 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, + 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, + 0xeaac07b5, 0x0a377949, 0xcea56fc5, 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, + 0x65e46fe0, 0x9a5df9f9, 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, + 0x8358ab8c, 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, 0xdc18fabe, + 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, 0xd48cbb77, 0xcffdb7b0, + 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, 0x8ac94023, 0x11efd6fa, 0x5a6574f0, + 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, + 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, + 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, + 0x743b1a4d, 0xcd7ff202, 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, + 0x18060bb0, 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, 0x4bdc887f, + 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, 0x58f5a07b, 0x3c0266e5, + 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, + 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, + 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, + 0xbbff8af7, 0xaab1617c, 0x596a01d9, 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, + 0xd980aa05, 0x9269bb19, 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, + 0x298eb742, 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, 0x27fd3816, + 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, 0x2ae780c3, 0x7374f385, + 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, + 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, + 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, + 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, + 0xc19f5cac, 0x0bed2aa4, 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, + 0x783cfc66, 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, 0x1628b35c, + 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, 0xb361da26, 0xc0e2aa6b, + 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, 0x10f2492f, 0x231be0f1, 0x2b6fc840, + 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, + 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, + 0x7f6ace2b, 0x21514ebb, 0xc46d4800, 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, + 0xaf2ba637, 0xc4063ea0, 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, + 0xf942657f, 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, 0xea694198, + 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, 0xb453ee10, 0xafe27498, + 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, 0xbb74e075, 0x4408ab02, 0x2eae958a, + 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, + 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, + 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, + 0xfc5ff382, 0xc25ae007, 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, + 0xca5e1ee1, 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, 0x27c57f08, + 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, 0x86952278, 0x2810740c, + 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, 0xabc1d828, 0x05b673a5, 0x93e0c5ce, + 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, + 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, + 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, + 0x9d268a7e, 0x0485322e, 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, + 0x4f7b98f0, 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, 0x9161c085, + 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, 0xd6243501, 0x50f99e78, + 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, 0xe7888474, 0x58967c61, 0x9c2344d8, + 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, + 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, + 0x4a543dd4, 0x72d27f50, 0x794b2c38, 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, + 0xde3dfa58, 0xeac4977f, 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, + 0x4e87a4a4, 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, 0x829272a4, + 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, 0x508ed11e, 0x34f13455, + 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, 0xd435af57, 0x3e86d270, 0x7f04d0f2, + 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, + 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, + 0xfc49bc3d, 0x55757973, 0x84149ef8, 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, + 0xa17f53c4, 0x882c2967, 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, + 0xb340d658, 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, 0x76c9e6a2, + 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, 0xcc17d17e, 0xc52d9ae0, + 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, 0xad9625b4, 0xdbb45f5b, 0xf707fbea, + 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, + 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, + 0x6107a718, 0x83643c4c, 0xf2f96503, 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, + 0x41397ea1, 0x5793b309, 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, + 0x30ed4df8, 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, 0x9e264e70, + 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, 0x3f767c6f, 0xd1c48bab, + 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, 0x50da0980, 0xac96ecf6, 0x008c4910, + 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, + 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, + 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, + 0x49a844d0, 0xbbf5495f, 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, + 0xc41a3c1d, 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, 0xdea90048, + 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, 0xb709b9fe, 0x4549aaea, + 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, + 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, + 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, + 0x17a388b9, 0x78038049, 0xc505ab47, 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, + 0x7e6727d2, 0x9cef5fce, 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, + 0x88bb5013, 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, 0x17261a8e, + 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, 0xf480ab6d, 0x39525194, + 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, 0xdfb74aec, 0x62aae2f0, 0x46b855b3, + 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, + 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, + 0xe260be49, 0x18b01f3b, 0x0a2fc30f, 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, + 0xfb85d9ea, 0x2ddace97, 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, + 0x8c823cb1, 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, 0xf22f9ccd, + 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, 0x769e9c28, 0x65f8905d, + 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, 0x631f0974, 0x3f48dae6, 0x025739cd, + 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, + 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, + 0x5113ea88, 0x72ef2942, 0xd4aa0766, 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, + 0x74798f9c, 0x35e96814, 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, + 0x5ddb2efb, 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, 0xf4ab5191, + 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, 0x88a6c986, 0xdb0e7bbb, + 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, 0x0baad5bf, 0xaed19942, 0x66e4b053, + 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, + 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, + 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, + 0x34268b83, 0xe4bb7d3a, 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, + 0xac836a26, 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, 0xec264fe5, + 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, 0x381f32a7, 0x20a5e8c0, + 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, 0x15470bc2, 0x9ef31ae9, 0xd9e26951, + 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, + 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, + 0x2bf519ed, 0xf57860ea, 0xd69ba992, 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, + 0xccfc8b54, 0x58a93087, 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, + 0x60d94733, 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, 0x8ae04ca7, + 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, 0xca2f0fa1, 0xaac2e3bb, + 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, + 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, + 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, + 0x07796220, 0x0f0f8722, 0xbd6092dd, 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, + 0x17862bac, 0x610b9ce2, 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, + 0xcf3f6b27, 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, 0xff007778, + 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, 0x15a2c929, 0x9263b116, + 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, 0x187b9976, 0xf5ea2689, 0x87e3b151, + 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, + 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, + 0xbaa41197, 0xe5dcc72c, 0xaf16a669, 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, + 0x257e15c8, 0x12fbc35b, 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, + 0x4f1906d3, 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, 0x6d7b3b88, + 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, 0xfc5fbfed, 0x18db2aa6, + 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, 0x4429b1aa, 0x838682ab, 0x5bdfd86b, + 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, + 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, + 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, + 0x5e68e36b, 0x838322dc, 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, + 0xed6bf807, 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, 0xfb7507a4, + 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, 0x532e6654, 0x0c528786, + 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, 0x230b4319, 0xdd780574, 0x58889d79, + 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, + 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, + 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, + 0x73e830ce, 0xb353b81d, 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, + 0xe7929941, 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, 0x45da675f, + 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, 0x52a33502, 0x7d4b918c, + 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, 0x4b0a5e47, 0xce55bc17, 0x09656fd6, + 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, + 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, + 0xfe627e5d, 0x791daf5e, 0x50943665, 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, + 0x3e6a0f21, 0x9dad2288, 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, + 0x72f16cfc, 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, 0x86de5619, + 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, 0x06add0d4, 0xd0c462c6, + 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, 0x494f49bb, 0xcd7f90a5, 0xb6709e40, + 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, + 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, + 0x9bafb81d, 0x62e53468, 0x86ec692b, 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, + 0x8d6632f1, 0x8ba05667, 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, + 0xcfad36f8, 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, 0x526af581, + 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, 0xdea23b22, 0x9f8c78c5, + 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, 0x8d801702, 0x98d2fe2d, 0x3ed6b821, + 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, + 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, + 0xb2ccc077, 0x6162fefd, 0xb3701463, 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, + 0xeabc4ede, 0x82191ff8, 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, + 0x3e457dab, 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, 0x5ecc278f, + 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, 0x0862a010, 0xb3c9a772, + 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, 0xed37dba7, 0x26112057, 0x68c688f2, + 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, + 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, + 0x67c335d0, 0x6981f384, 0x6ca54c87, 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, + 0xf5315cf0, 0x995fb40e, 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, + 0xa571dfbf, 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, 0x1ce39a6b, + 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, 0x33a6d8b3, 0xd9101e64, + 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, 0x13eb0f7c, 0x77b31835, 0x65c53459, + 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, + 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, + 0x0e5f8848, 0xd61ad101, 0xf44c42a4, 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, + 0xd37d5397, 0xeada6952, 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, + 0xfea92813, 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, 0xded23976, + 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, 0x881ccb9e, 0xa1bb6a8d, + 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, 0xe19a859f, 0xfb877d69, 0xc91faf5e, + 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, + 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, + 0xd5e24aec, 0x6731d1b3, 0x48ebc226, 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, + 0x18281991, 0x42588569, 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, + 0x915978fc, 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, 0x4a5faf73, + 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, 0x477d5c34, 0xe2ef3d70, + 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, 0x6db3425d, 0xce451d6f, 0x6f2a53e9, + 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, + 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, + 0x0365098d, 0x013e15ad, 0xc990d5f4, 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, + 0xed216f9a, 0xcb714de5, 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, + 0xf602de55, 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, 0x99029b50, + 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, 0xbd2995e9, 0xd906ec04, + 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, 0xb921c72a, 0x9fc5a234, 0x55d0fbec, + 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, + 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, + 0x84b6ab49, 0x5b3c6835, 0x0015afb6, 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, + 0x89cc97bc, 0x713d3b24, 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, + 0x86363b5f, 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, 0x7368089c, + 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, 0xe516c9a0, 0xeab5aa5d, + 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, 0x614782cd, 0xce169d44, 0x6433de5e, + 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, + 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, + 0xc0ac7573, 0xca381e11, 0xfc5916b6, 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, + 0x332f9714, 0xa3804fc5, 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, + 0x37552b9e, 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, 0xe9b11f94, + 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, 0xcfed5315, 0x27f4a06d, + 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, + 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, + 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, + 0x3c9c2d05, 0x6794edd6, 0xc22cc352, 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, + 0xc045f697, 0xfd090038, 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, + 0x36ae74e4, 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, 0xd85611c1, + 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, 0xb326cc47, 0xe0faa978, + 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, 0xb77eda67, 0xc49052e6, 0xc514a075, + 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, + 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, + 0xf28a6231, 0x9eaa4f64, 0xe9468748, 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, + 0xd8eae4af, 0x46876f0b, 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, + 0xd1daf994, 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, 0x5389bce5, + 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, 0x62a8e0a5, 0x200442ca, + 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, + 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, + 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, + 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, + 0x29bc2f91, 0xac5eaa62, 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, + 0x8bc6cf4f, 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, 0x6bbb33dd, + 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, 0xf708838e, 0x2caf050b, + 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, + 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, + 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, + 0x6746103e, 0xa0eff544, 0x0bba778a, 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, + 0xf1ee2d08, 0x1b100e82, 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, + 0x7ea8c2c3, 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, 0xd1d5c2c0, + 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, 0x5ce3fa8a, 0x2075b595, + 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, 0xdb4a2241, 0x806460ec, 0x183637f9, + 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, + 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, + 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, + 0x724a1e6a, 0x1f49fcfc, 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, + 0xf8481f7d, 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, 0xc548731c, + 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, 0x92d1c238, 0x59503c44, + 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, 0x82172a29, 0x5db3569b, 0x6a0ab6f7, + 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, + 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, + 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, + 0xc2110048, 0xef4c9825, 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, + 0x3d923162, 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, 0xaddd3c63, + 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, 0x20d00302, 0x0718e1f1, + 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, 0xb6747958, 0x6bcb60f5, 0xbce4158b, + 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, + 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, + 0x436ca416, 0x0091a7da, 0xe705853a, 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, + 0x99f5e336, 0x67e6d388, 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, + 0x20fa88af, 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, 0xdeb5cc9a, + 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, 0x112a8ec2, 0x385e89a8, + 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, 0x0c60638a, 0x0c83492d, 0x95d61b20, + 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, + 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, + 0x50f5b110, 0x0c23b119, 0xbc27c7e8, 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, + 0xd1b98d82, 0x632df3e2, 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, + 0xe98733e0, 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, 0x75257595, + 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, 0xf12a2f87, 0x900624fa, + 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, 0xf3be72c7, 0x01ca0052, 0xdf927440, + 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, + 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, + 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, + 0xc226cc77, 0x294e0e4e, 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, + 0xd0489c01, 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, 0x5d6bc3c2, + 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, 0x0c117533, 0x0b70ddeb, + 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, + 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, + 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, + 0x4cd711a6, 0xc46a6a58, 0x2d82b595, 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, + 0x9920ac09, 0x02db13ae, 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, + 0x108cdb88, 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, 0x2944706d, + 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, 0x8ee22fc9, 0x9970baae, + 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, 0x253d5795, 0xa8e3738b, 0x9770975d, + 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, + 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, + 0xacabe801, 0x47952193, 0xd3138e94, 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, + 0x68161660, 0x6365afcf, 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, + 0x96847976, 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, 0xedabeffe, + 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, 0x25d6ba47, 0xec63d289, + 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, 0x671596a0, 0xa08b6a5b, 0x0bca7779, + 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, + 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, + 0x9e283138, 0xb2631843, 0x8c9d46d6, 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, + 0xa4fa2f87, 0x472f5be5, 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, + 0x6fba83bf, 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, 0x7d4f1ea5, + 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, 0x9b0b0ade, 0x6373a3b0, + 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, 0x4c9ca5fd, 0x7f1f3313, 0x30013306, + 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, + 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, + 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, + 0xbed76d66, 0xf5b960da, 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, + 0xad500497, 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, 0xef6e61d8, + 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, 0x4ed7b964, 0xff1f6c98, + 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, + 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, + 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, + 0xbbdb8c62, 0xf6dd386b, 0xe3358787, 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, + 0xce5af4fb, 0x712564e1, 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, + 0x66f6d4a7, 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, 0x499c86a6, + 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, 0xc94b8391, 0x7bd8e512, + 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, 0x449df40e, 0x93f035f8, 0xafd2521a, + 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, + 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, + 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, + 0xf9621d42, 0x77ee21f3, 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, + 0x45317e93, 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, 0x080f5133, + 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, 0xf8ab5684, 0xbd3b8b9a, + 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, 0x428761dc, 0x97459150, 0x709e0a12, + 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, + 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, + 0xac7d020e, 0xa7bf5312, 0x4c6834b7, 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, + 0x03f9e743, 0x3004dfb0, 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, + 0x9ad90bde, 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, 0xa1fc99fe, + 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, 0xfd35ccf2, 0xd2473bb9, + 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, 0x32e8b9f2, 0x103ef0a9, 0x1888642e, + 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, + 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, + 0x8ec2282a, 0x146232d5, 0xf4241f66, 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, + 0x2d03e06e, 0x305c322c, 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, + 0x2c33b686, 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, 0xa9d0de99, + 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, 0xce93f4cd, 0x822382ec, + 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, + 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, + 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, + 0xc83c381c, 0x098d5293, 0xc0738c93, 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, + 0x359fc239, 0x806328f8, 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, + 0x7d0cf9c7, 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, 0x356f9c19, + 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, 0x96e32fe0, 0x142e5994, + 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, 0x702f1422, 0x4008e264, 0xbbf91d05, + 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, + 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, + 0xa6b29bb4, 0x67777742, 0x65b6542c, 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, + 0x86507fb1, 0x26f76111, 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, + 0x658bb0c8, 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, 0x685d4d9a, + 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, 0x30d5acc3, 0x18d236ab, + 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, + 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, + 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, + 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, + 0x37160e0f, 0x9f623018, 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, + 0x99b0115b, 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, 0xc7d5de52, + 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, 0xf080b017, 0x4da4d290, + 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, + 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, + 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, + 0x0d628e03, 0x4a93cdd8, 0x6f643479, 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, + 0x1983f603, 0xd4591b19, 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, + 0x3488b648, 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, 0xde17a435, + 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, 0xc4706c3f, 0xdf14d9ab, + 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, + 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, + 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, + 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, + 0xb8c941ca, 0xe26b9187, 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, + 0x0bbe4840, 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, 0x7fa40f5f, + 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, 0x611a0f89, 0x3a0e5f8a, + 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, 0x01079381, 0xc250fa30, 0xead64afb, + 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, + 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, + 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, + 0xe5b8b32e, 0x9c6261e3, 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, + 0x8f854e38, 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, 0xa8e1a4e5, + 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, 0xff46bbb2, 0xa38e83bd, + 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, 0x6a145a5c, 0x6a41add1, 0xd954c1f0, + 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, + 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, + 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, + 0x5eba32d0, 0x3cc4a69c, 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, + 0xc8013642, 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, 0xe9e313b3, + 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, 0xef679615, 0xc074d215, + 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, + 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, + 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, + 0x208a0b6f, 0x7245f138, 0x352dee4f, 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, + 0x46fc92f6, 0xfcfa9de2, 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, + 0xa44da7f3, 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, 0x35818ebe, + 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, 0x3a03b930, 0x868b0e63, + 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, 0x4d72927a, 0x1b62ae8f, 0xef765353, + 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, + 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, + 0x83b4c653, 0xfd8585e4, 0x23af00e8, 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, + 0x822679ff, 0x695356ac, 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, + 0x9a82734d, 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, 0xccf76bc6, + 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, 0x0e3e6c5f, 0x83452a89, + 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, 0xdadeeb74, 0x7425d656, 0xdcf615c1, + 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, + 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, + 0xc725ecc0, 0x35b295d1, 0x7534f83a, 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, + 0x98a03f22, 0xd70a9952, 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, + 0x7ccba435, 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, 0x771d7fac, + 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, 0x59029f2b, 0xb47ed32a, + 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, + 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, + 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, + 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, + 0xdf2b52bc, 0x0849a8d7, 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, + 0xcca50f90, 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, 0x38d03044, + 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, 0x7ec20957, 0x2e01a0db, + 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, 0x0b90f4dd, 0xa36b8065, 0x31933133, + 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, + 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, + 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, + 0x339b1a9d, 0xcd9c7feb, 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, + 0x85fd0e01, 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, 0x0470618d, + 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, 0x89209a5c, 0x5a60a94e, + 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, 0x22497a31, 0xf3512771, 0xb6adb43b, + 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, + 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, + 0xfc9d64e3, 0x1b454a6d, 0x8b220894, 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, + 0xc66316e8, 0x52366573, 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, + 0x2d196453, 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, 0x6fb6bf96, + 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, 0x3c9257fd, 0x8a3d0140, + 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, + 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, + 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, + 0x615723de, 0xf5fde9a0, 0x96bab4f4, 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, + 0x54f0e2e2, 0x5355cc42, 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, + 0xf6ff9372, 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, 0x0230da46, + 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, 0x26a6191d, 0x83da081c, + 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, + 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, + 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, + 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, + 0x8bf9c71e, 0x1a682b8a, 0x7bbd75b5, 0xb06c035c, 0x9bd1355b, 0x03f15e1b, 0xe1dc6a96, 0x724c12d5, 0x5eeb7abd, + 0x6f1a533d, 0xe4163b97, 0x53963f78, 0xf4bdc4cf, 0x30bc6aa8, 0x55020a94, 0x87424139, 0x7f4e0fc0, 0x0dced4cc, + 0xcc44f761, 0xdc915d5d, 0x5923afae, 0x5fca09df, 0x6da60086, 0x4176cac0, 0x2cd1c0be, 0xeaf4a65a, 0x9a2b0460, + 0xd9adceb3, 0x837911fc, 0x24a064e2, 0xf62aef80, 0x2c72361c, 0xabcea574, 0xc9e8494f, 0x58fdc7fe, 0x19835be7, + 0xe2f50795, 0x22577eee, 0xf37a909d, 0x01085e15, 0x433de341, 0x47e376d9, 0x0bba767a, 0xf77fa338, 0xdaabb9e6, + 0x321bb7de, 0xd9c18914, 0x63c61551, 0x608ac9b2, 0xdc175799, 0xa3b005c1, 0xb30ba812, 0xb8f13ae7, 0x4e6515ee, + 0x63b6e03c, 0x21dc18eb, 0x92116367, 0x912c40eb, 0x67431a9d, 0xa3ac94ae, 0x8778ab34, 0x97d032f9, 0xe363d369, + 0x83361fee, 0xfc13d3ed, 0xa8b81258, 0x3ad31da7, 0xf22b43bc, 0x5e4dc39b, 0xaf3c8d97, 0x4e4f0c56, 0x9ad45750, + 0xce42b7f5, 0xfee1c9dc, 0xda821b40, 0xe112aa6d, 0xc534e246, 0x49278e21, 0xb44895c1, 0xe3d1ab5b, 0x73a79242, + 0x6c9f7498, 0x635ece54, 0x11679e76, 0x2ecfb564, 0x32fac952, 0x9ef53d09, 0xe639b29c, 0x6bc8773e, 0x1bc739cc, + 0x89ba5c0c, 0x4bd2bc26, 0x422ddfd6, 0xfdb0a8e4, 0xcf2f81a5, 0x14841e89, 0xd4f78e53, 0x63013219, 0x359821da, + 0xb02ce75b, 0xac288e79, 0xd6225779, 0xe9c65694, 0x49a11a14, 0x1607727d, 0x5371ef25, 0x6e32e37e, 0x46463aa1, + 0x2f9f3be7, 0x008814a8, 0x4aaeb902, 0xeaf8f5a0, 0x36ff71ae, 0xeda38d7c, 0xc8154fa2, 0xbd72884c, 0xeb83e123, + 0x8c815ce0, 0xe3cec3c1, 0xb7cb6a68, 0x4b2967a5, 0x6f401978, 0xa790036a, 0xd7098ddf, 0xe29bc8fc, 0x990029a6, + 0x03cdb1fe, 0x0dd3e1d0, 0x154d7ad7, 0xf416dee7, 0x5563bc46, 0x724bd24d, 0xc9afafda, 0x15fbdda1, 0xdafbcb38, + 0xd5a26b25, 0x619bed77, 0xba04b927, 0xfd2d6b8a, 0x77894e2e, 0x3a2b2115, 0x4f97c16a, 0x624c5c48, 0x87b8ac99, + 0x52727b94, 0x1e24f7f7, 0x075e8797, 0xf6c0d443, 0x1bbfc65e, 0xaaef1178, 0xc6ee8328, 0x328b718e, 0x6f763df7, + 0xf0198c11, 0xd6cd4bf9, 0x3ee66642, 0x717949cd, 0xd07b2cb7, 0xa023dc26, 0x36fb0e07, 0x833771f3, 0x865405d9, + 0x440f6fbb, 0xaf079d0d, 0x2187a5d8, 0x1c48bf61, 0xd1a3e59f, 0x022d6bda, 0xd6bbf539, 0xf7e1e652, 0xd13cd569, + 0x1953bd8c, 0x2c00848e, 0x15a8bd5e, 0xf1633fe7, 0x56e8f0b5, 0x3b009bee, 0xd18e24a5, 0x06e6be5a, 0x20b080a8, + 0x2b7c3d6b, 0xc9e867d9, 0x013902a6, 0x722d7f90, 0xaa97b1b4, 0x6a72eaa5, 0xa35fb788, 0x02c7801c, 0xf528ad86, + 0xc08e0f90, 0x36013f85, 0xb6507cfb, 0xce50853b, 0xdc81a410, 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, + 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, + 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, + 0xca3c7387, 0x3ebc4e22, 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, + 0x0d609b5c, 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, 0xe964371d, + 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, 0x8549a545, 0x72cd25a6, + 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, 0xfa0f309d, 0x2450505b, 0x7e62d6b6, + 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, + 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, + 0x554de3f7, 0x00236229, 0xb65a8838, 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, + 0x1e0f4174, 0x0e4f84a9, 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, + 0xbecc7016, 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, 0x36f74f81, + 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, 0x49684acc, 0x27ceed4c, + 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, 0xc18462c5, 0x30407eb5, 0x8e18797a, + 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, + 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, + 0x39bc1a46, 0xf4865fdf, 0x22bd8658, 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, + 0xd9382232, 0x947cd63b, 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, + 0x65a5e218, 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, 0x9cff960e, + 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, 0x5da4cf70, 0x861ef098, + 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, 0x2d914387, 0x9ed7f94b, 0xf00b5441, + 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, + 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, + 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, + 0x78603c0a, 0x7c403889, 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, + 0xe1fecec4, 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, 0xee70ca50, + 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, 0x57098afb, 0x744d626d, + 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, 0x5936ff74, 0xc1477a35, 0x3665ecdc, + 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, + 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, + 0x7e1959e1, 0x91787e6c, 0xda51caa5, 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, + 0x8fc78d5d, 0x3ea2142c, 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, + 0xa69d279e, 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, 0xb001c899, + 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, 0x46ebff79, 0xccb7b9b6, + 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, 0xac829629, 0x9ffbf3a3, 0x718c8f7c, + 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, + 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, + 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, + 0xbba13c12, 0xdd02c804, 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, + 0x347c5339, 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, 0x4396ff24, + 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, 0xee7ad3a2, 0xcc436c78, + 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, + 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, + 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, + 0x68c77435, 0x356f1249, 0xec7fe5ec, 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, + 0x8bac2cae, 0x5104a87d, 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, + 0xd5a33292, 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, 0x129c6972, + 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, 0xa54b4c48, 0x667c537f, + 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, 0xe16ab1b9, 0x3d5dd389, 0x5947821b, + 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, + 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, + 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, + 0x8e2665b7, 0xee93572c, 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, + 0x07a80a9b, 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, 0x8a302c05, + 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, 0x9b86cabe, 0x48f7ca80, + 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, 0x79bda240, 0x909fd98e, 0xf49643bc, + 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, + 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, + 0x8821bf49, 0xde5b8005, 0x6e749b41, 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, + 0xc85a975d, 0x00904827, 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, + 0x3ac88c9e, 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, 0xadef941f, + 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, 0x15116dd8, 0xcf51bdc7, + 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, 0xe55e6fbb, 0x43524b5b, 0x12dbc403, + 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, + 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, + 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, + 0xb541d640, 0x84ceb075, 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, + 0xd2f96c90, 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, 0xc9f9d7ed, + 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, 0x3ba18f38, 0xb9d8d6f5, + 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, 0xf818f739, 0x08eaf9e5, 0xc9f08a15, + 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, + 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, + 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, + 0x730d6d4c, 0xb4f2cb42, 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, + 0xfffa9c44, 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, 0xb4ba3765, + 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, 0xf93f4075, 0x9d0ed557, + 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, 0xa5fd92c4, 0x48985b22, 0x9d228641, + 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, + 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, + 0x7e4bb890, 0x1c7739a1, 0xc91fad83, 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, + 0x1eb7fdad, 0xa71313bb, 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, + 0x75bea2bc, 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0x753eab5b, 0x028a7174, 0x528577a3, 0x527f8b02, 0xa1b0144f, 0xdaf318be, 0x8b70ef61, 0x0a6f4e98, 0x5c5402b0, + 0xf5f647c0, 0x09391889, 0xa368a8c3, 0x2dc9680d, 0xa053cead, 0x904b7287, 0x88459cf3, 0xd2f4f2a2, 0xe9665755, + 0xbb5da568, 0x574a1348, 0x93b4a825, 0x37c32f05, 0xe012ff04, 0xb9eaadad, 0x52bbf0ef, 0x452ee923, 0x46f414f1, + 0xb13669e5, 0x680a6737, 0x7ff4bc68, 0x2d47049f, 0x37cf822e, 0x0583d362, 0x8875d1c4, 0x4c53f671, 0x11cef396, + 0x3dcf89b8, 0xdd2d198f, 0x505f5de7, 0xfbde4756, 0x580d6240, 0x12396e9e, 0xd04f3af9, 0xb186f576, 0x12b2eef3, + 0x9ae8f924, 0x79946ed1, 0x870f473c, 0x462233d2, 0x4fdc6229, 0x9d68407f, 0xf4574c11, 0x355df27d, 0xda1de3be, + 0xbdd9bf46, 0x7723e0c6, 0x93f18b70, 0x306a6ce1, 0x5d41b997, 0xd6de717a, 0x77f1220d, 0x22a9c6b2, 0x8f97fe4c, + 0x952cf499, 0x748ea696, 0xfb9b4ae4, 0xd87fae01, 0x36fccf5a, 0x6620b80b, 0x8b775603, 0xdc231fb0, 0x421c13c4, + 0xbd9216ac, 0x9608c70d, 0x9d5f6ba2, 0xdb7c0ebe, 0xae39479e, 0x94e77aae, 0x693e8781, 0x4d32b434, 0x7e62d809, + 0xad4fe846, 0x4c6cb1e4, 0xf7341c44, 0xdab78d72, 0x88cc179a, 0x34752f51, 0x2d637722, 0x7ab4618e, 0xb7c0e04a, + 0xfe04b8cf, 0xae1b6f06, 0xdbda536e, 0x02194b20, 0xe1fd1e8a, 0x1acadfa6, 0xf47bea6c, 0x3330ac5a, 0xa8deb025, + 0xab935609, 0x5d2bc1ca, 0xb25e9564, 0x6bc65a9f, 0xeec6e181, 0x5e6a3d52, 0x0f65008b, 0x6e162c6a, 0x87c3e109, + 0xb684f32f, 0x59622c89, 0x723a0677, 0xb2cebfc9, 0xaa6747bc, 0xdb84b110, 0xc986eadb, 0x1ef4b74d, 0x257244dd, + 0xc156d646, 0x7fab92ef, 0xd424e78b, 0xb3f3c72a, 0xdee49f1b, 0x93fb2c85, 0x0cb3bddb, 0x78993a21, 0x320f261c, + 0xaf7bd6e0, 0x5568d12c, 0x3df76622, 0x652e01ae, 0x23c1a517, 0xac5189aa, 0xec9cf336, 0x17da11d6, 0x6e8e3c34, + 0xa59326db, 0x08b15079, 0x4a3d8b05, 0x866aca5e, 0xae94c250, 0xef5a6c93, 0xbbcc9c7f, 0x4d5edcbf, 0xe3e485d8, + 0x182f07cf, 0xc9168886, 0x1cda176f, 0x00ab3bc7, 0x608bb920, 0x4f315ef1, 0xd8e3cc46, 0xa47388e3, 0xb2cad482, + 0x556def36, 0xa682fa5d, 0x85cad9e2, 0x14079dcf, 0xd78ca346, 0x3fbe135a, 0xc4a78f5d, 0xf4e114ba, 0xee9e3c30, + 0x8b0af991, 0x12e41605, 0xb6267ce7, 0xcc004296, 0x90f3b8f2, 0x2343ef18, 0x2f8052cf, 0x60deb848, 0xf56fe3c8, + 0xad3102f7, 0x89d4a9e5, 0x8af74ed6, 0x62e5b6d5, 0xff59e2a1, 0x6c22b412, 0x5d392bc8, 0x90a724bc, 0x5c978d0c, + 0x830cbc90, 0xe32ddbac, 0x449e7fd3, 0x60b0addf, 0x49dcccbe, 0x5b0462bb, 0xac21c138, 0x8e006f90, 0xa61a2c78, + 0xb5971d36, 0xafdaa33f, 0x1307afee, 0x5ccd38a8, 0x2b79f482, 0x8cf7732a, 0x32c7a0df, 0x6b2ff39d, 0x032680ed, + 0x526206dd, 0x9fddda0f, 0x6d8cfa10, 0x1dd2ba03, 0x243d6ff3, 0x62268387, 0x87230bbc, 0xb8d3b10c, 0x4f6ca07a, + 0xee4f2821, 0x714b1bdd, 0xe6fc96a4, 0xe856122d, 0x477d1b83, 0x70d75b6f, 0x049b7e50, 0x0bf03690, 0x4ba8c681, + 0xc4028d04, 0x2717d0d2, 0xe41916f7, 0x216b1173, 0x97f3bff7, 0x281f9d0e, 0x2c1f2031, 0x6ff48a47, 0x0786c132, + 0xa1b278e8, 0x30e5f64c, 0xfbf93909, 0xf7395c32, 0x832f21b9, 0xbead903c, 0x280f2090, 0x9593f614, 0xb78316c1, + 0xfca3a4c6, 0x609dc7e3, 0x4f273fdd, 0x63f744f1, 0x2c1bbbc0, 0xe4891946, 0xd5f7fa64, 0x9f3f3720, 0x94110d39, + 0xc8ece3ac, 0x4b25b77f, 0x2c2f228f, 0x56986c0a, 0xce8cdea6, 0xd6333dbb, 0x4b5b5e98, 0x326b743a, 0xd0ca9df7, + 0x6993475b, 0x5c002d47, 0x59432f3f, 0xc3f9bd0c, 0x26d08264, 0xb4f895ba, 0xdd8fc625, 0xe0c6e345, 0x75a33645, + 0x19bb6cb5, 0x5a0e78da, 0x193d092a, 0x4e440935, 0xbe128268, 0xd2b9f588, 0xf70c23fe, 0x7379ca35, 0xb57e785d, + 0x6054f3ed, 0x303ebe2f, 0xe935e1a6, 0xb8c1e2de, 0x8bb7a5cc, 0xa6ac5c41, 0xe44e56d0, 0x69139cb7, 0x03a28789, + 0xa7cdf44e, 0xbbf56d72, 0x083d0dd4, 0x192129b1, 0xb7693796, 0x8b198c5c, 0x9de5a28d, 0xf9c6d7c8, 0x99e1d4c8, + 0x8e31d930, 0x7080a51f, 0x073eab76, 0x40df41a4, 0x767d2144, 0x59d43fe2, 0x34a8544f, 0x9b730ff4, 0x2f4bc370, + 0x8ee7f066, 0x4673c32c, 0xe2c7db70, 0xec9179e5, 0x88645dbe, 0x4f79e3e9, 0xe48fba9a, 0x1c3ce3dc, 0x5a477874, + 0xf57dc98b, 0x55976ece, 0x70e9158c, 0x7549148a, 0x18c7e7bd, 0x72660072, 0x67257dec, 0x90e48a8c, 0x5855fad7, + 0x7e9c91d6, 0x4e8ce0ff, 0x18dc5215, 0xc7f6c34f, 0xe7bbf889, 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, + 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, + 0x50dd62e5, 0xf2dc2490, 0xb742d94c, 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, + 0x40278377, 0x4f1306d5, 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, + 0x3c727cc6, 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, 0xe3f264d4, + 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, 0xdf701ef3, 0xdbee77ed, + 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, 0x1830df51, 0xc306d523, 0x9cda51bf, + 0x8e5cd4cb, 0x9c64a289, 0x518101c7, 0xd5398283, 0x485e68ab, 0x3e692182, 0x3f8404fc, 0x0f7b8288, 0x21a08619, + 0x67218b02, 0x8b8dd8b8, 0xad06a7f7, 0x11164df6, 0x25a251ff, 0x42824851, 0x95b27094, 0xf78419a5, 0x409fc546, + 0xe9806b95, 0x51c49c8e, 0xa17e8fc0, 0xa283549a, 0xca0556d6, 0x5a85b755, 0x8b4c4467, 0xb3a58530, 0xe335fac7, + 0x2478b91e, 0xa851b1cb, 0xb8f6e40d, 0xf7cbe7e0, 0x19f408f5, 0xab076b70, 0x4af368d0, 0x97ab3ebe, 0xee6831f1, + 0xef8927b9, 0xae5765ac, 0x2d9bc5e8, 0xea2c246f, 0x15333dbf, 0x240e189a, 0x6a166d85, 0xe0319a41, 0x5f6f8498, + 0xf83a2e4a, 0xf7f8876f, 0xc61d46c9, 0x22e0f274, 0xb6cdcf38, 0xe570e569, 0x9fcf899e, 0x4b270423, 0xe5427fee, + 0x4d645555, 0x4700cfb1, 0x5817d1b4, 0xe8dd508e, 0x77f2ba83, 0xfa4998c2, 0x9f433c68, 0xd5e9bf3b, 0x2efd4983, + 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, 0xc0c97ca0, 0xd6456515, 0x86a49990, + 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, + 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, + 0xab800038, 0x0e5f415b, 0x77d71868, 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, + 0x7999f376, 0x687e76cc, 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, + 0x5d416565, 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, 0x4e064454, + 0xfd9ac6cd, 0x657932b0, 0xcef18b7d, 0x0bf4f022, 0xf908ad45, 0x2e433c0f, 0x7ba69d22, 0xf794e0a8, 0x29e2a151, + 0x59957799, 0xa4754f9e, 0x2de5faf3, 0xc9448dd7, 0x5a8bbe16, 0x817b3cba, 0x015e0438, 0xb6584eac, 0x3cf4538c, + 0xad46789d, 0xd6c7fb4b, 0x2a6bb8e8, 0x95be9156, 0x606ed9f5, 0x5752db89, 0xf9cd5980, 0x616d1e0b, 0xb7e00031, + 0x172330da, 0xb31e0cfc, 0xdb764c09, 0xa75d8e3e, 0x6aa8c866, 0xbdc54d53, 0x2e677e0f, 0x16a51a10, 0xe9499530, + 0x1da12df1, 0xe6dfb914, 0x3bfa92a8, 0xf3f3a88f, 0x87c9392d, 0x111b0840, 0x5ab1777a, 0x192c38c7, 0xf8c834fc, + 0xe8308665, 0xeb187ac7, 0x9c1c5fd1, 0xcca65034, 0x5f8cfc36, 0xd9d46261, 0xf8f4ff49, 0xf1d5e8ef, 0xcce1cd6e, + 0xd1dde85f, 0xe65a1855, 0x433c96b4, 0x93e2108d, 0xcfcf8df3, 0x7666a9d0, 0x82d04f02, 0x9f1d6e6f, 0x735470b8, + 0x8506f50d, 0x74ac2545, 0xac7e968b, 0x8eaebbf6, 0xb78302a7, 0x71a95323, 0x08db57c0, 0xf54079c4, 0x1824e5a0, + 0x7770bb93, 0x320d84f7, 0x31375ff2, 0x671804f9, 0xf7279def, 0x12af1225, 0x9e850124, 0x61b08a45, 0x1b1a25dc, + 0x1583cb8d, 0x85e488d8, 0xa6a2b821, 0xebc28a80, 0x2b042894, 0x1a85276b, 0xb0f5d179, 0xcf990742, 0xfefbe005, + 0x1fb67447, 0x570d2ddd, 0x02811ae5, 0x793feaba, 0x09762f7b, 0x14100df3, 0x7fe64e07, 0x5af3e3be, 0x31eb0ec9, + 0x786d747e, 0x0e0e27bc, 0x47a504c9, 0xeaa9fbb2, 0x1c0d8abc, 0xf8bff67a, 0xaa82f222, 0x8b13aaba, 0xdffcd564, + 0x31726b4c, 0xe9ae18cc, 0x352ad2f4, 0x6b1557aa, 0x135c680b, 0xd4406df5, 0xa79c30c1, 0x231658d4, 0x2fd89315, + 0x36a55e66, 0x159002b4, 0xd05109d6, 0x68dec1c7, 0x97ef5984, 0x68a8fbd7, 0x8dd3e9da, 0x27909f99, 0x28c108df, + 0x54cb0adb, 0x7ce99a35, 0xbede9144, 0xa5672e1f, 0x710533e0, 0x9a2cd910, 0xc2ce4b92, 0x8c80d84f, 0xcee7a884, + 0xdc354a4d, 0x3fc1a23a, 0xeadf8431, 0xd928adc6, 0x2343a0c6, 0x061e72ac, 0xb96ad161, 0x4eabcb14, 0xccd60c7d, + 0xb391f7a4, 0x2beaddc5, 0xb6b90496, 0xb790fe17, 0x465016e8, 0x7da09148, 0x70317f3e, 0x3d032b28, 0x1b054900, + 0x1b74faa1, 0xc754ecc2, 0x126b083d, 0x1d555dfd, 0x60815984, 0xfbbaf3a0, 0x89ca45c6, 0x7812b56f, 0x9cd88171, + 0xb9de6295, 0x843420d9, 0xe56a4205, 0xc061a140, 0x82f466b4, 0xafdec08a, 0x6019c28c, 0xb80e9ebb, 0xdf6bd76c, + 0x01f92766, 0xaabd233a, 0x5f9f1623, 0xd636d41c, 0xb6f0bec6, 0xefd69807, 0x6b32c69a, 0x0b4ad7d4, 0x303bc7ed, + 0x71e76113, 0x72a8b06f, 0x23d24a41, 0x1f672e66, 0x032aa26c, 0xa0cece16, 0x1d383468, 0x3fadf1ac, 0x9071b6a1, + 0x7d060ebb, 0x8724194b, 0x70aa4fe2, 0x7bfb70fd, 0x14464d6a, 0x34e46949, 0x89e163d7, 0xee324189, 0xe7dd5b05, + 0x629d5ac9, 0x9494ec58, 0xda9b9ecf, 0x18810ee8, 0xf64eb695, 0x0412aeb9, 0xbb9974f2, 0x34981e12, 0x183a4215, + 0x0c4ed021, 0x0e2d056c, 0x4eb8189c, 0xdb2491a8, 0xe667f135, 0x830b681f, 0xb0e43c1e, 0xade0eee7, 0xd45ad4b9, + 0x417fdb47, 0xf9521b28, 0x4d491903, 0x9bdac353, 0x7fb4e96c, 0x82e24ee9, 0x550a84ec, 0xca173646, 0x3726dfa4, + 0x1480bb91, 0x9c4bb2aa, 0x518421ac, 0x419bdd5f, 0x4656308e, 0x655f02e8, 0x8cea41ce, 0x29667add, 0xe3f528b8, + 0xd9f0242d, 0x7b3293eb, 0x15f51e24, 0x599ef467, 0x7004d8ca, 0xe25dd7b3, 0xa67f263b, 0x36c8ee1e, 0x94ccd4cf, + 0x8217f229, 0xbda88aa0, 0xb5a8cf82, 0xce0ecfd3, 0xc56425e4, 0x7377f696, 0xe2233c10, 0x7878124f, 0x7ddfdbfc, + 0x3c0a74e2, 0x76f7a00b, 0x8aa3116d, 0xe585bdc2, 0x3454b808, 0xb8eb525d, 0xf03de612, 0xd3625812, 0x5f9e2734, + 0x538214a7, 0x21f2740d, 0x39cafc80, 0x092f0669, 0xc244c4ff, 0x569c8561, 0x8ce00cec, 0xfad3174c, 0x17a98478, + 0x3fba51e2, 0x7839ccd3, 0xd3cc2942, 0x34459786, 0x9e605d5a, 0x481ee65e, 0x63c01029, 0x97c3b03b, 0x0556943c, + 0x9ca515fa, 0x45ee4c64, 0xfed15ef4, 0x65baabdb, 0x037c4d51, 0x892ea8a2, 0x2de6038c, 0xd8716227, 0x57424e4f, + 0xf1b5ca70, 0x287fcd83, 0x653d548d, 0x2baaa7ed, 0x6af133ba, 0x4bfb12eb, 0x0585c00b, 0x7926e62b, 0x67f71020, + 0x06941d09, 0x3269b9d6, 0x6becf31f, 0x18b598fe, 0x139643a5, 0x9a9160e1, 0xbe2df596, 0x782f8037, 0x9bcce7db, + 0xf3be74bc, 0x4f7f7177, 0xddcacedb, 0xd348bb00, 0x0ef68de3, 0x1ff7d95c, 0x6201a28d, 0x24f67327, 0xa1425633, + 0x48426e5d, 0x3ccfed4a, 0x92baf081, 0x868d6418, 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, + 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, + 0xa4f0c02c, 0x006bdbc5, 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, + 0xd9d19ac8, 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0x40bb52d5, 0x654712b1, 0xd8e940e2, 0x8ff4683c, + 0x2a998600, 0xd4aad8ba, 0xee241d02, 0x94346fe9, 0xc02eb848, 0xc2c91e1a, 0xea843f6c, 0x5bc57c6c, 0xddd8a617, + 0xebf9c3c0, 0x4980bc36, 0x6d334dcf, 0x97a4b3df, 0x2a94b788, 0x83811aca, 0xbbc37422, 0x6292df1d, 0x761131db, + 0xb2d8dbe4, 0x7ff0219d, 0x95d470ee, 0xda8c0e74, 0xcf981bc4, 0x95642758, 0x215c055b, 0x2aaea2f2, 0x28a91766, + 0xe750abab, 0x995e1edf, 0xe39955fc, 0x33af7feb, 0x238315d1, 0xa31128b0, 0x46bd2722, 0x6ba31556, 0x1eb5680a, + 0x047e04f2, 0xd0be878a, 0x5803fe07, 0xc5925308, 0x8cd72b70, 0x13bce9e4, 0xef142b76, 0x68732c0c, 0xe74c8b77, + 0xfc9f477a, 0xd05a1414, 0x55b72aa8, 0x4243a9d6, 0x1cf28fe8, 0xc49061c0, 0xf6b1a1f9, 0x6afdd3c0, 0x22b8edff, + 0x8b5ca144, 0xe1d7e6eb, 0x93272db3, 0x89cfb745, 0xcd87fdd9, 0x5096d5bf, 0xbf8b9f4f, 0xa8bc074d, 0x1abdc486, + 0xa9723f41, 0xf4ec25b4, 0xac929bd3, 0x9c4fba86, 0x2a8f1125, 0x5eef358e, 0xea07476c, 0x43cca072, 0x46a07977, + 0x196b7bb4, 0xa4d88ec9, 0x1e1f5fa0, 0x991a7581, 0x5b484319, 0x67a216af, 0xb5e540a1, 0xdd927f99, 0xb410088a, + 0x947b9e49, 0x68a1737e, 0x3890f47d, 0xb0a0347d, 0x3d378123, 0x486a79ca, 0xd226fad4, 0x50af1c4d, 0x6665e7ab, + 0x66a3cdd9, 0x37ffe10a, 0x2b4f5b40, 0x1984039d, 0xcf71baaf, 0x105b0271, 0xce92f7b7, 0x47b7ba55, 0x7dede31e, + 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, + 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, + 0x11e80584, 0x3a49181b, 0x01877253, 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, + 0x7b06c1bd, 0x241bb5d3, 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, + 0x6a39fefc, 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, 0xe97476ff, + 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, 0x6bc54667, 0x5da05bd4, + 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, 0xa18cde24, 0xa865edcd, 0x4a0863f2, + 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, + 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, + 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, + 0x9d3fcbd9, 0xa2157e5f, 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, + 0x8430e9fe, 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, 0xcff88a4f, + 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, 0x027ff968, 0x7c059f38, + 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, 0xd8861fcc, 0xa171057c, 0xc650cd2a, + 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, + 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, + 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, + 0xd2063aba, 0x38356c3f, 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, + 0x1c1010ce, 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, 0x52f9037c, + 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, 0x49c20c19, 0x5283a436, + 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, 0xc2223c9d, 0x99554000, 0xcd28bc49, + 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, + 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, + 0x553e3c53, 0x4ff910a9, 0xb16d9d48, 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, + 0x1ead51ac, 0xf531936c, 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, + 0xd81a58c7, 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, 0x5bf25e25, + 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, 0xc806079c, 0xc684f5d5, + 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, 0x4adb2b92, 0xf781402f, 0x870c8ab5, + 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, + 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, + 0x5d7847cb, 0x800a7cd4, 0x2174ea30, 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, + 0x2e1cd1e9, 0xc7308954, 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, + 0xb2b5f06d, 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, 0x8692254d, + 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, 0xdee4891d, 0x83247a45, + 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, 0x3e9a6812, 0xb7981ce1, 0xd48dac33, + 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, + 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, + 0x79d4b7c0, 0x4f0d800c, 0x6615417d, 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, + 0xb2213194, 0x520c5c4b, 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, + 0x4dbd49c2, 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, 0x7fd1b105, + 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, 0xc844714c, 0x83a50459, + 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, 0x795f7841, 0xa403bc22, 0x95959ab1, + 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, + 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, + 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0304.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0304.h new file mode 100644 index 0000000000..626d8adcb6 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0304.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1110_trx_0303.h + * + * \brief Firmware transceiver version 0x0303 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0304 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x50ac6ada, 0xce141465, 0xe731341d, 0x0a1b7fd4, 0x70036eb7, 0x50edec65, 0x7ef44310, 0x92d846ae, 0xc876e4db, + 0xa72dce23, 0x2c1dcb7e, 0xb562f3f0, 0x8fda552f, 0x25934237, 0xae33f397, 0xc8d9e15c, 0x975172a9, 0xf0684388, + 0x92822a3d, 0xdd64d110, 0xaea510f2, 0xe3b19f19, 0x8b2adf95, 0x09152ad8, 0xb3e33ca2, 0x2ec327ca, 0xe173298b, + 0x81b32269, 0xbb621904, 0x049a0f15, 0xb8c2063f, 0xd2f22703, 0xd276d67e, 0x5cad2676, 0x1144e501, 0xbc5ea2ef, + 0x04926e7d, 0x538810c0, 0xb463a7ac, 0xe21eb11d, 0xbfd23695, 0xcbea4a2c, 0xac150263, 0xe2a0cc57, 0x2c208c5c, + 0x83866c64, 0x4480013b, 0xe35f3c63, 0xc8d531b1, 0xca1b1141, 0xa49f4551, 0xd43d2624, 0x583687ab, 0xf4234de2, + 0x52f0fae2, 0xd32992c8, 0x44d802af, 0xe627c7ed, 0x1b45845d, 0x9c8ccc0d, 0x78e845d3, 0x030ff43e, 0xb44f026e, + 0xe55b5a32, 0xda35fe3a, 0xf2f524c9, 0xfd37d0a6, 0xa2641c24, 0x8b1b1958, 0xdd75140d, 0x91c15b07, 0x7716d556, + 0x667017e6, 0x010b651e, 0x75b48549, 0xdba12372, 0xcc7f3803, 0x4964e37c, 0x5f6beeac, 0x8ded8ef3, 0xf5f214a9, + 0xb3178e89, 0x2816944b, 0x5543b752, 0x0d75fc92, 0xbd199635, 0x22fcc3ba, 0xd817b72a, 0xfe03a6dd, 0x784bdee8, + 0x7cc0ab6a, 0xc6b6bbfe, 0xd3df22a7, 0xcc9e5313, 0x719dc4b8, 0x85f11b46, 0xe8fcfb0c, 0x524975f6, 0xf28c26a1, + 0x7c8b7248, 0x65d0d3f1, 0xe4eb947c, 0x4d2c56ae, 0x25b01cdb, 0x94c2c5de, 0xc654b386, 0x53bd5802, 0xde86e41d, + 0x1cc08cf3, 0x5294207c, 0xc5aa5b4f, 0x354e38b1, 0xeaa7f64e, 0x116a0896, 0xf5b3e56e, 0x27f1f66c, 0x06da31de, + 0xb21cde98, 0x64e8ded9, 0x78b5a35a, 0x083b1dce, 0xdb80a844, 0x30e3e0df, 0x6ad57127, 0xa6716f1d, 0x85c35397, + 0x64052567, 0x2df14bff, 0x3e2ce289, 0x3c5bfca9, 0x0f14e557, 0x7f3a74e4, 0xf0b1e7a1, 0x0c6ee4d0, 0x49020688, + 0x63b41799, 0x0a97ea3d, 0x34906f4d, 0xd76be6a7, 0x2f4f0236, 0xb92d828d, 0x6675fd32, 0xba072f90, 0x7c913389, + 0xc29a8480, 0xdd17060c, 0x3bf5ceb0, 0x079e2c50, 0x41ce9e3e, 0x2086bd07, 0x069228a5, 0x2eb72bdf, 0xa28ac08b, + 0x1f6efc36, 0xf72ead5c, 0x28639ce6, 0x825d8b5c, 0x9266cac7, 0x4db60980, 0x97e155a7, 0x3034869f, 0x6b544a4f, + 0x6c2a94f1, 0xee3c0c21, 0x5bfcd5c2, 0xb9b7bef6, 0xf10d228d, 0xcc04d3f6, 0xdfa8c040, 0x0b12f37b, 0x23014e73, + 0xfecba2ce, 0x3a9b9145, 0x65d15654, 0xdd2e1b7b, 0x8aa19a0a, 0x4b993787, 0xade442df, 0xf1a9b731, 0x06362802, + 0x7732435c, 0x6eb61cf0, 0x9c96a1b8, 0x1123ccb9, 0x0ee69ddb, 0xf14e147d, 0x732aa9d6, 0xb10c93ad, 0x8f8c3b22, + 0xc056f357, 0xd458212f, 0x8ebe9a3a, 0x16f76871, 0x9c5d4f83, 0xd9c7aee9, 0x9d307cda, 0x6b7b42ba, 0x6e03c929, + 0xbac87d8d, 0x8bc1abc3, 0xb5442201, 0x50841372, 0xc824a494, 0x854d837c, 0x12678064, 0x080948d8, 0x74adcd86, + 0x70152efa, 0x5671b0d3, 0x99a4f0e8, 0x613f6920, 0xb985fd37, 0x704e00b0, 0xa08ff828, 0xc1db7958, 0x8b72179d, + 0x0ee5ec20, 0xb6f9a7aa, 0x594eb04a, 0xbd3ce872, 0x1075b028, 0x3f83cd26, 0x507c112c, 0x14434553, 0x6fd52e0a, + 0x4b75435f, 0x63039140, 0x20a7605d, 0x8f30cfa5, 0x39fc9ede, 0x43f1a1bd, 0xee628e3b, 0x997ffbfd, 0xbbea1f34, + 0x78a0b9f6, 0xd9e1332e, 0x429da48c, 0xa28cba7f, 0x39375d86, 0x9e9a8315, 0x79bc4866, 0xe24bb943, 0x184e29bc, + 0xadd12337, 0x5abd3419, 0x48346b52, 0xb9366fea, 0x7dfc41bb, 0xe7649223, 0x38cb04b5, 0x44c27006, 0x8aededfb, + 0x420bf026, 0xe96381c7, 0x9f089d11, 0xb95b9a48, 0x440434cf, 0x6577ebf2, 0x8cec08f2, 0x3705d669, 0x5f346a6f, + 0x22138620, 0x5e3f35df, 0x290cbda9, 0xcd5d0cc9, 0xa93697ae, 0x886d150e, 0x53d2a626, 0x389e9eb2, 0x3341938f, + 0x54a0b192, 0x1ba058ca, 0x654bba4f, 0x97fa580e, 0x221c3669, 0x7adaa0af, 0xc8b0bec4, 0x834e8546, 0x8907c6f6, + 0xa4346017, 0x99f05336, 0x11ca7fa5, 0x3a8e1722, 0x6e8a6fc7, 0x84a9c670, 0x72ef86f4, 0x969bab22, 0x58efd58e, + 0x041025af, 0x474fb779, 0x5fa6beb5, 0x8a1c82e4, 0x1e465e64, 0x6ba85bfd, 0x4d785f4d, 0x8a352f8d, 0x6affebd1, + 0x112270a1, 0x900ec9df, 0x4bcf7e2a, 0x62c5485e, 0x3c79cb95, 0x9506c9df, 0x25b20ff5, 0xa90ab5ca, 0x0de436f2, + 0xcef1fb5f, 0x795f5d07, 0x40d9df55, 0x437e30fd, 0x56151ca9, 0xcfb04c5f, 0x4b12f167, 0xf6274864, 0x92d1778f, + 0x00fac577, 0x84de7d90, 0x29e48dec, 0x66de4e51, 0x552507e8, 0xd7385a71, 0x8a7b88c0, 0x54e4fa2a, 0x245fa79f, + 0x36b7be0d, 0x382e274d, 0xfe708552, 0x30176c2c, 0x962dbb42, 0x6bf547b7, 0x76ec9a64, 0xa9c55ced, 0xd2ebce8a, + 0xdcfd3459, 0x4dc61db7, 0x2307854b, 0x24eb5fab, 0xd3d5ee47, 0xbfbb970a, 0xdd715ee7, 0x488f703b, 0xa0073b3a, + 0xa4ebc8fe, 0x0b3facfd, 0x2057865f, 0x37754e8c, 0x7dd4a391, 0x9a635b95, 0xb8613d01, 0x320da102, 0x35f7ea1d, + 0xe93ab7ba, 0xa8f506f3, 0xd9cc64ff, 0x9d2d1629, 0x39b71887, 0xcd1826d9, 0xef3e41fa, 0x8d9e289b, 0x81a01555, + 0xa42f1239, 0xe4a20174, 0x2abbc8f2, 0x01966ef0, 0xd3118ecb, 0xa2852ec5, 0xaf8b3149, 0x3c205022, 0xdcd1e254, + 0x6bd58cc4, 0x4eebb56d, 0x1833eee6, 0xa7a3da56, 0xedc2de47, 0x5a3262d6, 0xc603d90b, 0x025192ed, 0x8c1cfc9d, + 0x9fe6df2d, 0xfb9ee5ba, 0xe41c7b4e, 0x13fb6522, 0x012121d2, 0x3c1b5add, 0xc6e0bb88, 0x1fa12a8c, 0x5e29dbc6, + 0xb593b5ed, 0xcaf1e4a0, 0xd67e55ff, 0xf64e3105, 0xdf524d6a, 0xeaf123fc, 0x0cb68e6f, 0xf7d69b3a, 0xb634d64e, + 0xf97192c9, 0x7e9dcb21, 0x0da089f9, 0xe57bd463, 0xd50d02a5, 0x8a531b1c, 0x08cb6b05, 0x440d0e01, 0xf71d902e, + 0xb087be47, 0xfae78175, 0x34e53a75, 0x8f90ee2a, 0x1a08a5ac, 0xf3d9a8db, 0xb3f21c46, 0xc56f0999, 0xc4e724ad, + 0x27f6d68a, 0x7d0e8e5f, 0x32e6bf30, 0xcbaeb386, 0xf2dc7d40, 0x89c1929f, 0x8232cbb8, 0xb8160cc6, 0xd6f22cec, + 0x394dbaeb, 0xad273421, 0x986d3a7f, 0x93611bef, 0x4b372876, 0xfebb8d1f, 0x9e102e3a, 0x177e1c58, 0x1730a6ec, + 0x8dff4fb0, 0xd7c80be9, 0x6d4ccbe5, 0xe7945b66, 0x5826f5bf, 0xe36af450, 0xb65f3076, 0x62344f60, 0x80ceefa3, + 0x98e0e4be, 0xc3c44d53, 0x9633dc88, 0x35350c88, 0x09fd933a, 0xe5c19c5c, 0xfe79a633, 0xfb56d6a0, 0xb708b922, + 0xd385feeb, 0xd0c8d0da, 0xf492ee4d, 0x3bebab56, 0xa610fa11, 0x3b46aa73, 0xb9a0ad9d, 0xf25a694f, 0xa3c45b60, + 0x7d7c970b, 0x5fccf602, 0x4349e0bf, 0xed153023, 0x512f3bb5, 0xc21ad95a, 0x19c27a58, 0x49f1398a, 0x7989d837, + 0xc9a6226c, 0x8f00e284, 0x8b3bbaf6, 0xf67ba537, 0x29ac3425, 0x156b4495, 0x29096f9a, 0xe389307d, 0x62215f00, + 0xd48d32bf, 0x6c1f8a3d, 0x14b7e2f3, 0xcbeb71d1, 0xbded9997, 0xa409500b, 0xfe28d63f, 0xbc7649f7, 0x105bd562, + 0xe164c769, 0xce945902, 0xf8db2777, 0xa86ead87, 0x710bf19c, 0x5443219d, 0xc98977b4, 0xf8918811, 0xc124b706, + 0x996145a6, 0xbb573b74, 0x29ee1ee8, 0x1b8c1df4, 0xe6585944, 0xc0d91db5, 0xde35499c, 0x0af8af83, 0xb942f688, + 0x49c59249, 0x2232aa30, 0x6b84d667, 0xb7836911, 0xee42b2e2, 0x9e4a2f19, 0x125622b7, 0x147da1f9, 0x3a29f1f5, + 0xc46febc2, 0x10c37558, 0x39137998, 0xe42effa5, 0xa3c97a13, 0x4f48f6d4, 0x844e85e4, 0xfa8b2b0b, 0x63fed4eb, + 0x7a53f565, 0x8bd60496, 0x99a65956, 0x19878ccc, 0x0164ae49, 0x637e5d5e, 0x7f00156c, 0x91ccdc41, 0xe2662257, + 0xd3fec119, 0x77de22fa, 0x0d5e8b05, 0x7d1f7a13, 0xbda1e703, 0xe5c9d5dd, 0x69fc419f, 0x13bfedfc, 0xaae10cb6, + 0xf0744aec, 0x55a277f5, 0x78539c78, 0xecfad5d5, 0xda9e4a46, 0x6d17b9d7, 0x384e5dfc, 0x62a31052, 0x431b598d, + 0x865f90f7, 0xf1c012cb, 0x49fc2ad2, 0xe28c7397, 0x04e3d7d3, 0xc2c95dd6, 0x404b0f35, 0x1aa9d108, 0xee474d3c, + 0xb859030e, 0x58ecdbe6, 0x05cd7792, 0xa031f730, 0x172bec35, 0x0801dbeb, 0xfc42117a, 0x58a37c51, 0xf8f95d6b, + 0x5beff029, 0x2cc44095, 0x0a609a24, 0xe8a19334, 0x8906639b, 0x4a5137f5, 0x220f9cfd, 0x5e6ef29b, 0x1c963ad8, + 0xea682aaa, 0x4acd39d0, 0x5c48f2d5, 0xfc327a25, 0x2f841f49, 0xe126d9d3, 0x72659669, 0x4aa9090c, 0x162fa6ee, + 0x4158f523, 0x5e3ef6de, 0x412abdb6, 0xc732cd99, 0x6472dcc5, 0x9fd1937c, 0x983b76d9, 0xf3d15adb, 0x36c78dee, + 0x6c20e3d9, 0xe344d28f, 0xaf474be1, 0x9772052f, 0x2db0d013, 0x77558dd1, 0x92e9a135, 0xbcb94a98, 0x54e06205, + 0xee06c3db, 0x65e4940b, 0x9ae54773, 0xf9fb4f96, 0x54cfe1b9, 0x52daad88, 0x35272be4, 0xe38d35ca, 0xf9ee6af9, + 0xbd308f6e, 0xf565d2e4, 0xa9b181e2, 0x8f83fad6, 0xa887a08f, 0xc9fcadda, 0xfc7b5d21, 0xcbf6824b, 0x6e872c88, + 0x08b1cd5c, 0xb2cc2645, 0x8a8c4196, 0xbae3d250, 0x5beedea9, 0xebd0ff01, 0x6e24eea4, 0x3eff7429, 0x7e2a2653, + 0x8645bd22, 0xa6d5bda1, 0xc02f75ac, 0xed261dfc, 0x7f76ce9c, 0xcdac6906, 0x0a7eb46d, 0xdf808b77, 0xd770c4ba, + 0xcc5353dd, 0xfd2c08cc, 0x65e88519, 0x7d4898b1, 0xb490c194, 0x07755768, 0x94e3fc6c, 0x6fe2378b, 0x7bff77e9, + 0x6308fad0, 0xee74827e, 0x4b5d9087, 0xa34be938, 0xfd320a37, 0x914be728, 0x7b6854b0, 0x0a968fad, 0xc369e55f, + 0x4d8a248a, 0xdce28b63, 0xe00de9bb, 0x53f87fb0, 0x2f5e6f12, 0x5742f9cf, 0x7b5161ab, 0xf7518929, 0xc880bca6, + 0xdb6c7f23, 0x6cffae31, 0xfb882c74, 0x3fd960f1, 0x505edefc, 0x44588cb6, 0x0c430604, 0xc14c6d39, 0xbadce9c1, + 0xd426e32c, 0xeafc49c4, 0x04c2c9be, 0x1b91b9c3, 0x12507f2b, 0xcdff114d, 0x971bfe72, 0x5489c2ff, 0xe33cfc93, + 0x7f6e96d7, 0x7adc94ec, 0x62e9fe79, 0xcd617801, 0xe9381623, 0x89619707, 0x8ff24973, 0xb9682714, 0x3b608880, + 0x805f1cd5, 0x7bd6d007, 0x62f414a1, 0x74b05392, 0x8371f590, 0x86594819, 0x86933249, 0x186ee98b, 0xec1550ff, + 0x8349184b, 0xd2243d7e, 0xd0485af1, 0x67078d11, 0x6b95275d, 0xa5d737ec, 0xbd4e07c3, 0x0e5e0b26, 0x945e2cae, + 0xdd7daef1, 0x022c7a2f, 0xeb6b8cd6, 0x284bc377, 0x740f7745, 0xe921563b, 0xfd8bc566, 0x067bdcb8, 0x4fd91418, + 0xfad8141f, 0x89f23bb1, 0x67bdb7a6, 0x213ace90, 0xe9d89160, 0xc9f3fae7, 0x6a0e4865, 0x757fef91, 0x445c61eb, + 0x822ad358, 0x355071cd, 0x429247c1, 0x97458f01, 0x84f82e2e, 0x81c7bfa6, 0x5408f355, 0x0aaea394, 0x07b8916b, + 0x4a4ff2b4, 0x56d5fbec, 0xba4bd7cd, 0x2ff77edc, 0x8dbf8bdd, 0xf2c12fde, 0xfaf116c6, 0xa67f1f77, 0x3048c108, + 0x71f76e1b, 0xcf4b6a23, 0x485c8ddc, 0x2d673cb1, 0xb6932b50, 0xca03a8ad, 0xad3584f7, 0x732fbb57, 0x75204ffa, + 0xd885d06a, 0x54ce36cc, 0x891efe37, 0xc8094ce8, 0x9309638e, 0xa67999b3, 0x13f517a0, 0x07cfb9ad, 0x1e12c9e6, + 0x8a3d242c, 0x06f9e62b, 0xf7e89569, 0xdc26ab49, 0x980f87c0, 0x8a662643, 0xb6a80f25, 0x1d877eb8, 0x7f347898, + 0xd5c0dc91, 0xedb56c83, 0x31e18e3a, 0xb3b2cb8a, 0xaa025285, 0x173f5171, 0xdc6aa954, 0x35c8398e, 0xb6031c39, + 0x404bba76, 0xae4919d3, 0xbedaaf1f, 0xc37d9a54, 0x813f478e, 0xd3801619, 0xad29c1df, 0xd68e1143, 0xe8bc0c70, + 0x513ffee4, 0xc3ff5f19, 0x422fbee2, 0xc48dc0f9, 0x1e708d2f, 0xbb44b00b, 0xb052219b, 0x284c8244, 0xcd998424, + 0x44a42cad, 0xfa7faa81, 0x5c04a9e1, 0xe086efa4, 0xd43399ab, 0xfba43078, 0xd2b081df, 0x54ab7f85, 0x6965e29c, + 0x70894a65, 0x57336996, 0x1c1d1ce0, 0x80b3944f, 0x46c6202b, 0xd3e7c90b, 0x6a86d9c9, 0x30462c43, 0xd79a8db3, + 0x10af7239, 0x6979bc16, 0x659bb567, 0x8b0642fe, 0x784e473b, 0xbcf0567a, 0xe1f07337, 0x39323233, 0x0d8efbce, + 0xc763cd44, 0x37940951, 0xfa118a7f, 0xa03046db, 0x1bc13b51, 0xc24a5db5, 0xdfe9312e, 0x00220f16, 0xe5d91e1a, + 0x35438e02, 0x1d1b41f1, 0x2e483a33, 0x2e00698b, 0x4dd10585, 0xf51327a6, 0xd038ad85, 0x86070183, 0xb34f9099, + 0x27a4c553, 0x995e5f38, 0x42b36584, 0x463f6410, 0x168d3273, 0x6e0fe70a, 0xf38aee92, 0x3b1317bb, 0x1c3ee3bb, + 0x2a2bb18b, 0x32272006, 0x14a71470, 0x94244b21, 0xe9ef2ca0, 0xa20a6ecc, 0x13206cf4, 0x54606d9d, 0x02cbbbaa, + 0xaf8cfa18, 0x43e28da5, 0x76c8aaf5, 0xc4738569, 0x7bba0422, 0x17f47430, 0x1de1e536, 0xffe31fe7, 0xeea64e6d, + 0x5e0a7b75, 0xf9a6dfe8, 0x13010634, 0xab657b76, 0xf1253e34, 0xb81b0684, 0x57f76882, 0x774437b0, 0x70b736c6, + 0x8b7270d2, 0xa61f31fe, 0xad763188, 0xad5a5fda, 0x2df7b88b, 0x33d5bcb9, 0x9550f7a9, 0xaaa0229d, 0x28e88acb, + 0x9234e5e5, 0xd01965b8, 0x08027ba1, 0xd32afaa4, 0x53894061, 0x0429b755, 0xf3b82731, 0xfd767200, 0x998a6421, + 0x68d68956, 0xdd3c6cc1, 0x29a04b23, 0xf97adae1, 0xbe021251, 0x8c46b675, 0x058fa5f7, 0xe436ee1f, 0xb8276afb, + 0x74fbbbae, 0x413cd2a8, 0x6ab94340, 0xd83ed371, 0x92c96626, 0x6d9bd129, 0x930c7f6f, 0x6381390f, 0x3a8c725d, + 0x4727b343, 0xcee730bc, 0xe937929b, 0xf53c201c, 0xc163c8b7, 0x9b1d1b5f, 0xcb657bb9, 0xf900e1c3, 0x119fb088, + 0xb58a34c1, 0x4bbe3514, 0x7af97f64, 0x8f146c23, 0x9ed6cef1, 0xd2c8d79a, 0x30261411, 0x1c97bee9, 0xfaa14760, + 0x0ba71c31, 0x347a36e1, 0xb74910ff, 0x7393cd94, 0xd2afc544, 0x6c4db6f3, 0xba51e12d, 0xd3049ca2, 0x1aa92c68, + 0x266f5bfb, 0x9c2af0b4, 0x77b64f9e, 0x4fd7269b, 0x86615c7f, 0xdebdbd83, 0x8cda3c6a, 0x0a7d79aa, 0xd56c5f0a, + 0xd8c4e56e, 0x4d0a17bd, 0xe33938ea, 0x35722e8a, 0x16bb769c, 0x5fbe5d6d, 0x5aafdaaa, 0x159175ff, 0x2722a46e, + 0x4be492ee, 0xc3fcf92a, 0x13e28dff, 0x7298e2be, 0x8a5ace20, 0x9f160c99, 0x6f5015f1, 0x30b1182f, 0xfdd63e1d, + 0x48ae5d54, 0xe42af1e3, 0x8f8911dc, 0xecf5c962, 0xf06b83de, 0xf572d6b7, 0x3c13d9c4, 0x6d8a2300, 0x6bb35a10, + 0x38fb2fed, 0xc746f6f6, 0x22eb20c9, 0xda3109e8, 0xe6145eb1, 0xa3b00199, 0xc8591951, 0xe930d99f, 0x6618205e, + 0xf7534777, 0x1430e198, 0x3cf2a376, 0x75c9a111, 0x16ef3387, 0x4d279576, 0xef0ca591, 0x42dd6f81, 0xcfe32141, + 0x235394c2, 0xd3565c4d, 0x1807c7a4, 0x2c036ca3, 0xd560e9a9, 0xe1cdd7b1, 0x0c8d0e92, 0x85b8c61c, 0x41a65c9b, + 0xd6e2ed83, 0xbd2a1f05, 0xca5cc960, 0xa3324b02, 0x3197ff00, 0x8f38e69c, 0xf74c8773, 0xd677fc90, 0xdea10704, + 0x7ff0423e, 0x86854dd4, 0x49b90a88, 0xf98dfeaf, 0xee001370, 0xa0862e8c, 0xfc6f90c4, 0x93c94796, 0x66fc7336, + 0x2654161b, 0xb5c1af4d, 0xc15ca32e, 0x26ee653e, 0x16d7c542, 0xaaa6b414, 0x09a7883b, 0xd94a6986, 0x8737dcfd, + 0x97d2625a, 0x0cf1c7e0, 0x97fd0d74, 0xd925bd08, 0x67ee020b, 0x19342be5, 0xe8e828ab, 0x1d892597, 0x141d1c5c, + 0x71186b1f, 0xf897d223, 0x70ffe534, 0xf9b811e9, 0x18b2ddd7, 0x3d74efc2, 0x19df61ed, 0x4d488d0b, 0x4c09656a, + 0xc83711c2, 0x724184c1, 0xef3c6620, 0x94d97bf3, 0x0b17b7bb, 0x4d8086c6, 0x6bb11ec0, 0xd52852bd, 0xa296bc26, + 0x04dd02e9, 0x4bb86d8e, 0x153a3802, 0xd2fb89d9, 0x534a50d7, 0xa60df23f, 0x42ba4cbf, 0x4fa430d3, 0x25b3da41, + 0x004231ed, 0xc19b2616, 0x3eeb646b, 0x85b22227, 0xccdf1ab5, 0x6c2309ec, 0x8a0af86d, 0x3843bc2d, 0x6f83db6d, + 0x1565c15f, 0x3c117e2b, 0xcddaae16, 0x5cf3a105, 0xf1c766ea, 0x4f79f406, 0x2a76f1bd, 0x8aed4525, 0x9fa34ff8, + 0x3fd79236, 0xf7027e0e, 0x726288c1, 0xc00e7cc3, 0x9ccbc366, 0xd931bcea, 0x2d61be3a, 0xa3ce50b8, 0x1923d306, + 0x0d68297e, 0xfd74bd94, 0x5345914b, 0x4b3c5a51, 0x7588a424, 0x097fdc50, 0xcd6b046a, 0x53b39441, 0x03083f35, + 0x8fa6ec26, 0x7bc65a0d, 0x9c075034, 0xe0aa8749, 0x44bd00dd, 0x8f286836, 0xe69ab4ff, 0x0681a0a6, 0x2af40639, + 0x760a060d, 0x13c57db8, 0x24c26672, 0xbae060c3, 0xffb7d395, 0xd4b1f494, 0xbb1a905b, 0x65986f5b, 0x1653c1b8, + 0x5605daeb, 0xe0880f7e, 0xe218aba9, 0xd77477ed, 0x186cd7be, 0x002fa538, 0x2ccf01ea, 0x166f8a89, 0xd90ed1a3, + 0xe300ffe6, 0x3dc3ae58, 0x301ba64f, 0x345f7e34, 0x78edf844, 0x17a23ce7, 0xa4781b4d, 0xebbdb357, 0x0b960aa0, + 0xee63c1ab, 0xa4ca057f, 0x9699c00c, 0x441f6545, 0x9fa6baed, 0x635fed86, 0x9cbedc7a, 0x7dc148be, 0xa1f06d81, + 0x6118a206, 0xc6155f8c, 0x4d185e77, 0x63f8913b, 0x15621d0d, 0xef152c58, 0x9e0e93d0, 0x532cd706, 0xc6ce8ac9, + 0x5c4006ba, 0x2c6e1bcb, 0x6a907056, 0xea84dfcd, 0x6f93d855, 0x34dc4d1f, 0x4dc77b62, 0xa7d4a8b4, 0x7e00250b, + 0xfb02fa58, 0x0c2da933, 0x435fb3da, 0x82cf2875, 0xf663d1bf, 0xb44a6e45, 0x46f6918b, 0x6e731117, 0x84169048, + 0x72e621ac, 0x5419191e, 0x2ac745f8, 0x7b9de817, 0x2361581f, 0x0d468227, 0x900d77ed, 0x3e4ed9ae, 0x516f5fa5, + 0x51cfe4a9, 0x443d7e45, 0x6306fdd5, 0xdab4ea97, 0x30cd08a0, 0x9d821f6c, 0x82ba0b51, 0x96fe46c8, 0x83d49a6e, + 0xf2d08541, 0x8b6aad93, 0x474f6695, 0xedc5bb13, 0xa575361c, 0xb4557417, 0x6ecb61a3, 0x84f7e60c, 0x4a0f5163, + 0x8cdcb3d1, 0xad9124c0, 0x890c3d9e, 0xbf169b3c, 0x720e7602, 0xf1fa54e1, 0x6b818d42, 0x44d8e955, 0x86664bc6, + 0x90377c22, 0x22382fbe, 0xccf418c5, 0xf838c0dc, 0x946b1d66, 0xc11be40a, 0x7a151938, 0xdc4336c2, 0x28c43eb2, + 0xc1f12298, 0x98cd9669, 0x166880cb, 0x84cffc47, 0x37c84d89, 0x1889a4cd, 0xdf2ce016, 0xded06116, 0xfae867c5, + 0x8d23d06b, 0x827dacf8, 0xfd11d25f, 0x68485ddb, 0xed506883, 0x43c5e555, 0x0330a16f, 0x3f7576af, 0x5f70c716, + 0xf298b8ce, 0x9e1df62a, 0x46fa9d88, 0xb06e68d0, 0xc3803412, 0xe8ba5d5d, 0x615d8c71, 0x1b0d6c3c, 0xb638706b, + 0x187d6983, 0x0e33f64f, 0xd9dd7778, 0x12410a8a, 0xcef7eda5, 0xfe74e21e, 0x60b70fc5, 0x8ed94fa2, 0x6cfde259, + 0x8058b411, 0x1ca93807, 0x19625c5a, 0x34215cec, 0x165baddc, 0x0ab44f83, 0xa6363e74, 0x3f7a766a, 0xdd702a61, + 0x3d0ca687, 0xd0909c3e, 0xdc7f7712, 0x3d9001ea, 0xc5d19495, 0x8017b1f6, 0x65da0eed, 0x0d030d48, 0x998c10e6, + 0x06f1c97d, 0x35204b05, 0x1c0da754, 0x777b48fe, 0x01521640, 0x203bfb59, 0x25e83cfa, 0xa3d40b91, 0xf396bd60, + 0x093880c7, 0xd5a77950, 0xe06ddcac, 0x87936f25, 0x12c7d991, 0x16103a0f, 0x4a1ee98c, 0xf70e1c84, 0x2f3f894e, + 0x176c0300, 0x34c08cc6, 0x89eff014, 0xb7d5666e, 0xf7636a27, 0x128ece3c, 0x71e7ddb6, 0x1070d4aa, 0x2dab9a05, + 0x3cdc279b, 0xe88781cc, 0x2771abc8, 0xf01d6e74, 0xe8cc296b, 0xeaafe927, 0xa3b3e542, 0x872acfc7, 0x4033a228, + 0xa922a98c, 0x82b18f3b, 0x6d5efbb5, 0x31d13a83, 0x6c4a1b1e, 0x7d5df44f, 0x539dfd5d, 0xda1e186b, 0x60f6948d, + 0xb4c2bb13, 0xa903a2c4, 0x76a5595b, 0xb85fc368, 0x87e3c57c, 0xeec8ee07, 0x39f42e4b, 0xdc13d659, 0x03ac1daa, + 0x123bab9d, 0x7789dec0, 0x5dba0ba3, 0xcee72d9f, 0xea4aa38f, 0x315633a7, 0xff276fb0, 0x0468ef67, 0x7fb82124, + 0xeb586ed5, 0xcdadda70, 0xb37e12d8, 0xe4411b87, 0xc740e4f5, 0x41ca5e11, 0x8e54997b, 0x023d8b2c, 0xda4cfb4e, + 0xee115485, 0xf9a61a29, 0x98aefaa4, 0x2523432a, 0xcfa165ae, 0xc2b7231b, 0x40766948, 0x5e71a770, 0x6f06068e, + 0x85cf33c3, 0xf44c2e49, 0xef9f9713, 0x7f35efb9, 0xff1d0bde, 0xa15bf493, 0x37c904bd, 0xfc677f2d, 0xa67afffc, + 0x06fab6d5, 0xf04f5fd5, 0x83db3794, 0x249a0146, 0x7e37df24, 0x2c3368ff, 0x1f91c223, 0x1702b3a2, 0x36529fb0, + 0x5a478f2c, 0xabd45842, 0x8529c2db, 0x4d98ab0e, 0x9eef3eb9, 0xbf25ad97, 0xb14e5362, 0xcba7bc8d, 0x2da5e097, + 0x2ce2525b, 0xeb18f1cd, 0xa304c984, 0x727cb146, 0x6005c133, 0xe81ac960, 0x7f688f84, 0x58046719, 0x14383216, + 0x078141b6, 0xd3e0e175, 0xf3bd17c0, 0x4fe2990e, 0xa3309ad1, 0xc79ee620, 0x393741c2, 0xd21fa67f, 0x8dce86ae, + 0x01f4a0a0, 0x495c3e7a, 0xc039a040, 0x6a3db81a, 0xf5b6b721, 0x1cc72ca6, 0x7830ddee, 0xc5ca37a9, 0x6bef9836, + 0x7caff8d1, 0x0bf526d4, 0x3457d5e2, 0x57bb20bc, 0x1e7baaaa, 0xb9e8c7e7, 0x91c866a3, 0xb741b298, 0x71b94951, + 0x338b586a, 0x55e6404a, 0x55127f7b, 0x8fdaaba0, 0xbf438342, 0x1efb7e78, 0x32a3bacd, 0xe3e237b6, 0xaf5c8258, + 0x316d30de, 0x80d48995, 0xe75b15f4, 0x7f3da80a, 0x0399eb2b, 0xea519cc7, 0xd9d73314, 0x9db63d9b, 0x0dca10ee, + 0xddefdb20, 0x5d3b1135, 0xdb97872c, 0xa4471784, 0x73f4b56f, 0xa5621ac7, 0xd77df297, 0x75c33f00, 0xd5e5c13a, + 0x4ea9d1c7, 0x9b3b41de, 0xe91e5a42, 0xd01c1968, 0x0598a57c, 0x4a2fe329, 0x896e370e, 0x7a216f47, 0x9b3e0b7c, + 0xc1caf2bd, 0x76010f7c, 0x42df9135, 0x20bd0262, 0xb50095be, 0x2dd531f0, 0x8e46329f, 0xe25c5359, 0x238f768a, + 0xf38ee9d3, 0x9957cc3d, 0xf379b499, 0x430b997d, 0x30fe8c76, 0x41fb6e86, 0x7e7544d2, 0x8ce2205d, 0x154b4834, + 0x3e32d867, 0xabbe29a1, 0xb3b3e0ff, 0x45eb03dc, 0xd2cacac4, 0xf0a02058, 0x2b018327, 0x7ef5a280, 0x727d1709, + 0x2207c363, 0x53de88a4, 0x7130c97c, 0x59d41c84, 0xbb567750, 0x543ff569, 0x565805ee, 0xe82eabef, 0xfbfe303f, + 0x7b581de8, 0x692a4134, 0xb17dc0df, 0xb994b37c, 0x7a0f74ae, 0x53e235e7, 0xd33478cb, 0xcb58c35f, 0xe8340cba, + 0x6292bb5a, 0xf82c56f9, 0xabd8bd48, 0x1580f5b8, 0xef05ec06, 0xc5fd8ad0, 0x50a7ca7a, 0x6c5e4364, 0x6b6c9f55, + 0x9e1141c9, 0x84cd06e7, 0xf1b41945, 0xbc4aaf4d, 0x8978bbe3, 0x455ae024, 0x482e3c8d, 0x6e25bc36, 0x13268d3c, + 0x12792a8b, 0xd711bfee, 0xf083b7d5, 0x007e210a, 0x14dd3c7f, 0xba38ad4f, 0x86e40d49, 0x2915f767, 0xf31b7c4d, + 0x928e5a3f, 0x931dc2dd, 0xfe1833ec, 0x2bd73960, 0xa6a22a17, 0x32c46f52, 0xee90b0b8, 0x197ff3e3, 0x22a7b3e7, + 0xb8d0bdfb, 0xf317c643, 0x6b9ceb9e, 0xfe8f3257, 0xcedbd713, 0xf1273509, 0x264c54a0, 0xfa8cd8b4, 0xcb42e484, + 0x97cbefa6, 0x3d60b97e, 0xe31f4c27, 0xbb85706d, 0x668ee859, 0x7fe23e33, 0x466d0da5, 0x45516a29, 0x8c64d7cc, + 0x6cd77457, 0x55857dcd, 0x1aebec4d, 0xc4b0eb57, 0x373a0a98, 0x6f6de661, 0x07fc4756, 0xf5c18ce8, 0x70dc11a8, + 0xd358449b, 0x8510f11b, 0x8f57cb8e, 0xe00af3db, 0xcd98114f, 0x8b5ecb4a, 0xc20b3cf2, 0xc421cd64, 0x7a97cd6b, + 0x40117f2a, 0xdc451484, 0x74b98543, 0xd9c1469a, 0x6e7fad24, 0x5dbd430f, 0x608dc833, 0xa318800a, 0xed9acbb5, + 0x0dabfa10, 0x67dea7f3, 0x378399fd, 0x7ae44e01, 0xdd541725, 0x551dcf9d, 0x4d50e1b0, 0x312fc985, 0xf79875a6, + 0x934dda2a, 0x3e3e8bdc, 0x0856afd7, 0xce97b767, 0x1193a27f, 0x328c6e33, 0x22fa34cf, 0xd8214885, 0x01e8b61e, + 0x88a959f1, 0xba6d5153, 0x0656f948, 0x540c3024, 0x5d94554c, 0xac51c164, 0x08699e5b, 0x9ba6fb37, 0x3fd5ad2b, + 0x4934f1d4, 0x64a741c6, 0xabc4edf0, 0xe339106b, 0x47bf88e4, 0xa88db9dd, 0x310976b2, 0xaf4c2743, 0x524a162e, + 0xfff04654, 0xefd85e4b, 0x6654acfa, 0xc6bf8daf, 0x22e9cc84, 0x792800bc, 0x2e81aa4c, 0x0257bee8, 0x241dcfde, + 0x855e88e8, 0x744a7c58, 0xdcc9ba37, 0x21488682, 0x4f753688, 0x0908c955, 0x6f2c22c4, 0xb5f0e979, 0x57dbabbc, + 0xd080fc83, 0x1fed5a7a, 0x82098933, 0x6a40393d, 0x061a7941, 0xcd8cce5d, 0x42801c05, 0xcbcbb9f0, 0x0711900d, + 0x8b3c21be, 0x5290542a, 0xb168ffe3, 0x750bb876, 0x46517f4f, 0x9d42928e, 0x19de27ef, 0x81da886e, 0x200b6006, + 0xa6398490, 0x054f5ae1, 0x25e7586b, 0xf5f1a42b, 0x3337a041, 0xa46f995b, 0xc67feb72, 0xf03dc698, 0x3e3c6737, + 0x5f3be343, 0x4be1a3bc, 0x05a68613, 0xbc7b42ab, 0xd0b95acb, 0x2e070a54, 0x5318172e, 0xd70ed28e, 0xfaf357b5, + 0xd0369ab9, 0x2b021593, 0x90c6a28f, 0xa8e92cb0, 0xb94200c8, 0x609306ce, 0x3cd44e98, 0x92fb9f32, 0x279e60cc, + 0x4fef121d, 0x41a605aa, 0x8b9efb98, 0x1ebb1b16, 0x86ff40b9, 0x928379e7, 0x9edcde66, 0x2b768d7e, 0x5d59b594, + 0xcd89554e, 0x5bcbe8d7, 0xf87c767a, 0x877feaf1, 0xd0a24d3f, 0x1c064c18, 0x2506dde8, 0x46cf6ef6, 0xaec702bb, + 0x942e5c3f, 0x204742fb, 0x6568d1ec, 0xc3bba507, 0x023562b8, 0x9f62935d, 0xd6e0a676, 0x15cfb291, 0xbb0ce283, + 0x7ad8cef9, 0xc74c8fe8, 0xf583c120, 0x3072e613, 0x11c2720b, 0x4a18c426, 0x74577b1c, 0xdc639e6f, 0x1b1579ef, + 0x3e8110f5, 0xea7b8c7e, 0xc60a1be5, 0x8d0834c4, 0x9086cef0, 0xd64484ef, 0x929c2ef4, 0x2ff762cc, 0xb7629f11, + 0xd7c03998, 0xec723bc6, 0xe62f1962, 0x85fb402f, 0x5cc9948c, 0x59cfac55, 0x68528eee, 0x875f70b8, 0x7b28094d, + 0xd0f8fca1, 0x72771a92, 0xb51c24e2, 0x1257d17e, 0xa646ae5f, 0x75171beb, 0x212297bd, 0xbfaa9ecd, 0x518c1d65, + 0xe09f7b6a, 0x62ca5758, 0x4442d549, 0x13f67d83, 0x695a59ff, 0xce62eaa2, 0x1de98a77, 0x38149cd7, 0x21d16739, + 0xe7c4a6ff, 0x64a08652, 0x496af47a, 0xf8fab8e1, 0x3abfa465, 0xc9902c26, 0x1ece20d4, 0x6d8d3b31, 0x779584cf, + 0x5d27b862, 0x47f329a6, 0x70aaff3b, 0xfda9db92, 0xaf30ae9b, 0xe4da8c2e, 0x01958b93, 0x4c612363, 0xa04ff51c, + 0x79ee4079, 0x612d503f, 0x03eadf9d, 0x1a0b270e, 0xfecde124, 0x7310320c, 0x4b5ba089, 0xd9b685fa, 0xe1c550b2, + 0x04e9af67, 0xeca9c9cd, 0x8da38f2a, 0x4f9614ca, 0x4b5dc145, 0xd11eeb3d, 0xe6fb9347, 0x179c060d, 0x2d3b49bb, + 0x63ada9c7, 0xa16aef66, 0x0cdd20b9, 0x529d9003, 0x5eb0a267, 0x9347b3fa, 0xf7ded177, 0x3f7d675d, 0x7d75fdf3, + 0x8a030e34, 0x67edd63b, 0x3d6e1f72, 0xec49614d, 0x0d8c5075, 0x74f4a8d3, 0xdf3aac4f, 0x524cb87a, 0xc14fefe7, + 0xc463e881, 0x528b3e91, 0x98e68da4, 0xfd6f71e6, 0x1b12b7b9, 0x662d3844, 0xeac7e74e, 0xe49165f1, 0xf27c697c, + 0x0db04844, 0x619da7fb, 0x589f0285, 0x05cfce0f, 0x8df4249c, 0x2a9d03c3, 0xd1b63979, 0xb5e611ad, 0x4b624e97, + 0x43b79c8b, 0xb8672abc, 0x6e409ba6, 0x4911d9c0, 0x6e62f54c, 0x553028f6, 0x71ae1eab, 0x401790c1, 0xd9ca96e0, + 0xc5d86c85, 0xa4b7e34d, 0x88a478b7, 0x27af0b2f, 0x356e0428, 0x5f6f841d, 0x255a3c69, 0xb66d88d4, 0x16858e89, + 0x978dbf34, 0x4bd81042, 0x57efbf69, 0x7a32736d, 0xa1f04aad, 0x5f15adec, 0x5ddbe1e5, 0x1d9e2f56, 0x384b8000, + 0xcf9c3d16, 0x28caa2af, 0xecac7bea, 0xcc0af3b0, 0xbecbd483, 0x58960d9d, 0x2a152a8b, 0x1f0675d6, 0xc1d12149, + 0x1de1e78a, 0xd827b4c9, 0x508623ee, 0xfca04a41, 0x799d49a0, 0x3e52aafd, 0x265f09f4, 0x286df636, 0x2ef5d77d, + 0x4ddd7640, 0x3b0fc9b4, 0x5eb999b8, 0xfd9293cf, 0xb0928ab4, 0x5eb42120, 0x8d58975d, 0x226daf1d, 0x358f5170, + 0x5a852d16, 0xcc60c64e, 0x03a8ad56, 0x46998caa, 0x205073e8, 0xbc869376, 0x3a230776, 0xcaea34aa, 0xce1f39e6, + 0xacd4b7e2, 0x1ac5e478, 0x16019f92, 0xcaa2f07c, 0x77e060d0, 0x9150a98f, 0xb50cc764, 0x0402c862, 0xbcf384be, + 0x9d197d1c, 0xa58be6b1, 0xeea88fa2, 0x99c7be9a, 0x0107ec42, 0x9146f4a0, 0xc7931e6c, 0x9471c0be, 0x36f88cc2, + 0x0bfd8b55, 0xc32284f8, 0xea79f45c, 0x142b5923, 0x9777de8a, 0x07ce8b8c, 0xf0f7ce68, 0xb00c7ad5, 0xff335954, + 0xae14383a, 0x9bef2367, 0x2428eae3, 0xd6f13768, 0x7900f4f3, 0x6f88d703, 0xe64d0f51, 0xd217ac84, 0xfa769410, + 0x8f4458ce, 0x99bc3e07, 0x61f07cd8, 0xd504bd03, 0xf64b9994, 0xfdda761e, 0xe2fddf67, 0xcdc9a48f, 0x9aea5585, + 0x52a68ccd, 0x4ae2d1b2, 0x903bb279, 0x2f1dee1c, 0xb19783e2, 0xa5b3e77c, 0x4781364d, 0x6580b5f9, 0xb9fdd5f1, + 0x5ed49203, 0xfb220d01, 0x401f1d5f, 0xab2eaa52, 0x36f7de6e, 0xabcfb2b3, 0xe6504a47, 0x12a0150b, 0xd2f73c24, + 0xd1556f74, 0xfbcb3bde, 0x5a1d48f8, 0x43744088, 0x0ad73669, 0xa6af64c6, 0x861dd87c, 0x572909fc, 0x88eac9da, + 0x81b74408, 0x3d054a61, 0xbe9944a6, 0x27fb1248, 0x110379ff, 0x6fb12280, 0x4842dff4, 0xd161f2e0, 0xba571eef, + 0x5b510cab, 0x787b17d9, 0xce0616b1, 0x9549f229, 0x183089df, 0x3a52c6e6, 0xc2bf407c, 0x65ed89af, 0x4392e40d, + 0x9167b0fc, 0x8059b961, 0x7ea43fab, 0x2640368c, 0x8d69ebf8, 0x10ccd93c, 0xe431a555, 0xb25a7d1e, 0x9c36af8e, + 0x3539bcb2, 0x1a409ca9, 0xcffb64e6, 0x1b402f61, 0xd976b87e, 0xecdd170b, 0xf164c2eb, 0xf93bab67, 0xa3fa7d28, + 0x6ca40902, 0xa0f71e84, 0x189efc97, 0x8b7f7db7, 0x1be2e9b9, 0xebda48b5, 0xb9ce2ead, 0xdc756b94, 0xd32d19c6, + 0xe5feffb0, 0x7231207d, 0x2de68ebd, 0x9a90e569, 0xeecb46fb, 0x530eef5d, 0x72fa0b78, 0x0c5cca45, 0x433040f4, + 0xc57f27fe, 0x48cee220, 0x171b7faf, 0xeb5884c9, 0x0fed315c, 0xa432b698, 0x81055aeb, 0x1d4eaa5a, 0xdd043b4a, + 0xb7e1cb75, 0xb48a86b1, 0x6f6519de, 0x3749e3f3, 0x1e4030e1, 0x346bed70, 0xcde03865, 0xfffdccac, 0x5a745407, + 0xe21ec10e, 0x2f4a3529, 0xf6d3fe40, 0x55145fa2, 0xfc3a2c92, 0x78d8c49c, 0x235cc460, 0x4fc22a80, 0xa2ed4089, + 0x25a0c74d, 0x59271538, 0x0ed7ade1, 0xb8d438cd, 0x7945835d, 0xd2641c20, 0xfb9455d3, 0x68af6c53, 0xd4c0e45f, + 0xc7c433fb, 0xb6c360f7, 0xc5ff2a45, 0x2b8ff8b6, 0x669efd1e, 0x32dfa2eb, 0x6a967870, 0x60aae9e9, 0x6a69c7ef, + 0x171d532c, 0xab192c2e, 0xad8ea531, 0xddea1aac, 0x7ceb80c5, 0x24b64349, 0x58f59e31, 0x8d9748ff, 0xf999aad7, + 0x106b8b87, 0xe79c9adf, 0x0a3429c6, 0xb28877a0, 0x9f387cb7, 0x57ad9e81, 0x47b76172, 0xa29d8cde, 0x72f26705, + 0xbfdd4dd5, 0x098c0c3d, 0x0a278667, 0xaf153668, 0xcfb5edad, 0x3045e37f, 0x47822fd2, 0x635ef5fb, 0x50c53eed, + 0xf18d9f43, 0x88876eb8, 0x2044fc94, 0x27dc3f65, 0x0346e38c, 0x194af21e, 0x0c5d763d, 0x0ec55217, 0xb720890d, + 0xfa38ac4e, 0xf6ffd7df, 0x4ab13d97, 0x186565b3, 0x2e0f4cc7, 0x5930774f, 0x345cb1c6, 0xe6081f7e, 0x694fd48f, + 0xae76bd33, 0xb187c287, 0x98bf2071, 0x2034b42a, 0x4a529aee, 0x02e0731b, 0xe7840aec, 0xbf89aac8, 0x94f9bc70, + 0x046ae8ab, 0x1682e981, 0xff2776c4, 0xfefcb670, 0x56a36f21, 0xb44306f9, 0x73831779, 0x429b2377, 0xd8e7fc71, + 0x808f881b, 0x35429f95, 0xf70cff9e, 0xc0d64e1e, 0x9661da63, 0xac7abe19, 0xddf5b6cc, 0xd686bb9a, 0x1bc2d82b, + 0x57027ae6, 0xbc361047, 0x50f75eb2, 0x8d9767c0, 0x5d6cb0ce, 0x099a8780, 0x4137867c, 0x6023fc6f, 0xd090f31f, + 0xdb5f9efd, 0x13abe1a1, 0xa05867ec, 0x545467ec, 0x0883496a, 0xff7576bb, 0x0d649d89, 0xc262bd69, 0xd1c06205, + 0x2da18b69, 0x2b865ff0, 0xb1779ed4, 0x307712b0, 0x7a949b32, 0xe739f72d, 0xe0069bd6, 0xbfbd17b5, 0x48e1a937, + 0x8c18764f, 0x3f80ff28, 0xbdfcd8e6, 0x59c98772, 0x9c366af4, 0x3ae0db7d, 0x930d5d4d, 0x1e840538, 0xe8ff31c3, + 0x56147619, 0x9dff369d, 0x1ead3e28, 0x20c346d6, 0xb673f0fa, 0xb4310e0a, 0x1a7ef740, 0x79d3bbc0, 0x35bf6244, + 0xadea72a8, 0x64d5cb11, 0xff9881d6, 0xcf9c61fa, 0x06a15b89, 0xb0088279, 0x17b3ea4e, 0x619f8304, 0x9eb270b5, + 0xed56dc6f, 0x41800aa7, 0x54fa646a, 0xc906979c, 0xd19831fa, 0xd60a2a39, 0x1cd2ffef, 0x04994370, 0xfff9e235, + 0xf46b53f8, 0x1e78d065, 0x0ff3a7b8, 0xddc394c5, 0xf1c6a5e0, 0xac98f91b, 0x6d1f1258, 0x756ddec2, 0xb77f51e4, + 0x4e787c5e, 0x381f18de, 0x2bfc34fc, 0xb3ebaebb, 0x425fce1e, 0xcb011617, 0xa04060f5, 0xf7a1bb1b, 0x5782ff96, + 0x35b89bc8, 0x5442d4a1, 0x4ba6b9d9, 0x3279705a, 0x9e657e74, 0x7d3f232e, 0x01a19e54, 0x5c80f44f, 0x296d02de, + 0x13f5adc0, 0xd28aaa53, 0xcc77221c, 0x73ba450c, 0xa2ce1e32, 0xb6877274, 0x2ed63aae, 0x92dd54bb, 0x2ca9d631, + 0xcb92a4c6, 0xd155f0fb, 0x1b718fe9, 0x9e37a6c5, 0xe5cbfa76, 0xfc031174, 0x1a7b4b78, 0xd3ee3df8, 0x07ab6cc0, + 0xe2090535, 0x39ec20a3, 0xf7902a92, 0x10e25e44, 0x6e430e71, 0x6cc86168, 0xf77c895c, 0x14ac7225, 0x40143968, + 0x3efece1e, 0x88e7cef6, 0x14be04cd, 0x6c0c332a, 0x08fbe7ad, 0xeaf4e7e3, 0x81edefc8, 0xccbe51b9, 0xfa9dae05, + 0x1a5777c0, 0xc594937b, 0x39a575d6, 0x6d5f3c0b, 0xc331cfc6, 0x40da7921, 0x4b8e49e5, 0x72873528, 0xccbf92fd, + 0xce3bd745, 0xc638093f, 0x3225e232, 0x85f442f3, 0x40792517, 0x6b6dc7c5, 0x364c91bd, 0x178a31a9, 0x4792c053, + 0x013fce0c, 0x198a4ac2, 0x299c597f, 0x59a51228, 0x4e59d080, 0xaa957078, 0xcd38dcd0, 0x8900660e, 0x22036abf, + 0xe1460b02, 0x58696f0c, 0xda66acf0, 0x06e341ae, 0x407dcbcd, 0x507110b2, 0x33cfdcc1, 0xc87b2303, 0x5c7da204, + 0x5bc4b176, 0x31d7c10f, 0x8a41d3fe, 0x0eec6415, 0x7ed5c474, 0x4edaf883, 0xa1de7d94, 0x05177cd5, 0x58899909, + 0xe0140185, 0x1bf75062, 0xab23302d, 0x31b69bcf, 0xee1c73d1, 0x7d70b0d0, 0x0f6fe336, 0xade755b3, 0x182391cc, + 0x167504f8, 0x60c64afe, 0xbf11acbc, 0x414f3893, 0x16a64913, 0x457a0401, 0x5bf7b068, 0x42ab702c, 0x80ebdbc9, + 0x2b2b2e10, 0xa80651e4, 0xacb46bbc, 0x1e89db84, 0xf0d11894, 0x41ac886f, 0xff74e0af, 0xfe7c115a, 0xd1eadea0, + 0x76b50316, 0xe811b9b0, 0xe6d42903, 0x078c5882, 0x8d4223f3, 0x6c2e5577, 0xeefd2b17, 0xf93777af, 0xf0f5def7, + 0xab80aa20, 0x4e22a4ad, 0xc548a92e, 0x25ac22bb, 0x9d4bfcf5, 0xd864e7d3, 0xa807c2cb, 0x5b2fb557, 0xc08dda2a, + 0xd6d864d9, 0x14613569, 0x991a2acb, 0x61554d44, 0x7b6e7b67, 0xa688fa1f, 0x547dc180, 0xe35b5e97, 0x6d207897, + 0x053e206b, 0xae40a62a, 0x22d2bb9e, 0x3f4ceb17, 0xe64dd02b, 0xc4414688, 0x4f12fd07, 0x92a048d3, 0xb60f8d82, + 0xb118f63c, 0xd5a14ca6, 0x0aa009c4, 0x6ef9a2fe, 0xe20b0f52, 0x0ed103e3, 0xd52c7744, 0x08b9878a, 0x704337ed, + 0xdce41422, 0x62fef670, 0x33ce873e, 0x7e006179, 0x8fee1ac6, 0x3b0c006e, 0x0879e102, 0x24d59944, 0xb5e7e385, + 0x6ce722f5, 0xdb3284a4, 0xf15b6bf4, 0x293704b7, 0xc7b33a0b, 0x12c97879, 0x80a406a8, 0x77d7da6c, 0x1745acc9, + 0xafa94b3a, 0x7bd3dc35, 0x84339853, 0x0a256bce, 0xe22c682c, 0x0eb49a97, 0x9376dd39, 0xbfbc26de, 0x1cdc77a6, + 0x690c6c96, 0x2d97c9ba, 0x17581c0c, 0x1c2c4968, 0x88e8b968, 0xc7f7fd49, 0x6e81ab5f, 0x52d44f00, 0xbee589a8, + 0xa99817c0, 0x93c9f278, 0xab8f60ad, 0x91b2025d, 0x45db5761, 0x1754de67, 0x8f496182, 0xab666dae, 0x6fc9eca5, + 0x1b564330, 0x27854cc7, 0x486c0858, 0xd65aedc3, 0xdbffc004, 0x7a9b7ab9, 0xd7a9d0ed, 0xe09c8baf, 0x77f8ce26, + 0xdb8d72a2, 0xbce8dce5, 0x3dfad6e6, 0xac1de9c4, 0x8f384f55, 0x2461ec11, 0x08adfc2b, 0x3a685f00, 0xf3b55b40, + 0x99194cd1, 0xe03b3b07, 0xfd8bc47f, 0x6cc0037c, 0x6545187e, 0x2c882db8, 0x67055ec8, 0xace15d6d, 0xbdb5bae3, + 0xa76550f0, 0x5441bfe5, 0xadd5df2d, 0xfa32dcc5, 0xf25d6dda, 0x10aa888d, 0x8e59daea, 0x21d57fba, 0x64dd5333, + 0x309cc18b, 0xac08806d, 0xe2080fa5, 0x670d1500, 0xfc2dbf00, 0x4f56f13b, 0x74ea15e0, 0x51dcbe23, 0xf369908e, + 0x4fd2f456, 0xb1018886, 0x73cb9ce3, 0xb79936ae, 0x814af583, 0x8436e89a, 0xf7599163, 0xab24e5a3, 0x12e0a524, + 0x0300a10a, 0x1659ee7a, 0xb4f25023, 0xc066c21b, 0x9278f1d6, 0x95c29ff1, 0x508d1251, 0x2c749bcf, 0xea26b308, + 0xe2b67a5d, 0x6e73a436, 0xd71190f8, 0xa23247db, 0x24e2114c, 0x20fc1fff, 0x9fb9a01d, 0x15a03fe3, 0xfe0db419, + 0x290740f2, 0x9ae9be0b, 0x48d47f3b, 0x6e3910f8, 0xa26d7548, 0xb1ff1bd2, 0x16f5d6a9, 0x70f164cb, 0xba7aed1d, + 0xc01acb85, 0xff57b499, 0xd0b5953e, 0x080dd003, 0xec40963b, 0x4554c1f6, 0xd9393cfb, 0x358216a3, 0x0cfb341d, + 0x38b21775, 0xafc61cad, 0x0251315a, 0x3cf4d8bf, 0x5837b341, 0xbcba39b0, 0xb3772be0, 0x81c0ebb9, 0xc6636eb3, + 0xf946c047, 0xb95f1455, 0x91e32164, 0xde93d203, 0xe16b5188, 0xb967f11e, 0x48c54d9f, 0x98d311b0, 0x98179ed9, + 0xc503c060, 0xe3b32cdd, 0xefbed6a2, 0x8a224424, 0x6fa64917, 0x36346f72, 0x60d612a0, 0x8189855f, 0xc82a2e5c, + 0x4e141d8f, 0xa9d4c794, 0xbe45ff4a, 0x2e60712d, 0x489c4871, 0x8c0d28c2, 0x34c73b7f, 0x3422cb43, 0xcae0645a, + 0x4c95b658, 0x46814ef3, 0xe1ce8e4e, 0x0e1c2b0d, 0x77f232d4, 0xcd66efd2, 0xa88299e7, 0x9f8dbbca, 0x6e33648c, + 0xccdff76d, 0xdb9eefc2, 0xa4f8a432, 0x5879ba50, 0x368c03e0, 0x155436f7, 0xd73a1085, 0x069e9fa8, 0xeb401ccb, + 0x84a22d19, 0x68ca6699, 0xb200deea, 0x71d33d13, 0xbbb5aba5, 0xb645f14f, 0x12f8bdfe, 0xb199d33a, 0x057829af, + 0x428619ea, 0x0aa1905b, 0xe717701e, 0x7d501758, 0xe18e6cb7, 0x8e05a414, 0x7d9eba3d, 0xdc37b073, 0xa18f4055, + 0xe91bb91d, 0xfa5e7b90, 0xe2bf1dff, 0x1c158a53, 0xf1aa7d03, 0xe8ca62a2, 0xd5f84ecd, 0x68eb5489, 0xa063cbee, + 0xb98075ad, 0xe7c0bbb4, 0x1ee26553, 0x339420d7, 0x80db4ae8, 0xd12efd67, 0x918e6941, 0x796fec13, 0xcce404f4, + 0x7f37ec87, 0xcd742a63, 0x336de28c, 0x57bb6bf1, 0x733d4597, 0x6eea90f8, 0x394e2aef, 0x53f23f67, 0x68d37f3d, + 0x0721ffbe, 0xb902c53e, 0x9fb56ca6, 0x0ca75cff, 0xa431f629, 0x6c6bc577, 0x231a742a, 0x36bbbd0e, 0x1f11c34d, + 0xce3228e1, 0xa99d4d73, 0xfe296928, 0xb87fea24, 0xd489b34b, 0x62123071, 0x5e8158cc, 0xb5391410, 0xad0d892f, + 0x7959cd1e, 0x1d958b83, 0xd722512e, 0xbb939611, 0x884d90c2, 0xd63a1dd3, 0x5849c469, 0x3bb826a2, 0x799aae2a, + 0xcd8646ee, 0x111dfacd, 0xd5619000, 0x94ae1b40, 0x100aa65e, 0x71fa8635, 0x595bbece, 0x807b1d2d, 0x45b2332f, + 0x5f73f49d, 0xfe199219, 0x375173c7, 0x0193344e, 0x314d0463, 0xb8290bde, 0xbb602d88, 0x55ddf39a, 0xe51e53f8, + 0x83a59f6d, 0x3adcc724, 0xf4a4f876, 0x3758aeb0, 0x27e19453, 0x08cc018b, 0x1d5f2637, 0x2e7f53a4, 0x9fd98182, + 0x64744193, 0x0150b08a, 0xb246fc19, 0x8fa1c3a6, 0xf89bfebf, 0xdc89f1e9, 0x4e38e5a4, 0xd9df6bf2, 0xd0468273, + 0x1976c73d, 0x751459f2, 0x9982e488, 0x8ea1ef6c, 0x28edbe16, 0x7ad0018d, 0x5934026f, 0xa728d5c4, 0xdb119a45, + 0xa0e2b12c, 0x1dafa4a8, 0x9918ff0b, 0x62749bc6, 0xd54fbbad, 0xd06b8dc9, 0xaf9949a3, 0xe5412016, 0x9dd96ce6, + 0x0415f0f4, 0x78891c49, 0xb76aef21, 0x1993f27d, 0x6e9ea6f8, 0x1e356594, 0x4953f739, 0xe4707976, 0x8f35f090, + 0xf061dff3, 0x6dd2ff84, 0x3d9bd396, 0xbbb51795, 0xbb931acc, 0xfd28deec, 0x4c48a4fc, 0x77080c8c, 0x786a2f9e, + 0xd8111cbb, 0x0c15700b, 0xa6bda1a0, 0x8228254b, 0x2268018b, 0x6be9f3d4, 0x3cf08bd3, 0x1eba4d10, 0x3f5901c7, + 0x1419d6f8, 0x759554f7, 0x0959b2fd, 0x8b8f6b98, 0x64227dab, 0xa79af448, 0xfaba2440, 0x9d82f1cf, 0xeca81981, + 0x54d7a592, 0x243673e5, 0xffea63ad, 0xe1578e8c, 0x0fc86186, 0xd954133e, 0x0005d777, 0x2c2378c5, 0x254c33da, + 0x3677ad1a, 0x39ffccb0, 0x6ab1ebf8, 0x95a18fad, 0xb84db261, 0x5b4839bc, 0xdbac00f5, 0xe486528f, 0xfe45ab49, + 0x8ca75f75, 0x76e9db98, 0x3fc11e2b, 0x89d3831a, 0x1a338275, 0x656ce2f1, 0x2e6806b1, 0x4692d6ce, 0x19c26244, + 0xb0ca0f2b, 0x8371beee, 0x217a177f, 0x26ffbb37, 0x9a46a48b, 0x7bcbac08, 0xc0f43a24, 0xe8b74d7e, 0x27f5cef3, + 0x18adb186, 0xd9619bd0, 0x9bd94da2, 0xd55c18b7, 0xadb296bb, 0xebd85d9e, 0xb41f2b06, 0x53023731, 0xdc882f17, + 0x16e71dc9, 0x5db9bc90, 0x3cd38ef8, 0x0da2dce5, 0xbed73df8, 0xaf5f7d5f, 0x9119c0fc, 0x18d4ebd1, 0x336b8d01, + 0x99b55a33, 0xe98c4c9f, 0x1bb8b794, 0x2c4c79ec, 0x85bed6ae, 0xbbec70c1, 0xe99e100f, 0x54566ddd, 0x304df26a, + 0xf377438a, 0x8ae86124, 0x7652c238, 0x996fc4a6, 0xa6236b1f, 0xd58de135, 0xa2986993, 0x243087c2, 0x3b2d91a4, + 0xc96660b9, 0xe736a3d4, 0xa5043d72, 0x60ab4695, 0x0171c790, 0xdefb5bce, 0x7168adf2, 0x9fde9a65, 0x79d410f7, + 0x97b180b0, 0xe547a8a4, 0xb0d128b4, 0x505bf9be, 0x16b1358e, 0x65942db8, 0x46cd7880, 0x9142d570, 0x91f6c7f9, + 0x89fc85ce, 0x4c6c85a5, 0xe3d8b8ab, 0xacd97a5f, 0xe4524187, 0xdcfb6be7, 0xc29b5dfd, 0xac439eb1, 0x53ab9cd9, + 0xee56c046, 0xaef6b122, 0x6f84ad2c, 0xd80de402, 0x387b3a10, 0xee27e5cb, 0x18163660, 0x1dbd52bf, 0x8d17d39a, + 0x30979362, 0xdc0a4f78, 0x7deabb45, 0xb5bbdade, 0x71eda6e7, 0x592f4af3, 0xcfca43a3, 0xac12467b, 0x53ec1506, + 0x7953eb74, 0x742aec3e, 0xd68ab2e9, 0x7b499200, 0x63460fb8, 0xcfdd5857, 0x5d75fb04, 0x9387d586, 0x3147e471, + 0x1496152c, 0x7fdaacf2, 0x13f0cdbd, 0x3c270947, 0x635e96b9, 0xcd59705b, 0x4f6a554b, 0x5dca3a8f, 0x72d79003, + 0x085a9e1d, 0xf6d76839, 0x424ff6cc, 0xb2942545, 0x58bbe9f8, 0x1a21d7dd, 0x1329c856, 0x6291942c, 0x0fdc3016, + 0x28d7b640, 0x55ea1e8b, 0x9a33501e, 0x52c1e8c9, 0xf53da209, 0x6f19c2d9, 0xb0b69bb3, 0x345b3d13, 0x6eb0c10a, + 0xeecef168, 0x618ca19b, 0xfc3c4ddf, 0x7157fce8, 0xd63acdcf, 0x51d8f4b6, 0xf7ec0c7f, 0x2dacf65a, 0x3d0e40ad, + 0x6009177e, 0xdca7400a, 0x3f5de6e2, 0xb8fbcd62, 0x54885e5f, 0x3b2180a0, 0x1c1e173e, 0x287d3b60, 0xc2dbe3b4, + 0x0ffdf4a8, 0xdd26fb26, 0x16328c19, 0x5318b0fb, 0xd829e477, 0xed94445b, 0xd5e9060d, 0x8246c9e6, 0x751b7f9d, + 0xccfcb19e, 0x841fea17, 0x13e85d59, 0x2da20aab, 0xfef08dc3, 0xf6b1269d, 0xd5cafe5e, 0x2a829a62, 0x1a9db2e4, + 0x7ea2a651, 0x9eeb02a6, 0xd2bbc7b6, 0x983ca6f0, 0x717d6d52, 0x42861a77, 0x72080a76, 0x64e35acf, 0x2cf439d1, + 0x1a322c0a, 0x23b699a3, 0x9b251b17, 0xfb32666f, 0xc13a2617, 0xed258b38, 0x706c7b7c, 0x11710729, 0x819ce3a9, + 0x533e9db2, 0x07483de5, 0xaeb29309, 0x93878413, 0x90b58d43, 0x28c62701, 0xcc429d68, 0x4643fa4f, 0x7b70cf18, + 0xf291bc30, 0x4ea922fb, 0x1cdeb164, 0xd14e99c7, 0x7706f07d, 0xc43bf023, 0xe269993e, 0x162471bc, 0xa421ae75, + 0x9d506bb7, 0x7df764bc, 0x3cdb924c, 0xb74b2516, 0x769d6edf, 0x642465bc, 0x6571c43c, 0xc54fdb74, 0x2ccb89b0, + 0x6dd4f37b, 0x3b877343, 0xc9fe90f7, 0x97437b99, 0x4e865173, 0x52f7f59d, 0x9ca8774a, 0x46ec7e3c, 0xe1a3153c, + 0x240ae87d, 0xe1310c06, 0x13635f66, 0xb66c696c, 0x21682ea6, 0x29813820, 0xeb041992, 0xd7d1aaaf, 0x1894550f, + 0x4621b871, 0xef77a810, 0xc39d553f, 0xdd731477, 0xf64dc992, 0xd3a8e42d, 0x2d1b1e0d, 0xaa1d5eb0, 0xee1b2d03, + 0x9edae79f, 0x6e0ff1b5, 0xe59177e1, 0xc61dfea4, 0x47dfe535, 0xf6290734, 0xf6f64d5a, 0x40545723, 0x9e04c2f2, + 0x955b3e0d, 0x7214c3da, 0xce9204f8, 0x2fdebb18, 0x814cbc4b, 0xfb003fdb, 0xb404ffd0, 0x3ebf28bf, 0x1b1cbe40, + 0xa2358c39, 0xd9f4a2c8, 0xdb736ee6, 0x987f52cd, 0x3965eeb8, 0xd6d310c1, 0x7d11e847, 0x8e73e5e4, 0x8ab18cd4, + 0xd254e152, 0x2baa6d3e, 0x0357edee, 0x45442cff, 0x0f106f2c, 0x740b5986, 0xf8409b68, 0xdf164f88, 0x299861a9, + 0x375306bc, 0x82fa2df8, 0xed8d211d, 0x1d13ab46, 0x4d67ee14, 0x6e9a9ea8, 0x46df1431, 0x039327b1, 0x6a636d5c, + 0x2920284a, 0xecb067f8, 0x3ab9ecd1, 0xbd5bec8f, 0x3fc6967c, 0x6c3c9f27, 0x0a4295e4, 0x32f9c982, 0x71a33c8b, + 0xac5728cc, 0x61a720c6, 0xc3797af6, 0x4f1fc199, 0x0532369c, 0x0414fa77, 0x557854a7, 0xd1c4af41, 0x723be344, + 0x5802003f, 0xaae7e14c, 0xfb91a002, 0x43032bb1, 0x61f8db28, 0xc2de8174, 0xac2bc091, 0x4bdde265, 0x1b2eea5e, + 0xb6a71e70, 0xe1191942, 0xd83e08b5, 0xe0ca20d0, 0x4b7a1ef8, 0x209f1001, 0x368c0ebf, 0x2fa43745, 0xe8352afd, + 0xbaccb9ae, 0x7475830c, 0x505edac0, 0x053b54bd, 0xf92dafd0, 0xb38c2234, 0x54550b50, 0x458dc083, 0x01ab2f9e, + 0xce3d9dea, 0x1585b197, 0xadaf6a8b, 0xf07f5b4d, 0x995e9f35, 0xaea3c8b5, 0x50678fa2, 0xc9af461d, 0x92234b8d, + 0x1e909955, 0x2ecf9793, 0x3c6608d9, 0x1025a9a9, 0x782094df, 0x56e55637, 0x6bb905cd, 0x488bc9e7, 0x5461b4d6, + 0x91488eb7, 0x585b2e0b, 0x25bd839d, 0x7643f162, 0xdfb00e3b, 0x47f0fa97, 0xad456ed1, 0xf7d267e2, 0x14d01ecc, + 0x43b35db2, 0xdc35de05, 0xc0652839, 0xeebab7dd, 0x585afbf5, 0x47521aa5, 0x8fb9b2d9, 0x9873d391, 0x9724d593, + 0x4bcdffd4, 0x320ffb35, 0x1ad66092, 0x59360bba, 0x91498aa9, 0xc33e5599, 0x6fd07d5b, 0x316d3d25, 0xebb579ad, + 0xcb879b8f, 0x8f5b6243, 0x94c0b2cc, 0x7ed598e4, 0x33b9a531, 0xdab344de, 0x9b8c0874, 0x4ceeca38, 0x8c66456a, + 0x5961c53b, 0x08e053c6, 0x0a0e70da, 0xf3f76161, 0x6a843c04, 0xb3031bd7, 0x47420d91, 0x39ffbf7c, 0x1f880879, + 0x24a71523, 0xa9eb2227, 0xcfef8ed4, 0xbb8cd492, 0x4aaa8af8, 0x25181221, 0x4edcfa32, 0x22c247b2, 0xd2d5679e, + 0x2a65c4ea, 0x2a476172, 0x335ce926, 0x8c593e9e, 0xbf020f07, 0xbba24a43, 0xd0e234d6, 0x1d1067cc, 0x470db7e0, + 0xd7561d6f, 0x893ff919, 0xbbcd5ac5, 0xb306406f, 0x6a36f92c, 0xe2dc3ed8, 0x806fc4de, 0x7fc79b7a, 0xbf510cde, + 0x18a980db, 0x8a40d668, 0xd6e7938d, 0x7dbf5890, 0x7130f2b3, 0xa3cded6d, 0x984c21b5, 0x7317294e, 0xb3c76366, + 0xff900a69, 0x7291b3d3, 0x4b571cdd, 0xf8a4e76c, 0x56f9c48d, 0x77898f87, 0x3d2e49cb, 0x90bc8368, 0xee33f281, + 0x058f7851, 0x91473d39, 0x33e92d7a, 0xbeffc970, 0x86ece455, 0xfd642575, 0x752fadad, 0x0e711e04, 0xb6057322, + 0xc70b0174, 0x863cb04b, 0x84537b2b, 0x37dabf83, 0x520d224b, 0xdfbd3280, 0x01ab00d9, 0xbffddd00, 0x1756c50b, + 0xe17c850f, 0x3a710387, 0x6eb05027, 0xecda032b, 0x1f32d186, 0xe6f2e738, 0xb81f4f7b, 0x8d7b5649, 0xac2a064f, + 0xe3f5f0a7, 0xf91c2356, 0x0b81d274, 0xd1aa50c9, 0xc322fbd5, 0x40322f61, 0x769856c5, 0x9b16e2b8, 0x78fd6c9f, + 0xa764c87e, 0x7a7e69a9, 0x4a249ed2, 0x3fca4e2d, 0x126ccc16, 0xb49bc5fe, 0x88ba744e, 0x86175131, 0x830ef53f, + 0x86708d29, 0x55587a71, 0x3b9e52eb, 0xd35cb99d, 0x4967d05f, 0x21d64f3b, 0x23f6ba03, 0xfb45947b, 0x71fdb6c4, + 0x398e1932, 0xc840c936, 0x651bddf7, 0xfe53bf87, 0x63818835, 0xa23e1a02, 0xbd3e5d7a, 0xc9bff735, 0xa38dc82e, + 0x25e2f62b, 0x09199508, 0xc63cfea0, 0x765798df, 0xb6894409, 0x2e02fa3f, 0x5cb0392a, 0x9b4fcb73, 0xc48ae6dc, + 0x22e4472d, 0xbf8c5462, 0xad73cd26, 0x31e3c6f1, 0x2b31a542, 0x48318147, 0x155ddd6e, 0x577d64e3, 0x8e82dbe7, + 0x113bdd8a, 0x398cee5d, 0xe8ff967e, 0x9b49d5ac, 0x87c5ae8a, 0x82edd22b, 0xb435dd2a, 0xa297c3ca, 0x53abc42e, + 0xd28be10b, 0xd49ff8cd, 0x41b0d929, 0x13f43ac9, 0xd78513c9, 0xf26b77c7, 0x90c53f24, 0x0076ea64, 0xa505152c, + 0xe6725df2, 0xc1a86cee, 0xe3531a05, 0xf77d0d29, 0xcfc0354b, 0xec4d88d3, 0xa0e5f195, 0x220173cf, 0x0b662372, + 0xe1154607, 0x55ec43ff, 0xb9815e3b, 0x4836f62a, 0x3408aa01, 0x048c416f, 0x563d3ade, 0x9d82a0dd, 0x05f39a91, + 0x1055cf34, 0xb0e7eb61, 0x2a11a242, 0x003b3485, 0xf5c6501e, 0x740e6945, 0x1f397fa0, 0x6cbb34ec, 0x03d4ac14, + 0x5d945c77, 0x8d9e3c59, 0x387e9f20, 0x2aa7ca8d, 0x21eb2082, 0xb193f3f3, 0x392c0d4c, 0x3d7ad354, 0x16c3e7f2, + 0xdcd00f5a, 0x0a9a030a, 0x7d9350f3, 0xc0812e1a, 0xe3cd9ccc, 0x553d870e, 0x69d1154b, 0x8176e0ca, 0xf9777068, + 0x2d941c98, 0x9af42287, 0xd4c7201b, 0xf7f36dc7, 0xce4734cb, 0xea141175, 0xdbbab98b, 0x033586af, 0x4bd3c776, + 0xece8faa0, 0xbf6432cd, 0x35808688, 0x76c656b7, 0xc6487250, 0xe7bb8074, 0x85b553b5, 0xbae89eef, 0x1e673580, + 0x787b6d05, 0x51a4534a, 0xbfc356cd, 0x9baa3445, 0x4655a10b, 0xd7656f70, 0x35614fb9, 0xed169192, 0xc8890cf3, + 0x30cf515c, 0x03bfcb05, 0xbf322383, 0xaeb31273, 0x72b0b0bc, 0xa355aa09, 0xba55475f, 0x115be1d0, 0x9b07cde9, + 0x1c4e3d15, 0x0e3d344d, 0xb6807133, 0x56c3dd49, 0x7b324fd5, 0xccd056eb, 0x42675a2a, 0x92590ac9, 0x0dffc588, + 0x75c8967c, 0xf6bb8a0a, 0x0dbe83af, 0x215ef6ce, 0x0de88f8c, 0xa428f6d4, 0x617f74d3, 0x770815dc, 0x48f9cbf9, + 0xb35dc488, 0x139a647f, 0xead45c62, 0x7ed66f05, 0x94c67f4e, 0xc1389adb, 0x481d873e, 0x96decdda, 0xc3c8beec, + 0xa75ea04c, 0xd77130e6, 0x8f7fca19, 0xc208fc79, 0x3d49638a, 0x47cd42cf, 0x6526ac2c, 0xdceaf1e9, 0x9b88a77a, + 0xb4a471d1, 0xef0dbb1e, 0x10b09cea, 0xfe0366d8, 0x0592ed64, 0xd36356ed, 0xb2b6de76, 0x81de7d4d, 0xf04ea185, + 0xbcac4457, 0xd360d5c5, 0x1de59bcb, 0x4753a856, 0x01416e92, 0xcf79b15e, 0x6d7bc88d, 0x401602c4, 0x1e4039ab, + 0xea7c1573, 0x8b4d8fea, 0xaab48c8f, 0x057170be, 0x3dfa35b9, 0xb3219571, 0x15968f2c, 0x6a1d7b83, 0x4bb95307, + 0xf3e44082, 0xe5a99708, 0x2513cc4d, 0x7f128870, 0x390969f2, 0x4b438ac1, 0xfe032050, 0x4d6965df, 0x0ba55d6d, + 0xd809fe6c, 0xbbd63eef, 0x0a7e11e7, 0x4307c0f1, 0x06f31472, 0xd33c67e8, 0xfd24e37f, 0x463753e8, 0x8af93462, + 0xc9c313ab, 0x247a8dce, 0xd449b3c6, 0xdbd5e00a, 0x58810ba9, 0xff7f4a6e, 0xdebf32ef, 0xfe3cc5a8, 0xb0b5a6e0, + 0xa30005c6, 0xaa179d7f, 0xa30a8534, 0x12ebb21c, 0x2264c956, 0x90cfb68f, 0x401963c4, 0xde1ce3b7, 0xd2508a8c, + 0x42ebb966, 0x9178c9f5, 0x42e647f3, 0x320f7dcc, 0x1bad101a, 0x935c5452, 0x74aaabdc, 0x2f76490f, 0xf8002b10, + 0x1454dea2, 0x63586578, 0x0eff8b61, 0x203dfed3, 0x76398dc9, 0xc8b8997e, 0xbf5ad325, 0xd7894f71, 0x27b8723b, + 0x4ab9502f, 0x1ab8ad94, 0x59d767a9, 0x08f40a6c, 0xa845ac4c, 0x685ea0f0, 0x98baa15f, 0x5ae5861f, 0x15aa609f, + 0xb8e14b19, 0x77cc6b6b, 0x6d785d54, 0xed9a1797, 0x61193808, 0xce3f4312, 0xd04c60b7, 0x3c361aaf, 0x2dbef308, + 0x29bc1799, 0x5d4f9d66, 0xca95084f, 0x5b173a11, 0x58396a7b, 0x90321db1, 0x23af9dbd, 0x90b2eda4, 0xae884a9d, + 0xb3ae9aa4, 0x14bc130c, 0x3635b878, 0x120d7e8f, 0x3d34eaba, 0x645ee7b1, 0x88bccc90, 0x90d3bc21, 0x29744349, + 0x85721e11, 0x18e34f07, 0xcd036866, 0x8c11160f, 0x2d6532d8, 0xeb81526a, 0xe7302e27, 0x3eb919ed, 0xb6da5e58, + 0xe5236fa6, 0x32224d50, 0x946542d6, 0xed9efdc1, 0xd69859a6, 0x43439f51, 0x631eb4db, 0xd91c8001, 0xf4e1dd20, + 0x66f6511f, 0x5e792c1c, 0x2982f449, 0xffb732bb, 0xe2951e8c, 0xe94b5e57, 0x14a76381, 0xc0ba177f, 0x3bdc965e, + 0xb73ff075, 0xbc76849d, 0xf1d4b57f, 0xa95a63e3, 0x30cde894, 0x1ca85c52, 0x1652d9a3, 0xc887e969, 0x9b5b2cf3, + 0x5b858cc2, 0x91f0c14a, 0x6f6d0ae0, 0x30b4e1d8, 0xfd0b8787, 0x31f3e4e8, 0xb3455db1, 0xfed5f41e, 0xf74aa4b3, + 0x79154c76, 0x2633a9ac, 0xe42dc461, 0x3445ee3c, 0x9c010d91, 0x1f903b27, 0xaa22a89d, 0x073d4947, 0x502ed2ce, + 0x580c5294, 0x22d14165, 0x1140fb3d, 0x69d17691, 0x098f3aec, 0xe7a5c0e4, 0x01bbc03a, 0xb37ab4c5, 0x5fd055c3, + 0x912a687e, 0x8d1264f7, 0xa001e0bb, 0x0ddbebd5, 0x2752cc48, 0x4e79241e, 0x419c789b, 0x98d3a6a3, 0x615fb5f8, + 0xa40e9d4b, 0x034abe84, 0xad63cb54, 0xcf8871f1, 0xf13a8ea9, 0x6ce6efab, 0xc708b4fd, 0x8097b2b6, 0xa21bbd0a, + 0x7dab5cf9, 0xf4a5ffbb, 0xfca1d1a2, 0x36a0059d, 0x44351b1f, 0x2cbf6fd0, 0xf3fdabd8, 0xbb519f72, 0xa79c33d2, + 0x2be376c4, 0xc5718612, 0xdb5709fc, 0x27d316d6, 0xb59930b5, 0xffe91be3, 0x8b320da1, 0xffd61c2b, 0x8f681ea8, + 0x60c0d5c7, 0x815822e5, 0xda231477, 0x35615524, 0xffb107c8, 0x4032f0af, 0x3544df64, 0x883dc7c0, 0xb32b4f86, + 0xbb166846, 0x318c7c49, 0x5faebd93, 0x11e9a838, 0xce01a081, 0xec891165, 0x05fa77d4, 0x2988fc31, 0xdd6850e6, + 0x26a1d1d5, 0xb3a4a94e, 0x80429fab, 0x5d7f7cc6, 0x098bca3d, 0xb0a56843, 0x22705ef7, 0xa10a9482, 0xa8e8c6fe, + 0xbcd0f593, 0x897a4d15, 0xca2885b0, 0x56aa1f50, 0xd0784015, 0x5daf6154, 0x4675d6ee, 0x3b9f14ea, 0xc1d77e72, + 0x203c544b, 0xe8b99679, 0xbc138e2e, 0x64a49784, 0xf0aaa328, 0x1e4828a9, 0x86607fa6, 0xd4343904, 0xc39f1ea8, + 0x87f8ed97, 0x1d160d7f, 0x6625ce63, 0x1e05665e, 0x53db6521, 0x6e719538, 0x9c553217, 0xaa59b697, 0xd04b05e3, + 0x582b7f3e, 0x67323f50, 0x1f358bdd, 0x4ce6530b, 0x48b812cc, 0x15ee9dee, 0x1ce3253b, 0x5d91a5fd, 0x75b414c8, + 0x9649510b, 0xab0e1632, 0x85f028f6, 0x80f9744f, 0xcad732b4, 0x7f35c191, 0xbb888e4c, 0xee39a580, 0x17ed5554, + 0xe61723b2, 0x7b18ec26, 0x2e47e7ea, 0xb39b06b6, 0xbbfb3630, 0xd12b0162, 0xb7a89da4, 0x911f2a2b, 0xb7628147, + 0xd30301a6, 0x77502ba0, 0x371ebf47, 0x62816d76, 0x61c130dd, 0x710346e3, 0xf65a2285, 0xdddc0c55, 0x926225d6, + 0xb7231ca6, 0x8d96b24a, 0xb87957b9, 0x96f24478, 0x9c4df571, 0xf7eb5d6e, 0x3900a4d8, 0x3c604c42, 0x22f4e1a8, + 0x9ca51298, 0x28bdee99, 0xde6f6c5b, 0x21b1b446, 0xa26b0ea4, 0x70c9a5ea, 0x7efe7c96, 0xed957c40, 0xbd149258, + 0x8a40654b, 0xef2a520e, 0x1a2391e1, 0x6fe678d2, 0xdfa3dcd8, 0x22965bb5, 0x39c8a664, 0x341be7ef, 0x656af9e4, + 0x2db20b67, 0x6bac1a74, 0x9566450b, 0x450e2fd5, 0x8d5226a4, 0x993b0d6a, 0x4e2a32db, 0x08cd4a78, 0x8845207f, + 0x2f58bf12, 0xc181e544, 0x314bc4e1, 0x68455bb0, 0xe58414a3, 0x53a2b98e, 0x3817d767, 0xf5c31296, 0x769586f4, + 0x828abb7b, 0x24149075, 0x7779344d, 0x1ba25a84, 0x876f994d, 0x842b1ca4, 0x46beaa82, 0x19723607, 0x5ef66de7, + 0x3e844e6d, 0x594ee949, 0x7c9c0ad3, 0x79a1f391, 0x60b3f8e9, 0xe4e3697b, 0x930d7ebb, 0xdee04970, 0x8b3b1e85, + 0xa9ace9f4, 0xbba418f2, 0xa5100ea2, 0x6d99ce1d, 0xda334eec, 0x4ce9905d, 0x596d2475, 0x66294ddc, 0xe9131183, + 0x5002729d, 0xeee1030b, 0x3d58d51e, 0xa4893cb6, 0xb66f7f8d, 0xdc5ea3f8, 0x8e9629b1, 0x843c66d8, 0xf3cd41b5, + 0x1446afc7, 0x354c1d57, 0x2e9c4d74, 0x473e879d, 0x49a384d7, 0xcd675136, 0xba7ddef3, 0x41530af8, 0xd2a6e3e5, + 0x274fb24a, 0x4cbfe5d4, 0x3350cbfe, 0xcbbfd48b, 0xe857a719, 0x280fea52, 0x2db7c470, 0xe89eb300, 0x45825914, + 0x90b4a7fb, 0x85c67f86, 0x0f5abcf7, 0xd965e6c3, 0x08484ef8, 0x4849a42d, 0x70178451, 0xffca9fc2, 0xc2c359a8, + 0xec88d132, 0x93f27776, 0x18134e5e, 0xbfa7199a, 0x44f57f5e, 0xb57f21b1, 0x566955f2, 0x9953e8c7, 0xa0a5d0d2, + 0x54c58f4d, 0x33d83e50, 0xbc9d7638, 0xb9fe9162, 0x1e9ac9ce, 0x9c9a7da3, 0x29692e13, 0x139a7626, 0x658f7904, + 0x5325db16, 0xb4853466, 0x0be355fe, 0x92ada551, 0xc8b90403, 0x8fc44395, 0x3c6e14df, 0x57b27f6b, 0x4dd23eef, + 0x10a057ac, 0xc38e037b, 0x3bb371c4, 0xc0ebf3f1, 0xa6d50c54, 0x6478067b, 0x592f801a, 0xa53aee37, 0x4c357176, + 0xf6e54225, 0xa51e1850, 0xb5ec06af, 0x3b66a7bf, 0x6a9db1b4, 0x1f5d859b, 0xa15bc013, 0x74181111, 0x4f0f3f1a, + 0x409b5e73, 0xcc291d76, 0xbb6b2b8e, 0xfe3027da, 0xb9b4a364, 0x644a3f39, 0x4e08d78f, 0x651c9633, 0x9adba918, + 0x086ae84c, 0x44629d3d, 0xda9c5fb9, 0x7c770526, 0xa69b274e, 0xf13c9c7c, 0xdb7d9366, 0x25c1ea37, 0x17c2eb06, + 0x0703e9bb, 0xdc2659ed, 0xd4831755, 0x7d3b0cce, 0x89210a69, 0x287f55d3, 0x6dd3c1ce, 0x47d25250, 0xaf9b08bc, + 0xfda647b1, 0xb023f67d, 0x1f89f285, 0x51a42733, 0x570423bf, 0x925cfadf, 0x968351fa, 0xcd7f98a8, 0x68459452, + 0x0d91f1fc, 0xf26349cf, 0x52271174, 0x954db3bd, 0x846fd690, 0x24fb9b4b, 0x04c30ac9, 0xf0d5f71b, 0x5f8810a3, + 0x1ef0dd66, 0x92b47966, 0x2a0cbd4d, 0x115c95c7, 0x73b4f77d, 0x6f109464, 0x4743d841, 0x06580b21, 0xf62a2565, + 0xd7f70a32, 0x9b43aca5, 0x55f74a72, 0x463abe64, 0x0843b4a3, 0x0b700a92, 0x8a8e55e9, 0xcaa7ffaf, 0x478b9b7b, + 0x925e1544, 0x70d1b369, 0x315d4c19, 0xe79993d5, 0x5f4e2f87, 0x87f0d38a, 0x38e75a59, 0x68cdc95e, 0xb528ac00, + 0x1d38dafb, 0x628d25e0, 0x3881172b, 0x7c5ebdb5, 0x69fb948c, 0x284f1f66, 0xb80373a6, 0x840da486, 0x5b5159a3, + 0x26ae38c0, 0x3c8c89b4, 0xd0f7cc34, 0xaa7a499e, 0xfaf6ac4e, 0xf2255b32, 0x5cc334f1, 0x4e908390, 0x7d69828e, + 0xfece1943, 0x4ad65a56, 0xf8cfb119, 0x0d2d7ec8, 0x01369bf0, 0x11a02660, 0xb22b92b7, 0xc1d7a0b1, 0x2fb8c0d3, + 0x86f26440, 0xfddde68a, 0x406d69fc, 0x97aa6aa6, 0xc9dec001, 0xc8bb0e7b, 0xdc3ef53e, 0x8b195912, 0xf43254d0, + 0x2f0790ac, 0x72f38c01, 0xb9f26837, 0x8a72cd73, 0xf13bbfcc, 0x8c8be6a8, 0xc3d6aff4, 0x2ea47ad1, 0x61e423a0, + 0xbdba9383, 0xbad92293, 0xe01e5fd8, 0xf6e5ea8b, 0x4363633a, 0xf0ca76a9, 0x4c22a282, 0xdaac861f, 0x4c555d1b, + 0xc1c21a72, 0x7bbbfbfb, 0x06ffdd28, 0xf64028e7, 0x33a5d8cd, 0xf87a37fb, 0x02a530c5, 0x0897e3f4, 0x8a3871ca, + 0x58705214, 0x071e0139, 0xad3d03f3, 0xbaef3dc9, 0xa9ed55f0, 0x66cdef91, 0x9ee82719, 0x3cdc8e9f, 0x256d1f62, + 0x090bd294, 0xf6a99888, 0x6faf95fb, 0x89d67ea7, 0xa31e9d05, 0xf276cab8, 0x799691a2, 0x26052dca, 0xafaa0ed9, + 0xa415451f, 0xc8f8b949, 0x0df12c40, 0x0519bb2d, 0xd307e441, 0xdbebf071, 0x6bf156bf, 0xc79f20f9, 0xf02375a1, + 0x6660abbc, 0x4bf5a3f1, 0xab872dea, 0x192be648, 0x2a19c2db, 0xe056610a, 0x7b5ba0f8, 0xbbb05220, 0x71869aa6, + 0x5bdc6ee6, 0x160e2822, 0xfd58717b, 0x0ce3b1e4, 0xa447afc2, 0x462d19d5, 0x64187281, 0x043acb9e, 0x2df5c49a, + 0x7259a6b0, 0x74d56162, 0x09c3409e, 0xb1bb4c5b, 0x57ab6888, 0x80b3e784, 0x66b02774, 0x32db1876, 0xb990dd60, + 0xb26db348, 0x858f6836, 0xf585d3ab, 0x6f8a4712, 0xeb2ab130, 0x9453998a, 0xf9877877, 0xbf2e1df1, 0x6f852ae8, + 0xb2e207b5, 0xf309a407, 0xc63c3dd1, 0x7fd7e3a7, 0x4772f78f, 0xaa32232d, 0x151bd2ec, 0x83aed5b1, 0x897220d0, + 0x3e7b5fe7, 0xe6627fd9, 0x48534d00, 0x3f223835, 0xb1a4aae5, 0xec907251, 0xc3846acc, 0xdc488219, 0xe8928263, + 0x2e35b2cb, 0x984c194d, 0x83d70432, 0x29f773bd, 0x3ac5f90e, 0xbacf90bf, 0xa37d510b, 0x1f822d49, 0x251dbfef, + 0xf13b67ab, 0x243b1dad, 0xe29394c9, 0xebaa9352, 0x9b682dd4, 0xfdf5d2ac, 0xd5444627, 0xfba83a42, 0x38f4dbc8, + 0xa7824473, 0x63a9e683, 0x66116c2a, 0x2a12966f, 0x3361097e, 0x58ae47cc, 0x13e8a8c0, 0x09d60959, 0xa08ca785, + 0x1f521d60, 0xfa417c4a, 0x6bcdb1c6, 0x41263c2a, 0x1e546326, 0x0082d46f, 0x4c3e4b57, 0x6d8ba5d0, 0x61c6cb6d, + 0xabb48c4a, 0xab90c1b0, 0x136ce3b3, 0x3f7ccb78, 0xc45ea918, 0x3161bc27, 0x3c77fe21, 0xd41dc1ee, 0x6ad9e550, + 0x9502fb0b, 0x90267f01, 0x153a7960, 0x464b0783, 0x5943d95d, 0xcc9acc28, 0xf18f07a6, 0xa9881078, 0x8ddaed07, + 0xca7effda, 0xccd92d06, 0x141dd10b, 0x968b7c5f, 0xeadbbc45, 0xf6a25333, 0xd35a5fe0, 0x0b991213, 0xd54f3977, + 0x8ebe68cd, 0xe9edd677, 0xc240a7ad, 0xbbd01f41, 0xe9a185f0, 0x7eb0c742, 0xc56f55fb, 0x15d713ab, 0x2826e587, + 0xbd53d226, 0x8be69ffb, 0xdf81ad5c, 0xb4cc392b, 0xcd35b755, 0xa4d179c1, 0x159feeb9, 0xaa1be84c, 0xc68bf3e9, + 0x835e4cbe, 0x444d79a8, 0x76c6cf47, 0xe6b163f2, 0x95bb39d5, 0x150f5e37, 0xe32bf956, 0x0e1bef00, 0xe795d3d5, + 0x0cb49b6a, 0xd8eeb50e, 0xc00ecbdf, 0xaf1af923, 0xb8fa49b6, 0x09fb4eee, 0xf0c7338d, 0x6202c6fb, 0x19276da2, + 0x703a0afa, 0xbbea9726, 0xf94a4344, 0x35a0191a, 0xea7d5198, 0xbdb48d62, 0xc87f7b6e, 0x4b3500ab, 0x0335604e, + 0xcf453dfb, 0xdbcd9b27, 0xc5c7739f, 0x0adffb78, 0x23b0e48f, 0xad20b2ee, 0xfe7e399c, 0xf734858f, 0x21f71f16, + 0x55e4e234, 0x3f0dac92, 0x66e2c227, 0xe1b3e4fc, 0x9d50c930, 0x9b9ff668, 0xc4b9f360, 0xa8d08bac, 0x4807aedf, + 0xf4d0c129, 0xa9dd0b3f, 0x210ab786, 0xcb291023, 0x64fcaa0e, 0xb06561a0, 0x2e00812f, 0x60e5226f, 0x51ed9666, + 0x3d8e865e, 0x2bd68410, 0x367884eb, 0xbd024f85, 0x28ffbb10, 0x749c19e2, 0x03c18756, 0x9fc35ad4, 0xa289135a, + 0x78abed85, 0x8e5e7e16, 0xf1ce714b, 0x83a34157, 0x8982465e, 0x9007c277, 0x94b61ba6, 0xad15cd57, 0x25d8dd0a, + 0xa121ab10, 0x57e581a0, 0x34f8ac16, 0xeb6cf800, 0xdeabea9a, 0x19ccd7f2, 0x624a1371, 0x25a2f338, 0x2ea60f75, + 0xb8adbd7a, 0x79b8aa84, 0xe9267ec6, 0xbef060be, 0xa4a685d0, 0xad3d5091, 0xa349d5ed, 0xba1646f7, 0xe6885d88, + 0xf91de8f4, 0x9b8ecc7a, 0xa8edf479, 0xadaf0719, 0x2a36b178, 0xe11af8f3, 0x718722b4, 0x1f9980e4, 0x4bf0e97c, + 0x6272acce, 0xcf40df0f, 0x61608239, 0xba678dc0, 0x84242ad7, 0xdfd66142, 0xaa8aab05, 0x12f58bbc, 0x784770d3, + 0xf1346187, 0xa19e8207, 0xb968e5b6, 0xec8c5f94, 0xbb496fc9, 0xf04894b3, 0x72a72055, 0x2be60ced, 0xe34db9c8, + 0xe3051d9c, 0x7fbf5b1c, 0xba144ed4, 0x1f1aad71, 0xaf61be6c, 0xcaeb52e0, 0xc58d5338, 0x59e5b21c, 0x4e3bc8d5, + 0x22e7fa71, 0x143e86d0, 0x0b5e7615, 0xad62837d, 0x68ef1b41, 0xa9b9d1a4, 0xf02009ae, 0xe973f658, 0x9d988c4c, + 0xa564aa03, 0xf67ef18f, 0x2a2543fa, 0x370ec46f, 0x009633b6, 0xba123415, 0xb3e7fa66, 0x51d42063, 0xcb76c238, + 0x53f9b3be, 0x8ee4bebf, 0x795a2e18, 0x0dfd2078, 0x54b891b6, 0x035d9fc5, 0x92a77f58, 0x795cf7a1, 0xedae22b1, + 0xda367339, 0xa6d99f92, 0x6a4e93fa, 0x7bc2a4ec, 0xcae61227, 0x6c44c121, 0xa80e9d54, 0x85a170ba, 0x2a736471, + 0xf50d5b1f, 0x32a89004, 0x4bbbee78, 0xa6548891, 0x5bf5e8ea, 0x0dc94d76, 0x503e69f0, 0x36f0f850, 0x16a71191, + 0x4d2fbdb8, 0xde15dc30, 0x6366af31, 0xb314b953, 0x00f663ac, 0x9fc9255f, 0x397fdce2, 0x43caa313, 0xc28b8c39, + 0xec7bde43, 0x66e3000c, 0xa8075789, 0xa8709fad, 0x218da9a8, 0x7efd413a, 0x10498337, 0xaef2ee55, 0x6c930bbc, + 0xa5dd1cbc, 0x02ea89be, 0x20ed8565, 0x2b32b2b5, 0xa02143a4, 0xc7ac79b3, 0xd6c8ecf0, 0x38060d08, 0xb4b2cfdc, + 0xae903562, 0x5558dc56, 0x031f1f4f, 0x6e1d78e1, 0x9a56394c, 0x6ef7e537, 0x29d4e7f0, 0x9f03eacc, 0xdd6ff5b9, + 0x34ed73d1, 0x598332c1, 0xbe32ebc2, 0xf333ffc3, 0x32ef0c3f, 0xf8f8fe61, 0xba26a735, 0xcf785eee, 0xbde66c30, + 0x0e04054c, 0xc6073bb7, 0x5dfa15c4, 0xcf3c6ec2, 0x4f809e7d, 0xb48b1ad2, 0x7dcf4bd4, 0x1e417796, 0x61fef601, + 0xc315b98e, 0x45ad1d13, 0x6fc74894, 0xc92db856, 0x9dbcd206, 0xc94557e2, 0xfd0029ef, 0xef939d91, 0xe74b64bb, + 0xa3bd7e4d, 0xcbec5bcc, 0x6b8e5f8a, 0xc1fb8615, 0xe30dd742, 0xe8873f04, 0xf796d180, 0x2aa14533, 0x02f0e4dd, + 0x4092f1ff, 0x46b17c79, 0xe0b76567, 0x5d0feb0b, 0x1979ecac, 0x9f5659d6, 0x2e5c63b9, 0xccaeab62, 0xf0064686, + 0xa22a9a79, 0x6a43aef6, 0xb65df672, 0xa38cd22f, 0x8733cdc9, 0x83b14336, 0x9282ab9b, 0xeb7441b2, 0x9aecf1ef, + 0x838d5070, 0x09779413, 0x069c8067, 0xca073079, 0x43739b7f, 0xe6f3ae9f, 0x2da4708b, 0xfcc77c76, 0x88c0a04e, + 0x8a37d822, 0x24a9b421, 0x2d118698, 0xc6c5eccc, 0xa30251c6, 0xd682fa41, 0xe3d8dd55, 0x90800654, 0x26eec74e, + 0x2e115931, 0x5412aa79, 0x04c46ef8, 0xb5c1dbfb, 0xc8e45c93, 0x1ff21215, 0x623979f4, 0xec7b361c, 0xc0b672f1, + 0x24ad455a, 0xb171fcd1, 0x77215bdd, 0x38031262, 0xf7496d85, 0xc558bb5b, 0x10abdde3, 0xe82932c3, 0x1f353a24, + 0xc27e1e7b, 0x5187b1f4, 0xfdb0dcd2, 0xc2d6cbd0, 0x48b59d31, 0x660c6866, 0x304ab77d, 0x07afbde4, 0x460cafd5, + 0xf8cd7d44, 0x727594be, 0x552240f5, 0x0a94db72, 0x374c0485, 0x645fa59b, 0x351e1770, 0x2c70d479, 0xf89d1e4c, + 0x3ba4edc0, 0x5ebffafe, 0x0fafb36d, 0xcaaf8874, 0x7c4407dc, 0x258f7d80, 0x1d0a277c, 0xa94de257, 0xb2f91e70, + 0x29d2e408, 0x94437714, 0xc9756b98, 0xee41e540, 0x5ca50188, 0xcb3d923b, 0xbf6a703e, 0x8160c698, 0x38c3ef08, + 0x23338b35, 0x1b2006a2, 0x5d18e757, 0x1023044e, 0x47b1c107, 0x48bb1ddb, 0x19874f03, 0xd436846f, 0x66ca3cf6, + 0xa592c7a2, 0xc2334420, 0x0ded1216, 0xfd04569e, 0x3f554681, 0xfb722f7b, 0x6100b12f, 0xdc7b1b2c, 0x322bf18c, + 0x80e46919, 0xbf30a8df, 0x9cfef529, 0x13993ea2, 0x0882591b, 0x1a15b671, 0x7bf2b84c, 0xd54f9d3c, 0xf6848439, + 0x4c3a198c, 0xe39d9dc1, 0x58cce97a, 0x61980483, 0xb499fd9c, 0x5b86175c, 0x786e687f, 0x30b73c80, 0x306687c1, + 0xae3de9a7, 0x50e8434d, 0x92c2d047, 0x0a336188, 0x8ff48d00, 0x1f881a0b, 0x81ce8d2b, 0x658f31bd, 0xbb144c2c, + 0xaea61e2c, 0x4bd31a1d, 0x5c7c2c9a, 0x6084d3df, 0x6232fcb5, 0x69f6b354, 0xdaf69678, 0x6fe4de92, 0x63b08819, + 0xb57d6eb5, 0x6a66e2bc, 0xf2c17fc8, 0x0049a064, 0xd7282906, 0x747bdf7d, 0x9eec496d, 0xa2e22e8d, 0x55ae4b6a, + 0xe3ceafc8, 0xa4ab8f08, 0x7c23301e, 0x370d7f2a, 0x8eba54c3, 0xc6e112d2, 0xcf2f3e6a, 0xc583a00e, 0x243e795d, + 0x2033fe30, 0xd2d5ca4e, 0xf1cb5996, 0x20032959, 0xdc95ef44, 0x88102279, 0xf50b933c, 0xb0b085f0, 0x2cd376da, + 0xb61e2bc6, 0x9e038a4b, 0x95c45ce2, 0xbaa6c610, 0xd61d49e4, 0xc7c59ac8, 0x39020002, 0xedf411a3, 0x3287faea, + 0x35b0e526, 0x04fba38c, 0xe50a95c9, 0xe10b25c0, 0x4e9d5049, 0x6fe19658, 0x69dc7f67, 0x5ea1ebd5, 0x9739ed9e, + 0x5ae852e1, 0x430fdffb, 0x11712a08, 0x34f45c04, 0x46b0872f, 0x5b7b9cd5, 0x369a6beb, 0xe217fa9d, 0x0c9e4509, + 0x82deb0d1, 0xcda9bccc, 0x45499a2c, 0x08d74a73, 0x3c1a7354, 0xb858848b, 0x494633b5, 0x80d42e7e, 0x14fd7fe0, + 0x53448869, 0xaee8794d, 0xaf5ba907, 0xabf0b96f, 0x07f5d2e1, 0x8d7f99a0, 0xcc210946, 0xfb69b7c3, 0x87b80632, + 0xad243b27, 0x456f653f, 0xc45b6163, 0xb36a2c1f, 0x634ee23b, 0xc73e4c37, 0x533ee5d8, 0xa8bb5bca, 0xde15f863, + 0xf9344628, 0x6ede8408, 0x62bbdcce, 0x71fc03df, 0xc25b2a70, 0xee1bbcf0, 0x7752db6f, 0xd72cc93d, 0xd1f241c4, + 0x7debdba2, 0xaf4c21bb, 0x7f87f9ef, 0xd7e18c08, 0x05d2d5a7, 0xe529f203, 0xebd0e6b9, 0x02c0ad67, 0x7fd92ceb, + 0x43aa7f53, 0x19c88a7a, 0x8b32098a, 0x0db009d1, 0x7f39030d, 0x60638a86, 0x8f6eec35, 0x89867613, 0x1a029b1a, + 0x6eafad95, 0xc9b0dd04, 0x5d231d00, 0xcb72dce8, 0x81dfe3c2, 0xc15e27de, 0x445b545a, 0xa40ce3d1, 0xb2516f1a, + 0x41b32f8a, 0xfc149b44, 0x46664e9e, 0x73259e1e, 0xc07e7b5d, 0xa1af66c5, 0xeb5031bf, 0xa9e25b27, 0x71c2191e, + 0x816ddb20, 0x4b25bf7b, 0x58a73be3, 0xaabe0356, 0x344b5a28, 0x157dbb46, 0x4a99c510, 0xecc557bd, 0xef3f085a, + 0xda54c52c, 0xff397218, 0x1e6135d6, 0x92f2962c, 0xa3baa124, 0x54ed4acd, 0x8371cb45, 0xf8b528b7, 0x0c461137, + 0x282bf1b6, 0xbc71545c, 0x9cfbb6d6, 0xeb2f4cf5, 0x28c44c8e, 0x2505d132, 0x13ea52f9, 0x8f636b51, 0xb83cf38d, + 0xf400dbf7, 0xe2063615, 0x54ac75f8, 0xe9b97f72, 0x84afc0fb, 0x37e9d038, 0xd3f1d0ec, 0x023f9229, 0xe9a47385, + 0xe0d7471e, 0xdd424018, 0x37ede853, 0x80711edc, 0xa6a783e9, 0xb654e568, 0x92ce8e53, 0x72cc8687, 0xfce7c1fd, + 0xf15d171f, 0x61d14b65, 0x349e4490, 0x843bfdab, 0xc47ad84f, 0x15f32d9d, 0x98a62171, 0x00a23a75, 0xe9ba4de0, + 0x489e84ff, 0x84f3fd78, 0xf2196d1a, 0x93d6f606, 0x521a52f9, 0xf7e52846, 0xeb849d23, 0xfd906f8a, 0xd6e7e1c3, + 0x943043c3, 0x5e5da163, 0x4477f967, 0x95451171, 0xc89fbe19, 0xba820588, 0x56372e8a, 0x1925cae0, 0xf9c982ff, + 0xd88a4047, 0xfcbc8d21, 0xffb10287, 0xc0225369, 0xb20856ac, 0xd14757ad, 0x13cb7a7c, 0x096a4d2f, 0xbc1ff14f, + 0x6500290b, 0xfc3ae44a, 0x9fb256fc, 0x642598e9, 0xff8ee3c8, 0x56ea3647, 0x47a220e8, 0x8c152f25, 0x333922d7, + 0x5754b17e, 0xb8da2104, 0xae8a2044, 0x502cc10d, 0x54cfc477, 0x0e12917f, 0xc7a94ee1, 0xe342a341, 0xe9a7068e, + 0xefc2a151, 0x0f8f8c85, 0x733a2626, 0xce152262, 0x1c67a0da, 0x420585e3, 0x9aeab5be, 0xd12df2d5, 0x96fd5eee, + 0x9c8be1df, 0xfbf1f296, 0x2043c8c2, 0x7e6053e2, 0x900901eb, 0xfc2d3bc9, 0x2314a632, 0x9f7f4d5d, 0x8d9528a4, + 0x6f4d0e25, 0xe48e4c78, 0x246d2c80, 0xa9f42856, 0x0fc2453f, 0x19bb0b26, 0x7307e10d, 0x61c90640, 0x5dee0b43, + 0x646244d9, 0xf9b13c3a, 0x51b25179, 0xfc2ea237, 0x1717208a, 0x4587b615, 0x50ed0eed, 0x47f07da4, 0x9accfa9e, + 0x8ae0de03, 0x97726846, 0xedb3ab18, 0xe6a17e0c, 0xb7c8860d, 0x3540fd34, 0x9113f055, 0x62f32694, 0x9aaaef19, + 0x699c63d8, 0x6f92c4d8, 0x1cc6c425, 0x6555828f, 0x4a17ef2d, 0x0aeb9c00, 0x26e2c8dd, 0x9efba388, 0xb0fd86b5, + 0x50451538, 0x44963138, 0xa02638b3, 0xe747745e, 0xb951de1a, 0x5f23086e, 0x6b000b9b, 0x206a60c3, 0x834a87fe, + 0x747c3c04, 0x6d20e608, 0x0421dfc7, 0x4c7f0d01, 0xf8df713c, 0x8bdd0599, 0x1f9f1e48, 0x4d7becf4, 0x25bc8e3b, + 0xce28705d, 0xc6040d69, 0x49fbdc40, 0x5dfd39be, 0xc17b880d, 0xd7ed739a, 0xa35f7fd0, 0x74c844c4, 0x7cb781ff, + 0x2e638799, 0x376ce6f5, 0x1a0347f0, 0xd26f54d8, 0x91dfdb2d, 0xebe447f7, 0xd1177886, 0xd534d9e4, 0xf614dab5, + 0xd449b62d, 0x27d9dcb5, 0xe8492e64, 0x9c4b89a1, 0xc132a218, 0xc82b96a5, 0x020fb671, 0xf3605d05, 0x85ab0592, + 0x5818000a, 0x06bc982d, 0x415df9f2, 0x614f04e6, 0x6442fa2a, 0x3b03bcba, 0x66e3a38f, 0x5de20260, 0x061a19a7, + 0x937f9b7b, 0x0831c39f, 0xf6ee4fee, 0x8c02b44d, 0x243af660, 0xf8f48f5c, 0x784c4ee0, 0x38ea8855, 0xa5a60654, + 0xe1ef31c6, 0x1b3e4889, 0xb84273d6, 0x3446d2ef, 0x2614ad37, 0xd260fa01, 0xf6c3c266, 0xf22c7c56, 0xbdf4285e, + 0xc31a5214, 0xf93f1d36, 0xc69dd8a2, 0x75606f0e, 0xadae2de6, 0x1f4eac7c, 0x7bd70f3f, 0xe875dc26, 0xafbfd166, + 0xdb9d72df, 0x93075ec9, 0x1fca9e23, 0x73c30a1f, 0xd409f606, 0x1ecdee3f, 0x008d92ff, 0x22e88522, 0xfbd25855, + 0x38ebf7b2, 0x23feea37, 0xa60a34f8, 0x61e80868, 0x6cb83e16, 0xc50082ee, 0xb0837567, 0xcde2e952, 0xfdc4383c, + 0x8c6d90e7, 0xd3f5d9b0, 0xf5549082, 0xafb39c0d, 0x13927a33, 0x5ca305d2, 0x02984325, 0x7c6447e3, 0x949ec78d, + 0xb1228fd7, 0x04d527f5, 0x54ee17f1, 0xaa461c66, 0x009db83a, 0x72e3cd95, 0xc2cb939f, 0xd22c0c91, 0x73955250, + 0xa46027ce, 0xef23e214, 0xc9f31d8f, 0x4616a531, 0x1ee51312, 0x7db6514e, 0x11e8ef2a, 0xb7f4ebb4, 0xc584c827, + 0x2d2fe0e3, 0x359096ba, 0x3a510ece, 0x87abfa70, 0xe440d759, 0xa4248022, 0x59e963f1, 0x092b0b16, 0xf6c0e9bd, + 0x35248d7b, 0x51a02879, 0xe9f8243e, 0x90597305, 0x9fb352df, 0x728dc2a9, 0x1cf05ea8, 0x812bdecf, 0x5b221c2e, + 0x73588e56, 0x42bc0062, 0xf98b39a9, 0xd2a0b925, 0x744c1ff6, 0x45130d95, 0x6a87ecfa, 0x4d5da7d7, 0x7b30ab85, + 0x2b64c25b, 0x2b60851e, 0x14206925, 0x726faaf6, 0x73d27fb1, 0x181a0195, 0x3c27e0e7, 0xf6adddde, 0x8aa02be2, + 0x55d6c016, 0xc3fcf824, 0xc01f574f, 0xcfe138c1, 0x798fa5cd, 0xa3e11db5, 0x8f1bc151, 0x7feec3ec, 0x95e56693, + 0x90bc438b, 0xa3e93140, 0x577bb446, 0x670e480d, 0x5842d1ea, 0x78130157, 0xe45aa5c9, 0xb5605f2e, 0x992ee623, + 0x58d58767, 0x4cd78c92, 0xb266e8c3, 0xfc67e6ec, 0xb33c0559, 0x489ff348, 0x15e89a44, 0x2a3fe4ce, 0x8a10c2b7, + 0xe14d8d99, 0x199a9bd9, 0x34f6be74, 0xab45ada6, 0x05b59c6d, 0x66b68061, 0x052985a3, 0x4ec2cbf4, 0xfa9d0cd4, + 0x50cfa119, 0x2366ce04, 0x25252fdd, 0x162e79cc, 0x2f0492f4, 0x1cfaa245, 0xd275e693, 0x89bb26e4, 0xea61df4b, + 0x233a2fa5, 0xf7ee80ac, 0xe29488c2, 0x3ff59a2f, 0xe6a913fe, 0xec65d734, 0x5a9ee8f4, 0x9ae5deb7, 0x75d1b356, + 0xb5b68d83, 0x42d7125d, 0x9d0af26a, 0x59adf811, 0x88fbbf0c, 0xd74a67cb, 0xfa0c9cf7, 0xc41e311b, 0xd8edda69, + 0x796568e8, 0x89949ce3, 0xc9a31b1b, 0x7d4f55c2, 0xf072b1ce, 0x4d1e2bf4, 0x815b8e12, 0x1bbf5f8c, 0xcfa28802, + 0xb51c462c, 0x19b23bfd, 0x4767383e, 0x8af29dd6, 0xfe4ea85e, 0xcf0fec3a, 0x17d83274, 0x6ad7644b, 0x670dec56, + 0x59bff927, 0x5c528c8c, 0xde875cd7, 0xceb50104, 0xe02c8e0f, 0xbdcda1e4, 0x17ddf103, 0x30273cf9, 0x39cdadde, + 0x2ee053e2, 0x7da6d185, 0xbc2af195, 0x98b88012, 0xfdb3182e, 0xd061763c, 0xd58262c7, 0x401a63ea, 0xb917f34c, + 0x7ca0d929, 0x7c4f8377, 0xcd37a326, 0x645505ee, 0x17d8c361, 0x75bc7ea2, 0x9deeac71, 0xd91645b9, 0xc318cc89, + 0xf1fd2e89, 0xff78e1f7, 0xa65eaaff, 0xcf42563f, 0x4deee25a, 0x1db5a7d2, 0xc1874857, 0x6c71667f, 0x25e9504f, + 0x4687be7e, 0x0cef2e44, 0x1360f556, 0xf3d22e78, 0xe6c7f526, 0xa48da479, 0x924e674e, 0x2594ca18, 0xf4f71b14, + 0x384190de, 0x337357be, 0xc3e756a5, 0x31a8c4b4, 0x69f06406, 0xd0230d8f, 0x0262eaef, 0xb1e341d1, 0xf34cbe6e, + 0x51e3cf97, 0x22302f56, 0x5c402855, 0xb9ccf264, 0x89fe150e, 0xaf4a180d, 0x73b014f8, 0x2ad12277, 0xddead256, + 0x5222591d, 0x4d55fdcf, 0x588bb82f, 0xf5120b36, 0xff5611e4, 0xdd7394ff, 0xb00ca702, 0xe3fad701, 0x007494fc, + 0x69170316, 0x6561303e, 0xcece731f, 0x2e64c30c, 0x20a92c17, 0xb7175e60, 0xfd088950, 0x032364fc, 0x5c2e04b7, + 0x62836bee, 0x15971de5, 0xc9ca3285, 0xaff01b66, 0x29b545d4, 0x347ba5ff, 0xd49d78db, 0xc0e0e7db, 0xca2ff2aa, + 0x986e7492, 0xf72efa72, 0xff09fbf0, 0xc23c6e20, 0x82a98adf, 0x336700ae, 0xae9a8b2f, 0x9c6eab3c, 0x7a0ee4c5, + 0x1d85530a, 0x9ac725e1, 0x1ddc3c67, 0x1501f993, 0xd5680e1b, 0xa7d04c12, 0x50ce4bcb, 0x3bed34c2, 0x49de6e04, + 0x14182909, 0xbd4ecdf3, 0x9fe1d8c9, 0xc8ac9155, 0x85df1dfd, 0x99dede6c, 0x486681dd, 0x1f4a5e8c, 0x26b83a16, + 0xc56586eb, 0x98a1ccac, 0x3ef17203, 0x01ddb679, 0x4e839270, 0xd124a9d1, 0xaa451d43, 0x041b9d15, 0x5b27290d, + 0xda54f269, 0xa1215a30, 0x1e2ca6b8, 0xa0bcba1e, 0xd6cfae41, 0xbb526df9, 0x0590d0bf, 0xd3964375, 0xc4a2369c, + 0x8133d363, 0x8aa87418, 0x9c33d85c, 0xd1a67741, 0xc8ee3a2f, 0x142db1f6, 0xf256fe87, 0x90af111f, 0xaa6f00e1, + 0x6ed31c34, 0x78bed727, 0x13213591, 0x725ac61a, 0x5e87b476, 0x2fd42ca5, 0x3d9d56ab, 0x89f38906, 0x25ae3b87, + 0x05e23ce8, 0x66396b1f, 0xe556d498, 0x5545f8ad, 0x53ffdc02, 0x0ff83f6e, 0x569f2890, 0x59ed4730, 0x40ce540d, + 0x1d034e25, 0xc5cff6ba, 0x53c57ca4, 0x852f147e, 0x1eb0d066, 0x4444bd31, 0xd628ecf1, 0x783f8ac7, 0xf184b8a5, + 0xc6ff40ef, 0x957774e6, 0x869690d9, 0xbf2fd509, 0xef08941e, 0x1b8affa4, 0xe5e601b7, 0x9ad2631c, 0x024ee009, + 0x3d39642c, 0x5af2f307, 0x7294cbf2, 0xb52edd43, 0x7da251e7, 0x38f3d802, 0x6e34eb1b, 0xc65377b1, 0x34ee27ac, + 0xa4bb06d9, 0xef438954, 0xa7428e9c, 0x4800dc51, 0x1d3d0605, 0x396ef197, 0x86f13b6a, 0xd57a9eb2, 0xd727eaea, + 0x6eda8601, 0xcca21fd2, 0x660652ac, 0xf7a6e174, 0x92652b63, 0x266c526e, 0x9b347654, 0xcdc29fa0, 0x76c58f59, + 0x6ac138f8, 0xc2381712, 0xbc1d238d, 0xcb68ab45, 0x90cb3351, 0x7e31e4dc, 0x6fc82f28, 0x9dd20820, 0xef386d74, + 0xf8198977, 0x88435f42, 0x19a6b949, 0x32095816, 0x68dae778, 0x20222708, 0xddccce91, 0x5c313899, 0xb12afbd0, + 0xbd96ed57, 0xc805e86e, 0x530a6c63, 0xf66c69ae, 0x01320e43, 0x2d289261, 0xb46042b1, 0xaf599c5c, 0x3f57f151, + 0x865c160e, 0x4343761d, 0x2fe1fd19, 0x3eecdd24, 0x99964fb8, 0x4e616ce1, 0x52e4867a, 0xab708f94, 0x056093fd, + 0x0401379b, 0x2f7425b9, 0xf1105eb7, 0xe694ed27, 0x6439d803, 0x7a1ac331, 0x78772b64, 0x858f5e2b, 0xf09920ad, + 0x76a6e0b0, 0xe80c3afe, 0x184f3c3f, 0xc41a154f, 0x1a0a3c3b, 0x2131af83, 0xd5466964, 0xec94b5a4, 0xf22e78ac, + 0xaef145a1, 0x8f8cf760, 0x444c347d, 0xf1fd69be, 0xb989b8ef, 0x03dc32c4, 0xe41fd81c, 0x38e1e3e1, 0x97f83711, + 0xb45c0ca4, 0x094772f8, 0xf4d3b1f4, 0x7f084c1f, 0x17bf7791, 0xabe32e98, 0xaa150a89, 0x9a823f4c, 0x4d1e0692, + 0xe4fd4ebd, 0xd81c75e0, 0xcf381d95, 0x49cd133a, 0x03c3ac26, 0x1fa288f1, 0xad48b7c0, 0x0880b51e, 0x5363d6ac, + 0x5e7c5fc1, 0x2a0097ff, 0xb65034be, 0x74808654, 0x8ae0ead4, 0x9167de05, 0x911a2404, 0xde0de9ad, 0x0971ac3e, + 0x71483a95, 0x4e0dc036, 0x1be58bb8, 0xeb22fe7d, 0xcf3d57cf, 0xe3966204, 0xeecb4016, 0xb6f14bf7, 0xefdb5515, + 0x8baf99e0, 0x9de06020, 0x607e6f68, 0xf4b277b4, 0x0833d46b, 0x88e79b1f, 0xc8d1f373, 0x69f03063, 0x6e5a571a, + 0x3e1da60a, 0x270914bd, 0x09fa089e, 0xbb8c05c2, 0xc52edd76, 0x883490bf, 0x0475467d, 0x89108ded, 0xdf8821cb, + 0x8d590551, 0xff1f928e, 0xe4591464, 0xea3dd6e6, 0x70aeac73, 0x0d74a6cd, 0x9aecf7e5, 0xac9641af, 0x06a26727, + 0xbcb15829, 0x54bc23cb, 0x1426fd9f, 0x10589a76, 0x50707634, 0xf80d5a23, 0xc0f9b3ac, 0x0eed7ea6, 0xc123a490, + 0x8a846955, 0xa414ff02, 0x29cfbbba, 0xb8745ad7, 0x3a0e72a2, 0xe805792e, 0xb9510de7, 0x55a5b9ee, 0x0be51417, + 0x857a72de, 0x6d9b21e2, 0xff4a003c, 0xb628a4f7, 0x79bd7238, 0xfa208609, 0xfa6035e5, 0x77121829, 0x4ab4813c, + 0x43042928, 0xaf8f74c2, 0x503aa714, 0x6a0ff8d1, 0x23e981a5, 0xf1244f6e, 0xeca002aa, 0x25683b1f, 0xa9808af2, + 0x5866a9f1, 0x4c969900, 0xd3f4c899, 0x43b52c47, 0x550aaaa8, 0x363981a3, 0x330ec33d, 0x53274d1a, 0xfd5c9aa8, + 0xb5544487, 0xf5050380, 0xd649a5da, 0xf9cacf92, 0x65298573, 0xf61c5cac, 0xde3bf4c8, 0xe1069767, 0x9cb84688, + 0x1c024592, 0x806e9fd8, 0x6a28499d, 0x0e2a2c93, 0x108d6f82, 0xde53482b, 0x505454c7, 0x41b9158e, 0x3d97a373, + 0x83dab190, 0x2c343a8d, 0x49f2aa73, 0x505f7148, 0xd8b5729f, 0xd0f06947, 0x3ec0ed65, 0x66ad0ede, 0xfbdaadca, + 0xb527d391, 0x6b44e360, 0x652e4504, 0x70ddd648, 0xe00a8f0e, 0x2f744ab6, 0xe9abd686, 0xa1d4050a, 0x22045a85, + 0xc4cb963c, 0x74961546, 0x08e8e8e1, 0x02b0cf4b, 0xc342a790, 0x69a2a036, 0x0d81883a, 0xb4812ebf, 0xbf4973d7, + 0x37ba98ba, 0x0e079776, 0xc42073d2, 0x952aa36b, 0x6b65c37d, 0xc7ee2237, 0xaef0b927, 0xe3f34976, 0x0dbacdb8, + 0xc4b11d0a, 0x493ef3ef, 0xab7549ef, 0xd18a7c44, 0x96c23446, 0xff6d7462, 0x0bd1c6de, 0x65504cc9, 0x64d98758, + 0x3f63ad0f, 0xec079025, 0x4666c5aa, 0x7bb47849, 0x3b23c784, 0x85be1659, 0x49aed175, 0x74416725, 0xcbef456a, + 0x059cccd6, 0xde20ee76, 0x60d432e3, 0x7819a140, 0xa043b588, 0x70af5f98, 0x7b49004f, 0xe999cd2a, 0x4a5ea12a, + 0x87bafb2b, 0x8f2ddff4, 0xc9ea3a54, 0x8b65b225, 0x68256003, 0xe90fa3bd, 0x2a465120, 0x0cc22a4a, 0x39c460a6, + 0xd3d35221, 0x4887ef37, 0x1d7832c7, 0xcd3bcecb, 0xf63c8a83, 0xe95fb276, 0x15fd3a5b, 0x786054ab, 0xc0b1471a, + 0x3b0d58ec, 0xc779b155, 0x9a653b98, 0xb1732675, 0xb26b2c17, 0x94146a59, 0x221364e9, 0xc871af43, 0x046fa750, + 0x681ee94b, 0x26061354, 0x95d7a29a, 0x656d4511, 0xb1d4ceb0, 0xbb2c11ac, 0x5a0eaa8e, 0x772236e8, 0x8ffa765f, + 0xcf7263fa, 0x5036e602, 0xbe5dbced, 0x679bd136, 0x21b300e0, 0x75ac36d4, 0x36bf788c, 0x26646faa, 0x6732d9f9, + 0xe9a11583, 0x6acdeffd, 0xa9f67158, 0xa7699767, 0x596e2a1d, 0x7c33f74c, 0x03b27739, 0xc4c2a997, 0xa6bb1c92, + 0x70522e5c, 0x5e88c8b9, 0x128f19ed, 0x9b140441, 0xa9748065, 0xc4d86ac6, 0xa166dcf3, 0x3cc171f5, 0xf04e64c0, + 0x1a9aabae, 0x9c98080a, 0x0a1498c3, 0xd0e18165, 0x6424d4ff, 0x0ddc4b3e, 0x1a0ebc26, 0x4ae76bfe, 0xc0ae6f1e, + 0xfbb71f42, 0x4c223371, 0x5cf9d631, 0xb51303d5, 0x7a543f70, 0x7fce618f, 0xf1c8c1c2, 0xa58f6510, 0x7cf9e167, + 0x9e19cf73, 0xc1641ed1, 0xd71ce6e4, 0x4731ce05, 0xc25a038c, 0x9e95b28f, 0xcbe961e3, 0x4033327b, 0x31021d81, + 0x85222502, 0x84efaa1c, 0xdb17b34c, 0x5483d531, 0x72bd1afd, 0xd2a63bc5, 0x240df289, 0x16867534, 0x94e3d2f6, + 0xf0815d48, 0x9c9ba057, 0x29237b8f, 0x5dfd28e8, 0x50509d3f, 0xf7cfe958, 0xf901ee8c, 0x6d223433, 0x0310f317, + 0x6f24ac2d, 0x1ff3c253, 0x750d45ec, 0x33eacc0b, 0xf8ffc505, 0xa4956b13, 0x721a66f1, 0x9a6f907f, 0x32b9e45e, + 0x22d04ccf, 0x04cf2c7e, 0xba0df128, 0xcfe809fa, 0x3796db5b, 0x6da47f77, 0x5d38a7bf, 0x418d3006, 0x511d4144, + 0xf450ebac, 0x85ee3466, 0x752d19bd, 0xfe807bc6, 0x07b1aa9a, 0xf62bec82, 0x8dbae155, 0x975eed03, 0x710725f9, + 0x57cc62e5, 0x845e5cbd, 0xbbe0c8e1, 0x024431d1, 0x85c40832, 0xbdd5fd91, 0xa4b0b7b8, 0x0454e09c, 0x1c14ca7b, + 0xf8d6d120, 0x8da7a07e, 0x81dcf6f6, 0x8a7c153c, 0x0d6ac1c1, 0xfc7e99fe, 0x3cdfdbed, 0x30aef1c4, 0xec67fa33, + 0x49ae9c66, 0x6ce7acf3, 0x08fd247c, 0xadf002b7, 0xe11b078f, 0xc37d4364, 0xa8c6dce6, 0x4227c70d, 0x32b4966c, + 0xd8dcbeed, 0xee20d02a, 0x41c086b3, 0x885fd773, 0xe33936e7, 0xba884da1, 0xac8e40aa, 0xa90a976a, 0xb0c9bb1a, + 0x3e3ff8f8, 0x04ecdaab, 0x62d85d5d, 0x8e41525d, 0x6c89bb69, 0x3008ae1a, 0xed165f81, 0x79ed07bc, 0x04a16f47, + 0xb37f7ac7, 0xfad69ffb, 0x86531fae, 0x5dc35565, 0xa510b426, 0x22a2c718, 0x8217e2b7, 0xefa171ef, 0x9f640bff, + 0x0238486e, 0xeaf6e4f4, 0x7f5ca1cb, 0x148cf60a, 0xb898fee0, 0xf61a4624, 0xd27d3a2b, 0xac5bc443, 0x6686d69c, + 0x769096a0, 0xc4f9f8ca, 0xdb9e5d3b, 0xa065bc59, 0xa91812bf, 0xc4105a92, 0xbc47690f, 0x2f03180b, 0x1eaaf260, + 0x99b96fa4, 0x449abf92, 0xd8808676, 0xd111587b, 0xe0bc8295, 0x8a23ec1a, 0x33d1fbea, 0x6a2902a5, 0x0430a500, + 0x023e17f0, 0x201f9ab3, 0x6ef1f7c9, 0xae887985, 0x5e6b870f, 0x3c164187, 0x2840d833, 0x31869aec, 0x5bf5f4ac, + 0x0e780c06, 0x445a5c21, 0x4ba8e0ef, 0xfb6e3ae3, 0xa647243b, 0x46f8bb31, 0xa195a4ca, 0x0b666955, 0x7b260023, + 0x23bf11fd, 0x1e987707, 0x462204d7, 0xde19e464, 0x53abe24c, 0xfe66cc10, 0x11171d17, 0x7295737e, 0xb35039d5, + 0x698c1c40, 0xe057e15f, 0xfcb80637, 0x91b7ce99, 0x11eed6f8, 0xdd8d577e, 0x117b4c5a, 0x2489d44d, 0x3d748dee, + 0x6ed52cd4, 0xf74fc5e5, 0x199b291d, 0xf3fa317d, 0x52d0e56a, 0xb998df85, 0x45ac5f8e, 0x293f94e9, 0x911ba7df, + 0x5efe59b2, 0xaf4c7f99, 0xff5f3a04, 0x6af35aec, 0x0402b0a0, 0xa68874b9, 0xa5b3654d, 0x86fc81ab, 0xe59a4725, + 0x3d57acfc, 0x5597d4fd, 0xc982ee51, 0x1804cc38, 0x55bcd042, 0x8df6e282, 0xcf6c7ff2, 0x135ff893, 0xfe31b1c1, + 0x02908964, 0x56ff28f2, 0x60286bb9, 0xd7eb40bd, 0x0ceeb72a, 0xb9babba5, 0x9fbd5401, 0x9bb2ef03, 0x5247f929, + 0xc260bc18, 0xfaaed889, 0x863a6f0e, 0x37972fd1, 0x97380325, 0xe09c9782, 0xe1881782, 0x687fdf72, 0xd6323fb1, + 0x496daa8f, 0x205c2e59, 0x40c9634e, 0xf244bcc4, 0x94d8fa52, 0xb5540376, 0xba03e671, 0xb3142798, 0xdbf9751d, + 0x9c734242, 0x3790ade6, 0xb33dc21d, 0x50dd7e98, 0x55fd9904, 0x0bf5666c, 0xd431e5ed, 0xf13aec96, 0x0b95c9da, + 0x94ed5352, 0x12312bbd, 0xdf023231, 0x33e5bedb, 0x45e08796, 0xc4617747, 0xbd2e0837, 0xcb5cd5d4, 0x89ef2c4d, + 0xadea5ef0, 0xb0b561cf, 0xc25eeb4e, 0xa3b7d5f7, 0x6a854971, 0x4a691dba, 0x93b76ae7, 0x6e9da636, 0x79e39ee3, + 0x8b953a5e, 0x8d792670, 0xed1a948f, 0x10416088, 0x00d85ece, 0x5c8d875a, 0xfa12714f, 0x69f7be4a, 0xebc5cc9f, + 0x02f009b9, 0x156cf526, 0x73f6dc3d, 0x81fbe0bc, 0xbfb8c90f, 0x760a9247, 0x889d9491, 0x7ad21e03, 0xfbc3d05d, + 0xa8677c04, 0xf17c8209, 0xe0457acd, 0x8af0e090, 0x6852c633, 0xf5e0ca9c, 0x85375058, 0x68a1bd74, 0x23e3cd73, + 0x48682918, 0x5534445c, 0xe8ead7b4, 0xb2c1d988, 0x4c370dd9, 0x623e403d, 0x23be998b, 0x362d4e8d, 0x229c8a70, + 0x7d6e8223, 0xe7d39392, 0x7b8b63c1, 0xd829a78b, 0x959e66ab, 0x92043a43, 0xa6f75686, 0x8ebe98af, 0x1494bea5, + 0x8ed02653, 0x77b23d8b, 0x6731f53d, 0x0674771b, 0xc08b4c9b, 0xa44d763f, 0xb5297227, 0xec22c112, 0xc61e05b5, + 0x89d7a090, 0x50d2563c, 0xd249c1e7, 0x2c198ef6, 0xf94a30ea, 0x38be0a3e, 0x711f7998, 0x80105f30, 0xcd788a1c, + 0xbf40553c, 0x985514e2, 0x9f8e8abb, 0xe91f7516, 0x51d17bb9, 0x1af7a241, 0xed37c710, 0x52b85c02, 0xbc133a31, + 0x2feb727e, 0xd3a84ac8, 0x54971d40, 0xa0120025, 0x6b284ea5, 0xd0a4992b, 0xf82eb826, 0x09aeeed1, 0xc389bc87, + 0x310d0896, 0x1fee7653, 0x8dd71ee4, 0x0d9ff95e, 0x297fd63b, 0xc995c896, 0x061e4dae, 0xd16e9d2c, 0xbda7f694, + 0xbf3e232c, 0x5a5a56e0, 0xabf06838, 0x5761424a, 0x128a2aab, 0xd715c29e, 0x8f016fd1, 0xf264bfea, 0x785f162b, + 0x10284d23, 0x7d3a9d76, 0xfea11217, 0x76501260, 0x95660d4a, 0x2ecf4124, 0xcf4315f3, 0xb6fcae1f, 0x7b877028, + 0x1f581e76, 0xc4270c62, 0x21e141a7, 0x76eec994, 0x41eadb96, 0x454f964d, 0x094d6e76, 0xa1fea1a7, 0x38c1f1b2, + 0xc260b08b, 0xe114a8bd, 0xd80ab6ce, 0xbc1076b0, 0x5fff9455, 0xe0bc0e03, 0xf030a9b4, 0x583149a5, 0x3411b754, + 0xaa11d235, 0x72e47965, 0x8c92503d, 0x4c2f1fa3, 0xd54ec8d2, 0x83d9e698, 0xffc0972f, 0xf32173c4, 0x2522ea3d, + 0xad3a7161, 0x1f953080, 0x886b7538, 0xfac62f41, 0x65134297, 0x0b4d7b4f, 0xf6d8c4e1, 0xe6f1e4d8, 0x3fe7d27d, + 0x7b6b70d0, 0x40a87ff9, 0xc89e0c6f, 0x2b1357b9, 0xce9a59aa, 0x155cb70c, 0x84176c83, 0x61071d11, 0x7a7154e0, + 0x32f72a5d, 0x0546bba9, 0x035867fd, 0xe95d8c53, 0x34b756f1, 0x6b9c978f, 0xe6852f39, 0x6024b0cf, 0x3504cdb2, + 0xb4dd0369, 0x485e7c53, 0xafe97447, 0x6bf41ccb, 0x3a23ca7c, 0x5554c4ef, 0xb2366933, 0x2ee417c7, 0x98e873ad, + 0x011a2faa, 0x1f935f18, 0x2f82f490, 0x0d1198a1, 0xf30f6f6a, 0xb1f218b2, 0xb3463dd8, 0x31e4303c, 0x45d72a49, + 0x19764b82, 0x7108f58b, 0x1fd5934d, 0xd4205e7d, 0x7eeaa5d2, 0x0f92e658, 0x15432cd1, 0x97f9912f, 0xea1b76da, + 0xce102461, 0xefaade3d, 0x93a0dad3, 0x6ad03b0d, 0x6767470b, 0xbb6faaf5, 0x0d85da5c, 0x645e736a, 0xec064558, + 0x9d475734, 0xf459500c, 0xcc4e019f, 0x12366bcc, 0x6640579a, 0xff854272, 0x70371603, 0x76f9ba54, 0xed8e53ef, + 0x24ec5110, 0xb739d5a1, 0x316d87d4, 0x9ceb9326, 0x57976738, 0x3b188c27, 0x784ac705, 0xa14dcb21, 0xf63c757c, + 0x3266f4cc, 0x10579951, 0xeef65b98, 0xb11cb927, 0x874306ac, 0x0c0c5c3f, 0x118501bc, 0x07933a44, 0x576a5d79, + 0xe1408109, 0xbac15624, 0xd8cb6db3, 0x474b921d, 0x81a724be, 0x9f01b847, 0x4761f9c3, 0x2d1f18cb, 0x94959eda, + 0xf7f5bb50, 0x3894fb3f, 0x4ccd3001, 0x583b0a33, 0x69c9a0b0, 0xe1051bee, 0xf5c252e9, 0xfdf4e363, 0x882bc64b, + 0xdc74a2a6, 0x29ff41da, 0xe10a9ca0, 0xcf460589, 0xb696b0c0, 0x7fe77514, 0x44ee77d6, 0x5a2ad4ac, 0x97508f0f, + 0x6bccf2bb, 0x26ab61da, 0x7499d114, 0xa8ee9219, 0x345f9e88, 0x72d7c1b1, 0x8b379e59, 0x4bc8e6de, 0x9a62d4d5, + 0xf1f0b854, 0x9e48956f, 0x3afa8883, 0x8cd0dc31, 0x1fbc5b37, 0x3f9969df, 0x688c0a9c, 0x2247f547, 0xb4a4462a, + 0x2febf78d, 0xb1697d31, 0xa0122573, 0x998830b8, 0xee29e2fd, 0xc3e3b502, 0xa21ce506, 0x4556b5d1, 0x826fd6b2, + 0x6e63b1b1, 0x3df7385a, 0xf3c340f5, 0x5eec5fc3, 0x67ca5a58, 0x7a9fc258, 0x1045c54c, 0xc13fc862, 0x6bdc4c30, + 0xeb1b2169, 0x5d8afac2, 0x99260829, 0x9de44ecd, 0x38181bc2, 0xdd66165e, 0xf14cc8a6, 0x7ba20689, 0x36852cf9, + 0xc552d717, 0x8cf338ae, 0x231ec360, 0xf00becc5, 0xef220c3c, 0xb84ec768, 0xd30a5afa, 0xb0b35547, 0x751f988e, + 0x42ec9fc2, 0x2be96886, 0x4843670f, 0x10e1c28c, 0x7a17c990, 0xbff86538, 0x170957ff, 0x9d95422c, 0x56b4a7bc, + 0x1ade97bc, 0x4ff0a978, 0xda71468f, 0xdb1f0e8e, 0xb361d3dc, 0x6d14b648, 0xa095ba3e, 0x5e8f0b5e, 0x6f3b16e8, + 0x66874a27, 0x3e0fc52f, 0x99d94ace, 0xced93c93, 0xdea72ff1, 0x9969925c, 0x7bf05511, 0xb511a26b, 0xa03ca33d, + 0x27d40bc6, 0x404841a5, 0x9634f226, 0x4ce0626a, 0x1054f784, 0x7b808b0a, 0x25b4ec37, 0x0668549e, 0xf66101aa, + 0xfdcc8eb0, 0xb2c40643, 0x7008a038, 0x918e4e8c, 0x459748d2, 0x41f9381f, 0x3c0b94f4, 0xf557d27c, 0xffecc2dd, + 0x563cbf6e, 0xb466c04c, 0x6344fddb, 0x70f441b8, 0x075f27b2, 0x030cb137, 0xca3f2e01, 0xf10752ca, 0x46536c76, + 0x820084e4, 0xac003132, 0x1d6345d3, 0x46a4c9c2, 0xc104dd35, 0x48ff6961, 0x0fb9dc72, 0x50b3c4d9, 0xd9857106, + 0x5325269c, 0x784476d5, 0x62dd66da, 0xa835dc40, 0x5f04dbbb, 0xabff62d7, 0x9571a533, 0xf4528408, 0x0af29dca, + 0x00a1385d, 0x5fd68d62, 0x8afeaec9, 0x6dbf1f96, 0x80271ddf, 0x24d5b0b3, 0x25cea925, 0xd54ed503, 0x9c956099, + 0xcac91c3c, 0x2e50dc9c, 0x64cbf8d3, 0x5c0b423d, 0xbf32dfb2, 0xa58958c7, 0xed3b9066, 0xc3152711, 0xd67b16a8, + 0x507910d5, 0xb250f832, 0x9de2817c, 0xa6d0d405, 0x86bea90f, 0xfb1c2bbc, 0xd413de1d, 0x1202ea72, 0x7170db2e, + 0x558afb9c, 0xfe948ac5, 0x257a5bce, 0xf06d86d7, 0xd0726abc, 0xe0443aa0, 0x0336d144, 0x80db1b62, 0x88698e9e, + 0x47cbb408, 0xb067cd2e, 0x83186865, 0x08879a61, 0x14314d00, 0xb4097be7, 0x380e9136, 0xf28afc90, 0x8e745478, + 0x7cbc0af5, 0x82437c00, 0x55337aa8, 0x9de1598d, 0xc5a4c58f, 0x9a790ca2, 0xe05538f7, 0xc795e79c, 0x2246260f, + 0x839ba5d4, 0x4302612e, 0xc1cc6da7, 0x86b4bc77, 0x17ad07c9, 0x1a75802c, 0xca422a07, 0xf3d475a4, 0xc35974dd, + 0x00ae573b, 0x1e65d4b3, 0xcc3ae175, 0x0f61e33f, 0xd278591f, 0x2fd71f67, 0x46a1134e, 0x12e892b2, 0x5b0fd422, + 0x42b6f46d, 0xa940886b, 0x97ad1081, 0x1e2ecc91, 0xe5fd3bfe, 0xe6f89c7e, 0x50c85b25, 0x1601bddc, 0xf10de694, + 0xa169bf15, 0x7abab534, 0x5cb51296, 0xeda3b615, 0xe6d97c17, 0x31b4554a, 0xfe80bbc2, 0x17b5c288, 0xfd5fd480, + 0x711c9caa, 0xd4442297, 0xcf8fe9f4, 0x02aa817e, 0x825cafff, 0xfe81ea2e, 0x4f6f4ad1, 0x702fe876, 0xe7b85f02, + 0x3c303d6f, 0x59c4caa5, 0x0bf1fe0c, 0x672025f1, 0xc1703049, 0x5eff1e3e, 0x7f7610b6, 0xc0372568, 0x50da9386, + 0x06b2d396, 0xc61d7a4b, 0x2165c191, 0xab8dc9a8, 0x7a674ba2, 0x680ae2d4, 0x5375ee64, 0x859400a7, 0x61fb7a0d, + 0xc585872d, 0xd856e1a6, 0x66a95f69, 0x733f03ed, 0x5a5e2798, 0x0a94fafc, 0x0a891f30, 0x33649755, 0xe0aa6a67, + 0x77e84196, 0xfca305cf, 0xb469f0e9, 0xbd30f3ef, 0x61f9e902, 0x511e3909, 0x781377cd, 0x93ae40c4, 0x03560ee9, + 0x1da50ce7, 0x89055279, 0xccbae9ad, 0x6a5e2a9d, 0x0d8a41a2, 0x0ce8a0f3, 0x89d9c0b6, 0x55fcc4ff, 0x6952c4c4, + 0x6a72c3ce, 0x2e3a0930, 0x07092094, 0x1d0f9214, 0x6ac1bdb6, 0x19acab12, 0x3b81e928, 0xafd3fe8e, 0xcfb1bbca, + 0x9c6b48d4, 0x9d2c6bc9, 0x23315a90, 0x17dfccd5, 0x0862224c, 0x68f8af6e, 0x5663cd1d, 0x296cb56f, 0xf66ea201, + 0xf1c9eea6, 0xc04e66d4, 0xd01b85e3, 0x087d84b1, 0xffafb1d9, 0xa163fa2d, 0x4639dbc3, 0xf13f4ee5, 0x69be26e0, + 0x8791b935, 0xfee963fb, 0xdfb5c7b5, 0x7e03b7e0, 0x7e83ed1c, 0x56e58a6f, 0x95dbfec5, 0xbbe114c0, 0x04718511, + 0x6c717b16, 0x16b8d394, 0x8e7ba6e5, 0xd475cc83, 0xb9e77b05, 0x9e49b039, 0x30c54a78, 0x1d6cc051, 0x80cd3ad0, + 0x89c0e36a, 0xe2802a73, 0x6a4eddfb, 0x02d452ca, 0xf8b6c23a, 0x3c547a96, 0x99c715f7, 0x6ffce80d, 0x8d24a1b6, + 0xdd09cc35, 0x9650c582, 0x766ce9a1, 0x0f404d46, 0x357ecfdc, 0xc68ed7b6, 0x0c818b52, 0xf15f494b, 0x1110f060, + 0x949e0809, 0x05566f3d, 0x20a5018a, 0xda4c5d80, 0x417c6e94, 0x40c497a1, 0x1430ff89, 0xd79b75dc, 0x667f2f14, + 0x9e10971b, 0xb03c5f80, 0x8187ba3a, 0x3732296e, 0xa7230f3d, 0xe53c9834, 0x0b99c926, 0x7ac3e2a6, 0xc790bebc, + 0x32d259b8, 0x56dc0297, 0xf77fdf0c, 0x4aad0ca8, 0xf6f2a1de, 0x2f650179, 0x4be52c74, 0xe9c5197d, 0xb65ef10c, + 0x7c665491, 0xb2ef5567, 0xcf569026, 0x0afe9399, 0x6eeab22c, 0xe1fc03f7, 0x88abe00d, 0x49197150, 0x92f14332, + 0x93c3a91d, 0x031270e3, 0xea3b9075, 0x8a58919a, 0x428fe03a, 0xf84d368b, 0xbb4f8b24, 0x46e67764, 0xaaffc78a, + 0xdea9c95a, 0xa38d8c41, 0xf9b74830, 0x9db0d13b, 0xb8fe6144, 0x4e522263, 0x273c89f7, 0x483b5d90, 0x4aff93e2, + 0x0f4bfa9f, 0xf1023ec5, 0x8b64af7f, 0x982b8296, 0xaa9f296f, 0x2ec492fe, 0x225b8c48, 0x53e7b4e5, 0xddd16e4d, + 0xf396399b, 0x7d9278a0, 0x143fb5c5, 0x22c5dc19, 0x970e1b1c, 0xdb5b7335, 0xd3bf1c8a, 0x9d62af74, 0xeaf5f099, + 0x53ce0fd3, 0x6d25bd8b, 0xb3561134, 0x6138e746, 0xc8bcb524, 0x2acaf10e, 0xf609a1c9, 0x0ecf2eeb, 0x339ecedc, + 0x55e4acde, 0xed9d1ca4, 0x5d286723, 0x12225da3, 0xc32487b0, 0xd99246ef, 0xcb1ca928, 0x31ed151a, 0xbe900f72, + 0x49824d44, 0x48b36775, 0x055308ac, 0x778647b4, 0x1cc11504, 0x608623d1, 0xa61becfe, 0xf9cdb8b6, 0x0c81b28b, + 0x3d289f96, 0xf823fe92, 0x12f926a4, 0xfa8525d1, 0x5ffe98f9, 0x7d640e0c, 0x8667002e, 0xcd91d347, 0x31f96ce4, + 0x2a6a6254, 0x710344a8, 0xb6674b03, 0x5b1e3eea, 0x1bde50bb, 0xa863833e, 0x323f0055, 0x9c651a89, 0xcd7a6d1f, + 0x4b302ba7, 0xa5a32291, 0xccaa019a, 0xf4c0c625, 0xcb85e523, 0x7216518d, 0x52f3dce5, 0xb7f63e20, 0x5f212f0d, + 0x6b91d53b, 0x850584c0, 0x1f41adeb, 0x7dba5b5b, 0xd58dc0fc, 0x0ea2b1d9, 0x7d11db80, 0xc126f36f, 0x352fd4c3, + 0x091a1295, 0xf46a77a5, 0xf07e5976, 0xcd73575b, 0xff7615d8, 0xd2ba4d77, 0x00290436, 0xce7d5b3a, 0xf7916a9e, + 0x7805f1b7, 0x727b31c3, 0x82b387ff, 0xe19dce41, 0x40938fd3, 0x4290e18b, 0x27e52b6b, 0x7b17319a, 0x4f162c26, + 0x6c96d532, 0xda30757a, 0xb0794df7, 0xee8a3d24, 0xa4158776, 0x13a31460, 0x02ca5f9d, 0x79b35bd1, 0xf9a9dd8f, + 0xda35066c, 0xb18baea9, 0xd549baa3, 0x083ae166, 0x823398c4, 0x0f9212e8, 0xe9b5ad13, 0x0ae42ed0, 0x1f123d74, + 0xc238d30e, 0x663e616c, 0x069b1124, 0x834a3804, 0xd9a02969, 0x21a6780a, 0x0549c25c, 0x0dd13b46, 0xb51566ee, + 0x26c0a172, 0x4f91c35c, 0xf0d6d2c0, 0x2a02058a, 0x00316f15, 0xb7e9e9be, 0x20719089, 0x2b9bc545, 0xbecb1013, + 0x37ad1cd5, 0x616267c8, 0x5a0b2fc4, 0x7c2f2b54, 0xa7093c5a, 0xfdb81a11, 0x0f3cf0e9, 0x99389aa2, 0x35a9884d, + 0x874f36fc, 0xf1796204, 0x19a04760, 0x54adf2c4, 0xae77d9d0, 0xee15bd05, 0xfae1de0f, 0x49919bce, 0x957dc7f9, + 0xd1a97915, 0xfbfc396b, 0x42a47a80, 0x94f71066, 0xeb2a31fb, 0x93289e92, 0xe16b3154, 0xc710eee6, 0x695c893a, + 0x673c7a84, 0x61dbf869, 0xa5e2f73c, 0xf73fd6e3, 0xab8a6dd4, 0xc7505bd8, 0x644d555b, 0x7b721a36, 0xba3be922, + 0x18509aa4, 0x84ee00ee, 0x7d873316, 0x588d75b6, 0xbf3061fe, 0x6aff5d0d, 0xe547f726, 0x026b00a2, 0xe53e82fc, + 0x6043ae6a, 0xaeb61ec1, 0x73436f92, 0xaf7ffea5, 0x489000f6, 0xa3b1a80c, 0xcf796373, 0x49e0b619, 0x2920efb0, + 0x6b8d8694, 0xec383012, 0xbe0df060, 0xf8a315c9, 0xe3aa02a7, 0x52c6f8fa, 0xad347c8f, 0xe151b159, 0xf6df7ac4, + 0xf0e48347, 0x3fc9e8f8, 0x39ff5470, 0x2ff5d59e, 0x7636144b, 0xcd9725d8, 0xe381f99a, 0x2c830446, 0x10ba3fff, + 0x58a9ec6d, 0xb594d0a1, 0xe6628772, 0x0be01112, 0xfedc598c, 0x7828a16d, 0x4a15c51b, 0x076f1dc2, 0x679d9812, + 0xd20bbd52, 0x53276ea3, 0x734984d8, 0x788c8663, 0xfed2bb70, 0x9781f8a6, 0x131666d6, 0x5739fa6c, 0xb12680b8, + 0x8f804678, 0x5167630a, 0xf06d982a, 0x9c6e6aa5, 0xaccc5205, 0xeb1b344b, 0x545eec81, 0x01a346d7, 0x7a410036, + 0x400224f7, 0x43c66170, 0x38501cf7, 0x3dff7433, 0x6ac49196, 0x2513771f, 0xd21e61c0, 0x992ea424, 0xcbefba54, + 0x72448fe8, 0x95cb7a64, 0xb275eb30, 0x6fa266f2, 0x2f34e813, 0x073755ef, 0x18df3fe2, 0x221481d0, 0xefdaedf7, + 0xf305de07, 0x1d34d01c, 0x9a498886, 0x20038c55, 0xbb9911a8, 0x48edf0a3, 0x8a431c72, 0x9744d6a4, 0xa1ef46f6, + 0x246ccba0, 0x141d2b69, 0xc61e0b1f, 0x15e022b0, 0x3d0e8a05, 0xea4bb6dc, 0xadf8f02e, 0xc8b6e210, 0xb4305969, + 0x878ed80d, 0x212a5f50, 0x6c6652f8, 0x85bb0cb4, 0x4b174794, 0xf8879ca0, 0x0158da1b, 0x0325d648, 0xe0f91eaf, + 0x43e93196, 0x62642c27, 0x646186b4, 0x7be3f811, 0x303fca40, 0xea3964ec, 0xa61ba1df, 0x665348c9, 0x07402312, + 0x7d56082b, 0xa929fc98, 0x5ca9087f, 0x64760f48, 0x73336d90, 0xdfb2e0e6, 0x1d45505d, 0xd44ce952, 0x7a1570c7, + 0x7c43990b, 0x2a59fed6, 0x2dfdaf5b, 0xabb354a2, 0x485eaf7a, 0xb7a4b478, 0xd964863a, 0x97809ea1, 0xf5c750e3, + 0x755c40c6, 0xf5b8ebeb, 0xde1b36bf, 0xaa0ec6bc, 0x854a755e, 0xaf793841, 0x6cd11993, 0x821f2852, 0xdb04dc7c, + 0x523cf6b6, 0x85ffac44, 0x0bf773f4, 0xdbbbeb80, 0x50bf208d, 0x7fa096a2, 0xf8b7e022, 0x08a62fd6, 0x14beb7ff, + 0xc049852c, 0x516d43bb, 0xc20ef3e5, 0x9d87033a, 0x266677f5, 0x07e29389, 0xcdcda503, 0x83ab0165, 0x4f66f519, + 0x1fdd8621, 0x585a0017, 0xd90c6eec, 0x308dd7e3, 0xba272a8c, 0x0a60a9de, 0xb98b468e, 0x461509a9, 0xf9466b3e, + 0x5c631694, 0x4e57ead9, 0xc0a37e0c, 0xc27b73d2, 0x6c2c51df, 0xb18e9136, 0x234a193c, 0xc91ea532, 0xa16a8843, + 0x08a4bf8d, 0xa6361689, 0x4b5df67d, 0x83c9ea86, 0x6a3d3674, 0x2c7d079d, 0xeff77784, 0x4790cedf, 0x0e9da18c, + 0x3bbc7f86, 0x1900c4cf, 0x5603cd98, 0x95eb0b87, 0xb0cba001, 0xe252316a, 0xf9f0907b, 0xad1f5dd4, 0x5c30ec02, + 0xbaf8aeda, 0x7e8eb590, 0x6946a08d, 0xdaca5b0e, 0x7249b360, 0x30cdbdc7, 0xee106ae1, 0x9830512c, 0x29336fa4, + 0xa86ad650, 0x7a6670e9, 0x2033a5dc, 0x73ded088, 0x99a6af14, 0xe3564734, 0x85a938ed, 0x8e428efa, 0x05bc3e5d, + 0x4369955a, 0xd6586436, 0xc2ab6e99, 0xdcd0c2fc, 0x4e97d70c, 0xe7b6e3ff, 0x247337a0, 0x7e2effdb, 0xba632256, + 0x00efa979, 0x3b681a95, 0x338da6a5, 0xdae07b9d, 0xf359324b, 0xdecab6bb, 0x0ac6b019, 0x48f24ae1, 0xd6be3db3, + 0x95c9be62, 0x44feeb24, 0x449617b9, 0x42e5da0b, 0x398e882d, 0xce4a2c0a, 0x7ccbaeed, 0xc90b899a, 0x29d5fa88, + 0x6fc74d0d, 0x0cd2fc2e, 0x0f9dfbda, 0xcfc09eb4, 0x6c47e62e, 0xb6c19b84, 0x00619968, 0x0fe06ba1, 0x497cf86d, + 0x163163f6, 0xfd9b243f, 0xa53b0578, 0xe873165e, 0x8e77e42d, 0xf2fef488, 0x0f8320ad, 0x9fe9d74e, 0x5a4bfbc9, + 0x345046b5, 0xcac71ac7, 0xd66a278b, 0x7aa5d7b7, 0x14462ec5, 0xfc055206, 0xf97d3e0d, 0x9208570c, 0x0aa89e63, + 0x693ad3a8, 0xcb1e0a54, 0x177cb218, 0x3959a37b, 0x688b1b1f, 0xec3f0d81, 0x6862ee88, 0xaafbc6ad, 0x9bc6fe0a, + 0xaf127bfc, 0xc18fd0d7, 0x4d8e3e76, 0x79d4da11, 0x55702f98, 0xdb166cfc, 0xca4c01b6, 0xf3ead533, 0xc66c5215, + 0xfb29a326, 0x96b81d81, 0x02bdc8d1, 0xe27b0ca6, 0xcc69b4a8, 0xa2ab78fb, 0xa41077fd, 0x2456b8d4, 0x7eb0ab56, + 0x612bc5ad, 0x5a434bfc, 0xcc845fa7, 0xef1c52b9, 0xd0782e43, 0x1c9ca1ca, 0xe7c5a377, 0x7d7bdc98, 0xc0f823d3, + 0x065bb9cd, 0x62a2276e, 0x18d6a144, 0x826e339b, 0x7eae0aea, 0x09df8fa6, 0xb18327bd, 0xeb9ef943, 0xf5e9e0b0, + 0xaaf2709c, 0x09a6bb24, 0xf3e2a73b, 0xb29473a2, 0xb45227dd, 0x2203f005, 0x16ecb15f, 0x1fbae7cc, 0x857a3ea8, + 0x8a49f0f0, 0x2f3bdb5f, 0x161176e5, 0x846ab989, 0x9689f58e, 0xa18ccbd6, 0x2ebbb8ce, 0xe6b7cebc, 0x5820a9b2, + 0xa4cb9fc1, 0xc43d2519, 0x785a8f8b, 0x4aa81465, 0xb6ca50d6, 0xac641f94, 0x6dd74769, 0x5bae0cab, 0x74772a9d, + 0x99d85d1c, 0xc35b9ded, 0x5d43a8f0, 0x4222a9ad, 0x1d3d8fbb, 0xbe2b68c9, 0xd748b16a, 0xf4dfa1dd, 0x418b765b, + 0xa2459b83, 0x972fd668, 0x3b989a27, 0x49c2e842, 0xc4af1f60, 0xe37217f9, 0x77e0edfe, 0x821014f5, 0xb6406024, + 0x075947fa, 0x654c51d6, 0x1992729d, 0xca7eb6cb, 0x47f25b77, 0x42a22fe6, 0x72926b8b, 0xd8da43d5, 0x97eff7d6, + 0xbedbd675, 0x2dba13e9, 0x1358f55e, 0x73b71ddb, 0xd55baa10, 0x97d979ae, 0x5299f6e8, 0xfc8d55d1, 0x140c5a74, + 0x982d4695, 0x30fb6c54, 0x2fc65d88, 0x60d08948, 0x7eff9798, 0xefb26376, 0xb32ba6bb, 0xc0a25f37, 0x6809b85b, + 0x6daeb3ee, 0x071f1cc7, 0xcefc539a, 0x7963c700, 0x638f15db, 0xcc5b113e, 0x20d812ba, 0x51fda166, 0x60504c11, + 0xf245be5d, 0x3ead7321, 0x8ceefc1b, 0x7b8b919d, 0x7cdcbf7c, 0xb8d0b043, 0x94a5b4db, 0x080bbd44, 0x3c42fa8d, + 0xadfa28ec, 0xb5bcf273, 0x5b5df96d, 0xfe4168c8, 0x54c10c0b, 0x82adf52d, 0x48e5ce08, 0xbbd86879, 0x45d71dba, + 0x03863912, 0xdfd42f23, 0xcf3bad46, 0x2e55d987, 0x33b8c10d, 0x13a3f9bc, 0x22c7a467, 0x541d2a21, 0xd23df1b9, + 0x462ffb40, 0x6a02bf7a, 0xae40662c, 0xfb6b8ae7, 0x24986cc8, 0x4a72ea96, 0xf8360ecb, 0x82908cf4, 0xe2c4c1e8, + 0x3f99efcf, 0xe0fb9ff6, 0xcffc4b2f, 0x475946e1, 0xd63874ab, 0xd1923982, 0x4b6745c1, 0x2b0d1894, 0x05ead834, + 0xbe4f65d5, 0x45c11aad, 0x92a941d7, 0x9fb44efb, 0x90aef464, 0x38f3e2d3, 0x88fcd2b4, 0xfdbf26e8, 0x868290f6, + 0x52c90123, 0x0b425873, 0x0b29525a, 0xf2f5711a, 0x06418183, 0x98bcce34, 0x8286dc8e, 0x67c090ee, 0x2ad16b52, + 0xd17ee591, 0x981151fb, 0x063c9078, 0x8e234bb8, 0x6d6bdbb8, 0x85386bc7, 0x67636ab1, 0x28618c62, 0x445d1bde, + 0x21005d47, 0xba4989df, 0x4884a668, 0x5444e0c7, 0x28c45c86, 0x82893d16, 0xdc72435d, 0x8caae7d2, 0x5c1ecd56, + 0x14f67d82, 0x111b8fa7, 0x8af6fad7, 0x5ecf8906, 0xc4e7e7c4, 0x92013fcf, 0x3da09eca, 0x4fbfa115, 0x8e823d87, + 0xb8caa4a5, 0xc5ab9542, 0x8ce3beb2, 0xafa4754f, 0x728398a0, 0xcacda3cb, 0x0b4a4088, 0x111e87b3, 0x4c34b8c9, + 0x03638eae, 0xbf4bfe29, 0x9a53be39, 0x5af9fe73, 0x7a664f2c, 0x5acca613, 0xb999795f, 0xc8ba7eba, 0x8330fe99, + 0x81c6285d, 0x7fda7ecc, 0x4ab1202b, 0x912fdb9f, 0x0f73013f, 0x6ed037f2, 0x824e25b7, 0x4d889632, 0x64de83d2, + 0x3862aafa, 0x0d3ff8db, 0x8bc7dc4e, 0x6a9b882d, 0x8a138338, 0x4e0d74a5, 0x6a3672ed, 0x86cd9a30, 0xf8ea841e, + 0x99856d07, 0x4f037e8b, 0x8891516d, 0x8647b141, 0xc450e2e9, 0x3c944211, 0x76d1fedc, 0x0f75d185, 0x48789477, + 0xbd8b0b98, 0xeb874e84, 0x30973371, 0x84598902, 0x052b4ed3, 0x786c8908, 0xafa7eb5e, 0xafb2065d, 0x270782e9, + 0x1bb7d261, 0x6bf22734, 0xa101547e, 0xbd34fa15, 0x8608200c, 0x73409e65, 0x32254c2c, 0xf648ae32, 0xde3138ef, + 0x3d6f6e87, 0x86c2a1aa, 0xb9a88c8a, 0x3dd3028e, 0x3e713c61, 0xb42e48c1, 0x02a706c0, 0x15559e88, 0xfc4f232a, + 0x15070af0, 0x639a3486, 0xc2fe2822, 0xdbdc68b6, 0x2d5a9457, 0x367a77c0, 0x0d22a626, 0x9ff0f38a, 0x48ff29e0, + 0x94ad8833, 0x6dad4af6, 0xd6817c77, 0x506f1426, 0x97599f37, 0x67653cdf, 0xbec1acf5, 0x9eb7f5ee, 0x75e0eeb5, + 0x9402f638, 0x100f68b4, 0x8fe5c4ee, 0x26a89f1a, 0x079c811e, 0x65ba287f, 0xcdc7e98b, 0x5238c175, 0xdb7c0e1a, + 0xeb44ba39, 0xf02e4096, 0xdc20a17d, 0xf6fd4da8, 0xcf89c200, 0xab8ef4f9, 0xecf3caf4, 0x1c1a48ea, 0x237167a1, + 0x1e179e61, 0x39220d5a, 0xc858b845, 0x6e3910ae, 0xf37d8e6d, 0xc9f3d80d, 0xfd426b70, 0x93bd9747, 0xf7674b99, + 0x1485084f, 0xab3ce65c, 0x6f30e1e2, 0x872aa2c7, 0xbd6bff39, 0xa6e833b2, 0xda1f99d0, 0xdc553a7c, 0xf43da100, + 0x447faec3, 0xc3ce683d, 0x22ff1d2d, 0x5cd729fc, 0x4a543280, 0x2d32cfbf, 0xfe09d8d6, 0x43ca2ed8, 0xb8fdd631, + 0x7f2e82c2, 0xda86fa83, 0x66c66241, 0x79c36d66, 0xff393e25, 0x6c71f120, 0xd559ec1b, 0xb6160ce1, 0x13d29787, + 0xd9249149, 0x0cba5df7, 0x4d113e99, 0x8fecd8ee, 0x2d475b2f, 0x71e0cb1f, 0xedcce1ec, 0x579e2684, 0x8a6f80fa, + 0x97ed057a, 0xad83ea26, 0xa01c33fc, 0x43659bf5, 0xd0602da2, 0x9b7967ef, 0xcdb4fba4, 0xa2ae4796, 0x43899469, + 0x5091d603, 0x9d1a9e42, 0x55fc93de, 0x97a54bd1, 0x65f4e352, 0xf23dc59e, 0xdf851511, 0x0fb014e5, 0xb8705e59, + 0x0417a38a, 0x5038393e, 0x228ccad9, 0xff974fac, 0x24f531e1, 0xf038d8dd, 0xac41c13b, 0xb9a2ec06, 0xa10efc29, + 0x7e42c2a5, 0x9c2970d0, 0x72850e5a, 0xa94ce2d1, 0x31ac3f59, 0x3ef703e0, 0xf4aff306, 0x90819d0f, 0x2284b8ca, + 0x1eb311b6, 0x6cdbf433, 0xab10881a, 0xe08e966f, 0x00d997ee, 0x866ba7e4, 0xd6a96892, 0xd99a9a88, 0x0a152892, + 0x0a2dd419, 0xcfbf7197, 0x2e091587, 0x72f85470, 0xa1c7e8ee, 0xb5af8c93, 0x28d46ba6, 0x60dab53c, 0x35a192e3, + 0x5692810b, 0x12991c33, 0xcfc156be, 0x514eba00, 0x5964e138, 0x6e682a4d, 0xfcf8b85c, 0x7a600128, 0x0250746e, + 0x7dbe99d1, 0x9a0832c3, 0x6f158360, 0x950565e5, 0x034e3a68, 0x6735c843, 0x1199b296, 0xd58367b6, 0xe9a9968e, + 0x1dc87de6, 0x03b5d611, 0x95a0f6e9, 0x36c35485, 0x317107c7, 0x8a6e246c, 0x1b5b7913, 0x50e3182c, 0xcc7b4fbd, + 0x45975501, 0xfdcc1740, 0x79021aee, 0x032c77d4, 0x2d020c5d, 0x5dd8a8bc, 0x1031c3cc, 0x2a395bec, 0x301050d7, + 0xa0407565, 0x75976695, 0xfd996d79, 0x51bd920b, 0x1d1f1548, 0x1abeeb28, 0xc4f48ea1, 0xf161cf01, 0xd2e5812e, + 0xda29caf1, 0x842f36cc, 0x86e02960, 0x741b7df3, 0x53460c37, 0xf2df7b65, 0xf3e30f03, 0x6a495a0d, 0xdd1e3327, + 0x7dc39e2a, 0x88763fc9, 0x6b9d09fd, 0x4092cc01, 0x532d520a, 0x81075f01, 0x157c83ee, 0x7546912f, 0x77e9734c, + 0x755e8849, 0xaf190fc0, 0xa2307398, 0x080bd622, 0x3b1b6730, 0x6f42b9b5, 0x113c4153, 0xf68a6b58, 0x99d642bf, + 0x2de8460e, 0xe8f9f667, 0xd77fbaae, 0xa3ddd729, 0x08f8fe18, 0xca46daee, 0x009bd2ac, 0x641d3b44, 0xdf95558f, + 0xae3844b4, 0x7a3ac2d2, 0x9af0c819, 0x7815afbf, 0x625649b9, 0x15d76438, 0x18d5b682, 0xc0658f8a, 0x8ad6df6f, + 0x8e5484ff, 0x33dab94d, 0xd6bbebc2, 0x0111827b, 0xe40dcc20, 0x1421d16d, 0x764500ee, 0xd7e5808f, 0xf0c1a3f4, + 0x0b15af70, 0xd207a553, 0x0fc413e0, 0xd33ce609, 0x3b23021d, 0x46e275f5, 0x42e6b6fa, 0xe98fcb59, 0x6ef8d9bf, + 0x20c7f065, 0xed607bca, 0xfcdd80be, 0x6d31db03, 0xe49f3ed5, 0xa1ba1ab4, 0x836141ec, 0x2af81a9b, 0xd41eed09, + 0xd538791f, 0xfa293a6f, 0x1748bdca, 0x1d5d3191, 0x37b5132b, 0x46f83a62, 0xafd79bcb, 0x20870bc0, 0xc3aa3d48, + 0x98900da1, 0xf15d30df, 0x56e834c8, 0x9f7180d6, 0x6fac4f3a, 0x095f5245, 0xca0b2b16, 0x11ad43b1, 0xefb9039c, + 0x3189f9fe, 0x01e323b2, 0xdae48982, 0x0ff91259, 0xa12f98df, 0x957b4823, 0x33c3a4b2, 0x7628596f, 0xa8e986e9, + 0xe96df308, 0x6c145468, 0x80fcd741, 0x79032344, 0x2426a217, 0x21eb74d2, 0x7fa73607, 0x11b41a69, 0xa592611b, + 0x5c570f0f, 0xa1748e23, 0xd7c6108b, 0x548e6b68, 0x1cd6e0fb, 0x1580e8b0, 0xc81bddd0, 0xae75a609, 0x2cf083e6, + 0x24646f31, 0x65525054, 0x7480b7b9, 0x6905ec2c, 0x73c58d26, 0xb210a126, 0x6f6c9bfb, 0x67445a13, 0x509a06d8, + 0xa88c4dea, 0xcf11b9d5, 0x7e39c77d, 0xe9ec62c2, 0x82af482d, 0xa3000d23, 0x305979e4, 0x9822cc69, 0x01600a7e, + 0x90ce1555, 0x328f8089, 0xb05d7b62, 0xbf9440e0, 0x97b8f721, 0x9c9529d2, 0xb6e374f0, 0xe5330102, 0x531eaea1, + 0x6182e2cd, 0xe3adfc08, 0xce693e44, 0x1be83485, 0x8594b0c6, 0xe70ba24c, 0xf7effd68, 0x1ea2db9f, 0x066a04bd, + 0x70b59fd7, 0x7c8fde30, 0xeafd6a40, 0xd454da71, 0x5ce455db, 0x6c838d96, 0x3133bd44, 0xa02021fc, 0x18c8b933, + 0xfb1baebd, 0x1df1447c, 0x09e11909, 0x358bc0a6, 0xd38d2fa2, 0x67a3239a, 0xb8d58451, 0x8a2e4161, 0x032a7b06, + 0xc1dd5b47, 0xb3641d6a, 0x108b2cb1, 0x0eee3d4d, 0x346e1012, 0xb3993f61, 0xd1338cea, 0xeb5add27, 0xb77a7369, + 0x625e842e, 0x5704d832, 0xf28cb1bd, 0x220c1cfc, 0x1e62513d, 0x6fa452bd, 0xa9b89e94, 0x09ff0006, 0x0f05dbcd, + 0xb91cdfcb, 0x402cb401, 0x8b248b75, 0x8e8c192a, 0x1e259cd2, 0x7ad780b7, 0x87f8c3ae, 0x7a92195d, 0xb78c0786, + 0x379224b4, 0x4dfc1071, 0x626b458c, 0x1c2521a4, 0x31ebef8a, 0xd54d0629, 0x1f42b3dc, 0x31904f15, 0x5c553906, + 0x46dd7786, 0xb109364b, 0x3dcf5727, 0x31eea74e, 0x50c3e4c3, 0x9692a4a2, 0x8c44c836, 0x089c3500, 0x4c527b83, + 0x0575677b, 0x05cac105, 0x842a767f, 0x521b1213, 0xb6303f79, 0x2f9039da, 0x9f703fbd, 0x89f27917, 0xbacbfb83, + 0x7f566d28, 0x8523a4f4, 0x5e069d46, 0xd9e8eb50, 0xb987cb8f, 0xc1dfb1dc, 0x9b6e490e, 0x035c8205, 0x12b2898b, + 0x5a196e75, 0x516102ca, 0x67cb0198, 0xba56db82, 0x9098050e, 0xda161d05, 0xa54044c9, 0xe2eff76f, 0x370223bf, + 0x03b436a8, 0x56b31d79, 0x5904ae74, 0x8bf71df0, 0x5ac304a8, 0x7fe5d3dc, 0x45fdefe9, 0x8c2a509a, 0xeaa01f1d, + 0x77ae6273, 0xfd35e4b2, 0xc1e8cf76, 0xe757b504, 0x77e45b87, 0x624f9b4a, 0xae5295f6, 0x53366b1e, 0x6742c48b, + 0x4d5f4f5f, 0xc0776921, 0xaf34c7bc, 0xc63ac526, 0x0b485bed, 0x55602dd4, 0x2580c49b, 0x8fb83a4b, 0x6e2afe40, + 0xc80795b7, 0x78652aec, 0xcd38ba2a, 0x73eef7a6, 0x6c33e1a8, 0xeba99bac, 0x56cd69cc, 0xcaaf2486, 0x788e188a, + 0x693ba161, 0x38e6ba65, 0x10d4c093, 0xd964b447, 0x2a3b772b, 0x24e0b517, 0x36784ec3, 0xff4984be, 0x90b40bcb, + 0x4d84a483, 0x4b0728c0, 0x7be4d385, 0x8415ab19, 0x1a3c365d, 0x415cb2d1, 0x7afec3d7, 0xba2b45cc, 0x9e8da346, + 0xf8d18ae6, 0x474887b6, 0xc6b3cb9a, 0xb9fc4ef9, 0x7609fce1, 0x58b787c9, 0x6bd12faf, 0x7777a6f6, 0x35591806, + 0xe14a13e8, 0x100af4cf, 0x834aee90, 0x9cca3778, 0x2dfe39e2, 0xb6c66a42, 0x80d5b798, 0x0a2aa9b5, 0x9630dc9d, + 0x73410b46, 0x39293b46, 0x7b7052c6, 0xb616d41a, 0xe6d287b9, 0x104990cd, 0x724b2d05, 0x4d223164, 0xcf34fac9, + 0x281e8990, 0x89261ed7, 0x0097cc86, 0xcafa41fa, 0x92750efb, 0x59cf9289, 0x47a50fa2, 0x3ce99f53, 0x967f4388, + 0xa61eb7be, 0x37cf36de, 0x326a5e6b, 0xb43a2ec4, 0x70952f57, 0xf79e86b1, 0x58853a47, 0x0c2dcbfc, 0xb6937d9f, + 0x22136da4, 0xe2e05f6c, 0x4e80244f, 0x64c58c69, 0xf39e5058, 0x074fa942, 0x6ac3d891, 0xd9918d28, 0xf6f3843d, + 0xc4252c7a, 0x0b2d2627, 0x294fc665, 0x3839d847, 0x13863b1b, 0x1128542c, 0x04644dad, 0x25d92c87, 0x30d7c17f, + 0x223365b4, 0xc8d6c7c6, 0x9e5d420a, 0x0b2de44f, 0x27009070, 0x0e8acd22, 0x143842f5, 0x8c15b5cd, 0x0a36790f, + 0x87c66823, 0x20801ae6, 0xd58ac699, 0x64704684, 0x95830980, 0x93b667b8, 0x449c47fb, 0x59bf54ab, 0x818e284d, + 0xad76a81c, 0x61cb9897, 0x844dc5a0, 0x04cce05a, 0xfc71284f, 0x0625489c, 0x8a76d8b9, 0xe39d57db, 0xb8652633, + 0x0a8a1d72, 0x98ed7d09, 0x4929ddbb, 0x8c7a0496, 0x457a056a, 0x3438e828, 0x75d6d688, 0x39806a58, 0xdb42655e, + 0x124e68ad, 0xf58c5590, 0x7f2393ca, 0xa968abd9, 0xe9602bf7, 0xbd250a5e, 0x1b5a9bee, 0x5d99eb6d, 0xd77bf3f8, + 0x3befd0b8, 0x4d5cd50b, 0x2c8c6f41, 0xd94049a5, 0x50a73840, 0x131254dd, 0x5b7101b6, 0xffee1cb7, 0xc7fccdcc, + 0xfdd0c2d4, 0xf6fe36db, 0xb75ac8b0, 0x2b3b6b89, 0x2e92cea2, 0xa84cefb0, 0x1bb8feeb, 0x18df8985, 0xd006e911, + 0x30230013, 0xae85604d, 0x631902d1, 0x552d039f, 0xa46c351b, 0x53dca102, 0xf438229e, 0xda9cdfe9, 0xddcc80c3, + 0xed8a56f5, 0x062625f7, 0xdd41121c, 0xc59adfc7, 0xda34d60e, 0x79081388, 0xd8491fdf, 0xbccb3a46, 0xb5172aca, + 0x9262dd1a, 0xf9c993fa, 0xf7e629db, 0xdad16bd3, 0x8fc458a4, 0xf6482583, 0xaa2207be, 0x62a8d5e0, 0x72165531, + 0x3cc10de1, 0x6e37bdad, 0x9509cfe6, 0x655337d6, 0xa2178a85, 0x803fe291, 0xc55746a4, 0x2f42cc8a, 0x84fe5952, + 0x86805d1e, 0x3aa11a61, 0x7a68c2e9, 0x7a9a4dd0, 0xeb2fcc81, 0x2ad0a284, 0x5f10d471, 0xe945365c, 0x0c43bcdf, + 0x57aeb2cf, 0x1b60770e, 0x34a75141, 0x86b94c65, 0x04fff67d, 0x21ad1938, 0x495d2655, 0x34a3f1bd, 0xb2ddf279, + 0xfe1e6bdf, 0x17c9be0a, 0x3cd5651a, 0x2c89a026, 0x137490f0, 0xc6255422, 0x5eb1f909, 0xb24b5246, 0x4afd07ec, + 0x70ecd661, 0x81e4c241, 0x95350f47, 0x6c10383d, 0x7f7defae, 0x193ea47e, 0xb25486ff, 0x1f25bbf7, 0x39bbb390, + 0x730bef24, 0x74214203, 0xcb6bc5e8, 0xa2263dbe, 0xb4810664, 0x05e37fa5, 0x85968351, 0x34fe6558, 0x435dcc8a, + 0x86155cf8, 0xc2ff7846, 0x51a6051e, 0xdae7e248, 0xdf68fbac, 0xb7a5d955, 0x8a5c3780, 0x79b39dd9, 0x493de156, + 0x5ed5187f, 0xd6e5c9f5, 0x7e0d56ab, 0xa3c6cb61, 0x69b8efdc, 0x34c6d378, 0x3202bcfe, 0x13331577, 0xbd2bc520, + 0xea885d5d, 0xa2d3320d, 0xfaf8fe37, 0x4d0bde81, 0x0f364238, 0xee152076, 0x70edb7e1, 0xbe1de3e1, 0x0a1611c8, + 0x4e3fbacd, 0xf89b1547, 0x2297a0c1, 0x5d9ef46f, 0x4ff7bcdb, 0x18101990, 0x3ff3f300, 0x9204d06a, 0x0b696aa8, + 0x2da9bffb, 0x81def63c, 0x6b3330da, 0xba9d6684, 0xd16620f2, 0x5c5d435e, 0xbc393c73, 0x14808e77, 0x36878637, + 0x616f8661, 0x94e2b560, 0xbceb61b1, 0x91e47946, 0xbb4e62f7, 0x33d5316c, 0xce79a558, 0x22bcdb1b, 0x60bd5943, + 0x28cfcd53, 0xe4b331d2, 0x141306e7, 0xac1bf4b1, 0xf642ede6, 0x093d0293, 0xe90ecb6b, 0x36285c54, 0x89e81284, + 0x9349fe25, 0x1b3b5427, 0x7bc13acb, 0xf9b15002, 0xce4f936d, 0xcb44e671, 0xfd994024, 0xfac5bfec, 0x133101cd, + 0xe8e71555, 0x02c78097, 0x8ab6693e, 0x43df94bc, 0x31d92c70, 0x8de20d2c, 0x94c66e9b, 0xdeb5a1de, 0x8d4d9da4, + 0xddc6b773, 0xcf54f077, 0x968a9fbb, 0xeb930de7, 0x12f6c6ce, 0x772ec424, 0xdeb0993e, 0x110fe968, 0x0a01b75b, + 0xfd73b51d, 0x1d4c5b07, 0xb91caa2f, 0xdbd8514f, 0x09ec435e, 0xacac5e3d, 0x17f5d162, 0x3d7bdce1, 0xb853a3e6, + 0x57eedaf0, 0xdf90073f, 0x17fefea4, 0xc0131e44, 0x489d0705, 0xd1fbe968, 0xe020d500, 0x5303d29d, 0x5374c4e6, + 0x342f16e6, 0x20451d72, 0xe4f7e156, 0x75a20398, 0x5ff753b8, 0xde8b246d, 0x2cf2359a, 0x2ac903c7, 0x072052d4, + 0x6801960c, 0x4e0f2661, 0xe06be1d8, 0x99768e60, 0x03572c60, 0xc03604e3, 0xd7a5b25c, 0xadd0ceb8, 0x559b1aab, + 0xbe9fe1bc, 0x593885e4, 0x02f6e231, 0xbd3e82a0, 0xa677b1d0, 0xa31275a8, 0x714820bb, 0x0bea3cc1, 0x1098bda0, + 0x84044251, 0x0a70e394, 0x0d464d62, 0x6a305d5d, 0x76d076bf, 0x9aa53a43, 0xc596482c, 0xa91c88f3, 0x8e2cfcff, + 0x9fafe6c9, 0xa144af67, 0x8ca6f272, 0xc433ea15, 0x45c8bc53, 0x9446560c, 0x13bad372, 0x61e221df, 0x92ba4684, + 0xacde52b6, 0xa7bdf424, 0xf856dfe7, 0x22137ef2, 0x5d875d94, 0x623efb12, 0x2bc67171, 0xf7490e57, 0x3c408deb, + 0x118ee3a7, 0x0ba427d5, 0x94172a7b, 0x4ddd9437, 0x54cb788d, 0xe1ad6037, 0x30b98dd4, 0x1e0216df, 0x42dc62dd, + 0x8c2b772c, 0xe2f10320, 0x55974b74, 0xadea1bc1, 0x0f1f053c, 0x02963be4, 0x160b9ccf, 0x26fd16b2, 0xb57e542f, + 0xcb1dd5d5, 0x87bfa498, 0xf6a49127, 0x74bb1608, 0x07597acc, 0x120b670c, 0x78a5ee89, 0x0140c068, 0x521d3ebb, + 0xfa813f23, 0xeeae3783, 0x4a09067d, 0xc76b8846, 0xa5067af3, 0x4c6000ec, 0xcee06713, 0x1c777478, 0x9415e789, + 0xfb7f2c7c, 0xfda2f44c, 0x0526fb8b, 0xa95ba09c, 0x4061cd0e, 0x7f11d81f, 0xa0fac047, 0xf719e282, 0x91c4aff8, + 0x400c3dba, 0x6b49e431, 0x6fc36d54, 0x6f698f86, 0x2abc8f71, 0x30b550f7, 0x1f9e4a17, 0x692a5751, 0xc71225b4, + 0xa14052e5, 0x3b6c1bbe, 0x9827ddd7, 0xf53702c1, 0xcc870995, 0x2e2bccf2, 0xa7c62c68, 0xcf17dfa5, 0xdcc33962, + 0x87015c4e, 0x9bf2a263, 0xbaa7ff42, 0xcfb5c079, 0x5e27f590, 0x1ffc2239, 0xb43deb11, 0x27f45a3b, 0xe56403ea, + 0x3e6efe82, 0x043e6945, 0x30cf0a1c, 0xabfd6aeb, 0x7ac57fa8, 0xab69b250, 0xe9f4002e, 0xeeb27066, 0x6e7c0ea0, + 0x6e8dfd6c, 0x375e72c0, 0x00c1ce88, 0x35d2d528, 0xad710b78, 0x4046a8c3, 0x3a44edfb, 0xaf05ca16, 0x7fd038c8, + 0x3063e85d, 0x6535a3a7, 0x5a24eb56, 0xbd563c74, 0x0ada8e42, 0xf2978241, 0xfa5c2451, 0xf6f09349, 0x2ac3848b, + 0x0d7033fa, 0x3f866972, 0x6a776712, 0x3f2dc622, 0x579d6d35, 0x0b9f5235, 0x2e9ab36f, 0x7edc3326, 0x15ef7d8b, + 0xb8de6a01, 0x965bf928, 0x9fc0ba3f, 0xc9b2524d, 0xcaae5a77, 0x2308f495, 0x484065ae, 0x691f5643, 0x7aa395dd, + 0xb282033d, 0x513177e8, 0xc2f21ffb, 0xead5bc4d, 0x2ee4d5d4, 0x2cac1903, 0x23ed6209, 0x32c2b296, 0x8e8fd4a2, + 0xd267385b, 0xe48632b7, 0x1fa7ef89, 0x3c3eda8a, 0x34183931, 0x7477acfe, 0xfff7431d, 0x5dd8e07c, 0xadc19b27, + 0xa3d14f5a, 0x3e83f1f2, 0x6a94b3ca, 0x84254b43, 0x09242a72, 0x4ffe79cb, 0x1deb6f02, 0xbeeeedcc, 0xd4f4daf1, + 0xf6b4be50, 0xb67bed65, 0xf094a5cd, 0xedcbc6b1, 0x73378a6c, 0xffcf542b, 0x249b2c2a, 0x9676a580, 0x4e9ae087, + 0xf57ba29c, 0x17efe13d, 0x7d1a05bb, 0x1e021b63, 0x06fba520, 0xb3fae978, 0x6853dcb5, 0xc3cafda9, 0x768ef5f7, + 0xb29cf8f9, 0x626ab265, 0x92bafb81, 0xd31797e1, 0x6debccd1, 0x30e079eb, 0x78e223ca, 0x17f03f84, 0x0e66c006, + 0xd0bac81a, 0xb57d0e83, 0xbf9a6ee8, 0xadb716b3, 0x3ce0f270, 0x75270981, 0xd38c9703, 0xa453c996, 0xf4821f5a, + 0xc4741fef, 0xf40822e9, 0xc9f4b96f, 0x9088ea07, 0x0e94a3be, 0x3f8f3b69, 0xd2b77236, 0xd6d60ad2, 0xc82e1ccf, + 0x7d6e1190, 0xbe287b28, 0xac0929c5, 0x353b5a97, 0x56c2e689, 0x25a07c81, 0xe72b31f6, 0x0d56868e, 0x1f875890, + 0x84ed0975, 0x5652520b, 0x9e702f0a, 0x3a51a828, 0x095ff94b, 0x3c695790, 0x09c6f929, 0xb8391932, 0x0be77d15, + 0xbe4f61a0, 0x17452ea2, 0x4a05dc37, 0x724fdb88, 0x4a11ecd1, 0x713934eb, 0xad1ad2a0, 0xfda7b0fd, 0x0f1c2f3d, + 0xf522a68d, 0x804fa173, 0x4560317c, 0x35db6e1d, 0x32d1e134, 0x5ed8e1d3, 0x91d38aba, 0xb5c68638, 0x0800d465, + 0x2e56e25e, 0x76b8615e, 0xf92bd552, 0xced96c9a, 0x3eaed2b6, 0x09793388, 0x835fd177, 0x4394781f, 0x591bc44f, + 0xa9c1fd2f, 0x15f85361, 0x3f6c716f, 0xb2ce207c, 0xa9b264e5, 0x1581c2f7, 0x07ee29a6, 0xb1cc4cab, 0x59b60464, + 0x189f6fc7, 0xb249ed31, 0x5bf9a2b4, 0x8669332f, 0x81c0abd2, 0xf9435ce0, 0xa2559c98, 0x9502f408, 0x8eaa4e16, + 0x70c098c6, 0x767af7e5, 0x1b1daaad, 0x009eeb78, 0xe6a8a58c, 0xce5ebb27, 0xabdbad01, 0x809b375d, 0x85deb66c, + 0x80ce17fe, 0x0c5c0d18, 0x99ba39a8, 0xe5c43c84, 0x6df827a4, 0x40143d39, 0x618a0bf2, 0x09073752, 0x5424cf7f, + 0x82314ffe, 0xe294f3d5, 0xa0714c9f, 0x7fc990f5, 0x4395ddce, 0x940dd09c, 0xb16b5e91, 0x424da89f, 0x5a18950a, + 0xb18e29f2, 0xde907e25, 0xbdf811ee, 0x638bb276, 0xcf1766bb, 0x8ce040f1, 0xb0f18504, 0xc9824582, 0x15f8e62b, + 0x8b89baf4, 0x21228875, 0x250ce3f8, 0x65095d63, 0xd5e13e7a, 0x8baf156f, 0x429deab5, 0x27e66cf4, 0xa563aabf, + 0x0556bd0a, 0x5800e02d, 0x7076462c, 0xaf2d37c6, 0x8bcea28b, 0x4509c6a7, 0x8733825b, 0xf8e8302e, 0x5226a17b, + 0x360713bf, 0x6151b745, 0xc9794f30, 0x83fb9441, 0x7ecc5be5, 0x4e232d2e, 0x7fb43654, 0xffcbb467, 0x1f711e02, + 0xeee4f3d6, 0x7798714f, 0x87beba2a, 0x7bcf8b94, 0x4a3cd855, 0x86ec3627, 0x32f5ecc4, 0xae4cb4a9, 0xaff6cb88, + 0x53fccb05, 0xeb3b6640, 0xb69187b8, 0x41fa45d7, 0xbaf5e437, 0x2c8f5209, 0x4a5a0cba, 0xd1061c51, 0xe46fc3bd, + 0xa1f929f6, 0xaaec20d0, 0xa572f194, 0xcd29fb3b, 0xf6101a18, 0x41b6e6bf, 0x9a4e8e48, 0x99959680, 0x75c0e973, + 0x61346978, 0x4829b6fa, 0x824fbe85, 0xcfc8de90, 0x316c5055, 0xf36a7d45, 0xaca927cd, 0xa883f78b, 0xeee97076, + 0xfd38bbbb, 0x255d5a14, 0x6695d56b, 0x77bf2554, 0x0021b512, 0x66c77055, 0x63619dae, 0x5e17c036, 0x81057075, + 0xbb169cbb, 0xeb7732dc, 0xac5f6d50, 0x145ccc20, 0xcc9071fc, 0xef48d4e1, 0xb5c6a567, 0x07a2f504, 0x225f7c4b, + 0x5c9d29f6, 0x2ea61c4f, 0x54377baf, 0x25185e02, 0x1a3f5f8d, 0x1d017556, 0x021f13f8, 0x583ae124, 0xf086f180, + 0xcb100581, 0xc1bdbbb5, 0x1446e89e, 0x7091af6d, 0x96840d79, 0x4edc5eb0, 0x585b727b, 0x02898ab2, 0xf2ae1c30, + 0xb4e62462, 0x24b40c46, 0xbef39fea, 0x9b8c21ad, 0x0c3e1e2f, 0x862366c8, 0x601c2c2c, 0xeae6c691, 0xf39e577e, + 0x75b463ab, 0xd005b9d6, 0x35933210, 0x8ceaef8c, 0xbf2243fd, 0x0cb5e27c, 0x776c0cc4, 0xc4d97750, 0x60d5b088, + 0xfab77c3a, 0x579fe4cc, 0x840605ee, 0xdddb9981, 0xde46d8de, 0x1b6be2e5, 0x3e0b569d, 0x01580a7a, 0xbb6ef452, + 0x53fec84f, 0xc8d9f803, 0x647ea271, 0x78db84a8, 0x42ff26c1, 0x9fc4f98f, 0x164afebc, 0x2eebd998, 0x8a271fe9, + 0x6303085e, 0x0cabefc5, 0x58bcf794, 0x068fbc64, 0xaf203799, 0xc241786e, 0x87886d76, 0x5eeb3b0e, 0x54f70d97, + 0xac547723, 0x30a88749, 0xfa3da8b3, 0x6c7d4584, 0xe6aecc50, 0xbd89582f, 0xeec07472, 0x62ff2922, 0x5ed9155a, + 0xbb3cd126, 0xc878c7c0, 0xe647752a, 0xbb213f8e, 0x501203f1, 0x34f70878, 0x703a8351, 0xe73e2724, 0x21d0f598, + 0xfb9fdbbb, 0x1f6fc1f7, 0xf8b42641, 0x82d88890, 0x41a369d0, 0x407380d1, 0x8cc89480, 0xc3d6e0d7, 0xf517ac47, + 0x919a9c60, 0x4b72c319, 0x8cb13b99, 0x6c154dac, 0xeb1d80f3, 0xa2653f1a, 0xcc645d7a, 0xb8d6a1cd, 0x0f8ba5e9, + 0x85ba5343, 0x1a0d3651, 0x5a86dcec, 0x681eaedf, 0x415fc0dd, 0xfdc818e8, 0x117dbf0d, 0xbbf40e11, 0x4762fe51, + 0x36cda997, 0xd53a7397, 0xdbc0b437, 0xe992e49c, 0xd57b365a, 0xb8919ab8, 0xa6981c14, 0xe337f611, 0x4940489b, + 0x5a8d31a3, 0xfb9a2a24, 0x23b2a723, 0xf0b63b61, 0x5f84694d, 0x63f18aeb, 0x713d86e7, 0x9e926e49, 0xde385013, + 0xd30fae24, 0x428a8442, 0xe1092797, 0xe0e71aff, 0x57954329, 0x0e934a6d, 0xcc3687be, 0x6d73ea99, 0x13d68623, + 0x54f5fadb, 0x6ae2b31b, 0x71c16bca, 0x2397d534, 0xa27dc02d, 0x3f237676, 0x5ef11cd4, 0x38ef1a33, 0xd299b712, + 0x088ead61, 0xb2e8c30c, 0xbc7034b8, 0x286d6154, 0x52fdcb0e, 0xa62e51d8, 0x4c7eb680, 0xbd868a07, 0x2a8fd0ce, + 0x8f2e8a8b, 0x6788dcdb, 0xc5bb3708, 0xbf9b41a0, 0x6639036e, 0x25c71d34, 0x92196778, 0x2c01a50a, 0xfeb30c23, + 0xd66f934f, 0xb0e0dd01, 0xc6ac9b20, 0x3fd76a3f, 0xfa21da90, 0x2baf8627, 0x2dbc12d0, 0x420d32d5, 0xf8a2985d, + 0x3e9caa58, 0x27e0efd4, 0xd332fad5, 0x47b5abbd, 0x665a571f, 0x70eef2df, 0x004cd527, 0x88921270, 0xc55eb82e, + 0x3603478c, 0x5405e57d, 0xdbe1b636, 0x5080351e, 0xa051b5f8, 0x45fda493, 0xba6e12e7, 0x638ca9f9, 0x08ec91bf, + 0xcecb51ef, 0x70035761, 0x1e29a9a3, 0xfc28d9f2, 0xa2a7ce5d, 0xaf3a6dd5, 0x1039e161, 0x25970832, 0x49ea6210, + 0x6d746f7e, 0x06ced63f, 0x9edf0031, 0x97f0b1f2, 0x797d5af8, 0x00676b43, 0xe44cfcc3, 0x12e5cf1c, 0x873c8fed, + 0xc82c0a3c, 0x9ad49b8b, 0x9fd4a4f0, 0x506727f3, 0x1ea649e0, 0x47402c98, 0x938cf6a0, 0x4b079cb1, 0xa5de68ea, + 0x29c46be0, 0x553a1093, 0x42c2d580, 0x53c02e86, 0x0d201c6c, 0xd1a1ffd5, 0x04d53722, 0x8693bb30, 0xeefc3826, + 0x55a9cb4a, 0xb15211bc, 0x01306011, 0x284afac1, 0x1e188267, 0x496b4fc7, 0x3eff8dcb, 0x0bbc70c7, 0x95c20576, + 0xc8c9df39, 0xf8cfb9ff, 0x431a749a, 0xc9d508db, 0xa4a0756f, 0x2e3e5ed7, 0xe7709e7d, 0xefea8b10, 0x22ebd590, + 0x8bb052b5, 0xdb1aa0ec, 0x95be85bb, 0xcfd6162a, 0x47e18ace, 0x159bdbf8, 0x1e5777b4, 0xf844fbee, 0x5ee3fe96, + 0x3a1bfba7, 0x07882efe, 0xbb330ee4, 0x174dea14, 0x9d5451b5, 0xd5189a43, 0x493b1787, 0xeeb49507, 0x6b875af4, + 0x29cda842, 0x5c919172, 0x96d9009d, 0x8237afbc, 0x79ebd284, 0x096702e2, 0x583a2276, 0x1b1955dc, 0x3fdff342, + 0x69d31f0d, 0x4339fbbd, 0xf3bfd437, 0xc292df32, 0xa1b07262, 0xca3bd86f, 0x10dcbf1d, 0x306e3be4, 0x9f14de26, + 0x88ae7952, 0x9dc885f0, 0x5824a383, 0x0dc29832, 0x60301927, 0x79c9adb0, 0x17545b05, 0x12f41688, 0x94defb7b, + 0x1080ece8, 0x1f5c75c1, 0x9cdb927b, 0x35d1a50b, 0xc32f9aed, 0x81f966e8, 0x3d467f9f, 0x1b7c2921, 0x98f5633e, + 0xbae5ce3d, 0xf4887ae3, 0xb4e1ea3a, 0x16dbb713, 0xc4971e3e, 0xc8e9fd78, 0xf1ad3605, 0x94b9c6c9, 0xb79f7385, + 0x206a6eaa, 0x9dab69a8, 0x239187f6, 0xc94ecc69, 0x335d65c6, 0xf3db0290, 0xb9c98b76, 0x51b7d368, 0x7bfd306a, + 0xa844d1b0, 0x65e8713d, 0x2d0b6ac9, 0x50e11e3f, 0x03f4f4ec, 0x04aadb53, 0xef3b366a, 0x293257af, 0x91d47bea, + 0xd75e5bd6, 0xeaa528c1, 0x81f90517, 0x6c1c8d6d, 0x57ca1b8b, 0x264f9e4e, 0x7165dd0a, 0xce102681, 0x74bc32bb, + 0xa4e1ccc1, 0xb1a27abb, 0x8e5f8949, 0x7a4c9e5a, 0xcaf50404, 0x6e725eed, 0xce1e9548, 0x01f159b9, 0x0c90aacf, + 0x69e12e16, 0x779d4fc7, 0xb28e8442, 0xf8aba63d, 0x8f7c4cc4, 0xfff701d1, 0x7b1e6419, 0x2d0c639f, 0x9499d96f, + 0xae7b4beb, 0x2b7354e2, 0x0b5e2279, 0x5442edc6, 0xefb50c14, 0xc7cff9ff, 0x8bda101a, 0xed9d2a88, 0xffbfc23e, + 0x18d49072, 0x7f9434f9, 0x9b69b2f0, 0x2817d4a4, 0x4bae9c75, 0x4a746103, 0xbc1f446c, 0xf1e26e81, 0x9a849e32, + 0xd15b334f, 0xab157edc, 0x5e852a43, 0x1e707d08, 0x4e47a0b8, 0xca8b866b, 0x342182ad, 0xec6c865f, 0x39ff9246, + 0xc1e28aeb, 0x2826532a, 0x8c2161db, 0xdb7ad0c2, 0x2cc21d1a, 0x7395b201, 0x05368938, 0x655d3a8a, 0x5e1c2e3e, + 0x3bc84682, 0x7a9a6835, 0x6dfb5647, 0x1f1e7bb2, 0xdafe9be5, 0x1b70547a, 0x0ee1ade8, 0x4ef85a74, 0x6a790941, + 0x3aed43bf, 0x3aa8c4f0, 0xe26246a0, 0x3be44b92, 0x392d542b, 0x927b1197, 0x9b6084a6, 0x6d060c67, 0xcfad0004, + 0xe6942b19, 0x3567b0f5, 0xa7ddf75a, 0x8cc645d4, 0xe9c66832, 0x63c1ff60, 0x829b324a, 0xd44dc4e6, 0x2d1b3a62, + 0xfb3858d8, 0x2b0660d4, 0xfed0553a, 0xc732a5c4, 0xdedbb8bd, 0x9acd5e38, 0xae3f69f2, 0x69266209, 0x3a1d2be7, + 0xc020c4b7, 0x1b1a8f4c, 0xd7eb8d6e, 0xb99804ca, 0x73562a0f, 0x79dfa260, 0x9044e8ee, 0x2dd2808c, 0x2462cf35, + 0x8415204d, 0xa8f32ec0, 0xbe9eb859, 0x50ea2917, 0x9213562c, 0x4eac6be7, 0xf0311030, 0xee20f66a, 0x230ad946, + 0xd2500c2d, 0x07460772, 0xe410ab69, 0x2e590515, 0x0c5b123c, 0x210a5fe0, 0xfcb8c216, 0x23e762c7, 0xbdec3d74, + 0x230ca192, 0x0f8fb73c, 0x99986dc1, 0x4ec737f1, 0xb11a0d90, 0x5c3c355e, 0x5679810e, 0x5075ad6c, 0xbf2833ad, + 0x0c4b527d, 0xec143fcc, 0x2d5313e7, 0x1423bcaf, 0xe591359e, 0x0930b2c4, 0xf1b3b2bf, 0x0f13887e, 0xed0857b9, + 0xe088a9ca, 0xcdedf6a4, 0x95930261, 0xe5a3d421, 0xf684d44f, 0x98c1e8bb, 0x16fa7b85, 0x0f056aac, 0x48e3958d, + 0xffef1ca3, 0xa787308b, 0xeca3fa3b, 0x85ccc821, 0x39659490, 0x1cfb55ca, 0x5bd8cbb6, 0x44484ccc, 0x5f38bc15, + 0x6b8de73b, 0x3ec0195d, 0xe01cafc0, 0x2a9d4930, 0xfa91739d, 0x7c0031ad, 0x38e85af8, 0xa034e827, 0xc07cdb3d, + 0xdd9419a0, 0xbbf4838f, 0xbfa9e485, 0x6aad5709, 0x0ab39a97, 0x0b7644b5, 0x88e67151, 0x12d779bd, 0xd9337eb4, + 0xc0cb4ccf, 0x5ccb68ef, 0x3c8db56a, 0xc4b0b06f, 0x6b85f651, 0x28975806, 0x1e51cb49, 0x3cfce50e, 0x1398df08, + 0x8b8a32fa, 0x7bff7819, 0x5e2d5819, 0x6bfc214b, 0x91d193cf, 0x3317e584, 0x93f19272, 0x59a28fb9, 0x419d7531, + 0x3fc1c7bf, 0x9b1bc2a1, 0x4fd51299, 0x78c65077, 0x78e5856a, 0xddc9b52b, 0x68c0a68d, 0x8f737a04, 0x94e6274e, + 0xb244f45a, 0xd23df0a3, 0x091116da, 0xfa6c9e15, 0x4b5e0011, 0xd0c08534, 0x6de4363f, 0x98b6f0b3, 0x790302d8, + 0x1a525b9b, 0x7fba8be4, 0xa791c628, 0x6cd8ebb2, 0x0d006a71, 0x005e9888, 0x2a708b92, 0xca21ead2, 0xae8f71a5, + 0xcf274d68, 0x64cab8d7, 0x36bfa06f, 0x959dd54e, 0x86fb489d, 0x2997eee0, 0xe2fa5ffc, 0xb8fbcfa9, 0xaa613270, + 0x2023b427, 0xf49b6dd4, 0x8f437ff4, 0xe8c91e68, 0x2c2871cd, 0xa780588e, 0xc3e91425, 0x29f197ba, 0x94b14c25, + 0x80023fd6, 0x718c7b6c, 0x52cf9b3a, 0xbf38fc11, 0x7fa8c752, 0x932afe0a, 0xeed5f341, 0x6389ec33, 0x73c37aea, + 0xad372390, 0x52277b02, 0xd0bb9806, 0x71a44538, 0xe486a222, 0x5a7c8b36, 0x8848fcdf, 0x920fe35b, 0xc05624b5, + 0x5d22f8c9, 0x8a280d71, 0x55b4208b, 0x5d33b847, 0xcb01a6cb, 0x39afb1ce, 0xae853ed2, 0x36e6cff0, 0x917c262e, + 0xd0395c55, 0x916fd001, 0xcf7528aa, 0x8b4e6b5b, 0x00b72696, 0x2bf13b8f, 0x49a20246, 0xe1d41801, 0x832bb0aa, + 0x135cc079, 0xaae4ca27, 0xe70fc30e, 0x7129f7d0, 0x4ad5ea37, 0x98175494, 0x649f3fdb, 0x1e791a85, 0x0d1e25b7, + 0x7a7d11bc, 0x15ea7875, 0x4d37b062, 0x5154c010, 0xf9033ccb, 0x222d2a3b, 0xfd333b0e, 0x25cb5152, 0x69c6f676, + 0x2a10e3d1, 0x8625da30, 0xe8f87568, 0x3b5cf14d, 0xb2a0df9c, 0x76d23852, 0x15e2c46e, 0x4a6fab03, 0x68947e15, + 0x3ca61277, 0xb88b79f4, 0x1bf61ead, 0x35a20e10, 0x11e33cfb, 0x8db0a899, 0x2506c113, 0xe3a1429a, 0x3e52137a, + 0xdd23cb3c, 0x5c9fff76, 0x2aeab790, 0x7b85b1f6, 0x8147f280, 0x9deb0143, 0x150b02c9, 0x3193572a, 0x0059e669, + 0xe8038e84, 0x9d472ba8, 0x0daac9eb, 0xe83ad3e7, 0x2e217dd5, 0x58523028, 0x6c18645c, 0x4a283a1c, 0x784a59c5, + 0x9352ce61, 0x84501e99, 0x0658ec91, 0x87e28544, 0x10ae06c8, 0x78aa623e, 0x3cc99eb5, 0xdef6040e, 0x41a891ca, + 0xb29f39f8, 0x321a0105, 0xcf7ab535, 0xee71a453, 0x86d8c01d, 0x8e25a0cb, 0x86885e4c, 0x7b2a776a, 0x4565e10d, + 0x95636533, 0x2d642b9d, 0xee896c77, 0x61bc5e9c, 0x6eb656b7, 0x8d914d3d, 0xda00cb50, 0x5c715d10, 0xc5437b85, + 0x4c0eb1fd, 0x2157df39, 0xd0b68e97, 0xedece231, 0x692a2a95, 0xbbde775a, 0x27801128, 0x1513b317, 0xe13517d5, + 0x8c7b4061, 0xe3cdd655, 0x172701bd, 0x9d1f5234, 0x4a03bd05, 0xa8ad26a9, 0xd0a1e2b3, 0x95eeb542, 0x4d1807ff, + 0xfd7d7c97, 0x1864ed8c, 0x140f1e01, 0x242f26fb, 0x1b2d4d48, 0x5805a631, 0xb8a4a976, 0x2a076ba1, 0x4ae7a8bf, + 0xab3e590f, 0x58a02e41, 0x67d83ec9, 0x5585e4f5, 0xe2e846d0, 0xc2b4bcd1, 0x8d47f1e4, 0xc7672685, 0x45e2a002, + 0x5b5d68ba, 0x7ef1a19b, 0x2babe170, 0x8385692e, 0xf5765a55, 0xed572b7c, 0x1a6efaf9, 0x5edd8004, 0x19c7fd2c, + 0x452c25ce, 0xb4b36fef, 0x9c3f2ab2, 0x8b59e5dc, 0xfe40e76f, 0xf630898e, 0xc5445112, 0x221c6e92, 0x43076128, + 0x6a988016, 0x44c0372e, 0x3f92c7a6, 0x245bcf13, 0x30d2be1c, 0x60eacd8f, 0x1c06edef, 0x7ab2a467, 0xa87a20e6, + 0x9227dc9a, 0x244280e3, 0x340005b7, 0x19472330, 0x165fc4d3, 0x8a07181d, 0xffd28758, 0xb5cb910f, 0xdc2f4947, + 0xf18bd28f, 0xba770f59, 0xf6c32d82, 0xc2d8fce7, 0xd5909105, 0x366479d6, 0xbf64294d, 0x9a835fb1, 0x269071ff, + 0x5d497962, 0x5eb92359, 0x5d3450a5, 0xd3dd9af1, 0x745e555e, 0x4118bc82, 0xe9e7863d, 0x4d3f9492, 0x7cb03ee2, + 0x98206dc0, 0x1567ebd3, 0x256fad6a, 0xfad51173, 0x59d17407, 0x90a780da, 0x0e0af331, 0xa3ccc97b, 0x2435bc89, + 0x194eb9ae, 0xc8915808, 0xaaf200f6, 0xb9956bfa, 0xdf0ee105, 0x68717264, 0x9d5943a1, 0x960a7452, 0xd8ae5daf, + 0xe52ee235, 0xd9ab93d3, 0xa3928916, 0xc8644e8c, 0xac3463a5, 0x186265cf, 0xa1bf8a8f, 0x90f22705, 0xefdf64c5, + 0x04aa0ff0, 0xe28b9e73, 0xcc6a871e, 0x6c28ae08, 0xd8f205e5, 0x0208a774, 0x8de80cde, 0x5b7872a4, 0x59aa8479, + 0x6533ba8b, 0x76a63448, 0x3ac27085, 0x6ed0c45d, 0xd5dca492, 0x50b40374, 0xa87132b1, 0x641610a6, 0x061c86f2, + 0xb40b18c5, 0x2ea9d9f5, 0x9e0b5ab7, 0xd4f8fb22, 0x615f1541, 0x543c7ac4, 0xf7e85316, 0xfa7ead2d, 0x2792e774, + 0x01b35a8d, 0xa0567424, 0x457eb8b7, 0x170ce326, 0x46c31289, 0xa86642f7, 0x0e56cbe8, 0xb43f2a9b, 0xc6db668b, + 0x2e2af9f2, 0x110590fe, 0x858ac09b, 0x9ffdfaf0, 0xc20322a4, 0x748f01db, 0x997cc7f3, 0x445cc18f, 0xeea1c116, + 0x0f9afa60, 0x8852ae25, 0x69240a05, 0xed1185a7, 0x421eef11, 0x650e54e9, 0x748c856a, 0xa627f6cc, 0x0c34b05f, + 0x3ed9c62a, 0x236ad94c, 0x6e029719, 0x7145b443, 0xc76c6b10, 0xdba24dff, 0x6a3da6d6, 0x23071807, 0xee2a62c3, + 0xab433efa, 0x26b25a9c, 0xced9ddbf, 0xe9527b96, 0x84547c9d, 0x9219c8ba, 0xe2e50e6c, 0x5af2780f, 0x9476a699, + 0x0d9773a5, 0x67a5d9df, 0xda66641b, 0x06f8284d, 0x621b8cdd, 0xb053400a, 0x16cdae3c, 0x10ec9604, 0xc2859f0a, + 0x5decf08c, 0x398429bd, 0x36dffa0e, 0xcf447fab, 0x8bd52337, 0x8d752047, 0xd266889d, 0xd3a2b86a, 0xdf2a5fa3, + 0xb96e2b9d, 0x796c1b5a, 0xcb04c09b, 0x2ab01cdf, 0xd43b0da7, 0xface40b5, 0xc416cf13, 0xb314ca3e, 0x2f4138bf, + 0xb92bd2d3, 0x48962f59, 0xad8de7d3, 0x88e9a0c3, 0x0675673c, 0xdfa43407, 0xe81ff9c4, 0x9b93074d, 0x0e524720, + 0xaefac65f, 0xd4ed10d8, 0x1d353f6c, 0xba9903ec, 0x66d2df1e, 0xdc0425da, 0x32358c92, 0x69c72076, 0xf7c4442f, + 0x7e325aae, 0x68e0d1d6, 0x95f906cc, 0x8a1e08ca, 0x0af883d8, 0x23ca5387, 0x920e3444, 0x94240594, 0x58d431f0, + 0xc93d698d, 0x6bd5ff01, 0x665b148e, 0x63c6e3d0, 0x69d60fc2, 0x66b4caa8, 0x873d5e91, 0x21f0753e, 0x504e7f26, + 0x3556b66a, 0x6315baa2, 0x0a0538af, 0x3a3b3adc, 0x3b368e0d, 0xab2a84b8, 0xe2a99baa, 0xfa747d0b, 0x2e877f81, + 0x38782699, 0x6b5a6863, 0xd6b2cd25, 0xcdf703f0, 0xd0876b29, 0x6e4845ee, 0xb239dbe9, 0x657d38ef, 0xd6c93218, + 0x04b83651, 0xcb866171, 0x6444db77, 0x273dba29, 0xee70ea6f, 0xbe3df979, 0xc9fbb2c2, 0x30ba991a, 0xb4111525, + 0x63ee5726, 0x12a29506, 0x2c7c7792, 0xe06acc1e, 0x0e3611b4, 0xebccfc0e, 0x1cec63cc, 0x9d9c9502, 0x81fb0dee, + 0x16db8c59, 0x3961879d, 0x491b5a75, 0x6d5eb19e, 0xaff9585e, 0x710dfad2, 0x324cc6da, 0xf129a6ca, 0xf8053fb7, + 0x7a999c6d, 0x5836fb0c, 0x361dbc10, 0xe4ff4e4a, 0xff6dcf93, 0x881c5cae, 0x8c19e8b1, 0xd556233c, 0x1f7dac84, + 0xbb3a08f7, 0xc40cfe6a, 0x9de4904c, 0x7168d870, 0xf6c45e40, 0x5bf7d652, 0x80510416, 0xeab8a9b8, 0x6f560b95, + 0x55462f6e, 0x02ff19be, 0xc505579d, 0x03a7b1ff, 0x3c39edd6, 0xfefca646, 0xfa9ca323, 0x6933434b, 0xd053a312, + 0x758d03db, 0x55768edf, 0x3cd21d98, 0x2adc10b7, 0xc6f9f08c, 0x67e1953f, 0xce750aab, 0x64bed30d, 0x4c93100e, + 0x2a3d9a53, 0x2bd76383, 0x0ce6b5f1, 0x48a9693c, 0xc017a0e6, 0xbcdacb3a, 0xf861e771, 0x3f0e9cc0, 0x53ae42be, + 0xed0d0841, 0xee5a3847, 0x92cb3b67, 0x897c3053, 0x3d413d0d, 0xa434ab16, 0x6926fe22, 0xdc9262b0, 0x9bd1afaf, + 0x2591e800, 0x8494af32, 0x65e1a736, 0x33077b23, 0x3d4c1d34, 0x999a7da9, 0xdc522f0a, 0x2592873a, 0x414ad5a5, + 0xf73dd6c2, 0x72c29370, 0x3ad10a53, 0x0d8c6bf2, 0x91556501, 0xcb63f9bf, 0x4af0c31c, 0x53180fe4, 0x0cbab884, + 0xccf9443a, 0x1ae5e88c, 0x35b07bca, 0x1ef15505, 0x469ae004, 0x7d2c5842, 0xeef661f6, 0x62d6c1e8, 0x4b004927, + 0xd9506659, 0x853821f7, 0x488f3ee2, 0x2c5404ca, 0x56b7754a, 0x5682f205, 0x851ee877, 0xdf67174e, 0x0a00e01d, + 0xbb6c85a0, 0xcd4fd4e9, 0xd45fe98e, 0x35ce3cb1, 0xf567c1b1, 0x0c88f7a8, 0xe29b0913, 0x8b127fd1, 0x0d183a24, + 0x7d40b499, 0xa7448e0f, 0xf3cdae1e, 0x379549bf, 0xc1f8dfc5, 0xdb50e42a, 0x133f16cc, 0xae03d057, 0xd835bc95, + 0xadbd127b, 0x3d8206b7, 0xc45dad20, 0xfe65bb8e, 0xd4e6af05, 0x62785ca5, 0xb1a176da, 0x9ac92790, 0x553e3829, + 0xd5bb1d07, 0x127d632f, 0xc0aabc5a, 0x47bd7312, 0x06ed7c14, 0xeeef69b0, 0x07490432, 0x4f9b1c72, 0x400a366a, + 0xeb57e68a, 0xb3b5478b, 0x2281619d, 0x8d8f0360, 0x17b43265, 0x9220f9c8, 0x5a54b73e, 0x80294132, 0x83654ce3, + 0x7b3534eb, 0x7e6bbcd5, 0x166e12b2, 0xe51278ea, 0x7bbb9eb0, 0xdfb06394, 0x50cc696c, 0xd16a2b20, 0x7b88cfe0, + 0x5ef894b6, 0xe7617fbd, 0xa0a0e9dc, 0xd915a12a, 0x71759895, 0x11fff9b9, 0xd362885d, 0x1bc6e1c2, 0x36e857b1, + 0x007f7cb7, 0xdbbec7c0, 0xfc1fc362, 0x3d67f715, 0xd551b091, 0x5d34b09c, 0xa0523793, 0xdc2ac6bb, 0x690ba8fb, + 0x5f32724b, 0x6ee0675b, 0x0076f598, 0x5fc7b757, 0xa249b480, 0x01e40ec1, 0xe191c903, 0x75405f2b, 0x62e5a77c, + 0x0858ac18, 0x22f2b6fe, 0x79c05783, 0xd04e1260, 0xf244a454, 0x1b0e52b1, 0xcd9cd694, 0xb69b8ef6, 0xc60c6316, + 0xaafa9b1a, 0x5a3b1bba, 0x44d9ad29, 0x8a01c029, 0x94f4ba8d, 0xe4812f72, 0xf74c668b, 0x5bd76dd6, 0x288fe6b5, + 0x216fefea, 0x731cbb83, 0x8439790f, 0x681970a2, 0x28a1beaf, 0x397ca784, 0xbdc4ee7c, 0xb6ea3253, 0xe648a5b0, + 0x42ce14fb, 0x8c1f86a7, 0x346723cb, 0x3ca51163, 0x4f063824, 0xc40962c8, 0xa9fef3d8, 0x7646509e, 0x29c50525, + 0x67f390c7, 0x459546f3, 0x1ef34233, 0xbaa818c3, 0x7f876f6c, 0xa4be17da, 0xbe0f3d2c, 0xefca333c, 0x9f7a45ff, + 0xd10cf285, 0xfcc8614f, 0x5f3edecb, 0x96730b9e, 0x49d3c2d4, 0xf29b60f0, 0x5779cfaa, 0xf9a9c952, 0x48b01319, + 0xb8807584, 0x612d044f, 0x16458c09, 0x7bd9198e, 0xe8881db1, 0x0bc5ff98, 0xfc1d3781, 0x9c4b3085, 0xff09a836, + 0x1d926096, 0xbc3160ec, 0xcf395e45, 0x322cc6c5, 0x0513eeb9, 0xdef5a722, 0xcfe29b2c, 0x520b244a, 0x38bcdbb6, + 0x98a93841, 0x611eb7ef, 0x2b1abb14, 0x5d484f5e, 0x74e624ea, 0x7f8017aa, 0xb429e85b, 0x35dc309b, 0x007c8e14, + 0xc9d0352a, 0xaa59337f, 0x48783bf0, 0xc6145208, 0x3d5b99f0, 0x2912d1f3, 0x05bb1ddc, 0xbb22272d, 0x7989d397, + 0x76804c94, 0xf97e40b1, 0x65d36b14, 0x61454c06, 0x02efe918, 0x136f9c5c, 0x74c7106c, 0xb4c16b5e, 0xa118b38e, + 0x57438260, 0xfc5e837d, 0xd0315994, 0xdca02440, 0x3b4bc577, 0x9763b189, 0x61c3896a, 0x66d792e8, 0x90177d2a, + 0x7e7eced7, 0xae229325, 0xd4f61336, 0x98166fff, 0x4187b1bb, 0x0fa7f1ff, 0xd59e0bb7, 0xe8261d96, 0x02437ad8, + 0x8a261a02, 0xf752d9a5, 0x849a9743, 0x2436c3d9, 0xf73f7727, 0x1560884f, 0x3bac24fb, 0xba0fe08f, 0x5f5268c7, + 0x16edc7f9, 0x7f30f04f, 0x8ff6d364, 0x84082e89, 0x1fe25cd1, 0x9fcf5f26, 0x43b789e1, 0x098852fd, 0x325e5c40, + 0x1c2f58e2, 0x64da8f46, 0xcfeb6046, 0xe503f9eb, 0x0b90ca72, 0x54b285dc, 0xda7447f4, 0xc66b57cc, 0x2c020f7a, + 0x913bd4ba, 0xb59280a9, 0xabafb3df, 0x9e6432f3, 0x6db10c03, 0xee7d217f, 0xe261349c, 0xde5ef0d5, 0x3913da91, + 0x818c0ee5, 0xcbfda9d9, 0x7d0bd6c4, 0xe17fad04, 0xbcf72dd4, 0x7297814e, 0x6c55e084, 0xae46d876, 0xd2eba51f, + 0xddaa6bc2, 0x0de42a0f, 0xcaed5f41, 0x85a3310a, 0x2d413c9f, 0x22065bba, 0xb5d359db, 0x745e8670, 0x6499896c, + 0xc8f8776a, 0xee2b22b4, 0xa40ccad0, 0x14c00477, 0x9b98f6a8, 0x7eeeeca5, 0x4b770d3f, 0x6803f5ee, 0xb63d0c80, + 0x12f62d31, 0xdf034b72, 0x2792dc19, 0x125269db, 0xd752ea32, 0xacb122ea, 0xbb097038, 0x469ca562, 0x216da113, + 0x487b901d, 0xe6d2f04f, 0x276ad5d9, 0x578f5056, 0xc8030671, 0xb331fa99, 0x2f9bb2b0, 0xaed1cc4a, 0x73dfa20c, + 0x13cc8c8b, 0x8b7fb367, 0x9dfd66f6, 0xd9a31766, 0xa2d72b79, 0x316eb43c, 0x7a205d2b, 0x44441568, 0xe66ab049, + 0x99e77317, 0xa63c2180, 0x3dd2d99d, 0x7bf3f527, 0x3505664c, 0x9bb42538, 0x0fb443bd, 0x25f0bb8e, 0xf576eceb, + 0xd5942727, 0x6023a56d, 0xbb88f019, 0x73afc33f, 0xa5628167, 0x5fdd0442, 0x5377809c, 0x99b57cf3, 0x35e0cb95, + 0xfdd60aca, 0x34235383, 0x5ad656fe, 0xd698dd60, 0xcf578ff8, 0xaa4e3a29, 0x7be06635, 0x218c2246, 0x2c21038a, + 0x4bb601af, 0xceca145e, 0xe2920461, 0xd4dd0a1f, 0x212e642e, 0x81812ae1, 0x0b71d9fc, 0xb412ffc5, 0xa6679369, + 0xade7fd3f, 0xd651109b, 0x0885076f, 0x0c9c8cda, 0x0e51737e, 0x0ebe358a, 0x2cc86e21, 0xae88bea9, 0x90a6945c, + 0x6a8146b7, 0x1e3e2cf4, 0x65a30f6c, 0x8d31f376, 0xadfe0520, 0x10d0a96a, 0xb64fa85a, 0xb3f7491f, 0x5fac49c9, + 0xd97cf941, 0x21120d6a, 0xd398d8a4, 0x0da5de1e, 0x40e28bb8, 0x2bfe3142, 0x0fd88e84, 0x773dba86, 0xf85f0e7d, + 0x68344003, 0x1ae4a76d, 0x5559ade2, 0x185ce030, 0x3e569847, 0xc430f8bb, 0x4ebd2306, 0x153f1b65, 0x03be63f5, + 0xa87a7a9f, 0xbf0107cb, 0x583d296b, 0x82c1185b, 0x18622e7c, 0x705cb1a4, 0xdc187254, 0x3f978abf, 0xa7d238e7, + 0x95f328a5, 0x57cb95db, 0x1f40647e, 0xf8c901a8, 0x702c596a, 0xde77da23, 0xde54ab41, 0xbe9746c5, 0xc1d9c97c, + 0x4e5fc235, 0x0ea430e3, 0x77aa89a9, 0xf1cb8ad9, 0xca380948, 0x571cd0e0, 0x3e0e207b, 0x1cb7be47, 0xc1d5220b, + 0xd07b4907, 0xf14a3dad, 0x12184403, 0xa3b925a4, 0x2ddf3390, 0x6a234bfd, 0x398b3a9a, 0xf855a5a8, 0xe352faee, + 0x37c85985, 0xfa086518, 0xd40a72f6, 0x1631ab4a, 0xcf9a7225, 0xb764872f, 0x0afb4c7d, 0xe030b037, 0x27f97a95, + 0xc5f34b52, 0x921213e2, 0xd8807ef5, 0x383373f2, 0xfd940577, 0x5225490d, 0x3d91d07b, 0x84bd64f6, 0x7762cfff, + 0xd7ff0761, 0x18ad111f, 0x01fe56e3, 0x1138ed40, 0x0d37f8fa, 0x1790d338, 0x26306b04, 0xbc7034d7, 0xad380eee, + 0x6ca2f8c9, 0x9c74383b, 0x477a6325, 0x6b482ceb, 0x7666e5b3, 0xbe22098b, 0x18af20e2, 0xe92c0bff, 0x3cf061cb, + 0x6648790d, 0x03fe1d3d, 0xacbaba65, 0x73aa6a18, 0x3b20cbc5, 0x8320486e, 0x0b7d15c4, 0xf59f02f6, 0x46c71192, + 0xab55376d, 0xc9c210e9, 0x815657dd, 0x1e64daa7, 0x804a35e9, 0x1e79d518, 0x09e68973, 0xb85d5afc, 0x32457987, + 0xcbf20e86, 0x47141279, 0x4746668a, 0xabebba4e, 0x426e3a8c, 0xb53b09c5, 0x57797b7f, 0xd3ef75de, 0x34b00e2a, + 0x1a665231, 0x52ccab70, 0xc1e2f29a, 0xa635262e, 0x91d6cf5e, 0x41540ba0, 0x97bbaf6c, 0x13c35112, 0x52c3caac, + 0xa6d50128, 0x4e679a26, 0x63bbbea6, 0x0c7256a2, 0xc9c1b72c, 0xe22934d1, 0x17ff5614, 0xb6096327, 0x35470bf7, + 0xbf663af1, 0xb389b2b0, 0x40fc5202, 0xc81f5d5a, 0x1aeee85c, 0xfa1a89f9, 0xc15c0f5e, 0x5e6d841d, 0xa25e6118, + 0x6e5b8aee, 0xb9fd9737, 0xda117ca5, 0x4e93a1b4, 0x69adf3ad, 0xbe04963b, 0x3d0e7132, 0x3db6f2f4, 0xc7e215ae, + 0x426d184f, 0xe63b3572, 0xbd681149, 0x3017b5bd, 0xf697b3c2, 0x88214469, 0x4192dffd, 0x107b2eb8, 0xb14e4a1b, + 0x8bed4170, 0x4aa9cfbb, 0x78912389, 0x5fc89977, 0x518d1006, 0x8077c3a8, 0xb295f833, 0x0891a4c7, 0x1f94e935, + 0xa9f13be0, 0x4fea7ad5, 0xefae50cd, 0x9657117c, 0xed19a474, 0xc28ea4d7, 0xe26bdcca, 0x45f5b3be, 0x8cbae64d, + 0x92d6b7e7, 0x05961664, 0x31cc0e7c, 0xa4806f2c, 0x884f6892, 0x280f2ebb, 0xdeda8411, 0xf6160a5f, 0xfe6cf207, + 0xe4ea979b, 0x75510e53, 0x2f5065c3, 0x8150e8a0, 0xb6c83345, 0x1408eb4e, 0xda867c52, 0x78e98a72, 0xa0a408a4, + 0x33bbf86c, 0x4c4ce03a, 0x4b266b79, 0x07db9a27, 0x19bfdc10, 0x8b371661, 0x6c11f453, 0x3f0a62ac, 0xe14dd9a9, + 0xbbb08c48, 0xbe1c29c2, 0x0b7de3bb, 0xfc076eee, 0xd4a1d386, 0x07926547, 0x535c99fb, 0xb16b1e3c, 0x01f86759, + 0x499cbc5e, 0x1414fd6c, 0x0603224a, 0x52b01eb2, 0x84dddf24, 0x659891c3, 0x09540759, 0x49dabb42, 0xa2d6ad78, + 0x10cf8d1c, 0x15fbe4a9, 0xb83aeee8, 0x786735ca, 0xe2b8c6c7, 0x90ab41f8, 0xcbdd9142, 0x7309f501, 0xd7270ec7, + 0x0be40e0b, 0x38ea03c4, 0x425f57d1, 0x4b69140a, 0x7fb59a02, 0xae82207b, 0xc8b0db28, 0x14cdb13e, 0x69c0a814, + 0x0f3527f5, 0xb0df3b99, 0x32d6de47, 0xd000b314, 0x4f03350a, 0xf82e987f, 0x7b2e3d4c, 0x79559067, 0x9115b499, + 0xd417fc24, 0x4a21826e, 0xda6534bd, 0x5d40ff36, 0x8f3d6a0a, 0x1bf095ef, 0xe28d17e7, 0xeec6f929, 0x3090e344, + 0x838e47a7, 0x06bd9188, 0xe1b501b6, 0x04f6f5e4, 0x8df9e072, 0xedffceca, 0x5e23c069, 0xe9040dd6, 0x91f3b3e9, + 0x1bbd35e3, 0xcdfecf98, 0x19af17b0, 0x5c9bd9cc, 0x268bbb06, 0xcefde610, 0x06383dbb, 0x072e2da0, 0x9a0e69e4, + 0xa4d510c1, 0xe55b89fb, 0x0cf8814e, 0xdcd2c325, 0x2095bd88, 0xb2395c4d, 0xa8dd849d, 0x977a99f9, 0x6edcfd15, + 0x146061f9, 0xa543374b, 0x98b45171, 0x3437f0a0, 0x640704c3, 0xcc59d00f, 0x30e62295, 0xa1b1e5a6, 0x888db4a5, + 0xaa14e20e, 0xefc76f6f, 0x1f323514, 0xeccca5a9, 0xbc98deaa, 0xd1010589, 0x3bab8a99, 0xcc424b2b, 0xd9288454, + 0x1aea63be, 0x44d0c5d9, 0xdbc3d5ca, 0xcf2d3560, 0x9111cda0, 0x8093fa57, 0x8fb1db07, 0xc35d0411, 0xc4506804, + 0x3053bb7d, 0x8e99d730, 0xb030d0e7, 0x2bd5296c, 0x0ead0b91, 0x9d23985f, 0xa3ecf7e6, 0xa41da06a, 0xb7edd715, + 0xc64a7f84, 0xd7d50408, 0x4cb5269d, 0x830771dd, 0x7b00332e, 0x6b618112, 0xa3b87e43, 0x6fb7da28, 0x39986367, + 0x881eacc1, 0x317abae2, 0xe5804a55, 0x7f54d3e9, 0x71206691, 0x00c777fd, 0xfe4195f1, 0x43622667, 0x9d749c4e, + 0x7a973854, 0x3da33080, 0xdc241cdb, 0xdccd1d2d, 0xa4b10a42, 0x11b950fd, 0x7eb50360, 0x435f6ad2, 0x898eebf9, + 0x9fe3d442, 0x985b7c46, 0x8a29acec, 0xad12b816, 0xd50ae3a0, 0xe4363ea1, 0x5429bd41, 0xeb8ba487, 0xd6ebb34d, + 0xa983cd81, 0xa92bd037, 0xb7ebddd0, 0x7228589e, 0xe5db068c, 0xd63e8272, 0x8be7be42, 0xaf3b3f02, 0x67c5dd70, + 0x8f926f4e, 0x17d3d63b, 0x977532ff, 0x0e97b02f, 0xcac66c47, 0x7c6d794b, 0x468c315c, 0x05f6e158, 0xb6c9f072, + 0xd3755cac, 0xb33e2b29, 0x3214a7d3, 0x4f3c6d0b, 0x1ec3acbe, 0x357a250d, 0x543648fa, 0x6b2ef1d6, 0x983ee4dc, + 0x6f68b146, 0x4bd1111f, 0x0ae291da, 0x93f2ec4d, 0xd99c6f17, 0x2075c42b, 0x8faa7273, 0xb95ef18f, 0x9dc3f563, + 0x8c5837a7, 0x98aa5f5e, 0xc328d06a, 0xd6bf3994, 0xc99cece0, 0xa3b7082c, 0x21e360d8, 0x4dcbd2df, 0x17e9a60d, + 0x1b876a14, 0x1d1998c4, 0xdfab78e5, 0xf3a675ec, 0x087c9981, 0xcc7ca17a, 0x066b8bb0, 0xf009c737, 0xbf2dbbf8, + 0xf64fc5c1, 0xab7ffc30, 0xded92505, 0xc79b4808, 0xb2fe8a67, 0x3dfa5f57, 0x6721f52a, 0x63cd397c, 0xa04b4bde, + 0x152f9de9, 0x92503b09, 0x384d6891, 0xc5acce21, 0xde5a56d0, 0x7b17ccf5, 0x784e94bc, 0xecb608f9, 0xa3dc7fad, + 0x57daf750, 0x6fd03d7f, 0x7894f2fa, 0x45e75bd1, 0xb88d220f, 0x731f09e1, 0x36e4b6a7, 0xc1c09443, 0x7c29484f, + 0xcece917f, 0x6faba45a, 0x57914d86, 0xfa5e6114, 0x9cc3cc78, 0x4ea3b388, 0xb87f5276, 0x34738086, 0xaa97f3cb, + 0x4ad87396, 0xb5b44921, 0x5380c1ca, 0x33729c48, 0x71b98bfe, 0xc20a4315, 0x710588f7, 0x97376b1f, 0x2a87a2a0, + 0xa5e254f0, 0xb30c66eb, 0x5c11fea9, 0xc7e5c5ec, 0x35233793, 0xdaf20245, 0x4d8efe14, 0x2d13b556, 0xf17b55fa, + 0x2f62cc28, 0x32a7e0f6, 0xb98faf8e, 0x7ea28927, 0x07f62944, 0x1e6f2b67, 0xde0e2293, 0xb630df0f, 0xce753ac6, + 0x18265c44, 0x67d84b80, 0x5a3124a4, 0x20e35727, 0xa9f01b0c, 0x9e5100f4, 0xcba9a081, 0x12863509, 0x4bc4dec3, + 0xde1c37ee, 0x35e2251c, 0xb8a11cb8, 0x36babbd9, 0x3a074e5d, 0xfa0a3ff9, 0xe2f75c03, 0x8dc875e7, 0xd2b2d5cc, + 0xc24d6f10, 0xd1f3fb67, 0x5895f342, 0x8ae6979d, 0x78bb46db, 0xa23dd67d, 0x7cdc31f7, 0xb0b99c18, 0x4a692e66, + 0x30267efa, 0x895a3700, 0x0d0b0256, 0x2a061c1b, 0xae86dd9e, 0xaadd6a14, 0x97b5e6bb, 0xf36a6f46, 0xfd359c3a, + 0x4bb9b94a, 0xfa9775c6, 0x6f5a9863, 0xf9a58062, 0xfd027b19, 0x2beef08a, 0x9fcc8523, 0x72f6d88f, 0x3b19db0f, + 0x26749cd6, 0xd5ef2b4e, 0x0f23be56, 0x8f09d63e, 0x2a5f4381, 0x673bb864, 0xa21446f8, 0x0eb9b0e4, 0x44ea86ea, + 0x5b5093df, 0x146ed40a, 0x361f0593, 0x5f41495d, 0xec3ff52c, 0xc6a81e13, 0xa167b765, 0xaa70373d, 0x86730f4b, + 0xa2880c4c, 0x54585e14, 0xef152b50, 0x16bef199, 0x1aca5c04, 0x77fb356c, 0x48d4a209, 0x868e6c02, 0x4ce3d8e6, + 0x28cd6e5d, 0x0a44505b, 0x8d82eedf, 0xf0aaedec, 0xebc85baa, 0xf51bee8a, 0xf94e7056, 0x83805144, 0xc40c46a8, + 0x0322ded3, 0x2b052429, 0xb29ec939, 0xffe3bda0, 0xadfd9321, 0x4e996744, 0x67a89ded, 0x4d708106, 0x04a777e5, + 0x51710dee, 0x71a9de0b, 0x2b09e930, 0xf9e3b8d1, 0xa9877d51, 0x80708edc, 0xd71e8d20, 0x590eef46, 0xe9f9b49a, + 0xfc9987c1, 0x4de20e2d, 0x0e627718, 0x4851cfef, 0x3db77f49, 0x6d9b98e4, 0x2593440b, 0xda421717, 0x0c18a6d6, + 0xe9748fcb, 0xad50f9ed, 0xe4af7bfc, 0xac0752f1, 0xb6662062, 0x7374036f, 0x16c426d1, 0xc97414a7, 0x0be4829d, + 0xf2fdd105, 0x36adad08, 0xbdca9ade, 0x58af0980, 0x2609f103, 0xc1200362, 0x2c15cc43, 0x3c178ff6, 0x9a1b955c, + 0xede269ac, 0x17b46e67, 0x5b04ff0b, 0x131c7173, 0x405b8c3e, 0xd67c8d30, 0xfda2df18, 0xfc0a788c, 0xb230720d, + 0x8cada50f, 0x8e2fea2c, 0xe52e5996, 0x95e0bf7e, 0xe3045823, 0x10f27cb7, 0x807c740a, 0x01319580, 0x30ed7227, + 0x5afae04d, 0x0fb74b3d, 0xbd9a48eb, 0xc3c56250, 0x790573cb, 0x0ac16885, 0x5f67d200, 0xfb320488, 0xa9e563ba, + 0x1a2586f7, 0x87f07bba, 0xb1b7eb33, 0x22cf3d24, 0xa2b1056d, 0xf9005117, 0xad225804, 0xf81e4a6f, 0x1eafa5d6, + 0xecc67a50, 0xdf4115ec, 0x9a94b96e, 0x42887deb, 0x56f672fb, 0x973a819b, 0x38f55342, 0x1afb7047, 0xc5261ea9, + 0x3ba8c258, 0xb895362c, 0xe09e925f, 0x69970aff, 0x1a0b5e2d, 0x7ed4183d, 0x2ade347d, 0x9b3bcfc2, 0x81a614e0, + 0x36f7522d, 0x7cafc82c, 0xff961b80, 0x98be18b2, 0xb1e7e846, 0xed3d1e84, 0x2f0ae88f, 0x401543a6, 0x97037f78, + 0xccfd85f9, 0x959aafc0, 0xff879d1c, 0x9aeff988, 0x04debcbd, 0x42d55003, 0xd330e6f8, 0x8e6373ed, 0xdef00ab6, + 0x1bececbc, 0x3154ea06, 0x07f6add7, 0x0e4b65e8, 0xff67cee8, 0x7701c963, 0xc73be4c7, 0xf05b4dc3, 0xa1bbeb7d, + 0x4ac6f9e4, 0x3c965314, 0x4f03454e, 0x26b9c33d, 0x848a18d0, 0xc2cd0b05, 0xd2c71a0c, 0x69f52267, 0xc368896f, + 0x4f0a9b54, 0xd929849a, 0x66c93721, 0xbd728d79, 0x2225b0f2, 0xd62547eb, 0xac1d322d, 0xb1cc198b, 0x09e58640, + 0x6b598398, 0x943f4271, 0xb32d4f75, 0xc5606ee2, 0x29b1094f, 0xcd4e2f7d, 0xe80431a4, 0x245bc6f0, 0xbc155828, + 0x877e9e3e, 0x37856c49, 0x3bd82b66, 0x14bdcbea, 0x92b2f122, 0xe2c23288, 0x1cffe6df, 0x1af3e581, 0x28a91535, + 0xea870e66, 0x3342959a, 0x07e43c32, 0x768a73be, 0xce32193b, 0x42990702, 0x2c689619, 0x790123ea, 0x620a04c0, + 0x57a13b19, 0x406278b2, 0x82cc1216, 0x74dda2fd, 0x54385636, 0x51e1f166, 0x1c59e598, 0x0d29b5a1, 0x02797300, + 0xdcd2cbee, 0x8cdf2eb5, 0xc6e0f90f, 0xbf5a2620, 0xfec6ee02, 0x0335eea3, 0x46a72381, 0x1fe5ebb0, 0x2bfde979, + 0xa27f45c7, 0xb019873a, 0xb47c08fd, 0x67ae4ca8, 0xd09fdde2, 0x13403c0f, 0x818f5f23, 0xeeedd8b4, 0x30af2bed, + 0xa050ab9d, 0x872ffa88, 0xc5ce2acd, 0x66bd027e, 0xd09cc5ba, 0x2e8a12af, 0x99886ab2, 0x89f32a93, 0x6393afb9, + 0x1f246442, 0xda9268d5, 0x3e49568d, 0x8d69a721, 0xa5bb8871, 0xf27e1f68, 0x13b95078, 0x6eef3b71, 0xe602056e, + 0x0a58dd49, 0xd3efe739, 0x22ab19e0, 0x8dc42007, 0xea42890e, 0xcf018acc, 0xb9102b62, 0x646461b0, 0xa7ae8717, + 0x8047cf79, 0x869b433d, 0x0559baad, 0xb2c77d16, 0x84260ad1, 0x643dd061, 0x12bade89, 0x15c7c818, 0x33d3473c, + 0x51687159, 0x6626bf0c, 0x28d5a1eb, 0x47a605f6, 0xf2731c95, 0x4e9e51cb, 0xa6ba8fa6, 0xe7480a60, 0x699a489c, + 0x53a4a6ca, 0x4e3523e7, 0xfd6483a5, 0xc7b7afe9, 0xbdcf0115, 0xc0800c4a, 0xcdb99210, 0x1b0588b6, 0x9432224a, + 0x631df9c8, 0xfcb883de, 0x8bed1cc7, 0xad4eb098, 0x30135726, 0x19a7b851, 0x2e50ad39, 0x9116f047, 0x6ccf8b57, + 0xfeb894e9, 0xf52ae1d1, 0xe4a3ff95, 0x42953a32, 0xed75c1ad, 0x1f1bb88c, 0xc08f61c0, 0xd2560e39, 0xa8429289, + 0xc1c917a3, 0x0500d66f, 0x8d3ad017, 0xe166856e, 0x07f069a7, 0xef2f8027, 0x85cc9c24, 0x307e8cc4, 0xf15080a6, + 0x7bc474d4, 0xdd200800, 0x2f8ceb41, 0x974db524, 0xa2639ed1, 0xd8aff8fd, 0x7fc07709, 0x2d6ab302, 0xc1143c1e, + 0xabc79cfb, 0xab640f05, 0xc1afa375, 0x7c1624bd, 0x94c5bd12, 0xabe11143, 0xa8fdcc1f, 0xa6574c7b, 0xa85587a3, + 0x08fdbca1, 0x71110b07, 0xcc88cb11, 0x5a908ac6, 0x5626374a, 0x40ac2400, 0xcd02de5e, 0xb26f04b7, 0x231e75a3, + 0xc22d5c13, 0x1710db9e, 0xcaf1bbbb, 0xbc7f3066, 0x324ffede, 0x936e6cd9, 0xca9d9d3d, 0x1f756b73, 0x89714827, + 0xd0b3f8d5, 0x6ac387d2, 0x2a07cbe2, 0xf5f26d87, 0xba0f0952, 0xdd71dac1, 0x2b927bf9, 0x150c4c4c, 0x3e220c3a, + 0xf258dbf8, 0x6d115845, 0xf43dc58f, 0x07c87341, 0xe4ec9dd7, 0xb096e87e, 0xbbc81c76, 0x482b38a6, 0x8d40cc64, + 0xadf895c1, 0xa3992ac8, 0x1eef6c41, 0x7fd3f832, 0x962987ff, 0x8fd6d289, 0xd7ffe0dc, 0xb5dc3d6c, 0x7d81dd4c, + 0xd55f17e5, 0x45dee199, 0x2498ee43, 0x04738029, 0x84122f99, 0x2965a2c3, 0xeb89ae7a, 0xbf57a902, 0x8b0078e7, + 0x1d23686f, 0xf835fb12, 0x47a93577, 0x55ddf03c, 0xc465b45e, 0xae1bfd6b, 0xa194007d, 0x84daa853, 0xc2f3df00, + 0xce62f6d5, 0x17472628, 0xdf740d6f, 0xd3d62992, 0x1b39dd7f, 0x6f87822a, 0x0c4a41d0, 0x627ebf27, 0xb8a8ad94, + 0xcd95a969, 0x5a3f7c80, 0xc3816fdd, 0x599cf30a, 0xe366acec, 0x1bf80db7, 0x6036a000, 0x05dd916f, 0x7e7c5205, + 0x00c6f282, 0xa162b093, 0xc766ef07, 0xe50b584c, 0xc6850c42, 0xb5f318d4, 0xe94f4c53, 0x15e0fe74, 0xb4843a1c, + 0xdb64d768, 0x9a68ef07, 0x0a09959a, 0x7eda9bf7, 0x50399290, 0xe5fb205c, 0xb7c58df4, 0xab1a38e7, 0xb67b88ee, + 0xb26bbdd3, 0x0668ce11, 0x1b82eeea, 0xeb904b51, 0xee304c8c, 0xc285ae26, 0xd23529ef, 0xb9917831, 0x09e68622, + 0x62749ffe, 0x0b255e4d, 0x9c75c7f8, 0x9d89e307, 0xb0dffac3, 0x880398c8, 0x64c53cf5, 0x9d7b8d66, 0x7bb95649, + 0x3ba0c95d, 0x880912e5, 0x0efb3a0f, 0x48155636, 0x2f8266fd, 0xd1b48578, 0x6fe02b5b, 0xd5c3ba2f, 0xe479c79b, + 0xeb039b13, 0xa57deb41, 0x28cc202c, 0xce48ad77, 0xb2fd2c55, 0x06ec1166, 0x0d3093f2, 0xf59429e8, 0xd1e0a286, + 0x09245fc5, 0xf0ac78ca, 0xb48b6429, 0x9c02249b, 0x1ade2754, 0xf172a765, 0xd90d74d1, 0x6039adef, 0xca4fbd13, + 0x00bb2c7e, 0x1a154366, 0xaf3ae80c, 0x67080965, 0xd0d35929, 0x37299aea, 0x5f727586, 0x03ebe240, 0xf12f3898, + 0x057708ea, 0x5a47b2b8, 0xf0b4f865, 0xe3a2ed09, 0xb915d3c4, 0xa2b0b1aa, 0x01363915, 0xc440bcb3, 0x63d1fe17, + 0x2c26f0fd, 0x2b6c6696, 0xcec0d40e, 0xb93d52de, 0x0895f761, 0x579fecf1, 0x99cfe1c0, 0x4f7c8fbe, 0x1a1c0cf2, + 0xd4ae2236, 0x19c065a7, 0xd4bd3416, 0x6f5baef5, 0x5f9711ea, 0xdbd71653, 0xc798977f, 0x402b8da9, 0xf1ddada4, + 0x06ffe446, 0xd67204e8, 0x389a0ece, 0xee5434ed, 0x0d2e357d, 0x881e6794, 0x4582a33e, 0xe28f7dc5, 0x13de5ed6, + 0x5bffd032, 0x39fa066a, 0x4e7f007b, 0x6043e714, 0x20fd31cd, 0x7928d6af, 0x7eba26ad, 0x8500aadb, 0x1accbbee, + 0xce90bcc1, 0xbf0d1f27, 0x95a12273, 0xa3d8bbe6, 0x4bea3a95, 0x66045eb8, 0xc875c533, 0x2d00aa3a, 0xee81087e, + 0x79419849, 0xb008eba9, 0x4a8917d6, 0x694b9158, 0xc812d8d9, 0x65873081, 0x01d087f7, 0x797bc8cf, 0x5afa36e2, + 0x4545e6f8, 0xa3be4e63, 0x348edec8, 0x63ae405c, 0xfa443652, 0xe5cce33c, 0x31f055cc, 0xd69b3cfd, 0xa22e718d, + 0xa7dc1b95, 0x54a1c9ac, 0x21e8cc66, 0xc623783f, 0xfe2ec656, 0x83e2eba7, 0x5fa14df4, 0x66064ff3, 0xa4050cfe, + 0xdc139307, 0xfe03b03e, 0x5c77d416, 0x89b63192, 0x200a9beb, 0x52362061, 0xb39f5cf5, 0x6ded58e0, 0x1cb6d03f, + 0xdfe9ae86, 0x51f5fb78, 0x05e6e034, 0xf2cd23c4, 0xe232ea94, 0x076c6063, 0xb6ecba4c, 0xb38637f5, 0x895cf217, + 0xb46df75d, 0xd723ffb7, 0x09405984, 0xa079b15e, 0xa4742d09, 0x8b277957, 0xe516ba84, 0xe179b891, 0x5b38a9b5, + 0xe428912a, 0x142eb79e, 0xf63bdb9e, 0xc9ffb397, 0x26974bcb, 0x9659b9a5, 0xce29ea03, 0xcf2b4f7a, 0xf92291f6, + 0xbb598327, 0xc73c440e, 0xe24a5777, 0x0935717b, 0x691676f5, 0xe63d6092, 0xbfcfa155, 0x82ab900e, 0x647789d2, + 0x4c502901, 0x4bc394de, 0xbc2fd194, 0x3d47c31d, 0xa6f04782, 0xd897661f, 0x22af31be, 0x46776d10, 0x8387068a, + 0x3b4b6064, 0x2c0387a8, 0xb91db315, 0xd3452987, 0xf9bac424, 0x2914d5bb, 0x8745e056, 0x94c6885d, 0x74126de7, + 0x9d463c97, 0xef299633, 0xd5efbb45, 0x80fec6bc, 0x841b562e, 0x1fb72568, 0xb3c426dd, 0x58354056, 0x5840b78a, + 0xeca62bd8, 0x810cab3b, 0x151d9ed7, 0x776c9ecb, 0xf1dce7f7, 0x65e3d4f6, 0x9c79798d, 0xa002235d, 0x98aeb819, + 0x76089427, 0x898a73cc, 0x5d3dd1c0, 0x2ed318ab, 0xf9dbefb2, 0xb7e5976e, 0x9ecac4a9, 0x6af4ea70, 0x334ddb97, + 0xec28108f, 0xce7b71a6, 0x1f33c4b0, 0x541cd2b5, 0xd9eab1ed, 0xb0647fd3, 0x75adb422, 0x95a0f0c9, 0xa0029d51, + 0xb4a79f2f, 0xcf7483a1, 0x9c51bf00, 0x575bd615, 0x58530607, 0xcff8d77c, 0x8d92a5a5, 0x71e848a6, 0x6d2cea8d, + 0x417b821c, 0xd77a81ad, 0x24740695, 0x2b2af59e, 0xc9a58f88, 0x488808e0, 0xc1fca4f4, 0x5da28963, 0xa1e00432, + 0x19937c0c, 0xaaa9a356, 0x421571cd, 0x1e00b983, 0x40f41d7e, 0x2304e30e, 0x347da8cf, 0xcba9668b, 0xedfa9185, + 0x0a38370b, 0x9d5f104b, 0x1e9a67ec, 0x112d2ca3, 0x340ea76d, 0x43b4f5fd, 0xdee42448, 0x08d1d251, 0x943e6e6a, + 0x380b84fb, 0xc5c4552c, 0x1f701fa3, 0x5e3495a6, 0xc41136a4, 0xe09d17d8, 0xb0190d17, 0x9ef78f77, 0xad20b726, + 0xfcf20cfa, 0x728d73e2, 0xca23eaa6, 0x1aedb4ac, 0xf1281de1, 0x6f752d21, 0x01679322, 0xf08c9f2d, 0x42fb04b0, + 0xf9ca8258, 0x5d4416f9, 0x5ab03258, 0x34dfa863, 0x6d3b9a0e, 0x516b1568, 0x68cd0279, 0x1a662447, 0x19d19cca, + 0xd64c74b7, 0x60059f2c, 0x50f28a7f, 0xfb26a5e8, 0xbc40793f, 0x22882145, 0xe996fc44, 0xa3be25bc, 0x1d76b395, + 0x27c75766, 0x616074ce, 0x90731de7, 0xf2683a32, 0x10a45d7f, 0x02bf9a92, 0x47536194, 0xafb65b2b, 0x1dbf9455, + 0xead818d2, 0x5100cc19, 0x99551d7f, 0x63f0f443, 0x9937ad00, 0x8d4c5605, 0x87dc39c7, 0x529c7079, 0x4f7058b9, + 0x35c396f3, 0x630699e3, 0x81beb0c7, 0xc4b3434b, 0x12df28e1, 0xc4d9a979, 0x1bacfe58, 0xfb15a868, 0xa8e50b49, + 0x6025fe3a, 0x9feec63d, 0xb8b737f4, 0xf2a34933, 0x89fba264, 0x2ee4f167, 0x83f57afb, 0x203bda42, 0xdac1349d, + 0x0b4cb731, 0x3501620d, 0x52a5c31e, 0x35ad8421, 0xdd87ba8a, 0x23baab23, 0x2b19d971, 0x75e2de3c, 0xcdddc465, + 0x1742c17b, 0xcd4a3b25, 0x54b99c1f, 0x24a961a2, 0x3b441f44, 0xb6f6028a, 0x608cc730, 0x45ef0a32, 0xad03b278, + 0x25aff881, 0xb2980c7c, 0xe0b9e9f0, 0x26039dc9, 0x285cffff, 0xcdbc7477, 0x08a89530, 0x9aafb011, 0x5376888f, + 0x3310709d, 0xe2c3191a, 0xee264a34, 0x176a3856, 0x2604332c, 0x034da18c, 0x9f19467c, 0xc0b9ba0c, 0xdd88ce90, + 0x5e154a91, 0x50220c87, 0x1fa83f09, 0x2fe58db5, 0x774f7d27, 0xc710c697, 0x7658114d, 0x84374d16, 0x79e919f3, + 0xdc6aade2, 0xdd6a5556, 0x106412a1, 0x56ff9ec9, 0xcc9799ca, 0x96ed9cfb, 0x394a8bea, 0x96ac0e53, 0x0ae58ede, + 0x6ed6a136, 0x6106aa64, 0xba6c627c, 0x1e58ee66, 0xb48ffa87, 0x294e665e, 0x6aebb347, 0x0584ab09, 0x91fb5065, + 0xba04721c, 0xeec0b8d9, 0x5a8454b3, 0x4a2431b4, 0xe0dcbf48, 0x3153bb25, 0x50909949, 0x0eea5fe6, 0x09b174fd, + 0x0e8d3ca4, 0x64cac883, 0xeb0407eb, 0x4e1997ba, 0xe87af67a, 0x143be850, 0xb87dfd4e, 0xf6917571, 0x71cc27f6, + 0xfe62b824, 0xdd0d1ac5, 0x6f518da3, 0x5d4bf1d6, 0x1a9da47a, 0xca8cf638, 0x9348a72f, 0x136754ca, 0x767d9681, + 0xcf1edda1, 0xcb106af4, 0xad987a36, 0x4dc9bc15, 0x6eb4667d, 0x7435a4ae, 0x58650369, 0xa63ad898, 0x653aafe0, + 0x947f05bc, 0x6b856580, 0xcefdfdd4, 0x9d6fa9d2, 0xddaff024, 0xae998f4d, 0x8ec4a851, 0x0853c1cf, 0xced53074, + 0xc84d064e, 0x179dcd79, 0xa0cdc991, 0x44d1142d, 0xa48d86f8, 0x53742fff, 0x18a3f51e, 0x8ff70ba9, 0x37da96dc, + 0xec5d661c, 0x69cf7631, 0x3f45f698, 0xa9fc705f, 0x2b05d32d, 0xd88f87a7, 0x5f21308b, 0xead30238, 0xda782b9a, + 0xe73ab692, 0xd9cb2e76, 0x938aaa6e, 0xc08178de, 0x84bd2ee3, 0xcc63b806, 0xe4ad5ab2, 0x22a04f68, 0x92367c87, + 0x44c300b7, 0x6b844cb4, 0x7bea7950, 0xd2cbdb4f, 0xa78b307c, 0x804bdf57, 0x68b55f44, 0x610d5eb3, 0x4b7149cf, + 0xc56ef8f3, 0x663cb71f, 0xaa58c03f, 0x530ae943, 0xdba89f14, 0xe9f06cd7, 0x16ce666c, 0x77e943b7, 0x78a9389d, + 0xcacb9fe2, 0xf715a7ad, 0x8dc86349, 0x5565540e, 0x320b1ac5, 0xe8d5bced, 0xaf1898ae, 0x298a94dc, 0x6ee7a831, + 0x08abfcb9, 0xc27724d4, 0xe58425f2, 0x8c41d6a3, 0x4a2487ee, 0x26f0ff7c, 0x17f89b16, 0x0b09d4ed, 0x22f12be7, + 0x78056f8b, 0x7e797a21, 0x51c27611, 0x9ef7ce0f, 0xb2cfa6f7, 0x4ca4d1ae, 0x9180bc68, 0x2e52d034, 0xe39c092d, + 0x1c37963a, 0x564c682c, 0x6f349efc, 0xd4a27e84, 0x9b20bdc7, 0x330f6add, 0x80c63cb3, 0x434e357c, 0xd3360509, + 0xe3fa1636, 0xbe8c90cd, 0x6d128053, 0x4d76464f, 0x9f0796a9, 0x949b0585, 0xb0e880a3, 0x2f23d20e, 0x70c58bc0, + 0x3b267623, 0x69d44a24, 0x3df5ea82, 0x3af61b5e, 0xbc08b6d4, 0xb679caf7, 0xb1bd1891, 0x9cc0fcd2, 0xd095c2ef, + 0x3a38a151, 0x20e80f8f, 0xd8b416bf, 0xe2a14890, 0xfc579f22, 0xb861bfa7, 0x32bd6a4d, 0x2dc2f681, 0xfdeb2d2e, + 0x073cc5dd, 0xbacc4e19, 0xd30ca0c9, 0x2e45ce17, 0x64abbc49, 0x5e18da04, 0x566648a2, 0x2350d7fd, 0xdb6ae101, + 0xe1e2e3ed, 0x73197617, 0x8698c6f3, 0xdbcc05e8, 0xbdab9399, 0x8082b4c1, 0x3fcebda7, 0x23b10430, 0x53dcc4a4, + 0x99b90bc6, 0xefe049b5, 0x2c85d171, 0x5aea2537, 0x5e66a472, 0x87f62a69, 0x01d30466, 0x1b0ee3bf, 0xb6cc6f81, + 0x0e893875, 0x464a6019, 0xb8b7a404, 0x7fa84c6a, 0x29cf63e7, 0x32f04df0, 0x9ca209b0, 0x924eb555, 0x5071a0dd, + 0x009b90e8, 0x1c0168d2, 0xc29b9ad7, 0xe1ba6cb4, 0x70e3bc06, 0x609ce8a7, 0x565a23b3, 0x4ffa6ae0, 0xa86503b1, + 0xeddec967, 0xc279173b, 0x7b112e00, 0xe4e3665d, 0xae5dad19, 0xf5951dea, 0xb9c88e73, 0x07f181f6, 0xb5e050ee, + 0x5726220b, 0x4ce545cf, 0xf2f7e78b, 0x84345e65, 0x1bc2bc7b, 0x7103c4fb, 0x8120e2f1, 0x6699c174, 0x9fbb92bc, + 0xeb3e7152, 0x278e602c, 0x359a7c48, 0x69d0e8dc, 0x98870a46, 0xf1c82944, 0x5e82255b, 0x7d44e355, 0xf5eb3918, + 0x488e23b9, 0x014c5b4b, 0x9f631f80, 0x31a1d375, 0x5980d14f, 0xe121b771, 0xd9350678, 0x4360cbf8, 0x606cc8a5, + 0x070f29bb, 0xd93abc26, 0x069aaf85, 0xbe78b8e6, 0x9fe76991, 0x9f9b1e00, 0x7adfadab, 0x27286a76, 0x19631fe9, + 0xd24aeb96, 0x11863449, 0x675f8828, 0x70a19554, 0x1392cf3e, 0x20bc5688, 0x99f7e9b1, 0x691d149a, 0xd3f8ec27, + 0x56644f71, 0x53857641, 0xf18eb5c4, 0x00a0f8a2, 0x4c26de68, 0x43c1ddae, 0xbf2647bf, 0xa3d26481, 0xfc8c5717, + 0x1c55e782, 0xaf802b1c, 0xd58f3157, 0x2bb8102d, 0x8822b1be, 0xa90d72ea, 0x0ddd8b45, 0x55927749, 0x0c6211b3, + 0xec1cf007, 0x83fbc52f, 0xde1e04dc, 0xbd64f702, 0x1d1b5718, 0x60b5c610, 0xc872a068, 0x616c6054, 0xf8ea88dd, + 0xf8ea9af6, 0xd6ee28fc, 0xe0728dda, 0xd6d7810b, 0x450e1a2c, 0x6cbf8dfd, 0x28736f87, 0x9131f9ce, 0x25eb4a53, + 0x860578cb, 0x6883f0e2, 0xa3d29cb3, 0x68398dd2, 0xee78b74e, 0xd482c858, 0x4d10a877, 0x65e1bbc3, 0xd829eef3, + 0xa76e72ec, 0xbc68ffd9, 0x13569821, 0xf374f445, 0x382ef1c6, 0x9f2386c6, 0xb92c9679, 0xbc604662, 0x41487283, + 0xb625fb83, 0x8012bee0, 0x4344d2de, 0x8c10381e, 0x7282419e, 0x8001a8f7, 0x4a87767b, 0xd94c229a, 0x81c70de6, + 0x315887c7, 0x1822be5b, 0x704bbfda, 0xf33f711b, 0x82cf3ec0, 0x242cc521, 0xb360beb9, 0x4d7015f4, 0x64bedcff, + 0x54555504, 0x3ba80176, 0x408ee987, 0xa936e18a, 0x6490fdf5, 0x9f850ed2, 0x0dce335a, 0xbcc7db22, 0x8269dfed, + 0x1dd62005, 0xddb0e897, 0x89afc89e, 0x50e89986, 0x3da0bcd0, 0xe44eecc6, 0xb645d30b, 0x8facdd9b, 0x918d7f89, + 0x10f4a713, 0x97c6ee6b, 0x72383678, 0xf2fb311f, 0x70dec647, 0xbc7d6cfc, 0xe9321ba8, 0xa11e26d1, 0x5125175c, + 0xf6a13558, 0xf5a9c3a6, 0x6fce2c26, 0x39faa2ee, 0x88091573, 0x695b2aa4, 0x75e0adea, 0xe4d7439b, 0x85f777d3, + 0x904fd2d3, 0xca341a00, 0xa4a970b7, 0xf8ccb549, 0x9cf0420c, 0x823a2105, 0x678bc8db, 0x039e99a0, 0x584383e2, + 0xdde275a7, 0xd942b82f, 0xcaf006f5, 0x1eb29b2e, 0x1da8aa51, 0x21e52c35, 0xfdeb6ad9, 0x7a5581d9, 0xfe7b99a4, + 0xfa1c76e1, 0xae99b6be, 0xb53fc163, 0x7baeb3db, 0xafe3f93f, 0xb20c996d, 0xc84d3c9f, 0x33621198, 0x26cef61c, + 0x1c1d5351, 0x1be9faa3, 0x99d59d23, 0x295f20ad, 0xa1618c67, 0xf6b908d5, 0x5621b5cf, 0xc319a1bd, 0xff1f3fcc, + 0x5c96b706, 0x70bec7d0, 0x11720cae, 0x29d666ea, 0xde2a5aa9, 0x6e5ea1f4, 0xe6649e9b, 0x0db5619d, 0xe70a0e04, + 0x5abd0bb0, 0xcc42f039, 0x6fa01029, 0x21f79fd5, 0x4df5ba35, 0x1cba7107, 0xd659ae91, 0x165a5d42, 0x60c715f9, + 0xe2fdd229, 0x4165d15d, 0x726b3aba, 0x45194fdc, 0x77d91bd9, 0x144f3973, 0x6c177b72, 0xbf5360ab, 0x358e87be, + 0xe204f601, 0xb37f09ba, 0x8a58f62a, 0xcca08fa5, 0x3b147e1b, 0xd50e7509, 0x54ff0651, 0x6741f129, 0x669523c4, + 0x084b147d, 0xe9c6f5d0, 0xf1fbef38, 0x6f491937, 0xb0509c9d, 0xebb5ff17, 0xd622e994, 0x9bcc358a, 0x18998f38, + 0x6938b7c2, 0xd6c621e2, 0xce0a26e5, 0x7ab54f7b, 0x4b79a71d, 0x229ca27a, 0x274ff780, 0x62add93b, 0x666c1ba4, + 0x15cfd0ce, 0x6bd012ea, 0xb9b21572, 0xdf353225, 0x8fbd62ff, 0xfe4f5635, 0x40c296b2, 0xe2d2a44d, 0xc97b107e, + 0x852788b9, 0x5eb9465d, 0x980e21ae, 0xdf529f1f, 0x81d63fc0, 0x827d5ae1, 0xe5c3b239, 0x1802a4c0, 0x02839a8d, + 0x9083056a, 0xbc2653e3, 0xdac27920, 0xe073840c, 0x608a7a8b, 0xafe8235d, 0xca10d46d, 0xafb980fb, 0xb0438ff7, + 0x4c80fec8, 0x335fb72e, 0x996a7a57, 0x1aa391fa, 0xf5020698, 0xa13ab9f8, 0x9f6aad3e, 0x5cb671b9, 0x3d69619d, + 0x9464f8ea, 0xf06f166c, 0xcaad5298, 0x0d907ba5, 0xd5ba000f, 0x66a1440e, 0x6daeefb4, 0x97ed03e9, 0x8586804c, + 0xae793c56, 0x7595e833, 0xeb058843, 0x125c1c96, 0x0df07d87, 0xdabc839a, 0x074a4492, 0x6faf4b46, 0x1cd8e07a, + 0xa51268e6, 0x4f48b4d3, 0x65628832, 0xc11620ca, 0x13d90652, 0x5dd8cc5c, 0x688d16c7, 0x674dc6d7, 0x3c212fb9, + 0x226b31f3, 0xa150a355, 0x0f8d6eac, 0x20f1bd47, 0x9f3c5186, 0xdcab6216, 0x3c35e2a8, 0xb8116e33, 0x1d5ee4e4, + 0xe382f003, 0x7522736f, 0x78d5df84, 0xbcf97c06, 0xd242723b, 0x7b88431d, 0x0b191db2, 0xaec1c441, 0x4e512d0f, + 0x71f56d40, 0xd58bbae1, 0xd7dabab0, 0x93f82a74, 0x131833cf, 0x2168658a, 0x05ca83bc, 0xd171572d, 0x230aba25, + 0x05afc1b1, 0x491669ce, 0x543eb875, 0xb8e2093a, 0x1298d1a7, 0x99cc2347, 0xd5e2fb2c, 0xcf936b00, 0xe633488c, + 0x3a688f1b, 0x5d7c7527, 0x4b2ec989, 0x4c694adf, 0x14e423f9, 0xbd85b48e, 0xf1728736, 0xec904cec, 0xec28801d, + 0x0f5551db, 0xde4f4591, 0x6db9cee6, 0x628a2a51, 0xd8f19279, 0xae5dff89, 0xf62ab35e, 0xafdb4946, 0xfc154c9b, + 0x4c9fbf90, 0xcb76d9c2, 0xf1b38825, 0xcbe9ef64, 0x9bbb8e76, 0x5d05d9b8, 0xe75e59a9, 0x416fc670, 0x7d8eee23, + 0xe784b4f2, 0xa1068bae, 0xf90c2892, 0x27923a8f, 0x7a8068e6, 0xf8b8a017, 0xe499694d, 0x3d264493, 0xbbf733e5, + 0xab2c97e1, 0x50391f95, 0x17d42593, 0xe026d8ed, 0xb5e76930, 0xe7bd523d, 0x29d0c66a, 0x11886f05, 0x418e02a8, + 0x9e24dae3, 0x5896423c, 0xa715c631, 0x4d15264d, 0xf18db004, 0xae9402d3, 0x7d8e78c5, 0x4a497ef9, 0xe3751ac0, + 0xcc4922cf, 0x8dde4601, 0x7a7e8444, 0x48ecbceb, 0x9f0eb7e0, 0x1abf9708, 0xb4079b3a, 0xa944b477, 0xd7ce5a06, + 0x01fccb9b, 0x74588da1, 0xce36f447, 0x8b940f0a, 0xc9daa0fd, 0xff5f8cc0, 0x15d7e17c, 0xba0f26ea, 0x18621d59, + 0x79c23690, 0xb6cafe67, 0x98e40b91, 0xd02eaf11, 0xef4de746, 0x32a7a694, 0xb9367e93, 0x79feb005, 0x11e9792f, + 0x725e905a, 0x620c3bea, 0x2bc01d0a, 0x1622c005, 0x75f579ec, 0xdd68d951, 0x133dd76f, 0x5df5db61, 0x1e4750a6, + 0x088b45ba, 0x4f378192, 0x334de598, 0xd80d195a, 0xe51bbdeb, 0x2bce39bc, 0x148be55f, 0xd675c6be, 0x21dcbffe, + 0x56f41c6b, 0xdbf4daa3, 0xe3abbf18, 0xf5d1b7be, 0xbfcea004, 0x38fef830, 0x4f39a97d, 0xdb29c2d3, 0x04a0191f, + 0x426686ca, 0x4520b05d, 0x32dc4dac, 0x81cfd605, 0xf2670802, 0x3f411d86, 0xa68fd33c, 0x4587a273, 0x019af75f, + 0x60f75f26, 0xec0296d8, 0x1f038029, 0xf379436a, 0x456ab76b, 0x2237539a, 0x53138a05, 0x1d56b36e, 0x29a83fcf, + 0x06ba60ed, 0x7762725f, 0xffb05b75, 0x56ef0696, 0x83434ce1, 0x9873907b, 0x2762a56a, 0xbbf7e28d, 0x56c1f3bb, + 0x0dccc157, 0xac7d9561, 0xf64428f2, 0xb74358c0, 0x340668d2, 0x760392fe, 0x0fe63cd3, 0x2ccd1044, 0xa806f953, + 0x8c3b1e24, 0x6e567e3e, 0x34e3d976, 0x4f390bdf, 0xe9e02a82, 0x0ae93703, 0x2afd0b32, 0xf3d75151, 0x1c0be553, + 0xcf7079af, 0xb9895bb1, 0x3fab4322, 0x8d133d18, 0x9697dd12, 0x750de828, 0x14ac3a18, 0x2acaca3d, 0x0b346eca, + 0x4eb05b59, 0xf8c3f698, 0xa56042d6, 0xc707e60b, 0x8597f721, 0x79b3e4d9, 0x0bd5da8b, 0xc4e88a4d, 0x69847fd9, + 0xdde90d2c, 0x4827020e, 0xc9814d01, 0xa67128ac, 0x986061af, 0xf8390b0e, 0x7fbd0e97, 0x57af1fc6, 0x10cddea1, + 0xe19ac52b, 0xd0e0b3b6, 0xf7e16075, 0x830b02eb, 0xc38d624d, 0xbda45ef1, 0x1f8c9aa7, 0x0c347558, 0x273aa7a7, + 0x8d8277d8, 0x4ef6104b, 0xa53626c5, 0x14ba7e93, 0xaffafcb7, 0xbf47a00a, 0xf559605d, 0x11c0ff2e, 0x55af3e7f, + 0x5e56c0fe, 0x7fc772a1, 0x95ddcac4, 0xa684b5a1, 0xabdeb617, 0x3abf524a, 0xfdfba2ea, 0xf63f4dae, 0xf61abb2b, + 0x10b23587, 0x52c5872a, 0x07f17fef, 0x15652bb0, 0x49c14f76, 0x156774d5, 0x02c65248, 0x1062e0e1, 0x5f27d701, + 0x2af9a825, 0x1c888d18, 0xfdbac634, 0x8d5f0e57, 0xb33d3f9f, 0x47891586, 0x1445cf1d, 0x4e5a4e74, 0x50b8beb2, + 0x589940c5, 0x82e21a68, 0x97feec31, 0x74188396, 0xff05187b, 0x5786bb7a, 0xaf75860a, 0x8d64e0ab, 0xef9c627b, + 0x3be097e8, 0xb3cb5cd0, 0xbe78beff, 0x227c603e, 0xed721c26, 0x3972f2d4, 0x15946c3b, 0xb93485be, 0xe39db447, + 0xae93ce90, 0x51cce519, 0x2a9c3628, 0x54e006c3, 0x0112a5b5, 0xd0576222, 0x9af9a679, 0x6d12fb07, 0x975e72b9, + 0x96e2ed6d, 0xf8233dfa, 0x94ac96ca, 0xe2d486ab, 0x480f05d4, 0xa01355ae, 0xbeb15085, 0x5f6fab08, 0xfc36bf15, + 0xf3f4df04, 0xe89382da, 0x09a336cf, 0x9367f8b4, 0x0e147c0e, 0x9274e09c, 0x3e606c23, 0xa60f5817, 0xc9fd8ba2, + 0x39721c98, 0x55ed93c6, 0x316ff4e9, 0x38799846, 0x68fcbe0c, 0x4bc434ee, 0x92f67049, 0x5da67bfb, 0x53080a84, + 0xfa78cb40, 0x650b403e, 0x1b10d346, 0x5ac042c6, 0xb03d599c, 0x8767b936, 0xaf79cac9, 0xdd5a0909, 0x013e534d, + 0x0cd063e3, 0xb70ad70d, 0xf38b5468, 0x047e8d50, 0x0893a8e9, 0xe50a9bfd, 0xa394d179, 0xc255924c, 0xc65debbf, + 0x22400c8e, 0x8d894237, 0x3be27d89, 0xff9c6530, 0x3c275c03, 0x2462dc88, 0x26f93424, 0xabb06059, 0x6260974a, + 0x0ec50d2a, 0xcc000368, 0x088bbc8e, 0x46154a40, 0xb1ae0c26, 0xe6d8cb4f, 0xde5dbbe6, 0xf14e7dbd, 0x794f8403, + 0xcebd9b1c, 0xec538b2e, 0xdf25d680, 0x908561db, 0xea3d0c58, 0xa10588d8, 0x7a9ddc16, 0x6434e6eb, 0x96cacb78, + 0x4f005dd6, 0xe2b35297, 0x55b0cd6e, 0x19a8b820, 0x23b0464d, 0x59632ba1, 0xf6c3d44f, 0xe27bef55, 0xa198bee7, + 0xe858c66b, 0xaa6d7b49, 0xfc2d378d, 0x5b526f3e, 0x13efee68, 0x05d190ee, 0xb2c93a4e, 0x6fedcfaf, 0x4351bc99, + 0x79e5254d, 0xcfd82685, 0x2d8ea8f4, 0xb264f56e, 0x9b453a37, 0xd61a427d, 0xcd37e856, 0xbdc05ea2, 0x8a46b07f, + 0xd273ef88, 0x74078f61, 0x56676a9d, 0x999e3c25, 0x0df63c0c, 0xe2f84d2a, 0x139be8af, 0x77cf2537, 0x1416510f, + 0x53b6bc0b, 0x508b4915, 0xe817a323, 0xc91bdee6, 0x8328ee9b, 0x1f81dbf4, 0x1e4a7324, 0xb423a086, 0x8d03fcf7, + 0x0a14eb46, 0xb7e7692b, 0x2a42859d, 0x9c9408c7, 0xa3173e57, 0x9b11978c, 0x209c0658, 0xbf1cec24, 0x3fd8f09c, + 0xabc3dfe0, 0xa018e2d8, 0xd7665751, 0x4d6c33f0, 0xe4784369, 0xf892e19e, 0x36cdddb2, 0x9bd4b748, 0x3a49653b, + 0x41e2a4dc, 0x7bfc6c5f, 0xc8fc42d7, 0x1a19d641, 0x9c1b95a0, 0x56d7f56f, 0x2f73383a, 0xcc177e68, 0x48df2648, + 0x55720619, 0xfc7fcf3c, 0x1dbd47a2, 0x6e470347, 0x27180f66, 0xa1d768ce, 0xe7828add, 0xb88579f8, 0x68bf6c67, + 0x05a1abb3, 0x6a1c43b3, 0x4179f9ee, 0xf21db8a7, 0x03df6211, 0x341eeddf, 0xc8963ec5, 0x66a49a41, 0x2b663758, + 0x6daeefaf, 0x4a76b282, 0x33db8061, 0xbf9de72f, 0xd6469e31, 0x6e031094, 0x3f236d3f, 0xe068f62d, 0xb54a235f, + 0x1eddceff, 0xa4ddb71c, 0xe7453ff7, 0x7a8197a7, 0x11f42fc9, 0xac15678f, 0x2f33413c, 0x77ef575f, 0x5a326999, + 0xcecd91dd, 0x6b61a64b, 0xa0fb84f0, 0x3f848f8a, 0x07d88d9c, 0xee1b24d1, 0xdc36618a, 0xc48048b1, 0x032a701e, + 0x7062774d, 0x34b6c0dc, 0xf17ecc55, 0x34aa46c0, 0xed54ec35, 0xccf48db1, 0x88200a6a, 0xbea26321, 0x5d20d60c, + 0x2aad01e5, 0xa2f9de36, 0xf5fcbb43, 0x11b4a078, 0xc4cf4ab4, 0x8b09accf, 0xef06971b, 0x6da416fc, 0x1b2f2a10, + 0x837fa844, 0x521c513d, 0xc43c50fd, 0x7d7c9e00, 0x39ce4637, 0x0641efec, 0x9dac50e1, 0x419ef7f1, 0xf792344a, + 0xb1866da1, 0x79159181, 0x0f8c82a9, 0x5b8a3965, 0x71db1785, 0xfad43e42, 0xe4816e92, 0x8b4acd03, 0x7317400b, + 0xf795ce9e, 0x8045a001, 0x15c82139, 0x4b46e714, 0x1fe2a6b5, 0x328c7cba, 0xe22a5aec, 0xd3384f9d, 0xb6194057, + 0x0f7bf6ce, 0x6738a1ff, 0x30e9d450, 0x5e385a8a, 0xf46db4cc, 0xe8999b07, 0x824c71d2, 0x0728aad8, 0x0ec739f1, + 0x8c750793, 0x8389b368, 0x03d33d89, 0x252eb969, 0x9b2ffab4, 0x7e131f9b, 0xc06a2830, 0x83cfb9ab, 0x0cf91a05, + 0x4c52f0be, 0xf64743e3, 0x955e8f88, 0xc6e2ffab, 0xfcf6b9a4, 0xf6ccd70f, 0x2b738f6f, 0x0b2c6356, 0xe9043027, + 0x9596993d, 0xfb3bcf4d, 0xd9e3f3a2, 0xc6afb90f, 0xe7d7f2b0, 0xd754c66c, 0x44eb3ba5, 0xb2e4d756, 0x9d4eafe0, + 0xba4bb86f, 0x98d58a9c, 0x13b805d9, 0x5c83bde2, 0x578f0dad, 0x67e78dbb, 0xa4433c1a, 0xf7dd876a, 0x5c3b9208, + 0x5f7895c0, 0xd8c94c27, 0x9eddec96, 0xad256389, 0x11173bb8, 0xcf9ad044, 0x24ece4cd, 0x9fa6e696, 0xcac6d474, + 0x40895f42, 0x7d894e82, 0xf3c17571, 0x63ddadc8, 0x27637999, 0xe0833899, 0x5b18d2a7, 0xc7494204, 0x7f7362a5, + 0x3a6ecbf1, 0x6f454f39, 0xb299927e, 0x6ed556bd, 0x28529b75, 0xa88a1e6e, 0x9e7d0890, 0x26c95f9d, 0x00f59e30, + 0xa0c77bf2, 0x930dbd0f, 0xb1fb2714, 0xe657d029, 0x59f5a80b, 0xbaa54503, 0x576f1609, 0xa7e7f290, 0xee70d8de, + 0x47f64581, 0x5f589b36, 0xad548546, 0x9f4b4d44, 0x4a05ffc8, 0x7db19242, 0x3c7b7bb3, 0x536d5f55, 0x0cfcf3b5, + 0x25453198, 0xa22e61a2, 0xac4aaa52, 0x45fd0510, 0x4c5c1883, 0x63b7e7a2, 0x05d07586, 0xc4e87412, 0xa616156a, + 0xf23cbc3e, 0x74173367, 0x1291a664, 0xbb110767, 0x77648035, 0x889d38f3, 0x937eed6e, 0x74878c25, 0xd54926af, + 0x0b80cd80, 0x88b8de9d, 0x5548fb9e, 0x1e76f969, 0x6821cd70, 0x53ea35ed, 0xe44ba2c0, 0x000b38ab, 0xaf1dd87c, + 0x76d12e30, 0x04f89d91, 0xd54edbc9, 0x943e4622, 0x800ea255, 0x050abf96, 0xbe3015a4, 0x8cb809ba, 0x8cb027a9, + 0x4223c872, 0xc51f09d1, 0x795f3411, 0xf995ff38, 0x423e30be, 0x46ac6928, 0xea2838b3, 0x73692d62, 0x111f1587, + 0xb22b3c87, 0xf2c02acd, 0x23f0e82d, 0x55f41676, 0x3a364a89, 0xc2d36af9, 0x9b396dcb, 0x081eb479, 0xa5822326, + 0xcea01409, 0xfc2fcf0f, 0x6ab3446c, 0xb3e8f2db, 0x6820a9cd, 0xbf892e94, 0xc11f1e11, 0x32fa5768, 0x01c672c3, + 0xa847b5a9, 0x2371094d, 0xd0a0cc01, 0xba764bd4, 0x4582f79b, 0x68625748, 0x8ba6cf91, 0xa020ead1, 0x8e0926a8, + 0x6ae5ab63, 0x0dc6790b, 0xadd26b42, 0xfbadd799, 0x254ea42a, 0x48278188, 0xc1c10751, 0x4d5b0c3e, 0x3ec072b5, + 0xfd732a64, 0x92bd36fc, 0x47169db8, 0x0a663b8e, 0x88c5bc96, 0xfdf8b20a, 0x960fb5e9, 0x673392b9, 0x3c0a97c9, + 0xcfb93945, 0x791b37ef, 0x66417b76, 0xea386a17, 0x94d7f198, 0x0e68d864, 0x2b12981f, 0x1caa81e6, 0xe3aa26ad, + 0xc985eac8, 0x74233c17, 0x0107408f, 0x054e1072, 0x1d60dfaf, 0x67b4f437, 0x55ccc3b5, 0xe5dda1f7, 0x3994cde2, + 0xe40c65b7, 0x841bdbef, 0xb3286dd7, 0x25879a94, 0x0986c107, 0xc5a8117e, 0xe547ac74, 0x732b9df1, 0xfbdaa820, + 0x78204a87, 0x4b1b63da, 0xe37056d7, 0x700838fb, 0xe3a44bd0, 0x09c0d1a8, 0xed85b110, 0x8fb40361, 0xca1dccad, + 0xbcf1da92, 0x0bad5de7, 0xddc3ad6c, 0x63bd297d, 0xb89a0f65, 0x0c1ab855, 0x56c35d4a, 0xe1d277a4, 0xb5af95d5, + 0xea74270d, 0xfd7626d3, 0xaf177284, 0xdab68b46, 0x467e01b1, 0x5fff1005, 0x8b9af627, 0x351ecb60, 0x1fd94d65, + 0x9efb703a, 0x4d057bd1, 0xc3b5857d, 0xd08af498, 0xd3498832, 0xbc97000f, 0x6915638a, 0x5f9a655d, 0x045a8f99, + 0xab66923a, 0x4ea4bf7f, 0x81c994ad, 0xb4e9a044, 0x6036d9d4, 0x1c11c99c, 0xb998f304, 0x439ecf47, 0x613b75c5, + 0x13b5c6c0, 0xa0f9a5fd, 0x4284ed32, 0xf4779b2b, 0x4db5c858, 0xb1981006, 0xb33ef2fb, 0xdbaa289e, 0x82785550, + 0x3476d883, 0x1228739a, 0xde289fd8, 0x4d419310, 0x07670055, 0xfc18c58e, 0x76bda94f, 0xe555837a, 0xdfc53bca, + 0xb93c593f, 0x9eaca943, 0xf470732c, 0x53dc5494, 0x0b710a9b, 0xc1ba72fb, 0xfe265752, 0x627948b0, 0x9084f815, + 0x3d055ff0, 0xf2acc4dc, 0x378fecac, 0xa51f5857, 0xdf6cd2d0, 0xfeefcfdf, 0xbe714949, 0x74b94da9, 0xeefec87b, + 0x9627d1cb, 0xc8c54a89, 0x3171a85a, 0xf7dbd338, 0x3125ebb1, 0x6c23bc15, 0xcc3d9b56, 0xa9c6b52d, 0x6fe4018d, + 0x63ec58a8, 0x9af14b02, 0xd0d03c2e, 0xec9e5f9d, 0x3b51f0ee, 0xd07ac3d0, 0xc5d42c35, 0xfe0cb41e, 0xd80a1141, + 0xc1bba213, 0x0dd26d80, 0x7acf1e45, 0x0024775e, 0xa16f93af, 0xc979038e, 0xe05ee485, 0x339a29c6, 0x3aafffd8, + 0x5d4cfffc, 0x3b97c8cc, 0x58633069, 0xa2803b36, 0x59a8f3fe, 0x25496daa, 0xaaaac3a9, 0x8d763fc8, 0x538e4109, + 0x340726f3, 0xed265941, 0x8219e121, 0xe5788def, 0xbc5f0ac0, 0x5622de67, 0x82b28168, 0x460bd827, 0xcd51b4e0, + 0xa6dde09f, 0xcddeeade, 0x49470e70, 0xd572bf85, 0x5e6c72d8, 0xd3df16b7, 0x38c2daaa, 0x81d7f259, 0xb0dfd765, + 0x47b24e36, 0xe292f72a, 0x6e1427c9, 0x74fe98eb, 0xc813ed30, 0xbf520467, 0x305e7eb6, 0x1a20a041, 0xa4ed4848, + 0xe98b6256, 0x36b1b641, 0x6d107e1e, 0x70a4d2eb, 0xab581ee7, 0x8baf4113, 0xdde5c7f8, 0xb573da96, 0x5357abf0, + 0xf53f8786, 0x471515b6, 0x7dba6759, 0x04f10737, 0x7b9cd601, 0xda18fe2a, 0x1ffd4604, 0x8ac56a89, 0x13d5c344, + 0xd8d9bd4b, 0xee01dccb, 0x2c95f633, 0xc3a54942, 0x5af77628, 0x25ead415, 0x0d9f5866, 0x71b447ea, 0x65c66edf, + 0x37189e5b, 0xf34b910f, 0xfd238736, 0x7e2ddf93, 0xb6114f3d, 0x59e0dac1, 0x5b5f101b, 0x85b9ad8d, 0xcb4b5fdc, + 0x9969a7b7, 0xa501d292, 0xc6f86613, 0xfa9ba91e, 0x110fb4ff, 0x7862f800, 0xefe735f7, 0x3e3c43f1, 0xfa21cf88, + 0xd032afb8, 0x5a8891bc, 0x88722030, 0xd3fe5243, 0x90ae1cfb, 0xac36a7e6, 0x6f001db7, 0xece785c0, 0xaab615c9, + 0xada703ac, 0xeb73f837, 0x80147870, 0xb42a6954, 0xde2ae877, 0xf312698b, 0x5232862e, 0x330d4461, 0x25e0fe51, + 0x9949a627, 0x1cf323fc, 0x2fb35940, 0xb9f7581d, 0xf1228300, 0x6fdbbd27, 0x6fd1b7b9, 0x91db2545, 0xfe93ad00, + 0xfe64be1c, 0x551bfd27, 0x9d7f9e1e, 0x0aacc6ed, 0xc08359d1, 0x596eee6a, 0xb803e035, 0x52fbd9f9, 0x824ad28a, + 0xc01b3059, 0x968341cf, 0x72663a93, 0xdaaa7fc1, 0x547eb440, 0xd6a8a3d3, 0xe7efc486, 0xc1be69f4, 0xd6a07be7, + 0x2bcddd88, 0x99f3af75, 0x1ef6accf, 0x947f46c2, 0x98ed55f8, 0x3adfab06, 0xe147ee10, 0xfd240635, 0x71d687a8, + 0x0d6f27c4, 0xd39e3999, 0xe239ab41, 0xc021c233, 0x901fd1a1, 0x81dc627c, 0xeb27a079, 0xb7c55db6, 0x913cff47, + 0x381947f5, 0x625dd3b1, 0x4e433168, 0x87e6237b, 0x3841eed9, 0x5bea66de, 0x6170af24, 0x9920107e, 0x6406b9cf, + 0xceaa425c, 0x539b1abe, 0x654fe61b, 0xe802c22d, 0x4eddb984, 0xc1e1abc0, 0xdb5375d3, 0xac75734a, 0x91883d25, + 0x8fd33188, 0x685d2a37, 0x1c698817, 0xce8d9ff7, 0x3f8d179e, 0x91ad5794, 0x9275d7f4, 0x909da457, 0xf51458b1, + 0xeab8afaf, 0x2f623b13, 0xeec869ca, 0xd2947209, 0x4805e533, 0x1bf1bb6d, 0xf747cb85, 0x1c6d9b5e, 0xae0fd94f, + 0x2b590850, 0xe639bf78, 0xcafd7fdd, 0x439023ac, 0xf0250424, 0x69d9e54b, 0x4b631694, 0x3657e895, 0xaf58f6f1, + 0x2f665068, 0x9578f94a, 0x8205b78c, 0x36ed53d9, 0x67a8a16a, 0x50423725, 0x76ff4569, 0x2549d3f5, 0x1b6e284e, + 0xe458912e, 0x0015749f, 0x56ffc36e, 0xd6e20e2b, 0xd92d5f7b, 0x3392a2d9, 0xdf2bfd69, 0xa5c330f1, 0x871ec27a, + 0xd8c9cedf, 0x2d47396c, 0xdbef708d, 0x9c957247, 0xb6a5ac75, 0xc41563f6, 0x6a7447ce, 0x61edbae9, 0x9e0c7861, + 0x0ba43d6b, 0xd7e4b362, 0x63ffb972, 0xc0ffcb44, 0x19b25514, 0xc1657a44, 0xeef0c9ab, 0xe4603c2d, 0xd652c43f, + 0x407fbd33, 0x8372b584, 0x55fa842c, 0xab331ba5, 0x1eb1563c, 0xa30136ce, 0xa3449dd5, 0xb9801721, 0xaff59d61, + 0xe5c419fc, 0x3e658440, 0x4804f890, 0x53907a0c, 0x500781d9, 0xd7490f99, 0x2845e2af, 0xfda4d1cc, 0x250bd550, + 0xef105daa, 0x4a59a445, 0x75a876dd, 0x12762823, 0xa36466a5, 0x46d2f29a, 0x9f673a23, 0x0566365f, 0x36a24edb, + 0xa7ee5f60, 0xdfd81803, 0x99103c7e, 0x59a0447e, 0xfbfa80e6, 0x26cc977e, 0xd3ed58e9, 0xf4a49bd4, 0x8878c1fb, + 0x7de7027f, 0x999a1d78, 0xd2321b7c, 0x27fcecfc, 0x2a5199fb, 0x1dc9a400, 0x52118f20, 0x6163ba33, 0x77b10b17, + 0x4c0cc900, 0x70d4f438, 0xba6a249b, 0x43cfcc1a, 0x6c3e1a03, 0x21dd3a71, 0x96f2bce3, 0x4c602960, 0x66304a99, + 0x0b1bcef2, 0xd9ff5d5c, 0x73548794, 0x6d3aa0d5, 0x69f29a58, 0x450cefa1, 0xc11ab081, 0x0bffa6ce, 0x597663cf, + 0x7693a795, 0x69cbc51c, 0x6e578e0c, 0x8fb73aac, 0x0bdc87bf, 0xa497de80, 0x17622372, 0x5cbf1a10, 0x1fe82cab, + 0x036bf43b, 0xd4a007a7, 0xe1823e80, 0x918bc8ea, 0x7d584815, 0x8b81be9d, 0x1f7e7eea, 0x69a72c96, 0xaa6b294f, + 0x81855a47, 0xe98937b2, 0x9d2d0c1c, 0x7ab0f0c0, 0x4e1bb2f9, 0xd5d5c7c8, 0x43c76ba0, 0x44a9f5ac, 0x1336f248, + 0x32b8541a, 0x9758d08b, 0x1a81bbf7, 0x22b81b3a, 0xe374f30c, 0x30754b50, 0x148531cf, 0xdc3102d6, 0x677d2565, + 0x647a3cf6, 0xf4d3753a, 0x82adf28b, 0x57b21c7c, 0xca4c5395, 0x3c384ca5, 0x0274880f, 0x7a10dc54, 0xbfe68bad, + 0x0ba124ad, 0x14b0e610, 0x68cba070, 0x085643c1, 0x67bba2e1, 0xad056e01, 0x1a8498b3, 0x2e985894, 0xc3420670, + 0xd5b21a17, 0x0c330b5d, 0xb8185a82, 0x184b7ba8, 0xaa5ed42f, 0xe972c964, 0x9b6bbceb, 0x47fa97fe, 0xcf188e19, + 0x8652ee07, 0xed3c7e3c, 0x766ff36e, 0xe4cb3e99, 0xd0ee5a77, 0xec7009af, 0xd7868e2a, 0x25ae209d, 0x3256a5c5, + 0xe4b1a972, 0x3fdde045, 0xcbd86aab, 0xdb13292e, 0x550e6fda, 0xaf3b99ed, 0xe09a0acf, 0xd3931291, 0xdf2f91b8, + 0xc9280665, 0x471111b7, 0x2489770c, 0xc1f68010, 0xcee2b06b, 0xd2cea727, 0x92940747, 0x5ae7e696, 0xf77774ff, + 0xe9829bb0, 0xe638e4b2, 0x1069aeef, 0x2ae0f53d, 0xb8184c4e, 0x9274f02e, 0x1ef265ec, 0x10bf8137, 0xc5ad34d9, + 0x1d61b2e1, 0xd72dadbb, 0x2c0971b8, 0x62353baf, 0xf8b6b3e7, 0x58924d4c, 0xdbe0ef4f, 0x05c26c99, 0x27bd7112, + 0xbaa8a146, 0x966cdeff, 0x8e12e6f5, 0x7d8bc3af, 0x4952c31c, 0xc6affd21, 0x6c51c1f4, 0xae4643f6, 0xd6860bd6, + 0x546281bd, 0x55a94a2e, 0xabffa372, 0x8f0a5630, 0xe3f88ba1, 0xeade8b7d, 0x1cd01e94, 0x17ee7405, 0x31646250, + 0x33cdd785, 0xcff0a699, 0x5e712ad6, 0x811e9265, 0xa73ed56f, 0xf84a2d16, 0x9095fe08, 0xc018f581, 0x6159f136, + 0x760cce53, 0x1199bd87, 0x0b8b4eb6, 0x83d5c8ac, 0x1b046594, 0x65bb6ca9, 0x76755348, 0xeaeb1594, 0x896c532d, + 0x95962d89, 0xf7f9f8dc, 0x216f2336, 0xab937c08, 0x5dd280b7, 0x691ed089, 0x7c99f6be, 0x4e9d7ea2, 0x7b614ac3, + 0x3bbef6dd, 0xc1da33db, 0x5102a7b3, 0x7a033694, 0x2da0eec4, 0x2f495faf, 0x11c0029b, 0xe7d0e457, 0x23d62293, + 0x71b8a560, 0xd79db7cc, 0xb1a231cc, 0x5503659b, 0x08eaa640, 0xd3b50592, 0x44b8e4c5, 0xb457bd0c, 0xa2a87aa8, + 0x14c71c3f, 0x19609198, 0x7664fd6e, 0x2fab307b, 0x39d737b1, 0xdb8bb6f0, 0x72d2b30f, 0x22757fcf, 0x13605118, + 0x52d0e341, 0x199ebbf4, 0x64747526, 0x25c7e4fd, 0x5dee142d, 0x85f58523, 0xdcbf952c, 0xb0acab68, 0x76a5dada, + 0x54d52789, 0xd689597a, 0xf5d44c21, 0x2bc9eabf, 0xd6db82eb, 0xaf18ceb4, 0xab23c8c7, 0x6effdd16, 0xed3687bc, + 0x38efad20, 0x099a1bc7, 0xedeaee0c, 0x3282c7c0, 0x317d9664, 0xba5615c9, 0x471a9ba7, 0x2ce5759d, 0x98620283, + 0x32059b6a, 0x0fb80a49, 0x0dba598f, 0xb7438cdd, 0xa5b7cf21, 0x2c9630f7, 0x2184d0a1, 0x8880773c, 0xf317498b, + 0x9f35e325, 0x41d2fe54, 0x1c7961a1, 0x422da360, 0x896c4ab0, 0xa52c8ebb, 0xab178d0a, 0xbc03c0e2, 0xf6e9c479, + 0x1a6e0bab, 0x6de7f0b5, 0x91b7e2f1, 0xbf0ba8b7, 0x2bd56707, 0xcfb942f5, 0x3b145125, 0x2a94e460, 0x6e9d7300, + 0xdd481039, 0x88082baa, 0x3f62bdb6, 0x8712f5e1, 0xfd756943, 0x9d575bbd, 0xf656c208, 0xa2c99a21, 0x9058d228, + 0xba2fd8ed, 0x3fd5d059, 0xe13a6ee3, 0x57760453, 0xb101b30f, 0xdb83b4e7, 0x71e79123, 0xae695035, 0x30ea9a3e, + 0xf9a1fa04, 0x032d21d0, 0x67dac325, 0x2622ccf3, 0xd277b3cb, 0x1c00026f, 0x6a1ed1cf, 0xba3fe07e, 0x9d227bc9, + 0x4be2fa6e, 0x481c92cb, 0x31d2ee4a, 0xbd389194, 0xf69616f6, 0xb83980dc, 0x57e25486, 0xab7472bf, 0x718b2c5a, + 0x60933a96, 0x946fe7e1, 0x5128d818, 0xd1501c8a, 0x5e4e8540, 0x5d4f42bf, 0xa947ba06, 0xd7b28d90, 0x70045e0e, + 0x5da832f1, 0x1443a166, 0xf7794fd9, 0x341cc18a, 0xddca74b3, 0x6d5dfd8d, 0xb90b4242, 0x73642005, 0xbe625e2a, + 0xc2f1795c, 0x44e146e0, 0xed1397c7, 0x6506004e, 0x5c4d654f, 0xdac17b07, 0xdcbd3283, 0xddaa8e9a, 0xdfc6ceb8, + 0xfe05283e, 0x559bd8fd, 0xfccd5a7b, 0x25018df5, 0x3bd04b89, 0xf0f92086, 0xf7fa7cee, 0x881f8250, 0x0f120d09, + 0x45ef5ad5, 0xaa776589, 0x8155fa4e, 0x4837894b, 0x9b34aaee, 0x9488fe87, 0x44df27fe, 0x446f8db5, 0xdc505c7d, + 0xed76277e, 0xdc777637, 0xb14c9418, 0xf4a09870, 0x420af690, 0xf3057cea, 0x34c4552e, 0x203417d6, 0xbcb7526b, + 0x6b44c2cf, 0xfab519f7, 0x951722dc, 0xdd9c9fce, 0x34d634ce, 0xb30adc8b, 0x7d938553, 0xa6f66a67, 0x6b25a1ca, + 0xb40a4ced, 0x60b13b22, 0x1243f22b, 0x85c927b0, 0x265fe027, 0x556ca565, 0xe536844d, 0x99ebff87, 0xf409d071, + 0xe6d77a10, 0x712010bc, 0x52ca4f01, 0x8b06b786, 0x44f82054, 0x1848740f, 0xbef614c8, 0xdb311e10, 0x99cc3276, + 0x8325839f, 0xd8d200a7, 0x50cc13e3, 0xcfd50d6b, 0x7e90e68b, 0x3102b986, 0x1592e8b8, 0x110515a7, 0x57a5b465, + 0x6dc75f99, 0xee6842ca, 0x892fa2e7, 0x720284b0, 0x6d28a1c2, 0x98c2d6bd, 0x6834a902, 0x1813bbbd, 0x439fca79, + 0x640d4cea, 0x0ef50248, 0x9c57aa51, 0x3a2a41e1, 0x7007444d, 0xd3209e6d, 0x20aa3498, 0xf3d97f7e, 0x0d9a34e8, + 0x4fa785e0, 0x7118cffe, 0xa1487e83, 0xd5970b90, 0xb0d65f55, 0x01a6c594, 0x646f4259, 0x3e4cfd7f, 0x2cbfc8cb, + 0x77658c1d, 0x3d9a01c6, 0xfbbf2bc9, 0x4ec30828, 0x2d5159f4, 0x2e288148, 0x7a1035a1, 0x0f5a5dcc, 0x21484779, + 0x0b271e6a, 0x37b2d9f4, 0x9ab203b5, 0xd210eab2, 0x3dc3006d, 0x9c90d7f4, 0xd39a8db1, 0xcf0e2976, 0x44822438, + 0x5e780b57, 0x56c4a92f, 0xf0a1bed0, 0x8c410051, 0x0422e8f6, 0xabd4c441, 0x5cea3d39, 0x1bc2abec, 0x8705bbbe, + 0x56e07f57, 0x1df18c7f, 0x24716c14, 0x46d043e0, 0xff7cbf41, 0xe573b4a4, 0xddb83859, 0xb409ca40, 0xe74b072e, + 0xa85e0f30, 0x0c4b18f4, 0x1530abf7, 0xb5049987, 0xffac6446, 0xc3c5b106, 0x0eacc235, 0x1cf21747, 0xd7b4be68, + 0x519849ba, 0xf8f7ab76, 0xc23674b6, 0x024d1648, 0xc0e44e35, 0xfb5c5620, 0x82cd3806, 0xab0cfdff, 0xe6563fdd, + 0xbda4f150, 0x4afaa0a7, 0xd9094c8e, 0x3f2e2beb, 0xc24b230e, 0xec8e3b41, 0x665ed160, 0x943f880b, 0x1bd1814b, + 0x8ef64457, 0x6304b1c0, 0x07681e39, 0x54e3bf9e, 0xa31c23bd, 0x2a157ab9, 0xea7650bd, 0x52f28d7c, 0xd54d3462, + 0xc4e3fb06, 0x2c90282f, 0xd46c9fbe, 0xa6677ab9, 0x2afface3, 0x73b8ec2d, 0x56aacdb5, 0x62e5adbe, 0xe3b46e0b, + 0xd0197902, 0xa579b0d4, 0x9918925a, 0xad7f3883, 0xc31c775a, 0x68c1bf33, 0x2e41f007, 0x5033d207, 0x3d7a6a97, + 0x6e87e35b, 0xc5c82701, 0x1332fecd, 0x41c3e805, 0x42d84a82, 0xbf0d8ed7, 0xe69fdf6a, 0x5ab27521, 0x8d40ff4b, + 0xfc15e7e0, 0x6fe5a408, 0xd2fa331e, 0x6724f49b, 0xf5a523bf, 0x15cd76f9, 0x812a73d2, 0x2bbf8f18, 0x07f4cf8b, + 0x2ea444a7, 0x738a0f86, 0x05fb43e9, 0x5cebdde9, 0x59e9bc58, 0xdc4ed6ac, 0x5df1445c, 0x0b2dfcd2, 0xe9ec5571, + 0xb9fe856c, 0xfe17d3b5, 0xdb480ccd, 0x0b64a0bb, 0xcb0225cd, 0xa885bd3b, 0x95706f3e, 0x841870f8, 0x66926ba9, + 0xf443d4de, 0x20de7563, 0xdcdc6efc, 0xb65cccd0, 0x2f071c26, 0x5c45970d, 0x7a88761f, 0xe21c5bcf, 0x20297ebf, + 0x52087211, 0xe4e3f687, 0x0965b5ea, 0x9374a342, 0x152a9bae, 0xba7d8600, 0x40ed1703, 0x66a530a3, 0xd54e8474, + 0x525fa810, 0x1ff54d5d, 0x5d222be8, 0xecb6a4e9, 0xc658cc10, 0xba8ab39f, 0xe5f6dca0, 0xb675c2d5, 0x7a3bb318, + 0x8cfe88ef, 0x491fae31, 0x656bfa9d, 0x0992bc42, 0x968013c5, 0xd30ca3e2, 0x7201d43d, 0xf5ad15e6, 0x9103a3a4, + 0x1bada6fb, 0x7892db62, 0x620a7617, 0x9d4410ac, 0x29f5a38e, 0xa583d7cf, 0x0e2e621b, 0xeae19d2b, 0xd2498a92, + 0xef6b9ebc, 0x295dbd5a, 0x1cb78cec, 0x97264694, 0x01bb2d98, 0xcd526028, 0x4470ba9b, 0x14e93784, 0x6b18720d, + 0x59085708, 0xcc942d66, 0x3c2dff06, 0x585c37ec, 0xdc3f0601, 0x35fc3ec5, 0x5e78b106, 0xf266d5ab, 0xb4298376, + 0x6b4310b7, 0xe0f12ae8, 0x6c89b237, 0x8b5165d3, 0x0256274c, 0x682d65ff, 0x199e83c9, 0x401bdc3b, 0x63e82166, + 0xb8b5eba9, 0x4dcd15a3, 0xf05f3629, 0xeb3bad4b, 0x0da7d36e, 0x94d67743, 0x84fe0e0e, 0x0daa517f, 0x61a82523, + 0xc09fd165, 0x6c940e14, 0xa12812e1, 0x62f76b87, 0x5245af23, 0x5910589d, 0x51547ad7, 0x5a6c0c33, 0xc4b7c2d2, + 0x8fb95d7d, 0x22c2362e, 0x3332ab86, 0x77ba9f5d, 0x5460a5fe, 0xe4e53fca, 0x6de6bf8b, 0xc2e8ef8f, 0xbadd2474, + 0x7afe1332, 0x14891e14, 0x812dc982, 0xafb9de02, 0xfc55917e, 0xdc46df28, 0x72c582c9, 0xfe283c2c, 0x9af211b3, + 0xfefbc4f4, 0xbb4d993c, 0xba97bb70, 0x85698411, 0xddc294b0, 0x9de21b12, 0x210c9739, 0xbfffab69, 0x7d8fd8b8, + 0x2ed8acdc, 0x9f53dcce, 0x657f35b3, 0x4c2dfc22, 0xae39d6cc, 0x5d5d2a3f, 0x83a694e8, 0x6e7a8f3d, 0x7e9e27c9, + 0x9dc95cb7, 0xf321d8d9, 0xead7f4c4, 0x6f0925de, 0x72952249, 0xea1b406c, 0x1fe2fde4, 0x037e205e, 0x502293c7, + 0x6404d802, 0x72664ea5, 0x8fc7c853, 0x72372781, 0xc4e4c661, 0xd132c70e, 0x1a413dba, 0x8f0f85d7, 0xeb8baff3, + 0x445fb19b, 0xfdf1559c, 0x36a9a51f, 0x5394880c, 0x1fc16422, 0x61ffbd40, 0x9bb02fe4, 0x1e43b70e, 0x05a10fad, + 0xba5e38d8, 0x06cb5525, 0x11bdd4cb, 0x3a72be13, 0xac8b8ee9, 0x35d70750, 0xfeaef260, 0xceb4c4dc, 0x27bc618e, + 0x46f6bfa3, 0x44a8d13a, 0x6aa5d206, 0xed709b66, 0x20ab24d3, 0x39886a05, 0x33c0e0c5, 0x27170313, 0x88dfed3d, + 0x82457032, 0xfb967113, 0x19782565, 0x6a3870ce, 0xd0bd6e07, 0xb8e46151, 0xca3cb27b, 0xd1be4ef7, 0x90fcf730, + 0xba13e0ea, 0x144454d2, 0xb313432c, 0xd586eea2, 0xb3ef3af5, 0x9245021f, 0x1021b157, 0xa65673ca, 0x2f7645bc, + 0x3c41047b, 0xbf9ef17b, 0xe3c99f4f, 0x6303c471, 0xfff28da1, 0x3c7a4932, 0x41b5f641, 0x0be2925d, 0xaff04e1e, + 0xd48bac35, 0x4494c062, 0x80c0d5af, 0x66b357c8, 0x631fdfc6, 0x8039d052, 0x09977fcb, 0x959d5244, 0xd973888a, + 0x44c83e06, 0xe247bfc1, 0x44acd73e, 0xdf5daf2a, 0xd6235395, 0x2fb3b716, 0x6abd4122, 0x4ff6314a, 0xa2c99355, + 0x381349ac, 0x258d821c, 0x6e79ac76, 0x72148d90, 0x53ce0b1d, 0x1729f954, 0x578931a4, 0xd10280d8, 0xc6941536, + 0x9035d67e, 0x54e44192, 0x736d0372, 0xe237359d, 0x7d17c972, 0x5133777a, 0x0d5a9654, 0x4f90eb0d, 0x2623ed17, + 0xa50dc491, 0xcd0f9cdc, 0xcb1549a6, 0x79ab1521, 0x62abff49, 0x7dbb47dc, 0xfe4eb3a2, 0xbcb4521c, 0x1a4561bf, + 0xb2f31a7c, 0xae56454a, 0xaeb986d7, 0xa72ad31e, 0xd39cc0d9, 0x83b10798, 0x9a6f9ed0, 0x70658e7a, 0x44da7939, + 0x83dbfbd4, 0x2ff05999, 0x313f6c11, 0x2129c548, 0xfd2399c4, 0x69dc3979, 0xd00deee0, 0x2a4559a5, 0x4796baae, + 0x8022f8af, 0x3fba7dff, 0xa96d2b6e, 0x079e5087, 0xbe5769e4, 0x455b9f36, 0x987cb658, 0xde60b3ff, 0x9443c8fb, + 0xc1518816, 0xd9991cd7, 0xcd52a560, 0x91870673, 0x0b91b54a, 0x543ddf76, 0x29eef31c, 0xdf61b6a4, 0x3364848f, + 0xf7d91563, 0x0d789bd6, 0x222a952b, 0x2bbd09d3, 0x85261573, 0xdd0c7dc7, 0x619dda34, 0x472488a0, 0xe53120f2, + 0xf6340bfe, 0x35ad90c0, 0x107fed06, 0x081b6704, 0x126ce8cc, 0xb50df48b, 0x00a68df4, 0xc531c7e5, 0x3afbef0f, + 0x30c64a36, 0xd2569235, 0xd43f2105, 0xe4438414, 0xd0d512e1, 0x0522d6a4, 0x36dedbec, 0x8b92553e, 0x0c849fee, + 0xe1c889a8, 0x99e56df5, 0x46177a90, 0x5f85d2c3, 0x2e8e85db, 0xc8e6010b, 0xad5c33b4, 0x5a4990f4, 0x95a25120, + 0x8b125fda, 0x7a8250f2, 0xbf4af79b, 0xd110ea45, 0xd8981e4b, 0x2bf052fa, 0x5f93a22e, 0xee5cb512, 0x51176490, + 0xe61e8cc8, 0x6616722f, 0x87d64b9f, 0xe74372ce, 0x67c16338, 0xf23a461b, 0x87b8fd67, 0xfd711362, 0x25213564, + 0x225ef10f, 0xed57eda3, 0xdcf3df55, 0x6b65fde4, 0x0468f43c, 0x9e6df288, 0xfc732265, 0x018bfd3c, 0xe2d56db7, + 0x1d92bde7, 0x40b6d53d, 0x5ed2e699, 0xe08b635d, 0x5be4c0c7, 0xd81bd980, 0xc6bdb100, 0x8399ae24, 0xff31f07b, + 0xb4183e2c, 0x599831cb, 0x1c38bff5, 0x4ed9928d, 0xc58c234b, 0x3be424b9, 0x623a41b7, 0xde1130ea, 0x882b33e7, + 0xf09bda71, 0x43b80e67, 0x1fbcd497, 0x2364f1f7, 0xd6cd545d, 0x95b1f8e3, 0x79ab66f1, 0xb853254e, 0x93026532, + 0xc35780a4, 0x5091db63, 0x8890b221, 0xe0c3b156, 0x5c130e0a, 0x6d363744, 0x8285dd1b, 0xf65a389a, 0xa204dc6b, + 0xc1187422, 0xc1c8c54e, 0xa10c8af1, 0x7450d393, 0xfa181d21, 0x3a1fc616, 0x5cf3e98c, 0xc4d80aa5, 0xea918d2d, + 0x866c21b7, 0x6dffd367, 0xebb7b57a, 0xd667cac2, 0x05107592, 0x58600669, 0x730eb641, 0xe6af08b5, 0x3dac192b, + 0xed693391, 0x2a1aece4, 0x29654591, 0x73d54e97, 0x5f1b315f, 0x95205d63, 0xba0cb753, 0x44181faf, 0x4bd97169, + 0xde2cd445, 0x2d15d8ad, 0xb2038377, 0xae79ff05, 0x33bbeb6b, 0x4addc5d1, 0x64f3e3be, 0x156deadf, 0x3b19b101, + 0x4644ce01, 0x1fea640e, 0xd1a94b37, 0xe4f14d44, 0x2547d8a0, 0x000e61dd, 0x6460bbd5, 0x63ac8974, 0x39d2b43c, + 0x016a4f6c, 0xeb35a9a4, 0x83b5b2ed, 0x46673b17, 0x9b3acd6a, 0xdba74135, 0x1308be94, 0xe43c8fb5, 0x1ef98c6b, + 0xe9c7dd31, 0x380eb08d, 0x1924c5b8, 0x8cf39a25, 0xca0907af, 0xb8b53850, 0x4318b34f, 0x0153ac47, 0x2a29a182, + 0xd4e5d466, 0xd2bf2883, 0x9b93450c, 0x0fe324c0, 0x04908f47, 0x12e29b9b, 0x4bc7e599, 0x51b07028, 0xd8fb4bc9, + 0x053b26aa, 0x1c443e74, 0xa6743158, 0x0050fd00, 0x8c90f4df, 0x6a7fd78a, 0x4120a18e, 0xa8c45a2b, 0xfde05e32, + 0x91b77eaf, 0x1f3d2958, 0x391df6aa, 0x62e0e6fe, 0xad1e5760, 0x0da44673, 0x4d528f92, 0xd3faa990, 0x9ff2475d, + 0x206a4fd4, 0x134e1678, 0xa2a40d24, 0xcb51b814, 0x7e8c2d86, 0xabcdb1d2, 0x7e0fb934, 0x7c6f0aaa, 0x3b527a5e, + 0x77436d9e, 0x8d22867b, 0x4e155221, 0xb85df9f9, 0x9caa807d, 0xb1aec469, 0xb09ce57a, 0xac55596e, 0x5d8b5e07, + 0xd2549870, 0x3155ed64, 0x237ae02c, 0x05a75e72, 0x94ecf38f, 0x09397f8b, 0x2caf1d14, 0xdaeabb72, 0xce16ef4f, + 0x8b38665b, 0xf24929c4, 0x38de27ff, 0x07accf55, 0xb173ca0b, 0x19499209, 0x71246bf8, 0x6dce9eb3, 0x9ae5aa18, + 0x4219e286, 0xa4f768a8, 0x645e91c9, 0xf6dbc909, 0x409896ee, 0x8cd86049, 0xc71bfc3a, 0xee9a3a9e, 0x598cb139, + 0xc25afc68, 0x0f208360, 0x1083fdf7, 0xc36905ef, 0xee70f0b2, 0xb6fab392, 0x6ea5e166, 0xf30363b0, 0xda3fe856, + 0x86b25dad, 0x2656db1a, 0x6aec7dc9, 0x5deef3aa, 0x091067a6, 0x916c3bbc, 0x324a08cf, 0xba87ffc9, 0xff6b5dfa, + 0x3b56e790, 0xadb2020e, 0x3dffa3a2, 0xbdd59493, 0x3d07cb94, 0x0223de2c, 0x06959b95, 0xde58d230, 0xd1ff20e6, + 0xf61040ae, 0x46e1c2f6, 0x57a61af7, 0x349fbf3a, 0x61f7becd, 0x67c2a7ac, 0x9b8504ac, 0x04d2c296, 0x396d9ecc, + 0x4f7a33a8, 0x852c028a, 0x8b47b9c4, 0x7bacc47e, 0x0fe2b2c6, 0x0a43ee82, 0x6656d2c8, 0xc63c2b45, 0x3b7b2d28, + 0x2ffa8bfa, 0x493a77d6, 0x9f43e7fa, 0x9c51339c, 0xa44bc17b, 0xe238fcda, 0xfde9cbfc, 0xaa2e6b18, 0x97ee812a, + 0x1c65bbf5, 0xbdb2aa1e, 0x9218f498, 0x473eb474, 0x9cca2695, 0x347528eb, 0x76e656d6, 0xce870ca3, 0xc511e0b9, + 0xa32b5c33, 0x1cc03a8d, 0xc42ac7ca, 0x41c7c93f, 0x1c54506e, 0xe5616749, 0x30978e18, 0x8d31358e, 0x5cce7cf8, + 0xb5344083, 0x57b7c23e, 0x11958502, 0x28c733a5, 0x7606f3af, 0x9fbb0919, 0xd6e159b0, 0xda48d9e0, 0x41111473, + 0x1eac7a37, 0x0d95fedb, 0xa135acde, 0x8ed054bc, 0xb8644073, 0xdb1eee6e, 0x0bdf4e90, 0xac147564, 0x1b130451, + 0xdb3d4e58, 0x6241c8c7, 0x292078bd, 0xe4c9aa70, 0x0e33a979, 0xd330b51e, 0xeed1eb53, 0xc5d790a5, 0x141fffcc, + 0xfe9ad159, 0x2d510449, 0xd481f9fa, 0xf30a5869, 0x0c938b7b, 0x48a7746e, 0x5bf502e2, 0x3c53a7d8, 0xfe35d644, + 0xeb1eb621, 0xf97f137e, 0xa0b143d4, 0x00dfacb3, 0x2458548e, 0xb134f1d2, 0xd3962795, 0xd9389095, 0xe3f567b8, + 0x821e1416, 0xf93819e1, 0x711e47ab, 0xb7ec3a10, 0xafc138ed, 0x5cb08c93, 0x8943131a, 0x4b13bb2d, 0xc6086b0c, + 0x2d73e12c, 0x6cd65155, 0x4e85c654, 0x6fd78750, 0x92784920, 0xf88bc5c0, 0x13d7b59b, 0xf215f195, 0xc7e85d88, + 0x988aa460, 0x16811ec8, 0x8737595d, 0xdc838336, 0xe79210c1, 0x50d3bf98, 0xefcf8ca1, 0x30d80f41, 0x98710dbe, + 0x47227ef8, 0x85d698b8, 0x54b17f97, 0x412c441c, 0x97e846d7, 0xe240b0b6, 0xfb71c7e7, 0xbee15208, 0xe97f79d1, + 0xc0454ea4, 0xf739d541, 0xa66c1632, 0x3e666efd, 0x87a91873, 0xeb34e146, 0x1e41c486, 0x872cf5e8, 0xef9440eb, + 0x25c5127c, 0x9513ae17, 0x595f4eec, 0x74a36ab9, 0x17dc80aa, 0x6a6eadcf, 0x1a4471d7, 0x294acb39, 0xbedd8440, + 0x30e9902b, 0x1765f234, 0xd9740541, 0x5a16fb48, 0xa1a79ef0, 0xdd5616b8, 0x654c8178, 0x0e7f86b6, 0xf8739265, + 0xd3d382ea, 0x8a6067b2, 0x0d183f92, 0x4ce9e96e, 0x0d7f97b3, 0x48e69a9c, 0x8cdfa013, 0x899d4cb2, 0x2dc25cd4, + 0xe4c9574e, 0x6ce9a8de, 0xb2bde581, 0xe38495fa, 0xaa00488d, 0xe9027099, 0x6c9aaf2f, 0xa517fb27, 0x5b7c20c2, + 0xdb949db4, 0x513a9e1d, 0x520f6766, 0x2c94f219, 0xe5a28ddd, 0x03776816, 0xc59c0d09, 0x5f553538, 0xe742fc83, + 0x04d13630, 0x00624cda, 0x01416ece, 0xafeb6e77, 0x30cd47da, 0x224f9516, 0x01213410, 0x44c1f564, 0x12c64176, + 0xddda3e5d, 0x5da7413e, 0xe4c5d5fe, 0x9a2bf305, 0x410b41ac, 0xaee38dc8, 0xfaf2578c, 0x3aa81128, 0xc7b6e567, + 0xc64d4241, 0xe839415e, 0xcb24ba26, 0xa4ce7435, 0xfe264902, 0x98c86c10, 0xa645769e, 0x6b9ae4e5, 0x8ff4006c, + 0x5a941cc1, 0x31e8c8fd, 0x16d334c5, 0x3c8bae7b, 0x9b5fa7a9, 0xa6f533af, 0xf6b0e05c, 0x4e515038, 0xa57cf631, + 0x37391a91, 0xe25cb8a5, 0x6481b7e0, 0xd2d632a1, 0xf1de724a, 0xb6f5b622, 0x396aeaa5, 0x3d451f47, 0xdb0c0458, + 0x9e0ef80d, 0xf7a9d270, 0xd8de6e89, 0x9cf3c4e3, 0x8642e9af, 0x5d8d2eec, 0xb4412799, 0x6449b988, 0xdaa48cc0, + 0x515bd1b7, 0xf08d0f26, 0x0bfb6a46, 0xaa46a2d7, 0xd63d79b1, 0x7147ab43, 0xf4a0a314, 0xbc634888, 0x6aa107a6, + 0xbf9603e3, 0xca306239, 0xb281803a, 0x5690c7ec, 0x776323c5, 0xec15fddf, 0x876fd179, 0xaed163ae, 0xe03823d9, + 0xe0a4a203, 0xfe16ec8b, 0x3d0faea6, 0x4d6fb837, 0xf1c9c2c3, 0x538db524, 0x957cf76d, 0xf8da3432, 0xd19a7276, + 0x7324cf90, 0x18b7cd95, 0x6664362b, 0x8a32cb41, 0x51dc4400, 0x88eb95a3, 0x6ed03228, 0xea477a43, 0x3744ac83, + 0x2264db69, 0xf848f5ad, 0xebd1b392, 0x0d3d5545, 0xf4dfc447, 0x790631c8, 0x5f58cc98, 0x25890443, 0xc7d2a06c, + 0xa0ab1a50, 0x5f7cbc17, 0x7cfc7148, 0x4e36003c, 0x54b08322, 0xaab9cb6f, 0x49fe7122, 0xfb3b22a9, 0x3f783227, + 0xc3e5690b, 0x9b383cb7, 0x242ce538, 0xcb75b467, 0xeccc9762, 0x14a003ee, 0xf278766b, 0x037c1556, 0x09f897ed, + 0x24636f01, 0x1afc2343, 0x113004a9, 0x2bda5e6c, 0x587774c1, 0xf7b3f7a7, 0x4c960d61, 0x88843363, 0x7b2ad99f, + 0xf0581187, 0x2441cab2, 0xdda01048, 0x4bf09bdc, 0x47348377, 0xc169eaf1, 0xc96454cc, 0x46b66777, 0x7060ee76, + 0x1c57f92a, 0x66c8ddd5, 0x4d147a08, 0x95c6f8d9, 0x14c95a63, 0x9f734a55, 0xd1a228ed, 0xdd381550, 0x918ef7bc, + 0x3cce3bc1, 0x03aab836, 0xfe0f472b, 0x77219956, 0x990fa044, 0x64e480d0, 0x04f5481c, 0x9b507b8a, 0xb2a4873a, + 0x876fdf8a, 0x0ec736b1, 0x46a0baea, 0x8e568193, 0xb0568ae9, 0xb92b9e1f, 0xb22292af, 0xecc2a810, 0xe48e4e21, + 0x079f8fcc, 0x653eb283, 0xe73c432a, 0xbbc4ef9b, 0x7b7342cd, 0x7a69fd27, 0xe5aa1ad0, 0x36710b8f, 0x59e8ca3a, + 0x5b8be76a, 0x3ad8a300, 0xe716c9bf, 0x2e84d3da, 0xd6b14b84, 0x6815b302, 0x7c4e1be4, 0xb4bb7e58, 0xc18b38b4, + 0xc7aad759, 0xbb2e84dc, 0x0fe306f8, 0x7abc50c8, 0xd740fff6, 0xd280e366, 0x8e656be1, 0x791d8f32, 0x31eae7e6, + 0xb308d07a, 0x32535e1c, 0xa1c0bc32, 0x25c2ce75, 0x34597558, 0x4e2c89bb, 0x4daa4d48, 0xe401dba1, 0xe87294fa, + 0x87a6d584, 0xa9a7b351, 0xe1acdcee, 0x0ebc3af5, 0x5d1d8196, 0x4e6e4351, 0x4b739b8c, 0x473615fd, 0x0d81cd42, + 0xf4b75632, 0xa88edda3, 0xf5819255, 0xf199f3b6, 0x20cec79a, 0x96db134c, 0xc5b63fc9, 0x8ff8fa76, 0x95c69015, + 0xccb5605d, 0x6173a401, 0xdea6575b, 0x2a4df631, 0x6452a525, 0x2aad45e1, 0xab41790d, 0x9a8824d5, 0xa6222ba8, + 0x611c70a1, 0x8afd58ef, 0x44fb4e65, 0x4f7f216d, 0x6e0e0b64, 0x1e570335, 0x2e635f2d, 0x66021008, 0xf895fc13, + 0x129306d4, 0x23a8f08b, 0x767f395c, 0x95f288f0, 0x36590bac, 0x9a4f68eb, 0x2a03a8c6, 0x94acb940, 0x34038da9, + 0xa2a3e111, 0x95e9b49e, 0xc2ba2b22, 0xfdf48703, 0x8d8dd1d2, 0xf947292a, 0x5945e867, 0x487d740f, 0x784895da, + 0x3a8b05e8, 0xad82edad, 0xd7ca7b2b, 0xc318c21b, 0x845f6131, 0x7c8408c6, 0xf861c0bd, 0x31c2d45b, 0x602b3da7, + 0x380ba4b4, 0x7578c3fa, 0x29cb614c, 0x6901fc2e, 0xd858ff13, 0x17c59703, 0xad4f4d3b, 0xcab9da16, 0x3c9310c7, + 0x54ec4df6, 0xe7d93249, 0x021bd48e, 0x4c4dcfb0, 0x995cf0ac, 0x566cb859, 0xc1bb18a3, 0x2e2c3a34, 0x157e8e15, + 0xdf3e93a1, 0xc812777c, 0xf2f44017, 0xb0509857, 0x5df5afc4, 0x5882146c, 0x03f8e1ee, 0xb9be065f, 0x227ed7aa, + 0x1641abc4, 0x33b69f1c, 0x54abc89d, 0x902c1a33, 0x840fbcad, 0xd7120bf6, 0x7aa8cb39, 0x5dbc3750, 0x871d3405, + 0x24420f38, 0x32561786, 0xa9081382, 0x4000df1e, 0x81042fe3, 0x1d3eb82d, 0x77c02e2b, 0xfa9e279e, 0x7e9b3791, + 0xb1d63bdc, 0xedf0b53e, 0xcb8f1a58, 0x5879d97b, 0x2b9b42e4, 0x6bedcd67, 0x41d20fb9, 0xd817cfc1, 0xceb08c5f, + 0x6d69c30b, 0x3ecf3c12, 0x6a99c917, 0xea610677, 0x032ac1bf, 0x3b53e1d5, 0xacd38685, 0xa19d819e, 0x089b0849, + 0x8a17d612, 0x51ec1f31, 0xbe2301c2, 0x328cce9c, 0x4db216bc, 0x63f0a5ea, 0x43609f9b, 0xe2c99ea5, 0x351fad44, + 0x76ba200c, 0xfcba44aa, 0xc049b7ec, 0xbc66ede4, 0x2eda872b, 0xe8266f66, 0x3ca87341, 0x4e59b649, 0x05d9ab9f, + 0x3f74417e, 0xf9144201, 0x45dc0d61, 0xf0eee387, 0x956007c3, 0x2002bbc7, 0x22016d0b, 0xa5fbc965, 0x2d1eeb34, + 0x2fab388b, 0x824766db, 0x99e0259d, 0x5b2d79bb, 0xf4bacb74, 0x20858e43, 0xe10b9e3f, 0xceb8a3dd, 0x33932b32, + 0x5ac7d9f4, 0x9a268365, 0xab4cae33, 0xabb1296a, 0x7a4d9ef1, 0x8aad49fd, 0x78cdb8af, 0xc22bb4ed, 0x2cd506ae, + 0xfeabd41e, 0x750f46ba, 0x5656eca0, 0x3628907d, 0xef2f4449, 0x95ebdeda, 0x62510ed1, 0x2dc2ae7d, 0xaf728e29, + 0xdcb7f946, 0x234f547a, 0x956c25f7, 0x36a5ff68, 0xf042ac5c, 0x9091e598, 0x82b46bb4, 0xe466b0ee, 0x3ce82736, + 0x063b30e9, 0xaa7c97d4, 0x1901f3a2, 0x0dc62c13, 0x1e51108f, 0xffda1d57, 0xdad32829, 0xd1680d69, 0x48ef201a, + 0xc6708d71, 0x583a1036, 0x653195a6, 0xe9c7197c, 0xd52928ec, 0x0cafdb0e, 0xbda5e200, 0xd7a7f133, 0x2a628371, + 0xdeb171a1, 0x0374175b, 0x18e5e7fd, 0xc271287a, 0xe0e54c9d, 0x3eee57d7, 0xe8004a9b, 0x653e2982, 0xa2a372e8, + 0xf6b6d1b7, 0x092ce7f7, 0x1a73b4f4, 0x5e6a7f80, 0x29dc763a, 0x320045f4, 0x7e069568, 0xb6d7d8da, 0x2edefed6, + 0xcf4f8a03, 0xd3e2ac9b, 0xfc5f7a9d, 0xc389083c, 0x0a1f1854, 0xc9a0376e, 0x4aa5d730, 0x0faa4c7b, 0xfdc8fd50, + 0x46091ce4, 0xc80eb984, 0xa09fe92a, 0x48d49407, 0x28a74e3c, 0x65b64a3b, 0x4566345f, 0x736a6336, 0x0538d89b, + 0xe66c143a, 0xdd8f4a86, 0x73e2af50, 0x22c30315, 0x473eee91, 0x03420a82, 0x478dbeea, 0x4acc35e1, 0x0d9783eb, + 0xe765f424, 0xa0accfff, 0x1812ccac, 0xe6efef31, 0xe8874d82, 0xa9547583, 0xaa7b02a6, 0x92008485, 0x2ae7f8c2, + 0x48989b04, 0x3631aab7, 0xeec10662, 0xff8ace00, 0x863e440d, 0x5af45841, 0x555b4b84, 0x7db730a8, 0xd4f26efd, + 0xa83abc89, 0x375fa2c0, 0xf15a4532, 0x9667d86e, 0x94c104c9, 0xf9d8850d, 0x61d89fdb, 0xe468d533, 0x4c689daf, + 0x7b16b6f2, 0xfb99b741, 0x408a70c4, 0x483398b0, 0x3f405e6a, 0x3fb3ca94, 0xe661d3de, 0x433ed631, 0xdcf04db8, + 0x58ba6405, 0x1ce704cc, 0xf9d1955f, 0x558cd66f, 0xc5f1657f, 0xe0aa7db5, 0xe34f3ce2, 0xca6d2c88, 0x4d2b8a9b, + 0x3d914f92, 0x54e822b1, 0x3753cb79, 0x5f6dbe0a, 0x91805920, 0xd18ac8f4, 0xcc461f49, 0x69d47310, 0x723473e0, + 0xb0ab0925, 0xbdb172ef, 0x423c612a, 0xb4ddc883, 0xfd1723e0, 0x68ea965c, 0x58898603, 0x06e311a3, 0x478c0046, + 0x7567f2b2, 0x186fe614, 0xd9e4de19, 0xc5d0bccc, 0xfeadb53a, 0xc5c83d22, 0x99f296af, 0x15850c35, 0x149ea82d, + 0xf8575204, 0x747c4e2b, 0x3d053315, 0xd7822994, 0x4596e227, 0x64db09cc, 0xe63f2d31, 0x0e51fc29, 0xe2863756, + 0xbf71164c, 0x6e1af52d, 0x91bbe730, 0x1ca369f2, 0x69c5bbb6, 0x65f72230, 0x5d8a2867, 0x77a9cb68, 0x804cf6ea, + 0x2f5639b1, 0x6c157336, 0x8d680a38, 0x9364af5b, 0xcf771048, 0xcd04b48f, 0x9ef48770, 0x282944ba, 0xf261c7ad, + 0x23f5c2d1, 0x56137510, 0x6e6b3363, 0x21059bf2, 0x16bc2c17, 0x1bbbcfd3, 0x3410e074, 0x3c9a27ce, 0x84e2c356, + 0x84db0a45, 0xbc545bc0, 0x405cc8c6, 0xece627bb, 0x76c4580b, 0x160a7333, 0xc7bf7bce, 0x43480bba, 0xb4586fd8, + 0x817b7190, 0x14e32bd6, 0xcdf8a22b, 0x1cd42b3a, 0x7064d172, 0xf91016da, 0x48acff88, 0x195b296e, 0xe8ab9366, + 0x37a63daf, 0xb61d2121, 0xef5aeda1, 0xec0c8912, 0x2d8fc5ee, 0x2ce730fd, 0xb03882e7, 0xe7b92da1, 0x78e4e883, + 0xe127f6ec, 0x5e2cb5ec, 0x70b58009, 0x36f719bc, 0xc98af5cb, 0x7c3b8251, 0x30a4e959, 0x4afa9dc2, 0x7a2359e5, + 0xbd090c02, 0xc8d0a615, 0xe005f0ea, 0xf9dd70de, 0x40217ad4, 0x57564e92, 0x44a9b0a8, 0xe0365bde, 0xfcac41b5, + 0xd65db2c8, 0x1dd08b1c, 0xc0c651ab, 0x6eb0145d, 0xec5da3a6, 0x83e1e5d2, 0xce600478, 0x670e7b67, 0x93e60a60, + 0xec0d51dd, 0xbaf91d46, 0xf11a4ba2, 0x04e4ab38, 0x0486ff71, 0xf997d55a, 0xffeec27d, 0x0d7f35a4, 0xce66e67a, + 0xcf0b5969, 0xdd2b6626, 0x36b1ebfa, 0xe1b02f65, 0xdbe7ab49, 0x6ad38549, 0xae403f1c, 0x77f38357, 0xcfd82bd8, + 0x352dda03, 0x796a9c08, 0x6dd75045, 0xf1908da8, 0x2d598ce1, 0x506beb00, 0xea29ee88, 0x643216e3, 0x9593887c, + 0x6d69af2c, 0x01507ecb, 0xc856d643, 0xadbe6784, 0x3e94f147, 0x5ce5e8b6, 0x2f5aed83, 0xfdd26d5f, 0x3fae2570, + 0x0bf6d183, 0xf75dd695, 0xea484809, 0x89f8bcb3, 0x4850b01f, 0x711c09d9, 0xf508dfbf, 0x8e492686, 0x5f92486b, + 0x3cb0825d, 0x34003d83, 0xd939690f, 0xef1596e6, 0x3d5ccad3, 0x178e6a61, 0x4c34b375, 0x7145fb82, 0x283bafce, + 0xb1594f17, 0x282ec3e9, 0xfbfce3ad, 0xdefa2f49, 0x30b2aa8c, 0x73909709, 0x289d0169, 0x605049b5, 0x32fb154a, + 0xa7a1708e, 0x42ccdd36, 0xaae7a5ea, 0x245d596c, 0x0bb1714c, 0x020b2d7a, 0x0689b2d9, 0x75fbae43, 0x9d1ef5b1, + 0x14b75944, 0xf318648e, 0xd6070433, 0xf64427d5, 0xddc1a1f5, 0xfce1fab2, 0xc6929596, 0xe6cecd8e, 0xd8fd726f, + 0x6ec27cc0, 0x7898afe4, 0xa67f0055, 0x43235b03, 0x43650b94, 0x40a2c5d2, 0xc6642d53, 0x7aa64281, 0xe76dbd8d, + 0x13d4ce51, 0x82f463cb, 0x67fd188c, 0x4e9b87ea, 0x4de33631, 0xf95631d0, 0xd1fddd1d, 0x77fadc86, 0xdf91b430, + 0x699e2356, 0xbc655f74, 0xfad965c1, 0x6c47b5ab, 0x4ecc8a3c, 0xcf5435e4, 0x8dffbd6e, 0x7bce8e60, 0xda495460, + 0xdc4b0a12, 0x266ec2c9, 0xa200ed2c, 0x393db90c, 0xefad6956, 0x46027de3, 0xa39ccb9b, 0x2e894737, 0x34828883, + 0x9ce25bb4, 0xb871a29c, 0x5feb71c0, 0x43c2d9a6, 0x301910c4, 0xeb273b35, 0xb5ea5ef1, 0xf0963075, 0x241f4612, + 0x2b3daa39, 0x6f4c9dab, 0x11ce663c, 0x03a1c8e0, 0xe11425af, 0xd2812201, 0x22c3e45c, 0xc22f89fc, 0xf4f10db3, + 0x51dcce15, 0x7a4d14fd, 0x1a6bc777, 0x3cb6705d, 0xd9bd8ccf, 0xbb23b09c, 0x40bb0cc9, 0x6c15196f, 0xf384ecbc, + 0x12e2edd8, 0xe9c39a7e, 0x3cd218b2, 0x3bb9bfe8, 0xd0e0db53, 0xd0fb2388, 0x786738c8, 0xd80bcc25, 0xe24a6f65, + 0x3d9ab7d6, 0x86f228c9, 0x93aa1112, 0xe5377992, 0x4fd817ba, 0x7d9b8642, 0x199600cb, 0xdaaadd72, 0x951c740f, + 0xf799d74f, 0x8264c652, 0xc679a004, 0x02ae8d58, 0x0ae1a3f3, 0x5c0a89e5, 0x5838ab14, 0x66aea565, 0x0dde6022, + 0xbda58428, 0xfc6c8aad, 0xfe432f06, 0x99be9eab, 0x68fdf000, 0xb0ab7f44, 0xa569a111, 0x926c51c9, 0x9a3213a1, + 0x12b95f69, 0x411fc2e3, 0xafefc718, 0xf16489bb, 0x1d9d0654, 0x05ddb0d7, 0x745e3bd9, 0x0c701cba, 0x2606afea, + 0x385b9f02, 0xedd22711, 0x61fd1847, 0x8b3c1aef, 0x360cd7da, 0x3e275692, 0xc6c68967, 0x9f663397, 0x46e8d3f0, + 0x8b489984, 0xe21cbc65, 0xdebbd9d7, 0x021d132e, 0xbdcb5def, 0xee85c61a, 0x275a611f, 0x8720651b, 0x3907a931, + 0xe08b7c65, 0x0fdfea60, 0x619fc5cb, 0x457ee39b, 0x2629061c, 0x2b7638b1, 0xf7f14d99, 0x8f34f43b, 0x6ca3b782, + 0xa27c83e1, 0x77cfd58c, 0x59d822c5, 0xbcf282a4, 0xce1c4246, 0xefbfa997, 0x87e00ad3, 0x48115105, 0x7edf3b88, + 0xa73ccb0c, 0xc32921b8, 0x4af55de0, 0xeacaa0f1, 0x871fe2ce, 0xd2788c90, 0xa4cb80be, 0x559403a5, 0x577364a3, + 0x202583d0, 0x7ba955ec, 0xfca38609, 0x1ad98526, 0x651566d0, 0xb5323d30, 0x64cdf09e, 0xa66e8f1e, 0x77ac10f3, + 0xb08fd628, 0x85b5ed16, 0xb03b129f, 0x2b2dc595, 0xefcf2c40, 0x00622c0e, 0xbe951421, 0xe4e0fffd, 0xf07fd0e2, + 0x6e6d108c, 0x079e3780, 0xe439eb0f, 0x0da9c4bd, 0x9b0a858b, 0x063e7b4f, 0x6689993e, 0x3fbfe627, 0x360875b4, + 0xccfd4ee6, 0x660eb727, 0xeaf9ad76, 0xdc9af916, 0x7c124138, 0x30d39829, 0xe5c4e3cc, 0xa05ea0c9, 0xa6afcf1a, + 0xf63558c8, 0x1fc73a1e, 0xd2828dbc, 0x822aad45, 0xc52ffc4e, 0x6788f673, 0xd0ab04f0, 0x36615f60, 0xcb0e1ab0, + 0xf984fe44, 0x3103ef8c, 0x5340bb8f, 0x8c88047f, 0x85dab5b2, 0x057c70b6, 0xacae37eb, 0x4623569c, 0xe27e7211, + 0x28dc1668, 0xc5ad899f, 0x9b221a3e, 0xc0644454, 0x32c6fc89, 0x089cd97f, 0x162d686c, 0x6f4fa81b, 0xcc44870c, + 0xb2faebad, 0xfbd888ab, 0xace553a8, 0xee86dcfc, 0x07ba0bd0, 0x769a332a, 0xab0d2593, 0x8cd5a999, 0x2121b235, + 0xf40c642a, 0x1d423aee, 0x317da651, 0x1eb255e4, 0xafb045c0, 0x012132f7, 0x4da258a0, 0x2b34109a, 0x7c280bcd, + 0x5e436503, 0x2862eba7, 0x907f60dd, 0xc6df57e8, 0x7f7d69ab, 0x12a89f7d, 0xc0dcc143, 0x2240a4d4, 0xcfc8be6c, + 0x22867113, 0x9e40c835, 0x8af113dc, 0x26ba7443, 0x67c4fd28, 0xb8f14451, 0xc291b128, 0xf587ef51, 0xdd31bd58, + 0x7283b84a, 0x611d3a2a, 0x4c514c37, 0x78c71e47, 0xeb4c2a16, 0x53c49eea, 0x959d720a, 0x2c9e6eff, 0xb944df76, + 0x679e51e2, 0xf4c69364, 0x7989fd8f, 0x5f060f07, 0xc3df67d5, 0x54df52ae, 0xfe888cf4, 0xa05e5b6c, 0x4031c75f, + 0x4a9fe645, 0xb796a526, 0x1c56b1bb, 0x5a2afb4f, 0x3986c8a3, 0x6fa21049, 0x8ba1d831, 0x3d21740c, 0xcb31c268, + 0x93ccb342, 0xc2271a3c, 0x851c4c8b, 0xfa32fb0d, 0xadb22eb1, 0xcd0bdd6f, 0x32346fca, 0x27ac7e74, 0x266caf24, + 0x38e2254d, 0xb91b1df9, 0xa2e1bf00, 0x023adffc, 0xe459557a, 0x7fa981f7, 0x4f2f2d4f, 0x18630502, 0xe69f9850, + 0x2b1240e4, 0x3e7cb049, 0xcf7c5ab8, 0x37d97966, 0xcf3114fe, 0x66be3082, 0xf059bfa2, 0x700be66d, 0x6813d2c2, + 0x7a876923, 0x9761a7c6, 0x5d52ee4e, 0x9f072974, 0xa5954652, 0x99fea1d7, 0x615e96cc, 0xd8417400, 0x66adbf96, + 0xd3e2a3a0, 0x4a96956c, 0xea947542, 0xceac2202, 0x80359a68, 0xc657ee66, 0x1e052e6e, 0x163ace84, 0x2c72da8a, + 0xd2cb5f38, 0x1abd8568, 0xdacbc6e5, 0xd173f0a1, 0x4fd046a9, 0x3bc72bf6, 0x82db4242, 0x47a8f42c, 0x57a3dd1c, + 0x36eebe61, 0x978c1c30, 0xb240669d, 0xc92cb283, 0xcc2dfe69, 0x5e17236a, 0xf8e005a5, 0x6ad7d82a, 0x0fea5d0c, + 0x3ca34ee8, 0x6d6eb19c, 0x42264c91, 0xe247403f, 0xc73b498e, 0xea9eba20, 0xce045caf, 0xd2530480, 0xb55e2aa6, + 0xfad4c751, 0x747c27d3, 0xa0f8ec60, 0x9ee4fa65, 0xd8f7afd3, 0xee6ffa32, 0x903557f1, 0x3353ddd7, 0x00ad75e4, + 0xfd360df6, 0x68751ebe, 0x328c49c3, 0x9f4c35b1, 0x0fa4dbf7, 0x9cd81f81, 0xfc1fe87c, 0xa9cdf341, 0x157075cc, + 0x16eb5113, 0xdab1b4a8, 0x47ab34f2, 0xad0d7037, 0x898b121a, 0x7266dc56, 0x3cd7e8d3, 0xa9b02b81, 0x83c7dbac, + 0xc74c645a, 0x844b268a, 0xfdf750ec, 0x2f9db5dc, 0x8acf91ce, 0x78a75b4f, 0xbc00ba72, 0xa117dc0f, 0x514dc1e9, + 0xb16ab40b, 0x1cd9fc3b, 0xae9fd13e, 0x167b1eb4, 0xc90ed386, 0xf8b477d6, 0x5ce2fd3d, 0x8092c3f4, 0x174c7d82, + 0x0180d2f9, 0x2030b93b, 0xa3fefd95, 0x6a72c1f1, 0x3f357158, 0xb2d45d9e, 0xf962057e, 0x82221aa3, 0x64032595, + 0xb84ddba6, 0x59f6350a, 0x15589f00, 0xae851de8, 0x09df21bd, 0x12b637e7, 0xfaf3fbce, 0x0375c239, 0x1cf697e2, + 0x32264c35, 0xa62167ef, 0x9a1f9f54, 0x8c14aa4d, 0xed5cf2f4, 0x83db36d8, 0xbd8d6e71, 0x5ab930c7, 0x0ea28131, + 0x2c6b067e, 0x94757fb5, 0xd6910899, 0x866d84b9, 0x3eaabf0c, 0x1da23144, 0xc94f8068, 0xf21a5f49, 0x784de0d4, + 0x7ce8eede, 0xb097d1bf, 0xcbe09fba, 0x2f99a891, 0xfc074367, 0x5dc8bc1d, 0x2efaa3e9, 0x8ce28f28, 0x5899ba4a, + 0x41e7600f, 0xc4473258, 0xd00a69ea, 0x86a02f9c, 0x66a62395, 0xed1d684d, 0x1579428b, 0x8dda92b0, 0xc27b9a1e, + 0x8ff27a3c, 0x95a4e697, 0x99a2f534, 0xc2bc8bad, 0xf75e2e07, 0x75dece25, 0x166c5e32, 0xf938cdb5, 0x78e3308e, + 0xcee7af1a, 0xc35389ec, 0x244a5b51, 0x7d96583e, 0x7f4a48e4, 0xb9c258a2, 0x73742a1c, 0xdea94b49, 0x080e63c4, + 0xb649a77a, 0x2883ca92, 0xb2e37a72, 0x7c459755, 0xae72c1d9, 0x69ee6ec5, 0xdc9a9f4c, 0x050ec791, 0x6e7212f4, + 0xd2295278, 0x6d029db8, 0x8fe251b3, 0x5084b94f, 0xbd85f67f, 0x284bf797, 0x278ffc3a, 0x72414b05, 0x9956db27, + 0xa41273d7, 0x8b9a7668, 0x36fe8cd2, 0x5caacdc9, 0xcd7747ab, 0xfee3e39f, 0x2c648d9e, 0xc1580e10, 0x999d6284, + 0xea6da858, 0x7a11a448, 0xc2c11665, 0xdb8f3aeb, 0x37e69245, 0xb3d9fb7b, 0x0918556c, 0x99c349d4, 0xdd56cfbf, + 0x4dbb2fcb, 0x57f38301, 0x26c5f69e, 0xd73fc7de, 0xe5c4a421, 0x754e543e, 0xc7d14bbe, 0x47463f99, 0xbe4cb1b0, + 0x8d020c5d, 0x89449d2e, 0xa9de4884, 0x2f372081, 0x3f126531, 0x8cd24363, 0xa0ba63a3, 0x7d337db2, 0x7760f1d5, + 0xd2d9af60, 0xf1424681, 0xb7b57919, 0xba7594a1, 0xa38c1764, 0x36e59ab5, 0xe6d0ca4d, 0x6e25bd71, 0x54518cb8, + 0x6a31c52e, 0xa224b086, 0x044839cc, 0x6a6a8835, 0x65bc7177, 0xedff693f, 0x6b3c968d, 0x28972c99, 0x42068373, + 0xb0aff035, 0x18414496, 0xd714017f, 0xef4719e9, 0x1a64d050, 0xf3f32cdf, 0x678af377, 0x05a78090, 0xd2c4718b, + 0xfba454eb, 0x428d619e, 0xbb9da273, 0xcc211d48, 0xaa3fc703, 0xf44de746, 0x3ab2560f, 0x9891d9f8, 0x0e02c5a0, + 0x949afb35, 0x99bb4a8a, 0x7842cc8b, 0x557a2643, 0xec655f71, 0x6f005b59, 0x21aa1dd0, 0x745cccdc, 0x59c442ae, + 0xabc6c8fa, 0xf9b97cd9, 0xa3d4911d, 0x7a0a9f01, 0xd56d5114, 0x076a5166, 0x6ff80017, 0xa09ddf8e, 0x19688e43, + 0xfe9a9d49, 0xbc1bb3e9, 0x5e76a91a, 0x092d12fc, 0x876fa481, 0x4288b500, 0x06861333, 0xf4e5b0a6, 0x2b105c96, + 0x1c75c029, 0x3d5fd41d, 0xcd797421, 0xde58660e, 0x38a6df6a, 0x9a970382, 0x6b5af20d, 0xf8ad6d29, 0xe04fbe9a, + 0x964c85db, 0xb51228fe, 0xed60d8d5, 0x982d6fc4, 0x86f756b0, 0x59cd2ac7, 0x4d736ea6, 0x6a77b07d, 0xb4227634, + 0xf0553d2d, 0xbe808338, 0xbcad7508, 0x3d0b56ff, 0x44bb7daf, 0xfdc7a2e1, 0xbaac6833, 0xe62d272f, 0x972c9958, + 0x96042931, 0x8884a59c, 0x6eaeb38a, 0x0fb1cd23, 0x5a04e150, 0xf1d99a51, 0x7ef4c706, 0xad686f73, 0x5426ab89, + 0xc777da87, 0x542f6b20, 0xf0bd1e3e, 0x2716aae0, 0x908a0d5a, 0x64e2df96, 0x6a27ff90, 0x5ac9884e, 0x3e10dbb3, + 0xacd45a59, 0x63f8f2bc, 0x994a949a, 0xe9746d03, 0x5981f10f, 0x34a0792c, 0x26dcb7f6, 0xadbd77d2, 0x933ee19f, + 0xe15ed709, 0xd0fce82b, 0x7eaeb380, 0x047eea00, 0xbe527eb9, 0x5bc8d206, 0xe223daf6, 0xaef49eab, 0x81b2709c, + 0x2c80e789, 0x855bbdf3, 0xe149eece, 0x4e9f3331, 0x67554f7b, 0x3007d5c9, 0xc57f906f, 0x359cd060, 0xb74ac336, + 0x81f9e6f3, 0xe2ded01f, 0x4f53d17f, 0x3c24bfab, 0x0fee88ec, 0xc8a2609d, 0xc5d4067e, 0xf4228a6b, 0x210fc535, + 0xfe1f9107, 0xe06a5e2d, 0x4f26ab14, 0x37fd258e, 0x746e753e, 0x45732df1, 0x97fe0ca8, 0xeec8cf0f, 0x607cfbd4, + 0x14f447a0, 0x9028033b, 0x0df2ead8, 0x2dd4fe9c, 0xa2fecad1, 0x60ddce35, 0x9583459f, 0x8ba614f0, 0x0b061128, + 0x046edbb9, 0x89856562, 0x4912ba1d, 0xcfabb13d, 0xc739614a, 0xa2ff8e68, 0xfdb3091d, 0x1a824189, 0x63e52beb, + 0xf0d12919, 0x726848f8, 0x0694b0be, 0xdc594fb9, 0x1e5d3f79, 0xf2b7a7ba, 0x6bafc002, 0x5bdcf5b0, 0xda0ea50f, + 0xc7a326fc, 0xa145d312, 0x59db7062, 0x8394d8d5, 0x669d686b, 0xd66eda4e, 0x5472bf16, 0x4835ba0d, 0x192013ae, + 0x9b625dcf, 0xedc1550a, 0xddee7eb8, 0x91dcafcc, 0x66c800dc, 0x3285daae, 0x8c054de5, 0x73c83a8d, 0x17c238e2, + 0xeed3d270, 0xa4e738c7, 0x1b026477, 0xf83b6e1d, 0x11f34833, 0xc58265a2, 0xa55d1e6f, 0xeb382596, 0xcfb72062, + 0xb41d9b68, 0xc9436064, 0xb31a5eb7, 0xa8c99db0, 0xaf106bbc, 0x3d6d2041, 0x144b3047, 0xd4bd2934, 0x5d0a6825, + 0x4a6ab2f4, 0xd54e103f, 0x479f5f04, 0x7ff9cc44, 0x1c3cdb0f, 0x9d0f870b, 0x33a077cc, 0x9454acb7, 0xe68c9ea4, + 0xb1a83829, 0x3e103d76, 0xbf872126, 0x4e8572ce, 0x999aa757, 0x9f619e9a, 0x075d9356, 0xe89b414d, 0xf9111341, + 0xe5bb9cd4, 0x2565008e, 0x3f60c402, 0xc9b7f5f6, 0x5ba3fa58, 0x24f6f43f, 0x0b2af0fa, 0x9e62477f, 0x735d410f, + 0xd2c54a03, 0x3978d2ac, 0x3455534a, 0x54a1f002, 0xb5fcd079, 0x17e9d20c, 0x2dc889a4, 0xc3300271, 0x6354c6fe, + 0x5f9c0510, 0x575c63bf, 0x10b009e1, 0x20d9816e, 0xe37f5f99, 0x3274aa6d, 0x612d1da4, 0x10f9280f, 0xa2575806, + 0x154fca4f, 0x071e6a8e, 0x7a5cc055, 0x44872ddf, 0xcff240f8, 0x9ece09b4, 0xa198dfb9, 0x0d57636d, 0xf25922a3, + 0x59f1b0dd, 0x9c47ccdc, 0xde5d34f0, 0x55fdfdbc, 0x8f05e9ce, 0xa80d30e9, 0x20d24033, 0xefd29ee5, 0x3077fad4, + 0x6c2d1a4f, 0x73df88d1, 0x3a55e8a5, 0xd7b66b23, 0xa2f8a2bd, 0xc03ffb01, 0x2c34aebb, 0x7e3ef5ee, 0x90b2be91, + 0x0b7c568b, 0x127245f7, 0x874d3e61, 0x6b9c608e, 0x4b9a7e72, 0xcc33ac42, 0xd3379b37, 0xbc5f3a89, 0x9af0d950, + 0x717411f0, 0x6e3a8ada, 0x9f1429b2, 0x1431c05d, 0xd8b289d9, 0x101be6c1, 0x60813256, 0x6c334b10, 0x8e83de62, + 0x6f9c891b, 0x3a3b6ac7, 0xc78fab95, 0x8e481dd8, 0x437bd6fb, 0x88829dd6, 0x6f392c34, 0x4b9faee2, 0x9557bf08, + 0xd7c92735, 0x3bdb8150, 0xd4d6ee05, 0xfaa3886e, 0x0c195d93, 0x3cef1bff, 0x250362b6, 0x3c905f5a, 0x2d9b9ab2, + 0xcb270516, 0x75c31dda, 0xda499cf6, 0x062560a9, 0x22de16d6, 0x5dd3f7b5, 0x7c960c2f, 0x6fbe7aa0, 0xbec14dcd, + 0x1d58035f, 0x1bcadc8a, 0x5181e53d, 0x42a4901d, 0x66c1f170, 0x8be3d3e7, 0x40c1995c, 0xd39c6f0d, 0x1b1234cb, + 0xdfa90a2e, 0xbbb70e81, 0xf41e7b65, 0x623a5a37, 0x0dce2c9a, 0xef39bd29, 0x35474842, 0xdff2acb2, 0xe53ea845, + 0x22ba8be3, 0x854ef405, 0x3b2adff0, 0x783d297a, 0xebdacbe6, 0x849e94f7, 0x1c0cbdc9, 0x8ff23426, 0x7958bccc, + 0xefad5f25, 0x13e6c166, 0x58872199, 0x1c2a414f, 0x03112231, 0x8a7647aa, 0x2e233574, 0xe5c86c25, 0x16861db7, + 0x91609cec, 0x95ee810c, 0x37fe0e8b, 0xbf55bb1a, 0x26e746ef, 0x13adeec9, 0x7cc718d3, 0xe2de50be, 0x923d8d31, + 0xe9845171, 0x21a1a4ab, 0x99759936, 0x388726f5, 0xc53fab3a, 0xb3d9360c, 0x1ff558a5, 0x0675b00e, 0x9aecee77, + 0x453a2f5d, 0x8be07e4a, 0x580d8124, 0x886874fa, 0xf7cdb242, 0x4da5ffec, 0x7bf12be1, 0x6b1398bd, 0x8339f94d, + 0xe9e67b3d, 0x8b24a0c7, 0x2aa706b1, 0x37c19e6b, 0x76ecbf30, 0x313488eb, 0x30e8fbd0, 0xb926152c, 0x6c14591b, + 0x2aa1c7d9, 0x6c43ff38, 0xe7c1b990, 0x41770349, 0xffe77de3, 0x0b6ac0aa, 0x1f1bf097, 0x510d197c, 0xc4d71dc3, + 0xd946a8ff, 0x96b81186, 0x2124ad41, 0x8bcdc139, 0xbf36de97, 0x6861ad2b, 0x4a324352, 0xc9b734c9, 0x51edec36, + 0xa7a393bf, 0x003fc73b, 0xc31997d9, 0x5acf0a61, 0xaf728325, 0x3fd87376, 0xfdda2ba4, 0x19fda677, 0x252d69f3, + 0x86ab80ee, 0xba0081bd, 0x48294345, 0xc01b858e, 0xce50ac8a, 0x105759e7, 0xd548c117, 0x2eb08103, 0x39c11769, + 0x93d30f1e, 0xd830c9fa, 0x9c554137, 0x616dc123, 0xb38c55d8, 0xb869525a, 0x37033201, 0x3ba4bcde, 0x1fa24d77, + 0x94c4e3e3, 0xbb742f07, 0xf6a4048d, 0x80fa1dd7, 0xbfd77b83, 0x5af3f8fe, 0x2da3394f, 0xddb8eb7f, 0x04630cf0, + 0x2dd3309b, 0xd57f802c, 0x0df1f23d, 0xb065270f, 0x73489ab5, 0x8cfafc43, 0x299798ba, 0x88607cec, 0xed1d84e4, + 0x1ab234f6, 0x076612d0, 0xa3e46ec4, 0xaf4dcb72, 0x229c3f67, 0xee7d6483, 0x52ee8396, 0xbf484b60, 0x05b1327e, + 0x4afb39d0, 0x4a70b623, 0x8706f5e5, 0x8c565955, 0xd8b90035, 0xe30fd5ac, 0xab62424d, 0xf4ddbba6, 0x9e86f3eb, + 0x6e5a630f, 0xf8d34a16, 0x8cd93e15, 0xb7edfe3b, 0x1773e20d, 0x8763adb2, 0xf0e4a856, 0x93ca89dd, 0x0e82588e, + 0x3b257d27, 0xf01b1815, 0xbe4ddd8d, 0xc4689583, 0xae02bc92, 0x6a75ef0f, 0xbee16afe, 0x7a02afab, 0xc187804d, + 0xebdf4ec6, 0x035ea689, 0xbfef25d2, 0xca9024f8, 0x54297816, 0xf4bbab16, 0x602d58a1, 0x454f14bf, 0x29ffa5f9, + 0xd07ba4d1, 0x331acdf0, 0xcbd098cf, 0x6827b253, 0x4ca1bc26, 0x5d2a863d, 0x1cdcf635, 0xbd45acbb, 0x04fecbae, + 0x051af73f, 0x81604f30, 0x668e1d8e, 0x39b7911f, 0x699e64f3, 0xfc03f9aa, 0x03042fcc, 0xb077a533, 0xfa8d0af0, + 0xa7ecdbff, 0xc46cb89a, 0x0ecd4071, 0xd65b7e25, 0x92970b8e, 0x10271c7d, 0xd5af596b, 0x6e4dd0a4, 0x35b7a9f1, + 0x3c719c8c, 0x49f935ac, 0x1e60b2d0, 0x32966fe7, 0xe96da242, 0x34d20ea0, 0x3e840c9d, 0xde9c0708, 0x19966e9b, + 0xce4126bb, 0x1d0e5a1d, 0x5fd09e59, 0xf4d9a0a0, 0x2e140e98, 0x1a52b201, 0xf58c3792, 0x78dc9c3f, 0xe00de261, + 0xb89f6cd3, 0x61cc500e, 0xf848c2c4, 0x4b9f4a0f, 0x7ff64ef0, 0x8a7a700c, 0x2b73f248, 0x990ec954, 0x21974595, + 0x89f67305, 0xfb254838, 0xd600c929, 0x291f967c, 0x465c8b7a, 0x60c914c0, 0xe1ac8ea7, 0xf2239e16, 0x8e2aa417, + 0x35272018, 0x595c17e1, 0x90c09cb7, 0x3b3a447b, 0xc7e7a048, 0x6ff5aba3, 0x6a42a381, 0x064e568f, 0x000bd8c0, + 0x5cea50bf, 0xe9f1d264, 0xc715af7a, 0xf62f0318, 0x416c57d5, 0xaa698ad3, 0x1f300b5b, 0x1222e5b3, 0x558c33cf, + 0xd70efdc7, 0xa36d742b, 0xdd7bdad5, 0xc3b8a753, 0x71823fe8, 0x9cdb1b64, 0x5ad73183, 0x545fcd62, 0x7a17137c, + 0x23c6d5fd, 0xb94f0b6e, 0x5ac7432e, 0x22f319f0, 0xdd84e204, 0xbb2d1b3b, 0xb39ab82e, 0xcb5e36fa, 0xa287920a, + 0xe41701e6, 0x0855ebc6, 0xbbc11420, 0x86dbc86f, 0x58652e47, 0x68ddddef, 0xf1dca454, 0x22b4386d, 0x3d6a1d28, + 0xd9f273d0, 0xc0f97579, 0xea8cb765, 0x27f11933, 0xce283f59, 0xb35fc766, 0xdc01e8a2, 0x13b2e944, 0xf9c3e753, + 0x0fe04df5, 0x65203094, 0x9934dd00, 0x4c68540f, 0xc84750cc, 0x38222321, 0x4b90db98, 0xd5919352, 0x9b8902c5, + 0x11b4eede, 0xcd612909, 0x6426b8ff, 0x0f1175c5, 0xf9cb462a, 0x58c9c4e8, 0xbfc11a64, 0xd8065af0, 0xbc814bec, + 0x3bda382a, 0xca773ac9, 0x408e859c, 0xa0aebb32, 0x6ea99cf2, 0x334a414a, 0x0560f4db, 0x7e14855f, 0x38d1079f, + 0xc77e22b7, 0xd41fffc0, 0xdfd26a44, 0x6a8b11b0, 0x768a47ba, 0x0cde3249, 0x45439124, 0xca43dc88, 0x70eeaa98, + 0x94ecdca5, 0xf0e62883, 0x244f04c9, 0x39041d27, 0x0f6ba98d, 0xa303848e, 0x2cff73cb, 0x7d926702, 0xa56a28a1, + 0xe9d124d9, 0x3a64f359, 0x17cacb3a, 0x8073e1bc, 0xb3376989, 0x52d148dd, 0xf5c91376, 0xc33da6fc, 0x609aaf61, + 0x3bbf5ad0, 0x5c569060, 0xed81be7c, 0x3708f9e8, 0x369fe068, 0xc65b7b04, 0x0e645aff, 0x782ffc17, 0x35b097cc, + 0xa79a1ca1, 0x84fc1652, 0xbced185b, 0xf454bc28, 0xb94b5586, 0xce44a1de, 0x7df51665, 0x951cbb29, 0xbcd2a469, + 0x8f983f40, 0x105e0bdf, 0xf96d4d64, 0x9f9c7a03, 0xcca94fc0, 0xb93ea388, 0x7c1fdc72, 0xc33b338b, 0x2821da1c, + 0x3bceeb15, 0x493cf474, 0x418b58c1, 0xd4db36df, 0xc5f8e58c, 0xa5e5fd39, 0x2fc2e0b3, 0xb38c5ef4, 0xa972ef47, + 0x121406ad, 0x0136b1a2, 0x708d0ccd, 0x39d39eed, 0x7d5a2c63, 0x5d773cb5, 0x5616b679, 0x341fd853, 0xb218c6eb, + 0xe83772f2, 0x1f7c6157, 0x62a00dea, 0x50ecc744, 0x35e4e260, 0xc71cd237, 0x87d5be8b, 0xcbcf6f8f, 0x1edd7785, + 0x20806a50, 0x3c7dce0c, 0x34446d29, 0xa803d2ff, 0x5a9c306f, 0x89fdd015, 0x24658608, 0x88c86094, 0x3936e31c, + 0x581e6667, 0x8a589eca, 0x9c4dd5cc, 0x484a2840, 0xfd0063b8, 0xa8a91c76, 0x233df8b4, 0x763a0a99, 0x0e853e1f, + 0x5177fa56, 0x527c78b1, 0xb0536f64, 0xecee8b10, 0xacebfece, 0x4396f67a, 0xad35c2ed, 0x06696167, 0x054392d0, + 0xbbdbb29e, 0x92b3a9e9, 0x8427709b, 0x194f5639, 0x130d95ba, 0x790f2230, 0xc669fd83, 0x71c794c6, 0x95a03e62, + 0xa56f449e, 0x640efb4c, 0xfc864eb0, 0xf3a14979, 0xb29b8ba8, 0x6d33aa86, 0x8fc27940, 0x8a6bdbc8, 0x2f7e059e, + 0x1fb95099, 0xbd7f3575, 0xa964914f, 0x74b3eda6, 0xace3c31d, 0xe6ddb456, 0xcb7a1fdf, 0xd9a4ead8, 0x890c93cc, + 0x8c746a8b, 0xa658dcdb, 0x16a708ea, 0xb1e8bacd, 0x87c5b37c, 0x1312ae36, 0xc1e7eba1, 0x82831823, 0xd7d0e545, + 0xfeed1392, 0x4c56628b, 0xb591ac7f, 0x3239cd6f, 0xef32ed3f, 0x3793a9b4, 0x1a4748b7, 0x039b62ce, 0x6c40cf85, + 0xd341b848, 0x80d5dd6d, 0xce4d007b, 0x5e29f677, 0x9ff1373e, 0xd1af0ced, 0x9d6dc878, 0x4d48fb30, 0x9869e15b, + 0x33286348, 0x2bba0716, 0xe3515c2e, 0x5ea6f695, 0x533333a8, 0x5d198a7c, 0xbf8593f7, 0xcb49824e, 0x6780d06d, + 0x41f4a61b, 0x33ebd29e, 0xcded8c02, 0x19f6dbd9, 0x2951eddd, 0xabd832ad, 0x1fe948a2, 0x6227d60f, 0xb72d783a, + 0xb3b4ae03, 0xf443ee4b, 0x275d8dd6, 0x1e2e75d4, 0x4131304d, 0xa1f371de, 0x676d39f0, 0x1f2b9834, 0x13f034e7, + 0xecd33cfb, 0x452e8114, 0x29a400e3, 0xb8df54be, 0x75fcd30e, 0xcf2d3378, 0x4341ae1e, 0x6b75fb93, 0xd895b705, + 0xc8f7b4a1, 0x88483c4a, 0xac5b0329, 0x07b89bca, 0x76c689ce, 0x4e52c31a, 0xc82e74fe, 0xcfa7192b, 0xe1b1cd07, + 0xcb72ddbc, 0x0f3dc362, 0x9fc865c0, 0xb2fdc21a, 0xc09a62fa, 0x0bab71a4, 0x49fa4a4a, 0x5736a467, 0x47dbf1b7, + 0x45639814, 0x4ce399ea, 0xf4e67407, 0x453a76bd, 0xd0b69633, 0x170db096, 0x1e0c3e03, 0x6d877ffd, 0x7d7d5e63, + 0x86855711, 0x7a69729d, 0xcc2285fe, 0x7e5a4a45, 0x085bcd62, 0xce0373d7, 0xe878bddb, 0x770e2400, 0xb2a84d13, + 0xa450a364, 0xe7d8fc18, 0x2227d6c1, 0x90c2084e, 0xaabaad18, 0x2b2f39dd, 0x3125c9c3, 0x0d706176, 0x3ed59793, + 0xd84e246a, 0xa70bd613, 0xca8fb61f, 0x51d724ce, 0x43d94332, 0x1458bb2d, 0x64208368, 0x8dab20c0, 0x364ed40c, + 0x5811b49b, 0x3d92217e, 0x154b9571, 0x113cf065, 0xa478c15d, 0x1c7cb4a4, 0x369ff193, 0x48cefe7b, 0x55ea8c1a, + 0x7035b3d1, 0x8a0e5d7c, 0x85e1a45b, 0x71addfef, 0x44957fb1, 0x3e04fdb2, 0x0d6060c1, 0x2220976f, 0xc129c53d, + 0x53f8b3ca, 0xfd30e9ac, 0x6bdf0be1, 0x3d2bd65a, 0x389f1c18, 0x31638353, 0x77523e2a, 0xca817d05, 0x2526bfae, + 0xa3946b27, 0xc108a702, 0x4c5a9c53, 0x60338292, 0x521a9b79, 0x145454fa, 0x29fa570f, 0xf0645523, 0x43fc5c85, + 0x889adbb4, 0xf177dcbd, 0x96cfae1b, 0x04475539, 0xbcafdcee, 0x29093af7, 0x4c6d9dd5, 0xebe5bf9a, 0xc363e6d3, + 0x27af00db, 0x51d19602, 0x8a0136c4, 0x61dba6fa, 0x5813c0a9, 0x4053f8bf, 0xef03b07f, 0x0c3cb7c7, 0x41033b01, + 0x39f089f1, 0x64cb3ecd, 0x8372b20d, 0x0dd9b9ab, 0xe21e85c8, 0x773e5614, 0xb94e1dc8, 0x5e4b5b82, 0xa86f2538, + 0x2817a7be, 0xc0ffaa86, 0x82bc4bb2, 0xf6a5aecd, 0xa282bee1, 0x78da7521, 0x57225f5b, 0x9c9b033c, 0x7a2d3784, + 0x954f37fa, 0x4b610f8c, 0x76cf770b, 0x322d9ef1, 0x7e74d3aa, 0xa32f1f15, 0xe268836c, 0x721dc7a2, 0x941203d4, + 0x9249b1a7, 0xc911c7e8, 0xdc8fcbe0, 0x810b11e7, 0xb0ed0ad6, 0xee4ff431, 0x280c699a, 0xfc7df539, 0x56394b78, + 0xf1ef5b29, 0x0f45deaa, 0x30c75949, 0x216b06ae, 0x426ce3ac, 0xe9542ae8, 0xcba74604, 0x9385ced7, 0x520dc44b, + 0xf31c32a2, 0x221e568a, 0xa48ea969, 0x76643fe7, 0x68391686, 0xb85eb2e3, 0xabadc2ba, 0x9852cce2, 0x5c8b83c2, + 0x0c6415a7, 0x9f661caf, 0xa701a579, 0xcc77267f, 0x1b2b3882, 0x03b3a648, 0x137802fb, 0xbc739b4f, 0xa92dc5bc, + 0xdf6f0d6a, 0x00ca8f52, 0x8c24db7f, 0x2351b8b9, 0xba561294, 0xe30073c3, 0x5a6bdc93, 0xba2c84c3, 0xef656588, + 0xebb0767b, 0xe069adfb, 0xb321600e, 0xd011df11, 0x1de40daa, 0x9b54d518, 0x0ce5c5ba, 0x14b819da, 0x8802032b, + 0x20f1034d, 0x40c477fe, 0x6bae9009, 0x53ae4f94, 0x421de472, 0xc5146561, 0x938949d4, 0x0c131c5f, 0x9f679b26, + 0x8cf651b4, 0x918c540e, 0xe5391682, 0x4d9d5ff8, 0x8c9f712a, 0x5e0dbcf8, 0x085ef7dc, 0x38dbd1bc, 0x9d94b266, + 0x473ff1b9, 0xd1448cca, 0x2ca46cef, 0xe2ea99ce, 0xf6ee1acb, 0x5031a735, 0xc7523efe, 0xf4f8fe01, 0x7c69abf9, + 0x4e1a3a1e, 0x07bb571f, 0x4f71b5ff, 0x9be5180f, 0x7424507d, 0x9dfbf568, 0xaa9bced9, 0xb466eea4, 0x58b8870d, + 0x17aac693, 0xe9f9f568, 0x358033c5, 0x742f8c79, 0x3c3f1ccd, 0xb517f386, 0xa1a339cc, 0xcd382786, 0x327e3864, + 0xa1777bdb, 0x50f23ef4, 0xec2aca2b, 0x12ed67a9, 0xbe031b43, 0xdcfd2e67, 0x811afbaa, 0xce27c61a, 0x06d4b610, + 0x59b27218, 0x26321414, 0x8fd030ac, 0x1f2119f4, 0xbad97399, 0x9aacfbb0, 0x469cfa77, 0x264d17bb, 0x9b28ec7b, + 0xe5578746, 0x91ad8f45, 0xe0ba4730, 0xf3acdf9b, 0x27150481, 0x4b560bc5, 0x94923fbc, 0xf26025b9, 0xdd48f87f, + 0x6046bdf4, 0xb0ddc6e8, 0xdf07e1ac, 0xf9289833, 0x5b015046, 0x364bf9e1, 0x6db664ad, 0xcbe826dd, 0xd500e4a1, + 0xd09625ce, 0x1439cc0e, 0x7afb19ff, 0x13a477fb, 0x63f35634, 0x863a371e, 0x0e5f201e, 0x95d4dfaf, 0x2a000e46, + 0xd042fc81, 0x6328254f, 0x3e2b893e, 0xbc646531, 0xdb1080ea, 0xc3da95f6, 0xd6085fde, 0x9260d008, 0x79f88063, + 0xcbdfda63, 0xb244e058, 0x64b73ce2, 0x35ed90b2, 0x0acc3dda, 0xf097c788, 0xc392f338, 0x517a80a2, 0x5c67b1a3, + 0x7c427768, 0x9cef4830, 0x17d22b28, 0x9e7a672f, 0x4951b057, 0xf140a5ec, 0xce7dd305, 0x4f9e3006, 0xbd0ef59e, + 0x68e806e3, 0x8e3eab53, 0xeeb52e2f, 0xe0ccee36, 0xb94769e2, 0xfae0e9db, 0xbdd7c81c, 0x41c121fe, 0x787f4500, + 0xcbbc230a, 0x9384d829, 0xe49f48d2, 0x13ccad00, 0xac627d49, 0x395b3029, 0x0dcadd08, 0x6e925ae0, 0x1c43fb20, + 0xbdf67e2d, 0x6fa51571, 0xc024c0f4, 0x8aa04b0a, 0x8fbcb3d9, 0x51a018c4, 0x19265d5d, 0xf9b63d3d, 0xd8e46924, + 0x082b7855, 0x1e1dbc6f, 0x85d86bf5, 0xe0c57d3e, 0x16db0efc, 0xeb1a8f3b, 0xd9f1ad09, 0xeb72eed6, 0x636e631f, + 0xf01e7081, 0xa43c223b, 0xbd175a21, 0x0a3a5eb0, 0xa335c846, 0x5c4472b8, 0x30fd207f, 0x9ac1c721, 0x573048d6, + 0xaff0d68f, 0x023d7b0e, 0x3d382165, 0x6818c4ea, 0x4bd1abdc, 0xe202ca9c, 0xf22251e0, 0x26750431, 0x28cc8904, + 0x245a842c, 0xa82eb60e, 0x499db60d, 0x44577d95, 0x5a61bcde, 0x5c0bca98, 0x9f80d502, 0x7c2e1c4e, 0x453ea8b7, + 0x7fab530e, 0xf75e2c42, 0x77b6899b, 0x0eedaa1e, 0xcdf39e63, 0x014ef278, 0x67596ff4, 0x49952f45, 0x8df4fabf, + 0xfcf052c9, 0xeca56911, 0xbbbd628a, 0x3179516a, 0x2ba26c2f, 0xc3c3f5fe, 0x5a80eabc, 0x89403243, 0xfb8d9229, + 0xe6ac9fa4, 0x0abaeda8, 0x113b3ee0, 0x6951d4cd, 0x10fa86f5, 0xfa75b54f, 0xd9b88afe, 0x7ef24d2c, 0xba3cb59c, + 0xf30eb36d, 0xcb238fe0, 0xe8ce94bb, 0xd78e56dd, 0x4caeb191, 0x3f8f353b, 0xf3783845, 0xb6d42049, 0x0d797b33, + 0x9a436144, 0x8eb8f0ca, 0x488fc138, 0x597648f7, 0x99eccfe4, 0x0df263a1, 0x3cef1c89, 0x7748a4a9, 0x004e6ab5, + 0x76ea6b2d, 0x3b72ca20, 0xc8a1faac, 0x4749c1da, 0xebb96f62, 0x686c7026, 0x7fbe8b56, 0x8d617c03, 0x7d87be57, + 0xf28c30f7, 0x74205c5b, 0x090dcf39, 0x2ee5da0d, 0x0a0de173, 0x246ab12f, 0x8421287c, 0x23046c1c, 0xc2e32b26, + 0xe4f6b248, 0x39700afb, 0x48eee3f9, 0xb0818910, 0x20ce0487, 0xf281b6fa, 0x5e088ffa, 0x5060c292, 0xbe9edb65, + 0xacb4f589, 0xe50bb18b, 0x46400120, 0xef055918, 0x51ad5b1b, 0x87d18d31, 0xb7a0ef22, 0x9c5c9bbf, 0x980ce3a0, + 0x562645ec, 0x6767c4b4, 0x90dc77e5, 0x6444fe9a, 0xc06c2d23, 0xb847c914, 0x3c62bf24, 0x8bc31764, 0xf889f8f6, + 0xe51b53ca, 0x9df448cb, 0xf7ffdc23, 0xe8c6a9fe, 0xf3371145, 0xdb696896, 0x9ea20a2f, 0x1d0254ba, 0xc9d02bde, + 0x774a1f1b, 0x17518079, 0x7df23f5e, 0xe3f07f18, 0x81b078a0, 0x3f9ab5c0, 0xd41c8440, 0xfc457b3a, 0x00423fe8, + 0x8143780f, 0x529ddd80, 0x8de9f0c1, 0xdfa07773, 0xfe9e5b23, 0xfb6a7adb, 0x28ff396b, 0xb95b7702, 0x985e8dbf, + 0x82b0fcf7, 0x091b2325, 0xca952543, 0x5343835f, 0xa964a69f, 0x9cd9e811, 0xbb281cc9, 0xc4fab07e, 0x8dfe6b11, + 0x71eda983, 0x419d9374, 0x048040c5, 0xa5e7f28f, 0xbbeb2f18, 0x68c5c8ef, 0x14d9ffc4, 0xba601b14, 0x6b2e4ea3, + 0x71f0f44d, 0xa0aab3da, 0xcbd6a40e, 0x1e692bdf, 0xc71f2dc5, 0x419ba1be, 0x0704426d, 0xf4265315, 0x49391402, + 0x3856dbfa, 0xb4a7ba67, 0x9e3703a8, 0x54abd9ff, 0xbc9b6fec, 0x17909cef, 0xdbc2592d, 0x1539a6b4, 0xa964ab25, + 0x661c635f, 0xe5eec6d2, 0x8698f580, 0xce236733, 0x2071f049, 0xc62a818f, 0x9a8eabab, 0xf6529ca0, 0xadceb82c, + 0x59420844, 0x6b389efb, 0x0fdd3327, 0x85fdfdee, 0x9fe28651, 0xf59f40ad, 0xe4e7cf3d, 0x1efd2c9a, 0xb690a004, + 0x4ae3a07c, 0x10a68d66, 0xb2e6644e, 0x5b0a2b44, 0x938d91d2, 0xb764442d, 0xa030fcf5, 0xb1a28b58, 0x262dfac5, + 0x6262cf80, 0x75670e4e, 0x06236a5d, 0x4701a704, 0xed22fc8d, 0x79fdcff3, 0x2377d4a7, 0x41d4a3cc, 0xda74ab77, + 0x243937d8, 0x42a27545, 0x36f9470d, 0xc8a5ce0b, 0x5e982650, 0x248d5190, 0xa51f03f1, 0xbed705af, 0x2bc22c04, + 0xa6d42c7f, 0xe2ff795f, 0x1d44c507, 0xd27a7809, 0xe9a159e5, 0xbdd3341b, 0x38b18254, 0xd33ea3e8, 0x804f6860, + 0xefd97f48, 0x5a2ede55, 0xdad3f1a2, 0x200c94e9, 0xacc36587, 0x65ee8766, 0x19aca0ca, 0x819bc8c2, 0x1f07cd65, + 0x7fd386de, 0x4e652eac, 0xde5ca346, 0xee4e01ab, 0xa477a08d, 0xf0b12155, 0xcb1a996a, 0xd9d727e3, 0xef66b93f, + 0xa912d752, 0x9e2f8595, 0x2afa69bc, 0xc637467b, 0xbeb03ad1, 0xd271ac75, 0xebe4c1a7, 0xa91c65c7, 0x782de8eb, + 0xa15ca8f1, 0xcbecf150, 0xe4470b69, 0x6f852ad0, 0x88703483, 0x302f8f6f, 0xf09b207f, 0x1f921c21, 0x8c2501a3, + 0x0bff6023, 0x9dbb921d, 0x85f4efb9, 0x36c4e097, 0x99428e5e, 0xf7434477, 0x43b2450b, 0x75e1da65, 0x9ae29dd3, + 0xad46e9e1, 0xa0938af0, 0x63762759, 0x69499158, 0x09a0cbb2, 0x14f1329d, 0x3a5c1b01, 0x138dfd2a, 0x2aaeee64, + 0xe10dfcb4, 0x9101188c, 0x0f6232e4, 0x8748501f, 0x9c60c1c6, 0xfbf0afb7, 0xba349829, 0x3270fd3d, 0x239f4ae3, + 0x93d3094e, 0xbf1f1276, 0x29e81b0e, 0x86d442e8, 0xa24cb4f4, 0x14eef83c, 0x69667d9b, 0x9b0b7041, 0x1c68abfe, + 0x6e37f808, 0x54511296, 0x406ec70f, 0xb4bc35cf, 0x502e046a, 0x68a8d40d, 0x7e7d60b6, 0x360cee30, 0xaf6664b6, + 0x9ac54d85, 0x695ba609, 0x6f5c3dc5, 0x1280a576, 0x70b90bdc, 0x53652a7c, 0x8dcbd702, 0x3e1e69e0, 0xd1992997, + 0x1d5e80ca, 0x6597af3d, 0xc8d8d265, 0x405ea254, 0x951ae44e, 0xadc45884, 0x92560175, 0x2956a55b, 0x88aade87, + 0x5c7a794b, 0x633357cf, 0x3141891c, 0xdcd955c1, 0x3dfc910e, 0x5f5e1108, 0x11633500, 0x2a1535a6, 0xe7466022, + 0x4ff1db24, 0xea9ffb12, 0x942988a5, 0xfcb486ad, 0x581acdb9, 0x62ce1179, 0xe404a158, 0xe19879d1, 0x0c31a38b, + 0x6df4f7d2, 0x62f07554, 0x5ee182ac, 0xdbbdbe9c, 0x0757419a, 0xe548d573, 0x55188363, 0x0071d046, 0x0931aff4, + 0x06190425, 0xbecb6958, 0x612b85be, 0x17f9ef30, 0x748ed110, 0x54a76748, 0xdc0c1636, 0x6ca51ea1, 0x1bfa8dcd, + 0x789f58ee, 0x2a6036d9, 0x24229608, 0x6de00081, 0x8f146142, 0x497d5a69, 0xf4311963, 0x6f23c5ab, 0x1db1cb4e, + 0x03c00ac8, 0x13342f36, 0x43f996ff, 0xac7dc023, 0x11399eca, 0x095ee11d, 0x5414d485, 0x65a28477, 0x417879a7, + 0x792b720b, 0x7f717629, 0xd3ba4dcd, 0x87c74e91, 0x2c5c7ea2, 0x0379829c, 0xe8aeee4b, 0xd043bc2b, 0x1a7420f2, + 0x30fcb712, 0x5f889981, 0x85f20d75, 0xf1d42e78, 0xa844fb44, 0x8a0a28c3, 0x1c0b932a, 0x2a918903, 0x1c5f5623, + 0x486ece59, 0x422ecda7, 0x1c47c829, 0x1504f7c9, 0xe4d2b1cf, 0xdc8cf333, 0xf48763d4, 0x37b80a9f, 0xd3d58afb, + 0xff560c0b, 0x221badac, 0xd858ed07, 0xbfa55565, 0x8f608d7e, 0x740ca37d, 0x2b86ff2c, 0xdf1c2b70, 0xc1aa8d32, + 0x77d378fc, 0xcfef2f85, 0xc22daf31, 0x6060b7ea, 0x53625d9b, 0x96554164, 0x2374c66e, 0x7573a10d, 0x2534a88f, + 0x9fdc9c74, 0x1fb1da84, 0x9b7cf762, 0xebb39eaa, 0xa963c6e6, 0x853eb20e, 0x94c3a3ab, 0xc281146e, 0xf7ff5923, + 0x05ca7c80, 0x110101fe, 0x5445ac2f, 0x520ad4f0, 0xe4b02d56, 0x59a3bee9, 0x44ea5369, 0x4f37d866, 0x61b219fe, + 0xe460c2cd, 0x735d4449, 0x453ece2a, 0x942c7707, 0x9c8166c0, 0x80d0a1ad, 0x7e9d4bf3, 0x41e5de89, 0xa57dd725, + 0x146ccc69, 0x52b2d96c, 0x3d5fb6d9, 0x0f73ac1b, 0x3a893546, 0xdee2ad35, 0x481d205b, 0x5e3fc8e8, 0x50fa88d0, + 0xdecc1c3f, 0x4ebae745, 0x7b5455c2, 0xb589f3a1, 0x479eb147, 0x71b0d732, 0xcf106f73, 0xe3149ce6, 0xdd5c313f, + 0xecf75705, 0xdd78fed3, 0x44ea631a, 0x2898b70b, 0x689508b8, 0xda136d70, 0x9eb3b51b, 0xfc747224, 0x51f7e9b8, + 0x464fc694, 0x7c5bfe13, 0xeb321c06, 0x6fd44848, 0x624413d2, 0x850f4c98, 0x25bbf018, 0xd1a8f80d, 0x6cdfe1c2, + 0x6d0407de, 0xb0c114b0, 0x9aef9816, 0x51862756, 0xfe7ece5d, 0xa8022bd7, 0xd4fe9c6b, 0xeeea50e1, 0x22fc63d5, + 0x6b28ccb4, 0xb560d2df, 0xf434f276, 0x28162ec7, 0x4dbf5d6a, 0x43109cb7, 0x1da1d14a, 0x18b143d9, 0xe7015103, + 0x9d68300a, 0x168e6f34, 0x3c888c33, 0x1ebd78c5, 0xf0eb6b86, 0xb3a8735c, 0xb5d844cb, 0x47f0f3aa, 0xa4ea8953, + 0x4301a552, 0x078c8dff, 0xe094682d, 0xcb1bd67d, 0xcd3e0798, 0x5eeb73ad, 0x8f773c57, 0x5353d86e, 0xb07a8b7f, + 0x0b49f608, 0x068a53b7, 0x3e9fa12e, 0xd57fb817, 0xa3b5844e, 0x780069a4, 0x478e4a63, 0xbfbce78c, 0x09e6b7db, + 0xa4a7b216, 0x3985aaa8, 0x6b96322d, 0x6c6b394f, 0xd116c627, 0x84eaa6c9, 0xb14e6e14, 0xb21854cd, 0x71d46d7d, + 0x41b77efa, 0x19fa59db, 0x4245b2b7, 0x5e661b49, 0x245152a1, 0x5886dfa4, 0xd8c82791, 0x59898493, 0xc4ad7f9c, + 0x9716d381, 0xeb76e049, 0x8b0a716a, 0x2f3da9ab, 0xcd96981c, 0x5b98ed83, 0xf4b38502, 0xdd5fc1ed, 0xc3b2f006, + 0x89da70a2, 0x485d771b, 0x655f2fcb, 0x82774baf, 0x26490038, 0x825d8e9d, 0x832b3e57, 0xc76a5e70, 0xc0e904bc, + 0x7d1cb1f0, 0xc80681a3, 0xfecd2eac, 0x87858ffa, 0x5d04d9d0, 0x6f5f485c, 0x5b219419, 0x8e4e218d, 0x850ba3c7, + 0x9846a24b, 0xf382efab, 0x90f70fcf, 0x61f31c4b, 0xd4f41a48, 0x8c443fdd, 0xa98ec892, 0x34346127, 0xeea27cd1, + 0x269861bf, 0xff4f9152, 0xec4881c7, 0x32ed867a, 0x4e5102c3, 0x1420c128, 0xb522920f, 0x8ccc9855, 0x54ba17e1, + 0x927d7583, 0x8d1e59ef, 0x9a5d1e6d, 0x3480d2f3, 0xbd5f8738, 0x7ec202c5, 0x5395ae8d, 0xda02ec78, 0x56424543, + 0x5639dd75, 0xf5b25da1, 0x74436e74, 0xdcece392, 0xe89ed819, 0x53957e67, 0xc0618e81, 0xe2aafa90, 0xd710d9ab, + 0xd9b2ae86, 0x3950b713, 0xf037ff8c, 0xcd6610a0, 0x05746373, 0x630b061d, 0x16321905, 0x5391affd, 0x8d195d24, + 0xa048e2f2, 0xf3f49866, 0xba574522, 0x2b00cff9, 0x493cf5db, 0xc4b7daec, 0x188735f9, 0x28c536cd, 0x961508bf, + 0x6d21783c, 0xb37b6d5f, 0x3f9781f6, 0xc6da0cc6, 0xf6ee36bc, 0xa62cf124, 0x2b03c5c6, 0xa486dca9, 0xfb912599, + 0xa4c5d533, 0x3089d6ad, 0x894f64e0, 0xdf00c02d, 0xd3e2e394, 0x60d97c40, 0xd65e4191, 0x9717a997, 0xf109ad49, + 0x77a28f4c, 0xc74b27bf, 0xf42598fa, 0x34568ba6, 0x473f4fbb, 0x64cf0cbc, 0xbe417cd7, 0x76f6b46e, 0xce471b90, + 0xa127ea32, 0x432e7e96, 0xb09707c2, 0x0eda1624, 0x840fa402, 0x09514726, 0xdf0bb9ec, 0x5ccc09c8, 0x20b362cc, + 0x37f27f8d, 0x8a3a99d1, 0x5e503226, 0xa7be5c5b, 0xd68f0731, 0xb9b96617, 0x849a2446, 0x4de8704b, 0x6881f9d6, + 0x299d904c, 0xac419537, 0xe1edad1c, 0xaec039af, 0x1c7b6389, 0x5d696169, 0x3683211b, 0x53e54aac, 0x046fcde1, + 0xd58879e5, 0x9ab8ae5a, 0x0f3e578b, 0x2dcd51c5, 0x2c0db0fc, 0x50cca556, 0x221f9465, 0x0ca61d66, 0x695ce4a5, + 0x16b0c097, 0x9af0782e, 0x7eb1a646, 0x97ffc698, 0x908e5ad8, 0xd551353e, 0x586749e8, 0x2314f1b2, 0xbfb09a50, + 0xc6667e87, 0x56f05f64, 0x7ba79978, 0x744991a1, 0xe77e3747, 0xbfee8cab, 0x860f1fd7, 0xd815a810, 0x142aac0b, + 0xede98284, 0xb3348906, 0xc9b5b866, 0xea0bf75b, 0x9312c0af, 0xf580931d, 0x092f5ed5, 0xa0061396, 0xd13dfbf3, + 0x3b653edc, 0xd79d8194, 0xe992316f, 0xcff15325, 0x5c585832, 0xf02f0039, 0x57f6b343, 0x0253197b, 0x109d78ac, + 0xde4f6917, 0x72a011a8, 0xbf89d123, 0xca5f7c96, 0x0e76a9fe, 0xde653ba4, 0x1c2190b0, 0xb3779b41, 0x333f7dbf, + 0x6dba20fc, 0x12801f18, 0x597fbeb0, 0xd245c596, 0x5aae5ea8, 0x30cc24d2, 0x0f500aee, 0xc656a41f, 0xdf007dd0, + 0x852e8dc4, 0x09a80ad8, 0xeee8c490, 0x0bcf4af3, 0x31b596fa, 0x5ada399d, 0x7535e571, 0x230a0cbc, 0xfee2ab39, + 0x04d0dacd, 0xd6f34fd4, 0x8e926f32, 0xab5a0632, 0x9f066c7f, 0x93c4a347, 0x47e9257a, 0x877658d9, 0x508d06f3, + 0x633a1300, 0x29ffd40e, 0x5b4a93d7, 0x3c6fe732, 0x903f4134, 0xff87d152, 0xd432e68f, 0x44f614f5, 0x4866c6dd, + 0xa9e0f22e, 0x5e64e029, 0x23a30acb, 0x3057ee0c, 0x4e9ee342, 0x5c194447, 0x9ac9af5c, 0x5be01842, 0xf76f46a0, + 0x94327eac, 0xb60e453c, 0xa79c8ed8, 0xa889bc43, 0x69149790, 0xd7e964cf, 0x14c20527, 0x21904ef1, 0xe8de6729, + 0x42ac2a5c, 0xc3e6978e, 0x4abefdd0, 0x60d0fe5a, 0x38bbd878, 0xd3e3d171, 0x289ccaa3, 0x97e711d0, 0xe7d6ca68, + 0x0cb002ab, 0xb949edde, 0x5c627359, 0x7ddc3e02, 0x0bee7bd6, 0x4b58d3cc, 0x986d666f, 0x11c0aec2, 0xa05371f5, + 0x55b1d367, 0x27b7075a, 0x8d701fc7, 0xcf2d7baf, 0xf460ea12, 0x76c0c43d, 0x350deec8, 0x8b6eb857, 0x6dd9405e, + 0xf99eac72, 0x509e38b0, 0x10e53c38, 0x2a82802c, 0x96505519, 0x92736e54, 0x39bf3ba8, 0x9235a8e0, 0xb7b92710, + 0xe2de4f8b, 0x593ac791, 0xb126dd76, 0x37e1f92c, 0x21121498, 0xbf348ba6, 0xeaa96a18, 0xbe9d434a, 0xf4df0e2d, + 0x1d8930f9, 0xe51a7986, 0x8a141b97, 0x03189bf6, 0x02208678, 0x05a5e5ca, 0x7d3ab4fd, 0x3a5a8b47, 0x3c8d6c08, + 0x2bd456ba, 0xf64bc074, 0x15f7cb4d, 0xefb33d3b, 0x6008b805, 0xea7ab6bb, 0x9212062a, 0x529ae079, 0x880fbfad, + 0xeca44333, 0x82437da0, 0x4373720e, 0xe7e89ff5, 0x7d2e42df, 0x31257aa0, 0xa462c506, 0x19c92ace, 0xe7238788, + 0x2d0f0bd8, 0x9a116583, 0x399f0ba0, 0xce51bf16, 0xcc11de2e, 0x5c2b2a4c, 0x1e841659, 0x633439b4, 0xe4466078, + 0xdf027196, 0xf54acf99, 0x37782a9c, 0x32a45118, 0xc63cda57, 0xcc83755e, 0x484fe5f0, 0x201cb9f2, 0x8d836c5d, + 0xe686a234, 0x167c739c, 0x5b38189b, 0x96910531, 0x904452be, 0x1d1f14b2, 0x2091d720, 0x89b7d2e1, 0xa10c9a55, + 0xb120e895, 0xcc0af78b, 0x91cc35bc, 0x26ddbcd6, 0x07c32c11, 0x4d8dd7f0, 0x5caf1cc2, 0xb8d22784, 0xf175c95a, + 0x98b0f0be, 0x2590e468, 0x9899b61b, 0x236d6e32, 0x4113f431, 0xf4832043, 0x484548a4, 0xcc825df8, 0xfdebbab8, + 0x09968f78, 0x29199996, 0xd3e29a35, 0xf00b8cc9, 0x99f7c710, 0x46c11d35, 0x803bbdaa, 0x78f4bf96, 0x96076a41, + 0xb6128427, 0x2ea64ec1, 0x8ab902d1, 0x496b973a, 0x56f994eb, 0x7804b670, 0x4fb30eb4, 0xeda6073b, 0x99032aae, + 0x7c79242c, 0x8516a05a, 0xc4ca83d1, 0x00f49598, 0xbb72d4f1, 0x9cb24fcf, 0xd175a587, 0x78266cc8, 0x3115c9e6, + 0xd21240c7, 0xaf1b4d93, 0xda9682b6, 0xae87ffaf, 0x17fd1423, 0xed1c6067, 0x51194e17, 0xed6d9982, 0x80ace4ce, + 0xe1e0e787, 0x1fad8614, 0x99f08d69, 0x938766d3, 0x06e83bc3, 0x6fa0c984, 0x2b2c70a9, 0x23566488, 0x400cfdd4, + 0x4127f003, 0xbf28af22, 0x8484ccde, 0x62baead6, 0x9da69866, 0x8d850983, 0x2da2a9e0, 0x6117bcae, 0x9f62bc98, + 0xf050cf90, 0x97f7a16a, 0x4a6e7bad, 0x88ffe3c0, 0x993f3cec, 0x42d952d8, 0x3e9c574c, 0x698130b8, 0x3afc5c36, + 0x1fa291f6, 0xf8031531, 0x39af79fc, 0x285c01fd, 0xb2b958a2, 0x96cc328f, 0xbc6ce596, 0xc77efe21, 0x07113f81, + 0x649e691e, 0x983f5d2a, 0xaa572c94, 0xe77cf87c, 0xd67fb65c, 0xae99c804, 0x32f054ee, 0xf56c780f, 0x7efd83c8, + 0x96b8300a, 0xb08690b6, 0xcd6223b8, 0x83ee0f87, 0xf3dd1432, 0x06727280, 0x138e0711, 0x8ae09322, 0xe2238b67, + 0x8ee26c1a, 0x4b66a110, 0x3d176dc7, 0xe72ec769, 0xa821c2bf, 0x615a9190, 0xc6b47999, 0xf523a486, 0x0fac8f00, + 0xcf80dd90, 0x83ff6fb3, 0xa4af3bda, 0x00221a2d, 0x607cbaf9, 0x4e641368, 0x9eba5a17, 0xcb61502a, 0x227fa562, + 0x9f5f8469, 0xa698b3c2, 0xe5734c31, 0xed672288, 0x148e65b4, 0xba4b8c22, 0x4253e153, 0xcaa0720c, 0xc28c214e, + 0x25e3d558, 0xb4eac407, 0x155c188c, 0xa1bf2814, 0xf5a2fd3e, 0x4bbe0df5, 0xd484fb43, 0x730653dc, 0x918f83cd, + 0xb8e79c88, 0xb7347c57, 0xcee26086, 0xcfc517b1, 0x92e560c2, 0xd7a8a23b, 0xb2b9fe80, 0x8b288855, 0xc62751fe, + 0x7584bc96, 0xe5e6aa85, 0x29c7a08d, 0x3facbd8f, 0x86f9ef6f, 0xf262d3b4, 0x5f50595e, 0x2ee1406e, 0xa3a6a5ff, + 0x09131c41, 0xdb46f7bb, 0x68b857ed, 0xdacaf698, 0xdd04f8c5, 0x0cb41629, 0x83f90b2a, 0xedc03a00, 0x76538ea6, + 0xe9b48b01, 0x148af86b, 0x257c676e, 0x4636d5a7, 0x3d9dae64, 0x57f1ecb5, 0xeca776a7, 0xd52d3224, 0x7115d92b, + 0xeb4ddcdb, 0x2e396f1c, 0xfc770c6b, 0x7cfec636, 0x5f6d73b4, 0x80c34879, 0x6e19170b, 0xb3ad5ae5, 0xd810e43c, + 0x0e62c543, 0xfc042aba, 0xe0ea4b30, 0xa583d632, 0xa0c99ee1, 0xf896d5aa, 0xc021d534, 0x1701a996, 0x37553569, + 0xc906dd30, 0xafa85148, 0x2c3d014e, 0x50a4c4f8, 0x17a524dd, 0xd180e143, 0xbb1e4a24, 0x0b3f64bd, 0x32a9dcd8, + 0xe1ce380f, 0xf8c2fd0d, 0x6a04b5df, 0xeeddfa20, 0x1d78ec5f, 0x8502f817, 0xd718c94a, 0x3b36b71a, 0xd902b5c7, + 0x240b09a3, 0xf0f3c469, 0x7494d103, 0x644b00cd, 0xbb315d50, 0x2b0fbd65, 0x6290bf16, 0xccae9586, 0x8ee4ff3e, + 0x14d904fb, 0xf7c56811, 0x87c0e1ec, 0xf35796c3, 0x32537a15, 0x2e339754, 0x1367125a, 0xea3f4209, 0xa7c8c4e9, + 0xef9b85e6, 0x0d4d7485, 0x3a42522b, 0x5f25cb07, 0x2307312c, 0x49754cb2, 0xfcc0e068, 0x3d08291e, 0x700a5600, + 0x1876985b, 0x2ef81199, 0x5f8e328b, 0x9ce6b72c, 0xed3d9320, 0xcb451cc9, 0x48ddb64b, 0x81e91315, 0x9a49a6f9, + 0x0b5d7fff, 0x13f545f3, 0x74ff3d1f, 0xfac35fbd, 0xdbc2e7c9, 0xe23aee4e, 0xf09fd8f0, 0x8d946f51, 0x2b3ea394, + 0x4b1cd846, 0xfc91e967, 0x30656b11, 0xd822dc11, 0x4bad7ba3, 0xbec4968e, 0xf7be0c26, 0x97e7df39, 0x15c3e0dc, + 0x60c61726, 0xa362c65a, 0xf34309af, 0x1cdaa808, 0xf3294051, 0x4efd7c71, 0x110e5883, 0xee8a26c6, 0x39d76b53, + 0xb94fa7e4, 0x2dadb18a, 0x1fdae779, 0x85f928c2, 0x33ed2cee, 0x2ca95b73, 0x5b05772d, 0x5532f9f5, 0xb6a082b1, + 0x05070260, 0xd0085f54, 0x25e6fcf4, 0x38c76f17, 0x1063f70b, 0x953d7621, 0xcf9b68bd, 0x834e4197, 0x82ab0c36, + 0x64f41231, 0xb2b7a73d, 0x4bb0e69c, 0x8bc32e03, 0x6a79f546, 0x1e0d0788, 0xd80261d5, 0xf0ffbfa1, 0xfda7c287, + 0x57ad017a, 0x4c91e661, 0x02f13e99, 0x8806a09b, 0x010b3fe6, 0xc5c0b853, 0x8887cf51, 0xd4ffe538, 0x699b76a7, + 0x2c464eec, 0x3a7124ef, 0x13d99ed5, 0x9a431142, 0xec9fc558, 0x3d27d291, 0x0fc3de7b, 0xaf89e8e5, 0x297ec1a9, + 0x96773c2c, 0xf3f9cba5, 0xde65730f, 0x72768ab4, 0xcc1cb4bf, 0x233ee030, 0x60ea5584, 0x5c36be1c, 0x40da06ef, + 0xbbd2f068, 0xc0e18650, 0x31c038bc, 0xf1722e6f, 0x9bf1ac71, 0x8ec0821c, 0xdd41f937, 0x53a2c894, 0xb0ac3c0c, + 0xdd7e78c9, 0x0bef0b5b, 0xc3313c58, 0xf8917b06, 0xd990990f, 0xcb48feac, 0xe1e356bd, 0xd8607d9a, 0x5e9c9efc, + 0xd9b33ffe, 0xdecf697c, 0xf324ff94, 0x8a3bbd40, 0xa7150499, 0x57e056b2, 0x03b6d582, 0x8282bc56, 0x72c19c0f, + 0x079dbfdc, 0x0c09cb7c, 0x9b2a114e, 0xaaca672a, 0x2a9cc2fb, 0x9fdfc281, 0x9b8fce76, 0x1b8e110c, 0x3b94879f, + 0xb83a4056, 0x22962677, 0xae9ec0d6, 0x4df077e5, 0xbc599ee6, 0x5dc88e83, 0xd984ccd6, 0xec3e1310, 0x7168ca3a, + 0xcf9445c9, 0x79467fa0, 0x3c4d62e7, 0xd7ea023a, 0x400eec0f, 0x02daf158, 0x5a724a83, 0x8cb916c6, 0x8a136139, + 0xb7d2f967, 0x73509d1f, 0x2780fa90, 0x25cfd668, 0x343f0ec8, 0x864388db, 0x43b86908, 0xf08ca078, 0x3096e9b9, + 0x4e3773de, 0x1826c955, 0x16ee68b3, 0x4d4318b1, 0xc41b20f5, 0x86c14ecb, 0x528089ec, 0xc58c9c87, 0x8a69b242, + 0x9cb4a5dc, 0x4298460e, 0x18d2e8ff, 0x8f481914, 0xda1fe417, 0xe43ca351, 0x50662587, 0x1fcd88fe, 0x5c799a77, + 0x3036bc18, 0x9330cce7, 0x3f2039a0, 0xccb8e19c, 0xb6e9a02b, 0xb2de79fd, 0xcb74dfda, 0xb14dcf43, 0x481dc65b, + 0xdf77e447, 0x141bda66, 0xe79807b4, 0x0d4b1e9b, 0x8e0d576b, 0xaa6c4ff1, 0xe078896d, 0x1ab36be9, 0x077a89b6, + 0x5c7185de, 0xd413b7d8, 0xbfbf4c6a, 0xd9548d62, 0x4440de1a, 0x1a6b37d7, 0x9875c8c9, 0xed5637c6, 0xba9616a3, + 0x370a530d, 0x8d3e76a9, 0x6b185d67, 0xe0efa55b, 0xdd51e612, 0x077e881f, 0xf7bd86f0, 0x8ce8b031, 0x4ebaf36b, + 0x8956f71c, 0xc1a493c3, 0x05e3c77a, 0x36bdbeb9, 0x99ae3f3f, 0x4fbcb8c1, 0xdc88173e, 0x85956904, 0xcad41459, + 0x91f4d53c, 0xbf98f857, 0x953def21, 0xa6b4a50d, 0x7c540ac9, 0xc6e4703a, 0x56e718bd, 0x69757261, 0xfd313a1d, + 0xdd729a42, 0xa994925c, 0x2ef578ad, 0x7afc0558, 0xb037eefd, 0x667dad80, 0x28449473, 0x8effa2d4, 0x257c362e, + 0x8546505f, 0xedb97347, 0x8db4c497, 0x2d05d17c, 0xf51525db, 0x970f4bc3, 0x97841982, 0xe3365c20, 0x9aea37fb, + 0xdc12c912, 0x58777647, 0xf63904a2, 0x00bbe497, 0xe728f025, 0xdb9dfdc1, 0x348d2cdd, 0x978b61d1, 0xada08865, + 0x71fc7c6b, 0xf020689a, 0xca11b2c1, 0x8a81c182, 0x0376ad52, 0x8a7ef011, 0x59003882, 0xe1432155, 0x61bace69, + 0x92d6f94c, 0x9dc400a3, 0x29f4df3e, 0x6646c513, 0x34197bc2, 0x8d9608eb, 0xe0bca708, 0x252e9627, 0x4e831712, + 0x37ec99f2, 0xac274efa, 0x98a00433, 0x21bebed1, 0x3c0e5b39, 0x41034062, 0xf449c2c6, 0xc6c1c51e, 0xd583be2f, + 0x96e2f91b, 0xc02b11c6, 0xd9a9632e, 0x47a88259, 0x41421132, 0x8a6b05e4, 0xf073cb23, 0xf0186762, 0x41421dcd, + 0x65c2b441, 0x753c4b46, 0x119cdb9f, 0x1d480c93, 0x1052dd82, 0xbec8d20b, 0xa027c711, 0xaddb9857, 0x75f7f409, + 0x6edfd42b, 0x44485a4d, 0x50af354a, 0x029eae27, 0x531c534b, 0x19152c98, 0xff2d72be, 0x2c9ccd81, 0x0d5d3a1e, + 0x63dee973, 0xb8802c89, 0x6047bdab, 0x5f73298f, 0xad9af145, 0xbbda6710, 0x6d8bcd10, 0xa1fb8dce, 0x5199de4b, + 0xda83e535, 0x50c803a7, 0xb18c8b69, 0x17f98e70, 0x3ad3c0ae, 0x3e647e7e, 0xc7b0f2db, 0xe1900173, 0x6cc7fb70, + 0x371b0e5b, 0xcb0eb33d, 0xa0e49caa, 0xda66e16d, 0x3619c557, 0x5c78a9f6, 0x2bf6cc91, 0xdb0b0077, 0x831707ac, + 0x104273c7, 0xd052c9e9, 0xbcf12760, 0x6bda9a4e, 0x286e55ba, 0xedd00380, 0x0cd1699e, 0x60e3a065, 0xef175e1e, + 0x8cf99fb1, 0x6146827c, 0x3a695300, 0xef62525e, 0x90adf355, 0x66abee3d, 0xe5038a12, 0xf5e4b0aa, 0xbf86e95c, + 0x598b1a26, 0xc7f46c35, 0x1adfc16c, 0x37b19e88, 0x8779fb73, 0x297fcd13, 0xbcbd29ac, 0x0834f979, 0x095d84c8, + 0x5ceb1d6b, 0xb69b43f4, 0xc84c62f4, 0x27d73888, 0xbc733351, 0xc35c59ee, 0x34804829, 0xc299d42e, 0xee940c7b, + 0x75fc6139, 0x9ac2b021, 0xbb7c881d, 0x52bddf2a, 0x476ed373, 0xe5e04d27, 0x4f223ab3, 0x009811d1, 0xd2f96f2b, + 0x51ec2a08, 0x7bab7132, 0x3a7a3aad, 0xcfebfe89, 0x99558624, 0x5b30f5c6, 0xe523504c, 0x8b9df7a3, 0x1650f2a3, + 0x02f76412, 0x6c6b4d52, 0x58bf4c67, 0xd6d2018e, 0x82bb0c1f, 0x7d1558a5, 0x23492609, 0xc1087510, 0x39d47082, + 0x3e2efe40, 0x5c6885a6, 0xd7e40a78, 0xb19506fb, 0x9d10306e, 0x591c4011, 0x35204fed, 0x035393f6, 0xd9ab9fad, + 0xdb8d82f6, 0x56ede73e, 0x07533463, 0xa85a0b77, 0xd280a98f, 0x5215c2e8, 0x14f7cb75, 0x96e5f88e, 0xf95f1ce6, + 0x568f3bb5, 0x94a9c554, 0x4f70260d, 0xed95f02e, 0x91bd5541, 0x452b7945, 0xab334e29, 0x0b5bd59f, 0x33c3125b, + 0x131ad98c, 0xb3037a18, 0x86290196, 0xb2a2dbe1, 0xafb1035f, 0x6b177c2e, 0xbad59e45, 0x10d8ffd6, 0x5973504d, + 0xa0437861, 0x66bbad2a, 0x99afdd77, 0xb867a322, 0xd24cc47b, 0x36119445, 0x94477e7f, 0xd50ae912, 0x3f26891f, + 0x8476e5ab, 0x38c6952f, 0x911b70da, 0x508d474a, 0x9a7d8dc4, 0xd3ff8477, 0xc241c3e9, 0x7ca24f1c, 0x58cd806d, + 0xda9d0e83, 0x032247d9, 0x83ebfc77, 0xa489b876, 0x605a64a3, 0xc5e972ff, 0xdd291d5c, 0xb6f27e25, 0xe4995ec1, + 0x9d9bbabe, 0xb24bcd93, 0xac428317, 0x7dad4f24, 0x90ebf917, 0x16409e30, 0x069300b4, 0x9483e81c, 0x25438818, + 0x7f794c83, 0x8dcfb2d6, 0xce083acb, 0xb470491a, 0x42187b39, 0x1a734da6, 0x6f6d2f48, 0xc7f75b0f, 0xb87b6761, + 0x21094e26, 0x9fc56501, 0xd4e9e9b6, 0x1740d613, 0xa4aea0aa, 0x005f43c3, 0xef599ba7, 0x4b9c340f, 0x1fce4647, + 0x2cca8b5d, 0xb99f3023, 0x33e03d3d, 0x5fa1bcd7, 0x003f76c2, 0x0b923f34, 0x928719c5, 0x226c5cbc, 0x42734e02, + 0x74b2aaa9, 0x7ed655fe, 0x72ac3ab4, 0xb133778d, 0xc1fb5598, 0x8a5260f4, 0x66a101e6, 0x7d223c57, 0xdd81ff98, + 0xdc71b0ee, 0xdcbd4cf0, 0xe069a98c, 0x194d252d, 0x1be100d7, 0x633a9d9f, 0x1718405f, 0x9fb70f30, 0x6fd4d2df, + 0xbf8e8ead, 0x2bab3b18, 0x71969901, 0xb7f6d627, 0xe3a7e0d0, 0x62cebc09, 0x38cd81e6, 0x183cc082, 0xf03b594b, + 0xc85c6bb6, 0x0cba2e9a, 0x63b918bf, 0x30864f80, 0xa2d9df1f, 0xa09d2740, 0x3b08208f, 0xf65258b3, 0x2e75bf15, + 0x9f705258, 0x34b46150, 0x90bae55a, 0x2bc9ab65, 0x81951923, 0xfd98d4dc, 0xbbd9c9fd, 0xaba815a3, 0xb2f4a602, + 0x88a56634, 0x075fa4ec, 0x2196b7e6, 0x362ad939, 0xc07dbf02, 0x2fc9061f, 0xbc72da71, 0x3d0f5cef, 0x3877c722, + 0x9379754a, 0x7583fcb7, 0x9e1ecda4, 0x9459673c, 0x31897e45, 0xec55b281, 0x10c8d069, 0x923d4c20, 0xd6665b83, + 0xa6290392, 0xeca130dc, 0xd4d32124, 0x527e73aa, 0xe0ec625e, 0xce4eb27a, 0xdff0ae98, 0xbf800c50, 0x59656253, + 0xaed0187b, 0xa367aecf, 0xe6114c25, 0x2f40922b, 0x8d98082d, 0xa54d1fa9, 0x038c261d, 0xfccb0c4a, 0x3f24a6f1, + 0xb3329c64, 0x0c6cb870, 0xe99d9fae, 0xd2e443e9, 0x5ce99dda, 0xb85de65e, 0x2c0b5f6a, 0x2ff3b42d, 0x1a38e582, + 0xfd78c6b7, 0xa765a084, 0xb879017a, 0x28fa49d6, 0x9f7ae92c, 0xa0fbd1da, 0xdbefd448, 0x668d16a5, 0xe1017462, + 0xc4b81a10, 0xa9c30ade, 0x1e85ecc6, 0x9284be2e, 0xa4831fe2, 0x8ab7f902, 0x5b529a70, 0xe5e947a1, 0xd435f9ef, + 0xad4ef185, 0xdca39340, 0xb4ef8fc1, 0x97442b0f, 0xe8323421, 0xf14dd068, 0x2f1f5bd5, 0x29d5d7da, 0xa0a25473, + 0xca2566cc, 0x5c64a3a8, 0xaab1c6c6, 0xfb2a00aa, 0xab2b15cb, 0x5276b968, 0x2e3a6996, 0x2025de02, 0xd34037a3, + 0xdae3f665, 0xcdc1ecca, 0x62f62c83, 0x268903a6, 0x8f1a3280, 0xa91971d6, 0x95bf208a, 0x4466b8e9, 0xce502213, + 0x2f924c76, 0x916ed878, 0x14903491, 0x5bf22d2a, 0xd1eca9ce, 0x18bdcc49, 0x5fb18d36, 0x00412c4f, 0x1bda360e, + 0xd8d8bb53, 0x9d53f7e6, 0x2b2cc75f, 0xbe9e75af, 0x15d06750, 0x5798405f, 0x2b002c43, 0x1f7d7a55, 0x4c784823, + 0x9702b2b2, 0x276f2f17, 0xbca4f6f6, 0xda9835a7, 0x10b13f7b, 0x7c313b98, 0x2592f3fc, 0x5822de51, 0x722d6743, + 0xe627df5f, 0xed64b47d, 0x452428e9, 0xf03fe33b, 0x0a41c6f5, 0xdc409b35, 0x6109653c, 0xabe62cb7, 0x4a951217, + 0x91b65a65, 0x337154fc, 0x765ce334, 0x76d55357, 0x947bd6e9, 0x7b207cb3, 0xbc9543a4, 0xe9c08d5f, 0x70ac1f11, + 0xe8bd5003, 0x50831bc2, 0x637a4f33, 0x3e3edfc4, 0x905f4eb3, 0xe73d0280, 0x74ec0b26, 0xfb87d30d, 0xa7c8466b, + 0xff64feef, 0xc59ed9f1, 0xda0a7789, 0xa310911a, 0xf6190e27, 0x7db46d68, 0x0e1b4c18, 0x6b70fb2e, 0x987ca0a6, + 0xd91647f2, 0x7ed6f041, 0xb1b367da, 0x843f39f1, 0x12a5f75c, 0xf6ff534d, 0x4e14ee90, 0x2c4e8d7b, 0xc34f3f5f, + 0xb6a03ed9, 0x27f5cc8f, 0x01f6805d, 0xea7097c9, 0xb0bf8771, 0x1bd55fd6, 0x3f703077, 0x89258764, 0x0d6d2b86, + 0x5877585a, 0xa4958c11, 0x4d4ad64f, 0x4c6dd18b, 0xa9018570, 0x2727d555, 0x5fb46b61, 0x29b19ead, 0x86816349, + 0x9d99dce5, 0xc0c89075, 0x72efdc5d, 0x9a909eaf, 0xbba932a6, 0x55a8715d, 0x0096b7de, 0x10bda48f, 0xc5ef4791, + 0x0eb658a9, 0xea90f6cd, 0xf66249fc, 0xda1c73f9, 0xde2ef236, 0x51e2e515, 0xfd089758, 0x74fe0f78, 0x26734928, + 0xa174f33c, 0x90dfab7e, 0x3e163983, 0x527d03fa, 0x726bbd67, 0x595fb17e, 0xb7fdc8aa, 0x23010073, 0x57c829a9, + 0x6ec203f3, 0xac2f4f46, 0x883fa5c0, 0x1adaad7c, 0xf4aea3c9, 0x211c01b0, 0x0aac617b, 0x21065fad, 0x4c862146, + 0xd7bcc0ff, 0x61f61662, 0x30ab7819, 0x25661e3e, 0x47c934fd, 0xbdc25d73, 0x06a985e3, 0x2b4c624f, 0x7197051d, + 0xede3b812, 0x2004a23b, 0xe403ee4b, 0x46aa28e8, 0x5fcf7168, 0xc0f0c312, 0x0d77a7c6, 0xfaf27dea, 0x93b64437, + 0xe73813fb, 0x6eea1b03, 0x8822b515, 0x3df39b5b, 0x5bd6728d, 0x8eaaf9f3, 0x703fa1c8, 0xd379a259, 0xef26b65b, + 0xe43419e7, 0xe868fec6, 0x0301a48a, 0x06367f34, 0x23c58d94, 0x3f1e0977, 0xe860a19b, 0x0eb29f58, 0xd890131e, + 0x03dd120e, 0xff42bb0f, 0x5d392b8f, 0xa1097dbb, 0x62fe06bc, 0x169153b0, 0xd27e53ea, 0x3625538b, 0xd6842e24, + 0x9bb1329d, 0xbac9de0a, 0x5ca81873, 0xc6018516, 0xd74605cf, 0x8296be52, 0x54055a20, 0x8726ab2e, 0x56b0728b, + 0x7e6f69b3, 0x7223303a, 0xcd09d471, 0xf476f297, 0xd0fb0216, 0x3118ad7c, 0x619d5ac9, 0x9544e0c9, 0xfd72c22c, + 0x1bcaf5ce, 0x4141b696, 0xd0188dbd, 0x621a25bd, 0x9915564b, 0x564297ed, 0xd9496743, 0xccc02690, 0xed8e2e33, + 0x02d10c8c, 0x34bba6e7, 0xf9c5fabe, 0x3f280d42, 0x0f33486d, 0x122cb491, 0x8007e1d1, 0x2729e1ea, 0x5b017b1f, + 0x6c7aa5d9, 0xd7befbeb, 0x9ec652e9, 0xaebcd364, 0xdf07680a, 0x796edda5, 0x2c338503, 0xe6c1e7f9, 0x56563aa4, + 0xcdac5564, 0x2dabd7dd, 0xde8fa37d, 0x5365bd04, 0xe195902f, 0x9f706d2f, 0xa9537013, 0x3785452d, 0xb2d4e878, + 0xb8df9824, 0x15d94392, 0x2b8d5ece, 0x419f8ffb, 0x75d4f62a, 0x99945613, 0xf167f669, 0xd68f6772, 0x48c47245, + 0xb00dcd96, 0x0158a59b, 0xdd8f2947, 0xe2996822, 0x2a7c09df, 0x4fa5ebe3, 0xdac32867, 0xd21765f0, 0xe5752641, + 0x6620f2d8, 0xed98e2cf, 0x25cf074b, 0xadbebfde, 0x0b68cd35, 0xd0b5cfec, 0xaf4c403b, 0x6e540e79, 0x07c045dc, + 0x04fc97d4, 0x45114d5f, 0xdcd5c402, 0x273590c8, 0x4a9bcdbb, 0xa3eebd9f, 0x11367c51, 0x42a06d66, 0x861fd6d3, + 0x42606b0b, 0xc7ed0fb1, 0x03cdcde7, 0x6783c9fb, 0x62b5efd3, 0xccec556d, 0x0a47b495, 0x81ee7752, 0xe40a8c85, + 0x3c09d216, 0x251d4f7c, 0x12301afb, 0x262b497b, 0xab569fdb, 0xcf96d4a6, 0x32c4a9cc, 0xb95413f3, 0x04cf5258, + 0xb432aa8f, 0x91233529, 0x0643d45d, 0x9d62f49f, 0xd56f18ec, 0x4284688c, 0x90cff09e, 0x62e24ec5, 0xfad014fc, + 0x36fd9788, 0xc78f71db, 0xed9b84e1, 0xd8795754, 0x1e0fa86e, 0xcb872e77, 0xbe0d2ad3, 0x2a563dbc, 0xb686e953, + 0x7fc9f1dd, 0xf1021062, 0x17acacf0, 0x3eaff109, 0xc6cbb6f5, 0x8899a4b7, 0x515c9b3f, 0x3c6366ec, 0x55a63dcd, + 0x3d14b09d, 0x88584374, 0x555a3fc8, 0x76c9d3ac, 0x51036f77, 0x4b9a97f4, 0x58c2f38d, 0x67a23edc, 0x8fe60f4e, + 0xb8290df2, 0xb2dfa674, 0x42fd4395, 0x3bb663d7, 0x3c9edf43, 0x391c44c6, 0x1f390443, 0x4c3ef5b1, 0x02ac904f, + 0x8333727b, 0x36678b0f, 0x20e19dcc, 0x89d254ee, 0xeca1bcfd, 0xe69e175c, 0x8816bc4a, 0xded59561, 0xf82e344a, + 0xbfd0bf9e, 0xb9e8a452, 0x10893595, 0x71fa3fb4, 0x63e280a2, 0x085732e7, 0x8c7743c0, 0xf8624468, 0x8a7f9787, + 0xbd46459b, 0x588c5173, 0x02afc901, 0x9a4b5401, 0xb5547af0, 0x7ce2c1c9, 0xfa3bd4df, 0x05b721b3, 0x4e83fc4f, + 0x0b329a83, 0x4faeb257, 0x87775e1a, 0xb13fc0f5, 0xdbd19563, 0x57b45329, 0x26398dbf, 0x419f81fc, 0xd18c5862, + 0xb3379592, 0xdd9e9a2e, 0x55d832ec, 0x6d18a596, 0x162bca1a, 0x2ecd9251, 0xb6c0e672, 0x1e53927f, 0xa17a2bee, + 0x9e567595, 0x80be0955, 0x9fae871f, 0x3bf0e188, 0xbe68768f, 0x783f484a, 0x0c308e72, 0x22e4199b, 0x68b9cca9, + 0xa80f98d4, 0x5d4384a6, 0xe58fc01e, 0xa15a5073, 0xf8cb9bfc, 0xaa32edb2, 0x0811538c, 0x3f9a81c9, 0x41e275df, + 0x4bfc64d3, 0x87324486, 0xcf112011, 0xc61de540, 0x600b86b8, 0x39099e9f, 0xe9812bb5, 0xfbdce584, 0x73666762, + 0x9454555f, 0x9eaf7885, 0x2478ede8, 0xa18c3af5, 0xd9605669, 0x4467536c, 0x4ad2534a, 0x1d4c5c79, 0x3972ea1a, + 0x032006fc, 0xbc485ebf, 0xe4afe010, 0x27fdedff, 0x8319a04b, 0x23b76599, 0x0450e352, 0xc054f5c4, 0x315a8253, + 0xf8730795, 0x9d0fa774, 0x3e983b21, 0xca221618, 0x359d6126, 0x781c00ba, 0xcc49a5ff, 0xb22a2dc2, 0xc9d8e707, + 0x61eeba80, 0xefbebe23, 0x24218522, 0x3dd0db0b, 0xab24a901, 0x17e4cdfc, 0x4fcd70a8, 0x10f46093, 0xa37ba2aa, + 0x54bc2be3, 0x7e2b80c5, 0x94032656, 0x6b1dc581, 0xf48cdcfa, 0xee2ab03e, 0x48fb4b46, 0x95dd6f09, 0x5661a912, + 0x06f74fdb, 0xee1271a2, 0xc8af8c6c, 0xb4585d55, 0x501639e2, 0xab496643, 0xd32d5402, 0xfc30da5c, 0x221d27c4, + 0xb3fdfa1d, 0x679d482e, 0x22fc8016, 0x4add70cc, 0x31dc8684, 0x7369c83d, 0xa0070c43, 0xbc459d58, 0x37e4da3c, + 0x7dc2b97d, 0x2da6a0ca, 0x54e57afb, 0xedbcd087, 0x32660c8b, 0xa1b7f696, 0x2954b127, 0xa8cabead, 0x72611a49, + 0xcdba4be7, 0xabbe3b60, 0xd468880d, 0x0ff189ff, 0xe47520b0, 0x5a1bc4f0, 0xf61be6ea, 0xbe818ecd, 0x41263a35, + 0xa8d1412a, 0x11d465d2, 0xd3bc7229, 0xfeecbe17, 0x0eb5dddc, 0x27accf2a, 0xf888ae8a, 0x04b21beb, 0x84cee7ea, + 0xe83103c1, 0x3bc8cd41, 0x7ca8435b, 0x65066767, 0x3231793f, 0xd6820fb6, 0x11d0f455, 0x5ffa5550, 0x74af2906, + 0x6149d444, 0x9d495945, 0x999a8176, 0x27b466f0, 0xf51f7d6d, 0xac9f85cb, 0x2e281c31, 0x1fcc3f93, 0x7e782060, + 0xea78dbbd, 0xcb1174cc, 0x03f75ac4, 0x06495dbe, 0x8816e845, 0x498daebc, 0x07393e41, 0x7a8490d8, 0x7cf62034, + 0xd3569119, 0x40d50643, 0x5251a39f, 0xf1cf64be, 0x0e9e843a, 0x9f3183b2, 0xe6eed8ed, 0x18dd45d3, 0xceff6423, + 0xa5e91692, 0xb2b9596b, 0x4abea8f7, 0xd77ba5af, 0x96eb414b, 0x80d553b6, 0x42fe69f8, 0x8f01f8da, 0x0f7e8c09, + 0xf8ef1cac, 0xa2ec6dce, 0x53f8b1be, 0x19babce0, 0x2acd1d00, 0xe22bc986, 0x89ec3ad5, 0x17c6f823, 0xe0c58e70, + 0x0b51741b, 0x551496d3, 0x4b3dddff, 0x02069cca, 0xc4dca88c, 0x56f5fe43, 0x380aae26, 0xec640faa, 0x066ddcb6, + 0x90947928, 0xfe141cb4, 0xd6e2610d, 0xbb3fca01, 0x27d42888, 0xb2fb8f49, 0x985d62c5, 0x4078cc7e, 0xb3bce0b5, + 0xcab33fae, 0xfe200b86, 0xf39c3b8c, 0x0603ad8d, 0xc7a5847c, 0x8c178858, 0x3d269b2f, 0x2958e340, 0x20ac2873, + 0x52b1dc59, 0x2d456460, 0xf0f9ad18, 0x092ce83e, 0x58483cc9, 0x1f29d19f, 0x46a40f4c, 0x067f1909, 0x362fc0bd, + 0x7e0f469d, 0x8d8c83f1, 0x1063e5fe, 0x1208879c, 0xb8659ed3, 0x4fb8fa36, 0x871cc8c7, 0xeb383558, 0xb4e0c2aa, + 0x6d3cb33e, 0xedbeae6f, 0x6e047cb8, 0xce35ca3f, 0x568bbab5, 0x1ff153aa, 0x4fb122f6, 0x3ba1ac3a, 0x45cc4f32, + 0xeab7443e, 0xff9a03fe, 0x2b1c927e, 0x551a1c08, 0xabe07053, 0x62cec3c5, 0x95cd531e, 0x49a3a02f, 0x0bd95bcc, + 0xa7d85ea7, 0xc6d5a2b7, 0xf3608d0a, 0x2f51b000, 0x19aedfb5, 0x8e055fca, 0xe18f98db, 0x03718e0a, 0x1d39c668, + 0x0b9f9dae, 0x5ea94019, 0xd204f9b1, 0x87957970, 0xf5037140, 0x50bf50c1, 0xd523ed44, 0x11e84aa4, 0xbe761060, + 0x33e0abd8, 0x76b0e2e1, 0x0b3c410a, 0xca4b859a, 0x107930bb, 0x75fa6ec5, 0x94de8851, 0xf077be61, 0x361a9a10, + 0x10a97d6a, 0xc8df11ca, 0x07affba5, 0x9e98ca6b, 0x60b6179e, 0xcfec6565, 0xca83a0a5, 0xec85a819, 0xf4f14aa7, + 0xea4f2385, 0x6a849644, 0xb88bea63, 0x3169f957, 0xa2a4bece, 0x28f57eb3, 0xd54ed66f, 0xf5124e22, 0xfc95c6bb, + 0x0db55a44, 0xefa41614, 0x9487ace6, 0x2a263b69, 0xcc250a1a, 0x285de950, 0xfcbf1201, 0xd8290015, 0xaac86814, + 0xf76c8b82, 0x5de43e9f, 0x051c1c4e, 0xccceb4b7, 0x063f9572, 0x429bfc5b, 0xf516044a, 0xed5db0a0, 0xecaee4a8, + 0xde3113c8, 0x9dcfe25d, 0x28dd9800, 0x3bc2ab02, 0xe6778cbd, 0x835f43ad, 0x47920ee9, 0xbb84c2e8, 0x993dc183, + 0x842b7943, 0xe5527d26, 0x9285db77, 0x12f6b03a, 0xf365781a, 0x13b14bd6, 0x85d9a158, 0x690f44c1, 0x67f3937e, + 0x089f41b9, 0xcd43698c, 0xdc054e62, 0x8622420a, 0x9e6e6694, 0x8d0aaa54, 0xb2e9c6fb, 0x67b64d54, 0xc2209d0e, + 0x302c7bcb, 0x44238f05, 0x2427ff27, 0xe22dfd25, 0xf6f2434d, 0xe0a71638, 0x37e37d31, 0x91a51a33, 0x5f210d99, + 0x53af6ad4, 0xce79d36d, 0x72b24773, 0x0ca88712, 0x709209ba, 0x8e9e4a8c, 0xf760c4a2, 0x45bd2a71, 0xea4ae463, + 0x4e8f47e3, 0xbbd33b7c, 0x62511f1f, 0x47dbaa97, 0xe499bf39, 0xbea89c04, 0x02f4d36e, 0x0cf9ef1f, 0xd2d410ea, + 0x90136f81, 0x5e3ce65b, 0xad4d0adc, 0x472edc3e, 0xab822e6b, 0x2b9189d9, 0x48845667, 0x73bc3a5f, 0x501d30e6, + 0xf18e5eb7, 0xe7c35ba3, 0x3a95e04d, 0xc07247a0, 0x7f231388, 0x73d1c26b, 0x6060b3a6, 0x1a32b502, 0x29a57987, + 0x08124c02, 0xf6c9e326, 0xeaf9bd8f, 0x799fe5ab, 0xd498ac8f, 0x1d5aba1a, 0x306ccad6, 0x0def4163, 0x09fc26c5, + 0x71be6164, 0x9d0684e5, 0x1eacb8e6, 0xeff9ba85, 0x6f0218c7, 0x621c87c4, 0xfe051b69, 0xd0e48557, 0x3dc42363, + 0x0e742ffb, 0x2b71fa40, 0xe0ff3d38, 0x7b873ce4, 0xb89c7794, 0xdf73bb71, 0xf49f3234, 0xe6f10d98, 0xd28b0b75, + 0xf5492168, 0xd6625a93, 0x79a1df5c, 0x4f768fd0, 0x937f7df1, 0xa28717c6, 0x617f028b, 0x40469eda, 0xbe04e6d6, + 0xed888ae4, 0xa4e9cede, 0xe6896cfa, 0x927cf4b5, 0x3c848c9c, 0x1c5a90bd, 0xbeb19768, 0x935a7c66, 0x94a9622b, + 0x62afb4f1, 0x4c97877e, 0x43bb464d, 0x34e5f5fc, 0x1e8211c6, 0x94e51505, 0xf405f57f, 0x9c6c0158, 0x10f7f6bf, + 0x9f9794ec, 0x7c841bb3, 0xfe7a66ab, 0x434ff5ef, 0x0ad2c84f, 0x3ffbefa4, 0x8fb05a5b, 0x76d69d36, 0x8036ee5b, + 0xc6d197f3, 0x73f3d4bf, 0x2f582b0c, 0x519e882c, 0x4f60a7c1, 0xaf8a1a37, 0xbeb5e017, 0xa933a9ff, 0xf28b962c, + 0x0e9d3476, 0x14302400, 0x8d8a93b1, 0x107277f5, 0x4a0ae1b0, 0xc551bdb5, 0xbc33d398, 0xe22e1b1e, 0x5d51c94c, + 0x1d2f6916, 0xa3c0db5a, 0xcca0cf45, 0xe8f50359, 0x475b8e28, 0x61a54abf, 0xb52397ae, 0xab9a53db, 0x79ff537e, + 0x84c4e5bc, 0x990b9c86, 0xbfacc834, 0x3558ba63, 0xb0335d33, 0x7844bdc0, 0xa1449e2c, 0xc2fedd93, 0xf8dbe31e, + 0xec472f82, 0x3de82fc5, 0xfc188725, 0xb78a7da4, 0xdc40ad60, 0xb672efcf, 0x856e416c, 0x2d14ec9c, 0x182db332, + 0x3fdd4677, 0xf9fc3e31, 0x08d64218, 0x3ba42983, 0x5c72c8db, 0xc42881fc, 0xc5625746, 0xcf832deb, 0x5f048dc5, + 0xb08912e5, 0xd62eebcd, 0xdc9154c8, 0x6660e2c2, 0x3905f695, 0xa9a60bde, 0x373f5f99, 0xf6396bd7, 0xb842f264, + 0x9571fd84, 0x2c5e58ee, 0xeebd3a85, 0x19a3957c, 0x3d4ad1b8, 0x1ed87c5d, 0x187c035d, 0x2ea28238, 0x9fe7c644, + 0x40b70eb1, 0x6d79a5e5, 0x6cb493f7, 0x6976dcb4, 0x68cc25b7, 0x7a44be6f, 0x50be7447, 0x49924363, 0x62112510, + 0x5979a835, 0xc4f0bc53, 0xe584f823, 0x2817073e, 0xab21e181, 0xb6bf9088, 0xa99f24f6, 0x03894167, 0x6f63e1a4, + 0x60c76652, 0x162c3f28, 0xb8a76610, 0x29e81425, 0x9a4a9fae, 0xcada505e, 0x2ee16e30, 0xa4480bca, 0x809e0602, + 0xc6611f32, 0xf18762fd, 0xcc83ec09, 0xee2febed, 0x4b2083ef, 0xd49c4d72, 0x5add2389, 0xc52500f1, 0xd31952cd, + 0xbf6a2520, 0x375d1b75, 0x3ba53536, 0x5c738c80, 0xbe6f0c5b, 0x92ac1ec2, 0x45545f56, 0x9c1c676b, 0xac842540, + 0x3b9b3a8a, 0x522a0f28, 0xeb9de2e7, 0x828a9d7e, 0xa05a9fe9, 0xd2886c39, 0xc88a7539, 0xd2632814, 0x130d5fcb, + 0xa6ebbaa8, 0x1578d858, 0x92848378, 0x807255c1, 0xb75b7784, 0x92c3b691, 0x6b772d1f, 0x840785b2, 0xca7e2e53, + 0x814d52c9, 0xb16aa015, 0xbc09b0ff, 0x566aef07, 0x3ec8e8a5, 0x80fc2fb8, 0x639c066c, 0x0e9890ba, 0x06990378, + 0x38e4543f, 0x47f24728, 0x4627bf82, 0x8c8d965b, 0x736922eb, 0xb0670b21, 0x570d78d5, 0xc9403158, 0x6027f52c, + 0xfed31744, 0xf7558a58, 0x5c9f3de4, 0x48d8e1bd, 0x4348ff79, 0xfe86b4b1, 0x8b5bda0e, 0x9417df42, 0xe790b24d, + 0x1b7e0357, 0x7cd15a1b, 0x60cd778a, 0xd7063fd4, 0x8ab00768, 0x05da60b9, 0xaf33cfc6, 0xc353a1d4, 0xf14f7b8d, + 0x024bead8, 0x2131bf4d, 0xd7f1404e, 0x899ddde9, 0xf82ff8f4, 0xbb010a0e, 0x67a4bccd, 0x6f93022e, 0xda53cf7e, + 0x22e2cd4d, 0x8dd0b1aa, 0xe5a0116c, 0xf8243e78, 0x8ff27804, 0xff812b8d, 0x388f5d87, 0xba9572b5, 0xaef183d9, + 0x1c5301bd, 0x8354e819, 0x32311c62, 0x76bc23b9, 0x96633300, 0x1b540aea, 0xddcd342b, 0x61972158, 0x35a0b01d, + 0x9b1ac6a8, 0x4c9e0801, 0x4d1dbae4, 0x222ca284, 0x4a9baf3a, 0xd966ef5b, 0x5c5132f6, 0x05dfb509, 0xe2709b47, + 0xe304045a, 0x215c210b, 0x098f187f, 0x0ffe295b, 0x620b99af, 0xb6e65bf4, 0x7dd5818f, 0x4b06707b, 0x22f3a1cd, + 0x2207b9be, 0x2bc953f9, 0x83829cb0, 0xbf7deebb, 0xc898138e, 0x0efa3b09, 0x232aa1b5, 0xb14d640b, 0x48866921, + 0x588764c6, 0xb44d137c, 0x9bc0e86e, 0x09187e75, 0xcd269556, 0x012265ef, 0x9b329c6e, 0x76fa5ffd, 0xd899abea, + 0x97f129fb, 0xad02c552, 0x6ce8e783, 0xd188a916, 0x77fd0664, 0xd7723d6a, 0x9aa102cd, 0x95bb4ad6, 0x2b9bd2cd, + 0x171da750, 0x4df1cb11, 0xdd4e9ae1, 0x6e943156, 0x730c2b46, 0x679848c6, 0xaa2cf4cb, 0xc0802fc0, 0xb2ffcee9, + 0x36892364, 0x25e6f87e, 0x53b0ca40, 0x15f4ac26, 0xdf14156d, 0xa7cffbf7, 0xc2a2f2f9, 0x447b3224, 0x4d8564db, + 0xe69212bf, 0x8f17c913, 0x5f476e17, 0x3f1e3ca5, 0xa9b085a3, 0x327b62ee, 0x4badd409, 0x4ede1d6c, 0x7f7d3560, + 0xc41de186, 0x564f02a4, 0x08cab905, 0xe0b0a69f, 0x6f08554d, 0x613a356c, 0xfde6bf52, 0x4c90a592, 0x062c179b, + 0x877514e0, 0xe400b0a2, 0x9f7b5868, 0xc075f217, 0xc6c4224e, 0xa7f5b58d, 0x912d47a5, 0x45af5635, 0x98286c24, + 0x8b50849c, 0x4a8ee2ed, 0xf4c92944, 0x31804dd4, 0xc500d5b8, 0x7c8a2866, 0xeec6bd9a, 0xfb5526a7, 0x2938a1b8, + 0xcb360b80, 0xf8a7e11b, 0x6dad7a53, 0x902a2201, 0x2d854d42, 0xc5dae351, 0xdbbf5c7e, 0x9fb830ce, 0xf4ad752c, + 0xe206c408, 0xb734a091, 0x04194ea9, 0xf446c7aa, 0x070af77f, 0x1683cba0, 0x8b0ac2bb, 0x142dcb30, 0x28e46b67, + 0x5027fbc5, 0x4f34c656, 0xfafb04b2, 0x49a9cbbb, 0xcb4e6f2c, 0x7d6b3abc, 0x103ca13d, 0x41f3341a, 0x325fa501, + 0x2ef75d29, 0xfae5b4eb, 0xb1d881f1, 0x32488646, 0xc8abdba3, 0x45a44ac1, 0xdf048714, 0x38a06e44, 0x95df3142, + 0x66e2c90a, 0xa28b1319, 0x1b0eb88d, 0x2bf4fb2e, 0xc6eb7e02, 0x3741a7e1, 0xb3bd077d, 0x8716edfa, 0xd10b6e20, + 0x7e1d481e, 0xa8356f48, 0x016faa74, 0x964d06fe, 0x7c2b19ac, 0xcd722aea, 0x54bbd480, 0xd6adaad0, 0x33b5989f, + 0xeb47b97b, 0x04506e2b, 0x8dfbeb64, 0xfca332e4, 0x56515ce7, 0xd0b7dff5, 0x645df52e, 0x39dfbc5e, 0xb0436d75, + 0x495bcc8f, 0x8fa052f3, 0xeec8f2cc, 0xb100752f, 0x4120ad55, 0x3267e5dc, 0x99408cc6, 0x24f075f2, 0xcbf9499b, + 0x1a74295f, 0x6c678651, 0x9f94f24c, 0x809757c6, 0xe93ebf24, 0x82b1b099, 0x3d32d3ce, 0x1f49575a, 0x430c1cbc, + 0xecf4116d, 0xac5a1b15, 0x155fd8d4, 0x8ea79f7d, 0x54d2927c, 0x18bc5904, 0x09e00bbd, 0xcecb4a81, 0x67e5fa71, + 0xfc9f3eef, 0x0e87c501, 0xb0a8f053, 0x9a425ef6, 0xcd8f0144, 0x5c1daa23, 0x01dbc7aa, 0xf5fea3b1, 0x98fba72b, + 0xe7589b22, 0x6e7707c0, 0x1503e666, 0x4f8241ef, 0x52c1341f, 0x330a18f1, 0x95f0b741, 0x27b0bec6, 0xed6899d3, + 0xb038b2a3, 0x4e4568da, 0x8f66a2cc, 0x7839f184, 0xa0d3eae4, 0x9d57dfb3, 0xcaa09237, 0x4f3d5214, 0xb4124748, + 0x11e3d8c3, 0xbcb35599, 0xfd9855af, 0x453c3f61, 0xb7670f7c, 0x75b9ac99, 0x3259857e, 0xd684159c, 0xec87b5f1, + 0xabbbe82f, 0x1b7fdf13, 0x48364d30, 0x249fb35f, 0x3d9df4a6, 0xc79b22e2, 0xe74b405b, 0xa3e376f6, 0xe92c47d8, + 0xb3a8cdcd, 0x19da625b, 0x0f8465d8, 0x29cbc751, 0x0193ad66, 0x44465f0c, 0x0517f18d, 0x8f241706, 0x1d110be6, + 0xdcbd9b06, 0x4484587c, 0x702527e5, 0x1575883c, 0x13b10ae0, 0x04a2075c, 0xed350c09, 0x738e467e, 0x53b225e7, + 0x5f54923d, 0xe7a4c79e, 0x70737e21, 0x97a16c47, 0x11266253, 0xd1a99758, 0xe5b00d77, 0x19389078, 0xd91a00bd, + 0xe084e75e, 0x6f4a5b99, 0xdba7823e, 0x22b81bc3, 0x8882b909, 0xb9d39b35, 0x93880b76, 0xce38163e, 0xbc9f5ed2, + 0x4187e93a, 0x5d50c6fd, 0x0de9653a, 0xbef349a9, 0x7b96ecda, 0xc3ed75c4, 0x09376780, 0x6e52fae4, 0x595ddccc, + 0x3eb99fc4, 0x6ccb7bd9, 0x3d682c5f, 0xcc19f144, 0xf54afcef, 0x91804f88, 0x8f3fab1c, 0x82c51fb5, 0x2f873136, + 0x111f987b, 0x001d2658, 0xbfd943df, 0x419176d6, 0x6ed41b52, 0xc9cdabfa, 0x12b12789, 0xc24821a4, 0x99cade02, + 0x6b9971cd, 0x6a4c11af, 0xd677d761, 0xcdcb1630, 0xefbe61af, 0x553e9fdc, 0x2f36a658, 0xed24622c, 0x8060f4ee, + 0x2bfbb282, 0xc9642ee1, 0x7d7f1e27, 0xf936d4a5, 0x703bc6e6, 0xb76e9f52, 0x459e7ef1, 0xe4229962, 0x6842d12e, + 0xe7772358, 0xdb26d2b1, 0xe752997d, 0xa66c9422, 0x2973fc0a, 0xeeb3ea5a, 0xac4370ae, 0xb17a1a8e, 0xbdc34417, + 0xd1ae5072, 0xe07f9c48, 0xd4cd00db, 0x5c14a14d, 0xd002ea34, 0x289b9f23, 0xa7929e28, 0xd124af2d, 0x74fdaa67, + 0xa77d171d, 0x10c00468, 0xb4b375bf, 0xa19887e7, 0xa6a7d08f, 0x3dca7594, 0xae921760, 0x50863649, 0xef5dee84, + 0x63b77253, 0xf5fb3813, 0xdd08a40b, 0x688fb28d, 0x184fde35, 0x6c1fcb86, 0x77c0d9fa, 0x06b5f0aa, 0xbce681f1, + 0x6590d8ec, 0x6ce3534c, 0x65f01744, 0x3cc9e06c, 0x1a502ae6, 0x8fc5f975, 0x19e410a2, 0x55230440, 0x19fc6f41, + 0x4902ece6, 0x909a87d9, 0xdc6e2c23, 0xbf1ab411, 0xcba475ff, 0x9e79be04, 0x120ea206, 0xaa6b4105, 0xd9465e12, + 0x33542fbb, 0xa9e3ffe4, 0xa15f9da0, 0xa6f05ed1, 0xa2433e22, 0x6ab526a1, 0x9767d600, 0x7766ddf8, 0x5a6b7855, + 0xa5764a33, 0x4be67631, 0x9f16655f, 0xf36582c9, 0xf16711a3, 0xce2d83ae, 0x0348c7d6, 0x8dbd3aae, 0x39f91ad6, + 0xe920d06c, 0x070458eb, 0x0e92a939, 0xf6b22464, 0x3fbaa007, 0x7c32cb79, 0x40ba86ad, 0x60758c48, 0x1d926a6f, + 0xe4f3fbc1, 0xdf83b061, 0x9048a2a5, 0xb501c2d2, 0x5068e5c6, 0xb41841c2, 0x24d257f0, 0xb136057c, 0x9ba3728e, + 0xdb7311f1, 0x239a0832, 0x2193d3fa, 0xddaef267, 0x0c15dfe7, 0x220c2914, 0x3d72cda2, 0x48cfc35d, 0xc9b0b4bd, + 0xc259aff2, 0x22abeccf, 0x94ca9eb7, 0x617ab375, 0x1aafd38f, 0xf92d6681, 0x0477efa6, 0x8143e5a6, 0x3b77ee2e, + 0xb64d6537, 0xaea7305e, 0xe6e49005, 0x449b2496, 0xde594c25, 0xab20ede0, 0x0a3cfa39, 0xb90be305, 0xc0474be0, + 0x5dee35d0, 0xcf50123c, 0x329887c4, 0x9c25086e, 0x6a15f13d, 0x4adf7ea6, 0xe2b78305, 0x54ad0836, 0x79c26a75, + 0x9ca3d04c, 0x26b250bd, 0x5135c9fd, 0x7edf95be, 0xa9752faf, 0x4387b141, 0xd4a89137, 0x4bf47851, 0xa1f8d3fe, + 0x809e22c0, 0xeb993689, 0xcf04be5e, 0xc081017b, 0xf78801f6, 0x05d72891, 0xb3404b4e, 0xc629ff9a, 0x5dd50f9b, + 0xdee7fcfc, 0x37f56eea, 0xe6e68db7, 0x6cf9773d, 0x4414c7e2, 0xb8fc6ad5, 0x92856530, 0xa2638105, 0xb1ffca48, + 0x4426495a, 0x0502bd52, 0x84e44dc4, 0x7d76266d, 0x515c945e, 0x62318030, 0x9bfda4d4, 0x1bd3a841, 0xc49d565b, + 0xf4b226a6, 0xaf95d250, 0xd7964573, 0x9c530f82, 0x6b5ae9a7, 0x6ed2cdbe, 0x994d0158, 0x79ac8930, 0x85230a8d, + 0xec0fc430, 0x679c7e68, 0x0b9b369b, 0x8c98c44d, 0x6b9c4f15, 0x10008fa4, 0x21de18ad, 0x37e17d51, 0x9150b39d, + 0x0e49d0fe, 0xf8ae3821, 0xa3bfb962, 0xbbec3ce9, 0x4e3beec2, 0x46c52c2a, 0xea27d666, 0x785cfda6, 0xb7e327bb, + 0x5693e32e, 0x42bfb657, 0xe133104c, 0xc6ec1054, 0x8f2870f6, 0x85ab7fac, 0x6f9fcdda, 0x0ad173c4, 0xb4325d1a, + 0x2442940c, 0x15950897, 0x61ec5dac, 0xe87fb5ce, 0xd921df93, 0x876185c3, 0x399cdb28, 0x7fda0404, 0xc358b96d, + 0x199ba6bb, 0x833de12e, 0x4792f9b5, 0x2dd1b7e9, 0x1692b5dd, 0x7e3585b3, 0xc7e1dce3, 0xba2d8e81, 0xd0ea0777, + 0x0940fc8e, 0x7051d0d2, 0x7b6a277f, 0x962aac26, 0x9506e86b, 0xb39825b7, 0x51df4309, 0x90b109a0, 0x43c006bb, + 0xc49aa98d, 0x9590b285, 0x17df966a, 0xae9a5f21, 0xdfd9c1f7, 0x0c107811, 0x4db4ab45, 0xb4abb487, 0xd0c908b0, + 0x65653113, 0xb6b0ba1c, 0x6014ac7d, 0x48b40e91, 0x4cee0b0a, 0x2c0d81f7, 0x7912490c, 0x9fb57d68, 0x01aa030b, + 0x1b44fdd3, 0xeb10ad9b, 0x71cdd57f, 0x51a86304, 0x05be9242, 0x91bdc099, 0xa4b14744, 0x2601f151, 0x6526cebd, + 0x46ebe70c, 0x852b02e2, 0x512ae3c7, 0x18a8fd1e, 0x944ed6e1, 0x497374ce, 0xeea72e60, 0x4aec1dbc, 0x823ecd4f, + 0xa58f15d1, 0xf2fed293, 0x59ed86a2, 0x3c58bdc6, 0x7b4fe612, 0x5e53700d, 0x47911bd5, 0x2db7325f, 0x96b5d5d8, + 0x2f81ab69, 0x2d571eb5, 0x756a22c4, 0x20c4e4a1, 0xfc53176b, 0xc18de3ab, 0x63227871, 0x2555db4d, 0x37c14128, + 0xdd9efbff, 0x7406c783, 0x6b5eb5d2, 0x345ecddb, 0x128eee6a, 0x2d4b279f, 0x861534c5, 0xa635b2cd, 0x146310a1, + 0xe46a36a6, 0x6fb628ba, 0x8a0a651d, 0xf04b0222, 0x223f2e1a, 0x295221c4, 0xad142e25, 0x9ce65662, 0xe3851612, + 0xf01ca88f, 0x651eedba, 0xf6297212, 0xc8a36839, 0x1e064bcb, 0x5504b797, 0x0b4e8c98, 0xacc624fd, 0x966c44a7, + 0xad947bdf, 0xf2185a63, 0x288d3f1f, 0x3dd2d70a, 0x23aa8ce1, 0xec04a90a, 0x57fd8787, 0x125db307, 0x0acbc33d, + 0xf53a9add, 0x51346ab8, 0x6d6d21d4, 0x160fc94b, 0x5ce0e352, 0xc443d3b6, 0x560526d4, 0xd9b9b375, 0x1e1b2a18, + 0x42cbcf74, 0x3b9a2907, 0xea85573c, 0xbb691ecc, 0xac67254a, 0xd74c55fb, 0x76e47356, 0x5f472231, 0x9dcabef4, + 0x5e70e9ab, 0x211ede4d, 0x9c26b77f, 0x837d5131, 0xc2c579cb, 0x51d65827, 0xfdc3edb5, 0x82db8463, 0x5600538e, + 0xf6b8d557, 0x551cf15b, 0xd005a287, 0x8397b6a0, 0x3c5d82dd, 0x493b41c8, 0xa4de7171, 0x88e8049a, 0xb61ade1f, + 0x63d33cba, 0x5e552b27, 0x7a30e8d9, 0xd03057b7, 0x8b665b3c, 0x8f7285ea, 0x051eadc2, 0x31e97f4e, 0x69bdbf3b, + 0x214b5ecd, 0xb34604a9, 0x150cc62f, 0xea39e582, 0xc98b867e, 0xd3195e56, 0xc2d4d4c7, 0x1045011d, 0x4fc50bef, + 0x56a5d25f, 0xffda96ad, 0x726760fb, 0xeb2cdad9, 0xcdd236fd, 0x04fe90dc, 0xefd4b3c8, 0xfd2ede27, 0x7c435415, + 0x6a84996f, 0x30a21e42, 0x6ecfe17c, 0x3a445f17, 0xed2e24cd, 0x9fb537c9, 0x7e2e6ab1, 0x6fe1926b, 0xf31814a1, + 0x111ee292, 0x41b69b9c, 0xc966cbfb, 0x25a06ed3, 0x929b80cc, 0x2176394f, 0x19bf49fa, 0x11c14efa, 0x8edcac6d, + 0x8436bb0c, 0x44eff15d, 0x2e849396, 0x03ceb550, 0x18795b13, 0x6c555fc0, 0x84ba4866, 0xe04f7477, 0x071d2d97, + 0x51ae9a7d, 0x47df1c97, 0x51e2a4b2, 0x2666fded, 0x7e996e1b, 0xdfe276f4, 0xee9c77ce, 0x3e3142f8, 0x8efeb621, + 0xa6f88351, 0x882e4b2a, 0x73d0f447, 0xb05a13a6, 0xe2ed8d13, 0xf73a9978, 0x2819a36a, 0xe741f5e8, 0x0173fb2f, + 0x5806dfa6, 0xec3505cf, 0x6f463808, 0xf2fd2791, 0x1b1019d0, 0xf8170e3e, 0xc1302877, 0x604caa97, 0x71a1912b, + 0x52048eb5, 0x163573a5, 0x1000aea9, 0x71abff0f, 0x5ae11b90, 0xc32c7f3c, 0x0b0b6a7b, 0x21b003de, 0x27f6baf1, + 0x74eadab0, 0x8dbc907e, 0x0b3bb8c5, 0x17a28ffa, 0xdb6226ec, 0x854dd0e6, 0x0af57b5f, 0x2a8d0565, 0xf4ba0a9c, + 0x1456d480, 0xf7ecf16b, 0x8313f562, 0xe8a8d539, 0x57cf8515, 0x40710c5d, 0x05d70c4b, 0x7caec862, 0x77a5900f, + 0x56a4a551, 0x283fca54, 0x8cd06b7b, 0x9ad1dc32, 0x9d7825c7, 0x9d9b18f2, 0x6e85385c, 0x14daf4c7, 0xe56dd4e4, + 0x40431d9c, 0x743158ec, 0x87ea12c7, 0xdaaf9055, 0x1653953b, 0x4797dfc9, 0xf72c26ac, 0xbd97a22e, 0xcd8df10e, + 0xda1e1561, 0x775eb998, 0x72e6cf71, 0x90fda923, 0xd4b5153a, 0x0563f3fa, 0xb23c0aad, 0x6f065f01, 0x0794f856, + 0x92770bb0, 0xf1716d6a, 0x403adcb8, 0xe83c8372, 0xd92e36ae, 0xa00d1cfb, 0xa1276b61, 0xb4d0d7ff, 0xd7a932a2, + 0xa786dfc3, 0x0eeaf211, 0xf0a442a7, 0xf5a4cb36, 0x72cf631d, 0x15ae6b1c, 0x31f1bca3, 0xe6d1f1c5, 0xbdaf9fef, + 0xa4207dfb, 0x7e4fca48, 0x5aea1a5e, 0xaa790b71, 0x0c503566, 0x84828363, 0x87c8314e, 0x177ebee0, 0x23cb3dd0, + 0x61bf7f9c, 0xc8c7f4b5, 0x6ec1fc5a, 0x0891a735, 0x7062819e, 0x078971fe, 0x737c9f88, 0x6cce572f, 0x18f11ceb, + 0x50c82f05, 0xaaeca209, 0x78610b09, 0x127c9387, 0xa62b0e6e, 0x9c77f443, 0x414b74ec, 0x4c9d00a0, 0x171973a8, + 0x11aaf3bb, 0x909f3ce4, 0x8c1da46f, 0x292c90b8, 0x1972a269, 0x81689ea5, 0xdd1fe886, 0x419c71f4, 0xe19e15f9, + 0x713249e4, 0x2906b9fd, 0xfe552500, 0x4853ca58, 0x0ac05778, 0x91b2f9a3, 0x49d92e38, 0x6fcb27ab, 0xb7c0b186, + 0x12618714, 0x74157599, 0x0e59bd98, 0x75bbc4c7, 0x98115aec, 0x206e4212, 0x05e1cbd6, 0xffe7b85a, 0x0f2bd4af, + 0x55dcd38f, 0xc954875d, 0xcef740a7, 0x5e97786c, 0xc874cc60, 0xddb5ba3b, 0x38d8ec78, 0x660b322f, 0xd4e1e0b4, + 0xd7039827, 0x32ef8264, 0x16e9c97f, 0x25aba941, 0x8257a845, 0x6bbcffd6, 0x41421f00, 0x5126c63a, 0x8ba2199f, + 0x1894739d, 0x588ebd73, 0xfc870c44, 0xbfd45981, 0x51e62a1f, 0x7494e1ff, 0xb9cc8ebe, 0xfc50b719, 0xa43777f3, + 0x7a5f9219, 0x6322bf6f, 0x30c3afb5, 0x4a6d21f3, 0x02f4d396, 0x1c68f805, 0xe5d47a04, 0xf34ef2ae, 0xcda3a9da, + 0x6ecb2875, 0x430c8a37, 0x30c15f2b, 0x99bc9c57, 0x101ce413, 0x35ae95e7, 0x666be5ba, 0xe6559124, 0x1f9ad726, + 0x36cbcc86, 0x44201a30, 0x16c51fbe, 0x7bd8abdc, 0x06cfc22b, 0x55f2ef36, 0xa8227917, 0x471dfcc0, 0x897b4d1c, + 0xb0391b53, 0x44081223, 0xe53d4eaa, 0xea4f8767, 0xd308c22f, 0x3ce2e680, 0xdd8da1a7, 0x394607c7, 0x50168d79, + 0x50251199, 0xa46a00db, 0x546b49da, 0x5ef4e7f5, 0xa9b4a26b, 0xba3acedf, 0x3521d6ad, 0x30798389, 0x22017363, + 0x820d5098, 0x3868e65b, 0xe77881bd, 0x84d3b835, 0x1c260aa2, 0xe6bf79d4, 0xb6600465, 0xa12d0870, 0xada63027, + 0xfb0701cb, 0xfae87809, 0x800d72b5, 0xf341728c, 0x21b45046, 0x06601211, 0x0c9827d0, 0x32c1a049, 0x7285008b, + 0xcf65a4fe, 0x30502a44, 0x36ac3df5, 0x0cc9bd17, 0x921138e0, 0x0e253041, 0xb94546ad, 0xf284e2d3, 0xf483ba0c, + 0xa4b9b248, 0xcf3641b6, 0xd1b73ba0, 0xfa0c4369, 0xa83c7e93, 0xa4490477, 0x3745f113, 0x2f68ebd7, 0x76524846, + 0x062b27a4, 0x8176e9f7, 0x3b066a42, 0x89a5b17d, 0xfa7585ad, 0xf67df2d3, 0x74cf88d2, 0x6e880970, 0x0ee21fca, + 0xb41c1987, 0x1f1177de, 0x368963e5, 0x8c0b1002, 0xb14e8dea, 0xa08ea6ec, 0x78e35ac9, 0xc1ed4c98, 0x6d1b4117, + 0xfa651269, 0xf3675968, 0x990f8716, 0xe9f423b0, 0xa2e441b6, 0x20add24f, 0x37c9fc62, 0xba747665, 0x87f5cb39, + 0xf83064ee, 0xc94d1218, 0x8e4dfde6, 0x22f83c0b, 0x9053c73d, 0x32d808d8, 0xcbf4e255, 0x0dc34efe, 0x3253b237, + 0x7200b1c2, 0x70597001, 0xfcc9631f, 0xbacdf652, 0x0dfbaf9c, 0xd10a770a, 0x6af01031, 0x4a316513, 0xd6969441, + 0x6f0b477a, 0x19b9c86e, 0x1a2d7cf9, 0x7229e11c, 0xb78440a2, 0x2556add0, 0xb9597d07, 0x26163f5d, 0x3cd01690, + 0xfde9ea70, 0xe69fdfd9, 0x67e1b24e, 0x3d019695, 0x1a485f72, 0xcce5cd5e, 0x199d2c34, 0x95edd515, 0x7fcf4613, + 0xb239a50a, 0x268ae1a6, 0x5ef2a887, 0x109180b7, 0x0daa7ff6, 0x7cf352c2, 0x7874c1cb, 0x44b822bc, 0x5c64b9e0, + 0x9a390634, 0x6c3ec23f, 0x537d0251, 0xa8e155ce, 0xe0bdab47, 0xa5b37d85, 0x336c023e, 0x3080aa8b, 0xd97ab027, + 0x8c92e513, 0x1dcd2d3a, 0x62815f7b, 0xa2651f45, 0xfba25765, 0x91346484, 0x75d10576, 0x194532c0, 0xc4140c02, + 0xd7c257ff, 0xa4b7ccd6, 0x2527dd7f, 0xdad72f78, 0xe184be1c, 0xdb597c5d, 0x8859d2e0, 0x13018758, 0x1872121c, + 0x2037a4bc, 0xe81b2deb, 0xa76fa3bc, 0x9fb7f3f9, 0x37894a52, 0xcbfec486, 0x3ee7c370, 0xbf994f9b, 0x5d03fd01, + 0x600b9056, 0x033010f6, 0x6efe531b, 0x42b91de0, 0xb9c5c431, 0xafd578ad, 0xdb59d7f5, 0xb5814ec7, 0x80ea7dab, + 0x40441452, 0x1ec790fd, 0x4faa0194, 0xe8b6a2f9, 0x0dd7df1a, 0x325c1b20, 0x8908304c, 0xd5a787b9, 0x87b7550d, + 0xeb6d7e00, 0xe2a017a2, 0x86cd9c1b, 0x6ccab21e, 0x4a97de55, 0xd0f5b4c8, 0x752d800a, 0x74902f1b, 0x88b2e3d8, + 0x512cc723, 0xda1a7244, 0xf36c4032, 0x51f9f703, 0x3ac57027, 0xbf83c63b, 0xd3a689b7, 0xe64b2da5, 0x29934973, + 0x107b5193, 0x382b2c35, 0x655767d8, 0x0ac67ee3, 0x70dfab2d, 0x3b9130ba, 0xb986618c, 0xf2075c65, 0x3dd08f16, + 0xcada854c, 0x0cab729e, 0xe555368b, 0x2cb07a44, 0x0521f6bf, 0x66b8f611, 0x01ce31cd, 0xd12e2236, 0x3fc84349, + 0xdc79a630, 0xc089c8f5, 0xbf68ec46, 0x6ab98cc5, 0x2840c2e6, 0xc5b92cc6, 0x50ed59d3, 0xe1aa8b20, 0x8306ea19, + 0xef8a8be0, 0xb089b5d2, 0xe1f2b30f, 0x115c5baa, 0x4d9cfb93, 0x5fab0670, 0xf1458683, 0x6bc393d6, 0x9f767caa, + 0x6d8fb960, 0x938ba837, 0xdd44164f, 0xb77f6c2e, 0x832c35a1, 0xcb85224c, 0x4d1bd64e, 0xca03b327, 0x5f271c17, + 0xab658fa8, 0x59779240, 0x10160817, 0x9f9a2f6a, 0x6ac9899c, 0x11b03473, 0x5b50fe23, 0xe8761b8a, 0xf3d1cde0, + 0x7b37defd, 0xa03286e8, 0x6de81052, 0x7a29fec9, 0x1ebcdfc7, 0x211358f1, 0xb3b16574, 0xb70d5c90, 0xc3ef2029, + 0xad2630ea, 0x8c3924f3, 0x93ff6cd2, 0x0189646f, 0x99917d5b, 0xf5a651c0, 0x762a6e7f, 0x66230405, 0xe00034b2, + 0x3b4fe28b, 0xf3cfed65, 0xf6bc21c8, 0x69716e04, 0x64f67933, 0xec3dd922, 0xe79d2cc3, 0xaaba0af6, 0xa623f73e, + 0x9271a17e, 0x6f12b2bd, 0x2b2294c2, 0x6f317ef9, 0xab0eb341, 0xfc717b94, 0x5f16a136, 0x2fb9a299, 0xda914554, + 0x3c54f3a0, 0x5f160a4d, 0xcee053de, 0x4eb420ff, 0x43c29f89, 0x34f17f07, 0x91c8c19c, 0x00f89401, 0x47e43c91, + 0xf62b2121, 0x720b1389, 0x3e9cf4b4, 0xc6d4aa19, 0x5683e924, 0xade3ee3a, 0xcd265363, 0x3a26b271, 0x51133e6c, + 0x5da7f9b6, 0xb5fc6f41, 0x9fda4884, 0x78d248d2, 0x3a238b70, 0x94a9a22c, 0xfd7a7358, 0x7d623e10, 0xc2d98840, + 0x93fdf79f, 0xc82adaf1, 0xca2a5069, 0x0cd9f898, 0x0bcd4a57, 0xd7a0ce90, 0x58c147a0, 0x90675fa9, 0x5e360c4f, + 0x4920ec9f, 0x89817f1e, 0x248b6176, 0xc7807d5e, 0x34794a47, 0xb73708ad, 0xd32dc067, 0x9375715a, 0x95f6409e, + 0x3fb1768e, 0x4ad84f55, 0xb8c8284d, 0xda14f254, 0xb322967d, 0xad67154a, 0x612edb7c, 0x2620f9e3, 0x6007ade3, + 0x55e5c61b, 0x12f06e55, 0x25d373b0, 0xe8e2e9c4, 0x9a4b2ad6, 0x309fbe9b, 0x4a08eb18, 0x9b938bcc, 0x856ef37e, + 0x14c00d8e, 0xb4d8280f, 0xae2a3e18, 0x2406b9ec, 0xf6f39e6e, 0xe6f45c76, 0x243c0326, 0xdb7b977c, 0x69a59ef6, + 0xd23c6920, 0x1b174075, 0x37db968d, 0x319cf322, 0xd76ace6d, 0x74ae9560, 0xfb60b35b, 0x0ff09ee4, 0x9988a339, + 0x1824614d, 0xab8c294d, 0xc1ee7cce, 0x9c835bd6, 0xfcc626a6, 0x64e72b7a, 0x94617a14, 0x24c653f4, 0x85375114, + 0x94aba374, 0xff4501c7, 0x5ee5ceb5, 0x56ed59ba, 0xd6edc849, 0x0e7b894d, 0x7b2754de, 0xdff65cbd, 0x003ce0b2, + 0x91fa72d3, 0x86ea5b14, 0xcf4de353, 0x1568fe17, 0xde97368a, 0x43c95abd, 0x5ba2e99a, 0x1051e810, 0xbc445bee, + 0xb891f170, 0x9ddb4517, 0xb48eac51, 0x227141d6, 0x7a869659, 0x8cfc79ec, 0x5d2bd900, 0xaf4148a4, 0x18286cc3, + 0x322bc203, 0xc7a9a064, 0x27fdf7f4, 0x01644959, 0x8516ac8e, 0x2eddce14, 0x1829dfd1, 0xb0662903, 0xafd252dc, + 0xd35012c6, 0x2a84c759, 0xdf1efd73, 0x355eb0d8, 0x5bd4499a, 0x4c6c3514, 0xec688be8, 0xf12d4242, 0x3e696ed1, + 0x07e53636, 0xd0fd1bd9, 0xc281684a, 0x473308dc, 0x397ad849, 0x274a2764, 0xd4510893, 0xfd9905d9, 0x33d61c07, + 0x8043b8fe, 0x1b3d7a7b, 0x2ce6533e, 0xa40e9a20, 0x7b7f29f9, 0xc6bb2b94, 0xff197c06, 0xe71a708f, 0x081f6f43, + 0x582479d3, 0xe4c048a7, 0xad6a1d53, 0xea8a596d, 0xb25b628a, 0x013a46fe, 0x4581e067, 0x973439a5, 0x33ccf1af, + 0x0f3e5206, 0xb75c133a, 0x09afb16e, 0xc959f2ba, 0xc709fd0d, 0x5c69fc2b, 0x11e39b31, 0x92a02308, 0xc0725af0, + 0x5a343a7e, 0xecadaadc, 0x88823f37, 0xe17e5caf, 0x1b390237, 0x8685d7bd, 0xaf0806d8, 0x51c707e3, 0x2dd0919a, + 0x7325a27a, 0x33bd3727, 0x342441e1, 0xe705a2c1, 0xde2e683c, 0xd984e614, 0x1def2348, 0xc845b73f, 0x5fe40b7d, + 0x24389ada, 0x392c4551, 0xae7e20e6, 0xee4f5543, 0xd37d47dc, 0x7531eb32, 0xdaae9257, 0x4428efac, 0xa0ae3da0, + 0xc6487db0, 0x596d483f, 0xbe687d6c, 0x03c66b85, 0x9c9456a8, 0x8b2e1460, 0xfbedb7a5, 0x82d968d0, 0x9ef80226, + 0xc6c056fd, 0x0614b7eb, 0x7a83eeaf, 0xc4253722, 0xe4d93016, 0xe6a1be77, 0x1c601f81, 0x6f74caf3, 0x2bc97edc, + 0x592ec852, 0xb0ac465a, 0x8b1c272e, 0xcf137f9f, 0x8ffaf778, 0x88234d70, 0xd0bad299, 0x2c0bc8ca, 0xe9558658, + 0x1c3490d5, 0xa933c489, 0x19660722, 0xfb81a052, 0xec135a68, 0xb4ba4f86, 0xac9e6ae4, 0x3eb237b5, 0x8ad94276, + 0xb3effc8f, 0x53050db9, 0x691828b4, 0xceea3129, 0x4a598afa, 0xea1a119a, 0xa9a652d6, 0x0b01df90, 0x88c5f726, + 0x9f86b02e, 0xf22481d7, 0x7e3cd44c, 0xa50a1a2b, 0xddaf819c, 0x41a8deee, 0x6cce731c, 0x0333f76c, 0xed730a55, + 0xfb90fa91, 0xba16eea0, 0xcf32e541, 0x53284b88, 0x659847ac, 0x1b3e5e43, 0xbca97511, 0x142e7eba, 0xe932dd17, + 0x61c1885d, 0xafbdeb08, 0x12d6c0ac, 0x2571e966, 0x3f1ba1ce, 0xd0fc40cc, 0xe2239677, 0x711d66ba, 0xba8ccfdb, + 0x9f70c857, 0x44c27893, 0x4ba29ed8, 0x2a37d5e3, 0x8769cca2, 0x733291c2, 0xbdd11a93, 0x5770c784, 0xf767f32e, + 0x8437ed1e, 0xfa4a87cb, 0x58d2857a, 0x069b1c6a, 0xd23040af, 0x51b2d14b, 0x2583cf36, 0xe58c12a2, 0x46745a01, + 0x3892f982, 0x21cd62b9, 0xe748b814, 0x38f9b02a, 0x3c321801, 0x9d3291df, 0xded914b2, 0x81ca2e97, 0x6fdc15dd, + 0xe7769a24, 0x40a02c8a, 0x3bda227e, 0x797314bd, 0x61f41632, 0x64dcb60b, 0x0d5042c5, 0xccb4997e, 0x6bad19ff, + 0x3ea2cbee, 0x7c718042, 0x229d48da, 0x12270343, 0xb34c047f, 0x31b74ea4, 0x90832858, 0x0ef55aa1, 0x118a78db, + 0x76061072, 0x6af6d2a5, 0x78905cd9, 0x37a12fb0, 0xd171c5b5, 0xcc36afcd, 0x9cbdcca0, 0x5133b617, 0xb48c53ce, + 0x2f9875b7, 0x75971246, 0xd30c180b, 0x7df5d7a8, 0xeb1fad19, 0xcf74dce6, 0xd3b2fa7b, 0xc101628a, 0xaffc0c7e, + 0x10b6ece1, 0xfa472fca, 0x887828dd, 0xf1417cbc, 0xf12d666b, 0x1d56db1d, 0x2be17e3d, 0x04a50934, 0x8655399e, + 0x58be4ab5, 0x02f3d6bf, 0x6df3a93b, 0x562121be, 0x0d58cac9, 0x1321c3a7, 0x3e30dfa8, 0xeebe7769, 0x05910a19, + 0xca480bb2, 0x17d721b6, 0x925fa13b, 0x594fcadf, 0x6241f54e, 0xde15cc68, 0xbda0e70a, 0xa3c66ce6, 0x6fdf8efd, + 0x3bf60834, 0x4f1948f8, 0xcd4f4697, 0xed31f8af, 0x5b809e85, 0x8213353a, 0x7b58bdfe, 0xe27e809d, 0x9be0bf3c, + 0xdeb44029, 0xaf69de02, 0x72cc8b45, 0x2654d5d7, 0x32d6cd88, 0x8d31aded, 0x694287cf, 0xd3fe79c5, 0xc3d54fd3, + 0x187849ba, 0x8d95c2e3, 0xd2c8db28, 0x1243cd0f, 0xeb626e6e, 0x94422542, 0xcc4a1714, 0x806b486c, 0x7f02bd27, + 0xec44b82b, 0x47f768d6, 0x38876a68, 0x3d6b2755, 0x23c90089, 0x778b5041, 0xf92d1b93, 0xf41bd75b, 0x34e05095, + 0x3bacbffb, 0xa284f7e0, 0xccd0cf0d, 0x02d14f31, 0xe55cba37, 0xad9afb4e, 0xbc80120c, 0x4cbad547, 0x5bb3854a, + 0x9a874002, 0x2103ab30, 0x55c69e68, 0xc6fe5d84, 0xadcab260, 0x2e081f13, 0x5a1a7c07, 0xe56ba6bd, 0xaf427b82, + 0xc090fe3f, 0x45528749, 0x312ba7f8, 0x8c805d33, 0xa227eaeb, 0xb0f066c5, 0x84a2ad1b, 0x47871805, 0x7ea27172, + 0x48c6a19d, 0xbf209a6b, 0x63bdf5b4, 0xa1c71cb0, 0x3ca65888, 0x2f3a229a, 0x3df652fc, 0x694b04fc, 0x455d0ded, + 0x0f2ae3c9, 0x17182ad7, 0x1a2a34ee, 0x3ce18261, 0x4e635740, 0x50ce4e03, 0x4eba245c, 0xbe0bc62f, 0x45d996f2, + 0x585064f5, 0x00ce5248, 0x56e12d93, 0xb5fb144a, 0x2737c92e, 0xc77194fb, 0x960fc692, 0x730cee93, 0xa6b9e7c9, + 0xdcd03824, 0xf7192903, 0xedb29130, 0xd119a0f8, 0x4f86cb39, 0x3149c604, 0x52ae03bc, 0x146c32d6, 0x3370c6fb, + 0xdfbed279, 0x5cfe3605, 0xdacf8c6c, 0x123047a1, 0x632294fe, 0xc472053e, 0xb1793301, 0xe9e61e0c, 0x8158ba58, + 0xb429551d, 0xcbf8277a, 0x09f958a3, 0xe328d41a, 0x346d3754, 0x7e2a5a56, 0xa1c72a48, 0xd88b721e, 0xc0b7dc3c, + 0x5a13f0fb, 0xd1415a12, 0x625a9a27, 0xa679aa65, 0x703cdbc5, 0x8c7494e0, 0x4bb12ccd, 0xfd9f1cd4, 0x2ada4b83, + 0x0e3fd3c6, 0x5f0b0413, 0x21f824bd, 0x4fa62eee, 0xc154faaf, 0xb34a5651, 0x32e441a6, 0x2800cda0, 0x1cd51733, + 0x173238cf, 0x626109da, 0x351def60, 0x15e3efcf, 0x61215d72, 0xb3895ab6, 0xa69bd320, 0x446904cd, 0x2f5ce2ef, + 0x334e4314, 0x6ccbe11c, 0xfedaf845, 0x454bbd93, 0x83446e65, 0xb6d78738, 0x53795cbd, 0x8f5cadcf, 0xf7994a3b, + 0xd9ee0c54, 0x6a853e4e, 0xecd35d1e, 0xaa74322d, 0x3dce5d95, 0x7adef1da, 0xff83ab2a, 0x11b4d30b, 0x98ea0c7a, + 0xeb9a7e44, 0x67b52468, 0xd2f51c9a, 0x442289f7, 0x7028c171, 0xe153a03c, 0x4072e7d3, 0x493c7192, 0x41e8328d, + 0x7ea5b156, 0x1c7fab62, 0xb8f95087, 0x580029a6, 0x5e76dd98, 0x104ccb13, 0xa38e66ef, 0x3694cd0a, 0xddda4c44, + 0x6d032c02, 0x405f1a85, 0xaff8ce48, 0x8e671d2d, 0x31bd0fbf, 0x23214f36, 0xe606bd22, 0x23c09df9, 0x348f3164, + 0x19ffe734, 0xd0855c1d, 0x230c0e60, 0x5d3ca47e, 0xe7327e6c, 0x352450c8, 0x882790f7, 0xaabc8d12, 0x734e58c2, + 0x64c01f18, 0x6402a5da, 0xb3d0d063, 0x298c919e, 0x2e6e2264, 0xefcc0cbc, 0x17ab99e8, 0xe8b90af3, 0x0e7323d9, + 0xc6098dd2, 0x12131e7f, 0x814ac380, 0xad898182, 0xd41fcdc5, 0x55d52217, 0x5bdb0fc4, 0xa95badf6, 0x87880ed7, + 0x705cc99d, 0x54ad774c, 0xf37ab2dc, 0x8a6ac980, 0x1c3bc917, 0x59fe6d51, 0x7c483876, 0x8b863007, 0x3c2dfb29, + 0xb3e6aba5, 0x08558f45, 0x5610d58d, 0x598288a2, 0xc2498b31, 0x61e12c27, 0xea1b327f, 0x884d171e, 0xcfc29900, + 0xd828a733, 0x6a28a259, 0x10fe4477, 0x777bb116, 0xb4448404, 0x114a9b2b, 0x42c3bde7, 0xd87bf744, 0xdfd22d04, + 0xea435c5f, 0x26588d0f, 0x6ef9a29d, 0x7876928a, 0xeaaa3e81, 0xa101534e, 0x7b033484, 0x887bceb3, 0x20aa0e6b, + 0x19fa5eea, 0xab9d4b7a, 0x21119cd1, 0xdf50fa3e, 0x34ce2abf, 0xa2337e77, 0x91981b9f, 0x8b2407dc, 0xa2c6dde4, + 0x799dc046, 0x8d19450e, 0x0a9b6203, 0x6fb6554c, 0x0a56df85, 0x108a0b02, 0xcf81e2e7, 0x27083741, 0x6fc64aaf, + 0xe8d7afbf, 0x0743a809, 0x960f49fb, 0x1394d147, 0xf4ecfffe, 0xff877560, 0xcef33b60, 0xc7a46f44, 0xfdbf5f08, + 0x67ce6ca2, 0xbd24ba56, 0x599e32d9, 0x25cfde72, 0x2b9f54a3, 0x52691487, 0xf41a47d0, 0x7df8a489, 0x849458b1, + 0x43a15c33, 0x42af701a, 0x809d0a10, 0x0fa4a0cc, 0x1ad1bd76, 0x8bd5245c, 0x8125159d, 0x5d012b99, 0x4fdd6878, + 0x157b33e9, 0x15fd8c68, 0xe779ff33, 0x5d6d6085, 0x044f3f78, 0x33568790, 0x0cf1ea08, 0xee8d7f73, 0x9cc9ef09, + 0xcc8393bf, 0xe5a4bd89, 0x8d8a224f, 0x217f118b, 0x00170aaa, 0x1b53882b, 0x4e691ca9, 0x1234bab6, 0x5646f44a, + 0x766e941a, 0xa6c57541, 0xe509153e, 0x1646d64b, 0xbc6675ad, 0xcb8f9a91, 0x73602fd4, 0xacd35cf1, 0x8b68dd77, + 0xc6a6fca2, 0xc580507f, 0x29e7b2b6, 0xa10173e0, 0xc5893c4b, 0x17ed73f9, 0xea8074b6, 0x6e7b155a, 0x68ce3188, + 0x1012e3da, 0x5b297448, 0xccccd296, 0x84f3a3bf, 0xcbbd9980, 0x46e60d2d, 0xf092ccde, 0xf695602e, 0x9cd0b07a, + 0x27c467d9, 0x8035178c, 0xdebf27b8, 0x77a6616f, 0x0c072a11, 0x3b09c555, 0x7ebb1339, 0x3df375e1, 0xd043fecb, + 0x4389b087, 0x35ea5c0e, 0xc9d82846, 0x43ac494d, 0xde5be2a7, 0xed0f6734, 0xa9e48d65, 0x318428a0, 0x51d7cb53, + 0x325cc6b8, 0xd780f954, 0xfe08cd40, 0xdeef1636, 0x36d5a352, 0xc3e1a66b, 0xf8dc395f, 0x5064ae9f, 0x793fec84, + 0x8778291a, 0x3ac1de37, 0xdd2970f0, 0x9f73d579, 0xd85f9866, 0x81562c18, 0x89e61889, 0xce28b41b, 0x0b1848b9, + 0x6b41d428, 0x0abc3764, 0x9037a7f5, 0x86aff87d, 0x07f319fd, 0x755522ba, 0xd315fd78, 0x388812f1, 0x62157647, + 0xe4caba74, 0xe0373726, 0x718c8bea, 0x083cf3f2, 0x58b8c22d, 0x4e2a6a9e, 0x0abb4d96, 0x54113b24, 0x6242bb46, + 0xc6127155, 0x8e7f0d71, 0x432dadd4, 0x79d0db4a, 0x85f764bd, 0xff88d9d3, 0xcc38ee75, 0x933ef9b3, 0xc6fc4a4b, + 0xbbf3a0ad, 0x87f7f33e, 0x4cf9eed2, 0xb909a123, 0x6e8823a0, 0x4f690430, 0xe52e923e, 0x915ced7e, 0x30d06dfc, + 0x90aa21e8, 0x4c1709a2, 0x5c869a6b, 0x3b6cd137, 0x9b65b509, 0x541ed4cd, 0xb2c96c02, 0x8d8249a6, 0x0c3b0719, + 0xde9ac4f8, 0x5422aca0, 0xb2756d26, 0x8f291839, 0x9c17af4e, 0x8ffb0516, 0x42d836a0, 0xf8a04fd0, 0x7220cfaf, + 0x8b7ce968, 0xd9a42e85, 0xc5d9ff5b, 0xc12a2662, 0x205f263d, 0x3766ceef, 0x74fa700f, 0x4de1b0d7, 0x533c9ffb, + 0x9490d0b7, 0xfbbe3af4, 0x5cfb933b, 0x4278f52a, 0xa04ec624, 0xd7932b2b, 0xc24d87df, 0x28e3e668, 0x50524788, + 0xfbbfe90f, 0x2548f8ad, 0x1ff0dd66, 0xd3302105, 0xf84aa42a, 0x4f85f9f5, 0x12bcdb51, 0xaf4a5d47, 0x187d25bb, + 0x59d3b7ae, 0xe1c438c8, 0xfff3e8af, 0xee18c4b4, 0x4fd5fe17, 0x7c6877b7, 0xedd18e8f, 0xbd6f025e, 0x1e795045, + 0xc1159b43, 0x759d2d41, 0xb8959b36, 0x6eefb4a2, 0xc6734e17, 0x35dbe012, 0xcbef731b, 0x65c88750, 0xb6bed631, + 0xa5a23396, 0x9b8df56e, 0x9f28ce67, 0x16333ebd, 0x363588d7, 0x91e64863, 0xb0414979, 0x8593ff03, 0xbfec750c, + 0xe9b3134f, 0x539a2248, 0x9a4b1325, 0x4ea5cd7a, 0x3a263165, 0x257d1af7, 0xf96c31df, 0x5c7aa0db, 0x665aaa7b, + 0x1d37173c, 0xb838171b, 0x09625b51, 0x10ec7aec, 0xca9a0fa1, 0x1b10379b, 0x8a46762f, 0x9552a4bb, 0x67d65086, + 0x34d3b3db, 0xe13fb3d7, 0x76cb0cdb, 0xed45beb3, 0x6f9e3082, 0x56503682, 0xea4e252d, 0xc7d69759, 0x95d112a0, + 0x30084fd4, 0x624a6571, 0x055634c5, 0x511b7a34, 0x079ba77e, 0xdce600a4, 0xe0fb2e28, 0x6660064d, 0xcf884d24, + 0xf5591a3a, 0x231a444e, 0xfdb60e52, 0xd86ba859, 0xae57a691, 0x11ad0b01, 0xe1c02d5c, 0xa683c2ce, 0xacf23676, + 0x9dc574fe, 0xd3d0e083, 0x6bfa0fe9, 0x81cbfcc2, 0x9d22f7f4, 0xe47e73bd, 0x0f59a327, 0xb1cbd8bb, 0xf09164ec, + 0x9b27be0a, 0x82a76c4c, 0x8a697d7c, 0xbe3afdfa, 0xa9badc5d, 0x452951fa, 0xb5ef471a, 0x2f6d6357, 0x5b45d3ff, + 0xcfa87855, 0x5d167958, 0x1926d703, 0xd17589d3, 0x612ac893, 0x4dc8c722, 0x86a34604, 0x0b086aa3, 0x60172633, + 0x56d94b6a, 0xa2ff1b4b, 0x89a36a0c, 0x9bcb9dd7, 0x4d8a3f47, 0x2740d452, 0xc91dad62, 0xe584558c, 0x6d81ffad, + 0xef1bdc23, 0x7220de7e, 0xd00dc738, 0xf46114d5, 0xa279706c, 0xd0180d43, 0xbf526019, 0x4704a786, 0x5149ba3a, + 0x02787993, 0x08e9d155, 0x0ed8f29f, 0x7bdc49b9, 0x47396a32, 0x1d3f92df, 0x752d7514, 0xbbb5614c, 0xdf414afb, + 0x09aa660c, 0x26d0dc0b, 0xed93dc54, 0x9d0d2ce1, 0x9a9b2bff, 0x32d93bdd, 0x19ffbad2, 0xd78ff0f7, 0x37004021, + 0x78ab3345, 0x12fa1e4f, 0xa06f1db2, 0xb244b1a9, 0x2b33853d, 0xf9254d63, 0xa856da13, 0x4b7d768a, 0x65d80768, + 0x91691dff, 0xe3791489, 0x29da84e9, 0x4014ec93, 0x2d5a7f56, 0x5740b417, 0x4c9b32f1, 0x4a48391e, 0xd73ba5b0, + 0x922cb789, 0x4e176dd7, 0xdacf7547, 0x94c1f943, 0x377033b9, 0x9659dbdf, 0xe59feaac, 0xb2f00b4d, 0xa6949143, + 0xe555aad6, 0xb5f88ca0, 0x95de8bd3, 0xd791bc3d, 0x30ad501b, 0x87bfe87f, 0x4afbe65d, 0xf14ff8a2, 0x72c0d8ef, + 0xa38407fc, 0xdd2d936d, 0x395e76df, 0x7bc82179, 0x27c1ac03, 0x041e444c, 0x6ea3dce9, 0xd4f59724, 0x56b80f91, + 0xc047fe23, 0x88dae323, 0x5ad95096, 0xccd5411b, 0x23a49fe0, 0x779b6cc8, 0x768435da, 0xcaa48fd5, 0x1f88734a, + 0xa4f60be0, 0x4cc245f5, 0x985ebce1, 0xfcd41303, 0x82b804a0, 0xee9974aa, 0xd19851d8, 0x3c79a821, 0x9af55b5e, + 0xd54fff7e, 0x45afe8a5, 0x02deba63, 0xfe092288, 0x20bc6ffd, 0xdff8fbfd, 0x03bcf5b6, 0x23aaed56, 0x110fd603, + 0x371c36de, 0x99ee4f2d, 0xc9f7e2f4, 0x0c066f3a, 0x027a8818, 0xbde2ac0d, 0x270b5c0d, 0x9787bb26, 0xed6e372c, + 0xde58bdca, 0x29755193, 0x66391e69, 0xb38ad0c5, 0xac1b9b4d, 0x65def332, 0xa20f7a41, 0x341767f5, 0x4aea52da, + 0xd6c697ed, 0x01701351, 0x039dcb57, 0xdb142059, 0x15e3eb64, 0x035f77d1, 0xc167e531, 0x32b1bdb4, 0x53d15f60, + 0x7cc08f00, 0x7d357747, 0x47d10d26, 0xce525fb0, 0x1f6dc280, 0x10aa461c, 0x725126f4, 0x29853a0e, 0xc9060a60, + 0x9db0a6e3, 0xb217c990, 0x0d4c59de, 0xfb9bcecf, 0xccadd1ee, 0x25436828, 0x582b0c26, 0x79616fb2, 0xf06a791c, + 0x5c14f7b0, 0x378a975b, 0xc54dc98b, 0xd084c200, 0x880488bb, 0xd13b8459, 0xb1b847b0, 0x28a7198d, 0x5f1fe198, + 0xb959db03, 0x3dd2163b, 0xbbc5102f, 0xdfff17b4, 0xc15c1c9d, 0xaea01a91, 0x03f8681c, 0x603be6ff, 0xe3403d13, + 0x77b2676a, 0x0f5c2d49, 0xaf21c7c6, 0x1dfc914c, 0x2d519616, 0x1ceefa16, 0x59c2addf, 0xb73ba333, 0x59b02a4e, + 0xdb847510, 0xece038f6, 0x7bae174e, 0x9ece31be, 0xf65817e3, 0x1b6a3996, 0x74e25e29, 0x521cdeb3, 0xabde4e93, + 0xd6f86c1a, 0x7f353a43, 0x0f2dc7e9, 0xe095add9, 0xfd22679a, 0x874bc801, 0x9b2dccfc, 0x1bfd6ccd, 0xd4d3aa73, + 0xdb7ce132, 0x9dd8bc7b, 0x6f19751e, 0x755a092b, 0x764932a4, 0xbdd47cd2, 0x5e0710b0, 0xae6ec399, 0xbb3c2e04, + 0xbb1293b7, 0xa2e0c14c, 0xdbe20c6d, 0xb3215934, 0xa5029887, 0xcbc7c62e, 0x8eac8dcf, 0x07d93377, 0xf64f5068, + 0x395216a3, 0xee1e6913, 0xf029105b, 0x3349fea0, 0x4926d8e6, 0xacd1df85, 0xd6a4390b, 0x3bf83876, 0x46f210e0, + 0xe7e26e7e, 0x3fe842a4, 0x2aa27798, 0xeceae58c, 0xdc17a598, 0x3a6bab1d, 0xc791cd60, 0x3dbe7432, 0x113b9e5a, + 0xac98e3b8, 0x8dd1c600, 0x8e2646fe, 0xe0a537df, 0x3fd269ab, 0xc5d250ce, 0x80f7a473, 0x20f710d3, 0x651f3190, + 0x977c71be, 0x62bbf2ea, 0x83640531, 0x5d43aa61, 0x9f53c97f, 0x6e736b39, 0x5fa1f284, 0x5edc7c87, 0x4f50a62e, + 0x1c4c32f9, 0x4a2aae04, 0xdcd52eeb, 0x1a6386c0, 0x430436bb, 0x6f538eb5, 0xc36d0126, 0x35ddabd0, 0xe6a40a48, + 0xb8de756c, 0x59875371, 0x154c68c2, 0x6c65701d, 0xdc5272c8, 0xd7db373c, 0xd5ee226d, 0xfbde3d85, 0x42b6199e, + 0xac5deafc, 0x57cd6abb, 0x5912c84d, 0x1f16b17f, 0x194678aa, 0xc06436d2, 0xfb0261e5, 0x87a5a0ed, 0x84434f33, + 0x0213c476, 0xab8e38fa, 0x883cb230, 0xe038542b, 0x84f3c916, 0xed3de79f, 0x8a711a72, 0x87cf2b40, 0x715b1640, + 0x5eee4735, 0xfae40599, 0xc181fb86, 0x2b014af0, 0xf70dc23a, 0x8d136dc5, 0xe7275e1a, 0xa4e80b6b, 0x1d09146a, + 0x54b0d030, 0x942024da, 0x53500efc, 0x06a40763, 0xf8b3b095, 0x1d543f71, 0xf80f16dd, 0x05b97c4c, 0xecd06544, + 0x2c874db1, 0x38b5edae, 0x5ccf0c47, 0xd9a3c268, 0xef746be7, 0x6889edfc, 0x0889405d, 0x03925c89, 0xbf7eaabd, + 0xcdbe9b77, 0xc7a64dcd, 0xe84e0afe, 0x9599f776, 0xa131163e, 0x1fc2f85c, 0x47db81c9, 0xf539eec7, 0x80169bb2, + 0x8fcf3ba1, 0x116b9347, 0x6437ecf0, 0xf63cf79c, 0x10295a32, 0x3d61c1ba, 0x7ec86f76, 0x1f0f006e, 0x27f30b5e, + 0x9600b9d1, 0x31722edf, 0x212dcaa6, 0x11a3581e, 0x416753a1, 0xfac70b3d, 0x24e7ae8d, 0x2e03698b, 0xf76b4620, + 0xca9f66c5, 0x36a831b7, 0xa4ff343a, 0xd1eaa176, 0x6e438c53, 0xe6d90040, 0xc7f0e3c2, 0xfa2abcbe, 0xaf6a814f, + 0x5f4884a0, 0xe9574eb3, 0x664ceff2, 0x2372c581, 0xb1f10685, 0x97cd95e3, 0x641b2307, 0xa8253af9, 0xa8dfa4ba, + 0x7bbcf513, 0xdc41c4c8, 0x8c428d36, 0xf6144d61, 0x87ac40e6, 0x073cfe93, 0xea0be995, 0xef063c90, 0x1623ecfe, + 0x6cd8a159, 0xea603d1a, 0xca926c72, 0x6a9ad1a4, 0xbd521dd8, 0xbf75a334, 0x26002cc9, 0x22007cd5, 0x87c2ec0f, + 0xef1fad1a, 0x970271c7, 0x8d888fca, 0xc059673f, 0x20daa5f9, 0x8a973168, 0xbbfa8fab, 0x3b88a5a5, 0xa542f0a1, + 0xbf710865, 0xb8d86ff0, 0xcc130019, 0xe434e990, 0x83429106, 0x34935fef, 0x40ad31c0, 0x2390ce2f, 0xb50f61f2, + 0xc4a7c3d6, 0xfbc3c082, 0x7a289f27, 0x37c95061, 0x9f442b01, 0xc7bd29fa, 0x4898a02a, 0x0782d07d, 0x6bef194b, + 0x4bc96bc7, 0x3423b63c, 0x97715d20, 0xa38d1c59, 0xe9863642, 0xcb5cc72e, 0xd75523b6, 0xcc2d10ea, 0x8e470ec6, + 0x36e960c3, 0xc7ab7cf5, 0x17e63c63, 0xf043363f, 0x2fb66db2, 0x20666956, 0xfa2c3fdf, 0x20d3fb75, 0xd025781a, + 0xa229543a, 0xa415f1a1, 0x57559eed, 0xd8ba05b1, 0xe646e19b, 0xc3556ca1, 0x0db2cf85, 0x9b8208bf, 0x1f711417, + 0x5143aee3, 0x9b3359af, 0x65052cc1, 0xd4d435ce, 0x33eb3df3, 0xa14c6991, 0x3315d373, 0x1c217f91, 0x99068f87, + 0xb7aaaebf, 0xe112faff, 0x63ac2dd3, 0x40eb5f14, 0x7df9c2c7, 0x568e36ef, 0x1806c67f, 0x3b2f20fc, 0xd96e01d0, + 0x9297ebda, 0x62ff088c, 0x20d7351b, 0x376de219, 0x95826491, 0xbb1edb81, 0x6fcc07fe, 0xafe7eb12, 0xbb92d5e8, + 0x09a7e446, 0x42d3d366, 0xd539da61, 0xfd58393e, 0xb7007632, 0x7c1ef569, 0x5ba75855, 0xe290b3c3, 0x4b2071d8, + 0x7cae50ea, 0x043de6ef, 0x6eedb026, 0xf15fcd41, 0xc2cee38a, 0x5e048589, 0xb9521a85, 0x84d60ea0, 0x7e4a5518, + 0x47defb3a, 0xb9dd4705, 0x21dc8b75, 0x978d146d, 0x84a23aec, 0x1e482677, 0x51aff38f, 0xca086849, 0xb25f32a1, + 0xaf07d90d, 0xe75d61bd, 0xfd524d06, 0x85b2c766, 0xa4c972d9, 0x1d77f972, 0x38d755bd, 0x2a662d18, 0x97d9352f, + 0xb040b063, 0x5dad84c7, 0x08410d34, 0x83ec5e0c, 0xa1406779, 0x2ff16e82, 0x27f411e1, 0x12bc28e5, 0x489d9196, + 0x5bfd1aeb, 0x9a067c0c, 0xc47dcc5c, 0xb6f1c84f, 0x687d011e, 0x1e8c0fdd, 0x173037fb, 0x8e55fc1c, 0x5d6a308d, + 0x55f7e56b, 0xd2f0d5d5, 0xaa5c44b7, 0x11d427d0, 0x2f1b1456, 0x2f50302f, 0x180d94e0, 0xa0322e9b, 0x6b956e1d, + 0x6f87e517, 0x44b2958a, 0x8f2c050a, 0x3d547881, 0x76292c8d, 0x9526297a, 0x03415176, 0xaac63945, 0xbe0c72d7, + 0x4af94c8a, 0x12a84a59, 0x18a0b2a9, 0xc8e21519, 0x61692470, 0xfd318d34, 0xda57b204, 0xb91e9d90, 0xa8101e88, + 0x29be7236, 0x8d1f0178, 0xefa47290, 0x5b21f712, 0xcacf98a6, 0xa828942a, 0xb8d45902, 0xac1959b3, 0x7b53a224, + 0x5a9680aa, 0x520f5886, 0x804285c3, 0x1398c793, 0x75eb3ed9, 0x863f0767, 0x8ce8c71a, 0xf2c7d1f8, 0x3d02cfd4, + 0x45c1f4b7, 0x110a2b3b, 0x6b92a265, 0x893fab6e, 0x2e8bac1c, 0x0afa0a8f, 0xf5bfc9aa, 0xbfb447fc, 0x60948c35, + 0xf9514079, 0x7b5c9c3d, 0x2c7c50e6, 0x096458a1, 0x45af204d, 0x71421183, 0x25fb058c, 0x344488f4, 0xcb7a4327, + 0xe5ea88f2, 0x36bde928, 0xa33c4afc, 0x7be6a8f5, 0xfef30645, 0xe952ace9, 0xea8c5475, 0x162a9576, 0x96694665, + 0x7a9a31c7, 0xe2ae7350, 0x355b6ad4, 0x342f059c, 0x72b8bd4c, 0xbf826c8e, 0x830e0822, 0x2e255099, 0x0d0ada17, + 0xc4fc5455, 0xd8b04522, 0x523342f7, 0x9ef83b2a, 0x38b889ce, 0xc17c1edf, 0x064409a7, 0xe35e6dd2, 0x2e225328, + 0xdd7211a4, 0xabb3ba2f, 0x834d0adf, 0x5e3edae8, 0x321d9479, 0xc9e2e260, 0x39a99b54, 0xb55af6f1, 0xf815d323, + 0xebe23156, 0x2a9da7ef, 0xa8736703, 0xfd37b7c0, 0x71a6b39e, 0xe75f149f, 0x26b573ed, 0x463716b3, 0x54120ba3, + 0x5249b222, 0x5b127a03, 0x20ff7f9b, 0x5baf20c9, 0x44c61186, 0x6610623f, 0x1106d8db, 0x38bc40c0, 0x771d6869, + 0x002c6419, 0xad961e9e, 0xfb55cb80, 0xcb5a0fa2, 0x2b20dd5b, 0xcad73d5e, 0x71edf877, 0xc0225f00, 0x8148cead, + 0x4107752c, 0xd86ac938, 0xb56a5db3, 0xfa4b42f6, 0x336b2771, 0xceb72f1f, 0xa21ff934, 0x8ab9e2cf, 0x7f0a5e2d, + 0x537807ad, 0x3ba9aa40, 0x7d3bd05f, 0x3e08361b, 0x703abdde, 0x45b36c7a, 0xad93c543, 0xca5b9245, 0x7a82fc4b, + 0xf8110772, 0x99d8dc53, 0x133be992, 0xab96c53f, 0x6b3039a2, 0xdf372a33, 0x68053516, 0xf52cd0b5, 0x0cc16866, + 0x7f343919, 0x371b98da, 0x11054b4d, 0x91603665, 0xd133f591, 0x51450aa0, 0x7a013368, 0xc919dd55, 0x2f86f53c, + 0x9d623137, 0x904f6814, 0x45ba3ffd, 0x6a07d437, 0xac4f4878, 0x49249991, 0x80a88008, 0x70a55556, 0xd5be4d0e, + 0xffd0ca13, 0xc2f23fa6, 0xcbb11c4e, 0x201ec13a, 0xf8dcc677, 0x8d139c85, 0xa2bbc5a1, 0x11559fb2, 0x3a6673cc, + 0xfb752565, 0x837d6d3f, 0x7d9e9067, 0x56ce205d, 0x4e37bcb0, 0x817aee2c, 0x3618f493, 0xd473e5d3, 0xbb1f0feb, + 0x02ffee41, 0xdf7747ea, 0xd5427188, 0x0ffc7a94, 0x4a552e77, 0x6ba11d69, 0x545593ac, 0x30f88764, 0x4b84884b, + 0x4eb47677, 0xab0f6bf3, 0x6be5c454, 0x100e357d, 0xfb932c9d, 0x783f2d83, 0xce8d4b35, 0xe979ae3c, 0x3a9202b3, + 0x502bdeb8, 0x48b6cfb6, 0xa43a12f6, 0x7ecd2ed1, 0xa0e81476, 0x360137c1, 0x52c323bb, 0x393a9b93, 0x92b01a60, + 0x028277c5, 0x6da670e9, 0xf3c45260, 0x02397769, 0x0c820615, 0x806d4ded, 0x70615f4b, 0xfe64f030, 0xc744b37e, + 0xb3fd7a8b, 0xe1c29fe8, 0xb315d5d8, 0x70b7ccb4, 0x513f2af6, 0x2ae5ba6c, 0xd950fa07, 0xf609c1bb, 0x048f9d86, + 0xad56c700, 0x74992b3c, 0xc6df6091, 0x476dca92, 0x81243399, 0x1316052f, 0xe46787e0, 0x5b311e7d, 0x81723c94, + 0xb5a9c47a, 0xe1c2f63b, 0xa0f92ed7, 0x79f8ff0d, 0x1dbed4cf, 0xca1c4369, 0x3b70888f, 0x30b85fa1, 0x3d3c5880, + 0x3ffb4193, 0x019809d6, 0xad626a88, 0x23381895, 0xa0e3d559, 0x7e1f544f, 0x8232a08b, 0x2b353223, 0x7eee7f39, + 0x7de804f2, 0xa20b8f2f, 0x06c68d77, 0x2443befe, 0x14ec030e, 0xd17ed40f, 0x86c2c76d, 0xe19c52ac, 0x4ab9c9f2, + 0x0d67aa6b, 0xb878379f, 0x6b63dab4, 0x83c81785, 0xb9621e80, 0xfb7de5fb, 0xeddfeded, 0x7b3e07b4, 0x457e8fca, + 0x1dd0808f, 0x2ea0d3ee, 0xebb924e7, 0xc93895bf, 0x02d186fb, 0xf751312a, 0xde9e8585, 0xfac943ef, 0x5b53d8b0, + 0xc7b6bf07, 0x5a1c5f4d, 0xf932be7c, 0x1d34f323, 0x5baf48cf, 0x0e8ec245, 0x3cf597a5, 0x6958a135, 0xb7bd6ada, + 0x81dab2c8, 0xb83dfcca, 0x98c928b6, 0x32b2d315, 0xfe1eccf8, 0x82ac737b, 0x145df1e9, 0xa597792b, 0x43ecb242, + 0x0488ec69, 0x16074ec8, 0x293b42bf, 0x6200fdcf, 0x54770689, 0x5d1a0fb5, 0x0e691801, 0xe5b78191, 0xc74c8a2e, + 0x871f5394, 0x11011854, 0xb0f980b5, 0x244b19a9, 0xd94b8c57, 0xea137d2c, 0x2fa46efa, 0x50403163, 0x901ac7de, + 0xe0112c69, 0x6b1e3648, 0x24f359dd, 0x0cab955f, 0x3b02ec42, 0xa7c0cfad, 0x4a89701a, 0xa7dc1416, 0x6a0dfa2d, + 0x896b45d7, 0x9044f372, 0xf18b2ed4, 0xd48aaae2, 0xf0c2ee6d, 0x20c9603a, 0xfd28654e, 0x084052d7, 0x527d4bcb, + 0x492989f4, 0x18c6231b, 0x84a33979, 0xd9b121ec, 0xd0576207, 0xe9dd7114, 0xc3f1a655, 0x7595a4c6, 0x9a7e88e7, + 0x9e2bc9af, 0xb7592c29, 0x5202be9f, 0xa55c4a8b, 0xe7898fa7, 0x6c762458, 0x6f2ee4db, 0x7365f303, 0x61101865, + 0x39bbfe8f, 0x119fb643, 0x243754b0, 0xfbb8a8bb, 0x430564c4, 0x16e092c9, 0x2503fe0b, 0x724a3d90, 0x8ed52879, + 0x863a5fa0, 0xe9c9201c, 0x631104e5, 0xf5713933, 0xd3d9295e, 0x2a6619a9, 0xde02ad9c, 0x7e5d0991, 0x2ad7eb77, + 0xa8071f66, 0x726af0e8, 0x407f0624, 0x67edf876, 0xffaffbbe, 0x822525de, 0xfa1c3503, 0xeb11e2cb, 0x2f18d528, + 0x155adb14, 0xb52af05f, 0x5115e932, 0x7c4ef27e, 0x0998396c, 0x7820d95d, 0xd365448a, 0xa3c5d1fd, 0x8994869a, + 0x2a4e22e3, 0x6d000656, 0x6c634cee, 0x07007a2f, 0x4a288096, 0xc0688a93, 0x15249ee7, 0xdd256946, 0x9d40df9a, + 0x3a8f91a3, 0xb885d3f6, 0x1f3dac46, 0x1053031a, 0x01b2b98f, 0x90ab95fd, 0xd268a728, 0x44462fd4, 0x1a966c90, + 0xfbfa8e7a, 0x49c70de4, 0xc6b3c546, 0xd98dd053, 0x66cdad61, 0xe6913c58, 0x54674000, 0x7b6d4aba, 0x1221a09f, + 0x503d7f9f, 0xb79a6230, 0x24f1da99, 0xac499a42, 0x2cdb368b, 0xd04b034e, 0xf8153084, 0x43efd426, 0xf9cd5e86, + 0x17777635, 0x5b619e64, 0xa8049c31, 0xc3cb3072, 0x68940638, 0x44448826, 0xb1dbe8ab, 0x22a035c7, 0x56627a6f, + 0xfe36b13c, 0x0f181c06, 0x4fdd53e3, 0x63656123, 0x1e499055, 0x0b02831a, 0x4e5c7e54, 0x251d9e72, 0x224a31a4, + 0xec7f1f6f, 0xf4393727, 0x9af81d1d, 0x2050af30, 0xab8d4df8, 0xf4e6378f, 0xbb67a458, 0xfa7f9e69, 0x77e0b4d4, + 0xa954bdf0, 0xfbce49e7, 0x21044667, 0x26b76a82, 0x8655e7b6, 0xd563a56b, 0x8952f55a, 0xaaab2dc0, 0xf384fbc6, + 0x6f5cb4bc, 0x0675b0d8, 0xd48296c9, 0x8667b21c, 0xdb4c079c, 0xd0cf506c, 0xb4fca895, 0xedc1717e, 0xa7970757, + 0x3fc98010, 0xbb64a7f1, 0xa0d49e29, 0xdc0f33f5, 0x62c7fe23, 0x57c46201, 0x788c5ca5, 0x42b01e15, 0xaeaa6da1, + 0x34d42d9e, 0x274e2993, 0x341158c8, 0x5e876d8e, 0x196a8bd9, 0xda0c090a, 0x70899f4c, 0x4b8587ef, 0xbe451943, + 0xdcea5bd8, 0x67e5c91a, 0x167e1fa1, 0x6ab7705d, 0x3de932ee, 0x1e534a91, 0x2746de42, 0x9c193b73, 0x8c3a74e2, + 0x2da7fec3, 0x7174516e, 0xdc08c6f6, 0x3f16da39, 0x16586e12, 0xeec0e69a, 0x5fd8d3cf, 0x2a358889, 0xa78d0a36, + 0xfdfa103a, 0xc6f0bf3c, 0xbfbd840e, 0x5d229619, 0x2f7cd037, 0x3c823da4, 0x22fb0ed5, 0x5512c6a4, 0x48d06bae, + 0xc0a1a9c2, 0x729458ba, 0xb29517e5, 0x83a314d1, 0xa42441f9, 0x7c5732ab, 0x09c12331, 0xa5cec6ca, 0x0569cb5a, + 0x8c51a7ec, 0x5dcf2572, 0x1a603e41, 0xeda61287, 0x1c7bc18d, 0xcfcd0cb7, 0x9ddf10c6, 0xa9428d30, 0xdae16af4, + 0x83b8eba9, 0xb582e789, 0xb456d919, 0xd0094f25, 0x9f75bcf1, 0x952c8a59, 0xbebc664d, 0xdff89f9f, 0x0b63aaf8, + 0xfb8282fb, 0xa467e52f, 0x76086a8b, 0xac776f1a, 0x970aab3c, 0x06fe05a9, 0xe52cf746, 0x47c3c38b, 0x2b78c98a, + 0x8b873e4b, 0x9df7f711, 0x7b83d63f, 0x1ebc93fb, 0xdf620986, 0xa0e32614, 0x69e30c88, 0x1f1e1cfd, 0x73299015, + 0xccc0844b, 0x93e7066a, 0xe26de513, 0x1888e223, 0x6e1b1fc3, 0x22138e97, 0x4fa70338, 0x18856c43, 0x50185138, + 0xaa415775, 0xebc89e9a, 0xc1aaebdf, 0x0c2959e0, 0x081c5c48, 0x625f58b9, 0x022c84c4, 0x5e18fac2, 0xbd47252f, + 0x17f80b21, 0xe97501d4, 0x7875bbc2, 0x9dbbb6e4, 0xafcbcb4e, 0x8e9fb418, 0xe9632b91, 0x1738b022, 0xaed22f2d, + 0xa9bdbeaa, 0x9ea2e4c9, 0xddcff1e9, 0x4109ad0b, 0x78ca1829, 0x527787a9, 0x176f6fb1, 0x81cfce3a, 0x79545b8a, + 0xecb2bdf5, 0xe714b66e, 0x4cae8cc8, 0x474ceaa5, 0x640aafd1, 0x223b315a, 0x3ab9d5ee, 0x14c03289, 0xf897c546, + 0x6fe32260, 0xd94eb95a, 0x50406fa1, 0x216b016c, 0x0196d9fb, 0x252f1e7f, 0x78929fe4, 0x12d0a4cc, 0x7e8e8f1c, + 0xc9aa7893, 0x1f68c058, 0x6c977ae8, 0xf8feffbf, 0xc5fe06b8, 0x8cb5d532, 0xc229493d, 0x0eceab29, 0xb93dd72b, + 0xd6c43c10, 0x42986333, 0x4539d5ed, 0xe0936c0b, 0x40c75bd4, 0x81883c00, 0xd1915fe2, 0x232342f4, 0x496f0773, + 0xba71878d, 0x896689d5, 0xeb76e23e, 0x674e0ab5, 0x744e194c, 0xcd755f28, 0x0e916475, 0x4752f41e, 0xec821031, + 0xb24ed432, 0x13db975b, 0xce59fd6a, 0x57e102aa, 0xa79a45c6, 0x065d21ca, 0x74206c0f, 0xf83c6e2b, 0xa5565f07, + 0x22fdf3bc, 0x5a965132, 0x482670af, 0x6415a563, 0x21cf9c38, 0x84ccefd3, 0x570722ba, 0x636e9424, 0x4c6a8136, + 0xed0eddf6, 0x1bc163ee, 0xfdb6d9da, 0x189e26c5, 0x5a508902, 0x0c9ce886, 0x7167d0e7, 0xb1a5ac75, 0x0bcca0c4, + 0x48b33c73, 0x45895874, 0xafb8f026, 0xea3c36a6, 0xd8cee696, 0xa67b18e4, 0xbf9ba69a, 0x0bedb920, 0x9c95d329, + 0xee0d08b0, 0x368fe1a9, 0xf3e89fe1, 0x55ec00e0, 0xaaa24a96, 0x9c2f6f0d, 0xf790386e, 0xc1cab53d, 0x3c970bd7, + 0x1ec5216c, 0x5bdac8d8, 0x975bfe1f, 0xbe89efb6, 0xe1d5e2a6, 0xb9a181ef, 0x3f9a293c, 0xa145893e, 0x790192d3, + 0x89114e3b, 0x242f069e, 0x9b7e21cb, 0xe1888b11, 0x049475e3, 0x2c372a2b, 0x64e26f8e, 0x7069315f, 0x695c2dc5, + 0xa4af47d6, 0x016edc61, 0xc58eb4c9, 0x1d41d19a, 0x3e4e5bd2, 0x87221960, 0x520c895b, 0x0581b16b, 0x2ef56096, + 0xdc53bb4c, 0xc61e3c55, 0xcd330a19, 0x6007edb2, 0x8a62ae16, 0x80cf9161, 0xbfec295f, 0x1693bbb8, 0x8b7568b8, + 0xed8aadc5, 0x448fc112, 0xf31462d9, 0xd6f4ad83, 0x3556518d, 0x9a1b7934, 0x0dd771d6, 0x8a92934e, 0xa4e51dc9, + 0x97c68c29, 0xb0bb4877, 0x0c63c726, 0x87802bef, 0xd0d0984d, 0x0924eabb, 0x981d34f2, 0x9405deb5, 0x036ccc2d, + 0xc1f15090, 0xdc3e8595, 0x902f33a4, 0x6a616d76, 0x27beda47, 0xf8f389dd, 0xc47f558c, 0xab354352, 0x264cf031, + 0x75e24aaa, 0x6aa059b3, 0x8ce98eed, 0x26772df5, 0xf75ac6a6, 0xb8c71638, 0x3ebb67f1, 0xc9927be8, 0xf9f84297, + 0xe09aec6b, 0x57ab3613, 0x08dcb3bd, 0x6ad9fe98, 0xb4db162d, 0x38878830, 0x91495579, 0xe1109e60, 0x644e1ad6, + 0x611d6752, 0x2b27ace6, 0x719daaa4, 0xbc152c4f, 0x79140823, 0x13829d6a, 0x96be92e1, 0x5e3f929e, 0xd3ed2f9a, + 0x46a967ab, 0x9098d8c8, 0xc2e7bca0, 0xfdcb723b, 0xb02f637c, 0x8dac2150, 0x183d9a16, 0xced9eaf0, 0xf11022f6, + 0x4d3de2f4, 0x11868c2c, 0xe52d5793, 0x9c9e69e6, 0x40793fba, 0xd2ce2a45, 0x2b57610f, 0x21a61f5d, 0x210341a0, + 0xd61da434, 0xcf3b5ceb, 0xf2a35687, 0x3b0ff58b, 0x9c61ea81, 0x89fdb740, 0xa53b58c4, 0x8a5ccdbd, 0xc13e335f, + 0xf27dfd22, 0x4734cd7b, 0xdf804028, 0xe7179244, 0x7177c0a1, 0x2c87190c, 0x01d692c2, 0xecd6fb2b, 0x15731464, + 0x5f89a558, 0x9f24239b, 0x735acc10, 0x55bcd612, 0xba4dfd80, 0xd866f6e1, 0x0b601e35, 0x2adf2320, 0x045a01e6, + 0x09feaffe, 0xaa5e2be6, 0x827d957e, 0x8d1cd997, 0xe0a8a4e3, 0x6364ab76, 0xcaffe160, 0xad3c965b, 0xb680519d, + 0x1f661cb6, 0xe9b3c3ba, 0x8979082c, 0xe35d10a0, 0xe715af86, 0x7fb83a15, 0xebf07dae, 0xcc0b45ed, 0xf7e0ee6b, + 0xc3d6e262, 0xa9239fe3, 0x2b1c27ae, 0xe8ceac38, 0xe9d514c3, 0x1d385cb2, 0xb1cbcbb8, 0x7ac6cf18, 0xfd39aaab, + 0x33950da0, 0x12692d77, 0xb95048ce, 0xe5caef6d, 0x587113a9, 0xdf408410, 0x687364ee, 0x35440561, 0x63dbe9fc, + 0x94f793c3, 0x30791b5b, 0xaf8776be, 0xb829a8f1, 0x182f7ada, 0xa2b94533, 0xb51499aa, 0xe223a63d, 0x1075f006, + 0x8e92c57d, 0xd9233c70, 0x54648429, 0x7b5dc536, 0xe0a125b7, 0xadc15f90, 0xe0d38685, 0x1a4e9909, 0xc6f471d7, + 0x5f60f1c9, 0xc84cb8f2, 0x89537966, 0xa84e821f, 0xd7174c05, 0x670372e5, 0x1084f0bb, 0xe3f07216, 0x20002535, + 0x35ce0c07, 0xc144f09e, 0x1e73efcb, 0xc7c55f9e, 0xbcbb008c, 0x213bc749, 0x0c8c90df, 0x28ec3f01, 0x66d88575, + 0xc0614370, 0xd3a0f9b4, 0x7389940b, 0xd4d1b92c, 0x40004adb, 0x6bbe7a46, 0x2022ce9c, 0x651bf9cc, 0xa4aaf451, + 0xe849c4da, 0xed3225a3, 0xc71cc242, 0x1ff15a06, 0xbcafb00d, 0x94008e4f, 0xee9d930c, 0x8c1fb832, 0xd69c87b7, + 0xe9d8541b, 0xba835a14, 0xdaad68ad, 0x74a4228c, 0x6a53c256, 0xa00fdfcc, 0x862184c5, 0x23e36602, 0xf44ef928, + 0x41380662, 0xdfa39485, 0xd81c1eca, 0x7e0f7bb4, 0x7a100aac, 0xead91b0f, 0x8b65a02e, 0x873c3325, 0xbf7679aa, + 0xe8e49065, 0x286cb9a9, 0xa83543cf, 0xfba6f89c, 0x24276a07, 0xbf505c75, 0xd5ca065f, 0x45f44483, 0xa964fd39, + 0x7230ef61, 0xc5671805, 0x9af8366f, 0x369d76bc, 0x77682089, 0x1abe6c43, 0xb1ecd14d, 0x2d8e7005, 0x19a21d14, + 0x5b811b34, 0xa6a3140f, 0x0fcc00f2, 0x8ac8f097, 0x84d53b0d, 0x299fdb7e, 0x074a7b07, 0x1c75241c, 0x10765390, + 0x372d547c, 0x24189575, 0xa9f48ed4, 0x00b3bce6, 0x6039228f, 0x6a8f4a25, 0x7e901c24, 0x75383e51, 0x3aed3e0f, + 0xa8e367ee, 0x0d979527, 0x904d9852, 0x0fd60c09, 0xf048e270, 0xf9ce86ef, 0x70af6dce, 0x3af08984, 0x3a562ce6, + 0xdf786b22, 0x0f81736b, 0x3147c1a5, 0x5f686ba9, 0x67bdc1f5, 0xde7b8a76, 0xd345cedc, 0xe3e72c45, 0x83617ca4, + 0xe34c5fed, 0xa0018678, 0x76343b9c, 0xe385ff33, 0x674c00fd, 0x5e358150, 0x92e04d6a, 0x291c61bc, 0x721b809b, + 0xcc1a61e0, 0xdc5a2634, 0xfa814d59, 0xfc0d884c, 0xee74a4d5, 0xfc5b69b2, 0x3c49f8f1, 0x7e08a56f, 0x5cace1d8, + 0x6cb50f63, 0x8ad000c3, 0xdb6d031c, 0xc3768f97, 0x42607c27, 0x0511283b, 0xa2d1218c, 0x64e84de1, 0xaf6a7f57, + 0x3f0bbe5e, 0x4d17941d, 0xc9dd87d4, 0x5f9365a2, 0xd6ceb7a8, 0x12150584, 0x1d037b16, 0x73cc45da, 0x5b6a7396, + 0x6c628dd8, 0x530d3ab7, 0x0c67d58b, 0xbb14c34c, 0x839862c3, 0xbd721e3d, 0x8ba5b348, 0x27e3b27c, 0xf047313e, + 0x4cf96611, 0xf2c307ff, 0xccacc367, 0x7159657c, 0xbafca79a, 0x44d87bc5, 0xd18bbb8a, 0xc9fa9fb8, 0x82ae06ba, + 0xc24f09fe, 0x2c1a7e90, 0x633fa987, 0x04a3b6f8, 0x36aa5928, 0xe23a8dc4, 0x7e41e1cb, 0xb588f147, 0x40bbd5af, + 0xcc713ac5, 0xaaee07ec, 0x841c666b, 0x35e0d182, 0x29708ef8, 0xc7f6f0d2, 0x8151b40a, 0xf8ac86ec, 0x3b5c1710, + 0xae6bd67a, 0x235fe38a, 0x75579dec, 0xad172ef9, 0xad4a7c6d, 0x5b29ee44, 0x204abc64, 0xc48457f9, 0x4404f92d, + 0x2c2d4a58, 0x9807d06b, 0x7573a424, 0xf09b252d, 0xf0c39e68, 0xa112b11e, 0x34c9a189, 0x5c7a6d3f, 0xc166b4d8, + 0x0b8972a7, 0x0a4a00df, 0xfc1fb297, 0x45ff701a, 0x9aa4c571, 0x69f95a45, 0xf75e6585, 0xd68db10c, 0x1c918589, + 0x536810af, 0x038f0a75, 0x1843a0c9, 0x479360e4, 0x46601990, 0xc7b19cc9, 0x366573c2, 0xa838e04e, 0x6c426efe, + 0x29335e90, 0x0e822e84, 0x50677ad3, 0xc30b0bb0, 0x53fb272e, 0xbe727b3e, 0x660c8420, 0xa43e4c17, 0x06d5da25, + 0xa088db19, 0x493ab767, 0x4763a279, 0xc1eec775, 0x6838cfd0, 0xc03d2254, 0xedd6d183, 0x239a2918, 0x58fd5ebc, + 0x31ab562e, 0xf064b93f, 0xefa7a932, 0xec5caacc, 0x5430e30e, 0x451b2a02, 0x25bca049, 0xf326c4b1, 0x9b8c34f1, + 0xd87a988c, 0x5cd78f2a, 0xb129cbaf, 0xed86d582, 0x6ef85a2d, 0x825f424f, 0x661cb6c2, 0x3289acd9, 0x784b9ff5, + 0xdf3115bf, 0xb6260e9c, 0xb115b641, 0xcede3cd0, 0x83cfb266, 0x8a2e0ad4, 0x288b02f6, 0x30ca8861, 0x5396f756, + 0x7e4ce221, 0xc203b3c4, 0x8ef774c6, 0xd7a017a9, 0x3e858988, 0xf7f02a6e, 0x228087e9, 0x03c79770, 0x7430bf80, + 0x6a3bdade, 0xdeb7af6c, 0x5718607b, 0xbffb03ea, 0xc436348b, 0x76f8cc9d, 0xb81cb9ad, 0x8253fcca, 0xd1df8ba9, + 0xb60a8eb4, 0x87b989a0, 0x38d89e88, 0x5d49ba5e, 0xba0126e1, 0xd615bb21, 0x72d76456, 0x0e79d356, 0x7d43555a, + 0x71a73e62, 0x0743e4ae, 0x14f632cf, 0xda183642, 0xb72f4bc6, 0x44fbcc15, 0x21ee123b, 0xaadc6e53, 0x86d593dd, + 0x704382b4, 0xb5775eaa, 0xd711a537, 0x771dee9b, 0xdaffb2a1, 0xe7c4f415, 0x60fb65ea, 0x33f36d4a, 0x34478585, + 0x46ac2c7e, 0x2becaf4f, 0xd665e168, 0x9b7c0169, 0xc0bb07ff, 0x851c4793, 0x8eae10f0, 0x44f96fd1, 0x3781127a, + 0xe782985d, 0x14774e0d, 0x178bdd8f, 0x28a5953e, 0x67cf522b, 0xc6f5fd44, 0xce7c90fb, 0x5105a1bd, 0xb5989145, + 0xf926ce59, 0x15fc5bff, 0x80ec2255, 0x35812b02, 0xe11b8cc8, 0xaf1fa6e7, 0x21383829, 0x3dd649cb, 0x240a0052, + 0x09cbcef6, 0x6a6f223c, 0x7630a249, 0x709fa4f0, 0xdc742ceb, 0x56a2e679, 0x6d780a26, 0x57cd09c8, 0x01d08816, + 0x24b8e513, 0x8dcd2da7, 0xe35703fc, 0x23e5b851, 0x3a3ec81e, 0xbb64d260, 0x7fef29bf, 0xedd286f3, 0x9b9075d7, + 0x694d309b, 0x243009a0, 0x705cf69a, 0x75726195, 0xc91aa9fa, 0xed15c8c1, 0xa70fd84c, 0x4f3610cf, 0x899f88f1, + 0xa3d3ef07, 0x3c4aea2f, 0xd8f40abc, 0xd025d718, 0x0cfb738d, 0x79972809, 0x7a631b37, 0x1bd6bdb7, 0xc79d8691, + 0x71b4614a, 0x1d006a1d, 0x0e478bbd, 0xf43bb2b8, 0xf5c62cfb, 0x778536fd, 0x82c57923, 0xc27aa72b, 0x9afa61aa, + 0xcb5858f7, 0x8912cbed, 0x9c5cc156, 0xf763836e, 0x1577467d, 0x7da6f3fc, 0x88967434, 0xaa981c00, 0x17a61fe1, + 0x9fa90715, 0xe5acd0f1, 0x30f3a68b, 0xfa20ec99, 0xf3a858e7, 0x63a3fc23, 0xb051123d, 0xba8f62f7, 0x1924b278, + 0x4d0851e8, 0xf357e55c, 0x50f621c0, 0x01de272b, 0x170c9d9a, 0xf62df94d, 0x0bc2945c, 0xd4ec9007, 0xfb33874e, + 0xadbba884, 0x8e6f5f83, 0x7960b153, 0x0bf360e4, 0xf8932e06, 0x84a2c6ff, 0xf337ee4b, 0xd016f4d9, 0x372c0b67, + 0xad507fac, 0xd745d842, 0x433caa5a, 0x0da1e60b, 0x93063fd1, 0xbc656949, 0xd5ddab9f, 0x806147d5, 0x9c06b7e2, + 0x8075b076, 0x32173409, 0xf39595cd, 0x0175972e, 0xf9789f03, 0x19ebb4bc, 0x657117cd, 0x33ff9088, 0xc9931c9e, + 0xe1ff4b11, 0x1110bf98, 0x4683fc14, 0xea9f05d9, 0x05c4951a, 0x91a047c4, 0xbaa69be3, 0x3d420d63, 0xb6a68365, + 0xfcca36c9, 0x83efe402, 0xc971dbb4, 0xc6450932, 0xb4035822, 0xf1db565c, 0x1765d5db, 0x8e4ba103, 0xebb01640, + 0x7844f5b6, 0xdbae18bb, 0x6dd39a7b, 0xf53f1318, 0xdc04ba9e, 0x4181201f, 0xa1cdcf4f, 0x4ba42fad, 0x11c28c7b, + 0x36237daa, 0x61ed8a22, 0x6a54fdc6, 0x8edef120, 0x871c059a, 0x6c682d0e, 0x6684f944, 0xbdb1bb2e, 0x37d9e699, + 0xb6bcb56f, 0x321574c0, 0x670f0ab7, 0x02a11b37, 0x2df73f09, 0xf1c305a6, 0xb318b85f, 0x6f59f570, 0xed8920e6, + 0x449986f0, 0xdec6101f, 0x05247473, 0x7db90e55, 0x11fb167e, 0xbecd586f, 0xe58198ea, 0xeda37875, 0x28b5c069, + 0x1e7a68a8, 0x297fbb23, 0x18bc2329, 0xcd305935, 0x1898ff8f, 0xc43764f2, 0x83e306e5, 0xc29b4c52, 0xadedcfda, + 0x4f2e7de8, 0xab13bf45, 0x0b96367b, 0xbe97a18d, 0x42a4c747, 0xdd3ae95c, 0x5d98a08a, 0x1584c0fa, 0x6b51ded1, + 0x377925a5, 0x0286b4b6, 0x2ef038d9, 0x8147c88e, 0x1e0b8e86, 0x371cbbe8, 0x1cb4317a, 0x1e2cdd2e, 0x9033bce2, + 0xdd4cbea6, 0x32c22e82, 0xce834c39, 0x7a805945, 0x2841995b, 0x34c6c676, 0x4d3b6fd2, 0xaa9b7446, 0xcc8d607e, + 0x45991d49, 0x332a58d5, 0x4a7b2b11, 0x52c0d547, 0xe033a869, 0x8b3bf118, 0x6a3cf46e, 0x1a80fb1b, 0xdbf1f2c3, + 0x309d2aab, 0x8534d1f3, 0xc4f2b01e, 0x654a1c22, 0xc13ebc62, 0xcbacfcfc, 0xb1dc19ad, 0x9e5950b6, 0xea3332de, + 0xfa5bdf66, 0xc7cee6a2, 0x2b6c06ef, 0xfaab72c3, 0x5ba14077, 0xe55df77c, 0xa897324d, 0x3800129b, 0xb1ac3310, + 0x5c589cd1, 0x40d942b8, 0x120f9e12, 0xa93c69c9, 0x2b9ef049, 0xd0722b6e, 0xe9a390bf, 0x18a3d70d, 0x5a57be8b, + 0x574805b8, 0xc7f87a2c, 0xd120b61f, 0x77eed27a, 0x01e00239, 0x70620e11, 0x67bb0a1a, 0xdf25e013, 0x97165253, + 0x2dfe6417, 0xbb22503a, 0x23904a68, 0xbe2c9c2f, 0x25a09bf2, 0x9249e6d8, 0x4259e454, 0x67f113f6, 0x7987da02, + 0xb989b7f1, 0x78a0f539, 0x8b171446, 0x7b60c05c, 0xf7c5cb65, 0x40adbf4a, 0xc5db0e93, 0xb21f6ddf, 0xfeb2b46b, + 0xfe75c115, 0xc08a0d53, 0x23eee961, 0xed2fa727, 0xc63043d0, 0xaf49844b, 0x50810bc8, 0x1f1962c9, 0xefb72698, + 0xca950e05, 0x350c728b, 0x0f02cb34, 0x920480f5, 0x7169c6e3, 0x2422d3f8, 0x0d5f3f38, 0xaf6664ab, 0xb55b4c20, + 0x9f47d5f6, 0xa3d35245, 0x34aa4210, 0x99776b2c, 0x0ff3bfc3, 0x8cd7190a, 0xe0ca9112, 0xb8a1f6d9, 0x53f0e54e, + 0x2b47e2bb, 0xe1d5abb5, 0x0827bbc4, 0x3c3e207d, 0x542bc7af, 0x3a59b982, 0x6aa3f2d1, 0x385e961f, 0x713e067d, + 0x802c8bed, 0x2014476a, 0xd716bc1f, 0x5e89d464, 0x6f9a85e3, 0x1ae054d0, 0xac6f7d07, 0x7681022d, 0xa70ea3b6, + 0x1046bef3, 0x7342f9cb, 0xe4110b14, 0x763140ae, 0x3df83541, 0x37e152da, 0xc3313950, 0xa1cffc78, 0x46fe118b, + 0x7c7c86b5, 0x1497e6e6, 0xe36e1dd4, 0x5474e0f2, 0x931840f8, 0xf721ac49, 0xc578df86, 0xad7bc35a, 0xf3a9d78e, + 0xc623fe0c, 0x355798be, 0x29574526, 0xda715cc9, 0x402f410d, 0xaf92de56, 0x47cceb27, 0xadfd4282, 0x09884763, + 0x34f702ab, 0xdd4978d4, 0xa5904853, 0x101a7d26, 0xa468be5a, 0xe7818e57, 0x7f9522a8, 0x3536d1a2, 0xb6d103b8, + 0xa1a91d62, 0xaa46eec0, 0x6708f216, 0xc4ca3b40, 0x45f8a8df, 0x66192ea7, 0x48bb9531, 0x2851696a, 0xcc7c1c48, + 0x748d7fe8, 0xe93eadd5, 0xa3cfa2f6, 0xbb2b71f1, 0x56aa07a5, 0x5be9cbec, 0xb83b587b, 0xb6f14fcb, 0xe9769495, + 0x1ebc21d3, 0xac697581, 0x5764f17e, 0xb6564cf3, 0xf5831c16, 0xc38e1d01, 0xabb1ac3e, 0xd0d5c590, 0x0603012d, + 0x6e229657, 0xb6efd063, 0x64610251, 0xaa5e028c, 0x35287274, 0x27fb7f3b, 0x439b064b, 0xfcfc419f, 0x63e62b8a, + 0x3aebdba3, 0xbf2e7182, 0x45ffdb0b, 0x82e7efc3, 0xf19bd660, 0x09939954, 0x02a6f44b, 0xf1e68238, 0x1dc2be8e, + 0xd51a5f88, 0x9b42f6b5, 0x9003cba4, 0x3971538e, 0xa747b977, 0x1b6b1a53, 0xe7d1c91e, 0xc8f1b38b, 0x57debaa4, + 0x46e54471, 0x141e36d6, 0xa70dcbfb, 0x2ffd24ea, 0x95432c9d, 0xabe796d8, 0xc84954a1, 0xcce9ecd5, 0x4bbe23e2, + 0x5d3e7d05, 0xbda8ae49, 0x3bf4340b, 0xf85edd21, 0xa5f798da, 0xef163d0c, 0xaec0db70, 0xa163764a, 0x0a1d8ba6, + 0x0afb873c, 0x8ee50b6e, 0x76835a29, 0x65341080, 0xff19d2aa, 0x072d6de2, 0x1dea35b2, 0x5e9e2011, 0x873cc3e7, + 0x343c3651, 0x6b677784, 0x1442d3c8, 0x70eb6235, 0x8a4401fa, 0x0c4ecb4e, 0xf8050cd5, 0x752c3f22, 0xba6e8e7c, + 0x0ff02569, 0xfdc2424e, 0x5ed9a0cd, 0x4deead41, 0x7c51e428, 0xc5545251, 0x1b53248d, 0x91d77818, 0x52806ba0, + 0xc9cb1ce5, 0x416ebbdd, 0xf41c8c2e, 0xd8d48385, 0xc00dffda, 0x764bb3bc, 0x7af5b178, 0xc74acdae, 0x143b7d44, + 0x054ea75b, 0xffffc634, 0x9c1bbf72, 0x9c292e88, 0xb17c3a25, 0x6eb3bbec, 0x9c8d6673, 0x10ad90ad, 0x1a60eddd, + 0xcb42cbe9, 0x54b0b540, 0xe64c3ad4, 0x3826eabc, 0x7799e4c0, 0xbac4f138, 0x95cd553e, 0x26d62b69, 0x39085fe0, + 0x7a16c932, 0x034a98f3, 0x757bec18, 0x10506786, 0xc8a4b3bf, 0x722a7290, 0x5be524fa, 0x6dcc8b84, 0x2e57522c, + 0x3b568ed1, 0xfc8e2c8c, 0x847d9062, 0x4c9dfb4a, 0xcd715496, 0x16b45d98, 0xb2dbec4e, 0xa1f375f3, 0xe59160cd, + 0xbed0a694, 0xede43a05, 0xb35c2cb7, 0xc365c25c, 0x7f193326, 0x40962709, 0xcbc75bc1, 0xbab00abc, 0x4c727be0, + 0xe4683e0a, 0x070554f1, 0xf73ccbe0, 0x0921d779, 0x2c2c39ae, 0x36055af2, 0xad1da65c, 0x2c18829e, 0x4a62c5cb, + 0x6fafd960, 0x7734cfd1, 0x8a11af05, 0x097093dd, 0xaf224e9d, 0xc4c9e2df, 0xbf6f277f, 0xb2c89135, 0x5c31b823, + 0x4e942bad, 0xc2cd8fbd, 0xf2d277f4, 0xc29f618c, 0x2aa178fa, 0xc8a76de3, 0x0b7b0594, 0x16cdd38a, 0xca523011, + 0x8668bdb1, 0x9abb667e, 0x05f374f3, 0x2fb4b21d, 0x3100b431, 0xfc010701, 0x9e1bc24c, 0x9d5d5419, 0xc68b6f5a, + 0xf36b296b, 0x844ea8d0, 0xbf4e3be7, 0xd9509943, 0x28cc6e4e, 0xf805704e, 0x51fcebd2, 0xf8918df7, 0xe6bc2d9c, + 0x5d58e6a3, 0xb086935c, 0x7282a8c6, 0x0be3e3be, 0xcfc58a4b, 0x7fcc447b, 0xb55c2b34, 0x8d73c9e6, 0x0516e1e0, + 0x23def1bb, 0xa00a2900, 0x070b9ee1, 0xa04a9d25, 0x76ccc9b8, 0xb8a692c4, 0xfa289f1c, 0xa146489c, 0x2baec1ab, + 0xeee7b62c, 0xd89ccbbf, 0x4fcb6182, 0xd4f9eb41, 0xdb0d9389, 0xe9330b7c, 0x1d600d22, 0xfcf68685, 0x50cc2a9a, + 0xd6da8716, 0x3d354acd, 0xf971d70f, 0xee38e63c, 0x9f211b07, 0x28507d55, 0x83399bf5, 0xdc32201c, 0x11bcdc0d, + 0x8fa9c05f, 0x86ccd7ef, 0x9dac9274, 0x81ecab96, 0xa6780f8a, 0x0751c601, 0x23118a29, 0x14393f8b, 0xabb1bd14, + 0xed3927ad, 0x98a5340f, 0x471a8714, 0x22d98910, 0x61aa45da, 0xb454a5b6, 0x3da6fa10, 0xa393b5fa, 0x53699e36, + 0x01cfe17f, 0x5551c730, 0xa17c2baa, 0xcacf97b8, 0xa76a289f, 0x3a607363, 0x2e0f5a01, 0x423c58bd, 0x01fd03e0, + 0xe6b5546c, 0x5b49d085, 0x2fa2dc51, 0xa7290489, 0x81a7e8b7, 0xd23abd1a, 0x6a3a4728, 0xb8c16dc0, 0x38ad9cc4, + 0xf77ec008, 0x387e3bbf, 0xed83a234, 0xb92707d4, 0xc68bf511, 0x7d333410, 0xfdea42c9, 0x6770ef63, 0x994710b2, + 0x50c88ecf, 0x8ba3d26b, 0x95ce44ea, 0xe2a68889, 0x76c6fb91, 0x8ecb7363, 0xf799e92c, 0x9e8e2cf9, 0xd104ee4a, + 0x50894793, 0x7f04653f, 0x154edc4a, 0xd1a17381, 0x39b1b59e, 0x67f6dd96, 0x5356fe3f, 0x4c1cd6e6, 0x62630487, + 0xb9e33e32, 0x218fc073, 0x3950e667, 0xd3da4df9, 0xd21c44bb, 0x4ad5bac4, 0xb9e31e6e, 0x8c776d9b, 0x4b2298d4, + 0x1468706b, 0x4ddafdba, 0xc773d914, 0x70efef48, 0x044a0e86, 0x0b04d854, 0x74ada48d, 0xee0ce2c7, 0x6f0626e6, + 0x06d69147, 0xd35c4a74, 0x83bfebe8, 0x2efce589, 0xe99e25f0, 0x47d70c8a, 0x700d0b53, 0x23949af2, 0xf799c69a, + 0xc395aeeb, 0xb43cf418, 0xa43393af, 0xe59504f8, 0x31913f56, 0x2eb1ef52, 0x1aa01c73, 0xa21fd60c, 0xfe5be3ee, + 0xf8454413, 0x97c20f31, 0x36e2a2f7, 0x724505d9, 0x66dbf669, 0xd7c96d2a, 0x7efa5b60, 0xb7f3fc24, 0x66b5878d, + 0x500b68fe, 0x9207c049, 0x0a46d147, 0x8dee9690, 0xf3b19610, 0x26376c04, 0xd33a12d2, 0x6b9c9d19, 0xf8da01bb, + 0xbf4f51e8, 0x8bf04869, 0x0252f742, 0xb1171c3f, 0xee943a8f, 0xe73d5ce6, 0x1baca524, 0x4309aeaa, 0x416ae850, + 0x62e45a42, 0xc43f5aff, 0x7a53d098, 0x76eebb2e, 0x75f4bf76, 0x5d083b6e, 0xefe3838f, 0xe8be2a12, 0x7ca4febc, + 0x1302929b, 0x4857f351, 0x0e9e2810, 0x537525b1, 0x2ae1b30e, 0x43c828c9, 0xbc535ca1, 0x8e9a82ed, 0xe4160514, + 0xb8b7ec92, 0x4063dece, 0x5a22069b, 0x8e209bf3, 0x9cbb4d2c, 0x1cd65a42, 0xbe94984b, 0x3012afbb, 0xeccd7374, + 0x0bce9ff8, 0xdbac685d, 0x1b2888cb, 0xe6bc883a, 0x91fe91a7, 0x067f9bab, 0x0b762275, 0xf7df60c2, 0xf75cbffd, + 0x244109e1, 0x039772f5, 0x9d6e9513, 0x0479d081, 0x298eeea6, 0x730ed538, 0x901a5acc, 0x9eaca2b3, 0xc69a3efc, + 0x6baed9c8, 0x62519e6c, 0x7232179f, 0xf13b3bd6, 0x4005254d, 0xbcbf9fcf, 0x218000fe, 0x77e93223, 0x2373f923, + 0x1d607694, 0x4fb35386, 0x12f56c84, 0x9de95504, 0x3873d0f2, 0x7bb4d64f, 0xc8943a88, 0xb28051c4, 0x46a782d0, + 0x3ef1cd06, 0xd2251b3f, 0xe251a595, 0x1ee6a135, 0x1a9145b1, 0x44d6cebb, 0x475a943c, 0x63d0b9bc, 0xdae2e288, + 0x5c97adf2, 0x8f7121ca, 0x180cd751, 0x17d426d3, 0x53850cb8, 0x1e76a2da, 0xf2db0f82, 0x83a60021, 0xb01ddeba, + 0x296afaa4, 0x5e8dee30, 0x8df71b23, 0x6e3074ef, 0xa488c813, 0x0f7ae50c, 0xe0381dff, 0x4c232410, 0x6c0d6737, + 0x592ba153, 0xf05c9576, 0x73b7218e, 0x5edcf347, 0x2f798c95, 0x8086df8c, 0xd196b255, 0xd8b48380, 0x515309f8, + 0xc480c3e6, 0xfaab623d, 0xc4aae3fd, 0x5a91ce17, 0x164d37e8, 0x73494415, 0x7367d9fd, 0x9b75c3b1, 0x05339a78, + 0x85bd2196, 0x5dc275dc, 0x3e2c9d05, 0xccd85be8, 0x9d14fc95, 0x056eb240, 0x5f60429c, 0x48a213b0, 0x2e9b732b, + 0xedfa919e, 0x1acb659c, 0x9fba7ded, 0x15ae494b, 0xb1297194, 0x6f215e0f, 0xfb472afd, 0xe53491fe, 0x1d5e1eb9, + 0x543d4485, 0xca1b1bcc, 0xe89a6d0a, 0x312b3e53, 0x1c07cc66, 0x716e1704, 0xe4fb9736, 0x605a23d2, 0x4751df3c, + 0x4c07fa80, 0x48afe943, 0x675d827b, 0xea53a9ab, 0x3bdc5edb, 0x64981774, 0x76194aac, 0x2eeee64f, 0x30b91b34, + 0x91b1b738, 0x93b849c8, 0x62600b3a, 0xcd84b074, 0x041dc5d6, 0xb79887ed, 0x0c7c01c1, 0x25362aa5, 0x38b6d3cc, + 0xbf270ded, 0xa5c55764, 0x7642f7e4, 0x5f446795, 0x9ed4cf22, 0x79de456c, 0xe5fd46c7, 0xcae0d84a, 0xd5db2b8e, + 0x7792beab, 0x82734d24, 0x128bcfdc, 0x0749ff00, 0x5ac83db6, 0x2cdbf4d7, 0x9d6e7310, 0x60d95b39, 0x2024c9b5, + 0x1168a32e, 0x0e3dd798, 0x48430d2f, 0x4cbf5ee3, 0x5e243435, 0x2fedbcbe, 0x30b7059a, 0x26d56353, 0xbd63bba2, + 0x49fefb85, 0x4c7e9784, 0x7c069005, 0x6b488862, 0x8c65c2fe, 0xf9a19c4f, 0x455710bc, 0x0d2a8b6b, 0x5cb19e9b, + 0x9d907b41, 0x450531fd, 0x60189f10, 0x0e7303ca, 0xa7ef8c32, 0x4ca0f841, 0x05188b13, 0x44c4c74d, 0xb63f4a4d, + 0xc219ed04, 0x447e567c, 0xff43bc91, 0x8c1b32ef, 0xdc9c880c, 0xd499fbdc, 0x3dd40739, 0x8753ce4f, 0xfd997733, + 0xd20b3d72, 0x023e11c3, 0x95437a38, 0x03f8429b, 0x9d0df3b8, 0xc603ab78, 0x47ac93bd, 0x915709ef, 0xca417464, + 0x96eb8b2c, 0x867d5fbe, 0xb6b5d5fb, 0x27f584aa, 0xa61c9b96, 0xa20e0342, 0x81377786, 0xdea3a60d, 0x7b2277cc, + 0xde93beec, 0x15de93b1, 0x168fe0d0, 0xc3722e24, 0x02c11ece, 0xfa6a17f3, 0x78fc70a6, 0x559e2c0a, 0x31f05f3a, + 0x12cb7f43, 0xc5f7dd26, 0xca2d144b, 0xa9bf5555, 0x2c17f025, 0xfc79ac7a, 0x5e516f3b, 0x82cc1327, 0x5d1e0440, + 0x3518c326, 0x16a5fd86, 0xf089d853, 0x54c6820e, 0x8505efc7, 0x6c8496ca, 0x6d62f338, 0xc1e78e67, 0x8f6cb9dd, + 0x5eb32447, 0xb71b53c9, 0x86a14ed4, 0xad77fe7c, 0x83b471ce, 0x0106a498, 0xbf4dd27e, 0x4c1488fc, 0x6f243376, + 0xb348e927, 0xbf7bb1b1, 0x2a7ca5d0, 0xd3c7da3c, 0x343409ab, 0xf043422c, 0x0e70444b, 0xea574e5b, 0x4322a5df, + 0x1115f36a, 0x91d02437, 0xe773340f, 0xcd0df102, 0x73c6c2a2, 0x649874a9, 0x936dfcb3, 0x12a991c8, 0x2f5a42cc, + 0x07bda97a, 0x61e62879, 0x7dc0860d, 0x6cbe25fc, 0xc2c460c7, 0xc2f5189c, 0xf912f97c, 0xbfeba36e, 0x80595d69, + 0xee9f322c, 0x4a823456, 0xedc1327e, 0x28b9a4c3, 0xa9c2b1ac, 0x0d6b5d87, 0x5f141538, 0x448f7910, 0x8a892a75, + 0x187834f7, 0x48530402, 0x7825ecc6, 0x3433e80f, 0x96916647, 0x5a05bc06, 0xc6b9a92a, 0xb9a8f342, 0xfea284e8, + 0x9dfdebd9, 0xcde82998, 0x73cd748a, 0x85c96a1f, 0x843e9eb0, 0x12cae7dc, 0x415093ad, 0x3d115346, 0x468c1a24, + 0xa5d0cd24, 0xe6e1f50f, 0xdf38a664, 0xb7f4f03d, 0x8bad8ac0, 0x421ae934, 0x4c1b76cd, 0xf3a4920b, 0xa31d6527, + 0xb883e8b5, 0x629d8128, 0x8d2a0121, 0x07546bdc, 0x1810b52d, 0x966d17c9, 0x3747fc5b, 0x05d32436, 0x3b559064, + 0x22b27192, 0x4beb4ba5, 0x29848608, 0x5c84dfdf, 0x082cd03a, 0x8637a2a9, 0x342e3c37, 0x59efa6e0, 0x0516e60f, + 0xbbc2ff9c, 0xeffd2b9c, 0x41a06ca2, 0x71c64783, 0x9e6c9088, 0xfbd26db2, 0xc936fa15, 0xdd94ca3a, 0xa70c86fc, + 0xe0040156, 0x1cca3ee5, 0x99446ac6, 0x8e1a2493, 0x12a5c3ac, 0xd4be8400, 0xa1cf83ce, 0x8a732406, 0x1a939e12, + 0xef97811d, 0x755c2b96, 0xb4e7632b, 0x78e3ff30, 0xeb59e3f7, 0x1df49b1c, 0x86f7dcd2, 0x96b8dbd1, 0x35580567, + 0x27e91c0d, 0x94050a49, 0xa587a163, 0xaa05825c, 0x43654ba8, 0x9116fc98, 0x4b2ad2f4, 0x6315d696, 0xbe6264b0, + 0x87bd13d8, 0x1d901125, 0xedfd46ec, 0x79ceefd7, 0xea7658d2, 0xda69da74, 0x81dcf680, 0x8c6d90e5, 0x788bfd11, + 0x7fb23104, 0x4bbad2ad, 0x47817701, 0x1d47a6b0, 0xbde7a89a, 0x13d422a7, 0xa8a1a949, 0x134dd11a, 0xb6ab41c3, + 0x14a22d67, 0xdd339a40, 0xe58f6b6c, 0x91df6565, 0x9c5c73ef, 0x26f28989, 0xb538c97e, 0xd8af0dd7, 0xdb097357, + 0x92e7b914, 0x7782d73d, 0x255299b0, 0xb06a6c3e, 0xb17d4fed, 0x6f643615, 0x2d4be25e, 0xa90870c1, 0x93abd785, + 0x19be767c, 0xffa669c6, 0xa68b2ca0, 0x20a94cc3, 0x4f2ede52, 0x71c4e25e, 0x9684e7c6, 0x09d193b2, 0xefc7fc17, + 0x5db9c1aa, 0x1b2904fb, 0x7a4e4bc3, 0xb16dde20, 0xf1198662, 0x4b111cdf, 0xd86ed8eb, 0x478154ee, 0xec3188d8, + 0x877a5181, 0xa4ec606d, 0x92993fec, 0x52848da1, 0x70901728, 0xd4aec3a6, 0x88cf7a69, 0xf4c86eb4, 0x43be488d, + 0x3dcab2ee, 0x7843e407, 0x7cc2f730, 0xf180f539, 0x1aec9b3b, 0xf0dd00f1, 0x2a3a3539, 0xa552eb95, 0xe3badbaf, + 0x0d4e55a0, 0xac51163d, 0x76cef024, 0x710c8d35, 0x06cad552, 0x55a7a268, 0x6a5d1f58, 0x18a1abce, 0x55f16d72, + 0x3d3acd19, 0x3b769c8a, 0x3a1843dc, 0x0cfe3e79, 0x755ca03d, 0x9719995e, 0xc7a2bfa2, 0xbc817ddd, 0x8f6aca2d, + 0x87a98589, 0x9105421f, 0x99eb0403, 0xe49853aa, 0x25484c62, 0x8d45e81c, 0x6c6a5bef, 0x8eb52f6b, 0x4407c60e, + 0x8413e1a6, 0x7a2cbce2, 0xe379c6c1, 0x6ef42b82, 0xfc38759c, 0x0de0a528, 0x63e7003f, 0x4d12779b, 0xb4528686, + 0x0db56e92, 0x106d35aa, 0x4f80a11e, 0x9278fde2, 0x50142fd6, 0x01d923cf, 0xbe459c47, 0x9840b380, 0x74c69b93, + 0x9727bd9e, 0x3a565ad7, 0x7ac2a585, 0x77ab9ae0, 0xd982c090, 0x5b03e0a2, 0x3ed2dec9, 0x72d0ba60, 0xe424073b, + 0x95b7ce74, 0x7031481b, 0x30469931, 0x11f8a15b, 0x1821f6b5, 0x4f916a6c, 0x0573173e, 0x1bfe4fef, 0x3f6b6134, + 0xbd320c28, 0xab1a8063, 0xbae7ce30, 0x8a8e6c1c, 0x9ea60dde, 0xdc0a6b46, 0x85589134, 0x59b4ff99, 0x56383123, + 0x899be9db, 0x3d4e7537, 0x0a0571d1, 0x9d76bd2b, 0x73ea10e1, 0x0f9571ed, 0x10d8b318, 0x70866197, 0x5b372a63, + 0x32cd34f5, 0x0071237e, 0x68971c94, 0x6974032d, 0xfabddc2c, 0x32175034, 0x4d536a8e, 0x8eb7a262, 0xb9615a8d, + 0xb5fd8d1d, 0xa1bc2347, 0xa113671f, 0x9eee60b2, 0x3be707e8, 0x1666ab4c, 0x5f2ca24d, 0x737c7f18, 0x7eb4ac60, + 0x632782db, 0x58cadd48, 0x440d1f72, 0x9705d1ff, 0xbb33c87e, 0xaaf66520, 0x11732f59, 0x5b478c02, 0x286320c8, + 0x7ab04dea, 0xffef44cb, 0xa6811628, 0xd6dd028d, 0x9f25e995, 0x61ad2408, 0x772c0f6d, 0x05b855f5, 0x5fab848c, + 0x0e59d1a2, 0x55df6e9e, 0xca4b9502, 0xe56d59f9, 0x59889c85, 0x84fe3809, 0x50f77ccc, 0x145c30cd, 0xf4d9491d, + 0x734db0aa, 0x1ef8a227, 0xfd4d3157, 0xc90eee9d, 0x57bfcde0, 0x8d794ce0, 0xff57b27d, 0x53b4c97d, 0x4c230cc7, + 0xca3db55a, 0x6d8d0d80, 0xc7e82942, 0xc3f173bb, 0x00626d36, 0x7de73eb1, 0xe9c9a673, 0x6f9f3321, 0xd94efbc8, + 0x320267eb, 0x3ee39e8b, 0x17e2b5d3, 0xe6aa236a, 0x62638af5, 0xcc9b41bc, 0x5160fb49, 0xdf7b6d34, 0x8cf8d72b, + 0x556e62e8, 0x76591104, 0xb9f704ce, 0x2e3c155e, 0xcb91a526, 0x4d7205c1, 0xdbbb5836, 0x5d40e7cb, 0x57fcd74c, + 0xda991c30, 0x467d2be4, 0x40d794b3, 0xb21d33e2, 0xa4336c72, 0xff6e34be, 0xe61fbd1a, 0xc99c424a, 0xa86808b4, + 0xb8336d13, 0x9879b3bf, 0x1fa6e043, 0x64d955f6, 0xda6f8945, 0xd0a50db9, 0xd1d2914e, 0xccaa344a, 0xf1643d4c, + 0x66fc24ec, 0x09a18d23, 0xc1e7d770, 0x2f854974, 0x0defbf2e, 0xceb7cbb4, 0x9c3375f2, 0x8e94a2c5, 0x04239410, + 0x5c897ace, 0x6bb00b98, 0x1015ca4e, 0x39ad4345, 0x45a34b5f, 0x0995017d, 0x6f013a24, 0x1d87ecb2, 0xb39ac418, + 0xf743d44c, 0xe2e8d731, 0x193a89b7, 0x213af4e1, 0xc52a3eb7, 0x6c0f69f2, 0xc40acb34, 0x0a32d486, 0x70fdc7f8, + 0x1a923901, 0x6d5da1b7, 0x7094b182, 0x9735cf82, 0x3b1a4bb0, 0xddbffcde, 0x75ba1af2, 0xdd692286, 0x69759168, + 0xee5b1f54, 0x5dcd11de, 0x8aec4348, 0xc4686f7e, 0x830005bb, 0xc5afd7bd, 0x8f622b0a, 0xe62f93f3, 0x11dd172b, + 0x0f0966e7, 0x60e8f03d, 0x92aac027, 0x395ccdba, 0x49a9a325, 0x928f9c4e, 0x2f165845, 0x24d0e63b, 0xdc65a259, + 0x3c45d94c, 0xbe7be278, 0x8d55350e, 0x7354405f, 0x8110595c, 0xbbd6327f, 0x5c77f306, 0xf480e5b5, 0xc551ea56, + 0x165d65f4, 0x0aea06a8, 0x6781ab52, 0xa1b6f5c3, 0xa38a54fc, 0x7b8e6e8a, 0x29c3c099, 0x7b061527, 0x8f43b989, + 0xc5cef76f, 0xc9385419, 0xc6a13796, 0x1373c50a, 0xf443f503, 0x9de072aa, 0x49399e65, 0xedd05441, 0x5615f60e, + 0x77d3fe2c, 0x9b2d00d7, 0x23d4b89a, 0x21f8be45, 0xea5a8dce, 0x8b11f58f, 0xe50be234, 0xaf6aa9aa, 0x2732bfa4, + 0x0b8b7a78, 0xa8479f6d, 0x00c2782e, 0xb48ee38e, 0x6f4565d2, 0xfffbfd1c, 0x67163484, 0x75ce30e9, 0x31b41b3f, + 0xee0edf43, 0x41876c75, 0xc3d28436, 0x2594ff00, 0xbd62d6a3, 0x4fb98d11, 0x6234154a, 0xa4079a69, 0x76cffa3c, + 0xceee4727, 0xe84c6025, 0x409eb85c, 0xf65e8dca, 0x96bdf1e3, 0x6a623cae, 0xfd5852d7, 0xaee231e4, 0x83208d66, + 0x046d5640, 0x6eb69e2a, 0x10f1d7b1, 0xe875d84e, 0x611fecf2, 0x1dbff7fb, 0xf0730718, 0x2ba807d7, 0x1efbcf11, + 0x1d223f53, 0x050a01f0, 0x1f4a0078, 0xa8be8628, 0xd6a88e1a, 0x6f01710d, 0xc8c1b430, 0x9d276446, 0x0ebdbb59, + 0x92899e1e, 0xdd84990f, 0x67534d85, 0xd27d7d79, 0x3daceff1, 0x4873c484, 0xf3817650, 0x6e07303a, 0xadc040b4, + 0x67c2d21b, 0x54fb5099, 0x403b2d96, 0xd32d50a3, 0x799bed6f, 0xdf0b8d3a, 0x673b57c6, 0xc07b9c5c, 0x235ecbdd, + 0x7a15498b, 0x08c141bd, 0x2ff4627e, 0x248d1932, 0x31c6ebe1, 0x1f4926f4, 0xbc0399c6, 0x0c9f939b, 0x9af079a7, + 0x7ad7aedd, 0x42d8b412, 0x8c3fd777, 0xba22cfad, 0xe3746ffa, 0x5384514b, 0x207f65f9, 0x51f1ebdc, 0xcffe5c9b, + 0xaf1c23ee, 0x4343b13b, 0x3182087e, 0x38c04b44, 0xd60a3052, 0x09b5a839, 0xf15b73a2, 0x6aa08035, 0xc589da69, + 0x25a92e7c, 0xcdf68970, 0xbcf22b30, 0x0e30982c, 0xe44d04dd, 0x470cb793, 0xae9acf7f, 0x48857043, 0x3956bf19, + 0x225094e7, 0x1198ec6e, 0xf5fb1dc3, 0x46875164, 0xf8b21233, 0x5669afd7, 0x8a1e1028, 0xa800ee74, 0x3bb24200, + 0x6ffafc61, 0x04de3354, 0x926a0f95, 0xc34d01c7, 0x7748dcb6, 0x293afdad, 0x10f985b8, 0xd74ad74d, 0x4b0d96dc, + 0x5049fde5, 0x1d4ff080, 0x7b5abf97, 0xd3fa37ee, 0x03be45b8, 0x4378f8fe, 0x4e8490bc, 0x4420daf9, 0x4462f8ba, + 0x3a26b3d9, 0xaf499d23, 0xa3b9a93b, 0x84fe50a0, 0x5ffb1e5d, 0xf2f30390, 0x8cefed77, 0x684d51ad, 0x8107392f, + 0x78b1f507, 0x114ab0bb, 0x00db4c7e, 0x0cc71136, 0xbe604e01, 0xdf052fe6, 0xc5d62cec, 0x8c50ffb8, 0x18c9c628, + 0x753a5c53, 0x2710d055, 0x2e3b3df6, 0xe66650e4, 0xc933398e, 0x0ea89bd9, 0xbabe9410, 0x3e0ee1af, 0x88602424, + 0x53482ed9, 0x8360eb97, 0x184e5313, 0x51f6b93a, 0x4f608235, 0x774b34c0, 0x6b3dd7d9, 0x2bec9daa, 0xc5d40580, + 0xc9189833, 0x540ee819, 0xdf7c58b6, 0x207edc8c, 0x7ee3c461, 0x4dcfb133, 0x5d983de3, 0x3b0e9153, 0x11af9fd1, + 0x512fa3d4, 0x13110cd8, 0x33c09054, 0x17941186, 0x5de82c7d, 0x356b0542, 0xc4b88269, 0x152c5d7e, 0x9ae46b5a, + 0xb71b839c, 0x2f78b852, 0xaa07a24f, 0xac09a5b2, 0x485defeb, 0x09cf0837, 0x7655dcc8, 0xcf1f6b66, 0xe17171ff, + 0x70ff50d9, 0xf2976a75, 0x34c2eecb, 0x6a1a033a, 0xfebadf0d, 0x9dc55caf, 0x8221a1a9, 0x8294a903, 0xba3d36c5, + 0x21c4e32a, 0xe18e9fb9, 0x56d8b537, 0xe0fd0f48, 0x2ed999a5, 0x3b0de182, 0x54c37758, 0xddf86c00, 0x7756b4e2, + 0x53bcbfd3, 0xb4ae38e8, 0x7d73195e, 0xb7df206d, 0xf54318f1, 0xe765ca32, 0x7b60c617, 0x8873ff1d, 0xd7370d95, + 0xe309df9a, 0xd4e41548, 0x2aaff6b2, 0x53a6df65, 0x2fb946ee, 0xbcba27d7, 0xbb481d67, 0x45cecc97, 0x478394a3, + 0xab73a593, 0x7d9cea9e, 0xe0d12f6a, 0x2c6ebcf7, 0x597500f5, 0x15175acb, 0xb1a66478, 0x59b25f28, 0xe635ff18, + 0x8b991ca4, 0xad431894, 0x54cddecd, 0x3d569ed5, 0xe1f09b61, 0xa9ffbf81, 0x0a6af6fb, 0xf5d98d50, 0xdfc425cd, + 0x27cd661a, 0xfd8a9ffd, 0x0392bb56, 0xe638fb9e, 0xfcb930cc, 0x763c804f, 0xcf871e84, 0x45e20852, 0xbadecc24, + 0x107ed282, 0xf5f74a1e, 0x7860cbc4, 0x37ce24cb, 0x111a4144, 0xb63c31dd, 0x84e6b68b, 0x0e7e64e7, 0x835670f7, + 0xb059c586, 0xa988fd4a, 0xf0a73b6d, 0x6f53865e, 0xf0f93975, 0x82b8abf7, 0x8ccc3b27, 0x03c1a74f, 0x225e34b8, + 0x1454d219, 0x041cbf27, 0x83dceb61, 0x4220b60c, 0x0d6dd7fc, 0xaeb64bb0, 0x06eac0cf, 0xb0655575, 0x4b3b073d, + 0x9a1348ef, 0x16c76541, 0x2f53b383, 0x546e0e2e, 0x13d5b917, 0x011f3891, 0x0b42822b, 0x15a4ffd5, 0xd7d4189b, + 0xb88a4b97, 0xcce687d2, 0x51968e06, 0x23d6054b, 0x414f0e2b, 0xaae3d03d, 0xfe2b2bad, 0x15cfc3f2, 0xaa466eb4, + 0x2ad0edcd, 0x31a59d7a, 0x8e4de6f7, 0x07745073, 0xc26b4ce7, 0xf2de0fdd, 0x651acb12, 0x84180f09, 0xd447ea65, + 0x1ed6412f, 0xeb13ee03, 0x2088eae6, 0x79545512, 0x883eeb68, 0xb1e397b4, 0x289a2ac7, 0xf2ca00ce, 0x86225d57, + 0xa9c63858, 0x8263ce38, 0x4e3a2f6f, 0xa098c2f0, 0xd1a680ae, 0x1c2a7b49, 0x87b0eaeb, 0xf0be8ef7, 0xc9b92a1f, + 0x9b554cc6, 0x8b49bc9a, 0x832bef35, 0xe8e9813f, 0x39660eb3, 0x6706b2fc, 0x6f0b419f, 0xa297116c, 0x912c7b35, + 0x0b11eac8, 0x6ff28533, 0xfad7e751, 0xc0943e66, 0xc645e526, 0x21fe2fab, 0xf70a6125, 0x2e82e4d6, 0x8586abc1, + 0x95897894, 0x786303ed, 0xc46c60c7, 0xe9e188b8, 0x7c618782, 0x2c7bfa6e, 0x934fbe6c, 0x8a0f301f, 0xdd689a2f, + 0x28678180, 0x3e10ca48, 0x9bf32db9, 0xed8dc400, 0xd5dd9db9, 0x8a48836c, 0x16eb5ec3, 0xc84a8ce6, 0xa3122cf0, + 0x7d8fdf3f, 0x6ad8ef14, 0xe608975e, 0xfa3ba5b3, 0xee6ba9bc, 0x7599e716, 0x908dfd74, 0xb4d06250, 0xcb302cdf, + 0xa580908a, 0x65d8759b, 0xe749fc4a, 0xcb0999d1, 0x50ad91a6, 0xe6d134c1, 0x0128650b, 0x0bb30f6a, 0xa45e636c, + 0x27a5e14f, 0x9b23917f, 0xd4aa295d, 0x6ce13ac3, 0xe5c766bd, 0x97eb5a52, 0x71543719, 0x4b94785b, 0xb95f64cb, + 0x76aed35a, 0xc66d92ef, 0x92743c1c, 0xbd44ec6c, 0x3dd54acf, 0x3cdc5c57, 0xc69d377f, 0x8582ea84, 0x5e2a5ec3, + 0xc75695c9, 0x72643872, 0x9c7d269d, 0x3fb9b116, 0xfb03b29c, 0xd742d9ef, 0x739ab6f4, 0x2e4ab8cc, 0x35b88968, + 0x5ddb51b7, 0xe347122a, 0x2ce7f518, 0x886f2cec, 0xe9905556, 0x0bbc72ae, 0x65de8d53, 0x638f0c82, 0x1856115e, + 0x5c5a3be2, 0x00a8d096, 0xdb922dff, 0x8b08f7d8, 0x226c7d46, 0xfaa5c18f, 0x03ed9550, 0xb668dda9, 0xd5dce385, + 0x4e1763f0, 0x89b71c52, 0xd6813f32, 0xeb985805, 0xc164333b, 0x536bc3d7, 0xa859e9b1, 0xaeea9295, 0xb9d99557, + 0xe853722e, 0x0add2591, 0xdd57a6eb, 0xbf8df735, 0xe11836a6, 0x2265cec4, 0x53019a28, 0x11f2b6d9, 0x77d9eff6, + 0x5953ccf2, 0xef7b12c9, 0xc4b8a973, 0xd0cd2af4, 0x6d99401b, 0x28a73c2a, 0xe4134562, 0x995c2dbe, 0x72a8c7bf, + 0xe606ecf5, 0xc8120039, 0xc4809aa1, 0x17681433, 0xbf7aff27, 0x6d040332, 0x8e7de795, 0x4148d8cd, 0xa30f8502, + 0xdef7585f, 0x110486b4, 0x9e98c636, 0xd8acc78d, 0x28d8dcb1, 0xb3ea1062, 0xf8b32a10, 0xcb34beed, 0xf22568bc, + 0x64a07f4b, 0xc2553143, 0x919287b8, 0x26e3904a, 0x527709c0, 0x4297e071, 0x03a08ada, 0xb2acdfc4, 0x3a41a085, + 0xec2ca90d, 0xc180a83b, 0x933c865f, 0xd625835c, 0xb86548d2, 0xd8235440, 0x17391997, 0x9b6c7405, 0x9c1aa96e, + 0x49ac0ac4, 0x563a0dc9, 0x4399fe8b, 0xc2e5ca41, 0x6d785bdd, 0xf5cf4bad, 0x8ce7f6ab, 0xf57c4ed7, 0x4d6e80ea, + 0xe68f5e3f, 0xf52a01ed, 0x4704b042, 0xbd2f8d6a, 0x33798bcc, 0x75d688de, 0x2f66a6a5, 0xe397e4e0, 0x983f10b6, + 0x2aefe63f, 0xf5e0f630, 0xa95dec69, 0x82f34375, 0x075bb898, 0x9b0c888a, 0x433cb939, 0x7b74bee6, 0x9cef5b1f, + 0xc199ca72, 0x7816d930, 0x3353a41f, 0x54d4accf, 0x9877b5f3, 0xf3159a71, 0xc520aa2c, 0x0545847c, 0xbbcf576d, + 0x0ef6063b, 0x693c6f7f, 0xf84fb927, 0x8ccd5b84, 0x9b556e39, 0xeb1d5331, 0x8cedb8d3, 0x1cbb582a, 0x8dca5b26, + 0xccf5bdb6, 0x07cec8ca, 0xdfe18a86, 0x67ca49ed, 0x83e700ac, 0x461ba995, 0xc62d4d07, 0x04e5761b, 0x5c558f80, + 0x9579ded0, 0x74137022, 0xfca1bbf1, 0x00adcf75, 0xd50a9035, 0x69a9d60a, 0xa313387c, 0xe5a38242, 0x709d3d7a, + 0x54a1e705, 0x37c64a5c, 0xf6ec72c3, 0xd510586d, 0x85d0e5b6, 0x625c4829, 0xe67ea4c6, 0x9d9465c0, 0x711e16d5, + 0x9e22d1df, 0x92bef085, 0xf664f0c1, 0xe8ffcedd, 0x11f48e17, 0xddece630, 0x6f859c28, 0xa41b2fd8, 0x7687452c, + 0x90b0e6fc, 0x53c40218, 0xaeb65ca6, 0xa53ac9db, 0x03021585, 0xc7e71411, 0x3058db37, 0x5511dcd8, 0x6159a00c, + 0x3b69653b, 0xaab6c01c, 0x9a576df4, 0x4b9b436e, 0x50ab5b6a, 0x44879233, 0x55a3c95a, 0x60fecaff, 0x18c74ad1, + 0x91171068, 0xb0e3f5ae, 0x5a3e2cf6, 0x7b40d9f8, 0x1c11ccca, 0x02a88a8f, 0xe4f7205b, 0x182ff19e, 0xb9bafece, + 0x69c19118, 0x0b5e181d, 0x2740bd71, 0x011198f4, 0x4782cc66, 0xf2356b8c, 0xe03dc597, 0x59ac1ba2, 0x0163f94f, + 0x35fd2c2a, 0x7a25afc2, 0xcf52d343, 0x8592165f, 0xa4eb3d2c, 0xd4c47dcd, 0xed47b458, 0xced3e37a, 0x8aab9227, + 0x300d0a5b, 0xf3e2551a, 0xd3538344, 0x41fff099, 0x3a4290f8, 0x8d8e6e3f, 0x2a7903a4, 0x62bf0063, 0xaf275e40, + 0xaab804ee, 0x3dffe631, 0xc9282a84, 0xf6bfe240, 0x2b5ce232, 0x9561fcf3, 0x1086ad2a, 0x8152f285, 0x2281029a, + 0x726a8cfc, 0x407612b7, 0xf77437a0, 0x6d0b9a99, 0x901179b9, 0x698414fd, 0x03c481fe, 0xb1d56e10, 0xd13fde38, + 0x0eec8c14, 0x4b5de264, 0x90dd4e7a, 0x8422dde8, 0x05fe3caf, 0xcad16d5d, 0x193762e2, 0x6e32036e, 0x9a592167, + 0x4ad7c5dc, 0x320573df, 0x8849b7e9, 0x686a29d2, 0xcf291c9a, 0x595bf0b0, 0xcd582a13, 0x9febf681, 0x45830115, + 0x5f7bcd89, 0xb60adf1c, 0xcfa78abc, 0x3298eee9, 0xec6967ef, 0x418daf3c, 0x91582f20, 0xbb34c5db, 0xedbb94bd, + 0x3fd353eb, 0x0df79d1a, 0x5c0ea63f, 0xd9ed5dc4, 0x633d9f7e, 0xfa2d65fa, 0x2b42b90f, 0x43ddf13b, 0x8d4b5277, + 0x0a43a4e5, 0xdfd28a99, 0x01bea266, 0x06766650, 0xa31474e6, 0x85d716f4, 0x5f1cd66b, 0xe43bf300, 0x6f888b0f, + 0x23a66707, 0x8f80820b, 0x8d494fdd, 0xfa7237cf, 0xf067058d, 0xe8715b4a, 0xd5560a9b, 0xd88daa02, 0xea041657, + 0xdc199f2a, 0x37651b07, 0xd83bc66d, 0x46a702f8, 0xa63f91ed, 0x23023cd0, 0xa1e3d1be, 0x8b49c7d7, 0xd19f7a66, + 0x5f827b67, 0xcb857ad6, 0xc456d753, 0xa11a34c1, 0xe5f21fa0, 0x538c1350, 0x3d5c088a, 0x1a6fbc38, 0x2b0aeeb3, + 0x4aee349d, 0x9df28985, 0x7eb70ef0, 0x44879595, 0xa23b1761, 0x26ee439a, 0xb607f1ae, 0xc0961106, 0x6f18e9be, + 0x5e4afe9e, 0x5d721b10, 0x7e7a86aa, 0x07542f9b, 0x508e30c5, 0x13324a3f, 0x9bbc2dc9, 0xbb795bf0, 0x1d2f6e0d, + 0xa1fa62c2, 0xe6ed5a2d, 0x294a3328, 0x4f6d501b, 0x44d77f1b, 0x3a2cb8a1, 0xc824406d, 0x90acc3b2, 0x25705877, + 0xd9fc0fd7, 0x4b81a473, 0xe766d1c7, 0x2c5db9fc, 0xa2b9ad7e, 0x2b25f9ed, 0xa7912c13, 0xf5392f1c, 0xc522394d, + 0x35057195, 0x14ac84ca, 0x9d869947, 0xa4db1447, 0xe2d4e80e, 0x8c77fa4b, 0x2cc17a61, 0x7e6ee657, 0xf746cca7, + 0xf7893233, 0xddc8556c, 0x08e5c25d, 0x77cc7118, 0x80909d0c, 0x127eaf38, 0xd1946b2e, 0xef058414, 0x84282e7a, + 0x1c2b0be4, 0x50bc4df1, 0xc355fb74, 0xa36fa5c0, 0xbcaa6a7d, 0x61a360c3, 0xacd319c5, 0x4dd8368d, 0x06dea887, + 0xcd7f376c, 0x2b632442, 0x3d3c1e75, 0x5d29eee2, 0x4fedcc3b, 0xb3424d44, 0x20dc9938, 0x3198eaa6, 0x58c92c7c, + 0x14071fa2, 0xc4b7615e, 0xb120cab0, 0x3f570640, 0x6b6d7ee5, 0x9e2e5dee, 0x5f4f4583, 0x53363924, 0x53e40252, + 0xd8224266, 0x4290aae0, 0x85fe74b7, 0x5776d443, 0x8213177f, 0x2a889f05, 0xf73aafbc, 0xb77f7e10, 0x6daca01f, + 0xc3dc8353, 0xf4f0a8a6, 0x3d12b60e, 0x0f965e1a, 0x3d149d24, 0x1df01d2b, 0x775e92d2, 0x27cb5cef, 0x1dc23b1e, + 0xd4480177, 0x96b68bac, 0x975d1261, 0xc53162af, 0xac6fa53f, 0x43ad7cbd, 0xdb32cf30, 0x32d5fa34, 0x0c6273bd, + 0x581f9181, 0x28824243, 0x57a7482b, 0x4d23840c, 0x9b20187d, 0x8e9ad065, 0x744d2487, 0xe19ff3bd, 0x5aba37f3, + 0xbb40806f, 0x3be8b2cb, 0xb67b06bf, 0x5380fb40, 0x8b40dbd2, 0x71787a49, 0x9e1f288d, 0x08ba0194, 0x75122422, + 0x3d4b4bb0, 0x2bb7c038, 0x202d1391, 0x9182569f, 0x76667a5c, 0x1261b329, 0x94c2605b, 0xca2aa314, 0x11d086c0, + 0xe1af5b14, 0x91d87433, 0x5baba449, 0xe6a48549, 0xd58eb322, 0xa6826780, 0x0f0913ae, 0xd815b39f, 0x7eec348f, + 0x33c12897, 0x5b06f781, 0xcbdbf1ed, 0x20ea3659, 0x7292389c, 0x0d5f5ee3, 0x3e94bd96, 0xc6d8b05b, 0x12c561bc, + 0xe3218733, 0x9ca5662f, 0x305d4967, 0x490c4c25, 0x5826a227, 0x4e74a77b, 0x697bd663, 0x4109bef2, 0x187dda36, + 0xd97637ca, 0x1ce7c995, 0x14cf451b, 0x4e58e275, 0x7318c4a7, 0xdf88c03a, 0x5ccd09ca, 0x1c6c90a7, 0x8ec58cf8, + 0x0910d006, 0xea7851e4, 0x738fe293, 0x0b22cfbb, 0x4c4dd0ce, 0xf4596e78, 0x97680d86, 0x46ce8f9c, 0xa9000685, + 0xb7a23c5c, 0xece55125, 0x3a5fbd1e, 0xc1dd9e58, 0x0f9b14ad, 0x43407efd, 0x271cce74, 0x0aefb8eb, 0x02b6e7a6, + 0x9a75fa04, 0x476e13f4, 0x8ae4e0e0, 0x6de1c27c, 0xf090a888, 0xb565c31b, 0x12ef1d00, 0x822a8f10, 0x27a27f96, + 0xcca2f515, 0x4588dd4e, 0xc597338d, 0xe70ead35, 0x49159b8b, 0xa22c63c3, 0x17a52f87, 0x986275d2, 0xd8edf7db, + 0xe85eec2a, 0x59cd243a, 0xa460d228, 0x924e570e, 0xc2500dfa, 0xc644476e, 0xb6dea66e, 0x45d709e4, 0x9e003f33, + 0x67c89d2d, 0x7e960eeb, 0x9db3359a, 0x849b17bc, 0xd27fa023, 0x539a2e79, 0x4be282ab, 0x67b93420, 0xdb228d35, + 0xd7a0748b, 0x59253ae5, 0x199a8bf8, 0x6232f19a, 0xe63967d9, 0x840f9417, 0xa254182a, 0x2fb0ce6b, 0xcd80ba3e, + 0xda323f8a, 0x69a29380, 0xcc53b796, 0x2b169c33, 0xced3d31d, 0x343c6d94, 0x4ae54c41, 0x184e4854, 0x20c3fd4b, + 0x2ca07ddf, 0xe5f16158, 0xbc512372, 0xc7e82939, 0x73fa8873, 0x97720f46, 0x5b129f30, 0x1272c028, 0x07ea6964, + 0x950d0497, 0xfc4e66fb, 0xe4a05681, 0xad6a41cf, 0x0b5b3601, 0xe55edf4c, 0xa45446df, 0x3ebaabdd, 0xe3b24924, + 0x6d2c3232, 0x788bbfa9, 0xa1dc4264, 0xd1873925, 0x1dcbefab, 0x2355493d, 0x7fba28c0, 0x46974d44, 0x005b5398, + 0x1fac6e35, 0x4c020809, 0xbdd2b7ea, 0xe610f40d, 0x86716754, 0x9d43bb25, 0xa63cd6e1, 0x1f0f46de, 0x6a54048c, + 0x659a12fe, 0xf1223a91, 0x268b24f0, 0x72fb918f, 0xc2cf0bd6, 0xb9de2b5d, 0x6253831d, 0x0009739d, 0xdb5dad09, + 0x6ec1873d, 0x562dc8d6, 0x6a6ce0fa, 0x0239032b, 0x6348a6db, 0xd34dc0f8, 0xd1db9f30, 0x50969b80, 0xc359075d, + 0xdeea8eed, 0x940b52b2, 0xb5c0d74d, 0xca2bf7f9, 0x207bb588, 0x9cafe865, 0xbb88915b, 0xe2c819e6, 0xccaa06bb, + 0x5b20166e, 0x81c2f3d6, 0xf27e554b, 0x23dc6614, 0x2bf22159, 0x95325888, 0x2995dcdc, 0x6d096485, 0xbfa211c6, + 0xe8e5f8f2, 0x18071dc2, 0x22906fac, 0x31d64f56, 0x690668e9, 0xca481587, 0x2080f507, 0xef99cb86, 0xfaa98a67, + 0x7b6f1ab0, 0xdbc466ac, 0x5fdf110c, 0x0c551bfa, 0x60f9451e, 0x33b2beef, 0x13f35825, 0x8d084533, 0x819b3bb9, + 0x02b28a7e, 0x1d895fbc, 0x3bbefb16, 0xece726bd, 0x556eafb3, 0x6776366c, 0xe9e13bf4, 0x9bdd7e22, 0x87892b8d, + 0x5392c402, 0x2765212d, 0x3ea479e2, 0xae604ed9, 0x553498d5, 0xf64e9cf5, 0xdf2b45b7, 0xed43ab78, 0x440d2a50, + 0x66314f41, 0xde517251, 0x36babdd8, 0x6c2c5f28, 0x3499045b, 0x84e94120, 0x5d80a952, 0x22a4ae7e, 0xd287f329, + 0x5a938df8, 0x5e632f26, 0x7aef0479, 0x4caf3560, 0x90f776ba, 0xa644d53d, 0x0f19b20a, 0x761bfbf3, 0x7719c0a1, + 0xf7259df9, 0x4482ac0c, 0x080426ce, 0xd64357c6, 0xcfe257b6, 0x496e2a90, 0x78b20a1c, 0xc6ae833a, 0xc4362d8a, + 0x934a14e1, 0xf67f6fd1, 0xc34831fd, 0xe2eb89c4, 0xee81aff1, 0x0a7e086e, 0x1dde5a73, 0x5010ea13, 0x54bb485b, + 0x408bff76, 0x38f01a29, 0x6e88e191, 0x41e56978, 0x8bf838ee, 0x44ff33ef, 0xce929226, 0x1074af35, 0xc30bd8f3, + 0xd02fba7f, 0x0136da06, 0x329b2c4f, 0xa6a49413, 0x257d79c4, 0x87d552ee, 0xa3d5b234, 0x78886de2, 0x925165df, + 0x3583d84c, 0xe91e2762, 0x5361923d, 0xcd314cc6, 0x3aac19bc, 0xa9176916, 0xdc526ecb, 0x0bbaf2ce, 0xadf2a420, + 0xadcb3ef8, 0xcac1f54e, 0x92b0aa85, 0x3bddc297, 0x13a5ba02, 0x47a8e885, 0xe6967ddf, 0x865e1f60, 0x719a932e, + 0xaa18c18e, 0x60457c39, 0x2418d744, 0x497c9724, 0x74c9747a, 0x83b2eabd, 0xd6d75d79, 0xca6cd83e, 0xbad873cc, + 0x52c912aa, 0x11dc1b6f, 0x05592128, 0xbfde9955, 0xcab08dff, 0x2dd16009, 0x3354abac, 0x60c8acd4, 0xa0a545e6, + 0x56cb6656, 0x7e73ee25, 0xa0627ff4, 0x7e0b04de, 0xeaa7d056, 0xea3bf6e6, 0x663c5f36, 0xa7350b60, 0xaa45fb32, + 0x4be7ab99, 0xca3a0893, 0x5f5b861d, 0x1b88b5c6, 0xe32ca9d9, 0x246187f1, 0x4a896a6a, 0xbbb49680, 0x9071046c, + 0x187037d0, 0xe1e0308a, 0x75f10496, 0xc73a5489, 0x34614c71, 0x7a51b65c, 0x0aebc160, 0x6f35fc29, 0xe5f696b0, + 0x8dc96aeb, 0xb7877930, 0x3ba7e6e1, 0xb9d10d4d, 0x4d613cb4, 0x2d67fa17, 0xdfaa73eb, 0xf3a2121b, 0xfd1b91b4, + 0x3df16e90, 0xd7c00747, 0xb0fbd31c, 0x6a4dd0c7, 0x858dda56, 0x98550dfb, 0x84f5e786, 0x1791cb2d, 0x2c1b8c0b, + 0xcb089b0e, 0x9152b569, 0x634fea00, 0x12541fca, 0xdede1705, 0x1c2dc3b8, 0x219d4bba, 0x43b2ee8d, 0x21243fa8, + 0xfc7b3c05, 0x259b2d43, 0xe9a236f5, 0xfb68439e, 0xd646d8bc, 0x4fb1a9fd, 0x52d1a85a, 0x938a08a5, 0x1ee70041, + 0xa84f4954, 0x6f00f37c, 0xbc7dae42, 0x69d25058, 0x1ba1f4df, 0xa87a3a19, 0xe6ec58dd, 0x4435be34, 0x62069483, + 0x49b42ff7, 0x0c66c57c, 0xa095d6c2, 0xed3d3a8c, 0x728412de, 0x77ff7524, 0x4f50619b, 0x5eaf1699, 0x89ba9720, + 0xd6d48add, 0xc3b9da7a, 0xe5df4c6f, 0x9c3ee8a1, 0xb1b08baa, 0x6cf13226, 0x51885549, 0x2b293f5d, 0x03a82c83, + 0xec30b6cc, 0xee68312e, 0xd538c026, 0x69f1dd4a, 0x4cfb0010, 0x972f6816, 0x6450dc65, 0xaeb2cd83, 0x89bd9ed1, + 0x57c79825, 0xc5a1f535, 0xbf07f67c, 0x6d530d03, 0x805505dc, 0x96baae33, 0x6f8774bc, 0x9c2f6f68, 0x32572511, + 0x66fbf7e8, 0x93ddfb0e, 0xf7e4f35a, 0xc591a5b1, 0x821d12df, 0x1cbc56d1, 0xac3ce5be, 0xe3b4ebe0, 0x95ded049, + 0xcd08bcc0, 0x6b7d870c, 0x3185fa5f, 0xb64eec18, 0xc5fdcda9, 0xad20818e, 0x2546c8ce, 0xab091709, 0x8ab2ffbd, + 0xc4b27431, 0x78d2bcf7, 0x129d5f5b, 0x9fbde066, 0xcec7ecd4, 0xc668591c, 0x980c9840, 0x4e1b4db8, 0x97f3b90a, + 0x3b21c51d, 0x50d8e229, 0xf3a837f4, 0x0cf70032, 0x486c3a1b, 0x2d61c26e, 0x66c1e659, 0x5cd717f5, 0x351d6cfc, + 0xbf5a1a98, 0xa58196ab, 0x45feac48, 0x56c678f5, 0x5279735e, 0xaee7193a, 0x2c3168d3, 0xa3db8eb5, 0x16ca5a29, + 0xb4dcb19e, 0x1e110a1d, 0xd14225d5, 0xf9ddb44f, 0x4eb2a6b6, 0x15d032ee, 0x8e885a2a, 0xdc309895, 0x43804682, + 0xd35f944e, 0x8ba6dd62, 0x352537ed, 0xa9b81e63, 0x366abf3f, 0xb315848a, 0x5bd0b6fb, 0x219da895, 0xcc3153b6, + 0x2df5e8ef, 0xe27d0f1e, 0x0b03063d, 0xbf5517a1, 0x71cdd496, 0x13ce3f2d, 0x378bb775, 0xc21b15a3, 0xad6e8809, + 0xb2e34b48, 0x44ce2b13, 0x1576ee1c, 0x5b24f8b1, 0x3a07cbcd, 0xd2b58ec7, 0xc556c895, 0x96548f56, 0xaae8f393, + 0xb1507f2c, 0xccb40312, 0x635f8ff5, 0x78c22f9f, 0xb96a86fd, 0xfb3e2a62, 0x689ab136, 0x0274e98c, 0x0ed810a9, + 0x581470ab, 0xc87b0620, 0xf9b88438, 0x7162eb12, 0x49c992a6, 0xb1da7027, 0xa5c5f7f4, 0xcd575ecd, 0x17336477, + 0x615d752d, 0x640019d2, 0xfb6a8e0b, 0xd16f7eee, 0xc867799e, 0xe8b839f0, 0x632f9741, 0x047775e7, 0xa4cd652b, + 0x542e0d3c, 0x881e47a5, 0x247bac86, 0x0d91a226, 0xe6eddf44, 0xf1c6c24e, 0x28aa1a5b, 0x42cb433b, 0xc6c1cbe1, + 0xc08b69b5, 0x548056c5, 0xa80ec6cc, 0x432c24d7, 0x42db7522, 0xaa7c0a74, 0x9fda0608, 0x4c571224, 0xabcf1509, + 0x802c3c36, 0x231685fc, 0x69ef1ebd, 0xa1c2d86b, 0x894cf051, 0xd05292c9, 0xdf9b9dfa, 0x20363916, 0x8bcc0a90, + 0x34b2e6e2, 0xa205058d, 0x5669ab5b, 0xd3a2f580, 0x2c30179d, 0x07ff36c9, 0x8fefb513, 0xa666c57a, 0x5785ad4d, + 0xb3acc3e0, 0x824b57a8, 0xbfee4ddb, 0xab542429, 0x146e09b9, 0x35ad69b1, 0x588d0586, 0x03b3f167, 0xcb724af6, + 0xc0e90e8b, 0x428b3372, 0x1fd020ed, 0x968d0955, 0xc54fe853, 0x3f5f44fe, 0x721ee2d3, 0xa574c7e6, 0x6a33a9a0, + 0x2177e8f4, 0xbe1c7229, 0x0a1c7ca0, 0xf1468755, 0xcf139fbc, 0x917aae6c, 0xbc94564a, 0x042bfeb3, 0x7c0f155d, + 0x14f589fb, 0xd28d005f, 0x541ee4e3, 0xb7f0015d, 0x9a98c247, 0x1d3f15b8, 0x1a66f714, 0x9adca9fc, 0x5ae835e2, + 0x568b650f, 0x320905d5, 0x1916375a, 0x9f1671d1, 0xaee009ae, 0x5737cb94, 0x8fba78ec, 0xd2d37707, 0xb1975fa6, + 0x3a7b2eb3, 0xde562d31, 0xda6576d0, 0x2b74d75f, 0x2eb8b0f2, 0xfa48a596, 0x203fe131, 0x3c50bcae, 0x526bfa4f, + 0x87beace9, 0xecdbdb9f, 0xd9dad01b, 0x4fdbb059, 0x30cb7b0f, 0x18c96d09, 0x89fc3557, 0x3850b38c, 0xafa891a8, + 0xfe5100ae, 0x29b2134e, 0x47b1a826, 0x5001ae34, 0x5df386af, 0x7cff9be5, 0x511d46a7, 0xeb6ceaa6, 0x5ff7799a, + 0x9160a46e, 0xe3a59c6b, 0x67a5af43, 0xdd0890d8, 0x308239f3, 0xbeb66277, 0xa0258dcf, 0xd8c34d97, 0x2304dcca, + 0x6a99ac73, 0x5743d206, 0x633932d1, 0x0c2adb0a, 0x107127fa, 0xab3e4653, 0xe188c1d6, 0xe608b9c1, 0x4c91d948, + 0xa313039a, 0x9643a239, 0xe9d5f973, 0x70d78939, 0x0ab16403, 0x74d4a643, 0x15fa1ade, 0x8bed425b, 0xe43cf634, + 0x8d76994a, 0x1534c70b, 0xf7b8ee7c, 0x46f9ea88, 0x364d4d75, 0xe3e3337e, 0x276e9bc2, 0xc3d180d4, 0x768bfbcb, + 0x04139ad0, 0x4dd5a795, 0x109b112e, 0x485c50fd, 0x64f924a2, 0xefd3b50c, 0x7e348e58, 0x2846d962, 0x6b9f780c, + 0xc5e23ff8, 0xb649feee, 0xf2b998c6, 0xb78d3839, 0xcefe83f7, 0x22f4e212, 0x0e7f2d8a, 0x5c3c024a, 0x426505da, + 0xae214840, 0x5db1bc82, 0x5ed5ace2, 0x8e977447, 0x6b47dbbc, 0x7383ec65, 0x42fba085, 0x7a5ec94c, 0x403589e2, + 0xa5e9f9aa, 0x27e87e1e, 0x137ffa18, 0x89fdf411, 0xbc8c24aa, 0xc427ff04, 0x12a2f9c7, 0x13e2dc7a, 0x837a1151, + 0xfe69b35f, 0x2863f572, 0x223f9b67, 0x2115d537, 0x95df9086, 0xc2ff0289, 0x758ed586, 0x82c15a0f, 0xc6e5b7a6, + 0xc88d7bdc, 0x28b02b0c, 0x6ce46259, 0x992b07bc, 0x588f197f, 0xabdfb7e7, 0x23e45897, 0x2ab5680a, 0x571335e2, + 0x4809d78c, 0x9a29d03c, 0x1ba4a1e0, 0x2dec3e3a, 0x4390dcd9, 0x9d463ef3, 0x8dcafb37, 0x71471e57, 0xad207765, + 0x2dc32e13, 0x73bfb5e5, 0xdd1ffa5f, 0xc42ff824, 0x092c8f94, 0x3d2fe256, 0xd31cad1c, 0xbf323044, 0x6821f0e4, + 0xca916e55, 0x10a61f31, 0xb412b978, 0x7f0b1fcc, 0x50c26ad1, 0x7f5de1fd, 0x0b77954b, 0x0d0b3bf1, 0xa79a2c0f, + 0x3445bf8d, 0x0f732ffe, 0x980516b3, 0x03832651, 0x951b44f9, 0x6bd7cee2, 0xef250ba4, 0x3e53148f, 0x49767b28, + 0x0a80ab16, 0xe1647134, 0xc287a373, 0x31512b04, 0xef0b79f1, 0xdeb3cc4e, 0x80a9401f, 0xd7bd9e37, 0x5bf1371c, + 0xcf8f6c9d, 0x690ea36e, 0x46368012, 0x4364d712, 0xabf418a2, 0x488633ca, 0xa4f9bdbc, 0x132faee3, 0x86f045f3, + 0x9d413d49, 0x67205b8f, 0x5bf0fe70, 0x31bed383, 0xe12f06b3, 0x2ffd5e51, 0x11890b16, 0x31ffb037, 0x937a6508, + 0xf01046a8, 0x807907b1, 0xd85c9d7d, 0x0455b142, 0x4621a0b5, 0xf97ebaa3, 0x7e3d5801, 0x22d9e95b, 0xf0b9aa27, + 0x0995af27, 0x047ec046, 0x39183d0b, 0x6bd17850, 0x7456f209, 0x93d68f96, 0x180a22ca, 0x21df769e, 0xb1c89b9b, + 0x07a44515, 0x32f451f2, 0x30fb9fa9, 0x65fa5073, 0x016d99c2, 0x7ae13c95, 0x92d66390, 0xc9d99cb0, 0xe4cf9776, + 0x19172486, 0xbba7463c, 0x64bcf500, 0xe552f2f5, 0x11e76177, 0x5d475838, 0x72d93657, 0x2944bd98, 0xa4f9cd61, + 0x87b7138b, 0xdf04a6d6, 0xa8841a54, 0xdb5dcbd7, 0xd9d18d89, 0x12177642, 0x7853c434, 0x8981c57e, 0x95aa67cb, + 0xaefe44e1, 0x8d674ed8, 0x92b585e5, 0x3356beec, 0x875acf5b, 0x08d8d24e, 0x388b6f93, 0xdfb6c9bf, 0xcc1f06b3, + 0x33e3d4e1, 0xbf2a5e2f, 0x775cec83, 0x3f024a7b, 0x284f0726, 0x8c77e81f, 0x8012625e, 0x0229823a, 0x0e115d70, + 0xd973a748, 0x20213466, 0xb74f1a34, 0x42e1e31a, 0xd016980c, 0x66e673fc, 0x18a9c7d4, 0x81b87f13, 0x380b67ff, + 0x46d69d9d, 0x5d9fdc8f, 0x465fd68d, 0xa5add67d, 0x34ca5da4, 0xcb4db2ee, 0xee2f0a26, 0x206f6830, 0x6ba8b11b, + 0xb6188806, 0x5250b539, 0x74bcc485, 0x7247e5b3, 0xe4f28bd2, 0xe6ea2d10, 0xb5aa7bde, 0x9e95fa20, 0xcdce990a, + 0xd6f0b3fa, 0x56ec516b, 0x2ae3bec6, 0x5ea908fd, 0x674f719b, 0x32d6c411, 0xb28150d7, 0x2a53f9e8, 0xb654a868, + 0x1d5e050c, 0x0339258f, 0xa7cc39ac, 0x2ebcc945, 0x28c8a0fc, 0x139e3b32, 0x6591eb6d, 0xdc55bc11, 0x5ecd0ab9, + 0x86c7c72d, 0x99819350, 0x429c75b6, 0xb67a4d9e, 0xd2583b1b, 0xbdf0bd5b, 0x1acfc652, 0x0d448d28, 0xefeb890b, + 0x88fcb396, 0xde088f32, 0x16660757, 0xdea8b894, 0x9e544666, 0xb5973db1, 0x22419581, 0x377220b8, 0xe387ec1e, + 0xfdec5756, 0xda8dd359, 0x778929c3, 0xf2d151d9, 0x9f2393c1, 0x21a95093, 0x36bbd6a3, 0xc7f8bcef, 0xdcc20fdf, + 0x409f3fad, 0xd97f7e6e, 0xaa7d8c8c, 0x2589e1a4, 0x51b0b858, 0xa9e2ffd1, 0x7825f450, 0x33525ebf, 0xb376e0f5, + 0x47226568, 0x009da53b, 0x1d6fc042, 0x23db9422, 0xa737cace, 0xd70d5438, 0x94deee5c, 0xdb078dee, 0xdeea8910, + 0x973014ed, 0x2d99477e, 0x67b356cf, 0xe2219fd1, 0xd7d613ab, 0xeec1aa74, 0xcf6fa422, 0xdae7489f, 0x819e4787, + 0x6e3f9812, 0xdd2f61a6, 0xe187ea34, 0x0b0f748b, 0x993d324e, 0x2608353f, 0xef644c64, 0xab5f2175, 0x68f19d1e, + 0x680d8d8e, 0xa54012b3, 0x7702c115, 0x149a20ba, 0x864106e1, 0xef5aa8c0, 0x04266662, 0xacb0c546, 0x2a8cc274, + 0x0e764395, 0xb744f026, 0x88466268, 0x377708ea, 0x6ffcaa5c, 0x61236969, 0x92333bee, 0x7a44f450, 0x5a8da650, + 0xd41b3f38, 0xa68cdb7c, 0xf272a0e6, 0xbc3bbbf9, 0x6b29f0ad, 0xcf7a73a8, 0xbafa6c37, 0x236b5f08, 0x3970eeea, + 0x9dbdf9c7, 0x05227107, 0x02ce0cb8, 0x8f57305b, 0x8b87b465, 0x2d9d683f, 0x1b1461b7, 0x08e39311, 0x47f7b65b, + 0x3298013b, 0xd16f92ca, 0x98ebf21f, 0x98c236c8, 0x66a8d4ed, 0x2f2ffdaa, 0x352a27ec, 0xf4d7a3df, 0x10d0f9f8, + 0xb542a452, 0x0a104822, 0x8669c006, 0x6780bd28, 0xdbcdfb56, 0x3ea8695c, 0xdfe52b40, 0xec1c0320, 0xa49d8450, + 0x34a8b856, 0xbcfb2c90, 0xf3b26f9d, 0x890f19eb, 0xb642fbc5, 0xb7913719, 0x7c16d299, 0x1216522a, 0xc5da260b, + 0x87318ae5, 0xa65d87ac, 0xa0e3968a, 0x7084f982, 0x1d771208, 0x359507f1, 0x1af0a1f9, 0xc5d1db29, 0x42b38dd6, + 0xa34cffce, 0xec9b439d, 0xcaab294b, 0x81519c53, 0xa098220a, 0x3c3a062f, 0xa0e1abaa, 0x71bd4062, 0x7c5a8d6f, + 0x95a56a8a, 0x6ce6a8c3, 0x21dbca7a, 0xba0b43d2, 0x94b21a10, 0x9d51a8e4, 0x0d701c1d, 0xcbfabb9f, 0x7062038b, + 0x8eb36819, 0x38e1a3c4, 0x958b6650, 0xcdfb30e5, 0x3334f6ac, 0x0990f7ae, 0xc495c5fd, 0x061bd2a7, 0x4e2c2a97, + 0x4cb7f7a6, 0x579a5713, 0x1463a4d8, 0xa77efc81, 0xbdffdfdf, 0x84ae79db, 0x0e927494, 0x9d514949, 0x1e07fd0e, + 0x6c8e6f66, 0xf5f86139, 0xfec16e9d, 0x4bf1618e, 0xad707c66, 0x2952021b, 0x9df3fcae, 0x8002f2b4, 0x13551ae8, + 0x4880bcae, 0x62efd56f, 0xfbdd0de3, 0x292238d3, 0x01a578b9, 0x3ff63962, 0x53eb0725, 0x793a7c23, 0xda51fed5, + 0x61a1b4b3, 0x706b986b, 0x52224c32, 0xca86b28f, 0xd3576e64, 0x452db883, 0x0ea6d0da, 0x1d7caafa, 0x6b3f1080, + 0xafe60150, 0x2a9f525b, 0x35272f4d, 0xdd70cc41, 0xe7713c94, 0x8b27c42f, 0x2ff80a90, 0xd04123ef, 0x0de33f8d, + 0xc12d0e8f, 0x1dc1e554, 0x721c1bed, 0xdffd47ed, 0xb971d89c, 0xafafcaba, 0x42338468, 0x91243cfb, 0x20d2695c, + 0x29cd3bde, 0x1b70684c, 0x3f9525c5, 0x9d6c4486, 0x2ea3ee40, 0x317515e5, 0xb8dcd3d1, 0x2df29b4a, 0x20fb6a42, + 0xe7dcda68, 0xec1eab1c, 0xa5700abf, 0x683b12e5, 0xe09ff354, 0x2e55a9dc, 0xf8b47f59, 0xe041f7b6, 0x47b94c25, + 0x94f176d2, 0xc780195d, 0x4019aa88, 0x1aa5cc43, 0xfbad1714, 0x85b352fe, 0xfed6f7f3, 0x016e11ed, 0xa1ee70f6, + 0x8ceccaf6, 0xba0400c1, 0x125d7bb5, 0x86d6adad, 0x04d59df1, 0xf3b69246, 0x07a22da6, 0xd91919c8, 0x45ab454b, + 0x63b6944f, 0x7b9b624d, 0xcd89b1d8, 0x1f8d4ae8, 0x4eb8d15f, 0x3e8f3d4b, 0x4eed6fee, 0x86a08a68, 0xc67c4436, + 0x45861a57, 0x18a06ad3, 0xc7e3afb5, 0xc8241841, 0x1e9e9fd7, 0x14229995, 0x54409848, 0x492a625b, 0xe5ac21f9, + 0x9d474cc6, 0x826b86b4, 0x0cfe542a, 0x6198e388, 0xf963a4ad, 0x40ec21bf, 0xaa356ab2, 0x54c7b456, 0xe4847684, + 0x08890545, 0x90c9d137, 0x8d4de5b8, 0x44fdb5a0, 0x6236a406, 0xe24401e9, 0xd69bc87a, 0x8dfb901b, 0xe31c7e2f, + 0x7ced3016, 0x23fab4d1, 0x2b4a36c2, 0xfbaacf9f, 0x6ece946a, 0xfc9b034c, 0x6afc4436, 0x236379b3, 0x5e4080a1, + 0xeb36943b, 0x48ed25e1, 0x95897c11, 0x2f4a7bc3, 0xd66ae792, 0x6648f76c, 0xe8772124, 0x84c812d3, 0x16e9114c, + 0x6a629a7b, 0x516c6ee4, 0xd9869664, 0xdf7c83d9, 0x4a4952d0, 0x4b24c37b, 0x99a25357, 0x8ccce064, 0x41fa38c2, + 0xe2cdc564, 0xf6afca4c, 0x442e2058, 0x9f70ea59, 0x67213abe, 0x63b7c478, 0x443c2249, 0x961eea24, 0x6ee38f72, + 0xcc0f3d36, 0x6009a727, 0x429e10eb, 0x5dc3dc07, 0x712a1dcf, 0x48cdabaf, 0xc74809a3, 0xe911fce6, 0x5899d30a, + 0x9729c3c3, 0x2f50e07d, 0x4b863302, 0x832b8f79, 0x364a1ea6, 0x9f88a4e3, 0x501e6b73, 0x37534580, 0xec444094, + 0x8b694b2d, 0xc3c5967f, 0x3cd62128, 0x0eef3120, 0xa3eca66a, 0xf2685ebf, 0x75eb5086, 0x915825f9, 0xb4b10421, + 0x5f851e29, 0x2ba17086, 0xfd6dba02, 0x1eac01fe, 0xfcb1e958, 0x18267f16, 0x0b2caa63, 0x9136a578, 0xb805a5b1, + 0xae546083, 0x4bdbed1a, 0xaf322cd2, 0xdcada3f8, 0x55a20ea7, 0x612d9ac2, 0x177427f6, 0x9ce87b74, 0x7b762fba, + 0xf3054b85, 0x0ab79614, 0x5997b2c2, 0x278d4fc7, 0xdae3d8cc, 0x8b2e6bcf, 0x4d7f66fb, 0xae5627b3, 0x81757ea8, + 0x61908b37, 0x8105d02b, 0xd6374b55, 0x5987b722, 0x9b41dd72, 0xe61dd2e2, 0x26da7319, 0xc402bb91, 0x83d26a44, + 0x3a6fa0c5, 0x50fe4095, 0x9a916ac5, 0xf770c767, 0x587635df, 0xdb4f3fd0, 0x0267f57a, 0x16ef0a6d, 0x3940ba3c, + 0x714bf64c, 0x86a27290, 0x32df9cfa, 0xf08a7fd0, 0xcd398625, 0xeaacb221, 0xce4ea29d, 0x924f4faa, 0xa3c26f5e, + 0x9bad1ff9, 0xf935837d, 0x4ba376bd, 0x073cbbe4, 0x32fb23f1, 0xd1ffb97b, 0x54fd1722, 0x0be14a56, 0xe81afafd, + 0x6d8d4f06, 0xbc4da069, 0xd13f5608, 0x275f4567, 0x3d94029b, 0x9dafafa8, 0xb7fa2a15, 0x29968f0f, 0x9a243153, + 0xcd45ecb7, 0x1afef119, 0xf42f6aaf, 0x189c7139, 0x653c698d, 0x4fe82f06, 0x3fb61632, 0xb2c8a9e4, 0x28adef4f, + 0x795d3187, 0x273d2188, 0xc79f7ef3, 0x772907a3, 0xe5b53348, 0x8daadf19, 0xdb7e0251, 0xe12d90b5, 0x67d654c1, + 0xa5d33029, 0x80d9bfaa, 0x5c020925, 0x46377998, 0xc203828d, 0x0c86d356, 0x215ffa1a, 0x6426f19e, 0x5ae7defa, + 0xf74b0109, 0x13b1a39f, 0xe016e983, 0xb7dbb8d4, 0xb2c8be44, 0xd4743c0c, 0xb076d99f, 0x1275a179, 0x31fc346a, + 0xa345dbf8, 0x451e8815, 0x78e7168e, 0xfecb5d24, 0xd5aa79cd, 0x4d98f388, 0xc97064c7, 0x0ba1740f, 0x007e134a, + 0x8bf94b26, 0x22be930f, 0x9e25e2a7, 0x7def7b13, 0x0c299653, 0xc4594474, 0xdcd58468, 0xdcb0cd7e, 0x6955df97, + 0xedb53e5f, 0x5f54dec4, 0xbadace80, 0x709f2c83, 0x7ed4c2b2, 0x5497de48, 0x823bdf62, 0x5c957d47, 0x1bb8250c, + 0x70ac12d8, 0x4619f530, 0xe0391e23, 0x30efb553, 0x2355366d, 0xd05a6177, 0x041d51f1, 0x5b95cc7a, 0x44ec115c, + 0xb213bb52, 0xe69ae825, 0x04ae56ca, 0x10e63397, 0xa66f215a, 0xd319e0df, 0xd6303b40, 0xf1d6402b, 0x7eaf99c9, + 0x1ea921c0, 0xd0aefdaf, 0xe9b58ef6, 0xba7931b6, 0x3b08ad61, 0xf8473284, 0x77f92308, 0xb04560a3, 0xaa13626b, + 0x6495b941, 0x38727ddc, 0x6e06e67f, 0x9863eb35, 0x75911b17, 0x0263fcd0, 0x5761c4e1, 0xdcddd274, 0x182066c6, + 0x926b145c, 0x568b656b, 0x3f770d29, 0xa99a9d6e, 0xd13dcb9c, 0x7d79f4bd, 0xe7eeee49, 0x46fb555e, 0xd4047162, + 0xa4ddc000, 0xd5829b4f, 0x812a2d73, 0xe289b15a, 0x747a56a7, 0x91b1df48, 0x6123a866, 0xe04ac87e, 0x34e8779c, + 0x43ff129f, 0x4da05b97, 0xc01a61e1, 0x3af67886, 0xcd313501, 0xbc71c7ab, 0x753eaa1d, 0x62d6be01, 0x123a0e61, + 0x1f6fcd79, 0xf196cc92, 0xb533d61a, 0x19ebef3f, 0x7f84f9cd, 0x93abd260, 0xef869e7e, 0xc21e2c2a, 0x8dd62aa5, + 0x051159d2, 0xed22b817, 0xb3caa05a, 0xe1a3d3f6, 0x0576911b, 0x414ae706, 0xfcc620ca, 0x8837ab64, 0xb7bca23d, + 0x70fa8782, 0xce1b4dbd, 0xd4404452, 0x9cd2a7e9, 0x7b67f49f, 0xbe0af395, 0x406d2d00, 0xbd1a0b56, 0x580607c3, + 0x48bc7967, 0x174ff9c0, 0xc0a31a29, 0xa7f89d1e, 0xfa3d3e13, 0x3d8e9207, 0x19713080, 0xe0c5dcdb, 0xb06cd3e4, + 0x5d5b5986, 0x8e9f56c2, 0x85bb9cba, 0xec901028, 0xe0e15da3, 0x1596fa11, 0xa50fa2d2, 0x299cdc46, 0x9fe2dd9f, + 0x9ba5e422, 0xa6c6f2af, 0x04aa1bde, 0xead67a38, 0xd2388d09, 0xc90489ee, 0x8e682424, 0x8e65d5ab, 0xe93b4b84, + 0x7bb15d3f, 0x80393aea, 0xdbd15193, 0xa6a9ed63, 0xcb8e16f3, 0x1fa44e64, 0x317e0b4e, 0x502f18ec, 0xaced8668, + 0x457327c8, 0xcd2d2622, 0x8ae6729a, 0xd944c913, 0x6a6a3c6e, 0x6b0506d2, 0x2ce5f18c, 0x51b056c0, 0x53682d60, + 0x609566fb, 0xd312d4a4, 0xdae32d41, 0xa51851c3, 0xc3309111, 0xd7327a3c, 0x3c2e6e1f, 0x8655e89b, 0xa7e37528, + 0x5bd5f568, 0xe461c20b, 0x73778a20, 0x720ed373, 0xa0020b56, 0x6b9c5790, 0x0859c46b, 0x2008857e, 0xefffc471, + 0x1fca1c63, 0xc078114c, 0x3fb599fe, 0xe4c11a13, 0x2c5e190f, 0xa565bf6e, 0xc826e940, 0x8ccdb891, 0xd42ef800, + 0xc54c5ee6, 0x7ef5ad31, 0xc8abaab4, 0x7596575c, 0xea669d75, 0xa7b49b8e, 0x67695b44, 0x1cb8539d, 0x4fdd8057, + 0x3590d8a2, 0x86075eb9, 0xee53e680, 0x7ef6589f, 0xd1331088, 0x95b5edff, 0xce100d23, 0x45ceefde, 0xf0703990, + 0x094a7cec, 0x198eedd9, 0xc867813a, 0x330cfd36, 0x85b60396, 0xa5d4d3cf, 0xf56e546f, 0x2a62b90a, 0x916101ed, + 0xf849f9a1, 0x8f3792d8, 0x6d473d27, 0xd16a7fa4, 0xdaac9f32, 0x835e245f, 0x3e83371e, 0x1f3c22df, 0xeb8e1a0e, + 0x9bfce31c, 0xf152f41e, 0x9b64e7b9, 0x5e84ceb6, 0xfdd4dccc, 0xcd1705c5, 0x3164f81c, 0x3c31d21b, 0xff7b40f0, + 0x09988a56, 0x3d02fb84, 0x3b2733d5, 0x20402d52, 0xaa3f27e7, 0x8af30ea1, 0x9755fc2d, 0x826c0b3e, 0xd965db97, + 0x0d34dbb6, 0x609f0368, 0x25b77279, 0xbc08a80e, 0xadb7206e, 0xedfbedc1, 0x69c6d155, 0x34ec35be, 0xfe72dfd3, + 0x3ae3ca96, 0x5c23d963, 0x481488bc, 0xb42fa889, 0x28cd02d1, 0x7ad8b68f, 0xe392a421, 0x61fd3d1f, 0xd4007a8b, + 0xaa7405b1, 0x6040e025, 0x31a31d24, 0x864394b9, 0x41011e9d, 0xa1ed4ba0, 0xd901f5cc, 0xfad186de, 0x82ba6ba5, + 0xe5e17201, 0x2f83aae0, 0x784af845, 0xd0eb4fec, 0x517bcbfa, 0xe3821029, 0x2124c311, 0xb2033d67, 0x9bad310d, + 0x99ca7d75, 0x64adf1c2, 0x9293f028, 0x6412ddff, 0x1d362153, 0x6fde41b6, 0x84f0c05f, 0xf1358326, 0xd38404f4, + 0xf835fe3f, 0x9343582e, 0x7a342fa8, 0xee4f6a97, 0x3d5b9bbd, 0xdacd760d, 0x2ecc9a42, 0xf0a74246, 0xe14acad5, + 0x6024e30f, 0x0bfb5b99, 0x8fba66b3, 0x52223aec, 0x1ee8a6d2, 0x882ca396, 0xa9e1d741, 0xb9300222, 0xa9fd191e, + 0x037194d0, 0xc8313419, 0x6624fe43, 0x55d97d35, 0x18a5f545, 0x47dfbb6d, 0xf71c12a5, 0xaf05ae59, 0xa3f81aba, + 0x0e2efba9, 0x05a1d7d4, 0x4cc27cff, 0xe4235af1, 0xcfe2849c, 0xca25a85e, 0x79a1503c, 0x507537fd, 0xe3a6e567, + 0x62ae40da, 0x2f0f6d30, 0xabd80182, 0xfd1fbdfe, 0xf1dccd36, 0x2510ff2f, 0x1fab5d5d, 0x1bd2f5be, 0x5589159f, + 0xa457f6f0, 0xb2bd103e, 0xa51e1f31, 0xd7dac836, 0xbac4260b, 0xf1e26216, 0xc746a9fb, 0xfeb4466f, 0x9644ec65, + 0x62a51e8d, 0xe62444e0, 0xccb7e2d7, 0x1a8cf62e, 0xc72d6a8b, 0x9b2f6969, 0x886da702, 0x996bd95d, 0x2ab0fbc5, + 0xe9bfe374, 0x91dafcb1, 0x475c2f01, 0x47090257, 0x1077444f, 0xec433e11, 0x963a62a2, 0xc45a1082, 0x30a51126, + 0x36135577, 0xcc224e23, 0x15ea78e7, 0x67b3deda, 0xc26cc5f9, 0x8f721dfc, 0x944e8a38, 0x0c2247a6, 0x1948046f, + 0x41da510e, 0xc9a5b01b, 0x1501ec22, 0x08f2159e, 0xc9a9b07b, 0xefde7ed0, 0x97ba9c65, 0x8ce11030, 0xd3f409bf, + 0xecc32768, 0x0ed40be2, 0x32f57fc0, 0x83e4ff70, 0xd5795cdf, 0x5cb5a1e4, 0xaf4b138d, 0xcb09ddf0, 0xfc9f898c, + 0xc4a037d9, 0xe7f54ba1, 0x341ecb58, 0xf7a34da7, 0x6e7754a2, 0xb5cf78a6, 0x34d2872a, 0x68e854cf, 0x40525a4a, + 0xbc0a7799, 0x1da2d5a3, 0xd990c0de, 0xb882e6c8, 0xd83ddfc8, 0x4b759498, 0xb4b6763e, 0xa9790bb6, 0x2628d4d2, + 0xbf2bd20c, 0xf66860b1, 0xc6cbc802, 0x588c0397, 0x380da303, 0xead86a5d, 0xa291b220, 0x4bd539ea, 0xdbefe267, + 0xf8a6f85b, 0xa9f373c7, 0x91bce619, 0x8f9ae845, 0x396f072e, 0xe4ea0d9d, 0x914cf9db, 0x213d5e3f, 0x7459af57, + 0xcaa8d62a, 0xa3e8e28c, 0x36b0329e, 0x78597895, 0x12548aae, 0xe5d0c760, 0xce23ebd1, 0xdc9aec60, 0xab07e150, + 0x817145d6, 0xdb40e232, 0xda8cd7bb, 0x3427bece, 0x989b6345, 0x4f357ff3, 0x45e7839e, 0xc1a5aed1, 0x6d321e27, + 0x5b203914, 0x8cc5e729, 0xeae429ba, 0xe59ac33a, 0x3df96616, 0x49c9cc1c, 0x4b4c7cbb, 0xd12e9067, 0xf4167d76, + 0x9c89a31b, 0x78eb8055, 0x9cc51533, 0x585351d2, 0x42ee7f48, 0xf2176d5c, 0xa6083c27, 0xa313838b, 0x81321f1b, + 0xbda6156b, 0x2a203cb0, 0x0a6a152e, 0x3dbf2c21, 0x88505a71, 0xddde2c40, 0x2d556855, 0xbf200017, 0x772d82b7, + 0xa760ba1c, 0x5279f817, 0xf9621d7f, 0x7a408d0b, 0x9ea1a30f, 0x1342a871, 0x0b585fee, 0x32a8d672, 0xb1c6d993, + 0xac4eeca0, 0x07b15a47, 0xe110f7d9, 0x3394d429, 0x035e80d8, 0x81868436, 0x10b64c43, 0x8309b75a, 0x9b9499d9, + 0x631e2037, 0x017a083e, 0x88b690f4, 0x6ea68537, 0x26c13441, 0xe41fdf64, 0x53f66987, 0x36ad6d1f, 0xc9687d33, + 0x785944c7, 0x42190c54, 0x57a62a13, 0x7ff70ab7, 0x5fcc4557, 0xd7094549, 0x71e90ce5, 0x866bdf20, 0x6d7cda46, + 0xf13bc018, 0xf1c185cb, 0x27bc150e, 0x19aa890b, 0x519fae49, 0xe9e8d443, 0xce085abd, 0x45d93012, 0x6e190e9d, + 0xad66deb3, 0x70658328, 0xc405dc35, 0x91a131da, 0x4b9b2e4a, 0xac8fe58d, 0x89023707, 0xcda1e005, 0x5ed60d47, + 0x033cd5c9, 0x511f76cd, 0xd0d9315b, 0xf16f50a1, 0x8034df31, 0x372eb6e1, 0x7d10e75f, 0xf2e579d1, 0xa93fb8b7, + 0x5265e07e, 0x8578b3ee, 0x92fd01c4, 0x4c241a67, 0xad02eefe, 0x7a289411, 0xa1b3efc9, 0x65abdc6d, 0xb3e2edd4, + 0x3560b8d4, 0xcfc6b19c, 0x04638952, 0xc54c3c59, 0x09815806, 0x293536b6, 0x6f04fdac, 0xfaeb28ac, 0xb6f6227f, + 0x9e7f8ce7, 0xd6e23958, 0xe5576c38, 0x340af718, 0x0d5542f0, 0xdb98ad0f, 0xe7e30a33, 0x067f42c4, 0x88a877f5, + 0xc9e556d6, 0xcd431733, 0x96c8916d, 0xc14d4ce5, 0xeb253b4c, 0x2b1aa9f9, 0xffe0ad54, 0xcd9169fd, 0x6460f78b, + 0x46563c0b, 0xd600a909, 0xab43f077, 0x784e0756, 0xf7604544, 0x9a78804d, 0x8d7106fd, 0x1388315c, 0x9448b04d, + 0xaf585e22, 0x83c9819e, 0x0dd4ba65, 0xd4ff8991, 0xa92f7841, 0xaf655670, 0x28a37ae4, 0x26ebb40f, 0xe008b66f, + 0x293680b7, 0xdcb2ab98, 0x6b2a6368, 0x085d8b38, 0x0664777b, 0x5040b86e, 0x49bc8fbd, 0xafa83f0e, 0xbeec8014, + 0x33fb12a8, 0xc6b1e2e2, 0x332ca6ec, 0x5eb95714, 0x63b57f4b, 0x44608c8e, 0x0e1a8ca7, 0xa3489102, 0x1ec46b90, + 0x5aa6e7f3, 0x7ba514b7, 0xde024279, 0xd23b4971, 0xd5a22f31, 0xacc15a30, 0x3f4fd9ff, 0x31be11c6, 0x1cb4e09f, + 0xca8fcaa9, 0x394f2f7b, 0xe813b39c, 0x100ce069, 0x843348b7, 0x814ef384, 0x6211238b, 0xe9c7201e, 0xb243eee7, + 0x9c1eb7b0, 0x30bc486b, 0xba20a99e, 0x1c97a267, 0x0920435b, 0x4ef53a27, 0xa77acf3f, 0x109993b1, 0x6c14defe, + 0x074c88ad, 0xae0e0b0b, 0x1415c33b, 0x17679a3b, 0xfec4ac26, 0x48a75239, 0x29716651, 0x100bf73d, 0xacae1209, + 0x1dfe7d04, 0xe5c70094, 0x249ba882, 0xc5a319d8, 0xaa2721f9, 0x087d5178, 0x55d075ea, 0xd666614f, 0xfcc70abf, + 0xec552acb, 0x60a5daf6, 0xf11148e7, 0x863b1316, 0x88c0524c, 0x88a5564b, 0x42a4d8ca, 0x63c4b28b, 0x75089a6a, + 0x919b0af7, 0xc7d7bed0, 0x2998f810, 0x693fa711, 0x0b1ea0f4, 0xce3c0ec5, 0x81759012, 0x529576bb, 0x52e7df86, + 0x298f049f, 0x3b7d7131, 0xb2a6a0e4, 0xef5369db, 0x9d75f3b8, 0xc46e1097, 0x2a0b204f, 0x2752397a, 0xd8f2bdaf, + 0xc5e8d199, 0x5fe6bc1c, 0xf5e36955, 0x293cd0ca, 0x3961688d, 0xd0bad3c3, 0x4bdd65b0, 0xc16fd7a0, 0x5e74247d, + 0x6fe725b5, 0x4ccbc149, 0x1e39358d, 0x70a17a8a, 0x129622d0, 0x74f53ecd, 0xa468b16b, 0x13251879, 0xcce51cc7, + 0xb8ea289b, 0x3cfc253c, 0x69902518, 0xc06e1e1c, 0x141f66bd, 0xa8a88948, 0xc967fe33, 0x01deb415, 0xdd05258f, + 0xaff86682, 0x2bde1f52, 0x7737ba64, 0xe8850fb8, 0xa4d773b6, 0x550419b6, 0x48e9d7e1, 0x7d7c0107, 0xe9f89146, + 0xf4a91617, 0xbf524d80, 0x84c94f46, 0x9490fa3d, 0xaad97db5, 0xf0bea312, 0x8c6fa402, 0x7190e04f, 0x5bd07289, + 0x8dcc7f3c, 0xe31c0727, 0x94033395, 0xe2c25339, 0xcb40a5c0, 0x51f5d749, 0x96c0a922, 0xbf94732e, 0x50f23049, + 0x0452fba7, 0x5f3af142, 0x2a4635ef, 0x37d415ba, 0x45b2a351, 0x8d309b9f, 0xb83ff7cc, 0x1bb777ce, 0x0000d182, + 0xa6f3200a, 0x4d68884a, 0x706c1564, 0xe8e79986, 0xd1fa1d9e, 0xcd969703, 0x255bb690, 0x124af4aa, 0xc55e9197, + 0x9d1374a2, 0x7f7b3ec4, 0x6f5c30a9, 0x511d60f4, 0xe0176f63, 0xc2683b75, 0xf32e097e, 0x2fa68570, 0x0bcec010, + 0x198caf59, 0x69d75bac, 0x51bfec85, 0xa1896c34, 0xd0ffcf84, 0x4e4b843f, 0x00ace9e3, 0x38ebbb4e, 0x6c655483, + 0x3b06dd64, 0xd5e71994, 0x472ed3a3, 0x677f6016, 0xeda5ea4a, 0x364b3b92, 0xf8571082, 0x7bfad0d0, 0xf6e7f49c, + 0xd809148e, 0x920270aa, 0x67811c09, 0x0fb2f6bc, 0x9e5e20fd, 0xc40d0045, 0x0a405270, 0xbfb6c632, 0x417346ef, + 0x27ffd828, 0xc2b39260, 0x74744b7f, 0xb915ec02, 0x3c590a9c, 0xa71cbfc4, 0xb29cf832, 0x18ac78e7, 0x6a94ae80, + 0x16db51cb, 0x6b0a5ca5, 0xe67f94ac, 0x40f01607, 0xae638993, 0xcf58414f, 0x791476ce, 0xc63f9f73, 0x6df328ed, + 0x629dae1d, 0x9678de19, 0xe7102aa8, 0x98221cc1, 0xb3d846d3, 0x73b0e5df, 0x3e405c94, 0x85b97919, 0xa043c7c6, + 0x395a6880, 0x17dc2165, 0x35d6c554, 0x5b8bd6e4, 0x870bfb78, 0xfdafeb4d, 0xbf3481d4, 0x57bcca7a, 0xcfc5464b, + 0x7846e66a, 0x92dd863f, 0xfd215362, 0xbbe5196a, 0x5067c611, 0x22920b82, 0xb397878d, 0x653546b2, 0xc81bc372, + 0xc45764aa, 0x927303e5, 0x184448a8, 0x198da626, 0xd8a1d875, 0x36adb20c, 0x8d32a756, 0x8bb7e2e7, 0x323b8084, + 0x9383b338, 0x601d803b, 0x5a233b88, 0xdc420643, 0x4f041954, 0xbd4f1c97, 0xdd559808, 0xcfa5071c, 0x7e480129, + 0x43d34bbe, 0x245d5c73, 0x4d4bd92b, 0x9a86bf52, 0xac80dfbd, 0x9b6cdd07, 0xb08093e0, 0xb7110fee, 0x1a569e72, + 0x5c50d536, 0x66f228d4, 0x8bc1f4ef, 0xd300feaf, 0x7fbfb3e3, 0xe44a4e90, 0x6268544e, 0x9bee4a5e, 0x2b5f7acb, + 0x0cf1be18, 0xe2ad518b, 0x7b01401b, 0xfe215c02, 0x44c9eba5, 0x48a2a4c6, 0x78ca1064, 0x2e6dade4, 0x9662e63d, + 0x2f255ba0, 0xadb4b3de, 0x2c6351f5, 0x1cfd39f1, 0x623c7107, 0xfd3d0755, 0x8e0cb271, 0x518f33ac, 0xc57d8cdd, + 0x23bc9e56, 0x9896c13b, 0xd01e3808, 0x43153b62, 0x75f582e5, 0x20594d0c, 0x52ca3240, 0x24cc8823, 0xc7418ecf, + 0x51502b2b, 0x1be6428c, 0x7afb9fc4, 0x68028fd3, 0x3c6fc006, 0x1a1a8eb6, 0x2eb76e1b, 0xff29b24f, 0xeaa3eddc, + 0xe375a8a7, 0xd46102cf, 0x74874901, 0xf1e0e8bc, 0x72b2742f, 0xebebce3d, 0x96ab33b4, 0xf82ca324, 0x13d0d425, + 0x6cb1e929, 0x2cb50d6f, 0x373b9f71, 0x6596dcf3, 0x4df2bbe9, 0x215c7833, 0xdc7e1354, 0xf6dfa6b8, 0x862a405c, + 0x0dbd390d, 0x3a571900, 0xeb564baf, 0x831b1a97, 0x4e7d41c9, 0xdf0bd44c, 0x2449d05a, 0x6b3480fd, 0x24f1a687, + 0x03e0dfb4, 0xd42d2284, 0x4828493d, 0xcf36415b, 0x506bfe10, 0x5a8021d8, 0xc81c30c3, 0xea677c0e, 0x8d151de9, + 0xd10f4669, 0x99034102, 0x1930d43a, 0x53dcc026, 0x143725d6, 0x02b05374, 0xc6691e4d, 0xe136f628, 0xe7bef585, + 0x5527f8ee, 0xc24bc159, 0xaf3f17b2, 0x8ba8dd84, 0x24041a2b, 0xcbb03787, 0xafe98e36, 0xddadb848, 0x128f1901, + 0x9f422a3f, 0x5e786b47, 0x6b25bc4d, 0xb8e71aa3, 0x300ff0c7, 0x6a17e839, 0x5431b933, 0x2e7c4f76, 0xddfb68db, + 0xbd109d68, 0x9606e3ed, 0x2b306893, 0xead9723f, 0x6a5a5bf6, 0xf35e4267, 0xb2c9b7db, 0x24cae828, 0xc13d094f, + 0x3b2d4e87, 0x39aa6b6d, 0x1b2514f1, 0x7d1c87af, 0x1b3bb232, 0xb4c22f31, 0x2a14320e, 0x6b5d63b9, 0x901cfd29, + 0x388d2577, 0x44fcbd94, 0xd9b75eed, 0x0347ea13, 0x5cf8c0f7, 0x02abdfed, 0xc10170aa, 0x0bbd52f9, 0x13040434, + 0xd5d207a4, 0x43181e8e, 0xf4c5ff0c, 0x6a30e9e4, 0x069fecb9, 0xa415d0fd, 0xaf8eb05e, 0x4e2b1297, 0xcbd73776, + 0x07410a80, 0x17d97648, 0xfb7115b8, 0x654e9275, 0x225f8a70, 0xef2871bd, 0x4baf1675, 0x70f3852c, 0xb979b2fb, + 0x10da362e, 0x6e42e816, 0xeef496db, 0x5ebe449c, 0x2ad867f9, 0xeb3a2ead, 0x712a9f02, 0x43a593a5, 0x92847ae1, + 0x7ad0776f, 0xc3f5d35e, 0x2c4dc20d, 0xceb8d530, 0x0fbb7922, 0x322df2bd, 0xaa9cbbdc, 0x4c34da5e, 0x9171faf6, + 0x3dee4281, 0xe99110f1, 0xa54474c1, 0x08ce0881, 0x390559d0, 0xab300dab, 0x8ffb9e9b, 0x9c956e8a, 0x3871d513, + 0x95a93030, 0x23c60e0d, 0x3a5ef20a, 0x7dacf0fc, 0x5f4c340d, 0x4509a776, 0x8a5e99d9, 0x9c012a78, 0x1212b75a, + 0x986d774f, 0x84f29479, 0xbf4781ea, 0x4b617f59, 0x26505815, 0x99cb5956, 0x3063cbdd, 0x6b7fda6f, 0x41d43a1f, + 0x3c361700, 0x85ceab50, 0x21af1917, 0xf2bd0a66, 0x03275879, 0x8e55388f, 0x2719b145, 0x070ad351, 0xcaf5751e, + 0x56c63122, 0xe19a0891, 0xbe725741, 0xa896a868, 0x61990aee, 0x60dad649, 0x566ac8a4, 0x4ef12d2e, 0xc5b2940e, + 0xdd2a7d2a, 0x3b386c1f, 0xcb7b6922, 0xda20c76e, 0x7852ddc5, 0xd6bdad59, 0x411c2808, 0xb989b24b, 0x28f869b6, + 0x0a6cc8d5, 0x9d0c4d3e, 0xaf113582, 0x4bae296f, 0xd87d41ce, 0xc48dd731, 0x63e573c9, 0xca4aa404, 0x420b2332, + 0xb8375fab, 0x939b9549, 0x32d31e7d, 0x861ff80b, 0x20a4bb66, 0x78bf3604, 0xcce42a65, 0xf2af533f, 0x7b2cfd85, + 0x6a60b01f, 0x380fb297, 0x12cf4bfb, 0xd6d5b8cf, 0xdcb5533c, 0xa225de7c, 0xcebdc1a6, 0x37d53fa8, 0xacf87f47, + 0x8d80dc44, 0x87cf6aae, 0xc7878278, 0x0b923942, 0xf8f88d3e, 0x4f0fb248, 0x28924222, 0x7329026b, 0xe657be1e, + 0x123199ea, 0xdc5c856e, 0x48575773, 0x950b4580, 0xc5cd09ef, 0x58f80a08, 0x75bcb400, 0xbf9d9fbc, 0xbd228857, + 0x46cebf90, 0x01dd7197, 0xeea327cd, 0x23db6ec0, 0x72c2df90, 0x2e41a756, 0xf0346e84, 0xd52c45f4, 0x975c7693, + 0x2b5a6bb3, 0x0457c3f9, 0xdcc6dba2, 0x5ac49f44, 0x0908c9b9, 0xbb3d9012, 0x8ec40835, 0x20a5e3f8, 0x0f47c1f5, + 0x8b2be13b, 0xc5b0b817, 0x8da48354, 0x747965f3, 0xd24222c6, 0x5220c46c, 0xb46749fa, 0x7247c4ba, 0x97af6cf9, + 0x3362651a, 0xa147c620, 0x73978849, 0x45021243, 0xb2568e1c, 0x36e77825, 0x21f86e68, 0xc91d42c4, 0x3d4d3bb0, + 0xefb5e16b, 0x62144a73, 0x5b83c29b, 0x651c0bbd, 0x1d7beca7, 0x703551db, 0x83408b5d, 0x8b667337, 0xb6d0f978, + 0x78b09d66, 0x18e50b28, 0xe3b42097, 0x4014a6c2, 0x8859b0d5, 0x16ebd4a7, 0x32f0ad34, 0x4981b8bf, 0xd4852826, + 0x94c85048, 0x09dbbde7, 0xc3c3c959, 0xf1332f34, 0xfc452019, 0xe23ccd1c, 0xaa77a7f7, 0xdd8b721e, 0x144fc58b, + 0xff03e407, 0xca955592, 0xd81cc0d8, 0x3134d38f, 0x580cfc31, 0xee37e078, 0xa5f0ad80, 0xd403a205, 0xa7e200db, + 0x4f9c21c3, 0x50fac4e6, 0xb22c5fa8, 0xfb0979b5, 0x3cfbb764, 0x8eba60c2, 0x6b4a7f0f, 0x84d78695, 0x096e783c, + 0xd2e8b060, 0xa04e1236, 0x31009bc4, 0x6c0bc238, 0xfe0df9e1, 0xd43a9dcf, 0x91e9d622, 0x780ea5c3, 0x5b49a6d7, + 0x6a81e5a8, 0x7dc6e47a, 0xfa4a3543, 0x25bc170f, 0xd662297d, 0xcf81c506, 0x8ba4ace3, 0x69ae08e5, 0x60bd8e75, + 0x9f30871f, 0xcd5bd932, 0x0c2461e7, 0x001d2043, 0x962e6a98, 0x65422294, 0xd97ca168, 0xd7a37954, 0xd2ac3ffb, + 0xfd00894c, 0xf03fa7a4, 0x46fbd2eb, 0x9ec2ef72, 0x11bfed41, 0xe16bb290, 0x06498fee, 0x1ba88468, 0xd35657d5, + 0xdb6f7aaa, 0x4cf31f57, 0xe09f5b49, 0x1c6ff68e, 0x200e8d09, 0x4840ed39, 0x173fd034, 0x2a2d08e9, 0x101c53a6, + 0x0699b95e, 0x2d92b680, 0xc0d02707, 0xfc3bced2, 0x2432e22b, 0x50bd4e4b, 0x0ecaaeef, 0xa28bf7e6, 0x61e0efb2, + 0x6f940c4e, 0xff0e827e, 0x277196ca, 0xe435abcc, 0x94b8468e, 0x32ce7296, 0xf0dfcbb0, 0xeee03c0e, 0xe794b586, + 0xcb34c190, 0xe1eb46f1, 0x9db599df, 0xef20aa4b, 0x04172252, 0x75650e7c, 0x4c1d1b04, 0x7dd07690, 0xd22b0a09, + 0x0be66c8c, 0x76dee294, 0x7853b42e, 0x11204c1a, 0x0f6ca330, 0xb62d5d15, 0x48100202, 0x71159ca5, 0xf7a12fb6, + 0xe6fb4cef, 0xe0bf8a4f, 0x405aa38c, 0x4e6ef3d9, 0x7be8d031, 0x735ca35e, 0x6bc260ac, 0x28cf555f, 0x867a6d10, + 0xd63e3c86, 0xab809cb4, 0x3ba4dca9, 0x20a47765, 0x72e962ba, 0x7eb0c955, 0xb555bec3, 0xf03a9897, 0x853f7e0b, + 0x6ce0f358, 0xd4c29d60, 0x4b4f55e1, 0x21bd530b, 0xb4f4fb77, 0xf79b6bb9, 0x98a60ef1, 0xa6d298ad, 0xf4b467fb, + 0xad428928, 0x89abfcad, 0x05841e0b, 0xb89c5f2b, 0x80d3bb36, 0x12c238f9, 0x9bee9960, 0x2eb4c79d, 0xe7418dc8, + 0xbbc9b243, 0xe27e4380, 0xd7ee276a, 0xcdfb6406, 0x5cddf65a, 0x9e6a37ae, 0x8acc4971, 0xdfafb1aa, 0x7fc763a4, + 0xfdb8bc2d, 0x88375f5e, 0x3ba8f168, 0x3fee996c, 0x0c8d85a8, 0x5d8bb8e4, 0x7d1d6dac, 0xe1419d7b, 0xdf938f03, + 0x7e119a6a, 0xe9499eee, 0x3403971a, 0xc2796697, 0xbe5ae8b2, 0xe4414084, 0x54fcd6b1, 0x1dbffe51, 0x68084bc7, + 0xc162b30a, 0x49dfc61b, 0xceca4ffb, 0x989fd122, 0xfc0f2787, 0x0fa54ea9, 0x2189d23c, 0x501a3eea, 0xd07dd0c9, + 0xc5a887da, 0xf894e994, 0xf9fc9c71, 0x5922f408, 0xe7f13875, 0x083e56ec, 0xca6b4e1c, 0x4fa59a10, 0x37efe209, + 0xbf5e51d3, 0xaa396772, 0xc9c1ae77, 0x0944733f, 0x8c12f010, 0x0e5dd2fe, 0x49f92cb3, 0xcad89f0c, 0xe481bc95, + 0x1321529c, 0xb0ddc3b8, 0xaa1c5216, 0xa72d01a9, 0x83d73065, 0xeb901ee2, 0xf76f8ecb, 0x82026f10, 0x46817fb3, + 0xbb77f83f, 0xe112b2ab, 0xcf75a8ed, 0xafc43cec, 0xe8b0d25d, 0x12c27139, 0x549516b9, 0x3917c261, 0x7680a4f9, + 0x191698e0, 0x6988a3a0, 0x318899cf, 0x4a2f264a, 0x6ab16ba5, 0x9d2a3a69, 0xa14c8148, 0xfb6f8ed8, 0xac9fd488, + 0xf50857d0, 0xc06ad7d1, 0xde503f68, 0xead9881e, 0x55ee0e80, 0xa672f174, 0xdb2e3fd8, 0x44881354, 0xbfc8b8c3, + 0x0d658b84, 0x28557800, 0x97b311e3, 0x8d2ec7a8, 0x3f932ad3, 0xdd37b34f, 0xbe52cdd7, 0x1c801aa7, 0x40589f02, + 0xd749b9d5, 0x3c815596, 0x564c2ad4, 0x2406bd44, 0x6927d878, 0xffdaf855, 0x5982f503, 0xd6d6dc2d, 0xfdba8ce5, + 0xa510d800, 0x505e65c0, 0x41656c29, 0x53610af9, 0x2c8d7a6a, 0x7dcd287a, 0x58e756f0, 0x3022355b, 0x5b073a5c, + 0x4062b1cd, 0x542d8ca2, 0x9f9ca96a, 0xcb882a1e, 0x63ebd55c, 0x4fd04aa9, 0xfb226395, 0x2702ccc3, 0x3d27f34d, + 0xc21ee0b2, 0xafcf208a, 0xfd1840c8, 0x52cd9a19, 0x5aabea21, 0x5775330c, 0xbca1c657, 0x9861251c, 0x6a3ff4da, + 0x420272e6, 0x95e238fa, 0xffd9196a, 0xfb834263, 0xfb05fa7a, 0x55f1bcd0, 0x0f6cf17b, 0x59703255, 0x000d4f65, + 0x93855124, 0xea33c539, 0x01768186, 0x2a8e77d0, 0xf25bbb64, 0xa6201036, 0x6504dbd4, 0xc0a31417, 0x6d261218, + 0x24d4a4df, 0xef2221c4, 0x4ca83160, 0x7f9cf0d4, 0x401bf55a, 0xd17c607d, 0xdfc1ea6f, 0x8569f4fb, 0x41bbc3bb, + 0x5f761f2c, 0xacd6fa38, 0xdb594c2d, 0xc4e8a459, 0x9814d2fa, 0x06a28288, 0x2138b9da, 0x6f2bb5e9, 0x335ccacc, + 0xf31e0479, 0x3cb7db48, 0x151728ea, 0x87aeb9a4, 0xff4b9e4f, 0x4fc4d879, 0x80e59281, 0x2be8ee8e, 0x9399227a, + 0x8c68863e, 0xe196f11b, 0x926284ec, 0xafea9d51, 0xe16998ac, 0x572cd678, 0x83b2c161, 0x95607041, 0x12c0e50d, + 0x321b7d45, 0x63b96a2d, 0xd5c7cf9f, 0xe24c50c5, 0x0c2bce8e, 0xb778cf27, 0xedb34d5f, 0x87d4beba, 0xa1d37215, + 0xf8c6dcad, 0x5d170285, 0x9e3bcff8, 0xa74d6a12, 0xfdc08328, 0x8ec742f6, 0xae85bd5b, 0xf73d44db, 0x4915587c, + 0x7958fee2, 0xce975a47, 0x565767d4, 0x6d78fbe3, 0xea1520ac, 0x03e87ffc, 0x46fb8f7a, 0xeaf2cdf4, 0xf07b5cb5, + 0x6fd3e221, 0xed89125e, 0x99037307, 0x5e191f2b, 0xc5558ac3, 0x048d35c8, 0x750275de, 0x768fbf53, 0xd59fa4ea, + 0x7d8560fc, 0x2ff52527, 0xdd277847, 0x9a2d00b5, 0xf5b43390, 0x141928dc, 0x332cf864, 0x4ecb586c, 0xf60b8c0d, + 0xee7a93f3, 0x801f38a0, 0xaaef37dd, 0x22799e3b, 0xb6b4f913, 0xa3bc995d, 0x889c66d2, 0x4b0c028f, 0x8cef4699, + 0x3911b681, 0x4664a75b, 0x2757fc18, 0x4cd97ccb, 0xb378d580, 0xd72bfc60, 0xcd46deb8, 0x705c5488, 0xd5cc326e, + 0xc00cf0a7, 0x721bbf68, 0x2b614cf9, 0x45fb3986, 0x37b98aef, 0x5dd9df4c, 0x6d5cbac1, 0x779c977b, 0x07aaab39, + 0x9dffd08d, 0xe2039ccd, 0x93266d4c, 0xba897c5c, 0x79640c20, 0x4dcda445, 0x5b0fce05, 0x752b76e4, 0x15985b98, + 0xb58a8c1e, 0xac3f98ef, 0x047c9b6e, 0x4ff0091b, 0x1bb3a40f, 0x53c84e42, 0x9d32b358, 0x256b9ff7, 0xe513a974, + 0x5dd602a0, 0xc38b0a0b, 0x41b199cc, 0x39dd9a61, 0x885d8b86, 0x093dc816, 0xa7c32797, 0x4477c8e4, 0x57efa3cd, + 0xb97dbb17, 0xe3116e5a, 0x5574ef2d, 0xe4f87122, 0x6b2220b2, 0xf4d8484b, 0x620b9b5d, 0x4fdfc573, 0x3faa0fd3, + 0xa008d48d, 0x310be58e, 0xa730798b, 0xeb640bc2, 0xfe75bd2e, 0x3afdff29, 0x374d26cd, 0xee83f33b, 0x61865f78, + 0xd8bf0eec, 0x0dc16e35, 0xc44da802, 0x214e7a12, 0xbc18c15d, 0x309e2e0a, 0xd93760cf, 0x64b7ee6b, 0x8344984e, + 0xdc30b0c9, 0x2dfe66e9, 0x04fc1eac, 0x32f14f5e, 0xa097515c, 0x559f9326, 0xaa3a0083, 0xc9d08e37, 0x5628cf67, + 0x705b2688, 0x470a92ec, 0x480338f8, 0xd57d502a, 0x2a5a77c5, 0xc934fe3c, 0x19faf378, 0x59b92aef, 0x98d5ddbf, + 0x1fc97802, 0x872cf718, 0x3567b3fd, 0xd60db1ef, 0xa73f7737, 0x7d3e3f1a, 0xb58b9dac, 0x7e5e393c, 0x8739aba7, + 0x1b3b66ce, 0x4a0e68df, 0xb940ce0d, 0x2205ebc0, 0x45343d80, 0xd36b2444, 0x06ae2fab, 0xe563af8a, 0x8fb798f9, + 0xa0c920c3, 0x3996e69c, 0xb527ecd2, 0xa45ed743, 0x46993f7b, 0x49e2bac6, 0x1665b76f, 0x34ffb22a, 0xda3ec278, + 0x2d95d5ff, 0x2c38200b, 0x4d874f13, 0x6cf5beb8, 0xec17a245, 0x1f4a542e, 0x19518935, 0x08a3480e, 0xe3676c91, + 0xa327d7fa, 0x8769de90, 0x98718b7e, 0x42c34c19, 0xd33ab129, 0x575e879a, 0x1601c4f6, 0x9b354408, 0x57f3e7cd, + 0xc01e79e5, 0x5cc66f8c, 0xd58cf729, 0x9b0d510b, 0x080aa0ac, 0x78fe2adb, 0x2f5874ad, 0xd69d06c8, 0x40ed94fb, + 0x012ed42e, 0xdde2f243, 0xd267cf0f, 0x6f577a22, 0x7c96f184, 0x8f46fafe, 0x703762a4, 0x3fd1de95, 0xa082861a, + 0xd4b38bd2, 0x96bf43db, 0x5dcf04d7, 0x1f91ae7a, 0x0413bae6, 0xb4ee812d, 0xd90cd6f0, 0x14a6efc8, 0x50162f57, + 0x6c18cc16, 0x2dbeb12b, 0xe24d4500, 0x4603ad61, 0xae1635d9, 0xf3d0aa3b, 0x4c2a5811, 0x8615b84c, 0x99c9affa, + 0xe3b8258a, 0xe274a89c, 0xa979efd1, 0xa43fe378, 0x1f3a196f, 0x175d454a, 0x53139c6d, 0x29f10542, 0x4232fe4e, + 0xc9ef7135, 0x609a4be6, 0xab240553, 0x6764a951, 0x766e3cdc, 0x4c9a269b, 0xe4557054, 0xc711de0b, 0x02003d3d, + 0x55c31229, 0x1588d89c, 0xec9a40e8, 0x211a7efc, 0x3b051ae6, 0xf67e5604, 0x2c4fc254, 0x9e7580cb, 0xde60670d, + 0x3ce36053, 0xe468a3f5, 0x46caa934, 0x4f542c37, 0x80b77606, 0x7a5eff26, 0xca7612b1, 0x23e8d528, 0x05bed6e9, + 0x05c6590e, 0x826b20a8, 0x1577512f, 0xe3d605a4, 0xd928be14, 0x8050d1c4, 0x97640f9c, 0x4929bf23, 0x756725e6, + 0x2129ef24, 0xaeca2351, 0x8d135fda, 0x3a50be16, 0x81f242ac, 0x686349ce, 0x123be6bf, 0x9eb5e297, 0xe3f4e249, + 0xfabf3e7b, 0x2ed637f0, 0xf4978742, 0xf6920947, 0x1b201e95, 0x2aad4576, 0xff3e9ea4, 0xa2cb6ec1, 0x2ff23413, + 0xde6f7fa0, 0x1b06e31d, 0x0203cac4, 0xc2dcaef8, 0x75d40053, 0xec10ff45, 0x43f1aeab, 0x06048c22, 0xa8f9da31, + 0x37426565, 0xda47208f, 0xd8bf17c0, 0xa616d3fb, 0x375bc73c, 0x635be72b, 0xf6035cea, 0x22c9452e, 0xbbd1f758, + 0x483776a9, 0xdb06c7bd, 0xd381fcfa, 0x5037eb68, 0xa7831343, 0xb8e3f2b4, 0x71eb5249, 0x9d5f3ba1, 0xd26678a0, + 0x1feacde3, 0xd9581aa2, 0x08c6964a, 0x268d4a82, 0xad1e3cdb, 0x6aca2339, 0xd76483b9, 0x71ff9c22, 0x495fcd76, + 0xb0e13bad, 0x14a89182, 0xc5846cc9, 0x524979d3, 0xb8676649, 0x351786e8, 0x9a0de6ee, 0xc2528489, 0xaa477126, + 0xfcf229e9, 0xccccc34c, 0xa1f1898c, 0xe496a192, 0x1c477a5f, 0xd05c8b15, 0x256a31bd, 0x497edb4f, 0x2a581881, + 0xacf99384, 0x0c8dbef5, 0x4434f9c5, 0x4fd6f358, 0x29b06f06, 0x167e678a, 0xea25950e, 0xc37cc21e, 0xdddcbe0f, + 0xd6045290, 0xffb97dec, 0xa5248f8e, 0x9920a9e4, 0xfafae95d, 0xf6c0ab3d, 0xee4e96cf, 0x1d64e4bb, 0x8c4b2be5, + 0xb21fa259, 0x362a019a, 0xcd0ef748, 0xc8dd4ec9, 0x20d0a6ff, 0x081b47d9, 0xc62043b6, 0x2ee5a691, 0x1d1018b9, + 0x3b6c0711, 0x38b565ae, 0x18b17995, 0x4e3acc5e, 0xecf35241, 0x907317bf, 0xcdb66d73, 0x0c41974f, 0x87ce3cb0, + 0x4c2dd8fe, 0xd91a4884, 0x27ee273e, 0x8b2c8aa1, 0xf829b6ba, 0x2f1af4d7, 0x7f9f5e99, 0x0bc232b2, 0x55d2854b, + 0x2128fed7, 0x3870c899, 0x6e8210da, 0x75184208, 0xc51b775b, 0xbd75a1b6, 0xdc151482, 0x25657ee7, 0x6bfabe01, + 0xe400b38f, 0x50e6b156, 0xeba57f41, 0x4ef73eec, 0x009045e8, 0x9c6c2095, 0x2ab15bd9, 0x92d99589, 0x85db42a3, + 0xa5e9cd84, 0x83c5a5f4, 0x5f67ecfc, 0x5d8428b4, 0x665af8df, 0x4d0592ef, 0x56d6798f, 0xe03f6019, 0xe3ac6523, + 0x0c57159b, 0x82561e31, 0x6df2555e, 0x6da29fb1, 0xee3f6f81, 0x054774be, 0x3a74ebf7, 0x318b4d1f, 0x58e0c061, + 0xacff0bf2, 0x28f3a392, 0x01004db9, 0x425283d8, 0xf8b27608, 0x9e76893e, 0x0dfbe285, 0xf7164805, 0x05996cb1, + 0x4e30d4b9, 0x7f69b865, 0x70a5e341, 0x8238b3c9, 0x6f3ed93e, 0x31866594, 0xed0433dd, 0xf8863915, 0x47f206a1, + 0x784a3af6, 0x1b492e1e, 0x02c5d6f1, 0x99fb0b7f, 0xbe4a3d94, 0xa9953ca4, 0xada34940, 0x71e155d5, 0x0c02c34c, + 0x30343f4c, 0x1879389d, 0x81a38932, 0x92b91748, 0x48cb09f5, 0x19b2f7e1, 0xba9520c9, 0x018c6228, 0x88966045, + 0xab88c59c, 0xdb75ef03, 0x79ad5fc3, 0xc10d4c7f, 0x97c581b8, 0xd93ad6d2, 0x47fdb926, 0xfa077939, 0x84f544f0, + 0x038246a4, 0x15bf9bdd, 0x96274b0e, 0x5e202aec, 0x87ce37bd, 0x516677dd, 0x3ff4c671, 0x7e1a7134, 0x528c6158, + 0xdcf6c1ff, 0xc380d9ea, 0xb3c988cb, 0x2ed03fd3, 0x8e29b738, 0xdf3b7c61, 0x6fc55b2c, 0x3ee05d5b, 0xeaced3a2, + 0xaffc0523, 0x748dc081, 0x7ddb5ac6, 0xd7ea75a7, 0xc4731fe2, 0x45274335, 0xacf219fd, 0x81d0dca8, 0x1946fe8d, + 0xd78195a8, 0x00037b09, 0xaf08a9f8, 0x02f45a10, 0x7d6e9232, 0xdd6a2b32, 0xbaac40d1, 0x2d8a1266, 0x91e38bef, + 0x7bc7f052, 0x20416437, 0xc2221063, 0x2509075a, 0x4236fbd1, 0x73d3eff4, 0x9bd7676b, 0x9de9cd23, 0x6d4a3229, + 0x6ba463d3, 0x9a69dc7a, 0x4933abef, 0xaec66420, 0x24072c64, 0x92858122, 0x7e5ce30e, 0x38c8ce2e, 0x26b79aad, + 0xc3931d68, 0x885bade1, 0xd7a26ea5, 0xe1cdc12e, 0xc0e83467, 0xb1e8d4fe, 0x5280e91e, 0x2e2fca68, 0x2bb535b1, + 0x0d6f07db, 0x23d59a9c, 0x788e63ee, 0x33e5621c, 0x79003da4, 0xcfc78dab, 0x76d0c491, 0x20881ebc, 0x40b551c2, + 0x41d12f33, 0xe936a913, 0x37f7e73c, 0x1f9ccc15, 0x849de0ee, 0xb93ddba4, 0x7cb4316e, 0x5e1f1126, 0x903cf822, + 0x70df0ee2, 0x666502a1, 0x9dc605ba, 0x265967e8, 0xd77392ef, 0xc1b04054, 0xdde5aa1a, 0xf57a4cb1, 0x26fb6195, + 0x47e09225, 0x869c0e7b, 0x45be5c2d, 0x88b88337, 0x81abda05, 0x11e36197, 0xe28a9a18, 0x0b201f94, 0xd8433fc4, + 0x79b6691c, 0xb86207ab, 0x965f235c, 0xeee3cdf7, 0x602c9273, 0xe900eda0, 0x2de7b099, 0x59717034, 0xac293521, + 0xdd7cfe66, 0x10b0b4eb, 0x3d1ebd85, 0xd2d275ad, 0xf4e6d56d, 0x4dc6403b, 0x319cf1ca, 0x1e5bc0bb, 0xe0f5eb93, + 0xaae78022, 0x6e8040a1, 0x6eb3609c, 0xcdb4556c, 0x444e965d, 0x2f8afd89, 0x34f873e8, 0xf5a6b5ac, 0x2d738008, + 0x41ed10a2, 0xdc2a48f0, 0x5120005b, 0x4045bada, 0xc9e44bec, 0xd6d47768, 0xb5009123, 0x3b430c30, 0xe22594a6, + 0x0b33d2ac, 0xc6849614, 0x7d426fc5, 0xa431cb96, 0xd552ac3d, 0xacfae580, 0x8e1cb4b9, 0x84e140ff, 0xe4fff8ac, + 0xae2250df, 0x568c0d5e, 0x3af43a40, 0xe3307168, 0x4e313e28, 0xed30fd69, 0x29e40892, 0x99ed5c36, 0x95a77f5e, + 0xee0fcdde, 0xeccb8ab5, 0x6423ffc2, 0x1a16c80b, 0x2410a219, 0xecc5e134, 0xc6a11ea3, 0xbeae08cc, 0xabca6c20, + 0x7a844362, 0xd5c51efd, 0x79f7ca16, 0xb40c9a6f, 0x0acbe083, 0x4f96837d, 0x2f0bbec1, 0x981ee9f9, 0x741ba05f, + 0xd1ca4636, 0x1942da46, 0x681d3bcc, 0x7a49f395, 0x0e97344b, 0xa6c90f65, 0x19e2eaa9, 0xb64c132a, 0x73716d3c, + 0x3b9ce194, 0x64297bae, 0xfcddc9e8, 0x32a7ce4c, 0x491fe4ab, 0x9fb0ce36, 0xbea72a0a, 0xa6d9dbf4, 0x408ecc73, + 0xb2f951e7, 0x24bc0cbc, 0xdb09b4f1, 0x42d1c7f0, 0x5094ec8b, 0x9a2c96d5, 0x3956dccc, 0x0234c6c0, 0x6214c650, + 0x1e758184, 0x66440b73, 0x2b11639b, 0x08c7cb1c, 0xa866db28, 0x76a258d3, 0x0120eea6, 0x96a0a8fa, 0xfd794fdb, + 0xe49baa5d, 0xbbc800db, 0x0d0da3d2, 0x7965cdc9, 0xc4d7d474, 0x4dd549fb, 0x634b1fee, 0x887c3eb0, 0xb5a92075, + 0xe21da8ec, 0x8e0576e2, 0x8bc790ff, 0xb24503d7, 0xef7858f3, 0xb46fad25, 0x50772b0e, 0x23152452, 0x1362a715, + 0xf0b6ac1c, 0x69cccfde, 0xedc9da94, 0xbc12c1dc, 0xc6f65052, 0x8f998986, 0x5821da4c, 0x7947e3cd, 0x379769f3, + 0xa081fd5a, 0x329abe63, 0xb0e4e8c0, 0x2a46df86, 0x2c5cbc0c, 0x83499751, 0xbd5d8328, 0xa7a07548, 0xff2600b4, + 0x11c428be, 0x08bdacb8, 0x7e9f9b2d, 0xa54785c7, 0xf0109cd2, 0xce2b2389, 0x78631f53, 0x393b0509, 0x97e0b90e, + 0x4717eb61, 0xddb8dcfc, 0x9c6dec19, 0x6f2e546b, 0x15394444, 0xbe6e4be2, 0x10129380, 0xbeb67777, 0xa67bea5d, + 0x2e8eafaf, 0x94da1ae9, 0x760a813f, 0xd6c576a9, 0x7b20ffef, 0xe6cc1500, 0x2e3196c3, 0x6106ad2f, 0xf93ab10a, + 0xe21e5251, 0x71503d45, 0x67ede477, 0x4b35caa2, 0x72845e1a, 0xe3cf4a8e, 0x2f7bb054, 0xd0a7230a, 0xe48ff470, + 0xca786753, 0x25e63cd7, 0x271c483d, 0xf5e306de, 0xa1a4d113, 0x1b83901d, 0x0a21b526, 0x859edb79, 0x885fb2d9, + 0x2c51ad44, 0xa04c2833, 0x61bc11db, 0xe4cd6d75, 0x7673b9da, 0x15e05233, 0x9e026995, 0xd574858b, 0x0d13049e, + 0xcc7b0589, 0xe9024311, 0xb85559de, 0x6d449aa1, 0x653edb1f, 0xba27ac82, 0xdea2af20, 0xd5438391, 0xa0bc772c, + 0xd244d330, 0x5c0d1c5a, 0x20c0336b, 0xf36a094b, 0x9b5d631d, 0xe5cd1f4f, 0x1837b2a8, 0xebda1358, 0xe0c4fdc2, + 0xce31832a, 0x41e995f2, 0xfeb8f8c1, 0x694a9eae, 0x5ea11c46, 0x2271e420, 0x24dd3ed7, 0x15f092d7, 0x77a9da84, + 0x06514e29, 0xe1d4bcf6, 0x91044a7b, 0x80ef3c01, 0x7c905313, 0x5c39722d, 0x0eb56cfc, 0x24db3bff, 0x8e673f27, + 0xd4251b9d, 0xf424f514, 0x0f489a93, 0x0b8df51e, 0xf2b8401a, 0x17efadc8, 0xbb7f21e3, 0xbd9c17bf, 0x8a3d85b3, + 0x87078f28, 0x1fe555f7, 0x3ad956d9, 0x8ee53747, 0x50071c1a, 0x9a0caa85, 0xc9fa5f11, 0x826251b3, 0x90086ce1, + 0x0fb95e65, 0x5d65e292, 0x0b4f8239, 0x18e52ec5, 0xdf433092, 0xfa470035, 0x30a0dd4d, 0xa84f4dde, 0x8527f692, + 0x4b3766c3, 0x6b1875af, 0x8155387a, 0xf4403f73, 0x8ac3f797, 0x88cdfb8c, 0xbd7f3eb9, 0x2e51de78, 0x6a4e4f00, + 0x153d0ca6, 0x7c937eb5, 0xc3abeb91, 0x5a28cd2e, 0xd3827ad0, 0xd3529750, 0x0be74203, 0xea2c825e, 0x95456095, + 0x25564403, 0xa4499a27, 0x5b778c70, 0x4b2e052b, 0x28dd9f4e, 0x8621a964, 0x47f6bca8, 0x38c42072, 0x783e7b0e, + 0x8f8dac88, 0x0820c706, 0x9931639c, 0xe67cff5d, 0x495c1487, 0xc959bbd0, 0x7eef915f, 0x16f31c53, 0xca7d8ba2, + 0x4114ea1f, 0xa384220b, 0x91540cad, 0x6db23db9, 0x7c57cc87, 0x39d14d53, 0x95feac49, 0xf0abcc9c, 0x8e8a048c, + 0x50c65da4, 0x2cb9386f, 0x2a81106e, 0xc76c4f75, 0x26e52a96, 0x29bb7d09, 0xe13aeb69, 0x5069173c, 0x855cf7e2, + 0xd6f9f606, 0x1be92620, 0xecdb91b3, 0x1d108bf3, 0x2fd0442d, 0xf718484e, 0x2a94a838, 0x33cc71e9, 0x08a7f8d0, + 0xbffd4f9f, 0xdcd19335, 0x8bd4a20a, 0x05177f15, 0x6cea3321, 0x07d54c67, 0xd17d4077, 0xecde2871, 0x8c5b4bb5, + 0xb5274c54, 0x650d42db, 0xf3a3ea08, 0xb9d8d791, 0xf0ea4740, 0xba21ee08, 0x06e358e7, 0xce992e09, 0xea70d35b, + 0x39f99c65, 0xc9bd9bf3, 0x7c5d34d9, 0x375d2db7, 0x9528b73f, 0x2e33c031, 0xf4e61afc, 0xb60f7838, 0x2539206e, + 0xdf4e5529, 0x53a266f2, 0xa5247148, 0x37150d56, 0x2f51b625, 0x0699bc9e, 0xe85a1dfc, 0xb43723c7, 0xdc25879e, + 0x9dee4ece, 0x4dda90e8, 0x0151c547, 0x6f69d523, 0x10006a8a, 0xa4e587ba, 0xb47ef56c, 0x4e6ff1c5, 0x2d19ede2, + 0xa9d61d9f, 0x7558a972, 0xfcff9cfc, 0x894d2642, 0xeba0a1e2, 0x7b844457, 0xb9f313ce, 0xb03fae63, 0xf2ae06fa, + 0xec09967d, 0x51e57b5c, 0x59c37753, 0xe502ec88, 0x29a499f6, 0xd53fca20, 0x9a7626d5, 0xf8c5f0bd, 0x8e1fb212, + 0xf066fcff, 0x47fdad50, 0xad444bd0, 0xb2d09f83, 0x8d6e4237, 0x5eda9b42, 0x9d5ee2a7, 0x8304fdbe, 0x61cd7f8c, + 0x989549d6, 0xecbdf36f, 0xfb11a44c, 0xd3ca3e32, 0x64a60794, 0x16f21fa7, 0x81cb3d10, 0xba652457, 0xf5a1d5e1, + 0x4fcfa6d4, 0x453cce41, 0x9f98c409, 0x187f095f, 0x83e9eb1a, 0x73feefcf, 0x8bd67a71, 0x7ba86c6f, 0xc08b75c8, + 0x510a8df8, 0x802d5dd6, 0x75184371, 0x9d828c9a, 0x5eda23a2, 0xa65d6e97, 0xba4510b0, 0x9ad38115, 0x7fc5f0a6, + 0xd0a8a911, 0x61d18332, 0xd2055064, 0xa3ff0f0d, 0xad534697, 0x544a4455, 0x35af04db, 0xb85c1adc, 0x63028ab4, + 0xf3ab5aaf, 0x7490afc6, 0x5b8da586, 0xfd7e259c, 0x64d3ef6c, 0xa35e7f7f, 0xe47403b1, 0xd25acf48, 0x5ad2024a, + 0x7f306bde, 0xc48958de, 0xe4efbb60, 0x7e1a35ca, 0xb802ed0a, 0xf05ef3d3, 0x0f16b169, 0xaaaa99ee, 0x59fd976f, + 0x73c6f20e, 0xf5de2403, 0x7c981675, 0x6aa71807, 0xca51d2ba, 0xe3bb84a4, 0xcdac5b10, 0x728f64dd, 0x9a473ac5, + 0xc9af7fca, 0xcfd5543b, 0x557081ba, 0xf54a3874, 0xb4d211f7, 0x329a95a7, 0x057ebbd9, 0x2991859e, 0xc8cd70a9, + 0x738df033, 0xa39f76bd, 0x086a8144, 0x03495b91, 0xe8fb75a1, 0xcf3e31b4, 0x5d4452a2, 0x3acd0386, 0x3db9e0ef, + 0xfb8dae89, 0x03d40de2, 0xf1d3428f, 0xc32bd5e5, 0x5a20e056, 0xc790e3a4, 0xd2c311fc, 0x74c41062, 0xccdc0b81, + 0x9f341406, 0x7ed91e40, 0xe43fc411, 0x684fd0d2, 0x5784cc61, 0x1918f715, 0x7c360bf0, 0x798c0a1b, 0x0bdfff11, + 0x17ecf2e7, 0xcacd6cc4, 0x2315afff, 0x8c92fbb7, 0x9f18da69, 0x758ac6b6, 0x802fb496, 0x31e5286b, 0x2758a322, + 0xaedc481a, 0xf1a089fe, 0x7c5b7f00, 0x92c837ab, 0x041fd2ef, 0x195ea34b, 0xce86df61, 0xa7870d06, 0x9107fd5b, + 0xf72d2e40, 0xeb2c425a, 0xea5dd0ce, 0x566315a4, 0x8efce65b, 0x0e7eea36, 0x97204199, 0xb06af3c7, 0xe44c25ce, + 0x3c33176a, 0x61c74399, 0x50e4b25c, 0x0f4df364, 0xaba4ddd8, 0x6a793fcd, 0xcfee0f85, 0x4507aa16, 0xce492128, + 0x53d5bfbe, 0x4500fd17, 0x8087a01d, 0xca353925, 0x52c8f65a, 0x32402807, 0xa5d97a04, 0x51420b77, 0xd5e86c03, + 0x316aa81f, 0xf9f1dd94, 0x7e5f9aff, 0x2e8de69a, 0x643d460d, 0xa0d9ef92, 0xf5c8602f, 0x71b63fb9, 0x7f150643, + 0xbab81729, 0x21383568, 0xf01cbe3b, 0xcc9d8bc0, 0x073ebba4, 0x055955d1, 0x056897ea, 0xc6268ff2, 0x96c91a27, + 0x2f9028a7, 0x319b7d16, 0x45864e73, 0x2caebdc2, 0xd35d3ff1, 0xc4fd7fb0, 0x3568a7d6, 0x274ee575, 0x63f2602e, + 0xe031d131, 0x98504540, 0xd122f6cc, 0xdbd05b7c, 0x26e90617, 0x01cf1c8f, 0x1d83df1d, 0xef62e42a, 0x4753a0b8, + 0xdd15a587, 0x1197eef1, 0xdd7e7837, 0x8841ed3d, 0x2986e832, 0x6a81a643, 0xa5a4618c, 0x9e584f92, 0x9b2a66f6, + 0x12d35d05, 0xfac7415f, 0xf62bf3ca, 0x962df830, 0xac3d680a, 0x25199f6b, 0x068fcc17, 0x09e53ffe, 0xbb292f8b, + 0x18dc0365, 0xc1d2e6e8, 0x52fa4275, 0xde2c927b, 0xd928d2ad, 0x5849ff0e, 0x1389e67c, 0xc4c7ae03, 0xee63294c, + 0x3dd914cc, 0xa56688ee, 0xadb7688b, 0x4271d9b7, 0xc8bf1208, 0x29aee822, 0x5effb05d, 0x6532f682, 0x6ad47096, + 0xea64d6a6, 0x0fce0fb3, 0x5a00c4a6, 0x019fcf5a, 0xf955282e, 0x09f901a4, 0x82e03e46, 0xda1ddb05, 0xe014f295, + 0x0b8e4974, 0xdc0a6901, 0x95aca406, 0xa5de0541, 0x1088613a, 0x3a0a2b74, 0x5619709a, 0x46595df7, 0x5f19b6fa, + 0xbe95a549, 0x866fc1a4, 0x1e58ef48, 0x32c281ec, 0xad2cb398, 0x15d46994, 0x43a7d90f, 0x8df3177c, 0x81422b7e, + 0x45f9a9a5, 0xe5bc8dcf, 0xd5d3b72e, 0x5da0f3f7, 0xe723366e, 0x28cec802, 0x2f48920b, 0x69aa5812, 0x4e025555, + 0x54374680, 0x4d34eed4, 0x24bdabfc, 0x8814a1f2, 0x65fa925b, 0xd3ba4a8b, 0x82d351a6, 0x45deecf3, 0x36f2089b, + 0x36239722, 0x431aad05, 0xefa299c1, 0x77a95400, 0x603edd54, 0xb69ca93f, 0xfcd385c5, 0x520ec7d9, 0xfb7793e5, + 0x3e395dab, 0x63d58e9c, 0x8820e10c, 0xfa3ca0e3, 0x1f2152ca, 0xa3e508fe, 0x67c21360, 0x6fc26975, 0xef084aef, + 0x39cf2845, 0xd4bd5328, 0x24adbb1e, 0xa277741c, 0xa304b938, 0x4a0ad1b6, 0xbf928d0c, 0xacc27268, 0x14b321d3, + 0x8debb8ff, 0xdca2bc95, 0xe1599f1c, 0x75aaee0d, 0xebfb2f85, 0x36927e6d, 0x8ce73b5b, 0xbd07a829, 0x9fcea906, + 0xc330f1bd, 0x37b42616, 0xd9ff1b60, 0xcb0d85a5, 0x0b505a02, 0x8d237eb8, 0x4ab0a881, 0x27143e2d, 0x657b73e9, + 0x2ab5941b, 0xe0fa977a, 0x6bc5d11b, 0x57e64973, 0xe39fca80, 0x747d86c3, 0x70fe8dfb, 0xcfc85111, 0xf6020610, + 0x3b720e50, 0x5444c6c8, 0x228ff330, 0xfbacb8ce, 0xf23cba2e, 0xfff60beb, 0xfb5210fd, 0x5c66d2e6, 0x22c855ad, + 0xf49361b4, 0x17430160, 0x054b3aeb, 0x65300b8e, 0xac56c0b1, 0xdf31a7ab, 0x4dc145ec, 0xe842b79a, 0x83e9614a, + 0xdce60473, 0x1980db5d, 0xd5da4b65, 0x849f4f29, 0xcfbf286e, 0xd3dbcfae, 0x6986a516, 0x69879d03, 0x66108000, + 0xceb2b979, 0xdc111404, 0x22ebec03, 0x122214ea, 0x964c8b20, 0x467afe15, 0xedb6c7d8, 0xdc9ede6e, 0x8c3189a2, + 0x69831718, 0x2d35ab5b, 0xbd5e9cba, 0xdd8a6cbe, 0x7589dbee, 0xa5a4b2f3, 0xfc4f2be5, 0x66b26a20, 0x6c1787b6, + 0x7ce67a46, 0x8859edf9, 0xab079873, 0xbd88e9c5, 0xb55dbde1, 0x45134cfe, 0x619b5496, 0x9b23c9f7, 0x215147e4, + 0x1188e395, 0xa6dad92a, 0xa079866d, 0x01abe1b5, 0xbf53b92a, 0xa6634d7d, 0xa7c38868, 0x3097bcec, 0xb3e7a219, + 0x78fff1ff, 0xf4db851a, 0x4d17de49, 0x8765364f, 0xde00f839, 0x08ac82d6, 0xf7c18e78, 0xb2724042, 0x57e2b96c, + 0x2008a48f, 0x777cffac, 0x6f9eae49, 0x63734995, 0x2b65a88a, 0xc4b19526, 0x7237b3af, 0x0f19ab09, 0xe0e3f37f, + 0xae654989, 0xc90d020f, 0xeb314d85, 0xa6ec8200, 0x44016b43, 0xf4dc82e9, 0x14d96987, 0x1a46f1ac, 0xf1e19697, + 0x61ba2b46, 0xbbc5d71f, 0xf1dbc089, 0x919e4830, 0x180168ff, 0xae61e5c4, 0x234c8c6a, 0x9195f05a, 0xd6f31bd1, + 0x42e3a2dd, 0x032ff763, 0xf4778740, 0xd0ef4529, 0xc5533151, 0xf40acda2, 0xb77615bd, 0x7496574c, 0x1c4fcc88, + 0xd376c75b, 0xbe71f118, 0xe5cadc21, 0xf2f75b22, 0xc3a767df, 0xbbc5c2e2, 0x75ef39a2, 0x17f29244, 0x7d18b96f, + 0x2bf81828, 0x551062ed, 0x691c0ce5, 0xd27cd1d0, 0xd81edaee, 0x06eeef88, 0x151d92b7, 0x46d136fc, 0x5a36919b, + 0xfd2de8ff, 0x99b72ed0, 0xbc0c0a25, 0xca33407e, 0x5f1a0e3c, 0xb24e76fe, 0xbead9ab6, 0x234dfbe5, 0xd618a671, + 0xf206c262, 0xb68faf84, 0xa7ef0526, 0x3ad6dc85, 0xc494d4d1, 0x2f46adde, 0x2be90094, 0xe22af826, 0x7fe6c8e8, + 0xbc3b5aa0, 0x0e24bb74, 0x9a7ba2d5, 0x61eb5aa4, 0x0374cdbe, 0xf3c05c02, 0x0b81cf98, 0x1775c907, 0xcf0897c2, + 0xb4227d6c, 0x36350330, 0x342b3996, 0x8ef785f1, 0x367a9953, 0x9602e845, 0x7df7cae0, 0x8e04c884, 0x327d9454, + 0x625ec259, 0x4720fc5c, 0x43e50698, 0x8b03d9f6, 0x2a60eebe, 0x23efda9e, 0x59a3bb4a, 0x350d7b04, 0x78d19299, + 0xed9857cb, 0x10283caa, 0x789a6277, 0xda4e0955, 0x39501795, 0x0e517aff, 0x049711c0, 0x782866d0, 0x2ad31a6e, + 0x5bda212e, 0x67a0ba40, 0xc3ee9168, 0x4602b8e2, 0x38349bfe, 0x6b0ba8c1, 0xfe4a0d7c, 0x3f310723, 0x093d3408, + 0x64c52432, 0x3ce6d50f, 0x69b6f64b, 0xe558c01a, 0xcaf86e48, 0x24d1f095, 0xf0acc022, 0xd8185b6e, 0x31f168cc, + 0x3221514b, 0x3966103f, 0xf19cceab, 0x4e895b5b, 0x95271775, 0x8c2ce7d4, 0xda33b094, 0xe4149411, 0x4997c533, + 0x901ee3f3, 0x7eafa400, 0xe6e4de62, 0x2b138665, 0x5d8e4df6, 0x1f29ed35, 0x7b4dbf00, 0xf5451b2f, 0x04aa303d, + 0x29951a06, 0x80da7ceb, 0x7bdcf358, 0x03b041ec, 0x32cb4d01, 0x4cf6572e, 0x79aa6d26, 0x1b671131, 0x00521bcc, + 0xb10fade8, 0xe64046d5, 0x7f3b6cea, 0xa61f70d5, 0xc9994875, 0x5abe08d0, 0x1ea3263a, 0xf0b08bf8, 0x1e81c66c, + 0x9da99b1e, 0x4f3fbd4f, 0x564d9f61, 0x87a23f08, 0x388a27ea, 0x698fcef4, 0x53798e41, 0x7f4e4db0, 0x0783c9f6, + 0x224086f3, 0xc8c96f5a, 0xb2079fff, 0xf7cd7185, 0xf09d67d6, 0x8956eee5, 0x066b1d0d, 0xbbdfcf7d, 0xd0794601, + 0xc12b77d5, 0xe3210855, 0x5c98fb5e, 0x44c4bec7, 0xec8bd9a8, 0x01561a65, 0x6237a0f3, 0x245059d2, 0x3b3a53f9, + 0x34ea2162, 0xdd368cc9, 0x123a54e0, 0x5acfe842, 0xebdae5a8, 0x53fd8ee1, 0xa83cf317, 0xc1826fba, 0x3f3631c4, + 0x9657a8a0, 0xbdaeab5c, 0x96b96d8f, 0x83ddc73f, 0x7bcc0945, 0x867ffde2, 0xc846328f, 0xf3080aaa, 0xe4095891, + 0x62169be5, 0x2fcb109c, 0xf3cc4ea2, 0xcb984222, 0x0353d3c8, 0xfc591da5, 0x6da0fabf, 0xecdc1ec2, 0xcf80e949, + 0x42547296, 0x9e9f1445, 0x66ca1432, 0xe8269db7, 0xfdabca54, 0x7e36142e, 0x2fdee21c, 0x4c80d6bd, 0xd4583e5b, + 0xb532511d, 0xf5f7cf23, 0x97551a06, 0x39c50f6b, 0xb43e224e, 0xb24fe5f4, 0xa721a74a, 0x0a1facc5, 0x2acee160, + 0x5e72815a, 0x8e25b91b, 0x43f80d10, 0xeb388bad, 0xcd49092a, 0xba2dfab2, 0xdd39e30f, 0xa1fa1e36, 0x1576e798, + 0x4b20294a, 0x67a72ac4, 0x9c9e69c6, 0xf9c2f5bc, 0xb4ccaa08, 0xa3393be6, 0xc5533910, 0x61118796, 0x6fb548c6, + 0x5eae5aac, 0x6aba0cb8, 0xc211b3b7, 0x5f666c29, 0xedf89587, 0xaeeb81e4, 0x826f08c3, 0x53c5c457, 0xd62b2e65, + 0x334c32d8, 0xb994cf8b, 0x45315689, 0x21dfde74, 0x326fff5f, 0x02071232, 0x1f24b089, 0xf6ae74ae, 0x51a7bb47, + 0xd56d8d2d, 0xc12fafe2, 0x24b7f33a, 0x2e7114da, 0x78d04dc7, 0x3f1320ec, 0x10f4b190, 0xd4028db3, 0x515e60eb, + 0x3b5e77db, 0xf49de7a6, 0x87252cb9, 0xa9ee0159, 0x23da9909, 0x629a834c, 0xf98d1bcc, 0x99ca114f, 0x90fe9461, + 0x3457f413, 0x84293f29, 0x85b1e823, 0xd9953067, 0xbbfe1b57, 0x989bab6a, 0x1b1f375e, 0x72eac8c5, 0xdc41a2be, + 0x3a0f894f, 0x0d5f92f2, 0xcd9b57a3, 0x9d47bae1, 0x8f6609a1, 0x89919d9d, 0xfa3f37c3, 0x52e14e19, 0xe6b96b91, + 0xbd24a37c, 0xcd0e02ce, 0x9fe69aab, 0x33ce5407, 0x9fc19ec0, 0x68acee73, 0x9b4322de, 0x2abf3a8e, 0x3447a2e2, + 0x89614b6a, 0xb8957228, 0x3d391b08, 0x43d5cbd6, 0x4fe2b2ba, 0x75e397d5, 0x98e77409, 0x29895794, 0x7142d022, + 0x6c25ed7c, 0x35139d08, 0x882f6379, 0x7635607c, 0x5c02f10a, 0xe6564b90, 0xa5f355fa, 0x78325980, 0x44560fe6, + 0x1b8b0b33, 0xe3747df2, 0x6b6effc6, 0x0ceff625, 0x3f147862, 0x56c5dbc7, 0x708b3d23, 0x233ada99, 0x55dc717a, + 0x73b183bc, 0xdcd766a8, 0xb24d4507, 0xf4166d2b, 0x30e61588, 0x6eb96f07, 0x45d79c7b, 0x0194dd08, 0x438c9e24, + 0xd506f073, 0x88a88ad3, 0x4348448b, 0x0cf50652, 0x36de9d89, 0x171ec03c, 0xe9c5be65, 0xc62eb79d, 0xf1152a54, + 0x88ae0094, 0x297abb5a, 0x9987e1e3, 0x1ef4eba2, 0x4475c49b, 0x13c8cc7f, 0x3ec70711, 0xbf2997d5, 0xfe43016c, + 0x23e5379e, 0xe4a55e12, 0xbce33a4f, 0x07c9ebdd, 0x450f2bf1, 0xebe69e15, 0x23ae86f5, 0xe0fc5a0f, 0xf6ce40e2, + 0xe930d157, 0x0c065823, 0x7ca8fa0f, 0xfe6c1f8a, 0x2d672263, 0xd6340c24, 0xd4ee3436, 0x4689039a, 0x610fb07a, + 0x65bab71c, 0x07bcb67e, 0x6154d2a5, 0x6d13eff0, 0x59109023, 0x5641c50a, 0x1a4e2e9c, 0xc1fc0beb, 0x91ca0a84, + 0x39eafba3, 0xbe9ab9a4, 0xb34c805c, 0x6e5e3264, 0xbe051be7, 0x05749c67, 0x397d9ba4, 0xbd076dac, 0x23312adf, + 0xbdad2fda, 0xc93a085d, 0x7738a606, 0x3efcca39, 0x55636a7b, 0xaee59887, 0x2d8f5176, 0xe69170e4, 0xf0331961, + 0x87f1e11a, 0xc8b6ac22, 0xe8fae042, 0xa0640ed4, 0x652dc509, 0x154e70f5, 0xb53380f9, 0xa49edcfb, 0x55c42d62, + 0xf04045af, 0xf4876b8e, 0x08cd29b2, 0x8aee0b1b, 0x0e72b807, 0x40acaff5, 0xd40a17e4, 0xd1f33639, 0xec004e9c, + 0x070ac943, 0x9de99b95, 0xbaafbb7b, 0xe8829931, 0xb96da19f, 0x15d80895, 0x0a2ee771, 0x678de186, 0xf0dd2b7f, + 0xd502b3c1, 0x5babe21a, 0xc79f5332, 0xdc6d8a5a, 0xb697c94e, 0x9f45782b, 0x769f3709, 0x25d7ff2f, 0x3268b97a, + 0xad279c67, 0x9f177b89, 0xfbe5b0d7, 0x7fdab824, 0x595f3361, 0x29148163, 0x48f56e6a, 0x7997cdfa, 0xdd39b31c, + 0x12823bfe, 0x9c052134, 0xe678770d, 0x6fba28c6, 0x1e52378d, 0x03b75fa3, 0x513df137, 0x36cdce8e, 0x239b7fa9, + 0xe7c71028, 0xf9214067, 0x84e9e952, 0xb20ad8e4, 0xcd1fb441, 0x91fc8dcf, 0x824bbb8e, 0xce9a3160, 0x886ca6d6, + 0xf6e259c8, 0x1396bc84, 0xe1a35d73, 0xdd93d74f, 0x8c188992, 0x04b46d8a, 0xe3afb8bc, 0x48d6d024, 0x8dc7e2a3, + 0x88bfba60, 0xa6228b32, 0xc510af3d, 0x3c029d27, 0x8e3030a0, 0x1ddec594, 0x536f274b, 0x9ef68c0d, 0x15ba2631, + 0xfcad3a94, 0xa979621f, 0x7f95b0a3, 0x01ad3b1e, 0x5a544ba7, 0x11280ae7, 0xa573d3a6, 0x1dc39575, 0x455c092e, + 0x93a84f00, 0x259f77b6, 0xd446dc58, 0xa018b020, 0xd0fe6fac, 0x0a3bb6fd, 0x3a803f07, 0x9420573d, 0x1d85df78, + 0x5a136343, 0x69a2debf, 0xd6388ee9, 0xa063b445, 0x59392403, 0x4a1f82f3, 0x5fe6205e, 0x1c18a7a0, 0x320ac4d8, + 0x9b34aa5b, 0x10a31c76, 0x7a49b33e, 0x4ed936f2, 0x490e440b, 0xcc714508, 0x3b5a81cd, 0x9b25c32b, 0xf32de9e7, + 0xfe753878, 0x3887467f, 0x932db9e3, 0x5f5ea18c, 0xde06a4b9, 0x3fd58327, 0x90df3101, 0x85abd6e2, 0x9559e4ad, + 0x68d01590, 0x224b0285, 0x31208277, 0xeee332f9, 0x07950386, 0x8833a6df, 0x1ee8dbed, 0x30c03823, 0xa8782d7e, + 0xa03abbd4, 0x70117af1, 0x10d5ab0a, 0xe9d93f75, 0x825f5dca, 0x12402910, 0x1e80e9f3, 0x4170a124, 0xc2630c69, + 0x475aac9a, 0x9ca83fec, 0xcb448860, 0xdc41b7ae, 0xa89457a5, 0x16d2471f, 0x943d75e2, 0x3b7e2043, 0xad3d4557, + 0x1e4ecb6f, 0x36a354af, 0x3134fc12, 0x27cca27b, 0xcf1261fe, 0x9dbf0906, 0xc51fa5b4, 0x35180382, 0x2813be5d, + 0xf40bbc4c, 0xda9298c8, 0xba712005, 0x767f9b4e, 0xe656f297, 0xcc781dcd, 0x51d6106f, 0xcde7e279, 0x9a0b27b9, + 0x5745a32a, 0x87f40fcf, 0xc1ab6bf7, 0x6be9e9d1, 0xbcc76223, 0x1851c1e1, 0x91a640ca, 0xf1005deb, 0x2c87a34e, + 0x9bd81db4, 0x471a98a4, 0x3b612470, 0x9c10cd45, 0xa3a7825a, 0x1b62c6d8, 0x619b5590, 0xae3d6d14, 0x9e2d0c39, + 0x2e931d8c, 0x68262dd2, 0xb25ef7c5, 0x686a4330, 0x2b9ac9cb, 0xf58b1c21, 0xb0be7d3f, 0xbd8f3f08, 0xfdc49618, + 0xf1485d7f, 0x9417ca27, 0x5cfe70ef, 0x6d1f5154, 0x6e748119, 0xd16709ad, 0x5cb226db, 0x2f9e125e, 0x71415964, + 0x52047d3c, 0xb4afbb59, 0x16d28ec8, 0xe1e0375e, 0x7dcec819, 0xd55be974, 0xb98a4351, 0x976d3ea9, 0x5721fa26, + 0x603553d7, 0x0c6f6b5e, 0x7f459495, 0x1e44ee6a, 0xa9392c6b, 0xf7c44827, 0x3f1218a1, 0x680db83f, 0xdefbb708, + 0x1e8d3b68, 0x8bb9e3ec, 0x7f5e37f7, 0xa270dfb8, 0xe55780f5, 0x6a7d6edd, 0x88d3f709, 0x37fb0bc9, 0x3baa3208, + 0x09958118, 0xaef4903f, 0x3d72b48c, 0x930dd01c, 0x05db5985, 0x17522e30, 0x2943c747, 0xb12fc34a, 0xcbc6b077, + 0x791ea360, 0xa7f2637c, 0xffd83e51, 0x33e542cd, 0xa50b634e, 0xe1941103, 0x54ae2747, 0xa890b822, 0x1046de59, + 0x5284ce77, 0x3a2826fd, 0xeb7d9c54, 0x650789ef, 0x728754fa, 0x9cd171c3, 0x35fba702, 0xea18df74, 0x8de0b4fd, + 0x756e0369, 0xdacf3a54, 0x1f200fec, 0xca3bbad2, 0xa70931bc, 0x97db2a81, 0x4c5c2809, 0x02db1295, 0x398cf808, + 0x4b8c07d5, 0xae5c3bb3, 0x169c4c11, 0xa6ba0f72, 0x2737aa5b, 0x6cac79e3, 0x42eead3d, 0x72603b75, 0x39a74558, + 0x8619e753, 0x658143c4, 0x41b4d0ea, 0xbf2146ef, 0xc8af47a5, 0xff62555a, 0xf61b5e2f, 0xbf5e8b98, 0x5f883455, + 0x0d38c472, 0xf48cc25d, 0x7ad14e6c, 0x4fe41082, 0x5a4ae510, 0x04e106f9, 0x1e91a10d, 0x7a2fc47e, 0x4776761b, + 0xf7df6c24, 0x7de740f0, 0xac33c834, 0x74303ec6, 0x06b5210f, 0x5a2c3747, 0xca5d4490, 0x410cd928, 0x8f29278b, + 0xf03ec309, 0xbb76fbb2, 0xfe302c5e, 0x868f4191, 0x67a083dd, 0x08f44735, 0x7d10f998, 0xc65179af, 0xa5a426dd, + 0xe3116df8, 0xb8d0ec33, 0xa3f12935, 0x69fad153, 0x0c1bde15, 0x01df80bc, 0x8bf7aa74, 0xa6c45e76, 0x308cf425, + 0x2009c4ff, 0x1ab273d0, 0xea15c243, 0xa7b391fa, 0xfc0097ce, 0xb870631b, 0xa25e619f, 0x6cd34281, 0x4b82dd38, + 0xf229fe29, 0x60a85857, 0x1b4a7bce, 0x64fecf45, 0x3a6a2345, 0x86c2d0b3, 0xd7587920, 0x6b8817f7, 0x722b1ab5, + 0x2bd50ea3, 0xbdb43fb0, 0x67c86263, 0x8b5d9c91, 0xdcd053cf, 0x9225e2c4, 0x4fd4e82e, 0x16e26bb8, 0x7c4b203b, + 0xf62533d5, 0x9eb96270, 0xcde06612, 0xc8b3a8fb, 0x86fd7017, 0x4d398c99, 0x28a3ec29, 0x52b09f55, 0x6d253b17, + 0x8598a444, 0xdff29b2f, 0x2f98a2b5, 0x678b5b67, 0x3ac1d51a, 0x948d5ed0, 0xd6cc5dfa, 0xff13f864, 0x4f7cb29c, + 0x58665755, 0x837dcc10, 0x4db87211, 0x844a9c61, 0xd4ab07aa, 0x76878e56, 0x0d1e1c61, 0xd36b4acc, 0xe7f3a0b0, + 0x5d02d7e1, 0x058e98f0, 0x15720d6a, 0x250f97c4, 0x75c61463, 0xd2a7de03, 0xb7479acc, 0x13b09253, 0x3104e640, + 0x60167933, 0xe5c1a34b, 0x009a2598, 0x6f7cba7e, 0x88b9c999, 0x09013758, 0x2cdda772, 0xf4bc7331, 0x9923392f, + 0xcb9549c0, 0xca96ed3c, 0xfaa697c5, 0x1baa7e98, 0x077acb9c, 0x5b81d39e, 0xd0d1b75f, 0x8a6e01ce, 0x63a79c9c, + 0x7d831e78, 0xe00820e0, 0x434664ba, 0x7c6f8a93, 0x39e1d14a, 0xc80f08b1, 0x33ac5112, 0x8872297d, 0x552f5608, + 0x2a301cc3, 0x4f78f55c, 0xf0cf82b0, 0xa349a6e3, 0x8a62b6c9, 0x0526b6f6, 0xed58f385, 0xb62415b9, 0xb0793397, + 0x86e6c13b, 0xb2fd52cf, 0x4a92d993, 0x33a254b2, 0x09cb602c, 0xfc08b157, 0xdc9ee9a1, 0x52f605bf, 0x6b55ac47, + 0x4e2b8840, 0xae0c2ff2, 0x48e79392, 0xf1bd8a85, 0x60a95874, 0x0464f18a, 0x18d5ab88, 0xaba88c6a, 0x1dde2761, + 0xada34563, 0x75749e64, 0x13a4dd4d, 0x492fd0b0, 0xe538694f, 0x2e8e6476, 0x9ce84867, 0xed46c59a, 0x0f72eda0, + 0x4d106b7f, 0x7a448e56, 0x7e2c09d2, 0xf145ace1, 0x240c2db2, 0x1d4b087b, 0xd3ad986e, 0x59e07a18, 0xf692dc6a, + 0x00543c71, 0xe6d85d06, 0x09a2ab25, 0x3b14531c, 0xe0e0eff8, 0x19e2adc3, 0x3c36b7f8, 0x5b888fa3, 0xe65296e9, + 0xc861b465, 0xf9215e05, 0xe2c3704c, 0x5010822a, 0xe339f0af, 0x81ccb716, 0xf5919a5f, 0xccc86e5d, 0x5ac30c95, + 0xe0d9a7c5, 0x9ed00c31, 0x85581100, 0x4811bc6a, 0xc65f45a3, 0xc2cb3272, 0xab7cb17c, 0xd08678d4, 0x3861f21c, + 0xa634a4d4, 0x5f52eb40, 0xd14d986f, 0x817bafa9, 0x483abe75, 0xf708f3fa, 0xc002c99f, 0xb5870c64, 0x46435a30, + 0x7b6f8210, 0x8f504be4, 0x186f5767, 0x62f8a7d0, 0xcd45cb67, 0xbadecde9, 0x569180c0, 0x47e81ca6, 0x0af015bd, + 0xc3687cec, 0x2c645fea, 0x164b6d0d, 0x145848ed, 0x77d82706, 0x8629924c, 0xe241cf4f, 0x5c4d96b1, 0xb5a3e461, + 0x64683d1b, 0x18d10926, 0x2defe4ff, 0xd3adf651, 0x77958f24, 0x3bf65c02, 0xd2344fbf, 0x1b2b17ad, 0x78be1c46, + 0x009e3fbf, 0x846ad69b, 0x168d4351, 0x6f099343, 0xc5621425, 0xebf6bc87, 0xa17aeca0, 0xb9eb84b8, 0x40ecd385, + 0x3ddca94d, 0x49b244d5, 0xd2767f03, 0xaba605b9, 0xbaa906ae, 0xd5cab7e2, 0xda06004e, 0xca041e32, 0x5433f322, + 0x8ed4fb22, 0xbebede9e, 0x23c55186, 0x8372d8a8, 0x888e0760, 0xc0690309, 0x4bbd95f1, 0xeab20709, 0x986f65a9, + 0x7a058ead, 0x12758a71, 0xc4cb52ab, 0x4d1c1172, 0xb49b262a, 0xff06669a, 0x50171b8f, 0x1e425664, 0xe1833fc4, + 0x66306463, 0x2fafb5b4, 0x53a09484, 0xc62f7e9d, 0xcda3911a, 0xa4c09a01, 0xd8f0c718, 0xc489dc91, 0xbf85cd05, + 0xeae6d722, 0xe0edb5f3, 0xd1ce2b21, 0x331ae7c2, 0x7fcab302, 0x5a7460ab, 0x06744c96, 0x9e2fdf45, 0x254176f0, + 0xb68ff750, 0xfe3333b9, 0xe960b583, 0x3f7de789, 0x26d854d0, 0x7ee6c323, 0xe9b19a00, 0xbac7b022, 0x114fb2ba, + 0xc702a5c7, 0xf818021e, 0xa6f09dab, 0x91a51df6, 0x2c293b49, 0x8aad4d58, 0x3499d039, 0xdbc590ac, 0x5a0d52ea, + 0x73bdc8b3, 0x7f2963d1, 0x2d6177eb, 0x24becc37, 0x3df0c0c5, 0x6cc1c0da, 0xc13da9fb, 0xff1144e1, 0xbb9433d5, + 0xf89401b5, 0xf4203522, 0xd5017d32, 0xbb3de2b6, 0x86a1c2f2, 0x98d8ed82, 0xb25ede60, 0xec435556, 0xb4a218c1, + 0x4377700d, 0xf32bccbb, 0x0aeb1046, 0x1a691d46, 0xeb825fb0, 0x60f8a5de, 0x809f9569, 0x0917e293, 0x2121c72e, + 0x7d103283, 0xfb259c39, 0x1c6a45b7, 0x5f0ec081, 0x394f7003, 0x5a029a2f, 0x69f24e5f, 0x1945c2d9, 0x245e8cb2, + 0x396b692f, 0xc5f8a2e5, 0x778b57c8, 0x2a76f896, 0x22fa736a, 0x4786442a, 0xba03492c, 0x242393e4, 0x9d785edf, + 0x6f2e64be, 0x8781a030, 0x798bfedc, 0xf3e5a3b5, 0x5f470da8, 0xee038beb, 0xb1609087, 0x7962c430, 0x4e4a0dc8, + 0xf4cf250c, 0xc9874805, 0x475eb275, 0x34fd8964, 0x994a89e9, 0x021a4776, 0x6d3e62d9, 0xef01056a, 0xeb820206, + 0xfcb8348d, 0x35643f31, 0x04c65429, 0x20290539, 0xbee8950b, 0x510e5b60, 0x674d0e36, 0xe05a8404, 0xc4ff702a, + 0x8c3e4f8d, 0x1b6f787a, 0x9898f3c0, 0x59e31953, 0x02308e88, 0xeef23af7, 0xbd73153f, 0xbb2527a5, 0x4dda0fff, + 0x67138be0, 0x595e6990, 0x769ca08f, 0xca9d1eb4, 0x181948a9, 0x90c1d5ab, 0xba0a9f20, 0x03f06837, 0xde770519, + 0xcfe22ffc, 0xa101e3e2, 0xf6a5a582, 0x7150bc4d, 0x40d77091, 0x706cc4ba, 0xcad75539, 0x2e2793c5, 0xc6d1657c, + 0x13c9e921, 0x044da673, 0xd3914dda, 0x7303fa3e, 0x13c55682, 0x9b3f982f, 0xa26c3ced, 0x7d75b86d, 0x31444740, + 0xad17ff1d, 0xf9dbbdbd, 0xe7b1e349, 0x140903c9, 0x845b8a8b, 0xf482a1aa, 0xf4f654b0, 0xe85d8d25, 0x19f92c90, + 0x291505d9, 0xcd3dcb52, 0xe069aa05, 0xc460e37a, 0x3c4adae4, 0xe581d3d3, 0x80375263, 0xd826c1c7, 0x10c08697, + 0x7e113b9a, 0x988eb729, 0x5f60ced2, 0xafdcce0e, 0x27677be6, 0xf0214625, 0xd3ffae0c, 0x66bf59eb, 0xd8f3abd8, + 0xaee120bb, 0x47460a3b, 0x0a85ce45, 0x33d680cd, 0x958461fd, 0x0951dcb7, 0xfef4a5a1, 0x106aa3dc, 0x362ac2ad, + 0xdc7081a2, 0xfb4e3bc0, 0xf1d5cb6d, 0x7681bb4f, 0xc86a8273, 0xd4a02365, 0x4f62f15a, 0x3970c529, 0x303b1e97, + 0x011cfae2, 0x485a5806, 0x4ffce7a4, 0x83d0b8f3, 0x6d6658ed, 0xd670f351, 0xdfb7b064, 0x2f845fce, 0x3ce1023b, + 0xb07cb11b, 0x559924ac, 0xa7899998, 0xf8d887d1, 0xa34398c8, 0x0b5d4160, 0x08c59cff, 0x0b436e9e, 0x36391573, + 0x0ba67ca3, 0x9db8d79d, 0xd0587fb0, 0x316eae97, 0xfa9dcfcc, 0x0448cbad, 0x666f2932, 0xeb9c41fa, 0x4244a493, + 0x548a0494, 0x62e22bf8, 0xa96f8528, 0x1aac1e6e, 0xf5dfc87e, 0xe9decd34, 0x1c7b995e, 0x8bef9838, 0xc5e9bcb6, + 0x2f8fd24a, 0x9d2655d3, 0x2bc3ad14, 0x780417fc, 0x818e3f68, 0xed3c8ad9, 0x3761f981, 0xef455e28, 0x3cb3973f, + 0xf07f8b9a, 0xff7c6092, 0xb70b2a8d, 0x4526ef3c, 0x78c5eb4b, 0x352f1cc8, 0x7ab3c8cf, 0xee275b22, 0x470af261, + 0x5180fc34, 0xa0d25980, 0x0bc09cd0, 0x7f184151, 0xbc41106a, 0x76f2c314, 0x34183600, 0x5874927a, 0x93e2bd87, + 0x3e3f414d, 0x2ccc2f1e, 0xf3234a73, 0x031a7775, 0xd6ff13ae, 0xd5dbddcd, 0x9e41378e, 0xd4b65644, 0x99923087, + 0x564096ba, 0x170d6131, 0xd2f82bea, 0xe5c9a602, 0x50ba821a, 0xcf58b6b0, 0x1e8fa293, 0xac30671b, 0xe505514b, + 0xb852858e, 0x231d2145, 0x4ca193a5, 0x0afa5881, 0x2e8f39ee, 0x4529edb9, 0xf2593c64, 0xf2ad8d50, 0x7778545b, + 0x41e66a39, 0x8188fc74, 0xa36520c9, 0x07b96652, 0x56d252ee, 0xda32f623, 0xdac63842, 0x025e45d0, 0xc7c721ce, + 0x5d30c32a, 0x444d3f64, 0x8fba1008, 0xc83f3455, 0x75b34f11, 0xd7384381, 0xafa5ff9e, 0x4d0cc3a3, 0x4cc8f6c7, + 0xfc6467b3, 0xac121499, 0x1642dc16, 0x55b2b4b2, 0x8b996f0b, 0xda7535bc, 0x7c4e60c6, 0x6b98efdc, 0x19e29184, + 0x7f6bb212, 0xd27d389c, 0x939d3d6b, 0x5b381413, 0x72387424, 0xfa48234b, 0x3ff124d2, 0x7fc66588, 0x74feefac, + 0xccec6d0a, 0xfe0e29ef, 0xaf44337a, 0xc264b9a5, 0x5044186b, 0x5d1b401a, 0xd768cf92, 0x0dfbe90f, 0xf42950eb, + 0xf193370e, 0xb17304a0, 0x9b4f8558, 0x87fdb9a5, 0x6cd896b4, 0x13d08d4a, 0x182aaea1, 0x04ea8b07, 0x1391ac92, + 0xd6a27b67, 0x2974d4f4, 0xb010f988, 0x66ebfd5f, 0x2aaca817, 0x47e00b84, 0xb82040cc, 0xb7d678a0, 0x058cf20f, + 0xa65b5de4, 0x2968cc9c, 0xc45d1840, 0x91957350, 0xb227fd3e, 0x1f2d6133, 0x95070982, 0xa45e7c30, 0x10181035, + 0x157a5ff6, 0xd49e9bb5, 0xa5248411, 0x25adcfb0, 0x8c599a62, 0x87d34da5, 0x1ef29dbc, 0xb81ea26a, 0xee52ca3c, + 0x1a598b13, 0x931cc6b2, 0xf12635f4, 0x7b392cc7, 0x0cc456d5, 0xf3e13e90, 0xcb740521, 0xa57265c9, 0xd74c4d24, + 0x615d9b17, 0x5e30e0bd, 0xdc1fc3f5, 0x3bca7438, 0xbe5a4c5f, 0xb81eebdd, 0x902f06d8, 0xea4cca17, 0xa68190e3, + 0x1d939976, 0xf273383c, 0x435834ac, 0xa69462a5, 0xedfd56fa, 0x14142eec, 0x9cd33a07, 0xce207630, 0xeadbc491, + 0xdf6eb29e, 0x022ad700, 0x1cfd6512, 0x78784099, 0x886e312d, 0x0e6c1c65, 0x0c40c78d, 0x4828260c, 0x0a9ecac2, + 0x3cd6dbc6, 0x1aca3a62, 0xd29429f8, 0x0e1241bc, 0xa7d1ff75, 0x0c6954aa, 0xc3b761b1, 0x7376f04c, 0x527c9eca, + 0x6fa112bf, 0x069dccd2, 0xabcbf57c, 0x3c31bfa4, 0x7ef525f8, 0x86488ac7, 0x14907fb4, 0x07e30411, 0x82042d52, + 0xc1d369d3, 0x1635ce0c, 0x86b92234, 0xedc8b982, 0xe15d85c5, 0xa97c6506, 0x158676d0, 0x7564e4d1, 0xa84c4a15, + 0xb8cf8a6b, 0xa738bd18, 0xcfbeb432, 0xc0ca70af, 0x55ff722a, 0xf8b149e7, 0x413057e0, 0x6f9a4691, 0xb357cd87, + 0x323880e4, 0xaa279ca0, 0x56aea39b, 0xd9710140, 0x09967b84, 0x90ec02a1, 0xbc12f0d0, 0x7508fc67, 0x5500705e, + 0xa8c1f23c, 0x9ce51d51, 0x3255008b, 0xf42658e0, 0x34e98968, 0xb5441531, 0x35729865, 0xf5298d71, 0xdd448593, + 0x09f8f8e3, 0x1c0ee9f7, 0x9a462c35, 0xdf3a2033, 0x28b7e043, 0x5c489d9d, 0x25a2a8ee, 0xddff4981, 0x64f37d86, + 0x28b221ba, 0xcd9082bb, 0x0e7de405, 0x297f8f05, 0xda2316b1, 0x3ef73931, 0xa87a6a7c, 0xb3793e7d, 0xea74f776, + 0xdf07eccf, 0x9b82541f, 0x369194a6, 0xccc1b08f, 0x0a47c583, 0x98fc1dc9, 0xba1b8382, 0x15fc08ce, 0xe5c96862, + 0x6aeeccc3, 0xa444fb3f, 0xd7d5db93, 0xecd6bdb4, 0xd95127b8, 0x3fe9cee1, 0xa6bfdf32, 0xfe5643ec, 0x917fcda3, + 0x67ac5655, 0x60ff36af, 0x8ca6a653, 0x55747a64, 0xf197696c, 0x3d48e6ae, 0xa8c9c431, 0x6a033f8c, 0x59ce0a0d, + 0x99214f2d, 0x2cb20db3, 0xe23a07c3, 0x06fa003b, 0x4c45eb3c, 0xc8bde544, 0xdef7b11f, 0x74035647, 0x4d3e5a64, + 0x8c465b7d, 0xdc38cc28, 0x3e72f401, 0xd1dc23ea, 0xfbc26608, 0x05f43eb3, 0x8f193ef0, 0x73b009ca, 0xb6c7dde0, + 0xf82f236a, 0xf800d9b0, 0x946d61a6, 0x0de76bdd, 0xc79e8817, 0xd9f8f701, 0x58790a19, 0xddcd6d06, 0xe0343a24, + 0x95243bd4, 0xcd9a3b43, 0x87a05e90, 0x3c7b4c46, 0x4306f34a, 0x05fc52ad, 0x00b755fc, 0x44510d50, 0x66ebbf34, + 0xf97bd534, 0xc2ab55a5, 0xf1411ab8, 0xc5e06af1, 0xada20414, 0xac360749, 0xcce3ba23, 0x28f11968, 0x907c7b7e, + 0xd7f53d45, 0x694b8936, 0xe9daa56e, 0x3ecad7d8, 0xd06cddb9, 0xfce70b5d, 0x41cf2ac3, 0x693fce3c, 0x3729690b, + 0x715fda17, 0xbbeeef7b, 0xaafb29ca, 0xcfcef3cd, 0xb424ef90, 0x6b810192, 0x03099879, 0xb9254e41, 0x7912f070, + 0x8d121d3a, 0x3098c028, 0x0de6d9b0, 0x4b226704, 0x5e6e2460, 0x84778345, 0x662ce54f, 0xfd7b38c3, 0x1a3f61fd, + 0x6925bfd6, 0xb8aa8dd4, 0xaddb8d89, 0x2de986fe, 0xf51361b0, 0xa051b413, 0xdf82a8d1, 0xa3b0324e, 0x60f09fa9, + 0x136b641c, 0x662f2daf, 0xc2e9f530, 0x1e2afba4, 0x02dfd428, 0x6df5a989, 0x53af7e1a, 0xbb38c1c1, 0x7fe087f1, + 0x73e26411, 0x5a16fed7, 0x91550809, 0xea834d61, 0x53fc28af, 0x75e3c3f1, 0x9dddf8a3, 0x179246c4, 0xaee6b30a, + 0xd3145fa4, 0xb256f7b2, 0x86bf6fed, 0xac9fa550, 0x0c67d4de, 0x0d1b0837, 0x83f6ce13, 0x6335696e, 0xb9b3dc06, + 0x8e826e63, 0x4a0a26f0, 0xbe54716d, 0xc1a7d06c, 0x83be6047, 0x9e8ed01c, 0xd8c09267, 0x1abe9d28, 0x45c6f8a2, + 0xd0d0496e, 0xe266765b, 0x94b5b92c, 0x92add09d, 0xa312cf3e, 0x349754ef, 0x759a18a1, 0xa4b3c298, 0xdc100fbf, + 0x02a570af, 0x7d97d4aa, 0x51937a8b, 0xce300dc7, 0x7d6ef543, 0x1ea5ce15, 0x002cffa6, 0x0d4c7160, 0x129af068, + 0x8b4919d7, 0xf63d14dd, 0x94387ce0, 0xae503194, 0x353df32d, 0x44eb0621, 0xa39b2129, 0x7dbb3b8e, 0x041855a0, + 0xa6a7b553, 0xbc1e27f9, 0xec353ded, 0x8d8be6ab, 0x619f65b1, 0xa434fe78, 0x64ed76f4, 0xfac0bbea, 0x88faa8dd, + 0x80a46e71, 0xe3334662, 0x9cf01f57, 0x27d26fd0, 0x95fb7587, 0x15f7db7d, 0x6fd66256, 0x6609d01b, 0x179547c1, + 0xeb4218ca, 0x138789a2, 0xd6e31a49, 0xa3795ebb, 0x1a57c8d8, 0x11da17a5, 0x3b7d2125, 0x7f60b7ac, 0xd01d99b1, + 0x83a92326, 0x1692b075, 0xcef2c3fe, 0x8231aca6, 0x68893232, 0x0ae6832c, 0x702021d2, 0x56b8d250, 0xe3a27314, + 0x3e80b89c, 0xa815a41d, 0xcdac5e00, 0x1b24e27d, 0x5136d71c, 0x6bfed12f, 0x9fa22ef7, 0x12d1f074, 0xa71b14d9, + 0x17040590, 0xd0c17835, 0x72eaff30, 0xcd63455b, 0x9e860bb5, 0x79d928e2, 0xebc7fa57, 0x69b8bc9f, 0xa8bd47d6, + 0x02226511, 0x1a324543, 0x262eb70f, 0x2d061bd1, 0x4e313d12, 0x615190a7, 0xc097ce51, 0xcee0e4e7, 0x9068d5a0, + 0xd21a14fb, 0x220bb72b, 0xea4b1bb3, 0xa506ae7c, 0x16d97878, 0xfc4a8298, 0x7d4eb1c6, 0x2b38685b, 0x1d509b72, + 0x82d5f7fa, 0xff650c7e, 0x030dd523, 0x2b3bea7b, 0x384bbbcb, 0xe260e1e8, 0x40f9cfcc, 0xabc47259, 0xf6cff06c, + 0x96630793, 0x1ebfcdce, 0x2477e01d, 0x4ddcc799, 0xc4bcf490, 0x6fca8b9e, 0x131c1c1a, 0xb53d659d, 0x5542c595, + 0xaa99f65c, 0x89093e01, 0x4662a7f8, 0x16b4b76f, 0xc5fac707, 0x06b32e4a, 0xaf1ddde1, 0x3c4448e1, 0xc6223052, + 0x3c6c6758, 0x2f7a112f, 0xa0a561da, 0x6bc7c596, 0xdee47ae0, 0x57c51197, 0x97f12237, 0x3b8883dc, 0x7bca6086, + 0x7b417c98, 0x829b0462, 0xa68e3fd1, 0x09633c07, 0xeb841d1a, 0x2d7cd8c7, 0x419541e7, 0x613096ce, 0x4eb472d6, + 0xe8af817a, 0x738e2819, 0xa3f88215, 0xa44ed8cd, 0xabb6b66d, 0x044a5119, 0xfda0817d, 0xcba610c4, 0x1413cb4f, + 0x1eeb9022, 0x7f2a992b, 0xc5dc9451, 0x9a042fd6, 0x79514c7f, 0xd7f7ac77, 0x109da0fb, 0x525c5722, 0xec754a88, + 0x9676c7a8, 0x2feb5438, 0x28e95af1, 0xf9d6c796, 0x6b0def85, 0xdae98c39, 0x5736c4f3, 0x7ff4ab31, 0x0aad3ff5, + 0x6c803707, 0xa9861794, 0x647e73c8, 0xabb33cdb, 0xccd3150a, 0x8f302bb7, 0x60ce866e, 0x849b7a5d, 0x911fa089, + 0x49aeac06, 0xe1550f24, 0x00efe380, 0x9b6bb6d0, 0x670a6cb8, 0xf329ed09, 0x406071e5, 0x3c502bb2, 0x64e8e87a, + 0x3e7720b0, 0xa7556e59, 0x44fafecf, 0x93f80a9f, 0x38c9da2a, 0x5b656070, 0x4a219000, 0xde3cdf3f, 0x6ab5ef15, + 0xc1779ecb, 0xd69d39d3, 0xd694504b, 0x5699666c, 0x2126d8ae, 0x79ddfa76, 0xf98bbf56, 0x47a5abe7, 0x2fbe5592, + 0xcd6f25a9, 0x6205f77e, 0xa11005ce, 0x6d13cab4, 0x644700a6, 0x08b69361, 0xdc258fa4, 0x0dce7fd5, 0x73e2766c, + 0xfa5fb5b4, 0xd6e36ba3, 0x331df775, 0x2fff7a09, 0x97d711a3, 0xb2713789, 0xddd556cd, 0xc863493f, 0xdada27aa, + 0x781492f8, 0x63bbd666, 0xe94bea0c, 0xaca32b1b, 0xe58b99ef, 0xd747a37d, 0xeebf13dd, 0x72d43b4c, 0xde191ced, + 0x6a752f38, 0x6672be2e, 0x32a40a5b, 0x96ec40e3, 0xbd70808c, 0x3feca169, 0x454ea281, 0x36cd7008, 0xe263c40b, + 0xd22279ae, 0x468f6469, 0x0f4d506a, 0x54ccbc91, 0x0c5cecde, 0x80f17090, 0x1f80da05, 0xe0c93575, 0x57b0549d, + 0xe2be0563, 0x25a5a38e, 0xbe3b2470, 0x3b2865df, 0x78fbeb9e, 0x35899f26, 0x501d5b02, 0x7bc929c4, 0xa718ce6a, + 0xc5e099e9, 0xfc75d118, 0xb9eebe4d, 0xb36f9d44, 0x5fa1ecbc, 0x3614bb6f, 0xe49797e7, 0xd961f88f, 0x076bb7bc, + 0xda2678c2, 0x0f5aa920, 0x75a64592, 0xc32ae90f, 0xa75f20d6, 0xcd51f72b, 0xb0276074, 0x2fc04664, 0x4aafc4c2, + 0x8423668a, 0xc04d9f43, 0x78ea767e, 0x1f30d795, 0x64ec4b42, 0x14be0677, 0x6261ab54, 0x4e2832b0, 0x6affa424, + 0xa6452c5d, 0x8c9bd7a5, 0x66ca4cf0, 0xa17d02ae, 0xdaace13d, 0xe93c24c8, 0x683ed165, 0xf15693cc, 0x885aef39, + 0xb72bcb56, 0x664c5056, 0xa9cf5141, 0x5b61ce48, 0x6ff8c3d5, 0x1228bb67, 0x668aed68, 0x83993b64, 0xb9f1de71, + 0xb99034e3, 0xcb984f7e, 0xa5a19e2c, 0x0f6986b4, 0x6aea0763, 0xfbda67b2, 0xc61532b9, 0x1a5074df, 0xe03067ac, + 0xf94a50f7, 0x5bcb2a25, 0x6edd8312, 0xec91b61f, 0xe752c0b8, 0xf62cdee2, 0x17e72ac7, 0xe693c820, 0xb2c7055b, + 0xf5401b69, 0x5ac72322, 0x5b1d19e5, 0xad19c6ce, 0xb4f34e99, 0x84cc6035, 0x37b220ce, 0x518b5395, 0x120ad630, + 0x687004ef, 0x92b9c4c1, 0x80cc5308, 0x23508a8e, 0xfc9d2fa8, 0xbf7987bf, 0xd723e7f4, 0xb50be127, 0xe2cb5211, + 0x6b8d27f3, 0x79c1c580, 0x07397be2, 0x0f581de1, 0x214e8ba8, 0x2c21d2e5, 0xf20462ee, 0x5ca18254, 0x8c081735, + 0x0d5a752d, 0xdb66bd1d, 0x175b1771, 0xf441acab, 0x7c68893d, 0x7ba768a9, 0x81b2b668, 0xfbb33383, 0xa0c53472, + 0x9b41c2bc, 0x4d6ebdf8, 0x6d88eab6, 0x8b7e39ca, 0xe505f1fe, 0xeff9a56f, 0x8fd27962, 0x164aa4a0, 0x1ddbe444, + 0x1c1b65a6, 0x7173fd02, 0x40a8c33c, 0xe56cc74f, 0x2ce59ae8, 0x76bde303, 0xdeec9849, 0x9f73e939, 0x07b281ac, + 0x88f0313c, 0xc4a86c91, 0x942b0b2d, 0x55b007c2, 0x2a334081, 0xda23c463, 0x4b4f63f9, 0xa006b234, 0xced42416, + 0x164ae8d0, 0x62c41b24, 0xf00c20e1, 0xf06f54a1, 0xcec7f4a3, 0x888d6b58, 0x17898d8d, 0xefb86ecc, 0xbe49cb63, + 0xeb2b85c3, 0xa9f434f8, 0xfa08301d, 0xabc66b99, 0x3bcc286d, 0x6019313d, 0x9f2abb69, 0x8bf88875, 0x749b3468, + 0xe5830d30, 0x0d628082, 0x1d3f4c09, 0x67dbd4d2, 0x94cf649e, 0x31c955a1, 0x2abf6d2e, 0x81b53ab8, 0x49fa9a18, + 0x36ec60e1, 0x8b80f488, 0x35eddabf, 0x71a651a8, 0x9c44bac7, 0x28bb333c, 0x4545b3da, 0x61cd0378, 0x863e7cb5, + 0xfd502b7e, 0x1097fba0, 0xa53ce422, 0xa49bc061, 0xc31cd0fc, 0x5b7a6f3b, 0x533e2d7e, 0xc4e30607, 0xcfbd00b6, + 0x89437c5a, 0xabaaca49, 0x57960d81, 0x08548c60, 0xc4a71b7c, 0x19a911a3, 0xc9327694, 0xd35f5804, 0x97ce4979, + 0x5ea29052, 0x406dba48, 0x981c3365, 0xdd40ebd8, 0xa675462a, 0x858c8564, 0xea93494d, 0x840fd9c3, 0xe86e4410, + 0x14070ab3, 0x327cdd11, 0x4b11d71d, 0x4308622a, 0xf9f76149, 0x22996bd6, 0x924edddf, 0xd7da0e11, 0xc3484ea6, + 0xeb1f757d, 0x488db1ac, 0x479b123c, 0xc3374d8f, 0x0f1f42b0, 0x7c64a047, 0xa7eb54cc, 0x99339a97, 0x11ee546d, + 0xb6bc3882, 0xebc1ec46, 0x5e6c73e6, 0x0722f275, 0x81fa6afe, 0x701e8930, 0x95fd1e85, 0xc188cad4, 0x69c95ef2, + 0x2158cc96, 0x950399e0, 0x003ba6c8, 0x4614e1ff, 0x6203b1fb, 0xd1070c90, 0x8aab15a6, 0x6dcd018a, 0xd456de08, + 0x706e40d2, 0x3391df2b, 0x9df62dfe, 0x69e52e95, 0xa2f8260f, 0xea0d9c28, 0xa1be358b, 0xdb98ad95, 0x2f012385, + 0x25f6fa59, 0xf0c3c995, 0x03056756, 0x5419e118, 0xa864af85, 0xe7af1d31, 0x705c43ac, 0x5aa79190, 0x7bf86a84, + 0xc44633f9, 0x3ab1f82e, 0xf0c0d9ed, 0x19dc73d0, 0x41f30f89, 0xca9c8048, 0xe7546354, 0x9e0b4583, 0xc8f7d365, + 0xe001b241, 0x3a7d7e10, 0xdab9d7c0, 0x42e656e1, 0x177e8f51, 0x7562e918, 0xfe864fe8, 0xde48c283, 0xf3eab497, + 0x0cf59a87, 0x515f4631, 0xc7e5d72f, 0x880a5fc8, 0x03297a82, 0x56b32326, 0x0b8833ac, 0x31d346fe, 0x3483186b, + 0x4ee8e95c, 0xc886f438, 0x76bb5730, 0x012f9ecb, 0xde197e1b, 0x64cde9d7, 0x95724a3f, 0x2f95481e, 0xcc3f3a42, + 0x8a515d8e, 0x9aa8f0c2, 0x31830b49, 0x7bcebfaf, 0xaf9909b8, 0x839a8e4f, 0x09134c5a, 0xaa7dfc76, 0xa2c25f0a, + 0x96444c63, 0xc704aec8, 0xf5c04725, 0xd7ee8ed9, 0xe065361a, 0x8fa3d56e, 0x205d2632, 0xeb0b89b5, 0xd17a5d8d, + 0x4d58ec95, 0x4ebfe723, 0xdc3748f4, 0x809754cc, 0x961ef810, 0xd2d2d120, 0xd5a6aafc, 0xe128541f, 0x8166c718, + 0xcceb86fc, 0x9ad0d91e, 0x3b71aa56, 0x43d7eefd, 0xed0ab1f2, 0x8d827327, 0x6c2b9378, 0x5c92f82c, 0xb7bd246f, + 0x11e118e7, 0x2f1d1f6e, 0x7a769cd0, 0x8cccdd77, 0x30094452, 0xfefffae6, 0xde9e93f8, 0x9aef1a44, 0x0361aa74, + 0x431733d3, 0x2d776597, 0x7d81e037, 0x503f87aa, 0x8846045e, 0xd209d2b3, 0x574a6e07, 0x287f192e, 0x2fef6526, + 0xb28d0638, 0xfc93c00d, 0x79d1df1e, 0xb0700824, 0xb26151a9, 0xfb5da1e7, 0x8a8bca34, 0x78d0d563, 0x40c197b7, + 0x14910613, 0x23b62c6f, 0x3b406585, 0xfcca12c5, 0xfd38a3c7, 0x854255a7, 0x9a40d078, 0x7e2046a2, 0x165e774d, + 0x51298a18, 0xf68f8dac, 0x5a16cdc1, 0xad46a5ec, 0x71edc613, 0x7f888a41, 0x215ce5b2, 0xcd13b0a3, 0x02f3f673, + 0xf589f21f, 0xe502c530, 0xe642eb84, 0xab848d4b, 0xa5723968, 0x8b4c5bf4, 0xfbd3d5ee, 0x534b7ba8, 0xd5e5dc46, + 0x23c616a0, 0x56645ee3, 0xf9b375f8, 0xfcfdb996, 0xe5bd33c4, 0xb0634660, 0x5cb0d97a, 0x02dcd189, 0xfc89070f, + 0x51cc62aa, 0x6e264d48, 0xf8f67d34, 0x367dbb8e, 0xe205dfe2, 0x163093fc, 0xeb702e8a, 0x4b33beaa, 0x1f2c69e6, + 0xa631bcb0, 0xd6ad54ef, 0x01b034ac, 0x34213c5d, 0xe20f48a4, 0x03b57aa3, 0xa9d18506, 0x963ed828, 0x9b805551, + 0xbb57c58c, 0xc6329ed1, 0x38487496, 0x7cf6d5a1, 0x8300dfbe, 0xb0a0610f, 0xfbe30c61, 0x98a07c1d, 0xc9e1eee4, + 0xda8bffa5, 0x5bc9fd61, 0x70a2ae7d, 0x91752e6f, 0xe46d0c17, 0x59178a23, 0xe32d91af, 0x57c869ce, 0xf04af9e9, + 0x449e3188, 0x60aec9a6, 0x1a84ebcc, 0x6257368b, 0xaed1eecf, 0x755d7e1c, 0xb7a28495, 0x642a6c3d, 0x4b0625e7, + 0xf832d8a1, 0x9405c6ff, 0x85fb6c90, 0x62bab2b3, 0x62bc8854, 0xfadbe031, 0xe29e0efd, 0xa883b6a4, 0xe44a7ed1, + 0xc021ecad, 0x66adb7d6, 0x56a21130, 0x78619773, 0x61812dad, 0x1ab6d672, 0x1383dfa4, 0xbe12ff1d, 0x9ebaa31c, + 0x682d4d61, 0xce2a6789, 0x8986327e, 0x6fc9c697, 0x44e9d667, 0x9bd3631f, 0xaa1b599c, 0x7fe08702, 0x6f541b32, + 0x1f71cbc4, 0xa3f72260, 0xe076d429, 0x79ecf60c, 0xb7ad2b2f, 0x3db26c6b, 0x4ce14149, 0xbc53cdf0, 0xd0d6b21e, + 0x1d0741dd, 0xb6855d76, 0x1a15ae69, 0xa870f350, 0x43559fea, 0x7ea576df, 0x7e3bf244, 0x55f29010, 0x5e65297d, + 0xba085b2c, 0xc3c5e49a, 0xcc28bf03, 0x3360b09a, 0xad5d27bb, 0x2dad4e58, 0x7dc1bc05, 0x86c0e880, 0x27681a22, + 0xebb8325e, 0x29998cc9, 0x3f1e9767, 0x1a1287dd, 0xd2457a70, 0x199f1dff, 0xd64ec7f0, 0x37c0ff31, 0x3326e265, + 0xf89107a6, 0x0ea5e8f9, 0x36ebb2db, 0x01975e95, 0x94b3975b, 0xa6f420ac, 0xe12a8ddc, 0xbc2365bd, 0x5195a6a5, + 0x1dc1d79a, 0x8e54d583, 0xab5e0859, 0x5b78d3d4, 0x053f865a, 0xec029bf6, 0x476cf134, 0xa81407b3, 0xe758d2e3, + 0x786f56cb, 0xaa173a24, 0x9af4f0d5, 0x0a7dcc70, 0x420950c9, 0x6de94e38, 0x1b66f3b1, 0x355385e7, 0x16bda9fa, + 0xa9b47578, 0x5b360692, 0x26a821f7, 0xf17234b2, 0x3b12adde, 0x3c785dc9, 0x98c46a88, 0x236946f4, 0x804b277c, + 0x58d13fd5, 0x42e4e31c, 0xd9cd86da, 0x6aa58e9a, 0xf30ba64a, 0x35300c9b, 0x41d95587, 0xab96a995, 0x40f88e9f, + 0x3caca9e7, 0x6c673f9b, 0xe457b50d, 0x6a23361e, 0x0a5f8a54, 0x560d89af, 0xcadabfde, 0xd70eee0e, 0x512ce0ae, + 0x2ce3c114, 0xfff50ac0, 0x0396fad6, 0xa14f7e69, 0xb02db8b5, 0x224c548b, 0x15b5a47b, 0x7de04e5f, 0x2ba8f346, + 0xf54ff41d, 0xe9f1ae1e, 0x1451da61, 0xebd241c1, 0xdeda80ca, 0x69ce5847, 0x617721ef, 0x15a56181, 0x7cc8b361, + 0xb058694b, 0xecbabe5c, 0xa67e5364, 0xdeef15ea, 0x92e1adff, 0xc17c4b07, 0xca512390, 0x4fde8e59, 0xa3c5432b, + 0xe77a8b4e, 0xe09dc2da, 0x130090ba, 0xb587899f, 0xf030aec2, 0x464106e4, 0x4ec3f755, 0x0ba53dd0, 0x2d4cee11, + 0x4868d16c, 0x35172da8, 0x6d3c49d8, 0x0b192065, 0xd5086e22, 0x71e513d8, 0xe0f59d6f, 0x13f7d602, 0xe6036731, + 0x50cd896f, 0x929ec1e3, 0x11c5d648, 0x4b77cc84, 0x70a0e665, 0xab98a1d3, 0x3d7cf313, 0x3548c8f2, 0x8eea541d, + 0xe68052a1, 0xbfadfd5e, 0xbb60c0d0, 0x09cbf7fe, 0x46b820c8, 0x091dad4a, 0xd3f88b0c, 0xbf9fcfac, 0x0ee546f9, + 0x4e2a4770, 0x9c754f27, 0xbacd1f6f, 0x9746e935, 0x4e56d1a5, 0x83d0b957, 0xe5d0d745, 0x2537f76c, 0x149d46b6, + 0x8abfeeb1, 0x3f119119, 0x052eaa40, 0x65ad471c, 0xc20f831f, 0x81f5cf89, 0x843d11d0, 0x12c144b1, 0x16f13d7f, + 0x7cfe4bb5, 0xf254a43c, 0x0f942117, 0xa6dbf9b5, 0x86189cf9, 0xd1455a51, 0xdf03736b, 0x6eb28a60, 0x37ae6686, + 0xfad652b7, 0x8f8d642c, 0x27998dfc, 0xb64c1497, 0x944d08ee, 0xa66b92bb, 0xea16bd18, 0x24c53bbe, 0xe8c6bb56, + 0x7e9dc031, 0xcfdf2acd, 0x9e5e7d31, 0xf9ba1702, 0x7a69bc68, 0xcdb34b69, 0xea1f65c3, 0xd60cc183, 0x9a0d7ebe, + 0x8f74f0ba, 0x16bf09c2, 0xbe3c4455, 0x2125434f, 0x8667c83d, 0x929d07a2, 0x9ec08000, 0xf44e6bf2, 0xce5925c1, + 0x8e19dc11, 0x0741326b, 0x466ff4e0, 0x722deaee, 0x6ab6c795, 0xf226dbfc, 0x160a5e82, 0xa264379b, 0xab46db0b, + 0x6ff81f57, 0xe74cfdb5, 0xe289b734, 0xcb468f64, 0xf9e898ef, 0x668e25b4, 0x0e71418f, 0x77e73191, 0x1c93baab, + 0x18146f1d, 0xc96fbdbb, 0x9fc04076, 0x67b53475, 0xc40664a4, 0xcb51471a, 0x57b033ac, 0xd985b92e, 0x698bc977, + 0xb6e801ed, 0x893e3974, 0x9f3ea148, 0xa0b23eb1, 0xceb41027, 0x14681940, 0x0bc39d50, 0xe12d2642, 0x57917765, + 0x4be621e8, 0xe6717cf1, 0x6c37d9c1, 0xcce83d58, 0x8e22973c, 0x947d346d, 0x20317d32, 0x2cf666b2, 0x72947a62, + 0x45000521, 0xc4a4b0f8, 0xfea07588, 0xea808355, 0x93807365, 0x1fb012cf, 0x8a33a949, 0x40ec147b, 0xdc10647e, + 0xf0abb33e, 0xe9f29848, 0x2fee3e64, 0x012b72af, 0x8c2561d4, 0x4aa5c1a1, 0xeb6fef18, 0xde9b8e10, 0xc84035e1, + 0x46bf5408, 0xce2b12bb, 0xfdc58b87, 0xe9bd0b3e, 0x4b898d41, 0x8203de73, 0x661249e1, 0x484005a1, 0xd89ab63f, + 0xa62337a0, 0x00e725c2, 0xa19b7fc9, 0xb5a753bc, 0x39e75c68, 0xc5607012, 0x561c17a8, 0x9668b908, 0x5a392ada, + 0x97901b2a, 0x77f2edf4, 0x35e652b9, 0xcfa389d7, 0xb9df5137, 0x42182d57, 0x1bff711d, 0xdc56baf2, 0x70afcec3, + 0x7ed2ef9f, 0x486de769, 0x24842a47, 0xb1e923a6, 0x6a44100a, 0x5a5e5211, 0xd5c927b2, 0x7cd9665d, 0xaec2e8b1, + 0x3fa4363b, 0x8a627de5, 0xc2281b7f, 0xaeb77670, 0x0c06dcfd, 0x899f929a, 0x909289b9, 0xf21bf691, 0x34ffa467, + 0x7ac55efc, 0xa92da08f, 0xce1df95f, 0x2268c4e0, 0x17d221d9, 0xdf4b473f, 0x58738716, 0x35980bdf, 0x57a3c512, + 0x71a34d72, 0x027cbb90, 0x0158badc, 0x8abd1630, 0x3b9f2b9b, 0x629d6f5b, 0x1b83899b, 0x8761e54d, 0x7dbeaf39, + 0x582798a3, 0x9d0d07c3, 0x5649c4f9, 0x78d69be8, 0xa70faf4a, 0x4d4e0020, 0x5a8f2aab, 0x9539cefc, 0x2af2c9b7, + 0x819542c1, 0x0ee86a9b, 0xe1341126, 0xa4edee45, 0x4105c00c, 0xdd927371, 0x488f4f52, 0x1f2919e9, 0xdff5a3a2, + 0x4b9638ff, 0x4f83bcf8, 0xcc4c5637, 0xf33e5129, 0x3d791634, 0xfa3bb6ef, 0xe4583367, 0xd19f8464, 0x01041dbf, + 0x95f07a99, 0x34b63908, 0x2b1d9629, 0x93b6a957, 0xd2f25606, 0x4751d41a, 0x26a7f4d1, 0x1f6d4e35, 0x26149f40, + 0x3f05cee1, 0x6295791c, 0x8afce077, 0xabccb56c, 0x92357dda, 0xe11e4719, 0x6f065b31, 0x924e506a, 0xea670a10, + 0xd40f069b, 0x9b96c7c2, 0xad9bb2fb, 0x0b6b48e9, 0x540834c7, 0xf5310aab, 0xac2b5ffa, 0x3b2d5060, 0x7a34213a, + 0xbc554f35, 0xfb9a2e51, 0x26b888c4, 0xedb12be7, 0x9d8ffa5a, 0x077f294b, 0x7fdf9259, 0x91261f30, 0x5159b4e4, + 0xb42fe2a9, 0x9faff88c, 0xaa41d248, 0x9ce7a277, 0xfa6b5f8e, 0xa4c04dd9, 0x6f263d6e, 0x6d4bdda8, 0x2933b289, + 0xf9160817, 0x4637f32f, 0x8da3fa89, 0x2ce1d2dd, 0x57af6a12, 0x94756413, 0x7af6d389, 0xd3dd82c4, 0xc1558c79, + 0x44b3cf64, 0xd8f0fd31, 0xe6250000, 0xade30e6d, 0xc7e87023, 0x55bdba9b, 0x1f97aa45, 0x82a1ab8a, 0x3f189abf, + 0xb3366645, 0x965e778f, 0x704d74a8, 0x7bb56dae, 0x4d281693, 0x2b54f7a9, 0x2453e0ba, 0x20d72783, 0x7c288f3a, + 0x6bb2e72a, 0x3d7c6170, 0x49571a05, 0x42f1543e, 0x8aa2669b, 0xce075487, 0x20260d1e, 0x47b9729e, 0xa50f73a2, + 0xd5078c92, 0xda92c68b, 0xae40c067, 0xad72001e, 0xb775f6be, 0xbf7854b4, 0xec0cab69, 0xb54b4414, 0xe5f7c22d, + 0xb13f9e36, 0x17972d72, 0xef9313c4, 0x99fc1998, 0xa41b9106, 0x6f23bfcd, 0xaca71821, 0xc14f3d64, 0x928d831d, + 0x1ed1a72f, 0xd953af97, 0xd535808b, 0x7c73b359, 0xcec0b5c9, 0x6d39574f, 0x1fa3bc00, 0x3fb93507, 0xfc7259bc, + 0x74fc88d4, 0x6e6a44b7, 0xebabd772, 0x49c5b04a, 0x41e7ab44, 0xab606390, 0x9db96884, 0x1663fb0b, 0xb456ca8d, + 0x0c99e21d, 0xa42ab7c8, 0x88c7e2f3, 0x8c04a173, 0x759e3f91, 0xd2f21991, 0xfd7ee2bc, 0x127f414a, 0xaa3ebae3, + 0x149d2096, 0x7d8044b1, 0x27a1722c, 0x9dc64dff, 0xde75a353, 0xb34fd4de, 0x278e8d96, 0xbc92ef0f, 0x4293542a, + 0x35e03a31, 0xdda645f8, 0x69c532b4, 0xf1a6e302, 0x86ea9985, 0xc45cf930, 0x8b6e273c, 0x155d8f01, 0x307c6b94, + 0x57e574bc, 0x3f01e7e9, 0x814c9d45, 0xcd67e314, 0x815d87a0, 0xeeead4c3, 0xa5e4ed64, 0xce6a4e9d, 0x91298cda, + 0x0a163b2b, 0x6ad93bda, 0x021d66d9, 0x6bba9863, 0xe3823e86, 0x0c475e04, 0xd1a8a6b6, 0xadd886bf, 0x41ba653f, + 0xce4e3035, 0xffc3c244, 0x7b550689, 0x964ce5ca, 0x22c875fe, 0x0f7ac205, 0x404e03ab, 0x54130ef3, 0xd1b2c84e, + 0x1bbcf340, 0x668fe972, 0x08f3cb94, 0xf67f17cc, 0x540320e5, 0x5f96cb11, 0xa8953533, 0xe10dcb10, 0xe1b7dd0c, + 0x29b62d9c, 0x42a1090b, 0x19302d6d, 0xce085e10, 0x01017c04, 0xf217f0dc, 0x3df2acb6, 0x1dd2ba04, 0xecc6a359, + 0xbba95a64, 0x889ff276, 0x632bbb86, 0xc00016cf, 0x8c9cafc8, 0x3a8961c0, 0xbbb884a0, 0x9daf7023, 0xb6ca71c5, + 0x599364ee, 0xe2055a4a, 0xb1386d01, 0xde926f26, 0x16c0c9f7, 0xf2120f9b, 0x3be50c30, 0x5f6839d1, 0xe9699803, + 0xaf8fd594, 0xe5e4eb68, 0x70ddd157, 0x16a6517e, 0xc7defc81, 0x159e2f8e, 0x7974a220, 0x5bdfe1a2, 0x751afdda, + 0x27e5a94a, 0x9691e7dd, 0x3dff4ab9, 0x97c8c72d, 0xfa9313b8, 0xc0255e7e, 0xf0b4d1f3, 0x2b9b5417, 0x422e6e5b, + 0x1c09e047, 0x79e19373, 0xe71575c0, 0xd79f90f6, 0xb888606a, 0x780313b1, 0x01ff18c9, 0x95be2dbd, 0x9cc920d6, + 0xfaff1fc7, 0x4cd98a06, 0x4a313ebe, 0x37fa1e7e, 0x9074ba79, 0xe821f7f0, 0x83df72f3, 0x320e2c4b, 0xee0f633a, + 0x0b366013, 0xf6a765af, 0x63231b4b, 0xc9121c64, 0x30fc7be7, 0xf542e20d, 0x349ee40f, 0x2e2622cd, 0x5cb37305, + 0x639e84e0, 0x4b1bc85a, 0x5086bc2d, 0x638217f4, 0x0f87cf87, 0x941ac72a, 0xe627a957, 0xf2bc41a6, 0x5a676610, + 0x130306e6, 0xf0849cf8, 0x608f5414, 0x2205daa7, 0xebe44f6c, 0xd4745546, 0xc4b51604, 0x7cc8ac97, 0xc99d9a34, + 0x8d501a4b, 0x4e06fb34, 0x7d5092df, 0x5db21793, 0xf6838375, 0x9e291eab, 0xfad10595, 0x99cd824e, 0x42dc525e, + 0x09f541dc, 0x36f52ee5, 0xfc01b187, 0x29154d41, 0xc10beec0, 0xf74b6a8b, 0xa6b9db6e, 0x4ec6c665, 0x86d5ba05, + 0x132db13d, 0x4a7a37ce, 0x56029f94, 0x57d2482b, 0xddf470b2, 0x7967e419, 0x8890f563, 0x6490fa01, 0x6add7d2d, + 0xd8df32e6, 0x968ac856, 0x858422af, 0x15836b0a, 0x1ac4869d, 0x8e88e50b, 0xea72ffc0, 0xdf2d5989, 0x0b956d5a, + 0xd1d5943e, 0x1d4c5012, 0x08767784, 0x4f628530, 0x45d626e7, 0xeaad02c9, 0xeb073b81, 0xb18290f9, 0x47d6683e, + 0xbdd958f4, 0x1640e2d2, 0x754961d6, 0x11c3ec2b, 0x69f72b6b, 0x33ca4987, 0x60fc34a4, 0x86405c87, 0xc979f907, + 0x5ce58d02, 0xdff97353, 0x72d0d324, 0xd7596ba8, 0xeaadb861, 0xdb66adb0, 0xf1b5605f, 0xeb5c2131, 0xfd1f6b3c, + 0x8969158d, 0xf26147a5, 0xe87ca534, 0xeaeaa516, 0x42146e7a, 0x0cb3433b, 0x56e3cc13, 0x49ddaa44, 0x4417251c, + 0x37009745, 0xb2558aa8, 0xe7fc2fe8, 0xb6d45e32, 0x938e3abb, 0x9c7d50e9, 0x7f526578, 0x0e7d36be, 0x01012f4a, + 0xc2aa3cec, 0x98b8f248, 0xcc5fd5c6, 0x5f48600a, 0x228a0054, 0x70c0ddf2, 0x1602a555, 0x1caf20aa, 0x9fd4290b, + 0xa14b708c, 0xfc0ed074, 0x3b843af0, 0x84d2002d, 0x97aa8a9f, 0x9b0f6bfe, 0xe494b2e2, 0x9cffa24f, 0x36d88b3e, + 0x3409e264, 0xd56c5b7b, 0x6e114651, 0x1b0ca3e5, 0x1e310475, 0x5cfcea67, 0x7a99f62b, 0xedba63e2, 0x2fda3d25, + 0x04bdf774, 0xbcace248, 0x02978a94, 0x2eab0163, 0x09c9d9f0, 0xfeb17857, 0x9bd75c51, 0xbe98ee65, 0xc4c6b737, + 0x1ab2097a, 0x339de3ab, 0x1ec7e44a, 0x2a6b0023, 0xc7173b8d, 0x1059a79a, 0xa93481a2, 0xec7b77c3, 0x590ad0d3, + 0x3d399052, 0x8635252e, 0xc3c7849b, 0x9c6c993e, 0x41074c9e, 0xc8479966, 0xae8b35ff, 0xda87ad48, 0xc8b021f3, + 0x490f7346, 0xc4bcae89, 0xd1686305, 0x26117217, 0x083826a4, 0xe57e4fd1, 0x73e84933, 0x42b82dcd, 0x0894c9a8, + 0xca2d9ee4, 0xeb9cb7c8, 0xfa1da16d, 0x27e3c77f, 0x2068d4cf, 0x1e650f75, 0x7498652f, 0x9769fa7b, 0x20308bb2, + 0x5d961a12, 0xe603a1a1, 0x2d8e710c, 0x9780d849, 0x3a6888c0, 0xb6010132, 0x85bd84d6, 0x968d0e4d, 0x0e593e60, + 0xfc807d3a, 0x2c01d833, 0xf855e9f5, 0x61cb45e8, 0x5ffcc6b2, 0x0aea7973, 0x8ade5438, 0x1fe9c4cf, 0x070cf636, + 0x5d7a1efe, 0x729a2efb, 0x27f6e806, 0x430c0c6b, 0xa863b83c, 0x12476dfe, 0x636eccd5, 0x8d4b4104, 0xad5219f6, + 0xb7d16f24, 0x057bf40f, 0x43a057ec, 0x12f8e792, 0x6b3264d3, 0x2abb4c82, 0x9cac3297, 0xbe472d14, 0x3d5a7c9e, + 0xd05842c0, 0x9b1278db, 0x93391b02, 0x0a5194bd, 0x905a15f8, 0x344248e7, 0xb529cbee, 0xb5366ade, 0xd3a3d1ab, + 0xb088c5a7, 0xb8fff38b, 0xc7fcfe45, 0x2c2a1f9e, 0x6979dc22, 0x792c5d28, 0x7d0979e5, 0xedd2a35d, 0x461b58f9, + 0x4ce86f92, 0xabdc6c30, 0xbc9e527a, 0x44108a4d, 0x1d68396b, 0x6d0e14fd, 0xc887cd35, 0x45aab5b7, 0x7eab5fda, + 0xe4ae4d89, 0x7007d7a8, 0x19bdc872, 0x625950df, 0xe8a289ed, 0xd67407fc, 0x29c7d510, 0xf3868357, 0x74baea9f, + 0xcef19a40, 0x4030e93a, 0xda80eb03, 0x376080ab, 0x7f0b0216, 0xb19ecd4b, 0x55bf7575, 0x64535db7, 0x67ca8492, + 0x2ff55e75, 0x55cc06e5, 0xc6296d59, 0x615ae68e, 0x79a1e183, 0x807a6808, 0xb74176c8, 0xd82058f2, 0x3c183a3c, + 0x194e4403, 0x17147acb, 0xc7c69f91, 0xf5f4d865, 0xe8af32fa, 0xc597a6cb, 0x4a333aa6, 0x12976e75, 0xe83a3f44, + 0xebe6d1c3, 0x60da28c8, 0xd653942e, 0xf2cffb19, 0x3a9d40ef, 0xa6b49f5e, 0x8e3c77eb, 0xf93caf60, 0xe9086e23, + 0xa96c6848, 0x4aa15932, 0xd7db2b69, 0x5ae079f7, 0x55d47a0d, 0x5bc092af, 0x0ac0b7ab, 0xde8938bf, 0x716880f1, + 0xd00d1bd2, 0x02c8cb60, 0xd846550a, 0x9ed7c9eb, 0x87098253, 0x097ada26, 0x87eb7f21, 0x4bcc1d25, 0xe52839aa, + 0x6a63a596, 0x69e96c0d, 0xd9a9061a, 0xcd98e011, 0x92187d8f, 0x7ee55c2e, 0x63e95120, 0xbb41d14c, 0xad1d8ba6, + 0x3da3dce1, 0x511e1dc8, 0xf2127a82, 0x2c835338, 0xd224eaea, 0xe595975d, 0xf170962e, 0x9da0adcc, 0xa152f5b5, + 0x9fd95c28, 0x4a6ec592, 0x3702b408, 0xa3d4b2ec, 0xcd9e3825, 0xd7e2c943, 0x576e12df, 0x29362f0f, 0x98e62e27, + 0xde01851f, 0xd24fc14c, 0xa0a39aef, 0x55aa0e81, 0x9b25007a, 0xfeeeb844, 0x306a832d, 0xd96a65f3, 0x6fd84c5e, + 0xc1499220, 0x4775b8fc, 0xcd885fd4, 0x185f7ec9, 0x44dfd5dd, 0xbf6b418c, 0x3a34682d, 0x398d2b6f, 0x0f2ad33d, + 0x7d15b93f, 0x2e37a931, 0x07f45246, 0xb5e42ac2, 0xe76b862e, 0xfeec57f8, 0xea51c5b2, 0xc9ed33a2, 0x63f0b034, + 0x656fa534, 0xc30087ca, 0xc97fdb5e, 0x4fdb9460, 0xada616c5, 0xf34a0834, 0x4ba2415a, 0x714e2583, 0x4c61a9fb, + 0x03856612, 0x97b55d24, 0x247d58cc, 0xb03a86b0, 0xcfef3420, 0xd03df394, 0xf5dcde69, 0x6b49a8a6, 0xa2f115cb, + 0x83e63425, 0x911d4481, 0xaf42af9a, 0x3dc51417, 0x6fa66b87, 0x969a114f, 0xa336509c, 0x226a5223, 0xf185640d, + 0xbd67b366, 0x85790ac8, 0x43764a9f, 0x2ae18c35, 0x2cc4faea, 0x5c7a1b0e, 0xa95aca5f, 0x9d07a24a, 0x2fff3560, + 0xbe2423b7, 0x2ff33750, 0x7a386076, 0xe9ea1f6c, 0x612f4278, 0xea1bf141, 0x3a25323c, 0xf07ddd31, 0x38edc2bc, + 0xdea5305f, 0x42f7ae30, 0x8fac2240, 0xc721946d, 0x01282a39, 0x9decfb0e, 0x759b178d, 0x2b257dde, 0x9a04fcdd, + 0x425544cf, 0xc7002eed, 0x2ba49535, 0xc6c48c01, 0x5cefd609, 0x338139f5, 0x182dfb20, 0xc4161f55, 0xe67bc11f, + 0xb3f80f09, 0xa5e12715, 0x95f5f99d, 0x55ecce7a, 0x027e3728, 0xe7428c4a, 0x3575cb2d, 0x4ff09701, 0xe013c39b, + 0x869bd25f, 0x6d2dfe31, 0xe9994bbf, 0x753f0aa6, 0x4369700b, 0x83cd25d4, 0x49b5ebc3, 0x859fcb89, 0x93c3006f, + 0xa45a8151, 0xfd2ac73f, 0x8b428f60, 0x8beab69f, 0xcdbb8342, 0x44e1cd32, 0xb6735ffb, 0x96bed338, 0xac0fc89e, + 0x0bb70b85, 0xd95808af, 0x6b7e65ef, 0x549de57c, 0xf52b70fd, 0xc553eca3, 0x60dc8559, 0x9e658a24, 0xbf7e4cfb, + 0xdbeef959, 0xc8a9aa8b, 0xf2f4e683, 0xa40b896a, 0x5bf0dec8, 0xa298d756, 0x8d1db30e, 0xc23896e8, 0x278e79aa, + 0xf86e8d0b, 0x3d35c3be, 0xab886ff5, 0x43962cf2, 0x978ea145, 0x58694f54, 0xb9ad5abf, 0x3800afdd, 0x4bbb0b60, + 0x9e3e0b5a, 0xfc2a0de9, 0x789f8ea8, 0x6951310d, 0xfcea7df6, 0xc71a2c8b, 0x8083a958, 0xfb5fe871, 0x42cb51bc, + 0xb03d376a, 0x0474ae59, 0x0abc5346, 0x7c24a194, 0xfecf6308, 0x413bf24f, 0x9295f294, 0x0d07c263, 0xe5e8391a, + 0xafc72d95, 0x0117579e, 0x8d85578d, 0x6ab95542, 0xee60f855, 0x64cd99e1, 0x2224ecba, 0xb9a3b5c1, 0x487ae1c7, + 0xda252fa4, 0xb0832990, 0x05dcab45, 0x8cd3e4e6, 0xa140918b, 0x52081e92, 0x73dd5d52, 0x37a477a0, 0x9bef09ec, + 0xcf571447, 0xb61bc571, 0x1101ed61, 0xfecca8ec, 0x8d2ff098, 0x3a1c4cca, 0xa8659edf, 0xf84fa87f, 0xab65059d, + 0x17d8e118, 0x119849ce, 0x87d082a7, 0x67f14ff2, 0xda59bef8, 0x4565dfac, 0xa28b9ab1, 0xfaf9596e, 0xcc819dfc, + 0xad948ee9, 0x95fae08d, 0x0b775271, 0x7ddee0c4, 0x2c546d8a, 0x3267a6d8, 0xabc51582, 0x4674a240, 0xcb047cfa, + 0x2dc5c08f, 0x0427a25b, 0xa613a7fe, 0xbb04c9b2, 0x7d5c4bfd, 0xdc127f88, 0xe672e1c5, 0xa9b7ace6, 0xea2b1e57, + 0x885fe566, 0x5b86590a, 0x2455cb9e, 0x4fb71a46, 0xa9214fa6, 0x4574da1b, 0xa9fc44c0, 0xf0bd93d0, 0xfde5d8cb, + 0x603ac8dd, 0xc71bcad7, 0x96c6348f, 0x643915bd, 0x1d506748, 0xcc1de616, 0x0febb2b5, 0x2611f7f5, 0xc01ae66e, + 0x36b2da93, 0x9fc37403, 0xb613595c, 0x08c26bca, 0x28fa4fe5, 0x90a313f6, 0xbbc3a1e2, 0x7a3d01dc, 0x273d9e86, + 0xb37b0307, 0xa404b9bd, 0x3bc238fb, 0x0cfff8d2, 0xcd47d096, 0xd697b05d, 0x41fa2ca3, 0xbd3f7dce, 0xbd76743f, + 0xe0c65d6d, 0xd4c742af, 0x3fa1cf55, 0xb9030fd6, 0x1eba6596, 0x26881b0b, 0x62c10ca6, 0x8681f794, 0x0881a3c3, + 0x71810d43, 0xde508de7, 0xe85853b2, 0x5efd3316, 0x985e30ac, 0x1200bbf8, 0xf0e1b584, 0x269672ba, 0x67ba9eaf, + 0x1072f9eb, 0xf9fcd9f6, 0xd8ca5387, 0x00c12109, 0x677cff99, 0x28adc464, 0x9dd7da13, 0x93dab788, 0x882c6a38, + 0xa3cb55c7, 0x49a303c8, 0xd4abf0b6, 0x32399081, 0x7f8eae33, 0x94ef4595, 0x224cadcb, 0xd44bfebb, 0x9c16ed30, + 0xcda37cdc, 0xe8b82842, 0x662ac0e6, 0x87ea71d3, 0x7086d03e, 0x48306ae5, 0x03770120, 0x09d85d98, 0x275ab660, + 0x395e25b0, 0x26837753, 0x22e1ea6d, 0x3c701d3b, 0x10244e88, 0xd90fab37, 0x359e677e, 0xf84d62b0, 0x33973e1c, + 0x3bad3d83, 0xb61115a4, 0x677f115d, 0x8f166266, 0x506d7e87, 0x3ef9d93e, 0x25dd903e, 0x59c2a2a1, 0xaea5dce1, + 0x5ad0e692, 0x2fa13423, 0x848c8a95, 0x3d32730f, 0x8b7b66d8, 0xd1cc1a14, 0x1c2ba972, 0x1eecb35c, 0xfe3ba2d3, + 0x717c217a, 0x1c9fe73a, 0xca2a1fb8, 0x826f4c74, 0xf5c87d65, 0x8a9cf01f, 0x6c80357d, 0x5603aafc, 0xc85dbd91, + 0x9c68646a, 0x0f7389eb, 0x299626e3, 0x4d9f4e7c, 0x5e2af664, 0x83ce0e5a, 0x223a06fe, 0xa32652e6, 0xfab8e5a1, + 0x638c84b5, 0x6ea3964c, 0x79e5b9ed, 0x2db69e6e, 0xd83b2090, 0xe38e5879, 0x808bfd1c, 0xaac5f878, 0x31d0af0f, + 0xadabc9f6, 0xa33c9770, 0xf4293c79, 0x7036f9da, 0xc1457a52, 0xa4a27cc1, 0x0352f3a3, 0x9a127d2e, 0x32f8a3d3, + 0x29cec43d, 0x70fe97d3, 0xa61ac28b, 0xcae75a61, 0x2ac54fbb, 0x00e5c054, 0xd76cfc82, 0xb14aae0b, 0xad52eb21, + 0x20038f38, 0x61d6ee35, 0x1ee72111, 0x8f47328c, 0x06ecb48c, 0xa0a52f81, 0x1b716a90, 0xbef3f740, 0x20919656, + 0x1f24616d, 0xba7d9add, 0x7606d05c, 0xb2cff3c3, 0x1ea2c0b7, 0x7d4619bb, 0xace10eec, 0xb72fd6ee, 0x86e97f6f, + 0x8dcaf8b3, 0x04d2c6cc, 0xc1f00e59, 0xf2339843, 0xcbd20304, 0x88462041, 0xc2d9edf0, 0x548eab69, 0xcea53539, + 0x4744446e, 0xfe57b8f7, 0x699cb326, 0xaee42b5e, 0x22fe4cb7, 0x29764351, 0x40c1b732, 0x6c1896d9, 0x9e1e8454, + 0x289746d9, 0x2eea0668, 0xf2159337, 0x5745e8d6, 0x38f7a185, 0x25460cf0, 0x796a96d8, 0xe7ddd3c9, 0xdfd170e0, + 0xcfd4bf3e, 0x9c38bf45, 0xe5bd47b2, 0xe7c42a4f, 0x9fd2a0a3, 0x9598177f, 0x2ccc6fcb, 0x575c938f, 0xc5ffc5c9, + 0xa7050a73, 0xb83c053b, 0xd20a3a39, 0x276cfbdd, 0xc2968d47, 0x41a03aff, 0x2f28395f, 0x20e573b3, 0x383a0e05, + 0x748278a8, 0x21475342, 0x9bf59258, 0xf695b17d, 0xc62bd4d8, 0x3ebdee7b, 0xfdad4a6a, 0x1095baf1, 0x84c76762, + 0x65e89c72, 0x4a14cfba, 0x9c0a7ef4, 0xebd0138e, 0xbae966d5, 0xff34a3ee, 0x5b57bd2b, 0x061987ef, 0xad3e4e55, + 0x088a0be8, 0x26820616, 0x2d5e9e4a, 0x027465a9, 0x994e6b2a, 0x9684f8cb, 0xf9c14464, 0x676a9375, 0xe0d2f76b, + 0x0c231cd7, 0x4e1fc96f, 0x11ad0510, 0x88c159b4, 0xe98ca118, 0x5230912b, 0x848a7bb4, 0xdb941289, 0xe7a337d9, + 0xc71a723b, 0xd034a77c, 0x439bc3e1, 0xcc38b0fa, 0xf2c947b6, 0x0509753f, 0x38d532b9, 0xca415f6d, 0xb137692e, + 0x0e73f1f5, 0x47d4afac, 0x0ab6f9f0, 0x16575c46, 0x3922a8a1, 0xe4c62c2a, 0x98ef75e1, 0x98d6b440, 0x8d9c87f6, + 0x85df565b, 0x25d123a0, 0x1066d645, 0x982ab350, 0x6e0bffff, 0x90acea71, 0xf42bd57d, 0xf9ef45ec, 0x5801f2a3, + 0xea917c7d, 0x0297ae5b, 0xfc033376, 0x45940343, 0x76990a11, 0xd2910324, 0x2ab6c568, 0x4e76702e, 0x3d86298c, + 0xc96038df, 0x9935f968, 0xbc3ff878, 0x1d1b153f, 0x015e0547, 0x14d6adab, 0x8b634447, 0x8b910348, 0xfe21f2f3, + 0x836635b6, 0x90f86234, 0xd13ce529, 0x6fc9b581, 0x36c4dc03, 0x828dd5c1, 0xe7b7dcb4, 0x23fd2068, 0x4b2dc949, + 0xb9e68dbc, 0xf4d0067f, 0xb84b6baf, 0x95967121, 0x73ec3adb, 0x928cf881, 0x2bef803c, 0x9d621033, 0x4ffa9606, + 0x3add1d9c, 0x19b6cae1, 0x18cadbf9, 0x0c75e079, 0x11aafcaa, 0x88df80b3, 0xb20ff13e, 0x575b6135, 0x0f60ff30, + 0xaacb8f8f, 0xf698d9cc, 0x76b2fc2c, 0xcd23c977, 0xff8d7315, 0xf9104fec, 0x180c4027, 0x345f045e, 0xe985e4ff, + 0x4685b131, 0xdb2c566d, 0xc86d8607, 0x314127fa, 0x9b77eae2, 0xebfebc8d, 0x91032291, 0x006d12f6, 0x450d16b3, + 0x03b44851, 0x55a91bb3, 0x237fb346, 0xfc6611d2, 0xc55e7d28, 0x004f0f1b, 0x63663af8, 0x47c4531a, 0x7a989409, + 0x6f1a331c, 0xec67f26c, 0x0f057d62, 0xe9b265f1, 0x02bc6da3, 0x30311319, 0xc14f8ddf, 0x16207ca8, 0x1ee3d1f8, + 0x4767af99, 0xefb437bc, 0xf9ed9374, 0x7fa85bd4, 0xbd419a09, 0x4c5af24f, 0x4a1b8e23, 0x5d2b0387, 0x50c9a5f0, + 0xc5fbd79e, 0x8b253e24, 0x1aea6033, 0x63ca8beb, 0xdb9e48ae, 0x83733d9c, 0x5299c804, 0x41c24780, 0x6e5646a8, + 0xd79b5cdf, 0xa9df67f6, 0x11178ec2, 0xa9364e12, 0xab0624b5, 0xf8c58a32, 0x6a0988f5, 0xfa81aa5f, 0x0e9a4ac8, + 0x1d0ae46c, 0x502bb217, 0xbff2ab63, 0x318a7e50, 0xd95962b1, 0x6493c495, 0xafe3a6f3, 0x30e0e656, 0xc1933a77, + 0x434aa8c3, 0xb79f30b6, 0x8cc82154, 0xc2a654eb, 0x9554ae8d, 0xdff98c0c, 0x5690c0a0, 0xc8e7e719, 0x696f6c50, + 0xf9fd4a42, 0xbcdbb334, 0x2604b700, 0x819e2402, 0xf9f37e3e, 0x4f61a729, 0x6d6fc9d7, 0x739d9268, 0x96d04ade, + 0xf311d6eb, 0xe7d32bce, 0xf77e7a19, 0x7c328c63, 0xb34a7dc3, 0xaab576ff, 0xac86bf0d, 0x9bed9301, 0x9f24b234, + 0x725fdbb3, 0xf33ae460, 0x301a17f4, 0xe5424e71, 0xdaad4db6, 0xdb674128, 0x82d6a413, 0xb58dcc88, 0x5321a8c6, + 0xa776aaa7, 0x98493be8, 0x4af5dda1, 0x78bacb43, 0xa459702f, 0xe631240a, 0x3cafdf5a, 0x7d940cdd, 0x19a74d82, + 0x5564e86a, 0x8ac10d7b, 0x701960b9, 0x49e75748, 0x42a072a4, 0x4bfa3edb, 0x18cdc66f, 0x9cc54e3b, 0x23f3afea, + 0x9ed150e0, 0xee480ec4, 0xbfbfe1a2, 0x3e21f250, 0x395c1d0a, 0x7701f73e, 0x26b0d7d7, 0x1dd219e6, 0x7f103717, + 0x16b8c1b3, 0xb6d21c82, 0x6fc5172a, 0xb26b8fb0, 0x9cee9e2d, 0xebb18385, 0x87c848b6, 0x34af263c, 0x7e4f2fde, + 0xdd9bf565, 0x59fd4be2, 0x948428a2, 0xf8b1f792, 0xc1657baa, 0x7b3ed9b7, 0x1f5c9b55, 0x7cbe1046, 0x9bd6f0c0, + 0xb31132c1, 0x34bd9bd5, 0x0c1e4661, 0x70e3743e, 0xbd1b3d3c, 0x0af359b2, 0x49070f5f, 0x2d558841, 0x298d330f, + 0xd9de8388, 0xbb3a9abe, 0x2f135d9c, 0x14177ef6, 0x68ed25be, 0x05e7681e, 0x29941fb7, 0x287055fd, 0xb402d9e3, + 0x8b613185, 0xa244ebba, 0xbd842bda, 0x7820c261, 0x012bb433, 0x3efbb2ff, 0x98d8153c, 0xbd8452ed, 0xc3824720, + 0x6b3d8fb5, 0x48f49f99, 0x4828d48b, 0xb5d50698, 0xfa398879, 0x338dfa13, 0x86ad6c9f, 0x6669fb18, 0x90899492, + 0x0d9cad6a, 0xd509fb41, 0x582e7aaf, 0x3a3745b6, 0x7572f536, 0x61ec29d3, 0x1886a3e3, 0xcf75232e, 0xa5ad5bed, + 0x3a88c1a7, 0x9ee4cc9b, 0x92ad9ff3, 0x89264a8d, 0xaba1b004, 0x23bd66c7, 0x13c73b14, 0x6f4fecb9, 0xb424d035, + 0xe5c0d19b, 0x3c374da7, 0x305ae630, 0xbf1c5e1f, 0xa2cd16a2, 0x8478045e, 0x602b5194, 0x23449198, 0x2d0f6993, + 0x960cd25d, 0x89378e04, 0x07f1dca3, 0xd19be90b, 0x24371c7c, 0x733f5822, 0x822f79ff, 0x27b3aa3b, 0x87fa5b5c, + 0x9243973a, 0x4f0fadea, 0x90a58966, 0x528940bf, 0xfea94a45, 0x72508db1, 0x9fa05774, 0x69782c35, 0x16b3f42a, + 0x94660217, 0x1af1f1dd, 0x590abae4, 0x850da4b5, 0xbab6a194, 0x7306b50c, 0x5c814e54, 0x278df2ca, 0xffeef239, + 0xa2160a38, 0x6d61ed21, 0x8faf4c09, 0xe47ab7d3, 0xf5fa4fdc, 0x66ff1046, 0x7fbad889, 0x2c2ddd0a, 0x2e736566, + 0x84044372, 0x3fc55bbf, 0x43de15b3, 0x6e82b8ab, 0x1b4d9555, 0x4c772566, 0xfd8f2fd9, 0x8ffa45fd, 0xd1b5126d, + 0xb254cccc, 0x09aaaf53, 0xee08d0cd, 0x8b552e9e, 0xef203d36, 0x3e8ad031, 0x31e94c9a, 0x4d6630b5, 0xbef20b58, + 0xa4e92499, 0x36615439, 0x5c876687, 0xf1c7a26f, 0x3195ef1b, 0x8e887123, 0x1151a32a, 0xdd3114e5, 0x59b2d7a3, + 0x4be242cf, 0x3ba00939, 0xeef5d174, 0xe9a12ee7, 0x0fa328d9, 0xcaaeaa65, 0xc7547757, 0xe38a96a8, 0xb90aa30d, + 0x2ebe5a77, 0xfc901ffe, 0xb3e08dc4, 0x671a8e86, 0x55d05ee6, 0x38b5fb94, 0xf08bc1d1, 0x25d22156, 0xae07defd, + 0x4697bda3, 0x1826521e, 0x1b3d9fd7, 0x8f88104e, 0xb2a8fe2b, 0x0b8b5c74, 0x522a48c5, 0x4e549917, 0xc806717d, + 0xc2e77da4, 0x37ccd5a7, 0xeda185a7, 0xcc5bb7b8, 0x9b39d50a, 0xa7364181, 0x2fdc4444, 0xaba693bc, 0xbd5ba2ef, + 0xa309c7d3, 0xac857e71, 0x80ffb38f, 0xa5600152, 0xbb843391, 0xbd289341, 0x878e5a9f, 0x481788f6, 0x215f6e94, + 0xef511244, 0x80f97f30, 0x4aa054ea, 0x41e70892, 0x5f3af1e6, 0x6c22d412, 0xfce219e7, 0x4575d182, 0xf4dccdb4, + 0x6aa296a5, 0xcd4353cf, 0xec68f66c, 0xfe6948a8, 0x609a6e53, 0x2010594f, 0xfefc001d, 0x5f906832, 0x96f9ecc3, + 0x4e95c7f6, 0x8333d232, 0x262b7ee2, 0xf113904b, 0xaac6acf1, 0x58e7ac0e, 0x1c76f21e, 0x0a6cd1a4, 0xe1258f45, + 0x970d7d3c, 0xd70783be, 0x188c75f2, 0x64709dd5, 0x1e1151ca, 0x3fc6fd6a, 0x185cb84f, 0x5748106e, 0x68cfb7e4, + 0x220cb5d1, 0x9fad9659, 0x0b905024, 0x246b4fcb, 0xc75d9f5c, 0x46680d6e, 0x54c1d0a1, 0x1863121a, 0x31ffd243, + 0x1390715d, 0xc7285108, 0x2439443f, 0xc511d692, 0x8aad4359, 0xf620c83a, 0x9fa03913, 0x934a000d, 0x4e4e4919, + 0xbc935655, 0xdadc45d6, 0xdf73e500, 0x2cfb9f15, 0x72a88e4d, 0x89f2bd98, 0x524ddc45, 0xd38ed997, 0x4d642056, + 0xcb9c0062, 0xdaeaea2d, 0x6a4b2bef, 0xf839ad41, 0x016e92dc, 0xcf17181e, 0x8afddc88, 0x93e00261, 0x8e8816c5, + 0x6c68a4ff, 0xccec99a4, 0x249fe354, 0xd3974704, 0xf722713e, 0xa955e73c, 0xfb0e033f, 0x78cfd84f, 0x164f9ef2, + 0xd50ff18a, 0x92d0be1e, 0xce62aa8b, 0xbfa10fc0, 0x353674db, 0xb2c7456a, 0x17c748e7, 0xa52a9ed1, 0xa81d9bc5, + 0xb7446798, 0xaf381266, 0x4539758b, 0xb191a38f, 0xc5c0403c, 0x7c18f6b7, 0x44a9789f, 0x2569ba33, 0x62c31cc2, + 0xc418614c, 0xafda071e, 0x18661307, 0xb78ef9e8, 0xedd7d216, 0x36cde88d, 0xb3b815ba, 0xb1670637, 0x8491669b, + 0x2a4d2cdf, 0x255b421c, 0x39d922de, 0x4a636ab8, 0x0fa400a8, 0x8792ca53, 0x73bbf8cc, 0x34f3edef, 0xcda951b9, + 0xdf757437, 0x0ae5d892, 0x0a4c688c, 0x432f02b9, 0xa1ce1124, 0x77d1099e, 0xdbf3ec4d, 0xc562939a, 0xc7513ca0, + 0x82be1c1e, 0xe06fee5e, 0xb42fc403, 0xe7fbff1d, 0x16acc56a, 0x596d2269, 0x8b4998cf, 0xd2e815e8, 0xa1b47a8a, + 0x74c1a330, 0x43d061f0, 0x197cf999, 0x2cf5b5cb, 0x5521c0f5, 0xeee22a76, 0xd6ea6f0a, 0xc0033b81, 0x81792051, + 0x9329de1b, 0x0ba30212, 0xe99eecd5, 0xa4b40ac5, 0x4f9f0a48, 0x46cc0a59, 0xdec73d47, 0x9c9f4efe, 0xefd4b718, + 0x974cf366, 0xcf39c386, 0xbc556e1f, 0xfc12b704, 0x13807bfa, 0x5507ea20, 0x70edc9dc, 0x0d480094, 0x0f27066e, + 0x57e5c953, 0x3ad732d9, 0xf8848962, 0x90742833, 0xded6c601, 0x93ad9a1c, 0x8ce6c255, 0xa4323698, 0x37a7ca02, + 0xc240839f, 0x2a5529b9, 0xd3250d69, 0x3e12bc89, 0xe7f0b91c, 0xe99569e0, 0x2ae7cef0, 0xca1d3cd9, 0xe69eca8c, + 0xae7b6a68, 0x8837888c, 0x09e3ed75, 0x58fe8f65, 0xd992944b, 0xea4ec767, 0x5b9887c2, 0x63a78bd4, 0x2ce1a477, + 0x285eb0c6, 0xed200563, 0x3f51bf41, 0x53ed4d85, 0xfa8a05a3, 0xea854a98, 0x7ca7ab1f, 0x6122e597, 0x2d1f99f0, + 0x0af3d099, 0xe9b1b731, 0xab40d124, 0xf152ba3b, 0xace4bc0d, 0x66e50b80, 0xd1852e7a, 0x579dd913, 0x394beac3, + 0xbe95eedd, 0x95549b2c, 0xa0d0d507, 0x8378ab77, 0x46a097a1, 0x2fb2a951, 0x59b25cf2, 0x1438e335, 0x56a0d3f8, + 0x8b3afd33, 0x44ada274, 0xfaa7f7a9, 0x32903f35, 0x56e8817e, 0x5d7d15cc, 0x1320078c, 0x6e5490ba, 0xacc09dce, + 0xbbb4008d, 0xdbfe8787, 0x861b44fd, 0xaf4a12ff, 0x33ec2b8e, 0x33ffc3ed, 0x0cbf530a, 0x1a826851, 0x30d043cd, + 0x590b9d63, 0x24d4a819, 0xcfa473e6, 0xe2a26a4c, 0x4ecb6b52, 0x630112d6, 0x6901e62c, 0x4639d546, 0xe2ca36a8, + 0xb99a1fe9, 0xff35e737, 0x18b72ed7, 0x6b4769b1, 0x1d01f2d4, 0x9590b389, 0xd50cade0, 0x9de5930a, 0x8b94b9fe, + 0xefa866ca, 0xdeab3260, 0x117205b5, 0xe4cec844, 0x7a39d371, 0xbb988c11, 0xd60b8b67, 0x5ec2cc5a, 0x10423f35, + 0x465cc3e4, 0x19b0ba21, 0xc21e1421, 0x86fe7300, 0xbc34bd45, 0x5dc6fb19, 0x6e0ae0d9, 0xe2555816, 0x5dd0c8be, + 0xdcff1cd8, 0x20fb18be, 0x210d4610, 0x96d4be98, 0x79adb6d4, 0xfd68748e, 0xf711979b, 0x018e6ded, 0x24db9b15, + 0x19048c9f, 0x97b5aab0, 0x50850377, 0xa2da300f, 0x3210ec7b, 0xa4199365, 0xa79d831c, 0xb58e2a14, 0x0d28a02e, + 0x86549568, 0x4d65254d, 0x01e85aa8, 0x66a72217, 0x2f0647bc, 0xcca53fed, 0x6ac68728, 0x3501f48f, 0x841e61e2, + 0x55fff555, 0xbb71bf8f, 0xbd94bc3f, 0x6956a668, 0x877e99a1, 0x17ea67f2, 0x36eaf992, 0x213a99e0, 0x971db6e7, + 0xdc1fe027, 0x1226783c, 0x1ce2285c, 0x59937410, 0x85276371, 0x02b22de1, 0xff6c0af4, 0xf33a4f46, 0x95df9ee1, + 0x32184453, 0xb690f77b, 0xa3d2df62, 0xcc04d5e0, 0x97807a95, 0x7fce5584, 0x15aff6c1, 0x05520287, 0xd3844627, + 0xfe6013f1, 0x4af1c50d, 0x2e9d0e6b, 0xad0b5673, 0x9a051a40, 0x71054180, 0xf6b22d06, 0xc21235d7, 0x5eba45e6, + 0xf37871a1, 0x1558ad17, 0x6f1c4437, 0xc53298a0, 0x67af4e7f, 0x6ff05efb, 0x4268080b, 0x6d29f884, 0xb761f129, + 0x0a0d5937, 0x56a6fe2b, 0x168af227, 0xd2b6347f, 0x9b94fff5, 0x17af6f21, 0xc9a66b73, 0x0d343805, 0x43bc88a5, + 0x04e6a01f, 0x8b79f578, 0xedcbb6b5, 0xae61d180, 0x54a31365, 0x520d9007, 0xa520a3e2, 0x4ff570bc, 0x66e9f98e, + 0x1d8bca83, 0xab04d235, 0x03bfa9bf, 0xb3b5328f, 0x56b72305, 0x63f2792f, 0x3443c50f, 0xcf721c6d, 0xb091ce50, + 0x0b837ad3, 0x07f3b627, 0xec420593, 0x9267d1e4, 0xbca5721e, 0x30e18f7e, 0x9576d814, 0x3319cbd1, 0xeaff6704, + 0x9631b2b0, 0xae4061ec, 0x294310a6, 0x09325642, 0x6a109eab, 0xd95b3ea3, 0x526cdba5, 0x495d3696, 0x27ddef1b, + 0x48b6aa91, 0xc16a2abe, 0xe77fe86c, 0x1013821e, 0xcc8ee824, 0xb19cc938, 0x1dc08c91, 0x5641f5b2, 0x7d08ae77, + 0xe50944d3, 0x51c5bb19, 0x3aed7f72, 0x6e11e885, 0x832919d5, 0xbe3af340, 0x7eee9cbc, 0x7f09cba1, 0x78ef386d, + 0xdf73fecb, 0xbbad017a, 0x4ca1fd3a, 0x80551057, 0xe1b7ac75, 0xdc8409dc, 0x2dc5c342, 0x969c6a8f, 0xa09ba24b, + 0xfde5019a, 0xc1ab9555, 0x98a8ee07, 0x2a7f5579, 0x7404a98d, 0x8949aa1e, 0x8cddd82e, 0x3f63c9de, 0x301ac48b, + 0x83b7f9bc, 0xef6e02e6, 0xaba43911, 0x85756352, 0x29455071, 0xb7629f72, 0xc5d5ab71, 0xf05a404f, 0x1864ff0c, + 0x32c636a0, 0x21eb0c4f, 0x77ed0078, 0x393c3aa4, 0x0b323c15, 0x86e99166, 0x867cbf24, 0x18a93e40, 0xf88a1ddc, + 0xb6f7ea35, 0xe2996e01, 0xcad9b9bf, 0x27996f27, 0x55af02bd, 0x12c706d4, 0xd480e0b9, 0xa70d9034, 0xaccdb444, + 0xadd6ffae, 0x03c271d4, 0x2054230f, 0x0a674dd4, 0x01272c2c, 0xe7b3b9c6, 0xf8ec7814, 0x50c42e85, 0x2114e972, + 0x0870f561, 0xf25cbc80, 0x4ec7abef, 0x011fbfac, 0xc8fd9f27, 0x796a3621, 0x20d26f56, 0xf237c156, 0xb57d608b, + 0xf1330e50, 0x6ccf1233, 0x30fea2f5, 0x66611d78, 0xb61ef3cb, 0x584ca659, 0x804e2af0, 0xaad3ef36, 0xbd634de5, + 0x522d0464, 0x1e68c4c8, 0x0c589602, 0x9f65f412, 0x89a4552e, 0xb9c59d4b, 0xa038a1d3, 0xbb152927, 0x161a8e82, + 0x697812f2, 0xc498031f, 0x11e667de, 0x4c0c9056, 0x5e36a21e, 0x0681cf96, 0x4e47c816, 0xb11f4ea4, 0x7847f79b, + 0x6bf347c5, 0x65df6a51, 0xccb963e0, 0xf46a7d57, 0xdd6308e6, 0xadc2e4f4, 0xabefba72, 0xfbb6bde3, 0x95498a90, + 0xb3e7d5e7, 0x2f510961, 0x61097e42, 0xc02ed9c4, 0x4180e14e, 0x779a27fc, 0xc5c7ba9d, 0x6fa46319, 0x02290c5f, + 0x889a6cc8, 0xbe522bc6, 0x21c328c9, 0x5fcfeeb5, 0xf737601a, 0x0c031c28, 0xaba6d668, 0x04bb2d59, 0x1bb960cb, + 0x4eee2267, 0xb1c4c238, 0x74235f10, 0xea9c2856, 0x6f03cad9, 0xfbe18580, 0xf2fc97ad, 0x873550f2, 0x1101b02b, + 0x519e8469, 0xb3aea8e4, 0x0f5069ae, 0x4b7c4522, 0x250d5cdd, 0x4f490fc3, 0x5aae6d31, 0x1a4dc4af, 0x51c738b0, + 0xfa11ad17, 0x086f1019, 0x8dd7baca, 0xc0799c42, 0x2e09cfc7, 0xd3de03ac, 0xa64df50f, 0x54556faa, 0x19f59e27, + 0x9f879157, 0x792ff981, 0x0596d2f5, 0xd9b5e3bf, 0x9c290b02, 0x95d6afcc, 0xd9519ea0, 0xb563c8a3, 0x9dbcb931, + 0xbbf86ee6, 0x4413c168, 0x8cf837e4, 0xe7f7fb67, 0x998084e0, 0x8ef46e6b, 0x06c73def, 0x92871660, 0xe954e401, + 0xce95cd12, 0xccaeda37, 0xae90390b, 0xd8131b58, 0x4856e362, 0xde2222ad, 0xf46a3f28, 0xc07924cb, 0x6d745fa3, + 0xca696f5e, 0xe6882510, 0xa0898782, 0xffb53385, 0x935436cc, 0xd248e7f4, 0x796353fe, 0x2268bf18, 0xa0ef859f, + 0x8190d779, 0x4eebe6f2, 0x3a1a1be6, 0xdb6bfa36, 0xeda2f4da, 0x0e94e6e1, 0xd3de561e, 0x1bbdcda4, 0xa908728b, + 0x465a8d58, 0x49513406, 0x9e64a04e, 0x0fed2e95, 0x22431a9b, 0x68a478d7, 0x6d869f11, 0x2b408881, 0xadef49c5, + 0xee5404ae, 0x54766a04, 0x13834640, 0x9daeda6b, 0x2801ba66, 0xb880853a, 0x36445fbe, 0x8fa263cf, 0x415b25b1, + 0x12662117, 0xbde13a03, 0xbe1de352, 0x452e4a6c, 0xbc9f3ced, 0xf4835b83, 0x84919542, 0x2ec0d15d, 0x88398782, + 0xa762d7e0, 0xf2b64708, 0xbe4d541f, 0x771ba46d, 0xd1f6238d, 0xdbdd4e85, 0xc66e9a01, 0xf28fe408, 0xdc0f143f, + 0x6383b970, 0x6d908345, 0x1c69ed8a, 0x3ec5a71d, 0xbc0233ed, 0x719d6deb, 0xaea36dd3, 0x70bc4237, 0xd569adf3, + 0xa83e9656, 0xa6ddd93a, 0xc1149107, 0x4e16b0a7, 0xf7cdfc1e, 0x5504295e, 0x6d96160d, 0x3754b37a, 0x6b903c99, + 0xba8435e4, 0xa8430e0f, 0x59e9873f, 0x85452c74, 0x78f5433c, 0x0dda2dd0, 0x6fb27311, 0x066fd1dc, 0xafc1d6b9, + 0x845a9555, 0xab278346, 0xf165aca4, 0x763bd2e0, 0x35e571a8, 0xe73e0891, 0xc41ed359, 0xfa19e2e4, 0xc0427f4b, + 0xf6e875ef, 0xf244c57f, 0xf6aeef46, 0x781db4d9, 0x9d54ea38, 0xd457c075, 0x70bc4e17, 0xf02d826a, 0x7197e4e9, + 0x6a2ad384, 0xe557eb44, 0x00a7d089, 0x9a1f2b4c, 0x21e54378, 0xc5f25ed1, 0x77743369, 0xec6ee72c, 0x8ab09d2e, + 0xe5926c48, 0x98ef5ba0, 0xdbb4876f, 0x00c4a9cf, 0xd01f3d73, 0xb72e41a8, 0x2865261a, 0x16c0e79d, 0xab314f02, + 0xb92ba4d9, 0x69c2813c, 0xc5bd00bf, 0xaaeaedce, 0x8f3a5db4, 0x0b4fe9b6, 0x0748ef63, 0x1e204480, 0x167e49c5, + 0xf4bce247, 0x824f5e80, 0x44e47511, 0x2e3c145a, 0x6fbf4bd1, 0x0ce22607, 0x83001887, 0xe6c4d6bc, 0xfc4c5a36, + 0x75511d3e, 0x77a86e88, 0x67f80e21, 0x85f2a9f3, 0x705fb9e0, 0xabc76429, 0x871334d6, 0x807e6ba0, 0x768ea361, + 0x9096b382, 0xd93f4b56, 0x978b4863, 0x4d661104, 0x3cf5b5af, 0xfd7efad6, 0x0d0a7bba, 0xf6f95f72, 0xa54ca114, + 0x97b5fd9f, 0xdb0d6af0, 0x91f8bba8, 0xa8fb5341, 0xc6c3c5bb, 0xfbf24478, 0xc490277c, 0x0b7da3b8, 0x9360ee1c, + 0x438c021e, 0x38df8ba0, 0xf87033e9, 0xf115b6a4, 0x292136c5, 0x58424613, 0xd5e96ad8, 0x805e26f7, 0xe63e7371, + 0xd3c90aa0, 0x15fd69df, 0x20b00b54, 0x89dd8ed1, 0x0c076829, 0xdbcfa8f0, 0x1aa05a7a, 0x572ebd1b, 0x4d667120, + 0x1cdc7270, 0xcf5ecccb, 0x38dd04aa, 0x2561d249, 0xa0bca63a, 0xa02cd993, 0x069c2d3a, 0x87b92224, 0x9d4236b1, + 0xc91b5186, 0xb655f2d5, 0x963caf7a, 0x666b8bd7, 0x5a3325e8, 0xd28069d8, 0x5ef93b74, 0xfc3328e4, 0x7c9b7818, + 0x6716ef34, 0x39331ac9, 0xab82b310, 0x1c8a42cb, 0x25cf947a, 0x8712e2f3, 0x81799ef5, 0xf31807e2, 0x477f462f, + 0xc42c1921, 0xcba6b65b, 0xf4af3c2b, 0x2af65aa4, 0xba3bd9bd, 0xf0ec996f, 0xfeab41f9, 0x9b07b687, 0xf6f5af0a, + 0xa03f5a5f, 0x6a412f41, 0x922946b0, 0x0892e2c1, 0xae4f4916, 0xc3dada2d, 0x1650d8c0, 0x9ddb47dc, 0xed34fe75, + 0x772a4aab, 0xa378754e, 0x552ac141, 0x72d56c21, 0x8ef10341, 0x696a7e75, 0xff3c2831, 0xa462fde9, 0x31bfe68b, + 0x65c37633, 0xfea078e1, 0xd3c539cb, 0x31578169, 0xf8e8fe2f, 0x34ce6905, 0xc3a4570c, 0x970e1341, 0x2a511c7a, + 0x04c6531f, 0x2323949d, 0x607c0240, 0x2c98e2db, 0x9918e8a4, 0x72ef7ff4, 0xf21509b8, 0xf9c78047, 0x3958bc57, + 0xb7a6da47, 0xda6e8a0c, 0x24bb6f9f, 0x937e765e, 0xb6b603f5, 0x04709ceb, 0x99c189ca, 0x4e065cbf, 0x77b7dad0, + 0xa7510390, 0x144b5d72, 0x07860de6, 0x25c79eb9, 0xeacfcd77, 0x317523eb, 0xd6a73672, 0xf3421ed0, 0xe0246f4e, + 0x2535b787, 0x6d06afef, 0xc3f903e8, 0xf0ec64d2, 0xa8d1d816, 0x431302ed, 0xa5821a97, 0x3aafaa92, 0xd5763724, + 0x075afb63, 0xe8a91385, 0x044df11a, 0xaa67b153, 0x83199aac, 0xc279c77b, 0xa9346bc2, 0x56bc3844, 0xc4732d4f, + 0x882c1c13, 0x72cb0616, 0xc0e323d4, 0x6021b385, 0xc7056918, 0xf0c251af, 0x4eea1f45, 0x37b7c68a, 0xc7693908, + 0x9c228763, 0xa67bef71, 0x96116a51, 0x254ea1f7, 0x25cb8719, 0xeb87d001, 0x632e3613, 0xa374c838, 0x6a2cc2f4, + 0x6a4cf37b, 0x75a4e6a4, 0xd31eb048, 0xc32b3339, 0x8689955c, 0x86a83b03, 0xcd98795d, 0x739d149e, 0x947c4577, + 0x77a90b0f, 0x34489bf9, 0x323de8cd, 0x05395d25, 0xd381c878, 0x02b69882, 0x1aeae259, 0x0b0a8ca7, 0x5e62d09b, + 0x6b2138f6, 0x22fc8dfc, 0x4c55a690, 0x8bfc8927, 0xfa0753d0, 0xcb38910a, 0x94b32e7c, 0xe3ca39b3, 0xc38d9cb8, + 0x7e3f40cc, 0x679c8205, 0x3b86ed11, 0xf34188eb, 0xb8bfc3ad, 0xc01bca6a, 0xafa80aa7, 0x77615dd2, 0x80752af5, + 0x74a88682, 0x9596f618, 0x8782b3ce, 0x6ac3e333, 0x8fffc8c8, 0x728f2406, 0xb0aeacb2, 0x3591cd38, 0x1430169b, + 0x97c2f20e, 0xfbd2b253, 0x4b5d9177, 0x9f21313b, 0x3a7ceca5, 0xe3213c8d, 0x3b58831f, 0x22fd2d9a, 0xd35d5352, + 0x1561cf8b, 0xc03e9f71, 0xd1ea0f2f, 0x6e0b415b, 0xb4eee602, 0x428648db, 0x4773f1ab, 0x3e73da1f, 0xa1c4e110, + 0xdb4000e8, 0x3ab0e401, 0xaefdbe23, 0xaf3cafac, 0x778cbc44, 0xdb3f2796, 0x17c12cec, 0x13af452c, 0xd256a7a1, + 0x0cd19880, 0xe4fe28ac, 0xc1e5de36, 0x785e38d4, 0x4ac7c632, 0x4ebeb9fe, 0x0b50d7a5, 0xdba00aff, 0xda7ef834, + 0xa9b6a49f, 0x86c841ba, 0x8c9b8885, 0xffa64f51, 0xda8a7cbf, 0xe571fc26, 0x1f169df7, 0x8a7eecbc, 0xa12cf92b, + 0xb1600519, 0x5c4b5ad7, 0x0172cbd2, 0xb59884fb, 0xc44368e7, 0xbcbab190, 0x8726261f, 0xa101790d, 0xa5eab30b, + 0x1ed36a72, 0xd51b8932, 0x392e8493, 0xe658e5c4, 0xe7f50496, 0x4b81039f, 0x3384b6c3, 0x26b6a057, 0x618c693b, + 0x8ea22f5d, 0xc02f2185, 0xeacca0a7, 0x20909ea7, 0x38172693, 0x563e37c6, 0x48286d87, 0x8d6bd5fa, 0x83d2130b, + 0x378318ef, 0x8a35d949, 0x8d2325d9, 0x38751790, 0x2c395cb6, 0x8ada9ebb, 0xbc2e9b55, 0xb4c81cd6, 0x365f2e25, + 0x9a97a1d7, 0xde990fec, 0xcd1d9ee4, 0xf75e580a, 0x15ace9f6, 0xf0ffdcb2, 0x03e1305d, 0xd3f322d9, 0xa3896638, + 0x9a0ee63c, 0x3cdb1f79, 0x41a40f77, 0xfcbc56e8, 0x60589c35, 0xf476fec1, 0x809b2e21, 0x7425abba, 0x07590333, + 0x37572f82, 0xddfa5bb4, 0x523cea9f, 0x029ccc36, 0xbc76fd6c, 0x379b4900, 0xfac222f0, 0x193e0e2b, 0xd51a32bd, + 0xa3b65b3d, 0x496c6020, 0x99b40fdc, 0xc11b6446, 0x61796992, 0xb9aaf1c7, 0xd270bceb, 0xc7a87f8f, 0xfb10c447, + 0xabfc26a9, 0x3215bf78, 0x9ca03aa6, 0x79abf8d0, 0x92ee6085, 0x24b27822, 0x6e04b7af, 0x78609faf, 0xa5ffacb6, + 0x6e76b1b8, 0x017f7990, 0xb6bbc84d, 0x3a4bb0a4, 0x3ac7b134, 0x7cf327ec, 0x5035850b, 0x2c97e457, 0xeb5ab624, + 0x1e4a4816, 0x3d818e73, 0xb69fc56b, 0x5e561864, 0x29605e76, 0x055df1a4, 0xe0ed0f79, 0xc8c7e665, 0x8dcb4ccb, + 0x7086f636, 0x2585d16b, 0x4c08c500, 0x05cad6c3, 0x8425ca35, 0xb7556f24, 0x3318d700, 0x06441e4d, 0x89c097cd, + 0xc1252d82, 0xc72c045a, 0xd383c5ff, 0xf255e806, 0xc0637569, 0x3963f05f, 0x3fa88cff, 0xd30ec63b, 0x3d8038f4, + 0x93d7679e, 0xd99ba3e2, 0x1a2affab, 0x4c205047, 0xa9fca989, 0xabd63fc4, 0x44da1de8, 0xc7a84636, 0xff452d71, + 0x16537eb9, 0xd8f52214, 0x01fa486e, 0x4da2a404, 0x3505692c, 0x1fe7bea8, 0x191474af, 0x03499f61, 0xc0588d60, + 0x61d63324, 0x94b7d84d, 0x40f794fc, 0x69f35e7c, 0x3c98e17f, 0x13b6807b, 0x6dc662f3, 0xf87d4e91, 0xb99bc609, + 0x7cae3d54, 0xc8772c50, 0x6da116d9, 0xd01e3843, 0x06ca89f9, 0xc3b472a6, 0x7d515898, 0x1df55617, 0xbf67a7cc, + 0x051bea14, 0x7743b988, 0xc76eaa7b, 0xe2a9ce02, 0xc7fb0da3, 0xe10e0480, 0xaff1faa2, 0x9f5af88a, 0xef324528, + 0x59692095, 0xc8226dc8, 0xf4387e02, 0xd20a03d2, 0x987831f1, 0x7fd9fac5, 0xe4a86f68, 0xb50d5f2d, 0xddf5b8d4, + 0x948327b0, 0xe6cf560e, 0x6c23e15d, 0x50020fb7, 0x0d23d64d, 0x77971c6d, 0x3dd14d7d, 0x0c4e9a2a, 0xb3a27c29, + 0xf612df4f, 0xd10385b3, 0xa3a551f0, 0xa19c6c7f, 0x6bf973ed, 0x6cc48425, 0x9e72c27d, 0xe255c6ad, 0x57350bd8, + 0x4de44581, 0xc737e42c, 0x1a22b0a5, 0x2bff15f2, 0xad03f046, 0x19b0f19a, 0x509b3ee1, 0x810500bd, 0xe37d9a2f, + 0xbc53d25e, 0x341e16ee, 0x63e6574b, 0x9487da1f, 0x9831ad08, 0xaf2b71b8, 0x7380d9cd, 0xdcf7b1a5, 0x140dae30, + 0xc02e1d21, 0xa1d59171, 0xb6aab81e, 0x3e20fe10, 0x962951ca, 0x8122aced, 0x1851a318, 0x8a2ac47f, 0x92969ab0, + 0x3274436a, 0x0977876a, 0x4dbe5dcd, 0x917e75fe, 0x0ca4601d, 0xcb5b39c1, 0x80ab015c, 0x66d03957, 0x880d7d2c, + 0x89a868ab, 0x05456778, 0xbab66a4a, 0xad67bd8e, 0xa0243ee8, 0xa49a091c, 0x140b5703, 0xd0aaa6f1, 0xbdd98dbc, + 0x909eeea8, 0xa45773c0, 0xc6e16b61, 0x8bf87d45, 0x79a6c207, 0xf40101ca, 0x4ddfd80a, 0xbf9fc883, 0xede6df3d, + 0xb643f392, 0x616092ff, 0x9fbaae5b, 0xb350ee51, 0x1d8eb030, 0x5decba0c, 0x07e92da2, 0x3dd2ad43, 0xb93db46f, + 0xdef024ed, 0x227a1f36, 0x5bd53310, 0xcdb2a156, 0xbd5a5abb, 0xc5a22e55, 0xc0ed394c, 0x5cb24506, 0xe764288f, + 0x632afd68, 0xd8cfc469, 0x05e5522c, 0x1be6fb28, 0x63eb51d8, 0x7bcfccb9, 0xed48624c, 0x9eb8cb14, 0x4374592a, + 0x5bb66287, 0x4c261f32, 0x5a7c4f90, 0x77e0e2f4, 0xe217f3e3, 0x402cef95, 0x09dc9d66, 0x904dae6f, 0xd500d0bf, + 0xb5217362, 0x3893cda8, 0x461db6aa, 0x7c25fe29, 0xf605586f, 0x064fd746, 0x87ef990d, 0x11b29002, 0x146702cc, + 0x41fe725e, 0xbbecb2c5, 0xae5616d2, 0x25cddeab, 0xd245b6a1, 0x562dddf6, 0xb6787843, 0xbdd8881f, 0xebb48444, + 0xe271b81c, 0x592ee65a, 0x8f770ef5, 0x700d7b99, 0x10ce8ac6, 0xfeff4584, 0x114cd0fc, 0xfc31ddc4, 0x42298850, + 0xc2b809b2, 0xca5020c1, 0x859fe2ea, 0xa534bfbf, 0xa1d019e1, 0xb8ba691f, 0xa8a67a7a, 0xe7318652, 0x4760eeda, + 0x760eea35, 0xedff264d, 0x5b099efd, 0x3a4763a2, 0x0899af88, 0x54dd3428, 0x094c9f45, 0xdcdd3784, 0xd4ad98a8, + 0xfee73f34, 0x5bb8a9e1, 0x58199d52, 0xdd9e5ea3, 0x6770b50f, 0xdc0c4831, 0x3cf7f845, 0xd5b6cb9e, 0x10bffcf7, + 0x836550a0, 0x9110b07b, 0x715c17fa, 0x6401f900, 0x6da7a5a9, 0xa3de0c9c, 0x51b3880b, 0xed573fb2, 0x3c454faa, + 0xd5005523, 0x352d531b, 0xed88b26d, 0x68671ffd, 0x5c59781e, 0xcf37e501, 0xd3017d09, 0xad08757f, 0xbd84f858, + 0xb6f12941, 0x3cbbba1f, 0x33d9659e, 0x4876fe83, 0xf5ed252c, 0x6e7f0b56, 0x53e20725, 0x915ee00b, 0x7a57ee43, + 0xc5f3f9e9, 0x723fdca6, 0x0ab6bf83, 0xafc79314, 0x894d5eb8, 0x0c648640, 0x64c77b66, 0x06ed91c2, 0xe97146a1, + 0xd7fe6751, 0xe3dc0cb5, 0xb35280c5, 0x1f39e7ef, 0x1b9cf68e, 0x70a6575d, 0xc726f9cc, 0xc5325363, 0xd469840e, + 0x3166697f, 0x03c10e40, 0xebf974cb, 0xf9cb41fd, 0x05063831, 0xe279d181, 0xbdac6e92, 0x1c863bb3, 0x76d900eb, + 0x9bb848c1, 0x644cdffe, 0x0d205f0b, 0x68ffbb13, 0x93afdab5, 0x61858315, 0xe19f5543, 0xa2096fcd, 0xe5ec6055, + 0x1850fa95, 0x20318b4a, 0x0ee76c4f, 0xc9ce91c4, 0x33b58bae, 0xbc24ffaf, 0xf00e8eda, 0x9c590059, 0x917a9469, + 0x998ecfaa, 0x17ae2680, 0x1bcfe2bb, 0x8b90974f, 0x14b73166, 0x4a941b92, 0xce87243d, 0x74cf4600, 0x2bc87265, + 0xb942d795, 0x66cec955, 0x31298c70, 0x59259196, 0x235f8f76, 0x47d357bb, 0xb9fe0bdb, 0x4728d8ce, 0xecf40911, + 0x16ae984c, 0xeefa9fed, 0x868cc0c3, 0x29d21890, 0x8795e5a1, 0x134f27c7, 0x8a7d825a, 0xbe816d0c, 0x60bd270a, + 0x6e296b08, 0x3bd3d386, 0xc790b558, 0x353f36e4, 0x1f54dbfe, 0x6f0ecd14, 0x0a0defa1, 0x40b2108f, 0x4c725846, + 0x19fa1554, 0xace5206b, 0x12787af6, 0x92badb7b, 0x066d6bd4, 0x3ea3f8e3, 0xe238e09e, 0xdb9a6614, 0x03ae7f95, + 0xe88c7eba, 0x18011c9b, 0x44bdf31e, 0xf8ad4a72, 0x561fa2ee, 0x9d370702, 0x7322731e, 0xc8ac1e76, 0xee889bc2, + 0x05fd204e, 0x362c79aa, 0xf0015d1f, 0x8eefae8b, 0x74612d1b, 0xfdc7c3cf, 0x5da4143c, 0xb2c895e3, 0xa7c95c83, + 0x44c49728, 0x27260a82, 0x1b234cb9, 0x80e0e87d, 0x2115f133, 0x41c40da9, 0xefb99526, 0xb61b6fb1, 0x4fe7345f, + 0xdd3c4728, 0x7ac634a0, 0x1f6a3591, 0x393c6165, 0x25e07cd6, 0xf07024a3, 0x39a362de, 0x55745539, 0x412b17d8, + 0xb3b43594, 0x691b9cc4, 0x34410f66, 0x95099afb, 0x5306e2af, 0xf15d87db, 0x145c4df7, 0xdc9cdff9, 0xb724d537, + 0x64a1f1c0, 0x841e745a, 0x376714de, 0x7af5110b, 0xef150bab, 0xbcae69b6, 0x307d1dca, 0x0b96abdd, 0xa76e0656, + 0x508dd064, 0x21338b60, 0x105a87f1, 0xfe8d3ebe, 0x8038e35f, 0x3c170018, 0xde00a86c, 0x6b1c6c8f, 0xeb0680a1, + 0xd93e6eb9, 0xd0c57a44, 0x94933977, 0x3ab2c185, 0xcfb350da, 0xc4d10918, 0x9c06bf9e, 0x1be56aa3, 0xe2272911, + 0xfe792b41, 0x2709cd02, 0xcfa94150, 0xb837d8b7, 0xfcea78f8, 0xcea040bd, 0x059f2aa6, 0xb3477ce7, 0x1602f0cb, + 0x3abe56d4, 0x1c54f837, 0x9387b282, 0x240bedbd, 0x15c0dc64, 0x27d5ab49, 0x0701cce3, 0xd89560b4, 0x4a67f66f, + 0xaab74cc8, 0x3f6fb7fb, 0x276471db, 0x71607abc, 0x374e4b02, 0xd0e0286b, 0x003b4e6b, 0x9358241b, 0xb37ecc1d, + 0x8149a460, 0xcf83c3be, 0x8587e5ed, 0x66876144, 0x27aa1caf, 0x13c95276, 0x58951d9e, 0xb2c00df4, 0x187120f7, + 0x6f6ad510, 0x5a64137b, 0x31c28361, 0x43ff2439, 0x855ebd9a, 0x384fa958, 0xf1d444c2, 0xe8a68dda, 0xda2330c0, + 0x210c048e, 0x57407cbe, 0x52cb1ab9, 0xb6f21bd4, 0xaa758bff, 0xa1ab9d05, 0x38813d29, 0x2352e197, 0xf8b5a92e, + 0x144bc84f, 0xa6a1926c, 0x175e7df1, 0xa9eee796, 0x108aa88c, 0x027a9d57, 0xa6ac0d09, 0xd1493302, 0x1cd6550a, + 0xf2acd728, 0x6aa9c541, 0x0bbfd218, 0x00ed6f29, 0x613cd4c5, 0xf8b6b5a7, 0x6e8ee440, 0xb02a3923, 0xb66fb620, + 0x6f117f23, 0xc239e742, 0xd29d7306, 0x31486a27, 0x25434663, 0x7d371a81, 0x0ae06820, 0x18de00c7, 0x3ae81b55, + 0x39e6b5a9, 0x0df2fd0c, 0xb25d63fa, 0x94c10cb3, 0xe9a3596c, 0xc8130752, 0x89d6179b, 0x417e4f4c, 0x151cc26c, + 0x90547623, 0x0490ab42, 0x84de3a3c, 0x086742d8, 0x12d4b8d5, 0x69f82e0d, 0x8971b74f, 0xb8bd2f35, 0x0cb36338, + 0xf462dee7, 0x4f26b70b, 0x5a6041b2, 0x342b5b7b, 0x82648f3a, 0x6dc2b2bf, 0xb459db32, 0x13122d2d, 0x80f6fb4d, + 0x201db9d6, 0x24fe1455, 0xff018cf9, 0x989355ad, 0x6177e1b7, 0xa672e5b9, 0x4765fec8, 0x0eb6c485, 0x8b95fa4a, + 0xedfc01a9, 0x31d9805c, 0xabb96fa9, 0x470bd27b, 0x15729b75, 0xc92dd53e, 0xaa6f245d, 0x4d619f2e, 0x3ab1ab71, + 0x926b3abb, 0x85e45083, 0xb3b93f1d, 0x55b6ecf2, 0x4c041e6d, 0x26048edc, 0x33595f94, 0x2e9dd2ec, 0x5db9763f, + 0xaf810383, 0x71eb7909, 0x5cb3a6e3, 0x638e2b49, 0x473c887d, 0x848de9af, 0x00cfa61b, 0x07a921ff, 0xbe0cd78f, + 0xfa8dff4d, 0x88edf662, 0x88d3fe3b, 0x73c43e79, 0xdbe32002, 0x970384da, 0x59dc9fd6, 0x36007b89, 0x8467969c, + 0x8a59131d, 0x38deff1e, 0xe122f58d, 0x2f9239ed, 0x2c29fb3e, 0x78795319, 0xf513fd5f, 0xfca7d840, 0x46dbf37f, + 0xb80cd623, 0x77eae2ba, 0xf91b8ecb, 0x4249a659, 0xed1cace6, 0xe973faa5, 0x01f51e5a, 0xb120e8f9, 0x60582f75, + 0x695e0037, 0x86d0c0db, 0x0068983c, 0x7d629526, 0x59c7a1a6, 0xbae77bb6, 0xffa9e73c, 0x31d78cc5, 0x5e6675fd, + 0x5d83ed00, 0x59e588c2, 0xcb581f60, 0xff44b0c1, 0xac2348b3, 0x08871755, 0xeb40126f, 0x60fceb90, 0xbd7ca0af, + 0x3e09a6af, 0xf365a55e, 0x203d5cb7, 0x1e3b81ba, 0x430d3bf6, 0x4f5408b5, 0x96e61b82, 0x4bea8a3a, 0x66f58972, + 0xe91a1443, 0x6a78e4c4, 0xda765559, 0x9276f078, 0xa310cd05, 0xaee9a527, 0x61b91ce5, 0x3ee103e7, 0x0e3e8107, + 0x454e5e22, 0xb01898cf, 0xd8e42a61, 0xec6fa30e, 0x182ffe99, 0xb64157d6, 0x07b7367b, 0x026463e4, 0xc49cc66e, + 0xdf6fc9e7, 0x828996c4, 0x91d9d1d4, 0x35120451, 0x34e21d64, 0x5fb93f75, 0x0bdf57a9, 0x2a856a9f, 0xddcf0d03, + 0x47e05bd0, 0x6e430ca0, 0x6ca9d51b, 0x861fa9cb, 0xa05e6ec2, 0x22edee49, 0xa4b65ec1, 0x1ba083df, 0x763472ca, + 0x926d6139, 0xbac72606, 0x276bc3e1, 0x9ec632e3, 0x73226b46, 0x7dc96b4f, 0x7b2e5c80, 0x33aabd2a, 0x3dfd8715, + 0x57a8dd5f, 0x829687dc, 0x45878d9c, 0xc7e65362, 0x4555b760, 0xc5293006, 0x517679e1, 0x6171f4b5, 0xe77b9b6e, + 0x9e616d21, 0x6cc454cc, 0x307af977, 0xd5483504, 0xd14656cd, 0xa5438f22, 0xab19e141, 0x0f4e9036, 0x4f4850c6, + 0x87e10d2e, 0x105739dd, 0x0a163d7e, 0xb39cf146, 0x3ca3754e, 0xc02ed1ca, 0x36483cf6, 0xa8bc4d92, 0xf0b5c02b, + 0xffa6b2e8, 0x17ac38ee, 0x814c86e8, 0xc1427e1a, 0xc7684ecd, 0x6a73da3b, 0x381572e1, 0x1f6ec7b1, 0x6c88c25d, + 0x1db5f51f, 0x174aea7d, 0x2af30370, 0xb2177525, 0x83145a9c, 0x96defb04, 0x0af887f7, 0x83750b16, 0x7225fe1d, + 0xafa2e98e, 0x1c17a6c0, 0x0d59ead3, 0xcc7fdc2d, 0xda67b6f7, 0xbcee9cf4, 0x3f1584f6, 0xfc9ca3db, 0xc091ccdd, + 0x1ff96c5c, 0x942dca8c, 0x3cdd33e3, 0xe146b4eb, 0x3f51af64, 0xe96a16f3, 0xaf0757fe, 0x59f5807b, 0x9e85a46c, + 0x8f7e6fe7, 0xe1734edd, 0xba0f2631, 0x064c2bc0, 0x8d8d5596, 0x99ccb5e5, 0xa65ca7bd, 0x4a887d0d, 0x317c7c21, + 0x8420a8e1, 0xe30425c5, 0x0ca6fb73, 0xf46aaa8a, 0x1390a5c1, 0xa5612147, 0xcc146371, 0x3be64d13, 0x9598891a, + 0x3a2d7491, 0xa43896be, 0x7e2af83a, 0x48b6a7bb, 0x975d4c0c, 0x7da534a4, 0xe6353558, 0x2234bb95, 0x6b194cd6, + 0xc024ca99, 0x3ec6cbc0, 0x0b0d0e5a, 0xb1b7629c, 0x2898f56d, 0xc30e4540, 0x9150ee48, 0xd119faea, 0x00340381, + 0xf541a00a, 0x5df7c98f, 0xd41c1728, 0xeef1e31f, 0x2c94d7a3, 0x9f67ae46, 0x78b212b6, 0x69a649ac, 0x4a2db2e1, + 0x24465b1a, 0x60a7cd5f, 0x86d0893f, 0x842e3b16, 0xf14d0a09, 0xb0e415d6, 0x633325ca, 0x74ebf912, 0xe3bde501, + 0x1c4e80eb, 0x3ce5fca1, 0xd715eda0, 0x819d00a1, 0x627d8fef, 0xbd55a318, 0x7f9b2095, 0xe7ff4f18, 0x09d90f05, + 0x3487b68f, 0x5e8f57ba, 0x0f0be592, 0xe74d2286, 0xa11f77c3, 0x63cd1610, 0xf822562d, 0xfe5915e0, 0x2c7b1133, + 0xdc546099, 0x43158d63, 0x8c493e6f, 0x0df4ba1d, 0x8b78e957, 0xb579f66c, 0x9759a9a3, 0x7edab8ce, 0x22f8abe0, + 0x28f27361, 0xe49592a3, 0x485e9ee2, 0x044079a5, 0xcdee7823, 0xb2e2283d, 0xcb288296, 0x5112cf24, 0x0e0acec8, + 0xcbd98b47, 0x8ea76ff6, 0x03952a25, 0xfea0eded, 0x6a439f71, 0x59b841cd, 0x66075545, 0x3eec3760, 0x78ea1b3a, + 0xd391bb9a, 0x50e2359e, 0x462db9f8, 0x65b622bd, 0xdc107934, 0x8d56870b, 0x6d29de7f, 0x5e8e0b60, 0xafea31a9, + 0xdc09451e, 0x4a6a367c, 0x77dff9b4, 0xedd25981, 0x05d2d04d, 0x44ff8d78, 0x547695a6, 0x08e60719, 0x52aa7ee1, + 0xdadfda34, 0xffc14174, 0x11f02ca4, 0xffc2f027, 0xaf5328d5, 0xbc8e2dd5, 0xdd9ff96a, 0xc57ca7be, 0xbbe8eb2e, + 0x151c65ec, 0x3de50166, 0xb19be115, 0x65bd0aa1, 0x9824156d, 0x08c868ff, 0xd746a31f, 0x61f5e1c3, 0xb0fd885b, + 0x63d1e938, 0x6b8293b2, 0xe6d82468, 0x9f231754, 0x7dd599dc, 0x9e66a0f2, 0xde2af09c, 0x61338608, 0x1212b709, + 0x363df247, 0x3d66d7d3, 0x52ddb1f3, 0x9fa7b50b, 0x7567801d, 0x5d716fc8, 0x40d8db51, 0xd2d1aee1, 0x29f97db1, + 0x2f76fe0d, 0x5b838947, 0x13734da8, 0xe30f9364, 0xc1bef4b6, 0xe70f30ed, 0x387dfd70, 0xe8dbee27, 0xb81547ab, + 0x5541df48, 0xb9ac4cb8, 0x23bfde34, 0x4c2fe6b9, 0xe51b3182, 0x9729a3a7, 0xca20a65c, 0x3bed82ea, 0x995656a7, + 0x1d3a25bc, 0x9aff3c6f, 0x6f297b6f, 0x34cea221, 0xf8f39bc8, 0xb282acba, 0x3d382952, 0x4bb08b11, 0x9d189edd, + 0xd73690bf, 0xaf3a88e2, 0x98230f6c, 0xf09897a6, 0x9282c179, 0xe2bfcda5, 0x5f333b0c, 0x3a23e8ca, 0x26f9eb1b, + 0xa1ce4a4e, 0x62825009, 0x4ff81163, 0xe4fdb007, 0xc040b136, 0x01f042b4, 0x18591ddc, 0x20b8486f, 0x1ef7af9c, + 0xce4e0d3d, 0x86e2072d, 0xa55fd666, 0xe32909f6, 0xea5c9f97, 0xe258d734, 0xd68af1d3, 0xc125eb09, 0x2d6b3b12, + 0xc4c3b3f8, 0x8f3c49da, 0x2268397c, 0x1a6ecee8, 0x6353319a, 0xe44aa56d, 0x82a0af64, 0xa3e88d1d, 0x2c782eeb, + 0x63d52a9c, 0xa26edcbe, 0xc309ed0a, 0x2a5b5f78, 0x1cf97b75, 0xadf04333, 0x0dadc62b, 0x7ece1bec, 0xe2a52f67, + 0x0bbf71aa, 0xe5651655, 0xce9eb93d, 0x675a21f7, 0xb0cfa778, 0x0b53bff4, 0x3528e837, 0xad71842d, 0xb720c29c, + 0xecb7f197, 0x8b692778, 0xf90ae1a3, 0x1ad1180f, 0xf9539b2d, 0x9abbb4d6, 0x7621895c, 0x91e8f1d0, 0xce65b761, + 0x05554157, 0xae599d65, 0x515f5138, 0x5292ed0a, 0x1dc82cfc, 0x62a03f52, 0xea114a36, 0x6a27d241, 0xaeb9b745, + 0xe5f7d063, 0xf39c7a2b, 0x2464321a, 0x47a84c9f, 0x33762511, 0x05094320, 0xe21c0396, 0x265edcdb, 0xd5a95c7b, + 0xaed530da, 0xb190cc6a, 0xcfdac421, 0xcb562276, 0x67810fbb, 0xde9f41f3, 0x0b4254a1, 0x881ca440, 0xe2e2b37f, + 0x2849b264, 0x81bdec0b, 0x0725f9a1, 0x690dc4c7, 0x9809000b, 0xe9a8705f, 0x72f9eb71, 0x41c0a941, 0xc930d114, + 0xa6093ca3, 0xbaddc8ff, 0x4d3f47c9, 0xaa86d3a3, 0x9503d08b, 0x659ffbec, 0x121f9a80, 0x1fb40a2b, 0x4d5c36b8, + 0xceb3dce3, 0x2a25138e, 0xf7dd86b9, 0x4d2301f2, 0x86797b6b, 0x4e8a6ded, 0x6323df79, 0x4255e146, 0x7f170655, + 0xe9a75fd3, 0xd1dd72de, 0x06e0fe02, 0x9fe89d10, 0x5f7ec669, 0x4a84c30b, 0x4266bd64, 0x1a710934, 0x1cb856f7, + 0x4521d651, 0x647aeb21, 0xd7f99583, 0x1517bfb6, 0x3923e6f2, 0x32c29632, 0x33291d95, 0x5f4b66e6, 0xf0fa02bc, + 0x1f240baf, 0xbcd9ef94, 0xe9448f5a, 0x69c2a844, 0xe6909c09, 0x13589493, 0x9e2f7cd0, 0x1732db93, 0xf06932ad, + 0x04a4f9c7, 0x03332883, 0xb9fb6e2e, 0x3669ef64, 0x5cf3fbf9, 0x6fef0cde, 0x79bd5024, 0xfd0f8807, 0xe1bbb82f, + 0x4315e5a9, 0x62bff578, 0x4801019f, 0xc02236ee, 0x84f29bca, 0x061f326f, 0x6eac2abe, 0xcbfe72c0, 0xdabba263, + 0x5df1fbcd, 0xf47dd2cd, 0xdc6b66cd, 0x1c16a9d6, 0x150769df, 0x47153393, 0x9db3ab5e, 0x21ee65fb, 0x6fdae145, + 0xcd34fdbb, 0xcde85981, 0x2a2a541d, 0xf7d1ed82, 0x76c4f83c, 0x8a843e71, 0x435c8b91, 0x187eb7f4, 0x2db7a162, + 0x59da8201, 0xf06cc33f, 0x047a0bea, 0xfcf67843, 0x638659fb, 0x2d28aa8c, 0x373fc160, 0x1705d0e9, 0x81c4d4c4, + 0xe5189a44, 0xcb138bef, 0xa9f34d9e, 0x8daa7dfc, 0xc577ab0b, 0xb278904b, 0xaa4935e3, 0xe00a8837, 0x7ac3165d, + 0x58caab83, 0x799c6090, 0x1115863b, 0x31e5ceda, 0xf9e99598, 0xf6d2d93d, 0xf021d880, 0x7bcb1856, 0x5d07b76c, + 0x2de09dc5, 0x4e268bd2, 0x774a51b2, 0x4caab945, 0x369c820f, 0x12be924a, 0xc2bcce99, 0x714b4ea4, 0x640b0b9c, + 0x2bda59fd, 0x35473f7f, 0xd9b939a5, 0x812128cc, 0x618e502b, 0xcbb75d10, 0xef023407, 0x10c798b4, 0x805365d6, + 0x58e8db14, 0x6985a88a, 0x2a6fcf65, 0x8527b0f0, 0x8367d544, 0x7b144af6, 0x1aa0153e, 0xc41323df, 0xd0e48854, + 0xadfe8a9d, 0x1139ecdb, 0x6b601a01, 0x512093b3, 0x8c73e0c0, 0xa0c00a4f, 0xfc552235, 0x57bd3a26, 0x26402ae0, + 0x3a51fd64, 0xa54a973b, 0xbfee0e0b, 0xdf2896e7, 0x4eb1b2c6, 0x066d8ebd, 0xeb4ee46c, 0xce17f904, 0x3e0c0a16, + 0x260d1f26, 0x6ff5b65b, 0x5e17be8c, 0x308b83d8, 0x14897b42, 0x8ab20186, 0xa6d7821d, 0xca5908f5, 0x0de4c9e2, + 0x15b4d438, 0xe30c5f16, 0x9885d72b, 0xe9548809, 0x6fd2b70b, 0x8e78e566, 0x0c87484f, 0x8bc1babb, 0x781610ee, + 0x43815c58, 0xd3db5986, 0x0c1879de, 0x53d04e93, 0xf016dd8e, 0x7088211d, 0xfb2abc2e, 0xb64e587f, 0x09e910c7, + 0x91ccd14a, 0x802deb99, 0xbf854bc6, 0xdd317f3f, 0xd4f0eda8, 0x0fe42b35, 0xf184af39, 0x46cce4b8, 0x9500ada1, + 0x29af3ba2, 0x8d90b1ae, 0x67f37428, 0x9b17929d, 0x54e38dee, 0xbf110014, 0x17abd4aa, 0x1457dde6, 0x19c729f1, + 0x15d07751, 0x04e1bbb4, 0xcbc4814b, 0x4f677551, 0x09e66034, 0xe05ab1aa, 0x80f65c20, 0x00ce6dd0, 0xb0560fba, + 0x87fd5077, 0xa003c364, 0xd672c641, 0x2e104f7a, 0xce816f9e, 0xeae4e267, 0x174e7206, 0x1c0b0330, 0x6aef032b, + 0x7d0e2848, 0xd26c4b27, 0x5bc21b00, 0xdf8aa9c2, 0x8450ca89, 0xe906b1cd, 0xe2f8f72d, 0xa43caf38, 0x810ac95f, + 0xf9bc6e4d, 0xc8724da4, 0x6aea5116, 0x171b2958, 0x603c4efc, 0x32ec0fc5, 0x160aef5a, 0x1b22dfbc, 0xf85c4f4d, + 0x1f3c96ea, 0x9e90f458, 0x072b07d8, 0x4b599cdb, 0xaa2bc336, 0xf7755506, 0x686f07ff, 0x41887c4b, 0xd101fee1, + 0xc756bf83, 0x59b97f3a, 0x67bbc3d0, 0xc3364049, 0x95a028be, 0x1ee3c984, 0xf13628bd, 0xa504eff4, 0x16ffcc62, + 0x8fe9850e, 0x58b20d75, 0x2cf49c3d, 0x75c53541, 0xe59facb1, 0xbb68d8e6, 0x88e2ab67, 0xb679bc0f, 0xa9cd71a2, + 0x6f231057, 0xb23eb652, 0xb4be49cd, 0x51e20309, 0x4de2e769, 0xe6bf50de, 0x4f40dadf, 0x70c21fd3, 0xa325fd37, + 0x91e7b09c, 0x946df1c1, 0x4892214d, 0x503b1948, 0xc037c92f, 0xe762afcc, 0x00e4b193, 0xe8ec940b, 0xf9019bc9, + 0x2f60aa76, 0xaab1559b, 0xcc2439b7, 0x93ce65f4, 0xf560055b, 0x49e67893, 0xe2ec44b4, 0x27501acf, 0x28b8e4ee, + 0xfb118bae, 0x2926e958, 0x1d8ffc4c, 0x2d89a3ac, 0x2a1a6235, 0x97bc7803, 0xefc9a5f8, 0x91b73aff, 0x1ba24d69, + 0x35df5d4b, 0x193adf09, 0x583e4036, 0x92c0219e, 0xab8138c2, 0x57cc7ce1, 0x189f926b, 0x87192706, 0xbc8734e8, + 0xabd32c9a, 0xf0da7748, 0x7757419b, 0xe0e0f722, 0xb190c0f9, 0x9fe3a555, 0x357486b7, 0xfd519e0b, 0xb3a10f6e, + 0x678a4297, 0x754c904c, 0xfd9a6dd9, 0xf113f6f1, 0x9ec3fe38, 0xb0b055a8, 0x8df0ef93, 0xb2dff12e, 0x1aa4b285, + 0xb0f18c02, 0xe9781e3d, 0x8b7b677d, 0xde62ca2c, 0xab1e5b6a, 0xa8c57d41, 0x33900ac9, 0x33984701, 0xc9a6fdc3, + 0x668d236d, 0x56162095, 0xbb825e19, 0x2810e54b, 0x65ccbeb5, 0x55880a8e, 0x5529edf4, 0x067530dc, 0x9240d73c, + 0xa7855f72, 0x28f773f4, 0xf1671a40, 0xbc2b0bb1, 0x8312604a, 0xab1be678, 0x634fee86, 0x907b4db8, 0xcea17324, + 0x15f0f8f6, 0x5d96d19b, 0x5fcdd1f6, 0xdf3b71ca, 0x5a7334bc, 0xd62a3b7f, 0x74b6eeeb, 0x3c2ebaf9, 0x989da197, + 0x3f756ad7, 0x701234a1, 0x69911249, 0x24ff3691, 0x38cb4c47, 0xfcafc2d9, 0xebd9354e, 0xa0e6f5d5, 0x8a4ce77b, + 0x7bf2aa09, 0xea9093a5, 0x8e19c8c5, 0xe48cba0e, 0x4864fa60, 0x04eb041a, 0xedff1de7, 0x20e56fbc, 0x1dfa9949, + 0xc91275f4, 0x0fc44e98, 0x9c4c5cbe, 0x842ac620, 0x746cc46c, 0xcf5204e3, 0xe937d545, 0xc72f217e, 0x94ddc74d, + 0x37370b7c, 0x812e2e9d, 0x2d2cd7e2, 0xd6f2a7c6, 0xd30915ad, 0x1a4e5719, 0xd67368cd, 0x95072ef9, 0x6b999a78, + 0x7fd199c1, 0x97cfdd9f, 0x05fe8204, 0x514076d0, 0xec839321, 0x8382bb96, 0xca049d14, 0x8cf88c9b, 0xb3b9be8c, + 0xcb896fcb, 0x27b5b3d7, 0x2bf73f7b, 0xe5206890, 0xcea282c8, 0xaf9ac646, 0x1c790aea, 0x4f2de971, 0x36c3e035, + 0x51194f0d, 0x1638023d, 0x5f94ef6b, 0xedb4ab28, 0x4027469e, 0x01e40344, 0x33a008d5, 0xfb5b13c4, 0x61f7045d, + 0x7c59d595, 0x5a4e0fd1, 0xeddb4c42, 0x11202fc7, 0x1affa3dd, 0x83f9b1f7, 0xe0feaa55, 0xe394ce1b, 0x1cd2ce38, + 0x407f5962, 0xa4fe8a21, 0x25832e6f, 0xa04f5da9, 0x5c48b494, 0x42994473, 0xca325163, 0x443c3d60, 0xbcf8c32b, + 0xa8ee3007, 0x04d88e99, 0x3e305a3c, 0xca416cf0, 0x61ce6511, 0x60f51f04, 0x8a38b544, 0xb5e50804, 0xd3afeec6, + 0xa540005c, 0xeedbf5c9, 0x877245dd, 0xb78e7ed0, 0xb457a7a8, 0x3383395c, 0xe785896e, 0x6411ef09, 0x42117c65, + 0x75dc357d, 0xcb08179b, 0xbffc6d5f, 0xcadb579f, 0x05267ba3, 0xbb39ff9a, 0x6ea7d41f, 0x4ee2594b, 0x057dd976, + 0x2ef1fa2f, 0xa808c4e5, 0xf8320611, 0x5f58b554, 0x8150a0b5, 0x261530c9, 0xda647456, 0x07689078, 0xd3b8e588, + 0x827f5f41, 0xeb748f8f, 0x81a48f02, 0x438f1459, 0x38b1e0a5, 0xd3a893c3, 0xbc697995, 0x9e3fdbfb, 0xacce195a, + 0x26eeb878, 0xcd55a4bc, 0x7cd2dfde, 0x095a4b58, 0x4d157cb0, 0xac521615, 0x77dedaa2, 0xc7dea3e5, 0xfd73c25e, + 0x84e95958, 0x5967a963, 0x6183697e, 0x7c3b6297, 0x4ed41a15, 0x2f386304, 0xcba5ca77, 0xeaafbe32, 0x779ada29, + 0x4876a2bf, 0xb2ea6554, 0xbecf2761, 0x7564817b, 0x60093264, 0xdcca3b13, 0xd2efe6e6, 0x089a7c37, 0xeabda79a, + 0x671db26d, 0x14326db0, 0x336d12f3, 0x55dbce2a, 0x09bafcfd, 0xd1a62334, 0xe36960b9, 0x89fb2100, 0x2a1bf56c, + 0x70cab00d, 0xd5c65eeb, 0x89f5e615, 0x663962bc, 0x44625066, 0xa4a5d310, 0xc0fb2e7a, 0x02288d8b, 0xd2eb571a, + 0x21c50b19, 0xe400f5c4, 0x235425d1, 0x0daf7333, 0xdac49424, 0xaa940104, 0x05c0468d, 0xbb4c90f4, 0x907c5c3b, + 0xb6c010f2, 0x0a58f0ad, 0xc98f4e3b, 0xab0d8332, 0x8b4d16b9, 0x0c392b5c, 0x9a7ecf72, 0x59ea64ff, 0x5fb99699, + 0x6c4a4aee, 0x451c0907, 0xc55c05c1, 0xb59d3056, 0xa7a0c0c6, 0x0801513c, 0x83e61650, 0x931b9a0c, 0x56605af8, + 0x7cc22da8, 0xb73bbacd, 0x242f19c5, 0x482bbb93, 0x9f3ef5a6, 0x62f69b91, 0xa9b79d06, 0x670a51d5, 0xd721adf6, + 0x0b436c17, 0x7c228c6e, 0xec385952, 0x5144eb17, 0x48707b95, 0x2e7b6331, 0xce48a7da, 0x47e6cf9e, 0x063064a7, + 0x69ddd7a6, 0xc561afe8, 0x6a451b9f, 0x5657b6f7, 0x4153eae6, 0x3425807a, 0xde1b5116, 0x7583ca58, 0x1511788d, + 0xcd28c817, 0xf428d095, 0xc6da6fc2, 0xfa57219c, 0xbc577a2a, 0xd0370eda, 0x048f72da, 0xe5fdd2c7, 0x038dde83, + 0xe07d8aa9, 0xef00e822, 0x5f53ffe9, 0x271c9e66, 0x472a791a, 0xdca72d36, 0x032c4e1c, 0xd3c4f320, 0x55ff7d02, + 0x1810b3bc, 0xe7959bc5, 0x45cfab27, 0xc16efa0d, 0xee807e26, 0xb91563c6, 0xcb99420f, 0xf2b2e9b4, 0x75d3bee2, + 0x2b3d4d0d, 0x9e0438c4, 0x31ac3d87, 0x5ae548d4, 0x8b6a563e, 0x8eea76c5, 0x7a45ff21, 0x7c7aaa3e, 0x509c8734, + 0x3e884767, 0xd60af4b4, 0x9b735dfd, 0x0428c08e, 0xf91e02be, 0x5487021b, 0x881ea121, 0xa3f83b66, 0xcde90fcb, + 0xa28726b2, 0xf4db31a8, 0x063e0e3e, 0x6b752e4c, 0x209bde3f, 0xece1533f, 0x099378ae, 0x1267b9f0, 0xee55acc8, + 0x00b5bb66, 0xd1f4bee6, 0xa90404b0, 0xcdd1354e, 0x7f73654d, 0xc3fbe002, 0x41e0cb04, 0x3922269a, 0x8e4c8842, + 0x6fb0b63c, 0xd1959f6c, 0xb0329514, 0x6b1e4592, 0x507911c9, 0x29b135e3, 0xcd9c090d, 0xefc36a96, 0x90aaa52f, + 0x3a488614, 0xf5c8f79f, 0x0d0fab13, 0x82bf1fe5, 0x012b9500, 0xb11bbec4, 0xd68ecf9d, 0xb3a4abbb, 0x1285447d, + 0x22ccccaa, 0xfc0e7be5, 0xf325cf75, 0x861596b8, 0x02eee318, 0xb3c90301, 0xbdd36f81, 0x58284cae, 0xd98ebf39, + 0x7ac4dde8, 0xbdc552f8, 0x1e10cc98, 0x4f179404, 0x72f4b3f2, 0xc62aea32, 0xecc2ee37, 0x07eba268, 0x412ecdb7, + 0x4c50023b, 0x8e628d56, 0xa3e7bef1, 0xe42f0c2e, 0xfcfac87e, 0x9f1360d8, 0x3b669cad, 0x28b9c776, 0x7d2a621e, + 0x3b40804a, 0xd8aee070, 0x48375ec8, 0xb9245580, 0xb109a7a9, 0xfc65c640, 0x7ff26963, 0x3f1fdf14, 0x4904f2b0, + 0x7ea2069e, 0x7c9fe24f, 0x8d16bb5c, 0xbbebd7b9, 0x65956523, 0x311f343d, 0x624e7805, 0x9b991c8d, 0x84c84795, + 0x3a8d7172, 0x22911a74, 0xd32ceebe, 0xf3ca8b85, 0x14ef42c8, 0xcf378c9b, 0x39342e3d, 0x5c157b32, 0xb210b0f5, + 0x53965361, 0xcfc9f947, 0xf11d6fa9, 0xd98eff4f, 0xf5337536, 0x629bef19, 0x14f375a9, 0x27909641, 0xfe1b7af9, + 0x69bc5361, 0x70bba5bc, 0x387a7b32, 0x15917da9, 0x04e804f9, 0xcaa12bda, 0x3d314f7a, 0x700053ca, 0xaed21357, + 0x96d68c0e, 0x1c0b2f33, 0xd6633939, 0x94247bbf, 0xb75fb221, 0x3aaae886, 0x200f4a81, 0x518af2db, 0x4c4a47bd, + 0x781bcda9, 0x19aa5530, 0xcf66b984, 0x3c32a801, 0xe2bf85bf, 0xeac2f083, 0x18e3aab3, 0x7c108730, 0x082ee464, + 0xfebb63b7, 0x2c13173e, 0x9be7bbce, 0x1f06a4b5, 0x04f3fcc6, 0xe75b2f20, 0x954f33a3, 0x7fec38df, 0x9422187b, + 0x4e13639a, 0xe73af623, 0x04b93442, 0xdbf6f3e2, 0xeb2ccded, 0x155e2ea0, 0x127b3108, 0x5b065d60, 0x30ee533f, + 0x8493df8f, 0x9cd842c1, 0x138b8449, 0x846cee23, 0x6451cc90, 0x9d6e907d, 0x4579a922, 0x73e58c3d, 0x24a8e155, + 0xff0fe9fc, 0x21f0640b, 0xa6ede7cd, 0x1fa3cbd5, 0x741f268a, 0xec9c4be8, 0x65f9ed5d, 0x49a37301, 0xcb869e12, + 0x8dcc2ada, 0xea7ad180, 0xd09f9b89, 0xa85288bd, 0xbd933016, 0xed4356ce, 0xb2bb7056, 0x454121bd, 0x7da67ebc, + 0xa539c0c7, 0xcbc400ab, 0x03a131cc, 0x1b03a9dc, 0x469c4871, 0x4c2ee1dd, 0x0bdac1c3, 0x7e79155d, 0xcfe494b6, + 0xdf00a423, 0x14f95e9e, 0xef75c958, 0x32cca3e8, 0x632ecb66, 0x2f987595, 0xde2c4ddb, 0xf0a876f3, 0xf67584fa, + 0x86714d4d, 0xee5401f3, 0xd19ede03, 0xbaa8484d, 0x31b8f8b0, 0x8bb988e6, 0x2bf52c9f, 0x81f5b044, 0xc7fed150, + 0x99cc766c, 0xc2b9495b, 0xa1ab0dd3, 0xc2ff1f2f, 0x6b0a00dc, 0xaa9c6a6b, 0x0c68a871, 0x3ebb7f24, 0xe55d3a80, + 0xc149fe2c, 0x272a6098, 0x58258a63, 0x62ed784b, 0x6c2ba4bc, 0x173e86c7, 0xa59e783e, 0x72e2175e, 0xb98a7ea0, + 0x6adb50e0, 0xca4d14d4, 0xebfbc30c, 0x76b4334b, 0x80dc4d4e, 0x239afaeb, 0xb2beacbc, 0x915f57e5, 0xeac3705e, + 0x5efd70e1, 0xd42bcce3, 0xdd6b33d0, 0x9de31187, 0xc807855c, 0xdc3c271e, 0x78fd08b6, 0xbc405ff5, 0x4d125842, + 0xbe016e66, 0xaea31402, 0xbf9ce98c, 0xe8cad580, 0xac65b729, 0xaecee862, 0x42490eb1, 0x39170f6b, 0x96faad33, + 0xf7c200d8, 0x722ca712, 0x97a0bd23, 0x4bbb3959, 0x72c502e8, 0x1395cbae, 0x006ea654, 0x14b0fd47, 0x44c11758, + 0x1818fc92, 0x3b9715a4, 0x6eaec638, 0x5cb80d32, 0x16e64cef, 0xe1c65485, 0x1278b578, 0x2cec51dc, 0x2909e12c, + 0x580e5a38, 0x9991101e, 0x6ff333dc, 0xd7e5a9f9, 0x5127b1d3, 0x653aa568, 0xe83342b5, 0xf5aab424, 0x14b4b10e, + 0x17b0b8bb, 0x6c33539b, 0xb6a1ceef, 0xa6673579, 0xc9ec287b, 0xa8d33dc1, 0xc72faf7f, 0x97bf19b6, 0xe5488d36, + 0xcc60b5ab, 0xecc9f99e, 0xe7791558, 0xe350e381, 0x1b390642, 0x515a443b, 0xc55a6239, 0xf6e8f9dd, 0x934b2259, + 0xd39338de, 0x8790d21c, 0xb735dbd6, 0x0249b57a, 0x6f210e17, 0xf398e511, 0x0eb3b0ae, 0xb95b06c3, 0x87245df6, + 0xc13986cc, 0x16e1afa5, 0x936c537c, 0x05f195cc, 0xede9c304, 0xec5373d6, 0x19c65335, 0x8782fe20, 0xcafa94b9, + 0xcf430320, 0x0813f881, 0xe939459e, 0x4e539b3f, 0xb69e6d93, 0xc211f646, 0x78fc1c1c, 0x6e8f09c2, 0xcd289d22, + 0xfb93d2a4, 0xdaf3fb17, 0xd9d41d9d, 0x8e62ddce, 0x357bc1cf, 0xa594443a, 0x7dddfb7f, 0xccb0b5ee, 0x9b105abc, + 0x77bd38bc, 0xb3609301, 0x91b13920, 0x0905776a, 0x2c8b2448, 0x7d169a5a, 0x03c35667, 0x705af605, 0xf6f3d4d9, + 0xf48a4444, 0xdb5660de, 0xaaf19f5c, 0x0d87cd04, 0x98328cba, 0x03fbce70, 0xc36c1d01, 0xa35f6e14, 0x50400f60, + 0x305b8912, 0xe8d301fe, 0x90b4541d, 0x0217a92a, 0x8b7a5a89, 0xb12bbb05, 0x437c1b95, 0x9e9a97be, 0xc92ab0d0, + 0x74c36997, 0x3e8beb93, 0xb585b45b, 0x9a8964d8, 0x2e069c5e, 0xb61808af, 0x46342fbb, 0x874aef6a, 0x4cb6b48c, + 0x53319695, 0xd92e5872, 0x252d5943, 0xff85e205, 0x3b8c08b4, 0xdad82f5f, 0xde60a78e, 0xa2ff4cfe, 0x18ea93f3, + 0x5879ab9f, 0xceb05aad, 0x153780d8, 0x3cbef169, 0x98dc72e6, 0xebcfc61d, 0x8026ac5e, 0x111815f7, 0x61df1838, + 0xce53cb6c, 0x5526bfcd, 0x368c64fd, 0x3e454316, 0x53e0e5cf, 0x122b0ec5, 0x2cb7bcba, 0x2d7e23b3, 0x2f2525cb, + 0x7e199cde, 0x3cbaa0a6, 0x3fb8a979, 0x242b3125, 0xf98af7a5, 0xa1e485a0, 0xb5b2668a, 0xca0fe7a9, 0x90e7c24c, + 0x64301a96, 0x441e24ff, 0xdf535a39, 0xe643df59, 0xb71c5290, 0xac84d527, 0xb6e8f6f3, 0xeaf0d681, 0x12ab4334, + 0xa40dc20d, 0xad8909e2, 0x0ad3113b, 0xba0e803c, 0x3521a266, 0xd1e561a1, 0x492706c1, 0x8cf5d1e2, 0xff744238, + 0x0410c058, 0x6cb44ac8, 0x3196243d, 0x24de8829, 0x371595a7, 0xaace0dd2, 0xa8fb9799, 0x09423399, 0xc8962a3c, + 0x88139d80, 0x26edcef1, 0xc747e0c3, 0xa922f3ea, 0xb578b76d, 0x0c507f61, 0x8b94e1df, 0xcfe88de1, 0xa484dce7, + 0x6db4cdfb, 0x8edbceb1, 0xdef9bd3b, 0xc0bb10b7, 0x6747d635, 0x6cfcc5d9, 0x909e59c3, 0x5f89ae34, 0xfaba93cb, + 0xa1a3391e, 0x391454d0, 0x85231151, 0x8db86244, 0xb8f21d85, 0x4712ac3b, 0x36fe980e, 0x620cabbb, 0xbb7bedca, + 0x3b193ac2, 0xedb3c7b7, 0x2c437cd4, 0x4603226e, 0xa4e9940d, 0x912246a1, 0x28f1c35d, 0x3cc29221, 0x261ee434, + 0x72dca42e, 0xfa597034, 0x21db54c9, 0xe945827d, 0x2606f4bf, 0x44bc5dc8, 0x3fbf7538, 0x814496fe, 0x29f05da4, + 0x9c972a5b, 0xb6122f99, 0xcbb4e90e, 0xd97e916f, 0x8284f4c6, 0x8bbe3f2d, 0xf06ecb0e, 0x1d3e70fc, 0x77eb45c7, + 0x7be6e851, 0x9587ca7b, 0x1ee81e68, 0xfa1c415a, 0x5a83617e, 0x5c3ad667, 0x0f395686, 0x4dcbe6cf, 0x805bc7d5, + 0x7db50743, 0xdd0502ce, 0x5a6fc105, 0xcf094a19, 0xf86e5ed8, 0x6f9fa8e5, 0xee2afa54, 0xbec805a7, 0x43eaa57d, + 0x73fefad3, 0x875deb2a, 0xffad30c2, 0xff1c1b7c, 0x8faefd00, 0xe77c90fb, 0x3cca0d84, 0xcccb2b7a, 0x4f71531a, + 0x66692b1a, 0x6c60b8f9, 0xee5fc797, 0xf0498e15, 0x2963f0ce, 0xf113f204, 0xc957adba, 0xe6afd13d, 0x783a7877, + 0x3a9d3cd7, 0x786d975d, 0xf570629a, 0x43ce41f6, 0xfbd7d875, 0x77d7482f, 0x231ea5f3, 0x14eefce6, 0x4d52fae4, + 0xc74120d3, 0xae6c9b15, 0xcad5cf62, 0xee57ce2a, 0x568436b5, 0x47a7e348, 0x476a8375, 0x177218e2, 0x82217ced, + 0x9b97c80b, 0x53186dc5, 0xb67d84c4, 0x69c69d23, 0xffe72e2e, 0xcf80b185, 0x37184355, 0xb64f81f3, 0x3caf8c0c, + 0xec06eeb6, 0x988700b3, 0xf37e1625, 0xc10ec438, 0x32f4e136, 0x387a47f3, 0xea04fcf8, 0x4bbf3225, 0xc91727d6, + 0xaa9d33db, 0x52abcf16, 0x95bc6e00, 0x6a11d15e, 0x66b6b553, 0x862f9e7d, 0x7ef04831, 0x6ec57110, 0x2665b347, + 0xaa7caf2f, 0x6d30c2c0, 0x2c4ebda8, 0xaac6bee5, 0x0a474a07, 0xfec26e9d, 0x8998378d, 0x4329eea5, 0x45f2c733, + 0xd42008ac, 0xdaf2a921, 0x1324e5eb, 0xc2e9ea69, 0xe3a3cfea, 0xf86e0aad, 0xbd256b7a, 0x41afcd0f, 0xec73ef6b, + 0x2002ba62, 0x8bccdee4, 0xbad44078, 0x24c1e0ef, 0xa3275182, 0x0a20d023, 0x461fea71, 0x5c511df7, 0x395114ab, + 0xbfb7400f, 0x2e6521ce, 0x7c6d10c6, 0xe2c71234, 0xaf979a25, 0x8a72809d, 0xb3bbd013, 0xa4275233, 0x4f2ae7ac, + 0xa3697708, 0xf1dce065, 0x914b12ff, 0x5d835281, 0x0753b6b6, 0x87bf550b, 0xd0f60dfe, 0x7bf6bc01, 0x7ac10d5b, + 0x2f2ff95d, 0x4ba79e34, 0x948f3a0e, 0x946d3a0c, 0x5f4b10b5, 0x366f102e, 0xca7897e4, 0x4524d01b, 0xaa9a968e, + 0xaac99d16, 0xf1d8b887, 0xf301a371, 0x24c08bf0, 0xdd2c35ea, 0x63f79d9a, 0xc1d4d0df, 0xf9084220, 0xc5cdc17c, + 0x04ab158a, 0x7041c91a, 0x3553520c, 0x255d3537, 0x3b845372, 0x038f8b01, 0x5ee71643, 0x364f80ac, 0xcc3ca712, + 0x5a0cb410, 0xfa1cf6d3, 0x20bd18d1, 0x49bb49a4, 0xf6429a98, 0x570496b4, 0x5efeab42, 0x3d3c0aa4, 0xca183148, + 0xb9532faa, 0x18a7c992, 0x2dad63d3, 0x68c76fea, 0xdc2e4c36, 0x27103d38, 0x3ac210b1, 0x2472190d, 0x0ebab5b1, + 0x66553dbb, 0x9ee6ba5d, 0xbc4a15b2, 0x6e592609, 0x076a7ad3, 0x46fa3cd4, 0x91f39175, 0xe3c5f616, 0xe90d9aab, + 0x6a8b7fe6, 0x2f6f4ec9, 0xc961ba87, 0x9e5fcf9e, 0x428c2e89, 0x68e7847f, 0xe3099698, 0x49fa7299, 0x9fcaed4d, + 0xbb708b7d, 0x5b00606d, 0xdb33368a, 0x0a6c4812, 0x6a442eb3, 0xad74af2a, 0x05f7693c, 0xea89eeb1, 0xeecd2b4b, + 0x0bca0588, 0xd0f3f0e1, 0x7731c993, 0xebfa418d, 0x4287d964, 0x4789091a, 0x2a7f3222, 0x71b866cd, 0x793711cd, + 0x805c8152, 0x90892e55, 0x7ba34c9c, 0x6b88f8c5, 0x0c604caa, 0x345a4676, 0xce9d9728, 0xd70bc84c, 0x1067f366, + 0x24815a65, 0xb12466dc, 0xa89c70d5, 0x0caf7ec2, 0x82fe6fae, 0xa4b983d2, 0xfcbf18e3, 0xa21fe738, 0x2534d2ca, + 0x09028424, 0x62c355f8, 0x77e7a6bc, 0xf85dfd7d, 0x17777a4d, 0x36bad90c, 0x5af2556e, 0x7524f056, 0x22386b27, + 0x0b66f694, 0xde8ecca8, 0xa8fcd09b, 0xace29b50, 0x1e04eff4, 0xc5dbbdd8, 0x69f146b3, 0xa14958b6, 0x8ced18ef, + 0x7109d998, 0x81c858d3, 0x776531a1, 0xa24a4330, 0xa989899a, 0x0a2ec497, 0x061c6f39, 0x8334f0aa, 0x025e38ae, + 0x28ec54ce, 0x6afab30c, 0xd45a6daf, 0xa88da9b8, 0x5e654729, 0x15bc906b, 0xa2b7cc85, 0xfe10dc36, 0x26b8aac8, + 0x35fe4f3e, 0xe3f9a5b6, 0xde1c62f5, 0x9704950f, 0xf09830ca, 0xb2680a8f, 0x0ad0236a, 0xbb74a40c, 0xf2733f3d, + 0x533cc3a1, 0x31e3c300, 0x75320b5b, 0x03311337, 0x816b079a, 0x084d131c, 0x74bed902, 0x23586fe4, 0xaa89e329, + 0x5e392672, 0x0485561d, 0x87c5b232, 0x75b02e5b, 0x27a65976, 0x87ef0e0f, 0xe5c5a50b, 0x7a48f07d, 0xd5d42d36, + 0xbe74fc86, 0xf1c55ce6, 0xdef31f87, 0x3634a100, 0x5c38a28d, 0x48585bed, 0x39c657b9, 0x262f048c, 0x1b8b602d, + 0xee283f45, 0x1fc3b0a0, 0xe9bc98d6, 0x2edc8c5d, 0x05214c00, 0x292dad5e, 0x2385ad4b, 0xcaaea3b8, 0xa1f815c1, + 0x98f801c0, 0x79f03443, 0x35fd1df8, 0x04f605b5, 0x079db3fa, 0x7a5e5974, 0x65879996, 0xa5767815, 0x696b4248, + 0x2602d1d4, 0xf4a5127c, 0xa6f62fe4, 0x266b9e76, 0x9c2f5530, 0x2feea562, 0x1a210fbd, 0x8c95b019, 0x6d73060c, + 0xa45524dd, 0xf545856f, 0xfa4cc442, 0x359ad61c, 0x56efef7f, 0x3342eb87, 0x79c68976, 0x457b2ac2, 0x1831c905, + 0x6b69d77c, 0x0a9eeb47, 0xa8e0a30c, 0x078c1660, 0xc77faa52, 0xd08c94a8, 0x38953407, 0x58911013, 0xb408ace2, + 0x875e9ef7, 0x38081b93, 0x4b8b7763, 0x85e31594, 0x4360696f, 0x95374cae, 0xb3a9f9ca, 0x89fc1172, 0xed444e5b, + 0x9ceebc13, 0x453bb62d, 0xb3a66ebc, 0xbc727b3a, 0x36cae8f7, 0xd214bc57, 0xddd5be54, 0xf3dfd081, 0x60d8be98, + 0x9ee49886, 0x720b2095, 0x6d7a646b, 0x56ff1ac5, 0x4893004f, 0xd9b2999a, 0x79ba11d8, 0x4524a498, 0x678ab943, + 0x390dfb54, 0x3d0af366, 0x1d000900, 0xc7aa0b06, 0x6fbc8e57, 0x8328f9a9, 0x8535ca37, 0x4abbab14, 0x139381b8, + 0x14d6c33a, 0x0469afe7, 0xac32267a, 0x1729be14, 0x16d6f2c1, 0x90e84ed1, 0x3258d1ea, 0x9703eb90, 0xda7cccab, + 0xd0744933, 0xdbac30ff, 0x09059902, 0xbe8eaa4f, 0xb82c6a1e, 0xc52c4846, 0x672d7e00, 0x33aacd3b, 0x70d66804, + 0x212d882a, 0x6540ad54, 0xacca6aa3, 0x77e04892, 0x15a8dfc2, 0x49163835, 0xdcebd941, 0x03157ce9, 0x061a40b3, + 0x76a43a20, 0xf04bd0aa, 0xade438bc, 0x3bce40cb, 0x92150032, 0x476b91c6, 0x4abfd45c, 0xcb490438, 0xd0d58ab9, + 0x2d925ffc, 0xfb5e073a, 0x0b3ddb49, 0x55df424e, 0xe718a226, 0x0500e86e, 0xe55adf00, 0x98b384f7, 0x81a1cab0, + 0x47268045, 0xce870d58, 0x3d7a50c0, 0x1bb0a734, 0x7e0c6896, 0x2e953659, 0xed85cde6, 0x504c39c5, 0xe0cb71b7, + 0x84287258, 0x257800c3, 0x8b028e95, 0xcb486547, 0x733522b7, 0x9cb9f3a2, 0xa38de0c8, 0x126f554c, 0x39f9436d, + 0x29227f8f, 0xb5e96bc2, 0xb6060bd3, 0x5a28df45, 0x8cd51954, 0x8644b349, 0x9dcb9b74, 0xe6ff4e46, 0x5f969a26, + 0x7fcbd7c0, 0x644276a8, 0xb1b17afa, 0x13101d6d, 0x30007447, 0x5a35b9a9, 0x6fab73f8, 0x7f96287d, 0x52a3820f, + 0xb0ec04f8, 0x53ced32f, 0xf675412f, 0x8540c791, 0x0a1ef8ef, 0xc2b3e825, 0x0b0c4731, 0xd91da58c, 0x4cb99d13, + 0x3baac2d8, 0x12a8ff89, 0x7a32d33e, 0xf72dafe1, 0x0176d9d2, 0x330b400f, 0xdd4abbc6, 0x08284001, 0xed65415a, + 0xb15c8342, 0xb8b2deaa, 0x7ab24150, 0x77a911bc, 0xaca71631, 0xf4ff279e, 0x32a21fc4, 0x8cc8274b, 0xaef6d3dc, + 0xe9ec0dec, 0x6aa0e028, 0x45f1a70d, 0xd9328757, 0xba70a09c, 0x05017ff3, 0x9d7b19bf, 0x3219aeba, 0x64a42383, + 0x5c76ea86, 0xb4f68d8c, 0xfae24abb, 0x0ae3d2e0, 0xa2afec0e, 0xe3d337e0, 0xefc21750, 0x5f9f9eb8, 0xca34d036, + 0xc795cc0e, 0xc49a1b2a, 0x4568638d, 0xad5ccc27, 0x4e4a428d, 0x0ff9fd32, 0xf923366b, 0x5b7227b7, 0xfdcd681f, + 0x865fd33f, 0xb1a8bc0c, 0x5aea3877, 0x183585d3, 0xa6f5fe30, 0x4def9de7, 0x8d1af9f7, 0xa55abc5c, 0x77f78df1, + 0xddd4c271, 0x85b96256, 0xd46073f9, 0x0f6f911d, 0x20cd04bb, 0x670e0416, 0xa66e3941, 0xbea63bc2, 0xe55a10c0, + 0x4a0606d3, 0x6e79f7df, 0x4001a1a8, 0x9c2d1bd9, 0xbe87c655, 0x242640ea, 0x8b70ef65, 0x5c139b25, 0x8a5a8695, + 0x27f071f7, 0x8d9a03f1, 0xa755abea, 0x333a4218, 0x9fab649c, 0x3bb6c963, 0xe4cbe2a0, 0x44b7ca40, 0x1069caa1, + 0x8980b9d5, 0x6de1a3bd, 0xb92f806b, 0xb8ecb707, 0x928094e8, 0x594b0ba9, 0xe7ad8191, 0xf45eeff9, 0xe4c05c07, + 0x5b5da67b, 0xc19cc966, 0xf3a7a854, 0xfd5eacfe, 0xa410a92e, 0x79566e86, 0x79d5df3b, 0x73c0cb9e, 0xa7685535, + 0x7889dd84, 0x21a2534f, 0xa090edaf, 0xa924edd6, 0x3e42015b, 0x2ebeb69a, 0xa6545708, 0xa1aaadf7, 0x91df2c35, + 0xbc81b3cd, 0x7234ab92, 0xe554cc92, 0x203bcc6e, 0x3a9c62a5, 0xadbb6c9a, 0x458ecce9, 0xf626d504, 0x23678668, + 0x9e1fede4, 0x99646f33, 0x910a6cac, 0x7a840e74, 0x9c0fc517, 0x8ef3a69a, 0xa27ef756, 0x81ab2b0d, 0x4c3cf204, + 0xb4cc203c, 0xa040174d, 0xe654eb00, 0xe765fd2a, 0x4cc7f279, 0x0a3b6968, 0x84d5a08b, 0x7f7f53f4, 0x83ae046f, + 0xc0c548f7, 0xfa2990f4, 0x11b68d68, 0x3a0498b3, 0xf50d2c6d, 0x8e4cdabd, 0x93dda826, 0xfbf5b733, 0x32bbfc25, + 0xb91a1b18, 0x83636ea0, 0xf48351e5, 0x21325334, 0x0da5bda2, 0x5ac2941e, 0xcefdc207, 0x92fe8dc1, 0x8ea25a50, + 0xb644b78a, 0x5c418561, 0x2ec541ad, 0xad6f082e, 0xf93f55e8, 0x533d6966, 0x0ef8676d, 0x08265269, 0x515a3d85, + 0x9231f969, 0x1eedbe73, 0xa144228c, 0x25790ea6, 0xc245ad83, 0xa6735fb2, 0xa2cc5c02, 0xc97087ec, 0xe3c65e60, + 0xd1eed5b5, 0x0b2b945b, 0x57a8e614, 0x35792752, 0x1f17a88b, 0xc58287d6, 0x87ec8a6f, 0x38cd7882, 0x86c87d0e, + 0x66150ada, 0x16115b2c, 0xda36dec4, 0x1e06cfb3, 0x8d9ca02b, 0xe8630bb6, 0x9dfff127, 0x23e256c2, 0x0c6cc254, + 0xa1af907b, 0xe031bc6d, 0x514a8a26, 0xb6d823f5, 0xc5992799, 0x1729321b, 0xb26c9dd0, 0xc4e3b859, 0x5ed31518, + 0x83696f44, 0x5b2f7dce, 0xf616111d, 0x9c6227b3, 0xf48221c4, 0x409b0a56, 0x244c8034, 0x2d13249d, 0xf3f77550, + 0x48093307, 0x230d0383, 0x11a71e6a, 0x829ada7a, 0x652c39cd, 0x743bbdc9, 0xa6938dc0, 0xa43e7f61, 0x7c39bfca, + 0x2c42cc8e, 0x2f8868db, 0xbcf6767e, 0xec7af731, 0x5b0c18ce, 0x9526f91a, 0x9a9a7e69, 0x432e8505, 0x5ee507e6, + 0x6f782590, 0xda9ac8e2, 0xc271430a, 0x08d2ba4e, 0xa0405dae, 0xe272346d, 0x28a202ca, 0x89de1753, 0xae6e5adb, + 0x4906f4a2, 0x0b1c1fb0, 0x42116d36, 0x4b4d65df, 0x1e7f13a6, 0x30d9cbd0, 0x0c12ccfc, 0xa85645fa, 0x049bf3af, + 0x1b13b577, 0xb636383d, 0x61d2d930, 0x139728cc, 0x5cf49eda, 0x2f8a36c9, 0x8491e1a1, 0xe12c3a17, 0xebe7a043, + 0x4dad94f7, 0x6e8c48a1, 0x85b13c13, 0xd10c474c, 0x2e087c53, 0xa725b4ec, 0xcc9bd23b, 0xc6f08c72, 0x4987e9a3, + 0x193a06a0, 0xbfdc1f5f, 0x436fa84a, 0x4e679fe2, 0x76c852f5, 0xa565828d, 0x70e9cc50, 0x868dd6b2, 0x1942e9a7, + 0x148e4285, 0xf78696e3, 0xe1d50e51, 0x130b8c11, 0xb9b835f5, 0x1087ae49, 0x988bf380, 0x19d9d84a, 0x9a45b817, + 0x8fa123cd, 0xe0779d74, 0xc7e967e6, 0x4785d8e5, 0xfe0c38b0, 0xf38425c2, 0xccec080e, 0xcd6da49e, 0xbbeb366f, + 0xb9797d8d, 0x8fbaa944, 0x80dff289, 0x2eb7e52b, 0x5438b748, 0xf3aaaf1d, 0x8b69af82, 0x9bdde21b, 0xb17835f7, + 0x86630057, 0x78300393, 0xd39986ce, 0x1e5fe3e8, 0x33db9f90, 0xc9023333, 0xb68c3ff2, 0x70ecbbfd, 0xe6dea378, + 0xda270f6e, 0x99cefb1f, 0x72c6a44a, 0x465ed24c, 0xed5387fd, 0x07e446c5, 0x8ac30321, 0x04bf9d2d, 0xf3e20e61, + 0x4bfb2ea2, 0xd76c9db3, 0x440e69b7, 0x29eddd7c, 0x92c017c9, 0xafd77b5f, 0x43288c48, 0x950a55a5, 0x413da1b8, + 0xda727218, 0x057ecb48, 0xfe7ea3b6, 0x6b43859b, 0xdfc48546, 0x7af1fc39, 0x9723a41d, 0x4ce8caaf, 0x69d8d067, + 0x2b5f890b, 0xdc42c485, 0x5ce37d3a, 0xc6a24e90, 0x23e2f745, 0xe0b97641, 0x688d63ab, 0xed758a98, 0x182132b1, + 0x2a606651, 0x19232dea, 0x666615ed, 0xa380a545, 0x29ff2cfb, 0x1a8167bc, 0x534bb561, 0xb7a6ac43, 0xb0ff4614, + 0xb0d6e65d, 0x78173147, 0x1553b6f2, 0x98e4aff8, 0x75dc971b, 0x9d30f517, 0x20e215ea, 0x56cf87e6, 0x6ae8f24c, + 0x47cdd6fe, 0xb06320d8, 0x0fa334f1, 0xe724feb1, 0x7cdf1832, 0xd64df7a6, 0xb280650f, 0x3c9d497a, 0xfa1bc476, + 0x23fba2bc, 0xd82e5acf, 0x173395b4, 0xdbf98624, 0x2cb78153, 0x806b11f3, 0xe158c4a1, 0xd3d985b7, 0xe9f326b5, + 0x3b20d280, 0xcc67f79e, 0x16343ac6, 0x44e4a56f, 0xb85f0d66, 0x4177f28f, 0x8f36a062, 0xe3847dd9, 0xc9d9e19b, + 0x4b338d89, 0xc5cd9cc8, 0x33954625, 0x3412da50, 0x7b3bea92, 0xc6765b29, 0x16c2d0a8, 0xcba1221d, 0x0df68205, + 0xf3978645, 0xc4f5e758, 0xff122f81, 0xc04fb8ea, 0x8bfff604, 0xaf69180f, 0x0ff5c4cb, 0xe153b677, 0x06123a70, + 0x8d8b614a, 0x59453db3, 0x68ecbf17, 0x4e4ec8b3, 0x93ea0eae, 0x3c7ecb4a, 0xc3494d94, 0x36e1d933, 0xc9ad4ea6, + 0x3c7303c4, 0x44242b58, 0x39441f39, 0x2c973f8b, 0xb93ec70f, 0x218bb038, 0xaf1f78ee, 0xe2de5eaf, 0xbdecaf10, + 0x4a4bf854, 0x3940af56, 0x3b85cc5f, 0x56645ddc, 0x81008cac, 0x87147715, 0x29e7b3c2, 0xbaa90fcd, 0x9f804491, + 0x9b1a4d4f, 0x21afab83, 0xb7030e40, 0xe8e24b64, 0x5e6041ca, 0x8083aeb2, 0xbd76eada, 0x2bee0e6d, 0x423dbd6c, + 0x8b50b20b, 0xd8a0b256, 0xd402080e, 0x9e7976b1, 0xc667ef6b, 0xfe6b86b1, 0x3aaab6e5, 0xf5904ce8, 0xf99dcca7, + 0xa5df9bc0, 0x50355a18, 0x89f78a80, 0xac980a74, 0x3e806b10, 0x4043869d, 0x20274b65, 0xa3c2897c, 0x6f3834ba, + 0xd904a349, 0xf9e59dbf, 0x88b2cceb, 0xe2f85868, 0xaf2a8788, 0x517e6585, 0xc63d9b2a, 0x0b956476, 0xf519e9ad, + 0xd4abe7e2, 0x5a308c7b, 0xb616674a, 0x2cdaa5a4, 0x6b749051, 0x20fecec5, 0x16b163ca, 0x268f05ef, 0xed65dc68, + 0xd38616da, 0x8c2af97e, 0x556c17f4, 0x809819f0, 0x1bdff175, 0x8de3458c, 0x6f7a13bf, 0x82184300, 0xfd983e75, + 0x3ea9ea6a, 0x53bc06d9, 0x086bc2c7, 0x6e7aa79e, 0xc0b05ebc, 0x09d6cd9b, 0xce616d20, 0xe5d361a4, 0x1d30a67c, + 0x3196a0dc, 0x0f7d1769, 0xfb7f22e5, 0xc6088663, 0xff88131e, 0x2a989f3a, 0x21e8145f, 0x825aafd7, 0xb9c8e545, + 0x5d971702, 0x846623d7, 0xb41ce120, 0x5276a935, 0xd3a03875, 0xa4d6aa9d, 0x5b5c9316, 0xb727fedc, 0x364bcfcf, + 0xf43db3ec, 0x311b9f7f, 0x50d6e2ab, 0x15cf55fd, 0x78cd6c50, 0xac614f5d, 0x8d66fdf3, 0xa3a8e210, 0x5bf3b888, + 0xee29ef88, 0x97bbb9fb, 0x103da6f3, 0xa88b83b6, 0x19bf2830, 0x0b32b597, 0xa147ee02, 0x4b6d91c5, 0xd116ac3b, + 0x62073d2a, 0x29230d21, 0xbe7e96c9, 0xcd7ffe1e, 0x71b101f4, 0x65212b93, 0x6e587af6, 0xcccb7616, 0x39eda6b6, + 0xda1814ad, 0x9bc37d83, 0xbc171f26, 0x4b2f64ea, 0xf040c87e, 0xf8c5407f, 0x1feb9794, 0x657016ba, 0xf61fb5bb, + 0xdc1d27b6, 0x068b9eb6, 0xc7f80c23, 0x7e7b4ec8, 0x24cd282a, 0x3d04fdce, 0xfeee89ee, 0xe77ff612, 0xef4ff113, + 0x8db1dc4e, 0x692cb1fd, 0x58da60b5, 0x69fe7cdd, 0x3b405313, 0x768792a1, 0x3285c702, 0xb80f7df6, 0xdb8a6d61, + 0x29e73a9a, 0xd4353504, 0xd1fc5d8d, 0xe15a2eaa, 0x9c4b15f2, 0x6c4d6077, 0x7338d39f, 0x37393575, 0xad182993, + 0x1a466c17, 0x71f6dbec, 0xc7460ad5, 0xa4cef319, 0x64e6ad02, 0x80d55885, 0xf5fdcdef, 0x0736b04e, 0xf888b7e3, + 0x05f02e41, 0xd4371fb7, 0x781c6b56, 0x32b0acb8, 0xd943cf93, 0x278e64a7, 0x31e9f10c, 0xfbf13247, 0x2100b4b3, + 0xfbffc7b7, 0x013cb349, 0x2f9b3d7f, 0x198fc6fd, 0xe8714c6d, 0x3bad2fc2, 0xaddb3ac9, 0x15e81b9a, 0x85acb2fd, + 0x1bd7125d, 0x8011967e, 0x8b632242, 0xf958de31, 0x71038c41, 0x86db62e3, 0xd10133df, 0x7a7e21fe, 0x8b0d2e79, + 0xd7eb013e, 0x3a96b9f7, 0x882d4a67, 0x19c05652, 0xa7c5b1b3, 0x172fefda, 0x1459b735, 0x29bb8953, 0xfdf85a63, + 0x55fa5bdf, 0x0814fd83, 0x48f0da98, 0xdc2a9960, 0x566e31e9, 0xa663c60f, 0xd320d874, 0x7ea77664, 0x4a2a0ed3, + 0x30de229d, 0xbfa81490, 0x9c7e429b, 0x9612a9be, 0x5e463829, 0x3930119a, 0x2be427dd, 0x023d14db, 0x07266ea9, + 0xbcc84d2b, 0x0d64ece3, 0xda7a876a, 0xa73921ef, 0xb70d306c, 0x3efa17cb, 0x2a948412, 0x2dd898f2, 0x78247ab7, + 0xd868935e, 0xdb2fa570, 0xae479cab, 0xacae774e, 0x05341fd6, 0xdd623d14, 0x3cdc99e1, 0x89216c0a, 0x09eae443, + 0x7365d201, 0x7fd4e2e0, 0x918c1c40, 0x68689515, 0x6606be79, 0x81984139, 0x0350a3cf, 0x018638be, 0xcbb45e2a, + 0x046bde13, 0x463ca6bd, 0x86297c46, 0x3b5e995b, 0xbd6b7986, 0x61731501, 0x58d01e1f, 0x7e8292c4, 0x9b33e7b9, + 0x19847d1e, 0xe189acca, 0xd2d150e8, 0x13baa0d1, 0xf684bbde, 0x434bb4ca, 0xafd070f3, 0x8189b766, 0x85294e19, + 0x04c86869, 0xb11cd050, 0xac246001, 0xd137d1b6, 0x0ebbbe9a, 0x99eab61f, 0xcf2ae25d, 0x40ef7e85, 0xb893a700, + 0xde2b7c09, 0x04210491, 0x60a6b788, 0xf4325c2a, 0xe31f823c, 0x8249acf4, 0xc32b1881, 0x796bfd37, 0xa3342782, + 0x05dc367e, 0x32dab28a, 0x90874f89, 0xd9285b17, 0x93847acd, 0xdcfebd9c, 0x18d45a1f, 0x8251c9ec, 0x561cf385, + 0x3e842ea1, 0x424b6136, 0xde571e1d, 0x9f41052e, 0xabf558fb, 0x231edb76, 0x0aabf78d, 0x6841ea1b, 0xc95471d6, + 0x224ecb2e, 0xa3eaac61, 0xd459bc30, 0x290235c0, 0x13cb675d, 0xce1edca9, 0xb71a88c2, 0x15a8659c, 0xb99389cd, + 0x6aa4f2be, 0x68dbcb9b, 0x87b46211, 0x5dad87ba, 0xd0c3de9f, 0xf5e2cd53, 0xbd9edd80, 0x10b270b6, 0x12e36862, + 0xd1f60880, 0xc738a99a, 0xd3576bcb, 0xf236d64f, 0x5d19699b, 0x87d86fb7, 0xf563c372, 0xfb688871, 0x6b734a9a, + 0xe191acf7, 0x26e480ce, 0x4f7d9063, 0x9dcb89e0, 0xdb22f502, 0x55e9919e, 0x89effd01, 0xea229f1a, 0xfdc0240e, + 0x562cafec, 0x6ee2ec88, 0xf7409201, 0x2863f0da, 0x2225577b, 0x4acc2503, 0x585ed27f, 0x9cebe9eb, 0x9e69142c, + 0x0660b086, 0x6f27cf58, 0x24abbd61, 0x464418bf, 0xaeaa1749, 0xc65ed17f, 0xf3874375, 0xe0f34c67, 0xe5636e2b, + 0xf7f44978, 0x6c5a4e33, 0xd7550e4d, 0xacb2467c, 0xaa0ebdf5, 0xac4a448a, 0x72905de5, 0x63b26b66, 0xb4eb3697, + 0x8123b7c0, 0x25c83b4d, 0x12f69328, 0x23d78e1d, 0xe0bf88ab, 0x52ebbdfe, 0x276e460b, 0x76eb272e, 0x38c2a7b2, + 0xa76dde4d, 0x0a7bbbd2, 0xe01bd147, 0x7a904e9a, 0xf63292d9, 0x08cee49a, 0xd6f507d0, 0xa64265b0, 0xe1f88ae8, + 0x762f1039, 0x4eae4f5d, 0x6ef735d1, 0x7adb9585, 0xdda6e3ff, 0x75c44947, 0x786dffb0, 0xfe04e1f5, 0xd3355624, + 0x6efb5cff, 0x8ac31157, 0xbaf804c9, 0xab4b1d6d, 0x2fbd6ec7, 0x62e46d8d, 0xd0de4ce8, 0x4443b743, 0x4a778ca4, + 0x0488f315, 0x87bc7b37, 0xa64848d6, 0x3d53871d, 0x1bde6097, 0x823979b2, 0x6a7805c6, 0x8d45e14d, 0x7029a005, + 0x7d2a69eb, 0xfdfee637, 0x0d2e890d, 0x26a27e8d, 0x532b8eee, 0xc9500735, 0xd99d6466, 0x6be64ec0, 0x9764900b, + 0xa9c4d543, 0xb792d7d8, 0xfdc69186, 0x9a45b4d3, 0x2b48b790, 0xad1cedcc, 0x0b3b6ba6, 0x7b7d5aee, 0xafebc5e0, + 0x04ee1984, 0x808c0e96, 0xf52068ba, 0x6e34076e, 0x5a81b585, 0x1b7b1de3, 0x7d8a0bda, 0x9a3ad962, 0x20a9f578, + 0x662a9cc8, 0x5ee6df0f, 0x8a0f4ab5, 0xf6928bfc, 0xecf7fc53, 0xccd50473, 0xcbe9c0d3, 0x11f68f6b, 0x1a87cacb, + 0x88041de8, 0x65cca367, 0x932a117c, 0x8a11064a, 0x18f8e9b3, 0x1c68e2ed, 0x45cf0bac, 0x75c3c8a3, 0x4acd3123, + 0x81a3e209, 0x3a7a816d, 0xab027fd4, 0xd06952ac, 0xd84ce813, 0x9a1c2b44, 0xae7578c4, 0xe21bdc7a, 0x9c976745, + 0x71637fff, 0xd77d5860, 0xac70dc83, 0xaf4a81ca, 0xbfe32279, 0x6eb5706a, 0xa154b33f, 0xfecc5009, 0x5780c123, + 0xfafa96f4, 0xd2aa748f, 0xdb872a83, 0xa83bcf40, 0x112654ec, 0xce5791b2, 0x9a5dd232, 0xb43c1ac7, 0xd76622c1, + 0x7da2186d, 0x92a1d94f, 0xf3ff8271, 0x0ccce37a, 0x32688a18, 0xa22b35a6, 0x89530a04, 0x31428cd7, 0x46e86146, + 0x5a03bf45, 0x58cbba74, 0x2df8aee9, 0xbaef1fa3, 0x8a373d01, 0xa72f3a5a, 0x6af66b0b, 0x0dadeff7, 0x7cb50715, + 0xb4ccfde9, 0x82bf5874, 0x73afeebf, 0xc56ae8d4, 0x8c200fdc, 0x41d4e5e4, 0x13e5fa07, 0xa085c8ea, 0xf7237365, + 0x5fcee4d9, 0x12aa9351, 0xeda572dc, 0xb26e7e60, 0xc2f5621f, 0x2cd22a7f, 0x4a6128a0, 0x55d99e0b, 0xf3700302, + 0x9a6fdb6d, 0x45ef9c80, 0x9f031a49, 0xc1b8907e, 0x744eb62b, 0xcc873ada, 0x3aff19ae, 0x943f6590, 0xfcc5c21d, + 0x73a84cea, 0xf2c94d22, 0x551ec9ed, 0x143dff99, 0xb9158e4e, 0x8c967690, 0xb1aba9f9, 0xc5a4870b, 0x33b3dbd7, + 0xdcac5e71, 0x29d113ea, 0xc7d8e618, 0xa9e8e9ea, 0xbf0c02a6, 0x84138f02, 0x3338aa7d, 0xc1a8e69d, 0x04ddbd48, + 0xdd4334e7, 0xa4752083, 0xc25703a1, 0xf4a232e0, 0x83af97d2, 0x7a442825, 0x21710984, 0x56cb5ae1, 0xf643e617, + 0xb1177c46, 0xa6eb416e, 0x10e06525, 0x970c4bf3, 0xa5a85734, 0x70810e74, 0x8ef6bd39, 0x1530682a, 0xba92f38f, + 0x6a26630b, 0x85c67753, 0x405bcd2e, 0x896296cf, 0xfbea723e, 0xc7dde11b, 0xae4abd03, 0x8bca80af, 0x9ac2a343, + 0x2d770e1a, 0x1954a51f, 0xcbc3c465, 0x1bbbf7a2, 0x9a0f4ea7, 0x869a3091, 0x3aee9b36, 0x094eac8b, 0x5a332f52, + 0xb089444e, 0x596d999f, 0xaaced67e, 0xc2fa9a8a, 0xafe45c5c, 0xd6cf70f6, 0x473b44f0, 0x114ab97b, 0xba6932e9, + 0x56357ada, 0x887f3a50, 0x112abe54, 0xe91cb072, 0xf72ac22c, 0xf73b6870, 0x8085e224, 0x97a946a3, 0x3bba3268, + 0x697e00fb, 0x466dabac, 0xa51957be, 0x30380a54, 0xbd7a44f6, 0xfd13f877, 0xae9ac85e, 0x1a241755, 0x559c33b7, + 0xf74e5894, 0x8c4c8633, 0x1d64fdb6, 0x8c893f06, 0xd37ba992, 0x211dae0f, 0x4e9f7c65, 0x2f4e0952, 0x35312eef, + 0x9b1e2e43, 0x8a675688, 0x3c80c6e0, 0xb48efdaf, 0x8832c8e6, 0xd9201eaf, 0xe1bfb838, 0x0a237833, 0x68523653, + 0x0642af02, 0x900f1b45, 0x99e8fdfc, 0xec5dc717, 0x3b3d1c4a, 0x31d5c701, 0x998d4682, 0xad4993ae, 0x2d2aa53a, + 0x290d7980, 0x794af323, 0x9911beab, 0x27c674ee, 0x006cbffc, 0xbdd54773, 0x38f887df, 0x579d1e0b, 0xfbcecc52, + 0x39c66c03, 0xd31f71d3, 0xb0296085, 0xb9eac4bd, 0xdb031803, 0x3c203d41, 0xfbd16ffe, 0x8fbef16c, 0x873af88b, + 0x25c0e38b, 0xf36e14eb, 0xcd7ea285, 0xb8c2fdf6, 0xbdff7686, 0x84e71250, 0x88c231a4, 0x41186931, 0xb264bdec, + 0x481bcacb, 0x97743aeb, 0x519583ee, 0xe5161da1, 0x893fcb0e, 0x5f587038, 0xa2e18adc, 0x9408c22e, 0x4e5933a5, + 0x7b05e27e, 0xaa7d3f06, 0xef0423a5, 0xa9d78f9a, 0x90c3ed2f, 0x0ba7fe2b, 0x8509ed20, 0x1c996058, 0x497c0349, + 0x2fd1f954, 0x2f0e8038, 0x5081fb46, 0x7b6ebe35, 0x1bd3ebde, 0xd16e242b, 0x3d004678, 0xc1070831, 0x935a7e81, + 0x1711a48f, 0x4c2c99cf, 0xbcb9d1f2, 0x4ab2a76d, 0x388f388a, 0x5d657afc, 0x1f45e8f8, 0x6e27c8e2, 0xd1d25d77, + 0x1fe01dc5, 0x001a6cd8, 0xfcbe4c91, 0x3b5a8429, 0x8bc17a9a, 0x4c6f83d5, 0xa90abfd3, 0x72e64a01, 0x9df7d8d2, + 0xcd441045, 0xf47c46c1, 0xfebc5eae, 0xf012f0c8, 0x880abdca, 0x6f549185, 0xc2e9fc0c, 0x69a00696, 0x8a15d5cc, + 0x3fa769c5, 0x476ac933, 0xb4f8e371, 0x40bc0ed2, 0xbe39013f, 0x4e3804db, 0xb8620202, 0x53f06c1e, 0xda0dd6aa, + 0x7a19d09f, 0x67452967, 0xb1ddcb64, 0xf7082eb4, 0x3fd6ae7c, 0x9d50417d, 0x735ca3ec, 0x1e03b10d, 0xa5022ed0, + 0xd83b8c98, 0x87330e93, 0x2f72b9fb, 0xbb9f5bb3, 0xea280ca8, 0xaa6ad635, 0xc831b92b, 0x5beb5107, 0xb54e2caa, + 0x0f72aedf, 0x87e4ed63, 0x980c33bb, 0x5589877b, 0x7809bf5d, 0x01e97965, 0xeea4893d, 0xc27752c7, 0xa0ef8dea, + 0x807a5303, 0x5bb0f79f, 0x3f125014, 0x0e9a6a8d, 0x9ce35609, 0x0b885261, 0xe42c4d7d, 0xb8d3d124, 0x2d5eb2cc, + 0xb00a74c3, 0x5b091e32, 0x487b179f, 0xedaa4d02, 0xb9d4bb07, 0x6f21e871, 0x3fffe5f3, 0x4329d687, 0x9d71b862, + 0xbfb1f493, 0x80f1a139, 0x96fc8a50, 0x942f9a7b, 0x0f692993, 0x8218aba3, 0x121782b4, 0xc865a01b, 0xe3494b3b, + 0x50ea3652, 0x5476835e, 0x1e549251, 0x5fc2b6c4, 0x6bdfd524, 0xf4233347, 0x5d5aabfd, 0x41123ab9, 0xddeedee2, + 0xc60ca7ba, 0x9debc0f9, 0x12780b3c, 0x4ad31844, 0xdd26dfd4, 0xd99908ef, 0x8231a57e, 0x9c58c28a, 0x5d1cfd07, + 0x8baf7c7d, 0x6cee8221, 0xf8bdc025, 0x443734de, 0x89ede225, 0xed908779, 0xfa509d4d, 0x7a034b9a, 0x19f9325b, + 0x5627c741, 0x365bdb36, 0xd0d3915e, 0x38ff831e, 0x6d2b0456, 0xdd7ba249, 0x68982441, 0x3c94d63d, 0x284ad36c, + 0x7317f746, 0xd7c2e04a, 0x19459ef4, 0xd405dc41, 0x71ebaa4a, 0x15c20c7f, 0x1e475392, 0x9f2300ad, 0x45022c06, + 0x0c6abcdd, 0x117f14fd, 0xe1583e43, 0x13a88d8e, 0x0e745d46, 0x304864d9, 0xabff48aa, 0x350d732f, 0xdd1d2119, + 0xefb92c95, 0x251ce3a1, 0x8e7b38b4, 0x6a08a6e2, 0xf5283bbb, 0x706b1f0c, 0x71eb055f, 0x8167a854, 0x47c813c3, + 0xf40933d7, 0xbd07a806, 0x7ff536e7, 0x1a5c0127, 0x49f1797f, 0x073cdae9, 0x48e7c0b2, 0x4e368da8, 0x06455ef4, + 0x8788eed9, 0xd75c4d06, 0xbc021711, 0xcf57026b, 0xa64a2f18, 0xafddada8, 0x285f334b, 0xc030a097, 0x01aba98c, + 0x987a50b5, 0x9af170b7, 0xdd689ce5, 0xf40fec55, 0xa8cafebf, 0x44131e7f, 0x77da2771, 0xf977c0f9, 0x8c6e81f3, + 0x56235bd3, 0x0a79bba7, 0xdeb86ed3, 0xcf4f3a4c, 0x925eda5f, 0x24e30be1, 0x8c0b978c, 0x3fed8763, 0x0fb12acf, + 0x5bc45b86, 0xbdd5c856, 0xb8c337b4, 0x0c0230d6, 0xdfa2c89f, 0x09dabcd3, 0x6ece20ac, 0x858230c2, 0xf44fc96f, + 0xa3eb5197, 0x39c66b3b, 0x25636141, 0xd9d66eda, 0x6ba6ad7c, 0x08defe48, 0x1a7f7697, 0x875c76ec, 0x554bc971, + 0xcf033225, 0x8e584600, 0x258e14c1, 0xb9db7443, 0x0e03a123, 0x6fa5aebf, 0x8f2d4adf, 0x1b3978a7, 0x297b5a31, + 0xbb23d57e, 0xda442a1c, 0x086a3c37, 0x9f442522, 0x64fd61b6, 0x8af3b898, 0x2c8e7ac2, 0xe9e7f4a0, 0x12e0ef96, + 0x6989e4da, 0x7e6bb691, 0x43872e72, 0x6316ac89, 0xf8d9997b, 0xe40f7ec7, 0x7775ce7d, 0x5f28e412, 0xf2f66a3e, + 0x21b11ae0, 0xf6509559, 0x5c1b6b79, 0x37151cc6, 0x49f21675, 0x07abc622, 0x5cd3837f, 0xe720d2fc, 0x193f7057, + 0xa092b82d, 0x50d03894, 0xbc098a6f, 0x8a4a39b1, 0xbe880dd5, 0x05926cce, 0x2b4bc6b0, 0xd6a7c3a6, 0xc7d2d13f, + 0x91ba7007, 0xdbde8b07, 0xb3549a51, 0xb0732438, 0x4544d8db, 0x4c8adcb3, 0x20f098eb, 0x58f87a4f, 0x224b70f1, + 0x01492625, 0x66b88adc, 0x43d80f76, 0x9715bc4e, 0xb4e84f03, 0xd84771d5, 0x1c72de02, 0x3d22ad92, 0xf0991b67, + 0x41140ddc, 0x575f5e46, 0xe5f0ca1b, 0x02b48603, 0x205bf48c, 0xb7205376, 0x6418c318, 0xab541721, 0xcf7fb0ac, + 0x0d02008b, 0x1bfae3cc, 0xdbb1b9a2, 0x2d87dc75, 0x71195cf0, 0x9466bbe8, 0x982f9a46, 0x40303dc1, 0x13b924ff, + 0xc2c13b66, 0xdaa1061c, 0x40a04cbf, 0xc87cf706, 0x1c013091, 0x345bfc23, 0x05b79d57, 0xc2c6d8b1, 0x9e3661ee, + 0x082d1852, 0x3218bba7, 0xd741d840, 0x7f88d4e5, 0x6256f979, 0xcc740170, 0xad1e25c7, 0xefbf712a, 0xe9963432, + 0x509dfa2c, 0x846890e1, 0x9efbd9f7, 0x6ee2fd74, 0xb6b697c7, 0x999a3f5f, 0xcc310acb, 0x69e97578, 0x50d895c7, + 0x38f5764f, 0xe5338759, 0xa2581cd8, 0x8035b76f, 0x9dd15bfe, 0x3ae4c0eb, 0x9ba929e9, 0xc0cbe6e4, 0xd0911e45, + 0xb3f34e72, 0x9a01011e, 0x00cce277, 0x83a53043, 0x46ab358b, 0x3a8f2641, 0x4df37648, 0x0bfabdac, 0x8fa0d557, + 0x8f7e0b74, 0x36992b2b, 0xc01d3e40, 0xaef22ff5, 0x3a01dea4, 0x9c4eaced, 0x0ced58b7, 0xe740b1b7, 0x16f31a8e, + 0x95e3aef1, 0x26744d93, 0xbe2d98e5, 0x9169ae65, 0xdf777048, 0x72c0e04f, 0x3e73fcb7, 0xa7b0852e, 0x493a0a33, + 0xb6abd981, 0xb5d1b8fd, 0x8baec91d, 0x1632fb2b, 0x58fede08, 0xb450015c, 0x261dd276, 0xc42ff79a, 0xbedca9e5, + 0xaed31e8a, 0xe64d7ac7, 0x2bfc4faf, 0x7aed06bf, 0x6ed2e94d, 0x3549e024, 0xa40c6853, 0x79b8fd53, 0x6b3675db, + 0x82486af1, 0x735d43d0, 0xe13ae0fb, 0x948dbef3, 0x4be9e862, 0x2769cdc0, 0xaf22ae1f, 0x4882c8a5, 0xcf927dcb, + 0x19f1c40d, 0xf7a729f9, 0x763b3b8c, 0xe5cf5624, 0x7ae009f2, 0x965a6d8a, 0x7f4e6048, 0x7e6d398c, 0xf76ed41c, + 0x21977f4a, 0x0d1b798d, 0xf1faf4ad, 0x38f6da61, 0xd1ebc4d9, 0xcc60624f, 0x65768048, 0x4f679f32, 0x9c069e17, + 0x3e12d0e3, 0x0154b37f, 0xe97e6bd3, 0x0c438cf8, 0x5ee6bc4e, 0x4fa229d7, 0xe9cb0d33, 0x035eed9e, 0xb2bab93c, + 0x897ed61e, 0x469533d0, 0x557a9c1a, 0xb3638395, 0x189be6f0, 0xe7b258aa, 0xdd918995, 0xa67953a4, 0xfbf07d9d, + 0x97e620e4, 0xcfcb73ca, 0x428a8c02, 0x68507283, 0x4778fd4c, 0x5603c631, 0x3106e7a9, 0xacb16c54, 0x1365d72a, + 0x8f099cdd, 0x6d7ca14f, 0x8844f218, 0x5c64cd1b, 0x1f8ae15d, 0x0b669a39, 0x1dfaf85a, 0x6c173107, 0xdf3dd29b, + 0x418d1179, 0xd0a38955, 0x5d21996d, 0xc9420430, 0xf07cd658, 0x62db42ec, 0x29b05bba, 0x6bef119b, 0xa5fe5bda, + 0xe6ee57be, 0x52d08e98, 0x9591a2f0, 0x4caa5e3b, 0x40abe906, 0x47895b57, 0x95380ae4, 0xce869751, 0x2af7302e, + 0xa0ec8913, 0x4df2feb9, 0x44b65475, 0x48e74925, 0xa11ad14f, 0xc8c08577, 0xc80e495f, 0x7e2ce286, 0x306ad7dd, + 0x00344e9a, 0x247b4158, 0x6836fe8d, 0x1ae31385, 0x89e40bef, 0xd197dc46, 0x71468618, 0x57de4d93, 0xed3580c9, + 0xdac0a83f, 0xc47fd155, 0x2bbdf62e, 0x0a74077b, 0xa2495759, 0xadad2e2e, 0xb5704679, 0x5f4b7fd6, 0xf965ebff, + 0xc02a0cf6, 0x6d15864c, 0x4cf5f824, 0x48929529, 0xbb7843a5, 0xbd3aa372, 0x9e584d7a, 0xceaba8ea, 0x9160ffb9, + 0x789e088b, 0x613f0349, 0x93698d5d, 0x0025f56f, 0xe3db8559, 0x068d6f81, 0x5eaebd15, 0x9db3695e, 0x7063b1f8, + 0x9531fb79, 0x5cda0c76, 0xd14a1dc0, 0x07734765, 0x86aea13c, 0xc5f16f6f, 0x3e9952e0, 0x109c2af5, 0x220e972e, + 0xfbdcd646, 0xc1468b76, 0x2326d32c, 0xa7b80b20, 0x32fa18dd, 0x3f437456, 0x9d24c1a8, 0x4aaa74a7, 0x4e7cf64c, + 0x8f57107d, 0xc8b6e0a2, 0xc5bfeb9b, 0xe8b29fed, 0x751599ea, 0xed3fb437, 0x0455bd40, 0xd3ef7a27, 0xa6974ce5, + 0xe165a247, 0x03b71ec2, 0xa8c99048, 0x815cb15d, 0x8f01b4ab, 0xe2040249, 0x1e0dcc44, 0x251df32b, 0xb227014c, + 0xdafe9506, 0xb12ecc5b, 0x0c18d48b, 0x5d325744, 0xb9e6749e, 0x84ae58ce, 0xfb76955d, 0x0196871c, 0x972c1889, + 0x7580c6f1, 0xce6ace61, 0x1eb98f6e, 0x878bfcff, 0x14ba6711, 0x7f7d05f4, 0xbe9aecdc, 0x64f4ba9d, 0x67cc6b59, + 0xd2fe4b7a, 0x7b7ed4c1, 0xaf59a2fc, 0x779f06ee, 0xf9ec202f, 0x01c65337, 0x5d0a8d54, 0xed1f896b, 0xae08d064, + 0x3ad69b2c, 0x97cf9747, 0xeac6597c, 0x436d51b2, 0x756be586, 0x7674e6ba, 0x6772fa1e, 0x272bce06, 0xdad41bc0, + 0x03587d58, 0x9ba62da1, 0x9896f69e, 0xd13fadcd, 0xc5646ef3, 0xc2abeae8, 0x55a928bf, 0xfc544d67, 0x942f9b82, + 0x8c037157, 0xcb45f228, 0x0aa9c2cb, 0x0669a0f7, 0x07fbf00c, 0x82b67405, 0xd6156d8f, 0x92097ec5, 0x37cf4206, + 0xbe162755, 0x490002ef, 0x4c2daa8d, 0x034ac8a5, 0xe1d28c72, 0xb3110fab, 0xd56e8a60, 0x595fe9cb, 0x410eaf1c, + 0x2089460a, 0x74282269, 0xd511dcf3, 0xbc724f4c, 0x56f909ed, 0xdaf41bb7, 0x938229ba, 0x76fac84f, 0x5b0edf12, + 0xd25be628, 0x782bc90a, 0xce189991, 0x167d734a, 0x9bbba01d, 0x19721043, 0x974be635, 0x60749d05, 0x3cc5aa56, + 0x068cfc95, 0xfe9e1395, 0xcd6d1cea, 0xfee8a05e, 0xc7a3ca45, 0x0547d5f3, 0x90ac5cf1, 0x333371de, 0x34298415, + 0x97b02818, 0x8c04a16e, 0xf16e81d0, 0xf2005af3, 0x262c5bf9, 0x02279505, 0x87472103, 0xbec1ffee, 0x7683a687, + 0xc729239e, 0x45317208, 0xf55e6c0d, 0x2ffffb29, 0x8d46d446, 0x5f9d6aab, 0x82cdffa3, 0xcc670cc4, 0xb2823073, + 0xb90e9a01, 0x007e500b, 0x8df69293, 0x912b3faa, 0xd1bd6192, 0x4597f27f, 0xcc6c1710, 0x396a1932, 0x68149ad4, + 0xeed910fd, 0x4d79262e, 0x9adde709, 0xb152db91, 0xf9b9b47e, 0xfbe815f0, 0xd769eec8, 0x8e61997a, 0x2c811d35, + 0xd0c1cdf5, 0x5c72122d, 0x61d80223, 0xeb8161fd, 0x76133310, 0x672a123a, 0x50fcc9ef, 0xb36bb35b, 0x1eb11ad9, + 0x59619934, 0x628e00b6, 0x578b6d2d, 0xeb296df3, 0xfe5eb66d, 0x9e9faecd, 0x818dc4cc, 0x15c63828, 0xf3ce3ed0, + 0xd9dc9aee, 0xf169e8be, 0xa39a8db7, 0x868032d7, 0xecabbae1, 0x6704d623, 0x72094b42, 0xfb08e935, 0x05e83e13, + 0xf8084c9e, 0xd4ef62b6, 0xcb3c4281, 0x03a411dc, 0xd826790f, 0xd248119d, 0xc8071ac2, 0xc989aefe, 0xae38db73, + 0x834fda2c, 0x34316ee5, 0x0acf18ec, 0x1bf12be1, 0x761c2328, 0x9ee89426, 0x57cd2ab2, 0xe7290631, 0x7610b4d6, + 0x19a3d8e8, 0xd6ec1786, 0xa9bd6f68, 0x3d522e58, 0xdb797ce6, 0x2f19408c, 0x999ce66a, 0x2342202a, 0xf8419e63, + 0xcd48833d, 0xc355fc02, 0xad08464f, 0x2cff2669, 0xd5d4e55f, 0x0fb98b30, 0x64827a9b, 0x01b3bfed, 0x06e6350f, + 0xdde6d0f5, 0x5f9e978f, 0xadcb5de8, 0x68ef976a, 0x9b9f2d0d, 0x679d362d, 0xf10e4d5d, 0x64fb9df8, 0x0d07ce61, + 0x998eb350, 0xd2949a7f, 0x48de000e, 0xb2829af5, 0xd069ce82, 0x88ec1273, 0xd98cd695, 0x831e46c4, 0x3c1f9e7c, + 0x3df486b8, 0xee28ffbd, 0x7170fd3c, 0x811aa0d9, 0xe6e2825e, 0xf5015fbd, 0x9e13a304, 0xc938e1dc, 0x18397da0, + 0xbb2d7371, 0xde4cf517, 0x1926465d, 0x9feb2837, 0x25984276, 0x4cca3ad8, 0xad9ca99a, 0xddc0e85d, 0xc9dc38a2, + 0xbf1b1a78, 0x09a288d6, 0x37c850c2, 0xa55e50c1, 0x361c21ee, 0x6e89a582, 0x9a151d2e, 0xc560408c, 0x98857aec, + 0x492740e9, 0x39ad7216, 0x30c6aac8, 0xcb4b519f, 0xfe9e2429, 0xc7a26a23, 0xdedaa0e4, 0xe89e7713, 0xd10ecbfd, + 0x8c7d1dc6, 0x165fbd59, 0xceea6a8e, 0x6555f5c6, 0x5ba3cd7f, 0x47c527ae, 0xec810e3d, 0x5f365dca, 0xbc464399, + 0x85b00210, 0x12825a6d, 0x4ca5bbfc, 0xe74b153c, 0x892edc83, 0xb7e93c0e, 0xf7413b36, 0x7497c5f0, 0x100725f0, + 0x528f3927, 0x6ee7fab7, 0x5d5f5f15, 0x3812dd15, 0xe407a092, 0x3ca8e0f0, 0xfde6a73d, 0xee6df2cc, 0x3e0bd682, + 0xf997ca10, 0x27def0c2, 0x5f5b66c0, 0xbb4be05f, 0x109ad48a, 0x014cb329, 0xb8642d0d, 0x1c4ae391, 0x3d89a799, + 0x18ed78b1, 0x88569314, 0x49c8e0e1, 0xc134ffa4, 0xd8627243, 0x1284a6b4, 0x8eb56e46, 0x1eb90ff2, 0xa6eab566, + 0x0fc3e6c1, 0x6f77f979, 0x599dfb6c, 0x95689034, 0xd4005e88, 0x66bf8c8d, 0xfadbb2a9, 0x8c1a5051, 0x3c68be2d, + 0x71b7cca3, 0xc5992bfc, 0xd9a56cef, 0x0a3652b9, 0x10ad229a, 0x205cf70e, 0x275b4363, 0x10a93224, 0x8cfc9bff, + 0xeb2a71a8, 0x383d8763, 0xbc642ec6, 0x79687f65, 0x3a4ecd09, 0x04235961, 0xfbe35851, 0xd11c2fbf, 0xc5a48048, + 0x7f03c52f, 0x5fff54e3, 0xc461ea81, 0x40381e35, 0xc7f0a221, 0x421fd552, 0x97b4450b, 0xcddf8148, 0x74d57a55, + 0xc2307c47, 0x0442bc3f, 0xa70f07cd, 0x9dd06e54, 0xfd09349e, 0x3e199f93, 0xef137dca, 0xf49a0a9f, 0x2b28e192, + 0x168e7e91, 0xe995135c, 0x78961ead, 0x5e201eee, 0xd19f4020, 0xc47cfaeb, 0x22466b87, 0x484f2fb8, 0x1a9ccc41, + 0x6d9998a5, 0x65bf4d24, 0xfed22321, 0x9d578b5c, 0x78a6a172, 0x5e52d296, 0x1d5b9ce2, 0x2d733324, 0x618b7efc, + 0xef5f57e0, 0x41a649c8, 0xac8b2137, 0x08ccd888, 0x7decb5c6, 0xefbb822e, 0xdd92c26e, 0xaa398cc5, 0x142dd8db, + 0x39ba011f, 0x3e224104, 0x6f9f252b, 0xf234b982, 0xbb3051fd, 0xb6beccc0, 0x8b1e2b59, 0xf13e46ad, 0xf73c9f87, + 0x07e97b78, 0xa4b147ed, 0x0df25c78, 0xb64ab008, 0x8894e294, 0xd984fd66, 0x98fb0790, 0x23b216e2, 0xc0adcc0c, + 0xa8703838, 0x9d6c7d1b, 0x2a7158e0, 0xe3608895, 0x35d56981, 0xc6b2ec64, 0x09a1542e, 0xa194f3c7, 0x4555a769, + 0x06d403cc, 0xd518eb7f, 0x2830cf6b, 0xd76099a2, 0xb71a2bf6, 0xc1f9b62d, 0x98a97dc8, 0x882eac4f, 0x4db20463, + 0xf5d2edbe, 0x119ac49d, 0x8ffc60b1, 0x852cb289, 0xd35c2d90, 0x1b9d5ef5, 0x26db50ff, 0x3e8625bc, 0x01fae535, + 0xa6d98699, 0x9bede4ff, 0xd080789c, 0xad58515f, 0x7eb348e7, 0xbb60accd, 0xf0edbb7f, 0xe7ca1bf0, 0xacd1bfb5, + 0x6d7d023b, 0x0a87fdf0, 0x5bfee236, 0x605bde30, 0x8018d0b0, 0x150b991f, 0x26852c8f, 0x8e534fd3, 0x4ebc0686, + 0xbe781e84, 0xccc47461, 0x36977732, 0x6bc15b0b, 0xd49c9163, 0x53667679, 0xf03d1e77, 0x1bd7a45b, 0xb1049e8b, + 0x1a7c5071, 0x571daf37, 0xa6c60310, 0x51b13cd8, 0xfb7b14ba, 0x011ce85a, 0xf1b3b478, 0xe6d1bbbd, 0x7f5290a6, + 0x3ab22116, 0x2e2680c3, 0xab10a18c, 0x708713d7, 0xcdd78512, 0x19316d7e, 0x482c8e7b, 0xe3bdbae1, 0x8b7fe22d, + 0xfbfab193, 0xa26a8578, 0xd92f2ab1, 0xee0c08bd, 0xb7e83419, 0xaad830df, 0x72f3229a, 0xa6e7ddfa, 0x47fb338e, + 0x2408fa00, 0x6c07418b, 0x6e5b9b2f, 0xd5420df3, 0x000bbf63, 0x31acc30a, 0x351b98cc, 0x91872724, 0xed51cd24, + 0x825f2e3f, 0x5eac2db3, 0x05b65a8e, 0x7ef6278d, 0x908bcc81, 0x78ada6f6, 0xc7ff8bab, 0xdf526ca9, 0x3a504ba8, + 0x84207e6c, 0xaf4f205c, 0x11b31ebe, 0x7ea1930a, 0xf682e8ce, 0x4710d75b, 0x57c3d7bb, 0xd405c66c, 0xf6d04fe4, + 0xa29b88ad, 0xb7079c4e, 0xe0c992a2, 0x2e99f959, 0x9050c162, 0x2ccd7ec6, 0xf89cde40, 0x8753b487, 0x8797967c, + 0x0452d14c, 0x74af66ea, 0x98aa528b, 0xa3c2c8fe, 0x80bd5c70, 0x13f22f49, 0x42fcd7f9, 0xb51d6307, 0x59fe8639, + 0x2b1620c7, 0x6359843d, 0x81ccfe24, 0xfd27f46f, 0xc7be90a4, 0x5c839f2f, 0x80e64420, 0x0df246cd, 0xc95a6f36, + 0x403754ce, 0xa0f09d14, 0x3e0c253c, 0x6dec9221, 0x47c37669, 0x7f2977cb, 0xb97652e1, 0x9c853d12, 0x989c679b, + 0x1b13ddd0, 0x0cf7ade8, 0xf9c8448d, 0xf09e5a42, 0xd78d86f4, 0x48a924fc, 0x2745268a, 0x671f14f2, 0xd1151823, + 0xb749fb51, 0x606c314d, 0x42665ed9, 0x5143090a, 0x65bac503, 0x8cae14d3, 0xf72ef6d7, 0x77f6daf9, 0x3dab3bde, + 0xc7fa614f, 0xea328f38, 0x9dbef135, 0x429dc065, 0xd76dac8a, 0x50b1a197, 0xe3063fb0, 0xa10aab03, 0xebbe2db3, + 0x7a0d6743, 0x6324bc97, 0xb42f9690, 0xd7fc5191, 0x742b87b1, 0xe9468a86, 0x1dd27f29, 0x451d8798, 0xf242f17f, + 0x94f76c19, 0xe2c03114, 0x31366bc5, 0xc395a099, 0x8df23ecb, 0xd6ce1c53, 0x34ad3c19, 0x4e140a7a, 0xecc2c1a1, + 0xd33cbf0d, 0xbca52217, 0x1980cf68, 0x01ee6da3, 0x4e3c7a09, 0x2d89049d, 0x3ea58b7b, 0x2bb2c69e, 0x9dfa60ec, + 0x4b009e08, 0x90f40c09, 0xe96dfc09, 0x4d542a13, 0xdbdc7de6, 0x62276374, 0x34a01fc7, 0xe916168b, 0xf02c8e7b, + 0x96bd7d3a, 0x8afeae38, 0xfa785c65, 0xce7d6dea, 0xa7b47d9b, 0x602ca3fc, 0x1a914b3f, 0xd3affa74, 0xaa533915, + 0x80518a16, 0x4e28b51b, 0xfe0aaf45, 0xf1f5e166, 0x12f4cbdd, 0xd74bff7a, 0xa4b9a904, 0x594f109f, 0x3753b151, + 0x5f61855b, 0xbddc4203, 0x2633870d, 0xaf789f81, 0xc9882511, 0x7d92c205, 0xe261c780, 0x56096e2e, 0x3a1e261e, + 0xfc17badd, 0xca0d01ed, 0xdf8e7eb6, 0xd5cb77e4, 0x36499ecf, 0x33346e74, 0x36bf6409, 0x877be3ec, 0xaebe9ef1, + 0xb552d301, 0xc3e20991, 0x010bcb52, 0x9a9eeae5, 0x2e0a805f, 0x728c2459, 0xed881bdd, 0xa179d412, 0x11fe6699, + 0x3f8ea38a, 0x08adc7f7, 0xa4866657, 0x212f8aea, 0xa3816db6, 0x682872e5, 0x14fdbeba, 0x86208675, 0x82aae081, + 0xc77ff249, 0x7cce1acc, 0x28a41d1c, 0xf310c59e, 0x25672f3c, 0xcd23fb11, 0x1c319d0f, 0x4c6876c9, 0x9de64ac4, + 0xf45f0ee8, 0x125975fc, 0x94ed329c, 0xaa73e8c7, 0xcb22d98c, 0x7a6fce5b, 0x94cfcc35, 0x37dae1ce, 0x7f3b855c, + 0x73726997, 0xf1517dc1, 0x24f4c4f0, 0xeea1c086, 0xaa984412, 0xfa540a8d, 0xec5ef9e8, 0x1fe079c4, 0x2a9eb4bb, + 0x9fa42044, 0x1f2c187a, 0x7655a289, 0x89913c01, 0xe488b6f8, 0x47e2494a, 0x23952a27, 0xdcea18a4, 0x661c1d81, + 0x1094b204, 0x7371c8d9, 0x06c84f54, 0x0d432aad, 0x08c9332f, 0xb5fbef97, 0x29cc713d, 0x424ef9c4, 0x1d5ea9ad, + 0xc9f5224b, 0x058d026d, 0x6e33cb8c, 0xd531fe85, 0x1c95775e, 0x1a0da36c, 0x95dbeac0, 0x5ff6c17e, 0xea9f7ebf, + 0x6b04d7c7, 0xf993fc84, 0x6d3cc0d2, 0x2cbf9ac8, 0x6890e900, 0x4cc9825c, 0x3a5623ee, 0x4eb72727, 0xc37fcc97, + 0xc8b1225c, 0x3b786f3d, 0x919be349, 0x5f9c807a, 0x9e15ed57, 0x1c698a3f, 0x918a2232, 0xa0099c4a, 0xab91963f, + 0x1a91a66b, 0x67e7e7e2, 0x7651eab5, 0xd3e2c5c4, 0x36583a65, 0x52e0ec92, 0x634b4dc6, 0x61b70779, 0x8225fd19, + 0x4f098cd4, 0x07a3b3e0, 0xbc730ac8, 0x4aa5e1b9, 0x2c6d541b, 0xd4970805, 0x20dfacff, 0x91e4e73d, 0x1179de7b, + 0x66c1a336, 0x074336c8, 0x4e96f65c, 0x122b6ca4, 0x64716ede, 0x1d843a95, 0xd728b29b, 0xb57365cd, 0x1749c65a, + 0xa5256f87, 0x0912d92e, 0x09457bff, 0x739f1e6f, 0xffbc6a3c, 0xabf7a8c4, 0xb4a0abf3, 0x66a701db, 0x7ac2b6ef, + 0x89dd31c0, 0x6cd5423a, 0xa6a03f78, 0x288916e6, 0x91070146, 0xf267431a, 0x6827ba23, 0x74375c91, 0x3f1b21a2, + 0x179eaa0f, 0xad7dc16d, 0xcad8bec4, 0x6a1a2eef, 0x50f9ac6d, 0x9c2700b2, 0xac51ee49, 0x7dea21cf, 0x9ccecadf, + 0xb2b2740b, 0x142dc5e9, 0xefe4bae2, 0xfc4a1e3b, 0x93990ea6, 0xdb32b656, 0x5dd4f053, 0x5b79d8ea, 0x57f5063a, + 0x09056672, 0xdd5ae19f, 0xec93cc66, 0x4950cfe5, 0x4b0bcb6f, 0xedced51b, 0x9edb3dd5, 0x2570be71, 0x3b846197, + 0x36768934, 0x58907cd6, 0xb7010a31, 0x497ebeda, 0x39690ec6, 0x135120a8, 0x80ef2809, 0x85b9918d, 0xf3ebc7ea, + 0x8dc1f8c4, 0x39700976, 0x20f37c85, 0xf56efb3a, 0x9a74a02e, 0x7cf5dfd6, 0x6c9c2fee, 0x2b0d8174, 0x028bd285, + 0x06ee3650, 0x83c2fdfc, 0x56634a7c, 0x8b9dc64b, 0xbde0b75c, 0x15dd5797, 0xab5428d1, 0x3dbb304a, 0xe89d1f62, + 0xb1a91b4f, 0xe8609def, 0x328e4b22, 0xd4d44032, 0x47e3ac44, 0xe76f8014, 0x93bd1bfe, 0xf5211339, 0x0614e911, + 0x55969e77, 0x9fb24dc5, 0xdfc92111, 0xdb38ff03, 0x7462be34, 0xd921290b, 0x566d002d, 0x793aa780, 0xdb389c0b, + 0x393a86e7, 0x198afe11, 0x2877669d, 0x674a37aa, 0x1896b5e3, 0x1d1d41fa, 0xb64f4701, 0x1e32d4ea, 0x580ac856, + 0xdb62d2b5, 0xdf1a2e32, 0x6c300361, 0x5e7e0e18, 0x0d29c988, 0xd82c1ec1, 0x7ec54a79, 0xaa42b606, 0xb55dfb66, + 0x9f822b8c, 0xaf48e9cb, 0xeb31e99a, 0xffcf1540, 0x038becf9, 0xd440a976, 0x1d70b101, 0x7b79b103, 0x0eef4351, + 0x5ce43008, 0x099e4681, 0xe15e60c6, 0x72585504, 0x338caca9, 0x04d2afb6, 0xe435b893, 0x9f73ba2f, 0x2b5f4ec9, + 0x8bfc6442, 0x0e40cf00, 0x07e23fdd, 0xb094dda7, 0xb4c78e5e, 0xacae3c47, 0x0577e387, 0xdc8ff4b0, 0xc7b06ef0, + 0x8c074d84, 0x9725dfd8, 0x49553889, 0x7aff22fb, 0x8e9c5e97, 0x73439694, 0x3838a9b8, 0x24cf201e, 0xcb6d01f5, + 0xff499fe0, 0x56c5b1c9, 0xb6d92927, 0x5f94f335, 0x66f3afc9, 0x444a4042, 0xb679d7b9, 0x4975f5ed, 0xe1dde1c0, + 0x341b5654, 0x3acafe57, 0xc78eaba5, 0xfc41546a, 0xd698ad64, 0x5e26514b, 0xe0c1228e, 0x4c2dffa5, 0x77f65c86, + 0xd4f38fca, 0x122816cb, 0xdab89edd, 0xb4783b5f, 0x7cbbd90c, 0x60a48e8a, 0xdb089984, 0x7f6a3d06, 0xd09016ac, + 0x7596745b, 0x6f3173ae, 0x13e769ff, 0x6e1d720e, 0xd4bfbad7, 0xf87332ad, 0xcbb9ff3f, 0x00131acf, 0xe1cfd1a6, + 0xc2d39dff, 0x2f0d18fc, 0x4711aa71, 0x3e59dd11, 0x8bf74321, 0x41128b5a, 0xd66c9795, 0x7501123e, 0xb4a7ae78, + 0xbfef3fae, 0x1f8e1d6c, 0xf04b86e8, 0x66e0ec53, 0x3cc344fd, 0x94b94636, 0x50c28676, 0xaf46a237, 0x9ad67c51, + 0x8dca36e2, 0xa1286ce3, 0xd837d846, 0xfeca4bf5, 0x18a9c5e1, 0x39e93de4, 0x3c107e58, 0x313e8239, 0xabb21544, + 0xa0cde34a, 0xca698500, 0xf5154d2a, 0xc6834c7f, 0x1aeb101b, 0x86424565, 0x3656df58, 0x37b10542, 0x532c0ecc, + 0x9b5a7bd4, 0x8d127cc7, 0xfeadd57a, 0x25682b6b, 0xc8e82ef7, 0x7ddd2935, 0x1ed3d53e, 0x44086059, 0x320fab56, + 0x753df4ad, 0x5f99b9d8, 0x6da7e201, 0xbbedf958, 0xe645d821, 0x517ae0ad, 0x1689b6e4, 0x47e7af13, 0x96954ae6, + 0xacf3f873, 0x443ef115, 0x5400796f, 0x8aef422d, 0x1bf605be, 0x0d5c3963, 0xf51f68dd, 0xf8922ad5, 0x2476e5ce, + 0x12ce043f, 0x73d69f79, 0xa979b164, 0xd1cd0391, 0x6d196ab3, 0xa956e195, 0x198b13ee, 0xe824a7fa, 0xb2538e3f, + 0x613524eb, 0x4851da77, 0x3a1ff8e5, 0x612adaf5, 0x6bdbf253, 0x0cc26d4e, 0xba3e8386, 0x1c78c902, 0x2dbe68c4, + 0x1a128d87, 0x29c1f24d, 0x6f919a9a, 0x6580ddb8, 0x20a160dc, 0xa4d5f8e3, 0xe820705a, 0xe0c8868a, 0x6fc166c9, + 0x925ac5a4, 0x019aa83f, 0x737b037e, 0xdec9c071, 0xe4bf8ad1, 0x67b87c3c, 0x46f9dcc0, 0x2e5880ac, 0x16ff0fc1, + 0xf48896e0, 0x150715b7, 0x65c24c86, 0x5b12475b, 0x07f7d08e, 0x1338eb5f, 0xf5175098, 0x0e818d43, 0x7771f9d8, + 0x51032866, 0xd548b766, 0xec3bbca8, 0x053d247b, 0x482d70c9, 0x9011cefb, 0x83da4dfc, 0x8bf7a97a, 0x1f31d3bf, + 0xed985463, 0x38f36c72, 0xb61ebff5, 0x5a84a79f, 0x3320c9c2, 0x313eabe7, 0xa227d416, 0x45fd696f, 0xcb4b2eb2, + 0xd603a2cb, 0xba0a5777, 0x5197b578, 0x6a3bc844, 0xb3225581, 0xda294ed7, 0x0eee22ad, 0x348f3e25, 0xc72fc545, + 0x23511d03, 0xe556c143, 0x98d64609, 0x8a5520dc, 0xb0ca02d6, 0x0947d39a, 0xa55d8722, 0x1f4990bc, 0x29fb7453, + 0x3233a386, 0x0a6f467e, 0xd2ebbb81, 0xa97d2cd2, 0xca07dafe, 0x526404e4, 0xbf751fec, 0x2e621156, 0xf068d0b2, + 0xa8ed8179, 0xa71b21b0, 0xf12bc8f0, 0x666fc97b, 0xb5266f40, 0xbfa1495d, 0xac3ee3bf, 0x027620da, 0xd3706ae4, + 0x66c8ba61, 0x33b1fb15, 0x85626041, 0x91266215, 0xd91f122a, 0xa32fa7e5, 0x9c91356d, 0xb35b1ae8, 0xaf6aeca5, + 0xad113e77, 0xae40315e, 0xf78e96e2, 0x6a45c692, 0x2a625e95, 0x397aef99, 0x8e894fdd, 0xb9a4542a, 0x9299a7f5, + 0xa664cf0d, 0x191e3ea2, 0x8d919b2d, 0x733129e2, 0x68031e6a, 0xb24a2171, 0xb5d4d04f, 0x0a331221, 0xd5974e04, + 0xcae4623f, 0x556a5d20, 0xaa7910a7, 0x45a47dc9, 0x3f5eb540, 0xda992daf, 0xba275de4, 0xbc4a323f, 0xb849db21, + 0x02cd7445, 0x6484514c, 0x887b9e4f, 0x79273561, 0xb9628332, 0xa1ceccb0, 0x61b50a59, 0x4ccd3096, 0xb223c455, + 0x05f9c4b4, 0x05528d69, 0xe82439fe, 0x8dd27cbb, 0x0fdee409, 0x6f2af46f, 0xb1788a69, 0x2562d7af, 0xf5268d6a, + 0x1f0c8bd3, 0x41c434b0, 0x7717e3a5, 0x65b4d72d, 0x1bd9715a, 0x6f014718, 0x6d8e4ce6, 0x524cd17b, 0xe9ce3485, + 0x2fda546a, 0xdab4b0ff, 0xb42a1593, 0xabefe7c9, 0x158b592b, 0x5eca4a69, 0xb9a5fdd6, 0xb4a0f597, 0xd254b90b, + 0x9a64437e, 0xd90e50e3, 0x88d845ac, 0xe7b784d9, 0x7d8a9360, 0x65d38d6e, 0xe7b1e913, 0xf8464a33, 0x183cd765, + 0x74e43e40, 0x48de84e4, 0x8deb12ba, 0x7903eec9, 0xc6a88e1e, 0xd22a2a01, 0xbe43568d, 0xee32e2d9, 0x95ccfba4, + 0x10d350d0, 0xf28db2ee, 0xfbbcefa3, 0x82d9641a, 0xa2bd971b, 0xe2034b0c, 0xcdde5cd8, 0xbded1c30, 0xa9b8e301, + 0x220e29fd, 0x368d8c2c, 0x7d461874, 0xc2fd59bd, 0x78529549, 0x25dd6c1b, 0xd53e84d5, 0x213aa71a, 0x2c2872e3, + 0x492ba4b6, 0xba2ae9e4, 0xd4b9de91, 0x62c527d5, 0x11587462, 0x3bea7244, 0xf4500b7f, 0x795133d8, 0x041bbb34, + 0x312bc129, 0x69f67a3b, 0x147cc6c8, 0xb01eb1f3, 0x743a0f7d, 0xe4a0aa57, 0x7d7c37a4, 0xeabf9238, 0x6773b4e9, + 0xeb36c98b, 0x698bb887, 0x8bc0a16a, 0xca08fa7e, 0x4d53400c, 0x3018c7bc, 0x73275ffa, 0x42d6799c, 0x52cb4715, + 0x51668e83, 0x13acf0c1, 0x171fb2f9, 0xb0d49706, 0xed2a957c, 0x65620114, 0xcc2af8f5, 0x565a7a7a, 0x4616413b, + 0x66490d2a, 0x3a802a26, 0x97861613, 0x5a6e2409, 0x6c5e0abf, 0x82bc2d72, 0xc7f864a3, 0x292035a2, 0x85c5cb80, + 0x4dd98a1d, 0x2047d2b1, 0xa7ef0631, 0xa51d7c95, 0xf00bac7a, 0x85f073da, 0xd471c6a1, 0x5f5fcc39, 0x48cb2026, + 0x01aa3c5e, 0x267fefdf, 0x1885eaca, 0xf35f8f75, 0x6df871e6, 0x4662194d, 0xb402ee84, 0xdafea7a9, 0xfd28e311, + 0x3266fd4b, 0xd953d31c, 0xef5c634b, 0x61201db1, 0xd0029f14, 0xe1214269, 0x0c6a3813, 0x832beebc, 0x174e50d3, + 0xd47b2dc2, 0x566215d7, 0x735ec08e, 0xab3a7b48, 0x329fe843, 0x08ba72f8, 0xc079befb, 0x996857fb, 0xea735558, + 0xc6074508, 0x87534efc, 0x05d52a0b, 0xfaa89962, 0x2d67b4a1, 0x0bf0c33e, 0xd562405c, 0x52e9f2d6, 0x447b16b4, + 0x598c75fc, 0xeb57a259, 0xb265f7be, 0x9cd5432d, 0xd000142e, 0xf1219363, 0x543a58bc, 0xf95f1ed2, 0x5eaea2d8, + 0x4a24fcca, 0xa932beb9, 0x70b59128, 0x5b43a8ff, 0xca3067ed, 0x81f25684, 0x4fcca2b7, 0x56393f44, 0x62866b2e, + 0xe52fd26d, 0x92771695, 0xc5d76102, 0xb416fcee, 0x09d0db9d, 0xde1ba6ce, 0xf84de9d6, 0x51101bea, 0xd564afdf, + 0x4cb6070c, 0x3c7f0d7f, 0xd0b601c4, 0xfe66046e, 0x26f11972, 0x39c4e81d, 0xefcb9601, 0xd8861905, 0x2b16a0d1, + 0x13906d66, 0x701bd322, 0x52506c74, 0x0d69f907, 0x81214e24, 0x8b49de6f, 0xda381e96, 0xb10ce209, 0x0ccd27d8, + 0x35950d67, 0xf2e4cde8, 0x06606d3f, 0x58d8fc81, 0xae0c1932, 0x7e896a97, 0xab4a1492, 0xb21ff91a, 0x2d591334, + 0x00fbe3b0, 0xbc191e9e, 0xa14d47ee, 0xf9ebf30f, 0xa1cf9e0c, 0xb3bece19, 0x26f1feed, 0x4fff8cc0, 0x6b19ef8c, + 0xec74a19d, 0xf49f75e0, 0x88c289b7, 0x7270ad4a, 0xc01695a0, 0x25bc4776, 0x879ac096, 0x00fa071f, 0xe9884f9a, + 0x58b49ca4, 0x7929e096, 0xd3182b40, 0xffcda776, 0xc4c515eb, 0xab32dd93, 0x152bfd90, 0x1e7c585b, 0x103c633a, + 0xd56330ee, 0x169bab4a, 0x63491d07, 0x4d70d717, 0x79502851, 0x4439b4dd, 0x32487852, 0x012f726e, 0xd4983674, + 0x9f8fddb6, 0x28bcb74b, 0xc91a62f3, 0xb5463f34, 0xa61d23b3, 0x00fb4492, 0x7410acbc, 0xbbf7b2dd, 0x672d5683, + 0xfe8514b2, 0x08077d85, 0x024c5678, 0xd165b4ac, 0x7b333034, 0xd61942ce, 0x73c7f6d1, 0xa3398135, 0x5d82dbf6, + 0x156bcdb1, 0x2ad8819d, 0xf334a74c, 0xf06010f0, 0xc38d3820, 0x8d22a6fa, 0x42595de6, 0xda753c10, 0x9ffa6903, + 0x7b48eea3, 0x137405d0, 0x909ad5a7, 0x5b9bb837, 0x88dece5d, 0xf6ef07a8, 0x5f432dbc, 0x4726688e, 0x7969091a, + 0x1cd56d0c, 0x889d2888, 0x1a96998f, 0x88fa1036, 0xb9eb08ae, 0x7514f178, 0x4fc7eed6, 0x090fa4df, 0x28f18ea8, + 0xcc488404, 0xb52844cf, 0x7f41dedd, 0x6847ad07, 0x41519445, 0xf279df4b, 0x22fd3984, 0x622e9907, 0xad8ffba5, + 0xc9fe5642, 0x51120d8b, 0xda1f721c, 0x5925f0f0, 0xc106503e, 0x03a6bdb2, 0x3c0e7196, 0x44cc440d, 0x8621210f, + 0x00352227, 0x6e5c1fce, 0x7f0c4a01, 0x0d2ec81d, 0xcbcec0e0, 0x3a82382f, 0x96394781, 0xbaa6ac9b, 0xa2169463, + 0x3ac50e58, 0x030828b2, 0x0716643d, 0x71e8ba04, 0xddede156, 0xffa7b13a, 0xefffd7f4, 0x49f62f36, 0x20b4bc10, + 0xd917c672, 0x01b3f573, 0x90ab221d, 0x300f4583, 0x8eafacf2, 0x464d212b, 0x65698824, 0xc3658dfc, 0x25dd9afc, + 0xe8408726, 0x937bad90, 0x4649604b, 0x2a842a17, 0xe44c8810, 0x9f8cce9f, 0x9a8589c2, 0x1319fde5, 0x1f13ca75, + 0x1650a6c2, 0x6d147823, 0xbab0d4b7, 0xc2c50f4e, 0xa82cfe26, 0xd7ab2755, 0x1f83311c, 0xa7717ece, 0x9d2da803, + 0xbf83f1a4, 0x7f35d12f, 0xe2f05b8e, 0x458242d8, 0x0695b162, 0xef12b349, 0x66fbc114, 0x5906a71e, 0x6a3a49e6, + 0x19a65780, 0x14a1d541, 0x6240bc3c, 0x562c8ea4, 0x481c313a, 0x8e0eb416, 0xf0c13e3c, 0x8ef975b7, 0x9d90b557, + 0x6bf20ed8, 0xc57058a7, 0xa5d27ceb, 0x7feeaf61, 0x3b5e6e12, 0x31727ff2, 0x8f62dbf3, 0xa685657b, 0x22bb8e97, + 0x9244a792, 0x85974138, 0xf7702b8d, 0x80bb945f, 0x2a34e810, 0x16b1cd91, 0x98a19c4c, 0x6cfd58f4, 0xbfd9ff86, + 0x2920b0a9, 0x6295bc40, 0x8d56be55, 0xc70ffb9d, 0x52001dd5, 0x41fde338, 0xd28ac441, 0xf567d542, 0x1e4b8d71, + 0x00e4ce94, 0xcd12e22e, 0xc04bed80, 0x6c8b50a3, 0x8f425362, 0xafa819c6, 0x5d99526f, 0x97507877, 0x902e6e2d, + 0x10cf7091, 0xf09b19a8, 0x9c43ba7b, 0xf290e6a1, 0xfc62054b, 0xeb85a5da, 0x9244a6c8, 0x961c3339, 0x685538b1, + 0xaa49913d, 0xc250f643, 0xac0cdd3c, 0x220c26df, 0xd3dbbbc7, 0x8b9bd927, 0xed58f0c6, 0xf1f8045a, 0xe13380f7, + 0xa1246b04, 0x4e5fa7eb, 0xe2430a57, 0xee8a3075, 0x10445e8a, 0x18cef242, 0x0cf70b7d, 0xd10206ae, 0x7e2597d6, + 0xa12c9d6b, 0x028dc8f5, 0xe42c320b, 0xc1efc2b5, 0xae4abc3b, 0xaaa9f9c8, 0x509d0776, 0x2cb41148, 0xa2400f97, + 0x2541421b, 0x2b949a50, 0x60e1fa2d, 0x4efedd28, 0x1d0cf7a6, 0xf3ef9a54, 0xc89c32c8, 0xbd652d6d, 0x8e788d80, + 0x9a2ed6b5, 0x113ab17c, 0x93b8931b, 0xa47b46fe, 0x0d4c115a, 0x91dedc9b, 0xc3d57b98, 0xb1d5664e, 0xf8b479ae, + 0xa6041b67, 0xc3b567c4, 0x7f93ce49, 0x8baa7eea, 0xf8485993, 0x17675dd4, 0xe472419c, 0xf59e1a18, 0x75ec1552, + 0x989576fe, 0xa686b795, 0x2cfd2ab7, 0xdcf6379b, 0x9d8112a8, 0x2f005587, 0x1fa5427f, 0x0890ca24, 0x6ac483b4, + 0x3c460b5f, 0xa4f7fbc7, 0xf8a9ddf3, 0x387aae50, 0xe2ae7656, 0xb47b011d, 0x0abb9193, 0x556a155d, 0xc1f630eb, + 0xb3fa713e, 0x0bdac8c3, 0x36718bff, 0x35e8419d, 0x7f2e0e44, 0xb879e4f6, 0xbddccce5, 0x9cb8728a, 0x64f42385, + 0xe7b52f16, 0x3eff565e, 0x5b76b7b3, 0x5fe6db9e, 0x9ecf08dc, 0x8e7bf9df, 0x826f52bb, 0x0d60f28d, 0x7ca53a04, + 0x08236fe5, 0x548d90a9, 0x5d3696c1, 0xca5452ae, 0xa7a82707, 0x91452d8e, 0x00f707ca, 0xbf66e40a, 0x90574a08, + 0x001922f9, 0x924a99f7, 0x86c8eb67, 0x062129c8, 0x73dbbecd, 0x14bbc6c8, 0x0a9bbb69, 0x6a37ca9b, 0xba3a092f, + 0x62956e5a, 0xd273b513, 0xf484d694, 0xd1bc0a26, 0x33b3cedc, 0xaa002a18, 0xbaa0c329, 0x941f9974, 0xcebb6d55, + 0x7f5e8fa9, 0x0b6963e8, 0x8aa9e6a3, 0x828c0dd1, 0x12321b13, 0xa3382c67, 0x89375b05, 0x50604f1c, 0x49528cee, + 0x21adf9e7, 0x603d94a6, 0xedf8f453, 0x3ea2fcee, 0xcbcd8961, 0xe3a262ca, 0xc04dd1de, 0xe7f958e8, 0xe3975aa3, + 0x130e3350, 0xb7e521de, 0x81da5d83, 0xe38e55c4, 0x42f9cb5c, 0x3fd05997, 0xef87198e, 0xa2ead839, 0x5c21e1a7, + 0xbf8275d3, 0xf88cd343, 0xb55a1c68, 0x2a2c62f3, 0xcfc827ec, 0xf648d67b, 0x6027d8bf, 0xc4c2a85f, 0x62a79771, + 0x6016e168, 0x8e903ed0, 0xae62f0ca, 0xade06be9, 0xb6fa0b89, 0x0dd5d66c, 0x202ec05c, 0xcf9cdacf, 0x087c2911, + 0x6c55c669, 0xc9e2de32, 0x5e5f4851, 0x22cbbfb7, 0x91901b02, 0x63a06dec, 0x29d8ab4f, 0x1e641288, 0x835581ed, + 0xa6d293e8, 0x3ce7de58, 0xcc35d6e6, 0x7ce7f218, 0x8e7543b8, 0x52001724, 0x3370db5e, 0xe7de4f2a, 0x00de7cfb, + 0xfec11df9, 0x6ad0b8df, 0x57442f83, 0x421bda93, 0x3e62571d, 0x1efeb4aa, 0xfdb8edab, 0xd269a93c, 0xa935a7d8, + 0xf6934ab2, 0x474c8d34, 0x04fa4751, 0x17ac1286, 0x8faf0d67, 0x270d500f, 0xa601dc1a, 0x7ace146b, 0xe3e6bfcb, + 0xa29cc42f, 0xfdb82472, 0xfee652e3, 0xa4e4c7fd, 0x91d75fe6, 0xab8baab1, 0xb3a51e4f, 0x07353a3d, 0x92e3b257, + 0xe7737dc2, 0xfba948e3, 0x2667379a, 0xaed2008b, 0xc6c485c9, 0x3dea0291, 0xb27c624b, 0x1265f04d, 0x7c53a5bf, + 0x781d0e27, 0xe05081c0, 0x8a7d60f5, 0x87b4497d, 0x75684c8d, 0x331a9e94, 0x6dc4d90a, 0x4a9ad248, 0xc430067a, + 0x4da7c7b5, 0x74cbee2f, 0xd70117bb, 0x3ca0bfda, 0xc6ba1bb8, 0xe22903f9, 0x8d0e6347, 0xe2bc6557, 0xc0dc5806, + 0xd722b793, 0xa1b5efeb, 0x1176a2be, 0xd8dce7f7, 0xe0630962, 0x1a3972c8, 0x3ce48cfa, 0x2f58437a, 0xc1df23dc, + 0x4eb14a23, 0x581046d1, 0x6bca5842, 0x0f274783, 0x8b0f0a61, 0xdbab7c47, 0x2a217351, 0x85f98334, 0x6cf0e3ad, + 0x03b27948, 0x202e45b0, 0x3f17e552, 0xed9d26e4, 0xb05d64cf, 0x36729714, 0x216c6fd0, 0x77c9c4f8, 0x80b664c8, + 0x25b502da, 0x5a26cf17, 0xb83afca3, 0x500937e2, 0xb380f2b8, 0x062360b6, 0x8477f313, 0x086a712a, 0xf24e6c2a, + 0x9de2664d, 0xf5f66442, 0xb3ebff8a, 0x8fab8041, 0xf0656b6d, 0x3116bafb, 0xe1729ed7, 0xc43c9923, 0x96903da1, + 0x4656433c, 0xdd07bdcd, 0x54e0d174, 0x66d2c84c, 0xd05a4757, 0xf4a49f1f, 0x322828ac, 0xac747805, 0x21d67968, + 0x20f1c0ed, 0x9a77e36b, 0xa08f0394, 0x4cfe743e, 0x52df135a, 0xc58dbaa7, 0x42c82d12, 0xfafbde23, 0x56ff5b92, + 0x5da40d28, 0x917128bb, 0x85e8bb54, 0x650a9a28, 0x796fabfe, 0x068ca6ba, 0x52e64205, 0xb5f50432, 0x123fc94e, + 0x54f3154f, 0xc033c71a, 0xa5927426, 0x4dbb0db9, 0xd47b1e7d, 0xa353b605, 0x94aaa996, 0x15ba75d9, 0xd9e7d603, + 0x7f0773be, 0x82bc4c73, 0xa981ec0e, 0xc7f25b15, 0x3e370aa3, 0xfe97775b, 0x86d10134, 0xfbaa7ff1, 0x971c87b8, + 0x52b0db39, 0x38a25971, 0xd9b13564, 0x2578fc47, 0x8068ece0, 0x60a14ce7, 0x1365e025, 0x15c895b6, 0x0df87889, + 0x68d99118, 0x6b5fef7a, 0x603f4eed, 0x87e26338, 0x5698bf12, 0x2b808347, 0xeb0f4657, 0xc7728d1b, 0xffbf1620, + 0xc7bd9e92, 0xc656b42a, 0x56061729, 0x8232d6f3, 0x416ccd13, 0x304b1f7c, 0xaa92590e, 0xba6aa49f, 0x526804de, + 0xae14f2de, 0xe930abef, 0x091d51f8, 0x072dda2c, 0x7a525463, 0x99bb94cd, 0xf758fc8a, 0x7950aad4, 0xa55d2ff0, + 0xd88133d1, 0x775f26d8, 0x23f3bcbe, 0xa5fd1c4a, 0x745ed83c, 0x327c39af, 0xbcb4bbcc, 0x1f76285a, 0x730ba40c, + 0x98409a71, 0xb03ec802, 0xb192760c, 0xbe78cd65, 0x3afc5751, 0x2e0dd937, 0x69642d24, 0x1b9143fb, 0xe82ff8d1, + 0x3e5e7d7e, 0x5d1426ca, 0x6b51334e, 0x37e6694f, 0x5493496a, 0x2e00c1e5, 0x500a81dd, 0x8576a65b, 0x9c858b7e, + 0x0a2f60fb, 0x8295ad5e, 0x3c85c517, 0x62fdea87, 0x7b8728dd, 0xcbe466ec, 0x72cca803, 0xfd3fa6d6, 0x0d65ef70, + 0xb5bd47ab, 0xa20767f9, 0xcc1afbf5, 0xb6d872ce, 0x5500ce2b, 0xa0d37e15, 0x8449a9da, 0x663a6917, 0xf2acbc9f, + 0x8dc35e60, 0x48bece69, 0x0f4bc104, 0xc92399ef, 0x794ec4aa, 0x87920c62, 0x3aa72f4e, 0x3da09042, 0x70737f97, + 0x61392cd5, 0x6a08a7eb, 0x91b24f2d, 0x4c9b17e6, 0x91884bcc, 0xdb2dc676, 0xf72455dc, 0x00112ded, 0x5b22efb7, + 0xa1091da1, 0xf8dbf24b, 0x7c050165, 0xc17f46d6, 0x049d5aad, 0x69776fa1, 0x0f406928, 0x7d5ee1a3, 0x10674d6c, + 0x8a36a9dd, 0xdfa11ea1, 0xcd66273f, 0x4d3e0dba, 0x2326be10, 0x8085b7eb, 0x86a5815a, 0xd6a9c078, 0x1dd6862a, + 0x96e28abc, 0x5997e120, 0x0c7007d9, 0x20e8d00d, 0x4b62fbe9, 0x50db5e9d, 0x4293ec2f, 0xc7f5a5dc, 0x30b62657, + 0x06562d55, 0x34d8345a, 0xd9ca6047, 0x202b2d18, 0xb7410d54, 0xd35590d4, 0xd9624e4f, 0x566086d9, 0x0ba98c0d, + 0x2d257cee, 0xdcbe826e, 0x3d513172, 0x87d29463, 0x25fb0816, 0xc51ed43c, 0x0213fc75, 0x0b95c35a, 0x678f9b00, + 0x5be955ed, 0x5b6098f2, 0xdafd1e44, 0x59e46644, 0x6631c795, 0x50f1cb7f, 0x92ae3940, 0xd4a0c285, 0x331496de, + 0x25bd034a, 0x3403aa9a, 0xdab1f36b, 0x86244de3, 0x185479ef, 0x6c25690f, 0xff4fd030, 0xc6932604, 0x9413d0c2, + 0x8af7de85, 0xaa38f331, 0x92ba15d6, 0xa099289f, 0x4cc0d1bc, 0xf202c735, 0xf0fd83db, 0x249c8297, 0x1bc35380, + 0xdf7c5abc, 0x6c2b938a, 0x48e73367, 0xb41d631c, 0xe5e28bd9, 0xa32b69b9, 0x93455c9f, 0x28ffa910, 0x61a2723c, + 0x5c21874f, 0xc1fcd3f2, 0xc93e46d1, 0xba2f23e6, 0x93069692, 0x233feb4d, 0x93fe10ec, 0x93b4dbd8, 0xcb13fcee, + 0xd23a5561, 0x2040fc3f, 0xf2965d2b, 0x0daa85e6, 0x8e6d5367, 0x591f60f1, 0xa2a6e885, 0xccf8f351, 0xd5537b8a, + 0x73115ca0, 0x4dc37ad7, 0xc407dfeb, 0x2ce44337, 0x2e399f8c, 0x17b8600b, 0xca751762, 0xeef04ebe, 0x8de2d0f3, + 0x68dc3749, 0xf15cb787, 0xaa0a7d60, 0xe04c8111, 0x1857e9cb, 0xb3cef2a6, 0x788c5712, 0x860aee8a, 0x6cf9eaaa, + 0xcdc175a9, 0x89023422, 0xac154f70, 0xbb7cf95e, 0x91df0065, 0x7fbbb3fb, 0xa909e9fa, 0xdc255354, 0xe9e813fd, + 0x7b4ccba6, 0x88cf4673, 0x9ffeaf5d, 0xb4c278a9, 0x11499716, 0x20ef76e1, 0xea7ecacb, 0x91c9a531, 0x38564ff7, + 0x47801c18, 0x0b8efe6b, 0xeb9c4cb8, 0x7dec3153, 0x8fdb61da, 0x92297af8, 0x234a6206, 0xed8cee8b, 0xd7b486e2, + 0x42d7f907, 0x758cd5f8, 0x38203642, 0x3f532cf9, 0xdff762da, 0x9f8de753, 0x9591b254, 0xe0489800, 0x4f7afcd5, + 0x24b333ea, 0xcc4ba603, 0x61df97e2, 0x489efd76, 0x911cb2e6, 0x5c318445, 0xe2300016, 0xd2aced5b, 0x8ff2a279, + 0x97327977, 0x5e9900e3, 0xd8f78a51, 0x2f803376, 0x1e34f69c, 0xcccd8e28, 0xf6054c69, 0x0f799374, 0x164ad9d3, + 0xb84d7609, 0xd79412e9, 0x79a66e79, 0xf5e182f0, 0xf61f8802, 0x2133a1bb, 0x86716e15, 0x97a362f5, 0xba38f4d1, + 0x45d08d2b, 0x2dc575de, 0xdb5a5685, 0x2df310cd, 0x206817e8, 0xc235d476, 0x31fe3c2f, 0x1ec63d06, 0xb8dbb83d, + 0x7d1da0e3, 0xdc66bb4f, 0x1a3d8261, 0xb0f4609b, 0x170e887c, 0x75e38f69, 0x85e8eb84, 0xc4561588, 0x3e5b1e8c, + 0xc569e183, 0xf9518837, 0xddd3252e, 0x2b69d3e6, 0xbbb800b7, 0x7f638447, 0x7391e512, 0x095ac164, 0x0a37022e, + 0x6dbbd988, 0xce766853, 0xbcae3c71, 0x7c5aef14, 0x0a4dec81, 0xbe319e6b, 0x70e93b57, 0xecaa19b2, 0xe92515a8, + 0x84ad2590, 0x8be921d0, 0x048b33fc, 0x11e07ed2, 0x7d2e317a, 0x9598dca6, 0x9565a3db, 0x9327213a, 0x9c928bb5, + 0x55ab369d, 0x6cb26159, 0x000403f1, 0x36f44523, 0x5f504ed9, 0x23fc15ce, 0xf4d0ac67, 0xc8c77bdf, 0xd19557d0, + 0xd258ba14, 0x86c21239, 0xafb457aa, 0x199c8bee, 0x8c561ace, 0xa1c418a7, 0x86d99486, 0xef27830c, 0x82a1af69, + 0xdafafb65, 0xae0c1f86, 0x741dcc95, 0xa627958b, 0x9bbbf2dc, 0x42e404f6, 0x3239059b, 0x8edc3c2d, 0x69595fef, + 0x6ebe4fb7, 0xf42d178d, 0x1f50ed8a, 0x3c6539a6, 0x0915dc53, 0x3fbf596c, 0xd580bdc0, 0x2c471fed, 0x35ae81ae, + 0xf6bc92b9, 0xd8280705, 0xb7dbd1e4, 0x09dff5cd, 0xb8328cf1, 0x13a68c38, 0x4558531d, 0x9569fdb0, 0x2c4110dd, + 0xd646639e, 0xadfc682f, 0x4a4677e4, 0xa6ed83af, 0x93cdc02e, 0xfb9193e6, 0x90d91551, 0x42f61f5f, 0x08b443a1, + 0x93371dc6, 0xef96979d, 0x944ae7a6, 0x533dfc02, 0x48db7b54, 0x553b4f34, 0x9fa15cd3, 0xa0a06bc3, 0xece437bc, + 0x02a1bc17, 0xad80268b, 0xec24b4eb, 0xa8a36d2f, 0x21b57de1, 0x1e67865f, 0x9d465739, 0xc90d166a, 0x94f0ff08, + 0xf4cb2291, 0x9a0098ee, 0xd6cb767d, 0x48e4cc0e, 0xd9b5ec8d, 0x08b5465f, 0x6922dd21, 0x66379a16, 0x2f52aa59, + 0x1a4b4195, 0x403d1277, 0xcaa92812, 0xa6544a0d, 0x563c9958, 0xc72880c9, 0x48ec7cc4, 0xd3e04e42, 0x8b674f81, + 0x6430c326, 0xea0a140c, 0xbb5a2c9d, 0x223d5916, 0x27fc533c, 0x260c87b8, 0x27410586, 0xbedc4c92, 0x82b8b661, + 0x1900d92c, 0x1cae550d, 0x271f2b32, 0x58020629, 0xd28a2adc, 0x93371741, 0x3b41c570, 0xd1de935d, 0x1a447085, + 0xf8fb1c54, 0xba890862, 0xd8f67915, 0xee13a722, 0x449e2253, 0xd6d771e0, 0x63cc8f70, 0x31f9b3ab, 0xa6e60c7a, + 0xe18c9c4b, 0x93026b82, 0xbcb8081d, 0xcfb65252, 0xa13706e0, 0xcb2e549e, 0x97c814e0, 0xd568690f, 0x8b75dad6, + 0x6f4437c9, 0x67d5287e, 0xd3ae48bd, 0xb9ba74bb, 0xcd9920db, 0xa159847b, 0x1abba2a7, 0xb16cfe40, 0xb4d3864e, + 0xb5a851a4, 0x48b6a699, 0x03ddee8c, 0x21be9349, 0x2b526ace, 0x350ed81c, 0x01ed63c6, 0x00518b70, 0x4a80aa72, + 0x259b06a6, 0x8763f8e9, 0x54712638, 0x7dbbc4a9, 0x9df29a1d, 0xacc30ce7, 0xb8120313, 0x3fd1d3f2, 0x0f4797b2, + 0xdd212e23, 0x3aa38ee6, 0x2537a2ef, 0x41b64ae9, 0x360e8040, 0x7ea21584, 0x56cb8260, 0x2a03b9a9, 0x2a5b7df1, + 0x88b25cfc, 0x3dadd4ed, 0x3ab16aba, 0xfc87b153, 0xbeca5f8d, 0x3a7bfe8f, 0x039de011, 0x39e1bd18, 0x682a0d90, + 0x8804c99c, 0x0af59265, 0xcd9f2a7a, 0x2111820f, 0x14a90b35, 0x0b05f75a, 0xb2676183, 0xec589d07, 0x02e2f675, + 0xb03923e7, 0x370707c1, 0x88882c3e, 0x5e75164a, 0xd5ea866e, 0xed0f9ee7, 0xe79a5e63, 0x63e44e74, 0x11a2d110, + 0x5590e3af, 0x1165fc13, 0xaa3e2fab, 0x7ff5089e, 0x179b529a, 0x3179ee91, 0xdbfebe6f, 0x7550ad5f, 0xf0700da7, + 0x94dbf47f, 0x0230f67e, 0xb50478be, 0xc3502edb, 0xbe30cec0, 0xe06f86d2, 0x3396792c, 0x12647d46, 0xa5d05fca, + 0x3543f339, 0x962fc905, 0x95bcf180, 0x08b441e2, 0x7b57ee3a, 0x616f3b73, 0x2a9d5308, 0x8fa75091, 0xd093a54e, + 0xa4be7923, 0xe5312011, 0x924a1352, 0x4aa99a9c, 0xd3ff81c7, 0x023f484a, 0x530187e7, 0x9d0246aa, 0xdcd7a4b4, + 0x6c5d80ac, 0x24c15fc8, 0x7272d96e, 0x5b5a4f64, 0xa9f416cd, 0xbc8ed6dc, 0x6833e0e8, 0xca0bab76, 0xeeb3bc60, + 0xdcdd0bd3, 0x22275f7d, 0xf2a8a6a5, 0xbc88462e, 0x6f4ef7f1, 0xf02ca895, 0x2c8b8990, 0x3195f153, 0x179ecaed, + 0xc420c7f6, 0xae35cdea, 0x0d5e4b56, 0x79ac7711, 0x573c0fb0, 0x084b1a2d, 0xa22528ec, 0x45b3aa7b, 0xd5487182, + 0x29dae54d, 0xada9c4b2, 0x25cac571, 0x61925906, 0x1caf9f1b, 0x46d46e05, 0xb1b6a775, 0xe6de96e2, 0x26f49aa5, + 0x52f4f210, 0xb1a0cc05, 0xe4ac95d2, 0x9d147e51, 0x437fecaa, 0xc3fe8c63, 0x064f6bc4, 0xb9d820ef, 0x931f141b, + 0x21d4f6e6, 0xac361392, 0x65d39ceb, 0x207e6f71, 0x24eb97f5, 0x741f0c79, 0x642fdbba, 0x70f4ebd9, 0x57a98d3c, + 0xb5ef06e3, 0xe2d57b49, 0x781a7367, 0x4aa06e71, 0x56fd3ee2, 0xa2b59931, 0x365116a0, 0xa3319448, 0x4059dafd, + 0xff8a2cbf, 0x0b8bfe6d, 0x65342f9d, 0x780bb252, 0x7a154a00, 0xae6ef380, 0x87697686, 0x01ad6d3d, 0x05926888, + 0xbf6ee225, 0x265f84b0, 0x12306a19, 0xecca09d7, 0x74520cc1, 0x563febc3, 0xa63c7bb3, 0x9f6544e2, 0x12b8b600, + 0xfe732cd3, 0xdd26d7f8, 0x83265586, 0x84df6807, 0xbff87670, 0xd8794e4d, 0xbc19f150, 0x3f8e61ac, 0x49fdceec, + 0x902b2ef6, 0x24c38e4a, 0x101dd0be, 0x99cd6c13, 0x481fc741, 0x82183ef7, 0x35cb76b8, 0x1fd1a656, 0xb5e46bae, + 0xbb89f5f4, 0x2f2b3911, 0x8a432c62, 0x9cbd050b, 0xfbc9066a, 0x2f38d4ba, 0x84cd912b, 0xa4d84fce, 0x2cf05ff0, + 0x829687bd, 0x899e8ae5, 0x27475cf3, 0xcd1758dc, 0xce35ecf5, 0xa7ef4c62, 0x86f06007, 0x2b8605d7, 0xcf6c7b57, + 0xe22d05d3, 0xe80a1e3d, 0x1911bd49, 0xb56ab843, 0xda834198, 0x7497e924, 0x99abbaad, 0x059cbaa2, 0x6d0367aa, + 0xce047282, 0x0dd67cd3, 0x432192a2, 0xeb52bcb8, 0x54e2c65d, 0xc743bdee, 0x95b2359b, 0xfa47c24d, 0x1322072a, + 0xc39a1646, 0x61009aee, 0x478aa97b, 0x06c04542, 0xbd5c0151, 0x7c8cc9b3, 0xf6fa3863, 0x07d56680, 0x1edbcd7d, + 0x1d6232be, 0xcedf46c5, 0x34249f0c, 0xd78d9cf0, 0xb45e26e5, 0x494b5140, 0xac08bb9d, 0x3c25d8fe, 0xcaa838c7, + 0x07703e78, 0xf3a23eb4, 0x50028c28, 0x3711e5e5, 0x2ae5e22a, 0x5a040c04, 0x1bddeb1e, 0x5ecfe949, 0x8c1ecc73, + 0xc4c4b291, 0x2ce6c4c2, 0xf63a7992, 0x32bd6fcb, 0xf3a4f1ae, 0xce78225d, 0xa6b13fa6, 0x2fbce716, 0xd7444e8e, + 0x11e8f5d1, 0x3c6a1020, 0x084f0c4a, 0x3e06e786, 0x94fdb81b, 0x2036b031, 0x0c686afa, 0x0d4037a3, 0xc8948656, + 0x5057b039, 0xffb9e6e0, 0xac681fc1, 0xb2ed9467, 0x5bb66ba0, 0xade77074, 0xd3f4c0ad, 0x5df6ce4e, 0x110a8b64, + 0x810d4d72, 0x5ae78216, 0xf8055489, 0xa6581b04, 0x42548116, 0xbe56fc11, 0x4a7805fc, 0xc542a96c, 0x5947ea7a, + 0xdf1114e5, 0x1a9212cf, 0x01b1b2ec, 0xd12f0eb7, 0x46c0771b, 0x30e38601, 0xd8161954, 0x408bc929, 0xcd809f78, + 0xd29ae77f, 0xa9b926b6, 0x34043551, 0xd2fb5680, 0x50be12a2, 0x65451b50, 0x82db6a16, 0x5a020499, 0xfa9b9f88, + 0x0b8627ea, 0xd8b5d8b1, 0xa5529cd2, 0xa0127182, 0xc56ab717, 0x1cf730eb, 0x65419de4, 0xc1838767, 0xc8a85ff6, + 0xc2b5d569, 0x48346010, 0xeee24b63, 0x5b6a6b76, 0x414d17bc, 0x9e11b76d, 0x2d2570f6, 0x26a23051, 0xe0852a6c, + 0xfff5a07a, 0x8811161c, 0x1a075814, 0xfbc480ce, 0x9e3d7b70, 0x898d7192, 0x9334e0ca, 0x85de6f33, 0xb16d5a51, + 0x422418c1, 0x15220d3b, 0x1d5c7552, 0x456d9187, 0xde232186, 0xe1a8f833, 0x595e5bb3, 0xb8c36f2d, 0x4f987a8d, + 0xbe49ffb8, 0xab657853, 0x40a0c522, 0xf7710476, 0xf859a458, 0x491e7e8d, 0x1b9d4f75, 0xb5c9affd, 0x47c51e4d, + 0x9b3a7405, 0x132572dd, 0xda5d006a, 0x2bc721c5, 0x675a11ce, 0xf2c7ec9e, 0x44919b2e, 0x626a9396, 0x9fd165ed, + 0x5b265cea, 0x26cce398, 0x952ca1fa, 0x86be4d62, 0x751f350f, 0x6a6816ad, 0xb99d2576, 0x2f3214a6, 0x9a150127, + 0x1112c340, 0x0b925422, 0xafdfc749, 0x804c7ef2, 0xea06f047, 0xb2e2a76a, 0x3a7e9625, 0xb9f967be, 0xac44a38d, + 0xee5774aa, 0x049ad3ce, 0xd19a60e4, 0x89e7577b, 0x06e4cfc0, 0x5024a761, 0x6cffbed6, 0x8a47bc4c, 0x00d33a02, + 0x46e39ad3, 0x82b267a2, 0xf35e6f09, 0xdaeeb428, 0xfc46ee2d, 0x9b200b4c, 0x95a2274c, 0x9d53abb6, 0x0fad0e9b, + 0x408e5a83, 0x90a374ba, 0xd84bdcdd, 0xde97dcf6, 0x6a4ab283, 0xfc3f4337, 0xb9c17af5, 0x4084870c, 0xba5e3aa2, + 0x0663801e, 0xff6a506e, 0x88b4c458, 0x6da3a9f5, 0x5d37be6e, 0x684efc43, 0xf1cc6a2d, 0xeaf0c28e, 0xf2b5e145, + 0x788e7680, 0x36973c9e, 0xa4e2768b, 0xdf98ef55, 0x95d04b68, 0x48ae2d49, 0xe3342c4d, 0xaf94c102, 0x63884388, + 0x5fdd623b, 0x0dff7067, 0xa5595ba0, 0xa3217c54, 0x77068320, 0x6710279f, 0xbcedc90f, 0x774e5c10, 0x51f57570, + 0x34a44355, 0xc3d786bb, 0xb10b88eb, 0xa0622124, 0xfb3e4514, 0xcaebfcef, 0x4ee7accd, 0xde30e974, 0x3cd1e648, + 0x93eee67b, 0xf0b8042e, 0x18f5e188, 0x7b21094a, 0x6587fc96, 0x6952aae6, 0x4ce7bcfb, 0x55c7b693, 0x1ff35b4c, + 0x320c1223, 0xe0a1cc8a, 0xb58afd7a, 0x237244f4, 0x9e9862ac, 0x275294fb, 0xaee39fda, 0x7486e721, 0xfd05140c, + 0x1b160fc3, 0x781eeadf, 0x514fbb57, 0x48bdd246, 0x7220145f, 0x74c224b0, 0xeea9db1a, 0x42c7a5c2, 0xde5473df, + 0x79d441f8, 0x8dc4e95e, 0x2b6cb258, 0x5e7ea791, 0x889206b2, 0x32b4a9c8, 0x1773aefc, 0x9bfa06cc, 0x8058374a, + 0x710fb5a2, 0xdd7e5f50, 0x595b45a1, 0x63831d0c, 0x3c5eab6d, 0x1e643b4a, 0xe7b05527, 0x4ce19761, 0x6bd9ec95, + 0xd5cf03a2, 0x2da61dc7, 0x40903b6e, 0x3457c802, 0x4be7540a, 0x2d385d6f, 0xe190e82e, 0xc6066c7b, 0xbd74c362, + 0x01bfc7a8, 0xdc9bfdf1, 0x5ceff0bf, 0x255d62bd, 0x9f7e71eb, 0xb29f1677, 0xbe261432, 0xe472c406, 0xf810d816, + 0x74b90c76, 0x3e3cddb1, 0xa7321d66, 0x1059da4b, 0x27353b1d, 0x084c4605, 0x4ddd1b3e, 0x6e0c0fe6, 0x29e7fe4b, + 0x051f14c6, 0xbbac03e8, 0xbcd07065, 0x4d6b6248, 0x409f8270, 0x9150fb5b, 0x338d9597, 0xeeb954fe, 0xc764666c, + 0x6b74fd87, 0xcce418d8, 0xc5cbcf8d, 0xafbb0b46, 0x2c5ffc17, 0xd54d5177, 0x794304a5, 0x9a48d736, 0x86b34679, + 0x431c2a15, 0x9aef854d, 0xd6544840, 0xa197ffa6, 0x7b70d13f, 0xe0bf3701, 0xeb5674c9, 0x8c4070bd, 0xbad89407, + 0x4de56223, 0x50b8ece0, 0x315351cc, 0xe1146304, 0x6474a828, 0x76be4e2e, 0xdd8566f9, 0x2afad76e, 0x6bf8b426, + 0x327d9e6b, 0x92375249, 0xaad9e218, 0xe50d429f, 0xdc4adb54, 0x2e6ddd76, 0x8960e9af, 0x4a24afb3, 0xcc4a5adb, + 0x1cdea009, 0x23070d5c, 0x761e4271, 0xd58185d3, 0xa405f8ac, 0x7c276412, 0x3f8bfc53, 0x233b3d14, 0x15c59283, + 0xa2b36815, 0x355ec54f, 0x2a0886e0, 0x2791ef9e, 0x317a327c, 0xb467950e, 0x8b4bc99c, 0x5ebd0767, 0x30282c67, + 0x37422a8e, 0x1c1a7389, 0x2c1fc0bd, 0x242be654, 0x1366bf36, 0x72e8399a, 0x57675864, 0x36aa608c, 0x06b3e973, + 0x855b3063, 0x2cc25698, 0x30b01aef, 0x028f9ff8, 0x9f499388, 0x1c211376, 0xb9d05aae, 0x3285d55e, 0x7194a5c5, + 0xa59e97bf, 0xc8b95d6f, 0x4fdc53ec, 0xa310d354, 0xf8f77408, 0x4692fc1e, 0xc255a69c, 0x5cdc9711, 0xff7af327, + 0x944ed487, 0x0ea3cb75, 0xd11eb3fc, 0xea33dbc1, 0x3a4e1049, 0x0f29ef9b, 0x2f252dd6, 0x7961b716, 0x2d52610e, + 0xa8dbded9, 0xa8458833, 0x2d6f6300, 0xb4dbd718, 0xe26d05f3, 0xddb62c95, 0x4f09d53d, 0xcd4ef484, 0xb4902169, + 0x398963a1, 0x8039d0e3, 0xa699ddbb, 0x9a4c7d61, 0xe9cb7f0d, 0xaf2aeca2, 0xee258866, 0x4748c32a, 0x02868672, + 0xe73ccf6c, 0x43414473, 0x17ed8d2e, 0xcc2137ac, 0x56d97dd0, 0xc334fd9d, 0x28ab3dde, 0x32a5e8d6, 0x40c7b07b, + 0x6905393c, 0xaad86b86, 0x84ff3b56, 0xbcb66b62, 0x1f8d3561, 0xf2d75a0e, 0xb90447c1, 0x08911881, 0xd7519cc7, + 0xead5ca45, 0x3314ef86, 0xdeacf62f, 0xbdd0cfa7, 0x66e43c28, 0x12d5051c, 0xade5804b, 0x5276c587, 0x039e8846, + 0x0fd5f96c, 0x648a584e, 0x8fa5a2a0, 0xfe7ab35f, 0x3b15c7cf, 0x7c37cc2f, 0x2df17f56, 0x08f0ae17, 0x76e33606, + 0x832beff3, 0xe4be8344, 0xcbe48e8b, 0x4bc458e4, 0x7a8d463d, 0x192eec15, 0xac520d17, 0x251a17f2, 0x72bfdc5a, + 0xfe77d3f9, 0x7ace7dbc, 0xd6b8b804, 0x42797bcf, 0x7d44da2c, 0xe6d29184, 0xe2f1b47e, 0x7929a8d7, 0x8bcdab5e, + 0x0415d7d2, 0xd0e1cc58, 0xeb48f3e0, 0xa6a14e26, 0x299d2881, 0x5cdd9f0c, 0xb95e07e3, 0x480cd471, 0x48f5a9d5, + 0x88608b57, 0x9b608746, 0x2c6047eb, 0x07eb6c0f, 0x438fa2e3, 0x5be69b33, 0x72b2b2ed, 0x310ed823, 0x0f821ed3, + 0xd219c9e5, 0x855c0a18, 0x7af0bdc9, 0x8334849d, 0x8d6d440a, 0x66342c95, 0xb5b0bc8d, 0x6d609005, 0x2b92b97d, + 0x6a4f5e28, 0xa629e728, 0x6af64954, 0xae737e56, 0x5577b158, 0x2c3b9ac8, 0xa1791f69, 0x7cc6be57, 0xf9b86b2c, + 0x05569087, 0xf941c582, 0xcdd05f76, 0x3475b09e, 0x9315f1c9, 0xbfb2ddb1, 0x27eb8ef2, 0xdf4afe19, 0x71a46fd2, + 0x0b4c648b, 0x89fa97cd, 0x09908bee, 0xb6826440, 0xb5fd0660, 0xb2bb5489, 0x7ddb5eb1, 0xd8192fbf, 0x99b6937c, + 0x0d13699f, 0x266e826a, 0xc3e74434, 0x9220a006, 0x558a93f2, 0x150d9202, 0x190943b3, 0x1dafcf11, 0x89f41eeb, + 0x5dcf61fb, 0x1974e674, 0x69f10a08, 0x9af138bb, 0x6f2e8fa9, 0xcb6f110f, 0xc3752f51, 0x1fbc3001, 0xeb6aa4a0, + 0xa3bad8b1, 0xa465c0c4, 0x6bde35c2, 0xbb77f0fb, 0xc55c0350, 0xc5224198, 0xd63cd846, 0xf07cc6e2, 0xa388d467, + 0xf02cd48c, 0x587a159e, 0xb4268b1c, 0x6995d86a, 0x96a64ee9, 0x6dbb22bb, 0x9a0636cf, 0x26ee3225, 0xa16732f7, + 0x88b0e918, 0xd8aade59, 0x856762fb, 0x5f6e63ac, 0x92e233ff, 0x0b531ed3, 0x9a8cfa6a, 0x53b3be76, 0xe1c80acc, + 0x75b82f2e, 0xb1adaf98, 0xe76018c8, 0x920a94b6, 0x1aee0b48, 0xa951a8e9, 0xe5fc868d, 0x072f55c6, 0x23ae35a3, + 0x3512d9b6, 0x8ec5dab7, 0xccf92ee9, 0xd02bb9a4, 0x0f1608cf, 0x8db82f1d, 0x053728c0, 0xed7abf92, 0xa13e3144, + 0xe558fc04, 0x3df2b309, 0xe792e9ca, 0xac985393, 0x0afd8dff, 0x86d56f65, 0xaad51823, 0x2ef669e4, 0x012cdbe8, + 0x719dadc4, 0x474c4326, 0x648a7de5, 0x763548e9, 0xe2273c34, 0x58987641, 0xcec0ca3f, 0xf2cba75d, 0xd637b1d5, + 0xd58e8833, 0x08dcc16c, 0x3fdf11f4, 0x76bacd97, 0xf0a58787, 0xc197198c, 0x8a11f6af, 0x2f3e6859, 0x8ce7322e, + 0x91ece500, 0x8a9ca749, 0xe59622c1, 0x05f574fb, 0xd1969d64, 0x69a72f1f, 0x06090b51, 0x0cac305f, 0x7cc987ad, + 0x04da4997, 0x5576b5cb, 0x859c8ee4, 0x1e7eaa08, 0x16c0a9a7, 0x4fbe8a0c, 0x13b62e78, 0xee63e4d1, 0xfa55aa0e, + 0x05b83a34, 0xf31e0b9a, 0x8b512efb, 0xf1ac8668, 0xc425216b, 0x73cb93b8, 0x0e26b272, 0x8fac8955, 0xb8fe4374, + 0xcc101d6f, 0xae78b24a, 0x4501e888, 0x8a568802, 0xbadb9662, 0x23464924, 0x5f0687ed, 0xb72abf06, 0x38fd1def, + 0x45b3c778, 0x2ee0c167, 0xae8a0325, 0x3ec44d27, 0x1d762262, 0x9857ebaf, 0x7686bd44, 0x106068fd, 0x1342c1c3, + 0x39126f3f, 0xc0d59583, 0x518ab36e, 0xff4fb536, 0x4c947dbb, 0xe971607e, 0xc1a3b30a, 0xe46fd0f3, 0x22b2300e, + 0x0fdc252d, 0x3f93e617, 0xa17f3ff5, 0x07d3f2b4, 0x88a22c18, 0x4484bd93, 0xe2352147, 0x425d8434, 0x8557f5f8, + 0xf7b03565, 0xf77724d3, 0x7f7c3520, 0x89a8d1f9, 0xe2775a3b, 0x80276e89, 0xfe782431, 0x8b0b36b4, 0x52803dc6, + 0x2b295093, 0xdfd8788b, 0x76b31f00, 0x190f23fa, 0x62e02d40, 0xd41ccf50, 0xb8a759cd, 0x5a1fd7f2, 0x70587e1f, + 0x421cc34a, 0xa87d456a, 0x430a57dd, 0x97c2effb, 0xa067b324, 0x19a290af, 0xd17c3e58, 0xb1f8c324, 0x7122b845, + 0x014c4691, 0x9d21bff9, 0x88e296e8, 0x71904652, 0xc98a78d3, 0xf2dfa5b1, 0x5aa4c976, 0xf7328e6e, 0x522ccd1c, + 0x13282c62, 0x9b3b1085, 0xa7d36127, 0xb430a245, 0x3c4e8a82, 0x5e4fce80, 0x7cb9ab69, 0x6d68b05c, 0xc29fce36, + 0x69ebb6d6, 0x82026956, 0x48ee0110, 0x043749df, 0xe13d14f2, 0x30ea0039, 0x0618ffcb, 0xdfb99727, 0x335a5d86, + 0x0214c2f7, 0xda8e4db5, 0x28fa7f7a, 0xbfb519af, 0xa4af40cb, 0xaae47da2, 0xcffb3857, 0x7c615aab, 0xed88d73f, + 0x93f711f0, 0xef66ecba, 0xfc7098e8, 0xdcb1eaca, 0xd8acafdf, 0xad518adf, 0x5bae53f8, 0x152c799d, 0xd0dbc666, + 0x0e5c6e8b, 0xfc8b87d8, 0xe689933b, 0x57eddbbc, 0xf8276e1f, 0xc7029b4b, 0xdf0a3154, 0xc771d9a5, 0xa4f9275c, + 0xb20775e4, 0xc249a4fb, 0xa797d9a5, 0x7480be23, 0xa14d4411, 0x1fe4cafc, 0xbc40f499, 0x2a2a3ec7, 0x889abac8, + 0xcd657ff5, 0x93199e56, 0x329a49d4, 0x1ea328e1, 0x6e0ce2f6, 0xd0a13c8f, 0xe78cca24, 0x2583fde5, 0xfacd875b, + 0x5d94bdfb, 0x962b9d7d, 0x85d667cf, 0x62092a4f, 0x2e59bbc8, 0x632f32b3, 0x3b8a6fc0, 0x7657f14d, 0x321f6488, + 0xe4954fd4, 0x68ae22af, 0xcbe98dcd, 0x39487c31, 0xeca007f0, 0xe31b1dad, 0x34297c7a, 0x3012b220, 0x4ca4f159, + 0xbcbe5e46, 0x43a3c7c8, 0x6a0c3de0, 0xbc832eba, 0xa1d4a52b, 0x2525f987, 0x62fc5791, 0xc72ef9ca, 0x3fc020ab, + 0xa394d7b8, 0xc17a1b34, 0x4bebfa0f, 0x38a7c1e3, 0x3774ebfb, 0xe0d6e78b, 0x6e573224, 0x34cf5baa, 0x832be8a7, + 0x62669f03, 0x9fb16cf9, 0xdfd3f0de, 0x3fa1f874, 0x19986cf4, 0xcebd98f6, 0xe4293a78, 0x0c7ea664, 0x2431da91, + 0x103fb2ed, 0x0e3cdf80, 0x0627696b, 0x8fd6e3f6, 0xcabdb1e4, 0xbb72ab32, 0x96bf9277, 0xccc0941f, 0x7eb144d9, + 0xd0557605, 0xa204e602, 0xb96f9141, 0xc9ced197, 0x9dad1d00, 0xfac419fb, 0xf53eda88, 0xd2cd279f, 0xfd1483c7, + 0x9219ca86, 0x335bb08a, 0xd058a8ea, 0x05285b66, 0x528bd19e, 0x95ac5431, 0xb192c529, 0x9a7d6d62, 0x1b554e9c, + 0x67920f7a, 0x6edaf80f, 0x66ef5615, 0x32cd80d6, 0xbe68ff1d, 0xe4fdb5b0, 0x3b80c86d, 0x3e8b5f63, 0xeb1bc898, + 0xa47618e3, 0xd54024aa, 0xd6c4648c, 0x8b5fc8c0, 0x90741240, 0xd5733a1d, 0x0d040d49, 0x90a1f9a7, 0xae10a3ac, + 0xde8fa914, 0x35337d58, 0x1eac2bf2, 0x893c2c83, 0x705327ff, 0xc77bf252, 0xffcd8036, 0xf10f86d2, 0xa53220a2, + 0x37a746c5, 0x1d7795c8, 0x6b0325c6, 0xf20eb5d0, 0x6ea8f146, 0xc67222d2, 0x40d8aff4, 0x7d73ac4c, 0x6a0ce05e, + 0xd7f25aac, 0xa327d7f9, 0x99cf76e4, 0x2aa02ab2, 0x4841e140, 0x254604cb, 0xd0e5ea23, 0x46edbd18, 0x4c391a17, + 0xec395245, 0x7760763e, 0x9764b2a3, 0x7181c5e4, 0x0c28d20c, 0x48763411, 0x4b6f2f9d, 0x1a5e03f6, 0xd33fa700, + 0x22036b54, 0x448cf9f5, 0x77873138, 0x92e682b0, 0xf57fcad0, 0x75a2f463, 0x5538e33d, 0x50de977b, 0xbe0ef22e, + 0x5b071e47, 0x9f4ecd0c, 0x50d9192a, 0xacc5c3cb, 0x20dab14a, 0xfc7516af, 0xb24b3001, 0xe5240b7e, 0xe9ca42d9, + 0x05c36af7, 0xf21f65c7, 0x61e2f1d1, 0x0c68f408, 0x9496fc8f, 0x77e91fb5, 0xe042eda7, 0x144251ad, 0xc7c1c248, + 0x9d79a630, 0x76b209ac, 0x58989e91, 0xf32d9c7b, 0x65d26f81, 0xd532a614, 0x517fa07f, 0xbbdfa9fa, 0x638aa012, + 0xa7716513, 0xb1cad7b8, 0x6f5d6d99, 0xe8016bde, 0xd8731ee8, 0xcee12c83, 0x683d3685, 0x4af58943, 0x7877b5f0, + 0xf3e3dc42, 0xfe144468, 0x4bdf7b18, 0x48b7f9c1, 0x667948c4, 0x158f9a51, 0x96a2e43d, 0xb51ad49a, 0x1bea6c86, + 0xfffe6004, 0x38cf9620, 0xa9a7cbd0, 0x51e8d293, 0x56f11ef0, 0x70c3268e, 0x878fe552, 0x7868f891, 0x211256f5, + 0x51734062, 0xc37e5e6e, 0x3b278249, 0x462d639c, 0xe7fc54a6, 0xb9aa0bdb, 0x2b5671fb, 0xa6ced401, 0x944c6095, + 0x7cfede9c, 0xca00df0d, 0x41c53ba0, 0xbfd50d55, 0xbf2ecbd4, 0x487ca3dd, 0x21607e7e, 0xd9ab1ef6, 0xe628c2be, + 0x7896bdb0, 0x17677207, 0xc2a84511, 0x4762e1a0, 0xd2a46f82, 0xdf134e20, 0xb6c57018, 0x48d7067a, 0xaca46214, + 0x84747519, 0xd38d3d90, 0x4aefde2c, 0x62e20792, 0x9e14d66d, 0x125f0daf, 0x0bc0f929, 0x505471f7, 0xe5b4f97d, + 0xbdb2797c, 0x713c086a, 0x76b5bc78, 0xd4c16c8c, 0x03eb8787, 0x3b14e5be, 0xbb5ce24b, 0xa1be371d, 0xa7432dec, + 0xdbf07011, 0xf88753ff, 0x006f1ca8, 0xacf320ee, 0x6bf1c9f5, 0x8bc16a8c, 0xecc8bb50, 0xfc5ec35a, 0x230695b1, + 0x56486b01, 0xbb47227f, 0xe1dafad7, 0x40672686, 0x8909846b, 0xf99980b7, 0x26189ee9, 0x1383eacb, 0x3736506a, + 0x2d247c6b, 0x8bc8325e, 0x7928246e, 0x3e0b71f0, 0x68c860ea, 0x11716b60, 0x4b876a11, 0x8a19ad3a, 0xb9b20e02, + 0x77b7b5b8, 0xb36bd02d, 0x4cec70d1, 0x73aacca1, 0x4b1d2ca1, 0xb58d7691, 0x8b4c3f52, 0xf1c3bd58, 0xb33098da, + 0xc2a2241d, 0x04cb382c, 0x80d4c1d7, 0x088a2c01, 0x24470574, 0xb119de03, 0xfa869fa9, 0xff0646bd, 0x7acac8bf, + 0x64666d62, 0xf8eef6ff, 0x0239de47, 0x5ab1159b, 0xf284e766, 0x3f06a7ef, 0x85a2aa24, 0x08add9d0, 0xf0479060, + 0xbf124fea, 0x6c78b096, 0x077d1741, 0x22959943, 0x9c9f74a8, 0x2f8b1670, 0x84e43037, 0x414e0629, 0xfab9b57c, + 0x1af8bf6b, 0xfb3cd9e2, 0x208fef77, 0xbe4cd23e, 0xc8dc2155, 0x2340041e, 0x213581ba, 0x06f9d04a, 0xb1eed558, + 0xb39dacb6, 0x93babc57, 0xb32b4992, 0xe9f98f2a, 0x2de6a463, 0x0802d307, 0x18a5cf21, 0x38d09e65, 0x6486d6b5, + 0xdf3eb868, 0x14b42b99, 0x5dee5b45, 0x640d7e72, 0xc4a086d0, 0x3de1fa09, 0xc30c20f5, 0x8c5d5a71, 0x18aaff49, + 0xe588d7ca, 0xbaaab89c, 0x395688a9, 0xa67012d3, 0x2e7532fc, 0x56e648d9, 0x3c91b5d2, 0xc38f1a3e, 0x66bee8b7, + 0x34343a99, 0xc33f49d3, 0x117e4ca6, 0xb8d9947d, 0x2d88cecd, 0x78437860, 0xce5c61d5, 0xdeee78e2, 0x0232d685, + 0x52922b45, 0xaa3718a4, 0xa8fd8e7d, 0x9e057d1a, 0x5b295114, 0xa6f32e3b, 0x26b54ce2, 0x4e13ac09, 0x2fa0433e, + 0x582c3973, 0x38ee9053, 0x2729fc28, 0xf5e38da4, 0x59e22f2a, 0x90cd9452, 0x2548be3e, 0x647e8248, 0x136cfe9e, + 0x74a23ca0, 0xc2d8ba26, 0x9038f371, 0x41ff7a82, 0x6957bd41, 0xea709ba0, 0x02bd2293, 0x83aeaa99, 0x8e54e8df, + 0xf7b7c871, 0x394c8a4a, 0xffd22a6a, 0x29377ffe, 0x8137c563, 0x212cd94f, 0x7e7242e4, 0xc1d9c7d2, 0x7f9d45ff, + 0x586008e7, 0x300b3ae3, 0xdc85d2a2, 0x76f8fd12, 0x9c4be539, 0xef03472a, 0x20801e55, 0x8a62f076, 0x90849376, + 0xcc24203a, 0xf2aee89a, 0xa5b38cd2, 0xf7ebe7ca, 0x9fca59d2, 0xfee83ba7, 0x5621ee10, 0xcfa90d72, 0x9f1399d0, + 0xc3e39695, 0x75780e08, 0xcac73d45, 0x9d3f2f8b, 0x221a2daa, 0xe182a8d1, 0xf9181e71, 0x50f204eb, 0x2eab3c2c, + 0x63d1ad07, 0xc9ed328a, 0x983e7b57, 0x083d63c4, 0x4f734d4c, 0xb67616be, 0xf930ba4c, 0xb330bc03, 0xa3f06757, + 0x0c41ccdf, 0x5fb6ee40, 0xb112dd3e, 0x83f11b36, 0xe7784f6e, 0xfa80e3c6, 0x35f1bc74, 0x50090492, 0x1265188f, + 0x6e9fa755, 0x6f4d51f7, 0x66374be7, 0xb6199976, 0x1281ae6b, 0x20372345, 0x1b017a74, 0x082ae93e, 0xe9795454, + 0x026fd2e2, 0xfbb89142, 0xa30deb68, 0x75e7640f, 0xbe3db876, 0x4fc1122a, 0xba27bf37, 0x9ef845ae, 0x853d7e60, + 0x914d93f7, 0x69432a66, 0x7b3eae69, 0xd7335c37, 0x68971616, 0x10e12558, 0x90cf62a1, 0xd7ba05ca, 0x8dbcc199, + 0x7e2dceda, 0xc1b947b0, 0xb86f4a27, 0xa6c64859, 0x9e95f740, 0xc81e6909, 0x8cf1b1d5, 0x57d28ab0, 0xbea22f13, + 0xe014ee63, 0x5ea75e8f, 0x0dc510df, 0x3d866549, 0x86517f1c, 0xa9684d17, 0x1098542a, 0xcd643137, 0xe8b0a671, + 0xf4ef4c86, 0x27c0653e, 0x6a9c70b4, 0xb29940c3, 0xed3b07c1, 0xc3a0f727, 0x2a309702, 0xaf455416, 0x0190715e, + 0x09038fa3, 0xaef3afa9, 0xc8163469, 0x3917e195, 0x60324de9, 0x2fab179e, 0xf4bd0fe1, 0x950ed058, 0x0d24bdee, + 0x09bb1b7b, 0xf9152f8d, 0x47bae1b2, 0x64e6d9da, 0xb06a2f52, 0xea3afa70, 0xf220532e, 0x0aca8ab7, 0x7336a4ea, + 0xfe14ef52, 0x3b3ff33b, 0x7d096ffe, 0x082ffbb7, 0x1be9e875, 0x5a5dd60d, 0x60977044, 0xec563b18, 0xa54a3179, + 0xa30a9638, 0xe98940e2, 0xde482099, 0x4f576e7e, 0xfb123ed9, 0x1bef977c, 0x8d8c658f, 0xb588b770, 0x3c8a9130, + 0x03eb0950, 0xf250ac1e, 0x9d410ec7, 0x6379d966, 0xb76e2279, 0x4748fe57, 0x8757ca64, 0x92d5f5dd, 0x7f69b318, + 0x3ae90dbd, 0xc1a7f38e, 0x0e959ac7, 0xc3127799, 0x557ec15b, 0x87cd1197, 0x5477c323, 0x13e1a6da, 0x81f27e17, + 0xfb8c9c60, 0x462d297e, 0xca76c9a0, 0x3a7bf8ee, 0x833c2acc, 0x6df6fd09, 0x0def8af7, 0x56a87536, 0x4028ca4c, + 0xc611bf05, 0xd8d3ddfa, 0x769ac429, 0xe119afa7, 0x51c1a656, 0x613954b8, 0x3e1e4575, 0x274f05df, 0xa9b0d89b, + 0x4637073d, 0xe1dc3bb3, 0x2b38e1d4, 0x97c64361, 0x8cbe01ec, 0xba5326f9, 0x2b79bae2, 0xc2d36094, 0x9493f2ca, + 0x88c1c20e, 0x857c2749, 0x6f4e1712, 0x66142e04, 0x5dcccaec, 0xe7cd073b, 0x22943f12, 0xcaea134f, 0xfe335ec7, + 0x47e26af9, 0x045213d5, 0x5d1820ff, 0x4d2157ac, 0x7da3fa03, 0x4542eec7, 0x369b5aef, 0x88b41e11, 0xb4c81bf6, + 0x76bb589d, 0xd705fbc0, 0x4b2bd5cf, 0xe7b033ff, 0x402123c3, 0x8e705b79, 0x7adf93dd, 0xe168e4b8, 0x7a312743, + 0xfcf94e59, 0x9658629c, 0xc39ab1c4, 0xe8e83428, 0x26daf3ce, 0x9e3dd308, 0xaf4c7df1, 0xbe4021aa, 0x352d8c82, + 0x32a8f69c, 0x740a2962, 0xec560434, 0x83924a0b, 0xa137fdcc, 0x9ed79c12, 0xd38117e5, 0x5829b3b1, 0xf95e1561, + 0x8ac5ae33, 0xe529b6ea, 0x984494d0, 0xbed83bdd, 0x7ae8406b, 0x0b932d11, 0x17e06ae7, 0x28169860, 0xc6b6f9f4, + 0xaecf55ba, 0x95763bc9, 0xab2b805b, 0x2a30710c, 0x817c833f, 0x03d1596b, 0x5bee8cc1, 0xea9f7ebb, 0x57e5950d, + 0xb670ecac, 0x2cc81011, 0x6da0bcbf, 0x8a557783, 0x3e328d13, 0xf7dd225f, 0xcef189bb, 0x0776ca2d, 0x2f01b2fb, + 0x3c4f93fa, 0xe630030e, 0x97efc7c0, 0xb18df001, 0x2fb0ce41, 0xae4a50b7, 0xd9fb5ecc, 0x92209419, 0xdd38d1e7, + 0x500956f4, 0xd4a70f63, 0x5d7c9ace, 0x651ec63b, 0x6ae33489, 0xdc548261, 0xcd8f9a0e, 0x0e7c1e0b, 0x7f3f529e, + 0x68eee0b0, 0xa01a590a, 0xf0bafcd2, 0xa3148e02, 0xd9a0626f, 0x4ef7da9b, 0xa06c3e97, 0xd4795a28, 0x8659b9e3, + 0x531da00f, 0x6f39782d, 0xc759e39c, 0x09d23cf2, 0xb79d7879, 0xffe0a47d, 0x0e71b788, 0xa096f563, 0xe67bb1a5, + 0x78ee3262, 0xd9df609b, 0x8095a896, 0xbfb766a8, 0x8bfda125, 0x7c7c88ff, 0x9530d321, 0x8eec92dc, 0xa279f7b7, + 0x27c10ff0, 0x3ec34751, 0x7101d3b9, 0xc3020b3e, 0x06627708, 0x95f08026, 0x7e5c282d, 0xc195442f, 0x647b6bdb, + 0xfb96bbb3, 0xefe4aac1, 0xbed5d875, 0xcec7bd9d, 0x4450857a, 0xcef6f7f0, 0x1ba66da6, 0xc9e37dd6, 0x8b255f66, + 0xd8c751c6, 0x3fde1dcf, 0x1863cb3e, 0x53dacc11, 0xf95a171d, 0x10e900f0, 0xb9e37c52, 0x9c9ca3f7, 0x5455b910, + 0x8664d457, 0xb20cfb05, 0xd9cf9783, 0xb4c8334d, 0x9d0bca9c, 0x513211de, 0x9a397e5f, 0x24be6d0c, 0xa06afb1f, + 0xf5623dda, 0x803e5992, 0x92a9a61e, 0x5e31dca5, 0x28b37e1d, 0xf29f7ae7, 0x99b5c35e, 0x2c527c6c, 0x13638b61, + 0xd0754868, 0x45ca8bf7, 0x26c17032, 0x593cc220, 0x3055ef42, 0x4bbcb58e, 0xe4304ed3, 0x61c4523e, 0x570e98b7, + 0x586661b3, 0xde5ac3af, 0xb640c7b2, 0xa50c8a6a, 0x3ca74a4b, 0x9cb22d16, 0xe789867b, 0xb719d1eb, 0xff192bca, + 0xe63a7aff, 0xad563bf1, 0xc9f904e7, 0x2285faa9, 0xa7998eb1, 0x1987d0f5, 0xc630f2d2, 0x364e2fe6, 0x1fce4f03, + 0x57d405b5, 0x3279a0f2, 0xc7573bac, 0x4243c194, 0xf7c03986, 0x2a0f1aa3, 0x71f2f3f1, 0x5c02e585, 0x91f67388, + 0x48172335, 0x86cd0048, 0x7d92296e, 0x11a45cb2, 0x760082eb, 0xb55bc810, 0x9cb91c40, 0xce7f0a87, 0x77537e73, + 0x7e2924c0, 0xe2aa6d29, 0x04ee0ed1, 0x3c89a44b, 0x6db2daff, 0x6fdca923, 0x3749bb83, 0xd73d2e37, 0xc7d45a9f, + 0xdd3edde6, 0x7fe60f00, 0x17354a42, 0xd727ea3e, 0xdd9a3fae, 0x4a5448ec, 0xa3fd1c2e, 0xd51b9212, 0x54064ce3, + 0x393f0fb3, 0x8871ac38, 0x4ec8448b, 0x28fa41d3, 0x41c6c7da, 0x47214b30, 0x545ac071, 0x8b26ba9c, 0xd737a103, + 0xb36f1d9b, 0xc5061fba, 0x252f9679, 0xad339f0e, 0xce26729e, 0x8f0e3448, 0x473c113c, 0xd7b06762, 0x4dda0fae, + 0xbef9414e, 0xf728b570, 0x54898c76, 0xb49a748a, 0x9ae7fc59, 0x353eed81, 0x8562d18f, 0x7333fcb3, 0x1f458dca, + 0xe8e1b271, 0x792911a7, 0xaeab5f6e, 0xe0852fbf, 0x5fad0a36, 0xffceb9fa, 0xdb0f250a, 0x50098eb5, 0x3b47c4f3, + 0x8b3cc760, 0x10e8d3f9, 0xb1484f3b, 0xabcd56a5, 0x729aec1a, 0xbe0786b8, 0xcd9e2949, 0xdbed77a6, 0xa137c99a, + 0x93145796, 0xecc5aa3b, 0x64cb2972, 0x830cf577, 0x47b52d5e, 0x712ffb23, 0xb0a48e59, 0x34b4b06a, 0x5a404d43, + 0xcad9ce33, 0xb63f8d3f, 0x340ec3fd, 0xb5973a4d, 0xadb894ae, 0x19d0d4e6, 0xe61b13f3, 0x9ebb630d, 0x2e0df2a5, + 0xf24724c9, 0xabd2beee, 0xe006b59b, 0xc97656d9, 0x852128cc, 0xcfe49986, 0x703ccf52, 0x73f73df8, 0x34cf0007, + 0xaa1273b2, 0xce30890d, 0xc1c089a2, 0xc86a62e5, 0x5b225e8e, 0xb0b06405, 0x24755fbc, 0x30ddef34, 0x401a4708, + 0x98de766d, 0x3c6a133d, 0xf4b8165a, 0x0c32e1a5, 0xb014b8fa, 0x6882ae80, 0xa3d6bd8f, 0xff0a4e8b, 0x507162fb, + 0x00da2217, 0xab96c328, 0xf8bfb2cf, 0x1e49053e, 0x3327bc6f, 0xb5c3368a, 0xba97922f, 0x76abe68d, 0x7781c30f, + 0x9d2df558, 0x4f47249a, 0xf4a3eb32, 0xd836460f, 0xb22468dd, 0xbfe9aba1, 0xb9a9c2af, 0x3977ae67, 0x8ff23abc, + 0x40867314, 0x60b862a4, 0x6b4d2bee, 0x146a7167, 0x1d11cefd, 0x03cbad3a, 0xb4fbd77c, 0x0b71a3dc, 0xd785a414, + 0xa642d656, 0xbe57a080, 0x2cb6ce84, 0x2df8a81d, 0xa0729db7, 0x61c06bb7, 0x8e7c938f, 0x339a1cd5, 0x2ba95dd8, + 0x12a0c00c, 0x5d9ce822, 0x907fad77, 0xee060df1, 0xf9b518df, 0xad9d6d74, 0x17056d9e, 0xa8d2c6c5, 0xaf298a59, + 0xfb2629a6, 0xe149b17a, 0x95d2638e, 0xdf48c44f, 0x6f3abd21, 0x5dbc6993, 0x65530e2f, 0xae423500, 0xc4fbbfeb, + 0xfdd7e176, 0xf39f7468, 0x24900562, 0xc1bca88f, 0x4541c5dd, 0xc434064c, 0x87a08336, 0xc908ef97, 0x7e18c2ee, + 0xf1064e71, 0xa7642622, 0x82b8dc03, 0x7f388420, 0x6e6ac701, 0xaa5a16f0, 0x191f3e8d, 0xac9f33a0, 0x1839bf93, + 0x2d5b93b0, 0xac780d96, 0xf48c29e7, 0x79d71ab0, 0x116abd19, 0x8ce67275, 0x0969e901, 0x7ffc3f3d, 0xd61997fc, + 0x7d6328e8, 0x5a16fe0b, 0xa8a3e303, 0x85454aa4, 0xa0471323, 0xe791cb15, 0x6042580e, 0x515abe54, 0xf6a7808d, + 0xd5e771c4, 0x3d07d8a2, 0xdf406248, 0x8da133db, 0xac1892fa, 0x4e8ea890, 0xdbe250c8, 0x1d68caa2, 0x410da178, + 0x3ddacf39, 0x6f81f884, 0xac4a35a1, 0xd84581db, 0xc11be06c, 0xc5f9ecad, 0x1796f0c2, 0x695e40c8, 0x2ca53370, + 0x5693a631, 0x95790b24, 0x964ed2e0, 0x69c51c05, 0x8080dd79, 0x22fc0afa, 0x4f741bc5, 0x1002a92b, 0xb86f4614, + 0xa6e12851, 0x3350c9e7, 0x8a2f2ec9, 0x41c2eaed, 0x07df9d63, 0x447dc144, 0x091c67cb, 0x68e6b110, 0xb702e318, + 0x7eda598b, 0xe191a7c1, 0x4e0ba090, 0x75dcbe98, 0x90b00f04, 0x5b267231, 0xb27f52bf, 0xaf5b2802, 0x38757069, + 0xbaeac964, 0x0b10c27d, 0x5cda3726, 0x8f35cf76, 0x215e5079, 0xf3519ae7, 0x95024bc4, 0x7c35bc04, 0xdcb471fb, + 0xcead1178, 0x285186eb, 0x2434b931, 0x2b55a005, 0xe1962385, 0x2b5ab2ea, 0xfe06bb1c, 0xc116fc54, 0x4821e49d, + 0x1a424cbf, 0x7e572350, 0x757f142a, 0x285973b9, 0xafe7ba16, 0x2f3a73f1, 0x1cde0d33, 0xb945b34c, 0xf6f935ee, + 0x9c6dbe53, 0x4ef886d4, 0xb76cd53f, 0x83be1a04, 0x434e652b, 0x507315da, 0xc4c3d7cc, 0x7bcd6606, 0x434f9fca, + 0x0fe00b49, 0x2a397256, 0xbb52ec89, 0x5c3d05b2, 0x0ab55cf8, 0x03aeaa5f, 0x15da750e, 0x6db7d469, 0x5434248c, + 0x63685c91, 0x900db82d, 0xc8af93a3, 0xc0fac972, 0xd0bcacb4, 0xf06f8360, 0x92b04ce2, 0xf8c6e72d, 0x45997f9f, + 0x4491c99d, 0xc19e0ba6, 0xb3d4efba, 0x7002dc17, 0x5e2e38c8, 0x5e1cdd37, 0x27f96147, 0xb495533f, 0x26449ce3, + 0xfa399425, 0xcf6613e9, 0xc7812398, 0x7bc31d1a, 0xb4a8d5b3, 0x679a2a6d, 0x59c203e2, 0x918147e6, 0x07194fb1, + 0x45f5ac03, 0xc7d5ab8b, 0x63d5f0e4, 0xe6ddf8a7, 0xc77844b7, 0x5aed261d, 0x5fcc4142, 0x75535136, 0xda518c86, + 0x7f0cee9b, 0x951972ec, 0x6a76cb7d, 0x9f5a7760, 0x95ab9216, 0x1e9325dd, 0x8907f8d9, 0xfe8c4fd5, 0xb94faea4, + 0x88afdce8, 0x46376e9d, 0xfe22f3fc, 0x97ea0636, 0xb4ecc54b, 0x738e8f53, 0xd1cacc53, 0x82485ff6, 0x59b7a122, + 0x5bf91593, 0x2f63a0b7, 0x0db68f3c, 0xa3eba1d6, 0x2454568d, 0x690dadf1, 0xda5a560c, 0x13d74317, 0x1d48f01a, + 0xabd3f13b, 0x2834c90d, 0x689e8a2f, 0xa75c2e69, 0x874bb412, 0xfe0e2db3, 0x24d2ee29, 0x9c9ca377, 0x8c5a92b6, + 0x7fa0aa41, 0x5a5f8651, 0x427b1e77, 0x540bb8eb, 0x073a8399, 0xed530c8a, 0x5fed09f0, 0x056b70f2, 0x13b34405, + 0x2a0fad6f, 0x0f362ee9, 0x5d37cb7f, 0x96a64c25, 0xa12922ab, 0x55a6a7b2, 0xe0d5f513, 0x7bd6725f, 0xbfd66228, + 0xcb7df5eb, 0x3e0f4b6f, 0xde596a0f, 0x5e757eb1, 0x6498ae24, 0x52653a62, 0xe9098346, 0xdaa176e3, 0x56fff30a, + 0x7c213b78, 0xc8cd1384, 0x8ff4aebd, 0x7bba66b0, 0xf5ed1cbc, 0xd3d22009, 0x294dd44f, 0x038ddda6, 0x72f5aee5, + 0x3a276c32, 0xd0084b64, 0xa7f1bfd1, 0x6701df88, 0xe78b8d58, 0xbb9166f2, 0x050343d6, 0xdcd9067d, 0x5c32b140, + 0xf170dd4c, 0x3148758d, 0xa74812bd, 0x12880609, 0x16bfda6b, 0x03a8b6f5, 0x9bbdedb3, 0x81dd9dad, 0x76b890cc, + 0x72edd190, 0x5e898110, 0xa85da601, 0xd6900d35, 0x3df2b422, 0xa6fe05a6, 0xb49972b7, 0x5fb262c4, 0xb7c981a8, + 0x0d604346, 0x49270e0e, 0xb5f4818b, 0x3c76e043, 0x929e75cd, 0xe96fba3d, 0xe4b7c54f, 0xec4847f4, 0x6895fa0a, + 0x06a1c192, 0x88850792, 0x6baf6989, 0xdef242d9, 0x60d278fd, 0xb3c77d6d, 0x520f6e60, 0xe65a3bc6, 0x208e8332, + 0x6c615065, 0x035c744b, 0xa8fda3be, 0x3183366b, 0x5eec7c60, 0x39940dfe, 0x17149bbb, 0x86ea7cb6, 0xdb764de4, + 0xe3753fad, 0x6985ff79, 0xf0b5c03c, 0x80475416, 0x9675d549, 0xcb1000af, 0x13e356f6, 0xe2d85167, 0x060c9b4f, + 0x35ebefb2, 0x41796049, 0xa35c6138, 0xc094b827, 0x00307b2f, 0xeabe88d7, 0x4e1656f8, 0x89252918, 0x8fe3e9cd, + 0xa1e88413, 0xfe4206bc, 0x3dea97ad, 0x166d7a76, 0x0166c4a8, 0x2ffa33b8, 0x8744ff76, 0xe4714f2f, 0x9c73b00e, + 0x2fa841fe, 0x07d6d256, 0xf644d0eb, 0x37e8b58e, 0x9027775c, 0x4297fa7c, 0xe98defc7, 0xc51d57ab, 0xad88b4c5, + 0x0761e98d, 0x1e76968c, 0xd025e7e3, 0x79acecbf, 0x2c963fe9, 0x86590b6f, 0xf1096b77, 0x3fe5bc22, 0xef4740f4, + 0x65e4c61f, 0x4a83fffb, 0x53e48e20, 0x3ad102d9, 0x0fb84377, 0x7cba70f6, 0x217a46a3, 0x5443e39a, 0x77b4da59, + 0xfc174021, 0x97959708, 0x852d8afb, 0xa0b36396, 0x570ddb05, 0x284f80b5, 0x502b765b, 0xe84942cc, 0xb770eff9, + 0x6263002a, 0x80019b3f, 0x8cd1ee55, 0x424743d3, 0x2a370b17, 0xa769a94b, 0x7e6503c8, 0x6faf16ce, 0x0891a5bd, + 0x76c25cf2, 0xb468c723, 0xc874162b, 0xf3f7adeb, 0xa9d4c762, 0x9041812b, 0x8fda1bce, 0xcd89bd43, 0x2b4bb46d, + 0x157a9882, 0x7627d408, 0x33e6d895, 0x8f16b4b0, 0x8e1abd26, 0x9f7884e2, 0x7402a8ad, 0xbbb1c7a3, 0xd52e335c, + 0x6f6d18ee, 0xcb6c4b76, 0xb896a407, 0x4538f24f, 0x1f838f07, 0x188f769a, 0x18277848, 0x5e478e03, 0x38533ce2, + 0x74235049, 0xc9eeb7ae, 0x46c4dba0, 0x67093799, 0x9d021c97, 0xe97d67b3, 0x499b43de, 0x25555bb4, 0xda4407eb, + 0x1711816c, 0xf7430816, 0x02460f86, 0x588ca372, 0x4057ecbc, 0xc5095f90, 0x4698e4d6, 0xb5c8f839, 0xf9821ce8, + 0xb57e6ebf, 0x8c254eb0, 0xcd35cd50, 0x67d2be0b, 0x206e16c6, 0xe18770db, 0x2d30c278, 0x4b94e366, 0x51e95ddf, + 0x9a9508c7, 0x379712c4, 0x6f35822e, 0xa4e61552, 0xe1b8b40d, 0xb7c6374e, 0x5af190b8, 0xbd205771, 0xfdc8d9cb, + 0xd29ceade, 0x7792e889, 0xb4d1666c, 0xb5c2ea95, 0xf1363c48, 0x7fd2dba1, 0x7275cccd, 0x23392ec9, 0x060722b1, + 0xc4897c7e, 0x4e0b2580, 0x3cfd7a73, 0xd5a3e393, 0x4fd3357a, 0xaa1f4ade, 0x032583aa, 0x3a3a6baf, 0xb4aa9f25, + 0xc774cf39, 0x41f64470, 0x2947bb9d, 0xeee13965, 0xb735b2df, 0xa9dca530, 0xd851c4b5, 0x28d3e731, 0xfbc11c2c, + 0x7151bcff, 0x64f06d6d, 0x8975a820, 0x028e41c5, 0x5e2f5388, 0x46ceac10, 0x4ee03105, 0xb1759a7e, 0x4db352c5, + 0xa7894144, 0xe2b84fe2, 0x2ee2c5a1, 0xb3cbef83, 0xda82d611, 0x74e22450, 0x62f576f3, 0xba477c46, 0xcbe5310d, + 0x9d7be74c, 0xa34f9fef, 0xb5a9b9a0, 0x5ceb06f3, 0x4174dc19, 0x934bb2cb, 0xb1928eaa, 0x1013e84a, 0xcca6eda1, + 0xfa789d18, 0x0c47e422, 0xd76ea934, 0xe877c68b, 0xe20278cf, 0x8d2f4cb2, 0x6479b8a1, 0x970d9518, 0x940fa1c2, + 0xd204b879, 0xb2854d20, 0xcd189c07, 0x09f2db8f, 0xced16026, 0x45c1c2e1, 0xd9d166dc, 0xffeea3ca, 0x49a7df1d, + 0x410c1b21, 0xd6b1ef63, 0x6c3b31ee, 0x9263442b, 0x4d3ceedd, 0x017fcbd3, 0xac20cc14, 0xb85b39dd, 0xbffa17c9, + 0xdeb565b9, 0xe2201509, 0x4df46247, 0x0b17c39d, 0x9f1cbd5f, 0x301dc9fd, 0xa8104206, 0x71f76596, 0xb67fe62f, + 0x824e1e29, 0x245690ed, 0x4f182b33, 0xbe9d503a, 0xe20a96b8, 0x06262410, 0xb2ec6954, 0x613c52a1, 0x576d7565, + 0xa25aac1d, 0xfeb8651c, 0x067e20f1, 0x539f702c, 0xa23ee4c6, 0xed7772da, 0x15bf3d70, 0x7f87156f, 0x6e454e7c, + 0x5815dc60, 0xa1c036fd, 0x2fadebab, 0x355ccc39, 0xa706ca41, 0x82a27870, 0xcd750e0e, 0x3d7f50e6, 0x2b678d4a, + 0x438317ba, 0x45f16d18, 0xdc901e53, 0x28b79531, 0x812530ca, 0x5ec13d16, 0x71a0a1a0, 0xba3e3342, 0x7037876b, + 0xfe78f808, 0x7e397e1a, 0x75707e0b, 0x13fd5f94, 0x4a6197bc, 0x08a6caa7, 0xbb2e5048, 0x954e7d5b, 0x67a63a74, + 0xd6a41140, 0x6c213a3e, 0xa20e8194, 0x33d0592e, 0xdd80bdc0, 0x47189906, 0xe4ea25fb, 0xcfb1f5c4, 0x10053631, + 0x55682878, 0x3cc9666e, 0xbf0f946a, 0x50af4034, 0xa0b561c7, 0x4caed1f4, 0xe94d38f1, 0xea42590e, 0x62d45a14, + 0x53213783, 0x3799b63b, 0x6d8f019e, 0x1eb48ccc, 0x5344aaa9, 0x7cbe56ee, 0xb9def1bf, 0xce8adec5, 0x33952056, + 0xc6d039c5, 0x053788f9, 0x8d74bca8, 0xbe7d5498, 0x61f005ec, 0xacb65510, 0x71f5a600, 0xa2ce6bad, 0xef2ad802, + 0x7637ddbd, 0x7ea44ce4, 0x935ec57c, 0x57b3e97a, 0xbaaf3010, 0x4e032e5d, 0x2c693263, 0x04c7c32a, 0xb6125053, + 0x75279d04, 0x4a3a3eee, 0x46e73f11, 0xce9988b0, 0xc302a9bc, 0x761fa8a4, 0x36d6a576, 0x3d206445, 0x04470c3f, + 0x1fd35239, 0xfda86395, 0xc3550b4d, 0x9f0c82a2, 0xb08c6d4b, 0xffe45631, 0xd25be98d, 0x1dcd79bd, 0x7bd8a6bf, + 0x2dae31e4, 0xeaed9636, 0x4d460cb7, 0xecfe1caa, 0xdd19505f, 0xe3bbab42, 0xeee08bb8, 0x912f2fec, 0xad448715, + 0xee58053e, 0xbce42f63, 0x852e30d2, 0xf9fa26a5, 0x4f65e06c, 0x731820f2, 0x0a79ddd2, 0x9e3b2675, 0xcb79db88, + 0x0f0060e8, 0x10d581ac, 0x434f9dfb, 0xd4452125, 0x765cca18, 0x20991c1b, 0x64a2c706, 0x2861e1a7, 0x9fe2701c, + 0x0ed3e9fb, 0xf406607b, 0xf5d4243a, 0x657eab08, 0x064dc48f, 0x2d128d9d, 0xbd0c298e, 0xd8dbd748, 0x1fdb387b, + 0x516e94f8, 0xfd0a6fe9, 0xa94d19c6, 0x8e498adc, 0xbd6c825a, 0x134917b0, 0x134ec430, 0x4a9e0cd5, 0xf159065e, + 0x457fb84d, 0x5337fba6, 0xc998b80d, 0x07c4b5ac, 0x10a5bab5, 0xcd8e4ee6, 0xef7d11c4, 0xa6c718cc, 0xe6aa258f, + 0xc4cccc3a, 0xd070fa2c, 0x63faf703, 0x9c0e11ac, 0x48fb56ec, 0x96c8aec1, 0xbf4d2a0d, 0xe468016a, 0x075ba1ba, + 0xedb5a7b1, 0x2cf56a62, 0x830abda7, 0xe1d3edcf, 0x4c2875bd, 0x4a7d98b4, 0x944f9948, 0xa4350e27, 0xe117ea0e, + 0xd172a256, 0xa7a17765, 0x52cee3f8, 0x0b412173, 0xb0aef278, 0x9f6a61f3, 0xf4bd0703, 0xec8ea5b3, 0x036d757e, + 0xa1ee0704, 0x292c823c, 0x005ab03a, 0x335935f2, 0x3bbd1c6d, 0xc08ec8f6, 0x98274126, 0xda1f4cd9, 0xfb401254, + 0xf73ae989, 0x9f949746, 0x4d64d501, 0x42b442b3, 0xcdfa9486, 0x46edfd40, 0x11ea21f8, 0xf20f5702, 0x0e65d9e3, + 0xf42a75ae, 0x9e9e538e, 0x803139de, 0x523d13ac, 0x13474513, 0x0c4f75ec, 0x27cc5ceb, 0x9c4bed26, 0x72531372, + 0x253facf6, 0x03690ee7, 0x8add4d17, 0x022607cf, 0x13eb99f6, 0x931f551c, 0x0b92ba36, 0x7351b37b, 0x148d5c07, + 0xa82dace4, 0x785c35dc, 0xaf750929, 0xb1443ac4, 0xdd1138dc, 0x92b0e180, 0x23abb58c, 0x0fd6954f, 0xb280a525, + 0xcee20bad, 0x58a7a953, 0x801bfcd5, 0x89232d83, 0xf19f9246, 0xb9b30b06, 0x4a05e2db, 0x76ec7feb, 0x879b750c, + 0xd5a3822e, 0x5233d7c3, 0x274ea04a, 0xd049653b, 0xc414a978, 0x7e93cf25, 0x419d5e82, 0x64a53fcc, 0x8ba3ff5b, + 0x9c887e7c, 0x792e2f70, 0xdcdf2c86, 0xcaa1e232, 0x2bf1a2cd, 0xce230f03, 0x218620e2, 0xee98fbdf, 0x87897d24, + 0x4c231931, 0xa17eb4c4, 0x0ec82763, 0x13b35883, 0xc23154db, 0x1e6a4634, 0x382afcf0, 0xb0357dd0, 0xadcd430e, + 0x63de2d05, 0x12e666b4, 0x09a958af, 0x03223fbb, 0xd6345ee4, 0x74d402f5, 0x237119ac, 0x1088c309, 0x700e776e, + 0x89f6df8b, 0xdd38d1e6, 0xeacf7c78, 0x766765aa, 0xbab0ec8e, 0xa2c70075, 0xd0393f4a, 0xfb880b1d, 0x61daf25d, + 0xdf66895a, 0x9aa37207, 0x4537b368, 0x6b6ce888, 0xab03d5a2, 0x7f64674f, 0xb52f38fa, 0xcf85d1bd, 0x702f88ea, + 0xbc4174bd, 0x186dfdee, 0x0e342ba4, 0xc045ff3a, 0x89fee3b1, 0x726e76fc, 0x6739292d, 0x9e047545, 0x7ed94b4e, + 0xf3d89bef, 0x209b2fd6, 0xba20fa41, 0xd851ac74, 0x28da267a, 0xef98dd93, 0x991debfc, 0xaf3d80a8, 0x90a437e4, + 0x0a71f5c8, 0xe4313d6e, 0xc089db82, 0xb02a80fb, 0x5726a5a2, 0x1fb9c1b0, 0xa7b21d79, 0x81ef8c24, 0x27293fc5, + 0x50ef1876, 0x61d35b77, 0xfd589d91, 0xb3d05c3c, 0x8062a647, 0xfbfd65d1, 0x00cee376, 0x35cc46c6, 0x9d0a4aa9, + 0x1f113bf0, 0x6c544b1a, 0x6075b43a, 0xaa914d12, 0x00edf7d5, 0x25427b04, 0xf3850b61, 0xf8eb7f66, 0xb783d7ff, + 0xd245d633, 0xe7dd690e, 0x63c2885f, 0x08fce9ab, 0x50392363, 0xd814fb3e, 0x31daf81d, 0x2d2c5186, 0xfc3cf64a, + 0xf60eabe8, 0xcedcde29, 0xf4648b21, 0x9661e8a4, 0x7629831a, 0x6a21888a, 0xd58c4dab, 0x58a03532, 0xbd3f5e8e, + 0xdcb9e023, 0x8b8148a4, 0xea56b89b, 0xe31bdc66, 0x70b8ab0d, 0x46d1b3bd, 0x43c86012, 0x304b84c6, 0x7646318e, + 0x6b6df343, 0x55047b56, 0xe4eb178a, 0x2740d414, 0x2f062c6c, 0x2bb87ab3, 0xbbe46759, 0x604592fd, 0x28034951, + 0x5a41d5b0, 0xab3cda0a, 0xec016b00, 0x7892a766, 0x69a55747, 0x5efc7560, 0xddc2a900, 0x22eb94af, 0xe60437d1, + 0xee44e8d3, 0xf371cc73, 0x4e5e6e7b, 0xdbcc442f, 0xbb2f778a, 0xc6d98bd7, 0x18538d40, 0xc979f0e9, 0x4f4be0dc, + 0xa638a6cb, 0x5d0983f6, 0x3e3bb206, 0x571d88fb, 0x241c6359, 0xad67b501, 0xb6253cd2, 0x79c59d55, 0xafd3041d, + 0xa62d0004, 0x939d6fb7, 0x92955860, 0x922f19bf, 0x031a3537, 0xddbb38eb, 0xdee7d821, 0x0207fc68, 0xed548b3b, + 0x70886283, 0x79e8ae43, 0x367892f5, 0x871499e9, 0x27cd4b86, 0xec865f04, 0x7ff18368, 0xe629f3aa, 0x624fc9d6, + 0x938a106c, 0x6d8a7a9e, 0x8c804933, 0x3eb5d6f5, 0x536d60a2, 0xc850fc9f, 0x27332521, 0x4c30fb35, 0xb3387981, + 0xc81f3618, 0x6d1dbdb0, 0x2fa4e5aa, 0x3c182f7f, 0xce06706f, 0xa6f76bf5, 0xb8accd9f, 0x859b6f01, 0xd172b494, + 0x172f34c2, 0x846b960c, 0xa75fb178, 0xd6a4d265, 0xa1821835, 0xb6983095, 0x4be9130c, 0xb56711c4, 0xc5f76010, + 0xdd2010a5, 0x8e85fc3e, 0xf5002fe6, 0xb5fcd270, 0xcde65a92, 0xf4f7ebaa, 0xa5171728, 0x596ed1b4, 0x8fe0487e, + 0xb3a452ed, 0x7be9762a, 0x937f6834, 0xb7ccb972, 0x33e38e1b, 0xc4b79540, 0x8d6936aa, 0xb7f57e24, 0x9142146f, + 0xc0aad048, 0x355f47c1, 0x94d67bef, 0x3f5f66f3, 0xa06f3bc5, 0xca821f31, 0xa3d1b427, 0xe09286e0, 0xfbb49e9d, + 0x22cd5984, 0xde3fbaa9, 0xf1228b0a, 0x109a0b9f, 0x7548c33b, 0xe941dbb2, 0x93f95e81, 0xab081a96, 0xdf747884, + 0x45ed0016, 0xbdb948f9, 0x52666432, 0x2294a781, 0x66b25bb4, 0x2335dca4, 0xc636dc96, 0x766687f4, 0x8273259d, + 0x856f58b2, 0xc5311f4e, 0xfa666467, 0xdaaee17d, 0xf5d22468, 0xb94d77e5, 0xe3ccd5cf, 0xf71ff3d5, 0x059c47e0, + 0xa2677a6e, 0x3690bf4a, 0xf7915003, 0x836ffa5f, 0x8a3df18d, 0x838d8411, 0xb6b54740, 0x5b2ba5a0, 0x2d8db59f, + 0x745bf9cd, 0xec9e0e62, 0x8bb57884, 0x5b5f6d82, 0x44be8f59, 0xe3ed39bb, 0x4ef5119d, 0x10c90758, 0x4c3de02e, + 0xcc0dcdcd, 0xae35ebaa, 0x8b079813, 0x707f4cd4, 0xb28ee485, 0x868e1475, 0x98dd2c9f, 0xbf7e4f5b, 0x2f2378c2, + 0x7e997fca, 0x0ae36578, 0x0714380e, 0xf942af1a, 0xdc924a4c, 0xd462660f, 0x73b985b2, 0xb3443ec0, 0xa79c0a43, + 0x74a7a67a, 0xd1d2f722, 0x3e9d04ee, 0x9a4e1195, 0x626273ff, 0xd2403034, 0xc4a06a7b, 0x59830abf, 0xe25c52c7, + 0x835a60fc, 0x74890b67, 0xba57e1c8, 0x16fd9a93, 0x318964d9, 0x73f3c4e9, 0xc8dcb69f, 0x6b19cc12, 0x848795bf, + 0x35bb1c1a, 0x1e328ed7, 0xb0f9eecf, 0xfcf7d0ef, 0x18084914, 0x41866a66, 0x9a53ef73, 0xc80279e4, 0xfaf76d6b, + 0x6bfc3811, 0x806e5e41, 0x939565a3, 0xb3aac7da, 0x8c29ef06, 0x40ee7f8e, 0x158b6c83, 0xff4fde31, 0xeb907b6b, + 0x1cae2e23, 0x0f2ee3c6, 0xb1695a77, 0x7347da79, 0x16ffd074, 0x4ac8b21e, 0xa36836e4, 0x96d832f1, 0x4f52a03b, + 0x87320d38, 0x4a9b3d5c, 0x96156427, 0xe0010793, 0xca4bb547, 0xa85f29a8, 0x85ee6d70, 0x507197f5, 0xc5727a49, + 0x1ca129bb, 0x87b85090, 0xa54860cf, 0x26e5a790, 0xd4b4c87c, 0x32a58dd1, 0xda70783c, 0x6331fe08, 0x6d5cf3c2, + 0x5ea90f67, 0x7b234c8d, 0x82709b2f, 0x6aae16ed, 0xfe8fb430, 0x91aae7a4, 0xa89c8475, 0x9ee038e1, 0x46752770, + 0x607bc2b7, 0x5a43428f, 0x22c889f2, 0xbab3c6ee, 0x0fac61b3, 0x75dffa55, 0x23d02d78, 0x9e425bb5, 0x59b2e2a7, + 0x9840368d, 0x0d7daf83, 0x5038f381, 0x1a2ca12e, 0xb796b6c2, 0xa8f2aaec, 0x08085d45, 0xe666f976, 0xd77c5ea8, + 0xfaa8692e, 0x89b8d180, 0xe3c2705f, 0x16234e9e, 0xcd4e4fc6, 0x870800df, 0xd723a9ec, 0x93aa6197, 0xccb05bc4, + 0xecf009cf, 0x228d7786, 0xcb35fff7, 0xe9dfde8f, 0xaa78f2a8, 0x3bdc97dd, 0xb0e60ac5, 0x8a238fa6, 0xb42b36b0, + 0xd0948639, 0x103bc6e0, 0xb9c624a2, 0x9ac7ee52, 0xe1bb553d, 0x25ba0f2d, 0xec5a50f0, 0x525071c7, 0x32ae5317, + 0x3664176c, 0xfd6e1cea, 0x40da8e5a, 0xfa450d23, 0x75246f3e, 0x2929379d, 0x8e9b60ce, 0xc0bbf00c, 0x2f72727b, + 0xe43257a4, 0x59a0fd18, 0x3a0585aa, 0x14ffc421, 0xa4ac0cad, 0x20346223, 0xac05560e, 0x3260af53, 0x4f0f2911, + 0xb7f749b1, 0x8dcbfebb, 0x6ed1040a, 0x9cf320de, 0xf91b5c8c, 0xe75e20c3, 0x167f9681, 0x6d2bc888, 0xc4fd3e7e, + 0xa6d9b333, 0xa4335f14, 0x6e3a8d38, 0x29812b76, 0x5f52e568, 0x8a9c434a, 0xde78bff1, 0x29a8e2fe, 0x1d19a3dc, + 0x79913344, 0xbb8e2c30, 0x7c5008e1, 0xffdcb3ba, 0x8d89d735, 0x08916038, 0xc72a7f5f, 0xbcc988f6, 0xd5eee570, + 0xec92250c, 0x5a7c4a47, 0x6d2e33a3, 0x24cb0d60, 0xf70685c8, 0xa3c806a0, 0xbdfae84b, 0xa4a67943, 0xe9b91b21, + 0x9e013594, 0xa81e232d, 0xe8e588ad, 0x775119cd, 0xcf750bda, 0x0ece7f14, 0x175b7be9, 0xf32b1a39, 0xc463947a, + 0x3edfb896, 0x0bfb16d6, 0xaf65c608, 0xdc641073, 0x0f7eac7c, 0xd323ac96, 0x4274a6eb, 0xb4292188, 0x5c04680f, + 0x2d95a695, 0xf4c315b7, 0x3316c523, 0x115295a4, 0xc9d3a324, 0x9b7ef8ea, 0xd92832f6, 0x57361199, 0xc0aeaf06, + 0x84240756, 0x603a8729, 0xbdb675e5, 0xb5ee6993, 0xaa403ec0, 0x389ab29a, 0x0479b39a, 0x0c17e0ac, 0x06d9f9db, + 0x8153fc3f, 0xc6f01456, 0x4fcc2b64, 0xee3c4364, 0x592f68c6, 0x63033033, 0x468cb226, 0x98df9e53, 0xff5036ab, + 0x1c0261cf, 0xd05d7071, 0x44465e19, 0x218ddb59, 0x77c47d9c, 0x9c69cb51, 0x1d2d5bfd, 0xbaeae40d, 0x5ea9b1e4, + 0xcf79acb9, 0xdfbecf79, 0x41fcebcb, 0x80dac72e, 0x2c7c1d77, 0x7ecee1f2, 0x72f4ac6c, 0x0b6a4925, 0x8467441f, + 0x14086e24, 0xe4d38856, 0x39702da0, 0xb8d98fef, 0xb98c2fc4, 0xa8e8edbd, 0x7eff0e27, 0xff3961f2, 0xbc14a79b, + 0x1ade7ff7, 0xf7132d2c, 0xb4416c2d, 0x1391c607, 0x233504bc, 0xc101cf9e, 0x576cc7c0, 0xb4fd6643, 0x5b3022fd, + 0xbf7d2f89, 0xddad1e2c, 0x282c78b4, 0x379a1549, 0x829e057d, 0x0572624e, 0x82317a72, 0x30903914, 0x5f9a21d0, + 0x6a4a1f7e, 0xca77d649, 0xd3418bc3, 0x2f29ee21, 0x9b4cafc7, 0x9e341421, 0x37d49fa7, 0xb84eaafd, 0xfd0a27ae, + 0xc4164067, 0x45dc9bed, 0x9eae801f, 0x5ff14c89, 0x545d3e16, 0x9a50bff8, 0xa4b473df, 0x5ba988f6, 0x1cbade3e, + 0x842b2979, 0x9f8e6bf9, 0x4a9985d4, 0xc20fced3, 0x606207c5, 0x0ffa2256, 0xfb44070d, 0x9b0cec7f, 0x4c1e5290, + 0x732e376d, 0x9d57ab15, 0x82965f34, 0x547e001b, 0x423c95ee, 0x87af89c8, 0xeaf9f712, 0x73850839, 0x55806767, + 0xb7c8377c, 0x29e7e714, 0x0516ad4d, 0xc40e9db2, 0x6bfd6dc6, 0x3a673e44, 0x2230a6b4, 0x66252f81, 0xdf4c86a0, + 0xecf42312, 0x5c589a47, 0xbbada40b, 0xfff3876c, 0xbb138b23, 0x979443c6, 0x6d5f1657, 0xda42d439, 0xc07f15dd, + 0xc363ddb9, 0xd33ff22c, 0xf9937c80, 0x38b30d82, 0xa1db1672, 0x2b3eac71, 0x67b4a8c6, 0xd1c19faa, 0x69cfc6ca, + 0x8c3026e7, 0xa188d3d8, 0xa892578e, 0x2161b6a0, 0x50c75ff5, 0xbb382b9e, 0xd22734e0, 0x71a2c96a, 0x80064848, + 0x62541ad0, 0xc59933ca, 0x3802e3a2, 0x7ffebca5, 0xc42fe47c, 0x1f9b0e66, 0x9e467753, 0x3bbaa10c, 0x9e376c80, + 0xc50a17f2, 0xa004f8d3, 0xccf4612c, 0xdcd3fac3, 0xb3404869, 0xcce5465b, 0xf5a8e022, 0x8d65bfbe, 0xc20cf2dc, + 0x4b06c247, 0xa1233135, 0x7e714e25, 0x88c8d7ff, 0x3e1bf788, 0x1256e988, 0x0f1ee492, 0x1ab61db0, 0x7703de3d, + 0x8b06d9e9, 0x56f112cd, 0x9c92dc4d, 0xab4f9bf6, 0x5badc60a, 0x36d9c113, 0x538b686a, 0xcbf9fb04, 0x25486110, + 0xe8164d57, 0xb6399585, 0x0dd561d0, 0x390e448f, 0xbd2738bd, 0x3a6bd084, 0x6e6fd2ce, 0x33eb46dc, 0x9851d49f, + 0x7e8956f2, 0x8a7133d2, 0xcb330bbb, 0xdf5452f4, 0x5cce6b37, 0x192223b5, 0x037890d7, 0x6839bce1, 0xe26e7626, + 0x842a705f, 0x623c3d5b, 0x367124b5, 0xc933a1f6, 0x263a7c9c, 0xe431756d, 0x586b640a, 0xeeadc0f0, 0x8a486fe4, + 0x74a0cc95, 0x94bcd961, 0x587a22d9, 0xf7ea06f6, 0xfdf978a0, 0x779979d1, 0xc667caa9, 0x0d223ca3, 0x31fa3620, + 0xeeeb21ce, 0xcc59875c, 0x0b36e640, 0x13f41cab, 0x58bad0b4, 0xe17f8eae, 0x44385a31, 0x8cba2cf5, 0x6814bf57, + 0xb5024a07, 0x0ae63377, 0x07dc4e7b, 0x28611a81, 0x4bad52c7, 0xe960870e, 0x7d4eab49, 0xe15b0826, 0xd4f5173d, + 0x6477ae2d, 0x419e522c, 0xa0d4c196, 0xec5c0366, 0x1450a111, 0x7fd76067, 0xd733a95a, 0xde2d316c, 0xb129c365, + 0x82326406, 0x86f2aac0, 0xa4b44353, 0x55485008, 0x60787fd6, 0x34022e64, 0x24ad19bd, 0x7533b42a, 0x2f3004ea, + 0xb3e2880e, 0xf34f6bdb, 0x31482889, 0x1cb00ae2, 0x60bf8565, 0x91a44186, 0x4d8cc0f0, 0xb42fae44, 0x71a5b90b, + 0xc9b216c8, 0x14f2b0aa, 0x2538a209, 0xeaa5d60f, 0x1dcd1483, 0x634dbd70, 0x05b036e2, 0x9e732c4f, 0xda05f6cf, + 0xa43365f2, 0xa1707719, 0x3d3ce930, 0xdaa201f0, 0x260142c3, 0xd5f2eaec, 0x26fc10a7, 0xc10f044d, 0x64b4b7e0, + 0x8b092cd1, 0xc5895c41, 0x5000db1f, 0xdf42aa2e, 0x92bffd69, 0x2b6f4b10, 0xfab8fe75, 0x8aabc5f6, 0x6fcf6030, + 0x1d5eb255, 0xc92d1a42, 0x05af67c1, 0x0df3fa0b, 0x1e041187, 0x1cdca169, 0x708bb289, 0x23adeaf5, 0x51b310ed, + 0x5979e282, 0x8acacecd, 0x53edb1ba, 0x5d1b0d71, 0x66fa8b64, 0xca50c67f, 0x6d9a8c51, 0x9bee1f78, 0xa07140b1, + 0x0ff494ac, 0xcffe116b, 0xf83e53f8, 0x11dc38b4, 0xfc0dbcb2, 0xd24d8174, 0x2a655ff1, 0x70f43419, 0x57e3aa8a, + 0x53da271d, 0x1a8b093c, 0x97434db6, 0xe40dffb2, 0x4b483d24, 0x70b51f05, 0x3d25e3cf, 0xe9472a16, 0xab88c55b, + 0x9ed43be3, 0x88d16f4f, 0x3a6b03a8, 0xadba6e7d, 0xd020f1c3, 0xb91e3ba8, 0x80f70de7, 0x2ee87a08, 0x528bcfa9, + 0xbb8d139e, 0xe44eb0fa, 0x3407e146, 0xeab0939f, 0x67bcb76b, 0x126663fe, 0x29682343, 0xa3edf195, 0x9d03ed8c, + 0xa710d32c, 0x0aba1ed8, 0x1f896dec, 0x8087b0a7, 0x15d60007, 0xd5ea6a47, 0x29fa3111, 0xf40375b8, 0x1b9f8988, + 0xc80c56d2, 0x39094020, 0x55b2d0bd, 0x1806b1e7, 0xc60ede03, 0x2e1de5d5, 0x11ca6ff1, 0xe6a5afb8, 0xe522f2e4, + 0x5df4d01f, 0x8e995072, 0xafb69320, 0x52468837, 0xbf4f5fdb, 0x33576ede, 0xad1d994e, 0xe953b081, 0xed2d5aa9, + 0xe89caa77, 0x86a00626, 0x084613b0, 0xc421434c, 0x97feb9b0, 0xadb154a2, 0x75f69eab, 0x874bf2ff, 0x3a0aff49, + 0xfd987a4e, 0x0d18b1b8, 0xb43c6d89, 0x15ce6556, 0xe1225c5d, 0x66de985e, 0x3d2038e3, 0xcd8bcb36, 0x3ada39ef, + 0xf3292eb6, 0x31c80d29, 0x7acfdcd7, 0xab0e8543, 0x9d789e8f, 0x3ef02323, 0xa0369754, 0xfa7f57cc, 0xef623b13, + 0x0698b8ed, 0x7b35142f, 0x8951cf78, 0x34d67a2c, 0xa5170445, 0xbe7c7d09, 0xf63ea350, 0xa4610859, 0x3002c035, + 0x0e30abac, 0xebc2a1df, 0x565ec8c8, 0xe1f78a5f, 0x5eaab708, 0x577dda71, 0x1b21ae97, 0x67d33082, 0x731e1b8e, + 0x9fa4834d, 0x20332fe1, 0x2871ea13, 0xb2506147, 0x3d216fb5, 0xf38852f0, 0x2abac208, 0x47dd73a4, 0x97f5fe0d, + 0xcadf83a4, 0xd2b1e702, 0x11e3c2f0, 0x2319d4ea, 0x7631adb1, 0xdf082a70, 0x030998f7, 0xd19d73f3, 0xbae361de, + 0xa37ca9b0, 0x65dde843, 0x82339586, 0x44191089, 0x83ef815d, 0x6c404b60, 0x69f747ae, 0x2c75627a, 0x6a3d8a76, + 0x54d03afe, 0x0e702436, 0x87618700, 0xa92f594a, 0x785dbcc3, 0x9c762f33, 0x8a35d8b7, 0x8b68856b, 0xf7a72986, + 0x3412720e, 0x4ae419cd, 0x8a7fde4a, 0xefcf02d0, 0x47c51b4e, 0x7e097801, 0x4e5e538f, 0x42ee1e3c, 0x79e9735a, + 0x84ec1d4c, 0xf492ec1d, 0x1e394b3b, 0x5a1df63e, 0xcf41e103, 0x3f424d54, 0x4ae3c55b, 0x3b4bcf51, 0xe006bc85, + 0x6a882dae, 0x07c807ec, 0x8ecd3f6b, 0x510ebde5, 0x40e8ea11, 0x1a947e6b, 0xd829138c, 0x10152437, 0x2867e431, + 0x1ffbab56, 0x12aa1847, 0xc00c7371, 0x46c55518, 0x42d66f3d, 0x7397b1bc, 0xa51db72f, 0x620cd3af, 0xcc51ea2c, + 0xf910d205, 0x325024a8, 0xbedab9f6, 0x847b597e, 0x53153261, 0xf5d301f2, 0x8b30f7b3, 0x967ec7ec, 0x9cc462fd, + 0xcfb4b559, 0x2f0b9835, 0x63d53406, 0x19bf36c7, 0x933e43b2, 0x5b494147, 0xa3f63023, 0x3b64fb54, 0x56787769, + 0x2f1a4f27, 0x07dfeb95, 0x0789b310, 0x3519475b, 0x35bdb28f, 0x4b8f549c, 0xed8b9634, 0x12dfade5, 0x3e484f1b, + 0xee53f86a, 0x7fdedc44, 0xef45cf13, 0xf836a949, 0x0c90b222, 0xca47a7ca, 0x0ab61bae, 0xfdd2ff22, 0x986391db, + 0x02df7ced, 0x58ee6dd1, 0x6ca7e8f4, 0xbf22b223, 0x20909a6b, 0x97bd3ca2, 0x39df16e5, 0x8ae78f74, 0xe326f58c, + 0x794cb404, 0xc1892f8f, 0x322ba43e, 0x205e982e, 0x6c87f5b8, 0x53979612, 0xa16b852f, 0xb8366878, 0x20e9894a, + 0xbe482ca7, 0x4e6e7478, 0x1def935f, 0x765b562d, 0x52f3fce8, 0xc657f8a4, 0xb48f2264, 0x3f208672, 0xa169ae61, + 0xc02164d2, 0x4b94daae, 0x02edafbb, 0xfbd26497, 0x20d9a57d, 0xe1509bf0, 0x451d06e4, 0xc3f102b6, 0xd811cf88, + 0xc3c22be1, 0x256a84bc, 0x10ed841e, 0xe1253333, 0x8ebc1154, 0xc0fe3ec9, 0x261a0cd5, 0x03294586, 0x75e0cd97, + 0x0f46cdfa, 0x84e83ae6, 0x5f54b283, 0x68d913df, 0xcd12c142, 0xe8e9a925, 0xf40818f7, 0x6aa14985, 0xd2975ab8, + 0xf30b256c, 0x04636e74, 0xd738d3dc, 0x73ad7d46, 0x14de12b6, 0x9efe7bdc, 0x525c546a, 0xd5090040, 0xd7bc9785, + 0x572aa464, 0xe8654954, 0xb0c9dce3, 0x48d2e36a, 0x24803cac, 0x989995fd, 0x4d65a34e, 0x3b36f8e1, 0x27703d73, + 0x6504a0cb, 0x587f566e, 0xe067e6e3, 0xd3ce0f64, 0xfd482ad5, 0x449ba984, 0x2d536a80, 0x95f4e22b, 0x36d842c6, + 0x4412332a, 0xa86fb1c5, 0xea6db14f, 0xed0f3b73, 0x7e709a37, 0xaf0ee520, 0x9f9b3aed, 0x9cd9a8a7, 0xd171ab41, + 0xc666a9dd, 0x1b277af0, 0x918debf4, 0x7292386b, 0x0e0407cc, 0x84451046, 0xdf657582, 0x0b1c6750, 0x08f035a1, + 0x600f7988, 0xe7a3a047, 0x86f28e02, 0x73cd2126, 0x3dfeb7d2, 0x6547f858, 0xcca05932, 0x34e98328, 0x89f8ae79, + 0xcfbfcfd7, 0x0a011590, 0x77e0197d, 0x76fd8545, 0x10539b9c, 0x52438e43, 0x3abedbf8, 0x2098b213, 0xd582ba3a, + 0x01117b14, 0x4263361d, 0xaa6ea4a1, 0x03b3682a, 0x84f77bbf, 0x0edd1c00, 0x600a11eb, 0xd43dab62, 0xde64a3a0, + 0x4caad086, 0x5ef5336d, 0x4aa8fa05, 0x40992438, 0xac9c940b, 0xb3d53891, 0x19906f9a, 0x6408f173, 0x662b327b, + 0x4fda62b3, 0xe9600181, 0x518a6df6, 0x85c58453, 0xbb5192ac, 0xe63856eb, 0xa6ed1cdc, 0x20602989, 0x393a61af, + 0xf5579ef4, 0xe20bc1c9, 0x5ad4e14c, 0x198b990c, 0x9c52011d, 0x16e5fbfc, 0xfea51813, 0xc3f90250, 0x571a693c, + 0xbcfed06c, 0xb2f26451, 0x4d8b2cd0, 0x00dbbdc6, 0x85202d13, 0xb810d5ab, 0xb5ba9640, 0x9fa07308, 0x4ac0af6b, + 0xff4c2c24, 0xd09daa0d, 0x9044ab06, 0x964d4175, 0x88f556c7, 0x656e31f2, 0xe0087fe8, 0xc432b408, 0x2ede3bd6, + 0x61c48166, 0x528a872d, 0x8e899bd2, 0xd00d72c5, 0xbf3115d5, 0x67f99831, 0x8cc78a29, 0xecf09b29, 0x217e765b, + 0x270c9319, 0x11837a57, 0x1fc7632f, 0xfe2e7a9e, 0x86cfdffe, 0x70c92ffc, 0x6b441d92, 0x0544e9b8, 0x66a6c138, + 0xac2657c6, 0x3b3cfa95, 0x1b643440, 0x2ac617b8, 0x1bd24ba1, 0xcd53149c, 0x6bedfd32, 0xcaea4f5f, 0xe0f2d53a, + 0x32222cce, 0x62f04f78, 0x281c4aea, 0x92f1d746, 0xddd30925, 0xbce5006b, 0x1964137d, 0x2f339eff, 0x073b06b9, + 0x3806fabd, 0x7cfdd1de, 0x8ea92392, 0xca2bf0c7, 0x6f19258a, 0xf3dfff39, 0x838e7d04, 0x21ee01b5, 0x4f79ad31, + 0xc81dec10, 0x8a021570, 0x032740a9, 0x671404de, 0x64b4f318, 0xe425749a, 0xb9f196ad, 0x752ca164, 0x55918347, + 0xfb3cbd07, 0x4a250a48, 0xf90af985, 0xdf827279, 0x1ff54a6d, 0x73a2e24d, 0x9d8a17a6, 0x22953d50, 0x9ec66708, + 0x21716936, 0x9ff27cd4, 0x66cabc9a, 0x7b15b7f9, 0xafa68161, 0x63ea3760, 0xef7e1f6d, 0x733d72dc, 0xebc902dc, + 0xaa8ecd95, 0xc633714b, 0x77cc13b6, 0x997bfd96, 0x289ab7ca, 0xeba7a264, 0xfd5c5651, 0xc3411a5b, 0x5d834ba4, + 0xd8bf1606, 0xdb24fb68, 0x1b3b9b6b, 0x80bb8791, 0x3f087e8e, 0x41c60f54, 0xe00c8f0a, 0x325554ec, 0xd1a0e434, + 0x4544b041, 0x9c42a29e, 0xb11832d1, 0x5af8ea30, 0xf9a79ab1, 0xb003d5a3, 0x942ca953, 0x582c8920, 0x2db624e1, + 0xe1424060, 0x412a9157, 0xc18d9a94, 0x68a427e4, 0x21cad876, 0xba1be04a, 0xd1ef84a9, 0x08988413, 0xe359ea1f, + 0x4cfe8dbe, 0x59863e1e, 0xf8327125, 0xd9f1753d, 0x77b4a25a, 0xf8b114c3, 0xf4259e25, 0x3d952dfe, 0xa0191376, + 0xe09dcb7f, 0xb761cbca, 0xfede9076, 0xb1404d99, 0xe1fc4db2, 0x00f50f6f, 0x7ae04d6c, 0xb339f845, 0x8ed71398, + 0x3a737281, 0xd04cef9f, 0x57a1615c, 0xef045732, 0x04503c6b, 0xddac7645, 0xa8f9f113, 0x61ef0675, 0xd21eb19a, + 0x0c4d93f9, 0xa485da9c, 0xf2ce65dd, 0xf2245f2d, 0x92090dc0, 0x72d599bb, 0x286d1e79, 0xad640608, 0xc7acf68d, + 0xeda7eb5d, 0x950e6744, 0x3922089f, 0x7b3037f8, 0x9e11b096, 0x7a46bb38, 0x1a15acac, 0x35902c06, 0xcc114eb1, + 0x81e319c8, 0x84c439d1, 0xafc550bf, 0xdc85cf14, 0x696e8ab8, 0x0a2ca729, 0x47c2502e, 0x8cf7732d, 0xb7589765, + 0x076ee187, 0xc4e26443, 0xe1c28f20, 0x8e01fc17, 0x97d32480, 0xcabb61d7, 0x82130285, 0x05aa1ce2, 0x6fd4ffdb, + 0x679b3fe6, 0x3454908f, 0x471e3edc, 0x36336495, 0x0a4739a7, 0x67cbf051, 0x6af0d047, 0x7da98fbb, 0x66174df0, + 0x8f75cbfa, 0xb42d0bca, 0xadceb870, 0x049a5a91, 0xa70439f1, 0xbe5b57ac, 0x856f0055, 0x07805fcc, 0xff4a7940, + 0xba3dd26e, 0xcbe3efbb, 0x90fd3ca6, 0xef180cad, 0xd49a2fe1, 0xeac70e33, 0x47640130, 0xc80fbcfd, 0x60d37b9a, + 0x66157a7f, 0x33b6be90, 0x9b7f1b83, 0x896fbe7d, 0x638886f4, 0x39b0322c, 0x37dcee0c, 0x54771a0c, 0xba7dd17e, + 0x19846706, 0xc08e1d00, 0xe17af913, 0x3221206b, 0x4eab89c7, 0xe589fd1f, 0x42b34450, 0x7fe711da, 0x7d235a38, + 0xbd725ee7, 0x8abcfd6f, 0xff5eb551, 0xdefdf921, 0x11c61d72, 0xc184d800, 0xe0f21ede, 0xbca2053c, 0xd7cce490, + 0x477fd3a2, 0xfef06802, 0xe205b0a1, 0x6796703a, 0x55a826c0, 0x91f7cd58, 0x28fe3da1, 0x68d27f1e, 0xa154309a, + 0xbd85d001, 0x4676e242, 0x2a4df060, 0x48767dfa, 0x7ba2eebf, 0xc3477ae5, 0xaf147174, 0x91fba18a, 0x2784b532, + 0x753a8929, 0xef7923b6, 0x840468d0, 0xee3c5ecc, 0xb98a6df0, 0x6b1977af, 0x59d7d858, 0x044e36dd, 0xc6441e11, + 0x5ab4eb9a, 0xd6954d71, 0xdbeb3110, 0x2ee22ed4, 0x3b09d65e, 0x226ceb8b, 0xf27a3424, 0x09bf27c5, 0xb1c9aac3, + 0x2db6a327, 0x3e15b3f9, 0xaab2e756, 0xd553ed67, 0xb694dba3, 0xee34f592, 0x23381868, 0xbb0d2b4f, 0x20a3cbf8, + 0x31daf122, 0xaf83621e, 0x3f6e3ade, 0x4475370b, 0xd12ddb85, 0x7bb94e5a, 0x970544bf, 0x471571f7, 0x8eecabd5, + 0x448e570b, 0x7e811c48, 0x76705125, 0xf4d7ef8e, 0xdbfa0a3c, 0x9871cfe6, 0xb9f13da2, 0xd06ce447, 0x9bc03f0d, + 0x34a34a38, 0x4b125fda, 0xbcc405cf, 0x3086bfd3, 0xf402de74, 0x693de838, 0x390fb739, 0x0304de02, 0xee05c928, + 0xb9b2b7c5, 0xe8692942, 0xfcff3148, 0xe8b6a95a, 0xba8439a4, 0x94e0ab9d, 0x2b67abe7, 0xf6b887ac, 0xd51d90fc, + 0x0cfe4129, 0x08bedd8f, 0x20aca1e2, 0x2d97f7dc, 0x768baf2c, 0xe070c4cf, 0x887b630a, 0x39226ce3, 0x223d3135, + 0x67087ecc, 0xde71591e, 0x9f449967, 0xe29397da, 0x4c86b95b, 0x9d0e9d46, 0xfd45a499, 0x8dff712c, 0x4b9efb11, + 0x8a7666bd, 0xb34bbc1a, 0xb8edc228, 0xd40a8ef0, 0x1c258871, 0x694cc695, 0x7f4ae6c1, 0x05798857, 0x0b2b387d, + 0xa3eb06f6, 0x26938660, 0xe6be3e7a, 0x9f04da64, 0x280c94cc, 0x88ba3c14, 0xf1eb649e, 0x1fb22abc, 0x3068af2e, + 0xd508d5f7, 0x456a7c1e, 0x755ccda5, 0xab47dfee, 0x37baae20, 0x522d9457, 0xd3bf8559, 0x557a5787, 0x54f484d2, + 0x834f0bf6, 0x90f10bec, 0xc89437f7, 0x40f24d50, 0x7da6c287, 0x85d4673e, 0xf5ef574a, 0x603ad149, 0x776d52f6, + 0xd5ff1c6f, 0x0b6ae110, 0x7f8e75bd, 0x29f34d63, 0x1a591451, 0xb158e06a, 0xb3cbde06, 0x5efa86f8, 0xb750b02e, + 0xa1d7d275, 0x928f8907, 0x7c1a228e, 0x59337335, 0xf7b7d508, 0x0ccea95f, 0xa3425d64, 0xdca257c0, 0xc43ca2f4, + 0xc65aaf40, 0xfee70d4f, 0x2e4112db, 0xbb52a3fd, 0x617d350f, 0x0235fb8d, 0x2738b3a4, 0x94e0034f, 0x57b28e1d, + 0x1eb54cc6, 0xec150a15, 0x4129a4ba, 0xa4e0a2df, 0x9c47a5ed, 0x8d963a28, 0x9b51b089, 0xcdd65aae, 0xc4bc26f6, + 0xeab4f15f, 0xc03f5105, 0xbbf8d7a1, 0xbbedb86b, 0x4ff3abf6, 0x4cf91f47, 0x81e3468b, 0x0203924a, 0x1280b5c1, + 0xfbeafea1, 0xa515e378, 0xa0af03eb, 0xc8ef5d11, 0x0bb01526, 0xae116bd4, 0xfec987bf, 0x455b2152, 0xa573f4cf, + 0xf7080fa4, 0x5186a1df, 0xb680ffe9, 0x18dac264, 0x3fc55505, 0xadc52c04, 0xab52b9a3, 0xb43d0280, 0xbbce7dc7, + 0x85a91ee6, 0x71ef84de, 0x4c0fd9fd, 0x3096c86f, 0x4804c9b7, 0x8c3e5aad, 0xdf5ba9cc, 0x6a8d1d59, 0x17525e19, + 0x85a919f9, 0xe8d2ae05, 0x4fd7bc70, 0x25fb552a, 0x17ed91e4, 0xb1fcf491, 0xd207fadf, 0x987b012a, 0x7570c3e8, + 0x4ab8eee5, 0x120b730d, 0x6ed38b5d, 0xb957464f, 0xd5d803dd, 0xf6b76176, 0x9d5f8513, 0x9a7ebda1, 0x5f4c70cf, + 0x25c56da4, 0x6dc8a442, 0x5eff37d7, 0x509f5861, 0x786958c1, 0x0dd17bda, 0x927069bb, 0xec2889c8, 0xb747b354, + 0x3504c4f1, 0x94258395, 0x05836f5e, 0x12068054, 0x42751853, 0x05859782, 0x784882ad, 0xc3988e94, 0x20c7eb21, + 0x6f5d9be5, 0x23840867, 0xfc160e47, 0xbb3bfe14, 0x2497e7ee, 0x42e5f8c2, 0xbdb0d262, 0x97d52dd1, 0x512c6081, + 0xf2beb1b9, 0xdab5a157, 0x9a86a417, 0x1f9a1932, 0xcf9da6e5, 0xf82d53a0, 0x2b0baa7e, 0x2327b4a2, 0xd71a161a, + 0xdf403475, 0x948bfb49, 0x24fc9862, 0x225123cf, 0xced76b57, 0x755bc1ec, 0xd0a2dc53, 0x64bfa749, 0xeca16661, + 0x61183c53, 0xcbbf1397, 0x49c5459a, 0x18e394b2, 0x1be4f48c, 0xf7d8ec91, 0xd81fc5c6, 0xcdb1c20b, 0xfe3c90b0, + 0x4b836637, 0x556781e5, 0x5af18ba0, 0xf0e454e4, 0x79278ba0, 0xe0c76baf, 0xb36c577e, 0xa23b9489, 0x11305ed4, + 0x1b2cf419, 0x250a4de5, 0xe5cf8de5, 0xc5aba253, 0xaba81623, 0xbf255563, 0x5956abd8, 0x54354af8, 0xae4ae23e, + 0x138d859c, 0xb6ab68ea, 0x28c55e2c, 0x5dc5e110, 0xb467d47c, 0xc3cc8685, 0xe1566c24, 0x322c8890, 0x677857fe, + 0xfe8eb38f, 0x0b61ea66, 0xddd1b4ca, 0x6f1cbf51, 0x44f08357, 0xcbe21396, 0x744fe8b9, 0x143b958b, 0xab05e6fe, + 0x3c54dcd1, 0xa5b694a5, 0x0030a4b7, 0x254a05bb, 0x4214883d, 0xd53902f1, 0xcc0e599a, 0x22298028, 0xa55470d9, + 0xbee9ff6c, 0xaf1e2a5e, 0x0f69d102, 0xfc02aa22, 0x19f1d3c7, 0xb6aa4ebe, 0xf1751cec, 0x8a0ae852, 0xd180a904, + 0xad8605a1, 0xb5f57878, 0x6b6db0ed, 0xaaf42553, 0x64f45bb7, 0x9ff787a7, 0x84e527c0, 0xb2839040, 0x4f044fec, + 0x14cbd950, 0x522ae19f, 0x0030916b, 0x517635ca, 0xc3a74420, 0xf13d6a0e, 0xeadd4b6e, 0x8e20585b, 0x0b36ab20, + 0x5f6b6be3, 0x6126831b, 0xdf84a59f, 0x4dd6380d, 0xb77899f2, 0xbb5e5703, 0xf2086ddc, 0x6532cc3a, 0xdb8aa73e, + 0x6570ee92, 0xf32f68c8, 0x019ddfdf, 0xa57896e4, 0xc10e0c77, 0xe3f15ffe, 0x900e26cc, 0x3cd78e47, 0x14354762, + 0x9d6a699a, 0x3ab5c295, 0x15bd0b3f, 0x751f7fab, 0x134faaa0, 0x70e112a9, 0xad293978, 0xdf35c6f2, 0x4ba653e2, + 0xc4fefeb4, 0x5b4e5baf, 0xefb1d2dd, 0xf79e0d2b, 0xbc488b42, 0xe7f21b7d, 0x5aa9157d, 0x6b86dec9, 0x835312f6, + 0x6adf72e9, 0xf613d479, 0xa2379126, 0xefe91cb2, 0x124d80d8, 0xf810e5b7, 0xa9780fd0, 0x15f06bb7, 0x50145248, + 0x502c59c2, 0xc8271ed4, 0x718152d3, 0xb138b95b, 0xfb031cf7, 0x5c4d4895, 0x7aa222ac, 0x566cacfc, 0x3283df05, + 0xe3b5f754, 0x91288231, 0xeb9b4a58, 0x3ab36dfe, 0xae69ec8f, 0xf9e33e4e, 0xbe85bb36, 0x870dca46, 0x7154ead6, + 0x6c3d6885, 0xde765276, 0x09309ecf, 0x5d1c9e35, 0x7cd844a9, 0xa1252152, 0x9967ff0d, 0xa792dde0, 0x2b5e20c1, + 0xebccd1cb, 0x3ceb2b15, 0x49538aae, 0xc1ae7073, 0x10ea8682, 0x6afbba45, 0xe0973996, 0xda059f47, 0xc5fdac19, + 0x7f0f74b3, 0x424d8f46, 0xfd844473, 0x2a8aebd0, 0x69dc3074, 0x86fe309d, 0x55c9310e, 0x0d7f978c, 0xc6dbee41, + 0x19c6edb1, 0x95c916c1, 0x77110905, 0x17deb9f5, 0x8bd33b28, 0xb483f91c, 0x1121b3cc, 0xf6233cb6, 0xef243748, + 0x9271a226, 0x01d89f4a, 0x2338f83f, 0x215fdd9c, 0xc62470c2, 0x6159032f, 0x7c523bea, 0x1d80e70b, 0x49d67bf1, + 0xbf6fd8c2, 0x6555f052, 0x224ac6ca, 0x1095a7fa, 0xf4161b64, 0xd3023679, 0x97f93cf6, 0xe8d0a971, 0x7355a50a, + 0xed4a763f, 0x977bffbc, 0xde073c28, 0x52826765, 0x97e44e42, 0xaed68ae8, 0x8ace251f, 0x71edc9de, 0x16cab2c1, + 0x96eddbcc, 0xfb734d47, 0x71480c74, 0x84b94b94, 0x6c236c04, 0x4d0c3de6, 0xb562e004, 0x3a986190, 0xadc294cd, + 0x3b006f5a, 0x2146b5c3, 0x196571c0, 0xdc6552e2, 0xfa52b97f, 0x11f974b4, 0x7b966641, 0x23f081fa, 0xae22a48c, + 0x056ebc03, 0x5dbb6742, 0x273b0378, 0x19f09b75, 0x35fc426a, 0x16c0e434, 0x97eb86cb, 0x323f6f61, 0x077820d4, + 0x2ae697d9, 0x2dca47ac, 0xe4b2af3d, 0xb53f500f, 0x7f8e17d1, 0xdcda13a7, 0xc531b97e, 0xdca522c0, 0x226ed058, + 0x90551792, 0x175e9a12, 0x53d3838c, 0x12f4451f, 0x738d2aea, 0xeb18a832, 0x5646355b, 0x8695d90d, 0x2a87de20, + 0x237b5c4d, 0x7d56d740, 0x8696dd8f, 0x0eee469e, 0x0477d2be, 0x76420bfe, 0xbfc3c534, 0x2d734253, 0x14749579, + 0x33a47713, 0xf58375b0, 0x9db44d59, 0x5dd5a550, 0x9594103c, 0x672172b6, 0x9721a601, 0xf22bce5d, 0xc6078ab6, + 0xc214a017, 0x7d2bcd16, 0x4461cdaa, 0xe9fcccc3, 0x9dd03af7, 0x00d0ab31, 0x4044ba0f, 0x079023d6, 0x3356d18f, + 0x07f4cc75, 0x8a15eaca, 0xd7e93425, 0x8f749cb9, 0x7f0da3b7, 0x927a943d, 0x23258aa0, 0xe65189c4, 0x1a97f8e7, + 0xbc772ba8, 0xec579f52, 0x31bca957, 0x0ff87e8a, 0xdba76ad6, 0x98d22cb6, 0xc20f56e0, 0xa647618b, 0xfcafe613, + 0x0b792c28, 0xd0d3d611, 0xb0206927, 0x91bee8e4, 0xe275c131, 0x5eb76a17, 0xb3aa5551, 0xd2709740, 0xbd98bfa9, + 0x82d101bb, 0x17ec637e, 0xa1f440a2, 0x4e8ba3f9, 0x22e2e36d, 0xca6a319d, 0xfbb6696c, 0x14137e4b, 0xfd07b93a, + 0x88187f43, 0xe25ec3c6, 0xeed94802, 0xd3cc9ee2, 0xbf24a2cb, 0x6a135c35, 0x0e03b434, 0x4ec89ccd, 0x6ea06429, + 0xd48a5822, 0x10189fcd, 0x4d8f8ce1, 0x1fb21f86, 0xdd542d32, 0x944bd3ec, 0x6df5785b, 0x588b4182, 0xf9fd1d64, + 0x94ff2b13, 0xd01c64b0, 0x02e8d32f, 0xfb51a649, 0x675b91f2, 0xe468ebcd, 0x0b78ef1b, 0x32bd69e0, 0x977084b2, + 0xedee1dc9, 0x54a06b39, 0xb4c0719d, 0x8b8f4989, 0x608d4eaa, 0x034e4683, 0xb2558cd0, 0x4feb8c0d, 0xc6a764c6, + 0x97c6225f, 0xb90e31e6, 0xcb6f3bcb, 0x29c445da, 0xf445a686, 0x83fdbecc, 0xd968f247, 0x868d2474, 0x9bd3cb08, + 0xa0f84f35, 0x91e211ad, 0x93a8c50a, 0x44a68fa8, 0x05aa1550, 0x1fe3a0b7, 0xe31f0d49, 0x6b7586d5, 0xb259cc82, + 0xf4c1cb1f, 0x942452d9, 0x4ea1beab, 0xa47b1a74, 0x7d1f64d5, 0x4afff063, 0x8533476d, 0x57313806, 0xf63d7c84, + 0xe3b34678, 0x8d5f885a, 0x4b28b571, 0xf975ed59, 0x895c16da, 0x30c3bc0c, 0x8ebbba49, 0x212ec712, 0x189c94ef, + 0xe2de388d, 0x12b13ee8, 0xed353d9e, 0xb62fedf6, 0x1c0c0536, 0x77d7ab11, 0x25b7c9ae, 0x69b40dc5, 0x5bf65ca2, + 0x8e4af743, 0xdee6c528, 0xd9c226e8, 0xddeb659c, 0xfbd87368, 0x0a0c0944, 0x2e1dcc24, 0xd1d71331, 0x6ca6d66d, + 0x9aa7ed35, 0x89f4b92e, 0xebe97071, 0x14f55b49, 0x4bad0750, 0xe692d6b0, 0xe51f95c9, 0xbd618500, 0x0230a9eb, + 0x3b6ee594, 0xba3212db, 0x96e1dc9e, 0xb6a8ed36, 0x0e939743, 0x52fad7e9, 0x3ce8c1b0, 0x31d9ba70, 0x6f0cde45, + 0x162f7ba0, 0x694fcbd7, 0x06d9a23b, 0xecffd9c6, 0xa0ac4b0a, 0x6004d03f, 0x8a6d36d8, 0xa616d57d, 0x9ea25802, + 0x65fe2b0e, 0x0f2c1340, 0xba689a69, 0x03c0caba, 0xc2c2867c, 0x74508495, 0x5d7e5ff7, 0x5f44a6ee, 0xe05a8d92, + 0x20641689, 0x7cefbb52, 0xb3abf4b1, 0x68258b5d, 0xfcab5325, 0x9d01fb49, 0x883ff097, 0xda553543, 0x3a09bd66, + 0x9ec26962, 0x12316d11, 0x9bafc881, 0x453c698c, 0x5b1d47c8, 0x707bf851, 0x7bd92353, 0x8179137d, 0xd6d03391, + 0xd490037d, 0x9265db64, 0x28e997af, 0xa742c9ab, 0xfbc8f9ee, 0x1976804e, 0xd7532d61, 0x0f81c023, 0x53457024, + 0x95ebafb7, 0xa5e16160, 0x7cfb5806, 0x73eaff15, 0x934d782b, 0x0ea9c60e, 0xa1e6b17c, 0x3231b481, 0xdb2f5923, + 0x23207cae, 0x8d5f5867, 0xa2165d07, 0xb312e6ca, 0xfa28b7d8, 0x0bdb5355, 0x73c38cf3, 0x95ed4789, 0x26e8d8af, + 0x38e0e6c3, 0xb7e8cb7e, 0x0cfeeefd, 0xbc8ea901, 0x0030d958, 0xd0d597d2, 0xfcad5b25, 0x5d950693, 0x131f4e81, + 0x421fb3dd, 0x723a94b2, 0x13d1549d, 0x5eff5c43, 0xc7199ac4, 0x06be9094, 0x1345abea, 0x6cecd91d, 0xfc78a14c, + 0x39b505d3, 0x55f77bfc, 0x2f4c8894, 0x00d9ca3b, 0x588a852b, 0x54232571, 0xfa1d3614, 0xce893159, 0xa7eb369c, + 0x1720d0b3, 0xc7493369, 0xe6d03427, 0x7ac9cd9d, 0x225b4f73, 0x4e5c46e3, 0x0326de68, 0x398bd1f6, 0xfd8ae901, + 0xcc027be3, 0xdbd37a6f, 0x1187778e, 0xb80e1e44, 0x3bac8341, 0x4045becd, 0x83678105, 0x361d5b98, 0xc041b4ab, + 0x0ff20c75, 0x6d85769e, 0xcfdf8eba, 0x66ede2b8, 0x7546fabc, 0x31a585d8, 0xd95d8b6c, 0xcd820ba4, 0x17e5f470, + 0x74ebec06, 0x24c2c8ac, 0x58a8324d, 0x88d28336, 0x1d2cb81e, 0xa3737889, 0x83cb6246, 0xb4870a7b, 0x40e7ce15, + 0xe6c2d647, 0x7ce1cda2, 0xf519577e, 0xeb98139a, 0xb188dbcf, 0x410a8fef, 0xb32c0ac0, 0x26934fb0, 0xfe6bb85b, + 0xe6e7e321, 0xfe3815cb, 0x39891e92, 0x9ea928a0, 0x808848c2, 0xaef16ded, 0xf3f5d35d, 0x3f4d699e, 0x61750dc2, + 0xfc61f29b, 0x16949d63, 0xad27b6ae, 0xe7f80937, 0x8d2ccdd7, 0xf0c5575e, 0x27ec8ca0, 0x76f87a58, 0xb4acd187, + 0xbc6eca0c, 0xcdd03f43, 0x1636010f, 0x7c569d41, 0xcf6720a5, 0x5a1e05d3, 0xc88dbbac, 0x537ceaf9, 0xd2d1567c, + 0x471cf798, 0xfc4ea62a, 0x40085c14, 0x8a2f153b, 0xd340d9a4, 0x5e62d588, 0x0b4cbbc4, 0x2af9446b, 0x74a4ec51, + 0x0b60cb45, 0x2880985a, 0x98b7ca90, 0x84884828, 0xd8b729c2, 0x160cf0e2, 0x8b9e0a33, 0xd528ff1c, 0xf3713f27, + 0x53789656, 0xfd8d1603, 0xf199d50d, 0xd76ef7f1, 0x1cd59be4, 0xc1f5f721, 0xc299c87e, 0x9f0378aa, 0x112cfe71, + 0xb0bdbdf6, 0x20e7ea47, 0x0a04f32a, 0xe613f10c, 0x277b4935, 0xb8752a42, 0x456313a4, 0xd7091a19, 0x15c24e40, + 0xb2218afa, 0x1c6fa453, 0x4333f97b, 0x8143703d, 0x4205ffdb, 0xf53435cb, 0x90f06e14, 0x125e7710, 0x3e8b817b, + 0x4efc46c7, 0x220aca2c, 0x29ad3364, 0x209d4a4a, 0xe5fb6179, 0xa2cff83c, 0xdf718e93, 0x8c81498d, 0xaa8486b3, + 0x308de16e, 0x844c793a, 0x7e1e2d40, 0xee069493, 0xa1cc8fcb, 0x21612b7b, 0x9294c821, 0xc640f204, 0x3531fdf6, + 0x2787b76d, 0x98432667, 0x27de809e, 0x71e85079, 0xa68d1b3f, 0xcd155b42, 0xfd2ce635, 0xf85224f4, 0xb3cee050, + 0x45447425, 0xa3bcc3f6, 0x7b391115, 0x6c83c7ef, 0xb372e7b8, 0x6b624482, 0xc9a8beec, 0xcd430082, 0xf1eb550d, + 0xee59781d, 0xd0588afd, 0xf799e61e, 0x54b9434e, 0xdc85c5a8, 0x18dfdd47, 0x128a80f3, 0xdccf26be, 0xeb845176, + 0x93b7d3b8, 0xc4ab1f61, 0x9aa83897, 0x581681f5, 0xf71d557c, 0xcbf9bb05, 0xa1d5817f, 0x1a32e7f3, 0x6af2c6e2, + 0xe69f42d7, 0x2bdef124, 0x17477b10, 0x8daf1655, 0xb66c34c9, 0xd7581a72, 0x136ce945, 0x20d22044, 0xf7b3ce34, + 0xd09db28c, 0xabf654e2, 0xc7bcb6bd, 0x3d3d6f97, 0x42200aaa, 0x6d1f91e3, 0xf184c3d4, 0x89833d4b, 0x28e6804d, + 0x1621d342, 0x2a4bad38, 0x11f41b4b, 0x8fe52cd3, 0x4fa4225b, 0x4ccea7e4, 0x3dd43888, 0x56f9f22e, 0xf3bf36ea, + 0x7838d875, 0xc2ab6978, 0x62b79fa5, 0x04409b8e, 0x8c416081, 0x07aeaecc, 0x2f239e11, 0x84545410, 0x5211d675, + 0x364eb6bc, 0xb789ea7c, 0x9fe64366, 0xf90b449e, 0x062481dc, 0xdf347d37, 0x7dd71cb3, 0xc451d00a, 0xc04dbadf, + 0x18c3df35, 0xdf32c4e8, 0x570372ee, 0xeb5bb1df, 0xbbae95e5, 0x77e7e52b, 0x059718fc, 0x71c41a94, 0x3fcd86e2, + 0x3972c4b6, 0x6de00867, 0xecd860d6, 0x5b4fa575, 0x64fe7e9b, 0xbc2421ee, 0x1b272e20, 0x81f55f73, 0xa4ec1311, + 0xc0c1ca2d, 0x9c11979a, 0x2dc5ab1a, 0x79905742, 0x13b3c373, 0xe4f47f7a, 0x594faf39, 0xa7d76a91, 0xc9c8091d, + 0xf2e79d66, 0xe0909c89, 0x8a05d398, 0x4a52b86f, 0x35fc9e62, 0xca009dfd, 0x2a5f31c0, 0xaa19da7c, 0x9da05481, + 0xf6a03189, 0x12f8c923, 0x36527327, 0x181d6027, 0x775fe5e4, 0x4bf77ef2, 0x2500da96, 0x6be8464f, 0xdac0173a, + 0xf771709c, 0x6e73f62b, 0x25583611, 0x5416bb9b, 0xb8092dfd, 0x72d102a2, 0x8bc34b1b, 0x51c8ca6f, 0x3078be98, + 0x85efe4bb, 0x4d023799, 0x696001e1, 0x45925265, 0xdf08155e, 0xd72f8eea, 0xb9d47b44, 0xcd095557, 0xb762d1d6, + 0x9c514142, 0xcad5396d, 0x744f3676, 0xe7dc649a, 0x6c43812a, 0x801df11e, 0x21421cfd, 0x464353ec, 0xf12a5ced, + 0x0e66b69a, 0x5b1e2274, 0xc52a3263, 0xc1b5f6e9, 0x449fb2b4, 0x832ba657, 0x6462b723, 0xf203e9b0, 0xfcf70f45, + 0x08ba5c5d, 0xcb96b4a0, 0x5985a570, 0x3744a5d8, 0x8f3e40dc, 0x8aee405d, 0xefab98e8, 0xaad27da9, 0xbb608302, + 0x770bdaf0, 0xe5a4c61d, 0x29e211bc, 0xf276b5b9, 0x0570c799, 0x321e508e, 0xdd1abc1a, 0xc8346064, 0x1b803a8c, + 0x9f44ab31, 0x58c83412, 0xcd859c18, 0xb82f1a9a, 0xb2e21376, 0x46a001ec, 0xccc78404, 0x75306cc2, 0x19abe50d, + 0xabcdd001, 0x933ae5ee, 0x29173e05, 0x7f27199a, 0x8b1456ac, 0xcf4fd945, 0xc769ab6f, 0x4125d2e1, 0x8ce679f3, + 0x24440b14, 0xeaa8742d, 0x743fb658, 0x095ac15b, 0x581d1bea, 0x92bd1033, 0x79a1da49, 0x424646c0, 0xe0347bc9, + 0x7dcf0021, 0xb421b43a, 0xc8be6615, 0x652f8cd9, 0x46cb3782, 0xf3bab7a4, 0xa2839090, 0x34c2785b, 0x705fa7a4, + 0xaa1d7083, 0xc732c292, 0x1fef7f0d, 0x474c09aa, 0x4a0355d2, 0xca029351, 0xceca09e4, 0xd8e3ab36, 0xe71efe2d, + 0x37666710, 0x4f32e5be, 0x65345af7, 0x47352116, 0x23535b8c, 0x57927b0b, 0x3e1a39b7, 0xbbcae9b6, 0x45b7e2b1, + 0xc8e2ee92, 0xb937c795, 0x83a0da63, 0x5f560ba0, 0x695dd28a, 0xcb6adf60, 0xfd5036ba, 0x154daa33, 0x15c39118, + 0xa77278bb, 0xe538e188, 0xe6b717b9, 0x11c3b802, 0xfa91bc78, 0x3bd5c85e, 0x089bef8a, 0x2263562a, 0xda4e7b59, + 0xe1698e2a, 0xed472ee2, 0x85268f92, 0x36ae9c0c, 0x2e31b796, 0x47d96081, 0x162c6c0d, 0xf9fe6fc6, 0xb2f21cba, + 0x083b64ac, 0x26991fae, 0x021480da, 0x0a9be338, 0x0cb597d1, 0xf82bdb93, 0x99674c09, 0xc2ef2ee3, 0xea6b9298, + 0x287626c3, 0xceaf5b22, 0xf33625a1, 0xb60b2bfb, 0xd85c6ca5, 0x6a19e7a7, 0x82a3f0ee, 0x089f85b9, 0x97df6de9, + 0x44bdbf1a, 0xa2a96965, 0x7078e4cf, 0x1b2ad738, 0xb4fff8d0, 0xbdff601d, 0x0dac0408, 0x9f9d3f76, 0x9f14276d, + 0x17cf39fa, 0x29228766, 0x52f50e91, 0x9fa7cb0d, 0xe8ae194b, 0xbbf7c1e8, 0x4f4a30ff, 0x8af60b3e, 0x7cd1292d, + 0x33f0c0ed, 0x5f55860f, 0x66dc282f, 0xe8377ef8, 0x5909fddb, 0xdc216942, 0x293b713f, 0xc7ee7977, 0xcac17ff5, + 0xd161ebf6, 0x287e4467, 0x665c78e6, 0xcf99a6e1, 0xd5cc878c, 0xfe8e30db, 0xfd8c31ac, 0x21e6ba64, 0xe59f64ef, + 0x4967b191, 0xb16b7f1c, 0xfa850359, 0xf8cad6e8, 0xec8d08e6, 0x59c82330, 0x86627afd, 0x28e9daab, 0x67d52436, + 0xe2ac95d8, 0xb9015a43, 0x15e80aa0, 0x29721ef6, 0x9677b030, 0x35940848, 0xd63e8c9d, 0x351a0313, 0x7f8fc681, + 0x34e57823, 0x52515564, 0xd834ebbe, 0x8dfa3ce5, 0x6f572947, 0x2f174c8c, 0xd7e919a5, 0xd0d970c8, 0x4fe42fa9, + 0x3214e3e4, 0xd8936f03, 0xd38db567, 0x7c29cb4f, 0xf6257d39, 0x5c065baf, 0xefe6255e, 0x88da2ce9, 0x2e16ec46, + 0xfcef6a1d, 0xe1b02b8a, 0x971e3d83, 0x340ae725, 0xdcd77616, 0x836a6d55, 0xba478746, 0x2abede00, 0xccb94c2e, + 0xd010d04e, 0x154f28db, 0x5461fba8, 0x09666baa, 0x697fae45, 0x1dcff8e9, 0x46b154a3, 0xc7c91ab9, 0xa467715c, + 0x0aa020a4, 0xd075bd9a, 0x7ad8a641, 0x11a9eaa8, 0x6f298a1c, 0xc7303180, 0x4638c946, 0x2e64814f, 0x07937bef, + 0x9b4324a5, 0x8ea76d5c, 0x686e667e, 0xbd83ce6b, 0x394931f1, 0x447a1bfe, 0xa4cc4f0b, 0x72762bd6, 0x4bc9b299, + 0xc21a7c63, 0x025a37b9, 0x7712637c, 0xae402638, 0xed12169c, 0x515e1324, 0xad388867, 0x13c01940, 0x97fea327, + 0x27a09be5, 0xd1a52c37, 0x656fa21f, 0x4ddd40c6, 0xa7c66fe6, 0x1ab2dfd3, 0xd19cb225, 0x1489b389, 0x8f9ae842, + 0xd3da037f, 0x43dfe8c3, 0x1beff226, 0x73a4b143, 0x724052c3, 0xea9b1b0c, 0x133567f0, 0x6dfc58b4, 0x4f78cdc2, + 0x63b217e6, 0x62e2ac32, 0x433ce2cf, 0xcfa7487f, 0x8facf052, 0x8ce4b2b1, 0x6225f7f7, 0x2ab1dabc, 0x1c80bec1, + 0x06eab75e, 0xa586df6e, 0x5bbca8c6, 0x7e10bf8f, 0xf49d5d5c, 0x7b7aa072, 0x66fd9972, 0x4722d3c9, 0x20628631, + 0x920d6e22, 0x337e7dca, 0xd65f451a, 0x6d6eee04, 0x5ad86d55, 0xbde011ce, 0x237b3f36, 0x1ce3c964, 0xe4332869, + 0x5724a4b7, 0x3705a9d6, 0xe7b47b21, 0x8193189a, 0xe9b47c7c, 0xe53d7a0c, 0x93bf2297, 0xb28934af, 0x0eaaac60, + 0x77dcc6ef, 0x11a20fe5, 0xc5eb96b4, 0x5c74927b, 0xe8f4bf26, 0xbb61eafd, 0xe7b74a40, 0x70e588c0, 0xdd3a5f89, + 0x5e69cc54, 0x0f960107, 0xfab1aef0, 0x3e58b1be, 0x87041330, 0xd9e580ef, 0x6f7b3f5f, 0x8d53c2aa, 0x9bfa66eb, + 0x1013d5df, 0x3c4bf1fc, 0xf9a53973, 0x08f1ce49, 0x7f28caa1, 0x56c89ae9, 0x9ec6fa3c, 0x2b28bfef, 0x0b331f11, + 0xd94e1c15, 0x8fe4fe9c, 0xa4879d84, 0x438d0cfc, 0xb6704b5f, 0xfb11ec4f, 0xbb1fa27d, 0xa12406b7, 0x56298c96, + 0x039b145a, 0x8b487338, 0x463c19db, 0x486fe798, 0xe17047d7, 0xc6cb4de7, 0xc17283a2, 0xe8ec6d09, 0x62b52ebd, + 0xfe922652, 0xed1e72f4, 0x56e9d697, 0x6cb2467a, 0xde8dd18f, 0x8d552a2b, 0x1adbe5f8, 0xf5a4684e, 0xb9b87bcb, + 0xe3b63b5a, 0x7dc9e5b3, 0x18c04264, 0xd05db611, 0xc1123931, 0x554c7bfc, 0xb3354e70, 0x15b2bdc0, 0xc13c90de, + 0xb3f9212c, 0x05065064, 0x6f7e4f6a, 0xb230a8ac, 0xafc06196, 0x626578fc, 0x8eaad2c9, 0x5e6012ab, 0x730bdac3, + 0xd7f3e9aa, 0xe2a846e6, 0x776481ed, 0x735e3ebd, 0x77db7192, 0x1b15cd0e, 0xc933cabf, 0xe1b6c906, 0x548c2da0, + 0x8f9363e9, 0x11e6504f, 0x6ef19803, 0x36d2071c, 0xce0966c3, 0x7e811f35, 0x3f87fb13, 0x97771c4b, 0xfc26f57f, + 0xbd0346f0, 0xe839a13d, 0xb5377036, 0x8e0ddee3, 0xa8b416a2, 0x62318f05, 0x08cae41d, 0xe5f2121f, 0x52939d59, + 0x03b33031, 0x8f8ae94a, 0x0184ff8b, 0xac95d623, 0xa181aeee, 0x1a453685, 0x00f0f333, 0x64c25b6a, 0x99259e86, + 0xf5e9fabc, 0x1b1e70d8, 0xd36ad6d7, 0x2063ff61, 0xb111138e, 0x13dbc2cf, 0xfeeb74ce, 0x33b41811, 0x894f12f3, + 0x7952a307, 0xf1abd6ce, 0x4a039bef, 0x8f4cc102, 0x91f47356, 0x7c753fef, 0x0cbe1c94, 0x00493d48, 0x497235b8, + 0x4d85f089, 0x0032a4be, 0x796b81fa, 0x3f235021, 0xab5b18fe, 0xd3cbe040, 0xf87a0217, 0xd3d3dc53, 0x21f9ddc7, + 0xca7ac635, 0xdbd25553, 0x8c958d7e, 0x15cedd71, 0xa9793024, 0x12509b48, 0x888cb7b2, 0x1cd9acae, 0x274e2982, + 0x333b496c, 0xdd64d085, 0x929fc5c7, 0x8f7ffc45, 0x5afddcda, 0x9ecb7fae, 0x09cbfc8a, 0xb6e32db9, 0xdb622118, + 0x444dd377, 0xb3b6a34b, 0xc8857faa, 0x6ced7f5f, 0xbade9c5b, 0x5ddbab3f, 0xeeb6dd39, 0xdd6629cf, 0xeb726db6, + 0x549a94f1, 0x63d3a647, 0xe61454b1, 0x21bbddb4, 0xde185688, 0xd848c30f, 0x61b2e6d5, 0x8fa92e76, 0x4a12dbc4, + 0x7f3f5c5b, 0xd35a7bb7, 0x80b83b62, 0x487f14df, 0xbd768ef6, 0x251b9eb6, 0x88566ac5, 0x951500b3, 0x4897da96, + 0x809c2d56, 0xc76b88b9, 0xef2d6ccc, 0x0170c749, 0xae9c7dea, 0xd1575d93, 0x02a099c5, 0x58e6b760, 0xd3219757, + 0x9cdb4ee1, 0xf0f0ec22, 0x280ee29d, 0xfcfdcba4, 0x91f237bc, 0x85349612, 0x1fd38aee, 0xe3792055, 0x204bce7e, + 0x2f50b539, 0xa2082d5d, 0x68128731, 0x84e1a93e, 0x78e48d85, 0xf9dd0570, 0x59f0681b, 0xa1284be1, 0x543cb643, + 0xa7462589, 0x19905dc2, 0xe20a0cac, 0xcfb815cd, 0x62010ea7, 0x603a5d9a, 0x4dfc7b67, 0xc6104ff2, 0x628835cf, + 0x1ae664b9, 0xbf2529f4, 0xf7b64a26, 0xfaae18ac, 0x6a07d075, 0xf6396e8e, 0xf3181ce8, 0x1f66f06e, 0xbc3d791e, + 0xe68b4cac, 0x6a328b68, 0xcbebfa49, 0xd7f8cf70, 0x094bca45, 0x346edc19, 0xf291b889, 0x2fbcc4d8, 0x4355da3c, + 0x050b9863, 0x430de159, 0x1783245e, 0xc9fb02d2, 0x37dd8ac3, 0xc9ff15e6, 0x04d8b7e2, 0x9a6e011b, 0xd535cee2, + 0x58b189dd, 0x555b6be9, 0xf4163d2b, 0x7f1fc2f1, 0x2d915c6a, 0x1c454c6d, 0x722f0dd6, 0x5084c3fe, 0x95cfe57a, + 0xf43ccc64, 0x4aea8c07, 0x0efe38ee, 0x395629a0, 0xeb481b9d, 0xcff69b54, 0xf55b121e, 0x842542cc, 0x5d947fcd, + 0x10d8fba1, 0xdfe72d91, 0x4ba9e691, 0x2829eafe, 0xe1c7a58b, 0x91d1c5d8, 0x334c1a76, 0xfd8a76b3, 0x098aaa29, + 0x7208b0a7, 0xd218c592, 0x4391c86d, 0x5492be67, 0xfac44e7b, 0x4a87c6ab, 0x9f57521e, 0x6079edfa, 0xc0eecba8, + 0x8ea4658b, 0x9826afe7, 0x16a739fd, 0x323364f5, 0xdbcf0f8b, 0xbab72a26, 0x72e88b4e, 0xcfcf322d, 0x77b781fa, + 0xf7914ec6, 0x13d21517, 0xa680ed44, 0x36b0f5eb, 0x4c9db0c8, 0xdbcc6d16, 0xf53ddcd1, 0x7208d83a, 0x13f086dd, + 0x2ee7684d, 0x73e98701, 0x8aa905c5, 0x82ea2156, 0xe3081ae4, 0xde619f03, 0xa371e0f5, 0x64bd7d0d, 0x18d5d09b, + 0xbbbc7c03, 0xe6a09c22, 0xf8ca08e6, 0x67c06127, 0x4d8b9f91, 0xa3907d27, 0x85fcde07, 0x7673f42f, 0x9c73bc59, + 0x0bf57423, 0xd36d6041, 0x1ba9a920, 0x5bf62d1f, 0xd1b43b6d, 0xc0f66b26, 0xbf91a7e1, 0x3d8cf29e, 0x662919ab, + 0xba5cfad7, 0x1b36a896, 0xfa65809d, 0x251a3cea, 0x8404698d, 0x0b369623, 0x8e1f646a, 0x724c6598, 0xb3fac1ac, + 0xbcded676, 0x0231d169, 0x6282bd49, 0x4a4d72c0, 0x5b83671b, 0xc0520cfa, 0x97e95cea, 0xd46c9aa1, 0x24f1022c, + 0x3bdd4e67, 0xd992e377, 0x42022263, 0x1745f402, 0x0630362a, 0xcbdbb2fc, 0x241c8bdd, 0x69a394fd, 0xfd00d732, + 0x12b58f8d, 0x15930aab, 0x3f84b134, 0x1bc70718, 0x36a6ee7d, 0x0cab7f94, 0x37a5016a, 0x0f8d4c24, 0x605bbf2b, + 0x07dced77, 0x63df0a1d, 0x5de1ab4c, 0xbde15af7, 0x45740088, 0x6a764623, 0xeb2d907a, 0xdba11b38, 0xcc2c9adc, + 0xac5406e4, 0x98e56b32, 0x6c1ba4c7, 0xd1aa0d23, 0x369f05b2, 0xc0b39e86, 0xe4e57dd7, 0x1d07cba8, 0xa7d2fe35, + 0x3402689f, 0x6e19bafa, 0x95a60808, 0x1d950f67, 0x0566e996, 0x10bff093, 0x79bd02c4, 0x5efdfec0, 0x5f720f43, + 0x32905ff8, 0x46b5e254, 0x331095d5, 0xec2a57b8, 0x8d01738b, 0x76a4456b, 0xfeee7136, 0x47bf7fcb, 0xb8ff6125, + 0x982ce0fb, 0x44bbacf5, 0x455c045c, 0xf3bfee37, 0xe640b4ac, 0x5876a207, 0xb094f750, 0x700280f7, 0xcd4e5aaa, + 0x192d32c1, 0x7b88271e, 0x1809ebaf, 0x6d2d1180, 0x29033f92, 0x94f9d2a2, 0x2c4fc7d7, 0x68a6a4d9, 0x0cbc4252, + 0xb630c039, 0x4792c6ce, 0xaec12f46, 0xe19e655e, 0x50b8f263, 0x12924b43, 0x1b1c3fbc, 0x56fd78d9, 0xce4f9c6f, + 0xc97d3a72, 0x57164293, 0x383349e6, 0x4da649c4, 0xa9b07b93, 0x002f0215, 0x8667924d, 0x9678fe5c, 0x5863f10f, + 0x3dac9893, 0x333f3965, 0x1b97f6d9, 0xfc1bd6e3, 0x2f6d4ed4, 0x5ed2146a, 0xc2869c7b, 0xdc8517ee, 0xd93174dc, + 0x7251189a, 0x61a47cf2, 0x1f13f6bf, 0xd60de9d9, 0x8057d6a8, 0x256ea754, 0x76f4c1f6, 0xc226d0f1, 0x348dcd66, + 0xc2c16483, 0x4bccf223, 0x65932c09, 0xf921c760, 0x9701f9c2, 0x6ed64405, 0xc1be4cd9, 0x0482fcaf, 0x67730fd5, + 0x888e7491, 0xed718690, 0x30910aae, 0x096f2b8d, 0x6bbc1aba, 0x306b570c, 0x571efe8f, 0x093d6c01, 0xaccb915b, + 0x99dc5a09, 0xb52f70b8, 0x7648f1c6, 0x2b04e824, 0x2ca77886, 0xbc686f14, 0x8dd47cf9, 0xc5b455a2, 0x6b54c4ff, + 0x435822b0, 0xb363f3f1, 0xaa7b2fe1, 0x183e0d79, 0xbd217836, 0x860a657a, 0xcfaaba5d, 0x4921caf7, 0xe04077cd, + 0x05e08eb0, 0xa1fcef95, 0x5234139c, 0xf7b84530, 0xbd952da6, 0xff58d551, 0x6206e740, 0x22ab63a9, 0x0779e9c3, + 0xfe004d07, 0xa3d3d042, 0x9b676242, 0xbaa2389e, 0xd970c818, 0x5f83ef64, 0x0de0a7d7, 0x0ef6c037, 0x9d4699ac, + 0x5a767b89, 0xaf183388, 0x57f6c505, 0xdf5a7e40, 0xcf9114be, 0x53865a32, 0x15c54f5c, 0x63e27f0c, 0x3de9d1e7, + 0x93eabb84, 0x5b39b8e7, 0x0dfb7aa9, 0xf9c76d31, 0x2a5cf2ef, 0xbe732937, 0xccc6096e, 0x0638b3e4, 0x8d566db0, + 0xd8e9772d, 0x6c382968, 0x4ecb0f98, 0x06523de9, 0xf5244029, 0xac495b9d, 0xa0f71785, 0xa14bbab2, 0x7c350e40, + 0xd1899b1d, 0x9bf2be21, 0x6bfcf76c, 0xe89ba755, 0x4b539ec2, 0x4782b7f8, 0x35bad3e0, 0x0d2afdde, 0xe6e0e887, + 0xd904a9bd, 0x587b79dd, 0x28068eec, 0xf2636924, 0x16b120e2, 0x7a4f8ed3, 0x98c66e8b, 0x760ce279, 0x9cab4acd, + 0x5c98476b, 0x2e6c8733, 0x77363f05, 0x77b4320b, 0xe709738a, 0x6f8e6555, 0x43977b55, 0x5fd66d5d, 0xbacbbacf, + 0x3a01488b, 0x1f7fa3db, 0x1f5c74c7, 0xa2280cb7, 0x6dc23df1, 0x76188040, 0xb7520e98, 0x27f609b1, 0x8464a1f2, + 0x390f131e, 0x00aba320, 0x6993b755, 0xf835e9f5, 0xafb233f4, 0xcb2df6d2, 0xdff73539, 0x4a043a50, 0xab604522, + 0xbd29217d, 0xaa1fd306, 0x25aa3034, 0x8fbe28f0, 0x7b98ce11, 0x2f24af1a, 0x14684ae4, 0x6b25d5ee, 0x34da8373, + 0xf06d6d3c, 0x777e6d18, 0x6ba5eced, 0xc0a4b5a6, 0x5ab0abcc, 0xaf440cf5, 0x896a2d85, 0xe3b11137, 0x77aabcdf, + 0x7bdbb646, 0xc9b9078a, 0xf31e1cc8, 0xdd7d4665, 0x527ff25c, 0x8793d647, 0xaca83a8d, 0x3685ca40, 0x93f8fc43, + 0x2913341d, 0xc7960568, 0x3233122d, 0x808b98d3, 0xd720b914, 0x69ae737f, 0xf87c6d2e, 0x80a2c7fd, 0x0608f2f0, + 0x3680e884, 0x29f6cd01, 0x56187725, 0x2085187b, 0x8913383e, 0x395c450b, 0xf3fc52a2, 0x2e7f27b8, 0x696c019b, + 0xa364bd1a, 0x10f05fd6, 0x728c9fd8, 0x5f06f31d, 0x5d007555, 0xe73ce03a, 0xc4d2a5ee, 0x34be22c8, 0xfad15aba, + 0x168dbf55, 0xa7955245, 0x06c58db6, 0x54e35ce4, 0x73d18f16, 0x04c1bc42, 0x7dc7dd93, 0xd3b72b0a, 0xe6da13c3, + 0x61d6629c, 0x9df21798, 0x23b22f09, 0xb25cf714, 0xb5a08a85, 0xceedb3d5, 0x90e1fe76, 0x8f3f977b, 0x4f700f1e, + 0x80b65b93, 0x9032a160, 0x706224ed, 0xd638c829, 0x8ab32fe4, 0x9b2780d5, 0xcd623098, 0x9755b4b4, 0x9b89c326, + 0x1c85ceb3, 0x32690907, 0x4e3f4733, 0x6f9b9419, 0x4452df1c, 0xfeb4a8cc, 0x50b3656c, 0x0ace5d73, 0x4dab0009, + 0x256dafc4, 0x11625c41, 0x62240a7c, 0xd43cf11a, 0x235e46e6, 0xcce2f4d6, 0x393b77cf, 0x75352a0a, 0xd1461009, + 0x1aee3a6c, 0x6a83821b, 0x486e05f2, 0xc0077ce1, 0x358b6eb1, 0x1371de27, 0xe9420465, 0x6f347ab4, 0xb689fe0b, + 0x8900ad40, 0xe69baec0, 0xf5fbce45, 0xb0122907, 0x4a82560d, 0x84466f4a, 0x4d54d218, 0x0be145ac, 0x131c6b08, + 0xd7e7dcd4, 0x97ffa9bc, 0x4f047a8c, 0x61c20927, 0xd3cde6c6, 0x2f5a4c16, 0xfd49d8fb, 0x31e6a7f6, 0xc62338a7, + 0x68f1678d, 0x27f0bc46, 0xffff55f7, 0x9f382989, 0xef167545, 0xd06393e6, 0xbc6044f2, 0xf2f0c6ce, 0x0ccdd603, + 0x734ae2ec, 0xc0cb2665, 0x043d24aa, 0x8d111b0d, 0x5b70c59c, 0x244c1bd0, 0x6fb1651b, 0xcf4a6e14, 0xdfe8c3ad, + 0x77d4003b, 0x1b08fe4c, 0xffe8c8d9, 0xe67c2e47, 0x4caaf841, 0xb19d3c19, 0x5079d2e7, 0x8ca67dde, 0xe3e4abc6, + 0x097eb1e8, 0x2d42c7f6, 0x3b880c66, 0xb0b6d2d0, 0xf69c1128, 0x7e6c20d6, 0x9d9ba33f, 0x83215307, 0x0a3128ad, + 0x4b4d3793, 0x3eda96eb, 0x4f7efc95, 0x57a11fee, 0x6995eccc, 0x162176a7, 0xd5a2e081, 0x25f43607, 0x0575208c, + 0x18316235, 0x829129c5, 0x30426a56, 0x54c377e7, 0xf992eca4, 0x9d82b911, 0x54cc5f04, 0xe57f8aa3, 0x15edafb3, + 0xa5f5e6c3, 0xd829b472, 0x9123bb6f, 0xa62401de, 0xb053f3e1, 0xd7939a11, 0x4570e3c8, 0xd391f5e8, 0x981a12c0, + 0xe745a6a4, 0x81a5b292, 0x81bc0fa2, 0xf9352ba7, 0x0e1c814c, 0x6a8feda7, 0x8135d245, 0x3a984091, 0xa0e3b97c, + 0xe8599d14, 0xc17f5d04, 0x2c6b12a4, 0x28f9a8ec, 0x956ace3a, 0x27c6589b, 0xe91ca2ff, 0xcee36546, 0xf15bda0f, + 0x9b049dee, 0xfc7cd73e, 0x3051ea52, 0x611eb7bc, 0xcba646f0, 0x3ee641dd, 0x42e7df65, 0xe67249fd, 0x0b62755d, + 0xec6db8f8, 0xc8ff8e54, 0x51fa22cd, 0xad65640a, 0x4da042c2, 0x27fe1b46, 0xe3b9b3a8, 0x8b6df453, 0xd76421e0, + 0x294c74dc, 0x686d33b2, 0xb886e4fa, 0xbdc7ecf2, 0x83794449, 0xf23df42d, 0x202162d1, 0x0d3b3f9c, 0x0fa19e61, + 0x5c944e6a, 0x26b39ffd, 0xbd40f07c, 0x8336c878, 0xf599c93e, 0x8049a9fc, 0xdb9cf234, 0xe3bceca3, 0xe89c769e, + 0xc05e6cb7, 0x5761469b, 0x0842d337, 0x8e5d9c69, 0x595e54d5, 0x714c2d52, 0xda4de357, 0x19d57c12, 0x22f7c405, + 0x8ff37ef9, 0xe59177bd, 0xf40e536c, 0x23b55ca1, 0x670feea4, 0x3b421cbf, 0x80d739cf, 0x1ee8e70f, 0x2c7f8446, + 0xebb55379, 0x5e23760e, 0x2d16d0f9, 0x910274af, 0x3d2fc1c8, 0xcc966ef0, 0x59a197ed, 0xad1065ba, 0xe990ed8e, + 0x55635305, 0x1391af25, 0x247c9058, 0xa4277895, 0xd09bff24, 0x74d9fd5b, 0xf71968b6, 0xaf7b67b6, 0xd0af1523, + 0x3e1c5fc9, 0x00074d21, 0x1451a29c, 0x8a97badf, 0x1bf52541, 0xfdb6dc9e, 0x663a168b, 0xe330a63c, 0x4729420b, + 0xb48957b7, 0xddf6ecc9, 0x4167cab3, 0x8443341c, 0x86aa4cf5, 0x0bbab5de, 0x3ce045c7, 0x6073da9b, 0xc6b96522, + 0x8857c91e, 0xa292b74a, 0xd83ff830, 0x169065e7, 0x82177a3b, 0x959c44f6, 0x265801e5, 0xa8dbf934, 0xb26ff68f, + 0x434975ad, 0xe304bfc5, 0x9f549db9, 0xd27467e5, 0x63816690, 0xeee0e9df, 0xe3764d51, 0x6844089a, 0x2ba9d850, + 0x90d8241f, 0x09bdb75b, 0xeb81562d, 0xbbd0488c, 0x00909f5e, 0x6520ce8a, 0x6db18f5a, 0x0d557742, 0x0044a56e, + 0xe10a79d6, 0xc69ecf9e, 0x0dcfa2a1, 0x7312db05, 0x9651604e, 0x21853664, 0x071959b3, 0xb8b0cb77, 0x406aa1bf, + 0x82d67db0, 0x9352b085, 0x5f36947f, 0xc5c4e62d, 0x1d92307c, 0x28c48035, 0xc0aebfaf, 0x2542b54d, 0xa79d97d7, + 0x54f13fdd, 0xb77054b4, 0xaa461fca, 0x9cd31ef9, 0x38be28a0, 0xd20dc1c2, 0x97be4d9a, 0xfea59699, 0x0c2c6655, + 0x931e9216, 0xec24eeba, 0x264ef044, 0xfa68f997, 0x917a8cc0, 0x47fe0320, 0x9c27e047, 0xa0e383d4, 0xa7a93e3d, + 0xd4b4d4e6, 0x8c78cb6e, 0xcf1172b2, 0x9e53324d, 0xde3fc35e, 0xbd6168a9, 0xa4ed6dd2, 0x40a005e5, 0xea97a1bb, + 0x5197e999, 0xf971e729, 0x6eb6e6c6, 0xf2186f26, 0x956be1c0, 0x198ae0c9, 0xf8837133, 0xc5345061, 0x71523372, + 0x2c740bb8, 0x6382559a, 0x956212c7, 0x09b22bf4, 0x88915936, 0x9e24e4b5, 0x9966e99e, 0x9b23f80e, 0x07ff318a, + 0xd8ef7cb9, 0x986eedaf, 0x10ef8dd3, 0x0cff9089, 0x1f257edb, 0x2c237e15, 0x6a7995fd, 0xc43d4d42, 0x138ad595, + 0x8ffdcb40, 0x55aa67a8, 0x467f1381, 0xe66e83e1, 0xc145d848, 0x34872eb9, 0x3b90edc5, 0x4fd6fcb3, 0x5d3e5045, + 0xbe079412, 0xc5479a0d, 0x79b05534, 0x747e76d8, 0x31e925df, 0xa87e3525, 0xc4414a25, 0x41ef729d, 0xd230ac7f, + 0xbc9ec796, 0xb4727881, 0xc82bf346, 0x78ed3d54, 0x9e32c423, 0x9e1a8127, 0xb9fc08cb, 0xd1348fae, 0x9989f1f6, + 0x5119fa9b, 0x271e6a6f, 0xb501d9f6, 0xbdae23db, 0x02737f5c, 0xc6972fcb, 0xea2252d4, 0x6f02751c, 0xb4a2e2af, + 0x96ec2c6b, 0x0dcb5ea2, 0x11a521d0, 0xa0bea2b1, 0xaa5fbc07, 0xb2b9a6d7, 0xe74ec9d6, 0x101a5a17, 0x0e00bd11, + 0xe18da710, 0x38e34672, 0x344427bd, 0x09b07dee, 0xd9ee80b3, 0x1710f3f4, 0x137cefac, 0x3caddfd0, 0x12fb7527, + 0x4d1e089b, 0xf257478b, 0x1de88770, 0x17626deb, 0x137dda4f, 0x491be67d, 0xac4018ac, 0x44e904fa, 0x71dd7582, + 0xedee4aae, 0x517c902f, 0x722cad2d, 0xaa77d80d, 0x94f732ac, 0x94a66b9e, 0xa815604f, 0xc1095b01, 0x3ccf402e, + 0x3c4ad225, 0x610c054d, 0x5da0f8f0, 0x718b0069, 0x19697713, 0x310bbf3d, 0x2b026413, 0x87ca982e, 0x3c51d3b3, + 0x1c28462f, 0xd9e076de, 0x0a8de2f8, 0x398b5fb2, 0x5e205feb, 0x7f97dc47, 0xf15aea65, 0xf777f2f2, 0xe1cf4860, + 0x50c4825f, 0x775bc143, 0x591b99d9, 0xfe3b3b04, 0xe2b53ee8, 0x84f9c3d0, 0x67879577, 0xd683455c, 0x6311006e, + 0x35874796, 0x260ea5c7, 0x279ee8de, 0x4c260a82, 0xf93c65b0, 0x00a93a7b, 0x9e39c181, 0x73207992, 0x49f84f5c, + 0x0c427642, 0x4a5e3bfa, 0x665e3fec, 0x4a2116f1, 0xb25f4f47, 0xc7187265, 0xbb9976fd, 0x4b5fc70d, 0xaa1ab35c, + 0xc935f9af, 0xeccd4c01, 0x62ab2f83, 0x5d4ab686, 0x429c5981, 0xdcc8ce86, 0x7da2c94b, 0x0bd1f284, 0xe3bd78e5, + 0x1de8f2b9, 0x2ce64b0f, 0x4940c79c, 0xbbcd761a, 0x282e241c, 0xe4b22c83, 0x60fce126, 0x36d207f9, 0x57f8f5b8, + 0xc908ced2, 0xf13f7684, 0x1c16daa9, 0x7881b0dc, 0xcffb4887, 0xeb23ffee, 0x04741745, 0x1a8b440e, 0x2a279e5f, + 0xe8b87ac2, 0x48514447, 0x1faa4cb6, 0x337e3bea, 0x00a0ca68, 0x84c88fc7, 0x58446190, 0x1e1a3f57, 0xce1bbacc, + 0xfea594f0, 0x947acd59, 0x6bafa9e9, 0x6965a3eb, 0x0fc46b0f, 0xe0a8aacf, 0x226a56e5, 0xb202ee77, 0x4f0caba7, + 0x5e9de277, 0x640f1ecf, 0xd758cc98, 0x0f81e2a7, 0xb38f4ac5, 0xd4bb4163, 0x74ed4c82, 0x129beb1d, 0x161cb722, + 0x8e6dced4, 0x2d8a7243, 0xc8e2801a, 0xce153026, 0x5a1d6568, 0x47e1fea1, 0x3bb72b5d, 0xd7040b68, 0xd17c139d, + 0xc1d56ac6, 0x3363dd8a, 0xdc5710b7, 0x7711511e, 0x9cbfe5cb, 0x1d42a34b, 0xc2fab8e5, 0x7c865f6f, 0x0213204b, + 0xfe308333, 0xfb997712, 0xb579ebcb, 0x49c2f396, 0x1bc98a4b, 0xc94935eb, 0x9b84ef17, 0x868bcf75, 0x24012c26, + 0x668f494c, 0x178b9f6a, 0x6140ace4, 0xcb569d9e, 0x082b6dfa, 0xa6b491db, 0x686060ea, 0xc7a149cd, 0xa1496e1c, + 0x7d0011c2, 0xdf3a1f77, 0x658df68d, 0xfec13283, 0x1cd3a05d, 0x6946f477, 0x0cd81f71, 0xdd3238a8, 0x35468f1b, + 0xd09e5e9a, 0x1cd493cc, 0x43c1573f, 0xe020d0e7, 0x6ea79977, 0x77f41bd3, 0xfc6ab36e, 0x1e5b967a, 0x29002d46, + 0x2997ad7c, 0xa36e36ff, 0x6112f679, 0x77b14bd1, 0x137c351b, 0x50985769, 0xfa014f42, 0x581afa04, 0x85e7efab, + 0xb9dad285, 0x864c3b89, 0x5c94964a, 0x578ad33b, 0xa310f863, 0x2b7634b2, 0x63da4928, 0xf5bc388c, 0xc2575509, + 0x221d2fb3, 0x148a2035, 0x9e4eb9d8, 0xc191f057, 0xb2a3325a, 0xbd3e5a38, 0x2427389a, 0x6fd8159b, 0x83ee446d, + 0xce92ea15, 0x7d73f141, 0x57d842e7, 0x85767cd6, 0x73942fe5, 0x966bb3f6, 0xd6713857, 0xa87d1855, 0xf6f8377c, + 0xb499e6a3, 0x669a2a74, 0xcff0f256, 0xb31987b0, 0x3ecc16b2, 0x9002b65e, 0xa30d7242, 0x7f6d8394, 0xc873be87, + 0x9ecf884d, 0x0f809a60, 0x2b06a94a, 0x581c4628, 0xa37088e2, 0xd64a063e, 0xfa366d59, 0x3dbfb501, 0x81b3934c, + 0xe11b4d16, 0x98981945, 0x851d93ce, 0x4e5f73b0, 0x8713cc4a, 0x990c3e88, 0x3f10dde9, 0x2c741b6e, 0x16ca9e62, + 0x8a9574c9, 0x5fddd704, 0x91e0f946, 0xe145b261, 0xd6c8e914, 0xd46a195e, 0x836f2b84, 0x888488f9, 0xa0171075, + 0x5b68e624, 0x69bf7207, 0x97f89c5f, 0xf68bf78b, 0x0e48fcd1, 0xeb49a381, 0xe04b4e48, 0x6c2b4749, 0xa84a84e1, + 0xe7359ec5, 0x651a830b, 0x9d95b25b, 0x65d139ac, 0xd452f94f, 0x28f3612c, 0x61c87396, 0xe429effe, 0x3ea8483a, + 0xac2bf450, 0x450615bd, 0xeb94bf71, 0xa759a259, 0x418fadc4, 0x59734a93, 0x7a47a6f9, 0xe1652560, 0x5afb7d14, + 0xcca9ac68, 0x3516a22b, 0x28d369f3, 0x5d6ea00c, 0xa7c9c0ad, 0x137b9fb3, 0x2c7137c7, 0x733a939e, 0x29a50a01, + 0x3fa44daa, 0x7160a761, 0xac698f11, 0x1653e030, 0x12d99a27, 0x07a9f12d, 0x45df07e3, 0x010fc0fe, 0xfbc7b3da, + 0x6d1e6dad, 0xf992a21f, 0x52f3d632, 0x909eed95, 0xb27215d1, 0x732961e8, 0xdcd541b0, 0x28c21d54, 0x0df2b4ac, + 0xac33143e, 0xa9ea0eaa, 0xcdfa2588, 0xc927571c, 0xca35f8ca, 0xc840a0fc, 0x55b4b757, 0x9434bd7a, 0x2e1ac1e8, + 0x0a9b1162, 0x8aca7625, 0x034f9307, 0x0491ef04, 0x785d0c72, 0x73b299f7, 0xd17861e0, 0x4323eaa2, 0xd7e0aca2, + 0xf989705f, 0xc4f09bb5, 0x99fd7f86, 0x271c30d1, 0x27e92bd2, 0x7286960a, 0x255036df, 0x941e2779, 0xdb8eae4e, + 0xf6adff46, 0x2b49ac54, 0x0a1cef40, 0x1f28d624, 0x8d6162c8, 0xf080d22e, 0xb6bb18f2, 0xa880e3dd, 0xa78846fe, + 0x4d2fa3ed, 0x05378029, 0xc49b8f5b, 0x2905cb26, 0xd3aeb39a, 0x1629690b, 0xdd1757eb, 0x2ff1f673, 0x9a688a6c, + 0x1d4d24c1, 0xc9742446, 0xabda29b1, 0xcdaec5b7, 0x295c0d7e, 0xd90ff9d0, 0x978d435d, 0xaf68329f, 0x38bed6ce, + 0xcff29244, 0xd79a356e, 0x5910c2a9, 0x77e55bd1, 0x505f5a79, 0xd26d9743, 0xe070d255, 0x4e577e72, 0x68f33845, + 0xc18b2566, 0xa83308d5, 0x022b9e46, 0x2b6f4a24, 0x6c7dfc72, 0xf76630f7, 0xb12f83b8, 0xfbc91237, 0xab95158e, + 0xf8aa7ac5, 0xd76a5eba, 0x891fbec4, 0xe1cde14e, 0xf5fd0124, 0x123ce625, 0xb2e43de0, 0x65626d23, 0x3333eaf7, + 0x1f29e299, 0xd6b24c0c, 0x6a6481f5, 0xeb4ad807, 0xd7a16f02, 0x9655eb0b, 0xc22d345c, 0x3bec5fa5, 0xd22848fb, + 0xb9117606, 0x99d8de15, 0xf58f6e56, 0x7533b564, 0x90ad90f7, 0xa114cff1, 0x7fd502b8, 0xac5a34e0, 0x76e2b46e, + 0x3e106b77, 0x01e92323, 0x556d779a, 0x18b1a5ad, 0x2d9d2887, 0x54e1bd94, 0x9994a582, 0x59cf2080, 0xe17b5ab2, + 0xcb1f04ed, 0xd42fe908, 0xcd00aec8, 0x820a5c05, 0x229bee59, 0xc8446595, 0xc9dd9716, 0xdbb9653d, 0xd55f6f4c, + 0x2183da6c, 0xf615fa3d, 0x88b43107, 0x85f645a8, 0x3436b234, 0x7e553a12, 0x2cef38fa, 0xa738eed6, 0x011e4dd9, + 0x915ccf5f, 0x20b174c9, 0x25215972, 0x30b7a4cd, 0x2129f05c, 0x29ea8163, 0x13f81c91, 0x9045309b, 0x2064548b, + 0xf91efa18, 0x579d0262, 0x24c3d838, 0x8b3be565, 0x553939e8, 0x31d0c06b, 0xd314be9d, 0xb6c246d2, 0x114f9e12, + 0x1d8c0eef, 0x57c98e18, 0x50116040, 0x0778bbf1, 0x30d91dd9, 0x948b14f4, 0x1cd63672, 0xd72dbc14, 0x72c165f4, + 0xadfd0381, 0xdfee0594, 0xfd8f9a78, 0x29cf2f71, 0xe25469be, 0xec88ecda, 0xaeda0c7c, 0xa4b9957f, 0x5dc1a43f, + 0x3a77b4e7, 0x62ad807f, 0x04a337ea, 0x9b506605, 0x0379c816, 0xdb7feb21, 0x9702e194, 0x50f3c880, 0x437398f9, + 0xdb172038, 0x19658647, 0x0cad25c4, 0xdac606c6, 0xb84181d5, 0xb0dd73f1, 0x19065c8a, 0x51f1f7f8, 0xbee06590, + 0xc89c841d, 0x0c5e131e, 0x35468f66, 0x99cb53ce, 0x406283a7, 0xb2452b5a, 0xc707ab70, 0x74fe1adf, 0xa0e5107d, + 0x9c00f3bc, 0x24396759, 0xa768b114, 0x5f43e28f, 0x81aa7895, 0x66a389d3, 0xb6fceb34, 0x04ce34fe, 0x3f3905e3, + 0x5b1cfb92, 0x60cb41c7, 0x737fb221, 0x2a083549, 0xbb8d21a2, 0x1cdf9641, 0x79f3099d, 0xb43db075, 0x7ea7dedf, + 0x715888e7, 0xd1e4685a, 0x7287bcf9, 0xccdd9a60, 0xbccecffa, 0xbafb6e86, 0xf14a9b3e, 0x61e07c8e, 0x82918d5e, + 0xeb7d33b8, 0xd556421c, 0x15973a1b, 0xb90c91db, 0xa28faa1e, 0xc75b5121, 0x22dd0094, 0xa1b18fde, 0xc31376fa, + 0x05ca884a, 0xa5ebb379, 0xf63ac40b, 0x8466e9df, 0x40fbe81e, 0xe48eee20, 0x439b3381, 0x49b7ba18, 0x4219a400, + 0x5b54e97f, 0x1f080608, 0x72f70697, 0xead22ab7, 0xc8882403, 0x4a225667, 0x6fed4907, 0x9cc37375, 0xcba56457, + 0x94f85aaf, 0x9530fa6a, 0x3c478d49, 0xbc802dbc, 0x128a1538, 0xfc7e6e7e, 0x56baafa0, 0xeee4137d, 0xe0eaba4b, + 0xf64fcc01, 0x42bcc451, 0x31d11845, 0x3eec0754, 0x14e34422, 0xcf9564f1, 0x14c28626, 0x4c0d2afc, 0x3b7ac641, + 0x2e20cbae, 0xf977574e, 0xad3d0f5c, 0xdaa9c35e, 0x2f2e7b3f, 0x887c91b9, 0xf719e901, 0xd9376c89, 0x08adaa13, + 0xac741cdf, 0x8649efca, 0x8ba0702a, 0xcd6aaa37, 0x2e79f9d9, 0x1b8fbe04, 0xf6749bcf, 0xc5cc75fd, 0xb26605dc, + 0x84c6a553, 0x0c7e811d, 0x4b8181fd, 0x2674568f, 0x94896210, 0x0d6e87a6, 0xe0480f9e, 0xaf0b04f0, 0xaacd4ccc, + 0x18cec985, 0x20969a9e, 0xb190cf4a, 0x7add1f18, 0xc036fbee, 0x4245caff, 0xc344905f, 0x1dfe6053, 0xbf0601c0, + 0xa44ace0a, 0xab6273c9, 0xf2a88c45, 0xd23b8264, 0x34c2ec26, 0xce570e10, 0x0e4630bd, 0xe3eb4789, 0xf665b661, + 0xe057977b, 0xaa193923, 0x3017954f, 0x7a711b1e, 0x20583480, 0x2532da05, 0xad78e090, 0x3667ca4c, 0x066b7657, + 0x2567444b, 0x194ec9e0, 0x2edb827f, 0xb1401823, 0xc26cd9ff, 0x6fd7f641, 0x39d2f320, 0x0f0fe22a, 0x742dfee5, + 0x1ad7277d, 0x6f766d1b, 0xcc88dedf, 0xfa95ff25, 0x67c42dd6, 0x66e510f5, 0x6ed71be4, 0xf265a559, 0x8997aab8, + 0x4a86abbe, 0x4f047175, 0x59b00f4a, 0x82ba7234, 0xd3a81753, 0xac92292b, 0xe3fd3b24, 0xf6b2c4a0, 0x4c596b11, + 0x3f742cd1, 0xbb15f74e, 0x56eea259, 0x8b79eb9c, 0xf1de113d, 0x1c3d3dbe, 0xca8ef39f, 0x61b6293a, 0x4e4b74c7, + 0x319bcb75, 0xf2e48f4b, 0xdb0c8439, 0x285a9edc, 0x97f4e07c, 0xea8c9801, 0xd84438c9, 0xc2def1ce, 0x99f34b3d, + 0xbb37d944, 0xd632c6d3, 0x28044d93, 0xe200c371, 0xaa8479c1, 0xa188b88a, 0x4b2dbfea, 0xb8e34345, 0x8db34bce, + 0x329595cb, 0x2905e1bf, 0x007235a3, 0x2a2acf97, 0x0a3171de, 0x3669135e, 0x987358ce, 0x8d692801, 0x8bd03049, + 0x82a3cecf, 0xbe44d6c5, 0xceb2802e, 0x165d24db, 0x51c801b8, 0x6b84e02c, 0x13261123, 0x46a3ab66, 0xdc50a6f7, + 0x7c4e95cb, 0xc7a14e17, 0xa03965bd, 0x7fb68aec, 0x2f268d3e, 0xcd6f095b, 0x4ced2018, 0x7b7c3c76, 0x36e8a0c4, + 0xa53067cd, 0x9469b12f, 0x86ffd9c7, 0x909e84cf, 0x591fb34d, 0xcbec6274, 0x014513ba, 0x3b5ab3a3, 0x1e0ff7a6, + 0xf99c8df9, 0x41ea2e46, 0xa8124a99, 0x9a61e6c9, 0xd0b0f054, 0xf711d3c5, 0x6214952f, 0xc7bef68a, 0x627ad183, + 0xb624fcaf, 0x63db7bec, 0xc5c62329, 0x718a79a4, 0x4786d2d5, 0xd198f724, 0x92577935, 0xd9905b94, 0xb9ba3a88, + 0xa9acd4ee, 0x51ce62c6, 0x2c8c5296, 0x108c38ac, 0x26a82778, 0x27100ed6, 0xc5e83fd7, 0x2a86e960, 0x411cb773, + 0x5593844a, 0x82586d69, 0x63b05c37, 0x0fd2b681, 0x4de2d032, 0xd40b3d86, 0x1ce8e784, 0x93ed3415, 0x04bb6556, + 0xdf10fdcd, 0x7fbc8586, 0x1d9a55e2, 0xe48c898c, 0x89a26ac2, 0xd598f771, 0x89e57236, 0x472d887c, 0x01757ad2, + 0xe98aea11, 0xea51243d, 0x26ccb359, 0xd7ad5777, 0x856017b1, 0xdbdd8f54, 0x5fd25865, 0xff70f445, 0x5e678fc1, + 0x9143078d, 0xd1001d25, 0x5fb99d91, 0xebdb4a7e, 0x299eed15, 0xf804a8e1, 0x0060b0ce, 0xc8826df4, 0x64fdc4bd, + 0xa20a85a9, 0xabe218a0, 0xbaeb1d06, 0x97454c3a, 0xe73584b3, 0x2ed4d6d0, 0x075bbe2f, 0x2b066332, 0x5057711d, + 0x3ea562de, 0x12f19209, 0xddebb68d, 0x9d86f1c3, 0xe67b0ad3, 0x483837a4, 0x8e24bbc2, 0x821478a1, 0x4504b886, + 0x8581b62a, 0x2602bcd1, 0x22767bf5, 0x3f38761c, 0xd36c62ef, 0x59a75948, 0x5c8770ab, 0xd8c91bae, 0xd58cd2a2, + 0x1f516691, 0xcf073d87, 0xda7b5736, 0x815e48e4, 0xae93d68d, 0x06dda188, 0x31e9a44b, 0x5d2b4be9, 0x59fb358b, + 0xb7651551, 0x25516ad9, 0x5c6db49e, 0x6f313106, 0x2ee99099, 0xb77931d6, 0xac758546, 0x04a8349e, 0xd42ff0ca, + 0x5ac6ca2d, 0x6009589f, 0x4822185c, 0xa06f4d80, 0x4bfec3f2, 0xacd318bb, 0x4e192596, 0x6714b64f, 0xf9825e58, + 0xfe638a1c, 0x5330cd6d, 0x7ffabff3, 0x70e1a4b2, 0x611c1d6a, 0xb89a15fe, 0x5694fa37, 0x4a2ada65, 0x696bb9d0, + 0x1cd3f89b, 0xaeb299d4, 0x7c9a6264, 0xe34b24e8, 0xef82fd0a, 0x37d159b0, 0xbb7e06e7, 0x0331a8b3, 0x154efd07, + 0x11f499e1, 0xb2c94bb2, 0xf2651a86, 0x12263988, 0x628934c1, 0x5f2f7a3a, 0x9a188b7e, 0x18eef4b4, 0xf772ac27, + 0xcb3642ea, 0x85647a9c, 0x92d99844, 0x6243dab1, 0xdb2cc472, 0x5af6e61d, 0x0879293a, 0x289022b7, 0x775dfbd5, + 0x2c88d058, 0x303864d9, 0x31cd279e, 0x99109b7a, 0xe9dbbc82, 0xd9f20e02, 0x35a3f5c8, 0x89bcec41, 0xf9b8e1b5, + 0x7ba2247b, 0x6c36b6c0, 0xff4684a9, 0x20e180d1, 0x1a26f5af, 0x3f029167, 0xc6286578, 0xea671668, 0x7dace0b1, + 0x9fbac223, 0x07bbed79, 0xa5265f64, 0xc9484628, 0xece44e21, 0xdf2b347c, 0x5d82bffc, 0xfd955ff3, 0x4e7ef717, + 0x9d3fe9f9, 0x7f32f83c, 0xf00c221c, 0xb4fd09d2, 0x67a02906, 0x777164a8, 0x32d47c14, 0x63a69faf, 0xd284948d, + 0x0afc1749, 0xf938e7f7, 0xde2679f1, 0x168f8dfd, 0x4783b9d4, 0xf2e3b92f, 0x35006c0d, 0xef93e013, 0x82259e83, + 0x82f4ca07, 0x4e3a1329, 0x2a443a9f, 0xd9353c37, 0xb2379bf8, 0x77bf23d4, 0x566e873d, 0x1bba9d69, 0x39764f4a, + 0xccb87f8b, 0x14e2c0b6, 0x7d0f1de4, 0x0ef8d912, 0xbb53ab97, 0x47669e07, 0xea29ce01, 0x43a79faf, 0xaed6704c, + 0x64868c06, 0xbd82b7ad, 0x629a3f4e, 0x5afa0b51, 0x4ab84053, 0x1a7194be, 0x1b0a8b74, 0xa9d72c5a, 0x75a2e829, + 0x0f9c49b7, 0x44321f10, 0xd37cfe07, 0xc5033924, 0x1f05eea4, 0x171aee5f, 0x549d29e3, 0x4169e2f0, 0x50042885, + 0xbc246839, 0x38873ef7, 0x70e71270, 0x2c89bee7, 0x0b0717c6, 0xe4fce65c, 0x4f759dd4, 0x646cef04, 0x3b91f684, + 0x3a3cb522, 0x52ee1abf, 0xbcdd918c, 0x9b47ceb4, 0xdedf4465, 0x0581d548, 0x04f6a22a, 0x7e3ac534, 0x1ace5460, + 0x292e9b3c, 0x888a7ecc, 0x111bd10f, 0x99a6c0d0, 0x37cdb16c, 0x8b7a4425, 0x4bb67439, 0xc6ff1f52, 0xcdbb6907, + 0xfb2c5f71, 0x3b950fa1, 0x0c2d4968, 0xd22eaf28, 0xa64eea0e, 0xe8f970f3, 0x7fd2e257, 0xb715cde4, 0x7dd46897, + 0xf8289696, 0xbf8a043e, 0x4afa1921, 0x79282c60, 0x23f8c563, 0xac172d8e, 0x400bd37f, 0x9aac6ca3, 0xadff1bf1, + 0xe38bacf5, 0x87996d7a, 0x54a2cec0, 0x2726dcf4, 0x17c7c9d3, 0xe67e7b39, 0x33663023, 0x538177a8, 0xdd0a4e50, + 0x1236c4fd, 0xd2e3dc27, 0xf03115e3, 0x7e2023b1, 0x2f7776f3, 0x43eace5c, 0x4cb71de9, 0x3a578723, 0x96330541, + 0xd66d57a2, 0x79f5e600, 0x1b0bb439, 0x1fed0086, 0x48b9e355, 0xeb8e91f7, 0xabde5122, 0xac4ef5f8, 0xc4594b5b, + 0xae8b0108, 0x9a83c393, 0xc13dce78, 0x86e71171, 0x1ae2b8b9, 0xd99d9607, 0x4632f1c9, 0x43f4892f, 0x96dc92bc, + 0x9c0da8f2, 0xeb8b79f9, 0x4207a730, 0x5b41afb7, 0x52fac629, 0xa78fa6bc, 0x0b43422a, 0xdd67e117, 0xcd3887eb, + 0x40f6f403, 0xbf52d1f6, 0xcd3fde6e, 0x6e201eb3, 0x62038e71, 0x2e4a0950, 0x34794045, 0x66261bf5, 0x91428efc, + 0x8d7d1036, 0x2b72f182, 0xa66c5063, 0xdea7bca6, 0xc8035e3e, 0x06faa4a1, 0x26722e5a, 0x082c86c4, 0x2a20a5d1, + 0xcece0551, 0x843be80b, 0x6a17fac9, 0x2caaaf1a, 0xdd865166, 0xb33d96c9, 0x536f1d97, 0x4763c816, 0x165d9809, + 0x3ad92896, 0x018e14be, 0xe31a780c, 0xe206ea16, 0xb1d37e70, 0x125e4b64, 0xd825cc67, 0x0b065f7d, 0x4e6b7e9d, + 0x4c6a5492, 0xca0726b6, 0x49c15c6a, 0x51402531, 0x803e3a93, 0x786e0349, 0x090fdaef, 0xe5491043, 0x75afc300, + 0x71a6bc29, 0x65efd0e0, 0xa15d5345, 0xfb744e2e, 0xc13dab30, 0x23a06cac, 0x359fe5fa, 0xa9e0d9e8, 0xbc01ce45, + 0xdf7e16a9, 0x5340688c, 0xdd4fe1b6, 0x4ca4ee01, 0xe2dec18a, 0x41caa48d, 0xdd0032ba, 0x71014307, 0xe07bdeb1, + 0x291c3ba6, 0x12620de2, 0x3d5a6519, 0x2343bc8c, 0x7a8c0e28, 0xf2b6e2ff, 0x479e66ee, 0x9a0025b8, 0x77fafe4f, + 0x01a4eba7, 0xc6faa1db, 0xbd4f4ffd, 0xd937e0f9, 0xfdf68d03, 0x1061f0ea, 0x6c8be0ba, 0xeed88a46, 0xa8b9b97a, + 0x2760b9bb, 0x322b6aa0, 0x48052305, 0x7580cc1d, 0xfd19f871, 0xc52bbc84, 0x127ee0d6, 0x2144e28a, 0x9f448e8f, + 0x9b5343ea, 0xa70a7097, 0x5d38cf2f, 0x2d03e9ae, 0x0bb96210, 0xdef9d77e, 0x2b49e626, 0x4fbd0cdc, 0x7eb0a5c9, + 0x6d03d59d, 0xc25d0147, 0x4697a2c0, 0x7cdece15, 0x782ee508, 0xb939f2c5, 0x9e981855, 0x6aca0cad, 0x336cce92, + 0xf030ed89, 0x8cafa7c1, 0xf858c121, 0x2caf1b16, 0xe2dbb97d, 0x6031008a, 0xbb42b6eb, 0x59847b8e, 0xb7debb32, + 0x2c12f199, 0x9a4c7332, 0xfe985aea, 0xc037cbf8, 0x1e33b2d5, 0xc594a03f, 0x641f9d99, 0x7db1568b, 0xa5c947b2, + 0x23b12c1b, 0xbe44d91e, 0xc04a8000, 0x1659ca3f, 0xd8b46e15, 0x068c9405, 0x209dc7ee, 0x4ed8962a, 0x4f8dd62f, + 0x2ede1fc4, 0x244f61de, 0x83daffb3, 0x2b28d968, 0x38dd7b55, 0xd0e6cd0c, 0x1172da17, 0x41f64cbe, 0x3f500d0a, + 0xeaeebf8b, 0x4f80bcf6, 0x29d9172b, 0x2af6b598, 0xe3a18caf, 0x3dfd77e6, 0xa0d941a0, 0xa3fd9f0e, 0xd6dfd70c, + 0x5c3f81b3, 0x3d644f24, 0x60082d32, 0x5d4c0676, 0x3afffe89, 0xc80b5547, 0x9d943943, 0x424430a2, 0xb3a4e5c4, + 0xf5bb2144, 0x1084d92d, 0x7ea3e332, 0x38898888, 0x20cbca4d, 0x18981394, 0x1a26b427, 0x3c5e8685, 0x24715561, + 0x1a295c97, 0x1728a499, 0x1b6bfa0e, 0x1bca92d4, 0xa8fa7663, 0x717bec98, 0xc4853dbd, 0xd66347bd, 0x6463e22c, + 0x7a4285c3, 0xc1e2a6d8, 0x2a0bd15b, 0xee10dd49, 0x778cb87f, 0xeb947afc, 0x1e4b04b1, 0xd266e525, 0x8f135d6b, + 0x19dca368, 0x35abe51d, 0x5d573ee3, 0xfa87b390, 0xece24f0d, 0x3f4dfd79, 0x3a142d98, 0x3ce76539, 0x7987ae45, + 0x1a617d01, 0xf9eb0345, 0x80cd6931, 0xcfc2e446, 0x6f7d679e, 0xd74de4fc, 0xb660598f, 0x02301c57, 0x3dce6e80, + 0x65ddbd03, 0x87cfb833, 0x09e5b257, 0x4c501c23, 0x2b28ac94, 0x285b2e98, 0xc6e0c877, 0x76050f1c, 0xe0072456, + 0x3425366c, 0xc63cc4d6, 0x4d17229f, 0x1f0a4b09, 0x9c7d5a73, 0xf4824cc1, 0x54081524, 0x568fa70a, 0x96635ff8, + 0x334a7f1e, 0xab1e2a6f, 0x8670c1a9, 0x1192fb9c, 0x0ef31f27, 0x48c7c3b5, 0xa5d44259, 0x011ecaed, 0x570ed039, + 0x683d1c5d, 0x7ba418f5, 0x81c26577, 0x6df4b105, 0x242fad3d, 0xcf156af5, 0xfb93105f, 0xa98747d6, 0x9d0f32a6, + 0xbe5f648e, 0x2c9ab4d0, 0x104aa52e, 0x5ccd3fd2, 0x2f59ffed, 0x5611296a, 0x1d66712d, 0x03bac541, 0xaa365585, + 0xc47c8c84, 0xdda5852e, 0x927ed385, 0xadaacd30, 0x4bd93d89, 0x44542438, 0x26f49cf0, 0x217837d6, 0x7921ff3e, + 0xa3015037, 0xeeda0115, 0x2d21c8d0, 0x1a111c99, 0xf9ff1a25, 0xd5d404fd, 0x36e4bd8e, 0x075907a3, 0x540a2cd9, + 0xdd1fce2b, 0x8a88a2bf, 0xf8c1bf16, 0x189c5844, 0xf2020a2e, 0x04b5c0e3, 0x3e574918, 0x3d1dda73, 0xe518d1a1, + 0xc043786e, 0x323a26b2, 0xcec1b5d3, 0x65d87d34, 0x1e7d2702, 0x905dd1bd, 0xa8395ee5, 0x249a5ee7, 0x4fd5e4a2, + 0x0d89e747, 0x56d0b3bf, 0x1e52255c, 0x374a0d96, 0x20715cc4, 0xb7100457, 0x32523fbf, 0x4b4ee063, 0xab73fb91, + 0x24760e62, 0x340091a8, 0x272a129c, 0x03493240, 0xc9d1c52b, 0x40cfb5f9, 0x41bcd22f, 0x23454170, 0x6565c3e2, + 0x177de95c, 0x930d9d2a, 0xca789491, 0x5427787a, 0x7c483e30, 0xb4b4bc0c, 0xe539b3a1, 0x6fc8e8ec, 0xf027efd5, + 0x55975b0e, 0x7ebb63e5, 0xa56acbc4, 0x18278a25, 0xa6f6a9e5, 0xbe14dfdc, 0xd2065f4e, 0x3de7c689, 0x2bc9ced2, + 0x2e5b5983, 0xafbdc2cc, 0xb03596bf, 0x40916d4d, 0xc83a5411, 0xa8c2da53, 0xe6f73f3f, 0xea89ced3, 0xf55dba4a, + 0x1ee6bbb8, 0x0a9892a7, 0xd56006f2, 0xec138a8d, 0xd01d7ed0, 0x1e4ea83d, 0x8be0c1d9, 0xcfa0b005, 0xf532b9f0, + 0x80563984, 0xb3a59038, 0xb23e08cd, 0xa5a470be, 0x4bba6dca, 0x1dd6348f, 0x1c49403b, 0xa1853f27, 0xb7b99d57, + 0x81160a99, 0xe9ea5ec5, 0x08e38190, 0x8ef5f4f6, 0xa8295bee, 0x3011a30f, 0xdd3e6935, 0xb58906e2, 0xd78aa7e2, + 0x4f823fec, 0xb2ad6be8, 0x3873af4e, 0xe489245f, 0x4c7c95d7, 0x64e3e4ce, 0x8f812234, 0xe34e2e8b, 0xb8e0690c, + 0xf93594c2, 0x7c247776, 0x4663978c, 0xdca98fa6, 0xf4fbad3a, 0x3bf1d597, 0x8859952f, 0xf9b7f6ed, 0xb2a31f3a, + 0xb4b93325, 0x379f5037, 0xb905c1bd, 0x19c30685, 0x24e4a7bc, 0x6bf23fa1, 0x95c1100b, 0x519048b7, 0xace71e73, + 0x3a79dabe, 0x2e28741e, 0x81c69dea, 0x21d4fb3c, 0xa0e6f814, 0x24b96f4d, 0xb987ddb7, 0xe7ee4975, 0xc6581e75, + 0x1b9f5be5, 0x45d5c546, 0xb8249841, 0x30c5b565, 0x1cc86c3a, 0x5337600b, 0x83784964, 0x513d5024, 0xbe69f80a, + 0x79790f15, 0x5223ac8b, 0x9f14b51a, 0x6d0a302e, 0x3a403446, 0x5db50618, 0x261660c7, 0xe6f00b11, 0x3977e572, + 0x06d23287, 0xe87aa100, 0x7653d8a2, 0x8ad07029, 0xdc0f04ae, 0x3edec3be, 0x56048113, 0x6f234b20, 0x5e87f1e3, + 0xc782d926, 0x0c265d6a, 0x72d032b6, 0xdd15a724, 0x1c1d52f3, 0xe367698e, 0x4294ef0e, 0x4143e789, 0xe82ee7f3, + 0x212fc9e6, 0x1ad603c5, 0x0f20a3d1, 0x61e50210, 0x0fdc8bcf, 0x5932a583, 0xf1b56bf8, 0x5bb67d8b, 0x8ba45140, + 0x6ee508d9, 0x7fd68f47, 0x23a808c0, 0x4a168099, 0x58e53eea, 0x703eaf95, 0x3ef2658f, 0xade384a4, 0x6138e01c, + 0x4a15a496, 0xd29305a0, 0x9f21018c, 0x93cfb677, 0x662c1ec0, 0x7cd8b90d, 0xfd9af42f, 0xb2248ee2, 0x0e9d53d3, + 0xb0367499, 0xdee4eb92, 0x60e27ac0, 0x815cd91a, 0x8ae80ac4, 0x5ef42cd6, 0x60b28a74, 0x86a6a326, 0x271f96ac, + 0x185b53fb, 0xbb329cdc, 0x75bbb1f3, 0x7a70adae, 0xfca41b74, 0x7a9f7778, 0x3fcd20dc, 0x6bcb966d, 0xae0b1f48, + 0x9c11bb2e, 0x45a6aa0d, 0xb6bb0544, 0x50ea381d, 0xadd09811, 0x34f6f98f, 0x050828cb, 0x15ea3717, 0x424faca8, + 0x0a07673b, 0x449b2062, 0xd7ee65cd, 0x41d2381c, 0x0343e106, 0xeb9f6633, 0xb38be08a, 0x2af63bf3, 0xded57c0f, + 0x24951246, 0xadf66c46, 0xdd2b97d3, 0x0b31f6e3, 0x3fe85ce2, 0x02a157bd, 0x7125b2a6, 0xa8ed921b, 0x8fe635b7, + 0x5675e045, 0xb2484af8, 0x309db473, 0x2d593fe3, 0xfd18c533, 0x5ccbabab, 0x816d939b, 0x3a8d7d2a, 0x18a1046f, + 0xa70f7f07, 0x8ebfd848, 0xdb04cb5d, 0x18679d68, 0xa7c46dc3, 0xaa43d48a, 0x76f0ea38, 0x9f00b75f, 0x4d93ab58, + 0x97a11726, 0x7279dac2, 0xdf4d15da, 0x46713ffc, 0x772e838e, 0x6a741427, 0xea4d6225, 0xbc28a5f2, 0x020c9ed6, + 0x3340a141, 0x1b49858f, 0x0c1a5bbb, 0xc79c5877, 0xe9c40b9f, 0x7c8087ec, 0x50fa6e2a, 0xd71d3ba2, 0x3612d60e, + 0xb32edccb, 0xde625545, 0x9dd1884f, 0x32cdc3b5, 0xec61ac1f, 0xfebd821c, 0x7a172cb5, 0x6e7f9bcb, 0xf45be6f5, + 0x5db0286c, 0x775a8031, 0xfe341cec, 0xcfe4063e, 0x38beb50a, 0x8419ce45, 0x17123771, 0x8400db40, 0xc3efbead, + 0x8f5b9513, 0x95344c32, 0xc6dccf4d, 0xa921693f, 0x7050fef3, 0xc49e00e2, 0xc9f5c993, 0xb5ced0e8, 0xac6ba2e6, + 0xf267773d, 0x63c05f7e, 0xe0ee9f17, 0x2245f10c, 0x829b5bdf, 0x8bc83629, 0x1d3e6a58, 0x1494f0f8, 0xdbea3303, + 0xa0a6cf33, 0x4160089a, 0x74a2d125, 0x52bb0fb0, 0x4c870caa, 0x251d0e27, 0x77785b1f, 0xf170652d, 0x24354645, + 0xb35d8108, 0xc6634f94, 0x7682e399, 0xe2d57a0a, 0x98839a66, 0xa12f68be, 0x88e9a2b7, 0xd9f0f4d5, 0x4bcb26f4, + 0x094c9319, 0x97a12c3d, 0x948b809a, 0x17831f90, 0x7296b7b4, 0xf5e22d34, 0x8108ee08, 0x58283fa2, 0x3f85f63c, + 0x78848d7c, 0x62926dac, 0xa4d6bf26, 0x41de0d3d, 0x8ed651f9, 0x89cf3df5, 0x492f7e33, 0x2065bf13, 0x3dd3439f, + 0x8366c69d, 0xc03505e7, 0x07afc857, 0xcd19bf4c, 0xe95ffcbd, 0x5139567a, 0x52bef3c6, 0x5f9dd084, 0xb5768d78, + 0xf1f4149d, 0x666fc892, 0x932c27d7, 0xec5ff1bc, 0x50d6bac3, 0xbe1aed17, 0xa34e01b8, 0x4aaef768, 0xf3448a73, + 0x55c860bf, 0x106f33c7, 0x48da17d2, 0xd9df6c2f, 0x70b625b6, 0xf9959a38, 0xb47b0ebc, 0x25200988, 0x29d0c4da, + 0x819c572a, 0x2b5100fc, 0xcb44efbd, 0x38693bf2, 0xd4701a28, 0xa6cb31f6, 0x5e048628, 0xfb20df8b, 0x451f55e6, + 0xb1fa0194, 0x5c5632ec, 0xe164d3c0, 0xa91ce4b3, 0x4268adfb, 0x5dd8d8db, 0xf4bdc713, 0x08b68c32, 0x858a64c6, + 0x0f3a6c8a, 0xd31d93ec, 0x33a2ffb5, 0xdd5a453c, 0xfd5ea415, 0x1c7ec15b, 0xa3146722, 0x7b74e9c7, 0x9f3ca02d, + 0x1014cee2, 0x3050bf74, 0x051aa679, 0xa05b36fa, 0x4fca0622, 0x6d4f3eb8, 0xc6fa90e4, 0x06a9e646, 0x1d2378cf, + 0x4d9117a4, 0x684e320e, 0x21be1a49, 0x7c268ab3, 0x7901e6bf, 0x6158ec15, 0x32a261bc, 0xdb41b0fe, 0xb68ff7db, + 0x51420568, 0x51269cab, 0x45553971, 0x3cfc4ab5, 0xe0968f5a, 0xfda23f36, 0x478abac8, 0x4fe0b545, 0x470471f5, + 0x24b1ec26, 0x41a00925, 0xd85e79fe, 0x108eb2c5, 0x964de8ff, 0xcffe493d, 0x417eeabe, 0x8c48badf, 0x2203ad1a, + 0xbc9d7ebc, 0x469a811c, 0xfda71c4c, 0xeb617574, 0x778fa89d, 0x6404ca45, 0xea7eb4e2, 0x75011f37, 0x259f9823, + 0xa95eb2b5, 0x200166d7, 0x929b967b, 0x3dbc6c8b, 0x887e3bbc, 0x0e91ac6b, 0xc927b046, 0xc3a82d99, 0x14a19cc6, + 0x648cc1c3, 0x545c6e37, 0x8c89cbed, 0xec54264c, 0x6cbedefa, 0x6431e9ad, 0x9af873f3, 0x1afa08bf, 0x516852a7, + 0xa7baf26b, 0xc4d35289, 0x3650dc4e, 0x6c83c079, 0x46f19780, 0x2716adcd, 0x268bc16d, 0xd765b804, 0xc4c7d8d3, + 0x6fbbed76, 0xaead230c, 0x2fcd30ff, 0x920d1001, 0xcb199b70, 0x8279380a, 0x8f1e5676, 0x691aee5d, 0x023367a8, + 0x40ce04cf, 0x80b28330, 0xecec8f0e, 0x6ddca04f, 0x1b026ee9, 0x8633dded, 0x503fb2e2, 0x7bc3dea4, 0xc981b9f9, + 0xa38bab35, 0x7bb8521d, 0x6077d00a, 0x1e70f876, 0x445ec589, 0x14eab75b, 0x150140a3, 0x9360a30f, 0xbf687993, + 0x7bfbddbd, 0x634eb082, 0x5ab9a810, 0x98e6eb0e, 0x2df7b610, 0xf434274a, 0x7e1daaac, 0x58fde125, 0x381f1a3b, + 0xddaf7c09, 0x7d1b2c52, 0x929c5f34, 0xc69398aa, 0xb53fb5a1, 0x918b135c, 0xaf8f7f25, 0xef3476ce, 0xafb1afaf, + 0xe5596068, 0x200697de, 0x33be5fc7, 0xa145571b, 0x2c6d26ed, 0x535de201, 0x9e813ece, 0x9128fffc, 0x77d1ad44, + 0x9befde34, 0xea4b41dd, 0xba7a4913, 0x21e95de8, 0x1e96f7ec, 0x9eec5aa6, 0xe07ae5c8, 0x658d87e2, 0x3d4660de, + 0x6265ab64, 0x9ff7f78f, 0x4820939a, 0x08fc266d, 0x462eec75, 0x08fc11f2, 0x7af25830, 0x6ac78ee5, 0xc041f5ae, + 0x69c84975, 0xc51efc7c, 0xc8281c6f, 0x26ade9c0, 0xa6242968, 0x5f10dc76, 0x1db88c5d, 0xff7d9f17, 0x65bbfbca, + 0xd2805666, 0x432e4d9b, 0x8381d503, 0xa76ddbef, 0xdb1964ee, 0x4c029133, 0xd695f2fe, 0xae161af9, 0xc50e05cc, + 0x75c8ed93, 0xe3437ad5, 0x08ae7237, 0xf9675c60, 0x8fe0e99f, 0xcadf4be7, 0x3ebf7612, 0x3550d3db, 0xc7c83ef8, + 0x7c1e1759, 0x00dbc66b, 0x5cbac9d2, 0x3597b922, 0x1e1e3355, 0x10d99744, 0x3f9ea0f7, 0x4ab57ad5, 0xa881ac18, + 0x10e0d659, 0x24ae9767, 0x1c38f619, 0x39aa2d20, 0xf4fd7219, 0x7155a3ff, 0xce8d6dee, 0x4f475409, 0x16f7efc6, + 0x0185c15f, 0x935ecca0, 0x4cf071ef, 0xf3af7b49, 0x70c86b7e, 0x41775d25, 0x5a37ca16, 0x008daef3, 0x5100a039, + 0x2fd53c38, 0x78eaf679, 0x8351fd1e, 0xd7bfe854, 0xac9207b9, 0x87b05ff2, 0xc6f31901, 0xa50f7afc, 0xffde3ca6, + 0xde079fe7, 0xaee223e5, 0x6e23524f, 0x84951bd9, 0x8c64c52c, 0x66774c4a, 0x4925b493, 0xe4b81421, 0x6b0e1383, + 0x3a81a959, 0x284861cc, 0xf4fa345a, 0x5d4d1245, 0xffc68fcb, 0x4e6facdc, 0x188ac395, 0x19b13157, 0xd876951e, + 0xdd995ca1, 0x76549427, 0x2b0b5610, 0x2c1ca852, 0x919a1742, 0x77df8800, 0x7286f2ea, 0x1f4c4b2e, 0xfc014ac7, + 0x2221d628, 0x4200b9d1, 0xa699d550, 0xdecc521e, 0x920481d9, 0xdade7765, 0x75864446, 0x3e6d147a, 0xfe124883, + 0x147d8f51, 0x8de7a9d5, 0x1efccd37, 0x30e0c188, 0x9fd328b7, 0x7e6f8ca4, 0x6ce9253e, 0xe3e20b27, 0x4737676c, + 0x9ea8c3bb, 0x66ac3dcc, 0xc12f6e8e, 0xdb83bd19, 0x77002024, 0x1383a74d, 0x833a1e0b, 0x9f747ade, 0x5d842867, + 0x8a651fe6, 0x660bf5b4, 0x6126caa4, 0xd288949c, 0x0a375ccc, 0xecefdc8c, 0xb86eafbf, 0x72a24aa5, 0x3e0cbdbc, + 0x203f0ff8, 0x6d34682f, 0xfb360c80, 0xad7de30e, 0xbd6469c7, 0xc99281c3, 0x83749f4e, 0x6dd204ed, 0x22df29fe, + 0x3a760d8f, 0xc1d29859, 0xc6f41bcf, 0x426e8dd5, 0x0a78dd67, 0x5697b4cc, 0x54464f5c, 0x4b794a08, 0x629cd208, + 0xba6e9f7e, 0xe45f8d89, 0xaa9990e8, 0x65362efe, 0xb4b0d1a4, 0x4e94c74b, 0xbe4d4b69, 0x80329293, 0x669848a7, + 0xd48f3bae, 0xa2e33679, 0xeeb4e514, 0x1370c897, 0xd5c02f6e, 0xefcb0f04, 0xec9bb166, 0x3f7387fd, 0x0cb5e0d0, + 0xa4e48913, 0x7d21a83c, 0x479b2298, 0xe21c68e1, 0xc4754c09, 0xc712fe03, 0xa06792bc, 0x91b0647c, 0x2917b0b1, + 0xba84f212, 0xfdd43daf, 0x05978ba0, 0x1ba0a877, 0x59295846, 0xf5eb7c20, 0x27f89e64, 0x9b704292, 0x7fe3bc7a, + 0xd64ec3bb, 0x591e3eb7, 0xba4bf60f, 0xa0b4812f, 0xeacdbe70, 0x35eced66, 0xb786faf5, 0x116de8e7, 0x5ffc5824, + 0xdb2b200a, 0xc73fc05c, 0xd6bcaaae, 0x0b4bbf04, 0x788a06ff, 0x63e7a530, 0x6cd36863, 0xd99977df, 0x4a99afd8, + 0x41f3190b, 0x083e4441, 0x4ba88689, 0xfa0ef62d, 0xd9bccb42, 0xfc0797f7, 0xb3dc581d, 0x4cb1892b, 0x2f7e1498, + 0xcd9215ff, 0x79ae278f, 0x59838b3d, 0x7b1737e0, 0x54244f7f, 0xb72a52bc, 0x2372985a, 0x12241d53, 0x6adc8539, + 0x9711abd0, 0xd8b24f36, 0x01980a3a, 0xd8b59f84, 0x75086d69, 0x62b3966c, 0xd01343a6, 0x6eca5c0d, 0x549577f5, + 0xbe111715, 0xd701d42a, 0x05a1bdb0, 0xf278ef4c, 0xae31e504, 0x6ed7bdee, 0xbf4c349f, 0xa74eb3ea, 0xb71274f9, + 0x91a56ca9, 0xbec35738, 0x9739f40b, 0xc005cbfa, 0x82cd5983, 0xee0cf47f, 0x4469cf1d, 0xd2aef6dd, 0xbcd7b016, + 0x986e82fe, 0xfd978861, 0x10c210d2, 0xfcbef2c6, 0x64f9f6ed, 0x15328bf5, 0xd9e50897, 0x457abbdf, 0xc85b4203, + 0x159cdf7d, 0x6fe38deb, 0xbba6e24c, 0x08771461, 0xbefdd29e, 0x5ca06667, 0xcefecb37, 0xc90661ad, 0x5e14f4dc, + 0x74f49c9f, 0xda7c7d89, 0xc54fb68b, 0x043b3db6, 0x4c577d46, 0x5785334c, 0x52fc2178, 0x9a0c4c9d, 0x22a6fb86, + 0x6762809a, 0x916c206c, 0x0be02f2c, 0x0dd94a9f, 0x66ecef06, 0x59a72d52, 0x4d3ddceb, 0x24c99b74, 0xec1bd3ed, + 0x280e6a89, 0x3fde1fe8, 0xc841196e, 0xdcb4ae66, 0x20e61c69, 0x226a87cf, 0x4ab88f39, 0xcdb51598, 0x1007a046, + 0x500958da, 0x46dd3be3, 0x7e9e433a, 0x973e279c, 0x35d9cf50, 0xeb26cffe, 0xc471c52c, 0x039ce931, 0xe0f97b52, + 0x4360a983, 0xf5ce202b, 0x21200db2, 0x32aade18, 0x53afc633, 0x2469d2f5, 0x89d24d88, 0x3bbb8c80, 0xa791e6b9, + 0xbec46474, 0x70f70413, 0x6ffd6368, 0x3c16cf1c, 0x41d2c391, 0x470bbd7a, 0x5f32bbcb, 0xd56672f5, 0x0199fcb1, + 0x21d9bf1a, 0xd03cf321, 0x1369cff2, 0x0ef098db, 0x00eedf16, 0x2e133a49, 0xd7b7de5f, 0xe2eb3b2c, 0xf4519b3a, + 0x0c62b78c, 0x9464783e, 0xdf71e28e, 0xd6bb3b8c, 0xb36cf127, 0xdf5ab111, 0xd0ef39ea, 0xa5721896, 0x3a8b8e81, + 0xa77fc3c0, 0x3eaa5f4e, 0xbf5566ce, 0x95b6d489, 0x24246e76, 0x3bc2d37a, 0xbcdf8d25, 0x3ebe7a59, 0x7f610c91, + 0x7736bcdd, 0x75bc2424, 0x85c70d05, 0xbeb7ba24, 0x4423de3b, 0x228f9f73, 0x7c01c1bf, 0x9f0d29a4, 0x61a80872, + 0x3ec5601f, 0x27ba04c4, 0xd7a5024e, 0x71452235, 0xfb211dc9, 0x61aa93d6, 0xbf25696f, 0x22b2f2a2, 0x969488a2, + 0x82dff5ba, 0xcfe623fd, 0x88329b88, 0x4cccb4ba, 0xb76482cc, 0xe5023477, 0xa46a3894, 0xbe7c5404, 0xd1fd3901, + 0xe6bbe2ce, 0x0c4f1b4f, 0xacc9b278, 0x3db561f4, 0x332dc3b6, 0xf38df13c, 0xeae891c4, 0x8f00c6d3, 0x778f1d35, + 0x99846b91, 0x5f3096ff, 0x4a87ec24, 0x7c7c7bfa, 0x47ee71c1, 0xb372259f, 0x572c7bbb, 0x9fac8e01, 0xbc3e5e7b, + 0x0a98ad4a, 0x8724098b, 0xb65b4238, 0x08816daf, 0x0ba64183, 0x50cc14e1, 0x42895df2, 0x8858e739, 0xcbe17ba9, + 0x1b74d24f, 0x4402d400, 0x5cc6ed20, 0x279a68ce, 0x7127622f, 0xb430e865, 0xe15ef496, 0x0ebe1de7, 0xd28793ef, + 0x1e95ce31, 0x753f0cb8, 0x9bdb6bfd, 0x5ecc4ba1, 0xf4421461, 0xadf6bdfd, 0xc01bd28e, 0x4419125c, 0x2d7d94e3, + 0x5073c54a, 0x96aeece3, 0x840a2b99, 0xb24aa255, 0x38345e2f, 0xf34125d6, 0xc761e37c, 0xb5ef96ce, 0x11d2d1fa, + 0xad59d51b, 0x360870ab, 0xbfcdf45d, 0x480e2047, 0x0dfda9b9, 0xdae944f9, 0x6f03ee85, 0x3b6f8dec, 0xed9fd4ce, + 0x2cfd70f7, 0xcb88d469, 0x5935984e, 0xa8d78801, 0x341df785, 0x020e6c47, 0x65f12cef, 0xdec04f23, 0x03e3fe4e, + 0xdd3008ff, 0xada46c49, 0x85e22f56, 0x278bb9f1, 0xfdcaa6b5, 0xaf47c5c9, 0x01381941, 0x3f60c1f6, 0x67f8da0e, + 0xa5939439, 0x4c0f815f, 0x2a17adbe, 0xed844395, 0xf2574d5b, 0x55e0b113, 0xdc8a1aef, 0x7ec73cd1, 0xb4d868e0, + 0x56f54288, 0x636cab2a, 0x5b33eb1b, 0x1a4f3fda, 0x613a2cb4, 0x5fac0fc4, 0x082f9f9a, 0xddea4a23, 0xc1484a94, + 0xa75a8bf9, 0x5575b1b5, 0x895bf61b, 0x7e3d5b23, 0x0c504c94, 0x8f7002be, 0xbb91b010, 0xe0c0e536, 0xdb74aee7, + 0xb1364dd8, 0x2d7610bc, 0xf0b00272, 0xa69f0300, 0x66e18979, 0x3268085a, 0x4efa9e50, 0xd084d664, 0x360f51fb, + 0x6b7a7c30, 0x2784ab4e, 0x3783c57e, 0xccf4e91d, 0x53b8639e, 0x194c94c8, 0xfe9f1f85, 0x2c3fd121, 0x5f61d770, + 0x5eae06a4, 0x58696c5a, 0xfc6871d1, 0x190701f4, 0x6ea70120, 0x1aabebf6, 0x634f5197, 0xee0233f9, 0xa86fec8c, + 0xf8b401e5, 0x3d41f088, 0xd040ff28, 0x35e174dd, 0x5e62e392, 0x7298867f, 0x4a0141f9, 0x16af8a83, 0xe79ade31, + 0x600f270d, 0xfba0bc80, 0x963ef16f, 0x1d356ea0, 0xfecd8e0f, 0xbe48905f, 0x4e444b91, 0xb00ddb84, 0x50dc11cc, + 0x66dbbdc1, 0x9b70316c, 0xaa65c3cd, 0xe4c95a37, 0x16807f45, 0x1c780fdb, 0xe48d9478, 0x551787d5, 0x5a9f9918, + 0x73d898a7, 0xdfadd8fd, 0x1929933e, 0x68ba46fe, 0x20216b46, 0x8ed90a4c, 0x468398db, 0x3d7c8352, 0x1791921e, + 0xbb5f1e08, 0x7e566151, 0x1c65b9ce, 0xd9a2f352, 0x81d68bd6, 0x80c980f5, 0xc9fd0a8f, 0x536fc6a3, 0x9e9d42bf, + 0x82fa063e, 0xcb52fabb, 0x07be95ad, 0x4677fb89, 0x3e6ce045, 0xa3b66e20, 0xc5061497, 0xffd971db, 0x5f535bc4, + 0x8c327bdf, 0xb1bc1ead, 0xea9cbf9d, 0xcdab1f9a, 0x76b2d7f2, 0xc3c2c476, 0xbffc7ea3, 0x0f2a9fdc, 0x33a14617, + 0x3fd9bb97, 0x07a1f3d9, 0xec3fabfb, 0xa9ff2d22, 0xf777121f, 0xa64456f4, 0xf7d1bd52, 0x411f3c98, 0x0f55fb48, + 0x053eacbb, 0x700c0ed5, 0x83b963ba, 0x97cd7698, 0x6f220158, 0xca43ce0d, 0x6b29fdf8, 0x60f1b4c6, 0xd547b235, + 0x0358ad8d, 0x7ebe869c, 0x5af8778e, 0xe2fbc986, 0xbd1c082f, 0xcd059775, 0x3cabcfda, 0xe2376984, 0x4747e9a9, + 0xd2373caf, 0xf6a5860b, 0xdfa4021d, 0x69ad5b16, 0x2284c521, 0x59d71496, 0x5f9c7000, 0x0c3b6c91, 0xbb9b4879, + 0x97582d54, 0xe0724668, 0xe2aeaa4c, 0x331f51b8, 0x6e2ca429, 0xc016e51e, 0x1c42d62f, 0x8b48d470, 0x271ae05f, + 0x5d90e07d, 0xf8785c52, 0x19a9c1e3, 0x02c97c1f, 0xb78faa43, 0xfbaeb138, 0x10586a10, 0x7dd1bd14, 0x91638d23, + 0xce1b1a7f, 0x30090d9c, 0xfff154b9, 0xdbd388e6, 0xa7ed52f9, 0x7bd0a9f0, 0x413dc608, 0x23475b4c, 0x3c79bb08, + 0x541906c3, 0xc25bfe53, 0x8cb22920, 0x396c9527, 0xc6e96e6d, 0xb1d78e9b, 0x978fb498, 0x36cd5f22, 0xac668ac5, + 0x54dafbfd, 0x593de62e, 0x2e42e635, 0xa881013f, 0xc094af28, 0x0efb8375, 0x11dab52e, 0x2540ed9b, 0xa68eded8, + 0x7abc5440, 0xde98a988, 0x9002bb36, 0xd84f6337, 0x75555601, 0x34586498, 0xd4dc0ef8, 0x7dd5914f, 0x8d99d5ed, + 0x4610e1a5, 0x270a8dec, 0x20dcbc37, 0x573da163, 0xc3de4fdd, 0xfed241c7, 0x5f702fdd, 0x69ef7655, 0x13a1d8ef, + 0xd3b95e3c, 0x1a5980fe, 0xb5319513, 0x9db66136, 0x5087d029, 0xfc5ee0b9, 0x3885f5f5, 0x434657f5, 0x3a93e272, + 0xd9352c83, 0x210a7dac, 0xc94a6161, 0xbecaaf13, 0xa203a2cb, 0xe4b7956e, 0x33a795ae, 0x3013f92d, 0x7017b2a2, + 0xe9648991, 0xf666727d, 0x87254196, 0x425e6c0d, 0xdd6921f2, 0xbaab70e6, 0x1950b964, 0xef38459c, 0xecc8dda3, + 0x0359da52, 0xbf0ea2f3, 0x26562873, 0x4b0c4eae, 0x3d39b42b, 0x24a24dcf, 0x6826ec80, 0xe6bcad15, 0xc709b4f6, + 0xea460683, 0x36d625ce, 0x8b397fe0, 0xa70fb52e, 0x3ae36977, 0x29420efc, 0x1ffe2ef9, 0x0b13fbc7, 0x8fa3efe6, + 0xff39eb23, 0x382bc4aa, 0xe4e01cac, 0x4d5a36ee, 0x65bf006b, 0xfcd44bca, 0x6a8977a0, 0xae97ebc1, 0xe198ac4a, + 0x6bf55534, 0x24b14646, 0xeccede04, 0x08196645, 0xf2ff38c2, 0x53c7ad99, 0x479f18f5, 0x9b838364, 0xa64bc511, + 0x60774fb5, 0x3b3d8676, 0x0450870f, 0x52c34a1d, 0x3291a5ff, 0x6fc88003, 0xe66014ce, 0x89952b9b, 0x926d28e7, + 0x97d1b86f, 0x27934ecb, 0x2bf47143, 0x6de7089a, 0x5069cdad, 0x0d9f31ed, 0x823b462d, 0x4ac4a013, 0x0b1c265b, + 0x67ff50eb, 0xf7ba8947, 0xedca75f0, 0x2c1562a0, 0x01b333b9, 0x5c229bb2, 0xd9438eb6, 0xebbb298a, 0x83f5346f, + 0x2ca83009, 0xcd6d1575, 0x1d869607, 0xc5844af1, 0xfb1d13bc, 0x0a923b7d, 0x543d836d, 0xce7b47c3, 0x09325077, + 0xddc69fc5, 0xa84fac2e, 0xf1a34dad, 0x037b9aa5, 0x1abb9cb8, 0x9373b949, 0xb990b1c8, 0xa578cf79, 0xe4dcc060, + 0x66c03367, 0xd9be1315, 0x4d555340, 0x11929d56, 0xaef2901c, 0xc57fdc57, 0xb93b1dda, 0x803acd41, 0x0a9d1d5c, + 0xace3a189, 0xb301b223, 0x1bcdef5c, 0xb1e320cc, 0x23f223e8, 0xfd7492d0, 0x8d2de4f2, 0xc9c5a5d7, 0x649a3287, + 0xf215a122, 0xe08f3ffe, 0x65653b50, 0x941fd735, 0xb3d79d1f, 0x7070d2b9, 0x70ce8d7b, 0x67889ef8, 0x9bdc7d28, + 0xcaf4f4f6, 0x05fef23c, 0x48b7dc57, 0x8bd7fa12, 0xa52c4ef4, 0x89a79b8a, 0x3ba605e2, 0xc819c385, 0x9e9f9104, + 0x8d5bcbf2, 0xe4fdf73b, 0x0643276f, 0x790eacaa, 0x13a90024, 0x3f1f28f3, 0xd8bd6ef8, 0xd8f910d2, 0x00c6be15, + 0xe06016f5, 0xaa221402, 0xa029ff77, 0x7817ba1a, 0xf9ed2c16, 0xe0971174, 0x3e7e3b5c, 0x60cdf284, 0xef759e55, + 0x4020458b, 0x182d9540, 0x85a32cab, 0x7be4e579, 0x1ea122b0, 0xd350c4b4, 0x8d44340b, 0xed086e64, 0xd411bff3, + 0xc08503e4, 0x032a0396, 0xd221159c, 0x6f7d68ed, 0x895a623a, 0x0909a5bb, 0xbee06f06, 0xb690e2fc, 0xdbd5cebc, + 0x265deef0, 0x6f2bf00f, 0xacef4f16, 0x09f65401, 0x1aadd1d7, 0x53ae0c18, 0xde0b4424, 0x936b315e, 0x712cb052, + 0xef49abac, 0xa3f4b791, 0xadbf41e5, 0xfaa53a83, 0x15f0595d, 0xd9e2cbb5, 0x6db0d781, 0x08a045f5, 0x34d4343f, + 0xe01bb483, 0x4a069213, 0xf5fbc43e, 0x23769f5e, 0xb305d49f, 0x4afef682, 0x3e557f40, 0xc8f8b987, 0xbe8d4db9, + 0x39704de6, 0x08cacb6d, 0x97c3c23a, 0xfab89da9, 0xe5dffd65, 0x5d11ab26, 0x5985d8b0, 0x8b6f15cd, 0x3731a369, + 0x9e616045, 0xbb07df01, 0x7d63bf86, 0xe457c930, 0x8f322cf0, 0xad0245b8, 0x5ff2b4dd, 0xc61bbdfd, 0x6242de03, + 0xe5b42446, 0xe03362fa, 0x7847fb04, 0x5afb1e6d, 0x0a072803, 0x0d48fc22, 0xa63c500f, 0x6fb7c6c8, 0x539ac025, + 0x55bdd19f, 0xb9b74278, 0x2e29de06, 0x9e71e2c2, 0x3619ca29, 0x8590bc96, 0xa7de08fe, 0x2b6f54cb, 0x34504373, + 0xe5ac41d7, 0x764b6ea5, 0x0418a0dd, 0x886cfe9a, 0xad5e90c5, 0xa87ae68a, 0xfaea2295, 0x70bda1ae, 0x24b9d102, + 0xa05d8bfc, 0x67c23eca, 0x1f9aee2e, 0xb6360e7f, 0x2676e750, 0x62fc7ced, 0xed7e3ed7, 0x61b5e969, 0xa6643ef2, + 0x13f78cec, 0x55d5c9e3, 0x7d0e1837, 0xd73509ce, 0x9ef54531, 0x53c616e0, 0x8debd429, 0x2de3ea22, 0xc498e68e, + 0x7287080e, 0x9aeac5da, 0x6edd1a1e, 0x1d6ec11b, 0x6314a901, 0xaaa84229, 0xb134b896, 0xc9d9f8d9, 0x8ff53af4, + 0xc8bc481b, 0x13ec8911, 0x4236d4eb, 0x975e841d, 0x531f9933, 0xad8706a6, 0x219544fb, 0x1c8dee20, 0x933c2bab, + 0x181b672e, 0xf9720f21, 0xbbe02e5b, 0xf28d5c07, 0x75c60f36, 0x756f764b, 0xb3c19956, 0xa48053d2, 0x14c8d0a9, + 0x3f541528, 0xe08a771e, 0xaa208bd3, 0x48aafb11, 0xb5a34887, 0xed4968af, 0xaf4a2979, 0x6d12f3d2, 0x7bf15781, + 0x3d861eb2, 0xc8d093b5, 0xd4af20f4, 0x8f8bec35, 0x61b78976, 0x6bd7c5e8, 0x1ecf4478, 0x89f76893, 0xdd7fc4f6, + 0x9575c902, 0x353cbd32, 0x122f2f2c, 0x12799078, 0xe115b5b6, 0x300ba238, 0x9641654f, 0x269c8c41, 0x1ba8dfaf, + 0xb58b6115, 0xccf81b09, 0xc484018e, 0x53e7f876, 0x33cb516d, 0xa598cd85, 0x96ff6cef, 0x6a01be51, 0x7e6da28e, + 0xec588f84, 0x50a23131, 0x4705dbea, 0xe4130e37, 0x844f43c1, 0x94a5d756, 0xb28a947b, 0x46b9b710, 0x812b8c04, + 0x08665e95, 0x0bbe6687, 0x3f5db4a7, 0x0d9d6564, 0xb2cd24fe, 0x435c572e, 0x738a8784, 0x734885a8, 0x7ea18bd1, + 0x76536b62, 0xf0b48e79, 0x60e8a486, 0x3a97dac8, 0xc8115663, 0x549d5228, 0x93664af2, 0x4170d3a6, 0x51cc64a3, + 0x47e50f43, 0xfd089994, 0xa7bf3669, 0x27c86218, 0xa2247c34, 0xcb0d4c98, 0xb942ea24, 0x7dafaf03, 0x39c8b291, + 0xa4dae21e, 0xeaff9c6c, 0x9fbe9c1e, 0x5beed636, 0x458721c7, 0x7897d79a, 0x8997ede2, 0x23408af9, 0xa16a6a89, + 0xf0d8d1fc, 0x88e265c8, 0xac9199f1, 0x51a39e4b, 0xe4445e46, 0xec2efde1, 0xd7d72398, 0xed2268b9, 0xbf073032, + 0xb7a5df43, 0x2bfcd0cb, 0x9b0125be, 0x71f9f9c9, 0xcc8182f9, 0xc8df86f3, 0x602761aa, 0x90657a06, 0x6ebd28ae, + 0xafaf29c9, 0xe34694ba, 0x61b2e8c5, 0xce4e7924, 0x657e0afd, 0x763e45fc, 0xc919161d, 0x7901c017, 0x9c411a6e, + 0x4f992658, 0x8dbac46a, 0x6aeec55e, 0x890995f8, 0x6dbf896e, 0xef063d70, 0x6e43a93e, 0x463ccd4b, 0x930b8bf5, + 0xbd0c9edb, 0x1a4f00f2, 0xdad07157, 0x4a53d6f2, 0x4507bdeb, 0x1d66ae55, 0x65cd467d, 0x4457ea6c, 0x7b63a40d, + 0xcc988b9a, 0xc92f1255, 0xb3620de4, 0x20af699c, 0x2d57af04, 0xb8cebe99, 0xca3386c4, 0xcb7064af, 0x250f7d6d, + 0x89daab04, 0x1fd4df63, 0x03cc955a, 0xe7b65b0b, 0x9f308231, 0xfdee35d5, 0x67952ae1, 0xef57ba35, 0x26debae3, + 0x278a27c4, 0xaedad107, 0x029afec4, 0x06be2547, 0x03ccdd16, 0x4ae9edf4, 0x164dc66d, 0x72808858, 0x8266b490, + 0x6371d8da, 0xbbba9710, 0x3a2f8a5e, 0xb7226451, 0xec0e3241, 0x0c013c22, 0xb7635ba2, 0xdb206d85, 0x939de79f, + 0x7b6dd4c8, 0xda7ff402, 0x1a13e32d, 0x304084dc, 0x23b85ad0, 0x2c06c157, 0x1687aca6, 0x865b43ed, 0x7861b813, + 0xb846e388, 0x4ad13c16, 0xb35e3b7e, 0x932870f0, 0xcf4d8779, 0x9bbec694, 0x9544d55b, 0x32d4cfff, 0x151ead2b, + 0x81f3ddf6, 0x4b2f74df, 0xcced2f0a, 0x3ae10a3f, 0x24172442, 0x64b7d114, 0x3ec4d54e, 0xc5e4755f, 0x439b8713, + 0xeb061e09, 0x7a125e49, 0x5df86019, 0x8ff08119, 0x8ebed408, 0x14ff71aa, 0x5424b7b5, 0xa7b754a5, 0x7036b5bd, + 0x75762122, 0x7f42117e, 0x2615c731, 0x4312c4bb, 0xdecee840, 0xedb3e8c9, 0xc3002ec4, 0xac55da69, 0xbd0cf99e, + 0x3e6601cb, 0x47a1a5a2, 0x3576086c, 0x8c625563, 0x06f203b1, 0x314c44c5, 0x9376844d, 0xa30e3fc8, 0xb7607bb6, + 0x2770d2f0, 0x2ed305f8, 0x9c508944, 0x2d28428b, 0xf5791986, 0x0bea0854, 0xe87682a7, 0x8dcdd57b, 0x3c5f7f62, + 0xe2c34ed9, 0x88b943bd, 0x3c526f89, 0xe0a81f06, 0xee7ea8e1, 0x92cfbd53, 0x95106aa8, 0x8d90cd5b, 0x1ba728f1, + 0x9bc67c35, 0x2899f904, 0xa6c6e5e1, 0x226bc9c3, 0x65abe7b1, 0xdce035f6, 0xd2b61238, 0x02e6e2cf, 0x54c12fec, + 0xc161dbf5, 0x859f2828, 0x8c5b9e79, 0xa5df359d, 0xef3f1b55, 0xf8d268d0, 0x7d95c48a, 0xb830f34a, 0xccac243b, + 0x077e7db4, 0x7337f267, 0xffad979b, 0xcf02dbb1, 0x47df9fcd, 0x7463edc0, 0x1709b4a4, 0x133ae09e, 0x18814e26, + 0xda936a79, 0x1c8ebcf2, 0x62817a87, 0xcddbaab2, 0x9bda2a82, 0xbfb6cd6e, 0x9fa115e6, 0x962464f9, 0xeab20517, + 0x9afbcac0, 0x9a3a3d63, 0xfc4353c6, 0x146c20e4, 0x8c077d7d, 0xda9010c3, 0xd0c019d5, 0x90389132, 0xd302a79c, + 0x9cd86849, 0x7c1dcb97, 0xa3c7f285, 0xc08b956d, 0x071dae19, 0x98c219da, 0x8f390315, 0xb646c1fc, 0x868b6c62, + 0x55ac5af1, 0x7cf83310, 0xd20483db, 0x96d87f7b, 0x1fce67a7, 0x1c1a1047, 0xd88e0c66, 0xbd1c41a0, 0x52f19184, + 0xcc52d74c, 0xbaaad1b7, 0x3b6a80b9, 0x8d9e2df3, 0x430b51d0, 0xcc687781, 0xc5ca82e5, 0xa42c7fc6, 0xc2f54339, + 0x28290fc9, 0x8d336d6e, 0xb6d9870c, 0xe855c5e3, 0xb9833e86, 0xf2b92f79, 0xf6471c7a, 0x33d180c4, 0x0905c92e, + 0xb2717f66, 0x3ef96242, 0xe260069e, 0xc8dcaca2, 0x8d93c38a, 0x065984d1, 0x8d4b8cd2, 0x71796a14, 0xa0a27951, + 0xb75c9090, 0xdf711621, 0xe35f81fa, 0xd2b3e4fa, 0x3a0c98e3, 0x0137e6ee, 0x62b63d61, 0xc45ac451, 0x3e477607, + 0xf1aedf18, 0x71141b4b, 0x9a3423c2, 0x0d12214b, 0xf20b8ea7, 0x5c3acde1, 0x912d82b8, 0xcf25a406, 0xfed72e8f, + 0xdf34f620, 0x3bb37f5e, 0xc0d4c85f, 0x22da59d9, 0xed835c03, 0x2215e8ba, 0x4269e829, 0x734232b0, 0xd812550d, + 0xe5fdef06, 0x3adc21a2, 0x03061a83, 0xe0d6b05f, 0x6a50fa60, 0x44aebdca, 0x6a90c92e, 0xea62fbef, 0xa5a19b7e, + 0x53b661d2, 0x2b72b7d5, 0x33217196, 0x76836928, 0x7be63aa0, 0x0f32c773, 0xc868ba8c, 0x02f3820d, 0x8e597e57, + 0x3176f661, 0x9cf5da78, 0xacc37217, 0x1ee68b5c, 0xab67e331, 0xcaa6630b, 0xf0370aac, 0xe91fc5cb, 0x310772de, + 0x631a911c, 0xa8edcaf1, 0xbdfdca5b, 0xe1b183d0, 0x522cdb46, 0xba6f3bca, 0x43d88a3a, 0xae8c81ad, 0x9e747a46, + 0x8d7a6c19, 0x90b234be, 0x62d34c63, 0x46c5166a, 0x39e2f1f8, 0xef97420c, 0xa6ebb2dd, 0x9288a17c, 0xb72f690f, + 0x4e841141, 0xc1445f84, 0x4b9a5daf, 0x2fd649cc, 0x66cf10ec, 0x995d5f95, 0x8c432bca, 0xcb0f1e0f, 0x99f04a1b, + 0x5cf2a0d0, 0x6993d144, 0x661f1e8f, 0x00e76b6a, 0x5dc38c0f, 0x7a17eb6d, 0x1998abeb, 0xd390a265, 0x101fe557, + 0xc371a6f9, 0x1e709856, 0xffabf7fe, 0xa3a9973f, 0x9c2ff899, 0xd8fcbc58, 0x79f04a2c, 0x2d54529f, 0xd5bc8517, + 0x0aa0a55f, 0x81bc1318, 0xf4e78334, 0xdc842b6e, 0x481c2b2d, 0x3cbea61c, 0xc4f8a9e8, 0x7dcabc71, 0x2e0e55d9, + 0xe573c5b4, 0xe1497518, 0x0dc84dcc, 0xe4f638f5, 0x36daa4ec, 0x744f9ff2, 0x50399ac8, 0xe662c96b, 0x0d4277e6, + 0xb0aa3558, 0x946ac393, 0xe17956b9, 0xecae1d0c, 0x391bea36, 0xe4c13366, 0xe348641a, 0x8daca675, 0x8e332d8e, + 0xd4bd9f85, 0xeaa71224, 0x8a3900ff, 0x30c61fe0, 0x4895d297, 0x27affdca, 0xc20c585a, 0x4303af42, 0x927acc3b, + 0x67376595, 0xa084f3be, 0x012907c4, 0x6f9a6af7, 0xc6633020, 0x1e2bc30b, 0xa63a1196, 0x42fd5522, 0xae73ff91, + 0x8755dbef, 0x4d8ac1dd, 0xf597c119, 0x27dfc56a, 0x0fb9fd18, 0xbac68ef1, 0xd6afed34, 0xa1b3cd74, 0x6fb33ab0, + 0x5c72454b, 0x5b8405b7, 0xafbcd4ec, 0x3a2e13b5, 0xa62a1f85, 0x98364004, 0x42924ed2, 0x5d7408f3, 0x772904c1, + 0x6fbcd820, 0xc3e94414, 0x1bdef62e, 0x6b245e4d, 0xfd559621, 0x3bbbdfa5, 0xaa256463, 0x6647ad25, 0x32486223, + 0x2ca43110, 0x3c42f050, 0x47bbcf2c, 0xb57b58cf, 0xed935219, 0x938ce832, 0x6eceb9ed, 0xecab65fc, 0x97089e33, + 0xd969c2d0, 0x50a6e5c6, 0xb1a71397, 0x8dd5c98c, 0xd7e52947, 0xa11fb664, 0x99970615, 0xfd2bee29, 0xf7a61839, + 0x46499e62, 0xa4399d84, 0x0b381a1f, 0xba020db1, 0x3c785925, 0xfaf8c847, 0x541c0e12, 0x805d14e2, 0xe1850c30, + 0xe08f66bd, 0x8ce1bd61, 0x6cad310c, 0x682fcc5c, 0x085cc6f6, 0xaaae460b, 0x2c514000, 0x59d01f17, 0x2ac9a26c, + 0x5a55aa76, 0x4f4733ef, 0x47fef406, 0x41aee863, 0xe75f6460, 0xb5a56e9f, 0x8f4053cb, 0x9ad2c925, 0x98ac87b9, + 0xf0515544, 0x6a9dcc32, 0x7586c933, 0x78211f03, 0xd1a314f4, 0x502a63c1, 0xbec4c465, 0xba90179f, 0xada6268b, + 0x609c949c, 0x6c8a3427, 0xef0e1720, 0x41083b9b, 0x8f3da87a, 0x32154fd2, 0x0f1b1377, 0xce945662, 0x1a5406ef, + 0xcc26381f, 0x174371fe, 0x3d3dd5d6, 0x53ca96e9, 0xc5c50797, 0xd3b387f3, 0xe3d743dc, 0xce7ceb6d, 0x08c27668, + 0x04879d01, 0x460ae430, 0xb8cba93f, 0x3ec26cf3, 0x93c36450, 0x3e72f2c6, 0x71d57414, 0x21997e1b, 0xa08e2d17, + 0xcb4a439e, 0x3c705d2d, 0x3decb54a, 0x0374c52f, 0xbd2843d0, 0x2f176563, 0xce9069c2, 0x38399d82, 0x322adbd6, + 0x69d4b869, 0x29e62ca4, 0x7e7546f2, 0x55d9e41a, 0x9a19b073, 0x9395d32d, 0xaa711c2d, 0xfeee413e, 0xeaa8837f, + 0xa2a5f124, 0x76f65a42, 0x8f408ecf, 0x4ee995a0, 0xd50e0c2b, 0xb5d1912c, 0xa7546e5b, 0x68a35392, 0x590892ce, + 0xe7366e53, 0x8bbe0891, 0x98ef078d, 0x13d0d191, 0x65beb278, 0xf3670a91, 0x2c79024e, 0x136d4540, 0xf8245491, + 0xb948f4ba, 0x30f899e9, 0x5728c3e7, 0x7ef7d995, 0x30f77053, 0x0558febc, 0x242508fe, 0x99cf48fd, 0x66eaa7c7, + 0xedfa9de6, 0x7e0f5c18, 0x5d771121, 0xf5b82db7, 0xa0e429d7, 0x70cd4549, 0x0f3cbef2, 0x69bf8f0d, 0xf47dbf57, + 0x0ca3b928, 0xdc560291, 0xf93603c0, 0x93c6efc3, 0xa160327b, 0x500a3212, 0xca026269, 0x2baf86d7, 0x57373a10, + 0x43347c1a, 0xcc8f56ff, 0xf25f5b6b, 0x8593adae, 0x66dc339d, 0xc774fb14, 0xe5adced6, 0x287bda99, 0x0daaca38, + 0xe68cabe0, 0x379669af, 0x7d7e3878, 0x644a6fd8, 0x30d4c6d3, 0x0330d2a7, 0x60d6389c, 0xabaa502f, 0xa9a9a9e6, + 0x332d8753, 0x9d1eca94, 0xae9193f4, 0xde8cb580, 0x8908e402, 0xe51ffb64, 0x999c63b3, 0xfd617497, 0x05d4adb8, + 0xf9e9031f, 0x0f96d9b1, 0x1efedd55, 0x3539e07d, 0x02ca7918, 0x70bf53af, 0x55c1ea4a, 0xebbd6c23, 0xb0e7c56c, + 0x02407354, 0xd59fae07, 0x9a0e7707, 0x9faee3a4, 0xa9a04740, 0x398df47b, 0x458b95d6, 0xba7d39c7, 0x69b21e3d, + 0x7bd6b6a1, 0xba9ed5c1, 0x3de36cf2, 0x270da498, 0x362c08fc, 0x5e93cb4b, 0x1b874657, 0x54af067d, 0x80cf8b84, + 0x07b3f079, 0x8b78f266, 0x8060fb46, 0xd7138fc1, 0x3dcb1225, 0x74276fe1, 0x35c7ee86, 0x48a58acf, 0x9d4b83ce, + 0x95a15bfd, 0x0d70463d, 0x8daf6d69, 0xaccf4cb0, 0xac6524d4, 0xf01d5696, 0xfef5ad3b, 0x67b3f590, 0x527ca541, + 0xd7154d88, 0xb317fda7, 0x144e5da6, 0xeb9d8888, 0x0b87d22d, 0xa5a25056, 0x550f41e1, 0x13f14b96, 0xdadfd378, + 0xb461c309, 0xce54ef09, 0x628bdf09, 0x1a9fce69, 0x0e31aeb2, 0xa8e6ddd5, 0x9dffea7b, 0x67f2503d, 0xf0998fd3, + 0x53334557, 0x766875ad, 0xf6c524f3, 0x100418c6, 0x80c9fec8, 0xb89acab6, 0x6dd3b788, 0x63e733c5, 0x3873c22f, + 0xa9e3453a, 0x2593fb95, 0x35434968, 0x078da9a4, 0x777320c1, 0xa8f666d8, 0x89cdf324, 0xa0ff45e0, 0x5f2ff9cf, + 0x1669d4e0, 0xaac4d8f8, 0xf9c4427d, 0x925bb311, 0xd125e6db, 0x61077e1b, 0xce1a8041, 0xf42b2418, 0x19819557, + 0x67ca9f2e, 0xdc7efcee, 0x5fafee2b, 0x30e38299, 0x68b11bc4, 0xc87c629a, 0x7cfa493d, 0x2f92c9b8, 0x41874919, + 0x3c5daf5a, 0x321ae89e, 0x35ffd898, 0x5737a9d1, 0xb7e5a503, 0x584a71f3, 0x00f5efe4, 0x7a6856c5, 0x243a8b26, + 0x7e38efe7, 0x8f4cd2c8, 0x5d5c4dc0, 0x49eb0096, 0x717d2e06, 0x0f94759c, 0xc76b5fcb, 0x5e87c011, 0x65b39b41, + 0xbbe46cee, 0x10e6bd8e, 0x36cc3c7c, 0x0edf2409, 0xdfc45c97, 0x7f864545, 0x83531e05, 0x9dcda3d5, 0xfd139fb9, + 0xdba826de, 0xff22c1a3, 0x19037270, 0x3992d5d2, 0x88d0f8bf, 0xdb122b56, 0x0b3dfbfa, 0xc4f12a82, 0x6ab6213d, + 0xdcc4a566, 0x53211da4, 0x8d77d985, 0xd22fab5e, 0x0f795422, 0x3b23a060, 0xebb827f8, 0xb7741643, 0x69b44698, + 0x61ac5fa1, 0x63fc078f, 0xcda4ef6e, 0x6e36ec63, 0x5d978c8c, 0xc5b4aebf, 0xc978b1b0, 0x5b324351, 0x77c96f8e, + 0x890f275e, 0x3bfc5cd8, 0xf34b64df, 0x79e4e6df, 0xc515c0e6, 0xd3f87c5b, 0xadbd2a2c, 0xfca4f093, 0xba468fd8, + 0x793049f2, 0x0b2b3f36, 0x55e5064a, 0x5e6d414e, 0x571258e9, 0x2e8c19ba, 0xeccae93f, 0x70c7da5a, 0x323c636e, + 0xa392dc4c, 0xe1502de0, 0xa659424e, 0x075f3a8c, 0x079bfbab, 0xd139f9ee, 0xc9a3f3a4, 0x3ef73e49, 0x65f8882a, + 0x5c11b2e9, 0xd3c4a12c, 0x7182b037, 0xa9b045db, 0xf3d41e88, 0xfd646014, 0xce405494, 0x14a1c02c, 0x57f9706e, + 0xfe4cdd78, 0xdb1a56df, 0x8ba2dad3, 0xf87a02c3, 0xf1602e0d, 0xa6da06bf, 0x68b73af0, 0x07edfea1, 0x54ac362e, + 0x0b7fa743, 0x201bc12f, 0xa0ef68fe, 0xffd595fb, 0xc39a7b80, 0xe92dc372, 0xca2f3014, 0xce25d36a, 0x3bee1fad, + 0x433b899e, 0xbd03c34c, 0xaa20d8b8, 0xfa3cc39a, 0xaa186323, 0x045e2540, 0x8d51a03c, 0x89f1ebed, 0x926f12dc, + 0x6af80481, 0x2e5d4106, 0xda3cd6ac, 0x35aa0c22, 0xa2a9cd33, 0xbfb9f59d, 0xe5be7a26, 0xa89f9b56, 0xdb7d24c2, + 0x08e72259, 0xb8b587b4, 0x009952f1, 0x0c84cc70, 0x7543c48f, 0x005db3ac, 0x05bc0456, 0x5936869e, 0x6480184c, + 0x4294cffd, 0x6a13da09, 0xd0eac4a4, 0x472019c0, 0x1494d5c2, 0x6dfac15d, 0x77fb0907, 0x33ce55bf, 0x71bacd0d, + 0xcefd40ee, 0x5ae526fa, 0x7e41274c, 0x4bc718a7, 0x081247a9, 0xe6d4c22b, 0xa71410ec, 0x58b5060b, 0xc634d6ec, + 0x3415cdcf, 0x03d92ee6, 0xf8232ba0, 0xd7103111, 0x64521d81, 0xf211fe73, 0x59eddb7f, 0xba6c9a2b, 0x96745125, + 0x77f0e1e8, 0xea9511bd, 0x92cc0877, 0x81b9f02b, 0xc773ce5a, 0xde35c3ca, 0x312875c3, 0x4a644e84, 0x252a2ec9, + 0x8c68f47b, 0x01458907, 0xece5b212, 0x734c0e70, 0x58d790dd, 0xfee2af0c, 0xb83b5f7f, 0x5686bc3b, 0xa7cc4bc7, + 0xbb1d7b0a, 0x958443d6, 0x6640f243, 0x62199cff, 0x85675fba, 0xb7f57540, 0x71e34984, 0x0070d744, 0xc02eddd6, + 0x3801294e, 0x56f82390, 0xcf79ccce, 0xba804b2c, 0x67d04ffa, 0x4d0803ac, 0xc242923b, 0xd5b9ce87, 0x189f92ff, + 0xea7c501e, 0xe9424eac, 0x032aac5a, 0xf7e28b79, 0x2bcf9320, 0x41c117d3, 0xc9c5af5b, 0x611e333c, 0x58577ce9, + 0xed7ffd48, 0x65932ee0, 0xea38375b, 0xb62524cb, 0xa25b2a9e, 0xbcbcb236, 0x2829739f, 0xa726279b, 0x3a2a7cbb, + 0xf1f88c4a, 0x56a64009, 0x7ff05aad, 0xc5abfdbf, 0xf3077f31, 0x897a4f06, 0xe92cb0b6, 0x42e9c786, 0x87e24ce9, + 0xb5543f1d, 0xbd252e8e, 0xb73517e3, 0x27b5dda4, 0xd117e2c8, 0x97a5c47a, 0xf7067bb8, 0x5aa55e69, 0xa7a78e9b, + 0x79be586b, 0x44eb3feb, 0xf3d241d5, 0x1c8d504a, 0x01517b07, 0xfe7bb97d, 0xf52d07de, 0x05bda0c8, 0xbd598dd4, + 0xf03f8006, 0x8c190fc3, 0x008f5d78, 0x2ec70ff0, 0x19654336, 0x61be7850, 0xe2468138, 0xba64722f, 0x8d2b10c8, + 0xe350a236, 0x283bffc5, 0x4f1aed79, 0x5a1beab9, 0x30befbbd, 0x76f3e0a9, 0xd61534d7, 0xcbe36646, 0xb18133de, + 0x98f9c740, 0x430faf4a, 0xfbb70b73, 0x22e48a81, 0x43e6b117, 0x25c243ec, 0x9bbcc190, 0x301a5d67, 0x31d9b732, + 0x01085dd0, 0xca552431, 0xeb4ecf90, 0xef6d2902, 0x63a0950c, 0x6ffdda48, 0x7ae9ba90, 0xa2cd32dd, 0x145cd7cf, + 0xc3890c9a, 0x90bce844, 0xd94e2c3b, 0x533b0551, 0x9884ca03, 0x9e13bff7, 0xc6714b8b, 0x27ed409a, 0x79525871, + 0x42fbdac1, 0xafeaa2c7, 0xe18b6932, 0x4f7d1848, 0x43b37157, 0x5d8af7b2, 0x12540d78, 0x42580dbb, 0x241fd38a, + 0xa7eb52be, 0x0ea95b6d, 0x180a1d48, 0xf1f71cd6, 0xa39eae8e, 0x3da412be, 0x399453f7, 0x7da7769c, 0x4fc32641, + 0xd0b72ece, 0x2a979f87, 0x183878fa, 0x9346bd51, 0x73c836cb, 0xa2817a46, 0xcb380df6, 0x6b37c4c4, 0x2c1e645d, + 0xd800a51f, 0xbabad700, 0xd0c7ef72, 0xba62c9d9, 0xb4def6f9, 0x596bbb6d, 0xeb95046a, 0x330ddf2a, 0x44cff86e, + 0x2b8a527f, 0x34414075, 0xc5770753, 0x04bf64ac, 0x27295346, 0xa493d709, 0x17cc179a, 0x9d25b924, 0x9862b7f3, + 0x503449e3, 0xe9363f9a, 0x44ca2b63, 0xc7578ccf, 0x64a27ac5, 0x84bd8fc5, 0x7d44f1cf, 0xe15e48fd, 0xc5b36a9e, + 0x4875d366, 0xb1633ead, 0x8111fc14, 0x7aacd415, 0x74b9af32, 0x1d011f48, 0x829e131d, 0xcb782946, 0xb71876b6, + 0x0b3659ce, 0xc59140db, 0x5b746547, 0xe4b6b46d, 0x01951b9f, 0xde2c23e4, 0xf6cb80fa, 0x424e7298, 0x66fee481, + 0x20cd804e, 0x86f9b360, 0x14099e53, 0x5081dc5b, 0x70b0bd0d, 0x5c1401c7, 0x6dc8868a, 0xd14e87ec, 0x6127347e, + 0xfe3bc4d8, 0x6bef8539, 0x7c3194c3, 0x223c894f, 0x6714f56a, 0x96ec4886, 0xc5acd0c0, 0xb2c96584, 0x343d7fa6, + 0x6ba99556, 0xcbb48bf2, 0xfc2c3485, 0x80800778, 0xeba7b9d3, 0x3a30afde, 0x465fa90e, 0x6714944a, 0x76baacdf, + 0x02db6595, 0x2fe3547f, 0x3729e399, 0x74ad8d35, 0xe3a4a4e0, 0xf7bd8637, 0x94186302, 0xcef60cd1, 0xd8b7726e, + 0xfad26c8f, 0x3902e352, 0x8ea8871e, 0xc36025cb, 0xf184381e, 0x52dc7ce1, 0xa38666f1, 0x505d087e, 0x603df3ca, + 0x2bdb04e7, 0x8b893469, 0xbe782803, 0x932ebe4b, 0x36522dab, 0xc4aa2ec9, 0x52b8a65d, 0x4c30f589, 0xac7a822b, + 0x40f2088e, 0x1cb45840, 0xe5ca6ceb, 0xf48505eb, 0x945a3b66, 0x3f1d898a, 0xa04c1ed2, 0xc0273a53, 0x30412cb8, + 0x3d859e0f, 0xc226c7b0, 0x4311c779, 0xc33fc307, 0x6aaca797, 0x2df26dfc, 0xb4f11d81, 0xd350dab7, 0x6557c420, + 0x408cf507, 0x5a7a947b, 0x25c74896, 0x7c1df36e, 0x5984d0ee, 0xe536f4f4, 0x13eb0805, 0xa3a615e4, 0xdb411d92, + 0x8c4f5240, 0xb3fb0835, 0x81889744, 0x8b9d9def, 0xbf97acf7, 0xf493f3bd, 0xeb436ad7, 0x52e2d93f, 0x6d5dc7d2, + 0xc1d3136b, 0x3e239a15, 0x82b8c9f2, 0xee96fbd6, 0xc8a28b6a, 0x8ae80e6a, 0x481440ad, 0xa72e2ce6, 0x3c9b9a42, + 0xaa4e92a0, 0x7f5881d7, 0x59921f42, 0x88054d10, 0x2d22f63a, 0x6cf2fc6e, 0x3f289a63, 0x23e3c778, 0xa55309b9, + 0x7e1e80b7, 0xc14f8a9d, 0x6b93b377, 0x42102ef0, 0xe11ab68a, 0x4f5a44bc, 0xc0d303d2, 0x32c34126, 0x82e6f213, + 0x6ea3864a, 0x595c7a93, 0x9e6bed13, 0x87a7edc6, 0xa1a4c120, 0xcbf5e0f6, 0x14c6200d, 0x1bc1adec, 0xe3892e40, + 0x1e33ef6d, 0xe0b68e6f, 0x7d59c3a5, 0x42427f62, 0xa008c84e, 0x7e98291b, 0x4af91dc3, 0x73646ce8, 0x5eba2140, + 0xa9492bae, 0x8c977ffd, 0x45d2675f, 0x557bd37a, 0x2fcef0e9, 0xfb2a6782, 0x46ab030f, 0x609e9951, 0xc94ab1ec, + 0x303dc8d2, 0x02b26212, 0x68668e2c, 0xfadccb3d, 0xe697ec13, 0x587f1601, 0xdf797b6d, 0xf2f4b47e, 0xeb6f86f1, + 0xc8efaf00, 0xcb223019, 0xb2aa9844, 0xf715c5aa, 0x72370ce1, 0xbb739aa5, 0x590dcfd0, 0xd6ceb05f, 0xc35a02aa, + 0x60b742cc, 0xd47bb27d, 0x1dfac348, 0x68260cad, 0x38475e6f, 0xfd848892, 0x7d77d6d9, 0xe47d6217, 0x497765c3, + 0xdd9626ca, 0x98db9723, 0xe0a7bc61, 0x0a85edd3, 0xaf1cf078, 0xf583fdd1, 0x82a2332a, 0xc4cba90a, 0xcd39214c, + 0x725e7acb, 0xeb1f3e26, 0x8c4cf67d, 0x928b6b63, 0xd598001b, 0xc3f0a119, 0x58ad5da6, 0x75f463da, 0x588dfcee, + 0x295d78a2, 0xd7a2a6b5, 0x05f5a03c, 0xf79886a0, 0x76afdd47, 0x00a00138, 0xfe1774f5, 0xbc2fea14, 0x71480902, + 0x4f4fa2cb, 0x37983d13, 0x7f04fb43, 0x6f39745d, 0x23ee578b, 0x07dd1931, 0x64c5589d, 0xfeff2b8f, 0x09216836, + 0x420adb24, 0x0035d31e, 0x960df348, 0xf5f735ca, 0x4b12a919, 0xcd0040b7, 0xbdec818e, 0x2a271163, 0x5625fbb4, + 0xfedf55ca, 0x02110730, 0x58b8ea9b, 0x3bacbdc8, 0x1b16fb3a, 0x1857ce56, 0xf25f967f, 0x091accc4, 0xcd07de20, + 0x1a7ea4de, 0x609269bb, 0x7860286a, 0x6fb0e4e6, 0x7bbb4ebe, 0xdcd94aed, 0x88a9d6e4, 0x492127e8, 0x3117c592, + 0x8d0eba94, 0x46c6b2ae, 0x39510967, 0x9007f1e7, 0xb8a62f85, 0x01f438d6, 0x8090c0d2, 0x2bc62709, 0xbef651be, + 0x286a7d0f, 0xc09430b2, 0x8accaf11, 0xa9c37371, 0xb5949e5f, 0x0fcc3673, 0xc9380994, 0x0b4fbefb, 0x7d94b97f, + 0x7de2a330, 0xbf03ad13, 0xd74013a1, 0xc4f3b335, 0x1d52840d, 0x078f85fe, 0xa31e39ea, 0x5f3e907c, 0x60c8d9a7, + 0x1e277a26, 0x92602c70, 0x0b426392, 0x74d41e5d, 0x3627b418, 0x328d13b3, 0xb8432ed1, 0xe2d0806b, 0xeddaed1e, + 0x46a02c71, 0x29a321c5, 0x3cd7d6d3, 0x85eb09c9, 0x9a551c03, 0xc604c8a3, 0x6d7a8bb9, 0x83cf4754, 0x486339a8, + 0xb93b2323, 0xd98c5613, 0x9acbc531, 0xe66667bf, 0xbf54e54a, 0xdd75d492, 0x961e3775, 0xad9eafea, 0xd75dcd60, + 0xdd3f7db5, 0xf9a3b21b, 0xdec730b6, 0x0851f2d7, 0xd2e4fef7, 0x658504b5, 0xa6893bbf, 0x3bf3a5f5, 0xdf6e28fe, + 0xe16793b8, 0xe0bf5fa7, 0x57c8051c, 0xdc8c315f, 0x80d45439, 0x08a7a04f, 0x0122c8f4, 0xadde44af, 0x9aca2f84, + 0xa96af956, 0xf66aaa98, 0x87c82e86, 0xdc69b199, 0x5cee8cb5, 0xb2edb201, 0xff54fc91, 0xf3368031, 0xc0b39823, + 0x3c2675bd, 0xcf534c28, 0x44cdb9d6, 0xd892ea9b, 0x492724d7, 0x651ea225, 0xf9f72c77, 0x1daa5e90, 0x715408f7, + 0x2a69da36, 0x4a59619b, 0x01dcb4e0, 0x0601e096, 0x3488e54b, 0x75ee353d, 0x82b7ae78, 0xc47d12ee, 0x529d06f8, + 0x92d07f88, 0x7f471b6e, 0x3bbeab7a, 0x39807db2, 0x94824e9d, 0xc9e94219, 0x7a3168a8, 0xab4313bc, 0x9afb8e29, + 0x2e95885e, 0x5d9daf0b, 0x76e5018c, 0x19d96bd7, 0xf751a9af, 0x38f5a1f1, 0x85631108, 0x02b0ae01, 0x244a913a, + 0x4dc6c8d3, 0xaa8eef4f, 0xb44c077f, 0x824a1b79, 0xe35888ac, 0x7d86534d, 0xe52cf404, 0x6fdd7abe, 0xbee2d249, + 0x76299fe3, 0x35e3a244, 0x2383a89f, 0x46c4aff1, 0x09cad952, 0xe72dede0, 0x67e924d1, 0x223eb1be, 0x65d754d4, + 0xb0234f76, 0xe8a649d1, 0x55a8af30, 0xd2426b91, 0x8f97117d, 0x3d0173ef, 0xd84e4dc4, 0xb1b3dd05, 0x6fb4e710, + 0xad02ba62, 0x3ca1b057, 0x7018bbb3, 0xcf40c44d, 0xcbfb4410, 0x3ca5bbb5, 0xeee5651f, 0x0e161659, 0x0090cc4a, + 0xd351072f, 0xddad1cb8, 0xe8601d2e, 0xc05aa289, 0x5922ff92, 0xa6655b9b, 0x5fe4a1cd, 0x4aaeec06, 0x3131b354, + 0x41ae8051, 0x5e3eebda, 0x61bc03fc, 0xd42b009b, 0x6dde50c1, 0x678dd67b, 0x501627a0, 0x84921239, 0xd0d781d4, + 0x3ab98a50, 0xf29392a7, 0x5971cc93, 0xc6b5b8a4, 0xfb185003, 0x5b323513, 0x03196ec7, 0x45623f7d, 0x2b37ab87, + 0x2debf459, 0x2977860b, 0x46cbdb58, 0x5ce8cc8c, 0xaec790c8, 0x736f312e, 0x0a63aecf, 0x9e33da67, 0x3b9ff724, + 0x6f915be4, 0xcb734fce, 0xf1543239, 0xfd18d1b9, 0xf7162e81, 0xb3a90c76, 0xad917a9e, 0x1562501e, 0x5a9f9c5d, + 0x3104f1b7, 0x019cddbb, 0x8c287d17, 0xad617f99, 0xfa88b38e, 0x8b6c609d, 0x56c40754, 0xfa10401e, 0x85a69a6c, + 0x60392124, 0xc02ef463, 0x78c2416c, 0xa73f384c, 0x58dc6105, 0xf26a22d2, 0xb05b6619, 0x15cd1ff9, 0x03096d0e, + 0x3195c0ce, 0x89a0d56a, 0x4c4d269b, 0xdfc82745, 0x918b8495, 0xecc84bbe, 0x905d547c, 0xa2ed6362, 0xc2cee5ed, + 0x30216b6d, 0xd18e5124, 0xf4c6ab8b, 0xa9a327a5, 0xaca23b9e, 0x29fbd7ee, 0x175764da, 0x86efc26c, 0x825de26c, + 0x1c4fe78d, 0x283ce248, 0x4ac10c0c, 0x50bbf3fb, 0x029f6275, 0xe4fa99bf, 0x03e447f9, 0xb58fe8c4, 0xd3ff4b84, + 0x62ceb07a, 0x154821ec, 0x57acf840, 0x820ebc15, 0xdc3634b3, 0x5ded71c6, 0x50b7c917, 0xf45c8e44, 0xfa3d34f6, + 0xac3f72ec, 0x8cddaeba, 0x9fd76792, 0xe8f631cf, 0xec652ab1, 0x4f77b310, 0x8731f203, 0x9b1ca4d4, 0x66bc06b6, + 0xd7bf2a9f, 0xe85e9a7a, 0x3c4b23d9, 0x500c633c, 0xae4c3699, 0xcf603f66, 0x5516d253, 0xce9cb03d, 0x4e4e94ad, + 0x9a6c97c8, 0xf64195a2, 0x4654bfaa, 0xfafcb9b6, 0x19d8950e, 0x5b1e76db, 0xbd65ed3c, 0x9a7c9495, 0x6ae08520, + 0xc5e76655, 0xb8283a1b, 0xa99506f4, 0x9bad69ac, 0x88bd2344, 0xec8462d7, 0x2138c82b, 0xe481c196, 0xfd3f41cf, + 0xe94bae66, 0x5bcb5b13, 0x2898f120, 0x53bfc982, 0x08f986e4, 0xae207148, 0xc22bfc08, 0x8a5020ce, 0x9b58ea3e, + 0x6f72422e, 0xbbe61f89, 0x858581f6, 0xc7b1c6e9, 0x469fb2a8, 0xb4610534, 0x9d58f6fe, 0x26bf4649, 0xf315de28, + 0xcec0f753, 0xeab9d8cb, 0x080fef72, 0x3aeaa30b, 0x66d795c5, 0x4bfdeef1, 0xfc91af88, 0x39416dfd, 0x5bbf1404, + 0x42a017df, 0x68ed4aab, 0xe62ab313, 0x9e9225ef, 0x43f8c595, 0x23287a84, 0xa2eb5953, 0xb8127b33, 0xe77a570a, + 0xa44386f7, 0x29d11f1e, 0x9c790194, 0x3b591abd, 0xca34f643, 0x6d19bba4, 0x375d77f1, 0x0b251032, 0x1b9cad58, + 0x07f75a65, 0xe350bde0, 0x330d51db, 0x9ac02a7a, 0x93850dc4, 0x1c4e38c4, 0x4df16ab4, 0x4d0539b4, 0xbcd073a7, + 0xdedb7462, 0x9a1735f2, 0x3a270ddf, 0x6e84f448, 0xd43ff76b, 0x6c223839, 0xc0146552, 0xc26d2da5, 0x391cd6b5, + 0x366b271f, 0x5c7f49fa, 0x1535d991, 0x7b99ed3f, 0x1268bf4a, 0x8feb08f2, 0xb3147781, 0x73eef8ec, 0x9a3baa11, + 0x471b3d3e, 0x28e15300, 0x2cd29643, 0x7869b033, 0x8ee2e423, 0xeba17e0d, 0x1147e107, 0x10cd31dd, 0xf62b8269, + 0x770ed913, 0x37c9e6bd, 0x71d5a928, 0x534e3ef1, 0xac6f4f8e, 0x12e4986c, 0x0e980054, 0xd82a7b68, 0xa8b65319, + 0x0d789d69, 0x04ee8210, 0x5240cec3, 0x44cdf9eb, 0x3e9be0fc, 0x5b4a29f9, 0x63feb3f8, 0x9cfb2a6d, 0x8511a2af, + 0xa70f0dda, 0x3874ca42, 0x8c1e33ec, 0x5c198862, 0x5d3d2126, 0xca76ab0f, 0x4bcf0901, 0x34634fed, 0x5f2f50d0, + 0x0a62a4c8, 0xfa3f8f9a, 0x6838c4fa, 0x45bcf291, 0x33420971, 0x3b19032f, 0x5a78ab1b, 0x8a2a2d9c, 0xf6e42092, + 0xe932953d, 0x21440e30, 0xc80d9ac9, 0xf4e21c8b, 0x2e304404, 0xb0d8a528, 0x502ec2e0, 0xae02393c, 0x1a7f6fd3, + 0x284f7eae, 0x472e20b4, 0x566fd29b, 0x266e4ffb, 0x094113e4, 0xf89aa4fb, 0x4831b50b, 0xb10d2943, 0xdaaef780, + 0xbc6bddac, 0xb10a66e1, 0x1b4323d0, 0x4709e2e1, 0xb1c94599, 0x7602fe88, 0x6828bd9f, 0x9fe233f5, 0xe500a509, + 0xa3d5179b, 0x6781be15, 0x198b1ac4, 0xbb8d607b, 0x59c3b2c9, 0x640974e5, 0x1bec4641, 0x57bfbe8a, 0xb8ee6496, + 0xa70dc9fd, 0x2d2ef7fe, 0xc8f33ebb, 0x7354232d, 0xb499006a, 0x4753f8cf, 0xbf47144a, 0x15b0f955, 0x08c4d36b, + 0x8f24c18d, 0x86c613b7, 0xee941bc9, 0xe5a4e391, 0x4c14ca0e, 0x5760ddf4, 0xb79cf32b, 0xd3815126, 0xe07e1924, + 0xd7d8b2f7, 0xa607b6b8, 0x8644e7bc, 0xa2df704e, 0x12ef3958, 0xc6fdab8b, 0xeae25855, 0xa19cd609, 0x514b1c09, + 0x51f9fd39, 0xbc71de26, 0xc7be4c41, 0x99a05417, 0xbe634f4a, 0x615edc1b, 0x89f5df75, 0xd933cc15, 0xeda34c06, + 0xf83f96b8, 0x3a28e253, 0xd4d65669, 0x599587c6, 0xdb59fc44, 0xf610a652, 0x5ca01eba, 0x12c68171, 0x504165ce, + 0x1034ca59, 0x69a94ef8, 0xe810b073, 0x3d832886, 0x516e34aa, 0xd729fa0a, 0xe22f63aa, 0xae8bcb90, 0xf4965962, + 0x1750148f, 0x649c4ff7, 0x4417a2ae, 0x574d8c5d, 0xee6368e4, 0x251f2f44, 0x77e9bb1d, 0x4801f2b1, 0x077c927c, + 0x77bda395, 0xb08a6b4c, 0x6c52e0ca, 0x60e769d9, 0xf619855e, 0x7c7652a6, 0xc47a2d6e, 0xf04f973a, 0x9f572aad, + 0xedc49347, 0x8eeea5fa, 0xcfc7b7d5, 0x18d29c3d, 0xfdfdf3c9, 0xd209381c, 0xddfc4ee5, 0x1585dfe1, 0x2859f52c, + 0xd70869fd, 0xd6d6a175, 0xdfe4dec4, 0x0a21b1b5, 0xcfae9b8d, 0x921eb7ad, 0xc9020997, 0x73b44e46, 0xa3bce24a, + 0x3bbbb9b8, 0x4ea918e2, 0x16288893, 0xec331eaa, 0x3ddeea11, 0x6b22a45a, 0x178f2200, 0x543fbbbb, 0x90c223ba, + 0xc167a255, 0x968b52c7, 0x237b45f4, 0x39c9679a, 0x12d07be7, 0xcff443f2, 0x3de08c70, 0xf9eb46bf, 0xecd3696f, + 0xccdd0312, 0x510fd99c, 0x7b075ce5, 0xf2d5972c, 0x13b1a565, 0x647f4407, 0x3dda1c52, 0x0db195b0, 0x2b2f8eff, + 0xfa137377, 0x6caedd85, 0x8fe097e1, 0x10ac8564, 0x72981d2a, 0x08801390, 0x0e3f1ef3, 0x7108f544, 0x6633d426, + 0xc4bd651b, 0x7d06da4d, 0xbc1d9a63, 0x90a067d5, 0x9a7df559, 0x1d0a11b7, 0x1e5da7f3, 0x29fc2c9b, 0xaf70f7dc, + 0xe41b41fd, 0xab9624c3, 0x5d75b435, 0x002621ae, 0x7a9b9919, 0xa33b4861, 0x27d3f2cc, 0x9dd5a907, 0x065640c3, + 0x07086a7c, 0x6ad3c7e8, 0xda61d0fd, 0x997065cc, 0x7ef2b121, 0xeb787574, 0x4d335fd6, 0x32924acd, 0x7a9b34e4, + 0xb141aab8, 0x142c608c, 0x6da52db7, 0x38f48141, 0x3e8c6aa0, 0xb8096c4f, 0x7b861d61, 0xa60fd6b3, 0xc64e4612, + 0x0df0efb5, 0x82a2098c, 0xf58f70cf, 0x090f9316, 0x7adc0c57, 0x89c80d7a, 0x98379e82, 0x07627449, 0xba249bde, + 0xe4071277, 0x335b6e37, 0x10197c05, 0x9806fcf3, 0xd419c50c, 0xa924d154, 0x686a0968, 0x1d4b2dce, 0x5f21ba32, + 0x22a288ce, 0xd46494a9, 0xcacd96f7, 0xd4fb0ef8, 0xb52990ff, 0x4328b4a4, 0xd53e43d5, 0xe17e01ab, 0x22c5f729, + 0xee0e806e, 0xaea91ce4, 0xc9368cf1, 0x3298a441, 0xada607d5, 0x0ce64ea4, 0xb039ee8a, 0xc624916d, 0xce3cb963, + 0x6a21afd7, 0x8bf96410, 0x4618d43b, 0x7def1c9e, 0xcbec3e7e, 0x2fd1e025, 0x87d93d6b, 0x0ff5f5d8, 0x7c21d0d1, + 0xf5ec1657, 0xf4c2190b, 0x2eb3b608, 0x08745f07, 0x6ebf3462, 0xe421705c, 0xe86372f3, 0x49adf1da, 0x5aecc162, + 0x671d0028, 0x1ebbda45, 0xd6d010cc, 0xf5395b97, 0x21df6419, 0x2d4b3d3a, 0x6ad03908, 0x81931219, 0xff65858c, + 0x8e78697d, 0xa9ff5ca6, 0xf2e609c5, 0xccf21be7, 0x83966dfd, 0x8a3cc868, 0x39233e2a, 0xc8902098, 0x69c98dca, + 0xe3ef8e7c, 0xa163b614, 0x14d2a62a, 0xc2c5c281, 0x6cc9b9d8, 0x1062064c, 0x6040cfcc, 0xf92fc8f3, 0xb802811e, + 0xdf2af1db, 0xe8e6f840, 0x1f4ca9cf, 0x6ba56df1, 0xd0ca8462, 0xe37139a6, 0x2fa37f0e, 0x522fb55f, 0xf73269ef, + 0x0a3d8ca8, 0xf16a0a01, 0x1802107c, 0xb4439056, 0x4b0a451d, 0x89ea2c4c, 0xa129618b, 0xceebbdb8, 0x4538462f, + 0x0f0245f3, 0xba48bd00, 0xc35b8aec, 0x87486b26, 0x046413a7, 0x82f0e45f, 0x030c82f6, 0xc8863f3b, 0x5e477d1d, + 0x9c146856, 0x13e2206d, 0x13bf11d4, 0x2be3908f, 0x7a4a1945, 0x1ac7ca96, 0x0c83535e, 0x7390f976, 0x2f2daefb, + 0xf0d7a92d, 0x9fb3f3c2, 0xe1c6de32, 0x834e151b, 0x69ae51f8, 0x4ced1563, 0xec6fb8a2, 0xff68a14c, 0xdc0bf8fb, + 0x01e1bd7b, 0xbc687394, 0x40c2f545, 0xe8af3002, 0xd37a3c35, 0xe7ab8da4, 0xd2096256, 0x838d60da, 0x5e44811f, + 0xe67a6484, 0x272eba23, 0x34568289, 0xe665c623, 0x28e32ebb, 0x380e31e2, 0xec66fa5f, 0x9326ce9d, 0x5d566645, + 0xe60c3eb5, 0x521e1756, 0x5480e735, 0x07b7f520, 0x344470f7, 0xbad01966, 0x435288a1, 0x1b8e3bd3, 0x840bfffc, + 0x06e4073f, 0x5ab23cde, 0xdb0482be, 0xf53e30d1, 0x51d5640e, 0xb5572dcb, 0xad565df8, 0xe60e26c9, 0x03368102, + 0x239bd1df, 0x80cff272, 0x9640352c, 0xa13d9d05, 0xf2e59975, 0x6eb89c1a, 0x081fc914, 0x5fd76af5, 0xb420cc67, + 0xd3941e78, 0x1ad61f76, 0x8fc02d0e, 0xece7be6e, 0x7e13393c, 0xeea6da04, 0xa4a3d76e, 0x3648ad17, 0x8aef288e, + 0xa1ce51e4, 0x64a93a93, 0xfd2f5089, 0x599bac3a, 0x8d3a0170, 0xf8b3cd30, 0x89ab7843, 0x1d3e5db8, 0x06cbb16a, + 0xd28952d2, 0xca284893, 0x8fd1a1e1, 0xecc8aa4d, 0x465de563, 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, + 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, + 0x9e794663, 0xecda4063, 0x4f3c615e, 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, + 0x5bee2390, 0x5bb0ac2d, 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, + 0xcbc03381, 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, 0x5e365ae5, + 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, 0x1da22f3d, 0xbde1988d, + 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, 0xc654b0f4, 0xb3c61edb, 0x34380acf, + 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, + 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, + 0x6ca12b76, 0xca9e521a, 0x3de6ed99, 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, + 0xe3860943, 0xf1f3f4e7, 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, + 0x401dd9b2, 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, 0x9c7c7cab, + 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, 0x68fd2cdb, 0x5b325dc5, + 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, 0xdfeceee9, 0xeff255fc, 0xfc97bd59, + 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, + 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, + 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, + 0x19026be2, 0x106a090e, 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, + 0xfd1119a3, 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, 0x2e43d2db, + 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, 0x24996054, 0xe5fd7518, + 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, 0x19490a6e, 0xbfcc1617, 0x967882fc, + 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, + 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, + 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, + 0x071ae0e6, 0xc3c8d053, 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, + 0x3678e185, 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, 0xb67c5819, + 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, 0xc2222ef2, 0x5a046246, + 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, 0x54a3bc82, 0x5706694c, 0x4664f6db, + 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, + 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, + 0xce8f27be, 0x5a559021, 0x9b1740dd, 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, + 0xe9952168, 0xdc81cac7, 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, + 0xb58b5c72, 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, 0xd99e6ac7, + 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, 0x3635a87c, 0xcee78062, + 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, + 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, + 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, + 0x384ad656, 0x9d824935, 0xec915f03, 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, + 0x4064fbb5, 0x66ad961a, 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, + 0xdbe24543, 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, 0xcadaf946, + 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, 0x628675d3, 0x6b1d569f, + 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, + 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, + 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, + 0x8d3c9334, 0xe5c6c529, 0x20e898db, 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, + 0x0d748033, 0xecc5393a, 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, + 0xf35661c3, 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, 0x5d2efdf7, + 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, 0x69c800e0, 0x5d310e80, + 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, 0xe9811969, 0xc08a7628, 0xe5e44555, + 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, + 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, + 0x80082d96, 0xb5a06d54, 0x1612537d, 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, + 0xf2fac0cc, 0x737aeb61, 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, + 0xaa36609d, 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, 0x0c2f32bc, + 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, 0x6a6777dd, 0xa7029cb3, + 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, 0x59ebc41f, 0x7e55932d, 0xcf78bead, + 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, + 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, + 0xc99944ec, 0x5289e5ff, 0xd64dd767, 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, + 0x4cf9307b, 0x1b6533fa, 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, + 0xe854ce92, 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, 0x408694a5, + 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, 0x24ed6723, 0x0c24fa00, + 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, 0x7db55eaf, 0x0fa8aabb, 0x0e942194, + 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, + 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, + 0x0350d608, 0x54e77f30, 0x866c2575, 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, + 0x3bf7c1bd, 0x5762abb7, 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, + 0xa9a36bdc, 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, 0x5b171723, + 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, 0xe66188ab, 0x4d2b635b, + 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, + 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, + 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, + 0xa31e8408, 0xac80b477, 0x7e7ddefc, 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, + 0x22eb7378, 0x08773858, 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, + 0x65c5fac3, 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, 0x7b9de18a, + 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, 0x804275c8, 0x6ff502be, + 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, 0xf65056f7, 0x18393ab3, 0xbf8c8b96, + 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, + 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, + 0x9685fd96, 0xc354066f, 0x9cdbc452, 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, + 0x328dfdbe, 0x7d168a67, 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, + 0x5fd2e5d7, 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, 0x3fb91263, + 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, 0xca097d3e, 0xa90c478f, + 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, + 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, + 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, + 0x4b823e48, 0x581b2420, 0x4ff2d70c, 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, + 0x476626bc, 0xad5c9d4c, 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, + 0x766880ca, 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, 0x89eac33c, + 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, 0x4eb31945, 0xf2c5d93b, + 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, 0x793fdc45, 0x519a1c15, 0xe31ee96d, + 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, + 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, + 0xd036e501, 0x0cb814a8, 0x06b9ab5d, 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, + 0x9284b162, 0x2cd5b7ab, 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, + 0x6ba484fe, 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, 0xdd4c9f22, + 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, 0x7143f3bb, 0x540b1347, + 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, 0xb2874627, 0x7f0c9a4a, 0xf8106eae, + 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, + 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, + 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, + 0x15aa0461, 0x1bc775e8, 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, + 0x68377d59, 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, 0x90689424, + 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, 0x362b4809, 0xec92588b, + 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, 0x32a14d01, 0xf4f6fec4, 0xada9360c, + 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, + 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, + 0x86428407, 0x45d6c023, 0xc77ebdeb, 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, + 0xf8198b68, 0x881246e7, 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, + 0x9e82681e, 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, 0x2d42e033, + 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, 0x0d1c971e, 0xe7795114, + 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, 0xb31d23cd, 0x8102d36d, 0x51aeed2d, + 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, + 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, + 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, + 0xbd3d8fa0, 0xe798d010, 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, + 0xa956eb79, 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, 0x723065f1, + 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, 0xac794782, 0x002064e9, + 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, 0x344f1195, 0xa7181920, 0xd05fcfd2, + 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, + 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, + 0xb75639f1, 0xadc76771, 0xd3543fd5, 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, + 0x6c95fd6a, 0xc3bb4a03, 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, + 0x045c945f, 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, 0x5acd89f8, + 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, 0x353f926c, 0xe3471231, + 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, 0xd16e5090, 0x9eff66f3, 0xa35ee078, + 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, + 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, + 0xc4062fef, 0x2bd3b757, 0xcbd45594, 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, + 0x2857a67c, 0xce5b2c90, 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, + 0xcd439cd3, 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, 0xbb20e7d2, + 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, 0xee542f36, 0xb0807f6e, + 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, 0x5104928d, 0x047c150a, 0x328cc000, + 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, + 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, + 0xcd61b411, 0xfddd923d, 0x638d0e61, 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, + 0x6bef47aa, 0xf460b130, 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, + 0xdfe4f729, 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, 0x55d094ff, + 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, 0x3161690b, 0x3ffa1fcd, + 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, 0x8a41bcac, 0x38d2f20e, 0x9aac541c, + 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, + 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, + 0x54705c7e, 0xba150347, 0xa80514ec, 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, + 0x7ce59906, 0x577da8f1, 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, + 0xd28382ff, 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, 0xb7bc9a79, + 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, 0xcc0be43f, 0xa606a522, + 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, 0xea4a38b5, 0x76901b4b, 0xe2583ac7, + 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, + 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, + 0x0cfe6db5, 0x5accdc39, 0x3377eaed, 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, + 0xc8bd6a8f, 0x625a6215, 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, + 0xae81db75, 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, 0xfee25664, + 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, 0x8bb3653b, 0x026eedbb, + 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, 0xb5bcee42, 0x6db10b43, 0x9fec55e3, + 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, + 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, + 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, + 0x429e2dc7, 0xc309b30a, 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, + 0x7874b53c, 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, 0xb92b80c7, + 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, 0x3326a1a1, 0x78b01e6e, + 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, + 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, + 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, + 0xc687b587, 0x383f7c40, 0x54830d04, 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, + 0xbf32f0c7, 0x2a796a67, 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, + 0xfd0367d1, 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, 0xc0e35390, + 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, 0xa32b3c81, 0x1d02d66b, + 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, 0x456c5876, 0x4c7a1f7d, 0x8210e535, + 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, + 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, + 0x03826132, 0xf505a1c5, 0x5536b8f5, 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, + 0x743d2b0d, 0xa82aed8d, 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, + 0xafef4d80, 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, 0x6b311848, + 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, 0x129d80fd, 0x18982768, + 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, + 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, + 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, + 0xeaac07b5, 0x0a377949, 0xcea56fc5, 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, + 0x65e46fe0, 0x9a5df9f9, 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, + 0x8358ab8c, 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, 0xdc18fabe, + 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, 0xd48cbb77, 0xcffdb7b0, + 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, 0x8ac94023, 0x11efd6fa, 0x5a6574f0, + 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, + 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, + 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, + 0x743b1a4d, 0xcd7ff202, 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, + 0x18060bb0, 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, 0x4bdc887f, + 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, 0x58f5a07b, 0x3c0266e5, + 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, + 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, + 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, + 0xbbff8af7, 0xaab1617c, 0x596a01d9, 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, + 0xd980aa05, 0x9269bb19, 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, + 0x298eb742, 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, 0x27fd3816, + 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, 0x2ae780c3, 0x7374f385, + 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, + 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, + 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, + 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, + 0xc19f5cac, 0x0bed2aa4, 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, + 0x783cfc66, 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, 0x1628b35c, + 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, 0xb361da26, 0xc0e2aa6b, + 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, 0x10f2492f, 0x231be0f1, 0x2b6fc840, + 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, + 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, + 0x7f6ace2b, 0x21514ebb, 0xc46d4800, 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, + 0xaf2ba637, 0xc4063ea0, 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, + 0xf942657f, 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, 0xea694198, + 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, 0xb453ee10, 0xafe27498, + 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, 0xbb74e075, 0x4408ab02, 0x2eae958a, + 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, + 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, + 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, + 0xfc5ff382, 0xc25ae007, 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, + 0xca5e1ee1, 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, 0x27c57f08, + 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, 0x86952278, 0x2810740c, + 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, 0xabc1d828, 0x05b673a5, 0x93e0c5ce, + 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, + 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, + 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, + 0x9d268a7e, 0x0485322e, 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, + 0x4f7b98f0, 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, 0x9161c085, + 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, 0xd6243501, 0x50f99e78, + 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, 0xe7888474, 0x58967c61, 0x9c2344d8, + 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, + 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, + 0x4a543dd4, 0x72d27f50, 0x794b2c38, 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, + 0xde3dfa58, 0xeac4977f, 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, + 0x4e87a4a4, 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, 0x829272a4, + 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, 0x508ed11e, 0x34f13455, + 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, 0xd435af57, 0x3e86d270, 0x7f04d0f2, + 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, + 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, + 0xfc49bc3d, 0x55757973, 0x84149ef8, 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, + 0xa17f53c4, 0x882c2967, 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, + 0xb340d658, 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, 0x76c9e6a2, + 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, 0xcc17d17e, 0xc52d9ae0, + 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, 0xad9625b4, 0xdbb45f5b, 0xf707fbea, + 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, + 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, + 0x6107a718, 0x83643c4c, 0xf2f96503, 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, + 0x41397ea1, 0x5793b309, 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, + 0x30ed4df8, 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, 0x9e264e70, + 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, 0x3f767c6f, 0xd1c48bab, + 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, 0x50da0980, 0xac96ecf6, 0x008c4910, + 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, + 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, + 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, + 0x49a844d0, 0xbbf5495f, 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, + 0xc41a3c1d, 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, 0xdea90048, + 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, 0xb709b9fe, 0x4549aaea, + 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, + 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, + 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, + 0x17a388b9, 0x78038049, 0xc505ab47, 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, + 0x7e6727d2, 0x9cef5fce, 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, + 0x88bb5013, 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, 0x17261a8e, + 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, 0xf480ab6d, 0x39525194, + 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, 0xdfb74aec, 0x62aae2f0, 0x46b855b3, + 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, + 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, + 0xe260be49, 0x18b01f3b, 0x0a2fc30f, 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, + 0xfb85d9ea, 0x2ddace97, 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, + 0x8c823cb1, 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, 0xf22f9ccd, + 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, 0x769e9c28, 0x65f8905d, + 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, 0x631f0974, 0x3f48dae6, 0x025739cd, + 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, + 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, + 0x5113ea88, 0x72ef2942, 0xd4aa0766, 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, + 0x74798f9c, 0x35e96814, 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, + 0x5ddb2efb, 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, 0xf4ab5191, + 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, 0x88a6c986, 0xdb0e7bbb, + 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, 0x0baad5bf, 0xaed19942, 0x66e4b053, + 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, + 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, + 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, + 0x34268b83, 0xe4bb7d3a, 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, + 0xac836a26, 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, 0xec264fe5, + 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, 0x381f32a7, 0x20a5e8c0, + 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, 0x15470bc2, 0x9ef31ae9, 0xd9e26951, + 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, + 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, + 0x2bf519ed, 0xf57860ea, 0xd69ba992, 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, + 0xccfc8b54, 0x58a93087, 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, + 0x60d94733, 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, 0x8ae04ca7, + 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, 0xca2f0fa1, 0xaac2e3bb, + 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, + 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, + 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, + 0x07796220, 0x0f0f8722, 0xbd6092dd, 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, + 0x17862bac, 0x610b9ce2, 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, + 0xcf3f6b27, 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, 0xff007778, + 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, 0x15a2c929, 0x9263b116, + 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, 0x187b9976, 0xf5ea2689, 0x87e3b151, + 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, + 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, + 0xbaa41197, 0xe5dcc72c, 0xaf16a669, 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, + 0x257e15c8, 0x12fbc35b, 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, + 0x4f1906d3, 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, 0x6d7b3b88, + 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, 0xfc5fbfed, 0x18db2aa6, + 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, 0x4429b1aa, 0x838682ab, 0x5bdfd86b, + 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, + 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, + 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, + 0x5e68e36b, 0x838322dc, 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, + 0xed6bf807, 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, 0xfb7507a4, + 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, 0x532e6654, 0x0c528786, + 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, 0x230b4319, 0xdd780574, 0x58889d79, + 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, + 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, + 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, + 0x73e830ce, 0xb353b81d, 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, + 0xe7929941, 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, 0x45da675f, + 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, 0x52a33502, 0x7d4b918c, + 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, 0x4b0a5e47, 0xce55bc17, 0x09656fd6, + 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, + 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, + 0xfe627e5d, 0x791daf5e, 0x50943665, 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, + 0x3e6a0f21, 0x9dad2288, 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, + 0x72f16cfc, 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, 0x86de5619, + 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, 0x06add0d4, 0xd0c462c6, + 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, 0x494f49bb, 0xcd7f90a5, 0xb6709e40, + 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, + 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, + 0x9bafb81d, 0x62e53468, 0x86ec692b, 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, + 0x8d6632f1, 0x8ba05667, 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, + 0xcfad36f8, 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, 0x526af581, + 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, 0xdea23b22, 0x9f8c78c5, + 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, 0x8d801702, 0x98d2fe2d, 0x3ed6b821, + 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, + 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, + 0xb2ccc077, 0x6162fefd, 0xb3701463, 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, + 0xeabc4ede, 0x82191ff8, 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, + 0x3e457dab, 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, 0x5ecc278f, + 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, 0x0862a010, 0xb3c9a772, + 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, 0xed37dba7, 0x26112057, 0x68c688f2, + 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, + 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, + 0x67c335d0, 0x6981f384, 0x6ca54c87, 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, + 0xf5315cf0, 0x995fb40e, 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, + 0xa571dfbf, 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, 0x1ce39a6b, + 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, 0x33a6d8b3, 0xd9101e64, + 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, 0x13eb0f7c, 0x77b31835, 0x65c53459, + 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, + 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, + 0x0e5f8848, 0xd61ad101, 0xf44c42a4, 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, + 0xd37d5397, 0xeada6952, 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, + 0xfea92813, 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, 0xded23976, + 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, 0x881ccb9e, 0xa1bb6a8d, + 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, 0xe19a859f, 0xfb877d69, 0xc91faf5e, + 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, + 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, + 0xd5e24aec, 0x6731d1b3, 0x48ebc226, 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, + 0x18281991, 0x42588569, 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, + 0x915978fc, 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, 0x4a5faf73, + 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, 0x477d5c34, 0xe2ef3d70, + 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, 0x6db3425d, 0xce451d6f, 0x6f2a53e9, + 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, + 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, + 0x0365098d, 0x013e15ad, 0xc990d5f4, 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, + 0xed216f9a, 0xcb714de5, 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, + 0xf602de55, 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, 0x99029b50, + 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, 0xbd2995e9, 0xd906ec04, + 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, 0xb921c72a, 0x9fc5a234, 0x55d0fbec, + 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, + 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, + 0x84b6ab49, 0x5b3c6835, 0x0015afb6, 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, + 0x89cc97bc, 0x713d3b24, 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, + 0x86363b5f, 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, 0x7368089c, + 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, 0xe516c9a0, 0xeab5aa5d, + 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, 0x614782cd, 0xce169d44, 0x6433de5e, + 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, + 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, + 0xc0ac7573, 0xca381e11, 0xfc5916b6, 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, + 0x332f9714, 0xa3804fc5, 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, + 0x37552b9e, 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, 0xe9b11f94, + 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, 0xcfed5315, 0x27f4a06d, + 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, + 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, + 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, + 0x3c9c2d05, 0x6794edd6, 0xc22cc352, 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, + 0xc045f697, 0xfd090038, 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, + 0x36ae74e4, 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, 0xd85611c1, + 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, 0xb326cc47, 0xe0faa978, + 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, 0xb77eda67, 0xc49052e6, 0xc514a075, + 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, + 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, + 0xf28a6231, 0x9eaa4f64, 0xe9468748, 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, + 0xd8eae4af, 0x46876f0b, 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, + 0xd1daf994, 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, 0x5389bce5, + 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, 0x62a8e0a5, 0x200442ca, + 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, + 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, + 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, + 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, + 0x29bc2f91, 0xac5eaa62, 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, + 0x8bc6cf4f, 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, 0x6bbb33dd, + 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, 0xf708838e, 0x2caf050b, + 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, + 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, + 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, + 0x6746103e, 0xa0eff544, 0x0bba778a, 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, + 0xf1ee2d08, 0x1b100e82, 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, + 0x7ea8c2c3, 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, 0xd1d5c2c0, + 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, 0x5ce3fa8a, 0x2075b595, + 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, 0xdb4a2241, 0x806460ec, 0x183637f9, + 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, + 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, + 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, + 0x724a1e6a, 0x1f49fcfc, 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, + 0xf8481f7d, 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, 0xc548731c, + 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, 0x92d1c238, 0x59503c44, + 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, 0x82172a29, 0x5db3569b, 0x6a0ab6f7, + 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, + 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, + 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, + 0xc2110048, 0xef4c9825, 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, + 0x3d923162, 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, 0xaddd3c63, + 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, 0x20d00302, 0x0718e1f1, + 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, 0xb6747958, 0x6bcb60f5, 0xbce4158b, + 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, + 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, + 0x436ca416, 0x0091a7da, 0xe705853a, 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, + 0x99f5e336, 0x67e6d388, 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, + 0x20fa88af, 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, 0xdeb5cc9a, + 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, 0x112a8ec2, 0x385e89a8, + 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, 0x0c60638a, 0x0c83492d, 0x95d61b20, + 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, + 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, + 0x50f5b110, 0x0c23b119, 0xbc27c7e8, 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, + 0xd1b98d82, 0x632df3e2, 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, + 0xe98733e0, 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, 0x75257595, + 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, 0xf12a2f87, 0x900624fa, + 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, 0xf3be72c7, 0x01ca0052, 0xdf927440, + 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, + 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, + 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, + 0xc226cc77, 0x294e0e4e, 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, + 0xd0489c01, 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, 0x5d6bc3c2, + 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, 0x0c117533, 0x0b70ddeb, + 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, + 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, + 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, + 0x4cd711a6, 0xc46a6a58, 0x2d82b595, 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, + 0x9920ac09, 0x02db13ae, 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, + 0x108cdb88, 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, 0x2944706d, + 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, 0x8ee22fc9, 0x9970baae, + 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, 0x253d5795, 0xa8e3738b, 0x9770975d, + 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, + 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, + 0xacabe801, 0x47952193, 0xd3138e94, 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, + 0x68161660, 0x6365afcf, 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, + 0x96847976, 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, 0xedabeffe, + 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, 0x25d6ba47, 0xec63d289, + 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, 0x671596a0, 0xa08b6a5b, 0x0bca7779, + 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, + 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, + 0x9e283138, 0xb2631843, 0x8c9d46d6, 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, + 0xa4fa2f87, 0x472f5be5, 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, + 0x6fba83bf, 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, 0x7d4f1ea5, + 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, 0x9b0b0ade, 0x6373a3b0, + 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, 0x4c9ca5fd, 0x7f1f3313, 0x30013306, + 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, + 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, + 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, + 0xbed76d66, 0xf5b960da, 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, + 0xad500497, 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, 0xef6e61d8, + 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, 0x4ed7b964, 0xff1f6c98, + 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, + 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, + 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, + 0xbbdb8c62, 0xf6dd386b, 0xe3358787, 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, + 0xce5af4fb, 0x712564e1, 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, + 0x66f6d4a7, 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, 0x499c86a6, + 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, 0xc94b8391, 0x7bd8e512, + 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, 0x449df40e, 0x93f035f8, 0xafd2521a, + 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, + 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, + 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, + 0xf9621d42, 0x77ee21f3, 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, + 0x45317e93, 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, 0x080f5133, + 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, 0xf8ab5684, 0xbd3b8b9a, + 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, 0x428761dc, 0x97459150, 0x709e0a12, + 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, + 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, + 0xac7d020e, 0xa7bf5312, 0x4c6834b7, 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, + 0x03f9e743, 0x3004dfb0, 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, + 0x9ad90bde, 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, 0xa1fc99fe, + 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, 0xfd35ccf2, 0xd2473bb9, + 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, 0x32e8b9f2, 0x103ef0a9, 0x1888642e, + 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, + 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, + 0x8ec2282a, 0x146232d5, 0xf4241f66, 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, + 0x2d03e06e, 0x305c322c, 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, + 0x2c33b686, 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, 0xa9d0de99, + 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, 0xce93f4cd, 0x822382ec, + 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, + 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, + 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, + 0xc83c381c, 0x098d5293, 0xc0738c93, 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, + 0x359fc239, 0x806328f8, 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, + 0x7d0cf9c7, 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, 0x356f9c19, + 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, 0x96e32fe0, 0x142e5994, + 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, 0x702f1422, 0x4008e264, 0xbbf91d05, + 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, + 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, + 0xa6b29bb4, 0x67777742, 0x65b6542c, 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, + 0x86507fb1, 0x26f76111, 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, + 0x658bb0c8, 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, 0x685d4d9a, + 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, 0x30d5acc3, 0x18d236ab, + 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, + 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, + 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, + 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, + 0x37160e0f, 0x9f623018, 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, + 0x99b0115b, 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, 0xc7d5de52, + 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, 0xf080b017, 0x4da4d290, + 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, + 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, + 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, + 0x0d628e03, 0x4a93cdd8, 0x6f643479, 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, + 0x1983f603, 0xd4591b19, 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, + 0x3488b648, 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, 0xde17a435, + 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, 0xc4706c3f, 0xdf14d9ab, + 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, + 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, + 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, + 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, + 0xb8c941ca, 0xe26b9187, 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, + 0x0bbe4840, 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, 0x7fa40f5f, + 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, 0x611a0f89, 0x3a0e5f8a, + 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, 0x01079381, 0xc250fa30, 0xead64afb, + 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, + 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, + 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, + 0xe5b8b32e, 0x9c6261e3, 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, + 0x8f854e38, 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, 0xa8e1a4e5, + 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, 0xff46bbb2, 0xa38e83bd, + 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, 0x6a145a5c, 0x6a41add1, 0xd954c1f0, + 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, + 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, + 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, + 0x5eba32d0, 0x3cc4a69c, 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, + 0xc8013642, 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, 0xe9e313b3, + 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, 0xef679615, 0xc074d215, + 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, + 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, + 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, + 0x208a0b6f, 0x7245f138, 0x352dee4f, 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, + 0x46fc92f6, 0xfcfa9de2, 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, + 0xa44da7f3, 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, 0x35818ebe, + 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, 0x3a03b930, 0x868b0e63, + 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, 0x4d72927a, 0x1b62ae8f, 0xef765353, + 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, + 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, + 0x83b4c653, 0xfd8585e4, 0x23af00e8, 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, + 0x822679ff, 0x695356ac, 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, + 0x9a82734d, 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, 0xccf76bc6, + 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, 0x0e3e6c5f, 0x83452a89, + 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, 0xdadeeb74, 0x7425d656, 0xdcf615c1, + 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, + 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, + 0xc725ecc0, 0x35b295d1, 0x7534f83a, 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, + 0x98a03f22, 0xd70a9952, 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, + 0x7ccba435, 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, 0x771d7fac, + 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, 0x59029f2b, 0xb47ed32a, + 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, + 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, + 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, + 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, + 0xdf2b52bc, 0x0849a8d7, 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, + 0xcca50f90, 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, 0x38d03044, + 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, 0x7ec20957, 0x2e01a0db, + 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, 0x0b90f4dd, 0xa36b8065, 0x31933133, + 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, + 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, + 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, + 0x339b1a9d, 0xcd9c7feb, 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, + 0x85fd0e01, 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, 0x0470618d, + 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, 0x89209a5c, 0x5a60a94e, + 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, 0x22497a31, 0xf3512771, 0xb6adb43b, + 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, + 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, + 0xfc9d64e3, 0x1b454a6d, 0x8b220894, 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, + 0xc66316e8, 0x52366573, 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, + 0x2d196453, 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, 0x6fb6bf96, + 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, 0x3c9257fd, 0x8a3d0140, + 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, + 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, + 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, + 0x615723de, 0xf5fde9a0, 0x96bab4f4, 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, + 0x54f0e2e2, 0x5355cc42, 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, + 0xf6ff9372, 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, 0x0230da46, + 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, 0x26a6191d, 0x83da081c, + 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, + 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, + 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, + 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, + 0x8bf9c71e, 0x1a682b8a, 0x7bbd75b5, 0xb06c035c, 0x9bd1355b, 0x03f15e1b, 0xe1dc6a96, 0x724c12d5, 0x5eeb7abd, + 0x6f1a533d, 0xe4163b97, 0x53963f78, 0xf4bdc4cf, 0x30bc6aa8, 0x55020a94, 0x87424139, 0x7f4e0fc0, 0x0dced4cc, + 0xcc44f761, 0xdc915d5d, 0x5923afae, 0x5fca09df, 0x6da60086, 0x4176cac0, 0x2cd1c0be, 0xeaf4a65a, 0x9a2b0460, + 0xd9adceb3, 0x837911fc, 0x24a064e2, 0xf62aef80, 0x2c72361c, 0xabcea574, 0xc9e8494f, 0x58fdc7fe, 0x19835be7, + 0xe2f50795, 0x22577eee, 0xf37a909d, 0x01085e15, 0x433de341, 0x47e376d9, 0x0bba767a, 0xf77fa338, 0xdaabb9e6, + 0x321bb7de, 0xd9c18914, 0x63c61551, 0x608ac9b2, 0xdc175799, 0xa3b005c1, 0xb30ba812, 0xb8f13ae7, 0x4e6515ee, + 0x63b6e03c, 0x21dc18eb, 0x92116367, 0x912c40eb, 0x67431a9d, 0xa3ac94ae, 0x8778ab34, 0x97d032f9, 0xe363d369, + 0x83361fee, 0xfc13d3ed, 0xa8b81258, 0x3ad31da7, 0xf22b43bc, 0x5e4dc39b, 0xaf3c8d97, 0x4e4f0c56, 0x9ad45750, + 0xce42b7f5, 0xfee1c9dc, 0xda821b40, 0xe112aa6d, 0xc534e246, 0x49278e21, 0xb44895c1, 0xe3d1ab5b, 0x73a79242, + 0x6c9f7498, 0x635ece54, 0x11679e76, 0x2ecfb564, 0x32fac952, 0x9ef53d09, 0xe639b29c, 0x6bc8773e, 0x1bc739cc, + 0x89ba5c0c, 0x4bd2bc26, 0x422ddfd6, 0xfdb0a8e4, 0xcf2f81a5, 0x14841e89, 0xd4f78e53, 0x63013219, 0x359821da, + 0xb02ce75b, 0xac288e79, 0xd6225779, 0xe9c65694, 0x49a11a14, 0x1607727d, 0x5371ef25, 0x6e32e37e, 0x46463aa1, + 0x2f9f3be7, 0x008814a8, 0x4aaeb902, 0xeaf8f5a0, 0x36ff71ae, 0xeda38d7c, 0xc8154fa2, 0xbd72884c, 0xeb83e123, + 0x8c815ce0, 0xe3cec3c1, 0xb7cb6a68, 0x4b2967a5, 0x6f401978, 0xa790036a, 0xd7098ddf, 0xe29bc8fc, 0x990029a6, + 0x03cdb1fe, 0x0dd3e1d0, 0x154d7ad7, 0xf416dee7, 0x5563bc46, 0x724bd24d, 0xc9afafda, 0x15fbdda1, 0xdafbcb38, + 0xd5a26b25, 0x619bed77, 0xba04b927, 0xfd2d6b8a, 0x77894e2e, 0x3a2b2115, 0x4f97c16a, 0x624c5c48, 0x87b8ac99, + 0x52727b94, 0x1e24f7f7, 0x075e8797, 0xf6c0d443, 0x1bbfc65e, 0xaaef1178, 0xc6ee8328, 0x328b718e, 0x6f763df7, + 0xf0198c11, 0xd6cd4bf9, 0x3ee66642, 0x717949cd, 0xd07b2cb7, 0xa023dc26, 0x36fb0e07, 0x833771f3, 0x865405d9, + 0x440f6fbb, 0xaf079d0d, 0x2187a5d8, 0x1c48bf61, 0xd1a3e59f, 0x022d6bda, 0xd6bbf539, 0xf7e1e652, 0xd13cd569, + 0x1953bd8c, 0x2c00848e, 0x15a8bd5e, 0xf1633fe7, 0x56e8f0b5, 0x3b009bee, 0xd18e24a5, 0x06e6be5a, 0x20b080a8, + 0x2b7c3d6b, 0xc9e867d9, 0x013902a6, 0x722d7f90, 0xaa97b1b4, 0x6a72eaa5, 0xa35fb788, 0x02c7801c, 0xf528ad86, + 0xc08e0f90, 0x36013f85, 0xb6507cfb, 0xce50853b, 0xdc81a410, 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, + 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, + 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, + 0xca3c7387, 0x3ebc4e22, 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, + 0x0d609b5c, 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, 0xe964371d, + 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, 0x8549a545, 0x72cd25a6, + 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, 0xfa0f309d, 0x2450505b, 0x7e62d6b6, + 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, + 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, + 0x554de3f7, 0x00236229, 0xb65a8838, 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, + 0x1e0f4174, 0x0e4f84a9, 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, + 0xbecc7016, 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, 0x36f74f81, + 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, 0x49684acc, 0x27ceed4c, + 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, 0xc18462c5, 0x30407eb5, 0x8e18797a, + 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, + 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, + 0x39bc1a46, 0xf4865fdf, 0x22bd8658, 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, + 0xd9382232, 0x947cd63b, 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, + 0x65a5e218, 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, 0x9cff960e, + 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, 0x5da4cf70, 0x861ef098, + 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, 0x2d914387, 0x9ed7f94b, 0xf00b5441, + 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, + 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, + 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, + 0x78603c0a, 0x7c403889, 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, + 0xe1fecec4, 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, 0xee70ca50, + 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, 0x57098afb, 0x744d626d, + 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, 0x5936ff74, 0xc1477a35, 0x3665ecdc, + 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, + 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, + 0x7e1959e1, 0x91787e6c, 0xda51caa5, 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, + 0x8fc78d5d, 0x3ea2142c, 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, + 0xa69d279e, 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, 0xb001c899, + 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, 0x46ebff79, 0xccb7b9b6, + 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, 0xac829629, 0x9ffbf3a3, 0x718c8f7c, + 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, + 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, + 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, + 0xbba13c12, 0xdd02c804, 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, + 0x347c5339, 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, 0x4396ff24, + 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, 0xee7ad3a2, 0xcc436c78, + 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, + 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, + 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, + 0x68c77435, 0x356f1249, 0xec7fe5ec, 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, + 0x8bac2cae, 0x5104a87d, 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, + 0xd5a33292, 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, 0x129c6972, + 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, 0xa54b4c48, 0x667c537f, + 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, 0xe16ab1b9, 0x3d5dd389, 0x5947821b, + 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, + 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, + 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, + 0x8e2665b7, 0xee93572c, 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, + 0x07a80a9b, 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, 0x8a302c05, + 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, 0x9b86cabe, 0x48f7ca80, + 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, 0x79bda240, 0x909fd98e, 0xf49643bc, + 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, + 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, + 0x8821bf49, 0xde5b8005, 0x6e749b41, 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, + 0xc85a975d, 0x00904827, 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, + 0x3ac88c9e, 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, 0xadef941f, + 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, 0x15116dd8, 0xcf51bdc7, + 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, 0xe55e6fbb, 0x43524b5b, 0x12dbc403, + 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, + 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, + 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, + 0xb541d640, 0x84ceb075, 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, + 0xd2f96c90, 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, 0xc9f9d7ed, + 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, 0x3ba18f38, 0xb9d8d6f5, + 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, 0xf818f739, 0x08eaf9e5, 0xc9f08a15, + 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, + 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, + 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, + 0x730d6d4c, 0xb4f2cb42, 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, + 0xfffa9c44, 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, 0xb4ba3765, + 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, 0xf93f4075, 0x9d0ed557, + 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, 0xa5fd92c4, 0x48985b22, 0x9d228641, + 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, + 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, + 0x7e4bb890, 0x1c7739a1, 0xc91fad83, 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, + 0x1eb7fdad, 0xa71313bb, 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, + 0x75bea2bc, 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0xd4fa8fc8, 0x298e3d87, 0x5e472547, 0x494a84d2, 0x647d8034, 0xac4098be, 0x4009c6b2, 0x8f971b24, 0xce15d184, + 0x0fb41b97, 0x193d85a5, 0x8ade3fae, 0x7be5a811, 0x5ad03572, 0x08e7051b, 0x6e2ee2ff, 0xd8345ba1, 0x5443a7e3, + 0x53a2abfe, 0xd4f59d16, 0x9f88e81d, 0xf244115e, 0xf0b2ba6b, 0xb1988699, 0xbb9b5e12, 0x70e87e85, 0x4be3ca07, + 0x2e428baa, 0x1e734902, 0x549f40b9, 0xbab86a07, 0xbb2e300c, 0x8ef685ba, 0xe0895ba2, 0x77767b22, 0x131dfca4, + 0x8da6eb24, 0x1bda5985, 0x6d00ff91, 0x722cb00c, 0xdf308f8d, 0x99829400, 0x4f496a27, 0xdef9fa35, 0xc60f301d, + 0xc8ff73a9, 0xca6e06bc, 0x8983790f, 0xac6bfc5d, 0x60471cac, 0xf0fbfc42, 0x17f53500, 0xf7bfc25d, 0xe327fe31, + 0x05750344, 0xb63ad995, 0xdec9128e, 0xbb672fb5, 0x71c76d58, 0x1ef91ab6, 0x47bfd7e9, 0xddddc7a5, 0xb32b01fb, + 0xe26ebb89, 0xa91d5f4b, 0x9787357d, 0x3b464566, 0x4382b18c, 0xe8cfac56, 0x5cef1081, 0xc01afc3f, 0xa76299d2, + 0x89c35558, 0x6e74f552, 0xfcc20336, 0x7e8bffcd, 0x5d3d2e4f, 0xb6d7afc0, 0x16c6cd4c, 0x1e8f301a, 0x8431800a, + 0x723228d5, 0x4be49662, 0x0e5bae7a, 0xc7c2bdb1, 0x8da96e1e, 0x84f14607, 0x5a50c4d5, 0x50769285, 0x5526702a, + 0x030dfef9, 0x1d3be1a1, 0xcb14ebfe, 0x028a93d4, 0x75b20b6e, 0xe64ca916, 0x4a47f540, 0xf77ba8c4, 0x2d951cef, + 0x7f9a9640, 0x6d4ef4e7, 0x45daa8f0, 0x4c0a46ff, 0x5b98be52, 0xa411dc84, 0x3e48dabb, 0xf6fdc6e2, 0x91cea2dd, + 0x38d25a02, 0xe3b7d79e, 0xa7655d0b, 0x5c8cd063, 0x14de0541, 0xd7228c6f, 0xb23b5084, 0x2a5adac0, 0x5ed77d86, + 0x42c17cbe, 0xbf586e7f, 0x4cc6ec9b, 0x9a39cd6d, 0x7373f3a4, 0x397d645c, 0x0b641d9e, 0x277aacb2, 0x59524c27, + 0xff8f73bd, 0xa10b97b9, 0xd166198a, 0x3b4a25d8, 0xc0ed5d1a, 0xb56746fd, 0x367bb4c9, 0x731a5238, 0x8218ee6a, + 0x612af553, 0xca340189, 0xac01f213, 0x9b3b20be, 0x7ba108cc, 0x3541af79, 0x8fc88951, 0x4a3269c7, 0x0ff70337, + 0xf1a9cedd, 0xac14dc44, 0xa44a8a96, 0x9e5ed0b9, 0x6388cb44, 0xf6e438c5, 0x13c4899f, 0xac37573b, 0xfd9172f4, + 0x18b15ef7, 0x7a495794, 0x451a4b06, 0x367ecddb, 0x4d89a56e, 0xfa69d9c9, 0xe7bcbb4d, 0x6f0dd775, 0x4908d40a, + 0x5ee60a87, 0x42ec1803, 0x7771789e, 0x4d3ffe6d, 0x21ce8f2d, 0x51ba9bd9, 0x331bbde2, 0x69535503, 0xb295a400, + 0x49d93e8b, 0x43920861, 0xa72be34a, 0x0ba77d43, 0x8cf43fa2, 0xd7fb4734, 0xce185cad, 0xa04654fb, 0xadf00e22, + 0x7c033f80, 0x0b5dbbe3, 0xd8f9d875, 0x4af737f8, 0x941b1d2e, 0xc2dc1fbc, 0x2eade5e0, 0x03bb0050, 0x6503f2f9, + 0x6064ef8b, 0x5fb4d7ac, 0x723ea425, 0xdc9182e7, 0xcb44f614, 0xee140310, 0x18b1ad42, 0xce4c46f2, 0xea7b7c10, + 0x0e32b86c, 0xde08244c, 0xa057c218, 0xd5420c94, 0x1cb9737c, 0x637aa739, 0x1d3a19ad, 0x388e26f8, 0x2e517d3f, + 0xc1d0e29e, 0xd70811f5, 0xc844c1f6, 0xcca085c3, 0xccef7e1b, 0x74c8a12d, 0x937aadf6, 0x3a333ce8, 0x615775a3, + 0x3b1d0f0a, 0x9dbf9990, 0x283d9dd2, 0x6612fe9c, 0x4401bf68, 0x5e71b357, 0x473797ea, 0x01364687, 0x426ddb6a, + 0x54b6f856, 0x98ba893d, 0x045a2bf9, 0xf67579cf, 0x8d77774c, 0xbc86e968, 0x0af75a60, 0x87882dc2, 0x8936d638, + 0x6ec83135, 0xa7f8938b, 0x28613b1f, 0x510d8ccf, 0x4b8b3bb7, 0xdd9d705a, 0xd2a87e4a, 0x60959d32, 0x8c7d650b, + 0x812bf858, 0x6d1fde77, 0xce4a4758, 0x26848a2e, 0xa4c520c4, 0x609c8e0e, 0x5b2da861, 0xcfccc726, 0x53b175bc, + 0x27c2356a, 0x43ed152c, 0x8ddbc723, 0x69ce3144, 0x19883c6a, 0x820bb17b, 0x84676b52, 0x1b4724b0, 0x34d61e47, + 0x86058e15, 0x5f3ad5b3, 0xaa9a18b6, 0x7eea420e, 0x6f5e42e5, 0x0e011973, 0xe5351a30, 0x8f50dccb, 0x2bb3a35e, + 0xd5a00dc0, 0x47b7f316, 0xa8ed96ed, 0xfaa0e2f1, 0xfe3f28ce, 0xae7114a4, 0xf7d6dd39, 0x5041de7a, 0xd93a8ab7, + 0x170182ba, 0xe7de179d, 0xbdd60723, 0xcb5e6069, 0x0e2f0d4f, 0xf3cd01f0, 0x7eb3df99, 0x031901f1, 0x3197f476, + 0xe637a162, 0x4e869926, 0xcd987daf, 0x1232e0b3, 0x86f88664, 0x6074a0be, 0xee45c4e8, 0xce5dfdec, 0x37f054e8, + 0xcdda2ff1, 0x2043e65a, 0xbd6f3b6b, 0x6ad1d025, 0x65cad15f, 0xc003e695, 0x0838221c, 0x6c54b2ef, 0x8bb0d7b3, + 0xc3373380, 0xf4217de3, 0xd0da628a, 0xd9641620, 0xe117c48f, 0x2a195bf5, 0xb88fe8ed, 0x257413ae, 0x19692276, + 0x5f81c3f5, 0x1307812f, 0x71599788, 0xbde7ff27, 0x55e3c66f, 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, + 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, + 0x50dd62e5, 0xf2dc2490, 0xb742d94c, 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, + 0x40278377, 0x4f1306d5, 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, + 0x3c727cc6, 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, 0xe3f264d4, + 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, 0xdf701ef3, 0xdbee77ed, + 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, 0x749c5fa2, 0x7bbfac6b, 0x944dc87c, + 0x2937ff1e, 0x87be8ef5, 0xd508b44d, 0x88f9b449, 0x09805e40, 0x747a7907, 0xcd189775, 0xc48c3e04, 0x8e044af2, + 0x69bd5360, 0x4365cd9a, 0x41934cff, 0x49281c0c, 0xac1a3b53, 0x49c1a094, 0xf285cbe6, 0x6939c327, 0xd492ce08, + 0x706fa662, 0x1781b9e9, 0x2ac19678, 0xd518ea0d, 0x7a374775, 0x07be58d3, 0xddccbc1d, 0x4c64df7f, 0x77557313, + 0x78f745bc, 0x7695ad4e, 0x1f199053, 0x44635e86, 0x1401a00d, 0xd443d30e, 0xb250c664, 0x3ec69195, 0xbca388ba, + 0x4be5e051, 0xdbc94cca, 0x58e07f89, 0x56a8747a, 0x8e98e7ac, 0x9267eec3, 0x594c3451, 0x3ebe4422, 0x46a7add4, + 0xdf5512c8, 0x20ae1c95, 0x53f909c4, 0x694f9d54, 0xad7e8f90, 0xdc387260, 0xfa4555ad, 0xa1da14c3, 0x72c56325, + 0x56011855, 0xf136f833, 0x86acff9f, 0xac88ffaf, 0xe9b77aa5, 0xa2501e80, 0x96a89a4f, 0xd5e9bf3b, 0x2efd4983, + 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, 0xc0c97ca0, 0xd6456515, 0x86a49990, + 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, + 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, + 0xab800038, 0x0e5f415b, 0x77d71868, 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, + 0x7999f376, 0x687e76cc, 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, + 0x5d416565, 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, 0xe1bcc050, + 0x58e9dea6, 0x9120a003, 0xaf81ac7b, 0x4bb3258d, 0x81175a7c, 0x9c0dfc15, 0xcc493ff4, 0x310244ca, 0x4744c647, + 0xba4acff8, 0xf7f2c903, 0x4d307533, 0xf3d3d65e, 0xd5f54c63, 0x501d2b16, 0x5fb04a6a, 0x17ef06f3, 0xed6fe1e1, + 0x6b689bd9, 0xcf0b906c, 0xb87f0c05, 0x68e6655f, 0xd2dbbb59, 0x6e7f68dc, 0xcb190ffd, 0xe5ad1843, 0xcf43d3cd, + 0xba9fbb26, 0x7292c37a, 0x2edbfc87, 0xc309ecd3, 0x2296fac7, 0xea11cd74, 0x44a5431a, 0x26eb5e3a, 0xe385b905, + 0x1855bad0, 0x272e3814, 0x03311bc4, 0xbecfc078, 0x43ed13e5, 0xe98431da, 0x1b156977, 0xfd3083ab, 0xc394ebca, + 0xcd25c4b6, 0xc58eee15, 0x0fbbd833, 0xa9e7c061, 0x42a51d37, 0x9919e922, 0x1962d841, 0x9c3e98ee, 0x60e546a4, + 0x688574b0, 0x50a2c84e, 0xd464e24e, 0x96bf6243, 0xf61dc96e, 0x2d9cdd50, 0x6b8117f4, 0x54955da8, 0x8b0998c3, + 0x8baf0db6, 0xf7e6bf89, 0xbecbc735, 0xc39e00de, 0x4e10e4fe, 0x6413f75f, 0x215e8148, 0x2bf72efe, 0x1d7cff6e, + 0xdb08ab8c, 0x6e537eb7, 0x669d59d9, 0x76d10e72, 0xa07aa161, 0x935a11af, 0x7cd7b149, 0xc9e8e540, 0x1db70600, + 0xfaafe3cf, 0x7b4d9f38, 0xb40b6275, 0xb726ceaa, 0x600ddd3d, 0xfa46364f, 0x4606cb16, 0xbaa7fb6a, 0x872a21b8, + 0xa4ce4d82, 0x4268bee0, 0xb0c76c16, 0x28a749db, 0xad5d68e4, 0x8b42ff83, 0x2d9490b8, 0xf8512caf, 0x47b20106, + 0xd5770487, 0x224856cb, 0xcb320805, 0x3a275b81, 0xf8430839, 0x373f3fff, 0x620596c4, 0x01faa3c5, 0x33b031d9, + 0x41e6df6d, 0x588b2df6, 0x321b4649, 0xcd9b3b90, 0x8ada2e5b, 0x67bca81c, 0x17de8242, 0xbec68a95, 0x2d2bea47, + 0xb986a75b, 0xac2456c6, 0x3b9b2ff9, 0x6fd600af, 0x10391225, 0xc5d7b055, 0x5095a20f, 0x09aae2d7, 0x2b12d63e, + 0x51607924, 0x1b10a4a0, 0x21bd699d, 0x962172bf, 0x30849f35, 0xbe9e6c38, 0x5a924cf3, 0x0c2c9279, 0x01ea6a4a, + 0x8201535b, 0x1a43b0af, 0x5a14628e, 0x2a1bd53d, 0xfb2292b1, 0x51cab661, 0xdad91326, 0x70e000e6, 0x64c846df, + 0x46422c08, 0x6ea48374, 0xc7c27c67, 0xc2241288, 0x03833097, 0xfa69432c, 0xa7c40ac5, 0x8ef29f05, 0x8b2599c7, + 0x239748c7, 0x3976582f, 0x7e63b803, 0x2206a2c6, 0x5f7fc961, 0xb8af162d, 0x579e4d70, 0xd53eeeb1, 0x66baa24a, + 0xf2ff8ce9, 0x698b6c1f, 0xca1b9f7d, 0xb06074b0, 0xd19e99d3, 0x545d10cb, 0x039f36e8, 0x9cfb78d6, 0xde0a5980, + 0x0a92866e, 0x3094a27b, 0xdcd07232, 0x50dbafc6, 0x1bb48c02, 0xf3c9be6d, 0xf8854fc1, 0xdc62dbc3, 0x2fd471c3, + 0xd4c5d20d, 0xbde52147, 0x9efdc8cf, 0x68922fc0, 0xb88e333f, 0x01278b3f, 0xb082deaf, 0xcaef9fb6, 0x2e2bd0e0, + 0xc66c96b8, 0x6fda0868, 0xa77e1f7a, 0x1d160a89, 0x85b1487a, 0x61d78902, 0xabee7f67, 0x96549880, 0x0531f910, + 0xf11c1886, 0xc7e97b0d, 0x41e6756a, 0x85f14859, 0xe3f0fc0b, 0x288c0086, 0x0430ba1e, 0x52e7f11c, 0x1c045213, + 0x1f4905be, 0x25f1210e, 0x56052d48, 0xd1dcd8a6, 0x4b6a63c6, 0x789dc29b, 0x9d0ec937, 0x7da8bb3a, 0x6d34fee5, + 0xb0cb417a, 0x79cbae75, 0x771ff408, 0x795efaf0, 0x08bba173, 0x8b087708, 0x31919e61, 0x58fc350b, 0x9724ae94, + 0x63c41461, 0x524803be, 0x1f321398, 0xae180121, 0xfc87c058, 0xba1f7804, 0xb3361eb0, 0xfbd0be38, 0x89a18736, + 0xf3f42412, 0x03b441c3, 0x9abdee97, 0xafd360f9, 0x4f4ea1bf, 0x95c8ba1b, 0x4443be52, 0xe1d07377, 0x0b1a5edd, + 0x6eddede1, 0x8269752c, 0x37e96258, 0x32818b93, 0x4335e781, 0xa7272ced, 0x399f7f83, 0xece7155f, 0x746b491c, + 0x40132011, 0x39cd4600, 0x535de5b8, 0xe585bdc2, 0x3454b808, 0xb8eb525d, 0xf03de612, 0xd3625812, 0x5f9e2734, + 0x538214a7, 0x21f2740d, 0x39cafc80, 0x092f0669, 0xc244c4ff, 0x569c8561, 0x8ce00cec, 0xfad3174c, 0x17a98478, + 0x3fba51e2, 0x7839ccd3, 0xd3cc2942, 0x34459786, 0x9e605d5a, 0x481ee65e, 0x63c01029, 0x97c3b03b, 0x0556943c, + 0x9ca515fa, 0x45ee4c64, 0xfed15ef4, 0x65baabdb, 0x037c4d51, 0x892ea8a2, 0x2de6038c, 0xd8716227, 0x57424e4f, + 0xf1b5ca70, 0x287fcd83, 0x653d548d, 0x2baaa7ed, 0x6af133ba, 0x4bfb12eb, 0x0585c00b, 0x7926e62b, 0x67f71020, + 0x06941d09, 0x3269b9d6, 0x6becf31f, 0x18b598fe, 0x139643a5, 0x9a9160e1, 0xbe2df596, 0x782f8037, 0x9bcce7db, + 0xf3be74bc, 0x4f7f7177, 0xddcacedb, 0xd348bb00, 0x0ef68de3, 0x1ff7d95c, 0x6201a28d, 0x24f67327, 0xa1425633, + 0x48426e5d, 0x3ccfed4a, 0x92baf081, 0x868d6418, 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, + 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, + 0xa4f0c02c, 0x006bdbc5, 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, + 0xd9d19ac8, 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0x40bb52d5, 0x654712b1, 0xd8e940e2, 0x8ff4683c, + 0x2a998600, 0xd4aad8ba, 0xee241d02, 0x94346fe9, 0xc02eb848, 0xc2c91e1a, 0xea843f6c, 0x5bc57c6c, 0xddd8a617, + 0xebf9c3c0, 0x4980bc36, 0x6d334dcf, 0x97a4b3df, 0x2a94b788, 0x83811aca, 0xbbc37422, 0x6292df1d, 0x761131db, + 0xb2d8dbe4, 0x7ff0219d, 0x95d470ee, 0xda8c0e74, 0xcf981bc4, 0x95642758, 0x215c055b, 0x2aaea2f2, 0x28a91766, + 0xe750abab, 0x995e1edf, 0xe39955fc, 0x33af7feb, 0x238315d1, 0x0cc1992b, 0xb2e68405, 0x3813b38f, 0xa380ece2, + 0xee2f0543, 0x60ec9262, 0x3b64b102, 0xeb278114, 0xd72e289b, 0x06c0b20e, 0x7239e577, 0x8613e1c9, 0xf1f5792d, + 0xd4b9c6a3, 0x963ffa00, 0xc8f22d61, 0x4d42a033, 0xdcc72405, 0xb55b7407, 0xd43450b4, 0x4c177200, 0x95b2f572, + 0x79686e33, 0x33eafcc3, 0x16de94f2, 0x3623320c, 0x4f532536, 0x32573813, 0x57c5824b, 0x22645f3c, 0x4662b4dd, + 0x30a54064, 0x6a16359a, 0x22d07103, 0xa94b6786, 0x56603213, 0x41ff6c2f, 0x0e17ba1e, 0xe1a84fff, 0x253f2fa0, + 0x1bca480b, 0x9e21239d, 0x6429e2f7, 0x1bc7bd99, 0x05b70708, 0xa991f02d, 0x1f7febda, 0xf83d3320, 0x7e7fa0a0, + 0xaf06e5f4, 0xe736a11b, 0xe94ddc0b, 0x43ec7b84, 0xe4f8ec31, 0x3589c155, 0x466741f1, 0x98a23ae9, 0x38b8d3d4, + 0x3b70459b, 0xf8c4c021, 0x01b89c7f, 0xd27c63e7, 0xf3c9703c, 0xeed502f6, 0xce92f7b7, 0x47b7ba55, 0x7dede31e, + 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, + 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, + 0x11e80584, 0x3a49181b, 0x01877253, 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, + 0x7b06c1bd, 0x241bb5d3, 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, + 0x6a39fefc, 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, 0xe97476ff, + 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, 0x6bc54667, 0x5da05bd4, + 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, 0xa18cde24, 0xa865edcd, 0x4a0863f2, + 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, + 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, + 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, + 0x9d3fcbd9, 0xa2157e5f, 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, + 0x8430e9fe, 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, 0xcff88a4f, + 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, 0x027ff968, 0x7c059f38, + 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, 0xd8861fcc, 0xa171057c, 0xc650cd2a, + 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, + 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, + 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, + 0xd2063aba, 0x38356c3f, 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, + 0x1c1010ce, 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, 0x52f9037c, + 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, 0x49c20c19, 0x5283a436, + 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, 0xc2223c9d, 0x99554000, 0xcd28bc49, + 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, + 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, + 0x553e3c53, 0x4ff910a9, 0xb16d9d48, 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, + 0x1ead51ac, 0xf531936c, 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, + 0xd81a58c7, 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, 0x5bf25e25, + 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, 0xc806079c, 0xc684f5d5, + 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, 0x4adb2b92, 0xf781402f, 0x870c8ab5, + 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, + 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, + 0x5d7847cb, 0x800a7cd4, 0x2174ea30, 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, + 0x2e1cd1e9, 0xc7308954, 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, + 0xb2b5f06d, 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, 0x8692254d, + 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, 0xdee4891d, 0x83247a45, + 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, 0x3e9a6812, 0xb7981ce1, 0xd48dac33, + 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, + 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, + 0x79d4b7c0, 0x4f0d800c, 0x6615417d, 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, + 0xb2213194, 0x520c5c4b, 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, + 0x4dbd49c2, 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, 0x7fd1b105, + 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, 0xc844714c, 0x83a50459, + 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, 0x795f7841, 0xa403bc22, 0x95959ab1, + 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, + 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, + 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0305.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0305.h new file mode 100644 index 0000000000..40997baad2 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0305.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1110_transceiver_0305.h + * + * \brief Firmware transceiver version 0x0305 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0305 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x4aaf9498, 0x5739308c, 0xffef2eb3, 0x3eaddc1a, 0xbf98868b, 0x84392034, 0x9ad36293, 0xbccffc65, 0x21f82252, + 0x98a4f885, 0x7fad362b, 0xd5a419da, 0x56292e33, 0x367e98cc, 0xaa3ee35b, 0x6f1b43e0, 0x5b85f493, 0xd0adc6e6, + 0xcf4afec8, 0x6ad95178, 0xe6b7606e, 0x396574fc, 0x3df5a7f5, 0x97faa8ce, 0xf7860e87, 0x374328d2, 0x1f39d2d4, + 0xb1a179d1, 0x07aa5dfb, 0x7852e94a, 0xc5f814d5, 0xa985c0d1, 0xc2591bcf, 0xc030bb4f, 0x152400c4, 0x3de682a5, + 0xf1a2e8d3, 0x6b88a5ac, 0xed5f1983, 0xd8b50c45, 0xca70dfe0, 0x7a652097, 0x7214efcd, 0xb9992bab, 0x9a318221, + 0x40d20eef, 0x65a1e480, 0xaef46f23, 0x82d3c3dd, 0xe9dc2b8e, 0x00c63531, 0xd019d7fb, 0x937c6618, 0x69ccc83b, + 0xad081647, 0xff53bb2d, 0xb75c5778, 0x22159f59, 0x28403141, 0x2e7285b0, 0x3aac230c, 0xcd0df139, 0x3044891c, + 0x23fe7ac9, 0x92e58cbe, 0xe67c1b11, 0x7dcaef20, 0x4f9d4339, 0xf647c6d0, 0x7d8b31e0, 0x82a48c77, 0x5ff465f3, + 0xecde4e7c, 0xc368105f, 0x581ad633, 0x04848dc4, 0x1626d640, 0xd1e032b5, 0x1de5c255, 0xef3b054e, 0x0ad3a5ae, + 0xdddd6d6c, 0xace2368b, 0x4f490f05, 0x3f522a9e, 0x6565f95a, 0x46e72678, 0x094bb224, 0x39368e4f, 0x0f10ad97, + 0x31c4735a, 0x3463ddc6, 0xd5a0c7e3, 0xb9843447, 0xeddb8df8, 0xd8d86b6c, 0xcc7fc5f7, 0x494f893f, 0x025e6524, + 0x362af4ad, 0xcf801181, 0x7cdf0e7d, 0x279c6812, 0x715ad5e5, 0x27262295, 0x635be502, 0x5d390672, 0x4b52f6f9, + 0xbe690f55, 0x21f7e84e, 0x76e6814b, 0x6e0907f5, 0x04bf9460, 0x09c7c396, 0x5648bc8e, 0xcbcbae10, 0xbae86bf3, + 0x4aa5c77e, 0xc582e293, 0x2daaff53, 0xc4ee2028, 0x3b7c17f8, 0xc8fe86d1, 0x24231eb2, 0xd2f99596, 0x39055c2a, + 0x5be184b5, 0x66f553a2, 0x3e2ce289, 0x3c5bfca9, 0x0f14e557, 0x7f3a74e4, 0xf0b1e7a1, 0x0c6ee4d0, 0x49020688, + 0x63b41799, 0x4f0f3ab5, 0xba25e1c1, 0x257adc62, 0x449c816a, 0xfe6f9b7f, 0xf168a513, 0xf3405fcc, 0xec747707, + 0x40d315d2, 0xecc1858c, 0x3c5e91dd, 0xcf52a3cb, 0x1ac0136a, 0xa0920394, 0x573f40b9, 0x03b7585e, 0x25471743, + 0xa690677c, 0x437bb10a, 0x49786984, 0x5cd8593c, 0xae3af29d, 0xd24482b5, 0xeea3de82, 0x40c53e94, 0x576b4761, + 0xfb1a09da, 0x53bbe878, 0x7de0913e, 0x9af92111, 0x82ccc412, 0xaf848eba, 0xc8c23e02, 0x754b9a6b, 0x85702abf, + 0xda509a9a, 0x8f295b02, 0xe74f2fdc, 0x4f6779b6, 0x40e83290, 0x87381789, 0xdcab025a, 0x06398b96, 0x60a4d6dc, + 0x5c8ce3af, 0x6df91b1d, 0xd06b64c8, 0x6e8a39e6, 0x4d65717e, 0x2a1e9308, 0x68d73623, 0x487caec4, 0xfd13efea, + 0xc05a8037, 0xdce9832d, 0x531c8ff7, 0x16f76871, 0x9c5d4f83, 0xd9c7aee9, 0x9d307cda, 0x6b7b42ba, 0x6e03c929, + 0xbac87d8d, 0x8bc1abc3, 0xb5442201, 0x50841372, 0xc824a494, 0x854d837c, 0x12678064, 0x080948d8, 0x74adcd86, + 0x70152efa, 0xdd01b681, 0x368a65a0, 0xc4ba385f, 0xef4c5416, 0x62d9f76f, 0x74e1c5a2, 0x4063e83f, 0x9231d0de, + 0xb4751cb3, 0x840b3e0f, 0x327e0c3d, 0xc81461fd, 0x3cc90c1c, 0x3da8aea5, 0xc5e8bf19, 0x438ac0c9, 0xe2f1b3f3, + 0x47e359e1, 0x066e3ab4, 0x37b76bca, 0xfe787cea, 0xe392b9e1, 0xe12c1370, 0x78274547, 0x1a3e849b, 0xebd1ac30, + 0x5a4598f4, 0x6a67c1d2, 0xe56befac, 0x9df7c055, 0xdd3249a2, 0x3f2db1f8, 0x2f3dd9a5, 0x91415095, 0x3cf51223, + 0x7da7e43b, 0xaccc9c22, 0x7fb05e67, 0xc2c68edc, 0x1772fd8e, 0x5d710d77, 0x753ad2fc, 0x9ac74da3, 0x62804648, + 0x888a0f1b, 0xdec7f623, 0xa9f82aaf, 0x8733d083, 0x440434cf, 0x6577ebf2, 0x8cec08f2, 0x3705d669, 0x48a7a1bc, + 0xd894bd7b, 0xc251de4b, 0xe32c4b71, 0x9311894a, 0x00744acc, 0xb7e92a7e, 0xac2bfa3e, 0x24486522, 0x4350de86, + 0x1fe2d81b, 0x67bb6d7b, 0xe1ee6e5a, 0xb6820229, 0x6fbbc4b1, 0xb3e91178, 0xde0394e5, 0x5dd66baf, 0x59572507, + 0xab34bb0e, 0x676df2e8, 0x0bf6578d, 0x36041c54, 0x02647250, 0x1211070a, 0xbd9f1432, 0x40b3fb68, 0x20777d0e, + 0x2ba117e2, 0xfbf15dad, 0xee1b4e74, 0xa96f5a1b, 0xe9f49326, 0x89d6155d, 0xf8228e75, 0x1bcf8467, 0xa1ba5f77, + 0xbaeca53b, 0xef72db61, 0x99a95190, 0xbbe8745d, 0xd6abbffe, 0x97e00c21, 0x6590b6c7, 0x2f3c4b0e, 0xf08b5aa4, + 0xab370275, 0x17179ba5, 0xacecfe68, 0x21a20eba, 0x929725fd, 0xf900c38b, 0x76d78992, 0x005f770b, 0x80ecaef7, + 0x6298a031, 0x243c3b05, 0x4ecefcf0, 0x947cce0b, 0xa1ef32fa, 0xd7385a71, 0x8a7b88c0, 0x54e4fa2a, 0x245fa79f, + 0x36b7be0d, 0x382e274d, 0xfe708552, 0x30176c2c, 0x962dbb42, 0x6bf547b7, 0x76ec9a64, 0xa9c55ced, 0xd2ebce8a, + 0xdcfd3459, 0x4dc61db7, 0x2307854b, 0x24eb5fab, 0xd3d5ee47, 0xbfbb970a, 0xdd715ee7, 0x488f703b, 0xa0073b3a, + 0xa4ebc8fe, 0x0b3facfd, 0x2057865f, 0x37754e8c, 0x7dd4a391, 0x9a635b95, 0xb8613d01, 0x320da102, 0x35f7ea1d, + 0xe93ab7ba, 0xa8f506f3, 0xd9cc64ff, 0x9d2d1629, 0x39b71887, 0xcd1826d9, 0xef3e41fa, 0x8d9e289b, 0x81a01555, + 0xa42f1239, 0xe4a20174, 0x2abbc8f2, 0x01966ef0, 0xd3118ecb, 0xa2852ec5, 0xaf8b3149, 0x3c205022, 0xdcd1e254, + 0x6bd58cc4, 0x4eebb56d, 0x1833eee6, 0xa7a3da56, 0xedc2de47, 0x5a3262d6, 0xc603d90b, 0x025192ed, 0x8c1cfc9d, + 0x9fe6df2d, 0xfb9ee5ba, 0xe41c7b4e, 0x13fb6522, 0x012121d2, 0x3c1b5add, 0xc6e0bb88, 0x1fa12a8c, 0x5e29dbc6, + 0xb593b5ed, 0xcaf1e4a0, 0xd67e55ff, 0xf64e3105, 0xdf524d6a, 0xeaf123fc, 0x0cb68e6f, 0xf7d69b3a, 0xb634d64e, + 0xf97192c9, 0x7e9dcb21, 0x0da089f9, 0xe57bd463, 0xd50d02a5, 0x8a531b1c, 0x08cb6b05, 0x440d0e01, 0xf71d902e, + 0xb087be47, 0xfae78175, 0x34e53a75, 0x8f90ee2a, 0x1a08a5ac, 0xf3d9a8db, 0xb3f21c46, 0xc56f0999, 0xc4e724ad, + 0x27f6d68a, 0x7d0e8e5f, 0x32e6bf30, 0xcbaeb386, 0xf2dc7d40, 0x89c1929f, 0x8232cbb8, 0xb8160cc6, 0xd6f22cec, + 0x394dbaeb, 0xad273421, 0x986d3a7f, 0x93611bef, 0x4b372876, 0xfebb8d1f, 0x9e102e3a, 0x177e1c58, 0x1730a6ec, + 0x8dff4fb0, 0xd7c80be9, 0x6d4ccbe5, 0xe7945b66, 0x5826f5bf, 0xe36af450, 0xb65f3076, 0x62344f60, 0x80ceefa3, + 0x98e0e4be, 0xc3c44d53, 0x9633dc88, 0x35350c88, 0x09fd933a, 0xe5c19c5c, 0xfe79a633, 0xfb56d6a0, 0xb708b922, + 0xd385feeb, 0xd0c8d0da, 0xf492ee4d, 0x3bebab56, 0xa610fa11, 0x3b46aa73, 0xb9a0ad9d, 0xf25a694f, 0xa3c45b60, + 0x7d7c970b, 0x5fccf602, 0x4349e0bf, 0xed153023, 0x512f3bb5, 0xc21ad95a, 0x19c27a58, 0x49f1398a, 0x7989d837, + 0xc9a6226c, 0x8f00e284, 0x8b3bbaf6, 0xf67ba537, 0x29ac3425, 0x156b4495, 0x29096f9a, 0xe389307d, 0x62215f00, + 0xd48d32bf, 0x6c1f8a3d, 0x14b7e2f3, 0xcbeb71d1, 0xbded9997, 0xa409500b, 0xfe28d63f, 0xbc7649f7, 0x105bd562, + 0xe164c769, 0xce945902, 0xf8db2777, 0xa86ead87, 0x710bf19c, 0x5443219d, 0xc98977b4, 0xf8918811, 0xc124b706, + 0x996145a6, 0xbb573b74, 0x29ee1ee8, 0x1b8c1df4, 0xe6585944, 0xc0d91db5, 0xde35499c, 0x0af8af83, 0xb942f688, + 0x49c59249, 0x2232aa30, 0x6b84d667, 0xb7836911, 0xee42b2e2, 0x9e4a2f19, 0x125622b7, 0x147da1f9, 0x3a29f1f5, + 0xc46febc2, 0x10c37558, 0x39137998, 0xe42effa5, 0xa3c97a13, 0x4f48f6d4, 0x844e85e4, 0xfa8b2b0b, 0x63fed4eb, + 0x7a53f565, 0x8bd60496, 0x99a65956, 0x19878ccc, 0x0164ae49, 0x637e5d5e, 0x7f00156c, 0x91ccdc41, 0xe2662257, + 0xd3fec119, 0x77de22fa, 0x0d5e8b05, 0x7d1f7a13, 0xbda1e703, 0xe5c9d5dd, 0x69fc419f, 0x13bfedfc, 0xaae10cb6, + 0xf0744aec, 0x55a277f5, 0x78539c78, 0xecfad5d5, 0xda9e4a46, 0x6d17b9d7, 0x384e5dfc, 0x62a31052, 0x431b598d, + 0x865f90f7, 0xf1c012cb, 0x49fc2ad2, 0xe28c7397, 0x04e3d7d3, 0xc2c95dd6, 0x404b0f35, 0x1aa9d108, 0xee474d3c, + 0xb859030e, 0x58ecdbe6, 0x05cd7792, 0xa031f730, 0x172bec35, 0x0801dbeb, 0xfc42117a, 0x58a37c51, 0xf8f95d6b, + 0x5beff029, 0x2cc44095, 0x0a609a24, 0xe8a19334, 0x8906639b, 0x4a5137f5, 0x220f9cfd, 0x5e6ef29b, 0x1c963ad8, + 0xea682aaa, 0x4acd39d0, 0x5c48f2d5, 0xfc327a25, 0x2f841f49, 0xe126d9d3, 0x72659669, 0x4aa9090c, 0x162fa6ee, + 0x4158f523, 0x5e3ef6de, 0x412abdb6, 0xc732cd99, 0x6472dcc5, 0x9fd1937c, 0x983b76d9, 0xf3d15adb, 0x36c78dee, + 0x6c20e3d9, 0xe344d28f, 0xaf474be1, 0x9772052f, 0x2db0d013, 0x77558dd1, 0x92e9a135, 0xbcb94a98, 0x54e06205, + 0xee06c3db, 0x65e4940b, 0x9ae54773, 0xf9fb4f96, 0x54cfe1b9, 0x52daad88, 0x35272be4, 0xe38d35ca, 0xf9ee6af9, + 0xbd308f6e, 0xf565d2e4, 0xa9b181e2, 0x8f83fad6, 0xa887a08f, 0xc9fcadda, 0xfc7b5d21, 0xcbf6824b, 0x6e872c88, + 0x08b1cd5c, 0xb2cc2645, 0x8a8c4196, 0xbae3d250, 0x5beedea9, 0xebd0ff01, 0x6e24eea4, 0x3eff7429, 0x7e2a2653, + 0x8645bd22, 0xa6d5bda1, 0xc02f75ac, 0xed261dfc, 0x7f76ce9c, 0xcdac6906, 0x0a7eb46d, 0xdf808b77, 0xd770c4ba, + 0xcc5353dd, 0xfd2c08cc, 0x65e88519, 0x7d4898b1, 0xb490c194, 0x07755768, 0x94e3fc6c, 0x6fe2378b, 0x7bff77e9, + 0x6308fad0, 0xee74827e, 0x4b5d9087, 0xa34be938, 0xfd320a37, 0x914be728, 0x7b6854b0, 0x0a968fad, 0xc369e55f, + 0x4d8a248a, 0xdce28b63, 0xe00de9bb, 0x53f87fb0, 0x2f5e6f12, 0x5742f9cf, 0x7b5161ab, 0xf7518929, 0xc880bca6, + 0xdb6c7f23, 0x6cffae31, 0xfb882c74, 0x3fd960f1, 0x505edefc, 0x44588cb6, 0x0c430604, 0xc14c6d39, 0xbadce9c1, + 0xd426e32c, 0xeafc49c4, 0x04c2c9be, 0x1b91b9c3, 0x12507f2b, 0xcdff114d, 0x971bfe72, 0x5489c2ff, 0xe33cfc93, + 0x7f6e96d7, 0x7adc94ec, 0x62e9fe79, 0xcd617801, 0xe9381623, 0x89619707, 0x8ff24973, 0xb9682714, 0x3b608880, + 0x805f1cd5, 0x7bd6d007, 0x62f414a1, 0x74b05392, 0x8371f590, 0x86594819, 0x86933249, 0x186ee98b, 0xec1550ff, + 0x8349184b, 0xd2243d7e, 0xd0485af1, 0x67078d11, 0x6b95275d, 0xa5d737ec, 0xbd4e07c3, 0x0e5e0b26, 0x945e2cae, + 0xdd7daef1, 0x022c7a2f, 0xeb6b8cd6, 0x284bc377, 0x740f7745, 0xe921563b, 0xfd8bc566, 0x067bdcb8, 0x4fd91418, + 0xfad8141f, 0x89f23bb1, 0x67bdb7a6, 0x213ace90, 0xe9d89160, 0xc9f3fae7, 0x6a0e4865, 0x757fef91, 0x445c61eb, + 0x822ad358, 0x355071cd, 0x429247c1, 0x97458f01, 0x84f82e2e, 0x81c7bfa6, 0x5408f355, 0x0aaea394, 0x07b8916b, + 0x4a4ff2b4, 0x56d5fbec, 0xba4bd7cd, 0x2ff77edc, 0x8dbf8bdd, 0xf2c12fde, 0xfaf116c6, 0xa67f1f77, 0x3048c108, + 0x71f76e1b, 0xcf4b6a23, 0x485c8ddc, 0x2d673cb1, 0xb6932b50, 0xca03a8ad, 0xad3584f7, 0x732fbb57, 0x75204ffa, + 0xd885d06a, 0x54ce36cc, 0x891efe37, 0xc8094ce8, 0x9309638e, 0xa67999b3, 0x13f517a0, 0x07cfb9ad, 0x1e12c9e6, + 0x8a3d242c, 0x06f9e62b, 0xf7e89569, 0xdc26ab49, 0x980f87c0, 0x8a662643, 0xb6a80f25, 0x1d877eb8, 0x7f347898, + 0xd5c0dc91, 0xedb56c83, 0x31e18e3a, 0xb3b2cb8a, 0xaa025285, 0x173f5171, 0xdc6aa954, 0x35c8398e, 0xb6031c39, + 0x404bba76, 0xae4919d3, 0xbedaaf1f, 0xc37d9a54, 0x813f478e, 0xd3801619, 0xad29c1df, 0xd68e1143, 0xe8bc0c70, + 0x513ffee4, 0xc3ff5f19, 0x422fbee2, 0xc48dc0f9, 0x1e708d2f, 0xbb44b00b, 0xb052219b, 0x284c8244, 0xcd998424, + 0x44a42cad, 0xfa7faa81, 0x5c04a9e1, 0xe086efa4, 0xd43399ab, 0xfba43078, 0xd2b081df, 0x54ab7f85, 0x6965e29c, + 0x70894a65, 0x57336996, 0x1c1d1ce0, 0x80b3944f, 0x46c6202b, 0xd3e7c90b, 0x6a86d9c9, 0x30462c43, 0xd79a8db3, + 0x10af7239, 0x6979bc16, 0x659bb567, 0x8b0642fe, 0x784e473b, 0xbcf0567a, 0xe1f07337, 0x39323233, 0x0d8efbce, + 0xc763cd44, 0x37940951, 0xfa118a7f, 0xa03046db, 0x1bc13b51, 0xc24a5db5, 0xdfe9312e, 0x00220f16, 0xe5d91e1a, + 0x35438e02, 0x1d1b41f1, 0x2e483a33, 0x2e00698b, 0x4dd10585, 0xf51327a6, 0xd038ad85, 0x86070183, 0xb34f9099, + 0x27a4c553, 0x995e5f38, 0x42b36584, 0x463f6410, 0x168d3273, 0x6e0fe70a, 0xf38aee92, 0x3b1317bb, 0x1c3ee3bb, + 0x2a2bb18b, 0x32272006, 0x14a71470, 0x94244b21, 0xe9ef2ca0, 0xa20a6ecc, 0x13206cf4, 0x54606d9d, 0x02cbbbaa, + 0xaf8cfa18, 0x43e28da5, 0x76c8aaf5, 0xc4738569, 0x7bba0422, 0x17f47430, 0x1de1e536, 0xffe31fe7, 0xeea64e6d, + 0x5e0a7b75, 0xf9a6dfe8, 0x13010634, 0xab657b76, 0xf1253e34, 0xb81b0684, 0x57f76882, 0x774437b0, 0x70b736c6, + 0x8b7270d2, 0xa61f31fe, 0xad763188, 0xad5a5fda, 0x2df7b88b, 0x33d5bcb9, 0x9550f7a9, 0xaaa0229d, 0x28e88acb, + 0x9234e5e5, 0xd01965b8, 0x08027ba1, 0xd32afaa4, 0x53894061, 0x0429b755, 0xf3b82731, 0xfd767200, 0x998a6421, + 0x68d68956, 0xdd3c6cc1, 0x29a04b23, 0xf97adae1, 0xbe021251, 0x8c46b675, 0x058fa5f7, 0xe436ee1f, 0xb8276afb, + 0x74fbbbae, 0x413cd2a8, 0x6ab94340, 0xd83ed371, 0x92c96626, 0x6d9bd129, 0x930c7f6f, 0x6381390f, 0x3a8c725d, + 0x4727b343, 0xcee730bc, 0xe937929b, 0xf53c201c, 0xc163c8b7, 0x9b1d1b5f, 0xcb657bb9, 0xf900e1c3, 0x119fb088, + 0xb58a34c1, 0x4bbe3514, 0x7af97f64, 0x8f146c23, 0x9ed6cef1, 0xd2c8d79a, 0x30261411, 0x1c97bee9, 0xfaa14760, + 0x0ba71c31, 0x347a36e1, 0xb74910ff, 0x7393cd94, 0xd2afc544, 0x6c4db6f3, 0xba51e12d, 0xd3049ca2, 0x1aa92c68, + 0x266f5bfb, 0x9c2af0b4, 0x77b64f9e, 0x4fd7269b, 0x86615c7f, 0xdebdbd83, 0x8cda3c6a, 0x0a7d79aa, 0xd56c5f0a, + 0xd8c4e56e, 0x4d0a17bd, 0xe33938ea, 0x35722e8a, 0x16bb769c, 0x5fbe5d6d, 0x5aafdaaa, 0x159175ff, 0x2722a46e, + 0x4be492ee, 0xc3fcf92a, 0x13e28dff, 0x7298e2be, 0x8a5ace20, 0x9f160c99, 0x6f5015f1, 0x30b1182f, 0xfdd63e1d, + 0x48ae5d54, 0xe42af1e3, 0x8f8911dc, 0xecf5c962, 0xf06b83de, 0xf572d6b7, 0x3c13d9c4, 0x6d8a2300, 0x6bb35a10, + 0x38fb2fed, 0xc746f6f6, 0x22eb20c9, 0xda3109e8, 0xe6145eb1, 0xa3b00199, 0xc8591951, 0xe930d99f, 0x6618205e, + 0xf7534777, 0x1430e198, 0x3cf2a376, 0x75c9a111, 0x16ef3387, 0x4d279576, 0xef0ca591, 0x42dd6f81, 0xcfe32141, + 0x235394c2, 0xd3565c4d, 0x1807c7a4, 0x2c036ca3, 0xd560e9a9, 0xe1cdd7b1, 0x0c8d0e92, 0x85b8c61c, 0x41a65c9b, + 0xd6e2ed83, 0xbd2a1f05, 0xca5cc960, 0xa3324b02, 0x3197ff00, 0x8f38e69c, 0xf74c8773, 0xd677fc90, 0xdea10704, + 0x7ff0423e, 0x86854dd4, 0x49b90a88, 0xf98dfeaf, 0xee001370, 0xa0862e8c, 0xfc6f90c4, 0x93c94796, 0x66fc7336, + 0x2654161b, 0xb5c1af4d, 0xc15ca32e, 0x26ee653e, 0x16d7c542, 0xaaa6b414, 0x09a7883b, 0xd94a6986, 0x8737dcfd, + 0x97d2625a, 0x0cf1c7e0, 0x97fd0d74, 0xd925bd08, 0x67ee020b, 0x19342be5, 0xe8e828ab, 0x1d892597, 0x141d1c5c, + 0x71186b1f, 0xf897d223, 0x70ffe534, 0xf9b811e9, 0x18b2ddd7, 0x3d74efc2, 0x19df61ed, 0x4d488d0b, 0x4c09656a, + 0xc83711c2, 0x724184c1, 0xef3c6620, 0x94d97bf3, 0x0b17b7bb, 0x4d8086c6, 0x6bb11ec0, 0xd52852bd, 0xa296bc26, + 0x04dd02e9, 0x4bb86d8e, 0x153a3802, 0xd2fb89d9, 0x534a50d7, 0xa60df23f, 0x42ba4cbf, 0x4fa430d3, 0x25b3da41, + 0x004231ed, 0xc19b2616, 0x3eeb646b, 0x85b22227, 0xccdf1ab5, 0x6c2309ec, 0x8a0af86d, 0x3843bc2d, 0x6f83db6d, + 0x1565c15f, 0x3c117e2b, 0xcddaae16, 0x5cf3a105, 0xf1c766ea, 0x4f79f406, 0x2a76f1bd, 0x8aed4525, 0x9fa34ff8, + 0x3fd79236, 0xf7027e0e, 0x726288c1, 0xc00e7cc3, 0x9ccbc366, 0xd931bcea, 0x2d61be3a, 0xa3ce50b8, 0x1923d306, + 0x0d68297e, 0xfd74bd94, 0x5345914b, 0x4b3c5a51, 0x7588a424, 0x097fdc50, 0xcd6b046a, 0x53b39441, 0x03083f35, + 0x8fa6ec26, 0x7bc65a0d, 0x9c075034, 0xe0aa8749, 0x44bd00dd, 0x8f286836, 0xe69ab4ff, 0x0681a0a6, 0x2af40639, + 0x760a060d, 0x13c57db8, 0x24c26672, 0xbae060c3, 0xffb7d395, 0xd4b1f494, 0xbb1a905b, 0x65986f5b, 0x1653c1b8, + 0x5605daeb, 0xe0880f7e, 0xe218aba9, 0xd77477ed, 0x186cd7be, 0x002fa538, 0x2ccf01ea, 0x166f8a89, 0xd90ed1a3, + 0xe300ffe6, 0x3dc3ae58, 0x301ba64f, 0x345f7e34, 0x78edf844, 0x17a23ce7, 0xa4781b4d, 0xebbdb357, 0x0b960aa0, + 0xee63c1ab, 0xa4ca057f, 0x9699c00c, 0x441f6545, 0x9fa6baed, 0x635fed86, 0x9cbedc7a, 0x7dc148be, 0xa1f06d81, + 0x6118a206, 0xc6155f8c, 0x4d185e77, 0x63f8913b, 0x15621d0d, 0xef152c58, 0x9e0e93d0, 0x532cd706, 0xc6ce8ac9, + 0x5c4006ba, 0x2c6e1bcb, 0x6a907056, 0xea84dfcd, 0x6f93d855, 0x34dc4d1f, 0x4dc77b62, 0xa7d4a8b4, 0x7e00250b, + 0xfb02fa58, 0x0c2da933, 0x435fb3da, 0x82cf2875, 0xf663d1bf, 0xb44a6e45, 0x46f6918b, 0x6e731117, 0x84169048, + 0x72e621ac, 0x5419191e, 0x2ac745f8, 0x7b9de817, 0x2361581f, 0x0d468227, 0x900d77ed, 0x3e4ed9ae, 0x516f5fa5, + 0x51cfe4a9, 0x443d7e45, 0x6306fdd5, 0xdab4ea97, 0x30cd08a0, 0x9d821f6c, 0x82ba0b51, 0x96fe46c8, 0x83d49a6e, + 0xf2d08541, 0x8b6aad93, 0x474f6695, 0xedc5bb13, 0xa575361c, 0xb4557417, 0x6ecb61a3, 0x84f7e60c, 0x4a0f5163, + 0x8cdcb3d1, 0xad9124c0, 0x890c3d9e, 0xbf169b3c, 0x720e7602, 0xf1fa54e1, 0x6b818d42, 0x44d8e955, 0x86664bc6, + 0x90377c22, 0x22382fbe, 0xccf418c5, 0xf838c0dc, 0x946b1d66, 0xc11be40a, 0x7a151938, 0xdc4336c2, 0x28c43eb2, + 0xc1f12298, 0x98cd9669, 0x166880cb, 0x84cffc47, 0x37c84d89, 0x1889a4cd, 0xdf2ce016, 0xded06116, 0xfae867c5, + 0x8d23d06b, 0x827dacf8, 0xfd11d25f, 0x68485ddb, 0xed506883, 0x43c5e555, 0x0330a16f, 0x3f7576af, 0x5f70c716, + 0xf298b8ce, 0x9e1df62a, 0x46fa9d88, 0xb06e68d0, 0xc3803412, 0xe8ba5d5d, 0x615d8c71, 0x1b0d6c3c, 0xb638706b, + 0x187d6983, 0x0e33f64f, 0xd9dd7778, 0x12410a8a, 0xcef7eda5, 0xfe74e21e, 0x60b70fc5, 0x8ed94fa2, 0x6cfde259, + 0x8058b411, 0x1ca93807, 0x19625c5a, 0x34215cec, 0x165baddc, 0x0ab44f83, 0xa6363e74, 0x3f7a766a, 0xdd702a61, + 0x3d0ca687, 0xd0909c3e, 0xdc7f7712, 0x3d9001ea, 0xc5d19495, 0x8017b1f6, 0x65da0eed, 0x0d030d48, 0x998c10e6, + 0x06f1c97d, 0x35204b05, 0x1c0da754, 0x777b48fe, 0x01521640, 0x203bfb59, 0x25e83cfa, 0xa3d40b91, 0xf396bd60, + 0x093880c7, 0xd5a77950, 0xe06ddcac, 0x87936f25, 0x12c7d991, 0x16103a0f, 0x4a1ee98c, 0xf70e1c84, 0x2f3f894e, + 0x176c0300, 0x34c08cc6, 0x89eff014, 0xb7d5666e, 0xf7636a27, 0x128ece3c, 0x71e7ddb6, 0x1070d4aa, 0x2dab9a05, + 0x3cdc279b, 0xe88781cc, 0x2771abc8, 0xf01d6e74, 0xe8cc296b, 0xeaafe927, 0xa3b3e542, 0x872acfc7, 0x4033a228, + 0xa922a98c, 0x82b18f3b, 0x6d5efbb5, 0x31d13a83, 0x6c4a1b1e, 0x7d5df44f, 0x539dfd5d, 0xda1e186b, 0x60f6948d, + 0xb4c2bb13, 0xa903a2c4, 0x76a5595b, 0xb85fc368, 0x87e3c57c, 0xeec8ee07, 0x39f42e4b, 0xdc13d659, 0x03ac1daa, + 0x123bab9d, 0x7789dec0, 0x5dba0ba3, 0xcee72d9f, 0xea4aa38f, 0x315633a7, 0xff276fb0, 0x0468ef67, 0x7fb82124, + 0xeb586ed5, 0xcdadda70, 0xb37e12d8, 0xe4411b87, 0xc740e4f5, 0x41ca5e11, 0x8e54997b, 0x023d8b2c, 0xda4cfb4e, + 0xee115485, 0xf9a61a29, 0x98aefaa4, 0x2523432a, 0xcfa165ae, 0xc2b7231b, 0x39d61511, 0xc75af56b, 0xdbb6325e, + 0xbd6a271a, 0x07b87e7d, 0x0fbebed0, 0x02c4975f, 0xdcd73a8a, 0x83ecd437, 0xe35fb8da, 0x9fdf4866, 0xb0ae7b52, + 0xa0e5399c, 0x08332d93, 0x6b9f613f, 0xd2ba9a5f, 0xd0ba4882, 0x8b9f09f6, 0x1b4d4734, 0xc9c12db2, 0x309ae57a, + 0x60324915, 0x556d151d, 0x1cca0eed, 0xc4522900, 0x0b9591c0, 0x4b81c865, 0x177b4653, 0x78c8da77, 0x5bd35a7c, + 0x1e85ddb5, 0x2201dfd3, 0xed3b2666, 0xc8f4277d, 0x3a46ec22, 0x6c7c908d, 0x58be3141, 0xd07f93a4, 0x412d0d3e, + 0xc0fa6a62, 0x77c91d21, 0x1c3ba9b8, 0x02500e93, 0xdbad0961, 0xb82c7c1d, 0x384857b4, 0xa3550344, 0x20816cae, + 0x8b82b9db, 0xdbd4af8e, 0x46e25578, 0x34dfa42e, 0x7cd4139e, 0x122a5a6b, 0x64572196, 0x5358318c, 0x1ad5da33, + 0xfc45fbb7, 0x88bdce58, 0xeb0e061d, 0x7b54b523, 0x5703aae2, 0x308de378, 0x8d7c9f44, 0xca59625b, 0x1f8d32c0, + 0x91a0e3c4, 0x9505fb02, 0x73fcdfbc, 0x01e2513b, 0x2321bcb9, 0x26a3eba5, 0x62b7196d, 0xd5eaeb48, 0x3d63ab18, + 0x3cd8afba, 0xd1aba121, 0xc99acdfd, 0xd866b0c7, 0x1d7ae062, 0x4d205f9f, 0xed68590a, 0xaae5d298, 0x58b40ccd, + 0x03120e91, 0xec31996a, 0x19fa4e25, 0x48f2a8d4, 0xdd1a3003, 0x7abd9d9a, 0x5e2036b5, 0x897d2f93, 0xe5bf16c6, + 0x54b99d56, 0x8978b8d6, 0x3652f4cd, 0x33547462, 0x6824a920, 0x6ed072f5, 0x6402eab3, 0xab3d9e6f, 0x8f801882, + 0x02dcfbff, 0xde7ac9c2, 0x99481157, 0x102abf29, 0xc893231a, 0x534da927, 0x22009b8e, 0xb35a3677, 0xa53ab45b, + 0x2359e00b, 0x9c5b59e8, 0x308ada9f, 0x7786f065, 0x9c94cca1, 0x41fb6e86, 0x7e7544d2, 0x8ce2205d, 0x154b4834, + 0x3e32d867, 0xabbe29a1, 0xb3b3e0ff, 0x45eb03dc, 0xd2cacac4, 0xf0a02058, 0x2b018327, 0x7ef5a280, 0x89415bea, + 0xefb095d9, 0x8ce743fd, 0x2b56a4dd, 0xfa8de3ad, 0x3902203d, 0xecb62c39, 0xd6e889aa, 0x4e674d48, 0x9878cf6a, + 0xba7104c2, 0xab47aa7e, 0x9ac820c2, 0x562c1234, 0x625d79ee, 0x097ddcaf, 0xe97457cd, 0x8df95ad2, 0x54972b5d, + 0x26ed91cf, 0x8ed7127d, 0x3092ea8d, 0x8eedf74c, 0x2204c7bc, 0x03874b72, 0x243fb626, 0xc83ed61a, 0x7136982b, + 0x92da1cb8, 0x81640eca, 0x0d29d696, 0xb15d5840, 0xb60e520d, 0xc49a8fc1, 0x1f9bb585, 0x8eab1a68, 0xbcc7db29, + 0x7abc6fa4, 0xb4a73b41, 0x640b62c3, 0x6668550f, 0x3f52a71b, 0x53e003c7, 0x7aef45f5, 0x86fb6a92, 0xb7e0ea14, + 0x26415676, 0x70441109, 0x2721d6e1, 0x82b254e2, 0x920ed19e, 0x9977990c, 0xee90b0b8, 0x197ff3e3, 0x22a7b3e7, + 0xb8d0bdfb, 0xf7e285b9, 0xf6af7a14, 0x4c712f18, 0x89aacf9d, 0xa23342ad, 0x9b1ab1ce, 0x90e92e34, 0xf7f05ef9, + 0xea90ab0b, 0xbf52f2a4, 0x97acce0b, 0xe63903c7, 0x89b2e395, 0x2285f0e6, 0x78017953, 0xbca3c4af, 0x462fcb5d, + 0x6a396976, 0xc6453237, 0x0a83790b, 0x2bf76556, 0x67ba3f60, 0xbe72aa58, 0xe88d1f88, 0x2595c18e, 0xd2afc143, + 0x3f519ef1, 0xd2e21dcc, 0x246c0d65, 0xf57135bb, 0x5cf16ecd, 0xf00a8782, 0xd2d7866f, 0xab8c17c8, 0x8a9b7100, + 0xaa30df48, 0x4189b2b8, 0x64fcc91c, 0x7ba641d8, 0x8915a82b, 0x0c1420f3, 0x30f02f37, 0x5efc7e2f, 0xb2b02de2, + 0xddc29384, 0x17113680, 0x59518665, 0xec21e5b0, 0x562f40da, 0x32fce5c3, 0x0db72445, 0xbb367363, 0x70de646c, + 0x01535396, 0x43fe0fe9, 0xff52a34b, 0x2e6d96fe, 0x4a11e4d2, 0x51bcbd51, 0x72588165, 0xd8214885, 0x01e8b61e, + 0x88a959f1, 0xba6d5153, 0xd7fe6d12, 0xf5e94762, 0x510e2e85, 0x21d07cb8, 0xba58cd56, 0xa86ac9c1, 0xf49fb473, + 0x5cc93a59, 0x278f81a2, 0xa0bd39bc, 0x9b7a9b01, 0x8ddb2369, 0x606c537f, 0x9797163b, 0xf433d01c, 0xd2237d8f, + 0x677611ea, 0x74e76d96, 0xfb31aa7b, 0x1c5495aa, 0x6cc5a258, 0xcb67695d, 0xaf5de7b8, 0xe605c218, 0xd760de46, + 0xce300001, 0x1f650df3, 0x81d475a9, 0x6accfba1, 0xa230d32a, 0x24692906, 0x398858b0, 0x1c0ff53d, 0xd4329bca, + 0xef590c05, 0xa33c9d44, 0x465fb58a, 0x5813e8ae, 0x5cefa93f, 0x668129d5, 0x2996920a, 0xe8e9ba34, 0x67ee2033, + 0x2d0941a6, 0x5211e34d, 0x9e179152, 0x2eebde15, 0x265dcba3, 0x46e7e126, 0xa8c8594a, 0x33ef314b, 0x3a936ea9, + 0xf0e50ba6, 0xe08da62f, 0xb1457f44, 0x1eea3b8f, 0x827882e3, 0x5b044b57, 0x30c51589, 0xa56e1dbb, 0x1fd9f3ef, + 0x3ef47a01, 0x07d33300, 0x0feec907, 0x6db3b41c, 0x2812626d, 0x075efa44, 0x33fa7d51, 0xcb17cd84, 0x27c697ae, + 0x5b6b31bc, 0x063fef77, 0x215c52f0, 0x10694a36, 0x07c661ce, 0x698cedde, 0xbb886f62, 0xcffcb4dd, 0x46da41ad, + 0x10fb334d, 0x83ff9e86, 0xa8b660f5, 0x9a95b105, 0x0975980d, 0x0a7ba47e, 0x261807d2, 0x79adc381, 0x27cea381, + 0x28102712, 0x608c48a8, 0x59ab2e6b, 0xeb3c277f, 0x0c52d173, 0x92f400cb, 0xec4d737a, 0x5c950f4f, 0x7246712f, + 0x0336fb27, 0xcad24f84, 0x2d7cb957, 0x92d665ee, 0x3d030a38, 0x886b9a05, 0x7e6c9c44, 0x15ec2568, 0xe138b0ea, + 0x805b8d24, 0x21afffc1, 0x32954ec8, 0xbf37575b, 0xd6c61eae, 0xcf8f6026, 0x34844481, 0x7520d763, 0x16dab4e1, + 0x52e59198, 0xfd7c72fc, 0xdf7762ad, 0xf6b023db, 0xaf220607, 0x1443f8fd, 0x8d1bbab0, 0xfb22a028, 0xca9c00b5, + 0xd7c03998, 0xec723bc6, 0xe62f1962, 0x85fb402f, 0x5cc9948c, 0x59cfac55, 0x68528eee, 0x875f70b8, 0x7b28094d, + 0xd0f8fca1, 0x72771a92, 0xb51c24e2, 0x1257d17e, 0xa646ae5f, 0x75171beb, 0x212297bd, 0xbfaa9ecd, 0x518c1d65, + 0xe09f7b6a, 0x62ca5758, 0x4442d549, 0x13f67d83, 0x695a59ff, 0xce62eaa2, 0x1de98a77, 0x38149cd7, 0x21d16739, + 0xe7c4a6ff, 0x64a08652, 0x496af47a, 0xf8fab8e1, 0x3abfa465, 0xc9902c26, 0x1ece20d4, 0x6d8d3b31, 0x779584cf, + 0x5d27b862, 0x47f329a6, 0x70aaff3b, 0xfda9db92, 0xaf30ae9b, 0xe4da8c2e, 0x01958b93, 0x4c612363, 0xa04ff51c, + 0x79ee4079, 0x612d503f, 0x03eadf9d, 0x1a0b270e, 0xfecde124, 0x7310320c, 0x4b5ba089, 0xd9b685fa, 0xe1c550b2, + 0x04e9af67, 0xeca9c9cd, 0x8da38f2a, 0x4f9614ca, 0x4b5dc145, 0xd11eeb3d, 0xe6fb9347, 0x179c060d, 0x2d3b49bb, + 0x63ada9c7, 0xa16aef66, 0x0cdd20b9, 0x529d9003, 0x5eb0a267, 0x9347b3fa, 0xf7ded177, 0x3f7d675d, 0x7d75fdf3, + 0x8a030e34, 0x67edd63b, 0x3d6e1f72, 0xec49614d, 0x0d8c5075, 0x74f4a8d3, 0xdf3aac4f, 0x524cb87a, 0xc14fefe7, + 0xc463e881, 0x528b3e91, 0x98e68da4, 0xfd6f71e6, 0x1b12b7b9, 0x662d3844, 0xeac7e74e, 0xe49165f1, 0xf27c697c, + 0x0db04844, 0x619da7fb, 0x589f0285, 0x05cfce0f, 0x8df4249c, 0x2a9d03c3, 0xd1b63979, 0xb5e611ad, 0x4b624e97, + 0x43b79c8b, 0xb8672abc, 0x6e409ba6, 0x4911d9c0, 0x6e62f54c, 0x122b3e20, 0xb8b49f84, 0x4f6fb59e, 0x4697327e, + 0x1303867f, 0x18a5dbdf, 0xebef1e3f, 0xe8711413, 0xde6747b9, 0x561b038a, 0x955ad958, 0x22d3793a, 0xc092010b, + 0x24024a9a, 0xcf4a8fe8, 0xe5aacd3b, 0x0547eb5a, 0x9b7940eb, 0x23992a39, 0xd15e2ccf, 0x3ca28ae8, 0xb8ecba76, + 0xc40c5f16, 0x88519ed3, 0xecac7bea, 0xcc0af3b0, 0xbecbd483, 0x58960d9d, 0x2a152a8b, 0x1f0675d6, 0xc1d12149, + 0x1de1e78a, 0xd827b4c9, 0x508623ee, 0xfca04a41, 0x799d49a0, 0x14bde12b, 0x074f73ad, 0xdc18f3a7, 0xe67c88ad, + 0x17d3c91f, 0x8ca2b337, 0x3dcd605a, 0x8c299f04, 0x21aef1b0, 0xcd4ada86, 0x1f6bf9c5, 0xb20fc24c, 0x2f878f46, + 0x127b0fc1, 0xb6a0030b, 0x5759bf31, 0x8845a837, 0x2c03e5a1, 0xbea53378, 0xf2813ba2, 0x671dff61, 0x1f26ac91, + 0x461c3a93, 0xbf27a06f, 0x5753c3c2, 0x0fc8a6cb, 0xa05061fb, 0x6ba6b2bb, 0xcfdd0997, 0x0750eb7b, 0x7d31791e, + 0xe96128de, 0x8e992829, 0xc5e4bd24, 0x960afcf5, 0x9e301a06, 0x5bfd30cf, 0xe20965a3, 0xab2d567f, 0x147448fd, + 0x811fff48, 0xe77bbca2, 0x9ef5c15f, 0xee747436, 0xa0ca44e9, 0x70682e52, 0x247a5e76, 0xda29860b, 0xbc9c427a, + 0xf796f4d4, 0x1a70d26c, 0xcdd03e81, 0xf3427cdb, 0x87759b8f, 0x3406c22b, 0x59fa18ef, 0xda9e54d6, 0xd50d53fe, + 0xded3aaa6, 0x2d262445, 0xee11a7e8, 0xb3a68e31, 0x738bbe24, 0x4ba2073a, 0xc70778f2, 0xa0072671, 0xa1ab1a43, + 0x2126beba, 0x0d6870dc, 0x5f1ac65c, 0xfc6cd6a3, 0x2f0dd5c3, 0x64456d82, 0x7fadfa10, 0xdeca2d53, 0x80ce1e2c, + 0x560a1e0c, 0xf733833f, 0x528ac8e3, 0xa9b6a518, 0xcbc289ac, 0x0a6de1b3, 0xe0b95877, 0xb3b8bfa0, 0x7514393e, + 0xefaba126, 0x2ec23b0b, 0xdc5b50a0, 0x38219718, 0x1f875cf4, 0xf2310d60, 0x297f4f67, 0x4aadd86f, 0x0c9bb56d, + 0x72f5745b, 0xafa6d650, 0xb06db42b, 0xb4d21ed3, 0x9dda789d, 0x376cd25a, 0xefeb609f, 0x0749b63d, 0xfd601a30, + 0x3d96093f, 0x5ccae828, 0x05f77eca, 0x1b537767, 0x7c9d9dd6, 0xaab077d7, 0xe3091265, 0x72964cfa, 0xb6f92d81, + 0x4747aaa3, 0x780c5fe0, 0x8cc825e9, 0xc8aa2f86, 0x8d69ebf8, 0x10ccd93c, 0xe431a555, 0xb25a7d1e, 0x70ade803, + 0x7d1d22a5, 0x75e724b3, 0x4a5fd5ce, 0x5e97a645, 0x9b2c8f68, 0xe333fca3, 0xe8c00107, 0xb2579a24, 0xe19485bf, + 0x1b6e6333, 0x5e665a16, 0xce414eb9, 0xe28212b3, 0x3126dcb3, 0xf8e1c6f0, 0x18faa0c7, 0xb92627fa, 0x699da8a0, + 0x2fde9ae8, 0x7c189452, 0x3c8a64d4, 0x194074c9, 0x418b5861, 0x943a2970, 0x13ef3d7c, 0xd2775ce0, 0xdce3e853, + 0x5e678ace, 0x9ab2b730, 0xe487c683, 0xe5e516fa, 0x159f3b47, 0xc0fa4712, 0x55c1a2e6, 0x39429f5d, 0x7addcb0a, + 0xe2cd869c, 0xff03cfb1, 0x2493aa4b, 0x0e14e892, 0xf91bd74f, 0x925c9d29, 0x95a736b2, 0x4b820d61, 0x8797d598, + 0x75f9094d, 0x1153eb0d, 0x1e26da91, 0x9a14adbc, 0x89a5eb56, 0xcd951bfb, 0x472547e0, 0x6efdc215, 0xe3d7404e, + 0x011d03f6, 0x6d46124b, 0x77971e32, 0xd06007ba, 0xb15f9a9a, 0xd2641c20, 0xfb9455d3, 0x68af6c53, 0xd4c0e45f, + 0xc7c433fb, 0xb6c360f7, 0xc5ff2a45, 0x2b8ff8b6, 0xeb094f34, 0xae71c677, 0x1d7ad73d, 0x15bae98f, 0x901ba809, + 0xf717c405, 0x317bff5d, 0x7ebbdadc, 0x4f4ebe3e, 0xe8f9d658, 0x54ae1ee1, 0xffee91d1, 0xae302ce9, 0x8501b381, + 0xc27f62ae, 0xe43ba757, 0x1acf75c3, 0x5c85dac5, 0x45b8671c, 0x8eae7ab3, 0xeb52281e, 0x1e55d3d7, 0x6fa640b9, + 0x19e69c3d, 0x83fe4b09, 0x12177333, 0x55a74cc4, 0xf669a7eb, 0xae6c58f1, 0x604fa6f2, 0x4de99d06, 0xfaffa61d, + 0xf8a9b69f, 0xf846ed78, 0xf2957604, 0x98c57c00, 0x3cc5eb82, 0x633aabb1, 0x672c2f49, 0x74674972, 0x1235fe31, + 0x5f2888e9, 0xf14c7609, 0x05b289d0, 0x5eeb3e73, 0xf9f80bb7, 0x2f9b4cf6, 0x25a23169, 0x5cac9e29, 0x08ca0352, + 0xa1fb2105, 0x72f8f509, 0x598ccb0f, 0x4f0e3488, 0xafea6669, 0x2da7eb0b, 0xbfb95733, 0xb86814db, 0xcdacf64c, + 0xf22b9fe2, 0xc4c46c88, 0x839d85c7, 0x65f62f9f, 0x2cf44171, 0x07abf2c6, 0x8911b476, 0x70512468, 0x1eec2eea, + 0xfcd4321e, 0x4de87300, 0x8bf8c6a5, 0x11d61a0e, 0x36b22c9c, 0x37b859cd, 0x8664478f, 0xbf1c6f2b, 0x2a24205a, + 0x43d66445, 0x8b9d3073, 0x28feaabe, 0x1bdb5b2e, 0x0a631c0c, 0xa420a0a7, 0x2369087b, 0x46105337, 0x016d8816, + 0x464a5686, 0xfd9b849f, 0x934e9554, 0xde334f0f, 0x6e3dbae2, 0x61564ae6, 0xe3253621, 0xcc0c353c, 0x76e0426a, + 0x422bad2c, 0xf6fdf38c, 0xf4045364, 0xf3cb984c, 0x92043cad, 0x02a563c5, 0x701dfb81, 0x858485f7, 0xf9c9377f, + 0x5e5ad598, 0x66988a48, 0x0276539e, 0x0299a3ce, 0x6f4fa5c4, 0x71a9efa1, 0xc2e3ce39, 0x0d6fe095, 0xe37521f2, + 0x918b2043, 0x99f8dacf, 0x9043ed44, 0x361c2a50, 0x077b1365, 0x6fa1f6b8, 0xb85999be, 0x79d3bbc0, 0x35bf6244, + 0xadea72a8, 0x64d5cb11, 0xff9881d6, 0xcf9c61fa, 0x06a15b89, 0xb0088279, 0x17b3ea4e, 0x619f8304, 0x9eb270b5, + 0xed56dc6f, 0xe803675d, 0x7b37d845, 0xe0bd5bff, 0x9a090655, 0xf73b6c05, 0x0942974d, 0x7ad59d23, 0x29d162bf, + 0x670f41b6, 0x52390621, 0x588ec88a, 0xbc5e7fae, 0xee5ee0e0, 0xd03d54ec, 0xc12e16f2, 0x84730d7b, 0x75ce0dbf, + 0x214da7fb, 0x6383809d, 0xeb1cb147, 0x789e0c81, 0x4d2268e5, 0x2b03fcb5, 0x8d536c16, 0x84e076ca, 0xa8619658, + 0x7661a173, 0x3e534ee1, 0x35e0bec9, 0x10354925, 0x8513e05b, 0xf1052cb2, 0x310998f9, 0x33a8baa7, 0x8820ee92, + 0x810ba338, 0x38ec4848, 0x063c6024, 0x5d33d63b, 0xba114cde, 0xc9047344, 0x75ecf71f, 0x8b56b12f, 0x56a6810d, + 0x5a82115b, 0xda7f6ef0, 0xe54bf909, 0xacbb0b6a, 0x591723ba, 0xd6829246, 0x39a7cda8, 0x2739e0ba, 0x07ab6cc0, + 0xe2090535, 0x39ec20a3, 0xf7902a92, 0x10e25e44, 0x6e430e71, 0x6cc86168, 0xf77c895c, 0x14ac7225, 0x40143968, + 0x3efece1e, 0x88e7cef6, 0x14be04cd, 0x6c0c332a, 0x08fbe7ad, 0xeaf4e7e3, 0x81edefc8, 0xccbe51b9, 0xfa9dae05, + 0x1a5777c0, 0xc594937b, 0x39a575d6, 0x6d5f3c0b, 0xc331cfc6, 0x40da7921, 0x4b8e49e5, 0x72873528, 0xccbf92fd, + 0x7b866281, 0x3125f8ff, 0x4f3495e2, 0x26225f5b, 0xa62c8a2a, 0x68203e28, 0x6d9cfc1e, 0x5c8ea789, 0x238cb16e, + 0xa77ffbec, 0x28eecc68, 0x7f611461, 0x7f687de1, 0x4fcb033a, 0x620a796b, 0x08776eb9, 0x5457d55a, 0x630ecc17, + 0x44318449, 0xbaf4f46e, 0x47e28ed7, 0xd17df52e, 0x9c56fb96, 0x93a50b8a, 0xd23f2f02, 0xd53cad41, 0x4dd94728, + 0x47b2167e, 0x8c642a65, 0x4dc5932e, 0x0fe5ee6b, 0x5fc0a2c9, 0xf50e8b2f, 0x755d3644, 0x6744b33e, 0xebe6aab2, + 0xe0140185, 0x1bf75062, 0xab23302d, 0x31b69bcf, 0xee1c73d1, 0x7d70b0d0, 0x0f6fe336, 0xade755b3, 0x182391cc, + 0x167504f8, 0x60c64afe, 0xbf11acbc, 0x414f3893, 0x16a64913, 0x457a0401, 0x5bf7b068, 0x42ab702c, 0x80ebdbc9, + 0x2b2b2e10, 0xa80651e4, 0xacb46bbc, 0x1e89db84, 0xf0d11894, 0x41ac886f, 0xff74e0af, 0xfe7c115a, 0xd1eadea0, + 0x76b50316, 0x6de8499d, 0xa5cf864d, 0x899ebe74, 0x35e7f205, 0xe15e6999, 0x6579c347, 0xbba90e5f, 0xca1eaf30, + 0x95d760d3, 0xe65d1db2, 0x8b63b189, 0x26a10500, 0x3f5205e7, 0x785c9a06, 0xaf17131b, 0x76c44297, 0x714ef0ae, + 0x88ffc4c0, 0x029c3b28, 0x98d34b51, 0xed75ab7d, 0xa922c63f, 0x536272ae, 0xb50954dc, 0xfcccc81a, 0xee62f413, + 0x5c17e421, 0xb63762d6, 0x8d055956, 0xf3ea93bf, 0x047d0af4, 0xc61ba35f, 0x369ba345, 0x994686af, 0xb7d5e0a5, + 0x33c850e9, 0xd5a14ca6, 0x0aa009c4, 0x6ef9a2fe, 0xe20b0f52, 0x0ed103e3, 0xd52c7744, 0x08b9878a, 0x704337ed, + 0xdce41422, 0x62fef670, 0x33ce873e, 0x7e006179, 0x8fee1ac6, 0x3b0c006e, 0x0879e102, 0x24d59944, 0xb5e7e385, + 0x6ce722f5, 0xdb3284a4, 0xf15b6bf4, 0x293704b7, 0xc7b33a0b, 0x12c97879, 0x80a406a8, 0x77d7da6c, 0x1745acc9, + 0xafa94b3a, 0x7bd3dc35, 0xdf14120c, 0xfa26f905, 0x72e79e5f, 0xd31520af, 0xb40f1270, 0x587a6daf, 0x6baaf9bc, + 0x44712f7f, 0x9652f9fa, 0xda4be4e6, 0xa20210e0, 0x4c3d8218, 0xdfca2853, 0x43768835, 0x204cecd1, 0xe8a466ad, + 0x67cf34f3, 0xb87b2cb0, 0x822f8241, 0x558632f5, 0xca70637b, 0x119ad954, 0x74e3b2a4, 0x86e88d0d, 0x10f271a3, + 0x5a2546d4, 0x61b1f73d, 0xa0771b92, 0x5dd7387e, 0xa3d741ab, 0xa0356f6f, 0x860a5466, 0xe9bb2a6c, 0x387a84cf, + 0x4cc593cf, 0x665fd52e, 0x0487c4dc, 0x08b90a2d, 0xc67e156b, 0x23fef568, 0x4ea48065, 0xc4afc4b6, 0x4c4627e9, + 0x2ae63f0f, 0xf3465709, 0x0b2bf6a6, 0x9570212a, 0x4a79f33f, 0xd79affbd, 0x173191c8, 0x50e23bbc, 0x2a4e8228, + 0x27d70c7d, 0xb5bfe33d, 0x6b9a0870, 0x85079f4b, 0x113fa7b8, 0x5ba984dc, 0xe5c924d1, 0xde5032f4, 0x9f57e3b7, + 0x81fc8abb, 0xf51f757d, 0x8d24a3bb, 0xbaa11f2a, 0x9f0e957a, 0xfff51ab4, 0x34ae1376, 0x86a0b831, 0x332d6588, + 0x983c01eb, 0x44f71a43, 0x09cc1e60, 0xd441c045, 0x33a5a0dd, 0x4fadf443, 0xe33ae342, 0x20caf224, 0xbdaf11d6, + 0xfef6177e, 0xe47b3491, 0x38ea6f52, 0x1149e413, 0x266d7055, 0x68e32d09, 0x95e79c59, 0xbe878df8, 0x97ec1c61, + 0xd9ef8b6e, 0xd597f8ba, 0x4b0195b1, 0x7d5f60d8, 0xbd1f9e0c, 0x5036ca69, 0x40fa881a, 0x055ff4c1, 0x81e8f800, + 0xc6f9f316, 0x622d48cd, 0xca89d40c, 0x6e3910f8, 0xa26d7548, 0xb1ff1bd2, 0x16f5d6a9, 0x70f164cb, 0xba7aed1d, + 0xc01acb85, 0xff57b499, 0xcbdbf2fd, 0x28926eab, 0x5bfa35ed, 0x8ec5a632, 0xd2809303, 0x3fe73c34, 0xf9c5ddd1, + 0xa8d8e95b, 0x649afaf0, 0xee17b988, 0x8e5f5fcd, 0x84c14cc2, 0xb97fc768, 0xcfd9da82, 0xa9e4fe35, 0xb47ef995, + 0xfc135b57, 0x1b0b21cf, 0x6bd63ffb, 0x66c4841b, 0x7cbf1c31, 0xe8861395, 0xadbf3d71, 0x73862308, 0x7a209daf, + 0x2411d352, 0x151275f0, 0x04968f2b, 0x9f1a5b51, 0x0dc6c3c9, 0x899ca466, 0x8ac3d9c1, 0xf2bd1a20, 0xefec4726, + 0x32ba35c9, 0x6ef752d1, 0xfa540123, 0xe65402f8, 0x0de6d603, 0x0ef41742, 0x36bf0767, 0x908c550d, 0xf34b04ec, + 0x918853c8, 0xd9e7ba4e, 0x21e36e4d, 0x580ebff2, 0x0bee84ca, 0xf52c070c, 0x7a840ff3, 0xd295a14a, 0x705e3ee1, + 0x72c13c1d, 0xc4fe2c8e, 0x47af9936, 0xc20a85f7, 0x368c03e0, 0x155436f7, 0xd73a1085, 0x069e9fa8, 0xeb401ccb, + 0x84a22d19, 0x68ca6699, 0xb200deea, 0x71d33d13, 0xbbb5aba5, 0xb645f14f, 0x12f8bdfe, 0xbc2f1683, 0x4fbb3932, + 0x5bcbc1b9, 0x63f567a2, 0x8a47b86a, 0x7bb81313, 0xd718a6c6, 0x45045643, 0x4b48e962, 0x07be789a, 0xc65c7fab, + 0xffd16b80, 0xdc87188e, 0x8e498047, 0xd8e0ed83, 0x6c2d3fcd, 0x821d28cc, 0xa300e116, 0xb71bd511, 0x7a82f7c8, + 0xbb4055f1, 0x040cfa66, 0x22cb2881, 0x2061bfc9, 0x984acbcd, 0x99b88ff5, 0x4acea3ce, 0x883d03db, 0xdecf21d4, + 0x8dbb5edc, 0x7b2f881a, 0xc983a71c, 0x94d9138b, 0x5e7b139b, 0x8c1243b8, 0xd2363f96, 0x83dec56f, 0x5e48b21e, + 0xccf075be, 0xa3217c2f, 0xddb06532, 0xd78fcc37, 0x18d46a9a, 0x26eb966a, 0x5655fe9a, 0xaa79f523, 0x59b8e90a, + 0x97748e3c, 0xa522d3c9, 0x78d14e72, 0xf83a3f37, 0x33ea4b70, 0x62123071, 0x5e8158cc, 0xb5391410, 0xad0d892f, + 0xc48f87bf, 0x7090bf82, 0x798f7966, 0x3cac4b10, 0xea25ebf0, 0x59d1fad7, 0xfe8edb11, 0x85e9c044, 0x8a4732b4, + 0xbd806bbd, 0x2e627e72, 0x87fb65dc, 0x02681a91, 0x27376671, 0x1eab5d2b, 0x09dedfe5, 0x81f1cf7f, 0x314e7b29, + 0x8a25ffcf, 0xd7b96c5c, 0x070fbd88, 0xe9ae8c32, 0x9839c161, 0x2ddfbed6, 0x624bf7e7, 0x6394266a, 0x0727eb25, + 0x6e32bb03, 0x52a2b152, 0xa41cb4a4, 0x63b4159a, 0xd10603ce, 0x15c56d36, 0x98f89e04, 0x3d174f68, 0xe6d4a728, + 0xad84c07e, 0x569bc4fb, 0x03829a5b, 0xf01149f1, 0xa12ce6f3, 0x9d20430b, 0x9da53efd, 0x72e0ca7f, 0x0c3cfb97, + 0x61869d1e, 0x3856489c, 0x4208f308, 0x9e237f41, 0x5d17cdbe, 0x7fac1c51, 0x16d70e6a, 0x586a0305, 0xefbbcc1f, + 0x35e76d3b, 0x8744ea0c, 0xc86f2d83, 0x6fee5811, 0x6675f176, 0x8bedcbc5, 0xaf9949a3, 0xe5412016, 0x9dd96ce6, + 0x0415f0f4, 0x78891c49, 0xb76aef21, 0x1993f27d, 0x6e9ea6f8, 0x1e356594, 0x4953f739, 0xe4707976, 0x8f35f090, + 0xf061dff3, 0x6dd2ff84, 0x3d9bd396, 0xbbb51795, 0xbb931acc, 0xfd28deec, 0x4c48a4fc, 0x77080c8c, 0x786a2f9e, + 0xd8111cbb, 0x0c15700b, 0xa6bda1a0, 0x8228254b, 0x2268018b, 0x6be9f3d4, 0x3cf08bd3, 0x1eba4d10, 0x3f5901c7, + 0x1419d6f8, 0x759554f7, 0x0959b2fd, 0x8b8f6b98, 0x64227dab, 0xa79af448, 0xfaba2440, 0x9d82f1cf, 0xeca81981, + 0x54d7a592, 0x243673e5, 0xffea63ad, 0xe1578e8c, 0x0fc86186, 0xd954133e, 0x0005d777, 0x2c2378c5, 0x254c33da, + 0x3677ad1a, 0x39ffccb0, 0x6ab1ebf8, 0x95a18fad, 0xb84db261, 0x5b4839bc, 0xdbac00f5, 0xe486528f, 0xfe45ab49, + 0x8ca75f75, 0x76e9db98, 0x3fc11e2b, 0x89d3831a, 0x1a338275, 0x656ce2f1, 0x2e6806b1, 0x4692d6ce, 0x19c26244, + 0xb0ca0f2b, 0x8371beee, 0x217a177f, 0x26ffbb37, 0x9a46a48b, 0x7bcbac08, 0xc0f43a24, 0xe8b74d7e, 0x27f5cef3, + 0x18adb186, 0xa1689b66, 0x0e789b84, 0xfbf71d18, 0x3ce4477a, 0x8d749bba, 0x9149b173, 0xb464123c, 0x2e3a5f1d, + 0xc85c244b, 0x8c1b71d9, 0x976628e7, 0xd5fa123b, 0x637a7c9f, 0x7030789a, 0xce21555d, 0xc0f4c1b1, 0xf6dee97d, + 0x6fe04563, 0xf9b1de43, 0x1f278c2b, 0xb3db3131, 0x564f9af9, 0x17f0551e, 0x630f7a2c, 0xf102d9bd, 0x2cb7b198, + 0x654def96, 0x46c2b46b, 0xd1ea74e9, 0x871209ba, 0xfa646217, 0xc8ff25bf, 0x28ef6741, 0x200fa9df, 0x9275125f, + 0xbd200885, 0xb8034338, 0xf515611c, 0x1503db39, 0xaa291487, 0xa42e3cac, 0xab9ac5df, 0x4b77ddc4, 0x94d3c133, + 0xe77dd3db, 0x1d8bd373, 0xa0a858ec, 0x3a0771be, 0x6f39e138, 0x29c65d8b, 0xdd79b2cb, 0x583c79b1, 0x91f6c7f9, + 0x89fc85ce, 0x4c6c85a5, 0xe3d8b8ab, 0xacd97a5f, 0xe4524187, 0xdcfb6be7, 0xc29b5dfd, 0xac439eb1, 0x53ab9cd9, + 0xee56c046, 0xaef6b122, 0x1584acfd, 0xd1fec680, 0xcf814cc0, 0xf7d80e81, 0x29dc1d30, 0xef699eb2, 0x65da5391, + 0xf8fbf9a2, 0x31b58627, 0x849d681b, 0x3f1fcd3b, 0xa8daee65, 0x5cbc4e54, 0x9c7b88d9, 0x03f22709, 0x8e35d88d, + 0x8f2d345f, 0xbb9036a7, 0x024384f7, 0xc6d3f3a7, 0x589bbf0d, 0xbbdcadcc, 0x02c897d6, 0x1493d32b, 0xae74bb69, + 0x59e9829a, 0xaacca728, 0x46a25cf6, 0xeeaa9cf0, 0x1dcf59fb, 0xa3e50f86, 0xa5a2a509, 0x47c9ec40, 0xbff72c43, + 0x1cffe35c, 0x942936e4, 0x0f3b41ec, 0xda847276, 0x5e799ca6, 0x817fdc2a, 0xd0024682, 0x79595b68, 0xea43f6f0, + 0x940ce03b, 0xbcebb548, 0x354061b4, 0x122f2813, 0xb6e8be11, 0x3f5bf1e1, 0x2a5b0622, 0x29bf0b2f, 0x50b34150, + 0xa50cb976, 0xbb67b4bf, 0x2aa597bc, 0x96e27e89, 0xd9c5cf34, 0xdcfab655, 0x78377d3b, 0x3ce2ad18, 0x839cfa8a, + 0x6678bdd3, 0xb550f585, 0x2799d334, 0xd464f83f, 0x000a10ff, 0x30951c67, 0x67bdf1ab, 0x06a1d062, 0x25552235, + 0xa4eafc36, 0x38e246fa, 0x50d37949, 0x2a1862b4, 0xd2aad063, 0xbac26324, 0x86a7b594, 0xd7c67ae9, 0x07024955, + 0xbbf14976, 0xd0cdbcd2, 0x58b4496c, 0xa4fd0b14, 0x1ed58697, 0x2cd84426, 0x42dc1f29, 0x1098b7ad, 0x941572ea, + 0xc63413fc, 0x1bb688dc, 0x80efdf12, 0xe979aae1, 0xa9da635f, 0xc0d15555, 0x9b218362, 0xf7430ce3, 0xeaecb0b0, + 0x33f7c4fa, 0x2fbe5058, 0x161d5a9d, 0x6bc1433d, 0x8e3d1b3c, 0xa8f6ee60, 0xaed599b4, 0x5ff36ee4, 0x2f644c30, + 0xf84e17f7, 0xc8f64926, 0x20345a24, 0x57245b69, 0x3f5600a9, 0x4860a7b8, 0x534d676d, 0x682834c9, 0x4f889555, + 0x76a5439a, 0x4ea922fb, 0x1cdeb164, 0xd14e99c7, 0x7706f07d, 0xc43bf023, 0xe269993e, 0x162471bc, 0xa421ae75, + 0x9d506bb7, 0x7df764bc, 0x3cdb924c, 0xb74b2516, 0x769d6edf, 0x642465bc, 0x6571c43c, 0xc54fdb74, 0x2ccb89b0, + 0x6dd4f37b, 0x3b877343, 0xc9fe90f7, 0xaaff8d02, 0xe5d8acb1, 0xbc40e76d, 0xea312a43, 0xfeae766c, 0xe3a071ff, + 0x0618af76, 0x8eee2864, 0xf2e87d07, 0x4948b68b, 0x6f1c9ce0, 0xace89c96, 0x46716e5e, 0x8729da1f, 0x4909ce35, + 0xbbf6aea7, 0x1843645b, 0x82090080, 0x221e42f0, 0xeb5fc43b, 0xd953ef8c, 0xd3ec1479, 0xade0c362, 0x1bbe6220, + 0x55ba147c, 0x64ac3064, 0x352b9267, 0x76719362, 0xe37e50ba, 0xf2427c77, 0x261e99b8, 0xd05f39ba, 0x6b22483d, + 0xc4df2260, 0xb66f5ed0, 0xba87e73f, 0x6ff39fd9, 0x690345bd, 0x08fd3e95, 0x08366641, 0x0f869a32, 0x3efec4bf, + 0x6e18359d, 0xaff7fa52, 0xdb736ee6, 0x987f52cd, 0x3965eeb8, 0xd6d310c1, 0x7d11e847, 0x8e73e5e4, 0x8ab18cd4, + 0xd254e152, 0x4bd4af93, 0x9e2f073d, 0xbdbe0655, 0xb7ed5cfc, 0xbe2a6352, 0x0e432d4f, 0x7113af7e, 0xbe947937, + 0xa2203285, 0xf3bbc871, 0xd22397d4, 0xc0e075c6, 0x3c1344cb, 0x7541697a, 0x0f13a372, 0xf6762edc, 0x716ea950, + 0xcd60c134, 0x77d9e3a7, 0x2086e182, 0x9ba5af39, 0x469b3485, 0x042e3473, 0xd44e6ba8, 0x3f907e79, 0xe4ef82b5, + 0x02b8354e, 0xf20845ed, 0xcb3cd92a, 0xc4d06e03, 0x23029c59, 0x5bbd64a0, 0x30d0050b, 0x1d4e81c1, 0x71728fd9, + 0x678ac6ba, 0x68c034ca, 0xba0a5199, 0x50bd4874, 0x6576da92, 0xd9ea56ea, 0x352a62e0, 0xa08cd696, 0x4feec61d, + 0x49cef1e4, 0x05c5fc7d, 0x8a727ccd, 0x34764449, 0x335c4303, 0x98ef0c17, 0x6bb4f1c2, 0xf120c14c, 0x98e7669b, + 0x166f6d01, 0x9d265bfd, 0xe33c48c6, 0x3833f24e, 0x2cadcf2d, 0xa77262ad, 0x71afd044, 0x76e5bde0, 0xc6612f0c, + 0xb818f436, 0x8d85c206, 0x084f3d91, 0xccb2089c, 0x1600ae94, 0x06759fc1, 0xaabc526e, 0xb48528c9, 0x6eb609b9, + 0x1038ac93, 0x724cff80, 0x6b227c85, 0x9fc818b0, 0x0006b66f, 0xb2c1f93c, 0x9916fe79, 0x9648bcac, 0x37c35ec5, + 0x71766c18, 0xcacf57d2, 0x54476fb2, 0x04984fbb, 0x41133dc6, 0xd4794965, 0xc2659b3b, 0xdb5ca250, 0x36b91802, + 0xe51a4031, 0x17d5ddff, 0x8495c9b2, 0x01fd0f7f, 0x32541074, 0xe2eb8157, 0x05dd7c28, 0xd4022334, 0xba8d2ab6, + 0xd9e4a24f, 0xeea3fc33, 0x752790c1, 0x0866c6a2, 0x9fa2c368, 0x1ba639c1, 0xfe2c77fa, 0x0bf90cdb, 0xc9b96af7, + 0xf517ab13, 0xdedfc88b, 0xe791e559, 0x855c3fc5, 0x6e18dfbc, 0x35cfd1ba, 0x9fd05750, 0x5279f09b, 0x24ac282d, + 0xeaa230ee, 0x10e9b819, 0x5ca5940d, 0x5ff37fb8, 0x6a843c04, 0xb3031bd7, 0x47420d91, 0x39ffbf7c, 0x08c2a1a3, + 0x9e4d86e5, 0x2a2f9c2d, 0x52b44780, 0xa60dc2a9, 0xa0515da0, 0x5a3e59e3, 0xc6635b45, 0x4c03a3b0, 0x55527847, + 0xc80486a9, 0xb856043f, 0x177fa819, 0x1b421e8c, 0x66fcf632, 0x4f4387e3, 0x6b061de6, 0x7a1f0c10, 0x66f6c3d9, + 0xedc1a5e7, 0xd70832ea, 0x26ff5c28, 0xc718746c, 0xb909dc90, 0x159e9640, 0xae46a6c8, 0x821add2c, 0xf429e611, + 0xfbae2654, 0x80dbf128, 0x0e9015cd, 0x2dde9221, 0x3e023621, 0xee92a0b5, 0x5f8f4452, 0x30c89642, 0x92fe74aa, + 0xea81dbcf, 0x20d05805, 0x2dd37f0d, 0x03cc1e0d, 0xfb31ed2c, 0x33bb89c8, 0x6070864d, 0x1cd82cf3, 0xd9219505, + 0x0249802d, 0xe4f37a43, 0x515b47cb, 0x2d0cf20c, 0xe0ebb487, 0x431fa614, 0xa9419a66, 0xd4eb5f71, 0xca0859e6, + 0x8aaba5ce, 0xb5f03326, 0x6c26af9b, 0x52cf6d6f, 0x32197d76, 0xdfbd3280, 0x01ab00d9, 0xbffddd00, 0x1756c50b, + 0xe17c850f, 0x3a710387, 0x6eb05027, 0xecda032b, 0x1f32d186, 0xe6f2e738, 0xb81f4f7b, 0x8d7b5649, 0xac2a064f, + 0xe3f5f0a7, 0xf91c2356, 0x0b81d274, 0x6eda3b69, 0xdeb65a8c, 0x3dcc2cda, 0x5340d080, 0x401755f4, 0xe07e7ae2, + 0x36aa1091, 0xa8ea77a5, 0x4c58e982, 0x7b2c791f, 0x2c8e01c2, 0x92981730, 0x9bd2beb6, 0xc84065ec, 0x30407a11, + 0x9cbc6cca, 0x5771285e, 0x1f3edaec, 0xa8809c0a, 0xf3dbe666, 0xab4aabdc, 0x6014b1d5, 0xbc3dc7c8, 0xd0a3713a, + 0xb39b864b, 0x75b8cb10, 0x85e994e7, 0x7c4c16b5, 0xcee201b6, 0xfb5ff7fc, 0x909bd397, 0x2083c7a4, 0x1952c7e3, + 0xc5ff680f, 0x47fc38b1, 0xb3e11066, 0x64711827, 0x08a484f9, 0x38b9c532, 0x1357ad87, 0xd7071a5d, 0x6f48fbd0, + 0xc98b536c, 0x30198f98, 0x6c3642ef, 0xe4215b87, 0x1dd8cb57, 0x57d8c712, 0x932de95c, 0x1538e710, 0x84796af3, + 0x7b9f0198, 0xbdbc7dd4, 0xd18463e4, 0xd41ee22e, 0xb3c02635, 0xadc174a4, 0x6dc33713, 0xe760dc29, 0xad51dbac, + 0xde660d9c, 0xcb78c2ca, 0xb6452721, 0x9215337d, 0x3d07a186, 0x8d016f4e, 0x961a67ab, 0x4d1994c9, 0x823588a8, + 0xf715d54e, 0x287b3afa, 0xedab4fbc, 0x3a3c5a1f, 0x629e0408, 0x29863bae, 0xc2b73dd7, 0x8d77eee8, 0x05cc1ab1, + 0xae889c36, 0x6283042c, 0x2f317695, 0x5c9ae2b3, 0x2db55137, 0xe43846bb, 0x1df459d7, 0x6d2f82fd, 0xa466689e, + 0x59bf15ed, 0xb52310e8, 0x27c152c2, 0xd801e7b7, 0xe675f89f, 0x2d991bdf, 0xca594e29, 0x877a5b86, 0xe487d9f2, + 0x1e7fd4de, 0xc91c061d, 0x74e87f01, 0x816b2aa7, 0x4a498070, 0xce624eba, 0xa3bb1d1c, 0x2a3e6d61, 0xf9267627, + 0x5bb3cb21, 0x2f0ca2d2, 0x7c839e52, 0x379d88db, 0xf9cf5760, 0x27a3219a, 0xb1b78179, 0x8176e0ca, 0xf9777068, + 0x2d941c98, 0x9af42287, 0xef456b81, 0x31fe7554, 0x80b7216e, 0x5a3b3661, 0xdce05264, 0x0f5c0d40, 0x460cf2df, + 0xcc36229e, 0x6f18eb74, 0xdf9feab8, 0xc273c4cf, 0x86d758a3, 0x6c9e3928, 0x955d617f, 0x30676a9a, 0xdc878261, + 0x105e8b1c, 0x110fa754, 0x26051f54, 0xbf96fe4b, 0x6f05860e, 0x072d318c, 0x54893a6e, 0x3660ba70, 0x4dddb6d8, + 0x73d694ce, 0x5312e6a1, 0x5c9a2e55, 0x5b735113, 0x5d69fc02, 0xbf020787, 0x6b289b6d, 0x5306d80b, 0xe0672ab9, + 0x66ddb899, 0x39153308, 0x82505d05, 0xfbaf3ad9, 0x59414924, 0x8a5f463b, 0x552a140a, 0x4b8beccb, 0xa564aee2, + 0x6f8b7270, 0xdfc911af, 0xb0ca4645, 0xfb297e2f, 0x33c4455d, 0x70f8f842, 0xd23033e8, 0xaa7cf530, 0x50042d8f, + 0xcea23ae6, 0x6073648f, 0x536b06b9, 0xc681e4c6, 0x37ff0e11, 0xff03ee66, 0xb3ab899a, 0xbc8bca43, 0xc3c8beec, + 0xa75ea04c, 0xd77130e6, 0x8f7fca19, 0xc208fc79, 0x3d49638a, 0x47cd42cf, 0x6526ac2c, 0xdceaf1e9, 0x9b88a77a, + 0xb4a471d1, 0xef0dbb1e, 0x10b09cea, 0xfe0366d8, 0x0592ed64, 0xd36356ed, 0xf88ba0ce, 0x7aa532f8, 0x78942fb9, + 0x423a40d5, 0x664af202, 0x6c774295, 0x7008dea8, 0xee55a75e, 0xd9c90f6d, 0xe3c17cef, 0xbecdc67b, 0xf63cbd00, + 0x2c9d6529, 0xec17405b, 0x1eafb34b, 0xae6fa8f8, 0xdd5324d0, 0x49b64439, 0x19645773, 0x0e228b97, 0xd1329473, + 0x85809fec, 0xd67112a2, 0xc6f5d69e, 0x7154e2c6, 0x9e688154, 0x8b52f868, 0x70c47b08, 0x9f017627, 0xa350a34b, + 0x89a1245c, 0xf1301b6c, 0x71193b45, 0x4e1ab032, 0x8dfb6c05, 0xe11d7783, 0xba890371, 0x8ae63f01, 0xf8c5c1c0, + 0xac7e8a4f, 0xfe05adce, 0xfe37cfe6, 0xf69494b5, 0xf07b9c13, 0x742e499d, 0x14d66ec2, 0x806496dd, 0x26a691cf, + 0xa30005c6, 0xaa179d7f, 0xa30a8534, 0x12ebb21c, 0x2264c956, 0x90cfb68f, 0x401963c4, 0xde1ce3b7, 0xd2508a8c, + 0x42ebb966, 0x9178c9f5, 0x42e647f3, 0x320f7dcc, 0x1bad101a, 0x935c5452, 0x74aaabdc, 0x2f76490f, 0xf8002b10, + 0x1454dea2, 0x63586578, 0x0eff8b61, 0x203dfed3, 0x76398dc9, 0xc8b8997e, 0x39c7f0fd, 0xc51ab172, 0xbba8e736, + 0x6cd616ab, 0x9252b8d5, 0xa2e938eb, 0x52073222, 0x5468560d, 0xb9563cd3, 0x4e4c929d, 0x333c199c, 0xc99f07a2, + 0xaab0d795, 0x5942a33f, 0xb136f6c3, 0x082cf529, 0x315de725, 0xcb9d1351, 0xab129009, 0x8712707f, 0xd74e10f9, + 0x58dd0127, 0xf78e4ed1, 0xcde7efe5, 0xfb0c4e3f, 0x41d735b9, 0xe0c85e06, 0xcabaf995, 0x8c8fc3a7, 0x912f2c10, + 0xbcb8afc0, 0xa5e34264, 0x62214583, 0x8b0f0149, 0x28ae1f03, 0x51852fc0, 0x54271e33, 0x250bc75e, 0x380018c8, + 0xc16b28fe, 0x18e34f07, 0xcd036866, 0x8c11160f, 0x2d6532d8, 0xeb81526a, 0xe7302e27, 0x3eb919ed, 0xb6da5e58, + 0xe5236fa6, 0x32224d50, 0x946542d6, 0xed9efdc1, 0xd69859a6, 0x43439f51, 0x631eb4db, 0xd91c8001, 0xf4e1dd20, + 0x66f6511f, 0x5e792c1c, 0x2982f449, 0xffb732bb, 0xe2951e8c, 0xe94b5e57, 0x14a76381, 0xc0ba177f, 0x3bdc965e, + 0xb73ff075, 0xbc76849d, 0xf1d4b57f, 0xa95a63e3, 0x30cde894, 0x1ca85c52, 0x1652d9a3, 0xc887e969, 0x9b5b2cf3, + 0x5b858cc2, 0x91f0c14a, 0x6f6d0ae0, 0x30b4e1d8, 0xfd0b8787, 0x31f3e4e8, 0xb3455db1, 0xfed5f41e, 0xf74aa4b3, + 0x79154c76, 0x2633a9ac, 0xe42dc461, 0x3445ee3c, 0x9c010d91, 0x1f903b27, 0xaa22a89d, 0x073d4947, 0x502ed2ce, + 0x580c5294, 0x22d14165, 0x1140fb3d, 0x69d17691, 0x098f3aec, 0xe7a5c0e4, 0x01bbc03a, 0xb37ab4c5, 0x5fd055c3, + 0x912a687e, 0x8d1264f7, 0xa001e0bb, 0x0ddbebd5, 0x2752cc48, 0x4e79241e, 0x419c789b, 0x98d3a6a3, 0x615fb5f8, + 0xa40e9d4b, 0x034abe84, 0xad63cb54, 0xcf8871f1, 0xf13a8ea9, 0x6ce6efab, 0xc708b4fd, 0x8097b2b6, 0xa21bbd0a, + 0x7dab5cf9, 0xf4a5ffbb, 0xfca1d1a2, 0x36a0059d, 0x44351b1f, 0x2cbf6fd0, 0xf3fdabd8, 0xbb519f72, 0xa79c33d2, + 0x2be376c4, 0xc5718612, 0xdb5709fc, 0x27d316d6, 0xb59930b5, 0xffe91be3, 0x8b320da1, 0xffd61c2b, 0x8f681ea8, + 0x60c0d5c7, 0x815822e5, 0xda231477, 0x35615524, 0xffb107c8, 0x4032f0af, 0x3544df64, 0x883dc7c0, 0xb32b4f86, + 0xbb166846, 0x318c7c49, 0x5faebd93, 0x11e9a838, 0xce01a081, 0xec891165, 0x05fa77d4, 0x2988fc31, 0xdd6850e6, + 0x26a1d1d5, 0xb3a4a94e, 0x80429fab, 0x5d7f7cc6, 0x098bca3d, 0xb0a56843, 0x22705ef7, 0xa10a9482, 0xa8e8c6fe, + 0xbcd0f593, 0x897a4d15, 0xca2885b0, 0x56aa1f50, 0xd0784015, 0x5daf6154, 0x4675d6ee, 0x3b9f14ea, 0xc1d77e72, + 0x203c544b, 0xe8b99679, 0xbc138e2e, 0x64a49784, 0xf0aaa328, 0x1e4828a9, 0x1092f757, 0x10bf00f3, 0x68bc3d19, + 0x9098a3de, 0x713f4f2f, 0x7589d961, 0x12e1a419, 0xeb733b20, 0xc7fe2995, 0x087e8c35, 0x6e73cf5a, 0xfdf540f2, + 0x84ff2bf7, 0x0bb8524c, 0x1ed4c10e, 0x4f62aa58, 0x7d36ddea, 0x011661f8, 0xc4b4e2ef, 0xb51b5d31, 0x2652cdb1, + 0xb28953ca, 0xd368cca2, 0x236e0c72, 0xe5de495a, 0x1ca859c5, 0x0c372509, 0xd280f600, 0x6da1e768, 0x865527b3, + 0xe2bb2201, 0x017e86f1, 0x759014ed, 0xfe5494d3, 0xa5c64eb7, 0x17d516df, 0xde574ad8, 0xb231f3ba, 0xd13cc46a, + 0xc328d3a5, 0x450cf846, 0x0bf556a6, 0x890bed06, 0xd7fe0db5, 0xcd54bdf2, 0x98b4bbf1, 0x962d2b7a, 0xa63d48aa, + 0xa476f036, 0x83eaf33e, 0xfe4b33c6, 0x5b50777d, 0x9c4df571, 0xf7eb5d6e, 0x3900a4d8, 0x3c604c42, 0x22f4e1a8, + 0x9ca51298, 0x28bdee99, 0xde6f6c5b, 0x21b1b446, 0xa26b0ea4, 0x70c9a5ea, 0x7efe7c96, 0xed957c40, 0xbd149258, + 0x8a40654b, 0xef2a520e, 0x1a2391e1, 0x6fe678d2, 0xdfa3dcd8, 0x22965bb5, 0x39c8a664, 0x341be7ef, 0x656af9e4, + 0x2db20b67, 0x6bac1a74, 0x9566450b, 0x450e2fd5, 0x8d5226a4, 0x127c46e3, 0xf9973e69, 0x3b60d746, 0x48a06e73, + 0xf5a53ed6, 0xd755d130, 0x69c57421, 0x5dca4bbd, 0x3b79ae5a, 0xb0c94859, 0xcc220ba7, 0xa7c96bb0, 0x23201c25, + 0x446a8702, 0xe9ff2948, 0x98d82d6e, 0x5214e7c4, 0xf5451f25, 0xa3413eeb, 0x27c9caa1, 0x9952915e, 0xd37fca96, + 0xa3cafa73, 0x3b5a08a5, 0x5ba97aed, 0x974a6759, 0xe6ac882a, 0xbc18b25d, 0xa34f8f98, 0xeb1e425c, 0x876e5293, + 0x2f8abc39, 0x508d9fbc, 0xfc978386, 0xd5f2aa3f, 0x46e3ebae, 0x4ce9905d, 0x596d2475, 0x66294ddc, 0xe9131183, + 0x5002729d, 0xeee1030b, 0x3d58d51e, 0xa4893cb6, 0xb66f7f8d, 0xdc5ea3f8, 0x8e9629b1, 0x843c66d8, 0xf3cd41b5, + 0x1446afc7, 0x354c1d57, 0x2e9c4d74, 0x473e879d, 0x49a384d7, 0xcd675136, 0xba7ddef3, 0x24fd8092, 0x81034731, + 0x35dba726, 0x542f3312, 0xe31e0dd5, 0x6e4423fd, 0xa69a6e28, 0x58dd74cf, 0x1b600049, 0x2a0a3340, 0x36ea2b9b, + 0xb308b21b, 0x9ad67afb, 0x87ebc7d4, 0x2ff42b4b, 0xdc6dfd6b, 0x44ea4585, 0xb8a4458b, 0xf791e504, 0xac035cb8, + 0x00add930, 0x1dddf524, 0xd8ddfdb2, 0x3b12d4e9, 0x24f1bf3c, 0xe1d7c097, 0x5915e112, 0x77eddb8b, 0x2202f343, + 0x2889af50, 0x34be4cf9, 0xe0e99118, 0xcee2273f, 0x2f6d09bd, 0x5ba8f71f, 0x12005f2b, 0x915b24f9, 0x0384c3fe, + 0x782b1f3f, 0x630b0be1, 0x20245511, 0x85204915, 0xe5d7b36b, 0x8a982b9d, 0xcd9299fd, 0x7ab98fe8, 0x9d8409aa, + 0x8489dd3a, 0xeb267fdb, 0x55c408fc, 0xdf3c6ba9, 0xd7c85bcc, 0x5c786bed, 0x52331fa2, 0x5494ccf6, 0x2056391d, + 0x475e32d8, 0xfca11c5c, 0x37c45d1f, 0xc04a9ecd, 0xdbd25a6e, 0xea8511eb, 0x6361d61b, 0xec585292, 0x05d2bf99, + 0x60d3919b, 0x46b8108c, 0xd6c4943c, 0xaefd9e36, 0xf234fb49, 0x8714ba37, 0x64c34245, 0x8935b58d, 0x44100546, + 0x5a3aff4f, 0x1b2ff6ae, 0xc2db1bc7, 0x62b14f73, 0x219bee05, 0x7cb86857, 0x9743753f, 0x432fa74b, 0x60b35ccb, + 0x89e1acf2, 0x1a799c64, 0x8cd0dff3, 0x2694af25, 0xf6ef716e, 0x0806707b, 0xcd4755bb, 0x0812ca7c, 0xb4ba3ef1, + 0xc38f1db1, 0xd9196f06, 0x592d7cf4, 0x5aae5961, 0xde6c1f28, 0x97dc5df5, 0x5e74e4f3, 0x6238016d, 0x7385e4e7, + 0x0ecaf286, 0xa23c98da, 0xc274d7e1, 0xca4c4118, 0xdee44ed0, 0xdd65a0f7, 0x156e0a95, 0xf0d5f71b, 0x5f8810a3, + 0x1ef0dd66, 0x92b47966, 0x2a0cbd4d, 0x115c95c7, 0x73b4f77d, 0x6f109464, 0x4743d841, 0x06580b21, 0xf62a2565, + 0xd7f70a32, 0x9b43aca5, 0x55f74a72, 0x463abe64, 0x0843b4a3, 0x0b700a92, 0x8a8e55e9, 0xcaa7ffaf, 0x478b9b7b, + 0x925e1544, 0x70d1b369, 0x315d4c19, 0xe79993d5, 0x5f4e2f87, 0x87f0d38a, 0x38e75a59, 0x68cdc95e, 0xb528ac00, + 0x1d38dafb, 0x628d25e0, 0x3881172b, 0x7c5ebdb5, 0x69fb948c, 0x284f1f66, 0xb80373a6, 0x840da486, 0x5b5159a3, + 0x26ae38c0, 0x3c8c89b4, 0xd0f7cc34, 0xaa7a499e, 0xfaf6ac4e, 0xf2255b32, 0x5cc334f1, 0x4e908390, 0x7d69828e, + 0xfece1943, 0x4ad65a56, 0xf8cfb119, 0x0d2d7ec8, 0x01369bf0, 0x11a02660, 0xb22b92b7, 0xc1d7a0b1, 0x2fb8c0d3, + 0x86f26440, 0xfddde68a, 0x406d69fc, 0x97aa6aa6, 0xc9dec001, 0xc8bb0e7b, 0xdc3ef53e, 0x8b195912, 0xf43254d0, + 0x2f0790ac, 0x72f38c01, 0xb9f26837, 0x8a72cd73, 0xf13bbfcc, 0x8c8be6a8, 0xc3d6aff4, 0x2ea47ad1, 0x61e423a0, + 0xbdba9383, 0xbad92293, 0xe01e5fd8, 0xf6e5ea8b, 0x4363633a, 0xf0ca76a9, 0x4c22a282, 0xdaac861f, 0x4c555d1b, + 0xc1c21a72, 0x7bbbfbfb, 0x06ffdd28, 0xf64028e7, 0x33a5d8cd, 0xf87a37fb, 0x02a530c5, 0x0897e3f4, 0x8a3871ca, + 0x58705214, 0x071e0139, 0xad3d03f3, 0xbaef3dc9, 0xa9ed55f0, 0x66cdef91, 0x9ee82719, 0x3cdc8e9f, 0x256d1f62, + 0x090bd294, 0xf6a99888, 0x6faf95fb, 0x89d67ea7, 0xa31e9d05, 0xf276cab8, 0x799691a2, 0x26052dca, 0xafaa0ed9, + 0xa415451f, 0xc8f8b949, 0x0df12c40, 0x0519bb2d, 0xd307e441, 0xdbebf071, 0xa5644fce, 0x0fa86145, 0xcf567978, + 0xa375abac, 0xab432419, 0x7594ca2f, 0xb466a291, 0xd047808f, 0xf460ca26, 0x5c2b353e, 0x326b826f, 0x95adf998, + 0x5bdc6ee6, 0x160e2822, 0xfd58717b, 0x0ce3b1e4, 0xa447afc2, 0x462d19d5, 0x64187281, 0x043acb9e, 0x2df5c49a, + 0x7259a6b0, 0x74d56162, 0x09c3409e, 0xb1bb4c5b, 0x57ab6888, 0x80b3e784, 0x66b02774, 0x67fe40c7, 0x948d5e10, + 0x3aa93072, 0xe5f84193, 0x89bfb36d, 0x4f41e5df, 0xa736d685, 0x65a3e8f7, 0xcffd27a2, 0x709227a2, 0x5be9d28b, + 0xc05e55ee, 0xca0ee85c, 0xb6cbf960, 0x611bc34f, 0x2e30fc42, 0x5a9dfdcd, 0xdc3bd710, 0x301d0dac, 0xb1a965b6, + 0x0655c672, 0x012947ae, 0xf116e966, 0x79e95005, 0x9cb70f14, 0x5dd36b06, 0x46c50326, 0x321fcb7a, 0xcdf2e38a, + 0xb87dbcc4, 0xfe0789b4, 0xfe3ae6c7, 0x03f8c3d3, 0x33f089ff, 0x5306367d, 0x8a9ae5f7, 0xc010c295, 0xaa37e6f6, + 0x1487d181, 0x40950cab, 0x4940f680, 0x5ad4de7a, 0x27bfcda2, 0x42642d07, 0x1a7bc00e, 0xbea95e80, 0xcd7bde00, + 0xca17e598, 0x63a9e683, 0x66116c2a, 0x2a12966f, 0x3361097e, 0x58ae47cc, 0x13e8a8c0, 0x09d60959, 0xa08ca785, + 0x1f521d60, 0xfa417c4a, 0x6bcdb1c6, 0x41263c2a, 0x1e546326, 0x0082d46f, 0x4c3e4b57, 0x6d8ba5d0, 0x61c6cb6d, + 0xabb48c4a, 0xab90c1b0, 0x136ce3b3, 0x3f7ccb78, 0xc45ea918, 0x3161bc27, 0x3c77fe21, 0xd41dc1ee, 0x6ad9e550, + 0x9502fb0b, 0x90267f01, 0x153a7960, 0x464b0783, 0x5943d95d, 0xcc9acc28, 0xf18f07a6, 0xa9881078, 0x8ddaed07, + 0xca7effda, 0xccd92d06, 0x141dd10b, 0x968b7c5f, 0xeadbbc45, 0xf6a25333, 0xd35a5fe0, 0x0b991213, 0xd54f3977, + 0x8ebe68cd, 0xe9edd677, 0xc240a7ad, 0xbbd01f41, 0xe9a185f0, 0x7eb0c742, 0xc56f55fb, 0x15d713ab, 0x2826e587, + 0xbd53d226, 0x8be69ffb, 0xdf81ad5c, 0xb4cc392b, 0xcd35b755, 0xa4d179c1, 0x159feeb9, 0xaa1be84c, 0xc68bf3e9, + 0x835e4cbe, 0x444d79a8, 0x76c6cf47, 0xe6b163f2, 0x95bb39d5, 0x150f5e37, 0xe32bf956, 0x0e1bef00, 0xe795d3d5, + 0x0cb49b6a, 0xd8eeb50e, 0xc00ecbdf, 0xaf1af923, 0xb8fa49b6, 0x09fb4eee, 0xf0c7338d, 0x6202c6fb, 0x19276da2, + 0x703a0afa, 0xbbea9726, 0xf94a4344, 0x35a0191a, 0xea7d5198, 0xbdb48d62, 0xc87f7b6e, 0x4b3500ab, 0x0335604e, + 0xcf453dfb, 0xdbcd9b27, 0xc5c7739f, 0x0adffb78, 0x23b0e48f, 0xad20b2ee, 0xfe7e399c, 0xf734858f, 0x21f71f16, + 0x55e4e234, 0x3f0dac92, 0x66e2c227, 0xe1b3e4fc, 0x9d50c930, 0x9b9ff668, 0xc4b9f360, 0xa8d08bac, 0x4807aedf, + 0xf4d0c129, 0xa9dd0b3f, 0x210ab786, 0xcb291023, 0x64fcaa0e, 0xb06561a0, 0x2e00812f, 0x60e5226f, 0x51ed9666, + 0x3d8e865e, 0x2bd68410, 0x367884eb, 0xbd024f85, 0x28ffbb10, 0x749c19e2, 0x03c18756, 0x9fc35ad4, 0xa289135a, + 0x78abed85, 0x8e5e7e16, 0xf1ce714b, 0x83a34157, 0x8982465e, 0x9007c277, 0x94b61ba6, 0xad15cd57, 0x25d8dd0a, + 0xa121ab10, 0x57e581a0, 0x34f8ac16, 0xeb6cf800, 0xdeabea9a, 0x19ccd7f2, 0x624a1371, 0x25a2f338, 0x2ea60f75, + 0xb8adbd7a, 0x79b8aa84, 0xe9267ec6, 0xbef060be, 0xa4a685d0, 0xad3d5091, 0xa349d5ed, 0xba1646f7, 0xe6885d88, + 0xf91de8f4, 0x9b8ecc7a, 0xa8edf479, 0xadaf0719, 0x2a36b178, 0xe11af8f3, 0x718722b4, 0x1f9980e4, 0x4bf0e97c, + 0x6272acce, 0xcf40df0f, 0x61608239, 0xba678dc0, 0x84242ad7, 0xdfd66142, 0xaa8aab05, 0x12f58bbc, 0x784770d3, + 0xf1346187, 0xa19e8207, 0xb968e5b6, 0xec8c5f94, 0xbb496fc9, 0xf04894b3, 0x72a72055, 0x2be60ced, 0xe34db9c8, + 0xe3051d9c, 0x7fbf5b1c, 0xba144ed4, 0x1f1aad71, 0xaf61be6c, 0xcaeb52e0, 0xc58d5338, 0x59e5b21c, 0x4e3bc8d5, + 0x22e7fa71, 0x143e86d0, 0x0b5e7615, 0xad62837d, 0x68ef1b41, 0xa9b9d1a4, 0xf02009ae, 0xe973f658, 0x9d988c4c, + 0xa564aa03, 0xf67ef18f, 0x2a2543fa, 0x370ec46f, 0x009633b6, 0xba123415, 0xb3e7fa66, 0x51d42063, 0xcb76c238, + 0x53f9b3be, 0x8ee4bebf, 0x795a2e18, 0x0dfd2078, 0x54b891b6, 0x035d9fc5, 0x92a77f58, 0x795cf7a1, 0xedae22b1, + 0xda367339, 0xa6d99f92, 0x6a4e93fa, 0x7bc2a4ec, 0xcae61227, 0x6c44c121, 0xa80e9d54, 0x85a170ba, 0x2a736471, + 0xf50d5b1f, 0x32a89004, 0x4bbbee78, 0xa6548891, 0x5bf5e8ea, 0x0dc94d76, 0x503e69f0, 0x36f0f850, 0x16a71191, + 0x4d2fbdb8, 0xde15dc30, 0x6366af31, 0xb314b953, 0x00f663ac, 0x9fc9255f, 0x397fdce2, 0x43caa313, 0xc28b8c39, + 0xec7bde43, 0x66e3000c, 0xa8075789, 0xa8709fad, 0x218da9a8, 0x7efd413a, 0x10498337, 0xaef2ee55, 0x6c930bbc, + 0xa5dd1cbc, 0x02ea89be, 0x20ed8565, 0x2b32b2b5, 0xa02143a4, 0xc7ac79b3, 0xd6c8ecf0, 0x38060d08, 0xb4b2cfdc, + 0xae903562, 0x5558dc56, 0x031f1f4f, 0x6e1d78e1, 0x9a56394c, 0x6ef7e537, 0x29d4e7f0, 0x9f03eacc, 0xdd6ff5b9, + 0x34ed73d1, 0x598332c1, 0xbe32ebc2, 0xf333ffc3, 0x32ef0c3f, 0xf8f8fe61, 0xba26a735, 0xcf785eee, 0xbde66c30, + 0x0e04054c, 0xc6073bb7, 0x5dfa15c4, 0xcf3c6ec2, 0x4f809e7d, 0xb48b1ad2, 0x7dcf4bd4, 0x1e417796, 0x61fef601, + 0xc315b98e, 0x45ad1d13, 0x6fc74894, 0xc92db856, 0x9dbcd206, 0xc94557e2, 0xfd0029ef, 0xef939d91, 0xe74b64bb, + 0xa3bd7e4d, 0xcbec5bcc, 0x6b8e5f8a, 0xc1fb8615, 0xe30dd742, 0xe8873f04, 0xf796d180, 0x2aa14533, 0x02f0e4dd, + 0x4092f1ff, 0x46b17c79, 0xe0b76567, 0x5d0feb0b, 0x1979ecac, 0x9f5659d6, 0x2e5c63b9, 0xccaeab62, 0xf0064686, + 0xa22a9a79, 0x6a43aef6, 0xb65df672, 0xa38cd22f, 0x8733cdc9, 0x83b14336, 0x9282ab9b, 0xeb7441b2, 0x9aecf1ef, + 0x838d5070, 0x09779413, 0x069c8067, 0xca073079, 0x43739b7f, 0xe6f3ae9f, 0x2da4708b, 0xfcc77c76, 0x88c0a04e, + 0xe81f2e56, 0xfbd4f534, 0x9ccdbd7e, 0xc6fe44ac, 0xea4f0cff, 0x6af29f8e, 0x5605825e, 0x5caf4e6e, 0x557c72c8, + 0xfbf26f73, 0x9aa4d69d, 0xf8503f6c, 0x3793fe6e, 0x95672d7a, 0xed83681e, 0x3d412ef5, 0xec2bdf2e, 0x89cc5b43, + 0x021f36b7, 0x976f5d53, 0x75124526, 0x8f25fbaa, 0xbeef0188, 0x488b4911, 0x2a987471, 0xc521283d, 0x9bba3b2e, + 0x40222083, 0x47504ab0, 0x06ed441e, 0xcc1be67b, 0xeb40c560, 0x47d3314f, 0x4162fcd8, 0x6bca0b90, 0x3633c963, + 0xb9bedbd5, 0x6dba19de, 0x176bd884, 0x75819130, 0x546a1522, 0x3947f6b5, 0xab70a97e, 0x259048a3, 0xdc5264b2, + 0xcc90a2c0, 0x25acfce8, 0xb8e0d447, 0x309b28ee, 0x4b5e0fcf, 0x6e64c0e6, 0x45981148, 0xa94de257, 0xb2f91e70, + 0x29d2e408, 0x94437714, 0xc9756b98, 0xee41e540, 0x5ca50188, 0xcb3d923b, 0xbf6a703e, 0x8160c698, 0x38c3ef08, + 0x23338b35, 0x1b2006a2, 0x5d18e757, 0x1023044e, 0x47b1c107, 0x48bb1ddb, 0x19874f03, 0xd436846f, 0x66ca3cf6, + 0xa592c7a2, 0xc2334420, 0x0ded1216, 0xfd04569e, 0x3f554681, 0xfb722f7b, 0x6100b12f, 0xdc7b1b2c, 0x322bf18c, + 0x80e46919, 0xbf30a8df, 0x9cfef529, 0x13993ea2, 0x0882591b, 0x1a15b671, 0x7bf2b84c, 0xd54f9d3c, 0xf6848439, + 0x4c3a198c, 0xe39d9dc1, 0x58cce97a, 0x61980483, 0xb499fd9c, 0x5b86175c, 0x786e687f, 0x30b73c80, 0x306687c1, + 0xae3de9a7, 0x50e8434d, 0x92c2d047, 0x0a336188, 0x8ff48d00, 0x1f881a0b, 0x81ce8d2b, 0x658f31bd, 0xbb144c2c, + 0xaea61e2c, 0x4bd31a1d, 0x5c7c2c9a, 0x6084d3df, 0x6232fcb5, 0x69f6b354, 0xdaf69678, 0x6fe4de92, 0x63b08819, + 0xb57d6eb5, 0x6a66e2bc, 0xf2c17fc8, 0x0049a064, 0xd7282906, 0x747bdf7d, 0x9eec496d, 0xa2e22e8d, 0x55ae4b6a, + 0xe3ceafc8, 0xa4ab8f08, 0x7c23301e, 0x370d7f2a, 0x8eba54c3, 0xc6e112d2, 0xcf2f3e6a, 0xc583a00e, 0x243e795d, + 0x2033fe30, 0xd2d5ca4e, 0xf1cb5996, 0x20032959, 0xdc95ef44, 0xf4d65402, 0x07782b63, 0x25f5bf2e, 0xf5a69ece, + 0x39a9f358, 0x224732aa, 0xe54fa98a, 0x6b9262b7, 0xeb2afdac, 0x1556533a, 0x8894eaff, 0x85e66f03, 0x94bda8d6, + 0xdbc1cd32, 0x43b7bfc0, 0xe63bd4a2, 0x008af0e1, 0x73fb1d30, 0xa28d0ca6, 0x45cb6eae, 0x818c52ef, 0x89741953, + 0x6e3ec5fc, 0xb04292c9, 0xee4dcbb4, 0x4cdb1208, 0xb64d8b33, 0xb25d3ee6, 0xaf246f15, 0x7d017169, 0xd3d33795, + 0x04e76afe, 0x0715f703, 0x5f766f4e, 0xbe09969e, 0xa0582067, 0xc18bcf31, 0xb90ceb5f, 0xb4786b31, 0x519d8252, + 0x53448869, 0xaee8794d, 0xaf5ba907, 0xabf0b96f, 0x07f5d2e1, 0x8d7f99a0, 0xcc210946, 0xfb69b7c3, 0x87b80632, + 0xad243b27, 0x456f653f, 0xc45b6163, 0xb36a2c1f, 0x634ee23b, 0xc73e4c37, 0x533ee5d8, 0xa8bb5bca, 0xde15f863, + 0xf9344628, 0x6ede8408, 0x62bbdcce, 0x71fc03df, 0xc25b2a70, 0xee1bbcf0, 0x7752db6f, 0xd72cc93d, 0xd1f241c4, + 0x7debdba2, 0xaf4c21bb, 0x7f87f9ef, 0xd7e18c08, 0x05d2d5a7, 0xe529f203, 0xebd0e6b9, 0x02c0ad67, 0x7fd92ceb, + 0x43aa7f53, 0x19c88a7a, 0x8b32098a, 0x0db009d1, 0x7f39030d, 0x60638a86, 0x8f6eec35, 0x89867613, 0x1a029b1a, + 0x6eafad95, 0xc9b0dd04, 0x5d231d00, 0xcb72dce8, 0x81dfe3c2, 0xc15e27de, 0x445b545a, 0xa40ce3d1, 0xb2516f1a, + 0x41b32f8a, 0xfc149b44, 0x46664e9e, 0x73259e1e, 0xc07e7b5d, 0xa1af66c5, 0xeb5031bf, 0xa9e25b27, 0x71c2191e, + 0x816ddb20, 0x4b25bf7b, 0x58a73be3, 0xaabe0356, 0x344b5a28, 0x157dbb46, 0x4a99c510, 0xecc557bd, 0xef3f085a, + 0xda54c52c, 0xff397218, 0x1e6135d6, 0x92f2962c, 0xa3baa124, 0x54ed4acd, 0x8371cb45, 0xf8b528b7, 0x0c461137, + 0x282bf1b6, 0xbc71545c, 0x9cfbb6d6, 0xeb2f4cf5, 0x28c44c8e, 0x2505d132, 0x13ea52f9, 0x8f636b51, 0xb83cf38d, + 0xf400dbf7, 0xe2063615, 0x54ac75f8, 0xe9b97f72, 0x84afc0fb, 0x37e9d038, 0xd3f1d0ec, 0x023f9229, 0xe9a47385, + 0xe0d7471e, 0xdd424018, 0x37ede853, 0x80711edc, 0xa6a783e9, 0xb654e568, 0x92ce8e53, 0x72cc8687, 0xfce7c1fd, + 0xf15d171f, 0x61d14b65, 0x349e4490, 0x843bfdab, 0xc47ad84f, 0x15f32d9d, 0x98a62171, 0x00a23a75, 0xe9ba4de0, + 0x489e84ff, 0x84f3fd78, 0xf2196d1a, 0x93d6f606, 0x521a52f9, 0xf7e52846, 0xeb849d23, 0xfd906f8a, 0xd6e7e1c3, + 0x943043c3, 0x5e5da163, 0x4477f967, 0x95451171, 0xc89fbe19, 0xba820588, 0x56372e8a, 0x1925cae0, 0xf9c982ff, + 0xd88a4047, 0xfcbc8d21, 0xffb10287, 0xc0225369, 0xb20856ac, 0xd14757ad, 0x13cb7a7c, 0x096a4d2f, 0xbc1ff14f, + 0x6500290b, 0xfc3ae44a, 0x9fb256fc, 0x642598e9, 0xff8ee3c8, 0x56ea3647, 0x47a220e8, 0x8c152f25, 0x333922d7, + 0x5754b17e, 0xb8da2104, 0xae8a2044, 0x502cc10d, 0x54cfc477, 0x0e12917f, 0xc7a94ee1, 0xe342a341, 0xe9a7068e, + 0xefc2a151, 0x0f8f8c85, 0x733a2626, 0xce152262, 0x1c67a0da, 0x420585e3, 0x9aeab5be, 0xd12df2d5, 0x96fd5eee, + 0x9c8be1df, 0xfbf1f296, 0x2043c8c2, 0x7e6053e2, 0x900901eb, 0xfc2d3bc9, 0x2314a632, 0x9f7f4d5d, 0x8d9528a4, + 0x6f4d0e25, 0xe48e4c78, 0x246d2c80, 0xa9f42856, 0x0fc2453f, 0x19bb0b26, 0x7307e10d, 0x61c90640, 0x5dee0b43, + 0x646244d9, 0xf9b13c3a, 0x51b25179, 0xfc2ea237, 0x1717208a, 0x4587b615, 0x50ed0eed, 0x47f07da4, 0x9accfa9e, + 0x8ae0de03, 0x97726846, 0xedb3ab18, 0xe6a17e0c, 0xb7c8860d, 0x3540fd34, 0x9113f055, 0x62f32694, 0x9aaaef19, + 0x699c63d8, 0x6f92c4d8, 0x1cc6c425, 0x6555828f, 0x4a17ef2d, 0x0aeb9c00, 0x26e2c8dd, 0x9efba388, 0xb0fd86b5, + 0x50451538, 0x44963138, 0xa02638b3, 0xe747745e, 0xb951de1a, 0x5f23086e, 0x6b000b9b, 0x206a60c3, 0xcb4c3540, + 0xc88ba00b, 0x0c9a3154, 0x20bfa1af, 0x451cd54a, 0xddbb0989, 0x46700e72, 0xde0e0353, 0x2d888fe8, 0xf771e657, + 0xd4d94675, 0x5c81059b, 0xc45aa0d9, 0x00a45f01, 0x46385f28, 0x0670937e, 0xe125fd35, 0xb4daa06e, 0xc42c2791, + 0x3053a249, 0x717f9fd7, 0xab6eac10, 0xb0eb1450, 0x4131790a, 0xa914c1b5, 0xc9f697ef, 0x6e00852d, 0x6236fa1b, + 0x848ab99e, 0xfb9f5ca4, 0x1f577bde, 0x33b40c14, 0xc132a218, 0xc82b96a5, 0x020fb671, 0xf3605d05, 0x85ab0592, + 0x5818000a, 0x06bc982d, 0x415df9f2, 0x614f04e6, 0x6442fa2a, 0x3b03bcba, 0x66e3a38f, 0x4c5c70b2, 0xf512aa0a, + 0xb1a4afc5, 0xaec845e1, 0xc9c8b999, 0x4b7abfb9, 0x136c8631, 0x8247635f, 0xf68c21be, 0xe59936ee, 0x5d04d244, + 0x9ed85699, 0x42ad41eb, 0x0910eb97, 0xccf682b7, 0xec589dee, 0x610e6005, 0xd96b339c, 0x5ad1adf0, 0x2a6c5b07, + 0x921aa785, 0xf27e47d1, 0x63e7e008, 0x65037311, 0x17a38a32, 0xdcfa7662, 0x404716fb, 0xbb8ab155, 0x62ede1dd, + 0x0cf4ee85, 0xe59a73de, 0x73e7f93d, 0x0392384c, 0x6b494259, 0x9c470f03, 0xa355f5cf, 0x7778fb8a, 0xa95758a0, + 0x40e8ae97, 0xce5b18b5, 0x4b020d62, 0x999691c0, 0x8a3c3e14, 0x3dcee990, 0xf64cb35a, 0x8e8948ee, 0x22d9ff59, + 0x4833826b, 0xa3055452, 0x1a047704, 0xca5a62e8, 0x12694ade, 0x5ca305d2, 0x02984325, 0x7c6447e3, 0x949ec78d, + 0xb1228fd7, 0x04d527f5, 0x54ee17f1, 0xaa461c66, 0x009db83a, 0x72e3cd95, 0xc2cb939f, 0xd22c0c91, 0x834a3d63, + 0x7c546f97, 0xdcc09454, 0x30767985, 0x0625c23f, 0x6f2e4681, 0x8294c3d6, 0x415f5b5a, 0xcb7148aa, 0x2cedbc93, + 0x2da99bbd, 0x0b16a6b0, 0x45b824af, 0xd8ef99c0, 0xd9ead9f5, 0x790157de, 0x4a81ec52, 0x683021fe, 0x9f85a705, + 0x9bd03ca6, 0x10eee031, 0xd52feb89, 0xb9a7cdae, 0x1d7380cb, 0x58833166, 0xfd6f89ae, 0xebc344e5, 0x615567df, + 0x4c5dea04, 0x931c1d5f, 0x08ef5799, 0xa2f9070e, 0x5fd568cc, 0xc8600a57, 0x8e0e7421, 0x5ea6c1bb, 0x60ec5fc3, + 0x7917a3ee, 0x86158b8c, 0x338fa916, 0xc33445fe, 0x4df96170, 0x5bbb05b4, 0x9ae0baa7, 0x87b43088, 0x8bac0a8b, + 0x7570d241, 0x37ecad9d, 0x68bbcfee, 0x4a4d1ac8, 0xfc58b290, 0xf93a6a13, 0x8f1bc151, 0x7feec3ec, 0x95e56693, + 0x90bc438b, 0xa3e93140, 0x577bb446, 0x670e480d, 0x5842d1ea, 0xfd9d17bf, 0x879cc227, 0xa2f7d038, 0x81c243c1, + 0x6c4155ca, 0xfd6c5832, 0x9cbf8664, 0xeaa63130, 0x522991ec, 0xe5437caf, 0x951954ba, 0x379652a0, 0x7e6a2bf5, + 0x33fc98d5, 0xca38dbaf, 0xc75dfb7a, 0x5a621c69, 0x178f5118, 0x8dedf7be, 0x022148c7, 0x19c6ad14, 0x0d5b5b5a, + 0x875da6f8, 0x7b3ecbc9, 0xb9718de6, 0xc94f1cb2, 0x00d1b2c9, 0x4515ceb0, 0xfa2661a9, 0xec80803f, 0x3c3598b0, + 0x2b3bd937, 0xb0e0dfa0, 0xfa47707f, 0xc77d7e49, 0xbbd21da1, 0x35ac5d85, 0x60298b67, 0x0583dec1, 0x40351245, + 0xaa875f10, 0x0d36d2b3, 0x028b8310, 0xbc57a08c, 0x994850a5, 0x3b00a38c, 0x64cc8daf, 0xb23359f6, 0x9aa9f125, + 0x358d901d, 0x9bce9b08, 0x39a003ca, 0x53e74155, 0x62918df8, 0xa560cdf0, 0x854ad474, 0x1bbf5f8c, 0xcfa28802, + 0xb51c462c, 0x19b23bfd, 0xe859f147, 0xd4d9af43, 0xfcca706b, 0xa875829c, 0x08858dda, 0x865f3563, 0xffe80780, + 0x37bd4acd, 0xa66c57ad, 0x2076ac70, 0xe13357f6, 0x29a3cd13, 0x27ebf143, 0xce451339, 0xe4e26984, 0x01f446dc, + 0xa0191765, 0xd28fde5f, 0x99bc5739, 0x8c112d84, 0xdc3e9481, 0xec378738, 0x01e68f9e, 0x90354c62, 0xbb473efc, + 0xaa745e18, 0xb5c9b921, 0x23353826, 0x3d40dbb9, 0xdfcf6fe1, 0x2170180b, 0x5f139563, 0xe9d52673, 0xda61c3a2, + 0xa1e94768, 0x3559cf00, 0xf0bf2108, 0x9f24d35c, 0xeb7f18de, 0x44c10aff, 0x6779346a, 0x660d98c6, 0xf14c83ec, + 0xb2b2943f, 0xaf7e1f18, 0x5ab22701, 0x641e5e5e, 0x537f95b3, 0x3dcb1299, 0xf3038cae, 0x7a074b34, 0x1a384628, + 0x0d5aa45f, 0x15dde593, 0x2166bb7e, 0x7cbf4ebc, 0x78509c84, 0xee8fdd05, 0x40762a18, 0x3d40243f, 0x7b7fc9f9, + 0xf4ee4171, 0x464deb51, 0x69d63a8e, 0xce584165, 0x76825969, 0x6fc4e18c, 0xb0ec9915, 0x826d1093, 0xf8aab0b0, + 0x42f34e18, 0xac8e7b8a, 0xf35bb7c8, 0xf2e463c1, 0x817685ca, 0x070d4946, 0x60a8fae2, 0x9416ab95, 0x4d7d082d, + 0x9345c8da, 0x7bda4cff, 0x1e3194f1, 0x78d46826, 0xa33f691d, 0x7a2da017, 0x4c914bd4, 0x5555cf1e, 0x8bf77013, + 0x54e69ea9, 0x70c50aa3, 0x5cfda069, 0xf85af9d0, 0xf7b8fde9, 0xe972a4c7, 0x64614f43, 0x6c8245d4, 0x48084ff6, + 0x94f3129b, 0x9cbb113f, 0x045b2286, 0x5cf2b73c, 0xf88f2569, 0x538473bd, 0x3ac8e12f, 0x24936045, 0xf75bdbd2, + 0x1307cd8f, 0xcc793eee, 0xedb054bd, 0x4a65e991, 0x18d382e7, 0x8b36d3c7, 0xb45db969, 0xd2f343c1, 0x8215d129, + 0x8385d7ed, 0xbcd14f14, 0x7b3879d2, 0x92fe1566, 0x897747a1, 0x6085d4cd, 0xe3598826, 0x2d31205f, 0xd3aef421, + 0xc56586eb, 0x98a1ccac, 0x3ef17203, 0x01ddb679, 0x4e839270, 0xd124a9d1, 0xaa451d43, 0x041b9d15, 0x5b27290d, + 0xda54f269, 0xa1215a30, 0x1e2ca6b8, 0xa0bcba1e, 0xd6cfae41, 0xbb526df9, 0x0590d0bf, 0x0e9c14c7, 0x8ff15919, + 0xeda09cfd, 0xc645150b, 0x3e3f8e43, 0xe3f0b89b, 0x6c57cf44, 0xe4281387, 0x89b5fb3a, 0x78c5eca5, 0x3e756d6b, + 0x9ccdc906, 0xf09d3503, 0x3a902e30, 0xfecf7f17, 0x810f5f8c, 0x81894162, 0xeaff1513, 0x47501d39, 0x0dfafef3, + 0x73ccb853, 0x4b2609ad, 0x9c00bdcd, 0xfcd6d32b, 0x705f0174, 0x2da77868, 0xfd4b8ba4, 0x36659a30, 0x5c3edc4b, + 0xbd1a706e, 0x75786f7c, 0x4568e448, 0xe870c0ba, 0x049797a9, 0x572adbc5, 0x71f9bae4, 0x5f7d8888, 0xba5b0cf7, + 0x719c75a9, 0x88a86ae0, 0x1e0cdad8, 0x1075f856, 0x340328fe, 0xd10c6286, 0xc22acf28, 0x3a58d4cb, 0xff2fbe58, + 0xd820ea44, 0x5af2f307, 0x7294cbf2, 0xb52edd43, 0x7da251e7, 0x38f3d802, 0x6e34eb1b, 0xc65377b1, 0x34ee27ac, + 0xa4bb06d9, 0xef438954, 0xa7428e9c, 0x4800dc51, 0x1d3d0605, 0x396ef197, 0x86f13b6a, 0xd57a9eb2, 0xd727eaea, + 0x6eda8601, 0xcca21fd2, 0x660652ac, 0x07b1a5c6, 0xc3ae179e, 0x404fa456, 0x60765372, 0xcd4965ae, 0xe1e6fcc9, + 0x7f98ab2a, 0xdd4c4742, 0xd09e6c09, 0x3ded6300, 0xff455ab1, 0x4b58277c, 0x5ce9dfe4, 0x535a9e33, 0x8f253d15, + 0xeeb8a6f8, 0xc5dc29ea, 0x1b68f28a, 0x37b357d9, 0x7897997c, 0xb451e203, 0xa79bd9da, 0xd974ca3c, 0xaa869f00, + 0xe8a0c351, 0xde210a86, 0xc68c28b2, 0x5f2ddf6a, 0x72034330, 0x076d6e75, 0x9793d4a7, 0x8a128e96, 0xdefbc085, + 0x99b4c7a0, 0x4570683c, 0xa568ef52, 0x65d2abd7, 0x4a20c0e4, 0xd5a96138, 0x3434fe57, 0x282995ea, 0x9f20c59a, + 0x1e365e5b, 0x68072d75, 0xf1105eb7, 0xe694ed27, 0x6439d803, 0x7a1ac331, 0x78772b64, 0x858f5e2b, 0xf09920ad, + 0x76a6e0b0, 0xe80c3afe, 0x184f3c3f, 0xc41a154f, 0x1a0a3c3b, 0x2131af83, 0xd5466964, 0xec94b5a4, 0xf22e78ac, + 0xaef145a1, 0x8f8cf760, 0x444c347d, 0xf1fd69be, 0xb989b8ef, 0x03dc32c4, 0xe41fd81c, 0x38e1e3e1, 0x97f83711, + 0xb45c0ca4, 0x094772f8, 0xf4d3b1f4, 0x7f084c1f, 0x17bf7791, 0xabe32e98, 0xaa150a89, 0x9a823f4c, 0x4d1e0692, + 0xe4fd4ebd, 0xd81c75e0, 0xcf381d95, 0x49cd133a, 0x03c3ac26, 0x1fa288f1, 0xad48b7c0, 0x0880b51e, 0x5363d6ac, + 0x5e7c5fc1, 0x2a0097ff, 0xb65034be, 0x74808654, 0x8ae0ead4, 0x9167de05, 0x911a2404, 0xde0de9ad, 0x0971ac3e, + 0x71483a95, 0x4e0dc036, 0x1be58bb8, 0xeb22fe7d, 0xcf3d57cf, 0xe3966204, 0xeecb4016, 0xb6f14bf7, 0xefdb5515, + 0x8baf99e0, 0x9de06020, 0x607e6f68, 0xf4b277b4, 0x0833d46b, 0x88e79b1f, 0xc8d1f373, 0x69f03063, 0x6e5a571a, + 0x3e1da60a, 0x270914bd, 0x09fa089e, 0xbb8c05c2, 0xc52edd76, 0x883490bf, 0x0475467d, 0x89108ded, 0xdf8821cb, + 0x8d590551, 0xff1f928e, 0xe4591464, 0xea3dd6e6, 0x70aeac73, 0x0d74a6cd, 0x9aecf7e5, 0xac9641af, 0x06a26727, + 0xbcb15829, 0x54bc23cb, 0x1426fd9f, 0x10589a76, 0x50707634, 0xf80d5a23, 0xc0f9b3ac, 0x0eed7ea6, 0xc123a490, + 0x8a846955, 0xa414ff02, 0x29cfbbba, 0xb8745ad7, 0x3a0e72a2, 0xe805792e, 0xb9510de7, 0x55a5b9ee, 0x0be51417, + 0x857a72de, 0x6d9b21e2, 0xff4a003c, 0xb628a4f7, 0x79bd7238, 0xfa208609, 0xfa6035e5, 0x77121829, 0x4ab4813c, + 0x43042928, 0xaf8f74c2, 0x503aa714, 0x6a0ff8d1, 0x23e981a5, 0xf1244f6e, 0xeca002aa, 0x25683b1f, 0xa9808af2, + 0x5866a9f1, 0x4c969900, 0xd3f4c899, 0x43b52c47, 0x550aaaa8, 0x363981a3, 0x330ec33d, 0x53274d1a, 0xfd5c9aa8, + 0xb5544487, 0xf5050380, 0xd649a5da, 0xf9cacf92, 0x65298573, 0xf61c5cac, 0xde3bf4c8, 0xe1069767, 0x9cb84688, + 0x1c024592, 0x806e9fd8, 0x6a28499d, 0x0e2a2c93, 0x108d6f82, 0xde53482b, 0x505454c7, 0x41b9158e, 0x3d97a373, + 0x83dab190, 0xcd9ebedc, 0xe6856bce, 0xc645c484, 0x7a4c2416, 0x9b7a91df, 0xa4a24206, 0x665a0060, 0xd144ece8, + 0x54db63af, 0x3f9b251c, 0x88c41058, 0x71cea04f, 0x62e72549, 0x97e22546, 0x61754184, 0xcba70b96, 0xf43e3a93, + 0xe49a09b6, 0x8f0decfb, 0xcbb53463, 0x6f59466f, 0xa7f6829c, 0x3487b402, 0x173f01ed, 0x3a2768bd, 0x7e0195e2, + 0xb34bcb76, 0x858cbda7, 0x539ca251, 0xd49fe508, 0x88dfe134, 0xc1e65ce7, 0xad5f93ee, 0x8b1b6f7d, 0x811cbffe, + 0x8f3ff4dc, 0x84ac76fb, 0x90229577, 0x63f26b20, 0x126dbbcb, 0xe2dadfa8, 0xd54c0b96, 0x0c0568b5, 0x439583ed, + 0x40a31cc8, 0x653943e0, 0xe191e58d, 0xb24bdd7b, 0x466cb127, 0x28c457ff, 0x7cc182b4, 0x69dd26a3, 0x8a4c8530, + 0xaae5256d, 0xb957a69f, 0xfb587d6c, 0x240a5cd5, 0xfc445895, 0x822b4771, 0x879aceea, 0x27071e4c, 0xc0565efc, + 0x95b76f6d, 0xcc5dc3da, 0xa6dbaa28, 0x2c99a4ae, 0xe87af896, 0xa5e2cd2e, 0xf4b06ca8, 0xa9fe1d80, 0x4f9a85fb, + 0x6c7d64c9, 0x6ccca902, 0x7646a753, 0x004a1122, 0x10eaf884, 0xe778aa12, 0x5cd43238, 0x793c34eb, 0x3826c4e0, + 0x09f14270, 0xc2c9b67b, 0x45daa4b4, 0xd30632e2, 0x5b0ea243, 0xcef77d5e, 0xc8558795, 0xcde88705, 0xba94746f, + 0x383a7535, 0x97392b90, 0x5188e6f8, 0x3482229b, 0x23fdc933, 0x5b56569a, 0x4adc4c2e, 0xb52f5c33, 0x2b0c2bca, + 0xc1a4e2bf, 0x16b9bd8d, 0xeff239b5, 0xfe88de7e, 0xb0cf5bca, 0x02790e0d, 0x64ea75e2, 0x45b5c0af, 0xf5aa3e3e, + 0xe863491b, 0xd46fb8a5, 0x15d0c2d4, 0xc50a2937, 0x346fe8d1, 0x42f702a5, 0x39d45d49, 0xdb0e4878, 0x14664ce9, + 0x1e70a98b, 0xe34d2033, 0x1890b531, 0xa01e4eff, 0x7989a696, 0x7a897a53, 0xf58cfd4f, 0x70e891cd, 0x0e6ba5ae, + 0x2a0a8b33, 0xdc084b65, 0x83158647, 0x97d0d226, 0x78e91c45, 0xd95dcf7a, 0x8ff5779e, 0xbc57d290, 0x9612ca90, + 0xb6fe5860, 0xfd451c6d, 0xd7c16970, 0xedef05f3, 0x5504bc75, 0xa54a425f, 0x29da829d, 0xe89d07fc, 0xa7ff1010, + 0xa64de249, 0xc46545f4, 0xf69d1609, 0x7461529a, 0x12ece680, 0x8e70b139, 0xcb427c2c, 0xa16e6e68, 0x3554c6d3, + 0x8a637c72, 0xdca9480f, 0xc836352f, 0x4bdf55e3, 0x0f2e1fa1, 0x492ca271, 0x6c31a06d, 0xf89bbfd9, 0xed160043, + 0x09378e91, 0x20e24ddd, 0xad4fcbcb, 0x2299dc5e, 0x3279eaba, 0x73dbcbd1, 0xf43099a2, 0xfd6a326c, 0x24c57b14, + 0xbd0473a1, 0xf0fd0a94, 0x8e2ce815, 0x50702b1e, 0x7ca3090d, 0x98d99f60, 0xbbe9be40, 0xfd719e41, 0x753898fe, + 0x75595607, 0xc040a19a, 0xe33c9252, 0x79a1fd6d, 0xee23ae70, 0xad7c55ab, 0x5012bcec, 0xd2849aa0, 0xd8ddf166, + 0x07a8e72d, 0x7645265d, 0x8bc02134, 0xe104767a, 0x6b381185, 0x5c81c5ee, 0x00fe349e, 0x62cae177, 0x4dc3b66a, + 0xbfb89561, 0x8294dd17, 0x2fe585c8, 0x8731fb3b, 0x17ab2391, 0xbb578959, 0x0ca6cba5, 0x3996a862, 0x784fedf4, + 0x481f7211, 0x16f8bf59, 0x3503b957, 0x5dcdc96c, 0xc74ea7c5, 0x98b7220b, 0xf64c443d, 0x2aec3264, 0x203af3b7, + 0x8b3c52fc, 0x3d66876c, 0x81c7ee80, 0xc46f038f, 0x6982075e, 0xe581cfbc, 0x2e8fafcd, 0xd32123f0, 0xb17a24de, + 0xcd5b20eb, 0xa00a3f68, 0x587e7f4d, 0x11c7698d, 0x4919baef, 0x6e981f6b, 0x35370e9a, 0x5f2dfb65, 0xd7c1bea7, + 0x1fce4b31, 0xe9973d1b, 0xe55bf6f7, 0x34921ce4, 0x8a5eb773, 0x5b65b5da, 0xc79778b4, 0xdf3fee72, 0x41794add, + 0x856be6cc, 0x20c0b87f, 0xe5b10f2f, 0x44061e13, 0xc1669893, 0x2893c0e6, 0xfc9e140f, 0x210a3770, 0xc9570985, + 0x4949453d, 0x641660dd, 0xf98d7bc5, 0x44aaf53b, 0x6b38a44d, 0xae3e5d09, 0xe25a385d, 0xb6322ebd, 0xd0f5648b, + 0xba07c6b9, 0xa921c2ff, 0x64b1534c, 0x5c1b193d, 0x10fb551a, 0xa9beba06, 0x9f926214, 0xf2254a5d, 0xca25c9b3, + 0xc0f13ba6, 0x0cd3ad3a, 0x6c1a4d4c, 0x53faa6c9, 0x93a98fef, 0xf2efe0ea, 0x8129e09c, 0x5747f888, 0x172ae5ea, + 0xb91372f5, 0x5d3d9d5e, 0xaafd53a4, 0x3a8a6a10, 0x4ac3b18e, 0xfe4f7f8c, 0x8e34d110, 0x55e39069, 0x1da4ef20, + 0x73cbcff4, 0x6a89f298, 0x6f851a5a, 0x6d73fdcd, 0x7491ba32, 0xb12ca9f2, 0x55b23fad, 0xf947b356, 0x12bdf926, + 0xada900b9, 0x00a3cee0, 0x494cbde9, 0x48af473e, 0xe4e89a4f, 0x275d7c8f, 0x960caa15, 0x5b56f927, 0xf50389a7, + 0x06a0e141, 0x5c2e27c0, 0x0244557e, 0x33efe294, 0x2860b066, 0x37eaf9ab, 0xdfc96694, 0x46067853, 0x099bb0a5, + 0x8a81cf76, 0x33a094f1, 0x0b7fba8d, 0xa1c2acf4, 0xb4583573, 0xbe17300b, 0x918409bc, 0x5e8484bb, 0x1bc90e06, + 0x539946fc, 0xf9b6e3b6, 0x1f5d2248, 0x0f75dd99, 0x3866195e, 0x07293f9f, 0x7bbba560, 0x147e6407, 0x02e5d083, + 0x47667333, 0x96dc8912, 0x9084597e, 0x5d9f3c32, 0xe0d9d92d, 0xb7c55c39, 0xd0bba37b, 0xb889bf55, 0x0349ce4a, + 0x78d07f62, 0x28494ac6, 0xea7d4b78, 0x95156c3c, 0x16455d4c, 0x07586e32, 0x7f20347a, 0x1c404ba6, 0x8c15f859, + 0x97c463f2, 0x6f5522d6, 0x50a1e2f0, 0x6913dbf9, 0xc9d8d1f1, 0x96b692bd, 0xebfd949b, 0x7e862347, 0x9766e3aa, + 0xf33d8642, 0x7c88048a, 0x1562fbc6, 0x3e5ba73b, 0xde498504, 0x88878e22, 0x3c89c266, 0xc3dac673, 0xc395476a, + 0x608f1033, 0x10f304e3, 0xbb0fc348, 0xd603537e, 0x1fc19bf9, 0xe6677dbb, 0x6ba28389, 0x6c4d17b3, 0x5351fe8a, + 0x72b62406, 0x79eaeea7, 0xdbf3c0a9, 0x356c9144, 0x424c8b61, 0x64dc7408, 0xdddfcde6, 0xa40c81d0, 0x7d1d67f6, + 0xc6070803, 0xa9c285d6, 0x86d524be, 0x74693598, 0xa3d3fc5b, 0x02df6121, 0xcb966ed3, 0x09807d3b, 0x57709ab8, + 0x95962671, 0x1617ebc5, 0x4fe58430, 0xe65ae6e4, 0xec0b4db9, 0xdffa41e3, 0x5ec6de93, 0xcd41a8c4, 0xe8054dc9, + 0x1e9bce44, 0xbed442bd, 0x72b965fb, 0xa56796ab, 0xe3f74a3e, 0xeda58e17, 0xd6f154c3, 0x0a0ed989, 0x261a2719, + 0xfddaface, 0x8b2c1282, 0x4978d7f9, 0x07cc7edb, 0x29f52e5d, 0x3dbcb5e1, 0x1c51a2a0, 0xbd1f8554, 0x2d6cc30a, + 0xb53db1ac, 0x5739d965, 0x4f6ebd82, 0xa0b3a5d4, 0xc4d678d9, 0x32286236, 0xda3d8356, 0xd61ad227, 0x052d531a, + 0xa26c1b51, 0x89cb635d, 0xee282d01, 0x42980e5a, 0xd6169216, 0x404cca45, 0xe930ada9, 0x5213e4cc, 0x2ec9b432, + 0x759cb622, 0xf1b09c3d, 0xafa00a4a, 0xe0ad2ad7, 0xddad1b36, 0x17881a92, 0x87a1afa8, 0x9c60952d, 0x7dab2b41, + 0x3d8ab729, 0xd6269825, 0x10dd44bd, 0x0d632723, 0xbe4983e1, 0xb52b4093, 0x03026d5a, 0x0af3b49e, 0x1265d0a0, + 0xea7c6a4f, 0x3ccf8c5c, 0x03209733, 0xa266c460, 0xe85e7b0c, 0x99029d24, 0xc0bc282c, 0x5fe8411a, 0xa14275fe, + 0xe85bcdd0, 0x44f04b2a, 0x53298133, 0x6e5bbdc6, 0x40a903d6, 0xcde3ac72, 0xd4f6c306, 0x7128034b, 0x765cb60e, + 0xd9f0f54a, 0x46893db0, 0x5a4903e5, 0x19a312bb, 0x0adb1943, 0xb3c97704, 0x105fdf17, 0x954139fa, 0x7b547de9, + 0xdcbeb6e6, 0xe5769137, 0xb5723b9e, 0xf6439ab6, 0x99200e35, 0x0237dc63, 0x61b1b647, 0xff3704bf, 0x33b5c3da, + 0x50a2f4ac, 0x64bc0ad7, 0x685d6e23, 0xaed5fe84, 0x2a06fa68, 0xd2df68be, 0xe11277a6, 0x4bbce0a5, 0xe5696040, + 0xe9361618, 0xf66b4232, 0xd6155b20, 0x55800dc8, 0x844265d0, 0x23e1cd06, 0x958a3f43, 0xfa1e5028, 0xec24cf8b, + 0xe06caffa, 0x712689f1, 0x26ddb15b, 0xc82916d1, 0x458d52b8, 0xb943bf2c, 0x9d0895f0, 0x64d54935, 0x3ba2a281, + 0x1f590dfd, 0x0d8e3872, 0x4e75fd8b, 0x821ff67f, 0xf8aa43bb, 0x7b112cb5, 0x3190ac0f, 0x7a9dec32, 0xf5cb13a9, + 0xcf39d81f, 0x7e37d5ec, 0x0c179eaa, 0x7ef14f4c, 0x4350603d, 0x7b4db591, 0x87bb1647, 0xffaa280a, 0xe8ee7be6, + 0xbad7d708, 0x2cb595eb, 0x9699a656, 0x1397c277, 0x47368722, 0xdc1e1be5, 0x57ea2823, 0x14cbdec1, 0xfce737a0, + 0xb78dec80, 0xea2749ac, 0x8d3bdf2d, 0x359591cc, 0x8e99b45b, 0xf968c391, 0xf5edc6d9, 0xe1b0d210, 0xb3edbd8f, + 0x3cc03b58, 0xfc534bcb, 0x8d28c330, 0x35b47db8, 0xca43dc58, 0xe89129cf, 0x5341bced, 0xcd0530b7, 0x49cd66df, + 0x620ec143, 0x5163357c, 0x623f4552, 0xcf54aa5d, 0xa1188530, 0xac813e96, 0x12b38c13, 0x13b708aa, 0x64d11b64, + 0xc2f3cd59, 0x09ac7a81, 0xe9853826, 0xfe668776, 0x0fb75ebd, 0x913acaf9, 0x677cd265, 0xc644d272, 0x62c5e9ff, + 0xedf23706, 0x50e4752c, 0x690d8fc0, 0x0826ccb9, 0x6fe10f05, 0x4ba3f0fe, 0x2219889f, 0x9c573708, 0x1625873b, + 0x92bc52da, 0xeb95f4ed, 0xe5fc30f6, 0x46fa4a93, 0x1d5b0e82, 0x628f123d, 0x95c7e0b1, 0xaac94ce4, 0xcdc1cecf, + 0x655e7487, 0x69952e47, 0xef527d01, 0xe41afffb, 0x5e86d4f7, 0xceca6c85, 0x756a884f, 0x9ee29ef2, 0xc6b2f8bb, + 0x0789ab18, 0x1a670e49, 0x236d451f, 0xb89480ac, 0x15cfbb99, 0x05575b23, 0x0fd47ccf, 0x821589df, 0x383743ee, + 0x595cabf4, 0xa3909f77, 0x66e00ed9, 0x867fe094, 0x9ee7ab87, 0xdbcaca62, 0xfac6cd5b, 0x9f3f3873, 0xf53b407e, + 0xd1369790, 0x5b10a855, 0x92446cd4, 0xcce958e3, 0x77c2f828, 0x759bb76a, 0x7d6ac706, 0x45fb36b2, 0x510b4bbd, + 0x532654ea, 0x5913f332, 0x66e9fa32, 0x2a1f6226, 0x150dd23c, 0x1bcf144d, 0x63be579c, 0x78307c0e, 0x401d1e15, + 0x6f901770, 0xad1106b4, 0x3b1f236c, 0x74718dc3, 0xc7878830, 0x64e60d31, 0x1c0f583e, 0xfbaf073d, 0x089375b9, + 0x140379b9, 0x3d6829e5, 0x54b96a6d, 0xec0f719d, 0xd032e4bf, 0x9e152232, 0x4f80890d, 0xd43850cc, 0xc6f01d44, + 0xed794de3, 0xc09611e6, 0xe9e695d4, 0xc8d7c945, 0xf15ac1e8, 0x9ac097d9, 0xb1ef158a, 0xd55a9990, 0xe7662ea6, + 0x7ef72700, 0x73abeddb, 0x80f17f50, 0x5a89b71c, 0x477be172, 0xca83bdf7, 0xd32ddd8d, 0xfff0d5e1, 0x50bc951a, + 0xe0a40d41, 0x044da623, 0x00711671, 0x86b0d81a, 0x3bfef673, 0xb65ca656, 0x452cc588, 0x2d8241b1, 0xce6fdceb, + 0xb3f7ce5c, 0x64f90837, 0x0fb156d8, 0xb5fda935, 0xdf3a666e, 0x7c5e9f47, 0x8780adc1, 0x2e76abef, 0xc2633ed7, + 0xb8c05a14, 0xe58162b6, 0x89fe2eee, 0x219348b0, 0x3a692199, 0x81325384, 0x16a40eca, 0xaa332296, 0xde0dd792, + 0x2179c72d, 0x906584a0, 0x2222216e, 0xb2968d4c, 0x57e25733, 0x18f4cfa3, 0x00033088, 0x43d07a27, 0x3bdd495e, + 0x74171d2b, 0x263db0e8, 0xc239db4e, 0x2a4ade16, 0x144a6662, 0xf6e13e0f, 0x6036bc2a, 0xfcc683f9, 0x7ece6261, + 0x61be6f62, 0x8ea3e051, 0xde3970d7, 0xd3f6421f, 0x223d16e3, 0xcc612707, 0xd63eb784, 0xa2153600, 0x3f04fa60, + 0x61053f21, 0xcc73ee40, 0xf8eda625, 0x95744ce1, 0xc6a8ad17, 0x91e2e54f, 0xd03d6547, 0xf73343f7, 0x94fe1666, + 0xcadb73f7, 0xeb8514c4, 0x88df6107, 0x2766b437, 0x748db9cc, 0x5135598a, 0xeb2b2c1c, 0xbfc63df4, 0x0ac5c67a, + 0x912a0d8f, 0x06bf6554, 0x138164ab, 0xd5021c92, 0x3c6a2cf6, 0x89849cb6, 0xae034323, 0x35b017e1, 0x16907ca3, + 0xa120c5fd, 0xa91ed2c7, 0x700495e2, 0x6625e458, 0x700aa9f2, 0x32934788, 0x24d533d1, 0xb1b402a9, 0x086a760c, + 0x22342cbd, 0x26d7e79f, 0x7751656c, 0x8630b7f3, 0x4b884867, 0x656ae75b, 0xd7810008, 0xe00e7ec6, 0x7aafd708, + 0x589945f8, 0xee3254cf, 0x52b68752, 0xf5266906, 0xaf90a469, 0x21ac1dc7, 0x5977c96b, 0xf3ea3a3f, 0xd81a64aa, + 0x8c40b24a, 0x3202893a, 0x21bea961, 0x74196dca, 0x042a2973, 0x2b73655e, 0x0c55415c, 0xde4fb1ef, 0x8e38804a, + 0xd6f7da37, 0x0542ae5c, 0xe0e73147, 0x97ec9f2d, 0x4e6df4ad, 0x4a1813fd, 0x0dde4f38, 0x5deb8203, 0x69809544, + 0x4ba4fab5, 0x6879faa4, 0x86744158, 0x29fc1340, 0xabbdfa35, 0x44c3a96d, 0x2ee1874c, 0xba878353, 0x6eb5a976, + 0xc5163e98, 0xbf8d1126, 0x90fe053a, 0xeb2f7ddd, 0x850357eb, 0xfe4d435e, 0x52310c1f, 0xa421817c, 0x8ff33011, + 0x9ef97907, 0xd71cb7b5, 0xbade434a, 0x27980687, 0xf945ad2d, 0x1742e6b2, 0x51bc578d, 0x41800c2d, 0x464082ac, + 0x845f05e2, 0xc1847052, 0x906c41a5, 0x248c5b3f, 0x804c9ffb, 0xd69fab19, 0x3d8ff32e, 0x152b64d0, 0xab2470d7, + 0x69dda279, 0x123ca790, 0x6f6f14e4, 0xa078e3b7, 0x23a1b128, 0x9568be57, 0xac80eb20, 0x3210f85d, 0x6a1cd51b, + 0x23a8d449, 0x7422fba9, 0x7f4a1198, 0x258b4ce1, 0xdf6c3357, 0x75bb4c8f, 0xaf741fd0, 0xe230588f, 0x8c741ce8, + 0x64cf6c8d, 0xb5684f47, 0x0259e5c0, 0x146a157b, 0xa9d939a3, 0xad791e60, 0xe63c54a7, 0xf4c22784, 0xcb3b862f, + 0xe804e819, 0xbb22028b, 0x7e5b69ae, 0x7d1209de, 0x31d794d8, 0x20a3ab7c, 0x58a18dc4, 0x9dd30211, 0x6f6930a5, + 0x2913f186, 0x03750e03, 0x94b6542c, 0xbd4d9cba, 0x2711a481, 0xca2e991f, 0x3d90021a, 0xfadb91b3, 0xdf2ad25f, + 0x370a219b, 0x027aac0f, 0x6ad88941, 0x3f6f1bfb, 0x31a10cd3, 0xac33f95d, 0x06a15c8c, 0x6617675c, 0x174c80bd, + 0xe60abea4, 0x7e4539e8, 0xfeb7fd5e, 0x77edea40, 0x60430131, 0xc1b662c3, 0xca8101c4, 0x94adbe97, 0x2600b093, + 0x01236b8f, 0xdde9cec9, 0xa4e2ca0e, 0xa6309ffc, 0x13f6dc49, 0x34fcf89d, 0x1ca0d185, 0x4025f71c, 0x45cc5243, + 0xf17e6a84, 0x3265087d, 0x3e917f20, 0x20898460, 0x4c822689, 0x47a9a408, 0xb7831771, 0x1f2de167, 0x6e041a74, + 0xdabc6e0b, 0x78521cdc, 0x31c9ec05, 0xcf6624d3, 0xc68a86a2, 0x22a33a60, 0x3e9f3851, 0x2f211aad, 0xa6d637be, + 0x34e5ed55, 0x11ef3d4d, 0x054aa150, 0x881698a8, 0x3404aec3, 0xf8f6fa0d, 0xcae57d2e, 0xed797673, 0xee685b0d, + 0x4205feea, 0xcfc4d8d1, 0x0684bdc2, 0xd97a1a01, 0xdf4ba7b0, 0xc6932786, 0x12f70b09, 0x3355bd20, 0xf5130bb5, + 0x51a17e98, 0xa14e9ecb, 0x444c6531, 0x892e12b4, 0x454abe03, 0x92f110d1, 0x40bfc41f, 0xa57835d2, 0x1b874f86, + 0x62bf3121, 0x9c9a9e45, 0x8c1f49b0, 0x3c4abff4, 0x65c8b533, 0x30914472, 0x1fac8133, 0xfd8b1348, 0x0d17d702, + 0xe91bffa4, 0x360bf43b, 0xc0360d3f, 0x4e4ae0c8, 0xdb71bffb, 0x12d5a412, 0x294d1c3f, 0x9d991685, 0xecf15443, + 0x74128039, 0xce1763fd, 0x3ed42a9c, 0x318cc12d, 0x347513bc, 0xaa5fc9db, 0x2ec59bb9, 0x50c14cdd, 0x1ff79230, + 0x2ab72fba, 0x8865dbc8, 0x211f77bd, 0xdbae8822, 0x887319f4, 0x85478361, 0x7187b395, 0xfd98332a, 0x80652f7e, + 0xcfb94b41, 0xdf576882, 0x1ba08cdb, 0x6625d48b, 0x68c99dd8, 0x9c0e36b6, 0x86a8819c, 0xd0e93897, 0xac5981af, + 0x48ede489, 0x7c12a436, 0x9a4e6ad2, 0x112e9e4f, 0x5a251395, 0x1a28004a, 0xdc2e4ba8, 0xcb33ae9f, 0x313b8b25, + 0x7e95a04c, 0xd4c592b4, 0x382056d4, 0x834dae39, 0x5a79fb8b, 0x622b6058, 0x83c44cf5, 0xd3d49dd8, 0xf970034d, + 0xeea051ee, 0xbc1a7f02, 0xf289389c, 0x08f6fbb3, 0x94cbdee2, 0x67a32514, 0xf4e80743, 0xf588f5c0, 0x174944ba, + 0x37b593ff, 0x97a893d4, 0x69dc1f6c, 0x7646bad9, 0x4b3ed810, 0x46f54c40, 0x8432bc27, 0x994e9178, 0x4aee5040, + 0xa75988b1, 0x427a37b0, 0xbe81936b, 0xcb0f5c8f, 0xd46e5eff, 0x26d1f733, 0xb815f6bf, 0x3e4458e1, 0xc1f6998b, + 0x76234b9f, 0xfd074df3, 0x5aab1a42, 0xf39c2ff0, 0x3b02aff3, 0x5ab12be5, 0x0d787f6e, 0x9a6a79ce, 0xdc10c6f3, + 0x826c6112, 0xf1e5d3dc, 0x2aeb648d, 0x8a7a76b1, 0xf70d4b97, 0xa1a44f6c, 0xc83f225e, 0xe878c919, 0x15d096c7, + 0x5d4e242d, 0x7ce3ef0e, 0x0707aab2, 0x7f91af8f, 0x280ddc30, 0x99c687a9, 0x1a25a962, 0x58d8f316, 0x67e8b87b, + 0xa054c2c5, 0x50f57949, 0xd27c17bc, 0xd67fbd81, 0x7c1853b2, 0x8701d65b, 0x68a1c6d1, 0xf322fddf, 0xd14f7547, + 0x01562902, 0x9988143d, 0xa153b2bb, 0x1c031e19, 0x95d35238, 0x9214a606, 0xb7a4f70a, 0x004afc08, 0xeab15f88, + 0xd1218576, 0x581d22b4, 0xad54a44e, 0x0ea2d42a, 0x6ee8e7c6, 0xa895d694, 0xd4e68a83, 0x5a7032eb, 0x39372274, + 0x575d23f5, 0x86c5e98e, 0x3a397a61, 0xd0696236, 0x9ab6a11b, 0xa2c08b04, 0x9cc87951, 0x01eb0e61, 0x10ea19dc, + 0xf34d49a1, 0x2010bdb3, 0xca66e0f5, 0xfe2b2281, 0x00a290c7, 0x2abf1140, 0x55920d46, 0xb1893861, 0x4aad7cf9, + 0xd10629a3, 0xe6ad00d6, 0x954c2190, 0x5c584210, 0x436064b2, 0xc82a7633, 0x621ac334, 0x3bc6dc40, 0xd710fa5b, + 0x608be52b, 0xfd7fc12d, 0x0a503cf4, 0x6184f606, 0x03e8c709, 0x64a2ac4b, 0x84e7d3aa, 0x3dbba778, 0x4e79f906, + 0x4e3e81b3, 0x514e9bd4, 0x5aae88f0, 0x6a1c45c4, 0x1e995dcd, 0xcff53801, 0x4d90c2d8, 0x5bb62b8f, 0xf156c0fb, + 0xeb0758b6, 0x7d05bc13, 0x95058f0b, 0x0eb4e6cb, 0x6c7cbefd, 0x6b89051d, 0x46a9e104, 0xa921e626, 0x43df9f73, + 0xc2bd3a0f, 0x8894426e, 0xd3a970f7, 0x208a994c, 0xc04bd202, 0x42f5979b, 0x021c7e4d, 0xae650494, 0x0f01cc10, + 0xd1a4f067, 0xe9e0fb4f, 0xac0399bf, 0xac378efd, 0x679db59e, 0xc68f3029, 0x734448b1, 0x9318d6c5, 0xbe5d26d6, + 0xe7c52e30, 0x559e3663, 0x43998e12, 0x40f605f3, 0x05ab31ac, 0x3f5c6058, 0x49632ee9, 0xb591e45a, 0xaa408367, + 0x52f1b93b, 0xb2cdb5c9, 0xa6d58e7e, 0x6f1b0da2, 0x636109b3, 0x0d01a22f, 0xb83ed438, 0x7b4f3e3e, 0x17e91e3f, + 0xda7d7b55, 0x2a232d8b, 0xe9f7e8dd, 0xc5cb1816, 0x6946cd6e, 0xe2b8c90b, 0xba8bb93d, 0x99e7c719, 0xa1b0073e, + 0xbaf2de09, 0xf28c5ffc, 0x848abf7a, 0xf5e9a145, 0xc6e56ce1, 0x578ec8a8, 0x8625c2e0, 0x9bcfbd37, 0x88b7adfb, + 0xbe9d6967, 0x52441649, 0xdf64670a, 0xd453ae11, 0xffb0c249, 0x5f7d163b, 0x27a4c000, 0x3cf1cdd0, 0x24707eea, + 0x28efcf03, 0x319a296d, 0x835cc953, 0xa0824da2, 0x9a8a4810, 0xa996e46e, 0x35ffbc54, 0x59210b26, 0xca25ac72, + 0x7054ed8d, 0xf34a8d30, 0x087985bf, 0x09816137, 0x9f8be985, 0x691713ee, 0x25ae9e49, 0xf8369d65, 0xf2923d09, + 0x913d58ef, 0xd27e60c4, 0x71408ee6, 0x012e6472, 0x47418ac6, 0x8488866f, 0xdc1770a8, 0x70fbde65, 0x0afdc39a, + 0xfe26b0b1, 0xa127628c, 0x442fdb26, 0x498c1bc7, 0x39b86435, 0xfe22adf8, 0xe13d3bf6, 0x7d84627b, 0x86f4ff49, + 0x78bd8d8b, 0x8febcd44, 0xe3fbb9a0, 0xa7f5332a, 0xe0ba16f1, 0x2b549c14, 0x30288e40, 0x597f0196, 0x23636b91, + 0x20ad194d, 0x47cf75cd, 0x21c7f087, 0xa0df583b, 0x491df3da, 0x0f8726c6, 0x95acdafa, 0x5999d33a, 0xe7173e81, + 0xdf7ee6ff, 0x6a7f9a98, 0x1a79914f, 0x354bf98c, 0x6da48c52, 0x3c3db736, 0x42ebb685, 0x16caa1ff, 0x33109535, + 0x49463391, 0x65af5a9a, 0x09279656, 0x7408fd6c, 0x906a6871, 0xb8ac81d4, 0xb32da5d7, 0x80b1569f, 0x202f5933, + 0xc6c9d916, 0x99875c34, 0x29f46628, 0x54eb6f26, 0x9321e5cc, 0x7be13264, 0x62d2beca, 0xabe06449, 0xdf4e33f4, + 0x79a71110, 0x8e6b03b4, 0xbaa99392, 0x3d097a0f, 0x8b328edc, 0x510e003c, 0x3b70980e, 0xb27f060c, 0x81f6fff9, + 0x874c73ed, 0xdba786a6, 0xe0765621, 0x92adc2a5, 0xcc8c9d6c, 0xdc484e76, 0x216e6f0b, 0xaeb0ff15, 0x034df9c1, + 0x598fcf2b, 0x1b7cee4c, 0xd2a02784, 0x756f1900, 0x4efc009e, 0xad3bb64b, 0xf3c201cf, 0x30269349, 0xae9c0230, + 0xb25992f0, 0x205885e3, 0x66e87702, 0xfe155d8c, 0x29aa747f, 0x9bc42eb6, 0x6d1d966f, 0x38334b06, 0xec93040b, + 0xaf4da4f1, 0x0854fab3, 0x02247c44, 0x8448f4f2, 0x387a9f27, 0x98e6d69a, 0x1be3fd82, 0x992f9248, 0x38861ba0, + 0xdf9fc680, 0xecadf5af, 0x4cf90efd, 0x45b50398, 0xba32f909, 0xa55d631e, 0xcaeb1f43, 0x7c1ac53c, 0x1df579da, + 0x6c19102b, 0xe3c03cad, 0x6f7f85e2, 0x7dfe3c42, 0x18fa7410, 0xc9a27e75, 0x13e6a01d, 0x241846e0, 0x1a6afbd4, + 0xa71c9fcb, 0x8c96139b, 0x155676a6, 0x73deb3e4, 0x5374e848, 0x849cfa2c, 0x6c45f274, 0x30c82a94, 0xd0d915e8, + 0xba0da402, 0xd841e14d, 0x789222b9, 0xab3aadb2, 0xf3c6568d, 0x13cdfcab, 0x4565b28c, 0x9587d482, 0x46dedc4b, + 0xdcaa9679, 0xd0cb5ee0, 0x5f9c05fe, 0x72018fe3, 0x79418646, 0x155692a9, 0xf5dc7e7e, 0x17c37d69, 0x89040cf6, + 0x4fa5f9cf, 0x8714dcdd, 0x7668dc66, 0x24a0a2e3, 0x21833332, 0xc810d54f, 0xcf5bcb20, 0xfdf3fdb2, 0x7164d0d2, + 0x9114d09a, 0xf036b84f, 0x00dcd2a0, 0xec29deb1, 0x796167d6, 0x043175ea, 0x75a61085, 0xbcf1a3bf, 0x81fd1749, + 0xe4c77cf7, 0xaf1bff2b, 0xff554eb9, 0xba0ccb68, 0x0a10f3e1, 0x11ce468d, 0x3dce4b86, 0xf780c4f2, 0xf427471b, + 0x430c7f66, 0x7eeb5a4d, 0xebf61b83, 0x05207f35, 0xaed1aa2b, 0x994c89f7, 0xe04437d2, 0xb11b3e37, 0x279a117f, + 0xd43b686a, 0xb1225c98, 0x0ba217bc, 0x0d9b86b7, 0x36954c15, 0x1ebd6584, 0x1466e496, 0xd35926e8, 0xfe27e231, + 0x62c9b328, 0x0cb642c3, 0x37a77d61, 0x8187bf07, 0x76d01eea, 0xe4325424, 0xd87400a6, 0xf824402e, 0x4866b44b, + 0x5aa264eb, 0x5694e1ae, 0x3f365cd9, 0x8ed9db15, 0x18d5842d, 0xe3026fbe, 0x1b67cd00, 0xb1d392d4, 0x563c1a33, + 0xd4224bc1, 0x8ff6ea4b, 0x87a26b26, 0xc97384ca, 0x354fcf02, 0xd47393f1, 0x75e089bb, 0x8aedf37b, 0x8ac3064c, + 0x9c404bad, 0xda1ad673, 0x55dd96e1, 0xbec79967, 0x021d1ef3, 0x7b8d6ac1, 0x76b3197b, 0x45e02069, 0xd4d4333a, + 0x03ef4315, 0xe81453b3, 0xea9fd009, 0xdf4d30a8, 0xbc0691a5, 0x16130965, 0xc949f1c4, 0x447c14eb, 0x05cd8b73, + 0xfdd9700b, 0x09e83f5b, 0x69a258a5, 0xc048c5bb, 0x742e2d1a, 0x092509f7, 0x1ae4f270, 0xa3f086ea, 0x845b7d95, + 0x14361835, 0x22226adb, 0x5e5d39ca, 0x03a643ae, 0xdfd6a740, 0x5405af02, 0x0572dc84, 0x62da8bfd, 0x226d9011, + 0xf1e59bfa, 0x152e49d2, 0xf9570363, 0x1c332f2a, 0xfd01583c, 0xfade8d35, 0x1ffc4973, 0x19b2f846, 0x8e08d93c, + 0xf8026e42, 0x56de91d6, 0x5743ad55, 0x84f248c1, 0x49aefe8a, 0x5df50df6, 0xfca859fd, 0xe46faef7, 0xaac7dbc2, + 0x22f8af49, 0xe8e06440, 0xf317b976, 0x19d1a041, 0x34e77e92, 0xbe980a45, 0x9d6a884f, 0x8a547ceb, 0xfb3a0e89, + 0x07a9f72d, 0xe72f6f45, 0x35fdfd4d, 0x6f9f874f, 0xd23440b4, 0x92ed25a1, 0x7cd8ae17, 0x4a68f1c6, 0x12744cfd, + 0xba02e108, 0xd89a5e06, 0x8dd74695, 0xb73d76d9, 0x622c277b, 0x02b172a0, 0x4ffd29ad, 0x51d80ab8, 0xe5c82a95, + 0xa0d99fac, 0x5fab04ef, 0x4d47ea97, 0xc411c2ad, 0x2f6bd3a7, 0xa9365fa8, 0x89e3a3f4, 0x40cd447b, 0x9b8d6646, + 0xb57730cb, 0x7fd5f4d3, 0x7165172b, 0xc7f742a4, 0xd3e5f29d, 0xcba2b1f2, 0x90644a6d, 0xd17a9acf, 0x35d5f5c6, + 0x84172161, 0xe41ffc00, 0x27fb5750, 0x72456dd9, 0x5e986c46, 0xaa157bad, 0x9508f0a3, 0x87ba27d0, 0x842f3d20, + 0xc1837a56, 0x4130b55a, 0x25bedc3b, 0x92abded6, 0xb352169a, 0x857e211c, 0x7238d2cf, 0x1a00174f, 0x2668d01f, + 0xa6a97478, 0xe4f038c4, 0x58d99437, 0xfa38a5ff, 0x23b29154, 0xf6001f16, 0x23ed74bc, 0xb9a48057, 0x13897a4e, + 0x8c42154a, 0xd3369742, 0x92bb7e08, 0x7c083cec, 0xb0a48986, 0x2ab63149, 0x9b90a38f, 0x6918975d, 0x0db801b6, + 0xdb2a2136, 0x679b50f2, 0x5db51c63, 0x64c8932e, 0x3c74ab10, 0xcfe6a716, 0x54c4a2fd, 0xd8a19eaf, 0x797695d8, + 0x5503e512, 0x6df7141f, 0x88025fe8, 0x8217dadf, 0x14062c63, 0x7c7af2ce, 0x50220023, 0x63a2dc5f, 0x4f507824, + 0x27bd93f3, 0xf96f984d, 0x9dfeb74c, 0x2034a268, 0x2dea54e0, 0x73eff45f, 0x7b95889b, 0xdebd31a8, 0xf1cf37bd, + 0xd790bfb8, 0xbaa6cd2a, 0x67e07372, 0xbe034e20, 0x0bd5b689, 0x4bc4c217, 0x68f0d537, 0x2efd3c6d, 0x84ed0301, + 0xca2fd14d, 0x0d64f7be, 0x9239fea1, 0xb4111fff, 0x97509c85, 0x06b771f7, 0xd3d8f82c, 0xf2f7046d, 0x6a61272a, + 0xac9293ca, 0xa1a763b4, 0x39574eb6, 0x2b297706, 0x093c2824, 0x8ba74852, 0x562fd749, 0x03f29964, 0x6af7b36f, + 0x225571f4, 0x3a8cc0e1, 0x661574a6, 0x87bf2e5e, 0x3ce2516a, 0xb5424c33, 0xae1421fd, 0xfb3c5f00, 0x4a0b53cf, + 0x7f2e9f3a, 0x1101f0ff, 0x8377341e, 0xc4a1f121, 0x10a42d6e, 0xd3f70141, 0x843997f6, 0x9923b373, 0x0d832621, + 0x9f08aada, 0x4eb2c4e1, 0xf107544b, 0xf42777aa, 0x4dd68b1f, 0xd8ecfe19, 0x598cf224, 0x2f102109, 0x13ae4c6c, + 0x64acd9e9, 0xa6bb72ae, 0xc954d2b1, 0x27216f43, 0x50cd482a, 0x79eb559e, 0x7fac2159, 0x5a9a0c5d, 0x46a6438a, + 0x14961e36, 0x4bce5825, 0x338d791c, 0x78c1136a, 0x43130eaa, 0x95c1e618, 0x4543f45e, 0x42f237fa, 0x4e176cc3, + 0xb31388aa, 0x0cf7963a, 0x10d3eabf, 0xcdb2c8a0, 0x3104caff, 0x75db234e, 0xe7842b48, 0xfa1b6973, 0x60096f7b, + 0x969aa1fc, 0x56372fb1, 0x057da6d6, 0x7b04c2c8, 0xee0df294, 0xee1f3b65, 0x1dcb68fe, 0x23010f7e, 0x5c8beeda, + 0xc2329f9d, 0x940fd23a, 0x59f9ea72, 0xcb32d8c3, 0x9cb9dd63, 0xf61bf4ed, 0x6033333a, 0x05b519d8, 0xbef39f22, + 0xe954d3d4, 0xda90bcee, 0xeadce3a0, 0x98b31bd1, 0xafdf3794, 0x0f7ece5a, 0x85044822, 0xfb3d11b0, 0x1e8db7ac, + 0x512f244b, 0xf0922cfd, 0x3051971f, 0xa7794718, 0x2b6a2c37, 0x63a08e10, 0x27863704, 0x804945c2, 0x0048ca4b, + 0xd66b3a71, 0x8d50ed53, 0x09089054, 0x848c9060, 0x17ce4aee, 0x8d4507b9, 0xe85dc33f, 0x52616b20, 0xf992dae7, + 0x92afb8e3, 0xbbabd7bf, 0xffc35f8b, 0x866aa1a6, 0xf02c7df7, 0x8956c7d3, 0x21cc3fb9, 0x4808d805, 0xf5b60d77, + 0x0bbbc907, 0x5eba0a57, 0x379d3593, 0x280ce62e, 0x4dfde7ac, 0x1ec657a7, 0x72626369, 0x5eb2c6f5, 0xb4171583, + 0xb9e53025, 0xd8c2d93d, 0x923a2f7c, 0xb4e50d58, 0xed69c710, 0x2142666e, 0xa4fc53b6, 0xdf0df4d4, 0xf4858ccc, + 0xcda24cd8, 0x867e00df, 0xfdbb5c71, 0xd09eb659, 0xf74f2daf, 0xff6bee7f, 0x6d19dc21, 0xaab030cc, 0x018e6814, + 0x4d2557cb, 0x2588cd59, 0xc28e292a, 0xe360010c, 0x37988491, 0x668f8e60, 0x4821e52b, 0x5326b9bf, 0xc27d5657, + 0xff5f4218, 0xef24c2c1, 0xc17ea9d4, 0x8a1e71a7, 0x859cd8bf, 0xd573113c, 0x04f1b859, 0xf3946a0e, 0x34c115f2, + 0xdf8f489d, 0x31f9a5aa, 0x4c529017, 0xfd9730ed, 0xf99e043a, 0x0c3b75ee, 0x42128766, 0x8de3f587, 0x7c5dd0c4, + 0xa4a66148, 0x49f5bb15, 0xed4f89b1, 0x988a950d, 0x2818653d, 0x6d153fb7, 0x1688efb7, 0x56aae992, 0x894e05fb, + 0xe8502295, 0x852eccfa, 0x02966aa8, 0xbe862eae, 0x3a4ea34a, 0x091dd2ba, 0xa4d7329d, 0x84080230, 0xff8e3739, + 0x957b6a87, 0xcd4cde79, 0x8dceebcf, 0x833d75d4, 0x1ed6e521, 0x8645cd4d, 0xf2324834, 0x075f8816, 0x2398adf2, + 0xd0e5dffd, 0x10ff6ac0, 0x14fbdc78, 0x521a0dde, 0xe76c1dd1, 0x132a0764, 0x7167b5b3, 0x5b6a83c6, 0xa44ea920, + 0xf6aebe1c, 0xb67611ef, 0x8fbdaba6, 0x0bb99acd, 0x5ec5e702, 0xc66726c5, 0x143d6664, 0xe74b1437, 0xc08d6b8a, + 0xb8810df1, 0x58cb44cd, 0x8027f89c, 0xc605b123, 0x7079c2c6, 0x99cda64c, 0x9c617f41, 0x7d062dc5, 0xb84c6bdb, + 0x8f0d4b13, 0x71ce154a, 0x9907d016, 0x780ed457, 0xcfd1b4d1, 0x960fa95a, 0x8bdbcad9, 0x61a699ef, 0xb565d870, + 0xcb113768, 0x1cf02f77, 0xe1eaa36a, 0xe8de4475, 0x5c07dfdf, 0x3942c0bc, 0xdbbf4510, 0x066fa070, 0xf98e441f, + 0x342624e9, 0x42ef5fc7, 0x46ae29a0, 0xbb7be8c3, 0x75d795bb, 0xae0adb29, 0x5481f42f, 0xfd6a9f19, 0xd8c02220, + 0xcd5aba09, 0x0418b0a3, 0x4d968ce2, 0x2157a7a1, 0xfd72f097, 0x02b32217, 0x56b50809, 0xcf9eca48, 0xd886b587, + 0x8383b568, 0x4d852faf, 0x95276e8f, 0x37805196, 0x70e29998, 0x32b322a6, 0x3f51e5c8, 0x8ec84559, 0x0627f619, + 0xf2785c1b, 0xdb581b25, 0xeac1e407, 0x1696aee3, 0x6d305dd7, 0xf24bdcdd, 0x5d8cfd6f, 0xc5f3cc29, 0x409a3fb7, + 0x13b9a8aa, 0x749c68a8, 0xd427545b, 0x1dd30eb9, 0x20d9eac4, 0xc2a5c8de, 0x0f737064, 0x83d56506, 0xb0070a9c, + 0xda55c1be, 0xf760daa5, 0xd71c755d, 0x26986e51, 0xf5969f7e, 0x12a52720, 0x6eceea82, 0xfd8dc7ca, 0x4dcfafd0, + 0xd82f156f, 0xc657bc57, 0x782f1175, 0xc38302d7, 0xa48c49fe, 0x6e9c6bb8, 0x869e0331, 0x4a42462f, 0x3bc984b6, + 0x00f0db6f, 0x702d75f3, 0x71a09fe1, 0x7c704dbc, 0x5c097a81, 0xdc44803d, 0x3bfdb64a, 0x7b01ebd3, 0xce450ed8, + 0xe53716bb, 0xda0dc26c, 0xcd14ee05, 0x87b9232a, 0xed96cc55, 0x370bba60, 0x2f2deeaf, 0x6e712fe2, 0x4bdfacfa, + 0x74868390, 0x47eeae60, 0xac25242c, 0x45d0a906, 0x29bffead, 0x84b35759, 0xc7053e6b, 0xad1730f3, 0x67e3cf75, + 0x2a60f645, 0x47e0e705, 0x152602a2, 0xee251e9f, 0xf012ae53, 0x5162fd00, 0xd013547d, 0x25c62dea, 0x965e472d, + 0xccca4a38, 0xe604634f, 0x1af52d82, 0x4334632a, 0xc76ce324, 0x59966773, 0x70a2450d, 0x29330b12, 0x43f2d3e7, + 0xdfa6cf57, 0x46bfcda9, 0x2efbb824, 0x04b0bc81, 0x5e73e5f4, 0x50e50959, 0x44f55f0d, 0xf3a238bf, 0xd3b4cd62, + 0x10159986, 0x1a786302, 0xd24c143f, 0x88bc1079, 0x48ccd35a, 0x1ef1277e, 0x9695fa2e, 0xd0789289, 0xeed1ada9, + 0x164a13ee, 0x19daf24b, 0x2191c45d, 0xc74d25e7, 0x77516195, 0x3895d93b, 0x55c4316d, 0x4609b1d3, 0xfd0daf8b, + 0xa0721998, 0x83225386, 0xcf135d67, 0x242ac282, 0xae26b62d, 0x79bd9b55, 0xd0ea4f87, 0x50cb9f19, 0xc7a0988d, + 0x74dec022, 0xf0ca1546, 0x9476f62f, 0x1f43510b, 0x09995d8a, 0xdb56a7fd, 0xfe81f338, 0x19585627, 0x26bc03eb, + 0xde27286d, 0x74c2ad9e, 0x93217d99, 0x77f288fb, 0xfc34acbe, 0x195ec6c8, 0x2c17a53b, 0x24a37c87, 0xfaf80e0a, + 0x17d44024, 0xb6dae5e8, 0x35439295, 0x966cc6f5, 0x4dba610b, 0xa847d355, 0x019e779d, 0x3cfdbf5c, 0x1ce7ee94, + 0xb68e6447, 0x04eb25e5, 0xa1e6409a, 0xded7247f, 0xdeb05719, 0x4c0af613, 0x5a5561ab, 0xfad0bcb9, 0x61b328dd, + 0x7c001506, 0x5d3430b1, 0xe976b657, 0x8e513462, 0xcb7ede9a, 0x458a41b3, 0x2e8024d9, 0x51ac60ba, 0xfa54ab78, + 0x4a8f4153, 0x9a7ce1aa, 0x73dcf385, 0x8923281d, 0x275304f4, 0xf2673ad3, 0xac801fd4, 0x54b623ff, 0x8d20ee0d, + 0x61737d30, 0x931b8672, 0xf6c554b7, 0x644ae38f, 0x9ac2a8b3, 0x5ab367e3, 0x8e83eb47, 0x7820c682, 0x3a45ad3c, + 0xe7212a2a, 0xc803d6f2, 0x78745aac, 0xc0ed8540, 0x5b8f5ced, 0xa47c5ebc, 0xf9156914, 0x984b8eaf, 0xd1759cc4, + 0x33a06f65, 0xa8ae8ddc, 0x4c81c3a1, 0x77d4b2d9, 0xa054d461, 0x67767ad7, 0x4122796b, 0x60973771, 0xf5f75643, + 0x4be9169d, 0x555bd5f3, 0x5f5cbb35, 0xb27b608d, 0x414f34be, 0xe036f5b9, 0x0fc84252, 0x18393fc5, 0xac08ef54, + 0xdaf5838e, 0xa7564449, 0xe1eba6f0, 0x96d1d300, 0x4d97c4ff, 0x9d9be839, 0x703f7a14, 0x40a62da7, 0xde651370, + 0x5fd757c9, 0x75522760, 0xf4fb3d88, 0x5a4b1ce6, 0x755ceb4c, 0x130f7c97, 0x7351d3b6, 0xbbf3707b, 0xb1f751a5, + 0x5bf6735f, 0x98d49bf1, 0x92aac3b1, 0x2bfe736c, 0xa7b725fe, 0x894ca7b4, 0xa1e00220, 0x96833305, 0x37491c8d, + 0x08485172, 0xaae787c7, 0x253154a6, 0x90b37e5b, 0xd54af740, 0x5f7ff4ec, 0x47431eb9, 0x4b741e89, 0x25911d8b, + 0x2f0634c0, 0x13633f64, 0x7ca63941, 0x41c30770, 0xf1f12e6e, 0x7b983055, 0x49197d1d, 0x2ec959ea, 0xdf8de3ad, + 0x2d43af0c, 0xbdedfdf3, 0x54e0efbf, 0x047f2502, 0x2a42e158, 0x64456793, 0x65b8e177, 0xcd19ecb3, 0xe8ae1e63, + 0xf55be37c, 0x39c99941, 0x37894216, 0x437579c8, 0x03b9892c, 0x3734720f, 0x876211ae, 0x4b16ff97, 0x438f7416, + 0x1f229d31, 0x2b295cf7, 0x2c985071, 0xf38ab7bf, 0x379a9dba, 0x899147dd, 0x34ad2815, 0x76cb1f4c, 0xea9eef8e, + 0x0067a2ac, 0x10b12e55, 0x2db3e05c, 0x1397bfd7, 0xf8e4f86a, 0x066bf8e5, 0x0b7325de, 0xaab9ce1a, 0xfbc3ff1c, + 0x53200ec9, 0x55b93598, 0xcb21324a, 0x011f7e1b, 0x53cbc431, 0xca2f15fd, 0xa6e61cf7, 0x0a53c7e3, 0x3922001e, + 0xe18d5a81, 0xbe457a85, 0xcd616737, 0x345e6043, 0xa93c3cf4, 0xb8080d78, 0xe5602147, 0x85a1322d, 0xe6be1b5e, + 0x426007d2, 0x6ee45699, 0xc1fad3ad, 0x5f06720d, 0xad07c63f, 0xe5955e12, 0x1c360aa4, 0x77c57cdf, 0x5c5d8167, + 0xf741a42f, 0x165c4e52, 0xc3dbcf4d, 0x3d08b02d, 0xc11b254e, 0xe15342fd, 0xe2b5337f, 0x0b6992bd, 0xbba48841, + 0xd5d1cc07, 0xed12fbe5, 0xd3b808a6, 0xf0d1e7f6, 0xc22bf4c1, 0xfdca84f3, 0xaeacea78, 0x4f9dc7cb, 0xa45bbd82, + 0xdf60983e, 0x0e4e7bc2, 0x41c61187, 0x69940098, 0xa83d78ef, 0x6ed255d8, 0xb54e8274, 0x2eef3c45, 0x3e74e7f1, + 0x68ea87a4, 0xc406110e, 0x20c32f5e, 0x5878fedd, 0x81735d70, 0x4b499e9e, 0x519d7d16, 0xb0e89616, 0xe89d6fd3, + 0x57dde8a2, 0x298b4c7e, 0x74cb0060, 0xd97ce7dc, 0x725fa6d7, 0xf47005ec, 0x908d34ac, 0xec28109f, 0xfbdea228, + 0x194776f8, 0xa3be77c9, 0x6fedd9f2, 0x10ab1779, 0x3128508f, 0xc623fb72, 0xf1dd62e8, 0x169d9088, 0x7c76d393, + 0xa9266ae5, 0xa5cfe9b0, 0x46435cd2, 0x38b6173d, 0xdb67215c, 0x227e6d87, 0xc43167b3, 0x03b277fb, 0x14556678, + 0x61b1abeb, 0x47b11ef4, 0xdfc97fbc, 0x9c34d8ac, 0x8cb7ab6d, 0x261aea2d, 0x511bc648, 0xc158c84f, 0xa2976129, + 0x59e8c2c3, 0x0004988c, 0xf318b79a, 0x1a991e4d, 0xd45a199e, 0x7c81f98f, 0x7324a395, 0x4e1de8de, 0xad8c15a9, + 0x8b1c0fb7, 0x8c4bf183, 0x4d84f0db, 0xee0cd270, 0x748eb333, 0x6e13b669, 0xb845feaf, 0x0d226f8d, 0xa98424e6, + 0x56068e9e, 0xb0823985, 0x6f6fe32c, 0xceb2d2ef, 0x5ad0206e, 0x8ed96681, 0x0d87d579, 0x92b5e9ff, 0x1d538eb9, + 0xfa8a0a3e, 0x8619e344, 0x7a9fe444, 0x04ba4e3a, 0x9f66497e, 0xd42edbcf, 0xc2f12e00, 0xbb3b71ce, 0xdc9fc91f, + 0xcec74f0d, 0xe6acc8ff, 0xdeaa3062, 0x4a884880, 0x26805985, 0x6030e717, 0x43d7a904, 0x919e3d23, 0x4caac7de, + 0xb0d270d1, 0x39e11bcd, 0x8009b8fd, 0x077ea03c, 0xa954f43e, 0x88f44cbd, 0xf00d9b8d, 0x4f83d36d, 0x83d5278b, + 0x29eaf6ad, 0xf31724f7, 0x26a82de1, 0x5d2d7d8b, 0x48e95854, 0x7a1c3450, 0xdee39e3b, 0x1288a57e, 0x5993518e, + 0xef849e08, 0x4a956312, 0x2bcc30ab, 0x70d27cd6, 0x0a889d23, 0x3d014d6d, 0x21982068, 0x634d7d0d, 0xfee8414a, + 0x21f4d0b9, 0xc4d023ad, 0x1ffcc628, 0xcb2a6aeb, 0x3a7f0bcc, 0xe0737557, 0x7273219f, 0x03b92272, 0x35ecf91b, + 0x2a89bce8, 0x875758bb, 0x3948fc07, 0x73973db8, 0x632634d5, 0x0439c173, 0x3e2b582e, 0xa24982d0, 0x11ee9e0d, + 0x442ec213, 0xa7c01582, 0xec615c73, 0x1c28ce2a, 0xb37947ab, 0x311573c5, 0x079b4686, 0xaddab1f4, 0x5db59e95, + 0x71980922, 0x1166f337, 0xd7df223d, 0x61dc1e31, 0x5919a9bb, 0x027bd1a5, 0xfaf89da2, 0x6d8db5ed, 0x49ec4cde, + 0xa2ca3d63, 0xd14805da, 0x471381c2, 0x827b2d72, 0x8d73b513, 0xadaf4c0e, 0x4154aec3, 0xfe6d2d36, 0x2cc8f645, + 0xb04f3275, 0x6321b897, 0x9a338a4d, 0xdafc946e, 0xa0a14cdc, 0xac87d2b0, 0xe508ce7c, 0x09f8d79f, 0x75a987c9, + 0xcebe8aff, 0x6bc6fd2f, 0x4b331cf0, 0x1324f95c, 0x86367a0c, 0xd507c40d, 0xa0616353, 0x05ac58a5, 0x0ee48d6d, + 0x4ddaeda3, 0xd517923a, 0x6ad367d9, 0x8d50151b, 0x36299d61, 0x7810cbe4, 0xb405bff5, 0xa39ec276, 0x0941cf1d, + 0xa4dbac97, 0x0d6f0b40, 0x45ab5e05, 0x781ac395, 0x66c75f87, 0x725ceaa6, 0xf1349e59, 0x7ac0b999, 0x1dc1b5ab, + 0x62e09db3, 0xb2c906b4, 0x5d4b2bb5, 0x0ce802fc, 0x84813452, 0x1ff538f7, 0x485e2148, 0x9db1a053, 0x16102a18, + 0x9dbda187, 0x0a2cd929, 0x5cf938c1, 0x13fcc566, 0x4cc92f7b, 0xd631faca, 0x610d51a6, 0x7a044ce7, 0x3296ef98, + 0x3394937a, 0x4bac3ea6, 0xbfc1d96c, 0xd3da5bbb, 0x219709e2, 0xbb0a3fd9, 0x388a3f9f, 0x864be9bc, 0x0bf36283, + 0xa4f5519f, 0x90f6365d, 0x9693389c, 0xd3429faf, 0xaf109d87, 0x626568cb, 0x24983549, 0x25568acb, 0xe15c43d5, + 0x3247372c, 0x761cc23e, 0x6723c133, 0x260b529a, 0x0dbcc8af, 0x9f7df4fb, 0xe014499e, 0xae2971cc, 0x84b31fa2, + 0x1e15d293, 0x6b325714, 0xdcc49eb4, 0x823d1b7c, 0xab7a0f16, 0x0fcefa0d, 0x22ec255d, 0xa0143f62, 0xf946bef7, + 0xc9fb1d84, 0xb4c19905, 0x956cc64e, 0xc76c65fb, 0x508b19cf, 0x7995c805, 0x7f6c71c0, 0x9f63e172, 0xc5d35a7d, + 0xd06b57e0, 0x1f201a70, 0x73986312, 0x3dfe8c73, 0xad70cc49, 0xe3c6d613, 0xffd2adac, 0xb8ebb807, 0x4244f439, + 0x3fee24d1, 0x95cb5d30, 0x09dacea1, 0x7034f843, 0x5b126968, 0x1d7dd563, 0x82fe48f5, 0x2f4a6d3e, 0xa1f45658, + 0x9859047d, 0xd3b7c6ba, 0x0246aa44, 0x60524ddd, 0xb13510a7, 0x513dd080, 0xe6708aec, 0x4710e506, 0x3c5c5cf1, + 0x4869568e, 0xc3486d35, 0xa3628ced, 0xef895067, 0x9dd47ddd, 0xcbd6ed0d, 0x720ba096, 0xc41983a7, 0xfcc9eb56, + 0x2bfbb2c3, 0x318e11a7, 0xf1e64820, 0xf97d3f14, 0x2c23d5d3, 0x7293a703, 0xa62151ec, 0xcc48369f, 0xd0e0d5b5, + 0xf95aff8c, 0xbe1ec202, 0x17d3d7dc, 0x970405d1, 0xe833bfcc, 0x574100d8, 0x5478bb29, 0x319a0553, 0x7f2b20e9, + 0x76e23004, 0xa4007b35, 0x7dcaf688, 0xfd0054cf, 0xf7edbe96, 0x2b7d076d, 0x32a7fe4d, 0xecb30cd0, 0x9997260f, + 0x0871e8b7, 0x137140f0, 0xbd1d89cb, 0x2227105c, 0x7f28a945, 0x62f59154, 0xff6290bd, 0xeb0f90d1, 0xf48d2ecd, + 0x1b519527, 0xf8ec4885, 0x1bafd098, 0x3aa1014b, 0x0fcec0a3, 0x5e878370, 0xd7d74087, 0x63ad9b90, 0xdaa7c25f, + 0xff1b2519, 0xd59f4b65, 0x2c7d4dcd, 0xdea306ee, 0x7d7d20a5, 0xf0f7944e, 0x1406586c, 0x618c0c4d, 0x09270e06, + 0xc1cd562c, 0x4dd966a6, 0x662f2d50, 0x0295f331, 0xbe1db4e6, 0x77665660, 0x53fcd474, 0xaa60d08d, 0x76d35a90, + 0x377be606, 0x50c6ac09, 0x29345459, 0xcd65de39, 0x2408dc9d, 0x0339f9e8, 0xfd8cbf50, 0x2a263a79, 0x755ebf8c, + 0xb0cb4316, 0xfe95fafc, 0xab797812, 0xc68db014, 0x893a2571, 0x3ff3ead1, 0x982d4089, 0x1e0b51cc, 0xf8b83cda, + 0x0218ced1, 0x0280a018, 0x8adc8e86, 0x2a0cc4ee, 0x7961345e, 0xdfde4608, 0xe47c6051, 0x6e6af588, 0x44bc0c54, + 0xc8c147c6, 0x5895582e, 0xa3e77cc0, 0xe15dd752, 0xb0f2afbf, 0x8adaec3c, 0x9e0663bf, 0xab161841, 0x0104eeeb, + 0x8da04d3e, 0xc22c9dee, 0xa554e873, 0xc9938d44, 0x44e551d7, 0xb2137d09, 0x0bb7c934, 0x244e5a6c, 0x3a135e5a, + 0xec22d85e, 0x29f154d9, 0xd92100ae, 0x714efbae, 0x011097b4, 0x74b9d067, 0xe26d9393, 0x93a43bb8, 0x5174e753, + 0x90c3d8ba, 0x579ab4de, 0x705cd097, 0xd64dff19, 0x8fe72cc4, 0x984ce4f5, 0xc26a6bfd, 0xf3b3154a, 0xf7f2c5d9, + 0x304ec148, 0xeea0e6dc, 0x78c12c6a, 0xbae8d465, 0xa15c57dd, 0x54b9cde7, 0x8fec777f, 0x3ecffed3, 0x5801217f, + 0x713ef853, 0xe56b6c9a, 0xfbadee1a, 0x455e1ccd, 0x2f2b99f7, 0xb308e39d, 0xe7356326, 0xd516d657, 0x1f0e94cc, + 0x06164618, 0x2844eaa4, 0xdc697a98, 0x5a886c79, 0xf6cbc11c, 0xdbb9d2fa, 0x0713bb96, 0xc82df680, 0x10cdbb7d, + 0x8b0a6582, 0xe4a4934b, 0xf6d6d916, 0x4f4d9268, 0x5ac34b56, 0xe7ac8b6a, 0x63108f08, 0x980dd317, 0x854cc955, + 0x362f1a19, 0xb1590c82, 0x32c606e7, 0x3c0cc721, 0x4d5928da, 0xbe23830c, 0x1c1bd7ee, 0x8fe0c948, 0xfd32c88d, + 0x0c6b3caf, 0xd9b59793, 0xe8272e07, 0x59544e51, 0x82948622, 0xff59014e, 0x5d2f967f, 0x9702aa44, 0x90189ab6, + 0x32dd3b03, 0x6017fb86, 0xd0eff236, 0xb452f47d, 0xbd64f5f0, 0x58368ae1, 0x3c46a538, 0x6d61fc17, 0x89d3f13e, + 0xc9815857, 0x35ab2ebe, 0xa0ddccee, 0x7fe49e9f, 0xa73cbf78, 0x935165a6, 0xcab2afec, 0xf1b34a31, 0xc16177d5, + 0xc3677187, 0xb9008b90, 0x57cac227, 0xc4d100c8, 0xf536791c, 0x7b8d2ade, 0x23ff830b, 0xb990ce77, 0xa378a681, + 0xb80bdda8, 0x68d23567, 0xd4986858, 0x6648de27, 0xe2679c55, 0x50dc96d3, 0x6bdccd27, 0x3db54235, 0xbc5c5516, + 0x97c5d0a9, 0x4a3c3dfe, 0xe54b2c21, 0x622eb57a, 0x126f852e, 0xeae79a8c, 0xb41b5cb5, 0x121cd5f0, 0xe91d7d33, + 0x7144c66c, 0xd34c7fac, 0xa1d2c556, 0x1c877d4a, 0x10ea88b1, 0x6cf955ff, 0x57019999, 0x9193a320, 0x8c5c4978, + 0x8d1d65b1, 0xe209c691, 0x1016d643, 0xbb8e4bde, 0x5eac772c, 0x2bbae995, 0x3d8ccd67, 0x499cc1ca, 0x2cfcefb3, + 0xaf2b71fe, 0xaaef9602, 0xf4fe2e24, 0x1735ff4c, 0x0e4fa704, 0x412d46ac, 0x92bb7fff, 0xfaca9fae, 0xb6aada19, + 0x10f590a9, 0xa34111f2, 0x416fa065, 0x543c70b2, 0x975852f7, 0x7c2e61fe, 0x14645880, 0x867bb026, 0x1c504638, + 0x34c8f2d5, 0x09ad63d2, 0xb89b40e0, 0x22c961a6, 0x6dca8301, 0xf83f5a65, 0xa3939a5d, 0x4b791a94, 0xd6eac1c6, + 0x960f9b8a, 0xefa06f02, 0x31ac888c, 0xabd94099, 0x695c9796, 0x056cb439, 0xce7ae2a4, 0x04c57749, 0xcbd2f3a1, + 0x02d4105c, 0x18f2418b, 0x60b05299, 0x6eb102ed, 0x0dad3eb0, 0x3821fd78, 0x39a4f23e, 0x240ebfde, 0x5a775f5e, + 0xe41aa4bf, 0x14c7d994, 0xeb89a06d, 0x1d90ae87, 0xeaa22daa, 0x78deb559, 0xf1347050, 0x08d8670d, 0xdc30d80a, + 0x9e1fe8c1, 0x728c9a3e, 0xe1c6a8c7, 0xfb096099, 0x4f7734f0, 0x3386a781, 0xdaa81903, 0x82647a0f, 0xa89fb825, + 0x19cd7964, 0x6ad05d60, 0x364c5906, 0x2ed5e5fd, 0xcbe21cdc, 0xaf5a61a2, 0xd7987c67, 0x922dd51e, 0x7ff12086, + 0x423987a1, 0xd8cd120e, 0x3a9825a4, 0x17ed9617, 0x7087a2c1, 0x31924078, 0x9593328e, 0x625dfecc, 0xb9fc2869, + 0x8a9e2b91, 0x5e1669fd, 0xade1655c, 0x69745532, 0x63d81f7a, 0x4b64f0fa, 0x120cf160, 0x78f257f6, 0xc159d41f, + 0x3ac872d6, 0x2476b4eb, 0x4d2352b5, 0x81422e6a, 0x3319ecde, 0x492e5d6d, 0xe504c4f5, 0xfc36022a, 0xfdf9ab40, + 0x46c6baa3, 0x39134268, 0xc550dc6e, 0x1c2a1a47, 0x40e26d1e, 0x2f2483a2, 0x8de4532e, 0x2b63984d, 0x62c50440, + 0x1e624094, 0x2657c902, 0x600d3132, 0x068290a5, 0x64518444, 0x9ea9f80f, 0x58585a13, 0xf69f8b98, 0x1171cecc, + 0x3d14832c, 0x3bafe71a, 0x1920ec35, 0xbe78d9ff, 0x1e2263da, 0x9e3bc7c4, 0xe440503e, 0x4b362bcb, 0x99b5f4c5, + 0x9f060e5e, 0x81681fdb, 0x934b2c68, 0x36ff0d70, 0xe53ca31e, 0x8e412917, 0xc7ff8b06, 0x412efdf0, 0x353e3a9e, + 0x9bab71f3, 0x8b724f72, 0xdf011749, 0xaf34bd39, 0xee102ce1, 0x1b4d82ae, 0xad8ba864, 0xb5ec6b68, 0x9ec325d8, + 0xe4b77caf, 0xf6273039, 0x7759163c, 0xec0354c2, 0x2f0c40a0, 0xc441b419, 0x5e064289, 0xb555567f, 0x1ffa3d4e, + 0xeb1812fb, 0x43c54fb8, 0xeb17a848, 0x03dd3962, 0xae5befa5, 0xc1236324, 0x5f8ab762, 0x87a47158, 0xe6628883, + 0x7d43c843, 0xd63ead4c, 0x7bac23f7, 0xaa5803c9, 0x1261db95, 0xa963b357, 0xa667e25f, 0xe648d4d1, 0x86cb894b, + 0x234adbdb, 0x8ab3b3f4, 0x2413fe37, 0x1546fbc9, 0xddd7ac32, 0x9c4606c3, 0x3afa0ddd, 0xd8de9cfc, 0xeb4e1da6, + 0x4b839237, 0xc46dd47e, 0x3effb3a5, 0x6c37a582, 0x51ec3809, 0x65c372b5, 0x568c50cf, 0x08aee3e3, 0x30f4bcdf, + 0x70b469d0, 0xd231fd01, 0x0643ba63, 0xb0bc6790, 0xb95f62a0, 0xed9fa3d0, 0xe7ef4557, 0x2d9ccbfc, 0x2f1e79fe, + 0x64ca65b5, 0x613e7d55, 0x1df530c0, 0x8fa94b8d, 0xb1cfccbc, 0xc23fdd75, 0xe5450e2a, 0x5ac0111f, 0x680b4e84, + 0xa19a22c1, 0xc634b81e, 0xacd40b4c, 0xc8543883, 0x2255251c, 0x71f1576a, 0xfacf6de4, 0xa13f6905, 0x94b6cb36, + 0xbc54e1ab, 0x9b9ea1ad, 0x1970a279, 0x4bcd7f24, 0xc104c842, 0xd8498658, 0x1b73fdeb, 0xa2c7340d, 0x0f77ce70, + 0x58514d5e, 0x85c7e1e6, 0xcf25a090, 0x41b07756, 0x5c23dd41, 0xb4f774c3, 0xdd803ad9, 0x25507f2c, 0xca7e515b, + 0xb746ceb9, 0x8871e453, 0xb660ab54, 0x73f6ca54, 0xb61ad3cb, 0x4d8f75bb, 0x10574fe2, 0x07693365, 0x3bbc40ff, + 0xc0fe2b63, 0x92035187, 0x95caa856, 0xdc2b69a6, 0xdfcd06ba, 0x09e27e3f, 0xf677cf8c, 0x5808c684, 0x6488554f, + 0xbe83f852, 0xaa8d5e0c, 0xb56536c1, 0x5055e39a, 0x7c640acf, 0xb0139f6d, 0xf52398b5, 0xfaaeac17, 0x196f693e, + 0x5c043029, 0x489604e1, 0x5d18a3cc, 0x523df058, 0x66b684cc, 0x4da08042, 0x4037089e, 0xe1e676bd, 0x9014e20f, + 0xb96ac0af, 0x437c039c, 0x532645b6, 0x91edf568, 0x12b65bce, 0xd9fb8afb, 0xaa781bf1, 0xdaba9498, 0xd0115ba9, + 0x77a9c136, 0xe58444a0, 0x256cf09b, 0x213afd83, 0x13d4cacb, 0xff9be7eb, 0xd133058e, 0x718c755b, 0x15e2fe53, + 0xdc75c603, 0xd905292e, 0x5a6fbf6c, 0x586031e3, 0x980f20c2, 0xda04581d, 0xf62d452b, 0x818ddae4, 0x223f42cb, + 0xa3df6660, 0x10491d72, 0x60b05a99, 0x4f994c4a, 0x279aba3c, 0x8ae621d9, 0xf25f3e37, 0x3470bf0b, 0xd9aff533, + 0xe38fce76, 0x13ec9913, 0x669ba27c, 0xa8f150a8, 0xb9dc143a, 0xd1c4a163, 0x9f0d29fd, 0x117463e6, 0xb32a8a0b, + 0x2593a1f6, 0x7b94b338, 0x288989a6, 0x134e94a5, 0xb8cca989, 0x585304d2, 0xc727a2ca, 0x6231c8a0, 0xad9a0f52, + 0x762a1dd2, 0x76c49341, 0x89547543, 0x8ed602ac, 0xc6144838, 0x921ee9ff, 0x0b994520, 0x61e57712, 0x7e77bd0b, + 0x062a6d93, 0x8de88d41, 0x7994b1c1, 0x3fb5f4d6, 0xf41078de, 0x97653828, 0xff157ec8, 0xae2913d8, 0x98a2fa33, + 0xc255aed4, 0xf492cff7, 0xc5bee06e, 0x33d1b1dc, 0x2073e680, 0x96bad610, 0x9dda3072, 0x68f76399, 0x159d14b6, + 0x8b6840b5, 0x834a372d, 0x2b61d164, 0xcc374c67, 0x94291c44, 0x48a94642, 0xafd11589, 0xfa0085d9, 0x0fe28b2d, + 0x0c8b7087, 0x8a5dfa52, 0x585b5e08, 0xac4013a0, 0x2f607793, 0xb990f0de, 0x6e71e05d, 0x1edecd3b, 0x046fb19b, + 0xc9a5808a, 0x98e2e9a0, 0x4951700d, 0xb7a1a776, 0xee095f05, 0xc1367eff, 0x8dd49887, 0x2c6da0b8, 0xee522ab4, + 0x7eb6f5db, 0x8f8e4416, 0x72f6df45, 0x2c415fd7, 0x7ef319f8, 0xa4e50304, 0x39410b66, 0x8d7d3cb0, 0xca4e0e56, + 0xd34210d8, 0xd6bdee37, 0xe8755b71, 0x38980557, 0xd10e673d, 0x83b4980a, 0x1e520bbe, 0x68768f6b, 0x8785bfbf, + 0x5acd64d1, 0x7c7ff6d0, 0x2d2422ae, 0x43ec2150, 0xa27be3ea, 0xdd2cf103, 0x21ccf909, 0x2767577c, 0x1c3dac42, + 0x436b7f4a, 0x71f20cbd, 0x0e900a46, 0xbad3fd86, 0x9d03f327, 0x06c00f12, 0xa9e3a894, 0x731dd697, 0xa19be5ec, + 0xd60af4c6, 0x346abf94, 0x3c63ce1f, 0xefb2a061, 0x6014597b, 0x10a1debb, 0x4faa832b, 0x610135b5, 0x7e2fcb66, + 0x589b21f8, 0xcb16820e, 0x3ffe2b55, 0x388d73e5, 0xcebdec48, 0x6261fb1e, 0x7b0705f3, 0x8c673e48, 0xa2dac047, + 0x7ac5a8a5, 0x31e0182a, 0xe13c6421, 0xae9299fa, 0x03e9e586, 0x8078383a, 0xd9b77da4, 0x87401939, 0x6ef661fa, + 0xabd3c272, 0x92e52c03, 0xca93109a, 0x8b8357dc, 0x2cdc9a64, 0x9a86e9e2, 0xfc40efc4, 0x0a5e8d81, 0xd1b7c411, + 0x2afe3911, 0xea3dfa23, 0x478fab3b, 0xc9d37ed3, 0x03fb8a74, 0xbd968a85, 0x58c34a8a, 0xd4bbd3c0, 0x1b024206, + 0xef3e40d0, 0x35f038ef, 0xa788bc32, 0x7c4ac330, 0xe9027796, 0x128b78e2, 0xe4e63331, 0x9db9a76c, 0x1d71f3b1, + 0xa6b63c74, 0x836f1faa, 0xb67cc9f1, 0xe519b6e0, 0x325b1ec1, 0xda9dd1ab, 0xa533bec6, 0xcbe39266, 0x0eedb051, + 0x7dbf6ebe, 0xc59f9ef5, 0xcda9f927, 0xa08a6319, 0xc18a0be8, 0x20c735c7, 0x1b556d78, 0x6ec23049, 0x72503971, + 0x33948d2f, 0xfc8e9138, 0x79f421f2, 0xce24cd97, 0x9d74b4ab, 0x1fac4abb, 0xcdc91cfc, 0xe20da724, 0x13cfc3e5, + 0x21d543d1, 0xf0ac7aae, 0xfad77157, 0xa731e9b3, 0xf63a4a4b, 0xdc8976b7, 0x9143ad92, 0x4755c22a, 0xcd03b1ea, + 0x30523de5, 0xec34efb1, 0x224d9566, 0x7ad3acfc, 0x10540401, 0xebbf0e60, 0x10b8dd40, 0x2f176ec7, 0x94538f0e, + 0xbed1e9bb, 0xd851a284, 0x8b535ad7, 0x0c5d29e8, 0xe8555985, 0x9a80fd2f, 0x2b82418e, 0x0b97b47c, 0xffc14c75, + 0xd8ee2813, 0x1b1d353f, 0xc069eab7, 0x97e46d7a, 0xa363829e, 0xf1842fda, 0xc5b3d23f, 0x608c0037, 0x79bcb58d, + 0xd32cafc8, 0x3606c739, 0x8a7b0271, 0x9c1d189f, 0x8330347c, 0xc0f40be2, 0x0fe7957f, 0x7d5bb9ec, 0x8c0d7c4f, + 0xec16184f, 0x1fa56cde, 0x1de8e006, 0x4aa63bb5, 0x0515f596, 0x49cb970f, 0x2a96b266, 0x97bebe5d, 0xe6e0373a, + 0xd3353af3, 0x849d2b8f, 0xd1151f8e, 0x4024af39, 0x4852f429, 0xba6d5650, 0x7ae78716, 0x931039ee, 0x10ae710c, + 0xb73ec90d, 0x01dabb5a, 0x8b6887cc, 0x82780910, 0xb2b00185, 0x66be305e, 0x134466cb, 0xed8f84c2, 0xf0d9ccb3, + 0x9bd7f004, 0xa01ac44c, 0x0c437885, 0x4f101f16, 0x68b32cf3, 0x58aaacb4, 0x13a59e8d, 0x466141af, 0xfd3b0e1f, + 0xc4454601, 0x4a8f329e, 0x29559d25, 0x7bcd337f, 0x5c5dc357, 0xa9b56584, 0xcb7a3682, 0x5d3766c8, 0x37a8220e, + 0x64faa3ab, 0x8e6bad2d, 0x9b44fa10, 0xa89a2441, 0x66d276b8, 0xdfc022dd, 0xe5e89e22, 0x923ed90d, 0x06bda6a6, + 0x0ff985f5, 0x8b3879b6, 0xa08b122c, 0x3a1c5643, 0x1fe27911, 0x7fac4563, 0x7582a502, 0x258ff54c, 0xb39f29c4, + 0xd932aa63, 0x9539236f, 0xf8ba455a, 0x58ff2563, 0x64e8ad11, 0x5de9976c, 0x320f4d4e, 0xf77d329d, 0xba863d65, + 0xff456430, 0x336dcd35, 0xe149871c, 0x8462dc19, 0x13f92db4, 0x830bed28, 0x62145623, 0xd418146b, 0x341d916a, + 0x4824b7b5, 0xc72f7c27, 0xe437aed0, 0xe542989a, 0x51e2b2a4, 0xd5b40d82, 0xf8c8b796, 0x5af2faa9, 0x07aa8871, + 0x10220252, 0x5702badf, 0xa71a0566, 0x07c0898c, 0x490ad7ec, 0x26b474ec, 0xa41afebe, 0x6caa7ae9, 0xde0bd305, + 0xaabb7e08, 0xc9dcb882, 0xad08524d, 0xf94aa85d, 0x426980d8, 0x822c8c26, 0x5641d804, 0xbdb5a1cc, 0x3d7fbe91, + 0x7e79c3d0, 0xe83a0d60, 0x20a05159, 0x3bbb55e9, 0x3864be7e, 0x414b8fc9, 0x76ec5844, 0xd7288c78, 0x6937c996, + 0xc953bfbf, 0x87632af7, 0xccc71ead, 0x2990fcec, 0xe9baee60, 0x9861e054, 0xffb73825, 0x8ed08387, 0x1b7c0ecd, + 0x4ab50f08, 0xa189a67a, 0x5c853dbf, 0x29e04dbe, 0x31bf98a1, 0x0dbf4e8f, 0x90b297d2, 0xee6b0b18, 0x3f7dc854, + 0x6e277124, 0xd7eaf05d, 0x516f2b21, 0x9b18ac0e, 0xb6610925, 0x0a365295, 0xdde62aa7, 0x09236732, 0x4dfc8888, + 0xb5c7cdaa, 0xd7a48ef6, 0x62bac4c8, 0x937eaa58, 0x2f3167b8, 0x54453e11, 0xcd19e094, 0xb26d65b9, 0xd0fd25e2, + 0x9cd4d4b8, 0xf14ef3c8, 0xbdf99487, 0xb7a37624, 0xa6cc8db0, 0x3de53338, 0x2e70b3fd, 0xc9cc6032, 0xb5d599d6, + 0x430f946f, 0xe09e39d7, 0xbbd6db54, 0xa1e614da, 0x0bfa5363, 0xf4af5f9f, 0xd164aa0a, 0xbe5a8ea5, 0x3244252d, + 0xa11b5378, 0xe3887423, 0x8e7e7b16, 0x2f3c7e68, 0x0a7727ff, 0xf7fef588, 0xb6ca6bf7, 0x62ebcf5e, 0xa2c777c7, + 0x6ea05253, 0x9520a6d2, 0x9a91bf85, 0x09514b94, 0x5fda4a9e, 0x5264335d, 0xdc7669cb, 0x9e9e2ee6, 0x5431a818, + 0x6db26be7, 0x9ff635f2, 0x2c77f101, 0x7f64a006, 0x9849e417, 0x566b0c11, 0x2e2932bd, 0x3fa32129, 0x0c8ef6a0, + 0x9def873e, 0xb0453b81, 0x43a2b63a, 0xd33e37d7, 0x4d57f18f, 0x6b331a33, 0xc4c39d30, 0x3ad1be85, 0x933a1a67, + 0x86b5cf30, 0xe3e12011, 0x06e41bb3, 0xd6331dc2, 0xa041ee7b, 0xa616bdee, 0xa4848f9b, 0x9bde590c, 0xdfae9f28, + 0xbe30c4e7, 0x52a0a233, 0xbae64532, 0x237f7ffd, 0x683441e3, 0x4a5c8209, 0x81e205a2, 0xbf4d5bd3, 0x4d6ecf8e, + 0x08de3fd2, 0xf0547670, 0x50da4c30, 0xdf05db09, 0x68147ded, 0xaf66cb78, 0xb87075ea, 0xb5a38346, 0x2a1f1bdd, + 0x5fdcc490, 0x5ae69396, 0xabf9e58c, 0x279c6fe3, 0xac660564, 0xc1127cfa, 0xe8870f21, 0xec4d1853, 0xaad8b13d, + 0x38541100, 0xb01274a4, 0xbc978fad, 0xe9048ef3, 0x6646112b, 0xc39a5ebc, 0x508ee455, 0x8ee1f1cd, 0xfc126843, + 0x2b8c6dc8, 0x90949217, 0x16824acc, 0x33a0e25c, 0x37566fd6, 0xf9b7fe0e, 0xa2a4c2a1, 0x410f1c23, 0xc144307a, + 0xf6c255a3, 0xacf567b0, 0x3fa39443, 0x6b6e77df, 0xddb88efa, 0xf955a6d8, 0x27e5daf2, 0xc62895d2, 0x930db373, + 0xdc0a84f1, 0x5adfceed, 0x1f198d8a, 0x2dcd2357, 0x4612d7d3, 0x63426df7, 0x4953c8ce, 0x1a49f4ee, 0x1b684cb6, + 0x6e0e70a2, 0x44059096, 0x68fdff46, 0x13736782, 0xde939f77, 0x2d3806d9, 0x471cbd7f, 0x15c0f671, 0x16615c14, + 0x7a27a2fa, 0xe039fe5a, 0xf7a4bfec, 0x14f479d3, 0xde3fc087, 0x8b0bc048, 0x8fc58bba, 0x2ac4a011, 0x5df25385, + 0x8d45d7b3, 0xe12f288e, 0x2b2dc7ce, 0x4299feab, 0x9d192d33, 0xe6e0efe5, 0x4ff34588, 0x4f471e13, 0xbe21956b, + 0x545f6919, 0x8b0e70e7, 0x88eaeff8, 0x33d54145, 0x27675925, 0x416b64f2, 0xda71c702, 0x80d17242, 0x71a437ea, + 0xe40ada1f, 0x146538e6, 0xdcc2739d, 0x63572250, 0x57f658aa, 0x63c5c952, 0x56db4191, 0xcdb11f4a, 0x3153b4ef, + 0x2a9d69d7, 0xc13418d6, 0x4d978024, 0xd61b9277, 0x85fc5095, 0xb399acdc, 0xa0a63659, 0x809725b4, 0x99b19776, + 0x90c3dca9, 0xa07c7edf, 0x916f9e82, 0xeab98f89, 0x9bceb90d, 0xec08c36f, 0x14e11fbb, 0xe9af5cfe, 0xbd32cbca, + 0x4900224f, 0xe057bb02, 0x4858cb15, 0xb62a6d42, 0x9c1188cc, 0xecaf0d64, 0xbc2ed505, 0x525ab2a8, 0xbc5532eb, + 0x486356f2, 0x02f13fc3, 0x1d974aee, 0x95c0f23d, 0xbe04cfcd, 0xf90487ee, 0x7e636e1d, 0x9201485c, 0x1a4d9983, + 0x81801a9a, 0xd4c7cf62, 0x689c97eb, 0x459e6cf4, 0x5a0be2bc, 0x56008ba2, 0x4936cb6b, 0x0dd299af, 0x6f3a7957, + 0x379ba155, 0xce37e806, 0xd38000f3, 0x8890ee10, 0x685e0d9d, 0xffe61db3, 0x9c88f8c5, 0xf7897ae6, 0xc6e682d5, + 0xa1e6c557, 0xe7d6856a, 0x94cb4071, 0x30589316, 0x7e258a4f, 0x1b49ccc6, 0x09f7166b, 0x0d020dfb, 0x47c1dfaf, + 0x471fd516, 0x1b78bde1, 0x89d5dcce, 0xbc1c4619, 0x5acf4179, 0xeb43f2d7, 0x79c7c79c, 0x70032c7d, 0x74b6058f, + 0xea40668f, 0x5d59b79b, 0x5eb6c03c, 0x1448335a, 0x188035f5, 0x15073032, 0x04b21035, 0xfe782f86, 0x4c8c1be8, + 0xa21c081a, 0x386162f9, 0x5da56646, 0x9ddf55e8, 0xa849215d, 0x64731c83, 0xaf9d5aba, 0x46ca6f3a, 0x6d5d1fbb, + 0x396c4049, 0x62a85dad, 0x0ad32dcd, 0x9a683853, 0xffd5aec6, 0x8f59d36d, 0xf19ad517, 0x9db934ee, 0xb5914a8d, + 0x59ff299e, 0xfafd831b, 0x312f1543, 0xffffdd21, 0x92694c35, 0x9d8635a9, 0x23c416fb, 0xdea7559e, 0xe7e84ae2, + 0x2774801b, 0x5fe925bb, 0xec4b9e95, 0x0deaaf39, 0x8ab1ef6b, 0x4bbc8f63, 0x0032e0f6, 0x301e216d, 0xecc9cf9f, + 0xacd73408, 0x6c28c2f4, 0x701fbf12, 0xe8ddad65, 0x52d609aa, 0x87d708c7, 0x83a80c0e, 0x29df2539, 0x494f5cd4, + 0xd87a0b9f, 0x42a2faed, 0xd1722e8a, 0x57639aa2, 0x892a3d7f, 0x437cf742, 0x6512a3b0, 0x395d527d, 0xc81fecca, + 0x3d69c387, 0xbe06b4db, 0xba994bde, 0xe190e16f, 0x7b505c8e, 0x0c1a6e08, 0x13085520, 0xedb43f11, 0x7985974e, + 0xb38c3b4b, 0x55db20bf, 0x636c490d, 0x2ebe6319, 0x2510b311, 0x6cbc37b7, 0x8e309922, 0xf3d8a739, 0xeaadce7b, + 0xa6f27788, 0xbc389357, 0xa79cd9da, 0xa2b734d7, 0x2a7ea667, 0x5739e6bf, 0xc03c288b, 0xaf9441b1, 0x7385abae, + 0x11397e9e, 0x16318397, 0xa2b269ad, 0xacebf366, 0xe620e0df, 0x836a12aa, 0xc01c18ca, 0xd3bc70ec, 0x2e00e276, + 0x4a14d7a4, 0x1c9d1189, 0x8849dea0, 0x5c073298, 0x05e4b2c8, 0xe71627c1, 0x6fd4d5fd, 0xf9b4304b, 0x0ff5cd8d, + 0xb898a686, 0x32f29ce2, 0x054775c0, 0xa0a34393, 0x8bd81ad5, 0x9e306843, 0x3c2954cf, 0xa04795b3, 0x7f969078, + 0x78d67563, 0x4891fb45, 0xab3d42b2, 0x12f472c5, 0xf33fcd97, 0x9ef7f990, 0xcc63554a, 0x6bacd830, 0x7d15f338, + 0x51c3a089, 0x8157e85e, 0xd24956bb, 0xb12ff240, 0x346ca25c, 0xce14b4a9, 0x3538ae98, 0xba10ff36, 0xcc7276bc, + 0x070d36f1, 0x3a16caae, 0x4af68ba5, 0xfa62773b, 0xdc651b95, 0xca5cb4f6, 0x88ab5868, 0xa036124a, 0x81d6cb21, + 0x325433f1, 0x43c90539, 0xd9bf8cf6, 0xacd2d440, 0x147d34b7, 0xf4bffeed, 0x0c95a902, 0xc6460f2f, 0xdb8c3c08, + 0x7c7460a6, 0x99f078c9, 0xb7fc1794, 0x46772545, 0x8c786686, 0x4496ba14, 0x6485405d, 0x19be6a7c, 0x6e51c091, + 0xe2de4532, 0x0f7c8757, 0x177fd4e9, 0x9f6d77b7, 0xa1efd98a, 0xc32a75f3, 0xccd6be35, 0x617a191b, 0x1259c0b4, + 0x9cbf766f, 0xcc75542f, 0xa2538aeb, 0x476574ec, 0xdf2d6920, 0xfc80028a, 0xacf0832d, 0xfbcbc062, 0xd30b9ff8, + 0xa77da1f3, 0x673eb70d, 0x2f692b2e, 0x9533ee6c, 0xcd4606cb, 0xab56b84b, 0x66140b0f, 0x52ed90e6, 0x46e97aca, + 0x09521fbc, 0x2521e754, 0x1bbf212c, 0xf16d1e3d, 0x5741b018, 0xd01ed01c, 0x9e832fd2, 0x5ace9547, 0x120900df, + 0xfc3d12ad, 0x4f5d5d2e, 0x17897747, 0xa65858be, 0xf0b51f1c, 0x4ae5d7d7, 0xb1a8e714, 0x84421942, 0x1cf062ee, + 0xe7559c15, 0xf824ad73, 0xb5d8f668, 0xae15cd88, 0xa87e81f8, 0x566fbb4b, 0x6d6395c7, 0x76a91cbf, 0x8e62f283, + 0x0085e77c, 0x0f31891d, 0x130e67ba, 0xb83d2cfc, 0x4bfa3253, 0xdfd7ae9b, 0x4e9015a9, 0x81e2f6a1, 0x55256008, + 0x043f4aeb, 0xf0bcb40f, 0xc0507909, 0x16f49e61, 0xf773539f, 0xc06919a9, 0xc120555a, 0xc288cf6f, 0x1a842fa9, + 0x4e56e225, 0xf56c4f2b, 0x504f747d, 0x6f38c14a, 0x1003079a, 0xdf25f0f7, 0xde317de0, 0x9f31ec70, 0x8f2aaee6, + 0xe92899ac, 0x38571e3b, 0x75209ba8, 0xee20785d, 0x38b7323e, 0xe07ccc37, 0x176deadb, 0xa612f0a0, 0x68eb0d39, + 0x0e44a6b3, 0x83e85d40, 0x05290ff6, 0x00d56765, 0x95a634c9, 0x4d802868, 0x177b09dd, 0x6989baea, 0xce395fec, + 0xb0b123ac, 0x1086fcb8, 0xc0e757ad, 0xfe8cb052, 0xca49d207, 0x70867f2a, 0x7715da1f, 0x51d45287, 0xf60b3030, + 0xc483fbb2, 0x2f6c0263, 0x7429b91b, 0x50666d32, 0xaac1069e, 0xf2f424d1, 0xd9e4e32b, 0xed523d5c, 0x1b49a9cb, + 0x31a4de8a, 0x7bd9de0f, 0xe1f5d0a6, 0xe5fb31b5, 0x7dfefbdd, 0x17dda5bd, 0xb906af9c, 0x7b573ae0, 0xc34f49d1, + 0x4fe8456a, 0x8c9b5435, 0xcc7203d1, 0xd0cfce25, 0x013785f7, 0x306581b9, 0x34a15e8f, 0x68119ef9, 0x255a9419, + 0x1227ec18, 0x146a8fab, 0x334582d5, 0x3ccc2c0d, 0x6bc28994, 0x6c2973b6, 0x1b4bde82, 0x48122f48, 0x46fe4f45, + 0x8e244cc3, 0xc7dc8cdb, 0x942f7c4d, 0x59320cee, 0x094c9577, 0x4b8ee8c7, 0xfe887af5, 0xecc31760, 0x8b6339f0, + 0x1489c2a6, 0x4e85439b, 0x3a38f389, 0x3a70b386, 0x13e19d72, 0x79e6ad25, 0x4705c0ed, 0x15694da5, 0x47cf0209, + 0x4499d136, 0x6fb8e8ab, 0x5bc43380, 0x584dc273, 0x16d1b304, 0xeb3f18c2, 0x7f6964ea, 0x7fabd577, 0x8cdabc79, + 0x7a1b52ab, 0x4fdf97f3, 0xc78f3a6d, 0x7cda477b, 0x879428e6, 0xf1aee7d5, 0x65479f3f, 0x07ae8ce5, 0xebe8ed4a, + 0x64e33681, 0x92777ae9, 0x7acc8e53, 0x7e12d4d0, 0x5c13fbaa, 0xd7438262, 0x34a6db5b, 0x33dba36d, 0x9f8533c7, + 0x250e4a4e, 0x4642a71e, 0x98e70873, 0xdfd15e7b, 0xdbaa21ce, 0x5f0b2159, 0x9b911e35, 0xcb0074f7, 0x13b15cac, + 0x5c0f5cef, 0x6511ebf1, 0x02538762, 0xd0e1ced5, 0x206b43ef, 0xe704b71c, 0xb689e7d3, 0xb84376c0, 0xcd8e040e, + 0x29bbecf5, 0x2539801d, 0x14895b3d, 0x1eb5ff3e, 0x03b09f65, 0x0820867e, 0x521121cf, 0xa5a9dc3c, 0x94a2dfd3, + 0x4d6548a7, 0xd9af24ea, 0xd6a82b7e, 0xbd0c9e10, 0x92915dc6, 0x9c47afc8, 0x6e6efdb2, 0x29dda078, 0xa31010ec, + 0x79b9d7f6, 0x88d1c06a, 0x510a36b2, 0x7c5210d8, 0x61afb9c8, 0x334b566d, 0x7e0e16b5, 0xea788575, 0x0089931b, + 0xd471ed56, 0x3bd71d3c, 0x87c07658, 0xef604db1, 0xde0c2b3e, 0x8511b43e, 0xa0762cf6, 0xf332995c, 0xb4914117, + 0x6676fc14, 0x9cc9cf50, 0x696d6929, 0xa6ac0157, 0x55d711c6, 0x5ff5393c, 0x71e1af63, 0x83cef989, 0x798cc00a, + 0x53b3fe31, 0xf126014c, 0x73bd716d, 0xf46342ba, 0x5014cb81, 0x0618471d, 0x4a32faac, 0x4df91d3d, 0x56c23086, + 0x031064e4, 0x07871b98, 0xaa4b9f47, 0xb0a23a22, 0xbb69ee56, 0xdc1368c8, 0xaa1592f4, 0x08b7049b, 0x4f04113d, + 0x8f926e67, 0x2818abee, 0xa5fc1dc3, 0xeb4ddc95, 0xb288debf, 0x55aeea8d, 0xe521f7bc, 0xb191c4b6, 0xf958aa34, + 0xbeb7b690, 0xcc02e556, 0x3b5fa3a4, 0xe4529ce5, 0x37fc1fc7, 0x2bb483fe, 0xd30935c8, 0x2fff90d8, 0x20d82597, + 0x88baceea, 0x3fc64e58, 0xe1842d09, 0x84b286d1, 0xb6d1ce7f, 0x2e582389, 0xad6ccc08, 0x38019093, 0x1b046f5f, + 0x4732523a, 0x8bd6f00b, 0xefb5e02a, 0x52025e23, 0x8aa64941, 0x55b07a28, 0xf04ca9ee, 0xe5a6fede, 0x54870107, + 0x64e7ab34, 0xf892408a, 0xf4bf877b, 0x64190678, 0x5fbe314f, 0x204574f2, 0x4e63144d, 0x5830cfa8, 0xb9d0c42c, + 0x425f7802, 0x41adbc6e, 0x88af934d, 0x207cab0d, 0x74448106, 0xb2cd3e55, 0x7c92ec55, 0x7e893846, 0x124615ed, + 0x5fb33665, 0x3ad94f37, 0x43911c09, 0xe827794b, 0x53bfee8a, 0x2739500f, 0x201568c4, 0xb2a3ca9d, 0x2d3c781d, + 0x089eece6, 0x3a1a5715, 0xb61b66a7, 0xeae5ba8a, 0x8cc8647a, 0x5a518511, 0xcec239e0, 0xbfa38a70, 0xdc64f001, + 0xecc00079, 0xd0806818, 0xb2e5f1f8, 0xa3894a06, 0xf7ef9e10, 0xc757c29d, 0x55acc0f0, 0xb212f334, 0x44d944c4, + 0xebe7cfbf, 0x2d3f3f82, 0x513c9da7, 0xd872f9ff, 0xd7ffd4e8, 0x807b9ca3, 0x024d59b7, 0xffeae185, 0xa474238b, + 0x9736bea2, 0xe19d4c86, 0x6a67de47, 0x89d466f1, 0xfd6d6a4c, 0x33d5c637, 0x9b2214ab, 0x32b01e76, 0x4d18e072, + 0xf6f6402c, 0x671b05a6, 0xf9e140b6, 0x8f3d3cd5, 0x7d70a31d, 0x202be2f8, 0x877bdf91, 0x6201231c, 0x340542fa, + 0x2cf75f41, 0x0cc00359, 0xca6dc3f7, 0x54d00bf1, 0x2cae5340, 0x9e3265a2, 0x4c418d1c, 0x08526c90, 0x56745742, + 0x50f10d98, 0x0aa7576d, 0x02f81ede, 0xc33f7ee2, 0x048dbc7e, 0xdfe0674f, 0x4d3ea73c, 0xd99c5004, 0x1cd8d946, + 0x13121123, 0xe25b9348, 0x8aee3a42, 0x83a97228, 0x5e05ae36, 0xc0c25f29, 0x05941f7d, 0xd5545ae0, 0xd51d206b, + 0x18b80632, 0x4a4d8958, 0x4428972e, 0xfc4c933c, 0x127175bf, 0x6fc05551, 0x1523bffb, 0x7a3bd294, 0x7e5bede8, + 0xf0250ff2, 0xea70b014, 0xaad62869, 0xc6b17730, 0x64abb345, 0x57d0c5f8, 0x65c74b91, 0xe298cbad, 0x64bf50f2, + 0x1350c089, 0x3f597426, 0x449220de, 0xa30c563a, 0x3eeb31f7, 0xac0f8fca, 0x694031fe, 0xd8306f7e, 0x72034e03, + 0xafed8131, 0x4b8acad6, 0xd3f58299, 0x65d568a1, 0xbba78b61, 0xbb70289c, 0x269befd2, 0x63b4b942, 0x106cb16f, + 0x6f20f07d, 0x0bcd2887, 0x504ff7a6, 0x10d1fc33, 0x4f46de94, 0xace1e3e7, 0xd751777f, 0x6f756d60, 0x957e39c9, + 0x5afaa66a, 0xf31d00fa, 0x29c37475, 0xcd1a5903, 0x56fbac3b, 0x1c155c3e, 0x8e7a098f, 0xe8218af4, 0x6d65af83, + 0xb04b1f4c, 0xc6e8f07d, 0x129c574e, 0x89cba694, 0x670d0e0c, 0x24c34519, 0x9b9ff95b, 0xb1b57e6e, 0xe13240c7, + 0x04fa7c19, 0xbe530c5f, 0x6ecd9028, 0xde370c00, 0xd2d4ee65, 0xac022b76, 0x640b6ee9, 0x13ddcf9a, 0x0822e884, + 0xcc0ecc90, 0x7f213dac, 0x7c250fe9, 0xbee7c35e, 0xe94a053c, 0x8ee7e2a7, 0x65d03f72, 0x8fa17244, 0xa8395559, + 0xb37f3f7d, 0x63824c61, 0xe398c478, 0x20f46764, 0xadaf6065, 0xfe29e1bb, 0xc4e6c0d3, 0x4b049036, 0x6fd3487c, + 0x5417cf13, 0x5b174b1f, 0xdc6aaadd, 0xa5e3bd07, 0x81216cd3, 0x663dc812, 0x8f7b9e56, 0x792b9df6, 0x870cee5d, + 0x94209f26, 0x1d04aa08, 0xe60b99d1, 0x39b6dbc6, 0x83ee266a, 0xf96ac52f, 0xf2f72785, 0x32738293, 0x1a833093, + 0xd859df6d, 0x73da5018, 0x94b9cf01, 0x95a85706, 0x3a91ceac, 0xf85f7421, 0x40cd16a8, 0x4daf6548, 0xbae18844, + 0xf212e351, 0xf491f498, 0x956a563a, 0x26c6a7ab, 0x82fbb3bc, 0xdc5fc994, 0x5d874a95, 0x99362488, 0x5e3fa7b9, + 0x06c3aa42, 0xbfb5c10a, 0x5281d6f3, 0x66c4513f, 0x8d5e7fa7, 0x00765348, 0x0854994e, 0xa0cbe43a, 0x30f01373, + 0xea95af89, 0x25967c8c, 0x3192d449, 0xae74db1d, 0x34584e0f, 0xb13d9d2e, 0x64a2f305, 0x4ffc9819, 0x13bb6818, + 0x4caaa87d, 0x33b5903a, 0xa1aecc4e, 0xd1a244c0, 0x657de025, 0x9fca20aa, 0xb7ac6420, 0x1b85881f, 0x5e704805, + 0x10984088, 0x2b132c28, 0x61c64033, 0x904c6c66, 0x4fb93379, 0x4da7f285, 0x30ad3f4e, 0x0869ff36, 0x2131bd69, + 0x416ee22f, 0x4377fabe, 0xdac883c9, 0x2d2902c1, 0xa1999000, 0x7eafc561, 0x7c8df29c, 0x70d746f7, 0x89aa550d, + 0xda745581, 0xce239820, 0x0f24b532, 0x48e5b5ce, 0x46048f92, 0x1c60814a, 0x6f3a4585, 0x8c8821d5, 0xdb8674af, + 0xc6b70d36, 0xe986c391, 0x735b33aa, 0x8a12a0d4, 0x91fbef72, 0x7ecda6e3, 0x460c8154, 0x0ac09d66, 0x97506209, + 0x71377877, 0x952d4e65, 0xc867616d, 0x89a0c3c8, 0xa8b98feb, 0x77ead120, 0x89faba2e, 0x6845ea1e, 0xfe4b7c98, + 0xf3b605b4, 0x7c9e3222, 0xe3e6102a, 0x76a75315, 0x358e31a7, 0x40e0d950, 0x958c5792, 0x063f7361, 0xd35a09ba, + 0xd42838bb, 0xb8e1f5f0, 0x1d33a858, 0x3c963047, 0x10b88bba, 0x205c02be, 0x1551cde6, 0xc3f0d1d7, 0x8614261c, + 0x9ba3170c, 0xdde65a10, 0x06d22e91, 0x93dbfff6, 0x012ff7c8, 0xfc304ef7, 0xf7350b8f, 0x92aa1ac3, 0x4f725e29, + 0xe1ec0a33, 0x49c957d9, 0xb0d215f8, 0x3fd254d9, 0x8d0c1e51, 0xf13a8b70, 0x6e54fcdc, 0x9d1ecd63, 0xe7f12c20, + 0x1a26b518, 0x63b0bd48, 0xe506719d, 0x9fdb1a97, 0x1cff5bda, 0xdc8897ef, 0x26e6025c, 0xd30ca1bd, 0x4c75a412, + 0x7db0ee0d, 0x8835be43, 0x2abe3d91, 0x02da4801, 0xed07ec95, 0xc60ec5ef, 0x80517298, 0x9894858f, 0x88a20f3b, + 0xfaa08b6e, 0x77d2e86b, 0x7495062b, 0xf5c9e007, 0xa648d4b5, 0xf6ca1b75, 0x4ba7bed4, 0x1cc818f7, 0x893fe97d, + 0x52b526fb, 0x98cc5f87, 0x9ff5ba65, 0xe07efd15, 0xc55c6dd6, 0xb55bbc25, 0x52437651, 0xe0a1d607, 0x95b6bd91, + 0xc155c793, 0x8ecf4dd9, 0xa94362e7, 0x83e3ed18, 0x1a083491, 0xc711b5f5, 0x22309dff, 0x26703b12, 0xcbbbda6f, + 0x1d036740, 0x4f143c54, 0x0e0fb8fd, 0x3b42e1da, 0x8747108e, 0x65fd141d, 0x12765575, 0x9ad43bd1, 0x77ab360b, + 0x749fe5c4, 0x3596aa6b, 0x08ef8144, 0x7a205951, 0xb988aea1, 0x60355888, 0x0edd3523, 0x97687cef, 0xbc741fe8, + 0xd4ee6af5, 0xdd9b488d, 0xfa4c5a40, 0xe4ba0ff6, 0xbababaa8, 0xa3c9f6a9, 0xb32851e0, 0x7f833620, 0xf8cfa0ca, + 0x651b842e, 0x04dc9c9c, 0x26440ca2, 0x5a0a9daf, 0x7fb991f8, 0x14b3095f, 0x48144801, 0x6d9ec9db, 0x813256c2, + 0x80de4add, 0xeb63ff5d, 0xb1ed52b1, 0xe71470e1, 0x1970d474, 0xe0caac9b, 0xefdfe0ca, 0x968a6cf8, 0xe1f3eacb, + 0x1d330847, 0xf6ebe18e, 0x73d00a36, 0x85130e4b, 0xd9d68ec2, 0xd8bfb2bb, 0x216cf56a, 0x813cb777, 0x948db445, + 0x139c52fa, 0xe42929dd, 0xfe575b64, 0xd96651be, 0x31a9a3ba, 0xb8812747, 0xab866a01, 0x926eed64, 0x98d1dbdc, + 0xc8a12a39, 0x4216a07c, 0xc898f2c8, 0x3c642980, 0x42ff8340, 0x79d93f4f, 0xa5742677, 0x446d8a73, 0x76c1b5f2, + 0x067cb2fe, 0x0714efbf, 0xd5123525, 0xd7f8bec5, 0xc4f92495, 0xf01ad4af, 0x97b0eb1e, 0x20b666f4, 0xda843b9d, + 0x467ce7dc, 0x084d8810, 0x0a222d5c, 0x93aa51f7, 0xbf6e4fab, 0x8787e005, 0x0b195441, 0x50fbe92e, 0x869e6cac, + 0x5dc0829c, 0x0b89b629, 0x7abb31c5, 0xc62ef30b, 0xf89cc160, 0x10820edc, 0x7f0cbfe2, 0x39627f12, 0xa44695ff, + 0xff6fb5d0, 0x916f06d5, 0x64d6551d, 0x809a0dea, 0x7715594b, 0x47c48066, 0x9806ca8f, 0x7ee667d1, 0x67ee2bd4, + 0x0c899af5, 0xd2031712, 0x8d69977f, 0xbd172fe7, 0x2b4f706b, 0xc5619896, 0xe5a2687a, 0x0f97d5c5, 0x7cbc0395, + 0xb6509784, 0x4d0f4c92, 0x205f733c, 0xc0ceccc8, 0xa99bb833, 0xe0452970, 0xd390d64a, 0x809ccd28, 0xa1b1fdc0, + 0xec9086cf, 0x9db39f13, 0xc16f7ed6, 0x9e879614, 0x22224c00, 0xb9feb098, 0xbe029ad3, 0xd42073f4, 0xd38d1198, + 0x5bc9ac33, 0xbec8956a, 0x7fc03668, 0x30f167ba, 0xbcbf7d90, 0x7e20cf3a, 0x6d5eecc9, 0x34de349f, 0x142ff794, + 0xa36c7571, 0x8a96f291, 0x3293e4c4, 0x253bd919, 0xcd87a6c4, 0x5d5655cc, 0x64479f73, 0x2af286bf, 0xd0ce934e, + 0x17dcf4ae, 0xfc0e4f84, 0x3a7de08c, 0x7bc84038, 0x7b4ca414, 0xfffb2f2c, 0xf30af91b, 0x7406e019, 0x38160eda, + 0x2297967a, 0xee713fa2, 0x4db15e53, 0x51754611, 0xf97f3107, 0x5cd1557b, 0x6a0a1af3, 0xc779ab98, 0xe5043d85, + 0xc97b23dc, 0x424a7b55, 0xb9ef8682, 0x8af6b765, 0xfb3d7e22, 0x3c1cb356, 0x27ef1657, 0x90113ffe, 0x7eb4d153, + 0x437ae5b6, 0xbab4f68a, 0x4e583991, 0xd057acc8, 0xdeb6dae2, 0x92dca040, 0x32a23287, 0x064c1e6f, 0x48e620d4, + 0x3b79f036, 0xc774d970, 0x6b3c09f5, 0xfba2d159, 0x54963931, 0xd3dfe229, 0x936eac66, 0xa935c714, 0xf11d5910, + 0x632b2533, 0xc8a691f9, 0xe397ea09, 0x07c99bd1, 0x94757afd, 0xb888cdf1, 0xa76fbc0c, 0x10baf2ae, 0xdc9a6347, + 0x3f7b52c1, 0xca68b969, 0xf4fef284, 0xd509f502, 0xe1034793, 0xa21f029d, 0x06e84a6b, 0x963b3bec, 0xd6c6cde6, + 0xb45680a4, 0x19888087, 0x604b340f, 0x627b1df9, 0x07883822, 0xdc071ccf, 0xca7d8a94, 0xe760453f, 0xa487a62b, + 0x0bc0dfc1, 0x4859b3c5, 0xa4cd6b45, 0x0581f1b0, 0xbdb6d301, 0x6c73bd60, 0xbfa8edee, 0x5ee38216, 0xd3112bc2, + 0x97092bde, 0x9a22ce08, 0x86308417, 0x147be9a8, 0xcb6d69ac, 0x19d2edaf, 0x0e46901d, 0x334eb9b1, 0xf3b8eda5, + 0x3047fe89, 0x163f6cf9, 0x954c26cb, 0xca437b7e, 0xfd26c1fa, 0x0ca85f90, 0x6bf53b25, 0x9983d30d, 0x44df3ca8, + 0x91152524, 0x32550dfe, 0x212f2ff1, 0x651bccec, 0x8faa19b8, 0xf86ff581, 0x4dd5a21a, 0x764aaf2a, 0x5aff2165, + 0x45153314, 0x9bacc2b5, 0x90a7d803, 0x4fff4c96, 0x1bd21c36, 0x7c35243e, 0x0bc9b837, 0xccb21ae5, 0x7db539ec, + 0x1976ebce, 0x1ae0011c, 0xce275cab, 0xf1ff138f, 0xf2fc02e2, 0xc544b974, 0x590526f2, 0xdcf53672, 0x76469ed2, + 0x46578db3, 0xb94db783, 0x95b95212, 0x7c4d76e5, 0xa3c35e07, 0xa1bd4202, 0x33457a6c, 0xdf2ac5ee, 0xef6084cb, + 0xf8581c97, 0x52a27710, 0xf0f2590a, 0xd6ff20f5, 0x7004bb8e, 0xb0090be2, 0xdbd63ab9, 0x305b89f0, 0x7a9c74c7, + 0x3c6dfe28, 0xaf159aa6, 0x4be9c8f5, 0xb296d7ce, 0x60438496, 0xd5ec8460, 0x6059342e, 0x6d98bd28, 0x99efad33, + 0x3662ee53, 0x209be32b, 0x12e5b0d6, 0x0a55e45e, 0x34d8b5ec, 0x9b1d082e, 0x2bf4c99b, 0xccf0e403, 0xb14bbd05, + 0x4ffcf803, 0x65ee6da6, 0xd6a33ae3, 0x9ca1c4b3, 0x5e223ceb, 0xf59e7d07, 0x213d2281, 0x63f027c3, 0x8a39abfb, + 0xdd84e09d, 0xa5e549c9, 0x18ed4185, 0x8064694c, 0x0be9e718, 0xbf6845d9, 0xb93524c3, 0x31bf097a, 0xa70b2d97, + 0x66af51ea, 0xf31061ed, 0xea872952, 0xec0eda49, 0x09fb8b72, 0xcab71cda, 0x52390311, 0x6ce42297, 0x2c503837, + 0x5304e804, 0x4161c95b, 0x466d210f, 0x68af4d37, 0xc00d9d92, 0x3fa1f1c8, 0xbc5df754, 0x511036d4, 0xc5f61f7e, + 0xdfbdd891, 0xc7b7efb5, 0xa9277f97, 0x06e738ca, 0x68de6388, 0x7802cbdf, 0x1faefa87, 0xc64567a0, 0xb7df1665, + 0x7a659d82, 0x52fbe902, 0xeb0aec0e, 0x58cc2eb6, 0x4d3d576e, 0xd6a23a13, 0x185afbaf, 0xd33178e4, 0x30dabbaf, + 0x5a3fc4db, 0x1cce7794, 0xe98d8e43, 0x94f92231, 0x4fde122f, 0xf22330ac, 0xb1ed518f, 0x88259909, 0x10d5207a, + 0x69bc02de, 0xd3b0f3c5, 0xc9f156e0, 0x7ced138a, 0x07d2de04, 0x6c859fbd, 0xce0262d7, 0xc411a1b1, 0x6cc84f39, + 0xb73aac7b, 0x9c80052e, 0x5e00106a, 0xcbe3e9fd, 0x3685afed, 0x05abbe1f, 0xe167236c, 0x30cc193c, 0xec01602a, + 0x9a2ccff7, 0xb712c20f, 0xeca53d90, 0xcfefb374, 0x015a3270, 0xf23709cb, 0x15ba8320, 0xaa89e991, 0xd23b4316, + 0xe8f74393, 0xadb999f7, 0x5b5a3e57, 0x9d3d8f36, 0x68552190, 0xb4584b5f, 0x9e459a64, 0x414caeb9, 0xc86658a4, + 0x3fe4cbb2, 0x94efac13, 0x642460ae, 0x0fb35d4b, 0xeae9a18f, 0xacffff32, 0xf56ad08f, 0x8fa444ae, 0x97685f8b, + 0xedf374ef, 0xf470bb14, 0xaeb76455, 0xa560b01d, 0x1d77938d, 0xf49e1fa3, 0x3c55dd81, 0x5b212e2e, 0x5ea100b5, + 0x187d2ba4, 0x841c9250, 0x5fae6577, 0x737e23cb, 0xcf3edf46, 0xd8b6058c, 0xfbe05da9, 0x428483fe, 0xbbb3ab96, + 0xd58eb096, 0x83adc222, 0x006d8dd5, 0xa150748a, 0x7d2a6206, 0xb8418105, 0x70ddb9ca, 0xe73c186e, 0x2421d049, + 0x624c7c95, 0x0e551e24, 0xa627a2d5, 0x0b13c0a0, 0xa932cb3a, 0xfdca6445, 0x584c600c, 0xff72b1e4, 0xb74fb774, + 0x05be8f93, 0xbfdb84d6, 0xe7d3fd7c, 0xdb396bd5, 0xe26328ee, 0x9534ea3a, 0x355c353e, 0xa4de8443, 0x2ad70e7a, + 0xf98fa235, 0x97200937, 0x5c1a4b52, 0x902109fb, 0x2a7f1ac7, 0xddbefd63, 0xa3e54c28, 0xf7bcc90a, 0x320033f0, + 0x98dbd22c, 0x3aa4d0d0, 0x68d16d60, 0xe4d223d6, 0x9404038a, 0xf4975181, 0x12811aef, 0xdd848a3b, 0x4ec0666b, + 0xa29359d5, 0xab78569e, 0xfc2ea7ed, 0xaea710ed, 0x4c2a6a8f, 0x56ca1dbd, 0x2aaee149, 0x24a76cb0, 0x9aed5574, + 0x85290295, 0xd615fce3, 0xc6f737f7, 0xcf30f997, 0xaf4be277, 0x6260ea6e, 0xd1885010, 0x012f4ad7, 0x37c51f67, + 0x33bfb130, 0x9a63a245, 0x4387e9ee, 0x9a236f99, 0xdd6937ff, 0xc88014fa, 0x7e0f436b, 0xf8c6fb73, 0xe0ce56bf, + 0xa0da8148, 0xe395167b, 0xb3251184, 0x8b491350, 0xbe95d250, 0xf041a544, 0x90c02b26, 0xf5c83f07, 0xb8cfe1d3, + 0xdec90b2d, 0x37505d06, 0xc62f387b, 0x327a1338, 0xd0357310, 0x519f135e, 0x9d059342, 0xc6784b20, 0xf3816338, + 0xb299cfa8, 0xf8d9ffef, 0xecef3538, 0xcce06abc, 0x6e2de5b1, 0xb7ef14cf, 0x1d7ea110, 0x9ef10220, 0x34a27bf4, + 0x54d4ac8b, 0x30adc1f4, 0xe8196687, 0x87d67023, 0x05c81a6f, 0x0e436819, 0xe0041cd2, 0x0274c439, 0x446e013c, + 0xb2ae23a9, 0x278749f1, 0xa2949154, 0x6204f556, 0x6beba18c, 0xedbb9d1e, 0x94d0e209, 0x5d211edf, 0xb1f7ec2a, + 0x51776df1, 0x9e1f1461, 0xcdcb0804, 0xc75cf2ae, 0x5fbf0c7d, 0x1ee4a0cf, 0x5131eeda, 0xa1f69398, 0x193f3f9a, + 0xf9610208, 0x0796d681, 0x5e39734e, 0x1d6b775c, 0x7d6b90b8, 0xc3d05bc7, 0xcd0c2334, 0x7647e389, 0x02540069, + 0x2bdc643d, 0xdb0c1df2, 0xea4969cb, 0xdf4c924a, 0x92bfa1a3, 0xea08277c, 0x6f303be3, 0xbc6fa379, 0xc851daa7, + 0xb29c2025, 0x18315523, 0xcacca44a, 0x04221d32, 0x4f70e8f6, 0xaa19cb1f, 0xb4de2b05, 0x5ea42df9, 0x7aa54b53, + 0xedd8d8bd, 0x20c1c41d, 0x0d76abb4, 0xb17c877d, 0x919f46c4, 0xa4d7e633, 0x46007f6d, 0x3e4bd6fd, 0xa931ce57, + 0x54236b66, 0x78ef11e6, 0xa4b4cd68, 0x803ba692, 0x38e8b2eb, 0xcbe2109a, 0xd6088e46, 0x8451baee, 0x5e4e4748, + 0x52550851, 0x33e85f23, 0x361bee75, 0xeeb0d427, 0xc1d9928b, 0x5614db36, 0x5c793488, 0x82bfa198, 0x7f326f03, + 0x1c5170f0, 0x421938ea, 0xfc745403, 0x576682ed, 0xf234ee70, 0x93f83330, 0x9e9063cf, 0x6de8bc34, 0xd484de53, + 0x155fdbeb, 0x84368122, 0xee281c91, 0xb2029ea1, 0x6eef198b, 0x58c6f0b7, 0xaa73b8c0, 0x31f77022, 0x9ecda988, + 0x4d27e131, 0x3a0d8c87, 0x71bbd406, 0x151b2ec0, 0xb74a05e1, 0xc05b2f12, 0x0a8a3c75, 0x9048a750, 0xb2b1af18, + 0x732af51c, 0x488b796b, 0x00b3e75f, 0x0cb16642, 0x8481583d, 0x4074cc53, 0xa0908024, 0x28e9301b, 0xdc53e0ac, + 0xbe27d73a, 0x7a1f1802, 0xa53da332, 0x0e62b3e8, 0xe5721d59, 0x13806347, 0x83dc1edb, 0xee65c5d4, 0x1ef3be2f, + 0x686480c4, 0xd0de34ba, 0xd9302bad, 0x155b3502, 0x34eb270c, 0xee2a3771, 0xa51be8f2, 0x5f54b29e, 0x83e8c7c8, + 0x2211f34c, 0x1befbda0, 0x1f6aa8d5, 0x45d9450d, 0x1e6078b4, 0x7a013e1c, 0x998d9a0d, 0x008d24b1, 0x9bcd6c7b, + 0xbf429bba, 0xc3f75d0b, 0x48d58041, 0x3835a68d, 0xddaf43a3, 0x89176293, 0xe4edfd8b, 0xdeb39ef1, 0xc136928a, + 0x47f39de7, 0x09d360a9, 0x359bdd38, 0xb360d102, 0x606d7c61, 0x88229648, 0x6a61b88b, 0xac50520e, 0x86a58656, + 0x8bf44bd5, 0x0e739feb, 0x7bb12b51, 0x8daccc08, 0xce817582, 0x8c21a13c, 0x4a4a0127, 0x6c7b5cda, 0xa140087a, + 0x1ddd22ef, 0xb2d68040, 0xd401b9f7, 0x2610a884, 0xbb50454d, 0x610648ac, 0xeb73c3d4, 0x4660dcee, 0x3b584774, + 0x357d2e55, 0x0daa1b0e, 0x731913fa, 0xc05192da, 0x07a8ac6b, 0xaaca8fad, 0x53989136, 0x9047bbfc, 0x86613f5d, + 0x550161b9, 0xa359158f, 0xac29d1f5, 0x66ae225b, 0x96e49de2, 0xe75b801f, 0x267e3afd, 0x01a11657, 0x83d8e22b, + 0x353346d5, 0x57c57cd2, 0xae0a1f7e, 0x78b74fbe, 0x17977487, 0xcea43038, 0x9cce5708, 0xb6062391, 0x01de3a56, + 0x2d3550b4, 0xeae5bb07, 0x1eb186ab, 0x8599a56a, 0x52df8dc2, 0x842c4d50, 0xc10bfb52, 0xf39d5ebd, 0xdf5d8747, + 0x18905a23, 0xfd562a02, 0xdcf09e05, 0x4b6a0b24, 0x3116395a, 0xf822a226, 0x85384adb, 0xd007e358, 0xb5f7e462, + 0x2230709d, 0x03210af0, 0xc2286f37, 0xaedb1f49, 0xe3c0fdb1, 0x5fda7000, 0x4f277ecf, 0xc5100fac, 0x3f092df9, + 0x042e98bb, 0x48ac11e1, 0xf83105ae, 0x3a455c53, 0x953ea9f9, 0xcf3eeb6e, 0xca54a436, 0x7fd39d27, 0xc08a1644, + 0xf169efef, 0x65de8ad4, 0xa37490dc, 0x2085377d, 0x6f7eebac, 0x4846f447, 0xaeadf6ea, 0xb0df1d57, 0xa7ea37c4, + 0x05870208, 0x7017c81d, 0x8b094276, 0x34b44a5e, 0x45d62b01, 0x54d7b959, 0xf621edee, 0x94397eab, 0xb08923c0, + 0x09f7c8c4, 0xea877375, 0x55a518d2, 0xd161fef9, 0x586895b1, 0x2ea5ec59, 0xbb890cd8, 0xe349207a, 0x6ffabc25, + 0xaa4959b9, 0x6727fb5d, 0x0eeabfd8, 0x6d36b108, 0xbd317909, 0xdca7ede1, 0x98a4e462, 0x74c54eaa, 0x7fa47532, + 0x9d317678, 0x54ecb416, 0x19619a7b, 0x685ecbf9, 0xb800f7a4, 0xe3a61e6f, 0xa1d1a416, 0x319cbd2f, 0xe64a314e, + 0x4bfef43a, 0xf43551fd, 0xb7f43482, 0x5a081f17, 0x04bc0c63, 0xd7432cef, 0xdcaf88d0, 0xcc76b1c7, 0x56575573, + 0xa87bec9e, 0x98209aab, 0x54d7ce81, 0x44e235b9, 0x4ed1d06f, 0xc61686fe, 0x108bf134, 0x6e8ff959, 0x1b27c851, + 0xeab38897, 0x315717bd, 0x5a10a09e, 0x507d170d, 0x8dea8c30, 0x40438196, 0x7d3a7074, 0x3a5ed84b, 0x96ddf46f, + 0x6e134296, 0x749b6bd3, 0x3112be10, 0xde252058, 0x3869225c, 0x4e15a494, 0xdc6b949d, 0xacc38e38, 0xac347fbb, + 0xb5c4b6bc, 0xe9be0f8f, 0x05bd184e, 0x81590ef3, 0x6881e41f, 0x285b65a2, 0x486b5d93, 0xd1a267da, 0x01aaec96, + 0x6ae5de9d, 0xec2e1ffc, 0xd177fe2c, 0x6fbc9cd0, 0x4c634b62, 0x547b9054, 0xcc00052e, 0x3237aa63, 0x440a624c, + 0x8137da5d, 0xa32495fa, 0x54220e2b, 0x9972d60f, 0xd2dc13df, 0xfb4c6e42, 0xb611b6a2, 0x4a1d8ca4, 0x95860d64, + 0x7e23a9d6, 0xe577d135, 0xed052238, 0xf4e638f5, 0x12506b4f, 0x2423a665, 0xaf37b8e0, 0x72911b7f, 0xb83ac12f, + 0x6c1a0622, 0x1f4b96df, 0x0acd739b, 0xc2d3f2b7, 0x6d9efe88, 0xe5ecf375, 0x2cd1e4cf, 0x64aef587, 0x9928051d, + 0x5eb59cbc, 0x0560f1f3, 0x8652316e, 0xde535852, 0x790063fc, 0x0f4f60b2, 0x4036fa7c, 0xf83ab78b, 0x246c8815, + 0xdc51fdde, 0xbed2694b, 0xfc73ad38, 0x1870847f, 0x74531be4, 0xdb7e219e, 0x1c9c6211, 0xe4dcbee4, 0xbcf71327, + 0x43947ccb, 0x2c878977, 0xf2cceb96, 0x6ec3a460, 0xdb474707, 0x4130bb8f, 0x415fad79, 0xf437bb49, 0xc74d83d0, + 0xc2eb90f5, 0x10af8b20, 0x89b4d4f6, 0x966ab0e8, 0xdc25c1fa, 0x7f789e8b, 0x90ecb893, 0x7d4f44c2, 0x2c936540, + 0x3ce08498, 0x3dcb8757, 0xcc8bc445, 0xc12c2b34, 0xcf9f572d, 0x6afff8c9, 0xc5945cba, 0x143129fb, 0xeb3b3d83, + 0xc7cab8a2, 0xac184694, 0x36b3de7e, 0x6bbea561, 0x6b46f143, 0x380ea764, 0xbe352ae9, 0x6e0b7407, 0x2db76e9c, + 0x22e81b55, 0x784ec6eb, 0x7c54c133, 0xe467aa03, 0x69aae710, 0x2577f4a9, 0x35d8b7ea, 0xddbb1741, 0xffa98315, + 0xa99c5577, 0x32409798, 0x66adc359, 0xba7b1542, 0x2f6f1d96, 0x50662132, 0x457209a2, 0x2a19b9bd, 0x93c4d4f0, + 0x3dabee8c, 0x47baecb6, 0x60cb99a5, 0xb2c6367f, 0xd3b4caee, 0x5cdeb7af, 0x2521a7b9, 0xfca90ee3, 0xb76b74a4, + 0xb1e85887, 0x86b6fe67, 0xa9232231, 0x8608c6e1, 0xa4a5d3ad, 0x362a5eb1, 0x240fbd72, 0xa9e1f6ba, 0xf99824f0, + 0x80078da3, 0x62ac218c, 0x1d4e4855, 0x5c8345c5, 0xd2b3604d, 0xd29bd416, 0xd3453069, 0xd336bb42, 0x8a438d26, + 0xd1925e03, 0x1ab80734, 0x9128896c, 0x6d4cb40f, 0xf71fdb26, 0x1426b015, 0x8504b122, 0x5433b51e, 0x4231b473, + 0x4d943fd6, 0xaf307807, 0x830e5dc9, 0x82cd4c8b, 0xe177356e, 0x463bd814, 0x1c624651, 0x3a49262d, 0xe8269cdc, + 0x69fbe3cb, 0x63e39394, 0x8b9022e1, 0xbe82b8e8, 0x4ada915a, 0xdec07b92, 0x21a56da3, 0x87eb06c8, 0x77fd0179, + 0xd476856c, 0x8867a2f7, 0xfc93bd61, 0xb8e59ce8, 0xc521803c, 0xf5385c13, 0x81091baa, 0xea8d214b, 0x05d8fe42, + 0xa68c3e80, 0x77d3e09b, 0xa02f2b6e, 0x13aa59d4, 0x21960e21, 0x876837c5, 0xdbecce6a, 0x31953625, 0x0a55b6b3, + 0x997386ff, 0x0bc98cc2, 0x41776bed, 0x53bb816c, 0xa097efe4, 0xaede4300, 0x07f6f408, 0xcd4d8e0d, 0xe30adb4e, + 0xbcebf388, 0xc36cebba, 0xfc9723fa, 0x3cf3226b, 0xce4673a4, 0xc1e911d8, 0xa56140da, 0xb5720d84, 0x2e688e92, + 0x9c46b0b2, 0x7fd23845, 0x38433619, 0x285f50a2, 0xecccdf1b, 0xfad6bd9c, 0x75d56829, 0x395b5428, 0x01f74d6d, + 0xc3356e8d, 0x4b15ce34, 0xaae256d8, 0x77d13554, 0x48da4821, 0x4afbccfa, 0xb642c662, 0xa56548f6, 0x8fc7c0e0, + 0xe97797ce, 0x48d45281, 0xe783ea55, 0xf99f64a1, 0x4ae14145, 0xab25a3e4, 0x9116353b, 0xacc5c5f1, 0xcab3e223, + 0x5a0d228f, 0x6bc23f43, 0x9d9d2366, 0x23dd6cb3, 0x9a61306c, 0x803e087f, 0x6338adfa, 0xf9651d02, 0xb3014332, + 0xad5914c5, 0xdf4aaebc, 0xeb5f4909, 0xb3509586, 0xf6b935e8, 0x145a5536, 0xf47c41a8, 0x5ae14553, 0xcb279f2a, + 0xb8f81b1d, 0x6c9876fb, 0x1c2a114e, 0xc20985f2, 0x0b394265, 0xadf7fdfc, 0xfe2f7bf6, 0x8ff6e0bb, 0xbd2537fb, + 0x84d64039, 0xce06ae65, 0x69be0d66, 0x33f90527, 0x19549729, 0x1063b8b1, 0x5db83158, 0x32eba209, 0xb7bef5f2, + 0x8aab32e4, 0x8f696699, 0xa52f7a8c, 0xfed507f1, 0x233635d6, 0x3040fdb0, 0xbbc04238, 0x4c63c6cf, 0x6b5d708f, + 0x18e159be, 0x1e19a7cb, 0x29931808, 0x5232f115, 0x5ab1b015, 0xedcd8123, 0x7a31fc1d, 0xe7d20f42, 0x04cedad2, + 0x4518f8ce, 0x8ca2af25, 0x717b6d7c, 0xb4dd75d2, 0x63a60542, 0x941b5d21, 0x786da36d, 0x1f4f177f, 0x3dc717e7, + 0x7e6473db, 0x8bc97927, 0x7a8c93d1, 0x125381f0, 0xee4530b8, 0xfa9d1e2d, 0xa2e5ddd7, 0xeb449f83, 0xdecd4463, + 0xc1ce4984, 0xd302dca3, 0x17d1e6aa, 0x2d41248f, 0x30863e5c, 0xa83a9122, 0x22e6ebc0, 0xa7491f39, 0x469dae02, + 0xa6459850, 0x67803223, 0x4c5c4434, 0x453a29b5, 0x844f530f, 0x8a72ba42, 0x3dabc906, 0xc6f6e514, 0xaa6d64c0, + 0xa3d0c4fb, 0x72dd3be5, 0xb1910697, 0x370a2317, 0x95dbbacf, 0xbd0758b1, 0xacbe5735, 0xef3172ed, 0xc247e14b, + 0x9878fba5, 0x5e8afb9a, 0x2ebca86a, 0x4a90096b, 0xaaa557ad, 0xdf3f9b9a, 0x88353731, 0x757a98ad, 0x7e09c9d3, + 0xd7a22b5d, 0x3fe9150d, 0x4650040a, 0xed0db04c, 0x5f6c441c, 0xbb2af3b2, 0xac518b58, 0x26ede485, 0x8e3a079b, + 0xebdf1ec9, 0x014a4f2e, 0xda4a1907, 0x9bd17008, 0x5fe0d800, 0x2748225d, 0xb53715df, 0x1d5c0a40, 0x61da3f76, + 0x3fcd712e, 0xbfd1a0c3, 0x705e6395, 0xbdde10d7, 0xcc6ecd6e, 0x64abdfe4, 0x6913e825, 0xb2352da6, 0x81b008d0, + 0x97cb7a5b, 0x7a5ada19, 0xe4a9214a, 0x0523bb70, 0x5dd44c51, 0xc40162e8, 0xe7b59b86, 0x689955f5, 0x20e79789, + 0x9f170ce0, 0x741f2c6f, 0x2ce6a52d, 0xee083ee8, 0x4c0ff8e5, 0x071d9709, 0x6a5069b5, 0x83256e04, 0xa1bc0de0, + 0x945dc3b7, 0x966b8533, 0xa5b51e45, 0xa3a6e4db, 0xe36b9b97, 0x427f4e4a, 0xf69a0d79, 0xd33c36b5, 0x9dfeb7c0, + 0x685bfed4, 0x9b774629, 0x935bcc0c, 0x77ccd696, 0x4545c60f, 0x3eb142f6, 0x61e0075c, 0xfc2df36a, 0xc94ab180, + 0x4e574f55, 0x07a43b93, 0xbe6b4ff7, 0x3af33c2c, 0x28229c9c, 0x397df206, 0x3ec92e2e, 0x4aa093b2, 0x19398304, + 0xf65164a4, 0x93c29cf7, 0xf6565897, 0x542a37ce, 0x73fe1bb0, 0xaf5b89eb, 0xf4e09be4, 0xa0d573d2, 0x034c6186, + 0x0894be7c, 0xb8c3ea13, 0x50335d50, 0xcfb711d2, 0x812942f2, 0x60aa282e, 0x7647c21a, 0x9b4cf924, 0xf924c2f5, + 0xd4b6dce4, 0x7112c302, 0x7799a445, 0xdbd226aa, 0x2999f36e, 0x3c2dd861, 0x7dc505a8, 0xe13a1203, 0x9fdb1a3f, + 0xda9693bb, 0x071ef333, 0xc2e72f72, 0xd2dcc7f0, 0xa4063861, 0x10961065, 0x755c0241, 0x26cf35b0, 0xec582da0, + 0x1eb2f28b, 0xf6b1b80b, 0x46dc04ff, 0xc03f5159, 0x2286037d, 0xe462eaa2, 0x7f04192e, 0x6b9e3f35, 0x74862038, + 0xc287a445, 0x921270a7, 0x301e6409, 0x20481e94, 0x504a2d7e, 0x1f203e78, 0xefaf5fde, 0x6389b3b8, 0xdf7389d4, + 0xe7b1ff0f, 0x812d8e06, 0xbfbce712, 0x09df93db, 0xfc3ce33a, 0x3c98ef6c, 0x518642ca, 0xe7b118c7, 0xbb259ce5, + 0x05b69f34, 0x071ee8cb, 0x94acbc39, 0x93eb689c, 0x67868126, 0x48a22ac9, 0x63745638, 0x920cf9e6, 0xfef7edad, + 0x9ca51f8b, 0x730c2e0f, 0x51652c7d, 0x40ae0d24, 0xed748e56, 0x1b4ddb9e, 0xb9e3a31c, 0x3dea431d, 0xd5ac8299, + 0x04affc6b, 0x18a2d8c2, 0x23b1f7c1, 0x1f5dceb0, 0xe81ce2fa, 0x2b6c08d2, 0x0d139025, 0x93844e7d, 0xb705cb2e, + 0x30397c85, 0xa099a357, 0xb8370bd5, 0xe1fc1b2a, 0x63696122, 0x3fa7fd5e, 0x9752435d, 0x8297caf5, 0x1468404b, + 0xa58b9221, 0x7f37a5a8, 0x24ed2faa, 0x195136fb, 0xdddda08f, 0x74463e7b, 0x4adb78a4, 0xdeabcc04, 0x9d25e91e, + 0xf9865a59, 0x857f4c20, 0x733abe6b, 0xd59e2bab, 0x80dc7608, 0x153c7bfe, 0x0a1d3d16, 0x298e4caf, 0x63468e50, + 0x7612c680, 0x069fb860, 0xd9a78194, 0x727bcb43, 0xd8369dab, 0x4e272f4a, 0xd10dce56, 0x93866400, 0x2e746b05, + 0x1731b7d9, 0x11e35ea0, 0x544db4e6, 0x6679ffda, 0xb13398b7, 0x3e6a7da4, 0x574f8934, 0x83f2d7f8, 0xe7de0944, + 0x9a7bb1d9, 0xca55368e, 0xfc754e7f, 0x818ea5ec, 0xe75f8719, 0x760a1a12, 0x98adf395, 0xf87f485c, 0xa5d94cd6, + 0x43c8cb0d, 0x733283e7, 0xffe74406, 0x25ed429b, 0x7573dc3e, 0xe9201d8e, 0xf9adad78, 0x3cb3bc51, 0x0cba051e, + 0xdac1400a, 0x7d7aa228, 0xd69455aa, 0xb8a4fa60, 0x2f3e078d, 0x26308e8a, 0x6ff925be, 0x71eb8540, 0xcb94f63b, + 0xdde53403, 0xb8f54c26, 0x58778efc, 0xe06673cb, 0x0801671b, 0xb79c8f1f, 0xed176fb0, 0xd099df71, 0xaa677c29, + 0xadd8513a, 0xed0205fb, 0x88edcd1e, 0xb5010294, 0x00f5826c, 0xf2d6f0b1, 0x3b356b2a, 0xb6076830, 0x3a83caf3, + 0xd469b4cf, 0x75201005, 0x05d9646e, 0x98da1abf, 0x5de55df9, 0x79a4b0a1, 0x2a580821, 0x74b3d3e4, 0xc8bb8c3a, + 0x8eaa5e44, 0xed3102de, 0xb764a5c3, 0x189ac4eb, 0x77f74446, 0x403ac82d, 0xcca047b4, 0x4ebbed94, 0x57363f6f, + 0x8778b725, 0x58aeb5f8, 0x00a7f03c, 0x83817936, 0x4b556c42, 0xe712f2eb, 0x92e9db54, 0xf6d9aba2, 0x29601942, + 0x248d8ebe, 0x73a3a760, 0xae6a65f0, 0xa8c19783, 0x911cd12b, 0x251348ff, 0x9715d968, 0x7c30399d, 0xa59e9549, + 0xf01ddf84, 0x3321440a, 0xd6054d27, 0x8f5d3fe8, 0x79b7de05, 0x86ab0ebb, 0xb3d12431, 0x784ae86b, 0xf5426e40, + 0x5f46907f, 0xcd4701ee, 0x40e512e1, 0x4f100466, 0x44c5c83c, 0x91ca60d4, 0x2d09e5e1, 0xae994e9c, 0xdbb3a794, + 0x7a74c4b2, 0x351cd62f, 0x64e95e58, 0xfbd1b1ce, 0xc82b8107, 0xfacd1ebb, 0x513bb2a4, 0xcd6138f0, 0xfbf0dcb3, + 0xa3312da8, 0xb3fb5953, 0x7f1e6e3f, 0x2b2a8921, 0x44e70f4f, 0x2f864b4d, 0x998f8c8c, 0x65cce424, 0x2e8fa06b, + 0xfc9ab5f5, 0x88a4a398, 0xf4584162, 0xd7606153, 0x20774759, 0x82463425, 0x52e7e403, 0xda28be8a, 0x2124210d, + 0xc9630b96, 0xa8a4ab37, 0xc659eba7, 0xb3e2b827, 0x80e4a37f, 0x374da1c4, 0xd692fad5, 0x5088685a, 0xf169ec9c, + 0xcff7c46f, 0xd70c85db, 0xc5de6a4e, 0x99562017, 0xd3241392, 0x96bd0014, 0xa83161c5, 0xd05c6037, 0xc8ffd983, + 0xbef04597, 0x8e485cb3, 0x764dc14a, 0x48d6b25a, 0x05f5bdb2, 0x299e7714, 0x9357799d, 0x021b68f9, 0x71554eaa, + 0x77ddaa1b, 0x987fa7c4, 0x202426ec, 0xed844ae6, 0x5a46be2e, 0x89d922bb, 0x76f29f79, 0x9486d9ac, 0x304bb2a2, + 0xd14a3c71, 0x139eee10, 0x848624c6, 0x55fa0fd4, 0xbb077823, 0xbe986ade, 0xdaf48589, 0xa7881f70, 0xc3e89082, + 0x6480bb86, 0xd7b67720, 0x6d05e8e2, 0xa6168fb0, 0x4d17f30d, 0x5f336d55, 0x7be3153c, 0xc6ba71ac, 0x37ccd61d, + 0x648ddc91, 0x60a8e60e, 0xfe2bf5e7, 0x496872c8, 0xac6c4b85, 0x553ea6b2, 0xd6829fda, 0xea2c37c7, 0x32de9e88, + 0x765e7a65, 0xaf4ef1e2, 0xba10e504, 0x989c16f7, 0x9e3b9238, 0x5173752d, 0x6f044695, 0xceee0c12, 0x1f8e1eaa, + 0xf6d9c308, 0x225d9aad, 0x981bc312, 0x9f4c5ce2, 0xedb38b5f, 0x96e36cde, 0xffb41daa, 0x59259eba, 0xd80c9c03, + 0x6b8aa6ab, 0xe55f092f, 0x29c5082c, 0xc9e871e7, 0x626366c4, 0xa9341677, 0xdce6873c, 0x786e9e39, 0x26acee96, + 0xe2d7a6ab, 0xeb15bc6a, 0x9af2eef6, 0xe7f9f938, 0xc5396a8c, 0x66e05b36, 0x8a77ffea, 0xa1e37767, 0xdbdd6c73, + 0x938641fe, 0x207dbe44, 0x7e456672, 0xc16710d5, 0xb38181f6, 0x37bd3ca1, 0x0d36976d, 0x58483a0f, 0x8ed9bbcb, + 0xa34ce3a5, 0x55a15427, 0x1ae41221, 0xd3db0025, 0x847d21e7, 0x76aa3a11, 0x6d27b1c3, 0x16043754, 0x1a910d50, + 0x9cf11c48, 0x4b31f8a6, 0xda3fc650, 0x16f87d5f, 0x71318bb1, 0xf29657b5, 0xb2ace3e9, 0x41883231, 0x5481343e, + 0x66747818, 0x0edaab34, 0x9f6a481c, 0x8d888b00, 0x1d5a33eb, 0x93f621b0, 0xa0da0982, 0x35382a8e, 0xf3320350, + 0x005217a7, 0x0c38873f, 0x0a76dd46, 0x580732f3, 0x59719010, 0x14f3db69, 0xf64af740, 0xd7bc7bef, 0x7e8c9fe1, + 0x779dacbc, 0x990dd354, 0x2a528f5e, 0xc629a321, 0xf65e2337, 0xae80a409, 0xe9bf14c1, 0xd24c0edd, 0x79504be3, + 0x09980fef, 0xdf309091, 0xa06fe698, 0xb3cc7420, 0xad836bea, 0x585e7c90, 0xc6c5f249, 0x2352804f, 0x6ae49ac1, + 0xed6e6cea, 0x9e31ff03, 0x8e6b0f20, 0xde7f08ed, 0x86478e91, 0xb63c0d2e, 0xce65b6cb, 0xe678eec4, 0x7660e786, + 0x9118cb8c, 0x5aeff7f7, 0xfe1ae8d8, 0x014b4fd3, 0x6bfffd43, 0x1d6d589d, 0x85692e29, 0x72685fa8, 0x85f6582d, + 0x56941ae5, 0x5ea09ba1, 0x4916e5e0, 0xfb87cf71, 0xcd4e7d97, 0xaf3914bb, 0x9bb26949, 0x332d6597, 0xb7e1b941, + 0x770efb90, 0x4dc83e26, 0x19273276, 0x2c618599, 0xd381bdbf, 0x20fe745a, 0xc85c7067, 0x4d6b7402, 0xb19a9ede, + 0x3c0574a2, 0x94280376, 0x97852df1, 0x85a352d1, 0x6dce9d6c, 0xee92be8b, 0xc19ae419, 0x6de1653d, 0xf235fb43, + 0xa91f6199, 0x15a39ad0, 0x584f8785, 0x1a9f6bdc, 0xf43cc31a, 0x8d786f91, 0x43f3a493, 0x03097222, 0x266f522b, + 0xc623f2bb, 0x49e7a546, 0x38ef15c8, 0x3526d838, 0x018ba557, 0x4bddba5c, 0x23d9030c, 0x7f4e4d18, 0x6d82cc63, + 0x23b9280f, 0x4a4f3c7b, 0xac084909, 0x98b56ccc, 0x3437425f, 0x8a13c4e5, 0xd4bdcbc5, 0xfd3f53f3, 0xabda0074, + 0x34ef4865, 0x1b63703c, 0xd19d04d9, 0x92ef7378, 0x891a8e40, 0x0893f99d, 0x0848829b, 0xd2fc9665, 0xeb336cbb, + 0x1e352779, 0x798bff77, 0x1affb1e8, 0xdac60cba, 0x6ecdaade, 0x88cc2f98, 0x8c48ee8d, 0x68f89915, 0xeb1d1c7b, + 0x412df6ae, 0x425b25d7, 0x62b61537, 0x352f5851, 0x84340d59, 0x459fbff2, 0x7cf8968b, 0xbf7f366b, 0xe34f8ca4, + 0xe6aeaa00, 0xb7c5a5ea, 0x69053586, 0xf56755b6, 0x91e609d7, 0xf956cc0a, 0xd8349b77, 0xfdf180f9, 0xaacf7939, + 0x39948f79, 0x01b7e918, 0x61eb1913, 0x2b357c74, 0x9a7baad3, 0x1d77c58f, 0x4f731aa4, 0xa4a390fa, 0xb6ed16d4, + 0xd2e7a1d3, 0x8e02ea06, 0xc3a75464, 0xcad3e2d4, 0x31206349, 0x6c686586, 0x484b4862, 0x41c9c36c, 0x03d00d67, + 0x254cf630, 0x5d6296cd, 0x5c1d3aee, 0x07ec5aa2, 0xe1a0a693, 0xc378b8dc, 0xde6d25b9, 0xe050a49e, 0xf9472a8f, + 0xe883ea9c, 0xe2a54104, 0x9f7164d9, 0x3191aa46, 0x0e34ed86, 0xbfe05f95, 0x55715631, 0x74b47be5, 0x171dd54b, + 0xc60e2435, 0xac309019, 0x5d1a85cc, 0xcf11b834, 0xdb8f052b, 0xae948e44, 0x2dac95b2, 0xbde88608, 0x41cab7bf, + 0x20838c5d, 0x2a56fb4f, 0xb44079f5, 0xd2ec246c, 0x9f4f0a42, 0xce8fa070, 0x335f247b, 0x4b0a28a4, 0x839a8279, + 0xbe1cb5be, 0x93f8fc2b, 0x0c1d382f, 0xff71aec1, 0xa6247b07, 0x65920208, 0xc568f6a3, 0x10c7e21c, 0x6ca5d00c, + 0x1d16610a, 0x05c7f562, 0x1e2d852e, 0x39990c35, 0x65ac8c95, 0xa84d8ea7, 0x0a61b871, 0xfad2aaf5, 0x783ffb05, + 0xed9398fd, 0xad6aea79, 0x0b4d4b0e, 0x84433fd0, 0x32d95d3e, 0x906ca1bc, 0x759c0dbb, 0x9fa3e027, 0x5441b676, + 0xf16a377e, 0xf016e21b, 0x80f9adc0, 0xab62529d, 0xa61f4c5f, 0x6ba9e2b0, 0xa1a83a92, 0xd7f4f464, 0xba617ccb, + 0xeeb4e2e4, 0x658398a8, 0xee55872e, 0xbb07af09, 0x7b7167dc, 0xad8f7a8a, 0xa67a1a4f, 0x5f3e5188, 0x38e825f1, + 0x378b933a, 0x41f94b97, 0x73c16919, 0x8a4daa0d, 0x3c87780f, 0xd5dca4e2, 0xbdfa9aa8, 0xa5855373, 0x29316bc2, + 0x11eee23d, 0xd2232e04, 0x2905ff9c, 0x7fd498c7, 0xad02c109, 0x19142026, 0xa9bb6e97, 0x9b5d4abd, 0x486a4ff7, + 0x8f9a5bb5, 0x8fb4af83, 0x6e205574, 0xac2c4b8b, 0x540e3477, 0xd397efab, 0x5611a966, 0x4d5da99b, 0x7dc1b943, + 0x491aeefb, 0x1ccd89f8, 0x2a69aea8, 0xb1fc1e0f, 0x251f8374, 0x2738e784, 0xf048b000, 0x13de1fdd, 0x0f656981, + 0x13d9b32c, 0x87ba2234, 0x9e661b3c, 0xf28522af, 0xf4f0e75d, 0xf32a8773, 0xc0c3a59a, 0x7700f9ae, 0xa5468edc, + 0x564b3448, 0xce40cd83, 0x68557762, 0xe38eb389, 0x55dc6a7f, 0xf437003a, 0xb60a90e9, 0x768c4c8c, 0x9b2b847d, + 0xb8931be5, 0x476ae4b8, 0xbbce2a8c, 0x21c0a4ed, 0x342d51a5, 0xa7e62643, 0x95f94b43, 0x439c69ba, 0xa0f29ffc, + 0x5bccf49d, 0x69430afa, 0x80e50611, 0xc8d0ada2, 0x03d7dc73, 0xe735718e, 0xf0b5363a, 0xbe68443a, 0xbd978e81, + 0xec82a108, 0xa1ba565f, 0x73ad6f46, 0x12e68fd3, 0x877e720f, 0x44039b22, 0x8db41d15, 0x952ecc04, 0xdd441718, + 0xebd6241a, 0xc15655c5, 0x1fcc8302, 0x88778fb4, 0xbe9b9806, 0x25110b0a, 0x011cc550, 0xebe277d3, 0x057d51fc, + 0x5e67f8a7, 0x61ba36ce, 0x06d5ba89, 0x36cac041, 0x1b8d9c99, 0x05bfc275, 0xdd6f28d3, 0x1266801b, 0x843ec24f, + 0x8d2af290, 0x80cba6ef, 0xb4c0f0de, 0xace4cc8b, 0xc5cbfd26, 0xa7a4e652, 0x5c30b267, 0x4ee9f9ac, 0xb9551e05, + 0x304bad8e, 0x6201b89e, 0xaef0e6c5, 0x62af110c, 0x02d8a319, 0x08603b32, 0x27b5b858, 0x6f1d27d6, 0x4299912c, + 0xee98f59d, 0x1f6b2cf5, 0x0747d084, 0x713970e9, 0xc5c50254, 0xa40fb25f, 0x1aa67ea4, 0x6b73e6b9, 0x38373ea5, + 0xe9b32fa3, 0x7add8fd4, 0xefe0b139, 0xcf1055f8, 0x97f47f1b, 0xfc1ca36c, 0x28c07ce4, 0x5b5c9cc4, 0xd0caeb46, + 0x165ff339, 0x965d60a5, 0x9f6131d1, 0x6fca7901, 0x4a3d5fed, 0xec93cc46, 0xdf2e6983, 0x6f56ed3c, 0xd1bb181e, + 0x5b332af4, 0x253750eb, 0x242e42a0, 0x3e056119, 0x2eae8abe, 0xcafd20e3, 0x670e7e14, 0x3598db46, 0x962024cd, + 0xafd98b16, 0xd2b26b07, 0x8d2d6d51, 0xcd2a2489, 0xc424ad58, 0x5201f120, 0xf1915b98, 0x6ebcfbae, 0x4f980fa0, + 0x1e56330b, 0x6c0d3b93, 0x166ae1ef, 0x148ccf1f, 0x816d5e91, 0x6a227f2c, 0x8379843a, 0xf2b7e06b, 0x338d2bac, + 0xa8403761, 0xca06d942, 0x4b92b87f, 0x381ad8f0, 0xd30d3411, 0xf6ab223e, 0x3df97a27, 0x2e83d09a, 0x361892f4, + 0xb9292399, 0xe9624f39, 0xa997ad6d, 0xf3adb017, 0x1016b167, 0x45c2c38d, 0x7b1d21dd, 0x9d77221f, 0x022d8ce5, + 0x013e736b, 0x0d33fe49, 0x4796d842, 0x9525dbdf, 0x22c978ca, 0x5677f21b, 0xd081d4ff, 0xebf65ab9, 0x6bf18307, + 0xb03d5340, 0x90754d80, 0x16c4f763, 0x716b8d22, 0x3383fc05, 0x79fdfd77, 0x9cfc0cd1, 0x926ae40e, 0x1c0cc4b8, + 0x07e14fb8, 0xf3122117, 0x1a0fda43, 0x0b87047e, 0xf8409203, 0x6d95183b, 0x38c33c59, 0xa07708be, 0xc369c691, + 0xdaa2a066, 0x666bed4a, 0x2e1e494e, 0xb082c24b, 0x0d4002af, 0x4b317795, 0x129a3e9c, 0xe1aa107c, 0xfc03a844, + 0xb22414b3, 0x86f49315, 0xbf228210, 0x3bd8c0e8, 0x6cb8445a, 0xabc4f1d9, 0x8a75109a, 0xa76c5abb, 0x699d1b95, + 0x1d9824fc, 0xc9db9afd, 0xc25ccc18, 0x251ec83c, 0xc2683794, 0x81b05635, 0x883d98ac, 0x6da7cd6e, 0xb8fb0ecd, + 0x860acb5d, 0x399b040d, 0x5eac4e76, 0x34033dfb, 0xce1fc744, 0x6ff42b2a, 0x96dd48f7, 0xf55bc60e, 0x156b1971, + 0x21d504af, 0x31d97031, 0x929f1954, 0x61a1fd42, 0x6eb9c03f, 0x79569ea9, 0x372db9d5, 0x02f64b28, 0x6357fd29, + 0x3ff55fe2, 0x08b9a532, 0xb3d7476b, 0x54122f7a, 0x6cd7726e, 0x034a5046, 0x279d60da, 0x39ca989b, 0x60216f15, + 0x6b02fb84, 0x4132818b, 0xb70f59a2, 0xd36798ec, 0xc199684f, 0xa9066b3c, 0xc6d43941, 0x1771bf55, 0xee45b3e6, + 0xae8dd33e, 0x6fcbadc8, 0x65060ba6, 0x61a48080, 0x824cbaca, 0xae92b0bf, 0x4dfc238e, 0x2b30d626, 0x8f4faa82, + 0x65c7b98a, 0xf1f29971, 0x30de19ca, 0xa033b246, 0xce6707da, 0x18131277, 0x829c4352, 0xd56b7c8e, 0x47559123, + 0xa1924384, 0x92f41f8b, 0x6b2b1f75, 0xb8aa16cf, 0x12a1acf3, 0x9103378d, 0xfbadb041, 0x696da1cb, 0x85f86899, + 0xae3aec0e, 0xc1a35d02, 0xc83140ec, 0xa8b8551a, 0x2a61fe50, 0xfbd832ab, 0xf28b3f77, 0x03bd1d96, 0x6ca647de, + 0x95ba3bda, 0xb1242f98, 0x75cd4d7d, 0x47b21622, 0x9edb97ec, 0xd986ff6d, 0x58dcb748, 0x003908bc, 0xe25c5e98, + 0x58830cc3, 0x51001ed7, 0xb2ed47bf, 0x4954c145, 0xe3687e97, 0xc038b2bc, 0x2e6496d7, 0x2d888639, 0xd4c2b865, + 0x4b13c7b5, 0x22802cc2, 0x10da359f, 0x487b6757, 0xcc9901cc, 0x330048e0, 0xe71ec96d, 0x1127dc6b, 0x2d3e4c34, + 0x850ad36e, 0x7ec5c023, 0x5461f382, 0x4477b6a7, 0x3380c109, 0xfd8823f4, 0x450c96ad, 0x380aed8b, 0x3300f54c, + 0xf037c4d5, 0x9e131ad8, 0x7be9c709, 0xbbe0b6f9, 0xfc0e45cf, 0x439e7d4f, 0x884f3b38, 0x411e0fda, 0x3e142200, + 0x67fd1e9e, 0x48e0da83, 0x819c2261, 0x756bcce2, 0x1f4a91f7, 0xa8c6e181, 0x41bcfda2, 0x3357364f, 0x4849c5b0, + 0xf95aff99, 0x2ea1a8cd, 0x0a09b3d7, 0x0f1b26d4, 0xd3004730, 0x2fcb8c04, 0xa4f92509, 0xcc435280, 0x14bf2ea0, + 0x5e2eecd5, 0xc2b3c929, 0xc2d733b4, 0x79ca241b, 0xa7e5e554, 0x117d1002, 0xd3f761a9, 0x60c66925, 0x589fecda, + 0xbf88c715, 0x1d928b06, 0x8cb368f2, 0x86ff3b57, 0x4ad41c53, 0xe6305fa7, 0x8071b592, 0xf86ef540, 0xb9644c90, + 0x0d097b30, 0xd7f4e89d, 0x9066d8b6, 0x5ec3e69f, 0xb9eafbda, 0x7a1268b4, 0x4dade902, 0xbd9d4b35, 0x995e99b6, + 0xa22ffb9b, 0x5c36bfa7, 0xaeb09e26, 0x9603156d, 0x56d0769c, 0x0f17a526, 0xdc3a239a, 0xf6277e9d, 0x5cf590cf, + 0x547f4643, 0xe6a3e12d, 0x2cd30a7e, 0xdc50068d, 0x623bc0d3, 0xbdb03f18, 0x7d2a197c, 0x25523d6b, 0x8b707dfe, + 0xf7545a14, 0xe7dd45c7, 0xd3f00d9f, 0x8b314707, 0x650bc1e0, 0xe1a8a071, 0x98ee6e3f, 0x69e82697, 0x43944075, + 0xcdb95927, 0x88f8ad86, 0xa433d8ce, 0x8160bc2f, 0x08204027, 0x839af593, 0xe761e688, 0x07f3a70a, 0x09392fd5, + 0xdabbf117, 0x05197dc9, 0x076d5831, 0x9d4cddda, 0x9b691899, 0xd31809bf, 0xe71c4ab3, 0xbf2af558, 0x78e47043, + 0x469f5b95, 0xaf8a1d72, 0x3ffd970a, 0x4fab0bf2, 0xecebbbe8, 0x89501318, 0xf67b10f6, 0x9b3178f3, 0x952309e9, + 0x6d6db6e8, 0xf616ec62, 0x7cf1ec8c, 0x33fa2dc6, 0x1cb3c1d9, 0x9e4ece06, 0x715c1e49, 0xc69eba8f, 0xdecd1eeb, + 0x67fe39e3, 0x43817983, 0xeeabb040, 0xb9d9f56d, 0x80e23495, 0xb3d3da15, 0x03bea99a, 0xed5e3be3, 0xff40a0cf, + 0x3880cfe3, 0xc136cb91, 0x820eabdc, 0xb18459a8, 0xc84caed6, 0x06112c12, 0x50fe359d, 0xc8f8ade3, 0x3389db4d, + 0x0f32b37d, 0xf29c3dae, 0xd7fb1598, 0x6104fdd5, 0x45991e0a, 0x449ffaf7, 0xb6413b7b, 0x20578c3c, 0xa2ae3dde, + 0x95cee6a9, 0x34b33a0f, 0x868e354d, 0x674bd702, 0xb09ece81, 0x67398501, 0x91a5ccfe, 0x1847bbb8, 0x366ba8f8, + 0xb06a3435, 0xcf26322f, 0x12436d6d, 0x38cead5e, 0x0df871f9, 0x85049918, 0x1525f9c9, 0xa3364ece, 0x3924bc4f, + 0xdb81d80e, 0x06cc0cad, 0x82861530, 0x89dd4351, 0x4518db09, 0x6d06293e, 0x31d650fc, 0x6dacfc67, 0xb067c0fc, + 0x13f71e41, 0x60d8d10e, 0xef075a27, 0x4c880b78, 0x1ade236e, 0xb7b704a6, 0x407e5bd8, 0xa7d6d642, 0xf6f6dd2b, + 0xdc5c9288, 0x03c132ce, 0xd536a5b6, 0xd1ab45d1, 0x7f9d361b, 0xb27e0c4e, 0x6afeccd9, 0xc992b5d7, 0x84d258c2, + 0x3fafb191, 0x52adbc51, 0xa52b60d4, 0xa725e9f5, 0x74020214, 0xe89202a7, 0x676a1405, 0x5176f3fc, 0xab708016, + 0xb0709cab, 0x50f2a666, 0x874e261c, 0x32ac1cd6, 0xf70012fb, 0x79f7dc16, 0x911aede2, 0x0deb02d1, 0x388aeb86, + 0xa495d737, 0x350faabb, 0x3a2c221a, 0xe197d49a, 0x29d9031f, 0x960818dc, 0x089a4443, 0xd254c9a5, 0x9ba935a5, + 0x2d9f6b14, 0xcfec12f4, 0xbd4ad699, 0x678bf528, 0xb3bf51c2, 0x298f79d8, 0x83a08ae5, 0x52cfae0c, 0xd38af978, + 0xd53889c0, 0xfcd2dea6, 0xfb14687a, 0x520542f7, 0x84356bb6, 0x2fc03c1a, 0xc7454f87, 0xa18e3f19, 0x4dc9d822, + 0xe208b804, 0x9197deab, 0xb7bc64db, 0x93609d60, 0x99f471a7, 0xa1de9d28, 0x24721955, 0xdf5971c2, 0x3318d54d, + 0x511dd01f, 0x2af23613, 0x7db8f419, 0x9c65b18f, 0x2151a61e, 0xcbd84c95, 0xae705573, 0x5f25797d, 0x30013dfa, + 0x92b000be, 0x9dffc150, 0xf79152fe, 0x29eb6dee, 0xa7917b3e, 0x85eabfa9, 0xc8e9d10b, 0xb751bca3, 0x41fed816, + 0xbeeb2624, 0x97145b17, 0x9b2cae1c, 0x88a3fd63, 0x79b1f278, 0xfa3557d4, 0xa90c3cdc, 0x70dc0120, 0xdebfd01a, + 0x3571e03f, 0x5c8785c9, 0x7f4ea586, 0x204a86ba, 0xbc31e720, 0xe20cef50, 0x797bf6d8, 0xd06cbfd6, 0xc8ac925f, + 0x1c30a9e0, 0x52a1a973, 0xd6f33f6a, 0x7c83167b, 0x8e808fc5, 0xb5bde58a, 0x24d78fee, 0x81fe2aca, 0xce02f9dc, + 0xd1045000, 0xaf096ac6, 0xbbbf6493, 0xdb928784, 0xdaeaeedf, 0xf30356ee, 0x024e568e, 0x0ff6b894, 0x3a9b81fa, + 0x5312e3be, 0x1bf88093, 0x87915179, 0xf91a7d1f, 0xf8308f66, 0x485cbc49, 0x3b37d76c, 0x719e9300, 0xcd883dd4, + 0x49f0de07, 0xc9f66120, 0x6045d4e8, 0x6cc6fcf7, 0xe035543b, 0x9bf8e4cb, 0x86ca27c2, 0x283a3870, 0xc22d3bc5, + 0x34232c9c, 0x98e207c0, 0x9584656e, 0x95480fc0, 0x530897b8, 0x1c7a6a70, 0xe26883c3, 0x8b822f97, 0x5bb23d6f, + 0xb094378c, 0x2e0c75ff, 0xbc80fbf7, 0xd8f4acc4, 0x9e41c2e7, 0xd68fe226, 0xc6d1e008, 0x643d6319, 0xeb565685, + 0xfe8bd8c9, 0x1e4ef8d8, 0xffcd9686, 0xb62c080a, 0x170a1310, 0x40ce3ad9, 0xe94d823f, 0x1473062f, 0xd5bb2c1e, + 0x12a9929a, 0xd9473308, 0x471129e2, 0x65d71143, 0x9064f8da, 0xad369acd, 0xf54f7f93, 0xfd0c308a, 0x697544d9, + 0xbe0306de, 0x0843a38d, 0x7c3cbde0, 0xb67caeeb, 0x56245de8, 0x2b2e4a80, 0xdda617e8, 0x2d23e372, 0x9019f2aa, + 0x5cc2ae9f, 0x6664ee25, 0xa1609fa3, 0xf481dff4, 0x92adacaa, 0xd8d7799a, 0x68f88d9d, 0x479408bd, 0xb89e1f36, + 0xf7d853a3, 0x7f41cd15, 0x0bc83511, 0xc08e1665, 0xf8ad2b60, 0xbfa3485b, 0x0d6ab35a, 0xc1ba6024, 0x29eec326, + 0xa75b1c16, 0x15a2f7e6, 0x7636a54b, 0xd30b45d6, 0x5a36c035, 0x5f5eebdc, 0x99f60f20, 0x42350d03, 0xd1cc5e3f, + 0x548d262c, 0x5f979752, 0xddca7bd1, 0xa22e1b28, 0xb577abb9, 0x39563e15, 0xf72d8afa, 0x64be31f6, 0x30d8315e, + 0x4fb2ed81, 0x5bcb7cd4, 0x2e7ebcb7, 0x83c147c6, 0x63dbf781, 0x6218221b, 0x85c5504c, 0xe5aff69a, 0x6a5d8d19, + 0x5413d848, 0x037fdebb, 0xd8732c7b, 0xe9d748ad, 0xd55a55b6, 0xc9b70afc, 0x15ae8767, 0x856c1b42, 0xd3406670, + 0xb2649806, 0x1405bb44, 0x02c6bfa7, 0xe6e42526, 0x790cb475, 0xcb7f4e53, 0xb87fbd7d, 0x594dda41, 0x0be3b717, + 0x1946e549, 0xcaad7000, 0x8e0be1c0, 0x9d52bd1a, 0x9b39410a, 0x1e6d6ed1, 0x249cd350, 0xfb25589f, 0x5eab43e8, + 0x48b417c5, 0x44c3fbfa, 0x069b5e62, 0xa792d7b5, 0x96ecf91f, 0xe3f411a3, 0xdc30cecf, 0x58199d16, 0x2b24ceb5, + 0x93e943b3, 0x57bdb1e1, 0x52e05bcf, 0xaba034cb, 0x224ec956, 0xb297b87e, 0x41a783e7, 0xa540931d, 0xf1241bce, + 0xfd611b65, 0x631c0ca2, 0x84b45e49, 0x86f833c2, 0x0e404ec0, 0xb4f06bdc, 0x7e440928, 0x123045b3, 0xa478c508, + 0x081a344b, 0x5de0086d, 0x9d861412, 0xe8fc4a0a, 0x3b8eb124, 0x02339373, 0xb3cd880c, 0x92a815a0, 0xc23af699, + 0x22f001e4, 0x11cf7e2d, 0xe9e236d0, 0x68d3a491, 0x69b169b8, 0x049f6504, 0xd825971e, 0x13fda911, 0x2237eccf, + 0x80ff01ec, 0x4805b6ab, 0x0aee21c4, 0xbdb918a0, 0xc4d59647, 0xc9dce702, 0xd3116e84, 0x5b7e0fe6, 0xef6f2324, + 0x0006b574, 0x4ad3d8b1, 0xf674c01e, 0xf6871bc9, 0x619ca4d5, 0x899c382f, 0xfd7967d1, 0x3aba01a7, 0x158cb92c, + 0x59b40e3b, 0xe39fe5ef, 0x4e0f7111, 0xc1788d16, 0xc5aa4a91, 0x8d5a015d, 0xa8a84275, 0x478044ba, 0x0980c0d3, + 0x9a6f6a6e, 0xeffc38a0, 0xaef7e329, 0x4fe5effd, 0x552b88ed, 0x8fb0b197, 0x64c83367, 0x0ac9c1aa, 0x3f92fa7f, + 0xbd7a26ee, 0x76538a2c, 0x69e2c9ea, 0x4482b0d0, 0xc48fe116, 0x8ed40b58, 0x332ced54, 0xf9bd2d58, 0xd006c771, + 0xe235022d, 0xb9edde60, 0x9c7a034d, 0x27847e06, 0x86c70cbe, 0xed8c9239, 0x45248d7c, 0xf30b0bcc, 0x7b847664, + 0x829b860c, 0x7adf0151, 0x2e03898c, 0x4dae9936, 0x6722ee3d, 0x2e968199, 0xf7650ea0, 0xdfdd1f7e, 0x06600c4d, + 0x8c46d666, 0x35ae76fe, 0x8e2f22c1, 0x42201e7d, 0x9b097e02, 0x1f108208, 0xf89bd712, 0x437b646b, 0x71f32c79, + 0xf5f5eb98, 0x0f1e1af1, 0x521dd7ce, 0x67699faf, 0x246d47a4, 0x5ae26c2a, 0x0d7280d7, 0x9caba6ee, 0x18767ce3, + 0x5ce5d9a5, 0x52433091, 0x29dff2a2, 0xbb716c02, 0x2bac58eb, 0x6e995434, 0xe79aa150, 0xa0f13d87, 0xe129ea0e, + 0x20fe54b9, 0xedb848f1, 0x6b0aa3c4, 0x1665dce5, 0x5194de31, 0x22ceca67, 0x7e3d7476, 0xf5fe7986, 0x9ce2e74f, + 0xd9e5d6ed, 0xc2439d1a, 0x374c580f, 0x643345d1, 0xe3b93834, 0x0ae3eef0, 0x754a36cf, 0xb6831f72, 0x319b1e97, + 0xcbd732a8, 0xbdad966f, 0xb15b2181, 0x7604c6bb, 0x039bc87c, 0xae8c53b2, 0xeb9153d0, 0xdfab99bf, 0x37b45df6, + 0x38a5d8c6, 0x5514393d, 0x820b8ec5, 0xf0f32fb2, 0xd780a045, 0x29535886, 0x20d5da03, 0x84b5fb03, 0xbef84646, + 0xe3127e4b, 0xdce10f4f, 0xcb596d49, 0xe20aa5dd, 0xe89364a5, 0xe72902a4, 0x11db9a5c, 0x8c52a843, 0x7905c806, + 0x1d14349b, 0x0ae54ac7, 0x7dc8fdbf, 0xb4e8e314, 0xde74444f, 0xa8907959, 0x2f7ad13f, 0xc05d569f, 0x6be7e332, + 0xb726c54f, 0x734d265c, 0x56b734af, 0xe4aad9e9, 0xb531fb1c, 0x4d20bc37, 0xe5e3088e, 0xbca83b90, 0xfd64702a, + 0x70b73b95, 0xfccbb76d, 0xb357dbf9, 0xa83f9e28, 0x8b6bbf2c, 0x19e853c8, 0xd9416411, 0x09f6c36e, 0x2a298099, + 0xd160d704, 0x0d33c728, 0x2c5f86c6, 0x017322e2, 0x916f2ab7, 0x1a41d305, 0x0018ae6c, 0x99347746, 0xc905e91a, + 0xf825c59d, 0x5e4a1e6f, 0xaf3521ea, 0x5a1fd67b, 0xc5170d36, 0x2cea391e, 0xe5f5638c, 0xe54fa694, 0xf8ccdaf5, + 0x3d26a06f, 0x84469a9e, 0x9e25b938, 0x643fcee7, 0x4adf3abc, 0x51134e79, 0xc90d28b0, 0x30874d14, 0x60828969, + 0xf34444b0, 0x2ee1cb14, 0x50bc34f9, 0x456942dc, 0x5168b2eb, 0x0b147a4c, 0xb2c5e323, 0x2e8482cc, 0x178baa87, + 0xb6cd8703, 0xae6fb556, 0xcd1370fe, 0x90717d17, 0x1170ef56, 0xa0286658, 0xa902eb21, 0x55de3053, 0x516c3bb0, + 0x4a085576, 0x7a08e3a1, 0x99b7a6de, 0xe5e8f790, 0x2280a66a, 0xdd3b4f28, 0xf726f201, 0x54bb149d, 0x4cdbc050, + 0xfba2a0f7, 0x6204b892, 0xfdcc8857, 0x84d9d4bc, 0xfc518848, 0x7a2efbd2, 0x80b371fb, 0x4af1ac89, 0x482e47dc, + 0x82b4170a, 0x43e1ed38, 0xebe01de0, 0x76fcac7e, 0x522425cc, 0xf7960692, 0xbb25c958, 0x580b6b91, 0x2d0420c9, + 0x3df27ce3, 0x7fd97d28, 0x1fee84f5, 0xcf870df0, 0xe0b3ed4a, 0x6b6b2d95, 0xc1f4d419, 0xcee56cf6, 0xda1204f9, + 0x6b135774, 0xbd9644cd, 0x7f1255f0, 0xc5557916, 0x1ad3b6d9, 0xf26ff04f, 0x4451463d, 0xc9a7ddec, 0x20aa6921, + 0xad5e8b03, 0xd83f6c05, 0x35622f8a, 0xac6999d9, 0x20ed004d, 0xeea2ca72, 0x0a402306, 0x5c172624, 0x0a8f1d57, + 0x0748907b, 0x3aecd78b, 0x4e9a81c4, 0xc7f188c4, 0xc49ad9b3, 0x35eaff85, 0xfe67ef37, 0x954ad3e3, 0xe32bfac7, + 0xe3aee3bc, 0xfbd21fc6, 0x6b0970e3, 0x649dbb6d, 0x12e33749, 0x0ac86f65, 0x91fd91d1, 0xc942d3b4, 0xfbd6cff0, + 0xcf803aef, 0x17fb18cf, 0x1a11f747, 0xe518ee8c, 0x943f59a3, 0xa10e4b39, 0xc15932d7, 0x4fe1911c, 0x450b52b5, + 0xb8dea131, 0x4a4a510c, 0xb83b2852, 0xc0ecf904, 0x654ab044, 0x27fb7696, 0xe876ac6d, 0xe815ecd9, 0xdb11001b, + 0x91c6fbda, 0xc69b1b14, 0xfef2e6b4, 0x2990b4d8, 0x7e098bd4, 0x9e78c68d, 0xd6bf4e81, 0xa85557e6, 0x2bb0b6ff, + 0xd7d5bacc, 0x3d4d4f5f, 0x1d70e7ae, 0x80930a31, 0x7acef07b, 0x23387f12, 0x1b673702, 0xb745b971, 0x2612d8ab, + 0xf9bc3c24, 0x89f442f1, 0x20e4b73d, 0x01eeaedf, 0xe62a27b6, 0x72aad22e, 0xd259a400, 0x7d74bbff, 0x6441fe7d, + 0xd2421c40, 0xf98ba33b, 0xfdda32a7, 0x78631bd1, 0xe02e9a68, 0x5cab124f, 0x41013cf6, 0xd2ef208f, 0x48591bf2, + 0x4f25e9bf, 0x4b00955d, 0x3cf049de, 0x95e748b1, 0xe60a487d, 0xd805bac4, 0x6ed57cbe, 0xdf6e1aa2, 0xa432cff1, + 0x72c2979a, 0xc90b1278, 0xecd3f378, 0xb961a3e6, 0x8754abb5, 0xaaa89e10, 0x509c4f73, 0x8555768b, 0xdd594a82, + 0xd89b89bd, 0x8ecd891a, 0x49fed54c, 0xbcb59b1c, 0x62d7a356, 0x7cd8fc9f, 0x5936a5c7, 0xdeef65dc, 0x921176d8, + 0x5eb1d7be, 0x8020fbba, 0x586d6f8e, 0x5d09e325, 0xd332cdc8, 0x98dc35a0, 0xf836577b, 0x4069c3a8, 0x58d7b723, + 0xd1d7d68d, 0xb15dbaa6, 0x087460f0, 0xa4f9c2a7, 0x8c4e327d, 0x049cd35d, 0x40beadb5, 0x02b95d65, 0xbe56626d, + 0xfa103a14, 0x5247c266, 0xc745fe0f, 0x6bc58a12, 0x7cf9003c, 0x97ee7178, 0xb17e3cb7, 0x112b79e0, 0xee3692d2, + 0x735b1230, 0x4eb7af0c, 0xd43cd7f5, 0x4876c59f, 0xa0943b4c, 0xcb49cda5, 0x67fd02cd, 0xcb0c5201, 0xdb34fe8f, + 0xa3ad1d3e, 0x013ce498, 0x84fd66e6, 0x2120b433, 0x18b51192, 0xd851ba7d, 0xed7b02c0, 0x86cf9218, 0x9f3bec2a, + 0x5685356b, 0x6435fc86, 0xdca11d22, 0xbb9f9660, 0xbd96b94e, 0x02f46667, 0xe24ba939, 0x73b0721a, 0x6a3a6943, + 0x31d122ef, 0xba2984c2, 0x3193c0b9, 0x03408b0c, 0xd6a9240c, 0xedfd1fed, 0x5e514d34, 0xb7c696f4, 0xc3ae561d, + 0x02faa5c1, 0x5250ba7c, 0xd8dae342, 0x60374f2e, 0x87dab2b5, 0x42d2d26a, 0x302d7648, 0xd56056e8, 0x8a9543f9, + 0x973cf33a, 0xfe669252, 0xda0d3d5a, 0x3cfcc9a2, 0xac249061, 0x24073b32, 0x7263bb7e, 0x83b131b6, 0x7be89223, + 0x62024b55, 0xededf299, 0xb64706d9, 0xe38650e0, 0xeeca6100, 0x6163d351, 0x6b502ff0, 0x4f510354, 0xc6412470, + 0x7eca1b5a, 0x2db7c8c4, 0x034be9b0, 0x34de4480, 0x9cb30ce8, 0x282f041a, 0xe661f9e2, 0x7724a3db, 0x90650d96, + 0xf5fc661b, 0x130a211a, 0x65223e37, 0x216b75e5, 0x184a9d40, 0x4de92d7c, 0x0804bbad, 0xc3c8452f, 0x4bb347e2, + 0x556ba639, 0x9c7a7d60, 0x97cff25b, 0xfec4c9c8, 0x2ba7477b, 0x2448393e, 0x0db396b4, 0x31633c1a, 0xaee20dd6, + 0x9570a29a, 0x67657bd0, 0xbd43da93, 0x28cbe636, 0xbe46f3db, 0x9704bb27, 0xbd57261d, 0x76b2387b, 0x9fb14ecb, + 0x74769680, 0xf64b5891, 0x8ea63eb8, 0xafddd7a9, 0x141e185e, 0x0d5e0ed6, 0xd501cf90, 0x08c658a1, 0x1a595d7a, + 0xedeec140, 0x213865d7, 0xf9ef6f9a, 0x0d2df5d3, 0x51958812, 0x7b613a25, 0x502ac53f, 0x8fc6ce4a, 0x2ccf709a, + 0x265f7aaf, 0xc24e17e7, 0x1a0c28f2, 0xe7cb5188, 0x4b6461a7, 0x45d66d30, 0x118bf70e, 0xd4549a07, 0x3ed003f9, + 0xf3e443b4, 0xff369736, 0x8a1f37b2, 0x6cee6c0f, 0x69148287, 0x341e66ef, 0x94e07861, 0x0e36745f, 0x991f4be4, + 0x056525a7, 0x615e9f43, 0xfecdd90d, 0x00844edf, 0x9ef26cc4, 0x2506a88a, 0x18375c6a, 0x3b465ec5, 0xcfef7ed7, + 0xf78bdfb9, 0x96cc1211, 0xf18d7221, 0xc71f333b, 0x2b0fdb9a, 0xa9daccfd, 0x00d2c26c, 0x48c2399b, 0xe2c5f1e9, + 0xa27c7fef, 0x50306d34, 0x88e8ebf5, 0xe0eac2c6, 0x688c0dd3, 0xa855ab11, 0x90c00ad4, 0x04bef501, 0x9923fac5, + 0x5b505e97, 0xb973535f, 0x7b72fb97, 0x42b83934, 0x13d214e6, 0x823a6b97, 0xb61e239f, 0x73503161, 0xe9e96ca9, + 0x9dca302d, 0x4db60544, 0x326165b3, 0x3af97174, 0xc40e581c, 0x6e5d6511, 0xfc78e73c, 0x0728dfd0, 0x63a04c58, + 0x42440997, 0xc6c98f76, 0x822f7c14, 0xe05ecf0a, 0xf7d8e5ae, 0x36583c3a, 0x82060796, 0x1baa8c8b, 0x3265f16d, + 0xaa7be4cb, 0xd2ed4596, 0xea934dd8, 0xfb602df7, 0x99dc50dd, 0x833db6da, 0x2ec62561, 0xef1926b3, 0x887c6f35, + 0x95cedf94, 0x36a4c09e, 0x6e63768b, 0xa27c64dd, 0x3f0983b0, 0x8b57aeeb, 0x75f9f97d, 0x094929ae, 0x7fc9d288, + 0x6dcfa53d, 0x23cb35bd, 0x53b03834, 0x00ee6cb5, 0x06d8e58c, 0x537e81cd, 0x7591ef6b, 0x4e23592e, 0x10c62369, + 0xcb6f652f, 0xc9638e57, 0xf3acdc56, 0x2ea1ca07, 0xc68f954a, 0x8d224eb4, 0xd4edcbeb, 0x095f464f, 0xf8dab26b, + 0x7315d6ce, 0x8719b187, 0xe780fdf9, 0x7cfa8ebe, 0x2985458f, 0x3cac4e92, 0xba2a6d30, 0x0a6f8b53, 0xa72c5449, + 0xecf31b00, 0x28716d39, 0x6f68ddb4, 0x1cf04280, 0x4195e18f, 0x6252ff06, 0x61ba369d, 0xfc9484e8, 0xd0fd6fd7, + 0x1539ac50, 0x0850e01f, 0x0301b897, 0x9d5cad56, 0x6a25d1d9, 0xbbf57a1e, 0xf3a7d4d3, 0x02f9795e, 0x9380fc97, + 0x0fe0f45d, 0xca83371b, 0xbe1cbaeb, 0x6c7b7ded, 0x13519a70, 0x95e8d8b8, 0x0b22f608, 0xef1d8eaf, 0x9ccbb4d2, + 0x731af47c, 0x41578ab8, 0xda86b304, 0x16ba4954, 0x8774ded3, 0xccca2f5e, 0xa1076d1a, 0xdc5926a1, 0x43db23b8, + 0x26530fd8, 0x547d3c4b, 0xb83645b0, 0xdd369be7, 0xf8d62212, 0xe7dbf5e7, 0x49672921, 0x0bd4da51, 0xa92777b7, + 0xd3278167, 0x78a9f9f1, 0x9fd2a3ba, 0x6526eb32, 0x4ecff74f, 0x9e019437, 0xdb340895, 0x3a14fdfe, 0xae1fded7, + 0x84ea8058, 0x083fe7a3, 0xde118e57, 0xd8d1b5b7, 0x4ee6db23, 0x0ad6bc45, 0xe8830936, 0x25d1d5a3, 0x74fa69e7, + 0x4392310e, 0xcdaff089, 0xf754d3fc, 0x5a3a7762, 0x3bdde3ab, 0xf9859d9c, 0x62d6877b, 0xdf7388c6, 0xcfb0cc9f, + 0xd4e22792, 0x3c7c943e, 0xf81e15f6, 0x20966f06, 0x492e5b90, 0xc2743288, 0xc4b358ea, 0xded5a044, 0x02492e16, + 0x35f7d7c9, 0xc13880d9, 0x4034f87d, 0x999b31a0, 0x4ebfe1e5, 0x4aa9c442, 0x2911899f, 0x8b2dbcf6, 0x94f7f783, + 0x3bdae0f8, 0x9007ad28, 0xc8495a69, 0xbfc1dcdc, 0xb12e1d2f, 0x6f451ff4, 0x94649265, 0x622b855b, 0x3a55d2c5, + 0xd74603f0, 0x2538b11d, 0x2e7d4e1e, 0x51eac3ed, 0x15319769, 0xb05818bf, 0xe2a606d4, 0x0ff86e64, 0xb7cc15b5, + 0x37a3a24e, 0xad68f876, 0x7135508c, 0xbfd2d9cf, 0x347bfbc8, 0x7b035f42, 0x74464f0f, 0x89f7f4d8, 0xd5b26fe3, + 0x17c9010c, 0xbbc5a2a3, 0x4cff0175, 0x00e03cbe, 0x79a96513, 0xebf730d3, 0x87285fa9, 0x18fa7303, 0xbad5eaa4, + 0x869f2873, 0x1ba50aaf, 0xeab1a5d2, 0xfa028ca4, 0xcd717e9d, 0xb955e3a3, 0x3c6c19e0, 0x21839b6b, 0xcc07a833, + 0x5aa6af47, 0x342c4657, 0x410ade9c, 0xa99c6682, 0x424e65f6, 0x4052c904, 0x0ae0e91b, 0x3ecfa7b1, 0xdaba6c33, + 0x149ebfab, 0xceb653ec, 0x38636e01, 0xbc74ccea, 0xd046d4fb, 0xe21b93b9, 0xa11f2059, 0xb11a1d67, 0xbfb59b27, + 0x0a858cdd, 0x50b509b1, 0x1d00e9a9, 0x974e8eb5, 0x2c96daf6, 0xff59d643, 0x9b16d6ee, 0xe21de74d, 0xb9158554, + 0xa0f4797f, 0x6176037d, 0x477a0aa6, 0x586a27ec, 0x68070435, 0x81a5d249, 0xd05bfb4a, 0x803326a8, 0x67aa53ff, + 0xd5582b88, 0xa4b6bb1d, 0xbd73585b, 0x72e51dfd, 0xc6255615, 0x6df172dd, 0x7bc8f775, 0xdd79888b, 0xb0057102, + 0xa69636ea, 0xae709eb9, 0x362c6281, 0x507ab3bc, 0xa2f5434a, 0x01733659, 0x3f406924, 0x4aa5896d, 0x786acac6, + 0x3019c85e, 0x9e2eb45f, 0xb1ac06ce, 0x29f885f8, 0x4a3dbef4, 0x961cc411, 0x595bcaaa, 0x1006888f, 0x8a4d373b, + 0x05d8e0f6, 0xb5c409d5, 0x1d884bd1, 0x8d6e876c, 0xddc327cc, 0x79f92750, 0x1310f919, 0x255c31b3, 0x882050d7, + 0xfa0e7825, 0x0e281e43, 0x68042a7b, 0xf50e2abf, 0x73cc2833, 0x5adb5008, 0x58444a23, 0x9b2a4ae0, 0xf49e3410, + 0x1369163a, 0x3a12d7ba, 0x58aa9c7b, 0x2f41c52f, 0x42cf1274, 0x646bae3a, 0xabf1dd44, 0xedce21ce, 0xd86a99ee, + 0xf936ec43, 0x90792448, 0x0ad3dad6, 0xfb44c610, 0x2251e7ff, 0x94e23bec, 0x4333d462, 0x4af7cf90, 0x3b1019e9, + 0x7582cdca, 0x5ad74bfa, 0xf4c08edf, 0xbf0d657b, 0xa6fa5528, 0x32cd5cf2, 0x9cdc0b2a, 0x70308615, 0x9828a11a, + 0x252daca8, 0xdd80c22b, 0x3809c60e, 0xd7865161, 0x64efeb2a, 0x97f6926e, 0x59546499, 0xbccab3fd, 0xbf581a92, + 0xfc53d65e, 0x37f5e826, 0x6e226483, 0x5961ca9e, 0x7b632b35, 0x48a3c86d, 0x3fc68df7, 0x56d7200c, 0xbaec6597, + 0x7e5c4c0b, 0x4a19c480, 0xbef3c2e2, 0x98f7036c, 0xfbc4b039, 0x645d5cb5, 0x8d43cf72, 0xf6141ea8, 0xdffc823c, + 0x4967a566, 0xd03ae1fa, 0xcaaa8ffe, 0x55773e99, 0x6f9688d0, 0x497e0ad6, 0x3fe7cde8, 0x565c7c52, 0xdf82ee74, + 0x1505ab3c, 0xdf051eed, 0xdc59da48, 0x0f269c70, 0xe62c097a, 0xed6597a9, 0x351a7103, 0x48e1e6a5, 0x36b88275, + 0xa4613d79, 0x3cae59af, 0xedd2a9ca, 0x27625e94, 0x3ecbb0d5, 0x489c3602, 0x408c74cd, 0x0746e867, 0xc1548433, + 0x1d938559, 0x1786e00f, 0x5128f1f8, 0x07bb8328, 0x2b65dd74, 0xa69b0621, 0x455ad6c3, 0x7e87e52e, 0xbf17ecdf, + 0x3a9d8a65, 0x67482820, 0x2b168978, 0xecf03797, 0xfc532095, 0x8c515976, 0xd846fc9e, 0x8569f1f3, 0xf1244276, + 0xb02110d6, 0xa3fefc83, 0x0260ddda, 0x5e25a0e7, 0x7d561ae7, 0xc6783441, 0xf51f6515, 0xacffdbf7, 0xce42a498, + 0x86630ad5, 0x16ceabf3, 0x0b50d347, 0x7bf3bd8a, 0x45d62d5b, 0xe1e3fc47, 0x2fcc01d9, 0x028fb476, 0x6b69cfd6, + 0xdaf2fa0f, 0xe3f30931, 0x869f8468, 0x46a15418, 0xa63ebef5, 0xe24adc15, 0x84b93377, 0x7e4dc6ae, 0x21bbdb47, + 0xdde0e32c, 0xb68ed906, 0x4be36b8b, 0x4c2093b7, 0x885abc04, 0xbc32a1ec, 0xe735fc98, 0x2f80f57f, 0x5ce0854e, + 0x525b75ad, 0x57fb7023, 0xf491533a, 0xb35965e7, 0x9bb2a327, 0x2b30b737, 0xdd6f0225, 0x25e7611d, 0xe55c123e, + 0x75ee761a, 0x553c5972, 0xad0e78a4, 0xc2c8b8e3, 0xd157850d, 0x67fdf6c8, 0xda7489f7, 0x6fbd857f, 0x9a57a2a2, + 0x79c86ea6, 0xd3d745a5, 0x1d568de2, 0xf868c525, 0x169a2e18, 0x6403c413, 0x7e62b8ae, 0x77cffee4, 0x90c2a80d, + 0x4a2abb34, 0x62b3989c, 0xe82d0ca1, 0xa9005418, 0x2667f243, 0xadc7e837, 0x0e8f2301, 0x433e18b8, 0x5bbdc4a9, + 0xf755cc99, 0x6054de21, 0x3b93a0c7, 0xdc58a387, 0xc745615f, 0x602e08af, 0xece1ab83, 0x4bf11861, 0x4e996580, + 0x885ab0be, 0xc5e0c5d8, 0x32b3da9d, 0x445f1ca9, 0xe848e82f, 0x5b6d4dc8, 0xa8fb887d, 0x049a0a0e, 0x1be1d1e1, + 0x863f447d, 0x05470c08, 0x239c519c, 0xa349b51e, 0xb2c4bd0e, 0x3f02844c, 0x9d8ed475, 0x207534c0, 0xd9d6969a, + 0x9c714594, 0x1130cef2, 0x7cf03fe8, 0xc8adb5f4, 0x6b9d2051, 0x935701e5, 0xa7060058, 0x4f281a26, 0xd376bc0b, + 0x10bf7ceb, 0x8e8cc64e, 0x2408ece0, 0x2ab95633, 0x8ba99273, 0x39f6d50d, 0x3893e63a, 0x0852f75a, 0x81055e25, + 0x212c79da, 0x97a5edd0, 0x56f8883d, 0xa594e101, 0xdce8c654, 0xf15cbe95, 0xc619bdab, 0xf6cff468, 0x02e1de3d, + 0xc9af55e1, 0x62133808, 0x4c47c068, 0x8fe58bc0, 0xa2c8ba16, 0x9c434fba, 0xefa1a329, 0x2994105b, 0x5e608ff8, + 0x857b72cd, 0x28b5ba56, 0x33e8367e, 0x4a9099dc, 0x10ff3f7e, 0x9cce46fe, 0xd5d70164, 0xbec7c50c, 0xcf91ef3d, + 0x1ecfba46, 0x63561cd2, 0x6752e7e6, 0x9a9eece6, 0x3b073d04, 0xe0e82ee6, 0x4caf0b6d, 0xd13686a6, 0xf4bc76fd, + 0x18dc4c4a, 0x4e88aee4, 0x6f198581, 0xc80f86cd, 0x0ad23775, 0x3ae701c3, 0xa9465bc2, 0x74c9ff6f, 0x438ce2b2, + 0x1961cfdb, 0x056ec654, 0x971d90e6, 0xd2bc4bef, 0x6eeae374, 0xb7b4f6e7, 0xdc5eca21, 0xcb88e5a9, 0xca3707e3, + 0xbea9e8ab, 0x99d60332, 0xc73ba6c7, 0x01cbcd1d, 0xa2692d37, 0xab4429a4, 0x5d377656, 0xb34e5a30, 0x6acfb792, + 0x6a2a0981, 0x45c2219e, 0xb7ea26a8, 0x64606ce2, 0x89304e6e, 0xfcff5b8c, 0xe922887e, 0x8c9f16bd, 0xf510d4ed, + 0x83aaf535, 0x54141f6e, 0x216e0a51, 0x4dfdf630, 0x114dae95, 0x40f9b0b8, 0x8601e917, 0xd40292b0, 0x35220715, + 0xfecf68de, 0x69e6763b, 0x3851f90e, 0x95c2a500, 0x2fe2e19c, 0xf311e24c, 0x8fc6ee14, 0x992660a2, 0x121fc324, + 0x127280d9, 0x87e4427f, 0x84aeca85, 0x551f9ae7, 0x847076a7, 0x546e983b, 0x98109a9d, 0xcb596d40, 0x7797abb0, + 0x9056a4fa, 0x3bf5b985, 0x0ed0971b, 0x5b51f787, 0xe9241f6a, 0x284616c5, 0x7294f41d, 0x74e89bb2, 0x3786820e, + 0x57b84197, 0xb8d2b63f, 0x0403537b, 0x6516002e, 0xfd4e9f4c, 0x19e52d7f, 0xcc0ce15f, 0x7a8d6504, 0xd19a99d2, + 0x66c551bc, 0x842fe8fd, 0x34119f70, 0x352fbedb, 0x51175fc9, 0xede5c7da, 0x7e4f62ba, 0x9402c039, 0xed930b24, + 0xe0976b3b, 0x49237a3a, 0xe6d1e9ab, 0x6e21e3f0, 0x4c82c49a, 0x724f5024, 0xc00d965d, 0x3cbc7473, 0xe8053ad8, + 0x5fe0fbd9, 0x85f2bfc4, 0xe112616a, 0xb30b4b89, 0xe2272898, 0xf9c0c3b3, 0x9d8d2213, 0x76b93559, 0x32911cf6, + 0x24ba7fef, 0xb67b6f1d, 0x7043fa07, 0x8913f894, 0x4d6bc224, 0xe71aa7a9, 0x68491b8a, 0x309efe22, 0x5b8b4838, + 0xea9b6740, 0x88974c60, 0x8fe6fad0, 0x6bfdb4a7, 0x8549a45b, 0xc84eca80, 0x394e189f, 0x45a9940e, 0x7639c644, + 0x61045423, 0xf3aded55, 0xe940afdb, 0x2107b089, 0xa8c8cfb0, 0xcfdb5e45, 0xd5b6e21b, 0x475e997f, 0xe409b53b, + 0x9ce069d4, 0xbb59012a, 0x776b40a9, 0x42737fcc, 0x454a82f4, 0xf04b2e5b, 0xf3c8a384, 0x458111fa, 0x03c013bf, + 0xd4066ace, 0x65e7ef6d, 0x56aad982, 0x05c11fe9, 0x1b48d897, 0x0d1fe79b, 0x4fed8b55, 0x25c17af8, 0xf0d3d150, + 0x05fbeb8c, 0x3e27ba1f, 0xa6a91047, 0xf195e626, 0xc11fd246, 0xa71f6983, 0x8dfc5315, 0xf5177aff, 0xe9f8078b, + 0x701acb86, 0x2329447b, 0xd910212d, 0xf170e6e2, 0x675c280f, 0xd8290d19, 0x14154821, 0x6d845584, 0xabe175c2, + 0xea62ff8d, 0x6fae9b38, 0x318b3279, 0x01d5b0e4, 0x930fb3d0, 0x09b5317f, 0x21f32de4, 0x434d0159, 0x485c907b, + 0xe958ff87, 0x94f52b2d, 0xfb327bb5, 0x91ad9435, 0x2a5f57ac, 0x4fced4a6, 0x50ae265e, 0xd7ca2fb8, 0x9c6549e7, + 0xeb1ac769, 0xe18a8b76, 0x5eddde57, 0x611e9265, 0xfd957fb4, 0x7e7e6d03, 0x697a84f0, 0x18f0324b, 0x8f21191d, + 0xd4aa4309, 0x72db9dad, 0x5ef5e58d, 0x674e1cea, 0x6a70f697, 0xb5137cbe, 0x84193eb6, 0x4ca524b8, 0x60a3d66b, + 0x9756002b, 0xfa13917f, 0xd3094b54, 0xe887de58, 0xfc0eb412, 0x08b6c06e, 0xf3f33816, 0x163a53c4, 0x075dc227, + 0xb6f32764, 0x0a02dd42, 0x20b00120, 0x41a85cf3, 0x66cc6e32, 0x371a92e2, 0xb057e492, 0x12341c8d, 0x5e00dbb2, + 0x10b8a712, 0xc26ef019, 0xe14406ce, 0x137e4ce9, 0x1bd1ea64, 0x3e5ef525, 0xbcbbe149, 0x67c1ee67, 0xeb035ad8, + 0x5354f832, 0x7cd7db4f, 0xa10a16d0, 0xf884ada9, 0x981ee1f6, 0x0a5413e7, 0xf787596f, 0x4fde5c1c, 0xc829e99b, + 0x54178939, 0xcb6de3e4, 0xea463456, 0xa27377e8, 0x4c583680, 0xb0547ac5, 0x082ef542, 0x7c8656a4, 0x3b6b1f0b, + 0xc3883ad3, 0xc8530eb2, 0x76822f03, 0x9134bbec, 0x9f5796e4, 0xcb7cfa6a, 0x1d36d35e, 0xd459bbfe, 0xa11df9f0, + 0x15d930d2, 0x4f2ea3ed, 0x6f78db3b, 0x8354d389, 0x1714ea11, 0x0cc9c295, 0x88d8ee10, 0xba445b8d, 0x4245310f, + 0xedc80a20, 0x50d4c485, 0x545596c3, 0xdf1e4400, 0xa78b45e4, 0xbf83c708, 0x8a63d586, 0x087c908a, 0x404a7f0a, + 0x5cf3dba1, 0x39e29664, 0xf4ca8846, 0x6703eb5a, 0xf092af0b, 0x69d3bd0c, 0x4271128d, 0x20aff125, 0xdc199525, + 0x2326da24, 0x7a1babc1, 0x4741ea72, 0x7e972071, 0x9c67b313, 0x43ed4c4b, 0x4f5a6433, 0xd2b8ba3e, 0x180f2d4a, + 0x9e2f1e48, 0xe6d6dbeb, 0xf694235d, 0x2e649105, 0x5160dfa3, 0x6659bd8d, 0x5bc98b75, 0x4e370884, 0xc6e59c88, + 0x3a81af9c, 0xbd79318d, 0x554f60ce, 0x3e2e965a, 0x1d70cf38, 0xe440be1f, 0xf7f10af8, 0x503f1014, 0x004ec808, + 0xebce3141, 0xa3507071, 0xa515a49d, 0xeffd2a68, 0xcd4c2d5b, 0x3ef14b63, 0x456fd735, 0xdae2e765, 0x59116ce5, + 0xbf66ce17, 0xf9aec2f1, 0x02ab448d, 0xa77f8d6d, 0x6424d70f, 0xd18d6f9d, 0x1c921979, 0x03721c69, 0xc4546fe5, + 0xa3153b38, 0xd149834f, 0x469aac29, 0x6394c064, 0x61b460c3, 0x49522e9d, 0x6aae4494, 0x5e9f0ad7, 0xed140eee, + 0x3eea9ebc, 0xa4ce33db, 0xed9a26ea, 0xd425b871, 0xcb0c9f72, 0xf975680a, 0x6070139a, 0x63be3d0e, 0x358eb10e, + 0x5c47eb4c, 0xa1451fd4, 0x18044ad0, 0xd59d9583, 0xc7049f6f, 0x7fb7b23f, 0x5c339b3d, 0x705140ef, 0xe9d3770c, + 0xc4a42012, 0x96d7ad5f, 0x1da3911c, 0x9e96f4ca, 0x433dcee2, 0xd0b10ed6, 0x06f76f38, 0x472899a6, 0x16b7bddd, + 0x3b623f18, 0xcfcdc049, 0xbfb3d7db, 0x0462ceca, 0xaaa75eeb, 0xe7490007, 0x81fbf7c9, 0xad67deba, 0xb2029a41, + 0x87f914d8, 0x0497fbbf, 0xdcf108ce, 0xe4668e87, 0xacfcfbec, 0x05519dd2, 0x563f20bc, 0xecd044ef, 0x523c546a, + 0x519123d0, 0x030a3b6f, 0xe3e8a5bc, 0x5ab27d55, 0x25bab1ad, 0x2f43dfe3, 0xd9eb0077, 0x72b72310, 0x51efd83b, + 0xa50a3ec5, 0xe6af4ac6, 0xf7ca749f, 0xa3981592, 0x73871ac6, 0x5a6d0007, 0x0e7ef3a9, 0xd91d6626, 0x8a3e767a, + 0x294f2383, 0xee7767f3, 0x956df560, 0x3850e5a6, 0x70dd03f3, 0x6015d864, 0x204097dc, 0x3ab64635, 0x05f3018d, + 0x8bdb9808, 0x989baef0, 0x9b0aef68, 0x0bc63763, 0xff13f6a8, 0x82fb5a04, 0x9b9e5242, 0x13ce8cc9, 0xdb98376a, + 0x7c324a43, 0x53ca0813, 0x6dc9f5a9, 0xe03d8a2d, 0x1bfdc96b, 0xbcf41a47, 0xd270b336, 0x06cfbffd, 0xe0c505b1, + 0x06325acd, 0x451c321a, 0xa5bbb630, 0x97d4523f, 0xdc52154e, 0xc006247a, 0x63ac030e, 0x4882a448, 0x25ef5cc2, + 0x7ba02755, 0x52fb23d8, 0xda7f4e4f, 0x4820223f, 0x1777a133, 0x5bd5eed4, 0xbdaa2ace, 0x5eea86ec, 0xaf7e46c5, + 0xbd7c1df4, 0x2de12797, 0x29cddecb, 0x5042d14f, 0xca6a7c1d, 0xf3bed24f, 0x92e50c7c, 0xc1af8a5e, 0x6ac0a6b7, + 0x05694b85, 0x63568501, 0xb9f5b68d, 0x3c50ab6c, 0xf8e6e65a, 0x9d88076f, 0x6297ea1d, 0x07816a22, 0x05d777bd, + 0x8fd173ed, 0x2e00f074, 0xb76ebc98, 0x87f4d391, 0x0a4a0793, 0x5f83cd76, 0x2d22aad2, 0x52430a90, 0x917b9951, + 0x48b67562, 0x92a1869c, 0x47a97448, 0xb05adb27, 0x4fc3443f, 0x4d888fdc, 0x0c3b999a, 0x25e6d0d2, 0xca817266, + 0x26a4ff99, 0x906cd8f3, 0x700e3528, 0x97bf2cd3, 0xfaf67577, 0xdd6fa023, 0xc70caa89, 0x205ec7a5, 0x79fbfa2a, + 0x3f8d0962, 0xb55779fb, 0xa81aca1f, 0x3cb6ba4a, 0xe9b1229f, 0x3328d3fb, 0xc04babac, 0x6cc4ff3c, 0x05f50831, + 0xc0ef3682, 0x201ea2ea, 0x80fe5283, 0x87a3eef6, 0xdaed0b30, 0x0169af19, 0xbd8707b8, 0x19560a36, 0x3126e433, + 0xec6c6835, 0xf3775767, 0xc3d297c0, 0x2cd73347, 0x57e611c3, 0x65bc1292, 0xa4b8c713, 0xc4a0dcd3, 0xb732a6af, + 0x8f850f14, 0xfa91a4fd, 0x780cd468, 0xd70ccfbf, 0x521f71cf, 0xe0fe6012, 0xb936be9d, 0x3ef14e47, 0x7a219279, + 0x7411058b, 0x60001590, 0x591ab0f9, 0x41515f47, 0x5bb64609, 0x5021fa61, 0xa2e12058, 0x20acf6cc, 0x092e2f49, + 0xb18d979a, 0x2a29fed9, 0x41f29c73, 0x2f28645e, 0xf7db1da4, 0x545a8ed9, 0xcc98971a, 0x2d41ed07, 0x4aefe738, + 0xb124c1c6, 0xe806f038, 0x9fecdd20, 0x29155694, 0x98ab6ff3, 0xa8148eb3, 0xceb057e9, 0xaf947fe3, 0x0cab5abc, + 0x0fbc710f, 0xd73e89fc, 0xbe36f206, 0xb96540d5, 0xf75e32a4, 0x52f97dc0, 0xa6f39e6d, 0x4136d487, 0x5a64999e, + 0xd1bb7a53, 0x82d21763, 0x4b25f69e, 0x79f9e034, 0xa2492148, 0x86b92c73, 0x3cbdcd5c, 0xda942247, 0x2b554d7a, + 0xd283dcec, 0x5e557800, 0x477b78e2, 0x741c5e1f, 0xb0ec3b31, 0xba6f7436, 0x83015f7a, 0x041ce8b7, 0xf870c318, + 0x9a0b93a4, 0x72763eaa, 0x5434d8da, 0x4701579a, 0x8fe7a89c, 0x3ebb05dd, 0x659049b2, 0x27dc8389, 0x324bd449, + 0x451a80ab, 0x0f35fa2b, 0x379534ba, 0x5cc140f6, 0x11672c61, 0x339de665, 0xe8e012fd, 0xec7a0d25, 0x47a9606b, + 0x8ef8bedc, 0x56906ce4, 0xf37fd7e1, 0xa99ebe2f, 0x805ec87a, 0xc27feffe, 0x64ed13bd, 0x1ee27ee1, 0x893d499d, + 0xaf8e76f9, 0x6bd3808e, 0x595778df, 0x4be177c7, 0x39e54079, 0x95c5f731, 0xb1052855, 0x5f4eeb22, 0x4bbee9fa, + 0x7543e9df, 0xbbf0633a, 0xb80434fd, 0x78b41ba9, 0x93f9f22d, 0xfd9a1a85, 0x1d39ccc9, 0xc75ad0bf, 0xc2efa428, + 0x9ba6eed3, 0x0cb61480, 0xf0f0e65e, 0x0a38143a, 0xe1bb21e8, 0x26d4a5b3, 0xac527955, 0xdeab9835, 0x23d1e1f1, + 0x16d4f3a0, 0x0c6757ac, 0x7fe88cfd, 0xb7c3081b, 0x615f26de, 0xcd282c25, 0xa06ac8b2, 0x1d5b4a0b, 0x72e38911, + 0xff7d5916, 0x7c86b0b5, 0x003ae307, 0x87bd3816, 0xb4fe2fbd, 0xbc306845, 0x294fcbd0, 0x58a025f7, 0x7f5f3a9b, + 0xfafab2c0, 0x124379ed, 0xc095ece5, 0xa28373e0, 0x046df3f9, 0x9d180fcd, 0x6bb85ef2, 0xd5dbef73, 0x52810dd1, + 0x0587f786, 0x7178367f, 0x9cdf66b1, 0x5762db89, 0x7f9a567e, 0x6a96bd1f, 0x53b01be5, 0x031f9e6a, 0x0fddcd5d, + 0x5caaa015, 0xf4667045, 0xbd3eb778, 0x20358182, 0xdc383a07, 0x29ab7d13, 0x0744a8d2, 0x49e87752, 0x1d840966, + 0x5f9b6da5, 0x1576891e, 0x34dde394, 0x2091aab1, 0x4b4c33c4, 0x327a524b, 0x263ffdc8, 0xd505c92f, 0x01218c7e, + 0xadab0bfc, 0x52fe7999, 0xd78986e2, 0x54c0f4db, 0x69304933, 0x1f09e738, 0x96a66f03, 0x52cd859f, 0xfc24fcab, + 0x775e42d3, 0x3f145785, 0x6ed7ee86, 0x696181fd, 0x020c5f7c, 0xf187ae7a, 0x8880ec3d, 0xee8dd749, 0x91835a48, + 0xd4fab005, 0xdc0cb069, 0x4fcf29ff, 0x75299ae9, 0xcd925c61, 0xf8a80dcd, 0xd8f661c5, 0xcb3bb72f, 0x9bd59e46, + 0xb2eec12b, 0x211d8398, 0xaf0f26d5, 0x36cb878c, 0x8cd2bbe2, 0x12465d81, 0x442d70f6, 0xd0428ed3, 0x8f008958, + 0x5c12f540, 0xc0a1edb9, 0xb83d0622, 0x28b936c0, 0xa3fc04e8, 0x8decf030, 0xa9612a6a, 0xc99f38cd, 0x86420fc6, + 0x7f1a83c2, 0xa1a2508e, 0xd99cf949, 0xe8481e23, 0xe8c3a018, 0xa37f196d, 0x85767eb3, 0x91de1fc4, 0x9d2decae, + 0xcd67045a, 0x64a843ac, 0x4f80a714, 0xac3dc157, 0x48797424, 0x22baff82, 0x3680cce0, 0x24d6c657, 0xd138c4d2, + 0x6bd55fb5, 0x787d1a55, 0xa31c4363, 0x5f6f8f5c, 0xb382f9d3, 0x8f44273e, 0xcdedc23e, 0x6c5db1e4, 0xd181b305, + 0xf624750f, 0xff6a3e08, 0xb4e2428a, 0xc061d7a8, 0x26b3502b, 0x6e7011b3, 0x53fc66e6, 0xdf249c36, 0xdc21f0a9, + 0x06292975, 0x15ed9f33, 0x96a89db7, 0xfe70c42d, 0x2b75f9a8, 0x197d68ae, 0xb722c126, 0xd370bd78, 0xbe71e565, + 0x9bbaf132, 0x2e643fe7, 0xdc43f19b, 0xfcd38a2e, 0x87e2fc34, 0xabcf93cc, 0xf756c01e, 0x93a66885, 0xdb600244, + 0x813ebbc1, 0xbdda15da, 0x4856866a, 0x207ed0e4, 0x8ffe7b7e, 0x54cc1813, 0x97ffc2e4, 0x5dea29aa, 0xcd8e3e37, + 0x01219a01, 0xc1b4e335, 0xe98d67d1, 0xc4438290, 0xf5551547, 0x991f952e, 0x5685ace0, 0x5057d6f9, 0xa4daec4a, + 0xb00e0830, 0x464f9283, 0xb5dd1d3d, 0x3600ac80, 0xe8d6c2d0, 0x855f83a7, 0x332c379e, 0xdc70bbb8, 0xe7b711a7, + 0x4cfc44b9, 0xc2e6c021, 0xffa3646f, 0x560c2f6d, 0x36b37c2a, 0x67c5009b, 0x6552c786, 0x51c1a1df, 0x8cc49f2f, + 0x93a0f966, 0xd7bb0439, 0xc2ac1c6e, 0x1937ae49, 0x7db16952, 0xabd335b3, 0x0b90a44f, 0x2f5f9d57, 0xe5101731, + 0xfb3b0d84, 0x2c80eaa0, 0x76ef4fe8, 0xb3777208, 0xb85f503c, 0x7ad398f5, 0xcd1ea1bb, 0x2f59a411, 0x497f9b3b, + 0x17f683b9, 0x51f33836, 0xcc0b3975, 0x0a749ae2, 0xb000fa32, 0x2efe5a13, 0x4d8d6548, 0xc212fcb6, 0xfb3dbd01, + 0x5525d7bd, 0x5fb36414, 0x9fc26142, 0x4a0ff73a, 0x45595e12, 0x67b698dc, 0x72176bad, 0xf73f5f48, 0x41f6a3be, + 0xb1d427c1, 0x1d8099b0, 0x9d5f272a, 0x346ee512, 0xd51fb3c1, 0xcb6107f8, 0x8e1fbc25, 0xece39ed0, 0xf3f69c02, + 0x68a2e09c, 0x0e69c8f7, 0xaef0195a, 0xa94878d0, 0xc58b4a79, 0x98f2b9a2, 0xef635159, 0x816f5c3d, 0x0502031b, + 0x11975162, 0xf96d1a5c, 0x01b5bea7, 0xa793bce7, 0x9c944adf, 0x58d4c900, 0xd780be73, 0xfe3f281c, 0xe23ac2d3, + 0x2b7059b8, 0xfb59c395, 0xf1ba840b, 0x0ebf6571, 0xdff18f0a, 0x2c2e28f9, 0x46fef8b4, 0x98361670, 0xd650624c, + 0xdb7da7aa, 0x8edfd938, 0x3dd6602f, 0x5c5b76fb, 0x82033a45, 0xece89098, 0xc89102a7, 0xfed88bc0, 0xbc24fca0, + 0x9d3226dc, 0x6bccbc1e, 0xd6fdf199, 0x3b0c45fe, 0x5ed50021, 0xfe0ffa8c, 0xc20e8832, 0xb3a2817d, 0xa77b8d83, + 0x191b9f85, 0x5a3e6d01, 0xfeaee393, 0xe1b39faa, 0x7079251d, 0x46151f7d, 0xd3ce3a7d, 0x06c05243, 0xfb0231ec, + 0x79b0c0ed, 0x28e00df8, 0xd75a6033, 0xc335a264, 0x433d2bb8, 0xf36a4ac6, 0x49b6a892, 0x15b09361, 0x961923e1, + 0x1d984864, 0xd5962e8b, 0x793fb595, 0xfc381bc4, 0x6937cea6, 0x4fd06103, 0x30a7172b, 0xc4f89a8b, 0xa4ff9e06, + 0x113d7dcb, 0x7dccf932, 0xc22f6f34, 0x111e87f2, 0xd3c6cd34, 0xdce93c9a, 0x33b06469, 0x21657bec, 0x8a33caec, + 0xeea31ecd, 0xb3dfcf63, 0x42db9f43, 0x8e4623ba, 0xa52e2ed6, 0xd5a3013f, 0x034bd59c, 0xab9b777b, 0xeb346eae, + 0x6568635a, 0x241749b8, 0x83d5f6ab, 0x1e677c16, 0x3568071b, 0xf0b88901, 0x76eac3cc, 0x006b79eb, 0xec7440f5, + 0xb160c7ce, 0x604b9a26, 0xf50f1c86, 0x93ffbca1, 0x283ffc28, 0xac12097b, 0x4edc0b46, 0xde3db008, 0x92961261, + 0x95ec2a72, 0x43b8d722, 0x5f707787, 0x160a00ce, 0x493d7a83, 0xdfbd714b, 0x405f5b5c, 0x2ee988bd, 0x1f296f7b, + 0x935162dd, 0xf0c975d3, 0xc8f69ac8, 0xccd46c36, 0x87766cdf, 0x4f3b5479, 0xaf374f53, 0xf6c2d908, 0xfe803088, + 0x8fc9c088, 0x8ebd2057, 0xf29d3017, 0xb9e0e7bb, 0x01e3f67d, 0x18ef9561, 0xb80dcf6e, 0x72f61c85, 0x3c691be9, + 0xc060cf05, 0x397dd6ad, 0x2b54b463, 0x8ff897ab, 0xc0917fdb, 0xdbeecdd4, 0x94cd55dd, 0x13a0185e, 0x76783e74, + 0x20c159cb, 0x070d55ff, 0x49e38688, 0x5d0688f9, 0xd8014daf, 0x9ab99747, 0x3ae18207, 0xe02e949d, 0x4ffb9b7b, + 0x531956ba, 0xd0b055dd, 0x5554d6f6, 0x3c74c31a, 0xd27b23a9, 0x2956dac4, 0x7cc2a3b3, 0xb00b6fea, 0x17be65a3, + 0xbdbcb259, 0x7031a4fc, 0xc70d4451, 0x7d794d99, 0xe9685cad, 0xcf9ac35c, 0xa1cfd370, 0xab512411, 0x6cfeeb18, + 0xe6ae2499, 0x649ca9fc, 0xa4f7413f, 0x1ac50a04, 0x4f382f69, 0x9fc3a17d, 0xc9a594ad, 0x79997930, 0x1f60adf3, + 0x47c9ec8c, 0xfa972002, 0xc2fe3cc3, 0x62f5b8dc, 0x13404d0f, 0xbccd0463, 0xed44f4a6, 0x0168f71d, 0xc5209a38, + 0xd1fd876c, 0x03101924, 0xd704da22, 0xc802caad, 0xefe657e9, 0x74251304, 0x85e834ea, 0x1371bdde, 0x7f069a2b, + 0xb54c0304, 0x927cae73, 0xc6371853, 0x9f1e0c21, 0x97139e4e, 0x26276695, 0x644a6f53, 0x3cafd6dc, 0x7ab7b55b, + 0x5404b682, 0xbde0d212, 0xe4206360, 0xb863b256, 0x27bd8525, 0x776ec5f7, 0xd093eb74, 0x69372d4b, 0x4ff32668, + 0xe773f142, 0xbcc3bd37, 0x2541fd28, 0x38d5a929, 0x8dd8b3fd, 0xfd02812c, 0x00ad32d0, 0xbba547d1, 0xde567f7e, + 0x6106cbba, 0xb77068f6, 0xee9d0183, 0x4be54c61, 0x5379acd5, 0x4f915045, 0x938374c1, 0x9e1cb4c0, 0x099e3707, + 0x9adeb2ca, 0x5eac132f, 0x96ff3f03, 0xe6e67498, 0x988aa125, 0x59dda9aa, 0xedcd3a62, 0xd44959b8, 0xff2cad4e, + 0x39be87a1, 0xe1141630, 0x468130c4, 0x41acd326, 0xf0b6b12d, 0x578c3451, 0xaca027b4, 0x318b31cb, 0x160be86b, + 0xf9054859, 0x54e444fc, 0xc97e49cd, 0xce1967bf, 0xfc9bf8a2, 0x7ed8b59b, 0xae7e50ad, 0x388b51c2, 0x544458dd, + 0xc4f11ab8, 0xf42a1c84, 0x9eee24eb, 0xdcf2ea67, 0x720a14f4, 0xe423663a, 0x42aa2f65, 0x44e3b786, 0xcbc4632f, + 0x265cdfb8, 0x1973fc07, 0x90f0ae49, 0x9d0f6814, 0x1b42e3ba, 0x9039f218, 0x0fb7099d, 0xa2204fb4, 0x5ebc668c, + 0x2874e808, 0xb9d1a25e, 0x5d0524d3, 0x50ad3ab6, 0x9c80cf6c, 0xbffefd2e, 0x3ed74a90, 0xf2cfabd2, 0x55520902, + 0xc4202fd2, 0xf3f66913, 0x509b49e6, 0x8c6e64e0, 0x9fd521b8, 0x4393430a, 0xb5896d4d, 0x5510a06c, 0x361ffa38, + 0xb43fdab4, 0x1918902a, 0x3d587ed1, 0xa58d234f, 0x829b3ac7, 0x8963138e, 0x6098a1c2, 0x798e0d71, 0x6ba7d4e1, + 0x16dea9fe, 0x9c3e271a, 0xf5ba0802, 0x2f5c00e7, 0x7138c0ed, 0x5a2faa13, 0xdaaa88ca, 0x1aed079e, 0x203f2242, + 0xf9418c36, 0x2c31024c, 0x628ff067, 0xc870a377, 0x097ec8a6, 0xfd20f743, 0xd369d9bb, 0x5073cd8b, 0xc27671b8, + 0x19161dce, 0x8b202d0a, 0x35b29f06, 0x18296093, 0x0200ca93, 0xefb84fb0, 0x565eb5de, 0x8f3bc2e0, 0x7e4909fc, + 0xffc27778, 0xbc62cffc, 0xb687f182, 0xd5d99518, 0xfece4d72, 0x6ac3469d, 0xfcd0a544, 0x35de9e7e, 0x71484af7, + 0x17957bff, 0xeefd4577, 0x5d477924, 0x665c755b, 0xe8b142e6, 0x6d816d97, 0xe9ef1cb5, 0x9e8762d4, 0xfbf52ba7, + 0xf18d1de8, 0xd70f4886, 0x9b81fa36, 0x93197efa, 0x77004412, 0xcab1b920, 0x328a88f1, 0xfb934ed5, 0x8fcaa4f4, + 0xdae6c906, 0xe3dcbe86, 0x136b56e4, 0x8b2e1d4a, 0x70f7745b, 0x2a3e958e, 0x39f120d6, 0x68c7ff93, 0xf16c7733, + 0xd9324138, 0x8cf6c1bc, 0x989427e3, 0xce5c2407, 0x36e18d20, 0x899d03fe, 0xc733aa73, 0xd10b97db, 0xb262b253, + 0xffd90f92, 0xc2a9a4c6, 0xc3ecd22d, 0x31227362, 0x9031c554, 0xe1945f69, 0xa35e3fd2, 0xd3fda436, 0x0e1521a4, + 0xf91b5cb5, 0x8a777d6d, 0x55852550, 0x93d7c1e9, 0x776fde6f, 0xae67dabd, 0x067f7c30, 0x4d64b0fe, 0x7e69adf8, + 0xced14544, 0xbff7ae4b, 0x7bbb7df4, 0xad9fbb5c, 0x7b3f0bdc, 0x1ee947b4, 0xaa4f2de1, 0x8b09c928, 0xfbdbf48b, + 0xa48b2e21, 0xc72eb68a, 0xc5c58133, 0xe5cc3dfd, 0x4ad2c02a, 0x22f5e13f, 0x13ce29e6, 0x0bcc87d7, 0xcfbbedd5, + 0xeee02a64, 0x01f4cc5c, 0xf9858ee4, 0x7e6e9a02, 0x054453e6, 0xc77c22db, 0x1e3a230b, 0x2f5ee691, 0x7c3432af, + 0x472be927, 0xf45dc89f, 0x74ec2bf9, 0x31beefa9, 0xfaec2b76, 0x4f2caa5c, 0x4f5a4d03, 0x95cbb7dc, 0xf67a7029, + 0xc6b311e4, 0xf43241b8, 0x499015d2, 0x9697435f, 0xc406bc94, 0x6c6fe662, 0xde002cbe, 0x33acc71a, 0x0d6ebd04, + 0x2a8f99a7, 0xc5a7e597, 0x118f2bb1, 0x68ce0359, 0x54039bb6, 0xb93a26ae, 0x66e52b21, 0x490cc55f, 0x97b4eeea, + 0xfb285862, 0x313f201b, 0x4955036b, 0x3efe023d, 0x5552a7f6, 0x4685afca, 0x04f6c11e, 0x51b3f768, 0x7b75708e, + 0x81ec3470, 0x4fcf4c4a, 0x59ca81e5, 0xc263ec04, 0x1ae2a43e, 0x6727b0cd, 0xb94c1c0e, 0x8dc8c71f, 0x41ffc9c3, + 0x5a4bb3a6, 0xf7adc439, 0x439c6d42, 0x01f7db65, 0xa03eb0cb, 0x92229a94, 0x763be661, 0xeb2e05e6, 0x1f17f511, + 0x5871af0a, 0xc2bee9b6, 0x209fdf32, 0x9a2b0587, 0x64d92492, 0x3bc2599a, 0x50be96f7, 0x39813ea2, 0xf0ff9e56, + 0xa0b3a586, 0x6eaf0034, 0x2003b648, 0x8c9b6073, 0x1f8e8d62, 0x1f880cf9, 0x0f95f1ff, 0xd644b3d4, 0x605fd5b4, + 0x5da62666, 0xa805446b, 0x3a6490fd, 0x6878c35e, 0x7f4c3e9f, 0x426a3077, 0xc8c7c52f, 0x7e09113b, 0x3a229aa2, + 0x29027e24, 0x2f7f8d37, 0x5f35c28f, 0xd68428c0, 0x889751e4, 0xf6a4b94e, 0x65ccb20a, 0x131551b1, 0x63f4a123, + 0xb0523e6b, 0xcab2caa8, 0x53958ec4, 0xce054b27, 0xc4cb3c32, 0xaae2b0dc, 0x128b2c00, 0x9f889747, 0x5b135a26, + 0xed1235ee, 0x286d41b1, 0xf1322ba0, 0x86d4f3e6, 0x84092daa, 0xa98cfa5a, 0xd9b9fad6, 0x09df7cbf, 0x96ce37be, + 0xe467f17b, 0x1da1de56, 0x39eac86d, 0x33c8c3fb, 0xaa8069d9, 0xdcc71428, 0x9f3ef976, 0x5a3987a5, 0xf9b3af96, + 0x811a34a3, 0xe67518bb, 0xaaa0e41c, 0x82b9d64e, 0x4014b7f3, 0xc8bb62ac, 0x1cca5311, 0x53672566, 0x94370fee, + 0x8d98b7a7, 0x12b14ace, 0x3030b685, 0x02685170, 0x056d0a57, 0xf622173d, 0x5c78e6b4, 0x8285af17, 0xa7a1ba8f, + 0xa9dff7c2, 0xcba63408, 0x127d28d2, 0xb9754757, 0x70247ba8, 0x85378e86, 0x7d8b8846, 0xa89a0001, 0x02fecc31, + 0x325e2f90, 0x85e3b5ff, 0x8933ba99, 0x09c7491b, 0x85ab13de, 0x709668f4, 0x44726701, 0x37fcc910, 0x398d1f73, + 0x8a5452ed, 0xc5cdb022, 0x72fb1b36, 0x2d3f51a5, 0x78d579c4, 0xa329a455, 0x5b0325b4, 0xb1b5a241, 0xb7089f3f, + 0x109ea090, 0x6e10b0ac, 0x671ef75d, 0x31af67e5, 0x05a0d10b, 0x2da63cff, 0x111bb54d, 0x7488df6f, 0x3aa6920e, + 0x2592ecd5, 0xfd927f11, 0x6b58848c, 0xeaca256e, 0x5f43231b, 0xf38b24eb, 0xd42beb4d, 0x65398f3e, 0x6b10f259, + 0x5fdac1da, 0xcf0f5b50, 0xed71a355, 0x3f706701, 0xaea25375, 0x5ec597ca, 0x07645733, 0x4067c775, 0x3686cb15, + 0xc3e97bcf, 0xb2cea840, 0x1cc60a7c, 0xc06fec80, 0x1cd209ed, 0x3f9c3419, 0xf59156a8, 0x331a93fa, 0xc83e327c, + 0x05e69422, 0x26270faa, 0xf33a5c7c, 0x0ec94aca, 0x29e843c2, 0x3391aaeb, 0x4dc2d26b, 0xc13900ce, 0x889ec95d, + 0x18867574, 0x9cb1cc34, 0xd893afd4, 0xd930e12b, 0xba0dd0f5, 0x9a2c70e9, 0xc05f0f6a, 0x5194947d, 0x8ecded30, + 0x226c7f34, 0xb0b79df7, 0xf60f50e4, 0xdf62997a, 0x2bce29ec, 0xeb955a60, 0x7769faa3, 0xbc200ce7, 0x575a456b, + 0xa183e40b, 0x7c5e35df, 0x207f4297, 0xc2eb3f98, 0x32811b37, 0xd56a6997, 0xe73c8510, 0x0e520a1e, 0x8cda87df, + 0x0d62f14e, 0x3a959569, 0xb882676e, 0xbd699a7f, 0xb9c2f3d4, 0xaff4bbfd, 0xae0059da, 0xcd0ceb80, 0x4ebc2d29, + 0x9f21193b, 0x4df1c12c, 0x7c68f4e7, 0x0793a332, 0x4ca441e7, 0x2a763593, 0x44002b8d, 0x746610e8, 0xec503568, + 0x45ef2e8b, 0x048ded53, 0x8d513b07, 0xf1a472cb, 0x06cf3b43, 0x0e465506, 0x1d769cfc, 0x6d5453ae, 0x96d70bc1, + 0x48ef1393, 0xc69eb15a, 0x7bcb7241, 0x6cd0dd7f, 0xfff5399a, 0x7cf8cf16, 0xaf451c25, 0xf5d8d421, 0x427249f4, + 0x3a7a1082, 0x730f2501, 0xfc1761fb, 0x4e35ca7d, 0x29651cca, 0xa07cf279, 0x136f4b84, 0xbed286ff, 0x6eeccdc6, + 0x0f9b3eaa, 0x07af724e, 0xa759d9de, 0xdb8622f0, 0x410bc087, 0xe654eadb, 0x83d2b61d, 0x5d81c025, 0xfc60c1fe, + 0x49feddce, 0x504d3499, 0x523ed833, 0xdbfd4fa0, 0x0213d764, 0x1bfb6127, 0x8031c1a2, 0x019c1aea, 0xd6f8e6fb, + 0x7e6c93dc, 0x8acf890d, 0x6bc2d016, 0x96e5173f, 0x2e1ffcb6, 0xc1a58e36, 0x51b887e5, 0xb58eca2a, 0x70360c43, + 0xeacfcad8, 0x98a95a0e, 0x02d004bb, 0xd9bd484e, 0x4bc175aa, 0xa06f398f, 0xeae18a0f, 0xdd43e30a, 0x183649b0, + 0x882f92d4, 0x746f5132, 0x51a6db65, 0x885b4e42, 0xb523eaee, 0x19014c83, 0x8ede1997, 0xfc8e6639, 0x64306926, + 0x72be02b0, 0x1342388f, 0x7ad0236b, 0x93c516bc, 0x97b65862, 0xa2fa1f39, 0xabd44172, 0x986f3a07, 0x1862463b, + 0x2d48101d, 0xc67443b4, 0x36f14a6b, 0xc651a017, 0x3029f7f9, 0xca905781, 0x820f00e9, 0xbae7852b, 0xe5938076, + 0x667b63bf, 0xfcd0c151, 0x21b3acad, 0x25e922a2, 0xe5d07e55, 0x8c6058da, 0x84edfac0, 0xb0380874, 0x136de21d, + 0xe71b1606, 0x56941f6e, 0xcff8af4d, 0x545ee826, 0x8de2b092, 0x4d85b134, 0x3b56f548, 0x6a541dca, 0x524272f1, + 0x1a1cd585, 0x6ef9320f, 0x7db4bd13, 0x4c6371cb, 0x6ceb91ae, 0xbb91114c, 0x3e3ab60d, 0xd2abb25a, 0x3fa24166, + 0xd251de2f, 0x9f455780, 0x7886ce17, 0x6ccb9d80, 0xbddf585b, 0x74f3098d, 0xd90c846e, 0xf8f1554e, 0x682d0987, + 0xd2c4365c, 0x9ca4b495, 0x9cbe34f2, 0x72b84357, 0x8fba65af, 0xaf05029b, 0xd773827f, 0xae6c7d9a, 0x1a361522, + 0x24f48925, 0x42d1ff0d, 0x23200a91, 0xe56c647c, 0x1868c271, 0xb5b8ed3b, 0xcf2155a5, 0xff3debdb, 0xfd36f5d1, + 0xd1efe543, 0x1327786c, 0x8df101b3, 0xf190c256, 0x4a741659, 0xc86151d0, 0xb957e29c, 0x5804e353, 0x585d8022, + 0xb04d33f2, 0x71c591f6, 0x962ec327, 0x11a87bf6, 0xa3500751, 0xb6bd3948, 0x479bd3a7, 0x76110c16, 0x0401b8ec, + 0x0303f698, 0x78ee5a5f, 0x690db778, 0xaace5424, 0x9c5e4684, 0x3f4848a4, 0x0bb6846d, 0x6b2dc44c, 0x61cc71ae, + 0x9148eb4d, 0xa128356a, 0xb44f00fa, 0xbae3eac7, 0x1a4d5a9c, 0x2f26d1f6, 0xe870be09, 0xdef9ddcb, 0x72caa902, + 0x4db112f9, 0x20c85b31, 0xd43e35ba, 0x61a9f881, 0x1cbc346a, 0x83e7f7e6, 0x8cd07cee, 0x36f70a6b, 0x4b95891f, + 0x01b2b04c, 0x27a3a0e4, 0x74207587, 0x37082b61, 0xc7005daf, 0x5145deee, 0x08bd615a, 0x8df3ff4f, 0xb87b3095, + 0x726b460d, 0x28b1d2c6, 0x4b22339d, 0x4feb01ec, 0x6f5da2bd, 0x09dce964, 0x528d79ae, 0xa84df118, 0x28f24996, + 0xd5b26fa6, 0x9c2accad, 0x56031015, 0x4486b8c5, 0x56272295, 0xadb79c5b, 0x9ce8acec, 0x221a98f7, 0xc0ea3097, + 0xc006e12e, 0x57c2ea70, 0xdee65770, 0x6f6b0b02, 0x0e92e140, 0x04b1a94b, 0x392a2ea4, 0x7d04da21, 0x5f7d0e87, + 0x12520db7, 0xc3cb6e69, 0xc539dd93, 0xf7e3ff65, 0x5a325964, 0xf99dfbfc, 0x76be702d, 0x80b04a40, 0x173b30c5, + 0x337971dc, 0xa3699a8f, 0x1d97280f, 0x05a9f91c, 0xf37999ef, 0xec2d57d4, 0x4a7a00cc, 0xfc8e610a, 0x3ced5e36, + 0x69d08345, 0xd5f5d29a, 0x2bc6507d, 0xf33b25bd, 0x65628c9e, 0xa293ab50, 0x9ffaf955, 0xf5ef30a7, 0x002c9003, + 0xc894ce53, 0x6c8a14f6, 0x0ae7a7dc, 0x7ff78a11, 0x22cc2a58, 0x67f9a377, 0xf9b8eddf, 0xe4d3faa5, 0xeff7c368, + 0x2f5236f3, 0xb86c8116, 0x539edd77, 0x4bf3fee5, 0x24c746ce, 0x71bad79d, 0x2af6ef64, 0x93326700, 0x98e2738b, + 0x4837d5d8, 0xcbf6f065, 0xe5c615c8, 0xa4c95722, 0xb22b9f19, 0x3b4fa261, 0x0dd790a0, 0x41e5b937, 0x1c0dd095, + 0x1a546852, 0xaa46a6d6, 0x2698e8fa, 0x6ce38257, 0xd3c694d1, 0xf18f5de0, 0x6764fbe2, 0x70c7343a, 0x94f42526, + 0xa5ceeac5, 0xbc219d13, 0x87c5b6c4, 0xb127dfe8, 0x572d2b5f, 0x1158cc97, 0xe50254a8, 0x1baff79d, 0xb6b37367, + 0x9f451e77, 0x5d9240f1, 0x1910f4e6, 0x04f90e4f, 0xcef0fb9d, 0xe7e8e140, 0xe47cbb85, 0xdb8f7a7a, 0xbc44c563, + 0xa3a3b3cd, 0x6e3a9a67, 0x650f35cd, 0x2b8c8888, 0x88dbea0b, 0xae116593, 0x98c7c96d, 0x2e666e3d, 0x2b278a4a, + 0xec876d61, 0xff64a704, 0x140c5997, 0x5cda2636, 0x7e9945ec, 0xe57ab4cc, 0x3ffbd8ab, 0x4e664d31, 0x18a66575, + 0x0104037a, 0x6871cff0, 0x5c35f8da, 0xdea0c544, 0x1c659046, 0xdb89fbe5, 0xba24cbfb, 0x338d5264, 0x03474c9c, + 0x3d749a08, 0xe3d5f565, 0x5ca1b808, 0xfa25baeb, 0x053a3625, 0x633381e8, 0xefa47867, 0xd373a8cc, 0x2d0b07ee, + 0x6d777113, 0xe94a8f72, 0xfb4590fe, 0xe35f42ed, 0xf65d42f5, 0x23323837, 0xa75bbe1a, 0xce492b33, 0x2af9e1e6, + 0x6fef7b76, 0x2fb18c61, 0x575157f2, 0x2c66431e, 0x891ba1ff, 0x9fcc2e76, 0x7fc596b3, 0x550c0787, 0x994c6e04, + 0xb1e41f1c, 0xa1eec524, 0x9f096b4a, 0x1ceacbd2, 0xbbf64c99, 0xc90fa698, 0xfed04a91, 0x05577325, 0xb0b186fd, + 0xd1298835, 0x97df3eab, 0x6dcbf4a4, 0x3b15debf, 0xf2e7075d, 0x06819d80, 0x816d3569, 0xb4952249, 0x3d8fd4e1, + 0xfd42a880, 0xb5e35338, 0x0ddfa32e, 0x46cfef33, 0x41184ae3, 0xf25033df, 0xbfb8e39f, 0x93c45af3, 0x15c4cf65, + 0x45b6192d, 0x62e076c4, 0x68eb2c5d, 0x701bcb83, 0x38eece2f, 0xb34e2c61, 0x841f5f1b, 0xff6ae47f, 0x7b4f102c, + 0xee206fd7, 0x1c3d70e6, 0x2f344ed6, 0x01ba94e3, 0x4c61a61b, 0xdffad450, 0xa234aa34, 0xac826c11, 0xc794e8c9, + 0xcc7c6868, 0xcebbd8e8, 0x937374da, 0x55d41369, 0x33835768, 0x79f2d883, 0xbb21bd7b, 0xa9fa8fbb, 0xddc4b5e6, + 0xd8759c55, 0xa3c02d5b, 0xafe7c5c1, 0xbeaf06da, 0x1b701545, 0x62a66b27, 0x042950ca, 0xa9dab5d9, 0x6b8806a9, + 0xfdd04dce, 0x6f2fae12, 0xc83b7fbe, 0xba2f596f, 0x64aaf03e, 0x2c1daf2a, 0xa1eff3ee, 0x65c7a0a6, 0x7c131805, + 0xd1b9c8c4, 0x735042e5, 0x93fc0945, 0xcd3e5c4c, 0x56891867, 0xc3ab58ca, 0x1f79c990, 0x48f66354, 0x60d5d0fa, + 0xd6cd80e3, 0x46def580, 0x3d8892b9, 0x76104fa7, 0x8fcc4e08, 0xaf340a6e, 0xd78ac9e5, 0x106ca51a, 0x67e5e79f, + 0x06f5a899, 0x4257b5e8, 0xe7fa2966, 0x260bb6d7, 0x9c97dddb, 0x922204a8, 0xac928b36, 0x2a6f8818, 0xb3e71b9f, + 0x5d268f46, 0x7cbf1b54, 0xc7e5e92e, 0xf13b0f12, 0xbc391ef6, 0xce25778a, 0x3d6c4973, 0x838ac618, 0x65e59357, + 0x52b90659, 0xd9ec7677, 0x5cf9145e, 0xb7db91d8, 0x7e05156f, 0xbdc98e7e, 0x86072b3d, 0xc6457666, 0x4a2a3f78, + 0x6599eef2, 0xc4e0550a, 0x546bb9f9, 0x784041bc, 0xb88499dc, 0x217945fc, 0xb66644c4, 0x061d0b87, 0x3402139b, + 0x3dbd49af, 0x22eb8abe, 0x0f286740, 0x2ea03adc, 0xed90e9fe, 0x0f2a5b58, 0x0d3ca74f, 0x68a329cf, 0xea71a48d, + 0x06fa1ff9, 0xd435c2a1, 0x75e7e1b3, 0x36ef75f2, 0xe79b1279, 0x1a6f5bd1, 0xab3a740d, 0x0e1dd4ef, 0xbb7a4454, + 0x609c9fc9, 0xf9ca07d6, 0x0e3c1c42, 0xc5686247, 0xb8e860a3, 0xd63c49ea, 0xc1aa08e4, 0x9e0c3d17, 0xe985b039, + 0x2d6aba26, 0x963c4a02, 0xe1db010d, 0x255c1fdd, 0x163cc8b8, 0xd7e47da7, 0x791a5fe5, 0x18efd602, 0x5baaa0ce, + 0x4290d184, 0x8f526c85, 0xaa2f9f3b, 0x3d22bbb6, 0x73791cf6, 0x76f73f13, 0x7ce56934, 0x1075fa20, 0xedb96e37, + 0xb4f4a88d, 0x0df1655f, 0xda65ba11, 0xee88e523, 0xad2e6645, 0x027ad9d0, 0x4d47f09c, 0xa0497184, 0x9741c8e9, + 0x0b8963f3, 0x43311600, 0x10a7dc04, 0x1c4e0f22, 0x777fd5e5, 0x44bc28dc, 0x3b5efa6f, 0x599ece48, 0xb5de247d, + 0x11944f9a, 0x1832305d, 0x2085b3cd, 0x2f839db8, 0xa06133d7, 0xdfed73d1, 0x637eb5f1, 0xf1fe82ee, 0xdf0c7520, + 0x0787c10d, 0x9f6a59c4, 0x11acd71f, 0xd05c3ec0, 0xbb604e7b, 0xa65340c6, 0x90c3e070, 0x7dcbec1b, 0x3a25ca70, + 0x70cfeda3, 0xb01224df, 0xf13a327c, 0xccd6ec74, 0x67508113, 0x39c41b88, 0x7af8f21c, 0xfd7c288b, 0x8aed43a2, + 0x9388be79, 0xa1a2b954, 0x177deded, 0x7df258b3, 0xf09a93ab, 0x25b6b2ab, 0x96046dd6, 0xa31a5443, 0x53910a78, + 0xb93fab0e, 0x4a456f8b, 0xfbc353fc, 0x13c7090b, 0xb4ae1da7, 0xc37c98a3, 0x330cc1d9, 0x0f546de0, 0x633f64d9, + 0xf595c948, 0xad1ae6dd, 0xa26fb87e, 0xc52f6d3a, 0x379c7bd8, 0xb9944442, 0xf96df92a, 0x997d8835, 0x0b9858a8, + 0x2514eac7, 0xa53677b0, 0xa3342e23, 0x6acaa693, 0xe2c9d4c4, 0x12f0e3cb, 0x4cd6ec90, 0xfd2bfab7, 0x34edab95, + 0x2b98b132, 0x26d6ac4d, 0xb245ed40, 0x85309828, 0x877b690a, 0xf4cb94d6, 0x70ab90ff, 0xf4e71286, 0xb6b33d46, + 0x871060fd, 0x721fc7a8, 0xd82ce615, 0x2ecf6254, 0x3e7c439b, 0x672fb53e, 0xd5861403, 0x0bbe4fcf, 0x68603f5a, + 0x2cd5ab36, 0x0625b382, 0xedb1407c, 0x2491387d, 0x5e05400c, 0xfe3bcc51, 0xcf9a2c3b, 0x7d0cd3b4, 0x54eb3138, + 0xbf7f2f15, 0x01024a9d, 0x502ca6e6, 0x8457d576, 0x0cdc5c40, 0x7feb959b, 0x0b5fe8c3, 0xb0853ad8, 0xc73830d9, + 0x86fda5c6, 0x6a2cfb1a, 0x2fa84359, 0xf56226af, 0x28b3fc60, 0x877f8163, 0x40563afe, 0xa9c72ad0, 0x5115b904, + 0xd029b85d, 0x283f5c08, 0x98dc0596, 0x7c11d8e7, 0x5990c37a, 0xc9b57c7d, 0x33881bd5, 0x5c110fe6, 0xff0e01eb, + 0x87031ae8, 0x3f86c077, 0xcfbe34b6, 0xc6b5a4f1, 0x8a264931, 0xaf5d029e, 0xc69b5f25, 0x1d321e70, 0x94421e4a, + 0x671f4bd4, 0x3a9c7bcf, 0xbed171b3, 0x5d13f391, 0xc1b83f69, 0xf483d2a5, 0x61f86f33, 0xd79d69d3, 0xa16f7e23, + 0x49013b88, 0x171db9f8, 0x18a5c0e7, 0xe207f0bd, 0x95b89140, 0xbcad048f, 0xd950d5c6, 0x1a6e9957, 0xbb4a654e, + 0xbb20573f, 0x156f7aef, 0x80b8e708, 0x1864d9d3, 0xc9dad81a, 0x37f9bbf4, 0xda3ffc6c, 0x19f836fe, 0x6646b72a, + 0x85480bfe, 0xd3e4903b, 0xa581e756, 0x34c33721, 0x1ce9c01e, 0x6387ba5a, 0x61d659dc, 0x3ed596c3, 0xd14f31a8, + 0x109118d5, 0x6583a931, 0x5057b608, 0xf19426c9, 0xe9a6c515, 0x0d5ad27a, 0x3e614168, 0xb62223bf, 0x4d8e1c48, + 0xb0425570, 0x06a97b56, 0x389127b0, 0x04e78ee0, 0xe4548530, 0x3f9b1109, 0xcca1aec9, 0xb3ea1182, 0xd0c3b0d0, + 0xb6b5407a, 0xb0ff06f5, 0xeb82453c, 0x39127595, 0x3e078c98, 0xda69b9bc, 0x87cef691, 0x596c188e, 0x4d0e981e, + 0x0c329a09, 0x096af33e, 0xd363249c, 0xd6534394, 0x9e1ce364, 0x57b4a910, 0x22902ec5, 0xb8972057, 0x7018664b, + 0xc6caac7c, 0xeab02f4b, 0x43b6662b, 0x9e6abde8, 0x59f27869, 0x643221ec, 0xa008e6a7, 0x262e842c, 0xe8f20e30, + 0x22892de8, 0x005476fd, 0xa3c5c762, 0xda9ac0d4, 0x682be8b1, 0x50bc8809, 0x3fa21500, 0x83158fd3, 0xb8ab5398, + 0x885d2117, 0x2285be73, 0x3023b5ad, 0x77e2f510, 0xc8742308, 0xe7c14f04, 0xc0efc436, 0xcb639971, 0x0d15bd88, + 0x8acf4dba, 0x3370051b, 0x8b6ee2d3, 0x2a3c1d40, 0xc40a523d, 0x6bafd6ff, 0x9be98308, 0x5dff4fbb, 0x1d8c6b2e, + 0x124cd131, 0x569be7fb, 0xba43bbc3, 0xa8b99620, 0x2483e32b, 0x2efdfa50, 0x2d5e697a, 0x46d95b09, 0x43d9cac9, + 0x0726b875, 0x85494788, 0xfdb77453, 0x21aaff4b, 0x51186bce, 0xc7d0d4b3, 0x9c6ceb8c, 0x4d64740a, 0x8958c6cc, + 0x85c12d1a, 0x2a2d86e3, 0xd622cc59, 0x4b983f4c, 0xbeb28e91, 0xe10eaa71, 0x9475d255, 0x20283c5f, 0x1a6e63c8, + 0x647157de, 0x1737b452, 0x7fef1616, 0xd69de7d6, 0x77cbe2d6, 0xf4f0206c, 0x45944a6d, 0x53a83dda, 0x39384fdb, + 0xab9e0008, 0xb951d55d, 0xbdb64058, 0x36ddf997, 0x1ba70ebe, 0x19779145, 0xef53482e, 0x64e71564, 0x8e98944e, + 0x60160b7a, 0xa3d737e4, 0x6f8c18e6, 0xfb62f6e0, 0xa5cbee8d, 0xdacf64a7, 0x7d9b9ec0, 0x3b402d51, 0xb2aee177, + 0x4018644d, 0xeee1039d, 0x106bd49c, 0xa4784a14, 0x16cefca3, 0x60bf4a32, 0x038cd9e0, 0x35a2ee5e, 0x67615917, + 0x5c62c416, 0xfcc123bc, 0x2e7185ce, 0xb21a13f9, 0xa2a0803c, 0x2d615bea, 0x42dd0d6b, 0x79758338, 0x26e418dd, + 0xe886525d, 0x7ab5c66d, 0xa0627f48, 0xaabcccfc, 0x70fff656, 0x652f516b, 0xd3d69fbf, 0x9d5eeee7, 0xe3597a5f, + 0xbfae655d, 0x382ad75e, 0xea92ac84, 0xe3106289, 0xdd2aaa32, 0x6e52e90c, 0x394fccb3, 0x25dce4af, 0xc2247fee, + 0x4d6c618c, 0xf81e9440, 0x0d1572ed, 0xc461afa7, 0xbf53d1c8, 0x1509a97c, 0xc78491aa, 0xd8977ee9, 0x0cba47b6, + 0x27f9db60, 0xffbe4aa8, 0x044eec4f, 0x3fde5097, 0x49dafb05, 0x9a2926fa, 0x085c9c35, 0x3e4eb5d9, 0x1adc0e2b, + 0x169984ba, 0x87c177cd, 0xf590d5c4, 0x5e30b16f, 0xc77dd42d, 0xb0ca8445, 0x4a372484, 0x7e6616d1, 0xc451d753, + 0x728bffb4, 0xc25e9bd5, 0x0b1d5401, 0x1ad65da3, 0x64fc9136, 0xd2b9b0ba, 0xa1442dd7, 0xe903fc31, 0xf2b73415, + 0x289978f2, 0x4910a046, 0x4bbd1739, 0x8e5f3c8b, 0x44ba41ef, 0x208ac4b5, 0xaa63fa83, 0x75831670, 0x6d95960e, + 0x20c0177c, 0x0dd58197, 0x79740c43, 0x308d9690, 0x669538d2, 0xdd670e7b, 0xee170f51, 0xe366e2c3, 0xa12fffba, + 0x1b6036df, 0xa0598e8c, 0xdb933274, 0xb014ed0e, 0x06d6f2db, 0xbbb7a23c, 0xb44cce9b, 0xec5cd2be, 0xb339280f, + 0xb30f9c37, 0x4cdedf53, 0x60657bf9, 0x53e9fb15, 0x06258a27, 0x73be6287, 0xf5dd1db0, 0x50d36b6e, 0x735f7fc4, + 0xe96c63d0, 0x9f85c747, 0x235ad6d5, 0x4bf387c4, 0x8eb33458, 0x5cada245, 0x13dd2ac7, 0x65420a33, 0x20c91fcf, + 0x87a777f8, 0xe9ad31c9, 0x00d2b31d, 0x4977bc8a, 0xe6e55a4e, 0x4c772e43, 0x591bee33, 0xaf93f738, 0xad844330, + 0xc2114a73, 0xee33750e, 0xf4f598cd, 0x90310a9d, 0xefaed9de, 0x01d83eea, 0x51514b5a, 0x78d5c45b, 0xd2964941, + 0x6d1150c3, 0xf5ddfb7d, 0x22b8fa39, 0x8c532af1, 0x3a15c24a, 0x9ebcbf1e, 0x72fb1320, 0x1d2b0278, 0x1d319dad, + 0x54aaba12, 0xa35a48d3, 0x44f04ffe, 0x605411bb, 0xf4f330d3, 0x7a11472b, 0xed63624c, 0xab42370f, 0x38846da8, + 0x259edfd4, 0x65662849, 0x8175a6e8, 0x692b823c, 0xc39fa5ca, 0x86fa9fe8, 0x45742930, 0x33a9ce9f, 0xc81a3c69, + 0x39a9b0cd, 0x75e9c383, 0x88b71522, 0x1fda5ab2, 0xd70e8339, 0x1e1cae04, 0x7a04d288, 0x781ed892, 0x35e7594a, + 0x3c890fad, 0xd27388a4, 0x60539a9d, 0x268b6566, 0x696e163f, 0x4c0c94a2, 0x5761fe0f, 0x34a71a85, 0x9edeb4f0, + 0xf42caa15, 0x0be76031, 0x7c7d98be, 0x165da2d9, 0x3d8f65e4, 0xd4ca1eac, 0xdbeeb839, 0x05f3cc55, 0x98a8ee43, + 0xe14e2cca, 0x41e368c1, 0xe17f5fab, 0x928ea72b, 0x281b0c07, 0x83449d1d, 0xee630cca, 0x8bae123a, 0x1bc20da5, + 0x2f1fbb0c, 0x26d50c91, 0x08181a26, 0x795edd8a, 0xcc755df8, 0xe4eded20, 0xf124f916, 0x243cbef8, 0x80aa03b9, + 0xb157572d, 0x67fc9361, 0x46748be8, 0xd389844e, 0x65220ee0, 0x932ed9c2, 0x7a966dec, 0x138ebf13, 0xacac95e4, + 0xb14f5f9d, 0x966f54ed, 0x57467919, 0xd85baebe, 0xc10279e6, 0x8abe89c6, 0xfec99567, 0x71123fa8, 0xb0e0f2d8, + 0xaefb2cac, 0xe380ba98, 0x95bb5d5e, 0xc2b283a7, 0x674ba41e, 0x5cc81ed1, 0x70ae6af7, 0x4bd8d9fb, 0xf3e641ca, + 0x62033344, 0xe0a96a61, 0xc41c4c51, 0xdf98cbd8, 0x0d4b117e, 0x02aa5d94, 0x3ae227e1, 0x5e426fd3, 0x42305704, + 0xf8ae7585, 0x3383a7f1, 0xcc759718, 0xf2371da5, 0x02f02c86, 0x3de3333b, 0x3c6d822a, 0x9450695c, 0xad40b7f4, + 0x697df81f, 0xb4832046, 0xcdc9f36e, 0x72d40665, 0xea23ff03, 0x24b4ad0f, 0xab7d5bdd, 0x143974f2, 0x37705bae, + 0x62883232, 0x821d2348, 0xc4cd2938, 0x328ca6a2, 0x1f2c68aa, 0xea9462fc, 0x28d4dfb9, 0xc9026bd0, 0x86222a2d, + 0x8c8f1365, 0x60f5506b, 0x7f9694f8, 0xa181e2cc, 0xebfdfe5e, 0xb8de21b7, 0x15feb4fc, 0x431129c2, 0x9b767fdd, + 0xcd4206c2, 0x8d86f97e, 0x34058499, 0xbeef0da6, 0x7d0c9dcf, 0x5879c5f8, 0x2b53a205, 0xc35364c1, 0xb9fd89cc, + 0x7cec2c24, 0xfd8bc84d, 0x4aaf716b, 0x6a285959, 0x773e427d, 0x58a98e02, 0x7b888a27, 0x6deffcd2, 0x25a92bac, + 0x4b35ea1a, 0x9c8b3bc8, 0x9fde3297, 0x121e4173, 0x5e96370e, 0xb49ea9b3, 0xbe79e2d8, 0x698cc1b3, 0xb13c4298, + 0x285b3342, 0x9a2cdfbc, 0x0652d0a9, 0x29460970, 0xee2082fc, 0x0efec6d5, 0x10cd69fb, 0x924ea91b, 0x76cf37da, + 0xd0fc6c21, 0x2cc96fc8, 0x959b2495, 0x0616bda1, 0x28730fa6, 0x25f72afd, 0xf10ce066, 0xcc052cc3, 0xa8094ad8, + 0x1855b7c1, 0xb76dabd6, 0x0212864b, 0x18768e64, 0x30f8d9db, 0x665616b7, 0x63b0863d, 0x48f8fa5d, 0xd3540fb2, + 0x90fda4e8, 0x75587f00, 0x86f67c55, 0xa22bf7ed, 0xa2baff1c, 0x0e024219, 0x50041c02, 0x93a36b0e, 0xeb3107e9, + 0x029c8149, 0x410029ab, 0xcc081691, 0x8753ec9d, 0x5554c598, 0xb1913865, 0x5c81f875, 0xa50d1d1c, 0x528a3cbc, + 0xf01cd9fa, 0x081b6589, 0xcf0af596, 0xb8ba5b6c, 0x7be237ba, 0xf29d6ff1, 0x8ada5696, 0xd44431d5, 0xe63125e4, + 0xe1f2e6fb, 0xe9d7ab04, 0x5f047627, 0x3abcbc5c, 0x5c3b6051, 0x824be184, 0x3a45354d, 0xe1ca37a8, 0xa9090488, + 0x592318fe, 0x18ec2b0d, 0xbd494ce7, 0x26216670, 0x6752125b, 0xbb31adf0, 0xb843233c, 0x460fb0cb, 0x82cee00f, + 0x1bec7b06, 0xe20868ec, 0x1928621a, 0x4186d2ae, 0xf2134a8f, 0xd9761054, 0x89319005, 0x52545d49, 0x42865469, + 0x9ba66e78, 0x2bb16f43, 0x97a0117b, 0x0dfd18d1, 0x5c38a88a, 0x411b12d1, 0x51cfc213, 0x674fe07c, 0x2b9e61ef, + 0x11d8dba8, 0x71741d98, 0x704438dd, 0xe9727fbc, 0xc383a785, 0x1495fc65, 0xf29fa11e, 0xd2e47a6f, 0x68a12745, + 0x0ab9b681, 0xd8b307c9, 0xf92f6283, 0x3ff78cd7, 0xa1e7ce2d, 0x1709c50b, 0x51fabeca, 0x9c3d628a, 0xd7b760a0, + 0x7f240953, 0xd66ec0de, 0xf0e3e147, 0x5126fd62, 0xec703b40, 0xd4b66bfa, 0x11ec913f, 0xf9dd52f4, 0xb146fb28, + 0xcfb66a9e, 0x6169f9df, 0x5e7cf29a, 0x48e35f3a, 0x50be2d8d, 0xfe6d199d, 0x40e44314, 0x454f2b80, 0x2a534fee, + 0x8c8c3de3, 0x6e6b59ac, 0x496e1bf6, 0xf3acf96d, 0xb7ad928e, 0x09025aea, 0xb96aad23, 0xeb26bf79, 0xa2fc7860, + 0xc89ab216, 0xc1233df7, 0x0843f469, 0xa5a5dd43, 0x73a88691, 0x598b7f53, 0xa82c8aae, 0x3bd0dae3, 0x8484a834, + 0xcd854038, 0x3a8fabdd, 0xc507f89e, 0xfc969320, 0xb005f17d, 0xc276f282, 0x3b04b5be, 0x76c311ba, 0xb1ca39ee, + 0x58a5966f, 0x1f616b08, 0x69c47b2c, 0x0abca054, 0x69f46b5c, 0xabe2dfb3, 0xbc0c71fc, 0x33f45619, 0x783aa867, + 0x1dcc955a, 0xdd6f003c, 0xc839b43d, 0xda706175, 0xc1a31f09, 0x27ef79e2, 0xf27db70d, 0x5f5a30fe, 0x3b941008, + 0x7742bc70, 0x1b733f8f, 0xd5e65b11, 0xaa5e5b1d, 0x7734bb12, 0x617baf39, 0xf878c1ee, 0x75022b33, 0xbef91840, + 0x09da681d, 0x211c1462, 0x3e242ea6, 0xccb13608, 0x580970ae, 0x6b568503, 0xe8a9c751, 0xd4c7a88e, 0x06a4c71a, + 0x5f2fbfee, 0x5ff30266, 0xe9d64cf8, 0x8dd6dc97, 0x3b4601e7, 0x8f986dac, 0x3274c85f, 0x183b0346, 0x1bb6a0ab, + 0x058cee0e, 0x0fb967cf, 0xd9e6b2fb, 0xa1992e9f, 0x9ca98f88, 0xb8df5f3b, 0xc41b536d, 0x857cfdc1, 0x04c2c07a, + 0x1d9c350c, 0x24615cc1, 0xf71c1d8e, 0x047ceb16, 0xd2baf34d, 0x55bc790c, 0xdc141f7e, 0xe3d14729, 0xe1de0050, + 0xa82290c1, 0x950632c8, 0x9a06b618, 0x4ca13792, 0xc58d07a2, 0xb1bddc9e, 0xb33d9665, 0x296b06df, 0xfe74b7d7, + 0x57580d75, 0x18e5bd2f, 0xb75a82f6, 0x709894ea, 0xecc8604e, 0xeefc2609, 0xe2ff390a, 0xfdf67df9, 0xab718bec, + 0x3271e7c7, 0x7a512d58, 0x9201d589, 0x0de6b268, 0x5fad7308, 0x462cd7eb, 0xd663c98d, 0x8da6bd8d, 0xd8235b09, + 0xe8653ef7, 0xb152b7aa, 0x3d3cbb1c, 0x2fbaa374, 0x01704b46, 0xb55511e4, 0xb3c616ed, 0x1e865bfa, 0xa44286fa, + 0x7409f5ca, 0xca0678a3, 0x7fdbc5f5, 0xeb846235, 0x3ee569e9, 0x7d871f18, 0xa722dbec, 0x266dacc6, 0x8d2069a1, + 0xb79bc658, 0x28c63949, 0xd2653753, 0x76b57ca5, 0x7e0f8881, 0x3ca47226, 0xad4c6b5c, 0xa1d55323, 0xb090e44a, + 0x3a64fef4, 0xc5c62886, 0xbb196f32, 0x04b937bc, 0x508710d3, 0xcf13dcd5, 0x7369e38f, 0x652952e2, 0xd139a7ff, + 0x5b298867, 0xe4da0e94, 0x97db8049, 0xe740549e, 0xf967241b, 0x1e78ceca, 0xd94b130c, 0x23170415, 0xe4efe06d, + 0xe5219703, 0xb6f276e0, 0x5a7b1e64, 0xd79ef7a8, 0x7bb9201a, 0xd0e5370d, 0xab5616cf, 0xf2817680, 0x09a55a4c, + 0x11dae4a9, 0x4ed3e89a, 0x6a6fc4f3, 0x5d0ad37b, 0x369ebc35, 0xf93b81a4, 0x46778577, 0x3356cb35, 0x915e0567, + 0x438c6e9b, 0x0205ff77, 0xd6d4485e, 0x03010d12, 0x81b8c4a3, 0x51e2c271, 0xf5dea40b, 0xe868e2f9, 0x28bc3577, + 0xc7eddc81, 0x3559ae39, 0xc81591c5, 0x7bbb481d, 0x450ecadc, 0x9b35dc60, 0xd0d3be61, 0x0dbdf885, 0x6bd011f5, + 0x20eb8688, 0x7b72a33d, 0xc8a05841, 0x4acb5285, 0x2c70a77a, 0xddfc150d, 0x3bca1a3a, 0x26d91e66, 0x4795c384, + 0xae13d0ab, 0x82e4ecea, 0xaf8c745f, 0x92f935b2, 0x77e88e20, 0x1be48f20, 0x7a161e33, 0x483ba7af, 0x6c638565, + 0xc91bd989, 0xa0b327aa, 0x7a5ffeaa, 0x3e9e56f4, 0x76f48f54, 0x84ff1a63, 0x8a78e858, 0x8b5c8e3e, 0x51bec55d, + 0x1fdbe06c, 0xd26c18cc, 0x81151865, 0x8098bbd6, 0xc1872f25, 0x30081a57, 0x29c8562d, 0xc92c219a, 0x9492eb9c, + 0xb68c47fb, 0x0e3387ea, 0x9149586f, 0x94184de0, 0xcf4b1fa9, 0xb7671c78, 0x74ab5b7e, 0x98184fce, 0x99f3bb3a, + 0xb9af490b, 0x82eb331a, 0xb5b78729, 0xd5d94b2f, 0xb2ab4163, 0x34ce01ba, 0xab04f8ab, 0x483cbc0d, 0x40edc513, + 0x671e92d5, 0x948eb15d, 0x614c7992, 0xddf8742f, 0x3d98c7ad, 0x507b5767, 0xc2ed8873, 0x886c1ef4, 0x6c0ffc5a, + 0x43cdcccd, 0xd5f739d1, 0x1edfd97b, 0xbe7928ef, 0x1194acca, 0xc8521584, 0x76077e55, 0x7946147d, 0x49473652, + 0x09b488c4, 0xc5fa1631, 0x1df9143d, 0x60255b3a, 0x77944307, 0x06f1ee99, 0xfe0c5774, 0x9dc26a53, 0x0ae9c679, + 0x92094b71, 0x910e37d2, 0x9bea417a, 0x391fd4f9, 0x40d8f4d5, 0x69bf0451, 0x803c5fc7, 0x29c2ebaf, 0x48ff9872, + 0xb878c55a, 0x57747939, 0xe80ed9be, 0x0e44d860, 0x5c8dcbe0, 0x3f23bc5a, 0x44be7efd, 0xcd37047d, 0xf97b7cf5, + 0xa9e082be, 0x34f94bd0, 0x6fda9e5a, 0x4826f722, 0x6e92445d, 0x8f55076e, 0xb0f21133, 0x3d80b0eb, 0xb4f34b7f, + 0x8f0c6933, 0x46dfc4a9, 0xf3e5d94d, 0xd4b0440f, 0x229840e2, 0x801bad00, 0xf8504a57, 0xa9b88389, 0xe6690c2a, + 0xcf72106d, 0xea9face5, 0x0a9c1da3, 0xf70b53f3, 0x305b5820, 0x5eee68c1, 0x7a8845ec, 0x39831bc8, 0x626e48fa, + 0x6e315779, 0x893f845c, 0x6f907441, 0x2595c115, 0x29de2a9d, 0x38909776, 0x73a5e4f6, 0xaf5c9fed, 0xb6f9ea5d, + 0x0653d8b1, 0x91cf5a54, 0x3e448a8d, 0x407eb059, 0x2e4955a8, 0xa4986d7d, 0xd12b7d5e, 0x0bbc9c6d, 0x7571a6d7, + 0x2d52d9ed, 0xd88810af, 0x981d2d78, 0x46481996, 0x9ec5b9b0, 0xeaeea55d, 0x26ab6019, 0xc35dc932, 0xdc420682, + 0x88a15dc9, 0x450833cb, 0x022e1174, 0xc41279ba, 0x129bbbc1, 0xa8f3819f, 0x50850e52, 0x4c1859ae, 0xe52fa9f5, + 0xb99166c1, 0x0b023953, 0x29eaffba, 0x92af16b3, 0x251aa71d, 0x2edf8a76, 0xdf6c4f46, 0x29463a42, 0xafdd4cce, + 0xd9b90f58, 0x005905a9, 0xa65665f9, 0xeec8dc81, 0xd720a871, 0x0ce53b72, 0x99d5374e, 0xc833a4ed, 0x063f9738, + 0xfc56aa6d, 0x959f6244, 0xae0fa503, 0x466f6535, 0xed0d9cce, 0xa3f910e4, 0x48c91981, 0x67a210dd, 0xe7adfef7, + 0xeab35d99, 0xbc0a1f1d, 0xe2004888, 0xdf0dc70a, 0xa5c7dd26, 0xbf555b3d, 0x3e85d51d, 0xf46902ae, 0x06991e41, + 0xb4e4b2b4, 0x09212001, 0xcca5779a, 0xa5f913f7, 0x04df94d2, 0x7eb92b78, 0xc6cdaaee, 0x81a60442, 0xd5c9d3c4, + 0xe2b5185f, 0x4faa17ff, 0xbf1a6f7e, 0x2a95c1e3, 0x7682bce5, 0xb792dc98, 0x1e2c10b6, 0x0c0fbf44, 0x71c15510, + 0x6e509fd9, 0x098a11fa, 0x1daaa4f1, 0x26f43ce2, 0x4d5332f5, 0x6ef7be3b, 0x82ed2b7e, 0x65bc76e8, 0xcdeed7fc, + 0x4463e6a3, 0x17b78181, 0xbe6e8f5f, 0x254bc138, 0x5789b18a, 0x18451eb9, 0x5d8f5e21, 0xaf9e641f, 0x1086dd39, + 0x83b78dfa, 0x14ef5f30, 0x90a56a49, 0xe952c4d3, 0xa1bc8eb3, 0x8d69f5e5, 0x007c7e0a, 0xcaafdd19, 0x9f16acec, + 0x3f60e640, 0x63dbbefb, 0xac5258c6, 0xc88d32a2, 0x44e78a8c, 0x9fb4380e, 0xcf401d88, 0xfa2f564e, 0xa2f70458, + 0x7867d04c, 0xe034b5bc, 0x557bd0c2, 0x27ea0de5, 0xd9387428, 0xb8c15681, 0x94ea6894, 0x8d0efa17, 0x6016a632, + 0xca521155, 0x415a85ef, 0x00d69984, 0x433468dd, 0x73bb1ed3, 0xf55a5ff8, 0x995a2dfa, 0x731d1d94, 0x49791200, + 0x3a21e9ea, 0xfa4b2141, 0x707b117c, 0x24de087a, 0xeb3161b6, 0x2df28c7f, 0x2a02a5c6, 0x0d584b85, 0x0573aa02, + 0xcb6c657c, 0x85596ad0, 0xc9fbf29a, 0x729bec69, 0xdc0bd3b4, 0x96a23af2, 0xacb70a10, 0x188f25d7, 0xb8fc076e, + 0x7adf3658, 0xb3f0f217, 0xf09d2489, 0x62d8c18f, 0x99061b08, 0xa47c59f1, 0xef4f6263, 0xb900113b, 0x15ecd0f5, + 0x17f8b513, 0xbfe66bbf, 0x9a386619, 0xbf43ee20, 0x8e2a6266, 0x1eef8bd2, 0x2f37cb0e, 0x4b442ed5, 0x52ef3933, + 0x3f1a40d5, 0xc431c283, 0x682ffa0f, 0x3395eb56, 0x71d4bda4, 0x6f372193, 0xef569b65, 0xc5a106ba, 0x2e4f80ec, + 0x6821b19b, 0xa77783b4, 0x362db0ff, 0x39ea2080, 0x02438de3, 0xdd4eebe0, 0x338754b0, 0x9bba679c, 0x47846129, + 0xc2b90cb8, 0xbc6c84e6, 0xa9802868, 0x3a4d3749, 0x94845466, 0x9b4e9ccd, 0x18e01661, 0x7291d427, 0x505a4ee4, + 0x273366df, 0x7a92f7e5, 0x2956ef24, 0xee8698eb, 0xea521fa3, 0x40a445cd, 0x53105466, 0xe015e0b1, 0x2afe3b55, + 0x71933b8a, 0xcdce3fda, 0x3fc1c734, 0x85ae3c42, 0x9b79bc03, 0xa26733f3, 0x028ac9f8, 0x448276c6, 0x67e26d72, + 0x3a1994c9, 0xa67ee9de, 0x76f4c5c3, 0x1e5378fd, 0xc7bf267f, 0x9a845613, 0x79d56386, 0xa960826d, 0x0ab4f26e, + 0x83888864, 0x3ae2d966, 0x5d820c11, 0xa6e2575f, 0xf932f2ea, 0xfd8923b9, 0xd69ef576, 0x45f00bfc, 0x870c32bb, + 0x0c57459a, 0x6f258ef0, 0x47f8f1b3, 0x0b1e32d0, 0xf3def980, 0x0de83f72, 0x3569a143, 0xb5e8cd33, 0xe0428014, + 0x416f70dd, 0x1a85244b, 0xdc36bcc3, 0xd9492959, 0xcfe7f71c, 0x957fe14e, 0x9e0f754f, 0xd1e44988, 0xe32d125f, + 0xe1100331, 0xeb614be9, 0x33ae98e1, 0xa8def97f, 0xf51790da, 0xd9771ef8, 0xd9d59b4c, 0xedb6d724, 0xf0098aab, + 0x5f1e0086, 0x8d5248f7, 0x468f7633, 0x1afb3d20, 0x5ae76f38, 0xb9255bf1, 0x9c395476, 0x080ae480, 0x633913e6, + 0x59ec3860, 0x3ead38ee, 0xc292b96e, 0xf3392a7d, 0x0ae9cce5, 0xfa2974b4, 0x363bc411, 0x7fcc8da3, 0x1eda21b9, + 0xd2e52848, 0x24fc8055, 0xc1becdf5, 0xb3f9889a, 0xbba80bf3, 0xe8ab93e2, 0x8ea7f4eb, 0xee51b13c, 0x395e8ff9, + 0x4238ebb5, 0xa894cd64, 0x5bf36cb4, 0xeb243eca, 0x03a9916c, 0xc056d0c4, 0x2658797f, 0xc1fbc6a7, 0x54c41ed1, + 0x573e3729, 0xa27233bf, 0x68e8c123, 0x642e1e19, 0xd7b2301f, 0xa16ccf90, 0xcb9a2740, 0x0ed71576, 0x816cb19e, + 0x35922a93, 0xcb2505d1, 0x053a5b49, 0xd87ca3ab, 0xabff87ce, 0x4e4c0f17, 0xac99bcb9, 0xfd74c23d, 0xdd1b85f1, + 0x46b9efc0, 0x7ef9cfdf, 0x3ebfc93f, 0x923a7149, 0xf7be960c, 0x6533e2a7, 0xa4341359, 0xb3f8cb05, 0x054af815, + 0x9ca4a535, 0xce2c4168, 0xb5d0f287, 0xc76d28cd, 0x81b5fb81, 0xb111b690, 0x7e6f6be7, 0xfe23b6d3, 0x3e7da344, + 0xe1d51fad, 0xf0b2e884, 0xefdd2699, 0x78a14aa0, 0x2120e3bb, 0x24d581c2, 0x84562936, 0xe8b87c9d, 0x5db9f672, + 0x46b8cae8, 0xc9b7c1e2, 0x17237e59, 0xfc81f17d, 0xec1a4840, 0x9719ca77, 0x334f3ca8, 0x5ee5a770, 0x16bf2245, + 0x13e61148, 0x82f7e14e, 0x9bd331e9, 0xa56d3590, 0x78b85329, 0x9f298d61, 0x11758f5f, 0x2ea629ba, 0xd92bdf71, + 0x239f4091, 0x9a60c6f1, 0xf55bcd71, 0xad040b4b, 0x4d4c6969, 0xed6d1734, 0x9a6015a5, 0x502bd426, 0x357e2d65, + 0x07123660, 0xe2cc588b, 0xc7121e46, 0x42667839, 0x3a46fcb6, 0x8c6e3f9d, 0xd2188632, 0x1b671c08, 0xcd8710d2, + 0x65797997, 0xd2f1a629, 0x475b6e61, 0xb50f2c31, 0x49d618a4, 0x6da853ec, 0x2e24282a, 0x6bcd11f4, 0xc198e9fe, + 0x57d1690a, 0x303fff0c, 0xc6381d15, 0x9d3ad31a, 0xe41698df, 0x3f0cb215, 0xfea74c41, 0x264ca262, 0xefb1c43b, + 0xccd3446f, 0x614db12a, 0xd6f3b17c, 0x04ca3302, 0xa73f5a71, 0x08693e5e, 0x9c8c73c3, 0xadbec8cd, 0xe9f4740f, + 0x73182875, 0x1823709e, 0x071c651a, 0x16d78de5, 0x38e79e3d, 0x74424949, 0x3e9fb304, 0x1b2b8734, 0x3874c713, + 0x2c495a3d, 0xf39663a7, 0xdb694c93, 0xba64b29b, 0xab48a4bc, 0x8dca6bd8, 0xa9bb033d, 0x9634db44, 0x0c3fbf18, + 0xed0f79e0, 0x595a4e0a, 0x81e8e85f, 0xe162c1da, 0xd466c1be, 0x061f16a4, 0x96391099, 0xe3d646c5, 0x6a1ec0a9, + 0x20d224d6, 0x1adfd5e1, 0x5725cc04, 0xe3e9b613, 0x815605d4, 0x3358e42e, 0xf915b9a0, 0xeb537728, 0xd78f3114, + 0xb3eda92b, 0x0b08ecd0, 0x8a861a69, 0xb763e5dc, 0x93362cbf, 0xed102387, 0xae7ab739, 0x21d0f94d, 0x70dd8d4b, + 0xeea30da2, 0x1d843c74, 0x9a08a5a0, 0x23ab1b45, 0x86b4892e, 0x776ff20f, 0xf6b0afd3, 0x0da85653, 0x824a5dc5, + 0x581849d3, 0xf9c708e8, 0x3c491c88, 0xc50a761b, 0x70747b47, 0x7f3b7f31, 0x952e3ecc, 0xf5e6a040, 0x762c7d6e, + 0x90aebd50, 0xd521b662, 0x43b6e640, 0xc1afd955, 0xb11a3a5e, 0x2b0410a6, 0xb4f43782, 0x9a5b4fc3, 0x72196e76, + 0x1f0a8dd9, 0xcbf85595, 0x0c86b410, 0xc7a3aedd, 0x6d0f2746, 0x77095fb7, 0xffaf2a33, 0xc232e8e8, 0x3de122db, + 0xb6900759, 0x4e4c986e, 0xb7959674, 0xcf316af5, 0x97b81b2d, 0x4bc2709b, 0x5cd5d47f, 0x5bf593e5, 0x519e1f49, + 0xc91c8fd5, 0x2a0173c8, 0x01e40e50, 0x686ebbb6, 0xf976b765, 0xb4099070, 0xd0d0134e, 0xfa2c1e9d, 0x9b62253d, + 0xff251feb, 0xca0e5de0, 0xcbd6dee9, 0xf8369caf, 0xc1b7b1e8, 0x13085d66, 0x98a00ce5, 0x9e6ec82d, 0xe1e92020, + 0xd11e851e, 0xb84919b5, 0x564987a8, 0x20c826c1, 0xd3401a6a, 0x1de2a02a, 0xa9313d38, 0x01ea70fc, 0xb09961e1, + 0xe81173b1, 0xb8454bd1, 0x5b4e7a36, 0x83bfb791, 0x1257bb64, 0xe826c48e, 0x86425692, 0x0c81b147, 0x40e993d1, + 0x5afcc631, 0xd37fb19b, 0x0fe36356, 0x43cf1ad5, 0x4f38ef07, 0x7d60f7e2, 0x1562b927, 0x3ce202a3, 0x56ed1f3f, + 0xd92a0ef1, 0x6dbec1dd, 0x1e3ade8d, 0x20133276, 0xac369576, 0x7be90aa3, 0xf2831d9b, 0x22266117, 0x1ce020a4, + 0xb4d1a374, 0x1f64831f, 0x0c541084, 0x9e5b6fae, 0x1d884f6a, 0x9af8315f, 0xf40a3a83, 0x196adb97, 0x34e35e14, + 0xf123d80f, 0x33ecae0f, 0x29a5b4fc, 0x5a121dd3, 0x3994687f, 0x3537d8a5, 0x8a2cc6d7, 0xb813f654, 0xf48525fe, + 0xc07879b4, 0xa68b912f, 0xd947bfdd, 0x6842c763, 0xa0752266, 0x460c22b8, 0xcdd58d96, 0x65c06a71, 0x4197373e, + 0xb973efd2, 0x86f550f2, 0x2ac4275b, 0x8c015f85, 0xa54f6cf3, 0x36420245, 0xd81a1894, 0x85958db5, 0x4c6267de, + 0x62690ad7, 0x259b5c81, 0x6497807e, 0x39a47e13, 0xeef86c2b, 0xe7f982c6, 0x62de2a4d, 0xafed416a, 0x49723495, + 0x82bcc84a, 0x7a7d2871, 0x68f45fda, 0x7d9bd1e7, 0x9c829787, 0x79179177, 0x9c81ad58, 0x6721fd1e, 0x3fb1c669, + 0x7fdb1367, 0x529ddd96, 0x1993fcce, 0xe1543946, 0x3cb45b24, 0x1d6f2a05, 0xa0dfa941, 0xd2aeb106, 0xb365711f, + 0x05682bb9, 0xc4bc798b, 0xeaf6f010, 0x5aa8d744, 0xd554a0d4, 0xbad8f88e, 0x9f248bcc, 0x9c9c10d2, 0x0528ebfb, + 0x9c8f76fc, 0x5c1e4f16, 0xee7bd233, 0x8ee3c32d, 0x403ac0c6, 0x80e4a223, 0xf95daddd, 0xd040c22e, 0xfcd98dc3, + 0x085af17d, 0xf65a2d07, 0x620c744c, 0x7b9b93a4, 0xbc9a0ab3, 0x69b3c5c0, 0xea60d868, 0x12901422, 0x09802805, + 0xf6eeb05a, 0xa3abdf08, 0x56ff6ed8, 0x21441335, 0xb658f154, 0x0a1422e3, 0xdd56ba24, 0x416c40c7, 0x6f4b8448, + 0xeaa36bdc, 0x61adda74, 0xc66c1341, 0xc154eedd, 0xf4a00a7c, 0xd1268d8d, 0xfd69d324, 0x4f9638d7, 0x60f139b3, + 0xe93240bd, 0xbcaa72ef, 0x7a9a1aee, 0x39c1da76, 0xb48e7edc, 0x98c2c4ea, 0x778f63aa, 0x3e23d200, 0x9307b847, + 0x92091d1a, 0xb6e02f15, 0x4dff8fba, 0x824084a9, 0xf9e6c7b5, 0xc2068b54, 0xd1a7d228, 0x39a33f40, 0x10a5d4da, + 0x9cfd4c0c, 0x66b4c78a, 0x1c51ea04, 0x4584b32a, 0xb0c9c94c, 0x8bb470bb, 0xffdb1e71, 0x4afe6bc3, 0x9d99b618, + 0x6669a33d, 0x81646e78, 0x9daf32ae, 0xa961e155, 0x65d5314c, 0xbd0cdce1, 0xb72d5fda, 0x2ea8d5e6, 0xfdcafdfa, + 0x04cc8fa5, 0x31d889a2, 0x73e69b0f, 0x5fee7ff4, 0x9cc8fa38, 0xfc17f039, 0x49a28f6f, 0x2c452622, 0x650b8e25, + 0xa0a4958c, 0xf2cb8ab5, 0x5a4b6ca7, 0x53185975, 0x08a851e6, 0xee7254dc, 0xc61bc3c6, 0x90ff805a, 0xf9f69a3e, + 0x8aea48ac, 0xe10fc9d7, 0x8207621f, 0x8b50653a, 0x4da28d21, 0x73eda667, 0x7e8d8dc7, 0xc03220ee, 0xcf524db7, + 0x8e6d8809, 0x21ea4c05, 0xaa5c6cfa, 0x80dac7d5, 0x38db0b93, 0xcaa4f503, 0x03c08630, 0x3efedff6, 0x303a7a5c, + 0xc66f207f, 0xbafe5176, 0xf7ad7fad, 0x717b8a15, 0x4ea92284, 0xa78408e2, 0x39b8589c, 0x3fcc8f10, 0x558839fa, + 0x063cc157, 0xa485feb1, 0xdbbafd9c, 0xb0b9ef27, 0x1ed8af3b, 0xf04dc298, 0x52f05a24, 0x8d9f226f, 0x63135775, + 0x3d0db671, 0x3a659aa8, 0x7a487539, 0xb9a1fc72, 0x0c95fe7d, 0xb876819c, 0x971ee957, 0xc9a923a5, 0xaeae6e7d, + 0x3279c3cf, 0x2ee89d3f, 0xece3247f, 0x42ad5f26, 0xd223656e, 0x7337834c, 0xa18cc2d6, 0x12c8fc30, 0x7c1fcbe7, + 0x88e18d46, 0xcebad034, 0xdaf2a063, 0xb134df80, 0xf063b29b, 0x4bc94adf, 0x6ae05d0f, 0x18d38b1a, 0x1e99a08b, + 0xc252a510, 0xe9806e5d, 0x1ef1506c, 0x2d675e64, 0x1e6cd316, 0x839ebb95, 0xe356012c, 0x395325fa, 0x28efdd15, + 0x6b7e7cb6, 0xb79c553e, 0xfeb0a09b, 0x8eda228b, 0x24b8a1ce, 0x0f780d23, 0x631eb4c5, 0x75621065, 0x896e1729, + 0x0194b5cd, 0x35dce93a, 0x2bd1a66c, 0x69f19233, 0x5df9cf84, 0x99a98dc7, 0x3b5ea64e, 0x7a9933d4, 0x717553ac, + 0xde47b18b, 0x35eca8be, 0x07e13838, 0xfc8bb3d5, 0x1faf882e, 0x914e9c4c, 0xebed3e94, 0x22af6091, 0x1e8e001c, + 0xbbae49dc, 0x067ba0d0, 0xd1b38b0c, 0x236dbe03, 0x0e0bda7d, 0x0b3f87c1, 0xec391624, 0xa57542f8, 0x1de73008, + 0xf05f0a75, 0xdb45d0ad, 0x6a5f1e80, 0xc46ed981, 0x3d20d4d4, 0xc0a7ca8b, 0x0b2e3533, 0xdb1e416d, 0x135d64ca, + 0x2665147a, 0x44629257, 0x8ce0a2b3, 0x3d7534c9, 0x4bf63b9b, 0x235425e7, 0x5cc9647d, 0xf014f3fd, 0x0d9a86b5, + 0xaa4be54b, 0x164861d8, 0x6aac49f4, 0x074d65db, 0xea9edd2b, 0xb7a45136, 0x123339be, 0x4a493301, 0xf5009151, + 0xaa247fb3, 0x25a4410c, 0x82299995, 0x2ac26639, 0x1808fe5a, 0x30ea41d6, 0x2c2809f1, 0xbf21fc2a, 0x240f00f3, + 0xee25373a, 0xa4784acf, 0x9332d44c, 0xd2f668b2, 0x1c614835, 0xa3d01ebe, 0x0163d94c, 0x1de24dc5, 0xaec6cecb, + 0xa8d98555, 0x5c2f6b01, 0x06512fa2, 0xe7bf1284, 0x6419aff6, 0x165f7e35, 0x880a716b, 0x77bcd995, 0x25633db2, + 0xfc26b01c, 0xa2f6d506, 0x42f7fed4, 0x29d732e7, 0xd51ec24d, 0x179adf52, 0x0f213b62, 0xfd55e33e, 0xc9e1190e, + 0xce17fe29, 0xfb9656ab, 0xdbf3bf82, 0xe604b28d, 0xea73a4ed, 0xafae8312, 0xe669f635, 0x0ca715d0, 0xfd60ae3a, + 0x2408ed93, 0xec700c18, 0xcefb3982, 0xcdbd39ea, 0x736fc6b8, 0x582c9762, 0x85fc30f3, 0x831769c7, 0xdce4eea3, + 0x2131c8e2, 0x4c426276, 0x251a1272, 0x656c2210, 0x2e44fc42, 0xc277568c, 0xf9e7bf02, 0xacc0dc61, 0xb3cc3cd0, + 0x74536f5e, 0xda2a03cc, 0x44b3e6c4, 0x66f09a18, 0x1061479f, 0xe6154d56, 0x08f59c3b, 0x2a7c65c4, 0x98b1cb01, + 0x5db8abfc, 0xc92fa87d, 0xc8d9daa6, 0x73e94772, 0x96b33fa5, 0x611e43f3, 0x39d40789, 0xca1b0cd3, 0xba12f43b, + 0x937d333f, 0xf76770d1, 0xc4d169ae, 0xc4f7f0c9, 0x8d59d4a8, 0xe52a41a3, 0x664ba4f9, 0x8c1532ef, 0xfaa23e05, + 0x9e8d31e7, 0x1045cab4, 0xbab3e855, 0x5c3427f3, 0xc37555f1, 0xd2234df8, 0xc5aedd76, 0x18a76da4, 0x42c25211, + 0x97976dc0, 0x0d4edcaa, 0x2f98f8ad, 0x452455a3, 0x6d109774, 0x4507437f, 0xfc968773, 0xe28f2b3c, 0xc1d4ccc6, + 0x60dda215, 0xd76eeacc, 0x0a7d2d8d, 0xb1edbc4a, 0x13807a0e, 0x0bbf8a3e, 0x653e4498, 0x70f074a6, 0xf9078ec4, + 0x36283406, 0x287b1500, 0xdc55c9a9, 0x4ba78a38, 0xbb93626f, 0xec042d1f, 0x23b31e8f, 0xb0347544, 0x249fa084, + 0xa5727a7b, 0x45216da5, 0x1635be75, 0x1567a6cb, 0x1faa6e8b, 0xb842e99d, 0x67a9f065, 0xa788eb02, 0x0f700d57, + 0xb0a77868, 0x0f88ba0c, 0x67239819, 0xabcc24dd, 0xe6fe77cb, 0xcf4890c0, 0x6131fc4c, 0x7fe67711, 0x56bd75ba, + 0x10c34779, 0x455f2cb8, 0x25794eac, 0x43ee7f5f, 0x28a61686, 0xaa02a7d5, 0x364cb9dd, 0xdc4f55b8, 0xc06295d8, + 0x9d9fa577, 0xfd61535a, 0x4f1fedbb, 0x77a8b408, 0xd144d3ef, 0x08ed2c8d, 0xad8cfa64, 0x7bb00464, 0x9e38d852, + 0xf6f86c29, 0x3ccc9f30, 0x11735602, 0x132eb7be, 0x3f940eb9, 0xfb1d4d0c, 0x21a2419e, 0x3b16eb8a, 0x588cc8ab, + 0xdf7149ac, 0x87b55f98, 0xd7095a34, 0xd5e8e4b7, 0xf0777daf, 0xda510d32, 0x9bb8feab, 0x4db8fdf2, 0x6728bb85, + 0x033140d9, 0x30ed0d8c, 0x2f756a3b, 0xc7cf6726, 0x0813b63d, 0x35d99284, 0x0915e37e, 0x7ff73339, 0x14ef3a8e, + 0x00abf031, 0x828398a7, 0x7b8a0342, 0x9a48c5cb, 0x01710c0b, 0x72c46051, 0x012bdfa1, 0x7efeb4b6, 0x39f6ab76, + 0x14ea8d31, 0xa5955809, 0xbae02413, 0x81389cd6, 0x6b4eb438, 0x6c3f9dfb, 0x00aca5de, 0xb36b4933, 0x74f0cd0c, + 0xcc837f21, 0x16576f99, 0xdda30dbc, 0xf0f5a4ee, 0x97d7f628, 0xd40e293e, 0xa6a2160e, 0xb2a88d4d, 0xa40d8b34, + 0x31ebb222, 0xe54281a5, 0xe6f31e89, 0x4300bb89, 0x51784704, 0x3d98af7f, 0xce24b513, 0x08df12c8, 0xb6ac3598, + 0xd78377dd, 0x0d63cb64, 0xea367c96, 0x42bfbe17, 0x4d4005af, 0x50fa45f6, 0x02a8bab6, 0x825008c6, 0xefd80e07, + 0xfe41e994, 0x0ea54fb2, 0xc5a25e5d, 0x0942ae0c, 0x285a3241, 0x7f95d5bb, 0x742ccffb, 0x63048e98, 0x8e1e7500, + 0xddc90cb9, 0x8b0d3714, 0x91a80bdb, 0xe472c3ea, 0xbfc7351a, 0x60400f73, 0x0e99b3f3, 0xb8d61612, 0xae2b0f6b, + 0x5681257a, 0xf6a76e27, 0xb271d1ab, 0x561a058e, 0x8c3f4ec5, 0x29744817, 0x2818a4f3, 0x4bf03468, 0xb0bb2e9b, + 0xd5922adf, 0x7e230c7a, 0xf2ca5181, 0x9dfeb91a, 0xac815c60, 0x9fb65dba, 0x09d18e4a, 0xe22c0b8c, 0xed401571, + 0x3e73265a, 0x6b72d58f, 0x86c15444, 0xda8e0597, 0xe1f270c2, 0x93592b11, 0xaad32e86, 0xc3bd972f, 0x7925f073, + 0xc2c6d193, 0xa35df1e0, 0x71bea1ab, 0xd76c881d, 0x226654f6, 0xd78134e9, 0x396a58f5, 0x3a343ad4, 0x711c4a85, + 0x3e4e57ad, 0x2548f74c, 0x137c6c6a, 0x4e1587f2, 0xd55c336b, 0xee7fdb9c, 0x5296d8a9, 0x2f40ee71, 0x322d7854, + 0xc7646537, 0xe3144770, 0x6d6efa18, 0x97478365, 0x4ab84665, 0xfb1a371d, 0xa4d3bd1a, 0x4cf8cba1, 0xc81a0b1d, + 0xa5878ede, 0x8e6edb4d, 0xce4c000a, 0x3b0ce220, 0x6e1f6c77, 0xcfb19396, 0xeac10a3f, 0x8686fd71, 0xe675cafa, + 0x8b00efb0, 0xc3858b1f, 0x81d1edcb, 0x3d7b0344, 0x1443c088, 0x054203fb, 0xd150d173, 0x2ffdc5c0, 0x797294cb, + 0x2c579edb, 0x1cddbf6c, 0xaa637ab7, 0xe2484404, 0x5785910e, 0xd2218e6c, 0xeff38f43, 0x45266f21, 0xcad39284, + 0xb0cf336b, 0xc7a0959c, 0xcce064ee, 0x67ea5ec3, 0xb6ed7279, 0xa6de8ea6, 0x0703f453, 0x8967128a, 0x75352f53, + 0x58323d58, 0x9e9a53d3, 0xf8215ff1, 0xe6f254b3, 0x136181b9, 0x0413476b, 0xcfb00d3c, 0x162446b8, 0x835a41e8, + 0x1ec9fa31, 0x5d99e806, 0xcf0d398b, 0xcc35cb58, 0xb5acab85, 0x84fac660, 0xe4fb97eb, 0xbb73c608, 0xf1531330, + 0xaf5b8d92, 0x09666380, 0x43b78924, 0x3bcff2c0, 0x78da315e, 0xa546f8b8, 0xf3ffe706, 0x30f79967, 0x2b166d1c, + 0x4e2d0d09, 0x05082f95, 0x7756407c, 0x6560d0ce, 0x0b808b24, 0xb7e901bf, 0xf0d4bbb8, 0x5883dc38, 0x93f130bb, + 0x5f31654a, 0x4df5a999, 0xfa2bda4e, 0xbc2f2c04, 0x90881cf6, 0xd1239a11, 0xa94f87c6, 0xf31d2863, 0xaac55426, + 0x991b700e, 0x7341f0ca, 0x6182d714, 0xdec3cac0, 0x55a0b8d8, 0xc819bbbb, 0xf1b2df80, 0xd9d4284a, 0x8b17b48c, + 0x49dafa9c, 0xb360ba78, 0x058531ea, 0xa105d202, 0x1f098e1a, 0xc2ab273e, 0x87be301b, 0x3ed261ce, 0xbe76c833, + 0x6bbbdb2c, 0x162b9c17, 0x8bd1556d, 0x3b1262a2, 0xea6424f0, 0xbc87b170, 0xade0f6d8, 0x4546d228, 0xb446c7d0, + 0xa80c0143, 0x2bbbe870, 0x9cb9b970, 0xb29ddb04, 0x6507e18e, 0x9bfbdf1c, 0x168f0371, 0xa68834ac, 0x6783e9ef, + 0xabaeb028, 0xdb95ec42, 0xf010eeb1, 0x46b57cc9, 0x436617b2, 0xa00c7a58, 0xfb01c9fd, 0xf785753f, 0x66bf6484, + 0xdb21f593, 0x3301d39e, 0xff670397, 0x37bb89bd, 0x19a0e4ec, 0x00e2d27e, 0x0d68f837, 0x64ba8420, 0x0ec27ff3, + 0x649b689f, 0xdae2b3ff, 0xbc7eff82, 0xd3074073, 0xb1937d69, 0x0cd02d43, 0x9883515c, 0xa2073684, 0x937f3a0a, + 0xe4cdebcd, 0x6cf16f67, 0xb2e2af7a, 0xe7671fea, 0x6a0fc0fb, 0x1e4eb0df, 0xb7a5981e, 0xc1bacf85, 0x6b738cda, + 0x765b11a6, 0x41db44b7, 0xdb9e9227, 0x0b45e5d5, 0xb96b2254, 0x1d259e7f, 0x4e77f668, 0x7e84d163, 0xa4671301, + 0x1dd79b0f, 0xe96ad9e5, 0x2de92576, 0x07d1de3a, 0xee05e5d1, 0x7ff13883, 0xf62cc79d, 0x36f3799e, 0x1a0fa93d, + 0x215074cb, 0xf9d2ba01, 0xdf548164, 0xeaa5c697, 0xb95b0ee1, 0xee43a58b, 0xa1d3902c, 0x683107c9, 0xaf61f4f1, + 0x846a74cb, 0xb4900d2a, 0xceb41368, 0xc9581cee, 0xe6eebf99, 0x4315f1cf, 0x9587f34a, 0xdc15ae4a, 0x6e507d89, + 0x957df27e, 0x477e8647, 0x384c1404, 0x1b9167d3, 0xaef68c99, 0xac0d5d91, 0xff7cefea, 0xaf8a59f9, 0x70f25f4b, + 0x48c086b2, 0x977ac2b3, 0x75b7647b, 0xc2b340c7, 0xe753b116, 0x98b94311, 0x5ab7da75, 0x78d3f06b, 0x9cb7560e, + 0x157e2da8, 0xf5e33f0c, 0x1ceb86dd, 0x556e9b8b, 0xe840bb5d, 0x48468fae, 0xe5b44fc8, 0x9900a83b, 0xaf9e930c, + 0xe91bb92e, 0x4d6a9b6b, 0x17e3b219, 0x4a8a93c8, 0x3cf73e8f, 0x3136f4e5, 0x0f340666, 0x7c98ee6c, 0x701b1111, + 0x89262538, 0xb2c620ad, 0x2e7a39d5, 0xbf0035f2, 0xeab4d81b, 0xf4482422, 0xfc135df7, 0xd37288d4, 0x925cfd29, + 0xb1ea8ffc, 0xc9c93b27, 0xb42ecf3c, 0x4e55785f, 0x97fff06f, 0xbb157219, 0x8bb81da5, 0x8a7add8d, 0xb195f415, + 0xe9f699e7, 0x2afb55f5, 0x55d7889c, 0x9330b45d, 0x378b5a51, 0x2b72caad, 0xd979ddff, 0x078a5300, 0x1f17a617, + 0xc2c9ceca, 0xe1df738e, 0x86b57a59, 0x26bb743f, 0x7e00b40c, 0x9b6d26c3, 0x9e95247e, 0x7be2fa8f, 0x0e91439f, + 0x6727911d, 0x4772a718, 0x685bf667, 0xcfae3bcd, 0x4823e022, 0x2f61bf63, 0x4410e1cd, 0x258b6797, 0x60b84349, + 0xe1fc6442, 0x120a6866, 0x16f5942e, 0xd8d228da, 0xe304a6f3, 0x0e9126df, 0x11696922, 0x835a925e, 0x9bd56142, + 0x4cc51367, 0xaafce41c, 0xa07c6de7, 0xdbb97379, 0x0d0a444e, 0xb18db6a2, 0x952bd604, 0xac24807a, 0xf4edd7cc, + 0x11b475ec, 0x3b6a79e9, 0x299ed90e, 0x12bb3462, 0x65fb1941, 0xd26059ae, 0xf57278b1, 0x022db010, 0xecd3b0c4, + 0xa14120f6, 0x6382bcd1, 0x69f1eeaa, 0x32f5ff03, 0xa52d0bb2, 0x64ff137e, 0xda8dd5d5, 0xe8b9aa5c, 0xb717fe8e, + 0x38b6b827, 0xe68a59f0, 0x3bf8659d, 0xa1109078, 0xa4197db0, 0x332c61b0, 0xeacb5a1d, 0x114c6867, 0xab573eb4, + 0x78335728, 0x883aec79, 0x1a500ff7, 0x61210154, 0x10624e0a, 0x07f17746, 0xca225311, 0x785a2978, 0x6362a87d, + 0xf7c519aa, 0x72f89688, 0x541d5349, 0xd0a020e3, 0x8fe868ab, 0xeb4a1fca, 0x94b94767, 0x2d8168b6, 0xeeb49822, + 0x4a76e635, 0xbd337e26, 0x66885a14, 0x4596a297, 0x5a5c7f29, 0x7e16b092, 0xcec24fb6, 0xed656ca1, 0x6323005b, + 0xaaad1c64, 0x4111d486, 0xeb92425d, 0x6b8a302e, 0x16a44110, 0x7e68aee7, 0x932a09f8, 0x456b3906, 0x053e0119, + 0x09027fc1, 0x207bd3ab, 0x791d961f, 0xa09e08c5, 0x696a4dce, 0x4a4178dc, 0x54eb8618, 0xc38e810c, 0x52f379cf, + 0x9d76e076, 0xdc19b81d, 0x0e684b58, 0xa2309d59, 0x06050aaa, 0x6c3a6fb2, 0x925e87d3, 0xb2e55972, 0xdce48820, + 0x7b922979, 0x93c7abd0, 0x7b57f861, 0xf2c572af, 0x03aa91bc, 0x280318fe, 0x2eabbd37, 0x1fc487a1, 0xe29b8da3, + 0x21ce6e2c, 0x2b10ac47, 0xcc3ef30f, 0x2b8bac2e, 0x5a69231f, 0x53dd37f2, 0x01568498, 0x9faa937a, 0x92943b70, + 0xa73c2ed0, 0xde9ded4f, 0xb15d58bd, 0xbec48ddb, 0x48c2d998, 0xfaeb6f61, 0xaa807611, 0xfd40f5d7, 0x76a79fab, + 0x8aa27255, 0xa139a2a4, 0x19750256, 0x28c405ab, 0xaf11afb5, 0x7c8d29ac, 0xe75f94f9, 0xef56c1ce, 0x45c7f29b, + 0x77c1d155, 0xe7b3ac8a, 0x0b124a18, 0xf23e2bab, 0x3bf61c94, 0x4f379e9c, 0x0bb7468d, 0xaf66684a, 0xfa2dbfa9, + 0xd835b48f, 0x952ca322, 0xa2492893, 0x914f6cac, 0x0c2e4adc, 0xf2ce916d, 0x99fbd66c, 0xb072706b, 0x6277676b, + 0x1db56cf0, 0x49ec2cf7, 0x042abf81, 0x11c659ea, 0x98bbf896, 0x4aeb7b26, 0x22e158aa, 0x7beb15bf, 0xf59e0f40, + 0xdbb73d17, 0x3a74d426, 0x964edeb9, 0xdb2224bd, 0xe3d7ceec, 0x9d57db40, 0x90a5e879, 0x1b878da5, 0x901f168b, + 0x33005ddd, 0xaded3c89, 0x1dc3f8e8, 0x2888f9d7, 0x06d1d94c, 0x0519a3be, 0x7571e61d, 0xd6273e37, 0x2b3b38b6, + 0xa28a6508, 0x8fe40d6c, 0x17736921, 0x14f52579, 0x3d4ce012, 0x531c9208, 0x728276cf, 0x07fad4a1, 0x9c1cccb3, + 0x12e41b4a, 0x0ebde433, 0xd28c32f7, 0x808274a1, 0xd2df70aa, 0xc994df48, 0xc7cce316, 0xd42fb2ac, 0x9f2180bc, + 0x03fe487a, 0xf6cbd3d9, 0xd9668e5b, 0xfa605264, 0x4a5e3149, 0xadadbea1, 0x80a1f968, 0xa574dd27, 0x0fddb5ac, + 0x87222106, 0x223cd79d, 0xb686b28b, 0x75d2b455, 0x0a5dd874, 0x3b12aac2, 0xedd7ce99, 0xd952bf18, 0x9f7c1e48, + 0x058bcf90, 0x294982da, 0xedcdfb83, 0xa7c42279, 0x4a30ee97, 0x11c7f5ba, 0x5864785a, 0x463f13fa, 0xc8b858ed, + 0x019b2ac7, 0x7e4c739d, 0x3fc0fe7b, 0x1156ea36, 0x4d46566b, 0x123978e1, 0x69684db9, 0x202c9837, 0x6fa8f4b0, + 0xeba63528, 0x95039169, 0x10c0859d, 0x399469db, 0xd2190843, 0x62552cb6, 0x5f62dd52, 0xd78f7d0f, 0xdc36c372, + 0x6796e6a5, 0x53b9907c, 0xdcad55e9, 0x521f0cf0, 0x9b03a5c5, 0x9a6417d6, 0xe96abb84, 0x7f73eb06, 0x3a1b9e57, + 0x9a4d00ff, 0xfa87d94f, 0x73468e5d, 0x9c051583, 0x37b1648c, 0x6c54204f, 0xd89bb79c, 0xf42a5d56, 0xbb3a8c71, + 0xbc1300f1, 0x482c6989, 0x38d90304, 0x8122df67, 0x955bc7e4, 0xd6471ebd, 0xa1aa6573, 0x7eb25dcf, 0x0e1c8ce9, + 0xdebb3cec, 0x6fa3f936, 0x044710a6, 0x27f6de79, 0x88bb9c09, 0x2b4f9b4d, 0x66558f1b, 0x2cbc57d5, 0x99ff746d, + 0x50a3fc37, 0x15f54d1d, 0xfda06557, 0xce0c82cb, 0x271c20af, 0x3d7a16e5, 0x99da5b24, 0xdf0524cf, 0x4b8b41f3, + 0x73795e72, 0x0206815c, 0x5dc18b27, 0x1962a521, 0x4422bee8, 0x97eecda1, 0x71426a28, 0xe31cbe54, 0x811b0e25, + 0x4187b567, 0xfcc727f7, 0x6339bd5a, 0x47b7ab32, 0x2df8dce2, 0x65b52e21, 0x4434e1ef, 0x074b5669, 0x9f35624c, + 0xabbf91ca, 0x0a6b12e8, 0xc51e1a7c, 0xcfc31165, 0x6d458bb6, 0x29921379, 0x0a2f9e1d, 0x15816ab7, 0xb78ed1f0, + 0x13149f17, 0xdf9b217a, 0x4336f6f8, 0x8eb6f77d, 0x94565743, 0x71058286, 0x2ae73e05, 0x6b6a5f72, 0xa9472379, + 0x6801fdf5, 0xa325c361, 0xe32e811b, 0xb854e573, 0xbc46e22e, 0xd2875ef2, 0x4f8186f7, 0x273c6951, 0x1af82d29, + 0x96644e9d, 0xa677fa29, 0x794fd99e, 0x5e74d4aa, 0xc6db7bc1, 0xb7061794, 0x8366e943, 0x70fac85a, 0x830389fe, + 0x3227d31b, 0x5f736304, 0x5414875a, 0x41c84122, 0x05eb932a, 0xfaa762a4, 0x91ca9f35, 0x177c96c5, 0xe7823e28, + 0xe4261789, 0x31938767, 0x6dfe95b0, 0x63d290a6, 0xe9c6b810, 0x3a24e175, 0xb2887af4, 0xe5cf36ef, 0x0112c867, + 0x68b6d1fd, 0xb5fb9f18, 0x66a4c0c2, 0xab94a922, 0xb7cdb3cc, 0x87cac473, 0xbde5e675, 0x0d4eae78, 0xc105301e, + 0xbc801a9f, 0x113d555f, 0x0d5c445f, 0xd550b6b8, 0x98d5ea92, 0x41a19a7f, 0xeb61f0c3, 0xb609e5b0, 0x31b26cc8, + 0xd308df4f, 0x6e061188, 0x0e09e3ce, 0x3024ae7d, 0xe05edcf3, 0xf54dd2e4, 0x824f2654, 0xb34845f7, 0x043af501, + 0x8eb05f6e, 0xd27ec35a, 0x3a57cc60, 0xdcf7f228, 0xa5e96382, 0xcf1f3925, 0xfa39e48e, 0x5d8f746e, 0x25fd4dd0, + 0x02af257c, 0xd95d20c5, 0x5cc0a2f7, 0xe91c84dd, 0xca9bab73, 0x8a68a963, 0x7d9fe6b9, 0x83aabd5d, 0x72235519, + 0x018c1059, 0x95d492c7, 0x25ef5172, 0x901fd772, 0xf66a8b88, 0xf181e020, 0xdc83cde8, 0xbb6a394f, 0x83bd34ae, + 0x1e9b84ef, 0x7278470b, 0xfea6bfd0, 0xacbcb9fd, 0x6b22fad9, 0x8f00807d, 0xc6bd98b8, 0x1fafe4ec, 0x94582e91, + 0x8b4594cc, 0xdee1657e, 0x55520415, 0xa2c536f0, 0xf137a180, 0x1c405298, 0xe001102e, 0xf35ab05b, 0xf181dbd6, + 0xcb3ab628, 0x3de38904, 0x3851eb3e, 0xecd19471, 0x294249aa, 0xb081e878, 0x6c182d96, 0xcff23526, 0xfb267ae8, + 0x2164ce31, 0xdf720bf2, 0x2ccfd714, 0xa6c495d5, 0x50ee2e55, 0x795f2bac, 0x237c5c38, 0x47b2df83, 0x7481eb64, + 0xa23de385, 0xd8b1adcd, 0x7a6902b9, 0x3a49927b, 0xa21fecdc, 0x057dd68e, 0x8bdc9cc0, 0xd75eb752, 0x0b922cef, + 0xaec79525, 0x4b195027, 0xa6fd496f, 0x2f132e85, 0x95468326, 0xfb56d30c, 0x4ef93e52, 0x20aa50a4, 0x1f295f08, + 0xe3cf307e, 0x766adcc6, 0x8e7db34b, 0xf863ed43, 0x77affeb9, 0x46e67bd8, 0x1254173c, 0xe4328667, 0x5d751dfd, + 0x6393ef87, 0x03ddedf2, 0x49a15360, 0x3abceeee, 0xa5315038, 0x952ca5fc, 0x5d2860d3, 0x26ddcaa0, 0xff059c8f, + 0x865bd647, 0x133e6d5a, 0x499510c8, 0xe0f5dd5d, 0x484fbcee, 0xa67e9582, 0xd586bf7d, 0x0b0fe6cb, 0xa1ca04bc, + 0x9f957cb0, 0xe7968b3a, 0x39952d4e, 0xbe4caecc, 0x51e475c1, 0xc1662da3, 0xe5d654f1, 0x3a0b0f05, 0x824ebc22, + 0xf9dc73d8, 0x94c1ed8d, 0xd219dea3, 0xda2c9e8f, 0x21153116, 0x8bda30a5, 0x6fee8fef, 0xd1627252, 0xd038def2, + 0x8a9fc4a8, 0x1f2ea589, 0xb4ce535d, 0x4ead9651, 0x6fd04c03, 0xa7b2f323, 0xf9ddd45d, 0x9b3321a5, 0x4d3f7d47, + 0xefb96250, 0x77ece24a, 0x2870faf5, 0x9a6fbaea, 0xe885b8aa, 0xeb3e6252, 0x64eea79c, 0x451489d9, 0x1675ea05, + 0x7ae6eff8, 0xb31565a6, 0x8ebf803d, 0xe0bd7173, 0x61630a84, 0x3a1dacc7, 0x80a211cb, 0x421f94cf, 0x602092d9, + 0xee9fbf34, 0x82a57882, 0x67aeae5a, 0x58e5a4d3, 0x653ce8c9, 0x86b5780b, 0xe989eba4, 0x994ce575, 0x424019e6, + 0xcd3d735c, 0x70f7e4bf, 0x1ef9ea88, 0x00a40d8a, 0x3c7aa7c7, 0xf0c590db, 0x6be78f4a, 0x9a352fdc, 0x2138fbf1, + 0x8b398928, 0x6971e72c, 0x903da97b, 0x7c81e591, 0xde9f06a6, 0x5f165720, 0xd428220a, 0xc0e3ad09, 0x3d030a92, + 0xfe066d56, 0x1e3928d8, 0x6cf10a17, 0x23ede363, 0xc6f99dc9, 0x62c57822, 0xb6957980, 0xee419248, 0xf1f16291, + 0xff9a3cc5, 0xf1d9ac40, 0x0de55179, 0x55060a87, 0x93a2b23e, 0xc64898e0, 0x71a7d23b, 0x29ff7b7a, 0x5a27a31b, + 0x34bf466a, 0x82aa1092, 0xa0d170dd, 0x4c9eabd9, 0x4d7771c1, 0xd7423246, 0xd8ef4395, 0xa5088011, 0x243f7621, + 0x5441a72e, 0x7b87a009, 0xca049229, 0xbbb69919, 0xf29dd17b, 0x20441a9e, 0xd3d513d6, 0x8c6b0d65, 0xc7215826, + 0x7463af77, 0x6780745b, 0x0e6dfbda, 0xbc650c38, 0xf57278f4, 0x60c13381, 0x995af8d2, 0x3f179555, 0xaca3fe27, + 0x3adeda70, 0xe7a128f3, 0x6bcebfd0, 0xb56e461e, 0xecf0ab19, 0x675a54eb, 0xaed8bd31, 0x886b48a8, 0xf8aeefc0, + 0x28b14fd4, 0x392ea6ce, 0x74a016de, 0x05381a1b, 0x9758da37, 0xf37301f5, 0xc945e1ca, 0x75bdab0e, 0x1b78ad9c, + 0x95dbcedf, 0x9b57cef3, 0xb8a10970, 0x315d65b1, 0x37575ea8, 0xc61b06cc, 0x2a8fcc36, 0xb462594c, 0xe7353b8c, + 0x9c84a188, 0x5c2362f6, 0xf16a74ae, 0x9ff41106, 0xb591b7bf, 0x5afb6b56, 0x36e12eba, 0xb3125b69, 0x86f6219b, + 0xf78c7fbd, 0xe413b78b, 0x02ea8a04, 0xd63805a8, 0x4b8ff139, 0x5d22668c, 0x80b05654, 0x49c6cbf3, 0xf1c3faa9, + 0x55c1c28f, 0x57ec8a51, 0x963f8a49, 0x36cba624, 0x0cd741be, 0x35f2f7d3, 0x3f1e2b90, 0x85909e74, 0x98835873, + 0xd10f0e68, 0x83fcbf51, 0x19196867, 0x70212f34, 0xa88128b6, 0xf1cb79ca, 0x5061b3ab, 0x95d3e28f, 0xded81177, + 0xb4a840d8, 0x22f399f4, 0x7b46b7e9, 0xdb571829, 0xb5e8fce4, 0x502eacd7, 0xc17efed5, 0xbdabd435, 0x3774a4c5, + 0x0e2ee9f1, 0xb14986e0, 0xe90e978b, 0x40ca6814, 0x52ea4769, 0x142349ec, 0xf71d005b, 0xea3c51bf, 0x64ab3207, + 0xc376c879, 0xe7673aa0, 0x29455ff0, 0x80efe789, 0xe8b0d5c0, 0xdcc5716c, 0x077f5f22, 0xac68554d, 0x736d9e15, + 0x7a46da41, 0x5e1c6f3d, 0x65b723ec, 0xba7037e5, 0x54070aaa, 0x345084eb, 0xbe11a53d, 0x1231bb3d, 0x50f89bb9, + 0xe1712ad6, 0xee48a7f4, 0xc5c9132b, 0xc7fbf443, 0x6e7c9e7b, 0x80d620ae, 0x6684fb81, 0xb441391f, 0x4d85b6dc, + 0xf86f2b1b, 0x1b90c219, 0x7fd0540f, 0x3528e9fb, 0x092651e5, 0x127f97e9, 0xab512fdc, 0xd5f45068, 0xfd092cd9, + 0x23064a9c, 0x8e1e372e, 0x578588eb, 0xee5e5325, 0x1d0f1da1, 0x8aced646, 0xb5ffd207, 0xcbe82849, 0xe5812ccd, + 0x9162f5cc, 0x02da9605, 0x68e86b3c, 0x913b8b76, 0x3de09e85, 0xba32a8be, 0x2ef3a98f, 0xda10ba0e, 0xb013116f, + 0x7e1d9e24, 0x6b6e5910, 0xab8594b2, 0xac113f11, 0x52be8695, 0x82b723b8, 0x340341a6, 0xb2589053, 0x6330549c, + 0xd72c7165, 0xdc03e6cf, 0x3e99d9db, 0x460cc385, 0x4534a310, 0x9306c14d, 0x796525c5, 0xdb52e7d1, 0x706789d3, + 0x2669df91, 0x9d93cf81, 0x66aae478, 0xa5313a5a, 0x4eaa25ea, 0xdc29ce74, 0xd7922e3d, 0x34b4b9f3, 0x19fff2ee, + 0x918b01b9, 0x754e0177, 0x553a7660, 0xd0fd1e9f, 0x0b402ab2, 0xb355c4da, 0x35ff3b67, 0xf47f76b9, 0xba50a1f4, + 0x85eebcf5, 0xfd415ea7, 0x082d6add, 0x3da7ecc8, 0x101b0112, 0x3aff7682, 0xcb95453e, 0x7a273f44, 0xcbd306e9, + 0x561d804b, 0xedcba475, 0xf040dea8, 0x32cceae8, 0xfd6d8655, 0x37466632, 0xe35ffb27, 0x9705281c, 0xe16ca6cc, + 0xfb2e4111, 0xce84394f, 0xc38dbab1, 0x522ee34a, 0x1273941d, 0x0d5b75e2, 0x0635555e, 0x0e65cdd1, 0x53558b7e, + 0x938a75b1, 0xfe8975a4, 0xb37ba4a8, 0x9a0560c7, 0xc83e1106, 0x1f796554, 0xd75f87f8, 0x16b36fc9, 0xbdcd697a, + 0x923537a6, 0xf938caa1, 0x88776d45, 0x309927c4, 0xd261f219, 0xa9ce3c6b, 0x74af5ec6, 0x1d6a9462, 0x6371c300, + 0x4847f846, 0xcafc1114, 0x9b39e363, 0x1d6defd0, 0x288e645f, 0xd03f61dc, 0x09b9ad82, 0xb157ac50, 0x262ba2ac, + 0xdd40433d, 0xf239dad1, 0x12bb4366, 0x669acd1a, 0x05809edb, 0xebeb0c37, 0xd7b6e236, 0x4a7c61c2, 0xa0050011, + 0x9358fed8, 0x6375dcbe, 0xc02bfbab, 0x9932e546, 0x7dae0561, 0xbc12735d, 0xa30e6524, 0x24bb8114, 0x4b79ecf5, + 0xac72deac, 0x6763814e, 0x7f99e290, 0x81537e4b, 0x56298f13, 0x35698dd1, 0x1a5bc471, 0xe72df69f, 0xad5548d8, + 0x0bb57b09, 0xfb629792, 0xec7d302e, 0x2498a352, 0xdba99913, 0x262252dc, 0x6f56c07b, 0x1327b5c1, 0xbadc3302, + 0x861cafae, 0x99591ab6, 0xf39d9b26, 0x3d6a2ed2, 0xd3d1f909, 0xa90c536f, 0x70720628, 0xb430c5e1, 0xce495da3, + 0xf0b92762, 0xccbe8870, 0x2c3abf8a, 0xbdbf3746, 0x2c050f16, 0x41004e9e, 0x23382a89, 0x23760739, 0xe042576f, + 0xc508ffe1, 0xee852a53, 0x6cce0bed, 0xa5934d30, 0xba42de1c, 0xd21fc481, 0xd4cb927a, 0x8fb8b394, 0x676a4945, + 0x8a3543fe, 0x0aed0153, 0xf5fbd84e, 0xd1f67e60, 0xdc238055, 0x472812d1, 0x444ff6b8, 0xefb61cfa, 0xe1be4844, + 0xaf18aa71, 0xb2c26a37, 0xd5cfd291, 0x74689676, 0x54290d41, 0xd5561154, 0xf5ba6962, 0xf65e4616, 0x12776afa, + 0x7542b9ee, 0xfc554986, 0x51395625, 0x0c555464, 0x43c9165d, 0xe94b6131, 0xa749d07a, 0xbfd84884, 0xe7f579d7, + 0xc3367c9b, 0xdafd7536, 0xf5e9dfcc, 0x77b97bd5, 0x0077101b, 0xd87a7ce3, 0xfc67154e, 0x483e6e34, 0x4051dcfc, + 0xd4407647, 0xe7534b3f, 0x4faf1a03, 0xcb75e9bc, 0xbeff557f, 0xed9a32f7, 0x29992345, 0xc98d331c, 0xcbf58773, + 0x3335c4d5, 0x55137891, 0xdfeadee2, 0x2c7de269, 0x4e911e33, 0xce997926, 0x370b787d, 0x039147dc, 0x0cae201c, + 0x03267ab1, 0x770c487b, 0x27d133e6, 0xef2f77ce, 0x0cb1a642, 0x518536f1, 0x8415b3fb, 0x6ad09092, 0xdd16738c, + 0xbe7523a0, 0xf71a5e3a, 0xd9bedc47, 0x5271b806, 0xcc8ec891, 0x867e10c9, 0x23888c2d, 0xd9097933, 0x91116600, + 0x3205fb3c, 0x55c69931, 0x2fd3f1e9, 0xadd69040, 0xe3a6ae0c, 0xa158922a, 0xc30f524b, 0xf87ded42, 0x44b55f12, + 0x19a5f5ea, 0x8aa4fdbe, 0x71d2068c, 0x82fae0a2, 0x6bb6d2a9, 0x5fd9e3b7, 0x172cc8ce, 0x4740e82f, 0xdbeae64d, + 0x53bda37d, 0x1f44c46e, 0x39600d17, 0x92fd95d8, 0xce8593f5, 0xf63bd18a, 0x0ea6a8ed, 0xe655e3ad, 0x7444f848, + 0xcffcaf92, 0x83642b11, 0x7452bbe7, 0x77e9eb40, 0x3f2eb48e, 0xb4a3a5ff, 0x5af62ab0, 0xddc46d91, 0x52efc735, + 0x06dabf96, 0x86f05502, 0x9e654b2c, 0x6e9cf146, 0x069d9c42, 0xb27118c8, 0xa9f48d7c, 0x532c25f1, 0x7d642f08, + 0xc16a6aae, 0x87098783, 0x731ac1f6, 0x9ccec3b9, 0x1bb25c2c, 0x6a4ff616, 0x777df1d6, 0xbd829dc6, 0x2bd74adb, + 0x65d0ae81, 0x9d772374, 0x1daa7d2d, 0xaa714149, 0xd411aae5, 0x605d4056, 0x1dc0700f, 0x85dbf703, 0x25dd7481, + 0xaf765432, 0xb176af41, 0x428da3d1, 0x85fdf30e, 0xc3fbaaf1, 0xe1af8cea, 0xaf82f54a, 0x72c18d0e, 0x5b0c7a2d, + 0x55187d60, 0x72ba5206, 0xa246ce79, 0xb78102d8, 0x7706300a, 0xd7344bc3, 0x191371b6, 0xe2d94a84, 0xd8356b64, + 0x61d6daf3, 0x458bb505, 0x2b90d7ad, 0x804ee2b2, 0xafdcfb5b, 0x3ef426a0, 0xe8f1386d, 0xe529bc65, 0x8f751eea, + 0xd828d8f7, 0xd55d2560, 0x007a2d68, 0x5dc1cea2, 0x0c620fed, 0x17502f29, 0xb95eddb6, 0x630b3401, 0x0fad2715, + 0x50dfff2f, 0x2b0227a0, 0x9520af00, 0x5899fd65, 0x97c97a9b, 0x43084346, 0xd16f6124, 0x77972c5b, 0x3815e4ae, + 0x8739cae0, 0xe3de4994, 0x96e60107, 0xd0092a5a, 0xa022dd6b, 0x60909fcd, 0x849dab87, 0x0aab0e7e, 0x34f1c072, + 0xc963dd09, 0x50a05a85, 0x0a0d9353, 0xd18db7bc, 0xf331c355, 0x0f8e0803, 0xe5aae026, 0xf7a17553, 0x61adb246, + 0x3ef9e15b, 0x1b290468, 0x6d2b3d05, 0xe0bc6509, 0x89c81620, 0xcd7a862c, 0x2a4d9894, 0x46af8118, 0x9a1ce1db, + 0xff57e0df, 0x26eadfad, 0x48f8be83, 0x4334d3f3, 0x92b02e3d, 0xfa385651, 0x40be33e6, 0x6b578763, 0x5cf7fd46, + 0x171dc1a7, 0x5383fac0, 0xbd093f07, 0x7c99bbc5, 0x28b30244, 0xc3c2f8fd, 0x48c7c60a, 0xde005d31, 0x441c5139, + 0xc7b32b22, 0x47e9d2cd, 0x63fba655, 0xe04cb243, 0xf4ef9b46, 0x29d4e388, 0x9b806596, 0xc499f8f3, 0x8c3ff372, + 0x6189a5d0, 0x1950fae5, 0x8cf99e51, 0x9bc20a4d, 0x810f27d9, 0x878f213e, 0xf7bf3d1f, 0x199c9bd0, 0xaf1f091a, + 0xa55a03a0, 0x8bb0b9aa, 0xb1e2881d, 0xc89fa5f7, 0xfa33b51b, 0x52cc8820, 0x16f00f54, 0xbf7f9e7b, 0xa624128a, + 0xdc504d7f, 0xda8e61b6, 0xfa8f97bb, 0x5757b68d, 0x15f9eaea, 0xf8e2debb, 0xe6791847, 0x0492ea0a, 0x518864dd, + 0xf903a727, 0x1243ca5a, 0xa68dec21, 0xcf0d7ca4, 0x08e72b01, 0xf3c3ceda, 0x9087d36c, 0x7ec73c57, 0x71f818c1, + 0xd3981cc0, 0xfbcf4429, 0x97b7797a, 0xdefb4c50, 0x17dcb547, 0x98a9f7be, 0x2d1c0ce2, 0x0083cff2, 0x3f3f8436, + 0xc9c38c0e, 0x245970a1, 0x8c4eed2b, 0xeff7eb3c, 0xfe1d30ec, 0xfbe2939e, 0x4ed93067, 0xcfec08ee, 0x1cdc410d, + 0x62e6daf3, 0x9089e20a, 0x359272e3, 0x25d91952, 0xfef053fe, 0xbd9ebaba, 0x8f0040c9, 0xa353bbb4, 0x8f10a901, + 0x11af99db, 0x75745658, 0xba09f5c6, 0xfaa5a32d, 0x6ef0d419, 0x36bdb4ae, 0x7b5aedd8, 0xa4e97fe5, 0x81d7993e, + 0xce31ab93, 0x201f2a8e, 0x1822d872, 0xb14c1e58, 0xed15ca02, 0xb86b1845, 0x8f6108f5, 0xd549c9b6, 0xe535a1a5, + 0x997d87a2, 0x765193f8, 0x4bda4f66, 0x76f21b8c, 0xd6045e59, 0x3ee71005, 0xfdb24ece, 0x8c9efbe0, 0x22c97c65, + 0x7b130440, 0x4f43092b, 0xe98628b1, 0x80ce4d84, 0xb39ff877, 0x32acb14a, 0xb40db5e8, 0x7d99d001, 0xbc34a242, + 0x7f41fcac, 0x1cc87ec1, 0x611221ac, 0x92ac1430, 0x016cf80d, 0x6d7338b1, 0xfa389321, 0xcf120bc6, 0xc7a7f235, + 0xb1e9ca3e, 0x968602bb, 0x64d511d1, 0xf669b3e1, 0x4fe3af09, 0x6064a77c, 0xe1b96a0f, 0x0e8b625a, 0x35d60bc9, + 0xc1fe3596, 0x30e782be, 0x92baa572, 0x5459aa6d, 0x16661ade, 0x889244b8, 0x691951f9, 0x652d9356, 0x4e6014e5, + 0x510b6bd2, 0x5b74b98f, 0xe9c117b1, 0x716dbd5d, 0xb886ffd9, 0x6cfd602d, 0xcb5e823b, 0x11c147a9, 0xa3d353bf, + 0x9743fdf3, 0x9666b2e8, 0xab3a192c, 0xdca99cbc, 0xd1302d1a, 0xd75db3f5, 0x30850c0e, 0x66ce533e, 0x4abc6f6c, + 0x7277d891, 0x25f15cb9, 0x3ad6e5b4, 0x896951c9, 0x9b5b466a, 0xca9137a4, 0xdffae616, 0xd86ec995, 0x4ea3600f, + 0xc4bb8329, 0x051ede1b, 0xd401de80, 0x0cafd039, 0xc00d784c, 0xe9f7f75f, 0x47acb584, 0xffa32c12, 0x03eb27f8, + 0x4db05c9c, 0xa9e10dc6, 0xd8cfed7a, 0x9514ce90, 0x727daa5d, 0x425fced9, 0x3af3296e, 0xe5a8bd17, 0xa2cc4b60, + 0x98446b21, 0x73218846, 0xd9b82e34, 0xdf4fc26f, 0x39c4176d, 0xf48886b2, 0x638b77ab, 0x2a5dd5b3, 0xc96ef3c4, + 0x84c12473, 0x62499eba, 0xca0f0ce0, 0x42702d35, 0xb4b1bfcc, 0x4bbf1401, 0x303c5382, 0x1675267b, 0xd2935b1a, + 0x2be1e9ba, 0xd29f51d3, 0x2ac37dfe, 0x05beb9ea, 0x12d951b1, 0x79ac0b12, 0xab871dec, 0x8f60a724, 0xd938c4ed, + 0xf0c23a54, 0x0b69b92b, 0xae8d8ccb, 0x33e1f3ed, 0x05b829ef, 0xbf00246c, 0x23368c05, 0x252d6d34, 0x34a8f264, + 0x21e5928a, 0x8f5e3aca, 0xd01e2c1a, 0xbf414407, 0xd053e83d, 0x3ef98f96, 0x336e25ac, 0x7847663d, 0x8d4a9f27, + 0x3ec83190, 0xc9503480, 0x88d5318f, 0xa81b0985, 0x1f516835, 0xa779c1dc, 0x75893c91, 0x276a2aab, 0xc48fcfa2, + 0xb52b5301, 0xa44f8a45, 0x2e359014, 0xdb62ae28, 0xa21c0dcb, 0x64974f7a, 0xb25dfc0b, 0xca4f12e9, 0xaec33026, + 0xed44ec2a, 0xad40c712, 0x5296cb11, 0x8246bd8b, 0x319f9073, 0xb32edf8f, 0x3a40d6d6, 0xa6411cd4, 0xbeb538a5, + 0xe9fdde96, 0x40d90d5f, 0xa5003cd2, 0xee8e8842, 0x67dfac0d, 0x1bdc0a96, 0xb0269089, 0x33532bec, 0xf3189263, + 0xfefb4ec0, 0xf6f10143, 0xb9f7384f, 0x1a246311, 0xff5cfba7, 0x52dc11e0, 0xbcf90db5, 0x10fe430b, 0xde0ad662, + 0x56154a3e, 0x547f568e, 0x12853fdc, 0x01b9813a, 0x253e37be, 0x6b3376ee, 0xdf3ba497, 0xa160200a, 0xae663871, + 0xad59d859, 0x7923e5e8, 0x97046420, 0xd2e64afe, 0x5f8dfd2a, 0xe328d9d6, 0x5dc05853, 0xac87b51d, 0xa3b7a8b5, + 0xcec33eeb, 0xf29c6714, 0xbb056d67, 0x696fe145, 0x324cb737, 0xd5777273, 0xad5d0e3e, 0xda7b818f, 0x1dbff6f8, + 0x7649d490, 0x908bbeb2, 0xcd700e1c, 0x85262564, 0x5c952989, 0x2d3d4a57, 0xba116526, 0x66c10e5b, 0xce5a2f96, + 0x240e827e, 0x9ba069cf, 0xdab9da1b, 0x4fdddc0b, 0x8ae401a5, 0x4bba746a, 0xe788062f, 0x714d1167, 0x0b247f7a, + 0x5ba681ef, 0xb718304c, 0x2047ddce, 0xc7bfaa91, 0x644ee8b4, 0x85f15b55, 0x3379074e, 0xf3cc594f, 0xbbd21194, + 0x2a69a97f, 0x475c95d2, 0x0f7ea1a9, 0xbe8f3125, 0x2405c4f8, 0x8bdc28db, 0xf9b32006, 0xe31bbd52, 0xbb84ab48, + 0xe7d4e780, 0xf27c2d13, 0x60bd497c, 0x7aebd023, 0xc4c3e096, 0x73072253, 0x1fd3e81d, 0x23c714b7, 0x153da598, + 0xc9a519e5, 0x35484875, 0x30cb4922, 0x4046bdc3, 0x6f983371, 0x37fde4a1, 0x2256d380, 0x6d7839e4, 0x18bc188f, + 0x4f51ec0d, 0x8dedbec7, 0xb5512ccc, 0x6ffae1c7, 0xa8e19cff, 0xb24c71dd, 0x8804e629, 0xf661cd2f, 0xfa042ac4, + 0xeba09512, 0x71eb8d84, 0x86cf0d8c, 0xcabce76d, 0x15b44ba6, 0x05356949, 0x1ba2c4e9, 0xbcdde389, 0x413ef46b, + 0xb0ee24e2, 0x448d3f08, 0x09f60425, 0xc25b7edf, 0x716dc8bd, 0xb176c9d7, 0xc6f903d5, 0x33160f22, 0x3a40369e, + 0x1563f167, 0xa254808e, 0x8ce57905, 0xbed83c00, 0x38c68ba7, 0xbcc22418, 0xeb7e9f37, 0x2b511ab3, 0x80bf3143, + 0xdfdb3acd, 0xe2e14310, 0x36a92875, 0x03910d2c, 0x5cf70984, 0x3f7e8b71, 0xba6df8d9, 0x2a7f8e0b, 0x14dbc8bf, + 0xd22ae2fb, 0x8791ad38, 0xc594db93, 0x69b1ddd8, 0x5ead0f78, 0xbfb335c2, 0xe1e6b43a, 0x4b734d6a, 0xae030ffc, + 0x0280f3ea, 0xd0880a32, 0xeb2dbf2f, 0x475c9dc4, 0xa260ac89, 0xb6142b30, 0x95c7f57f, 0x0b6c31f4, 0x9a9b6d4d, + 0x99b4d811, 0x200e9d93, 0x90c3e1d0, 0x78df540f, 0x5f64cc6b, 0xd78ec768, 0x7c435d2e, 0xcf08f313, 0xcb4196b2, + 0x7393d88a, 0xd1fcc4a0, 0x122fea03, 0x107b9e25, 0xfb5b44e9, 0x9ead03ee, 0x0b85086d, 0x2e516ebb, 0x544b6535, + 0xdb0b961d, 0xbfefa431, 0x1d40d7a9, 0x7ddf25f3, 0xcb24762a, 0xa7f38dcb, 0x5f49a6d9, 0xfad61562, 0x36bd8212, + 0x3c5d1c3f, 0x63bc4c8c, 0x8bc9f4ee, 0xa3f76d6a, 0x9f146dc4, 0x3240fd31, 0x98785365, 0x5684f564, 0xe2338659, + 0x6b31743b, 0x37e3dffa, 0x5075d170, 0x0ff83834, 0xa7fc8171, 0x4583b429, 0x8da36d5c, 0x9841d421, 0x5351dc11, + 0x1170a89e, 0x3dacf425, 0x3f313a49, 0xcff49e2d, 0xb7261324, 0x52fc89df, 0x3d8d6c0e, 0xdadbd523, 0x30e7a0a5, + 0x9da41246, 0x5c907e8c, 0x0510464b, 0x21c343b7, 0xc205d086, 0xf8444597, 0x59f128c0, 0x1e504c52, 0x2eccda2b, + 0x04229d4a, 0xdcbde164, 0x9aa181ca, 0xfcc90da5, 0x67763829, 0x05024bf5, 0x2ee45109, 0x6ec8efa5, 0x46a08954, + 0x2db0578e, 0xdf5f3e43, 0x55b7cb66, 0xd38aee64, 0xd4d0b0dc, 0xde93a8fd, 0x6ee0eff8, 0xd3e8fec9, 0x986bbd84, + 0x73555b7d, 0xf50395c6, 0xd953f5b5, 0xa701a060, 0x4fd4863e, 0x682a113d, 0xc0aeb0f5, 0xfa73da69, 0xaef10542, + 0xc4d1e081, 0x75309e28, 0x1be8445b, 0x9b73ae96, 0x05a6d719, 0x379991b7, 0x1b119848, 0x95e362a0, 0xd48d4541, + 0x5b2aa902, 0xe5d421fb, 0x2a4dd64d, 0x4065dced, 0xe103ebca, 0xff7de50e, 0x609fab9d, 0xe272e8d4, 0x46567a19, + 0xce3cee67, 0x852f1c44, 0xb9c53c98, 0x46bd3838, 0x33154781, 0xe5c556de, 0xb3a92a3f, 0x38b97dd1, 0x1899a1be, + 0x2e1e4186, 0xabe3aa13, 0x15123f4a, 0xa851ffc7, 0x8c9666c2, 0xf212ba50, 0x6fcb397d, 0x467546fc, 0xf4cc26cc, + 0x12260636, 0x40812610, 0x3099ba7c, 0xe80bc5b1, 0x742c0b5f, 0x325cc4d7, 0x2e9090f1, 0xf1897a40, 0xe3ff64d6, + 0xc92ee834, 0x2d7324bc, 0xf20790f4, 0xe7c1a4bf, 0x6b5b6616, 0x42595796, 0xe428dbed, 0xb4bc24ce, 0xefec0285, + 0xb8337f51, 0x8bcad6de, 0x0d3b10bd, 0x040f4399, 0x03d47d9b, 0x6259c152, 0x40eada12, 0x357b0c8f, 0xb0ba2248, + 0x1a8e2193, 0xb77aa491, 0xb6de8401, 0xddfb302b, 0xc30db098, 0xe392f761, 0x88b5cf73, 0x256a1412, 0x7c4aa3f4, + 0xdf39c186, 0xade63fe1, 0x8e74a89d, 0x41370724, 0x100216ea, 0x1ed528bc, 0x2d3d85ce, 0xb7e4b1d4, 0x78282530, + 0x4cfa7d76, 0x4e868dfe, 0x518a3797, 0x92589a9f, 0xda6a4ab7, 0x48c7d8b7, 0x51eacbcd, 0x000c8267, 0xa9435c90, + 0x694dcc59, 0xab8be50e, 0x2b6dacb3, 0x7e93fef6, 0xee4a01ad, 0xea987123, 0xb6f523be, 0x5a7f9972, 0xa1fa804f, + 0xd7993d2d, 0x6db76f7c, 0x55adb60d, 0xb6c9b76f, 0x9703209e, 0xdbe45a2c, 0xf1bebf61, 0x68f39787, 0x33b40283, + 0xbf9406ae, 0xe8d4dde8, 0x77e9f004, 0x5407da80, 0x6ffdbe94, 0xe41f75cb, 0x7bd072f6, 0xd07953b3, 0x1c66f724, + 0x118aaa4b, 0xc4261eb9, 0x14862784, 0x7e2589f8, 0xbb8369b0, 0xebdd9457, 0x9ebbe0e5, 0x2d244961, 0xaf59dfd2, + 0x8ba7066e, 0xa9a1d6ce, 0xad902372, 0x72d9b7b6, 0x2142d337, 0x448674ab, 0xddc4d2ad, 0x3dfbf043, 0x69393b0e, + 0x6615774e, 0xc5b9aaa1, 0x05d6d97b, 0x5bd4bf20, 0x1e74539d, 0x8cd47689, 0x44a397e2, 0x80fa96e5, 0xb7265937, + 0xb1b544a9, 0xf3495976, 0x616a5bb2, 0xb866dc40, 0x96cf2803, 0xf4cf4101, 0xa90d4b5b, 0xfe683989, 0x23b2cfdf, + 0x423b7243, 0x5034c384, 0xe8159d7f, 0x2cc19274, 0x73a6fdd5, 0xb6494bb8, 0x4b72053f, 0x736be89d, 0xa825fdb5, + 0x76552d9c, 0xc09de8ab, 0x42606475, 0xc0e0bb26, 0x452517c6, 0x29e67e72, 0xcfc071cf, 0xc7fabd6f, 0x5905fafd, + 0x494cdd50, 0x36611c78, 0x7fc7e8c3, 0xb3ce4be7, 0x2e658ee4, 0x3acdfdd9, 0xfa051883, 0x2616d702, 0xbcd58377, + 0x74ee2b37, 0x4c6f38a9, 0x2e368b62, 0x1fed1e34, 0x92046625, 0x67086eaf, 0x65bb0989, 0x49ddcdce, 0x4dbe0720, + 0xbc405e2d, 0xedec33e4, 0x92f2f8e3, 0x6edb59b6, 0x7c7db209, 0x857d13a6, 0xf1c21ee2, 0x93fadbbe, 0x77da942d, + 0x55442645, 0xa1b8f06a, 0xaa14c42e, 0xe3b6344b, 0x894ef40f, 0x7be308aa, 0x6cac5cbe, 0xd0f86fc8, 0x0d75ce97, + 0x3004a07e, 0xfaca3246, 0xc2edbe49, 0xc90da776, 0x370ed92e, 0x2a4c7488, 0xc523a2a4, 0xeeaa1ef2, 0xaa3173a3, + 0xecb4e81c, 0xf9c88c13, 0xf2572adf, 0x307cafc2, 0x2ff01488, 0x3db105de, 0x670bde99, 0xf164637e, 0x3aa3c1d2, + 0xbd4884c5, 0x06e8ecfb, 0x9e8ce15b, 0xf4e824ed, 0x647062c0, 0xafe4a6e6, 0xe57da7f4, 0x3bfd97f6, 0x04693e35, + 0xbfbcc5ef, 0x397e3c2d, 0xd7bf8634, 0xf3e230d6, 0xb908e16b, 0x7e64ef7d, 0x283a1b0a, 0x1f670245, 0x3e14a1cb, + 0x7418952b, 0x36154762, 0xb2a039a0, 0x6e2e8799, 0xffc13854, 0xe190c9db, 0x9d9a106a, 0xc60a6105, 0xe097f52d, + 0x282b8251, 0x617f2b37, 0xb04c97fa, 0x20b560a8, 0x39f57ec2, 0x534dffdd, 0x04d4d885, 0x616d8d98, 0x98e76e94, + 0xb224edf9, 0x99bd47f6, 0x60a2953b, 0x835705b4, 0x3fffa73d, 0xd86c8348, 0x1278589e, 0x7f7345a0, 0x0388e61f, + 0xa0cbb653, 0x6c580816, 0xc71a84d1, 0xb1cba5f8, 0x00f41508, 0x1ab4789e, 0xdb3628f6, 0x28e0f2c4, 0x548f24eb, + 0xe63d819e, 0x274ceed6, 0xb1a2eceb, 0xc865599b, 0xc68cc6c7, 0xb6e918bb, 0xeedd2846, 0xaa8961c5, 0x3a9131b2, + 0x979c345e, 0x35ea92a4, 0x1dfde897, 0xa93ca055, 0xaecbcdfe, 0x4fb19d61, 0x21fd82a6, 0x3569206e, 0xdb953228, + 0x1c71fc06, 0xf98716e1, 0x6817672f, 0x988a8adb, 0x80ee47c1, 0xc3459c00, 0xc48fdcaa, 0x2175b9c2, 0x65eaced9, + 0xc27180d6, 0x2a2ab323, 0x81242b6e, 0xc718a112, 0xe97ee065, 0x57c4552f, 0xba2f26a5, 0xeae05cfe, 0x19815621, + 0x03d0e474, 0x5ac549bb, 0xeb9c39ab, 0x2bf4317d, 0x7725b3e6, 0xd1691f75, 0x469aa690, 0x348523d4, 0x80ad2fcf, + 0x93d3bd7c, 0xb360e044, 0x3318eae6, 0x829d7566, 0x221f02ec, 0x87ca6a94, 0xac88af4b, 0xe0373171, 0x19480a91, + 0x335debce, 0xaaf05175, 0x40c2b524, 0x680bbee4, 0x8fc5a647, 0xf504fddf, 0xed506ef2, 0x32e29afc, 0x11f820d8, + 0xa6c5e018, 0x093419d2, 0x710eac6b, 0x27b5c56b, 0xec074a0d, 0x420ee7c9, 0x23ec0709, 0x17d280bd, 0x18441708, + 0x354fd59c, 0x53272d1f, 0x33825870, 0x7ebb0a93, 0x1c021ff5, 0x19dd7efc, 0x9a6616db, 0x8f0498fe, 0xa38c1ff8, + 0x6669b17c, 0x2d4706cb, 0xfd0f4e87, 0x7a0ac0f8, 0x81c38f87, 0x68ab0504, 0x026c279f, 0xe3dc9115, 0x80367f5f, + 0x6127179d, 0x79ab8722, 0xa0eb0a04, 0x4e4886cc, 0xa2d74a56, 0xc1893009, 0xb556aafb, 0x24a26050, 0x9d96675c, + 0xd8a08cff, 0xe9c102f8, 0x8952a40f, 0xc52255b3, 0x541cf652, 0x85933232, 0x55ca5f6c, 0x5212b007, 0xa990fca3, + 0x383ed57f, 0x5d226441, 0x70ea86e4, 0x770b63a3, 0x89aee85f, 0x73cde96c, 0xf62a1ba2, 0x3d2e598f, 0xeb22793f, + 0xcde30f5a, 0x659916ab, 0x5a3a4dd7, 0x2c1223c5, 0x463309c5, 0x945a1397, 0x7cd07686, 0x54c3615f, 0x9c87dd37, + 0x52493884, 0x64764456, 0x57982e96, 0xb6c81f96, 0xc7bea1d4, 0x5437d8f7, 0xdd95732f, 0x0d57954f, 0x1fa4ecf0, + 0x78862ab6, 0xd48a6cc9, 0xf3e03596, 0x794872ae, 0xf7d0c43c, 0x70172b26, 0xd4614c03, 0xf0171621, 0x3f54df7f, + 0xa436446f, 0x87d2c9c2, 0xba2a37fc, 0x30008961, 0x552a4ddf, 0xb69ad9fa, 0x34d3f2d5, 0x3e425362, 0xc2d98c97, + 0xa4ef87a0, 0xd89a6e17, 0x3b3fbaaf, 0x7f5438f6, 0x3a0d1ed2, 0xb44e405a, 0xf8993192, 0x1486ebb1, 0x216c6a99, + 0xbcf861c2, 0x2a446d04, 0xe9a7b07d, 0x7ffab763, 0xa4ac1883, 0xb1929ab2, 0xbceff4aa, 0xb6eafa79, 0x16993508, + 0xbfc3a634, 0x17927de9, 0xf570d9b5, 0xb515590f, 0x010cbe9a, 0x3f8b517a, 0x6f358119, 0x29e0d637, 0x80bfdd5b, + 0x9e1bfae8, 0x452a3db7, 0xb1f6538f, 0xdeb5eedc, 0x8c77fdbf, 0x4569822d, 0x9be649b6, 0x6d1785f9, 0xffd3b549, + 0x6eab45f6, 0xf72852d0, 0xeaf057c1, 0x1928fd21, 0x6003d50e, 0xfa159c0f, 0x0a9e3415, 0xc45b3fed, 0xf4154b8b, + 0xd22d2d73, 0x8974d99b, 0x01d4d783, 0x1a1583d8, 0xc56412e5, 0x1607894b, 0x0d2242dd, 0x9f67584d, 0x0180f6c2, + 0x43a98b2a, 0xd340e25e, 0x1b9e6a57, 0xc25de1c9, 0xf51c47e8, 0x85ba4568, 0xf2b58f7a, 0x978ae767, 0x076eb87f, + 0xd9a7b07b, 0x8927cb4c, 0x9c08acfe, 0x4c9b459c, 0xf5ba597f, 0x5af3c733, 0x94d48472, 0x563fbe29, 0xdd412a39, + 0x56d0e8b2, 0xeec8dbf5, 0x335031d6, 0x172f8227, 0xceab684e, 0x79b6667a, 0xefb06ad7, 0xcec51add, 0x77bd2aca, + 0x990dcd67, 0x86f43cac, 0xe2ed54bf, 0x96efffb8, 0x353a8f9e, 0x5439c56b, 0x47f9ee2a, 0x104b757f, 0xb2beca3c, + 0x7662f2bd, 0x88ba4a9f, 0x32e00f9f, 0x086fffab, 0xca11b972, 0xd71a5d50, 0x7e8f1d9f, 0x6350cfaf, 0xc476d8cc, + 0xd6dde915, 0xb5a156d9, 0x7712c4c2, 0xe03a6f7a, 0x3893b5f3, 0x2c90c6e5, 0x3e6c913f, 0x96d21650, 0xc477b549, + 0xc0dc5d14, 0x4668599c, 0x4efe11d6, 0xde257e6b, 0x04755244, 0x33132fc7, 0x8a263a55, 0xb54c8ae0, 0xa8623d14, + 0x92186027, 0xe294d8b2, 0x55e0c5f3, 0x6a036e4d, 0x23ab6b02, 0x9cac368c, 0xbf24ad2a, 0xd2b8c030, 0x67c04ea0, + 0x0ada9132, 0xcfdf0dce, 0x8c1e72f2, 0xbb2c2831, 0xb4215a76, 0x964973c0, 0xba2a760c, 0x9baf4110, 0xd5003240, + 0xddafd8d2, 0x172e36a3, 0xa72c51be, 0xe1b0645f, 0xc3ff23f7, 0xb7efa0b1, 0x3a65ebcb, 0x0f4a6997, 0xade7e121, + 0x5ffce802, 0xdcde50e0, 0x82b0d727, 0xdd1d12bd, 0xf8d2d3d5, 0xf8ec8e23, 0x9b26678e, 0x615d1160, 0x19931c16, + 0xcb23e628, 0xcd5c4081, 0xcfd7ef04, 0xcbc07cdf, 0x5829650f, 0x59d9e657, 0x471c593b, 0xa32daa5b, 0x5dec182f, + 0x00dd499e, 0xbf3ab4da, 0x31a6bb16, 0xf33e7e90, 0x8798dcc0, 0xfe695b50, 0x5855fe18, 0x42ee633b, 0x39ec9930, + 0x593ce7ce, 0x00c2ce7c, 0xc1cb5201, 0x2f432dea, 0xeac2b70a, 0xc21c2ce0, 0xedbc693d, 0xa7b2e07c, 0x4c4856e2, + 0xc09e6db2, 0x8edf0d29, 0xe05789f5, 0xe7098c9f, 0x8c662228, 0x28350963, 0x1cd03552, 0x71b33466, 0x526b7d51, + 0x5b948df5, 0xc5b77b5b, 0x9028361d, 0x0f9e9556, 0x0af430a2, 0x8bcd3bca, 0xfdaefa75, 0xa88346f8, 0xbfdb2778, + 0x66416167, 0x0e7b77c4, 0x4cf5eaea, 0x71db04a4, 0xc646e919, 0xe4c6691f, 0xa3e986bb, 0x6671e460, 0x3ca9965d, + 0xe6ef1ac1, 0x5e553a13, 0x7dbfb319, 0x9f65426a, 0xeeacbf87, 0x8afd728f, 0x1318801d, 0x05da5701, 0xbbaa90fd, + 0x8ffdc561, 0x2c744c03, 0x43683b38, 0xec68d21f, 0xabf247f3, 0x2bb3926f, 0x1b0b70c1, 0x82374b6a, 0xde2cb43f, + 0xee4cddc1, 0xadea765f, 0x4bfb6aba, 0x7dc6114a, 0xfc2841ff, 0x5b888af4, 0xfeacd565, 0x2751797b, 0x1c2bc137, + 0x860a3ac9, 0xa2f39eb1, 0x265f0223, 0x959f35ff, 0xc9143f4f, 0x6e17fe99, 0xd9e33c16, 0x0efc0601, 0x704cf6f6, + 0x9b52bcfb, 0x565f6b39, 0x550959dc, 0x9ca5a520, 0x785cf189, 0xfad5c720, 0x642986dd, 0x87166c9c, 0x04f50208, + 0x4069b84f, 0x1c11f856, 0x75d71068, 0xec4526f7, 0xfcfad7a8, 0xcd149ba6, 0x6b57b9b5, 0x8a4eda32, 0x8c4a1297, + 0x9906054b, 0xf5d6a0e0, 0xcf41e15b, 0xda51a523, 0xe94881fd, 0xc15f6c4e, 0x3706398a, 0x94f6d1eb, 0xe992d74b, + 0x111051f0, 0x1dc285c2, 0xa0debf4c, 0x8d5da434, 0x43e880b6, 0xaf1be4d5, 0x83eb1ca5, 0xd71a2bec, 0x7691171c, + 0xbe0fef4e, 0x13ac1a46, 0xeea570fb, 0x7d6dcb98, 0x0d499796, 0xcf0a04aa, 0xffffe9d1, 0xd7a4393a, 0xcadad0ae, + 0xc83d2d3c, 0x310cc3b6, 0xc2571a9d, 0xf569a34c, 0x51761017, 0x6ba88871, 0x9da3b1bf, 0x598fbc4f, 0x19722432, + 0xada4e080, 0xd7ecc793, 0x11b04515, 0x28acd76e, 0x892220e2, 0x0e8e309f, 0xd05074a1, 0x4e280703, 0x6ce28278, + 0x2f3609b2, 0xb4f6c225, 0x18c2daa3, 0x62be69a3, 0xf1d52486, 0x18544829, 0x6b705bb1, 0xf05e191b, 0x9684610d, + 0x435fc790, 0x0a56b99c, 0xd2617fee, 0x5a6445aa, 0x361b90ad, 0xcc8e8817, 0xd22b8528, 0x9d250bb6, 0x5a7eabcd, + 0xf46b5544, 0x4c48b97c, 0x90e1fbc3, 0xb680105c, 0x51445379, 0x4c4e4f29, 0x16551601, 0xd033723d, 0xa812ebd4, + 0x1dc937d9, 0x22ba2569, 0xc58dc9d1, 0x4515079a, 0x595857b9, 0xfc9bbd27, 0x954a7f40, 0xb16d01c6, 0xa03be964, + 0x0c2d8c25, 0x2ce2a996, 0x45265c64, 0x772f50c2, 0x7e10d3c4, 0x6b22f909, 0x23cad985, 0xed82b165, 0x19741d70, + 0x73c040be, 0x8d65676d, 0x08b25bc8, 0x09f66eaf, 0xf8f758a9, 0xdc2f3d1e, 0xb8854eb2, 0x3a26e8ea, 0x86ebde09, + 0xe7e353fd, 0x514b6730, 0x3ad5d13d, 0x353c2e21, 0x69bbd278, 0x91fa698e, 0xb7f60bd7, 0x219b0ff9, 0x9de99c70, + 0x09b126c3, 0x4e5425e6, 0x9251b748, 0xebc7a18f, 0xfb8ccb96, 0x17e700f4, 0x5037e750, 0x496c6969, 0x5e7f691e, + 0x3e552561, 0xc53babaa, 0x0cd20679, 0xd0db7499, 0x10671cd5, 0xe419763c, 0x2910bd1b, 0x6f68df9b, 0x453c31a0, + 0x3d71d255, 0x3c8d177e, 0x787b59f8, 0xf3e1716e, 0xc0d7e624, 0xec92b56d, 0x6593ac66, 0xa32b015e, 0x712ada38, + 0x7d534a14, 0xe3f488de, 0xe6c2c5f6, 0x75f4442e, 0xb4ade4d6, 0x04535e05, 0x11fdf32d, 0x640c8ded, 0xdd5d2e69, + 0x67ab6d8f, 0x23a83928, 0x820b8e54, 0x4a2301d0, 0x9d201ce5, 0x7da739fa, 0x66844590, 0x5ff9dcdb, 0xbd63ab01, + 0x44af02f4, 0x6fc6acae, 0xbe4a42a3, 0xadbf629f, 0x7dce7e1f, 0x8e68be18, 0xe778c1ad, 0xf4b49bd6, 0x53533a25, + 0xd6353779, 0x368aa6e5, 0x9a49fa0f, 0x3375bc07, 0x58f83c3d, 0x129cbc6f, 0x3fc4cc30, 0x367cabc3, 0x56a206c0, + 0x787e879e, 0xcc2586d3, 0x7a2055f9, 0xa538feae, 0x4d78cf1e, 0x66ca6f65, 0xbd7f68fb, 0x7342e363, 0xf1a3861d, + 0x463597c9, 0x64576365, 0x91bf0dea, 0x3ed8d98c, 0xe4327f0a, 0xc6f37861, 0xbae012c9, 0x366740c1, 0xeebe1083, + 0x22adc5f5, 0x6acbef46, 0x7f178e45, 0x006a512b, 0x15513f4f, 0x2d320297, 0xc13c6938, 0xa217dc8e, 0x7a95ebc3, + 0x8bf377e6, 0x8bd17f31, 0xb6aec3ec, 0x611f35e6, 0x6b404381, 0xbf7fa4d9, 0x1c927df8, 0xa8a00a15, 0x1750d531, + 0x639eea3e, 0x50abc064, 0xad79be0f, 0xd465a157, 0x0dc22051, 0xe8cf25d3, 0x951b1d70, 0xb03f33cd, 0x73b27d87, + 0x3751d61a, 0x2310e599, 0x25f9238f, 0x81c1b181, 0xb66a37b2, 0x43bbebcc, 0x3bf1e082, 0x5b927d39, 0x9b1d2d47, + 0xe0b0e705, 0x827617e6, 0xe9a9fc42, 0x52aab378, 0x3dd77a25, 0x8700d29d, 0xdd7643a9, 0x0be4dcea, 0x98a07fa0, + 0x2d88769c, 0x7fdd4cbb, 0xb1969159, 0x9a54ac90, 0xa585ecc2, 0x7851baed, 0xc5af9c89, 0x800aefba, 0x023b0b37, + 0xc5990c32, 0xfaf009a0, 0xf083e32d, 0xe9f11186, 0x6f24688c, 0xa1362f15, 0x7d9e4c15, 0xca6968b8, 0x934870d4, + 0x5a621f12, 0x0326df36, 0x1ac2cd4b, 0x3bb8e552, 0x32983861, 0xebccbe32, 0x9c8fafa6, 0xe21be059, 0x86af740a, + 0x2213309b, 0x149a045c, 0x66e4154c, 0x6967f34a, 0xae139c3b, 0xa59a155c, 0x05a910fc, 0x4d946968, 0x7fa5e3ff, + 0xb57af6fc, 0x3d611408, 0x26c4df78, 0x56969dab, 0x99103e54, 0x38e88ee9, 0xb0f0a887, 0x21ef173c, 0x530a7361, + 0x34dfa6f7, 0xa9068f67, 0xf4eae25e, 0x8583cfbc, 0x085e7c9a, 0x0b71c51d, 0x213a050f, 0x6e5a1583, 0x25465f9a, + 0x5cc43316, 0xf77a5d4a, 0x08842aef, 0x3f6713fa, 0x5b532cda, 0xcb399e70, 0xe59da876, 0x2582a566, 0xc9277d55, + 0x1eedf3fc, 0x2510df44, 0x458c6bf8, 0x57673cab, 0x736adf55, 0x3266a76a, 0xa01862c0, 0x53efc586, 0xf64ca0b2, + 0x2a093115, 0x54385567, 0xa8afe290, 0x1c91bba3, 0xffa21c39, 0x1ce2311d, 0xd5175578, 0x3b7b2eb4, 0x99b07496, + 0xa6c899b3, 0x645384a7, 0x19da34f0, 0x08f68846, 0xd9839135, 0x2d964155, 0x9642b7c8, 0x8ad77d67, 0xde5d0c8f, + 0x3c8af413, 0x8dd07b77, 0x8fb138c3, 0xde7d59bb, 0x4f2d624a, 0x0b5e35b8, 0xf29ae368, 0x31ad575a, 0x82d48155, + 0xb62d8e50, 0x466bd96b, 0x3694dc98, 0x81afee81, 0x831f9ad0, 0x197f522d, 0x13994aa5, 0xf213596a, 0x5b665daa, + 0x3ef294bd, 0x82ef4a8d, 0x7eb3d2a4, 0x318f3e44, 0x1490ceb8, 0x1253860a, 0x476d462d, 0x76487e78, 0xf4e64f91, + 0x24b259c2, 0x2706c921, 0x72e5915d, 0x279f1068, 0x21d70ba8, 0x6c2a6b11, 0xdade4138, 0x07e9bf35, 0xb30e6ac2, + 0x70200c20, 0x58e64a00, 0xbf2b3ad9, 0x1c55e97c, 0x735a0f75, 0xd2971b33, 0x041c2891, 0xd039aef6, 0xe3003643, + 0x353fc139, 0x59f8c240, 0x68b410ce, 0x75ebae8d, 0x736eae3a, 0x577917c3, 0xc2571bed, 0x7ab85192, 0x054b9d4f, + 0x52123f01, 0x4a202a42, 0x8586b0ea, 0xf15effa9, 0x1f9279e1, 0x6f968921, 0x8e7406eb, 0x81276902, 0x96e1bc15, + 0x03d34f4c, 0x3949e049, 0x0561bcef, 0x87b5e80f, 0x5bba2ce6, 0xf44da695, 0xf0ddc750, 0x472f00c2, 0x30320b5a, + 0xcd8602f6, 0x82107dc5, 0x336feb52, 0x410dab9a, 0xcf506214, 0x9c8230fb, 0x721fa89b, 0x310f63a2, 0xed4374a0, + 0xb9a9839b, 0x34edefb2, 0x95aa6766, 0x5426841f, 0x92baf07c, 0x779daf8e, 0x92ced10b, 0x63e40474, 0x99791906, + 0xfc8353ee, 0x79a9920f, 0xa2bbb913, 0x1b7f37a4, 0xde403c7d, 0x646de774, 0x2125c13a, 0xef4ae38b, 0x5ec1dc32, + 0x128fa5f7, 0xd8b4345b, 0x54ee8f7f, 0xd7c6f099, 0xe945d6fd, 0x731ad091, 0x7e318837, 0x2d7f7bfe, 0x2080ab84, + 0x3be122fb, 0x83e9fd62, 0x8e2b845d, 0x9528c10c, 0x2c2c7903, 0x70b0f02e, 0x3c9ebc0a, 0xe79430b4, 0xe8dfd67c, + 0x4c5c677f, 0x9c01ae7a, 0x124ae3e2, 0xc50d7157, 0x4767be94, 0xd6fef1d1, 0x34c6407c, 0x072af6c2, 0xba42eff9, + 0x86f80c10, 0x48216ae6, 0x0cda12dd, 0x858b9e3b, 0xa7ed1d16, 0xad5b06ab, 0xdab03509, 0x33938d96, 0xbdbfa99d, + 0x26fd76a2, 0x13795264, 0xd946aef0, 0x79bc14a1, 0x2f460b97, 0xe0acf908, 0xa0694e70, 0xd0e8fd94, 0x88cd2ce4, + 0xa5526ff7, 0x37ddcba5, 0xabb88f44, 0x16448e6f, 0x3785195f, 0x874d4dec, 0xa9d7ffde, 0x83353fec, 0x938518aa, + 0x5b6a3066, 0x65f44efe, 0xe4d4ddb7, 0xcb8e9db7, 0x589ffe86, 0xbcf8848b, 0x50ae4e9b, 0x50cc2012, 0x74953ece, + 0xe1d98785, 0x8ac89613, 0x94d2da31, 0x537e3478, 0xb0cc3f61, 0x659b6d00, 0xe7e3373e, 0x15c8ed6a, 0xb03bddd8, + 0x6e85a78c, 0x65ed2af2, 0xd65c2c11, 0xb13690d5, 0x6190910d, 0xa3ca91e2, 0xc8350cc3, 0x4bfdc458, 0x16d256b7, + 0xa73b82d6, 0xe8c6120b, 0xbca39e0a, 0x3452e141, 0xb5dea83a, 0xbccc8c40, 0x987b71ac, 0x71c40eb9, 0x6863f365, + 0x2dbb3858, 0xd7f3ff1b, 0x5e94e782, 0xf010da08, 0xb59e798b, 0x724ac74f, 0x832a5098, 0xea0d93f9, 0xa86738b3, + 0x8d8d951d, 0xa81dfc60, 0x5a7f43d1, 0x7a355c48, 0xee5660ac, 0xe6990dc5, 0x97458e43, 0x597781b3, 0x7fe506c3, + 0x705e6078, 0xb4a89b68, 0x9c138397, 0x91d8adcb, 0xb7277712, 0x6fc09748, 0x0e0d08c0, 0x5a414d04, 0x5b05ea64, + 0xece4d6cf, 0xe5c08b0e, 0x40233d04, 0x29e0d710, 0xb91736a9, 0x7d71dd85, 0xc45406ae, 0x24ca6368, 0xe6707508, + 0x3d12424c, 0xdd346f42, 0xf4cc3be3, 0x9c3f04d2, 0x3ecbb7f2, 0x0048bf0e, 0x7e8ff84d, 0x3e108db2, 0x0ca795e4, + 0xd8c093c0, 0x8ebf57d1, 0x43b2968c, 0x2624802a, 0xd6b8dc01, 0x9a7c0a57, 0x7139ae13, 0x841bb735, 0x190544df, + 0xcb994a14, 0xd607ae55, 0x62fea489, 0x923df6c7, 0x8703dfa4, 0xbaf945b9, 0x975a4aad, 0x1351c878, 0xb253d6df, + 0x38a9f5fc, 0x6f3310e4, 0x5a8dbc2f, 0x17afc4e4, 0x129254d8, 0x67001ee9, 0x94dffabf, 0x146a32a3, 0x82a9dc4e, + 0x34660ca6, 0xa2e2449d, 0xcbe64f58, 0xcccec911, 0x4442b709, 0xc76de27f, 0xf029eefb, 0xe9c60001, 0x91b9a8cc, + 0xceef0804, 0x9b3a5f11, 0xcf63afc1, 0xf467561f, 0x2d078653, 0x097c3647, 0x690892a4, 0x24f9123b, 0x67d8bb6e, + 0x7c64baa2, 0xc09cc526, 0x37f950cd, 0x212d0a1e, 0xe84660ac, 0xe760432f, 0x93a24f14, 0xc1471c54, 0x03012785, + 0x392a5b58, 0x11f1ccda, 0x5bb6b83b, 0x1f582961, 0x0fba63a6, 0xc669ef34, 0x7dbf9808, 0x4765a1e5, 0x36fea530, + 0x040418eb, 0x24aba5e9, 0xd6951583, 0x59f2d728, 0xd95b8295, 0xfcf43365, 0xbe379b53, 0x5dba0dab, 0xa411b465, + 0x55db448e, 0x3d92df19, 0x40ac8598, 0x4d7c5bae, 0xeaa2730e, 0xba658502, 0x7e835e86, 0xf4b40124, 0x368d3c23, + 0x338359c2, 0x7fb19138, 0x60edcefe, 0xe4cd7e75, 0x296801fe, 0x20170994, 0xde8dd70b, 0x41b60971, 0x6e238613, + 0x09ea2c4f, 0xa20f2aaf, 0xb00db2b7, 0xcff6e297, 0xe1b4433b, 0x67c3af9b, 0xb22fae8a, 0x4193eff7, 0x0836fb47, + 0x1d38aaa1, 0xb3caefd8, 0xf3e859f0, 0xcd057a17, 0x756ee7b6, 0xeb78a476, 0xfc679a44, 0x564d81a5, 0xcb141570, + 0x7f59e518, 0xb5dde48b, 0xf780271c, 0x1e5ca019, 0xc5286a07, 0x8aaf5851, 0x88254b4d, 0xcfa21b8f, 0xab901582, + 0xff96aa8d, 0xd5d262ff, 0x7f146646, 0x477f9767, 0x0849e473, 0xbf7eebf7, 0x6fa57c64, 0x8abe9d81, 0xc4659d4c, + 0xd47ed8c5, 0xd410b5e2, 0xcbe4dbdb, 0x3a21576c, 0xfa5a5c25, 0xb94a6c19, 0xffe4e4da, 0x43975a49, 0xef08623c, + 0xa10869c5, 0x0bf72216, 0x97b5c38d, 0xbee37b43, 0xdf74520e, 0xafd9b62a, 0xe7be11a7, 0xce54312f, 0x04c30c74, + 0xf0fc05da, 0x498a139b, 0xf8adba9b, 0xdce0cc15, 0x086528f1, 0x91a0557a, 0xfc1b36cc, 0xf0f643fc, 0xd9242b7f, + 0x769bec9d, 0xc751a8ad, 0x4f5787cd, 0x191a0793, 0x0940a785, 0x3d5df678, 0x0edf01e7, 0x4b1ab797, 0x599d75ba, + 0x01e1dcf3, 0x1e556573, 0xe6d1f499, 0x9aacaa26, 0xa60bffd7, 0x2172b495, 0x8ca177d2, 0x8b3fadca, 0x5f085ce0, + 0x32bbbf7e, 0xb64ebe64, 0x086a6814, 0xeb41ec31, 0x2927e429, 0x9145bc96, 0xf7760fb1, 0x0a77858e, 0x80441057, + 0x814e610b, 0xa63b3969, 0x62c2a469, 0x74485765, 0xa6c7a3b0, 0x30f6fa18, 0x7855f39b, 0x19610ef4, 0x4823f2e3, + 0xd683629e, 0x8f0ecc18, 0x4313e57c, 0x24d210d0, 0xb7d71b12, 0x582bec50, 0x563951da, 0x35159e5a, 0x2d1a24c8, + 0x46312d7d, 0xa032ea59, 0x583ddb4e, 0xf6a26191, 0x7db19bf5, 0xbf044358, 0xdf7b0601, 0xf64ebebf, 0x9e442ed4, + 0x43f98ba1, 0x13f959c2, 0xb4ea39b9, 0xf1efc69a, 0x2b9a320e, 0x1e93a604, 0x20a3ed2f, 0x5b6b7d40, 0x67523f15, + 0xc577b077, 0x027d4e3d, 0xc223abd1, 0x3055f5b7, 0x7a99c7ca, 0x36c24720, 0x1d42a459, 0x0265f954, 0x33b3c0ab, + 0x08ab99c4, 0xc84e0624, 0x7d76be6f, 0x6dce60bd, 0x37e008f8, 0x233e9757, 0xc7d2a5a3, 0xda53c433, 0x547f97ab, + 0x7560d8cb, 0xb78fbcda, 0x4f06a9f4, 0xef3ff338, 0x4431e0f4, 0x29d75d97, 0xa31b1aa0, 0xcc4bb62e, 0x2ca1f847, + 0xbb60c23e, 0x94ca3392, 0x4c65c122, 0x12e28dec, 0xcd452f1f, 0xed4a45a0, 0x9ff82fc9, 0x4d1cc834, 0xc244f549, + 0xf096eba5, 0x57166698, 0x4768a6e0, 0x01f19610, 0xcfed66dd, 0xae9158de, 0xae47c73d, 0x935ce2f0, 0x0c4e2b4f, + 0x78834759, 0xc33dede8, 0x9528dfda, 0x47a7df25, 0x2a4ebf7e, 0xd2004d8b, 0xb2e7e829, 0x9b5c93dd, 0x47526bb1, + 0x14ba71d3, 0xacf8636c, 0x4c997a3e, 0x3ae86c68, 0x79818f54, 0x893a8cb0, 0xb0ea11f1, 0x1642aec1, 0xc249c8fc, + 0xdc0d44cf, 0x4c5ea943, 0x5cc7253a, 0xa56a69ad, 0x96e84b2e, 0x4c558a5f, 0xf6ba675c, 0xc4c0c791, 0x3922194c, + 0xc8bd6abd, 0xeb45c63e, 0x1ed284dd, 0x2a9d5f95, 0x58b36a17, 0xb98d27fe, 0x49c579c1, 0x3a05c1b6, 0x0e581c9d, + 0xb627e201, 0x4276c1cc, 0xd0e6f70d, 0xed85b96a, 0x7472bf12, 0x6fbaf8f6, 0x4d0b7d28, 0xcefd9cbe, 0xe77fec44, + 0xdfab8183, 0xb4b0ac40, 0x327a7a20, 0x66c7615f, 0xdda2a6af, 0xc176a4f4, 0xb3b75cb7, 0x9886152d, 0x5d77918d, + 0xd0d7f321, 0x2138cdda, 0x70e72b12, 0xd76bdd97, 0x528fef6b, 0x950a8a92, 0xc8119823, 0x51877e21, 0x3063e154, + 0xe8f91afe, 0xd37b8d61, 0x62445109, 0x8ef4ce87, 0x5b50b43a, 0x4fe87bfe, 0xd8e0c056, 0xe46b43ef, 0xccd109a8, + 0xb57acb1b, 0x8589bc0c, 0x52bce64b, 0xe3e0f3a1, 0x7090acce, 0x21dbea52, 0xabe74bbd, 0xd9196480, 0x087ce7b5, + 0x1dbfd84e, 0xff247a8e, 0xd8b6d936, 0x24dd3ebb, 0xddf2b669, 0x8eabbd92, 0xc5d1e934, 0x8cc0beac, 0x2b06c9fd, + 0xa5b206d7, 0x290c993b, 0xae6c49bc, 0x200a1318, 0xfe4e1237, 0xe01e6a16, 0xf8714a68, 0xd9f1ca1f, 0x2b979499, + 0x247a231f, 0x3e24bed7, 0xc7dcf87f, 0xe4c1d98e, 0x71612aa7, 0x97d91f1b, 0xc014c94e, 0x39928582, 0x9f402395, + 0x4c8499d6, 0x46f62ae8, 0x4e061907, 0x6dd59860, 0xfc74fe34, 0xb5336110, 0x1ef055b8, 0x667a8728, 0xd15b45ba, + 0xb37edfeb, 0x292f1254, 0x61948d64, 0xcfee6c80, 0xa833ad3e, 0x5c72897b, 0x95de1a14, 0xca7113d9, 0x45470e5b, + 0xd9be1313, 0x499be942, 0x0438a414, 0x8b649821, 0xe1d796be, 0x19c8df78, 0x34014bcf, 0xfdcaff77, 0xa40dfed3, + 0xc0f79e9a, 0x0acb1f69, 0xadd24f8a, 0x4226fad2, 0x97dded06, 0x055d2f2a, 0x85941334, 0x30c8b5b2, 0xd11f2a17, + 0x63d85888, 0xfac7a62d, 0x28625717, 0x47990df8, 0x0b99fb92, 0x5bf5612a, 0xa8bb6884, 0xcbe221b7, 0xebd8999e, + 0xdfd4214f, 0x0bf3fe6d, 0x9fe975d4, 0x50e5eab6, 0x91c7209c, 0x236a1be0, 0x79ad5d9a, 0x19ca4e68, 0x080c4885, + 0x6e5b04bc, 0x3b81c9f1, 0x3ef6e9d6, 0x92a86c00, 0x56fe7a61, 0x8cd21c19, 0xd46a1464, 0x02a57f53, 0xd96d41f0, + 0x9bf4ab55, 0x32ba6a25, 0xbaf715eb, 0x6e21293c, 0x06d254e9, 0x99e6a8ee, 0x919e1177, 0xe2544eed, 0xd202ab55, + 0x2bed24cb, 0x68d00b2c, 0x6f62d9ed, 0xf29ee3ff, 0x1c25375d, 0x8573d7d9, 0xd01071a5, 0xf46102b2, 0x4b4f40e8, + 0x26da8d13, 0x116bf95a, 0x45f8ebef, 0x9c64c1fd, 0x1ccbe014, 0xab24d4a3, 0x5719fef0, 0xfd62afb3, 0x532dcb8d, + 0xe548dad7, 0xcf49a8fd, 0x5f94903f, 0x47047464, 0x6eb389c0, 0x123dc742, 0x7fe0f7b2, 0x28e328cf, 0xb0fef261, + 0x6a702c5c, 0x14dd5634, 0xa2eb1355, 0xdc359737, 0x0672e61d, 0x2a3f4a46, 0x562d85f3, 0x223a539e, 0x2eb8dfd4, + 0xa2baab77, 0xd3dd315b, 0xc8664ad8, 0xaedd1d5e, 0x01fcc4fb, 0x606f1465, 0xb20ed563, 0xd1f2cff4, 0xe245ed96, + 0xe6ac3184, 0x448a0429, 0x6c0a5d22, 0x37c2d776, 0xb02f6718, 0xa0665a19, 0x004acab7, 0x5eceb5b5, 0xf454813c, + 0xcfc42139, 0x1ecb5e5e, 0x6e54da80, 0xee45e6f6, 0x1db0caee, 0x44ed06e9, 0x3551cb51, 0x8fa91eff, 0x2851e7be, + 0xb9381596, 0xe9c4f3da, 0x67f1dd13, 0xf957e00f, 0x66d8d5e7, 0x39be6061, 0xde43b904, 0x216cd993, 0xdfde8c3c, + 0xfc23be6b, 0x4cea0688, 0x83af0d0d, 0xa0235b64, 0x0fe4f60a, 0x234ee5e2, 0x0f7fd230, 0x5dd2b9ee, 0x985d7997, + 0x1f7e3bb5, 0x201445dd, 0xc44cdc47, 0x45a06e2f, 0x706bb8fb, 0xba759a2a, 0x6e133111, 0xf63058d8, 0xb6c0910d, + 0x4ed48fab, 0xdd974c47, 0xb3eb51f6, 0xb15e90e9, 0x7f57aada, 0x65513b16, 0x2172359d, 0xe088a04b, 0x1ddf555a, + 0x015e413d, 0x7bc94548, 0x77a6a7f5, 0xa0fd346f, 0x34d73d85, 0x6c05d3cd, 0x56793771, 0x985b8422, 0x26989498, + 0x2888d15f, 0xdb292808, 0xe6ae4dc3, 0x877b4fa0, 0x8d49638a, 0x63acdfa2, 0xd64fc850, 0x04c0dd67, 0xddd20357, + 0x199041dc, 0xae6770ed, 0x892592ab, 0xb9b5fe3a, 0xa1500108, 0xc0a7a890, 0x7df1a734, 0xd4744b5a, 0x993546ab, + 0x9a02c400, 0x451bb21f, 0xfd8f2919, 0x6e374b94, 0x7cc6a232, 0x3da7b0d7, 0x156e3995, 0x9714db77, 0x868183d2, + 0xc29f6c2c, 0xbf44caca, 0x2a90c1d8, 0x07f008ba, 0x6b6eac7c, 0xaceccdf1, 0x5116a3ea, 0x97ae7860, 0xf74cdec0, + 0x276a53f2, 0x6cb36d31, 0x2d1e7a5a, 0xfb85f987, 0xaba0a98e, 0x8d7c7698, 0xb1aee48b, 0x52fe4f62, 0xe78f99e0, + 0xe10e5125, 0x2b1a5ef1, 0x8a2386b0, 0x97f21d1c, 0xf23ab46d, 0xa1c7d317, 0xab4927dc, 0xccdbea63, 0xfe3c1067, + 0x0de50256, 0xeff05dd9, 0x227f34f2, 0xc8e4e5df, 0x24e4aa96, 0x7d80ef77, 0x6796b4ad, 0x698df2e3, 0x659e2889, + 0xba2d9db9, 0x4c399478, 0x680b3864, 0x9d9a1d47, 0x405b8d18, 0x999d5ccd, 0x768a6575, 0xc13bb286, 0x1936f8a2, + 0x21c5713d, 0xba052a78, 0x485029f3, 0xae14aaca, 0x93beda97, 0xc344d0c6, 0xd202f161, 0x2718e9cb, 0x63aae4a7, + 0x9c9af356, 0xe23cda34, 0x76380ca9, 0xfea5d942, 0x547964fa, 0x4cc31880, 0x7a01d012, 0x58aab8b1, 0xfd6cc659, + 0x393578af, 0xbd1e7f4d, 0xf359e620, 0xfcae8136, 0x9c8c6a05, 0x8aa1ad49, 0x877df5ce, 0xe3c79264, 0xa102160f, + 0x4f551fc8, 0x0ceefa7b, 0x8e7e710d, 0xc4f238a5, 0x69df8ef4, 0x780ad5d9, 0x4f047e0a, 0xcedf023f, 0x0a7f129b, + 0xb1fdbc7c, 0xbf97eb1d, 0x37767331, 0xcf869e25, 0xdebc15bc, 0x06352d7d, 0xa59136ab, 0xfd943827, 0xdaf5fac7, + 0x3f0c3cab, 0xadb07fb4, 0x26ddb9f1, 0x131d14bb, 0xc1b8fe3b, 0x6626a5ff, 0xd6dfa9f4, 0x8fe31f97, 0x60fee4cb, + 0x0a2044b4, 0x6a17c077, 0x833dde2b, 0xeee2e41b, 0x1b38cb84, 0xef835868, 0xa6175369, 0x77da4139, 0xee4921f2, + 0x4295b7a8, 0xd9c930a8, 0xbc138947, 0x2c3161df, 0xc4ffa1f2, 0x1d365ba9, 0x68b5fc9b, 0x654d4f99, 0x1f3862cc, + 0x13b1a1ae, 0xee196d16, 0xad324b10, 0x646868eb, 0x2ee32b23, 0x0c9c1482, 0x2361001f, 0xdc8aa584, 0xd93341e3, + 0x5e7b3b6b, 0xc005510a, 0xfa2a2f59, 0x3fd9cd39, 0xac350bdb, 0x15c50ba4, 0xfbc732a9, 0x4a5c719c, 0xea00b6d7, + 0xbd47591b, 0xf23c8a1c, 0xdd065bc5, 0xd040f795, 0x21466365, 0xdcaaf36e, 0x807ad6d9, 0x84912b93, 0xc888aef4, + 0xa53bd871, 0x3cf27c06, 0xcf9ac2ea, 0xb46c0a25, 0x08e95769, 0x481c3b97, 0xbeb02515, 0x5bd37188, 0xf393a4ae, + 0x4222e033, 0x9bccfc27, 0x8f495a20, 0x008e938b, 0x16257c9e, 0xe5f82cee, 0x7abf27ce, 0x517d4931, 0xa40b1797, + 0x97d9e33e, 0xaea37931, 0x78a9a34c, 0xcef3f063, 0xe87fa78a, 0x1f9a3dfc, 0x495d7ff5, 0x6dc9cab6, 0xce05c3ef, + 0x580103be, 0x6d8ab3b7, 0xc4df186c, 0xf791cc1e, 0x07d7d787, 0xc27ef0f7, 0x851d18de, 0x55751201, 0x6af56e14, + 0xe99bd168, 0x12ee9e25, 0xc30f7c8a, 0x90533dcb, 0xf5a53e7d, 0x10b14788, 0x66084a58, 0x9b573155, 0x5037eda0, + 0x05978d36, 0x677809a9, 0x5561f6a5, 0xdd8d66e6, 0x4a7fe74f, 0xf1ab911e, 0x424ac52b, 0x5852b643, 0xba07b5a9, + 0x473df220, 0xbdea3182, 0x435b63bd, 0xfad92420, 0xa3c154c9, 0xcb7c8f9a, 0x1d263e66, 0x7bb1cf4f, 0xb553f276, + 0x862dd90a, 0x2339a6ff, 0x120a88b3, 0x4a3e7a57, 0x416455e2, 0x9e1f854c, 0x388cdff8, 0x59f82fbb, 0xb2f7b52c, + 0x5c043b79, 0x20a3b337, 0xc7a552cf, 0x8113825e, 0xede72228, 0xc3fba608, 0xeffa4cec, 0x1b8c6ff9, 0xa5ac741f, + 0x093e7c2b, 0xacafb572, 0x4d893838, 0x79ba6801, 0x9255d4b2, 0x35894b1b, 0x83f1bcfc, 0xb23f2225, 0xbb3fe5c1, + 0x2523c26b, 0xd706bdeb, 0x85159939, 0x5052c228, 0x0d72e79e, 0xab9a49d0, 0x7dd9ef79, 0x7e07a151, 0x93112bf5, + 0x2f4d1e1d, 0xefda6e20, 0xd65d5e3b, 0x9b5904d5, 0x398eff1a, 0xb0dafd87, 0x149cbdf7, 0x6eb65f48, 0xba9f20bd, + 0x41459797, 0x87c464b8, 0xb7fa64aa, 0x5db6a406, 0x196c9dbf, 0x6378d4a3, 0x9d6ce01c, 0xa2dd3138, 0x7a3c4988, + 0x8b4c0295, 0x99139dd1, 0x0bc7fe18, 0xfc628263, 0xe745974a, 0xcad8c30f, 0xa160f62e, 0x2cde1712, 0xb7343bbd, + 0xdfdecc4a, 0x065debfb, 0x1cde8618, 0x2e66968a, 0x5646cac7, 0xf6942d97, 0x657c8d5f, 0x60acc793, 0x8e25a915, + 0x2fa499b6, 0x07e3aa45, 0x93df9d25, 0xe5226885, 0x7d875753, 0xb95f0dc9, 0x898b99a7, 0xbcca1e68, 0xc55082d8, + 0x5cd4800f, 0xd7ae4f90, 0x8c4b7dc3, 0x9e152791, 0x87cf1d19, 0x9c7c883b, 0xb9e5fa77, 0xe7d65271, 0x0a7eab15, + 0x71df39c7, 0x61c92259, 0x5054d05d, 0x8c5d22db, 0x83a68b4a, 0x3eee9ec1, 0xa4a1c26a, 0x41981b3e, 0xd3eb59cc, + 0xd481c6d3, 0x8faf7493, 0x458395c4, 0x5b48f6da, 0x2270fe2a, 0x5ac64be8, 0x3feb36f1, 0x985141d0, 0xf24639c6, + 0x98b32ac0, 0x58ab12c4, 0x09a28900, 0x27f9328e, 0x9185dacd, 0xe4ac0a7f, 0x41488fe3, 0xbbd0f47f, 0x8c7bc1be, + 0x25f1f313, 0x806772a1, 0xcef2ec2b, 0xf2721003, 0x9615d29b, 0xd53ab1d3, 0x7cf994eb, 0xb14ed01b, 0xd2ebb7b0, + 0x7f9f9a93, 0xc6a9e00b, 0xd7ec2384, 0x11129606, 0xd214a94d, 0x81634e0c, 0x437c6984, 0x3023a9c4, 0xdcf5a8c8, + 0x8466d210, 0xc0a757a3, 0x3e1132fb, 0x9918c424, 0xde97ee14, 0x45bcd74e, 0x4e24da8f, 0x27d7be85, 0x417590cb, + 0x9f29d7e1, 0x4cd2d042, 0x917df7b6, 0x28711cd0, 0x7c16b520, 0xb5578577, 0x1f2aebe7, 0x9723550a, 0xb0f0b897, + 0xd03ac2d7, 0x872546f2, 0x42548cca, 0xbb512dbb, 0xb015c358, 0x0543a1ee, 0x982c46ce, 0x71f864aa, 0x2b602d3b, + 0x0aff21d0, 0xb45b16d4, 0xbe49f157, 0x2572f5f1, 0x1f6d9cb3, 0x501cec4c, 0x220118a8, 0xf102fdf7, 0x9e665690, + 0xa8ddc7d6, 0xf7e2ed2e, 0xc55cf35d, 0x7ccddb68, 0xea362b56, 0x34db03b3, 0x4de988af, 0x588a9b6c, 0x42bbb0f5, + 0x1f592bf0, 0x690de06a, 0x5a3afcea, 0x924d5754, 0xfaf2ea91, 0x10027710, 0x24704330, 0xf21c6774, 0xb393bc28, + 0x0d9a8123, 0xb9cce2c1, 0x6d377aee, 0xae7c71d0, 0xb95111ef, 0x172f7e84, 0x0018784d, 0x4b1b4df5, 0xb61efa18, + 0x13595dff, 0xb516cd96, 0x3c505bf3, 0xd83a3582, 0xb6628350, 0xc154e83f, 0xa7998fd4, 0x14608832, 0x984b3b1d, + 0x3efe8537, 0x802b39a9, 0x17474c55, 0x78cf60bf, 0xabc0a295, 0x8e3041d1, 0x2c4b7046, 0x9545ff32, 0x6cb819ec, + 0x9008c398, 0x28b08e6c, 0x00788f48, 0x6876418f, 0xdfc30fa3, 0x137118d5, 0x4d31d493, 0xb3c313fe, 0x8f3ae12d, + 0x7eb9d909, 0xa7812bdf, 0xde082b36, 0x2ca1318b, 0xdfcb3200, 0xf7c7c21d, 0xdfb77ebb, 0x248b9d2f, 0x0b06c79d, + 0xdf44e4bd, 0xdf52d242, 0xb398d083, 0x737a1f04, 0x5402fb18, 0x710bbd42, 0xae4366ed, 0xb3642a0e, 0xb0f35577, + 0xbf7e2551, 0x6a322d88, 0x841795a5, 0x68ee137b, 0x96430b21, 0x0372cb3a, 0x8aca2d7f, 0xdc317391, 0x1ea569c1, + 0x0f75d15c, 0x56bffb24, 0xe33c9014, 0xf899042c, 0x4340fde8, 0x31982551, 0x054f6b19, 0x998f6206, 0x1c767037, + 0x32fec46b, 0x4f3331e5, 0x1e696b1f, 0x5d7047b4, 0x536bfc82, 0x595cf3a4, 0x4365ce15, 0x96df5ba1, 0x054817ed, + 0xdc63fb87, 0x09e472f8, 0x95609b49, 0x8cd4b909, 0xef7dd7c4, 0x086fca8c, 0x202127e1, 0x186aceca, 0x56831ba5, + 0xf5944751, 0xdf810952, 0x9f243b14, 0x84df1805, 0x858039cd, 0x5ddfb904, 0x27ed999c, 0x9af08823, 0xca4e579a, + 0x2b12aba5, 0x033656fd, 0x2d54917e, 0x1a9d56fb, 0x317c47ea, 0x5c26a1c6, 0x2d5d2974, 0xb96773dd, 0xfef349b7, + 0x6bafcd48, 0xc4eed3f4, 0x6c804ca3, 0xd7930976, 0x1bc19f68, 0x6fd30bcc, 0xa90a4ebb, 0x8e47fe11, 0x4d7634f1, + 0x605dfad6, 0xb8944c7b, 0x7760975a, 0x3977a404, 0xdaebeb90, 0xf25000f2, 0xfc8e319c, 0xafab3118, 0x416b760b, + 0xc81fd2bf, 0x98c3032c, 0x91521be1, 0x4d1c40e3, 0xf33d6c28, 0x82887309, 0x27de8b8e, 0x97741c32, 0x871f7936, + 0x29b2442c, 0x75e90448, 0xd244c4ec, 0x7d3eef71, 0xefeb6419, 0xc588f775, 0x3669df31, 0xbad39779, 0xa887b81e, + 0x4dfc72ef, 0x662938bb, 0xf683d48c, 0x203e880e, 0xf1ac2bf7, 0xb17d656b, 0xf2ba9c2a, 0x6a1adc92, 0x37c526ee, + 0xb2a314c8, 0xa3e5f8b1, 0xef86647c, 0x84606778, 0xa6153739, 0xf08f405f, 0xfb097664, 0xbb01b46b, 0xaa9f58dc, + 0x3824bd9f, 0xe11c0140, 0x4a3b1c63, 0x858106f1, 0x5ade9741, 0xf3090cd1, 0x735854f7, 0x2f5fd6b9, 0x6f3a52c6, + 0x85744e6f, 0x76e1dee2, 0x4fb0940c, 0xc895a286, 0xe6205313, 0x6cc0f91e, 0x20b74f1f, 0xa0dd3fbf, 0x0c9f14c6, + 0x5ed9a6a6, 0xf27484ea, 0x796ff8b3, 0x22b4e738, 0xaf19fd9d, 0x72b05438, 0xf4e90430, 0xa8672b2b, 0x081100c1, + 0xe240bd85, 0x36ae1d1d, 0x5f09bb87, 0x238dbda3, 0x2e652d53, 0x9c34d87c, 0x3933e41f, 0xeea5d665, 0x83fcb931, + 0xc1992707, 0x91f5b1a5, 0x0328689e, 0xbd0ee62c, 0xb220397f, 0xf67cb752, 0x3ee7f9c0, 0xebba5742, 0xa745fd85, + 0xeb1b0da3, 0x726966ec, 0xede59e3f, 0x90567de4, 0x49e1f354, 0x81439fec, 0x9cda776e, 0x938d8007, 0xc49e2704, + 0xb70e6cce, 0x6fe8b91e, 0xaa81acab, 0xe09894e7, 0x98a7359b, 0x89fa8d42, 0x9b01343c, 0xaf0b112e, 0x85bdadaf, + 0x54cd54da, 0x31fdf290, 0xfc1661c3, 0x7cc4f0a5, 0x51fdd1ea, 0x873b784b, 0x76b0bb66, 0x6876ff93, 0x2f4fd27c, + 0x2c86b57c, 0xb4d69137, 0x45e9dfe3, 0xf1f720a4, 0xed7d1ea6, 0x89f0fb1d, 0x75ac57a0, 0x2734c39d, 0x507807d8, + 0x217357ef, 0xcba83511, 0x981c6d85, 0x9770bfec, 0xed043ed3, 0xf3d89a35, 0xadb419b3, 0x681420c6, 0xa9d2afcc, + 0x387dc209, 0x9c9ca02a, 0x6c836ce1, 0x4f5cb4ee, 0x385019ec, 0xacddc596, 0x4c95f778, 0xda4514b8, 0x1f0caf72, + 0x076cd994, 0xe9204fd1, 0x8a9bd947, 0xf861f558, 0xf7ede25f, 0x95547cad, 0xd9b56b43, 0xb339919b, 0xea2a2cd1, + 0x837033ea, 0x333649f9, 0x07533cb1, 0xb5994831, 0x01dd5607, 0x50fc6fee, 0x99ce1e8d, 0xa0ea81c8, 0x0ce201ca, + 0x38b735e5, 0x890741e8, 0xc829ca6f, 0x7d26507a, 0x5b53faae, 0x3f7b8d7e, 0x8a5eec0a, 0x6ac3f0d8, 0x40a71471, + 0x2e5237f5, 0xc628ede8, 0x87f1e71c, 0xec68ae07, 0x7d6e3109, 0xedcb25cb, 0x285cf57e, 0x93941249, 0x5cf073c9, + 0xf74171ca, 0xc8ba4206, 0xce831f56, 0x21a9297b, 0x22aecb9f, 0xce043f9b, 0xfc4eb223, 0xe3453bf7, 0x453fb3ef, + 0x6a1451af, 0x746543b6, 0xf8f1c2e3, 0xf2d08929, 0xbe9e4f3b, 0x0375a371, 0x55718552, 0x853bc925, 0xcbe3a91c, + 0x423db2c1, 0x72f5a158, 0x0f1f515a, 0x7ee49813, 0x74bbed26, 0x018978f7, 0xef3b5b8f, 0x84a4f5db, 0x146779a0, + 0x733c2837, 0xd3e5c777, 0x377de955, 0x4c5e9d35, 0x9d520d4a, 0x99ca07ab, 0xf551ff8d, 0xe85f7c42, 0x182df71a, + 0x37ee223a, 0xa84da06f, 0xe2344b12, 0x86a88faa, 0x57044776, 0x8a0cd402, 0x4125386a, 0xdc061ab7, 0xf523ffc0, + 0xa81e5cae, 0xb82e763f, 0x7f2b5b51, 0xe1e809ca, 0x707f1983, 0x07e12946, 0xe72c41b2, 0x1c9fd1ae, 0xecdc3d55, + 0x469a7d86, 0x42c404c2, 0x14837be2, 0x038942a9, 0xada7160b, 0xed6724a3, 0x98f29e6c, 0x47fb8433, 0x2ec0e616, + 0x06150669, 0xe842b509, 0xffacc59d, 0xecc192af, 0x24896cc2, 0x3d7f83a2, 0x24e111c1, 0x4dd5e79d, 0xdac782b1, + 0xd9c857c8, 0x6eb3612b, 0xcf10721f, 0x9076b8f6, 0x137c9670, 0x1abdb69e, 0x1b692590, 0xa70df57f, 0x26165d8e, + 0x4ad4dba8, 0x1dc50a1a, 0xf30619bf, 0xbb6c4b22, 0xaa4761a0, 0x2225b8f2, 0x62411730, 0x92a949d0, 0x3a7101a7, + 0x23377b07, 0x57da5201, 0xf8ffab69, 0x80661d00, 0x41c37636, 0x8656aaa7, 0xdf1180db, 0x5f8b0f87, 0xc6c9f1b9, + 0x1b9b6271, 0x45f0eb64, 0xe33ca67d, 0xbeba0593, 0xdb2001ff, 0xc49aab9d, 0x68684356, 0x04bc1993, 0xcd1b2615, + 0xf7e0a17c, 0x6f81ddfe, 0x4e05eb26, 0xe9ea39bd, 0x0124b2b7, 0x4e0ef416, 0x5ef7129c, 0xd2db1673, 0xfb01cbfa, + 0xc865f3d1, 0x5e0e9a0f, 0xd3bad8ba, 0x195e9c9b, 0x7a156d57, 0xe6661bed, 0xfa762441, 0x8f5f8c2c, 0xa171be31, + 0xefa6f766, 0x0979c56f, 0xc9724549, 0x0abe2a04, 0x3c0fd1c2, 0x79c3a0a3, 0x0437dc7e, 0xee89a706, 0xca3cb189, + 0xf1420f2e, 0x6e55ad3f, 0x5b0206b0, 0x41f999b2, 0x384e25a4, 0x16d1b37d, 0x2cd8200f, 0xeac568f4, 0xfb90991a, + 0x9ca9aae3, 0xc2ebc95d, 0x8c72f87e, 0xa7ff4bdb, 0x0912c8a8, 0x7e6ffe58, 0xd4488b44, 0x07998d2c, 0x9f46f275, + 0x5d89cd62, 0x332b5c4f, 0x37ca2778, 0xa16a4580, 0x661493ae, 0xa44e0e43, 0x84a0ffe2, 0xad102637, 0x452655d3, + 0x9ba3b7e7, 0x8c686cde, 0xee092a64, 0xa8ea8405, 0x3fcf26e5, 0x943af959, 0xbae5d219, 0xfd621776, 0xa6a210a4, + 0x6e97158f, 0x02546099, 0x91f1382a, 0x7dd5bbd2, 0xb5e80da3, 0xb9d18bb6, 0x116715ef, 0x5110812b, 0xa87bca57, + 0x69fb62e8, 0x0f1ab171, 0x25b4a27f, 0x6421ca96, 0xe1c29215, 0x3eb1174b, 0xd74c93f6, 0xcdbd5162, 0xa3db8738, + 0xe88af7e5, 0x17f7b7f5, 0x78bd1747, 0xb820ba2f, 0xef1feb02, 0x95b492bb, 0x5ef15107, 0x694671b8, 0x941a9da3, + 0x4cef217a, 0xeff53c94, 0x71112bf4, 0x9db6c616, 0xe3873c4c, 0xcee87494, 0xe9d351e3, 0x467041db, 0x06d07079, + 0xa7dfa736, 0x69cd0162, 0x5e114706, 0xe94a64d0, 0xa830bedb, 0xea4e0edc, 0x5ef98b18, 0xf2551274, 0x96a059a7, + 0x94e6eceb, 0x3177ca6e, 0xb761ceff, 0xd5fdc807, 0x2223f349, 0x9001e0e4, 0x9f95f2b9, 0xa970b2fb, 0xa67b5182, + 0x399e7538, 0x18df8b36, 0x0c972ff6, 0xbf0682af, 0xf5189f03, 0xf4769269, 0x0564ef9c, 0x0b40f90d, 0x90f6086e, + 0x33cc6bca, 0x871114da, 0x191cb3d4, 0xe3a7cc4f, 0x252f6aef, 0xa1ea1e5c, 0xf1374336, 0x4cc1c345, 0xeacd7646, + 0xda392736, 0x2ab47512, 0x33011261, 0x56050f25, 0xede6f993, 0xb1a913a3, 0xa01ea5b4, 0x750cb02b, 0x5e8b3734, + 0xc69f23ee, 0xf9f7c88a, 0x00946808, 0x874cbc65, 0xdd6a689e, 0xb560f8c9, 0xd88a11c9, 0x0acc75bb, 0x3452657b, + 0x69a481c8, 0x8ca6e152, 0xd541cfda, 0x57ca1b97, 0x7982aa9d, 0x75b17c75, 0x56f4f5a7, 0x559f2f7b, 0xd3e6ed5f, + 0x2f6a76db, 0x65da8a04, 0xd325476a, 0xd8c32841, 0xfadd0475, 0x44a225c7, 0x9b0d3ab4, 0x60d34a6f, 0xce1db26e, + 0xa4efcfda, 0x9ad40131, 0xbbbb2206, 0x093b4307, 0x2c501265, 0x18df5eba, 0xb402ba1c, 0x1540f06b, 0x70cc6818, + 0xa2b8486c, 0x5c2119d0, 0x9b7452dc, 0x864ea3f1, 0xcf76878d, 0xca617434, 0x16aa444c, 0xcb91cb5e, 0xd1972e39, + 0x2539ec85, 0xdd8ecfc4, 0x743412d1, 0x95c598fe, 0x16b15336, 0x0d29bfb5, 0x30eb8d2e, 0x5fac70d6, 0x1e498841, + 0x1274695a, 0x52f36ece, 0x0e01420b, 0x3564e82e, 0x11d2f6a3, 0x5fe69d32, 0x44479899, 0x9b63cdba, 0x6e734e60, + 0x60eb282f, 0x079adffd, 0xd298c5b6, 0xba088929, 0x19a86eb8, 0x1bd1c2b1, 0x121103a2, 0x69c8ae6e, 0x8914ba0b, + 0x3b569f40, 0x91246ecc, 0xcfb25210, 0x331edae9, 0x1176477e, 0xc5e4e54e, 0x69659908, 0xd1a969cf, 0xa2a64e3a, + 0x52b7efe8, 0xb9d06742, 0x3313470d, 0x30003e7e, 0x4b63df42, 0x00ecc29b, 0x84ddaae0, 0xf0256c72, 0x9e612815, + 0xf1550879, 0x74e4883a, 0x7f6d77f1, 0x69659501, 0xf62010e1, 0xb429d921, 0x23aa87da, 0x40d6e208, 0x8fc8649d, + 0xbcaea4f9, 0xfd958567, 0x1e213ab0, 0xf2eca8f6, 0x33ad3719, 0x879eef73, 0x31f3a832, 0x2f3d76b8, 0xaf12717e, + 0x30e6f074, 0xe651530b, 0xa3a274fc, 0x231895ba, 0x4f01c1ad, 0xbb0faa6a, 0xb24c8de7, 0x31b0ef09, 0xfb69444f, + 0xf576b805, 0x762b4895, 0x49e6413d, 0xe51fce9f, 0x9e66b6fa, 0x6fb07863, 0x6ddd527b, 0x6bad0e88, 0x7fdc65fd, + 0xe86a18ca, 0x7be39fdc, 0x9ea42849, 0x0b3b4cd7, 0x0987ea0c, 0xd767bc26, 0xe7528971, 0xf7776bd0, 0xb7fd8b39, + 0x54b986c2, 0x36a554d3, 0x2b5d7132, 0xc15ec342, 0xe27bfb61, 0x1720422e, 0xb446e7a1, 0xea7abc1d, 0xfdf9ea1f, + 0xd7c3f5fa, 0xd5b0faff, 0x5c09bbc4, 0x5ca70c67, 0xf9fc9bb5, 0x52f1f2a9, 0xf0cebbe6, 0x9b6336a2, 0xa5f2243b, + 0xd13cc40d, 0x80c03918, 0x43a9cc98, 0x7639d275, 0xd5749b9f, 0x0efdffcf, 0xb2154419, 0xc306bee6, 0x4841abf2, + 0xd2f49f24, 0xca734e44, 0x7deefeef, 0xaf5dc604, 0xf90fb358, 0x02bd81ad, 0xcc77f191, 0x0b11e91f, 0x024e624a, + 0x412aef77, 0xf88e5b5a, 0x9142c3b3, 0x1e94ccaa, 0x7c7b3630, 0x33e7d457, 0x171e67b2, 0x21692eb8, 0x26351276, + 0x1a8b3a17, 0x97beedf0, 0x02a143e3, 0xf886a208, 0xc493c0b5, 0x46c37d89, 0xa6fd5333, 0xd35a9643, 0x2a25ae15, + 0x330b4580, 0x0d70adfa, 0x7c463d6b, 0x14608a89, 0xa4f029eb, 0xba6f34a1, 0x453d6499, 0x8bc9a728, 0x6461abce, + 0x1b4e886a, 0x659a8a4c, 0x4d1c79f4, 0xe758af31, 0x0bc6351b, 0x94d62bc1, 0xcdcd2110, 0xd1b1acde, 0xc6191434, + 0x00deece3, 0x86d9e2f8, 0x995185bc, 0x7fd58c13, 0x06e5d9a3, 0xbd42b5cc, 0xebb846b3, 0x6a659d20, 0x155cfe6c, + 0x5d31e8e4, 0xac2c64e7, 0x0032514f, 0x588777e8, 0x105313a6, 0x6a693dfe, 0xc4f33f35, 0x0b6af409, 0xfc8c5583, + 0xb8d708ed, 0xd0a9803e, 0x23e537e8, 0x819791b2, 0xc9019654, 0x831ab7ac, 0xad3a0d4b, 0xa645df54, 0x64d01690, + 0x20b933ce, 0x8b760838, 0x00eb5d1a, 0xdd5c3c83, 0xe6ba15d2, 0x85cddc84, 0x6ff0a665, 0x1c3c43ed, 0xbfef5dc8, + 0xae1fec76, 0xd5727eaa, 0x9170372a, 0xe6d38c41, 0x337c18c7, 0xaa6dd62b, 0x537d3d27, 0xd140729a, 0x1b45fe1c, + 0xfcc0acb8, 0x916c73bc, 0xa86a5b24, 0x34e63b4a, 0x540b5079, 0xe820b48e, 0x5f705733, 0x13c7a278, 0xf8638eca, + 0x7ef25c86, 0xfdd9c6d8, 0xc1a73e4e, 0xfbe2b54d, 0xea9055c0, 0x0cb9602b, 0xc1dbb097, 0xf3a7ed5a, 0x5e06a055, + 0xee492bb4, 0x73e91454, 0xbe4a6ad9, 0x3b7410f3, 0xf9c1e7bd, 0xe4fa029d, 0x91fb17ba, 0xe5b24086, 0x27baf373, + 0xf0baac2f, 0x6a8b8c82, 0xda74287b, 0x373e6baa, 0xbf700aa4, 0x5a8acb10, 0xf2b82539, 0x1645e8a0, 0xbd068725, + 0x14cf216b, 0xe327334a, 0x41c2a05b, 0x6e8d3006, 0x39f15b71, 0xc1a41348, 0xb16667cc, 0x31f821f6, 0xc60f0152, + 0xb690dc1b, 0xb5438430, 0x170d2432, 0xdb074b83, 0x29916335, 0xfb5cd515, 0x8634923f, 0x304dfefc, 0x8b1cb306, + 0xa9ab8cd9, 0xcccf0842, 0x493fdac7, 0xdbaa8c36, 0x1e165797, 0x1fe81e91, 0xa166fd7d, 0xb7c00acc, 0x762659ef, + 0xe3ab757f, 0x5b0de55f, 0xe0f4ee5b, 0xe6c9a29b, 0x764e29fc, 0xdf594d84, 0x8853d2e6, 0x8244b93b, 0x50dd3211, + 0xdf8601c1, 0xf8cd0672, 0x6161242f, 0x0ffdaab3, 0x86b4fc24, 0xfe673751, 0x732418ba, 0x7faa6e3b, 0x2cbfff39, + 0xb25466b3, 0xf39b40d9, 0x96443122, 0x6e1cf485, 0xa48fdcdd, 0x60c47d1f, 0x9b82218f, 0x75281264, 0xf8741cce, + 0xc6064918, 0x28c62a6c, 0xac3851e4, 0x4eeddade, 0x2c0fe310, 0xab2343a8, 0x77c4dfec, 0xd50c9b0f, 0xb88e0705, + 0xf8e8f6d4, 0xb30e0021, 0xaac99c96, 0xea6eacae, 0x62b08c01, 0x04bb8e38, 0x9abd2ab8, 0xbd28c061, 0x085ff970, + 0x904e07fe, 0x0d18efae, 0x7af177ee, 0xa0b23a03, 0x49db6dd5, 0x51ddb638, 0x338374f6, 0x4c01f438, 0x5591c8a4, + 0x1f0a9262, 0xe547d4cb, 0x9dbef67f, 0x93103708, 0xcf7063e9, 0x068d3e3c, 0xe023d1f1, 0xe68ca7ac, 0x18d482b3, + 0x9fbd33a6, 0xab506b7a, 0x5a5c4850, 0xfade656b, 0xfd5a1c36, 0xc0204b8e, 0x0345f9c0, 0x1edfed11, 0x699a8668, + 0x0ad85e36, 0x7bf80e42, 0x7e8c37b5, 0x783d0f88, 0xd3c51ca8, 0xb68990f8, 0xbe58541a, 0x920a9c85, 0x16d33b7d, + 0x073b48d3, 0xa83fe78c, 0x11e951ec, 0x2ccb7712, 0x430b990a, 0x08aa0439, 0xf3b62178, 0xa4e46f98, 0x00d6681d, + 0xa73a8fd9, 0xb41615c8, 0xa138dfe7, 0xc02b23ce, 0x466fe473, 0x952335f0, 0x335cc489, 0xa47381e4, 0xeae1eda2, + 0xaaba918b, 0x92150fd0, 0x91c8b07d, 0x3407709e, 0xc04384ad, 0xb1aeb1a0, 0x8256810e, 0x4f07c17a, 0xedf303f6, + 0x360cbdf8, 0x912ac1c7, 0x348d3bee, 0xfc1aa8fb, 0x3972ba91, 0xbc1247f7, 0xf45edaba, 0x60705cbd, 0x543b5342, + 0xc4a36e1d, 0x6f8e61ae, 0x217e5e67, 0x37965cad, 0xfe84392c, 0x85736b32, 0xd442c149, 0x650223d3, 0x7e501656, + 0x95090b5f, 0x5c9832aa, 0xb32e4f0e, 0x1f620fd3, 0xb9f14e9e, 0xba6e3f4f, 0xcfeea366, 0x86efe9c9, 0x68f5b9d1, + 0xa1955af8, 0x0daf7c24, 0xdb4707bc, 0x4c5c4c58, 0x3ef0e5e0, 0x4d1de4b5, 0x1564d72e, 0x5fff0a17, 0xa05a03ba, + 0x7102a14b, 0xf9a179ea, 0xe9493861, 0x55610eec, 0xb135dbc9, 0x660ed19f, 0xb51f8cde, 0x6d55c0ab, 0x8f80c4a7, + 0x56185db9, 0x3aaf144b, 0x352ba4ed, 0x9021750a, 0x4ad296af, 0x5d86e671, 0x4a374321, 0x19273a10, 0x3e70e10d, + 0x2d5541df, 0xa71877b0, 0xa997abe6, 0x83d1c70d, 0xeee303c2, 0x53e9f63c, 0x74f9034d, 0x14897993, 0x5c38f669, + 0xa123cf1e, 0xe87ade65, 0xc3cb2525, 0x28198042, 0xbea111cc, 0xd3ad6965, 0xd99bd35f, 0x0b13f308, 0x7e2cf096, + 0x2e52e24b, 0x2823646f, 0xd869c125, 0x7f8ef0a5, 0xb1c64d68, 0xcfa74d57, 0xa3036728, 0x1d04d5a8, 0x9e965b2b, + 0xf984b3a1, 0xeedf355b, 0x99351636, 0x58dc1dce, 0xc0d50b32, 0xf2c2f8cf, 0x2cb4ee76, 0x7779f573, 0x04fb99fc, + 0x1cd7b3a3, 0x40d6bd66, 0x13212adb, 0x7e908d39, 0x1e8d23ea, 0xefbcfc83, 0x49b4f6e6, 0xe8e3f571, 0xb98a3d02, + 0xaee25dde, 0xeb01ad92, 0x353c58c6, 0x3eaf6f5f, 0x304bfe96, 0x6e223b2c, 0x1fa8f713, 0xa1aff8a6, 0x059b8902, + 0xe2ae6118, 0x66e931f5, 0xfb2f35fe, 0x49d48b0a, 0x3a577de7, 0x7384ecf9, 0x43c8d9cb, 0xf0dbe0eb, 0x16d3a6d6, + 0x9060f66f, 0x2912de4f, 0x8e8b0d46, 0x2cecc1ff, 0x76cf8bcc, 0x2933ca39, 0x4f3ce72b, 0x1f4c9a3a, 0x73bac6fa, + 0x201cd7bc, 0xf82bc5d7, 0x64fdf423, 0x48c62202, 0x05d35a52, 0x83d3b652, 0xec6b67cc, 0x69f8a42b, 0xe3422930, + 0x87a91471, 0xcef2d1c7, 0x98da5bdb, 0x7189b56a, 0x448771f5, 0x6dc56b76, 0xf33642f6, 0x069842d4, 0x1a5584f9, + 0x1cbdc4a3, 0xd8256316, 0x76108b9c, 0xfcbc52c8, 0x2bec21eb, 0xc6acebdd, 0xce1deb70, 0x7ecd6e9a, 0x2ea715b7, + 0x776f6075, 0xe29d9341, 0xf2d876f3, 0xb67f7204, 0x1d763d0f, 0xa6f27ad9, 0x85352026, 0xabf9106e, 0x7e3f4cb6, + 0x22d26568, 0x83a3f57e, 0x34e00445, 0x8aeba540, 0xec8a6e86, 0xb783a428, 0x8987d5b9, 0x9332b6da, 0xaf129486, + 0xc02095e1, 0xcf94bded, 0xab3c2cad, 0x718f52a7, 0xaae34242, 0x0a7fa52d, 0x8a4b97d6, 0xa2048d59, 0xb2192a0e, + 0x4e0a95c2, 0x1dadd5b1, 0xf3fc8aed, 0x459d5ebf, 0xeef15d74, 0x1cd75e6d, 0xb9498397, 0x23956974, 0xd0c2fc20, + 0x67cf399a, 0xb3c1335a, 0x912e7295, 0x202456cd, 0xb22a5f0a, 0x5146d817, 0x30b37845, 0x9edb5a5e, 0xbeb5f757, + 0xe61eddc4, 0x9cdaf15f, 0xc8c76d49, 0x5476d853, 0x1a578902, 0xbda1fa75, 0x29257bf1, 0x70a84f12, 0xb200b615, + 0x4fd289e9, 0x62ae5ba6, 0x7159a528, 0xba029305, 0xa6200ec0, 0xfafe7fe0, 0x85346995, 0x45c8e365, 0xe1d1ffc8, + 0xb3e7b378, 0xdef54d86, 0x68b670ba, 0x0d0a1760, 0x0367f45e, 0xe444963b, 0x3de9eca9, 0x2629c9cf, 0x0b5a4ac8, + 0xd7d96bff, 0xfda81673, 0x54c4ce56, 0x92b64838, 0x13e928f5, 0x2600ea71, 0x341904d9, 0x27ab0822, 0x745cdf45, + 0x15aaa2b6, 0x563d7e61, 0xf62a2669, 0x335753a3, 0x38115c12, 0x431f9a28, 0xac1f1369, 0xb3227d34, 0x3ea84dfa, + 0x50a3f6b7, 0xabb9d991, 0x3da3e264, 0x03ffdb97, 0xb12f4641, 0xe31c5e8c, 0xa546b3a5, 0xc8b6cefa, 0x0162f565, + 0xc2f1e3ca, 0x18945551, 0x1ff8b0c6, 0xa40ab8c3, 0xab291a5a, 0x42f20fec, 0x0c256e96, 0x9e4c9a53, 0x8e526873, + 0x7f2164f2, 0xdebf08bf, 0xca6f6a51, 0x2eaea03e, 0x48ed65f5, 0x150f9a6e, 0xa558a215, 0xf0851213, 0xcd39f1f4, + 0x1f1b901e, 0xed9a6388, 0x512391ab, 0xe774964f, 0xc85b38ed, 0x584dd168, 0xce225d3c, 0xd55c6aac, 0x45091398, + 0xcff8a244, 0x37dbe0e4, 0x2949db11, 0x772c6377, 0x9707de59, 0x6c99d856, 0x0860006c, 0x725fe81e, 0xd94c64fc, + 0xe5dccba2, 0x5594296a, 0x296d3da9, 0x9d73923d, 0x70734934, 0xf30b983e, 0x318d6255, 0x5bd36fe6, 0x9f2f571c, + 0x6d60c027, 0x652c5990, 0x2b5d5aa4, 0x7ba06b12, 0x2b5e6252, 0x447befa8, 0x9a180ee8, 0xaccddefc, 0xc2c90516, + 0x5eec0523, 0x9404001a, 0xf3289536, 0x924bfa82, 0x1ce35713, 0x97879a85, 0x4135d2a1, 0x525326b6, 0x481ab585, + 0x5e22a12b, 0x12ee4f5c, 0x92be12ef, 0x23dbeb5a, 0x3cb74a91, 0xec79195c, 0x57881e92, 0x56207b70, 0x397d2899, + 0xd0fbfa96, 0x26e546d2, 0xdf64ad33, 0xaf9bd293, 0x3346749b, 0x584f4634, 0x06a55761, 0xf98129f0, 0xf231d685, + 0x17852d7c, 0xe6b9f592, 0x892683cb, 0xf976c09a, 0x0e7126f2, 0xb3310cb8, 0x5cd093d5, 0xabb5bb4a, 0x454a866e, + 0xab4d6951, 0x653181ab, 0xf30f83d1, 0x48b6a388, 0x57dbbdcd, 0xd5e880e6, 0x36086809, 0xce3a8e78, 0x7cb7e24a, + 0x2d36278c, 0xf9aac9cb, 0x8bbe2b33, 0x02445f12, 0xc7cac8fa, 0xa5613dd1, 0x3b2eecd3, 0x7229b62e, 0x6695d77a, + 0x10ec41f2, 0x4076bcbc, 0x90756c4a, 0xe70f941d, 0x7d0ccd02, 0x8762895a, 0x8348578b, 0x87fe45e1, 0x59ee84fd, + 0x67ac9b98, 0x0b4c7432, 0x8b0b8622, 0x7f0ecf2e, 0x530919c8, 0x31867ddb, 0x38033c62, 0x3de49ec7, 0x10302bed, + 0xe28daa6e, 0xc7423f17, 0x2007d376, 0xbfda2b42, 0x1caff547, 0x3393465f, 0x54ef77f5, 0xed093b43, 0x6df9f79a, + 0x1349a8ed, 0x06e29853, 0x7b72d005, 0x2499043f, 0x3d065cf6, 0xcfd3eb70, 0x4eb0cb7e, 0xd63a8e9c, 0x24f07b9b, + 0xf9f4098e, 0x6d2f7cb9, 0x7f66dbba, 0xe8900c67, 0xe96a342f, 0xecbcf4f9, 0x36d0be57, 0x0ec3c560, 0x2d26c5bd, + 0x5fbf143a, 0x0ce61a04, 0x7cda5e6b, 0x00c36888, 0x51aaec5d, 0x863eada4, 0x9d2268df, 0xb27a6a06, 0x7e47c3b3, + 0x1f028da9, 0x8aafce11, 0x60745d82, 0xc825be28, 0x7301b83e, 0xea90b150, 0xd56bfe00, 0xd342912f, 0xd3ce7c77, + 0x9b7ac117, 0x421d80b5, 0x373bc21b, 0xd7d9bd4d, 0xe7c8740a, 0x802b7ccc, 0xdde360c8, 0x528c7725, 0xa63562f5, + 0xdc9a939a, 0x86b48deb, 0x591ab60e, 0x3b55f4e9, 0x2090b0ad, 0x1b1ae005, 0x70de2ad1, 0xb08b0453, 0x6da02dda, + 0x856946b4, 0x2782cfc3, 0xcad2b2f9, 0xec3a7967, 0xd5e36e44, 0x5eaa9ff8, 0x1852f753, 0xf12f1822, 0x3c0e8150, + 0x7d25edee, 0xd4545a7d, 0xc7aa86b1, 0x9ed6e4b5, 0xea894704, 0xe15c951a, 0x11fb2be7, 0xd11d4a1e, 0x9f422a11, + 0x83e40682, 0x69bce85f, 0x58f952da, 0xc730eca2, 0xef84f175, 0x809e281b, 0x2182d07e, 0x5e8fcf93, 0x5a03f237, + 0xaaaf5c2e, 0xc73a70f6, 0x830e0970, 0x89313093, 0x71c3030c, 0xe9055c33, 0xc28fb79e, 0xe8c648ff, 0x35e75e33, + 0x9164a28b, 0xf4bc712d, 0xee72b3f4, 0x797f225f, 0xddc29b37, 0xf6b7f6f7, 0x47a0f4e1, 0x56df9f0b, 0xbe024775, + 0xf4973c8e, 0xcc8c129e, 0x45e4c1d5, 0x3137862c, 0xa863a9c1, 0x80ed92c5, 0x6d869762, 0xa35d24ca, 0x325ba3ce, + 0xdc9793cf, 0xe123951d, 0x19c44669, 0xd6276d91, 0xf8f9f50b, 0x811ac6fb, 0x436fdd5b, 0x6b97e256, 0x62b377d3, + 0x4e91c273, 0xfa1e2e70, 0xeba15b53, 0x01022b14, 0x8322ddcf, 0xd5ef4052, 0x47a18d95, 0x37da23c5, 0xb1fe006b, + 0x652ded55, 0xf4c0481f, 0x95c8871a, 0x6e1850e9, 0x97195451, 0x37290482, 0x27b871ff, 0x298f4b52, 0x0e22a26e, + 0x04ad0c7c, 0xc46631ba, 0x5d9d079d, 0xba486cef, 0x28955a15, 0x928e4907, 0x1cf5f3bc, 0x43fb38bd, 0x8484803d, + 0x56242daa, 0xc10205ad, 0xfe1774a5, 0x25c5c70b, 0x20490a32, 0x1421a69a, 0x8e06b4e4, 0x4ef863ee, 0xfbba9eb7, + 0xe38f769c, 0xb6112377, 0xd2e5c56f, 0x07f13a91, 0x1b79fca0, 0xdc9ce87b, 0x9e71d3ea, 0x3f8b7eae, 0xf6ab4d8c, + 0x8d493390, 0x5a730962, 0x6ecd9b74, 0x352f3d9e, 0x36d68715, 0x722e5724, 0x7f45f13b, 0x217a0795, 0x0aeefed2, + 0x4dc843d4, 0x76ebc802, 0x5de036e9, 0xc5a9fcfb, 0x168ef262, 0x2a3d26ec, 0x619b7d2f, 0xd81530ad, 0x0374d1dc, + 0x33b4a602, 0x9b759d29, 0xe1f23926, 0xd67999e2, 0x38be0b7b, 0xe0f67d29, 0xe35a9681, 0xfb904bb3, 0x1e45287b, + 0x32849aa2, 0xda11cfb1, 0x80b04ca4, 0x21d73e46, 0xc9076f25, 0x82797d27, 0xa6bb0530, 0xc263fb64, 0x328c8740, + 0xd79697d1, 0xadbc3a9e, 0x3b04624a, 0xbfe0295d, 0xf393eb96, 0x7f710ba4, 0x0722d2a4, 0x272c5b0b, 0xe167f5db, + 0x581271ad, 0xcbed3fd5, 0x6f77ab2f, 0x11d7b9a2, 0x9642db1d, 0xcee54bb1, 0x6b1d38e5, 0x68e09112, 0x1d982f78, + 0x4676202b, 0x3d4991b0, 0xb1b1cd30, 0x7b503a66, 0xa19ba046, 0x1002e0e9, 0xa4e61a3f, 0x4017fbeb, 0xd96e52a3, + 0x3d3d4777, 0x77a242b7, 0x2cdf0130, 0x439ab3e0, 0x82f52d2b, 0x194b9832, 0xd73e1497, 0xd57df77f, 0x216e4943, + 0xb54bc242, 0x49db5781, 0xff782744, 0x25f4fad0, 0xa343b6c4, 0x328de31b, 0x378c54d3, 0x39f321ea, 0xdf14200c, + 0x07a1aeb1, 0xd6763779, 0x9443efd9, 0x6854fe72, 0xdc0a7338, 0x71852b50, 0xc2e41ecc, 0xbcbba0f9, 0x55604ad6, + 0xc37aeb9c, 0x6cb3f447, 0xbabbccb5, 0xeabb3209, 0x83fd175c, 0xfcdc3a7a, 0x0d556d67, 0xb4985f22, 0x8a8b9154, + 0x4fcdda58, 0xbe2d700f, 0x7177a8c0, 0xdb5749d6, 0xf36efca4, 0x316234a6, 0x16a0b4ba, 0x1d2cf9db, 0x3fb95417, + 0x6396a30a, 0x06f6e412, 0x0ed0e411, 0xc2bde22e, 0xde869759, 0x5f58338d, 0x517e59c8, 0x3c7bd971, 0x36751351, + 0x1c7758f7, 0x8988c026, 0x418af408, 0x831ceb6a, 0xdc6f9a32, 0xd5f9b883, 0x4bebcc38, 0xb3de550b, 0xe61340eb, + 0xabdfa77f, 0x778aa17a, 0xd29da960, 0x31a17f25, 0x47bd6416, 0x483ae1b4, 0xa8460401, 0x751751ef, 0xe6f1b72a, + 0x5b65a0ae, 0x0294019a, 0x42da4bc3, 0x0a3a68bd, 0xaa4dfd1f, 0xffff42f8, 0xcbe6663e, 0xcf180e17, 0x9cbb2993, + 0x45ca21d3, 0xe67f78cf, 0x6cef7f62, 0xc98e313f, 0x56623caa, 0xc5ef23fa, 0x55aa2d16, 0x9ade91f3, 0xe71a00da, + 0x1e03c706, 0x21107b8a, 0x977d8d5e, 0xf3776e61, 0xe50efc33, 0xd81e5cfa, 0x34df7c83, 0x1b72f3de, 0xbb512511, + 0xe56d53c3, 0x942e1551, 0x38957c1c, 0x6125c012, 0x6eca424e, 0xa71be8c7, 0x7e3e2c28, 0x2d1b92ae, 0x8dcb251a, + 0x8bc9437b, 0x11fe0821, 0xd9fdda57, 0x2e378c82, 0x0930e062, 0x8520d3ce, 0x02936357, 0x5f2e4889, 0xd60ad8f6, + 0xa5a2facf, 0x6937def9, 0x2004d3fc, 0x6a633909, 0xb1b34676, 0x1f434670, 0xb7f0efc4, 0xdf4c71ee, 0x397f839e, + 0x6e870dcf, 0x00a985e1, 0x7ae6f090, 0x35d1f0b4, 0xbf5395a5, 0x42087331, 0xb176f9f4, 0x8894bd40, 0x7a891a86, + 0x37c95147, 0x68382ed1, 0x3329e133, 0x5ba8058d, 0xcbc5d517, 0x8b4d47ba, 0x1f3c78c0, 0xe4c474c3, 0x6fcf9ad2, + 0x4f40f67f, 0xe86d7237, 0x1defd611, 0x64844f7b, 0xecf8fb1c, 0x0e3db146, 0x58107a04, 0xe004546e, 0x6e7d2164, + 0x72efd213, 0xf887ed9f, 0xdb3b9112, 0xda44eb4e, 0xc47056d7, 0x64f17a8c, 0x758eece9, 0xe8577e98, 0x3b90f034, + 0xbb4b3eca, 0x2c7beec7, 0x4925195f, 0x593f0b52, 0x5794068f, 0x9e36fb1a, 0xd4414638, 0x5c6cb8de, 0xa7fb8228, + 0x6aa73cb4, 0xea1b9d4b, 0xf504cc37, 0xe9c1a0a9, 0xff8b64a5, 0x6ddbb12e, 0xed7d31de, 0x32de5d97, 0xc7821bc9, + 0x5265e471, 0xead82860, 0xa25687f0, 0x541e11f7, 0x3333294b, 0x552c2152, 0xa5698a73, 0x05c95267, 0x648601d8, + 0x853a872c, 0xc3c8e681, 0x7056669d, 0xbb6a8c4a, 0x2079bcfc, 0x193907ea, 0x9b63cd4c, 0x623f289a, 0x4000a9da, + 0x57c00673, 0x4109b2c0, 0x81cbb058, 0x3d90d12a, 0xa4e52c92, 0x66b4e0a9, 0xae8bb518, 0x8cf425f0, 0xec703ff3, + 0x37683e7b, 0xcb63ff99, 0x2d90d74a, 0xc2fd7444, 0xe53ffea6, 0x7c0f4b9e, 0x1e55ec90, 0x14953574, 0x01cacc3d, + 0x85eae6f7, 0x2ab4086b, 0xd686e9ac, 0xc4a3e225, 0x72be5476, 0xf0f12b50, 0xaf658d0d, 0x467c0322, 0x2feb42c6, + 0x3d6d7252, 0x392e9fbb, 0xb982a0fa, 0x332724a2, 0xb0447056, 0x5eee1d2d, 0xc87ce1d0, 0x2723622c, 0x6e098c99, + 0xb545616b, 0x57039874, 0xb5869442, 0x8b16c05f, 0x0b52cd32, 0x62803c71, 0x7c2b7e1a, 0x4a99f36e, 0x8dc13260, + 0xf4a98146, 0xb85745e3, 0xa2c4ae68, 0x0eb083e4, 0x91467ebf, 0x98d5a0bb, 0xc39b2c8f, 0xb20c7a00, 0x818b4486, + 0x9052c8c1, 0x72c6ab15, 0xc4583934, 0x33c183b8, 0x485a24b7, 0x0a249712, 0xb57fb220, 0x20dabcfe, 0x392d8cd9, + 0xf1d0d554, 0x9d1bdf65, 0xf6ce6725, 0xad6410e6, 0xb02ecb21, 0x9415a44b, 0x4824360c, 0x854d0e10, 0x47a5a75f, + 0xc9a0e029, 0xff6a5dc4, 0xd4f3995b, 0x7fdea143, 0xe79fe4b7, 0x45d1acd9, 0x417433de, 0xe9121d98, 0x62ff551a, + 0x4d9f4087, 0x1250a5e0, 0x48078f23, 0x3cf68286, 0xb202671c, 0x814009c6, 0x55beefa8, 0x2e3a94a7, 0x4d5d8566, + 0x9e15fcbd, 0xfcefd1e4, 0xc305475b, 0xbe3123fc, 0x55d36fb3, 0xf233e34d, 0x54944a2b, 0x09340a53, 0x70e9191b, + 0xe319572a, 0x84bb8123, 0xc793da4d, 0x8e2c923d, 0x1f4be0c8, 0x91678c61, 0xd2663216, 0x8f6afaf4, 0xe638c38e, + 0x100d0e5a, 0x70435083, 0xe8f47f31, 0xdfadc41c, 0xe7e72094, 0x4c302cea, 0x5ffe5cce, 0x01eeacc4, 0xdae258f6, + 0x39b6f93a, 0x593fa0e1, 0x5de2c3e3, 0xb714c5e0, 0x6521a793, 0xcc1ed570, 0x12fd0451, 0x93b395a6, 0xeb03702c, + 0xbf9a2630, 0x2e84b476, 0xdd8058e4, 0xf835848a, 0x28fc7f1b, 0x44fb1d6c, 0xa34b72a7, 0xe34c7ea6, 0xd73bdf5f, + 0x1f2f14fb, 0xe5fd5a41, 0x5c595a4b, 0x8eaabc80, 0x1896389e, 0x4fa099e4, 0x41beff14, 0xfa1751ca, 0xf0542fbf, + 0x864ac26e, 0x60e52305, 0x6946403a, 0x0a3fa4a3, 0x241ed067, 0x26b9baa4, 0x39d1a85a, 0x70ac5b72, 0xccacc33e, + 0x7614b432, 0xe3545670, 0x7e10be6b, 0x00d066b5, 0x84500630, 0x2fcb83d9, 0xb0aeabbd, 0x31d45da4, 0x2a413a04, + 0xe74d53c8, 0x9959fda5, 0xab210499, 0xbf04cd02, 0xb71a09cc, 0x958e2dfa, 0xa62b9e27, 0xf35ead26, 0xef7435c2, + 0x5bc36cdd, 0x57488558, 0x44ff3429, 0x8a5211db, 0x1d045119, 0x7b9ddf69, 0xd31f271d, 0xba7e7908, 0xe070e771, + 0xa09bbe61, 0x4d8e2fc2, 0x196d4ad7, 0x76a72c89, 0x902898d5, 0xf73f0f34, 0x3ce2d5eb, 0x0b8d654f, 0xfb482a52, + 0xad1a5075, 0xba492e4a, 0xa6bbf48d, 0x4b09f907, 0x01431e0b, 0x866d9a7a, 0xd7b932f1, 0x14a3abcf, 0xa6acc281, + 0x1d121f64, 0x2e8ee1fd, 0x82f69d61, 0xccea3eea, 0xd0143423, 0xbfbd2bfe, 0x0c85340c, 0x2e925755, 0x56aea167, + 0x283dd673, 0x66c6b49f, 0xeed7d2c5, 0xac61a92b, 0xae110eca, 0xdf8034c8, 0x26b8706a, 0xfd5d95e3, 0xbcd72b40, + 0x5d0f7cf4, 0x25e8893d, 0xa2206330, 0x76f182b6, 0x8a6a11bc, 0xe7aa3db4, 0x1fe46f97, 0xb2194a77, 0xfac70a3a, + 0x8e6d3219, 0xab4f723a, 0xee4c85bf, 0xe34d71df, 0xbfe9de58, 0xd7cfbe21, 0x4fc12714, 0x8203b7cf, 0xd195fdfb, + 0x012f1fb2, 0x8927572d, 0xdb016793, 0xf91122fb, 0x78061b75, 0xf9a78755, 0x60ccbf7b, 0x66e1e250, 0x4b4a8af6, + 0x074d1640, 0xcc60474a, 0x7b34a1cd, 0x228b7fab, 0x608c65ec, 0x436dff70, 0x81938d1c, 0x9de5318d, 0xd6b46092, + 0x88cf936e, 0xa7924257, 0x19f75bed, 0x311325c2, 0xf1b110e6, 0x1888ee9c, 0x0b6d9273, 0x54f65192, 0x2bd4c7a4, + 0xd7c56fa3, 0x5d23170d, 0xcaeeb157, 0x957ad57a, 0x40b1965f, 0x9350598c, 0x0f7ab792, 0xe324b421, 0x037229a1, + 0x423d450c, 0x2d8f50ed, 0x27e15fb8, 0x0f50faff, 0xdcbec61b, 0x871c682a, 0xf167085f, 0x973bc3ee, 0x59bdb044, + 0x04d5e986, 0x1a9b1629, 0xb8ce3ec0, 0xe6332eaa, 0x5d3b7273, 0x81b55735, 0x72fb1b3c, 0x3af44608, 0x94606e0f, + 0x9570f24f, 0xe95ba248, 0x228353e4, 0x28cf3f97, 0x7a710f85, 0xf096f88f, 0x088cba4f, 0x67db7b22, 0x9700d8f9, + 0xd94fb591, 0x07310195, 0x2f7343a1, 0x92741d68, 0x7aa87e6e, 0xd6bc64c9, 0xc691a609, 0xa30e321e, 0x77dcd06e, + 0x783c8c32, 0x17ed2aeb, 0x9ff41587, 0xbe808e1e, 0x49da4a47, 0xa865d984, 0x7b44aff1, 0x684f11a4, 0xd5a3daa4, + 0x7b101c23, 0x497156f7, 0x5f2a29b7, 0xf68d30a5, 0x0da4338c, 0xd2757e5a, 0xda567b13, 0xac01c34b, 0x4542a294, + 0x636195cd, 0x59ed6e9c, 0x61c51ddf, 0x0f8ff3ab, 0x52ca6d65, 0xe42cafac, 0x42267f10, 0xaf487c3d, 0x20c8dea7, + 0xbdaead18, 0x9342bbdc, 0x336f4c6b, 0xf4be6b00, 0x9be2f63e, 0x6bfd9109, 0x33391b54, 0x5b82754c, 0xa24ffa1f, + 0x06789e61, 0x3e32130a, 0xcfbbdeeb, 0x5961111f, 0x10e8afc5, 0x426cea68, 0x4c9dfe1d, 0xa179e600, 0xd137b8a6, + 0x0e506738, 0x90742c9f, 0xd8315971, 0xe1dcd90d, 0x93a8d88a, 0x2b7bab53, 0xd84a38d8, 0xad020232, 0x35d9f535, + 0xa65afa4c, 0xe2f654d9, 0x41caa6cb, 0x13e1d643, 0x7fd6f4b0, 0x86fd40e4, 0xe20e1f9a, 0x923ea65a, 0xacb5ee6f, + 0xa72433df, 0x77feb7ef, 0x868338a6, 0xa343ab16, 0x330273c8, 0x5c83506f, 0xe2c7cadd, 0x7ec26ee0, 0xe2d2d264, + 0x47aa6f09, 0xc19ee40e, 0x0237b8f6, 0x2dc49958, 0x839d7153, 0xf954cf73, 0x53c8192e, 0xa6aebeed, 0x64f10154, + 0x697cf5bb, 0xc299b1f5, 0x5b3d63c2, 0x94ae5910, 0x4fd25cb7, 0xec52a63b, 0xfe1d38f9, 0x487b2547, 0xdbc188f9, + 0x4d0f6867, 0xd6218bf0, 0x6ac7ed00, 0xb0f69856, 0x0f471848, 0x7822fcd7, 0x41b1e868, 0xc87003a9, 0x9f3b1b3e, + 0x647bbe1c, 0xe3bbd39e, 0x29cbcf90, 0x1b411003, 0x85e447ff, 0xc67ee436, 0x1bdf0875, 0x46a35e04, 0x81b9b78d, + 0x655622ef, 0x639b1cd2, 0x4734b130, 0x3ad2799e, 0x53e5b1d5, 0xbc85ed39, 0x777f3e53, 0xc33cca4d, 0xa5a1a4f4, + 0x83b29339, 0xee8751be, 0x25f09299, 0x16264a97, 0x28a6bea8, 0xb79aa7f8, 0x167f3c92, 0x66e30fca, 0xf736c488, + 0x7a5d7b29, 0x684aef8b, 0xd6df9176, 0xc70dd719, 0x66fb482f, 0xbdb8e59d, 0x64f651a9, 0xb22dd3eb, 0xbeb336a5, + 0x601cda98, 0xc71f7fe4, 0x08d6c94c, 0xac88fca1, 0xf392bd7e, 0xb70c4b7d, 0xd8bee37f, 0x362795f5, 0x1f45d589, + 0x0ca758ec, 0x9ed778a2, 0xef161ad8, 0x2645f935, 0xb977a221, 0xdec786be, 0x1c0e0b4d, 0xae585d96, 0xf8ef2df7, + 0x165e089d, 0xccd42853, 0x3fe4f9dc, 0x0e27c450, 0xc95523da, 0xb2020a61, 0xd28f8ed4, 0x24ffd8f6, 0x854f0dc8, + 0x0d4a63e2, 0xf51b1a04, 0xb5352bb6, 0xa30931c4, 0x293529e6, 0xfa5166a1, 0x95c0d53d, 0x01778f3a, 0xc9fdaabf, + 0x7f9d966c, 0xfee152c7, 0xc4bb4691, 0xb543ea52, 0xf29ae6ac, 0xb91eab6f, 0x6609a3de, 0x5bfd9bd7, 0x2c8f0128, + 0xec550000, 0xe2ba6588, 0x592b8ee4, 0xa047a35b, 0x8dfb81d0, 0xd0cee182, 0x06bd3d78, 0xb6f7f92e, 0x0a0701c2, + 0x3921478c, 0x1f9e5587, 0x2995ac18, 0x50701536, 0xddd2568e, 0xad95aa8b, 0x284b1df9, 0x233c231d, 0x40ce118e, + 0x6ca2a3c4, 0xfa9f5b5c, 0xb6ee86e3, 0xf6dd2214, 0xc815e246, 0xc8f6fb31, 0xabc8983c, 0x793438fd, 0xaca15648, + 0x37e93b49, 0xd306f2d6, 0xf44174f7, 0x2f561f63, 0x38367de8, 0x2f2fc075, 0x56791137, 0xdaa77e08, 0xd5aa66d9, + 0xb84c2384, 0x4f44322b, 0x1a4facd6, 0x6337b1f7, 0x19b941d1, 0xfe279e2e, 0x1573bb60, 0x62d05236, 0xab899440, + 0xc0e5215d, 0x05c214f7, 0x0fd26006, 0x08e3ab97, 0x1c1395fa, 0x7eafaa2e, 0x398e3589, 0xb3c148d5, 0x6fb2f429, + 0x6d3cd38f, 0xcabc29f9, 0xacbd14d5, 0x69d6add6, 0xf8edae91, 0xb7383e0b, 0x66bb2da3, 0x01224a8d, 0xb63e4f8a, + 0x2a78fcfd, 0x397cb2aa, 0x086da09f, 0x60e66f2a, 0x84ab58f9, 0x79b133c7, 0x7e65b614, 0x5c43a7ca, 0xf4cd47a4, + 0x690af636, 0xfe9822a6, 0xeb8b28e2, 0x25cb2edf, 0x80e7111e, 0x8a236f6d, 0x6173d969, 0x62de15b9, 0x41631e7f, + 0x2e30d178, 0x0294ba8b, 0x30c1f6d5, 0x23b56f49, 0x9e78930e, 0xf6f6775f, 0x840d7f63, 0x86d7f979, 0x269b4c9d, + 0x0544b22f, 0x74c34023, 0x32389884, 0x8675eb93, 0xf62e9a8d, 0x589109a8, 0xa7048b66, 0xd46dfdd1, 0x0882e101, + 0x99779828, 0x7fcc4511, 0xb5b8cbbf, 0x97fe9c5b, 0x2a9d6314, 0x5b0e5fdd, 0x65130b70, 0xbab2b032, 0x172c7b52, + 0x507e337e, 0x2bea7934, 0x0c64a041, 0x57dcbc7e, 0xa7cba754, 0x814ee733, 0xa24a8022, 0x4a297ad7, 0x1577d674, + 0x42b28088, 0x9ed5377b, 0x81077432, 0xe1cf3f38, 0xa4eaae89, 0xd5a36293, 0x557e7b33, 0x054deb44, 0x57dced5f, + 0xee60dacd, 0xb1ceeadd, 0x24d9f9fa, 0xef64c6e3, 0xfd52af57, 0x1f76b80a, 0x89012cb8, 0xd7d3d28f, 0x216ef87e, + 0x33a57778, 0xf1c587b4, 0x6b76ab07, 0xb7e34c8f, 0x746f203f, 0x6c72329e, 0xcb82d49a, 0x3babb9a1, 0x1cf8812d, + 0x3cb15971, 0x060552da, 0x2b6df608, 0x6b3b8b0d, 0x3799b235, 0xb81b4f28, 0x963b5790, 0x60cd2839, 0xbe2ca8d2, + 0xef804870, 0x2e66fc9f, 0x2938e1cd, 0xafce00e0, 0xbb73cffc, 0x69b08ebd, 0x5470d37b, 0xc850eaf9, 0x879b7faf, + 0xfe339b46, 0x17c1e7da, 0x6c6ca39f, 0xf3465d41, 0x962cf8bf, 0x666cc68e, 0x8f99d0c2, 0xe63dd0ae, 0x4c51b85a, + 0xe4d6496e, 0x5e03620a, 0x34fe51b6, 0x55152784, 0x1f859b8e, 0x0b9b3377, 0xb7fd4f2e, 0xd883a569, 0xd9b08b1f, + 0x74db141c, 0x4b0f2847, 0xd806802e, 0xbef76cae, 0xb3500d00, 0x9da355c4, 0x4f037497, 0xe8f6b925, 0x423e88a3, + 0x18774076, 0x4a74568e, 0xc9c2ce4a, 0xf583cea8, 0xc29ad692, 0xda6b922f, 0x23a38373, 0x4ca10896, 0x20fd7bd7, + 0xce379164, 0xc4d1cad0, 0x70e8fdf5, 0x12e77974, 0xadd3d077, 0xc227c24d, 0x1ed950ce, 0xb42344d4, 0x660eabac, + 0x6afccb6a, 0xdcc142c8, 0xef433290, 0xbc47bafa, 0x85667238, 0x6086c28f, 0x07003114, 0x8e26d0ed, 0x1084d2e0, + 0xa5138bb4, 0x6c4dbd1d, 0xdec855a7, 0xe4a016db, 0x3a0e121c, 0x220c61e0, 0xbdeedad8, 0x6b146bf0, 0x778e188b, + 0x0787ef52, 0xda9daae2, 0x6c257539, 0x51182502, 0x7aa8535b, 0xdf2e524c, 0x965a0c9e, 0x1a1187cb, 0x27a4f069, + 0xae75bb74, 0x5dd7bcc0, 0xd5d4fb5b, 0xbfde141f, 0xb1a830dc, 0x9e0fcdc5, 0x3cebb767, 0xb155d3db, 0xe13bffd6, + 0x7228d212, 0xcc4a5aa4, 0x5d9224ef, 0x3829f479, 0xed870e5e, 0xa1c0618a, 0xa03fe9d1, 0x47d54ec2, 0x2b4f082f, + 0xbbf109fa, 0x310b3805, 0x9056122b, 0x9f933e66, 0xa278fdd1, 0x30456b2f, 0xdb7ef0ef, 0x356d2728, 0x80771960, + 0xb44dc6ad, 0x125b92e4, 0x6a987c9d, 0xfda15aea, 0xbac0288f, 0x5c52594b, 0x83f780a4, 0xfcbbe243, 0x4d44fda5, + 0x434ad8e3, 0xd60388ae, 0x108ae0ff, 0x79f84587, 0x05d57449, 0x1318e392, 0xf3fb1e34, 0xd9a4e2e6, 0x767193f9, + 0x380d5c6d, 0x3e20b720, 0x0660b978, 0x9da82c19, 0x2bc507cc, 0x704305f6, 0x9a61e370, 0xe63b6b1e, 0xcc19eeaa, + 0x11bea40f, 0xa02f7226, 0xd47da533, 0x7736438a, 0xb3b3e972, 0x6654093a, 0xe1b56621, 0xc10fc8fa, 0xf6b21877, + 0xf757dd21, 0x634b5db6, 0xc43a7b15, 0x37d60d70, 0x1eb36ec5, 0x64fa7192, 0xe9e015dc, 0x009cdc1b, 0x040a8f5e, + 0x2d9dbe3f, 0xe740a1c4, 0x1be813e7, 0x05d34776, 0x69f346eb, 0xbf14a50d, 0x99bd5072, 0x4019dd2d, 0xb4517865, + 0xc76628f6, 0x103e4c34, 0x5245cdd2, 0xc2ab9edc, 0x245f1bad, 0xa7eeacb1, 0x88c7ecb4, 0x4338b002, 0x30036704, + 0x074b9740, 0x4e0371f7, 0x04b9540a, 0xa569e0ee, 0xb56df4ab, 0x635c19fc, 0xead37e4a, 0x053537d9, 0xbeae4bab, + 0x43f00f0f, 0x8b2e0bd0, 0xef7e5627, 0x403fc1a5, 0x4f21c226, 0xb44483ac, 0x83880242, 0xf765e0dc, 0x03cbe007, + 0xfd0ca9ba, 0x0f8e9109, 0xa3ee10db, 0x3fd4d2a4, 0x989b6029, 0xefed0498, 0x61553949, 0x6c5efd78, 0xb546f601, + 0x8a55fe20, 0xa0df1a94, 0x0be28c8b, 0x3a9830a8, 0x32b75f9b, 0x6f5b801a, 0x9004ce49, 0xdb822ba4, 0xaa4ae807, + 0x1aff9c43, 0xe4a0a0f8, 0x81bca5b3, 0xd3840986, 0x28b21d9c, 0xde876de4, 0x30bbbdba, 0xd27def5a, 0x52488a70, + 0x10734ce3, 0xec922565, 0x2405bd80, 0x8d81efff, 0x3236dada, 0x2cf23c23, 0xd70a9e68, 0x96345ff6, 0xe0ca7c95, + 0x6a769f8e, 0x9c8ed746, 0x8b20e9e8, 0xad1fcbd4, 0x0338bad4, 0xdaa2b284, 0xc5dc3053, 0x32702d55, 0xfba2a07f, + 0x6f173354, 0x84081d9a, 0x0cf2aa6d, 0x973784fb, 0xde93d032, 0x98609d25, 0xc182e81d, 0x78cb52bc, 0xd48fe34b, + 0x664e5b4f, 0x8154d9e3, 0x466b90b1, 0x4b7bf17a, 0x4663b75b, 0x300faecc, 0x80e7e255, 0x3849efcf, 0x247bd2a5, + 0x176c1ec7, 0xbaafe41b, 0xd3bcf270, 0x42c39d4b, 0xda439866, 0xabcab532, 0xa2d800f9, 0x9189379b, 0xdca771ca, + 0x21958f1d, 0xf9ff0e4e, 0xd04218bf, 0xaf5d44d4, 0xc5056840, 0xbb8fb99d, 0x458a4d07, 0x30d89db1, 0x979a88e1, + 0x2a85115e, 0x6a2e1dab, 0x619bcb8e, 0xbb5948a3, 0xabf25860, 0xb31ccb4f, 0xdf916739, 0x1ca273f7, 0x04316167, + 0xe89b50d0, 0x9b0fdadf, 0xefe14853, 0xc2c2d5a4, 0x3c91fce2, 0x0ecbf59c, 0x20606cc9, 0xe8ac9e96, 0x3d45612e, + 0x693aef4c, 0x20bf5f09, 0x425140c3, 0x55532b57, 0x7b21011f, 0xb5922792, 0xda055f02, 0x19dd5d87, 0x4abf8533, + 0x0bbf21f8, 0x7c60b261, 0x150d0083, 0xd3923229, 0x1afccbbc, 0xe9266e69, 0xc016b982, 0x374d98e4, 0x93d108c9, + 0xccc7177a, 0x682e7d81, 0x8a5f5f0f, 0x04aa0d16, 0x470e4f67, 0x71b6c228, 0x7a59bad4, 0xbabd7023, 0x2b82d95e, + 0xdb155b4f, 0xeaed5a79, 0xe66886d9, 0xb374cce3, 0x461bb839, 0x0b1102cc, 0x0f19bdf8, 0xf6564588, 0x749c3fb0, + 0x6544c962, 0xe0cd48ca, 0xfa86918d, 0xb462144d, 0xbb378f27, 0x0659c257, 0x3f1b8b27, 0x5bcdfdf1, 0xe5beb987, + 0xbef2007b, 0x1ddb136c, 0x4e655ecf, 0x5c77e261, 0xb69bc6b2, 0x0f072e35, 0x0b07af7e, 0x9ae2c8e8, 0x3d3b4eca, + 0xb6a7cc8b, 0xc5bbec8c, 0x6accf60f, 0x8d7b83cd, 0x3aaae87a, 0x4b2f7395, 0x810d3bfd, 0xda696757, 0xad83e14f, + 0x2b3b53a4, 0xc7ea6826, 0x7f302345, 0xf96b26b0, 0x248f31b6, 0xa123b862, 0x84fddb94, 0xb3358aa6, 0xa8f0869f, + 0x210748dd, 0xd4f79dff, 0xb0a4c6d6, 0x7c0b35da, 0xbcdaf581, 0x87474c19, 0x5ebf9d72, 0xbc000aa6, 0x400ac893, + 0x50d15c7b, 0x0143ccb2, 0x166b10fe, 0x827551a3, 0xb3c15f13, 0xcce5a682, 0x0d92d62b, 0x3729b954, 0x2d43b889, + 0x16b861a9, 0xbcafb74c, 0x00878539, 0xf91e05f4, 0xa5d4cd03, 0x692f8c2a, 0x16b3d269, 0x6d9c3da3, 0xfc338b66, + 0xc3565e42, 0x284a5478, 0x49612030, 0x63a53da0, 0xb2bad495, 0xa9e659a3, 0xa3e52cee, 0x4a8b939d, 0xae968b42, + 0xcf35db73, 0xcb14821a, 0xb3736379, 0xb5bff609, 0xf6d0ea6f, 0x1dc87117, 0x12f3db9c, 0x4c6f648b, 0x0f393967, + 0xfabb69a0, 0x9e4adac4, 0xc4be3cb0, 0x984d9e53, 0xe968c46f, 0x09e8f99e, 0x04c443d3, 0x5b3c06ff, 0xcff85230, + 0xf8010daa, 0x6385586a, 0x98f24e07, 0x4fbd34cb, 0xcda68214, 0x11f1fc7c, 0x24929ef9, 0xe4ab68e5, 0x1c5fd5b7, + 0xf8ccc135, 0x34eef45b, 0xac9c400d, 0xd21f4811, 0x70b5cab5, 0xb1c8b0b9, 0x8b1387e7, 0x9bf80f7a, 0x1e0b5d1e, + 0x248499c5, 0x95295c06, 0x500a741e, 0x988b91b7, 0x290fdb1d, 0xec9fff42, 0xe86d8884, 0xb9e2be14, 0xe4c22f15, + 0x7851c2de, 0xd6c9a4c1, 0xb6df072b, 0x6ad5d7cd, 0xc63f1a47, 0xbfc9a1ed, 0xa931c270, 0xe9c6583b, 0x4529ce0f, + 0x8038c215, 0x11a856ef, 0x2756e110, 0xcbd1c98f, 0xb112f41f, 0x116005f8, 0x26d17fa7, 0x9fe576bf, 0x399fe4a0, + 0x4e970c66, 0x4d2c8b07, 0x369d55fd, 0xaf70fdc3, 0xd433027b, 0x3f3c4eac, 0x6ba17dbb, 0x19282132, 0xd079ede0, + 0xd8db9846, 0x66cf04f8, 0xf4a3b9d0, 0x03c88710, 0x906ee49b, 0x54205124, 0x1d8ea89c, 0x9bb9d3cb, 0x0e6da352, + 0x826a5e9d, 0xe98df8a9, 0x8368f72b, 0x3e7a49ad, 0xa6f57ec3, 0x908e9079, 0xd79a56d1, 0x72e83eaa, 0x218f32ce, + 0x0cc4ee0a, 0x5431d0db, 0x4da61407, 0x15ddb2a9, 0x39e17c65, 0xc6b7df37, 0x55a5fa80, 0xb5000ab7, 0x6a66d078, + 0xab8571e1, 0x023d8fd9, 0x408f7bf1, 0xc43f362c, 0x8a7d1876, 0xcc789f51, 0xe057d54e, 0xde5b7017, 0x2fbb7425, + 0xaef41e9b, 0x39cd7eea, 0x59692040, 0x4680da61, 0xab7718bd, 0x870acf11, 0xd57772d6, 0x0a9b271a, 0xb611d9ee, + 0x9a0f8e00, 0x8c57ce66, 0xcfbe2a67, 0x01bdc994, 0x0b985b18, 0x9faedd3a, 0x813d23cd, 0xf0cdaed1, 0x6917e4db, + 0x374aea35, 0x69cdce9c, 0xc6421975, 0x3b33eebb, 0xd330ee72, 0xbd49c4e9, 0xb016c42e, 0x185cf3bf, 0x25a46be8, + 0xb60d0964, 0x4b70a46d, 0xd8351be0, 0x2cd48d86, 0x27a70317, 0xb5b2b847, 0xd88bb7a5, 0x409f6b22, 0xe60d9ad6, + 0xd35de432, 0x7243cdb9, 0x1ec5c045, 0x0e94de06, 0x90ecef9d, 0x384ef724, 0x93b2c038, 0x40f88cbc, 0xbcc04797, + 0xccc1ef80, 0x407b71b6, 0x43a63aaa, 0x97565952, 0xb8040175, 0x3185ec93, 0x76ebaa81, 0x6e6de154, 0x8a213a31, + 0x84014ad5, 0x34bb32af, 0x99c9272a, 0x38d46174, 0xee65d1d9, 0xa1cf4155, 0xaf0915a4, 0x835e29d7, 0xe3a0fe45, + 0x17a47f9b, 0x829305e7, 0xe9a9e039, 0x48f29201, 0x308b8ab6, 0xec41d6d4, 0x438b7302, 0x6ccd0c1e, 0x7991e7b5, + 0x8b6a38da, 0x681075bd, 0xe19e2d2e, 0x328a2d90, 0xba8ad464, 0x57dac61a, 0xcaad692b, 0xa0c36721, 0x232f9a60, + 0xff824832, 0x4649f901, 0xf9f13a50, 0x0fd637ad, 0x2369f57f, 0x1a5b08f1, 0x49bc6885, 0xe9146a23, 0x29267778, + 0xd979b7f8, 0x2e587bc6, 0x6c5184ff, 0x0f61332a, 0xf37269fc, 0x9835a6b0, 0xbb6dd061, 0xb1306ad0, 0x2e0c4469, + 0x4ebadb32, 0x154fd6ff, 0x7dd12abf, 0x040df46c, 0x20f4369e, 0x538e0983, 0x80e31113, 0x203b263f, 0x5c2003a0, + 0x288d41e8, 0xb86b4e13, 0xbe9a93f7, 0xfa29435b, 0x700bca38, 0xec7a6d3f, 0x8ca4266e, 0x35c26ffa, 0xd180883d, + 0x30c320be, 0x1576a482, 0xf01d4897, 0x1bd1819b, 0xa05c48e0, 0xa194452f, 0xdc2abd8b, 0x5ab40309, 0xd29a2210, + 0x0ec76c40, 0x2be4f5d5, 0xc465d2fc, 0x445c7324, 0xc20149b8, 0x7d8afd76, 0x9110b41b, 0x13ccac9d, 0xf32e2065, + 0x96488869, 0x8745b560, 0x012ebcd1, 0xce19730e, 0xb44cbfd2, 0xe57d6855, 0x04c2ca8c, 0x74f7cde6, 0x335e6a9f, + 0x68b728e1, 0x57ccfdf6, 0x0a49bf2b, 0x07dee2d8, 0xe80a4ecb, 0x7ca58de4, 0xf4808d3d, 0x54f9f276, 0xfac83b74, + 0x1edba2c7, 0xa7a999d0, 0xd506300c, 0x44e8c1d5, 0x3906b16c, 0x64007a9c, 0x35dc133d, 0x6b10d4ad, 0xbf0c209f, + 0xcd339f50, 0x8cc5a5c8, 0x3ca2c11a, 0x799186e0, 0x3d12b3eb, 0x422c9c2f, 0xdee90842, 0x30c4d23d, 0xe1b19691, + 0x55e1ce6b, 0x1577cec8, 0xe58e664e, 0x8b811012, 0x03a508a4, 0x7c207eb4, 0x2304b2a4, 0xc1e87e7a, 0x43066841, + 0x3a863bec, 0xe73ca3c7, 0x4bacfa61, 0x9849eae1, 0x5a8057c4, 0x3a3e8b95, 0xb226936e, 0xfba5a825, 0x0c3541b2, + 0x4c7ce5cc, 0x30f8b9c2, 0x2a4d7dfc, 0x8acb6929, 0x8fca3f25, 0xc3362a59, 0xcdbe4938, 0x473ee86a, 0xeffb0cfc, + 0x85edb845, 0x68dfe4f2, 0x3fe3ba7c, 0xd06580d7, 0x565d096a, 0x270a163d, 0x8c297414, 0x5309a416, 0xea669e73, + 0xfa4484d8, 0x1629a8b2, 0xb9101ffc, 0x071ad95c, 0x9a8eb614, 0x1221a51d, 0xe697c4c1, 0x363e25c1, 0xc028d65e, + 0xa68f5058, 0xf9d0f047, 0x7837cef3, 0x082e03e4, 0x83b49349, 0x118c9857, 0x7c2b3de1, 0x20a61874, 0x8150ab3c, + 0x95ea7ed5, 0x2ed253bb, 0x2c76e610, 0x18b9d8a2, 0x81551ea3, 0xc5f82347, 0xe4f98e22, 0x93cc5296, 0x99b04ecd, + 0x41da532a, 0x5b687d5e, 0xdb3a84ff, 0x8f768eaf, 0x597fa6dc, 0xe4868a81, 0x7112c1be, 0x46cf2867, 0xe25e90a2, + 0x2ebee85d, 0xcc76db3d, 0x4637c7a3, 0x3cddf9d7, 0xaeeac69a, 0x5465263f, 0xa10cfeee, 0x946f56f8, 0xc6d2f18e, + 0x66924eab, 0x1a76118b, 0xb06c1643, 0x39b5ed32, 0xed79af00, 0xff32fc08, 0x4157d419, 0x9e4d6708, 0xe56fd3ff, + 0x3b1aefbd, 0x3ded9cdb, 0x87357af6, 0x21699a88, 0xf3f2e8b2, 0x11057437, 0x3e8ef4ac, 0x347d37a6, 0xccb96b29, + 0xdd05867a, 0xe83705e6, 0x1e80c0a4, 0xc32fe340, 0x55b31153, 0x39ac32a5, 0xf7d65057, 0xc22ba08a, 0xe99ce135, + 0xb67afcfc, 0x34ec19fa, 0x32eb8ad2, 0xc85126d0, 0x297b8707, 0xe7faec14, 0x289e6364, 0x12a8cc3f, 0xc56a7d59, + 0xa0ccc1ec, 0x1fc5fe29, 0x62dd7dd4, 0x7a616a19, 0xd5a4e4ad, 0x31ab68c5, 0xf192ea07, 0x92a8bc4e, 0x4fa721e5, + 0x62e47033, 0x3281c1a7, 0x89611355, 0x3df379ae, 0xba97f34e, 0xd2ae1d06, 0x9c42913f, 0x3b660a52, 0xe5fc1020, + 0x8a73de25, 0x776028c1, 0x0ff812b9, 0xa1eadf33, 0x0ffcd673, 0x8b01cefb, 0x28153be2, 0xc496986a, 0x2e9de1d6, + 0x9c782b37, 0x610b2733, 0x1bd57ef5, 0xf32002a4, 0x718c7ff8, 0xcf362a12, 0xc9e382bb, 0x558fc05d, 0xcf1f2893, + 0x69b3ae3b, 0x54caff8d, 0x02b052d1, 0xd4f99f38, 0x5763ca83, 0x579eb029, 0x475f4299, 0x286e4ac1, 0x9303df2c, + 0x3caaf50f, 0xecf5a7cc, 0xfc4844ce, 0xadf53a42, 0x2c244a38, 0xbafc813a, 0x35be3868, 0x8b1c28cb, 0xcaf57bb1, + 0x2069a22d, 0x2655b007, 0x9f29801d, 0x0dfbc6d7, 0xbf118d8f, 0x96bd00e8, 0xf78fec56, 0x59ba6393, 0xc4efc803, + 0xebdb6dce, 0x10cd900f, 0x58cb795f, 0x7d31fc21, 0x8228ffc8, 0x7a932766, 0x5c2ed5dc, 0x83064aa3, 0xf3c7a176, + 0xe3add6d5, 0xcf10aa89, 0x53080f1e, 0x006bec56, 0x64cff00b, 0x3907b813, 0xacc57ae6, 0x03870780, 0xf09343e8, + 0xd6de7dc4, 0x6145c086, 0xc6a80a8f, 0xf6a0d15c, 0x016a407f, 0x7a0f769e, 0x4206b97c, 0xfee4e638, 0x2b8c78e3, + 0xe91dc5cd, 0x2c71071d, 0x2cc627d2, 0x4756c4f1, 0xf59d5fb9, 0x1f0f04f8, 0xe341f550, 0x1a40eee6, 0x3abc4b8d, + 0xcc533c0d, 0xac5513fa, 0x4597bf57, 0xfc1cefbc, 0x2ed80710, 0x2ff8a5a0, 0x434d0694, 0x90ed3612, 0x7503b346, + 0xf7c67b0a, 0x6d4ab8ec, 0x6cd1cf20, 0x22fa91e8, 0xf569dfbc, 0xcd356d10, 0x940a35d7, 0x061a2b9e, 0x09322bb0, + 0xd0676316, 0x08d09521, 0xa1421de4, 0xfcaddfaf, 0xf43de67a, 0x3b172206, 0x62e9067d, 0x3b0eed7d, 0xae22f97a, + 0xca07d8d3, 0xf6bb1a92, 0x8c231bac, 0xf3b90808, 0xde2af614, 0x367b30fd, 0x06ad6d1d, 0x11363f3b, 0x5261658e, + 0x05fb41b8, 0x49572a7f, 0xedc0bd2d, 0xb0a31df7, 0x1182f0aa, 0x12449eb3, 0x6476faaf, 0x053ca60b, 0xa3b6462f, + 0x8b342236, 0x0998b885, 0x7872984f, 0x57b78106, 0x288496ae, 0x62586e9b, 0xf4a3b890, 0xf6d82eb2, 0x0227736f, + 0xfed4ed1a, 0x55d152ad, 0x072495c5, 0x39182d8b, 0xac53c0a4, 0x3b085068, 0x37d50754, 0x6198c9b9, 0x2a112e76, + 0x20e48f31, 0x0c364621, 0xf65bfc45, 0x3a4e86f9, 0x1e607f49, 0xb0251673, 0x4d13ff61, 0xafc16772, 0xe33082e2, + 0x0c9aeed4, 0x0af29d2b, 0x759e4317, 0x6f5bbf0a, 0x34dab900, 0x24d1e2d6, 0xdbcfead8, 0xae4fda6c, 0x5fe63a89, + 0x7fcabbc5, 0xdc1813d2, 0xd1717d18, 0x663ed082, 0xc27678a7, 0x377eb1dc, 0x863effc2, 0x43119ab0, 0x20e3fde0, + 0xff777db1, 0x0028623f, 0x42ed2093, 0x9631e5ee, 0x4e3572dc, 0xe543ab52, 0xff59bc8b, 0xb95b474e, 0x58662b1a, + 0x30843ea2, 0x5ff6cd26, 0x9bc7058b, 0x60b01a2b, 0x4d1094b1, 0xb95b6d18, 0x551cc4e6, 0xbd97acab, 0x12c05b54, + 0xfb34b94c, 0x737c9a69, 0x240ec924, 0xc1d989f5, 0xd89763f8, 0xcc0be8ff, 0x1af261e4, 0x3a51cb33, 0x28f72af5, + 0xa804af74, 0x48b4f444, 0xe138ada4, 0xce2e8f21, 0x7c6404ad, 0x6404e4f2, 0xca505259, 0x65cba3c0, 0xd0b571d0, + 0xd0dbf73f, 0x1a36f13d, 0xa68bda48, 0x0d6f4c1b, 0xed8c8b23, 0x39f35d5e, 0x5ec846ae, 0xa2f82cde, 0x8e428694, + 0x6a9e659e, 0xc2b6d238, 0x31540da3, 0xd3710e18, 0xd0465b03, 0x3e7220ad, 0x5f2293bf, 0x2fe356c2, 0x8d1615f9, + 0x731a2afb, 0x409dd67e, 0xe69d0947, 0x5f9c868f, 0x0349682f, 0x7491308b, 0x1e54e885, 0xd84ca61e, 0x7c866937, + 0xfd6b5067, 0x131b1327, 0x3ecebc04, 0x46bd57fb, 0x742a812c, 0x6a06596f, 0x01fc0c18, 0x94439288, 0x382b17f6, + 0x6795e5cd, 0x454a6672, 0x5160f490, 0x95786b79, 0xa1a735e9, 0x4aeeb632, 0x2293dab1, 0x5cdaf2f7, 0x2136216c, + 0xe661af8b, 0x7ba07f7d, 0xa4a4b410, 0x862f4df0, 0x4b06a6c1, 0x3fac7afd, 0xa740595f, 0x96ec6f4c, 0xadde4bfd, + 0x94aa0a11, 0x75b3a58e, 0x8058e492, 0xfd4338f3, 0x3beceae9, 0x2d0b162b, 0x113577f8, 0x0adb0af8, 0x18718ca7, + 0xde85376d, 0x26ed8638, 0x63b19429, 0xf00bb882, 0x373ff788, 0x09650b54, 0x125c8439, 0xeed8eb70, 0xdff74f06, + 0x3b28ca65, 0xbcdaf317, 0xba57f064, 0xe7829a9c, 0xfe2ee336, 0xe19f590c, 0x6309def5, 0xd71abdb6, 0x8f6da67d, + 0x90dc6233, 0x9e9d8eea, 0x3db6003c, 0xbd97b631, 0x9154a830, 0xfce6664f, 0xf499c728, 0x2f336896, 0x12b14bef, + 0x1dcb235b, 0xe83c4330, 0x06468762, 0x5dc66295, 0x1f2246e8, 0x03fc06cf, 0xc947b9f5, 0x198af555, 0x4ac3d429, + 0xfdc4d775, 0x4163bfe8, 0xe146f772, 0xcd5cdf18, 0x347cc21d, 0xe28e9687, 0xeb1b388e, 0xc921fd50, 0xd06beee3, + 0xddbf21a7, 0x6fbd2ef6, 0x51e2de9f, 0x6194c52c, 0x129bc699, 0x71fecd80, 0x807b10b2, 0xfc963b1c, 0x064f974c, + 0x7bfe715e, 0xaf9f2dab, 0xe98695d9, 0x2aa55962, 0x0df0406a, 0x31c71e5a, 0x766c44b0, 0xe67acf6a, 0x9d33c3ec, + 0x2c9ee698, 0xb3a664fd, 0xa74d4bb0, 0x47812b60, 0xafe36335, 0x1406ae9f, 0x4ff6f3d4, 0x1dc17115, 0xd0cbe40d, + 0xce9827c0, 0x7c95bd76, 0xdeb9dddc, 0xbed73b16, 0x1f7c26e4, 0x5b56763d, 0x77d84055, 0xefa2a451, 0x4686472d, + 0x7bdb50d6, 0x975d669a, 0x295dfe99, 0x635abec0, 0xb448f12a, 0xf3cb1bb0, 0x8e54b7a1, 0x4f10d51b, 0x8c565518, + 0xcbc7fc70, 0x09495e1b, 0x7a372650, 0x6b9e7ca9, 0xc7faa5e9, 0xde2f718f, 0xf75770dc, 0xdfe3ec15, 0xaf4357d9, + 0x85aa21ef, 0xc233168e, 0xa4cb2ab9, 0x17a1c3aa, 0xcc802e0a, 0x4b3cb21f, 0xc997b58c, 0xd4021fad, 0xe772a043, + 0xd66154e4, 0xc6e5e61e, 0x5c0a5a71, 0x4cf77457, 0x37b87fae, 0x6929a39c, 0x81b60032, 0x92284cae, 0x2d0d8f8c, + 0xe55693df, 0x4b12ca53, 0x355837b5, 0x6672bad4, 0xa0253005, 0xb7a00b85, 0xe0e057be, 0x457add65, 0x18e5b0a8, + 0x18897be4, 0x8c303aa6, 0xabcf5507, 0x4f442517, 0x3274b171, 0xaeaa72da, 0xc753c89d, 0x3b441c8a, 0xf4b12f03, + 0x243bd283, 0x2e3b866b, 0xd66f4c96, 0x3d809707, 0x9dec1c03, 0xe172462f, 0x20fc42be, 0x5965ed49, 0x3eead662, + 0x4ff2e71d, 0xdd2589c1, 0x6caaf15a, 0x29de82ce, 0xfaf39cea, 0xdff529d3, 0x07c39669, 0x751bff55, 0xbd41eb87, + 0x1d619862, 0xb491134d, 0xd77878b0, 0x8b8c0272, 0xb29d9ddc, 0x63d2b202, 0x5b7662dd, 0xef8cdde6, 0xaa89bd0c, + 0x1f6174f8, 0x360eb651, 0xdaca5a97, 0x34070af7, 0x909cd14e, 0x0c44d130, 0xe4bdf0a7, 0xacc755be, 0xdcb715d7, + 0x656ae7ca, 0xc14fc18a, 0x34d4e587, 0x2d39babd, 0x125105d1, 0x628f9783, 0xe11e53e2, 0x081772bf, 0x358e0d58, + 0x25500070, 0xaa49d068, 0xb385f332, 0xeb60e94c, 0xebbdcf7f, 0xd331a54c, 0xeb4c1fdb, 0x36973e16, 0xbd47d5ca, + 0x202b3f34, 0xec4087ba, 0x83d941d4, 0x184a2799, 0x616b2444, 0xf1b5b82b, 0x340df970, 0x95fee12b, 0x83da34bd, + 0xa7f90e42, 0xfeaabe2b, 0xd804b008, 0xef69914d, 0xcd6a62c4, 0x9cd9c407, 0x579a6693, 0xc19c4888, 0x013985cf, + 0xb07ca38d, 0x8c5510d8, 0x71893480, 0xbaea765e, 0xbc430845, 0xbbce571d, 0x9fd00588, 0xb196a52e, 0xb2bb0789, + 0x57f4f8e6, 0xc7bbbe33, 0x179f6ce9, 0x37722a40, 0xb90d259c, 0x4decb683, 0xc046e11e, 0x7033425a, 0x211229ad, + 0x07b44701, 0x391d59a4, 0x03d58ca0, 0x0f3ff585, 0xa6306451, 0x39cb441b, 0x3139ad3c, 0x9f0ae5f5, 0x03284d2e, + 0x0fb0618d, 0xbffda993, 0xd98f8e46, 0xc71aeb1a, 0xcbb71f2c, 0x24908d55, 0x9c27960c, 0x2260e780, 0x1838337c, + 0xc9fb39b1, 0x9831fe2e, 0x9cdb63cd, 0x33fae5fc, 0xf7c41680, 0x8273d530, 0x33fff45f, 0xed58f931, 0x25481554, + 0xf4a7ece2, 0x29e6ecb2, 0xab813c7b, 0xa2545843, 0x7162963e, 0xeb7a7989, 0xd970ee5b, 0xb3c35bba, 0x9cc5d15d, + 0x7ab127c4, 0x92ee6c09, 0x9b8783bc, 0xba017597, 0xb23c0e9a, 0xf0b9fbd2, 0x8c1237d8, 0x56cdd85b, 0x17000f74, + 0xbf3e4adb, 0x16b878d9, 0xfcca6b68, 0x0dbfa5f4, 0xf0aadac9, 0x782e7916, 0x8e95c3d9, 0xa8e56468, 0xed1bf8f0, + 0xec4964ce, 0x89fc1312, 0x71e3305e, 0xd22a0b33, 0xf7f3e660, 0xb15f6b2c, 0x406ed171, 0x2416cba8, 0x8eb25a38, + 0xc7af659b, 0xe536ad35, 0xef86a60c, 0x094d9266, 0x1785ca00, 0x7916c20e, 0x66ba492a, 0xfea4e293, 0x6e3e23d2, + 0x7d33c50f, 0x78a1a2a1, 0x9f4dc9bb, 0x8674655d, 0xc9bc9e96, 0x6fcdf134, 0xd09e6154, 0x27d8d131, 0xa38f9ade, + 0xddc5b3e1, 0x737533ef, 0x5e9bb682, 0x4609252b, 0x5da285a7, 0x52ccb8d3, 0x4782f094, 0xe861a034, 0x584cdcae, + 0x41d2d93a, 0xc536004b, 0xfe645255, 0xc5b9c374, 0xdfcf5b38, 0x0ea894a4, 0xe1022c38, 0x63f49e24, 0x088cd129, + 0x77160107, 0x53d4c9c2, 0xb2e0696f, 0x30e1227d, 0x87ab586e, 0xb2ae6b57, 0x8aaccce6, 0xdcca89fb, 0xead70648, + 0xdda42cd3, 0x9c36f9e9, 0x6d3319d8, 0xad363a5d, 0x430390de, 0x6a6833eb, 0x34dad49c, 0x19d2835b, 0xc4cf7bc8, + 0x0a6b3c52, 0x36dc5d3f, 0xe5bf67ce, 0x32c207c5, 0xbde15e66, 0x65efe0ca, 0x8ab43a7b, 0xb5ebd974, 0xd51ac9be, + 0x3e58e093, 0xd3fa9af3, 0xb3a460ed, 0x7f2f6895, 0x35dbfedf, 0x58e0cead, 0xd64e5740, 0x6236f15e, 0x25ca9d9d, + 0x1d0e85cb, 0x47f9a378, 0x14363967, 0xd02a7bde, 0xefc97955, 0x6771c77d, 0x4927c336, 0x5aa6400e, 0xc5569589, + 0x97341e91, 0x456cc899, 0xf0e6de28, 0x0d89b096, 0x0c918672, 0x01278cf1, 0x8fedda8d, 0x29eb408c, 0x1428a9a4, + 0x58cd68ba, 0xcc4154d5, 0xb0cf6d2c, 0x5f51567b, 0x4181cbad, 0xba52adc2, 0x4fb999e0, 0xb7128b62, 0x67e96cd9, + 0xc3f7fda2, 0xf9efb84d, 0x737bf62f, 0x75431e9d, 0xb78f9973, 0xbe5df21d, 0xfc9ac3b4, 0xcc9747b0, 0x019b28cb, + 0x0c2febca, 0x44e1fa9b, 0x8e6365cf, 0x6267e12a, 0xce5d8399, 0xd8c5fda6, 0x031026ad, 0x7469f9c0, 0x0f775309, + 0x2f6b072e, 0xe2367ef9, 0xca6583aa, 0xa3382c70, 0x5c169769, 0xc2e46b2a, 0x29876cbd, 0xdcc1dc20, 0xb0ae0281, + 0xad92569f, 0x33f15edc, 0x0112eaa8, 0xdd303a18, 0x93c260d7, 0x7d9d6fe8, 0xcab45bc7, 0xe7f5ec7d, 0x428be6ff, + 0xb4096587, 0xbff0464d, 0xed41955e, 0x0348e8bc, 0x724b5a59, 0xae32908d, 0xf46f5816, 0x05cdf870, 0xeae11f7b, + 0x8790c62a, 0xb7e410c3, 0x39b27e40, 0x88d0f488, 0x1358882d, 0x94268e6e, 0xefac743e, 0x76d0c387, 0x9e9cf916, + 0x483d3fa7, 0x4c0d82e4, 0x1de48c35, 0x93145362, 0x8becae90, 0x19a57bef, 0x29761b3a, 0xe9659fdf, 0x95a59de3, + 0xf83f3f53, 0xe79d13bb, 0xa83ca0a9, 0x4f297740, 0x6bd03189, 0x6934bde1, 0x4c34b14a, 0x98d3a4fa, 0x68b70b07, + 0xcadccbc0, 0x102f0f2e, 0xe2708ec7, 0xf4134d2a, 0xe0b8a0ac, 0x91cf7bdb, 0x68e5425a, 0xa6a95fc3, 0x88e016d8, + 0x53759c68, 0xadacf24e, 0xbcbfa16a, 0x209862b0, 0xb7e899ad, 0x7fdb4580, 0x2487feb2, 0x672b7b2b, 0x611921b3, + 0x6d46e03e, 0xf11bdf27, 0x10d00545, 0x8636957e, 0xd9e9e6aa, 0xe0c67c59, 0x5b453af7, 0xfb932ef5, 0x4d5e9061, + 0x269626a3, 0xc4582cb5, 0xab663dcd, 0xf3960796, 0x750aebb6, 0x900d4f83, 0xc3081160, 0x879ef40a, 0x9442beb4, + 0xb8971e20, 0x3d49dc54, 0x9e3f7aac, 0x8175210d, 0x94102d47, 0x9e1d2641, 0x68ddd718, 0x2b34f3c4, 0xe2f11db7, + 0x807766a4, 0xd41d7baf, 0xad4f7232, 0x5eb35930, 0xb0d8a8ac, 0x35f2309c, 0xd0b21751, 0x4de8fe9d, 0x07b4d77a, + 0x5715872c, 0x292b9344, 0x5c43f3e6, 0x5a892e2f, 0xfe078066, 0xe0d69f46, 0xbd6b398b, 0x361dfe6a, 0x7bc1f835, + 0x8e0c8645, 0x6598b3a7, 0x5ead3fab, 0x833b96d8, 0x046cf015, 0x2e212073, 0x0bcff007, 0xadeb27b8, 0xe9e3fdba, + 0x052ad6a7, 0x09c90907, 0x31864b08, 0x01307a97, 0xb1ff7dbc, 0xee002e48, 0x49c37c1e, 0xb27838a2, 0xfce50f1c, + 0xf89efef1, 0x92a99aff, 0x3d99d407, 0x605cd85d, 0xc0ff40ef, 0x6fff0f32, 0xe6cf5ac0, 0x9024f11f, 0x21267226, + 0xe18da5c8, 0x673755f3, 0x4c96f00c, 0x84d5357c, 0xc1cadbfb, 0xcaf309ca, 0x421a8b74, 0x01424fd5, 0x496518ee, + 0xa7897adc, 0xdb157aea, 0x07c7455c, 0xfdd7c2ed, 0xedd0432f, 0xa817ff57, 0x341f50a0, 0x2d02cf20, 0xbb2be51e, + 0x264001e8, 0x5245af65, 0x1a2a501c, 0x8c6620f6, 0x5ce7e11b, 0x933513ff, 0x2ec272c9, 0xfbb21764, 0x1bf4c9ee, + 0xb45c490f, 0xe7db5dbc, 0x5c87fd28, 0x6f1e3231, 0xf8bc8592, 0x3b0832aa, 0xac110d5e, 0x85093b4c, 0x3251931e, + 0xf1edc1bf, 0x202d989b, 0xd70b0057, 0x783ea5d4, 0xd48e72ac, 0x4bd16278, 0xd11f46b7, 0x29319879, 0x24b97728, + 0xc8a67d00, 0x44eb2827, 0x35e9dfaa, 0xf89432d6, 0xa01d48ed, 0x0871b4e2, 0x666bc00f, 0x55b1cd44, 0x9f4c2598, + 0x8096071b, 0xdd4c15e5, 0xc90a68e8, 0x9756e0a9, 0xf9c0a5ff, 0x4e966857, 0xa82d1f66, 0x218adde1, 0x72cd4100, + 0x91407ef9, 0x2d541702, 0x455838b6, 0x7a392aa3, 0x692146be, 0x35c7a130, 0x31964ce3, 0x824741c4, 0xbc192666, + 0x692b1e3d, 0x20e2c83d, 0x0e27d84d, 0x293907d0, 0xacb00856, 0x5dd216eb, 0xc84fc648, 0x0dca82c6, 0x39608e85, + 0xf798047d, 0x1357f6d9, 0xc8f6043d, 0xcd33bee4, 0xdafe9073, 0x0137533c, 0xc2cf6abd, 0x0756198a, 0xe9e5cb17, + 0x735b20b6, 0x890b7d9d, 0xf3d78c6d, 0xc9e575f0, 0xd21d7a84, 0x4e1adb68, 0x342a8e64, 0x05c1c95e, 0x69985a6a, + 0x6a002541, 0x30200857, 0xe0ae8466, 0x1e041732, 0xc5b3b214, 0x0c2e150c, 0x60d0ad00, 0x4c811508, 0x7478208c, + 0xc918589b, 0x28765396, 0x3e9c9468, 0x6f6732c9, 0x8e90bb0f, 0x2e91c61d, 0x28717f81, 0xd63cce1b, 0x9bdcf4df, + 0x33412c18, 0x79a2d472, 0x921fc250, 0xb819f5da, 0xb00986f4, 0xfc2564e9, 0xf0780917, 0x394d61d9, 0x9a892233, + 0x6c953ffc, 0x86728403, 0xe89e57e4, 0xa106acb8, 0x1a79258a, 0xf0432a18, 0x9eb0907e, 0x2106fa2a, 0x191c9305, + 0x5a4fa66e, 0x75395ddd, 0x7f99ae45, 0x084f6a93, 0x74a24db9, 0xd4e01edb, 0xbd7daadb, 0xe7da056f, 0x41129f6f, + 0x1c3eb4e1, 0xd0f055e6, 0x9069314f, 0x0dbf213f, 0x5fbbcfb6, 0x5f1eced1, 0x4876ea55, 0x07fdcbc6, 0xe5383916, + 0x2c2d1fd7, 0xe2aef1bb, 0x8190d37f, 0xbcdce7d6, 0x00a976f0, 0xb174346a, 0x963be539, 0x4256f204, 0x495bd3f3, + 0x5087a5e0, 0xef708aa8, 0x51717e47, 0xdc9de9f2, 0xcb6c8fe5, 0x5f7cd291, 0xd7dfeb38, 0x3c40fc93, 0xd8b4f170, + 0x86558630, 0xb2587c4f, 0x4a0b74c9, 0x0e5cf03b, 0x2bc8327c, 0x6eaca967, 0x3fa37fcf, 0x533bbb8c, 0x93daca7c, + 0x664b4f30, 0xd3590683, 0xa1a97403, 0x49a931b6, 0xc0b0b5d3, 0x340534bb, 0xf70e56e7, 0xb83a9418, 0x89bfc942, + 0x84267173, 0x4381dc18, 0xce143ea6, 0xf477eee6, 0xde98864d, 0x4c6f86ad, 0x81c3ed55, 0x3d0858f7, 0x016d2822, + 0x170f0646, 0x927296c5, 0x88e61705, 0x2d7b663f, 0x2118db44, 0x67493438, 0x63d59723, 0x14177dc4, 0x7355fe59, + 0x977d6ec4, 0x0bc2bd99, 0xce489f64, 0x56a775a8, 0xf8e132a8, 0xb7a4caaf, 0xe9d8173c, 0x4391f5f8, 0xb2b45bfd, + 0xf18f8bc7, 0xd29c1a30, 0xa5de9f3f, 0x112c4765, 0x05c0c640, 0x6252f8da, 0x9d7b4586, 0xa011143d, 0xccc856e4, + 0xafe876a6, 0x8116f1f5, 0x604d27ca, 0x148d48f5, 0xd8ace825, 0x6d47bd79, 0x26301afe, 0x07694cf3, 0xebe9fa6d, + 0x51449dac, 0x20abc880, 0x51076415, 0xd914f268, 0x89a77e24, 0x282db2d1, 0x50775a53, 0xefc9295b, 0xfc006e7c, + 0xd09efd02, 0xe9844157, 0x9f292b46, 0x37cf6acd, 0x854b053e, 0xc6bbcbef, 0x90cc17bc, 0xf22f083e, 0x4f0d2de6, + 0x54897f42, 0x5cb0606e, 0x9c7b0dca, 0x06246ba2, 0xa789d528, 0xfb6a0f9a, 0xb026192b, 0x7c5672d9, 0x1412107c, + 0x6427c8b5, 0xf28fff76, 0x8310bf3f, 0xba60892c, 0x7f41f0c2, 0x2a3c5879, 0xe0ffbb77, 0xf085420d, 0x0dfd7758, + 0x8036a9b1, 0x222e8d70, 0x6adfb319, 0x25343542, 0x37350194, 0x02e91242, 0x3a721058, 0x628caef7, 0x6f183e93, + 0x693f2b28, 0x4f1e4c7d, 0xc202bcec, 0xd0c35567, 0xf7d2fc30, 0x03103eda, 0x5e351ef2, 0xfcc61f7a, 0x37997316, + 0x63cbeea4, 0x22651f8c, 0xc0029630, 0x69b12137, 0x757dbd0e, 0x9a5ded61, 0x5a9691d8, 0x8228dcfb, 0x80a5ae69, + 0x21e52dce, 0xd51c8fb0, 0x99fe99ad, 0x3abe6aab, 0xed817331, 0xa544babd, 0x7a643704, 0x9755ffe0, 0xe1fe8c5c, + 0x67bbfe8a, 0xe6e9f661, 0xf002e821, 0x665fa24b, 0x2be70fac, 0xde70e6e5, 0x27dd4a83, 0x8f68a7ca, 0xc79380f3, + 0x9784b11b, 0xea1929eb, 0xea8f8904, 0x76e65e75, 0xd2452bc5, 0x1e41844d, 0xd296a817, 0x997e471c, 0x124f17de, + 0xe4d39067, 0x6d0da84d, 0xb77f3bb6, 0x0d850896, 0xfccd509c, 0x731c142c, 0x0373480e, 0xc900d924, 0x64b5e04f, + 0x502430df, 0x519ff106, 0x153c3098, 0x1bca53e2, 0xef24e98c, 0xfb0dde1f, 0x6f4b5134, 0x3f430670, 0xd92d1d5a, + 0x80028e29, 0x768b6e0d, 0x2b8447c5, 0x30f80f04, 0x0a0c91af, 0x2c5745ba, 0xb9a815a2, 0x950adba1, 0x98a918da, + 0x8649a8c2, 0x64931aaa, 0xa6a85372, 0xaa5a840a, 0x2bc7797d, 0x8b89355d, 0x43baac76, 0x02f61bcd, 0xb464cee0, + 0x3fb937a4, 0x77aeac28, 0xa8e664c7, 0x9404e13d, 0xe8f6f828, 0x02b5eecc, 0x858b441e, 0x584d1fae, 0x3a5fd9be, + 0x6571040c, 0x02d934b2, 0x53e0cc9d, 0x5950c9e1, 0xeaf79e65, 0x78ace299, 0xa2ca10e5, 0xae47c23c, 0x8bdb6fc2, + 0x86087ebb, 0x40a56ed7, 0x780c97f3, 0xf2c02214, 0xf6a05799, 0xfd7a3ae5, 0x77dbba1b, 0x18e1b4d8, 0x69c9cc4c, + 0x3ac5563f, 0xacc6cdd2, 0x01333781, 0xeaf44520, 0xe1e2fd75, 0x53af1b28, 0xd96e542d, 0x5af3c7f7, 0x75af5813, + 0xa2c6fb26, 0xd159c7c6, 0x3ec7da81, 0x8f3d198f, 0xa3e7caa8, 0x055a8e57, 0xe4cef341, 0xb6f78619, 0xe06056df, + 0xebd1e0a6, 0xaefe5968, 0xff4d3527, 0x4b98b5b9, 0x3398a09f, 0x3fee1a9a, 0x0a3ae91f, 0xabc9f44d, 0x1e79db1f, + 0x3e92841b, 0x44a59456, 0xccdf288b, 0x8f6817ae, 0xb6504843, 0x5a4de9c8, 0x61b549ef, 0x79e7211a, 0x71cac469, + 0xc21c0bc1, 0x07603e9f, 0xfdbdc6f4, 0x88c439ed, 0xbe7b106c, 0x609b8a42, 0x70799f51, 0xb2abce0d, 0xc1ad5f0c, + 0xa7d927d4, 0xaf53a05b, 0xab3dc966, 0xfbee37b4, 0x4280ab5a, 0xb99bf2e8, 0xde681ccc, 0xdf4edf46, 0xf5e8b689, + 0x90e31d6b, 0x65efabf2, 0x53dbe713, 0xb2b3d9ec, 0xed68c776, 0x9ec89c56, 0x011c8c4a, 0x0dc2bd1a, 0x8497257e, + 0xd320aafe, 0x20877ccf, 0x77ca427e, 0x727e225c, 0xbd467853, 0xca98b9e1, 0xace6383b, 0xbfa12013, 0xc9e37acb, + 0x9d8db7f3, 0xa688bbe4, 0x289ed03c, 0x78b667c8, 0x9234e307, 0xc2eaec41, 0x1f644588, 0x0966e5c7, 0x01cfb4c3, + 0xbcaff2f2, 0xb60e977b, 0x720f138a, 0xf80553a6, 0xdb9bd5b7, 0x0f511c43, 0x9fe1a430, 0xb0dccdc0, 0x597d8654, + 0xaac1fe77, 0xa78b7ad7, 0xc41b667e, 0xf61cc144, 0x359032b7, 0x29e00d67, 0xb0de2463, 0x011d8b8a, 0xfc358cfe, + 0xfaefa8d5, 0x0cc7a01c, 0x82c1e02c, 0x011045c3, 0xb306fe21, 0x05ae18cf, 0x13a15936, 0xc27012c6, 0xfbcc90a3, + 0xd327b56d, 0xee9c1b7b, 0xc7320699, 0x8783f7e3, 0x349c7b2e, 0x921beab3, 0x534cc601, 0x1b083c02, 0xbf6bfe44, + 0xcae4f24b, 0xc7e9a627, 0xcb31ab2f, 0x2e83a166, 0x1ae41045, 0x24725a52, 0xc60b1110, 0x5f71adf5, 0x128925ec, + 0xa9c66386, 0xe7fa13ce, 0xb53f428a, 0x655d7a4f, 0x0c6173b6, 0x365ec73a, 0xbd1086fb, 0x37956cef, 0x1e1bb270, + 0x415b6b4f, 0x248313b4, 0xce6b8622, 0xc128b2c1, 0x18e2d614, 0xc735e670, 0x2a70951d, 0x291055c7, 0x04d69a88, + 0xa74d3a0f, 0xfc876164, 0x5ce91c64, 0x4ff05262, 0x2324b93d, 0xd0fdeed9, 0x129ff7e3, 0xee102119, 0xfb126e1e, + 0x1a6cb597, 0xe3c6f0cb, 0x6bd25677, 0x881da61d, 0xd851698e, 0x0154ca91, 0x4f83cde6, 0x4277f44c, 0x2e00eb9a, + 0xba4b5651, 0xd279bdca, 0xe90eb5e2, 0xd3822479, 0xadb3b7c0, 0xf3f42ad8, 0x358f8197, 0x2708bebc, 0x0539a67b, + 0x5a896c19, 0xe773aec3, 0x71f9bf9d, 0xb4cbe681, 0x6833f1cc, 0xc1f007f3, 0xc860fc68, 0xa0a99e8d, 0x8731236f, + 0xcf181813, 0x300262ff, 0xac49c2a5, 0xe1f932d8, 0xd05283fb, 0x388c0d68, 0x2e33a1ba, 0x29c3a076, 0xd1aaa96a, + 0xff2ca2ac, 0x21dc39c7, 0xce59d13e, 0x956973bf, 0x8256195c, 0xa1144be5, 0xaa1c843c, 0x2fe0547b, 0xe891abcc, + 0x656081d4, 0x4abdd773, 0xc1c4bf39, 0x288556c9, 0x2823ca88, 0x22a72353, 0xb780d4d4, 0x7ba9a0fc, 0x17b734be, + 0x41957305, 0x5282cade, 0xfc0d86c2, 0xaff47d1c, 0x23df2ca8, 0x4fdb569c, 0x19d8a6c4, 0xa0619fe7, 0xf0f0aa40, + 0xf16bb536, 0xdffb4b2d, 0x88d58090, 0x93dc0a50, 0xaf9e0d93, 0x2cbdfc15, 0xeabd0590, 0xddc12d18, 0x42ee6cb6, + 0x4187ebdb, 0x9be6cd04, 0xb52fcf3a, 0x55bfd61d, 0x9ea4cbd7, 0x8b9c30e5, 0x6efb76e7, 0xe0be58cd, 0x498d5936, + 0x1d245244, 0x5215b148, 0x1af15788, 0xe9e5cbfb, 0x8220b6d3, 0xa6e29fb8, 0xfe7e107e, 0xc33ae661, 0xb5c5f24f, + 0x56e43516, 0x958abcee, 0x9d7f897f, 0x964e86ae, 0xab2c4bc3, 0x70d44d08, 0x6de54913, 0x9381b093, 0xf8b69524, + 0xe841a0cf, 0xdb247df9, 0x218a69fe, 0x807df081, 0xdefd7063, 0xc73ab916, 0xcffc5177, 0x533c255a, 0xa65c30aa, + 0x4e371260, 0x3cf444e1, 0x89345e1f, 0x02cd9d1d, 0x18fd24fc, 0x73e446a5, 0xd1615ca9, 0xf91e0818, 0x6a9a902e, + 0xea4e2d7b, 0x2073fb34, 0x9f5581e7, 0xc2a5772a, 0x9b638f91, 0x40925ed4, 0xf8b0d84c, 0x6c3579b9, 0x1768b41b, + 0x1b122428, 0xa56f6d9f, 0xcd08760e, 0x04c52938, 0x2a8d18f4, 0xa0b3dd6a, 0x6bc9bca1, 0x525debaf, 0x92a63eda, + 0x013218a3, 0xea82b013, 0xf8b49e36, 0x290cfc86, 0x0ae7cbe0, 0x3e5072a6, 0x8707de8b, 0x3e8df2b6, 0x7b5d7519, + 0x294173ff, 0x00818523, 0x263dd965, 0xfcc35b37, 0x4bfaf809, 0x470b3428, 0x05e983da, 0x29fb32da, 0x02afb982, + 0xcd1db3e8, 0xce54d968, 0xe2df3033, 0x4f931ee5, 0x04889f3e, 0xeed48dfd, 0x3be330f3, 0x7318bd1b, 0x622178a5, + 0x94daaf8d, 0x0bcb6623, 0xf6de2fc7, 0x121b9732, 0xc7d46fa5, 0x143d4c46, 0xb8e5195b, 0x71b591ec, 0x0730791c, + 0xa4c3147c, 0xa76506d8, 0x1d2f020f, 0x66ad99b1, 0x734d2227, 0x15c089a3, 0x24a68f54, 0x10862888, 0x23e68c2c, + 0x7ea1fc57, 0x34aebf3d, 0x3c8ab663, 0x28353bf9, 0x30e20ec7, 0xbc36ecb4, 0x0eb01734, 0x011c862f, 0x6871c8c7, + 0xfcd1058d, 0xb80a89ac, 0x8b2fefe4, 0x2ecd24dd, 0x4de580a2, 0x4db692e3, 0xfeb2f2f1, 0x2bd0760b, 0xe22300f8, + 0x84ae169f, 0xcd7d376a, 0xbd4b7e29, 0x80dc474b, 0x1414b4b1, 0x3fd0a7f2, 0x76eef12d, 0x2f40360d, 0xf9d6682f, + 0x1a23384c, 0x7afd96bb, 0xdf7fe853, 0x0fc5c643, 0x44379d16, 0xe0210b83, 0x95268150, 0x0103f7f9, 0x514491fc, + 0x3a91de6a, 0xfa21756d, 0x71465618, 0x3da4298c, 0xff5940ea, 0x7d90411a, 0x29db3308, 0x115adabe, 0x950887b1, + 0x6000cf64, 0x1b90378f, 0xb4200167, 0xcac48d1b, 0x3d2fdbcd, 0x94b47476, 0x867fd6e4, 0xf42646cb, 0x12c76da1, + 0xbdfb08bc, 0xfdf8b2ac, 0xe8ee4dd9, 0xa25b8a9c, 0xf55b8dc0, 0x0d51fd7d, 0xda7ca3c9, 0xb3a18012, 0xdb0c9745, + 0xf9181575, 0xa199737e, 0x53ae10b1, 0xbd8f280c, 0x215727fd, 0x157f1221, 0xf95bc20b, 0xd41902b6, 0x23c5c4f5, + 0x859599ee, 0x521f7759, 0xec9fcf06, 0x88252245, 0xa6b25805, 0xb35f9e5f, 0x1bcb6ea5, 0xd90d397b, 0x230f8ad3, + 0x62955f00, 0xb55a8e73, 0x2ecffa31, 0x5405e920, 0xd1bf2d14, 0x0250eebd, 0x33fe8ca0, 0xfe647c57, 0xb6cdab55, + 0xb18e7a68, 0x7ed8d695, 0xcba4ef33, 0x42345768, 0x2f317fff, 0xfa89009f, 0x81b74fbd, 0xedf1a61d, 0x160505c6, + 0x12f317a6, 0x97182f54, 0x30b1d614, 0x9264b020, 0x18f7aa63, 0x46d0802d, 0x10604c0d, 0xcc58a4f2, 0x8b4cd18a, + 0xd5a9f445, 0x9e3c13a0, 0x1245d4c0, 0xf4930702, 0xac128c21, 0x6f005b3e, 0x5fba0701, 0xdd83ddb9, 0x9e19b893, + 0x841bccb8, 0x82f502af, 0x4baf7a60, 0xaae68651, 0xa9b71c06, 0x09556b2e, 0x1c1c0e9d, 0xa375c144, 0x2253ec3b, + 0x5e632f06, 0x40c4689c, 0x338e3c84, 0x2ef8ca8f, 0x5976efef, 0xde9501a4, 0x42adcf2f, 0x972d3d4c, 0x07c7b51b, + 0x447fbb21, 0x921cc0b1, 0xac677203, 0xcdb84ef0, 0xccc83980, 0x5de7d1fc, 0xf7e21217, 0x80a4bac2, 0x92e8bff6, + 0x508a28b8, 0x18ecae3c, 0x56f5ea90, 0xe576d5d7, 0x30b8756c, 0x825ba3a2, 0x8d41c211, 0x23a70390, 0x772eac90, + 0x7302ece4, 0xb107e15d, 0x00439141, 0xaaacf211, 0x750efd72, 0x14469dd4, 0x56ca636b, 0x568a0812, 0x3173a576, + 0xc7a820d3, 0x64ca6456, 0xa809f6a9, 0x3a3b8866, 0x5b44a9d4, 0xf134691e, 0x331a8ef3, 0xa6ce870e, 0x8ae6033b, + 0x4fd20fa6, 0x8fe5f8d7, 0x9e156c59, 0x2b2a46ec, 0x038923e7, 0xaeffe1f6, 0xf9427c7f, 0x0355480f, 0x622fa74f, + 0xea7a067b, 0xc8a9fa8f, 0xfd972d76, 0x41b09742, 0x006c4ef6, 0xbe7a62c8, 0x5c22c26e, 0x5420b35f, 0xdca0dd04, + 0x01c48cc9, 0x07c02bdc, 0xe2b5b663, 0x458c54e0, 0x7c4920b0, 0x664cf567, 0xb057b206, 0xd858fb92, 0x11823bb0, + 0x02120641, 0xcdec7f2f, 0x4f94c678, 0x503cd0a2, 0x37da406b, 0x99725139, 0x0e8acb88, 0x0829ea5f, 0xe19b0c1d, + 0xad0d4943, 0x3e428203, 0xc1f6865f, 0xffc55f26, 0xbc83f356, 0xa1d2f35d, 0xeffb424b, 0xb7403fcf, 0x41943110, + 0x84124223, 0xf7373789, 0x50aaec81, 0x7f557d24, 0x0e87a1d8, 0x00876c43, 0xc6b06c66, 0x9352b552, 0x4b7aba47, + 0x36bc0dc7, 0x0ad22711, 0xc0157d72, 0x97317abe, 0x2dc67db3, 0xfd2dacbb, 0x10a73a88, 0xa14d878e, 0x02a4e601, + 0xefe4aebd, 0xfa9aed7a, 0x046368f8, 0x05cef825, 0x4bc35875, 0x5b0cf0b4, 0x3d74a3eb, 0x4c50260c, 0x70d11e2b, + 0xf3ac2769, 0x771205d6, 0x5423a759, 0xee408527, 0x510a74ea, 0xe3576fa0, 0x7d9b22d0, 0x521fa6b7, 0x8b190a39, + 0x54a4f6cd, 0x7fd47f5a, 0x3dcaf87b, 0xcb826a08, 0xd9ea2c74, 0x9bcff212, 0x66209c02, 0x3ca35279, 0xfd110e8d, + 0xcb052f0c, 0x209c3ff6, 0x02df2353, 0xde1b5344, 0x4d9d727b, 0x8b4adc03, 0x23823823, 0x6ce44b75, 0x2ae79883, + 0xd8e0be65, 0x77279906, 0xaccfbe9d, 0xc579c01d, 0x8f85e1ce, 0x63e3eda3, 0xc5777f46, 0x97e1b86e, 0xfa0b52d4, + 0x3b287c6d, 0x8a1cf539, 0x6a8c05fd, 0x61dbe243, 0x2456f7c1, 0xa6c44e1a, 0x373f8fbe, 0xae10c9cb, 0x770ee5ad, + 0x801039ed, 0x617f4961, 0xdb26f0d5, 0x414532ce, 0xc23b729b, 0xb01a75dc, 0xad2f308b, 0x941c0262, 0x3c5cf2fb, + 0x27358e56, 0xf433684b, 0xa335d6e4, 0x474bde40, 0xf854af7d, 0x1476640a, 0x0a81d100, 0xbe1e36cc, 0x4bfec4d4, + 0xa0f6243b, 0xf714263a, 0xe2ac7511, 0xf07bea54, 0x74bbb0c7, 0x30059993, 0x794bd2c9, 0xa9ed6327, 0xff661744, + 0x4434d0fa, 0xfd0e6cce, 0xda878486, 0xc9d4b87d, 0x0a08bb73, 0x27eceddf, 0x566eb915, 0x003df7fd, 0x79e7e262, + 0x95c393c1, 0x800c3d39, 0x7dedffd3, 0x18bd9271, 0x08201684, 0x80e6dbb5, 0x0990c09c, 0xa1958621, 0xeca62547, + 0xd7655adb, 0x0b39bc04, 0x2e736c4e, 0xc3e82c71, 0x16bcf995, 0xbf4a04e6, 0xd1d4e107, 0x68481492, 0x1cf7e364, + 0xd73e3ff5, 0x0a05ebba, 0x448b67cc, 0x845d6b49, 0x10089b1f, 0xfd6b4701, 0x46710b58, 0x8cd3cf05, 0xa3d5d176, + 0x80198230, 0x5346a3ce, 0xeb7350aa, 0xb1fe8204, 0x23a8130f, 0xc2be4a75, 0xef42bf5e, 0xd4fc4182, 0x5209db48, + 0x66cf9c5e, 0xf0294fef, 0x92be4656, 0xddc66277, 0xe9380525, 0xe18d09dc, 0xf8554982, 0xc30afabd, 0x09dcedeb, + 0xceadcf57, 0xf03bd21d, 0x9233dda7, 0xdb434259, 0x28e18128, 0x3584dee2, 0x3efeac1d, 0x8d84ab2b, 0x38f72f3c, + 0x85640b58, 0x93963f5a, 0x318a89be, 0x485689ab, 0xd42c0d38, 0xc88243d7, 0xea89e21f, 0x97c6bfc2, 0xe2936fd9, + 0x9113d678, 0x7161ce84, 0xafb6a521, 0xa905bcdb, 0xa0425cda, 0xd0fb67b8, 0x05b29b85, 0x1ae2caa2, 0x2c99ae5a, + 0xb4de38ae, 0xee237c48, 0x78ceacc7, 0x86692753, 0xecbed965, 0x3606c5e6, 0x6b236a7d, 0x90a63d5d, 0xd6f0d62f, + 0x2aebdc80, 0x699de24e, 0xfb2cad31, 0x7dfee1db, 0x93686597, 0x9cfd83b8, 0x9cff68ed, 0xb3fa05ab, 0x1ef17b60, + 0x8c98a69d, 0x654f7099, 0x864ddff7, 0x597cf239, 0xc073488f, 0xbe6bfb15, 0x455a5d8f, 0x54687c1d, 0x004fd28b, + 0xe86f1db3, 0x36508a6f, 0x31625395, 0x3b68d165, 0x425929b4, 0x35cf9af7, 0xcf4da45f, 0xa2e04ff5, 0x670879d3, + 0x91386ad8, 0xe86f6194, 0x74d11b12, 0xa4fe6a89, 0x8ebd9148, 0xa21e54c7, 0x5c6cde0f, 0x0c22ce75, 0x00292cb0, + 0x1681c668, 0x90bbe949, 0xfb2cea09, 0x52d98427, 0xfca1a6cd, 0x96f5ead0, 0x4ec5b85c, 0x19387998, 0xdb0330ff, + 0x6db5f8b9, 0x1d2c50af, 0x97a5cad9, 0xaed85ab7, 0x40ec29f2, 0x87f204d6, 0xe9db0e72, 0xb82105d6, 0x364e2560, + 0x8cb00ac7, 0xac257304, 0xbbdbf41a, 0x3f1cf67f, 0x1a64e348, 0x5c103c43, 0x64f82d87, 0x2d03bb7e, 0x100a4cb1, + 0x97e3c15b, 0xdfd88440, 0xf29d79d9, 0xdab50a91, 0x9ce69c8b, 0x09c41ab9, 0xefd56dd4, 0x87a265bd, 0x14f21c23, + 0x03737848, 0x2d187afe, 0x119a7f9e, 0xaf3ac508, 0x2303defe, 0x10b3cfa4, 0x8cb32aea, 0x396c18ae, 0xfd458ddf, + 0xb2317c99, 0xf4d19e04, 0x008ac49d, 0x48be1a45, 0xf98994f6, 0xdfc959ce, 0x1e01c451, 0x5d82a6d7, 0xce3e2bf2, + 0x3f4c661f, 0xd867ec72, 0xa0ffe401, 0x707e2fa3, 0x219ba9d7, 0x5d905d40, 0xa7339a34, 0x2ddee5cb, 0x7e754326, + 0x0eed4d94, 0x6e23a39b, 0xd15206e9, 0xcf23c701, 0xfef3da21, 0x02798518, 0xcee4a705, 0x5f3f56c6, 0x5ea565cf, + 0x15a1b5a2, 0x091d17a2, 0x4602a96a, 0x3e97a52a, 0xb7cc9b9f, 0xbaa66c11, 0xa81c3b3a, 0x03ecde01, 0x2b07f314, + 0xfdeb851c, 0x270e1a02, 0xa6d1809a, 0xacf9bbc0, 0x91f4b7ea, 0xae77e401, 0xdb43856f, 0x4e308bdd, 0x4be8e9ce, + 0xea8a3823, 0xc66c45fe, 0xa37bd2fc, 0x8c32f9cb, 0x940975be, 0x933eb997, 0xda2283a9, 0xac8bf7b3, 0x8065cc22, + 0x8bb8b516, 0x7d23d5d8, 0x4c01d7d5, 0x4152e33b, 0xade06c04, 0xdfe6b431, 0x6ba3512b, 0x9778e185, 0x375d747b, + 0xf8fc7e1d, 0x4bd635f6, 0xb92cc22f, 0x3cc9186a, 0x3bb3394f, 0xc0cfe79d, 0xf63cdea9, 0x4f6714c6, 0x4179668c, + 0xc2c07e8d, 0x964f7da8, 0x0f3a6321, 0xb7631d08, 0x500e1f2a, 0xbf5c9c69, 0xb44072e5, 0x3a9e6cf2, 0x36d0398d, + 0x240b0d05, 0xb0b0f751, 0x4551ff08, 0x61ed0768, 0x79817c81, 0xf9ff5b03, 0x98290361, 0xe6a1600b, 0xf590ac8d, + 0x1885aac8, 0xa26bf023, 0x61195a74, 0xdce35e71, 0x0f6bd4a6, 0x56006460, 0x2d7f8ccf, 0x3867dcb4, 0x95ff8cf3, + 0x3f17d30c, 0x3287c5a9, 0x188614cf, 0x14da09a1, 0x3f5a5b21, 0x39e2774c, 0xcc342902, 0x5a9aa95b, 0x5395606b, + 0x70ec8e51, 0x893de54a, 0x38d09ccf, 0x150a756e, 0x4965a451, 0xc7ec15d1, 0xdf873d2e, 0xf7cdfdfd, 0xffe78612, + 0x8118178d, 0x72e09499, 0xb2cc19a2, 0xa72f07f6, 0x3bbaf065, 0x92e8e15d, 0x2d5e40e3, 0xe6606fa7, 0x393cb026, + 0xfe7a5584, 0x8d0c689c, 0x327678de, 0xafa37dec, 0xb289a4ca, 0xce69c61b, 0xa9612515, 0xa2ab2340, 0xf145cef0, + 0xcdf3d371, 0xa7491c7f, 0xeb8c20df, 0x6df9a621, 0xd4fa725a, 0xd0e65c6c, 0x8bcbe401, 0x0745e3b4, 0xe455529c, + 0x18b084b6, 0xb0f92125, 0xf92f45c0, 0xe6dda755, 0x6a7c0b21, 0x72256b45, 0xa57673c7, 0x6c479545, 0x0814f763, + 0x5d1a995a, 0x87f4f577, 0xced12561, 0xe6f3439f, 0x95db5f21, 0x93f3d79d, 0xc746ad25, 0x8c4cb79a, 0x2f685ae2, + 0x1da9285d, 0x7aebf81f, 0x92a0d758, 0x03c1bd90, 0xa2bf3f9e, 0xebae6ef6, 0x609e8c6d, 0x0585b0b0, 0xcef67b99, + 0xa97fc1b0, 0xae39f5ae, 0x39e97a09, 0x726bfe76, 0x6997809a, 0xf964ee11, 0x466881da, 0xe6ef105e, 0xbc1b7eea, + 0x6ea1fccf, 0xaff1e7fa, 0x86605e56, 0x4546a260, 0xdc6f4c56, 0x1f923234, 0xc707e95a, 0x82d3e9c3, 0xdad0db40, + 0xa2c12eda, 0x086a9635, 0x2c541a3a, 0x70cc3171, 0xb0dfb491, 0x852b8822, 0xa6f0fd37, 0x0ae36fcc, 0xcb113644, + 0x29efc703, 0x40774eac, 0xfdc089f7, 0x24a0b92f, 0x7bf0f227, 0xc1ffc748, 0x1fdf61fc, 0x4e338a6c, 0xc7f08555, + 0x9837ff02, 0xb7155e30, 0xca71b00b, 0xbc82cd62, 0x609df4d0, 0x32521753, 0xf45ea846, 0x82b8ce26, 0xad94c900, + 0xa86ebfcb, 0x63bf5ce2, 0x6daa9c27, 0xab3bbe4b, 0xc22f53b6, 0xd7147a1a, 0x06a899eb, 0x8159e157, 0x0097663b, + 0x780a98ae, 0xccfd3dc7, 0x717bffec, 0x5ea78a22, 0x9c9104bf, 0xc775e202, 0x235d4671, 0x913eec66, 0xa8002fea, + 0xf6120e96, 0x71ca09bb, 0x3c0740d6, 0x612f80c8, 0xacf0118b, 0xce15d620, 0xf0d83200, 0xf425882a, 0x3797287b, + 0x1aa5a7fe, 0xa112077a, 0xfc6515d2, 0x8e93569c, 0x3af7f8e6, 0xe3154d1a, 0x63ee2786, 0x4f8bf733, 0x90cc4099, + 0xb02da2de, 0xb3e84202, 0xfdd20f1f, 0x48e14045, 0xe0989933, 0xdbc7a639, 0x47531439, 0xa672ed67, 0x77eb4bab, + 0x8bcd2c05, 0xaafcd4d5, 0xb78f00fb, 0x36becccc, 0xb520fe7a, 0xc2279f95, 0x224e6997, 0x7792daf6, 0xf97d981d, + 0xab5bd3b4, 0xb45cf080, 0x366a5b52, 0x8b854ee2, 0xd2538717, 0x9d229577, 0x358b6ce3, 0x444efa48, 0xd48a93aa, + 0xe0269f2d, 0xcf23012b, 0x1cd59c47, 0x6bbea5dd, 0x5a6ec362, 0x656d2571, 0x366a07ab, 0x320cdba5, 0x656a7282, + 0x073eeb11, 0x48a660f6, 0x7e0b57ba, 0x62c1bab4, 0xaaad44e4, 0x246878af, 0xd23aa4b0, 0x5a01dfb2, 0xbbb8f835, + 0x78896756, 0x1fc3d1c5, 0xcc8382af, 0x2012a24c, 0xa10882f7, 0x2eb9efc7, 0xc44ce5b0, 0x3ab6dc5b, 0xab39fdfb, + 0xa936e058, 0x0813fb9e, 0xcb10de7c, 0x6540e291, 0xd2a1e3e5, 0x027895fe, 0xa78b235f, 0x00e4d740, 0x796d045b, + 0xa375cf25, 0xd6abed64, 0x9018baff, 0x81717289, 0xdd3ebbb8, 0x379edbaa, 0x86a9225a, 0xa40dc7fd, 0xa711d31d, + 0x1a0cfaff, 0x88605d2c, 0x034b0703, 0xa74dc484, 0xfc3812ca, 0xe73db579, 0xcaafd7e2, 0xd77d2fc3, 0xe70c61d0, + 0x9cf1eb0b, 0x2c753c5b, 0x78611ec8, 0x2a424b6a, 0x20cc6314, 0x791c9b00, 0x2f052bf2, 0xf2db55d1, 0x04972944, + 0x0d103a88, 0x7f892ebc, 0xaed765dd, 0x2c62dba9, 0xafea8b32, 0x09ab4500, 0x61d5b3ab, 0x5eb62fc1, 0xffdbf140, + 0xc8d5d944, 0xe277961d, 0x09cfb418, 0x5a575c66, 0x4d2b48a9, 0x52a8bd11, 0xb353cbb1, 0x4333b7ab, 0xaf70c2b9, + 0x0592962e, 0x8fe12b3e, 0xa6af107f, 0x02099542, 0x22b3ddab, 0x3d79449f, 0xc4ed90f1, 0x63a5b5ff, 0x9d8ed279, + 0x4cf3d7bb, 0x15348670, 0xaa6ebbaf, 0x3d8956b9, 0x8b8131af, 0x211105ac, 0x6a2bdc53, 0xb11f1e5a, 0x7dfd3ce0, + 0xc6e003c9, 0xe182d922, 0x2442ec9a, 0x9aa823c2, 0x98aca2cc, 0x09e40214, 0x322c437d, 0xc7ed2e75, 0xc42468f4, + 0x8e6a41ac, 0xd5ecf71b, 0xdc5f6ecb, 0xdac107a4, 0x55066996, 0x7ea6f323, 0x7f55759b, 0x9e853bc4, 0xecafffc4, + 0x07915e52, 0xc01778b3, 0x649dbe3a, 0xe2f236a4, 0xe424f50e, 0x8386b7eb, 0x0efed4d5, 0x8c239f10, 0xbca6487c, + 0x1bf245c8, 0xeb0d1f4d, 0xde9cf178, 0x6a5e81e4, 0x1433a643, 0x992bba6a, 0xf41248aa, 0x74bf8d07, 0xf55f71d1, + 0x2e84cc63, 0x657c1680, 0x5b136e96, 0xbab6baab, 0xb404a913, 0xa3346bae, 0x38637cc3, 0xe27db53a, 0x7b761780, + 0x37376734, 0x433db25e, 0x9ec204ab, 0xf08f51e7, 0xd424a7ff, 0x11bc598f, 0x728e54e2, 0x7c455655, 0xd6290876, + 0x3735f0b6, 0x302c5fe6, 0xcbe55f4b, 0x3b936159, 0x01c3be62, 0xf384f993, 0xad285e06, 0x2a6a1911, 0xffcdf3a0, + 0x6e892267, 0x5988a441, 0x6e89af75, 0x03f61b13, 0x1a356273, 0x255ab97a, 0xdd84d987, 0xaa16e018, 0xd4d444c0, + 0x985ae1e3, 0x4de10a6b, 0x15f01511, 0x51b91a04, 0x23828d26, 0x7d5c21d8, 0x4d484e33, 0xb242a90f, 0x3e305510, + 0x0cf1e25a, 0x23ea9b04, 0x783fca79, 0x798aa680, 0xe4102048, 0xb9343661, 0x517d1e02, 0x9476182f, 0x47821971, + 0x6556d318, 0x908abc4f, 0x742bfd06, 0xbed66f42, 0x87f5e247, 0x115c5bae, 0xa8adf301, 0xf29cb1f6, 0x9b019a48, + 0x65c4c28e, 0xfc590f3a, 0x8cbd4d2e, 0x50427f81, 0x345b24a9, 0xff9c06fa, 0x39d57de4, 0x2f54ae2e, 0xef2fad76, + 0x898edf99, 0x5015699b, 0x9211c0bc, 0x9a628e80, 0xf967e6fe, 0x5cec38e0, 0x87a03f6d, 0x0580edac, 0x7616afce, + 0x6ae32098, 0x644c7ac3, 0xcb5ef8be, 0x87b2beab, 0xb4807cfe, 0xfbb1ca8f, 0x8134dd24, 0xa64d0ddb, 0xf276bfc0, + 0x5bb930dc, 0x25125d02, 0x610abeb0, 0x5e453c2f, 0x35999f50, 0x43937efd, 0xdb6668f4, 0xf6995ca7, 0x179e2e19, + 0x8b90e05c, 0x8e06ffd1, 0xeca9886d, 0x43ec9b65, 0x32da7d72, 0x06ce9582, 0x18f8d630, 0x3d355da9, 0xe98a1062, + 0x6dd2f1cc, 0x5350d525, 0xbfae0293, 0xfb5cfa63, 0x3b8266d5, 0x1d736bc4, 0xb8cb9762, 0xb663b600, 0xf6876965, + 0x48fb7953, 0x7315b018, 0x0aed5a20, 0x8d11ac28, 0x20d229f1, 0x1b50f931, 0x0b8976c3, 0xeb353aee, 0xe58faa61, + 0xa54ae754, 0x1190f401, 0x0c4c6a84, 0xe2898f41, 0x34b46fc5, 0x66b7afde, 0xf506d355, 0xd71b8ba2, 0xf0c76640, + 0x9096fd3c, 0x5179df27, 0x8263559a, 0x6c47b6f6, 0x85898e19, 0xb43af08f, 0xdf0c8b58, 0x9b573323, 0xa8e09260, + 0xcffdc271, 0x77ac971a, 0x79515310, 0x9898633f, 0xf05c0d04, 0x4625a01d, 0x114916f3, 0x6c28d775, 0xf5fdacc4, + 0xbb516db3, 0x758b71e3, 0xa2266a33, 0x7b5cfef8, 0xa424f5e7, 0x12ddfdcb, 0x27b56926, 0x5c5135f4, 0xe130b0a3, + 0x3e36cd9d, 0x0115f6a4, 0x79714b41, 0x2280aadc, 0x43199abf, 0xdc7661f8, 0x804e6086, 0x321a28f1, 0xa4c104b7, + 0x8daeefe6, 0x402297a4, 0x63679138, 0x899f0bce, 0xa16927db, 0x29d2e0e8, 0x0b92c6d8, 0x6d05dc23, 0x28760fc1, + 0x56cc1ea2, 0xa9e4e299, 0xcb490a7a, 0x17f87b29, 0xbdc95ab7, 0x90c181f1, 0x38118d82, 0x8e775e7e, 0x6622a0eb, + 0x1ceb3b2c, 0x32eff46a, 0xb3dcf78e, 0xd920a3c2, 0xe89bc8bd, 0x612f10ca, 0x3326ed80, 0x53df3262, 0xae4f37d5, + 0x9ec7ab08, 0xd2d9d959, 0xdcc1d9bc, 0xf7a2db53, 0x32617834, 0xfa96f8af, 0xd3ae8656, 0x00f3a338, 0x75617dad, + 0x26961ef1, 0xe2e0f4ee, 0x7e9cf06f, 0x635ce2db, 0x0a1edd09, 0xbe343d0f, 0x65940bf8, 0x9bf3b317, 0x123a40ad, + 0xeccadf95, 0x96e0d9e9, 0x697c39c2, 0x93b77052, 0x6d738e0d, 0x9928356e, 0x7618f025, 0xc98efc2c, 0x1591509c, + 0x0ebc2f3e, 0x9d1696cc, 0x9c86b74e, 0x3469dbee, 0x196358e3, 0x1f933112, 0xe4a6d9ea, 0x25bcb5de, 0x33a832a2, + 0x6903fce0, 0x2b92ca14, 0x89e3777d, 0x925dac2c, 0xa96ef285, 0x36db3119, 0x7a8f05f4, 0x010e01b1, 0xdd9bcb76, + 0x0d116aa7, 0x4b5b7545, 0xd1b26e7f, 0x1f5fce21, 0x8a78cd3c, 0x1563791a, 0x63f5ce1a, 0x8a591f49, 0xb06e27a8, + 0x9a77d61c, 0x094c2919, 0x418a2d1a, 0x3458877f, 0xeb884310, 0x9057ba51, 0x13053e10, 0x488a0251, 0x18bbbd73, + 0x2235ef61, 0x02769f1c, 0xb2448abe, 0xbfbfcc1c, 0xbc185997, 0x08278690, 0x805b8c61, 0x8138cd07, 0xec771fa1, + 0x1992d971, 0xa60b583c, 0xfe705003, 0xf3742931, 0xf34f5b49, 0xa93d91f6, 0x51bc6a1b, 0xa8006d51, 0xe8ffad44, + 0x0b1aa8c3, 0xe3772eac, 0x79cd1083, 0x3c179d2b, 0x6b455d6e, 0xb8d4513a, 0xd09378e9, 0x47bc724e, 0x351bc17c, + 0x304bd69d, 0x83952b28, 0x1dcda188, 0xc17220a6, 0x356dd100, 0x304045da, 0xeeef9578, 0x54389780, 0x30dc2630, + 0xf62604c2, 0xf14b9d4f, 0xc4126ac2, 0xa335544a, 0x12d463bb, 0xa29143fd, 0xbd462018, 0x91fb781b, 0xfaaffde6, + 0x5e3b42b2, 0x7b82f72f, 0x54facba8, 0x31389eb8, 0xbb0dbfb4, 0x50488f42, 0xdcbf1940, 0xe29107ac, 0x8828359e, + 0x13b60fc0, 0xc2ae42e8, 0x4cbf6bb0, 0x9000c4d9, 0xea64ed89, 0xab2a20de, 0x5c96663a, 0xccf1ec02, 0x7c84823a, + 0x9d0e1b77, 0xf6774210, 0x4205bcb4, 0xf3b6ffa7, 0x41723aa0, 0x4794500d, 0x8869df64, 0x928e69f3, 0xeaaef0a8, + 0x73cc6430, 0x640e8080, 0x9659f786, 0x00cf92dc, 0xad60c6c8, 0x464dcf96, 0xeee5f93d, 0x9133b06a, 0x87d51d4e, + 0x9c5d1bf3, 0xd0b02794, 0xb57b0ba5, 0x690dabca, 0x3a19cef7, 0x099fecf7, 0xfcdc9966, 0x3c9feea2, 0xb6841ec6, + 0xacbae658, 0xcae22886, 0x7b742a07, 0xbc3fe698, 0x882542e1, 0x01d2cf5b, 0xc9af0f71, 0x281ec0e2, 0x9c018c6d, + 0x0f7cb447, 0x01719bc3, 0xd69e1ff3, 0xe40f57f5, 0x3f578c39, 0x4792a570, 0xe3e6bb58, 0x11a26816, 0x9b2625fe, + 0x051ed1c5, 0x666457fd, 0xed89fcd4, 0xedbe44e6, 0x354e9d35, 0x5736f92d, 0xae93d785, 0x1878fb25, 0xaf8df52b, + 0xbd3f5f19, 0xdaa89ae5, 0x9a52f399, 0xb4720630, 0x8d92de1e, 0xc4d17ae4, 0x070ce72e, 0xa3219988, 0xf6be5155, + 0x2dd46474, 0x36ac62b5, 0x52f24af4, 0x9f348a43, 0xf2fc45cf, 0xc3b6a848, 0x1a600452, 0x24154403, 0x4f548995, + 0x6a2200a6, 0xb9dd3226, 0x23e1cf13, 0x0979f3e8, 0x678249b4, 0x79ef4365, 0x1789f188, 0x06d9d54d, 0xb584ba60, + 0x1601d916, 0x46fd6ef2, 0x0f101472, 0x04e691ee, 0x8c1ade64, 0x3fe5dc72, 0x02d1c8ec, 0x927795a1, 0x6d025a24, + 0x1e49ccbf, 0xb639e3b6, 0x33753951, 0x5bbe693f, 0x576b5306, 0xa0d475bf, 0x56bf53d2, 0x3ce8a5df, 0x19f0f4c4, + 0x20fb9107, 0xc9d70527, 0x205212dd, 0xd56996ab, 0xfe9fb327, 0xbb942bd7, 0x62403ebf, 0xbd860689, 0x273922e2, + 0x7173a6f5, 0x10d93bd8, 0x25e49e93, 0x4f1bc9fc, 0x745b52b2, 0xdeea7ced, 0x5975ef15, 0x1a93f32f, 0x7f1f976c, + 0x3f7b9a71, 0x3ef5d328, 0x4dc5d2c6, 0x6535eb0a, 0x48208cdd, 0x63659523, 0x79fcb906, 0x055c2385, 0x847a2ef3, + 0xf48d4155, 0x7185badb, 0x3de92b89, 0x9703b89a, 0x6c585d32, 0x511b287e, 0xed44e1d7, 0xe6e49cc4, 0xb008a632, + 0xfed7375c, 0x6df07e84, 0x2f3a3864, 0x8c2fc2a6, 0xc85a034a, 0x7c1833d0, 0xfd8fc312, 0xc9f22632, 0x7366f32f, + 0x15ca844b, 0x7023fda4, 0xb4fa6d81, 0x54951699, 0xb36c821b, 0xf3f7fe73, 0x0f1d00da, 0xfc51eef8, 0x5e6ea7a3, + 0x3c2332c6, 0x67c9c699, 0x2d553812, 0x68fc1b25, 0x7d961e70, 0x3430c884, 0xf5351692, 0x0e7b16a0, 0xd94291d9, + 0x4b6fc03e, 0xec248e9c, 0xf880d639, 0x1a35b769, 0x816d4a7e, 0x481c7fb0, 0x43b9ec5b, 0x59c84c02, 0x54169006, + 0x74482b00, 0x4ab6a09a, 0x9abea288, 0x92b30b92, 0x663b3c6f, 0xcaf3c061, 0xd0a3a594, 0x51190b81, 0x75c65d6f, + 0x8790c443, 0x39aad886, 0xf68fb4f2, 0xcf357b08, 0xa899e1f1, 0x52c666db, 0x5818768c, 0x838c6941, 0x1fb0abf3, + 0xc8a313a6, 0x726f36b9, 0x5b0acb99, 0x80614bf2, 0xdbd9fba4, 0x3b881fb6, 0x710f4600, 0x44a19a92, 0x82177050, + 0xddfc6ab4, 0xd21871cb, 0xcc37708b, 0x830c1d1f, 0xa8b1b795, 0xa97a9d4d, 0x580d489a, 0x7ec85be9, 0x0bf01bce, + 0x6344715f, 0x90cf346d, 0xb8f79129, 0xb3586000, 0xf1998292, 0x3b4193f4, 0xa0385108, 0x083f4f8d, 0x3ce61913, + 0xaeac5793, 0xbd84d19f, 0x59ee2235, 0xcbd21928, 0x05f55e86, 0xaa7e3fe6, 0x594b3943, 0x12a5fae2, 0xd96ce437, + 0x20306abc, 0xc6291222, 0xafec3644, 0x15f2848e, 0xde08874e, 0x46689581, 0x7d15d155, 0xbd10fa4b, 0xa2fcef6d, + 0x35ff4bfb, 0xeffcb175, 0xf1e76a37, 0xdaf7ff5b, 0x04cd8bed, 0x7834ba69, 0xca235e2c, 0xa72bc317, 0x95e1d740, + 0xaff879fa, 0xc4c087e9, 0x51e53859, 0x719646cf, 0x8cfcf904, 0x3b2e82e4, 0xd5c04ef7, 0x7e673e22, 0xb711b339, + 0xc64d583c, 0xdad64bb6, 0x8bc7f36c, 0xb013156b, 0x0b019718, 0x389e6326, 0xccd44ef0, 0x106dce57, 0xfdd31d23, + 0x2edadbd0, 0xc9a7907d, 0x7c694cac, 0xf3eb14eb, 0xd28b9349, 0xd7ecd5e1, 0x71f4b475, 0x343b076d, 0x500a3146, + 0x5c2c4972, 0xb1ae3cbf, 0x7db22cd2, 0xbe229fdf, 0xf7b6e8ab, 0x8bac7950, 0x3ab56ade, 0xb4f871af, 0xb1aeac9e, + 0x740511f8, 0x0a38859e, 0x575f9320, 0xdba01df7, 0x0c6420a7, 0x3669263d, 0x61651b78, 0xca40079f, 0xc0905d3f, + 0xe8aea396, 0x505bf93e, 0x7cd0e531, 0xad19607d, 0x0772e868, 0x7fcdfea4, 0xa97ae234, 0x07b19543, 0x45985aa6, + 0x609c7284, 0x45df9904, 0x9f9e75e2, 0x3afcdc5a, 0x6f56dd9c, 0x4268ad28, 0x2b19010f, 0xd7f2918f, 0x70a6252c, + 0xbbf94e7a, 0x11dead9d, 0x20e898b7, 0x41e391b1, 0xec1c5d7b, 0xd66f2f14, 0xc9e1cddc, 0x4fc8499e, 0x4c0d7789, + 0x6cf86f20, 0xa9a904c8, 0x963b14ae, 0x3058bde2, 0xa2303034, 0x7ae4c5c9, 0x965e7f6f, 0xd83632f0, 0xcc1b3826, + 0xb80e8b40, 0xbb52ed67, 0x80bcae69, 0x88c2a48b, 0x2c563abd, 0x0b97b0d5, 0x7e5e2039, 0xb82eda56, 0x885b7048, + 0x4efa48ef, 0x1ee18169, 0xdc71f99d, 0xf07050c3, 0x1ce76a9d, 0x4aba6bef, 0xa0aa6810, 0x38bf6263, 0x211b6c6a, + 0xa91d87c2, 0x7abc59ed, 0x755e8010, 0xe166ceb1, 0x642d3ad9, 0xd5e21ac4, 0x3f26a91d, 0x142b9e81, 0x51ab63e1, + 0x8e7e699a, 0xd44046aa, 0x8d0a2503, 0x83267faa, 0x0efa5563, 0x72462b46, 0x7f112709, 0xfb147242, 0x0596b5c5, + 0xc01b0121, 0x75731b89, 0xceecf6d6, 0xae585d5e, 0x7950d036, 0x37d059c5, 0x83d46c4e, 0xf3767fc0, 0xb6a3a96d, + 0x9588f33b, 0x5ed33c59, 0x21c6a9e7, 0x474a3d70, 0x16553843, 0x205bfcf6, 0x1625d407, 0x6ab213aa, 0xcf91d1b4, + 0x5ce5d818, 0x3412a089, 0x07772920, 0x225f0503, 0x8efd20fe, 0x91f4eb04, 0x40160022, 0xc7f03039, 0xcd652b9a, + 0xf9f2da20, 0xafc5b103, 0xedc58767, 0xcc0bb6a7, 0x684175de, 0x0ee39fba, 0x402d8f1d, 0xe462cc6e, 0xcfc744fb, + 0x6706e1b1, 0xbcafc907, 0x2ebc7cff, 0xa69ca2d0, 0x6f92afe8, 0x11c57750, 0xbadc6198, 0x46c50464, 0x9dec1108, + 0x5acaa0da, 0x1a932d68, 0x1359c0c5, 0x8472d726, 0xc5fb3574, 0xe15f9a79, 0x0771c6e1, 0xaf08798f, 0x3bc20121, + 0x6672f49c, 0xe6aceb2b, 0x731e0e43, 0xd3c0f326, 0xe2bed527, 0xc4f1f1a6, 0x2c9c9da4, 0x4bbcc64e, 0xa52317e5, + 0x0743073a, 0x243c6b1c, 0x17cff7cf, 0x1818e134, 0x285fabec, 0x41897066, 0x5996184e, 0xd5f1e08d, 0x1db8dd3c, + 0x479e39b4, 0x3a3c9409, 0xcc826276, 0x376eaa50, 0x2de0becf, 0x36454e8b, 0x7e812052, 0x3db38541, 0xc06c9fb2, + 0x661e2f15, 0xab095ddd, 0x27aad1d4, 0xe28cbf77, 0x69e8cf67, 0xb9d6c37c, 0x3692abe8, 0x20987b30, 0x36787db2, + 0x0badcf80, 0x3f540f27, 0xd3520996, 0x13b001d3, 0x1cda30c2, 0x508ba6e6, 0x3601500a, 0x911a159a, 0x9e9e92aa, + 0x43f0ce8f, 0xfd643bd6, 0xd08370c2, 0x11dff337, 0xa417672d, 0x1c491d21, 0xa02ac4ba, 0x29ef57f6, 0x98cae7cd, + 0x228786d5, 0x3f5a9e2e, 0x992439a0, 0xad570a43, 0x0c229abf, 0x784acd78, 0xb4abc544, 0x6f62a661, 0x5ebf72fe, + 0x944f84e4, 0xe1f7f822, 0xf9e8ebec, 0xf37fb17f, 0x7e7aac49, 0x7c795239, 0xd461bc0d, 0x21708bc4, 0xecf368ae, + 0xc6470030, 0x302d9253, 0x4bf35003, 0xb0d4c1e6, 0xd3ecc0d2, 0x4bde12ef, 0x6fef9d8a, 0x5b13943c, 0xf768328e, + 0x62bb8d4e, 0xe969a35d, 0x747d031e, 0x7ebc8678, 0x7285f1f5, 0xcdcb8bae, 0xa31e76bb, 0x2b9256b5, 0xdd747e77, + 0x2ad66982, 0x6d15756f, 0xded9dec5, 0x59772fdc, 0xf2729c18, 0xc0a05b44, 0xe99b49df, 0x3504478e, 0x932f9153, + 0x1645ba5a, 0xbf022040, 0x42e2f68b, 0xaec4d10a, 0x6ec449d7, 0x35607fef, 0x0bf1b6ca, 0x4aabd52c, 0x61959145, + 0x7da362f1, 0x0bf491b4, 0xc273853e, 0xfd176322, 0xdcc85724, 0x0d8a51b8, 0xb422a3e6, 0xe1ab3dbf, 0x71e8f5c3, + 0x96541f82, 0x98e970a7, 0x9bd9f187, 0x65a64a86, 0xb05eda61, 0xe4affb34, 0xd74a88fe, 0xc416bcd3, 0x37f88f75, + 0xa5b2e6ee, 0xf952e4a4, 0x53f84a41, 0xd72eba5d, 0x13d4a1d9, 0x7da9f1fa, 0x9c6adaf2, 0xab843e85, 0x5d21fb2a, + 0x9c1b6722, 0xab2a0a78, 0x4c4e5f18, 0x237e521e, 0xa3b3789a, 0x798affec, 0x30bd3056, 0xde087ec9, 0x52381d8c, + 0x025d709b, 0x11fae899, 0xfa77b8ec, 0x99d980ae, 0x9fdceb18, 0x739b1c0d, 0x94d6a02e, 0xd32135f8, 0x599f4912, + 0x23b635a9, 0x6cc8b714, 0x37de8c3f, 0x1208bfce, 0x48b5663b, 0x39891bc5, 0x65956d01, 0x4bcc17b4, 0x2d4a0d5f, + 0xf2aac74f, 0xcbc4a207, 0x87c63441, 0xc39cf984, 0x20b08eed, 0xab20143d, 0xed812110, 0xb5d49b1b, 0xc62cc0f8, + 0x2364207e, 0x289c486d, 0x60ce78b9, 0xac62a873, 0x401740e2, 0x1b93a58b, 0xdb7dfad7, 0x1eb9a274, 0x3bdae903, + 0x57944836, 0xc0198b9c, 0x4fbf0b29, 0x937baec4, 0x67f3a7b8, 0xc0191176, 0xec517dbe, 0x6855c29b, 0x46c873e5, + 0x4019e21a, 0xe94eff4a, 0x501c5817, 0xc6e2a69e, 0x7102e39b, 0x659b7db1, 0x533a1657, 0xca2539fb, 0x582b56c7, + 0x5438deef, 0xd8fcca6e, 0x4e23c95f, 0x84727490, 0x214e63d8, 0xeb326bee, 0x3f8fd77e, 0x954f8638, 0xb72c7e78, + 0xde5a88bb, 0x74ace66e, 0x417120f5, 0x1841b3e4, 0x74b0f378, 0xe0967a94, 0xb9480e7e, 0xf7734be4, 0xe81bdc55, + 0x5d268dd4, 0x23acf5c4, 0x47ffce74, 0x6aaa5fe4, 0xdbbf4c79, 0x37d08cd0, 0xcf82b798, 0x80b8bf65, 0x83a71398, + 0x5beebdd2, 0xeede32ad, 0x613c9252, 0xf9dccf91, 0x467a91dd, 0x335765e8, 0x2799ee7b, 0xc3e59e40, 0xa813980b, + 0x6604bee2, 0x28b80ace, 0x1a2ea593, 0xdf4dfb74, 0x95d4e4b1, 0xe4247b97, 0x82e30e1d, 0x4d4b05aa, 0x87e7f3c5, + 0xc27d6916, 0x2a547e3d, 0x9429bfa2, 0x7d6d8c90, 0x028577db, 0x17afa724, 0x697ca8cc, 0x392f48f2, 0x746f2234, + 0x5deafb8e, 0xc8f9210d, 0x201068c0, 0x89996655, 0xc8b981e0, 0x052edcc3, 0x654e3c72, 0x8bb37712, 0xe56c2c53, + 0x6c8e2a7e, 0xc349bcaa, 0x9bdb4419, 0xaa2ab4f7, 0x0ae59ee6, 0xbb70677e, 0xe8ccfef0, 0xefcb9e99, 0x5f0595ac, + 0xadd97752, 0x4d41feb9, 0x58b0fdc5, 0x213f02d9, 0x206d3995, 0x099da887, 0x2fead869, 0x862aae3a, 0x9a454d83, + 0xf4b2dd33, 0x717189b0, 0xbbee4d9e, 0x3c56fc14, 0xad5ecc73, 0x627ca93a, 0x63ed0257, 0x9535e425, 0x013d35c2, + 0x9f139eab, 0x2014aa0d, 0xe7a92b2a, 0x4c5aadb9, 0x96360ad8, 0x31c21bb8, 0xf893f751, 0xec556ea6, 0xb799c6ec, + 0x3d6cba81, 0x7e91e1e3, 0x42b528a3, 0x871253d9, 0x1d1269e4, 0x5eae03e0, 0x7409318d, 0xbef4558f, 0xd9bad2da, + 0x427cc18e, 0x2e87462b, 0x189042ac, 0xaeb83f60, 0x3b20d49a, 0xc7a78b79, 0x37b42182, 0xe602385d, 0xe0fce276, + 0x05e8c5ca, 0x29a967be, 0xa8e41838, 0x55ed8422, 0xac487d6b, 0x383901d7, 0x699c3bd2, 0xea9d5a93, 0x682d0705, + 0x55aa1994, 0x9442a11d, 0x69013384, 0x0ca18525, 0xc8818867, 0x302939b2, 0xbd6abfc6, 0xc6bccbe4, 0x7d2693ce, + 0x6426c8d3, 0x211fc4cb, 0x6c6e7927, 0x4f034ba7, 0x206931e4, 0x915db94f, 0x29085286, 0xeb6bd586, 0x9e58395f, + 0xc839d9e6, 0x3b440974, 0xaaab0c68, 0x3d9582de, 0x3fe6551b, 0x5c19da0e, 0xd71550ce, 0x12b5c065, 0x6402e537, + 0x7bc59f9e, 0x243b7848, 0xabe9213c, 0xda79d4cb, 0x4239a929, 0x5459c118, 0x567d7995, 0xe028b890, 0x5d4adbc7, + 0xa134b6ef, 0xb68f8cef, 0xc6f26ca8, 0x868de3db, 0xb985622d, 0x6a84cdcc, 0x5495a07c, 0xb0b076e6, 0x8d46b9e6, + 0x54de225d, 0x9e6d7e44, 0x9ba013aa, 0x2c18d869, 0x40d842c8, 0x2fc982d7, 0xc233974d, 0xb824102b, 0xed51bce4, + 0x26e75d65, 0xb51c31cb, 0x6b7b3e09, 0x8ffce1e1, 0xffb63226, 0x432e90ac, 0x758d04ec, 0xd387fce4, 0x2bf1f502, + 0x7bb179ef, 0xed3c7a2c, 0x0ea22c15, 0x57917378, 0xcede819b, 0xc2dd0b29, 0x635d9a34, 0x371e27fa, 0x7fbef739, + 0xc413ca78, 0x6767e939, 0x2a877013, 0xc974358d, 0xa84ce18a, 0x6cae048d, 0xbf263a41, 0x44ad94a3, 0x8a01001f, + 0x322d9bfc, 0x52a24517, 0x800ab5ff, 0x07f2f9b5, 0x0b98d14d, 0x5943ddf0, 0x5a362c2b, 0x37801d49, 0x15727a3e, + 0x169f0a68, 0x294b97d0, 0xad723562, 0x48f78442, 0x65cf85ca, 0xa9840e1b, 0xa55700ff, 0x662d1ed8, 0x3ebe45ff, + 0xf81cf03c, 0x569dd75d, 0xa18d1684, 0xb7440099, 0x31ddfbb7, 0xdd0083bb, 0x1bc2dfc8, 0x57264ff2, 0xfc89eb9b, + 0x6c579fe7, 0xf4f97039, 0x1d869932, 0x88eaf042, 0xbe94f73f, 0xc36ff615, 0x523a0018, 0xe15c4556, 0x66dc9bd2, + 0x6e37cd00, 0x6cf0709a, 0x749c269f, 0xf810a8bc, 0x25236317, 0x3c6ba553, 0x587985b8, 0x0bd68744, 0x7bf652f4, + 0x0b7692d5, 0x78938867, 0x66b2aa82, 0xb3087bc0, 0x9d91b286, 0x7d041b3d, 0x6a6d2f3e, 0x9dd5e1c7, 0x4be73157, + 0x88d80066, 0x853c30ef, 0xe8c0e618, 0xce2d3053, 0xd1b4677b, 0xe3a7f5d8, 0x91904d24, 0xdfca5218, 0x8a1ca314, + 0x1f017a4f, 0xf65c8b58, 0x3b2c09c7, 0x9575870b, 0x41c4dc8f, 0xa93f67f5, 0x2cbd48b1, 0xd487d9b4, 0x270915d3, + 0x076db419, 0x5f73e529, 0x8b2db758, 0x351cf749, 0x164a37ab, 0x73429f9b, 0x094f2d93, 0x6d1b5bf7, 0x6fe71d57, + 0x3afcbc09, 0x43dc5a54, 0x1f08077a, 0x54463ce5, 0x386d65a5, 0xe86d66c8, 0x2c174af8, 0x2f774320, 0x6fe0e316, + 0x73848b81, 0x0c533bc4, 0x609a1152, 0xe3c0ff0e, 0x25650d15, 0x327fd344, 0x17b968cc, 0x8fc48f52, 0xca25cdf5, + 0x2507d627, 0xd1cfa36e, 0x2323a968, 0x1490d76c, 0x5e7ccfde, 0xa5412a82, 0xc0bc5426, 0xe6df1c38, 0xaaa1428a, + 0xe2b0adfd, 0x5385465d, 0x153e97ef, 0xc959e23d, 0x57c100c6, 0x14a017ab, 0x5007f45f, 0xd9c6423e, 0xf4ba6638, + 0xb110582f, 0x6e227f59, 0x9602dc69, 0xfdf5439a, 0x5e1d606f, 0xcb777537, 0x5f21ae82, 0x0cc23757, 0x96a20998, + 0x370c8fb7, 0xd1cd13ce, 0xa480142d, 0x45e9e951, 0xa6faab9f, 0xe0d16510, 0x798514be, 0xc085f119, 0x9b2a7dfc, + 0x76f4faa0, 0xb9e708ca, 0x32353df6, 0x9d860038, 0x2f0632d2, 0x3f0442e4, 0xdf33370a, 0xf7965555, 0x39ea89f5, + 0xc584c4e2, 0x821a97b2, 0x6d5c1ecc, 0xf766ba56, 0x5879756f, 0x19a46714, 0x21d3810e, 0xe2875443, 0xfe3d9a4c, + 0xec328311, 0x04305ed9, 0x26e95a0b, 0x14c782a6, 0x79a67967, 0x066b58f5, 0x6c458b04, 0xa526ab1f, 0x1705b65e, + 0x4cf7f66a, 0x37092e5b, 0x829a3ec6, 0xcf503b43, 0xe2127ff9, 0x238f5ff4, 0x8a322252, 0xd3275acb, 0xd46ecd69, + 0x14ca079e, 0x00591509, 0x9eb91961, 0xb018eaeb, 0x356d7b54, 0x49374894, 0x5a20626e, 0xb854935f, 0x1f4a78a9, + 0x00804c14, 0x84daa04b, 0x10366a1e, 0x7014a36c, 0xf1b9dace, 0xde1bc722, 0x85e0599d, 0x1a77c0dd, 0x5e137ff1, + 0x6f683173, 0x0573c7a1, 0x3b3e6f7a, 0x4631a9a2, 0x28f26c58, 0x49d0badb, 0xa588cfac, 0xa1afdc32, 0x929b70a4, + 0x848cda80, 0xe4f8cae9, 0xbb341f68, 0x6c57fd5f, 0xe55ad741, 0xe06e07d6, 0xff571080, 0x5949203a, 0x560fde2f, + 0xafd93a55, 0x3aae9240, 0xe33b0896, 0x19fd6ed2, 0xed67da2b, 0x0efcb876, 0x2681b93d, 0x2e076005, 0x7b899184, + 0xfb016639, 0x5fed272a, 0x8d563364, 0xac28fdab, 0x1e2b84a0, 0xe0f7c77e, 0x20817069, 0x2c1b9593, 0x21b8fdd3, + 0x57c6dd93, 0x99ee80a5, 0x5c469ffc, 0xc0cf2ee5, 0xf82b9946, 0x7eb4ef5a, 0x3b5343cf, 0x3b5694ec, 0x79d60bc6, + 0xe838be7f, 0xb2dcfd6e, 0x2fd858b1, 0x1d0edbf0, 0x871e6a1b, 0x01acf670, 0x4f6f7cc0, 0x14aded8c, 0x0a35fdb4, + 0x75a92517, 0x1f0d7748, 0xb1d6aa09, 0x6fcc5bb4, 0x3c8c0816, 0x0346dd48, 0x5d358bbd, 0x98f941ca, 0x4bf47c81, + 0xe273cae0, 0x0c506fe9, 0xa6bc6fac, 0x2dc89379, 0x814aa378, 0x121ae1c5, 0x386e193d, 0x3d661112, 0xc10de16e, + 0xa5ccb444, 0xd3c93ddd, 0xbae5b515, 0x83e84859, 0x5ccd6a43, 0x47bee70c, 0x02e39b0c, 0x1ebc91b9, 0x2b929b66, + 0xf80220dc, 0x0c98a6b1, 0x39712a4a, 0xaed6c0c8, 0xbf6b5835, 0xd945aecd, 0x22dc7936, 0x0bb39532, 0xa7c4f417, + 0x680dcaf8, 0xdbd6e080, 0x3d1f6b24, 0x8247b55f, 0x5faecc19, 0x1e4db5dd, 0xf0516fae, 0x35dbb87a, 0xa278c19b, + 0x7b40bcc6, 0xb5114467, 0xaad9471f, 0x8c5f6659, 0x80c1d2d9, 0x05c87407, 0x78a6277f, 0x382ebe86, 0x73130f8a, + 0xf0267d7d, 0xcfa53e1e, 0xf39de662, 0x53c62140, 0xaf5122e2, 0x16e4c9c0, 0xb474ee04, 0x187ca47c, 0x64db13bb, + 0xd169e337, 0x7c4416fe, 0xb392e124, 0xe8030869, 0xd30a0c4d, 0x481652ca, 0x253e53f0, 0x61788153, 0x372b1fb6, + 0x178500f1, 0xf26c9454, 0x98da5758, 0x3b03458c, 0x9fd45f99, 0x613058c6, 0x4902a753, 0x1d595ffa, 0xe569e5c8, + 0x7e392bd9, 0x49ce2b6a, 0xee451649, 0x2a26567d, 0xa5d7999f, 0x2017763f, 0xfa34480c, 0xc6662d0d, 0xc8fc99a7, + 0xd1190b59, 0x9180251f, 0x8ed974e2, 0x61dbf610, 0x02493da5, 0xc2a03aa2, 0x086141c9, 0x3d2511a0, 0xaf4e94ea, + 0x57bb57ba, 0x8605d882, 0x7046eb5f, 0x6299d16e, 0x398262a1, 0x57e29bc4, 0x5763223e, 0x674696c7, 0x0194ce94, + 0xbc6ac0c7, 0x3199b64c, 0xebc09eab, 0x6030b5af, 0xa4af2ce5, 0x0815541b, 0x4b3e740c, 0xbf2ed75c, 0xfe4daedd, + 0xd2da6267, 0x677cb319, 0xbb3e5b95, 0x2c890158, 0x12a53ae1, 0xe361895e, 0xec5f281a, 0x8c5b3f2a, 0x2dad7220, + 0xb751159f, 0x33e79c83, 0xc9e847ec, 0xc26d0b80, 0x7b7f4dd9, 0x16f3bf0e, 0x51654850, 0x6c652df9, 0x8dcda548, + 0xe859cdd4, 0x7d369457, 0xf3f247b3, 0xa5101412, 0x4e36913c, 0x4b773678, 0xe726a790, 0xaa43c13e, 0x2360ed21, + 0xc7f1c1cd, 0x5dabcd42, 0x7fdebd9b, 0x8d9c835d, 0xed1446aa, 0xf10a1d3a, 0x040e093c, 0x4ec165ba, 0x15b85294, + 0x2ec7c666, 0x6aea8e6b, 0x04021522, 0x55495e14, 0x54ae0f89, 0x6eac12fb, 0x31b2bcea, 0xda944e31, 0x4ff15beb, + 0xa4123154, 0xc0bf5da9, 0xadbe71a5, 0x59701523, 0x5ee26b40, 0x2312a0d7, 0x86cef943, 0xaa68f1a2, 0x7cfac0b1, + 0x185fbf82, 0x78a181da, 0x54f02aa0, 0x50d44cb5, 0x96ddfb6f, 0xe4e97274, 0x01a380a2, 0x25202661, 0x6a2e3760, + 0x8b42731f, 0x26663674, 0x9f9c0d53, 0xf67fcdf9, 0x92c6354c, 0x554aa412, 0xc030adfa, 0xa37c6c62, 0x382fa060, + 0xcb427fd6, 0xd39e856a, 0x0a058105, 0x1126faa7, 0x33868982, 0xe07adf0c, 0x6132a197, 0x9de2727b, 0xd6d2cabb, + 0xa24582e3, 0x9ecd0c43, 0x55ef286e, 0x56467e37, 0xb686b7f0, 0x0835580b, 0x49912acb, 0x97d4f718, 0x99e83025, + 0x5978ff6f, 0x0739eaaf, 0x50386d1f, 0x5850eb0b, 0xc587a004, 0x5f721c38, 0x7b48bd38, 0xd3bdf430, 0x590b8177, + 0xb2cb97ff, 0x4522bfae, 0x2ae00c32, 0x73913bcb, 0x660eabdd, 0x55f649d6, 0x65eb6e2f, 0xdef7b389, 0xdcd2877b, + 0x70439a05, 0x817e7fd8, 0x66d39eec, 0x6c7e811a, 0x16e6284f, 0x7c6513ec, 0xd388ece9, 0xdf02a0ff, 0x47fd0b77, + 0x618000b7, 0xd248617c, 0x07585708, 0x4a967650, 0x46f966b1, 0x8e085cb5, 0x1d8475bf, 0xc0f500cf, 0xc3f2038b, + 0x2f5d7046, 0x321d6215, 0x91c03333, 0xb15cf646, 0xe82ad923, 0x8cc96780, 0x80907d7e, 0x3bf9a6dd, 0x07854c8c, + 0x03bee3cc, 0x323816bd, 0xb064c688, 0x27a1e29a, 0xba0f6169, 0x0aecb9d4, 0xbe4b5b84, 0x16e09279, 0x47548874, + 0xe44d89ee, 0xc045b836, 0x371ebfb5, 0x83382dc4, 0x875fd321, 0x04d3b64a, 0xf6df8195, 0x8711c2d5, 0x2f800b7c, + 0xc0ea6415, 0xb3168558, 0xfa5cc32d, 0x626fb567, 0x5f73fc5d, 0xb328ebb9, 0xa36dba3e, 0xe17ca5f2, 0xff2751d2, + 0x48973a3a, 0x1943b524, 0xf516fcd3, 0x440ab45f, 0x5b79b7ee, 0x84b448f0, 0xd2e5ea29, 0xefe60f27, 0x401944ec, + 0xc0076701, 0x701520b7, 0x9c63ad24, 0x183c8a1c, 0xd8f08fe4, 0x97314e03, 0x5d37256d, 0x5c9fc46e, 0x006ffb74, + 0x75a06343, 0x6e731a8b, 0x251a32fe, 0x530e6506, 0x3f2389d7, 0x0a1f6189, 0xc9d2a5ae, 0xa6f431a5, 0x097f2d0a, + 0x82d915de, 0x76634c55, 0x9f3dbe68, 0x2963db68, 0xe8bd1bfc, 0xa7a7afb1, 0x5249f26d, 0xd5a9ec19, 0xed6db846, + 0x72fe4721, 0x74f46b42, 0xfafb8ac4, 0x9cf7239f, 0xcf815226, 0x5a1659df, 0x14e79cff, 0xb2eaf3bf, 0xb87e1688, + 0x156e2888, 0x4964bcf2, 0x8a86de6a, 0xd3f215f8, 0xe3d322f2, 0x1032d01c, 0xc29f7d3b, 0xabaa643f, 0x1cda67fa, + 0xb2e70d78, 0xb7b2c71c, 0x85b50e10, 0x97065bd3, 0xff97357f, 0x2a4654ef, 0x3768b0f8, 0x1ce5c2ad, 0x442aea00, + 0xd7f4a3f8, 0xcc51f126, 0xa335abb8, 0x018eaba5, 0x4882ed5c, 0x52818069, 0x1e3fd50d, 0x0ea2775e, 0xde6b8e1d, + 0x69ef10d8, 0xf1517adf, 0x57a3d53d, 0xa36d7d93, 0x9b772ace, 0x7e41b4ad, 0x6549f278, 0xdac19fd3, 0x9f7d8d23, + 0x9665564e, 0x1c080f8f, 0x17ab354c, 0x0daa6b17, 0x239fd6da, 0x6104d00c, 0x6da12852, 0xe7097ccc, 0x91ceca19, + 0x20611df1, 0x34e5f339, 0xe92886a6, 0x76120fc5, 0x700738fc, 0x218bebc5, 0x550006ae, 0x13f71885, 0xcb1e69fa, + 0xe9301126, 0x963d4bfe, 0x8833f60b, 0x6a9dca88, 0xb40a7668, 0x3df63a0b, 0x5cde1f3f, 0x41d669bc, 0x71f6bbca, + 0xefed6ce2, 0xd122e1a4, 0xc636f29b, 0xf7f866ef, 0xce155c77, 0x52afda7f, 0xa6e6bb18, 0xebad6d5b, 0x9774d437, + 0x8d20e130, 0x6f93d1cf, 0xa68f82c6, 0x4fb2a315, 0xd90b6b42, 0x29e0d4de, 0x8cfc4750, 0x2b740e18, 0xc8c7bc34, + 0x02630bd0, 0x9d5ed742, 0x3cb2e259, 0x4cac6d87, 0x901496c4, 0x23b9dd3b, 0x6bef68c0, 0x44b2301e, 0xd7efcee6, + 0x49ef5fec, 0xb482cad8, 0x341d29b1, 0x452a2f1d, 0xdbe10aeb, 0x0ba71383, 0x68c0fb06, 0xa732405b, 0x59a1e950, + 0x3004e9a0, 0xe762af21, 0x76f3a8c5, 0x41d58f0c, 0x20df1ed4, 0x9627386f, 0x463f0831, 0x3fad86b7, 0x3a42c65b, + 0x6b9f4040, 0xf9fa506b, 0xf54d0113, 0x70d7d631, 0x0c94b3b3, 0xe22e2224, 0x57b1b883, 0x478aa606, 0xef6f001c, + 0xa0e3f45a, 0xb30cf2a0, 0xdac31dca, 0x889ac3ac, 0x71da0633, 0xfbc60fd1, 0x74b223e1, 0xab72bdc5, 0xb2b980a8, + 0x6341e07f, 0xe9efe6fa, 0xc95aa650, 0x3bfcf57a, 0x749aeda3, 0x78bc4a07, 0x83a800ca, 0x32da7940, 0x32b9d1a0, + 0x0edfdab3, 0x059fb89f, 0x64188b52, 0x7902a098, 0xc223b58b, 0x6f8a4ec4, 0xc26e1ac5, 0x1f00474c, 0x7cc71d68, + 0x5197aa9b, 0x6ce58a6b, 0x9910f298, 0xa6db8f00, 0xfd165b07, 0x4acc97bc, 0xdb9753fb, 0x713813d1, 0xbfa1686c, + 0x0bac1b96, 0x14fb9190, 0x37c853d5, 0x8a4ebcb8, 0x1ddeaa01, 0x3e61e717, 0xe96c992c, 0x2e0c82f9, 0x354a36d3, + 0x207cf094, 0x4621889c, 0x29c4331d, 0x3c3d95ac, 0x073ecd93, 0xbcf9522f, 0xbf57cebc, 0x531fc67b, 0x513f1dbc, + 0x82effb4d, 0xee659054, 0x00090c80, 0x772408d5, 0x3ff97c5e, 0xc7a5f0b2, 0xde6d02b0, 0x84d719e5, 0x0bc34bed, + 0x75911134, 0xa86949b5, 0x8ba1b736, 0xe1d453a1, 0x6c37f861, 0x42aa80b5, 0xb67e0982, 0x6bc324da, 0xf124362a, + 0x44a8aad9, 0xa94c84f7, 0x244b29e5, 0x0d4ca4bd, 0x633f8601, 0x79afe7d4, 0x7e10ddc1, 0xb7ea78a7, 0xcc43a040, + 0x011a7425, 0x1f343320, 0xd73178de, 0x4899e30b, 0x9c4c4247, 0xff2a351b, 0x58ac8177, 0x771711d1, 0x86a89ce1, + 0xa298828c, 0x386146a8, 0x91b2109a, 0x5f02b46c, 0xfe085ff4, 0xa321e578, 0x40b340ad, 0xc0841e5b, 0xfef687c9, + 0x97aa3ef6, 0x4f423253, 0x7c017ba8, 0x20fc1059, 0x4c09729a, 0x6df955d5, 0x26ba3eba, 0xa4cb04e2, 0x9ae870f6, + 0xfa1349f6, 0x3f39ce3a, 0xa7d863b4, 0x011957e6, 0xae619187, 0x9f31dda9, 0x9af80ce7, 0x4e7e98ba, 0x08ada8c5, + 0x384d56f9, 0xd2645a47, 0x30fdb2ac, 0x387c9a27, 0x7e330201, 0xe90724f3, 0xc9931a25, 0xa7645943, 0x812283b5, + 0x6d1b675a, 0x78b9a829, 0xd046fc54, 0xea010172, 0x867bf806, 0x2dc1a9c3, 0xef85b3b9, 0x3fcf3a0b, 0x63285d1c, + 0x901139b3, 0x75b6a287, 0xdd8d798b, 0x0031d912, 0x7232dfb7, 0x5a263ac7, 0x9ae350f6, 0x70977588, 0xe15babd8, + 0xc727da38, 0x6e307a7e, 0xb900ce36, 0xbd26eb32, 0x652a79ea, 0xcd361c8d, 0xe46f9aa3, 0x58f0807b, 0x282b8978, + 0x03d50147, 0x1d886503, 0x48052d9a, 0xaa02628d, 0x32c66ace, 0xbf4af48b, 0x72d8a0a4, 0x20c2af1e, 0xf354c3c8, + 0x35c07ab0, 0x563e30ee, 0xabcc0a22, 0x96fa0671, 0x9382a08a, 0xa1757145, 0x68d5ee4e, 0x05743797, 0xf48e7129, + 0xc4cbf5f0, 0xd7f975a1, 0x8e4f586d, 0x3a418e2c, 0xb99e2ad5, 0x5d0caa5e, 0x8b961982, 0x885b390b, 0xae928c48, + 0x0649caf3, 0x6ba09f0e, 0xf640ce7d, 0xaa06d49a, 0xf10d4f7a, 0x492ce650, 0x7abca738, 0x21dd70b3, 0x6db4334c, + 0xa8c2a087, 0x6045d3b9, 0x7645540a, 0xdf283203, 0x6c177196, 0x353af1db, 0x719dd286, 0xb5a302dd, 0x1d702afd, + 0x937d83d5, 0xb05c01d3, 0xc9bae29e, 0x94343ecb, 0xeba16090, 0xe9c20db5, 0x4c019488, 0x89e9411c, 0x1595be7f, + 0x9ebdb228, 0x056c782a, 0xdcf7aca8, 0xc7ea2efa, 0x64908de7, 0xec2a88e4, 0x5e2f8179, 0x74d4ad55, 0x94d78ae5, + 0xdc32ee2f, 0x8966686a, 0xf411639f, 0x69bb9af7, 0xa4b73e8b, 0x97a1e81b, 0xb3c75242, 0xcff0f3d6, 0x2828672f, + 0x8403cf5c, 0x44e963ae, 0x7eb018a7, 0x49a54174, 0x420b1df5, 0x94f2526c, 0xd9c363b9, 0x964ef51c, 0x45314031, + 0x78ab9542, 0xe7909afd, 0x46050c7a, 0x1a78f36e, 0xed4602cd, 0x8ec4fca9, 0xea05335d, 0x4c272706, 0x53286849, + 0xcadd8644, 0xb6a418a3, 0xcacdfbc8, 0x43b28db3, 0x9c74d647, 0x41a46f24, 0xc44be388, 0x45e421e8, 0x4816d122, + 0x221d439a, 0x8b13df4b, 0x9586a911, 0xf6bd2fd9, 0x6da99c92, 0xa497420a, 0xb4e74bfb, 0x44a0d8ca, 0x28d85df1, + 0xca444b55, 0xc7b3e8c2, 0x4469fd0a, 0x190b090d, 0xd35d2fa3, 0x3df2e827, 0x91cb6ab4, 0x168cd588, 0x36667580, + 0x12c398e9, 0xacd06686, 0x94e284f7, 0x4c3b9da4, 0x78f11c80, 0xdb529cca, 0xbb107211, 0x2e6d0dd0, 0x420ba8fe, + 0x19e1840d, 0x804531ab, 0xfd2beb56, 0xb9210fef, 0x7b3afebf, 0x9acc3909, 0x3759a204, 0x93acc7bc, 0x40cc38dc, + 0xbb1ab21c, 0x9364b621, 0xc5df592d, 0xa50a8fc0, 0x1539a914, 0xa6a866ca, 0xd135a0f0, 0xf2657ad1, 0x96c7dbd6, + 0xd1ea4cd0, 0x3cd7ec78, 0x8ca628d8, 0x3c6a2d1e, 0xa1a1be19, 0x68e0834e, 0x78464da7, 0xd90c9a0c, 0xfdf2ca8e, + 0x32d437e0, 0x2c1075b7, 0x24b97f10, 0xbcede81b, 0x60bfe4b2, 0xd6a140bd, 0x5a48a944, 0x4b147214, 0x47d55a0a, + 0x7192d286, 0x7cd3102d, 0xe3592c62, 0x1200ba94, 0xd1af89a2, 0xc49281d4, 0x62ed6b3d, 0x466b5d01, 0x762614e5, + 0x6868708f, 0xccfefb09, 0xe10e4e0a, 0x01efc9c6, 0x32569f34, 0x8dc41a14, 0x0e1b88f9, 0xd7683556, 0xa9b7f4bf, + 0x32d8430b, 0x46545640, 0xc29666e4, 0x7f175768, 0xee5f6f06, 0x6b24a86e, 0x24a2d4b7, 0x956d3786, 0x4d8c23ba, + 0x09223ee7, 0x15aee55c, 0x292da766, 0x54083e89, 0x7f3bf24e, 0x82f1c893, 0x0a91fd76, 0x34b95776, 0x2021b3d5, + 0xa88d4ea6, 0x65d1c2cd, 0x1fa4ccd4, 0x606e221e, 0x2989da58, 0x210d6600, 0x522f096d, 0xa79ac22a, 0xda3e9a06, + 0x964c01a1, 0x0b99c0ee, 0x9bc6150d, 0x298b9ded, 0xb081c47d, 0x06fcd944, 0x44df53fc, 0xe375b5bd, 0xdde82bcb, + 0xbc36cf89, 0x17182629, 0xa0c3fa6f, 0x96c929e5, 0x6b841473, 0xc0b73894, 0x7cdeb497, 0x4e87365b, 0x68619a18, + 0x86c59cf3, 0x9f9e72e2, 0x802b186c, 0x0044742b, 0x6447bb93, 0x93fcc45c, 0x349b4baf, 0xc0270a36, 0x72760161, + 0x28b9262e, 0xaa27d2b7, 0x4aa39630, 0xe88a54e1, 0x474a5bf1, 0xe60ddc98, 0x23e0b945, 0xbb345858, 0x8a1826b0, + 0xa7612cb5, 0xc6a2f08a, 0x56529172, 0x50d10458, 0x859f5ca0, 0x450ae9e3, 0x06b7afea, 0x598045f8, 0xc3b8e0f7, + 0x7999ba54, 0xa14a6563, 0x2ec174ca, 0xaa522b72, 0x443d0f96, 0xe56683ee, 0xcc1c670a, 0x54168670, 0xbebe669b, + 0xae1cc570, 0xc33c3cef, 0xd13e0a66, 0x089a6921, 0xefe7d1ee, 0x8b1037df, 0x9149581a, 0xe6c486e8, 0x00c09f4f, + 0xdfda44cd, 0xfe6c5c7f, 0x60b2e9f2, 0x53a6ef0e, 0x395b2e36, 0xc4d2b9a7, 0xc4c118d7, 0xf786ce20, 0x6228e030, + 0xfbd9cac5, 0x91b712ae, 0xf4531ff0, 0x97ccb1db, 0x4fad9676, 0x94f5fe84, 0x613c3477, 0x20a9a6ad, 0x068f9b79, + 0x0b9dfcda, 0x68a64f5b, 0x805a4625, 0xff2929cd, 0x6f53f39e, 0xc9f768f3, 0xa3e10a8a, 0x2add8335, 0x63f08e56, + 0x864ddc49, 0x68d8761c, 0x44fbddbb, 0xe5de7ba4, 0x4a82ebc5, 0xce381e26, 0x1cd67ce1, 0x04fdfd68, 0xcaeb183c, + 0x0ce3e9f9, 0x55ea34ad, 0x0733ff2f, 0x90fe72bf, 0x2927c014, 0x66029ab7, 0xe3c67b98, 0x5fd010e9, 0x6b7135d3, + 0xc72cf164, 0xb786f154, 0x7854737b, 0xad2d2518, 0x74f7a7fa, 0xa162beb7, 0xebb34817, 0xd4947ff4, 0xcf49736d, + 0x37f135fb, 0x67d75c3d, 0x986807d2, 0xefdc9c77, 0xfa601836, 0x0738585f, 0x75f53de8, 0x07b375fa, 0xc4dc8832, + 0x6872d92c, 0x8ed8186b, 0x539222bf, 0xa07124b9, 0x4e82da04, 0x3f117cb9, 0x4507e445, 0xf16efb1a, 0x78dc2ac0, + 0x53677e83, 0x33f78c2b, 0x5cfcb427, 0x67aaf8fe, 0x1253a667, 0x1c967165, 0x6729967b, 0xf5463e07, 0x1171f422, + 0x7a7e33a6, 0x7ae12618, 0xa5975e2d, 0x53640463, 0x2dab6ba2, 0x8a9b09d6, 0xd956276d, 0x24853007, 0x9c454f80, + 0x7016ec00, 0xbc01ee11, 0xbd56fa40, 0x842b85f4, 0x196b49c5, 0xe5e1286b, 0x865a1cb2, 0xfa7a0e84, 0x948d3eab, + 0x49082119, 0x58155649, 0x01520744, 0x0eced19a, 0x5af1475a, 0x8410d89c, 0xe4a81644, 0x072cf65e, 0x1dc754a2, + 0x48480519, 0xedd9e3d1, 0x4ec85db6, 0xeda12cb2, 0x1ffee6ed, 0x0d031c57, 0x8a565fbd, 0xee156ee0, 0x7715da0f, + 0x5ae42c8f, 0x9263c46a, 0xcf47a90d, 0x80bc8cee, 0x7f6fdf9f, 0x2cd55500, 0xa16c1b8a, 0x9468f34a, 0x5e572c90, + 0x0943ee30, 0x26451384, 0xa137f633, 0xde34665c, 0x540abb40, 0xa49e341d, 0x19a8d585, 0x10f638e2, 0x40f55948, + 0x36f623df, 0x66640649, 0x410c8419, 0x802006dd, 0x46b06c4c, 0x66fc930a, 0x3ac14a4a, 0xe3e7727f, 0xad60b7cf, + 0x54fc92d0, 0xf7c468b0, 0xed049586, 0x88caea0c, 0x40a8faf9, 0x25e23914, 0x0d2bda61, 0xdf13550a, 0x27df5cf3, + 0x153f844d, 0x204a37c1, 0xcb82d106, 0x89838191, 0x6fea56e2, 0xf012ca39, 0xec081423, 0xd5341285, 0x7aad4997, + 0x7f59521b, 0xe3cae568, 0x36dab245, 0x60504847, 0x7dea0257, 0xd8e5fcb4, 0xfce79d55, 0x837137f9, 0x37690fdd, + 0x08c225df, 0x9095a44f, 0x4777c542, 0x9cb0e96e, 0x2ade9140, 0xa25eaf9a, 0x95856318, 0x359cac6e, 0x7db8c0a5, + 0x235580a7, 0xf84721a6, 0x99ff3b81, 0x909f3722, 0x4ed802e8, 0x4a609648, 0xaa4952da, 0x400e58f8, 0x0f1d2245, + 0x75bd0731, 0x5563a0c3, 0xe40f14f4, 0x5fc76fc3, 0x79e31537, 0x7c2cc8d8, 0x8f13ea37, 0x62a489d6, 0x479ac6ec, + 0x7a6cf464, 0xbe820176, 0x05ba8038, 0x4e5d3f1d, 0xe4f027ba, 0x683eadc4, 0x7f90549e, 0x1a874a4c, 0x089e4b2a, + 0x828fb3e9, 0x7378d488, 0x6ed46f96, 0x209ebfe5, 0xbd9b5e0e, 0x9fed1cd6, 0xd59e9703, 0xde8472e0, 0x2e8be66d, + 0x76457431, 0xa82ccca2, 0x68f81c86, 0x43e9c718, 0x858cb15d, 0x99356526, 0xf03cda83, 0x98bc3432, 0x6206c4a5, + 0x82031edc, 0xe80fa310, 0x967d0ffb, 0xc30e0617, 0xb7f739c3, 0x3fefc0b1, 0x6e1d8a30, 0x4e4ebfe0, 0x911d80a3, + 0x960519bf, 0xf746da48, 0x5930bb7a, 0x1848eb9b, 0x75e464a7, 0x8650e61a, 0x3f94b665, 0x4875c5d3, 0xe9a239d8, + 0x1bdf9874, 0x53026a8f, 0x6bdfe556, 0x03849708, 0x99392032, 0x39b8978d, 0x9d12ad84, 0x52163ba5, 0x7451ba19, + 0x862c6a21, 0x5c018791, 0x28d00baa, 0x2ec56c27, 0xb7f94302, 0x256777d3, 0x420afefb, 0x0c9b4397, 0x9b2cf5bf, + 0x6120860d, 0x9f569187, 0x1e5607f7, 0x513ad8b3, 0xe2571f93, 0x1d61b2cb, 0x469e29c2, 0x2a377b2c, 0x363725e5, + 0x43019682, 0x1e025530, 0x79080433, 0x13f0a2cf, 0xb6b2eebc, 0xbceef484, 0xfc5075bf, 0x9f5a7cc4, 0x4b80322a, + 0x1438f22d, 0x872dc726, 0x9c220281, 0x89f38085, 0xa163734f, 0x4dc4b968, 0x1e8a4aaf, 0x032671f2, 0xff7acdf3, + 0xe38f87bf, 0xc99b3f85, 0xa8a22025, 0x5cfe277d, 0x58e5ebad, 0xbbb99f3f, 0xf0b3e91f, 0x96392ae2, 0x0c2c55bd, + 0xe0f8d639, 0x5bf39869, 0x93f284db, 0xd4cc2f1b, 0x79e177dd, 0x6fdc23c1, 0xac40f7ec, 0x279ed118, 0xb5d56db4, + 0x75c840cc, 0xd044be94, 0x991ea378, 0x7cf01c54, 0x4ee88a12, 0x9f47c933, 0xb2c53a1d, 0x08850f2e, 0x5e62af92, + 0x29051c6f, 0x42f0ac9d, 0x1e1f5666, 0xd327f5a1, 0x0a885348, 0xc9808899, 0x6eadc376, 0x6d03793b, 0x035d3530, + 0x90683ff4, 0x6e2f62ca, 0xb47428c8, 0x803c7e7b, 0x94cd9d63, 0xc3a4a6e7, 0x6b743168, 0x1e037457, 0xb475c311, + 0x60a01ea5, 0xf8f9f320, 0x19c21269, 0xf75ae05b, 0x559c2c7e, 0x79ce03ea, 0x67dfc9e0, 0x06185117, 0xf5e022a4, + 0x2b802646, 0xb55a30b0, 0x9e01650a, 0xa8856400, 0x8ce703e9, 0xaa186c10, 0x14f2ba01, 0x423021bc, 0x92152bf0, + 0xfe2db195, 0x48155488, 0xf88b72cb, 0xf4409ad9, 0x95fbad9d, 0x7e44ad4d, 0x93561ab3, 0xe7585f1a, 0x0ad04124, + 0x0534f00a, 0x81750ef1, 0x9c8de6cd, 0x1cadf304, 0x8fea2021, 0xd6085cd3, 0xdec589e2, 0x9f9bcc16, 0xb3ac91f5, + 0xd8b4986e, 0x08b835c6, 0x3762a60d, 0x4c9dcb42, 0x9c417444, 0x495c366a, 0x9a2dc1f9, 0x68bcb848, 0xbc6dc1e5, + 0x81cff050, 0xfce5cc06, 0x81643a82, 0x7646d489, 0xa8ec79b0, 0x41274b48, 0x7f914747, 0xf7094aa2, 0x13661e97, + 0xc7bafecb, 0x353d4cc6, 0xf19dbca8, 0xfac6ac46, 0x74290986, 0xb707c8e8, 0xa1ff1b36, 0x016822c8, 0x73aad5fc, + 0xd1f7dee7, 0xed71e7c7, 0xb365325d, 0x72933721, 0x710c42a9, 0xb53eb4af, 0x5b65c02d, 0xc06b61fd, 0xcda718c9, + 0xc3b0517d, 0x777b8842, 0x57583741, 0x1faa217e, 0x8b6e8784, 0x629e7285, 0x7e12faed, 0x2c3c3caa, 0x7207b933, + 0x7edf4edd, 0xa1d3edb5, 0x1773209f, 0x529ba2d5, 0x1374fe42, 0x37d5408c, 0x893edea6, 0x1d688335, 0xc208c81f, + 0xe3912fb4, 0x62a780f8, 0x7c34461f, 0x4e10977a, 0x9ff51a7c, 0x0d407746, 0x435aa44b, 0x63943260, 0xa261ed28, + 0xc963bc2a, 0xd52650ee, 0x880b5662, 0x7ca4187f, 0x6e203849, 0xf175049f, 0xd8adf644, 0x322ab3d9, 0x1eed9744, + 0x09a13d18, 0x45f059cc, 0xdea3f98e, 0x2e0f050d, 0xe8cc7029, 0xe9601e94, 0x58baa895, 0x96445de2, 0x9d46b88f, + 0x673a91a4, 0xf2a3aa8b, 0xbfcd7a18, 0x1a4001e3, 0x48629a37, 0xb09189d2, 0x3d1f77fc, 0x7d20869a, 0x209b535c, + 0xc0610c61, 0x9f00d1e3, 0x113d58b4, 0xa20200f0, 0xba904c6b, 0xc6bac1ae, 0x86639e7f, 0xd4d80062, 0x5a47e10b, + 0x31477e94, 0x73573278, 0x41bddef2, 0xfb8d8fd9, 0x040744b2, 0x25e123e4, 0x0bc4030e, 0xb57bb538, 0x47d2b6e2, + 0xc84ce54b, 0xa46b7e90, 0xe2f89598, 0xa61abe3d, 0x5bb9788a, 0x71fa1c4f, 0xfb8857ff, 0x5b9ab989, 0xa32af041, + 0xb15c785f, 0x6d1ee156, 0xba91d132, 0xd64915f1, 0xb3bdde07, 0xc059fe70, 0x69b42ae2, 0x8119ce16, 0x80cca534, + 0x9557317e, 0xcf9abc7b, 0xde058b19, 0x6457c2ab, 0xf4a73319, 0x74a47189, 0x9435debb, 0x46ffc997, 0xc85a208f, + 0xd552b396, 0xd56f375f, 0x16a5aeea, 0x04ad72f5, 0x553d9320, 0x9852fb1d, 0x3f34035f, 0xd03d0e14, 0xc7cdd401, + 0xc74f4d85, 0x306dcb22, 0x387769da, 0x92d6851d, 0xcc9a078f, 0x88e2c450, 0x073c06d4, 0x8dfa7c61, 0x446e4d04, + 0x14a0651f, 0x8862122d, 0xe7b78d28, 0x6af8c081, 0xddddeaec, 0x5bf3d424, 0x82365e4a, 0x0b1a37c3, 0x6f429e21, + 0x5b71cebb, 0x667e4281, 0x414faa07, 0xce3000e8, 0x0502572b, 0x5379de76, 0xc5ee8f8c, 0xe609550a, 0xb8b84ecf, + 0x5ee5f6ae, 0x9da39872, 0x0ea0a8c6, 0x06d266ec, 0xd7418f61, 0xb385e4f6, 0x20d06270, 0x552214c6, 0x26082c65, + 0xa355e41d, 0x778f3386, 0x8f3a65ec, 0xb2806bad, 0x574da48e, 0x06eb134e, 0x3fe1f3e3, 0x0e0e5631, 0x4ff17734, + 0xe2c339e3, 0x9be14bda, 0x137467c5, 0x9a6f961c, 0x131afbd1, 0xd50b1df2, 0x2520aac2, 0x7256eefd, 0xd01469ea, + 0x1fb4f923, 0x93d28d4a, 0x4ea867fd, 0x5a4ef418, 0x2b939c55, 0x5b7f6ea1, 0x30d3f51f, 0x71971f89, 0xe1eb614d, + 0xa7e8f7aa, 0xbef645e8, 0x86850925, 0x416766a1, 0xabc3a424, 0x6d9c45bc, 0xf4cb3de8, 0x8151048d, 0xe03a3f9a, + 0x44d366cf, 0x44da556a, 0x8ed459a5, 0x562ec0b7, 0xb115c9ab, 0x7e8aaafb, 0xacb9b6e7, 0x908afa56, 0x51a22b04, + 0xb747710b, 0x079aa392, 0x23dd67cc, 0x2a99ab53, 0x8a645868, 0xcc68ac58, 0x1b09e8cf, 0xaf48074a, 0xe8e4d3d2, + 0xd3d9793e, 0xba20926a, 0xd331f4a5, 0x8380af60, 0x2580bded, 0x492f85d7, 0xc5b4adff, 0x66675c3f, 0x76adf03d, + 0x569adf53, 0x775678f4, 0x90bac58f, 0x37acdbed, 0xa04caf14, 0x99136ab2, 0xc767315b, 0x8070b2f4, 0xf796c61d, + 0xa53fd3c7, 0xabecf03f, 0x08a69a0d, 0x9004ddb6, 0x7d6c4108, 0x3707fca2, 0x02e1dbdf, 0xdd538755, 0xe70bf9e2, + 0x00fb19a3, 0xae60ce5a, 0x5083d68a, 0x6ffaa8de, 0xbc8c1fe5, 0xc56b1bfd, 0x810c2027, 0x11860580, 0x9ada3dce, + 0x670c0549, 0x12e91c5d, 0x12f0d3d6, 0x30ccea27, 0x9365d991, 0x00a7157b, 0x740705d0, 0xeebfec56, 0x3a5ab59d, + 0x166d4267, 0x57df572e, 0xb36ae55e, 0xd6cc0eef, 0x727c5958, 0xbf07ec63, 0x57457301, 0x7ad06f11, 0x3de2a1de, + 0x56be2f9d, 0x18276f6a, 0xb3ea0911, 0x0d8f8581, 0x12be29da, 0x582a7156, 0xb8f98bb4, 0x82fbeb66, 0x5f02951d, + 0x33a9fdb6, 0x11cdf360, 0x5b1634e9, 0x5373c3a0, 0xfaf8bc1a, 0x16b2177d, 0x028c33dd, 0x75e3c055, 0x0b258150, + 0x04fee86f, 0x82519844, 0x31c657d1, 0x19f44f1b, 0xd67623e1, 0xb4b0cdc8, 0xa5c9d700, 0xe462d5f1, 0x5f1c5a2f, + 0xe04ca80e, 0x69ae2d4a, 0x24d003c0, 0xa85f7e9f, 0xb23a30d3, 0xe79824a7, 0xb47db63e, 0x244d588d, 0xd86bb535, + 0xb5d8be25, 0xa72b60d6, 0xf45a85f8, 0x479f1e2d, 0xcf090bed, 0x7d9f106e, 0xb3373657, 0x7573bc54, 0xf3de956b, + 0xb9ef3144, 0x43234f25, 0x4e15fc8f, 0xfbb7e2c5, 0xeb2062cd, 0x6ae3390f, 0x78ae9131, 0xc8c0d3b2, 0x5c240ad1, + 0x9171d77e, 0xd48f0e01, 0xbba107ae, 0x73ffaea9, 0xf3d7ae70, 0xc27416ff, 0xdf8596c7, 0x01cc0e05, 0xc4b65685, + 0xf8b318b7, 0xb71d5274, 0x7dc4a4d8, 0xadbda914, 0x3359083e, 0xff584ab8, 0x10cb0cf3, 0x3b99a1a5, 0xec95cfd3, + 0x41033ba6, 0xa1060403, 0x4e090f2d, 0x7e004504, 0xfae3763c, 0xdafe1987, 0xc4fae461, 0x2e1bf7ae, 0x1303144f, + 0xeaeae1b2, 0x269a3843, 0x6f4348ad, 0x4d6bf262, 0x3eafd93f, 0x4749d164, 0x8e588443, 0x0a561ad7, 0xc6b47d4e, + 0xf821ae3a, 0x076a5e01, 0xcba67a6c, 0x06dba92e, 0x79f9919a, 0x4afe55b0, 0x71e38afc, 0xf4202d17, 0x8cc8c334, + 0xbaff51f0, 0x03e84cc5, 0xe6e48b28, 0x098210ee, 0xe9d44cab, 0xcab73cf3, 0x91b41485, 0x982b77c6, 0x2145d22a, + 0x396963c9, 0xf7a1fa59, 0x9acb71b6, 0xcf4d888a, 0xe0a23c71, 0x533de3b7, 0x84150d4e, 0xb1f67ccc, 0xd277d5ef, + 0xba1d8c13, 0xcd42ed97, 0x0cbc0d54, 0x8df9652c, 0xb77fde8e, 0xf07bc674, 0x02977fa8, 0x818a422b, 0xd911ae52, + 0xcb3e0503, 0x5c20b1fb, 0xa79dd88c, 0x13dba7b7, 0x5422b327, 0x628db3f4, 0xb91cf895, 0x5c4dab4a, 0xd731e926, + 0xacf7249e, 0x69967efa, 0x55ad7742, 0x91d8d45b, 0x879bda32, 0x0b845949, 0x841c737b, 0xb983deb1, 0x69fa0c8c, + 0xe3575061, 0x60e31891, 0xd1fca55e, 0x616f56c5, 0xbc1152fe, 0xfb8b20f9, 0x6a329f90, 0x7702d872, 0x2da042b3, + 0xa0056284, 0x17e71c7f, 0x42d4d0eb, 0xdbef0ace, 0x9bdc5f73, 0x2b556809, 0x2d989ec0, 0x09c55e84, 0x0f45527e, + 0x050ede78, 0xd1e7c0e8, 0x547d8718, 0x3dfac963, 0x4fde189a, 0xc8600024, 0x8267632f, 0x272d1614, 0x5becff09, + 0x2e753ca8, 0xbc314cb4, 0x1d8d5ddc, 0x2cae6c08, 0x672d0c8e, 0xeebb44a3, 0x9fe59228, 0xfecad9e1, 0x75e70c62, + 0x49b90a29, 0xe51dafc2, 0x3d1816ad, 0x95e42544, 0xa9fc25c9, 0x1a0d8626, 0xd9546bdd, 0x713cafac, 0xfd344a8a, + 0x25d1d120, 0x413c95d1, 0x1d129838, 0xca415f7a, 0x91048a8d, 0x8b76b36c, 0x99e2117f, 0x1981af9b, 0xa1a02742, + 0x176172e2, 0x6fdc10f3, 0x2aef03f2, 0x0a457534, 0x043828e9, 0x47bef962, 0x56575b71, 0xb2d31de3, 0xbc2f323b, + 0x2b5c1531, 0x1565418c, 0x1e222613, 0xb3567c8a, 0xd71ed4d5, 0xe899f95b, 0x65c73ce8, 0x37393199, 0x2f2345a4, + 0x10eb06f2, 0x05c1c662, 0x6813d7e1, 0x882a9ea4, 0x0f0f28a8, 0xaa615754, 0x685281b1, 0x7445ef41, 0x488b2891, + 0x1b888f54, 0xfa7e2447, 0x6bb18d5e, 0x470945b4, 0xc0946702, 0x02bddb34, 0xbe39cea3, 0xc47f63ac, 0x6c3a2751, + 0x8bcff44e, 0x6970e90d, 0xebb865b4, 0x0f50d1f8, 0xe11babde, 0xb0e7d595, 0xa33f8f4d, 0xbadb6003, 0x9587c582, + 0x5a85fa80, 0xf6bb0e5d, 0xaf10af25, 0x05cc7305, 0x2105c965, 0xbc547e15, 0xb6ec0a0a, 0x383992f0, 0xa8803b67, + 0x52e4c056, 0x4eaabdb8, 0x561963cd, 0xfa2d948a, 0x2f6c6cf8, 0x148e4f76, 0x44270827, 0xee41e036, 0x7dfb90ec, + 0x13f918fc, 0xacc076d7, 0x5b5fe1e6, 0xb136ec3b, 0x7ee86d1c, 0xa10b7698, 0xb9b473b7, 0xe37d0b09, 0xaef521fd, + 0x4f4df568, 0x01345802, 0x7dc3a2df, 0x500ab4bc, 0x99526c40, 0x9f54f3f3, 0x3fa2c688, 0xa0c01375, 0x2c665c26, + 0x6223667b, 0xf628f7ca, 0x5fe8edc4, 0x1506336f, 0x6cb43ec4, 0x800b9894, 0x9239bec6, 0xb9fac891, 0xa8bb62bc, + 0x741c18dc, 0x7b5388e9, 0x89f55763, 0xd86ad49b, 0x750f460c, 0xb1a7eefe, 0x4f169248, 0x45d04534, 0xe7737744, + 0x84d9beef, 0x74203b4a, 0x289bf7a3, 0xf85392eb, 0x594db93b, 0x3a0e5b51, 0x176e32b9, 0x1becf353, 0x34fc1755, + 0x5e8e9ad7, 0x10ebd76c, 0xa582d450, 0x359d4c6e, 0xde73324f, 0x4f7c6ae4, 0x42913b29, 0xf7016afe, 0x19dd44bd, + 0x48c099b8, 0x3e7a9f46, 0x9e52eea7, 0x9f943525, 0x46f973a8, 0x979e06e7, 0x93c0a750, 0x13abc521, 0xa06dd4d3, + 0xb92db328, 0x100415c1, 0x40834180, 0x02a4ff1c, 0xc021ccaa, 0xaf0589a3, 0x82eb7529, 0xe55320d5, 0xd6453e54, + 0x5611c8fb, 0x3a4dd3cd, 0xa1cfa66f, 0x85f7b6b3, 0x54d25e2e, 0x7776d720, 0xe90eec71, 0x6dbd86df, 0x5cafba3d, + 0x36122af1, 0xc83c14ea, 0xb3025f8e, 0xed285d2b, 0x477544b5, 0xfa7397df, 0x1f74e6bf, 0xd82de980, 0xea918cdb, + 0xccbb10a3, 0xea66d555, 0xdeefcf73, 0x1684e363, 0x723cbbe3, 0x0dd19638, 0x23381f2c, 0x6ea57d53, 0xa89dbc7c, + 0xd42c9c8d, 0x6440dac8, 0x6099b40e, 0x56b409db, 0xd9fa9230, 0xebd856ca, 0x15c89c99, 0xa05a21e3, 0x37299634, + 0x720ef7df, 0x2b428e43, 0x2b571658, 0x06b4a307, 0xc4252321, 0xe99ef778, 0x6a22db93, 0x349d8a34, 0x0437f294, + 0xb7b6dcad, 0x630e17d3, 0x61187037, 0x9249c642, 0xea22044b, 0xfe796537, 0x962bcf3a, 0x95df9cce, 0x26c3e900, + 0x29f4b7c2, 0x8efd1195, 0xc5b89bec, 0x061cbfef, 0x5ae61535, 0xcd76bc55, 0x780920e0, 0x7291bda3, 0xfc265c56, + 0x7e0c68c4, 0x8873ff67, 0xec79527d, 0x82cf9146, 0x60e9ffa4, 0x8de7f639, 0x73b86c5c, 0x42f98ec0, 0xc8176d2d, + 0xf4d1174b, 0xc50b8832, 0x6182a2fa, 0xbe154ea1, 0x199e6de6, 0x79dfa79c, 0xb7ec2576, 0x97e8c6c0, 0xc3f20c1a, + 0xbc5520fd, 0x9d4f5c21, 0x7ab014c9, 0x9a82b3c2, 0xb486c221, 0x1e5d4787, 0xb0710f6b, 0xb24f7138, 0x1579b72f, + 0x74331f28, 0xf9a594c8, 0xc95f96b5, 0xedea9de0, 0xa19c60d6, 0xfac2a645, 0xe7352d5a, 0x7e9b8c51, 0x12274534, + 0xe969f39a, 0xd37e1c9c, 0x9c8b76b5, 0xd585f2a2, 0x017b4335, 0x2871843f, 0x0e35ce0a, 0xcc419650, 0xccdcefff, + 0x4645ba43, 0x69be7ba6, 0x675f31ad, 0x63e57032, 0x9bd41adc, 0x282e1786, 0x28dbea20, 0x79217abf, 0x98e0b2fc, + 0x3e915293, 0x41ca385c, 0xd91ccd46, 0x150577b9, 0xd021a549, 0x50103787, 0x6fd4d846, 0xfb911ae6, 0x7060aca2, + 0x64fc1f92, 0x44cf9e43, 0xf8d5797a, 0x80b0d485, 0x2546373c, 0xc52daaab, 0x29f60125, 0xb21a24c4, 0xfc1731fd, + 0xae5429f4, 0xb93d0de1, 0xb07b316b, 0x7d63f48c, 0x04de6035, 0xa802fa19, 0xac46b502, 0xab95e958, 0x00bce4b8, + 0x71b3f49e, 0x7ab5cfba, 0xdbe3a30d, 0x34f02bcf, 0xafb3c232, 0x8c150289, 0x21025232, 0x546f39f7, 0xfea14c1a, + 0xfbce0413, 0x5bdc45a6, 0x44da414c, 0x0e8f4c97, 0x855b7590, 0x5ce6326c, 0xf7d8c7a0, 0x3d082be0, 0xc946d067, + 0x208d626c, 0xdf7e7880, 0x89eff5f1, 0xf4bac409, 0x653589b9, 0x4a357737, 0x4900742c, 0x6b5ca108, 0x8b8fe6d2, + 0xd7049bc4, 0xff4f6311, 0x2ca04211, 0x896714af, 0x8e716ac1, 0xab776f58, 0xeff6c6fa, 0x45f988f2, 0xd9fb3354, + 0x9e6b7fbc, 0x8a9109df, 0xdd841866, 0x7d011ad9, 0xa3c3492a, 0xb9010441, 0xea5e0c25, 0x6b184b43, 0xeb2fd20c, + 0xcfa73598, 0xc4ac08d9, 0x3f7c2308, 0x544d7758, 0xf852f11f, 0x019cb47b, 0x82155706, 0xbca1ee78, 0x7729fe40, + 0x220dfe9f, 0x5ae92d80, 0x5aeeacde, 0xb374bbe2, 0x52a423cd, 0x55955c54, 0x8965ad73, 0x15f54e8e, 0xe01a7902, + 0x87a4e0c5, 0x85476b6e, 0x9d1e1dfb, 0x875f6bac, 0x2fa8d0cf, 0xef4a4ccf, 0xd7a07f36, 0xed217d39, 0xbb5da73d, + 0x99d1c07d, 0xac8098a8, 0x85796dba, 0x3e3f38dc, 0x3ac1cb6c, 0x4ab099c3, 0x213f0d0a, 0xf69dbb30, 0x3a5bde4c, + 0xf84b8171, 0xbe6e743c, 0xe82fd9fa, 0x8df5f1d2, 0x18213784, 0x379d8a38, 0x3b7365b7, 0x7ed147fe, 0x89be473e, + 0x1804e582, 0x07f2ff15, 0x3618535b, 0x6a470357, 0xe630c4e7, 0xb7d31f1e, 0x4e1575a7, 0xec22627f, 0x891cbb21, + 0x8bae861e, 0xd8b39ec9, 0x7f2c931a, 0xe961f545, 0xc770b482, 0xac368521, 0xd2fe4f53, 0xd9c25a87, 0x980b4cc6, + 0x63a8025e, 0xdee8763f, 0x62ef62a3, 0xc71777be, 0xf26949d2, 0x4daa8835, 0x27745b43, 0x46b3f8d0, 0x7f162f9a, + 0x357e20ba, 0xd9cff9f1, 0xf0b8f7c7, 0x1b2ab02f, 0x80279995, 0xfafb06f3, 0x6f2fe1b3, 0x376e59c9, 0x8f3348c0, + 0x19105b05, 0xbc85bc9e, 0x4666e759, 0x5133fe56, 0xfe130226, 0x82054905, 0x2fc137f3, 0xdc33fd2e, 0x65387288, + 0xf8d6b4b3, 0xa9c26307, 0x0ddd1b75, 0x36e4576c, 0x1f51cd51, 0xf15a6ea9, 0x7d78285c, 0x3452247a, 0xccefda49, + 0xc413609a, 0xf8fc0a07, 0x39f135e6, 0x5592ee48, 0x3fc4476f, 0x70b0f9d4, 0x8f4180d1, 0x76470653, 0x446515f0, + 0xf2e61dca, 0x9643dc32, 0x9d609492, 0x76cd14e6, 0xa5dc5389, 0xd38c188c, 0xf2db632b, 0xbe1cd83c, 0xc0c5531f, + 0xc3439c44, 0x6a19930f, 0x26762abc, 0x877f8c1b, 0xb5a68b64, 0xe4220195, 0x0fa38cde, 0xdcb66ff3, 0xa2b4c29c, + 0x7b25bf7d, 0x2c7c93fb, 0xad856727, 0x18cbbfe4, 0x5156a5ab, 0xa43c950f, 0xd1666aa4, 0xd07e6a10, 0x10ba6d5f, + 0x9c6dbf76, 0x7395a70f, 0x684e67c1, 0xf7d841c9, 0x7e823eab, 0x86ac5faa, 0xc06b8394, 0x43acbc83, 0x13a6e0b3, + 0x8385501f, 0xd0c5cc0c, 0xbb47fdb2, 0xbfd589b9, 0xc3965fc1, 0xede7b0f8, 0x88e1fb3e, 0xbb0ff82a, 0x7c19a166, + 0x8e0ccf1d, 0x42a9ccbc, 0x8925897c, 0xb37984a8, 0xe8e2a146, 0x744aa836, 0x1e6416b2, 0x080b746e, 0xe3aad5c7, + 0xd2e98f62, 0x81590d15, 0xb7b9eb89, 0x346e4079, 0xe228433d, 0xfc45f2bb, 0x9c5334fe, 0xcffbace1, 0x101ab4b1, + 0x74730d9d, 0x5e20aea0, 0x5f923a45, 0x86b5363f, 0xe8f6c8d2, 0x50fcc748, 0x6ecedddd, 0xddae20bc, 0x59bb5baa, + 0x95b74bcc, 0xfd4a89a1, 0xad882fc9, 0x76a0513b, 0x6ac0819a, 0xcd8549ff, 0x7d613da3, 0x46c5ea8f, 0x21269a33, + 0xa3bde81c, 0x22b42109, 0x89c09bf3, 0x047669bc, 0xd7c9865e, 0x8fdf7a1d, 0xab80b4ad, 0x9d1b8d84, 0x9c8fe78f, + 0x6ebe3988, 0xeaa5af7b, 0x55ef96c7, 0x819e5fdb, 0xfe1e0ea4, 0x39f7803a, 0x83aa04f7, 0x52c90229, 0x0bbd03d1, + 0x7d73e22e, 0x5a75b33c, 0x64373df1, 0xedc1d811, 0x4ae0d4c3, 0xebcaad18, 0x5d8ad669, 0x35d06218, 0x0501d16d, + 0x79c9f518, 0x9614cb81, 0x4d520b03, 0xc76e0bd4, 0x9bc59058, 0xe3de0e13, 0xda84ad7e, 0x4e96b70d, 0xf6fd2874, + 0x1c101179, 0x4586ee26, 0x3980cd9f, 0x0a4d4705, 0x2e046606, 0xc35cf808, 0xc6425c16, 0x0c6a2ff5, 0xc54960f5, + 0x9d0381b3, 0xfa720ee7, 0xb9d4d8d0, 0x14393144, 0xbd4b72eb, 0x23fa7a50, 0xb4c4b8fd, 0x853958f1, 0xa0ffb773, + 0x4bac70e9, 0x303092e1, 0x8c6d9f1d, 0x4b13aaab, 0xb372b970, 0x634e32e9, 0x70cac3cf, 0xbca12be2, 0x8f76971c, + 0xcf415608, 0x94fb2325, 0xdbc30ebb, 0xfc6eeb61, 0xa643011a, 0x1682de16, 0x8dfb3b11, 0x2ed86fa4, 0x5135dcb4, + 0x9fc6139c, 0xc1035978, 0x32c75c79, 0x89c1f999, 0x11f33739, 0x42c21e96, 0x952f5fcc, 0x5ccd8bd4, 0xc52bfe60, + 0xe2f8dd94, 0x2d4e6fd2, 0x2ad973aa, 0x2ccf59f3, 0xaf409093, 0xb1270f0c, 0x4e1ae1c2, 0xc28bf485, 0x97f09468, + 0x841255a0, 0xe874b837, 0x9d4f555b, 0x78c5e974, 0xbb282509, 0xa99defe3, 0x35223b80, 0xaceb577c, 0x71b08597, + 0x51e68b2d, 0x1d756dbc, 0xedf85abf, 0xa7f81025, 0x1b509d20, 0x6bfd9dc9, 0x62d24096, 0x575e28d0, 0xf7b56391, + 0x437583c2, 0xecca9aff, 0xbfb466e2, 0xc6dc24d3, 0x4306a86b, 0x080f15f0, 0x84540f35, 0xef8c0c05, 0xd9e43f91, + 0x9761ac7e, 0x090b9740, 0xf1b29836, 0x2472b889, 0x81ce8536, 0xe1ca039c, 0xf9020889, 0x3b031848, 0xdd23c7e5, + 0x6d61843d, 0xca8cd44e, 0xd1105d31, 0x9a130de6, 0x41fdb73e, 0x2698b541, 0xd2b8e7f2, 0x7c16d4ca, 0x10ac8974, + 0x14153144, 0xfa413a8e, 0x7e1c0920, 0x7114d74e, 0x87b67c60, 0xd9cc04cd, 0x9ba72475, 0x08db15f2, 0x9f8eccec, + 0x6ae28ddf, 0x0c887dcb, 0x9ec21e0e, 0xd5a7598f, 0xb17fa0f7, 0x2be56ffc, 0x5243a551, 0x9d09bd4e, 0x7cc936ea, + 0xd7addcff, 0xd08c0c0a, 0xee7c5fb3, 0xbcc34721, 0xe213ba6c, 0x0d3f35e8, 0xdcd2e489, 0x82ce2336, 0x19bf69cf, + 0x8350369d, 0x2890893a, 0xef5ba69e, 0x29adcfe0, 0xca62290e, 0xe88a624d, 0x8277f84e, 0x0ee71f4a, 0xdb9b6b80, + 0x913733f2, 0xd88bad39, 0x52dbb322, 0xcf627375, 0x26118b4d, 0x0004060f, 0x0c7268cc, 0x44af755c, 0xd53e74b5, + 0x5af535bd, 0x650e9ae1, 0x7edfe16d, 0x43d10cd2, 0xd7590503, 0x861806c4, 0x7ec1da66, 0xabe58e9b, 0xa30fa0e2, + 0xe018faa5, 0x98f996b7, 0xef2154ea, 0x82c9f300, 0x5d18404d, 0x16e23d5d, 0x52595d92, 0xf1b3d607, 0xd1dcd8d2, + 0xac6f8a99, 0x9f6ac4bb, 0x34f2f481, 0x96b19c58, 0xc15e6e3c, 0x116d1af5, 0x101b74c9, 0xf7c8ec1d, 0xca9700f8, + 0xe3120d91, 0x3bcaf54b, 0x9c0dc683, 0xbaab96ca, 0x67b84e94, 0xed9c25d6, 0xa6b008e1, 0x2c19041d, 0x90148189, + 0x33b0fb9f, 0x5456f73f, 0x14fa4775, 0x61d7027d, 0x16575dae, 0x69a538dd, 0x6d9be3d5, 0xdaaa756c, 0x2a2aea11, + 0xcf8ba31b, 0xd19af7c6, 0xf0855098, 0xe4e8debc, 0x80b5f546, 0x529240b2, 0x9fc70a4f, 0xc31443c4, 0xe3b8fe63, + 0xf2a736d0, 0x8bcd941a, 0x69be0139, 0x5967a823, 0xa1ea119c, 0x3c9bfd49, 0xbbcae8ca, 0x5c14ff44, 0x00c7c9d3, + 0xafc465a7, 0x9eb29b39, 0xabe25d8f, 0xf1cf7cd2, 0xda2fb026, 0xbe13cc9f, 0x9ea13114, 0xd8ecb3f0, 0xc99a161d, + 0x0116ec61, 0x39742862, 0xe09ad6f1, 0x9dffd107, 0xe0f04245, 0x63e5d19b, 0x27b84881, 0x48569a92, 0x94851074, + 0x4cff726b, 0xadb26b67, 0x0473e52c, 0x9849ef0f, 0xeaac99ce, 0xa7ef42bc, 0x6be517ce, 0x55cff84f, 0x6cd256c8, + 0x96cda6c6, 0x639cec14, 0x7dba18ee, 0x670f37ac, 0x5d30b8f8, 0x6df899bb, 0x8952f305, 0x2b6c89ee, 0x7eab6591, + 0x5aead776, 0xdbcf0dad, 0x7ece4fe0, 0x25b86e92, 0x7fb06955, 0x8605c277, 0xefb200a7, 0x162a5259, 0x08179570, + 0xc2616ee6, 0xd793f837, 0x8263eb2a, 0xa3846a4c, 0xa6d57a19, 0x7505b47c, 0x44bed209, 0xfb7fa6f4, 0x2b97c2d3, + 0x74cffa4b, 0xcd3b2906, 0x47fb6bdd, 0x4af0db1f, 0x9bf1e13c, 0x345d515c, 0x9ba7457f, 0x136edad8, 0x8f2bdd32, + 0xe6f4541a, 0x634135b2, 0xc0794977, 0x14056485, 0x1106f3bb, 0x728277e8, 0xbc729411, 0x4b29a36a, 0xade5d935, + 0xab0041bf, 0xa1576291, 0x93271c72, 0x9c5f64d3, 0x666be6f8, 0xec57e1e5, 0x75c170da, 0xafdf602b, 0xe62ae253, + 0xe4a97a5f, 0xef607d5c, 0x05d523d4, 0xda4ae9d6, 0xb5b266eb, 0x2dfabffa, 0xd94a9fd0, 0x8a614ebc, 0xb5d81228, + 0x91de136e, 0x3e64f793, 0x7093614a, 0x2d076b99, 0xcef7db07, 0x6297d4ee, 0xe423c798, 0x0d9cdca2, 0xaa085b77, + 0xaa2bc70b, 0xedcbbfa7, 0xd8917033, 0xc36b8f13, 0x706e43b0, 0x904e9eee, 0xd18ea041, 0xf42531c4, 0x37aae090, + 0xf5d26771, 0x7c815f74, 0x2d34179e, 0x43e2760f, 0x1319c315, 0xc57f75d2, 0xb5159a57, 0xbe15defe, 0x7ee80324, + 0xc9b00535, 0x7d63b30b, 0x9c03c1c3, 0x288cfd03, 0x969adbc6, 0x194d2dcb, 0x47fa2ad0, 0x0014f06f, 0xec4a75d8, + 0x5d4bf74f, 0xdab3b996, 0xcadfca45, 0xd5a983ef, 0x96eb3314, 0x7788ac45, 0xbda8fc2c, 0x57083315, 0x8c7e66de, + 0x965c7844, 0xc701e721, 0x597718bb, 0x7c2c115e, 0x75fde069, 0x23f6a93d, 0x26279126, 0xb3991be3, 0xb8f7b5a1, + 0x65df9a19, 0x78da2e5e, 0x57ace4e0, 0xdb7770a0, 0x0dcf3f3d, 0x1af6704c, 0xa6068de8, 0x4fdca94f, 0xb1c3ee8a, + 0x8a59ccfc, 0x5ca37e68, 0xc4c14b46, 0xd4d6dbc1, 0x473e75f5, 0x9d2d2c41, 0xd5f36f99, 0xc80fb366, 0x1bfdc6ad, + 0xef6935b6, 0x6a3f381e, 0x117c268a, 0xedc2862d, 0xf2bbd4b8, 0xb0744fcf, 0x1ac7057e, 0xaab3db3b, 0xef2e3a43, + 0x62697ab8, 0xd5844351, 0x48951ff8, 0xce426e77, 0x4c816301, 0xdf66d64e, 0x88133ea9, 0xf0550052, 0x8d04ce05, + 0xbe98704c, 0x5a0069ff, 0x71528e7a, 0xa29157a7, 0x95b9efe8, 0x30ef28ed, 0xe3723503, 0x70c55f2a, 0xede9be52, + 0x9fc0a0ca, 0x43b6f750, 0xd910b63c, 0x7d416731, 0x51013a3a, 0xbb10fe7d, 0x0f2ffc70, 0xc9df44e7, 0x4a840ca3, + 0x99fac79b, 0x10ad1cd7, 0xe1f5a78d, 0x4fe073da, 0x419d6a7c, 0x56cdff67, 0xc65a56a9, 0x7da35a70, 0x1bce9881, + 0x92b416c8, 0x92d8932f, 0x199c5dbc, 0xdaa7aa37, 0xded7977b, 0xdf967c66, 0x731c8fcb, 0xc350ebe6, 0x5acc02a0, + 0x5b3a4630, 0xa1efa702, 0xa8299405, 0x9ffc1d6f, 0x0ce8b1f9, 0x82cac57a, 0xa0dbf9ec, 0x5ebad6ec, 0xa56c9674, + 0x76b5a00f, 0xa990e95b, 0xc20c9866, 0x5e00f6cd, 0x35f38711, 0x58236485, 0x2c09da5f, 0x1a431942, 0xde5c25c9, + 0x77aec9f7, 0xe8dc6e5e, 0xf29cda08, 0x08c829f7, 0x98df4dc6, 0xeaa72f5a, 0xcef9ab2d, 0x227ba04e, 0xdda6fd86, + 0xcded5b2c, 0xc50a456c, 0x35c71ebf, 0xe55bb5f5, 0xc7ad3126, 0x8c841834, 0xec9d709a, 0x986f0ae6, 0x7f1789c6, + 0x6621baf9, 0x25c4bfea, 0x8558b942, 0x8a1aba2d, 0x4da9d376, 0x7a7e02c8, 0xf85ae79d, 0xc4d7e8f4, 0xee747fe0, + 0xd2c39c64, 0xdc4df4a2, 0xef8957de, 0x2844e9db, 0xda191e4f, 0xddaf76d3, 0xd19ec935, 0xd024714c, 0x23c1da91, + 0xc676ee9b, 0xb02e135a, 0x815535e2, 0x0353cfd9, 0x89c83fda, 0x9175b019, 0xa6527b73, 0xb59a783f, 0xb8267545, + 0xfdbd68fb, 0x8a6a37f7, 0x3f034992, 0x46d1e177, 0xbd5b7839, 0xa76dbbd9, 0x94f9b78b, 0x23d024f4, 0x76d41b78, + 0x0d417995, 0xb613b0cf, 0x01b995cb, 0x1484319f, 0x00caaae8, 0x696b3957, 0x3ec3ab55, 0x4be962bd, 0x759368e2, + 0xb343da47, 0x4f27dcfb, 0xc39b3204, 0x66a6dd46, 0x4813424a, 0xd23e225b, 0xb6fe76f1, 0x5dcbe0fa, 0x4239f917, + 0x31832a8a, 0x8097ff15, 0x1271a053, 0x3ca120cd, 0x0e75a172, 0xa7126b6a, 0xb0cd86ea, 0xcc8acd4c, 0x41aaf78c, + 0x8e3e3ea6, 0xad450211, 0xd78b740b, 0xb2d1c3a8, 0x065da50e, 0xc67b5a77, 0x14d5e1e7, 0x35e2c84f, 0x62788a54, + 0xe12652d6, 0x81d55a51, 0xd957d75f, 0x6f373e87, 0x4e5eb8c9, 0xbb8ec885, 0xc214d8fc, 0xd61fba97, 0x2630e8de, + 0x9c1c196f, 0x255eca38, 0xda1da697, 0x59e31e57, 0x5ad551ea, 0x62098e5e, 0xe6174678, 0xa1907151, 0x0e8f628d, + 0x16ceb225, 0x38bdd125, 0xcf477e81, 0x8e3e2c73, 0xb12a458e, 0x3905707c, 0x400a6ec2, 0xfb0ee822, 0x25444822, + 0x0879064a, 0xb69ffeb0, 0x6f46d9e5, 0x64f0cc79, 0x56deb81c, 0xb32cdb2a, 0x3ec33007, 0x6ff97ad1, 0x97c4264c, + 0x4a2223d0, 0x0fb89253, 0x8f8e6456, 0xc1fc6729, 0xa1992265, 0x6af01a34, 0xa103abb9, 0xf8b6d99f, 0xad83933c, + 0xedef57fe, 0x28a9cb2f, 0xe67ae7f0, 0x701696c2, 0x0bae5bb0, 0xfc836fcd, 0x0ba765bb, 0xf783552c, 0x72c73bec, + 0xea4bdf60, 0x9eaa55cb, 0xcdf93adb, 0xbf335f27, 0xfe0fd035, 0x76903cb6, 0xabcb1745, 0xd5b57bb5, 0xcee6f51c, + 0xa92365b8, 0x32b77c08, 0x2d54b47d, 0x97aca35a, 0x2393fc60, 0x7593e29d, 0x9f1f5e63, 0x8296a8d5, 0x91f2f9e6, + 0x1d3c5b39, 0x32852cd6, 0x91e484d3, 0xe3d4eb71, 0x039dc3b8, 0xedbd7631, 0x0b5e7b1a, 0xa3b2c09b, 0x62c5bdb5, + 0x83686624, 0xa943b583, 0xf57c40c7, 0x503c50df, 0x09786ae3, 0x469785ec, 0x110e9fdf, 0x7b7a4299, 0x3c96869a, + 0x07b4cf54, 0x2eac3c48, 0x61fd0347, 0xb912a285, 0xa22d3b9f, 0xd42e9da6, 0xf2bcef33, 0xd4d62104, 0x6671a8fb, + 0x4e235a3d, 0xa189c0fb, 0x8b7e6c42, 0x80284dc8, 0xdf67b72e, 0x582ae268, 0x55c1f348, 0x3b9cdf1c, 0xb96923fd, + 0x805322b7, 0xe3006e9f, 0x50c42b0f, 0x3d761d33, 0x7ac80a77, 0x49678aa1, 0x5eb17e52, 0xb657bb33, 0x677b5ffc, + 0xda416e73, 0x6d91fa17, 0x5a8ae753, 0x09b8956b, 0xda8cc8eb, 0x4c5dd715, 0x4667cf38, 0x51b7f619, 0x72fca7ba, + 0x5b0bdd6b, 0xdc22dc1e, 0xbc1483f0, 0x8aa1a077, 0x9e68e9c2, 0x766aa9fc, 0xccd4432a, 0xe84b871f, 0x8b931bb1, + 0x60b82aef, 0x61e2633e, 0x814804ef, 0x9c7cb0b7, 0x49a29a07, 0x0e5cd7dd, 0x035d642d, 0x5c0dc227, 0x34fbd604, + 0xb344f859, 0xf93b9eca, 0x81aad835, 0x18ee9265, 0x3925f2b7, 0x9a337227, 0x996d0edf, 0x82b047c0, 0x0849ed7c, + 0x0480f549, 0xe2789482, 0xe5c24111, 0x56097e28, 0xaf0e0231, 0x2f92e614, 0x9694a948, 0x4f291923, 0x3614e52c, + 0x8e708197, 0xf57ff62a, 0xa2c13543, 0x9a712297, 0x46cce5c5, 0x5736160e, 0x9522a04e, 0x17fb1527, 0x6b9a8af9, + 0x00f12c39, 0x437b6e13, 0x7e478d76, 0x1281a963, 0x226ef99c, 0xeccc4c90, 0xfcb4a0f9, 0x92d0e7a7, 0x2f715c4f, + 0x9b7af7be, 0x5f07eaca, 0x29203564, 0xdcfc5216, 0x79e0bca2, 0x0fdcce65, 0xbd9475e3, 0x0af6adb2, 0xe5e3b65c, + 0xd481aaee, 0x05e30c7c, 0x88b7d7fb, 0xde8b6332, 0xc9922cfc, 0xd4276a7f, 0x7661a4e4, 0x83d8683b, 0xd1b32e5f, + 0x7a1a274e, 0x91315756, 0x83e40c8f, 0x9f14da1a, 0x0c81fd4b, 0x8ec8eba1, 0xb0bc25fd, 0x98963da4, 0x859a5562, + 0xa49bf9fa, 0x8134fe33, 0xa17d2101, 0x79d53b93, 0x2c4775b1, 0xf531e9b8, 0x53337b61, 0xed955526, 0x5d272f33, + 0xa7fd2a28, 0xe63719da, 0xc2cc9c28, 0xeba7d00a, 0xc217e683, 0x5e22db1a, 0x3d5ca3c8, 0xeb0dc8c3, 0x44d193c0, + 0x842d7ee4, 0x10d23370, 0x1e2b58c7, 0xeaeac8e1, 0xe7b594de, 0xbf4f0478, 0x8003558a, 0x7d03c062, 0x8e5686f9, + 0x41a470b4, 0xd3d3448e, 0xc467a645, 0x61f5231d, 0x44680962, 0x2e581e75, 0xf29d99ab, 0x85b45fad, 0xfb00024e, + 0xf8d88eb8, 0x4c142a5a, 0xe23cc923, 0x4e1c2235, 0xd867e91e, 0x8b3d6b58, 0xf603deb1, 0xc261a07c, 0xc797d540, + 0x7922f111, 0x66c4d396, 0xa0cc61bb, 0x7d52f3df, 0xd5db7b41, 0x3786e753, 0xf5619443, 0xc29787d2, 0x3e6dd166, + 0xfb2080cf, 0xfb458f3c, 0x3e1ad6fc, 0x90d26964, 0x24f89530, 0x30786baa, 0x4e1eea91, 0xdb641b63, 0xa68e20c8, + 0xc6ebf10a, 0xd98f2884, 0x9d555906, 0xcfa76e96, 0x86dd62b5, 0x8248fb06, 0x6e87de78, 0x7dd6e6ec, 0x9021dddc, + 0xe0a4a1b6, 0x2a5508e1, 0x8533efa1, 0xb62c85a0, 0x8d924dee, 0x50b7555c, 0x892fe50b, 0xeb2dd761, 0x401af532, + 0xe98cf182, 0x5bb3f417, 0x28961bc3, 0x5cc80e66, 0x4c3b44a7, 0xf60ddea2, 0xd069b8d3, 0x7c57cbf0, 0xc2384bc5, + 0xcd43725e, 0x737ca09d, 0xe7266dc5, 0xf8c34a58, 0x2931a981, 0xddbf5e41, 0x16a5b009, 0xa503e656, 0xa093132c, + 0xe7e81600, 0x6fa6ebd7, 0xa05d2f2a, 0x0682e2a8, 0x679bd0eb, 0xede3f80c, 0xa9f4f2fd, 0xa17e05d8, 0x0520b0ba, + 0xd86e033f, 0xac79117e, 0x875a44fe, 0xd375e08f, 0xafc1861b, 0xafafa61a, 0x26cf8c83, 0x608ab7af, 0x74617b04, + 0x389c75cf, 0xce7d55c8, 0x224c64f2, 0xf1859562, 0x5ab101cb, 0xd25cae25, 0x07ffddfd, 0xad96b114, 0x34a04b2a, + 0x46382c13, 0x858cfa2c, 0x317a1f85, 0xd841b5f6, 0x4d39f817, 0xe9575c82, 0x1976fa21, 0xe068281a, 0x8221fa58, + 0xf9e9ff85, 0xcb9c8ed2, 0x3367c5be, 0x12aca764, 0x55813b34, 0x57bd615a, 0x526a78fb, 0xde428136, 0x2d93776e, + 0x62e2796a, 0xd7fe8d45, 0xa0e25964, 0x35248ef2, 0x8834d94c, 0x56056a29, 0xe8d4027c, 0x9b176dd8, 0xb195be48, + 0x76c6724f, 0xdd8e7aa7, 0x4fc30568, 0x0c83d827, 0x7099d893, 0xd37ebdd1, 0xf07c6a51, 0xf82101c7, 0x7d95eaa1, + 0xcbfd79ff, 0x63729c3b, 0xaa62e3bb, 0x023e15d9, 0x0a4451ca, 0x0bd3b182, 0x8cfe25e5, 0x02ad30b1, 0xe160f198, + 0x0554123e, 0x058e39a3, 0xaaa206f4, 0x65977ab6, 0x2c5e3e52, 0x53678531, 0x44ff4a48, 0xde296f75, 0x8419d10c, + 0xc9fe06af, 0xf1fd6ce9, 0xc4e2152b, 0x2de3ec84, 0x6f05eea8, 0x537c8281, 0x705ff13a, 0x20e5f0d1, 0x4adb2dbf, + 0x9f536f32, 0x43e6ae8c, 0x9dd00e0f, 0xc8136106, 0xd5e6ac33, 0x3a71b76a, 0x35f9a12c, 0xa2e6e6da, 0xce0a5a62, + 0x0e9f323e, 0xd47198f1, 0x1a772c4b, 0x32f48e22, 0x37da70e8, 0x9f8a534f, 0x09df58ab, 0xb21c5a0a, 0x6e6726cf, + 0xe27c8c68, 0x621d51ea, 0xe0406163, 0x7b403ce3, 0x1222c4ec, 0xaa60f05c, 0xf763aaee, 0x9def4642, 0xae4bb22d, + 0xb4118ee7, 0xfafb82a8, 0x8e26a4ac, 0xb218d80e, 0x683d98ea, 0x7849c45d, 0x7c1bd2fb, 0x2adeebe4, 0x063d34f6, + 0x8bf5118d, 0x3b3bce2f, 0x932783ab, 0x2d3d8807, 0x47658a64, 0xee16b089, 0xa29b12aa, 0x6f3a9af6, 0xfac8fb7d, + 0xaacdea0a, 0xe58a6084, 0x943051c0, 0x68499410, 0xd5d036d7, 0x0f31f645, 0x0fc13212, 0xd1d665e2, 0x79d51d05, + 0x732daab5, 0x36ed547b, 0x2dacb907, 0x7b3a70f7, 0x7c5f0819, 0x0adbcffb, 0x3ce37d2a, 0xd9f0b5a0, 0x0a057f65, + 0xd3cb59c9, 0x047d7428, 0x9fabd7a5, 0x7f7fc587, 0x952d798e, 0x51fa9f4f, 0x9d8bff91, 0xa783867c, 0x34aa5eac, + 0x1f11e94d, 0x0e5a621f, 0xfb086231, 0xff2a26f4, 0xb9e796e6, 0x8b31a22c, 0x7fa7d878, 0x709bf886, 0x4bbfea08, + 0xa7b3a3cd, 0x17d09e51, 0x97a5f1e8, 0x0d7cd452, 0xbbc515a7, 0x19c2c17d, 0x368ce86d, 0xbc3e667f, 0x70986704, + 0x627e1762, 0x99c4fc1b, 0x6ca7f04f, 0x668aa079, 0x4c48c229, 0x641b38ca, 0x93366334, 0xff38b206, 0x39cae349, + 0x165dd16d, 0x1c52dd36, 0x0cc7ec42, 0xf1c3d522, 0xf02ecf80, 0x94fc53a1, 0x0549f322, 0xedb5d3a3, 0x586b4530, + 0x7fafbd8c, 0xb94a2f99, 0x3ed4e571, 0xc943a27d, 0x3565d301, 0x96535f78, 0x77e79300, 0x62abf90f, 0xed04675a, + 0xf0b2cbcf, 0xb50a24c5, 0xa8b3dda1, 0x5bcb1339, 0xce6f1e50, 0x26da838c, 0x17d37d24, 0x433af0a3, 0xa4652359, + 0x8c723752, 0x600cda73, 0xc39ab8d4, 0x7b438656, 0x0c13cd58, 0x2030faa9, 0x75513833, 0xeabbeeb1, 0xf0dae197, + 0x56e74c1c, 0xf2fb3755, 0xaa15aef8, 0x99d65ae8, 0x3ca5f0d7, 0x870a4b2a, 0x042d3906, 0xdc25cf61, 0xc2efd65e, + 0x8fff9eea, 0x86f7d96a, 0x6c760a5a, 0x9fc2a55a, 0xf83a7ba5, 0x3c682ed4, 0xf458e6d7, 0x61b623df, 0x00352b63, + 0xc44eae58, 0x4756a6cc, 0xfd4a64a6, 0xc4d030fa, 0x9ad03949, 0x8a86924b, 0x0a897402, 0x5832ba61, 0xabc2ca0b, + 0x3f4e4513, 0x629453ee, 0x0a7594a1, 0x2f3ffeea, 0xc3ee4034, 0x15759c37, 0x55bea454, 0xb2fc1b67, 0x0ff47e04, + 0x126e30bd, 0x243e6010, 0x096686da, 0x337644f6, 0xc76adb18, 0x9b5596ea, 0x11e449d4, 0x6f216af7, 0x8f29e439, + 0x79945772, 0x0e5c8790, 0xfe4858cc, 0x893846e1, 0xe1434c6f, 0x09b14189, 0xc5c35d67, 0x53b3621f, 0x4df43d68, + 0x2150cbf1, 0xfa32ef9c, 0xd227cc48, 0x6e6b990b, 0x418bfa21, 0xe986db17, 0xa3e0c89b, 0x4cdcd7cc, 0xff2611a6, + 0x35f18d30, 0xf6ba703d, 0x25e2c676, 0xf632154a, 0x766f4ed5, 0x4d689cbd, 0xba16863d, 0xf07dbafb, 0x749b8cd4, + 0xd7e59773, 0x83534a2c, 0x60ca62d8, 0x6ba4c3d5, 0x9d1a302c, 0x7aed3f7c, 0x3b4f07ab, 0x5ac3a56a, 0x718208aa, + 0x57162df4, 0x78c1aa15, 0x638da45b, 0xaf365412, 0x224700eb, 0x9ecf0edc, 0x9134ce95, 0x3bcdb36a, 0xbd1ee972, + 0x54509893, 0x9f489d9c, 0x2eab42ee, 0x9979954c, 0x85d4160f, 0x8abe71a8, 0xdff343f9, 0x7a3086be, 0x4fd48f46, + 0x1b355741, 0xc75c4d9e, 0xca081c24, 0xc80f94d1, 0xa6018487, 0x5a52cb4a, 0xd3127f24, 0xab77b78d, 0x3780083b, + 0x67fa867d, 0x2e73df56, 0x7f267c9e, 0x8a10b478, 0x2ffeac7e, 0x551aebf7, 0x4b5fd22e, 0x6d4b5c9b, 0x86bd0585, + 0x78a21351, 0x150d63cf, 0x5042b31a, 0x5607b79b, 0xc3fef9d9, 0xa9e0b49e, 0x46b13906, 0x9f7e1268, 0xc934b834, + 0x734da634, 0xb347f975, 0xb61ad4a8, 0xfcb34ce3, 0xee0bdf72, 0x430929df, 0x7437f1d5, 0x852f09ea, 0xefcef8b6, + 0xd8200299, 0x60ea41e4, 0x68b60865, 0xe7ded158, 0xe3d87603, 0x7ffdf6b6, 0x6914eedf, 0x936d43bb, 0xfed58b50, + 0x5a7782cd, 0x42adccf8, 0xb947eef5, 0x593acedf, 0x1acfae7d, 0x0ea468ef, 0x69456312, 0xb603e3ef, 0x7ea13183, + 0x99b75faf, 0xf6b32b18, 0xa7dd7db4, 0x766b8105, 0x7f7a12ef, 0x35f9a014, 0xcf8098e1, 0x811d9cdf, 0x23ab8439, + 0x9136ab66, 0x5e1b387d, 0xb33988ce, 0x1ec4e625, 0xf7bc38a1, 0x43460d12, 0x69f17086, 0x41e3da0b, 0xcc5cc425, + 0x379b26ef, 0x02866a3b, 0xf5ed34d8, 0x2434b537, 0x354edcb7, 0x3a91f5d2, 0xef1eb318, 0x07ef7873, 0x68950ef4, + 0x7b169618, 0x6efbf04e, 0xc27f957c, 0x1cd203ef, 0xf28f010e, 0x5b4e6e69, 0xb22b9834, 0xd4b740d5, 0x74be9474, + 0x2d2f65c2, 0xe7f17ec1, 0x8ebac076, 0x0d916bf0, 0xf2e1e378, 0x8f3881b4, 0x5abfbe38, 0x0d42a69e, 0xc89e70c6, + 0x86e6205d, 0xb678bb77, 0xd50896e4, 0xb289c238, 0x19d6335b, 0x150a9e3f, 0x313081dd, 0x4ea39048, 0xd5d7357d, + 0xdc6cea9a, 0x3924fb57, 0x098b391a, 0xd7baab56, 0x6acbe88c, 0xb5e985fb, 0xb84a058f, 0x035ac0f0, 0x0af1df4b, + 0xeedf742d, 0xcebcc5e3, 0x1d32f09e, 0xec21d8a6, 0x9f18fe42, 0xeaee284d, 0x7ed9e12e, 0x82d5a0cb, 0x35f5f5ff, + 0xbe1baae5, 0xd51202a8, 0xc0b101ec, 0xb1b5e69f, 0x7b0c5eb0, 0xb5a163a0, 0x0d13c6c1, 0x5a930c74, 0x1607ab7b, + 0xa14cdc9f, 0x9cd87d18, 0xb83744e1, 0x10bfefd5, 0x492bcdc8, 0xa1a688d2, 0xf7599235, 0xe6d03229, 0x5cfe604e, + 0x99504ad0, 0x2f295ac3, 0xd937b95e, 0x03149c7b, 0x59bcceba, 0xa9691a17, 0xe1e6b0be, 0xf1f41258, 0x4a97698c, + 0x04e8ffe5, 0xde17c711, 0x32783a3b, 0x28b78bc0, 0xa548950e, 0xed1b53d9, 0xc7aded8e, 0x2507d1dd, 0x23b5e7bb, + 0x00e4dada, 0xe35412fe, 0x240d0885, 0x33b49f5a, 0x018ddecb, 0x79dbbf5a, 0xba139c7b, 0x7c6c89db, 0x4cbb9dce, + 0x1a8e3992, 0x692a07cc, 0x6c74b7e1, 0x81ed0e08, 0xc5ab784c, 0xa9a84c6e, 0xbf508214, 0x71fe7577, 0xf7bf366b, + 0xe4c835d6, 0x8d611ab6, 0xd7332f4f, 0x17b8a5c1, 0x42d3a695, 0x8f09c20d, 0xebb84daf, 0x4a6b1261, 0x8b714e25, + 0xa268b0d3, 0x25aa4a66, 0xf48fd0b0, 0x92a0cf91, 0xc8ebb38e, 0x9d2efd9e, 0x51326d63, 0x91fb5af0, 0x51800183, + 0x5b6ed78e, 0x3177dc22, 0xed1a59f6, 0x69b26e6a, 0xd70e84b0, 0x62543fb7, 0xf1162bef, 0x721c6722, 0x0564255f, + 0xe686c881, 0xb6bc9bbc, 0x7782e50f, 0x07f7c6d3, 0x144f2c82, 0xfbe670fe, 0x28a0fac0, 0xd3a784a8, 0xe6694722, + 0xea93412c, 0x8d94870c, 0xe664dc43, 0xc55a9bf6, 0xc3e3fb7f, 0xd2319a1a, 0xa4b854d5, 0x6a77f7bd, 0x2418ef95, + 0x32bb1cfe, 0x15d7210e, 0x4c9b4ef0, 0x017749c0, 0xb0044f73, 0x017985d6, 0x8a598ffe, 0x6707713c, 0xbea11d74, + 0x1ef58e74, 0x6054a3bc, 0x8bc99aed, 0x1db64e9c, 0x7e755c67, 0x48f8ba82, 0x066bb139, 0xa6b5d870, 0x70751268, + 0xe5fa9f3a, 0x3ff3efae, 0x67c45e9b, 0x4b00608b, 0x26102e0f, 0x0e9e759c, 0xa52ba0dc, 0xead68dfd, 0x7698e43d, + 0x410f714f, 0x83007b57, 0xccdf9e27, 0x163260ab, 0x8ecce818, 0x399b1969, 0xd4182bf5, 0x41bbadb9, 0x90e4d408, + 0x4e4db53c, 0x2a17933c, 0xab121a2f, 0xc505c406, 0x40014be2, 0x5f6e870b, 0x3d864cbb, 0x94ee2676, 0x9686a42a, + 0x43e09e82, 0x1a09ff98, 0x038fbfac, 0x48d2fc3d, 0xdf7ba972, 0xba917b30, 0x0c229506, 0xf73c252b, 0x7d1df612, + 0xe0052de4, 0x1200ea48, 0x3c119aa5, 0x59857334, 0x38ae58b4, 0x83c44e5d, 0x398ad7ab, 0x9198846f, 0x4a5dd58a, + 0xe0734451, 0x34daf8fc, 0x92f1aa7b, 0xe5e0b414, 0x953457df, 0xfced4dad, 0x41044b41, 0x86595a06, 0x53a3ba8e, + 0x704ec56f, 0x5c381f74, 0x0bdfb97e, 0x76edcbdc, 0xfb3352bb, 0x90e5c149, 0x221867ce, 0x548e265b, 0xf377ca6a, + 0x04666220, 0x507a3464, 0x84e186c4, 0xaa1f6085, 0x26e43d5a, 0x399dd2e4, 0x2374f9f3, 0x8fbd5143, 0xba4e1b8f, + 0x795387ca, 0x85d9bf6f, 0xc1637a9f, 0xc67301b0, 0x2be78ea6, 0x2bab3143, 0xad717b02, 0x8c2174c0, 0xcc909aab, + 0x05cf10bf, 0xc2c75632, 0x1e4dfb50, 0x9ca83ddd, 0xa55310fb, 0x60919105, 0xb59996c0, 0x4143f34a, 0x73fc1f28, + 0x4a1411ab, 0x43dc036a, 0x39b01fdb, 0x3fbdaf5a, 0xa19358eb, 0x91ed1368, 0xff3f16e6, 0xbbddbe56, 0x563b96da, + 0x76e6e912, 0xa8109550, 0x09d23b31, 0xfba28e2e, 0xea32bcb4, 0x2c27d903, 0x66b20f13, 0xc358551b, 0xfb33d3ee, + 0xd65c51e9, 0x8e0b1295, 0xf41a5354, 0x7e4ec610, 0x88f5f3a2, 0x7f531699, 0xcd1ee198, 0x9b4179d0, 0xb03b88e8, + 0x21df96cc, 0xe129eb6d, 0x8644db9d, 0xc6837cd7, 0xb3ac02a9, 0x025d5e6c, 0x54f54422, 0x02e2770d, 0xcadd361e, + 0x7c13284b, 0xe66b1ba3, 0xc589775e, 0x219c4dfa, 0x1e4df0ea, 0x9675620d, 0x61826655, 0x18dc0a5c, 0xe6f56d29, + 0xd6867c62, 0x5ac7671e, 0x61713c38, 0xd877662d, 0x2d3378a3, 0x1ba7e168, 0xc5d8713f, 0x0473a26a, 0x43093b17, + 0xace617fe, 0xf7e1e3f1, 0x84410df0, 0xdf24a15b, 0xdf402030, 0xe4a39c43, 0x1fb11f45, 0x8072dfc3, 0x27238b49, + 0x63822997, 0xe83da440, 0x82bce555, 0x1a29484b, 0xc4d89f4a, 0x4bd11fd1, 0xab388546, 0xc1766eff, 0xe5ea0b20, + 0x4737aca3, 0xc657e830, 0x827d3825, 0xc9dfdb82, 0x17b3f5b6, 0x76a50dd1, 0x60fffa23, 0xcc4a21ea, 0xc6b72712, + 0x9da5fb95, 0xcd079f63, 0x3f31000e, 0x34d6d3f4, 0x77704ab3, 0x373f6425, 0x4ff9b4b1, 0xfb56e3b0, 0xe01dc8e8, + 0x8eb6a546, 0x2bfb3c68, 0xe7402792, 0xe0381afc, 0xb1a9946c, 0x0720023e, 0xda6dc07d, 0xfcf562dd, 0xa1af5925, + 0x6954858d, 0x96d156e7, 0x45dbe3fd, 0xd34cd271, 0x4e5c5763, 0x34bb153f, 0xdb0046bc, 0x3824d0fc, 0xc1368df2, + 0x28152c8b, 0x366366d3, 0x01bddf42, 0xbfb92153, 0x0038bb82, 0xf547310b, 0x487532b9, 0x85859370, 0x9e83d699, + 0xba310a67, 0x1f5a3172, 0xcef5ac15, 0x068dac99, 0xc4365b4b, 0x7dcb05f8, 0x5f2edca2, 0x4d7117e8, 0xc25a895e, + 0x7170034e, 0x69e59e53, 0x19303df7, 0x4e2769c8, 0x9073f032, 0x5423ad98, 0x09413f60, 0x701946ad, 0xe7c2a5b8, + 0xddd58595, 0x6f9680f3, 0x1ba65da2, 0xc6f9420e, 0x2aeb062c, 0xb6e54dab, 0x06eb282e, 0xd007f108, 0x553cf0eb, + 0x2f00a7d9, 0xa37c968b, 0x642f81db, 0x87b24217, 0x6a0e3da9, 0x1762ecf8, 0xc0f636ac, 0xfdb8550a, 0x22684227, + 0x44f94635, 0x795ac7e2, 0xec373f51, 0xfef0ccfe, 0xe1d856ec, 0x83ec3d3b, 0xaf29aff4, 0xeb0c0b6c, 0x87403bed, + 0xc0b41034, 0x17a465d9, 0x54de1463, 0xd69d2b82, 0xfdfe6e21, 0x1eaa1c9d, 0x8af795d3, 0x35714b4c, 0xe5fbd833, + 0x045d8688, 0xa9b48dc2, 0x3c287eca, 0x6613bf24, 0xaea4e378, 0xcdc2df53, 0xb8d5b17a, 0x498f1068, 0x50366ac3, + 0x843becf6, 0x2102853b, 0x842962eb, 0x166454fb, 0x3b7f4238, 0x2c14c764, 0x3d0abef2, 0x9807b14e, 0x2dba5dec, + 0x0ba76fa5, 0x766c3adc, 0xdc2b9c2d, 0x7f42c223, 0x0f0a6df5, 0xe0250977, 0x195a934b, 0xfbb2fa05, 0xf4d9eba0, + 0x72407c0e, 0xb0a08790, 0xe89e0cbd, 0x31d3f388, 0x9c6ce736, 0x5385e5a8, 0x68ce8187, 0x150a15ea, 0x74709b52, + 0x3cc9c7a6, 0x5c9e6fc1, 0x2a871f66, 0x0b52ff9a, 0x2cf2e6ff, 0x7329bd80, 0x6eee3ce2, 0x2c08a217, 0x651e273b, + 0xa6bb719d, 0xb933704b, 0xf5df9caa, 0xdcf25f78, 0x4bc58392, 0x596cfbe9, 0xa66b5903, 0xeda88dc4, 0x6f84f70b, + 0x657c6725, 0x4b7270ae, 0x5de9926c, 0x31fed097, 0xbc461263, 0xe1664e7c, 0x888c4bff, 0x0257ce27, 0x712c32ae, + 0xacdd691d, 0x7b2ce07e, 0x22a1955e, 0x5d2a84eb, 0x0028a083, 0x45616509, 0x1f64b4a6, 0x57921f8d, 0xd232409b, + 0x1744d241, 0xd29e360c, 0xc8caeef7, 0xf443a689, 0x0d96f15c, 0x10f238fa, 0xc0bdd7f0, 0x04da6286, 0x81f472d8, + 0xea15faba, 0x2218b5fa, 0x8045612f, 0xc159e2a9, 0xc23a557a, 0xa18812e8, 0x49eae3bf, 0xf6a994a0, 0xdae8c803, + 0x9475b3c9, 0x472b2b37, 0xed4a1713, 0x45e659ad, 0xdcc2d3f8, 0x821a2e27, 0xb5a0e98a, 0x4de604c8, 0x3a54a37b, + 0x09bd9ca8, 0x8f90bb74, 0x4be12a30, 0x14ff3795, 0x52d393f5, 0xc57068fa, 0x91ea1b9f, 0xac2b8d82, 0x39667f84, + 0x4b4dc427, 0x23e9a006, 0x685022b1, 0x174f4a5b, 0x9356f8f9, 0xc5b095c6, 0xbcc12556, 0x654b5070, 0x28a68802, + 0xcd8d0289, 0x1fb559cf, 0xe8e81c83, 0xc1702a86, 0x1cf201c3, 0xd7481169, 0xd7e2c0b6, 0xa50e875f, 0x41600ebb, + 0x7cb01fc6, 0x148fc694, 0x534bea54, 0xeaeb97d8, 0x95880617, 0x4c9a00b6, 0x297d3e34, 0x0f79b0ee, 0xce31566f, + 0xb1943e34, 0x7bf45500, 0xd5d47f70, 0xf52018fe, 0x39cbf0f1, 0x404a8d92, 0x52faa686, 0x2da97433, 0x17627f59, + 0x28ec4711, 0xc0b6270c, 0x05fd4aa9, 0x764c2280, 0xb48cdaf0, 0x8b0d55ad, 0xbc554f86, 0xcd9f95fb, 0x7a3bda84, + 0x3e913cff, 0x3c5a9de2, 0xe0564117, 0x7b87a149, 0x2f42b905, 0x80e2afd2, 0xab36ae6f, 0x45b57c65, 0x982c5032, + 0x9898446a, 0x6e207f05, 0x9b86be36, 0x61e9e6c8, 0x9f3a010d, 0xb96815e7, 0x14c2c5e6, 0x0f9c8f67, 0xe4bd095b, + 0x20e922dd, 0x4b766e2e, 0xbe7dc960, 0x21aa564e, 0x36e83819, 0x2f26641a, 0x5139e3f7, 0xa8b074ae, 0x41625831, + 0xd7c0fe53, 0xbaef6585, 0x6d5f3fa4, 0x2e056490, 0xc2bb9972, 0xdc9369b5, 0xfa0b14d8, 0x7d376e3b, 0x60abafbc, + 0x8a0cb996, 0x41c40e70, 0x9525bb0e, 0x9d0edf97, 0x24489b44, 0xf90bb0af, 0x69447753, 0x717a53d1, 0x3806a122, + 0xc5387f1f, 0xa43d26d5, 0xf002a74b, 0x8d42e1d7, 0x6264fcfb, 0xacadea55, 0x5f5462d0, 0x65a6b866, 0x2fbd2de0, + 0x639e9d96, 0xaab3841d, 0x5cdd02cb, 0x8f3243d8, 0xa3384a2d, 0xdc64d173, 0xd3dbcf1b, 0x2489d944, 0x29c25b87, + 0xaae377c8, 0x4b7319c9, 0x854b60c5, 0xd27c79ae, 0x93676595, 0xbb855906, 0x851e6368, 0xbd670fb8, 0x436b9432, + 0x08b05fcb, 0x81067074, 0xfea6e793, 0x11f7355d, 0x2ad2fb17, 0x3dde3c5f, 0x7e1292d8, 0x4ef1e9da, 0x7c150d4b, + 0xf0f360db, 0x9a9bad50, 0x8a74cac2, 0x4d272314, 0x1ba69abb, 0x46c5dfd7, 0x321ec3e9, 0x20a67e48, 0x7f27f5ae, + 0xcec6a027, 0x57e0ca36, 0xda286198, 0x76b34d7c, 0xc7e7feb7, 0x17f47513, 0x031eecd7, 0xf872d24b, 0x55fe57a4, + 0x888a88a8, 0x3ed8813c, 0xe338ba85, 0x3addca17, 0x5a484a32, 0x7dc7643a, 0x744165b9, 0xee29ea8a, 0x21e21107, + 0x05c64655, 0x5666ef54, 0x60696d85, 0x18f6f695, 0x848c92ae, 0x4d0fda84, 0xb1abcd26, 0xd1a8d948, 0xe73c23a6, + 0xefc5c90f, 0x9bd457a9, 0xf797a04b, 0x5fc8f8c8, 0xbe84dcde, 0x2baa6f17, 0x31587e99, 0x1735cf4c, 0x10fa78d9, + 0xbe9df6f6, 0x0dd5c4f8, 0xe08c5483, 0xffc5034c, 0x22fe556f, 0x4372bc69, 0xdd6d6255, 0x8728854c, 0xd185393b, + 0x6951b9cb, 0x944e197f, 0x8d91468a, 0x4bc481cf, 0xbe79e9a7, 0x332b1c6e, 0x626fd834, 0x072a50b2, 0x08a0dc99, + 0x58dd157c, 0x436c9e48, 0xa6a3f744, 0xb31f4ad0, 0xd20b3177, 0xc97cf0ed, 0x35f55a94, 0x84cd0a66, 0xc265415c, + 0x3db37476, 0x05f3a7df, 0xbc550739, 0xc8aca650, 0xdfe4075a, 0xcbcc5e27, 0xa2716d6d, 0xb4c8713d, 0xcdbef283, + 0xf72f3289, 0xe28e29d6, 0xb5456357, 0x79d5bd03, 0x921cf971, 0xc07a476c, 0xf13f71f9, 0x2a364e30, 0x206dd894, + 0x83caaca0, 0xd12229f2, 0x56e02d08, 0x7bdac829, 0x1be45d24, 0x6cd9b421, 0xc782d7f4, 0x48563a0e, 0xb78feb26, + 0x6af50e33, 0x2b6db5b4, 0x8610736b, 0x14af8b76, 0xdc19bcc1, 0x7acf254c, 0x6dc4e66f, 0x317d845c, 0x9b83904f, + 0xc8bf8616, 0x5571ae25, 0xf59d5c71, 0x4b6960b1, 0x16c9abf5, 0x48dbf942, 0xd7e65b3d, 0x9de58349, 0xeec5cf35, + 0xff5f7779, 0x95bf6d48, 0x3824e6f5, 0xf1c8c99b, 0x07ba70b2, 0x3b2e4cda, 0xa3a2b3c4, 0xef7d7b90, 0x9130da8b, + 0x5a279496, 0x05a4b0e3, 0x54feeb24, 0x1fe3533f, 0xffb4f76e, 0xd1151795, 0x2f13dff3, 0xac4e3dc1, 0x54123fa8, + 0x06288b8e, 0x105a7488, 0x44a6cfd8, 0x4c5ae813, 0x8bef55e0, 0xbea453af, 0x6bae8d28, 0x5511dfa0, 0x5ad78325, + 0xa43b5989, 0xe6a3749d, 0xc248c5a3, 0xb5654953, 0xd2b9a200, 0x0d01f871, 0x5e1b4026, 0x4e715cf7, 0x1cdd89c9, + 0x530e34c7, 0x4b50e335, 0x27463e4a, 0x5fbfe368, 0xfe29306f, 0xa149fba3, 0x7694ef94, 0xa13f211d, 0x43be50e7, + 0x5b9bb3ad, 0x616e76f2, 0x1b5309e5, 0x11fd7de5, 0x4ce0bb6e, 0xe72fed4c, 0xbe3fc0b6, 0xc05a7899, 0x18ac4cd7, + 0xeb195535, 0xf4d77e08, 0x951cf942, 0xe1737313, 0x5389eca3, 0x5fd1245e, 0x5fd407d3, 0x0100e867, 0x0c91aacd, + 0x6083a0ee, 0x9402f464, 0xef1e9570, 0xc9ad515e, 0x11a0b8d6, 0x0c4dc437, 0x5dc645dd, 0x40610c1c, 0x09c37f62, + 0xc2de6711, 0x1b621638, 0x5aa404ff, 0x4e700111, 0x96066f7e, 0xe53337be, 0xb5305fdd, 0x5c6f04fb, 0x896de76b, + 0xaee4a315, 0xf1b18cd8, 0x0dc003f0, 0x7104b846, 0xcbbab00f, 0x8b2bd32c, 0x4c6ba51a, 0x3c6e0bea, 0x2972e320, + 0xc86e360c, 0x5eec1fc3, 0x29b51edf, 0xd274ada0, 0x438c45b9, 0x8407b8d3, 0x9d34c42b, 0x8df46818, 0x3dedb1ee, + 0x39eefd9f, 0x3712b4a4, 0xc6950b35, 0x3fe4824e, 0x53bc8438, 0xaa3e9821, 0x7f066170, 0xeca66f8d, 0x31a9de09, + 0xccfafc72, 0x74975b6a, 0x5dbf340d, 0x80212546, 0xce604b9c, 0x9b6aa76e, 0x920c6b33, 0x1a3240a0, 0x387c9ba1, + 0xd822a6b2, 0x057873fe, 0xd926f761, 0x57d89e32, 0x27be41de, 0x473bd084, 0x23695038, 0x520ed0d1, 0x7f298874, + 0x8a6eed1f, 0x0f87c313, 0x9276410b, 0x89d85eee, 0x3abaf95d, 0x8f55db7a, 0xcc0c178b, 0x3ab47740, 0x2f0f1c3c, + 0xa81231dd, 0xc24a4498, 0x06c43e9d, 0xd0e63945, 0x57927921, 0x96300baf, 0x6e6fa409, 0xe684f635, 0x111a19de, + 0x7f6aaea9, 0x3dd74587, 0x8a2d6552, 0xb22f3f32, 0x1a2b4593, 0xd649beed, 0xbeaeb51c, 0xd29c26e6, 0x1bf6839c, + 0x79b9cd07, 0xbc9654cb, 0x8d5c4a3f, 0xd4a69dd6, 0x73f02540, 0x37cc68e3, 0xf0512b64, 0x8adc0c23, 0x50008aca, + 0xd85dae8b, 0x3f983208, 0x38826975, 0xf0342a64, 0x2ef42c87, 0x6925b9df, 0xce79541d, 0xac8121c1, 0x84526765, + 0x03fb7069, 0x9ce425c3, 0xab4d4454, 0x9113b9d5, 0x7c77ab87, 0x110428a9, 0xc4852749, 0x6f795732, 0x7cd8b584, + 0x817aafc4, 0x1e5387b6, 0x183b4f15, 0x6ea59971, 0x29120f5d, 0x5adc6db1, 0xdf913507, 0x3a06c1b3, 0x0f8c16e5, + 0x58658efb, 0x299bb86b, 0xee20aa0a, 0x2dabda0d, 0x2b221f6f, 0x77e97ada, 0xf28f0690, 0x1a875af7, 0xcd456392, + 0xf8408a74, 0xdbf90ee9, 0x96f09aee, 0x9a77e74c, 0xeea429ab, 0x6e636bc9, 0x6455079e, 0x1b03c596, 0x223c44e9, + 0xdf940f7b, 0x35bf5907, 0x793ec6cd, 0x286fe677, 0xd400e2e8, 0x23cfee44, 0xa29558f6, 0xc7d34f81, 0x7b40a1e6, + 0xe3185093, 0x3d1a0b76, 0x6b63899d, 0xff7779b6, 0x01c4877b, 0x86a531cd, 0xf37ffb11, 0x14cba381, 0x0c246721, + 0x88ad289f, 0xb7fe8c12, 0x37ec3cb9, 0x2bf9a393, 0x57e0fd0b, 0x71e89899, 0x7e43ea79, 0x978fcc54, 0x2860f1a5, + 0x8b35a204, 0x5af2e362, 0xd04ae87e, 0x58bb68a5, 0xf5f7d797, 0x2bafdc13, 0x7435d7d4, 0xc1b561bb, 0x4ecd3f56, + 0x9922a428, 0x37283d5f, 0xa25de813, 0x3bc26c46, 0x4af96ba7, 0xd4748bb2, 0x1cbc80ca, 0x44629fba, 0x81da3c3e, + 0x37bbadc6, 0x7bddfb3d, 0xe836c12c, 0xaf67f586, 0x40255869, 0x53ad42c0, 0x79b741c7, 0xfef2b5ff, 0x41f9dbad, + 0xc0fd8df2, 0x62b5cff6, 0x97807943, 0xe10016f3, 0xe4e2c436, 0x51567ebe, 0x1468b0af, 0xc5ebfb44, 0x441658fc, + 0xc6d2d6b2, 0x551d49d7, 0x170a33ca, 0xe8cf6224, 0xb99e907e, 0x778f37cd, 0xc619cd40, 0xa02666b2, 0x33c78aff, + 0x89977524, 0x9a5969f0, 0x8a0234f5, 0x0d7a7167, 0x86076bd6, 0x0333f36c, 0x89dea2ff, 0x431f9a19, 0x8b02db0b, + 0xfdd0c839, 0x2d8506ce, 0x705aedc5, 0x2bc57188, 0x33cf0389, 0x40357bfe, 0xd232493e, 0x5d96b9b3, 0x625a0c6b, + 0x23954ffe, 0x25dc0f1e, 0xa72189c4, 0x3fbfe32d, 0x788ddf7d, 0xefb54901, 0x85959a0e, 0x686bc72b, 0x1def656b, + 0xd26a6372, 0xa209f5ac, 0xcc309f05, 0x3ab17a2f, 0xf8a814f7, 0xf1df1414, 0x08362ada, 0x54a7555f, 0x8614661b, + 0x8e853787, 0x9da6b8d1, 0x25258988, 0x7980d993, 0xd7c59a92, 0x0e9eef3e, 0x02866d93, 0x094c8eb7, 0x71c8cee1, + 0xa16d1f66, 0x38dac263, 0x59a55fe1, 0xb09faf3a, 0x91cfda30, 0x5d3e63e7, 0x8683d5d3, 0x6424a75b, 0x2f852694, + 0xfd5b3623, 0x3e2b83ff, 0x208c2ecb, 0x39b1e90a, 0x343264c3, 0x8a3ee786, 0xb7cd5c14, 0x035f7503, 0xde208157, + 0x94dcb19f, 0xd74b16d7, 0x09bfd2eb, 0x2a535be1, 0xa261ee37, 0x7a52157d, 0x17e9e3ef, 0x36a5fbc4, 0x6f132597, + 0x4126b3a1, 0x5af7e12a, 0x656fc9f1, 0x15876807, 0xb3215c28, 0x8a20bb32, 0xdf890328, 0x24da7737, 0x469f2c67, + 0xc7e2818f, 0x839314cf, 0xc3a1e295, 0x2392e559, 0x33b323e7, 0x2573bfc6, 0xaf6413f8, 0xe1ad8577, 0xefa1bc81, + 0xdc6b1d4a, 0x06ea1767, 0x57fbd06e, 0x845d6d0a, 0x5bc03977, 0x78456312, 0xaaf0c71b, 0xe9259ea7, 0xc50f7ac7, + 0xe95977cd, 0x91ed176f, 0x1ffb173d, 0x24d8b493, 0xf467b9c3, 0x81852847, 0xc8fbf01d, 0x62f92b01, 0x40b8027d, + 0xd3d2a686, 0x47621851, 0x64499bbe, 0xefb6ba92, 0xab85a163, 0x541fab44, 0xd42c4143, 0x7b472329, 0x5b95f948, + 0x08ab56fb, 0x0f233f2a, 0x932f5562, 0x7ded337b, 0xc9593340, 0x1654f7b6, 0x4e63133c, 0xd119765b, 0x096f6b09, + 0x71e28bf7, 0x76d75c1a, 0x2737bc89, 0x689b895d, 0xa81f530d, 0xe9a16b28, 0x385013f1, 0xdeab79d6, 0x7588a36a, + 0xd9847088, 0x1b5303dd, 0xfe70ae85, 0x0cbbe99c, 0xc247214c, 0x537eddb4, 0x7be528bd, 0xfbb84ffe, 0xf8d20a83, + 0x910f120d, 0xb699e476, 0x8e6b8d50, 0x48845095, 0x08a0fee9, 0x11cc6850, 0x6c4ee552, 0x51fa4993, 0x640d931e, + 0x2fb930b8, 0x222d8e00, 0xa41fa3fc, 0xfea4efcb, 0x5fc93238, 0x9981ed52, 0xeed0446d, 0x861a21c0, 0xe54f8fdd, + 0xafad0e40, 0x32276980, 0x9fca52a4, 0x97e02273, 0x2a318bcd, 0x347a8da7, 0x8a652d06, 0x31708202, 0x5e24cf21, + 0xa8f7bf16, 0x79a803fa, 0xe5fb3cd6, 0xabab808d, 0x3bd6fbeb, 0x3e621daa, 0xd11a25cc, 0x166bca28, 0xcb6a43ac, + 0x9c3195ab, 0x684c8898, 0x7e235e60, 0x4bbd4db8, 0x6cef2b29, 0xd6fb106a, 0x1adf5417, 0xff010fee, 0x0b9cab26, + 0x9e7c479a, 0xd18d7f06, 0x379f220e, 0xed8a951f, 0xff1948b3, 0x20adf443, 0x67c19270, 0xaed5f2d0, 0xc91f34c4, + 0xc6598c75, 0xcdbaedc9, 0x0c14a47f, 0x0a743d50, 0xa91ffcf8, 0xe2d3887d, 0xfff02826, 0x076f9f98, 0x87233aed, + 0x688432a2, 0x956c0380, 0x3da159f2, 0x44bb6b9b, 0x86d4b697, 0xa0903570, 0xb3f48747, 0x1ce36f3b, 0x93fa1b87, + 0xa27f39b4, 0xd4235fb3, 0x8b74b42d, 0xf2bd7a3a, 0xfec8416c, 0xe0b2e844, 0x10397d9f, 0xb703a436, 0x30f993d3, + 0xb4c6a06a, 0xa137219b, 0x17c51097, 0x4661b841, 0x1c5ac0cf, 0xa4d3b60f, 0x3ec46b4f, 0xa15ad69a, 0x389f77ed, + 0xd01c8b13, 0xcab1491e, 0x1e6e7c54, 0xfb95fe04, 0x649f8197, 0x34c3f130, 0x1aeefc35, 0xdff6381b, 0x21eb489e, + 0x1257ab06, 0x22a4b391, 0xc08c9839, 0x564e0cee, 0xf7000a0d, 0x10680ed3, 0x88c4dc21, 0xd1799e93, 0xdc60bcea, + 0xc4bf6ffe, 0xaa6a1a78, 0x3d883772, 0xd486ccd8, 0x8327e3cf, 0xf54c2223, 0xc34f3f0a, 0x54c1e6e9, 0x369e2323, + 0x7d3824a0, 0xf461d3e5, 0x6d9cc8b2, 0x518ac781, 0x51391e45, 0x12d3a69a, 0xfe378eda, 0x87adf0c1, 0x1c467c9e, + 0xb3de1f3f, 0x520d7cb2, 0xdfa7a070, 0x064ae2e4, 0x5d1d8f40, 0x9cb6956b, 0xbf2cb539, 0x6a50cd9f, 0x735595fd, + 0xbfc5ebe4, 0xd6ca3526, 0xacac8a6d, 0x3b76a116, 0xc336056d, 0xffe4ae5c, 0x73c9a15c, 0x3169fdfe, 0x4298470b, + 0x839b9899, 0x0314d838, 0xb56bc4c7, 0x827c5e3e, 0x49bc1dae, 0x27180c1f, 0x47bc11c8, 0x92a9aab5, 0xc6667e64, + 0x5ab8286c, 0xc92ddd94, 0x5156eb60, 0xaaa5e855, 0xeb6d72fa, 0xddec0a09, 0x0158eb09, 0x90ffbd3f, 0x942606b3, + 0xec585d34, 0x0579fc24, 0x78c20eca, 0x3982f3b1, 0x39ebb42e, 0xc0f5f98a, 0x9cfd681f, 0x9f4e5210, 0x41295198, + 0x8f9b6103, 0x6487f2a2, 0xa8008bbc, 0xdd729ce4, 0x9872c299, 0x8baa1ead, 0x95929f5b, 0x2615fcb7, 0x6fdf9171, + 0xc53f38f9, 0xcf107ecd, 0xff809abb, 0x1961610e, 0x2c68a6ff, 0x5c454c88, 0x91c34b69, 0x1c0e7228, 0xfcd87291, + 0xd26dcdd9, 0x75057632, 0x0c627283, 0x409093dc, 0x5f4994d9, 0xa9fda80c, 0xf2514bef, 0x7a7ee91b, 0x538c0f31, + 0xe3d6cfbb, 0x747be636, 0xf7535437, 0xfcd13b51, 0xcd76aa3e, 0xf73b2ca5, 0x8e51aba7, 0xc90367da, 0x8896c10e, + 0x20f1019d, 0x53422248, 0x09cac676, 0x98ec015a, 0x23dda45e, 0x19f8c499, 0x7fdeb022, 0xe37576c6, 0x32a602bf, + 0xd987c746, 0xbd9e068c, 0xc1f7cb53, 0xe949b67b, 0x6d5c7b0e, 0xf33e7f89, 0x6a06dcb3, 0x619711ac, 0xb1d6dadf, + 0x825d2f57, 0xfbafd55f, 0x7cc779fa, 0x2c9bfa5e, 0x14ecc1b1, 0x6d491cf7, 0xe92f6d8d, 0x9998b550, 0x48b10f7d, + 0x8866e703, 0xc10c4dc5, 0x5a195504, 0x81e73908, 0xc102aace, 0x2ed6373d, 0x62325407, 0x7469f03b, 0x71ca5e64, + 0x929e9a3b, 0xfc9208a1, 0x971b953f, 0x3069fb95, 0x09a5344a, 0xf8f841a5, 0x48378e71, 0x70f8640a, 0xeb55e3ba, + 0x4bc44e57, 0x363e5252, 0x217e52ed, 0xa127c6fa, 0x3df7dbd7, 0x0c9cbe5c, 0xb153020c, 0xbcb98810, 0xee2b93ba, + 0x580fced9, 0x11051785, 0x826f409f, 0x5369f837, 0xe3ce740b, 0x0bee888f, 0x0916ab07, 0x46985473, 0x15cfa68d, + 0xea8b1fcc, 0xe9aa7f6a, 0x4a42c3b0, 0x00ceb1be, 0xa280a6f7, 0x779b07f3, 0xcf11acde, 0xcf351dcb, 0xbaee2a2c, + 0x500373ef, 0xd768db65, 0x069bafe3, 0x88f6a7eb, 0xc53d9fe0, 0xc40ed242, 0xb855efce, 0xd5276bd2, 0x8261f0a5, + 0xb7e1963a, 0x7f08efbf, 0xfb0eb8c4, 0x073fc1a1, 0x71024b36, 0x94e34dc2, 0x9ee83223, 0xcbeeb0c2, 0xefa61976, + 0xdbae4ffd, 0x0fbdf934, 0x525eec6f, 0x60584b69, 0xd84b0d4e, 0xeb999b26, 0x9d5f7e4e, 0x4de3b202, 0x98887610, + 0xa868b97d, 0x92b2b693, 0x610fc012, 0xcd1ac286, 0x7b41126d, 0xa32677d5, 0xf9b64eba, 0xee966cf2, 0x131431b1, + 0xb919d754, 0xcf9ff037, 0xcb0fbc30, 0x6522affa, 0xccc09091, 0x1df2e7ff, 0x79cbdae1, 0x9ffc8c39, 0x80d95990, + 0x3fb8c4b8, 0x5981f707, 0x1ad759de, 0x35c6ee13, 0x374d2a4e, 0xc2a9255a, 0x8cdde164, 0x18a20412, 0x7e773aa7, + 0x0a1dda70, 0xd453194f, 0x28321124, 0x74260e19, 0xf61063d0, 0xd45b8763, 0x3695a323, 0x25764952, 0x0b2fb140, + 0x02fcdc32, 0xbc01750b, 0x5d4dc245, 0x7381f472, 0x2e1fdc10, 0x6b659c55, 0xd258f768, 0x4e6dad04, 0x773d4459, + 0xadcd5774, 0x65920c3e, 0xb0329a02, 0x34b7544a, 0x9bdd3b61, 0x4bca4a0f, 0x17b72d81, 0x06b348e8, 0x89aa8da0, + 0xa0ec21f3, 0x9bd0e1c0, 0x7025f528, 0xa4ae37ca, 0x4cf10870, 0x2a8c4e12, 0xfe81e2a4, 0x30e554b5, 0x23164f26, + 0x41b18407, 0xe133e70e, 0xed15144e, 0x5a6913b2, 0x924c0942, 0xd53da404, 0xd803a04a, 0x1d262894, 0x32906122, + 0x971c83cc, 0x094e1752, 0x260904f9, 0xdc4eeb9f, 0xf547dc20, 0x16aafdee, 0x7ddbd252, 0xe2dc47f2, 0x4eecc425, + 0x234db61d, 0x7cd35796, 0xd4847def, 0xdc9c16b7, 0x602236a3, 0xea0b5c64, 0xf884907f, 0x9f0bfb7f, 0x023c1b20, + 0x8b89c123, 0x38b6851e, 0x2ec161fe, 0x27a2767c, 0x2add0d8d, 0x384fdfa0, 0x0f4f2036, 0x48e8a050, 0xaf5a4dbf, + 0x83bbd603, 0x8da298da, 0xab7f0b07, 0x3c07d168, 0xbb3a604c, 0xefdacf3b, 0x79a33d06, 0x714e831f, 0x132f92e6, + 0x4e7ae4ba, 0x8fe9ae09, 0x3399d397, 0xfbd7aef2, 0x093df6d2, 0xac772873, 0xd2de7237, 0x4b4bc051, 0x4ef56866, + 0xed14641e, 0x1bf02660, 0xd93ff4df, 0xceead883, 0xa93acc35, 0xf76f5ad7, 0x86c2faa8, 0x8d1ccdb2, 0x577f09b5, + 0x8d95b38a, 0xce55fedb, 0x52c3998c, 0x973d5d1d, 0xe36fe0e9, 0x6a1baff2, 0x7f8c1476, 0x490dff96, 0x632af025, + 0xbbfdc274, 0x843eb42f, 0x5929bc85, 0xbfd2d32d, 0xe0c9ba33, 0xd751e2da, 0x90eb5d95, 0xa9b55b1a, 0x403329f0, + 0x39b5ce26, 0xaadba3c4, 0x00c9d4e5, 0xd1fd64c6, 0xc67cbeb1, 0x8732282c, 0x8ded2ecf, 0x99dd0881, 0xd04751b2, + 0xec35de08, 0x0f290d59, 0x048bae83, 0x15a35285, 0x1c308de5, 0x2a04ed56, 0x6a80d47d, 0x5d59e642, 0x5ff0a19b, + 0x8ddd3d8a, 0x293f89bd, 0x70d477c8, 0x5c1b6f8c, 0x9f2868f4, 0xb0d7b6fc, 0x2e96e4f4, 0x375fbb40, 0xe81365fa, + 0xb5371d78, 0xe896a72a, 0x323a56d1, 0xb7bea220, 0xd148f763, 0xa9bf8f07, 0x4883f17a, 0x866ad7ac, 0x2b46c0ff, + 0x06523c65, 0x1a7d0569, 0xdb6df8f1, 0x31e05002, 0x3ec9ab7c, 0x21fc8e75, 0x98108be8, 0xcc24cd72, 0x02813535, + 0x1b404494, 0x8e671773, 0xa03b9b41, 0x866cb0ee, 0xb692d521, 0xecb743b6, 0x5e45e374, 0xfacfb482, 0xd266afe7, + 0xe0ca4276, 0x69498c8d, 0x72668e75, 0xd2fb0b7b, 0x591a216c, 0xafd64986, 0x28144db8, 0x1dff0dd1, 0x13e7bd8b, + 0x60a3d889, 0xe482fd66, 0xd853f605, 0x7d344696, 0x29e9db54, 0xc66b84dc, 0xf9a6d90b, 0x6985b29d, 0x80c73baf, + 0x5a25927a, 0x99875a2e, 0xc2f92259, 0x537c2233, 0xd65cd019, 0x2594b9aa, 0xf16bacba, 0x0d414568, 0x6f5a3856, + 0x55e679a5, 0x4bfe557d, 0xd9599f37, 0x58317ca6, 0x520a0922, 0xa889ec5e, 0x1b9ed785, 0xf853ffbf, 0x6376e59e, + 0xfdd5d418, 0xeb87d0c2, 0x850ac71d, 0x04b13beb, 0x9aadc9a7, 0xd354da86, 0xd5bb9b16, 0x6409e482, 0xd2998e10, + 0x52bd4cfa, 0x3c414d4e, 0x27509ef2, 0xa2a6ec94, 0x6b7401a7, 0x59b148a5, 0xc64ffc8a, 0x157087cc, 0xd775a3b5, + 0x075fcfff, 0x86cce787, 0xf2dd18c5, 0x979e4379, 0xfb903883, 0x9792ee98, 0xda93573d, 0xc4115bcd, 0x5f19b49a, + 0xc161be52, 0xbd3b807f, 0x32dbb4c2, 0x8d4466d1, 0xd05c4942, 0x20df163e, 0xb0546469, 0x73b4479e, 0x7262743a, + 0x65f59a05, 0x76029875, 0x54db2e7f, 0xcffc1518, 0xe6aabb21, 0xd7c6dd07, 0x0de40dd5, 0x48960386, 0xca2d1468, + 0xe12cc4c5, 0x37926424, 0xdc4c17eb, 0xc8d7de6a, 0x284b4853, 0xa0f2a063, 0x044eeeab, 0x60e12cfe, 0xd18b85b4, + 0x57ac8daa, 0xa64c019d, 0x9c1fead0, 0xfa999c5a, 0x4cfe4bf1, 0xcc134b8d, 0x22b7c2af, 0xa6ab6b78, 0x706dd19d, + 0x04f80b2b, 0x10c84283, 0x34337967, 0x3afd4375, 0x0f09a648, 0xba66011d, 0x5dc136b7, 0x074d5b1c, 0xd20c2540, + 0x19e65c0d, 0x6968e737, 0x6c54bfb6, 0xe406d9d8, 0xced5e5a4, 0x6c30906b, 0x6636c712, 0x79672842, 0x921777a4, + 0x65573c1a, 0x29d47781, 0x6d175d04, 0x99f99f0f, 0x3ee606bb, 0x52d63d51, 0x095c534f, 0x6c91237b, 0xc1eb1d6a, + 0xf61d1de4, 0x63a2688b, 0x44501cde, 0x2e3c7f0d, 0xb211a74a, 0xc1ec31ff, 0x47be7820, 0x3eaa3872, 0xd0a363dc, + 0x04adf7b1, 0x9fcc8c91, 0x8cde058e, 0x1cf4a5cc, 0x6bf4b588, 0xe331b81e, 0xd7276c72, 0xfc5059eb, 0x005706f6, + 0x2c97fa0d, 0x5e352e91, 0xf4159e02, 0x11245ef3, 0xacc7c8df, 0x4c9e6691, 0x2c0d6eef, 0x0c4b7db0, 0x56966cf3, + 0x75dac1a6, 0x570fd276, 0x032b59dd, 0x6af0759e, 0xb7c493da, 0x13b8bbfd, 0x0e468922, 0x51e7a985, 0x8f29127d, + 0x0a52b8b2, 0x364c16d7, 0x1c985251, 0x1aa84342, 0x7482c229, 0xf9c3e6a0, 0xb72e7891, 0x03a6581f, 0xb2cb9156, + 0xff919683, 0xc4627e3d, 0x198354c4, 0x764da10f, 0xa2eb57d4, 0x40b51928, 0x2fa58f3c, 0xb3d66c14, 0xa25cc401, + 0x038f4dbf, 0x65910a7d, 0x55a2f6af, 0x59161657, 0x35ff80e5, 0x6a8d7967, 0x25d05cc3, 0x8a595f0d, 0x44411773, + 0xd9884edf, 0x5440672a, 0xe6eec704, 0x934284d2, 0xb758b949, 0x845ae576, 0x8f9590a2, 0xcdb6c7db, 0x0fdc50c8, + 0x53ce121a, 0x4c8fbfb2, 0xabbd24d3, 0xda59db25, 0x9ace63af, 0xe42d717c, 0x58983d12, 0xa3042fd5, 0x6341756e, + 0x611d78cc, 0x130f6c90, 0xf3e7fd61, 0xaf9aa645, 0x9cc719df, 0xdf5e48dd, 0xb892436d, 0xc827c9a3, 0xa95a74ad, + 0x202edcb2, 0x9ddf4a4d, 0xd1066244, 0x28688155, 0x4e4b1a98, 0x9eed8733, 0x29a995a3, 0xd07e1b11, 0x5b3c16ea, + 0xa9bbd944, 0x7e75105d, 0x6737d4bd, 0x00e7a83d, 0xad3fc627, 0x07888d86, 0xc6d367ab, 0x738251e4, 0x4e4d1e34, + 0x8b3ae8f6, 0x31e07d45, 0xdee885c1, 0x80f1c441, 0xfe623a2d, 0x2a9fa495, 0x200280c2, 0xdc361c2c, 0x9f316f06, + 0x4eb20657, 0xd72dd3ec, 0x80824941, 0x0eef8c4a, 0x5fddd44b, 0xb1cbc633, 0x89ca0891, 0x9044ba4c, 0x20a0eda6, + 0x45f59d91, 0x69d5c552, 0xb1b009fb, 0x4e797c54, 0xcc76a271, 0xa529fae0, 0x0244fdc8, 0x5d34727a, 0xa91c9085, + 0xd115e8d7, 0x27a7b56a, 0xa2700de5, 0x65638235, 0xe3d2d484, 0x31e10d91, 0xe9ce48d2, 0x679891bb, 0x0f0be3e3, + 0x508b6dca, 0xf31df602, 0xad3ff6b9, 0x9af0df88, 0x6235c3b6, 0xfac1da52, 0xceb85645, 0x2697cc7e, 0x4634f481, + 0x0e7e89ba, 0x8a24a858, 0x840ecef5, 0xc154a1db, 0x4529775d, 0x994b844a, 0x0fd1a12c, 0xeee280cb, 0x07f53ad1, + 0x2c72cc26, 0x1106c597, 0x06bb07c4, 0x4b5c091d, 0x3b2e8af1, 0xcfdec606, 0xf0aac480, 0x79067ad7, 0xa20036a5, + 0x7d7d94cb, 0xfe8ac4a7, 0x5dbe4536, 0xff9b948a, 0xba4905db, 0x0da6a957, 0xff90f89a, 0xc3512e31, 0xca1532db, + 0x67a74bae, 0x0f923ab0, 0x3f828b49, 0xc008ccc8, 0x0e2ebf02, 0xf0a53075, 0x378f9b9d, 0x25ea39e2, 0xb4a3563c, + 0xeade8e39, 0x843bebac, 0xc6d27fda, 0x517ae9bf, 0x0d86fab7, 0x10bfa803, 0x79d519f9, 0xd38b45b1, 0x9b176693, + 0xcdfa256a, 0xbec5224d, 0xe472bd89, 0x1d11574a, 0x985586f2, 0xc410baf8, 0xd38d7797, 0xb676a9a8, 0xe777c642, + 0xc280faee, 0x2a181981, 0x6d68389c, 0x98f3d256, 0xb4f7c355, 0xcf000a72, 0xdbdaa7c3, 0x51c5e981, 0x4b3bd5f3, + 0xd14c2662, 0xc6171cc1, 0x3a0242cb, 0x1625dfbb, 0x14e6f87f, 0xb5ea063a, 0x74df114c, 0xe7af4397, 0x617fac6e, + 0x51d47576, 0x8d0bf89d, 0x2677ba91, 0xe782d3f8, 0x9d8f4e6d, 0x0a73bcd9, 0x930038a0, 0xfe974ba5, 0xfcd710e2, + 0x6ff201cf, 0xd74ef285, 0x9b8674e3, 0xbebbbb69, 0xd8c63d9b, 0x54711aff, 0x4df189e7, 0x9d187883, 0x0a0d2d9e, + 0x23bee7af, 0x625254be, 0x88b69493, 0x5ed43eee, 0x127eef5c, 0x4a676f7f, 0x0a07b068, 0xaef86c77, 0xd4fd56cf, + 0x04967feb, 0x3bf16ff0, 0xc12165f1, 0x215a08ee, 0x6cce5ce5, 0x2c096e93, 0x51bc0b17, 0x48353ddf, 0x3f0bd3b3, + 0x3e90f512, 0x3a23dcec, 0xbca4b4d8, 0x88a63ed3, 0x550ad721, 0x49a0858d, 0x721e8c42, 0xede8bf3f, 0x7b683508, + 0x4a6cefd4, 0xc60bdaaf, 0x97b99b10, 0x7605af1f, 0xcde64936, 0x1b519b2a, 0x409ea0d4, 0x48c30cdd, 0xbaf6f35b, + 0x495581de, 0x861545a4, 0xaab3f283, 0x3ec1d1b1, 0x8ae776e4, 0x74de6b8d, 0x55ded3cc, 0x70762ac7, 0x9191a2c5, + 0x3ae7f90d, 0xab38bcda, 0x1ef7f07e, 0x0e4cd2a2, 0x5126d516, 0x888fc47c, 0x62347b4e, 0x23ce7866, 0xdcb9ff02, + 0x9a4b40ce, 0x9759236b, 0xd0425f2c, 0x51d81c88, 0xf439a464, 0xae926380, 0x4f675c0f, 0xa306b8bc, 0xd048560d, + 0x4c6d23f6, 0x027eb8d4, 0x0736d717, 0x678d3858, 0x73ac92f6, 0x5f529300, 0xaa414ff0, 0x4a38ab22, 0x4afe077f, + 0x4ce50b6b, 0xecd3c48e, 0x8a135d8f, 0x7f8cdcd0, 0xfc3d0e42, 0xa5ecd9e5, 0x010fd0f8, 0x9576f60a, 0xf8f6d35d, + 0x90f5b52e, 0x040e31d7, 0xd36d202c, 0x7c3e256c, 0xc80d44ed, 0x05043894, 0x3075a010, 0x030547c2, 0x7d3924bf, + 0xb0ce5f9d, 0x110635c5, 0xf768d13f, 0x25c27628, 0x5dee6014, 0x225607b5, 0x04a1a99f, 0x8c42cf50, 0x80c8d73e, + 0x37c76836, 0x9c9d7098, 0x87e33a9e, 0x90264398, 0x548ec637, 0x2515efaf, 0xb7baeb98, 0xc14289b4, 0x150b1f77, + 0xb4372e58, 0x2257ee96, 0xefd10cf9, 0x41eaa462, 0x9c254b1f, 0x4ec38417, 0xe81f4b87, 0xf49d2aa1, 0x774c4b95, + 0x26059be0, 0x41b13d25, 0x5c585da5, 0xda898b90, 0x0302fb35, 0xa43697c3, 0xb2448660, 0xdd8e9d53, 0xad54c8b8, + 0x1af17c80, 0x256b5645, 0xb97e9dfa, 0x4d27a4fa, 0xe8ad3016, 0x8d9e9edc, 0xc787d1a2, 0x7381cf00, 0x6e7ee162, + 0x2115eb4c, 0xf0a818ea, 0xf7901727, 0x0985cc15, 0xf4bc5246, 0xffb45a40, 0x71510885, 0xf0e2f3df, 0x6c23c236, + 0xe5e209c7, 0xf3257f78, 0xad4a322c, 0xd20a9dc6, 0x5cd4e914, 0xb96b94ee, 0x8d9988d5, 0xde3b8879, 0x72048e36, + 0x3c24494b, 0x8de6066b, 0xbc6c1ed8, 0x7306ebfa, 0x57d2f83e, 0x80a449c9, 0xf520939a, 0xb6f7a865, 0x3bfe3b8c, + 0x524da44b, 0x6cd7b896, 0x4f61b945, 0xf0cbaec1, 0x644cfde9, 0xca956685, 0xca6ab9cb, 0x4f7306dc, 0x047a8a44, + 0x0cd7e116, 0xea381620, 0x6293638f, 0x2d5f8f9f, 0x38d77f44, 0x6602b20f, 0x34f60412, 0x333c30ff, 0x76b56e43, + 0x0a4c8526, 0x9ac206df, 0x3385838f, 0xb4105a60, 0x75aa9baa, 0x9df613e3, 0x552a7ce8, 0x9e020406, 0xcd515640, + 0x9f85cbd3, 0x24604af3, 0xcfc52faa, 0x759d453e, 0xd0006282, 0xc9b99d4e, 0x9b4df262, 0xecd772d2, 0x13ecbfdb, + 0xd04982df, 0x67e9eef7, 0xd1bf46f6, 0xe67055ae, 0x24710bba, 0x9283df5a, 0x7367ff60, 0x67fc487b, 0xd239490f, + 0xcf3663c7, 0x8bb9ca5b, 0x6fc18572, 0x14f9fbe3, 0x69b642f9, 0x0122927f, 0x031caa4a, 0x31681da2, 0xf2b82c6a, + 0xca5e74a8, 0x813acdbc, 0x8228646e, 0xcd0298d5, 0x2a8094ce, 0xd6af176b, 0x9adfec2d, 0x00a26af6, 0x8c43ca85, + 0x22c6c6cb, 0xdc3a96f8, 0x09587ff3, 0x04ef03fd, 0xb64f168f, 0xae844159, 0xd2e9165e, 0x51e76a97, 0x411cac38, + 0x1bc690f1, 0xe2f375e9, 0x3a0624b8, 0xceed8f76, 0xbd2422d1, 0xb9c8cc23, 0xc1801427, 0x2f78053d, 0xd5e89137, + 0xe35c60ef, 0x4168edbb, 0x16d2f78e, 0xda63b4ef, 0x6571a92f, 0xad46a00d, 0x69bd94a3, 0xa811a80b, 0x88ea6508, + 0x112b852a, 0x2edff43f, 0x920ab169, 0x4d22455e, 0x756320cc, 0x89763538, 0x7669db42, 0x53c91208, 0x8999f498, + 0xb84d315d, 0x81409211, 0x18562bfa, 0x52be63c1, 0x5c32e966, 0xd1f3e577, 0x1435006b, 0x563440bc, 0x50b7cf31, + 0xa533a836, 0x2e6958c7, 0xa07fc34e, 0x2a20cadf, 0x17b02011, 0x9da2a467, 0xca8d4e25, 0x68ace613, 0xb74834f3, + 0x06cf0cbf, 0x5d75b859, 0x8fc968f6, 0x64df4ff7, 0x8bbb57db, 0xb651c3f1, 0xa12d8891, 0x9bc00e85, 0xf9a86e15, + 0x64b95cbd, 0x0321f2b2, 0x7fcfe4a2, 0x3b323e04, 0x92063f64, 0x30fb7f58, 0x19b95808, 0x206fe10b, 0x7981299a, + 0x6e8eaec7, 0x90af2229, 0x544d1871, 0x25a8df2e, 0xd6397d28, 0x69d46e1b, 0x9875a7b1, 0x398f0573, 0xc9b295a0, + 0xaef9f2cb, 0xf2a3fa64, 0x63f43d37, 0x3a8da8a0, 0xdbae4197, 0x0317a146, 0x37c5c5e4, 0x29918603, 0xf03c0ace, + 0xe2982d56, 0x2bf22f0a, 0xd4516faa, 0x14c9da06, 0xbf28d302, 0x6581a43a, 0xa9a1b277, 0xe56c5765, 0x5cf614d0, + 0x9a0241f2, 0x4a04cfd1, 0xb1608b02, 0xa9f49bfc, 0xe33177c6, 0x8a56cd37, 0x704541ad, 0x3b36b56d, 0x09547c5b, + 0x887cfff5, 0xdc6dea4c, 0x6cabbf3d, 0x61b65c26, 0x92fac194, 0x80313d73, 0x2781d6c5, 0xed316c20, 0x82e7e1d8, + 0x6c6ad27b, 0x4b74e18c, 0xc407495a, 0x712985e5, 0x0009ced0, 0x992d9d08, 0x433d0eec, 0xe3a322d3, 0xd9c302e7, + 0xde124538, 0x95a4e2ac, 0x1f57d05e, 0x19c14d77, 0x7f8eda3d, 0xf10904c6, 0xe896fdd7, 0xb400a75e, 0x4394ce0e, + 0x01f4c035, 0xf6e89d37, 0xe52a993f, 0x1bc7b282, 0x74d39e7a, 0x91ab4d57, 0x6cd92be7, 0xe37cccc1, 0x87522656, + 0xb12d4b38, 0xe4a7fca2, 0x3b7a1c2b, 0x03ff1134, 0x53400df4, 0x14138449, 0x97f3d0e4, 0x8edc93af, 0xadf3b529, + 0x589bfdad, 0x1c3d3c8a, 0xd5015440, 0xa0dae3f8, 0x8bf7340c, 0x1db20a7c, 0xc5f88835, 0x6e2a231a, 0x982a0353, + 0x2fe83f07, 0x6ddcbf79, 0x1348b9a5, 0x23c8541b, 0xddabdff4, 0xf9cad9d1, 0x0a1c4bb2, 0xba4dfbfe, 0x74a3a20a, + 0x06a306b3, 0xf869264f, 0xb75e1b47, 0x77cc5af3, 0x6b08b3b2, 0x1e325ef4, 0x7a37b9a7, 0xf96a8843, 0xa597b151, + 0xc8cf47bf, 0x421cfae1, 0xb1d899df, 0x6ab468af, 0xdf37c731, 0x68903349, 0xf5f526db, 0x1c907a37, 0x2ab20020, + 0x76f9b087, 0x7ee9aa19, 0x942c9cc2, 0xf0abdc97, 0x10db03da, 0xe2b6726f, 0xa3361c6d, 0xbe097275, 0xcab63f89, + 0x8a5e13e8, 0xd8d362e4, 0xdbdbd058, 0x157fe006, 0x4203f1ef, 0x7b2c4013, 0x876e3d46, 0x6ef3614d, 0x9909be6c, + 0xa6bd454a, 0xd6978c13, 0xdb8787be, 0xd86ddab7, 0xad8919cc, 0x2f0fb613, 0x01ee0856, 0xb88d1326, 0xe97384f1, + 0xcecf11f0, 0xc239985c, 0xf5a44304, 0xc89c1128, 0x5bd57621, 0x397e7c28, 0xcd106dd4, 0x4e699e52, 0xa9e00c7f, + 0x32e13292, 0xc4ae3b81, 0x6fa22922, 0x70fe641f, 0xad0e49d5, 0x0c45583e, 0x116d15f4, 0x6dd60842, 0x051fce66, + 0x507341e3, 0x634a9a66, 0xac767802, 0x4b541b02, 0xd6c3aa1d, 0x1b187959, 0x120ae271, 0x846348bb, 0xb73b1200, + 0xacad1aab, 0xc6bb14ef, 0x8468020f, 0x9bc4be5d, 0x924af9b1, 0x826fd91e, 0x640ec8d0, 0x989bef68, 0x3b0a9833, + 0x99b82461, 0x3173d535, 0xd097a826, 0xc6fa81b1, 0x470273e2, 0xe515828f, 0x2c5bae9c, 0xbb842705, 0x9e3f52ee, + 0x646fa2ca, 0x7e0f6ec5, 0x05e345e8, 0xdee4d33a, 0x28e6a68d, 0x3e3bff60, 0xbedd432c, 0xa0bee175, 0x73b995b0, + 0xb01d38b2, 0xcf566983, 0x19e43bfb, 0x77abebbb, 0x4e4f7d60, 0xbaf29df4, 0x9d4adbb9, 0x268dc23d, 0x68c99157, + 0x4594f78b, 0x65c6dc7d, 0xe8abd234, 0x2920fb2d, 0x6c5eb757, 0x59e2ee62, 0x36e341e8, 0xb233fbd5, 0xd3e9c603, + 0x3b2d6bae, 0xeafbf0cd, 0x9ef57d63, 0x1013e5d5, 0x0d63d675, 0x7a83c019, 0x63c85521, 0x2710ae8d, 0x4840995f, + 0x9f52f72c, 0x316c131d, 0xa023462b, 0xadfd2984, 0xf0439750, 0x4545ef8f, 0x902110c6, 0x4737d080, 0x3b2d8600, + 0x4e770d4e, 0x15e2188a, 0x9f005050, 0xda657f59, 0x76a9ce61, 0x2a3e3364, 0x16398753, 0x34d29a1e, 0x8d647459, + 0xc4110267, 0x5b900120, 0x16110c6a, 0x69e83933, 0xbfff1d81, 0xa8b8b539, 0x9b1df9a4, 0x01f8373e, 0xf98159de, + 0xa49e859c, 0xda3b30be, 0xb7574ed2, 0x02b1a8ea, 0x26e0af06, 0xf0c8e654, 0x1da2fe17, 0xb7ee000b, 0xd29733e6, + 0x6abeac12, 0xd11d16bf, 0x72dd1025, 0x07e21963, 0x6c3d1e8d, 0x3a42f23a, 0xd7ed994d, 0x689814bd, 0xecc3cd53, + 0xcbd5e6a4, 0x68dd3eeb, 0xc1d350ff, 0x823629be, 0x4353baf5, 0x966af430, 0xfed42627, 0x5542cb63, 0xdf545660, + 0x66373bd7, 0xfd2b8077, 0xaa8be3a2, 0xafc45879, 0x6a02fb9e, 0xa2ebbf1e, 0x7d168576, 0xbfbd7828, 0x31237655, + 0x51445d00, 0x2901a02f, 0xcc0643e6, 0xeabdff80, 0x9e99f17a, 0x13d5ffdd, 0x9e21d41f, 0x744a304f, 0xe19bdaad, + 0xe7c7d03c, 0xd318906f, 0xd0d807d0, 0x36cb6dba, 0x0eeb7464, 0x8decb894, 0xf1fbbcff, 0x6f2ac892, 0x829b9ae9, + 0x9fed91b5, 0x53da972d, 0x716feb96, 0x81ac9609, 0x5392d37d, 0x51fa5621, 0x9fe82294, 0x73ecd083, 0x82970fd3, + 0x63ceb2a9, 0xefa29c40, 0x1f1c0118, 0x6828a941, 0x798c524f, 0x962ea210, 0x3b4fa8f2, 0x20f63148, 0xf7d38ebd, + 0x5598d1d7, 0x5fdebbb4, 0x24eb15cc, 0xf9dde275, 0xfb33df92, 0x2812a4f2, 0xd0878c99, 0xe7e6314c, 0x8f3fea5c, + 0x2c050c93, 0x7a4c38ac, 0x4e0c6753, 0x5dc8eeb4, 0x6e0c1ddd, 0xa146fdb6, 0x3823ec3b, 0xb72e2b55, 0xa7502597, + 0x37be04c5, 0x7633a4f2, 0x09b4589a, 0x931adca9, 0x1539083a, 0xc2f371eb, 0xa4c36187, 0x2325c959, 0xe2181ca7, + 0x5c07d95d, 0x37bde2e2, 0xe11aa176, 0x2ee746e0, 0x5c1e85a2, 0x2fae19d6, 0xb871bc32, 0xc6dc2105, 0x1c52d096, + 0xc3703ffa, 0xe918b6ef, 0xca445335, 0xd3054a8e, 0xac3d1a80, 0xdbff0a3d, 0x58478b58, 0xd29c1e10, 0xb738875b, + 0x39065ad1, 0xd3f19b58, 0x0a51ca77, 0xbbd399aa, 0xe0e0b44d, 0xfe34d1e8, 0xf09b9bff, 0x223e861a, 0xfbf1d82e, + 0xd191d9a6, 0xafdeaf86, 0x05cfa07a, 0x52ab74a2, 0xa63566f2, 0xf84d2886, 0xcc389eca, 0x3e2e1024, 0xb079336f, + 0x87651c5e, 0x4f945ec7, 0x2175bc37, 0x7cdb11af, 0xd9cd809c, 0x2bbfdd17, 0x74826326, 0x5af4059b, 0xfd293913, + 0x3ce6ce3c, 0xbcd13b96, 0x2c4c2228, 0x521f91f1, 0x02abf5e5, 0xf8ed1c39, 0x285ef297, 0x9e39389b, 0xb578670a, + 0xaa100f0d, 0x15f8488d, 0x380d2f29, 0x75c52ba5, 0xa3ae55bc, 0xbda1e9f2, 0xcfe7ad74, 0x3b4dd8fb, 0x147e5c7e, + 0x351759ba, 0x1093f3f5, 0x792a34db, 0xff62468a, 0x23ce2a29, 0xb6dcdfff, 0xa95352fd, 0x44d16958, 0xcde3a6f0, + 0x355770e4, 0xf51697d4, 0x13d13cd3, 0x9c25eef3, 0x6f94290f, 0xcb263b95, 0xfa53d77e, 0x58876597, 0x816f3182, + 0x848067a3, 0x368397f6, 0x0ef2611c, 0x96bf1817, 0x2a033255, 0x008d07d7, 0x8d6b9871, 0x09eef52a, 0x3d29eddd, + 0x9ad4f63e, 0x6417602e, 0x5cd8e384, 0x5c3422b5, 0x6cf74141, 0x304b7637, 0x44ba7672, 0x691bd504, 0x27f5ce3e, + 0xf67c5875, 0xf7278110, 0x0fdc4fcf, 0xd2bae543, 0x7933a05b, 0xaf90ec16, 0xaf7e0099, 0x927cbc2d, 0x1364644d, + 0xd5baa158, 0xb5b8c0be, 0x292af6b5, 0xf8b9b847, 0x313864b6, 0x1150b877, 0xd50c5ced, 0x4d6310e7, 0x045dabd4, + 0xa99b8da8, 0xfd0aeaa7, 0xc01c7297, 0xa095ae9f, 0xaa8730d4, 0x91572081, 0x4b0c8041, 0x4008da70, 0x29f5770e, + 0x6f07d1f7, 0x2dda5edf, 0x222b7823, 0xc0a101a5, 0x5430d396, 0xb78876c8, 0xbbb79126, 0x49f26673, 0x7fc5c3a2, + 0xdbbea7eb, 0x6c90723d, 0x99266757, 0x53ab24df, 0x2a6700c5, 0x9ebdbd23, 0x573cddc4, 0xa36202aa, 0x6ff68efc, + 0x32f83911, 0xa08f59dc, 0x787a1d28, 0x51f64d8a, 0x61c7173d, 0xd35fde64, 0x31db774e, 0xac4e56ea, 0xd322a6e2, + 0xb6a5f40e, 0x27f1141a, 0xe62ac560, 0x454c95d6, 0x258206b4, 0x3e5b7ba5, 0x255a2922, 0xb1e3f6bb, 0x902aa16c, + 0x9d564569, 0xcac98a72, 0xd9b1164e, 0xc14d8fd8, 0x6b560fe0, 0x866dc236, 0xc2612452, 0x87b5e2b6, 0xb2038545, + 0xca0a7f08, 0x649e3e65, 0x7285d943, 0x84813fe6, 0xbfe40af2, 0x2ffa37e3, 0x600ed01b, 0x5e5ac947, 0x7d8675d4, + 0xf1b0b754, 0x1349e05a, 0xce265273, 0x92b2fd9f, 0x6c59fa1d, 0x6e3d8e5c, 0xed6ba270, 0xe03802d4, 0x35a572a3, + 0x07c3c676, 0x0903bc12, 0x53fec98a, 0x2b14e5f5, 0x2c418816, 0xf97676f7, 0xfa8fc848, 0xd9825c94, 0xfcf3fb76, + 0x559099cd, 0x401358f6, 0xfaf0ef6f, 0xae6bccdf, 0xbff9e68f, 0x5ea9dbad, 0xe2fcc30b, 0x68b78e6e, 0x3096a942, + 0xa08b32cb, 0x33d07bff, 0xe275eba8, 0x90c79b9c, 0xb35ac5c7, 0x712c769e, 0xe57fbcc4, 0x5eec80f8, 0x54d6043d, + 0xead55a9b, 0xe8bf8904, 0x2a291d43, 0xc798f1d5, 0x0964e382, 0x6b0d18f5, 0x2a7868b9, 0x2e05dd65, 0xbaccb38e, + 0x0dc890e6, 0x905fe2d2, 0x07153f42, 0x7a165797, 0xcb27078b, 0x669e2a7e, 0x25132618, 0xc6e50640, 0x4f0a59f9, + 0xd09eed55, 0xec94224e, 0xee3e8e8c, 0xc6d10353, 0x5d494953, 0x8581bcb5, 0x7ea9d6ef, 0x43895f52, 0x9e1fa00e, + 0x4e7c196f, 0xd6a70268, 0x782df4e5, 0xbfd57ce1, 0x2f8333f9, 0xb290043b, 0xed9a1499, 0xd4f40e25, 0x1f8c449a, + 0x12b461cc, 0x55b48bdf, 0x3c12c248, 0xf9fe1e5e, 0x422c06de, 0x44a8a929, 0xf871301b, 0xe8d78307, 0x612d9ff6, + 0x150c3318, 0x9bcb457e, 0xa7356d26, 0xb2b6b81f, 0xe32dc831, 0x770a5958, 0x73c85284, 0x2e73912f, 0xac5742ad, + 0xaa1c22e3, 0xff598065, 0xc49fae91, 0x15c5282f, 0x966af8d2, 0x1d906683, 0x6688e000, 0x5454919b, 0xb90a3e97, + 0x438c2139, 0xf2f21acf, 0xed29388e, 0x97aed648, 0xa970f66e, 0x6eba48de, 0x37a2c033, 0xeb32b6d7, 0x984c8b2f, + 0x47dfeed4, 0x4cb04e12, 0xa4159e1f, 0xdfb1e0fe, 0x4322f163, 0x7f3560a4, 0x7666f35e, 0xa1e3894c, 0x95f4ea53, + 0x5a78d02c, 0x3bae68d5, 0x863d0041, 0x86a25424, 0x8ed03ab3, 0x8fb9fdcb, 0x36278d15, 0x6e674be6, 0x78337675, + 0x74a406e5, 0x40417df1, 0xfc17f0d0, 0x7ad5e2ea, 0x124d8942, 0x7d16800d, 0xe0f843f7, 0x4da1ca92, 0x0b20be25, + 0xe9ab49f5, 0x6a1e8a0e, 0x7465d350, 0x33489ff2, 0x89d5bfc5, 0xb3eb7579, 0x681305be, 0x2c8332f4, 0xdb358155, + 0x70dfc842, 0xa6cd4c37, 0x62f16010, 0xc118a59f, 0xe65f0704, 0x49585f44, 0x41045724, 0x4240be76, 0x579f2745, + 0x553f1aff, 0xca3b1932, 0x91d1602a, 0x953f4934, 0xbb7ba233, 0x9a062f29, 0x4515e834, 0x5c48444c, 0xea0b659b, + 0x9c7f02ab, 0x2cb5f61e, 0x735011e6, 0x2c04bf22, 0x72b44fa8, 0xa191269b, 0x85575e6c, 0x34801a04, 0xfa55ba43, + 0x060e0174, 0x1e0499fe, 0xda9bc63c, 0x6b7bf794, 0xc89a72d3, 0x856b2030, 0x9dcdc47a, 0x43aadd4f, 0x290c6ed0, + 0x3b83bb71, 0x3db10c2c, 0x77db0df7, 0x25ff434e, 0xab2eb293, 0x1a9c914d, 0xcd9759e1, 0x7e735e4c, 0xa5af4a1b, + 0x967011fb, 0x367a95d5, 0xaf7c0e82, 0x9b976608, 0x05f62104, 0x2b2fef92, 0x38ec66da, 0x17f0c4e6, 0x945d0b1a, + 0x4567928b, 0x0fa1ddb5, 0x05f462d4, 0xb010b2fe, 0xdadd98f4, 0x318711b7, 0x5999b242, 0xeb947a16, 0x74728565, + 0xb261d3d8, 0x638d10f2, 0x30a287ce, 0x52e2f5c2, 0x5f2ad086, 0x4b79d3cd, 0x3b1523fb, 0xbb27ff68, 0xf6f42138, + 0x476621a6, 0x240c4fa9, 0xc0d4e7f4, 0x58d7e5da, 0x31bebb37, 0x622f8fe9, 0x8e91e65c, 0x710abbea, 0x5c4e101a, + 0x4390535b, 0xda358b59, 0x47fe45be, 0xe4058a5d, 0xa0d58671, 0x1129274e, 0x285950f4, 0x2a70ca0e, 0xc8f62228, + 0x46d11295, 0x07dc4960, 0xab42c5af, 0xda72ec4e, 0x2568f836, 0x831b00d1, 0xb9e66421, 0x91b54107, 0xa0d6eb36, + 0x70acffc5, 0xd8bd3240, 0x81063ae8, 0x9bfcc840, 0xe6350e36, 0x09be9c0b, 0x375062df, 0x78f0853f, 0x2f2a0b32, + 0x0f19babe, 0x2d90ed01, 0x983783e8, 0x48ae5bcd, 0x33fe58f6, 0xa1c839d5, 0xa6ec809a, 0xd80c1c0e, 0x218f6307, + 0x903e6a2f, 0x6a65432d, 0xa1e0e4b6, 0xe3606099, 0x7d9da628, 0x0e6d14eb, 0xaa917983, 0xbfa84e35, 0x5b7574e4, + 0x2b619aa6, 0x392590cb, 0x115ff1e2, 0x842b66b6, 0x465116fc, 0xd7532c92, 0x38cded96, 0x43814e4d, 0xfef6da0e, + 0x6fb8b41c, 0x0f743270, 0x430ccb8b, 0xec0bf97d, 0x9050e71c, 0xfbb7d3da, 0x7217cf81, 0xb49b5419, 0xa7964644, + 0xeebd7c1b, 0x9f8e1795, 0x0775b7d9, 0x0caf03b2, 0xbe796a85, 0x23c67a08, 0xd53d1faa, 0x6f12c81e, 0xeb1f4b61, + 0x19b44f65, 0xbb1b9713, 0x2fcfe248, 0x54a27d56, 0x29aa6065, 0xa81344b5, 0x2ee8462a, 0x1d428522, 0x4d224079, + 0x6ea5117f, 0xf08430e9, 0x6c12143d, 0x701727d9, 0x4ee2606d, 0x4a2fc638, 0x29ed3969, 0xd0c0b9a8, 0xcf7a595c, + 0xa821d238, 0x85392d71, 0x5fc075d3, 0x52dd84a2, 0x84b07e9f, 0x3ad2ae2c, 0x3c100942, 0x53b2a6a4, 0x405db181, + 0xde40adab, 0xd8e6e995, 0xcd0abb37, 0xd69e9895, 0x6745eab4, 0xc15cdd65, 0x749c5f78, 0xe0239d8a, 0xdf6d6084, + 0xfe4696c5, 0x6860b5f2, 0x4b63fbb3, 0x29a90b4a, 0xca3f7036, 0x15208e1b, 0xd9c03a7a, 0xd31b1215, 0x9e0f7a3c, + 0x33f7e3ce, 0x5baf1cc0, 0x609b70f7, 0xa9aacc22, 0x1f4c0245, 0xce151ee8, 0x6cf89044, 0x55db8dd9, 0xaa606036, + 0x697f85c1, 0xaa42f4b8, 0xb071d188, 0x798fd3f9, 0x311f879f, 0x116d4328, 0xf1597163, 0x15b88af9, 0x11d886ea, + 0xcb6346b5, 0x57573e17, 0xf2de5e95, 0x1982f9f0, 0xf36cc1aa, 0x7ee5faca, 0x487bdbde, 0x85accf71, 0xe766dcca, + 0xac9e7e66, 0x0c94ea2a, 0xf12a4714, 0x095c8673, 0x6d54e1c6, 0x1f41ee7d, 0x2dc2b4ab, 0x8443de73, 0x1fa3a5ca, + 0xbedbe95f, 0xc49d39fa, 0xa446809d, 0x1b063405, 0x96ebb833, 0x03201c8c, 0x4499c9c0, 0xb8494c0d, 0x3ba87a8d, + 0xb7c499bc, 0x0bf61676, 0x15cb2747, 0xc2d29d2a, 0x7694b6fe, 0xbcbad00d, 0x9ad0e388, 0xbc33b345, 0x89818f68, + 0x7b989223, 0x401fe4e4, 0x00588044, 0x5f4ea9a8, 0xea4478de, 0x4e8ca574, 0xbec1cfd9, 0xb48a7837, 0xfae2fc76, + 0x9ee8b2b9, 0x78483772, 0x1aaf76e1, 0x2b71333b, 0xaaa718f7, 0x5f7c3a67, 0x6249703e, 0x9cd4782a, 0xd900f48a, + 0x22440478, 0x5ca7820d, 0xf91f00e4, 0xad690ca0, 0x78f9829a, 0xe2c6e61c, 0x1e9f7b4a, 0xc0e597d1, 0xb4bd2846, + 0x743eae63, 0xe21237b1, 0x10894b17, 0x70f3f946, 0xf841cfb5, 0x8fa0094d, 0xce3c074f, 0x2ef37ca4, 0xdf146b5e, + 0xaf030e5d, 0xd2d7d74f, 0xf5eb4fd0, 0x8d480b71, 0x714ac879, 0x75669cdd, 0x9363f3ae, 0x4e939b15, 0xcfa7cabf, + 0xda59d42f, 0xfc6edaed, 0xaa73c3f6, 0x4cf89592, 0x873dc512, 0x2983f094, 0x4117edcf, 0xe08c16e9, 0x336aec1f, + 0x97625b41, 0x45383818, 0xd89cc81b, 0xc78ae3bd, 0x3a676c8b, 0x5b44809e, 0x609229c7, 0x2cdd583f, 0x8fa4e997, + 0x2d27fcdd, 0xe064667d, 0xb70508ec, 0xa5580b7a, 0x7724c9b0, 0xe104b6ec, 0x121463b2, 0xcecc86d3, 0x159dfd0f, + 0x21eb152b, 0x1b7dac31, 0x36d0f5e5, 0x0d6ad546, 0x34a07ddf, 0x7d497228, 0x7b1c30e5, 0xd22f6850, 0x395b644f, + 0x4aed7509, 0xd375458a, 0x7b3efd7a, 0x81d3b6fb, 0xbf0d2b36, 0xfeb53783, 0xe21f7095, 0xac5812eb, 0x53af9bc7, + 0xd6e0b138, 0x29afa524, 0x39feb23e, 0xdae8a59c, 0x6a9067e5, 0x9ff8ca5a, 0x50489447, 0xbc9d6952, 0x2324c3f5, + 0xb946108e, 0xe342051d, 0xc7854cb5, 0x2ffebdbc, 0x15e1de39, 0x99997a29, 0xff2be9f6, 0x2408e41b, 0xa76b4873, + 0x7f3cf740, 0x9319db4d, 0x0b64cb6f, 0xf00ce130, 0xf4f28c9b, 0x8242699b, 0xd9f7a2de, 0xa8ffe664, 0xf0c1dbe1, + 0xe97d6be5, 0xefe9f562, 0x960b42a5, 0xa1fe565b, 0x35b9bec8, 0xf19f4188, 0x3b0e92cb, 0x5b1ac1bc, 0x36f1468b, + 0xa1cc4e6e, 0x1bbc085a, 0xb3ffdfbe, 0x52e9f5fa, 0x8c1d8f10, 0xe166e890, 0x32ed3765, 0x2275b4b8, 0xd5449d1a, + 0xd3dae0bf, 0x8ec14285, 0xc27b3573, 0x80348b34, 0x939fe11c, 0xa9e27edc, 0xf2b93fe8, 0x37aeecfa, 0x35aca3a2, + 0x5429f510, 0x88009039, 0x5aa0241d, 0x7f296515, 0x0909da20, 0xb8ac693e, 0xd9238692, 0x8d804849, 0xebd4f93b, + 0xb10edbbd, 0x4e1ea44f, 0x465547aa, 0x61274f8b, 0xbf21c997, 0x6d2954d7, 0x47f5f537, 0x5967f459, 0x3d7bfdfb, + 0x7f52f1fc, 0xf98b67b1, 0xd3bab966, 0x1b9405ec, 0x8643aaca, 0xf2b96e12, 0x12c26e9e, 0xfe13b88e, 0xbc169065, + 0xb3c70e1f, 0x2e5ad4be, 0x6decdeee, 0x62babb48, 0x412828c7, 0x0eff5fa7, 0x94046a3d, 0x76df0233, 0x59964fd4, + 0xfa26a224, 0x5546af76, 0xf48afaac, 0x97020e3e, 0xaf588781, 0x219aeced, 0xea3f8856, 0x611f9676, 0xbda351e2, + 0x7ec27b4c, 0x4a016f45, 0x46ccdc46, 0x2b0e9af3, 0x1158370a, 0xe9c6691d, 0x1450f98a, 0xc9bad6c1, 0xc5b06de8, + 0xa1940953, 0x751666ae, 0x0451a366, 0xb7a6ad13, 0x229a84e5, 0x66c45636, 0x644b714a, 0xc392edae, 0xcd80cec3, + 0x4b179b5a, 0xe6d1ef20, 0xb5ee0a9b, 0x778556e1, 0x354d8fcd, 0xd6f9438f, 0x5d699a89, 0x3a387b4b, 0x47d72ad6, + 0xf6160733, 0x61b54376, 0xb7bf3ce7, 0x78c06b3b, 0xe31671e8, 0x6b67e599, 0x6c3cf80e, 0xcca71b8e, 0x45048e10, + 0x5ab353eb, 0x50e813f2, 0x5d6f13e7, 0xacfa1cd0, 0xf3ac4d2a, 0x228d19ca, 0x37a8edc1, 0x5789b88f, 0xb5e363ff, + 0xc550ad66, 0x0753e700, 0x5d94ba14, 0x5b5480f8, 0x9c1f6350, 0x190dafdc, 0xaf9736d8, 0x74966f4c, 0xc91562b4, + 0x5915e2e9, 0x6ced7a53, 0xaad3bfb6, 0x2adf258c, 0xee4560d7, 0x13e6e9ed, 0xbe74d27f, 0x35e6807c, 0xc1fa2aed, + 0x74bb45b4, 0xa46d76b9, 0x572804c8, 0x121bdb83, 0xa0d3efbe, 0x13879485, 0x337b3c86, 0x66732ff3, 0xdf886546, + 0x249e47fa, 0x280207a5, 0x4e0387f3, 0x508f209c, 0x293b1072, 0xd3e3d84c, 0xca16f548, 0x22ca3508, 0x9f5d5395, + 0xcecb3bff, 0x4bfe25ca, 0x579e940d, 0xd166749d, 0xbe384e76, 0x25390cef, 0x4aa7c5d9, 0x305f8dcd, 0xd25a54b6, + 0xc581a8c1, 0x76a1ca16, 0x4784bdba, 0x6ab82f77, 0x214ef592, 0x23022934, 0xb45ce320, 0x7b5c3be5, 0x24fb136b, + 0xc27de494, 0x4f8c1252, 0xf2fe0d8f, 0xa45da69a, 0x00cad7a2, 0x08d83dd7, 0xb11d74bf, 0x878f5b53, 0x16de2549, + 0x877a1f6a, 0xc044a23d, 0x022c4e86, 0x49725369, 0x822073ce, 0x960fb5b3, 0x01b41e29, 0x35b839f9, 0xb468a849, + 0x050f8164, 0x744825d4, 0xd60bb98a, 0xf948a7a8, 0x5b701c8a, 0xb61447f6, 0x078d2a39, 0x5fdefb97, 0xc6168364, + 0x5dafdcf2, 0x974e8c8d, 0x7d64f8fd, 0x03a52695, 0x747d3f30, 0x698c0220, 0x7305ecbd, 0xd1664186, 0x3faa1679, + 0x17c1c3cc, 0xe881450b, 0xa573f680, 0xc20bc760, 0xec4da340, 0x7519b37d, 0xe78dc2d0, 0xe91ff230, 0x9185f78c, + 0x9b7590b9, 0x5907e9de, 0x03f17663, 0x301f3e91, 0xf3796c83, 0x696688e7, 0xd9e44903, 0x3875e4ae, 0x534d3b44, + 0x6b98fd16, 0xe4e92e79, 0xd83c5ac6, 0x2117b418, 0x01463ed3, 0x6d78c4e7, 0x129c1b30, 0x74c225d1, 0x5a3c9113, + 0xe67bbb96, 0x041ff2e2, 0xddb025cf, 0x013f4253, 0xba1e84e5, 0x37f2001b, 0xa66c5f41, 0x7dd52978, 0x966dc47f, + 0x6bdda0cf, 0x63b44195, 0x8558c34d, 0x2801b4e6, 0x59b2dc73, 0xbea9310f, 0x4c12ac91, 0x6dc55f06, 0xa4170add, + 0x78705bb0, 0x5a6c21c0, 0xac639054, 0xf7f878c2, 0xdc7175b1, 0x7c029539, 0xc29eb05e, 0xce79466f, 0x072ee17f, + 0xb6beec2d, 0xba762be9, 0xc5b2ec67, 0x4280c13f, 0x39cf4732, 0xd1c3bafa, 0xde0ef94a, 0xe0304304, 0x1a6dd67f, + 0xf5291eff, 0x3b1ad05c, 0xcb4c44d3, 0x8af78599, 0xb3fca945, 0x3e216972, 0xe6f60442, 0xd72bee7e, 0x1de5bb75, + 0xf88fb29e, 0xc864d367, 0x7f4e2a50, 0xcd475bf3, 0x91d4273d, 0x9bc26f22, 0x0d3c65e1, 0xdeb11909, 0x0901db45, + 0x5ff57daf, 0x3a0b1626, 0x7c8998ee, 0xc5181049, 0x5879ca71, 0x042d3cd8, 0x73cea3a2, 0xb7846b24, 0xf087d8f6, + 0x5253d539, 0x43eb4f50, 0x4f2896d3, 0x85a74782, 0x9da2fec7, 0xc5293b2c, 0xbb18ec7e, 0x4234f356, 0x474f537f, + 0xc39896d3, 0x10c0863e, 0x14566805, 0x5504b142, 0xf7112f16, 0x45efbd6b, 0x5c01eb24, 0xb49851b8, 0xa972d021, + 0x4226a0bc, 0x90c33171, 0x91290a57, 0x9890cb06, 0x43b3d5cb, 0x8f04edbb, 0xd5ad2151, 0x2ddaf706, 0x6c4399ce, + 0xac19df89, 0xa09af734, 0xf698a96d, 0x48aba18d, 0x3d08c84f, 0x38ba20b3, 0xe84cc894, 0xf7498525, 0x522e3804, + 0x966279f9, 0xe7845fed, 0x1d76a1c3, 0x7169bf87, 0x30de79fa, 0x8d29a7c8, 0x9bc9f6a3, 0x0d75fee0, 0x90ad6e88, + 0x48458329, 0xbb4a10b3, 0xcf09bae5, 0xbdc7cbf3, 0x61eb86b8, 0x4d0ca58e, 0x12141184, 0x65a6ead5, 0xa1c09186, + 0xb18dccda, 0x189378bb, 0x5d53c7c2, 0x13fbff02, 0x09804865, 0x50f9f473, 0xba00688c, 0x2a7ec55a, 0x2d6bab12, + 0xa023423d, 0xba333290, 0x68c29f17, 0x226055b2, 0x3565ef64, 0x01192857, 0xa5d66ef8, 0x59389522, 0x8883542b, + 0xe6e96714, 0xaac06793, 0x959067f3, 0x4a85bcab, 0x8eeda920, 0xc6906bb1, 0xa7aca3bf, 0x2d348bd9, 0xf6a0945e, + 0x9b67b197, 0x924ecd86, 0x87ae926e, 0x26d69e7b, 0xe16aa4b6, 0xe989e066, 0xa25ca993, 0x81b53e5c, 0x5431182c, + 0xac38557c, 0x64be9fc8, 0x2eab76d0, 0x79122ef7, 0x53197c79, 0x4c45f33a, 0xc3a68069, 0x6d99c068, 0x848d7bc6, + 0x4414e9ba, 0xf9c6327d, 0xa8bf8b59, 0x934dcede, 0x7526cbc4, 0x907d8322, 0xf2c7739c, 0x71e36884, 0x69309ce5, + 0xe7652475, 0x072c9db2, 0x2c010391, 0x5b2f352f, 0x435b31e5, 0x3c78004c, 0x66df86ad, 0x3296efdb, 0xb5b97534, + 0x805fef10, 0xa6cbbee3, 0xae9599a8, 0x45a6beef, 0x26d7a2de, 0x6cf23f75, 0x2ece9c29, 0x7ea16eb0, 0xe7e93464, + 0x10e3828a, 0x9d8d76cc, 0x75ddd06e, 0xbdac8f58, 0x065f4144, 0x00d9d1a5, 0x3befa1d1, 0x66af9766, 0x3921c088, + 0x8b2aa80a, 0x71cd19e9, 0x4a942531, 0x656cca6f, 0x03b9551d, 0x40b0d0d3, 0xd8892b5b, 0xbb0fea5c, 0x1a60e6ce, + 0x68d77395, 0x977a5eb5, 0x29f4085e, 0x450c17e0, 0x8d6e8950, 0xaca9399b, 0xd80d9fbf, 0x859fb2fe, 0x43ae03eb, + 0x73e3317a, 0x06568b1c, 0x0bd430da, 0x57a7e48f, 0x9d507acb, 0x72a934f1, 0xe25e66b3, 0xee0e8fe2, 0x55d2e51f, + 0x3bdd2144, 0x9bda42b5, 0xfee79eb2, 0x84eb6493, 0x0ad67f88, 0x977ee89f, 0x0595b2f6, 0xf82da76a, 0x844b4ab6, + 0x95a2a517, 0x764df391, 0xf8b4f3d1, 0x9aa06507, 0x4c7dec76, 0xb717b3da, 0xc1b29cd2, 0x06b71777, 0x8ccf05d4, + 0xca57875b, 0xcfd5d7af, 0x413cdbef, 0xc0dbe51b, 0x6ad61f7a, 0xbf37b522, 0x51319932, 0xf5de3ae2, 0xd5b2c189, + 0x643ee0e8, 0x62f3668b, 0x6a3e2124, 0x82a9cee8, 0xaecf8eeb, 0x9dee67de, 0x9ec60bda, 0xed06c7dc, 0x7ae3c161, + 0x187574e9, 0x9da95d70, 0xcef24fbb, 0x32e40e6c, 0x4b5c0325, 0x91e89083, 0x2703e4d9, 0x7f2f52f8, 0xf74eb042, + 0x3e2c81d8, 0xb993a0a3, 0x4bb65923, 0x4fe1e6c9, 0x4fde8d73, 0x386f31a6, 0x3d3b008c, 0x65fe4672, 0x7539cc1e, + 0xa972782c, 0xbdb2442a, 0xd892177b, 0x9cbc7da2, 0x36186fc9, 0x7d1dd572, 0xd63527a9, 0xbeea4c49, 0x72d151be, + 0xe49097a6, 0x7eca97f3, 0xb0e18b42, 0x0acae167, 0x3628e495, 0xace12268, 0xfd092177, 0x1fbfe09d, 0xb2df64e8, + 0x9b1349a8, 0x3174f7f5, 0xb4905483, 0x894b6b7e, 0xc09f42b5, 0x11185b78, 0x3ea0f283, 0xff03dbe0, 0xb624c901, + 0x1e1fdb95, 0xbee1f556, 0xc6924dc3, 0x2412f627, 0x6208e2a8, 0x2b2d0eb9, 0x8f1eb983, 0xf08cc935, 0x506f61c4, + 0x74ea1271, 0xcaa59629, 0x37c07f16, 0x77876fae, 0x8023e684, 0x943da4ff, 0x717a25db, 0x79b1c8f4, 0x53d575c2, + 0x474b91e7, 0x2734f8ab, 0x4f15c69e, 0x1f09852c, 0xe45b5b3f, 0x8e853d9d, 0x45c4ddfd, 0xd7993465, 0x73ee6c55, + 0xb7588d4e, 0x776465c8, 0xd9741752, 0xcf794861, 0xc3fbe69d, 0xace92dd6, 0x2a43bbe2, 0x5a2065cd, 0xc0e75226, + 0x536a275f, 0x793a6154, 0x65ba6fe0, 0x9b83f257, 0x8f5f66d7, 0x6f6bfa98, 0x011d5e8f, 0x00541f5c, 0x4b203f11, + 0xb0be47f3, 0x414cc517, 0x0ab45c7b, 0x60cc4fbe, 0x95862295, 0x398a4910, 0x51f0edbd, 0x207ce78f, 0x9d55b6fb, + 0xce408b67, 0xb1268cbb, 0x38fa3048, 0x917e2551, 0x2056d4e4, 0x3e011b3d, 0xdc9d3763, 0xc8fad911, 0xb3cf3c29, + 0x428b253d, 0xc32a0ea0, 0x3a2358b2, 0x036217b9, 0xb7a07972, 0xb3abcba5, 0xeb371489, 0x5a9360be, 0x01a6d239, + 0xb2ff65fa, 0x75ad7f49, 0x43f5f71e, 0xc2fa075a, 0xdccccb5d, 0x69787402, 0xac568ab8, 0x88bea7fa, 0x7b88e919, + 0x54b0abd9, 0x6189732a, 0xc4ba977b, 0xb33a219f, 0xabce9d9f, 0x9ee8abf2, 0x6fe61a6b, 0x2847d552, 0x94039a58, + 0xbbe73f90, 0x166790de, 0x43e8fbc0, 0x94e2e60d, 0x782e7ba5, 0xad652d77, 0x52df98e6, 0x10398a17, 0xc3e0420d, + 0x71dd4442, 0xb5589f8a, 0xb129d2a3, 0x62ab45ac, 0xb026db4b, 0x66fc8609, 0xd75223c4, 0x784a863a, 0x0ca5ed09, + 0x9ab40388, 0x23aebf0e, 0x13f8dfd6, 0xb1376bb8, 0xa4cd5aac, 0xd672af25, 0xafd65df7, 0x04648847, 0x85d6a1bf, + 0x1b7bcee8, 0xd27a47b6, 0xade45be7, 0xb8f2179c, 0x2625bd00, 0x0e6e1071, 0x509e5e1d, 0xa7d514c6, 0xb61caf5c, + 0x65936994, 0x62386e73, 0xc848a9d1, 0x2a470dd4, 0x41c09a58, 0x56ab247f, 0x5244c3a5, 0x7ba1b02a, 0x4458f8a2, + 0x4e711533, 0x084196ad, 0x501599d7, 0xaa653c25, 0x772ce0aa, 0x7f5484ed, 0x56ca75df, 0x5b8ddbb5, 0xbb42bfb6, + 0x19eb6efa, 0x895a4b6d, 0x9e77bab7, 0xe259d89f, 0xbeefd513, 0xf2c22de0, 0xe4b3661c, 0x9a08ee06, 0x388df900, + 0xc53abc8a, 0xf5e35715, 0xc1f043d2, 0x655e2657, 0x26db2b57, 0x68f052e5, 0x8a4a3ef0, 0x3897697f, 0xd218cc64, + 0xa7739a16, 0xdd20be72, 0xb8dc0d01, 0x817a20db, 0xd51d33e3, 0x9deb52f6, 0xbcde491d, 0x314bf2b5, 0x38eb9080, + 0x1f3c79b9, 0xb8a30a66, 0xd65a56df, 0x241561e3, 0x5e40af92, 0x419b8e12, 0x1042d038, 0xe80faaf0, 0x2fb24041, + 0x915a6114, 0x00f3dc27, 0xd915189b, 0x5df5d58f, 0xf191d0dc, 0x68baf718, 0xf6fa4ba8, 0x6a87bfba, 0x55bdc451, + 0xc5855fd5, 0x5eb02d73, 0x7cf72118, 0x95a48e09, 0x14056103, 0x06988bc9, 0xe05e7cc1, 0x2d2c0c21, 0x2e21aab9, + 0x8b86d749, 0x152f06be, 0x41419c0a, 0xfcec2c36, 0x1c388e70, 0x80bcdc49, 0x5c97181c, 0xd6408894, 0x938c9074, + 0x0fe108fe, 0x51769b6b, 0x22966020, 0xd12a2cb7, 0x58004c0f, 0x0661c08c, 0x92640867, 0xbe53b55f, 0x12e2548c, + 0x163aca44, 0xb328a809, 0xc5da598a, 0x2a70fca2, 0x1eda21e3, 0xf8da2deb, 0x74358861, 0xd835a4c2, 0xcaef96a3, + 0x8787d4f5, 0xbbc69de9, 0xc1f3949f, 0xd39458b9, 0x8422f2e7, 0xf480e795, 0x773aad68, 0x1dc4c0bd, 0xdfc6c68a, + 0xcaa4987b, 0x949deeba, 0x7fe7d8ce, 0x80f03b29, 0x9a135329, 0x2566fe66, 0x085a21f2, 0x297f795c, 0xc1454201, + 0xdc390655, 0xb929b7da, 0x8ba70318, 0x9b3ff352, 0x035f4aea, 0x9fc0d7d0, 0xf7fa8960, 0x22ced9ce, 0x721985cc, + 0x314e2969, 0xf3dbb1ba, 0x18e56286, 0xe56aca85, 0xa9945768, 0x57906d8a, 0x00a56c66, 0xa6449ec7, 0x48a2426c, + 0x51e4093b, 0xab34f083, 0xfef7facf, 0x2fc868e5, 0x5eb4d194, 0x9fd561a1, 0x153b4ebd, 0xbb1b33da, 0xb0996f0e, + 0x7bda77b7, 0xdaaa8b4c, 0x62369eea, 0x18d9e7e6, 0xef77b1e3, 0xcca27f0d, 0x44ebfc93, 0x127b14b0, 0x6274e599, + 0xc0d37dd9, 0x2bd2358c, 0xe5a6f796, 0xabb8e0fc, 0x07b594c7, 0x7208f68b, 0x0f4af38a, 0xe13fc94e, 0xfdf43817, + 0x51745d34, 0x03c6219b, 0xd8185421, 0x1e9920d0, 0x978e2504, 0x770c739a, 0x49966ca8, 0x8a36257d, 0xcec470f7, + 0x329fc7e8, 0x78287597, 0xa5764361, 0xbc5359b1, 0xbe42466e, 0x9fba1cc5, 0x98097243, 0x72b51b34, 0xd158e048, + 0x6e6f4ca1, 0x52127006, 0xbc909ef1, 0xcb64d2f1, 0x7865812f, 0xde6a128c, 0xe7156ee0, 0x9eb731c4, 0x8a395d84, + 0x989f4f6d, 0x11e1fdb8, 0xc1ffcd71, 0x4658a732, 0xd91eea04, 0xe760c6e2, 0x2fba96d4, 0xcadb1eb4, 0x510e4dc0, + 0xf800f6a4, 0x6473ee61, 0x55d676b9, 0x7e601337, 0x64404934, 0x93b5918f, 0x211f356d, 0x3683f4eb, 0x9ce3fb5a, + 0x66fb6f35, 0x663501a7, 0xfa738f91, 0xcc020363, 0x50515223, 0x692e275f, 0x50b38f37, 0xef4c0a41, 0x3552c082, + 0xa6310f15, 0xda932c2b, 0xe22c4951, 0xc93eb31c, 0xf07c3d7c, 0x20ef85ce, 0xde789d9f, 0x675b95b2, 0xec9ed0f7, + 0x4a8f80ec, 0x1fdb731c, 0xd16eb25a, 0xce9b8fe4, 0xe0bff4f7, 0x2648f223, 0x567180c5, 0x1b0c51a6, 0x0d606554, + 0x43f87226, 0xba8a2dd6, 0x00b5ed9d, 0xabf5ef85, 0x3aa6df24, 0x5c879ce9, 0x45fe1d7a, 0x22d8e3f8, 0xac9c019f, + 0x080fb10b, 0xd99f118d, 0xaa403aed, 0x04e677db, 0xf4ab10a7, 0x97767198, 0x11c62b93, 0x7e59c79b, 0xabaa42b4, + 0x362e4ec5, 0x6d909b72, 0x7d439535, 0x481d029e, 0x097ace19, 0x2f44ee66, 0x4d41d51a, 0x6f17f1da, 0x599e47ba, + 0x8aa82d91, 0x135ca9d2, 0x1c885bff, 0xa12c8903, 0x160afe22, 0xa59d9a50, 0x6ba2e3c4, 0x71540d54, 0xe5d1dcc5, + 0x3ad5ff88, 0x2dccce1d, 0x59a331c7, 0xfd06755d, 0xef2c70a2, 0x734f054f, 0xc0facdf3, 0x6fd309c8, 0x7ca4bd37, + 0xf616c8bc, 0x71064b0d, 0xc7827a37, 0x4eacf127, 0x0846bb6d, 0x3967795a, 0xdf56918a, 0x1d5fcfe5, 0x64e09aa3, + 0xa379f9d9, 0xdf1fdc0f, 0xec1cc094, 0xd68258e4, 0x8ad79307, 0x9ae4a1cb, 0x15f39087, 0xe10488ce, 0x5ad06e29, + 0x11011663, 0x7a51d0ad, 0x391aef4d, 0xaea189de, 0x0bbbbe2f, 0xc40bc3aa, 0x2b2024e5, 0xca10deb2, 0x506dd409, + 0x69240de2, 0x7805dc6a, 0x5e20dd51, 0x36fcc039, 0xa5784634, 0xcc7b7ea1, 0x20f0a054, 0x0e506089, 0xd25366f8, + 0xfa528592, 0x51f62600, 0xdeb87f12, 0x98e07641, 0x69be417b, 0x7da5308e, 0x65a95aff, 0xabd812e1, 0x760adc20, + 0xa4d8d2ae, 0xdcf2e156, 0xe5846a65, 0x0b02bfa0, 0x21739a8e, 0x57068d31, 0x5e7eee5a, 0x06e32274, 0x7fa5f9cf, + 0xd4ce9e57, 0xad86b4e9, 0x4bb1ff7e, 0x5d6ce0e4, 0x6d1821e9, 0x3c14710b, 0xcf18e569, 0xdb53a310, 0xa0aeb8d4, + 0x86a891d2, 0x447a95d6, 0x0f7b7e79, 0x77057a6f, 0xede585a9, 0x5889355d, 0x5232b5ad, 0x61428560, 0x8b50b4a0, + 0x951e29cb, 0x4f1c8c7f, 0x9a677e48, 0xa21dd031, 0x596869e0, 0x11be8a6b, 0xa85c760c, 0xecc614ed, 0x4a65c003, + 0x0a8482e5, 0x856de4d0, 0x75b8108e, 0x1768a521, 0x043c7adb, 0x4b243538, 0xb8d34eba, 0xc8abba8e, 0x59056163, + 0x8c2c59d8, 0xcb6e9194, 0xdfe772ac, 0x1814068b, 0x0d325c22, 0x36c4f669, 0x685fcb76, 0xd35cc9cb, 0xd54bd706, + 0xe6cf8f27, 0x853b234d, 0x163a9a3e, 0xeb684468, 0x8dd0def6, 0x2a82483c, 0x39f5c183, 0xa532f338, 0x1678d926, + 0xcc8ca72c, 0x7ea85eee, 0xb832101e, 0x29eb876c, 0x2308620d, 0x723c983d, 0xfac01bba, 0xbd1fb4b3, 0xa3d166c7, + 0x913cccc4, 0x71801439, 0xb2f598c8, 0xaefe0c3a, 0xd1640b82, 0x9708f3cc, 0x0fa28cf7, 0x912e4451, 0xa6e32c90, + 0xe8f62f6a, 0x68821827, 0x28a68395, 0x2ed0b736, 0xe3b6da18, 0x38137930, 0xd4dea574, 0x0842ccef, 0x97239394, + 0x76d219f9, 0x2f54d5d0, 0x4414cc4e, 0xf84b6c6d, 0x113150f7, 0x5a04f48b, 0xc194cb4e, 0x8426e34a, 0xf851eb6f, + 0xeb9edc96, 0xed283579, 0x064b9fbe, 0x94d0ec1c, 0x12c9a11a, 0xdc490b15, 0xf62f0c26, 0x77f79312, 0x606d1853, + 0x7b39d5b9, 0x51001339, 0x363fe7ce, 0x8d1d75c0, 0x3d7045b3, 0xc3112e69, 0x2688c5e1, 0x6fe84755, 0xa78bdf1e, + 0x02ffd2a6, 0x78add178, 0x3988f3e7, 0x097d6839, 0x53a76705, 0x38497b15, 0x6bdd449d, 0x9c418c2f, 0xa4bc96fe, + 0x5c9125fe, 0xa3065bbe, 0x67cd1ccc, 0xdeb12566, 0x2240eb25, 0xb19a4924, 0x18ad258e, 0x2b74d044, 0x51d6a764, + 0x2590f701, 0xde4423a7, 0xd88f2a9c, 0x7976fafc, 0x57ce065a, 0xd9053e6e, 0x42f17d56, 0x383378ae, 0x55339cd9, + 0x07b83351, 0xa201de2c, 0x7a63feb2, 0xfaf15ce0, 0x5efc55dc, 0x082b1b4d, 0xacc11815, 0x481898b1, 0x7abf8518, + 0xe4f42680, 0x49debfac, 0x95a190f4, 0x29a31eed, 0x74ceb211, 0x6e984250, 0x99dc951e, 0x519ecb88, 0x5b194347, + 0x6e6d1d6a, 0x2e3106a6, 0x120a28f6, 0x3c8b22ce, 0x41f2d739, 0x50bf1162, 0xa3e96b71, 0xd092e197, 0x6cae81fe, + 0x31f4ade2, 0x353c89ac, 0x9ca84a08, 0x240d212b, 0xd13ccc90, 0x2598a517, 0x7414178e, 0xb7145518, 0x9bdcc3f1, + 0xbea6987d, 0xbfb810cf, 0x1daf470b, 0x742bbc45, 0xd2771919, 0x4bae7e2b, 0x9be7a7ae, 0xbc163e18, 0x1e499568, + 0x9bb2098d, 0x3435cf68, 0x3e803b57, 0x76a44177, 0x60d4f6b1, 0x679b124e, 0xe18956e3, 0xae7aba23, 0x33acbc9a, + 0xd23a9ff5, 0x84f9548f, 0x6fa03097, 0xb552aa81, 0x4e67a493, 0x0d2cf627, 0xfe8ec7c8, 0x9b283d21, 0x248d16a2, + 0xc6d794be, 0x5d466347, 0x17e112b4, 0x3641007a, 0x8ce646f2, 0x9f59a025, 0x3c6c6c62, 0x9f8567b7, 0x10e9789d, + 0xf31e98fa, 0x4aada950, 0xbfde0ae6, 0x11813f09, 0xea351664, 0x9b47889b, 0xd0e31f83, 0x042596d5, 0xfd3fcd7c, + 0x7a3ea048, 0xeb421679, 0xbab49e3c, 0x5255becb, 0xef340e90, 0xec56618b, 0xa7d1d95b, 0xbb6a95b6, 0x0286078b, + 0xc38573a0, 0xcaecb1bd, 0x7ceb81ec, 0xedd3a17b, 0x24d0b80c, 0xd5d9979f, 0x3c88ca31, 0xc2d87d0b, 0x1530977c, + 0xf12f7d98, 0xb9b7b795, 0xd062a0d8, 0x2174a546, 0x49bb05d1, 0x5e8762f1, 0x9ed49753, 0xbb3c18bc, 0x4c26f35d, + 0xfaa7b736, 0xb375b6f1, 0x1a417a3f, 0xced4eb75, 0xb8d05068, 0x51bbe40f, 0x61823cd3, 0xf6bc7310, 0xd0cf830a, + 0x63b4e881, 0x0f65dbbb, 0xe30d5c1f, 0x7708749e, 0x739bfd82, 0x18addaeb, 0xa92f6e82, 0xf75de8fc, 0x359b9fab, + 0x2c046458, 0xc4b296ed, 0x67c82caf, 0x30073518, 0x5b363918, 0xb151185e, 0xa9770542, 0x8da2fcc1, 0xe13271aa, + 0xaa4e00a4, 0x3de3ca3e, 0xe1fab285, 0x4d6c9a18, 0x059d03b1, 0xc9b0cbd8, 0x7d4e08cb, 0x6263be47, 0xad6d273c, + 0x21d84996, 0x8be9f7b1, 0x73431924, 0x4db7651d, 0x9e8b9fca, 0x1ab8a35c, 0x44999193, 0xe12a3dc6, 0xf0db2590, + 0x1a518b2d, 0x3bed377b, 0x79c46a46, 0x75f07038, 0x816b3180, 0x3e6283b2, 0xb02ef4f5, 0xa2b3ce3a, 0xdeb6c3df, + 0x96b4c746, 0xdd253c22, 0x61b9b7dd, 0xe5e147e0, 0xcf855d6f, 0x4ee91621, 0xd3dec6e0, 0x6392a1fd, 0xb2e79a3b, + 0x3888417e, 0x6c37b154, 0x6c0085ba, 0x57e301af, 0xc4f8f23a, 0x5701bed0, 0x49b57358, 0x7641c07c, 0x8235ee56, + 0xcf7bbb58, 0xaf2c44a3, 0x2b342961, 0x7e13c2c7, 0x4a14ca15, 0xd7294107, 0x1a0c924e, 0x2b0768a4, 0xf0c32f0f, + 0x58ba45cc, 0xbaa9c5ce, 0xa1cbaf95, 0x56ccb4ce, 0x82cb19ad, 0x29c11670, 0x3c882fc1, 0xf396b83b, 0x1f5a4503, + 0x4ade6f2e, 0x00aea821, 0xbdd8e57d, 0x6de89901, 0xfa6d7dbd, 0x0d2cf171, 0xbcb46571, 0xfc2c7ccc, 0xac75ee93, + 0xc3cfcd15, 0xc8f436e5, 0x990dab32, 0xbe9edcbb, 0xd748311e, 0xbf402ea0, 0x8bd8c5a8, 0x85f50293, 0xcf3185d6, + 0x9a7c09a7, 0x3c4a5d68, 0xc15ff9b6, 0xd16f328b, 0xf3ae2b01, 0xa3282ffe, 0xf49e9752, 0x3b8bff4b, 0xfeb60b00, + 0x8d1da7dc, 0xbc01712c, 0xe368aadd, 0xc8214864, 0xd739f10a, 0x0e07740a, 0x44424bc8, 0x4c8beaf3, 0xc3b05a3e, + 0x55ae6a74, 0xee8dfc5a, 0x347515b3, 0x56f4b284, 0xfcfea25b, 0x8ea599e8, 0x9ff7335a, 0x1ba60c95, 0x40117ef4, + 0x39d763c4, 0x6e67519a, 0xe92c79f6, 0xfc9de8d7, 0xf8fb6bc5, 0xbd93dcbf, 0x2143d1bd, 0x59981bd8, 0x5e1cc4b7, + 0x6916de56, 0x343e60f6, 0x5575a529, 0x9d3b628e, 0x6f9920b8, 0xad0a1bbf, 0x32f07b80, 0x046a3ede, 0x42468468, + 0xda0d9dbb, 0x1bd2b0ba, 0x015c9d31, 0x425efae1, 0xdf4e2de1, 0x4334168c, 0xa16dfb53, 0x49f4c13a, 0x7af28afd, + 0xcfbf6c7e, 0x85fcaed7, 0xedd4a5a0, 0x0ca7effa, 0xb5ca7135, 0xef96b8ab, 0xc587e4c8, 0x787f46c2, 0xa21064ae, + 0x26157c03, 0x87f7b68d, 0x5edf2866, 0x1338ea0f, 0xcace3dd2, 0xa0c646da, 0x22115879, 0x49bd3c04, 0x5e4afc3b, + 0x8542eb56, 0xaa172e4e, 0x7f531081, 0x61bc10c1, 0x5824050e, 0xf7311b41, 0x4965e462, 0x19bb64cf, 0xee0168fe, + 0x38ef0356, 0xa0e4b02d, 0x4dbe84cc, 0x76ca41db, 0xcc73206d, 0x94db4f1a, 0x474180a7, 0x9d714d1c, 0xa89aad43, + 0xcebeebc8, 0x71cedd3e, 0x715f1979, 0x25d1bf41, 0x3e91b1ca, 0xfbb0a63e, 0x86d3f89c, 0x972afd39, 0xf8c8c2a1, + 0x847d2977, 0xb7c71f23, 0xe2eab121, 0x1e55a687, 0x9bb727b7, 0x387764aa, 0x7b05b0d7, 0x8eea7da4, 0xc8b655a8, + 0xfc8234df, 0xb5086768, 0xf1151e1a, 0xe4e90765, 0x326897c1, 0x4015ea89, 0xd5bf8714, 0xb4c55ca1, 0x7174155c, + 0x3ef44b36, 0x57f468fb, 0xa0637a9e, 0x652c7505, 0xfa2d4a65, 0x161381a7, 0x64a6250f, 0x3ae68538, 0xd10d8638, + 0xe7d9d360, 0xdf91d24d, 0x6a3dd4fc, 0x899f3e9f, 0xb71012a4, 0x0ee0d38d, 0x161ccfd8, 0x4aa5cd25, 0x3b0bd654, + 0xeb223c94, 0xf71d4ab6, 0x6a4097cc, 0xd0f29f12, 0x728ea7ee, 0x5f938e71, 0xc47c7249, 0x4e66f2c5, 0x044d7101, + 0x64dc14f3, 0xc53e5f14, 0xf61ad8d2, 0xc8f2ff94, 0x9da2577d, 0x4a353316, 0x2cfef63a, 0x2bb54461, 0xe02386e7, + 0x80ae276d, 0x197ffd78, 0x4b4493e7, 0xe41237d8, 0x58c339ef, 0xa97169cd, 0x3a807da4, 0x588be9f6, 0x5969f76d, + 0xa094eb63, 0xe4a3d816, 0x0445f9ef, 0xaf05f592, 0x20331033, 0x74ff02ed, 0x60f1a443, 0xbf9035ef, 0x0c3a8755, + 0xdd968cd3, 0xce113624, 0x07db2719, 0x50e566bf, 0xc024fc81, 0x09a51926, 0xd9da52f6, 0xb44ee3a3, 0xd589a180, + 0x7c546e73, 0xdd72a634, 0x6073d57a, 0x9dd534da, 0xb77f7882, 0xb3599f4a, 0x9407a7b6, 0xdd23d405, 0x106113d3, + 0x75dae06a, 0x8c24f16f, 0xdea93906, 0xa7ff1295, 0xe531155d, 0xcbf1bd44, 0xf4563232, 0xdee0911d, 0x3bf74f18, + 0x6ae356b6, 0xc9a45d61, 0x427d494d, 0xa601a321, 0x8a404f9c, 0x16a01ae1, 0x982ab5a0, 0xb00d24c5, 0xa04df929, + 0xc6e1fad3, 0x851b2b1c, 0xd413235e, 0x80da7736, 0xb3138a4d, 0xd43e3956, 0x8cfece88, 0x9b3f7f08, 0xbea12bd8, + 0x596d4084, 0x49d224cb, 0xf5052b21, 0xf547be99, 0x08fa6ddf, 0x5e192022, 0x944e00ce, 0x3aba7408, 0xc7908745, + 0x8065b052, 0x972be41c, 0x6baf89fa, 0x245ecd29, 0x6a104bd0, 0xab3575dc, 0x860db0fd, 0xdae60693, 0xe3db5321, + 0x9129926d, 0xb999af07, 0xb23f581d, 0x492a52d6, 0xa4fe6908, 0x9ddefa33, 0xc8c2e970, 0x83ac344f, 0xa71dc94c, + 0x7052be23, 0x1035c823, 0x190593f5, 0x660f758b, 0xc20bbe5e, 0x1bebd41c, 0xd35a3cb4, 0x89560bb4, 0x0b727345, + 0x6ce6899d, 0x224f416a, 0x073eb182, 0xd9de3e10, 0x81919c76, 0x07d3cd8c, 0xc6a28fed, 0xb2567533, 0x1ac88b8d, + 0x05c2519f, 0x0d1fa3a4, 0xe6fd7f58, 0xcb96d3bc, 0x706ce1ec, 0xf6af3c6d, 0xb281ed95, 0x80bd323a, 0x75c3d057, + 0x3ee7ffae, 0xb547511f, 0x39f04dc0, 0xed5308cd, 0xa99658a6, 0x7ceca07e, 0x91398627, 0x2a343e2e, 0x412dce39, + 0x0a7e82d7, 0xc982f03c, 0xec12b308, 0x9de5e62c, 0x04305551, 0x3fd81b9e, 0xcba07a0f, 0x044f603c, 0xb58b7b57, + 0x1b7fedf0, 0x8394c60d, 0xdb4c153e, 0xd11e3430, 0x4b925d4d, 0xc4c869a9, 0x2ae393b7, 0x48793778, 0x339bf26b, + 0x4b7cda9d, 0xdf485a4c, 0xf8771151, 0x5a4e2bf3, 0x08ac1f39, 0xf5748f00, 0xa7903834, 0x032a6481, 0x7d1b68e9, + 0xafdaae01, 0x3166cf69, 0x118b0784, 0x082fbe09, 0xf2cf15da, 0x520ba3ff, 0x19624d95, 0xcdc493f9, 0xcd7b108e, + 0xadcbd1d3, 0x4d7c4c5a, 0x171c175c, 0xb9786380, 0x9aabe658, 0x5a4d90ae, 0xacbfc843, 0xe73a80d1, 0x91e8a1f9, + 0x26e7cbed, 0x9033ebf1, 0x12dd448c, 0x20b59c5c, 0x164af3db, 0x49a2a218, 0x6ca25331, 0xce9b43c7, 0x51afd10f, + 0xd167baf6, 0xe9c1dc55, 0x350fc3c3, 0x6c7520cc, 0xc116ff60, 0xa7464b39, 0x9a6ab29b, 0x597b0af0, 0xbb259f00, + 0x1fc5859f, 0x5b4ab00d, 0xae6f9f8e, 0x475c0604, 0xf5254e15, 0xe19d6f45, 0xc2248186, 0x364e14ce, 0xd318cccf, + 0x144536ca, 0xcae19c13, 0x7aa02e0b, 0xb6b27721, 0x5ca1297e, 0x0e0cc036, 0xc91a1495, 0x1e1a1a1c, 0x73b0d1ea, + 0x75119514, 0x52c31c60, 0x41cf30fa, 0x88dd8a9e, 0x088e9f58, 0xca1db2a4, 0xd65bb017, 0x6c23b1b5, 0xb9b92a9b, + 0xff5de9c8, 0x81407316, 0xb203669b, 0x43ea4f57, 0x7722d106, 0x67f4d448, 0x7e0ec5de, 0xd4f61404, 0xbc47a6d4, + 0x44753164, 0xba839480, 0xbdb5ba85, 0x3ff52fb4, 0xdd28babe, 0x41b0b2d3, 0xce4b2919, 0xc67324bf, 0xc6230cc8, + 0xad3da581, 0xe0fddd26, 0x99760201, 0xf526756d, 0xcfa96b97, 0xc868e45a, 0x524f54f4, 0x30af7f00, 0xa8fa99f4, + 0x18a3409d, 0x31625fb3, 0xa4ec7dfb, 0xd082c603, 0xa876a426, 0x9d6b2030, 0xe14fe44d, 0x145765cc, 0x4239ab59, + 0xec4e8d8c, 0xf9fe37d3, 0xf1abf2b7, 0x010fe4c5, 0xb30d9b5b, 0xea9a4816, 0x117d07da, 0xb6829563, 0x3935ef4c, + 0x26782ceb, 0x0ae6cacf, 0x9dec9c69, 0xf733c1be, 0xa3ff4d90, 0xc31ac65e, 0x7ad5d35b, 0x922ee9fd, 0x431b6377, + 0xcacd210e, 0x3961524d, 0xf9ac3c8f, 0x4042b4ee, 0xd3c5ac57, 0x018863aa, 0x8f88e4a4, 0x85841ec0, 0x8bb3ab40, + 0x1a4bd927, 0x9d8ba29b, 0x661ef6b8, 0xa3dc0225, 0xcabf10d6, 0x0de42ad5, 0xf44350be, 0x3967a1ed, 0xc85c14c0, + 0xa1b6c244, 0x56c00093, 0x590596ac, 0xae114662, 0x9cac38ab, 0x397d54fa, 0xb98d092d, 0x37f5d65c, 0x6afc1387, + 0x4a96ca75, 0x2e31144a, 0x05f0b9ae, 0xd0faa09a, 0x345c2c08, 0x90d3114e, 0xa161a47d, 0xa5b89a01, 0x463ede7a, + 0x6de31221, 0xe200f856, 0x16410303, 0x382edca3, 0x0672dabe, 0xfcd7a6af, 0x11dc2b33, 0xa6f3e5b9, 0xc7fe0b9e, + 0x6b93123d, 0x3dc40cc3, 0x05cc49d6, 0x71468a56, 0x146abf43, 0x278f14cf, 0xb495966a, 0x705cf2b3, 0x500740de, + 0xa88bb770, 0xff8e2fa2, 0x4e51e823, 0x44770eea, 0x5908b83c, 0xed3cfaf7, 0x679d50d9, 0x59b490a6, 0x668b7a8b, + 0x3e7531eb, 0xfcf58251, 0xe0ec6786, 0x2440301d, 0xdfc986a0, 0x50e69a0e, 0xee65536f, 0x29931b52, 0x88d05393, + 0xd5faadf7, 0x47593d91, 0xb89776b2, 0xd0027d2b, 0xa76d6d1e, 0xbe2ca082, 0x297c1299, 0x25c90dc5, 0x1f13f897, + 0x9720c505, 0xfcdb8145, 0xd05e88f5, 0x0b196039, 0x6562dc4e, 0x36e0857e, 0x59cd029e, 0x49984605, 0x97002f7e, + 0xac395462, 0x2fb494bd, 0xc3d24a52, 0x090e1541, 0xcd73b0eb, 0x88a06410, 0xaefae9b7, 0xc5cfda00, 0x45a7cc5d, + 0x9e9646c8, 0x5218784b, 0x9c16fa71, 0x3dc72f92, 0x023e2814, 0x85a960d1, 0x425cf213, 0x8f10670b, 0x3260ebfd, + 0x2298018b, 0x8fbe5ff4, 0x732e1928, 0x2f22d55d, 0x8da79d7a, 0x2b61e8a2, 0xa872faad, 0x24b777e7, 0xa0ea960b, + 0x50265d10, 0xd74f8eb1, 0x095698c4, 0xdd2733df, 0x1713403b, 0xfc50a73e, 0x52a0ac81, 0xfcd19ce7, 0x0856ca9a, + 0x040182d0, 0x7d950746, 0x116acfc5, 0x9a3d4613, 0x1e3bd82e, 0xbf838f74, 0x2b2f7350, 0x214c94bb, 0xfe365b3e, + 0x962cafbf, 0xfbd895f8, 0x20f0b4af, 0x6d12fc80, 0x97408981, 0x859c7f22, 0x427e4441, 0x5ed66079, 0x575029e9, + 0x72f9f368, 0x343c128e, 0x73352d26, 0x064f661c, 0xb525b098, 0x5d83d5d7, 0x7b0dd9d6, 0x6317d6f5, 0xa1af729d, + 0xfbc6f184, 0xced6cb7f, 0x3ffeba0c, 0xdeb74d26, 0x79924fe1, 0xcaf898b9, 0x58d1ee16, 0x97d6edb9, 0xc1d90856, + 0x4e186b71, 0x6220ed20, 0x6d139cda, 0xb5ba9462, 0x931b262f, 0x80db4674, 0x9ad61557, 0x2e9e52bf, 0xfb5991ec, + 0x59427e8c, 0xb4ef1458, 0xa9fa8530, 0x53a8d903, 0xfe1082f6, 0x1075f3b1, 0x102579f0, 0x6e9bd6a5, 0x082f6c30, + 0xf95ac792, 0x32a447a9, 0x905248ae, 0x2a2cf5d6, 0x9877f2f2, 0x04f4fa3e, 0x58f80488, 0x23f5074a, 0xab1b77dc, + 0xa6d807c6, 0xbadd8472, 0xa35f0a02, 0x6b261fab, 0x3688c986, 0x0ce99270, 0x3fc740cd, 0x2796388b, 0xa2d346cc, + 0xe41f7ea7, 0xa78dd2a3, 0x545c79a9, 0xa6f11d19, 0xf0973f4e, 0x30f8f15f, 0x1c35b905, 0x4cb54da8, 0xddd8c589, + 0x21c9a291, 0xe7dc5e36, 0xb5a2e8c9, 0x867f1377, 0x4ec76df9, 0xefed5e01, 0x91871886, 0x391819ff, 0xc406f433, + 0xffd46373, 0x100d2db5, 0xa00f5fae, 0x8326af6d, 0x9d4f46f1, 0x3f7c5451, 0x73a0f05e, 0x64770778, 0x410186f0, + 0xbe6aacd1, 0x68f1888b, 0x5470b54e, 0x29b0bbb4, 0x3c5cd576, 0x1f2dc057, 0xd6c6ce1a, 0x9facc949, 0xe530d402, + 0xd3664416, 0x4b5aa673, 0x07dc7ccd, 0x6d64f8b6, 0xb56f20ca, 0x5f9cef0a, 0x310fe08c, 0x0ed15c67, 0x4c22b973, + 0xb2a2f553, 0xb01716db, 0x742d23b4, 0x4f8e4421, 0xbdb313d0, 0x31969519, 0x78cd119c, 0x2dc083c7, 0xbf16aedc, + 0x6f3b3a40, 0xc8ed5ecd, 0xcf8a5e0d, 0xd6fbf33a, 0x101bcef6, 0x7450a024, 0x1509ecdb, 0x4fe96dff, 0x8967abde, + 0x80eaaa75, 0x092ecaea, 0x7667545f, 0x4c7b3db5, 0xb40cde5f, 0xa2a2a782, 0x1c0aca10, 0x0a406891, 0x55d2b8de, + 0x67dff3f5, 0x90aa1ad0, 0x471b5a8e, 0x4ce649fe, 0xb0760da6, 0x31b18dc6, 0xee0f59c1, 0x2677b50c, 0x0185ebed, + 0xb738ed25, 0x1bce558f, 0x3d9f94b9, 0x1a3a60dc, 0x7f2e1ed1, 0xb4b809b3, 0x369de25c, 0xd27e29bf, 0x95230fe0, + 0xfbf6748b, 0x5f984cb0, 0x00a88b76, 0x69cb20c2, 0x16971ced, 0x81b2777f, 0xc371dc9f, 0xdbfabff7, 0xce503464, + 0x6ac3d732, 0xcd81727b, 0xf2f0abca, 0x25046d92, 0xaf8893f4, 0x83769c03, 0x83558b75, 0xfe57d481, 0x2aa9ada5, + 0xb0def0d6, 0x10f14337, 0xe6735144, 0x86771678, 0x601426ed, 0xaa062355, 0xfb824463, 0xbc72f3ec, 0xcec07d67, + 0x3683caf5, 0xff04f41a, 0x774dc559, 0xa08e77b0, 0xbce08761, 0xe02ec51c, 0x4d9bbadf, 0xda6d8750, 0x3766cfdb, + 0x280b55b6, 0x2b53df4e, 0xf059dc1b, 0xbbbe0208, 0x67fc8f92, 0xb43c4500, 0x8226728d, 0x0aa58642, 0x72706801, + 0xb04c38a7, 0x8f0a625a, 0x9895b8e0, 0x74760c33, 0x3b459dc8, 0x8c2e5db1, 0xe3c27372, 0x93b9fafc, 0x8a21030c, + 0x84e4ec18, 0x38d74d9f, 0x11f9c2d9, 0x57d592b3, 0xe2b8b3b1, 0x31dac6dd, 0xc2c71a04, 0x520435e1, 0x36deec57, + 0x020ba3b7, 0x4f8d1bb5, 0x5ab8d5c5, 0x4c07df9c, 0x9a0efcd6, 0x5ba77781, 0xa2b5bd16, 0x226f0127, 0x1d890544, + 0xab6e4a62, 0xe7462b13, 0xa2f25811, 0x9997be68, 0x63a5f9a7, 0xbabc9fb6, 0xc6e27fc9, 0xba2ab61b, 0xf1067abb, + 0xaf556a37, 0x6db30d66, 0x74e4936f, 0x90bcf9eb, 0x2b6feb82, 0x89a1767b, 0x50bc6134, 0xeeee3ad1, 0x721dce49, + 0x9797dac9, 0x0714fc28, 0x4b611dd3, 0x3850ddae, 0x9b05ae0f, 0xcae86524, 0xdeb4e50c, 0x39323833, 0xff1f71e5, + 0x1f4775a1, 0x0cdc60c4, 0x6bb0fc42, 0x5291fa73, 0xd64c069c, 0xa8bfd6de, 0x37bde358, 0xc2cb2b8a, 0x96a74515, + 0x2beced15, 0xc9fb8001, 0xfdf2068f, 0x3445950f, 0xaa92fed9, 0x19959972, 0xfbb59fcc, 0xc7c3b161, 0xb572bb0d, + 0x86a0d25b, 0x44c89f3b, 0x3edfc1f7, 0x7695022c, 0x0586b4cc, 0x769c85d0, 0x9cd188a0, 0xd9fb66cf, 0x0c0b6fda, + 0x43c26fee, 0xde7981f9, 0x48fd24c5, 0xfcab4534, 0x87576227, 0x4d003fb6, 0x4151d8bc, 0x8f16cb44, 0xddd5888e, + 0x2c69d33e, 0x005fc8c7, 0xcbccb288, 0xab49ee88, 0x5d9a6cc3, 0x4f74836c, 0xc16cb842, 0x23c0b8d8, 0x7ec22e64, + 0x747c9eba, 0x06dff93e, 0xf4c331b1, 0x02d89fcc, 0x7fc45a4e, 0x6f92da8a, 0xddcb4993, 0x126c3839, 0xd1d85db8, + 0x9f143d3c, 0xfd4be6ad, 0x5f28cecc, 0xdd4124dc, 0x386cfb8a, 0x03df6288, 0xf0556065, 0xe979bbab, 0xbba15805, + 0xf3fd1282, 0xb4923a17, 0xfe8c083f, 0x20b6e0fe, 0x5ae75a82, 0xb1b641c0, 0x8c9f2fea, 0x3ec0b7bf, 0x28a8ba11, + 0x618332f1, 0x63fce346, 0x26574fe4, 0xa24f7c1f, 0x30da6a52, 0x4bcd14d4, 0xa7ae204b, 0xf4284223, 0x3c47e76a, + 0x0f009c00, 0x2e37ae79, 0xbfa2bf1b, 0xc05fe09a, 0x18cc43cd, 0xfbacb3be, 0x2bb1de1f, 0xba69cae5, 0xbeb7d682, + 0xf5713195, 0xd4e9e857, 0x77be0226, 0xf13829e9, 0x9ff07afc, 0xdbbc7fad, 0xfa262b4c, 0xdf7b2adc, 0xf5d9358a, + 0x2185e4dd, 0x777d8da1, 0xb19c9282, 0xe75c7dab, 0xf64031f5, 0xb3e5c05f, 0x24b21dd6, 0x6c9c1b21, 0xa412cb1f, + 0x5ab09a4b, 0xbd7f83a7, 0xd822efc6, 0xfe10cd2e, 0x16eb7388, 0xa9a76f42, 0xc91be73b, 0x685a6a39, 0x16c6b6fd, + 0x49e57c4b, 0x10186b94, 0xab728d22, 0x8254c9ab, 0x3ddc529d, 0x3aed1e60, 0x344d94b1, 0x5eb0a33a, 0xc8632617, + 0xd3fe7ee4, 0xde8fe194, 0x6699a045, 0xf5c5b39d, 0x5dcb9bfc, 0x9835bc28, 0xd774d6f4, 0x60f12ee3, 0x13553cd2, + 0xfc6c07c7, 0x403d9c31, 0xb27996a0, 0xe887a301, 0xff9d9604, 0x11f5d844, 0xea2d04de, 0x5327b204, 0x52c6e531, + 0xd8ae1298, 0x12279800, 0xfb09e714, 0x5e6fb551, 0x478a8975, 0xfa64eb43, 0xdfdd3878, 0x3543ec20, 0x62e53ca8, + 0x1ffd1cba, 0x292412b5, 0xcd74773f, 0x69a68bdd, 0xb5f58949, 0xb8293872, 0x9608b18b, 0xbbbc2900, 0x1241a67c, + 0x5cc4c234, 0x695f291e, 0xb2372475, 0x6a759423, 0xbeb37167, 0x61ac4c4a, 0xa161b84c, 0x166039da, 0xc54aaba7, + 0x9f4e803b, 0x3ca7d95a, 0x61b19b0d, 0x56fe7bf2, 0xddbc53dd, 0xc4991086, 0xb386146e, 0xaec9fbce, 0xd900a4cf, + 0xb2b41b17, 0xb904a0ed, 0x0c922ba8, 0x00c0f475, 0x4822da3e, 0xa44345e0, 0xc69a744b, 0x12d7d0f9, 0xd1d0311d, + 0x96deb926, 0x5c020326, 0xc725a54f, 0x10b03b18, 0x87368be8, 0x1488c1a3, 0xa66391cd, 0x9ae5288c, 0xd8ce2ad4, + 0x0b15e612, 0xfbff5cad, 0x22009499, 0x81095bb9, 0x36f4b8f3, 0xb846e7ea, 0xe3f99a1e, 0xfe0fec13, 0x6a4ca818, + 0x180e4b15, 0x2e4a6773, 0x4a4559b8, 0x8255ab1d, 0x26ca703c, 0xe145c28f, 0xd6b148c0, 0x3a9fa58d, 0x60794126, + 0xa2f06683, 0xe56f7e36, 0x60e39ea2, 0x3ad1e9bc, 0x238e707a, 0x46c4a5b7, 0x9b3d2b6e, 0xdfafde70, 0x2215901a, + 0xc6dd8003, 0x19c0edcb, 0x39d83956, 0xe9f50272, 0x71147213, 0xae1f18de, 0x9eb60d64, 0x56955e80, 0x0b504097, + 0xb3b2b93d, 0x64abfd5d, 0x54a82d1a, 0xac12507c, 0x5de84b25, 0xbcee8a16, 0x637ad257, 0x5c5b4282, 0x209a76d5, + 0x7c9005e4, 0x2c6abdd2, 0x72941a95, 0xcdfd3b7d, 0xd917dded, 0x9caf5e5c, 0x796c5021, 0x5bb66b45, 0x76761fb8, + 0x2078db37, 0xff35a799, 0xbc34b796, 0x99b1e086, 0x5b00fc39, 0x9ee3cf74, 0x70557a2b, 0xa6d8baac, 0x18244d4e, + 0xc79754b2, 0xc63bd52a, 0xfd1d24a0, 0x848a5df1, 0xed32b571, 0x36dfad32, 0x2ac959da, 0x06c74b50, 0x541261bc, + 0x1d536308, 0x140a3da4, 0x47b75483, 0xa57736b8, 0x22beea28, 0xcc109b16, 0x45779c6d, 0xf446e8f8, 0xf8718ee5, + 0xc073216e, 0x1e565df0, 0x33feb2ce, 0x802f3e11, 0x90a860e6, 0xba186f64, 0x74747c70, 0xf2402288, 0xede6ecc6, + 0x6f768d03, 0x8c896531, 0x1f978d6f, 0x3baa59c0, 0x00ca79d2, 0xcf083a50, 0xb23cdba2, 0xb995d198, 0x82b2b17b, + 0xe1346d81, 0xce3ad02a, 0x99d0b040, 0x622bde65, 0xac4906be, 0x3816794e, 0x7719005c, 0xf30813e7, 0xd867286e, + 0x1afdf3a8, 0xb2d023dd, 0x5bba0bdd, 0x55a8853f, 0x644e7bee, 0x65c1a7e5, 0xd10d55ae, 0x1d4ac74c, 0x8fe22c71, + 0xe7b4ab9e, 0x8410e72d, 0x660fdc0e, 0x9ba2cf3d, 0x91f79c84, 0xfb864260, 0xc0d2049d, 0xcfe41b81, 0x920f456b, + 0x9d531393, 0x3bc53942, 0x59e402f8, 0x0522b726, 0x4f957303, 0x74d25dba, 0x4e15b2fe, 0xb8faafe4, 0x01bedf94, + 0x1f595d83, 0x75ebcda4, 0x07da6c12, 0x6ed1fba8, 0xfc7165c7, 0x817048a4, 0xf25e7553, 0xb887dd12, 0xa1fe0437, + 0xa8050e89, 0x6394d884, 0x724b9d3f, 0x7bbf0fb5, 0xaf7e3225, 0x8f902db8, 0xa9b9d734, 0x48771c29, 0x1e94396d, + 0x6673c9c2, 0x4604fc0f, 0xa72735fe, 0x0a85bff0, 0xb4178e14, 0xc9bff09d, 0x22241ad4, 0x5e14054c, 0xa8829682, + 0x51439ab3, 0xb4d34fbc, 0xabc1c5da, 0x1ebaf6c2, 0xc1aa8f63, 0x34fb2ed0, 0x0948cff1, 0x554690aa, 0x04ee10a3, + 0x5df3bee5, 0x46b5ccbc, 0x258661bb, 0x6cfebc7d, 0x492ba14d, 0x68008ff3, 0x38f2fa91, 0x945641d3, 0x61779230, + 0x16efa15f, 0xc76830b7, 0x47347e7e, 0x62328111, 0x74dff405, 0x6689cc38, 0x24deaa77, 0x50f3becc, 0x89da2b55, + 0x534ef6b4, 0x9fef72ce, 0x6d125e71, 0xeb0b79fd, 0x8f0f1604, 0xa253e315, 0x4f0a67a7, 0xfa74248c, 0x360c98c0, + 0x3cf77fd9, 0x19406689, 0x9722e923, 0x21b91ddf, 0x708d25f2, 0xb17325e7, 0x29dcc8c3, 0xefa573c3, 0x034043a2, + 0x6a3c12b4, 0x99295ab1, 0xaa4aa1c5, 0x5c4a6f95, 0x965735b6, 0x6ff03639, 0xaa9759b7, 0xb11bf12d, 0xb18c4584, + 0xd227cd2f, 0x450588e0, 0xcd714b03, 0x3552d258, 0x01ca44c0, 0xf07d4023, 0x92ea4c0b, 0xae460447, 0x4f0d5301, + 0x6b6adb95, 0x320dfd1c, 0x2dd340ad, 0x1dad1389, 0x48e4d963, 0x289ef921, 0x463854f7, 0x16e265a3, 0x91ba5c3b, + 0x0485af1d, 0x6686ec02, 0x888fcc48, 0x955db39e, 0x395e5130, 0x6ba056ec, 0xc7fd5e38, 0xee5245b4, 0x4ef7056e, + 0xf9f6de5b, 0x77afc2b0, 0x3d12bb26, 0x54958d85, 0x6002599f, 0xa86b060f, 0x79028c3b, 0x2e51933f, 0xe44175f0, + 0x8dd4709a, 0x5bbfc24d, 0x5643deb9, 0x099f1642, 0x5ec1e782, 0x691043f3, 0xd65a42b9, 0x1ccaf6bd, 0x7c8deea3, + 0x805b1173, 0x95356f11, 0x5a95bc40, 0x12aa494f, 0x566bf0b0, 0x9f54d2d8, 0x6d56d54b, 0x49f22c8f, 0x59625dcd, + 0xbc5f8432, 0xc665c096, 0x505d0be5, 0xc6845ffc, 0x64565791, 0x6eff043b, 0x67c901b8, 0x536d4c7b, 0x621b568d, + 0xcbebd103, 0x55e731ad, 0xd8b23ee8, 0x97158356, 0x803ae41b, 0x85be8c62, 0xe5a3f704, 0x78813992, 0x13a0864a, + 0xfd3d9e54, 0xc44f3499, 0x0638313d, 0x06816a3c, 0x0097fab9, 0xd9e0ad77, 0xa08a6314, 0x4d481ac1, 0x04b46590, + 0x34ec3187, 0x5f3e35ea, 0xad2c1e77, 0x45203d73, 0xa2794daf, 0xc43c6f79, 0xc2158c6c, 0x444bf338, 0x09bce32d, + 0x3d2fe42b, 0x6265b681, 0x8e44f353, 0x29df9047, 0x1f30484d, 0xa352b5be, 0xab32afec, 0xe93dd8c4, 0x09908257, + 0xe9ee5924, 0xbacbe731, 0x181763df, 0x71613470, 0xb6dfd5ac, 0xe94fc198, 0xa6d5ae26, 0x6a398f50, 0xb9a0f22c, + 0x068867e2, 0x5c5aa4a4, 0x3d42ee00, 0x147983e6, 0xd7788c1b, 0xd9b881c5, 0xc7541fc0, 0xee9d6910, 0x7ff8e5d3, + 0x39fd2d9f, 0x5a02c32d, 0x509f6b93, 0xf5b3b53a, 0x7c56c97f, 0x7bbef570, 0x74e9241e, 0x7cdac2f8, 0xd61a573b, + 0x9072080b, 0xd89fa16c, 0x6b390777, 0xc2c12226, 0xf9cb72df, 0x86205ae0, 0x6f86950f, 0x953b303c, 0x6de7e2d0, + 0x37348811, 0xe6c1e42a, 0xb42bd765, 0xf9fe29ea, 0x07e05d86, 0x468731e9, 0x022de0aa, 0x3c5d5c8a, 0xe5e15888, + 0x1c4bb029, 0x913e4a68, 0x82d4e98f, 0xb8e5abff, 0xcb06e804, 0x63f684e5, 0x3053c6b9, 0xb1c0a15d, 0xc41977ca, + 0x00a13884, 0x5bbbb66f, 0x3ac6138b, 0xc1386679, 0xf519cb44, 0x233e3777, 0xfdf66de2, 0xadc20865, 0x8cb29d2c, + 0x79f1483b, 0x31256013, 0x1569c517, 0xf1f091bd, 0x175bf7f2, 0x839d7a26, 0x87c2bb1e, 0xc4cf5194, 0x4262cfab, + 0xb97d3bfc, 0x4bd8802d, 0xc3264c69, 0xeabb4a02, 0x95605f26, 0x1a7db148, 0xf9cbaab0, 0x04bb5614, 0xfdcc7fd4, + 0xee7b5c04, 0xac63d2dd, 0x04ec93a8, 0x32541e7f, 0x93217b12, 0xb84031bc, 0xefe086d4, 0x87eb5496, 0xc6020145, + 0xe2449008, 0x70d05030, 0xff7da1da, 0x9edecb74, 0xa5ac0918, 0x14b73f79, 0x2c59e1e0, 0x251fb7aa, 0xcf957043, + 0x81bcc327, 0xefaca691, 0xbcda7cdd, 0x01686c33, 0x08a7948f, 0x121f937c, 0x1bd4f139, 0xedf6ab5f, 0x8b587515, + 0x39f3e435, 0x3ebda1ca, 0x3655b800, 0xcb3589f6, 0x141dea0f, 0xd2439958, 0xf1a7aaeb, 0x1d0fda8c, 0x3500a819, + 0x17ce3976, 0xceddd150, 0x275416de, 0xc98130e7, 0xd67c4142, 0x54bcb6d9, 0x93b1b6f8, 0xb7cc2d4c, 0xb37b1c7c, + 0x6b8d06d3, 0x378e1459, 0xbd00669b, 0x7e18395e, 0x9f514d96, 0x3bf9c888, 0x965cbbb2, 0xe736d6de, 0xb6c12104, + 0x022b7247, 0x19f071ab, 0x45d38c85, 0x19b47cc9, 0x5f0ed1a3, 0x1500b38d, 0x12ba0b8a, 0xc7c09b5d, 0xacb8076c, + 0x6e8d61c5, 0xbadc1283, 0x6fd6b643, 0x5f4b62de, 0xf7d58f26, 0x9e227401, 0xa272199d, 0xfadfbf5f, 0x0cd48c9a, + 0xe6ef16ae, 0x197614ad, 0x1f63dacc, 0x83cad60f, 0xd7f40696, 0xff07924f, 0x10076632, 0x8da13406, 0x4a8efc1a, + 0xe537b9fd, 0x5e585e92, 0x09cd12a0, 0x56aeff56, 0x61d85a74, 0x75221ea6, 0x34f6f4eb, 0x82343061, 0xe33cf83e, + 0xe647d85a, 0x87eef61a, 0x8c2d128d, 0xb5ed06b6, 0x7699feb0, 0x039f175d, 0x79af8f3a, 0x3b475a7d, 0xad24d12b, + 0x16d133d1, 0x056b5ea1, 0x79666ec1, 0x053524a9, 0xa2fd472a, 0xf00dde5e, 0xb86f30c1, 0x21e68ba0, 0x18988e64, + 0x85f26a23, 0x6b2134aa, 0x12d17bd5, 0xcf2d4448, 0x59113496, 0x892e09ac, 0x9e422245, 0xa83089cc, 0x089ff7f1, + 0x8e565211, 0x3dedea71, 0x16594db3, 0x93e6be51, 0xa9b4c7c2, 0x081e5449, 0x143ed5d4, 0xd79cd2eb, 0xb710bc55, + 0x0e05f38e, 0xc1d42e8f, 0x4351d2da, 0x30b392d3, 0x1137d17e, 0xfb94d865, 0xe02932c6, 0x087a0ed4, 0xdba711ba, + 0x58339bb3, 0x24f28e22, 0x7a8ff6aa, 0x25906e50, 0x6cc389bc, 0x5c1017f9, 0x090ee923, 0x189f2ef3, 0x0951a592, + 0x9cdd1536, 0x898e24e9, 0xc19b0ee7, 0x7bb24653, 0x7c5fc4f5, 0x90870bbe, 0x19c056b1, 0x12bd89e7, 0x565246dd, + 0x57c78684, 0x6a5fdad8, 0xce82f6c5, 0x017b864e, 0x3c77d400, 0xe40f0dac, 0x0d662800, 0x08fadb77, 0x8554d8f3, + 0xd2f54932, 0x8c2d0db3, 0x968162c7, 0xd16615d2, 0xa73dde91, 0xfd4a6b07, 0xceb1e4ca, 0x1ca88ac9, 0xc80a1d0b, + 0x0b1c4885, 0xf3506832, 0x9122f9f0, 0x8199328d, 0x6a17b64d, 0x07113f0a, 0xa4db55d0, 0x9e18d3fb, 0xfd45f7d3, + 0x8b33c265, 0xed56a573, 0xaad88abd, 0x18a6eb20, 0x6932cdd3, 0xfbf4acd4, 0xdf4d557d, 0xb41af030, 0xaf4331c6, + 0xb24ab62c, 0xe83d57f4, 0xd619bca0, 0x240c613b, 0xd42b1070, 0xa518df84, 0x9e534e95, 0x6cc1f1af, 0xd6d8f13a, + 0xbce1bce6, 0x2ac956db, 0xe2599eec, 0xca1b31f7, 0x7c57858b, 0xb19582b6, 0xd039cccd, 0x808951f2, 0x95ab3cf4, + 0xc6c64fb1, 0x806d4898, 0x08802148, 0x600c83b5, 0xda21afd9, 0xdf546dbd, 0xb04a4966, 0x3957e75c, 0x793d3c30, + 0xc54a3173, 0x82801f6f, 0xf6b6af74, 0xaad96b07, 0xa3de9e15, 0xbcd50b43, 0xe5bb9c79, 0x7293d030, 0x193b3905, + 0x5ead4fe4, 0xb54c43e5, 0x2523a963, 0xdc98787f, 0x1639c5ad, 0x81b4c853, 0xc00765d0, 0x0135a1e9, 0x3a12722c, + 0x81dd1fc9, 0x30fa86f6, 0x75bfaabc, 0x5eb7e855, 0x3b45f79a, 0x13c94e8f, 0x62b84153, 0xe7aa954c, 0x76beb9f6, + 0xb427e4ab, 0x849e753f, 0xa49c464c, 0x348c99d9, 0x2e2b5f32, 0xfefbe8f1, 0x30886121, 0x76f092df, 0x53408029, + 0xb1ca928c, 0x0f7a1fcb, 0xa12ec28d, 0x363cb3a9, 0xa90c61fe, 0x022f4b73, 0x6b14eb21, 0xc8b4e847, 0xcf5acd87, + 0xf76ffea7, 0xd9202d41, 0xb31eb0f3, 0xb862d361, 0x397ccbca, 0xc580d92e, 0xe20cf4d4, 0x64a25fdf, 0x0a7ede77, + 0x91e56cf4, 0x3a86acc2, 0xed93aaf7, 0x8e304d93, 0x1b5bffbb, 0xdcd35ca7, 0x8782cc98, 0x2ec98479, 0xc588b14f, + 0x62b310a2, 0x791370a7, 0x7408b4cd, 0xb9294a29, 0x352228d0, 0x94772243, 0x3a48760b, 0xd880e453, 0x6e3a24ac, + 0x1122767f, 0x53407c3e, 0x45c3289c, 0x173b91d6, 0x1e361057, 0xb8196872, 0xf3230c27, 0xdb71dd97, 0x996d892f, + 0xaa9b3174, 0x835a0654, 0x448eada7, 0x2e9218bb, 0xf3b796c4, 0x03db8219, 0xa16c1248, 0xb7b6a677, 0xb322f10c, + 0x2b9fa1ff, 0xcab8ee4f, 0x28638e28, 0x04ca1704, 0xf0eceae5, 0x582dda72, 0xe0a2d8b1, 0x92346e5d, 0x38534996, + 0xbd501df3, 0x155c6c89, 0x912ad99b, 0xe79e4904, 0x07fa553a, 0x47916eea, 0x478784b7, 0x9565a2b4, 0xd2d7aec3, + 0x2187ec68, 0x5718c509, 0x4a873e52, 0x8de0a61c, 0x44b837cc, 0xfe397667, 0x35dd70dc, 0x66841d7a, 0xd53d86af, + 0xb5626486, 0x7cac917b, 0x04df3dc1, 0x9c3c341e, 0xf7f8590c, 0x36b6b67e, 0x1d38dfe7, 0x50bfd30c, 0x5c7e38c5, + 0x1917ffaf, 0xe89e378f, 0x553bc0e0, 0x67d95a83, 0x9dbeae7d, 0xe7e65625, 0x64ec6cd3, 0x66276d03, 0xb8a3ffbd, + 0xd69c00c6, 0x56441485, 0x6f9cd22f, 0x6da46b46, 0x7a326627, 0x744f3e94, 0xe937aa3c, 0x2c9e9a78, 0x2316138b, + 0xb6998858, 0xbe574c0e, 0xcc0b16ef, 0x6186fe64, 0x4aee6454, 0x01037cda, 0x2e2fd6f0, 0xba5d04aa, 0x98999c78, + 0x3c2d73f6, 0xe173b872, 0x0c23c028, 0xa568288e, 0x93a65348, 0x88014242, 0x6f2205fc, 0xae0c047d, 0x2cfa6c4e, + 0x4cf1bb18, 0x2b5b7af0, 0x0d0a8e0e, 0xf295ecd7, 0x07a21e3b, 0x09463c70, 0xcc0fa5e3, 0xaa36fdab, 0xdad78045, + 0x63e665a4, 0x01e5c86e, 0xe64feff0, 0x7664f221, 0xcdd03b19, 0x7358317a, 0xe95a3a92, 0x4a4eccd4, 0x62b17742, + 0x245fafc1, 0x3573c4c3, 0xf97fb24e, 0x570f4c6a, 0x0b9099db, 0xe92c3a14, 0xe44a2fc0, 0xdafc95a0, 0x8858f873, + 0x4831873d, 0x3a27e477, 0x7db91b0f, 0x0883c2a1, 0xaceeb44a, 0xf371e130, 0x65c3c2ab, 0x564417d6, 0x958e4fbb, + 0x16b22d7a, 0x8a2cca9a, 0x5847a848, 0xd2be452b, 0xee28a394, 0xb601a3bb, 0xc7272ff8, 0x1af4e096, 0xf4e38ca4, + 0xdc12169e, 0x1103da12, 0x5f080da6, 0xa214a169, 0xe1bc6d4f, 0x4687f189, 0xf270876c, 0xeb0627cf, 0x9dac2fbb, + 0x82a3e71a, 0xc6d3cede, 0x62d3b198, 0x9a70bc74, 0xefa9928e, 0xeb6d30ec, 0xe5c82564, 0x8290f03a, 0x2fa142d0, + 0xedc3da4a, 0xe8af7708, 0x86773d4b, 0xbd88aa44, 0x92a43326, 0xa56c44cb, 0xad3ad871, 0x7d27fb61, 0x85d79c88, + 0x4fbf0a57, 0xfd6f20cd, 0xcbb0561c, 0x73731f49, 0x7d22b508, 0xfd99724c, 0x4c9e23f1, 0x171825e5, 0x5c28adf8, + 0x0cb6b6ad, 0xf3d86210, 0x7440bf96, 0xb791d474, 0x7c6c29c7, 0x1265af29, 0x1b8794bd, 0xdf904fc9, 0xb379f58c, + 0x0331a289, 0x8af6b9e2, 0x2cf7b7ec, 0xb6eca68c, 0x9e82ef12, 0x06b80343, 0xc55d7c82, 0xe7223fd5, 0xbcc9cc94, + 0xea7fa63b, 0x86d7aeff, 0x4a55f712, 0x8b848a76, 0xae7b1e62, 0x55fe0b97, 0x079c7891, 0x05fa5590, 0xeedda267, + 0x9637c421, 0x6b404634, 0xe7a4f04c, 0xec7028df, 0x31dd1574, 0xaab726b6, 0x6e7ab931, 0xb4b5aaf9, 0x22a2beeb, + 0xb0ccc540, 0x5f001cb9, 0x44d6ad57, 0x565a668a, 0xfd6aa26b, 0xdf713946, 0x03f79249, 0x6d808195, 0x6784d497, + 0xc7409f15, 0x64d6dbea, 0xb7e03b62, 0x676345cb, 0x6e014729, 0x10bd2f89, 0xf6a33096, 0x4212e14d, 0x94cff661, + 0x4181593d, 0xc3ac2b14, 0xa2c0d77b, 0x66266c8b, 0x7c62e684, 0x7d591d44, 0x31038784, 0x0d933462, 0xb20beb89, + 0x3925da78, 0x59b817a2, 0x20107c0e, 0xf4895b40, 0x2f6fb121, 0x1e38b370, 0x59ada560, 0x64ba8683, 0x119c456b, + 0xace31d00, 0x159b586e, 0x3a8f9a1b, 0x0e1045ef, 0x9738d8e9, 0x77de228d, 0x57c6b6a2, 0x28d676fb, 0xed09eb9b, + 0x6306d50b, 0x7d786237, 0xe1fcb040, 0x4eab8753, 0xdcd55e1d, 0xee63409c, 0x818007f0, 0x495ad34d, 0x52bd5f9e, + 0xfdacd07f, 0x70e656b8, 0xabefa7b7, 0x14146e2e, 0xe4d86643, 0x556da7cc, 0x0fd4ebc8, 0x3c8f35e2, 0x8d5374a1, + 0x7c74d85a, 0xdcad6266, 0x23ae701f, 0xa1720e04, 0xab6a38f3, 0x812596db, 0x5488ac89, 0x2fa2f1b0, 0xa41ef600, + 0x336fca98, 0x515bf76c, 0xc0ad2a3d, 0xbe9c6a45, 0x7314535f, 0x3f6dbc5c, 0x5dbe5fce, 0x845c2d9b, 0x32d1a93d, + 0xd65a2f9c, 0x22beb5bd, 0xd7a3248b, 0x84db9750, 0x0e2be980, 0x1e53380b, 0xd57c0036, 0x9c33082c, 0x02bcc49c, + 0xb40f8caf, 0x3406e8eb, 0x7651f9d7, 0xac21b580, 0xff830d01, 0x6b012e91, 0xd9feb513, 0xe9a9d53f, 0xd9adf5a4, + 0x1a418cbe, 0x6407e79c, 0xcd99ac86, 0x6728fcbc, 0xd3581b58, 0x9cfb67b5, 0xf44c970f, 0xc1190a5e, 0x78272c05, + 0x55ff3bbe, 0x1f7cd0d2, 0xeeacb9bc, 0xd87f0729, 0x55aa7119, 0xfbf5f9a1, 0xdce0c28d, 0x7672c928, 0xa06c24a9, + 0x66024387, 0x8bbf5fa3, 0xb046d17f, 0x8c0b0368, 0x786f24db, 0x88e9191a, 0x4c65b778, 0xf7e59d83, 0x335f6577, + 0x21aee7f4, 0xbe36cec6, 0x292d3217, 0x608eac3c, 0x0eb28dd3, 0xf470ac5e, 0x2d5264bb, 0x74f4a894, 0x271c9b06, + 0x985cb9b1, 0xf6f79449, 0x29741df5, 0x29a7c916, 0xeddefab4, 0xa5d43adf, 0xdd456ccd, 0x8490eb0f, 0x02bc7208, + 0xb967493c, 0xec1a4b15, 0x41932aa9, 0xdb626b93, 0x79e83194, 0x88021c3f, 0x23525641, 0x33e956ea, 0x747ed8ec, + 0xcf1c305a, 0xcb5cde1c, 0x882a9436, 0xc3b0618f, 0x260e38d4, 0x75d0b64b, 0x266a4992, 0xbd526716, 0xe99bda42, + 0xad749755, 0x7f0cbc00, 0x80103ab9, 0x997700fe, 0x32351f87, 0xc3a1b9aa, 0xb0b83082, 0xf23a6e11, 0x45c7ce64, + 0xa8dec671, 0x001cf8b0, 0x39f125cf, 0xd330cac2, 0x79b6e83b, 0x683adc92, 0xf927c070, 0x2e1a2510, 0x08cd7af6, + 0x4e9785c4, 0x78147eb2, 0x99f69a0d, 0x2351f332, 0xeaf8452d, 0xf360a2cb, 0x37ca073d, 0x08314462, 0x40b2d331, + 0xada227e5, 0xa0ee8b41, 0xe2244efd, 0x30645a0e, 0xe3b707d7, 0xf9ec50a4, 0x16d95e7f, 0xc309367b, 0x623b8739, + 0x3847a386, 0xb47f90cb, 0x8b397273, 0x297989cb, 0xd920929e, 0xb6361258, 0xd23fa317, 0x44bb988d, 0x5534bf15, + 0x4b8ab29e, 0x89bad415, 0x7677706c, 0x210c6aa6, 0xaee94f1f, 0x658ac457, 0x399b92fd, 0xca2443ea, 0xa234996c, + 0x63c7de67, 0x6cec7be3, 0xdd0501b6, 0x59cda3a8, 0xd0736f8e, 0xf184621d, 0x639b1559, 0xfa10a0f6, 0x8ef54373, + 0x26de4678, 0xb83dd1eb, 0xd2c4d544, 0xd777a8a5, 0xebc34044, 0xe5d94245, 0xfb90d1b4, 0xc6f7688d, 0x03becd29, + 0xbf3498f8, 0xbad28004, 0x66df2ad9, 0xaa5e8dad, 0x01016cce, 0x91910a7f, 0xeee45e02, 0x103c8f3f, 0x1b0b8e47, + 0xd08b5ba2, 0x82102404, 0xdb829825, 0x9c277474, 0x7abbe52c, 0x43aae45d, 0xb4e1bf49, 0xb92cbc08, 0x138d6292, + 0xaea03357, 0x12a3cb08, 0xe955cf6c, 0xb9d0eefd, 0xd7b77b45, 0xc82e3bdf, 0xbd7240bd, 0x880b58fa, 0x5cbb861f, + 0x1c90cf72, 0x13c6d630, 0xe9b840df, 0x9ecfa961, 0x8f87da43, 0xd07b6a28, 0xbaffdfde, 0xf364d8a9, 0xd7af261c, + 0xf38af766, 0xc09ce3d3, 0xf418ee9f, 0xb83e1683, 0x553e8ce6, 0x13f3813e, 0xc7566465, 0xb98a8868, 0x01276e9d, + 0x45acad9f, 0xd0a9f3d4, 0xcfd46699, 0x8f450601, 0x56446920, 0x7980ff01, 0x9203045c, 0x0e30028b, 0x423208e7, + 0x9d6c98f5, 0x4bd8db86, 0x3c8419f2, 0x09b122aa, 0xa48b180e, 0xb79d5f6c, 0xbb5b1fb4, 0xc72038e1, 0xe858660f, + 0x0ae72d91, 0x26f86910, 0xba172417, 0x0fe2c7db, 0x0838d130, 0xca755b5f, 0xfe1a7ced, 0x98f1c54c, 0x6ff8af16, + 0x6409964e, 0xe2844950, 0xf9cd62f2, 0x6a4df9a0, 0x9180b7b8, 0x471f42c3, 0xf27aba4f, 0xf643538a, 0xf852be12, + 0x348ad5f1, 0x176f8e7e, 0xb2e68246, 0x8c672700, 0x7c83cbc6, 0x3ad3f445, 0xc925698f, 0xba1b5f98, 0xcf902e47, + 0x22442643, 0xbeabb5ba, 0x863d5ca5, 0x4e281793, 0x0dd6fd2e, 0x954be4b6, 0x525a674d, 0xde75aed8, 0xcd3b24a3, + 0xb9548e74, 0x614f6217, 0x2eed0e9b, 0x79b68628, 0xc731ae59, 0xd0daf705, 0xdd65e899, 0x94749c51, 0x2910f501, + 0x10bbfb87, 0xe3f4f8ee, 0x279a7bd5, 0x7fdcd3e0, 0xfbeee426, 0x7051fe91, 0x26b095f5, 0xc3a86ebf, 0x0a5a433d, + 0x34f41f12, 0xe54d999b, 0xb9366057, 0xe515f7c1, 0x610d163d, 0xc407ed4d, 0xb9f290e1, 0xf88b3a8a, 0xcfe360b5, + 0xe920f66c, 0x604735f9, 0x9eed2e95, 0x4a3dd665, 0x24e5bb84, 0x899a9713, 0xa59d2646, 0x30769e8a, 0x2afa3666, + 0xb60223af, 0x31675c9b, 0x6dfba800, 0x2a3190bb, 0x79889ddd, 0x933e6d08, 0xae4d422a, 0x403f5aac, 0x7d6ab08a, + 0x2369b969, 0x8665f758, 0x6f8f7dfb, 0xe94ad15d, 0x63ba3c49, 0x81392a24, 0x2a08458f, 0x167c22f2, 0x8626a1cf, + 0x6b9f5662, 0x7adf23b7, 0xd5781026, 0xd7155a3e, 0xe94a10da, 0x76ac3c99, 0xde8e8327, 0x70b5dc31, 0x7d740f9d, + 0x10826377, 0x3435bf6a, 0x355e622f, 0x3e9fd344, 0xed62e2e2, 0xe0cc9799, 0x34471d59, 0x691d0219, 0xf877d424, + 0x01630bdd, 0x4d1f672a, 0x7238d373, 0x29866f12, 0xface25d7, 0x267db3ca, 0x6441adf4, 0x7fcbfa58, 0xd176ddbb, + 0xa5386948, 0xbc146984, 0x921bae5b, 0x29c803c2, 0x07664e8a, 0x6252054c, 0xd962d9d0, 0x8004bb7c, 0x0955b86e, + 0xcac6c145, 0x4c8ffbdc, 0xe37420df, 0xe7c2acaf, 0x04edd822, 0x00e626c8, 0x17c898c5, 0x820d03af, 0xcd6bdbf5, + 0x26cc5c59, 0x494f35b6, 0x55a60872, 0x129a3d4e, 0xa13afb80, 0x0889f7dc, 0x7ee754f3, 0xe09e67cc, 0xfdbdcd4c, + 0x37628c0f, 0x10a913ec, 0x7410f76b, 0xcac4ee1c, 0xf1d7df2a, 0xed60a304, 0xaf7ed5d0, 0x10ad8ad4, 0xff52f104, + 0x4373a807, 0xf23cbdb9, 0x0943d938, 0x10f60aa7, 0x3fbd8246, 0x37f6ff9c, 0x9ba57afa, 0x13504b83, 0xa668d453, + 0xd0438dfb, 0x663453bc, 0x71ec0d26, 0x1f0c3b3e, 0xa02cb14f, 0x0b936ef0, 0xa2dc026c, 0x1eb192f0, 0x1221e45e, + 0xf4a96292, 0x5f9bfe12, 0xedcaa478, 0x2e7a2de0, 0x812942a5, 0x170beb77, 0x88ac22cb, 0xec2d5d51, 0x4c032e7a, + 0x6e41c27d, 0xa3848156, 0x8dcbcdd4, 0xb1bb065b, 0x8bff270d, 0xd3b98252, 0x8c5da35b, 0x150a51e4, 0x4b36d295, + 0x770c4677, 0xf24e3cb0, 0xf47ed3bb, 0x39b1a492, 0x559004f0, 0xffaae941, 0x229f04b4, 0xd3a51495, 0x4bb78ea6, + 0xcfecd253, 0xbd50b69f, 0x7196e91d, 0xa4d66cac, 0x9a074b42, 0x8d54fe3d, 0x8d2e3da0, 0x5f3e4166, 0xa43ef7fd, + 0x6008ae53, 0x1d1b3858, 0x5873a402, 0xa0dca58c, 0x5f5c487a, 0x8307c5ac, 0x216dc9d5, 0x09d80283, 0x6c215875, + 0xc6877328, 0x7f7e9080, 0xf13aa300, 0x28db0fd8, 0x773fd732, 0xb7336e3c, 0xb7815ea3, 0x848908fe, 0x64f08aae, + 0x6fd938f2, 0x71404787, 0xc123c815, 0x8fcf573f, 0xbb44266e, 0x9daff220, 0xa4c204f4, 0x8f5df86d, 0xdeb097b4, + 0x4597d9de, 0xb121348a, 0x1d591c2a, 0x41953eab, 0xff50b9b7, 0x8ef2399e, 0x032e709c, 0x5b3719d4, 0x0d64a207, + 0x2763e8ff, 0xf7fa2465, 0xdd0e8501, 0x8a5cb440, 0x35f59b2a, 0x13e77113, 0xaf875f94, 0x85dccbcc, 0x4228e490, + 0x5bf4fdee, 0x8b9d1505, 0x278f20a8, 0x3df0830a, 0xe58483b6, 0x14ecb6f8, 0x93ec1e77, 0x955e7a3d, 0xfcd2417e, + 0x3aba6bab, 0x2075d8d1, 0xdf2baf5c, 0x875d2111, 0x020344c4, 0xba3cc8ba, 0xd4a87413, 0xf941f9eb, 0xe68933e1, + 0xe2888094, 0xd0e289fa, 0x772fb35b, 0x21da0a1b, 0xaacee66b, 0x9e54e2ca, 0x347e9a14, 0xd64af3fa, 0xe82d824b, + 0xf4f56272, 0x0fa9ffe7, 0x8c5fb933, 0x48d7f18e, 0x3abb623b, 0x89e2594c, 0x1f259447, 0x116a2c72, 0x9c534964, + 0x9f02c144, 0x51355e09, 0x301e29f3, 0x786e50ba, 0x95728984, 0xa7d24b7a, 0x401bc8e0, 0x959558eb, 0xef59cfc0, + 0x62812904, 0xc16fe500, 0xccdddba5, 0x4a9456f1, 0x84dcfb07, 0x90c6c5e5, 0x667bf2f9, 0x0f91b4f4, 0x76ce8451, + 0xfcf1912e, 0x2e4330fd, 0x7752da51, 0x0751080a, 0xa7839304, 0xaab23077, 0xb95b4964, 0x3b44c1c4, 0x8bf3afec, + 0xfce1b676, 0xbaa132e3, 0x2c06601b, 0x589b76a4, 0x0fb371fe, 0x28e9bced, 0xab0f800a, 0x8ca4a63a, 0x9df6f937, + 0xb6223915, 0xd69bd346, 0x40a8f05a, 0x6c522852, 0xed7a5d3e, 0xc2fa4613, 0xe0ae86d7, 0x99673ab2, 0x82a5f3a8, + 0x6d78af40, 0xda6b542f, 0xb31e8b7d, 0x876dc569, 0x8c94d54f, 0x75531cb4, 0x8bbedc5f, 0x66192846, 0xa8460e17, + 0x5001f089, 0xdc0becd6, 0x5c9bdea9, 0xc921efe6, 0xb8d33f76, 0x52e8f84b, 0x946345c5, 0xad7a8e33, 0xa5c5c2c9, + 0x19d86c22, 0x19050055, 0xa983d45b, 0x15697ec4, 0xccdc2ad8, 0xec79fe34, 0xf2ad6ac2, 0x437b192a, 0x78371c04, + 0x2dd0813f, 0x5380beca, 0x6c4596ab, 0x7d44065c, 0xe7919807, 0x0c0d979c, 0x8c53e55d, 0x5212881f, 0x1971afe5, + 0x2252bd14, 0x41b442a3, 0x91dc8987, 0x2dbe11a4, 0xe1407b08, 0x2bc0b07c, 0x94bf75b1, 0xc20ac5f0, 0xcd927d99, + 0x5d9d21b0, 0x6afc5ed3, 0x1f9dc0fc, 0xa190c829, 0xbb79b836, 0xe53e2cf2, 0xdab8f3a9, 0x5b26b5ed, 0x2ff66216, + 0x2701a3d7, 0x41dcf7d0, 0x878f6c50, 0x93a36b35, 0xe124f2f3, 0xc99cd63b, 0xd3a4dbcd, 0x67bc444f, 0xd64b3985, + 0xff42b51e, 0x5a8ee059, 0x45b02be0, 0x07562755, 0xf08d4ee5, 0x1deac084, 0xa702b35f, 0xa51ff318, 0xe2c7ae43, + 0x3a172ae9, 0xad7e7da8, 0x786dcfc5, 0xde221715, 0x76705f0b, 0x55f601a7, 0x102b1be8, 0xf3867c10, 0x39132a33, + 0x6dca2b80, 0x3320123f, 0x351ded7b, 0x635900b6, 0x5647bda3, 0x42161596, 0x5ec8f9a3, 0xaa04929d, 0xf4adf29d, + 0x2ea89a39, 0x1b92cfb7, 0x1947775f, 0x1963dd20, 0x9630bed8, 0x7f9b36d7, 0x64ff4d59, 0x3bcc7d7e, 0x7d813988, + 0x97b54f46, 0x46499b47, 0x95fab84b, 0x84aa00f6, 0x96e7fdda, 0x31bf7af5, 0x047a25ff, 0xf319f056, 0xb8b323a6, + 0x4b5196a1, 0xcae0271e, 0x8ab16261, 0x88531cdb, 0xa42bce87, 0xd6df79d3, 0x66d0398e, 0x0483eb5a, 0x8c5e81d2, + 0x0fad0995, 0x7eea5643, 0x3a94d978, 0x9b5a57db, 0xf30aa21d, 0x42cf71f6, 0x38e90e8e, 0xb0e8237f, 0x8b66d54e, + 0x270e7473, 0xd4689be0, 0xea39d714, 0x7a267f82, 0x37d3cd6d, 0x6468fd28, 0xb74d62ad, 0x14e3961a, 0x5f0da84b, + 0xb3703ff2, 0x96462846, 0x447d20bf, 0xf21a3a7a, 0xf214c981, 0xaab590b9, 0x0208ad4d, 0xdfe6ebbc, 0x261bf4d6, + 0x4c2a431a, 0x17ad8d08, 0x1358c1de, 0x9ee45e67, 0x84c0ac32, 0xaf27aa87, 0x7f7f1c45, 0xfeabaf1b, 0x68cd47d3, + 0x80b8bb11, 0x9a88d4f8, 0xccb2ab44, 0xba0804a4, 0x1418fb7c, 0xd84fe552, 0x5d54a40f, 0x47273f76, 0xe3628c74, + 0x66550877, 0x1582ab69, 0xd680416e, 0x903656e0, 0xe51c23e1, 0x71724d6a, 0xbcd8f624, 0xbc3c48e6, 0x49a3d429, + 0x107469b0, 0x4f860c64, 0x8a771d39, 0x983fd58c, 0xd9626ae3, 0x98b8daad, 0xaef596cb, 0x335cc8bc, 0xa927cb2b, + 0x47cd0576, 0x776fee04, 0x53d77b00, 0xc87dc181, 0x23245a40, 0xc7a34d3c, 0xfec4ff3a, 0x5172473c, 0x8ba3e1fa, + 0x186bc6db, 0x0a58ef91, 0xa0e8ebab, 0xf218c8c0, 0xf2a361df, 0xaeac9367, 0xcdd675d1, 0x0471e98a, 0x517b6534, + 0xb17ab649, 0x4e3b97e3, 0xc73f93c1, 0xabe24569, 0xfd8a36de, 0xddef8f1c, 0x5c070d77, 0x47311163, 0x40465775, + 0x08e22f7d, 0x9913cff6, 0xbb12fc39, 0x567342da, 0x07c33e2f, 0xee4a1dc2, 0x8091a79f, 0x5547ba03, 0x54236eec, + 0xf4260b36, 0xfe7dabf6, 0xca706df3, 0x4def5101, 0x6088f6e0, 0x23decd3a, 0x400f3f1d, 0xafcd9e3d, 0xc8135139, + 0x5cb67eb0, 0xf1fd28fb, 0x68f99bb0, 0x917a1e6d, 0x4175d5ed, 0x8be4f8e5, 0xcd0f995d, 0xe86686f7, 0x3fa2c8c8, + 0x66137e21, 0xd3dac091, 0xf7ec6605, 0xa7c47bb5, 0x3821ebab, 0xa423b9e5, 0x6b064e95, 0x21b7c957, 0x782e78d2, + 0xf0086925, 0x67201fa2, 0xda8413ed, 0x3dec5634, 0x65b9c173, 0xe84f2426, 0xd01af726, 0x1ce3bb84, 0xd72a614f, + 0x2bdf121b, 0x913425b1, 0xc9016615, 0xe9d700e5, 0x598419fd, 0xaa6a1a3b, 0x8892daef, 0x31b62633, 0xa5a6ddf3, + 0x3e976d30, 0x487e342e, 0xe2cfb0ac, 0xddbab9bc, 0x0192d535, 0xfbc98fcd, 0x9ac55bec, 0x046806a1, 0x03f10735, + 0xef9af462, 0xfb3f4f5e, 0x2b86bf27, 0xbe805efa, 0x0d8b25d2, 0x547a4278, 0xb74227f2, 0xe7428507, 0xb3cdf0b9, + 0x794bc750, 0x914cb7ba, 0xa72d0d9e, 0x27607c77, 0x9c15c00b, 0x6aca86ca, 0x15732061, 0x12372311, 0xf3623ef9, + 0x07c4bcaa, 0xd373d140, 0x9244359e, 0x3f68137d, 0x600f1a61, 0x5267ac41, 0x749e0c3f, 0xf6a7c0c1, 0x3fce0018, + 0xf14c18da, 0x4f7fde5d, 0xd74fb1ae, 0x5af00b16, 0x8d70830a, 0x7bf7fbb1, 0xf4e17f1a, 0xc1c1463c, 0xb88e5f52, + 0x6a5b15f9, 0x8d3177f2, 0x0c18eebe, 0x6b14788d, 0x1432f355, 0xab02a5eb, 0x12268e01, 0x2cc7b6aa, 0x11fd22fe, + 0x1a2960dd, 0x66785beb, 0x57c0a227, 0xef21893b, 0xd4834ab6, 0x8ab31f3d, 0x4b35078a, 0x1d4ca1cf, 0x18b42d78, + 0xabbcfa7f, 0x35bc9a94, 0x3b3c9691, 0xa7428ceb, 0x4a55aa29, 0x8968710e, 0x9f50e742, 0x866be3c2, 0xd4cb30ab, + 0x25aa148d, 0xc0fb95d3, 0x691c9d88, 0x5af32b06, 0x0326b9d0, 0xb88402db, 0x47a8c767, 0x15ad4f82, 0xf6c3ee5f, + 0x1511cc2c, 0xe2f97f46, 0x6f6d2283, 0x8fe5eb3a, 0x8fbf86bf, 0x119a1709, 0xbb7b27ac, 0xfc314fa4, 0x69657944, + 0x7ef59961, 0x378d87e6, 0x10bac40e, 0x03095e88, 0xd7e65300, 0x7202ea0d, 0xfd652a94, 0x957c40f0, 0x9f6218b3, + 0x3467b5ca, 0x8a941375, 0x1da4989c, 0xc5b69ef4, 0xb889f583, 0xe7bdd9b2, 0x7465b8a8, 0xbdd42a2a, 0xb6f7c91c, + 0x8352e9e8, 0x5a599009, 0x831ff5da, 0x197da6cc, 0x74d3fab3, 0x7364a6d6, 0xce1342b2, 0x82048270, 0xa3b1ee2f, + 0x4983a102, 0x60a7fc78, 0x998dd4fd, 0x64ec5e3a, 0xd2de6cb3, 0x529fb635, 0xfd8ada9c, 0xcf41c056, 0xd6ec4a25, + 0x83a6932d, 0x9cec1d97, 0xe06a9bf2, 0x0d55cddf, 0x3bc8614c, 0x11b5a447, 0xca8c041a, 0xe72f6ab5, 0x60ee1bd0, + 0xd3dc1b11, 0xe05c8019, 0x2faea2ae, 0x09aaf409, 0x1f3a44de, 0xfc9ecaa0, 0x1b2f95cb, 0x1c43627a, 0x80598d37, + 0x2943bc89, 0x96766006, 0x34db1041, 0xadfb4f6f, 0x1bdb6323, 0xdcc4f379, 0x4173ccd3, 0x63e0c16b, 0x62640afc, + 0x7dd7077e, 0x221222a9, 0x730e96bb, 0x13193dfd, 0x1cf8698d, 0x60506a9c, 0xd11ca825, 0xdd66d49b, 0xc68f5a14, + 0x902b40af, 0xe9dc3e52, 0xbc8e894a, 0xe5a6f35d, 0xf8485993, 0x17675dd4, 0xe472419c, 0xf59e1a18, 0x75ec1552, + 0x989576fe, 0xa686b795, 0x2cfd2ab7, 0xdcf6379b, 0x9d8112a8, 0x2f005587, 0x1fa5427f, 0x0890ca24, 0x6ac483b4, + 0x3c460b5f, 0xa4f7fbc7, 0xf8a9ddf3, 0x387aae50, 0xe2ae7656, 0xb47b011d, 0x0abb9193, 0x556a155d, 0xc1f630eb, + 0xb3fa713e, 0x0bdac8c3, 0x36718bff, 0x35e8419d, 0x7f2e0e44, 0xb879e4f6, 0xbddccce5, 0x9cb8728a, 0x64f42385, + 0xe7b52f16, 0x3eff565e, 0x5b76b7b3, 0x5fe6db9e, 0x9ecf08dc, 0x8e7bf9df, 0x826f52bb, 0x0d60f28d, 0x7ca53a04, + 0x08236fe5, 0x548d90a9, 0x5d3696c1, 0xca5452ae, 0xa7a82707, 0x91452d8e, 0x00f707ca, 0xbf66e40a, 0x90574a08, + 0x001922f9, 0x924a99f7, 0x86c8eb67, 0x062129c8, 0x73dbbecd, 0x14bbc6c8, 0x0a9bbb69, 0x6a37ca9b, 0xba3a092f, + 0x62956e5a, 0xd273b513, 0xf484d694, 0xd1bc0a26, 0x33b3cedc, 0xaa002a18, 0xbaa0c329, 0x941f9974, 0xcebb6d55, + 0x7f5e8fa9, 0x0b6963e8, 0x8aa9e6a3, 0x828c0dd1, 0x12321b13, 0xa3382c67, 0x89375b05, 0x50604f1c, 0x49528cee, + 0x21adf9e7, 0x603d94a6, 0xedf8f453, 0x3ea2fcee, 0xcbcd8961, 0xe3a262ca, 0xc04dd1de, 0xe7f958e8, 0xe3975aa3, + 0x130e3350, 0xb7e521de, 0x81da5d83, 0xe38e55c4, 0x42f9cb5c, 0x3fd05997, 0xef87198e, 0xa2ead839, 0x5c21e1a7, + 0xbf8275d3, 0xf88cd343, 0xb55a1c68, 0x2a2c62f3, 0xcfc827ec, 0xf648d67b, 0x6027d8bf, 0xc4c2a85f, 0x62a79771, + 0x6016e168, 0x8e903ed0, 0xae62f0ca, 0xade06be9, 0xb6fa0b89, 0x0dd5d66c, 0x202ec05c, 0xcf9cdacf, 0x087c2911, + 0x6c55c669, 0xc9e2de32, 0x5e5f4851, 0x22cbbfb7, 0x91901b02, 0x63a06dec, 0x29d8ab4f, 0x1e641288, 0x835581ed, + 0xa6d293e8, 0x3ce7de58, 0xcc35d6e6, 0x7ce7f218, 0x8e7543b8, 0x52001724, 0x3370db5e, 0xe7de4f2a, 0x00de7cfb, + 0xfec11df9, 0x6ad0b8df, 0x57442f83, 0x421bda93, 0x3e62571d, 0x1efeb4aa, 0xfdb8edab, 0xd269a93c, 0xa935a7d8, + 0xf6934ab2, 0x474c8d34, 0x04fa4751, 0x17ac1286, 0x8faf0d67, 0x270d500f, 0xa601dc1a, 0x7ace146b, 0xe3e6bfcb, + 0xa29cc42f, 0xfdb82472, 0xfee652e3, 0xa4e4c7fd, 0x91d75fe6, 0xab8baab1, 0xb3a51e4f, 0x07353a3d, 0x92e3b257, + 0xe7737dc2, 0xfba948e3, 0x2667379a, 0xaed2008b, 0xc6c485c9, 0x3dea0291, 0xb27c624b, 0x1265f04d, 0x7c53a5bf, + 0x781d0e27, 0xe05081c0, 0x8a7d60f5, 0x87b4497d, 0x75684c8d, 0x331a9e94, 0x6dc4d90a, 0x4a9ad248, 0xc430067a, + 0x4da7c7b5, 0x74cbee2f, 0xd70117bb, 0x3ca0bfda, 0xc6ba1bb8, 0xe22903f9, 0x8d0e6347, 0xe2bc6557, 0xc0dc5806, + 0xd722b793, 0xa1b5efeb, 0x1176a2be, 0xd8dce7f7, 0xe0630962, 0x1a3972c8, 0x3ce48cfa, 0x2f58437a, 0xc1df23dc, + 0x4eb14a23, 0x581046d1, 0x6bca5842, 0x0f274783, 0x8b0f0a61, 0xdbab7c47, 0x2a217351, 0x85f98334, 0x6cf0e3ad, + 0x03b27948, 0x202e45b0, 0x3f17e552, 0xed9d26e4, 0xb05d64cf, 0x36729714, 0x216c6fd0, 0x77c9c4f8, 0x80b664c8, + 0x25b502da, 0x5a26cf17, 0xb83afca3, 0x500937e2, 0xb380f2b8, 0x062360b6, 0x8477f313, 0x086a712a, 0xf24e6c2a, + 0x9de2664d, 0xf5f66442, 0xb3ebff8a, 0x8fab8041, 0xf0656b6d, 0x3116bafb, 0xe1729ed7, 0xc43c9923, 0x96903da1, + 0x4656433c, 0xdd07bdcd, 0x54e0d174, 0x66d2c84c, 0xd05a4757, 0xf4a49f1f, 0x322828ac, 0xac747805, 0x21d67968, + 0x20f1c0ed, 0x9a77e36b, 0xa08f0394, 0x4cfe743e, 0x52df135a, 0xc58dbaa7, 0x42c82d12, 0xfafbde23, 0x56ff5b92, + 0x5da40d28, 0x917128bb, 0x85e8bb54, 0x650a9a28, 0x796fabfe, 0x068ca6ba, 0x52e64205, 0xb5f50432, 0x123fc94e, + 0x54f3154f, 0xc033c71a, 0xa5927426, 0x4dbb0db9, 0xd47b1e7d, 0xa353b605, 0x94aaa996, 0x15ba75d9, 0xd9e7d603, + 0x7f0773be, 0x82bc4c73, 0xa981ec0e, 0xc7f25b15, 0x3e370aa3, 0xfe97775b, 0x86d10134, 0xfbaa7ff1, 0x971c87b8, + 0x52b0db39, 0x38a25971, 0xd9b13564, 0x2578fc47, 0x8068ece0, 0x60a14ce7, 0x1365e025, 0x15c895b6, 0x0df87889, + 0x68d99118, 0x6b5fef7a, 0x603f4eed, 0x87e26338, 0x5698bf12, 0x2b808347, 0xeb0f4657, 0xc7728d1b, 0xffbf1620, + 0xc7bd9e92, 0xc656b42a, 0x56061729, 0x8232d6f3, 0x416ccd13, 0x304b1f7c, 0xaa92590e, 0xba6aa49f, 0x526804de, + 0xae14f2de, 0xe930abef, 0x091d51f8, 0x072dda2c, 0x7a525463, 0x99bb94cd, 0xf758fc8a, 0x7950aad4, 0xa55d2ff0, + 0xd88133d1, 0x775f26d8, 0x23f3bcbe, 0xa5fd1c4a, 0x745ed83c, 0x327c39af, 0xbcb4bbcc, 0x1f76285a, 0x730ba40c, + 0x98409a71, 0xb03ec802, 0xb192760c, 0xbe78cd65, 0x3afc5751, 0x2e0dd937, 0x69642d24, 0x1b9143fb, 0xe82ff8d1, + 0x3e5e7d7e, 0x5d1426ca, 0x6b51334e, 0x37e6694f, 0x5493496a, 0x2e00c1e5, 0x500a81dd, 0x8576a65b, 0x9c858b7e, + 0x0a2f60fb, 0x8295ad5e, 0x3c85c517, 0x62fdea87, 0x7b8728dd, 0xcbe466ec, 0x72cca803, 0xfd3fa6d6, 0x0d65ef70, + 0xb5bd47ab, 0xa20767f9, 0xcc1afbf5, 0xb6d872ce, 0x5500ce2b, 0xa0d37e15, 0x8449a9da, 0x663a6917, 0xf2acbc9f, + 0x8dc35e60, 0x48bece69, 0x0f4bc104, 0xc92399ef, 0x794ec4aa, 0x87920c62, 0x3aa72f4e, 0x3da09042, 0x70737f97, + 0x61392cd5, 0x6a08a7eb, 0x91b24f2d, 0x4c9b17e6, 0x91884bcc, 0xdb2dc676, 0xf72455dc, 0x00112ded, 0x5b22efb7, + 0xa1091da1, 0xf8dbf24b, 0x7c050165, 0xc17f46d6, 0x049d5aad, 0x69776fa1, 0x0f406928, 0x7d5ee1a3, 0x10674d6c, + 0x8a36a9dd, 0xdfa11ea1, 0xcd66273f, 0x4d3e0dba, 0x2326be10, 0x8085b7eb, 0x86a5815a, 0xd6a9c078, 0x1dd6862a, + 0x96e28abc, 0x5997e120, 0x0c7007d9, 0x20e8d00d, 0x4b62fbe9, 0x50db5e9d, 0x4293ec2f, 0xc7f5a5dc, 0x30b62657, + 0x06562d55, 0x34d8345a, 0xd9ca6047, 0x202b2d18, 0xb7410d54, 0xd35590d4, 0xd9624e4f, 0x566086d9, 0x0ba98c0d, + 0x2d257cee, 0xdcbe826e, 0x3d513172, 0x87d29463, 0x25fb0816, 0xc51ed43c, 0x0213fc75, 0x0b95c35a, 0x678f9b00, + 0x5be955ed, 0x5b6098f2, 0xdafd1e44, 0x59e46644, 0x6631c795, 0x50f1cb7f, 0x92ae3940, 0xd4a0c285, 0x331496de, + 0x25bd034a, 0x3403aa9a, 0xdab1f36b, 0x86244de3, 0x185479ef, 0x6c25690f, 0xff4fd030, 0xc6932604, 0x9413d0c2, + 0x8af7de85, 0xaa38f331, 0x92ba15d6, 0xa099289f, 0x4cc0d1bc, 0xf202c735, 0xf0fd83db, 0x249c8297, 0x1bc35380, + 0xdf7c5abc, 0x6c2b938a, 0x48e73367, 0xb41d631c, 0xe5e28bd9, 0xa32b69b9, 0x93455c9f, 0x28ffa910, 0x61a2723c, + 0x5c21874f, 0xc1fcd3f2, 0xc93e46d1, 0xba2f23e6, 0x93069692, 0x233feb4d, 0x93fe10ec, 0x93b4dbd8, 0xcb13fcee, + 0xd23a5561, 0x2040fc3f, 0xf2965d2b, 0x0daa85e6, 0x8e6d5367, 0x591f60f1, 0xa2a6e885, 0xccf8f351, 0xd5537b8a, + 0x73115ca0, 0x4dc37ad7, 0xc407dfeb, 0x2ce44337, 0x2e399f8c, 0x17b8600b, 0xca751762, 0xeef04ebe, 0x8de2d0f3, + 0x68dc3749, 0xf15cb787, 0xaa0a7d60, 0xe04c8111, 0x1857e9cb, 0xb3cef2a6, 0x788c5712, 0x860aee8a, 0x6cf9eaaa, + 0xcdc175a9, 0x89023422, 0xac154f70, 0xbb7cf95e, 0x91df0065, 0x7fbbb3fb, 0xa909e9fa, 0xdc255354, 0xe9e813fd, + 0x7b4ccba6, 0x88cf4673, 0x9ffeaf5d, 0xb4c278a9, 0x11499716, 0x20ef76e1, 0xea7ecacb, 0x91c9a531, 0x38564ff7, + 0x47801c18, 0x0b8efe6b, 0xeb9c4cb8, 0x7dec3153, 0x8fdb61da, 0x92297af8, 0x234a6206, 0xed8cee8b, 0xd7b486e2, + 0x42d7f907, 0x758cd5f8, 0x38203642, 0x3f532cf9, 0xdff762da, 0x9f8de753, 0x9591b254, 0xe0489800, 0x4f7afcd5, + 0x24b333ea, 0xcc4ba603, 0x61df97e2, 0x489efd76, 0x911cb2e6, 0x5c318445, 0xe2300016, 0xd2aced5b, 0x8ff2a279, + 0x97327977, 0x5e9900e3, 0xd8f78a51, 0x2f803376, 0x1e34f69c, 0xcccd8e28, 0xf6054c69, 0x0f799374, 0x164ad9d3, + 0xb84d7609, 0xd79412e9, 0x79a66e79, 0xf5e182f0, 0xf61f8802, 0x2133a1bb, 0x86716e15, 0x97a362f5, 0xba38f4d1, + 0x45d08d2b, 0x2dc575de, 0xdb5a5685, 0x2df310cd, 0x206817e8, 0xc235d476, 0x31fe3c2f, 0x1ec63d06, 0xb8dbb83d, + 0x7d1da0e3, 0xdc66bb4f, 0x1a3d8261, 0xb0f4609b, 0x170e887c, 0x75e38f69, 0x85e8eb84, 0xc4561588, 0x3e5b1e8c, + 0xc569e183, 0xf9518837, 0xddd3252e, 0x2b69d3e6, 0xbbb800b7, 0x7f638447, 0x7391e512, 0x095ac164, 0x0a37022e, + 0x6dbbd988, 0xce766853, 0xbcae3c71, 0x7c5aef14, 0x0a4dec81, 0xbe319e6b, 0x70e93b57, 0xecaa19b2, 0xe92515a8, + 0x84ad2590, 0x8be921d0, 0x048b33fc, 0x11e07ed2, 0x7d2e317a, 0x9598dca6, 0x9565a3db, 0x9327213a, 0x9c928bb5, + 0x55ab369d, 0x6cb26159, 0x000403f1, 0x36f44523, 0x5f504ed9, 0x23fc15ce, 0xf4d0ac67, 0xc8c77bdf, 0xd19557d0, + 0xd258ba14, 0x86c21239, 0xafb457aa, 0x199c8bee, 0x8c561ace, 0xa1c418a7, 0x86d99486, 0xef27830c, 0x82a1af69, + 0xdafafb65, 0xae0c1f86, 0x741dcc95, 0xa627958b, 0x9bbbf2dc, 0x42e404f6, 0x3239059b, 0x8edc3c2d, 0x69595fef, + 0x6ebe4fb7, 0xf42d178d, 0x1f50ed8a, 0x3c6539a6, 0x0915dc53, 0x3fbf596c, 0xd580bdc0, 0x2c471fed, 0x35ae81ae, + 0xf6bc92b9, 0xd8280705, 0xb7dbd1e4, 0x09dff5cd, 0xb8328cf1, 0x13a68c38, 0x4558531d, 0x9569fdb0, 0x2c4110dd, + 0xd646639e, 0xadfc682f, 0x4a4677e4, 0xa6ed83af, 0x93cdc02e, 0xfb9193e6, 0x90d91551, 0x42f61f5f, 0x08b443a1, + 0x93371dc6, 0xef96979d, 0x944ae7a6, 0x533dfc02, 0x48db7b54, 0x553b4f34, 0x9fa15cd3, 0xa0a06bc3, 0xece437bc, + 0x02a1bc17, 0xad80268b, 0xec24b4eb, 0xa8a36d2f, 0x21b57de1, 0x1e67865f, 0x9d465739, 0xc90d166a, 0x94f0ff08, + 0xf4cb2291, 0x9a0098ee, 0xd6cb767d, 0x48e4cc0e, 0xd9b5ec8d, 0x08b5465f, 0x6922dd21, 0x66379a16, 0x2f52aa59, + 0x1a4b4195, 0x403d1277, 0xcaa92812, 0xa6544a0d, 0x563c9958, 0xc72880c9, 0x48ec7cc4, 0xd3e04e42, 0x8b674f81, + 0x6430c326, 0xea0a140c, 0xbb5a2c9d, 0x223d5916, 0x27fc533c, 0x260c87b8, 0x27410586, 0xbedc4c92, 0x82b8b661, + 0x1900d92c, 0x1cae550d, 0x271f2b32, 0x58020629, 0xd28a2adc, 0x93371741, 0x3b41c570, 0xd1de935d, 0x1a447085, + 0xf8fb1c54, 0xba890862, 0xd8f67915, 0xee13a722, 0x449e2253, 0xd6d771e0, 0x63cc8f70, 0x31f9b3ab, 0xa6e60c7a, + 0xe18c9c4b, 0x93026b82, 0xbcb8081d, 0xcfb65252, 0xa13706e0, 0xcb2e549e, 0x97c814e0, 0xd568690f, 0x8b75dad6, + 0x6f4437c9, 0x67d5287e, 0xd3ae48bd, 0xb9ba74bb, 0xcd9920db, 0xa159847b, 0x1abba2a7, 0xb16cfe40, 0xb4d3864e, + 0xb5a851a4, 0x48b6a699, 0x03ddee8c, 0x21be9349, 0x2b526ace, 0x350ed81c, 0x01ed63c6, 0x00518b70, 0x4a80aa72, + 0x259b06a6, 0x8763f8e9, 0x54712638, 0x7dbbc4a9, 0x9df29a1d, 0xacc30ce7, 0xb8120313, 0x3fd1d3f2, 0x0f4797b2, + 0xdd212e23, 0x3aa38ee6, 0x2537a2ef, 0x41b64ae9, 0x360e8040, 0x7ea21584, 0x56cb8260, 0x2a03b9a9, 0x2a5b7df1, + 0x88b25cfc, 0x3dadd4ed, 0x3ab16aba, 0xfc87b153, 0xbeca5f8d, 0x3a7bfe8f, 0x039de011, 0x39e1bd18, 0x682a0d90, + 0x8804c99c, 0x0af59265, 0xcd9f2a7a, 0x2111820f, 0x14a90b35, 0x0b05f75a, 0xb2676183, 0xec589d07, 0x02e2f675, + 0xb03923e7, 0x370707c1, 0x88882c3e, 0x5e75164a, 0xd5ea866e, 0xed0f9ee7, 0xe79a5e63, 0x63e44e74, 0x11a2d110, + 0x5590e3af, 0x1165fc13, 0xaa3e2fab, 0x7ff5089e, 0x179b529a, 0x3179ee91, 0xdbfebe6f, 0x7550ad5f, 0xf0700da7, + 0x94dbf47f, 0x0230f67e, 0xb50478be, 0xc3502edb, 0xbe30cec0, 0xe06f86d2, 0x3396792c, 0x12647d46, 0xa5d05fca, + 0x3543f339, 0x962fc905, 0x95bcf180, 0x08b441e2, 0x7b57ee3a, 0x616f3b73, 0x2a9d5308, 0x8fa75091, 0xd093a54e, + 0xa4be7923, 0xe5312011, 0x924a1352, 0x4aa99a9c, 0xd3ff81c7, 0x023f484a, 0x530187e7, 0x9d0246aa, 0xdcd7a4b4, + 0x6c5d80ac, 0x24c15fc8, 0x7272d96e, 0x5b5a4f64, 0xa9f416cd, 0xbc8ed6dc, 0x6833e0e8, 0xca0bab76, 0xeeb3bc60, + 0xdcdd0bd3, 0x22275f7d, 0xf2a8a6a5, 0xbc88462e, 0x6f4ef7f1, 0xf02ca895, 0x2c8b8990, 0x3195f153, 0x179ecaed, + 0xc420c7f6, 0xae35cdea, 0x0d5e4b56, 0x79ac7711, 0x573c0fb0, 0x084b1a2d, 0xa22528ec, 0x45b3aa7b, 0xd5487182, + 0x29dae54d, 0xada9c4b2, 0x25cac571, 0x61925906, 0x1caf9f1b, 0x46d46e05, 0xb1b6a775, 0xe6de96e2, 0x26f49aa5, + 0x52f4f210, 0xb1a0cc05, 0xe4ac95d2, 0x9d147e51, 0x437fecaa, 0xc3fe8c63, 0x064f6bc4, 0xb9d820ef, 0x931f141b, + 0x21d4f6e6, 0xac361392, 0x65d39ceb, 0x207e6f71, 0x24eb97f5, 0x741f0c79, 0x642fdbba, 0x70f4ebd9, 0x57a98d3c, + 0xb5ef06e3, 0xe2d57b49, 0x781a7367, 0x4aa06e71, 0x56fd3ee2, 0xa2b59931, 0x365116a0, 0xa3319448, 0x4059dafd, + 0xff8a2cbf, 0x0b8bfe6d, 0x65342f9d, 0x780bb252, 0x7a154a00, 0xae6ef380, 0x87697686, 0x01ad6d3d, 0x05926888, + 0xbf6ee225, 0x265f84b0, 0x12306a19, 0xecca09d7, 0x74520cc1, 0x563febc3, 0xa63c7bb3, 0x9f6544e2, 0x12b8b600, + 0xfe732cd3, 0xdd26d7f8, 0x83265586, 0x84df6807, 0xbff87670, 0xd8794e4d, 0xbc19f150, 0x3f8e61ac, 0x49fdceec, + 0x902b2ef6, 0x24c38e4a, 0x101dd0be, 0x99cd6c13, 0x481fc741, 0x82183ef7, 0x35cb76b8, 0x1fd1a656, 0xb5e46bae, + 0xbb89f5f4, 0x2f2b3911, 0x8a432c62, 0x9cbd050b, 0xfbc9066a, 0x2f38d4ba, 0x84cd912b, 0xa4d84fce, 0x2cf05ff0, + 0x829687bd, 0x899e8ae5, 0x27475cf3, 0xcd1758dc, 0xce35ecf5, 0xa7ef4c62, 0x86f06007, 0x2b8605d7, 0xcf6c7b57, + 0xe22d05d3, 0xe80a1e3d, 0x1911bd49, 0xb56ab843, 0xda834198, 0x7497e924, 0x99abbaad, 0x059cbaa2, 0x6d0367aa, + 0xce047282, 0x0dd67cd3, 0x432192a2, 0xeb52bcb8, 0x54e2c65d, 0xc743bdee, 0x95b2359b, 0xfa47c24d, 0x1322072a, + 0xc39a1646, 0x61009aee, 0x478aa97b, 0x06c04542, 0xbd5c0151, 0x7c8cc9b3, 0xf6fa3863, 0x07d56680, 0x1edbcd7d, + 0x1d6232be, 0xcedf46c5, 0x34249f0c, 0xd78d9cf0, 0xb45e26e5, 0x494b5140, 0xac08bb9d, 0x3c25d8fe, 0xcaa838c7, + 0x07703e78, 0xf3a23eb4, 0x50028c28, 0x3711e5e5, 0x2ae5e22a, 0x5a040c04, 0x1bddeb1e, 0x5ecfe949, 0x8c1ecc73, + 0xc4c4b291, 0x2ce6c4c2, 0xf63a7992, 0x32bd6fcb, 0xf3a4f1ae, 0xce78225d, 0xa6b13fa6, 0x2fbce716, 0xd7444e8e, + 0x11e8f5d1, 0x3c6a1020, 0x084f0c4a, 0x3e06e786, 0x94fdb81b, 0x2036b031, 0x0c686afa, 0x0d4037a3, 0xc8948656, + 0x5057b039, 0xffb9e6e0, 0xac681fc1, 0xb2ed9467, 0x5bb66ba0, 0xade77074, 0xd3f4c0ad, 0x5df6ce4e, 0x110a8b64, + 0x810d4d72, 0x5ae78216, 0xf8055489, 0xa6581b04, 0x42548116, 0xbe56fc11, 0x4a7805fc, 0xc542a96c, 0x5947ea7a, + 0xdf1114e5, 0x1a9212cf, 0x01b1b2ec, 0xd12f0eb7, 0x46c0771b, 0x30e38601, 0xd8161954, 0x408bc929, 0xcd809f78, + 0xd29ae77f, 0xa9b926b6, 0x34043551, 0xd2fb5680, 0x50be12a2, 0x65451b50, 0x82db6a16, 0x5a020499, 0xfa9b9f88, + 0x0b8627ea, 0xd8b5d8b1, 0xa5529cd2, 0xa0127182, 0xc56ab717, 0x1cf730eb, 0x65419de4, 0xc1838767, 0xc8a85ff6, + 0xc2b5d569, 0x48346010, 0xeee24b63, 0x5b6a6b76, 0x414d17bc, 0x9e11b76d, 0x2d2570f6, 0x26a23051, 0xe0852a6c, + 0xfff5a07a, 0x8811161c, 0x1a075814, 0xfbc480ce, 0x9e3d7b70, 0x898d7192, 0x9334e0ca, 0x85de6f33, 0xb16d5a51, + 0x422418c1, 0x15220d3b, 0x1d5c7552, 0x456d9187, 0xde232186, 0xe1a8f833, 0x595e5bb3, 0xb8c36f2d, 0x4f987a8d, + 0xbe49ffb8, 0xab657853, 0x40a0c522, 0xf7710476, 0xf859a458, 0x491e7e8d, 0x1b9d4f75, 0xb5c9affd, 0x47c51e4d, + 0x9b3a7405, 0x132572dd, 0xda5d006a, 0x2bc721c5, 0x675a11ce, 0xf2c7ec9e, 0x44919b2e, 0x626a9396, 0x9fd165ed, + 0x5b265cea, 0x26cce398, 0x952ca1fa, 0x86be4d62, 0x751f350f, 0x6a6816ad, 0xb99d2576, 0x2f3214a6, 0x9a150127, + 0x1112c340, 0x0b925422, 0xafdfc749, 0x804c7ef2, 0xea06f047, 0xb2e2a76a, 0x3a7e9625, 0xb9f967be, 0xac44a38d, + 0xee5774aa, 0x049ad3ce, 0xd19a60e4, 0x89e7577b, 0x06e4cfc0, 0x5024a761, 0x6cffbed6, 0x8a47bc4c, 0x00d33a02, + 0x46e39ad3, 0x82b267a2, 0xf35e6f09, 0xdaeeb428, 0xfc46ee2d, 0x9b200b4c, 0x95a2274c, 0x9d53abb6, 0x0fad0e9b, + 0x408e5a83, 0x90a374ba, 0xd84bdcdd, 0xde97dcf6, 0x6a4ab283, 0xfc3f4337, 0xb9c17af5, 0x4084870c, 0xba5e3aa2, + 0x0663801e, 0xff6a506e, 0x88b4c458, 0x6da3a9f5, 0x5d37be6e, 0x684efc43, 0xf1cc6a2d, 0xeaf0c28e, 0xf2b5e145, + 0x788e7680, 0x36973c9e, 0xa4e2768b, 0xdf98ef55, 0x95d04b68, 0x48ae2d49, 0xe3342c4d, 0xaf94c102, 0x63884388, + 0x5fdd623b, 0x0dff7067, 0xa5595ba0, 0xa3217c54, 0x77068320, 0x6710279f, 0xbcedc90f, 0x774e5c10, 0x51f57570, + 0x34a44355, 0xc3d786bb, 0xb10b88eb, 0xa0622124, 0xfb3e4514, 0xcaebfcef, 0x4ee7accd, 0xde30e974, 0x3cd1e648, + 0x93eee67b, 0xf0b8042e, 0x18f5e188, 0x7b21094a, 0x6587fc96, 0x6952aae6, 0x4ce7bcfb, 0x55c7b693, 0x1ff35b4c, + 0x320c1223, 0xe0a1cc8a, 0xb58afd7a, 0x237244f4, 0x9e9862ac, 0x275294fb, 0xaee39fda, 0x7486e721, 0xfd05140c, + 0x1b160fc3, 0x781eeadf, 0x514fbb57, 0x48bdd246, 0x7220145f, 0x74c224b0, 0xeea9db1a, 0x42c7a5c2, 0xde5473df, + 0x79d441f8, 0x8dc4e95e, 0x2b6cb258, 0x5e7ea791, 0x889206b2, 0x32b4a9c8, 0x1773aefc, 0x9bfa06cc, 0x8058374a, + 0x710fb5a2, 0xdd7e5f50, 0x595b45a1, 0x63831d0c, 0x3c5eab6d, 0x1e643b4a, 0xe7b05527, 0x4ce19761, 0x6bd9ec95, + 0xd5cf03a2, 0x2da61dc7, 0x40903b6e, 0x3457c802, 0x4be7540a, 0x2d385d6f, 0xe190e82e, 0xc6066c7b, 0xbd74c362, + 0x01bfc7a8, 0xdc9bfdf1, 0x5ceff0bf, 0x255d62bd, 0x9f7e71eb, 0xb29f1677, 0xbe261432, 0xe472c406, 0xf810d816, + 0x74b90c76, 0x3e3cddb1, 0xa7321d66, 0x1059da4b, 0x27353b1d, 0x084c4605, 0x4ddd1b3e, 0x6e0c0fe6, 0x29e7fe4b, + 0x051f14c6, 0xbbac03e8, 0xbcd07065, 0x4d6b6248, 0x409f8270, 0x9150fb5b, 0x338d9597, 0xeeb954fe, 0xc764666c, + 0x6b74fd87, 0xcce418d8, 0xc5cbcf8d, 0xafbb0b46, 0x2c5ffc17, 0xd54d5177, 0x794304a5, 0x9a48d736, 0x86b34679, + 0x431c2a15, 0x9aef854d, 0xd6544840, 0xa197ffa6, 0x7b70d13f, 0xe0bf3701, 0xeb5674c9, 0x8c4070bd, 0xbad89407, + 0x4de56223, 0x50b8ece0, 0x315351cc, 0xe1146304, 0x6474a828, 0x76be4e2e, 0xdd8566f9, 0x2afad76e, 0x6bf8b426, + 0x327d9e6b, 0x92375249, 0xaad9e218, 0xe50d429f, 0xdc4adb54, 0x2e6ddd76, 0x8960e9af, 0x4a24afb3, 0xcc4a5adb, + 0x1cdea009, 0x23070d5c, 0x761e4271, 0xd58185d3, 0xa405f8ac, 0x7c276412, 0x3f8bfc53, 0x233b3d14, 0x15c59283, + 0xa2b36815, 0x355ec54f, 0x2a0886e0, 0x2791ef9e, 0x317a327c, 0xb467950e, 0x8b4bc99c, 0x5ebd0767, 0x30282c67, + 0x37422a8e, 0x1c1a7389, 0x2c1fc0bd, 0x242be654, 0x1366bf36, 0x72e8399a, 0x57675864, 0x36aa608c, 0x06b3e973, + 0x855b3063, 0x2cc25698, 0x30b01aef, 0x028f9ff8, 0x9f499388, 0x1c211376, 0xb9d05aae, 0x3285d55e, 0x7194a5c5, + 0xa59e97bf, 0xc8b95d6f, 0x4fdc53ec, 0xa310d354, 0xf8f77408, 0x4692fc1e, 0xc255a69c, 0x5cdc9711, 0xff7af327, + 0x944ed487, 0x0ea3cb75, 0xd11eb3fc, 0xea33dbc1, 0x3a4e1049, 0x0f29ef9b, 0x2f252dd6, 0x7961b716, 0x2d52610e, + 0xa8dbded9, 0xa8458833, 0x2d6f6300, 0xb4dbd718, 0xe26d05f3, 0xddb62c95, 0x4f09d53d, 0xcd4ef484, 0xb4902169, + 0x398963a1, 0x8039d0e3, 0xa699ddbb, 0x9a4c7d61, 0xe9cb7f0d, 0xaf2aeca2, 0xee258866, 0x4748c32a, 0x02868672, + 0xe73ccf6c, 0x43414473, 0x17ed8d2e, 0xcc2137ac, 0x56d97dd0, 0xc334fd9d, 0x28ab3dde, 0x32a5e8d6, 0x40c7b07b, + 0x6905393c, 0xaad86b86, 0x84ff3b56, 0xbcb66b62, 0x1f8d3561, 0xf2d75a0e, 0xb90447c1, 0x08911881, 0xd7519cc7, + 0xead5ca45, 0x3314ef86, 0xdeacf62f, 0xbdd0cfa7, 0x66e43c28, 0x12d5051c, 0xade5804b, 0x5276c587, 0x039e8846, + 0x0fd5f96c, 0x648a584e, 0x8fa5a2a0, 0xfe7ab35f, 0x3b15c7cf, 0x7c37cc2f, 0x2df17f56, 0x08f0ae17, 0x76e33606, + 0x832beff3, 0xe4be8344, 0xcbe48e8b, 0x4bc458e4, 0x7a8d463d, 0x192eec15, 0xac520d17, 0x251a17f2, 0x72bfdc5a, + 0xfe77d3f9, 0x7ace7dbc, 0xd6b8b804, 0x42797bcf, 0x7d44da2c, 0xe6d29184, 0xe2f1b47e, 0x7929a8d7, 0x8bcdab5e, + 0x0415d7d2, 0xd0e1cc58, 0xeb48f3e0, 0xa6a14e26, 0x299d2881, 0x5cdd9f0c, 0xb95e07e3, 0x480cd471, 0x48f5a9d5, + 0x88608b57, 0x9b608746, 0x2c6047eb, 0x07eb6c0f, 0x438fa2e3, 0x5be69b33, 0x72b2b2ed, 0x310ed823, 0x0f821ed3, + 0xd219c9e5, 0x855c0a18, 0x7af0bdc9, 0x8334849d, 0x8d6d440a, 0x66342c95, 0xb5b0bc8d, 0x6d609005, 0x2b92b97d, + 0x6a4f5e28, 0xa629e728, 0x6af64954, 0xae737e56, 0x5577b158, 0x2c3b9ac8, 0xa1791f69, 0x7cc6be57, 0xf9b86b2c, + 0x05569087, 0xf941c582, 0xcdd05f76, 0x3475b09e, 0x9315f1c9, 0xbfb2ddb1, 0x27eb8ef2, 0xdf4afe19, 0x71a46fd2, + 0x0b4c648b, 0x89fa97cd, 0x09908bee, 0xb6826440, 0xb5fd0660, 0xb2bb5489, 0x7ddb5eb1, 0xd8192fbf, 0x99b6937c, + 0x0d13699f, 0x266e826a, 0xc3e74434, 0x9220a006, 0x558a93f2, 0x150d9202, 0x190943b3, 0x1dafcf11, 0x89f41eeb, + 0x5dcf61fb, 0x1974e674, 0x69f10a08, 0x9af138bb, 0x6f2e8fa9, 0xcb6f110f, 0xc3752f51, 0x1fbc3001, 0xeb6aa4a0, + 0xa3bad8b1, 0xa465c0c4, 0x6bde35c2, 0xbb77f0fb, 0xc55c0350, 0xc5224198, 0xd63cd846, 0xf07cc6e2, 0xa388d467, + 0xf02cd48c, 0x587a159e, 0xb4268b1c, 0x6995d86a, 0x96a64ee9, 0x6dbb22bb, 0x9a0636cf, 0x26ee3225, 0xa16732f7, + 0x88b0e918, 0xd8aade59, 0x856762fb, 0x5f6e63ac, 0x92e233ff, 0x0b531ed3, 0x9a8cfa6a, 0x53b3be76, 0xe1c80acc, + 0x75b82f2e, 0xb1adaf98, 0xe76018c8, 0x920a94b6, 0x1aee0b48, 0xa951a8e9, 0xe5fc868d, 0x072f55c6, 0x23ae35a3, + 0x3512d9b6, 0x8ec5dab7, 0xccf92ee9, 0xd02bb9a4, 0x0f1608cf, 0x8db82f1d, 0x053728c0, 0xed7abf92, 0xa13e3144, + 0xe558fc04, 0x3df2b309, 0xe792e9ca, 0xac985393, 0x0afd8dff, 0x86d56f65, 0xaad51823, 0x2ef669e4, 0x012cdbe8, + 0x719dadc4, 0x474c4326, 0x648a7de5, 0x763548e9, 0xe2273c34, 0x58987641, 0xcec0ca3f, 0xf2cba75d, 0xd637b1d5, + 0xd58e8833, 0x08dcc16c, 0x3fdf11f4, 0x76bacd97, 0xf0a58787, 0xc197198c, 0x8a11f6af, 0x2f3e6859, 0x8ce7322e, + 0x91ece500, 0x8a9ca749, 0xe59622c1, 0x05f574fb, 0xd1969d64, 0x69a72f1f, 0x06090b51, 0x0cac305f, 0x7cc987ad, + 0x04da4997, 0x5576b5cb, 0x859c8ee4, 0x1e7eaa08, 0x16c0a9a7, 0x4fbe8a0c, 0x13b62e78, 0xee63e4d1, 0xfa55aa0e, + 0x05b83a34, 0xf31e0b9a, 0x8b512efb, 0xf1ac8668, 0xc425216b, 0x73cb93b8, 0x0e26b272, 0x8fac8955, 0xb8fe4374, + 0xcc101d6f, 0xae78b24a, 0x4501e888, 0x8a568802, 0xbadb9662, 0x23464924, 0x5f0687ed, 0xb72abf06, 0x38fd1def, + 0x45b3c778, 0x2ee0c167, 0xae8a0325, 0x3ec44d27, 0x1d762262, 0x9857ebaf, 0x7686bd44, 0x106068fd, 0x1342c1c3, + 0x39126f3f, 0xc0d59583, 0x518ab36e, 0xff4fb536, 0x4c947dbb, 0xe971607e, 0xc1a3b30a, 0xe46fd0f3, 0x22b2300e, + 0x0fdc252d, 0x3f93e617, 0xa17f3ff5, 0x07d3f2b4, 0x88a22c18, 0x4484bd93, 0xe2352147, 0x425d8434, 0x8557f5f8, + 0xf7b03565, 0xf77724d3, 0x7f7c3520, 0x89a8d1f9, 0xe2775a3b, 0x80276e89, 0xfe782431, 0x8b0b36b4, 0x52803dc6, + 0x2b295093, 0xdfd8788b, 0x76b31f00, 0x190f23fa, 0x62e02d40, 0xd41ccf50, 0xb8a759cd, 0x5a1fd7f2, 0x70587e1f, + 0x421cc34a, 0xa87d456a, 0x430a57dd, 0x97c2effb, 0xa067b324, 0x19a290af, 0xd17c3e58, 0xb1f8c324, 0x7122b845, + 0x014c4691, 0x9d21bff9, 0x88e296e8, 0x71904652, 0xc98a78d3, 0xf2dfa5b1, 0x5aa4c976, 0xf7328e6e, 0x522ccd1c, + 0x13282c62, 0x9b3b1085, 0xa7d36127, 0xb430a245, 0x3c4e8a82, 0x5e4fce80, 0x7cb9ab69, 0x6d68b05c, 0xc29fce36, + 0x69ebb6d6, 0x82026956, 0x48ee0110, 0x043749df, 0xe13d14f2, 0x30ea0039, 0x0618ffcb, 0xdfb99727, 0x335a5d86, + 0x0214c2f7, 0xda8e4db5, 0x28fa7f7a, 0xbfb519af, 0xa4af40cb, 0xaae47da2, 0xcffb3857, 0x7c615aab, 0xed88d73f, + 0x93f711f0, 0xef66ecba, 0xfc7098e8, 0xdcb1eaca, 0xd8acafdf, 0xad518adf, 0x5bae53f8, 0x152c799d, 0xd0dbc666, + 0x0e5c6e8b, 0xfc8b87d8, 0xe689933b, 0x57eddbbc, 0xf8276e1f, 0xc7029b4b, 0xdf0a3154, 0xc771d9a5, 0xa4f9275c, + 0xb20775e4, 0xc249a4fb, 0xa797d9a5, 0x7480be23, 0xa14d4411, 0x1fe4cafc, 0xbc40f499, 0x2a2a3ec7, 0x889abac8, + 0xcd657ff5, 0x93199e56, 0x329a49d4, 0x1ea328e1, 0x6e0ce2f6, 0xd0a13c8f, 0xe78cca24, 0x2583fde5, 0xfacd875b, + 0x5d94bdfb, 0x962b9d7d, 0x85d667cf, 0x62092a4f, 0x2e59bbc8, 0x632f32b3, 0x3b8a6fc0, 0x7657f14d, 0x321f6488, + 0xe4954fd4, 0x68ae22af, 0xcbe98dcd, 0x39487c31, 0xeca007f0, 0xe31b1dad, 0x34297c7a, 0x3012b220, 0x4ca4f159, + 0xbcbe5e46, 0x43a3c7c8, 0x6a0c3de0, 0xbc832eba, 0xa1d4a52b, 0x2525f987, 0x62fc5791, 0xc72ef9ca, 0x3fc020ab, + 0xa394d7b8, 0xc17a1b34, 0x4bebfa0f, 0x38a7c1e3, 0x3774ebfb, 0xe0d6e78b, 0x6e573224, 0x34cf5baa, 0x832be8a7, + 0x62669f03, 0x9fb16cf9, 0xdfd3f0de, 0x3fa1f874, 0x19986cf4, 0xcebd98f6, 0xe4293a78, 0x0c7ea664, 0x2431da91, + 0x103fb2ed, 0x0e3cdf80, 0x0627696b, 0x8fd6e3f6, 0xcabdb1e4, 0xbb72ab32, 0x96bf9277, 0xccc0941f, 0x7eb144d9, + 0xd0557605, 0xa204e602, 0xb96f9141, 0xc9ced197, 0x9dad1d00, 0xfac419fb, 0xf53eda88, 0xd2cd279f, 0xfd1483c7, + 0x9219ca86, 0x335bb08a, 0xd058a8ea, 0x05285b66, 0x528bd19e, 0x95ac5431, 0xb192c529, 0x9a7d6d62, 0x1b554e9c, + 0x67920f7a, 0x6edaf80f, 0x66ef5615, 0x32cd80d6, 0xbe68ff1d, 0xe4fdb5b0, 0x3b80c86d, 0x3e8b5f63, 0xeb1bc898, + 0xa47618e3, 0xd54024aa, 0xd6c4648c, 0x8b5fc8c0, 0x90741240, 0xd5733a1d, 0x0d040d49, 0x90a1f9a7, 0xae10a3ac, + 0xde8fa914, 0x35337d58, 0x1eac2bf2, 0x893c2c83, 0x705327ff, 0xc77bf252, 0xffcd8036, 0xf10f86d2, 0xa53220a2, + 0x37a746c5, 0x1d7795c8, 0x6b0325c6, 0xf20eb5d0, 0x6ea8f146, 0xc67222d2, 0x40d8aff4, 0x7d73ac4c, 0x6a0ce05e, + 0xd7f25aac, 0xa327d7f9, 0x99cf76e4, 0x2aa02ab2, 0x4841e140, 0x254604cb, 0xd0e5ea23, 0x46edbd18, 0x4c391a17, + 0xec395245, 0x7760763e, 0x9764b2a3, 0x7181c5e4, 0x0c28d20c, 0x48763411, 0x4b6f2f9d, 0x1a5e03f6, 0xd33fa700, + 0x22036b54, 0x448cf9f5, 0x77873138, 0x92e682b0, 0xf57fcad0, 0x75a2f463, 0x5538e33d, 0x50de977b, 0xbe0ef22e, + 0x5b071e47, 0x9f4ecd0c, 0x50d9192a, 0xacc5c3cb, 0x20dab14a, 0xfc7516af, 0xb24b3001, 0xe5240b7e, 0xe9ca42d9, + 0x05c36af7, 0xf21f65c7, 0x61e2f1d1, 0x0c68f408, 0x9496fc8f, 0x77e91fb5, 0xe042eda7, 0x144251ad, 0xc7c1c248, + 0x9d79a630, 0x76b209ac, 0x58989e91, 0xf32d9c7b, 0x65d26f81, 0xd532a614, 0x517fa07f, 0xbbdfa9fa, 0x638aa012, + 0xa7716513, 0xb1cad7b8, 0x6f5d6d99, 0xe8016bde, 0xd8731ee8, 0xcee12c83, 0x683d3685, 0x4af58943, 0x7877b5f0, + 0xf3e3dc42, 0xfe144468, 0x4bdf7b18, 0x48b7f9c1, 0x667948c4, 0x158f9a51, 0x96a2e43d, 0xb51ad49a, 0x1bea6c86, + 0xfffe6004, 0x38cf9620, 0xa9a7cbd0, 0x51e8d293, 0x56f11ef0, 0x70c3268e, 0x878fe552, 0x7868f891, 0x211256f5, + 0x51734062, 0xc37e5e6e, 0x3b278249, 0x462d639c, 0xe7fc54a6, 0xb9aa0bdb, 0x2b5671fb, 0xa6ced401, 0x944c6095, + 0x7cfede9c, 0xca00df0d, 0x41c53ba0, 0xbfd50d55, 0xbf2ecbd4, 0x487ca3dd, 0x21607e7e, 0xd9ab1ef6, 0xe628c2be, + 0x7896bdb0, 0x17677207, 0xc2a84511, 0x4762e1a0, 0xd2a46f82, 0xdf134e20, 0xb6c57018, 0x48d7067a, 0xaca46214, + 0x84747519, 0xd38d3d90, 0x4aefde2c, 0x62e20792, 0x9e14d66d, 0x125f0daf, 0x0bc0f929, 0x505471f7, 0xe5b4f97d, + 0xbdb2797c, 0x713c086a, 0x76b5bc78, 0xd4c16c8c, 0x03eb8787, 0x3b14e5be, 0xbb5ce24b, 0xa1be371d, 0xa7432dec, + 0xdbf07011, 0xf88753ff, 0x006f1ca8, 0xacf320ee, 0x6bf1c9f5, 0x8bc16a8c, 0xecc8bb50, 0xfc5ec35a, 0x230695b1, + 0x56486b01, 0xbb47227f, 0xe1dafad7, 0x40672686, 0x8909846b, 0xf99980b7, 0x26189ee9, 0x1383eacb, 0x3736506a, + 0x2d247c6b, 0x8bc8325e, 0x7928246e, 0x3e0b71f0, 0x68c860ea, 0x11716b60, 0x4b876a11, 0x8a19ad3a, 0xb9b20e02, + 0x77b7b5b8, 0xb36bd02d, 0x4cec70d1, 0x73aacca1, 0x4b1d2ca1, 0xb58d7691, 0x8b4c3f52, 0xf1c3bd58, 0xb33098da, + 0xc2a2241d, 0x04cb382c, 0x80d4c1d7, 0x088a2c01, 0x24470574, 0xb119de03, 0xfa869fa9, 0xff0646bd, 0x7acac8bf, + 0x64666d62, 0xf8eef6ff, 0x0239de47, 0x5ab1159b, 0xf284e766, 0x3f06a7ef, 0x85a2aa24, 0x08add9d0, 0xf0479060, + 0xbf124fea, 0x6c78b096, 0x077d1741, 0x22959943, 0x9c9f74a8, 0x2f8b1670, 0x84e43037, 0x414e0629, 0xfab9b57c, + 0x1af8bf6b, 0xfb3cd9e2, 0x208fef77, 0xbe4cd23e, 0xc8dc2155, 0x2340041e, 0x213581ba, 0x06f9d04a, 0xb1eed558, + 0xb39dacb6, 0x93babc57, 0xb32b4992, 0xe9f98f2a, 0x2de6a463, 0x0802d307, 0x18a5cf21, 0x38d09e65, 0x6486d6b5, + 0xdf3eb868, 0x14b42b99, 0x5dee5b45, 0x640d7e72, 0xc4a086d0, 0x3de1fa09, 0xc30c20f5, 0x8c5d5a71, 0x18aaff49, + 0xe588d7ca, 0xbaaab89c, 0x395688a9, 0xa67012d3, 0x2e7532fc, 0x56e648d9, 0x3c91b5d2, 0xc38f1a3e, 0x66bee8b7, + 0x34343a99, 0xc33f49d3, 0x117e4ca6, 0xb8d9947d, 0x2d88cecd, 0x78437860, 0xce5c61d5, 0xdeee78e2, 0x0232d685, + 0x52922b45, 0xaa3718a4, 0xa8fd8e7d, 0x9e057d1a, 0x5b295114, 0xa6f32e3b, 0x26b54ce2, 0x4e13ac09, 0x2fa0433e, + 0x582c3973, 0x38ee9053, 0x2729fc28, 0xf5e38da4, 0x59e22f2a, 0x90cd9452, 0x2548be3e, 0x647e8248, 0x136cfe9e, + 0x74a23ca0, 0xc2d8ba26, 0x9038f371, 0x41ff7a82, 0x6957bd41, 0xea709ba0, 0x02bd2293, 0x83aeaa99, 0x8e54e8df, + 0xf7b7c871, 0x394c8a4a, 0xffd22a6a, 0x29377ffe, 0x8137c563, 0x212cd94f, 0x7e7242e4, 0xc1d9c7d2, 0x7f9d45ff, + 0x586008e7, 0x300b3ae3, 0xdc85d2a2, 0x76f8fd12, 0x9c4be539, 0xef03472a, 0x20801e55, 0x8a62f076, 0x90849376, + 0xcc24203a, 0xf2aee89a, 0xa5b38cd2, 0xf7ebe7ca, 0x9fca59d2, 0xfee83ba7, 0x5621ee10, 0xcfa90d72, 0x9f1399d0, + 0xc3e39695, 0x75780e08, 0xcac73d45, 0x9d3f2f8b, 0x221a2daa, 0xe182a8d1, 0xf9181e71, 0x50f204eb, 0x2eab3c2c, + 0x63d1ad07, 0xc9ed328a, 0x983e7b57, 0x083d63c4, 0x4f734d4c, 0xb67616be, 0xf930ba4c, 0xb330bc03, 0xa3f06757, + 0x0c41ccdf, 0x5fb6ee40, 0xb112dd3e, 0x83f11b36, 0xe7784f6e, 0xfa80e3c6, 0x35f1bc74, 0x50090492, 0x1265188f, + 0x6e9fa755, 0x6f4d51f7, 0x66374be7, 0xb6199976, 0x1281ae6b, 0x20372345, 0x1b017a74, 0x082ae93e, 0xe9795454, + 0x026fd2e2, 0xfbb89142, 0xa30deb68, 0x75e7640f, 0xbe3db876, 0x4fc1122a, 0xba27bf37, 0x9ef845ae, 0x853d7e60, + 0x914d93f7, 0x69432a66, 0x7b3eae69, 0xd7335c37, 0x68971616, 0x10e12558, 0x90cf62a1, 0xd7ba05ca, 0x8dbcc199, + 0x7e2dceda, 0xc1b947b0, 0xb86f4a27, 0xa6c64859, 0x9e95f740, 0xc81e6909, 0x8cf1b1d5, 0x57d28ab0, 0xbea22f13, + 0xe014ee63, 0x5ea75e8f, 0x0dc510df, 0x3d866549, 0x86517f1c, 0xa9684d17, 0x1098542a, 0xcd643137, 0xe8b0a671, + 0xf4ef4c86, 0x27c0653e, 0x6a9c70b4, 0xb29940c3, 0xed3b07c1, 0xc3a0f727, 0x2a309702, 0xaf455416, 0x0190715e, + 0x09038fa3, 0xaef3afa9, 0xc8163469, 0x3917e195, 0x60324de9, 0x2fab179e, 0xf4bd0fe1, 0x950ed058, 0x0d24bdee, + 0x09bb1b7b, 0xf9152f8d, 0x47bae1b2, 0x64e6d9da, 0xb06a2f52, 0xea3afa70, 0xf220532e, 0x0aca8ab7, 0x7336a4ea, + 0xfe14ef52, 0x3b3ff33b, 0x7d096ffe, 0x082ffbb7, 0x1be9e875, 0x5a5dd60d, 0x60977044, 0xec563b18, 0xa54a3179, + 0xa30a9638, 0xe98940e2, 0xde482099, 0x4f576e7e, 0xfb123ed9, 0x1bef977c, 0x8d8c658f, 0xb588b770, 0x3c8a9130, + 0x03eb0950, 0xf250ac1e, 0x9d410ec7, 0x6379d966, 0xb76e2279, 0x4748fe57, 0x8757ca64, 0x92d5f5dd, 0x7f69b318, + 0x3ae90dbd, 0xc1a7f38e, 0x0e959ac7, 0xc3127799, 0x557ec15b, 0x87cd1197, 0x5477c323, 0x13e1a6da, 0x81f27e17, + 0xfb8c9c60, 0x462d297e, 0xca76c9a0, 0x3a7bf8ee, 0x833c2acc, 0x6df6fd09, 0x0def8af7, 0x56a87536, 0x4028ca4c, + 0xc611bf05, 0xd8d3ddfa, 0x769ac429, 0xe119afa7, 0x51c1a656, 0x613954b8, 0x3e1e4575, 0x274f05df, 0xa9b0d89b, + 0x4637073d, 0xe1dc3bb3, 0x2b38e1d4, 0x97c64361, 0x8cbe01ec, 0xba5326f9, 0x2b79bae2, 0xc2d36094, 0x9493f2ca, + 0x88c1c20e, 0x857c2749, 0x6f4e1712, 0x66142e04, 0x5dcccaec, 0xe7cd073b, 0x22943f12, 0xcaea134f, 0xfe335ec7, + 0x47e26af9, 0x045213d5, 0x5d1820ff, 0x4d2157ac, 0x7da3fa03, 0x4542eec7, 0x369b5aef, 0x88b41e11, 0xb4c81bf6, + 0x76bb589d, 0xd705fbc0, 0x4b2bd5cf, 0xe7b033ff, 0x402123c3, 0x8e705b79, 0x7adf93dd, 0xe168e4b8, 0x7a312743, + 0xfcf94e59, 0x9658629c, 0xc39ab1c4, 0xe8e83428, 0x26daf3ce, 0x9e3dd308, 0xaf4c7df1, 0xbe4021aa, 0x352d8c82, + 0x32a8f69c, 0x740a2962, 0xec560434, 0x83924a0b, 0xa137fdcc, 0x9ed79c12, 0xd38117e5, 0x5829b3b1, 0xf95e1561, + 0x8ac5ae33, 0xe529b6ea, 0x984494d0, 0xbed83bdd, 0x7ae8406b, 0x0b932d11, 0x17e06ae7, 0x28169860, 0xc6b6f9f4, + 0xaecf55ba, 0x95763bc9, 0xab2b805b, 0x2a30710c, 0x817c833f, 0x03d1596b, 0x5bee8cc1, 0xea9f7ebb, 0x57e5950d, + 0xb670ecac, 0x2cc81011, 0x6da0bcbf, 0x8a557783, 0x3e328d13, 0xf7dd225f, 0xcef189bb, 0x0776ca2d, 0x2f01b2fb, + 0x3c4f93fa, 0xe630030e, 0x97efc7c0, 0xb18df001, 0x2fb0ce41, 0xae4a50b7, 0xd9fb5ecc, 0x92209419, 0xdd38d1e7, + 0x500956f4, 0xd4a70f63, 0x5d7c9ace, 0x651ec63b, 0x6ae33489, 0xdc548261, 0xcd8f9a0e, 0x0e7c1e0b, 0x7f3f529e, + 0x68eee0b0, 0xa01a590a, 0xf0bafcd2, 0xa3148e02, 0xd9a0626f, 0x4ef7da9b, 0xa06c3e97, 0xd4795a28, 0x8659b9e3, + 0x531da00f, 0x6f39782d, 0xc759e39c, 0x09d23cf2, 0xb79d7879, 0xffe0a47d, 0x0e71b788, 0xa096f563, 0xe67bb1a5, + 0x78ee3262, 0xd9df609b, 0x8095a896, 0xbfb766a8, 0x8bfda125, 0x7c7c88ff, 0x9530d321, 0x8eec92dc, 0xa279f7b7, + 0x27c10ff0, 0x3ec34751, 0x7101d3b9, 0xc3020b3e, 0x06627708, 0x95f08026, 0x7e5c282d, 0xc195442f, 0x647b6bdb, + 0xfb96bbb3, 0xefe4aac1, 0xbed5d875, 0xcec7bd9d, 0x4450857a, 0xcef6f7f0, 0x1ba66da6, 0xc9e37dd6, 0x8b255f66, + 0xd8c751c6, 0x3fde1dcf, 0x1863cb3e, 0x53dacc11, 0xf95a171d, 0x10e900f0, 0xb9e37c52, 0x9c9ca3f7, 0x5455b910, + 0x8664d457, 0xb20cfb05, 0xd9cf9783, 0xb4c8334d, 0x9d0bca9c, 0x513211de, 0x9a397e5f, 0x24be6d0c, 0xa06afb1f, + 0xf5623dda, 0x803e5992, 0x92a9a61e, 0x5e31dca5, 0x28b37e1d, 0xf29f7ae7, 0x99b5c35e, 0x2c527c6c, 0x13638b61, + 0xd0754868, 0x45ca8bf7, 0x26c17032, 0x593cc220, 0x3055ef42, 0x4bbcb58e, 0xe4304ed3, 0x61c4523e, 0x570e98b7, + 0x586661b3, 0xde5ac3af, 0xb640c7b2, 0xa50c8a6a, 0x3ca74a4b, 0x9cb22d16, 0xe789867b, 0xb719d1eb, 0xff192bca, + 0xe63a7aff, 0xad563bf1, 0xc9f904e7, 0x2285faa9, 0xa7998eb1, 0x1987d0f5, 0xc630f2d2, 0x364e2fe6, 0x1fce4f03, + 0x57d405b5, 0x3279a0f2, 0xc7573bac, 0x4243c194, 0xf7c03986, 0x2a0f1aa3, 0x71f2f3f1, 0x5c02e585, 0x91f67388, + 0x48172335, 0x86cd0048, 0x7d92296e, 0x11a45cb2, 0x760082eb, 0xb55bc810, 0x9cb91c40, 0xce7f0a87, 0x77537e73, + 0x7e2924c0, 0xe2aa6d29, 0x04ee0ed1, 0x3c89a44b, 0x6db2daff, 0x6fdca923, 0x3749bb83, 0xd73d2e37, 0xc7d45a9f, + 0xdd3edde6, 0x7fe60f00, 0x17354a42, 0xd727ea3e, 0xdd9a3fae, 0x4a5448ec, 0xa3fd1c2e, 0xd51b9212, 0x54064ce3, + 0x393f0fb3, 0x8871ac38, 0x4ec8448b, 0x28fa41d3, 0x41c6c7da, 0x47214b30, 0x545ac071, 0x8b26ba9c, 0xd737a103, + 0xb36f1d9b, 0xc5061fba, 0x252f9679, 0xad339f0e, 0xce26729e, 0x8f0e3448, 0x473c113c, 0xd7b06762, 0x4dda0fae, + 0xbef9414e, 0xf728b570, 0x54898c76, 0xb49a748a, 0x9ae7fc59, 0x353eed81, 0x8562d18f, 0x7333fcb3, 0x1f458dca, + 0xe8e1b271, 0x792911a7, 0xaeab5f6e, 0xe0852fbf, 0x5fad0a36, 0xffceb9fa, 0xdb0f250a, 0x50098eb5, 0x3b47c4f3, + 0x8b3cc760, 0x10e8d3f9, 0xb1484f3b, 0xabcd56a5, 0x729aec1a, 0xbe0786b8, 0xcd9e2949, 0xdbed77a6, 0xa137c99a, + 0x93145796, 0xecc5aa3b, 0x64cb2972, 0x830cf577, 0x47b52d5e, 0x712ffb23, 0xb0a48e59, 0x34b4b06a, 0x5a404d43, + 0xcad9ce33, 0xb63f8d3f, 0x340ec3fd, 0xb5973a4d, 0xadb894ae, 0x19d0d4e6, 0xe61b13f3, 0x9ebb630d, 0x2e0df2a5, + 0xf24724c9, 0xabd2beee, 0xe006b59b, 0xc97656d9, 0x852128cc, 0xcfe49986, 0x703ccf52, 0x73f73df8, 0x34cf0007, + 0xaa1273b2, 0xce30890d, 0xc1c089a2, 0xc86a62e5, 0x5b225e8e, 0xb0b06405, 0x24755fbc, 0x30ddef34, 0x401a4708, + 0x98de766d, 0x3c6a133d, 0xf4b8165a, 0x0c32e1a5, 0xb014b8fa, 0x6882ae80, 0xa3d6bd8f, 0xff0a4e8b, 0x507162fb, + 0x00da2217, 0xab96c328, 0xf8bfb2cf, 0x1e49053e, 0x3327bc6f, 0xb5c3368a, 0xba97922f, 0x76abe68d, 0x7781c30f, + 0x9d2df558, 0x4f47249a, 0xf4a3eb32, 0xd836460f, 0xb22468dd, 0xbfe9aba1, 0xb9a9c2af, 0x3977ae67, 0x8ff23abc, + 0x40867314, 0x60b862a4, 0x6b4d2bee, 0x146a7167, 0x1d11cefd, 0x03cbad3a, 0xb4fbd77c, 0x0b71a3dc, 0xd785a414, + 0xa642d656, 0xbe57a080, 0x2cb6ce84, 0x2df8a81d, 0xa0729db7, 0x61c06bb7, 0x8e7c938f, 0x339a1cd5, 0x2ba95dd8, + 0x12a0c00c, 0x5d9ce822, 0x907fad77, 0xee060df1, 0xf9b518df, 0xad9d6d74, 0x17056d9e, 0xa8d2c6c5, 0xaf298a59, + 0xfb2629a6, 0xe149b17a, 0x95d2638e, 0xdf48c44f, 0x6f3abd21, 0x5dbc6993, 0x65530e2f, 0xae423500, 0xc4fbbfeb, + 0xfdd7e176, 0xf39f7468, 0x24900562, 0xc1bca88f, 0x4541c5dd, 0xc434064c, 0x87a08336, 0xc908ef97, 0x7e18c2ee, + 0xf1064e71, 0xa7642622, 0x82b8dc03, 0x7f388420, 0x6e6ac701, 0xaa5a16f0, 0x191f3e8d, 0xac9f33a0, 0x1839bf93, + 0x2d5b93b0, 0xac780d96, 0xf48c29e7, 0x79d71ab0, 0x116abd19, 0x8ce67275, 0x0969e901, 0x7ffc3f3d, 0xd61997fc, + 0x7d6328e8, 0x5a16fe0b, 0xa8a3e303, 0x85454aa4, 0xa0471323, 0xe791cb15, 0x6042580e, 0x515abe54, 0xf6a7808d, + 0xd5e771c4, 0x3d07d8a2, 0xdf406248, 0x8da133db, 0xac1892fa, 0x4e8ea890, 0xdbe250c8, 0x1d68caa2, 0x410da178, + 0x3ddacf39, 0x6f81f884, 0xac4a35a1, 0xd84581db, 0xc11be06c, 0xc5f9ecad, 0x1796f0c2, 0x695e40c8, 0x2ca53370, + 0x5693a631, 0x95790b24, 0x964ed2e0, 0x69c51c05, 0x8080dd79, 0x22fc0afa, 0x4f741bc5, 0x1002a92b, 0xb86f4614, + 0xa6e12851, 0x3350c9e7, 0x8a2f2ec9, 0x41c2eaed, 0x07df9d63, 0x447dc144, 0x091c67cb, 0x68e6b110, 0xb702e318, + 0x7eda598b, 0xe191a7c1, 0x4e0ba090, 0x75dcbe98, 0x90b00f04, 0x5b267231, 0xb27f52bf, 0xaf5b2802, 0x38757069, + 0xbaeac964, 0x0b10c27d, 0x5cda3726, 0x8f35cf76, 0x215e5079, 0xf3519ae7, 0x95024bc4, 0x7c35bc04, 0xdcb471fb, + 0xcead1178, 0x285186eb, 0x2434b931, 0x2b55a005, 0xe1962385, 0x2b5ab2ea, 0xfe06bb1c, 0xc116fc54, 0x4821e49d, + 0x1a424cbf, 0x7e572350, 0x757f142a, 0x285973b9, 0xafe7ba16, 0x2f3a73f1, 0x1cde0d33, 0xb945b34c, 0xf6f935ee, + 0x9c6dbe53, 0x4ef886d4, 0xb76cd53f, 0x83be1a04, 0x434e652b, 0x507315da, 0xc4c3d7cc, 0x7bcd6606, 0x434f9fca, + 0x0fe00b49, 0x2a397256, 0xbb52ec89, 0x5c3d05b2, 0x0ab55cf8, 0x03aeaa5f, 0x15da750e, 0x6db7d469, 0x5434248c, + 0x63685c91, 0x900db82d, 0xc8af93a3, 0xc0fac972, 0xd0bcacb4, 0xf06f8360, 0x92b04ce2, 0xf8c6e72d, 0x45997f9f, + 0x4491c99d, 0xc19e0ba6, 0xb3d4efba, 0x7002dc17, 0x5e2e38c8, 0x5e1cdd37, 0x27f96147, 0xb495533f, 0x26449ce3, + 0xfa399425, 0xcf6613e9, 0xc7812398, 0x7bc31d1a, 0xb4a8d5b3, 0x679a2a6d, 0x59c203e2, 0x918147e6, 0x07194fb1, + 0x45f5ac03, 0xc7d5ab8b, 0x63d5f0e4, 0xe6ddf8a7, 0xc77844b7, 0x5aed261d, 0x5fcc4142, 0x75535136, 0xda518c86, + 0x7f0cee9b, 0x951972ec, 0x6a76cb7d, 0x9f5a7760, 0x95ab9216, 0x1e9325dd, 0x8907f8d9, 0xfe8c4fd5, 0xb94faea4, + 0x88afdce8, 0x46376e9d, 0xfe22f3fc, 0x97ea0636, 0xb4ecc54b, 0x738e8f53, 0xd1cacc53, 0x82485ff6, 0x59b7a122, + 0x5bf91593, 0x2f63a0b7, 0x0db68f3c, 0xa3eba1d6, 0x2454568d, 0x690dadf1, 0xda5a560c, 0x13d74317, 0x1d48f01a, + 0xabd3f13b, 0x2834c90d, 0x689e8a2f, 0xa75c2e69, 0x874bb412, 0xfe0e2db3, 0x24d2ee29, 0x9c9ca377, 0x8c5a92b6, + 0x7fa0aa41, 0x5a5f8651, 0x427b1e77, 0x540bb8eb, 0x073a8399, 0xed530c8a, 0x5fed09f0, 0x056b70f2, 0x13b34405, + 0x2a0fad6f, 0x0f362ee9, 0x5d37cb7f, 0x96a64c25, 0xa12922ab, 0x55a6a7b2, 0xe0d5f513, 0x7bd6725f, 0xbfd66228, + 0xcb7df5eb, 0x3e0f4b6f, 0xde596a0f, 0x5e757eb1, 0x6498ae24, 0x52653a62, 0xe9098346, 0xdaa176e3, 0x56fff30a, + 0x7c213b78, 0xc8cd1384, 0x8ff4aebd, 0x7bba66b0, 0xf5ed1cbc, 0xd3d22009, 0x294dd44f, 0x038ddda6, 0x72f5aee5, + 0x3a276c32, 0xd0084b64, 0xa7f1bfd1, 0x6701df88, 0xe78b8d58, 0xbb9166f2, 0x050343d6, 0xdcd9067d, 0x5c32b140, + 0xf170dd4c, 0x3148758d, 0xa74812bd, 0x12880609, 0x16bfda6b, 0x03a8b6f5, 0x9bbdedb3, 0x81dd9dad, 0x76b890cc, + 0x72edd190, 0x5e898110, 0xa85da601, 0xd6900d35, 0x3df2b422, 0xa6fe05a6, 0xb49972b7, 0x5fb262c4, 0xb7c981a8, + 0x0d604346, 0x49270e0e, 0xb5f4818b, 0x3c76e043, 0x929e75cd, 0xe96fba3d, 0xe4b7c54f, 0xec4847f4, 0x6895fa0a, + 0x06a1c192, 0x88850792, 0x6baf6989, 0xdef242d9, 0x60d278fd, 0xb3c77d6d, 0x520f6e60, 0xe65a3bc6, 0x208e8332, + 0x6c615065, 0x035c744b, 0xa8fda3be, 0x3183366b, 0x5eec7c60, 0x39940dfe, 0x17149bbb, 0x86ea7cb6, 0xdb764de4, + 0xe3753fad, 0x6985ff79, 0xf0b5c03c, 0x80475416, 0x9675d549, 0xcb1000af, 0x13e356f6, 0xe2d85167, 0x060c9b4f, + 0x35ebefb2, 0x41796049, 0xa35c6138, 0xc094b827, 0x00307b2f, 0xeabe88d7, 0x4e1656f8, 0x89252918, 0x8fe3e9cd, + 0xa1e88413, 0xfe4206bc, 0x3dea97ad, 0x166d7a76, 0x0166c4a8, 0x2ffa33b8, 0x8744ff76, 0xe4714f2f, 0x9c73b00e, + 0x2fa841fe, 0x07d6d256, 0xf644d0eb, 0x37e8b58e, 0x9027775c, 0x4297fa7c, 0xe98defc7, 0xc51d57ab, 0xad88b4c5, + 0x0761e98d, 0x1e76968c, 0xd025e7e3, 0x79acecbf, 0x2c963fe9, 0x86590b6f, 0xf1096b77, 0x3fe5bc22, 0xef4740f4, + 0x65e4c61f, 0x4a83fffb, 0x53e48e20, 0x3ad102d9, 0x0fb84377, 0x7cba70f6, 0x217a46a3, 0x5443e39a, 0x77b4da59, + 0xfc174021, 0x97959708, 0x852d8afb, 0xa0b36396, 0x570ddb05, 0x284f80b5, 0x502b765b, 0xe84942cc, 0xb770eff9, + 0x6263002a, 0x80019b3f, 0x8cd1ee55, 0x424743d3, 0x2a370b17, 0xa769a94b, 0x7e6503c8, 0x6faf16ce, 0x0891a5bd, + 0x76c25cf2, 0xb468c723, 0xc874162b, 0xf3f7adeb, 0xa9d4c762, 0x9041812b, 0x8fda1bce, 0xcd89bd43, 0x2b4bb46d, + 0x157a9882, 0x7627d408, 0x33e6d895, 0x8f16b4b0, 0x8e1abd26, 0x9f7884e2, 0x7402a8ad, 0xbbb1c7a3, 0xd52e335c, + 0x6f6d18ee, 0xcb6c4b76, 0xb896a407, 0x4538f24f, 0x1f838f07, 0x188f769a, 0x18277848, 0x5e478e03, 0x38533ce2, + 0x74235049, 0xc9eeb7ae, 0x46c4dba0, 0x67093799, 0x9d021c97, 0xe97d67b3, 0x499b43de, 0x25555bb4, 0xda4407eb, + 0x1711816c, 0xf7430816, 0x02460f86, 0x588ca372, 0x4057ecbc, 0xc5095f90, 0x4698e4d6, 0xb5c8f839, 0xf9821ce8, + 0xb57e6ebf, 0x8c254eb0, 0xcd35cd50, 0x67d2be0b, 0x206e16c6, 0xe18770db, 0x2d30c278, 0x4b94e366, 0x51e95ddf, + 0x9a9508c7, 0x379712c4, 0x6f35822e, 0xa4e61552, 0xe1b8b40d, 0xb7c6374e, 0x5af190b8, 0xbd205771, 0xfdc8d9cb, + 0xd29ceade, 0x7792e889, 0xb4d1666c, 0xb5c2ea95, 0xf1363c48, 0x7fd2dba1, 0x7275cccd, 0x23392ec9, 0x060722b1, + 0xc4897c7e, 0x4e0b2580, 0x3cfd7a73, 0xd5a3e393, 0x4fd3357a, 0xaa1f4ade, 0x032583aa, 0x3a3a6baf, 0xb4aa9f25, + 0xc774cf39, 0x41f64470, 0x2947bb9d, 0xeee13965, 0xb735b2df, 0xa9dca530, 0xd851c4b5, 0x28d3e731, 0xfbc11c2c, + 0x7151bcff, 0x64f06d6d, 0x8975a820, 0x028e41c5, 0x5e2f5388, 0x46ceac10, 0x4ee03105, 0xb1759a7e, 0x4db352c5, + 0xa7894144, 0xe2b84fe2, 0x2ee2c5a1, 0xb3cbef83, 0xda82d611, 0x74e22450, 0x62f576f3, 0xba477c46, 0xcbe5310d, + 0x9d7be74c, 0xa34f9fef, 0xb5a9b9a0, 0x5ceb06f3, 0x4174dc19, 0x934bb2cb, 0xb1928eaa, 0x1013e84a, 0xcca6eda1, + 0xfa789d18, 0x0c47e422, 0xd76ea934, 0xe877c68b, 0xe20278cf, 0x8d2f4cb2, 0x6479b8a1, 0x970d9518, 0x940fa1c2, + 0xd204b879, 0xb2854d20, 0xcd189c07, 0x09f2db8f, 0xced16026, 0x45c1c2e1, 0xd9d166dc, 0xffeea3ca, 0x49a7df1d, + 0x410c1b21, 0xd6b1ef63, 0x6c3b31ee, 0x9263442b, 0x4d3ceedd, 0x017fcbd3, 0xac20cc14, 0xb85b39dd, 0xbffa17c9, + 0xdeb565b9, 0xe2201509, 0x4df46247, 0x0b17c39d, 0x9f1cbd5f, 0x301dc9fd, 0xa8104206, 0x71f76596, 0xb67fe62f, + 0x824e1e29, 0x245690ed, 0x4f182b33, 0xbe9d503a, 0xe20a96b8, 0x06262410, 0xb2ec6954, 0x613c52a1, 0x576d7565, + 0xa25aac1d, 0xfeb8651c, 0x067e20f1, 0x539f702c, 0xa23ee4c6, 0xed7772da, 0x15bf3d70, 0x7f87156f, 0x6e454e7c, + 0x5815dc60, 0xa1c036fd, 0x2fadebab, 0x355ccc39, 0xa706ca41, 0x82a27870, 0xcd750e0e, 0x3d7f50e6, 0x2b678d4a, + 0x438317ba, 0x45f16d18, 0xdc901e53, 0x28b79531, 0x812530ca, 0x5ec13d16, 0x71a0a1a0, 0xba3e3342, 0x7037876b, + 0xfe78f808, 0x7e397e1a, 0x75707e0b, 0x13fd5f94, 0x4a6197bc, 0x08a6caa7, 0xbb2e5048, 0x954e7d5b, 0x67a63a74, + 0xd6a41140, 0x6c213a3e, 0xa20e8194, 0x33d0592e, 0xdd80bdc0, 0x47189906, 0xe4ea25fb, 0xcfb1f5c4, 0x10053631, + 0x55682878, 0x3cc9666e, 0xbf0f946a, 0x50af4034, 0xa0b561c7, 0x4caed1f4, 0xe94d38f1, 0xea42590e, 0x62d45a14, + 0x53213783, 0x3799b63b, 0x6d8f019e, 0x1eb48ccc, 0x5344aaa9, 0x7cbe56ee, 0xb9def1bf, 0xce8adec5, 0x33952056, + 0xc6d039c5, 0x053788f9, 0x8d74bca8, 0xbe7d5498, 0x61f005ec, 0xacb65510, 0x71f5a600, 0xa2ce6bad, 0xef2ad802, + 0x7637ddbd, 0x7ea44ce4, 0x935ec57c, 0x57b3e97a, 0xbaaf3010, 0x4e032e5d, 0x2c693263, 0x04c7c32a, 0xb6125053, + 0x75279d04, 0x4a3a3eee, 0x46e73f11, 0xce9988b0, 0xc302a9bc, 0x761fa8a4, 0x36d6a576, 0x3d206445, 0x04470c3f, + 0x1fd35239, 0xfda86395, 0xc3550b4d, 0x9f0c82a2, 0xb08c6d4b, 0xffe45631, 0xd25be98d, 0x1dcd79bd, 0x7bd8a6bf, + 0x2dae31e4, 0xeaed9636, 0x4d460cb7, 0xecfe1caa, 0xdd19505f, 0xe3bbab42, 0xeee08bb8, 0x912f2fec, 0xad448715, + 0xee58053e, 0xbce42f63, 0x852e30d2, 0xf9fa26a5, 0x4f65e06c, 0x731820f2, 0x0a79ddd2, 0x9e3b2675, 0xcb79db88, + 0x0f0060e8, 0x10d581ac, 0x434f9dfb, 0xd4452125, 0x765cca18, 0x20991c1b, 0x64a2c706, 0x2861e1a7, 0x9fe2701c, + 0x0ed3e9fb, 0xf406607b, 0xf5d4243a, 0x657eab08, 0x064dc48f, 0x2d128d9d, 0xbd0c298e, 0xd8dbd748, 0x1fdb387b, + 0x516e94f8, 0xfd0a6fe9, 0xa94d19c6, 0x8e498adc, 0xbd6c825a, 0x134917b0, 0x134ec430, 0x4a9e0cd5, 0xf159065e, + 0x457fb84d, 0x5337fba6, 0xc998b80d, 0x07c4b5ac, 0x10a5bab5, 0xcd8e4ee6, 0xef7d11c4, 0xa6c718cc, 0xe6aa258f, + 0xc4cccc3a, 0xd070fa2c, 0x63faf703, 0x9c0e11ac, 0x48fb56ec, 0x96c8aec1, 0xbf4d2a0d, 0xe468016a, 0x075ba1ba, + 0xedb5a7b1, 0x2cf56a62, 0x830abda7, 0xe1d3edcf, 0x4c2875bd, 0x4a7d98b4, 0x944f9948, 0xa4350e27, 0xe117ea0e, + 0xd172a256, 0xa7a17765, 0x52cee3f8, 0x0b412173, 0xb0aef278, 0x9f6a61f3, 0xf4bd0703, 0xec8ea5b3, 0x036d757e, + 0xa1ee0704, 0x292c823c, 0x005ab03a, 0x335935f2, 0x3bbd1c6d, 0xc08ec8f6, 0x98274126, 0xda1f4cd9, 0xfb401254, + 0xf73ae989, 0x9f949746, 0x4d64d501, 0x42b442b3, 0xcdfa9486, 0x46edfd40, 0x11ea21f8, 0xf20f5702, 0x0e65d9e3, + 0xf42a75ae, 0x9e9e538e, 0x803139de, 0x523d13ac, 0x13474513, 0x0c4f75ec, 0x27cc5ceb, 0x9c4bed26, 0x72531372, + 0x253facf6, 0x03690ee7, 0x8add4d17, 0x022607cf, 0x13eb99f6, 0x931f551c, 0x0b92ba36, 0x7351b37b, 0x148d5c07, + 0xa82dace4, 0x785c35dc, 0xaf750929, 0xb1443ac4, 0xdd1138dc, 0x92b0e180, 0x23abb58c, 0x0fd6954f, 0xb280a525, + 0xcee20bad, 0x58a7a953, 0x801bfcd5, 0x89232d83, 0xf19f9246, 0xb9b30b06, 0x4a05e2db, 0x76ec7feb, 0x879b750c, + 0xd5a3822e, 0x5233d7c3, 0x274ea04a, 0xd049653b, 0xc414a978, 0x7e93cf25, 0x419d5e82, 0x64a53fcc, 0x8ba3ff5b, + 0x9c887e7c, 0x792e2f70, 0xdcdf2c86, 0xcaa1e232, 0x2bf1a2cd, 0xce230f03, 0x218620e2, 0xee98fbdf, 0x87897d24, + 0x4c231931, 0xa17eb4c4, 0x0ec82763, 0x13b35883, 0xc23154db, 0x1e6a4634, 0x382afcf0, 0xb0357dd0, 0xadcd430e, + 0x63de2d05, 0x12e666b4, 0x09a958af, 0x03223fbb, 0xd6345ee4, 0x74d402f5, 0x237119ac, 0x1088c309, 0x700e776e, + 0x89f6df8b, 0xdd38d1e6, 0xeacf7c78, 0x766765aa, 0xbab0ec8e, 0xa2c70075, 0xd0393f4a, 0xfb880b1d, 0x61daf25d, + 0xdf66895a, 0x9aa37207, 0x4537b368, 0x6b6ce888, 0xab03d5a2, 0x7f64674f, 0xb52f38fa, 0xcf85d1bd, 0x702f88ea, + 0xbc4174bd, 0x186dfdee, 0x0e342ba4, 0xc045ff3a, 0x89fee3b1, 0x726e76fc, 0x6739292d, 0x9e047545, 0x7ed94b4e, + 0xf3d89bef, 0x209b2fd6, 0xba20fa41, 0xd851ac74, 0x28da267a, 0xef98dd93, 0x991debfc, 0xaf3d80a8, 0x90a437e4, + 0x0a71f5c8, 0xe4313d6e, 0xc089db82, 0xb02a80fb, 0x5726a5a2, 0x1fb9c1b0, 0xa7b21d79, 0x81ef8c24, 0x27293fc5, + 0x50ef1876, 0x61d35b77, 0xfd589d91, 0xb3d05c3c, 0x8062a647, 0xfbfd65d1, 0x00cee376, 0x35cc46c6, 0x9d0a4aa9, + 0x1f113bf0, 0x6c544b1a, 0x6075b43a, 0xaa914d12, 0x00edf7d5, 0x25427b04, 0xf3850b61, 0xf8eb7f66, 0xb783d7ff, + 0xd245d633, 0xe7dd690e, 0x63c2885f, 0x08fce9ab, 0x50392363, 0xd814fb3e, 0x31daf81d, 0x2d2c5186, 0xfc3cf64a, + 0xf60eabe8, 0xcedcde29, 0xf4648b21, 0x9661e8a4, 0x7629831a, 0x6a21888a, 0xd58c4dab, 0x58a03532, 0xbd3f5e8e, + 0xdcb9e023, 0x8b8148a4, 0xea56b89b, 0xe31bdc66, 0x70b8ab0d, 0x46d1b3bd, 0x43c86012, 0x304b84c6, 0x7646318e, + 0x6b6df343, 0x55047b56, 0xe4eb178a, 0x2740d414, 0x2f062c6c, 0x2bb87ab3, 0xbbe46759, 0x604592fd, 0x28034951, + 0x5a41d5b0, 0xab3cda0a, 0xec016b00, 0x7892a766, 0x69a55747, 0x5efc7560, 0xddc2a900, 0x22eb94af, 0xe60437d1, + 0xee44e8d3, 0xf371cc73, 0x4e5e6e7b, 0xdbcc442f, 0xbb2f778a, 0xc6d98bd7, 0x18538d40, 0xc979f0e9, 0x4f4be0dc, + 0xa638a6cb, 0x5d0983f6, 0x3e3bb206, 0x571d88fb, 0x241c6359, 0xad67b501, 0xb6253cd2, 0x79c59d55, 0xafd3041d, + 0xa62d0004, 0x939d6fb7, 0x92955860, 0x922f19bf, 0x031a3537, 0xddbb38eb, 0xdee7d821, 0x0207fc68, 0xed548b3b, + 0x70886283, 0x79e8ae43, 0x367892f5, 0x871499e9, 0x27cd4b86, 0xec865f04, 0x7ff18368, 0xe629f3aa, 0x624fc9d6, + 0x938a106c, 0x6d8a7a9e, 0x8c804933, 0x3eb5d6f5, 0x536d60a2, 0xc850fc9f, 0x27332521, 0x4c30fb35, 0xb3387981, + 0xc81f3618, 0x6d1dbdb0, 0x2fa4e5aa, 0x3c182f7f, 0xce06706f, 0xa6f76bf5, 0xb8accd9f, 0x859b6f01, 0xd172b494, + 0x172f34c2, 0x846b960c, 0xa75fb178, 0xd6a4d265, 0xa1821835, 0xb6983095, 0x4be9130c, 0xb56711c4, 0xc5f76010, + 0xdd2010a5, 0x8e85fc3e, 0xf5002fe6, 0xb5fcd270, 0xcde65a92, 0xf4f7ebaa, 0xa5171728, 0x596ed1b4, 0x8fe0487e, + 0xb3a452ed, 0x7be9762a, 0x937f6834, 0xb7ccb972, 0x33e38e1b, 0xc4b79540, 0x8d6936aa, 0xb7f57e24, 0x9142146f, + 0xc0aad048, 0x355f47c1, 0x94d67bef, 0x3f5f66f3, 0xa06f3bc5, 0xca821f31, 0xa3d1b427, 0xe09286e0, 0xfbb49e9d, + 0x22cd5984, 0xde3fbaa9, 0xf1228b0a, 0x109a0b9f, 0x7548c33b, 0xe941dbb2, 0x93f95e81, 0xab081a96, 0xdf747884, + 0x45ed0016, 0xbdb948f9, 0x52666432, 0x2294a781, 0x66b25bb4, 0x2335dca4, 0xc636dc96, 0x766687f4, 0x8273259d, + 0x856f58b2, 0xc5311f4e, 0xfa666467, 0xdaaee17d, 0xf5d22468, 0xb94d77e5, 0xe3ccd5cf, 0xf71ff3d5, 0x059c47e0, + 0xa2677a6e, 0x3690bf4a, 0xf7915003, 0x836ffa5f, 0x8a3df18d, 0x838d8411, 0xb6b54740, 0x5b2ba5a0, 0x2d8db59f, + 0x745bf9cd, 0xec9e0e62, 0x8bb57884, 0x5b5f6d82, 0x44be8f59, 0xe3ed39bb, 0x4ef5119d, 0x10c90758, 0x4c3de02e, + 0xcc0dcdcd, 0xae35ebaa, 0x8b079813, 0x707f4cd4, 0xb28ee485, 0x868e1475, 0x98dd2c9f, 0xbf7e4f5b, 0x2f2378c2, + 0x7e997fca, 0x0ae36578, 0x0714380e, 0xf942af1a, 0xdc924a4c, 0xd462660f, 0x73b985b2, 0xb3443ec0, 0xa79c0a43, + 0x74a7a67a, 0xd1d2f722, 0x3e9d04ee, 0x9a4e1195, 0x626273ff, 0xd2403034, 0xc4a06a7b, 0x59830abf, 0xe25c52c7, + 0x835a60fc, 0x74890b67, 0xba57e1c8, 0x16fd9a93, 0x318964d9, 0x73f3c4e9, 0xc8dcb69f, 0x6b19cc12, 0x848795bf, + 0x35bb1c1a, 0x1e328ed7, 0xb0f9eecf, 0xfcf7d0ef, 0x18084914, 0x41866a66, 0x9a53ef73, 0xc80279e4, 0xfaf76d6b, + 0x6bfc3811, 0x806e5e41, 0x939565a3, 0xb3aac7da, 0x8c29ef06, 0x40ee7f8e, 0x158b6c83, 0xff4fde31, 0xeb907b6b, + 0x1cae2e23, 0x0f2ee3c6, 0xb1695a77, 0x7347da79, 0x16ffd074, 0x4ac8b21e, 0xa36836e4, 0x96d832f1, 0x4f52a03b, + 0x87320d38, 0x4a9b3d5c, 0x96156427, 0xe0010793, 0xca4bb547, 0xa85f29a8, 0x85ee6d70, 0x507197f5, 0xc5727a49, + 0x1ca129bb, 0x87b85090, 0xa54860cf, 0x26e5a790, 0xd4b4c87c, 0x32a58dd1, 0xda70783c, 0x6331fe08, 0x6d5cf3c2, + 0x5ea90f67, 0x7b234c8d, 0x82709b2f, 0x6aae16ed, 0xfe8fb430, 0x91aae7a4, 0xa89c8475, 0x9ee038e1, 0x46752770, + 0x607bc2b7, 0x5a43428f, 0x22c889f2, 0xbab3c6ee, 0x0fac61b3, 0x75dffa55, 0x23d02d78, 0x9e425bb5, 0x59b2e2a7, + 0x9840368d, 0x0d7daf83, 0x5038f381, 0x1a2ca12e, 0xb796b6c2, 0xa8f2aaec, 0x08085d45, 0xe666f976, 0xd77c5ea8, + 0xfaa8692e, 0x89b8d180, 0xe3c2705f, 0x16234e9e, 0xcd4e4fc6, 0x870800df, 0xd723a9ec, 0x93aa6197, 0xccb05bc4, + 0xecf009cf, 0x228d7786, 0xcb35fff7, 0xe9dfde8f, 0xaa78f2a8, 0x3bdc97dd, 0xb0e60ac5, 0x8a238fa6, 0xb42b36b0, + 0xd0948639, 0x103bc6e0, 0xb9c624a2, 0x9ac7ee52, 0xe1bb553d, 0x25ba0f2d, 0xec5a50f0, 0x525071c7, 0x32ae5317, + 0x3664176c, 0xfd6e1cea, 0x40da8e5a, 0xfa450d23, 0x75246f3e, 0x2929379d, 0x8e9b60ce, 0xc0bbf00c, 0x2f72727b, + 0xe43257a4, 0x59a0fd18, 0x3a0585aa, 0x14ffc421, 0xa4ac0cad, 0x20346223, 0xac05560e, 0x3260af53, 0x4f0f2911, + 0xb7f749b1, 0x8dcbfebb, 0x6ed1040a, 0x9cf320de, 0xf91b5c8c, 0xe75e20c3, 0x167f9681, 0x6d2bc888, 0xc4fd3e7e, + 0xa6d9b333, 0xa4335f14, 0x6e3a8d38, 0x29812b76, 0x5f52e568, 0x8a9c434a, 0xde78bff1, 0x29a8e2fe, 0x1d19a3dc, + 0x79913344, 0xbb8e2c30, 0x7c5008e1, 0xffdcb3ba, 0x8d89d735, 0x08916038, 0xc72a7f5f, 0xbcc988f6, 0xd5eee570, + 0xec92250c, 0x5a7c4a47, 0x6d2e33a3, 0x24cb0d60, 0xf70685c8, 0xa3c806a0, 0xbdfae84b, 0xa4a67943, 0xe9b91b21, + 0x9e013594, 0xa81e232d, 0xe8e588ad, 0x775119cd, 0xcf750bda, 0x0ece7f14, 0x175b7be9, 0xf32b1a39, 0xc463947a, + 0x3edfb896, 0x0bfb16d6, 0xaf65c608, 0xdc641073, 0x0f7eac7c, 0xd323ac96, 0x4274a6eb, 0xb4292188, 0x5c04680f, + 0x2d95a695, 0xf4c315b7, 0x3316c523, 0x115295a4, 0xc9d3a324, 0x9b7ef8ea, 0xd92832f6, 0x57361199, 0xc0aeaf06, + 0x84240756, 0x603a8729, 0xbdb675e5, 0xb5ee6993, 0xaa403ec0, 0x389ab29a, 0x0479b39a, 0x0c17e0ac, 0x06d9f9db, + 0x8153fc3f, 0xc6f01456, 0x4fcc2b64, 0xee3c4364, 0x592f68c6, 0x63033033, 0x468cb226, 0x98df9e53, 0xff5036ab, + 0x1c0261cf, 0xd05d7071, 0x44465e19, 0x218ddb59, 0x77c47d9c, 0x9c69cb51, 0x1d2d5bfd, 0xbaeae40d, 0x5ea9b1e4, + 0xcf79acb9, 0xdfbecf79, 0x41fcebcb, 0x80dac72e, 0x2c7c1d77, 0x7ecee1f2, 0x72f4ac6c, 0x0b6a4925, 0x8467441f, + 0x14086e24, 0xe4d38856, 0x39702da0, 0xb8d98fef, 0xb98c2fc4, 0xa8e8edbd, 0x7eff0e27, 0xff3961f2, 0xbc14a79b, + 0x1ade7ff7, 0xf7132d2c, 0xb4416c2d, 0x1391c607, 0x233504bc, 0xc101cf9e, 0x576cc7c0, 0xb4fd6643, 0x5b3022fd, + 0xbf7d2f89, 0xddad1e2c, 0x282c78b4, 0x379a1549, 0x829e057d, 0x0572624e, 0x82317a72, 0x30903914, 0x5f9a21d0, + 0x6a4a1f7e, 0xca77d649, 0xd3418bc3, 0x2f29ee21, 0x9b4cafc7, 0x9e341421, 0x37d49fa7, 0xb84eaafd, 0xfd0a27ae, + 0xc4164067, 0x45dc9bed, 0x9eae801f, 0x5ff14c89, 0x545d3e16, 0x9a50bff8, 0xa4b473df, 0x5ba988f6, 0x1cbade3e, + 0x842b2979, 0x9f8e6bf9, 0x4a9985d4, 0xc20fced3, 0x606207c5, 0x0ffa2256, 0xfb44070d, 0x9b0cec7f, 0x4c1e5290, + 0x732e376d, 0x9d57ab15, 0x82965f34, 0x547e001b, 0x423c95ee, 0x87af89c8, 0xeaf9f712, 0x73850839, 0x55806767, + 0xb7c8377c, 0x29e7e714, 0x0516ad4d, 0xc40e9db2, 0x6bfd6dc6, 0x3a673e44, 0x2230a6b4, 0x66252f81, 0xdf4c86a0, + 0xecf42312, 0x5c589a47, 0xbbada40b, 0xfff3876c, 0xbb138b23, 0x979443c6, 0x6d5f1657, 0xda42d439, 0xc07f15dd, + 0xc363ddb9, 0xd33ff22c, 0xf9937c80, 0x38b30d82, 0xa1db1672, 0x2b3eac71, 0x67b4a8c6, 0xd1c19faa, 0x69cfc6ca, + 0x8c3026e7, 0xa188d3d8, 0xa892578e, 0x2161b6a0, 0x50c75ff5, 0xbb382b9e, 0xd22734e0, 0x71a2c96a, 0x80064848, + 0x62541ad0, 0xc59933ca, 0x3802e3a2, 0x7ffebca5, 0xc42fe47c, 0x1f9b0e66, 0x9e467753, 0x3bbaa10c, 0x9e376c80, + 0xc50a17f2, 0xa004f8d3, 0xccf4612c, 0xdcd3fac3, 0xb3404869, 0xcce5465b, 0xf5a8e022, 0x8d65bfbe, 0xc20cf2dc, + 0x4b06c247, 0xa1233135, 0x7e714e25, 0x88c8d7ff, 0x3e1bf788, 0x1256e988, 0x0f1ee492, 0x1ab61db0, 0x7703de3d, + 0x8b06d9e9, 0x56f112cd, 0x9c92dc4d, 0xab4f9bf6, 0x5badc60a, 0x36d9c113, 0x538b686a, 0xcbf9fb04, 0x25486110, + 0xe8164d57, 0xb6399585, 0x0dd561d0, 0x390e448f, 0xbd2738bd, 0x3a6bd084, 0x6e6fd2ce, 0x33eb46dc, 0x9851d49f, + 0x7e8956f2, 0x8a7133d2, 0xcb330bbb, 0xdf5452f4, 0x5cce6b37, 0x192223b5, 0x037890d7, 0x6839bce1, 0xe26e7626, + 0x842a705f, 0x623c3d5b, 0x367124b5, 0xc933a1f6, 0x263a7c9c, 0xe431756d, 0x586b640a, 0xeeadc0f0, 0x8a486fe4, + 0x74a0cc95, 0x94bcd961, 0x587a22d9, 0xf7ea06f6, 0xfdf978a0, 0x779979d1, 0xc667caa9, 0x0d223ca3, 0x31fa3620, + 0xeeeb21ce, 0xcc59875c, 0x0b36e640, 0x13f41cab, 0x58bad0b4, 0xe17f8eae, 0x44385a31, 0x8cba2cf5, 0x6814bf57, + 0xb5024a07, 0x0ae63377, 0x07dc4e7b, 0x28611a81, 0x4bad52c7, 0xe960870e, 0x7d4eab49, 0xe15b0826, 0xd4f5173d, + 0x6477ae2d, 0x419e522c, 0xa0d4c196, 0xec5c0366, 0x1450a111, 0x7fd76067, 0xd733a95a, 0xde2d316c, 0xb129c365, + 0x82326406, 0x86f2aac0, 0xa4b44353, 0x55485008, 0x60787fd6, 0x34022e64, 0x24ad19bd, 0x7533b42a, 0x2f3004ea, + 0xb3e2880e, 0xf34f6bdb, 0x31482889, 0x1cb00ae2, 0x60bf8565, 0x91a44186, 0x4d8cc0f0, 0xb42fae44, 0x71a5b90b, + 0xc9b216c8, 0x14f2b0aa, 0x2538a209, 0xeaa5d60f, 0x1dcd1483, 0x634dbd70, 0x05b036e2, 0x9e732c4f, 0xda05f6cf, + 0xa43365f2, 0xa1707719, 0x3d3ce930, 0xdaa201f0, 0x260142c3, 0xd5f2eaec, 0x26fc10a7, 0xc10f044d, 0x64b4b7e0, + 0x8b092cd1, 0xc5895c41, 0x5000db1f, 0xdf42aa2e, 0x92bffd69, 0x2b6f4b10, 0xfab8fe75, 0x8aabc5f6, 0x6fcf6030, + 0x1d5eb255, 0xc92d1a42, 0x05af67c1, 0x0df3fa0b, 0x1e041187, 0x1cdca169, 0x708bb289, 0x23adeaf5, 0x51b310ed, + 0x5979e282, 0x8acacecd, 0x53edb1ba, 0x5d1b0d71, 0x66fa8b64, 0xca50c67f, 0x6d9a8c51, 0x9bee1f78, 0xa07140b1, + 0x0ff494ac, 0xcffe116b, 0xf83e53f8, 0x11dc38b4, 0xfc0dbcb2, 0xd24d8174, 0x2a655ff1, 0x70f43419, 0x57e3aa8a, + 0x53da271d, 0x1a8b093c, 0x97434db6, 0xe40dffb2, 0x4b483d24, 0x70b51f05, 0x3d25e3cf, 0xe9472a16, 0xab88c55b, + 0x9ed43be3, 0x88d16f4f, 0x3a6b03a8, 0xadba6e7d, 0xd020f1c3, 0xb91e3ba8, 0x80f70de7, 0x2ee87a08, 0x528bcfa9, + 0xbb8d139e, 0xe44eb0fa, 0x3407e146, 0xeab0939f, 0x67bcb76b, 0x126663fe, 0x29682343, 0xa3edf195, 0x9d03ed8c, + 0xa710d32c, 0x0aba1ed8, 0x1f896dec, 0x8087b0a7, 0x15d60007, 0xd5ea6a47, 0x29fa3111, 0xf40375b8, 0x1b9f8988, + 0xc80c56d2, 0x39094020, 0x55b2d0bd, 0x1806b1e7, 0xc60ede03, 0x2e1de5d5, 0x11ca6ff1, 0xe6a5afb8, 0xe522f2e4, + 0x5df4d01f, 0x8e995072, 0xafb69320, 0x52468837, 0xbf4f5fdb, 0x33576ede, 0xad1d994e, 0xe953b081, 0xed2d5aa9, + 0xe89caa77, 0x86a00626, 0x084613b0, 0xc421434c, 0x97feb9b0, 0xadb154a2, 0x75f69eab, 0x874bf2ff, 0x3a0aff49, + 0xfd987a4e, 0x0d18b1b8, 0xb43c6d89, 0x15ce6556, 0xe1225c5d, 0x66de985e, 0x3d2038e3, 0xcd8bcb36, 0x3ada39ef, + 0xf3292eb6, 0x31c80d29, 0x7acfdcd7, 0xab0e8543, 0x9d789e8f, 0x3ef02323, 0xa0369754, 0xfa7f57cc, 0xef623b13, + 0x0698b8ed, 0x7b35142f, 0x8951cf78, 0x34d67a2c, 0xa5170445, 0xbe7c7d09, 0xf63ea350, 0xa4610859, 0x3002c035, + 0x0e30abac, 0xebc2a1df, 0x565ec8c8, 0xe1f78a5f, 0x5eaab708, 0x577dda71, 0x1b21ae97, 0x67d33082, 0x731e1b8e, + 0x9fa4834d, 0x20332fe1, 0x2871ea13, 0xb2506147, 0x3d216fb5, 0xf38852f0, 0x2abac208, 0x47dd73a4, 0x97f5fe0d, + 0xcadf83a4, 0xd2b1e702, 0x11e3c2f0, 0x2319d4ea, 0x7631adb1, 0xdf082a70, 0x030998f7, 0xd19d73f3, 0xbae361de, + 0xa37ca9b0, 0x65dde843, 0x82339586, 0x44191089, 0x83ef815d, 0x6c404b60, 0x69f747ae, 0x2c75627a, 0x6a3d8a76, + 0x54d03afe, 0x0e702436, 0x87618700, 0xa92f594a, 0x785dbcc3, 0x9c762f33, 0x8a35d8b7, 0x8b68856b, 0xf7a72986, + 0x3412720e, 0x4ae419cd, 0x8a7fde4a, 0xefcf02d0, 0x47c51b4e, 0x7e097801, 0x4e5e538f, 0x42ee1e3c, 0x79e9735a, + 0x84ec1d4c, 0xf492ec1d, 0x1e394b3b, 0x5a1df63e, 0xcf41e103, 0x3f424d54, 0x4ae3c55b, 0x3b4bcf51, 0xe006bc85, + 0x6a882dae, 0x07c807ec, 0x8ecd3f6b, 0x510ebde5, 0x40e8ea11, 0x1a947e6b, 0xd829138c, 0x10152437, 0x2867e431, + 0x1ffbab56, 0x12aa1847, 0xc00c7371, 0x46c55518, 0x42d66f3d, 0x7397b1bc, 0xa51db72f, 0x620cd3af, 0xcc51ea2c, + 0xf910d205, 0x325024a8, 0xbedab9f6, 0x847b597e, 0x53153261, 0xf5d301f2, 0x8b30f7b3, 0x967ec7ec, 0x9cc462fd, + 0xcfb4b559, 0x2f0b9835, 0x63d53406, 0x19bf36c7, 0x933e43b2, 0x5b494147, 0xa3f63023, 0x3b64fb54, 0x56787769, + 0x2f1a4f27, 0x07dfeb95, 0x0789b310, 0x3519475b, 0x35bdb28f, 0x4b8f549c, 0xed8b9634, 0x12dfade5, 0x3e484f1b, + 0xee53f86a, 0x7fdedc44, 0xef45cf13, 0xf836a949, 0x0c90b222, 0xca47a7ca, 0x0ab61bae, 0xfdd2ff22, 0x986391db, + 0x02df7ced, 0x58ee6dd1, 0x6ca7e8f4, 0xbf22b223, 0x20909a6b, 0x97bd3ca2, 0x39df16e5, 0x8ae78f74, 0xe326f58c, + 0x794cb404, 0xc1892f8f, 0x322ba43e, 0x205e982e, 0x6c87f5b8, 0x53979612, 0xa16b852f, 0xb8366878, 0x20e9894a, + 0xbe482ca7, 0x4e6e7478, 0x1def935f, 0x765b562d, 0x52f3fce8, 0xc657f8a4, 0xb48f2264, 0x3f208672, 0xa169ae61, + 0xc02164d2, 0x4b94daae, 0x02edafbb, 0xfbd26497, 0x20d9a57d, 0xe1509bf0, 0x451d06e4, 0xc3f102b6, 0xd811cf88, + 0xc3c22be1, 0x256a84bc, 0x10ed841e, 0xe1253333, 0x8ebc1154, 0xc0fe3ec9, 0x261a0cd5, 0x03294586, 0x75e0cd97, + 0x0f46cdfa, 0x84e83ae6, 0x5f54b283, 0x68d913df, 0xcd12c142, 0xe8e9a925, 0xf40818f7, 0x6aa14985, 0xd2975ab8, + 0xf30b256c, 0x04636e74, 0xd738d3dc, 0x73ad7d46, 0x14de12b6, 0x9efe7bdc, 0x525c546a, 0xd5090040, 0xd7bc9785, + 0x572aa464, 0xe8654954, 0xb0c9dce3, 0x48d2e36a, 0x24803cac, 0x989995fd, 0x4d65a34e, 0x3b36f8e1, 0x27703d73, + 0x6504a0cb, 0x587f566e, 0xe067e6e3, 0xd3ce0f64, 0xfd482ad5, 0x449ba984, 0x2d536a80, 0x95f4e22b, 0x36d842c6, + 0x4412332a, 0xa86fb1c5, 0xea6db14f, 0xed0f3b73, 0x7e709a37, 0xaf0ee520, 0x9f9b3aed, 0x9cd9a8a7, 0xd171ab41, + 0xc666a9dd, 0x1b277af0, 0x918debf4, 0x7292386b, 0x0e0407cc, 0x84451046, 0xdf657582, 0x0b1c6750, 0x08f035a1, + 0x600f7988, 0xe7a3a047, 0x86f28e02, 0x73cd2126, 0x3dfeb7d2, 0x6547f858, 0xcca05932, 0x34e98328, 0x89f8ae79, + 0xcfbfcfd7, 0x0a011590, 0x77e0197d, 0x76fd8545, 0x10539b9c, 0x52438e43, 0x3abedbf8, 0x2098b213, 0xd582ba3a, + 0x01117b14, 0x4263361d, 0xaa6ea4a1, 0x03b3682a, 0x84f77bbf, 0x0edd1c00, 0x600a11eb, 0xd43dab62, 0xde64a3a0, + 0x4caad086, 0x5ef5336d, 0x4aa8fa05, 0x40992438, 0xac9c940b, 0xb3d53891, 0x19906f9a, 0x6408f173, 0x662b327b, + 0x4fda62b3, 0xe9600181, 0x518a6df6, 0x85c58453, 0xbb5192ac, 0xe63856eb, 0xa6ed1cdc, 0x20602989, 0x393a61af, + 0xf5579ef4, 0xe20bc1c9, 0x5ad4e14c, 0x198b990c, 0x9c52011d, 0x16e5fbfc, 0xfea51813, 0xc3f90250, 0x571a693c, + 0xbcfed06c, 0xb2f26451, 0x4d8b2cd0, 0x00dbbdc6, 0x85202d13, 0xb810d5ab, 0xb5ba9640, 0x9fa07308, 0x4ac0af6b, + 0xff4c2c24, 0xd09daa0d, 0x9044ab06, 0x964d4175, 0x88f556c7, 0x656e31f2, 0xe0087fe8, 0xc432b408, 0x2ede3bd6, + 0x61c48166, 0x528a872d, 0x8e899bd2, 0xd00d72c5, 0xbf3115d5, 0x67f99831, 0x8cc78a29, 0xecf09b29, 0x217e765b, + 0x270c9319, 0x11837a57, 0x1fc7632f, 0xfe2e7a9e, 0x86cfdffe, 0x70c92ffc, 0x6b441d92, 0x0544e9b8, 0x66a6c138, + 0xac2657c6, 0x3b3cfa95, 0x1b643440, 0x2ac617b8, 0x1bd24ba1, 0xcd53149c, 0x6bedfd32, 0xcaea4f5f, 0xe0f2d53a, + 0x32222cce, 0x62f04f78, 0x281c4aea, 0x92f1d746, 0xddd30925, 0xbce5006b, 0x1964137d, 0x2f339eff, 0x073b06b9, + 0x3806fabd, 0x7cfdd1de, 0x8ea92392, 0xca2bf0c7, 0x6f19258a, 0xf3dfff39, 0x838e7d04, 0x21ee01b5, 0x4f79ad31, + 0xc81dec10, 0x8a021570, 0x032740a9, 0x671404de, 0x64b4f318, 0xe425749a, 0xb9f196ad, 0x752ca164, 0x55918347, + 0xfb3cbd07, 0x4a250a48, 0xf90af985, 0xdf827279, 0x1ff54a6d, 0x73a2e24d, 0x9d8a17a6, 0x22953d50, 0x9ec66708, + 0x21716936, 0x9ff27cd4, 0x66cabc9a, 0x7b15b7f9, 0xafa68161, 0x63ea3760, 0xef7e1f6d, 0x733d72dc, 0xebc902dc, + 0xaa8ecd95, 0xc633714b, 0x77cc13b6, 0x997bfd96, 0x289ab7ca, 0xeba7a264, 0xfd5c5651, 0xc3411a5b, 0x5d834ba4, + 0xd8bf1606, 0xdb24fb68, 0x1b3b9b6b, 0x80bb8791, 0x3f087e8e, 0x41c60f54, 0xe00c8f0a, 0x325554ec, 0xd1a0e434, + 0x4544b041, 0x9c42a29e, 0xb11832d1, 0x5af8ea30, 0xf9a79ab1, 0xb003d5a3, 0x942ca953, 0x582c8920, 0x2db624e1, + 0xe1424060, 0x412a9157, 0xc18d9a94, 0x68a427e4, 0x21cad876, 0xba1be04a, 0xd1ef84a9, 0x08988413, 0xe359ea1f, + 0x4cfe8dbe, 0x59863e1e, 0xf8327125, 0xd9f1753d, 0x77b4a25a, 0xf8b114c3, 0xf4259e25, 0x3d952dfe, 0xa0191376, + 0xe09dcb7f, 0xb761cbca, 0xfede9076, 0xb1404d99, 0xe1fc4db2, 0x00f50f6f, 0x7ae04d6c, 0xb339f845, 0x8ed71398, + 0x3a737281, 0xd04cef9f, 0x57a1615c, 0xef045732, 0x04503c6b, 0xddac7645, 0xa8f9f113, 0x61ef0675, 0xd21eb19a, + 0x0c4d93f9, 0xa485da9c, 0xf2ce65dd, 0xf2245f2d, 0x92090dc0, 0x72d599bb, 0x286d1e79, 0xad640608, 0xc7acf68d, + 0xeda7eb5d, 0x950e6744, 0x3922089f, 0x7b3037f8, 0x9e11b096, 0x7a46bb38, 0x1a15acac, 0x35902c06, 0xcc114eb1, + 0x81e319c8, 0x84c439d1, 0xafc550bf, 0xdc85cf14, 0x696e8ab8, 0x0a2ca729, 0x47c2502e, 0x8cf7732d, 0xb7589765, + 0x076ee187, 0xc4e26443, 0xe1c28f20, 0x8e01fc17, 0x97d32480, 0xcabb61d7, 0x82130285, 0x05aa1ce2, 0x6fd4ffdb, + 0x679b3fe6, 0x3454908f, 0x471e3edc, 0x36336495, 0x0a4739a7, 0x67cbf051, 0x6af0d047, 0x7da98fbb, 0x66174df0, + 0x8f75cbfa, 0xb42d0bca, 0xadceb870, 0x049a5a91, 0xa70439f1, 0xbe5b57ac, 0x856f0055, 0x07805fcc, 0xff4a7940, + 0xba3dd26e, 0xcbe3efbb, 0x90fd3ca6, 0xef180cad, 0xd49a2fe1, 0xeac70e33, 0x47640130, 0xc80fbcfd, 0x60d37b9a, + 0x66157a7f, 0x33b6be90, 0x9b7f1b83, 0x896fbe7d, 0x638886f4, 0x39b0322c, 0x37dcee0c, 0x54771a0c, 0xba7dd17e, + 0x19846706, 0xc08e1d00, 0xe17af913, 0x3221206b, 0x4eab89c7, 0xe589fd1f, 0x42b34450, 0x7fe711da, 0x7d235a38, + 0xbd725ee7, 0x8abcfd6f, 0xff5eb551, 0xdefdf921, 0x11c61d72, 0xc184d800, 0xe0f21ede, 0xbca2053c, 0xd7cce490, + 0x477fd3a2, 0xfef06802, 0xe205b0a1, 0x6796703a, 0x55a826c0, 0x91f7cd58, 0x28fe3da1, 0x68d27f1e, 0xa154309a, + 0xbd85d001, 0x4676e242, 0x2a4df060, 0x48767dfa, 0x7ba2eebf, 0xc3477ae5, 0xaf147174, 0x91fba18a, 0x2784b532, + 0x753a8929, 0xef7923b6, 0x840468d0, 0xee3c5ecc, 0xb98a6df0, 0x6b1977af, 0x59d7d858, 0x044e36dd, 0xc6441e11, + 0x5ab4eb9a, 0xd6954d71, 0xdbeb3110, 0x2ee22ed4, 0x3b09d65e, 0x226ceb8b, 0xf27a3424, 0x09bf27c5, 0xb1c9aac3, + 0x2db6a327, 0x3e15b3f9, 0xaab2e756, 0xd553ed67, 0xb694dba3, 0xee34f592, 0x23381868, 0xbb0d2b4f, 0x20a3cbf8, + 0x31daf122, 0xaf83621e, 0x3f6e3ade, 0x4475370b, 0xd12ddb85, 0x7bb94e5a, 0x970544bf, 0x471571f7, 0x8eecabd5, + 0x448e570b, 0x7e811c48, 0x76705125, 0xf4d7ef8e, 0xdbfa0a3c, 0x9871cfe6, 0xb9f13da2, 0xd06ce447, 0x9bc03f0d, + 0x34a34a38, 0x4b125fda, 0xbcc405cf, 0x3086bfd3, 0xf402de74, 0x693de838, 0x390fb739, 0x0304de02, 0xee05c928, + 0xb9b2b7c5, 0xe8692942, 0xfcff3148, 0xe8b6a95a, 0xba8439a4, 0x94e0ab9d, 0x2b67abe7, 0xf6b887ac, 0xd51d90fc, + 0x0cfe4129, 0x08bedd8f, 0x20aca1e2, 0x2d97f7dc, 0x768baf2c, 0xe070c4cf, 0x887b630a, 0x39226ce3, 0x223d3135, + 0x67087ecc, 0xde71591e, 0x9f449967, 0xe29397da, 0x4c86b95b, 0x9d0e9d46, 0xfd45a499, 0x8dff712c, 0x4b9efb11, + 0x8a7666bd, 0xb34bbc1a, 0xb8edc228, 0xd40a8ef0, 0x1c258871, 0x694cc695, 0x7f4ae6c1, 0x05798857, 0x0b2b387d, + 0xa3eb06f6, 0x26938660, 0xe6be3e7a, 0x9f04da64, 0x280c94cc, 0x88ba3c14, 0xf1eb649e, 0x1fb22abc, 0x3068af2e, + 0xd508d5f7, 0x456a7c1e, 0x755ccda5, 0xab47dfee, 0x37baae20, 0x522d9457, 0xd3bf8559, 0x557a5787, 0x54f484d2, + 0x834f0bf6, 0x90f10bec, 0xc89437f7, 0x40f24d50, 0x7da6c287, 0x85d4673e, 0xf5ef574a, 0x603ad149, 0x776d52f6, + 0xd5ff1c6f, 0x0b6ae110, 0x7f8e75bd, 0x29f34d63, 0x1a591451, 0xb158e06a, 0xb3cbde06, 0x5efa86f8, 0xb750b02e, + 0xa1d7d275, 0x928f8907, 0x7c1a228e, 0x59337335, 0xf7b7d508, 0x0ccea95f, 0xa3425d64, 0xdca257c0, 0xc43ca2f4, + 0xc65aaf40, 0xfee70d4f, 0x2e4112db, 0xbb52a3fd, 0x617d350f, 0x0235fb8d, 0x2738b3a4, 0x94e0034f, 0x57b28e1d, + 0x1eb54cc6, 0xec150a15, 0x4129a4ba, 0xa4e0a2df, 0x9c47a5ed, 0x8d963a28, 0x9b51b089, 0xcdd65aae, 0xc4bc26f6, + 0xeab4f15f, 0xc03f5105, 0xbbf8d7a1, 0xbbedb86b, 0x4ff3abf6, 0x4cf91f47, 0x81e3468b, 0x0203924a, 0x1280b5c1, + 0xfbeafea1, 0xa515e378, 0xa0af03eb, 0xc8ef5d11, 0x0bb01526, 0xae116bd4, 0xfec987bf, 0x455b2152, 0xa573f4cf, + 0xf7080fa4, 0x5186a1df, 0xb680ffe9, 0x18dac264, 0x3fc55505, 0xadc52c04, 0xab52b9a3, 0xb43d0280, 0xbbce7dc7, + 0x85a91ee6, 0x71ef84de, 0x4c0fd9fd, 0x3096c86f, 0x4804c9b7, 0x8c3e5aad, 0xdf5ba9cc, 0x6a8d1d59, 0x17525e19, + 0x85a919f9, 0xe8d2ae05, 0x4fd7bc70, 0x25fb552a, 0x17ed91e4, 0xb1fcf491, 0xd207fadf, 0x987b012a, 0x7570c3e8, + 0x4ab8eee5, 0x120b730d, 0x6ed38b5d, 0xb957464f, 0xd5d803dd, 0xf6b76176, 0x9d5f8513, 0x9a7ebda1, 0x5f4c70cf, + 0x25c56da4, 0x6dc8a442, 0x5eff37d7, 0x509f5861, 0x786958c1, 0x0dd17bda, 0x927069bb, 0xec2889c8, 0xb747b354, + 0x3504c4f1, 0x94258395, 0x05836f5e, 0x12068054, 0x42751853, 0x05859782, 0x784882ad, 0xc3988e94, 0x20c7eb21, + 0x6f5d9be5, 0x23840867, 0xfc160e47, 0xbb3bfe14, 0x2497e7ee, 0x42e5f8c2, 0xbdb0d262, 0x97d52dd1, 0x512c6081, + 0xf2beb1b9, 0xdab5a157, 0x9a86a417, 0x1f9a1932, 0xcf9da6e5, 0xf82d53a0, 0x2b0baa7e, 0x2327b4a2, 0xd71a161a, + 0xdf403475, 0x948bfb49, 0x24fc9862, 0x225123cf, 0xced76b57, 0x755bc1ec, 0xd0a2dc53, 0x64bfa749, 0xeca16661, + 0x61183c53, 0xcbbf1397, 0x49c5459a, 0x18e394b2, 0x1be4f48c, 0xf7d8ec91, 0xd81fc5c6, 0xcdb1c20b, 0xfe3c90b0, + 0x4b836637, 0x556781e5, 0x5af18ba0, 0xf0e454e4, 0x79278ba0, 0xe0c76baf, 0xb36c577e, 0xa23b9489, 0x11305ed4, + 0x1b2cf419, 0x250a4de5, 0xe5cf8de5, 0xc5aba253, 0xaba81623, 0xbf255563, 0x5956abd8, 0x54354af8, 0xae4ae23e, + 0x138d859c, 0xb6ab68ea, 0x28c55e2c, 0x5dc5e110, 0xb467d47c, 0xc3cc8685, 0xe1566c24, 0x322c8890, 0x677857fe, + 0xfe8eb38f, 0x0b61ea66, 0xddd1b4ca, 0x6f1cbf51, 0x44f08357, 0xcbe21396, 0x744fe8b9, 0x143b958b, 0xab05e6fe, + 0x3c54dcd1, 0xa5b694a5, 0x0030a4b7, 0x254a05bb, 0x4214883d, 0xd53902f1, 0xcc0e599a, 0x22298028, 0xa55470d9, + 0xbee9ff6c, 0xaf1e2a5e, 0x0f69d102, 0xfc02aa22, 0x19f1d3c7, 0xb6aa4ebe, 0xf1751cec, 0x8a0ae852, 0xd180a904, + 0xad8605a1, 0xb5f57878, 0x6b6db0ed, 0xaaf42553, 0x64f45bb7, 0x9ff787a7, 0x84e527c0, 0xb2839040, 0x4f044fec, + 0x14cbd950, 0x522ae19f, 0x0030916b, 0x517635ca, 0xc3a74420, 0xf13d6a0e, 0xeadd4b6e, 0x8e20585b, 0x0b36ab20, + 0x5f6b6be3, 0x6126831b, 0xdf84a59f, 0x4dd6380d, 0xb77899f2, 0xbb5e5703, 0xf2086ddc, 0x6532cc3a, 0xdb8aa73e, + 0x6570ee92, 0xf32f68c8, 0x019ddfdf, 0xa57896e4, 0xc10e0c77, 0xe3f15ffe, 0x900e26cc, 0x3cd78e47, 0x14354762, + 0x9d6a699a, 0x3ab5c295, 0x15bd0b3f, 0x751f7fab, 0x134faaa0, 0x70e112a9, 0xad293978, 0xdf35c6f2, 0x4ba653e2, + 0xc4fefeb4, 0x5b4e5baf, 0xefb1d2dd, 0xf79e0d2b, 0xbc488b42, 0xe7f21b7d, 0x5aa9157d, 0x6b86dec9, 0x835312f6, + 0x6adf72e9, 0xf613d479, 0xa2379126, 0xefe91cb2, 0x124d80d8, 0xf810e5b7, 0xa9780fd0, 0x15f06bb7, 0x50145248, + 0x502c59c2, 0xc8271ed4, 0x718152d3, 0xb138b95b, 0xfb031cf7, 0x5c4d4895, 0x7aa222ac, 0x566cacfc, 0x3283df05, + 0xe3b5f754, 0x91288231, 0xeb9b4a58, 0x3ab36dfe, 0xae69ec8f, 0xf9e33e4e, 0xbe85bb36, 0x870dca46, 0x7154ead6, + 0x6c3d6885, 0xde765276, 0x09309ecf, 0x5d1c9e35, 0x7cd844a9, 0xa1252152, 0x9967ff0d, 0xa792dde0, 0x2b5e20c1, + 0xebccd1cb, 0x3ceb2b15, 0x49538aae, 0xc1ae7073, 0x10ea8682, 0x6afbba45, 0xe0973996, 0xda059f47, 0xc5fdac19, + 0x7f0f74b3, 0x424d8f46, 0xfd844473, 0x2a8aebd0, 0x69dc3074, 0x86fe309d, 0x55c9310e, 0x0d7f978c, 0xc6dbee41, + 0x19c6edb1, 0x95c916c1, 0x77110905, 0x17deb9f5, 0x8bd33b28, 0xb483f91c, 0x1121b3cc, 0xf6233cb6, 0xef243748, + 0x9271a226, 0x01d89f4a, 0x2338f83f, 0x215fdd9c, 0xc62470c2, 0x6159032f, 0x7c523bea, 0x1d80e70b, 0x49d67bf1, + 0xbf6fd8c2, 0x6555f052, 0x224ac6ca, 0x1095a7fa, 0xf4161b64, 0xd3023679, 0x97f93cf6, 0xe8d0a971, 0x7355a50a, + 0xed4a763f, 0x977bffbc, 0xde073c28, 0x52826765, 0x97e44e42, 0xaed68ae8, 0x8ace251f, 0x71edc9de, 0x16cab2c1, + 0x96eddbcc, 0xfb734d47, 0x71480c74, 0x84b94b94, 0x6c236c04, 0x4d0c3de6, 0xb562e004, 0x3a986190, 0xadc294cd, + 0x3b006f5a, 0x2146b5c3, 0x196571c0, 0xdc6552e2, 0xfa52b97f, 0x11f974b4, 0x7b966641, 0x23f081fa, 0xae22a48c, + 0x056ebc03, 0x5dbb6742, 0x273b0378, 0x19f09b75, 0x35fc426a, 0x16c0e434, 0x97eb86cb, 0x323f6f61, 0x077820d4, + 0x2ae697d9, 0x2dca47ac, 0xe4b2af3d, 0xb53f500f, 0x7f8e17d1, 0xdcda13a7, 0xc531b97e, 0xdca522c0, 0x226ed058, + 0x90551792, 0x175e9a12, 0x53d3838c, 0x12f4451f, 0x738d2aea, 0xeb18a832, 0x5646355b, 0x8695d90d, 0x2a87de20, + 0x237b5c4d, 0x7d56d740, 0x8696dd8f, 0x0eee469e, 0x0477d2be, 0x76420bfe, 0xbfc3c534, 0x2d734253, 0x14749579, + 0x33a47713, 0xf58375b0, 0x9db44d59, 0x5dd5a550, 0x9594103c, 0x672172b6, 0x9721a601, 0xf22bce5d, 0xc6078ab6, + 0xc214a017, 0x7d2bcd16, 0x4461cdaa, 0xe9fcccc3, 0x9dd03af7, 0x00d0ab31, 0x4044ba0f, 0x079023d6, 0x3356d18f, + 0x07f4cc75, 0x8a15eaca, 0xd7e93425, 0x8f749cb9, 0x7f0da3b7, 0x927a943d, 0x23258aa0, 0xe65189c4, 0x1a97f8e7, + 0xbc772ba8, 0xec579f52, 0x31bca957, 0x0ff87e8a, 0xdba76ad6, 0x98d22cb6, 0xc20f56e0, 0xa647618b, 0xfcafe613, + 0x0b792c28, 0xd0d3d611, 0xb0206927, 0x91bee8e4, 0xe275c131, 0x5eb76a17, 0xb3aa5551, 0xd2709740, 0xbd98bfa9, + 0x82d101bb, 0x17ec637e, 0xa1f440a2, 0x4e8ba3f9, 0x22e2e36d, 0xca6a319d, 0xfbb6696c, 0x14137e4b, 0xfd07b93a, + 0x88187f43, 0xe25ec3c6, 0xeed94802, 0xd3cc9ee2, 0xbf24a2cb, 0x6a135c35, 0x0e03b434, 0x4ec89ccd, 0x6ea06429, + 0xd48a5822, 0x10189fcd, 0x4d8f8ce1, 0x1fb21f86, 0xdd542d32, 0x944bd3ec, 0x6df5785b, 0x588b4182, 0xf9fd1d64, + 0x94ff2b13, 0xd01c64b0, 0x02e8d32f, 0xfb51a649, 0x675b91f2, 0xe468ebcd, 0x0b78ef1b, 0x32bd69e0, 0x977084b2, + 0xedee1dc9, 0x54a06b39, 0xb4c0719d, 0x8b8f4989, 0x608d4eaa, 0x034e4683, 0xb2558cd0, 0x4feb8c0d, 0xc6a764c6, + 0x97c6225f, 0xb90e31e6, 0xcb6f3bcb, 0x29c445da, 0xf445a686, 0x83fdbecc, 0xd968f247, 0x868d2474, 0x9bd3cb08, + 0xa0f84f35, 0x91e211ad, 0x93a8c50a, 0x44a68fa8, 0x05aa1550, 0x1fe3a0b7, 0xe31f0d49, 0x6b7586d5, 0xb259cc82, + 0xf4c1cb1f, 0x942452d9, 0x4ea1beab, 0xa47b1a74, 0x7d1f64d5, 0x4afff063, 0x8533476d, 0x57313806, 0xf63d7c84, + 0xe3b34678, 0x8d5f885a, 0x4b28b571, 0xf975ed59, 0x895c16da, 0x30c3bc0c, 0x8ebbba49, 0x212ec712, 0x189c94ef, + 0xe2de388d, 0x12b13ee8, 0xed353d9e, 0xb62fedf6, 0x1c0c0536, 0x77d7ab11, 0x25b7c9ae, 0x69b40dc5, 0x5bf65ca2, + 0x8e4af743, 0xdee6c528, 0xd9c226e8, 0xddeb659c, 0xfbd87368, 0x0a0c0944, 0x2e1dcc24, 0xd1d71331, 0x6ca6d66d, + 0x9aa7ed35, 0x89f4b92e, 0xebe97071, 0x14f55b49, 0x4bad0750, 0xe692d6b0, 0xe51f95c9, 0xbd618500, 0x0230a9eb, + 0x3b6ee594, 0xba3212db, 0x96e1dc9e, 0xb6a8ed36, 0x0e939743, 0x52fad7e9, 0x3ce8c1b0, 0x31d9ba70, 0x6f0cde45, + 0x162f7ba0, 0x694fcbd7, 0x06d9a23b, 0xecffd9c6, 0xa0ac4b0a, 0x6004d03f, 0x8a6d36d8, 0xa616d57d, 0x9ea25802, + 0x65fe2b0e, 0x0f2c1340, 0xba689a69, 0x03c0caba, 0xc2c2867c, 0x74508495, 0x5d7e5ff7, 0x5f44a6ee, 0xe05a8d92, + 0x20641689, 0x7cefbb52, 0xb3abf4b1, 0x68258b5d, 0xfcab5325, 0x9d01fb49, 0x883ff097, 0xda553543, 0x3a09bd66, + 0x9ec26962, 0x12316d11, 0x9bafc881, 0x453c698c, 0x5b1d47c8, 0x707bf851, 0x7bd92353, 0x8179137d, 0xd6d03391, + 0xd490037d, 0x9265db64, 0x28e997af, 0xa742c9ab, 0xfbc8f9ee, 0x1976804e, 0xd7532d61, 0x0f81c023, 0x53457024, + 0x95ebafb7, 0xa5e16160, 0x7cfb5806, 0x73eaff15, 0x934d782b, 0x0ea9c60e, 0xa1e6b17c, 0x3231b481, 0xdb2f5923, + 0x23207cae, 0x8d5f5867, 0xa2165d07, 0xb312e6ca, 0xfa28b7d8, 0x0bdb5355, 0x73c38cf3, 0x95ed4789, 0x26e8d8af, + 0x38e0e6c3, 0xb7e8cb7e, 0x0cfeeefd, 0xbc8ea901, 0x0030d958, 0xd0d597d2, 0xfcad5b25, 0x5d950693, 0x131f4e81, + 0x421fb3dd, 0x723a94b2, 0x13d1549d, 0x5eff5c43, 0xc7199ac4, 0x06be9094, 0x1345abea, 0x6cecd91d, 0xfc78a14c, + 0x39b505d3, 0x55f77bfc, 0x2f4c8894, 0x00d9ca3b, 0x588a852b, 0x54232571, 0xfa1d3614, 0xce893159, 0xa7eb369c, + 0x1720d0b3, 0xc7493369, 0xe6d03427, 0x7ac9cd9d, 0x225b4f73, 0x4e5c46e3, 0x0326de68, 0x398bd1f6, 0xfd8ae901, + 0xcc027be3, 0xdbd37a6f, 0x1187778e, 0xb80e1e44, 0x3bac8341, 0x4045becd, 0x83678105, 0x361d5b98, 0xc041b4ab, + 0x0ff20c75, 0x6d85769e, 0xcfdf8eba, 0x66ede2b8, 0x7546fabc, 0x31a585d8, 0xd95d8b6c, 0xcd820ba4, 0x17e5f470, + 0x74ebec06, 0x24c2c8ac, 0x58a8324d, 0x88d28336, 0x1d2cb81e, 0xa3737889, 0x83cb6246, 0xb4870a7b, 0x40e7ce15, + 0xe6c2d647, 0x7ce1cda2, 0xf519577e, 0xeb98139a, 0xb188dbcf, 0x410a8fef, 0xb32c0ac0, 0x26934fb0, 0xfe6bb85b, + 0xe6e7e321, 0xfe3815cb, 0x39891e92, 0x9ea928a0, 0x808848c2, 0xaef16ded, 0xf3f5d35d, 0x3f4d699e, 0x61750dc2, + 0xfc61f29b, 0x16949d63, 0xad27b6ae, 0xe7f80937, 0x8d2ccdd7, 0xf0c5575e, 0x27ec8ca0, 0x76f87a58, 0xb4acd187, + 0xbc6eca0c, 0xcdd03f43, 0x1636010f, 0x7c569d41, 0xcf6720a5, 0x5a1e05d3, 0xc88dbbac, 0x537ceaf9, 0xd2d1567c, + 0x471cf798, 0xfc4ea62a, 0x40085c14, 0x8a2f153b, 0xd340d9a4, 0x5e62d588, 0x0b4cbbc4, 0x2af9446b, 0x74a4ec51, + 0x0b60cb45, 0x2880985a, 0x98b7ca90, 0x84884828, 0xd8b729c2, 0x160cf0e2, 0x8b9e0a33, 0xd528ff1c, 0xf3713f27, + 0x53789656, 0xfd8d1603, 0xf199d50d, 0xd76ef7f1, 0x1cd59be4, 0xc1f5f721, 0xc299c87e, 0x9f0378aa, 0x112cfe71, + 0xb0bdbdf6, 0x20e7ea47, 0x0a04f32a, 0xe613f10c, 0x277b4935, 0xb8752a42, 0x456313a4, 0xd7091a19, 0x15c24e40, + 0xb2218afa, 0x1c6fa453, 0x4333f97b, 0x8143703d, 0x4205ffdb, 0xf53435cb, 0x90f06e14, 0x125e7710, 0x3e8b817b, + 0x4efc46c7, 0x220aca2c, 0x29ad3364, 0x209d4a4a, 0xe5fb6179, 0xa2cff83c, 0xdf718e93, 0x8c81498d, 0xaa8486b3, + 0x308de16e, 0x844c793a, 0x7e1e2d40, 0xee069493, 0xa1cc8fcb, 0x21612b7b, 0x9294c821, 0xc640f204, 0x3531fdf6, + 0x2787b76d, 0x98432667, 0x27de809e, 0x71e85079, 0xa68d1b3f, 0xcd155b42, 0xfd2ce635, 0xf85224f4, 0xb3cee050, + 0x45447425, 0xa3bcc3f6, 0x7b391115, 0x6c83c7ef, 0xb372e7b8, 0x6b624482, 0xc9a8beec, 0xcd430082, 0xf1eb550d, + 0xee59781d, 0xd0588afd, 0xf799e61e, 0x54b9434e, 0xdc85c5a8, 0x18dfdd47, 0x128a80f3, 0xdccf26be, 0xeb845176, + 0x93b7d3b8, 0xc4ab1f61, 0x9aa83897, 0x581681f5, 0xf71d557c, 0xcbf9bb05, 0xa1d5817f, 0x1a32e7f3, 0x6af2c6e2, + 0xe69f42d7, 0x2bdef124, 0x17477b10, 0x8daf1655, 0xb66c34c9, 0xd7581a72, 0x136ce945, 0x20d22044, 0xf7b3ce34, + 0xd09db28c, 0xabf654e2, 0xc7bcb6bd, 0x3d3d6f97, 0x42200aaa, 0x6d1f91e3, 0xf184c3d4, 0x89833d4b, 0x28e6804d, + 0x1621d342, 0x2a4bad38, 0x11f41b4b, 0x8fe52cd3, 0x4fa4225b, 0x4ccea7e4, 0x3dd43888, 0x56f9f22e, 0xf3bf36ea, + 0x7838d875, 0xc2ab6978, 0x62b79fa5, 0x04409b8e, 0x8c416081, 0x07aeaecc, 0x2f239e11, 0x84545410, 0x5211d675, + 0x364eb6bc, 0xb789ea7c, 0x9fe64366, 0xf90b449e, 0x062481dc, 0xdf347d37, 0x7dd71cb3, 0xc451d00a, 0xc04dbadf, + 0x18c3df35, 0xdf32c4e8, 0x570372ee, 0xeb5bb1df, 0xbbae95e5, 0x77e7e52b, 0x059718fc, 0x71c41a94, 0x3fcd86e2, + 0x3972c4b6, 0x6de00867, 0xecd860d6, 0x5b4fa575, 0x64fe7e9b, 0xbc2421ee, 0x1b272e20, 0x81f55f73, 0xa4ec1311, + 0xc0c1ca2d, 0x9c11979a, 0x2dc5ab1a, 0x79905742, 0x13b3c373, 0xe4f47f7a, 0x594faf39, 0xa7d76a91, 0xc9c8091d, + 0xf2e79d66, 0xe0909c89, 0x8a05d398, 0x4a52b86f, 0x35fc9e62, 0xca009dfd, 0x2a5f31c0, 0xaa19da7c, 0x9da05481, + 0xf6a03189, 0x12f8c923, 0x36527327, 0x181d6027, 0x775fe5e4, 0x4bf77ef2, 0x2500da96, 0x6be8464f, 0xdac0173a, + 0xf771709c, 0x6e73f62b, 0x25583611, 0x5416bb9b, 0xb8092dfd, 0x72d102a2, 0x8bc34b1b, 0x51c8ca6f, 0x3078be98, + 0x85efe4bb, 0x4d023799, 0x696001e1, 0x45925265, 0xdf08155e, 0xd72f8eea, 0xb9d47b44, 0xcd095557, 0xb762d1d6, + 0x9c514142, 0xcad5396d, 0x744f3676, 0xe7dc649a, 0x6c43812a, 0x801df11e, 0x21421cfd, 0x464353ec, 0xf12a5ced, + 0x0e66b69a, 0x5b1e2274, 0xc52a3263, 0xc1b5f6e9, 0x449fb2b4, 0x832ba657, 0x6462b723, 0xf203e9b0, 0xfcf70f45, + 0x08ba5c5d, 0xcb96b4a0, 0x5985a570, 0x3744a5d8, 0x8f3e40dc, 0x8aee405d, 0xefab98e8, 0xaad27da9, 0xbb608302, + 0x770bdaf0, 0xe5a4c61d, 0x29e211bc, 0xf276b5b9, 0x0570c799, 0x321e508e, 0xdd1abc1a, 0xc8346064, 0x1b803a8c, + 0x9f44ab31, 0x58c83412, 0xcd859c18, 0xb82f1a9a, 0xb2e21376, 0x46a001ec, 0xccc78404, 0x75306cc2, 0x19abe50d, + 0xabcdd001, 0x933ae5ee, 0x29173e05, 0x7f27199a, 0x8b1456ac, 0xcf4fd945, 0xc769ab6f, 0x4125d2e1, 0x8ce679f3, + 0x24440b14, 0xeaa8742d, 0x743fb658, 0x095ac15b, 0x581d1bea, 0x92bd1033, 0x79a1da49, 0x424646c0, 0xe0347bc9, + 0x7dcf0021, 0xb421b43a, 0xc8be6615, 0x652f8cd9, 0x46cb3782, 0xf3bab7a4, 0xa2839090, 0x34c2785b, 0x705fa7a4, + 0xaa1d7083, 0xc732c292, 0x1fef7f0d, 0x474c09aa, 0x4a0355d2, 0xca029351, 0xceca09e4, 0xd8e3ab36, 0xe71efe2d, + 0x37666710, 0x4f32e5be, 0x65345af7, 0x47352116, 0x23535b8c, 0x57927b0b, 0x3e1a39b7, 0xbbcae9b6, 0x45b7e2b1, + 0xc8e2ee92, 0xb937c795, 0x83a0da63, 0x5f560ba0, 0x695dd28a, 0xcb6adf60, 0xfd5036ba, 0x154daa33, 0x15c39118, + 0xa77278bb, 0xe538e188, 0xe6b717b9, 0x11c3b802, 0xfa91bc78, 0x3bd5c85e, 0x089bef8a, 0x2263562a, 0xda4e7b59, + 0xe1698e2a, 0xed472ee2, 0x85268f92, 0x36ae9c0c, 0x2e31b796, 0x47d96081, 0x162c6c0d, 0xf9fe6fc6, 0xb2f21cba, + 0x083b64ac, 0x26991fae, 0x021480da, 0x0a9be338, 0x0cb597d1, 0xf82bdb93, 0x99674c09, 0xc2ef2ee3, 0xea6b9298, + 0x287626c3, 0xceaf5b22, 0xf33625a1, 0xb60b2bfb, 0xd85c6ca5, 0x6a19e7a7, 0x82a3f0ee, 0x089f85b9, 0x97df6de9, + 0x44bdbf1a, 0xa2a96965, 0x7078e4cf, 0x1b2ad738, 0xb4fff8d0, 0xbdff601d, 0x0dac0408, 0x9f9d3f76, 0x9f14276d, + 0x17cf39fa, 0x29228766, 0x52f50e91, 0x9fa7cb0d, 0xe8ae194b, 0xbbf7c1e8, 0x4f4a30ff, 0x8af60b3e, 0x7cd1292d, + 0x33f0c0ed, 0x5f55860f, 0x66dc282f, 0xe8377ef8, 0x5909fddb, 0xdc216942, 0x293b713f, 0xc7ee7977, 0xcac17ff5, + 0xd161ebf6, 0x287e4467, 0x665c78e6, 0xcf99a6e1, 0xd5cc878c, 0xfe8e30db, 0xfd8c31ac, 0x21e6ba64, 0xe59f64ef, + 0x4967b191, 0xb16b7f1c, 0xfa850359, 0xf8cad6e8, 0xec8d08e6, 0x59c82330, 0x86627afd, 0x28e9daab, 0x67d52436, + 0xe2ac95d8, 0xb9015a43, 0x15e80aa0, 0x29721ef6, 0x9677b030, 0x35940848, 0xd63e8c9d, 0x351a0313, 0x7f8fc681, + 0x34e57823, 0x52515564, 0xd834ebbe, 0x8dfa3ce5, 0x6f572947, 0x2f174c8c, 0xd7e919a5, 0xd0d970c8, 0x4fe42fa9, + 0x3214e3e4, 0xd8936f03, 0xd38db567, 0x7c29cb4f, 0xf6257d39, 0x5c065baf, 0xefe6255e, 0x88da2ce9, 0x2e16ec46, + 0xfcef6a1d, 0xe1b02b8a, 0x971e3d83, 0x340ae725, 0xdcd77616, 0x836a6d55, 0xba478746, 0x2abede00, 0xccb94c2e, + 0xd010d04e, 0x154f28db, 0x5461fba8, 0x09666baa, 0x697fae45, 0x1dcff8e9, 0x46b154a3, 0xc7c91ab9, 0xa467715c, + 0x0aa020a4, 0xd075bd9a, 0x7ad8a641, 0x11a9eaa8, 0x6f298a1c, 0xc7303180, 0x4638c946, 0x2e64814f, 0x07937bef, + 0x9b4324a5, 0x8ea76d5c, 0x686e667e, 0xbd83ce6b, 0x394931f1, 0x447a1bfe, 0xa4cc4f0b, 0x72762bd6, 0x4bc9b299, + 0xc21a7c63, 0x025a37b9, 0x7712637c, 0xae402638, 0xed12169c, 0x515e1324, 0xad388867, 0x13c01940, 0x97fea327, + 0x27a09be5, 0xd1a52c37, 0x656fa21f, 0x4ddd40c6, 0xa7c66fe6, 0x1ab2dfd3, 0xd19cb225, 0x1489b389, 0x8f9ae842, + 0xd3da037f, 0x43dfe8c3, 0x1beff226, 0x73a4b143, 0x724052c3, 0xea9b1b0c, 0x133567f0, 0x6dfc58b4, 0x4f78cdc2, + 0x63b217e6, 0x62e2ac32, 0x433ce2cf, 0xcfa7487f, 0x8facf052, 0x8ce4b2b1, 0x6225f7f7, 0x2ab1dabc, 0x1c80bec1, + 0x06eab75e, 0xa586df6e, 0x5bbca8c6, 0x7e10bf8f, 0xf49d5d5c, 0x7b7aa072, 0x66fd9972, 0x4722d3c9, 0x20628631, + 0x920d6e22, 0x337e7dca, 0xd65f451a, 0x6d6eee04, 0x5ad86d55, 0xbde011ce, 0x237b3f36, 0x1ce3c964, 0xe4332869, + 0x5724a4b7, 0x3705a9d6, 0xe7b47b21, 0x8193189a, 0xe9b47c7c, 0xe53d7a0c, 0x93bf2297, 0xb28934af, 0x0eaaac60, + 0x77dcc6ef, 0x11a20fe5, 0xc5eb96b4, 0x5c74927b, 0xe8f4bf26, 0xbb61eafd, 0xe7b74a40, 0x70e588c0, 0xdd3a5f89, + 0x5e69cc54, 0x0f960107, 0xfab1aef0, 0x3e58b1be, 0x87041330, 0xd9e580ef, 0x6f7b3f5f, 0x8d53c2aa, 0x9bfa66eb, + 0x1013d5df, 0x3c4bf1fc, 0xf9a53973, 0x08f1ce49, 0x7f28caa1, 0x56c89ae9, 0x9ec6fa3c, 0x2b28bfef, 0x0b331f11, + 0xd94e1c15, 0x8fe4fe9c, 0xa4879d84, 0x438d0cfc, 0xb6704b5f, 0xfb11ec4f, 0xbb1fa27d, 0xa12406b7, 0x56298c96, + 0x039b145a, 0x8b487338, 0x463c19db, 0x486fe798, 0xe17047d7, 0xc6cb4de7, 0xc17283a2, 0xe8ec6d09, 0x62b52ebd, + 0xfe922652, 0xed1e72f4, 0x56e9d697, 0x6cb2467a, 0xde8dd18f, 0x8d552a2b, 0x1adbe5f8, 0xf5a4684e, 0xb9b87bcb, + 0xe3b63b5a, 0x7dc9e5b3, 0x18c04264, 0xd05db611, 0xc1123931, 0x554c7bfc, 0xb3354e70, 0x15b2bdc0, 0xc13c90de, + 0xb3f9212c, 0x05065064, 0x6f7e4f6a, 0xb230a8ac, 0xafc06196, 0x626578fc, 0x8eaad2c9, 0x5e6012ab, 0x730bdac3, + 0xd7f3e9aa, 0xe2a846e6, 0x776481ed, 0x735e3ebd, 0x77db7192, 0x1b15cd0e, 0xc933cabf, 0xe1b6c906, 0x548c2da0, + 0x8f9363e9, 0x11e6504f, 0x6ef19803, 0x36d2071c, 0xce0966c3, 0x7e811f35, 0x3f87fb13, 0x97771c4b, 0xfc26f57f, + 0xbd0346f0, 0xe839a13d, 0xb5377036, 0x8e0ddee3, 0xa8b416a2, 0x62318f05, 0x08cae41d, 0xe5f2121f, 0x52939d59, + 0x03b33031, 0x8f8ae94a, 0x0184ff8b, 0xac95d623, 0xa181aeee, 0x1a453685, 0x00f0f333, 0x64c25b6a, 0x99259e86, + 0xf5e9fabc, 0x1b1e70d8, 0xd36ad6d7, 0x2063ff61, 0xb111138e, 0x13dbc2cf, 0xfeeb74ce, 0x33b41811, 0x894f12f3, + 0x7952a307, 0xf1abd6ce, 0x4a039bef, 0x8f4cc102, 0x91f47356, 0x7c753fef, 0x0cbe1c94, 0x00493d48, 0x497235b8, + 0x4d85f089, 0x0032a4be, 0x796b81fa, 0x3f235021, 0xab5b18fe, 0xd3cbe040, 0xf87a0217, 0xd3d3dc53, 0x21f9ddc7, + 0xca7ac635, 0xdbd25553, 0x8c958d7e, 0x15cedd71, 0xa9793024, 0x12509b48, 0x888cb7b2, 0x1cd9acae, 0x274e2982, + 0x333b496c, 0xdd64d085, 0x929fc5c7, 0x8f7ffc45, 0x5afddcda, 0x9ecb7fae, 0x09cbfc8a, 0xb6e32db9, 0xdb622118, + 0x444dd377, 0xb3b6a34b, 0xc8857faa, 0x6ced7f5f, 0xbade9c5b, 0x5ddbab3f, 0xeeb6dd39, 0xdd6629cf, 0xeb726db6, + 0x549a94f1, 0x63d3a647, 0xe61454b1, 0x21bbddb4, 0xde185688, 0xd848c30f, 0x61b2e6d5, 0x8fa92e76, 0x4a12dbc4, + 0x7f3f5c5b, 0xd35a7bb7, 0x80b83b62, 0x487f14df, 0xbd768ef6, 0x251b9eb6, 0x88566ac5, 0x951500b3, 0x4897da96, + 0x809c2d56, 0xc76b88b9, 0xef2d6ccc, 0x0170c749, 0xae9c7dea, 0xd1575d93, 0x02a099c5, 0x58e6b760, 0xd3219757, + 0x9cdb4ee1, 0xf0f0ec22, 0x280ee29d, 0xfcfdcba4, 0x91f237bc, 0x85349612, 0x1fd38aee, 0xe3792055, 0x204bce7e, + 0x2f50b539, 0xa2082d5d, 0x68128731, 0x84e1a93e, 0x78e48d85, 0xf9dd0570, 0x59f0681b, 0xa1284be1, 0x543cb643, + 0xa7462589, 0x19905dc2, 0xe20a0cac, 0xcfb815cd, 0x62010ea7, 0x603a5d9a, 0x4dfc7b67, 0xc6104ff2, 0x628835cf, + 0x1ae664b9, 0xbf2529f4, 0xf7b64a26, 0xfaae18ac, 0x6a07d075, 0xf6396e8e, 0xf3181ce8, 0x1f66f06e, 0xbc3d791e, + 0xe68b4cac, 0x6a328b68, 0xcbebfa49, 0xd7f8cf70, 0x094bca45, 0x346edc19, 0xf291b889, 0x2fbcc4d8, 0x4355da3c, + 0x050b9863, 0x430de159, 0x1783245e, 0xc9fb02d2, 0x37dd8ac3, 0xc9ff15e6, 0x04d8b7e2, 0x9a6e011b, 0xd535cee2, + 0x58b189dd, 0x555b6be9, 0xf4163d2b, 0x7f1fc2f1, 0x2d915c6a, 0x1c454c6d, 0x722f0dd6, 0x5084c3fe, 0x95cfe57a, + 0xf43ccc64, 0x4aea8c07, 0x0efe38ee, 0x395629a0, 0xeb481b9d, 0xcff69b54, 0xf55b121e, 0x842542cc, 0x5d947fcd, + 0x10d8fba1, 0xdfe72d91, 0x4ba9e691, 0x2829eafe, 0xe1c7a58b, 0x91d1c5d8, 0x334c1a76, 0xfd8a76b3, 0x098aaa29, + 0x7208b0a7, 0xd218c592, 0x4391c86d, 0x5492be67, 0xfac44e7b, 0x4a87c6ab, 0x9f57521e, 0x6079edfa, 0xc0eecba8, + 0x8ea4658b, 0x9826afe7, 0x16a739fd, 0x323364f5, 0xdbcf0f8b, 0xbab72a26, 0x72e88b4e, 0xcfcf322d, 0x77b781fa, + 0xf7914ec6, 0x13d21517, 0xa680ed44, 0x36b0f5eb, 0x4c9db0c8, 0xdbcc6d16, 0xf53ddcd1, 0x7208d83a, 0x13f086dd, + 0x2ee7684d, 0x73e98701, 0x8aa905c5, 0x82ea2156, 0xe3081ae4, 0xde619f03, 0xa371e0f5, 0x64bd7d0d, 0x18d5d09b, + 0xbbbc7c03, 0xe6a09c22, 0xf8ca08e6, 0x67c06127, 0x4d8b9f91, 0xa3907d27, 0x85fcde07, 0x7673f42f, 0x9c73bc59, + 0x0bf57423, 0xd36d6041, 0x1ba9a920, 0x5bf62d1f, 0xd1b43b6d, 0xc0f66b26, 0xbf91a7e1, 0x3d8cf29e, 0x662919ab, + 0xba5cfad7, 0x1b36a896, 0xfa65809d, 0x251a3cea, 0x8404698d, 0x0b369623, 0x8e1f646a, 0x724c6598, 0xb3fac1ac, + 0xbcded676, 0x0231d169, 0x6282bd49, 0x4a4d72c0, 0x5b83671b, 0xc0520cfa, 0x97e95cea, 0xd46c9aa1, 0x24f1022c, + 0x3bdd4e67, 0xd992e377, 0x42022263, 0x1745f402, 0x0630362a, 0xcbdbb2fc, 0x241c8bdd, 0x69a394fd, 0xfd00d732, + 0x12b58f8d, 0x15930aab, 0x3f84b134, 0x1bc70718, 0x36a6ee7d, 0x0cab7f94, 0x37a5016a, 0x0f8d4c24, 0x605bbf2b, + 0x07dced77, 0x63df0a1d, 0x5de1ab4c, 0xbde15af7, 0x45740088, 0x6a764623, 0xeb2d907a, 0xdba11b38, 0xcc2c9adc, + 0xac5406e4, 0x98e56b32, 0x6c1ba4c7, 0xd1aa0d23, 0x369f05b2, 0xc0b39e86, 0xe4e57dd7, 0x1d07cba8, 0xa7d2fe35, + 0x3402689f, 0x6e19bafa, 0x95a60808, 0x1d950f67, 0x0566e996, 0x10bff093, 0x79bd02c4, 0x5efdfec0, 0x5f720f43, + 0x32905ff8, 0x46b5e254, 0x331095d5, 0xec2a57b8, 0x8d01738b, 0x76a4456b, 0xfeee7136, 0x47bf7fcb, 0xb8ff6125, + 0x982ce0fb, 0x44bbacf5, 0x455c045c, 0xf3bfee37, 0xe640b4ac, 0x5876a207, 0xb094f750, 0x700280f7, 0xcd4e5aaa, + 0x192d32c1, 0x7b88271e, 0x1809ebaf, 0x6d2d1180, 0x29033f92, 0x94f9d2a2, 0x2c4fc7d7, 0x68a6a4d9, 0x0cbc4252, + 0xb630c039, 0x4792c6ce, 0xaec12f46, 0xe19e655e, 0x50b8f263, 0x12924b43, 0x1b1c3fbc, 0x56fd78d9, 0xce4f9c6f, + 0xc97d3a72, 0x57164293, 0x383349e6, 0x4da649c4, 0xa9b07b93, 0x002f0215, 0x8667924d, 0x9678fe5c, 0x5863f10f, + 0x3dac9893, 0x333f3965, 0x1b97f6d9, 0xfc1bd6e3, 0x2f6d4ed4, 0x5ed2146a, 0xc2869c7b, 0xdc8517ee, 0xd93174dc, + 0x7251189a, 0x61a47cf2, 0x1f13f6bf, 0xd60de9d9, 0x8057d6a8, 0x256ea754, 0x76f4c1f6, 0xc226d0f1, 0x348dcd66, + 0xc2c16483, 0x4bccf223, 0x65932c09, 0xf921c760, 0x9701f9c2, 0x6ed64405, 0xc1be4cd9, 0x0482fcaf, 0x67730fd5, + 0x888e7491, 0xed718690, 0x30910aae, 0x096f2b8d, 0x6bbc1aba, 0x306b570c, 0x571efe8f, 0x093d6c01, 0xaccb915b, + 0x99dc5a09, 0xb52f70b8, 0x7648f1c6, 0x2b04e824, 0x2ca77886, 0xbc686f14, 0x8dd47cf9, 0xc5b455a2, 0x6b54c4ff, + 0x435822b0, 0xb363f3f1, 0xaa7b2fe1, 0x183e0d79, 0xbd217836, 0x860a657a, 0xcfaaba5d, 0x4921caf7, 0xe04077cd, + 0x05e08eb0, 0xa1fcef95, 0x5234139c, 0xf7b84530, 0xbd952da6, 0xff58d551, 0x6206e740, 0x22ab63a9, 0x0779e9c3, + 0xfe004d07, 0xa3d3d042, 0x9b676242, 0xbaa2389e, 0xd970c818, 0x5f83ef64, 0x0de0a7d7, 0x0ef6c037, 0x9d4699ac, + 0x5a767b89, 0xaf183388, 0x57f6c505, 0xdf5a7e40, 0xcf9114be, 0x53865a32, 0x15c54f5c, 0x63e27f0c, 0x3de9d1e7, + 0x93eabb84, 0x5b39b8e7, 0x0dfb7aa9, 0xf9c76d31, 0x2a5cf2ef, 0xbe732937, 0xccc6096e, 0x0638b3e4, 0x8d566db0, + 0xd8e9772d, 0x6c382968, 0x4ecb0f98, 0x06523de9, 0xf5244029, 0xac495b9d, 0xa0f71785, 0xa14bbab2, 0x7c350e40, + 0xd1899b1d, 0x9bf2be21, 0x6bfcf76c, 0xe89ba755, 0x4b539ec2, 0x4782b7f8, 0x35bad3e0, 0x0d2afdde, 0xe6e0e887, + 0xd904a9bd, 0x587b79dd, 0x28068eec, 0xf2636924, 0x16b120e2, 0x7a4f8ed3, 0x98c66e8b, 0x760ce279, 0x9cab4acd, + 0x5c98476b, 0x2e6c8733, 0x77363f05, 0x77b4320b, 0xe709738a, 0x6f8e6555, 0x43977b55, 0x5fd66d5d, 0xbacbbacf, + 0x3a01488b, 0x1f7fa3db, 0x1f5c74c7, 0xa2280cb7, 0x6dc23df1, 0x76188040, 0xb7520e98, 0x27f609b1, 0x8464a1f2, + 0x390f131e, 0x00aba320, 0x6993b755, 0xf835e9f5, 0xafb233f4, 0xcb2df6d2, 0xdff73539, 0x4a043a50, 0xab604522, + 0xbd29217d, 0xaa1fd306, 0x25aa3034, 0x8fbe28f0, 0x7b98ce11, 0x2f24af1a, 0x14684ae4, 0x6b25d5ee, 0x34da8373, + 0xf06d6d3c, 0x777e6d18, 0x6ba5eced, 0xc0a4b5a6, 0x5ab0abcc, 0xaf440cf5, 0x896a2d85, 0xe3b11137, 0x77aabcdf, + 0x7bdbb646, 0xc9b9078a, 0xf31e1cc8, 0xdd7d4665, 0x527ff25c, 0x8793d647, 0xaca83a8d, 0x3685ca40, 0x93f8fc43, + 0x2913341d, 0xc7960568, 0x3233122d, 0x808b98d3, 0xd720b914, 0x69ae737f, 0xf87c6d2e, 0x80a2c7fd, 0x0608f2f0, + 0x3680e884, 0x29f6cd01, 0x56187725, 0x2085187b, 0x8913383e, 0x395c450b, 0xf3fc52a2, 0x2e7f27b8, 0x696c019b, + 0xa364bd1a, 0x10f05fd6, 0x728c9fd8, 0x5f06f31d, 0x5d007555, 0xe73ce03a, 0xc4d2a5ee, 0x34be22c8, 0xfad15aba, + 0x168dbf55, 0xa7955245, 0x06c58db6, 0x54e35ce4, 0x73d18f16, 0x04c1bc42, 0x7dc7dd93, 0xd3b72b0a, 0xe6da13c3, + 0x61d6629c, 0x9df21798, 0x23b22f09, 0xb25cf714, 0xb5a08a85, 0xceedb3d5, 0x90e1fe76, 0x8f3f977b, 0x4f700f1e, + 0x80b65b93, 0x9032a160, 0x706224ed, 0xd638c829, 0x8ab32fe4, 0x9b2780d5, 0xcd623098, 0x9755b4b4, 0x9b89c326, + 0x1c85ceb3, 0x32690907, 0x4e3f4733, 0x6f9b9419, 0x4452df1c, 0xfeb4a8cc, 0x50b3656c, 0x0ace5d73, 0x4dab0009, + 0x256dafc4, 0x11625c41, 0x62240a7c, 0xd43cf11a, 0x235e46e6, 0xcce2f4d6, 0x393b77cf, 0x75352a0a, 0xd1461009, + 0x1aee3a6c, 0x6a83821b, 0x486e05f2, 0xc0077ce1, 0x358b6eb1, 0x1371de27, 0xe9420465, 0x6f347ab4, 0xb689fe0b, + 0x8900ad40, 0xe69baec0, 0xf5fbce45, 0xb0122907, 0x4a82560d, 0x84466f4a, 0x4d54d218, 0x0be145ac, 0x131c6b08, + 0xd7e7dcd4, 0x97ffa9bc, 0x4f047a8c, 0x61c20927, 0xd3cde6c6, 0x2f5a4c16, 0xfd49d8fb, 0x31e6a7f6, 0xc62338a7, + 0x68f1678d, 0x27f0bc46, 0xffff55f7, 0x9f382989, 0xef167545, 0xd06393e6, 0xbc6044f2, 0xf2f0c6ce, 0x0ccdd603, + 0x734ae2ec, 0xc0cb2665, 0x043d24aa, 0x8d111b0d, 0x5b70c59c, 0x244c1bd0, 0x6fb1651b, 0xcf4a6e14, 0xdfe8c3ad, + 0x77d4003b, 0x1b08fe4c, 0xffe8c8d9, 0xe67c2e47, 0x4caaf841, 0xb19d3c19, 0x5079d2e7, 0x8ca67dde, 0xe3e4abc6, + 0x097eb1e8, 0x2d42c7f6, 0x3b880c66, 0xb0b6d2d0, 0xf69c1128, 0x7e6c20d6, 0x9d9ba33f, 0x83215307, 0x0a3128ad, + 0x4b4d3793, 0x3eda96eb, 0x4f7efc95, 0x57a11fee, 0x6995eccc, 0x162176a7, 0xd5a2e081, 0x25f43607, 0x0575208c, + 0x18316235, 0x829129c5, 0x30426a56, 0x54c377e7, 0xf992eca4, 0x9d82b911, 0x54cc5f04, 0xe57f8aa3, 0x15edafb3, + 0xa5f5e6c3, 0xd829b472, 0x9123bb6f, 0xa62401de, 0xb053f3e1, 0xd7939a11, 0x4570e3c8, 0xd391f5e8, 0x981a12c0, + 0xe745a6a4, 0x81a5b292, 0x81bc0fa2, 0xf9352ba7, 0x0e1c814c, 0x6a8feda7, 0x8135d245, 0x3a984091, 0xa0e3b97c, + 0xe8599d14, 0xc17f5d04, 0x2c6b12a4, 0x28f9a8ec, 0x956ace3a, 0x27c6589b, 0xe91ca2ff, 0xcee36546, 0xf15bda0f, + 0x9b049dee, 0xfc7cd73e, 0x3051ea52, 0x611eb7bc, 0xcba646f0, 0x3ee641dd, 0x42e7df65, 0xe67249fd, 0x0b62755d, + 0xec6db8f8, 0xc8ff8e54, 0x51fa22cd, 0xad65640a, 0x4da042c2, 0x27fe1b46, 0xe3b9b3a8, 0x8b6df453, 0xd76421e0, + 0x294c74dc, 0x686d33b2, 0xb886e4fa, 0xbdc7ecf2, 0x83794449, 0xf23df42d, 0x202162d1, 0x0d3b3f9c, 0x0fa19e61, + 0x5c944e6a, 0x26b39ffd, 0xbd40f07c, 0x8336c878, 0xf599c93e, 0x8049a9fc, 0xdb9cf234, 0xe3bceca3, 0xe89c769e, + 0xc05e6cb7, 0x5761469b, 0x0842d337, 0x8e5d9c69, 0x595e54d5, 0x714c2d52, 0xda4de357, 0x19d57c12, 0x22f7c405, + 0x8ff37ef9, 0xe59177bd, 0xf40e536c, 0x23b55ca1, 0x670feea4, 0x3b421cbf, 0x80d739cf, 0x1ee8e70f, 0x2c7f8446, + 0xebb55379, 0x5e23760e, 0x2d16d0f9, 0x910274af, 0x3d2fc1c8, 0xcc966ef0, 0x59a197ed, 0xad1065ba, 0xe990ed8e, + 0x55635305, 0x1391af25, 0x247c9058, 0xa4277895, 0xd09bff24, 0x74d9fd5b, 0xf71968b6, 0xaf7b67b6, 0xd0af1523, + 0x3e1c5fc9, 0x00074d21, 0x1451a29c, 0x8a97badf, 0x1bf52541, 0xfdb6dc9e, 0x663a168b, 0xe330a63c, 0x4729420b, + 0xb48957b7, 0xddf6ecc9, 0x4167cab3, 0x8443341c, 0x86aa4cf5, 0x0bbab5de, 0x3ce045c7, 0x6073da9b, 0xc6b96522, + 0x8857c91e, 0xa292b74a, 0xd83ff830, 0x169065e7, 0x82177a3b, 0x959c44f6, 0x265801e5, 0xa8dbf934, 0xb26ff68f, + 0x434975ad, 0xe304bfc5, 0x9f549db9, 0xd27467e5, 0x63816690, 0xeee0e9df, 0xe3764d51, 0x6844089a, 0x2ba9d850, + 0x90d8241f, 0x09bdb75b, 0xeb81562d, 0xbbd0488c, 0x00909f5e, 0x6520ce8a, 0x6db18f5a, 0x0d557742, 0x0044a56e, + 0xe10a79d6, 0xc69ecf9e, 0x0dcfa2a1, 0x7312db05, 0x9651604e, 0x21853664, 0x071959b3, 0xb8b0cb77, 0x406aa1bf, + 0x82d67db0, 0x9352b085, 0x5f36947f, 0xc5c4e62d, 0x1d92307c, 0x28c48035, 0xc0aebfaf, 0x2542b54d, 0xa79d97d7, + 0x54f13fdd, 0xb77054b4, 0xaa461fca, 0x9cd31ef9, 0x38be28a0, 0xd20dc1c2, 0x97be4d9a, 0xfea59699, 0x0c2c6655, + 0x931e9216, 0xec24eeba, 0x264ef044, 0xfa68f997, 0x917a8cc0, 0x47fe0320, 0x9c27e047, 0xa0e383d4, 0xa7a93e3d, + 0xd4b4d4e6, 0x8c78cb6e, 0xcf1172b2, 0x9e53324d, 0xde3fc35e, 0xbd6168a9, 0xa4ed6dd2, 0x40a005e5, 0xea97a1bb, + 0x5197e999, 0xf971e729, 0x6eb6e6c6, 0xf2186f26, 0x956be1c0, 0x198ae0c9, 0xf8837133, 0xc5345061, 0x71523372, + 0x2c740bb8, 0x6382559a, 0x956212c7, 0x09b22bf4, 0x88915936, 0x9e24e4b5, 0x9966e99e, 0x9b23f80e, 0x07ff318a, + 0xd8ef7cb9, 0x986eedaf, 0x10ef8dd3, 0x0cff9089, 0x1f257edb, 0x2c237e15, 0x6a7995fd, 0xc43d4d42, 0x138ad595, + 0x8ffdcb40, 0x55aa67a8, 0x467f1381, 0xe66e83e1, 0xc145d848, 0x34872eb9, 0x3b90edc5, 0x4fd6fcb3, 0x5d3e5045, + 0xbe079412, 0xc5479a0d, 0x79b05534, 0x747e76d8, 0x31e925df, 0xa87e3525, 0xc4414a25, 0x41ef729d, 0xd230ac7f, + 0xbc9ec796, 0xb4727881, 0xc82bf346, 0x78ed3d54, 0x9e32c423, 0x9e1a8127, 0xb9fc08cb, 0xd1348fae, 0x9989f1f6, + 0x5119fa9b, 0x271e6a6f, 0xb501d9f6, 0xbdae23db, 0x02737f5c, 0xc6972fcb, 0xea2252d4, 0x6f02751c, 0xb4a2e2af, + 0x96ec2c6b, 0x0dcb5ea2, 0x11a521d0, 0xa0bea2b1, 0xaa5fbc07, 0xb2b9a6d7, 0xe74ec9d6, 0x101a5a17, 0x0e00bd11, + 0xe18da710, 0x38e34672, 0x344427bd, 0x09b07dee, 0xd9ee80b3, 0x1710f3f4, 0x137cefac, 0x3caddfd0, 0x12fb7527, + 0x4d1e089b, 0xf257478b, 0x1de88770, 0x17626deb, 0x137dda4f, 0x491be67d, 0xac4018ac, 0x44e904fa, 0x71dd7582, + 0xedee4aae, 0x517c902f, 0x722cad2d, 0xaa77d80d, 0x94f732ac, 0x94a66b9e, 0xa815604f, 0xc1095b01, 0x3ccf402e, + 0x3c4ad225, 0x610c054d, 0x5da0f8f0, 0x718b0069, 0x19697713, 0x310bbf3d, 0x2b026413, 0x87ca982e, 0x3c51d3b3, + 0x1c28462f, 0xd9e076de, 0x0a8de2f8, 0x398b5fb2, 0x5e205feb, 0x7f97dc47, 0xf15aea65, 0xf777f2f2, 0xe1cf4860, + 0x50c4825f, 0x775bc143, 0x591b99d9, 0xfe3b3b04, 0xe2b53ee8, 0x84f9c3d0, 0x67879577, 0xd683455c, 0x6311006e, + 0x35874796, 0x260ea5c7, 0x279ee8de, 0x4c260a82, 0xf93c65b0, 0x00a93a7b, 0x9e39c181, 0x73207992, 0x49f84f5c, + 0x0c427642, 0x4a5e3bfa, 0x665e3fec, 0x4a2116f1, 0xb25f4f47, 0xc7187265, 0xbb9976fd, 0x4b5fc70d, 0xaa1ab35c, + 0xc935f9af, 0xeccd4c01, 0x62ab2f83, 0x5d4ab686, 0x429c5981, 0xdcc8ce86, 0x7da2c94b, 0x0bd1f284, 0xe3bd78e5, + 0x1de8f2b9, 0x2ce64b0f, 0x4940c79c, 0xbbcd761a, 0x282e241c, 0xe4b22c83, 0x60fce126, 0x36d207f9, 0x57f8f5b8, + 0xc908ced2, 0xf13f7684, 0x1c16daa9, 0x7881b0dc, 0xcffb4887, 0xeb23ffee, 0x04741745, 0x1a8b440e, 0x2a279e5f, + 0xe8b87ac2, 0x48514447, 0x1faa4cb6, 0x337e3bea, 0x00a0ca68, 0x84c88fc7, 0x58446190, 0x1e1a3f57, 0xce1bbacc, + 0xfea594f0, 0x947acd59, 0x6bafa9e9, 0x6965a3eb, 0x0fc46b0f, 0xe0a8aacf, 0x226a56e5, 0xb202ee77, 0x4f0caba7, + 0x5e9de277, 0x640f1ecf, 0xd758cc98, 0x0f81e2a7, 0xb38f4ac5, 0xd4bb4163, 0x74ed4c82, 0x129beb1d, 0x161cb722, + 0x8e6dced4, 0x2d8a7243, 0xc8e2801a, 0xce153026, 0x5a1d6568, 0x47e1fea1, 0x3bb72b5d, 0xd7040b68, 0xd17c139d, + 0xc1d56ac6, 0x3363dd8a, 0xdc5710b7, 0x7711511e, 0x9cbfe5cb, 0x1d42a34b, 0xc2fab8e5, 0x7c865f6f, 0x0213204b, + 0xfe308333, 0xfb997712, 0xb579ebcb, 0x49c2f396, 0x1bc98a4b, 0xc94935eb, 0x9b84ef17, 0x868bcf75, 0x24012c26, + 0x668f494c, 0x178b9f6a, 0x6140ace4, 0xcb569d9e, 0x082b6dfa, 0xa6b491db, 0x686060ea, 0xc7a149cd, 0xa1496e1c, + 0x7d0011c2, 0xdf3a1f77, 0x658df68d, 0xfec13283, 0x1cd3a05d, 0x6946f477, 0x0cd81f71, 0xdd3238a8, 0x35468f1b, + 0xd09e5e9a, 0x1cd493cc, 0x43c1573f, 0xe020d0e7, 0x6ea79977, 0x77f41bd3, 0xfc6ab36e, 0x1e5b967a, 0x29002d46, + 0x2997ad7c, 0xa36e36ff, 0x6112f679, 0x77b14bd1, 0x137c351b, 0x50985769, 0xfa014f42, 0x581afa04, 0x85e7efab, + 0xb9dad285, 0x864c3b89, 0x5c94964a, 0x578ad33b, 0xa310f863, 0x2b7634b2, 0x63da4928, 0xf5bc388c, 0xc2575509, + 0x221d2fb3, 0x148a2035, 0x9e4eb9d8, 0xc191f057, 0xb2a3325a, 0xbd3e5a38, 0x2427389a, 0x6fd8159b, 0x83ee446d, + 0xce92ea15, 0x7d73f141, 0x57d842e7, 0x85767cd6, 0x73942fe5, 0x966bb3f6, 0xd6713857, 0xa87d1855, 0xf6f8377c, + 0xb499e6a3, 0x669a2a74, 0xcff0f256, 0xb31987b0, 0x3ecc16b2, 0x9002b65e, 0xa30d7242, 0x7f6d8394, 0xc873be87, + 0x9ecf884d, 0x0f809a60, 0x2b06a94a, 0x581c4628, 0xa37088e2, 0xd64a063e, 0xfa366d59, 0x3dbfb501, 0x81b3934c, + 0xe11b4d16, 0x98981945, 0x851d93ce, 0x4e5f73b0, 0x8713cc4a, 0x990c3e88, 0x3f10dde9, 0x2c741b6e, 0x16ca9e62, + 0x8a9574c9, 0x5fddd704, 0x91e0f946, 0xe145b261, 0xd6c8e914, 0xd46a195e, 0x836f2b84, 0x888488f9, 0xa0171075, + 0x5b68e624, 0x69bf7207, 0x97f89c5f, 0xf68bf78b, 0x0e48fcd1, 0xeb49a381, 0xe04b4e48, 0x6c2b4749, 0xa84a84e1, + 0xe7359ec5, 0x651a830b, 0x9d95b25b, 0x65d139ac, 0xd452f94f, 0x28f3612c, 0x61c87396, 0xe429effe, 0x3ea8483a, + 0xac2bf450, 0x450615bd, 0xeb94bf71, 0xa759a259, 0x418fadc4, 0x59734a93, 0x7a47a6f9, 0xe1652560, 0x5afb7d14, + 0xcca9ac68, 0x3516a22b, 0x28d369f3, 0x5d6ea00c, 0xa7c9c0ad, 0x137b9fb3, 0x2c7137c7, 0x733a939e, 0x29a50a01, + 0x3fa44daa, 0x7160a761, 0xac698f11, 0x1653e030, 0x12d99a27, 0x07a9f12d, 0x45df07e3, 0x010fc0fe, 0xfbc7b3da, + 0x6d1e6dad, 0xf992a21f, 0x52f3d632, 0x909eed95, 0xb27215d1, 0x732961e8, 0xdcd541b0, 0x28c21d54, 0x0df2b4ac, + 0xac33143e, 0xa9ea0eaa, 0xcdfa2588, 0xc927571c, 0xca35f8ca, 0xc840a0fc, 0x55b4b757, 0x9434bd7a, 0x2e1ac1e8, + 0x0a9b1162, 0x8aca7625, 0x034f9307, 0x0491ef04, 0x785d0c72, 0x73b299f7, 0xd17861e0, 0x4323eaa2, 0xd7e0aca2, + 0xf989705f, 0xc4f09bb5, 0x99fd7f86, 0x271c30d1, 0x27e92bd2, 0x7286960a, 0x255036df, 0x941e2779, 0xdb8eae4e, + 0xf6adff46, 0x2b49ac54, 0x0a1cef40, 0x1f28d624, 0x8d6162c8, 0xf080d22e, 0xb6bb18f2, 0xa880e3dd, 0xa78846fe, + 0x4d2fa3ed, 0x05378029, 0xc49b8f5b, 0x2905cb26, 0xd3aeb39a, 0x1629690b, 0xdd1757eb, 0x2ff1f673, 0x9a688a6c, + 0x1d4d24c1, 0xc9742446, 0xabda29b1, 0xcdaec5b7, 0x295c0d7e, 0xd90ff9d0, 0x978d435d, 0xaf68329f, 0x38bed6ce, + 0xcff29244, 0xd79a356e, 0x5910c2a9, 0x77e55bd1, 0x505f5a79, 0xd26d9743, 0xe070d255, 0x4e577e72, 0x68f33845, + 0xc18b2566, 0xa83308d5, 0x022b9e46, 0x2b6f4a24, 0x6c7dfc72, 0xf76630f7, 0xb12f83b8, 0xfbc91237, 0xab95158e, + 0xf8aa7ac5, 0xd76a5eba, 0x891fbec4, 0xe1cde14e, 0xf5fd0124, 0x123ce625, 0xb2e43de0, 0x65626d23, 0x3333eaf7, + 0x1f29e299, 0xd6b24c0c, 0x6a6481f5, 0xeb4ad807, 0xd7a16f02, 0x9655eb0b, 0xc22d345c, 0x3bec5fa5, 0xd22848fb, + 0xb9117606, 0x99d8de15, 0xf58f6e56, 0x7533b564, 0x90ad90f7, 0xa114cff1, 0x7fd502b8, 0xac5a34e0, 0x76e2b46e, + 0x3e106b77, 0x01e92323, 0x556d779a, 0x18b1a5ad, 0x2d9d2887, 0x54e1bd94, 0x9994a582, 0x59cf2080, 0xe17b5ab2, + 0xcb1f04ed, 0xd42fe908, 0xcd00aec8, 0x820a5c05, 0x229bee59, 0xc8446595, 0xc9dd9716, 0xdbb9653d, 0xd55f6f4c, + 0x2183da6c, 0xf615fa3d, 0x88b43107, 0x85f645a8, 0x3436b234, 0x7e553a12, 0x2cef38fa, 0xa738eed6, 0x011e4dd9, + 0x915ccf5f, 0x20b174c9, 0x25215972, 0x30b7a4cd, 0x2129f05c, 0x29ea8163, 0x13f81c91, 0x9045309b, 0x2064548b, + 0xf91efa18, 0x579d0262, 0x24c3d838, 0x8b3be565, 0x553939e8, 0x31d0c06b, 0xd314be9d, 0xb6c246d2, 0x114f9e12, + 0x1d8c0eef, 0x57c98e18, 0x50116040, 0x0778bbf1, 0x30d91dd9, 0x948b14f4, 0x1cd63672, 0xd72dbc14, 0x72c165f4, + 0xadfd0381, 0xdfee0594, 0xfd8f9a78, 0x29cf2f71, 0xe25469be, 0xec88ecda, 0xaeda0c7c, 0xa4b9957f, 0x5dc1a43f, + 0x3a77b4e7, 0x62ad807f, 0x04a337ea, 0x9b506605, 0x0379c816, 0xdb7feb21, 0x9702e194, 0x50f3c880, 0x437398f9, + 0xdb172038, 0x19658647, 0x0cad25c4, 0xdac606c6, 0xb84181d5, 0xb0dd73f1, 0x19065c8a, 0x51f1f7f8, 0xbee06590, + 0xc89c841d, 0x0c5e131e, 0x35468f66, 0x99cb53ce, 0x406283a7, 0xb2452b5a, 0xc707ab70, 0x74fe1adf, 0xa0e5107d, + 0x9c00f3bc, 0x24396759, 0xa768b114, 0x5f43e28f, 0x81aa7895, 0x66a389d3, 0xb6fceb34, 0x04ce34fe, 0x3f3905e3, + 0x5b1cfb92, 0x60cb41c7, 0x737fb221, 0x2a083549, 0xbb8d21a2, 0x1cdf9641, 0x79f3099d, 0xb43db075, 0x7ea7dedf, + 0x715888e7, 0xd1e4685a, 0x7287bcf9, 0xccdd9a60, 0xbccecffa, 0xbafb6e86, 0xf14a9b3e, 0x61e07c8e, 0x82918d5e, + 0xeb7d33b8, 0xd556421c, 0x15973a1b, 0xb90c91db, 0xa28faa1e, 0xc75b5121, 0x22dd0094, 0xa1b18fde, 0xc31376fa, + 0x05ca884a, 0xa5ebb379, 0xf63ac40b, 0x8466e9df, 0x40fbe81e, 0xe48eee20, 0x439b3381, 0x49b7ba18, 0x4219a400, + 0x5b54e97f, 0x1f080608, 0x72f70697, 0xead22ab7, 0xc8882403, 0x4a225667, 0x6fed4907, 0x9cc37375, 0xcba56457, + 0x94f85aaf, 0x9530fa6a, 0x3c478d49, 0xbc802dbc, 0x128a1538, 0xfc7e6e7e, 0x56baafa0, 0xeee4137d, 0xe0eaba4b, + 0xf64fcc01, 0x42bcc451, 0x31d11845, 0x3eec0754, 0x14e34422, 0xcf9564f1, 0x14c28626, 0x4c0d2afc, 0x3b7ac641, + 0x2e20cbae, 0xf977574e, 0xad3d0f5c, 0xdaa9c35e, 0x2f2e7b3f, 0x887c91b9, 0xf719e901, 0xd9376c89, 0x08adaa13, + 0xac741cdf, 0x8649efca, 0x8ba0702a, 0xcd6aaa37, 0x2e79f9d9, 0x1b8fbe04, 0xf6749bcf, 0xc5cc75fd, 0xb26605dc, + 0x84c6a553, 0x0c7e811d, 0x4b8181fd, 0x2674568f, 0x94896210, 0x0d6e87a6, 0xe0480f9e, 0xaf0b04f0, 0xaacd4ccc, + 0x18cec985, 0x20969a9e, 0xb190cf4a, 0x7add1f18, 0xc036fbee, 0x4245caff, 0xc344905f, 0x1dfe6053, 0xbf0601c0, + 0xa44ace0a, 0xab6273c9, 0xf2a88c45, 0xd23b8264, 0x34c2ec26, 0xce570e10, 0x0e4630bd, 0xe3eb4789, 0xf665b661, + 0xe057977b, 0xaa193923, 0x3017954f, 0x7a711b1e, 0x20583480, 0x2532da05, 0xad78e090, 0x3667ca4c, 0x066b7657, + 0x2567444b, 0x194ec9e0, 0x2edb827f, 0xb1401823, 0xc26cd9ff, 0x6fd7f641, 0x39d2f320, 0x0f0fe22a, 0x742dfee5, + 0x1ad7277d, 0x6f766d1b, 0xcc88dedf, 0xfa95ff25, 0x67c42dd6, 0x66e510f5, 0x6ed71be4, 0xf265a559, 0x8997aab8, + 0x4a86abbe, 0x4f047175, 0x59b00f4a, 0x82ba7234, 0xd3a81753, 0xac92292b, 0xe3fd3b24, 0xf6b2c4a0, 0x4c596b11, + 0x3f742cd1, 0xbb15f74e, 0x56eea259, 0x8b79eb9c, 0xf1de113d, 0x1c3d3dbe, 0xca8ef39f, 0x61b6293a, 0x4e4b74c7, + 0x319bcb75, 0xf2e48f4b, 0xdb0c8439, 0x285a9edc, 0x97f4e07c, 0xea8c9801, 0xd84438c9, 0xc2def1ce, 0x99f34b3d, + 0xbb37d944, 0xd632c6d3, 0x28044d93, 0xe200c371, 0xaa8479c1, 0xa188b88a, 0x4b2dbfea, 0xb8e34345, 0x8db34bce, + 0x329595cb, 0x2905e1bf, 0x007235a3, 0x2a2acf97, 0x0a3171de, 0x3669135e, 0x987358ce, 0x8d692801, 0x8bd03049, + 0x82a3cecf, 0xbe44d6c5, 0xceb2802e, 0x165d24db, 0x51c801b8, 0x6b84e02c, 0x13261123, 0x46a3ab66, 0xdc50a6f7, + 0x7c4e95cb, 0xc7a14e17, 0xa03965bd, 0x7fb68aec, 0x2f268d3e, 0xcd6f095b, 0x4ced2018, 0x7b7c3c76, 0x36e8a0c4, + 0xa53067cd, 0x9469b12f, 0x86ffd9c7, 0x909e84cf, 0x591fb34d, 0xcbec6274, 0x014513ba, 0x3b5ab3a3, 0x1e0ff7a6, + 0xf99c8df9, 0x41ea2e46, 0xa8124a99, 0x9a61e6c9, 0xd0b0f054, 0xf711d3c5, 0x6214952f, 0xc7bef68a, 0x627ad183, + 0xb624fcaf, 0x63db7bec, 0xc5c62329, 0x718a79a4, 0x4786d2d5, 0xd198f724, 0x92577935, 0xd9905b94, 0xb9ba3a88, + 0xa9acd4ee, 0x51ce62c6, 0x2c8c5296, 0x108c38ac, 0x26a82778, 0x27100ed6, 0xc5e83fd7, 0x2a86e960, 0x411cb773, + 0x5593844a, 0x82586d69, 0x63b05c37, 0x0fd2b681, 0x4de2d032, 0xd40b3d86, 0x1ce8e784, 0x93ed3415, 0x04bb6556, + 0xdf10fdcd, 0x7fbc8586, 0x1d9a55e2, 0xe48c898c, 0x89a26ac2, 0xd598f771, 0x89e57236, 0x472d887c, 0x01757ad2, + 0xe98aea11, 0xea51243d, 0x26ccb359, 0xd7ad5777, 0x856017b1, 0xdbdd8f54, 0x5fd25865, 0xff70f445, 0x5e678fc1, + 0x9143078d, 0xd1001d25, 0x5fb99d91, 0xebdb4a7e, 0x299eed15, 0xf804a8e1, 0x0060b0ce, 0xc8826df4, 0x64fdc4bd, + 0xa20a85a9, 0xabe218a0, 0xbaeb1d06, 0x97454c3a, 0xe73584b3, 0x2ed4d6d0, 0x075bbe2f, 0x2b066332, 0x5057711d, + 0x3ea562de, 0x12f19209, 0xddebb68d, 0x9d86f1c3, 0xe67b0ad3, 0x483837a4, 0x8e24bbc2, 0x821478a1, 0x4504b886, + 0x8581b62a, 0x2602bcd1, 0x22767bf5, 0x3f38761c, 0xd36c62ef, 0x59a75948, 0x5c8770ab, 0xd8c91bae, 0xd58cd2a2, + 0x1f516691, 0xcf073d87, 0xda7b5736, 0x815e48e4, 0xae93d68d, 0x06dda188, 0x31e9a44b, 0x5d2b4be9, 0x59fb358b, + 0xb7651551, 0x25516ad9, 0x5c6db49e, 0x6f313106, 0x2ee99099, 0xb77931d6, 0xac758546, 0x04a8349e, 0xd42ff0ca, + 0x5ac6ca2d, 0x6009589f, 0x4822185c, 0xa06f4d80, 0x4bfec3f2, 0xacd318bb, 0x4e192596, 0x6714b64f, 0xf9825e58, + 0xfe638a1c, 0x5330cd6d, 0x7ffabff3, 0x70e1a4b2, 0x611c1d6a, 0xb89a15fe, 0x5694fa37, 0x4a2ada65, 0x696bb9d0, + 0x1cd3f89b, 0xaeb299d4, 0x7c9a6264, 0xe34b24e8, 0xef82fd0a, 0x37d159b0, 0xbb7e06e7, 0x0331a8b3, 0x154efd07, + 0x11f499e1, 0xb2c94bb2, 0xf2651a86, 0x12263988, 0x628934c1, 0x5f2f7a3a, 0x9a188b7e, 0x18eef4b4, 0xf772ac27, + 0xcb3642ea, 0x85647a9c, 0x92d99844, 0x6243dab1, 0xdb2cc472, 0x5af6e61d, 0x0879293a, 0x289022b7, 0x775dfbd5, + 0x2c88d058, 0x303864d9, 0x31cd279e, 0x99109b7a, 0xe9dbbc82, 0xd9f20e02, 0x35a3f5c8, 0x89bcec41, 0xf9b8e1b5, + 0x7ba2247b, 0x6c36b6c0, 0xff4684a9, 0x20e180d1, 0x1a26f5af, 0x3f029167, 0xc6286578, 0xea671668, 0x7dace0b1, + 0x9fbac223, 0x07bbed79, 0xa5265f64, 0xc9484628, 0xece44e21, 0xdf2b347c, 0x5d82bffc, 0xfd955ff3, 0x4e7ef717, + 0x9d3fe9f9, 0x7f32f83c, 0xf00c221c, 0xb4fd09d2, 0x67a02906, 0x777164a8, 0x32d47c14, 0x63a69faf, 0xd284948d, + 0x0afc1749, 0xf938e7f7, 0xde2679f1, 0x168f8dfd, 0x4783b9d4, 0xf2e3b92f, 0x35006c0d, 0xef93e013, 0x82259e83, + 0x82f4ca07, 0x4e3a1329, 0x2a443a9f, 0xd9353c37, 0xb2379bf8, 0x77bf23d4, 0x566e873d, 0x1bba9d69, 0x39764f4a, + 0xccb87f8b, 0x14e2c0b6, 0x7d0f1de4, 0x0ef8d912, 0xbb53ab97, 0x47669e07, 0xea29ce01, 0x43a79faf, 0xaed6704c, + 0x64868c06, 0xbd82b7ad, 0x629a3f4e, 0x5afa0b51, 0x4ab84053, 0x1a7194be, 0x1b0a8b74, 0xa9d72c5a, 0x75a2e829, + 0x0f9c49b7, 0x44321f10, 0xd37cfe07, 0xc5033924, 0x1f05eea4, 0x171aee5f, 0x549d29e3, 0x4169e2f0, 0x50042885, + 0xbc246839, 0x38873ef7, 0x70e71270, 0x2c89bee7, 0x0b0717c6, 0xe4fce65c, 0x4f759dd4, 0x646cef04, 0x3b91f684, + 0x3a3cb522, 0x52ee1abf, 0xbcdd918c, 0x9b47ceb4, 0xdedf4465, 0x0581d548, 0x04f6a22a, 0x7e3ac534, 0x1ace5460, + 0x292e9b3c, 0x888a7ecc, 0x111bd10f, 0x99a6c0d0, 0x37cdb16c, 0x8b7a4425, 0x4bb67439, 0xc6ff1f52, 0xcdbb6907, + 0xfb2c5f71, 0x3b950fa1, 0x0c2d4968, 0xd22eaf28, 0xa64eea0e, 0xe8f970f3, 0x7fd2e257, 0xb715cde4, 0x7dd46897, + 0xf8289696, 0xbf8a043e, 0x4afa1921, 0x79282c60, 0x23f8c563, 0xac172d8e, 0x400bd37f, 0x9aac6ca3, 0xadff1bf1, + 0xe38bacf5, 0x87996d7a, 0x54a2cec0, 0x2726dcf4, 0x17c7c9d3, 0xe67e7b39, 0x33663023, 0x538177a8, 0xdd0a4e50, + 0x1236c4fd, 0xd2e3dc27, 0xf03115e3, 0x7e2023b1, 0x2f7776f3, 0x43eace5c, 0x4cb71de9, 0x3a578723, 0x96330541, + 0xd66d57a2, 0x79f5e600, 0x1b0bb439, 0x1fed0086, 0x48b9e355, 0xeb8e91f7, 0xabde5122, 0xac4ef5f8, 0xc4594b5b, + 0xae8b0108, 0x9a83c393, 0xc13dce78, 0x86e71171, 0x1ae2b8b9, 0xd99d9607, 0x4632f1c9, 0x43f4892f, 0x96dc92bc, + 0x9c0da8f2, 0xeb8b79f9, 0x4207a730, 0x5b41afb7, 0x52fac629, 0xa78fa6bc, 0x0b43422a, 0xdd67e117, 0xcd3887eb, + 0x40f6f403, 0xbf52d1f6, 0xcd3fde6e, 0x6e201eb3, 0x62038e71, 0x2e4a0950, 0x34794045, 0x66261bf5, 0x91428efc, + 0x8d7d1036, 0x2b72f182, 0xa66c5063, 0xdea7bca6, 0xc8035e3e, 0x06faa4a1, 0x26722e5a, 0x082c86c4, 0x2a20a5d1, + 0xcece0551, 0x843be80b, 0x6a17fac9, 0x2caaaf1a, 0xdd865166, 0xb33d96c9, 0x536f1d97, 0x4763c816, 0x165d9809, + 0x3ad92896, 0x018e14be, 0xe31a780c, 0xe206ea16, 0xb1d37e70, 0x125e4b64, 0xd825cc67, 0x0b065f7d, 0x4e6b7e9d, + 0x4c6a5492, 0xca0726b6, 0x49c15c6a, 0x51402531, 0x803e3a93, 0x786e0349, 0x090fdaef, 0xe5491043, 0x75afc300, + 0x71a6bc29, 0x65efd0e0, 0xa15d5345, 0xfb744e2e, 0xc13dab30, 0x23a06cac, 0x359fe5fa, 0xa9e0d9e8, 0xbc01ce45, + 0xdf7e16a9, 0x5340688c, 0xdd4fe1b6, 0x4ca4ee01, 0xe2dec18a, 0x41caa48d, 0xdd0032ba, 0x71014307, 0xe07bdeb1, + 0x291c3ba6, 0x12620de2, 0x3d5a6519, 0x2343bc8c, 0x7a8c0e28, 0xf2b6e2ff, 0x479e66ee, 0x9a0025b8, 0x77fafe4f, + 0x01a4eba7, 0xc6faa1db, 0xbd4f4ffd, 0xd937e0f9, 0xfdf68d03, 0x1061f0ea, 0x6c8be0ba, 0xeed88a46, 0xa8b9b97a, + 0x2760b9bb, 0x322b6aa0, 0x48052305, 0x7580cc1d, 0xfd19f871, 0xc52bbc84, 0x127ee0d6, 0x2144e28a, 0x9f448e8f, + 0x9b5343ea, 0xa70a7097, 0x5d38cf2f, 0x2d03e9ae, 0x0bb96210, 0xdef9d77e, 0x2b49e626, 0x4fbd0cdc, 0x7eb0a5c9, + 0x6d03d59d, 0xc25d0147, 0x4697a2c0, 0x7cdece15, 0x782ee508, 0xb939f2c5, 0x9e981855, 0x6aca0cad, 0x336cce92, + 0xf030ed89, 0x8cafa7c1, 0xf858c121, 0x2caf1b16, 0xe2dbb97d, 0x6031008a, 0xbb42b6eb, 0x59847b8e, 0xb7debb32, + 0x2c12f199, 0x9a4c7332, 0xfe985aea, 0xc037cbf8, 0x1e33b2d5, 0xc594a03f, 0x641f9d99, 0x7db1568b, 0xa5c947b2, + 0x23b12c1b, 0xbe44d91e, 0xc04a8000, 0x1659ca3f, 0xd8b46e15, 0x068c9405, 0x209dc7ee, 0x4ed8962a, 0x4f8dd62f, + 0x2ede1fc4, 0x244f61de, 0x83daffb3, 0x2b28d968, 0x38dd7b55, 0xd0e6cd0c, 0x1172da17, 0x41f64cbe, 0x3f500d0a, + 0xeaeebf8b, 0x4f80bcf6, 0x29d9172b, 0x2af6b598, 0xe3a18caf, 0x3dfd77e6, 0xa0d941a0, 0xa3fd9f0e, 0xd6dfd70c, + 0x5c3f81b3, 0x3d644f24, 0x60082d32, 0x5d4c0676, 0x3afffe89, 0xc80b5547, 0x9d943943, 0x424430a2, 0xb3a4e5c4, + 0xf5bb2144, 0x1084d92d, 0x7ea3e332, 0x38898888, 0x20cbca4d, 0x18981394, 0x1a26b427, 0x3c5e8685, 0x24715561, + 0x1a295c97, 0x1728a499, 0x1b6bfa0e, 0x1bca92d4, 0xa8fa7663, 0x717bec98, 0xc4853dbd, 0xd66347bd, 0x6463e22c, + 0x7a4285c3, 0xc1e2a6d8, 0x2a0bd15b, 0xee10dd49, 0x778cb87f, 0xeb947afc, 0x1e4b04b1, 0xd266e525, 0x8f135d6b, + 0x19dca368, 0x35abe51d, 0x5d573ee3, 0xfa87b390, 0xece24f0d, 0x3f4dfd79, 0x3a142d98, 0x3ce76539, 0x7987ae45, + 0x1a617d01, 0xf9eb0345, 0x80cd6931, 0xcfc2e446, 0x6f7d679e, 0xd74de4fc, 0xb660598f, 0x02301c57, 0x3dce6e80, + 0x65ddbd03, 0x87cfb833, 0x09e5b257, 0x4c501c23, 0x2b28ac94, 0x285b2e98, 0xc6e0c877, 0x76050f1c, 0xe0072456, + 0x3425366c, 0xc63cc4d6, 0x4d17229f, 0x1f0a4b09, 0x9c7d5a73, 0xf4824cc1, 0x54081524, 0x568fa70a, 0x96635ff8, + 0x334a7f1e, 0xab1e2a6f, 0x8670c1a9, 0x1192fb9c, 0x0ef31f27, 0x48c7c3b5, 0xa5d44259, 0x011ecaed, 0x570ed039, + 0x683d1c5d, 0x7ba418f5, 0x81c26577, 0x6df4b105, 0x242fad3d, 0xcf156af5, 0xfb93105f, 0xa98747d6, 0x9d0f32a6, + 0xbe5f648e, 0x2c9ab4d0, 0x104aa52e, 0x5ccd3fd2, 0x2f59ffed, 0x5611296a, 0x1d66712d, 0x03bac541, 0xaa365585, + 0xc47c8c84, 0xdda5852e, 0x927ed385, 0xadaacd30, 0x4bd93d89, 0x44542438, 0x26f49cf0, 0x217837d6, 0x7921ff3e, + 0xa3015037, 0xeeda0115, 0x2d21c8d0, 0x1a111c99, 0xf9ff1a25, 0xd5d404fd, 0x36e4bd8e, 0x075907a3, 0x540a2cd9, + 0xdd1fce2b, 0x8a88a2bf, 0xf8c1bf16, 0x189c5844, 0xf2020a2e, 0x04b5c0e3, 0x3e574918, 0x3d1dda73, 0xe518d1a1, + 0xc043786e, 0x323a26b2, 0xcec1b5d3, 0x65d87d34, 0x1e7d2702, 0x905dd1bd, 0xa8395ee5, 0x249a5ee7, 0x4fd5e4a2, + 0x0d89e747, 0x56d0b3bf, 0x1e52255c, 0x374a0d96, 0x20715cc4, 0xb7100457, 0x32523fbf, 0x4b4ee063, 0xab73fb91, + 0x24760e62, 0x340091a8, 0x272a129c, 0x03493240, 0xc9d1c52b, 0x40cfb5f9, 0x41bcd22f, 0x23454170, 0x6565c3e2, + 0x177de95c, 0x930d9d2a, 0xca789491, 0x5427787a, 0x7c483e30, 0xb4b4bc0c, 0xe539b3a1, 0x6fc8e8ec, 0xf027efd5, + 0x55975b0e, 0x7ebb63e5, 0xa56acbc4, 0x18278a25, 0xa6f6a9e5, 0xbe14dfdc, 0xd2065f4e, 0x3de7c689, 0x2bc9ced2, + 0x2e5b5983, 0xafbdc2cc, 0xb03596bf, 0x40916d4d, 0xc83a5411, 0xa8c2da53, 0xe6f73f3f, 0xea89ced3, 0xf55dba4a, + 0x1ee6bbb8, 0x0a9892a7, 0xd56006f2, 0xec138a8d, 0xd01d7ed0, 0x1e4ea83d, 0x8be0c1d9, 0xcfa0b005, 0xf532b9f0, + 0x80563984, 0xb3a59038, 0xb23e08cd, 0xa5a470be, 0x4bba6dca, 0x1dd6348f, 0x1c49403b, 0xa1853f27, 0xb7b99d57, + 0x81160a99, 0xe9ea5ec5, 0x08e38190, 0x8ef5f4f6, 0xa8295bee, 0x3011a30f, 0xdd3e6935, 0xb58906e2, 0xd78aa7e2, + 0x4f823fec, 0xb2ad6be8, 0x3873af4e, 0xe489245f, 0x4c7c95d7, 0x64e3e4ce, 0x8f812234, 0xe34e2e8b, 0xb8e0690c, + 0xf93594c2, 0x7c247776, 0x4663978c, 0xdca98fa6, 0xf4fbad3a, 0x3bf1d597, 0x8859952f, 0xf9b7f6ed, 0xb2a31f3a, + 0xb4b93325, 0x379f5037, 0xb905c1bd, 0x19c30685, 0x24e4a7bc, 0x6bf23fa1, 0x95c1100b, 0x519048b7, 0xace71e73, + 0x3a79dabe, 0x2e28741e, 0x81c69dea, 0x21d4fb3c, 0xa0e6f814, 0x24b96f4d, 0xb987ddb7, 0xe7ee4975, 0xc6581e75, + 0x1b9f5be5, 0x45d5c546, 0xb8249841, 0x30c5b565, 0x1cc86c3a, 0x5337600b, 0x83784964, 0x513d5024, 0xbe69f80a, + 0x79790f15, 0x5223ac8b, 0x9f14b51a, 0x6d0a302e, 0x3a403446, 0x5db50618, 0x261660c7, 0xe6f00b11, 0x3977e572, + 0x06d23287, 0xe87aa100, 0x7653d8a2, 0x8ad07029, 0xdc0f04ae, 0x3edec3be, 0x56048113, 0x6f234b20, 0x5e87f1e3, + 0xc782d926, 0x0c265d6a, 0x72d032b6, 0xdd15a724, 0x1c1d52f3, 0xe367698e, 0x4294ef0e, 0x4143e789, 0xe82ee7f3, + 0x212fc9e6, 0x1ad603c5, 0x0f20a3d1, 0x61e50210, 0x0fdc8bcf, 0x5932a583, 0xf1b56bf8, 0x5bb67d8b, 0x8ba45140, + 0x6ee508d9, 0x7fd68f47, 0x23a808c0, 0x4a168099, 0x58e53eea, 0x703eaf95, 0x3ef2658f, 0xade384a4, 0x6138e01c, + 0x4a15a496, 0xd29305a0, 0x9f21018c, 0x93cfb677, 0x662c1ec0, 0x7cd8b90d, 0xfd9af42f, 0xb2248ee2, 0x0e9d53d3, + 0xb0367499, 0xdee4eb92, 0x60e27ac0, 0x815cd91a, 0x8ae80ac4, 0x5ef42cd6, 0x60b28a74, 0x86a6a326, 0x271f96ac, + 0x185b53fb, 0xbb329cdc, 0x75bbb1f3, 0x7a70adae, 0xfca41b74, 0x7a9f7778, 0x3fcd20dc, 0x6bcb966d, 0xae0b1f48, + 0x9c11bb2e, 0x45a6aa0d, 0xb6bb0544, 0x50ea381d, 0xadd09811, 0x34f6f98f, 0x050828cb, 0x15ea3717, 0x424faca8, + 0x0a07673b, 0x449b2062, 0xd7ee65cd, 0x41d2381c, 0x0343e106, 0xeb9f6633, 0xb38be08a, 0x2af63bf3, 0xded57c0f, + 0x24951246, 0xadf66c46, 0xdd2b97d3, 0x0b31f6e3, 0x3fe85ce2, 0x02a157bd, 0x7125b2a6, 0xa8ed921b, 0x8fe635b7, + 0x5675e045, 0xb2484af8, 0x309db473, 0x2d593fe3, 0xfd18c533, 0x5ccbabab, 0x816d939b, 0x3a8d7d2a, 0x18a1046f, + 0xa70f7f07, 0x8ebfd848, 0xdb04cb5d, 0x18679d68, 0xa7c46dc3, 0xaa43d48a, 0x76f0ea38, 0x9f00b75f, 0x4d93ab58, + 0x97a11726, 0x7279dac2, 0xdf4d15da, 0x46713ffc, 0x772e838e, 0x6a741427, 0xea4d6225, 0xbc28a5f2, 0x020c9ed6, + 0x3340a141, 0x1b49858f, 0x0c1a5bbb, 0xc79c5877, 0xe9c40b9f, 0x7c8087ec, 0x50fa6e2a, 0xd71d3ba2, 0x3612d60e, + 0xb32edccb, 0xde625545, 0x9dd1884f, 0x32cdc3b5, 0xec61ac1f, 0xfebd821c, 0x7a172cb5, 0x6e7f9bcb, 0xf45be6f5, + 0x5db0286c, 0x775a8031, 0xfe341cec, 0xcfe4063e, 0x38beb50a, 0x8419ce45, 0x17123771, 0x8400db40, 0xc3efbead, + 0x8f5b9513, 0x95344c32, 0xc6dccf4d, 0xa921693f, 0x7050fef3, 0xc49e00e2, 0xc9f5c993, 0xb5ced0e8, 0xac6ba2e6, + 0xf267773d, 0x63c05f7e, 0xe0ee9f17, 0x2245f10c, 0x829b5bdf, 0x8bc83629, 0x1d3e6a58, 0x1494f0f8, 0xdbea3303, + 0xa0a6cf33, 0x4160089a, 0x74a2d125, 0x52bb0fb0, 0x4c870caa, 0x251d0e27, 0x77785b1f, 0xf170652d, 0x24354645, + 0xb35d8108, 0xc6634f94, 0x7682e399, 0xe2d57a0a, 0x98839a66, 0xa12f68be, 0x88e9a2b7, 0xd9f0f4d5, 0x4bcb26f4, + 0x094c9319, 0x97a12c3d, 0x948b809a, 0x17831f90, 0x7296b7b4, 0xf5e22d34, 0x8108ee08, 0x58283fa2, 0x3f85f63c, + 0x78848d7c, 0x62926dac, 0xa4d6bf26, 0x41de0d3d, 0x8ed651f9, 0x89cf3df5, 0x492f7e33, 0x2065bf13, 0x3dd3439f, + 0x8366c69d, 0xc03505e7, 0x07afc857, 0xcd19bf4c, 0xe95ffcbd, 0x5139567a, 0x52bef3c6, 0x5f9dd084, 0xb5768d78, + 0xf1f4149d, 0x666fc892, 0x932c27d7, 0xec5ff1bc, 0x50d6bac3, 0xbe1aed17, 0xa34e01b8, 0x4aaef768, 0xf3448a73, + 0x55c860bf, 0x106f33c7, 0x48da17d2, 0xd9df6c2f, 0x70b625b6, 0xf9959a38, 0xb47b0ebc, 0x25200988, 0x29d0c4da, + 0x819c572a, 0x2b5100fc, 0xcb44efbd, 0x38693bf2, 0xd4701a28, 0xa6cb31f6, 0x5e048628, 0xfb20df8b, 0x451f55e6, + 0xb1fa0194, 0x5c5632ec, 0xe164d3c0, 0xa91ce4b3, 0x4268adfb, 0x5dd8d8db, 0xf4bdc713, 0x08b68c32, 0x858a64c6, + 0x0f3a6c8a, 0xd31d93ec, 0x33a2ffb5, 0xdd5a453c, 0xfd5ea415, 0x1c7ec15b, 0xa3146722, 0x7b74e9c7, 0x9f3ca02d, + 0x1014cee2, 0x3050bf74, 0x051aa679, 0xa05b36fa, 0x4fca0622, 0x6d4f3eb8, 0xc6fa90e4, 0x06a9e646, 0x1d2378cf, + 0x4d9117a4, 0x684e320e, 0x21be1a49, 0x7c268ab3, 0x7901e6bf, 0x6158ec15, 0x32a261bc, 0xdb41b0fe, 0xb68ff7db, + 0x51420568, 0x51269cab, 0x45553971, 0x3cfc4ab5, 0xe0968f5a, 0xfda23f36, 0x478abac8, 0x4fe0b545, 0x470471f5, + 0x24b1ec26, 0x41a00925, 0xd85e79fe, 0x108eb2c5, 0x964de8ff, 0xcffe493d, 0x417eeabe, 0x8c48badf, 0x2203ad1a, + 0xbc9d7ebc, 0x469a811c, 0xfda71c4c, 0xeb617574, 0x778fa89d, 0x6404ca45, 0xea7eb4e2, 0x75011f37, 0x259f9823, + 0xa95eb2b5, 0x200166d7, 0x929b967b, 0x3dbc6c8b, 0x887e3bbc, 0x0e91ac6b, 0xc927b046, 0xc3a82d99, 0x14a19cc6, + 0x648cc1c3, 0x545c6e37, 0x8c89cbed, 0xec54264c, 0x6cbedefa, 0x6431e9ad, 0x9af873f3, 0x1afa08bf, 0x516852a7, + 0xa7baf26b, 0xc4d35289, 0x3650dc4e, 0x6c83c079, 0x46f19780, 0x2716adcd, 0x268bc16d, 0xd765b804, 0xc4c7d8d3, + 0x6fbbed76, 0xaead230c, 0x2fcd30ff, 0x920d1001, 0xcb199b70, 0x8279380a, 0x8f1e5676, 0x691aee5d, 0x023367a8, + 0x40ce04cf, 0x80b28330, 0xecec8f0e, 0x6ddca04f, 0x1b026ee9, 0x8633dded, 0x503fb2e2, 0x7bc3dea4, 0xc981b9f9, + 0xa38bab35, 0x7bb8521d, 0x6077d00a, 0x1e70f876, 0x445ec589, 0x14eab75b, 0x150140a3, 0x9360a30f, 0xbf687993, + 0x7bfbddbd, 0x634eb082, 0x5ab9a810, 0x98e6eb0e, 0x2df7b610, 0xf434274a, 0x7e1daaac, 0x58fde125, 0x381f1a3b, + 0xddaf7c09, 0x7d1b2c52, 0x929c5f34, 0xc69398aa, 0xb53fb5a1, 0x918b135c, 0xaf8f7f25, 0xef3476ce, 0xafb1afaf, + 0xe5596068, 0x200697de, 0x33be5fc7, 0xa145571b, 0x2c6d26ed, 0x535de201, 0x9e813ece, 0x9128fffc, 0x77d1ad44, + 0x9befde34, 0xea4b41dd, 0xba7a4913, 0x21e95de8, 0x1e96f7ec, 0x9eec5aa6, 0xe07ae5c8, 0x658d87e2, 0x3d4660de, + 0x6265ab64, 0x9ff7f78f, 0x4820939a, 0x08fc266d, 0x462eec75, 0x08fc11f2, 0x7af25830, 0x6ac78ee5, 0xc041f5ae, + 0x69c84975, 0xc51efc7c, 0xc8281c6f, 0x26ade9c0, 0xa6242968, 0x5f10dc76, 0x1db88c5d, 0xff7d9f17, 0x65bbfbca, + 0xd2805666, 0x432e4d9b, 0x8381d503, 0xa76ddbef, 0xdb1964ee, 0x4c029133, 0xd695f2fe, 0xae161af9, 0xc50e05cc, + 0x75c8ed93, 0xe3437ad5, 0x08ae7237, 0xf9675c60, 0x8fe0e99f, 0xcadf4be7, 0x3ebf7612, 0x3550d3db, 0xc7c83ef8, + 0x7c1e1759, 0x00dbc66b, 0x5cbac9d2, 0x3597b922, 0x1e1e3355, 0x10d99744, 0x3f9ea0f7, 0x4ab57ad5, 0xa881ac18, + 0x10e0d659, 0x24ae9767, 0x1c38f619, 0x39aa2d20, 0xf4fd7219, 0x7155a3ff, 0xce8d6dee, 0x4f475409, 0x16f7efc6, + 0x0185c15f, 0x935ecca0, 0x4cf071ef, 0xf3af7b49, 0x70c86b7e, 0x41775d25, 0x5a37ca16, 0x008daef3, 0x5100a039, + 0x2fd53c38, 0x78eaf679, 0x8351fd1e, 0xd7bfe854, 0xac9207b9, 0x87b05ff2, 0xc6f31901, 0xa50f7afc, 0xffde3ca6, + 0xde079fe7, 0xaee223e5, 0x6e23524f, 0x84951bd9, 0x8c64c52c, 0x66774c4a, 0x4925b493, 0xe4b81421, 0x6b0e1383, + 0x3a81a959, 0x284861cc, 0xf4fa345a, 0x5d4d1245, 0xffc68fcb, 0x4e6facdc, 0x188ac395, 0x19b13157, 0xd876951e, + 0xdd995ca1, 0x76549427, 0x2b0b5610, 0x2c1ca852, 0x919a1742, 0x77df8800, 0x7286f2ea, 0x1f4c4b2e, 0xfc014ac7, + 0x2221d628, 0x4200b9d1, 0xa699d550, 0xdecc521e, 0x920481d9, 0xdade7765, 0x75864446, 0x3e6d147a, 0xfe124883, + 0x147d8f51, 0x8de7a9d5, 0x1efccd37, 0x30e0c188, 0x9fd328b7, 0x7e6f8ca4, 0x6ce9253e, 0xe3e20b27, 0x4737676c, + 0x9ea8c3bb, 0x66ac3dcc, 0xc12f6e8e, 0xdb83bd19, 0x77002024, 0x1383a74d, 0x833a1e0b, 0x9f747ade, 0x5d842867, + 0x8a651fe6, 0x660bf5b4, 0x6126caa4, 0xd288949c, 0x0a375ccc, 0xecefdc8c, 0xb86eafbf, 0x72a24aa5, 0x3e0cbdbc, + 0x203f0ff8, 0x6d34682f, 0xfb360c80, 0xad7de30e, 0xbd6469c7, 0xc99281c3, 0x83749f4e, 0x6dd204ed, 0x22df29fe, + 0x3a760d8f, 0xc1d29859, 0xc6f41bcf, 0x426e8dd5, 0x0a78dd67, 0x5697b4cc, 0x54464f5c, 0x4b794a08, 0x629cd208, + 0xba6e9f7e, 0xe45f8d89, 0xaa9990e8, 0x65362efe, 0xb4b0d1a4, 0x4e94c74b, 0xbe4d4b69, 0x80329293, 0x669848a7, + 0xd48f3bae, 0xa2e33679, 0xeeb4e514, 0x1370c897, 0xd5c02f6e, 0xefcb0f04, 0xec9bb166, 0x3f7387fd, 0x0cb5e0d0, + 0xa4e48913, 0x7d21a83c, 0x479b2298, 0xe21c68e1, 0xc4754c09, 0xc712fe03, 0xa06792bc, 0x91b0647c, 0x2917b0b1, + 0xba84f212, 0xfdd43daf, 0x05978ba0, 0x1ba0a877, 0x59295846, 0xf5eb7c20, 0x27f89e64, 0x9b704292, 0x7fe3bc7a, + 0xd64ec3bb, 0x591e3eb7, 0xba4bf60f, 0xa0b4812f, 0xeacdbe70, 0x35eced66, 0xb786faf5, 0x116de8e7, 0x5ffc5824, + 0xdb2b200a, 0xc73fc05c, 0xd6bcaaae, 0x0b4bbf04, 0x788a06ff, 0x63e7a530, 0x6cd36863, 0xd99977df, 0x4a99afd8, + 0x41f3190b, 0x083e4441, 0x4ba88689, 0xfa0ef62d, 0xd9bccb42, 0xfc0797f7, 0xb3dc581d, 0x4cb1892b, 0x2f7e1498, + 0xcd9215ff, 0x79ae278f, 0x59838b3d, 0x7b1737e0, 0x54244f7f, 0xb72a52bc, 0x2372985a, 0x12241d53, 0x6adc8539, + 0x9711abd0, 0xd8b24f36, 0x01980a3a, 0xd8b59f84, 0x75086d69, 0x62b3966c, 0xd01343a6, 0x6eca5c0d, 0x549577f5, + 0xbe111715, 0xd701d42a, 0x05a1bdb0, 0xf278ef4c, 0xae31e504, 0x6ed7bdee, 0xbf4c349f, 0xa74eb3ea, 0xb71274f9, + 0x91a56ca9, 0xbec35738, 0x9739f40b, 0xc005cbfa, 0x82cd5983, 0xee0cf47f, 0x4469cf1d, 0xd2aef6dd, 0xbcd7b016, + 0x986e82fe, 0xfd978861, 0x10c210d2, 0xfcbef2c6, 0x64f9f6ed, 0x15328bf5, 0xd9e50897, 0x457abbdf, 0xc85b4203, + 0x159cdf7d, 0x6fe38deb, 0xbba6e24c, 0x08771461, 0xbefdd29e, 0x5ca06667, 0xcefecb37, 0xc90661ad, 0x5e14f4dc, + 0x74f49c9f, 0xda7c7d89, 0xc54fb68b, 0x043b3db6, 0x4c577d46, 0x5785334c, 0x52fc2178, 0x9a0c4c9d, 0x22a6fb86, + 0x6762809a, 0x916c206c, 0x0be02f2c, 0x0dd94a9f, 0x66ecef06, 0x59a72d52, 0x4d3ddceb, 0x24c99b74, 0xec1bd3ed, + 0x280e6a89, 0x3fde1fe8, 0xc841196e, 0xdcb4ae66, 0x20e61c69, 0x226a87cf, 0x4ab88f39, 0xcdb51598, 0x1007a046, + 0x500958da, 0x46dd3be3, 0x7e9e433a, 0x973e279c, 0x35d9cf50, 0xeb26cffe, 0xc471c52c, 0x039ce931, 0xe0f97b52, + 0x4360a983, 0xf5ce202b, 0x21200db2, 0x32aade18, 0x53afc633, 0x2469d2f5, 0x89d24d88, 0x3bbb8c80, 0xa791e6b9, + 0xbec46474, 0x70f70413, 0x6ffd6368, 0x3c16cf1c, 0x41d2c391, 0x470bbd7a, 0x5f32bbcb, 0xd56672f5, 0x0199fcb1, + 0x21d9bf1a, 0xd03cf321, 0x1369cff2, 0x0ef098db, 0x00eedf16, 0x2e133a49, 0xd7b7de5f, 0xe2eb3b2c, 0xf4519b3a, + 0x0c62b78c, 0x9464783e, 0xdf71e28e, 0xd6bb3b8c, 0xb36cf127, 0xdf5ab111, 0xd0ef39ea, 0xa5721896, 0x3a8b8e81, + 0xa77fc3c0, 0x3eaa5f4e, 0xbf5566ce, 0x95b6d489, 0x24246e76, 0x3bc2d37a, 0xbcdf8d25, 0x3ebe7a59, 0x7f610c91, + 0x7736bcdd, 0x75bc2424, 0x85c70d05, 0xbeb7ba24, 0x4423de3b, 0x228f9f73, 0x7c01c1bf, 0x9f0d29a4, 0x61a80872, + 0x3ec5601f, 0x27ba04c4, 0xd7a5024e, 0x71452235, 0xfb211dc9, 0x61aa93d6, 0xbf25696f, 0x22b2f2a2, 0x969488a2, + 0x82dff5ba, 0xcfe623fd, 0x88329b88, 0x4cccb4ba, 0xb76482cc, 0xe5023477, 0xa46a3894, 0xbe7c5404, 0xd1fd3901, + 0xe6bbe2ce, 0x0c4f1b4f, 0xacc9b278, 0x3db561f4, 0x332dc3b6, 0xf38df13c, 0xeae891c4, 0x8f00c6d3, 0x778f1d35, + 0x99846b91, 0x5f3096ff, 0x4a87ec24, 0x7c7c7bfa, 0x47ee71c1, 0xb372259f, 0x572c7bbb, 0x9fac8e01, 0xbc3e5e7b, + 0x0a98ad4a, 0x8724098b, 0xb65b4238, 0x08816daf, 0x0ba64183, 0x50cc14e1, 0x42895df2, 0x8858e739, 0xcbe17ba9, + 0x1b74d24f, 0x4402d400, 0x5cc6ed20, 0x279a68ce, 0x7127622f, 0xb430e865, 0xe15ef496, 0x0ebe1de7, 0xd28793ef, + 0x1e95ce31, 0x753f0cb8, 0x9bdb6bfd, 0x5ecc4ba1, 0xf4421461, 0xadf6bdfd, 0xc01bd28e, 0x4419125c, 0x2d7d94e3, + 0x5073c54a, 0x96aeece3, 0x840a2b99, 0xb24aa255, 0x38345e2f, 0xf34125d6, 0xc761e37c, 0xb5ef96ce, 0x11d2d1fa, + 0xad59d51b, 0x360870ab, 0xbfcdf45d, 0x480e2047, 0x0dfda9b9, 0xdae944f9, 0x6f03ee85, 0x3b6f8dec, 0xed9fd4ce, + 0x2cfd70f7, 0xcb88d469, 0x5935984e, 0xa8d78801, 0x341df785, 0x020e6c47, 0x65f12cef, 0xdec04f23, 0x03e3fe4e, + 0xdd3008ff, 0xada46c49, 0x85e22f56, 0x278bb9f1, 0xfdcaa6b5, 0xaf47c5c9, 0x01381941, 0x3f60c1f6, 0x67f8da0e, + 0xa5939439, 0x4c0f815f, 0x2a17adbe, 0xed844395, 0xf2574d5b, 0x55e0b113, 0xdc8a1aef, 0x7ec73cd1, 0xb4d868e0, + 0x56f54288, 0x636cab2a, 0x5b33eb1b, 0x1a4f3fda, 0x613a2cb4, 0x5fac0fc4, 0x082f9f9a, 0xddea4a23, 0xc1484a94, + 0xa75a8bf9, 0x5575b1b5, 0x895bf61b, 0x7e3d5b23, 0x0c504c94, 0x8f7002be, 0xbb91b010, 0xe0c0e536, 0xdb74aee7, + 0xb1364dd8, 0x2d7610bc, 0xf0b00272, 0xa69f0300, 0x66e18979, 0x3268085a, 0x4efa9e50, 0xd084d664, 0x360f51fb, + 0x6b7a7c30, 0x2784ab4e, 0x3783c57e, 0xccf4e91d, 0x53b8639e, 0x194c94c8, 0xfe9f1f85, 0x2c3fd121, 0x5f61d770, + 0x5eae06a4, 0x58696c5a, 0xfc6871d1, 0x190701f4, 0x6ea70120, 0x1aabebf6, 0x634f5197, 0xee0233f9, 0xa86fec8c, + 0xf8b401e5, 0x3d41f088, 0xd040ff28, 0x35e174dd, 0x5e62e392, 0x7298867f, 0x4a0141f9, 0x16af8a83, 0xe79ade31, + 0x600f270d, 0xfba0bc80, 0x963ef16f, 0x1d356ea0, 0xfecd8e0f, 0xbe48905f, 0x4e444b91, 0xb00ddb84, 0x50dc11cc, + 0x66dbbdc1, 0x9b70316c, 0xaa65c3cd, 0xe4c95a37, 0x16807f45, 0x1c780fdb, 0xe48d9478, 0x551787d5, 0x5a9f9918, + 0x73d898a7, 0xdfadd8fd, 0x1929933e, 0x68ba46fe, 0x20216b46, 0x8ed90a4c, 0x468398db, 0x3d7c8352, 0x1791921e, + 0xbb5f1e08, 0x7e566151, 0x1c65b9ce, 0xd9a2f352, 0x81d68bd6, 0x80c980f5, 0xc9fd0a8f, 0x536fc6a3, 0x9e9d42bf, + 0x82fa063e, 0xcb52fabb, 0x07be95ad, 0x4677fb89, 0x3e6ce045, 0xa3b66e20, 0xc5061497, 0xffd971db, 0x5f535bc4, + 0x8c327bdf, 0xb1bc1ead, 0xea9cbf9d, 0xcdab1f9a, 0x76b2d7f2, 0xc3c2c476, 0xbffc7ea3, 0x0f2a9fdc, 0x33a14617, + 0x3fd9bb97, 0x07a1f3d9, 0xec3fabfb, 0xa9ff2d22, 0xf777121f, 0xa64456f4, 0xf7d1bd52, 0x411f3c98, 0x0f55fb48, + 0x053eacbb, 0x700c0ed5, 0x83b963ba, 0x97cd7698, 0x6f220158, 0xca43ce0d, 0x6b29fdf8, 0x60f1b4c6, 0xd547b235, + 0x0358ad8d, 0x7ebe869c, 0x5af8778e, 0xe2fbc986, 0xbd1c082f, 0xcd059775, 0x3cabcfda, 0xe2376984, 0x4747e9a9, + 0xd2373caf, 0xf6a5860b, 0xdfa4021d, 0x69ad5b16, 0x2284c521, 0x59d71496, 0x5f9c7000, 0x0c3b6c91, 0xbb9b4879, + 0x97582d54, 0xe0724668, 0xe2aeaa4c, 0x331f51b8, 0x6e2ca429, 0xc016e51e, 0x1c42d62f, 0x8b48d470, 0x271ae05f, + 0x5d90e07d, 0xf8785c52, 0x19a9c1e3, 0x02c97c1f, 0xb78faa43, 0xfbaeb138, 0x10586a10, 0x7dd1bd14, 0x91638d23, + 0xce1b1a7f, 0x30090d9c, 0xfff154b9, 0xdbd388e6, 0xa7ed52f9, 0x7bd0a9f0, 0x413dc608, 0x23475b4c, 0x3c79bb08, + 0x541906c3, 0xc25bfe53, 0x8cb22920, 0x396c9527, 0xc6e96e6d, 0xb1d78e9b, 0x978fb498, 0x36cd5f22, 0xac668ac5, + 0x54dafbfd, 0x593de62e, 0x2e42e635, 0xa881013f, 0xc094af28, 0x0efb8375, 0x11dab52e, 0x2540ed9b, 0xa68eded8, + 0x7abc5440, 0xde98a988, 0x9002bb36, 0xd84f6337, 0x75555601, 0x34586498, 0xd4dc0ef8, 0x7dd5914f, 0x8d99d5ed, + 0x4610e1a5, 0x270a8dec, 0x20dcbc37, 0x573da163, 0xc3de4fdd, 0xfed241c7, 0x5f702fdd, 0x69ef7655, 0x13a1d8ef, + 0xd3b95e3c, 0x1a5980fe, 0xb5319513, 0x9db66136, 0x5087d029, 0xfc5ee0b9, 0x3885f5f5, 0x434657f5, 0x3a93e272, + 0xd9352c83, 0x210a7dac, 0xc94a6161, 0xbecaaf13, 0xa203a2cb, 0xe4b7956e, 0x33a795ae, 0x3013f92d, 0x7017b2a2, + 0xe9648991, 0xf666727d, 0x87254196, 0x425e6c0d, 0xdd6921f2, 0xbaab70e6, 0x1950b964, 0xef38459c, 0xecc8dda3, + 0x0359da52, 0xbf0ea2f3, 0xf13104d5, 0x7013eb29, 0x1527c3a6, 0x8b37e6b6, 0xb6d41338, 0x1d25d8a9, 0x755c097d, + 0x0e7fd790, 0x705c51e3, 0x5d60c463, 0xd33d6222, 0x9d4dce8f, 0xaa62acb0, 0x5299d22c, 0x159978b0, 0x5833d779, + 0x15c0ad78, 0x2f62d6c1, 0xb082ced0, 0x9c46e0d9, 0x7616e78f, 0xe1d1fd35, 0x09b38247, 0xc0f8d1a4, 0xea653faa, + 0xf0d47877, 0x61a6a592, 0x0f2b3c17, 0xe9541ee2, 0x64725e4a, 0x61f2554f, 0xa7d932d7, 0x71792aec, 0xa58d081e, + 0xafc2aeca, 0x2bf1bbf8, 0x011c549c, 0xa3fffe74, 0x1af8f9cd, 0xb8d64e63, 0x0cd99896, 0x99c233af, 0xb7cfedb5, + 0x6a374313, 0x62fadfa0, 0x4c9bb710, 0xc71acdb8, 0xec3f103b, 0xab15765e, 0xc722d7ed, 0xcc3ee52f, 0x6b8547f5, + 0x3086683a, 0xcd5c9934, 0xe66c6b82, 0x4e8ed849, 0x01b333b9, 0x5c229bb2, 0xd9438eb6, 0xebbb298a, 0x83f5346f, + 0x2ca83009, 0xcd6d1575, 0x1d869607, 0xc5844af1, 0xfb1d13bc, 0x0a923b7d, 0x543d836d, 0xce7b47c3, 0x09325077, + 0xddc69fc5, 0xa84fac2e, 0xf1a34dad, 0x037b9aa5, 0x1abb9cb8, 0x9373b949, 0xb990b1c8, 0xa578cf79, 0xe4dcc060, + 0x66c03367, 0xd9be1315, 0x4d555340, 0x11929d56, 0xaef2901c, 0xc57fdc57, 0xb93b1dda, 0x803acd41, 0x0a9d1d5c, + 0xace3a189, 0xb301b223, 0x1bcdef5c, 0xb1e320cc, 0x23f223e8, 0xfd7492d0, 0x8d2de4f2, 0xc9c5a5d7, 0x649a3287, + 0xf215a122, 0xe08f3ffe, 0x65653b50, 0x941fd735, 0xb3d79d1f, 0x7070d2b9, 0x70ce8d7b, 0x67889ef8, 0x9bdc7d28, + 0xcaf4f4f6, 0x05fef23c, 0x48b7dc57, 0x8bd7fa12, 0xa52c4ef4, 0x89a79b8a, 0x3ba605e2, 0xc819c385, 0x9e9f9104, + 0x8d5bcbf2, 0xe4fdf73b, 0x0643276f, 0x790eacaa, 0x13a90024, 0x3f1f28f3, 0xd8bd6ef8, 0xd8f910d2, 0x00c6be15, + 0xe06016f5, 0xaa221402, 0xa029ff77, 0x7817ba1a, 0xf9ed2c16, 0xe0971174, 0x3e7e3b5c, 0x60cdf284, 0xef759e55, + 0x4020458b, 0x182d9540, 0x85a32cab, 0x7be4e579, 0x1ea122b0, 0xd350c4b4, 0x8d44340b, 0xed086e64, 0xd411bff3, + 0xc08503e4, 0x032a0396, 0xd221159c, 0x6f7d68ed, 0x895a623a, 0x0909a5bb, 0xbee06f06, 0xb690e2fc, 0xdbd5cebc, + 0x265deef0, 0x6f2bf00f, 0xacef4f16, 0x09f65401, 0x1aadd1d7, 0x53ae0c18, 0xde0b4424, 0x936b315e, 0x712cb052, + 0xef49abac, 0xa3f4b791, 0xadbf41e5, 0xfaa53a83, 0x15f0595d, 0xd9e2cbb5, 0x6db0d781, 0x08a045f5, 0x34d4343f, + 0xe01bb483, 0x4a069213, 0xf5fbc43e, 0x23769f5e, 0xb305d49f, 0x4afef682, 0x3e557f40, 0xc8f8b987, 0xbe8d4db9, + 0x39704de6, 0x08cacb6d, 0x97c3c23a, 0xfab89da9, 0xe5dffd65, 0x5d11ab26, 0x5985d8b0, 0x8b6f15cd, 0x3731a369, + 0x9e616045, 0xbb07df01, 0x7d63bf86, 0xe457c930, 0x8f322cf0, 0xad0245b8, 0x5ff2b4dd, 0xc61bbdfd, 0x6242de03, + 0xe5b42446, 0xe03362fa, 0x7847fb04, 0x5afb1e6d, 0x0a072803, 0x0d48fc22, 0xa63c500f, 0x6fb7c6c8, 0x539ac025, + 0x55bdd19f, 0xb9b74278, 0x2e29de06, 0x9e71e2c2, 0x3619ca29, 0x8590bc96, 0xa7de08fe, 0x2b6f54cb, 0x34504373, + 0xe5ac41d7, 0x764b6ea5, 0x0418a0dd, 0x886cfe9a, 0xad5e90c5, 0xa87ae68a, 0xfaea2295, 0x70bda1ae, 0x24b9d102, + 0xa05d8bfc, 0x67c23eca, 0x1f9aee2e, 0xb6360e7f, 0x2676e750, 0x62fc7ced, 0xed7e3ed7, 0x61b5e969, 0xa6643ef2, + 0x13f78cec, 0x55d5c9e3, 0x7d0e1837, 0xd73509ce, 0x9ef54531, 0x53c616e0, 0x8debd429, 0x2de3ea22, 0xc498e68e, + 0x7287080e, 0x9aeac5da, 0x6edd1a1e, 0x1d6ec11b, 0x6314a901, 0xaaa84229, 0xb134b896, 0xc9d9f8d9, 0x8ff53af4, + 0xc8bc481b, 0x13ec8911, 0x4236d4eb, 0x975e841d, 0x531f9933, 0xad8706a6, 0x219544fb, 0x1c8dee20, 0x933c2bab, + 0x181b672e, 0xf9720f21, 0xbbe02e5b, 0xf28d5c07, 0x75c60f36, 0x756f764b, 0xb3c19956, 0xa48053d2, 0x14c8d0a9, + 0x3f541528, 0xe08a771e, 0xaa208bd3, 0x48aafb11, 0xb5a34887, 0xed4968af, 0xaf4a2979, 0x6d12f3d2, 0x7bf15781, + 0x3d861eb2, 0xc8d093b5, 0xd4af20f4, 0x8f8bec35, 0x61b78976, 0x6bd7c5e8, 0x1ecf4478, 0x89f76893, 0xdd7fc4f6, + 0x9575c902, 0x353cbd32, 0x122f2f2c, 0x12799078, 0xe115b5b6, 0x300ba238, 0x9641654f, 0x269c8c41, 0x1ba8dfaf, + 0xb58b6115, 0xccf81b09, 0xc484018e, 0x53e7f876, 0x33cb516d, 0xa598cd85, 0x96ff6cef, 0x6a01be51, 0x7e6da28e, + 0xec588f84, 0x50a23131, 0x4705dbea, 0xe4130e37, 0x844f43c1, 0x94a5d756, 0xb28a947b, 0x46b9b710, 0x812b8c04, + 0x08665e95, 0x0bbe6687, 0x3f5db4a7, 0x0d9d6564, 0xb2cd24fe, 0x435c572e, 0x738a8784, 0x734885a8, 0x7ea18bd1, + 0x76536b62, 0xf0b48e79, 0x60e8a486, 0x3a97dac8, 0xc8115663, 0x549d5228, 0x93664af2, 0x4170d3a6, 0x51cc64a3, + 0x47e50f43, 0xfd089994, 0xa7bf3669, 0x27c86218, 0xa2247c34, 0xcb0d4c98, 0xb942ea24, 0x7dafaf03, 0x39c8b291, + 0xa4dae21e, 0xeaff9c6c, 0x9fbe9c1e, 0x5beed636, 0x458721c7, 0x7897d79a, 0x8997ede2, 0x23408af9, 0xa16a6a89, + 0xf0d8d1fc, 0x88e265c8, 0xac9199f1, 0x51a39e4b, 0xe4445e46, 0xec2efde1, 0xd7d72398, 0xed2268b9, 0xbf073032, + 0xb7a5df43, 0x2bfcd0cb, 0x9b0125be, 0x71f9f9c9, 0xcc8182f9, 0xc8df86f3, 0x602761aa, 0x90657a06, 0x6ebd28ae, + 0xafaf29c9, 0xe34694ba, 0x61b2e8c5, 0xce4e7924, 0x657e0afd, 0x763e45fc, 0xc919161d, 0x7901c017, 0x9c411a6e, + 0x4f992658, 0x8dbac46a, 0x6aeec55e, 0x890995f8, 0x6dbf896e, 0xef063d70, 0x6e43a93e, 0x463ccd4b, 0x930b8bf5, + 0xbd0c9edb, 0x1a4f00f2, 0xdad07157, 0x4a53d6f2, 0x4507bdeb, 0x1d66ae55, 0x65cd467d, 0x4457ea6c, 0x7b63a40d, + 0xcc988b9a, 0xc92f1255, 0xb3620de4, 0x20af699c, 0x2d57af04, 0xb8cebe99, 0xca3386c4, 0xcb7064af, 0x250f7d6d, + 0x89daab04, 0x1fd4df63, 0x03cc955a, 0xe7b65b0b, 0x9f308231, 0xfdee35d5, 0x67952ae1, 0xef57ba35, 0x26debae3, + 0x278a27c4, 0xaedad107, 0x029afec4, 0x06be2547, 0x03ccdd16, 0x4ae9edf4, 0x164dc66d, 0x72808858, 0x8266b490, + 0x6371d8da, 0xbbba9710, 0x3a2f8a5e, 0xb7226451, 0xec0e3241, 0x0c013c22, 0xb7635ba2, 0xdb206d85, 0x939de79f, + 0x7b6dd4c8, 0xda7ff402, 0x1a13e32d, 0x304084dc, 0x23b85ad0, 0x2c06c157, 0x1687aca6, 0x865b43ed, 0x7861b813, + 0xb846e388, 0x4ad13c16, 0xb35e3b7e, 0x932870f0, 0xcf4d8779, 0x9bbec694, 0x9544d55b, 0x32d4cfff, 0x151ead2b, + 0x81f3ddf6, 0x4b2f74df, 0xcced2f0a, 0x3ae10a3f, 0x24172442, 0x64b7d114, 0x3ec4d54e, 0xc5e4755f, 0x439b8713, + 0xeb061e09, 0x7a125e49, 0x5df86019, 0x8ff08119, 0x8ebed408, 0x14ff71aa, 0x5424b7b5, 0xa7b754a5, 0x7036b5bd, + 0x75762122, 0x7f42117e, 0x2615c731, 0x4312c4bb, 0xdecee840, 0xedb3e8c9, 0xc3002ec4, 0xac55da69, 0xbd0cf99e, + 0x3e6601cb, 0x47a1a5a2, 0x3576086c, 0x8c625563, 0x06f203b1, 0x314c44c5, 0x9376844d, 0xa30e3fc8, 0xb7607bb6, + 0x2770d2f0, 0x2ed305f8, 0x9c508944, 0x2d28428b, 0xf5791986, 0x0bea0854, 0xe87682a7, 0x8dcdd57b, 0x3c5f7f62, + 0xe2c34ed9, 0x88b943bd, 0x3c526f89, 0xe0a81f06, 0xee7ea8e1, 0x92cfbd53, 0x95106aa8, 0x8d90cd5b, 0x1ba728f1, + 0x9bc67c35, 0x2899f904, 0xa6c6e5e1, 0x226bc9c3, 0x65abe7b1, 0xdce035f6, 0xd2b61238, 0x02e6e2cf, 0x54c12fec, + 0xc161dbf5, 0x859f2828, 0x8c5b9e79, 0xa5df359d, 0xef3f1b55, 0xf8d268d0, 0x7d95c48a, 0xb830f34a, 0xccac243b, + 0x077e7db4, 0x7337f267, 0xffad979b, 0xcf02dbb1, 0x47df9fcd, 0x7463edc0, 0x1709b4a4, 0x133ae09e, 0x18814e26, + 0xda936a79, 0x1c8ebcf2, 0x62817a87, 0xcddbaab2, 0x9bda2a82, 0xbfb6cd6e, 0x9fa115e6, 0x962464f9, 0xeab20517, + 0x9afbcac0, 0x9a3a3d63, 0xfc4353c6, 0x146c20e4, 0x8c077d7d, 0xda9010c3, 0xd0c019d5, 0x90389132, 0xd302a79c, + 0x9cd86849, 0x7c1dcb97, 0xa3c7f285, 0xc08b956d, 0x071dae19, 0x98c219da, 0x8f390315, 0xb646c1fc, 0x868b6c62, + 0x55ac5af1, 0x7cf83310, 0xd20483db, 0x96d87f7b, 0x1fce67a7, 0x1c1a1047, 0xd88e0c66, 0xbd1c41a0, 0x52f19184, + 0xcc52d74c, 0xbaaad1b7, 0x3b6a80b9, 0x8d9e2df3, 0x430b51d0, 0xcc687781, 0xc5ca82e5, 0xa42c7fc6, 0xc2f54339, + 0x28290fc9, 0x8d336d6e, 0xb6d9870c, 0xe855c5e3, 0xb9833e86, 0xf2b92f79, 0xf6471c7a, 0x33d180c4, 0x0905c92e, + 0xb2717f66, 0x3ef96242, 0xe260069e, 0xc8dcaca2, 0x8d93c38a, 0x065984d1, 0x8d4b8cd2, 0x71796a14, 0xa0a27951, + 0xb75c9090, 0xdf711621, 0xe35f81fa, 0xd2b3e4fa, 0x3a0c98e3, 0x0137e6ee, 0x62b63d61, 0xc45ac451, 0x3e477607, + 0xf1aedf18, 0x71141b4b, 0x9a3423c2, 0x0d12214b, 0xf20b8ea7, 0x5c3acde1, 0x912d82b8, 0xcf25a406, 0xfed72e8f, + 0xdf34f620, 0x3bb37f5e, 0xc0d4c85f, 0x22da59d9, 0xed835c03, 0x2215e8ba, 0x4269e829, 0x734232b0, 0xd812550d, + 0xe5fdef06, 0x3adc21a2, 0x03061a83, 0xe0d6b05f, 0x6a50fa60, 0x44aebdca, 0x6a90c92e, 0xea62fbef, 0xa5a19b7e, + 0x53b661d2, 0x2b72b7d5, 0x33217196, 0x76836928, 0x7be63aa0, 0x0f32c773, 0xc868ba8c, 0x02f3820d, 0x8e597e57, + 0x3176f661, 0x9cf5da78, 0xacc37217, 0x1ee68b5c, 0xab67e331, 0xcaa6630b, 0xf0370aac, 0xe91fc5cb, 0x310772de, + 0x631a911c, 0xa8edcaf1, 0xbdfdca5b, 0xe1b183d0, 0x522cdb46, 0xba6f3bca, 0x43d88a3a, 0xae8c81ad, 0x9e747a46, + 0x8d7a6c19, 0x90b234be, 0x62d34c63, 0x46c5166a, 0x39e2f1f8, 0xef97420c, 0xa6ebb2dd, 0x9288a17c, 0xb72f690f, + 0x4e841141, 0xc1445f84, 0x4b9a5daf, 0x2fd649cc, 0x66cf10ec, 0x995d5f95, 0x8c432bca, 0xcb0f1e0f, 0x99f04a1b, + 0x5cf2a0d0, 0x6993d144, 0x661f1e8f, 0x00e76b6a, 0x5dc38c0f, 0x7a17eb6d, 0x1998abeb, 0xd390a265, 0x101fe557, + 0xc371a6f9, 0x1e709856, 0xffabf7fe, 0xa3a9973f, 0x9c2ff899, 0xd8fcbc58, 0x79f04a2c, 0x2d54529f, 0xd5bc8517, + 0x0aa0a55f, 0x81bc1318, 0xf4e78334, 0xdc842b6e, 0x481c2b2d, 0x3cbea61c, 0xc4f8a9e8, 0x7dcabc71, 0x2e0e55d9, + 0xe573c5b4, 0xe1497518, 0x0dc84dcc, 0xe4f638f5, 0x36daa4ec, 0x744f9ff2, 0x50399ac8, 0xe662c96b, 0x0d4277e6, + 0xb0aa3558, 0x946ac393, 0xe17956b9, 0xecae1d0c, 0x391bea36, 0xe4c13366, 0xe348641a, 0x8daca675, 0x8e332d8e, + 0xd4bd9f85, 0xeaa71224, 0x8a3900ff, 0x30c61fe0, 0x4895d297, 0x27affdca, 0xc20c585a, 0x4303af42, 0x927acc3b, + 0x67376595, 0xa084f3be, 0x012907c4, 0x6f9a6af7, 0xc6633020, 0x1e2bc30b, 0xa63a1196, 0x42fd5522, 0xae73ff91, + 0x8755dbef, 0x4d8ac1dd, 0xf597c119, 0x27dfc56a, 0x0fb9fd18, 0xbac68ef1, 0xd6afed34, 0xa1b3cd74, 0x6fb33ab0, + 0x5c72454b, 0x5b8405b7, 0xafbcd4ec, 0x3a2e13b5, 0xa62a1f85, 0x98364004, 0x42924ed2, 0x5d7408f3, 0x772904c1, + 0x6fbcd820, 0xc3e94414, 0x1bdef62e, 0x6b245e4d, 0xfd559621, 0x3bbbdfa5, 0xaa256463, 0x6647ad25, 0x32486223, + 0x2ca43110, 0x3c42f050, 0x47bbcf2c, 0xb57b58cf, 0xed935219, 0x938ce832, 0x6eceb9ed, 0xecab65fc, 0x97089e33, + 0xd969c2d0, 0x50a6e5c6, 0xb1a71397, 0x8dd5c98c, 0xd7e52947, 0xa11fb664, 0x99970615, 0xfd2bee29, 0xf7a61839, + 0x46499e62, 0xa4399d84, 0x0b381a1f, 0xba020db1, 0x3c785925, 0xfaf8c847, 0x541c0e12, 0x805d14e2, 0xe1850c30, + 0xe08f66bd, 0x8ce1bd61, 0x6cad310c, 0x682fcc5c, 0x085cc6f6, 0xaaae460b, 0x2c514000, 0x59d01f17, 0x2ac9a26c, + 0x5a55aa76, 0x4f4733ef, 0x47fef406, 0x41aee863, 0xe75f6460, 0xb5a56e9f, 0x8f4053cb, 0x9ad2c925, 0x98ac87b9, + 0xf0515544, 0x6a9dcc32, 0x7586c933, 0x78211f03, 0xd1a314f4, 0x502a63c1, 0xbec4c465, 0xba90179f, 0xada6268b, + 0x609c949c, 0x6c8a3427, 0xef0e1720, 0x41083b9b, 0x8f3da87a, 0x32154fd2, 0x0f1b1377, 0xce945662, 0x1a5406ef, + 0xcc26381f, 0x174371fe, 0x3d3dd5d6, 0x53ca96e9, 0xc5c50797, 0xd3b387f3, 0xe3d743dc, 0xce7ceb6d, 0x08c27668, + 0x04879d01, 0x460ae430, 0xb8cba93f, 0x3ec26cf3, 0x93c36450, 0x3e72f2c6, 0x71d57414, 0x21997e1b, 0xa08e2d17, + 0xcb4a439e, 0x3c705d2d, 0x3decb54a, 0x0374c52f, 0xbd2843d0, 0x2f176563, 0xce9069c2, 0x38399d82, 0x322adbd6, + 0x69d4b869, 0x29e62ca4, 0x7e7546f2, 0x55d9e41a, 0x9a19b073, 0x9395d32d, 0xaa711c2d, 0xfeee413e, 0xeaa8837f, + 0xa2a5f124, 0x76f65a42, 0x8f408ecf, 0x4ee995a0, 0xd50e0c2b, 0xb5d1912c, 0xa7546e5b, 0x68a35392, 0x590892ce, + 0xe7366e53, 0x8bbe0891, 0x98ef078d, 0x13d0d191, 0x65beb278, 0xf3670a91, 0x2c79024e, 0x136d4540, 0xf8245491, + 0xb948f4ba, 0x30f899e9, 0x5728c3e7, 0x7ef7d995, 0x30f77053, 0x0558febc, 0x242508fe, 0x99cf48fd, 0x66eaa7c7, + 0xedfa9de6, 0x7e0f5c18, 0x5d771121, 0xf5b82db7, 0xa0e429d7, 0x70cd4549, 0x0f3cbef2, 0x69bf8f0d, 0xf47dbf57, + 0x0ca3b928, 0xdc560291, 0xf93603c0, 0x93c6efc3, 0xa160327b, 0x500a3212, 0xca026269, 0x2baf86d7, 0x57373a10, + 0x43347c1a, 0xcc8f56ff, 0xf25f5b6b, 0x8593adae, 0x66dc339d, 0xc774fb14, 0xe5adced6, 0x287bda99, 0x0daaca38, + 0xe68cabe0, 0x379669af, 0x7d7e3878, 0x644a6fd8, 0x30d4c6d3, 0x0330d2a7, 0x60d6389c, 0xabaa502f, 0xa9a9a9e6, + 0x332d8753, 0x9d1eca94, 0xae9193f4, 0xde8cb580, 0x8908e402, 0xe51ffb64, 0x999c63b3, 0xfd617497, 0x05d4adb8, + 0xf9e9031f, 0x0f96d9b1, 0x1efedd55, 0x3539e07d, 0x02ca7918, 0x70bf53af, 0x55c1ea4a, 0xebbd6c23, 0xb0e7c56c, + 0x02407354, 0xd59fae07, 0x9a0e7707, 0x9faee3a4, 0xa9a04740, 0x398df47b, 0x458b95d6, 0xba7d39c7, 0x69b21e3d, + 0x7bd6b6a1, 0xba9ed5c1, 0x3de36cf2, 0x270da498, 0x362c08fc, 0x5e93cb4b, 0x1b874657, 0x54af067d, 0x80cf8b84, + 0x07b3f079, 0x8b78f266, 0x8060fb46, 0xd7138fc1, 0x3dcb1225, 0x74276fe1, 0x35c7ee86, 0x48a58acf, 0x9d4b83ce, + 0x95a15bfd, 0x0d70463d, 0x8daf6d69, 0xaccf4cb0, 0xac6524d4, 0xf01d5696, 0xfef5ad3b, 0x67b3f590, 0x527ca541, + 0xd7154d88, 0xb317fda7, 0x144e5da6, 0xeb9d8888, 0x0b87d22d, 0xa5a25056, 0x550f41e1, 0x13f14b96, 0xdadfd378, + 0xb461c309, 0xce54ef09, 0x628bdf09, 0x1a9fce69, 0x0e31aeb2, 0xa8e6ddd5, 0x9dffea7b, 0x67f2503d, 0xf0998fd3, + 0x53334557, 0x766875ad, 0xf6c524f3, 0x100418c6, 0x80c9fec8, 0xb89acab6, 0x6dd3b788, 0x63e733c5, 0x3873c22f, + 0xa9e3453a, 0x2593fb95, 0x35434968, 0x078da9a4, 0x777320c1, 0xa8f666d8, 0x89cdf324, 0xa0ff45e0, 0x5f2ff9cf, + 0x1669d4e0, 0xaac4d8f8, 0xf9c4427d, 0x925bb311, 0xd125e6db, 0x61077e1b, 0xce1a8041, 0xf42b2418, 0x19819557, + 0x67ca9f2e, 0xdc7efcee, 0x5fafee2b, 0x30e38299, 0x68b11bc4, 0xc87c629a, 0x7cfa493d, 0x2f92c9b8, 0x41874919, + 0x3c5daf5a, 0x321ae89e, 0x35ffd898, 0x5737a9d1, 0xb7e5a503, 0x584a71f3, 0x00f5efe4, 0x7a6856c5, 0x243a8b26, + 0x7e38efe7, 0x8f4cd2c8, 0x5d5c4dc0, 0x49eb0096, 0x717d2e06, 0x0f94759c, 0xc76b5fcb, 0x5e87c011, 0x65b39b41, + 0xbbe46cee, 0x10e6bd8e, 0x36cc3c7c, 0x0edf2409, 0xdfc45c97, 0x7f864545, 0x83531e05, 0x9dcda3d5, 0xfd139fb9, + 0xdba826de, 0xff22c1a3, 0x19037270, 0x3992d5d2, 0x88d0f8bf, 0xdb122b56, 0x0b3dfbfa, 0xc4f12a82, 0x6ab6213d, + 0xdcc4a566, 0x53211da4, 0x8d77d985, 0xd22fab5e, 0x0f795422, 0x3b23a060, 0xebb827f8, 0xb7741643, 0x69b44698, + 0x61ac5fa1, 0x63fc078f, 0xcda4ef6e, 0x6e36ec63, 0x5d978c8c, 0xc5b4aebf, 0xc978b1b0, 0x5b324351, 0x77c96f8e, + 0x890f275e, 0x3bfc5cd8, 0xf34b64df, 0x79e4e6df, 0xc515c0e6, 0xd3f87c5b, 0xadbd2a2c, 0xfca4f093, 0xba468fd8, + 0x793049f2, 0x0b2b3f36, 0x55e5064a, 0x5e6d414e, 0x571258e9, 0x2e8c19ba, 0xeccae93f, 0x70c7da5a, 0x323c636e, + 0xa392dc4c, 0xe1502de0, 0xa659424e, 0x075f3a8c, 0x079bfbab, 0xd139f9ee, 0xc9a3f3a4, 0x3ef73e49, 0x65f8882a, + 0x5c11b2e9, 0xd3c4a12c, 0x7182b037, 0xa9b045db, 0xf3d41e88, 0xfd646014, 0xce405494, 0x14a1c02c, 0x57f9706e, + 0xfe4cdd78, 0xdb1a56df, 0x8ba2dad3, 0xf87a02c3, 0xf1602e0d, 0xa6da06bf, 0x68b73af0, 0x07edfea1, 0x54ac362e, + 0x0b7fa743, 0x201bc12f, 0xa0ef68fe, 0xffd595fb, 0xc39a7b80, 0xe92dc372, 0xca2f3014, 0xce25d36a, 0x3bee1fad, + 0x433b899e, 0xbd03c34c, 0xaa20d8b8, 0xfa3cc39a, 0xaa186323, 0x045e2540, 0x8d51a03c, 0x89f1ebed, 0x926f12dc, + 0x6af80481, 0x2e5d4106, 0xda3cd6ac, 0x35aa0c22, 0xa2a9cd33, 0xbfb9f59d, 0xe5be7a26, 0xa89f9b56, 0xdb7d24c2, + 0x08e72259, 0xb8b587b4, 0x009952f1, 0x0c84cc70, 0x7543c48f, 0x005db3ac, 0x05bc0456, 0x5936869e, 0x6480184c, + 0x4294cffd, 0x6a13da09, 0xd0eac4a4, 0x472019c0, 0x1494d5c2, 0x6dfac15d, 0x77fb0907, 0x33ce55bf, 0x71bacd0d, + 0xcefd40ee, 0x5ae526fa, 0x7e41274c, 0x4bc718a7, 0x081247a9, 0xe6d4c22b, 0xa71410ec, 0x58b5060b, 0xc634d6ec, + 0x3415cdcf, 0x03d92ee6, 0xf8232ba0, 0xd7103111, 0x64521d81, 0xf211fe73, 0x59eddb7f, 0xba6c9a2b, 0x96745125, + 0x77f0e1e8, 0xea9511bd, 0x92cc0877, 0x81b9f02b, 0xc773ce5a, 0xde35c3ca, 0x312875c3, 0x4a644e84, 0x252a2ec9, + 0x8c68f47b, 0x01458907, 0xece5b212, 0x734c0e70, 0x58d790dd, 0xfee2af0c, 0xb83b5f7f, 0x5686bc3b, 0xa7cc4bc7, + 0xbb1d7b0a, 0x958443d6, 0x6640f243, 0x62199cff, 0x85675fba, 0xb7f57540, 0x71e34984, 0x0070d744, 0xc02eddd6, + 0x3801294e, 0x56f82390, 0xcf79ccce, 0xba804b2c, 0x67d04ffa, 0x4d0803ac, 0xc242923b, 0xd5b9ce87, 0x189f92ff, + 0xea7c501e, 0xe9424eac, 0x032aac5a, 0xf7e28b79, 0x2bcf9320, 0x41c117d3, 0xc9c5af5b, 0x611e333c, 0x58577ce9, + 0xed7ffd48, 0x65932ee0, 0xea38375b, 0xb62524cb, 0xa25b2a9e, 0xbcbcb236, 0x2829739f, 0xa726279b, 0x3a2a7cbb, + 0xf1f88c4a, 0x56a64009, 0x7ff05aad, 0xc5abfdbf, 0xf3077f31, 0x897a4f06, 0xe92cb0b6, 0x42e9c786, 0x87e24ce9, + 0xb5543f1d, 0xbd252e8e, 0xb73517e3, 0x27b5dda4, 0xd117e2c8, 0x97a5c47a, 0xf7067bb8, 0x5aa55e69, 0xa7a78e9b, + 0x79be586b, 0x44eb3feb, 0xf3d241d5, 0x1c8d504a, 0x01517b07, 0xfe7bb97d, 0xf52d07de, 0x05bda0c8, 0xbd598dd4, + 0xf03f8006, 0x8c190fc3, 0x008f5d78, 0x2ec70ff0, 0x19654336, 0x61be7850, 0xe2468138, 0xba64722f, 0x8d2b10c8, + 0xe350a236, 0x283bffc5, 0x4f1aed79, 0x5a1beab9, 0x30befbbd, 0x76f3e0a9, 0xd61534d7, 0xcbe36646, 0xb18133de, + 0x98f9c740, 0x430faf4a, 0xfbb70b73, 0x22e48a81, 0x43e6b117, 0x25c243ec, 0x9bbcc190, 0x301a5d67, 0x31d9b732, + 0x01085dd0, 0xca552431, 0xeb4ecf90, 0xef6d2902, 0x63a0950c, 0x6ffdda48, 0x7ae9ba90, 0xa2cd32dd, 0x145cd7cf, + 0xc3890c9a, 0x90bce844, 0xd94e2c3b, 0x533b0551, 0x9884ca03, 0x9e13bff7, 0xc6714b8b, 0x27ed409a, 0x79525871, + 0x42fbdac1, 0xafeaa2c7, 0xe18b6932, 0x4f7d1848, 0x43b37157, 0x5d8af7b2, 0x12540d78, 0x42580dbb, 0x241fd38a, + 0xa7eb52be, 0x0ea95b6d, 0x180a1d48, 0xf1f71cd6, 0xa39eae8e, 0x3da412be, 0x399453f7, 0x7da7769c, 0x4fc32641, + 0xd0b72ece, 0x2a979f87, 0x183878fa, 0x9346bd51, 0x73c836cb, 0xa2817a46, 0xcb380df6, 0x6b37c4c4, 0x2c1e645d, + 0xd800a51f, 0xbabad700, 0xd0c7ef72, 0xba62c9d9, 0xb4def6f9, 0x596bbb6d, 0xeb95046a, 0x330ddf2a, 0x44cff86e, + 0x2b8a527f, 0x34414075, 0xc5770753, 0x04bf64ac, 0x27295346, 0xa493d709, 0x17cc179a, 0x9d25b924, 0x9862b7f3, + 0x503449e3, 0xe9363f9a, 0x44ca2b63, 0xc7578ccf, 0x64a27ac5, 0x84bd8fc5, 0x7d44f1cf, 0xe15e48fd, 0xc5b36a9e, + 0x4875d366, 0xb1633ead, 0x8111fc14, 0x7aacd415, 0x74b9af32, 0x1d011f48, 0x829e131d, 0xcb782946, 0xb71876b6, + 0x0b3659ce, 0xc59140db, 0x5b746547, 0xe4b6b46d, 0x01951b9f, 0xde2c23e4, 0xf6cb80fa, 0x424e7298, 0x66fee481, + 0x20cd804e, 0x86f9b360, 0x14099e53, 0x5081dc5b, 0x70b0bd0d, 0x5c1401c7, 0x6dc8868a, 0xd14e87ec, 0x6127347e, + 0xfe3bc4d8, 0x6bef8539, 0x7c3194c3, 0x223c894f, 0x6714f56a, 0x96ec4886, 0xc5acd0c0, 0xb2c96584, 0x343d7fa6, + 0x6ba99556, 0xcbb48bf2, 0xfc2c3485, 0x80800778, 0xeba7b9d3, 0x3a30afde, 0x465fa90e, 0x6714944a, 0x76baacdf, + 0x02db6595, 0x2fe3547f, 0x3729e399, 0x74ad8d35, 0xe3a4a4e0, 0xf7bd8637, 0x94186302, 0xcef60cd1, 0xd8b7726e, + 0xfad26c8f, 0x3902e352, 0x8ea8871e, 0xc36025cb, 0xf184381e, 0x52dc7ce1, 0xa38666f1, 0x505d087e, 0x603df3ca, + 0x2bdb04e7, 0x8b893469, 0xbe782803, 0x932ebe4b, 0x36522dab, 0xc4aa2ec9, 0x52b8a65d, 0x4c30f589, 0xac7a822b, + 0x40f2088e, 0x1cb45840, 0xe5ca6ceb, 0xf48505eb, 0x945a3b66, 0x3f1d898a, 0xa04c1ed2, 0xc0273a53, 0x30412cb8, + 0x3d859e0f, 0xc226c7b0, 0x4311c779, 0xc33fc307, 0x6aaca797, 0x2df26dfc, 0xb4f11d81, 0xd350dab7, 0x6557c420, + 0x408cf507, 0x5a7a947b, 0x25c74896, 0x7c1df36e, 0x5984d0ee, 0xe536f4f4, 0x13eb0805, 0xa3a615e4, 0xdb411d92, + 0x8c4f5240, 0xb3fb0835, 0x81889744, 0x8b9d9def, 0xbf97acf7, 0xf493f3bd, 0xeb436ad7, 0x52e2d93f, 0x6d5dc7d2, + 0xc1d3136b, 0x3e239a15, 0x82b8c9f2, 0xee96fbd6, 0xc8a28b6a, 0x8ae80e6a, 0x481440ad, 0xa72e2ce6, 0x3c9b9a42, + 0xaa4e92a0, 0x7f5881d7, 0x59921f42, 0x88054d10, 0x2d22f63a, 0x6cf2fc6e, 0x3f289a63, 0x23e3c778, 0xa55309b9, + 0x7e1e80b7, 0xc14f8a9d, 0x6b93b377, 0x42102ef0, 0xe11ab68a, 0x4f5a44bc, 0xc0d303d2, 0x32c34126, 0x82e6f213, + 0x6ea3864a, 0x595c7a93, 0x9e6bed13, 0x87a7edc6, 0xa1a4c120, 0xcbf5e0f6, 0x14c6200d, 0x1bc1adec, 0xe3892e40, + 0x1e33ef6d, 0xe0b68e6f, 0x7d59c3a5, 0x42427f62, 0xa008c84e, 0x7e98291b, 0x4af91dc3, 0x73646ce8, 0x5eba2140, + 0xa9492bae, 0x8c977ffd, 0x45d2675f, 0x557bd37a, 0x2fcef0e9, 0xfb2a6782, 0x46ab030f, 0x609e9951, 0xc94ab1ec, + 0x303dc8d2, 0x02b26212, 0x68668e2c, 0xfadccb3d, 0xe697ec13, 0x587f1601, 0xdf797b6d, 0xf2f4b47e, 0xeb6f86f1, + 0xc8efaf00, 0xcb223019, 0xb2aa9844, 0xf715c5aa, 0x72370ce1, 0xbb739aa5, 0x590dcfd0, 0xd6ceb05f, 0xc35a02aa, + 0x60b742cc, 0xd47bb27d, 0x1dfac348, 0x68260cad, 0x38475e6f, 0xfd848892, 0x7d77d6d9, 0xe47d6217, 0x497765c3, + 0xdd9626ca, 0x98db9723, 0xe0a7bc61, 0x0a85edd3, 0xaf1cf078, 0xf583fdd1, 0x82a2332a, 0xc4cba90a, 0xcd39214c, + 0x725e7acb, 0xeb1f3e26, 0x8c4cf67d, 0x928b6b63, 0xd598001b, 0xc3f0a119, 0x58ad5da6, 0x75f463da, 0x588dfcee, + 0x295d78a2, 0xd7a2a6b5, 0x05f5a03c, 0xf79886a0, 0x76afdd47, 0x00a00138, 0xfe1774f5, 0xbc2fea14, 0x71480902, + 0x4f4fa2cb, 0x37983d13, 0x7f04fb43, 0x6f39745d, 0x23ee578b, 0x07dd1931, 0x64c5589d, 0xfeff2b8f, 0x09216836, + 0x420adb24, 0x0035d31e, 0x960df348, 0xf5f735ca, 0x4b12a919, 0xcd0040b7, 0xbdec818e, 0x2a271163, 0x5625fbb4, + 0xfedf55ca, 0x02110730, 0x58b8ea9b, 0x3bacbdc8, 0x1b16fb3a, 0x1857ce56, 0xf25f967f, 0x091accc4, 0xcd07de20, + 0x1a7ea4de, 0x609269bb, 0x7860286a, 0x6fb0e4e6, 0x7bbb4ebe, 0xdcd94aed, 0x88a9d6e4, 0x492127e8, 0x3117c592, + 0x8d0eba94, 0x46c6b2ae, 0x39510967, 0x9007f1e7, 0xb8a62f85, 0x01f438d6, 0x8090c0d2, 0x2bc62709, 0xbef651be, + 0x286a7d0f, 0xc09430b2, 0x8accaf11, 0xa9c37371, 0xb5949e5f, 0x0fcc3673, 0xc9380994, 0x0b4fbefb, 0x7d94b97f, + 0x7de2a330, 0xbf03ad13, 0xd74013a1, 0xc4f3b335, 0x1d52840d, 0x078f85fe, 0xa31e39ea, 0x5f3e907c, 0x60c8d9a7, + 0x1e277a26, 0x92602c70, 0x0b426392, 0x74d41e5d, 0x3627b418, 0x328d13b3, 0xb8432ed1, 0xe2d0806b, 0xeddaed1e, + 0x46a02c71, 0x29a321c5, 0x3cd7d6d3, 0x85eb09c9, 0x9a551c03, 0xc604c8a3, 0x6d7a8bb9, 0x83cf4754, 0x486339a8, + 0xb93b2323, 0xd98c5613, 0x9acbc531, 0xe66667bf, 0xbf54e54a, 0xdd75d492, 0x961e3775, 0xad9eafea, 0xd75dcd60, + 0xdd3f7db5, 0xf9a3b21b, 0xdec730b6, 0x0851f2d7, 0xd2e4fef7, 0x658504b5, 0xa6893bbf, 0x3bf3a5f5, 0xdf6e28fe, + 0xe16793b8, 0xe0bf5fa7, 0x57c8051c, 0xdc8c315f, 0x80d45439, 0x08a7a04f, 0x0122c8f4, 0xadde44af, 0x9aca2f84, + 0xa96af956, 0xf66aaa98, 0x87c82e86, 0xdc69b199, 0x5cee8cb5, 0xb2edb201, 0xff54fc91, 0xf3368031, 0xc0b39823, + 0x3c2675bd, 0xcf534c28, 0x44cdb9d6, 0xd892ea9b, 0x492724d7, 0x651ea225, 0xf9f72c77, 0x1daa5e90, 0x715408f7, + 0x2a69da36, 0x4a59619b, 0x01dcb4e0, 0x0601e096, 0x3488e54b, 0x75ee353d, 0x82b7ae78, 0xc47d12ee, 0x529d06f8, + 0x92d07f88, 0x7f471b6e, 0x3bbeab7a, 0x39807db2, 0x94824e9d, 0xc9e94219, 0x7a3168a8, 0xab4313bc, 0x9afb8e29, + 0x2e95885e, 0x5d9daf0b, 0x76e5018c, 0x19d96bd7, 0xf751a9af, 0x38f5a1f1, 0x85631108, 0x02b0ae01, 0x244a913a, + 0x4dc6c8d3, 0xaa8eef4f, 0xb44c077f, 0x824a1b79, 0xe35888ac, 0x7d86534d, 0xe52cf404, 0x6fdd7abe, 0xbee2d249, + 0x76299fe3, 0x35e3a244, 0x2383a89f, 0x46c4aff1, 0x09cad952, 0xe72dede0, 0x67e924d1, 0x223eb1be, 0x65d754d4, + 0xb0234f76, 0xe8a649d1, 0x55a8af30, 0xd2426b91, 0x8f97117d, 0x3d0173ef, 0xd84e4dc4, 0xb1b3dd05, 0x6fb4e710, + 0xad02ba62, 0x3ca1b057, 0x7018bbb3, 0xcf40c44d, 0xcbfb4410, 0x3ca5bbb5, 0xeee5651f, 0x0e161659, 0x0090cc4a, + 0xd351072f, 0xddad1cb8, 0xe8601d2e, 0xc05aa289, 0x5922ff92, 0xa6655b9b, 0x5fe4a1cd, 0x4aaeec06, 0x3131b354, + 0x41ae8051, 0x5e3eebda, 0x61bc03fc, 0xd42b009b, 0x6dde50c1, 0x678dd67b, 0x501627a0, 0x84921239, 0xd0d781d4, + 0x3ab98a50, 0xf29392a7, 0x5971cc93, 0xc6b5b8a4, 0xfb185003, 0x5b323513, 0x03196ec7, 0x45623f7d, 0x2b37ab87, + 0x2debf459, 0x2977860b, 0x46cbdb58, 0x5ce8cc8c, 0xaec790c8, 0x736f312e, 0x0a63aecf, 0x9e33da67, 0x3b9ff724, + 0x6f915be4, 0xcb734fce, 0xf1543239, 0xfd18d1b9, 0xf7162e81, 0xb3a90c76, 0xad917a9e, 0x1562501e, 0x5a9f9c5d, + 0x3104f1b7, 0x019cddbb, 0x8c287d17, 0xad617f99, 0xfa88b38e, 0x8b6c609d, 0x56c40754, 0xfa10401e, 0x85a69a6c, + 0x60392124, 0xc02ef463, 0x78c2416c, 0xa73f384c, 0x58dc6105, 0xf26a22d2, 0xb05b6619, 0x15cd1ff9, 0x03096d0e, + 0x3195c0ce, 0x89a0d56a, 0x4c4d269b, 0xdfc82745, 0x918b8495, 0xecc84bbe, 0x905d547c, 0xa2ed6362, 0xc2cee5ed, + 0x30216b6d, 0xd18e5124, 0xf4c6ab8b, 0xa9a327a5, 0xaca23b9e, 0x29fbd7ee, 0x175764da, 0x86efc26c, 0x825de26c, + 0x1c4fe78d, 0x283ce248, 0x4ac10c0c, 0x50bbf3fb, 0x029f6275, 0xe4fa99bf, 0x03e447f9, 0xb58fe8c4, 0xd3ff4b84, + 0x62ceb07a, 0x154821ec, 0x57acf840, 0x820ebc15, 0xdc3634b3, 0x5ded71c6, 0x50b7c917, 0xf45c8e44, 0xfa3d34f6, + 0xac3f72ec, 0x8cddaeba, 0x9fd76792, 0xe8f631cf, 0xec652ab1, 0x4f77b310, 0x8731f203, 0x9b1ca4d4, 0x66bc06b6, + 0xd7bf2a9f, 0xe85e9a7a, 0x3c4b23d9, 0x500c633c, 0xae4c3699, 0xcf603f66, 0x5516d253, 0xce9cb03d, 0x4e4e94ad, + 0x9a6c97c8, 0xf64195a2, 0x4654bfaa, 0xfafcb9b6, 0x19d8950e, 0x5b1e76db, 0xbd65ed3c, 0x9a7c9495, 0x6ae08520, + 0xc5e76655, 0xb8283a1b, 0xa99506f4, 0x9bad69ac, 0x88bd2344, 0xec8462d7, 0x2138c82b, 0xe481c196, 0xfd3f41cf, + 0xe94bae66, 0x5bcb5b13, 0x2898f120, 0x53bfc982, 0x08f986e4, 0xae207148, 0xc22bfc08, 0x8a5020ce, 0x9b58ea3e, + 0x6f72422e, 0xbbe61f89, 0x858581f6, 0xc7b1c6e9, 0x469fb2a8, 0xb4610534, 0x9d58f6fe, 0x26bf4649, 0xf315de28, + 0xcec0f753, 0xeab9d8cb, 0x080fef72, 0x3aeaa30b, 0x66d795c5, 0x4bfdeef1, 0xfc91af88, 0x39416dfd, 0x5bbf1404, + 0x42a017df, 0x68ed4aab, 0xe62ab313, 0x9e9225ef, 0x43f8c595, 0x23287a84, 0xa2eb5953, 0xb8127b33, 0xe77a570a, + 0xa44386f7, 0x29d11f1e, 0x9c790194, 0x3b591abd, 0xca34f643, 0x6d19bba4, 0x375d77f1, 0x0b251032, 0x1b9cad58, + 0x07f75a65, 0xe350bde0, 0x330d51db, 0x9ac02a7a, 0x93850dc4, 0x1c4e38c4, 0x4df16ab4, 0x4d0539b4, 0xbcd073a7, + 0xdedb7462, 0x9a1735f2, 0x3a270ddf, 0x6e84f448, 0xd43ff76b, 0x6c223839, 0xc0146552, 0xc26d2da5, 0x391cd6b5, + 0x366b271f, 0x5c7f49fa, 0x1535d991, 0x7b99ed3f, 0x1268bf4a, 0x8feb08f2, 0xb3147781, 0x73eef8ec, 0x9a3baa11, + 0x471b3d3e, 0x28e15300, 0x2cd29643, 0x7869b033, 0x8ee2e423, 0xeba17e0d, 0x1147e107, 0x10cd31dd, 0xf62b8269, + 0x770ed913, 0x37c9e6bd, 0x71d5a928, 0x534e3ef1, 0xac6f4f8e, 0x12e4986c, 0x0e980054, 0xd82a7b68, 0xa8b65319, + 0x0d789d69, 0x04ee8210, 0x5240cec3, 0x44cdf9eb, 0x3e9be0fc, 0x5b4a29f9, 0x63feb3f8, 0x9cfb2a6d, 0x8511a2af, + 0xa70f0dda, 0x3874ca42, 0x8c1e33ec, 0x5c198862, 0x5d3d2126, 0xca76ab0f, 0x4bcf0901, 0x34634fed, 0x5f2f50d0, + 0x0a62a4c8, 0xfa3f8f9a, 0x6838c4fa, 0x45bcf291, 0x33420971, 0x3b19032f, 0x5a78ab1b, 0x8a2a2d9c, 0xf6e42092, + 0xe932953d, 0x21440e30, 0xc80d9ac9, 0xf4e21c8b, 0x2e304404, 0xb0d8a528, 0x502ec2e0, 0xae02393c, 0x1a7f6fd3, + 0x284f7eae, 0x472e20b4, 0x566fd29b, 0x266e4ffb, 0x094113e4, 0xf89aa4fb, 0x4831b50b, 0xb10d2943, 0xdaaef780, + 0xbc6bddac, 0xb10a66e1, 0x1b4323d0, 0x4709e2e1, 0xb1c94599, 0x7602fe88, 0x6828bd9f, 0x9fe233f5, 0xe500a509, + 0xa3d5179b, 0x6781be15, 0x198b1ac4, 0xbb8d607b, 0x59c3b2c9, 0x640974e5, 0x1bec4641, 0x57bfbe8a, 0xb8ee6496, + 0xa70dc9fd, 0x2d2ef7fe, 0xc8f33ebb, 0x7354232d, 0xb499006a, 0x4753f8cf, 0xbf47144a, 0x15b0f955, 0x08c4d36b, + 0x8f24c18d, 0x86c613b7, 0xee941bc9, 0xe5a4e391, 0x4c14ca0e, 0x5760ddf4, 0xb79cf32b, 0xd3815126, 0xe07e1924, + 0xd7d8b2f7, 0xa607b6b8, 0x8644e7bc, 0xa2df704e, 0x12ef3958, 0xc6fdab8b, 0xeae25855, 0xa19cd609, 0x514b1c09, + 0x51f9fd39, 0xbc71de26, 0xc7be4c41, 0x99a05417, 0xbe634f4a, 0x615edc1b, 0x89f5df75, 0xd933cc15, 0xeda34c06, + 0xf83f96b8, 0x3a28e253, 0xd4d65669, 0x599587c6, 0xdb59fc44, 0xf610a652, 0x5ca01eba, 0x12c68171, 0x504165ce, + 0x1034ca59, 0x69a94ef8, 0xe810b073, 0x3d832886, 0x516e34aa, 0xd729fa0a, 0xe22f63aa, 0xae8bcb90, 0xf4965962, + 0x1750148f, 0x649c4ff7, 0x4417a2ae, 0x574d8c5d, 0xee6368e4, 0x251f2f44, 0x77e9bb1d, 0x4801f2b1, 0x077c927c, + 0x77bda395, 0xb08a6b4c, 0x6c52e0ca, 0x60e769d9, 0xf619855e, 0x7c7652a6, 0xc47a2d6e, 0xf04f973a, 0x9f572aad, + 0xedc49347, 0x8eeea5fa, 0xcfc7b7d5, 0x18d29c3d, 0xfdfdf3c9, 0xd209381c, 0xddfc4ee5, 0x1585dfe1, 0x2859f52c, + 0xd70869fd, 0xd6d6a175, 0xdfe4dec4, 0x0a21b1b5, 0xcfae9b8d, 0x921eb7ad, 0xc9020997, 0x73b44e46, 0xa3bce24a, + 0x3bbbb9b8, 0x4ea918e2, 0x16288893, 0xec331eaa, 0x3ddeea11, 0x6b22a45a, 0x178f2200, 0x543fbbbb, 0x90c223ba, + 0xc167a255, 0x968b52c7, 0x237b45f4, 0x39c9679a, 0x12d07be7, 0xcff443f2, 0x3de08c70, 0xf9eb46bf, 0xecd3696f, + 0xccdd0312, 0x510fd99c, 0x7b075ce5, 0xf2d5972c, 0x13b1a565, 0x647f4407, 0x3dda1c52, 0x0db195b0, 0x2b2f8eff, + 0xfa137377, 0x6caedd85, 0x8fe097e1, 0x10ac8564, 0x72981d2a, 0x08801390, 0x0e3f1ef3, 0x7108f544, 0x6633d426, + 0xc4bd651b, 0x7d06da4d, 0xbc1d9a63, 0x90a067d5, 0x9a7df559, 0x1d0a11b7, 0x1e5da7f3, 0x29fc2c9b, 0xaf70f7dc, + 0xe41b41fd, 0xab9624c3, 0x5d75b435, 0x002621ae, 0x7a9b9919, 0xa33b4861, 0x27d3f2cc, 0x9dd5a907, 0x065640c3, + 0x07086a7c, 0x6ad3c7e8, 0xda61d0fd, 0x997065cc, 0x7ef2b121, 0xeb787574, 0x4d335fd6, 0x32924acd, 0x7a9b34e4, + 0xb141aab8, 0x142c608c, 0x6da52db7, 0x38f48141, 0x3e8c6aa0, 0xb8096c4f, 0x7b861d61, 0xa60fd6b3, 0xc64e4612, + 0x0df0efb5, 0x82a2098c, 0xf58f70cf, 0x090f9316, 0x7adc0c57, 0x89c80d7a, 0x98379e82, 0x07627449, 0xba249bde, + 0xe4071277, 0x335b6e37, 0x10197c05, 0x9806fcf3, 0xd419c50c, 0xa924d154, 0x686a0968, 0x1d4b2dce, 0x5f21ba32, + 0x22a288ce, 0xd46494a9, 0xcacd96f7, 0xd4fb0ef8, 0xb52990ff, 0x4328b4a4, 0xd53e43d5, 0xe17e01ab, 0x22c5f729, + 0xee0e806e, 0xaea91ce4, 0xc9368cf1, 0x3298a441, 0xada607d5, 0x0ce64ea4, 0xb039ee8a, 0xc624916d, 0xce3cb963, + 0x6a21afd7, 0x8bf96410, 0x4618d43b, 0x7def1c9e, 0xcbec3e7e, 0x2fd1e025, 0x87d93d6b, 0x0ff5f5d8, 0x7c21d0d1, + 0xf5ec1657, 0xf4c2190b, 0x2eb3b608, 0x08745f07, 0x6ebf3462, 0xe421705c, 0xe86372f3, 0x49adf1da, 0x5aecc162, + 0x671d0028, 0x1ebbda45, 0xd6d010cc, 0xf5395b97, 0x21df6419, 0x2d4b3d3a, 0x6ad03908, 0x81931219, 0xff65858c, + 0x8e78697d, 0xa9ff5ca6, 0xf2e609c5, 0xccf21be7, 0x83966dfd, 0x8a3cc868, 0x39233e2a, 0xc8902098, 0x69c98dca, + 0xe3ef8e7c, 0xa163b614, 0x14d2a62a, 0xc2c5c281, 0x6cc9b9d8, 0x1062064c, 0x6040cfcc, 0xf92fc8f3, 0xb802811e, + 0xdf2af1db, 0xe8e6f840, 0x1f4ca9cf, 0x6ba56df1, 0xd0ca8462, 0xe37139a6, 0x2fa37f0e, 0x522fb55f, 0xf73269ef, + 0x0a3d8ca8, 0xf16a0a01, 0x1802107c, 0xb4439056, 0x4b0a451d, 0x89ea2c4c, 0xa129618b, 0xceebbdb8, 0x4538462f, + 0x0f0245f3, 0xba48bd00, 0xc35b8aec, 0x87486b26, 0x046413a7, 0x82f0e45f, 0x030c82f6, 0xc8863f3b, 0x5e477d1d, + 0x9c146856, 0x13e2206d, 0x13bf11d4, 0x2be3908f, 0x7a4a1945, 0x1ac7ca96, 0x0c83535e, 0x7390f976, 0x2f2daefb, + 0xf0d7a92d, 0x9fb3f3c2, 0xe1c6de32, 0x834e151b, 0x69ae51f8, 0x4ced1563, 0xec6fb8a2, 0xff68a14c, 0xdc0bf8fb, + 0x01e1bd7b, 0xbc687394, 0x40c2f545, 0xe8af3002, 0xd37a3c35, 0xe7ab8da4, 0xd2096256, 0x838d60da, 0x5e44811f, + 0xe67a6484, 0x272eba23, 0x34568289, 0xe665c623, 0x28e32ebb, 0x380e31e2, 0xec66fa5f, 0x9326ce9d, 0x5d566645, + 0xe60c3eb5, 0x521e1756, 0x5480e735, 0x07b7f520, 0x344470f7, 0xbad01966, 0x435288a1, 0x1b8e3bd3, 0x840bfffc, + 0x06e4073f, 0x5ab23cde, 0xdb0482be, 0xf53e30d1, 0x51d5640e, 0xb5572dcb, 0xad565df8, 0xe60e26c9, 0x03368102, + 0x239bd1df, 0x80cff272, 0x9640352c, 0xa13d9d05, 0xf2e59975, 0x6eb89c1a, 0x081fc914, 0x5fd76af5, 0xb420cc67, + 0xd3941e78, 0x1ad61f76, 0x8fc02d0e, 0xece7be6e, 0x7e13393c, 0xeea6da04, 0xa4a3d76e, 0x3648ad17, 0x8aef288e, + 0xa1ce51e4, 0x64a93a93, 0xfd2f5089, 0x599bac3a, 0x8d3a0170, 0xf8b3cd30, 0x89ab7843, 0x1d3e5db8, 0x06cbb16a, + 0xd28952d2, 0xca284893, 0x8fd1a1e1, 0xecc8aa4d, 0x465de563, 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, + 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, + 0x9e794663, 0xecda4063, 0x4f3c615e, 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, + 0x5bee2390, 0x5bb0ac2d, 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, + 0xcbc03381, 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, 0x5e365ae5, + 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, 0x1da22f3d, 0xbde1988d, + 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, 0xc654b0f4, 0xb3c61edb, 0x34380acf, + 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, + 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, + 0x6ca12b76, 0xca9e521a, 0x3de6ed99, 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, + 0xe3860943, 0xf1f3f4e7, 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, + 0x401dd9b2, 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, 0x9c7c7cab, + 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, 0x68fd2cdb, 0x5b325dc5, + 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, 0xdfeceee9, 0xeff255fc, 0xfc97bd59, + 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, + 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, + 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, + 0x19026be2, 0x106a090e, 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, + 0xfd1119a3, 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, 0x2e43d2db, + 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, 0x24996054, 0xe5fd7518, + 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, 0x19490a6e, 0xbfcc1617, 0x967882fc, + 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, + 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, + 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, + 0x071ae0e6, 0xc3c8d053, 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, + 0x3678e185, 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, 0xb67c5819, + 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, 0xc2222ef2, 0x5a046246, + 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, 0x54a3bc82, 0x5706694c, 0x4664f6db, + 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, + 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, + 0xce8f27be, 0x5a559021, 0x9b1740dd, 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, + 0xe9952168, 0xdc81cac7, 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, + 0xb58b5c72, 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, 0xd99e6ac7, + 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, 0x3635a87c, 0xcee78062, + 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, + 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, + 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, + 0x384ad656, 0x9d824935, 0xec915f03, 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, + 0x4064fbb5, 0x66ad961a, 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, + 0xdbe24543, 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, 0xcadaf946, + 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, 0x628675d3, 0x6b1d569f, + 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, + 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, + 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, + 0x8d3c9334, 0xe5c6c529, 0x20e898db, 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, + 0x0d748033, 0xecc5393a, 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, + 0xf35661c3, 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, 0x5d2efdf7, + 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, 0x69c800e0, 0x5d310e80, + 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, 0xe9811969, 0xc08a7628, 0xe5e44555, + 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, + 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, + 0x80082d96, 0xb5a06d54, 0x1612537d, 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, + 0xf2fac0cc, 0x737aeb61, 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, + 0xaa36609d, 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, 0x0c2f32bc, + 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, 0x6a6777dd, 0xa7029cb3, + 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, 0x59ebc41f, 0x7e55932d, 0xcf78bead, + 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, + 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, + 0xc99944ec, 0x5289e5ff, 0xd64dd767, 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, + 0x4cf9307b, 0x1b6533fa, 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, + 0xe854ce92, 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, 0x408694a5, + 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, 0x24ed6723, 0x0c24fa00, + 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, 0x7db55eaf, 0x0fa8aabb, 0x0e942194, + 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, + 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, + 0x0350d608, 0x54e77f30, 0x866c2575, 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, + 0x3bf7c1bd, 0x5762abb7, 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, + 0xa9a36bdc, 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, 0x5b171723, + 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, 0xe66188ab, 0x4d2b635b, + 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, + 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, + 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, + 0xa31e8408, 0xac80b477, 0x7e7ddefc, 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, + 0x22eb7378, 0x08773858, 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, + 0x65c5fac3, 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, 0x7b9de18a, + 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, 0x804275c8, 0x6ff502be, + 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, 0xf65056f7, 0x18393ab3, 0xbf8c8b96, + 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, + 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, + 0x9685fd96, 0xc354066f, 0x9cdbc452, 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, + 0x328dfdbe, 0x7d168a67, 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, + 0x5fd2e5d7, 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, 0x3fb91263, + 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, 0xca097d3e, 0xa90c478f, + 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, + 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, + 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, + 0x4b823e48, 0x581b2420, 0x4ff2d70c, 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, + 0x476626bc, 0xad5c9d4c, 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, + 0x766880ca, 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, 0x89eac33c, + 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, 0x4eb31945, 0xf2c5d93b, + 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, 0x793fdc45, 0x519a1c15, 0xe31ee96d, + 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, + 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, + 0xd036e501, 0x0cb814a8, 0x06b9ab5d, 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, + 0x9284b162, 0x2cd5b7ab, 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, + 0x6ba484fe, 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, 0xdd4c9f22, + 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, 0x7143f3bb, 0x540b1347, + 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, 0xb2874627, 0x7f0c9a4a, 0xf8106eae, + 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, + 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, + 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, + 0x15aa0461, 0x1bc775e8, 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, + 0x68377d59, 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, 0x90689424, + 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, 0x362b4809, 0xec92588b, + 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, 0x32a14d01, 0xf4f6fec4, 0xada9360c, + 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, + 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, + 0x86428407, 0x45d6c023, 0xc77ebdeb, 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, + 0xf8198b68, 0x881246e7, 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, + 0x9e82681e, 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, 0x2d42e033, + 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, 0x0d1c971e, 0xe7795114, + 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, 0xb31d23cd, 0x8102d36d, 0x51aeed2d, + 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, + 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, + 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, + 0xbd3d8fa0, 0xe798d010, 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, + 0xa956eb79, 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, 0x723065f1, + 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, 0xac794782, 0x002064e9, + 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, 0x344f1195, 0xa7181920, 0xd05fcfd2, + 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, + 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, + 0xb75639f1, 0xadc76771, 0xd3543fd5, 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, + 0x6c95fd6a, 0xc3bb4a03, 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, + 0x045c945f, 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, 0x5acd89f8, + 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, 0x353f926c, 0xe3471231, + 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, 0xd16e5090, 0x9eff66f3, 0xa35ee078, + 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, + 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, + 0xc4062fef, 0x2bd3b757, 0xcbd45594, 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, + 0x2857a67c, 0xce5b2c90, 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, + 0xcd439cd3, 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, 0xbb20e7d2, + 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, 0xee542f36, 0xb0807f6e, + 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, 0x5104928d, 0x047c150a, 0x328cc000, + 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, + 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, + 0xcd61b411, 0xfddd923d, 0x638d0e61, 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, + 0x6bef47aa, 0xf460b130, 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, + 0xdfe4f729, 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, 0x55d094ff, + 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, 0x3161690b, 0x3ffa1fcd, + 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, 0x8a41bcac, 0x38d2f20e, 0x9aac541c, + 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, + 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, + 0x54705c7e, 0xba150347, 0xa80514ec, 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, + 0x7ce59906, 0x577da8f1, 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, + 0xd28382ff, 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, 0xb7bc9a79, + 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, 0xcc0be43f, 0xa606a522, + 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, 0xea4a38b5, 0x76901b4b, 0xe2583ac7, + 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, + 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, + 0x0cfe6db5, 0x5accdc39, 0x3377eaed, 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, + 0xc8bd6a8f, 0x625a6215, 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, + 0xae81db75, 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, 0xfee25664, + 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, 0x8bb3653b, 0x026eedbb, + 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, 0xb5bcee42, 0x6db10b43, 0x9fec55e3, + 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, + 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, + 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, + 0x429e2dc7, 0xc309b30a, 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, + 0x7874b53c, 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, 0xb92b80c7, + 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, 0x3326a1a1, 0x78b01e6e, + 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, + 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, + 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, + 0xc687b587, 0x383f7c40, 0x54830d04, 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, + 0xbf32f0c7, 0x2a796a67, 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, + 0xfd0367d1, 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, 0xc0e35390, + 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, 0xa32b3c81, 0x1d02d66b, + 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, 0x456c5876, 0x4c7a1f7d, 0x8210e535, + 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, + 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, + 0x03826132, 0xf505a1c5, 0x5536b8f5, 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, + 0x743d2b0d, 0xa82aed8d, 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, + 0xafef4d80, 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, 0x6b311848, + 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, 0x129d80fd, 0x18982768, + 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, + 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, + 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, + 0xeaac07b5, 0x0a377949, 0xcea56fc5, 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, + 0x65e46fe0, 0x9a5df9f9, 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, + 0x8358ab8c, 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, 0xdc18fabe, + 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, 0xd48cbb77, 0xcffdb7b0, + 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, 0x8ac94023, 0x11efd6fa, 0x5a6574f0, + 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, + 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, + 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, + 0x743b1a4d, 0xcd7ff202, 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, + 0x18060bb0, 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, 0x4bdc887f, + 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, 0x58f5a07b, 0x3c0266e5, + 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, + 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, + 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, + 0xbbff8af7, 0xaab1617c, 0x596a01d9, 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, + 0xd980aa05, 0x9269bb19, 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, + 0x298eb742, 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, 0x27fd3816, + 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, 0x2ae780c3, 0x7374f385, + 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, + 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, + 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, + 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, + 0xc19f5cac, 0x0bed2aa4, 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, + 0x783cfc66, 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, 0x1628b35c, + 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, 0xb361da26, 0xc0e2aa6b, + 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, 0x10f2492f, 0x231be0f1, 0x2b6fc840, + 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, + 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, + 0x7f6ace2b, 0x21514ebb, 0xc46d4800, 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, + 0xaf2ba637, 0xc4063ea0, 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, + 0xf942657f, 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, 0xea694198, + 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, 0xb453ee10, 0xafe27498, + 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, 0xbb74e075, 0x4408ab02, 0x2eae958a, + 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, + 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, + 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, + 0xfc5ff382, 0xc25ae007, 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, + 0xca5e1ee1, 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, 0x27c57f08, + 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, 0x86952278, 0x2810740c, + 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, 0xabc1d828, 0x05b673a5, 0x93e0c5ce, + 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, + 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, + 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, + 0x9d268a7e, 0x0485322e, 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, + 0x4f7b98f0, 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, 0x9161c085, + 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, 0xd6243501, 0x50f99e78, + 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, 0xe7888474, 0x58967c61, 0x9c2344d8, + 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, + 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, + 0x4a543dd4, 0x72d27f50, 0x794b2c38, 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, + 0xde3dfa58, 0xeac4977f, 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, + 0x4e87a4a4, 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, 0x829272a4, + 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, 0x508ed11e, 0x34f13455, + 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, 0xd435af57, 0x3e86d270, 0x7f04d0f2, + 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, + 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, + 0xfc49bc3d, 0x55757973, 0x84149ef8, 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, + 0xa17f53c4, 0x882c2967, 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, + 0xb340d658, 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, 0x76c9e6a2, + 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, 0xcc17d17e, 0xc52d9ae0, + 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, 0xad9625b4, 0xdbb45f5b, 0xf707fbea, + 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, + 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, + 0x6107a718, 0x83643c4c, 0xf2f96503, 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, + 0x41397ea1, 0x5793b309, 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, + 0x30ed4df8, 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, 0x9e264e70, + 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, 0x3f767c6f, 0xd1c48bab, + 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, 0x50da0980, 0xac96ecf6, 0x008c4910, + 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, + 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, + 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, + 0x49a844d0, 0xbbf5495f, 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, + 0xc41a3c1d, 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, 0xdea90048, + 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, 0xb709b9fe, 0x4549aaea, + 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, + 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, + 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, + 0x17a388b9, 0x78038049, 0xc505ab47, 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, + 0x7e6727d2, 0x9cef5fce, 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, + 0x88bb5013, 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, 0x17261a8e, + 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, 0xf480ab6d, 0x39525194, + 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, 0xdfb74aec, 0x62aae2f0, 0x46b855b3, + 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, + 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, + 0xe260be49, 0x18b01f3b, 0x0a2fc30f, 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, + 0xfb85d9ea, 0x2ddace97, 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, + 0x8c823cb1, 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, 0xf22f9ccd, + 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, 0x769e9c28, 0x65f8905d, + 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, 0x631f0974, 0x3f48dae6, 0x025739cd, + 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, + 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, + 0x5113ea88, 0x72ef2942, 0xd4aa0766, 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, + 0x74798f9c, 0x35e96814, 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, + 0x5ddb2efb, 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, 0xf4ab5191, + 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, 0x88a6c986, 0xdb0e7bbb, + 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, 0x0baad5bf, 0xaed19942, 0x66e4b053, + 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, + 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, + 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, + 0x34268b83, 0xe4bb7d3a, 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, + 0xac836a26, 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, 0xec264fe5, + 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, 0x381f32a7, 0x20a5e8c0, + 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, 0x15470bc2, 0x9ef31ae9, 0xd9e26951, + 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, + 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, + 0x2bf519ed, 0xf57860ea, 0xd69ba992, 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, + 0xccfc8b54, 0x58a93087, 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, + 0x60d94733, 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, 0x8ae04ca7, + 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, 0xca2f0fa1, 0xaac2e3bb, + 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, + 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, + 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, + 0x07796220, 0x0f0f8722, 0xbd6092dd, 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, + 0x17862bac, 0x610b9ce2, 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, + 0xcf3f6b27, 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, 0xff007778, + 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, 0x15a2c929, 0x9263b116, + 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, 0x187b9976, 0xf5ea2689, 0x87e3b151, + 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, + 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, + 0xbaa41197, 0xe5dcc72c, 0xaf16a669, 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, + 0x257e15c8, 0x12fbc35b, 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, + 0x4f1906d3, 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, 0x6d7b3b88, + 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, 0xfc5fbfed, 0x18db2aa6, + 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, 0x4429b1aa, 0x838682ab, 0x5bdfd86b, + 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, + 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, + 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, + 0x5e68e36b, 0x838322dc, 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, + 0xed6bf807, 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, 0xfb7507a4, + 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, 0x532e6654, 0x0c528786, + 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, 0x230b4319, 0xdd780574, 0x58889d79, + 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, + 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, + 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, + 0x73e830ce, 0xb353b81d, 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, + 0xe7929941, 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, 0x45da675f, + 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, 0x52a33502, 0x7d4b918c, + 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, 0x4b0a5e47, 0xce55bc17, 0x09656fd6, + 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, + 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, + 0xfe627e5d, 0x791daf5e, 0x50943665, 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, + 0x3e6a0f21, 0x9dad2288, 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, + 0x72f16cfc, 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, 0x86de5619, + 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, 0x06add0d4, 0xd0c462c6, + 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, 0x494f49bb, 0xcd7f90a5, 0xb6709e40, + 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, + 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, + 0x9bafb81d, 0x62e53468, 0x86ec692b, 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, + 0x8d6632f1, 0x8ba05667, 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, + 0xcfad36f8, 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, 0x526af581, + 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, 0xdea23b22, 0x9f8c78c5, + 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, 0x8d801702, 0x98d2fe2d, 0x3ed6b821, + 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, + 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, + 0xb2ccc077, 0x6162fefd, 0xb3701463, 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, + 0xeabc4ede, 0x82191ff8, 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, + 0x3e457dab, 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, 0x5ecc278f, + 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, 0x0862a010, 0xb3c9a772, + 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, 0xed37dba7, 0x26112057, 0x68c688f2, + 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, + 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, + 0x67c335d0, 0x6981f384, 0x6ca54c87, 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, + 0xf5315cf0, 0x995fb40e, 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, + 0xa571dfbf, 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, 0x1ce39a6b, + 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, 0x33a6d8b3, 0xd9101e64, + 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, 0x13eb0f7c, 0x77b31835, 0x65c53459, + 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, + 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, + 0x0e5f8848, 0xd61ad101, 0xf44c42a4, 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, + 0xd37d5397, 0xeada6952, 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, + 0xfea92813, 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, 0xded23976, + 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, 0x881ccb9e, 0xa1bb6a8d, + 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, 0xe19a859f, 0xfb877d69, 0xc91faf5e, + 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, + 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, + 0xd5e24aec, 0x6731d1b3, 0x48ebc226, 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, + 0x18281991, 0x42588569, 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, + 0x915978fc, 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, 0x4a5faf73, + 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, 0x477d5c34, 0xe2ef3d70, + 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, 0x6db3425d, 0xce451d6f, 0x6f2a53e9, + 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, + 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, + 0x0365098d, 0x013e15ad, 0xc990d5f4, 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, + 0xed216f9a, 0xcb714de5, 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, + 0xf602de55, 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, 0x99029b50, + 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, 0xbd2995e9, 0xd906ec04, + 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, 0xb921c72a, 0x9fc5a234, 0x55d0fbec, + 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, + 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, + 0x84b6ab49, 0x5b3c6835, 0x0015afb6, 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, + 0x89cc97bc, 0x713d3b24, 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, + 0x86363b5f, 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, 0x7368089c, + 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, 0xe516c9a0, 0xeab5aa5d, + 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, 0x614782cd, 0xce169d44, 0x6433de5e, + 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, + 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, + 0xc0ac7573, 0xca381e11, 0xfc5916b6, 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, + 0x332f9714, 0xa3804fc5, 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, + 0x37552b9e, 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, 0xe9b11f94, + 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, 0xcfed5315, 0x27f4a06d, + 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, + 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, + 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, + 0x3c9c2d05, 0x6794edd6, 0xc22cc352, 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, + 0xc045f697, 0xfd090038, 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, + 0x36ae74e4, 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, 0xd85611c1, + 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, 0xb326cc47, 0xe0faa978, + 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, 0xb77eda67, 0xc49052e6, 0xc514a075, + 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, + 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, + 0xf28a6231, 0x9eaa4f64, 0xe9468748, 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, + 0xd8eae4af, 0x46876f0b, 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, + 0xd1daf994, 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, 0x5389bce5, + 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, 0x62a8e0a5, 0x200442ca, + 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, + 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, + 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, + 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, + 0x29bc2f91, 0xac5eaa62, 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, + 0x8bc6cf4f, 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, 0x6bbb33dd, + 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, 0xf708838e, 0x2caf050b, + 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, + 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, + 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, + 0x6746103e, 0xa0eff544, 0x0bba778a, 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, + 0xf1ee2d08, 0x1b100e82, 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, + 0x7ea8c2c3, 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, 0xd1d5c2c0, + 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, 0x5ce3fa8a, 0x2075b595, + 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, 0xdb4a2241, 0x806460ec, 0x183637f9, + 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, + 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, + 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, + 0x724a1e6a, 0x1f49fcfc, 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, + 0xf8481f7d, 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, 0xc548731c, + 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, 0x92d1c238, 0x59503c44, + 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, 0x82172a29, 0x5db3569b, 0x6a0ab6f7, + 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, + 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, + 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, + 0xc2110048, 0xef4c9825, 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, + 0x3d923162, 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, 0xaddd3c63, + 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, 0x20d00302, 0x0718e1f1, + 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, 0xb6747958, 0x6bcb60f5, 0xbce4158b, + 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, + 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, + 0x436ca416, 0x0091a7da, 0xe705853a, 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, + 0x99f5e336, 0x67e6d388, 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, + 0x20fa88af, 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, 0xdeb5cc9a, + 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, 0x112a8ec2, 0x385e89a8, + 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, 0x0c60638a, 0x0c83492d, 0x95d61b20, + 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, + 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, + 0x50f5b110, 0x0c23b119, 0xbc27c7e8, 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, + 0xd1b98d82, 0x632df3e2, 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, + 0xe98733e0, 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, 0x75257595, + 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, 0xf12a2f87, 0x900624fa, + 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, 0xf3be72c7, 0x01ca0052, 0xdf927440, + 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, + 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, + 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, + 0xc226cc77, 0x294e0e4e, 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, + 0xd0489c01, 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, 0x5d6bc3c2, + 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, 0x0c117533, 0x0b70ddeb, + 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, + 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, + 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, + 0x4cd711a6, 0xc46a6a58, 0x2d82b595, 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, + 0x9920ac09, 0x02db13ae, 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, + 0x108cdb88, 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, 0x2944706d, + 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, 0x8ee22fc9, 0x9970baae, + 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, 0x253d5795, 0xa8e3738b, 0x9770975d, + 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, + 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, + 0xacabe801, 0x47952193, 0xd3138e94, 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, + 0x68161660, 0x6365afcf, 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, + 0x96847976, 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, 0xedabeffe, + 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, 0x25d6ba47, 0xec63d289, + 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, 0x671596a0, 0xa08b6a5b, 0x0bca7779, + 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, + 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, + 0x9e283138, 0xb2631843, 0x8c9d46d6, 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, + 0xa4fa2f87, 0x472f5be5, 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, + 0x6fba83bf, 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, 0x7d4f1ea5, + 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, 0x9b0b0ade, 0x6373a3b0, + 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, 0x4c9ca5fd, 0x7f1f3313, 0x30013306, + 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, + 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, + 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, + 0xbed76d66, 0xf5b960da, 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, + 0xad500497, 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, 0xef6e61d8, + 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, 0x4ed7b964, 0xff1f6c98, + 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, + 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, + 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, + 0xbbdb8c62, 0xf6dd386b, 0xe3358787, 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, + 0xce5af4fb, 0x712564e1, 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, + 0x66f6d4a7, 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, 0x499c86a6, + 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, 0xc94b8391, 0x7bd8e512, + 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, 0x449df40e, 0x93f035f8, 0xafd2521a, + 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, + 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, + 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, + 0xf9621d42, 0x77ee21f3, 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, + 0x45317e93, 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, 0x080f5133, + 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, 0xf8ab5684, 0xbd3b8b9a, + 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, 0x428761dc, 0x97459150, 0x709e0a12, + 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, + 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, + 0xac7d020e, 0xa7bf5312, 0x4c6834b7, 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, + 0x03f9e743, 0x3004dfb0, 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, + 0x9ad90bde, 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, 0xa1fc99fe, + 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, 0xfd35ccf2, 0xd2473bb9, + 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, 0x32e8b9f2, 0x103ef0a9, 0x1888642e, + 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, + 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, + 0x8ec2282a, 0x146232d5, 0xf4241f66, 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, + 0x2d03e06e, 0x305c322c, 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, + 0x2c33b686, 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, 0xa9d0de99, + 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, 0xce93f4cd, 0x822382ec, + 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, + 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, + 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, + 0xc83c381c, 0x098d5293, 0xc0738c93, 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, + 0x359fc239, 0x806328f8, 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, + 0x7d0cf9c7, 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, 0x356f9c19, + 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, 0x96e32fe0, 0x142e5994, + 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, 0x702f1422, 0x4008e264, 0xbbf91d05, + 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, + 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, + 0xa6b29bb4, 0x67777742, 0x65b6542c, 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, + 0x86507fb1, 0x26f76111, 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, + 0x658bb0c8, 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, 0x685d4d9a, + 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, 0x30d5acc3, 0x18d236ab, + 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, + 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, + 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, + 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, + 0x37160e0f, 0x9f623018, 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, + 0x99b0115b, 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, 0xc7d5de52, + 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, 0xf080b017, 0x4da4d290, + 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, + 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, + 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, + 0x0d628e03, 0x4a93cdd8, 0x6f643479, 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, + 0x1983f603, 0xd4591b19, 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, + 0x3488b648, 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, 0xde17a435, + 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, 0xc4706c3f, 0xdf14d9ab, + 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, + 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, + 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, + 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, + 0xb8c941ca, 0xe26b9187, 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, + 0x0bbe4840, 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, 0x7fa40f5f, + 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, 0x611a0f89, 0x3a0e5f8a, + 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, 0x01079381, 0xc250fa30, 0xead64afb, + 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, + 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, + 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, + 0xe5b8b32e, 0x9c6261e3, 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, + 0x8f854e38, 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, 0xa8e1a4e5, + 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, 0xff46bbb2, 0xa38e83bd, + 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, 0x6a145a5c, 0x6a41add1, 0xd954c1f0, + 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, + 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, + 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, + 0x5eba32d0, 0x3cc4a69c, 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, + 0xc8013642, 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, 0xe9e313b3, + 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, 0xef679615, 0xc074d215, + 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, + 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, + 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, + 0x208a0b6f, 0x7245f138, 0x352dee4f, 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, + 0x46fc92f6, 0xfcfa9de2, 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, + 0xa44da7f3, 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, 0x35818ebe, + 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, 0x3a03b930, 0x868b0e63, + 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, 0x4d72927a, 0x1b62ae8f, 0xef765353, + 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, + 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, + 0x83b4c653, 0xfd8585e4, 0x23af00e8, 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, + 0x822679ff, 0x695356ac, 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, + 0x9a82734d, 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, 0xccf76bc6, + 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, 0x0e3e6c5f, 0x83452a89, + 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, 0xdadeeb74, 0x7425d656, 0xdcf615c1, + 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, + 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, + 0xc725ecc0, 0x35b295d1, 0x7534f83a, 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, + 0x98a03f22, 0xd70a9952, 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, + 0x7ccba435, 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, 0x771d7fac, + 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, 0x59029f2b, 0xb47ed32a, + 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, + 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, + 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, + 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, + 0xdf2b52bc, 0x0849a8d7, 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, + 0xcca50f90, 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, 0x38d03044, + 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, 0x7ec20957, 0x2e01a0db, + 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, 0x0b90f4dd, 0xa36b8065, 0x31933133, + 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, + 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, + 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, + 0x339b1a9d, 0xcd9c7feb, 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, + 0x85fd0e01, 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, 0x0470618d, + 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, 0x89209a5c, 0x5a60a94e, + 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, 0x22497a31, 0xf3512771, 0xb6adb43b, + 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, + 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, + 0xfc9d64e3, 0x1b454a6d, 0x8b220894, 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, + 0xc66316e8, 0x52366573, 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, + 0x2d196453, 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, 0x6fb6bf96, + 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, 0x3c9257fd, 0x8a3d0140, + 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, + 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, + 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, + 0x615723de, 0xf5fde9a0, 0x96bab4f4, 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, + 0x54f0e2e2, 0x5355cc42, 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, + 0xf6ff9372, 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, 0x0230da46, + 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, 0x26a6191d, 0x83da081c, + 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, + 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, + 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, + 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, + 0x8bf9c71e, 0x1a682b8a, 0x7bbd75b5, 0xb06c035c, 0x9bd1355b, 0x03f15e1b, 0xe1dc6a96, 0x724c12d5, 0x5eeb7abd, + 0x6f1a533d, 0xe4163b97, 0x53963f78, 0xf4bdc4cf, 0x30bc6aa8, 0x55020a94, 0x87424139, 0x7f4e0fc0, 0x0dced4cc, + 0xcc44f761, 0xdc915d5d, 0x5923afae, 0x5fca09df, 0x6da60086, 0x4176cac0, 0x2cd1c0be, 0xeaf4a65a, 0x9a2b0460, + 0xd9adceb3, 0x837911fc, 0x24a064e2, 0xf62aef80, 0x2c72361c, 0xabcea574, 0xc9e8494f, 0x58fdc7fe, 0x19835be7, + 0xe2f50795, 0x22577eee, 0xf37a909d, 0x01085e15, 0x433de341, 0x47e376d9, 0x0bba767a, 0xf77fa338, 0xdaabb9e6, + 0x321bb7de, 0xd9c18914, 0x63c61551, 0x608ac9b2, 0xdc175799, 0xa3b005c1, 0xb30ba812, 0xb8f13ae7, 0x4e6515ee, + 0x63b6e03c, 0x21dc18eb, 0x92116367, 0x912c40eb, 0x67431a9d, 0xa3ac94ae, 0x8778ab34, 0x97d032f9, 0xe363d369, + 0x83361fee, 0xfc13d3ed, 0xa8b81258, 0x3ad31da7, 0xf22b43bc, 0x5e4dc39b, 0xaf3c8d97, 0x4e4f0c56, 0x9ad45750, + 0xce42b7f5, 0xfee1c9dc, 0xda821b40, 0xe112aa6d, 0xc534e246, 0x49278e21, 0xb44895c1, 0xe3d1ab5b, 0x73a79242, + 0x6c9f7498, 0x635ece54, 0x11679e76, 0x2ecfb564, 0x32fac952, 0x9ef53d09, 0xe639b29c, 0x6bc8773e, 0x1bc739cc, + 0x89ba5c0c, 0x4bd2bc26, 0x422ddfd6, 0xfdb0a8e4, 0xcf2f81a5, 0x14841e89, 0xd4f78e53, 0x63013219, 0x359821da, + 0xb02ce75b, 0xac288e79, 0xd6225779, 0xe9c65694, 0x49a11a14, 0x1607727d, 0x5371ef25, 0x6e32e37e, 0x46463aa1, + 0x2f9f3be7, 0x008814a8, 0x4aaeb902, 0xeaf8f5a0, 0x36ff71ae, 0xeda38d7c, 0xc8154fa2, 0xbd72884c, 0xeb83e123, + 0x8c815ce0, 0xe3cec3c1, 0xb7cb6a68, 0x4b2967a5, 0x6f401978, 0xa790036a, 0xd7098ddf, 0xe29bc8fc, 0x990029a6, + 0x03cdb1fe, 0x0dd3e1d0, 0x154d7ad7, 0xf416dee7, 0x5563bc46, 0x724bd24d, 0xc9afafda, 0x15fbdda1, 0xdafbcb38, + 0xd5a26b25, 0x619bed77, 0xba04b927, 0xfd2d6b8a, 0x77894e2e, 0x3a2b2115, 0x4f97c16a, 0x624c5c48, 0x87b8ac99, + 0x52727b94, 0x1e24f7f7, 0x075e8797, 0xf6c0d443, 0x1bbfc65e, 0xaaef1178, 0xc6ee8328, 0x328b718e, 0x6f763df7, + 0xf0198c11, 0xd6cd4bf9, 0x3ee66642, 0x717949cd, 0xd07b2cb7, 0xa023dc26, 0x36fb0e07, 0x833771f3, 0x865405d9, + 0x440f6fbb, 0xaf079d0d, 0x2187a5d8, 0x1c48bf61, 0xd1a3e59f, 0x022d6bda, 0xd6bbf539, 0xf7e1e652, 0xd13cd569, + 0x1953bd8c, 0x2c00848e, 0x15a8bd5e, 0xf1633fe7, 0x56e8f0b5, 0x3b009bee, 0xd18e24a5, 0x06e6be5a, 0x20b080a8, + 0x2b7c3d6b, 0xc9e867d9, 0x013902a6, 0x722d7f90, 0xaa97b1b4, 0x6a72eaa5, 0xa35fb788, 0x02c7801c, 0xf528ad86, + 0xc08e0f90, 0x36013f85, 0xb6507cfb, 0xce50853b, 0xdc81a410, 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, + 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, + 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, + 0xca3c7387, 0x3ebc4e22, 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, + 0x0d609b5c, 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, 0xe964371d, + 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, 0x8549a545, 0x72cd25a6, + 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, 0xfa0f309d, 0x2450505b, 0x7e62d6b6, + 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, + 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, + 0x554de3f7, 0x00236229, 0xb65a8838, 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, + 0x1e0f4174, 0x0e4f84a9, 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, + 0xbecc7016, 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, 0x36f74f81, + 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, 0x49684acc, 0x27ceed4c, + 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, 0xc18462c5, 0x30407eb5, 0x8e18797a, + 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, + 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, + 0x39bc1a46, 0xf4865fdf, 0x22bd8658, 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, + 0xd9382232, 0x947cd63b, 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, + 0x65a5e218, 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, 0x9cff960e, + 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, 0x5da4cf70, 0x861ef098, + 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, 0x2d914387, 0x9ed7f94b, 0xf00b5441, + 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, + 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, + 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, + 0x78603c0a, 0x7c403889, 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, + 0xe1fecec4, 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, 0xee70ca50, + 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, 0x57098afb, 0x744d626d, + 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, 0x5936ff74, 0xc1477a35, 0x3665ecdc, + 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, + 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, + 0x7e1959e1, 0x91787e6c, 0xda51caa5, 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, + 0x8fc78d5d, 0x3ea2142c, 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, + 0xa69d279e, 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, 0xb001c899, + 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, 0x46ebff79, 0xccb7b9b6, + 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, 0xac829629, 0x9ffbf3a3, 0x718c8f7c, + 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, + 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, + 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, + 0xbba13c12, 0xdd02c804, 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, + 0x347c5339, 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, 0x4396ff24, + 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, 0xee7ad3a2, 0xcc436c78, + 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, + 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, + 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, + 0x68c77435, 0x356f1249, 0xec7fe5ec, 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, + 0x8bac2cae, 0x5104a87d, 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, + 0xd5a33292, 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, 0x129c6972, + 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, 0xa54b4c48, 0x667c537f, + 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, 0xe16ab1b9, 0x3d5dd389, 0x5947821b, + 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, + 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, + 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, + 0x8e2665b7, 0xee93572c, 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, + 0x07a80a9b, 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, 0x8a302c05, + 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, 0x9b86cabe, 0x48f7ca80, + 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, 0x79bda240, 0x909fd98e, 0xf49643bc, + 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, + 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, + 0x8821bf49, 0xde5b8005, 0x6e749b41, 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, + 0xc85a975d, 0x00904827, 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, + 0x3ac88c9e, 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, 0xadef941f, + 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, 0x15116dd8, 0xcf51bdc7, + 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, 0xe55e6fbb, 0x43524b5b, 0x12dbc403, + 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, + 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, + 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, + 0xb541d640, 0x84ceb075, 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, + 0xd2f96c90, 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, 0xc9f9d7ed, + 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, 0x3ba18f38, 0xb9d8d6f5, + 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, 0xf818f739, 0x08eaf9e5, 0xc9f08a15, + 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, + 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, + 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, + 0x730d6d4c, 0xb4f2cb42, 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, + 0xfffa9c44, 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, 0xb4ba3765, + 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, 0xf93f4075, 0x9d0ed557, + 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, 0xa5fd92c4, 0x48985b22, 0x9d228641, + 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, + 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, + 0x7e4bb890, 0x1c7739a1, 0xc91fad83, 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, + 0x1eb7fdad, 0xa71313bb, 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, + 0x75bea2bc, 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0xd4fa8fc8, 0x298e3d87, 0x5e472547, 0x494a84d2, 0x647d8034, 0xac4098be, 0x4009c6b2, 0x8f971b24, 0xce15d184, + 0x0fb41b97, 0x193d85a5, 0x8ade3fae, 0x7be5a811, 0x5ad03572, 0x08e7051b, 0x6e2ee2ff, 0xd8345ba1, 0x5443a7e3, + 0x53a2abfe, 0xd4f59d16, 0x9f88e81d, 0xf244115e, 0xf0b2ba6b, 0xb1988699, 0xbb9b5e12, 0x70e87e85, 0x4be3ca07, + 0x2e428baa, 0x1e734902, 0x549f40b9, 0xbab86a07, 0xbb2e300c, 0x8ef685ba, 0xe0895ba2, 0x77767b22, 0x131dfca4, + 0x8da6eb24, 0x1bda5985, 0x6d00ff91, 0x722cb00c, 0xdf308f8d, 0x99829400, 0x4f496a27, 0xdef9fa35, 0xc60f301d, + 0xc8ff73a9, 0xca6e06bc, 0x8983790f, 0xac6bfc5d, 0x60471cac, 0xf0fbfc42, 0x17f53500, 0xf7bfc25d, 0xe327fe31, + 0x05750344, 0xb63ad995, 0xdec9128e, 0xbb672fb5, 0x71c76d58, 0x1ef91ab6, 0x47bfd7e9, 0xddddc7a5, 0xb32b01fb, + 0xe26ebb89, 0xa91d5f4b, 0x9787357d, 0x3b464566, 0x4382b18c, 0xe8cfac56, 0x5cef1081, 0xc01afc3f, 0xa76299d2, + 0x89c35558, 0x6e74f552, 0xfcc20336, 0x7e8bffcd, 0x5d3d2e4f, 0xb6d7afc0, 0x16c6cd4c, 0x1e8f301a, 0x8431800a, + 0x723228d5, 0x4be49662, 0x0e5bae7a, 0xc7c2bdb1, 0x8da96e1e, 0x84f14607, 0x5a50c4d5, 0x50769285, 0x5526702a, + 0x030dfef9, 0x1d3be1a1, 0xcb14ebfe, 0x028a93d4, 0x75b20b6e, 0xe64ca916, 0x4a47f540, 0xf77ba8c4, 0x2d951cef, + 0x7f9a9640, 0x6d4ef4e7, 0x45daa8f0, 0x4c0a46ff, 0x5b98be52, 0xa411dc84, 0x3e48dabb, 0xf6fdc6e2, 0x91cea2dd, + 0x38d25a02, 0xe3b7d79e, 0xa7655d0b, 0x5c8cd063, 0x14de0541, 0xd7228c6f, 0xb23b5084, 0x2a5adac0, 0x5ed77d86, + 0x42c17cbe, 0xbf586e7f, 0x4cc6ec9b, 0x9a39cd6d, 0x7373f3a4, 0x397d645c, 0x0b641d9e, 0x277aacb2, 0x59524c27, + 0xff8f73bd, 0xa10b97b9, 0xd166198a, 0x3b4a25d8, 0xc0ed5d1a, 0xb56746fd, 0x367bb4c9, 0x731a5238, 0x8218ee6a, + 0x612af553, 0xca340189, 0xac01f213, 0x9b3b20be, 0x7ba108cc, 0x3541af79, 0x8fc88951, 0x4a3269c7, 0x0ff70337, + 0xf1a9cedd, 0xac14dc44, 0xa44a8a96, 0x9e5ed0b9, 0x6388cb44, 0xf6e438c5, 0x13c4899f, 0xac37573b, 0xfd9172f4, + 0x18b15ef7, 0x7a495794, 0x451a4b06, 0x367ecddb, 0x4d89a56e, 0xfa69d9c9, 0xe7bcbb4d, 0x6f0dd775, 0x4908d40a, + 0x5ee60a87, 0x42ec1803, 0x7771789e, 0x4d3ffe6d, 0x21ce8f2d, 0x51ba9bd9, 0x331bbde2, 0x69535503, 0xb295a400, + 0x49d93e8b, 0x43920861, 0xa72be34a, 0x0ba77d43, 0x8cf43fa2, 0xd7fb4734, 0xce185cad, 0xa04654fb, 0xadf00e22, + 0x7c033f80, 0x0b5dbbe3, 0xd8f9d875, 0x4af737f8, 0x941b1d2e, 0xc2dc1fbc, 0x2eade5e0, 0x03bb0050, 0x6503f2f9, + 0x6064ef8b, 0x5fb4d7ac, 0x723ea425, 0xdc9182e7, 0xcb44f614, 0xee140310, 0x18b1ad42, 0xce4c46f2, 0xea7b7c10, + 0x0e32b86c, 0xde08244c, 0xa057c218, 0xd5420c94, 0x1cb9737c, 0x637aa739, 0x1d3a19ad, 0x388e26f8, 0x2e517d3f, + 0xc1d0e29e, 0xd70811f5, 0xc844c1f6, 0xcca085c3, 0xccef7e1b, 0x74c8a12d, 0x937aadf6, 0x3a333ce8, 0x615775a3, + 0x3b1d0f0a, 0x9dbf9990, 0x283d9dd2, 0x6612fe9c, 0x4401bf68, 0x5e71b357, 0x473797ea, 0x01364687, 0x426ddb6a, + 0x54b6f856, 0x98ba893d, 0x045a2bf9, 0xf67579cf, 0x8d77774c, 0xbc86e968, 0x0af75a60, 0x87882dc2, 0x8936d638, + 0x6ec83135, 0xa7f8938b, 0x28613b1f, 0x510d8ccf, 0x4b8b3bb7, 0xdd9d705a, 0xd2a87e4a, 0x60959d32, 0x8c7d650b, + 0x812bf858, 0x6d1fde77, 0xce4a4758, 0x26848a2e, 0xa4c520c4, 0x609c8e0e, 0x5b2da861, 0xcfccc726, 0x53b175bc, + 0x27c2356a, 0x43ed152c, 0x8ddbc723, 0x69ce3144, 0x19883c6a, 0x820bb17b, 0x84676b52, 0x1b4724b0, 0x34d61e47, + 0x86058e15, 0x5f3ad5b3, 0xaa9a18b6, 0x7eea420e, 0x6f5e42e5, 0x0e011973, 0xe5351a30, 0x8f50dccb, 0x2bb3a35e, + 0xd5a00dc0, 0x47b7f316, 0xa8ed96ed, 0xfaa0e2f1, 0xfe3f28ce, 0xae7114a4, 0xf7d6dd39, 0x5041de7a, 0xd93a8ab7, + 0x170182ba, 0xe7de179d, 0xbdd60723, 0xcb5e6069, 0x0e2f0d4f, 0xf3cd01f0, 0x7eb3df99, 0x031901f1, 0x3197f476, + 0xe637a162, 0x4e869926, 0xcd987daf, 0x1232e0b3, 0x86f88664, 0x6074a0be, 0xee45c4e8, 0xce5dfdec, 0x37f054e8, + 0xcdda2ff1, 0x2043e65a, 0xbd6f3b6b, 0x6ad1d025, 0x65cad15f, 0xc003e695, 0x0838221c, 0x6c54b2ef, 0x8bb0d7b3, + 0xc3373380, 0xf4217de3, 0xd0da628a, 0xd9641620, 0xe117c48f, 0x2a195bf5, 0xb88fe8ed, 0x257413ae, 0x19692276, + 0x5f81c3f5, 0x1307812f, 0x71599788, 0xbde7ff27, 0x55e3c66f, 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, + 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, + 0x50dd62e5, 0xf2dc2490, 0xb742d94c, 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, + 0x40278377, 0x4f1306d5, 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, + 0x3c727cc6, 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, 0xe3f264d4, + 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, 0xdf701ef3, 0xdbee77ed, + 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, 0x749c5fa2, 0x7bbfac6b, 0x944dc87c, + 0x2937ff1e, 0x87be8ef5, 0xd508b44d, 0x88f9b449, 0x09805e40, 0x747a7907, 0xcd189775, 0xc48c3e04, 0x8e044af2, + 0x69bd5360, 0x4365cd9a, 0x41934cff, 0x49281c0c, 0xac1a3b53, 0x49c1a094, 0xf285cbe6, 0x6939c327, 0xd492ce08, + 0x706fa662, 0x1781b9e9, 0x2ac19678, 0xd518ea0d, 0x7a374775, 0x07be58d3, 0xddccbc1d, 0x4c64df7f, 0x77557313, + 0x78f745bc, 0x7695ad4e, 0x1f199053, 0x44635e86, 0x1401a00d, 0xd443d30e, 0xb250c664, 0x3ec69195, 0xbca388ba, + 0x4be5e051, 0xdbc94cca, 0x58e07f89, 0x56a8747a, 0x8e98e7ac, 0x9267eec3, 0x594c3451, 0x3ebe4422, 0x46a7add4, + 0xdf5512c8, 0x20ae1c95, 0x53f909c4, 0x694f9d54, 0xad7e8f90, 0xdc387260, 0xfa4555ad, 0xa1da14c3, 0x72c56325, + 0x56011855, 0xf136f833, 0x86acff9f, 0xac88ffaf, 0xe9b77aa5, 0xa2501e80, 0x96a89a4f, 0xd5e9bf3b, 0x2efd4983, + 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, 0xc0c97ca0, 0xd6456515, 0x86a49990, + 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, + 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, + 0xab800038, 0x0e5f415b, 0x77d71868, 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, + 0x7999f376, 0x687e76cc, 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, + 0x5d416565, 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, 0xe1bcc050, + 0x58e9dea6, 0x9120a003, 0xaf81ac7b, 0x4bb3258d, 0x81175a7c, 0x9c0dfc15, 0xcc493ff4, 0x310244ca, 0x4744c647, + 0xba4acff8, 0xf7f2c903, 0x4d307533, 0xf3d3d65e, 0xd5f54c63, 0x501d2b16, 0x5fb04a6a, 0x17ef06f3, 0xed6fe1e1, + 0x6b689bd9, 0xcf0b906c, 0xb87f0c05, 0x68e6655f, 0xd2dbbb59, 0x6e7f68dc, 0xcb190ffd, 0xe5ad1843, 0xcf43d3cd, + 0xba9fbb26, 0x7292c37a, 0x2edbfc87, 0xc309ecd3, 0x2296fac7, 0xea11cd74, 0x44a5431a, 0x26eb5e3a, 0xe385b905, + 0x1855bad0, 0x272e3814, 0x03311bc4, 0xbecfc078, 0x43ed13e5, 0xe98431da, 0x1b156977, 0xfd3083ab, 0xc394ebca, + 0xcd25c4b6, 0xc58eee15, 0x0fbbd833, 0xa9e7c061, 0x42a51d37, 0x9919e922, 0x1962d841, 0x9c3e98ee, 0x60e546a4, + 0x688574b0, 0x50a2c84e, 0xd464e24e, 0x96bf6243, 0xf61dc96e, 0x2d9cdd50, 0x6b8117f4, 0x54955da8, 0x8b0998c3, + 0x8baf0db6, 0xf7e6bf89, 0xbecbc735, 0xc39e00de, 0x4e10e4fe, 0x6413f75f, 0x215e8148, 0x2bf72efe, 0x1d7cff6e, + 0xdb08ab8c, 0x6e537eb7, 0x669d59d9, 0x76d10e72, 0xa07aa161, 0x935a11af, 0x7cd7b149, 0xc9e8e540, 0x1db70600, + 0xfaafe3cf, 0x7b4d9f38, 0xb40b6275, 0xb726ceaa, 0x600ddd3d, 0xfa46364f, 0x4606cb16, 0xbaa7fb6a, 0x872a21b8, + 0xa4ce4d82, 0x4268bee0, 0xb0c76c16, 0x28a749db, 0xad5d68e4, 0x8b42ff83, 0x2d9490b8, 0xf8512caf, 0x47b20106, + 0xd5770487, 0x224856cb, 0xcb320805, 0x3a275b81, 0xf8430839, 0x373f3fff, 0x620596c4, 0x01faa3c5, 0x33b031d9, + 0x41e6df6d, 0x588b2df6, 0x321b4649, 0xcd9b3b90, 0x8ada2e5b, 0x67bca81c, 0x17de8242, 0xbec68a95, 0x2d2bea47, + 0xb986a75b, 0xac2456c6, 0x3b9b2ff9, 0x6fd600af, 0x10391225, 0xc5d7b055, 0x5095a20f, 0x09aae2d7, 0x2b12d63e, + 0x51607924, 0x1b10a4a0, 0x21bd699d, 0x962172bf, 0x30849f35, 0xbe9e6c38, 0x5a924cf3, 0x0c2c9279, 0x01ea6a4a, + 0x8201535b, 0x1a43b0af, 0x5a14628e, 0x2a1bd53d, 0xfb2292b1, 0x51cab661, 0xdad91326, 0x70e000e6, 0x64c846df, + 0x46422c08, 0x6ea48374, 0xc7c27c67, 0xc2241288, 0x03833097, 0xfa69432c, 0xa7c40ac5, 0x8ef29f05, 0x8b2599c7, + 0x239748c7, 0x3976582f, 0x7e63b803, 0x2206a2c6, 0x5f7fc961, 0xb8af162d, 0x579e4d70, 0xd53eeeb1, 0x66baa24a, + 0xf2ff8ce9, 0x698b6c1f, 0xca1b9f7d, 0xb06074b0, 0xd19e99d3, 0x545d10cb, 0x039f36e8, 0x9cfb78d6, 0xde0a5980, + 0x0a92866e, 0x3094a27b, 0xdcd07232, 0x50dbafc6, 0x1bb48c02, 0xf3c9be6d, 0xf8854fc1, 0xdc62dbc3, 0x2fd471c3, + 0xd4c5d20d, 0xbde52147, 0x9efdc8cf, 0x68922fc0, 0xb88e333f, 0x01278b3f, 0xb082deaf, 0xcaef9fb6, 0x2e2bd0e0, + 0xc66c96b8, 0x6fda0868, 0xa77e1f7a, 0x1d160a89, 0x85b1487a, 0x61d78902, 0xabee7f67, 0x96549880, 0x0531f910, + 0xf11c1886, 0xc7e97b0d, 0x41e6756a, 0x85f14859, 0xe3f0fc0b, 0x288c0086, 0x0430ba1e, 0x52e7f11c, 0x1c045213, + 0x1f4905be, 0x25f1210e, 0x56052d48, 0xd1dcd8a6, 0x4b6a63c6, 0x789dc29b, 0x9d0ec937, 0x7da8bb3a, 0x6d34fee5, + 0xb0cb417a, 0x79cbae75, 0x771ff408, 0x795efaf0, 0x08bba173, 0x8b087708, 0x31919e61, 0x58fc350b, 0x9724ae94, + 0x63c41461, 0x524803be, 0x1f321398, 0xae180121, 0xfc87c058, 0xba1f7804, 0xb3361eb0, 0xfbd0be38, 0x89a18736, + 0xf3f42412, 0x03b441c3, 0x9abdee97, 0xafd360f9, 0x4f4ea1bf, 0x95c8ba1b, 0x4443be52, 0xe1d07377, 0x0b1a5edd, + 0x6eddede1, 0x8269752c, 0x37e96258, 0x32818b93, 0x4335e781, 0xa7272ced, 0x399f7f83, 0xece7155f, 0x746b491c, + 0x40132011, 0x39cd4600, 0x535de5b8, 0xe585bdc2, 0x3454b808, 0xb8eb525d, 0xf03de612, 0xd3625812, 0x5f9e2734, + 0x538214a7, 0x21f2740d, 0x39cafc80, 0x092f0669, 0xc244c4ff, 0x569c8561, 0x8ce00cec, 0xfad3174c, 0x17a98478, + 0x3fba51e2, 0x7839ccd3, 0xd3cc2942, 0x34459786, 0x9e605d5a, 0x481ee65e, 0x63c01029, 0x97c3b03b, 0x0556943c, + 0x9ca515fa, 0x45ee4c64, 0xfed15ef4, 0x65baabdb, 0x037c4d51, 0x892ea8a2, 0x2de6038c, 0xd8716227, 0x57424e4f, + 0xf1b5ca70, 0x287fcd83, 0x653d548d, 0x2baaa7ed, 0x6af133ba, 0x4bfb12eb, 0x0585c00b, 0x7926e62b, 0x67f71020, + 0x06941d09, 0x3269b9d6, 0x6becf31f, 0x18b598fe, 0x139643a5, 0x9a9160e1, 0xbe2df596, 0x782f8037, 0x9bcce7db, + 0xf3be74bc, 0x4f7f7177, 0xddcacedb, 0xd348bb00, 0x0ef68de3, 0x1ff7d95c, 0x6201a28d, 0x24f67327, 0xa1425633, + 0x48426e5d, 0x3ccfed4a, 0x92baf081, 0x868d6418, 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, + 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, + 0xa4f0c02c, 0x006bdbc5, 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, + 0xd9d19ac8, 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0x40bb52d5, 0x654712b1, 0xd8e940e2, 0x8ff4683c, + 0x2a998600, 0xd4aad8ba, 0xee241d02, 0x94346fe9, 0xc02eb848, 0xc2c91e1a, 0xea843f6c, 0x5bc57c6c, 0xddd8a617, + 0xebf9c3c0, 0x4980bc36, 0x6d334dcf, 0x97a4b3df, 0x2a94b788, 0x83811aca, 0xbbc37422, 0x6292df1d, 0x761131db, + 0xb2d8dbe4, 0x7ff0219d, 0x95d470ee, 0xda8c0e74, 0xcf981bc4, 0x95642758, 0x215c055b, 0x2aaea2f2, 0x28a91766, + 0xe750abab, 0x995e1edf, 0xe39955fc, 0x33af7feb, 0x238315d1, 0x0cc1992b, 0xb2e68405, 0x3813b38f, 0xa380ece2, + 0xee2f0543, 0x60ec9262, 0x3b64b102, 0xeb278114, 0xd72e289b, 0x06c0b20e, 0x7239e577, 0x8613e1c9, 0xf1f5792d, + 0xd4b9c6a3, 0x963ffa00, 0xc8f22d61, 0x4d42a033, 0xdcc72405, 0xb55b7407, 0xd43450b4, 0x4c177200, 0x95b2f572, + 0x79686e33, 0x33eafcc3, 0x16de94f2, 0x3623320c, 0x4f532536, 0x32573813, 0x57c5824b, 0x22645f3c, 0x4662b4dd, + 0x30a54064, 0x6a16359a, 0x22d07103, 0xa94b6786, 0x56603213, 0x41ff6c2f, 0x0e17ba1e, 0xe1a84fff, 0x253f2fa0, + 0x1bca480b, 0x9e21239d, 0x6429e2f7, 0x1bc7bd99, 0x05b70708, 0xa991f02d, 0x1f7febda, 0xf83d3320, 0x7e7fa0a0, + 0xaf06e5f4, 0xe736a11b, 0xe94ddc0b, 0x43ec7b84, 0xe4f8ec31, 0x3589c155, 0x466741f1, 0x98a23ae9, 0x38b8d3d4, + 0x3b70459b, 0xf8c4c021, 0x01b89c7f, 0xd27c63e7, 0xf3c9703c, 0xeed502f6, 0xce92f7b7, 0x47b7ba55, 0x7dede31e, + 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, + 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, + 0x11e80584, 0x3a49181b, 0x01877253, 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, + 0x7b06c1bd, 0x241bb5d3, 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, + 0x6a39fefc, 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, 0xe97476ff, + 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, 0x6bc54667, 0x5da05bd4, + 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, 0xa18cde24, 0xa865edcd, 0x4a0863f2, + 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, + 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, + 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, + 0x9d3fcbd9, 0xa2157e5f, 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, + 0x8430e9fe, 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, 0xcff88a4f, + 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, 0x027ff968, 0x7c059f38, + 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, 0xd8861fcc, 0xa171057c, 0xc650cd2a, + 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, + 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, + 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, + 0xd2063aba, 0x38356c3f, 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, + 0x1c1010ce, 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, 0x52f9037c, + 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, 0x49c20c19, 0x5283a436, + 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, 0xc2223c9d, 0x99554000, 0xcd28bc49, + 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, + 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, + 0x553e3c53, 0x4ff910a9, 0xb16d9d48, 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, + 0x1ead51ac, 0xf531936c, 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, + 0xd81a58c7, 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, 0x5bf25e25, + 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, 0xc806079c, 0xc684f5d5, + 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, 0x4adb2b92, 0xf781402f, 0x870c8ab5, + 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, + 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, + 0x5d7847cb, 0x800a7cd4, 0x2174ea30, 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, + 0x2e1cd1e9, 0xc7308954, 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, + 0xb2b5f06d, 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, 0x8692254d, + 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, 0xdee4891d, 0x83247a45, + 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, 0x3e9a6812, 0xb7981ce1, 0xd48dac33, + 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, + 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, + 0x79d4b7c0, 0x4f0d800c, 0x6615417d, 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, + 0xb2213194, 0x520c5c4b, 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, + 0x4dbd49c2, 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, 0x7fd1b105, + 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, 0xc844714c, 0x83a50459, + 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, 0x795f7841, 0xa403bc22, 0x95959ab1, + 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, + 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, + 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0306.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0306.h new file mode 100644 index 0000000000..5cbec867fe --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0306.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1110_transceiver_0306.h + * + * \brief Firmware transceiver version 0x0306 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0306 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x8d8c69fe, 0x0d79ef17, 0x807d337d, 0xdae2dc5f, 0xcc13b1f8, 0x25af209f, 0xc57008e9, 0x702387b8, 0x517e2566, + 0x94f3fac6, 0x2118e221, 0x5a79db38, 0x19a44320, 0xde794ede, 0xbc3da658, 0x54bcce06, 0x757d146a, 0xa68e58f9, + 0x5490ff42, 0x34c5e66c, 0xfd2ea920, 0x3bac5348, 0xdca339e6, 0x77b63219, 0x1ab4a379, 0xd5386017, 0xef74efc3, + 0x3714aa01, 0xa4db5690, 0x118557ab, 0x0c8af131, 0x9909df82, 0x2204d0b0, 0x99fcd238, 0x27d3c267, 0x811eeb57, + 0xc4d26c2b, 0x98334271, 0x3c0c53e6, 0x146b21ba, 0xe4f15f54, 0x7361a6fa, 0x879ad11e, 0xfd14e3df, 0xcd396128, + 0xb2050916, 0xb935daa2, 0xfc5dadb7, 0x874e8911, 0x450b5aea, 0x273aad4c, 0xe4e45d3f, 0xaa7a96ac, 0x88fabea9, + 0x4cb23815, 0xfc26d0c7, 0x41a6c6d0, 0x27c2caa5, 0xc4cbdc5d, 0x1c9507e2, 0x7418efd1, 0x1794c02f, 0x2537ac04, + 0xe4d1c834, 0x20fced6a, 0x754e28c8, 0x93cbd557, 0xdeb31d89, 0xb077159b, 0x42923762, 0x8e389bb8, 0x56f394af, + 0xe815e9b0, 0x91f18ecc, 0x52e7f5f8, 0xbdcdc480, 0x5aa94625, 0x0bf794f7, 0x06b673ea, 0xcb89f134, 0xdfd21c16, + 0xb27b4cad, 0x5a77b7a5, 0xd3e21ee3, 0x5e3ad0e7, 0xe4cb1297, 0x5e7eb0bd, 0x02168a95, 0x61d43f61, 0x54b8eda9, + 0x8f4150ac, 0x3c824d20, 0x74473eb5, 0x73c82cbb, 0xd4f1368d, 0xc3a17cb0, 0x69b9454d, 0x20331b3d, 0x5049efab, + 0x76472c48, 0xb802023f, 0x2ce971f7, 0xc13184db, 0xdff67a55, 0xc3c8036b, 0xa35e8903, 0x03544294, 0x0fd9f522, + 0x46eab4a5, 0xaa9bb202, 0x1eb729f6, 0xe2928efb, 0xe78b2cc8, 0x5277370c, 0xcacec353, 0x0a0c5375, 0x2b4ef904, + 0x84d192f8, 0x2178de10, 0xd22b2c0d, 0xaa51592c, 0x4e14a02f, 0x0f8c1501, 0xaf4cbfa1, 0x6194c60e, 0x47ac09a6, + 0xdd0a5ee1, 0x9e961736, 0x3e2ce289, 0x3c5bfca9, 0x0f14e557, 0x7f3a74e4, 0xf0b1e7a1, 0x0c6ee4d0, 0x49020688, + 0x63b41799, 0xe07b2287, 0x44e9fd84, 0x1d4b759a, 0x247fc9b4, 0xe89b3fdc, 0x6189c916, 0x0b999a10, 0x675b1280, + 0x7209656b, 0xf9050757, 0xa7ee5453, 0x3655ee4f, 0x4a407f9b, 0xb0752f79, 0x86e5594d, 0x268f62bc, 0x47e29966, + 0x71166faa, 0xbc5c4661, 0xef0513e8, 0xe9be0e96, 0xc6fe9900, 0x1e4ca6b8, 0x381edff4, 0xe7716702, 0x41ab11f2, + 0x4691b728, 0xd0effa68, 0xd18c9e64, 0xb00614a9, 0xc762f7a3, 0x14a99443, 0xcab9455b, 0xed15cf14, 0x1d5cd762, + 0x5e8cc2ac, 0x4f9b8bfe, 0xd9d8b5ce, 0x3669f461, 0x320b0e84, 0x1a512b1f, 0xaf21b6ff, 0xd5351f75, 0x0bb8e0c0, + 0xc101824e, 0xb78c20a0, 0x12d40079, 0x10e76f86, 0x63240e4e, 0x4f4abee7, 0xa9f59a0a, 0xe3ca149c, 0x53c20a26, + 0x57763ab5, 0xe38ff8f0, 0x0318817a, 0x16f76871, 0x9c5d4f83, 0xd9c7aee9, 0x9d307cda, 0x6b7b42ba, 0x6e03c929, + 0xbac87d8d, 0x8bc1abc3, 0xb5442201, 0x50841372, 0xc824a494, 0x854d837c, 0x12678064, 0x080948d8, 0x74adcd86, + 0x70152efa, 0x2503838f, 0x9ad83dca, 0x045355c6, 0x08d3752e, 0xdb46dc16, 0xc1f8ba80, 0xed4085a4, 0x6aa0d46b, + 0xe4b49c98, 0x117761ab, 0xeb37d1ff, 0x4ad3637a, 0x592d49c8, 0x1191887c, 0x2f96b316, 0xf530eb28, 0x41fe8547, + 0xe732282d, 0xb6652df9, 0xf5ae946c, 0x575c942b, 0x78804e97, 0x62fc7d53, 0xce8f4ac3, 0x0a45305c, 0x887f1956, + 0xc8a6afc5, 0x0e47ed8f, 0x08e333a3, 0xd08465a4, 0x8181f533, 0xe0416dce, 0x1c266304, 0x46c541b7, 0x23277b30, + 0x7948d3a0, 0x40485cb8, 0x4d83bcdf, 0x79adb2a0, 0x05d058f2, 0x1e5c9770, 0xdb11b973, 0x385d7e54, 0xc4e73867, + 0xa1e8c83b, 0x888afbb7, 0xbf26c583, 0x13fc259b, 0x440434cf, 0x6577ebf2, 0x8cec08f2, 0x3705d669, 0xcdb6df20, + 0x3442f712, 0x41160113, 0x586cccf0, 0xa7400dfa, 0xe9eb4837, 0xbf34742e, 0xfafef41b, 0x64136adf, 0xd9858116, + 0x5d0ac9cd, 0xb9a70a86, 0xa3a049b5, 0xda3fb926, 0x90bcb869, 0x963ba3df, 0xf1aa5cfe, 0x22747fe2, 0xacce692c, + 0x4c250191, 0x07128811, 0xefc5212e, 0x48b88c79, 0xf807b3be, 0xb7883b02, 0xb866eb35, 0x39687e9f, 0xde638242, + 0x7f435d06, 0x24997336, 0xf31e9394, 0xfc71a625, 0xc0ba220e, 0x4686b220, 0x0ed86ea8, 0x8563e46f, 0xc5bf1af2, + 0x8736fe2f, 0x9e8bff0d, 0x4d816e50, 0xc3dc0c90, 0xf246924c, 0xcde54a70, 0x2c9d3cd8, 0x6c83f562, 0x79781426, + 0x2c3392b3, 0x1e8abf72, 0x942b9a97, 0xe8a272a1, 0x016dabb8, 0xae0ed010, 0x0a2cbcfb, 0x2d6c705f, 0x054f55f6, + 0xa7695033, 0x34b1a735, 0x65df243d, 0x7542a63c, 0x27588977, 0xd7385a71, 0x8a7b88c0, 0x54e4fa2a, 0x245fa79f, + 0x36b7be0d, 0x382e274d, 0xfe708552, 0x30176c2c, 0x962dbb42, 0x6bf547b7, 0x76ec9a64, 0xa9c55ced, 0xd2ebce8a, + 0xdcfd3459, 0x4dc61db7, 0x2307854b, 0x24eb5fab, 0xd3d5ee47, 0xbfbb970a, 0xdd715ee7, 0x488f703b, 0xa0073b3a, + 0xa4ebc8fe, 0x0b3facfd, 0x2057865f, 0x37754e8c, 0x7dd4a391, 0x9a635b95, 0xb8613d01, 0x320da102, 0x35f7ea1d, + 0xe93ab7ba, 0xa8f506f3, 0xd9cc64ff, 0x9d2d1629, 0x39b71887, 0xcd1826d9, 0xef3e41fa, 0x8d9e289b, 0x81a01555, + 0xa42f1239, 0xe4a20174, 0x2abbc8f2, 0x01966ef0, 0xd3118ecb, 0xa2852ec5, 0xaf8b3149, 0x3c205022, 0xdcd1e254, + 0x6bd58cc4, 0x4eebb56d, 0x1833eee6, 0xa7a3da56, 0xedc2de47, 0x5a3262d6, 0xc603d90b, 0x025192ed, 0x8c1cfc9d, + 0x9fe6df2d, 0xfb9ee5ba, 0xe41c7b4e, 0x13fb6522, 0x012121d2, 0x3c1b5add, 0xc6e0bb88, 0x1fa12a8c, 0x5e29dbc6, + 0xb593b5ed, 0xcaf1e4a0, 0xd67e55ff, 0xf64e3105, 0xdf524d6a, 0xeaf123fc, 0x0cb68e6f, 0xf7d69b3a, 0xb634d64e, + 0xf97192c9, 0x7e9dcb21, 0x0da089f9, 0xe57bd463, 0xd50d02a5, 0x8a531b1c, 0x08cb6b05, 0x440d0e01, 0xf71d902e, + 0xb087be47, 0xfae78175, 0x34e53a75, 0x8f90ee2a, 0x1a08a5ac, 0xf3d9a8db, 0xb3f21c46, 0xc56f0999, 0xc4e724ad, + 0x27f6d68a, 0x7d0e8e5f, 0x32e6bf30, 0xcbaeb386, 0xf2dc7d40, 0x89c1929f, 0x8232cbb8, 0xb8160cc6, 0xd6f22cec, + 0x394dbaeb, 0xad273421, 0x986d3a7f, 0x93611bef, 0x4b372876, 0xfebb8d1f, 0x9e102e3a, 0x177e1c58, 0x1730a6ec, + 0x8dff4fb0, 0xd7c80be9, 0x6d4ccbe5, 0xe7945b66, 0x5826f5bf, 0xe36af450, 0xb65f3076, 0x62344f60, 0x80ceefa3, + 0x98e0e4be, 0xc3c44d53, 0x9633dc88, 0x35350c88, 0x09fd933a, 0xe5c19c5c, 0xfe79a633, 0xfb56d6a0, 0xb708b922, + 0xd385feeb, 0xd0c8d0da, 0xf492ee4d, 0x3bebab56, 0xa610fa11, 0x3b46aa73, 0xb9a0ad9d, 0xf25a694f, 0xa3c45b60, + 0x7d7c970b, 0x5fccf602, 0x4349e0bf, 0xed153023, 0x512f3bb5, 0xc21ad95a, 0x19c27a58, 0x49f1398a, 0x7989d837, + 0xc9a6226c, 0x8f00e284, 0x8b3bbaf6, 0xf67ba537, 0x29ac3425, 0x156b4495, 0x29096f9a, 0xe389307d, 0x62215f00, + 0xd48d32bf, 0x6c1f8a3d, 0x14b7e2f3, 0xcbeb71d1, 0xbded9997, 0xa409500b, 0xfe28d63f, 0xbc7649f7, 0x105bd562, + 0xe164c769, 0xce945902, 0xf8db2777, 0xa86ead87, 0x710bf19c, 0x5443219d, 0xc98977b4, 0xf8918811, 0xc124b706, + 0x996145a6, 0xbb573b74, 0x29ee1ee8, 0x1b8c1df4, 0xe6585944, 0xc0d91db5, 0xde35499c, 0x0af8af83, 0xb942f688, + 0x49c59249, 0x2232aa30, 0x6b84d667, 0xb7836911, 0xee42b2e2, 0x9e4a2f19, 0x125622b7, 0x147da1f9, 0x3a29f1f5, + 0xc46febc2, 0x10c37558, 0x39137998, 0xe42effa5, 0xa3c97a13, 0x4f48f6d4, 0x844e85e4, 0xfa8b2b0b, 0x63fed4eb, + 0x7a53f565, 0x8bd60496, 0x99a65956, 0x19878ccc, 0x0164ae49, 0x637e5d5e, 0x7f00156c, 0x91ccdc41, 0xe2662257, + 0xd3fec119, 0x77de22fa, 0x0d5e8b05, 0x7d1f7a13, 0xbda1e703, 0xe5c9d5dd, 0x69fc419f, 0x13bfedfc, 0xaae10cb6, + 0xf0744aec, 0x55a277f5, 0x78539c78, 0xecfad5d5, 0xda9e4a46, 0x6d17b9d7, 0x384e5dfc, 0x62a31052, 0x431b598d, + 0x865f90f7, 0xf1c012cb, 0x49fc2ad2, 0xe28c7397, 0x04e3d7d3, 0xc2c95dd6, 0x404b0f35, 0x1aa9d108, 0xee474d3c, + 0xb859030e, 0x58ecdbe6, 0x05cd7792, 0xa031f730, 0x172bec35, 0x0801dbeb, 0xfc42117a, 0x58a37c51, 0xf8f95d6b, + 0x5beff029, 0x2cc44095, 0x0a609a24, 0xe8a19334, 0x8906639b, 0x4a5137f5, 0x220f9cfd, 0x5e6ef29b, 0x1c963ad8, + 0xea682aaa, 0x4acd39d0, 0x5c48f2d5, 0xfc327a25, 0x2f841f49, 0xe126d9d3, 0x72659669, 0x4aa9090c, 0x162fa6ee, + 0x4158f523, 0x5e3ef6de, 0x412abdb6, 0xc732cd99, 0x6472dcc5, 0x9fd1937c, 0x983b76d9, 0xf3d15adb, 0x36c78dee, + 0x6c20e3d9, 0xe344d28f, 0xaf474be1, 0x9772052f, 0x2db0d013, 0x77558dd1, 0x92e9a135, 0xbcb94a98, 0x54e06205, + 0xee06c3db, 0x65e4940b, 0x9ae54773, 0xf9fb4f96, 0x54cfe1b9, 0x52daad88, 0x35272be4, 0xe38d35ca, 0xf9ee6af9, + 0xbd308f6e, 0xf565d2e4, 0xa9b181e2, 0x8f83fad6, 0xa887a08f, 0xc9fcadda, 0xfc7b5d21, 0xcbf6824b, 0x6e872c88, + 0x08b1cd5c, 0xb2cc2645, 0x8a8c4196, 0xbae3d250, 0x5beedea9, 0xebd0ff01, 0x6e24eea4, 0x3eff7429, 0x7e2a2653, + 0x8645bd22, 0xa6d5bda1, 0xc02f75ac, 0xed261dfc, 0x7f76ce9c, 0xcdac6906, 0x0a7eb46d, 0xdf808b77, 0xd770c4ba, + 0xcc5353dd, 0xfd2c08cc, 0x65e88519, 0x7d4898b1, 0xb490c194, 0x07755768, 0x94e3fc6c, 0x6fe2378b, 0x7bff77e9, + 0x6308fad0, 0xee74827e, 0x4b5d9087, 0xa34be938, 0xfd320a37, 0x914be728, 0x7b6854b0, 0x0a968fad, 0xc369e55f, + 0x4d8a248a, 0xdce28b63, 0xe00de9bb, 0x53f87fb0, 0x2f5e6f12, 0x5742f9cf, 0x7b5161ab, 0xf7518929, 0xc880bca6, + 0xdb6c7f23, 0x6cffae31, 0xfb882c74, 0x3fd960f1, 0x505edefc, 0x44588cb6, 0x0c430604, 0xc14c6d39, 0xbadce9c1, + 0xd426e32c, 0xeafc49c4, 0x04c2c9be, 0x1b91b9c3, 0x12507f2b, 0xcdff114d, 0x971bfe72, 0x5489c2ff, 0xe33cfc93, + 0x7f6e96d7, 0x7adc94ec, 0x62e9fe79, 0xcd617801, 0xe9381623, 0x89619707, 0x8ff24973, 0xb9682714, 0x3b608880, + 0x805f1cd5, 0x7bd6d007, 0x62f414a1, 0x74b05392, 0x8371f590, 0x86594819, 0x86933249, 0x186ee98b, 0xec1550ff, + 0x8349184b, 0xd2243d7e, 0xd0485af1, 0x67078d11, 0x6b95275d, 0xa5d737ec, 0xbd4e07c3, 0x0e5e0b26, 0x945e2cae, + 0xdd7daef1, 0x022c7a2f, 0xeb6b8cd6, 0x284bc377, 0x740f7745, 0xe921563b, 0xfd8bc566, 0x067bdcb8, 0x4fd91418, + 0xfad8141f, 0x89f23bb1, 0x67bdb7a6, 0x213ace90, 0xe9d89160, 0xc9f3fae7, 0x6a0e4865, 0x757fef91, 0x445c61eb, + 0x822ad358, 0x355071cd, 0x429247c1, 0x97458f01, 0x84f82e2e, 0x81c7bfa6, 0x5408f355, 0x0aaea394, 0x07b8916b, + 0x4a4ff2b4, 0x56d5fbec, 0xba4bd7cd, 0x2ff77edc, 0x8dbf8bdd, 0xf2c12fde, 0xfaf116c6, 0xa67f1f77, 0x3048c108, + 0x71f76e1b, 0xcf4b6a23, 0x485c8ddc, 0x2d673cb1, 0xb6932b50, 0xca03a8ad, 0xad3584f7, 0x732fbb57, 0x75204ffa, + 0xd885d06a, 0x54ce36cc, 0x891efe37, 0xc8094ce8, 0x9309638e, 0xa67999b3, 0x13f517a0, 0x07cfb9ad, 0x1e12c9e6, + 0x8a3d242c, 0x06f9e62b, 0xf7e89569, 0xdc26ab49, 0x980f87c0, 0x8a662643, 0xb6a80f25, 0x1d877eb8, 0x7f347898, + 0xd5c0dc91, 0xedb56c83, 0x31e18e3a, 0xb3b2cb8a, 0xaa025285, 0x173f5171, 0xdc6aa954, 0x35c8398e, 0xb6031c39, + 0x404bba76, 0xae4919d3, 0xbedaaf1f, 0xc37d9a54, 0x813f478e, 0xd3801619, 0xad29c1df, 0xd68e1143, 0xe8bc0c70, + 0x513ffee4, 0xc3ff5f19, 0x422fbee2, 0xc48dc0f9, 0x1e708d2f, 0xbb44b00b, 0xb052219b, 0x284c8244, 0xcd998424, + 0x44a42cad, 0xfa7faa81, 0x5c04a9e1, 0xe086efa4, 0xd43399ab, 0xfba43078, 0xd2b081df, 0x54ab7f85, 0x6965e29c, + 0x70894a65, 0x57336996, 0x1c1d1ce0, 0x80b3944f, 0x46c6202b, 0xd3e7c90b, 0x6a86d9c9, 0x30462c43, 0xd79a8db3, + 0x10af7239, 0x6979bc16, 0x659bb567, 0x8b0642fe, 0x784e473b, 0xbcf0567a, 0xe1f07337, 0x39323233, 0x0d8efbce, + 0xc763cd44, 0x37940951, 0xfa118a7f, 0xa03046db, 0x1bc13b51, 0xc24a5db5, 0xdfe9312e, 0x00220f16, 0xe5d91e1a, + 0x35438e02, 0x1d1b41f1, 0x2e483a33, 0x2e00698b, 0x4dd10585, 0xf51327a6, 0xd038ad85, 0x86070183, 0xb34f9099, + 0x27a4c553, 0x995e5f38, 0x42b36584, 0x463f6410, 0x168d3273, 0x6e0fe70a, 0xf38aee92, 0x3b1317bb, 0x1c3ee3bb, + 0x2a2bb18b, 0x32272006, 0x14a71470, 0x94244b21, 0xe9ef2ca0, 0xa20a6ecc, 0x13206cf4, 0x54606d9d, 0x02cbbbaa, + 0xaf8cfa18, 0x43e28da5, 0x76c8aaf5, 0xc4738569, 0x7bba0422, 0x17f47430, 0x1de1e536, 0xffe31fe7, 0xeea64e6d, + 0x5e0a7b75, 0xf9a6dfe8, 0x13010634, 0xab657b76, 0xf1253e34, 0xb81b0684, 0x57f76882, 0x774437b0, 0x70b736c6, + 0x8b7270d2, 0xa61f31fe, 0xad763188, 0xad5a5fda, 0x2df7b88b, 0x33d5bcb9, 0x9550f7a9, 0xaaa0229d, 0x28e88acb, + 0x9234e5e5, 0xd01965b8, 0x08027ba1, 0xd32afaa4, 0x53894061, 0x0429b755, 0xf3b82731, 0xfd767200, 0x998a6421, + 0x68d68956, 0xdd3c6cc1, 0x29a04b23, 0xf97adae1, 0xbe021251, 0x8c46b675, 0x058fa5f7, 0xe436ee1f, 0xb8276afb, + 0x74fbbbae, 0x413cd2a8, 0x6ab94340, 0xd83ed371, 0x92c96626, 0x6d9bd129, 0x930c7f6f, 0x6381390f, 0x3a8c725d, + 0x4727b343, 0xcee730bc, 0xe937929b, 0xf53c201c, 0xc163c8b7, 0x9b1d1b5f, 0xcb657bb9, 0xf900e1c3, 0x119fb088, + 0xb58a34c1, 0x4bbe3514, 0x7af97f64, 0x8f146c23, 0x9ed6cef1, 0xd2c8d79a, 0x30261411, 0x1c97bee9, 0xfaa14760, + 0x0ba71c31, 0x347a36e1, 0xb74910ff, 0x7393cd94, 0xd2afc544, 0x6c4db6f3, 0xba51e12d, 0xd3049ca2, 0x1aa92c68, + 0x266f5bfb, 0x9c2af0b4, 0x77b64f9e, 0x4fd7269b, 0x86615c7f, 0xdebdbd83, 0x8cda3c6a, 0x0a7d79aa, 0xd56c5f0a, + 0xd8c4e56e, 0x4d0a17bd, 0xe33938ea, 0x35722e8a, 0x16bb769c, 0x5fbe5d6d, 0x5aafdaaa, 0x159175ff, 0x2722a46e, + 0x4be492ee, 0xc3fcf92a, 0x13e28dff, 0x7298e2be, 0x8a5ace20, 0x9f160c99, 0x6f5015f1, 0x30b1182f, 0xfdd63e1d, + 0x48ae5d54, 0xe42af1e3, 0x8f8911dc, 0xecf5c962, 0xf06b83de, 0xf572d6b7, 0x3c13d9c4, 0x6d8a2300, 0x6bb35a10, + 0x38fb2fed, 0xc746f6f6, 0x22eb20c9, 0xda3109e8, 0xe6145eb1, 0xa3b00199, 0xc8591951, 0xe930d99f, 0x6618205e, + 0xf7534777, 0x1430e198, 0x3cf2a376, 0x75c9a111, 0x16ef3387, 0x4d279576, 0xef0ca591, 0x42dd6f81, 0xcfe32141, + 0x235394c2, 0xd3565c4d, 0x1807c7a4, 0x2c036ca3, 0xd560e9a9, 0xe1cdd7b1, 0x0c8d0e92, 0x85b8c61c, 0x41a65c9b, + 0xd6e2ed83, 0xbd2a1f05, 0xca5cc960, 0xa3324b02, 0x3197ff00, 0x8f38e69c, 0xf74c8773, 0xd677fc90, 0xdea10704, + 0x7ff0423e, 0x86854dd4, 0x49b90a88, 0xf98dfeaf, 0xee001370, 0xa0862e8c, 0xfc6f90c4, 0x93c94796, 0x66fc7336, + 0x2654161b, 0xb5c1af4d, 0xc15ca32e, 0x26ee653e, 0x16d7c542, 0xaaa6b414, 0x09a7883b, 0xd94a6986, 0x8737dcfd, + 0x97d2625a, 0x0cf1c7e0, 0x97fd0d74, 0xd925bd08, 0x67ee020b, 0x19342be5, 0xe8e828ab, 0x1d892597, 0x141d1c5c, + 0x71186b1f, 0xf897d223, 0x70ffe534, 0xf9b811e9, 0x18b2ddd7, 0x3d74efc2, 0x19df61ed, 0x4d488d0b, 0x4c09656a, + 0xc83711c2, 0x724184c1, 0xef3c6620, 0x94d97bf3, 0x0b17b7bb, 0x4d8086c6, 0x6bb11ec0, 0xd52852bd, 0xa296bc26, + 0x04dd02e9, 0x4bb86d8e, 0x153a3802, 0xd2fb89d9, 0x534a50d7, 0xa60df23f, 0x42ba4cbf, 0x4fa430d3, 0x25b3da41, + 0x004231ed, 0xc19b2616, 0x3eeb646b, 0x85b22227, 0xccdf1ab5, 0x6c2309ec, 0x8a0af86d, 0x3843bc2d, 0x6f83db6d, + 0x1565c15f, 0x3c117e2b, 0xcddaae16, 0x5cf3a105, 0xf1c766ea, 0x4f79f406, 0x2a76f1bd, 0x8aed4525, 0x9fa34ff8, + 0x3fd79236, 0xf7027e0e, 0x726288c1, 0xc00e7cc3, 0x9ccbc366, 0xd931bcea, 0x2d61be3a, 0xa3ce50b8, 0x1923d306, + 0x0d68297e, 0xfd74bd94, 0x5345914b, 0x4b3c5a51, 0x7588a424, 0x097fdc50, 0xcd6b046a, 0x53b39441, 0x03083f35, + 0x8fa6ec26, 0x7bc65a0d, 0x9c075034, 0xe0aa8749, 0x44bd00dd, 0x8f286836, 0xe69ab4ff, 0x0681a0a6, 0x2af40639, + 0x760a060d, 0x13c57db8, 0x24c26672, 0xbae060c3, 0xffb7d395, 0xd4b1f494, 0xbb1a905b, 0x65986f5b, 0x1653c1b8, + 0x5605daeb, 0xe0880f7e, 0xe218aba9, 0xd77477ed, 0x186cd7be, 0x002fa538, 0x2ccf01ea, 0x166f8a89, 0xd90ed1a3, + 0xe300ffe6, 0x3dc3ae58, 0x301ba64f, 0x345f7e34, 0x78edf844, 0x17a23ce7, 0xa4781b4d, 0xebbdb357, 0x0b960aa0, + 0xee63c1ab, 0xa4ca057f, 0x9699c00c, 0x441f6545, 0x9fa6baed, 0x635fed86, 0x9cbedc7a, 0x7dc148be, 0xa1f06d81, + 0x6118a206, 0xc6155f8c, 0x4d185e77, 0x63f8913b, 0x15621d0d, 0xef152c58, 0x9e0e93d0, 0x532cd706, 0xc6ce8ac9, + 0x5c4006ba, 0x2c6e1bcb, 0x6a907056, 0xea84dfcd, 0x6f93d855, 0x34dc4d1f, 0x4dc77b62, 0xa7d4a8b4, 0x7e00250b, + 0xfb02fa58, 0x0c2da933, 0x435fb3da, 0x82cf2875, 0xf663d1bf, 0xb44a6e45, 0x46f6918b, 0x6e731117, 0x84169048, + 0x72e621ac, 0x5419191e, 0x2ac745f8, 0x7b9de817, 0x2361581f, 0x0d468227, 0x900d77ed, 0x3e4ed9ae, 0x516f5fa5, + 0x51cfe4a9, 0x443d7e45, 0x6306fdd5, 0xdab4ea97, 0x30cd08a0, 0x9d821f6c, 0x82ba0b51, 0x96fe46c8, 0x83d49a6e, + 0xf2d08541, 0x8b6aad93, 0x474f6695, 0xedc5bb13, 0xa575361c, 0xb4557417, 0x6ecb61a3, 0x84f7e60c, 0x4a0f5163, + 0x8cdcb3d1, 0xad9124c0, 0x890c3d9e, 0xbf169b3c, 0x720e7602, 0xf1fa54e1, 0x6b818d42, 0x44d8e955, 0x86664bc6, + 0x90377c22, 0x22382fbe, 0xccf418c5, 0xf838c0dc, 0x946b1d66, 0xc11be40a, 0x7a151938, 0xdc4336c2, 0x28c43eb2, + 0xc1f12298, 0x98cd9669, 0x166880cb, 0x84cffc47, 0x37c84d89, 0x1889a4cd, 0xdf2ce016, 0xded06116, 0xfae867c5, + 0x8d23d06b, 0x827dacf8, 0xfd11d25f, 0x68485ddb, 0xed506883, 0x43c5e555, 0x0330a16f, 0x3f7576af, 0x5f70c716, + 0xf298b8ce, 0x9e1df62a, 0x46fa9d88, 0xb06e68d0, 0xc3803412, 0xe8ba5d5d, 0x615d8c71, 0x1b0d6c3c, 0xb638706b, + 0x187d6983, 0x0e33f64f, 0xd9dd7778, 0x12410a8a, 0xcef7eda5, 0xfe74e21e, 0x60b70fc5, 0x8ed94fa2, 0x6cfde259, + 0x8058b411, 0x1ca93807, 0x19625c5a, 0x34215cec, 0x165baddc, 0x0ab44f83, 0xa6363e74, 0x3f7a766a, 0xdd702a61, + 0x3d0ca687, 0xd0909c3e, 0xdc7f7712, 0x3d9001ea, 0xc5d19495, 0x8017b1f6, 0x65da0eed, 0x0d030d48, 0x998c10e6, + 0x06f1c97d, 0x35204b05, 0x1c0da754, 0x777b48fe, 0x01521640, 0x203bfb59, 0x25e83cfa, 0xa3d40b91, 0xf396bd60, + 0x093880c7, 0xd5a77950, 0xe06ddcac, 0x87936f25, 0x12c7d991, 0x16103a0f, 0x4a1ee98c, 0xf70e1c84, 0x2f3f894e, + 0x176c0300, 0x34c08cc6, 0x89eff014, 0xb7d5666e, 0xf7636a27, 0x128ece3c, 0x71e7ddb6, 0x1070d4aa, 0x2dab9a05, + 0x3cdc279b, 0xe88781cc, 0x2771abc8, 0xf01d6e74, 0xe8cc296b, 0xeaafe927, 0xa3b3e542, 0x872acfc7, 0x4033a228, + 0xa922a98c, 0x82b18f3b, 0x6d5efbb5, 0x31d13a83, 0x6c4a1b1e, 0x7d5df44f, 0x539dfd5d, 0xda1e186b, 0x60f6948d, + 0xb4c2bb13, 0xa903a2c4, 0x76a5595b, 0xb85fc368, 0x87e3c57c, 0xeec8ee07, 0x39f42e4b, 0xdc13d659, 0x03ac1daa, + 0x123bab9d, 0x7789dec0, 0x5dba0ba3, 0xcee72d9f, 0xea4aa38f, 0x315633a7, 0xff276fb0, 0x0468ef67, 0x7fb82124, + 0xeb586ed5, 0xcdadda70, 0xb37e12d8, 0xe4411b87, 0xc740e4f5, 0x41ca5e11, 0x8e54997b, 0x023d8b2c, 0xda4cfb4e, + 0xee115485, 0xf9a61a29, 0x98aefaa4, 0x2523432a, 0xcfa165ae, 0xc2b7231b, 0x0921e4f2, 0x0ce01bd4, 0xe148db74, + 0x72c2ea66, 0xfa451b82, 0xc8a46a20, 0xeac8684c, 0x6139fca9, 0x6168529c, 0x05fe9b49, 0x9c474c27, 0x04a5183a, + 0x66cc414c, 0xfc6edea9, 0xb66c551b, 0xa56f05e4, 0xf979d70c, 0x07cc94b9, 0x312db988, 0x84f59bc1, 0x8bd27922, + 0x71487c6c, 0xc9e1cfb6, 0x9aef07cf, 0x611a82d2, 0xfe70f5bf, 0xd835444d, 0xcd319833, 0x28fb2d06, 0x97eb7579, + 0x39ffea70, 0xe074fe09, 0x3794cbb0, 0xc3a83724, 0x90b69daf, 0x36ffb885, 0xaac9bfd9, 0x5b93aa8b, 0x34183f26, + 0xacac0307, 0xd03e1b22, 0x9a86c004, 0x273f4cf0, 0x3a129fef, 0x81b546af, 0xe9362ee4, 0x3f7cbe67, 0x5eb11348, + 0xaf00dbbb, 0x6e59e9e0, 0xcf373509, 0x09ada769, 0x6c26dab0, 0xca062faf, 0x1754617d, 0x5eaccb37, 0x63d7eebc, + 0xde875b0d, 0x8415067c, 0xf548972c, 0xd23b784f, 0xf60f1f8f, 0x864ea4c6, 0x7faf3a89, 0xf9147765, 0x17566942, + 0x269f178f, 0xfa5e9841, 0x9ee0d8fa, 0x95d1cc47, 0x8835728e, 0x1c5d8b17, 0xe22a97fc, 0x7e8d4d75, 0xa1c8d523, + 0x792302fd, 0xf281d1d5, 0x2a0f46c8, 0xa77c23dc, 0x5fe5f0b7, 0x73646cd7, 0xbddf3dc0, 0xc9a7186b, 0xca3e47eb, + 0x5bce6956, 0xa4552b5b, 0x75353efb, 0x2f921894, 0x2db87ed0, 0xa03622fb, 0x157dbaa5, 0xdf07e698, 0x3fbfe102, + 0x473148f2, 0x7aea72b6, 0x64af705f, 0xb03b9474, 0x5405c6aa, 0x6b13c339, 0x79e482d0, 0x6804e098, 0xd8b7925c, + 0x719f3c5e, 0xbd37e79f, 0x639e16f7, 0x95d448d5, 0x91cf7e35, 0x8f7f38d3, 0x7f9b1650, 0xc141cecb, 0xaa6311bb, + 0xf6d85c1a, 0x2eb84045, 0x1f94e005, 0x11615d13, 0x6d2520fa, 0x41fb6e86, 0x7e7544d2, 0x8ce2205d, 0x154b4834, + 0x3e32d867, 0xabbe29a1, 0xb3b3e0ff, 0x45eb03dc, 0xd2cacac4, 0xf0a02058, 0x2b018327, 0x7ef5a280, 0xaa21db4c, + 0x783369db, 0x7c421490, 0x6f69fb6c, 0x6cfab757, 0xb3cffbb9, 0x245dec02, 0x5d7441b2, 0xb7ec0a3a, 0x2967af2c, + 0x67469c95, 0x7df543c3, 0xde97ccd9, 0x69c4a1f2, 0x836a9af4, 0xb45df9b5, 0x64197bdf, 0xe6da6b4e, 0xaae43a9a, + 0x1bc35ebb, 0xb7bd8443, 0xf9c1eca2, 0x167a19fd, 0x59d4bc08, 0x5fb3a6c1, 0x3eb4983e, 0x741f08ad, 0xe1be7883, + 0x456f90be, 0x0eecfc09, 0xd62f4714, 0x528a4f85, 0x953afbf3, 0x618392c2, 0x7617a8c5, 0xde6ba3b3, 0x196fd803, + 0x035f771c, 0xfdb01787, 0xbab599a8, 0xc3e82305, 0x6aa17802, 0x67d3a855, 0x8eee715a, 0x003eb2f7, 0x153537db, + 0x29095460, 0xc4594d5c, 0x5d8f91aa, 0xc51b8229, 0x92609683, 0x390ae3dc, 0xee90b0b8, 0x197ff3e3, 0x22a7b3e7, + 0xb8d0bdfb, 0x498ec358, 0x934fd511, 0xf320996e, 0x6e270f5a, 0x625ea059, 0x58519d36, 0x9bb03610, 0x7d8e385e, + 0xef3f3445, 0x0330581d, 0x53ed9ad7, 0x28bb9f34, 0x7e740157, 0xcaeab174, 0x0a8d9eb4, 0x9a067eb1, 0xe2dd8a16, + 0xe73fe56b, 0xe9298f8e, 0x0568dfd3, 0xb5f0e1d6, 0xde62564d, 0x6bed5c63, 0x2ca944b2, 0x42bf299c, 0xd5ae25ef, + 0x4101e9cc, 0x891161ed, 0x9594a3b2, 0xac137772, 0x189030c0, 0xfd4bb1d3, 0xf1544f21, 0xaa25a34f, 0x23921615, + 0xc4864a67, 0x56eb0815, 0x14775155, 0xae879945, 0x9a6f194c, 0x6a7a5d65, 0x50ce1303, 0xf29c7553, 0x6cd56673, + 0x9f650f82, 0xf58726e1, 0xb46e5424, 0xadd2c70d, 0x4af16143, 0x85d3a462, 0xe7120157, 0x885cf38f, 0x71e34022, + 0xa50450e7, 0x180bd720, 0x0bee8a60, 0xa7875723, 0x93613eeb, 0x89f6c240, 0xf0aa191e, 0xd8214885, 0x01e8b61e, + 0x88a959f1, 0xba6d5153, 0x8eaeac50, 0x551d76bd, 0xf0ca58c8, 0xa2f9941b, 0xe00452b7, 0x0bd98203, 0x545a2ebe, + 0xee851950, 0xd8f68cc1, 0x94150932, 0xd3bcfd82, 0x1fe50112, 0x99c14e40, 0xc9b73001, 0x89b894d6, 0xb69228c1, + 0x43020bc9, 0x0df16931, 0x283d79f0, 0xc649ef68, 0x2b24688d, 0xe62310b4, 0xb0b790f7, 0xe5af1a73, 0x2d529f11, + 0xabf49c86, 0x43812889, 0x6daf3709, 0x9d50e133, 0x19f51b6f, 0xade48ebb, 0xa377fc22, 0xfcf54083, 0x743c57fd, + 0x022bc0c9, 0x9ef97cef, 0xe37380a0, 0x755d296e, 0x18a340e9, 0xb32167f3, 0x80cbf8aa, 0x6d5fe0cb, 0x94d7910f, + 0x5048121e, 0xc71f811c, 0x9267849b, 0x5f3bd62c, 0xe99ed21d, 0xae7ca008, 0x14b44101, 0xc6b07a55, 0x95305c85, + 0xc91897ce, 0x4607c847, 0x2c076353, 0xad3b60aa, 0x4f3f6826, 0xa6787205, 0x17640780, 0xb1e52b4c, 0x84394521, + 0x196ed950, 0xaaf91281, 0xb33f4827, 0x54e602ed, 0xfa40f437, 0x2083a596, 0x6f540481, 0x5b5fccf6, 0xc658ed81, + 0xe42f593a, 0xe139fb48, 0xbf01e140, 0xbdcc1d80, 0x4b3287ba, 0x890bf8d4, 0x23aaa684, 0x3d15b4b8, 0xe27c712b, + 0x44dff4c2, 0x86bca452, 0xc3cea5b0, 0xfd9bfd9b, 0x9e376c39, 0xac43bfa9, 0x503292a3, 0x1fd11bbd, 0x1bcf75c6, + 0xae368396, 0x2f8e5d71, 0x95bb02d0, 0x4caa0007, 0x9f59de37, 0xc9bc8f47, 0x10302e69, 0x850c97dc, 0x9a468c78, + 0x3adfdeaa, 0xe568f04f, 0xab4fceb4, 0x3e731aef, 0xd8ffac48, 0xc75a5289, 0xc32b7b0f, 0xbdc12a20, 0xf69464d0, + 0xc63b78b5, 0xb3ed2c25, 0x3d2bac76, 0xefb9c6df, 0xb7f7cb6a, 0xf5cb469d, 0x6eabd242, 0x5ea70ad6, 0x7cb999f0, + 0x2870a589, 0xe7c7ca90, 0xc2fbce52, 0xfe4f9063, 0xd5dbff2a, 0xc13b8a3c, 0x5b585736, 0x5a4ea316, 0x4148ae16, + 0xd7c03998, 0xec723bc6, 0xe62f1962, 0x85fb402f, 0x5cc9948c, 0x59cfac55, 0x68528eee, 0x875f70b8, 0x7b28094d, + 0xd0f8fca1, 0x72771a92, 0xb51c24e2, 0x1257d17e, 0xa646ae5f, 0x75171beb, 0x212297bd, 0xbfaa9ecd, 0x518c1d65, + 0xe09f7b6a, 0x62ca5758, 0x4442d549, 0x13f67d83, 0x695a59ff, 0xce62eaa2, 0x1de98a77, 0x38149cd7, 0x21d16739, + 0xe7c4a6ff, 0x64a08652, 0x496af47a, 0xf8fab8e1, 0x3abfa465, 0xc9902c26, 0x1ece20d4, 0x6d8d3b31, 0x779584cf, + 0x5d27b862, 0x47f329a6, 0x70aaff3b, 0xfda9db92, 0xaf30ae9b, 0xe4da8c2e, 0x01958b93, 0x4c612363, 0xa04ff51c, + 0x79ee4079, 0x612d503f, 0x03eadf9d, 0x1a0b270e, 0xfecde124, 0x7310320c, 0x4b5ba089, 0xd9b685fa, 0xe1c550b2, + 0x04e9af67, 0xeca9c9cd, 0x8da38f2a, 0x4f9614ca, 0x4b5dc145, 0xd11eeb3d, 0xe6fb9347, 0x179c060d, 0x2d3b49bb, + 0x63ada9c7, 0xa16aef66, 0x0cdd20b9, 0x529d9003, 0x5eb0a267, 0x9347b3fa, 0xf7ded177, 0x3f7d675d, 0x7d75fdf3, + 0x8a030e34, 0x67edd63b, 0x3d6e1f72, 0xec49614d, 0x0d8c5075, 0x74f4a8d3, 0xdf3aac4f, 0x524cb87a, 0xc14fefe7, + 0xc463e881, 0x528b3e91, 0x98e68da4, 0xfd6f71e6, 0x1b12b7b9, 0x662d3844, 0xeac7e74e, 0xe49165f1, 0xf27c697c, + 0x0db04844, 0x619da7fb, 0x589f0285, 0x05cfce0f, 0x8df4249c, 0x2a9d03c3, 0xd1b63979, 0xb5e611ad, 0x4b624e97, + 0x43b79c8b, 0xb8672abc, 0x6e409ba6, 0x4911d9c0, 0x6e62f54c, 0xf30d2338, 0x4636c4ae, 0x4c08f0d8, 0xf2aad7b3, + 0x1980c84b, 0x4fdbc117, 0x54991155, 0x2db6a9b7, 0x87781852, 0x69e03c5f, 0xac05435f, 0xa727b944, 0xd12ab07a, + 0xe9b3c2f7, 0x72deac1a, 0x32d86e81, 0xf3d6b85d, 0xa84a41ba, 0xeeb4907e, 0xb37aa9c8, 0x3128429b, 0x43e6943d, + 0x352ba4e5, 0xb2297a57, 0xecac7bea, 0xcc0af3b0, 0xbecbd483, 0x58960d9d, 0x2a152a8b, 0x1f0675d6, 0xc1d12149, + 0x1de1e78a, 0xd827b4c9, 0x508623ee, 0xfca04a41, 0x799d49a0, 0x7e6a4c76, 0x36f5b7c4, 0x9604ffa3, 0x1a73b899, + 0x604c6c5f, 0x93af772e, 0x42cb4682, 0xf4fc9b96, 0x3b479cdb, 0xb0305323, 0x8c8f18bb, 0x11b224cd, 0x2032aa08, + 0x3e12968a, 0xa8a74652, 0x53d8b1e2, 0xe3e3bbfa, 0xd8e1565d, 0xd3960d41, 0x507646ca, 0x819f7974, 0xda18a84c, + 0x6959d95b, 0x85604dc3, 0x3d37cb41, 0x9642c5e4, 0xeed48e09, 0x8c62fdcb, 0x2d1919e2, 0xc487e9d6, 0x6f7d5751, + 0x37bc5683, 0x08c8ec16, 0x087a5541, 0xcc6436bc, 0x26e378a4, 0x7533652d, 0x54868f3a, 0x502aab88, 0xe7fdd2ff, + 0x26a43bdf, 0x086c7de2, 0x4d2ba533, 0x51f6a4f9, 0x812c6f59, 0x4df1e484, 0xdfeb4995, 0x168ccd7b, 0xd555b12c, + 0xe66e71e7, 0x27c0dadb, 0xde5a1c54, 0xda71ef6c, 0x5aebbc35, 0x502be540, 0x2392f2e1, 0xc0a9b39e, 0x7dec3c45, + 0x9549e09d, 0x5c22d405, 0xff468787, 0x3d17dc22, 0xd30cae0d, 0x18832f36, 0xc80a667c, 0xdcaabde6, 0xf00373c1, + 0x421e1774, 0x420becbe, 0x73ff88ab, 0x5f3cbac8, 0x62276fde, 0xfb09c35b, 0xa87c0306, 0x3cda4409, 0xafd28237, + 0xaf1d92fc, 0x6fd46998, 0x95599ccc, 0x7f273316, 0x8466196a, 0x44609172, 0x63aa8b37, 0x4d94a19f, 0xab7705cf, + 0x1990ada4, 0x8f128cc0, 0xd27cd9b5, 0x3f0dfe61, 0xaa95486f, 0xf948aa91, 0xf8c0f8ea, 0xe48396c7, 0x0e0395e5, + 0x66a068ac, 0x3256b64c, 0x9e29f9e2, 0x74d55b21, 0x6e365164, 0x05f1acf1, 0x1ab81387, 0x628c74f5, 0x16c73245, + 0x557c1b0d, 0x3af90ac8, 0x5ff9ddcf, 0x3e92ddc2, 0x3a985b55, 0x3f6a4963, 0xad6887f0, 0xe5c3d9ac, 0x7857464e, + 0x9d115809, 0x7be57c99, 0x4f48b0fa, 0xf196b12f, 0x8d69ebf8, 0x10ccd93c, 0xe431a555, 0xb25a7d1e, 0x158d3036, + 0xd7cd78d8, 0x6dc49afd, 0xa2884ee2, 0xb6747ddb, 0x2f5960fe, 0x08be4d13, 0x623e8e16, 0x9a770b81, 0x805a827b, + 0x54efa462, 0x0e53bea0, 0x7bfa245f, 0x38ec2257, 0x53839c99, 0x60c5954d, 0xbdfd186d, 0xb1f0065f, 0x1c757bac, + 0x63f79d69, 0x9246ea65, 0x4c6ad07e, 0x43bc5ba0, 0xd7114245, 0x7fec0ac3, 0x85e83cef, 0xc79771ff, 0xad6f96d0, + 0xabfd2580, 0xbf604c98, 0x31d927e2, 0x55cd400d, 0xe80d6901, 0xb91c336b, 0x064e159a, 0x2f71f3fa, 0x51c9e163, + 0x4b3d9261, 0x6a544bae, 0x288c6319, 0xf04154d5, 0x28406f2f, 0xdb079949, 0x36272e44, 0x96a87193, 0xabea4b0d, + 0xacba2c69, 0x30ae665c, 0xbf0bf180, 0xd132c7c7, 0xc1f7de60, 0x15c69b6a, 0xc1e8109b, 0x7af06701, 0x9a4187a4, + 0x9d8c602e, 0x5ec7bdad, 0xfc1d429c, 0x1fce507f, 0x61eedb1b, 0xd2641c20, 0xfb9455d3, 0x68af6c53, 0xd4c0e45f, + 0xc7c433fb, 0xb6c360f7, 0xc5ff2a45, 0x2b8ff8b6, 0x79f364ee, 0x7878ced7, 0xba418d06, 0xc27e5507, 0x2b872e90, + 0x13b5134b, 0xfde1aa67, 0x986136ba, 0xf6949503, 0x014904e4, 0x2516622c, 0xff48df6f, 0xe1141e8b, 0x16de3d2c, + 0x0be0d3f2, 0x00326d03, 0x7f5573fc, 0xbad5ad70, 0x0bc3f64b, 0xa34172c9, 0x43d98e47, 0xf3d1d6c7, 0x1bf070a5, + 0x6898cf12, 0x8f043705, 0x37d29876, 0x157559ac, 0x3e6baca1, 0x5687083a, 0x20935898, 0xc9dcdcf1, 0x3694f50d, + 0x635d39bb, 0xf9238f2b, 0x169b593c, 0xd240b7d2, 0x680f592f, 0x7caa36c5, 0x3009d172, 0x6449699e, 0x87c3c773, + 0xa8ce8448, 0xe3713382, 0xe69dd6d5, 0x97e7abd7, 0x1ef3576e, 0x4335cfdd, 0xa726231b, 0x9c270982, 0x9e84116a, + 0xe0d7eea8, 0x6bbe9da5, 0x2a3c025a, 0xb785283a, 0xc0945ee9, 0xad74ee14, 0x58a55529, 0xc62a95df, 0x32745f39, + 0x0efc2acb, 0x2286c211, 0xd666d364, 0x2bc52c9d, 0x25bd002b, 0x390c38bc, 0x415e3016, 0xabc34b62, 0x91cb0af1, + 0xc692c932, 0x47c11076, 0x20ab5809, 0x1d7164b3, 0x16174663, 0x111a3117, 0x8d138a52, 0xf12cbcc1, 0xbd3f70ff, + 0x4b8d1ce8, 0xc1e85fd8, 0xc6e7315f, 0x920c9915, 0x3a3fbad3, 0xb46e1f4e, 0xf91fc5b2, 0xcb8230aa, 0xfeda1d3a, + 0x6f6d5cc5, 0x06638584, 0xd840fc89, 0x72e31d3c, 0xbd70e32c, 0x5425565d, 0x36b08d85, 0x5dbeb3d5, 0x94770bc3, + 0x859d0e3f, 0x1290d4c6, 0x3073f271, 0xbb64e6c1, 0x7d47629b, 0x0eee0615, 0xb3aacf3a, 0xd93dcc71, 0x37a40e87, + 0x43615894, 0x76914cf6, 0x8873eb58, 0xa07c7858, 0x0e93cadc, 0x9160bbfa, 0x7b2ca0a6, 0xa6b4ba53, 0x1de0e021, + 0xbeb1324e, 0xac9a926f, 0x6ede529c, 0xe610a011, 0x69acb53a, 0xd477392c, 0x3611a92b, 0x79d3bbc0, 0x35bf6244, + 0xadea72a8, 0x64d5cb11, 0xff9881d6, 0xcf9c61fa, 0x06a15b89, 0xb0088279, 0x17b3ea4e, 0x619f8304, 0x9eb270b5, + 0xed56dc6f, 0x725373bf, 0x46b9a198, 0x7cbfd590, 0x0d6a16ff, 0x203499f2, 0xc6d7d153, 0x40222368, 0x64fd04c2, + 0x684c00f4, 0xf37a75f3, 0x8c775d96, 0x44c36388, 0xd20b265c, 0xaa113067, 0x4007f4f5, 0x78a3d209, 0xabcc5334, + 0x7a544083, 0x0f91b3b4, 0x76c0429b, 0x505afc4b, 0x410738b4, 0x43f8490e, 0x30faad6b, 0xf8617a28, 0xf2731e46, + 0x42c92374, 0xb4073889, 0xf14c7ec0, 0x829ce886, 0xb841bc6b, 0xc5f715b6, 0xaa20950b, 0xa1d10c07, 0xab7f7a56, + 0x478173ad, 0xa225c656, 0xd6399642, 0xf82f24ae, 0x9b4ee142, 0x33702bae, 0xdd23d7e0, 0x58654ce9, 0xe6cb834f, + 0x40817aff, 0x4cb6c5d8, 0xa334e39a, 0xf0fa9b37, 0x79ef318f, 0xaae2c3fa, 0xeaf5dc68, 0x8bc9e6a5, 0x07ab6cc0, + 0xe2090535, 0x39ec20a3, 0xf7902a92, 0x10e25e44, 0x6e430e71, 0x6cc86168, 0xf77c895c, 0x14ac7225, 0x40143968, + 0x3efece1e, 0x88e7cef6, 0x14be04cd, 0x6c0c332a, 0x08fbe7ad, 0xeaf4e7e3, 0x81edefc8, 0xccbe51b9, 0xfa9dae05, + 0x1a5777c0, 0xc594937b, 0x39a575d6, 0x6d5f3c0b, 0xc331cfc6, 0x40da7921, 0x4b8e49e5, 0x72873528, 0xccbf92fd, + 0x4cbb9048, 0xe9821ef2, 0x63f8f4d4, 0x4a8a77aa, 0x8320c4eb, 0xf0f89a72, 0x1ceaf236, 0x899c35cd, 0x7de2d219, + 0xff166cb5, 0x04ced8f4, 0xaf0a77b9, 0xe6afeb1c, 0xe0f3f8ce, 0x714ded3f, 0x9101752f, 0x916e753f, 0x88b629d6, + 0x0dccb34d, 0xe45afaf7, 0x5d979256, 0x953ced0d, 0x41d07a91, 0x3a980ee0, 0x326bb867, 0x2ba042b0, 0x38d9be80, + 0x5715dbce, 0xe3815cf4, 0x9ca17de4, 0xabdcd00c, 0xab3385bf, 0x74da3c99, 0x8985dcaa, 0xb7d18d55, 0xb1590918, + 0xe0140185, 0x1bf75062, 0xab23302d, 0x31b69bcf, 0xee1c73d1, 0x7d70b0d0, 0x0f6fe336, 0xade755b3, 0x182391cc, + 0x167504f8, 0x60c64afe, 0xbf11acbc, 0x414f3893, 0x16a64913, 0x457a0401, 0x5bf7b068, 0xadc057f1, 0xa3abc249, + 0x144fdb4d, 0xab30459c, 0x647bfffd, 0xe50b3a31, 0xb965ea0c, 0x571b06f2, 0x72da57ea, 0xbf4492c5, 0x0675a695, + 0x6744a899, 0x141e3567, 0x093de9d3, 0x61f3b06e, 0x6d9c7eed, 0xdbff51c8, 0x44cd14ed, 0xbee2eb0e, 0xae428171, + 0x508548e8, 0x42135e35, 0xbe594e6f, 0x4e43466e, 0xb5553ed7, 0x2bafb2d6, 0x8add1192, 0xeca20ff7, 0x131f3178, + 0x119b6147, 0x89caf76a, 0xb57fa8e4, 0x5063fe0e, 0x019ff057, 0x92dfb7cf, 0xbc51c5e7, 0xf491bd11, 0x88a492a0, + 0xfffa029b, 0x96834702, 0x9e066130, 0xd9f1ba87, 0xd1cc8409, 0x5ae45d72, 0xf61e47f5, 0xe39f608a, 0xfcf3f7d2, + 0x9fe6ac04, 0xd5a14ca6, 0x0aa009c4, 0x6ef9a2fe, 0xe20b0f52, 0x0ed103e3, 0xd52c7744, 0x08b9878a, 0x704337ed, + 0xdce41422, 0x62fef670, 0x33ce873e, 0x7e006179, 0x8fee1ac6, 0x3b0c006e, 0x0879e102, 0x24d59944, 0xb5e7e385, + 0x6ce722f5, 0xdb3284a4, 0xf15b6bf4, 0x293704b7, 0xc7b33a0b, 0x12c97879, 0x80a406a8, 0x77d7da6c, 0x1745acc9, + 0xafa94b3a, 0x7bd3dc35, 0x832cfc99, 0x6c2e1fa3, 0xe2528c49, 0x99a5ea15, 0x3cdb10bd, 0xf3025b21, 0x2bf898af, + 0x03798df4, 0x07188a24, 0xf90b47e6, 0x9452f955, 0xfb228b6d, 0xbe20bce2, 0x754a10d2, 0x290f3bb2, 0x642d24db, + 0x7fa4972b, 0x02898201, 0x4efa0066, 0xcb3c3439, 0xc5d37440, 0x044c22cb, 0xdcdb28b0, 0xad12a2ad, 0x3bdef085, + 0xd14c9475, 0xd824d5ef, 0xe6e23dbc, 0xd1486057, 0xa9b74d14, 0xfa66336b, 0x8f19eb62, 0xcfd2e784, 0xce1ea4a7, + 0x4bf51021, 0xb012c688, 0x2de5d0cd, 0xdf7b2ff1, 0xdb49b257, 0x30f1555c, 0x76163a65, 0x436f3aca, 0x6c2fc79a, + 0x8ca3e2a1, 0x62699b70, 0x51d07b8e, 0x33fe2582, 0xf2faaf96, 0x375ee9ec, 0x14b3500c, 0x6a6b847b, 0x48174d7f, + 0xe7d73ff5, 0x9d54e5ce, 0x6fdf8392, 0x51dd8efb, 0xef5fda1d, 0xe04fb289, 0xa61850bc, 0x41587afe, 0x2a1f2dbe, + 0xc959f1ab, 0x6fe18011, 0xd9a74de6, 0x0391d231, 0x6842d3ad, 0xec6ffa13, 0x0e423642, 0x8a2b3859, 0x5df6df77, + 0xd89a14ed, 0x27237531, 0xbb227800, 0x4fcf7b14, 0xbffdfa18, 0x9e758f55, 0x898a39e6, 0xe64172fc, 0x59d053b4, + 0x9163ba62, 0x61bdd2f7, 0x6e7d28e6, 0xf80d6f1c, 0xeaaa5ed7, 0x2c488e11, 0x2e2b0e42, 0x67236ff7, 0x2c516aa9, + 0xc547fa9f, 0x58295677, 0x7d7a1521, 0xf41021e2, 0x789f9f6e, 0x244bf952, 0x0b45dabe, 0x071c942b, 0xd5b2124e, + 0xdf6c13c2, 0xd1b8c2fc, 0xff30395d, 0x6e3910f8, 0xa26d7548, 0xb1ff1bd2, 0x16f5d6a9, 0x70f164cb, 0xba7aed1d, + 0xc01acb85, 0xff57b499, 0xa66be4dc, 0x61f353ce, 0x108d9c35, 0x69158028, 0x02045355, 0xd896ec98, 0x8be5af78, + 0xdd870a79, 0x71bd3b28, 0xf4106401, 0xad993c73, 0x79f85318, 0xc4d7da50, 0xa20df1f8, 0x249d73da, 0x7d2748cc, + 0x377a9e1e, 0x6ca9eba7, 0xb0c0338a, 0xe8f764f6, 0xecae1c9f, 0xf19e2d78, 0xa578c1f2, 0xab47db3e, 0x80b47d15, + 0x5af5ae91, 0xcc5504e9, 0x190cb65c, 0x91ad15ec, 0x99884d85, 0x705cca9e, 0xeac7af0d, 0x8bf8fe24, 0x820bd36f, + 0xe1ba6178, 0xd8d6b93b, 0xe2b1350c, 0xc916681a, 0x22c6bb4e, 0x30a954a6, 0xce09be4b, 0x8e71898e, 0x072e719c, + 0xe5c0d7c5, 0x1fb8d194, 0x148d4138, 0xdceeccba, 0x31f53f0b, 0xafab0d08, 0xf5388634, 0x98b186b3, 0x1cf88f8a, + 0x89221d97, 0x6c4e7b61, 0xfc898cd3, 0x0ecefc17, 0x368c03e0, 0x155436f7, 0xd73a1085, 0x069e9fa8, 0xeb401ccb, + 0x84a22d19, 0x68ca6699, 0xb200deea, 0x71d33d13, 0xbbb5aba5, 0xb645f14f, 0x12f8bdfe, 0xed39afeb, 0x759e36f3, + 0x81d52b98, 0x1f4fda93, 0xd227e278, 0xa76d8e4a, 0x7a45cec5, 0xf51a4049, 0x026c3322, 0x2e9d715f, 0x2242e086, + 0x4f5355e9, 0x84aacc21, 0x516f1892, 0x32f4be3f, 0x3a8f9684, 0xc7402be7, 0x91ddd50d, 0x2f856f87, 0x22cc328f, + 0x185bf078, 0x14056abb, 0x198bc961, 0x64d0bd85, 0x903f1039, 0xca9055ab, 0x2650e210, 0xcca915ae, 0x84c9d326, + 0xa882b8e5, 0xf32b2586, 0x2ec130bf, 0x7192d167, 0xf84d3519, 0xc070da26, 0x731d1ea8, 0x6279eb65, 0x3d494f1c, + 0xa6f665c4, 0xbfa58508, 0x5f87b8e7, 0x93671106, 0x7180fc5a, 0xa57c443e, 0x5775c2b7, 0x402475b0, 0x601b19ba, + 0x4aacb39d, 0xa2acc92d, 0xc5c5ac33, 0xde6c000e, 0x8f666170, 0x62123071, 0x5e8158cc, 0xb5391410, 0xad0d892f, + 0x77e1aa07, 0xd9f57d3b, 0x39131753, 0x6fefbd34, 0x99b1a0b7, 0x6a239bac, 0x5198f27d, 0xce4ce8b0, 0x91d9f8fd, + 0x7627a694, 0x1aaf9630, 0x8b3a311b, 0xa0362955, 0xb4c6a285, 0xcabd6945, 0x1370ac05, 0x7998e7fd, 0x9601c958, + 0x69fc23ef, 0xbe6eba14, 0x4841c046, 0xd5638d96, 0x67d5ba92, 0x2d396bab, 0xa3491377, 0x58ee8390, 0x889c9818, + 0x3b7aac0c, 0x0a3ca7c3, 0x2edc9c23, 0x5422c3ed, 0x71be79a0, 0x44c6af7e, 0x29c5fc9a, 0xc70dc748, 0xc8b9e4d2, + 0xbf83014e, 0xb3a9b9fa, 0xe25529a5, 0x910c086e, 0x39b28c16, 0x5eb284cd, 0x9f326c97, 0x9e6858b1, 0x4cc02b5a, + 0xfcf24625, 0x042722de, 0xf3145a15, 0x26483a85, 0x85fb3c48, 0x0a78892e, 0x338457b5, 0x28e472be, 0x7d5b6675, + 0x66233d3e, 0x0f58c30b, 0x879f2179, 0x645dd60a, 0x6c841507, 0x6646447f, 0xaf9949a3, 0xe5412016, 0x9dd96ce6, + 0x0415f0f4, 0x78891c49, 0xb76aef21, 0x1993f27d, 0x6e9ea6f8, 0x1e356594, 0x4953f739, 0xe4707976, 0x8f35f090, + 0xf061dff3, 0x6dd2ff84, 0x3d9bd396, 0xbbb51795, 0xbb931acc, 0xfd28deec, 0x4c48a4fc, 0x77080c8c, 0x786a2f9e, + 0xd8111cbb, 0x0c15700b, 0xa6bda1a0, 0x8228254b, 0x2268018b, 0x6be9f3d4, 0x3cf08bd3, 0x1eba4d10, 0x3f5901c7, + 0x1419d6f8, 0x759554f7, 0x0959b2fd, 0x8b8f6b98, 0x64227dab, 0xa79af448, 0xfaba2440, 0x9d82f1cf, 0xeca81981, + 0x54d7a592, 0x243673e5, 0xffea63ad, 0xe1578e8c, 0x0fc86186, 0xd954133e, 0x0005d777, 0x2c2378c5, 0x254c33da, + 0x3677ad1a, 0x39ffccb0, 0x6ab1ebf8, 0x95a18fad, 0xb84db261, 0x5b4839bc, 0xdbac00f5, 0xe486528f, 0xfe45ab49, + 0x8ca75f75, 0x76e9db98, 0x3fc11e2b, 0x89d3831a, 0x1a338275, 0x656ce2f1, 0x2e6806b1, 0x4692d6ce, 0x19c26244, + 0xb0ca0f2b, 0x8371beee, 0x217a177f, 0x26ffbb37, 0x9a46a48b, 0x7bcbac08, 0xc0f43a24, 0xe8b74d7e, 0x27f5cef3, + 0x18adb186, 0x2cb6ed57, 0x0281cd0c, 0x9fe0365c, 0x81772498, 0xeea14b88, 0x86318d83, 0x7e0f3006, 0x387188f6, + 0xd1ea268d, 0x1cce58b7, 0x2d378599, 0x43af0de2, 0x07315a71, 0xd5cc69af, 0x74110575, 0x97476e6d, 0xf27ea6b0, + 0x9fa97d61, 0xaadb9500, 0x8acd3802, 0xf1bbff31, 0x3bd53f9b, 0x62de7b85, 0x15a6a101, 0xd0529ceb, 0xe53e98b5, + 0x511e528a, 0x4bd82158, 0x7265db10, 0x5da44b46, 0x95e44b90, 0x14c8c262, 0xa5ebda2e, 0x56c921cb, 0x6bbc5d36, + 0x8e0eff09, 0x6cef3536, 0xe70a892f, 0x21aec716, 0xa483688f, 0xb67abdb9, 0xb182f25d, 0x12f36103, 0x6522011a, + 0xb11196fa, 0xa9f6c5a3, 0xc33e5524, 0xf325f28d, 0x50dc2da0, 0x953d9b7e, 0x9b27c710, 0xeec1b7cd, 0x91f6c7f9, + 0x89fc85ce, 0x4c6c85a5, 0xe3d8b8ab, 0xacd97a5f, 0xe4524187, 0xdcfb6be7, 0xc29b5dfd, 0xac439eb1, 0x53ab9cd9, + 0xee56c046, 0xaef6b122, 0xf4d90b93, 0x530f52b1, 0x21b31881, 0xfc828bbc, 0x7e5e172c, 0x3f80df20, 0xc7fae7ff, + 0x1c21f336, 0xf5c940bc, 0x5fc7e7a0, 0x1b3e113c, 0x189af961, 0xa7561adc, 0xdf9d0272, 0x78a0e824, 0xb526992a, + 0x6af07a4f, 0xf1cdea04, 0x500ed0e2, 0x1c74d3ea, 0x171ce984, 0x1d94cdc8, 0xffe557bb, 0x324de45c, 0xa3d2618d, + 0x83fb6975, 0x1ba31868, 0x65e7f3a5, 0x8492251a, 0x711fd2bd, 0xa251d372, 0x9df6f097, 0x54b50112, 0x0abef728, + 0xb7c2f25e, 0xb6c29ab8, 0x72904f2e, 0x44a2de60, 0xd6351105, 0xa76c5547, 0xd20db526, 0xb86dd739, 0x3a21f13b, + 0xe0a09525, 0x35210e81, 0x4db777fa, 0x2f8b8da3, 0x7ff91c92, 0x3d52ab92, 0x45e48b53, 0xdac8866e, 0x130efff8, + 0x15d2e1c8, 0xe480f3ee, 0xae2d5d00, 0x4e8be617, 0xfbafaa69, 0xee7023fa, 0x2bab9d2a, 0x9755bb06, 0xefc18108, + 0x853e5a37, 0x2be659f9, 0x2fb794cd, 0x6d10c4ab, 0xd12e97bc, 0x86c5bb9d, 0x262a6372, 0x5950f5f6, 0x25c1deed, + 0xf953834f, 0x718125c8, 0x9a93daac, 0x703ff099, 0x199edf94, 0x95a9067a, 0xac16f681, 0x34340c45, 0x261898ca, + 0xeb20d772, 0x07dae723, 0xe3290549, 0xc0c84350, 0xacc80279, 0xe728c153, 0x321ad336, 0x8051b34d, 0xcbf674a7, + 0x9c870dc0, 0x015def02, 0x8fed1fde, 0xebd9092d, 0xa5bd5295, 0x06e01e9e, 0x3fc45716, 0xbe60d027, 0x4ef749bc, + 0x9dfc95dc, 0x7d8db055, 0x832dd2a9, 0x29b927c5, 0xec1bdde1, 0xc0098b72, 0xbc91aebb, 0x1f1e7cc2, 0xc088a4dc, + 0xaf86b283, 0x2172e8b5, 0x39db3bc8, 0x882a4770, 0x956e01b8, 0x0d3d279a, 0x795b4275, 0xcfc87195, 0xdb64a3f4, + 0x91d94033, 0x4ea922fb, 0x1cdeb164, 0xd14e99c7, 0x7706f07d, 0xc43bf023, 0xe269993e, 0x162471bc, 0xa421ae75, + 0x9d506bb7, 0x7df764bc, 0x3cdb924c, 0xb74b2516, 0x769d6edf, 0x642465bc, 0x6571c43c, 0xc54fdb74, 0x2ccb89b0, + 0x6dd4f37b, 0x3b877343, 0xc9fe90f7, 0x3f9ba096, 0xca5e9a10, 0xf3ac0580, 0xc3edcd74, 0x4dc9b764, 0x5ed2f141, + 0x2f916ab9, 0x3f1d750e, 0xe844d6ab, 0x0454358f, 0x56a2efa7, 0x3c169d10, 0xab3ad607, 0x4a761828, 0x91d67681, + 0xc1c496ea, 0x23f91d58, 0x164dfa8b, 0x67e8a350, 0xa2c83d78, 0xb952e689, 0x3d30079d, 0xec35193d, 0x8430dfba, + 0x24ef9ab3, 0x04c638fc, 0xb189b714, 0x7cc52589, 0xd6c17938, 0xdd3af756, 0x71696d07, 0x4394e204, 0xb27cf9c6, + 0xeed814f2, 0x518fb93b, 0x257806aa, 0x803cd1aa, 0xcb3fe7d5, 0xa3243b5e, 0x4c17c42a, 0x10bd9876, 0x004be8c8, + 0x7f177cd2, 0x23da3bb7, 0xdb736ee6, 0x987f52cd, 0x3965eeb8, 0xd6d310c1, 0x7d11e847, 0x8e73e5e4, 0x8ab18cd4, + 0xd254e152, 0xe4734322, 0xa1d6541f, 0x5ec0ef8d, 0x39d79b8c, 0x39ed34a3, 0x5d9bf861, 0xff008bff, 0x71fc7fb6, + 0x84178deb, 0x6c1bd1a9, 0xf7235fcf, 0xaf937f6d, 0x51ea59f1, 0x98c39af9, 0xa94f96ff, 0xcdcfc278, 0x756d60ad, + 0xad3a36d3, 0xbc2ee3e3, 0x0afe5763, 0x620df3ae, 0x06a52146, 0x7d06d01d, 0xe3a78d9f, 0x55714d88, 0xd9801c6f, + 0x5803d125, 0x034c2ed2, 0xbedf8f87, 0x23e078df, 0x31bbba3f, 0x5f865c1d, 0x1b13dec5, 0x3352497d, 0x913f2cdc, + 0x65f66df2, 0x212cd84d, 0x1771d457, 0x265174d5, 0xb267c4fb, 0xde42d0cc, 0xef881a17, 0xd8b164d7, 0x27fb0a8f, + 0x5f01f5ba, 0xc41d41b3, 0xca73e3c7, 0x7ee2070b, 0xf0f42d1c, 0xe91be1fc, 0xf9278e36, 0x0f6df952, 0xf91e0d6d, + 0xcd907041, 0xccc28d9f, 0x03f4654b, 0x53ceb08e, 0xdcca9afe, 0xe4223f4c, 0x02e3f027, 0xfba36cdf, 0x7b57a40a, + 0x24345995, 0x25e8a67e, 0x14393ed9, 0x1506d65f, 0x7715bb76, 0xdfc6abcb, 0xb17422c5, 0x158715fd, 0x0c309c6e, + 0xe841205c, 0x3f05a99a, 0xfd8f110a, 0x144ee487, 0x8f9dc6fa, 0x8bfcd50f, 0x7516a8db, 0x194ce38e, 0xb374ac3f, + 0xa4f41b1d, 0x2c587ad8, 0xc3471459, 0x542d91a5, 0x7f1b5398, 0x5464ffb4, 0x6740434e, 0xab5abf5e, 0x89a35541, + 0x9f22536b, 0xa0d77a8a, 0x3f990976, 0xacd375a9, 0x5360b726, 0x5ba06f36, 0xb3cf032d, 0xb0b65a23, 0x43a7d085, + 0x9101fea8, 0x5457fae5, 0xc74dd8f2, 0x48ae84b7, 0xadf9f662, 0xdb157a92, 0xe082ed8b, 0x03663973, 0xdf73e745, + 0xaf8e7922, 0x2033f635, 0xc2951fc7, 0xe4244f0f, 0xcd674873, 0xaefbf4dc, 0xd2c9a42e, 0x54ef6a3a, 0x5247e80f, + 0xab888770, 0x412c4269, 0x196f8094, 0x0422014f, 0x6a843c04, 0xb3031bd7, 0x47420d91, 0x39ffbf7c, 0x2d772627, + 0x7b277bdc, 0x58c0a995, 0xfbc48e91, 0x97ba7fda, 0xdbf3ee33, 0x46076d0f, 0xa6da0d3c, 0xad14bc94, 0x0f1c13ba, + 0xe4d22126, 0x776d0a61, 0xcb6d9357, 0x0596aed8, 0x9ed92007, 0x65544186, 0x77d207dc, 0x552cb752, 0xd065963a, + 0x9482a882, 0x64b18f2c, 0x6822757d, 0xcd5b66eb, 0x3b985c74, 0xd0225db3, 0xd5a28a4f, 0xfadb41d4, 0x69cc44e6, + 0xc38ddcc2, 0x3e3d2371, 0x136f90c4, 0x4b0932ab, 0x13636930, 0x7d93b459, 0x89f12500, 0x6015ed02, 0x6d1eac33, + 0x1d3415e4, 0x3471cf34, 0xcb15da60, 0x17dfd11d, 0xdc23df3a, 0xdd057c41, 0x1d14964a, 0x5be098e7, 0x0fae3d0d, + 0x955e90f9, 0xbd7353ae, 0xaf42273e, 0xfb8c4d2d, 0x8e9aad74, 0xd85436da, 0x7011fb39, 0x3a6cc361, 0xc3d15bb5, + 0x7811a2ef, 0xc8db7768, 0x7ab6699e, 0xac4e0c83, 0x808fcab3, 0xdfbd3280, 0x01ab00d9, 0xbffddd00, 0x1756c50b, + 0xe17c850f, 0x3a710387, 0x6eb05027, 0xecda032b, 0x1f32d186, 0xe6f2e738, 0xb81f4f7b, 0x8d7b5649, 0xac2a064f, + 0xe3f5f0a7, 0xf91c2356, 0x0b81d274, 0xcca0411b, 0x98b4c2c8, 0x3f8838ec, 0xa071e2e5, 0x87bc4503, 0x32c79550, + 0xb5bc250d, 0x309718f8, 0xdc6d26d1, 0xa7b7dea3, 0x9cc048ef, 0xbb72dfd3, 0x540c97b8, 0x6afce490, 0xe61a4fad, + 0x09764e01, 0xd05da685, 0xa4ddd496, 0x73948be1, 0xc7ad962f, 0x1304c8f5, 0x79be1d70, 0x881f4bee, 0x74201aca, + 0x958b33cf, 0x46b40491, 0x2a7919c4, 0x5bfc2de7, 0x3cf659de, 0xbda0994a, 0xaf9a413a, 0x822f663b, 0x7bbfc642, + 0x53b0944b, 0xe504224d, 0x27f5ed24, 0x20fe6f3f, 0x81dbd97f, 0x8663ff99, 0x1b475318, 0xb4db4132, 0x821a6067, + 0xdc2f5bc8, 0x7302e054, 0xf6bfc6e0, 0x526bcc01, 0x14133c04, 0x0e479d32, 0x932de95c, 0x1538e710, 0x84796af3, + 0x7b9f0198, 0xbdbc7dd4, 0xd18463e4, 0xd41ee22e, 0xb3c02635, 0xadc174a4, 0x6dc33713, 0xe760dc29, 0xad51dbac, + 0xde660d9c, 0xcb78c2ca, 0xb6452721, 0x9215337d, 0x3d07a186, 0x8d016f4e, 0x961a67ab, 0x4d1994c9, 0x823588a8, + 0xf715d54e, 0x287b3afa, 0xedab4fbc, 0x3a3c5a1f, 0x629e0408, 0x29863bae, 0xc2b73dd7, 0x8d77eee8, 0x05cc1ab1, + 0xae889c36, 0x6283042c, 0x2f317695, 0x5c9ae2b3, 0x2db55137, 0xe43846bb, 0x1df459d7, 0x6d2f82fd, 0xa466689e, + 0x59bf15ed, 0xb52310e8, 0x27c152c2, 0xd801e7b7, 0xe675f89f, 0x2d991bdf, 0xca594e29, 0x877a5b86, 0xe487d9f2, + 0x1e7fd4de, 0xc91c061d, 0x74e87f01, 0x816b2aa7, 0x4a498070, 0xce624eba, 0xa3bb1d1c, 0x2a3e6d61, 0xf9267627, + 0x5bb3cb21, 0x2f0ca2d2, 0x7c839e52, 0x379d88db, 0xf9cf5760, 0x27a3219a, 0xb1b78179, 0x8176e0ca, 0xf9777068, + 0x2d941c98, 0x9af42287, 0x6b8921b9, 0xc9a9735f, 0x02d90422, 0xb7de3622, 0x8cabf182, 0x8619503f, 0x18060cb5, + 0xeb406485, 0x4a0a2833, 0x84a85ef0, 0x1653677e, 0x0a743e78, 0x93e44286, 0xc2e007ae, 0xfa42483f, 0xbee694d1, + 0x3f28b146, 0x6fae3ac6, 0x367133cf, 0x1b6044b9, 0xf1e31e9d, 0x69b68ab4, 0x66beb909, 0x5091e28c, 0xf6d45f23, + 0xb9c06b99, 0xd39715d6, 0x964d0ea2, 0xe7eefdb1, 0xf4ea3f38, 0xbca062f4, 0xb66b54d9, 0x925a5945, 0x2a586fe2, + 0x1a882ffb, 0x4effcb85, 0xd431a6f5, 0x7bcbb7ec, 0xa2e1bcf6, 0x7e5bceb9, 0xcad57518, 0x12bddc95, 0x3bb829ae, + 0x3e948562, 0xdd48287d, 0x4520f06f, 0xaae0fc87, 0xc409f784, 0xa0b8d30b, 0x072328f8, 0xaa2b8e30, 0x419adffe, + 0x832c10b4, 0x829ad9c3, 0x949c1e32, 0x783b28e7, 0x6f17d9f3, 0x126310eb, 0x0ed517a2, 0xa0aa0bdb, 0xc3c8beec, + 0xa75ea04c, 0xd77130e6, 0x8f7fca19, 0xc208fc79, 0x3d49638a, 0x47cd42cf, 0x6526ac2c, 0xdceaf1e9, 0x9b88a77a, + 0xb4a471d1, 0xef0dbb1e, 0x10b09cea, 0xfe0366d8, 0x0592ed64, 0xd36356ed, 0x0a2ff145, 0x63f7b1f0, 0x0e0b6e41, + 0x2bdb63db, 0xed85e545, 0x4d9c9529, 0xab9848e2, 0x2f270bb6, 0x1d22cd20, 0xe93a5ba1, 0x7577b885, 0x4b86c085, + 0xd02d329b, 0x08d9ab7f, 0x6bcbd7d1, 0xbce9c4d7, 0x8aea3f4b, 0x4f8bc7e1, 0x1de2f223, 0x16f00dc6, 0x96a1b59b, + 0x9586ece9, 0xf578486f, 0x2960da37, 0x7e7ed2c3, 0x6b9b7659, 0xe973e9d5, 0x0b797ff5, 0xb1029660, 0xef35107a, + 0xcc88ad8d, 0x8da3a29e, 0x3248a511, 0xcfbe3be4, 0x32be0ed5, 0xad4b439b, 0x59fcd6cf, 0xa52c4291, 0x0414803b, + 0xed60797b, 0x87f0a97a, 0x65cb9652, 0xc66e9e51, 0xd6ba8888, 0x47552a2d, 0x8e3a10d4, 0xe9583754, 0x727ddd66, + 0xa30005c6, 0xaa179d7f, 0xa30a8534, 0x12ebb21c, 0x2264c956, 0x90cfb68f, 0x401963c4, 0xde1ce3b7, 0xd2508a8c, + 0x42ebb966, 0x9178c9f5, 0x42e647f3, 0x320f7dcc, 0x1bad101a, 0x935c5452, 0x74aaabdc, 0x2f76490f, 0xf8002b10, + 0x1454dea2, 0x63586578, 0x0eff8b61, 0x203dfed3, 0x76398dc9, 0xc8b8997e, 0x39c7f0fd, 0xc51ab172, 0xbba8e736, + 0x6cd616ab, 0xf1e5a61a, 0xd4e570ff, 0x207a7234, 0x5cd7ef6b, 0x80971049, 0x98b53cf3, 0x4f3b7991, 0xecc03cf9, + 0xdf5eb195, 0x5012365f, 0x010b6e81, 0xec789fe3, 0x5403f891, 0x530a99b2, 0x765ce868, 0x9bb23827, 0xaa6de51c, + 0x1d7f6f06, 0x7af670bf, 0x3161079b, 0xd13c5bc3, 0xfaef68fb, 0x141192db, 0x1833feb7, 0xf0e9ebe9, 0xcb535d11, + 0x84f2a1c8, 0x28180d74, 0xcb53ec65, 0xebd21ed2, 0x95c7e498, 0x3f0623a5, 0x19406031, 0x708e5557, 0x64c92792, + 0xc8c6a98d, 0x18e34f07, 0xcd036866, 0x8c11160f, 0x2d6532d8, 0xeb81526a, 0xe7302e27, 0x3eb919ed, 0xb6da5e58, + 0xe5236fa6, 0x32224d50, 0x946542d6, 0xed9efdc1, 0xd69859a6, 0x43439f51, 0x631eb4db, 0xd91c8001, 0xf4e1dd20, + 0x66f6511f, 0x5e792c1c, 0x2982f449, 0xffb732bb, 0xe2951e8c, 0xe94b5e57, 0x14a76381, 0xc0ba177f, 0x3bdc965e, + 0xb73ff075, 0xbc76849d, 0xf1d4b57f, 0xa95a63e3, 0x30cde894, 0x1ca85c52, 0x1652d9a3, 0xc887e969, 0x9b5b2cf3, + 0x5b858cc2, 0x91f0c14a, 0x6f6d0ae0, 0x30b4e1d8, 0xfd0b8787, 0x31f3e4e8, 0xb3455db1, 0xfed5f41e, 0xf74aa4b3, + 0x79154c76, 0x2633a9ac, 0xe42dc461, 0x3445ee3c, 0x9c010d91, 0x1f903b27, 0xaa22a89d, 0x073d4947, 0x502ed2ce, + 0x580c5294, 0x22d14165, 0x1140fb3d, 0x69d17691, 0x098f3aec, 0xe7a5c0e4, 0x01bbc03a, 0xb37ab4c5, 0x5fd055c3, + 0x912a687e, 0x8d1264f7, 0xa001e0bb, 0x0ddbebd5, 0x2752cc48, 0x4e79241e, 0x419c789b, 0x98d3a6a3, 0x615fb5f8, + 0xa40e9d4b, 0x034abe84, 0xad63cb54, 0xcf8871f1, 0xf13a8ea9, 0x6ce6efab, 0xc708b4fd, 0x8097b2b6, 0xa21bbd0a, + 0x7dab5cf9, 0xf4a5ffbb, 0xfca1d1a2, 0x36a0059d, 0x44351b1f, 0x2cbf6fd0, 0xf3fdabd8, 0xbb519f72, 0xa79c33d2, + 0x2be376c4, 0xc5718612, 0xdb5709fc, 0x27d316d6, 0xb59930b5, 0xffe91be3, 0x8b320da1, 0xffd61c2b, 0x8f681ea8, + 0x60c0d5c7, 0x815822e5, 0xda231477, 0x35615524, 0xffb107c8, 0x4032f0af, 0x3544df64, 0x883dc7c0, 0xb32b4f86, + 0xbb166846, 0x318c7c49, 0x5faebd93, 0x11e9a838, 0xce01a081, 0xec891165, 0x05fa77d4, 0x2988fc31, 0xdd6850e6, + 0x26a1d1d5, 0xb3a4a94e, 0x80429fab, 0x5d7f7cc6, 0x098bca3d, 0xb0a56843, 0x22705ef7, 0xa10a9482, 0xa8e8c6fe, + 0xbcd0f593, 0x897a4d15, 0xca2885b0, 0x56aa1f50, 0xd0784015, 0x5daf6154, 0x4675d6ee, 0x3b9f14ea, 0xc1d77e72, + 0x203c544b, 0xe8b99679, 0xbc138e2e, 0x64a49784, 0xf0aaa328, 0x1e4828a9, 0x2c61cc15, 0xf3941649, 0x69f13e77, + 0x9a77ad70, 0x682d5ee3, 0x99febe52, 0xad8090b6, 0x982f83ff, 0x1b4143ae, 0x3f1a383b, 0x2837397e, 0xaf2dde29, + 0xce3693f5, 0xba46ab26, 0x841bfa8f, 0x6157691d, 0xcb27248d, 0xa082464a, 0x36174cf0, 0x99fc29fb, 0x696ab0a2, + 0xe7d5f46a, 0x2ee8ae2c, 0x8ce479d3, 0xe63d09a4, 0xcd2cf8db, 0xf5779ed3, 0x746ef97f, 0xcfa84974, 0xfa7d344d, + 0x3b8c98a4, 0x2eafc478, 0x15dfd481, 0x585932cd, 0x9fac9318, 0xfe970a64, 0xdbb40047, 0x28506aa1, 0x0c5650ae, + 0xf475e8cd, 0xad936a4c, 0x0305dcc6, 0x876db0f4, 0x90e88586, 0xa38eeaf5, 0x58ddbeee, 0x124b1142, 0x1f60a09a, + 0xaf96bced, 0x3957ed81, 0x034e500b, 0xc854feb1, 0x1a218e0e, 0x836b0cc9, 0x039cf306, 0xf2d1d31f, 0xd99aca96, + 0x7e19cd42, 0x67e064f2, 0xc5404e78, 0x4fe9b5db, 0xa86f8602, 0x370ad804, 0xeb758ba4, 0x5288d619, 0x1d4dec8e, + 0x977a6416, 0x23819a45, 0x504ffb3c, 0x292e964e, 0x704b7e46, 0x46631f30, 0x02467af2, 0x1c3fdef8, 0x88db0309, + 0x4fb4f489, 0x1c0a652d, 0xf39c621e, 0xdf80844f, 0x95a259d6, 0x04781d30, 0x2af9fbe8, 0xa3887ddf, 0x53774fb0, + 0xa2482f4e, 0xd1eabf9c, 0x84a31179, 0x8920f945, 0xa6eba5ee, 0x701d8eaf, 0x957e4a7b, 0xb5fd9ab0, 0xab6dabb6, + 0xdfcbd19b, 0x834500b1, 0x2155f277, 0xbc7d8a2a, 0x1c8fa40e, 0x43ab94f1, 0x3e1b37f8, 0xd2cb8eb6, 0xa0df23eb, + 0xf2d9b60a, 0x5f182bdc, 0x7d47b5cf, 0x9596ff8a, 0x6d0b3ed9, 0x41347978, 0x61caa498, 0x4d0edf04, 0x2e4aea5a, + 0x3c17b6e4, 0xa66d952a, 0x014f0db2, 0x8c279822, 0x3e3aef20, 0x332d9d03, 0x0bc2ed90, 0x93d8fc5c, 0x42c8a597, + 0xdb786860, 0x5395d6d9, 0x9671dfc0, 0x847f9143, 0xd3ff01b9, 0xa2ec45fd, 0xbabd8f8b, 0x51fede15, 0x05a99226, + 0xcd806e73, 0x8b64c23e, 0x6019074a, 0xdc5a207b, 0x796d0a02, 0xf0957d76, 0xb1e472d6, 0x20acffde, 0x18e7974e, + 0x67a92817, 0x2a035e61, 0xad8baea3, 0xf4458da9, 0x422b6b6f, 0x0199e56a, 0xa3316b7b, 0x647f5c5e, 0xa0a870e9, + 0xa5fc1478, 0xad204204, 0x082d5d07, 0xeb591871, 0x25ed0509, 0x870b57ba, 0xbfb3d2fa, 0x50bd2be4, 0xe1f0683e, + 0x329134e2, 0xb3ad19e0, 0xbb3352f8, 0xcf7a67b1, 0x4978173c, 0xf0259953, 0xe473293c, 0x4f03fa1f, 0x7a32f092, + 0xa4a89a24, 0x2fa1a818, 0x6d490448, 0x15a1beb3, 0x37450f3d, 0xf5727aa7, 0x09d1303c, 0x6d2930e2, 0x3efee032, + 0x46c6e253, 0xad1388f5, 0x83a108ad, 0xf59cd5da, 0x2fc388a9, 0x8de5911d, 0xb3c6159d, 0x1d2730dd, 0x396dc565, + 0xf5f6be83, 0x46f5aa29, 0x2090388b, 0x4e466ff6, 0x7c2d389e, 0x346c8f5c, 0xc991d633, 0xd3ed632a, 0x30bfac0d, + 0xcb6a70e7, 0x5c677e3e, 0x2e3bfc17, 0x9dbcf9dd, 0xb4e29af1, 0xa2466f36, 0x95865151, 0x4c3cce16, 0x13faacf4, + 0x94da73a7, 0xe8221009, 0xaf8bee9a, 0xc9e640be, 0x041783a6, 0x136c789f, 0xd8c15b23, 0x8eef2aab, 0xafbddda2, + 0x02a1aad6, 0x9ec66616, 0xf53cbd23, 0xedd4a88c, 0x15c2c363, 0xb9cb048e, 0x05e41bdd, 0xac397a58, 0xc4f8ce8b, + 0xb3a29d67, 0xb5b06e82, 0x8372efd5, 0x0a19b612, 0x24a47d23, 0x0496c57d, 0xddaeab6f, 0x8a65f83b, 0x7cadc25e, + 0x5168d57d, 0x8a0af7b0, 0xc9a2ec8c, 0x881094b9, 0x672b53fd, 0xfe8b0ee4, 0xf55161fb, 0xc7074d9f, 0x0dfb9fdb, + 0x5d41e144, 0xf615875b, 0xec34a973, 0x938d9ae5, 0xf539b6a2, 0x0a04ebf7, 0x75abd0d3, 0x1ef75183, 0xa72ad497, + 0x87d2868f, 0x2770d897, 0x16b11739, 0x6e1da19f, 0x52a88129, 0x03be27c0, 0xf75e9433, 0xec9f99e7, 0x7a9a8798, + 0x4c61e324, 0xa2b13ea0, 0x6ee89bd7, 0x8a03f824, 0x8a7be76c, 0xd4197ba8, 0x2194b0df, 0x597b4bce, 0x376a790a, + 0x50f94e6f, 0x9fa9cf8f, 0xd8b05945, 0xe21c13cc, 0xd6aabe48, 0x19dcb053, 0x5a789376, 0xa7a15d88, 0x15adf5a8, + 0xc399f681, 0xc15dbfb8, 0x2751c7a1, 0x1d0b7be0, 0xa6b32251, 0x2b4a2f62, 0x4c404feb, 0x52b1f919, 0x9780bd8c, + 0x0a3383f3, 0xd761e578, 0x8a69fe83, 0xfd218057, 0xee0cfbda, 0x7cb3e136, 0xf081d716, 0xf4c92a5a, 0x42aef23c, + 0x4f68ba39, 0xdb36b71c, 0x30640a8f, 0xa558e150, 0x81bb4d4d, 0x77662c07, 0xde156afb, 0xb77e5db4, 0x9dab09d0, + 0x8e44b7da, 0x7529e449, 0x5c2355d0, 0x6651c1c9, 0x3ebad1e3, 0x3531fd9f, 0x6406a613, 0xb64de75d, 0x83bfcfd3, + 0xe218e22f, 0x7efc41e5, 0x043494ea, 0x0f840072, 0x457e3bf8, 0xb5989802, 0xa4897bf7, 0x4e740f68, 0x2f0a966f, + 0xaa3e054b, 0xa12c5fe3, 0xaa195657, 0xf0e928af, 0x7affb548, 0x8fb0436a, 0xa177d122, 0x9ab9501c, 0x4c80ee61, + 0xfc751203, 0xa9a05853, 0x79fae1e9, 0x8c182abf, 0x9c43cd7d, 0xcc512430, 0x2698e9d7, 0x355b3cc4, 0xbf737e78, + 0x8c590d3c, 0x8713bc59, 0xfe2c1dbe, 0x48fa7f35, 0xf1820431, 0xa6eec176, 0x0d19a7e8, 0xb2c2e57d, 0xfc8a0eb8, + 0x79f52a9b, 0x064f8732, 0x9a651017, 0x0c7467ed, 0xf9319e30, 0xbe655cf3, 0x0810d8db, 0x7916d0cd, 0xd4c603a2, + 0xea1b59ee, 0xef8acb28, 0xa1e15003, 0xaf5e85fd, 0x1e37253e, 0xe4368ef8, 0xaf5bd3c6, 0x98a03f36, 0xc4b5dbc6, + 0x2d79ed29, 0x39453e5d, 0x9a2a602d, 0xaabb23fc, 0x46dbd797, 0xe33f56df, 0x31398e69, 0xa03d15c8, 0xbfd66713, + 0x8d590c62, 0x435f6476, 0xa308fb09, 0x1d50bde9, 0x48009009, 0xf26cd4ff, 0x4e4fd400, 0x6f34b186, 0x81c63975, + 0x9dcfeb79, 0xd22b8177, 0xced191ae, 0xf95edf50, 0x8c922299, 0x4ebc6133, 0x849dc17e, 0x0c63115f, 0x8abb54eb, + 0xab5a972c, 0x21d997a5, 0x34afe045, 0xce68baca, 0x19b1909f, 0xf8c0c9d4, 0x20d9a24e, 0x2be200df, 0x55171c43, + 0xdeb6796d, 0xfff8f186, 0x52de5f98, 0xb802abd8, 0x9f51c11c, 0xd00138f6, 0xb2f3b807, 0xc930e3a5, 0xc79e882f, + 0x9426017f, 0x6364e20c, 0x1e3dce64, 0x0d6bc7d5, 0x2806b5c7, 0x8e11b069, 0xd3041d2c, 0xfa470d31, 0xe9671b7c, + 0xdcf78b2c, 0x00ad2310, 0x39a6b5c7, 0xcfba2b19, 0x7677b198, 0x0a7620bb, 0x0ca7aafd, 0x517eb646, 0xc39215c3, + 0x4ef75ac5, 0x3b82bb09, 0xad68d5d8, 0xea8021a5, 0x7594bb0d, 0x8d84e3ee, 0x045e15df, 0xb769371d, 0x0e4b38cc, + 0x1c447e33, 0x501fc134, 0x8aa9d6d2, 0xe7c5dcc1, 0x117103dd, 0x564b42be, 0xfd7c1bec, 0xd2aec536, 0x1dce3b76, + 0x88d72aaa, 0x361a3597, 0x1bedd2bd, 0xab352957, 0x1b956d7f, 0x6c710124, 0x8aeda541, 0xe0933173, 0x278cea81, + 0xc2aecf09, 0x2e6fb704, 0x61023626, 0x65c426b9, 0x052bb9ac, 0xc3640d13, 0xfad78404, 0x253376d8, 0x05540c13, + 0x8e225706, 0x0d1a31a6, 0xa5f65cf4, 0x896cd656, 0x703377f5, 0x095a6b0a, 0xbeac5b3b, 0x1038d7f1, 0x9c3a3a8f, + 0xebb97ebf, 0x585c196e, 0x034d3794, 0xb870118d, 0xfde55a3a, 0x6de316dd, 0xa383c557, 0xba514466, 0xc0db97e5, + 0x223ac074, 0xe88a2f6a, 0xb0f58ab8, 0xa63ab291, 0xb32e8d73, 0x75a57652, 0xd50fb9d3, 0xfa7f2e06, 0xb4d54ae5, + 0x68698105, 0x833efab4, 0x88522c89, 0xbb5d5339, 0x70e4628c, 0x2bd5c455, 0xd7a564bf, 0x164a3db8, 0x6659f463, + 0x6c72abaa, 0x8582b664, 0x0fd018d7, 0x5707e58e, 0xefb33863, 0xf058567e, 0xe7eeafe8, 0x7be5b781, 0xde2186e1, + 0xf3f682cd, 0xb2182b53, 0x70fff61d, 0x4e040ec8, 0x8c27f4f0, 0x254ba66f, 0x7ded65ff, 0xee5bc73d, 0xbbe93f4b, + 0x3cde1c46, 0xb5dace78, 0x1ff0900d, 0xe5270db0, 0x90761c3a, 0xf8a3db64, 0x24654ff5, 0xafe8174b, 0x7c847d8d, + 0x53e69578, 0xeb09cf8f, 0xbfc62d26, 0x8ad8fd59, 0x1e13c602, 0xed4a74eb, 0x03ce12b3, 0x48766ae5, 0x6424d547, + 0xf661635d, 0x0d8d5a1e, 0x8756442a, 0x215f1509, 0x40131410, 0x0f998683, 0x97b1ac50, 0x9b4111ba, 0x7f262154, + 0x7d3e20d3, 0xb0da3987, 0xb93951da, 0x656cbb7a, 0x7141ca7d, 0x75eeb8ed, 0x93d98027, 0xa12bd578, 0x837ced5b, + 0xf72689ea, 0x08459c49, 0x1205a014, 0x1cb3e440, 0x8ce561ed, 0xdf6da2fa, 0x18386433, 0x52550c3e, 0xf994b468, + 0x7b80dce1, 0x8e003e48, 0x896fcc8c, 0x78cc3045, 0x53d03000, 0xab63c633, 0xfc1fb772, 0xc64a22bb, 0xa9541346, + 0xe60b6b5b, 0x173e0473, 0x15fc02c2, 0x0a1da5a1, 0x413ec769, 0xc74a9ecf, 0xfd54945e, 0x97777e4f, 0xf8d01ffc, + 0x06caca06, 0xadf1f815, 0xc8c2ae7d, 0xc04e41d4, 0xae3f939e, 0xf6678469, 0x7f92e5bf, 0x65d8ff0b, 0x7d0a3b90, + 0x4778d58f, 0x08275a1c, 0x1317281a, 0x4a10e4e4, 0xa485a9f3, 0x748306b3, 0xe6f113f5, 0x2949708a, 0xd92134c5, + 0xe4f5ca6f, 0xe7c6f351, 0x7137c4ab, 0x8586b77e, 0x6d358b4c, 0xf88d95b4, 0xfbf2af69, 0x7f8d1522, 0x55d8a68d, + 0x2439d667, 0x90caf7a1, 0x30e3bfa5, 0xa720732a, 0xb2aa3d5c, 0x2d38b01f, 0x340cb194, 0x9cc2104f, 0xa38f458e, + 0x1abf0041, 0x1ce8a0d2, 0xa6a6e0c3, 0x3a05698b, 0x88b3007a, 0x604e01c2, 0xb363a265, 0xb1b356fe, 0xb795aa3a, + 0x53e5f742, 0x4f4560d8, 0x7fcb6c4e, 0xbd0aeefd, 0x109e2b85, 0x96eead6f, 0x413bc2cc, 0xa1205844, 0xeb236561, + 0xc3507009, 0xaa60b30d, 0x39971c64, 0x182fba9f, 0xd4daa2db, 0x5a6e015b, 0xec84044d, 0x8c15272d, 0x8fc40962, + 0x871ae6ac, 0xd0765588, 0x510c30cc, 0x976f269e, 0xace0fc9f, 0x6dff1374, 0x77a1c610, 0x8ea0d061, 0x90cb86fa, + 0x051584f2, 0xc42f46ad, 0x952e3dea, 0x1d73a3d7, 0x50efd5e8, 0x41ce2aba, 0x388e40f5, 0xd40fb3d1, 0xae5e0dd9, + 0x4a480e96, 0xc4c19d71, 0xe20709c2, 0x42d9804b, 0x5971ac59, 0xb71190cd, 0x7e4aa08e, 0xaf298142, 0x33cecac2, + 0x6b64b39b, 0x41c3cad3, 0x6126621a, 0xdab7103d, 0x002ca89c, 0xa27d3784, 0xc2c52e98, 0xecf53abb, 0xfec6cb17, + 0xfd38cef7, 0xde53cad4, 0x1c90dbb4, 0x5796870e, 0x90bc980d, 0x7fb605a4, 0x425ebbc6, 0xecba2134, 0xf89585dc, + 0x7425bc07, 0xe2531b1f, 0x525aac1f, 0x4d02255e, 0x961bfeeb, 0x4f1c58cc, 0xdd7e9c3c, 0xe7daad62, 0x429a744f, + 0x7da60fc9, 0x485f9139, 0x8c9d1e8a, 0x2abe9a1b, 0x72804002, 0x0b306b43, 0xdd18cb06, 0xba7f0bbd, 0xf8e206e9, + 0x1fc95269, 0xc7c1b7aa, 0xa976fb77, 0x7af6f1b0, 0x97620f64, 0x29091bd8, 0x1b714ac1, 0x4a6de79a, 0x706193c1, + 0x11250ab6, 0xc0bed635, 0x398d9c9f, 0x3be6f644, 0xad24784a, 0x59d61a61, 0x68aadeab, 0x12eb1324, 0x1c778428, + 0x7fc8c502, 0x8df7c0e3, 0xc3b282c2, 0x7235453b, 0xa2a2a438, 0x53383d09, 0x77c123a1, 0x9171c7c8, 0xaaaf6b99, + 0x75d2b8a7, 0x6a357c9f, 0x76da671c, 0xc22780fa, 0x6111f144, 0x76506bac, 0x782c38aa, 0x45d2a5c4, 0xae66bf1a, + 0x8a6b92a5, 0xd51c16c3, 0x07b7d0cc, 0xdbb06ac7, 0x16ff102e, 0x3ae35691, 0x59826ac9, 0x6ac2405b, 0x46d8e07a, + 0x1bbc2c1c, 0x064b1cce, 0x4f0253c2, 0xb199c1cb, 0x662d4210, 0x18f0af05, 0xe435162d, 0x2315f176, 0xe12b157b, + 0x17e1d18a, 0xe0e2c119, 0x0ae823d6, 0xeceed207, 0xbc0f7f9d, 0xab560e2f, 0x00931fa7, 0xd13d1cf8, 0x90cf818d, + 0x401e772b, 0xa571c5e5, 0x3847a578, 0x9e26eb25, 0xe23beb09, 0x32c49981, 0x726010bf, 0xf8be505d, 0x2514673b, + 0xdc55311c, 0x34965557, 0x45bc2f9f, 0x72d3b84b, 0xa3043ad0, 0x0d754ae1, 0x5d985839, 0x71afc67f, 0x2fa77b56, + 0xd3731818, 0x2861f932, 0x81edb8ed, 0x54944a04, 0x9bd9a973, 0x84daf260, 0xf4f0e02b, 0xdc4285ca, 0x09508a7d, + 0xaec1f891, 0x89260e07, 0x5250618a, 0x00bb11b4, 0xb4db75bd, 0x84d351b1, 0x121b6a67, 0xf56be6f6, 0xbdba9783, + 0xfb49c6aa, 0x780a6538, 0x228a8c13, 0xaa04793b, 0xf3695743, 0x393e6361, 0x1d95c6d9, 0xd62f8771, 0x4006cdeb, + 0x5883e5b5, 0x36a6f3c0, 0xa65c282e, 0xa55b316c, 0x02a9c376, 0x4a443d29, 0x1baae29b, 0x88ccccc7, 0xe17b0c45, + 0x9fdba3e9, 0x7ab1a2d0, 0xd05a7447, 0x3e050c74, 0x8ca5281f, 0x97b5a585, 0x4a6efda1, 0xa38cec81, 0x9fe1c5f3, + 0x28ad18b4, 0xe484546f, 0xdb1b0119, 0x96d4e32a, 0xb919ff13, 0x2712098a, 0xa77c9435, 0x5bdefe09, 0xcec7c6a9, + 0x9646b867, 0xd2ff9b6a, 0x2f4fd4cc, 0xb8d50dca, 0x95533090, 0xec81878f, 0x2dd1187d, 0x83bb8f07, 0xb4a7f531, + 0x5e585425, 0x0ec8f99f, 0x173e9042, 0x3b4afda6, 0xa0629139, 0x4e01ff7a, 0x22fbde94, 0xef083f14, 0x5ae013b4, + 0xe9aeccbf, 0xcfde49a2, 0x51b44e90, 0x0ee4d0fc, 0x2e485458, 0xbb4c6932, 0x50c2a951, 0x1ae2c448, 0x0c18b0ce, + 0x6115fe2a, 0x7f52215f, 0x50ef6071, 0xa48e5ff8, 0x6750aa41, 0x1ae6a5bf, 0x4bb68275, 0xa70d1bf3, 0x2511e28e, + 0x4cc406d8, 0x7b7e071a, 0x333b260e, 0x279290ec, 0x35bd080b, 0x3fbd7e2f, 0x8f7b7d8d, 0xfeae91b4, 0x3bcfcb4b, + 0x594ebfb6, 0xbdb791f0, 0x1f7fd4d0, 0x5a86f347, 0xcf08b97a, 0x6a05e7f0, 0xcb909be8, 0x3568cf83, 0xa594d59b, + 0x37ea0f45, 0x8c065857, 0x81490549, 0x1b055acf, 0x4f96f55d, 0x28c84b6a, 0xd409f786, 0xe35b901e, 0x236161d2, + 0x10828ac5, 0x1acd3dbd, 0x51026585, 0xce2ae533, 0xd830d17e, 0x864cace0, 0xf04184a2, 0xb8bdcad6, 0xe30dff13, + 0x68de6fd7, 0x55c4684d, 0x27524b59, 0x4696fcf8, 0x2b79ebcb, 0xbf0f8c6d, 0x6328560c, 0x4df48c38, 0x62d67541, + 0x211dfa01, 0x0cc94eef, 0xbcc7f016, 0xd113c75c, 0x76758a4c, 0xe64c11ce, 0x290e6db6, 0xdb4e1652, 0x7f6e0eeb, + 0x82a322a7, 0xf07fdc24, 0x15920a1b, 0x385263a7, 0x92aee4bb, 0x0b9b2a02, 0xe236b50e, 0x85bf9a26, 0x959e3202, + 0x37f44480, 0x7c0f94c8, 0x160c6c4c, 0x2896a6ba, 0xbdcccdd7, 0x0de561ef, 0x1a9509df, 0xe738f66a, 0xd75d669f, + 0x0aa36517, 0x06c934e3, 0x612ca716, 0xb4ecfd95, 0xab7e3a84, 0x621c544f, 0x3d6983f0, 0xb1be92af, 0x3b42962e, + 0xe1fcdccd, 0x670a87ef, 0x2cc9c06a, 0x14c4f7ca, 0xf5090754, 0xcbad73ca, 0x8dbd78c3, 0x599668e5, 0x9d93ca5c, + 0xfc0c19d1, 0xeed3b204, 0x56ad01e5, 0xb0547134, 0xcfa2bea4, 0x82460302, 0x4ea81c3f, 0xe783a393, 0x3c088006, + 0x5cf6e1e8, 0x740e92bc, 0x8082de11, 0xaa5497a1, 0x4227a07f, 0x5f9e1140, 0x845939cc, 0x617133f7, 0xdd546ec4, + 0x98ac2fbd, 0x4ad5f4a2, 0x48e91c60, 0xa58a5b9e, 0x5d0bb90d, 0x5ba99681, 0x6d8bb785, 0xd202a48d, 0xdc9c6c1d, + 0x3ae4e68e, 0xd268e2f3, 0x8845a9a9, 0x14e09a77, 0x53773660, 0x06ed01f3, 0x0c020b44, 0x3c45d160, 0x15d37a90, + 0xe7ebeddc, 0xefc467ae, 0x48966382, 0xbee94353, 0xa0ac8428, 0xe6d233fb, 0xe6d3c545, 0x338a0cc9, 0x4239f1db, + 0x0a248da1, 0x04bc9dcf, 0x9dd4dd96, 0xd63cd276, 0x92c585de, 0x5c354b11, 0x17d13cd9, 0x649b8c93, 0xe16c03d7, + 0xdbfab278, 0x95dfa5e0, 0xc32dab4f, 0xb1f85d9e, 0xc702280f, 0xfdc80c1f, 0xe6050e8f, 0xd9934c94, 0x1063e4f4, + 0xbefc5fbb, 0x305c8659, 0xcc5b1fd9, 0xe10477ad, 0x0d778e64, 0xba3acce3, 0x71eae061, 0xb30b8888, 0xf58cdad2, + 0x367a736d, 0x57bace8c, 0x0912620e, 0xc0e3d1da, 0xb63af2d9, 0x5a91896a, 0x726f4c21, 0xa8fc2611, 0xfb56a0ba, + 0x528e31f8, 0xd713c705, 0x32ba3f49, 0x66b0dfc4, 0xbfa55505, 0x2c18b584, 0x5c882bf5, 0xd20f6c3c, 0x2de9737c, + 0x4e4651c1, 0x02cf345d, 0x31fc3f6c, 0x5faa4240, 0x493e3fd5, 0x6887248d, 0xc15636fa, 0x1803c7df, 0x9233d52e, + 0x62615575, 0x0532e5f6, 0x1ec1c28b, 0x3b389b82, 0x0110fd01, 0x49f4eac7, 0x361988dd, 0x42cf1cd2, 0xd1516140, + 0x8c5658b7, 0x78f805bc, 0xe5501e84, 0xd8ea651c, 0x61faa8be, 0xe74de8b4, 0x70cef733, 0xf5123834, 0x1fded654, + 0x69d0ffc6, 0xc836849c, 0xd71e493d, 0x8b77e5a8, 0xb7931a11, 0xc10a46cd, 0x65eb91d6, 0xd790d47e, 0xe9af74a4, + 0x169a05b9, 0x4e537d11, 0xc7d5a93e, 0x2d05ae57, 0x20c0d796, 0x29dfa540, 0xb5398fe9, 0xd452443c, 0x72085842, + 0x2a29bc81, 0xee737091, 0x4c323da7, 0xd7983120, 0xcf81638c, 0xaa2a582a, 0xd80636b4, 0x167b4b17, 0xc51ee300, + 0x15bf6a2a, 0xa895bf14, 0x4e2ba747, 0x4540911c, 0x1e0b29c2, 0x76ff0bf5, 0x21935fe5, 0x63413b47, 0xb7dc7b2d, + 0x344c4586, 0x00ba9ec5, 0x1c55d568, 0x61d0506d, 0x4ae9ae1b, 0xbc2820bc, 0x724523bd, 0x153dd2ae, 0x185b4b78, + 0x40580366, 0xd4042540, 0x1eecf0b7, 0xa0941c66, 0x6a2223bc, 0x5f524ca7, 0x8dee0eda, 0x897901c0, 0x4b4f701f, + 0x9d90a173, 0x2acbb3f5, 0x92931c90, 0x996f61b6, 0x181e04e3, 0x737a1581, 0xa3d892ce, 0xa5fb44ed, 0xef1e2283, + 0xacf2e1cc, 0x86b6f17e, 0xb1eeca29, 0xc6277ac8, 0xcb5c1f54, 0xe7122e01, 0x0bcd0465, 0x32d82e66, 0x9a38104d, + 0x7a16e4a9, 0xef97c686, 0x3d927bdc, 0xfa284623, 0xeaedfd3b, 0x69c04add, 0x20f7b0db, 0x33dc3554, 0xea805359, + 0xabde9131, 0x38e7161f, 0x0afcbc1e, 0xd1e1b3c3, 0x0f697ee5, 0x24cd56c9, 0x31f1fb56, 0xb02fcfa9, 0x94731698, + 0x45cf2ad1, 0xb310433c, 0xa5d721b3, 0x20dbc6ad, 0x918c7e17, 0xbd775a05, 0x21918eab, 0x8b851b81, 0xc1475a54, + 0xf6d9d53d, 0x1fbcff8b, 0x458dba06, 0x717cc8f1, 0xbd4373bd, 0xf85cc5c9, 0x9fe6b23a, 0x487a0650, 0xcd13dd30, + 0x106261b3, 0x19c45a9e, 0x35894c63, 0x0e149019, 0x14477447, 0x839011bf, 0xa69a41d0, 0xf5f5bd6d, 0x03183b74, + 0x9adaeb3d, 0xb6c2b7db, 0x37d7744e, 0xef6b3c21, 0xcb4843e5, 0xe0cd16e8, 0x0308b927, 0x84521f96, 0x039af9bf, + 0xd4fd49fe, 0x8bbc880b, 0xe5884b9c, 0x694009dd, 0xec711a7c, 0xd94bdbf9, 0xa8804fb2, 0xc8c485d2, 0x72775573, + 0xeca76208, 0xc5771e25, 0x3306d750, 0x93169214, 0x7d78f3b2, 0xf7cbf28d, 0xd312cfcb, 0xf76b5ef7, 0xfe5be875, + 0xf8c8fa03, 0x549680e7, 0xcf85c421, 0x86c2b785, 0xea908ddd, 0x1b42565d, 0x62362886, 0xe754860a, 0x1256f434, + 0x2da73456, 0x71d6e0dd, 0xb84b1920, 0x7e4a9dfb, 0xb9b6cb37, 0xbe94ac69, 0xa19376a7, 0x4fa6f321, 0x970d6ceb, + 0x8753a289, 0xbb4fb1d3, 0x514bf650, 0xb6335d4e, 0xdc8cb84d, 0x775cdebb, 0x7763b73f, 0xc86e504a, 0x4f2e0f89, + 0xeddff0a2, 0x73a3d91b, 0x53258442, 0x1b363149, 0x372f24ba, 0x26a84190, 0xc99e0a5f, 0xc063baf8, 0x9f1aa14c, + 0x37092230, 0x281f0395, 0xf058a01b, 0x526d10e0, 0x4e613b15, 0x6927a0e1, 0xfae2508c, 0xecedf616, 0xcd40f66b, + 0x77e44ed7, 0xe10f083c, 0xbd0eee43, 0x4bed20df, 0x7d1ac6ed, 0x579b909f, 0x1af8767b, 0x38a79938, 0xc7ee1ed5, + 0x402842f9, 0x7b402349, 0x3adcf0b9, 0xfab8525e, 0x73b77d96, 0x01614b53, 0x1ecb4069, 0x8d7b9ae7, 0x5c86811b, + 0xf5516616, 0x3b8e4502, 0x4f8146c7, 0xc6ad0924, 0x6a2d990d, 0x75bb6532, 0xeea1f5bb, 0xe03b18cb, 0x5d8a813e, + 0xd7452570, 0xb3719234, 0x538177a0, 0x9a8d3f0d, 0x3da6c108, 0xab95bf92, 0x066c9d91, 0x483344bb, 0x81ce3a91, + 0x804dfcdf, 0xbecabb3c, 0xcbbad8e3, 0xad174c84, 0xb25b9053, 0x9945338f, 0x1d9a5c6f, 0x6b35fd94, 0x5d3099f3, + 0x09fe6352, 0x116f59fd, 0x5142f1d4, 0x5e8a65bd, 0x4bfbb2c4, 0x07bf283b, 0x47bc5c0c, 0xef6490a5, 0xcc2a6ff7, + 0x22f1053f, 0x812ca1ae, 0xea53bdb7, 0x6f9064ad, 0xdc487fb1, 0xe5a72641, 0x19b90c00, 0xdb3493be, 0xf38fa223, + 0xff018fac, 0xf29264dc, 0x79cfa996, 0xebef3ab1, 0xfe46ed6a, 0x34b08d13, 0x8321a03b, 0x68146348, 0xbf2f8413, + 0x5677ce1d, 0xfaed9768, 0x398c7cec, 0x829d359b, 0x53c13706, 0x79fc8af1, 0x28b5945f, 0xa0d37d4c, 0xfed8fcaf, + 0x2ea71b01, 0xf86a9587, 0x10cae7e8, 0xd5036fea, 0xb5616419, 0x860aabbf, 0x8669b790, 0xaa8769a3, 0xb7ce90bf, + 0x04eb2c6f, 0x5e140cce, 0x1ebf90aa, 0x0c4f85fe, 0xbda841e7, 0x4cdf60f1, 0xb2aba20b, 0x885e725a, 0x6b674031, + 0x091c00d8, 0x4c817357, 0x12b397d2, 0x195ac239, 0x60073530, 0x501a6ab1, 0x12a51a2b, 0xbeec52db, 0x693d6979, + 0x47373d5c, 0xdd10d30e, 0xe403398e, 0x151ef908, 0x6b74c5ed, 0x922f5599, 0xf616c405, 0xe1826d33, 0x57ecd662, + 0x06a0841a, 0x407719f8, 0x87813be3, 0x6dbdb570, 0x4d81044a, 0x4e797352, 0x4fc46dd0, 0x8103c12a, 0xa8aa54ba, + 0xaf177fda, 0x393688b7, 0xbb2b6ecf, 0x7108f730, 0xb8ceb677, 0xa900b27c, 0x9d33e449, 0x5ad73504, 0x520641b1, + 0x132fc69a, 0xae01fa3d, 0x2312ce3c, 0xaeb55a82, 0x12877650, 0xcc466689, 0xa694f0c6, 0xc894e616, 0x75228c2a, + 0x45d9d50b, 0x4c8691ef, 0x1321ccb9, 0x248d4322, 0xda108d64, 0xf3510b20, 0xaf085c01, 0x6d223642, 0xed630d33, + 0xbf822846, 0x11a7a79f, 0x58564421, 0x8a20e469, 0xd767d0ee, 0xff3fa485, 0x055663f0, 0xd46a8750, 0xe756676b, + 0x0bb94d94, 0x47399350, 0xa5c70a97, 0x4b8af5b9, 0xcb975a61, 0x0a32b76f, 0x95324224, 0x097d91eb, 0x39cb1087, + 0x2664dbe7, 0xb0b2515c, 0xc1b5e371, 0xb21bd15f, 0x78153bf2, 0x7a246b4d, 0x369d9230, 0x6353d7c1, 0x943e776b, + 0xc6c651e1, 0xfc110c78, 0x2cd89447, 0x2bea8a23, 0x7f2456f6, 0xab2386be, 0x6d053059, 0x87d0929a, 0xaaf61481, + 0x35d28e21, 0xb6b2abe9, 0xca746785, 0x76bbc20b, 0x245cd4db, 0x6a903160, 0x53db424a, 0xf81a2e02, 0x33c4e3fe, + 0x8d337ec8, 0xd89c6c03, 0x1a39c8d8, 0x741705ad, 0xffd0499f, 0x272616cc, 0x27943ca0, 0xa5f5e07e, 0x10aa7059, + 0x9c96478e, 0x1e5306e8, 0xf04c8f4e, 0x2469dc7d, 0xa487fdd4, 0xb6c46a1c, 0xdf5f5d32, 0xacd2359a, 0xc47dfa09, + 0x9cd610d6, 0x63fe81d4, 0x47a5b035, 0x48ac0542, 0x0a428125, 0x2100683b, 0x971db31b, 0xb399c6e3, 0x7d4c35c3, + 0xe4025606, 0xfa04b505, 0x1a13f307, 0xa3f814f3, 0x0493ca70, 0x2c8fee14, 0xd179a4ec, 0x884e213a, 0x45002700, + 0x8e458059, 0x1f25e46e, 0xad744c6e, 0xe399e1f0, 0x5ad32c6f, 0x634d5873, 0x3ea38be2, 0x7d562b64, 0x1d30d113, + 0xc5f814f8, 0xd0eeaf03, 0x6e65c40b, 0xe513732b, 0x515bb642, 0xa8df6c6c, 0x3eeeb445, 0xddfdeb7b, 0xe1961f30, + 0xc4680594, 0x1870bcc6, 0x20a9d724, 0x6a2d1f39, 0x74139e11, 0x1fc2d45f, 0xd19855a2, 0x3f2cfe66, 0xcb4f7145, + 0x6e238101, 0x1e816b7e, 0xebade788, 0xa90ce157, 0xd1d495e1, 0x932e2ef6, 0x2fb8b9fa, 0xe24259e8, 0x898adc85, + 0x2dbdf790, 0x869cc363, 0x9253921a, 0xe3632d01, 0x8c5dfe64, 0x50516890, 0xfe47c414, 0xb160e3e5, 0xb7ed51eb, + 0xaf7f33f7, 0x4189b57a, 0x6e10ac0b, 0xa9b8885e, 0xd111a1e2, 0xbae90500, 0x10bd3e90, 0x845095bc, 0xe5cd0757, + 0x9f424f6c, 0x37f3279e, 0x6d1996e7, 0x37559e87, 0x61efcf0f, 0x238d20a4, 0x0c90ca42, 0x06082fd1, 0xd99046e8, + 0xa75607a1, 0xd8a4c712, 0x48657f46, 0x7917abc6, 0xdcb5c534, 0xff4a25b7, 0x4f968f85, 0xbb672457, 0x65c26ef8, + 0x846b3445, 0x094bc485, 0xb59d4d66, 0x9a19647e, 0xde8ddf87, 0x45fc5c09, 0x15bd9180, 0xf902556c, 0x6cd5ff39, + 0x1ebe9178, 0xe463d67b, 0x61bb7d55, 0xb34d167c, 0x247a2ebe, 0xbd366363, 0x7064ac3f, 0x8a22949c, 0x03ac46ec, + 0x93e5cdaa, 0xe1eeb0a0, 0xb2662d1e, 0x09fa78a9, 0x621bbf75, 0x45dc184a, 0x9c0e84f5, 0x014760fd, 0xd0b788ac, + 0x7f6d4138, 0x7243664f, 0x511d7f8b, 0xdac34d1b, 0x1e3581d9, 0x3ff8374a, 0x04903e90, 0x64985b1f, 0xebba1639, + 0x139ed99a, 0x94870314, 0xdaf3c04d, 0x33472768, 0xcae2c5f1, 0xa2db14b5, 0x83da2727, 0x051a3ac4, 0x8aad87d2, + 0x670ac9c5, 0x9de1e765, 0x3744015e, 0x38339682, 0xb0ddfeaf, 0xfbe851a7, 0xf1b9bd60, 0x7df343fd, 0xd8bc0071, + 0x23edf857, 0xdbf71dd2, 0xf0ab2c30, 0xe6d87498, 0xd8a9f252, 0xd1ccecc9, 0xd5732b14, 0x730b9c51, 0xafeb424e, + 0x1ec779c8, 0x2319b5b3, 0x62fc8382, 0x283e797b, 0x7aeeaa4e, 0x214da719, 0x011ca3a3, 0x70e5fad8, 0x19a9b3cf, + 0x3d4de6b8, 0x7a32125d, 0x359e3133, 0x532b3038, 0xbd8bebad, 0x2360b3e6, 0xd23144a4, 0x46b9399b, 0x1bc31a9a, + 0x60f2e866, 0xa8c04591, 0x496894cc, 0x4a657760, 0x139b92c3, 0x3b132521, 0x89061ad0, 0x226af7a6, 0xad6b65ac, + 0x4a8924b9, 0x976addd2, 0xd670860a, 0x61469722, 0x0db71fea, 0xb45a84cd, 0x511c1371, 0xf0f529c4, 0x002bb336, + 0xeabcc870, 0x78e9c31a, 0x54fa8922, 0x343148f7, 0x84b8b767, 0x0bd7099b, 0xe76b5c71, 0x8b126e2d, 0x0feb65af, + 0x95f55ee3, 0xb0493546, 0xa81b67d9, 0x40d2daed, 0xf83c8492, 0x853a2bf1, 0x296ac510, 0xd89b962c, 0x273ab9aa, + 0xfc18e2f0, 0x78403acd, 0xf175076f, 0x8b4f8479, 0xe12c2a56, 0x36153bd5, 0x2536c405, 0xa62ebddc, 0xe40d3009, + 0x475a6fdc, 0xa673110b, 0xe2723676, 0x969094dd, 0xf24e65b4, 0x39e93824, 0xf62984a6, 0x86835678, 0x0aaa9f53, + 0xb38fc365, 0x8433c960, 0xf3dd442c, 0x068fd746, 0x6005408c, 0x624ef6b5, 0x082ad24e, 0xc2ff4ee2, 0x876ddb9b, + 0x40f47d02, 0xe0912c6c, 0xa0788754, 0xea7425fa, 0x1fa88f07, 0x437e51e7, 0xd746a4dd, 0x8985fbcc, 0x101eab79, + 0xf4c0de21, 0xb88b0269, 0x0d9a401e, 0x6d85b516, 0x9203db76, 0x54ecf0d5, 0x21f07561, 0x28fe8f56, 0xe05b58bb, + 0x65182975, 0x4c22d743, 0x4e40a9cf, 0x046f0d7a, 0x851651e7, 0x3f7256e7, 0xf5565d86, 0xd14e9cb4, 0xa46c1f9b, + 0x0abc8f0a, 0x36e8881d, 0x0df4a97b, 0x85dd5880, 0x59c083f7, 0xfd1dba18, 0x18e6b040, 0x8e0f33c7, 0x9fa484eb, + 0xb84d762d, 0x7847ef47, 0x7e02a139, 0x28594852, 0x561724b6, 0x81cd3e50, 0x55b5e090, 0x3d0a097b, 0xba4723c3, + 0xb625650f, 0xbe9ee9c4, 0xa5bdcd04, 0x396d39d8, 0x016c987c, 0x1ad64ead, 0xc761a79f, 0x945a8a92, 0x64ac5078, + 0x7ed670b7, 0x7878e5e5, 0x6f76f8f2, 0x999e13e5, 0x7498170e, 0xf2116b6a, 0x5d76dc92, 0xb228972e, 0xc06f5a00, + 0x3c76355c, 0x1aaac47b, 0x4439d58d, 0x429a4bc3, 0xd99b28f9, 0xb13371b4, 0x60fa446e, 0xd214777f, 0xd4982bf4, + 0x7abc8345, 0x22cf8aba, 0x890af84e, 0x5ff228c8, 0x3cfc6dbc, 0xf80c2808, 0xf03b011e, 0x763610b1, 0x4dc68465, + 0xa109bed0, 0xae26e87b, 0xf6159129, 0x9e1fce3a, 0xfb0a3d82, 0x26e81535, 0x279c17a1, 0x007fa8d8, 0x43fa2532, + 0x6eba2042, 0xcbbc98f3, 0xa558b295, 0x9e643bd5, 0xc9a55275, 0x47b91950, 0x20d96679, 0x56e918ee, 0xf392dd7c, + 0xefb4e63c, 0x646a992d, 0x6151a255, 0xa996fadf, 0xac50ee8b, 0x1f8aa654, 0x44c8a307, 0x83dd06f0, 0x0714a333, + 0x13d907e2, 0xc56a085e, 0xc1f711ec, 0xbb9aecc8, 0x798212d4, 0x989ba9df, 0xc93be9ee, 0x24c810cb, 0x9c72fcf2, + 0xed22608f, 0x803fc6b0, 0xbadb60e0, 0x9716d502, 0x7b2a326b, 0xe1d8e524, 0xc77cfbb7, 0x72378d13, 0x3b41eac3, + 0xb11e8bef, 0x9e35b2af, 0x2019b380, 0xfcc9cb15, 0x82c6f1e5, 0x83b7e974, 0x7fa0156b, 0x28d27514, 0x6ce527c7, + 0x7283d119, 0x914867a0, 0x10a69bc7, 0x19b2a68a, 0xf6e7b2cd, 0x82cac361, 0x0b23da51, 0xa11a4b54, 0xca12f4d2, + 0x8eac5ed0, 0xbdf746d5, 0xdba37d4c, 0xfed4a359, 0x52755551, 0xc4a924a5, 0xb38e1894, 0xdd79db6e, 0x508ddf39, + 0x11c17045, 0x708b655b, 0xbcef9220, 0xae784c78, 0xb415c4ca, 0xc6285e1d, 0xfba18508, 0xd20523b9, 0xac472a31, + 0x9ce9cbe2, 0x8c2310f8, 0x33bc23d0, 0x358a7194, 0x33428b1c, 0x8ad86694, 0xa06d47f4, 0x82bca282, 0x341937bc, + 0x64a2292f, 0x14936b30, 0x04fba78f, 0x28e2788a, 0xb4c35dfe, 0xf12af912, 0x8b338756, 0x6df92d26, 0xa39012cb, + 0x27edf4a3, 0x7f5c37eb, 0xdb922da4, 0x0517be2a, 0xa60b66a6, 0x5b593f21, 0x56b9a392, 0xe7072a3d, 0x516aff77, + 0xb6d1a15a, 0x00f736c6, 0xac15fd4c, 0x17376cae, 0x1f613889, 0x27f16878, 0x46dc8d0b, 0x08ba11b6, 0xb9fa8cf6, + 0xef6cc1b4, 0x4e7bce04, 0x5004f19d, 0xde4835db, 0x31200c16, 0xc03b86e7, 0x67e7ad4c, 0x6c80ad85, 0x0cfadd5b, + 0x53a6b6bd, 0xb7c44616, 0x8e3d1b6e, 0x801c6497, 0xf0580d18, 0x42352c7e, 0xe38196b0, 0xc4121250, 0xb7982b58, + 0x24cf45d5, 0xc8eeda69, 0x44507fe0, 0xba93a881, 0x88f1a1f1, 0x626db2d0, 0x7e3dcb99, 0xbd838334, 0xd087c3e9, + 0xdbe38eae, 0xc76e9b24, 0x725989e3, 0x42572e18, 0x8a077545, 0xc052784b, 0x87d38e4e, 0x09dac348, 0x2861ed9a, + 0x4dab9f1a, 0xacc53831, 0x82f5bd56, 0x167e830f, 0x18d93959, 0xd6401a8c, 0x4d80e5fd, 0xbe03f358, 0xb8c23e7f, + 0x0fc70ffa, 0xb31e6625, 0x260e1bef, 0x9117f145, 0xd3d13c01, 0xd1d5b539, 0xc7960965, 0x65d58611, 0x6f248c7e, + 0xa1efd016, 0x4eb05472, 0x229c4bca, 0x915d0fe2, 0x18384167, 0xc224367c, 0x76940876, 0x9ba0777f, 0xaf775734, + 0x0e2ade94, 0xe0189f21, 0x64add66d, 0x9a2253a3, 0x6e409ba1, 0x710163cd, 0xf95f21c7, 0x9d010910, 0x116311ab, + 0x6f523e25, 0x9c44ceef, 0xf11756e0, 0xf90c87ef, 0xec31321e, 0xc42d2eed, 0x00bf2a6b, 0x0dc7ef35, 0xb82bcb48, + 0xf385143f, 0xf823eeff, 0xbab7de2c, 0x4766ac39, 0x5154e4cd, 0x01032e8b, 0xeeb697ab, 0xec77678a, 0x939081a3, + 0x38e6bfa3, 0xb2ca4ee6, 0x1adf7fd3, 0x715f6720, 0xdb7e744f, 0xdb96087c, 0xf51095c7, 0xbf565b25, 0xfc4cb25a, + 0xa3811142, 0x7f1cd307, 0x1b68b69c, 0x3392741a, 0x916d90bd, 0x87728a59, 0x362c4693, 0x98278ca2, 0xb57c2786, + 0xde3347b2, 0x1dc93598, 0xc3da82cc, 0xd235c84c, 0xd0162632, 0xffdc464e, 0x6248bcf1, 0x7fd5d3ec, 0x1f825138, + 0xa7fd3eea, 0xde0683b1, 0x7d4d2c6c, 0x01f06618, 0x5948fb6f, 0xe2280ae4, 0xa02de20b, 0xe853648b, 0x124dcee0, + 0x2b29017e, 0xbef44052, 0xf0fef3d2, 0xca72753f, 0xc0c271e1, 0x043afb50, 0xf2e2e2af, 0xe4d7b8f0, 0xd7fd6e96, + 0x80f6e55e, 0xe93cbf38, 0x24c1690e, 0x3b09ab44, 0x66ca9507, 0x7a5771f9, 0x98b81096, 0x29566556, 0x1a810cab, + 0xad9b8173, 0x9c26a17e, 0x354c3e67, 0x27ee00be, 0xbf0e8290, 0x3ef84fa2, 0x19433bc9, 0xf190e16f, 0xf30d08e5, + 0xa0abaad0, 0x6d47d339, 0x5d071dcc, 0xb8f12243, 0x328b314a, 0x28ae8657, 0x2f58113f, 0x526466a9, 0xff94978c, + 0x764fd4d4, 0x1c034f01, 0xeb4cd2b7, 0xf3c60aa9, 0x8d573623, 0xf5607c9a, 0xec7fb5c2, 0xa2430624, 0x8cb9187f, + 0xf8750e09, 0x34e1a40d, 0x19b0e056, 0x116b784a, 0xe1881a7a, 0x7c074f9a, 0x637860e8, 0xaaf9adec, 0x2b58bbc7, + 0xa0486a56, 0xfd2db708, 0x180bafbc, 0x21fe756a, 0x1ba5eb99, 0x1e97b3b8, 0x5e0d1434, 0xde356fdc, 0x4f961979, + 0x62004294, 0x171f13dc, 0xda028ac9, 0x58ab9e43, 0x94a81f1a, 0xb1f75007, 0x608457fb, 0x8fd057d7, 0x3d00ea6a, + 0x9366de92, 0xcb066510, 0x8e4aa61d, 0x8ed24d41, 0xc2363829, 0x8bf5f85a, 0xfea1e715, 0xaee55fd3, 0x91227302, + 0xdbf5b541, 0x8f0f5c93, 0x4f718e7b, 0x580446e1, 0xae6d3bac, 0x53fd22f7, 0x19201498, 0x0eabc2c8, 0xfbd32a69, + 0x3e8827a0, 0xad78d2a7, 0x96e55db4, 0x1e85474a, 0x2607937a, 0x01046734, 0x165bb09e, 0x814d9c1f, 0x31fc11ce, + 0xc9a46fbc, 0x06104a39, 0xf80c0083, 0x5f2f38df, 0xadeab423, 0x578848aa, 0x5a2b6a61, 0x9c256ebc, 0x17ec4180, + 0x6679b8c9, 0x521bcb0e, 0x0f5e773e, 0xa3cbe211, 0x04adf29b, 0x2218a099, 0xe6135070, 0x6294163e, 0x993d15a6, + 0x83306a8e, 0x8bf0466c, 0xcd545f08, 0x1213ded9, 0x1de1945b, 0x4ff3e186, 0xa6b6470f, 0x36100310, 0x13743c57, + 0x85a45b83, 0xb6c870a3, 0x586ed056, 0x43e895f8, 0x5581ade6, 0x6a769c51, 0xac752f77, 0x678cfe85, 0x987212f8, + 0x2c16063c, 0x756371f4, 0x7e959f82, 0x2300f4db, 0xaadd0dec, 0xc476dd3f, 0x9126dc8b, 0xbff676a5, 0x55f02c5b, + 0xebd89b18, 0xf9eb620a, 0xeac8d3a1, 0xe2a04276, 0x042006d4, 0x7f9777a7, 0x4e060931, 0xcd5c0d73, 0x132d8e5d, + 0xf5f0a3bb, 0x499c9213, 0x7baeaa38, 0x3b16c88c, 0x19dcc7f8, 0x341b7451, 0x625413a5, 0x1aaea474, 0x53a5f495, + 0x9a3e8b5b, 0x5bbb0d0d, 0xac671810, 0x37936049, 0xaf3918e4, 0x4bd23fd5, 0xf112fe79, 0xf50b7779, 0xd72a5a95, + 0xe529bb7b, 0xa9bb4c68, 0x11813d57, 0x6cd899fe, 0x4d8e05be, 0xea753082, 0x67e050aa, 0x9bee6388, 0xdece7a4a, + 0x90c9cbec, 0x0a550012, 0x637e2011, 0xaea394ca, 0x1c25a238, 0x4838705d, 0xc55563f2, 0xd52438a7, 0x2cede4d4, + 0x0b71b9d5, 0xdcb2253a, 0x89477fb8, 0xbf618f7f, 0xfdd57ee2, 0x71839b66, 0x2d82450e, 0x30a1922b, 0xcb854a25, + 0x71f6b655, 0xcc7546d6, 0x672e927e, 0x76a7dbd0, 0x5d9a9c0c, 0xd956615a, 0x6bcefb4d, 0x0954c667, 0xda08aeda, + 0xfea87951, 0x4e85ed6b, 0xf141b221, 0x967ec912, 0xac9e23d3, 0xb1df2536, 0xfb290064, 0x453da5ec, 0xea273050, + 0xbee48106, 0xfd187df9, 0x26855acf, 0xef6bd41c, 0xf2550baa, 0x17668ebe, 0xcb88d9fb, 0xec4c1f0a, 0xcbbe2122, + 0x9d37b03d, 0x4607bc93, 0x3041a06e, 0x86c4c702, 0x48a965c2, 0xc12b15d3, 0xdd2653cf, 0x1d73715c, 0xf68610ec, + 0x0eeabf55, 0x4ba075d7, 0xcb167da9, 0xbdf041ee, 0x87bde965, 0x38f5abde, 0x0ed44df7, 0x56ac3a98, 0x3140b521, + 0xba8a27b1, 0x954b50a3, 0xf19fd800, 0x3f5a3e66, 0x24781e6b, 0x228f5f23, 0xb27f9d70, 0x046a9e97, 0xb813c058, + 0xdae3ad68, 0x3464b7c7, 0x9a2f1d17, 0xa95f1823, 0x3186092b, 0x207e7558, 0xb3bcf558, 0xe7d01a5a, 0x318131bc, + 0xd667c03a, 0x212f0642, 0xeb7ee6db, 0x17e0166f, 0xb2605be1, 0x7850384c, 0x79b26ee0, 0xebbe8c58, 0x422ec1aa, + 0x1b812987, 0x7f775898, 0x5203b843, 0x5711b1fa, 0x1884d30a, 0x9546b504, 0x6f7d7f85, 0xff280e63, 0x0d801e52, + 0x6a352c5e, 0xbb533dbc, 0x742d5ea7, 0x07c9906c, 0xf6da6e41, 0x6626e39a, 0x81fc40a9, 0x19353de0, 0x59a42447, + 0x7a41432c, 0x3c7b8ef2, 0x200100e7, 0xbce43559, 0xb0409806, 0x4e0d4f33, 0x0226f4bb, 0xe5607e36, 0x3819e622, + 0xb37dcdf2, 0xc5903b55, 0x66c4ce19, 0xfce6bbd8, 0xd4b96857, 0x32a3c8fb, 0x104c26d3, 0x0a2619d4, 0xa83ef1d3, + 0xed9a9d05, 0xda648c6e, 0x59a7d2f0, 0x0ba0dc58, 0xaf315272, 0x3b822f0c, 0xe80b071f, 0x6d580dd5, 0x9a79fb16, + 0x12716a76, 0x6586c78f, 0x8ba6ad87, 0xb1f589c7, 0x69a3a495, 0x934bba87, 0x1d69c4dc, 0xc631ef0e, 0x5ed8f0a1, + 0xbeb0ba0f, 0xe53757e5, 0x1f2473d1, 0x7e79e355, 0x9c717c49, 0x7ad3f417, 0x5f1caa11, 0xa53028e3, 0xa3daf8fe, + 0xd3e8909c, 0xf5e6af7b, 0x3e2bfcc6, 0xd7dda350, 0x816cdc87, 0xf8107f59, 0x69e5d6ae, 0xcab2a98c, 0x21fe2bb2, + 0x4041c1eb, 0x08c5be6b, 0x46666c2f, 0x75e6573a, 0x49bfc547, 0xa51f79aa, 0x35873d8f, 0x0f9c2519, 0x03dd6634, + 0x252abc45, 0x8db4d8be, 0xdca118e4, 0x4beb8841, 0x7af8a7aa, 0xe8681db8, 0x633241f4, 0x642c40e6, 0x0f0a742b, + 0x3e3a4e93, 0x75a35c85, 0xf80690d5, 0x456ed7ea, 0x3d282bbf, 0xd9a5f43b, 0xce728330, 0x969f3f46, 0x2365d1a3, + 0x70e96032, 0x14dc5bbe, 0x9a7f1a19, 0x8bfe8e83, 0xca54a8c7, 0xdbfcd764, 0x6d9a4277, 0x179d94fd, 0x2d93c30c, + 0xc8f33106, 0x9a4f47a4, 0xb15c53c4, 0x89a92b84, 0x412a4045, 0x82782684, 0x307c02e0, 0x908ff9e1, 0x2f9b93b3, + 0xe75df8c7, 0x1b2afd2e, 0xdb8b2148, 0x13f7cb04, 0xc3e9e47f, 0x1de402df, 0x05cee3e3, 0x7884ad3f, 0xab74ee22, + 0x6e99841a, 0x348ed138, 0x93b33f28, 0x4e26f859, 0xe833ef23, 0xd6aa57b2, 0x8dd56824, 0x4dd69d54, 0x2579a152, + 0x9733f383, 0xbb3ae5a2, 0xe335d071, 0x98da119e, 0x578e2220, 0xa7f49076, 0x12324693, 0xf4956579, 0xa6f4aa6f, + 0xd28dfeff, 0x3461ed36, 0x2df76c03, 0x7f71bd4a, 0x34a33167, 0x5b6768b7, 0x8a68a337, 0x868ab587, 0x909e465a, + 0xe6b823a7, 0xae47a8b5, 0xc004e20f, 0x246c5331, 0xfd1564ee, 0xa89ff0b5, 0xcccedaea, 0xde9c932e, 0x049d67c0, + 0xefb9470c, 0x70341b99, 0xcf44a2bd, 0xa7aca703, 0xfdfe7004, 0x57149f46, 0x5042838f, 0xa4a563ff, 0x1aa9c1f1, + 0xcca4b625, 0x681d3fb5, 0x3f2272b2, 0x2606eccf, 0xfa6259eb, 0x4fef9492, 0x652284c0, 0xb93f6b24, 0x8066bc74, + 0xc2691272, 0x5b2417ec, 0x5d350634, 0x988d30e3, 0x8824b59f, 0x1f4ed9cb, 0xb3d17205, 0x12930421, 0x30a32bdb, + 0x644a4b8d, 0xa0934fdf, 0xf7d74218, 0x031c7808, 0x2feb641d, 0x22a8ab65, 0x64b9814c, 0x93c500c5, 0x42987649, + 0x87e4308b, 0x43a350ae, 0x5f55a615, 0x283d0456, 0x63462cee, 0x5e55e7cc, 0x4106c2fc, 0xa1222dbb, 0xa71eb009, + 0x5dd482b7, 0x7444e8ba, 0x889bef59, 0x5c01289f, 0xfccc850c, 0xd31d76b8, 0x43bc3ee8, 0xd13f9d38, 0x409c8efc, + 0x247f98e0, 0x67de1e70, 0x412c6977, 0x7cfb4a7f, 0x8ab3955f, 0xc60d945a, 0x3d8c49e1, 0xd397ee0a, 0x03e449ef, + 0x5f8ed8ba, 0x48b8901f, 0x7f96d34f, 0x8ab109e2, 0xf4270e6c, 0xaa4036cc, 0x95cfc376, 0x13f9bc97, 0x3e3f21e5, + 0xbd1e0749, 0xf0c2c1de, 0x746e5f60, 0xb7022d91, 0x2fc4c397, 0x792cf485, 0xb2f78986, 0x1acfe8ac, 0xfd063ef1, + 0xfc595569, 0x8e252806, 0xee9907ca, 0x4d418cd5, 0x373aa1ed, 0x608441c4, 0x541444c7, 0xe662e537, 0x0a4c87b0, + 0xf121eaae, 0x21df9fa4, 0x80c89e3b, 0x9ff78cdb, 0x72191c2c, 0x999b663b, 0x729a6bf8, 0x475754f5, 0x2e0b76b5, + 0x8ffdd791, 0xc63d72e0, 0x2bbfdac2, 0x39490db0, 0x7479cf6a, 0x8195b9de, 0xb3f2f2a9, 0x3ffb3234, 0xdc6af063, + 0xcf7c7db4, 0x491cce93, 0xf6de6aed, 0x19c2047b, 0x62b5d4e5, 0x6f7e2416, 0xab315652, 0xebfa613a, 0x01e3371e, + 0x3f4a1925, 0x2607e102, 0xedbb52ec, 0x9f47aa14, 0x00301d24, 0x81283f1f, 0x9e6b0686, 0xe8b5ba62, 0x38f2ed6b, + 0xf889a118, 0x016d425f, 0x830f762a, 0x0693359b, 0xb0a1c67a, 0x30b4ad6a, 0x2c67239c, 0xb8878394, 0x2d41dd3e, + 0x1854dc13, 0x5256ddcb, 0x8305ad56, 0xdd2468e4, 0x3632bf3d, 0xe9ac7e38, 0x1ee01367, 0xd8aa28d6, 0x067d3a5a, + 0x9edc60a6, 0x3ec82700, 0xee5e8abd, 0x797500aa, 0x506ee73f, 0x1f3954db, 0x53dac852, 0x2335b989, 0xdefe686e, + 0xf9b05fda, 0xa95df3a4, 0xabd52e5e, 0xeae80974, 0x3ba76bd7, 0x0180dab6, 0x304b9967, 0x53213df3, 0x1e24df3e, + 0xa331bf5b, 0xb260ee6b, 0x89fac910, 0x5e9d5f42, 0x1aa7d7e4, 0x9b07f2ac, 0xb43cf943, 0x2ae55410, 0xfe05d6dc, + 0x0e8215bf, 0xb0127017, 0xab9ddf17, 0xbbd89a81, 0x00d7e8b3, 0x4243ed3a, 0x53caf315, 0x684a7f2a, 0xc0946b2a, + 0xe05d568f, 0x095b230b, 0xbef16416, 0xd4c3d0d7, 0xa3bfafa7, 0xd56d4761, 0x34cf3c58, 0x5c117120, 0xccc6c9a6, + 0xa1c25f5a, 0x5bffa28a, 0xd58c06b7, 0xce4c32c0, 0xb04ea0d6, 0x1711966d, 0x4155a105, 0xc8dee540, 0x39f37627, + 0x1b7b6801, 0x96db889e, 0x56fdd3dd, 0xe8cf839a, 0xa849a612, 0x9bf5ade9, 0x7c58fc3f, 0x11cb5e1f, 0x7c328313, + 0x5e98a3dc, 0x5a76d7f0, 0x9bab58c6, 0xb123a19c, 0xd0c0353b, 0x7e08bb15, 0xe608136f, 0x96adc690, 0x2c0b96fe, + 0x6a785524, 0xdaa47cea, 0x05c7b888, 0x8acb0ba4, 0xfbe73f71, 0xab9375b4, 0x57fd1b6f, 0x16ac52aa, 0x50e0cf5a, + 0xebb26c22, 0x7a56de04, 0xc8be657b, 0x4547090b, 0xf698604a, 0x16d34117, 0x8686b131, 0xd8a999af, 0xd1ba3954, + 0xa32fab85, 0xd3482350, 0x5d7b7602, 0xb7c0b70d, 0x14eb2db9, 0x6a320449, 0xf1d0f52a, 0x10d07abc, 0x7e5d6c7f, + 0xb45fc29a, 0x37691d60, 0xc8ea7b56, 0xeafd4213, 0x0cb54442, 0xbfca1906, 0xecc1d593, 0x01467c88, 0xd3744d9c, + 0x8a0f5c4b, 0x531f6d66, 0xc06960ee, 0x1af4f868, 0x819e8ffc, 0x487a72ce, 0xe01fac73, 0xe65a69cd, 0x9a073f63, + 0x6123ff50, 0x0f51a752, 0x15fe36d6, 0x9cc7e32b, 0xf20b7c5e, 0xffc868df, 0x2aab8742, 0xe20499d8, 0x38eee2b0, + 0x97d64b9b, 0xa45fa913, 0xbbb5f89a, 0xd18cf1ca, 0xb42525b2, 0x4b92f52b, 0xb8c73a4c, 0x57d280ca, 0xb4e35745, + 0xafed3d03, 0x6123c47f, 0x6e778d50, 0xd71d84c3, 0x3d6894eb, 0x6a3a705d, 0xfeb7f503, 0x284b200a, 0x09ab290b, + 0x288933bb, 0xa64387f9, 0xf81e3313, 0xb613aa3e, 0x88948eba, 0x309c4a04, 0x92ef42b1, 0x794adf00, 0x2cb1a494, + 0x5e73a29b, 0x80c9c647, 0xb1232261, 0xd2152911, 0x2ff73ecd, 0x0bb97b88, 0x5f09334b, 0x6d10df40, 0x338b6023, + 0x3e876b33, 0xb0ce681a, 0x72329a63, 0x76398fdb, 0x7bec4219, 0x57508e81, 0x01512c64, 0x707396c8, 0xbca21b25, + 0x117cf77e, 0x3d068340, 0x5b0cf013, 0xdb9889ec, 0xf550fe53, 0xf1d6c75d, 0x862fc211, 0x16f936a4, 0xbf14bb2a, + 0xf440e182, 0x732db748, 0xb75e4d47, 0xbe3aa2ef, 0xff8965f1, 0x45d38d03, 0x558631eb, 0x367d59ac, 0x32517947, + 0x729449e2, 0xe787c7d8, 0x5496dc9a, 0xd7e72e68, 0x0016a3b7, 0x9e309a3a, 0x4191727b, 0x8a7760eb, 0xe816b1d4, + 0x4da6abe2, 0xc99ed702, 0x29e7e002, 0xd271507d, 0x7c6dd0c0, 0x74bfc11c, 0xd79b7791, 0xa538ffe1, 0x70667630, + 0xa93de7d2, 0x8fcd9012, 0x5972cdee, 0x4c87de08, 0xfdae66b4, 0xa7bbdfea, 0xe60d00ed, 0x559aa023, 0xd1de9e12, + 0x4a321df2, 0xcb760aee, 0xa107993c, 0x0e847341, 0xa9db3825, 0x866aede8, 0x4cc568c8, 0x846741ea, 0x9a8bc323, + 0x0b9fd949, 0x12434348, 0x648c678c, 0xfacade50, 0xf7ae0645, 0x43da8a99, 0x55bd6088, 0x1c81cfea, 0x559bc217, + 0x81a512e8, 0x8e793ac9, 0xe24f6f8a, 0x528a4f78, 0x4c524af8, 0xad927ef7, 0xf358e62b, 0x622adb8f, 0x87645f98, + 0x257b0100, 0x5c99f4b5, 0x5ac8b9a4, 0xf8f2079a, 0x6ae60944, 0xad57345d, 0xb9ca5bb4, 0xfd58a986, 0xcd19ad17, + 0x4cb486a7, 0x1a3d769c, 0x33dbf35f, 0x2e3db0c5, 0xefbb3e5e, 0x777b8914, 0xaccbbf6d, 0xe94f1eff, 0xb56825d8, + 0xaf56daf3, 0x28874492, 0x9437ecec, 0x6fe10d59, 0xdd2c3834, 0x4d419c7d, 0x8d4b35ba, 0x9878825b, 0x62d38aec, + 0x2306c988, 0x3b5c9f70, 0xbfdccbef, 0xc4f960d9, 0x2f52afca, 0x33242018, 0x4dd1e6cf, 0x4ed7c034, 0xa5842903, + 0x6b5a557b, 0x77abf034, 0x4e687a90, 0x72552c89, 0xc911f6ae, 0xd594a1ed, 0xd04e2554, 0x0956ec5e, 0x8677075d, + 0x78adf37a, 0x56571cd9, 0x84e11448, 0xee0c6841, 0x58014336, 0xafe1fcba, 0xce94e119, 0x83840e6e, 0x205251bc, + 0x8d71e597, 0x7e1217d5, 0xb9416ac3, 0xfbc228c8, 0x400843ad, 0x8cf47105, 0x8891f93e, 0xa5a28ebe, 0x26fd8d90, + 0xa7c480c9, 0x25355926, 0x0ad433ae, 0x9aa3082c, 0xd312e3a5, 0xb2a3dc22, 0xae219334, 0xe7848eea, 0xa3fa425b, + 0xfce2ef10, 0xfb28610a, 0x8e82024d, 0xe4d73817, 0x2f18b144, 0x7a316615, 0xa35f361c, 0x9cd3b797, 0x8cb5f02c, + 0x9fec546f, 0x11c239b0, 0xd6a06804, 0xc0bc6a1b, 0xd806280b, 0xeca56318, 0x3bc4f5a7, 0x0b277c98, 0xfa66d28e, + 0x9785041e, 0xeede840d, 0xc7e3e654, 0x65006637, 0x277869e5, 0xa123f401, 0x4d27d6f7, 0xea38dfb7, 0x380befe9, + 0xb26c9c5b, 0x467fd7f7, 0xf91dca9c, 0xd4dc0b3b, 0xc6b21c87, 0x77910c9e, 0x30576592, 0xa992ba0b, 0x039d5d49, + 0x7e485dbb, 0x3b8037e7, 0x8d374d9f, 0xc3ac6935, 0xe2f393ee, 0x993f63e9, 0x43dc2de8, 0x331d6549, 0x676d8024, + 0x68f50ca2, 0x58a980b6, 0xb28c988a, 0xdaf36b8d, 0xf665ddc0, 0x59f2e496, 0x034b1998, 0x24fd19c9, 0xfe993b68, + 0x906358ed, 0x1b839442, 0xa5b0fb22, 0x79b40989, 0x184bb525, 0xb46c39c5, 0x0467ca70, 0x6636ce52, 0xbe8c2cbf, + 0x7ed95dae, 0x46f0fccc, 0x9bace6d3, 0x2b847450, 0x772e7aea, 0x56e00743, 0x7007b4b0, 0xc6a61597, 0x34b7cd7a, + 0x0ce3e8c9, 0x63c24683, 0x130807ed, 0xf2060356, 0xad9928ba, 0x56be37e0, 0x0fedc50e, 0xda7c4f36, 0xae7587b2, + 0x88a4702c, 0x62c81b03, 0x7102b56f, 0xe40a9f54, 0x3af632ca, 0xb983e1c2, 0x08d1d13b, 0x0437683f, 0xba7fc269, + 0x8e9652db, 0x7ae7d566, 0xfd6406d6, 0xad5b247a, 0x435d41e7, 0x50d763be, 0xb8b739ce, 0x4f7542a0, 0xeca05703, + 0x485651d2, 0xaf65aae7, 0x0a4a0057, 0x5b8f710a, 0xf5fc40b9, 0x976c13aa, 0x1a7344e4, 0x541f8e42, 0x030edbe1, + 0xcf6f7ecf, 0x8470b417, 0x08874926, 0xdc088cff, 0x32c98085, 0x0b455f33, 0xbfc28996, 0x1a6ef37c, 0xf5a54378, + 0x74269c15, 0x9261458e, 0xfa56cb6e, 0xbab2b3e1, 0xded109a5, 0x0989a214, 0xa43de87a, 0x66ef383a, 0x7ae5ba21, + 0x53fd245b, 0x5c3e7de9, 0x80682406, 0xd66edf76, 0xd949c175, 0x7d9e35d6, 0xc9adb00c, 0xfd78a1bc, 0x308d1e6b, + 0x667c3f51, 0xe56038b1, 0x0943bbd6, 0xc0f07438, 0x5d7ce0e9, 0x385fb1a0, 0x368b2ff7, 0x33157bab, 0x0e54c9df, + 0x59a1095c, 0x5906f1d0, 0x9f57fcdd, 0x75a5d221, 0xc67496dc, 0x2a5ad4e0, 0xf9085cad, 0x9ad46302, 0xdc81407d, + 0xb5193ef0, 0x01351f10, 0x6b3a4d8e, 0xa92bc312, 0x9a3d761b, 0x84774919, 0x2a72ad0f, 0x5127bcba, 0xc6f1b160, + 0xb3e26bdc, 0x19b024fc, 0xb83d1b59, 0xc7c75e61, 0xdcc6d4dc, 0x31464c13, 0x09a8a9a7, 0xad9e5e27, 0x7033b4a4, + 0xda20b3df, 0x6db8cb5c, 0xb85bf09b, 0x27168a23, 0x8300878f, 0xa421cfb4, 0x312ab91c, 0x7657cb83, 0x18cb2f7a, + 0xcec10a90, 0xbb79ecad, 0x3ad6a8f5, 0x25f0ad69, 0x329d12e4, 0x2658390b, 0x700f7fa7, 0xaebfddba, 0x4325f559, + 0x8aa6bf52, 0xcbbbdeef, 0x0b85f397, 0x6541f096, 0xc1585dd5, 0x52da536e, 0xca32a4e8, 0xae74f1a4, 0x37d67fd9, + 0x6d9968de, 0x31a04a60, 0x45c4f5fd, 0x40b5316b, 0x48b921fc, 0x5b54d902, 0x86307de3, 0xf1f04ccc, 0x954ea146, + 0x7d29ea42, 0x97384b8f, 0x6fe10bd6, 0xe6c69ae4, 0x55723dde, 0x4cabc2a3, 0x9d46ef9c, 0x8570e587, 0xc7fbc98e, + 0x6919206c, 0x41893495, 0x631f708d, 0x851640d9, 0x76c65153, 0x43d317bb, 0x1c87154f, 0x27f0927d, 0x1a9be087, + 0x1e595025, 0xe9214222, 0x71360a48, 0xef00086b, 0x1685770d, 0x8f02724b, 0x4f9b6bfc, 0x0cdc439c, 0xb4a64fca, + 0xa66b730d, 0x3e517024, 0x8c9422c9, 0x8f2226d2, 0x99a9508f, 0xc11dedd1, 0x04bba8ec, 0x22384c43, 0x0a086c84, + 0x4c25ca03, 0x29d79ec7, 0x393a25b3, 0x8bccd08f, 0x4cdbd46e, 0x22b8b444, 0xea746d25, 0xc65b5180, 0x2f689141, + 0xc0752611, 0x8434b71c, 0xd3ca9580, 0xbdcf73f3, 0x522da0a4, 0x87b6cf54, 0xf62c7852, 0x36babb7e, 0xaa088ac8, + 0x33588644, 0xc4bf118d, 0x75e5cbde, 0x96145c06, 0x416d504e, 0xc8524a45, 0x5f890ddc, 0xb971612c, 0xe1034e88, + 0xff1d43a6, 0x8607556b, 0xcbdc65a5, 0x0edf6dec, 0x1122813e, 0xc59bd1d3, 0x531edd10, 0x7b20e64a, 0xb57db090, + 0x74026aa8, 0xfa8c87ec, 0x81a3f98a, 0x5f3d6091, 0x265df278, 0x928cdba8, 0x71cfea86, 0x1209ffd7, 0xa9502d4f, + 0xcceff534, 0x3eadc396, 0x0fa83866, 0x3bd78a40, 0xbd58158f, 0xc538dd5f, 0xbfa6f606, 0x6e270310, 0x923cdec9, + 0xa6b8de03, 0x7f5f7ffa, 0x174e47cc, 0x8486ee65, 0x2c56e17f, 0x7a43c22b, 0x56445207, 0xe4e3348b, 0x2b27314d, + 0x2d3f3a76, 0x4894701e, 0x7545b4d2, 0xc15ae088, 0x8ba3f667, 0x085fbdf4, 0xbc6dbd21, 0xa40c06a8, 0x7f559bd8, + 0xa30945c1, 0x2ff52c04, 0x4257afe5, 0x585f0874, 0x113d615a, 0x2e0477c3, 0xbf1847ca, 0x3a1e4660, 0x4a321391, + 0x1799cc21, 0x6794839d, 0x6ad510fc, 0xb67821f7, 0x65b156a8, 0xe3e46094, 0x86319184, 0xf5e28a58, 0x808df735, + 0xf7993549, 0x211fd7b6, 0xed6b1bf7, 0xf3ef7da9, 0xd7743713, 0x9c16faed, 0x49fb14cb, 0xbe06fb5e, 0x07826e8d, + 0x4088358a, 0xe8ff3c41, 0xc757450e, 0xa6ce9213, 0x26d30882, 0x47e445a0, 0x5f726fe4, 0x28b454bf, 0x39817d97, + 0xd341686c, 0xb3ce0e0a, 0x374caee0, 0xca1f327f, 0x7a7ffa14, 0x81560d5b, 0x35d7fc79, 0xbfd34643, 0xf6340486, + 0x864eb05d, 0x9fb3b220, 0x27734b56, 0x220dabd9, 0xb5868038, 0x1e8460c9, 0x1c38bf36, 0xd69a8fad, 0x789245c6, + 0x30efbd66, 0xab641213, 0x542887b0, 0x4094a9b5, 0xb4d35f94, 0xe944d746, 0x790c996f, 0xd8741f9a, 0xe6af478f, + 0xd3780426, 0x27dc0a4c, 0x5f3edb2f, 0x40bd85b4, 0x3b6bb92b, 0x7500581b, 0x86fa8f8d, 0x186986c2, 0xe2ed7fce, + 0xc76e5c2c, 0x4d50fd36, 0xee50c220, 0x0dd0422d, 0xac456a5f, 0xca0d9a38, 0xeb2f0479, 0xf0c0802a, 0xbd0fa9f9, + 0xd11c7066, 0xe47d5629, 0x413da362, 0x63a4bbcb, 0x293fdf50, 0x235c07db, 0x4718309f, 0xf195bacb, 0xd57ef695, + 0x9be669fc, 0x2ff8c68d, 0xaac8d8a8, 0xdac2a5a2, 0x152b0a4a, 0x9eafa751, 0xec014a3d, 0xdc7ae7a9, 0xc5ec8894, + 0x5722f507, 0x5feb2474, 0x7132cd92, 0xcd79fa57, 0x55f4ae63, 0x1c4d0f0f, 0x196c702c, 0x891aa637, 0x9e9f2924, + 0xcce0216a, 0xeeb30939, 0x078c5c93, 0xb207ba0a, 0x3e701dfa, 0x8ba9fa8c, 0x2121144d, 0xf686fca8, 0xe3f7cca7, + 0xd0f1f47f, 0xa91bef00, 0x785790a4, 0xe79194c8, 0xfafa89f7, 0xd5d2acc0, 0x5e882755, 0xd048933d, 0x0085c030, + 0xdefe2efe, 0x087642d7, 0xa073bb40, 0xe7d8c631, 0xe085a220, 0xe8f6aa13, 0xc5cbe8a0, 0xc556d10c, 0x525486d7, + 0x6343f836, 0xe5bdf06c, 0x2a6ab51b, 0xd759e4fa, 0x39d5243d, 0x63f2ea07, 0xf482ab8f, 0x473be70e, 0x4d4a1b01, + 0xeab19357, 0x59898d21, 0x6f546fda, 0x58c1b3e6, 0xfe50c71e, 0x23c27c95, 0x1383f5cb, 0x566ba694, 0x28f6f866, + 0x0273b246, 0x5ec03a59, 0xe9a24ef6, 0xb2133187, 0xe36d8c8a, 0xd2e048ae, 0x3f37e610, 0x145c1b5e, 0x532c5326, + 0xecc6d953, 0x97e30831, 0x6ee200a1, 0x5ca328e3, 0xea37ba63, 0x21cf6665, 0x32bc3f7d, 0x964f04af, 0x68d74b6a, + 0x88def012, 0x6c635770, 0x499cfddf, 0x504cfc65, 0x2e94efa4, 0xbc056cd0, 0x856f11f2, 0x2b9b6838, 0x270a18b9, + 0x7b17a797, 0x6eff4e39, 0x9d344c66, 0x78c9d00d, 0xb1d9b5ac, 0x1912219f, 0x6686b638, 0x7fe50dab, 0xc9481bfe, + 0xdce58607, 0x16d74f72, 0xd1991047, 0xb3b5addf, 0xe163e4de, 0xbba06915, 0xcb382098, 0xbe5165ac, 0x8e7252ae, + 0xb9b05191, 0xb7b5afdf, 0x88a2cd72, 0x4a508610, 0xa3d1b946, 0xb84bcf30, 0x3c3054e6, 0xa2a048cf, 0xd9e947be, + 0xb52bb890, 0xe3771232, 0x6380cab5, 0xa3c3344d, 0x5337cab8, 0x5dfcfc2b, 0x81c82683, 0xb9213780, 0x261bfb95, + 0x5b64e286, 0xc358132f, 0x4525aa83, 0xc523d08d, 0xf704d3ba, 0x476c998d, 0xfa2443a2, 0x276ac936, 0x62b167c2, + 0xbc0a6ce5, 0xdcbbaeec, 0x50adf7b1, 0xade33daa, 0xc30a2808, 0xb1e5ef87, 0x5c3fad93, 0x490b34ee, 0x71904a02, + 0x30d846d3, 0x3e08bf8c, 0xdd8433b0, 0xadcbd576, 0xd520f191, 0xe93a71b1, 0xd2f1a7ba, 0xd0777277, 0x5820d8f1, + 0x3925159a, 0xe8268e94, 0x6ffba609, 0xea24672d, 0x252841b7, 0xc5b560fb, 0xa47f5980, 0x2842c153, 0xf019d642, + 0x992e3044, 0x5e6a78ee, 0x04a748b9, 0x8e2f71be, 0x72b547bc, 0xf202dc82, 0x48e3ad0f, 0xf0af85a3, 0x42d6e217, + 0x4d81eb78, 0xe932f820, 0x8ddb3b36, 0x57178cc3, 0xa9b0dcc5, 0x7ede352a, 0x7b7cd12a, 0xa0042aec, 0x0855900a, + 0xeec108f9, 0x60eb5c98, 0xbc3081a5, 0xc3cccba6, 0x900d1e32, 0xe7300eb9, 0xa425c1ee, 0x8989a136, 0x93628f73, + 0x2483fe54, 0x16978bb0, 0x6679d25b, 0xf5c92774, 0xdb861cf1, 0x7cbc7665, 0x778c8fa4, 0x69653ac4, 0x108a7fc2, + 0x7d8de18e, 0xc13f5318, 0x445260c3, 0xf1c69929, 0x9d641eb0, 0x9e8a188f, 0xa54b9034, 0x5c35a629, 0x5e6c65bb, + 0xfd6212cd, 0x0720476f, 0x55989bf7, 0xaefcf2bc, 0x354a26fa, 0x761d1a47, 0xa0c000ad, 0x2f77effe, 0x82ca7ff8, + 0xc48dc494, 0xc49cb825, 0x602de0f6, 0xccc5b66b, 0x1a40817d, 0x2bb094a7, 0x92704a5a, 0xf075a1de, 0x7ef6ac3f, + 0x17612d39, 0x2ecdcc22, 0x54da465b, 0xd6c0f249, 0xdea803b0, 0x5814e9ba, 0xf0e13242, 0x06bf3479, 0x7d247a1c, + 0x976bc0c1, 0x9d2b3462, 0x6543ddfb, 0x8494c811, 0x0b168783, 0x45e363d5, 0x298e098d, 0xf636f575, 0x3e3afaa3, + 0x3adf90d2, 0xc77eb1ec, 0x9f8d950b, 0xc027b633, 0x87a97c23, 0xeea8451e, 0xd72b33d2, 0x0cd33b83, 0x97ffd269, + 0x68941dcf, 0x6353f925, 0x29e940c7, 0x2fe15b1b, 0xfc75cd5d, 0x7d3451c9, 0x97d0b3c9, 0xe8607df0, 0x0b24cf3a, + 0x8b2d6b78, 0x0d0c22c4, 0xe55795b3, 0x50556fd2, 0xb7425c3a, 0x9cf05924, 0x207546df, 0x881eec4c, 0x32ab707e, + 0x81ee5a12, 0x8f1c2d42, 0x75c0c40f, 0x0909e458, 0x2ffd2eb3, 0xf071bfae, 0x0715ea7d, 0x11242575, 0xd4a8ba61, + 0xd4ff1985, 0x7d2598b1, 0xcecfd44e, 0xea11edb8, 0x9ffedc80, 0xb98ffd74, 0xf5495d74, 0xa22062b2, 0x2ad3f235, + 0xf3f8b46d, 0x55b32d58, 0x7a6a0356, 0xba2e4078, 0xef8a6743, 0x6d66c7be, 0xa4d0ece5, 0x979776a9, 0x3e6c9afc, + 0xdd6666be, 0x62daf15d, 0xd5c077e5, 0xdc05cd18, 0x20e4d3ab, 0x9767548e, 0xff1352bb, 0x7a8d9b2b, 0xbb21ab0c, + 0x8828e28a, 0x5d10571b, 0x5cfbf109, 0xbac367dd, 0x5e0954a0, 0x59c680fe, 0xbf01a906, 0x0e34bf5f, 0x4f11ef94, + 0xe28747f4, 0x1d8beb07, 0xece56157, 0x58af0132, 0xd1fd9224, 0xc0a82ffe, 0x4835a538, 0xce7b09d6, 0x0547117f, + 0x3ccff171, 0x8da2c7b5, 0x26d1ae2a, 0xa782e4e4, 0x0c250628, 0xd1a7ffeb, 0xba3d7dbd, 0xf235f8a3, 0x57d82f05, + 0x997c29c3, 0xbaa361e8, 0x8c351a9c, 0x3de50a16, 0x5113bd07, 0x6669ebbb, 0x63660321, 0xb06ed667, 0xc30ec507, + 0xcb7c136f, 0xc4f4a6f5, 0xec6be127, 0xbc95ab32, 0xbc507150, 0x2b644676, 0x6b65090d, 0x8cf68961, 0x728f8b3a, + 0x7b65c5e0, 0xb6f28277, 0x1450f1d2, 0x9e889a99, 0x6d546960, 0x9b64871e, 0x21f9a9c8, 0x37449dd8, 0xedba79f6, + 0x5c2418f9, 0xa0d34d48, 0x1f91249b, 0x658a98e7, 0x7d94bce7, 0x88d67d96, 0x0f615d0b, 0x04381e03, 0xa678712d, + 0x54cbb902, 0x8cc66f92, 0x31a249d8, 0x6b5c4da4, 0x252f04d6, 0x08063c4d, 0x46e88198, 0xe1cc1756, 0x8ce163c1, + 0xc7a9ccbd, 0x4196ef82, 0x3404d434, 0xdc9b74d3, 0x32dd6bb4, 0x0a8f9ac3, 0x2eeca9ca, 0xa071ec31, 0x455b7174, + 0xc37150d3, 0x2827835f, 0xa10d9b93, 0x69048d70, 0xaada270e, 0x604a3686, 0xe1e56a27, 0xdcad2f44, 0x07ccc089, + 0x6ccadea0, 0xc8ea5fd6, 0xbfd0da70, 0xfb7aeabe, 0x34627a68, 0xe0ab513a, 0x2a6738b2, 0x0aedfa6b, 0xbb3cafb0, + 0x6a2a2281, 0x3dc9a1d5, 0xb9928a6f, 0x4baf5db3, 0x0bcec7df, 0xafc9ba5f, 0x51b49b72, 0x36b54d59, 0xb520a628, + 0xee43c3d0, 0x54f278d5, 0xd2692b03, 0xa2f8f7ee, 0x90e3d187, 0x4636bc68, 0x7e7b22c4, 0x12d494b5, 0xaf77d12f, + 0xf1fb418a, 0xfa4117bf, 0x5438629d, 0xce75e5a1, 0x1edda5ba, 0x43f72f6f, 0x9c7b428b, 0xa82b5419, 0x72e1a80e, + 0x858e1668, 0x491edda9, 0x58d0e9e8, 0x4f02e73b, 0x772c9a64, 0x3ae48914, 0x22eb7b71, 0xf59e19a2, 0xcb651b42, + 0x152d4f9c, 0x4c16bf2e, 0xb0a169a7, 0xde0cebda, 0x54ad00ae, 0xd18215b5, 0x02027f90, 0x8e256a82, 0xd79a6fb3, + 0x122f3b46, 0xe878b69e, 0x6de26f2c, 0xb158ae69, 0xc08e355b, 0x81b10b35, 0xef2d79b1, 0x5e5b29a6, 0xe7eb6f10, + 0x6094c1f9, 0x9ab91014, 0x6c13bdc0, 0xbb4e4e6b, 0x761eed0f, 0x63bdd7df, 0x04654e14, 0x8412ee44, 0x7c54a5e4, + 0x056c3fc4, 0x172d1c99, 0x216586eb, 0xef36c05b, 0xac7d5c80, 0x7dece8aa, 0x4c3aaad1, 0x7e8bebed, 0x01d1fe8d, + 0xd32fdf15, 0xc3cd6ecf, 0xe57bf295, 0x62c3b175, 0x776068f3, 0xe98530df, 0x0b04097d, 0x9de4ecee, 0xc7a92373, + 0x20fbeefa, 0x2b269d71, 0x23f7d860, 0x9091d750, 0xe7a1a2cf, 0x9330755a, 0x90e66f97, 0xb64615f4, 0x562fccda, + 0x11d90294, 0xae79f764, 0x97fada0f, 0x74c13d0d, 0xb271f56f, 0x381d0af4, 0xfc0570cb, 0x21d7c037, 0xdfebe73d, + 0xaac60bef, 0x587b423b, 0xc607b8b9, 0x734dd393, 0x7e3de650, 0xf70ec1a1, 0xd6281848, 0x729b6d44, 0xfd6926e4, + 0x7cba7198, 0x338b4479, 0xf4fb9bdf, 0x78e9781f, 0x318d304f, 0x16dd2f2c, 0x2d978467, 0xf406541e, 0x4f6184dd, + 0x19b4d4e6, 0x86b08dfe, 0x59d625f2, 0xf5bc557b, 0xe5ed156c, 0x3126ddc7, 0x77a5460a, 0xfe805d1f, 0x43021cd2, + 0x6db55cb5, 0xdfa40dc5, 0xf63c836d, 0xa9229a80, 0x1ff0a629, 0x5bdde754, 0x97e0c942, 0x7725210b, 0xec8bab77, + 0x496f2876, 0xa8bf42ec, 0xca8d6ad4, 0x2057db4a, 0x7043f925, 0x00b0a1e1, 0x7263e8e5, 0x0b95dfc7, 0xe885012a, + 0xd4477422, 0x2b15bbb5, 0xd192a2dc, 0xb000d4f6, 0x4beee5f8, 0xe71896a1, 0xfd49f4ee, 0x317f39d1, 0x03b34074, + 0xc4a23cbe, 0xd70e4048, 0x2e3fd30c, 0x6dc57470, 0xc79655b0, 0x3a522665, 0x59f59446, 0x2017909d, 0xda51b750, + 0x139fa0a0, 0x66cae63a, 0xa9af23a3, 0x572b6f95, 0xafb42e2b, 0x19622a68, 0x72117975, 0x37e4bd73, 0x185b47f5, + 0x23d736b5, 0xcdb482b5, 0xbf44dafa, 0xa1a06d4a, 0x4ea1019e, 0x2292354d, 0x905855bd, 0x82cdb9ab, 0xb6614d2f, + 0x0748935f, 0x83cb3212, 0x1db071bb, 0x590c7246, 0x91f5ae46, 0xb6f76f97, 0x621ab2f3, 0x64049032, 0x25f2dd01, + 0x35a53333, 0xcdf77a5e, 0xab4bf592, 0x286a4131, 0x08f0cdea, 0x5610fc7a, 0xc367bbb6, 0x3d7573d0, 0x2c4260a3, + 0xd1b5bfcf, 0xf8143886, 0x2750aaa0, 0xb4dfecd0, 0x28c7fe06, 0x1370655a, 0x9becc3cf, 0xbcbff525, 0x053ba4f3, + 0x27e3e7a7, 0xc97b6df0, 0xeb188f74, 0xdfa8a13b, 0x9cd8a36b, 0xb0ef6c32, 0x90345a5a, 0x363797e3, 0xd7d01e2b, + 0x1ce08fdd, 0xa243aa4d, 0x7f5c1e3f, 0x5c47e524, 0xe796d4b4, 0x29594319, 0x31c6959a, 0x81f42c03, 0xf6869acc, + 0x0cffaef3, 0x7f7ccbc8, 0x2dbab210, 0x9dbf6c09, 0x37a31103, 0xf28d96a2, 0x50f5e146, 0x107e4c45, 0x2501a619, + 0x821ed402, 0xbad0e4e1, 0x6275a6cb, 0x96746901, 0xe8115fd9, 0xaa222643, 0xda400e0c, 0x0a5cc00e, 0x9e606f33, + 0x14fb32e7, 0xa4b2793c, 0x779146a1, 0xfd6a7c36, 0x6f1b9c30, 0xd459768f, 0x09d0baf0, 0x3e65d0b8, 0x0135766a, + 0x78656c74, 0x0528ac05, 0x87198057, 0x03282ea6, 0x8b2641c0, 0xff02789f, 0x2115f9b8, 0xb1fcfe1a, 0x9bb180b3, + 0x65cbec6b, 0xe24d975a, 0xa6c64ce1, 0x4c52fbca, 0xf4c96fa8, 0xac214b49, 0x5ac876ed, 0xb3e2e087, 0x0af6ad09, + 0xf4bcc1ee, 0x34cfbd0b, 0x535eba61, 0x38139a6f, 0xb19f848e, 0xd69dd8b5, 0xb04610ff, 0xc7dacfe6, 0x55c38d5c, + 0xd0a4a708, 0x3d5d08f9, 0xee4b89ba, 0x83589775, 0x96c91a0b, 0xd4139002, 0x85143690, 0x60a69af7, 0xcdf04600, + 0xbcfd37ea, 0x7c73522e, 0x715b8cb6, 0xf6806c8a, 0x15368f00, 0xd3dc1870, 0xa381fef7, 0x494379b3, 0x76113207, + 0xecccb1a5, 0x5c85d554, 0xfdad7979, 0x49d518b1, 0x08978b7c, 0xd6468050, 0xdfab2165, 0x499846cc, 0xe870390f, + 0x76d40f48, 0xa6d5d0f2, 0x983b8c84, 0x8a3d0480, 0x3166cd39, 0x86aaca24, 0xf97b361a, 0x1c30e01e, 0xdc6ccb10, + 0xd753bb1c, 0xe890d47b, 0x22b485da, 0x6d3142ac, 0x62a80a6d, 0x9a912507, 0xffd14ba3, 0x95badbd7, 0x8f012e8b, + 0xf4fb5b9b, 0xe24fd908, 0x04223e20, 0xc2cb2112, 0xf2acc853, 0x75204f14, 0xa5883eb0, 0x563f6407, 0xec1d8718, + 0x42516dbc, 0xe89ab70f, 0xbfb37ebb, 0x55a07677, 0x4756d997, 0x3ba58c25, 0x0934b8f7, 0x5ba13b04, 0xe9f61de0, + 0x4508df99, 0xe51e39c5, 0x8451d939, 0x3373d61e, 0xda63aa7f, 0x69a478d1, 0x0532a777, 0x5cfb59cf, 0x7d904f21, + 0xb230efcf, 0xc863fc1f, 0x04580a7e, 0x62134e45, 0x13509a7e, 0x9f54a111, 0x11c81a72, 0x7310d892, 0x468fd0c6, + 0x5b47ad7c, 0x51e412b3, 0xfd8c4a61, 0x2abcb7ad, 0x20ceb0a4, 0x336d69ad, 0x813e4c6e, 0x286d7698, 0xa3bd6ce7, + 0xf86117e5, 0x55a106c7, 0xf77b07a0, 0x3c1a762b, 0xc171905e, 0x70b0af39, 0x3b29248a, 0x994fd08a, 0x1f84737e, + 0xe96c5b2c, 0x00a69ee5, 0xfe0fad59, 0xad987108, 0x17002fc2, 0xe193e2b6, 0x2388dc04, 0x849aeab4, 0x2080b3b6, + 0x94446908, 0x97925d1a, 0x3523be7f, 0x38d37ed5, 0x24ca5422, 0x15847a84, 0x090ffb09, 0x3baf86b1, 0x291b0f84, + 0xd9cd623a, 0xda9fa9cd, 0xf8fb8c12, 0xda0b7568, 0x9d322f2b, 0x2a16e9be, 0x38791079, 0x87678300, 0x596651c4, + 0x7565e31b, 0x6a4d27f8, 0xf5034bc7, 0x13ca7f0b, 0x6d49ad5c, 0x1cac905a, 0xf3d69c55, 0x00cd005b, 0xd1b9a890, + 0x9bcb3a80, 0x6a9ae9e0, 0x5590c582, 0xc3bdb3a3, 0xcace4289, 0x1ef3328c, 0xf8970278, 0x84d89990, 0x8b76022d, + 0xe95b0975, 0x33c3c102, 0xedd1be0b, 0x09f6049d, 0x7347cc59, 0xb71eb723, 0x41f3d945, 0x6e690be7, 0xdcd1add1, + 0xacb192ff, 0xb1d6fdcb, 0x865f6c19, 0x142e95d0, 0x9da1934e, 0x8146085d, 0x6c97074d, 0xf3acbe65, 0x2c3d0e29, + 0x982532d8, 0x6e5841e5, 0x69ec12db, 0x5c0a4d59, 0xec953c6a, 0xcca8852f, 0xd82a7566, 0x7838a17d, 0xe0529346, + 0x220d0982, 0x3c1841fb, 0x14e5b1c7, 0xac99dde5, 0xa7d3ede7, 0x90811900, 0x64cb6b32, 0x006241e1, 0x52307d92, + 0xe081acda, 0x216d3d6e, 0x67a71dbe, 0x5163032c, 0xa49deede, 0x3a3cf875, 0x01a4fa9a, 0xafd3c474, 0xb09d585f, + 0x5afc8c06, 0xe796ba17, 0xc54636db, 0xd6d6809b, 0x5cdf51df, 0xde9f0123, 0x2f56593d, 0xa98f312a, 0x7b0b313e, + 0x13bc3a75, 0x672ebf2f, 0xeaaac511, 0x37470335, 0xf3dad16b, 0x96046348, 0x9b656aa9, 0x5ccc008b, 0xb84f0269, + 0x28ded135, 0xc81a8c47, 0x97dad21c, 0x349b7874, 0x27a99f09, 0x6cf57fd4, 0x42688041, 0x27ec11ea, 0xa21e4bc0, + 0x0e2d16e1, 0x472d284b, 0x3d19d84d, 0xe35fe514, 0xbb10cfe4, 0x911d990b, 0xf2d847e9, 0x3c3ffbef, 0xd70dd4b1, + 0xf5ac9fe2, 0xe8edbdc6, 0xf40f17a7, 0x5ec9604c, 0xdaa9ef73, 0x474870a2, 0xb730bf57, 0x7cb75aaf, 0x533321d7, + 0xdced918b, 0xf3223dbc, 0xb980e94f, 0xbe620306, 0xcd9905b1, 0xea86e95a, 0x8b7b2562, 0x03e31428, 0x486b1e5f, + 0xa0dcf8d5, 0xd3cc2713, 0xb401b20a, 0x6992738a, 0x3f8bfa9a, 0x977c10e9, 0xfafe2f74, 0x40aa39ce, 0xac733ba2, + 0x62ac7eb6, 0xd1790900, 0xcc4aa2e1, 0x369f326a, 0x9f15e6ad, 0x2c06ad9e, 0xd7dbf459, 0x9768b649, 0x31cfdb41, + 0x9ae0b9ec, 0x96645b21, 0x7f9169ec, 0x0a0d9aad, 0x4e8fbaeb, 0x95c3f5d6, 0x8a01bac9, 0xa5236bb4, 0xd93054c3, + 0xea64ab73, 0x44b218ed, 0x77428edb, 0xe9e3dc89, 0xb202f961, 0xc4970d90, 0x8e45498d, 0x36e1d6b1, 0xae13e46c, + 0x4c737bd9, 0x7839db9e, 0x3ed5493b, 0x449ab61b, 0xfa6282a7, 0xd8cec4fb, 0x0a4e9240, 0xefdaa9cf, 0x5a8cd914, + 0xa3b392cb, 0x8618e1eb, 0x51a11edf, 0xc15c8e7f, 0x43aa6561, 0x5ee3fd64, 0x2004c0fd, 0xd5c31dec, 0xed4a2c98, + 0xa4304304, 0xada5ec1a, 0x39341cac, 0x862bd495, 0x839179e6, 0x88dccaec, 0xadd8f936, 0x14c39828, 0x61a14d48, + 0x7e62048b, 0x0b31cde2, 0x2b033046, 0xe0713bc8, 0x9145dec0, 0xc1018075, 0xcf9944ae, 0xd724d256, 0x060e2bd5, + 0x0fd10d1c, 0x4b5e256f, 0x4f1baa09, 0x1fd538ba, 0xc3d6fe00, 0x44b3de63, 0x33236cd2, 0x9abfbdd0, 0x485644df, + 0x127af43b, 0xdf379fc0, 0xb4b7c32c, 0x33b32599, 0x83d2dae9, 0x82008178, 0xbde3d425, 0xf2f16645, 0xf36070f4, + 0x816292db, 0xc849663b, 0x3bb14a65, 0xe77b105e, 0xb52e4903, 0xb995ad25, 0x25faf038, 0x889c59c3, 0x15708484, + 0xd3230b1d, 0x77329fa3, 0x06398ac2, 0xfcad0ed9, 0xd2234205, 0x59e73538, 0x3709b2e6, 0xcf4a1200, 0x0ebef0c4, + 0x92ce5f3d, 0x6541f288, 0x884b36dc, 0x72274788, 0x7ff2876b, 0x95257c93, 0x766efd06, 0xf018bc15, 0x9c6e6009, + 0xd8268969, 0x5454fccf, 0xd4024dfa, 0x40c5df7b, 0x9680e48f, 0x57617fc0, 0x654414ef, 0xf3285ba9, 0xf3186428, + 0xe346af79, 0x60cb2c1e, 0x79f2c899, 0x82bf47ad, 0xc5b9d2be, 0xe9d82cb0, 0x6f66261a, 0x845934d9, 0x3bb70363, + 0xc34be3cc, 0x422c752b, 0x8cc2ccc7, 0x1ced4d9d, 0x360beb4e, 0xda1ce047, 0x5a10efc5, 0xc283afd8, 0xba5337ed, + 0xeb5098a3, 0x85d3726a, 0x81a5ac11, 0x96d36453, 0x57cf9598, 0xf5a68ff1, 0xb7e253a4, 0x64e8aa48, 0xf02b50e6, + 0x199dfaea, 0x8e0ecc3f, 0x22a05b1e, 0x95f98be3, 0xe7eb19ba, 0x3d76d3a5, 0xe7a0af5b, 0x9276327c, 0x53a869c3, + 0xe60f4a9f, 0x96b0f9f8, 0xd74b7ee1, 0x25469c8b, 0x72fe44b0, 0x4f41f79d, 0x94802b3a, 0x349aa456, 0xc9e928ca, + 0x19563dd0, 0xd5f99f3f, 0xcec1cebe, 0x092abc26, 0x0476dc35, 0xaa1a88d3, 0x96523219, 0x32296d5f, 0xff514371, + 0x2979a21e, 0x794b2fe6, 0x3362e36d, 0x0240398b, 0x976bc541, 0x6fe9e5a1, 0x436261a7, 0xd9971220, 0x8680e63c, + 0x05375b46, 0x2b3cb153, 0xd3abc561, 0x070621e5, 0x8670e554, 0x79486705, 0x104b1972, 0xf79b0f29, 0x5c5ea64a, + 0x7ec6d8e5, 0x2f7cc17d, 0x21d1d80d, 0xeacf5356, 0x2b688fb2, 0x23119852, 0x839ac90b, 0x0056ec27, 0x7b682ee9, + 0x969f8929, 0x1386fc99, 0x40db3632, 0xdf7a9c3a, 0x03757369, 0xa469b2e3, 0x62b650ad, 0x12de704c, 0x16854761, + 0x9317bdda, 0x21a99c60, 0x0f37848e, 0x821c68e1, 0xe1e7ead0, 0xd019b834, 0x8def4c58, 0x09a0ffd6, 0x9b97ef55, + 0x8cb88bfe, 0x4a85df31, 0xdbcedcea, 0x0c03e46a, 0x320b8303, 0xf1851a58, 0xd2c8aa4c, 0x9d9e2f1d, 0x0ab516b7, + 0x8e3c4eb7, 0x38fdc767, 0x43f914f4, 0x9b59ee16, 0x2bced08a, 0x6565a9ce, 0xf61eb368, 0x1143b84b, 0x03598613, + 0xb3ebf912, 0xdc06788c, 0x0114da9d, 0x4fac7ac5, 0x0c25131d, 0x6e130e9c, 0x56a97706, 0x931c7536, 0x630d7be1, + 0xccfc3871, 0x8ca635f1, 0x2e7f94a5, 0x15b3edbf, 0x09b07154, 0xaf6c21af, 0x707b499b, 0x1ee17819, 0x8fee49ec, + 0xf3f8ec08, 0x5ba0345e, 0x8d03444a, 0xd2286771, 0x3281e16a, 0xb3416a82, 0x70384430, 0x28af9d36, 0x12c0fb9e, + 0x1b3e8e45, 0x60cef329, 0x9e6f36f3, 0xa3bf1e55, 0xd73d507d, 0x0eb6434e, 0x84fd8f7b, 0xfbaf574f, 0xf77aa0c3, + 0x02d79208, 0x96d583fb, 0xf5f2d10c, 0xf9f5d17b, 0x15874287, 0x4deb7701, 0x28fb7e9d, 0xe371e0e7, 0x289d5435, + 0x9d3a129d, 0x66a0f7dd, 0xd611bd42, 0x9bc8011b, 0x7545cc94, 0x9d63e638, 0xbe3892df, 0x7c8cdc12, 0x6259a081, + 0x383be5a2, 0x7f3fd851, 0x92307486, 0xc24b4b76, 0x14d07a07, 0x08dfb665, 0xc8c5e313, 0xb871a496, 0x0a7fd1b8, + 0x0090a17f, 0x4ed529e7, 0xd96de9f7, 0x90932418, 0x02ffa933, 0xd843d063, 0x546aa5e6, 0x0b6ba734, 0x416b7573, + 0x2373ec5c, 0xb2d01b6e, 0xa5996b8c, 0x0b0f8a56, 0xb8ef46ee, 0x45216dba, 0xe1c9caf8, 0x323bacaf, 0x5752037b, + 0x52b22b4a, 0x848d2b50, 0xefa49c9c, 0xc12a2c6f, 0x563b3fdf, 0xe49a1f16, 0xfc26add4, 0x8ac4431b, 0x1cb5914e, + 0x55fd388f, 0xff3837ea, 0x0d202aad, 0x5f4547c1, 0xbe08c6df, 0xe4c06b64, 0x536f46dc, 0x23c4cabd, 0x63742ed0, + 0x7aac059f, 0x619f5749, 0xcff399d7, 0xed0a68d2, 0xc33e8b70, 0x45b5fe96, 0x5ae2a325, 0xe1a93b0a, 0xdb0975c8, + 0xae7a932c, 0x67d8124c, 0xdfad404b, 0x61157bd6, 0x210a1f7f, 0x72fb91b0, 0x1721dc57, 0x608e44c5, 0x1ac73007, + 0xfab63e6b, 0x08c3984a, 0xfc6231f6, 0x8aca4930, 0xa89d263a, 0xda710ee3, 0xefb9b525, 0xd19315cb, 0xe381775c, + 0x65fe64b0, 0x0911c04e, 0x14bf4dab, 0xd62c31d3, 0x92721122, 0x58f57348, 0xfaf4a40e, 0xab94426e, 0x5bfbe06e, + 0xdb2824a9, 0x3b9eddf0, 0x5bf0e540, 0x89274b72, 0x379ff578, 0x5971987d, 0x6c9e6102, 0x00afd94b, 0x113fbd1b, + 0x25e08981, 0x73f1c63a, 0xedb5d3d6, 0x60239e24, 0xec78e844, 0x32f91b6f, 0xcfa5f4ee, 0x7dc3ab53, 0xba6ec6e3, + 0xdc2189eb, 0xbb2b85b7, 0x78e06f3b, 0xa0b14d50, 0xed192ec1, 0x8281858c, 0xb49ee82e, 0xb9893295, 0x897da340, + 0xaaedf94c, 0xbd450c6b, 0x07002168, 0x301cf6f6, 0x5a5e537e, 0x7fdcd252, 0x5ce74ab3, 0x1460793f, 0xb64e56ea, + 0x89381be5, 0x6cd02be1, 0x599812a8, 0x1120cf23, 0x16a16b46, 0x14d2552c, 0x34de5c7c, 0x80eed808, 0xc9ed4b43, + 0x8fe62f73, 0xd4211ae3, 0x61c7c102, 0x8ed5f78c, 0x048f1d1e, 0x08cc774e, 0x8a1a7c8e, 0xa028052b, 0xd05dbf60, + 0x4e4af477, 0x53fd2930, 0x45e71f3e, 0xab16b4f8, 0x1dd40992, 0x945e807a, 0x1150cbdc, 0x673469d6, 0xf48a544e, + 0xb21964c9, 0x53dc1de2, 0x122e788c, 0x0e78780c, 0xf1527f6f, 0xed976ae5, 0x5e4e1367, 0x35e31b7e, 0xf6657f9a, + 0x724025bc, 0x7803e395, 0x57d8e5ea, 0x187d7de4, 0x2d06956f, 0x24604dad, 0x4c1a2262, 0xa6e14af5, 0x470f40ba, + 0xa85cee5b, 0x015e6c7a, 0xef808af8, 0x8a866eff, 0xb90dc2ee, 0xb6b630ed, 0x7c06ff2d, 0xfedab94e, 0x1e00b80d, + 0xa062e4e3, 0xe7b56a21, 0xa4fb26a9, 0xea0788a4, 0x20e4e52e, 0x213e89ba, 0xa599c3a5, 0x04c12c8b, 0xed3c9297, + 0xa2e08641, 0x5ac15cfc, 0x744d9e4f, 0x3f58990a, 0x3f0529bb, 0xc51e6949, 0x8df79745, 0xdef60ce1, 0xae053e24, + 0x5db859da, 0xd1e2379b, 0xa2ffbe1b, 0xf740e8a3, 0x88892aa3, 0x7f79e8eb, 0x6e48bb05, 0x8d358046, 0xb36e6584, + 0xde4eea64, 0x2f6b7931, 0xd17edf4f, 0x946d759d, 0x79836c56, 0xe7afd9c4, 0x1c89f5e9, 0x8d35fc5e, 0x22cea1e4, + 0xad16c5b3, 0x234980c5, 0x95195e1f, 0x33efa3eb, 0x0d35025d, 0xc478ef0d, 0x117c3f1c, 0xed621609, 0x4ad0f7d8, + 0xeedbf848, 0xdb44789a, 0x2a00e6a0, 0x90b9e36b, 0xba3f6d7a, 0x41c043e2, 0x47e72d98, 0x3a00e083, 0x3fee438f, + 0x184012da, 0xc561e10e, 0x8e15062b, 0x6ba4e007, 0xa59869ff, 0x036a6181, 0x5dfe0ce2, 0x985597ce, 0xbdf58b34, + 0xfc8163f8, 0x3dd53e73, 0xf76a5fef, 0xfb815cf7, 0x7297fad4, 0x872ad2df, 0xddbbe86a, 0x31064673, 0x8ca88212, + 0x1133e04a, 0xb682fe07, 0x962c8233, 0x363f9fc9, 0x8916e908, 0x7729a7e5, 0x4210d64c, 0x149e4e86, 0x19ae5ee0, + 0x14d8356c, 0x0b766994, 0xa5a791f1, 0x7d7e685a, 0x6d455bd2, 0xa0ea8ce6, 0x9b6dc3d6, 0x3ca486ed, 0x559d6915, + 0xca5c9107, 0x23d2f136, 0xacbb0550, 0x0dab3fb5, 0xb1fa5527, 0xaa00e7b5, 0xbed51ea3, 0xe1659afa, 0x63f974c0, + 0xdeed830a, 0xc083257e, 0x6abc3fb3, 0x5053e876, 0x035ef0db, 0x1e882fb7, 0x5492202c, 0x16399e0b, 0x24f7212e, + 0x2f3af54c, 0x01063e1c, 0xcddef5ba, 0xcbe4d643, 0x9976df94, 0x670bbe14, 0xa6d88c26, 0x8204f5b9, 0x2a0608a0, + 0x86cf6c22, 0xa93c6173, 0x84df91ca, 0x325de5e2, 0x1485f336, 0x41380abc, 0xa923a7fe, 0xc63ff0fd, 0x7b7d4f54, + 0xdcc11033, 0x6da929fe, 0xea4197e3, 0xc8e33442, 0x74f10096, 0xf7554f97, 0xeb947ead, 0xf5eb0b79, 0x55e01306, + 0xf38b9add, 0x795b63ee, 0xf220d5a6, 0xa823469d, 0x54fe951a, 0xc3808821, 0x90cde384, 0xc9920a6e, 0xd63afb45, + 0xa6bb4c56, 0x23cc5f58, 0x6c5295e8, 0xd47f0a50, 0xa67b684d, 0x8ad4b6f8, 0xd319a332, 0xca93af11, 0xd2f42ede, + 0x0c925c6c, 0xd67b7f61, 0xeede92f7, 0xdcdbc313, 0x8a7a7a55, 0xdca835fc, 0x307b98ad, 0xbb1afa0a, 0x7cc366e2, + 0x425c2e50, 0x0a42ae17, 0x5cf76320, 0x4f15cf88, 0x126dce49, 0x5a2a3325, 0x293a49b5, 0x18fae42d, 0x84fa9bac, + 0x1ae29587, 0xd50b7d11, 0xcf0572ac, 0x64e3ea26, 0x8d81ecbb, 0x8249b5e3, 0x4840e25c, 0xb3de6ad7, 0x131869a7, + 0xe0490430, 0x7685d8fe, 0x3cec6488, 0xaa5c61ed, 0x9f471c7b, 0x79ab2b16, 0x252c0f64, 0x6136e0d5, 0xfeb287f9, + 0x97621b74, 0x34ae276e, 0xc8dc6c73, 0xd23b0643, 0x2b52e06d, 0x1daf34b3, 0x28f5aa08, 0x54123619, 0x5225eb3b, + 0x9074c568, 0x5c6c233e, 0x86b8fe85, 0x75e5e8cc, 0x8f0fa389, 0x59904920, 0xdc861e32, 0xf324a998, 0x41a8b7de, + 0x75da7bd9, 0x6bbc71c7, 0x92630000, 0xcf9d47a7, 0xc5f9b4f7, 0x4a239905, 0x18942d5d, 0x2579654e, 0x2c760545, + 0x43350329, 0xf59e8fed, 0x609279f8, 0x7a5239d3, 0xc74a6ac4, 0x83678ff0, 0x3504a72f, 0xa66ecb47, 0xf39ba560, + 0x0502ae7f, 0x757f80c2, 0xd61eb8fb, 0x5b7d1c2a, 0x90322180, 0xd71fa482, 0xfc46be33, 0x56845674, 0xdaf0e06e, + 0x915e08d7, 0x13626ea1, 0x5a3b1b4f, 0xf791950b, 0x82c1f9e6, 0x968d4b69, 0x77401b7e, 0xb7a54040, 0x7b17d000, + 0x39f32a45, 0x47f254e4, 0x90838430, 0xf5af64be, 0xab03ebc3, 0x5e318ba4, 0xc7436603, 0x5403d4f6, 0x522c3575, + 0xd642ea20, 0x6af90855, 0x5a222323, 0x250de2a8, 0x4b7c2778, 0xc5d0ae85, 0x26e60e26, 0x24e98c32, 0x8ca58584, + 0x3a3542a8, 0x98c01902, 0xa902fd71, 0x5941f59e, 0xa3ef98c5, 0x3b7cec12, 0x1ef6b032, 0xc4da00a4, 0x98056043, + 0x54e7cff5, 0x8e819841, 0x900209c0, 0x062741e0, 0x57f94b35, 0x10f8fad8, 0x970a3e5a, 0x8acc231b, 0xe39d33fc, + 0xdbaaf177, 0x8fcd810e, 0x76d0a378, 0x085c68e1, 0x141a6962, 0x49c4b799, 0xa533e371, 0x355bf6be, 0x383df4c4, + 0xfc8f1f53, 0xcba57722, 0x2ce9c20b, 0xcb37e7bd, 0x164e3871, 0xfe1e3b38, 0xaaea201e, 0x6141341f, 0xe437f609, + 0xe50420f0, 0x8fe087a3, 0x5a44fd2c, 0x4d00bc30, 0x284bf8a5, 0x5604c687, 0xe068ffab, 0xed5d7edb, 0xf4877de2, + 0x0d51c9e9, 0xcf1eb254, 0xb74015fa, 0xfd3308a1, 0x65536ced, 0xd3c77565, 0x87145f77, 0x49e22297, 0x9711c15f, + 0xa4bec9fc, 0xa892d43b, 0x71d41622, 0xea760834, 0xda535655, 0x509f3588, 0x2d0b9aac, 0x7c2effdd, 0x95dd3284, + 0xa41c865a, 0xcde21aba, 0x94519a27, 0x79141a2b, 0xf5df0452, 0x1c19d0ad, 0x77af1a00, 0x97194a4a, 0xf9e461d8, + 0x4ba3e40c, 0xab4624ae, 0x6796a123, 0xb64e0477, 0xb006b099, 0xefbdfa8f, 0x9804f046, 0x234282ef, 0x45dc0f99, + 0x7b46821b, 0x9aaa15e3, 0x97d228c3, 0x2a51f01e, 0xc142728d, 0x66e61efd, 0xc6072c6b, 0x7ba05dec, 0x2104a712, + 0x45ba984d, 0xb14c2a0c, 0x73b3aeb6, 0x90ebd8da, 0xee9d9d1a, 0xc3ae93e1, 0xd52f4bf8, 0x4897fbf5, 0xc7e00e4a, + 0x97419a9e, 0xfcff817f, 0x2dc0b43d, 0x403f830e, 0xe13bee32, 0xad8b6424, 0x2694e41b, 0x734e266a, 0x29d82e08, + 0xed53c6c2, 0xc0858f0a, 0x7fe3d367, 0xbd69c7f2, 0x0b4352a6, 0x7ba827f4, 0xcf628cae, 0x9683042d, 0x801bd875, + 0x3ff2daa9, 0x15c53af6, 0xc10b368e, 0x97b06cc7, 0x90612d43, 0x6fbc9203, 0x979d3bb0, 0xd1a1cf62, 0xe05912c1, + 0x74f22a63, 0xd4634eee, 0x00958a05, 0x13795339, 0x5b325ff4, 0x457eb808, 0x6b4514bc, 0xf9bd26d5, 0xb5d6a5c7, + 0xdc31ca72, 0x946f4b1c, 0xd8bc9bf3, 0xcd4d421b, 0xb6433c59, 0x0cdb9353, 0x5bbb7ba5, 0x1a72f3e9, 0xc2874a51, + 0x2d786856, 0x18d1e5f6, 0xbac33e29, 0xfb523f52, 0xf4f7f709, 0xfe7e1d41, 0x0b934b94, 0x2b3479b4, 0xd7a862c9, + 0x6c8d361d, 0x3f11d18f, 0x1662339e, 0x8afc0acd, 0x5bbacf75, 0x8f922e11, 0x1b451a88, 0x1a3b4351, 0xe48b7d4a, + 0x343532c4, 0x2799e73b, 0x159e4053, 0x4afb804d, 0x8ee99dbe, 0x4f3ae6d1, 0x4c9a0355, 0x3b9cf798, 0x58115d3d, + 0x5d01762b, 0xcb080d49, 0x52de2b62, 0x56049d31, 0x1dd6accc, 0xac46a12b, 0x07e8a476, 0x6800cee6, 0x6e2c9838, + 0xd77da498, 0xcf558d6b, 0x0b38f171, 0xc46b8549, 0xb7ba4408, 0xe2f95b17, 0x011baab3, 0x5b79b015, 0x1d298203, + 0x0078d8f2, 0x56c4f90b, 0xae8a3a50, 0x562761b6, 0x71d0baa3, 0x954c026e, 0x270c94f0, 0x1065d7ea, 0x5411b394, + 0xa5076720, 0x8bd5bb44, 0x03e890a3, 0x69a11b1b, 0xf4599c86, 0xbe306a8b, 0x70a3c2f1, 0xbd9ac9b9, 0x7ed4153e, + 0x5b0df6de, 0x56388636, 0xd8d21945, 0x39fdbb33, 0x1c8f610b, 0xe714b2f9, 0xa06a1d13, 0xc5e8e83c, 0xabfbed2f, + 0x38d4244a, 0x9a056745, 0x45252d52, 0x33e9a486, 0x364eb044, 0xf853a5c8, 0x33e9b1ff, 0x0cb02807, 0x8f2cfaba, + 0x51a992b1, 0x09b3f80c, 0xb3642cda, 0x28575b2d, 0xacc4cfad, 0xc4e22826, 0xdbb1f66f, 0xdd363322, 0x6760532f, + 0x729fa6e2, 0x99d0647d, 0x8f48e38e, 0x7244de20, 0x9f2296a7, 0x30eb3fb9, 0x669c66fd, 0x17c560fd, 0xf1c51db4, + 0xd3fe64c5, 0x945b06b2, 0xb5a596e0, 0xd08059dd, 0x828ca3c1, 0x5bbc48e5, 0xb96a0929, 0x949a8847, 0x54eb079d, + 0x69e57c89, 0x313ccf36, 0xa92fbdb4, 0x43434bfe, 0x7c87c193, 0xbe152699, 0x5cec282c, 0x699d0a4d, 0x3219d3b4, + 0x05bddd37, 0x78ad988d, 0x077f11b3, 0xa1443a26, 0x91632f76, 0xf9e19ba2, 0xb8701c57, 0xfa76f106, 0x8ab9a9d1, + 0x5ba5df21, 0x4ef432a2, 0x72f0d46e, 0xdc93ba6e, 0xb47d33ad, 0xf7de129f, 0xdecaa56f, 0x2a1d35ae, 0xf1c7be6d, + 0x189aba9c, 0x8e348cc1, 0xad3b6a98, 0x8a000a1d, 0x2c1c612d, 0xeb38ef5a, 0xdec8aaf1, 0xcc789688, 0xfe999391, + 0x8b42d27c, 0x22616470, 0x1e065350, 0xc6c1eb3f, 0x370f8ba0, 0x22a47a6c, 0x4506d3bd, 0xf4952d75, 0x8224c03f, + 0x81fc1654, 0x6eb3ef78, 0x981474b8, 0x1c6c37fe, 0x975e20eb, 0x091fa5b9, 0xbff1a784, 0x9c230327, 0xd7f0103f, + 0xcc0ec938, 0x146da2e7, 0x371f9985, 0xcafaaa7a, 0xd6d2576a, 0x68797dec, 0x069ec0d3, 0x77e18f21, 0xfeaa13fa, + 0x388c500e, 0xc69e596c, 0xded17595, 0xa687d7d0, 0x0d9e6865, 0x3db1e71b, 0x2950448a, 0x0c50af55, 0x6efa9f58, + 0xa622df76, 0xc45863e8, 0x3de5f9bf, 0x2c768641, 0x76ae8c08, 0x02c18950, 0xbfec0be0, 0xa07bd830, 0xfcd0c428, + 0x822f693d, 0xe7c9bc7f, 0xf7a99c75, 0x117a492e, 0x3d81a2c1, 0x17f82f3c, 0x798552bd, 0x492100db, 0x1633083a, + 0x7d070671, 0x7e0e7cb7, 0x5b8ccb8a, 0x75bac41d, 0x66120b97, 0x31bb3e7d, 0xb208c1be, 0x95fcdf76, 0x21a771ce, + 0xc6a1b58a, 0xf88cdf33, 0xe2763b1f, 0xe979bb54, 0xf890517e, 0xff632d19, 0x6e2778bf, 0x05a67b0b, 0x49799ef2, + 0x0aa24e7d, 0x08d1bd24, 0xd0f3378e, 0x05028421, 0xac816391, 0xd87cb729, 0x3a1f3264, 0xa06a4a48, 0x1c51c09b, + 0x9af77cd0, 0x1500a67f, 0xf84ec48d, 0x7800370d, 0xfc064916, 0xf4371a0e, 0xd8eb10ed, 0xf5887135, 0x062dd20e, + 0x7fcdaa0c, 0x7e937b9e, 0x36992048, 0xda8565f4, 0x15d2b27a, 0xb0cac959, 0xecd9ee43, 0xe600658d, 0xf1615f0f, + 0x3efdf8f3, 0x574b09c5, 0x91ba5db0, 0x98b54655, 0x947db946, 0x305adc4f, 0xee27ec70, 0x39248d3c, 0xe690f539, + 0xad68b2c9, 0x268c722f, 0x74c09f50, 0xbcab28f4, 0x8d9eeea5, 0x8097d583, 0x9f28ef8b, 0xd01e04d0, 0x85a15b0f, + 0x9b45dd08, 0x9d3295a7, 0xd14afa71, 0x1f14a51c, 0x7124db5a, 0x411566cb, 0x9570a5cc, 0xe5d2574d, 0xd4858043, + 0x25c33dbd, 0xf1b85229, 0x6c468210, 0x0b7b0b64, 0x9dc5638b, 0x260ce0d4, 0x42cdc437, 0x00b1e6d8, 0x8c03d51c, + 0xc1fc5e80, 0x7029e9f8, 0xafad10f1, 0x49ffa6e7, 0x5366f296, 0xd3d3a220, 0x8553313f, 0x4f1cf9d3, 0xf4a35ca3, + 0xa2e59903, 0x5900b736, 0xdc568d47, 0x151e3186, 0x61ec7a3a, 0x1739405e, 0x4222726f, 0x58b316b1, 0xf841d2e2, + 0xef1840d1, 0xd83a94e1, 0x9154e4d5, 0xbadb7730, 0xb8e41024, 0x415b567e, 0xea880483, 0x52364cb7, 0x2a76afbe, + 0x2b52e723, 0x8f6f6876, 0x30224bc2, 0xe26134c9, 0x8330b05b, 0xd49cec97, 0x1848ac0d, 0xc4a7ae33, 0xf8d33274, + 0xeb7bd689, 0x0ac6d32d, 0x288dfb43, 0x1ad22cd8, 0x03dc2280, 0xef953647, 0x70370578, 0x3e864dac, 0x5cde7bec, + 0x25241874, 0x5b956fef, 0x8079be21, 0xc4a0ee30, 0xfeba8aea, 0x855aba7d, 0xcff3b367, 0x234a263c, 0x13adcc86, + 0x7ba1a1f1, 0xb66c565e, 0x9c3852c8, 0x73f20612, 0x851c5df4, 0xc3c76d9b, 0xf9d32242, 0x61b77284, 0xde17acb3, + 0xbd0dd319, 0x50df5579, 0x168fc4fd, 0x554599f7, 0x8e893e34, 0xcd77e800, 0x3bf89304, 0x4fdab08d, 0x9a49a380, + 0x82367cc9, 0x871959dd, 0xc76491ea, 0x53d946a5, 0x2638957b, 0x5032d89c, 0xcc7906fb, 0x3391040d, 0x677c6742, + 0x93334374, 0xb4c0350a, 0x80bcdc1b, 0x58e01cff, 0xbb54c9d1, 0xb4ceefa3, 0xf8a3bf63, 0xd9bbb404, 0xf57ec226, + 0x5354434a, 0x6068645f, 0x9478a119, 0x682e5612, 0x07d01b5a, 0x793b4053, 0x66e7c5d2, 0xcfdc22e7, 0xa1afc6ff, + 0x6a128d62, 0x57f4d2b7, 0x01def488, 0x299649ac, 0xa852ad7d, 0xde8523f1, 0x4ae57cca, 0xb752e63d, 0x93e00d44, + 0xdea43b9b, 0x2827ba0a, 0x928f91d7, 0x6ac0dc47, 0x9d0ff81a, 0xcd7eb8f7, 0x5739fd2c, 0x4b9ac1ff, 0xc0ce13be, + 0xc13b0c0c, 0x6311244b, 0x5fe3739a, 0x6a155c7c, 0xff3b245a, 0x79c9c1e7, 0x8120c9cb, 0x686e1b4d, 0xbdcd0356, + 0x8644c58a, 0x35306a75, 0xdbf28647, 0xef29af50, 0x1bf22d24, 0xcf642162, 0x47e10839, 0x2a8a04df, 0x3fc8a741, + 0xc5a04f8c, 0xba764e88, 0x7ecc0e7e, 0x5c586125, 0xdae03974, 0x5451a95d, 0x43885c2c, 0x73ad899f, 0xd1797705, + 0x920152bf, 0x2b72054d, 0xe6940fc8, 0x138d3385, 0xa15de4e1, 0xbf013422, 0x124c4e03, 0xd3b53152, 0x1ed75bf9, + 0x904be280, 0x270fd6cc, 0x28e173aa, 0x251474e7, 0x928ad410, 0x60d5c932, 0x65740c06, 0x85dff9c2, 0xf062f7b5, + 0x4a3323cc, 0x566e8e01, 0xb829e428, 0x6c857422, 0xd367020e, 0x9506620b, 0x8b25f417, 0x3283d29b, 0x55b94407, + 0x052a938e, 0x71670150, 0x239bc81f, 0x4fc7172a, 0xd67a81e6, 0xc01c3289, 0x97ebf000, 0x8f28a722, 0xef2717db, + 0x6871d2a3, 0x6c46bfef, 0x7d956af2, 0x066bcbdf, 0x50c7cb1e, 0x261696ce, 0x26e3efa0, 0xf18ea1e3, 0x442a094e, + 0xd158b109, 0xae071c56, 0x1c4a7004, 0x7597e6b5, 0x704ac978, 0x2a25ed60, 0x27a39dd5, 0xb02b8c0d, 0xb202053f, + 0x50cb9634, 0xc5ad0ba0, 0x9f5eff66, 0x29a6fe93, 0x828b6b2a, 0x04d6fe9a, 0xa4fb4040, 0x5d286a19, 0x21570461, + 0x1b62447a, 0x2cee4c52, 0x240276f2, 0x294afa13, 0x24392fa3, 0x45ad4f8a, 0xf30153a2, 0xf140ea4c, 0x96cbedbb, + 0x4cd6f80a, 0xcc93ae8f, 0xefabbbef, 0x85dca33b, 0x08539666, 0xb477f80c, 0xf62a6723, 0x500b6fc0, 0x4563a439, + 0x0febff9f, 0xbbb23403, 0xf0680307, 0x75196f48, 0x97b4b745, 0x9700e895, 0xd858f1ad, 0xd26172e3, 0x956b329f, + 0x366bb105, 0xcecbca1d, 0x4618d978, 0x5a4a1523, 0x76a0cd21, 0x02d68b62, 0x4088f552, 0xa78dcfef, 0xc59aab31, + 0xd9357c46, 0x698abb08, 0x3e61686b, 0xfdfa8193, 0x5c56a5be, 0xfc0bc34b, 0xa9f9f211, 0xf80c4f9d, 0xc46977e7, + 0x858bba59, 0xe8352a30, 0xe0238ea3, 0xb9371920, 0xe8ba88eb, 0xe0a67c6a, 0x2790872f, 0x6e6dd105, 0x23070e11, + 0xc1c5f40f, 0x9da4e571, 0x4c8e5c07, 0xfd1cc4d1, 0x68c88ea6, 0x2dabee95, 0x1dfe46d1, 0x41d2454d, 0x87f2d6e4, + 0x35fb4034, 0xf9f3d451, 0xf34bb6e2, 0x3597bfb9, 0x9cc92764, 0xf585e645, 0x58ff5811, 0xb4db48d9, 0x9a499618, + 0xd6ac101e, 0xc0aec0ce, 0x3c8f7f3e, 0xcc91bbcf, 0x578bfb02, 0x5df5b13a, 0x685d0c25, 0x4c2a0f74, 0xe6adad49, + 0xb0336854, 0xeb564efd, 0xf4e79b2e, 0xd5bb449b, 0xd841864f, 0x76b4f0a8, 0x49afbedb, 0x84e48484, 0x171c691e, + 0x8fb91dfa, 0x392e2dab, 0x1b203773, 0x1298def9, 0xaa1489cb, 0x923f54d2, 0xc8fb008e, 0x0d8fe9b3, 0x8b8d32cc, + 0xca67acc6, 0x9342e654, 0xeb906cf5, 0x599c4538, 0x7e249c16, 0x1fd77392, 0x273d9b58, 0x389a1aa7, 0xefa945b3, + 0x4127785c, 0x7739bcec, 0xd975407f, 0xf6565333, 0xd51eeca3, 0x94c0eb73, 0x91465cb1, 0xeb011228, 0x71557fcf, + 0x559f5ba3, 0x88eefd07, 0x53b8083f, 0x6d12d929, 0x9e7b4809, 0x4a9c5988, 0x9d29b6a4, 0xb540d8de, 0x76f4f609, + 0xce348efb, 0xac94a2b6, 0x17496860, 0xfc33ab6e, 0x5a1cbacc, 0x5ca76358, 0x03ed8477, 0x789a436d, 0x860681c8, + 0x5ed65582, 0x1b0777eb, 0x107ce309, 0x662c8655, 0x83871cb0, 0x3b8f17d0, 0x50446ba8, 0xef74dc8f, 0x9e0aad68, + 0x31738422, 0x51e3e55b, 0x1083561d, 0x1e9d96b3, 0x90a54f04, 0xecf83c83, 0x6fe7c3b4, 0xa26c3ad9, 0xaa77c717, + 0x45d5e9d8, 0xf42caafc, 0x2c2d7136, 0x19db5405, 0xc257268b, 0x7b27a9bb, 0xf64c4c69, 0x71898b03, 0x23c14573, + 0x7d016e0d, 0xdeed80b6, 0x58c16456, 0x65cbbc18, 0xa61ca409, 0x6bdaabfc, 0xa80c4667, 0x69b96290, 0xce5d05e0, + 0xf43bf940, 0xefa8b950, 0x2744a0e6, 0xc839fcfb, 0x92bf350d, 0x4296cc45, 0x168a0deb, 0x430c5558, 0x8a497886, + 0xa98f22ba, 0xaeae537b, 0xd1022096, 0xf3a85737, 0x82ebc753, 0xd68b7df1, 0x221367fd, 0x12c357fb, 0x290650bb, + 0x7289359e, 0xa7bf62a2, 0x788737da, 0xad472739, 0x2b5e0a5f, 0xbf56c409, 0x61f4b5f3, 0xe7aa6999, 0x07fd4772, + 0x73b3ea93, 0x501579ce, 0x9697ef10, 0xeef8fbd0, 0x147bb583, 0x7e64b230, 0x307124e0, 0xc3b69c45, 0x44590514, + 0x9c1e936d, 0x8a8d8f94, 0x786463a4, 0x5bbf7edf, 0xe56e5a63, 0x69de91d0, 0xe2b0e47b, 0xe2a02a67, 0x8662124d, + 0x2b4d183f, 0x8af237d3, 0xc49165f5, 0x9cc4bdbe, 0x9a768903, 0x2f3ced9d, 0x4684f188, 0x163763a6, 0xa56602a4, + 0xfcd4fc45, 0x6b28ef61, 0x70365915, 0xde8a25cc, 0x555678d6, 0xc5174340, 0xaa4d44dd, 0xc083880f, 0x9bed0581, + 0xeb173a91, 0x8961adac, 0xc1e0fe54, 0x2e9b59f0, 0xf6b81d19, 0x92913a9e, 0xa4a36345, 0x47473637, 0x79a5605e, + 0x061c3b08, 0x4d06815c, 0xf21bbe13, 0x1c298e51, 0x9f1f1821, 0x002b63b7, 0x7e02c526, 0x0fb264f5, 0xab29e6a0, + 0xcf361149, 0x3013226e, 0x98cf6777, 0xdfcf4cc9, 0xa1cb1ece, 0x9640332a, 0x6a38e871, 0xd41f945b, 0x213039f2, + 0x910d01f2, 0xb5777429, 0x3f97a39a, 0xdf9d1639, 0x48dfad89, 0xc73f0f3c, 0xd2ac3a18, 0xb949806b, 0x5a13e5cd, + 0x1f82b700, 0xdead3f71, 0x5f654dc5, 0xd4f30fc3, 0x649dae55, 0xaae814b9, 0xcc2bfd6d, 0x9c8ea089, 0x709729a0, + 0xc49fb3a0, 0x35302dd7, 0x409c62e7, 0xb608cf60, 0xe4102aa2, 0x013ab38f, 0xba92bb69, 0x8b4d04dd, 0xeb0ccd5f, + 0xb25e295c, 0x1f2a2d6b, 0x18a67fb5, 0xd0961cf1, 0xd8e3b004, 0xa851c96b, 0x1386b31f, 0x03ffc95a, 0xdfb16b85, + 0x10eee18b, 0x73439a30, 0xf51ee8ac, 0xfd651457, 0xd7dd019c, 0xb885ae69, 0xbd774e0e, 0x3d61d9c1, 0xedbf2f19, + 0x8e5d25a9, 0x2c8c5252, 0x5911ae79, 0x9982f623, 0x837dd0bb, 0x6598c4de, 0x6672be1a, 0x1b7c72e1, 0x34acec54, + 0x06f9741e, 0xa7ddf3e1, 0xc70bf760, 0x4399dbe4, 0xee34bcf8, 0xe0a1a45e, 0x0885ed59, 0x259eb09b, 0x81ea557c, + 0xb91e9952, 0x3f319d64, 0x68ad5f1d, 0xa686b461, 0x3084edf8, 0x8a32e938, 0xd6c7a537, 0xd5f76776, 0x8f5be637, + 0x51c6f378, 0x78b00f95, 0x89ae37cf, 0x76089c44, 0xb594e3e1, 0x9130fe4e, 0xa677a057, 0xd79afa2b, 0x2f2192f4, + 0x62709352, 0x811d5570, 0x71ab1cae, 0x1f9aa91c, 0x805d64ae, 0x6c9ee660, 0x11be8edb, 0xf2b7b16a, 0xf0ba2330, + 0x5c72b3df, 0xb6014b44, 0xece8e4d0, 0xb9621a61, 0x91694ee4, 0x5aa524fc, 0xa1621a3f, 0x5d959554, 0xe966cc1a, + 0x080095c1, 0x1e9761e5, 0x581ed025, 0x31a1c8c3, 0x9e0872f4, 0xc17d7ba4, 0x9e0f4191, 0xd21700e9, 0x8fa9b2ef, + 0xfa519233, 0x817525d9, 0xad158e62, 0xf9a0ff41, 0x76139c97, 0x868f4536, 0x647c4a20, 0x84fc686e, 0x5e05d3d5, + 0x15520fa8, 0xfdfb5d53, 0x5ca21490, 0x4b5a9fe5, 0x92834313, 0x27352893, 0x08fe6fc9, 0x27577d90, 0x005c4b7a, + 0x4ceef39d, 0xd68a4986, 0x6c87f020, 0x7356e075, 0x48c0b210, 0x09e58461, 0x4477dd91, 0x99a38f61, 0x92f3208a, + 0x5cd22da2, 0xcb9addf6, 0xc6925456, 0xe0f07bbf, 0x24334deb, 0x1bc1be6e, 0x9628582e, 0xad22cda2, 0xd93284cc, + 0xb4830440, 0x3aac73e2, 0x9515b829, 0x024c1590, 0xe441109d, 0xd1a582be, 0x72547623, 0x3d2e0fc8, 0xd7f5688c, + 0xc211429c, 0xce4fe5dd, 0xe7dfce2f, 0x038544a9, 0xa5cbf325, 0x307651d8, 0xee9be4d2, 0xeda61ef3, 0xab828540, + 0x2fef765e, 0x610062d0, 0x755f4c00, 0xf3cc681c, 0xa94ee980, 0x3562b287, 0x92b4a20a, 0x3172d1ae, 0xd11a4113, + 0x5e9f243e, 0x22436fbd, 0x64b9b012, 0xd10821dc, 0x4bcc6f61, 0x69c091fb, 0x05930e32, 0x1f4b4a70, 0x8e74c5e6, + 0xf2790afe, 0xed1b2ddc, 0x90cbd807, 0xccb1db36, 0x38ca2349, 0x29c11f64, 0x85d53993, 0x50c22996, 0xddf092e2, + 0x6e6c9732, 0xcf555ec3, 0x8bab11ea, 0x3fcecf2c, 0xd4943c7d, 0x984e3416, 0x729c3857, 0x08d05f69, 0xf05b565b, + 0x155629b6, 0x389f7e63, 0x6d0b592d, 0x226cdb91, 0x047a9e2f, 0xd03cb2bf, 0x9abe5f5f, 0xe738ad13, 0x6f265bf9, + 0x47f4c4cf, 0x812f501e, 0x34e784d4, 0xd0fb5b1d, 0x7819db01, 0xc776ccef, 0x68f72120, 0x961d4240, 0x2d904820, + 0x81b80ad6, 0xf3bc1a8f, 0x7a59e01b, 0xce0fca65, 0xaf5abf29, 0x386635f7, 0x06c72a6e, 0xc0691c14, 0xc49ab656, + 0xef11173c, 0x0a1fcc33, 0x1fcf54d6, 0x96c82acf, 0x9dccef5a, 0x16a5f388, 0x207d3239, 0x90773846, 0x3d588ce4, + 0xe95893a7, 0xde18192e, 0x6e341cb2, 0xad3c5cf8, 0x1fead890, 0xd6c6f9b8, 0x594a0679, 0xeff8cd7d, 0x895cf003, + 0x42cae807, 0xfff261ca, 0x40edcf5c, 0x3ce3986a, 0x0f4e590a, 0x7e13cc39, 0x80ef7455, 0x047d4ea2, 0xa2e8678b, + 0x55f989c2, 0x997c4cd4, 0x910d4a11, 0x245d764c, 0x6b8bc267, 0x724c8612, 0x47a25a44, 0x165ddbe4, 0x029029e9, + 0xdee123cf, 0x0c39ca89, 0x583c16d6, 0x7ed6b1b8, 0x091c2399, 0x80a8764e, 0x5af00438, 0xc9fa7767, 0x9206a3f8, + 0xb5d8cbe1, 0x01c38cfc, 0x57828d7a, 0x1373191e, 0xf804b568, 0x3dd0e4c4, 0x204dc2cc, 0x66fbec3f, 0x8c814682, + 0x82a46b59, 0x1f5564b9, 0xaf116916, 0x052fb800, 0x8947255c, 0x330a8611, 0x038d4a36, 0xd1b7879c, 0x114b0de7, + 0x14697702, 0x54c8bf05, 0xbd76cc82, 0x0d6c9f87, 0xdd64a13e, 0x70727f41, 0x9651d151, 0x34b922c2, 0xa44d3270, + 0x6ec2c509, 0xbdcba150, 0x6a681eee, 0x5be6dc3c, 0x538f2682, 0x8f94a7cc, 0x78486d0f, 0x358d296c, 0x6fd91631, + 0x1a09a205, 0xa0da4bfb, 0xf2ecdb44, 0xecdd9295, 0x49045586, 0x0ef09c3f, 0x680de4b3, 0xe9048b2b, 0x7ec8fed0, + 0x4c4e3abe, 0x6344976a, 0x6c023710, 0x4244d611, 0x53f98f61, 0xd4d85c75, 0xbc597980, 0x244574e0, 0x9754cfb0, + 0x4228ffee, 0xbfa67ed8, 0x4e9454e5, 0xa87ddf1f, 0xe808523d, 0xb3bd782c, 0x0ce78c81, 0x867062d2, 0x017db56e, + 0xa2b5cd42, 0xe5b3105c, 0x4814c3ea, 0xcf0c925e, 0x0231eb7a, 0x6db952f1, 0x447557b4, 0x1a6f1cc3, 0x1de399a6, + 0x7313db87, 0x02c77ad7, 0x18080999, 0x59045535, 0x691c991c, 0x109d1344, 0xf2d9751e, 0xfe7a3cb5, 0xac0fe4e4, + 0x91e6c785, 0xe843c92f, 0xd0141067, 0xa0161419, 0xf4145d06, 0xc6f50ea3, 0xfc0a7d23, 0xbde4774f, 0x5a5730ca, + 0xa0d69e49, 0x78d736b3, 0xe38bba0d, 0xd5a79f2e, 0x005e0cc6, 0xae713a4b, 0xca50d98e, 0x08cc4bf6, 0x54e84c70, + 0xd7095153, 0xf163e5e6, 0xc36f4550, 0x62031e04, 0xf9a77d0d, 0x315c6588, 0xb55eaddc, 0x27f68fce, 0x947ad9a0, + 0x41adecc2, 0xd34296d4, 0x1df2710d, 0xb9700027, 0x449decdf, 0x958956a5, 0x29e3ccd8, 0x20b6002c, 0xf5e22b7e, + 0xe967f123, 0xbf9142e2, 0x9aaac867, 0x30b4397d, 0x6b55b51c, 0x087d3291, 0x3b3001be, 0xa5e0a17a, 0xaedafa41, + 0xd6942f01, 0xfed07c76, 0xe09f26ff, 0xec03a3d7, 0x96a03371, 0x0e31d9e6, 0x4d04c522, 0x9b67f32a, 0xad773379, + 0x61583682, 0xd4241fe4, 0x1c648f48, 0x4e27d0ec, 0x5e7d7fd4, 0x815fdb45, 0x66e78a17, 0xa5c7b5c8, 0x87e2788b, + 0x5cf62694, 0x01d0e371, 0x1783cf73, 0x57ae0beb, 0x5b636793, 0x2c8b79c7, 0x2af9d7ea, 0x18f39df1, 0xbb327600, + 0x642388f0, 0xa6b8ca87, 0x6c9f1fc5, 0xddd34bc0, 0x3b1311ad, 0x141c273f, 0x8b5d457a, 0x353cec7f, 0x6300a61c, + 0x24086b75, 0x458324a7, 0xaaff52d1, 0x0a901d6e, 0xb4b5b6f5, 0x9ced1a48, 0xb55fc394, 0xfa3e2b28, 0x08fdb122, + 0x0008d3f1, 0x44208136, 0x976b73d9, 0xfcab5de8, 0xb50398c7, 0x0ba817e0, 0x165e5ee4, 0x9e65c7a9, 0x4e9356a7, + 0x8208ab1e, 0x51e467cc, 0x57937a67, 0x9bd3333b, 0xb8a3b7f1, 0x74c97a9b, 0x1dc9119f, 0x9ddfcb50, 0xa103b5bd, + 0x86a3fb97, 0xaa46fc20, 0x7880c907, 0xa584dd5f, 0x10ddabb2, 0x048d2054, 0xa21b67fc, 0x13a88546, 0x3f88a2e6, + 0xb7e906c7, 0x552a478e, 0x0f0a5552, 0xf8b015af, 0xb0cfe5f8, 0xe74429dc, 0x595d1ca4, 0xf2e3a6f9, 0xfe2fe809, + 0x965c45ec, 0x7e7cb572, 0x1e3ca13e, 0x5a80ffce, 0xb03575b0, 0xcf5efc3b, 0x003db31c, 0xb30369aa, 0x993fe5f8, + 0x7365088f, 0x5c2bcc64, 0x1343391a, 0x801a8866, 0x4f58e971, 0x373435fb, 0x67d6ac16, 0x0e60aeb6, 0x193fe901, + 0xf1fd0da0, 0xf8b3cb7b, 0x19abd521, 0x1352cc4d, 0xfc3870a1, 0x59af26b4, 0x418f1ce9, 0x37c05cd3, 0xc88af3a9, + 0x4481d527, 0xddfd5dee, 0x0e8e6b8a, 0x37a12f72, 0x98b63b0e, 0x235f6228, 0xbdcb8bb2, 0xe54211b1, 0x007e856f, + 0xe416321a, 0x3bdc5a21, 0x3b85f9e5, 0x22019804, 0x5d134027, 0xfc74800a, 0xa5d29bd2, 0x30390537, 0x83d3130a, + 0x2e9464e3, 0x56c82fd4, 0x524569d5, 0x51624517, 0x7e5e5477, 0x25051abb, 0xbbf4fbec, 0xa43a7cae, 0xcc8d63ad, + 0x0bc67263, 0xbc8b3e32, 0x5de9e0fd, 0x113fae49, 0xfba0bf51, 0xd7846838, 0xe3502b0a, 0x91a61192, 0x151f15a3, + 0x8114e382, 0x11319f09, 0x781bdfaa, 0x6d8c3e04, 0x75c2fdb6, 0x071e0004, 0x76d99290, 0x889c0b0c, 0x311dac2b, + 0xb6072a7f, 0x47984a24, 0xbaea7c91, 0xc74c6d7f, 0xdb22826f, 0xcdfb9233, 0x5aa1e238, 0x8f70a687, 0xc6f5822d, + 0x92871dc1, 0xb19a4bef, 0xa3fc032a, 0xf80e8782, 0x49c04c6a, 0x53c56267, 0x13dd2b95, 0xe9d0bab1, 0x0e243bc5, + 0xa8a1f3c5, 0x1bb0f739, 0x935412cd, 0x0da67c82, 0x47955636, 0x2d285892, 0xdac9a11d, 0xe269f551, 0x364d16be, + 0xc29d2606, 0x60aba52e, 0xc63efccb, 0x23498c86, 0x728760c3, 0x3773e2e0, 0xad7108bf, 0x1dcc4746, 0x529f58fc, + 0xf22782e8, 0x24d7f67a, 0x7aa28533, 0x7bd9a0c8, 0x6e7aa42c, 0xa9e94254, 0xee7a8429, 0xe1ac3c42, 0xf8f4caa0, + 0x56261cb2, 0xff807583, 0x7ebddedd, 0x606dfe2d, 0x33648510, 0xebd585ab, 0x96d48c8d, 0x31075c28, 0xbe91132c, + 0x19bccb4f, 0x645b04cf, 0x93d53606, 0x8b074507, 0x4f075da8, 0x7690bbb6, 0xad656a58, 0xbe3d0811, 0x0884c4a9, + 0xc586df01, 0x59747f59, 0xadd974ac, 0x431a96c1, 0x2e624062, 0x0c0b1ec0, 0xac41e0e1, 0x5805ad1f, 0x09f15bcd, + 0x15eb871e, 0x0bed97e5, 0x95987d79, 0xe3babb71, 0x6ad2f518, 0x5e97c2b9, 0x28ee24ed, 0xb8dd96e8, 0x4d6091ce, + 0x23892522, 0x94b93111, 0x26530e07, 0xf73b5e2d, 0xb333b7ac, 0x485e5a99, 0x26e4d528, 0x04d2c137, 0x4bf11591, + 0x3762b076, 0x103ecb0f, 0xbb3754b6, 0x0d67381e, 0x9a851106, 0x8c721fdc, 0x2c32e44d, 0xfb7123e9, 0x6a80f14d, + 0xa2a07d99, 0xdad76c6b, 0x229b7d1f, 0x3906eca8, 0xf283f4d7, 0xa8ef2678, 0xba53adb4, 0x251f85c2, 0x0e27ef5e, + 0x61992f3a, 0x918aa5b8, 0x38c5ea4d, 0x658ce9f6, 0xefb7b16a, 0x13923f65, 0xe908ab59, 0xe7ec79c2, 0x0f2e3398, + 0x3799b9ec, 0x1d1a630f, 0x8c48d4a9, 0xfe2740f2, 0x98903e18, 0x0f86f6bc, 0xa7ef603c, 0xb6cceda0, 0x4d7f3759, + 0x9bbba114, 0x5aca2c4e, 0x11c7ccc3, 0x4e815917, 0x3b296fcd, 0x2c74438e, 0x3b6ac7a1, 0x5cfbac60, 0x74e200aa, + 0x9bc86ceb, 0xfcf6d5d1, 0xcb2587dc, 0xaaa1abd7, 0x7617fae9, 0x2070f59d, 0x87de255f, 0xc4755198, 0xc1c5f675, + 0x5e2cb21e, 0x819e8de4, 0x588ec249, 0x1d241e03, 0x22fd234a, 0x96f7dd45, 0x06d0cb20, 0x6da2df4b, 0x3f44cb4e, + 0x52b86eb1, 0x77a0fbfc, 0xb1770446, 0xb321dc17, 0x9b77beb5, 0x2e8406a0, 0x0abb6fe7, 0x4e38a7df, 0x0c88c643, + 0x3e5d66ef, 0x7ee70732, 0xafc523d3, 0xb0be54c3, 0xeb69b791, 0x4bb3c084, 0x851ff1b5, 0x8607ad9c, 0xe744292a, + 0xea1c7046, 0x9ed55399, 0xbd70c525, 0xd8d58f72, 0x82d9ddf9, 0x6bab6abe, 0x6984061f, 0xe6355621, 0x908d87de, + 0x817c0a30, 0x1995a44e, 0x7a33c446, 0x00a7009f, 0xb7e97cb3, 0x7b5f5cbd, 0xcdb958fa, 0xfd38a6ae, 0xd021cd97, + 0x87cebcd8, 0xcf7e7b47, 0x1540f502, 0xcca50e91, 0xac8fee6f, 0x57fe363b, 0xe247371e, 0xa9fbd651, 0x20546fcd, + 0xb00467a9, 0x64710cc4, 0x92a33ec3, 0x0231f8a8, 0x062e584a, 0xd692736a, 0xf7e80f5c, 0x666aa104, 0xf5719de5, + 0xe43cd0ff, 0x6ed6be83, 0xeedb7d49, 0x90730412, 0xeafde4d5, 0x86fd92b7, 0x4d49e9ae, 0x071c9529, 0xec04337d, + 0xf5b765d9, 0x45c34bb2, 0x7b5d9f13, 0x49aaadaf, 0x3295242f, 0x06856dd2, 0xd16180f4, 0x9aa88e5a, 0xdeba987e, + 0x2f482313, 0x604f2ebb, 0x3b58d57c, 0x4685a395, 0x91ecbcd2, 0x61997c4c, 0x9711850a, 0xa5e7967b, 0x7fe2884d, + 0xc5429d7a, 0xb11b818a, 0x4c43533a, 0xaccac0c5, 0xd2ce704b, 0x14c374ab, 0xfe86c102, 0x0a98a2e3, 0x3ece24ee, + 0x2a6e0807, 0xb279da81, 0x395e6bc0, 0x3a7c3f3b, 0xbab9e111, 0x15f7a5a3, 0x5217e51e, 0x5007e2ff, 0xeda89e94, + 0x8b14ab6d, 0x676b3dde, 0xd1069bec, 0x91ec7c75, 0xa69b1411, 0xdb67779d, 0xe2395395, 0x71c1b949, 0x4313d043, + 0xae65f03b, 0xd3a9bf0b, 0xccbf7e16, 0x1b295853, 0x72dfd015, 0x4ec78d7d, 0x4d084d51, 0x40b5ead5, 0x75222bdd, + 0x6243b053, 0xecd80dca, 0xe5348d8e, 0x709bedd0, 0x2a34a7f2, 0x4f4b3e91, 0xf835c13e, 0x6a37a456, 0x20710a27, + 0x8b50c0fe, 0x8a96b267, 0xc7a871b9, 0x574dfc27, 0x61460fa9, 0xfbcf8410, 0xde997b31, 0xd85f66e1, 0xf7c28485, + 0x47bbcc03, 0x5c20fb01, 0xb3ca547e, 0x06089b4c, 0xb0a95fbf, 0xd3169ba1, 0x9a9cd198, 0x24d07a8c, 0xbb544214, + 0x1d871ff9, 0x28a78322, 0xa8ec26d0, 0x6d04cc17, 0x6b1d1fe2, 0x21ac5b01, 0x9a93f234, 0x42181fbe, 0x95416e46, + 0xfcf9e95e, 0x0165c7e7, 0x82a5c500, 0xdcd7a347, 0x29e0fe90, 0x3be1a027, 0x6ffdc8c3, 0x923cda72, 0xf0c1eb98, + 0x822aade1, 0xcae606c1, 0x7db5b61a, 0xef286c3d, 0xcbfbbdee, 0xfd965b10, 0x07bfc3e4, 0xea1a1432, 0xbbb56d9b, + 0xbdee63dd, 0xb27c32c5, 0x323e8164, 0xceacaa5f, 0xf34186d8, 0xecf87d77, 0x8fc19ef6, 0xd11237ea, 0xefc26101, + 0xea09594a, 0xbcd07858, 0x7bb2ceb5, 0xdd57a8db, 0x0fd0ec91, 0x5abe9fa9, 0x7dc30ea3, 0xbcd35631, 0x7682e1e1, + 0x54d2bc44, 0x6f8b6c67, 0x73648c0e, 0xee61c835, 0xaa22b3d7, 0x2492123b, 0xaadaed7f, 0x890840bb, 0x3a62941d, + 0x2ac6d919, 0xe8a6e4ce, 0x648f8ad7, 0x80852613, 0x2eff5b04, 0x4ab42fd1, 0x84986e4e, 0xa46f1236, 0x2518129f, + 0x1b95f713, 0xd68ee683, 0x1bb07916, 0xe587602e, 0x09bf70eb, 0x648d801e, 0xd33fac99, 0x54b6227d, 0x093a2a30, + 0x0bfdce59, 0x53f47c42, 0xff85c26a, 0xda90fabb, 0x49c74c2c, 0x3be6acd8, 0x5662af57, 0x567b98c6, 0x359bff88, + 0xf44667ff, 0xf439b445, 0x57bf6202, 0x8bc8d4e7, 0xc5a1485b, 0xec60195d, 0x36726a51, 0x9935faa8, 0xffade6ca, + 0x5c128d08, 0xe8df8f68, 0x4664c761, 0x784e1a46, 0x5102a281, 0xa4caa466, 0x661b1576, 0xc66ebf4e, 0x170a9db4, + 0x677f8a23, 0x249fac15, 0x5dcb3660, 0xfcb642ff, 0xa2a9c46e, 0x8800d3d2, 0x801a9421, 0x4fcb81a9, 0xed70fea0, + 0xd0dc000b, 0x4973f3a5, 0xdd40e138, 0x954d2f2b, 0x0099bd56, 0x1f4f5478, 0x6d68a6cf, 0x75ceb3ce, 0xa4b13b20, + 0x743a2a32, 0x8f093cc8, 0x77e03446, 0x77bcf53e, 0xb1d6ceba, 0x01256911, 0xccb73dfe, 0xf8ebf285, 0x99091d4c, + 0x0fa28cc3, 0x98a26be7, 0x6760ed2d, 0x70a49bfd, 0x4b61b5df, 0x269f4067, 0xa3e87464, 0x935d7fc0, 0x497db622, + 0x73273310, 0x3ee5ce9c, 0x48b4d855, 0x85a1335b, 0xf1839f3e, 0xa8c347ad, 0x61a1826b, 0xc6c07253, 0x694ec4c5, + 0xe9a41021, 0xb1c12c7c, 0x5a017d7e, 0xfee3622f, 0x0ae9aa1c, 0x18cd9af9, 0x34d00a89, 0x095b726f, 0xa231e0b2, + 0x20a7c437, 0x9c4e80ee, 0x2d2643d5, 0x54197bfd, 0x26fc5494, 0x24979dba, 0xc7796f67, 0x7ba80213, 0x1d81cab4, + 0xa763abcf, 0x4a7ae151, 0xebfb988b, 0xe371551c, 0xc0e82b82, 0x0ae89d7c, 0x2c640eaa, 0x8e0cd4d1, 0x76b9c12f, + 0xf8c503c8, 0xcd0652a6, 0x1874b799, 0x0e83e7f1, 0xc667ee9b, 0x2b57dc23, 0x4b003b2e, 0x904eea1d, 0x17a949c4, + 0x7df0eef5, 0x18103d7a, 0x01252528, 0x9387c916, 0x71ef9a55, 0x1fd89c29, 0x0c63b44e, 0x7e31dfaa, 0xaeb0094b, + 0xdfa257fa, 0x6c5762d6, 0x416edeb3, 0xd7dceece, 0x63d53c18, 0xb40d5384, 0xda341ccc, 0xc3e32ca8, 0x52b1230c, + 0x4cc1bb3e, 0xebbb31fb, 0x0423820d, 0x96d5b636, 0xf18fc52e, 0xd5da93fd, 0xb74744a8, 0xea4d2efb, 0x102081f5, + 0x8830a8de, 0xe4b50ca3, 0x1961b0e8, 0x69652bdc, 0xc66ac797, 0xf4991908, 0x364f7e92, 0x93680ebe, 0x585cdea3, + 0x877124e9, 0x7e8103ab, 0xd4de0976, 0x621e1e43, 0x187417bb, 0x7a4acf39, 0xa42785df, 0x4308fc1c, 0xf083d901, + 0xaf683c17, 0xea7b6941, 0xf4b351c4, 0x6b7704a5, 0xa22a721f, 0x4aa15008, 0x2c5f5fb9, 0x3d6fc18d, 0xbcdb34a4, + 0x975c6788, 0x3327c1e6, 0x00c39a64, 0x80e0281f, 0xb6063151, 0xf402dfda, 0x802759ac, 0x0b504b09, 0x0ce264c5, + 0x1fc6e5b1, 0x987fc8df, 0x03da2acc, 0xe70df798, 0xbf2807bc, 0xf96aede1, 0xafbf81e6, 0x46c7f4be, 0xc91f10e2, + 0xbb43089a, 0xe7e5f545, 0x06985422, 0x648e9c1f, 0xb23d2a9e, 0x0a7beb9f, 0x0279f58c, 0xbd75d063, 0x43596b2a, + 0xb1168cb9, 0x7491c5c1, 0xe58c465a, 0xffe65b23, 0x699fb8ee, 0xcd162ae6, 0x21475203, 0xfb866d4e, 0xebd4c6c0, + 0x88de4263, 0xa2adc8fe, 0xb9ba7ebf, 0x2a26b489, 0x48667a6b, 0x450131c8, 0x097acd7d, 0x920ebfa7, 0x04dce495, + 0x5d1442f5, 0xa9c8f329, 0x0d380f1d, 0xdaaf2f65, 0x278557c8, 0xc4bb85ea, 0xe3c19c4c, 0xdca1f333, 0xed1cbb12, + 0x5179f064, 0xa28d1212, 0x7e9bb4ae, 0xaa774819, 0xfeccb121, 0x266e1f3a, 0x88b4f157, 0xa7c4500a, 0xa33db702, + 0x2457eb56, 0x11d4b787, 0x3f2f8d5f, 0xfee1cace, 0xa949a635, 0xe00305d3, 0xa7ba5fd7, 0xe0388599, 0x6814d908, + 0xfbd77241, 0xd457c0da, 0x4e71249f, 0xe76caded, 0x85dd393c, 0x9a274553, 0x91325114, 0xd2dce7fa, 0xe5c990ed, + 0x386cf93c, 0x4df25139, 0xf2a436bd, 0xeb448b29, 0x8b16c0d2, 0x088b1a50, 0x09a6a063, 0xc3a2fb2d, 0xb2da750e, + 0x84eb4972, 0x63b7f5ce, 0xd014af60, 0xa71d0e32, 0xf42fad55, 0x2eb2005c, 0x15ab1751, 0x8df1995a, 0x31a67f6f, + 0xbf798dc0, 0x96e7eb8b, 0x8f019d5f, 0x87595cab, 0x975e331a, 0xf5eaed47, 0x14b1c3c8, 0xe2163758, 0x9cf16ae8, + 0x46b9423c, 0x6832337e, 0x193158d6, 0xea703e42, 0xb452c8a2, 0x3ffc2cda, 0x2931223d, 0xac93025c, 0x54f9dcc1, + 0x7cd02d82, 0x93e1c042, 0xf718f0e1, 0xe2891d13, 0x2dec21df, 0xfb97c51b, 0xde530f40, 0xf1cb54d4, 0x71f8aa0a, + 0x131f1772, 0xf7f06119, 0xe65c7866, 0x8c58fd11, 0x0dde43d0, 0xeb64b021, 0x11f2eebb, 0x6fe868ba, 0xb98aa6f6, + 0x2f52b4c0, 0x512c0b54, 0xd90a35e7, 0xcd42840b, 0xb506b319, 0xeef9cd76, 0xf810069a, 0x4962d225, 0xe6f7bf0e, + 0x40ce8550, 0x8ae7cedf, 0xb7d5f65f, 0x11d576a8, 0x6f15d2a4, 0xf32f7997, 0xc480bf8d, 0x047228d7, 0x6303b98e, + 0x7ef0acb5, 0x0cb73285, 0x9dbba963, 0xfb12fa7f, 0x415b26a1, 0x28894549, 0xe541c09d, 0xc6980ed2, 0x329fdbd3, + 0x9cd739aa, 0x3bcc9a57, 0x0897a67f, 0xf42f5aa9, 0xeb5ceddc, 0x38f122f7, 0x50963031, 0xc51253f4, 0xd7dd60f1, + 0x740d3c4f, 0xc1193cbf, 0xc4082114, 0x205370ee, 0xccac7efa, 0x0c447dfa, 0x3e31cfb1, 0xa3156e7f, 0xb43054fb, + 0x3bf6c332, 0x82b220c7, 0xe01294a9, 0xc0a96350, 0xf9cba6bc, 0x275b6a4e, 0x9d15e07f, 0xf8718076, 0x9859f91a, + 0xf8e4be88, 0x60a2ffd7, 0xd9c82057, 0x861d3327, 0xd5aa2e76, 0x4cd67ce3, 0xed9f44f9, 0x150624b5, 0x6465eafe, + 0xfb445d05, 0x561504fb, 0xa194dfe0, 0x462e5cab, 0x8dbbd6fe, 0x0483c2a5, 0xd8806c70, 0x3375a869, 0x61fd44a0, + 0x88910961, 0xa6afc3ff, 0xfb09ca2c, 0x8ecad2f7, 0xe205d4dd, 0x424ec6cc, 0xbb4728e0, 0x8f47ecac, 0x507eed98, + 0xaa004e06, 0x90d98a5f, 0x60bb5898, 0xb387652d, 0x0648bd94, 0x5af88552, 0x92990d12, 0x7c6f8233, 0x7c6f6d68, + 0xe7d4c95a, 0x69dd21bd, 0x9f7996dc, 0x4bc72b4e, 0xc781c7d8, 0x7fab882c, 0x6dc3e4b7, 0x4a28937c, 0xc11c44e1, + 0x8275912e, 0xcaa3c3d4, 0x71a532e9, 0x2307e2c0, 0xc9418255, 0xaa6049db, 0xf42ddaff, 0x41c29f1a, 0xc4e29a07, + 0xcc3329ee, 0x6a47dc7a, 0x836c2219, 0xc3670682, 0x8aa39c20, 0x0c91cfdb, 0x53857bd2, 0x92b8c531, 0x8b92a4da, + 0xeb8e26de, 0x06a06ee5, 0xdfff3ff9, 0xba9fe48e, 0xcfc0800a, 0x6bcb78e8, 0x53c29a84, 0x4489614d, 0xaec40acb, + 0x24d8b42e, 0x573a81a5, 0x5d23b9ec, 0xf5855ee2, 0x298f1972, 0xff69deee, 0x069a639c, 0x03b4a161, 0xeddd1902, + 0xcb73e670, 0xcc0a5b23, 0xdf89fd17, 0x1f393e49, 0x93e07093, 0x8d23fcf2, 0x7a4c1359, 0xdcfb9bc0, 0x63dcaf28, + 0x17ba572c, 0x6b467ee5, 0x5aa863d0, 0x6f440628, 0x2c0930cb, 0xd49a9e39, 0xdd8f4cc3, 0xda2290f9, 0x94aed4dc, + 0x14ae529f, 0xec69b9bf, 0xa951b778, 0x1ec980ba, 0xd0e46c83, 0xf07a0ce4, 0x03fc5e37, 0x7897472b, 0x10980c89, + 0xe12e1314, 0x02acecd0, 0x6e930760, 0x28593013, 0x69522563, 0x9ea6ce51, 0x13680744, 0x02e14e09, 0x2f2d6a1f, + 0x35d726e2, 0x3cec7536, 0x1bb33230, 0xb8495fc8, 0xc7ccc80b, 0x7bfee380, 0xae23da1d, 0x09532da7, 0x6ff86e04, + 0xf8a2e4e6, 0xc4fa061f, 0xb8f16174, 0x5a48ae02, 0x20ce1a88, 0x6b9a567f, 0xaad52a4b, 0x2db537f5, 0xe18b5faa, + 0xccb79378, 0x524c872e, 0x434ceebd, 0x1941e83c, 0x6e110e7b, 0x1ee26dfc, 0x0c723886, 0x99719531, 0x8bc8231f, + 0x933fa331, 0xaa8262ad, 0x00bb7f90, 0x582a7bd6, 0xaecbfe12, 0xea8a057e, 0x63287c63, 0xd44fc38c, 0x0785b630, + 0xa3720eaf, 0x022c5846, 0x7454f957, 0x0979b2c3, 0xf95623df, 0xc2687b40, 0xa1fb4005, 0x58397621, 0x16a832df, + 0x59b829a2, 0x862dd99e, 0xd93e25f0, 0x7835f493, 0x46c82150, 0x0a4f9355, 0x48d45336, 0x331e5ee8, 0x6eb93613, + 0x6304099c, 0x07d90e2a, 0xd2e68a16, 0x46a6c031, 0xcf604fb7, 0x8137c187, 0xebf61bfb, 0x0fe89fef, 0x4a18b3a5, + 0xce6f76ca, 0x9ccf6900, 0x8199c17c, 0xbabf6c3a, 0x5bb2c2bb, 0x5db61df9, 0x2c5f17f4, 0xd24a4f6c, 0xe09450e5, + 0x63756ab6, 0xca8fa5fe, 0x07941da8, 0x429fc127, 0xf0a4044c, 0x21bd88a7, 0xba9ad1bc, 0x04bd8260, 0x12f35cf0, + 0xcb2909af, 0x6ebfece9, 0x83daf3af, 0x56c1a647, 0x586c9228, 0x42e25e82, 0x21cf780d, 0x1422bdf2, 0x60786ce1, + 0x4f688cd5, 0x8743c2bd, 0x378ff2ad, 0x80492dac, 0x89e2985e, 0x7d44d626, 0x075a3437, 0x5acd0263, 0x1febef41, + 0x294fe667, 0xa4798e30, 0x5dac2dad, 0xff74b496, 0x01259257, 0xaf9319aa, 0x3de18fcc, 0xcebc6a33, 0xa310c118, + 0x85268f37, 0x65221d2d, 0x3e5e3fd6, 0xa8aaa1ed, 0x3fb049da, 0x68c5fba9, 0xa867524c, 0x19b1dc71, 0x5af14539, + 0xe62a1552, 0x98e2f48d, 0x09521ed0, 0xb913cbb3, 0xb671f205, 0x126ac46b, 0xfb9de310, 0xd918ac3b, 0x4611c377, + 0x5e4d63b2, 0xd91329ef, 0x60d74cb6, 0xa31b041f, 0x0aff1b62, 0x37d5281d, 0xd7a48075, 0x8d7a0826, 0xf4f64fba, + 0x80a0288b, 0xd3af2b66, 0x752916d1, 0xff0c3470, 0xf8a0b170, 0xdaa409c3, 0x72026664, 0xc14becf5, 0xcfc32c18, + 0xc754b9e1, 0xccde9017, 0xeaefdac3, 0x3adede2e, 0xa4dc0164, 0x2070241f, 0xebd5c5cd, 0x4d26a9f2, 0x483c717f, + 0xe19caaa1, 0xf7f6324b, 0xfb13a820, 0xf928d5df, 0xe27df00e, 0x6eeb37f9, 0x77f4713a, 0x78f48360, 0xb6538d7f, + 0x03d633ad, 0xe9969f0c, 0x0bead14f, 0xce0b12b5, 0x1f745e2a, 0x0cb6e819, 0x5cbe77c8, 0x913fbfbc, 0x67eef571, + 0x88abcd01, 0x3bf073cd, 0x0d4eb2b4, 0x7059e7cf, 0x274fb4c5, 0x3804dd44, 0x2c6d09cf, 0x019e55ed, 0x9d74c05d, + 0xe9837eaa, 0xdefa7262, 0x7ca16c02, 0xd53add37, 0x407faa20, 0xaddf8e3c, 0x04fbc6d7, 0xb6822494, 0xc09797bb, + 0x4920cebc, 0xbac0bf66, 0x305fdd17, 0x23e7b3dc, 0x46062cd7, 0xb5db80d3, 0xf20382ad, 0x85b6c4ae, 0x1f5587e9, + 0x59c62d0f, 0x0661009c, 0x84a0acfe, 0x5f2fcb80, 0xc5155e0a, 0x1c426caf, 0xe17f4da4, 0x8f30fcf0, 0x69b59cda, + 0xbcc030f3, 0xdd2de9d3, 0x73119c5b, 0x2cbb45c9, 0x3c59c29b, 0x47430014, 0x3c24444b, 0xae060a67, 0xa589ea7d, + 0xc89a81d5, 0x0e7f777e, 0x0b0d2a1b, 0x0865feec, 0x1f07ce2a, 0x909b171b, 0xdbb80eff, 0x0ee1c39d, 0x7c48e77f, + 0xd159d7a4, 0xb1e82ddd, 0xec7b2d45, 0x201c2ec7, 0xd83bf26d, 0x6a0909e7, 0x3af3c734, 0x478f1b26, 0x9ced46eb, + 0x6a9d5b11, 0x93c6cca5, 0x0340b4ca, 0x80895083, 0x100923f0, 0x2c708914, 0x5858be17, 0xbbf867ef, 0xffb9ee3e, + 0x3df3350d, 0x0796da4e, 0x718999e7, 0x05b5b1cf, 0x317bd705, 0x34dafdb3, 0x48d61656, 0x48f0e46e, 0x2fb5e1ec, + 0xd14d169d, 0xd464bfa0, 0xa3ba032e, 0xb7fdc6de, 0x9172c1c0, 0xb5284754, 0x91b32313, 0xf83200d9, 0x5d31da51, + 0x026c4e13, 0xe407e267, 0xbce47fe0, 0x5027bec6, 0xb7f3da47, 0x0c1f92b9, 0x257f8047, 0x85e2677c, 0xd661621a, + 0xe4b76893, 0x2b0d77f8, 0x29659288, 0x1f6413f5, 0xbf4f1712, 0x3065956f, 0x35f3bbfa, 0x0dacc343, 0x77483a60, + 0xac094695, 0x378b24a4, 0x136a4559, 0x8c69fe60, 0x6c052af1, 0x7844008a, 0x87adc8a8, 0x91d8684f, 0xc1d55f2f, + 0x8a9e6c94, 0x8385b7e6, 0x55e66067, 0x78b4d700, 0xa00ef8ec, 0x0dfb29a2, 0x048e816c, 0x636f808e, 0xa63450df, + 0x906dfb36, 0x7e7c6c9e, 0x8f4f36b6, 0xd7c65b57, 0x66601d8d, 0x760c24aa, 0xd4d66237, 0x6cb498e1, 0x0d2ee682, + 0xb2536927, 0x0b1179ee, 0xb105d041, 0x7488f77a, 0x0bc2d43a, 0xf2495456, 0x8a2371ac, 0x0f6a8707, 0xf093b7cc, + 0x3af2a2a4, 0xd87aeec0, 0x7e5f0d03, 0xff85ab37, 0xc972c91e, 0x2b08673e, 0xe2b2b5b5, 0x55dacc03, 0x8136b88b, + 0x705b1f8a, 0x814836f9, 0x250f68a9, 0x80076e0b, 0x68fcfb00, 0x3b7432d1, 0x52a72a61, 0xc3538068, 0x10949aa4, + 0x5190baf7, 0x4d32cc90, 0xf127f825, 0xfdd885d0, 0x58393345, 0x2ec1996d, 0x143a25ca, 0x261ef85b, 0x736d02b0, + 0x8f37d29d, 0x6cca6c14, 0x7d381131, 0xaa719125, 0xb6268571, 0xce0b3c0d, 0xd118dbfb, 0x43658675, 0x36b800c7, + 0xaa8f3790, 0x99018fb8, 0x7c5e4c86, 0x29a8f245, 0x96d9dede, 0x8d6a95b6, 0x8b9a663d, 0x14e069a5, 0xfcf6eec1, + 0x519f85b7, 0x825b6dfa, 0x39d06a86, 0x1499d3f0, 0xb51b00cb, 0xf28128be, 0x38e3f8bb, 0xb3188a29, 0xb05686f0, + 0xd1d40014, 0xa800881a, 0x5dbba746, 0x0cbbc30d, 0xad97131e, 0xdc2a3af4, 0x536544d5, 0x50c50a45, 0x017ad983, + 0xe22ad6cb, 0xf2441ab4, 0xfedeefea, 0xa4f93d61, 0x8cf930d6, 0x04883c22, 0xb0b85045, 0x3255e16b, 0xc9f7a0f6, + 0x20bd6b05, 0x6f46956b, 0xe7c62c0b, 0x276b7f6e, 0x54658175, 0x9446a14b, 0xbdadbc9e, 0x4def171e, 0x7efe261e, + 0x079fcd88, 0x221bdb3a, 0x4c1566b2, 0x5ebeb22a, 0x591ed37b, 0xd7430506, 0xdfc0473d, 0x631862bc, 0x6bf43353, + 0x05d4ef81, 0x3c60eabe, 0xd708c2a3, 0xfac29726, 0xf46f80bb, 0xb67b5f54, 0xd31e7631, 0xfbf2c53d, 0x9114c560, + 0xaccced11, 0x76aba6b2, 0x32748c94, 0x9165cedd, 0x7c19d320, 0x0f976a8c, 0xb4a7d69e, 0xb2520200, 0xd8b5f5e5, + 0x2dcd2ba0, 0x70c92991, 0x4f775f3b, 0xf6d31c55, 0xa73c2c14, 0xc433d299, 0xc24626f2, 0x84d8ce5c, 0xc2e76feb, + 0xadc5eec0, 0x8f247120, 0x66f9a1df, 0xbcf7b52a, 0xfe216ee5, 0x97399475, 0xf8faa580, 0x897a3375, 0x6fcf5203, + 0xfc11f0b2, 0x63226a64, 0x4effd59f, 0x3e27d2c6, 0xf7f9eed2, 0x01ef4c22, 0x5fc801bd, 0x2cae1212, 0xcfa6627d, + 0x6afecd23, 0x84d85146, 0xbccd543e, 0x7e38647c, 0xae778281, 0x1606c658, 0xd04c5c2c, 0xfbde6fc2, 0xb557a18a, + 0x52c1138b, 0x44f41d69, 0x0a69f585, 0x7a3476fe, 0xe8d2886f, 0x93a66b87, 0x49eb9ecb, 0x12e96bd8, 0x356100ca, + 0x784ddc67, 0x482a3fb2, 0xabbd4912, 0xeef7400b, 0x1e601cd6, 0x0f423f5d, 0xdc69465e, 0x4e1eb5d8, 0xe23044ce, + 0xf4d295a4, 0x7bfd7331, 0xbf79c3bb, 0x592857d8, 0xf50c8060, 0x98847635, 0xcbf44002, 0x84d7d5bb, 0x36ef4c9e, + 0x0cef6c60, 0x108288fd, 0x878a1975, 0xb02889e7, 0x57450c4e, 0x4b8306b8, 0xd587dc55, 0xea036ea2, 0x09983985, + 0x0cc43246, 0x4b1df5fd, 0x4ce9e2df, 0x73df0b68, 0x7ecd58ae, 0x0e60e8df, 0xa5622b10, 0xa9797688, 0x5190287e, + 0xdae0808c, 0x037063b3, 0xe79b64c4, 0xd7214b6a, 0x71364ff0, 0xec18e102, 0x8e058353, 0xca25a385, 0x32b1ef12, + 0xa3d3a06a, 0x58181167, 0x075c69c4, 0x4556f66e, 0x9036237f, 0x35361cec, 0x2b3ab2df, 0xa4a6df65, 0x7f8323c5, + 0x3f4d2892, 0x946cfa32, 0xb690119d, 0x28e2c838, 0x770567d5, 0x18b19fb6, 0x978546b5, 0xe15d7740, 0xbefd1497, + 0x3eec4d1e, 0xbb12f73b, 0x5cd09a4c, 0xe9d5e220, 0x7afd9160, 0xe5f0f112, 0x38a7a995, 0x618005e9, 0xaa0d3bee, + 0x0820a1bb, 0xa102285f, 0x5cc82e6a, 0xa7b458b2, 0x8bda5d0e, 0x5a33fd7e, 0x63427d0f, 0x89466d1d, 0x590bf9e1, + 0xbc1d3e86, 0x55f21f74, 0xf213ec7a, 0x2cc84d85, 0x2f964e03, 0x49a5527f, 0x87012d28, 0xfd6e6e5c, 0xd38c6dfe, + 0x3b525053, 0x401f9922, 0x548495b9, 0x7a6b7e21, 0xecad09ee, 0xd60f90c8, 0xb6594caf, 0x333b8f8e, 0x85d09f67, + 0x14e1a83f, 0x7f121dd4, 0x87c4019b, 0x3019f088, 0xf07248b8, 0xdeaa3476, 0x38826af6, 0x06bf49a7, 0xf0d5a5e6, + 0xda7ecc40, 0xd94dae02, 0xedcdc979, 0xbb6d783d, 0x6420d1a9, 0x46b16f06, 0x54a0e06e, 0x8af55a68, 0xb4e4032e, + 0x646d5b85, 0x288063b5, 0x31ac6050, 0xcd273dc4, 0x62f3c7a1, 0x90824f81, 0x46f99de2, 0x32077f4c, 0xc4ec605d, + 0xd83e1f00, 0xe483630d, 0xe920a8b9, 0x058371e0, 0x849fd7cd, 0x85de7e63, 0xf26bdc93, 0x4b5d7580, 0x3cee1ce2, + 0x01b294b5, 0x4f7160de, 0xe10006ec, 0x252e202c, 0x2cf0b851, 0x72aa23ac, 0xd6637a93, 0x441b822e, 0x87f6ebac, + 0x25715f33, 0x8e9d5893, 0xa3010398, 0x48a06b5c, 0xa49223b0, 0x0be072ac, 0x7d1f2936, 0xe8486ba5, 0xcb0021da, + 0x51fba7a9, 0x5909a5e8, 0xa23dc3d1, 0x03aac1c3, 0x4ce8a646, 0x61e57830, 0xeee875c4, 0x80028be7, 0x7cae4ba8, + 0x510e846b, 0x752f9b01, 0xd3cd0ca9, 0xf076e260, 0x21043d59, 0x36821977, 0x205b297b, 0x92194311, 0xe23fd88b, + 0x23e4f1fc, 0x5a569c04, 0xf8cb6804, 0x51650ef3, 0x310af5b5, 0x363414ff, 0x6d0248d8, 0xbd8a6c8f, 0x1b8074ff, + 0xfcca6872, 0x9dc25e49, 0x34aec5b5, 0x2f1605d1, 0x1e22d48e, 0x85969fc1, 0x7361adc1, 0x460e426d, 0xf54063a5, + 0x98b748b7, 0x2ddef5f7, 0x0d3ee1d7, 0x150248db, 0xc3a56193, 0x42389f95, 0x8ac87fb5, 0x3cdaf87f, 0x6c7d6fc2, + 0x7db2e354, 0xc8cf5bd9, 0xd3f1d9b5, 0xc7441c35, 0x9d2b34b7, 0x1ce70ecf, 0x5eba04af, 0xa81c4f34, 0xf836b7e1, + 0x83014b7c, 0xadac6a1e, 0x7ee36574, 0xf548ee46, 0x58e41fff, 0xc82335a5, 0xec570485, 0x38351bea, 0x8b83b71d, + 0x7d43a118, 0x4ee57a10, 0x958c83fe, 0x8998488f, 0x19e0250e, 0x794ec03a, 0x96e94af9, 0xd936f9cb, 0x875aebf6, + 0xf16ff41e, 0x7e6d5bcb, 0xf4d69601, 0x8792c0a6, 0xc060c00b, 0xb750da38, 0xf492e8a4, 0xad9b2e48, 0x87d748c3, + 0x40b8fcb4, 0xea974178, 0xf6524d1b, 0x64802533, 0x9b370319, 0x025a96b9, 0xa83353a5, 0x671c06f1, 0x9d54c844, + 0x6f5f903e, 0xd154775d, 0xe0ba1dc5, 0x61412481, 0xc851d00a, 0x470510ca, 0xa72f06eb, 0x99f6688f, 0x70ef0e71, + 0x390b0ee2, 0xe2d352f6, 0xbbcc13d0, 0x6d769e74, 0x7c68cd08, 0xb0315eff, 0x9b541f0f, 0xea5db1e7, 0x558e114a, + 0x057fd038, 0x283d8a1b, 0x330e3d81, 0x1eeebf5c, 0x98bbbbd6, 0x81bb36f7, 0x06fefe9a, 0x903ab3c3, 0xae0e12f7, + 0x40015f17, 0x79880148, 0x7861daa1, 0x17b7c581, 0xcd28e26f, 0x1d89745f, 0x6cd3c2de, 0x88b8db48, 0x70d7c9aa, + 0xcfcef5d9, 0x71a1f127, 0x3b99f7b1, 0x8eb2c9b4, 0x0cb617f1, 0x068be4fe, 0xb8b7f5cb, 0xe1126f2f, 0x07b8aa10, + 0x45a0ac14, 0x6189e4cb, 0x8c788598, 0xa4915e24, 0xd71e41f1, 0xc1890029, 0x1fda81a8, 0xcf5ca094, 0x32e87fb4, + 0x750690df, 0xdb7f3f9f, 0xe1f785af, 0x1d0ff36f, 0x217bf389, 0x358e69ae, 0x518b7084, 0x504eabb9, 0xc62cf1f7, + 0x1e269ed8, 0xffb83176, 0xae2d1109, 0xdc4b722f, 0xb2d5ab7f, 0xb0a5d653, 0x9a639286, 0x2e509f1b, 0x145dd7c2, + 0x9f967e99, 0x115a7b6c, 0x13af3af9, 0xb3f60137, 0x8fbee1c5, 0xe892fe49, 0x16080177, 0x082e3d6e, 0xf24d247a, + 0xb41dbfda, 0x04587fa9, 0x5ea69a78, 0xd5af8c5d, 0x0f4563ae, 0x5f95f4b6, 0x750d6f0a, 0xdf69d352, 0x69379b41, + 0xf8331af4, 0xaac43fd6, 0xa8beccc4, 0x01808386, 0xdff969ad, 0x8403ca2e, 0x848581e1, 0x44f9c982, 0x7767f130, + 0x40e51b1f, 0x21e197ed, 0x038b6ee7, 0x8c2060ad, 0x75506653, 0xd347d0f9, 0x05959dbc, 0x9a22ecf4, 0xdb7fd43a, + 0xcc6c514a, 0x69d28558, 0x228a94e2, 0x26c8b11a, 0x8a62b8a0, 0xa3016c57, 0xc9717167, 0x395e1138, 0x6a3ea39c, + 0xb74a53e2, 0xd2797731, 0x99f93337, 0xfbe76f0b, 0x256102fa, 0x3b62f089, 0x6a6a75cb, 0xfcd95f2f, 0x5c2995a1, + 0xcd32a4fa, 0xcd06082e, 0x305c61b9, 0xd64b7444, 0x06e03e18, 0xbbdf92b7, 0xa2a6eda6, 0xcb233b88, 0x31ab3a43, + 0x25c651c3, 0xbc5b88e5, 0x3bc65517, 0xe483aad6, 0x7f01437e, 0xd40b297f, 0x978c4b3c, 0xf292e138, 0x2d677a58, + 0x6d6208bb, 0x1106e726, 0x127956fc, 0x5551a572, 0x470d3d50, 0x3aa08bdb, 0xc4bd80c3, 0x1b7227da, 0xd1b37bdc, + 0x9598d9b3, 0x067b9c93, 0x428f8c90, 0x7fd41780, 0x6eb39f79, 0x8b7fad9a, 0x9bedb4af, 0x8965c99b, 0x6ea78f00, + 0x9e7b6fd4, 0xc1e53e34, 0xd3206d4f, 0xcd07d346, 0x856b612d, 0xb46586fa, 0x03673cab, 0xc7bfd1db, 0xf3785cf7, + 0xa93ec64c, 0xb31feeea, 0x0ec809ea, 0xa823e471, 0x8449beb8, 0xb12602cc, 0xfc18d2d1, 0xc685da49, 0xe91fc3c1, + 0xb68d4f1a, 0x617f9edb, 0x04ac0967, 0xe2946115, 0x7be0e2d6, 0x883effb2, 0xa9f364ac, 0x9914d915, 0x400e4c23, + 0x6b7e6267, 0x24c1c2e2, 0x1d159fb1, 0x0a06c131, 0xdb7d63b0, 0x7693c667, 0xa2b5f01d, 0xa53ee33a, 0xe53c4951, + 0x952c89c1, 0x5181ea91, 0x6901ba80, 0x70e476cf, 0xbfd24216, 0xffa44c8d, 0x34f5e5ba, 0x3773d0fa, 0x3474132c, + 0xb1e51072, 0x67b97fe5, 0x37950fa6, 0x1860a3f3, 0xea3a8af0, 0x75f71f1a, 0xab076c5e, 0xb0670685, 0x10f68e9a, + 0x1ef953d8, 0xe544dc82, 0x93017c7b, 0x51fa2e4b, 0x82e50123, 0xd237ab71, 0xc943828d, 0xc5667f2d, 0x8807e093, + 0x7b9bac41, 0x66418a94, 0xa30286f7, 0x0d41f238, 0xd48bbe6b, 0x263207d5, 0xedb6d1d5, 0x4b1b3b45, 0xaae4b4b0, + 0xa7a69f02, 0x50084be0, 0x5d4edc8a, 0x6e6c4a7b, 0x36c84a4f, 0x4aeba7b4, 0xf44a88e4, 0x039bc4cb, 0xc2607fe8, + 0x6e923dea, 0x39b42485, 0xf02b7689, 0xd57ce68e, 0xbda195bb, 0xe60448ef, 0xe0765031, 0x4be0c274, 0x78f2523c, + 0x7f939b1a, 0xa6039f8c, 0xbbdc553f, 0x9cffee31, 0x281e1b33, 0xa1047052, 0xc77db9e3, 0x0ef75be7, 0x2b586534, + 0xdbb3d1aa, 0xe548018b, 0x7c1c18e8, 0xa24d3d2d, 0xfc710948, 0x465dda1d, 0xdf744bbb, 0xfc5f32ad, 0xfed3455f, + 0x5a979685, 0xe63319cc, 0x87c390ea, 0xa5fa6331, 0x71255515, 0xf4ada029, 0x24792627, 0x3ee09ed5, 0x58368ab4, + 0xc0060067, 0x31af7e8e, 0x4633ce3e, 0xc442800c, 0xa32c9970, 0x96c3e8d3, 0x31b44dd8, 0xabf1f509, 0x4ed776ed, + 0xeac4cb3e, 0xd02fa9eb, 0x8a0e4c1a, 0xe4e6c660, 0x61550f78, 0x7f19a611, 0x2cd0ca2f, 0x7a85ae20, 0xb852c593, + 0x867f9d5e, 0xd7e4e5f0, 0xf488fcdc, 0x7e9689e7, 0x1093c3a1, 0xc679d1cb, 0x120d91cb, 0x08c437e5, 0x7c06cc01, + 0xf46ce461, 0xa7b3e95c, 0x16f53848, 0xcd7612c1, 0x2a061cf3, 0x145d978e, 0x314f72f6, 0xb105506e, 0xae78720b, + 0x9eff401a, 0xb76b9c76, 0xed68f42f, 0x382a7365, 0x3535d7c9, 0x92ab52f6, 0x3067c06d, 0xf3189b0b, 0x8b580269, + 0xa9ce9f1e, 0x6e661b58, 0xd32f2319, 0x519479ed, 0x5ca4e366, 0x86e0cdea, 0x8813acfd, 0x554a5da0, 0x4781f81c, + 0x436c160c, 0x94e5478d, 0x514f9eb9, 0x84ad36ed, 0xa8ab6592, 0xe4d3f65c, 0x5a510844, 0x49472fd4, 0xd9910eda, + 0x4f217a46, 0x578ba79d, 0xaf049a71, 0x08b06978, 0x407dbd93, 0xa28d9be3, 0x3999f724, 0x59d86fea, 0x631d702b, + 0x942e2949, 0x28c3717d, 0xde2b755a, 0xea818704, 0xc2046862, 0xc7012547, 0x3d041925, 0x6d519553, 0xa342b99e, + 0xa09547e4, 0x67924cdd, 0x23b57d93, 0x9e9d4d86, 0xe0ab129f, 0x768031db, 0x750453ca, 0x4207301a, 0xf3f29860, + 0x9c2cad7e, 0xfa207fa4, 0x66142b9e, 0xcf27debf, 0x77cf5b7b, 0xc0f45c13, 0xa17f0f1a, 0xafe5382a, 0x7145fe10, + 0x73418e1e, 0xd8b18353, 0x67ccd197, 0xb7fd27e7, 0x991a58f1, 0x5c157c78, 0x005b99f7, 0x23507646, 0xbdd4d3b6, + 0x8b78a335, 0x0f10fc85, 0xa01ae37e, 0xf48d9ff2, 0xe3f37ea6, 0xd926b28b, 0x13ec9fca, 0xfcf5bff3, 0x5ae881c6, + 0xf0aba87e, 0xa6f33989, 0x93d126c9, 0x62f6bd7d, 0xa77e85a4, 0x842a3945, 0x08a34a7b, 0x8c62e673, 0x857bc63b, + 0xb66a1462, 0x2cfcf190, 0xcf53ebfb, 0x9265c63b, 0xf716b369, 0x7979dc53, 0x8fdba868, 0xb36a523a, 0x456de5fa, + 0x865edceb, 0x948cbfb3, 0x28d52372, 0xe78513fa, 0xf44b0ac4, 0x0eee1e25, 0x38ae5da7, 0x617bd72b, 0x53d5daab, + 0x4411e0ae, 0x283555b3, 0xce18fb4f, 0xcb1a11b7, 0x58524b22, 0x1782c038, 0xcc7d0e7e, 0x96f758ca, 0xb2469dc3, + 0x73d69d5a, 0x4fa31c02, 0x828cfedf, 0x606dc07f, 0x813424ed, 0xcdfd0a42, 0x68fbbd3a, 0x7c9fe1c0, 0x5749f4e4, + 0x153cb91a, 0x58e670a2, 0x33e84d0d, 0xc59c6ea6, 0xcaf0e646, 0xf146e728, 0xa4e27062, 0x0e3a927a, 0x627f15d9, + 0xe483ba2a, 0xcaf56195, 0x6bd92f4e, 0x670164f3, 0x4b2f5f9e, 0x3c2ee6a5, 0xc1244cb4, 0xc9038962, 0x22977629, + 0xef43e91b, 0x5ec9a1a1, 0x1c95fd84, 0xfd5f3aba, 0xd4ee1d32, 0x9d13a190, 0x2380b6d6, 0xc7a80c9b, 0xe58761f9, + 0xd7312631, 0xc931b2aa, 0x0a3cf041, 0x4c23c8d9, 0x0940d9e6, 0x49fbdea2, 0xb38de55b, 0xb1f283f0, 0x16f67178, + 0xb5b6cf1b, 0x8d068a1f, 0x01334d1a, 0x0c4aa176, 0x6c364f3b, 0x0467d478, 0x136fccce, 0x173bb030, 0xf58564a9, + 0xe409f657, 0x7c8258e1, 0x1ab44fbe, 0xe5bc9717, 0xc3afd236, 0xd14fa621, 0x096b734d, 0x2857401f, 0xa68e5346, + 0x01160db8, 0xfa9d834c, 0x592bc396, 0x122c8544, 0x3af9411e, 0x85b3c6f4, 0x53115b46, 0xfaada0f0, 0xfdeb317e, + 0x0f139c64, 0xc4ddc389, 0xbf35edce, 0x3c9ef28f, 0x285541f6, 0xa7caca54, 0x8efed880, 0x2f118fe4, 0x09111257, + 0x4ee9f1bf, 0x6e01df30, 0x9df9691d, 0x3cf0cc97, 0x55f1bd30, 0x31bd7d1a, 0xf842955b, 0xc3d8a02a, 0x37af067d, + 0x0257de93, 0xbb37ac26, 0x4c6c1a3c, 0xa7b1557e, 0x8692e524, 0x4f223bd6, 0xf97c710f, 0xc3dd2672, 0x80c3b901, + 0xb9e4d9d9, 0x7f247cfc, 0x5ab2488b, 0x67fcaf41, 0xb075ab0f, 0x9b01208e, 0x84a1c632, 0xf4d7a5ad, 0x02239f8c, + 0x796eba16, 0x7c3e6afa, 0x167f8a7b, 0x7e40f9b8, 0x572ccab6, 0x89df2643, 0x33c33f34, 0xca196c28, 0x4786bc81, + 0x34217350, 0x8eef485b, 0xf1820a9a, 0xd9f069b2, 0x7bb58c46, 0x4c0b6f37, 0xdd9af6d9, 0xd128f2d0, 0x29af5cfe, + 0xf1c1b306, 0xae2b6a75, 0x8e095972, 0x7a4d8c02, 0x1db588fd, 0x53ac1f75, 0x409feb84, 0x2c47a328, 0xd266b53c, + 0x3165083c, 0x84e53977, 0xbaccf290, 0xe7c0bc8b, 0x2e199491, 0xed5e70ec, 0xe633cc42, 0xf0d87bd2, 0x39ec02cd, + 0x49b5219a, 0x07c73a2f, 0xb88ddae5, 0x14b1b092, 0xe8438ae4, 0xb71546af, 0xd3d2d015, 0x5c39a748, 0x73820b8c, + 0x2a292dcd, 0x2651b7ef, 0x00751ed8, 0xec9cc06a, 0x0d6ed278, 0x24f7c462, 0x24b2ead4, 0x0e77bfd7, 0xa8343000, + 0x538425e2, 0x4c1fff49, 0xe9bb1d5e, 0x017f6a98, 0xf38332cc, 0x23ceb1ab, 0x4aacb687, 0xcd00adf5, 0xb37f87c9, + 0x330978d7, 0x8b2a212d, 0x5c50cace, 0xa925e653, 0x8d392064, 0x01cd1808, 0xb5af7a1d, 0x131d6dde, 0xddf7c374, + 0x9c3abee9, 0xb503a613, 0xcad00e96, 0xd4de71b1, 0x7b7c080c, 0xe85d235f, 0x57a73a6d, 0x616c622b, 0x32b46e6e, + 0x93b45604, 0x90f3f356, 0x5fda508d, 0xdb1e9201, 0x3f86d59d, 0x8994d7b1, 0xab0ba504, 0x1c5b0264, 0x558e9954, + 0xa0eb6afc, 0x8369f8ea, 0x70f39471, 0x8fdabbf2, 0x8667befa, 0x54db7b04, 0xf287c107, 0x06035528, 0xa110dff6, + 0xc3a1718c, 0xd40fb86e, 0x981bab53, 0x4584812b, 0x9a3d8646, 0x07762554, 0x0286b3e4, 0xe5e7aefe, 0xf602b26c, + 0x59b2fb61, 0x657af450, 0x4a761850, 0x9afb8ddf, 0xf62cb4d8, 0xa5aae117, 0x5bdd0610, 0xfa78a8d6, 0xd75e11be, + 0xe5622f81, 0x8b6ecc80, 0x7c868a27, 0x594d6777, 0xdc97fdfd, 0x1b5fa83b, 0x2ea3a6ed, 0x264c3d68, 0xbd63bad6, + 0x5b804321, 0x68d55144, 0x2641551d, 0x933a8b8a, 0x84cb4da2, 0x87ba101a, 0x01821b6f, 0x5e55537d, 0x1418fea6, + 0x27b77e7d, 0x4705b75f, 0x1952b9b1, 0x57c2440d, 0xe43b0192, 0x20ece09a, 0x338f9073, 0xef55e858, 0xaa09f54a, + 0x941a0bfa, 0x0ada9333, 0xbe067665, 0x3b6be168, 0x7199ac40, 0x41495547, 0x96c52f87, 0x3ab9132e, 0x5cf777f0, + 0xea921fa0, 0x19f24b50, 0x4b73f090, 0x8de190ee, 0x47410cd1, 0x6c75f1a6, 0x258472f7, 0x0c0ee0bc, 0x09aadc2b, + 0xbf341964, 0xc20df1f3, 0x409bd417, 0x4892deca, 0x3908503e, 0x454f66ff, 0xee42cf4e, 0x9b3dac8b, 0x603fa102, + 0x1ebc49fa, 0x0f89e939, 0x3105d7d1, 0xb4903c93, 0xd597b439, 0x678fd683, 0x26bb1473, 0x53193f3a, 0xebac16dd, + 0x4b1d5b72, 0x79c4bbe6, 0x321a4761, 0xcf4c377f, 0xc0e6cb7d, 0x071a3633, 0xb3da0995, 0x623a3522, 0xcddc4401, + 0x789998f6, 0xfbca42c0, 0xc03f4cee, 0xe16760ac, 0x05903ece, 0x244d277d, 0x174d17e9, 0x457b05d8, 0xa3c30bb9, + 0x062d7c12, 0x7c58d8fa, 0xeea772fc, 0x46de90c0, 0x30d27340, 0xf4c72531, 0xac82fdc5, 0x73d93085, 0xdf54a7ab, + 0x5d43b19f, 0xcc442e3c, 0xf982de9e, 0x620d088b, 0x17f18b9e, 0xf2911874, 0x91de6b44, 0x89618bc3, 0x9b516230, + 0x25c3d19e, 0xd0f3e8ac, 0xdbe1282b, 0xe632b8e7, 0xb632a027, 0xc1119442, 0x285a340e, 0x9bd7552d, 0xa2c805f4, + 0xda4b34b2, 0xf4661c38, 0x08a53968, 0x1cafbfbc, 0x13654011, 0xace0d6f9, 0xe56cb7e9, 0x26aa2e7e, 0xcf2f95c3, + 0x09a19669, 0x94247721, 0xcc656e35, 0x9e89d606, 0x703c5c40, 0x6693805b, 0x1129adae, 0xb2ca46c8, 0xf5c75099, + 0x53e05e05, 0xb56f6ace, 0x3f7a3dde, 0xb54b632b, 0x887177a8, 0xbdb8fb14, 0xfde3a594, 0xcd15da1e, 0x1edabc0b, + 0x5a6fa9df, 0x5967b126, 0x6217deb0, 0xcc96c71c, 0x408250b4, 0x5d5a657c, 0xb468f81b, 0xdef4b53b, 0x22a19d88, + 0xd3528e47, 0x673bb59d, 0x3b457ecd, 0x31b0f33a, 0x2939e18a, 0xd7d99479, 0x4e8ee09f, 0x509a84b1, 0x9e833b36, + 0xd051937e, 0x60b5d18b, 0x75dfb116, 0x28f10314, 0x176dc224, 0x2996561e, 0x13c91e90, 0x5ea7f0b0, 0xc0aa19ea, + 0x380abb9c, 0x9e22fcbf, 0x4011fad0, 0xd6e00e79, 0x70bcafb8, 0x8d1bd31b, 0x25791f89, 0xde85ce10, 0x6389bfa6, + 0x0f4d1946, 0x72f4e339, 0x305e6833, 0x425562dc, 0xfb7d02b7, 0x33885660, 0x6c88001a, 0x81a6e79e, 0x461fd9d1, + 0x88948242, 0xec704d58, 0x6e132a04, 0xbca349c2, 0x6f47e4c8, 0xe874f5ac, 0xb4664127, 0x9423317f, 0x777b5cd6, + 0x31752d8b, 0x9d223779, 0x44f57276, 0x8b490543, 0x69ec3bf8, 0x9e692c61, 0x26869112, 0x2c1f1e10, 0x8e081214, + 0x583fc638, 0x169c886d, 0x630fac21, 0x67c20b5f, 0xf3015b69, 0x02029471, 0xe33a48c9, 0x65f22ecd, 0x5cbee411, + 0x12753442, 0x2a19a8a2, 0x76d5f5a2, 0x22579557, 0xcb8251bf, 0x811e3c4a, 0x5fadbd67, 0x9f8f7157, 0x9536e530, + 0x86459371, 0x50992fd8, 0xcaeacb81, 0xb3316541, 0x2d2b7dde, 0x465d3af7, 0x0e758f01, 0x7fb5f0ec, 0x98b67ae3, + 0xee09e698, 0xb07ea89c, 0x253a91aa, 0x9e46b409, 0x8f34c8e2, 0x339eb92f, 0x8e77203c, 0x024c8e15, 0x2cafccce, + 0xd6cd8430, 0xa60d3794, 0xdb323d27, 0x950dce2c, 0x98bd6041, 0xcedd6725, 0x84fa6964, 0xda4620b8, 0xe8664bc5, + 0x6ed8ed99, 0xf94c392a, 0x742f6be2, 0x5576d97d, 0x80480c9b, 0x12fab1d2, 0x0a044c74, 0x4835f3ce, 0x0580e89d, + 0x176fa7df, 0x962a4d03, 0xace0d482, 0xd45f3ef4, 0x965689a4, 0xe81ca552, 0xe3a40df3, 0xa5970adb, 0xf6e5de1c, + 0x4ce3466c, 0x4488d744, 0xae925106, 0xbe508221, 0xee59f1c6, 0xb8429039, 0xb7a35154, 0xe237c2db, 0x9a0e77f7, + 0xc05311d7, 0x1d471df2, 0x21186698, 0x57159aee, 0x815bb140, 0x244948be, 0x2e8b5c1b, 0xbb5dfec5, 0x9abc6777, + 0x6955958f, 0x5250d407, 0x165c64db, 0x3df2a1af, 0x0d8611d9, 0xb9a0e2cd, 0xe83ee86d, 0xd0d2f181, 0x7c8c113e, + 0xcb1a3bec, 0x6b74a69d, 0x7b6dde8d, 0x8a725d31, 0x3a6b8f48, 0x597d7073, 0x07ee8341, 0x3ae14f59, 0x8ed8b3bd, + 0x82f3deee, 0x1781d9f6, 0x527f9c7f, 0x90eb4eef, 0x4c6db58a, 0x51f0fd8b, 0x35b9e48c, 0x13ed19cb, 0xc66ad3c9, + 0x2c4ba399, 0xed151b1d, 0xbf3c5803, 0x7dca4c97, 0xa2e1d93d, 0x45dfdde7, 0xdcd25e1b, 0x74edfd65, 0x646d9a59, + 0xe081faba, 0x2860feb7, 0x962166cb, 0x35e44347, 0x1aee8dce, 0x2aa41206, 0x4c12d94d, 0x6074f786, 0x2cbd4b34, + 0x9984f08d, 0xbcdc48a6, 0xe5a05ab5, 0xe63b4b5d, 0x60da863f, 0x750692eb, 0x0ba1794d, 0x73be2d85, 0x711127cc, + 0x01369273, 0x98d56b64, 0x656c12d2, 0x4e7e8c92, 0x7e90a1c5, 0x461ae9d5, 0xff4caf3f, 0x043cfc0f, 0x74484212, + 0x440dc1ba, 0xeaf1e22a, 0x3021e76a, 0x361b7edb, 0x5e9e918a, 0xde5b6190, 0x3de1692a, 0x8c1267be, 0xe0294395, + 0xd20c5fed, 0x0a4faefd, 0x184a5ab2, 0x8ff60a10, 0x7890efd4, 0x26a6ba36, 0x20460f40, 0x5825ef27, 0x60f8f4f8, + 0xf449e2f7, 0x9374aad3, 0x980acd35, 0xebcb9f0f, 0x1cd94e15, 0x2458be57, 0xc81d69f0, 0x6a816678, 0xb14d72ea, + 0xa60352e5, 0x972b5c82, 0x12755697, 0xcd778379, 0x624c7b87, 0x2021a12e, 0xf3710c1e, 0x6db7a5cd, 0x440b7344, + 0x24714d56, 0x444ecabb, 0x5da6d87f, 0x8462bb83, 0x0007f8e9, 0x176acff1, 0xccc08de4, 0x6c4c5afa, 0xa155d80e, + 0xaa01011b, 0xc55c4829, 0x6dc05755, 0xa20b5cbb, 0x52052b90, 0x97454f4f, 0xb00e8bbe, 0x301456c3, 0xf20ad606, + 0xb1038346, 0x10c545bf, 0x46327d15, 0x5c5ccf5f, 0x590e9909, 0x999b41ca, 0x05157afb, 0x3ce4bb9d, 0x2d4485fa, + 0x2e05f9a5, 0x648de31a, 0x1a629533, 0xf04e9483, 0xe265bf26, 0x6ea30972, 0x7895a878, 0x0d23682e, 0x8bb11c05, + 0x16c6567c, 0x4661478d, 0xf5a31a73, 0xbdfbabd5, 0x4dfc4eb3, 0x2632cdbb, 0x62b7cec3, 0x03cb8915, 0x280e00c5, + 0xe01896f1, 0xfd1fb17f, 0xc006e669, 0xa0f76f63, 0x3af3b1f2, 0x4b7e1d03, 0xa0bbc651, 0x9292edf9, 0x9b919a23, + 0x2eaaa7d7, 0x2cb41d73, 0xb3c5bafd, 0x3c936903, 0xc9082470, 0x7856f589, 0x8f8aa38c, 0xbbc507d0, 0x9d82fdb0, + 0xa1e516e0, 0xb2f68707, 0xf1cd9c7e, 0x9ba21140, 0x5ad561f5, 0xbc7afb6c, 0x143ad4ed, 0xb33c861c, 0xbaef4795, + 0xc329aa00, 0x1e76d8ab, 0x3ceffeea, 0x9bdb0402, 0xa0aed4fb, 0xcedc1000, 0xb0b74d57, 0xb085b76f, 0x6d15fb4c, + 0x1755b74c, 0x3d168b79, 0x9faea450, 0x19d21f22, 0xb19fdc9b, 0xe79bc48f, 0x00efd6dc, 0x077ab404, 0x17b99add, + 0xe5ccb75d, 0xcaa820d1, 0xb29b6bb9, 0x6ccf3cf5, 0x36db676b, 0x76eb6b19, 0x934bdbef, 0xe3ab2764, 0x61d3ef7c, + 0x6c61e3d8, 0x8a181597, 0xd80c2dab, 0x1598e2c3, 0x9bcd10c5, 0x06dcc55c, 0xee54af61, 0x3cc0c39d, 0x33ab784f, + 0x8e41fa69, 0x7b889276, 0xd5e38bcd, 0x430f2f90, 0x6d63771a, 0x1df8bd38, 0x91a03147, 0x719325d5, 0x19bf575a, + 0xcaae4a80, 0x14d807bd, 0x0eb098d9, 0x91912b11, 0x0da83f09, 0x6e0287a5, 0x46fecd79, 0x979460ba, 0x9ea019db, + 0x7a6e057a, 0x535b9d77, 0x5b54f81e, 0xf1fa49e6, 0x40248723, 0x12bc0e5e, 0x61772e0c, 0xa318282e, 0x13f515de, + 0xca07628e, 0x24850aaa, 0x303487b3, 0x1d6ca7a6, 0xb0eb6bf0, 0x11c65350, 0x9a42708d, 0x8f5605c9, 0x6380ce59, + 0x23f1b53c, 0x3ecd3216, 0x0f285322, 0xa0b33a0f, 0x76fc1c94, 0xe277a51e, 0x3f08b5b6, 0x62804125, 0xf68ac117, + 0xc75ab118, 0x754cef43, 0xfca1f1df, 0x90cb86f9, 0x24ff3ff0, 0x6df1a33e, 0xe97e38b3, 0x2affc604, 0x9cc5e628, + 0x88cc522a, 0x66cc548f, 0xce3c8b26, 0xde6f1a7b, 0xdf2dafdd, 0x986a1c5c, 0x47d65748, 0xa217ed6b, 0xcb0d7297, + 0x87ed48b9, 0x4dacbc84, 0xd33f738c, 0xcdded94b, 0xe3bb329f, 0x6ebbc480, 0x4cb2d915, 0xf28ebdd6, 0xad5cb7b6, + 0x2082b882, 0xecb92fb0, 0xb12ff770, 0x446229ea, 0xe3ff1900, 0x49178def, 0x4425b351, 0xab7646f3, 0xcdf362c3, + 0xedd4a5d6, 0x967fac0a, 0x27d0df93, 0x75e60bb4, 0xed84b8cc, 0x6460310c, 0x0f78e4f0, 0xdca18731, 0x5076590c, + 0x9c34ab10, 0x18ecf385, 0x7e6760e0, 0xa7a0d5e5, 0xa8761263, 0xfb118a8a, 0x64713d70, 0x46a144fa, 0x26547700, + 0x2c24dbdf, 0xbf0d2913, 0x5db8e63b, 0xe8217a2e, 0xfcf562cd, 0xba570fae, 0x22d8380c, 0x03d57573, 0x6d1da3df, + 0x609a9954, 0x859b2423, 0x2bbef993, 0xd81061ff, 0x9368f3dc, 0x6db5cc6d, 0xd7f72d47, 0xe4a033f3, 0x24866557, + 0x2d1f687a, 0x4ab70a6d, 0x3005e33c, 0x564b5cb6, 0xf2c2bf93, 0xb2bc6896, 0xae9d9b03, 0xdfca1f34, 0xd8656e71, + 0x85297627, 0xaad00f34, 0x76b2738a, 0x721ea89c, 0x2a53c2a0, 0x3254f88a, 0x508db7a9, 0xabb2ed64, 0xd40cd526, + 0x87ef5dc0, 0x71380ecb, 0x06157303, 0xae3398bf, 0x898a8d91, 0x0228a031, 0x88cfeb8c, 0x6a84dede, 0x613ad142, + 0xb6c43f2b, 0x39605a77, 0x754cac3b, 0x3e364db1, 0xbbeec950, 0x27b13259, 0xcd286d03, 0xcafa7582, 0xc8f8ac99, + 0x43d70fc9, 0x9b8324aa, 0x759585ad, 0xdbf68484, 0x25359dc8, 0x5b00b79f, 0xb90e4b33, 0xe8571ff8, 0xd0c10d34, + 0xd1a75175, 0x33ffb719, 0xcc7fac98, 0x5f852eec, 0x98c75f79, 0x69512dfc, 0x55ba8fc0, 0xd6a0a669, 0x8c472547, + 0x7eb0e9ff, 0x37357cef, 0xd5327542, 0x48beb72c, 0x4a42daac, 0x4c8587f7, 0x8ed5f84d, 0xb97f1e87, 0xbd439146, + 0xcbc779c5, 0x00031dc2, 0x30379905, 0xb21b87b3, 0xd048dba7, 0x74c832f5, 0xa3182e86, 0x873676d7, 0xe69e914b, + 0xd7aad6c2, 0xc8d11896, 0xe82283a7, 0x75983764, 0x13379a84, 0xc2b11e79, 0xf5356764, 0xeebb197f, 0xf5f0fec0, + 0xbe976883, 0x6d5ac1a2, 0x3a231576, 0x7d8374d2, 0x10583b1f, 0x2fca0f49, 0x775f52fa, 0xa60495a9, 0xdce2f93e, + 0x7876dd25, 0x38c0dcc3, 0x6df5db76, 0xf88c103c, 0xe413c821, 0x319288e1, 0xeafc5f11, 0x6708e2b2, 0x621961c2, + 0xd0904458, 0x617a9c26, 0x98e4d9f4, 0xd1fdcc4c, 0x244a8822, 0x271737a3, 0x6fbb810c, 0x4253e589, 0x095e265a, + 0xfe511c96, 0x06e20a22, 0xd53e6c22, 0x552056f4, 0x13594bb4, 0xf154f763, 0x99cafa82, 0x92f2132d, 0xbce542b0, + 0x6ba43a58, 0x635ac5c3, 0x0a9a49c9, 0x86d4a676, 0x597d2a20, 0x542ae4c5, 0x4c839de4, 0x8a27c88e, 0x15805b1d, + 0xfb1c7498, 0x970e0c33, 0x5ba4a369, 0xaa0d96a7, 0x0b8e48dd, 0xa4aef733, 0x16a6e4c3, 0x468520aa, 0x4aca042a, + 0x2f83b45b, 0x802e709d, 0xe6ec6571, 0x9bab2bad, 0xba994f39, 0xc3c557e3, 0xfce1c4ee, 0xe9e7ebdc, 0x71462dff, + 0xc63f23d1, 0xcd5ed217, 0x2bbd4002, 0x1f07b4c1, 0x0fbc4bf9, 0xd58d8fe8, 0x71a9778a, 0xce3e26c8, 0xab1397ae, + 0xb0c1a9e2, 0x156b564b, 0x900bfa36, 0x4dfdddda, 0xa958cb4d, 0x2365cd81, 0x3103786b, 0x61490258, 0xf6d537b8, + 0x02565fdb, 0x1a3d38a5, 0xc23c06f5, 0x9a8f27f9, 0x5d3e1b27, 0x70b37147, 0x49b69dbb, 0xe14cf3b7, 0x3287d2b5, + 0x03f4d327, 0xe913c4c2, 0xc139f708, 0x4dbef475, 0x3544c70e, 0xe4b66f7f, 0x44c49a49, 0x7e8d5633, 0x293a7b95, + 0xef871f9e, 0x8c9bdda5, 0x88ccf785, 0xa4cf6690, 0x43c002d3, 0xec841fdd, 0xba4a840f, 0x8c6e6c76, 0xf61fc4fa, + 0xc7712768, 0x0638edb0, 0x54dd51ab, 0x74414bca, 0x107ea273, 0xd51db38c, 0x1b3490e7, 0x66ecad84, 0xda0e3da1, + 0xd91ac09f, 0xa2b173bd, 0x1cb2db62, 0xe5dc63a4, 0x36ded4de, 0xa0c93984, 0x8f7dfe2e, 0x83f74028, 0xe275b9f9, + 0x30116f4f, 0xab58a420, 0x93870d8e, 0x2f40447a, 0x212a6f00, 0x9a284142, 0x84a8a1db, 0x92c9075b, 0x8965c24d, + 0x10c13355, 0x91392f30, 0x34ca2fee, 0xd2388327, 0x88d12677, 0xf6ba0151, 0x101a4bff, 0x3cd949df, 0x8259f320, + 0xed58b42b, 0x0928a2a2, 0x2d3a4147, 0xe879a42e, 0x613198ea, 0x3ffac767, 0x88dcbce4, 0x05b9dc95, 0xe03ab40e, + 0x2abcbc61, 0xe805dabf, 0x3dd90a2a, 0xb483b1ba, 0x7b7e8c49, 0xab23f834, 0x0c8c7254, 0x2299f595, 0x36f4fd4b, + 0x3c4bbabe, 0xc1177a93, 0x65f2baf7, 0x5900458f, 0x2d2d81b2, 0x48f0e200, 0xbb4fd2f7, 0xf7280dab, 0x87a9b385, + 0x352572ac, 0xbb4d5a10, 0x9bbc39aa, 0x29b3b73d, 0x1d44d846, 0x2fe5787d, 0x2bc5b0c9, 0x10ce26e7, 0xb022fc6b, + 0x89114761, 0x02c80c37, 0x01180582, 0xd619f247, 0x77c6cfb3, 0x7f06ad4c, 0x66d3ca0a, 0x10688720, 0x42826d90, + 0x7cefbedc, 0x240b6ecf, 0x924c6efa, 0xb0ee472c, 0x70d8a18b, 0x20451bf1, 0x7da09e73, 0x96712309, 0xa69da8c9, + 0x51a4f765, 0xbc793fec, 0xb7a5e592, 0x4ff2d3b8, 0x94314802, 0x8c168af1, 0xcbc7cd84, 0x841e4cdb, 0xbaf2b6a3, + 0x6e1dca59, 0x75eb4f33, 0x6d5c4d00, 0xd66ef9ef, 0xab879882, 0x6fb1f796, 0xac25b37d, 0x6c95b80f, 0x8137f6a9, + 0xa3655890, 0x005c02f2, 0xd849a592, 0x111de97a, 0xd6150797, 0x6596326c, 0x2f97b0fe, 0x8a38a23c, 0x68f35057, + 0x27c0c4c5, 0x13ec3f74, 0x3849bdd9, 0x645ae2d3, 0x8298bb2a, 0xee6e9f04, 0x673337b9, 0xaa44e181, 0x8768fa94, + 0x05516399, 0x96d40816, 0x2746e8d8, 0xb7f4a744, 0x7e0a4290, 0xdbcbdf34, 0xc4f0783f, 0x73b4f6e1, 0x51cf06fc, + 0x4254e9ed, 0x53ad9d1d, 0x7d449f0e, 0xd2019fcf, 0x78f7ea75, 0x47e1cbd7, 0xc02d27c9, 0xe1e41256, 0xea6d8a57, + 0x9bcfa2b3, 0xcc7b472b, 0xf13cee9a, 0xfbd13dfb, 0xf8f2d12e, 0xaf575051, 0x702167e1, 0x17f7f4f8, 0xd9963904, + 0xe6177334, 0xd203f656, 0xff67a7a8, 0xc557135b, 0xb16d3a2d, 0x9d850b52, 0x62470dd8, 0xbac53cb0, 0xd761b060, + 0x9a6b5872, 0x39e7f492, 0x8763388d, 0x5caefe8f, 0xbab9f5d5, 0x92cad846, 0xaa9445be, 0xa4aab30d, 0xb9634b76, + 0xca828f6a, 0x9603fef3, 0x6f56b6cd, 0x8f0c8c55, 0x226dcfdf, 0x150392df, 0xfc22627e, 0xfff0a8e9, 0xde2afd0a, + 0xe9971730, 0xa759493e, 0x02835556, 0x0f05826f, 0x777cd4fe, 0xe0966e18, 0x7bd9d95d, 0x5ae9f45e, 0xca8d0bc4, + 0x7ed928eb, 0xdeb9607d, 0x67c56202, 0xe97d5d13, 0x9755bc3f, 0x1cabf4dd, 0x4b81687f, 0x1e6ee674, 0xb86e119f, + 0xc7d63bcf, 0x8e1d99bb, 0xcd3603fb, 0x0393548c, 0x92ebb2a7, 0xed2eb3fc, 0x1496c58f, 0xb80214cb, 0xc390a5a0, + 0xcffca276, 0x1b952b05, 0xaf20497c, 0x9a03d9c8, 0x97211d0f, 0x10333811, 0xa21ce99f, 0xd7a4a7f1, 0x7b9d6103, + 0x25d88c9b, 0xa98b66f8, 0x86f5d0c0, 0xfc5312dc, 0xfee2f179, 0x6fb166e0, 0x004e1084, 0x27b32a17, 0x37eda628, + 0xd956c944, 0xede72d3d, 0x4a126447, 0x427d55c9, 0x8bd5e54f, 0xdd10392c, 0x63dd04ea, 0x3c2bc3e9, 0x6c796154, + 0xa3a2604f, 0x8d1833ba, 0x73c8a011, 0xb17546a0, 0x04105802, 0x41928fa7, 0x87788b8a, 0x9aa37a73, 0x4530b6da, + 0x4372e60d, 0xf5e2c91d, 0xa90a40bf, 0xeefd1006, 0xdebd37de, 0x0c103d3e, 0x960641e9, 0x32bd6219, 0xe1d10eee, + 0xebaf152d, 0x122c3149, 0x5a0be7b1, 0x9842c4e4, 0x60f361ce, 0x12a66694, 0x5aa3dfc6, 0xe3e30ef8, 0x524f2b87, + 0xff2b6b47, 0x9df654ee, 0x05b9aca2, 0x91f5115a, 0x0128aec2, 0x1d384bc0, 0xd87470b8, 0x132bfec1, 0xec4bf820, + 0x86bc9a59, 0xdc6261ef, 0x134d4699, 0x4adbe3c8, 0xc29c1878, 0xd34bdc81, 0xa887d92f, 0xbdd3738c, 0x48e2d8d7, + 0x87f29311, 0x94011d68, 0xe8931495, 0xf30c9a8b, 0x7f67d2ff, 0xa061df4e, 0x706e9817, 0x011f9009, 0x95c713d7, + 0xdec5b3ad, 0x3cc23a89, 0x629a12e0, 0x42b3d53e, 0x89ec04d4, 0xed1e020b, 0x12a7bd93, 0x77e11384, 0xbd6ed01e, + 0x1b46a19b, 0x4020c7c3, 0xbf1275ba, 0x4a7165da, 0x99a14f17, 0x85b14025, 0xbca1a31a, 0x7a3e6188, 0xe6f5ecde, + 0x68b2d10b, 0xef1db868, 0x50d1f5a7, 0x1da8e1d3, 0x9e0623b8, 0x3b3cf5af, 0x7a729337, 0x3f109dea, 0x84520fb9, + 0x01aa1bf9, 0x53ba33c0, 0x66f91bd9, 0xcc376f7a, 0x7cffc2d3, 0xba8d2eb9, 0x9f3527ac, 0xeef350f4, 0xa870c18c, + 0x96f355a5, 0x8234793e, 0xa004be22, 0xd1a76410, 0x5ad31b00, 0x38c11f6d, 0xc0131de5, 0x23bd16e9, 0xeeee5d32, + 0x66e7811c, 0xad6e855e, 0x211f4047, 0x76e7a846, 0x9c2d92d7, 0xcb9a7844, 0x07b6259d, 0xd9bc905d, 0xb3a5cd50, + 0x9055ccf0, 0x654b2b15, 0x04571267, 0x19c0712a, 0x5ba0eef3, 0x6d80d0c1, 0xead64b6e, 0xbcce50d5, 0xcf36aaa1, + 0x7a449451, 0x9cbb9167, 0xad8a988e, 0x08881c58, 0xb7ea88fb, 0x534859b7, 0xf3b2d778, 0x81a0bcf8, 0x12720e2d, + 0x5e495f8a, 0x1aaf0f39, 0x55dae658, 0x2494fc71, 0xfaf7ced0, 0xcca430d0, 0x492763d1, 0xd33b6e9d, 0x6d19302a, + 0xd37d9b17, 0x0b503371, 0xb147d3c0, 0xcb09d827, 0x201d37d6, 0x4712c9a0, 0x54a9792d, 0xcc62d746, 0x1898c79b, + 0xd858672a, 0xf62ef92a, 0xf2fd26d3, 0xd2f3c844, 0xc3a6416f, 0xe69159e0, 0x00b7ee7a, 0x9e2a1d7e, 0xd7de9b12, + 0x169b3fcd, 0x550a4df6, 0x0af2c651, 0xac81aafb, 0x2203cba6, 0xe5432ea7, 0x39e71abb, 0x998448c7, 0xf5b43192, + 0xe5c12664, 0x7d4ce972, 0x725186ff, 0xcff2d4b4, 0x82d0339e, 0xc18052b1, 0x775102f4, 0x46079eb6, 0x4118d44c, + 0xe29c91cf, 0xa819afa3, 0xa498b7ef, 0x79fcc8e6, 0x11cd5ae9, 0x01f691e8, 0xe4f35860, 0x17ecbebf, 0x8d500657, + 0x1a1fe9ca, 0x0172b273, 0xcfa14706, 0x6b69c3fe, 0x16d852cf, 0x78df0e5d, 0xe5fb570c, 0x024f73ee, 0x2a5dcdfe, + 0x9d55df70, 0x65cf8471, 0x77617060, 0x27b7abf2, 0xcd836ea7, 0x8ed39933, 0x139e1350, 0x16c5e6a3, 0xcaa189db, + 0xb9fc1c76, 0x083f4ca3, 0x82839326, 0x81d41929, 0x923717ff, 0xb751284e, 0xd15a7e6a, 0xb5088e51, 0x7916bfc7, + 0x561ec6fe, 0x84356ba5, 0xa94b3c77, 0x20663574, 0x38e2ce85, 0x368014be, 0x991d7294, 0xe84f4e4f, 0xc7fa66c9, + 0xb0d18bd4, 0x3df42eff, 0x4cb83c26, 0x55b0f521, 0x9136de9a, 0xef063e9b, 0x83cea36b, 0x69e78ac7, 0x296c7549, + 0xacec11fa, 0xa59a86a9, 0xf8f83e02, 0xcda22056, 0x4942ae85, 0xdd49e71f, 0xf8076625, 0x83aa9cff, 0xf49020c4, + 0x895d18bb, 0xc0ba4225, 0xe9310636, 0xbd48bb6a, 0x35facc20, 0xb4c6a1a8, 0x56235eb7, 0x0b15931f, 0x441f46ba, + 0xaf0585c0, 0xb1681527, 0x5c80dffb, 0x1ffad0cd, 0xc63fb7b4, 0x5d3035e9, 0x84ac7665, 0x951b3a6f, 0xf7c7ab10, + 0xea9347ac, 0xe6ea6dce, 0x7efbe8b9, 0xcc092eaa, 0xa52cf7e9, 0x6c16cf0e, 0x39004f1f, 0x17768389, 0x5ba419a4, + 0x7dc3fd26, 0x8a4d5971, 0x3c4f55cd, 0xb3ec7fec, 0x32307869, 0xc3a5c4a4, 0x7962dd44, 0x8a999bdd, 0x71227243, + 0x0d83c200, 0x91ce89b6, 0x9c3cc9da, 0x151cc85a, 0x134cf758, 0xd3d17c17, 0x935b1e0c, 0x9c105275, 0x0140bc4c, + 0x061f48ae, 0x87fbd568, 0x9c268b42, 0xddb86478, 0x7414a53b, 0x07e11370, 0xa2470caa, 0x86b61d53, 0xd430c8da, + 0xdec4b3b1, 0xd77d5f95, 0x14fcf47c, 0xcb30252e, 0x04e9c595, 0xbb3d5379, 0xa751970f, 0xc1b2ad2e, 0xbee255d8, + 0x9ed50fef, 0x43ebb256, 0x0bde525b, 0x8c54b385, 0xc4831447, 0xba83861e, 0x37c335b9, 0x15b4b200, 0x10d5b4d6, + 0x75094475, 0x0e053907, 0xc6691f42, 0x549bc3b4, 0x65501918, 0x44b0a735, 0xbd7e6ad4, 0x46dc9603, 0x1d3f7bfb, + 0x83ad29a1, 0x8251d50b, 0xe85420b4, 0x1b7a9915, 0x43943135, 0x8b489311, 0xcc9c5c04, 0xdaae8e9a, 0x4c4a815e, + 0x7532f7ca, 0x26e034d5, 0x0161f18d, 0xca5d69be, 0x50afa623, 0x453bbd78, 0x082f1b9d, 0xb26a6ecf, 0xa997088c, + 0xc61ffdb8, 0x8e93e046, 0xdb92df02, 0x70632105, 0x2490387d, 0xa43c28a4, 0xcac1f158, 0x25058ad8, 0x79afb468, + 0xfb552d5d, 0x289d7775, 0x4ea362e5, 0x43d4436e, 0xe415e10e, 0x52b19f69, 0x87f7e433, 0xc376011a, 0x9df411b5, + 0xbdde0eb0, 0xa8fa070e, 0x217655f1, 0xfae0a955, 0x1c0258ec, 0xedf10a62, 0x156bb5ce, 0x2b50af29, 0x958bbbcc, + 0x4064125c, 0xe211b766, 0x1ae25e28, 0xb5c06fe3, 0x07ff3d0a, 0x2430d6f2, 0xf7843d55, 0x84c1a963, 0x7021a68b, + 0x5f5caa20, 0x428b74c5, 0x7c016774, 0xa6891297, 0xf716eed6, 0x75de657f, 0xcc422a88, 0xdbc86a0b, 0x420115ca, + 0x8c7cbd1a, 0x0dfb31e1, 0x7543d68f, 0xb2f1100e, 0x859e4cbb, 0x2e87e9fa, 0x55583d5a, 0x6d4506c1, 0xc676f0f0, + 0xa20c0e20, 0xd9cdbadd, 0x23791c37, 0xd87a4ac3, 0x782ffa70, 0xaca4de71, 0xa57972c9, 0x8b965bab, 0x394cc0d4, + 0xe98006ed, 0xa685bfc1, 0x626ca042, 0x8097f4ce, 0x52e024f2, 0xe7491059, 0x96e07748, 0xd21167e1, 0xb70d9b8a, + 0xbf795280, 0x4301b987, 0xd8e0724d, 0x155aa2a4, 0x1ba62655, 0x19789f00, 0x68ef5ad1, 0xbbaa8738, 0x50a57943, + 0x68f1cdea, 0x3dfd6581, 0x74c95429, 0x60fbcd49, 0xfe612fe0, 0x1bad4893, 0xf0b2473d, 0x1daed6f8, 0x526887ac, + 0x5103e672, 0xb97c8eb9, 0xa894bca7, 0x75e029ba, 0xd9a18768, 0xa9dd0b5b, 0x4b340ddc, 0x2db4f26e, 0xb2d800a0, + 0x12ba01c6, 0x2031eaba, 0xdc64be65, 0xae47516d, 0xc059a5f5, 0xb1604188, 0x07b7f3ed, 0x855b313a, 0x72dc4a5a, + 0x958372bf, 0xdb1ce09f, 0x79d2e99d, 0xb2c65d26, 0xfd41e54d, 0x0d656a86, 0x8f6c6453, 0xe7053b4c, 0xe241fbff, + 0x606d4040, 0x86ccf947, 0x39f3c568, 0x93d98a96, 0xd433bcca, 0x64f10e44, 0x35b6d3ee, 0x1b352bd8, 0x871ff739, + 0x5d40f26d, 0x013dd118, 0x3fbd6bb3, 0x63a3f490, 0xcd37abd5, 0x73b8c9cb, 0x4535f615, 0x136435bc, 0x9668ab8e, + 0x670fd460, 0xca29b75f, 0x4c7a012f, 0x0b0302af, 0x290fa1f0, 0x6be2b15d, 0xf5e92a41, 0xb7e9b544, 0x819b7a47, + 0xe72d1e90, 0x455c7a9c, 0x7993b8b8, 0x8bfb3649, 0x1ebdeee6, 0x483770ca, 0x1676641a, 0x2faefc77, 0xa191a746, + 0x273a25ed, 0x2c741cde, 0x7526dcf0, 0x82106e04, 0x0db22880, 0x5d0ae6d4, 0xc83b4c66, 0x39f65084, 0x1c3e4e3b, + 0x6898f687, 0x1e0a5e8f, 0x113cf8f2, 0x5c58335b, 0xbf58c6aa, 0xbf79ca3d, 0x4160968c, 0x4cc8dce3, 0x4ff44f20, + 0xe69e58b6, 0xb2db4807, 0x1a22e3df, 0x93f0e41a, 0xa79dbf29, 0x29d624a7, 0xf2384dab, 0xaec45027, 0xd173dfff, + 0xa94774a0, 0xb43b6858, 0x84810096, 0x70856686, 0xb88fca67, 0x0ba39576, 0x5317d893, 0xecdaeb2f, 0xce0605f0, + 0x8fada02d, 0xbf13d2b6, 0x174284c4, 0x61ad8e5d, 0x2ad00f48, 0x12435cae, 0xccaa9c4b, 0x1b2e5fd5, 0x92c0cabc, + 0x20a523bb, 0x4802b3d6, 0x7cd9eba3, 0x8ccd929f, 0x73911e0a, 0xc96aa5a8, 0xbaa0a3da, 0xe16426d1, 0x1012af8f, + 0x29ad4352, 0x5f239a45, 0x0f65a9fb, 0xd4c1c8e5, 0x082b9bd7, 0x3d912b73, 0xd2516704, 0xf77bfe4e, 0xb0ce196b, + 0x329df5be, 0xe797ce29, 0xf97da09b, 0x13b707b9, 0xe3a8042e, 0x1c036172, 0x02484aa3, 0x1d257f1e, 0xdc25d6ea, + 0x8b95dff9, 0x5a4cc954, 0xbce858a6, 0xfcd3304b, 0xda014ae8, 0x73236f94, 0x2a3fc7c0, 0x8eccdf97, 0x31ee25c8, + 0x7a40c1c7, 0x2b99862b, 0xb6d2c4b7, 0x6483c729, 0x2c8341c2, 0xec33f578, 0x1b8728da, 0xfa364112, 0x975c9013, + 0x040b8389, 0xe9202111, 0xa14bf79a, 0x84a0a864, 0xa1a210af, 0x3c41efbe, 0x6cd25201, 0xf38c5dfa, 0x0f15de25, + 0x86d210f5, 0xd92fbbdf, 0x989b84d2, 0xfedeff5c, 0x7b267891, 0x2f241b6e, 0x4af344e8, 0xfde20685, 0xc40fd7d7, + 0xaf70af41, 0x757adf6f, 0x45517c50, 0xc6ce29e5, 0x32a15ad6, 0x819ff766, 0x7bff7b33, 0x81003f1c, 0x585390c5, + 0x45877ac6, 0xb77b190e, 0x83b8c351, 0x6ec765bc, 0x73275b88, 0x6a110831, 0x8dea67da, 0x9f36e453, 0x28bf112d, + 0x9d6c36c2, 0x5cb90fc2, 0x6a86c152, 0x009eb9b0, 0x1475543c, 0x20bb5e75, 0xba68b1bd, 0x03d49ad0, 0x16bda12d, + 0x507ab77a, 0xdff6c028, 0x795d151d, 0x726a8b41, 0xfbdf5def, 0x3065f1aa, 0xbd557d9f, 0x978078c2, 0x19687521, + 0xd00b73dd, 0x20b3c8a6, 0x9064b240, 0x78ea5e44, 0x654868de, 0xf2c4a7b4, 0xd03a830e, 0xe0b0a022, 0x944df9a7, + 0x4d249a0a, 0x0801eab3, 0x249b33d4, 0xe74d9063, 0xf67f7e8d, 0x392b0f85, 0x892c54e1, 0xb8886132, 0xcbf8951e, + 0xf2afe4e4, 0x20b295ab, 0xec4b9673, 0x34333fcd, 0x20b2cd26, 0x0342843a, 0x722e6873, 0x131e0370, 0xc8e80152, + 0x7ecbd905, 0xed6470f8, 0xe5a5c05c, 0xfb219f4c, 0x64a55972, 0xa798e2b7, 0xe186c3cd, 0x2173b213, 0xb8ed8a23, + 0x2d57d28c, 0x3a6de959, 0x5ca69891, 0x65480928, 0x8ed7fb7c, 0xeebc9f3f, 0xc3a055e2, 0xff7f3d7f, 0x28356387, + 0x9a205c1c, 0xd4d57365, 0x33beb738, 0xa7267ab2, 0xe994e47d, 0xcbc3768d, 0x6afa3938, 0x08932a9e, 0x90788860, + 0x5c53a3a8, 0x6b1de61d, 0xb933c354, 0x99d06ab0, 0x4552a3ff, 0x15418f72, 0x496b5794, 0xff96c90a, 0x73cfb8d5, + 0xcec2df17, 0x8013fbea, 0x816bd3bb, 0x8cd198fc, 0xefc6ff6e, 0x24720d50, 0x2c961aa6, 0x48748439, 0x2b3e18c8, + 0x8bcf022c, 0xf2ae7bee, 0xaa608b94, 0x7bee1458, 0x46088004, 0x392766af, 0x4e36f739, 0xfe42e846, 0x0260df2d, + 0x69b74372, 0x0bbc1110, 0xbf614b9a, 0x8f3e6237, 0xc85e251a, 0x343d078f, 0x138dec4a, 0xfb2d8e0a, 0xf04561ba, + 0x088efa34, 0x807d1474, 0xa21aeb3f, 0xc85d1b84, 0x7c80d1aa, 0x957f1e96, 0xeeb5bf7f, 0xfc2e097b, 0x435e6343, + 0xd353a20b, 0xd683f277, 0x793cb153, 0x86b802a8, 0xb78dab0c, 0xf99cd47e, 0xece2ed1d, 0x56d8b593, 0x9e42852c, + 0x53ee1d7c, 0x023b6e1f, 0xffe60421, 0xfc86a520, 0x642cde64, 0xd1470fe9, 0xfcec786e, 0x53d13fc3, 0x29041a2e, + 0x1b648813, 0x2fbbf553, 0x1d41129f, 0x4ef6394b, 0x485d09ac, 0x12e24fe3, 0xf5a4bcb8, 0x7fc0c37d, 0x06918725, + 0xfbc1adb7, 0xa7113957, 0x9ca45a5f, 0x2758c7cd, 0xe66f8baf, 0xf207e9b9, 0x22b8df9c, 0x4813b64a, 0x935aa2d0, + 0x68f05bb6, 0x1d0477f8, 0x5886a5f0, 0x9f983804, 0x8fc6e9a3, 0x93212d3b, 0xe4666f1b, 0x1bb0316c, 0x3ba97f21, + 0xfbf8d65e, 0x45558f8d, 0xa923e8af, 0xc19eb15a, 0xdd9b5de7, 0x42152d38, 0xb9b3f1b2, 0x7403f622, 0x00389d07, + 0x5592ac21, 0x3e6a2112, 0xeff00097, 0xc65e6260, 0xcdecd668, 0xfc0621c9, 0x98fb915e, 0x41dac8ff, 0x312913ee, + 0x1e0d484e, 0x11ab4274, 0x4035bb3c, 0x03a0a678, 0x1dd92f88, 0x7ed3f980, 0x505ace2d, 0x07d86252, 0xc2feb706, + 0xd2a0ad0b, 0xf2b99ea0, 0xbea884bc, 0x388116e0, 0xd3702bcc, 0xffbc4184, 0x97cbc2c2, 0x48652a79, 0x2b715c41, + 0xdb9e79cd, 0xa37126c9, 0xf2ed6d26, 0x7abc6199, 0xc040e9e0, 0x116fbbb8, 0xaae315e2, 0xda27fa0c, 0x0df1f2f2, + 0xfe4349f1, 0x6796e467, 0x0dac5bc7, 0xaa259c03, 0xa1fdd094, 0xbac94396, 0x77ed8caf, 0x4ca5025b, 0xb3b11127, + 0xbd84bf18, 0x789b9134, 0xf941de3c, 0x4075afe3, 0x75b602a2, 0xf239b24d, 0xea193bd6, 0x265d10b3, 0xb992ff3d, + 0x52b0edcf, 0x49a488bd, 0xb12f9f2f, 0x75c74a56, 0x14b6e86f, 0xc3107b1b, 0x2a223e1d, 0xbc617f5f, 0x9072834a, + 0x1a08b93a, 0x5d98a0ac, 0xe6c76b8a, 0x0af8a4a6, 0x765f37f3, 0xa53fe476, 0x9f9f0f9f, 0xa69b3f9b, 0xb672ea99, + 0xd88da8b3, 0x65fb14c0, 0x77efa7e0, 0x15eb0060, 0xd6533b25, 0x49074c3c, 0x2e1be494, 0x822c0159, 0xbc2ec9cc, + 0x78c6296f, 0x3bff57bf, 0x2a153de6, 0x6eb76474, 0x57ba526c, 0x1333a224, 0x1bdfc2d7, 0x33c11b81, 0x2368e296, + 0x106f907e, 0x069ea223, 0x179230b0, 0x23901c67, 0xb85a30f5, 0x873beec3, 0x501a37f0, 0x72f6b6f4, 0xcfee373e, + 0xde1f55e4, 0xda248c9a, 0x181877c9, 0x539161e8, 0x10d1c339, 0xf26e0e9a, 0xb099b673, 0x5fb6fbaa, 0xb843d95a, + 0x58589600, 0xa6f0fd4c, 0x545a0bf4, 0x0366b5ce, 0x1f148cf6, 0x2cbf395a, 0x23db8332, 0x7c429428, 0x7366044c, + 0xa480678d, 0xb5b9bb75, 0x3e28b910, 0x4589f0bc, 0xa9e7f15a, 0x9e95e8ea, 0xa4425f9a, 0x9d037ed3, 0x4916146c, + 0xb1306d56, 0xd60992c9, 0x946a6e29, 0xffd7acec, 0xb2a85126, 0xedc2a148, 0xf01d1331, 0x44417ccd, 0xeba7abb2, + 0xcdfbbf21, 0x7896911c, 0xbe97300f, 0x24c1f5cd, 0x83d8d6a8, 0xdc916254, 0x34839c43, 0x88d4a921, 0xdd6c5692, + 0x3df7a434, 0xcfa85814, 0x38715a50, 0x62c705a2, 0xda8963fb, 0xc4c81a55, 0x997a4d7e, 0x590d3c02, 0x4e5b7386, + 0x932787f8, 0xf029c5b1, 0x2c0002a6, 0x5fed11b5, 0x16221236, 0x4c90c72b, 0x818af572, 0x2294b0f6, 0x7cdbbdae, + 0x99596f67, 0x56892e8c, 0x6989c9cc, 0x12e74b52, 0x84e6d24e, 0x214a6695, 0x4c31aaeb, 0x7728e226, 0xd7aa3a76, + 0xda8d8108, 0x2c09051b, 0xdec8627a, 0xdd24e355, 0x252b21b2, 0x547686c7, 0xd61132c7, 0x2af32db3, 0x33fd013a, + 0x87027f57, 0xd147f126, 0xd54eb330, 0xe6b8ca6b, 0xa1adf30e, 0xc35685e1, 0xf8373e76, 0x9bde1a94, 0x8ad9d0c7, + 0xda314b69, 0x08cd3fc1, 0x4823a254, 0xa4ce6fd8, 0xdff182ac, 0xb26fce3c, 0xed283cbd, 0x9932b7be, 0xb07b5d03, + 0xce83040c, 0x3ad0afb9, 0xa88e75ca, 0x9d827084, 0x03e95a4b, 0x7ea89367, 0xce210356, 0x4187bda2, 0xf8e3cf9c, + 0xba281d77, 0xac0c683a, 0xa0632c37, 0xbaf9b3b8, 0xeed78db4, 0xb2129aae, 0xe5013d3e, 0x5c19c76f, 0x5cb705c6, + 0xd9cdd544, 0x429d4c0e, 0x667db2d6, 0x15189415, 0x767cb347, 0xe7ef5eb5, 0x9ceed804, 0x0a08bd3d, 0xf8b642ba, + 0xc0a877c3, 0xe8e1197e, 0x4d0ed0e9, 0x908497a5, 0x86088cd4, 0x0bfa5249, 0x1c8b9dd5, 0x2087957f, 0x45670527, + 0x67516646, 0x01396e43, 0xbbd2bc8c, 0x7b8a44da, 0x626b2233, 0x306b720a, 0x70a63328, 0x5eef4c03, 0xb90db0ad, + 0x4d362c26, 0x9c62c4d3, 0xa78a7990, 0x411f3153, 0x37bc392b, 0x2a5d48f3, 0x15fc715f, 0x54091054, 0xb7b334e8, + 0x329741e9, 0x8216a041, 0xfc25d2c4, 0x2239e995, 0xd7614687, 0x633db7cb, 0x61bead2c, 0xae283511, 0x98ce6019, + 0xdf573eb9, 0x2e3ea814, 0x5a2ee44f, 0xf185e12a, 0x2483f2da, 0xcf7caf27, 0x90dc7845, 0x3d889f41, 0xda304188, + 0xbaac7683, 0xaf137ef2, 0x854176f6, 0xd0467949, 0xcec68f0f, 0x63698366, 0x195d648c, 0xd1b5783e, 0xf2999b9c, + 0x3d7ec658, 0xcd953c1a, 0x8e265487, 0x0271fe9c, 0x70a04fe3, 0x720f5d1c, 0x2f300618, 0x69de7a43, 0xe9cefa0e, + 0xd022d023, 0x3191bd70, 0x12d042b3, 0x32aa0d40, 0x65309796, 0x5983ae7f, 0x01f241f3, 0xa532b57c, 0x291dc42e, + 0x1324660a, 0xdf265155, 0x84d57e81, 0x3588430f, 0x2c79c6cd, 0x453d81ea, 0xe590a59a, 0xdd1fd398, 0x0d495f0c, + 0xe60b1f1a, 0x8d8ea20b, 0x43df0b6c, 0x5b42bea1, 0x2a1ac2d9, 0xf68d6a0d, 0x800a777d, 0x6f6d2206, 0x9a34901c, + 0x8c5458f1, 0x05e3ee77, 0xc5be6f3a, 0x8f236ffd, 0xfc41c26f, 0xc04b7f94, 0x2281523f, 0x0b25d8a6, 0x002aebe5, + 0xc55f7780, 0x664df91c, 0xdcf5ee32, 0x2a166aaa, 0xf9530197, 0x7be6a70f, 0x05fe833c, 0x0a3b3c23, 0xf97abc19, + 0x1a0cfd4f, 0x7a6284f9, 0xd556f6da, 0x070d1afe, 0xfc64f5a0, 0x52606373, 0x6392f213, 0xf4668831, 0xa24256b4, + 0x09ee0518, 0xadbdfe59, 0xa3310e89, 0x6458ddc0, 0xf2512b84, 0xe8760dba, 0xbe6edb62, 0xf3151a32, 0x1e53b07c, + 0x8dd821e4, 0xcf246e9a, 0x3f7eebe4, 0x1d589c7f, 0xe9d0f2e9, 0x1828dd41, 0xd7f0b290, 0xb588e9d7, 0x71278043, + 0x03708472, 0x05d9deb5, 0x575bfee9, 0x6b79b23c, 0x07ab8983, 0x5808efa1, 0xd6ce9b01, 0xfa864b00, 0x99d71bcf, + 0x0bf2c720, 0xf87e643d, 0xc94d7e84, 0xd1ac3de0, 0x6c45fd58, 0x16c3e187, 0x2bd74ec3, 0xa7c62561, 0xd0254c9c, + 0x361ccf17, 0xb2102d3a, 0xf2e85d46, 0x4560bfbe, 0xb922e642, 0x700bf09e, 0x31a90701, 0xb48a3943, 0x0a6cf5c6, + 0xdd1fe812, 0xce08814a, 0x51563d5c, 0xcd69fc24, 0xf8b8fc4e, 0x721d4a97, 0x9a04d72b, 0xa4929c86, 0x4d7c3ed9, + 0x8e63b3c3, 0x29757d56, 0x61a1c267, 0x0f0796f7, 0x502a8bd7, 0x69d699e6, 0x3e49481a, 0x487452a6, 0xbc0b5fb8, + 0x917b4198, 0xa2a807ac, 0x9d68ea8e, 0x2b58b973, 0x8d1b8f4d, 0xfca4c4a2, 0x662cff29, 0x62c23f18, 0x4d200df0, + 0x44933e61, 0x2f46ba76, 0x6df9ebe5, 0x16009402, 0x1afb5979, 0xdd8db9a6, 0xd13f2258, 0x7445dbdc, 0x7da34ceb, + 0xd6dd824a, 0x5f56f29d, 0xe097e108, 0xde0457e3, 0xa6310b32, 0x031a9d23, 0x463209d7, 0x1cb6098b, 0xbae37d01, + 0x5b1fcade, 0x707c9e46, 0xf0fe06f8, 0x0b1c81b5, 0x35c56e65, 0x22205bf9, 0x0a6777d6, 0xfdbb29c0, 0xaacf1a0b, + 0x43932f45, 0x3f12177e, 0xf3dfeafb, 0xd487eaba, 0xc8037e7d, 0xce1dd0e2, 0x7256270b, 0x8e8c3238, 0x5e459f77, + 0x0b37f4df, 0x15cabfa7, 0xb3d953a1, 0xa4a00e6e, 0xfa1cd2d0, 0x30c96990, 0x22b92fa7, 0x9522c111, 0xeb631058, + 0xc29de432, 0x4fb64cd8, 0xc6165a1e, 0x22f8b4b1, 0x5187036a, 0x8a09360b, 0xda2a27ed, 0xbbee91ab, 0xe23b6eca, + 0x49812e22, 0xa154f215, 0x7f539387, 0xa8b8c76a, 0x040428d1, 0xd04b01f6, 0x0648c623, 0x9059ddbe, 0x11071fce, + 0x711f7556, 0x4e290239, 0x098f6479, 0x454416cb, 0x7f0ba1bd, 0xe7d23878, 0xb8fd698f, 0x383a640f, 0x3ba277d7, + 0x7f4de905, 0xc8cca4e1, 0x32a63f90, 0x39e1dbc8, 0x5a04e1c1, 0x6f153b9e, 0x82958009, 0x167b7915, 0xb516f521, + 0xd9f83af1, 0x4e77111e, 0x11401957, 0xe683edfe, 0xe2558c8f, 0x761c65cf, 0x409dc73d, 0x074e9967, 0xecafd5a0, + 0xbeb66a82, 0x21970f63, 0x606f1d0a, 0xbd6cae59, 0x1cd980ef, 0x05f3b7b6, 0x5bacdeaf, 0x7b4505a7, 0x96154ba2, + 0xf7248fd4, 0xa89bc4e2, 0xd2674b01, 0xc0ef6771, 0x6f60dfba, 0x7fdae132, 0x50f401dc, 0x2016c2bd, 0xd8fc0cc3, + 0xaf92eae5, 0x36784f15, 0xbe8b9491, 0x281b2fc6, 0x55c7ef56, 0xa4222c10, 0x326d73fd, 0xec0b73e4, 0x1af184c3, + 0xe6d4e57e, 0xa37ba8ad, 0x5dba0d1a, 0x037b2cfc, 0x54a73d85, 0xba93544c, 0xf6157d57, 0x9900609f, 0x4e54f263, + 0xc9c54a3d, 0x129a3d11, 0xb8187a71, 0x41f3b34c, 0x7fcf69f9, 0xc8eb5b83, 0xe0196f62, 0x0f98baa4, 0xe7da50fe, + 0xe2569364, 0xd0e582da, 0xe05168ad, 0x84738b25, 0x46dbf426, 0xbb7d71ba, 0x7b325408, 0xa5cfb69e, 0x9e898bab, + 0x276a15f3, 0x72285f65, 0x8c310561, 0x7b50383b, 0x236c70d0, 0xe8026081, 0x0a24b6f2, 0x840e8aaf, 0x1829797f, + 0xf03b5b28, 0x88bd5179, 0x21821b0a, 0xa77e13ab, 0x598b39d3, 0x62f059d8, 0x4ca5db68, 0x1a7080ca, 0xe0bc2398, + 0xb0c7bc41, 0xe249b565, 0x3fded727, 0x7867254d, 0xac73fa6d, 0x492b8913, 0xe6f44dc1, 0x7a6f06b2, 0x28bf1d5d, + 0x1808292f, 0x252f9665, 0xae9d0666, 0xa572a5eb, 0xc656849d, 0x967f3847, 0xe26777ec, 0x27471322, 0xbdd2fc7b, + 0x38f15d6d, 0x49155350, 0x72f9c758, 0xb21c1eb0, 0x6173e57a, 0xef575d2e, 0xcc2c9fe2, 0x75037268, 0x85bece3c, + 0x3d310f35, 0x4f8b24a0, 0x60db54e7, 0x4f926e0f, 0xab73d8d7, 0x466df618, 0x0c5e6079, 0xa2f1155d, 0x63660d69, + 0x4ffc23c0, 0xef902218, 0x2727c3f1, 0x339bfbce, 0x27545b9b, 0xc0332b80, 0xe02e8a27, 0xba8466bc, 0xa6bf4576, + 0x577c11d5, 0xf37baea4, 0x8285d9f3, 0x55519e45, 0xc0299824, 0x8d93fdfd, 0x90bcfe85, 0x316efade, 0x713cc08f, + 0x2020b457, 0xb35a56a3, 0x9daa9f56, 0x8be3ec31, 0xc63aa1bc, 0xddce4888, 0xf97134f9, 0xfb86d16c, 0x982fff67, + 0x6c6b32bc, 0x5ea7b0c7, 0x34b6d0f1, 0xdeec3fcf, 0x2d09b094, 0x553ba11f, 0x7b4ca3b4, 0xc187fde2, 0x18f18cd0, + 0xcc3e3f58, 0xaace192e, 0xd57d828e, 0x2f2d8a87, 0x69d3e489, 0xc501659f, 0x6d95556b, 0x0196e218, 0x27204a1f, + 0x2f4838e9, 0x53bab428, 0x0426d2a7, 0x4bfc6221, 0x34cd07c1, 0x5408efe7, 0xe55326f7, 0xa56f73c2, 0x6d480321, + 0xc864859e, 0xa1badb2b, 0x84b415d7, 0xa819e211, 0x2cd3244b, 0x7b57e1ce, 0xa3d888e2, 0xd8e28cd4, 0x5b949138, + 0x94eecadb, 0x0796ef01, 0xb6a3db8e, 0xd323d6ba, 0x8c768360, 0x1e13a7e9, 0x4a14ae55, 0xfdfaed58, 0x11c3b550, + 0xdd7c389c, 0x5f31fdc8, 0xc8dc97d3, 0xc44dcfc0, 0x01a8891c, 0x66c47241, 0xe0a0e5aa, 0x3aeea5ea, 0x264f9ba8, + 0x8eb26d54, 0x49dd380b, 0xfd973950, 0x8593d54f, 0xdca24f1a, 0x93ed71ba, 0x35fa96e5, 0x351ebc33, 0x42692a51, + 0x44f33103, 0xd9b53ba9, 0xfc46ce01, 0x60bed181, 0xaffba953, 0xe1ef372c, 0xbdb315cc, 0x0bc56916, 0xea96a8e9, + 0x7be0aec6, 0x1f93cf85, 0xf1254506, 0x0a80516e, 0x317efb5e, 0x78838f84, 0x7bdaa099, 0x2a0d3fa1, 0xd5ba26c2, + 0x833e49d6, 0x24e24603, 0xac10a02e, 0xb2ded6c8, 0x2de86bb1, 0x7f97e1b7, 0x033143a6, 0x821f9c00, 0x38a6ab36, + 0x27a3edb3, 0xdd4f0901, 0xa604d5c1, 0x854ab32f, 0xedf3b2d5, 0x4376f72f, 0x248067bc, 0xaf0bab58, 0x6abc1f7a, + 0x7ce77694, 0xefa4fe15, 0xc7b0b8ba, 0x5761cb32, 0x08cb11fe, 0xcd35db50, 0x9b834052, 0x275594ca, 0x77ecd0e5, + 0xc90f36ed, 0xf21affde, 0x2c035f95, 0xcfb5ac50, 0x794c3354, 0x3ee3a7a3, 0x38ebf42c, 0x1422c69e, 0xc5981b04, + 0x9000cb24, 0x52f66442, 0xc8672262, 0xfaf31047, 0x7e39ffa4, 0xe690cb9f, 0xe44b0b49, 0xe0732438, 0x87e8aa4a, + 0xdbcd5962, 0x2502a3d9, 0xf90e638f, 0xa1165794, 0x7fc66957, 0x983393dc, 0xbaab6cc7, 0xe020c54a, 0x658520e2, + 0x16330c27, 0x7426f583, 0xe64842ac, 0x71300274, 0x55ae23c0, 0xc1af2005, 0x850548f7, 0x2e1d437c, 0xd3b67d44, + 0xc1515dd8, 0x01ef56bb, 0xcfe9af86, 0x2c674d0c, 0xa26c54fe, 0xd1d19a0e, 0x1520bbe5, 0x0e2fc38d, 0x67749144, + 0x6a3d49dc, 0xb77eb243, 0x51e7fab4, 0x30a4212e, 0x8e536189, 0x4a1de0da, 0x9ebbb4cc, 0xec174b91, 0x945e7fff, + 0xb5aef9f5, 0x8b0bb53b, 0x6c1c7449, 0xdcec5bcf, 0x99978ac6, 0x7100ad89, 0xc2fdecb2, 0x4ba97fd4, 0x35498784, + 0xa84d6ac4, 0x98682d8b, 0x7e15c7e4, 0x3e61011b, 0x4ca183ef, 0xfae0de70, 0xd73fdb0e, 0xa7df3fda, 0x8ff63224, + 0x6412da0c, 0x257f014e, 0xe163109d, 0x9aa10411, 0xe04bff83, 0x7b587e88, 0xe0a0eee6, 0x698ee967, 0xd7839c7b, + 0xd9228b52, 0x4ca53197, 0x5aa8bd54, 0xac6b9c89, 0x963cc507, 0x1ae4ba67, 0x3e5729b8, 0x88225f18, 0xc9457823, + 0x3e7b8cdc, 0xc65e2855, 0x57a022ee, 0x37d961ee, 0x87cf9dbc, 0xb84220c4, 0x2cefa948, 0x01467b77, 0x5349f1b6, + 0x28d8336b, 0x7f03c596, 0xa9dc40c0, 0xcc09c73e, 0x72bde553, 0x354bc77c, 0x7e6bd76b, 0x3519c588, 0x16167ed2, + 0xafb91dd2, 0x2db68b5c, 0x46e67adb, 0x6cc116b4, 0x924cc7ac, 0x1d1404f8, 0x66f4fb39, 0x8e6171a6, 0xa6ec5790, + 0x32630428, 0xae735fbd, 0x3f959add, 0xd6bc5481, 0xf8340d5d, 0xc904ab46, 0x608f0e99, 0x6a6a7b83, 0x39c301fd, + 0xd8bd7456, 0x2e4ebeab, 0xd4f650b3, 0xed12f8ef, 0x04735b08, 0x8f3417f5, 0x338f5479, 0x6f70b536, 0x2d50fee0, + 0x8372eb01, 0x38eec15a, 0x538db3a2, 0xde9d1ca7, 0x442a40a9, 0x2e447b01, 0x78622e5f, 0x721a1e33, 0xe0b8892a, + 0xa25c9971, 0x35702293, 0xe08129e3, 0x4b9d2a72, 0x81a95462, 0xa98f0951, 0x1567c9b4, 0x31d7cd9c, 0xd4423a64, + 0xf085498f, 0xba5cda3d, 0x320aea68, 0x83a255da, 0x27da5e70, 0x8458b204, 0x06ca49fd, 0x9f681e82, 0x72d3190c, + 0xc5dd2b65, 0x1d3d7c93, 0x26001a6c, 0xcbf63b16, 0x6b7896da, 0x218a0d7a, 0x716f8440, 0x419dd9df, 0x2d60bde2, + 0x090d1d8e, 0x34dc40b9, 0x03af1577, 0xab585d90, 0x424c3473, 0xda371ab3, 0x1f5e47c2, 0x82ccd9ac, 0x10710a9d, + 0x5c7bb06e, 0xadfd66bc, 0x17a8f12e, 0x1437d9e0, 0xcd7a0b1a, 0x73ba525e, 0x6c88389a, 0x5a1c9550, 0xdb1f3e71, + 0x9e16b19d, 0xcc15a255, 0x742b7f77, 0x7571d2d0, 0xd7c37a8c, 0x36a083c8, 0x963617e7, 0xc1b46b15, 0x5eef884c, + 0x327722f9, 0xeed519e9, 0x176540a8, 0x5f26aeb3, 0xf42e67da, 0xf101d97f, 0x62ad570d, 0x09a97127, 0x758c0120, + 0x259dd4a6, 0xbe235492, 0xf332d278, 0x83de246a, 0xdf3600cd, 0x01bfe240, 0x0e9980f0, 0xa635d9e3, 0xbe3a32f0, + 0xdcb52f97, 0x11b8e9b9, 0x0fdfa576, 0x9af9fe6e, 0xb14ff417, 0x9cca8e82, 0x71e28bdc, 0x5b9e0680, 0xbc734498, + 0xe50a16f5, 0xb471abe5, 0x5d946d53, 0x3b72ca03, 0x3edd2ff7, 0x28b4145c, 0xc3a39978, 0x2b4eb5fe, 0x790ca567, + 0xe1345cb6, 0x8a314365, 0x1d2c3558, 0xccc57228, 0xc7157928, 0x96fbeb1f, 0x2c13e61b, 0x9facd698, 0xeb61a6ef, + 0x8a24f7d2, 0x12bfd558, 0x465582fb, 0x0bb9cc3d, 0xef2e509a, 0x7542d464, 0x428a98ce, 0x2dd13ffd, 0x6f257b9e, + 0xad08e0f8, 0xd4b854b1, 0xeffc6edd, 0x9df986e4, 0xd119c7ea, 0xfc9cf926, 0x98cbb56b, 0xe5d9825d, 0x5d0ecbd2, + 0x56047ca6, 0x35da47a1, 0xcb448286, 0x2dc64165, 0xe3dc828a, 0x25684657, 0x52835d67, 0x195cd8bf, 0xf85c3903, + 0xdf8ac243, 0xd04ae737, 0xffd0f3c0, 0x275ef938, 0x88045189, 0x670352d5, 0x07e8d8d7, 0x22a27618, 0x2987f72f, + 0x2de33965, 0xc0236dda, 0x95283716, 0x3d6fafef, 0xf67ea441, 0x427f3b02, 0xb5abbbe4, 0xa1d6b34e, 0xe6908cb0, + 0x190ededa, 0x615e74f9, 0x90ad3de2, 0xf34c73ff, 0x5b64b76d, 0x03190162, 0xe7a8215d, 0x45131526, 0x03875914, + 0x321358fb, 0x1e82c0a6, 0x21411a14, 0x82655e27, 0xb11f0189, 0xf8240164, 0x6fe09748, 0x22e26a09, 0xecbc5ed7, + 0x2256325e, 0x973f221a, 0xae10620c, 0xc3b2e11d, 0xe37c86b8, 0x9da7d23a, 0x75031107, 0x3535bc4d, 0x68bc1456, + 0xd6401603, 0xa24e6422, 0xbd57e166, 0xa22f8938, 0x70550c8b, 0xaf37cfd8, 0x7b7e8324, 0xb93f1a8f, 0xd5d711cb, + 0x90ae1c3f, 0xfc60133b, 0xaad63cbc, 0x4b5de7d6, 0xb74fb433, 0x7360e19f, 0x31f9257c, 0xac5ea4ce, 0x959ba866, + 0xc72e72ca, 0x032973e6, 0x253328bc, 0xb7a4d154, 0x42b7ca8a, 0x9df133ca, 0xb6523953, 0xa6d7350e, 0x8ce89bd1, + 0x5dc7836a, 0xf1301872, 0xa7dd2367, 0x010d038d, 0xe7c4e849, 0x73dca0ec, 0x5ca1ef0f, 0x9f8cb756, 0xe8cd0a66, + 0xf894000a, 0x93522fe3, 0x110d08f6, 0x1f7d4053, 0x9aaada8e, 0x4688cf1f, 0xb53c54d4, 0x57c4694b, 0xc834c125, + 0xe1e12fce, 0xed475b3b, 0xc6d81c42, 0x53e8ab93, 0x9ad47ad4, 0x2d1733ea, 0x6b302637, 0x83c0da56, 0x5400a4a4, + 0xb63674aa, 0x02238f12, 0x3b72206c, 0x395169ff, 0xaec6c883, 0xaeb83fb2, 0xbb97de85, 0x3230de7f, 0x12c228ec, + 0xd458ee32, 0xe746c05c, 0xf16cf6e5, 0xc4b00bb9, 0x0efbc100, 0xfb54c5d0, 0x9af08024, 0x309620c7, 0x0f6fcd0a, + 0xd5a6ee03, 0xa972598d, 0xcb046dbe, 0x1361bb57, 0xe57c46ee, 0x48d2ff4d, 0xa24227eb, 0xef502aef, 0x346a2479, + 0x9327839f, 0x112621b1, 0x4d819b57, 0x218eb18e, 0x2f57e49c, 0x43e85591, 0x79a93a36, 0x49f45476, 0xad78fee0, + 0x855be7ed, 0xf35eb736, 0xe38b36aa, 0x7ac7821c, 0x593bc708, 0xe6c86332, 0xbcd6e053, 0x84203f40, 0xb3d1e632, + 0x66ff8e99, 0xa76dee82, 0xd6036d8d, 0xbcb67606, 0xade30994, 0x05e90706, 0x9f7c24c4, 0x0679ac29, 0x73c556dd, + 0x06ead8c7, 0x4b35837f, 0xe1ca9542, 0x1463e5da, 0x8e108a55, 0x08d343ad, 0x2dd5519e, 0xe2345cac, 0x1db19906, + 0x549d4330, 0x9d31f2e9, 0xcf27d09a, 0x02acb5ef, 0xc7e397f6, 0x7f7c048a, 0xf6a80c5e, 0x137a75bd, 0x79651ed1, + 0x0244fba4, 0x6407eb99, 0xf489c109, 0x187cdf73, 0x7c33bd1e, 0x28ed4402, 0x9b4bbe39, 0xdb90c424, 0xd0a1246e, + 0xe195109e, 0x38edb530, 0x3281c012, 0x99d8057b, 0xa2c95f16, 0x92da6a20, 0xa028d34a, 0x557a26b8, 0x3229b207, + 0x9c57acd0, 0xfde9071a, 0x61b60e99, 0xfc87189d, 0xc28ef1c7, 0xdf2a3d28, 0x10d5d38e, 0xf31d0aa6, 0x63e53af7, + 0x0519eb6a, 0xb0d80f01, 0x95176cab, 0x549edd12, 0xd83aa3dd, 0x33458f13, 0x6acdbe76, 0x2ec5de14, 0x6ac52e61, + 0x56c7a013, 0x1f463e60, 0x416507e3, 0xba872831, 0xefddbd46, 0x40eae15e, 0xf8769189, 0xdcbbc9e7, 0x91d1b789, + 0x8f1abe4e, 0xf4d9917d, 0xe89ab2db, 0x991ce579, 0x201f8c63, 0x04f74d9f, 0x129ca5c6, 0xb81251cd, 0x48cf64c3, + 0xcf008127, 0x1873a698, 0x756a8116, 0xf8e95e70, 0xc9b69216, 0xafaaa02d, 0xbfc7feb7, 0x69fa24a8, 0x88d7e372, + 0xaf1adf1d, 0xefda9ef9, 0x2c2f5c57, 0xa38cf07c, 0xaf60a012, 0x2e16b603, 0x427965be, 0xe29a6a2c, 0xa4533e8b, + 0x0fa7b219, 0x2107676f, 0x75820440, 0xf2840f8f, 0x1a7ac09d, 0x25562c27, 0x8c83a5f9, 0x44c805ab, 0xf2270e37, + 0x27a389bf, 0x22fd63dd, 0x0c6378f1, 0x401ccb90, 0x5c63ca87, 0xd9476feb, 0xd818e64a, 0x9a718c1d, 0xffe64084, + 0xff4bf985, 0x0b81009e, 0x95a9733d, 0x1e33063c, 0x27183b91, 0xfc6dad4a, 0x1a386b7a, 0xf5d5014c, 0x180feca6, + 0x7396b6f0, 0x9f58537f, 0xa0345048, 0xce5c2d03, 0xba0c3812, 0x8bb96288, 0x2a2aaf7b, 0x05e6a2e0, 0x5bc28e80, + 0x1bf2adf9, 0xf2a1309f, 0x79c73373, 0x87aaf372, 0x3e5c3a73, 0x75e04dd4, 0x4416c72f, 0x78d5fbb6, 0x6ce5080c, + 0x5d6a50c0, 0xd685cc93, 0xd29978a9, 0x6a775fa6, 0x4c908f6c, 0x06147450, 0xdff80a39, 0x514a7b3f, 0x86f73c36, + 0x8649d7a7, 0xff16b553, 0xa159ba24, 0x836c4df8, 0xbcf2f471, 0x4a470a72, 0xc0a00e12, 0x98e2d766, 0x38221c15, + 0xd91ceb84, 0xf978a05c, 0x0887a183, 0x56ee5070, 0x5eaa8518, 0x081a32db, 0xd3b9b6ac, 0x633a0e8b, 0xa61f27aa, + 0xecc1feb0, 0xb1fe3622, 0x8999a75f, 0xb5eb17f7, 0x01cac8ce, 0xa6687f64, 0xcfe12604, 0x29c492e7, 0x5d789f34, + 0x8a5065bc, 0xadc03ed1, 0x1b102ff9, 0x97939233, 0xebe221cf, 0x694c9c94, 0xeffbc3ce, 0x2e3dbb54, 0x28142bb1, + 0x8630b3c5, 0xa1842600, 0xb9fadad4, 0x2f57c12f, 0x2632210a, 0x69915c8d, 0x1845fed0, 0xc9441e65, 0x1352e131, + 0xf1c815aa, 0x8b1a9137, 0x16eb79b8, 0x1fee16a5, 0x380a1b25, 0x2c6c728f, 0x77d5d53d, 0x63f3cec8, 0x86ff8c67, + 0x910682b1, 0x69c45523, 0x5a313208, 0xf96dfa3c, 0xe233d0b8, 0xa12a1179, 0xcc5bb164, 0x5a7a33d9, 0x6f2cce1d, + 0x37189fab, 0x43c97076, 0x489be792, 0x5ce0a000, 0x1a04e43a, 0xe1284fd0, 0x7126b34b, 0x68972066, 0x61231ba7, + 0xa6dc9ae9, 0x92967056, 0x5e453af4, 0xae80bae9, 0x079148a0, 0x94b85d48, 0xbed61fd8, 0xb73a8fc8, 0x010c98c6, + 0x159df977, 0x196bc374, 0xd2d30543, 0x439d5563, 0x3166f9cc, 0xf8e1a7da, 0x174d6289, 0xf763d9a8, 0x36f8d688, + 0x1a60117c, 0x92f26eb4, 0x44a3ae25, 0x306a39ca, 0x27e556db, 0xae7e9096, 0x7ca41665, 0x02c2576a, 0xfa6de6c0, + 0x1c159ac2, 0xc6d6d58e, 0x30d3b93f, 0xb299fa46, 0x74625090, 0x4a9478a0, 0x62a5c0fb, 0x9a740779, 0xeb50aa46, + 0xa20b5e1d, 0x2fee6dba, 0xc011a278, 0x5471194d, 0xf3d77220, 0xf3457c62, 0xa98c6f8a, 0x43a27e0b, 0x8ce53485, + 0x0b9647c1, 0x63175124, 0xb2c828d9, 0x17598886, 0x1cb04fc3, 0x6e9cd06c, 0x36957456, 0xd7b7f9fd, 0x52bf841e, + 0x4f22a6ec, 0x17670004, 0xf4de1816, 0x2083802d, 0x15f7c072, 0xe2fbf54b, 0x43bd6ab5, 0xb700a225, 0x1886d866, + 0xe5269092, 0x03558c24, 0x35493a25, 0xfcf455cb, 0x60b89b46, 0x1c8d5e4c, 0x3026e1a1, 0x26e91da2, 0x959528be, + 0xeae11f42, 0x082bfc52, 0xea20bbf5, 0xc753cef8, 0x13da320d, 0xf8208d60, 0x5a3c2a21, 0x263dc085, 0x55fafad4, + 0x90dd8420, 0xbf615462, 0x3a90d312, 0x38b0e068, 0x4191eacb, 0xf3e90453, 0x2c495c13, 0xdeb08812, 0xe9c71000, + 0x140151f7, 0xdbd31bdc, 0x09a38ce3, 0xf60d8ea0, 0x85ff97eb, 0x9a06a928, 0x8bee09f1, 0xc762c9c3, 0x49f89d5b, + 0x405383b2, 0x4a46f3f2, 0x68164f1c, 0x1301558a, 0x02e20f94, 0x9a82bea5, 0xfcc4968d, 0x268bc537, 0x79db5628, + 0x6e00f564, 0x7cedc631, 0xf7535725, 0x371d7db0, 0x3c5920d0, 0xfa34cee8, 0x12d33a25, 0xf0ce34a9, 0x4615ab58, + 0x894c1e3f, 0x0ea58d47, 0xbb3de23a, 0xab23fb6b, 0x3a958f67, 0x4c3565aa, 0xd096857f, 0x23ed41cc, 0x7a5894a9, + 0x0d70febd, 0x66487576, 0x51bc272c, 0x1d5e42de, 0x977137a6, 0x95cac438, 0x6fd04862, 0x699dccd2, 0x54687cf7, + 0x393cd3ea, 0x007c20b2, 0x9451b006, 0x9cc5f2b1, 0x12bb3071, 0x6fdf07fc, 0x8951030f, 0x9dc043b2, 0x31b9d459, + 0x4c0bc918, 0x4083f720, 0xe4eb842f, 0x6159ce8f, 0xcaeba344, 0xe9c44da3, 0x33d0cd0a, 0x8809dd49, 0x198f83ae, + 0xe75a6884, 0x0f06f36e, 0xc0f1aab3, 0x637ac2f9, 0x5f27cd43, 0x3dadbb4b, 0xd2cbfde1, 0x54a68bd7, 0x8bba6b51, + 0x28072fb7, 0x01894cfd, 0x0c96a186, 0x60e54c53, 0x0174e5ef, 0xaf2c01cf, 0xf002c76d, 0x4c06648f, 0xeff3baad, + 0x2cd3ea38, 0x2523f8e6, 0x1c512a9a, 0xf8844a61, 0x52dd9e24, 0x2c410533, 0xb68437e4, 0xb8b4ea0d, 0xbba4ef49, + 0xddb5ce14, 0x69066ba1, 0x95e4aa4a, 0xe936d633, 0xfc12c3e9, 0xa01e6909, 0x19909dc2, 0x3022f914, 0x1d429101, + 0x6f50aff7, 0x04e7117a, 0x785aaefb, 0x6368967f, 0x90fe995e, 0x2bd1fb1e, 0xc87bbe3b, 0xbc42881f, 0x65af1073, + 0xd1e7a7e1, 0x0b746d13, 0xe4988560, 0x5dbccf8c, 0x031424e6, 0x88a0f71e, 0xc830bd7f, 0x3d5c6475, 0x6548c3c2, + 0x9e09430e, 0x3659e423, 0x241dbcd7, 0x2f00a881, 0x4ce595df, 0x1c4b5305, 0xce24da43, 0x9df651c6, 0x3910de3e, + 0x438519c8, 0xb4115165, 0x32b060f9, 0x0459b459, 0xa54a7e44, 0x5ad79afe, 0x9ca2a621, 0x3e933347, 0xe86cc156, + 0xd06849e5, 0xec771331, 0xc773070f, 0xa42e2d5c, 0xdbca9cf6, 0xc33b6e36, 0x052bc57f, 0xe0c62889, 0xe92c8642, + 0x45c3d880, 0xea719c52, 0x01fb5970, 0x864e61e3, 0xd808d19d, 0x00ece3c7, 0x84788950, 0x7a73ada7, 0x97662499, + 0x2414dc8c, 0x1bbf24d8, 0x5bdbbd4a, 0xecfd3c9d, 0xed56c0e0, 0x3b4233f0, 0x6345479c, 0x6c63015c, 0x35aba98a, + 0xaf3d9dc2, 0x0633b562, 0x3413b1d7, 0xe6fe7426, 0x71a9bf6d, 0xccc8b1d4, 0xe254bbd0, 0x6aff6ce0, 0x8aac9d5e, + 0x696043a3, 0xb879175f, 0x779fc59c, 0xe4e5086f, 0x6366df3f, 0x66ef4fe1, 0x20bb1388, 0xe50bf98e, 0x5a474e6d, + 0x24262a2d, 0x2aaede14, 0x64916c39, 0x4a4f8df1, 0xfa67796c, 0x78ff2584, 0x87541a49, 0x6e74ec90, 0xf1ad5862, + 0xbb686670, 0x6152f192, 0x28bd9a20, 0x23528e01, 0x84bfab27, 0x22c57c35, 0x7a6c3311, 0xc758a121, 0x57fc4f3f, + 0x3d44d699, 0xf7272dee, 0xbf6a9472, 0xb82797a8, 0xb1a16f94, 0x2ef93fb4, 0x2cd1b1f2, 0xad2545f3, 0x072c0f71, + 0x4bad5e37, 0x20cfc5e4, 0xdbcaa79e, 0x4ff178fb, 0x5fbfe54b, 0xd9a638fa, 0xe5f95370, 0xf0c4d924, 0xa73982a7, + 0x969806ef, 0xd3962da9, 0xd9966177, 0xf54163cc, 0x3ffefa04, 0xa1df5aef, 0x587bcfd3, 0x3d7aa52c, 0x7cc701b1, + 0xb34c1f82, 0x1b1a853e, 0x9a2be9f6, 0x49407b7f, 0x8c825be5, 0xdc815ae6, 0x277d1cd4, 0xc972831d, 0x7de4fb48, + 0xb04e434c, 0xee0cacec, 0xb6e271f2, 0xdfb4712c, 0x56752f2c, 0xa5169b05, 0xd1bb2f7a, 0x303901b6, 0x5522cd85, + 0xa0f8c06a, 0xcaefa3ab, 0x18325a79, 0x0e6e9c00, 0xfc37c587, 0x84196c97, 0x1e81e296, 0x6ac99790, 0x7bff46e0, + 0x385403ef, 0xed318be9, 0xbe895e9d, 0xadfea9f2, 0xae92b96f, 0xca40ab21, 0xcc3f20c4, 0x4700d738, 0x0af8994c, + 0x836d9de4, 0x0d0c0388, 0xf22e9eb8, 0x416062eb, 0x4ec8861b, 0x15efa9ff, 0x0fadf24c, 0x70b262d3, 0x6b4331c8, + 0x9dfe1ea1, 0xef00d354, 0x38e621a5, 0x1f01e3ad, 0x2c8674f2, 0x15be7312, 0x4560145f, 0x733ec406, 0x6a8e6935, + 0xc695d733, 0x7ed6ccab, 0x7bc9bbb9, 0xba86094b, 0xc899a1c5, 0x0a49a7fa, 0x4847e24c, 0xdd4b8725, 0x0f7a8874, + 0x6f50866d, 0x2f1fba5e, 0x815f8376, 0xbd7a68ef, 0x3c2caf97, 0x91d4d1ee, 0x91b6cbfa, 0xa5acccf5, 0x25c4d267, + 0x055c123d, 0x7b09ae21, 0xce9b688c, 0x311ff5b5, 0xc70af304, 0xbcc68da9, 0xad7d5a7b, 0x176d73ef, 0x8aff879e, + 0x764b4c72, 0x8148ffd0, 0xf7d2542e, 0x843e513e, 0x9c80ee56, 0x9b737b9f, 0x66846e90, 0x261474a7, 0xa1fe790c, + 0xf8845d61, 0xa0aabfa5, 0x2b3af833, 0xc46c1038, 0x1c81e35c, 0xd9de4733, 0xbbb0e78d, 0x2658aec6, 0x82421e87, + 0x07a57cfc, 0xdbb8d002, 0x51063b69, 0x50334cee, 0x633a6c35, 0x7f4493d6, 0x60227503, 0xb8dc94fe, 0xbf6a7a75, + 0xfe83a1b0, 0x6c0dcdba, 0x2da2792f, 0xb279ed4f, 0x620c2765, 0x27b0e687, 0x47f4028e, 0x5b3b1557, 0x27fe50c2, + 0xb58f1e7b, 0x05f45f4b, 0x43791111, 0x26c99ed7, 0x4028037b, 0xb52ec6a2, 0xe3745926, 0x4a42334d, 0x69f9fd2c, + 0x2386c2ef, 0xe776291d, 0x39c4ac11, 0x13a42ea5, 0x3514c70a, 0xbed5a3c7, 0x282402b8, 0x66df85f6, 0xcbbe339e, + 0x1f96530b, 0xd0e04c99, 0x23ea76d4, 0xe70302ec, 0xf002fed5, 0x22bd4f76, 0x606607c7, 0x47b4a79c, 0x2fa78885, + 0x000a3614, 0xb4f6e228, 0x64860ae4, 0x1250ad73, 0xfef7bcea, 0x8660f809, 0x1e550472, 0x98991a4e, 0x12404761, + 0x1e9b7963, 0xc14ed8bf, 0x08f7d372, 0xb5a4edcb, 0x649862f4, 0xcd511f4e, 0x31e1f0c3, 0xde955d9f, 0x2bde20ac, + 0x91fb7644, 0xc1c380b8, 0x4bb16f45, 0x965c05f1, 0xf310a065, 0x7bfeac05, 0x6b279436, 0x4d5d9fad, 0x1aa3d771, + 0x0cbfd060, 0x7e19ff94, 0x5c35438b, 0x7dc766b4, 0xacfe0cac, 0x4ab84d98, 0x32134f9a, 0xa68db771, 0xb708193e, + 0x26ecaaf7, 0xad89d2f7, 0xb927ea96, 0xb46ff630, 0x565dd320, 0xedece7c0, 0x7d8b838d, 0x658e50cd, 0x024a10be, + 0x455afa08, 0x80e5ca79, 0xa77b6bf9, 0xa3163eeb, 0xdc3f9cde, 0x8633d6ed, 0x6069f64b, 0x38902670, 0xe9d2a832, + 0x42c6513e, 0xc66efdc5, 0x7beefb0e, 0xdf517927, 0x82563546, 0xe50fe193, 0xc4b0302a, 0x0acb7000, 0x02bd6fe5, + 0x3083ff30, 0x6b77660d, 0xc3044397, 0xac166ad4, 0xb0615ebe, 0xc67d2220, 0x82eb0d10, 0xb1b7c24e, 0x8ae275b0, + 0x0ac06068, 0x96ef18db, 0xb30a2b96, 0x066f93a7, 0x77976f3d, 0xd87a7223, 0xeb47bc0a, 0xdc2f7b12, 0x106ffe31, + 0x0e21ce08, 0xc0f7ce61, 0x689b89d1, 0xde9e3ea7, 0x59c57099, 0x6d5fed9e, 0x3e365044, 0x70a4243e, 0xc8535417, + 0x495c6151, 0x4e85e803, 0x1143361f, 0x990f7a1e, 0x8ed9cb95, 0x8e0378fe, 0x41ebc5ab, 0xdebd4d44, 0x30d5d548, + 0x4d56b0e8, 0x9f898fc1, 0xdf77ea84, 0x072da66b, 0xe88a961b, 0x84f2b6a2, 0xb082d175, 0xde24936e, 0x1ed0030b, + 0xffb549c6, 0xed3039f8, 0xd5d8051b, 0x4ff80167, 0x849b1667, 0x86e7d112, 0xed17f06f, 0xf46546c0, 0x1c6ecfbc, + 0xd9f4494a, 0x0cc9d328, 0x1f3165e7, 0x249fb09c, 0xb133270c, 0xbc0178c8, 0xf20b4245, 0xf940a6d4, 0x4cfda579, + 0xf95e85d4, 0x98022941, 0x7ff9edee, 0xad0eda63, 0xb500db44, 0x270f9c66, 0xe41916f9, 0xbeff6302, 0x852d1daf, + 0x15cc81a6, 0xd408b973, 0xdc6598cd, 0xc2339527, 0x83e19b8e, 0xe4b299d3, 0x68fe4b7f, 0x594c1148, 0xe3ef32f7, + 0xd7dea727, 0x6e66f532, 0xae2d8014, 0x7b05b837, 0x95288601, 0x07d8c1e1, 0x24354437, 0xb6e6cd0d, 0xf9e11dd0, + 0x0fc7cc65, 0xe60b5fe1, 0x41d368ce, 0xfec069f5, 0xa26a6718, 0xfcaa3228, 0x811ea54d, 0x4296bd99, 0x614f1840, + 0x0a6647bf, 0x2de27724, 0x75007f13, 0xfb0e9892, 0xdf40c3b4, 0x4d4577f9, 0xfb900c70, 0x92bd8afa, 0x2fd2225f, + 0xadfd2ae4, 0x4435cbf9, 0x2694e787, 0xf07f15fc, 0xda2f7b07, 0xa183ae89, 0x5f05a649, 0x49667aa9, 0xb90a7fc2, + 0xe0b7f016, 0x3bdbcba8, 0x05dca51c, 0xd91122c2, 0x012d8d7c, 0xdde9277a, 0xa212ed59, 0xaedab853, 0x0e0251ed, + 0xbae4cbb0, 0xa9345b2e, 0x7bae43a8, 0x21843668, 0x7c5d5296, 0xba2eb74b, 0x3c0609b2, 0xb33f2df0, 0xd5fbb6ba, + 0x56c73fd9, 0x507a2c99, 0xb970a0b0, 0x962cbafa, 0x030a41b9, 0xc6a90ef9, 0xfdb129fe, 0x6710f146, 0xb156ae5a, + 0x71721733, 0x16815a77, 0x3a891fdc, 0x6c53bbee, 0x27761ddf, 0x9fadc9c0, 0xe69b4fc6, 0x072923a0, 0x01c073ea, + 0x00af7b8c, 0xcf197a7b, 0xabb179aa, 0xe7b46650, 0x151f4b75, 0x025a6e65, 0xa59e6629, 0x30b7a705, 0x3916ea1f, + 0x60e22b47, 0xca130005, 0x2dc76e75, 0x61f876db, 0xfe41a2f2, 0x2f8d4f9a, 0xd63919fa, 0x2dd8a856, 0xa8da9b52, + 0x07a91a7d, 0x23962a60, 0x01288d1c, 0x198ca6a3, 0x67f4e242, 0x1e00c787, 0x35d602c8, 0x6b810a8c, 0xaa817a89, + 0xac4ae058, 0x0057703a, 0x91dec2c3, 0xafe770ac, 0x863d7b70, 0x3ac9c657, 0x090a243d, 0x66ca3143, 0xb05ae15f, + 0x0ced08cd, 0x66683d0b, 0x90fb1978, 0x1a515307, 0xb0488e31, 0x5f991be9, 0x84f8f19f, 0x8a12e8b5, 0x2e11bbcb, + 0x2c90e536, 0x6179283c, 0x341a81e5, 0xf7dd48e8, 0x7f50f7d7, 0x348b6f20, 0xe8436c46, 0x70809b28, 0xa31c25f0, + 0x5412dab7, 0x80aadf52, 0x151d2708, 0xe50b083c, 0xc4242201, 0xc14422cf, 0xeab6e701, 0x368fb33b, 0xcdcb4916, + 0x7f54dd10, 0x76284761, 0xa41cf0ad, 0xa2074842, 0x018765e7, 0x77b9f9d6, 0x447b13ba, 0x9c9bc257, 0x7a07e8b0, + 0x338f340e, 0xffbb6310, 0x14b9822e, 0x9ec2189d, 0x0858462e, 0x131112e6, 0xc402cf04, 0x06f04f69, 0xd3c62909, + 0xb249d808, 0x4f9c2645, 0x2208bb86, 0x516e1c1f, 0xce112504, 0xad93fdc9, 0x524777d9, 0x1279b73f, 0x9997d60f, + 0xceebf9e4, 0xb243b26b, 0xfce7f6df, 0x21251b19, 0xe7d5ce8c, 0xb7a5bddc, 0xe8146664, 0x6e04deeb, 0x10198434, + 0x22e799ad, 0xa58f0fc8, 0x3a8cd25c, 0xc0323a31, 0xc3314dd0, 0x8571aa4c, 0x0e0698a5, 0xcb5deccc, 0xf00b0880, + 0xbd74bfd2, 0xa59d18b2, 0x8af583d4, 0x921d508a, 0x67d5d40a, 0x316e9b7e, 0xdcf770d5, 0x923cd917, 0xd37ae223, + 0x923115da, 0x6c8a305d, 0xa67ca22f, 0xea43477e, 0xb4d33c1a, 0x83b6ad85, 0xef87f864, 0xd278bf2d, 0x6fcfc795, + 0x93403d44, 0x41c715f6, 0x910a2f10, 0x2a9e40cc, 0x0df3ed31, 0xa09d4f10, 0xf0bae317, 0xd9a10daf, 0xb11efb9a, + 0x60b93129, 0x457ef9db, 0xb86f4eb1, 0x69680293, 0x4677b3f4, 0x6acf0abf, 0xe07d9855, 0x71631c85, 0x0c22db38, + 0x3e522bca, 0x67a58266, 0xc8a28940, 0xbfd9e02c, 0xc26ed2ed, 0x04c1b8f8, 0x54fbcce0, 0x2d91347c, 0xdee2e94e, + 0x42aa5c78, 0x311a269a, 0xaaf5272b, 0x0eb256ac, 0x6ea3ea7c, 0x4047c66e, 0xe9b6b6e9, 0x914a1d6b, 0x087358d6, + 0xdc3b7e5f, 0xf656624d, 0x079cd616, 0x3052f18b, 0x32895f6f, 0xa4c636c8, 0xf5c43436, 0x1ebc4b6c, 0x51476335, + 0x74b64966, 0x4d34edc8, 0xc4354b46, 0x4e9f6c27, 0x1aa4488b, 0x8c44964a, 0x67f5d859, 0x3fa119c5, 0xecffd76f, + 0xfc7c0fc1, 0x8606967a, 0x76b531a9, 0x37c0c059, 0xecffa0ec, 0x709a2a9f, 0x15436770, 0xb61f035c, 0x80b6a824, + 0x2d715597, 0x714763ae, 0xe6d40d6c, 0xf623f330, 0x268f2948, 0x5c4ccb98, 0x3af609cd, 0x75606f85, 0x314bc0a3, + 0x865d4ff3, 0xcc6c376e, 0xf4ad8e2d, 0xb52b7ffd, 0x09a14a3c, 0xcf530c59, 0xc53de3e6, 0x264b0432, 0x6e6d5306, + 0xcdd3109f, 0xd9bcdc3a, 0x225596a4, 0xe1190ff1, 0x79c7da44, 0x41365918, 0x780239ce, 0xfa90db8a, 0xf607dbc0, + 0x32949b53, 0x3e37925d, 0x8c1d51c5, 0x4924781e, 0xd24e4496, 0x3a66b411, 0x38a7167e, 0x7e87c69b, 0x1363cb4e, + 0xcbbd272f, 0x5ef0176f, 0xe450eef1, 0xae3e88da, 0x72f3a836, 0x3f2366a5, 0x86b890d4, 0x1bf2bd18, 0xdc15cd6c, + 0x15b46424, 0xc41f0b2a, 0xaafd5141, 0x5f637db5, 0x88e2da68, 0xe2713f0c, 0x3a7997bb, 0xc3f1181a, 0x7b5155e0, + 0x2d7a26fc, 0x58dcf1b2, 0x6e411af6, 0x1aa18f37, 0x50dd279e, 0xac3ab8af, 0x6c0d8cd2, 0xf0f25ef8, 0x0164394f, + 0x677f0cb3, 0xa2ace8b8, 0xfed74661, 0xc0258b56, 0xbc1ab35a, 0x4f78e60c, 0x57a8a9ba, 0x767500a4, 0x0785fbb2, + 0xab8b46d8, 0xcfdcd229, 0xa2962723, 0x598d6a2b, 0xe86baefc, 0xc728e64d, 0xd2d9a151, 0x8b6ca1ac, 0x963d8479, + 0xabe62a7c, 0x07ec4b00, 0x57cc954f, 0xec162a96, 0xdf78f0bf, 0xdab1b68e, 0x5e4f6134, 0x433a52ba, 0x682861b2, + 0x45f68c68, 0x3c89a336, 0x0728fe85, 0xe68edc3e, 0x0905800c, 0x98418202, 0xd0f695bb, 0x2b3decc8, 0xfea98758, + 0x0cd95ac6, 0xbcfa7ea2, 0x12bf8f04, 0x32f1c796, 0x1ddbe62e, 0xf579b454, 0x47d020c1, 0xb65197a3, 0xa8a536fa, + 0x860ab556, 0x9e65816a, 0xded62449, 0x47903628, 0x8fd10ff7, 0x53d7647c, 0xbec88936, 0xa5529217, 0x5f1b1cca, + 0xf4745145, 0x77a7e2a0, 0xb308238e, 0x5bed17bc, 0xd8e4a9e5, 0xd0332a30, 0xefc07bce, 0xdf42c265, 0x4f4196a1, + 0xe35e762b, 0x9e106ac0, 0xa17e68e3, 0x6d6ee617, 0xb97d7377, 0xe71f17b9, 0x1a0ddeec, 0x313655b2, 0x690dd0b0, + 0x6b620ae1, 0xf9a1c6d8, 0x3f342fe7, 0x02f850c0, 0x1e755393, 0x1b0a6f31, 0x5c9526e3, 0x4aca9686, 0xa5a7a21a, + 0x32995180, 0xf98641be, 0x6903b348, 0x814e9824, 0x527596ab, 0xbad5bf6e, 0xabd365ef, 0xf90b4774, 0xa584f89e, + 0x6d4c9877, 0xa0b1d244, 0x9dffda8f, 0x61cceba3, 0x1ae34176, 0x5684753c, 0xc56569a0, 0x7b59d17e, 0x43a8301e, + 0x92f58c7f, 0xb468a0ed, 0x3c9ec40b, 0xea5cb2ab, 0x52ce22cc, 0xace8190c, 0x474d535b, 0x9780bb5e, 0x52ef9e93, + 0x925f4f29, 0xde7dad04, 0xf881f750, 0x9bba8763, 0x4acedfa7, 0x2d672460, 0x14dd0be5, 0x9c7c38c8, 0x9a2c8ebe, + 0xe82caca4, 0x7680d6ca, 0x984927df, 0xf3df69d6, 0x0bc25267, 0x72200da9, 0x54161ef0, 0x146b0f4a, 0x5467da8c, + 0x7da8b3b5, 0x72a26704, 0x3aad1851, 0xfe73a222, 0x8e1ecc61, 0x267cd238, 0xf3ea8c27, 0x50feec63, 0xe8cdbb0d, + 0xd955e6c1, 0x14c55978, 0x529f439a, 0xefab68cf, 0xe62b0aec, 0xc355de81, 0xc1ead3c6, 0x8578d000, 0x80df0372, + 0xd6e4ea74, 0x6df71a74, 0xeea972ec, 0xd086d2ca, 0xb59c6408, 0xf32f68b8, 0x5529b401, 0x868561be, 0xd1a19b13, + 0xf6de65a4, 0x35d90372, 0x6a7e4a4b, 0xf9644dd6, 0x16c9bf35, 0x17d4655f, 0x53af020a, 0xb5c626ce, 0x574f4ef8, + 0x4b4bba07, 0x095aa3d0, 0x4b612d21, 0x2bcfeeef, 0x49c3588e, 0xa85a3445, 0x5d3e4aa8, 0x5ac91a25, 0xf1db8a20, + 0xacc1358c, 0xb2666740, 0x32daecb1, 0x0fc45e23, 0x690335b3, 0xc349627d, 0xb11bae22, 0xceb87e06, 0x50bcfdda, + 0x26714253, 0xb00f3ff6, 0x9cb69ca7, 0x0d4e12ec, 0x3c2413e0, 0x5cd56285, 0x6767bc1a, 0x485ad7e6, 0x2452c91f, + 0xd68469e1, 0x32ebc736, 0x4c62c7cf, 0x6f4c90b6, 0x080c4706, 0xe1c86f4e, 0x44a95095, 0xcb0141c6, 0x131e0832, + 0x34e13c63, 0x74826f2c, 0x247801b7, 0x21978b88, 0xa7cf2a20, 0x2c198e0d, 0x2e8a63b5, 0x56fe6e14, 0xdd18cc8e, + 0xbc14ead0, 0xc2fe8dff, 0x3abdefae, 0xa1e764c2, 0x6dfc0692, 0x8e6c9563, 0xb9716f20, 0x9079fe84, 0x900a9e46, + 0x5264c090, 0xb0cb977a, 0x40c0bc9b, 0x28370203, 0x96032e75, 0x1a9505a5, 0xcb155259, 0x885021a1, 0xc25ca2c4, + 0xefbd7b3c, 0x4be8bb86, 0x59698b33, 0x78744f54, 0x5ea6e24f, 0x5f219794, 0x1cb86b47, 0x9e1a761c, 0xa3a0b3c4, + 0x9e12046d, 0x3265821f, 0x656b7d6e, 0x304c5e25, 0xb03ef132, 0xda174624, 0xb4f68677, 0x21207a43, 0x0a0ac1c7, + 0xc43d1f9b, 0xce5aa940, 0x7c0653e9, 0xb2a57841, 0xdcb52ddc, 0x926dcd9f, 0x1dcf685e, 0x5e43ca3a, 0x763efbbf, + 0x60c06715, 0xc0f30d5c, 0xb6503aac, 0x4a5d0997, 0x2ab02c0f, 0xd5acf438, 0x7402b40d, 0x35fbb3c8, 0xf169028f, + 0x67cfc105, 0x5cbd0376, 0xd3bdc1df, 0x0fb576ae, 0x496a204f, 0x5061d816, 0x1d03ebd0, 0x66e38e81, 0x7e24f43f, + 0xa21e9d09, 0xbdebbe3d, 0xca6a9a25, 0x657db71a, 0x92058f6b, 0x1517f0ca, 0xd726852f, 0xb02605f5, 0x7d693857, + 0x51d1d6e0, 0xc62fc5d3, 0x7e9bca70, 0x0581e23b, 0x5f6108fe, 0x38cbc0cb, 0xc2373925, 0x9b8be30d, 0x17f67762, + 0xd6ecf7c3, 0x9a62474e, 0xd9b4eb2c, 0x9d2f4aed, 0x3d1b822f, 0x88e75866, 0x290c23a7, 0xb7f8d1d9, 0x17b00489, + 0xecc506e1, 0x40d0f3e4, 0x78748120, 0xdd0e52dd, 0x9a4978b7, 0xb213cbd1, 0x86d31077, 0xe44eb414, 0xf1aa02e9, + 0x43e7b203, 0x88f309ac, 0x83c8d287, 0xfb3d8964, 0xcc3cbada, 0xa26cdc0f, 0xafedf7c2, 0x6050e982, 0x888ddef0, + 0x8fa36460, 0x85d57498, 0xf732eb4c, 0x77f988c0, 0xc6128431, 0xe3e88d60, 0x4326aa80, 0xb15c45ad, 0x2bc028d1, + 0x52fafa8a, 0xc8521d3c, 0xff1a066b, 0x3bbf6af7, 0x9cc7a992, 0xc65f1859, 0x92fcd4e9, 0xaab761ec, 0xc0e4d51a, + 0xe525dcc7, 0x6e728e76, 0x2be4462a, 0xa53c56f7, 0xe9acb2f9, 0x1991ff6c, 0x32f38ed4, 0x797ba257, 0xdc509df8, + 0x346a93d9, 0x6a0a5baa, 0xe5d72ae8, 0xdb9f2a98, 0x7ea57eff, 0xa25c6da7, 0x7f3a8872, 0xf21599a9, 0x57269965, + 0x27b4bb23, 0x555ecf25, 0x1e4cfb89, 0x1a1fc839, 0x97cd36e6, 0xf725ccfb, 0x0a205c72, 0xbcc1694d, 0x76ac475c, + 0xbba0d5f7, 0x8603a73b, 0x67d8fcf8, 0xf04195ce, 0x28b49eb9, 0xde1a76f2, 0x6555ebdc, 0x307731c3, 0xebc80972, + 0x9fe8490d, 0xa5e446be, 0x3004303a, 0x57131502, 0x6b90927a, 0xf85139b5, 0x25ce0fd3, 0xa5b3515e, 0xb2681082, + 0xab2ee557, 0x7a3f27f8, 0x651c886f, 0x58a8bcc5, 0x37ec2b24, 0xb65c8cec, 0xf29baa96, 0x45bab858, 0xe7359c16, + 0x18436888, 0x78ceb1ee, 0x67f2338e, 0x042a8726, 0xcf9ce008, 0x9d505913, 0x799577c0, 0xa4beed96, 0xe7715ad7, + 0x2142aa94, 0xfb9138f3, 0x454ba5d1, 0x1b18235b, 0x85b10633, 0x93361b67, 0x53b1907e, 0x32da9de5, 0xf296aacb, + 0x9dfcbf6d, 0xefe8dc10, 0xd759ff86, 0x3cd645a4, 0x656b786d, 0xc7b538a1, 0xdd860df1, 0xd028bc29, 0x34b9956d, + 0x4a586c60, 0x47a6ccdb, 0xac96ac65, 0xa31e0354, 0xf51089d0, 0xe218d563, 0x727df2a2, 0xd90fa4e6, 0x23d78228, + 0x260269b8, 0x53025424, 0x4fb2dca5, 0x23be2884, 0x96f60cd9, 0xe433b512, 0xbcb93ccf, 0xeeb39fc9, 0xd19cf024, + 0x23ed8e3e, 0xa4fa1134, 0x33693a16, 0xeda3ef9b, 0x861fc6dd, 0xa899db32, 0xe108bc61, 0x5c4d0e91, 0x1c7b57b7, + 0x7c06f2fa, 0xbdeaf513, 0x3ac98bfa, 0x766746ea, 0xac30bc23, 0x1522bae9, 0xed41166b, 0x1908c28a, 0x27969999, + 0xff1cd9e6, 0xef64dda3, 0x0d9111d2, 0x02f3bae4, 0xe83adaf4, 0x3104cb8f, 0x6b8974cb, 0x22172c06, 0xaca59444, + 0x790ac649, 0x1482821a, 0xb8f9c2f2, 0x5eb76bc5, 0x6c66b163, 0xbd6b3b84, 0x87796fed, 0x930533c7, 0x81e26433, + 0xe3fc37ec, 0x44f137fc, 0xaf0d7ff6, 0x01da2429, 0x0c57dd26, 0x7f2c4ff0, 0xb2c050d0, 0xd1b3a987, 0x802da26a, + 0x6eee9738, 0xdc62c82f, 0x267a5e37, 0xc5126b43, 0x981e9bac, 0x6d3cf404, 0x19681a39, 0xfdb8243f, 0x0a91a4a0, + 0x355532db, 0x3e4339e7, 0x5048465d, 0xab2c2db0, 0xd0559060, 0xf249ad37, 0xf8ebbedc, 0x8ed2a5bd, 0x4268e18d, + 0xfb1a14cb, 0x373f7f40, 0x957b48dd, 0x1978be9f, 0x446ecbd6, 0x6be18f32, 0xb00a4b67, 0x66451f3a, 0x73836f06, + 0xe067a5e2, 0x12eaadcc, 0xdf6428c1, 0x3fdd57a0, 0xde80886e, 0x9e3ea27e, 0xe7d3d1df, 0x4b571516, 0xcf2d01d7, + 0x9f3b0c59, 0x0ac54bd2, 0x2785083c, 0x94a1e25b, 0x92955e76, 0x88005fc4, 0xbbe9d47c, 0x1c5862e9, 0xacf8bc8e, + 0x3128acb6, 0x977966cf, 0xf676393e, 0x25f5591e, 0xe7239aef, 0xf181afbf, 0xd4e6a72e, 0xa79c1476, 0xb424f810, + 0x255ea672, 0xa7b20316, 0xfef83238, 0xf8bd4ed9, 0x4ec5bcbe, 0xf4d119e0, 0x41fb24c9, 0x7eef7a3c, 0xbe481b7d, + 0xda4f117a, 0xeba88902, 0xd66ab249, 0xe740ef03, 0x967fa099, 0x2087d3ac, 0x64bbd0fb, 0xe54f559f, 0x096f25c6, + 0xd7f525ce, 0xcdef5bf2, 0x0d33d812, 0x9bdc4635, 0xa166e80e, 0x922d076d, 0x41596028, 0x80bbb2be, 0x01d78fa3, + 0xf0693a7f, 0xe772e8e6, 0x411510b2, 0x869c36c6, 0x082e2a07, 0x39dfebcb, 0x7db5f80c, 0x7da3daf0, 0x441f7914, + 0xae05354f, 0x58d4321b, 0xe6934d97, 0x49a571f6, 0xb80071b8, 0x05dac2f6, 0xc3ce6f6b, 0x893cf4c6, 0x1b0919b0, + 0x276bf4cc, 0x6ae1f6a8, 0xeae24b74, 0xdf509703, 0xc96d4bf4, 0x01693afd, 0xc9b08d52, 0x6ae64139, 0x03a1f2f6, + 0x719f963a, 0x08e9cd25, 0xa6721cf4, 0x4175a248, 0x9ac084f7, 0xf4d9bca0, 0xb978f4e2, 0x251230c9, 0xc58ef797, + 0xd4bf0a45, 0x3cfa0382, 0x3dd44093, 0x64bac50b, 0x9f381660, 0x974029a1, 0x18e485c8, 0x07b3d99a, 0x2bde3213, + 0x3b501ada, 0xfe56e355, 0x8f227bfb, 0x811b054b, 0x3a8d3d6d, 0x6b21f64d, 0x098446be, 0x70e7360d, 0x0893dbeb, + 0x9b4e4186, 0x3a71bb26, 0x115ab05e, 0x6913884f, 0x3b57dae9, 0x64fa9d8d, 0x773e7c84, 0xb4e0f661, 0x23982832, + 0xb2a0a2f6, 0x640df933, 0x8731f714, 0x369756d1, 0xb68bd5aa, 0xf8abc99a, 0x6993f3c7, 0x8af68966, 0xc09df2be, + 0x6e6e3e36, 0x745cf449, 0x034802cd, 0xedd4f56a, 0xd99380cf, 0xc55f28a9, 0xcef85b2f, 0xbf4d0ba4, 0x3602ce32, + 0x1c96f536, 0xd56a39b0, 0x70acb901, 0xabb1489e, 0x4a7d06c0, 0x2ac38ebb, 0x48d99756, 0xf96f3843, 0x97be8497, + 0x17879809, 0xcdd81ecf, 0xf0e35231, 0xdbb97991, 0xf22bfd0c, 0xab619a5a, 0x444e8a49, 0x1e4ee69a, 0x178c20e3, + 0x7901fa21, 0x3f3e5d09, 0x3675692b, 0xd862c79b, 0x78b040c7, 0x2dca9214, 0xe050c12e, 0x27b35c5f, 0x587fa465, + 0xae4fc16b, 0xf46aee1f, 0x50fa793f, 0xaa48a660, 0x997e338f, 0xb9fe2b08, 0x1b68406e, 0x4721f3f2, 0x97c89559, + 0x9bcd8043, 0xf9452bf3, 0xd6d771a3, 0x8ce298f8, 0x285153ef, 0xc152eecc, 0xd308571f, 0x7d16b520, 0x22e7955d, + 0x4313e623, 0xd80ce4de, 0xe20fc188, 0xb846459e, 0x465b20b9, 0x037a94b4, 0xda8c9384, 0x00222bfc, 0xedf13b89, + 0x6542aede, 0x27c9cfad, 0x979777df, 0xc213afdb, 0x03311d48, 0xeae848d6, 0xed850286, 0x6eb2339a, 0x79c64cd8, + 0x1b0df5ef, 0xda8e2fa1, 0x87509f8d, 0x98b31711, 0x22b10fda, 0x93db4b1c, 0x6ebe5f8a, 0x0d61e141, 0x1185c1de, + 0x83eca815, 0x7f12fffc, 0xa6decc8e, 0xc6613e83, 0x77984e9a, 0x17a997a0, 0xc48833c2, 0x2c8dc8cd, 0x4dcba771, + 0x021d1442, 0xdba41a79, 0xce498bd7, 0xd8bc7776, 0x05325b47, 0xcf7e9a9e, 0xe7908bee, 0x12d7971f, 0x32707317, + 0x054c450a, 0x231eeddd, 0x349b3476, 0x24bf6aa3, 0x5ba1994d, 0xc16e2848, 0x1129be3a, 0x8bf0eef1, 0x94816a74, + 0xef908946, 0xf793f113, 0xc8433ec7, 0x8a9d18f5, 0xc73914fb, 0x7e310e67, 0xfca9c196, 0x2ddd7566, 0x53d048b7, + 0xe791e487, 0x6542f35f, 0xd490b9b3, 0x18f6a2b9, 0xe12e824c, 0x478a8e08, 0x7b6e8530, 0x5e8cb291, 0x2076f714, + 0xaf58254e, 0x85b1d00c, 0x6b9786c4, 0x28357cb8, 0xcfcee1d4, 0x8fec05f4, 0xb9ea3fd4, 0x025c1866, 0x97622aa6, + 0x6d424a76, 0xe71e5f87, 0x0f5ba69e, 0x81807f0f, 0xe705f64f, 0x587f2ecb, 0x6cc81c07, 0x6174b809, 0x2cdf8444, + 0x1541664b, 0x5425316d, 0x66bd4a21, 0x8ff6cc0b, 0x18867fc0, 0x78171992, 0xbd3269c9, 0x61c5cb27, 0x1ed264b2, + 0xcb73943a, 0xb779d22a, 0x0d5b4742, 0xb17f59f1, 0xea13d62d, 0x8bc3ea57, 0xe960a0f0, 0xb5694607, 0x6da49377, + 0xb61dcee9, 0xd34744c7, 0x0674359f, 0x18bdaeee, 0x4704f3ed, 0x34d148b8, 0x0eb34f77, 0x979acfc4, 0x56e78671, + 0x943f9559, 0xaed87ef6, 0x6222ffec, 0x1780ca1b, 0xf2611b1d, 0xdeaaa7b3, 0xbd8b232a, 0x1515ce6a, 0xbd9e9efb, + 0xb700dd63, 0xc2905613, 0x4918a97c, 0x70014db3, 0x2ceb9616, 0xaed95f0a, 0x82f64937, 0x9345cf04, 0x4948b452, + 0xaf858bc5, 0xb72bdf83, 0xe21e03cc, 0x729bbc9a, 0xcf024564, 0xdbc41665, 0x44d81532, 0x7e69ab50, 0xb9afc16c, + 0x0af05408, 0xc52f83a4, 0xb6847337, 0x9dfe3b27, 0xe4205c1c, 0x01582dec, 0xe4ef913a, 0x0a09dad8, 0xf4db3501, + 0x497c212b, 0xc45cf310, 0xc0b975e6, 0x4838ca06, 0x37a57756, 0x1b176b7c, 0x479e44f2, 0x57b959ad, 0xf9ca71fa, + 0xa0002f16, 0xf961eda7, 0x91e090c1, 0x0d3fe90f, 0x4af1a6b8, 0x2c9475b1, 0x3ebcab8d, 0xc18a73b5, 0x20e52ba7, + 0x21beca4e, 0xb5c7f9d2, 0x85a764e7, 0xffabec5d, 0x6cb49e9f, 0xb78b191d, 0xe40d1ba7, 0x92e458a9, 0x509b5b7c, + 0x20d79092, 0xf5a9b23e, 0x6ef84a32, 0xfb965a55, 0xbe19e449, 0x61084a83, 0x9e46be8b, 0x0cb7df60, 0x7209ae78, + 0x272b151f, 0x203caa9e, 0x0c2e6829, 0x73f2af29, 0xa33bb024, 0x9c93fc86, 0x4bbcad30, 0x54127b5a, 0x6add3165, + 0x1792c30b, 0x9df694cd, 0xabbe5e7f, 0x4077e185, 0x0c342ee7, 0x0efaae21, 0x9911e44f, 0xd06dd943, 0x3cbb7043, + 0x40f42e2f, 0x8242abb1, 0x30751f7d, 0x98266a8e, 0x7d1e9926, 0x96617b8c, 0x3b422f69, 0x118b738e, 0x53c658e2, + 0xe24ea87e, 0x0797f80d, 0xdd05cc9c, 0x7bde4473, 0x96574064, 0x3c68fed8, 0x4215d35e, 0x9d76463f, 0x227d7526, + 0xf83868b0, 0x82003ce2, 0x421a0c5a, 0x47fee635, 0xc41cfa08, 0xf4853b94, 0xbd8498bd, 0x1295dd48, 0xba5be095, + 0x8ac253eb, 0xb40aa16e, 0x58826f36, 0x6d20f58d, 0x864c2a49, 0x5a1eb887, 0xbeb004b3, 0x824df311, 0xdbeeceb6, + 0x471d5085, 0x33853387, 0xea3e80ac, 0xec7c927d, 0x34c7f6b6, 0x55475d80, 0x1c657cf5, 0xe390fa44, 0x1980f742, + 0x6cffcae3, 0xe5bc5956, 0xf471832c, 0xe33f7cee, 0x8e2dd168, 0x0cda7e35, 0x095667b8, 0xb6d815f4, 0xefff6126, + 0xceff5c6f, 0xd8071ca3, 0xfa03f9b5, 0xd38f0e66, 0x0fbac5ff, 0x0a0008e0, 0x8c3518d1, 0xaa1fa890, 0xdeb23cee, + 0xf26b7afa, 0xc3cead74, 0xed291f0b, 0x8ed1619e, 0x7d0e7371, 0xd7a573e2, 0xd6cc463b, 0xb0193503, 0x54b59e1d, + 0x788c84f1, 0x60996226, 0x1a13ae8c, 0x6b92a81d, 0x7d8c17aa, 0x75c641a2, 0xd7b4fa71, 0xe4b810d0, 0xde26f3f3, + 0x897496b1, 0x4e6d109d, 0x74140b2a, 0x781ca1d8, 0x651e5694, 0x52fb5bf0, 0xef415981, 0xd82de10a, 0xa9f8b1b1, + 0xd3f2625d, 0x5019d868, 0x8940eb38, 0xb8e51291, 0xc4973741, 0xe81f1f3a, 0x943706b5, 0x08afa4b1, 0x2aaeebe0, + 0x29384030, 0xce4e6b05, 0x4787a89f, 0xa615a9f0, 0x7999e6f1, 0x2013fa1d, 0x76e9528c, 0xf9baac72, 0x19094497, + 0xcdf5dbdd, 0xbe63bf73, 0xa645ba66, 0x21ff3740, 0xb5eb9858, 0xfa8e75bc, 0x225fbca8, 0x89d9b256, 0x7e98e2bd, + 0xd4ad892d, 0x73ba4612, 0x470e2217, 0x959f12ac, 0x7c463386, 0x3a494590, 0x80337054, 0xbee9e80b, 0xc8fe2671, + 0x32a84e93, 0x92f60e85, 0x54aef2a9, 0x3cc0ae89, 0x53691ab7, 0x2072d5e2, 0x3a9d555b, 0xca7ebd03, 0xb512d6bb, + 0xe4867767, 0xe8b1d3d6, 0x79491891, 0x02e81df5, 0x3bc16a78, 0xdfdff679, 0x41bf6816, 0x1bc00d90, 0x359c99cd, + 0x6c84f3a1, 0xf8d58246, 0x68216b1c, 0x847e1cb2, 0xf109bf6a, 0xe78841f9, 0xda609bef, 0xd4f2a4e5, 0x0afe9a61, + 0x7b8040fe, 0xa2f3ba60, 0x22478805, 0x33d21ce2, 0x3d73dc12, 0x2ceb3663, 0x507a3ccf, 0x97625faa, 0xcca51f11, + 0x5372b264, 0xe365d25d, 0x2579dc9b, 0x2ee2d46c, 0xd0da7e8a, 0x095009cb, 0xbe9080c6, 0x7acdd2e9, 0xe261b705, + 0x1744ff28, 0x7c2ffd5e, 0x8c96feb9, 0x6b32bcb4, 0x245b1bf6, 0x5ceff342, 0x18b6fa2f, 0x6ae45037, 0xe0ac2ff3, + 0x16515ee6, 0x4400b786, 0x77197dff, 0x0f7f9b1f, 0xe628562d, 0xdf1c86b0, 0xa64b095e, 0xebee57ae, 0x8d5625d3, + 0x656b4f3f, 0xee6f426f, 0xf6c69a01, 0x68ec9b70, 0x2447976d, 0xa68157ac, 0x270e6539, 0x5e190865, 0xac9e3563, + 0x92d0d4aa, 0xb0d0392a, 0xf202cf78, 0x26b09886, 0xc7335f86, 0xdfdab706, 0x92514fed, 0xfc7d976b, 0x0bf8c65c, + 0x8225789d, 0xd706b9b6, 0x91892d87, 0x1f18abf8, 0xf1afcfbd, 0xc6374320, 0x5a414d86, 0xdc649552, 0xa9586e41, + 0x9c26dee8, 0x90037b57, 0x385e61f8, 0x5b4b0fb8, 0x7f449c52, 0x7215998a, 0x073b74e2, 0xd9c6ce44, 0xdd150426, + 0xdf37d8b1, 0x2ca69425, 0x00c9a320, 0x36c5c8b6, 0x4546ee3e, 0xd26eb61f, 0xb62a3cfc, 0x0039ddfa, 0x5533dd5f, + 0x4737433e, 0xcf4ff6f1, 0xa3b11d07, 0x5f1a3c3d, 0x0f06cc4f, 0x779079e1, 0x8e4c6b5b, 0x533613cb, 0xcdec85e7, + 0xf3b91b3b, 0x6759190f, 0x760b0000, 0xe1595a39, 0x1160d6e8, 0x6417d6cf, 0x85f4638d, 0xafe10c4f, 0x7b430e8c, + 0x2993ebfa, 0xb0eb6014, 0x63f8d95e, 0x3bfde39b, 0xbfd14cba, 0x5375ba44, 0x19013e9f, 0x4422f376, 0x3cd1cdc5, + 0xf480fa46, 0x7963d935, 0x02c1a8bf, 0x56a49e87, 0x9861f132, 0xd684ef8b, 0x5bec1679, 0x4a0a7247, 0x0d978cc7, + 0x555e440a, 0x7b536b91, 0xbb2cc3a2, 0x651bedd7, 0x6ac6d0d2, 0xb84577bd, 0xd0d8a1a0, 0xd47e4a3b, 0xa2067e14, + 0x0785189e, 0x7bbda375, 0x781fcdea, 0xacdd77e9, 0x1983a4da, 0xd294f715, 0x178f27ef, 0x26d2df13, 0xc166ddd2, + 0x13a14adf, 0x1bbcad8b, 0x0fe7d8fd, 0x4c712e21, 0xc7f7aee2, 0x86e9ca07, 0x119841d4, 0x3beb4b80, 0x6fbd0067, + 0x616bd835, 0x3d178378, 0x26f273dc, 0xa5d1ec1d, 0xd25f3549, 0x8529e162, 0x37601896, 0x7f113980, 0xd5477421, + 0xe455a90c, 0x23954a31, 0x6d5ff858, 0x92e9d18e, 0xecc3afd3, 0x32615cbc, 0x5ee8d4da, 0x5400cdd7, 0x8f7c2ea1, + 0x92eb83dd, 0xbc936350, 0xd5321ba4, 0x2042a089, 0xc898a9f6, 0x806b7c97, 0xada7473b, 0xf6e75160, 0xcfc08cdc, + 0xed7da8ae, 0x21369596, 0x3b77b280, 0x0203d3d7, 0x00c9ce88, 0x5c91dd7d, 0xb04f6ba3, 0x30bec322, 0x125890d9, + 0x8496e7f4, 0xa47cc141, 0xa1405a26, 0x90fc6ce4, 0x9af0bdb6, 0xf06cba66, 0x1a4eba09, 0x4444f3f8, 0x18146b4e, + 0x5d80bc3f, 0xe72325e2, 0xc69dc8da, 0xce5b5547, 0xc6944d32, 0x83450720, 0x15b1dbe1, 0x31ea59f7, 0xbd00c8ad, + 0x75f470a9, 0xe441189b, 0xd4aa5cba, 0xca19ccd4, 0x92776634, 0xbd1ef82c, 0xf1af3599, 0xc5d0dc6d, 0xb8491d06, + 0x3d5c07a8, 0xffd23c31, 0xd35bc11c, 0xa5897180, 0xcb358a45, 0x00b4604f, 0x3009daf2, 0xa5b415c4, 0xc5297650, + 0x1a64ce29, 0x114f26e4, 0x813ce7c1, 0x9f245880, 0x517b3c96, 0x298bdbfb, 0xb8291e68, 0xe1c89077, 0x7d96a95c, + 0xf10172d8, 0x27e0d3ad, 0x76331fb0, 0xc457bce9, 0x11d00723, 0x25e09634, 0xa7a44cdb, 0xa56af24f, 0xe72dc006, + 0x4bf82588, 0x66987637, 0xd6a2d990, 0x937ba348, 0x84cf72c1, 0xc9117bdb, 0xf52ea329, 0xf71e7c03, 0x75e17da7, + 0xe4efc48a, 0xa83ca6c1, 0xccf17853, 0xefa11946, 0x45a760f2, 0x3541a574, 0x4d60426b, 0x07bddc4d, 0xc8e45549, + 0x02e282d7, 0xdda96ed5, 0xbab63d94, 0xc9bbf180, 0x5dc2bc26, 0x0d3e69e5, 0xd902077f, 0x3eda163c, 0x256c77f9, + 0x7ed51e0e, 0x327ba0d6, 0x9ad12e42, 0x74edeada, 0x8e8f6d28, 0x01c3fdab, 0x45460798, 0x1e2f3d80, 0xa3fcd2df, + 0x727a41a3, 0xe8c1510a, 0xc8956518, 0x6d7adbab, 0x922fd2b1, 0x168779d3, 0xc0afb21b, 0x38b421e1, 0xf18e07b1, + 0xc2c41e06, 0x18754761, 0x9507b822, 0xe5d1913c, 0x2fa088c4, 0x5df29db8, 0x1d18da3d, 0xec6a3f1a, 0x7a130d9d, + 0x5499a18d, 0x44ed3570, 0xcc57b920, 0xe61a6b39, 0xf08540ef, 0x7f8195bb, 0xf568a945, 0x7eec3832, 0x0bfd4af1, + 0xf811099b, 0xae68a1ae, 0xe3cb90f4, 0x8c19d19f, 0xb62c9094, 0x4ffb0499, 0xb890f027, 0x5e7c9d8a, 0xfbe1e110, + 0xf5cfd9ce, 0x959d8a28, 0x2e1f79d6, 0x3a4e81d6, 0x1202973b, 0x391e5fc4, 0xff3b5941, 0x73a210c7, 0xe79e884b, + 0xcb0a031b, 0x48129e6f, 0x20f32176, 0x75979e16, 0x97040b50, 0x69cecf34, 0x552a0be3, 0xd0ebcdf2, 0x71b2d26b, + 0x43bff19e, 0xb8d0be5d, 0xa75e0565, 0xb0eae31e, 0xafd8150e, 0x03ec48b5, 0x3ab7370a, 0xbffe6678, 0xe19acb49, + 0x7342825e, 0x7bc0c96d, 0x55ec4361, 0x799b6a54, 0xde744b38, 0xc17628da, 0xc985d966, 0x9c52481d, 0x0b91f9c7, + 0x2772a411, 0x0bff93ce, 0x04c9cad5, 0xadca1fba, 0x1449b552, 0xa40002f2, 0x1a6656b4, 0xd0c6db09, 0xe0a924ce, + 0x6d274241, 0x68a5cb2e, 0x1a1b6207, 0x6e920790, 0xed74d557, 0x6de99a2b, 0xe6249393, 0x66c6ef23, 0x652499aa, + 0x3c12cc5c, 0x49530156, 0x32b1033b, 0x66681a46, 0xa5f51a82, 0xaae7705d, 0x4afd8a96, 0x494be96e, 0x10526f24, + 0x4dce92de, 0xb0cd6756, 0x50d5cf43, 0x2f417035, 0x11f8a7c1, 0x45689758, 0xd0133e69, 0xa9e2ec7e, 0x86a9eab6, + 0x4bd759ad, 0x9a993e2f, 0x2c940eb0, 0xb10f73e9, 0x61269d67, 0x02b8f811, 0x42b11269, 0x4a4dcd15, 0x2cabd025, + 0x4992baad, 0xe8d76017, 0xda2088bf, 0xf24d1d4d, 0xbaa747da, 0x66b659f7, 0x60c2a681, 0xcf5a6c41, 0x65183020, + 0xa06eda11, 0x5ae247a9, 0x36669d10, 0x3f3a5eb7, 0xb487268c, 0x275b01d7, 0x9242eec4, 0x6c64e9e8, 0xb380d62c, + 0x76056d55, 0x8500c774, 0xac260549, 0xda46d7e5, 0xec2f3cff, 0xaa85d6ad, 0x8d12ce69, 0x06ade850, 0x3be57d1f, + 0xf1195297, 0x835207fd, 0xea69a5e9, 0xff922ffd, 0xcb3cb265, 0xa7596f56, 0xb489e9f7, 0x7e122f3c, 0x716ac0f2, + 0x65448929, 0x811f4127, 0x454707f5, 0x149048d3, 0x3cc1c498, 0xedd7ddec, 0xdd49dc0b, 0xed7d68d8, 0x463e074a, + 0x6af96ced, 0x2afd7ab8, 0xeaeb3795, 0x35bc23c4, 0xf74fc5a2, 0xe6ee1931, 0x3de60073, 0xfce7a4b5, 0x4309434a, + 0xd74ea5aa, 0xa9fb7b31, 0xe39497fb, 0x57093e7e, 0x05548028, 0x42fa7dc3, 0x09792f20, 0x5fed1074, 0x3ebc4f98, + 0x5ed8f1a1, 0x0b09e6ac, 0xbec23efd, 0x60424f76, 0x67fd7574, 0x87a607cc, 0xae02b01c, 0x0995d35e, 0x525271a8, + 0x21673e19, 0x60ca18c3, 0x00f826c3, 0x787b6ee3, 0x19bc8df9, 0x7e247b8a, 0xa383d1d6, 0xdba936ce, 0xd6ab1d46, + 0x065fef60, 0xfb65a5f0, 0x15e0e80c, 0x7803b39e, 0x0bfa7891, 0x2c517c90, 0xeda590dd, 0x8333cecd, 0xf94f6082, + 0xb27a1c58, 0x7fd93a08, 0xf47ea873, 0x43c59982, 0xf13f0901, 0x17eca436, 0x1faf9b4a, 0xb2361738, 0x2abe76b7, + 0xb1a11178, 0x2743beec, 0x9472b59e, 0xa31c13b1, 0x235deb14, 0xf947a62f, 0x7bfe9de8, 0x869e6ad0, 0x1c9633c8, + 0xa55010b2, 0x444d2d39, 0x177b5c00, 0x294eaef1, 0x625ed506, 0xea885c7d, 0x4ea8def8, 0x845399a6, 0xc4591d57, + 0x9685c798, 0x2c61ceda, 0xacc977a4, 0x6867d8ec, 0xb5a9786a, 0xffbf122d, 0x59e08592, 0x9a46e630, 0xc77e87f5, + 0x97f10407, 0x9604d752, 0x27b2bc96, 0xd7d5752c, 0xf0474d9c, 0x400059cc, 0xfa0e40f4, 0xa25f4a42, 0x4c889dc4, + 0xc9509858, 0xad782ba3, 0x02f406f3, 0xd20fc214, 0x4c4e6ed5, 0x735ddc0d, 0x615380d5, 0x15c9c541, 0xdb006ece, + 0xc344fd7b, 0x533ecd41, 0x27a44302, 0x3f7d8222, 0x8a957dc0, 0x63ffd8ae, 0x37234575, 0x244eb856, 0xd841fcc0, + 0x5a525136, 0xf22af122, 0xb5cf9d4d, 0xbf28b352, 0xc77e2750, 0xe6f93b6d, 0x608ce134, 0x85fdfc3d, 0xe3ea2418, + 0xa0e28087, 0x8ed8c74d, 0x63012dd1, 0x4bb3ef4f, 0x00791be3, 0xe1f7e7ce, 0xbdd1346b, 0x582d0272, 0x7cccf839, + 0x72d1cc28, 0x4d709bcc, 0xf9667a53, 0xf92bd13c, 0x816c720b, 0x5291808c, 0x6d89cff2, 0xfe8120e2, 0x8167897f, + 0x99ef41a7, 0xde6fe43b, 0xa1ff0a46, 0x19bc6b32, 0x7cf53f29, 0x50a79230, 0xf60e4ec1, 0xdf4fd858, 0x6bdf34cd, + 0xaa28aa43, 0x928aa7b4, 0xb1621ddf, 0xd1b220cc, 0xff28ccec, 0xfa54027d, 0xf5811c42, 0x783cc71d, 0x7639b4d8, + 0x09301525, 0xe5c32bc8, 0x6b37e4a2, 0x06d9f0e4, 0xd7252137, 0x7608651d, 0x262a44cb, 0x985a95b3, 0xfcd40a6d, + 0x0ba40467, 0xa503dee3, 0x148c4439, 0x1116f6b1, 0x724047c1, 0x45289bde, 0xd689a6a3, 0xf5908cb0, 0x06edb597, + 0xc28d19b9, 0x11dc9abf, 0x7cc523a5, 0x396b7482, 0xe3bca646, 0xd380a9a8, 0xe393e30a, 0x3efb5345, 0x6020bbcc, + 0x930070bf, 0x28a316a8, 0xfd642a52, 0xe6ccd4c9, 0x0b29521e, 0x4e3e3513, 0x418f21d6, 0x1b13e9c8, 0x343945b1, + 0xcb6551d9, 0x5b0db379, 0xc5c2d656, 0x0719561d, 0x4b3af43b, 0xf0d8147f, 0x9714dfa4, 0xf461f440, 0x2152b80d, + 0x6f75cc8c, 0x8b4affbe, 0xb786accb, 0x10dfbdef, 0xc8ec440b, 0xe7d92df1, 0xa962b4b5, 0x29b5e5f9, 0x903af8fc, + 0x1df99a39, 0xe9a11bf8, 0xb8e329ad, 0x07c61908, 0x643e9e15, 0x5c433954, 0x3737d932, 0xe9b82d7e, 0x11a3815d, + 0x789c703c, 0x408c64bb, 0xe8eeccaa, 0x890cbef1, 0x3bf4c3bd, 0xfc6050ef, 0x2c1e413c, 0x7cebe7ad, 0x8ea9c590, + 0xeeb389aa, 0x6d512536, 0xf9dac2eb, 0x60833120, 0xa9c3022b, 0x1a2c85c5, 0xb258684a, 0x3cce4e58, 0xc955b8c2, + 0x06b26496, 0x616e8922, 0xddc7c162, 0xfdbe5661, 0x4ceafecc, 0xcf083802, 0xeebcaca8, 0x3801ad61, 0x5292bdce, + 0x52e7f9ad, 0xdbc6bf1e, 0x4f9b4eb4, 0xc198a788, 0x41835278, 0x51c9245a, 0xac5dcf8a, 0x89fbe0a1, 0xe5696bc8, + 0x832e3385, 0xf87e6662, 0xb6c43c42, 0x7a824bff, 0x715f00c7, 0xc08cc0c7, 0x74e2e71c, 0x2d97a848, 0xe6ece5fb, + 0x18fd7204, 0xde3003c9, 0x2d78062d, 0x9c499a3f, 0xb474a204, 0x093a881d, 0x9911e580, 0xc20e7963, 0x68f01ded, + 0x9ae2d5ba, 0x220b78ba, 0x86bd1e45, 0x948aa970, 0x5f2a675c, 0x5b59fc5f, 0xc09a30af, 0x8382feeb, 0xcaea5b83, + 0x84b2c4e8, 0x9568cd84, 0x06d5ac07, 0xe92e2248, 0x1b86676a, 0xdd82bb6b, 0x759a3a73, 0x7cc3d279, 0xa8958e9a, + 0xf8182b54, 0xc77376aa, 0x31924ac9, 0x846c09d5, 0x746e843f, 0x0584d5dc, 0xd6da8db4, 0xb5f316f4, 0x492029b0, + 0xc5022f0f, 0xe9e20bd9, 0x0bd0657e, 0xdf563307, 0x3344a085, 0xec02efc1, 0x3b516aa6, 0x00a9bbc3, 0x53f12e24, + 0x5eef1407, 0x8c255fec, 0xf5cfb46b, 0x5875be5d, 0xedec430a, 0x8391e7ea, 0x2b9d2046, 0xe3726921, 0x0f263acc, + 0xe963adf4, 0x2e7fb184, 0x06a998a1, 0x64fe8cd6, 0xc06f302a, 0x3156a275, 0x0a877db4, 0x7ecfde68, 0xc7944eb7, + 0x241e2eee, 0xa20addef, 0x8e4f08b1, 0xf5970af8, 0x3559aa35, 0x02e1c094, 0x35a2e730, 0x6a76eb3c, 0x19ac5a79, + 0x53c4ab40, 0x8734cec6, 0x2415cc38, 0xf08459e7, 0xc51fb83f, 0x9d2b8cf1, 0x2f479c98, 0xa35d0ffc, 0x54878f9a, + 0xc0ce3f7e, 0x69582417, 0x33195eeb, 0xf25eff2f, 0xca64da53, 0x1a5c9fa3, 0xe9b83fdf, 0x1edb15c2, 0x184b1935, + 0xa6c1aaaa, 0x727e3c53, 0x32a47098, 0x690b774d, 0xf80350bd, 0xe3c8a90c, 0xc51b1866, 0x1fba279e, 0xf62f4f87, + 0x7e487ba4, 0xbfea56af, 0xf011808f, 0xb457b8c7, 0x9fd6fff7, 0x46f2372f, 0x4528113e, 0xfc3cf9c3, 0xb51fc22c, + 0xc01d3deb, 0x1a9742f8, 0x3cd59960, 0xe61681ad, 0x5fcdba81, 0xe818483f, 0x7daf9b2e, 0x00f07aa5, 0x19ef763c, + 0xdaaadb6f, 0x9ca9d2c6, 0x8fd39d19, 0x15614534, 0x354f1235, 0xf08d9fd5, 0x1f759382, 0xa74c03f9, 0x94e72369, + 0x42b9f1c7, 0x359d99b0, 0xd3f76e8a, 0xd7f5b0dd, 0x7c0ed8ea, 0xa1bffeeb, 0xac4fee32, 0xd994c6ae, 0x350856b5, + 0x1edea278, 0x945a7ba8, 0x344f9058, 0x518b97ba, 0xa2cf16f4, 0xb0d49b78, 0x2bb3f6d8, 0xeb33c160, 0xd4efea94, + 0xd190d083, 0x5506421e, 0xe18c1d90, 0x3fda2559, 0xcf8be5f4, 0x58cf760a, 0xa86b00c2, 0x281e14f8, 0xd16cd833, + 0x9ff044d9, 0xec9c8bdf, 0xaa20e642, 0xea2ad57a, 0x46d3cee6, 0x83f96abb, 0x99fabe2c, 0xa5f16a6c, 0x891f7421, + 0x1acdad4e, 0x5ea6de6e, 0xb49b500c, 0x3b6f4fc2, 0x3b52a19d, 0x2760c3d4, 0xdbaf3262, 0xd4232e22, 0xd6f84358, + 0x8337200a, 0x5c74dcf1, 0xd2422d0a, 0x1ce1960e, 0xe3dadc2b, 0xa8af9773, 0x3a0b59bb, 0xe3b0cb01, 0x50da2d02, + 0x7a70d84d, 0x2cb6d712, 0x24e62ead, 0x5839340c, 0xc426a06f, 0x58988bfc, 0xd443d547, 0x7720f291, 0xa991af97, + 0xab3a7847, 0x7b481df6, 0xad17b95b, 0xa10b845f, 0xdc60183e, 0xea41c427, 0x8ef5e7db, 0x1b3f13be, 0x9c32cd26, + 0xf8f38fcb, 0xf8c4238c, 0xf659dbee, 0x737017af, 0xab08e7ca, 0xe315fa2a, 0x0e01e129, 0xbf443d4c, 0x55f844e9, + 0xfd32e8e7, 0x27ccc9b2, 0x1893aa27, 0x050d5cc2, 0x12c034ae, 0x028d890f, 0x9eed006d, 0x651d3885, 0xf8cd177d, + 0x0e0e1afe, 0x733c225c, 0x4ae62bfb, 0xc1f43627, 0x32feb226, 0xe0d35ed7, 0x02c36579, 0xd803136d, 0x97140c26, + 0x514952ed, 0x6b447dd5, 0xebdbb907, 0xb7e1c527, 0xb24b2302, 0x5bb89740, 0x4d1698d9, 0xc08a1976, 0x9afce1c3, + 0x8087bcf5, 0xa5eb5f5f, 0xe6b20272, 0x81005646, 0x5d83c467, 0xaf897702, 0xc2895e1e, 0x5c5b2c75, 0x2b61bb45, + 0xe08aee1f, 0x4c7a6ab8, 0xa69754a2, 0xeac720c7, 0xdb70692e, 0x8f4942f3, 0xb50163b6, 0x0f713688, 0x00ba7fc5, + 0x20381d82, 0xdb3be15c, 0x7b551de9, 0xfd4dd031, 0xf8af36c9, 0x8a06e789, 0x9ce836b9, 0x56774f94, 0x4fbb68dc, + 0x844fe76a, 0xb236e0db, 0xe1a2de19, 0x44900617, 0xee8e78af, 0x3ac710e1, 0xfaad5b94, 0xe28a8b93, 0x2ae9b911, + 0x4696e750, 0x34b4ea05, 0xfd2010ae, 0xe3e867de, 0x1b69ad14, 0x7cd18774, 0xa410b963, 0xf2b0924a, 0x2b5cd28c, + 0xd704ad61, 0x024a5ae3, 0x749afa18, 0x403ab68f, 0xda7400d3, 0x7895f387, 0xc02bace6, 0x6d5cb625, 0x4e3a4d9d, + 0x4fa23552, 0x6f18a32b, 0x4e0cb3f4, 0xb8e70212, 0xa1f59584, 0xf5dcfcc4, 0xf36a67c6, 0x4767456c, 0xb7cea88d, + 0x1b8c7d2d, 0x78a33d51, 0x6d61e3f1, 0x13854a7d, 0x4648d434, 0x83c2b616, 0x3768c257, 0x49d5c413, 0x7a028de1, + 0x263958e4, 0x8d6c209c, 0x00f549c3, 0x996640ec, 0x238dc69d, 0xc060fa43, 0xabbb8742, 0xb8dbc505, 0xbb4ff76c, + 0x19481ca8, 0xd80220ae, 0x692566b0, 0x9225baa1, 0x1cbec39e, 0x39bfc558, 0x6bfceaab, 0x6d3cac71, 0x7d186705, + 0xa84ba4c3, 0x00ff8723, 0x30e5b273, 0x309b8a06, 0xb16e462d, 0xd3c80adb, 0x2e0d0e54, 0x7c6ddc31, 0x705212ca, + 0xc95e1e6f, 0x210ec2f5, 0x12420ac9, 0x56336e23, 0xb98dafab, 0x1cee2698, 0x341e8726, 0x2d0bbba7, 0x3f04c76a, + 0xd53e0d88, 0x52d3c108, 0x47fbf33e, 0x2b748621, 0xdfa91412, 0x918f4fde, 0x4de86954, 0x8a350692, 0x971b5f3e, + 0xd5da9a08, 0xa0724dd1, 0x3aaf964e, 0x90737837, 0xecce3db6, 0xa618b54c, 0xc2b69075, 0xa9973254, 0xcaed1c25, + 0xa3a13d28, 0xcbab6bb0, 0x946fa5dc, 0xdd764707, 0x11daecfc, 0x7ef5aafd, 0xfe555359, 0x7f2c2ac2, 0x5f49e618, + 0xfa86f073, 0x4bc25b60, 0xab4626b8, 0x5743f4e0, 0x9bcc2a0f, 0x440920ae, 0x56b5b564, 0x3bbd5659, 0xdb24204e, + 0x523a76ac, 0xcf75dd42, 0x9f73f153, 0x21899c80, 0x354d75b3, 0x694aec71, 0xb50d028a, 0x163890f0, 0x1ee58d14, + 0xeef8f058, 0x72b43cce, 0x70715a1f, 0x12fe143a, 0x4d854aa9, 0x50c5ad70, 0xdb9da8b6, 0x96e04916, 0xf4beadf7, + 0x00535b11, 0x274831e8, 0xf5d87dd1, 0x9aeb647c, 0x3c2e2cc3, 0xcc17ea3a, 0x814505b0, 0xec58b457, 0xf96065d5, + 0x1d5d35e0, 0x3b116ec2, 0x8caf4957, 0x5505a1e5, 0x174ecf17, 0x03a1af61, 0x66668271, 0x396bac03, 0xb5919ebc, + 0x29d0ec17, 0x72584169, 0xcb2bcabe, 0x9dc778e3, 0x235412e7, 0x91cf94ba, 0x74bf720b, 0x22a347fa, 0x93feddac, + 0xa5cc2517, 0x28596704, 0xe4fc7787, 0x146d3545, 0x6f30e84a, 0x3bf220e1, 0x348a544f, 0x840c298a, 0xd299bb22, + 0x4459a7ca, 0x6907f022, 0x98cf9f4a, 0x48430de7, 0x947e014d, 0x10109d7d, 0x54537b07, 0x75e20d18, 0xb853ab56, + 0x438674be, 0x63511c96, 0xea01dce8, 0xcf778efe, 0x45cab9a5, 0xa7575988, 0xdcff666d, 0x2852709d, 0xab6c55ae, + 0x280fa231, 0xe54081bb, 0xf1ee2a1d, 0x161735ec, 0xf7d82c7e, 0xf72d6e31, 0x9086af03, 0x4a3fe8e1, 0x257dd3cf, + 0xdbe3e602, 0x0ccd6040, 0x0f22380c, 0x3814cb50, 0x1bce1131, 0x1218448d, 0xc76548ca, 0x1197be88, 0xd29a530d, + 0xb311f3a5, 0x906c6431, 0xf19ecde5, 0x6f5af252, 0x541f9f1c, 0xb2d25528, 0xcd59540a, 0xe36ed921, 0xd6709f16, + 0x7e84da6e, 0x6e5e38e4, 0xc4795a5f, 0x8805ae6a, 0xff0c80ae, 0x526d8637, 0x60fdfb96, 0xc6df3bc8, 0x9aaa64e8, + 0xb02731d8, 0x7130c1ab, 0xe11ed6e3, 0x67ca316a, 0xa43e47c5, 0x1668660f, 0x1e5593a7, 0xb0d6b647, 0x7fe1101d, + 0x53498e4a, 0x2ffe2f43, 0x4986558a, 0xb25a2ae8, 0x851113e8, 0x60d847fb, 0x166a5c31, 0x9995bd4d, 0xd4a19411, + 0x69372066, 0xb3a0e78a, 0xb9a3804d, 0x19e29bd6, 0xe3dff78a, 0x67b82279, 0x761a8be2, 0xc71ecd43, 0x5e2a005e, + 0x48f38ce4, 0x0aec18ce, 0xc3eecc95, 0x1a069190, 0x6a916f9a, 0x671dcfa9, 0x00949666, 0x21769764, 0xcfd329d8, + 0xb0a6fbfe, 0x606f4a81, 0x3cb59333, 0x3b6756c2, 0x24e7eeed, 0x3788836f, 0x5ac28ba4, 0xa5fb0e35, 0x12bcb910, + 0xe9d368b2, 0xd06cc095, 0xfe4cae3c, 0x7cca4e03, 0xf40957a5, 0x629fcee5, 0xb0e12879, 0xe5995172, 0x974d758c, + 0x75f6155c, 0xe5b9964a, 0x5cb58c40, 0x2d6cde87, 0x0aec0075, 0xa4f10e30, 0x6fca7330, 0x5362fd7e, 0x3c110d99, + 0x648f7fcf, 0x032a99fe, 0xbd76c275, 0xe46901e8, 0x09adf69b, 0xc2cead9d, 0x634e846a, 0xa9a5e6e9, 0x765a61f3, + 0x618a6413, 0x347b8bd1, 0xe2c81c2e, 0xc440ffd1, 0x27f08344, 0x49a829b0, 0x800425b6, 0x0d5e92fe, 0xa540e8c8, + 0x3c98aaaa, 0xdbdbbf4e, 0xa09ec60d, 0xd1598c01, 0x0f0f252c, 0x032daa68, 0x360a4a1a, 0x9bd5bb32, 0xcfc19330, + 0x1b88188d, 0x797d0aec, 0x4adb6f6b, 0xd32f2ada, 0xf42778c3, 0x673aab7b, 0xb4978e2a, 0x2641a32a, 0x96ca07a1, + 0x0a56eeee, 0x86e84f26, 0x36f015fd, 0x81f88ef2, 0xa3135608, 0xc39be64c, 0x1012e644, 0x9c556061, 0x7d6e9b20, + 0x1d269bfa, 0x86aaba29, 0xc9087303, 0x238d0989, 0x65ea4399, 0x0813154f, 0x8984401e, 0xc705df6d, 0x78dbe47b, + 0xace09e22, 0x32da25cc, 0x936d6e29, 0x59fa4268, 0xf4fa06a6, 0x12546864, 0xf3655b64, 0xb0fe78e8, 0x31d88977, + 0x7792d862, 0x77491402, 0x7174c223, 0xd122d87d, 0x18934924, 0xeeea5b3a, 0xc75cf31b, 0x4096688f, 0x00a4e97f, + 0x998d271d, 0x692a031c, 0x971e9621, 0x706d1506, 0xe51d2d0b, 0x66dece0c, 0x070b081b, 0x8ba9b221, 0xc1b2efd0, + 0x0fa85021, 0xdfcdfb33, 0x1f7ab9ad, 0x046a9299, 0x766a6a53, 0xd9e89036, 0x041d33bd, 0x07260103, 0xe4514c88, + 0xe8ced537, 0x8ba6bcb3, 0x604233db, 0x658faa8f, 0xb60b03b9, 0xcd48a2f5, 0xe0c7a8f4, 0xb42eda2c, 0x378043a2, + 0xeb54d089, 0x2d5f5963, 0x74400cb3, 0x1500da45, 0x16f6c44d, 0x1bb52afb, 0xaf47841d, 0x9f681848, 0xf4d12442, + 0x5b30d77b, 0xfd8d0383, 0xda15d77e, 0xb6439844, 0x0cc2833a, 0x6ea4f3c8, 0xdfe12ddb, 0xcb83894f, 0x2423459e, + 0x2c2cfd7e, 0x777bc6ad, 0xdbbbdbd1, 0xf0d95b1d, 0xa77f1a2f, 0x4709f7cc, 0xdb18c757, 0x87427010, 0xafc3e150, + 0x58893194, 0x8cb5b49e, 0x190ae499, 0x9c7b4c11, 0x270a7050, 0xf2464cb9, 0x844a1366, 0x5d9753dd, 0xec127f76, + 0x3db2e3b7, 0xfb1f7078, 0x7d446a7c, 0xd729802d, 0xf95aa867, 0x1d69e2fc, 0xe292314f, 0xf29550f8, 0x68535d1b, + 0xd4bd3a95, 0x5ddba353, 0xbd8580ee, 0x8248c0ae, 0xfde2397b, 0x14945c75, 0x6ce1956a, 0x33f35676, 0x7c1dfe19, + 0x21abc020, 0xfaf36abd, 0x1e253c7d, 0x963b8a09, 0x5e5ecf2c, 0xe5c140bb, 0xee1e6587, 0x3a6df30c, 0x3cfe25c9, + 0xcb0f3c63, 0x3318dd9d, 0x59a96084, 0x19677343, 0x470a323d, 0x679bb0d7, 0x8213f0f0, 0x540775b3, 0xe120f6c2, + 0x948ec722, 0x0e32f0d5, 0x6ed3f14c, 0xff925d84, 0x48116567, 0x547b0de4, 0x10f8d23e, 0x3986f4e3, 0xfb950a64, + 0x7a41e8e5, 0xcbf7db2d, 0xb8a13ede, 0x437439dd, 0xf978cee6, 0x00fee970, 0x370316ba, 0x105b6d32, 0xa18bdf30, + 0x7b02e10d, 0xb1fa1dea, 0xc66f93a6, 0x6b9c8176, 0x4dd2c1ce, 0x08f79da5, 0xf9c1db50, 0x97a8dd05, 0x3468e5b7, + 0xbc26409c, 0xe4e3b20b, 0x9995ec37, 0xf53d2b2b, 0x2c10b516, 0x0b890b4a, 0xec442356, 0x892376c9, 0x5781b384, + 0xe96fe9d8, 0x2ee25b77, 0x6292a6a8, 0x9f93e5e8, 0x845a0cbd, 0xa1a867e6, 0x5dd473b1, 0x37289792, 0xf0e5b9ed, + 0xfcd63875, 0xca9f2b90, 0xaad5b2ca, 0x729fdd75, 0x13a0a925, 0xd793e0fd, 0x543e14b9, 0x1ced62bf, 0x64e3cd3e, + 0x6405bc86, 0x823f5477, 0xe056f181, 0xd2b03979, 0x5a6379db, 0xa9e7fb4a, 0x87dc29b8, 0xe0cad2d8, 0x9f6f07c6, + 0x46dd6e99, 0xee7f875a, 0x027c39f4, 0x2bde6ea5, 0x9eb4b469, 0x3c65e5c5, 0x805e15f5, 0xa627fd39, 0x75137edd, + 0xa967b0be, 0x27fb6e41, 0x2ea2515b, 0x863c8dd7, 0xfd07fc8e, 0x7cbb01a2, 0xc9ad8382, 0xd33e1898, 0x2b5d2d6f, + 0x144adbb4, 0x12e2cbfd, 0xabf208f2, 0xf1f2ba4e, 0x7105f727, 0x6de1b95e, 0xe448dd58, 0x0f47e8e9, 0xd33b1a6e, + 0xb46b4eb9, 0x913f4a3e, 0x32759fa7, 0x8778ca52, 0xfac16e71, 0x45fb045c, 0x3db05d6a, 0x0235e907, 0x73570ffe, + 0x6e57e5d3, 0x490a33a2, 0x04c9761b, 0xb78a24f4, 0x8d8ae5cd, 0xecce5547, 0xfd28d6ae, 0xc64b40c5, 0xf3769501, + 0xfdcf8700, 0x6aad7b98, 0x72dc3057, 0x0512084d, 0x13279773, 0xec963b49, 0x2af510c3, 0x9c897977, 0x58a6c856, + 0xfe4934a2, 0x13aec0e7, 0xc6bdf018, 0x94370897, 0x68858680, 0xdc67325a, 0x071fb8ef, 0x440efb3e, 0x01b7ba4f, + 0x3b330226, 0xdd67631d, 0xae1ce64b, 0xcb543bff, 0x1a5c55a0, 0x6fef3fd7, 0xb9dd5fd6, 0xf9c588f9, 0x12f4ec30, + 0x6fd201b2, 0x9bdda7a2, 0x851d66b5, 0x9c031593, 0x71acdceb, 0x810db838, 0x651b75d2, 0xa5f7627a, 0x5904ab4c, + 0x6069b614, 0x935cf3cf, 0x4958afe9, 0xb0b62546, 0x59f2e620, 0x8cc1926d, 0x5fdf12be, 0xc2a29268, 0x5fdf1283, + 0x2e299e51, 0x621e02e9, 0x42c8f0c9, 0xb8e76c64, 0xd0cb9d84, 0xab1539eb, 0xa1eef3e6, 0x2c8191e5, 0x3ac18046, + 0x99a0ce45, 0xfc32ad16, 0xcfe58ffd, 0x8b3f7840, 0x335af347, 0xa9538192, 0xa6ee6549, 0xd6b89f1f, 0xa748494b, + 0xfeb1e512, 0xd4c557f6, 0x06d4ec7a, 0x62470c57, 0xd332f60f, 0xfcfb6855, 0x6d0c38ce, 0x9b30f05f, 0x45b563a4, + 0x1283ab06, 0xc3e44840, 0x4a70a8b9, 0x8cf6875b, 0xf49059d8, 0x4e7aaa0c, 0xbdaa93c6, 0xed2067a3, 0x02c56337, + 0xbb3ddaf6, 0xa630224b, 0xfc8890a0, 0x530e6ab2, 0x40ac7c3a, 0x76393588, 0xe098d585, 0xde83db58, 0x8131ab6a, + 0x2693b7da, 0x96a1e2ef, 0x67bac73c, 0xbba68a27, 0x93c1a419, 0xa5fdd7b3, 0x33ce8f42, 0xa19464f1, 0xc626cf86, + 0x5bb7df73, 0x06a8d10d, 0x1711ae89, 0x3fe9c1fc, 0x8580deb2, 0x1415f64b, 0x4832070d, 0x99044ffd, 0xfebc2694, + 0xf4cf7057, 0x1fefbfca, 0x6797fd03, 0x4264056e, 0xd21eda24, 0xbbaf9ca5, 0xc9df86b8, 0xb5611d24, 0xc31807dc, + 0x59aeee97, 0x049d694b, 0xf15c405f, 0xaef93dbd, 0x66d522bb, 0x04b61828, 0x587abce6, 0x59aa9b0f, 0x2d8dd9e9, + 0x80de5e83, 0x29967334, 0x9aec9637, 0xaeb12988, 0x45aa8cee, 0x68a08bb7, 0x32164ac2, 0x75206aff, 0xdc858fbf, + 0x02c14877, 0x99860a46, 0xeb45caf1, 0x55259050, 0xad0132b1, 0xf4b9ffe1, 0xf6f8afce, 0xf8070576, 0xb1651e8b, + 0x658a7a63, 0xb388d90a, 0xfbd3bdc9, 0x93deea1d, 0x74872b11, 0x3797d61c, 0xe262006c, 0xdc82eba6, 0x2920e1ae, + 0x23b7f103, 0xb7c8a360, 0x6f1063f3, 0xb7406588, 0x657f9af8, 0x4c0cec1e, 0xcf6ec0b4, 0x37fc1af3, 0xcd615a68, + 0xdee08778, 0xe0079569, 0xa87c171b, 0x7eb6563b, 0xddbf02fe, 0xb273a935, 0xc12f61a4, 0x4b5a1b7d, 0xeb6cb3ac, + 0x1ae58698, 0xf750f6d6, 0x3a741533, 0xbe9d79a5, 0xb97ad490, 0x081c748f, 0xc78f925b, 0xdb01ff4c, 0xc5767fd4, + 0xf9f95ae7, 0xb339829d, 0x037b395b, 0xd4180905, 0xe9e62001, 0x1b6db23d, 0x7576c28c, 0x137263bc, 0x9276c27e, + 0x0a80c41c, 0xb0e182e1, 0xff3e148d, 0x0b1b33b5, 0x4d29c30c, 0x5cc3ea6a, 0x8b174fdb, 0xe4073115, 0x4045d993, + 0x875e23f4, 0x1f509372, 0x70247d0c, 0x4d39a310, 0x2f5909da, 0xd92af3a1, 0x7c8015ee, 0x06ccb6dc, 0xb5464736, + 0xc9befeed, 0x8bb698f0, 0xfee185a1, 0xce854a12, 0xc8263ca1, 0x7bb4ba81, 0xf7f74631, 0xe08ed96b, 0xa0b89d73, + 0xfa05379c, 0xab1ec70f, 0xc556e242, 0xe7e74dd8, 0x0cbe3ac7, 0x9e1123a7, 0x3a091fc1, 0xc4f722b2, 0x31ebdbd8, + 0x72e8a566, 0x416c7d2d, 0x02af768c, 0xa4c19bd6, 0x8b91ca48, 0xa2ac7d41, 0x164fdf3b, 0x2291f5cb, 0x21ef409a, + 0x984af6c0, 0x10e66b03, 0xf8a3eb5f, 0x64043cb5, 0x503afe2a, 0xcd20e685, 0x580f40c6, 0xd25503f2, 0x32fe7791, + 0x282bead6, 0x6039b86a, 0xba623d4d, 0x17e764d7, 0xd2433f87, 0x4b345d74, 0x9033c67c, 0x8b4654ab, 0xd1ad3367, + 0x7f2c4044, 0x6b63190e, 0x51d18600, 0x6ca0c5aa, 0xa619598d, 0x428599d5, 0x4a9640cc, 0x235d7425, 0x3195dd11, + 0x301456ee, 0xfbf97d9d, 0xd1e3dce4, 0x0e5658b5, 0xbc308115, 0xcae69dde, 0x2b626a7e, 0x7189d3a1, 0x19269c2b, + 0x5fde295c, 0xf7e10d47, 0xaf7388b6, 0xd3d59278, 0xfdf7624f, 0xe47f1842, 0x956c3be6, 0xa8da501e, 0xfbdaf93d, + 0xe58f5f40, 0xbebd0894, 0xe0021831, 0x39e58fd0, 0x231ac097, 0xb467d405, 0x4e1f96f2, 0xc4f6d6a3, 0x1086827e, + 0xf48988da, 0x3b0de08d, 0x772a5590, 0x5682302b, 0xe7a6c6dd, 0xa51a5394, 0xdb1de92b, 0xbe77e4e2, 0x7507ed2f, + 0x4523ddea, 0xcf996bdf, 0xe2aac752, 0x540b0996, 0xb5cc0b88, 0xfea6142a, 0x793631b4, 0xe74727c8, 0x7160c006, + 0x721029d6, 0x0ae7a2a0, 0xec809f9a, 0xddab1dae, 0x88b4598c, 0x158ed296, 0xd1b528a9, 0x3db1d960, 0xb3bf57d5, + 0x5ddb4faa, 0x3f733ad3, 0x599cc6b9, 0x139a8be1, 0x2f1047b9, 0xf74c2397, 0x841d893d, 0xc138e8dc, 0x770844fa, + 0xadc3befc, 0x5fd33e33, 0x78bcf587, 0x49b71c29, 0x3baf5dd3, 0x388ff36a, 0x7595a518, 0x28cbdd0d, 0x03b957d0, + 0xb5c68228, 0x1474f775, 0xdb3c42bb, 0x610a890c, 0x45b021b9, 0x4bd34492, 0x6eddc1a0, 0x5abd07be, 0x25fee7ba, + 0xfd839e60, 0x063a6bd6, 0x1328ac1b, 0x2423e366, 0x152c47bc, 0x7387824a, 0xd069591f, 0x5acdacc8, 0xbfb8f147, + 0x67a5f9b9, 0x0438bca1, 0x7a445527, 0xc9d1fb2c, 0x0c4970fd, 0x04ee758c, 0x111340fb, 0x4ab435c7, 0x70971a07, + 0x5c0474e5, 0x09eca90a, 0xa5b9cfc1, 0xb4c39ae5, 0xe89570b7, 0x06a87333, 0x2bec46d2, 0x8ff1fc52, 0x1c2f22eb, + 0xffd324c2, 0xcb641154, 0xa5bb431c, 0x7c8ade5a, 0x67e9daf7, 0x55cd1618, 0x7a85f1ae, 0x8c73a5d6, 0xf550069e, + 0xac5a1c7a, 0x40a48f86, 0xb6833608, 0xcd4b8d0d, 0xeee9bc31, 0x82d5e25c, 0xfac00d7e, 0x3668a50d, 0x2c05572f, + 0xcdef26e1, 0xfc6548a0, 0x9d160b6d, 0x8d9f4ab8, 0xe80973d4, 0x3878ba1e, 0xb506345a, 0x988614ed, 0xb4de403d, + 0x9da6a862, 0x643fbaf0, 0xc227a9d7, 0x65b96409, 0xd55b371a, 0xbb5a667e, 0xd5a283e5, 0xaa5405c4, 0x05093ab6, + 0xf7992224, 0x7508541f, 0xca8bbfae, 0xa39ba733, 0x7493f5e8, 0xedc9ef12, 0x571b3959, 0x99934cb1, 0x49acf2e6, + 0xed4198f6, 0xb060b1c3, 0xab61615b, 0x6119cb86, 0x3dfae375, 0x4c6b8f29, 0x3ea3b1e9, 0xeb21b38d, 0xcba0b202, + 0x3278dced, 0xd80b71cb, 0x44228f58, 0xe5d0ac3d, 0xbeac1d68, 0x6f2cad9b, 0xa7fccdc4, 0x2040717d, 0xe9c6841f, + 0x3e3cddd9, 0x765ea3d0, 0x3c76a3ec, 0x1a86ab38, 0x9be40682, 0xd7d3649e, 0x49b6d57e, 0x8f60d986, 0x604ee909, + 0x32bf1086, 0x2d83e0b4, 0x4d81bb08, 0x30ab63a2, 0x912c05b8, 0xd48f880c, 0xd3226e31, 0x517bfafc, 0x10ccb714, + 0x7c049807, 0x8406bcd0, 0x1d888994, 0xe5d50846, 0xeb1c0379, 0x3cc4af46, 0x27959002, 0xa4f8ae06, 0x4e19e672, + 0x655449d7, 0x236f4afc, 0x461a089c, 0xfc32c38e, 0xd8c6c847, 0x8e6cedbb, 0x567314f3, 0x67595fe3, 0x89ec8740, + 0x3f1497f9, 0xf5baf8b8, 0xe8d93746, 0x36a01a36, 0xa213a2b8, 0x9d5cf9fb, 0x07897608, 0xc6f98e4e, 0x77743bab, + 0x84f7addb, 0x3e88764c, 0x2eb0adc1, 0xc4069322, 0x78321146, 0xff5da8ce, 0x3f736317, 0xde759fed, 0x74047a5a, + 0x3d27da60, 0x7fb13c21, 0xc5f3ebcf, 0xde3a9645, 0x5450c14f, 0x58b676d6, 0x7fa96d5c, 0x1889ffff, 0x88d09490, + 0x446f908f, 0x9955428b, 0x81d4d8cb, 0x36af1a50, 0x03d4b386, 0x9ed6531f, 0x70359cc7, 0x533cad0d, 0xe377d6c9, + 0xdf0c1473, 0x09c6b302, 0x5903d113, 0x8202d6a8, 0x0a7a050d, 0x55486f66, 0x2e58b7d8, 0x32d48568, 0x63154de0, + 0xb2a58350, 0x1ee887e5, 0x0aab0e08, 0x52ff20f4, 0x9af29ffc, 0x8ef664fb, 0x835f269f, 0x5d2597c1, 0x06d38701, + 0x379177e3, 0x3ef55855, 0x4bccbcac, 0xa6d28f5c, 0x64402619, 0x65c06aad, 0xded9635b, 0xeb3a5e10, 0x19b29c01, + 0x073bef05, 0x12e2bf1a, 0x3c6c6865, 0xb2cd1bb1, 0xe1e5f2dc, 0x13deb782, 0x20cc704f, 0x36430993, 0xe1296d3c, + 0xe45daada, 0x4720c190, 0x94315792, 0x87740127, 0x087492e3, 0xde0492c7, 0x4aad8388, 0xb0fb8ee4, 0x46e0f8e4, + 0xb0ca8550, 0x84588076, 0x6e5a373e, 0xcd35a79d, 0x64ed1a98, 0x8334745e, 0x51424547, 0x6d30b1e7, 0x2ee7390c, + 0x990325df, 0xee9319f3, 0x6f24aba2, 0xf537e2cf, 0xca474ad1, 0xff9700ea, 0x0aa41102, 0xf6903a58, 0xcd44ee17, + 0x01cea709, 0x0b4d65d1, 0x22787e0d, 0x349ad40a, 0xcf1ac8a0, 0x8b9b4b67, 0x9b91afae, 0xe9d6ef9e, 0x26947c6c, + 0xcdbab723, 0x6e92c5de, 0xe2238ffa, 0xd51bb3c4, 0x2206539a, 0xbebe0f33, 0xda955e39, 0x47978015, 0x1456a6af, + 0x98c42d4c, 0xe5319085, 0x54b9232e, 0x633b4e04, 0xd955843d, 0x9840f7bc, 0xe972f7e1, 0xe740bff5, 0x57f3ea54, + 0x06b0e523, 0x85794e3f, 0xcbbd30eb, 0x349e82ff, 0xd1f6fd35, 0x23195377, 0xb15f998d, 0x3b07dccc, 0xb13ae98e, + 0x82aba08e, 0xa0c0f5e0, 0x585ecd24, 0xda985be4, 0x946a4b36, 0x549fa001, 0xf5cd8fc1, 0x884a76c4, 0x8b23a2df, + 0xc7cc045a, 0xef89505b, 0x5bc0315a, 0xb02e4c7c, 0x761c1d88, 0xb1e9aaa9, 0x051dd00b, 0x18692171, 0x5f214161, + 0xe60e43b1, 0xf258eaa3, 0xe4f75c54, 0x18553578, 0x124870e8, 0xb16a1ed1, 0xb3afd9c0, 0x48d5435e, 0xd8366ea3, + 0x46fd14bf, 0xf3784afe, 0x4f9aac87, 0x6e39483f, 0x86bc7881, 0x1254ab33, 0xe398ece3, 0x86ea43b9, 0xa7a569ec, + 0x17e938cb, 0x83d26bb2, 0xaee66a89, 0xf3462fd3, 0x64808261, 0x40fa8c23, 0x012f7bfa, 0xa2c17934, 0x96f3fb3a, + 0x9bbf2cb0, 0x91a67d1d, 0xc92e77e0, 0xa9d7fedc, 0x5bbf7269, 0xbea31128, 0x57e375bd, 0xa28cdb40, 0x3b5ac86e, + 0x22ca0606, 0x992944b9, 0x50dee88f, 0x45e014cd, 0xce13c841, 0xe7fec09e, 0xa881c073, 0x7b6303ce, 0x5aee1ea5, + 0x3a609076, 0x7cb195a8, 0xbf80388a, 0x97e0b0e6, 0xdf03e7ed, 0x8911c8bc, 0x37a8e369, 0x4dcb41b3, 0xf8d97f26, + 0xa1a24cf2, 0x48b24b01, 0x9a4bd737, 0xabc9ebed, 0x720dc820, 0xdb2cb39d, 0x51d7c2c6, 0xeda4945e, 0x0c050666, + 0x6322dee5, 0xc3d67495, 0x5eaa49d2, 0xc1e27a63, 0x49d8aeb4, 0xa0db6e4f, 0x8b99c741, 0x116da344, 0xc2cb6436, + 0xaa1143f1, 0x16c52663, 0x52fe2f61, 0x1277f22c, 0x25b5943d, 0x758f6308, 0x8183a909, 0xfba195ea, 0xa884c40b, + 0xddd14e2f, 0x48fe1fe2, 0x05f45def, 0x7873aebc, 0x2a8b966a, 0x3739775a, 0x45436863, 0xa46e8b20, 0x301520cc, + 0x0bb78021, 0x736b3253, 0xb93aa45c, 0x62d33f71, 0xe4978152, 0xafea179f, 0xb81cee6d, 0xaced64d4, 0xbf174eae, + 0xd8b5cf80, 0xd53ab93f, 0x6e49284a, 0x511c4849, 0xd8a25ce8, 0xcd104de7, 0xb2e493c5, 0xe5288919, 0xa409d213, + 0xd037e5a5, 0x75d749b3, 0x29cab5b5, 0x482076f4, 0xf00094f9, 0x842a7f50, 0xb784b7dd, 0x1c24199a, 0x76acf418, + 0x1cd6e8a5, 0xc3bc7555, 0xe5b340c0, 0x3eafcec8, 0x9d03a80f, 0xf9b3425a, 0xe3b8dde7, 0x54e6ee03, 0x1dd8358d, + 0x5c85639f, 0x7e5a4de7, 0xe34d59be, 0xbe55bc7f, 0x668f82b0, 0x1133fc58, 0xcebb6146, 0xc7a6e7cc, 0x18f45858, + 0xc327bace, 0x2b0304b0, 0x0a5af66c, 0xa62b7f68, 0x0553b101, 0xced7a554, 0x23b13f20, 0x318fe5b1, 0x59a607bc, + 0x8d289711, 0x533dfd0d, 0x85993c0a, 0xc5050400, 0xe8a58680, 0xfb5ab5ad, 0x45bcabe6, 0x386c4586, 0xcb752037, + 0xa002f2d2, 0xbfb26cc8, 0x26bebbeb, 0x65c89493, 0x33bde5f5, 0x009833e1, 0x296443f5, 0x087c6706, 0x72211af0, + 0x02e69e16, 0x1887220c, 0x84e14755, 0xfe145cea, 0xd5ed7151, 0x78e6f666, 0x43007bfd, 0x99497c98, 0xbe1f6bb0, + 0xfb94130f, 0x8995a133, 0x7068353e, 0xea6f72ef, 0xb1819330, 0x7b3dec92, 0xa49b35b6, 0x8608605e, 0xa2561bf1, + 0xd303066c, 0x91a30a2e, 0x68c5fd5d, 0xee059652, 0xd46809b3, 0x61d6c637, 0x2d409b76, 0x0e454f9f, 0x5b9bf4ed, + 0x35d0d1b2, 0xaeb9789e, 0x31b727cb, 0x27c99fa8, 0xe021c399, 0xe4a3fa60, 0xbc9b8231, 0xc8d7b25d, 0xfdabac88, + 0x23e38030, 0xa0a791a8, 0xe9e27675, 0x91ce6042, 0xfc7b296e, 0xa9ae24b0, 0x51c0d363, 0xecc55296, 0x9fe340eb, + 0x7ee132ae, 0x8ba1916f, 0x5899dee7, 0x7f41e055, 0x3b755195, 0xcc43543f, 0x21f546ed, 0x19ae29de, 0x1f832771, + 0x7f6f50c4, 0x2f0d4db0, 0xd1a808c8, 0xedcd4588, 0x9d421b6a, 0x7a27e517, 0xde0f226f, 0x8f0b6e98, 0x524a80c4, + 0x30a8e79b, 0x96a8625b, 0xb9ef515f, 0xca2b7a14, 0xb6b11140, 0x448de03b, 0x50a29bbf, 0x13997f8e, 0xbb220d54, + 0xd12eb048, 0x108c4c41, 0xc7df4b51, 0xc6ec1558, 0x47bbe9be, 0x745305d3, 0xa405e1d8, 0x4998b1e0, 0x61b526c5, + 0x70cc1328, 0xec9f1216, 0xfcae2328, 0x1a26dfef, 0xeeda2cc6, 0x7b212cde, 0xb57f1bc1, 0x54f7311f, 0x555b0fd8, + 0x835f80eb, 0xa241c6b9, 0x96a13967, 0x8f755211, 0x432991bb, 0x273f7d42, 0x5ac751eb, 0x1b8e571f, 0x2a66d25d, + 0x9054a900, 0xce74a233, 0x3debbc03, 0x77eb85e4, 0xc32579cd, 0x3c64c6dc, 0x318649ee, 0x1614292f, 0xa1c23eeb, + 0x3b0242de, 0xe3799de6, 0x1b5f6a5d, 0x0a1d8b36, 0x70a62b50, 0x8102308b, 0xb868c581, 0x2102e25f, 0x6df1d1d5, + 0xbea0e689, 0xf2e023b0, 0x31119c6f, 0xdad2654f, 0x4dadff33, 0xe5dd203d, 0x91d66d34, 0x5ace8546, 0xb96f08e5, + 0x5b006608, 0x1f75b109, 0x06407458, 0xebd1aa19, 0x87defbf0, 0x2cf2e90b, 0x0d22e516, 0x857f1d3c, 0xffb3766d, + 0xc6a828a2, 0xad28ad9f, 0x2995de77, 0x4cbdbf7a, 0x21d1d1ce, 0x9ef4cf24, 0x775e2dc2, 0x748651fe, 0xaf2ae334, + 0x658411d5, 0x793340ff, 0x4740db2f, 0xa4ef67ab, 0x46def4c4, 0x35ddb465, 0x6d973ef9, 0xd7837e6b, 0x6c8f9731, + 0xa1cf32f0, 0xb9aee7d5, 0x88ee71bf, 0xb53513c2, 0xa704334a, 0x59192694, 0x35158ea8, 0xe648077b, 0x3195cfa1, + 0x9a92df73, 0xe8994b27, 0x7705a35e, 0x31b91606, 0xe57c29dd, 0x07500d62, 0xa96dfcf9, 0x8a0a1b39, 0x87e62c84, + 0x4e1ac0e6, 0x255b97dd, 0x7eb473b2, 0xd47bfdbe, 0x3c7def4f, 0xcf70ca07, 0x10da0ec2, 0xbb736aa3, 0x493fb79b, + 0x40f1c960, 0x8f7cd4a1, 0xc95960d8, 0x5223acfb, 0x35ea00ca, 0x8cb819af, 0x09dc9de8, 0x8b875432, 0x8d3907a2, + 0xe0dc126a, 0x1e50a5b0, 0x2d6088ef, 0xd2fcb05a, 0x074e8034, 0x78c7027e, 0x608b3558, 0x49b28202, 0x319bc1be, + 0xe5009e02, 0xe4613976, 0xe018b74c, 0xeb64dcb5, 0x3036889c, 0xd9cdd3ca, 0xdf9bfb46, 0xf5e2bf00, 0x77025598, + 0x60603007, 0x7aedf990, 0x6e82fea8, 0x45581894, 0x76b4275a, 0x98520b83, 0x1dd865c6, 0x79dab2a0, 0xad4e90c5, + 0x324acfb1, 0x5ee23a50, 0x95989fc9, 0x2dd7ff26, 0x982e796d, 0xb0b04eb5, 0x6ee7a15c, 0x25309b4f, 0x5ad2fa78, + 0xd6f09652, 0xf8c8fc7d, 0x6ec7adea, 0xe5ffba62, 0x7722bf20, 0x21170e40, 0x97631cb7, 0x08ce0d7f, 0xf20a64ba, + 0x0571d046, 0xaf323d66, 0xc6112d8e, 0xaaa7c879, 0x0ae12440, 0xd0aeb51d, 0x1269cd01, 0x6f933c6f, 0x05e87883, + 0xfe24a553, 0x5411122c, 0x317dbc1f, 0x7f067aed, 0x083d1d6d, 0x341dcd88, 0xb62a8685, 0xca296488, 0xe5f3ce6c, + 0xb34604f3, 0x90fd7d4b, 0xb756003d, 0xd6397265, 0x6a8a6231, 0x9544b023, 0xe9145f04, 0xab698da5, 0x048aaaf1, + 0x22d94efb, 0xef42e95f, 0x3384e690, 0x62581f01, 0x43fba2cf, 0x831d6032, 0xf5c94e33, 0x4b67b485, 0x0e5660f7, + 0x222d3ce2, 0x6e6cf849, 0xe453787f, 0x55672eb4, 0xa75c6f47, 0x5d9d2163, 0x2a82cc81, 0xf140cd16, 0xf36b359b, + 0x5b915949, 0x38d81b3b, 0x8f22ee14, 0xee7ab114, 0x27c2c076, 0x8ecfc327, 0x5683bf6f, 0xab0492b7, 0x1d53f602, + 0x696a6724, 0x7f67df0f, 0x996e4d66, 0xc0215312, 0x53aa0e37, 0xd3b8f79a, 0x6900887b, 0x62d54c90, 0x65bff774, + 0x8f06dfb5, 0x4f8726b4, 0xd982a74d, 0xd5b4b1f1, 0x337cfeb6, 0x858c5e50, 0x9322ad92, 0x8035b71a, 0xbb904d58, + 0x0c4291d3, 0x4b0f545b, 0x30d0c54a, 0x02ec06dc, 0x30e84fa6, 0xfee11347, 0xe4fc4c66, 0xcf6fec38, 0x7357a26f, + 0xfce80471, 0xa01acd4f, 0x4b05c00a, 0x27d62983, 0xa93da8c4, 0xe6bdf83b, 0x89a1b67b, 0x26496046, 0x126d5b8c, + 0xa03c34bf, 0x3b0003b7, 0xcf719ddf, 0x4e7a99b8, 0x60ad3a5d, 0xe1ddce87, 0xd1b06aa0, 0x6fe7694b, 0xd28a85a6, + 0x9241a923, 0x83d256df, 0xe06a9379, 0xcbd79187, 0xb0ef1815, 0x05908b46, 0xb1f5ac09, 0x91972561, 0x9d754a52, + 0x7d214c58, 0x0be76523, 0xa51ca97d, 0x61678e6e, 0xde263f3c, 0x506c800b, 0xc5bee74b, 0x4a9d3c0a, 0x797b1951, + 0x2e9f91d5, 0x45396884, 0xba0ba344, 0x1a51a011, 0x6151b99a, 0x4833cd2a, 0x03cb24e5, 0x2d82b251, 0x21ac5926, + 0xf6f70d1c, 0x31332baf, 0xa628a810, 0x53884e75, 0x84b75751, 0x66ee551d, 0x654797d1, 0x4883d321, 0x1b72f191, + 0xb2a9dae2, 0x64db6d3a, 0xa2ed3c84, 0x59e61de0, 0x7be88b34, 0xfa207d54, 0xa974aa1f, 0x26a4dfa8, 0x8aba86f9, + 0x90453eae, 0xb3ed76aa, 0xe3c0ab2a, 0xefb1b8fc, 0x34db734a, 0x281fe100, 0x5a245d98, 0x97a1fb1c, 0x3f73191d, + 0xf9d5f81c, 0x83274cef, 0xb365a997, 0x1e2e263c, 0x8bab1ea5, 0xc24757a0, 0x85dee0f2, 0xa2d4191f, 0xbde0499a, + 0x6ddcc69c, 0x7c1e449b, 0xaed98a07, 0x123daa49, 0x4577266e, 0x9d64306b, 0x377378fd, 0x7aad10a5, 0xefabaf67, + 0x5d204bef, 0xe245f50f, 0x58eeed79, 0x2a0a7cfd, 0x822e6961, 0x059c8fa3, 0x9a4578bb, 0x6c201b77, 0x4b30ab81, + 0x198a09f7, 0x39b49254, 0x22b88b3c, 0xce2bf018, 0x7a7453c0, 0xa648679d, 0x907e655f, 0x6e9ccd40, 0x4af5b156, + 0xfa5cda51, 0x06744623, 0x6e9a1897, 0x0c002ecc, 0xe192f93e, 0x8183a353, 0xab0f8616, 0xd1d36459, 0x3d3ed309, + 0xfdccb787, 0xf548de57, 0x8cc69ef2, 0x31a3342e, 0x7d973f9e, 0x33c9b3de, 0x0286d09a, 0xd81cc0bc, 0xdc2a63e7, + 0x5adbdb51, 0x1f3e385b, 0x3e99bfa3, 0x2512d641, 0xe81b4704, 0x14e3d84b, 0x3b989966, 0xf13db04b, 0x51ffae11, + 0xf8e3806c, 0x2c80c9ef, 0xd23e0917, 0x2a292c3e, 0x377d537c, 0x33679a8e, 0x321e7e5b, 0x17db3562, 0xe57b8ce3, + 0x87c004aa, 0x180a5124, 0xeda16271, 0xa54a910f, 0x14987e55, 0xf4b8ae83, 0x998d95a4, 0x855f951f, 0xc0f7493e, + 0x0442e99c, 0x358faecf, 0xdf17fe12, 0x7670d433, 0x68d47617, 0x2e8a8d7f, 0x0402b923, 0x626b0312, 0x92a9073e, + 0x517206f5, 0x1c925b06, 0x2ae250ca, 0xa8fba4f4, 0x86f38414, 0x445dacba, 0x993e1a2c, 0x43a68c05, 0xc10f0a6b, + 0xdd8c8583, 0xffa53f80, 0xc614fbe6, 0x286deed4, 0x479bdc6e, 0x362131f2, 0xd1af1533, 0x614ce235, 0x63bb3920, + 0x678374eb, 0x6c098fb9, 0x84c4ab7a, 0x580331cc, 0x0b62f4ee, 0xd659d1ee, 0x45d526d7, 0x24dbfea9, 0x865782f3, + 0x0d1a36ed, 0xb2ac7d2c, 0xe678055a, 0x6f518d7b, 0x1ff916e6, 0x795c0a01, 0x295bb456, 0x61143f21, 0xecde98a4, + 0x77259b49, 0x0405bbc3, 0xd2a067c7, 0x3a9baf94, 0x8df7d29f, 0x52eda039, 0x938d4f92, 0xdf9dbcc9, 0xb0c0ae03, + 0xe10e46bb, 0xee090657, 0xa67483c1, 0xb9811d2b, 0x69dadc77, 0x95b7bfaa, 0xfea78f42, 0xd086eb78, 0x437c1e0e, + 0xb4e54b4a, 0x35c9acfd, 0x60aed000, 0x5d59d309, 0x3c92afac, 0x89ae710a, 0x96fcf587, 0x65e2df8d, 0xea57cb6d, + 0x0640c83e, 0x7ba3e6d3, 0xd50bf82d, 0xc42715b3, 0x3770a922, 0xd0c27f13, 0xff5f5011, 0xb10cebf6, 0xce03af5c, + 0xea48b2e3, 0x246a1524, 0x2ad95b42, 0x97081b51, 0x4b1f0dec, 0xdf6a07c0, 0x727ffcb0, 0x37048f40, 0x69edd6c3, + 0xa94f55ce, 0x9e503545, 0xb2be2343, 0x12a960df, 0xe5191ce1, 0x42c0485c, 0x8b7d6cc9, 0x3f8a2d8a, 0xf7c1cff4, + 0x5e6a6ea9, 0x900042a3, 0x7110c4fa, 0x1d77acfd, 0x9ca01241, 0xa196d580, 0x2466bba0, 0x9eb4e1eb, 0xe07c3691, + 0x973f748e, 0x35331691, 0x40cf820a, 0x83206bf5, 0x05c8e3f1, 0x6f7149f5, 0xe5712d0b, 0x7d24fe05, 0xb1a1b040, + 0x04d14e11, 0x684f9d91, 0x0be26c52, 0x3e05471a, 0xdb0e5b6c, 0x94782f16, 0x5cfa49c9, 0x3288f792, 0x6b83f90e, + 0xd9e689a4, 0x3e1c5d28, 0xc32dbd67, 0xcd7cdb2f, 0x22643a36, 0xeb738cd8, 0x4222e864, 0xaeaad7db, 0x956a5c79, + 0x9c903ceb, 0x4dfbfe35, 0xb24f3457, 0x3daf73fb, 0x7f23b57a, 0xad73b1a6, 0xe0bcc328, 0xcef5b1e2, 0x14656273, + 0xa5fc9d67, 0x1d7d8992, 0x6cc24efb, 0x90721a0a, 0x43779558, 0xc0a06e20, 0xeace842d, 0x263757a6, 0x2cdb66b3, + 0xf9476874, 0xa77daa0d, 0xbca14f9b, 0x21ef4f94, 0xf7449eda, 0x2554190d, 0x712126f4, 0xf978d218, 0x56a42510, + 0x2288d39e, 0x77505e52, 0x4e5dc5bf, 0x3d181a32, 0x21e86a41, 0x2d3e931f, 0x1021b45f, 0x186e07e7, 0x7d7f6b4f, + 0xe8c1dfbb, 0x4b74be4b, 0x122b32ae, 0xd2d9bb7c, 0x41b6cdd3, 0xf2b5f0d1, 0x1bcc3897, 0xad00d43e, 0x2d4be6a7, + 0xcf602902, 0x74a6c0e8, 0xb3f094ca, 0xc31f4bfa, 0x3b5e3f55, 0x5e5f4d62, 0x698cc65e, 0xc4fac72c, 0x0e2fc1ba, + 0x311e8804, 0x4f323887, 0x2ca103e2, 0xd06dc866, 0xc4a50ec9, 0x8ba314a1, 0x5cbdaf58, 0x2bba47e5, 0x51299306, + 0x5073b2db, 0x05b3ae39, 0x4d549004, 0xb9b26261, 0x252bec1d, 0xb1810135, 0xdbfdfffa, 0x23fd404b, 0x13e5746a, + 0x1fd26785, 0xa5ced7b0, 0x7e51e714, 0xa0e585ba, 0x7bd3938c, 0x3edf885a, 0xe0de8131, 0x9f74713e, 0x820de4fc, + 0x0fd87da6, 0x368878cd, 0xd42295c8, 0x0302c6a1, 0xa45a85fd, 0xa65f749d, 0x271544a5, 0x5eb8ccde, 0xee1af450, + 0xcb082b3a, 0xa8c93aa2, 0x7164f78f, 0x8ba87103, 0x744ace56, 0x9584bdd1, 0xab53d748, 0xe075eef0, 0x39ab6c6d, + 0x63a83137, 0x8e14244e, 0x3162b2a9, 0xde236132, 0x185e1fe9, 0x4090b689, 0xdc84e2c5, 0xaee1ae7d, 0x716dffd9, + 0xf0c8a8a0, 0xf8a8eb4d, 0xd264eacf, 0xe4f755e7, 0xe601c543, 0xe3b8cb97, 0xc89157be, 0x191fbf51, 0x99aea52a, + 0x39470096, 0x513ba710, 0xc198ae89, 0x0d580777, 0x083e734e, 0xb5e73933, 0x6e9aa5d9, 0xf4501be5, 0xf8305681, + 0x8edbc8a5, 0x216a374f, 0x0b957be3, 0x96637292, 0x117e83ae, 0xc94eef9f, 0x7c324718, 0xd2c085d3, 0xe6f30268, + 0x3c9de7d4, 0x39a0f728, 0xacd52ddf, 0xdea68380, 0x8616d23b, 0x3c396537, 0x71aba3ca, 0xc742f64c, 0x038d8391, + 0xb2d47bca, 0xfdd289bf, 0x53271175, 0xbf9c55ee, 0x0b8b5549, 0xd252f67b, 0x8d633941, 0x45c44cfb, 0xe461d3fa, + 0x284f2ddc, 0x9ce722ab, 0x02a178e0, 0x6f4eae02, 0x5565df92, 0x6b94c9be, 0xd97c7e36, 0x3d70623f, 0x871e4b17, + 0xc1666c34, 0x2b8b663c, 0x3e798fa9, 0x8c72dadd, 0x520cfa9b, 0x73903854, 0xe0d1b446, 0xb05308f9, 0x6ae0bd71, + 0x12cad991, 0xf0904609, 0xa2149cf9, 0x1cbaa517, 0xad555813, 0x4499cff8, 0x7ce4437a, 0x2c57b973, 0xf5f63448, + 0x98dbd3cb, 0x55f7b6f3, 0xa8c51206, 0x77022c4e, 0x3185219c, 0xa7ac6ec3, 0x76ab999a, 0xaffa1f76, 0xeaa22e04, + 0xbee14edd, 0xef4e77a8, 0x3c2095ca, 0x68dfaff4, 0xc96ecac3, 0x02e3a14b, 0xeaa81fe7, 0xf1a2d3ed, 0x84c83b40, + 0xeb2f93c4, 0xb0572b1c, 0xefcc5659, 0x4ccfc49e, 0x5baf4463, 0xae604cb4, 0x7d3396d7, 0xe01433b9, 0xfa5356fa, + 0x78094583, 0x73647728, 0x1dab5cab, 0x9cb6c678, 0x716501a1, 0xa3029f07, 0x682d3bb9, 0x7314c885, 0x8cbe4c9f, + 0x729af865, 0xe8506dc4, 0x137ffba9, 0x697ddf89, 0x9f9c4eca, 0x77c4af2b, 0xb7dfd2d2, 0x34066db0, 0x6224112d, + 0x6836c38c, 0x88fd6220, 0x6c4c4211, 0x24f9b107, 0x68a9a9a7, 0xfe0398ef, 0x9998998e, 0x7ea53dc4, 0xfe0e004c, + 0x425597e5, 0x7da78bde, 0x72f15322, 0x8d78e52a, 0x94a4bfd1, 0x4a650e5a, 0xaa9e3fa0, 0x6080dc26, 0x20048366, + 0x52943593, 0x7d12264d, 0x281e8b96, 0xe9a33961, 0x0d55d2de, 0xf4807364, 0xfc626f1c, 0x2eba8a2e, 0x1afb41aa, + 0x0f2bdb6d, 0x8e54efab, 0x86c09f96, 0x4f78a3e5, 0x6b5e1603, 0x3c2e8ea4, 0xce397994, 0x8e0b221f, 0xf655bd8f, + 0x2da4ba2c, 0x5d6bf73a, 0xa2235642, 0xf29b742e, 0xb73a3169, 0x0efd8c3b, 0xa6e35f35, 0x5ae50658, 0x577bb5d4, + 0xcf3de4ad, 0xda24d674, 0x4f46dd8d, 0x0eee4f84, 0xa35cba63, 0x4272f3a7, 0xe3a6fa76, 0x05395dd8, 0x2364081c, + 0x5f8b1b2b, 0x4ebdb9f4, 0x16e0e666, 0xcc68e30f, 0x5938dc9f, 0x56acd9de, 0xe91daa77, 0xbdcc0c36, 0x5cc75e2c, + 0x3a7049f5, 0x0965f5aa, 0xe6ccd482, 0x3e9e54eb, 0x971189ad, 0x84c1f613, 0x7356531f, 0xa48d68db, 0x803a402b, + 0x0d9391ed, 0x4d7e8619, 0x1d6bdcb9, 0xc45013ac, 0x32618ab8, 0x6a45b3cc, 0x16e68e31, 0x5d1eb4d0, 0x8842b2a3, + 0xa095ab4c, 0x45911af7, 0x9873bc47, 0x2dbf3a9a, 0x22413c1c, 0x133627be, 0xe73e7dc7, 0xb7b19337, 0xbe758d65, + 0x58f3195c, 0x181a5435, 0x5cf011f2, 0xcefc90ab, 0xf8eb9b34, 0x131366f6, 0x87a69c9a, 0x533b535e, 0x7e34c225, + 0xf0a8af8a, 0x5a962781, 0x629897eb, 0xd068bbd3, 0x81a50638, 0xcb221dee, 0x68fe8a93, 0xd4a83a9e, 0xe1412f00, + 0x8d8d9bef, 0x38a82ceb, 0xe4b815db, 0x7c6f3f9a, 0x1aa01819, 0x347f9e0c, 0x4aac0c42, 0xd8600b44, 0xdacc527d, + 0x97bab3c9, 0xe89ea7e6, 0x01bdd7b9, 0x22151b8b, 0x06275653, 0x3235def7, 0x16e8ed86, 0x26718f87, 0x55f5f4e4, + 0x3899d14f, 0x75f6ade1, 0x436f5640, 0x0fed17eb, 0xbe0839a8, 0x76830fe3, 0x78d927fe, 0x2aae1cda, 0xc41a0207, + 0xaa3b2755, 0x89f6b945, 0x452cfe65, 0x1285a2f3, 0x1be62ecf, 0x146afd44, 0x815b8337, 0xe20bc782, 0x5ca0045c, + 0xf08847b8, 0xf082eac6, 0x9e1eebd2, 0x192b2c86, 0xad14c662, 0xb29d8bc0, 0x245928c2, 0xb31a81b0, 0xc8fee67d, + 0xfeb50f0a, 0x0e616b10, 0x70312d99, 0x5e509efe, 0xe2862aed, 0xe8bfa7a2, 0x7692584f, 0x4dd05f1b, 0xfe4ef13d, + 0x779bcbc3, 0x1763c545, 0x24bb1d1b, 0x7d1f2dea, 0x7637abc7, 0xf3bd5fe6, 0xa3d4d7b6, 0x534636b1, 0x39703d81, + 0x877be2f2, 0x6267144d, 0x5fd708e5, 0x9a58addd, 0xd92c9d70, 0x01786004, 0xe7c693c7, 0x6f5947f9, 0xaef991e7, + 0x454adb15, 0x13df8025, 0xc92770f6, 0x9b63950a, 0xf16d0871, 0x99879a08, 0x5d6b8412, 0x93662340, 0x4a12a3a5, + 0xb05cb0b0, 0x729c29e2, 0xaa3fc832, 0xcbb0c6cd, 0xb9b1e2f6, 0x3c5c8021, 0x4b0cdf2b, 0x7ca405ed, 0x1ec3dcbb, + 0x3779d7f0, 0xea201e54, 0x50bba433, 0x5b8263e0, 0x0de09fec, 0x617f9178, 0x135bd38f, 0xd60da797, 0xfa3b536e, + 0xfcd1cbc1, 0x54f0f2ac, 0x420c84a4, 0xf8188695, 0xdde49a34, 0xada745e7, 0x14a5549b, 0xcde91099, 0x35bddd0c, + 0x24205329, 0x85fe0cf7, 0xd45607ba, 0xc3d1d1ca, 0x83e4ba0f, 0x020217e8, 0x45cf40a7, 0xd146eb48, 0xa0301c0f, + 0x46e73b65, 0x154965d6, 0x00503aa1, 0x6bc91a57, 0xacc51363, 0xe4efd30b, 0xdc2efcad, 0x38c164cf, 0xbbd064a8, + 0x3cfa77e6, 0x33594723, 0x55c150da, 0x45aae8e0, 0xe857aaa1, 0xe130db22, 0x366f64c3, 0x1b4bfb38, 0x504d3c2d, + 0xb3c3ba8d, 0x630705db, 0x6031afb6, 0xd0b2894d, 0xa6ddd393, 0x4b20f9f3, 0x1d5c8a6e, 0xb9077e59, 0x2af65af8, + 0x9dbb19b6, 0x84b43ffa, 0xfc498173, 0x428f988b, 0x7a701965, 0x97acd6d3, 0xf7bdb2ed, 0x15ec6129, 0xf5296809, + 0x5816ca70, 0x0bec24dd, 0x5d9814d7, 0x6ad0e079, 0x5680b05e, 0xf7dd4a1b, 0x61965233, 0xc52fbe65, 0xcfe88ff5, + 0xd84106c4, 0x1c470b6e, 0x899cc1ee, 0x89a46676, 0x05e1d667, 0x4ddf3fa4, 0xf0786087, 0x547c8f2e, 0xc027cd12, + 0xd7f4aa00, 0x93ae4c75, 0x78945d6b, 0x049a9454, 0x2b223fbb, 0xce6c950d, 0x6445b061, 0x872efe03, 0x95842cb1, + 0xebebb78d, 0x1fb285c7, 0xa44f21dc, 0x4bb6ec7a, 0xcc1963e0, 0x33562f85, 0x2a064c9c, 0xb025bf7f, 0xaacf9347, + 0x2b1f85a5, 0xdea874ab, 0xe6a7e4e1, 0xebd9452b, 0x0269e275, 0x1aede4dd, 0x241a15bd, 0xa40c6816, 0x35b0a74f, + 0x1c561b90, 0xd21004c9, 0xd78ea8a0, 0xd6e5fd5e, 0x7725805c, 0xd1262a43, 0x343af413, 0x7b2575a6, 0xe42a896d, + 0x5853bb13, 0x23268577, 0xa1e92a93, 0x02e5e1dc, 0x3e4bbfed, 0x5f0f22e8, 0x597123f0, 0x90d5faca, 0xb7037224, + 0x8902ec28, 0x95a4ad5b, 0xe2e80510, 0xda42613b, 0xb6f55ce7, 0x0d2959f8, 0xf88303d0, 0xfa3f7310, 0x4f73a77a, + 0x0049765c, 0xbf067018, 0x4755d0b9, 0x09124de8, 0x8aced100, 0x0da01956, 0xf714dba6, 0xfa279a14, 0x07479bd6, + 0x3617f910, 0xde192e1f, 0x8bbc974f, 0x4409ca5f, 0xc1c3d4c5, 0xf19e3d66, 0x8c97a78a, 0xafb963fc, 0x73ef4979, + 0xd875b0e8, 0x0ec9f3a6, 0xab76ec84, 0xc16e85ad, 0x061e2f31, 0x35c75faa, 0x602e9761, 0x145f3853, 0xa1e41536, + 0xaf46bb29, 0xaf2625c1, 0xd4ab3d67, 0xb3258eb5, 0x3db25814, 0xf2be8aec, 0x25e51277, 0x2289d7fb, 0x9052c40e, + 0xa8da5c09, 0xe55cda64, 0x1f53a6ed, 0xe4a4842d, 0x2d78ab13, 0xb873ccc3, 0x39c4af97, 0xc2e63968, 0x483d5221, + 0xe3749ec5, 0xb1d3c038, 0xbae509e6, 0x34df8a7a, 0xd2e0a472, 0x9e839e78, 0xc5ef281e, 0xe0991ce1, 0x31b09078, + 0x31d861a2, 0x4964316c, 0x5d2e18bf, 0x50120407, 0xf5241686, 0x6fe96816, 0x983afedd, 0x03b60d58, 0x5c124596, + 0xa3137f53, 0x8dbfcd9b, 0xa19baa1f, 0x3f36d504, 0x0d34bcb5, 0xb2a9d823, 0x90969a71, 0x4f6c1605, 0x5578c444, + 0xb82de3be, 0x24f20786, 0x36204e46, 0x96cf696e, 0x3fd96b65, 0x20a15f07, 0x7a2c612d, 0xb5742cce, 0xa22cff88, + 0x7bdc97c4, 0xcb4136f4, 0x6fbe039c, 0xe2fa31df, 0xc408ef3c, 0xffc7865c, 0xd2431cf7, 0x6f00271a, 0x340d9f9a, + 0x3805d154, 0x26aadeee, 0x393511ab, 0x914f845c, 0x33455ba7, 0x342d6e23, 0xa6782440, 0x9be1248e, 0x8a52980b, + 0xd21651e1, 0x98608361, 0x4c4c1411, 0xd0ab5822, 0xf884fdd3, 0xab1c6c64, 0x584f6a96, 0xec9481b9, 0x1aea773e, + 0x26775d38, 0xe5b84f7e, 0xc34ada8f, 0x549c8098, 0x02ba5918, 0x8fb49a99, 0x10120d69, 0xc7b68aba, 0x4c92b674, + 0x76403532, 0xa5dbffc4, 0xc1e7d19b, 0xc0057425, 0x2514c69c, 0x83f3d03a, 0xaf4cbe01, 0x2a4802b2, 0x05443020, + 0xa42f588f, 0x2f21cb9f, 0x98db4835, 0x5786f479, 0xb35fda65, 0x7476251f, 0xfb6e1e00, 0x20719d98, 0x62632047, + 0xd036fad8, 0xc4024d6d, 0x98cf04d9, 0x645f906f, 0x9124032c, 0x9f29a92c, 0x483a80fc, 0x3707b287, 0x85e7657e, + 0x87271ced, 0xc04d6364, 0x87ed4ae2, 0xdd5f2e87, 0xa0786371, 0x3e3a0a9d, 0x77ff8be6, 0xecd4ca53, 0x30085aa4, + 0xa5f46c05, 0x3f6de6ea, 0x167502b8, 0xa737f079, 0x31bb9dbe, 0x5dc4371b, 0x99645a98, 0xe9a98a18, 0xd7be06e9, + 0x2fd16db7, 0xddcb4758, 0xe7af1dd6, 0xaacff963, 0x50d65088, 0xdce43460, 0xea5c19fb, 0x3cf66cdc, 0xfb5ddae6, + 0x79d63a8b, 0xb20eb24e, 0xe64d8f0b, 0x8ee244a7, 0x78a242d6, 0x9ed01619, 0x068b4ab8, 0x17ec6d22, 0x9f26ee1e, + 0xd4f32b8b, 0xd1747d4a, 0x9127ada5, 0x3ebbd18e, 0xc5ce2709, 0xee6adbd8, 0x554a8d51, 0x6eceecb9, 0xe30430d3, + 0xcc9925d0, 0x55669cbd, 0xeeffd590, 0x3b04deaa, 0x36ff9e45, 0x6aac7be1, 0x2f9f00ce, 0x026be538, 0x620dd513, + 0x2f4f7fb3, 0xa643d38b, 0x9d59479a, 0x44a1b7fe, 0xbebd2c86, 0x043e6b6b, 0xde905426, 0x4cd95f4b, 0xdd4b96a6, + 0x8d8f0467, 0x3727d15b, 0x0ae40c88, 0x0b332c31, 0xca2f4475, 0xe6dee05e, 0x9bea7e9f, 0x9c0178be, 0x146f04e2, + 0x1953381d, 0xc3139d3f, 0xbce42544, 0xd24847ba, 0x54d6a1a9, 0x914b240e, 0x14abd789, 0x7f5fb854, 0xf0beb0ab, + 0x56848bc4, 0x4bbd26e7, 0xbe408a4d, 0x516045b4, 0x77a340d4, 0x92d941a1, 0x0852bf0e, 0x6b3dce28, 0x66490ee1, + 0x2836c36a, 0x9fc7367f, 0xb750bd51, 0x15431a3b, 0xabfd73b7, 0xdcf3fd34, 0xaa1cde6c, 0xe66341ee, 0x963b682e, + 0x7cba8304, 0xabc3b394, 0xddf3e031, 0x13462a94, 0x46902fe4, 0x1dc32983, 0xc6e95a10, 0x96b38267, 0x13e2a17e, + 0x9d4db5d9, 0x447fe820, 0x69c99d32, 0x9a8608cb, 0xa156dfb5, 0x014fd7ec, 0xdd1f236e, 0x97dc974b, 0x7e907c26, + 0x30881c72, 0x2e28d3d3, 0xaaccb735, 0xc5913809, 0x123a37b1, 0x2ae1aeaa, 0x3178f737, 0x9f6431a2, 0xe6650e59, + 0xd020c9fc, 0x6b087b83, 0xdef76f05, 0x7e8d751d, 0x7d2c0b54, 0x0e970156, 0x88061cf2, 0x686f096b, 0xc1689ebb, + 0x1e2af141, 0xe70993dd, 0xd3c79356, 0xe77f6026, 0x5a2f6988, 0x6792fa7e, 0xb401639d, 0x54b5e434, 0x66e3c06b, + 0xb720c81b, 0xe28dd0d1, 0x7bf92e90, 0x4108708f, 0xe262f410, 0xc1fcaaba, 0x8f5adada, 0x9aa240bd, 0x910250ea, + 0x1966aeaf, 0x3290f5f7, 0x245f6d1a, 0x3e4c8e9d, 0x75ed101c, 0x9779ae91, 0xa9907239, 0xbf59ce5b, 0xdc6d20a4, + 0x961f4339, 0xf225a265, 0xe2536ef2, 0x2acf8509, 0x588c37fc, 0x88c90308, 0x932b24fa, 0x9a7910be, 0x6ae96c9b, + 0x3b01c6de, 0x16750c86, 0xbd3c6b4b, 0x3e24fd29, 0x339ce24d, 0x90ad5037, 0xdd0244f9, 0xca9331bf, 0xb42b33f6, + 0x1c5719a4, 0x0be32011, 0xb27d95ca, 0x1932f8a8, 0xa2d8e0b8, 0x017cf10f, 0x0a058150, 0xa5355a21, 0x1439b39e, + 0xf5e6ad46, 0x924ce7e9, 0x8ced7db0, 0xcb661e3c, 0x2f51ec58, 0x7ff97a8d, 0x59de9f92, 0x8d83f6d0, 0x9afb9da7, + 0xd99707db, 0x18ccbe82, 0x27025b5e, 0xd05cc9ff, 0x5a689e0b, 0x2451691c, 0x358f63f7, 0xf53f09b2, 0x48348fa3, + 0xc5d58723, 0x563fbcf1, 0xa53e571f, 0x049307b5, 0x9a5d0dbd, 0xaab27404, 0x082d51f6, 0x01b0e950, 0x5857ec52, + 0xc4533003, 0xce5a884a, 0x74d292b2, 0x3e40fb67, 0x97825f0a, 0x52764372, 0xbfccc5e0, 0xc10ee094, 0xa12ada1f, + 0xe72c2317, 0xa4dca664, 0xbae0e344, 0xa2f62c29, 0xd37952d3, 0xf139c0ad, 0x44df8f62, 0xd6e6a98b, 0xe172402a, + 0x8be3306e, 0xd712ae4c, 0x766282fb, 0x15e58749, 0xd912ea7d, 0x29bf8541, 0x7e8345c2, 0x35be19ad, 0x73483f52, + 0xc1cb82f8, 0x3094d3a9, 0xfa6cd367, 0xff3b90ff, 0xd998b497, 0x318f04b3, 0x6b08e8b5, 0x52036b55, 0xad7e0db5, + 0xbedb3b13, 0xacdf5842, 0x71b5766e, 0xfa763943, 0x75842b59, 0x486ad12e, 0xb5f41345, 0x47c85f38, 0xed293ed0, + 0xded26506, 0xb66cf28a, 0x4eb7f1e7, 0x24c5ea93, 0xe3aaeb81, 0xc071a539, 0xb66afdb4, 0x3f8c3166, 0xb3d28f99, + 0x01f0e5ec, 0x8bd20d9a, 0xad8e269e, 0x4cef1f7a, 0xcc280d07, 0xfb58875c, 0x5e857ed5, 0x51404a64, 0x5d8641d1, + 0xf0b2cae9, 0x1644f9b1, 0xaa7b628a, 0x1b8658c0, 0x0756b09e, 0x5b4736eb, 0xc96fa7c7, 0x8376b9f2, 0x8b0f2499, + 0xa80f043d, 0x7ae2b110, 0xbcef73ec, 0x5047a31a, 0x65d050f0, 0x966d57bf, 0xd604b2d3, 0xc22a7463, 0xaa3c3d23, + 0xf50a0677, 0x8bcd77c2, 0xb7bc04c8, 0x91f60c8c, 0xa681294b, 0x02b072ce, 0x27ff0f0f, 0x72dde2a0, 0xf057690a, + 0x3494b522, 0x309ec67d, 0xb7e3d48b, 0x50ae3b93, 0x81fad81b, 0x350f6395, 0x8f8acda2, 0x7539e74b, 0x0d5b772c, + 0xb3e5ba6b, 0x006f6d76, 0xfbc922d7, 0x6e7669bb, 0xaf228932, 0xc62a1444, 0x41ffe5e8, 0xd1dd4b6e, 0xa2184cc2, + 0xf9c8aa90, 0x5f36b0b6, 0xd6fbfd46, 0x28ef1089, 0x86cda921, 0xdb538e7d, 0x2cf3f378, 0x625a5998, 0x80943963, + 0x6814c22f, 0x2eb6402b, 0x75d11f4e, 0x1ba810c0, 0xba7c45b6, 0x86778a0f, 0xf502ad1f, 0xe8bd5696, 0x117ec451, + 0x7fcc6dfd, 0xe0f6df92, 0x75aaa3e7, 0x30626c8c, 0x3ce1de2e, 0x2b64ad8f, 0x0cd9a297, 0xfd5692cb, 0x6d54e5ac, + 0x81f332d1, 0x5b05ed3c, 0x2afb18eb, 0x2fe45d20, 0x65b12dee, 0x0bffbf2d, 0xa11b3a9e, 0x7e59aef0, 0x6265a48b, + 0xf24db451, 0x99bc22bb, 0xedd15fba, 0x900fdfb2, 0x718a641d, 0xd4675259, 0xa3700f13, 0xf0d1253c, 0x0cbc4041, + 0x23ef77c6, 0x0ff851b4, 0x3bd4cfe7, 0xa16120d7, 0xf2c28c68, 0x28dc2d5e, 0xb126f7c4, 0x1a4264ef, 0xb1947226, + 0xd110d57f, 0x2dc250d0, 0x8efb8fd9, 0xeb95b093, 0x89f0c1e3, 0x86faf5cc, 0x37c525ce, 0x74fd4502, 0x27f489f0, + 0x1892d36c, 0x604a181d, 0xdc77afb6, 0x008a630a, 0x70933e8a, 0x5f7a2709, 0x8f653593, 0xb67a4d0b, 0xe05e8e9c, + 0x2ea2f88c, 0x867f7b7a, 0x5718f885, 0x061e811b, 0x24a2362d, 0x57e611ec, 0xca78ef6c, 0xe628c528, 0x3a4bfc59, + 0x48371249, 0x4b443718, 0xcd62326d, 0xe8c415cc, 0x5cd28e64, 0x9fe6b6e5, 0xb60e15a3, 0x4c406d72, 0xe0a1a81f, + 0xdb9598ee, 0x6ed972a9, 0xb5ebe719, 0xb08a6661, 0x29e6b190, 0x89f6be98, 0xfcef286f, 0xfbc7b5fe, 0x9aef166b, + 0x8a661f96, 0xdf7c53a1, 0xe5143ec2, 0x0e6d6788, 0x985f4a87, 0x8efa52d9, 0x390364b7, 0xfc742e26, 0x53349ff2, + 0x66f750fd, 0xfe62ae67, 0x02776fb6, 0xb95eceb9, 0xbb40154f, 0x43825127, 0xc77d83d2, 0xfe78bce6, 0xecc825c7, + 0x200baee8, 0x8a78f1f2, 0xea25ec51, 0xe9b2e8bd, 0x6280bbb3, 0x48219819, 0x4b6f621f, 0xf363bc07, 0x7561bc17, + 0x5adc9587, 0x1498e13c, 0xd1945e7d, 0x3c246c70, 0x36aab9c2, 0xdf306a4f, 0x59eab33a, 0x126caab4, 0xab75cc3a, + 0x1f59da40, 0x0a8cd7c6, 0x19422082, 0x73e7527e, 0x846cf4e8, 0xb9962e60, 0x1b7f1aa8, 0x4c2bd445, 0xf8ca0fee, + 0x5aee6569, 0x694bc2fb, 0xcffc8151, 0x6342ff06, 0x6d7fc1b7, 0x01a867bb, 0x33a0ab5f, 0x51262547, 0xd35db4db, + 0x316ff851, 0x62aa7622, 0x30d25e2f, 0xfcdded41, 0x89fd1b3e, 0xf530e54f, 0x3e1ce846, 0x5bd38fb2, 0x67f065c6, + 0x81768209, 0x95aa7f7d, 0xea9b899a, 0x7a50995a, 0xfeb9d2bb, 0x23ccc7f1, 0xfb83b52a, 0x80a90f7e, 0x7e08ef92, + 0x8f277b12, 0x4a46578c, 0x702ba9fe, 0xbdc2680d, 0x5dc76a4a, 0x4f8ccf14, 0x0f29cd39, 0x454c773b, 0x01393fd3, + 0x5167ca08, 0x1f236a52, 0xcf1ae2da, 0xb1060766, 0x1bc45067, 0xaf1a6a57, 0xf1a86805, 0xaaedc43c, 0x441a0f5c, + 0x8c4c475a, 0xa32b2c9f, 0x6adf1f73, 0x661c81ef, 0x86d7ef3a, 0x98b40675, 0x3d7617fc, 0x69e34efc, 0xdcf09399, + 0x62c047b0, 0x93e4696e, 0xed17b3dd, 0x73621f79, 0x0f4716e5, 0x4d622bbd, 0x042f86bb, 0xeb8bc47f, 0xab301f86, + 0xa93d0f0e, 0xa414d122, 0xa8bedbcc, 0xbdedb10e, 0xfafa0cf4, 0xd23a8b0c, 0x671ff97a, 0xad2fe9f7, 0x6705af6c, + 0x1924ce04, 0xd5e74912, 0x788feeba, 0x51142b99, 0xb6f030ee, 0x0b467780, 0x4e30d815, 0xb7611faf, 0x4bd29c92, + 0x537a8c93, 0xc1e0d1a9, 0x8ce8bb8f, 0x04e951dd, 0x9e1b4a2e, 0x39e82eef, 0x8516b8d2, 0xa2cdae7f, 0x95361988, + 0xb6f62d18, 0xba85d13b, 0xb7c33a32, 0xe6256cce, 0x947afcd1, 0x66faa3d4, 0x7d5b9b78, 0x32a53774, 0xf7bb0c64, + 0x8d3f3455, 0x0ce0abe1, 0x8a99f7d8, 0xcbda8dc3, 0x01498a2c, 0x736b2e88, 0xf8d9ce97, 0x01c39d4f, 0x440d1108, + 0x524fd57f, 0x4b0c3e3b, 0xbf197ee5, 0xa8054083, 0x8d52363b, 0xfbab5ea9, 0x60379d0f, 0x207587bd, 0x65ebc8c8, + 0xd5f53cab, 0x2ea74c91, 0x5eff9950, 0x9f6d8884, 0x8f9a9d67, 0x30f1d733, 0x928f8be3, 0xfd308aa2, 0x0c79d1a0, + 0x521820f8, 0xbc2692f4, 0x45c7fb35, 0x9924aa9d, 0xb9ac0422, 0x1ef124cd, 0x84894185, 0x5c2e8074, 0x4f1da083, + 0x74c6a71f, 0xafaa8bf9, 0x687d8618, 0x595a490c, 0xe5c8e9c6, 0x7a5ac6b1, 0x18d2b6e8, 0xac2c9d99, 0x82fc8e6a, + 0xb8d8eb81, 0x5ecb0eff, 0x96db0468, 0x9f195bf8, 0x6948fd0f, 0x5fc72a75, 0x424a0879, 0x51037b83, 0xcd619a9b, + 0xef6cb61e, 0xb9f0dc3b, 0x5ea725b9, 0x1c665f9b, 0x4216879d, 0x2128b27a, 0xf8ad32d3, 0x0280cce4, 0x39bb6ecc, + 0x034d652b, 0x438df3ca, 0x0fcbed68, 0x5006023e, 0x8350c1f5, 0x01db7666, 0xc9b736ab, 0x3646a201, 0x9bf77393, + 0xf13b058a, 0x36df84d1, 0xda1157f1, 0xd86588f7, 0x071a2041, 0xd936242b, 0xf401a950, 0xb15809de, 0x7964b6d8, + 0x83c57951, 0xce93677e, 0x7d8c4261, 0xe7e1cc41, 0x770c37ea, 0x492d3541, 0x9acb5a6e, 0xa2ba107d, 0x6034eb9c, + 0x733e8725, 0x9ea7cd3f, 0x3c8210cd, 0x44503cb7, 0xff98e9ab, 0x92213f28, 0x0a550885, 0xaa575ce6, 0x52ca8ebf, + 0x6b06c9e3, 0x0bb9dfd7, 0x851b543d, 0xf82ea49e, 0xeb05ea79, 0x09546d8d, 0x9e75153d, 0x8aff0102, 0x3427dd44, + 0x8d3c452f, 0xe30a5007, 0x8de560bb, 0x708ef3f4, 0x7de07407, 0xa911bc28, 0xbee3610e, 0x1fd1b725, 0xe2f0a82d, + 0x5252e030, 0x173f92c0, 0x474cff4a, 0xd9d8c7dc, 0x2c77ada1, 0x2c562cf2, 0x94eb7339, 0x9b7048bc, 0xc80d8b74, + 0x5f0cb06f, 0x21a56a26, 0xcd756d72, 0xb69afeb8, 0x1da1bed3, 0x97ccb006, 0xdf4725cb, 0x31a7c678, 0xeb5cde0a, + 0x12b50798, 0x2e615da2, 0x6970b532, 0x70abad98, 0xb0546b94, 0x3d5bda3c, 0x761bf6c9, 0x1a46133b, 0x24a609b2, + 0x24c03d1f, 0x7d16ec88, 0x40b62944, 0x43bb93c0, 0x9b30d062, 0xcfbca910, 0x0560893a, 0x9c0ade12, 0xa959e778, + 0x996da217, 0xa04871c4, 0xf06e1145, 0x584a8b3b, 0x730c570d, 0x98aa50d5, 0xbb74815f, 0x5673ba16, 0x6db40d5e, + 0xd6c0c377, 0x932ca09d, 0xc32dd4c4, 0x13952f53, 0x0302d956, 0x75881f12, 0x3a3dcc2e, 0x573b529c, 0x6f15d799, + 0xdf0e00e9, 0xa1488654, 0xf45d3a92, 0xf042bdfd, 0xa583615c, 0x1baa182d, 0x789d291a, 0x6ddaf08e, 0xb695238d, + 0xca4ea42e, 0x0dff1760, 0x430e56bb, 0x95ef759d, 0xc0a7525e, 0x977e6739, 0xf74bc16f, 0x37b678ec, 0x412920a2, + 0x56b7924d, 0xebbbfcfd, 0x97574d4f, 0x671fa5ae, 0x206b0189, 0xa8615b88, 0x6bd0eb44, 0x19e7c0c0, 0xde03ac0e, + 0xb7aec1a9, 0x636d440a, 0xe672fbc2, 0x739d049e, 0x6e8ce489, 0x08ee55c9, 0xc4089bdb, 0xbe92a5c9, 0xa6103e3b, + 0x9de0da71, 0x369192b2, 0x8745f734, 0x956a6bd5, 0xab69e023, 0xfb51d3ac, 0xac01f71c, 0x4760eada, 0x2badf07a, + 0xc06e06a3, 0x4b9d6008, 0x6e2b5a54, 0x75011b54, 0x7337b751, 0x02aef799, 0x35b4c10a, 0x2c9575fb, 0x91b69e15, + 0xb957e838, 0x1f13c3d8, 0x5b75721e, 0x1d33aba5, 0xd7a4a172, 0x566b9904, 0xdb843739, 0x28e3198e, 0x1a633464, + 0x9b261e3b, 0x46899def, 0x3f97ad09, 0x9536ae2b, 0xdcd9b674, 0xe6085cfc, 0xbd29f379, 0xd927960b, 0xb93d76f6, + 0xebb777dc, 0x56cd57a5, 0x84861ca1, 0x1944aeef, 0x63a18e25, 0x152870db, 0x4ffe2cc0, 0x4bc5d882, 0xd45955b4, + 0x0a7dce5c, 0xcfcb0c15, 0x7ea9340e, 0x925245e4, 0x01265f99, 0x6933d7e0, 0xb9bf90d7, 0xfc5f0536, 0x9565e756, + 0x5b8e6b14, 0x6a12f5a3, 0xb94c3b9f, 0x2ca983bc, 0xf7cb110c, 0xa999d94a, 0x5245c9f5, 0x8f8b8b22, 0x3234e7fc, + 0x634e0bc0, 0x0b5eb451, 0x81d17e93, 0xfad19f5b, 0x9f34659e, 0x7620f0da, 0xcdbfe6e6, 0xcc13c405, 0x681908de, + 0x806aef8e, 0xd62dd858, 0xfc9b00ad, 0xbfe2eadd, 0xf7174a28, 0x2d1f4bd1, 0x42ec0c62, 0xd265080b, 0x7e6770c8, + 0x9fdd358d, 0x5b3c6249, 0x5bc9d05c, 0x88552d34, 0xfa8d1148, 0xcf64ff66, 0xe4ac5f59, 0x73905f31, 0xc7f3e8c6, + 0xc6948231, 0x385cb6f6, 0x2357a806, 0x6fb5cc6e, 0xe5bdf40b, 0x79aae054, 0x57f20caa, 0xd5581eb0, 0xbfd03a42, + 0x9a6f8f6d, 0x17e57189, 0x96292f50, 0x77d78ade, 0x8ece7d2d, 0x21b6cfe9, 0x10bb7e4f, 0x0e3dd6ef, 0x32ab07f3, + 0x9200352b, 0xb007f9a3, 0xbe1d9311, 0x97668f70, 0x908a1898, 0x495f9fd9, 0x2684c8a1, 0x17a86534, 0x64fd6d7c, + 0xa21ca56c, 0x06ca66b4, 0x5ee9deb1, 0x822d7319, 0x8009589c, 0x3d09a9c8, 0x6819db60, 0xc9a58872, 0x153a8c0f, + 0xaa702b9f, 0x83f933cf, 0xbe2b1602, 0x3fec7781, 0x66e65148, 0x933b8a30, 0x6fcd2a3a, 0xfcda059f, 0x992a29d9, + 0x1e9bcb07, 0xb30dcaf4, 0xe6f64f78, 0x80e7a293, 0xc00456a8, 0xc6aeac50, 0x32e5ca5e, 0x5e86eb92, 0x3efb53fe, + 0xc835d868, 0xd1c8987b, 0xf68cc4b1, 0xe593d82c, 0xbfe8770d, 0x50653b54, 0xb7036dce, 0x2d585f46, 0x0c9fbbd2, + 0x507f8070, 0x3a6d7700, 0x6d382c6a, 0xaf92c22c, 0x6c714882, 0x7ca5b9b5, 0xed27ca6a, 0x24b524cd, 0x79cd9267, + 0xb1e5ca42, 0x5cd967a8, 0x45265a38, 0x611b7255, 0xd353d839, 0x2e79e351, 0x3c1e5f6f, 0x69f83b08, 0xf5f52fc7, + 0xe4d1f488, 0xbb4b0d2b, 0x6e9fe611, 0x87f4ead1, 0xd9dd94da, 0x5de441f3, 0x8558db2d, 0x9a136dc8, 0x23548124, + 0x569a6bf1, 0x19cee584, 0x14890c08, 0x25ffb010, 0x4d12e5c7, 0x5d881524, 0xaf34f960, 0xeb9b38c3, 0xbc791c06, + 0x26bae422, 0x52e83a49, 0xf3697aba, 0xdfd03c7b, 0x6427551f, 0x8ec70ca3, 0xdc752449, 0x7e8fc183, 0xaae4cb1b, + 0xb37b3136, 0x706e4bb2, 0x967feea0, 0x7c654ad1, 0x1ef5774b, 0x99851620, 0x46d34856, 0x321f0a5c, 0xccb50adc, + 0xbe5c13f5, 0xe015614e, 0x3529df67, 0xb127bdd1, 0xd1f65a88, 0xf4410c30, 0xbf90195b, 0x1f7f93af, 0x0bcfd331, + 0x88cf9513, 0x8a034d55, 0x0b7645b1, 0x131b79cf, 0x1ef1e716, 0x6e36081c, 0xc6698630, 0xd9fde18d, 0x2925c981, + 0x1139bb2f, 0x51c53ef3, 0x7fe6d6b5, 0x319ff5bc, 0x951d1c53, 0xe33a3b6f, 0x54f76db5, 0xcde4fdfb, 0x452d593d, + 0x7bfd8c89, 0x5687160b, 0x58fb174f, 0x099eb684, 0x6f938cb9, 0x6be7a5df, 0xbd9d2ec1, 0x5ccbcdbd, 0x49e394b6, + 0x50d7eda9, 0xc68c2a47, 0x4740e1e3, 0x56c1962e, 0x774089bd, 0xb89d63fd, 0x5127e724, 0x921c5fb3, 0xa3c4fe1b, + 0xdc08fc6a, 0x00320c8a, 0x5cd0902a, 0x90472de0, 0x6ef5638a, 0x43012a72, 0xecf2c7b1, 0x69776c98, 0x84713f5d, + 0xfe234d8d, 0x42913987, 0xce31550c, 0x17d9f297, 0x450c2d62, 0x110ad2bd, 0x89e9966e, 0xa1994dea, 0x33e5fba0, + 0xdc9dae27, 0xd79bb7c5, 0x1ce7df87, 0x74b77f15, 0x3cdb0676, 0xcd49cacb, 0xbea80d6b, 0xa635b8f1, 0xef48629a, + 0xe94ffea0, 0xf6aea7bc, 0xffd9ec2e, 0x1ecc3ee3, 0xda2a1ff4, 0xe88e8886, 0x5e6190da, 0x8717a4da, 0x2dabe1c3, + 0xa72469bc, 0x900cab57, 0xe6008a9d, 0x6568cccb, 0xb94773c8, 0x2ecbeb78, 0xf7e44a32, 0xafc3ab11, 0xc2effbbf, + 0xf54e32bc, 0xc94261d1, 0x21bb7907, 0xe6c829da, 0xc03193e0, 0xa9b9721f, 0xcbbd786f, 0xb247c5ad, 0xa13427f1, + 0x1e9fd29b, 0xef5f1350, 0x40c8883d, 0xc3d2100b, 0x82588ec8, 0x3b071f64, 0x5a94d9fe, 0x891ca5e9, 0x8b79930b, + 0x39c5123b, 0x531cabba, 0x54be8ac3, 0x1f2feac0, 0xcf412be5, 0x77a13943, 0xb5d2358e, 0x8bb3b179, 0xd4d6258b, + 0x8fecb99d, 0x15adf869, 0xf905d09a, 0xa499ad7c, 0xfedc26ff, 0x96bccd8c, 0xcb528374, 0x2a6b45c5, 0x14cc80b1, + 0xb83c9b00, 0xa91a7fa1, 0x6057837d, 0x6839ae46, 0x30af8cd4, 0xbdaaa473, 0x59ac1a75, 0xa04487ec, 0x7cec51ed, + 0x4fae004a, 0x8caa5472, 0xfc64e72b, 0x2c16dc1d, 0x9f2ba10c, 0x3dc33338, 0xf090a934, 0x83a00c89, 0x26e0bfb4, + 0xea2ea087, 0x47ac8489, 0x08415d8d, 0xaa6105dc, 0xaa25c5fe, 0x5602e453, 0x5491a1b4, 0x626f9883, 0xd839325e, + 0xbf488b17, 0x2418b5b6, 0x18ea8a13, 0xdd186ac2, 0x3b5544e7, 0xc030b6ad, 0x27571775, 0x9ecf156d, 0x799de740, + 0x73beb89b, 0x491cfcdb, 0x9c95aa82, 0xde28b0a8, 0x51308445, 0xff7db8d0, 0xcb91a065, 0xb92eb8e0, 0xe9c442df, + 0xf71740bc, 0x17dc4405, 0xd49c0073, 0x8d8ea2a9, 0x7d9fcb50, 0xd3a3a151, 0x01c40048, 0x2a936c73, 0xddce1610, + 0x19d471c3, 0x7eaa8943, 0x9ab5f259, 0xc5341207, 0xf8b7fbaa, 0x94465af6, 0x456c319d, 0x07e161c0, 0x0a0efbce, + 0x871b9e1a, 0x68b0b5f2, 0x0705fdf1, 0x11be5e07, 0x028a0186, 0xcd7d0a92, 0x78cf0c2e, 0x7594a6cc, 0x824a0491, + 0xd22bbefe, 0x772b8cf6, 0x9792e5ac, 0xe567e730, 0x2b25eebd, 0x0d2f9204, 0x9f8432c9, 0xd96fc434, 0xf30adb95, + 0x2347ecc8, 0x50a04dda, 0xf54bc7ae, 0x2b1761f9, 0xc69b18b6, 0xfc55d1ec, 0x579fe6a8, 0x74b3afc0, 0x712eaf53, + 0x2f294e29, 0x6ebe17b8, 0x613e4505, 0xf9c6de49, 0x3d4db371, 0xeeece5bc, 0x5b8cd259, 0xb01616b0, 0x0efacf06, + 0xd454fa8b, 0x2a1aee32, 0xb28fdd85, 0xa69ba02e, 0x9d81cbd2, 0xfc14cd79, 0xeb79a83c, 0xb98ecca2, 0x12637041, + 0xf047d25f, 0x3cab1e92, 0x4fbcdc22, 0x55619d11, 0x816664fc, 0x426a31e9, 0x8f3f7804, 0x6924187d, 0xc4023161, + 0x3dbd57a5, 0x2dc4ec91, 0x164716b2, 0x18eb3eec, 0xbddb02ee, 0x72abc27c, 0x1a48fc85, 0xf34f1383, 0x64d9b430, + 0x0ec695ee, 0x262ffbdb, 0xb9c9d5f4, 0x27762978, 0x508b7a94, 0x14780308, 0x2862267c, 0x8ce11553, 0xe4066103, + 0x73760b33, 0x96612e9f, 0xae89ef46, 0xaad7ee59, 0xf35707f0, 0x8230da05, 0xcac81348, 0x76f7f2cb, 0xee4e5c4d, + 0x191543ad, 0x216a6e29, 0xe0766b5a, 0xee65d93f, 0x4cbf395c, 0xde9845b2, 0x7e57a498, 0x3e943a52, 0x4f490d34, + 0x1f09165b, 0xecdfd856, 0xbd499be5, 0x33c34217, 0x7efeb60c, 0xcb55fa44, 0x704dcb55, 0xd4e58fe0, 0xf025f81b, + 0x388a78e6, 0x792b6100, 0xb320ce20, 0x3b4e67f4, 0x56dc0199, 0xf17defec, 0xb13d3eeb, 0x6663f979, 0x47dd24ba, + 0x2bc57c40, 0x8aa4a7b8, 0xfd8452d6, 0x931b9707, 0xb00ec185, 0x4efe83ea, 0x2ecc279f, 0x7eae13f9, 0x2680a5a7, + 0x9077b816, 0xd2eba265, 0xafa37ae4, 0xd84231a3, 0x99912e17, 0x2127ad86, 0xe651aa65, 0x0cec692c, 0xde400112, + 0x815dc069, 0xde485f16, 0x8c864c6f, 0x703eafb9, 0x218c38a6, 0xf9fe7010, 0x23a201dc, 0x028ef8ee, 0x350eb233, + 0x23b68b81, 0x5b048eae, 0xfefc02e9, 0xf861f512, 0x778ac8e6, 0x6a8443ee, 0x17a73c19, 0x3d3746fb, 0xda3c400f, + 0xafc0a268, 0x3e365558, 0xd7dc117f, 0xa552d545, 0x22de62d0, 0x7f8ac636, 0x4aaa923f, 0x940d027b, 0xb1862c51, + 0xd3dc311e, 0x285cd55f, 0x72ca1f97, 0x75558186, 0xd44788a4, 0x539e25e8, 0xf90d001b, 0x42603a32, 0x72eb640c, + 0x96781cf5, 0xaa0947b2, 0x84d548a0, 0x2c64b710, 0x8de1e24e, 0x93d7a116, 0x85ade5e2, 0x6574573d, 0xfc87818b, + 0x5f352ae2, 0x54d1e487, 0x09caba8c, 0x488c5c20, 0xf332c77d, 0x30ff24fa, 0x3413ca6b, 0x4eb91b2b, 0x167d79c5, + 0x0fb4e276, 0xa1e126da, 0x249b5da0, 0x9f498425, 0x5138c3a8, 0x967adff4, 0x2b19cf52, 0xa2b04064, 0x1a50a513, + 0x28d37275, 0x2c95af20, 0x9cbbe8d1, 0x72f0f213, 0xbab81ea9, 0x2a0524f8, 0xe04b2ae2, 0xc2f37e51, 0xd0837a0d, + 0x2771a3fa, 0xf8542c66, 0xac98ad00, 0x35eb3cf2, 0x07fce353, 0x6736143e, 0xfc37148a, 0xbb1201cf, 0xaccdb659, + 0x1ae0e139, 0x1a72e007, 0xc1f35beb, 0x294af032, 0xd6f85ab7, 0x172a4186, 0x7a7684f6, 0x6a419eab, 0xc1a579b3, + 0xa487ebdc, 0x9c6605b7, 0x46462d42, 0x7ccc2ba8, 0x5babb7b1, 0xd2ffad0e, 0x55aceca3, 0xe6731663, 0x74f510a3, + 0xb34ddeb7, 0xee20150e, 0x5530895a, 0x7ff54188, 0x7cfbde54, 0x50f6fe6b, 0x8da67812, 0x334bb38e, 0xcf2a342c, + 0xf4e4845c, 0xb6565f25, 0x1f0b011c, 0x031ea0ef, 0x2cea6a04, 0xe014c9b4, 0xbc1c391d, 0x373b45a9, 0xd8139512, + 0xa274076a, 0x467e43e7, 0x5a46a67f, 0x36dbe35a, 0x9437d569, 0xc8b578df, 0x29b129a8, 0x821761b1, 0x0a120fbd, + 0x4b7286e7, 0x117a9be7, 0xcf9a17a7, 0x08023b02, 0xa8a864a8, 0xd14ff2a6, 0x9415ac30, 0x1aaa951e, 0x0dcfbad7, + 0x6f9cfb7b, 0xc23b06e7, 0x15bdddbf, 0x72a8d7c8, 0xa07372ca, 0x161afd2a, 0x86e106f3, 0x66d7fc18, 0x5c6bce91, + 0xe57ddf2b, 0x5ae3b500, 0x9f19b905, 0x366b35aa, 0x6ffe32c5, 0x754c0ce3, 0x94c3b96c, 0x6cc064a1, 0xd6bac832, + 0x937effa0, 0x72c3f0e6, 0x2b1c5f43, 0x557cfc55, 0x5702d679, 0x6388f18b, 0x86ae9f04, 0x7ad75be9, 0x8bc98e45, + 0xa6fd3f0f, 0x3b7bdb3c, 0xa63ff060, 0x37df299b, 0x59fa2402, 0x63073275, 0x20d297cb, 0xaaf160e9, 0x0c1c0344, + 0x111a0af4, 0xef153b30, 0x74d6ddf0, 0x966c5677, 0x6a974c24, 0xc7171419, 0x5ade821d, 0x195f9025, 0x76f71182, + 0xc06db345, 0x9bb5fcff, 0xf6ebb168, 0x5786f67d, 0x587c9410, 0xc1bd439a, 0x9614a52f, 0x3a18718a, 0xb2bd2842, + 0x2fef32c3, 0xf41330fd, 0x18a1eda4, 0x19517f1b, 0x5ff9733a, 0xed9c0e40, 0xc0572b5f, 0xdce39bdc, 0xacafe5b6, + 0xa96972e4, 0xf2a6ae77, 0x8960d369, 0xf2164c3e, 0x8b6cadf9, 0x56a502c6, 0x9c61979c, 0x2adcd138, 0x4d4435ca, + 0x5cd8d1c5, 0x0085c89b, 0x688fedf0, 0x00c42ba0, 0x95fdf2eb, 0x1e4f13e8, 0x32a3ad55, 0x621fbe71, 0x7b36999f, + 0x8c1d7b0e, 0x46429a0a, 0x5d4d8b63, 0x7f98e17c, 0x8f0cee1a, 0xf43b567f, 0x50c6d9e4, 0xc1ec7688, 0x4dd579fa, + 0xfeb57501, 0xc3c8a705, 0x1842ad5c, 0xed22887f, 0xe9757fc8, 0x6eca7656, 0x1ea05d64, 0x9879e27c, 0xf70dcb47, + 0x2153aafa, 0xb58672d4, 0x0a59f0e9, 0x559b40d5, 0x9d434b58, 0x95727963, 0xb016542e, 0x70b74c68, 0x662eb2ec, + 0x616baef6, 0x43bc849e, 0x8cf709da, 0x7ed63578, 0x038be7ce, 0x5497dcfe, 0x60e8837d, 0x064aa5c4, 0x8ce1f5f8, + 0xa018b2c8, 0x7a4f754f, 0x7410a476, 0x27b05479, 0x9165582e, 0x15a35e4a, 0x8b694b40, 0x770b5562, 0x63102872, + 0x651140cf, 0xaf7d0c30, 0x96b3e86d, 0x3bf670b1, 0x3ee55b81, 0x86e5ce99, 0x274565d5, 0xcd9c6072, 0x57bd038e, + 0x831b0981, 0x7b030494, 0xa9250741, 0xc3806184, 0x4d10ee30, 0xa397ea74, 0xf686f320, 0x932e0902, 0x2e3444ba, + 0x6c3bcf0e, 0x0ac56a38, 0xeb68d1b0, 0xbeb5d331, 0x0e83a9dd, 0xaca387ee, 0xfe490c0f, 0xf2da7f15, 0xf304eed9, + 0xb857ab89, 0xad7c9843, 0x8634af27, 0xc992d90a, 0x9fd47a05, 0x1bfe926c, 0xfe7df91b, 0x54df678e, 0x25fbc81b, + 0xdf54ba95, 0x40977c49, 0xb639beb0, 0xbe9b2c92, 0xcc235f8d, 0x898f84f3, 0xb1374e90, 0xfdffee98, 0xac7d18ca, + 0x0cbae5d2, 0x5719b2e8, 0x50a3d6fc, 0x0e65640c, 0x6695374b, 0x8b28f739, 0xa082d74b, 0xab27d757, 0xfb9df509, + 0x9da64c52, 0x9d958898, 0x92b81d30, 0x2a0df4ec, 0x200a7ee7, 0xaaef9321, 0x51591590, 0x58ae9443, 0x35a07dcd, + 0xbc0b92d4, 0x9beb61b4, 0xfb5f7a30, 0x3eb99bb8, 0x9f98bfc3, 0x20f9607d, 0xdb329fa0, 0x9715f046, 0xd3a574ee, + 0x1ab57ffe, 0x4fc3dc36, 0xb6818426, 0x2f186412, 0x0b32719a, 0xc0cfbb67, 0xdc833cc2, 0x7f0ad3fd, 0x847a11e1, + 0x7ab74de6, 0x2623d85f, 0xcc2b1e19, 0xc7d51113, 0x1fbd64ba, 0x9ff50395, 0x9ab1206d, 0x00eada2e, 0xad410925, + 0x11ff6e3a, 0x6a321064, 0x4a66b004, 0xc014f9a4, 0x42151e28, 0xd7b72ede, 0x330e626f, 0x46cd0859, 0xdd9c0d4e, + 0x521b3903, 0x82e19b1f, 0xc3894b02, 0xd1d6c08c, 0x171896db, 0x097cf8c1, 0x7f02caed, 0x30accac0, 0xf21759c7, + 0x3bc507b0, 0x6099e739, 0x0b6aa423, 0x3ad615e9, 0xcdfd9b30, 0x4d805e25, 0x89247b66, 0x25c26911, 0xcb85338b, + 0x87dce3c2, 0xc7d69a8a, 0xcf63d085, 0xb063bcca, 0x3514d926, 0x9103bfdf, 0xdf83e404, 0x3d99954c, 0x8d074153, + 0x4933588d, 0x24393cac, 0xfabfd11e, 0xf17d9d87, 0x5e0a762e, 0x96e555a5, 0xccb561ad, 0x1c93ac91, 0xc90f255b, + 0x69077b0d, 0xdf438675, 0xb687e386, 0x629e5716, 0x0906f13c, 0xa670326a, 0x0317ca13, 0x057199d0, 0x2f40f4a8, + 0xc7229f35, 0xd7b5a7aa, 0x6dbc5800, 0x1478a900, 0xb70c7a79, 0xd44ddc18, 0xc1a47a87, 0xe67cf52c, 0x5beee34b, + 0x3088ba09, 0x3b8a3c1e, 0xdd8a3d15, 0xf4269b3f, 0xa7294693, 0x98ff4d85, 0x08930364, 0xa783aeb6, 0xcc89d494, + 0xd32aa7d2, 0x575902c4, 0x83ffecc9, 0x21366fee, 0x3a287fca, 0x750746ab, 0x8a4283d3, 0x63e4b9c2, 0x31464933, + 0xc36a8efc, 0x1d771740, 0x804cfdc8, 0x58495b19, 0x77263d7b, 0xbc7ea86f, 0x4ea16bc7, 0x7a761856, 0x19031943, + 0xdd5e6917, 0xb62b5341, 0xa9f8eb1c, 0x73f53098, 0xe2b3087f, 0xae36c36f, 0xf473555c, 0x4bcdfe92, 0x1c6e93cf, + 0x0cd99af5, 0x47383673, 0x99342dfb, 0x99ae4c49, 0xa0fca715, 0xc2e16594, 0x0e639779, 0x29b6f43a, 0xe703af12, + 0xcbc30316, 0x5fbb3071, 0x6c397fcb, 0x3d29ae9e, 0x3064398d, 0x790a00da, 0x1fb978ac, 0xd45b99fd, 0xeccbf0f8, + 0x74d32024, 0x7d4f00e9, 0xc67e88ab, 0x2ca80f17, 0xceb75176, 0x99d508f5, 0x6df546af, 0x2dced5db, 0xa16a7aea, + 0x1b558e0c, 0xfda65cdd, 0x282309a9, 0xf6d9f932, 0x80d32c66, 0x5b6d95c2, 0xf0d47319, 0xfa25d66a, 0x44162776, + 0xb0eb4e89, 0x34e5633b, 0x32acdb06, 0x1bf6f2f5, 0x83f14352, 0x2aa6f0e0, 0xcca5c92f, 0xeac6ef75, 0x95dc6825, + 0xd5449b7b, 0xc4fee268, 0x6712d8cc, 0x136d1985, 0x4b932950, 0xe4ca37e5, 0x44fc7635, 0x4ec6a50c, 0x0ceef437, + 0xb1181c0d, 0x3bc00595, 0xc9b39d3c, 0x5a6469ee, 0xb2cde2b6, 0x7c18fd76, 0x470a47d4, 0xcd9b3a0d, 0x73a17592, + 0x453c829d, 0x97a0e085, 0x1092da8f, 0xfc7e14de, 0x21dba4f2, 0x19f8b65f, 0x7b9324db, 0xfa23783f, 0x2b153f0a, + 0x21038375, 0xdc97e25f, 0xec30958b, 0x1caefbab, 0xcb28b34e, 0xfe5a9442, 0x437bb711, 0xeb2d48f1, 0x622ae9df, + 0x5b9bd71f, 0x07961a20, 0x6d79586f, 0xb7f93187, 0x9386fc60, 0xf1d84ee6, 0xe2f7862c, 0x14dd96de, 0xe4c0d0be, + 0xfcea4199, 0x562490ef, 0x474363b6, 0xaceacb5c, 0xca6b00b5, 0xac4652d2, 0x84189c76, 0x440ff253, 0xcd727fc8, + 0x86e9cf1a, 0xe68c57b5, 0xa15dc3ee, 0x18110f1d, 0x3bf82f3c, 0x5319fd14, 0x84cd88e6, 0xc2f04bb3, 0x9be4e1a1, + 0x4a571d7d, 0x58e8d774, 0x641be9bd, 0x1214b134, 0x30794f3a, 0x00aa8565, 0xd13a0d17, 0xf0511445, 0x49fbe158, + 0xebc0ac10, 0x8a776429, 0x057e9b90, 0xeb057723, 0xaa0d2a13, 0x992b6684, 0xfcb32fb3, 0xc8e3eb16, 0x4fe266b2, + 0x34f6f60e, 0xdb2c4e7b, 0x53aae461, 0x6d9bf778, 0xd707cf0f, 0xba33c6e0, 0x11f7a428, 0x47241b51, 0x4ea6adbb, + 0xdf74ea59, 0xc2d57377, 0x6eb1bb18, 0xc89adcb2, 0x64d5c4b7, 0x11b758e0, 0x0b62a58c, 0x8bc3496d, 0x75f4d94d, + 0xf8ff68bf, 0x85abadcb, 0xe4fe8ef0, 0x2487eb33, 0x35d03ce1, 0x50b19b8a, 0x1ea67221, 0xc8e639d4, 0x9e0517ce, + 0x98097723, 0x353a4521, 0x93b4ed5e, 0x250addf7, 0x6d2bca56, 0xf36a4451, 0x80ae5146, 0x7d95e48f, 0x3e918483, + 0x201c7e9b, 0x9c9f216e, 0x21193079, 0x152af02c, 0x650124e1, 0xc56b5536, 0xfd7a551f, 0x71d254e5, 0xc9ccf520, + 0x2f1d7e7b, 0xd7ff9bb7, 0xe1bdd053, 0x721d9c2e, 0x4e342f11, 0xd17ec7c4, 0xc0781b95, 0x00c3d670, 0x5ae87e20, + 0x990129bb, 0x79827c48, 0x17db54a1, 0x3a590ea3, 0x7ec98162, 0x3977ea64, 0x957c80d5, 0xb3dc709d, 0x8d4d9ff2, + 0x12e4906f, 0x999f0edf, 0x28f3da40, 0xb95756c4, 0x63fd984a, 0xf6ce8b79, 0xac7807e1, 0x7e08efd0, 0x894991ab, + 0x36d6cde5, 0x34e0499a, 0x15852237, 0xa2b0de1c, 0xf9f0fb39, 0xb2559a6f, 0x16e2baa5, 0xb3c039c4, 0x25eb08f9, + 0x7275d379, 0xe89dc672, 0xd19e837d, 0xc99bbb1e, 0x069de3ba, 0x17d56ef5, 0x7aeee2e3, 0xc2d8f293, 0x9bdb6e51, + 0xccdd72fb, 0xf9901246, 0x19e5b258, 0xe79f3fbc, 0x9d68c620, 0x68041114, 0x8a021cc2, 0xc41dfc00, 0x2641d582, + 0xd83d5b7f, 0xc916d69e, 0x007154f8, 0x0591059d, 0xe95d9550, 0x77fbafe3, 0x9b959463, 0xb8d78120, 0x09772f77, + 0xaa2ba2f8, 0x04b366ba, 0x7bf496c0, 0xceda3dc3, 0xcdb63783, 0x6d4af359, 0x95ab8194, 0x8438d3bd, 0xa2b95ede, + 0xd79c3bbb, 0x7cdefbd1, 0x3b340d4c, 0xcfa70d68, 0x7b64ad36, 0x91f7c00b, 0x341bc8c2, 0x8d924f5d, 0x9dda2705, + 0xdf9cbb7a, 0x0b5a590c, 0x9365f7b1, 0x2fe22f67, 0x9a059b98, 0x9213c111, 0x5c0fd095, 0x7b4ab45c, 0x40a10516, + 0xfd08323f, 0x9675ab42, 0xb9fcb467, 0x8fb39009, 0x0eb4a81f, 0x3e4d62c6, 0x31c2e698, 0xbf5aafad, 0x71738a30, + 0xcc8ea37f, 0x6bc31286, 0x4f311d86, 0xff6eaf31, 0xfc3365b7, 0x055c115b, 0x5639f72f, 0x40771238, 0xa30c53fc, + 0x0b2dd232, 0xa2e6c3f5, 0xb49becf4, 0x91043e30, 0x61b2a67d, 0x5886b597, 0xc5b83a8d, 0x1a5137f6, 0x2f745650, + 0x2aebc2b5, 0xdf44b0db, 0xfc86873d, 0x44e702ce, 0x8fe7171d, 0xf60d2c71, 0x112f0500, 0xb5a80072, 0xa310d821, + 0xd5b51d26, 0xfca6ffbe, 0xd3b34d01, 0xedd46a6c, 0x9911c6c7, 0x2c7efe4e, 0x093a9a36, 0x0ea0c243, 0x4f4810ea, + 0x213abab4, 0xf715b2e4, 0xaa799e9f, 0xd623a8ed, 0xd8172ea1, 0x7a6ebe2b, 0x73728ef9, 0x62eabc5d, 0x61864b6c, + 0x9dec9fab, 0x87c31f47, 0xe5796861, 0x9bc7e7a8, 0xf9805105, 0xa38f90e9, 0xf2ac0a3a, 0xaff58ea5, 0x849be558, + 0xfec01e3b, 0x76fe2f17, 0xa67231d1, 0xf8f65c46, 0x873a72f2, 0x7efb6dac, 0x09ecc955, 0x4b7946fd, 0x78771b2f, + 0x55babdc5, 0x92d17ca0, 0x63186b63, 0xa8248800, 0x794f5d34, 0x35e3e380, 0x77bb3ff8, 0xe9be3880, 0xba559c22, + 0x1dfe8c11, 0xc09d19e6, 0x29529fc6, 0xf92c1c63, 0x405819a1, 0x2274c631, 0x2b4e7654, 0x86de7d45, 0x78a3c2f5, + 0xa474f205, 0x0b57d591, 0xd0569e93, 0x0e17bf53, 0x887406ee, 0x9e2fab29, 0x75e77239, 0xef6e1ac4, 0xb65c79b3, + 0xd8e5137a, 0xf8be0ffb, 0xc1706b14, 0x6e61c3ce, 0x5550f520, 0xe8fefde3, 0x56ca1db1, 0xce81c479, 0xc029f463, + 0xa31a9ac5, 0x8481affc, 0x7bda34ce, 0xd3ca8900, 0xb34bc77d, 0xd1efff23, 0x2550799d, 0x5a5abcf3, 0x69ea9900, + 0x990b8cd6, 0x161f2126, 0x174978ca, 0xfc9d95bd, 0xf6042325, 0x183e6a77, 0xed89b109, 0x7d5ed520, 0xd17214e3, + 0xac25a0f7, 0x04c43357, 0x2768f5bb, 0x86512e11, 0x9f5e108a, 0xb245f373, 0x5bdb29cb, 0x397b63a6, 0xc4249e11, + 0xbc5956ce, 0xb68118cf, 0x9fadb6d6, 0xd7363485, 0x906e83c5, 0x4520cf68, 0xe55c1383, 0xd4392515, 0x01cab7cd, + 0xc7385383, 0x96767649, 0x256068d2, 0xa80733ec, 0x9f1fb61f, 0xc9f8a687, 0xa479b826, 0xb309468e, 0x62efe741, + 0x9c24e62c, 0x7d423c7f, 0xb5029eed, 0x707c48d6, 0xff0e50d9, 0x1a2cd3b8, 0x05d0c8c1, 0x2eebb560, 0xacda5a7f, + 0xaf32add8, 0x9a8c0809, 0x074d9fc7, 0x62eec03c, 0x42437a05, 0x17268ea3, 0x3c6e88d2, 0x3c7b2b1b, 0x566f903a, + 0xd78ab01e, 0x308bea64, 0x1a829448, 0xbeb10b4a, 0x64a38b92, 0xdf9e309e, 0x34c065f1, 0x152aef63, 0xbf8bcdf2, + 0x7d386bcf, 0xf090095a, 0x68769053, 0xc2341da6, 0xa0bca7d4, 0x905b96b0, 0x67747cee, 0x665aaece, 0x133d3723, + 0xf23ec517, 0xf229959b, 0xa15dc81b, 0x83294472, 0x1e6c3b80, 0x5692a5bb, 0x83ae02cf, 0x5e4d0e47, 0xaf708a58, + 0xbabface8, 0x54da8cbb, 0xf695b50d, 0x7670b8d3, 0xfe1ded72, 0xfde156c9, 0x62197273, 0x3cc41ed9, 0x3623d7fd, + 0xf5aee850, 0x4ded6178, 0x38b698c6, 0x02891084, 0xae0c9a8c, 0x5209ee2d, 0xc91e9b6b, 0x9f52e82a, 0x8d733c52, + 0xdb2403c5, 0x1ec3c905, 0x5550e00c, 0xe61c8938, 0x53f65f5d, 0x0096effb, 0xdf7731e8, 0x15d84934, 0xbbf0f300, + 0x38424a65, 0x9c6ba9b1, 0x71e7b706, 0x862fdfdc, 0xa5c7b5b0, 0xc8a302dd, 0xcde7a545, 0xcf322e9d, 0x22895bc4, + 0x751947a4, 0x3007b516, 0x43ced23d, 0x1c556971, 0xae5e76f2, 0xb63fff8e, 0x1b2a89b4, 0x982258a3, 0x843f9d10, + 0x600e4b7e, 0x053b904c, 0x6f3a05c2, 0x16e2b7c6, 0x3fbdb224, 0x42e4e333, 0x172b13c0, 0x8ae6611d, 0x6c9449ab, + 0x13c1a0f7, 0x53a42f5e, 0x41962ebe, 0x8668b752, 0x6883fa1c, 0xd8dbded0, 0x7c6afb06, 0xaf293e1b, 0x15bd72fb, + 0x7136c16a, 0x1f30bd65, 0xbdccbd40, 0x9b00fc0c, 0x57d285aa, 0x540ae451, 0x3ec7bbe8, 0x0fdaa4f0, 0xb986ed9d, + 0xe210e44b, 0x44fd90b5, 0x33551649, 0x71bb1f2d, 0xb4a57fd8, 0xd55e8d29, 0xb031506f, 0x526d36b5, 0x91546a36, + 0xe4bbb73e, 0x823e4938, 0x1629fc4b, 0x8d1e263e, 0x65867962, 0xa9747e2f, 0x167a1d73, 0x41ffe89f, 0x3e6b3333, + 0xaece3cbd, 0x1b8e359e, 0x2d2869dd, 0x53e70c41, 0xdbaab449, 0xe061e7cd, 0x654339b3, 0x4407f9d2, 0x157cb54a, + 0x878410bf, 0x25fbcd23, 0x1ca8eda4, 0xf7465832, 0x0902a786, 0xe0016923, 0x252ea600, 0x99a37c9c, 0x2495e57e, + 0x847c0d5a, 0x5a7fcc1d, 0x9faf696b, 0x3b17ffa6, 0xacecbab5, 0xd19bfff5, 0xa1033bf0, 0x8f6c3cbf, 0x3d03c422, + 0x6d693813, 0x7130a672, 0xa1a919d3, 0x6b76f885, 0xb009040e, 0xc0c7604b, 0x14da792a, 0xf85d3264, 0x815b2f7f, + 0x9a0494c3, 0x88621426, 0xc794dc4e, 0x9fc6529a, 0x39192542, 0xf6af24a9, 0x7bafa99c, 0xa7561848, 0x7dc2e876, + 0x8280620f, 0x7ef52a2c, 0x6a0cb357, 0x5d317e85, 0xdcddff35, 0x576d9b7b, 0xd636fcf4, 0xf84072d4, 0xe8d06654, + 0x5c957075, 0xd0da8533, 0xbc9ac0fc, 0xc081a817, 0xf267d6fd, 0x02baabeb, 0x672107f4, 0xd2f089f3, 0xc12fd13a, + 0xcd531cdf, 0x506e6717, 0xca682e39, 0x9abc468d, 0x92fc358a, 0xd128d1be, 0x40e514a6, 0xb8e26b3b, 0xa08f2ff1, + 0xa36dd7f2, 0x23d690a0, 0xf1883aa1, 0x12e39264, 0x1e64c28e, 0xd6146cff, 0xd2d1dad3, 0x43bbd429, 0x856b2a7c, + 0x002dcce3, 0x72db4e5b, 0x5acf3518, 0x62e6c905, 0xc3f60303, 0xb3fdf06d, 0xc165d10b, 0xdff9b49e, 0xf5e6cf52, + 0x18e28384, 0x09b28835, 0xc6840acd, 0x9b7308c5, 0x0d379a4b, 0xc04efa95, 0xa782f37f, 0x795dcf30, 0x960a0084, + 0xc82e3400, 0xa9361c0a, 0x4550933b, 0x69c37ea9, 0xbdc25699, 0x4bf500dd, 0x78aaf05a, 0x9dbf8392, 0xc49dfed7, + 0x37b49c9a, 0xcce4bb67, 0xd1f4aeb2, 0x34fd165a, 0x6bed52ba, 0xa1df7c7c, 0x17b8464a, 0x33192052, 0xabb62152, + 0x99bbdb26, 0xae2c6b9a, 0xd57eab71, 0x7b2d6b8b, 0x15be6d0b, 0x61925d3e, 0x47bcc571, 0x0dbe2043, 0x6849a100, + 0x9817011f, 0xa24c7c98, 0xbb586ad5, 0xa9287675, 0xfe973715, 0x612dcbdb, 0x57d75d0a, 0xaff40969, 0x6d72f199, + 0x275fba1e, 0x7771e7f2, 0x1733c766, 0x06198cd7, 0x2f50b834, 0x8a2ac4f2, 0x10080a5f, 0x26438ce0, 0x4792d0c2, + 0x2bf9ebea, 0x9f95b095, 0xfd9aa079, 0x18f8cf0d, 0xf9da9c49, 0xf172bd8b, 0x07181ea3, 0x43f089c7, 0x022081e8, + 0xce6d2266, 0xc2a012a2, 0xe625ce4e, 0x4f0b7029, 0x77423beb, 0x1c7d152f, 0x0fcc9bce, 0x7d37b272, 0x0f3dab13, + 0xccaed92d, 0x659f3251, 0x09c1dc80, 0x90adca84, 0xe6c146ee, 0x02dcaa9b, 0xec948878, 0x28e2bcfb, 0x5c691225, + 0x9bf89aec, 0x8cbd95f7, 0xe0883407, 0x273caca1, 0x95e9ff22, 0x256b1035, 0xcf07f186, 0x7a4bb6a9, 0x527961fa, + 0xfb7bd6e1, 0x04d238d1, 0xe7f5d897, 0x6dce28ca, 0xf337c528, 0x71193ac4, 0x4c31646f, 0x178c8956, 0x84047ba4, + 0x5ff4dab5, 0x1181d57c, 0x5dfc26e9, 0x23449393, 0xde6db330, 0x96dd68d4, 0x91031b49, 0xc3961013, 0x63428021, + 0x1794bdae, 0x1e48691e, 0x571a2629, 0x52fc3ebf, 0xeae370f4, 0xc9a8b239, 0x703277ef, 0x3ea9d1b3, 0x9b3a2c88, + 0x362180b7, 0x70da8053, 0xb9b05e86, 0x8548226c, 0xca49e709, 0xee04c607, 0x435f37d3, 0xe387e68e, 0x6ac0114e, + 0xe6dc0610, 0xbb4a83ff, 0x5df06c4d, 0xecc7b887, 0x090862d3, 0x6453c448, 0x026f3d83, 0x25dbc241, 0x014b23a7, + 0x1bbc1c8d, 0x735a46d5, 0x1b397631, 0xb0cc8d96, 0x90119280, 0x92bbb622, 0x196a7620, 0xbcce6673, 0x9a335f19, + 0xe729a276, 0x52a0c34c, 0x35847065, 0xa5b8fae7, 0x4e570d2c, 0x1f5488a1, 0xe7630866, 0x0dd0cde0, 0x27802880, + 0x53f45d58, 0x9aae73d0, 0x05d1825e, 0xa8a8d05c, 0x09f55e61, 0x33aa88ee, 0x03484ad9, 0x81711350, 0xbbd4f455, + 0x9151e69b, 0x6e1a34e7, 0xb4d524d4, 0x6edcb718, 0x11916eed, 0xc9a11e33, 0x26e452dd, 0xb710b3b4, 0xfea3b801, + 0x9418da15, 0xcf8af52a, 0x3ec55e63, 0xc7f31aa1, 0x223c570d, 0xf767490d, 0xfeee9f48, 0x9c7a7eaa, 0xc553b21b, + 0x0e9efd36, 0x3786ed29, 0xa1bf85ad, 0x618389d0, 0x729aa8f6, 0x91f71f7f, 0x37136e35, 0x62ef6b96, 0x95b5535a, + 0xa0a87669, 0x2e9c1342, 0x5e556997, 0xc53b811d, 0x7d054316, 0x5cc10215, 0xd1a7729f, 0xacfe5062, 0x4ed1e49e, + 0xc5ae31f4, 0x1017e6cc, 0x02e541fe, 0x23c3bf6e, 0xcf5088e6, 0x6b36da69, 0xed51d645, 0xe4224888, 0x65b1c997, + 0x7a1df5aa, 0x4be38caa, 0xce617677, 0x80751929, 0xbf1b9b06, 0xcb1d2725, 0x8de730b0, 0x98d8ae19, 0xbc09fa03, + 0x6f8f46ea, 0x7498ad8a, 0xe2a339a9, 0x53c99f07, 0x9a4b0885, 0xe7200d1a, 0x75bd9660, 0x91af30bf, 0x763e14c4, + 0x1b37438c, 0x7f0ebda9, 0xebd014ff, 0x7756b293, 0xcb0ff656, 0xa5c7d282, 0x777cb983, 0xf03f216e, 0x8103cbcc, + 0x01843a04, 0x264bf562, 0xa5275483, 0xd0876bd5, 0x6ee215dc, 0xf08192a5, 0x0b150bf4, 0x8d18db51, 0xff14e849, + 0xf2164ae2, 0xfbf181b3, 0xcc271832, 0xf7758e72, 0x7d93e42c, 0xf8ef6dd1, 0x6cb66cd7, 0x9ff022fe, 0x9879db33, + 0xf1f00625, 0x3a773301, 0x1307a92c, 0x4bf826ba, 0x083eac1c, 0x021253ee, 0xec50f301, 0xb9008ff1, 0xe45b20db, + 0x9072adcb, 0xf52d30f4, 0x30280981, 0x75e22c04, 0x41eec8c5, 0xedcf0024, 0x18632c8c, 0xf525eb43, 0x86717b87, + 0xe7fe5d0e, 0x24d85c39, 0x8c216059, 0xa0bea62f, 0x45a053da, 0xe9ce7c9e, 0x2bbf2dcc, 0xb51bb58c, 0x8f8772f0, + 0xb1f00c02, 0x12ddff6b, 0x931fc309, 0x6580e88b, 0x6977dc71, 0x6fffa200, 0x29e6eeb1, 0xb319de12, 0x5682f3ce, + 0x5c2a3d5d, 0x160809ab, 0x9b8fd226, 0x51f60e26, 0x1477a1a3, 0x829b90d7, 0x41f5f6af, 0x7345bce3, 0x287e377d, + 0x08144d92, 0x931a79b9, 0x0795d8d2, 0x7c53f670, 0x8c8689b5, 0x0ad20715, 0xd79dfe2c, 0xd967c292, 0xa442ca31, + 0x13fa0f5e, 0x6d7d36e9, 0x6e7930cc, 0x505beef8, 0x32684074, 0x810f487a, 0x745afc97, 0x7499d3b2, 0xf3cdd5ca, + 0x15b4d0ee, 0x025efb46, 0x4e2ceeba, 0x44e6a513, 0xa36d80cb, 0x4a773f23, 0x27aea4ab, 0xd9afbaab, 0xe61dbfec, + 0x8bae816d, 0x4b74c43d, 0xccf6a227, 0x4f143fcb, 0xfb53461f, 0xfffa18cd, 0x97e758b4, 0x4fd002a0, 0x18c1f4c5, + 0x473bfcae, 0xf023b048, 0x6f1ef179, 0x97be2f38, 0xd259ec53, 0x5f8e1f00, 0xfc4114cf, 0xbad23041, 0x2bd0a12f, + 0xbf88e99f, 0x5d6dcd14, 0xa95cc0b0, 0x6c87809d, 0x0948867b, 0x9fc937a2, 0x9b9f6790, 0xcc09eea2, 0x4f94dba7, + 0x071ff13f, 0x700a8e8d, 0x9ee5aebc, 0x01ecfe48, 0xf4ff9c51, 0xd8b95aa8, 0x95acf2e4, 0x71496d74, 0x5f7bd293, + 0x20f24799, 0xb116a796, 0xd4a4fb6d, 0xf67bd7e4, 0x6968d182, 0x23b40e71, 0x14e92a74, 0x8585c8c3, 0x8165a877, + 0x664d375f, 0xcc68205e, 0xa5d8c107, 0xadf26d0d, 0x2cb69e49, 0x35cbf5a8, 0x6a5b2502, 0xd86444b8, 0x3ce22da7, + 0xa607407f, 0xe77c7995, 0x0a7aaf44, 0x03b1553e, 0x3e7827ff, 0xeafaa806, 0xdd9545f8, 0xfb8cc9bb, 0x7f112d10, + 0x642e6476, 0x06f33160, 0xaedb030b, 0x1b275077, 0x0c81e5a4, 0xcbb6e9d8, 0xda158f92, 0xaf9ef236, 0x1b7aeeaa, + 0x481d6498, 0xd56d3296, 0x39ce99b7, 0x87260194, 0xa41c0f77, 0x541fabc8, 0x1002dd89, 0x88683003, 0xa3b398f2, + 0x809bace8, 0x81cd51de, 0x9b317102, 0x8af69ce6, 0xae932127, 0x53744569, 0x29a2ad46, 0x985707ad, 0x93b77b74, + 0xe0533861, 0x0d4caf36, 0x5ca86578, 0x99815df0, 0xee8bb06f, 0xf3281f15, 0x66e839d0, 0x9bac2396, 0xefd60c45, + 0xc323c69f, 0x0a99df9d, 0x3d7b1d06, 0xd945a9fb, 0xd1514f43, 0xf52a4748, 0xa6fa6a3a, 0xbbf448aa, 0xca928241, + 0xe5dc90c4, 0x090dc0b5, 0x981e1133, 0xa2f6bb2f, 0x52ac35ab, 0x78b91c61, 0x164e1d76, 0xac23b4bd, 0xf4af8796, + 0x291d376f, 0x2e9e6766, 0x7e3173c5, 0x6b7b7d65, 0x4b7b8c12, 0xf8575f97, 0xef3ed9cc, 0xfa7f7607, 0x5e54c8f4, + 0x4ed40951, 0xf42a10d2, 0xbd9d007f, 0xffd33e50, 0xaf940e64, 0x6d8dc7e1, 0x6ee8e1d5, 0xf46306d9, 0xa3ff4f79, + 0xb3552bce, 0x48b2412a, 0x13ea090f, 0x31dd1155, 0x5ad7ead7, 0x1394d6a5, 0x7a6f79b8, 0xa9c79d90, 0x93271bc0, + 0xe71121a0, 0x89b0b3aa, 0xd6f1ca60, 0x3dfa15bd, 0x23e07a53, 0x0c6d6356, 0x6efcabaf, 0x4c6886fa, 0xcc82b45b, + 0x2374e5b9, 0x2b2baf02, 0xc4e72c2e, 0xdf52e636, 0x80e92272, 0xdf5d7b13, 0x7bdd3ea2, 0x6a1eda28, 0x69844b16, + 0x07ddd525, 0xbfc4eb9c, 0x83bc9e1d, 0x22c5b1a7, 0xa5b506fa, 0xf71740c5, 0x081eddca, 0x514a5a69, 0xcaefa191, + 0xc6584d0c, 0x1321a666, 0x0b7ca825, 0x4f568115, 0x628c2439, 0xef80e34f, 0x2026db96, 0x7b53cec3, 0x64e19acd, + 0xb19473e6, 0x2d27d31c, 0xb9f6a407, 0x8a010f2c, 0x38a9f4fc, 0xee1ccdd8, 0xb4566960, 0xa7800ca1, 0xaac721e6, + 0x7cc97a2a, 0x7d2b72e9, 0xf00d082c, 0x676a3440, 0x04ad8856, 0x29ac23f8, 0x8da64322, 0x88cc2165, 0x3b870902, + 0x6f3c303a, 0xa7aecf01, 0x243a5b74, 0xbd59f1b5, 0x283cee43, 0x24f9502e, 0xf18d13c7, 0xaba85ec2, 0xae3b6d42, + 0x9f2c474c, 0x510c26e2, 0xa84d46c0, 0x6d86c71f, 0xa7b0d797, 0xe94f9848, 0xad33d76b, 0x2c19657c, 0x509a9d10, + 0x7d62f3d1, 0x33364d77, 0xf20ad2d7, 0xd7e4bd9f, 0xa3a18798, 0xf3905045, 0x45642ace, 0x8e514697, 0x309b4dda, + 0x4e773c03, 0x91b1b137, 0x0ce813de, 0x820d936d, 0xe02efc80, 0xd32c8ae4, 0x45daa0c8, 0xb6043515, 0x9822ad62, + 0xdad321fb, 0x849e26e1, 0x6d6d54ab, 0x8febf0bd, 0x3cec8702, 0x6f0e255f, 0xf124d1f1, 0xa38494a4, 0xcadeb53d, + 0xd3676b51, 0x3962ea34, 0x3161bf22, 0xa461e2c1, 0x762668e8, 0x29557ba7, 0xf8a64236, 0xfe12f08f, 0x48361930, + 0x6bc77961, 0xba50e183, 0x2d96ba68, 0x6e64fdaa, 0xa4a3a1c6, 0xfafdf2ab, 0xf34c16dc, 0x4b83dc12, 0xbe823e46, + 0x220e9f8e, 0x01ff09a0, 0x57290d6d, 0xacc77468, 0x85d42410, 0xea80c43a, 0xd8711cbe, 0xb38f8b05, 0x033e4d93, + 0xbad26fe1, 0x4dc4c684, 0xb6604eba, 0xdb379048, 0x3057c71e, 0xcdea1327, 0x02449795, 0x2d5f5e17, 0x69fd917c, + 0xe9eeb92f, 0xc9491264, 0x9fa167e3, 0xf49eeebe, 0xddfe8c8b, 0x21831e1d, 0xd4ed2d14, 0xeade1ab2, 0x6abadd6f, + 0xe71053bc, 0x62b99d89, 0xe3912e0a, 0x0e914777, 0x8d575117, 0x2907a4a6, 0xcbd8146e, 0x7e54305a, 0x6062a8a2, + 0x88141f08, 0xba843b6d, 0x06db3439, 0x2f722e6f, 0xa40f1e87, 0xad8e3a7c, 0x19073451, 0x5e849670, 0x1737f970, + 0x35874e21, 0x358b7f91, 0xe7357f1d, 0xb2d8e64c, 0x7c438fee, 0x0d5d4db0, 0x10e4448e, 0xb7e5303c, 0x64315738, + 0xc2945e44, 0x02308b70, 0x937fc518, 0x689d68e9, 0x59800c20, 0x77fa27cc, 0x66f77533, 0x69abbf4b, 0x13b0fb41, + 0x4cde21e1, 0x80acb8c8, 0xda2577f0, 0xbf22a54e, 0x9a8c118b, 0x66a4cd42, 0x38d5bc5e, 0xcc9987bd, 0x87263423, + 0xcf727d2a, 0x566eb37a, 0x0c320ca2, 0x778d8266, 0x75529fac, 0xd1963644, 0x5348479f, 0x14043914, 0x3374deca, + 0x2a00ea85, 0x9a11306d, 0xe5244d0b, 0xee15393d, 0x78001000, 0x367da6cf, 0x835890ee, 0x37336863, 0xd7273817, + 0xbf260108, 0x3c7a382b, 0xec9e382b, 0x10448ceb, 0x5a0bc554, 0xf1e23c50, 0x6b273d49, 0xc32774df, 0xde2b6230, + 0x7515a5e1, 0xd9647c43, 0xc68738c3, 0x289956f1, 0x8bed1a76, 0xb7dd3dc9, 0x994e1f76, 0x0cf2738a, 0x82b5c688, + 0x6182390c, 0xbe95adab, 0x2247a767, 0x89678abb, 0xb8400df0, 0x096eb56b, 0xc86df089, 0x56c8ce8e, 0x90daf0ac, + 0x6e85c6bf, 0x00b0dd2c, 0xa00e8f19, 0x077b0753, 0xd308e93c, 0x50d351ce, 0x343c692c, 0x798b16e5, 0xa6790591, + 0x4dbd4d76, 0x3090891c, 0x00b5e32a, 0x8766512f, 0x9d69eb63, 0xbcb3dd72, 0xe47316b8, 0x2adf1eea, 0x7523b370, + 0x244871eb, 0xb54039c4, 0x277fecc3, 0x997fa2be, 0x90321e18, 0xf7e03531, 0xefcfae83, 0xcbd9785f, 0x98470a8c, + 0xc7ec15c5, 0x1fb620bd, 0x91a7632a, 0x170f22f0, 0x5f6f7d12, 0x5fcb23cc, 0x87433373, 0x8ce836c0, 0x9545ba00, + 0x81841506, 0xf42910c0, 0x69dbec70, 0x29c21953, 0x4784f6d2, 0x8b1356c5, 0x8db5e6f4, 0x7e564c7d, 0xf7c0543c, + 0x031b8315, 0x5c47dd22, 0xf2e09bae, 0xd29dbd03, 0x3c75846c, 0x62f3823c, 0xefac9f96, 0x3f70a423, 0xe37cf4a0, + 0x88bfa872, 0xb5f9c5d4, 0x158e9782, 0x94d30ceb, 0x1751afce, 0xd419488c, 0xa2e2868e, 0xa8fb4a45, 0xcb1cb177, + 0x99dca796, 0x0862c381, 0x51f12fdd, 0x0e2b2bef, 0x97e0b958, 0x4ee37847, 0x16a0bc49, 0x8cd02c6d, 0x94dc6a9b, + 0xce4f1d72, 0x2a213513, 0xfab31537, 0x5368c610, 0x9357d1d3, 0x481fd9db, 0xdd9464b3, 0x5807bf09, 0xa55ffa2e, + 0x03561861, 0x69dec31e, 0xd19874ef, 0xaffcd4a1, 0x9ba738a2, 0xf9d5f1d0, 0x4d1d7b39, 0xbf70360b, 0xde1824e0, + 0x77a81183, 0xb745ff37, 0x72e3f439, 0xc1aed5cf, 0x81e7bef0, 0x96064297, 0xd4f42df1, 0xc9b70192, 0xe1810803, + 0xebba1b5a, 0xb0c3982e, 0x986c2fc1, 0xce81be78, 0x95e0cc18, 0xda2fbe11, 0xcdc86129, 0xc38dc443, 0x8fbdf2a3, + 0x3becfe35, 0x39e46a9e, 0x67a7db68, 0xd5200876, 0x0c385cc2, 0xe8a44ea7, 0x206ca50c, 0x4f7cbc4d, 0xbadb082e, + 0x608da750, 0x5f05af20, 0xca1ddc00, 0x85498714, 0x96593a7c, 0xb5678bc4, 0x72e2da58, 0xc55f352c, 0x27190d67, + 0x46ab9396, 0xb1bdfeb7, 0xb5eef239, 0xa7afb5c7, 0xfe46f4be, 0xc1a0fa39, 0x6e360a02, 0x10e7de2f, 0x7020cdde, + 0xad8258ce, 0x410ad140, 0x346d5e52, 0x268d5e8e, 0x264929f5, 0xf24ab217, 0xaf655c8e, 0x66ab7caa, 0xff3ea776, + 0xfd707c07, 0x7a980973, 0x0305d4a2, 0x5918774d, 0xc0329d6b, 0xa3c62c10, 0x8f480b97, 0xae9ed439, 0x567c355d, + 0x9fdada04, 0x58cafef1, 0x528505e1, 0x42732cb2, 0x486daa37, 0x258b2bb5, 0xd2b8cf5f, 0xb0399e0e, 0x15182c57, + 0xa42e507a, 0xfce5a3e7, 0x48ce8090, 0xccf7fc25, 0xeefb24e4, 0x3dce6ef8, 0x168bf8c1, 0x079256d6, 0x4dc1c5d5, + 0x8a27d939, 0x4ce8aa8c, 0x65c338bf, 0x14cf32f5, 0x9c85be2b, 0xdd4e3736, 0xefd81824, 0x0ca312da, 0x398da6a7, + 0x0894b831, 0xba15ddba, 0xb33ee78b, 0x2c9d2f36, 0x48f0f90c, 0x602e8fdd, 0x1c568e2d, 0xf770f47d, 0x4a8576c8, + 0xba7fc35c, 0xb13ede91, 0x34311e47, 0x566aaf29, 0x60007cb4, 0xd7ba0c40, 0xd4a13d93, 0x21fbe02e, 0x8d572ca0, + 0x8b0b6e75, 0xd07fe04d, 0x1a2d47c0, 0x98805eef, 0x61e95254, 0x211b4dee, 0xc22a1ba1, 0x3e90a07a, 0x61fc6254, + 0xaa19682a, 0x0ed6a8e3, 0xd9dca8be, 0xf132ebf8, 0x1f022ba7, 0x4708cfc8, 0xd0e26e27, 0x78385976, 0x847499a0, + 0xbc9442d5, 0xafd571a3, 0xba8ca18d, 0x7ea44a10, 0xdb9944df, 0x98219d86, 0x8617cadf, 0xea0f020e, 0xc61f9bb6, + 0xd93060e9, 0x406488a9, 0xa8cf44a9, 0xed1419d3, 0xc2d3aed3, 0x805130c8, 0xc7a26316, 0x9e117235, 0x9ac10395, + 0x4af5dc3a, 0x39f6f71a, 0x3a82c293, 0xcf77b5d3, 0x653e2fa3, 0x05deab55, 0xdfa8ec0a, 0x3d6137b1, 0xc6cd1d58, + 0x8da95440, 0x3eb8bb09, 0x2adbb572, 0xa632c18b, 0x504d27a0, 0x901ba13c, 0x4d242aca, 0xa877ca96, 0x93b0f7a0, + 0xab89bb42, 0xa81e7133, 0x1b85cf41, 0x14a6e984, 0xcb772558, 0xb1d7d9f0, 0x69294be4, 0x97ce1f17, 0x17247d45, + 0x642d0afd, 0xfef7b0d1, 0x1a1dd205, 0xd276b6c2, 0x25c7dfb2, 0xfe247f64, 0xfba0662b, 0x7fe7991a, 0xc71291f1, + 0x0be54d1f, 0xbef935a7, 0xbb961684, 0xff368841, 0xc6d10bb0, 0x7e93bafd, 0x6703154e, 0xe5041509, 0x1a459032, + 0xb50c6056, 0xcef7b53b, 0x25771f76, 0x709f5bf9, 0x8d2c4098, 0x14b847d3, 0xaf41ca46, 0x7df69945, 0x9eb50dad, + 0x2f040f45, 0xf142b269, 0x75616222, 0x3be79e21, 0xb9f12751, 0xb36dbe31, 0x0e57bad3, 0xd68e7eb5, 0xfed9f56c, + 0x99bdbde3, 0x77353c02, 0x70d86e91, 0x18b4dc09, 0x92d6ae60, 0xc0b06c86, 0xcb65aa02, 0xd60a4938, 0x9bb38119, + 0x164ba9b3, 0x91b54449, 0xb93abee1, 0x948ce363, 0x77f60d18, 0xfeda3ed1, 0x09578dd0, 0x61e7c400, 0xc0d0b7d1, + 0x35ce415f, 0xab08da36, 0xab562abd, 0x0ec25769, 0xf894dd50, 0xe1b0ddf5, 0xef770020, 0x3119e27a, 0x25ab33d1, + 0xacdb64fd, 0x9906f562, 0x16a297a7, 0x70ec5b4a, 0x2aee4a66, 0x9864aa0a, 0xca353bdd, 0x69ffef69, 0x869a4ef0, + 0xd62fac46, 0x28329c37, 0x1daec9f3, 0x433297c5, 0x5f313cf5, 0xf02f130b, 0x79c61201, 0x0354d481, 0xa87b5291, + 0xc721fe24, 0x11bba106, 0xab9e93a9, 0xbdf219ac, 0x23859ade, 0xf032057f, 0x79fe989b, 0x7f36bd74, 0xce3c5f2b, + 0x03719ee8, 0xa5206ea9, 0x3ea1449a, 0x7e1e2a79, 0x6e76dddd, 0xf38d0064, 0x049a8cf2, 0xc1c9a9cf, 0x17bc9d99, + 0x994c17fe, 0x4e3630c1, 0x0c338d33, 0x9330e3d0, 0x017d8332, 0x02647f80, 0x6703075d, 0x7007cd85, 0x1beff579, + 0xc178007b, 0xab312874, 0xb64109aa, 0x7ac2a1d3, 0xba2427c2, 0xd4adf337, 0x12996f72, 0x60bc1eab, 0xe79cb112, + 0x7ec2eee8, 0xc4f0ee91, 0xb39803d6, 0x5a3743c4, 0x6d6146ca, 0x354cffab, 0x36081a27, 0x3825e403, 0xf6ff6b1f, + 0x45d3fb13, 0x2dc8c411, 0xa9a27e8e, 0x755f5107, 0x69d2ff7f, 0x520716e5, 0x7edfe599, 0x7965272f, 0x357ec6b9, + 0xbeb33a7a, 0x82d552e1, 0x53e6ffb6, 0xb81eb331, 0x24251cbe, 0xaf48022b, 0x0528dd10, 0xe98c7985, 0x154ae09c, + 0xb0f3f4aa, 0x0b78db9c, 0xbd7ea5e2, 0xe68e618a, 0x4776e214, 0x183dc6cd, 0x7cc1c6d9, 0x6e38aa1d, 0x9f5425b7, + 0x81cda9c9, 0xf7ed3ce6, 0x75878511, 0xe57d2c31, 0x5738230b, 0x440295a5, 0xf3d26abf, 0x092e1d93, 0xc9593282, + 0x2acfc4c9, 0x8177fc8a, 0x7a374790, 0xe605acd7, 0x9e356afc, 0x71b78dbc, 0xb54062c4, 0xee474b99, 0xea31a2f6, + 0x21b50541, 0x567d2f83, 0x77b4f710, 0xa3d61d5c, 0x2c8f4a28, 0xf5c85d1c, 0xacdf46f6, 0x1d8894ee, 0xf60f7463, + 0x62fba7fa, 0x231a7530, 0x806efeed, 0x05265400, 0xe5254d49, 0x7108fa5b, 0xfedc67ff, 0x78841909, 0xb32a6385, + 0x85fbae6a, 0x112b2b39, 0xb881d898, 0xc2b0f738, 0x25f0546b, 0x087fe000, 0x2a70b6bb, 0xb52787a7, 0xe7a01295, + 0xf2bfc93b, 0xddb5bdfd, 0xb35348e6, 0xcdda7bfa, 0x00f35f44, 0xafd1e89f, 0xac43940b, 0x30f013b4, 0xa103291d, + 0x76bd1f13, 0x6a281e5a, 0x41c78364, 0x40115ffa, 0x6b25edf1, 0x2c3e6db8, 0x6d2775ac, 0x2e51137d, 0xf52ae090, + 0x1836dd18, 0x4a1c6f5e, 0xb88f9248, 0xc6c01b79, 0x302e24d5, 0xbd0751cc, 0xf1369de0, 0x270cae5f, 0x398f1761, + 0x2a221c78, 0xaff10b2e, 0x352a3ea0, 0xada3f40e, 0x37deadf9, 0xcceb27d1, 0x1a1e7e81, 0x08b1d54c, 0x8d4aa3ef, + 0xbf84122f, 0xb9f183cf, 0x99fe5895, 0x8f10e93d, 0x3f7b8a0e, 0x49561111, 0x47920f1d, 0x66cbda57, 0x5e51f166, + 0x48b3e0a7, 0x86344b63, 0xbf87c3a2, 0xa64df3b9, 0xecd54e01, 0x88f9b554, 0xa66fe401, 0xd7bcb150, 0xd57af4c2, + 0xbd0fa52d, 0xa7edbdc4, 0x4a8f8d7d, 0xb3ad773d, 0xa18ec8f2, 0x09a499b3, 0x1adffc40, 0xcd1340aa, 0xa98854bb, + 0xdd7bf115, 0xea0860f3, 0x9edb6665, 0xfbe7e4eb, 0xa1559d77, 0x8dd4f73e, 0xf58749a4, 0x3ac66850, 0x40526087, + 0x908cfd6c, 0x558734f2, 0xf77c87f3, 0x09fde054, 0xad548725, 0x86315d77, 0x8c99f36e, 0x12525d7f, 0x9d997970, + 0xb233cb1d, 0x20a1d4c5, 0x0e373384, 0x4f50bf59, 0x42258edc, 0x1def9714, 0x51cb0e9f, 0xa020bc60, 0xb7c739c9, + 0xee6ff1bc, 0xf7cf791b, 0xa9c16ae4, 0x23599817, 0xc4a219eb, 0x4e8bdf69, 0x93ab98ed, 0xa0c8902a, 0x20636eca, + 0x7d873a31, 0x6f8b48d8, 0x9a10f209, 0x07c48746, 0xaedcbbdb, 0x972fcb88, 0x01b4d19a, 0x34e4ea2b, 0x27dca3e9, + 0x84fbfff2, 0xc3833e1f, 0xc56e8b8c, 0x779445f5, 0x6145c382, 0x12bab023, 0xa32d904e, 0xa322be6f, 0xffdc71ab, + 0x3ce2fdf9, 0xeb27b726, 0x6c32d4b7, 0xded97d86, 0x02e3ccc1, 0x023b5cee, 0xef871e25, 0x7a2f93c3, 0x19213e92, + 0x5bf3a373, 0x33b6f8c1, 0x7df77cbe, 0x12597ac0, 0xbac37d44, 0x17bc9260, 0x07493eb8, 0xda8f1551, 0xc2b8ad55, + 0xe38a4d3c, 0xbb236146, 0xa9a27256, 0x9e0149b3, 0x542ab2f3, 0x30f6c92a, 0xb7caaa68, 0x3ed62af4, 0x6d4dbada, + 0x945b34bd, 0x37f28cfb, 0x22c33176, 0x59403d7f, 0x4895d58f, 0xb228beea, 0x65bfb051, 0xe77ae5f2, 0x2ca14906, + 0x64829e02, 0xded16200, 0xd6cee5d0, 0x0f7bc1b2, 0xc48f0ff9, 0x8a393b53, 0x51a8c087, 0xec89ded3, 0x61a49044, + 0xd1a7d1bc, 0x50955bec, 0x8d5ffa1f, 0xcc5020f3, 0x50483fec, 0xe77460c8, 0x1e293651, 0x170c6a81, 0x7f85c62f, + 0xe968fc7c, 0xb9498ba7, 0x857c8d30, 0x6fd8ca7b, 0xb928c151, 0x5275c7f0, 0x4c0bbf6f, 0x7ce0c5b4, 0xfb2e0977, + 0x19b97819, 0xed22e77b, 0xa37963a1, 0xb8f2dfa5, 0xa0c11d56, 0x0f1a0e5a, 0x2e8c3c3d, 0x36a10cee, 0x09acdf51, + 0x54963f83, 0xaefd9c7c, 0xa9b47d0d, 0x26fec7db, 0x13fd8a4a, 0xea9aeb8e, 0x0bee1c05, 0x54b1e457, 0x42170082, + 0x7123e047, 0x6b23c7ce, 0xdac08b10, 0xf7a2478b, 0xa89619f9, 0x6642773a, 0xaccff0ac, 0x1699e0a8, 0x6fb19095, + 0x7743c799, 0x215385ff, 0x501d8e69, 0x0a59a218, 0x56ffdc26, 0x96a558bb, 0xb1471532, 0x93a8802e, 0xd384c68f, + 0xf2f06291, 0x7a435dde, 0x20e4c9f6, 0x12e16d07, 0x2ad42e6f, 0x98426b51, 0xec1f66cd, 0xe2a4723a, 0xc4dc1dcb, + 0xbd913ea4, 0x04545a1d, 0xb3ea4814, 0xd71289fe, 0xf9aa82a2, 0xa0f645a9, 0xff2452e6, 0x66312d4b, 0xc295bae9, + 0xd5223ef3, 0x8aebc891, 0xcd0251fa, 0x32901794, 0x38c9c567, 0x3c43350b, 0xec25edaf, 0x778520a3, 0x5c79ad94, + 0xcedf582d, 0x61632d76, 0x8c7c424d, 0x833d3031, 0x5ce02282, 0xc44d85bf, 0xbc16274e, 0x8807eac3, 0x5fff2374, + 0x5bcee5e1, 0xd6a731d1, 0x1599de17, 0x2a44877e, 0x23fabd7e, 0x3d9f273e, 0xbe8593c2, 0x2fcecdca, 0xeee8fe9a, + 0x212288ad, 0xb909088b, 0xdaf1c317, 0x41d58e0e, 0xd6635612, 0x811cdb3c, 0x396b859d, 0x646eb065, 0x9f825041, + 0x4653d8dd, 0x3b9bb3c8, 0xcb2ba9f9, 0xfbf0479e, 0xdc06d34e, 0xbcca6dd6, 0xf6e7cee7, 0xa09730f3, 0xf0ba0cf6, + 0x6940b4bd, 0x3d977dbe, 0x5717a64c, 0x7dbe1ddf, 0x0c70ffff, 0xafe1a671, 0xc847ae18, 0x30e18300, 0xda1bcebb, + 0x904451cc, 0x512aea36, 0x53e81566, 0xa408cb3b, 0x23fc0396, 0xc90daf46, 0xbe04e0b8, 0xb5a61bd8, 0xd9084a9d, + 0xc2453b1d, 0x776f6d7c, 0x12f03440, 0xcbff1391, 0x642634c0, 0xd6ef6e7c, 0x95745811, 0x85f83880, 0x9d8700d6, + 0x472a206a, 0x53926f50, 0x0d4800e0, 0xfd8db11e, 0x8acb9421, 0xaf3a78f5, 0x9e6ab3b3, 0x0a2b3eab, 0x42b01825, + 0x76b71e65, 0x20ced890, 0x727d9b84, 0x1b649f46, 0x1caaec16, 0xd72ea372, 0x50efe84a, 0x528dc348, 0xcaf40167, + 0xbd9f964c, 0xd281e46f, 0x19d6871a, 0x42ba6979, 0x8218c687, 0xde992d0d, 0x0e0534c5, 0x167f3cc9, 0xda66028c, + 0x6da29743, 0xecca8326, 0x95f3c133, 0xf90fe557, 0x738bd9de, 0x5d0f5acf, 0x2ffc9320, 0x9fe7d45d, 0x282fe7b0, + 0x4f1c6f43, 0x944cc575, 0x732bcf68, 0xea03aa98, 0x4556c6c6, 0x18f1dfd8, 0xae179bc5, 0xbd5bf965, 0x784f4784, + 0x19dfd404, 0xb5214493, 0x2e7b3bfc, 0xf6f1c214, 0x05355185, 0x883b0364, 0x7ceb847c, 0xa68543e9, 0xd272de0a, + 0xa60dfd16, 0xc346a80c, 0x4a9a2390, 0x04888b4a, 0xdc76599e, 0xab490c89, 0x70dee9a6, 0x96dc6ffc, 0xad42dfbd, + 0xf9cc108d, 0xdf1c802f, 0x8dd869da, 0x616c1ad2, 0x40c0e3d1, 0xeca0a132, 0xc9c964c3, 0x353717dd, 0x02fa5cb1, + 0x9a000e60, 0x3167b458, 0x3386c4f8, 0x8f8a9861, 0x0dc111c3, 0x3d568618, 0x3e535bb5, 0x67669c78, 0x0a070dc9, + 0x16847b2f, 0xedc6afb2, 0x64353c87, 0xb5e184a4, 0xaad2918c, 0x8c829a86, 0x6fa687ac, 0xee9c75e7, 0x783f84c8, + 0x8e80b1f7, 0x9b40a3ee, 0x3f7824b6, 0xc4034686, 0x9da433f2, 0x04ca1842, 0xdcf5ab1a, 0x6995fba5, 0x18ddbb07, + 0x708697cf, 0xd12fc109, 0x6889d435, 0xef52bf53, 0xfffda138, 0xb5531243, 0x739a0880, 0xa56dddc2, 0xc55be902, + 0x5236e878, 0xacbec5df, 0xbe718dab, 0x1d9db4a9, 0x6af5bbf6, 0xc2712375, 0xdb7aab3d, 0x6c1e3f84, 0xf15ecdc2, + 0x256cbc8a, 0x3793fde3, 0xbb429d69, 0xd306f801, 0x6e929a4f, 0x8829a82f, 0xa44ff9fe, 0x5465c217, 0x943835b0, + 0x5ed6324e, 0xd1a7b02f, 0x45b03003, 0x6877bd54, 0x5699caea, 0xcc092de2, 0xe89f046b, 0xb3a32b70, 0xa6010960, + 0x2ec6172b, 0xd1faa9db, 0xdfb141cb, 0x488f4211, 0xabb6cd4b, 0xfbeb809a, 0xcdef4c29, 0xda106fc6, 0x88524203, + 0x9100bdc0, 0x5cd6d819, 0xa0a0e9d3, 0x7b18d3a2, 0xcc44b116, 0xc1184c58, 0x98e37d59, 0x1fc6e0fc, 0xa8a6db30, + 0xde094f1b, 0xad7990e4, 0xe828f58b, 0x2be0337f, 0x551d4a46, 0x8e449f78, 0x5dc49219, 0x81cc6590, 0x65951b87, + 0x58291254, 0xba5781d0, 0x2efb9f06, 0xe85e5367, 0x46c1735d, 0x71632c42, 0x6d38102b, 0xd425dec0, 0xde9edd0f, + 0xfd54fe0d, 0xe02fa18b, 0x282007f8, 0xdc6e518f, 0xb8314049, 0xe2589921, 0x88b529de, 0x4bb1b2fe, 0x17085bf4, + 0x667f0867, 0x3546b610, 0x792563af, 0xddc7ff49, 0x17ecf93b, 0xa1497714, 0x4603e891, 0xb0849eff, 0x723dbfcc, + 0xf328151a, 0x5d9d05a0, 0xb8835bf4, 0x0afa07a8, 0x711df691, 0x5a9959a6, 0x8f452faa, 0x139ab2a0, 0x766d8492, + 0xb0ca12ec, 0x8a430854, 0x5232586e, 0x52cd3dd5, 0x8d4b83c0, 0xee708145, 0xad164059, 0xcf1db060, 0xd0e9c9f4, + 0x30e01205, 0xf48c565f, 0x076bcf02, 0x556a6ea1, 0xb3890ead, 0x426507c1, 0xf2e6097c, 0x204b825a, 0xe0fb6fb7, + 0xffdfdde8, 0x6ffe7e05, 0x8d3f2d33, 0xe81b122d, 0x5acd8ec6, 0x3072dbba, 0xb2ac2051, 0xd8baf4cb, 0xa62ecd99, + 0x42373cab, 0x061a5724, 0xbc34237c, 0x69887b0e, 0x575583b8, 0xdd62bf20, 0xa5a349f6, 0x5d287790, 0xf03fe5d9, + 0x4baa1cd3, 0xaf2bcd6a, 0x185714b9, 0x49f87cd2, 0x23f69999, 0x89831387, 0xb6687a63, 0xb47d48f1, 0x7d5766c0, + 0x4c6b1011, 0xc6857df6, 0xa519124c, 0xd60935b9, 0x42dfe682, 0x5e379f02, 0x9d781d59, 0x8e3a32e2, 0xc3cd7ea4, + 0x6cabb7af, 0x8abf332d, 0xec6d8984, 0x4e4fd04e, 0xa2ea93ba, 0x9f35358c, 0xf6f054c3, 0x66422e67, 0x3e09d94a, + 0x6f691da4, 0x02807bfa, 0xc7da9b01, 0x646285b8, 0x5b306c23, 0xc0b49349, 0x23c259c1, 0xb1f31caf, 0xea34c1c4, + 0x9378db54, 0xf7472b0d, 0x8c6af90e, 0x9ab13dc7, 0x718337a6, 0xa78a5742, 0x27f8e2a0, 0x3ed149f0, 0x2829cfba, + 0x7b4873e3, 0xe906ae5e, 0x90038b0d, 0x51f7cac2, 0xeb32ad81, 0xe5efd90e, 0x4264aff7, 0xd9f0b829, 0x78328b10, + 0x2616a257, 0xd27fa475, 0x101333a3, 0xf08f2ab1, 0x0c02a74c, 0xae150c14, 0xc92dadf2, 0xf62ec8be, 0xbb144b53, + 0x60aea644, 0x789534e5, 0xf49b6d29, 0x6ec1d4e3, 0xb360c6a5, 0xddab851b, 0xc9da0089, 0xa275639d, 0xad834fc8, + 0x292a46d1, 0x04384a2e, 0xc15267c1, 0xc501d079, 0x424a57db, 0x5c0d476c, 0xbd7b46b2, 0x4e708942, 0x1a16eecc, + 0x48f5491c, 0xf4a35ee7, 0x86f63b85, 0xd17b3e2f, 0x8e11691d, 0xe81b55ad, 0x51fa5a5d, 0x4af75e22, 0x7227463b, + 0xd630a517, 0x5cf182f3, 0xd1934537, 0x94744d74, 0xfb5a0d2c, 0x25d64058, 0x7ce3083d, 0x591bcfbb, 0x24f38782, + 0x61afbaea, 0x70d81f2b, 0x12885717, 0x8ce9a3ec, 0xbe618463, 0x789dcd51, 0xc5c8aeae, 0x081e3732, 0x6cec6ac6, + 0x794dfbe3, 0xb36e5082, 0xb34c52d9, 0xfa124ebb, 0xb2ba2fab, 0xa16f1ebc, 0x5f93e0b1, 0x99271235, 0x216ce150, + 0x816e8916, 0xe34b6522, 0xfdf38cac, 0xebcc689a, 0x3e0aff3b, 0x4b3c788f, 0xb322b10f, 0x04c8930f, 0x9e4c3ac8, + 0x40595b42, 0x1f3cfba4, 0x14b4c46d, 0x1e945fe0, 0x58529ac0, 0xc899d129, 0x158787cd, 0xc3dffa8c, 0x343ac2c7, + 0xe94b7d46, 0x6c635aec, 0x777d3d62, 0xba4b9d8f, 0x673387e7, 0x0a2ce52f, 0x47d16f7b, 0xfe972e7f, 0x0a34f34d, + 0x80a9fc08, 0xca20709d, 0xd5dfdf4d, 0x22ea4f94, 0x99b97594, 0xa8c32b5d, 0x56940679, 0x756ec262, 0x82707f64, + 0xa5bcac3a, 0x64ea6f86, 0x841393ec, 0x2d84f684, 0xaa9f748b, 0x18d8cd16, 0x4c3bbb1f, 0xb46ffb30, 0xfe44bf80, + 0x9d22a366, 0x72b32faa, 0x113a119d, 0xb076d48e, 0x531678b6, 0x10a61364, 0xbcfae686, 0x44082fcb, 0xf52cf2f9, + 0xe7743705, 0x5daabc0b, 0x5a97146b, 0x99787c88, 0x043a249c, 0xe2b2c170, 0xe4320492, 0xdd0e862f, 0x4cfd953c, + 0x978f91d3, 0xf98bb653, 0xe3a3b26a, 0x38caa9c0, 0x0275a1b2, 0x03056c8e, 0x92342979, 0x23b02001, 0x0fb82103, + 0x75bdf243, 0x28bcfe84, 0x7e843242, 0xd4ceec3c, 0xb4715daf, 0x7a0cf9e6, 0x4597b2a4, 0x87c6f90f, 0x883d41d0, + 0x510a938e, 0x72519710, 0x5c28982b, 0xe9c050f4, 0x675f00cc, 0x306a5bf3, 0xbb338395, 0x88b9dbff, 0xe531be67, + 0x40df7159, 0xeec72d70, 0x7bd0d3e9, 0x5dcda9fe, 0x363d7490, 0x81982f95, 0x2c7dadd9, 0x5b08e7b3, 0x7448abd3, + 0x9688aa76, 0x4dc7fa27, 0x81786026, 0xb62578f2, 0xd85ad87b, 0x6211964e, 0x449d4246, 0xb35db9ad, 0x03f2d302, + 0x281aadef, 0x58386c34, 0xf9b57137, 0x81b6cfde, 0xfbdb3e3f, 0x4a6ebe18, 0x978fe084, 0x1302eed0, 0x4dfd16b3, + 0xe1f98225, 0x666fe090, 0x661919b4, 0x5db7b00c, 0x53e7adcb, 0xdc17262b, 0xe14761f0, 0x07136764, 0xc173550c, + 0xfe3e917d, 0x5547c7f7, 0xae38ccf3, 0xc8b25747, 0x0272e7da, 0xe43a8200, 0xd065cb73, 0xe16b47ad, 0x40e5baa2, + 0xde59500c, 0x22f91a37, 0xa1b6e57e, 0x0b0707e4, 0x90b9c501, 0xd62bc285, 0xacbfc532, 0x271d25d8, 0x2b137265, + 0x92b70341, 0x2acfe036, 0xeb304d0a, 0xef66935e, 0x4e215755, 0xba806449, 0x3eb6e031, 0xf054a97c, 0x7e38070c, + 0x7ec608f9, 0x0218791a, 0x4a3964d6, 0xabbf80ce, 0x0bb36a3b, 0x188e4421, 0xe0fab25b, 0xd9845aae, 0x46f5a2d2, + 0x68ab6c61, 0x65d044fa, 0x190df41d, 0x99816f60, 0x494c6cf1, 0x68d5d146, 0x9c55ec2f, 0xeaa43f86, 0xa80d9ba7, + 0x1e15abb3, 0x37e5cbc3, 0xb8227a6c, 0xb79ddb43, 0xf9e59a1a, 0x8eedd33a, 0x9c11d720, 0xb8ab875e, 0xb3d10458, + 0x8d3cd9d1, 0x53746eb9, 0x9d22a8b9, 0xd801c5b9, 0xf794ec53, 0x3764cda9, 0xbb7fc036, 0xcb9a9c93, 0x9541e392, + 0x1a0c03c5, 0x6a1d7840, 0xb42d1f47, 0xc0bd573b, 0x094a3be9, 0xfd198817, 0xc521a376, 0x0a2370a6, 0xa72493f3, + 0x8fc157d8, 0x23267b4e, 0x47f6b461, 0x06bf939f, 0x521bc1f0, 0x618e67cd, 0xaa06c016, 0x6e60f109, 0xe170c8cf, + 0xa5820150, 0x728680fe, 0xb249b611, 0x2bc81298, 0x71bd8bc4, 0x4d93fd87, 0xd801f5a0, 0x9a1fb03a, 0xde383d93, + 0xf55c9eb4, 0xe22d728b, 0xc01685bc, 0x5bf957bd, 0xc0b34d64, 0x798b9c53, 0xb44c87b7, 0x21b44a1c, 0x312e095b, + 0x096e16ab, 0x431773ba, 0xa6b1dd34, 0x427061ab, 0xcffacead, 0x1dce0603, 0x33155688, 0xa0385eb0, 0x06d5a63a, + 0x70266568, 0x79a62d8d, 0x4acbd648, 0x52a5e976, 0x5d57bd1f, 0xc1b814a1, 0xb0e03afd, 0x074eabeb, 0x451b1b67, + 0xe02933cc, 0xda95472d, 0x5ab3b7df, 0xfd9ab5e5, 0x31e18f03, 0xfad30297, 0x9bbde221, 0x155dce37, 0xb1274880, + 0xb77a1e95, 0xe7d8ef47, 0xebb8e44e, 0x4ad4e08f, 0x8d9695b9, 0x364933e6, 0xa8dbc9bd, 0x08da288f, 0x5f211212, + 0xeed8175a, 0xf7613703, 0x9ba5b58c, 0x0bdce02c, 0xf164cc85, 0x801fe6af, 0xbd7447dc, 0xe8c7e368, 0xada7983b, + 0xa38aab9c, 0x7e541a4d, 0xe4b08122, 0x0eff2348, 0x74151f51, 0x5c914f9a, 0x888c7178, 0x01ba24d8, 0x6474f4cb, + 0x2279c3f9, 0xd79c47f2, 0x41998497, 0xb7511781, 0x6f8f6899, 0x36cff274, 0x589b1775, 0x41761779, 0x9f161e58, + 0x70ed3cdb, 0x0524a1a0, 0xa90adf87, 0x1a84d061, 0xf89d1971, 0xc7a78a9b, 0x7a412607, 0x0dd0aea0, 0x2a999bdc, + 0x471421a3, 0x8ad933e7, 0xf638a0ba, 0x195b53fc, 0xdc499349, 0x045c7973, 0xe62d4583, 0x4192df98, 0x2c7e048c, + 0xb435f32a, 0x4dda93dc, 0x4977c948, 0x136cff7a, 0x15ef8586, 0x4fa0819f, 0x1c8a24bc, 0x6d12770c, 0xeb6d74d6, + 0xbab35133, 0xe2fdb341, 0x84760e60, 0xd97f6477, 0x8c9c46d4, 0x7c2a0438, 0x787273bf, 0x732b7fc0, 0x6f6a036d, + 0xa86355f0, 0x443b0566, 0x375e0c2c, 0x095bc03c, 0xc99ec0c7, 0xb6b39dcb, 0xc2c8501d, 0x61f0800c, 0x5dfefe69, + 0x79924b39, 0x166bb62f, 0x3eefaeb7, 0xa1671b7c, 0x180364f9, 0xc5a76e15, 0xefb44087, 0xd6acc464, 0xf41e206e, + 0x5bc4ebfd, 0xeb25d343, 0x914c356a, 0x9dd1178f, 0x021a1f1b, 0x8bb5e614, 0x504ca29f, 0xeac5f1a9, 0x5c3161b6, + 0x7f512dfe, 0x6b41d44e, 0xcbd0ee32, 0xe85daa5c, 0x4d58e8b9, 0x32bd2d6f, 0x71229e38, 0xcc60175e, 0x78a4d51e, + 0xfea74128, 0xc27de63c, 0xbd965f6c, 0x488621ee, 0xc9ece8e9, 0x345595d8, 0x6cc8c0f6, 0x961a54f6, 0x0578d036, + 0x7eb9a1db, 0x9502d100, 0xe219ba8c, 0x0999794a, 0xb644fe92, 0x2ab17be5, 0xbd483b02, 0x4c8065aa, 0x81b523c6, + 0xf8f35dc8, 0x5aab565d, 0x15b0ff8b, 0x502b6092, 0xd0b0069c, 0xfe03b9e4, 0x45a5411b, 0xf4ee0777, 0x1c53b2d0, + 0x612ab774, 0x0547aefc, 0x518e3939, 0x2ba509b0, 0x8dfbd360, 0xd79c17fe, 0x1455f228, 0x69a8d6bf, 0xddce0c4f, + 0x9573fce9, 0x571aee13, 0x068b9e50, 0xca8d2905, 0x6da76189, 0x7190adca, 0xd66ca6a3, 0x8d3c5568, 0xc2f8df10, + 0xfd805b5b, 0xa68f4421, 0x9db20c06, 0xbaa7d28a, 0x56ff584a, 0x3b8f131d, 0x5aa35dec, 0xe1c2fd27, 0x603dd172, + 0x23594852, 0x9711491d, 0x1792207d, 0x200809a4, 0xc558e745, 0x5d1ce6e9, 0xe83ce230, 0xdcbfa30b, 0xba5729ee, + 0x8fd2c9cc, 0x7debd2ec, 0x8c1ef1d1, 0x9326aad9, 0xa7a1f44f, 0x34952e5f, 0xaa7e5288, 0xbcea7b44, 0xa33c86b9, + 0xb26ff078, 0x706098fb, 0xe463bc15, 0x7c080419, 0x8b5f09dd, 0x8ae0060d, 0xa7c798c2, 0xaf802ae1, 0x06e37456, + 0x21fdf818, 0x63eb620b, 0xa83bdd5e, 0x27b0e991, 0x2fdd9234, 0x759bfe89, 0x0552d082, 0x5ba85275, 0x35a39432, + 0x85f1fb45, 0xa2414277, 0xac9f0be7, 0x962ecca2, 0x70c9ea67, 0xef6f117f, 0xdf119b69, 0xb5b398c4, 0x52764626, + 0x24adb475, 0x0394fd6c, 0xdc195a43, 0x149de6e6, 0xc3195d59, 0x45f7dcaa, 0xd8154b12, 0xc4f47a2b, 0xaa3c9c17, + 0xd74ec998, 0xed673ebe, 0x8c7f1f99, 0xfb695601, 0x22969263, 0xe15cec7f, 0xeaa6830f, 0x73b48c01, 0xe0074aae, + 0x8efc59d8, 0x3bcb2a14, 0x518daedf, 0xe57cdb33, 0x321729c0, 0x88a836bb, 0xfb27fb30, 0x6cd17c1e, 0xc50f135f, + 0xc7f1b654, 0x7ed33892, 0x377893dd, 0x18432f02, 0x2d5bd645, 0xe5483bb5, 0x282fb5ab, 0x945afc4e, 0x981af27e, + 0xf5749e4d, 0x360f855d, 0x2b0247c3, 0x07bbb484, 0xa39696c9, 0x2212d653, 0xfb084682, 0xe231cfdb, 0x3ecf160a, + 0xf406d7c5, 0xa7ea7528, 0xfb5a5385, 0xbd9526e7, 0x5851866f, 0xce2befe7, 0xabc1cd28, 0x1236217b, 0x84c35c46, + 0x266e6251, 0x33a570ef, 0xbfae2654, 0xe20319a0, 0xcd44240c, 0xb9e441c3, 0x04479359, 0x214bb3de, 0xf8bbba22, + 0xe888c6a4, 0x532152a8, 0xeb20a9fd, 0x81541fff, 0x181c0a7c, 0xf2f658c1, 0x58d7c335, 0xeaed404c, 0x06df0e33, + 0x5e8097a3, 0xe1b7f6d2, 0x8e1e710e, 0xbbe22197, 0x648e8b59, 0x5678246d, 0xbbddab2e, 0x3e83f2c5, 0x121e38da, + 0xe274de5e, 0x880da7e1, 0x9329bdc4, 0x92706b7d, 0x6216d3a6, 0xfcba4f15, 0x7c67b82d, 0x73c11501, 0x04d61628, + 0x6ebabd3a, 0x5a96ce4e, 0x7de34f0a, 0x7e3efab0, 0xf8fe831b, 0x9b9b0d55, 0xfeade3bb, 0xba310634, 0x13126e74, + 0x0ef26e5b, 0x26fcdada, 0xa839f6c9, 0x1a9eaef8, 0xff1f6e34, 0x846cc56b, 0x7035c32a, 0x13c7580b, 0xbf1f8a73, + 0xab43e2ff, 0x8124b303, 0x9beb65bd, 0x42e685f5, 0xa73eaa0a, 0x6723ad81, 0x4cb9106e, 0x1f27237f, 0xc8998529, + 0xc2b9a658, 0xe5dd63bd, 0x3bccaec4, 0x8b07a8a7, 0x377b13db, 0xe182701b, 0x8d01ec45, 0x791f2361, 0x4f7610d2, + 0xb6aad81e, 0x65ffd5a5, 0x45dad49a, 0x5d66663d, 0x7423cd3f, 0x74604dd2, 0x2b072cae, 0x4338d6f0, 0xb07c6626, + 0xf3f19d9a, 0xc467eedc, 0x780a4be7, 0x42734df3, 0xad4f7159, 0x105ad877, 0x7125cbe9, 0x98112ded, 0x3c71ee06, + 0x814e15fc, 0xec3401a0, 0x789755cc, 0xd8d5f901, 0x7883e248, 0xc426f94d, 0x27596020, 0x3dcc094a, 0x829a2a34, + 0x47ef551c, 0xd6c061d4, 0x2e4beb4f, 0x92c2b929, 0x0f98a381, 0x073a9fc4, 0x270dc2d7, 0xc999abf2, 0x46540e96, + 0x4ff96a39, 0x3c16468b, 0x9e92de75, 0x320e3c5f, 0x5881cbb8, 0x5288efea, 0xfac8dc33, 0x7459d94a, 0xea45469b, + 0x90569072, 0x62f059f6, 0x8c1a5d66, 0x471bed19, 0x57da4433, 0x9b338271, 0x0412e3a3, 0x5e12aa69, 0x935cc818, + 0x0939cd3b, 0x129b4fa7, 0x555e1b6b, 0x137e5e4a, 0x98297a8f, 0xa58e7292, 0xdb415493, 0x4211922f, 0x70bd7ed6, + 0x9782e5ac, 0xfa78c66d, 0xce29ed31, 0x65b19c3f, 0x8072057d, 0x28622867, 0xc5baf5a6, 0xc62047d2, 0x504cd44a, + 0xf4bcaec5, 0x0bf2fd25, 0xa75def42, 0x06de54a8, 0xc28dd676, 0xf5a857be, 0xb337dd75, 0xd4a1c724, 0x6c0a6e51, + 0xf6682587, 0x93c05cca, 0x975b0c66, 0x5bf1f9db, 0x20715c39, 0xdc212644, 0xd19c8780, 0xad5945d7, 0xe7a9c132, + 0x5629f9bc, 0xd4cbd83c, 0xfd54a801, 0x689131fb, 0xb37e684d, 0x7e605dad, 0x90950aa4, 0x30345155, 0x0be4d469, + 0x3575b6bb, 0x07799382, 0x74ce082a, 0x1b9bc3b4, 0x3ae71166, 0x11484a28, 0xe380e788, 0x097b7e5a, 0x605053c1, + 0x732b9f60, 0x98cb906a, 0x6d238825, 0xd14cab58, 0x51546031, 0x031043b2, 0x02cf682d, 0x120b5615, 0x832a3c98, + 0x11d39417, 0xace010d9, 0x61cf17d4, 0x6e703632, 0x8757b270, 0x0885dd32, 0x09c30163, 0x18b636d5, 0xaaa4087e, + 0x69ceac91, 0x657d2f85, 0x11c4b82a, 0x085a034a, 0x8d2720c3, 0xe3c67cbc, 0x3504b6c0, 0xce7cd0bf, 0x600f1fb5, + 0xf3156cdc, 0x9534c0d4, 0x4699925c, 0xeaaa7c0f, 0x578a0ad6, 0xeecd9b5a, 0x75ee501f, 0xf71d8a6d, 0xaafe6b73, + 0x539a62ca, 0xa2a0b4f3, 0x4f83040e, 0x2720f225, 0x58d0d22e, 0x2dc457d5, 0xd353042d, 0xe2698244, 0x548adca3, + 0xafdebbe9, 0x858e56af, 0x5b4c1066, 0xeb0470d9, 0xe070baac, 0x012844ab, 0xb455f682, 0x21f454f9, 0xa63dc0d6, + 0x94dd5a6b, 0xdca97069, 0x4a5c935b, 0xdecda668, 0x27354cd3, 0x280d2786, 0x9db7495d, 0x103d8dd9, 0x1ed2e5f5, + 0xbaee5ea6, 0xcfa801ed, 0x42d6dc22, 0x1e6a7869, 0x55110cb9, 0x7a926869, 0x04c57a87, 0xc8e7a5dc, 0xd6bcf16b, + 0xbdcdbbcd, 0xdb5989d1, 0x0f3e8a42, 0x8ee5510d, 0x0824f6e3, 0xe1a84de0, 0x55834378, 0x6facc731, 0x64df2f7e, + 0x3b24396a, 0xe7fc64d7, 0x45823b0b, 0xd2d7b19f, 0x6f399830, 0x37c3d703, 0x30318bd6, 0x673c2cbb, 0x62dc52d8, + 0x832ad194, 0xfc7ed84f, 0xdb9c3097, 0x1107a321, 0x3812b1b2, 0x416ae765, 0xa793c399, 0x834854f2, 0xf1bfcd0a, + 0x9b830e29, 0xb73b9303, 0x17eba60c, 0x95170ebc, 0xf276cc91, 0x41991895, 0xeb0bc9b7, 0xa2e96e4c, 0x08e58c97, + 0xa0003a00, 0xe9888e83, 0xc041830e, 0x9bf5711c, 0x778e9a6b, 0xc59a14b8, 0x1ba8eaab, 0x7117e825, 0x5da5b44d, + 0x3fbd6d68, 0x01feda96, 0x82261153, 0x5bb0a9b2, 0x01248788, 0x6bf98cc7, 0x81dbccbb, 0xb632b3d4, 0x909861bb, + 0xdf77cd78, 0xffc9f1d4, 0x62223240, 0x8e8e2d00, 0x94268995, 0xecf91eef, 0xac3e2896, 0x9f9fd21d, 0xe1763ce6, + 0xdd80c0c7, 0xb51d0fbe, 0xf756ec81, 0x2f0b2660, 0x6ee32eb6, 0xa8d3b26f, 0x4adca931, 0x5ea9f0b1, 0x59cdfea4, + 0xa0437701, 0x9c791e7d, 0x71b72553, 0xfb4475b5, 0xb3afcd84, 0xbb86002d, 0xd0920e44, 0x78fcbb01, 0x7004bad8, + 0x06f3e0ce, 0x16216d97, 0x4d2aa87d, 0x134a3d74, 0x03e199e8, 0x5ab14f23, 0x1e493128, 0x917659ee, 0x105dc190, + 0x7a2c65e4, 0xdd287f2b, 0xc2c02019, 0x4fdff74d, 0x8ef0d0e9, 0x7e808a95, 0x2bad7d70, 0x99ad9bed, 0xcc2d83d2, + 0x937e0939, 0x908eb3f3, 0x8ada6423, 0xc55c8c3e, 0x6d38301b, 0xd71a4f5a, 0x2299b7a1, 0x57a5448f, 0xd74d2ced, + 0x1f31bf7b, 0x00125891, 0x76da6dbc, 0x76d96f31, 0x0d4d336e, 0x76ea460a, 0xd351e175, 0x76684cb7, 0x8c1b8a79, + 0x0e9e2a1f, 0x848f6541, 0x56241c05, 0x5aa14c9c, 0xf668b823, 0x60d2ee8d, 0x620d6140, 0xd4be0cbd, 0x4830f989, + 0xd81628af, 0x7868b184, 0x5dfa215e, 0x2a9f7123, 0x21f87202, 0xc673e55c, 0x3db239f0, 0x0bbd2dd7, 0x05e5e4ec, + 0x63d8d3a1, 0xb2527d37, 0xcfb8931e, 0x823770f0, 0x61e3c789, 0xcb664365, 0x0d7c16f5, 0xb3c0a786, 0x0ac53d83, + 0x865c827a, 0xd1837926, 0x340135ca, 0x41065146, 0xa41a40f0, 0x3ebb238f, 0x99875a7b, 0xe8a45c1f, 0xec2b47fe, + 0x35568548, 0x0dd61fa1, 0xa825c496, 0x883c637a, 0x2ff32790, 0x15f3f271, 0x368a7d89, 0xa13a89bc, 0x820dab5f, + 0xb5c41b08, 0xfe628c7a, 0x0458b3e4, 0xc43ff8a7, 0x2bee7777, 0xad5f6ba1, 0xcfb770ef, 0xb7d3ae02, 0x47394b49, + 0x734388b6, 0x168ccb0e, 0x2a9ae899, 0x4395c49c, 0x87fcf6d2, 0x6b7a9335, 0x687d57fb, 0x3b4c9dd8, 0xa6160c23, + 0x008e1010, 0x3dbacfc7, 0x6868d8e6, 0x9c870dd1, 0x391458de, 0xa7865b75, 0xde83c0f6, 0xad630a1b, 0x80b39e45, + 0x41e65267, 0xbc6b1a2e, 0x3505b24d, 0x7a3b25a7, 0x527819e4, 0x279e6b83, 0x0962ff4e, 0x729e1bd1, 0xa10dbb7f, + 0xc707f943, 0x3ec3251d, 0xd6450652, 0x515c6a65, 0xb3484898, 0x9d7e703c, 0xcdbcdb96, 0x90ea6a5d, 0x6aced511, + 0x74a3bea0, 0x2d9351af, 0xc9618c3e, 0xb5c1ab3a, 0x80eecaba, 0xb0ad97a6, 0xfae5d44e, 0x52a855bc, 0x63649010, + 0xc284bbb8, 0x8f88e8e2, 0xf6304825, 0x1a543b76, 0x6b324c4f, 0x9755f475, 0xc20ef24d, 0x16405e41, 0x5365d857, + 0xd094b2c4, 0xb44b4bcf, 0x05fec60a, 0x4a1bdf1a, 0x089cf700, 0x5de0c755, 0xf346b20f, 0x3f4c4a47, 0xb7c2eb92, + 0x33492e29, 0x197ccaf7, 0x6cd55cd8, 0x9997a8a9, 0x9fc2f067, 0xa703dad4, 0xef29f37c, 0xe0ef0de2, 0xd34502c1, + 0x1a4d69a3, 0x799e3bc6, 0x98b1d1e4, 0xc6f841ab, 0xc20de355, 0x6f19440a, 0xd7f036ee, 0x8772b72f, 0xb2895667, + 0x447b3fbd, 0x610c5fa9, 0x3dbffbe8, 0x100088e1, 0xe81725c2, 0x22155ffc, 0x4fa4e104, 0xb0e356a7, 0x3ab161ee, + 0xa457b83b, 0x495a1181, 0x31ba1f24, 0x53d43e2c, 0x6331249f, 0x64fad35e, 0x746737c6, 0xd4907ddc, 0xd1e45174, + 0x1de4acb7, 0x1a5b42f2, 0xb2146bb8, 0x78e6f0ce, 0xae667287, 0xefafbab5, 0x79bea0b4, 0xdff5f736, 0x7417c594, + 0x48c5a1f3, 0xc3c805ff, 0xc2b815a3, 0x7f8a6f5e, 0x48b9b49f, 0x7b344212, 0xa46ffa0a, 0xffe146f0, 0xdaea2a68, + 0x0a6c790c, 0xccfd2c15, 0xf985299a, 0xc0c85001, 0x78ba302a, 0xbe02518c, 0x1ce14e46, 0x5c7acbc7, 0xc3da8733, + 0xc513efe4, 0xf68fa687, 0xb7a2f57e, 0x41849553, 0xd4376f44, 0x2279c3e7, 0xe0f79feb, 0x9da322c0, 0x45b71e60, + 0x5c5b9a8e, 0x8d9360c3, 0x4e720932, 0x89f2e45f, 0x95ae86fb, 0x25815288, 0x94e5449c, 0xd6c02aeb, 0x8243a331, + 0xa7b94291, 0xaaf30351, 0x3acfcf1d, 0x421d3f72, 0x3b8fc9b5, 0xf6804af5, 0x4b248ab5, 0xc2c1fbcf, 0x3260e3c2, + 0xe838e11f, 0x9522a298, 0x113c9eb4, 0x87f639cb, 0x67c12148, 0xc26ae3a3, 0x6c36b6e2, 0x9d42ae1e, 0x617eaebc, + 0xc8b8c9b5, 0x93a911d7, 0xba2b9398, 0xfd771688, 0xe2249a49, 0x12fd8e82, 0x2c813a25, 0x73f4cd3c, 0x1d62a65a, + 0xcff04b37, 0x86cd68be, 0xb770e95f, 0x7f1a0290, 0x0c1a2998, 0x93152117, 0xa6f34e5e, 0x3c195525, 0x569a5b19, + 0x75a19cfd, 0xea3c8e50, 0xc34479ae, 0x581cd08a, 0xfbbd2963, 0xcbb9d208, 0x38eea4bf, 0x32087963, 0x790a5f23, + 0xad41cead, 0xa0e648ba, 0x83ce8d96, 0x5e5b16f7, 0xe33a1a12, 0xa5a21284, 0xaecd5a6b, 0xc70acdd9, 0xdb783550, + 0xcc581e18, 0x28657354, 0x05ed0280, 0x9ca0a6ec, 0x6be1e9b3, 0xa991e145, 0x9a7a69d5, 0x4db4a222, 0x43da12c3, + 0x40c84797, 0xf06ed290, 0x2565eccf, 0x6d518433, 0xfcc078f9, 0x7a0de495, 0x10dba621, 0x41f6a8c8, 0xfd1efb76, + 0x2add912e, 0x09ea4d34, 0x29aa5e66, 0x94b1421d, 0x25c13330, 0x7a15a7cd, 0x3b8cbe2f, 0x4474b833, 0x302b78cd, + 0x15c1773e, 0x6c3f3b3c, 0x83817313, 0x27ac7490, 0x5cb7e9f1, 0xbc62bf1b, 0x2ee52697, 0x01ef3dc4, 0xf5709596, + 0xc324ed63, 0x276f9d19, 0x4a2f1f7f, 0xbff0f96a, 0xc96e1f56, 0xe5253680, 0xa647e0e8, 0x5fec11cb, 0xbecee20c, + 0x6f6e0519, 0x14f1613d, 0xfb8b2a7d, 0x25909ae6, 0x476377f7, 0xdce07107, 0x665ae931, 0x33b4fdb2, 0xb9745aa1, + 0x3034c234, 0x29e90d9c, 0xa7ba3c3b, 0xb35f8cdf, 0xa23579db, 0x808f81a2, 0xb0d661a7, 0xeb41d55c, 0x2f831b18, + 0xe96cb7c5, 0xf0bf274b, 0x265d14b0, 0x3bdeba7f, 0xd3b1ca56, 0x786777af, 0xccd8bc8d, 0xb466d631, 0xa69fefe3, + 0x391f2de9, 0xf6ebef9e, 0x07578c18, 0xd3b90963, 0xfacc018c, 0xea457b74, 0xca387beb, 0xa2442f4b, 0x7cf15bcf, + 0xf945d42e, 0x295139cf, 0x4b33d0aa, 0x19fbf687, 0xa1ccb164, 0xa0ec04bf, 0xc3733b8c, 0x6cb6d240, 0x236eb6e8, + 0xcd88b49c, 0xc12c3a86, 0x9dd77692, 0x35e5a36c, 0x40b078c7, 0x1c6901df, 0x813a1bf9, 0xd5c83ab1, 0x04023071, + 0x28146fa8, 0x96f0af24, 0xb75a765c, 0x32010f09, 0x1b0f9c17, 0x9db63261, 0xc0d9f553, 0xb0a80171, 0x1c671544, + 0x4a5ac816, 0xc5f318f1, 0x21e8f074, 0x98df811f, 0xdccfbb85, 0xcdf044a6, 0x0b030aca, 0xfe72941c, 0x140ee45d, + 0x88d7cd91, 0xe380a7ca, 0xbc8cdac0, 0x6f640d5b, 0x46c2c2c0, 0xe3943b15, 0xec9827bb, 0xda86a246, 0xe73af85e, + 0x5f203d6f, 0xd5cf8243, 0xcc86fb6f, 0xcb56e44b, 0x83388dfa, 0xc494c249, 0x58310b28, 0x2f846812, 0x6ccb7c56, + 0xc629bcbe, 0x20f84600, 0x7dad0f1c, 0xc8afed95, 0x35015a5a, 0x74ffae4a, 0x0aef2b5c, 0x99de41b3, 0xb40ce21f, + 0x7bc733d4, 0xbae8c4c3, 0x9d65074a, 0xe72a2e0a, 0x8f2f9e3d, 0x1e341e0a, 0x368c1938, 0xb6bced4e, 0xeaaed852, + 0xc734997f, 0xf1956efd, 0x2b738555, 0xf23c79fb, 0xca63953f, 0x1acd56db, 0xb2a565ec, 0x016e67a1, 0xadecc046, + 0x408f5b57, 0x77a2f1cf, 0x10fc6e9e, 0xbde46b03, 0x98f561c6, 0x4b6b702c, 0x733b2b20, 0xa08c82f8, 0xb20b8af6, + 0x70d06f20, 0x92b73f5f, 0xd300b6d3, 0xbcc75242, 0x1f41ba2e, 0xaaf505de, 0x4d9d2cb1, 0x8f195258, 0x59c9459f, + 0x22838a42, 0x3500db18, 0x213a1a44, 0x4211eaf1, 0xf7dbfdc9, 0xd4f771ec, 0xeef2ff77, 0xd05e5e37, 0x05d7cd01, + 0x068ac624, 0xe1dbbd9b, 0x9525739d, 0xbaaa2ff7, 0x184c24f4, 0xeffa9f52, 0x007b51b3, 0xcd1db7eb, 0xb2d908f1, + 0xe66a5ddd, 0x308dca6b, 0xa70d44af, 0x0f0b05c6, 0xe2d91ab0, 0x6b8be452, 0x85774f6a, 0x39aad890, 0xc32de4ee, + 0x469d7140, 0xb57e9aaf, 0x2eaaab79, 0xecfcf492, 0x22e619eb, 0xfe026c64, 0x411ecedf, 0x7994b478, 0x4f2487dd, + 0x095a64c5, 0xa2b24e93, 0xe45fc771, 0x5ee62f1f, 0xab588152, 0x6b10140b, 0x5ee2b3c8, 0xb929d84f, 0x08219866, + 0xbf5468c9, 0xe171e76f, 0x65a9cecc, 0xf350ad65, 0x47c03fb5, 0x8f0d797f, 0xf6647b85, 0x44708908, 0xca620b3e, + 0xeaa05d5b, 0x0b4e0d65, 0xe24beea8, 0xe9c88044, 0x60d99023, 0x66bbb4fc, 0x181c1a3c, 0x2979f2dc, 0xc05b5e9a, + 0x6706459a, 0x43899efb, 0x71418377, 0x85c58dbb, 0x2b5fa9fc, 0xb2947da6, 0x1ce33f6c, 0x0987895a, 0x39c2cd13, + 0xcf97687d, 0xb045021b, 0x26095b4a, 0x80b2b5c9, 0xec3da70e, 0x8ffaadf4, 0x8cae623e, 0x9eec7f26, 0x0824e52c, + 0xbbeb2940, 0x69fa500f, 0x7b79caa0, 0x2f1e080b, 0x28d9ce82, 0x22814f5d, 0x82ad63ab, 0xd1c877eb, 0x0075b509, + 0xc7cc439b, 0x2d794cef, 0xa4160fc3, 0xe197f8c2, 0x7f633324, 0xc12a986e, 0x7d8e6993, 0x30b5b798, 0xec46e641, + 0x969db406, 0xe0f6286b, 0x75accafd, 0xcec138bc, 0x3bb7091d, 0x34b09c8f, 0x52aadd53, 0x1812f8b6, 0xddd51a7b, + 0xaf83d6e0, 0x78ac2ae6, 0x06a8b659, 0xd022fb1f, 0x0d9278dd, 0xe2b8d933, 0x3cc12d0b, 0xf611dccd, 0x3ef2724c, + 0xc407870f, 0xc5378fcc, 0x767800c2, 0xb7ee0042, 0x739cf60e, 0xb572ac68, 0x7ea73b31, 0x51511944, 0x776c7503, + 0xcf4a6579, 0x18906595, 0x4d334d77, 0x8383685a, 0x928d9993, 0xae7c1740, 0xac5681c7, 0x5a67b5b4, 0x54923dbb, + 0x814610d5, 0x26e27d3d, 0xb5cfc300, 0xb4ae2afa, 0x9f49f73e, 0xb62acf57, 0xb15dba5e, 0x7e57a0cf, 0x26b04bba, + 0xbd457896, 0xb915a1fe, 0x5b99d643, 0x51ad24a4, 0xec05c19a, 0xf5d276a0, 0x20031062, 0x84768ad4, 0xfdb03e59, + 0x21745a60, 0x6b509a25, 0x023aafe8, 0xe1ad4483, 0x9b15c9d5, 0xe4db160c, 0x2e98dc51, 0x690f779b, 0xfe71fa61, + 0xfd81dac1, 0xac3a19bb, 0xd098064c, 0x773566e3, 0x6177b492, 0x69fabd72, 0xaa08af29, 0x7b96f9e2, 0x626e6be0, + 0xd344f542, 0x2db71e30, 0xc33bc4cc, 0xa8fa17f8, 0x5856850c, 0x0adbf582, 0x5120ce04, 0x999d133d, 0x0430e3c7, + 0x9b4eaa8b, 0x28db6c68, 0x17f9a07d, 0xa6b45277, 0xabe0b24a, 0xb87dec8d, 0x023c67b9, 0x9ad58211, 0xe7604d61, + 0xbe637fe2, 0xdf83eeb2, 0x45d38cf0, 0xd23caf5c, 0x8f692541, 0xe624370a, 0x8edb6937, 0x5a97c221, 0x1269ed99, + 0x47d6db6f, 0x7a6824d2, 0xd960d304, 0x354078c8, 0x8a2a0dc4, 0xe30a9342, 0x8507547e, 0xfc985b11, 0x7a515215, + 0x634d6e60, 0x267b6999, 0xc79dc786, 0xb17159b1, 0xf625719e, 0x383c54ee, 0xbc95e1b5, 0xf73da24d, 0x600daccd, + 0x425ebab3, 0xc88542a1, 0xf4d7452c, 0x65fb78f5, 0x3a553d73, 0x65f2e751, 0xda710681, 0x93a39322, 0xf03687f1, + 0xc92b7882, 0xa12fa024, 0xfd2c0f16, 0x76498519, 0xb2e03b69, 0x2b887cab, 0xa869e58c, 0xb6afdae0, 0xfdf2df26, + 0x02c00a1b, 0x7cf2d7f7, 0xe7a5d5f9, 0x53d1a374, 0xa217f175, 0xab0bf408, 0x33601237, 0xef0572b0, 0x9ad24cb4, + 0xa8d2aac1, 0xd0609c5c, 0x0a942d58, 0x41c03762, 0x714a6195, 0x652120b0, 0x481e6bca, 0x45dbc3f3, 0xcef88643, + 0x7ff77e5b, 0x5a339db4, 0x19cfba07, 0xbe9f20e6, 0x452f0670, 0xe36697db, 0x83826530, 0x4a191c11, 0x2bfc21ed, + 0x847e9617, 0x09560d9b, 0xe1840266, 0xe7b12529, 0x8c6ff726, 0xf255da5a, 0xb77edf5b, 0x079ea4d2, 0xf33bd7b4, + 0x6d029bfc, 0x8e4ae1c0, 0xd0e8c574, 0xd907e908, 0x6ed8e7de, 0x2145cfe2, 0x0ec2d9f8, 0x97057a39, 0x94216f6d, + 0xc45732b4, 0x685eb48e, 0x6993eb36, 0x62801b61, 0x0c7ed481, 0x3fac7b8c, 0x24a75134, 0x141860b9, 0x155296c5, + 0x367cccca, 0x69c425af, 0xb34c3c11, 0xe50a0d47, 0x7fb02351, 0x95bfe4df, 0xdad98e4a, 0x7785c7db, 0xcb4cf6e7, + 0xbbc81fd4, 0x3667271a, 0xfc957866, 0xa8218966, 0x981d9fa4, 0x022e8427, 0xf543f674, 0x016b95f7, 0x32b4b944, + 0xe58be65a, 0x7aab4a25, 0x661d5fcd, 0xca677d5e, 0xb469037a, 0xb2759ad4, 0x61c7fe51, 0x9540f530, 0x2e5e8572, + 0x389ba337, 0x8b11a849, 0xa4c71f34, 0xcdc82411, 0x242cee43, 0xa5d5953d, 0xef3e0ac5, 0x2dd8ccb8, 0x9885f821, + 0x6a89f5cd, 0x25f3b0b5, 0x496d9fa9, 0x36155a84, 0xfc4ca83e, 0x7df82534, 0x88d3549f, 0x405e9ebd, 0x66c6b2f8, + 0xfe53f3e4, 0x90a73118, 0x698449c4, 0x78696912, 0xf2ce3b51, 0x3efe1a27, 0x1772e0c7, 0x44d45973, 0xd8bdca35, + 0x4df0efe4, 0x519279e5, 0xf41261a1, 0xdf0ff8ae, 0xca2e5498, 0x91f78e65, 0x6e59a279, 0x9be007ed, 0x414b6d64, + 0xb4e69440, 0x3d919823, 0xdf7b0d1d, 0x4d4867fa, 0x570d87c1, 0x24cb5450, 0xebe5ba5e, 0x327b5183, 0xcae657ea, + 0x971d48ae, 0x259d94dd, 0x84e6c431, 0x5a3b6f26, 0x8de38fce, 0xd26328d7, 0x8850f923, 0x07bda69a, 0xbdbb2042, + 0x4b65f4ec, 0xfcae94ef, 0x0db0c422, 0xb5f40332, 0x43228bfc, 0x3a56507b, 0x1c600955, 0x43a8d7d6, 0xc510f7ec, + 0xedc40e5a, 0xe725c5e0, 0xb33a3ec3, 0x2174ddc1, 0xb3ff0880, 0xf4b2d864, 0x008dc7c8, 0x35235b81, 0x038d7ce4, + 0x4a146961, 0x94e46d99, 0x13d715be, 0xf0f9968a, 0x3bf05371, 0xe48ffd28, 0x2ac826e4, 0x271fda36, 0x7b92d13c, + 0xa609bd0c, 0xca995a8c, 0x9da05cfa, 0xf638b74e, 0x996cc4d5, 0xfc5040d2, 0x70695495, 0x64a85410, 0xce70d5be, + 0x9e657948, 0x17208ab0, 0x46c744dd, 0xd334984e, 0xa456a115, 0xf276f6a6, 0xdf4a8ce3, 0x682e633d, 0x460c5506, + 0x446f2be8, 0xdccafb96, 0x1a98114b, 0xf6f2db08, 0x0dc50e4e, 0xa2a33fab, 0xa119f496, 0x8c2c451e, 0x9a3b81a1, + 0x7a3aada8, 0xe5a5522f, 0xa386d461, 0x4212f5e5, 0xdc53995d, 0x473dc18c, 0x60852d7e, 0xa73869a3, 0x2a36e3db, + 0x065d36c5, 0x0a592356, 0xc9da94c8, 0x02a9455b, 0xe21033d0, 0x7a6cc060, 0xe1c06834, 0x93bb0020, 0x162362f1, + 0xadd7216c, 0xc86e8b7f, 0x1bdda0f6, 0xef5c13f2, 0x22aa1d7b, 0x124f64da, 0xe4d7c4e6, 0xb8f80ef6, 0xbfc7ed55, + 0xcc13f074, 0xa321556f, 0x634119cb, 0xedbdc0f4, 0x3968161d, 0x95f4aa39, 0xcae2efb1, 0xee1f5929, 0x5138694f, + 0xbba9e675, 0x87e3de6a, 0x65261c4c, 0x2ccb44f4, 0xe44b528a, 0x391b9f03, 0xa9fc31c0, 0x1bb29492, 0xd23bc040, + 0xe746945e, 0xf6a99546, 0xb8383ddd, 0xc21e0881, 0x570d755c, 0xec1bbd09, 0x042a50e6, 0x28ef826d, 0x97d894b0, + 0x3386e569, 0x3c450da4, 0x3172646a, 0x335ff57b, 0x1927187d, 0xab6b2df6, 0x77faf274, 0xc363af12, 0xb0b1e001, + 0x3880ac0e, 0x624a5a16, 0x46c0bbf7, 0xff190144, 0x386b438a, 0xb6331d88, 0x05a5f224, 0x4d2b8736, 0x2e088e5b, + 0xdfacfb88, 0xb7748211, 0xdba9d298, 0x3de41829, 0x3af6898c, 0xfb3533bd, 0xf6a531cf, 0x01b75ea7, 0xfe26da4f, + 0x27a09fd0, 0xe59a5617, 0x686d1837, 0x03e3e6be, 0xff029b08, 0xc7082251, 0x8d17a76a, 0x299ff213, 0x719ae509, + 0x3cd2fc61, 0x39b41d77, 0x367756f7, 0xa307f0f2, 0xa1c1c50c, 0x0498fcc7, 0x708ec456, 0xa253ada9, 0xbf09d3a4, + 0x4780abf9, 0x795e41fe, 0x25a1804b, 0xeb0feb01, 0x49cad2c5, 0x82e5b536, 0x480269d5, 0x25913027, 0x4f469be7, + 0xd7de1fc5, 0xaf795d47, 0xb9d280f8, 0x812a179c, 0xc85f5a90, 0x7d4c162d, 0x1c40cecd, 0x61e2e2c5, 0xc4b0a6a6, + 0x548cc5b0, 0x0e033423, 0xa551704b, 0x24e35e9a, 0xcaa09392, 0x9e72a64c, 0x2fa4bb60, 0x2e5d29c7, 0x454fa961, + 0x10f8ac8c, 0xe3fe42f4, 0xc39c16b7, 0xf0d9aab8, 0xfb114bf8, 0x117beca1, 0x39be9a5b, 0x3288ea27, 0x5bd40aad, + 0x79dbe041, 0x32e83ecd, 0xde735be0, 0x63c22871, 0x7e680f35, 0xf8c408d1, 0x18e708d5, 0x263ad56c, 0x2d13d770, + 0xaf52d801, 0xc264520f, 0x864f665d, 0x3a8df7f0, 0x65d5fd5c, 0x5034ccf9, 0x8121a50d, 0x2eb0db16, 0x6aea595d, + 0xe8a9ee8a, 0xbad9cea8, 0x7f1af5cd, 0xd6281722, 0xb77bd023, 0x10703a94, 0x7a0275ad, 0x9b3f6c73, 0xe6251b6d, + 0x62301bfa, 0x92660405, 0xdf4930e5, 0x35cc5860, 0x70c4fa1d, 0x7bd89cca, 0xe041abbe, 0xbc6e2e79, 0x237fca8e, + 0xbc6bdff7, 0xed7ac0f7, 0x2edfd82e, 0x8fced2fd, 0x48204c7a, 0xcecfb848, 0x51b7ab8e, 0x63352171, 0x10058ac4, + 0x6c391916, 0x83c251da, 0x2bea0071, 0xdf6e0636, 0xc2ba004b, 0x86cf0309, 0x92455362, 0xe2a59c29, 0x533fab8a, + 0xd866b802, 0xa7371e2b, 0x62ca1a0b, 0x4269b6a3, 0x8a5de3e2, 0xc0d9a783, 0xed5f93c6, 0x2e3c400c, 0x18ce694c, + 0xed3ed196, 0x143ab102, 0x77b10b74, 0xa49a454f, 0x53410141, 0xedbd2f31, 0x0f07aac9, 0xe5ee4aea, 0x7fa54306, + 0xdc64c7a2, 0xc8a41588, 0x5d9b2f9f, 0x29a06539, 0xf2e0a3c1, 0x09e90a78, 0xd8a5f060, 0x22952a67, 0x7836de35, + 0x3cd3aa6f, 0xc9cde45a, 0xdf1c284b, 0x2ac58128, 0x151137e0, 0x27b6a08d, 0x667fd94b, 0x093da9ab, 0x26b225c0, + 0xb6267063, 0xb77f9a12, 0xcdf1a0bb, 0xb3811453, 0xfbd3abdf, 0x3ec4a763, 0xeb72a99a, 0x39d12ae2, 0xab51ecea, + 0x63975043, 0x9a604b7d, 0xa130a5b0, 0x7af1f6d3, 0x60c0f8b3, 0xbc0e8afe, 0xa3d8822d, 0x167ccb6f, 0x3a88d09f, + 0xe252c49e, 0x3ba7a93d, 0x29251cdd, 0xbe971ed4, 0x470c39d2, 0x965aed9b, 0x2e4f9b08, 0x757f96be, 0x67aa2920, + 0x9c3d6302, 0x5c7f70c2, 0x0448d601, 0x2c76ef4c, 0x7bfc5a2f, 0x3138aafe, 0x4d40fe0d, 0x62a208c0, 0x29995325, + 0xdc6f025f, 0xdb5aea4f, 0xfdb7d44c, 0x85bf8f91, 0xbfc6daf7, 0x3b37e466, 0xc544a58c, 0x59e53a18, 0x2831512c, + 0x61a50f9c, 0x607bca41, 0x0b64935c, 0x056a286f, 0xd7670066, 0xd140d7db, 0x0056b05e, 0x866313bb, 0x06675749, + 0x2b9bb128, 0x6e508f21, 0xef8ca992, 0x5023f885, 0xeffe3568, 0x0d58ce9f, 0xa21bf54c, 0x3c163dd8, 0x617e9d65, + 0x5206afea, 0xe7d31663, 0xecd73b10, 0x152890b6, 0xe6f113af, 0x58759fbf, 0x9aa614ad, 0x2ef46a45, 0x0f73b861, + 0x94082c7e, 0x25ee0f7e, 0xeea1413f, 0xd2c4e66c, 0x15ad928c, 0x8485d9b6, 0x68679baf, 0x6b2cb3da, 0x84f47c18, + 0x28dc9b74, 0x6a9b19ae, 0x9116d734, 0x88a51c0c, 0x53f93764, 0xc4fa3ddc, 0x2c4fcd1c, 0x5c774d10, 0xf1646045, + 0x5ef56835, 0x36fbad22, 0xc80035db, 0xb25667f1, 0x9bc30de3, 0x89363a39, 0x0f210afb, 0x2514e89e, 0x882a3af3, + 0xc35ff994, 0xf4318d16, 0x03dc0db3, 0xceec1f50, 0xa1054b38, 0x30c5672b, 0x3b162c0d, 0xe89601bd, 0x41868fb4, + 0x919146f5, 0x2ab006f8, 0xbe778d77, 0xacc4ce63, 0x33f1e239, 0xc5a4e645, 0x85e3a3b4, 0xe5d99da8, 0x08e1bdb4, + 0x3bab980e, 0x6db5848d, 0xaff4b0f8, 0xee96b9ed, 0x017944f3, 0xd9a906fc, 0x45a7fac7, 0xb33293f8, 0xe696e92a, + 0xe187175c, 0x080d6ff6, 0x2f0b845c, 0xbfe2d2a9, 0x49f1bd6c, 0x978854e3, 0x1d37496a, 0xf3e8c6f5, 0x6e3ffa85, + 0xff309f55, 0xfea044e3, 0x6518bc1a, 0x00eff7ea, 0xdcde9408, 0x935cae16, 0xc5b914d6, 0x4515ee14, 0xff9943f6, + 0x41d9a962, 0x7f46c235, 0xd9ff6816, 0x6673977b, 0xfc7601e9, 0x39118fda, 0xe49b7b1e, 0x350b1ff9, 0xcb7cac21, + 0x83a8e015, 0xa381bdbc, 0x58755989, 0x97c44f8c, 0xd8b9dcbd, 0xd91c2cfd, 0xf6306cb9, 0xa0b675cf, 0xf0f031a2, + 0xd0ccccb0, 0x99ff4acf, 0x67d38342, 0xa4be4ff0, 0x12861fb8, 0xd09aa704, 0x886a2ec0, 0x58658f18, 0xc85b03e1, + 0xa8f0796e, 0xdc89e093, 0xf8fdda6f, 0xf75c9ed8, 0x4aa69273, 0x57171a76, 0x20beea91, 0x302986f8, 0x94c1acd1, + 0xa427c6bc, 0x6d49983c, 0xab0db9a1, 0x2ed08824, 0xfc604b66, 0xe0ec9d51, 0x19960dde, 0x802d8d1f, 0xab6c8c0b, + 0x73565c13, 0x6b22ed18, 0x4e861a9b, 0xcebb191d, 0x1ceb18b0, 0x89fa516e, 0x7d9ee51f, 0x021aa0ed, 0xe8b6bb81, + 0xc618b8fb, 0xc1a50bea, 0x268027b8, 0xf25eee44, 0xc5ddf85f, 0x895f5053, 0x0c7b2826, 0x9d215932, 0x58b21cf9, + 0x97f4db26, 0xf9ad71d2, 0xdaccb207, 0x9933b150, 0x4b0723d6, 0x830a8c41, 0xd9711372, 0x0cebd34f, 0x67b8a6e5, + 0xa96e7a7e, 0x55ba4c99, 0x85def452, 0x9aadf8a0, 0xbcab9744, 0x70e985f1, 0x6738cf24, 0xa6dcd647, 0xa5c7de6c, + 0x27349b69, 0xbb142887, 0xbe6ed649, 0x40a1d404, 0x2277b0c3, 0x24e4def9, 0x9fc0bdbb, 0xf3410533, 0x5f4593d3, + 0xa83713c9, 0xf3e2bc74, 0x44f4ed23, 0x3d03d805, 0xc46ecac8, 0xbdfc0be1, 0xa95236c2, 0x7a4df22e, 0xeca52414, + 0x0c21adcf, 0xbb1882d4, 0x9e789569, 0x4c36b656, 0x5644312e, 0xcccff992, 0xbc215c9f, 0xa6c15c5e, 0xf51988f7, + 0x2d494725, 0x67aded6a, 0x4be64aba, 0x2a4f9cf9, 0xaaf12e70, 0xa3ae068e, 0x747ee554, 0xbd46cff2, 0xdcbeeddc, + 0x4dd9d5eb, 0xba27e5f5, 0x6c9769c9, 0xce18c0f9, 0xdef590af, 0x201cf411, 0xd6bf38cf, 0x4c8cbdf5, 0x7abb952f, + 0xa85f506a, 0x1b000ee1, 0x1430e6f2, 0xe17ef12c, 0x1b75b997, 0x3dfbef49, 0xf4529c43, 0x3290ffa5, 0xd2a7ebd4, + 0x63b577c2, 0xe6aa3daf, 0x17accbaf, 0xd2cd870b, 0x83b7c6c0, 0x82290cc0, 0xf99d0591, 0xcf5bdbe5, 0x64c64e55, + 0x67a57edd, 0xb6114281, 0x3caafd37, 0x6b6c7fc3, 0x1802cb99, 0xafa5d9b4, 0x294060b4, 0x53b9c424, 0x2e08ce43, + 0xf251ea19, 0xd972423d, 0xe32f8571, 0x782cbef4, 0x5a09c250, 0xd1f3954c, 0xd55ebd2b, 0x6d0eb5fa, 0x425de7e5, + 0x6c24616b, 0x14799cf3, 0x52e82f43, 0x161a46c4, 0x22412171, 0x0e5d7aac, 0x24bcde63, 0xf57df04d, 0xe8108833, + 0xe29f8d99, 0xdfd7ecc4, 0x27201a51, 0x0327e067, 0xf4028086, 0x09a75c2b, 0x5242f961, 0xde678568, 0xe3c2211e, + 0x98d2999a, 0xbafffe4d, 0x9344dc0d, 0x85457aba, 0xb2460a01, 0x5c4f13f9, 0xe8525c42, 0xba55a9a9, 0x055f9ea5, + 0xcd86712d, 0x8c02d509, 0x03fd645b, 0x5104056e, 0xf584520b, 0xb16f7b6a, 0xc1ce9606, 0x63a56842, 0x1d847196, + 0x3f825d80, 0x6274a8df, 0x7f70ad6e, 0xbcfaf9f2, 0x5ed303bf, 0xad9fa281, 0xd7eb5333, 0xb0e35aff, 0x82f4f0ea, + 0x9dd12cb1, 0xb679289a, 0x75b69aa6, 0x548618ed, 0x1b73f929, 0xb41b0b15, 0x35512964, 0x3b0b4a77, 0x7753afea, + 0x078d7fbc, 0x4347843c, 0xfd9e7bde, 0x4e52f4d8, 0xd5a05c3a, 0x9b0ead04, 0x1c441252, 0xcd033fd9, 0xb3cafafd, + 0x8f25cf3d, 0x363b5077, 0xf03c5c91, 0x1215deef, 0xd07f0ed5, 0x93267148, 0x68d210dc, 0xf75f8573, 0x9b57012f, + 0x2938bf67, 0xd460a455, 0x6b233c43, 0x0cd41cf1, 0xa80e3b3c, 0x7f565a4d, 0xc1b37a22, 0x9e4b75dc, 0x71a94067, + 0xc3e440ca, 0xed40a1df, 0x1a08ef6a, 0xa0a43acc, 0x22a91f03, 0x9c7a350f, 0x4440f63a, 0x28bec0b1, 0x3feaa14d, + 0x41f77181, 0xe0795c6f, 0x9d41e159, 0xaab61b5b, 0xf03e0fad, 0x81792872, 0xe2e630d1, 0x9bc550d6, 0xd4dd433e, + 0x548551e6, 0xfb61b685, 0xf44a1ccd, 0x960894c0, 0x0a8cf350, 0x3f117e41, 0xb2580a11, 0x49995090, 0x3c27a976, + 0xee9479e9, 0xd391d4d7, 0x36a04fd9, 0xc5a626fd, 0x23c1d7d4, 0xf61ab6fc, 0xa2237ee7, 0x83fca279, 0x22052751, + 0x137cbd63, 0x58af7dcf, 0x9eacfb28, 0x8e888149, 0x4c85ac83, 0x8aa07060, 0xc5eb3fb6, 0xcb4fedf4, 0xcd2abe06, + 0xf84a2276, 0x4d14e518, 0x82fc3668, 0x97d162ee, 0x569c16f0, 0x8432b20b, 0xf3214c82, 0x85b60c64, 0xec9d2014, + 0x7045c658, 0x24b01bba, 0x63511659, 0xc3680d80, 0xf53f5008, 0x93960421, 0x2ffd5a76, 0xae17a483, 0x47a4c08d, + 0xc47d7881, 0xff4f458b, 0x72a52a88, 0xa8127678, 0x2b513214, 0x166565bb, 0xe90ac865, 0x297fd584, 0xbd865ed1, + 0xf9e17f42, 0xc58e42f6, 0xd200c4f7, 0xcfab7543, 0x07b63cf0, 0x573e6530, 0x204001ab, 0xae6e1b8d, 0x187fabe7, + 0x03d2419c, 0x74d735a5, 0x00d51fb2, 0x9a6fb5bf, 0x4b47e75e, 0xd32e265d, 0x54cfc193, 0x0c740464, 0xfe631255, + 0x635b9edf, 0xd9e9e6b2, 0x7a9b799c, 0x9f588c7b, 0x1803c455, 0x663eda6e, 0xa141ea8f, 0xee30e03b, 0x513c1de2, + 0x9dd90702, 0x8ad22b49, 0xbea891f5, 0xba9c9946, 0x85cc42e7, 0x78eb8e0a, 0xb02869b5, 0xfb718c6a, 0xeda477b8, + 0xf0f29dfb, 0x860455db, 0x10970832, 0xa26304d1, 0x1e0f5ffe, 0x71ec2025, 0xf51e14e2, 0x99662f74, 0x6990f669, + 0xf8df6082, 0xa539b639, 0xbd029d49, 0xa30327b0, 0x8239e7ef, 0x656af70f, 0x8c24df7c, 0x12bc8516, 0x000b4afa, + 0x55a7f3f9, 0x866db05f, 0x7613486d, 0x328bfb3a, 0xed5b1321, 0xd443715a, 0x2b12cc4c, 0x40e986d5, 0xffd6a9bc, + 0xaea283df, 0x4088768d, 0x7f64e4b9, 0xa57088c3, 0x3fa53c0e, 0x631fb765, 0xd6e60373, 0x17596fbb, 0xd65e50d4, + 0xe317b623, 0x12e3b65e, 0x73629c01, 0x3024ed99, 0x48e1d04b, 0x7ccbb1c8, 0xd8fd9899, 0x762f2f44, 0xdcf21401, + 0xd8e5deb7, 0x82076953, 0x610a2882, 0x16d778e0, 0x933e0471, 0x40a6ca6f, 0xd6e9718e, 0x41459249, 0x1dcf6d24, + 0x2de5d505, 0x2c9ef261, 0xfbd5fdd2, 0xf7c21e23, 0xda6246e6, 0xb4ddd1c0, 0x2a31f785, 0x53c41a95, 0x3678c472, + 0x7da10184, 0x66cf1e0c, 0xa130ca55, 0x08c53ca2, 0x86e5e5ec, 0x095236b6, 0xd0a91135, 0x9b5147dd, 0x59447f18, + 0xdc384f69, 0x482983f4, 0x96d00a2d, 0xe869db06, 0x2959ead1, 0x18886097, 0x89bd0de7, 0x3b57f4a8, 0x0c25706a, + 0x6c4577a8, 0xbadabcc7, 0x1e098d63, 0x39d6e14d, 0xef5b3e4d, 0x7bebf89c, 0x43b7390e, 0x3c1e0d41, 0xd45aaaac, + 0xe21f5b89, 0xb8adebf8, 0xad0b2b1c, 0x1b054cbe, 0xfc90c9cc, 0x5b47f245, 0xc0a1f3a3, 0xbc0357ac, 0x67ffbeb3, + 0x1290942f, 0xab656355, 0x6b23ae3e, 0x128ca769, 0x31b7c8fb, 0xb9a36de0, 0x4d6c41f8, 0x969602a4, 0x0efed082, + 0xf622cf71, 0xa8b9bbf6, 0xb0f911c3, 0xe7868d10, 0x3ae9bd9c, 0x7b3f2361, 0x5bb3dea1, 0xe8b8bef7, 0x914ed786, + 0xc48e190a, 0x7457fc9a, 0xb243f602, 0x447a1365, 0x8ba80e05, 0xd3c81a27, 0x56948191, 0x3ef73ea0, 0xfeb6b21b, + 0x2adb781b, 0x02e85319, 0xb7911d74, 0x955f61a0, 0xbceafdf0, 0x99df973d, 0x545b7337, 0x5478a8b2, 0x8c5b2e6d, + 0x182bec03, 0x98a7a851, 0xe3c7c308, 0x1d6220f0, 0x8ae589c3, 0xaba2649b, 0x7f251875, 0xd4f29bd6, 0xe38a5a19, + 0x01b9c934, 0x9eb983e5, 0x48f9cdb3, 0x3a0a88d0, 0xbe87e3f4, 0x0d5016a8, 0x8e936845, 0x4d651e79, 0x32539d0e, + 0xd8b1f434, 0xdf4731f3, 0x3fb3c620, 0x8c96cd82, 0x2416767e, 0xcb4b0121, 0xdebb620c, 0xaed7f399, 0x1d4c94ed, + 0xf55f3600, 0x00f57109, 0x8e51bc5a, 0x2b883060, 0x3f275449, 0xd748b6ab, 0x1555ce2b, 0x6a039f96, 0xeb400d98, + 0xd052ad23, 0xa65392a1, 0x2cf90247, 0xce3cc760, 0x2c8d56f6, 0x1167ec17, 0x8646e82d, 0x11200443, 0xfb8da0b7, + 0x285ae18a, 0x67934ac8, 0xb7766f15, 0x9de0f371, 0x33a4711d, 0x943e71f0, 0xaffbf9f2, 0x4d0e48d8, 0x0e26eac4, + 0xd2acac37, 0xfe344bff, 0x3df96765, 0x13f07062, 0x957ddc44, 0x8b6a9d7e, 0x537047cb, 0x36f11bbe, 0x764eb43e, + 0x32830bb2, 0x47247cb4, 0xa96d3292, 0xc5314ff6, 0x6864c3ce, 0xee334b87, 0x144aa64b, 0xaacc1781, 0x344cbb4e, + 0x22cfdf71, 0x059efc6b, 0x4debf945, 0xa1028dde, 0x7fc78b83, 0x721511c3, 0xbc5ea26a, 0x102faff2, 0xbddd2563, + 0x9b7075d8, 0x57e0e748, 0xf29231ef, 0xb21b4526, 0x48054f7d, 0xe7bbc9f2, 0x2b8dde93, 0x218c1594, 0xca5d14f8, + 0x5bac51c3, 0x60558d84, 0xce4e5825, 0x36ff2a71, 0xad9c3eec, 0xc6974938, 0x50ac65e0, 0x0b0b875f, 0x77df1590, + 0x02ccc701, 0xbe750233, 0x3805f7c6, 0x58be4d40, 0xc8d2c923, 0xf98d9f6c, 0x50a90d2b, 0x5390848a, 0xe561e11a, + 0x50e3e0ac, 0x7533a212, 0xa8e07304, 0xecfd1935, 0xa2c1c4c9, 0xec611f0f, 0x4916c3ca, 0xa5730cd9, 0x8665944c, + 0x398755c5, 0x869a1ed4, 0x5f5d400f, 0x16a528b1, 0x734c3135, 0xc224cef2, 0xd9df7518, 0xc8b89200, 0xd759b56b, + 0x69f8d5ff, 0x0e54c089, 0xa8f4ef1a, 0xae92cd27, 0xed12141d, 0x62cef6b5, 0x30003201, 0xe8f77b71, 0x60ba2f22, + 0xec6bc582, 0xb874d652, 0x218ac05c, 0x3ce3b38e, 0x42c5f75c, 0x4b33cfd1, 0x04a0b9cb, 0xdf260aa6, 0xc69df6f3, + 0x5d840f15, 0x7db0de56, 0x46ccb900, 0x37ee22a2, 0x4b728a71, 0x66083462, 0xcd51d095, 0x4bab9081, 0x7d83f9fa, + 0x838e95dd, 0x0abcb020, 0x0c87f537, 0x1d08a731, 0xebe9f4b9, 0xfadfea67, 0xb0e1d9cf, 0xf8589a9c, 0x9a314ae1, + 0x95ee3778, 0x644d81b0, 0xb2fbd75d, 0xc2f4ac71, 0x960eb0da, 0x3b1a46bd, 0xd9d11c29, 0x4a465099, 0x89c4a5e9, + 0xea8672a5, 0x92c93a72, 0xee2095bf, 0xf5cd77f5, 0x3ffea103, 0x14847da8, 0xb2540be2, 0x288815a0, 0x7d2ca240, + 0x9aaedfe6, 0xa884093e, 0x6b47c5d4, 0x9a6d02dc, 0x4437a9e7, 0x11933792, 0x4cff2e61, 0x6980e7de, 0x570c2ddf, + 0x9b1a461b, 0x16be727a, 0x809e6c91, 0x3c1fc47a, 0x77e076b6, 0x8e8eeaa2, 0xc50d5167, 0x1d94c939, 0x2e6e61fc, + 0x6bc9c2bd, 0xb55c9354, 0xcec95b8f, 0x341c2793, 0xec7476f2, 0x3cf737fe, 0x703d2e4c, 0x438ec95d, 0xabb3e324, + 0xa5e0dc98, 0x838f7f21, 0x5fc9f926, 0xf4af9f78, 0x63ffb1e2, 0xe5d31b4c, 0x18665dd0, 0xd8976b1d, 0x67eb4a1a, + 0x673b7967, 0xbc10392b, 0xc074a271, 0xb9717512, 0x54eb261d, 0x064d041f, 0xf20a10cb, 0xcdeced1c, 0x4615410c, + 0xf4657b5d, 0xd5e9a0a4, 0x8ad512b6, 0xcc2bee94, 0x3604c539, 0x0365a303, 0xae6d34b9, 0xaf22d71d, 0x5c85929b, + 0xd1df614e, 0x8faa95cf, 0x81cc775f, 0xa2bb1aea, 0x26796997, 0x4eb858d9, 0x6988ad21, 0x8fb7bc02, 0xfa6b84db, + 0xa322d983, 0xb495d425, 0x1be88f1a, 0x3ba8ae2c, 0xe7ea2881, 0xb5224a8d, 0x4ff66520, 0x56c5735e, 0xc313d53b, + 0xfca44092, 0x80bc2b51, 0x6c413517, 0x6e5db705, 0xbb460c47, 0x6bf9108f, 0xadc81c5b, 0xbea25ca6, 0x52ae98bb, + 0x3608b673, 0x815ecc25, 0xa81c7e08, 0x2c266dd5, 0x00713e3b, 0x70bce130, 0x12c3ec12, 0xc1c7fbe9, 0xd1fd549a, + 0xd432458e, 0x2e316bc9, 0x62b594a7, 0xefb2cee6, 0xd466906a, 0x8035495b, 0xe5349184, 0x3d820abf, 0xcd57d1cf, + 0x726c5115, 0x3f63040d, 0x1a75f2f0, 0x45053503, 0x70630b90, 0x31df9a58, 0xeb329d53, 0x29415f06, 0x44c4bb04, + 0xf1e78318, 0xcd5a1fbd, 0x1a67a60a, 0x1da7c83c, 0x12141da0, 0x025f8ecd, 0xfe72c535, 0x35105e20, 0x3037ad22, + 0x7a044f26, 0x20a2d815, 0x6f018c4c, 0xe920c2b2, 0x15f9e266, 0xf5f9f659, 0x3342aa37, 0xf0440bc6, 0xefa2dfeb, + 0xa902690c, 0x119a4439, 0x02859c02, 0x2ccfd812, 0xc54b0cc5, 0xfe53de2b, 0xa5e0aca7, 0xf15ee502, 0x76b88a6e, + 0x681b84dc, 0x64d60f34, 0xdadc76af, 0x8da0b0fa, 0x34373f13, 0xaca69b9a, 0x8a94505f, 0x8b67fd3f, 0xdba7f511, + 0x78671563, 0x5029c1ca, 0xb3f5985c, 0x7e9113a7, 0xccf646c6, 0x1e980dc0, 0xec793ac8, 0xf1fe97df, 0x3696df78, + 0x3ccc1e57, 0x2d9aa879, 0x7b348130, 0x662b33d9, 0x8f3d46bd, 0x7baedb60, 0x84489d11, 0x14887e9c, 0x04d7490f, + 0x5b7838f6, 0x2f9ece79, 0x5f09e75c, 0x0a48a240, 0x3990662b, 0x3eb24c25, 0xa5989e0e, 0x09a5aa49, 0x4e0b3ce8, + 0x6604fe75, 0xcf39d490, 0xfbd1177c, 0x98adbc11, 0x51fcd1fc, 0x22153c45, 0xc17fa916, 0xb14a08a5, 0xf6041a4b, + 0x9a0222ff, 0x9db08ca2, 0x2cfd5d4e, 0x7756fc87, 0x7dd2e0a4, 0x698ff0b0, 0x7fe093e8, 0xd9202caf, 0x3d3e0203, + 0x38555bfa, 0x51cfbd6e, 0x9008bf9d, 0xfc320fa6, 0xf4969469, 0xb7a917bb, 0x04eb645e, 0x01c1f233, 0xa077f89a, + 0xfc55d2b2, 0x95f53178, 0xe0f170e2, 0x035e5a9e, 0x569af79b, 0x3210ab56, 0xb3c2fc3a, 0x916d90b9, 0xd8ce67ff, + 0xc70f3e60, 0x9695746f, 0xa705e4f0, 0xa4594bda, 0x2d67501f, 0x7fa8dfbd, 0x01c28ecd, 0x5222f9f3, 0x078b1a95, + 0xb4a4e534, 0xd7ee67ba, 0x1812a75e, 0x26477ba5, 0x5777e1a0, 0x1400ae8e, 0xc7757b0c, 0xdbc6e4bd, 0xcf4a9847, + 0x7f4ed8d9, 0x798a1131, 0x04fdeab5, 0x85efcb5e, 0x725668b8, 0xd37a0d9d, 0x873a8a92, 0x092c1032, 0x1e7a485e, + 0xcb4e3964, 0x6c89c53e, 0xa09f272e, 0x2ae40967, 0x48599084, 0x478401ab, 0x6244cef8, 0x56af6106, 0x67cb160d, + 0x095386ed, 0x0251a651, 0x2b646571, 0xd399a48d, 0xe108878d, 0x94778819, 0x40521520, 0xd3d7de77, 0x5a5334ca, + 0x03737a9b, 0xdf8d78e8, 0xb382a6f7, 0xb7b3868f, 0x5c5890c9, 0x364bb8df, 0x8a172cf8, 0xb28636fa, 0x33333f5b, + 0x113fe368, 0x6d5fa1b3, 0x78e29938, 0x074c9066, 0xe38554b5, 0xdcd7c738, 0x34854192, 0x62efe6c2, 0xf7421155, + 0x38deb547, 0xcf46ffc5, 0x7301437e, 0xfc18ab22, 0x40402147, 0x17f55c6f, 0xad446001, 0x96dfb242, 0x1ea3700f, + 0x3643f085, 0x456aa194, 0x6f15f46e, 0x945ec185, 0x3cedf10b, 0x42db0788, 0x46299cd2, 0x16bbeedc, 0x46acffde, + 0x6d5def07, 0x821dffaf, 0x39c2961a, 0x8112637a, 0x8352f88f, 0x3272bcaa, 0x4f7aac86, 0xe2a24e03, 0x80728f68, + 0xa01b2743, 0x714f2480, 0x2abcc2b0, 0x8e509893, 0x7df6165e, 0x72e65e8a, 0x67d4740c, 0x9775f4b5, 0x8bb4fccc, + 0x1e6c6d07, 0x470a658d, 0xe1a6115f, 0xfedb3d8e, 0x964b8880, 0x85367e40, 0x1717c37b, 0x9a397282, 0x827d30ea, + 0x784783db, 0x6a81aa9c, 0x688e7a30, 0x63682e3b, 0xdcd68f9d, 0x1dd8f3c5, 0xdb7969c4, 0x7671ab30, 0xc047697a, + 0xc0f70c48, 0x648acb47, 0xb41522f9, 0xe613591b, 0x1243c7a5, 0xc9ddf808, 0x1948b0b5, 0x2cdd8b9e, 0x59ae7c52, + 0xf05d1926, 0x17b4cc16, 0x9bdd3bc9, 0x7f17f7f4, 0x59e5237a, 0xd26ba32f, 0x56fc42f8, 0x4cd306c0, 0x09e5baf4, + 0xdcc28eb7, 0x86703bbc, 0x07c16ab1, 0x0360bc85, 0x2cbf5723, 0x8690e367, 0xb7e919f7, 0x55a44987, 0xd4b094e9, + 0x951f388c, 0x4ec64d44, 0x2c103fde, 0xafb89f68, 0xb5fb5997, 0x3c006782, 0x628ac3e0, 0xa8f1e45c, 0x6f558602, + 0x300284c9, 0x4aa25426, 0x3a9ef130, 0xa4f67078, 0xc010d341, 0x76ebc38c, 0xf33d81ce, 0xdc7b4eb8, 0xc2327d47, + 0x5966ccd2, 0xe8a9795e, 0x55693670, 0x08e39e41, 0xb1b56069, 0x878e84f5, 0x25eba30a, 0x2d7f9d05, 0x292df6ab, + 0x7a240bac, 0x618add13, 0x71707fed, 0xab5987ef, 0xfb3712e8, 0x2fd3e009, 0x3f40ee01, 0x08befdc3, 0xc2a1e89a, + 0x5451c8d3, 0x09cc4ea1, 0x15f24ab5, 0x08262602, 0x706a42bf, 0x38084eab, 0x275646cf, 0xd4e33b59, 0xc2a02ba5, + 0x063b4ab3, 0x111bfc0b, 0xb687fb83, 0x72e07f3a, 0xc6f9cacb, 0xe70ca59d, 0xbbd0b394, 0xd17828cb, 0x35c0c04f, + 0xb37e01e4, 0xe63e159a, 0xa64936b9, 0xec0c998e, 0xaeb105b4, 0x3a5fffee, 0x0edf624d, 0xd5eb5273, 0x81170962, + 0x0e944d4b, 0xd66e5cf5, 0x3b7e0c0e, 0xd3587d42, 0x37d267c9, 0xe216d11c, 0x813cd8b3, 0xb60c5abe, 0xf5c5dc70, + 0xf85a5c11, 0x60e41b75, 0xc7d2e89c, 0x9b248e00, 0x02a1ca00, 0x040bdac6, 0x0f72a55a, 0xaf673b46, 0xd8b0f8ae, + 0x1ae50205, 0x11ff47e4, 0x48065f37, 0x6078af76, 0x79354bcc, 0xbef3eb17, 0x1b09c17b, 0xc547d42f, 0x5d1c52fd, + 0x74a6545a, 0x0280be47, 0x7239549f, 0x2712f8bd, 0x7b90adaf, 0xb776a261, 0xee39b574, 0xb753d771, 0xc86f58c1, + 0xfbcc0337, 0x31ed43c1, 0xd3c7b625, 0x1312c214, 0xc7cd38e4, 0x36885a45, 0x44b0c963, 0xdfdb5493, 0xc8f8a461, + 0x06df7790, 0xc7f3fc08, 0x92f43589, 0xa4ec1fe3, 0xed9a83ab, 0x4b4c4264, 0x26cfdcff, 0x1425bf1e, 0xfd2db4eb, + 0xa8732087, 0x5d872507, 0xc0267744, 0x4fa996a9, 0xf4618c23, 0x8e6ce5ef, 0x4ffa3c8d, 0xf3192860, 0x1c6dc104, + 0xbcf44246, 0x8ccf617a, 0x58097db1, 0xf1f5aeb9, 0x6ac261f7, 0xb9ecfef3, 0x28def7cd, 0xaf7a9aae, 0x84030b07, + 0xdeb27a7a, 0x5cbb3746, 0xe2e8bd1a, 0x35ecd1c0, 0x1304f021, 0x93258180, 0x87679963, 0xbde548dd, 0x1bb4bd47, + 0xae2362ee, 0x7b28e31c, 0x9f2adf1c, 0xfc06ddb6, 0x33f1839f, 0xa70db376, 0xd374bed3, 0x20ed1ea5, 0x5776eaaf, + 0x57eb814c, 0x8ce10bae, 0x8d110d4e, 0x9b625290, 0x7a439e6f, 0xbe42caec, 0xa5463c55, 0xd18d96a9, 0x83bd8036, + 0x1ab0e598, 0x2a429b9d, 0x2f8c51db, 0x780269fb, 0x9ea25499, 0xf8403bc1, 0xe9a947d4, 0x4fe8d696, 0x7fceac01, + 0x680899ca, 0xba4bafd5, 0xce140acd, 0x2143e0d0, 0xb45ec582, 0x58c85177, 0xf5a90e23, 0x4a83bafa, 0xce095204, + 0x42370596, 0xb7d6fd36, 0x30064da5, 0x2ea2af17, 0x9f75e700, 0x128571f5, 0x5e6a19fe, 0x8eac0dce, 0x9e7563fb, + 0xb040cb94, 0x07db94df, 0x46eceaaa, 0x4bf16ef0, 0x1923bee0, 0xea1bf8d7, 0x8af96f5d, 0xc9063c7d, 0x6754b90b, + 0xcea79ff0, 0xfb1efabe, 0x66307817, 0x997af146, 0xce3fd528, 0x7da28841, 0xb0e04a11, 0x962b4389, 0x7ced3722, + 0x39989648, 0x0e2b955f, 0xda151576, 0x3c8b96a6, 0x2523f6f4, 0x0084ab5c, 0xa80a95be, 0x5e04c221, 0xe804da28, + 0x29c937ec, 0x6d707324, 0x631685e5, 0x2d4fe709, 0x52e29482, 0x79ce3658, 0x75960087, 0x0478c693, 0x3c646df2, + 0xc05ca806, 0x5c1107c8, 0x8fe69660, 0x8048379b, 0xee3fd9f0, 0x182bb8cb, 0xafbd3345, 0x64c402c1, 0xa75bf30d, + 0x3a4db8a6, 0xb9348e63, 0xbc983c6e, 0x13cdac68, 0xb2278118, 0xd2e846c4, 0xa3159ec6, 0x2bc5176a, 0x854535a7, + 0xd3e52bb5, 0x7e7077b3, 0xa1aef737, 0xe5ae3b1a, 0xf9ccd9c3, 0x5a987578, 0x51580576, 0xd7f84ecf, 0x8f3ab05b, + 0xc95eacc7, 0x5316ba7c, 0x1029cf12, 0x7332d2c6, 0x67867e19, 0x3855b94f, 0xc3acf214, 0x8b2e2ef0, 0xa9fbc105, + 0x30c96723, 0x50133794, 0xb5dc79a9, 0x80d86e28, 0xed85c0bc, 0xb01b713a, 0x3f109c46, 0xe4d41be7, 0x9e95fb7e, + 0x31662f3b, 0x64a5dbdf, 0xfbf9fd29, 0x69bf8c58, 0x387834b1, 0x8d3c8436, 0x46be5629, 0xe42684fa, 0x96ad5b36, + 0xcf862544, 0x662a7c88, 0x8825e1d8, 0x21685e78, 0x49ae4ae4, 0x916ffaa7, 0x17265c8a, 0x63f9fca5, 0xd777a011, + 0x12173ccb, 0x46f15ae6, 0xf72084c8, 0x50ed2ab2, 0xfa0fcb5c, 0x5e659a4e, 0xf5d6cf25, 0x52c1c39f, 0x5ef1b68c, + 0xc8565ff9, 0x9eb91c4f, 0xf68b9097, 0xaee35157, 0xe6e02665, 0xdc6d56ca, 0xb7089c36, 0xf117e314, 0xee046d97, + 0x0f8c9704, 0x8b7fb597, 0x93eda6cb, 0xa9087265, 0x628e7e15, 0xa6738794, 0x1e5e94b4, 0xe8f75534, 0x80f8258a, + 0x8246f8b0, 0x631a0e7c, 0xf6c4efa3, 0x74c610f6, 0xc9d400bd, 0x442c90c0, 0x9a0aa044, 0x2bd73784, 0xa3116f7a, + 0x3f3271e3, 0x1f1c3123, 0xce069514, 0x4541b37e, 0xa207eec3, 0x78deadd2, 0xb51f0ac3, 0xf44d4e49, 0xede51f6d, + 0x748f59b2, 0x5531bbd1, 0xd9117781, 0xca2acf14, 0x3ddfa323, 0xa767c764, 0xb57b7ac7, 0x9e21776f, 0x1811cd8d, + 0x3cb15ee5, 0x814c4fea, 0xff8bd43a, 0xb9f22ae7, 0xba01d239, 0xbe1dec83, 0xeb845cc8, 0x0e4d1961, 0x4718e2a8, + 0x0980745e, 0x615cb7d9, 0x21aee3b7, 0x2da4d84b, 0x867ef3b4, 0xfbac3f86, 0xdd8fba0a, 0x22e2dda2, 0x5576d414, + 0xeb4a3845, 0x362a4c5f, 0x9fc20427, 0x04fd82e7, 0xecf997e4, 0x89c909f7, 0x6705519d, 0xc6898af9, 0xe9076492, + 0x6ba6c056, 0x06409fae, 0xa6a62ca4, 0x4b40eb9d, 0xa0636923, 0xc860073e, 0x85e0fa3a, 0x073996b5, 0xcf12e8e2, + 0xf2db56b0, 0x24c9de55, 0x7c5cf956, 0xbb1a07ee, 0x2aad5126, 0x96fd14ed, 0x0e92ac0c, 0xa558088b, 0x5b560db6, + 0x7e60d7b2, 0xc9979361, 0xc751aa48, 0xcc0e492a, 0x44cebf10, 0x82894e86, 0x6c10236d, 0xc4ce0c25, 0xef3058b5, + 0x675c49b0, 0x042b7614, 0x2c1f2d11, 0xc0f126d6, 0xc7c8cab6, 0x6e3457f0, 0x004ead36, 0x5147084a, 0xff4b9eca, + 0x3cdcf8a5, 0x19b6d2b9, 0x6cad6dab, 0x2a403c59, 0x6e04daa2, 0xb5542d7a, 0x589dc3b4, 0x79f3bdcd, 0x18907c4c, + 0x0d78e14d, 0x38306319, 0xbcf25bb9, 0x6eace3e2, 0x8fc19754, 0x209b6342, 0xae57056d, 0x559fb7aa, 0x8f514f73, + 0x27b22910, 0x5ad2d5a6, 0x96630afc, 0xa3b240a8, 0xbda0d63f, 0x5693e11d, 0x1bb45646, 0x7182daa8, 0x885e5e0f, + 0x2d684506, 0xd3f21bcd, 0xc3c6c2fe, 0x1c29b891, 0x83e47212, 0x467909fc, 0x38b4cfbd, 0xfda944a1, 0xeda71aa6, + 0x3b778623, 0xd39e590a, 0x522b623d, 0x4f97cbe6, 0x17ff8e9f, 0xc0d96366, 0x0a1b17de, 0xd03b58dc, 0x1dc403ac, + 0xe3e03e10, 0x077bdbcd, 0xe3dd8933, 0x270f297b, 0xcbd22ce6, 0xf6bb0296, 0x75309a0f, 0xe1a15e77, 0x2f743a82, + 0x538409e0, 0x23f5cf74, 0x47e34d44, 0x506ba973, 0x422fde28, 0x4098981d, 0x524afc5d, 0xb889414d, 0xd0817190, + 0x74dd9901, 0x27397637, 0x4331ede1, 0x36286a3b, 0xdc306e35, 0x30a999ef, 0x8c8661f9, 0x9adece7b, 0xa3f6e291, + 0x7ea74979, 0xc369e3b2, 0x4408f61e, 0xee0bc26a, 0xebd49968, 0x0005904c, 0xf567c23c, 0xb411b425, 0xc61f3111, + 0x8fcd1e2d, 0x52ae814c, 0xec7602c6, 0xec489f63, 0x0ff6e026, 0xc2a11ef2, 0xa0201996, 0x38e78987, 0xc7556acb, + 0x8b00c239, 0x9ece4990, 0x438cac2e, 0xfc4ea282, 0x23645a08, 0x94aaf8c1, 0xa444bd08, 0xc653c035, 0x5634bb88, + 0x3772659a, 0x76c5f5d1, 0x4126bd34, 0xed2eabd3, 0x454eea57, 0xdd4513a0, 0x81e0640b, 0x94fd4aa4, 0x4583f7ae, + 0x007a5620, 0xeaada6ce, 0xec4456cb, 0xfadfd867, 0x528a4981, 0x8d1c49bb, 0xfc20f4fa, 0x4c74f4aa, 0x8994a0b0, + 0x06d95a03, 0x9a9f1ba8, 0x5e98f8e3, 0x6e45c6e6, 0x459eb8ae, 0x898c886e, 0xa91b8c2e, 0x9870f822, 0x77eed1a9, + 0x2f7b1005, 0x734f4fbb, 0xfd19d86f, 0xed215d80, 0xa0261b40, 0xee07f20f, 0x4ac0b540, 0xacad9735, 0x87636eb9, + 0x28d914d0, 0xcbd04768, 0x45189dce, 0x8a73c14a, 0xd498b0c0, 0x28184e9c, 0xe0a4c630, 0xca365557, 0x46e89d31, + 0x834461ca, 0x5458d6d5, 0x540af0a7, 0x5a6c8aa9, 0x700cd432, 0x31784b9e, 0xcbbcdfa4, 0xb9ae975f, 0x12555a62, + 0xbec0a33e, 0x611b3c31, 0x7d63829f, 0xb9512552, 0xb91c72d7, 0xb420e997, 0x0a2e50bd, 0xdf2f7bb0, 0xf599c049, + 0xfcb7181d, 0x3c6938a8, 0x912abae9, 0x5303d355, 0x50ba3ea6, 0xb8c57ed7, 0x221a5fe2, 0x66b493d2, 0x89a9fe62, + 0xa7444958, 0x6f07057b, 0xd8524498, 0x23a3cf3b, 0xa56b567a, 0x0fa36314, 0x3c71e96b, 0xdc2a29d4, 0xb19654ee, + 0x155c37b9, 0x7465dff5, 0xa15b9c12, 0x9f44194a, 0x66466f2e, 0x1e95a7cb, 0xe63b4dbe, 0x961f0a64, 0x4ba1426f, + 0x3fea968e, 0x603b6462, 0x9335fc71, 0xaa27c44e, 0xa30b4d8c, 0xe9d8aa47, 0xd585c1f3, 0x348c257f, 0x9d7f37bc, + 0x804e9d95, 0x47dcb2cf, 0xbdc86cd1, 0xddb63970, 0xc52a9f2e, 0x1036093b, 0xa057a72b, 0xd9e185e8, 0x35b8f6c6, + 0xa39df6db, 0x79ddb24a, 0x391f69f2, 0x4530019e, 0x70efc984, 0x92cfd8f9, 0xc81a4dd5, 0x6e0140d7, 0x3238aadd, + 0x504e6758, 0xdb83be73, 0xfe4cbeaf, 0xc7d7920f, 0x2ed35d9d, 0x5499a0e3, 0x0b6ea129, 0xffcd4b6c, 0xf992dda4, + 0xfe711159, 0xe376b2ed, 0x9c22a09f, 0x93347daa, 0xbf951115, 0xad2a6a72, 0x7ba31aa1, 0x9285031c, 0xa979182b, + 0x36329103, 0xfb9a44a6, 0x9e337ed7, 0x3024e779, 0xf0882598, 0xc00aa845, 0x5a6ce546, 0xe27da7ac, 0x49469fe6, + 0xef92627d, 0x9e4dc934, 0x547c5540, 0x9b0601a5, 0xd65a222e, 0xd90a4487, 0x8a003d9a, 0x441b713d, 0xb865d55d, + 0x112a48e2, 0xdfec6bd5, 0x025e38c5, 0x2e0749ed, 0x6ea58860, 0xd2290fed, 0x5c6acad3, 0xebff2bf0, 0x59441fce, + 0x63d2b15a, 0x3b55a9f4, 0xb04c74af, 0x23e74e55, 0x4a89fba5, 0x55f90b6b, 0xb24bedc1, 0x7f839bdb, 0x76aac315, + 0x18d8d36c, 0xc8c871bd, 0x8e2291c0, 0x1bca8eb1, 0xc3a61b22, 0x3be22341, 0x06b59590, 0x4409562f, 0x16fac0fe, + 0x97e7cb9a, 0x2fa4c23f, 0x855d2230, 0x2f51112d, 0xa6dc2bbd, 0x35854cb0, 0x5a71c464, 0x594641f4, 0x19519016, + 0x607673c3, 0xbcaeac8f, 0x53933242, 0xa41f0bf2, 0xb253dd8d, 0xe22ada0f, 0xd85ad6d1, 0x469e6a5a, 0x6e1be907, + 0xaaddc256, 0x2b36f3ef, 0x9e1c0438, 0x8c7bc9d1, 0x694c3eee, 0x65e0b7a6, 0x0e3a0d1c, 0x17721617, 0xc3e7abff, + 0x80807d32, 0xb0879859, 0x79cde05d, 0xa8e6c910, 0x974f18c1, 0x3d9850cf, 0x6c151545, 0xc7d8c1f4, 0xa09ad899, + 0xda6f9937, 0xe7381a09, 0x01b66b45, 0xefbc2d45, 0xd0bea094, 0xccd2f3a5, 0x18d0add5, 0x4b2cf0f6, 0x3c14ac0b, + 0x3d9254ff, 0x3b80b982, 0xc51a025e, 0x42b81d87, 0x69e778bf, 0xce64b318, 0xb498665d, 0x98e5a213, 0x99f86ca3, + 0x584478e7, 0x3bd148f2, 0x842ffdc3, 0x7c3da0d7, 0x3f052d8f, 0x5dbcbf49, 0xd85705e1, 0x0e268630, 0xf9a790b1, + 0xd71859a1, 0xd72f44dc, 0xf5a56598, 0xbb7a8fbd, 0x4a639215, 0x341d355d, 0xa095c7fc, 0xe463e908, 0xe04aac1d, + 0x07d7977a, 0x2d029ca9, 0xc0c71fc3, 0x995bc743, 0x45fa9e39, 0x09b35473, 0xd0cdd8b3, 0xd3b1a1fb, 0xe745e424, + 0x3bc81e29, 0xc3660d42, 0xeb367cf8, 0xd24a28ba, 0x43f365fc, 0xd9e34a48, 0x0109d62d, 0x971b9150, 0x4824f86b, + 0x22faad83, 0xeb36bf77, 0x93a95f66, 0x22e62ffd, 0x048c05c4, 0x280cdc8a, 0xff15dd25, 0x91cd3500, 0xba531b71, + 0x9bb5130a, 0x7485219c, 0x6f1fb7e3, 0x26e5b2ff, 0x695be9b9, 0x8820c59e, 0x3050952c, 0x62c152b2, 0x864099ec, + 0x339582b6, 0xd7c39df5, 0x2a6d10d6, 0xb2a92391, 0x4142583a, 0x23b198e2, 0x2e1e18d4, 0xd3b2c40d, 0xeb9915ee, + 0x4b7ad223, 0x46a2d3e8, 0x89b79647, 0x477028cc, 0x121ce1a2, 0x0f9002eb, 0xbeb76f9f, 0xd6adead8, 0x431fdbc7, + 0x479565c5, 0x14febffd, 0xc096fa8b, 0xa0326375, 0x13b24e19, 0x8bf94987, 0xa98e92f4, 0xb4ba7612, 0x7bdec934, + 0xa18d001c, 0x98f3a850, 0xc7b94903, 0x4a17ff0e, 0x2a90338e, 0x21e9dca0, 0x809b4ecd, 0x19c47261, 0x73e7f7a5, + 0x1f906f15, 0x86e5c287, 0xc6516544, 0x49fb6f78, 0xc0f58cf5, 0x87992d81, 0x852e772c, 0x392a05f9, 0x9f208792, + 0xaa09d6be, 0x7b23a7a8, 0xb73b7cd5, 0x52b0f80b, 0x71c59ce2, 0x6adb4a50, 0x69589de2, 0x82e985fa, 0x22f5f4e9, + 0xb207a32c, 0x864a4d9c, 0xccbcc455, 0x959ca69f, 0xd980cfeb, 0xb7aa991e, 0x42bc6b64, 0xd0599f33, 0x1c2942ad, + 0xccb79b69, 0xa4f74700, 0x1383ede8, 0x6188ca61, 0x81c8f6b1, 0xf7c12e40, 0xb9eda78f, 0xcff2bf26, 0x10e14bb5, + 0xd8388aae, 0x91d36fdb, 0xfeace92a, 0xee4c73eb, 0xd2e9f227, 0xb576fe8e, 0xb1f37b24, 0xa4db43ad, 0xed8d9306, + 0x658f8443, 0x606a451a, 0x9f8fc0e3, 0x06501008, 0xa245c852, 0x26bc06a6, 0x8f9e22f6, 0x695bb40b, 0x68ea090a, + 0x8a368f01, 0x4396c4a1, 0x9175f868, 0x0f6c5c3f, 0x83109e22, 0x6f72b644, 0xbe9f44d0, 0x335a3e8d, 0xd4ae8927, + 0xf8897fd7, 0x3d3f9cc1, 0x9080a514, 0xe35d904f, 0xa5646820, 0xd3e4ab34, 0x0ad130bd, 0x471774ae, 0x5b447dcc, + 0x9328c7b0, 0xce90c704, 0x44f40907, 0xf78c4661, 0xc73671a8, 0x0897a5e7, 0x708e78ca, 0x8b7efbab, 0x8ec3225d, + 0xd74ec270, 0xab4a7f4d, 0xb7339dbf, 0x0adf8634, 0x0ccfd9b4, 0x6b4c5f77, 0x4c39a475, 0x7f972a28, 0x1683faaf, + 0xd0bdf57c, 0x6bdb06b3, 0x81af1856, 0x539e2da3, 0x0ebba24b, 0xc90dcb23, 0xa58eaeb8, 0xbb95cdfa, 0xc6c88122, + 0xd6f7b7ce, 0x8f6f703a, 0x12c297fd, 0xb1d4c077, 0xcc0c45d2, 0xc759b535, 0x213ad77c, 0xaa994ab8, 0xe0d7735e, + 0x1a2e038d, 0x373086cf, 0x9ac8f220, 0x905b933d, 0xe17353c7, 0x819d0ce4, 0xdb99bfa0, 0xdf6d4af2, 0x85ca81d6, + 0x12119a58, 0x08dccd37, 0xbcbba8d9, 0x2a97dfa8, 0xf7c36c49, 0x22002039, 0x4e680126, 0x822aefa7, 0x887976a0, + 0x5bb77d77, 0x0a6e2cf1, 0xa444ccff, 0x9255853a, 0xafe52533, 0x6bd9c3a7, 0x364136eb, 0xb00af3f9, 0xa8102de0, + 0xb1067c1d, 0xd82581fd, 0xef8d4288, 0xb57376c3, 0xa85e1930, 0x6f921d26, 0x78092057, 0x451f0a41, 0x1ad1c1a1, + 0x35796678, 0xf0ad48d3, 0x0c745564, 0x034873a7, 0x2307373d, 0x61287441, 0xf6363298, 0x4a3ea689, 0x3f780eaa, + 0xc7699126, 0xadd13a89, 0xf5e97ade, 0xd81dd465, 0xb69aa508, 0xeea27bad, 0x1eefd9a6, 0x309f6e2c, 0xb2cabe07, + 0xf4f2122b, 0xcb89d338, 0xc2e09ab5, 0x9276fba4, 0xfd3578ea, 0x56573866, 0x9acec004, 0xc3d0825c, 0xf5b9d222, + 0xdbe3f76f, 0x6828aaac, 0x6f621540, 0xb1c3c9e3, 0xb3229676, 0x0e60fe9d, 0x1cbb392d, 0x5ad91a57, 0x75981904, + 0x91bea92a, 0xd7af8d58, 0xeffc501d, 0x3c3c2c06, 0xf5f747f9, 0x00a6e7ce, 0x77ada904, 0x9f674446, 0xee6c9229, + 0xfb0bba52, 0x1018b8cb, 0x848d6899, 0x1a1af119, 0x7be3fd54, 0xaa5fcfbf, 0x43649d94, 0x8e85d23a, 0x94bad39b, + 0x4c09722c, 0xaf926fd7, 0xad80cda7, 0x3457d9a8, 0x8630789b, 0xd6891721, 0xc0601b74, 0xb86c8be6, 0x4584c2ac, + 0x3baec780, 0x40645eb7, 0xa919facd, 0xb2f86d07, 0x86556ad9, 0x0d8f7728, 0x3f53ba40, 0x40091787, 0xb863baff, + 0x8675945b, 0xc469bdc7, 0xcfcdaba6, 0x312695c7, 0x1c0e49dd, 0xe7aa4366, 0xec9f2d54, 0xfa1d66fd, 0x4e7fbcb7, + 0xf9784c81, 0xc22d327e, 0x0aaad5b3, 0xff9a81f1, 0xc68080a8, 0xa2a5f4a2, 0xc328566b, 0xf5f3304b, 0x3afdb0ff, + 0x718e257a, 0x57921794, 0xbe98fec6, 0xe4d8ad6e, 0xa6884c35, 0x738af62f, 0x1c9a64cd, 0xc3b8f885, 0xa7408018, + 0x9cc8ea44, 0x392c5a42, 0xf94a2e25, 0x2f53bf98, 0x2e72c590, 0x2e98eef4, 0xda58940f, 0x860ecaf3, 0x51a3ef4d, + 0xf9fac7c0, 0xba3fe96b, 0x5c2457ce, 0xd2c17570, 0xade630ab, 0xceba3527, 0x33c25f11, 0x5dfc30c0, 0x280f45ef, + 0x74010b60, 0x0e88e366, 0x5abf0956, 0xaf387fb1, 0xe837c656, 0x6e5f91cf, 0x825ced8a, 0xd0af8049, 0x1708108e, + 0xf918d3f9, 0x6a2c8ba0, 0x1bd91fb4, 0x2ff808e0, 0x1be67e27, 0xd61c65f7, 0x9c9a2f20, 0x5db6d572, 0x31ef12e6, + 0xd22d0025, 0xdc65b2e9, 0x62d64bb0, 0x9c5ab345, 0x60f6fe7a, 0xa6b0f3ff, 0x0d0a09ad, 0x6a7801da, 0x68d43016, + 0x470bee04, 0x5c25aedf, 0x63d25bde, 0x1e9ec7ea, 0x3f06951f, 0x4720eb21, 0x05600584, 0x609ab8bd, 0x343af8db, + 0xbc35a036, 0x03d8267d, 0x2c303d5a, 0xbb1c9cc5, 0xdfab572d, 0x8431dd0f, 0x37d5d26e, 0xe80a3801, 0xc35bb986, + 0x3a7016b7, 0xc3e084b3, 0x9fa89ac0, 0xe335e867, 0x072de67e, 0xab907c93, 0xe14f9e70, 0x3a5de490, 0x5ee89ffe, + 0x770bcd11, 0xed19c23e, 0x001bbb2f, 0x78a0fa61, 0xf7858e15, 0x8a352ee1, 0x674e4eef, 0x67b77607, 0x580c3e8c, + 0x5c57eedb, 0x96c1252f, 0x7eccaaf9, 0xb3130c9c, 0x8dc16840, 0x5be65ae8, 0x27855cfd, 0x092e4118, 0x24969961, + 0x6698c47f, 0xdf9d4066, 0xc9976990, 0xf873329d, 0xc2337036, 0x23c0d364, 0xe03bbb13, 0x71637c6c, 0xa72b3907, + 0xb5a7ae51, 0x01a8b311, 0x3a43e19b, 0xf44e2bbd, 0xf1cf1c7d, 0x51db975d, 0x00757e67, 0x871eaacb, 0x6deb92ba, + 0xc758a7f1, 0x4fb0ba88, 0xe303d359, 0x83c3366d, 0x1ebd6b73, 0xedabd116, 0xfc066171, 0x140a77e2, 0x367a79b6, + 0xdd8384f9, 0x2c3e8296, 0x754e97f9, 0xa09809b9, 0x55f8bb1c, 0x4c119b9c, 0x6aefaf0a, 0xbab7df1c, 0xbb5ae110, + 0x58af07ab, 0xcc29e3e7, 0xb5bcf142, 0x7f4b9430, 0xf5ed9623, 0x34b5dec1, 0x9578eee8, 0x9ab387cc, 0x4cba6a6d, + 0x57ed72ef, 0x17df8b68, 0xac5b2645, 0x507d36c4, 0x87b41ec6, 0xe1646255, 0x82aacc83, 0xea04d1e5, 0xa61a8d7e, + 0x413eeba8, 0x19b2cd7c, 0xae1cad43, 0x13f227e5, 0x2b560c45, 0x4832e809, 0x49483290, 0xfa42e483, 0x9841d48f, + 0xe2ae79f6, 0x635eaa02, 0x6ab9400c, 0xcd4098d3, 0x5352d2c8, 0x56069abc, 0xd6a3c396, 0x71899cd8, 0x254decb9, + 0xb054d38d, 0x95fead7e, 0xdd0da5a2, 0xf74694d6, 0x0c8b6941, 0x71978b69, 0x522fe530, 0x8d0ca831, 0x421e0dab, + 0x3bea8b25, 0x529f8ebc, 0x7c82105b, 0x4cbe519b, 0xe39497a2, 0x71a166e5, 0xf3c8f21b, 0xe65f2bc7, 0x33b4b33b, + 0x243d59cc, 0xb89b7ffd, 0x022bd41b, 0x4ae9b219, 0xe10d6c36, 0x88271c4e, 0x6059f6d4, 0x7b439d08, 0xb08f7194, + 0x3ea663c5, 0x565f4f1b, 0x07556f5f, 0x3206cdce, 0x2ceb432f, 0xece145ba, 0x9c8a83b9, 0x0251a164, 0x55d39e85, + 0xc15a7ad0, 0x3b87556a, 0x7f7dc3cc, 0xf3d488cf, 0x070d17fc, 0xea925860, 0x6ab73225, 0xa30c375c, 0xcf0f6c37, + 0x25849baa, 0x2bf47b63, 0x19a1ac21, 0xd1367498, 0x8fdfb991, 0x955bdc96, 0xd254d81b, 0x830f4cb8, 0xa5d5621f, + 0xc1782f76, 0x78807814, 0x7b1aee2a, 0xaf5ad83f, 0x5956341c, 0xd8e35f46, 0x32e1a10b, 0x20c713f9, 0x363664dc, + 0xeb8fa42c, 0x08f0646d, 0x3398e0de, 0x754816ea, 0x13b6e604, 0x1661363c, 0xe8a5c91d, 0xe5bb7eaf, 0x995b046c, + 0x3e24ccb0, 0x5214fe8e, 0x1e35fa83, 0x75dae369, 0x574ffe75, 0x2d31f6f4, 0x738ecfc7, 0x503f9f3b, 0x0f7639b3, + 0xc2acf218, 0x561badf5, 0x20b45c96, 0xddff68d2, 0x4f446259, 0xddf154f4, 0x20c560cd, 0x33c9b2e3, 0xbc8dcd9a, + 0x9a008d85, 0x1dc05731, 0xdfe2ad8e, 0xa5abfcf7, 0x880cfe50, 0x5474a34b, 0xd4c6e651, 0xdf42db20, 0x1028a1bf, + 0xf034b99a, 0xcb896e5f, 0x35e1a1db, 0x1362b154, 0xc9a5e08b, 0xd07362bd, 0xa01c1557, 0xe548734f, 0x135c81c1, + 0x9bd62e90, 0x640a4d53, 0x3ceea688, 0xc9b4b674, 0x1587f230, 0xc73fd160, 0xace6658d, 0x5450abdd, 0x62fbd400, + 0x840bf071, 0x575ca643, 0x9f35b4df, 0x926a7485, 0x305259ac, 0xece60202, 0x7d4ff7cd, 0x454d7a87, 0x7945ea91, + 0xeba79bcc, 0x4f75891a, 0xf63a5f5b, 0x303a8777, 0x751b6399, 0x3f932aa2, 0xaf906282, 0xce73fe37, 0xfbf5ff00, + 0x60acae88, 0x04c1ff27, 0x3264ca97, 0xeb8cc047, 0xe240cf11, 0xd1f769c5, 0xabeaa31d, 0x9ccfc99d, 0x29d86ccd, + 0x491df17b, 0x6a4680c9, 0xd80eb82e, 0x78c2faa8, 0x58497a64, 0x5250baa0, 0x66bc0479, 0x4ab02fa8, 0x178e2919, + 0x030fd01f, 0x69a443cc, 0xd1c9eb12, 0xba47e316, 0x4ae4e6ef, 0x22af0c45, 0x4484c0e2, 0x71c4fd2c, 0xbe367a24, + 0x3e56882e, 0x5a48f5fb, 0x1dcc0bbb, 0x587d7946, 0x516651f3, 0x7e29eb0f, 0x2e049db3, 0xd08060d5, 0xdbbdcc00, + 0x762c8ec8, 0x50673044, 0x9ce6b51f, 0xc260056e, 0x43547c85, 0x7abf121f, 0x41e1fd2b, 0x57b9144a, 0x2c75c72e, + 0xa73f9d77, 0x8db89827, 0x93c55264, 0xc697ba2b, 0x86fc4262, 0x8759f7b6, 0xecec732d, 0xc87f4151, 0xb27d0498, + 0xb6772f47, 0x17573ac5, 0x69209bcb, 0x05b3ed79, 0x68b750d9, 0x052ee017, 0x59a8c355, 0xc864ccbc, 0xad9cfca3, + 0x2f7f8454, 0x67e4fd91, 0x74f1dbc7, 0x3358d038, 0xa6385266, 0x3e2c88ac, 0xdfa68c5b, 0x91285d0a, 0x85c20f69, + 0x79913df9, 0x4aeb8b6d, 0x3aeb19af, 0x15e3dfcd, 0x1967223d, 0x02c61223, 0x0c457620, 0x9674fabf, 0x5bf3ba0c, + 0x08848bbe, 0x412eb30d, 0x37e10758, 0xd821f47f, 0x6382ebcb, 0x9bf0f34e, 0x36f34e1f, 0x4f537504, 0x5789647c, + 0xe0be61b9, 0xd28b68e0, 0x2c9e0a7a, 0x7ca03fc4, 0xe1262528, 0xfaa5d090, 0x8867a10b, 0x4fa3c7d5, 0x8eec652c, + 0x6481f61a, 0x823eb505, 0x3d3830c9, 0xfd841cda, 0x0129239b, 0x01e42da6, 0xcd9ef848, 0x6b6c638f, 0x1041fd9e, + 0x14ef3eb3, 0x3f62f6cf, 0x0fce6dfd, 0x43e9863b, 0x4916c65c, 0xfab6480e, 0x5f1db6a5, 0xb0a1a4c5, 0xd0889807, + 0xd3f44db4, 0x50cac412, 0x7a50b6db, 0xb409cefe, 0x11cbc625, 0x8327590a, 0x275cb510, 0x20eecbea, 0x37657c9c, + 0xbbb0bba6, 0x192e5fc1, 0xb54516fc, 0xd85136f8, 0xde39bcc8, 0x1f366509, 0xf233a616, 0xb233550e, 0x128ba8a6, + 0x5c72d950, 0x9250bc08, 0x903356ae, 0x171cc9f5, 0x12456de1, 0x39a64fc1, 0xc68618d9, 0x50cf69ec, 0x4d4700ef, + 0xa9fd234d, 0x024ee5ed, 0x93469958, 0xea236fb1, 0xfdbbb550, 0x7f400cc1, 0xeb49d36d, 0x0b8c7300, 0x3997989b, + 0x77467e4e, 0xffb74110, 0xc207081d, 0x5d1f6d2b, 0x1ab18ce1, 0xde75e951, 0x481db920, 0x2ca43016, 0x11a62040, + 0xbb5a6b25, 0x5b42b1ad, 0x148123fd, 0x80fdcc03, 0xb8afe5fc, 0x248b161f, 0xcce31c93, 0x12face32, 0x8ab58807, + 0x619dea8e, 0xe2446532, 0x0c10bae8, 0x16fe635b, 0x4d234a59, 0xa8c0678b, 0xbad9ea6c, 0x25a8af73, 0x60df8a19, + 0xeab55d10, 0x76cc7305, 0x471a5410, 0x59b1282e, 0xc7564a30, 0xbf937876, 0xfb07cf3b, 0xa18c2fe3, 0x7d1d235f, + 0x476b1abd, 0x168f978f, 0xbd8bab7b, 0x1b24ad32, 0x6f447888, 0x9650d67e, 0xc5629974, 0x56f888bb, 0xbdefbe04, + 0xd774331b, 0x45b43b6a, 0x034d4745, 0xf80b9ac1, 0x69827033, 0xbaf0425c, 0xbe68a21b, 0x75958b90, 0xe0798719, + 0x447c7b4f, 0x21106083, 0xcb6ed518, 0xcecd857a, 0xec2225f1, 0x6e2e64b1, 0x05d49751, 0x0f42b68e, 0x6f80eeab, + 0xe380707c, 0xf785e967, 0x22f84ddb, 0x9a0e7232, 0x4166b0f1, 0x7eb71e86, 0xc26262c6, 0x2275a3a3, 0xaa05780e, + 0x08107d33, 0xccd1153a, 0x3acbd827, 0xb6d8f5c8, 0x8c6589c9, 0x158d70d5, 0x883453ed, 0xd78609e9, 0x35ca0a49, + 0x39885ae3, 0x625e7c76, 0xd956d84c, 0x4cb0b9b5, 0x580f7485, 0x8969767b, 0x80175137, 0x653b1306, 0x531b8400, + 0x56c1c3df, 0xc4335b1c, 0x52d52776, 0xd6d89fa4, 0x69f7931d, 0xc40f20e1, 0x3fd4dd46, 0xa866ffcd, 0x392f694f, + 0x3ba3dc33, 0x90b1bf69, 0x7ac24dad, 0x3d5ed96f, 0xe2210c85, 0x3a70c662, 0x9ed61afe, 0x8b4964c1, 0x3d19b776, + 0x91474c25, 0x740967b8, 0x02c22fed, 0x24086164, 0x82dee374, 0x5d919f37, 0xc83656ec, 0xb3eee5bf, 0xf4c7d386, + 0x90f614b7, 0xb96578c4, 0x32b48ff1, 0x4edd613f, 0x12f99d81, 0x2b32372c, 0x9b6eb0d4, 0x6165a4f3, 0xa520daf6, + 0x6da9d512, 0x23a61578, 0xdd76dc79, 0xc53486ab, 0xbfc008c2, 0x95d84dbf, 0x284b46b4, 0x9f04defc, 0xb7c8135d, + 0x2fe59cdf, 0x81329fda, 0x7af6173b, 0xdf415888, 0xe3be45c7, 0xe29ad88f, 0x4f36d5f9, 0x817fcb89, 0x83549dbd, + 0xbd8bb698, 0x5260ee90, 0x7f3e8996, 0x044b58fd, 0x434aecdb, 0x2ef13736, 0x4ebc782b, 0x21f87cad, 0x393e78a3, + 0xf4d49301, 0x4a8bdeea, 0x95ed7afd, 0x52cb714a, 0xa2bc7a33, 0xc69a5a7d, 0x13ebb8d4, 0x55a14de3, 0xeda383dc, + 0x8012aad0, 0xf191e677, 0xcdc61180, 0xa3e3be53, 0x0165d33a, 0x93be6e1f, 0x8e3adebc, 0x3a6a1398, 0x89c62163, + 0x86c6c83d, 0xa888c8d0, 0x5f4c8ef0, 0x7f841e6f, 0x6840b454, 0x6ff00a2c, 0x77c07b74, 0x0bcfc050, 0x26e7692a, + 0x9e8841a1, 0x5da716d8, 0x00cebf69, 0x5021136c, 0xd356f935, 0xcb18b62d, 0xf97aef51, 0xc93e590e, 0x1e918481, + 0xd4b0e666, 0x819143c6, 0x4890939b, 0xafdba13a, 0x77d02441, 0x1268af96, 0x8aa19f88, 0xc5048ad7, 0x62ec7e33, + 0x031f18ca, 0x501c8645, 0xc243f915, 0x68dc0f1f, 0xec796ba9, 0x08673a4d, 0x5d4cb524, 0x6d6c4913, 0xa6e02ea3, + 0x4e725474, 0xf3f61c36, 0x5d7b4ce2, 0x7d74f7dc, 0x203e6ae0, 0x1266a0c0, 0xa6b0dbde, 0xf28fa57b, 0xc5e61795, + 0xa4fe0528, 0x3cfd60c8, 0x7c64d394, 0x8489ccf8, 0xf1675abb, 0x91755cad, 0x6870d21f, 0xc28ef5c6, 0xfcdf567d, + 0x4d415f00, 0xee819e3d, 0x23a2be08, 0x226f6d0a, 0x09d21ae4, 0x3972fea1, 0x4f17117b, 0x3b091f71, 0xb1a5a252, + 0xba92cc7f, 0x71882627, 0xb582d29a, 0x3564d5f1, 0x84ba49b9, 0xc16bce98, 0x548dcf64, 0x6c33cfaa, 0x4f1cafcf, + 0x0798935e, 0x8a6d7edf, 0x9975c14a, 0x303a3f5d, 0x45525afc, 0x586ab960, 0x7dc74e35, 0x82138351, 0xa1e3dd79, + 0x50d36b1f, 0x283b88ab, 0x1fef83f2, 0x82db378a, 0x6e2e2e21, 0xf18c5ba7, 0xc84164f5, 0x39d6412e, 0x3ed832b6, + 0x230b9ac0, 0xb288eac6, 0xd86d1a08, 0x0719a4da, 0x63da00b7, 0x732394ab, 0xc55267d2, 0x902c71c1, 0x968e8f59, + 0x0c9606f2, 0xb4511c74, 0x0ee71351, 0xc9e9b1b6, 0x03265534, 0x27b2799f, 0x4d8ed1d1, 0x95b188a3, 0x58f16fc5, + 0x4d437625, 0x53fb4e2b, 0xff085033, 0x44b5559d, 0xc9f3c8f8, 0x67cb4fbf, 0x9f2f9390, 0xa3627513, 0x11012f3c, + 0xb2f0d901, 0xb2df1df6, 0xf55f4c7f, 0xafed7210, 0x44760eda, 0x8ab84c11, 0x11425fb5, 0x382bd075, 0x1826fa90, + 0x74855041, 0x9d9b8ecb, 0x87cc5de7, 0x0c3d9ebe, 0xf5229f00, 0xa6845d59, 0x0d58205f, 0xcc88f730, 0x9e55462d, + 0x781f4d75, 0xf0995ecb, 0x423d9fbe, 0xdbd9c29f, 0x3c94a8ba, 0x60907668, 0x4fc33da8, 0x24805dce, 0x04bfa3d4, + 0x0f57f87a, 0x0025c7d1, 0xacdbec85, 0x53fd4fc8, 0x16e17ae4, 0xe689a5af, 0x641d5295, 0x0b6be4ea, 0xee9371c4, + 0xc6c5de36, 0x88cf232a, 0x6a57ec91, 0x96e94b36, 0x4c22506b, 0xe96b1142, 0x283d46ca, 0x2bbf14e2, 0x87db44b2, + 0xd4f8273e, 0xacb8b0df, 0xd05cdbb4, 0xa6d842eb, 0x08ee3e25, 0xfc886243, 0xfa7a83b4, 0xe0fb892e, 0xe083c594, + 0x8a6608d0, 0xd564083c, 0xa5c77127, 0x5a74fee7, 0x4f416c1c, 0xc9bf4d97, 0xa4e0768a, 0x2adf82ba, 0xcd91264f, + 0xc9f352ba, 0xdab3e0ab, 0x2a5d1b53, 0x226adaba, 0xc31fa585, 0xb9ce9b62, 0x70f7e8dd, 0x9c20af25, 0x7b49bf32, + 0xd050b576, 0xa19fbbb3, 0xfa3ba9cc, 0x8cf59259, 0x7a0fdbdf, 0x2fb02275, 0x7337c1dc, 0xf62ade33, 0x654d2e13, + 0x0e5a6f3f, 0x9115a159, 0xdd29da1a, 0x09e46e4f, 0x420612f3, 0xb99441e3, 0x5aa18bad, 0x1a11b6b7, 0xd56736b7, + 0x985f0dc1, 0x85ef06d7, 0xc48693b8, 0xd2d46d9c, 0x84036d0a, 0x867d6101, 0xb783281a, 0x8e55e463, 0x5497258a, + 0x46e64b4c, 0x5f3109e5, 0x2046f545, 0x8d6dfeb4, 0x1ed226a3, 0x642bbc48, 0x7b6479b9, 0xc54f498a, 0x3e594241, + 0x46a595bb, 0x24a10681, 0xa53d4fe8, 0x3407dda7, 0x195609f4, 0x1df27fa6, 0x3da6fbbe, 0x13000a8d, 0x3a945a79, + 0x31faf9f9, 0x35e5b989, 0x27231bca, 0xf8308909, 0xecb80732, 0x5b5e327d, 0xded1095d, 0x08c6cd85, 0x33919302, + 0x7ba3da30, 0x9aca2881, 0x4886b5a6, 0x8743a3ce, 0x716f853c, 0xbac526cc, 0x617097c7, 0x69407c05, 0x776dda25, + 0x7078f5de, 0x2cfa28b6, 0x6accb448, 0x0b8cce3e, 0x1167ba37, 0x4dfc4f60, 0xdb3557ff, 0xa22e647f, 0xc59632ec, + 0xb46b3c45, 0xf36e287d, 0xda1acc0e, 0x977d08f6, 0x91ff7478, 0xb2484044, 0x91dc9132, 0x7b54bf61, 0xd1b1c0d8, + 0xac2ca524, 0xeb6ceb48, 0xa36cbadb, 0x9f31f2d6, 0xaf947da5, 0x7b18da77, 0xd4c87b2f, 0xe8ab9c4c, 0xd79e1379, + 0x750c57eb, 0x6a05a178, 0x00968900, 0xe44ee4d6, 0xa4b72eaa, 0x90b9730d, 0xf2085f9b, 0x731cb34a, 0x9db73a7e, + 0x42b15d32, 0x96179174, 0x76c8c8f4, 0xeb3c3e8d, 0x667e6bea, 0xf427d832, 0x9dccfe3b, 0x1675d06c, 0x11030b91, + 0x4990cc1d, 0x12b7f619, 0x29342564, 0x7d2aa79f, 0x7851641c, 0x5fe42513, 0xbb095388, 0x83f9844f, 0x86b0df0f, + 0x5204c12c, 0xa45e78c9, 0xcc422679, 0x729a42d4, 0x2375b3b3, 0xfe4028d8, 0x83a03ee2, 0xd7d92810, 0x8c9210fe, + 0xda6bb4b9, 0x07278070, 0x2fa01c6b, 0x1ded657b, 0xe6f94879, 0xed1c2fc8, 0x61ef3a08, 0x40b27811, 0xb5337f63, + 0x05100f79, 0x74cad796, 0x48568580, 0xc4d16c63, 0xba8a90b6, 0x725f0049, 0x2708a957, 0x930f5fe6, 0xb90c2249, + 0x70805fed, 0x7b988556, 0x4c7b3583, 0x421218d5, 0xf6332d07, 0xe3bbf695, 0x492dc85a, 0xdf186828, 0x1c87d5fe, + 0xacece0a5, 0x54f007de, 0x6efc736f, 0x185f8cce, 0x19e0a402, 0xd11c6769, 0x5f4abc7e, 0x1dcc6d24, 0x0c3a459c, + 0x125028be, 0xbb285f39, 0xcd197c0d, 0xf04ddf2d, 0x9e8f1f08, 0x4c05a70b, 0x75c47479, 0x18a4cb7c, 0x4914a8cd, + 0x93d6c257, 0xf630c0b3, 0x9099362f, 0xa2fa9b48, 0xc05e60c9, 0x47094ff4, 0x49c39975, 0x87329350, 0x5b2a5b2a, + 0x138793bc, 0x4fd45a32, 0x4c03fdf2, 0xf4490394, 0x1821784d, 0x397ba2a2, 0xf73bfaad, 0xc82c821a, 0x8af2b363, + 0x5aaa52eb, 0x0f0f2dcf, 0x05cc51ed, 0x7c8115cc, 0x8b053ebd, 0x6e698b9b, 0xc9ffd391, 0x24b49468, 0x1f0d0d21, + 0xb27e30ce, 0x3efc3c0b, 0xbf3b3118, 0x6fae4537, 0xbb2c8b59, 0xde9ddcae, 0xb3cd989b, 0x6afde929, 0x16e75f07, + 0xb19e6503, 0xf3666eb8, 0x76ad44a1, 0xce5c162c, 0x1af25b77, 0x71db0818, 0x5c00d4c0, 0x180ddcdc, 0xb1525402, + 0xa726ef4d, 0xd369b3cc, 0x32d4dbb7, 0xa61ff33a, 0xe5ad55bf, 0xed9595fe, 0x6c95103e, 0xdb7cfbe6, 0x093db942, + 0xe65eb285, 0xcf3b7ee4, 0xfe81d5df, 0xa0e22273, 0xb4fd3d6a, 0xf88b4ce8, 0xcd9e03a1, 0x958bf1f7, 0x29a14805, + 0x08c4d56f, 0x9723cc4f, 0x44695faa, 0x9fe3fe47, 0x00826041, 0xdccd22ce, 0xc1a35ba2, 0x19de0ce0, 0x2b46b3fd, + 0x3645a428, 0x84efcf13, 0x31675880, 0x6c7d9c2f, 0x84368646, 0x8b123b14, 0xb7115f09, 0xa8b2dd49, 0xbf6333df, + 0xad9c6add, 0x47ece839, 0x40c3b15e, 0x08415521, 0xab1e7dab, 0xd321574d, 0x9eb4ef15, 0x7c5f15a5, 0x4bf1fa4f, + 0xdc6e8551, 0xd47e6625, 0x8a2b9868, 0xc30a078b, 0xd6a2d4ce, 0xc4131570, 0x0f33dce0, 0xb4b395eb, 0xb81de2fd, + 0x3dd80e7b, 0xa5153d9a, 0xe49dc051, 0x95eb3248, 0x1a6e42cb, 0xd6a48bf4, 0x1677e79c, 0x1a0f33c7, 0x497b4a9e, + 0x1fb05739, 0x0f0cc05d, 0xd75cf377, 0x8a5ed037, 0x084d8044, 0xb9aacafd, 0xeaf91d76, 0x22a7cbb8, 0x3a35e9f7, + 0x6834b330, 0x0ada17db, 0xf35ae922, 0x95f6eb22, 0xdb75d6a8, 0xe5c6de98, 0xb9603033, 0xf33a369b, 0xe06c51c1, + 0x2030e419, 0x2b8b0409, 0x7bd48d6e, 0x5723f874, 0x2b451771, 0x541e8608, 0xfe3191ff, 0xe1eaeb75, 0xd5c97924, + 0x22afd1f5, 0x44f48154, 0x31a14b46, 0x0535a3d4, 0x26832d95, 0xe2c53461, 0x0d3964cb, 0x13d9ab61, 0x7c779880, + 0x21b75b6e, 0x5a952594, 0xe3932fa4, 0xd879fc7f, 0xf254edf8, 0x08935a52, 0xc2149b25, 0x4656b5e7, 0x6cf9b893, + 0x78c9a27e, 0xe58e54df, 0xf61d464b, 0x1467016f, 0xd5628f13, 0x736588ce, 0x542a2bbc, 0x885a9b08, 0x50b7690a, + 0x95da59ac, 0x39c3a444, 0x43ece943, 0x7712a2dc, 0xe352f022, 0x9e115c0b, 0xcf33aa5e, 0xee0aff87, 0x4afc2852, + 0x337f237c, 0xa62e6d8a, 0xd0f26a2f, 0xe5d6edbf, 0x3a92965b, 0x58460e8a, 0xbee1939f, 0x3ec9c8c6, 0x9096bf33, + 0x804131b8, 0x0f0058c9, 0xf23a7ad4, 0x08e17c69, 0x483dec97, 0x68452f09, 0x9122f728, 0x0d4ed2ed, 0xbb4ea0cb, + 0xba089853, 0x45c0d99f, 0xaaa71914, 0x64578fdf, 0xe22dcca7, 0x062e2322, 0xf6374468, 0x042f95d4, 0x47ed3b80, + 0x612e1280, 0xc619d1b0, 0x430ba4b9, 0x64f9ae91, 0xfcdedd25, 0x2b47cf2e, 0x5c191dbf, 0x0afbbb05, 0xd601289d, + 0xf4b83480, 0x8b4b3f6e, 0x33f44f36, 0x87e39cdb, 0x56a29b26, 0x916ed899, 0x058d96b9, 0x759d9a85, 0x58636435, + 0xecdde101, 0x2ab1ea4e, 0x30cdd312, 0x050ebc50, 0x6093e5f9, 0x54dedb37, 0xb2dc6acb, 0x8ae1a28d, 0xb3f772c2, + 0xeed0b7da, 0xc84e4154, 0x6f97a35d, 0x00f0b9b3, 0x22e4aefa, 0x71b3d06a, 0x2c01366b, 0xc6fb7168, 0x1d077283, + 0xde0e3a51, 0xc665f9e6, 0x70c44b61, 0x1ef4a99e, 0x5628c60e, 0x6e55845d, 0x3c97cfd3, 0x9f4e108f, 0x61a08081, + 0x6d973a74, 0x088d0393, 0xcf79959f, 0x0a003fdc, 0xb410b388, 0x7d0d6a6b, 0x63914679, 0x98549fa2, 0xb1617e1a, + 0x9b275fd9, 0xbf5fa250, 0xd9df7060, 0xf559c750, 0x5abcbf0f, 0xdc1deb0e, 0xd7315b19, 0x1f4c07c1, 0x81a769e2, + 0x6771c195, 0x0ada03d4, 0x7b52a633, 0xe4c2d6ff, 0x7edc1b92, 0x1c743cdc, 0x9db5077a, 0x9fda4278, 0x9394aa9b, + 0x518bd21c, 0xb0a7eae1, 0xe9eb14ae, 0x6660fdae, 0x17b969be, 0x53815b19, 0x4d9286b9, 0x91567f7e, 0xb1f265ac, + 0xdc95532d, 0xe48c7209, 0xbe5bb741, 0xdfe3e132, 0x0ff07a54, 0x05ceab92, 0xd89b39eb, 0xa75a9e97, 0xa1f11d65, + 0x3773ac4a, 0xb495e444, 0xa98af69f, 0x113b38bb, 0x4a798fb3, 0xd40c1d6b, 0x4991db1c, 0x17afeaf2, 0x9b390e84, + 0x92929b5e, 0x962b0a88, 0xf160752d, 0x20bd8c9b, 0x5a532d14, 0x901e8466, 0x31982028, 0x462a10a8, 0x19212083, + 0x4412db77, 0x7ed9d748, 0x2d4c5b1b, 0x66429788, 0xe5425a9e, 0x889749dc, 0x6d03afba, 0xc0aea129, 0x57decf40, + 0x6c93752c, 0x2407ea81, 0x9e3e362f, 0xb15db23b, 0x7330c6b1, 0x2bdba1dc, 0x25ea63b6, 0xac9c47d9, 0x1fe262fe, + 0xf9368b0c, 0xd8745055, 0xa248218f, 0x681e620f, 0x3954bada, 0x39a75fc1, 0x007e3349, 0xa0e570f9, 0x92a98c08, + 0x214db080, 0x5256a5b9, 0x48c6b8d5, 0xb5376650, 0x3db60db6, 0x7dea1bc5, 0xee291425, 0x424f4611, 0x12ad77c4, + 0x1b2e7c16, 0xe6f3d395, 0x1feba2ca, 0xb74701d2, 0xd29cb091, 0x13544599, 0xf980a0cb, 0x43cfe106, 0xb48c41d6, + 0xa7f87fdd, 0xb29c8c16, 0x6aeae812, 0x3fd455ff, 0x04f52596, 0xfe8c399f, 0x7d4f9d38, 0x5463b849, 0x76c9cfe2, + 0x72efa7c9, 0x78d64d4b, 0xcdb20550, 0x3ad3e3a5, 0xe19ab216, 0xf792a4ce, 0x82d0f755, 0xcbe99cd2, 0x491fdaf8, + 0x4bf79ddb, 0x1033e1e7, 0xfff627cb, 0xd4a2d9c6, 0xef5c419b, 0xe2a95993, 0x428f6a53, 0xc4eb7a48, 0x93239d4a, + 0x58995742, 0xaeccfac8, 0x60c19844, 0x36142e91, 0xe6c06939, 0x34c96861, 0xd0f5d267, 0xbc207a0a, 0xbd63af40, + 0x9abd9f95, 0x4c03668f, 0xf31f8a40, 0x0738c136, 0x265a4322, 0x2d83d562, 0x45eb9d9a, 0x4c9c0a0b, 0x204d7d62, + 0x0338fc32, 0x48a4c4d9, 0xf9ad73e4, 0x0764de11, 0xfe1c3862, 0xc4c2e656, 0xe9c33284, 0x0e965438, 0x2919dcf8, + 0x3c63a026, 0x1658559f, 0xffe58eb1, 0x78b2faa1, 0x239b8617, 0xb0e6db32, 0x3d8ba1ce, 0x0f0a8324, 0x7aca8353, + 0x324786cd, 0x9679c535, 0x77543ae5, 0x5b419cc4, 0xf573d061, 0xcff5e409, 0x1038fb5f, 0x57f3588f, 0x11714df0, + 0x0b8ab8d4, 0x0588aac5, 0x64d8bf5d, 0x07607ed4, 0xe0f4cd29, 0xe6165913, 0xab3e7820, 0x9b3b716b, 0x01c150fd, + 0x4f14a9b4, 0xb4c2c1ea, 0x04a672db, 0xdf42b41c, 0x52a58435, 0xafc5e9e7, 0x33bc3038, 0x6cc7f42c, 0x3e33206c, + 0xcc75920a, 0xc09f9bd3, 0x2999e70a, 0xcd73fd06, 0xc3aafa4c, 0x75fab9aa, 0x397f5140, 0xb298ade6, 0xd4c1f4f8, + 0x50692f7e, 0x5216a8b9, 0x1bdb78df, 0x1573af42, 0x4ed16941, 0xc77ac846, 0x9bc93591, 0xd1f928ec, 0x7fd1ba68, + 0xa626afef, 0x73525a15, 0xee63b326, 0xab8a1fa4, 0xe419aed1, 0x056d2fad, 0xc9154a12, 0x283b44f1, 0x79d01cd1, + 0xc4d31d5e, 0x9b6e2e8e, 0x648f7aeb, 0x76ea94b3, 0x49b345f1, 0x2547e844, 0x2d81fb22, 0x60e0ff6e, 0xee221f5f, + 0x5dbb6a9c, 0x7609b1c1, 0x61e4131e, 0x61dd5677, 0x73ff3c5e, 0x0584a123, 0xc9c3aeae, 0xb56379c2, 0xdd7dfdaa, + 0xd161dd8e, 0xfac5d0fd, 0xc567281e, 0x6ae385ee, 0x8dbc7a15, 0xdeb1d9d1, 0xba8c1f52, 0x2b36bce7, 0x0ccde041, + 0xc8c84a71, 0xf72528b1, 0x960ca0ee, 0x42a896da, 0xb7862abc, 0x019f68d1, 0xdef84cb0, 0xe610aacc, 0x42256443, + 0xbebb3f92, 0x27962c8e, 0xa6cbc38c, 0xad98233c, 0xdb2411b0, 0xa49488a3, 0xc553c066, 0x8763ab92, 0x37ce294c, + 0x131a23d8, 0x3f075f11, 0x3695bad3, 0x4875344c, 0x71a57f79, 0xd4c961cb, 0x2a7dae37, 0x75b8b219, 0xe03e60d3, + 0x963f89f6, 0xf30a0c0b, 0xace51095, 0x38916b7e, 0x01e8dcb0, 0x8c768c02, 0xa79cd99d, 0x41c48758, 0xf0b6a272, + 0xe5ec941a, 0x8abccf06, 0xcb658516, 0x8d3e01b2, 0x2c73d40d, 0xc5291043, 0xbbd66f14, 0x1c80b98e, 0x735478a1, + 0x2ce8d633, 0xd599dd5a, 0x24cfc975, 0x7700adc0, 0x8218370d, 0xffbc5fba, 0x90adbaa7, 0x11cbdf42, 0x30530590, + 0x63a2d0cd, 0x41abdca7, 0xc10907f4, 0xe0f9c146, 0x095c4821, 0xf3b1c0d7, 0x21b75329, 0x7cb179ad, 0xe963bbe2, + 0xe3365833, 0x49279cfd, 0xfd87b45a, 0xa703a459, 0x2c808ab6, 0x12a73b11, 0xc901955f, 0x33a228f8, 0x87cd5ad5, + 0xe1003820, 0x1f1c44f8, 0x9462e2a3, 0xced2ed89, 0xe03787f5, 0x0954d28b, 0x97a5518d, 0x288e8fad, 0x51366b9f, + 0xcfb207be, 0x15213bc3, 0x8e946d92, 0x606011d1, 0x6542a7ca, 0x92781868, 0x05861349, 0xf9841a5a, 0x377ffe5e, + 0xd4d0d6b6, 0x5017f365, 0x103d7bbf, 0x4b168d7a, 0x71d23dbe, 0x5279986e, 0xc75aba0c, 0x9a7a0f58, 0x7bd9ea6f, + 0x166cec00, 0xa19e3175, 0x21aadf31, 0x5b9ffc83, 0x205486de, 0xdc78a7ce, 0x862b4b58, 0x696b5762, 0xd8604cc8, + 0xc9d552e7, 0xb7ae0e89, 0x900069c7, 0xf8ce2a38, 0x184f26ad, 0x134b0d5e, 0xd396a459, 0x703986fa, 0x683708a6, + 0x34c664e2, 0x466523d2, 0x43eead0b, 0xca0a563f, 0x52f079cb, 0xd9b7d1da, 0x5ed4a97b, 0x6d33c57f, 0xa9d8e5ea, + 0xb7f9f1d0, 0x3377a5dc, 0x8b170510, 0xbfa44b7b, 0xb2e1888d, 0x8ff4326d, 0xc24f6479, 0x7db699bc, 0x9680f79e, + 0xa1505090, 0xc52b0c3e, 0x26348729, 0x8b3bd170, 0xa7bb1c7b, 0x33522bb8, 0x15cbd19b, 0xc9e535ce, 0xaa3228a8, + 0xaf6ff232, 0xee75bf67, 0xb0712572, 0x43bd29a6, 0x540b520c, 0x9460d13a, 0x39ec4cb2, 0xe613ce81, 0x675e2d84, + 0xe95058e2, 0x8ffbedc8, 0xa492becb, 0x0408e4ba, 0x6245f6ea, 0xce488a5b, 0xfa9c9e69, 0xdfecb3cf, 0xebd35bc4, + 0x7f791eb1, 0x15bb631b, 0xff362d3f, 0x05bd7cbf, 0xd463526d, 0xc336b409, 0x317ffb1b, 0xe69a5584, 0xd1a38084, + 0xce09f1d0, 0x15704410, 0x6899d32c, 0xd79b19a2, 0x01b8bfb3, 0x7685155d, 0xacc24929, 0x51f7fa0c, 0x0f5af7e7, + 0x3d20b0b3, 0x9b404c72, 0x7a0f7839, 0x4cb3208e, 0x515766d9, 0x62969d1a, 0x31f97ff3, 0x4868bd15, 0x89927798, + 0xb1186352, 0x24263729, 0x0a732729, 0xfac40482, 0x53099824, 0x4f16e17f, 0x7d193dac, 0xd059fc06, 0x62570ed6, + 0x980f967d, 0x4080aba5, 0x523b54a7, 0xffdaa141, 0x29bc421f, 0xe6f644b4, 0x5d8ef7e0, 0x71880b4c, 0xe88769f5, + 0x0a7dd83b, 0x277bb62f, 0x1337546d, 0xf40217ae, 0xc4264f59, 0xae526fee, 0x18ad7cd0, 0xe0f52ebb, 0x0ed0792d, + 0xac51f652, 0x11edd575, 0xf60a1144, 0x44285825, 0x29c8d6d7, 0x6a4b4444, 0x0b5d7a84, 0x15038768, 0xaac2585b, + 0x8042046e, 0xc4f25392, 0xf737b5e9, 0xd03c328b, 0xfaa347a2, 0xbee72b30, 0x68616545, 0x472deb5f, 0x1bd24800, + 0xeb68733f, 0xd0dcc329, 0x8a96a291, 0x68bf5366, 0x232fb718, 0x0ce7c9e8, 0x0ab7c5e5, 0x0b610169, 0x608c1f4d, + 0x8825c646, 0x056b8f22, 0xf79696f4, 0xbc555233, 0x58d5b715, 0xe74171f8, 0x423bdd3d, 0x15ae88a8, 0xf46f0bc8, + 0xe2eb5511, 0x14b86583, 0xfae049c6, 0x5dffb14a, 0x73e2fc91, 0xc80ee347, 0xe49b427e, 0x863ad560, 0x6657c828, + 0xb4914445, 0x6a6ff590, 0x273841e2, 0x723e60d7, 0x57569486, 0xe57509eb, 0x524db2a1, 0x1f9dc3ed, 0xb7b4c863, + 0xba2da130, 0x3eb7fc35, 0xba9d8659, 0x2069c2c9, 0xf35e1953, 0x6d67a7eb, 0xade58952, 0x218206a9, 0xe70b5395, + 0xbcf6c798, 0xabf3d6e3, 0x7e1c89c7, 0x29f1d31f, 0x3563d5f8, 0x47b07a13, 0x1b0abdea, 0x8b2d2faf, 0x72c16091, + 0x70e0bc1d, 0xdb2cc2cd, 0xdb24883f, 0xf9534f55, 0x8291910f, 0xa741ce15, 0xcc04375e, 0x2f9522f1, 0x18fce5dc, + 0xf2227244, 0x1af3f08e, 0xf496b4a1, 0x0cf5baa7, 0x193c25c1, 0xfa3cda93, 0x6592db75, 0x9cdeaeee, 0xb0037a48, + 0x7ef6659d, 0x92d771b2, 0x97813122, 0xd108147c, 0x36f87294, 0x65fb1ad5, 0xf45e9f7e, 0x3211c3d6, 0x659dd441, + 0xe472d5c2, 0xf6c6c0c3, 0xcf96d414, 0xc5acf6ee, 0xcef3c13c, 0x6a2a1550, 0x728965b1, 0x7b599cc5, 0x295a1441, + 0x4027ca89, 0xb1b42b95, 0xafa18c0b, 0x4ad6e517, 0xa7a37003, 0x078ba7b0, 0x269df337, 0x7e4687d4, 0x6adf7f65, + 0x98dc9d43, 0x4a1c88ef, 0x18be8a84, 0x62ddcebb, 0x48fb4ba0, 0xbd3e840a, 0xa82fa9f0, 0x64eb6598, 0x2bbbf3c7, + 0x8e45e30d, 0x22fc305a, 0x33a76dc0, 0xfd599d96, 0xfa572a8b, 0x4ff99c07, 0xc310d6cf, 0xee9c9890, 0x5223a9cf, + 0x0cfbfcc0, 0xd17a66b0, 0x3ec8ecf9, 0x50924404, 0x567f1c9a, 0x81721be0, 0x969c643e, 0xfbecac45, 0x57e69070, + 0xd0d0f987, 0xdd521dc0, 0x8fc12c0b, 0x936a5314, 0x9821e02e, 0x1d29db6d, 0x64ecf046, 0xa4bf13fa, 0x32f31bab, + 0x3715684d, 0xf39f2663, 0xeb1a9519, 0xf79ef9d5, 0x4b7c9b87, 0xe06d3916, 0x84b9d734, 0x57189ad2, 0x5663e962, + 0x1be2a956, 0x1ed19c47, 0x17863314, 0x8bf507cd, 0xc4d29183, 0xc7d088a7, 0x78f6e38c, 0x79765705, 0x99eccb89, + 0xaa4d4723, 0x092a69ff, 0x81d17d52, 0x6d96567c, 0x4220b98c, 0x2a100878, 0x5d9b6877, 0xf59d8072, 0x88c8d223, + 0x27bb2f04, 0x67c97246, 0x23f696dc, 0x14db86e2, 0x8b0d5192, 0x3c2b7a7b, 0xb9d93372, 0x9d35ef5f, 0x479d6890, + 0xec14eed7, 0xad388082, 0x7dce6921, 0xcb1a601c, 0x36308482, 0xdc596578, 0x9db80d85, 0x6b749927, 0x21763e88, + 0x7872df7e, 0x4c55ff0b, 0xaf268469, 0x71797a1f, 0x2e9acd75, 0xd38042e1, 0x85f090b9, 0x0f194385, 0xf207e99e, + 0xa2c9af41, 0xe17e27f7, 0xeb46918f, 0x0bef0a6a, 0xaa938495, 0x7f9f1848, 0xcc789321, 0x41bf5f85, 0x03a178bd, + 0x78a03829, 0x8f90918f, 0xae031702, 0x7de6d549, 0x8882e526, 0x0d671582, 0x7a6f525a, 0x444dfaa5, 0xf307e976, + 0xbbb21059, 0x55497a9f, 0x86c863ab, 0x7cd74f50, 0x9201f32f, 0xe31af008, 0x5c4ad84a, 0xcf901068, 0xc48e598a, + 0x0ac21025, 0xea18d0a5, 0x6f6be198, 0xe17812b3, 0xf5424f9d, 0x44f5bda2, 0x305a5492, 0x0ac83d3f, 0xcd96555c, + 0x7e0d7870, 0x435f5a20, 0x667171a4, 0xe4529dd5, 0xd479bfbb, 0xdadb5b5b, 0x46d3641e, 0xf8e023b3, 0x2268ac44, + 0x58a9fff1, 0xf8ba9010, 0xb84fdbc3, 0x8179eaa1, 0x35008a61, 0x81d14dde, 0x038e5d8b, 0x9bb900ac, 0xbc16c746, + 0x925227ba, 0xf4834c53, 0x343b688c, 0x59375c94, 0x5d755a42, 0xc5edca49, 0x3b14ac24, 0xfdea9132, 0xc4f0bfe7, + 0x1b744b23, 0xc2c74c92, 0xe4948160, 0x769734b1, 0x48956fe9, 0x42c99a9e, 0x67558ecf, 0xd342b87f, 0xbe923d87, + 0x6cd9bd2c, 0x6082ba74, 0xc50be914, 0x6b6f980c, 0x45e3d005, 0x473816de, 0x11a9a97d, 0x4491b8bc, 0x09be9f85, + 0x51595ed1, 0xb032fcfb, 0x8a6b335f, 0x0f382a94, 0x37f87174, 0x05d7c2fd, 0x29d7a2d8, 0x321faa94, 0x407807d9, + 0x4f6c2806, 0x19b03ada, 0x730e1b9d, 0xcdaaccb8, 0x0fbf8fad, 0xb2484727, 0x12417349, 0xb1c2443f, 0x770c4383, + 0x50be0677, 0x88b4562a, 0x228f233f, 0xc55b9f18, 0xd5412fe7, 0x567c0737, 0x501fa8df, 0x750e4708, 0x3bbda5d6, + 0x135a00a6, 0x72cdbb0c, 0x24df2645, 0xf84f37ff, 0x343363cc, 0x91ead32a, 0xa160e5d5, 0xc0400810, 0x96a3ec32, + 0x96e09cef, 0x6d382bbf, 0xf21f33c5, 0x20a9b5db, 0x63ebfe30, 0xad0af649, 0x4b6cef98, 0x2275c536, 0x9f08191f, + 0x401d35a2, 0xfe5e130b, 0xcb598f10, 0xe7e0796e, 0x144980a5, 0x29a557f3, 0x790aa646, 0x53751404, 0xa8c22da2, + 0x33d353db, 0x68313a0a, 0x02590def, 0x7870c800, 0x9b5db86c, 0x0fac56f9, 0xb2446d54, 0x9d4509bb, 0x92a97cdb, + 0xc6f8dbc7, 0xa684a548, 0x5c59a996, 0x98d7bddd, 0x1bcd9df8, 0x17f969ac, 0xea49e176, 0x945da242, 0x3cb43290, + 0xc39f0f88, 0xe34e3dbc, 0x7711d688, 0x6766ec15, 0x5af759d0, 0x2883b5b5, 0xacee6eb9, 0x9e7ff3ca, 0x1a0d7362, + 0x82526236, 0x127a82eb, 0xd70e5533, 0xa300f7ec, 0x9a265646, 0x4087c546, 0xbd6764d9, 0x4d0ca6ad, 0x1c1ee5de, + 0xbb736489, 0xba9f670c, 0xae16aec1, 0x13d4a66b, 0x11c0da1f, 0xf3263dab, 0xa8b1bb8e, 0x802b1082, 0x670b1825, + 0x90ffe5d5, 0x0c4b651d, 0x90bff6e9, 0x6254b0de, 0x4ba7405a, 0xa69aa6a3, 0xd0329a49, 0x84d3d7d8, 0xd09daa44, + 0x027e50c8, 0x1ed450e5, 0x22cf8032, 0x4d25b768, 0xbd1d0f33, 0x259d74e7, 0xcf5d0d1f, 0x15b751b7, 0x2b0fb2b8, + 0xfcfa4517, 0xb0faf290, 0x1e347dd5, 0x74d23e73, 0x43d3b17d, 0xb85bc447, 0x0643af53, 0x3b9fc175, 0x866612aa, + 0x754fda09, 0xb3a8f071, 0xd0910a8c, 0xe9756396, 0x50be5589, 0x52b9e6de, 0x76252d6b, 0x617a390f, 0x6625709f, + 0xb2a510e1, 0x28a6cc57, 0x1df39f14, 0xdada0dd1, 0x9709eaa7, 0x694774e5, 0xf3534cdd, 0xbe96597c, 0x6a94d66e, + 0xb412640a, 0x8b8d19bd, 0xd02ab847, 0x5325b7f6, 0x97cb0068, 0xeb800ae9, 0x1afe9a93, 0x56bc2d21, 0x4acde6f4, + 0x097fe2a8, 0x258d6748, 0xf6bd72f8, 0xd6013bf2, 0x5ef5d066, 0xd829e966, 0x12d10040, 0xfe2ae200, 0x19d486ba, + 0xd406ffd2, 0xe9ba56c2, 0x6bf72aec, 0x566ac050, 0xfecbbf71, 0x45f1d7f2, 0xaa0a9af6, 0x65c5211d, 0x5e79b1de, + 0x1cd5f850, 0xfdb45b2a, 0x574cbea8, 0x22010fef, 0xd33917c1, 0xad3fcf27, 0x40b21597, 0xef52bf3c, 0xe09575f8, + 0x1b5243eb, 0xf70fb199, 0xc2d16563, 0xd5f79f73, 0x6867222b, 0x7b3f991a, 0xc452fb4b, 0x18c02e08, 0x20178d34, + 0xb4a9ca4b, 0x36c65c87, 0xac261312, 0x25e576c3, 0xaaa5a599, 0xb93ec303, 0xede2687a, 0x0e51d853, 0xdd21fb01, + 0x6bdb57cd, 0x6f667778, 0xdfeaf4cf, 0x56ddf6dd, 0x83262b05, 0xe25893c2, 0xc1963a33, 0x651b6f22, 0x7d5a0144, + 0x9bde8e96, 0xb1735182, 0x65b2dfa0, 0x094bc31b, 0xbf4f58ea, 0x2708acd0, 0x12004c02, 0x56e90a1e, 0x6e5642ae, + 0xed38f466, 0x1be34c66, 0x2665537f, 0x5e4504e3, 0x31aad240, 0x0ee65485, 0x343fb8b0, 0xcdc2a950, 0x46df16be, + 0xa7232a98, 0xca0355a7, 0x557c679e, 0x5f384fb7, 0xefbd63ce, 0x06d3c58e, 0x9868925a, 0x2908577f, 0xcb515219, + 0x72fa947b, 0xcda15c8e, 0xa1f6475b, 0x83f4c173, 0xab4f8986, 0x03dd24f9, 0xf7de7c27, 0xb4425e77, 0x5cd1297e, + 0x42de169b, 0x813330f4, 0x1b49b7f3, 0x8f1178d9, 0xd61c6d19, 0xa31d018c, 0xc25a3526, 0x55afa6c9, 0x29fb3e17, + 0xda4055dc, 0xfa76587f, 0x23e266c8, 0xc33ac1e7, 0x98be8361, 0x694bd8a6, 0xf21bb036, 0x82e64ba8, 0xd629fe44, + 0x35f8148d, 0xa6029e42, 0xd0c70ccf, 0xbf67f9fa, 0x2342761e, 0x02a26725, 0x37a9c706, 0x8d54eb0d, 0x96219523, + 0xc5a3f7b7, 0xbc8196ca, 0xac6ee261, 0x714bfe10, 0x4d7f0308, 0x1e60d556, 0x2ef55297, 0xef2f9224, 0x8c8e2f7f, + 0x211a1b0b, 0x82f17f51, 0x1d90fd23, 0xe17d223e, 0xc5d33723, 0x1f2850a8, 0x3eb45f61, 0x6c3478cf, 0xad2e8831, + 0xfbe946b6, 0x92593217, 0x087042a3, 0x609b2c63, 0xd396ea56, 0x67e2018d, 0x01cfbf57, 0xe6c0a6f0, 0x7643f92e, + 0xff209199, 0x23d8b549, 0xb936c38f, 0x5827ce5e, 0x8f4fe3ee, 0xe022eb2f, 0xd63aaabd, 0x0619c345, 0x04c4f93b, + 0x487196fa, 0x4b416705, 0x150f718a, 0x12882453, 0x23901725, 0xccdf8d6d, 0x79008641, 0x536221c5, 0x3aa6d0ce, + 0x411f7f47, 0x24b84c7b, 0x3a807480, 0xfbffe49b, 0x5849f4a8, 0x3f1abb9b, 0x825b355c, 0xe977b9ec, 0x076daf5b, + 0xac932445, 0xb84271b5, 0xe7f9dca4, 0x070246cb, 0x74ed7460, 0x4c6e4d10, 0x9a337f97, 0x30ef64f9, 0x030e764e, + 0xb08a4285, 0x747a229c, 0xe3ac56ea, 0x673de1ca, 0xb71b0504, 0xf3571b00, 0x0031e67f, 0x0ff66209, 0x828a52c9, + 0x865c3b7a, 0x3e24ed20, 0xf99a5a65, 0xfe6ce68b, 0x6ef32c02, 0xea4feab7, 0x90af3125, 0xdf796e86, 0xba68524b, + 0x177c60d6, 0x193a1662, 0x14b6fb19, 0x5dc1b7a1, 0xee0c4d28, 0x14c9b65d, 0x8a79d3e1, 0x17738175, 0x87dcbc0a, + 0x5d61d1fe, 0x36a71ff1, 0x3fd5fdcc, 0x50701425, 0xa3ef25dd, 0x38f0fafd, 0x59ec5839, 0x464b4045, 0x40563a4b, + 0x2b0b42a7, 0xb1ff41cd, 0xf2fb4b23, 0x01dc2790, 0xec174033, 0x9db78be1, 0xfd0bf049, 0x636e7d24, 0x226d3a99, + 0x1a7f30c6, 0xc44d7402, 0xa096e9f5, 0x1ae01c3e, 0xc8dfca1d, 0x2fd43933, 0x93a3456d, 0x710cdb63, 0x0d5dc7b8, + 0xf6f86d9c, 0x268824cc, 0x7d0839dd, 0x2e8555d7, 0x1013d3d5, 0x9a592581, 0x73014b94, 0x8abd68f7, 0x686ea1e9, + 0x052fc39b, 0x069a742b, 0xbf4242df, 0x9619016d, 0x6543e841, 0x18358c2e, 0xfc05fef6, 0x1f1d005b, 0xf81cf0c9, + 0xed52a93e, 0xd719d0f8, 0x472c8c2f, 0x364b5931, 0x5160b02d, 0x09cb741e, 0x99039a3a, 0x1b5d17c9, 0x0f0e0894, + 0xcd82f03b, 0xe18a5497, 0xc0ed709a, 0x9a1a628d, 0x94cde1f2, 0x70a50e8b, 0xbd0e7586, 0xf63f7dcf, 0x398f128e, + 0x91c91a98, 0xfb37240f, 0xf9e7aec1, 0x08cf48f5, 0x3c9f394d, 0x0dd22fea, 0xac21fd60, 0x7103276e, 0xa2329b05, + 0xedd6d903, 0x83f5cd05, 0xdae5f7ab, 0x5b75c7d1, 0x0cc89ad8, 0xdfef3c75, 0xd8ee6e8f, 0xbf33ee00, 0x6770ece0, + 0x5a6ac8ec, 0x98c953a4, 0xb2fbf0c3, 0xe5193450, 0x5b6c9bf9, 0x2f33402a, 0xf70f3fed, 0x05f9d01c, 0xd9bd7507, + 0x5e3471a9, 0x94171e25, 0xc17bc479, 0x4fc8d8ee, 0x173cf2f8, 0x9acc7d5a, 0x772df7d8, 0x13a85817, 0x34e9dad5, + 0x512ba4fd, 0x1a0e79c5, 0xcc4fb5cf, 0xc03f3e58, 0x49d4089f, 0x5eba57b5, 0xcb8b9001, 0x4cd7e284, 0xfc545c7e, + 0xfd36789c, 0x2520d8d1, 0x6ec7b248, 0x102528bf, 0xa2e8841f, 0xe76f7eeb, 0x281c0251, 0x566d6e53, 0x1f6b7aa2, + 0xdcd1ae4d, 0x09dde320, 0x9cb330ea, 0xa1cd16e1, 0xee0447ab, 0x750ef482, 0x7c5d627e, 0xc6541617, 0x971d39d9, + 0xf68147e0, 0x8d2391dc, 0xfbed2a8c, 0x3e1e1a5e, 0xdbcbf3b9, 0x41c6f5c9, 0xe9292a93, 0x82c56415, 0x5211e2cf, + 0xa1c2081a, 0x0e2d6f12, 0x2e00d230, 0x56898ff8, 0x948bafea, 0x2d4a4d67, 0x8d43693c, 0x682ab5d0, 0x7be37d25, + 0xa68502c7, 0xe704a5c5, 0x208660c8, 0xafec786e, 0xab6d157c, 0x4825fe59, 0xbfe180fd, 0x2c7061dc, 0x25aee88d, + 0xd7e0f21e, 0xa81fa247, 0x5825db46, 0xaf3157b8, 0x56de0739, 0xd0f5842d, 0x1d6e3e45, 0x0d58ff59, 0xaa96b14d, + 0x93b41ced, 0x0fe52e3d, 0x2be5b43b, 0x49502215, 0xaa2ea464, 0xb37bcda7, 0x463e112c, 0xd9c87203, 0xc6b9f4c5, + 0xb1c81c17, 0x0d681f64, 0xd9ad60ce, 0xc24ba1cb, 0x3966b652, 0x7ed288ba, 0x831b610c, 0x140f8eb1, 0xae49e6b8, + 0x36b6f1f6, 0x3f5cc636, 0x31ccf6e7, 0x6bcaa4c8, 0x1e26a414, 0x3dc4139f, 0x613199c2, 0xda6521d5, 0x43fe1d06, + 0xae006406, 0xd2f5a430, 0x22683b2b, 0x5f7798d1, 0xa66746ae, 0x18b74d59, 0x2ab79f0d, 0x7a491751, 0x3d662e58, + 0xe6fb4e9c, 0x4cb1b125, 0xade70cee, 0xb7fc1d4b, 0x724da84e, 0x117e0abe, 0xa2667dc2, 0x07b4c5d9, 0x1407ac31, + 0x3864b82e, 0x0d8dbd34, 0x5c900efb, 0x8132d062, 0xddd5e44f, 0x5beece7d, 0xc701e40d, 0x7b7f5b81, 0x0498b3db, + 0x04841dcc, 0x8ce80c23, 0xbc84dcf1, 0x51c8b7be, 0x56069def, 0xd46c2057, 0x1970fb24, 0x952d946b, 0x38250704, + 0x8abf36b7, 0x8bab8a6b, 0xc03fabb5, 0x97c5f49e, 0x6d82de09, 0x8a2556cd, 0x2964516a, 0x6890e307, 0xcba0b74a, + 0xd38b1a70, 0x1d6c1a5f, 0x7f6d10b8, 0xd83849bd, 0x7f662b49, 0x26193663, 0xf167f48e, 0xb9389f67, 0xb07975b6, + 0xd288dafb, 0xd46de0b5, 0x38ab1f6d, 0x3869163f, 0xb398d136, 0xa09b7627, 0x90a2ba68, 0xeb4ce77a, 0x6d64e798, + 0x8b55feed, 0xe95d691d, 0x960aff97, 0x88ac1178, 0x8917851d, 0x7a6f6c33, 0xee25f04f, 0xf2fa9037, 0x2ce57111, + 0x8d04c27e, 0x9550a463, 0x854ec4dc, 0xb1128b1b, 0x47b71b56, 0xb05ea614, 0xfe8b23c0, 0xb2986f50, 0x353058c4, + 0x717677da, 0xe5881926, 0x28427daf, 0x5c2561be, 0x73b8246e, 0xb59936d2, 0x53f92184, 0x29367208, 0x7d1a2efd, + 0xd728954d, 0xe150647b, 0x90f5c605, 0x5ccfe6b2, 0x6e911593, 0x0271c529, 0xcca85d01, 0xc7a01bde, 0x63711af8, + 0x3efad20f, 0xdb15646e, 0xda681717, 0x6e2a3585, 0x0aa2feb5, 0xf19d76cb, 0x5b72d7a3, 0x39435f8a, 0x1cc9fb0f, + 0x9fdecb00, 0x552c7cfe, 0x6b249adf, 0x9ef08834, 0x8cd32d83, 0xb6a0c382, 0xa9e5765b, 0xd7d3459e, 0xcda328b8, + 0x61081772, 0x9a5e6b67, 0x58a81115, 0x400ca83d, 0x7b825a8b, 0xbfb8957c, 0xe389bd92, 0x86ddbbc1, 0xd182a50b, + 0x686fea85, 0xc4bff967, 0x79ffcbeb, 0xe74b24b1, 0x94bf06e0, 0x449fecab, 0x0dab055b, 0x0de539bc, 0xf943c769, + 0x7bd6b0d6, 0x39ed8066, 0x9cb614b1, 0xcdf72aa9, 0x39caaf12, 0xf65308bf, 0xacae3812, 0x2b6adb70, 0x6943a7a3, + 0x9820ddfb, 0x6080e7db, 0xae44dc22, 0x626996ad, 0xf23ef43c, 0xa1194baf, 0x972c41f1, 0x40760919, 0xa2e98825, + 0xc474463e, 0x1f06d0c5, 0xa7996e08, 0x476ecc2d, 0x4cf82192, 0x7bdc4a48, 0xba03da0c, 0xa7f42fec, 0x68c0921b, + 0x8c22d462, 0xe49aacaf, 0xc24cfbb5, 0x8522f3db, 0xe7882333, 0x7353a6d9, 0x9890dec0, 0xc916ae17, 0x844d9a78, + 0xf335dc21, 0x404f7d90, 0xf01f720e, 0xd19909f9, 0xb985722c, 0xc74e6313, 0xd31da329, 0x54220eba, 0x3d2b78e8, + 0x987cb6a2, 0x90c8b6ed, 0x62ab5227, 0x2696e01a, 0xc05d4702, 0x044e446d, 0xb55ebaab, 0xc5d82b9c, 0x416401fd, + 0x4271ebb8, 0x605d2e22, 0xef58537d, 0xdadba6c5, 0xbb3fc621, 0xbfe6ad55, 0x682d88b7, 0x412b3f35, 0x2ae7329a, + 0x4ea10a2e, 0xc2907b21, 0xcb415bce, 0xc0101739, 0x5b0535a7, 0x07ccc7c8, 0x813471bc, 0x34d475ef, 0x555bfe11, + 0x05881fcf, 0xdc91ee82, 0xed7fac2a, 0xa00a3ca1, 0x2f8e4490, 0xf07f2ce9, 0xf89ca3b3, 0x0d71ae0d, 0x2e053fbf, + 0x5f55a160, 0x3d819f3c, 0x3a6bf50c, 0xb164b979, 0x926cb146, 0x920f1b31, 0x9011f858, 0xe1df91d1, 0x5af4ade3, + 0x67018581, 0x43a0c137, 0xeb31eaac, 0x6393462d, 0x0e0d3e48, 0xc8b9b13d, 0x065a78b6, 0xd8bd0be4, 0xd05cd0fd, + 0x1b66938a, 0xf373e17c, 0x1e72f710, 0xb0ebe79f, 0xb9fb9385, 0x0165a71a, 0xdd17f77a, 0x6fa68fe2, 0x1a1345b4, + 0x770845cb, 0x1213a496, 0x3a1106f4, 0x7cf05513, 0x5b8ed013, 0x17c1737c, 0xbe381497, 0x357589ec, 0xbe2d1dfe, + 0xe6efd8a4, 0xbc22f025, 0x98cf0bae, 0x7f45963e, 0xe32d5263, 0xdd70ab3c, 0xc179e860, 0x44dea630, 0x6b5f52d8, + 0xe6067337, 0xcb75264b, 0xcd1b8cdc, 0xb21ebb69, 0xdef8375d, 0x7d3a02c7, 0xeca4251a, 0xd0c07259, 0x54aa28af, + 0x0c2c43fe, 0xd5ffb543, 0x83466620, 0xe916b334, 0xb014762a, 0x2eb32f13, 0x3da8b333, 0xec952a6d, 0xd3e6cae9, + 0x5455a015, 0xb431cb08, 0xc388d1fd, 0xbda5918f, 0x708edf44, 0xf354e983, 0x9786e88b, 0xad5fddb4, 0xe85ec69a, + 0x6b8211f4, 0xfd4e2b31, 0x76699c92, 0x7c980b34, 0xe9b84676, 0x0a9de947, 0xbf8f6c6b, 0xfa67042c, 0xa9e4af00, + 0xa526d808, 0x26dae5fc, 0xe1b33af1, 0x41e12b06, 0x8385f830, 0xd9ffdbf1, 0x33de4866, 0xd05fc738, 0x90f951aa, + 0x77af3fba, 0xb6453b75, 0xfd51af1f, 0x1db097ad, 0x95f62720, 0x931ec5e2, 0x173f3163, 0x29b27b96, 0xaabcc422, + 0x69ca096f, 0x77c5caaa, 0x6c21cb5f, 0xb36556a0, 0x18b7f90b, 0x8bc2d076, 0x82ab473c, 0x12926504, 0x8d579bfd, + 0xbf62234b, 0xa85b7006, 0x90a64e17, 0x59fac39e, 0x91735bc6, 0x24b1f0e5, 0xabe9ff09, 0xee46dc59, 0x774a5e7a, + 0xf8f55361, 0x9e592c0f, 0x3593c0d3, 0xf9cb9c2d, 0x79885577, 0x4d8dddac, 0x7e03c0fa, 0x2e94037f, 0x01d8d15a, + 0xc7975d52, 0xe7e6c638, 0xa8617ff6, 0x81725647, 0x926e19fb, 0x149cc412, 0x3c101388, 0x517691ce, 0xaa40aec8, + 0x3a0c471d, 0x802b26f2, 0x7635ef73, 0x0b10ef93, 0xe0258adf, 0xf74ee01d, 0x22abb254, 0xda17d768, 0xc68426d7, + 0xb2e3da36, 0xe393de05, 0x492f7519, 0xac784f2b, 0x208fd1fc, 0xb580c115, 0x78cd3d8c, 0x266bdc3c, 0xfe0dd2ad, + 0x318fde56, 0xc772cead, 0xaec51773, 0x45e78093, 0x869ace0f, 0xab91c3e6, 0x3e6271d8, 0xe77b31c2, 0x23f79ada, + 0x16ff266d, 0xc7fa7a92, 0x32b6224e, 0x62242d54, 0x5143e8d7, 0xbf4278c7, 0xcb6a6318, 0xa38c93bb, 0xb2f4719d, + 0x6f530a2c, 0x8ceab65d, 0xc0305908, 0xd852e8b6, 0x0a5e238a, 0x7a82bc89, 0x8cc7ae9a, 0xfdd32333, 0xd4b44b0b, + 0xf05fa1fa, 0xc0052e22, 0xb3001244, 0xcfebe4af, 0xbd5fc2c0, 0x351997ae, 0x54c8ef7a, 0xc87969a9, 0x790419aa, + 0xdb1a6f8f, 0x137d9987, 0x2882db5c, 0x6f4a0d07, 0x1282a26c, 0x2b4d7d20, 0x16fadb51, 0x7fae643d, 0x43df3e86, + 0xe3684f02, 0xed5ad056, 0xb3b79fb8, 0x2bccf0b2, 0xa5627c17, 0x5d781dcf, 0x3eac4b0d, 0xabd231fa, 0xb898976c, + 0x86ad4cb5, 0xea8f4a81, 0x83ab512a, 0x5ca1c8af, 0x134275ea, 0x5f23db49, 0x0e52c300, 0x8e578a58, 0xaf347c46, + 0xc78c8199, 0xe93e7cb5, 0xb07aa76f, 0xa044fa54, 0x3df8f34a, 0x83763d16, 0x3f19136e, 0x8d5de15b, 0xfe8a78ae, + 0x020bd1da, 0x745b8152, 0xe1580cac, 0xf0e785e2, 0x0007b3e0, 0xdd52bb6d, 0x08b23e5f, 0x8673343f, 0x49496715, + 0x01e9220e, 0xd855f35d, 0x474d264d, 0x65a41ece, 0x51947370, 0xbc472052, 0x841fcb21, 0x60b5cce0, 0x9702f92b, + 0xc7c107cd, 0xeb9d06a3, 0xed500857, 0xc2a4cbcc, 0xccfc0bfe, 0xe3fbe267, 0xc7f57797, 0x688c0753, 0x8c9d5f45, + 0xc18dd268, 0x289b9ff3, 0xbb1393c7, 0x082f6812, 0xbe5d1152, 0x45703851, 0xf481d7c3, 0x69d77497, 0xf6f9c149, + 0xf2193ecc, 0x883ca40e, 0xeb67ad30, 0x0e689c4d, 0xe3830c17, 0x9e5eeae8, 0xaf33538b, 0x4a5dfb32, 0x6d57669a, + 0xd2051b10, 0x17ff27e2, 0x2288b812, 0x4eea0107, 0x3b3279d0, 0x40ed3be1, 0xb7c650ee, 0x99dde03d, 0xbb9ae24d, + 0x30320c27, 0x49375deb, 0xa8a265ef, 0xf0279f85, 0x512a5940, 0x8c592965, 0x439a82fa, 0xfc74a94f, 0x32b51f70, + 0xb20c7db0, 0x0276f4d7, 0xaf3b2569, 0x82017ff6, 0x7701689a, 0x22f38984, 0x1ce87950, 0x7283ea69, 0x0f523287, + 0x3bf33e2e, 0xc2757300, 0x3128839f, 0xba274310, 0x97a7e3be, 0x1fd1c51f, 0xbf339475, 0xb3a89e66, 0xd649586a, + 0x1419f9b5, 0x792f8616, 0x74937c3c, 0xc421c942, 0xd95955fd, 0x218e83e1, 0x49eefe11, 0x7fd5ae1f, 0xc43219a7, + 0xe9ba1661, 0xe92d608f, 0x54e979df, 0xebb4a72d, 0xaa08dacd, 0x224b96b2, 0x9e431b45, 0x275685ca, 0x36fad64e, + 0x1b0d4dab, 0x1e68d91b, 0x05e57104, 0xdba0781f, 0xe2a83db2, 0xbad95bc6, 0x86ed3535, 0x2238347d, 0xac046283, + 0x3df03f8e, 0xa5572280, 0x3b96642a, 0x7573ee3c, 0x37e7ce92, 0xa60d779f, 0x5863ad97, 0x644923e3, 0xbdc197c8, + 0x14142d85, 0xd6c2e146, 0x12a4443f, 0xf77c00e5, 0x6e0bbd0a, 0x26124499, 0xcda68359, 0x3f76a250, 0x4d0974f4, + 0x2006a3df, 0x3b73e1ca, 0x11b6421c, 0x87136a5f, 0x62e9c9da, 0x2b350731, 0x56837655, 0x97c33225, 0xfaf25744, + 0x9a534ec9, 0xa80cbf7a, 0xb61f12e7, 0x1f7bd551, 0x75a8204b, 0x9f18299c, 0x306f7653, 0x856553bf, 0x20834ed8, + 0x8f8017e4, 0xb0245dbb, 0x73a8d317, 0x1cfeddc4, 0x5bb791b4, 0x6f75aa6f, 0xc80fadac, 0x74f6b3c7, 0x40584950, + 0xe4c193e3, 0x0688bd52, 0xc3aebd8f, 0x8363414b, 0x076ed608, 0x761f279a, 0x15369963, 0xe64088d2, 0xc54041db, + 0x3e3f8b2f, 0x16bde14e, 0x40c459be, 0xa726d92a, 0x78f363a8, 0xb1341961, 0xc6366d2c, 0x9c452957, 0x9ddab922, + 0x134c4c4e, 0x90643255, 0xb1634c3e, 0x3faf7b80, 0x09daef5e, 0x12eb2571, 0x273d2e3b, 0x8fb84360, 0x2543f8eb, + 0xde5897b2, 0x3337e594, 0x9305cc80, 0x56e037fb, 0x2ba6f6b2, 0x66840b1a, 0xad55555b, 0xe07b231a, 0x47654ee3, + 0x6f3431b5, 0xb2a5db16, 0x9dbdc92e, 0x1e2d4b96, 0x34a52d04, 0xd2579323, 0x95bd7dad, 0x0044b594, 0x7b227dfe, + 0xb5e710d9, 0xbd693a9c, 0x5696bcc6, 0x93ecd9ca, 0x1690512a, 0x78402677, 0x9c744406, 0xf058ffab, 0xccf5295a, + 0x1b148310, 0x6961f10d, 0x74021696, 0x7a2d5e49, 0xd4af088b, 0x9c1967e4, 0xf9582967, 0x3e6f4c61, 0x7ac48dfb, + 0x30500207, 0xe5dc5e89, 0x384a0ac1, 0x036a2a28, 0x7c2beca8, 0x72fb2c7c, 0x4b43133a, 0xb97abb2a, 0xf7c171ff, + 0x9448ed5f, 0x4be098a7, 0x438995a2, 0xf75d36bc, 0x80cd8e4d, 0x1d9f6f8f, 0xf2231202, 0x0ffc48e5, 0xcc3599e3, + 0xbc39f044, 0x88d60828, 0x9dee8591, 0x34579796, 0x34454dfb, 0x919d2be3, 0x37dcbc16, 0x2bde953c, 0xf76599a2, + 0x751fdc1d, 0x0c071061, 0xa1c93269, 0x7ac57b24, 0xea51f230, 0xa94bde05, 0x63e34407, 0xa6d39844, 0xf021b840, + 0xa64c8231, 0x5290bedc, 0x9d3941d6, 0xa8521397, 0xd279a0f9, 0x86d4bef4, 0x92608f18, 0x6511290e, 0xc66b1957, + 0x7fe40eba, 0x9e261c7d, 0x0a675d77, 0x13bff344, 0x8c2456e4, 0x11b4f022, 0xd6090669, 0xae09d7f0, 0x3e449421, + 0x77b056d8, 0x335bbb0a, 0x3a6ddac8, 0xa9d8cb2b, 0x23a7c05d, 0x1c10e006, 0xccbc2e37, 0xf1e1f6b7, 0x459d938d, + 0x28a6336f, 0x4b7025d6, 0xe371e10a, 0x206c2a55, 0x134fd109, 0xdd293a05, 0x795b4006, 0xab453e10, 0x353754be, + 0x06b21fe7, 0xff0a4f20, 0x2753e543, 0xb0334614, 0x9e83317d, 0xd7d545fa, 0x1d1afb79, 0xf9ba1ddb, 0x92470eaa, + 0x8f599ee2, 0x9342b2c5, 0x36d666fe, 0xdb8a0b52, 0x8a33a7cd, 0xbcbd3536, 0x5c79bec9, 0xe6ea07ab, 0x106b04ba, + 0x0adba63f, 0x899e2e20, 0x61309cfe, 0x75cb546e, 0x7e6024d2, 0xffd7403f, 0xec1cb01b, 0xfc94496a, 0x11e58c36, + 0x06d1f0a3, 0xd4b05ffa, 0xfb5964ec, 0xd02c19f3, 0xfc8a4efa, 0xd9a33199, 0x9e71e564, 0x3c3c1cb3, 0x8ebdfec6, + 0x547e14bc, 0xa57b997c, 0xf97467b3, 0xa1cd6c97, 0x25fc2fce, 0xbeb05021, 0xa8aa5278, 0x936ff6e9, 0x25257555, + 0x0ac0c33a, 0x94a5ed00, 0xb6f6301c, 0x61ae72c1, 0x3d4aafaf, 0xedbc9d85, 0x0cd50474, 0xcef74dfe, 0xad609d48, + 0xf88b532d, 0xf7816a76, 0x92489bcf, 0xaf2fd5c9, 0x73064eda, 0x2736b407, 0xda75cac1, 0x9f94e099, 0x5321d394, + 0x801b2e93, 0x3062ff5e, 0x71ad89cd, 0xffaab977, 0x70ed475f, 0x05926f0d, 0x8368bf36, 0x67523ccc, 0xbb02c441, + 0x72e3b19c, 0xf57eccbc, 0xee21aa56, 0xaacd4ecf, 0x49df3c9c, 0xe5b30a57, 0x2f85f17d, 0xcaaa8372, 0xf9ddcb7b, + 0x0ba62e58, 0xd6e92742, 0x9c63e548, 0x974aac79, 0x0fb73982, 0x3c33e233, 0x45d39b65, 0x5321dece, 0x10e8ca82, + 0x6fa1c683, 0xaee4806e, 0x13daccd6, 0x432d0b07, 0x88c42fb5, 0x3806b477, 0xea9efb6f, 0x87d6c37a, 0xfff6adc6, + 0x74f20ed0, 0x30ae9c50, 0x9703a8e3, 0x04c2f03a, 0x43d94e36, 0x62babcd4, 0x69512a43, 0x7c48897c, 0xfc517259, + 0xfa11f32f, 0x5d6d164c, 0x3fe3edd1, 0x016cc586, 0xdfd053a3, 0x9d9e3b3f, 0x2354b895, 0xc552e0f7, 0xba919c95, + 0x379d5420, 0x32f42d7e, 0x0198a074, 0xaa2407c4, 0x6be17a05, 0x61cd926f, 0xbb951c88, 0xfbd5e58b, 0x6429d6d5, + 0xb2579363, 0x40afee8c, 0x4a38f3cb, 0xccdd1ec8, 0xc8d09144, 0x888e953d, 0x6d590b18, 0x36b0175d, 0x628e548d, + 0x4a679d61, 0x69d1da77, 0x3ebaabfb, 0x834973c7, 0x671308d3, 0xd75131f2, 0x4874415e, 0xd659e091, 0x9ef6448d, + 0x25f296c5, 0x4b5aa6bf, 0x8eeafa21, 0xdcc8b1c3, 0x46cbf099, 0xa4ea9d12, 0x418a2906, 0x3ad4e66d, 0x8343d68b, + 0xba7021dd, 0x952a0a29, 0x2dc69de4, 0xc6f3d6c4, 0xd1feff7a, 0x23c476bb, 0x041f056e, 0xe84884fd, 0x65690eac, + 0x0165c5c8, 0x121bba88, 0xb9f35405, 0xb950da05, 0x853f000e, 0x10a2a8ab, 0x8737b5a5, 0x37626ed2, 0xa2f230dc, + 0xc01eda4c, 0x6aa7d33f, 0x9a3986a7, 0x934a7c34, 0x07554fc9, 0xbd086a96, 0xbffd6d0e, 0x6bdf3914, 0x6290a44c, + 0x89122b4c, 0xe3d28b64, 0x29b38156, 0xef09523b, 0x79a22a8f, 0xf16694dc, 0x9ef6db59, 0xc432dc28, 0x47169ef6, + 0x00f2c031, 0x93c3668c, 0xe8204865, 0x856e6001, 0x66a76386, 0xbd5ca973, 0x4bd14835, 0x3535c98b, 0x86fe6064, + 0x382f1edb, 0x25985b74, 0x471536ee, 0xb3aa9969, 0xf9e487f3, 0xc6630473, 0x52b39937, 0xeebef9c5, 0x8dbad903, + 0xb3bb7602, 0xd026de23, 0x8a4f5abf, 0x4a0e5b97, 0x6089fab0, 0xd5d46e9c, 0x4b622bff, 0xe57caadb, 0xb8525887, + 0x20e52af8, 0x782be374, 0x86fb4f87, 0xf7aebd85, 0x5c7cb816, 0xf88e841f, 0x58acb3c1, 0x09ed99a2, 0xd20ebb22, + 0xf12f594a, 0xa32f2349, 0x0b5729e7, 0x492027a3, 0xde2c78dd, 0x4bea3140, 0x9d1b1b20, 0xd438fc61, 0xaa4088ca, + 0xbc822a14, 0xd6c932b7, 0x7f186ee3, 0x900d1a56, 0xb189cd9c, 0x77678463, 0x67356c48, 0xa65f9c62, 0x26fb2f51, + 0x03780115, 0x7ab933ac, 0x3041f139, 0x2429f101, 0xce26320a, 0x264cc50e, 0x778639d0, 0x45946ad3, 0x7d69f922, + 0x46380b21, 0xc2f02202, 0x3d7fa1c2, 0x7c25f6e2, 0xe97e8c45, 0x10f9883d, 0x43e1b7b2, 0x924e5b07, 0x2fb0e877, + 0x76d6800c, 0x16f4ed20, 0x51868af6, 0xafc9164c, 0xa3d19062, 0xa26cd4a6, 0xdefc45a4, 0xd5f293c0, 0xf9a867b4, + 0x035afb31, 0x02970c00, 0xe3b82aad, 0xcf91ae16, 0x320bd0f0, 0x421e1c3d, 0x851c4da0, 0x72db4790, 0xd16fac11, + 0x9087868c, 0x2c11d857, 0xfb6ac1bf, 0xa490541e, 0xf8eb5546, 0xb91e3d0c, 0x702a55a8, 0xad82a78f, 0x039a161c, + 0x96e30714, 0x95d2f5a1, 0x68964421, 0x196c5061, 0x7cfd26f3, 0x472d2880, 0xbedce43c, 0xec32b094, 0x19825e0d, + 0x8b395454, 0x9fdadbb8, 0xebe987d8, 0x52b893bb, 0x95946eaa, 0x68f76b56, 0x1500bcb6, 0x98f88696, 0x3f40ecce, + 0xf57d4c6f, 0xf18f8d94, 0xa8ae9e2a, 0x90b29e19, 0x585be992, 0x3aa1ff13, 0xc28c8739, 0x7f2c0eb5, 0xd8172d7b, + 0xad7881e1, 0xfde065dd, 0xe800e1ed, 0x3e5c132a, 0x24917e45, 0x8d7320da, 0x691a5b79, 0xc6ca529b, 0xc54d67aa, + 0x19d56c10, 0xedf989d7, 0xb4f8fa6d, 0x16e2a9c0, 0xe2ea1fb3, 0x325cf4ec, 0x21339fb3, 0x0a86995d, 0xcf8c4aac, + 0x73edbb4b, 0xb4b5de1c, 0x5c7f194a, 0x4dec94fa, 0xdc055a7b, 0x954a1eb4, 0x2d552cb4, 0xf43642ec, 0x03929e40, + 0xca673dd3, 0xb75df576, 0x51fe19ed, 0x701a7a6b, 0x37b8b311, 0x9063ce27, 0x56cf63d9, 0x847cf6a8, 0x35396e53, + 0x14183807, 0x4630cbde, 0xa302b00d, 0xf6622ef8, 0x8aaea861, 0x7a69bdb0, 0xcc94405d, 0x48b4899c, 0x42da5105, + 0x07497c01, 0x94ff1cfa, 0x3c7321aa, 0x165a5efc, 0xd7a6a75c, 0x50063d33, 0xdb0e6421, 0x827b3bf7, 0x8337ed6c, + 0x9dbf403c, 0xc700e0c6, 0xf556b02a, 0x91aa2593, 0x97713b7f, 0xa57f3d7b, 0xccaf7fc5, 0xf9058eb2, 0x27e2e359, + 0x8d072d33, 0xe03a5bdc, 0x76bd0077, 0x30220f25, 0x99ab3d27, 0x37fd3cd5, 0xfbd3a738, 0xbdb79604, 0xe3d665d6, + 0xe2b101cd, 0x648a09da, 0x69bf3687, 0xece0f8d4, 0x6dfdd332, 0x1139d8b3, 0x2b3e65ef, 0x202e3c1a, 0x381e4eff, + 0x3ed4341a, 0xbe0d9a7b, 0x64de23c4, 0xc2e19f63, 0x5375ee34, 0x7a564c0e, 0x9f1db2fd, 0xa1a1ba34, 0xb78a84a2, + 0xb3a8390e, 0x97d782a9, 0x2537839f, 0x5c827e91, 0x8948e2de, 0x5215d74e, 0xf7c72ed1, 0x4fbf31a2, 0xa96185ce, + 0x13046ce5, 0x90abf746, 0xfe4ffb11, 0xa8917303, 0xcc8b07e0, 0xf594521e, 0xd9e4cb36, 0xed6757a2, 0x1c5c2528, + 0x7abd6e22, 0x6568b84d, 0x4a37e29d, 0x6a7b1282, 0x26757020, 0xdb099874, 0x15d42b79, 0x48831152, 0x58279b23, + 0xe79c7a8b, 0x73641602, 0xed0a1c6a, 0x502a9b87, 0x175d8891, 0x9d8c8c16, 0x8edfc318, 0x06db1dcd, 0xf6cbbee3, + 0xa6f86195, 0x54ade4d5, 0x391492cd, 0x7fa06f9e, 0x3ffae332, 0x57611717, 0x6db73921, 0x9801b364, 0x2d335536, + 0xf79629f5, 0xd9dc0e1f, 0x5d82136b, 0x191ae2fd, 0xb4e2aaee, 0xa5bd60c5, 0xf33e5f08, 0xc5c419c9, 0x843f1cfe, + 0xbe13aee3, 0xbee11483, 0xeed50dbe, 0x2cda71dd, 0xb08365c2, 0x83e4bd9e, 0x7692d282, 0xeed1cf32, 0x47f98dbe, + 0x2c7d73b0, 0x035695f9, 0xd23c8359, 0x4a743eb1, 0x802de83c, 0x5f9c0db4, 0xbcac78c1, 0x9b4e7e72, 0x1a64eb0d, + 0xcdad5923, 0x1bd9b0ea, 0xd9cc2966, 0x81b37b71, 0x5d59f82c, 0xa9099da4, 0x8221ddd2, 0xe2e3c79b, 0x87b17f19, + 0xb77d69ee, 0xe21df10f, 0x0dde950c, 0x29681a89, 0x174b903c, 0xa4f8044f, 0x8d7c1662, 0xed592ff7, 0x382ff3df, + 0x4f0478e3, 0xf1cd224d, 0x50253b23, 0xd330bd71, 0xf56d3a4b, 0xd0f46f0b, 0x08e9afb5, 0x968bc27e, 0xa06a32da, + 0x4778bf6b, 0x0ac7c925, 0xe4362620, 0x99d50a0d, 0xc5c16afa, 0xbf3d78e3, 0xd581a82e, 0x40e9a236, 0x81f4ec41, + 0x178f50ef, 0xb7d5be9b, 0x48550b3b, 0xe19dc166, 0x46348182, 0xd111b0b9, 0x04900803, 0x4d4cdca9, 0x4a8fe2f3, + 0x264d198b, 0x2ca1386e, 0x173090cf, 0x41105094, 0x6ec3b4a3, 0x6c562e6a, 0x54e885ed, 0x5d17da71, 0x9fc80a2c, + 0x493c7292, 0x04d2f690, 0xd2ffcc1b, 0x9ada3a22, 0xda3dc934, 0x6d5fb09a, 0x1c617135, 0x35f7c23c, 0xf6db7d45, + 0x98882391, 0x378bda1c, 0x34d6de37, 0x93de61a4, 0xc93c28a8, 0x5e64dde0, 0xc3146691, 0x52c334c8, 0x3b4d5c28, + 0x7ee0d541, 0x1db78066, 0x6c920172, 0xc5e66824, 0xd4c5f2b0, 0x4fdbcc75, 0xe2ce858e, 0xb0842873, 0x691f6642, + 0xd127b0b5, 0x5769c89f, 0xa539a55f, 0xb784f3a4, 0x29e2ac47, 0xbe4151ed, 0x93c27868, 0x1c5612a3, 0x24ecf01f, + 0x2a406182, 0x8f1a4d44, 0xae744b40, 0x89ca5d6d, 0x3f3b07f6, 0x1b1825dd, 0xd54f86eb, 0x26a10d11, 0xc39e373e, + 0xc47dd84c, 0x6c60feea, 0x72b43e8d, 0xc9e15042, 0xc0593de6, 0x71750abb, 0x5ff9e89a, 0xbdadce46, 0xefec4c7b, + 0xf5ba0da2, 0xc1f4e72d, 0x71c79c6c, 0xe890ce50, 0xdf0503f9, 0x36868d44, 0x8894e1fc, 0x6351926b, 0x77726be8, + 0x97270f4a, 0xa182437a, 0xd26f1b31, 0x07337ead, 0xe352b901, 0x37423820, 0x878fc779, 0x30cc9d9f, 0x0fd3931c, + 0x059ec79d, 0x30883375, 0x7cef768b, 0x54386436, 0x82c07638, 0x0f2b7510, 0xae429a10, 0x17568dee, 0x0b43bcae, + 0xc5a37b42, 0xff0896ac, 0x8e0b3e13, 0xecf4a144, 0x8914133a, 0xaaffa7ad, 0xe5decc55, 0x1f8b8f31, 0x202933ab, + 0x59b49928, 0x77171c64, 0xfa01f3de, 0x69d6fd94, 0xaa034ef8, 0x7f71bec3, 0x413f4e8f, 0xa6eddf6a, 0x37a56be5, + 0x143bd258, 0x21c2ba3c, 0xe54272a3, 0x08ed8d18, 0xb26daacf, 0xc5399bca, 0xd8c4aa71, 0xa603b457, 0xe7510f0f, + 0x58f334c1, 0x63bc8685, 0x99dfc25d, 0xc4ee3929, 0x24202da5, 0x5d5a7b61, 0xdba17f23, 0x88950310, 0xe71c1bb6, + 0x117ba215, 0xc9b40fe5, 0x4ba1153a, 0x19532a63, 0x88951a2f, 0x4ee76dea, 0xb6bcbf99, 0xb7015c77, 0xef71e60a, + 0xd57d0fae, 0xba51c846, 0xc2fb306c, 0x6af569bf, 0x9e0f6acd, 0x55fd7879, 0xafafdf30, 0x6a6b713c, 0xe1f0c84e, + 0x0d384a4a, 0xa50a30bb, 0xc7f5efb4, 0x6b615191, 0x49960057, 0x2a2da7bd, 0x6fa00c7d, 0x4c6ff846, 0x6dce651e, + 0x08d7e58c, 0xf0e730b7, 0x1fd80a24, 0x3d850e05, 0x64fcebf3, 0xa0859790, 0x4fe43910, 0x8255c216, 0x2059405b, + 0xd651ce26, 0xe9f2c692, 0xa4851c8d, 0x12e68210, 0x7f16f258, 0x9fae1b54, 0x6dd0f60e, 0x7a485b39, 0x6e3b0f73, + 0x9851eb7c, 0x7d7a6b7b, 0x3837e5d0, 0x9db8eb66, 0x026c256c, 0x11bde916, 0x06b25369, 0x8bcf6714, 0xf1f81f9d, + 0x0751cc08, 0xfd4b798e, 0x13c20654, 0xe4a5c0c1, 0x73761832, 0x141545fb, 0xf82d4f76, 0xd52054b7, 0xda9823ce, + 0x9344ca53, 0x69219f5b, 0xf8b29248, 0x197033ab, 0xe116ae77, 0x3517c99d, 0x64bd1f65, 0xa29d7f6e, 0x8c4c463b, + 0x4c2ba8ab, 0x0351552e, 0x5d4e9656, 0x3ecfc988, 0xfb7e1132, 0xd2288a67, 0x76aac44a, 0x83b48df4, 0x424e48f6, + 0xb50c95a4, 0x0787c556, 0x3b3cd89c, 0xd46ded10, 0x3339e266, 0x8d560ddc, 0x735723de, 0x408c71fd, 0x9e2bf73b, + 0xa06c757a, 0x45dc534e, 0x7d1131b9, 0x8e35a75f, 0xdab813cd, 0x1422171b, 0x9b350a84, 0x7bdaf1d4, 0x2b1a73b1, + 0xacf021ea, 0x42f9819e, 0x7f731a89, 0x19d04123, 0xb18007dd, 0x04439b62, 0x91d69106, 0xc1e345da, 0x69cec2f6, + 0x4c1d72e0, 0x80d84669, 0xa357a25e, 0xb2d158c8, 0x7ae9c3a1, 0xae667f9b, 0x5e009ada, 0xc9afd2b9, 0x7c479c19, + 0xaaebc37f, 0x95263a4f, 0xffc9561e, 0xb831290d, 0x6002f3e6, 0x7596b9ab, 0x27acc1d1, 0xf2eff429, 0x7ae6d841, + 0xabb857db, 0x7580a37c, 0x182809de, 0xdca8619d, 0x57697a68, 0x64b83aa4, 0x7b3043d4, 0x57594fc9, 0x0ee57053, + 0xd5771ea4, 0x4e89f348, 0x33e63759, 0x1fdedf6c, 0xa76f4a7d, 0x31c49f09, 0x54281d06, 0x0db129fc, 0xd769ab2c, + 0x55c88dcb, 0xe2cd689d, 0xdbd5c9f5, 0xb34745fe, 0xb4a1520a, 0xa8c59017, 0xd436db3e, 0x827a717d, 0xb17b706c, + 0xeaf77467, 0x7f13a91f, 0x262a4bf5, 0xc740689e, 0x488dcc0c, 0xe6fa1ebe, 0xa96890d4, 0x61b6907c, 0xefca8c47, + 0x45dd172b, 0xf6c46316, 0x263b82cc, 0xe052ae5b, 0x9252b18f, 0x3d33c6e9, 0x7903b2d5, 0x3597343a, 0x4ab7a0c0, + 0xba676911, 0x73af3e51, 0xdd16da0a, 0xc47d1140, 0xebfb7789, 0xf8659e63, 0xea42a678, 0xa0a6de46, 0xda73bc28, + 0xad8000bf, 0x0860e132, 0xdb824152, 0x41e5fb04, 0x0b0ca85a, 0x6e144a65, 0x58b80d76, 0x24e169fd, 0x3fef583d, + 0x797a1191, 0xa6474aa4, 0x1f8f0422, 0xff5a3ca6, 0x4f0decd0, 0x7ef7b765, 0xbf6abf7a, 0xc6cec979, 0xc086cf86, + 0x9cd62f67, 0x53a9b98c, 0x94c8e720, 0xded4d785, 0x808710a1, 0x56fd15ea, 0x425ea661, 0xbfceca88, 0x276d5466, + 0x8b6d8603, 0x82f424ae, 0x098346ba, 0x1ed96ecf, 0x4bf53b4f, 0x56c30566, 0x5a00c81c, 0x848dac3c, 0x4e86c7e7, + 0x30bad272, 0xc3126745, 0xc152335c, 0xd623d388, 0x61bfbaf4, 0xf84a0058, 0xc955b9cd, 0x7a40085f, 0xb36748a0, + 0x3849a0f8, 0x801600c2, 0x31c3387b, 0x0bf75368, 0x719b3662, 0xdf27efcc, 0x6892ac58, 0x62c7eea5, 0xccd1856c, + 0x35b82ab6, 0x31f37021, 0x340c2ad0, 0x7bbfd4df, 0x82fd8f1d, 0x8a6db6cb, 0xe81450d4, 0xc0b1f434, 0xd1724704, + 0x88b16cf1, 0x5ab869a8, 0x8c35e9ea, 0x4b833a02, 0x7f23f384, 0x53d9f2b0, 0x401d4d78, 0xff9b9fa3, 0xd37d7375, + 0x79f8b34d, 0x092c458a, 0x44b54425, 0xd916e987, 0x95f50bd7, 0xc5415104, 0xd15ac5a1, 0x304f58a3, 0xbcacb32e, + 0xabc9653f, 0x11022741, 0x8a58cc28, 0xe60ec10a, 0xf50758aa, 0x23669fc2, 0x38013a6d, 0xe21a53f4, 0xc0bd48d0, + 0x3cc5bea6, 0xb67e75e9, 0xe5355ec3, 0x1356c073, 0xca6fb7e9, 0x56bec268, 0x6731063b, 0x7a36d575, 0xda7eb64f, + 0xe6120554, 0xf79eb20d, 0xd94b4d2a, 0xbc403584, 0xf80343d6, 0xb2266d60, 0xc0844926, 0xfb465147, 0xb33af921, + 0x3e42ec40, 0x853b969e, 0x58734e0b, 0x2ff816fd, 0x081548b1, 0x394a2abb, 0x10fb4955, 0xe8ce3772, 0x2a2ce3d5, + 0x52907c8e, 0x823eb93c, 0xcd689fa8, 0x84051f51, 0xaa6ef101, 0xde370df8, 0x237c9a60, 0xdca50f98, 0x030e0f1b, + 0x6e367d8c, 0x82499f2b, 0x78f96950, 0x13e7262a, 0x71ea42c5, 0x88539252, 0x0243a7c8, 0x766577cb, 0xffae6db4, + 0x281a9b78, 0x1fd5ea38, 0xd170767a, 0x18b681ae, 0xd3c2bddc, 0xc0bd84fe, 0x2304dc57, 0x8be3fe12, 0x136fbcb9, + 0x66cfa6d4, 0xd9eda435, 0x2738675e, 0x53fa88c9, 0x4db86e84, 0x2d4b3490, 0x182a72f6, 0xd9d31848, 0x8ef8fa6f, + 0x97e5478e, 0xa0bc419e, 0xc539658f, 0xfa8968e4, 0x7dfe9a9a, 0xb0a423d6, 0x7d8040a2, 0xaa9be44a, 0xb1c8c5f9, + 0x08211f19, 0x1fab5260, 0xa3b0bb58, 0x6e1c1350, 0x88796374, 0xd555fe0d, 0x783b7655, 0x7f0ee35f, 0x4eb02d56, + 0x6035ca68, 0xfa4d51f1, 0xf454bfb3, 0x0f99383f, 0x0ac94b6d, 0x64e22d74, 0x94ce578e, 0x9c0e76cd, 0xd6eee08b, + 0xcbeb3c35, 0x2b120bf6, 0x68e45a49, 0x5727cba7, 0xf6996986, 0x3501da36, 0x48109461, 0x8c14e542, 0x39acb257, + 0x0eb760d6, 0x7a803160, 0x88f184d0, 0x01d7b546, 0x58912519, 0x70bc3e84, 0x358274f7, 0xef1799bc, 0x2b6288a6, + 0xff25e20e, 0x686bac11, 0x72b2245c, 0x1a832a1a, 0x691e96e3, 0x0ec4fa57, 0xcc74e1d6, 0xf5a7edc7, 0xf8707de7, + 0xa01a7fda, 0x1631b488, 0x6dc35877, 0xf9804f91, 0xd194e606, 0x47f3709c, 0x4b985383, 0x290e8475, 0xe1d1e230, + 0xa55ead4c, 0xb97107ce, 0x3f0d15ff, 0x91ae9167, 0x5164d3de, 0x8bb7a4c9, 0xa3332643, 0x1d74552a, 0xa057b2ed, + 0xb4cf8a63, 0x22426d20, 0xb5c99eb6, 0xc35fd868, 0xd383e254, 0xb3d0681f, 0xc123994a, 0xb5e19892, 0x208a23a7, + 0xa410156a, 0x41de7ff2, 0x2a89d752, 0x4ab12f12, 0x6cee913c, 0xde41a886, 0x1539d066, 0x2929162f, 0x660df236, + 0x90a7ffe3, 0xb38ea975, 0x2771cd19, 0x79c846b9, 0xbca8e010, 0xc8830e3a, 0xc61231a3, 0xa7160ea0, 0xbdd93fcc, + 0x7dc0ae30, 0x7086b32a, 0xba10c59d, 0xb5a30848, 0x0fc4ea47, 0x11daf8b0, 0x23a41d17, 0xfd32b124, 0xd845d3db, + 0x5c6c62a0, 0x695143c9, 0xed8206c3, 0x0fdd902a, 0x223aac03, 0xfb3bb484, 0xca59b86c, 0x3e4e0515, 0x13646231, + 0x5da8aa16, 0xa250e646, 0x3bb2ebde, 0x87a53265, 0x89c4ad49, 0x4e8b160f, 0x940f7382, 0x9171ea86, 0xe3e7fae4, + 0x6400d994, 0x6312305e, 0xdf83c575, 0x7bea0585, 0x18e01628, 0x81a3b836, 0x94c1ba29, 0x32090467, 0x0191753d, + 0xdc4c4218, 0xe5df420e, 0x13b1d3e5, 0x214e0360, 0x9b34a4ff, 0xeb01255e, 0x223087af, 0x38ec1fdc, 0x40c7a011, + 0x5578ae13, 0x8380387c, 0x4250c9fc, 0xe82b7f0e, 0x5ef67811, 0x5e4f2305, 0x21c7f3e7, 0x625a64e1, 0x7305f347, + 0xc1c2d4c9, 0xce02722b, 0x8150443a, 0xc01b086d, 0x3ca7464e, 0x7c20b865, 0x69af8a3f, 0x484f5c1e, 0xbb08a2ea, + 0x865f783c, 0xff093b09, 0xb6f785a2, 0x4b52efd8, 0x6e15c9a4, 0x2615c0ed, 0xeac42703, 0x10d0aa55, 0x83a638e0, + 0xf3e47e9b, 0x627087b2, 0x8c0a8c47, 0x658b40c1, 0x385bd394, 0x2d6a6d75, 0x1284249a, 0x44179df2, 0x44a4a309, + 0x5ecdf0ae, 0xf9607304, 0xc342dc64, 0x849b7975, 0xb64e6812, 0x56b719bb, 0x934cc7a0, 0xfaebb6ed, 0x02a6b0a5, + 0x46858c38, 0x7e8373a7, 0x00daab4d, 0x80e687ec, 0x25fa20e6, 0x9a101ff1, 0xe34cf47e, 0x66e037a6, 0xa18f69e9, + 0xb145dcd3, 0x82426fdc, 0xffaf0e41, 0xef87d786, 0xfa99a187, 0xa7cabc54, 0x3de22d93, 0x3e9ade5c, 0xe5dd7b05, + 0x3373812a, 0x2b2e7274, 0x080f8ef2, 0x5fe1c0da, 0xa5b299c8, 0x2b756289, 0x2f44c93b, 0x451d73ff, 0xfb2c134c, + 0x9cb579b0, 0x7617ed14, 0x165eadaa, 0x6e1d7d68, 0x1d15b978, 0x0427addf, 0xbca2f41d, 0x1a75ba7e, 0xc7d36a2b, + 0x22931096, 0x43af165a, 0x233ce7ae, 0x2c69b3e8, 0x0bd23aa0, 0x295825bf, 0x6ce655e2, 0xe9b56fcd, 0x03b4be07, + 0xf8304e42, 0x6371b092, 0x6437dad5, 0xd745275e, 0x7868f2f8, 0xbd70291f, 0x8aed6583, 0xb88dab1a, 0xaf986639, + 0xe30a455a, 0x422c1529, 0x18901c32, 0xeb777536, 0x5f28d4c9, 0x7202d009, 0xa0eefd93, 0xc3f92f09, 0xeb290f9c, + 0x1e0d5b7f, 0xdb12117d, 0xfbfd2beb, 0x63043f9a, 0xd3722879, 0xe6e4f0d9, 0x554a54b6, 0x565e3b84, 0x09639f77, + 0xae5a82a8, 0x569e8271, 0xfb5b959e, 0xe74e3c22, 0xdac4b11f, 0x3e69ba45, 0x4eb19001, 0x1c6efb9a, 0x853457d2, + 0x9d316592, 0xd6529e2f, 0xce8bd331, 0xc5663ca9, 0x92624e10, 0x05499cff, 0x4c8ce0dc, 0x22fc90b6, 0x8d312a01, + 0xa4e88f96, 0x79775ed5, 0x7946a5a0, 0xee5e1019, 0xa8b40cb1, 0xe008da12, 0x7bb50354, 0x14426f93, 0x24446a4d, + 0xaa29bda4, 0x5c97ffea, 0x5821854c, 0x4ea90eaf, 0xe7af0442, 0xf78f2a8c, 0x8f4fc494, 0xa421a690, 0x1546436a, + 0xe1539f09, 0xf5442770, 0x7dedcf19, 0x5a324d44, 0xc93c8493, 0x6fe8aa92, 0x0b77d9b0, 0xbc51875c, 0x37da677e, + 0x19612de4, 0xc754a5e1, 0x64a5370d, 0x67538ab5, 0xbfed3048, 0xbb2eca0a, 0x51d37049, 0x279b50da, 0x988e981a, + 0x697c3103, 0x3bd228e3, 0x457107ee, 0x339bee76, 0x04ba72cf, 0x962d21f3, 0xb19054f6, 0x40283c3d, 0x0a45657d, + 0x43e98ec1, 0xf3be5d6e, 0x96a9312a, 0xaa934664, 0xb2789d9e, 0xb208570c, 0x0d2fa50e, 0xe4531a8e, 0x9a584542, + 0x1c8e623e, 0x0f3b629e, 0x81ce75d9, 0x16ddb2f4, 0x79bf7ad5, 0x2c170d6e, 0x44d94e35, 0x0a8ebb34, 0x3ad5689c, + 0xe20067d6, 0x927f3d65, 0xd76e961c, 0x970660d7, 0x8841f478, 0x2f55a9c2, 0x2796abfb, 0x482737f1, 0x2052c600, + 0x04b6ccc6, 0x1faef83f, 0xaac6a699, 0x235bf027, 0x728cc6df, 0x5b10f901, 0x1c8f0eb5, 0x2db0cd2e, 0x88953985, + 0xcf6d9774, 0xec35a35c, 0xd6d12308, 0x4d1d3ebc, 0x342ec326, 0x2bf2db3b, 0xd986fb26, 0x3ff037d4, 0x8b1ddfea, + 0x217a0f09, 0xace60438, 0xcb79aef7, 0x8c799254, 0x37fc3087, 0xec985717, 0x39a26aa5, 0xa8b18b66, 0x530f95e8, + 0x80a38f76, 0xa9ddd7c2, 0x994a51b0, 0xeb70b593, 0xd3b640d6, 0x51ea5171, 0x1d8852a8, 0x9af7f19e, 0xb695bbdc, + 0x056d5502, 0x1160186e, 0xc880ed72, 0xc3adf72e, 0x1afbb470, 0xac333a97, 0x94d225d5, 0xf36f4831, 0x3c391472, + 0xa75a6135, 0x7ead441d, 0xa022a88b, 0x6e20ce63, 0x1c91e2db, 0x60fdfaac, 0x4aa1f3a6, 0x10a01621, 0x123247bb, + 0x8b189f55, 0x4b4442f1, 0x25efe421, 0x52afe2e1, 0x9836d4ba, 0xf0d4d8b7, 0x336588aa, 0x5c143ff3, 0xb0bd775a, + 0xd434d4d5, 0x36dd01f5, 0xf56092eb, 0x1ba24bf4, 0x87623bab, 0x07f2c44d, 0xdee4356f, 0x1cb4e8d8, 0x08cd8c28, + 0x495e2021, 0x739a9df0, 0x78ae8c32, 0xd82a718f, 0x34673e10, 0xc53f13a2, 0x867ee154, 0x249fcd0f, 0xb230e450, + 0x9802f9f4, 0x1bd40cfd, 0xbd60e2ce, 0x80bd490b, 0xf6ef94c7, 0x3bc153ff, 0x2b3cdb40, 0x76a2ded3, 0x0f98df54, + 0xc0e1fcbc, 0xf5b46467, 0x72017d00, 0xba7bbffc, 0x1f5adb34, 0x65a30e00, 0xe4169760, 0xf01bf14f, 0xc6463ae5, + 0xc901b106, 0x63603a33, 0x9e618547, 0x4c7dbb09, 0x53462bea, 0x2e8b4a0a, 0x8cc01b76, 0x3b1e2b73, 0xd90ab30d, + 0xd087746d, 0x02d85830, 0x153b1ea6, 0x375c0ee5, 0x427c6f4e, 0xc4672933, 0x60c5d6cb, 0x501f71a0, 0x7a462d72, + 0x22262a1e, 0x0f98687a, 0x418a17d8, 0xd585a945, 0x0bc4e6b6, 0x8d2fed27, 0x4613e3db, 0x9f1c3303, 0x546e217d, + 0x566ba7f8, 0xa4dd0ff0, 0xa6371b4e, 0xeacce33c, 0xb18473e6, 0x507f374d, 0xcf2e27ef, 0x91ba14c1, 0xd190267d, + 0x5654f2b2, 0x0dee2e53, 0x0a2848e3, 0xb1292cec, 0xcbf32208, 0xb746602d, 0xab9d6c99, 0xb5360e69, 0x5c7d9ebb, + 0x4c1df83b, 0x8ee3c8bd, 0x06f4bf03, 0xd5c5e284, 0xa19351b1, 0x9f2adb00, 0xad5b580e, 0x07206a60, 0xe8e4a8df, + 0xcffccb1b, 0x5f7d14a5, 0xb667558e, 0x0a8c20e3, 0x72b30c17, 0x9415f189, 0x32dc8316, 0xf6490e41, 0xede39b78, + 0xbfa05c56, 0xfe67e73b, 0x631d2668, 0x6e53892d, 0x825a77b7, 0xdbc75024, 0x6b00b634, 0xec7d6030, 0xb0b6affc, + 0x2563e7a4, 0xfd21f4a1, 0x0e57382c, 0x2de96bd9, 0x95f6659c, 0xb1e8334d, 0xe9d60ff1, 0x2c7157b9, 0x0920f444, + 0x3649d8ae, 0x27c5b450, 0x576d7ef5, 0x7f9d2507, 0x97f888f7, 0xf693bbab, 0x5cf59abc, 0xeeb353d4, 0xc5868769, + 0x9c028d99, 0x6b1c7de0, 0x89baa914, 0x962acab1, 0x98504892, 0x82312e4a, 0xc7ee0013, 0x42dedd9c, 0xe7fb944d, + 0x9419d779, 0x0199c8f8, 0x79f2ae9e, 0xc45a483c, 0x3e5b2c16, 0x1c1ef35c, 0x962f6b92, 0x5318d808, 0x3c61452f, + 0xff5db225, 0x999acf84, 0xba97a92f, 0xdf79488b, 0x39e962f9, 0xd4188569, 0x3694c761, 0x87ecb640, 0xc8305ac8, + 0x5257fc5c, 0x970b1f6b, 0xb2c7eeb9, 0xd53cb3a6, 0x0f428bb1, 0xe105783c, 0xe79eff69, 0x319795a6, 0x9ba821fa, + 0xe2d715bc, 0x5cf17bb7, 0x03742219, 0x56156951, 0x6cf05fd0, 0x5b792ca9, 0x519b47f5, 0x1c71dfcf, 0xbe682711, + 0xe6301609, 0xdc523ffe, 0xc4e02035, 0xed944edb, 0x2af91ea1, 0x6434433b, 0x88da7d7a, 0xfe3a7adf, 0x2d9ca4fb, + 0x1c26c6f3, 0xbf2053ce, 0x4c340894, 0x4818ee2a, 0x8738ecd9, 0xec3b20d4, 0xbe8386eb, 0xa718633f, 0xdb0d7560, + 0x41126350, 0x1cf67c55, 0xcabb6a12, 0x7de43b9f, 0xf1868300, 0xf3647dbe, 0x21340d22, 0x2ca25c92, 0xfd997821, + 0x289d511b, 0x10708824, 0x8787b4f8, 0x59a7904b, 0x4d45f2ee, 0x58181c7d, 0xe1624a17, 0x21276ec4, 0x41af4f41, + 0x7ef7dc0d, 0x00711887, 0xa1cf1e7a, 0x01d6a22e, 0x862bab8e, 0x4f857af8, 0x70eec479, 0xd1ca2ac6, 0xf1ab333d, + 0xa2cd0dd6, 0xea60849b, 0x63d07b65, 0x48e32d6a, 0xde6fb8bb, 0xb621058e, 0x940bcfb8, 0x9bf324b3, 0x67798556, + 0xf38b7651, 0xcc4528c3, 0x951411aa, 0x0a8c9b8b, 0x12b2578e, 0x6a92d375, 0xdb61aa30, 0x8f432e3b, 0xf1969b67, + 0x64a1b960, 0x608532a8, 0xfab2adef, 0x203cbcfa, 0xf0fd7cd0, 0xd6502369, 0xc1ab6677, 0x68ae2120, 0x2f12d951, + 0xbeeebd70, 0x6bc78098, 0x0757dd0f, 0xc8baf55f, 0x49441c88, 0x2f42e57e, 0x29f9acaf, 0x18d8e3e5, 0x2f55d060, + 0x1f4d43dc, 0x731f9d50, 0x44d1bdc9, 0xff7b9cc3, 0x3e65cc26, 0xeb46b2bc, 0xabc5f713, 0x81a96fe4, 0xf929d6a5, + 0xb1e96605, 0x225a1bb1, 0x7eea1a73, 0x74534c4a, 0x7710f378, 0xa135338c, 0xce9d17c1, 0xee100482, 0xe21e20b7, + 0x0fe366b3, 0xcf110e96, 0x59fca906, 0xdc0b26b6, 0x4cf010ad, 0xb5730479, 0x8671c4e7, 0x7da33f14, 0xcaaef08d, + 0x621dd0a3, 0x4d6c5817, 0x1dd49b3c, 0x4c0cfc48, 0xd95a717d, 0x4fbca982, 0x63603454, 0xa92a4f22, 0x05fc9807, + 0x9201b204, 0x8c86c992, 0xeae26efb, 0x4d0a652d, 0x0c45c9c8, 0x4884b002, 0x3732b7e3, 0x8d6f4ebd, 0x01636de5, + 0x6a561edb, 0xce9a27be, 0xd6752aa5, 0x59269976, 0x41db8366, 0x705576b6, 0x4b5726fa, 0x3dfb4116, 0x100e24e8, + 0x71202b91, 0x40eabeee, 0x42b51a66, 0x630dcbbb, 0xcba384af, 0xa6c8d4a6, 0x9a223b37, 0xfc28289b, 0xb5d7bd80, + 0x65d5e969, 0xa9d8908c, 0x7d790895, 0x0d56d6a7, 0x8784f9ee, 0x2368920f, 0xe273793f, 0xbb88ba0f, 0x34705f04, + 0xceaf9e4b, 0x252d0fa2, 0xc9c3d9c6, 0x3c259864, 0xa7ce6873, 0x5da3e572, 0x64ce8ecd, 0xc6aef058, 0x877b53db, + 0x1822271f, 0x3b047618, 0x104d0c26, 0xe6b986b8, 0x208bda3e, 0xd09828b9, 0xcbe5c31c, 0x52b3c9fb, 0xc8e76332, + 0xfcc68c6b, 0xf5f27226, 0x8d44c939, 0x06119e2b, 0xbae6ef66, 0xfba9fcc9, 0xda04cd18, 0x3a0587f7, 0x999ee48b, + 0x2f4c7b7a, 0xacd20261, 0xfced7aaf, 0xdb11cf49, 0x37a04127, 0xfab185cf, 0x35cb9bce, 0x3ece138f, 0x71bd6176, + 0x511d7667, 0xf0223f11, 0xd19a952a, 0x839d55aa, 0x07b20ad2, 0xbb3c15c3, 0xc0274d17, 0x56b998dd, 0x80e13f20, + 0x952e9a09, 0x51d7a313, 0xb1454175, 0xdfdaa772, 0x77757ecf, 0x6997f98d, 0x50f0675e, 0x4cf00fce, 0xeb12bec9, + 0x1b71ea64, 0x7a69ac56, 0xc52d1e73, 0x5a0872b0, 0xd80bbe3d, 0xc0fc1bd7, 0x6c14c9f8, 0xb0fe5be1, 0x13c52556, + 0x724217c7, 0xa7adb3b3, 0xc1243dfd, 0x2be425a0, 0x99dce5aa, 0xbaf382b2, 0xed5344c6, 0xf17a16a4, 0xa0cc4a84, + 0xcb20684c, 0x017ec0c0, 0xf1c35be2, 0x18e11c32, 0x1bf02c0c, 0x0b7ccc80, 0xf5bd2006, 0x64537378, 0xfaf373c5, + 0xe6e85eee, 0x543625d2, 0x3d7cd888, 0xe060d18f, 0xa3018666, 0xeba45d3a, 0xb67edf70, 0x4f4ab38f, 0xcdf88120, + 0x544cd2dc, 0x214b83b7, 0x59aad106, 0x7cf73638, 0x22abe8d0, 0xe3bf43ab, 0x670d6fc1, 0xd23b79f2, 0x4af94c9e, + 0xb0952b11, 0x383e9a4a, 0xa64b6755, 0x56061320, 0xe704193f, 0xb68dacec, 0x3773b583, 0x43792652, 0x7befab22, + 0xcb3b06f3, 0x9d9e3692, 0x77bd7c93, 0xece983cf, 0x68cf303b, 0xeb0b0bc4, 0x17d4bb9a, 0x39fc9b21, 0x94d69102, + 0x62ab7480, 0x3be7ab90, 0xad855e2b, 0xd8f684a1, 0xabe69e80, 0xbc68da2e, 0xed0c1bb2, 0x9d4c157f, 0xfcb71913, + 0xa5829c3b, 0x9346578a, 0xcab15b58, 0x9828c602, 0xbc2c5655, 0x5aee6a1f, 0x4ed15c05, 0x457c2b7c, 0x030ca429, + 0x5c2fc433, 0x52447503, 0x85b6eaed, 0x1863d03f, 0x8a694fac, 0x19d7075c, 0xd2dfb8e1, 0xac85c799, 0x40cae74b, + 0x9f694174, 0x7a5fd06c, 0x5c2af964, 0x7e70286f, 0x244e5f2c, 0x38230ff5, 0x6cb08d3b, 0x7443a455, 0x25d5ff34, + 0x65a94d97, 0xdf655b5a, 0xf9209caf, 0x9b5e6e16, 0x8798f0b0, 0x5d92b134, 0x00bb75cb, 0x296d9b53, 0x1ec5765b, + 0xb5eb9abd, 0xe6100c56, 0x3152bdab, 0x144ad58a, 0x7e37e138, 0x506173e3, 0x9cb1e2b4, 0xa944c31f, 0x97cdfc2d, + 0xaab56b22, 0x7fef0f57, 0x62d95ec6, 0xb21ad216, 0xfc288492, 0x6b0e1659, 0x7a130158, 0xe99c76be, 0xbabdecad, + 0x52eb44fc, 0x29cfc644, 0xbf2da9ab, 0xfecb79d3, 0xf9ea3cb0, 0xe264afa9, 0x0890632c, 0xa70c9515, 0x34727bb9, + 0x6ad55b7b, 0x93e3713e, 0x207138ae, 0x0f89c22e, 0xe7272277, 0xd17572ff, 0xaa5a1b78, 0x937c5bd4, 0x93dab949, + 0x279605d4, 0xcbb84735, 0xd5a482aa, 0x95d0fb7e, 0xf138e773, 0xb4628bc5, 0xedeab878, 0x16bb749e, 0xac0e3684, + 0x4dedd01f, 0x52c2c6df, 0xd7842c42, 0xa3e5d7cc, 0x11d52858, 0x0bbf8be4, 0xa66caafb, 0x98a5d3b7, 0x7402971c, + 0x9c2f26af, 0xf5a23cc4, 0x3cd6596e, 0x1e74e7ae, 0xea34d0a9, 0x10ce4a5e, 0x918fb561, 0xdc5e3a54, 0x1cf40ce8, + 0x42cbd72e, 0x54fc1a00, 0xbf0a8259, 0x1c120dc8, 0x5ede977a, 0x400b977c, 0xb3d88211, 0x3f9a8ea2, 0x6d71599f, + 0x3ee48917, 0xd7c90036, 0xfcafbed8, 0x8d2ce736, 0x4244a8fc, 0xcfe0bce2, 0x55543c03, 0x72e00710, 0xb57f36f5, + 0x3fed204d, 0xdeb15e3a, 0x2e581d57, 0xbe357dfe, 0xedcc8655, 0xe0d37349, 0x7be892db, 0x509cb38c, 0x2a81f17f, + 0x7a6449ff, 0x0782b3e8, 0x7f9c1d83, 0x54678751, 0x5cbb0e09, 0x7f75f667, 0x9d00adf9, 0x89181010, 0x571c1eed, + 0x51465333, 0x0b8a9ec9, 0xfc3d6a4b, 0x63db96cc, 0x929e9194, 0xf28c8145, 0x20ad3693, 0x961e40df, 0x709322db, + 0x48ae0a35, 0xb029f56d, 0xa251f44a, 0xcb50b233, 0x2c8d241a, 0xcad4eece, 0x0096253b, 0x7f0b5ddf, 0x116e5112, + 0xc7509253, 0x37d93ee3, 0x3e33590c, 0x10c9bdb6, 0x12bbc754, 0x695fb2f1, 0xb99b707e, 0x5589ca72, 0x254bddfe, + 0x3fe14e82, 0xb29fed71, 0x784c1f78, 0x852b3c44, 0x3bfcd027, 0x91ed7cb4, 0x537f1798, 0x9e1127a7, 0x2d91c01c, + 0x50b0819e, 0x7e5413c0, 0x4c8a068e, 0x8ea0d16e, 0xac4d3e58, 0xd3909c31, 0x69d40f0c, 0xf2aa4115, 0xf813a351, + 0xa252f1d3, 0xe329af31, 0x68cfe62f, 0x78815231, 0x809d7e38, 0x55a1278b, 0x7bea9973, 0x20671324, 0x6b85e47b, + 0x0dd35cd9, 0x7d7fef9e, 0xa0fa1c9b, 0xa401a7e9, 0xdbd4f242, 0x10d985a9, 0x33df2c1d, 0x4525beee, 0xab543f39, + 0x633be3c3, 0x5ee83569, 0x7e4b1986, 0xe05193c0, 0x8174e28f, 0x9eeca271, 0x503d91c1, 0x96777f30, 0x7b6cd149, + 0x6b564107, 0x05506cfa, 0x22b9144e, 0xf7cb0979, 0x3b8c4de4, 0x31912dea, 0x1c764fcc, 0x14de5ed2, 0x3fd1009b, + 0x079a6572, 0x2ef17075, 0xa94ad78b, 0x570e1de3, 0x7eafae49, 0x964a2d4a, 0x760506b7, 0x6f9e393f, 0x2ef62ce8, + 0x0bd1fcf7, 0x63e7c765, 0x784fa887, 0xc891a434, 0x313be74a, 0xfd00a964, 0x3747b3aa, 0x42a01c82, 0x9931f2dd, + 0x527871de, 0x5a74f8d8, 0x9a3efe49, 0x0d69a73f, 0x842e2e3d, 0xdabf56a1, 0x622b7c45, 0x20bfe241, 0x4f6f060d, + 0x2251efee, 0xcaf2e95d, 0x710ef5c3, 0x46f14855, 0x9c594cb7, 0x4bcfd993, 0x62cb625d, 0x2f3a501a, 0x1bb711d6, + 0x8c0903d4, 0x208fdbba, 0x484b946b, 0xdfd0c4b1, 0xc2fbe7c4, 0xad6d8477, 0x30ad0ab3, 0x4eb35e7a, 0x3d2ad46b, + 0xb97c3378, 0x363a000c, 0xcd088c99, 0x83019ad6, 0x13e27c62, 0xf19eee1d, 0xf5d0c9f1, 0xcba76822, 0x967dde81, + 0x7d24df7f, 0xdf858747, 0x90cf86e5, 0x386deb95, 0xd7c899f2, 0xe649b5f2, 0x4d2387f6, 0x1b27b34a, 0x1cad1022, + 0x27dece5a, 0xb332f575, 0x3e46936b, 0x2a62e372, 0x0e92d909, 0x167146eb, 0xe3638c6a, 0xec119d87, 0xb8177626, + 0x98cd2880, 0x804d96e6, 0x83282bce, 0x09b66156, 0x62881a30, 0x50b6c088, 0xe908d617, 0xce3fbd42, 0xd1627ed4, + 0x3b2b54d4, 0x4acf4945, 0x6a62c2f7, 0x2bf0b21e, 0xb2e89564, 0x193705ea, 0xcf52665f, 0x5c0592ab, 0x3cb8c7f7, + 0xc255264f, 0x19df1904, 0x4af6ddce, 0x32b5ad7a, 0x4d91c078, 0x264ddda6, 0x1c15fcde, 0xead49890, 0x27fbd570, + 0x1e4ede66, 0x471f33f3, 0xa2fc06b1, 0x56e580e8, 0x97b68c3c, 0xb2569180, 0x977c3e5e, 0x11d99c3d, 0x35de2c9f, + 0xa53942a7, 0x8cd49cc9, 0xe222ca7e, 0xbd2018a1, 0x096c27d3, 0x766b2b3f, 0x0442bceb, 0x5a372323, 0x28591e0a, + 0x58847081, 0x7dfaedad, 0x3781d3d0, 0x3534a11b, 0x3dc912fa, 0xa23abcdf, 0x0345aa76, 0x377f73d3, 0x539983b8, + 0xbae9e2a6, 0x16ab7dc6, 0xe30a00ee, 0x54a54a28, 0xa07c79ce, 0x03c9a3d9, 0xc91c5baf, 0xbfae3b6d, 0xb1490de6, + 0xd3c2d1fb, 0xeb1611ef, 0x9acf3206, 0x87e0028e, 0xbdd688fc, 0xbe892c17, 0x84595b98, 0x88911f0c, 0x48c00e3c, + 0xab7ff0d2, 0x1de2feb6, 0x96d43ff2, 0xa6700514, 0x050dc2cd, 0xf89eb3c6, 0x8986f71f, 0x1048cc12, 0xa149d1dd, + 0x790de10b, 0x58e83092, 0x9aed68f5, 0x691ef49a, 0x637d876c, 0xcfbff8f3, 0xd7d83f91, 0x65dfaa8c, 0x35a7b657, + 0x5c5e0160, 0xf208b7ae, 0xb43c8833, 0xa0e87d1e, 0x8a68d7e4, 0xd126b418, 0x9883c757, 0x19f32c4a, 0xf13fa655, + 0xe8bb8c12, 0x5f89c4c3, 0x0c636fd8, 0x441207c2, 0x4b171ca8, 0x1d9c9dbe, 0x6d86197a, 0xc7736312, 0x45365294, + 0xc048d759, 0xd6586cb5, 0x1aa8b732, 0x805b1002, 0x6b690fc9, 0x77d9dfee, 0x0cbc2545, 0x4fbb2f8b, 0xbdf27f3e, + 0x7d1486e1, 0x1ca23809, 0x50fc1781, 0xb9258c67, 0xbfe2e95e, 0x9d334644, 0xbbfd6532, 0xb1730b23, 0x3b1c880f, + 0x53d5d370, 0xbd31e136, 0x75b6e6f8, 0xb0dcefd0, 0x81b4f5aa, 0xd6ed73a8, 0x91cc3cc1, 0x72950915, 0x999282e3, + 0x2b99c700, 0xf358c686, 0xf0dccee6, 0xc8abea90, 0x252f96b9, 0xddb31037, 0x81801bc6, 0x7cf830be, 0xef46f47d, + 0x87bde40f, 0xfd518e5d, 0xa269975c, 0x5ec60acd, 0x449644a6, 0x6bee83a3, 0x3251ab8b, 0xb6c5560f, 0xef0f5360, + 0x78615094, 0x75428431, 0xa123ed63, 0xd029df7f, 0x1bd89baf, 0xb1fad812, 0x2d469c66, 0x0f80a61b, 0xab52430f, + 0x236d450b, 0x73393a1d, 0xa416fb69, 0xc1f284cf, 0xfb0d4cb3, 0xbc5d448f, 0xb1f5cbb4, 0x7e3e1add, 0x219a5e27, + 0x2b418a80, 0x936a89db, 0x33309cc9, 0x930e4218, 0xff4a0950, 0x067a019e, 0x0cfbf5f4, 0x874b4d30, 0xbbca25be, + 0xf0d9f93f, 0xca76c0eb, 0xaaa06332, 0xc8744b55, 0xc514279c, 0xa0060133, 0xbfedb907, 0x5d201ac3, 0x5c84bb77, + 0xb95ca6dc, 0x21ee2188, 0xd6c66410, 0x46ec7eae, 0xc799b344, 0x39402b08, 0x9b366002, 0xf75aa893, 0x2b29be06, + 0xc0165d6a, 0xb28476b6, 0xe233eb23, 0xfe329aba, 0xf17605df, 0xb21a8d14, 0x5491de30, 0xa3ee3b87, 0xa66dc983, + 0x53e84db6, 0x6d3e1242, 0x7e53cb70, 0x9fc07322, 0xd968b715, 0xe9716ad4, 0x8096bd26, 0x06bfac85, 0xd988c809, + 0xabda6eb1, 0xcecf4e8d, 0x42860767, 0x996b7c47, 0xd94ac48d, 0xb0524894, 0xcb40a4e0, 0x91b0e7b7, 0x218cd830, + 0x0f331c2b, 0x82b68f0e, 0x2b8b0f02, 0x042c1b92, 0x8c162e26, 0x54c466d2, 0xd6c991b6, 0xfdbd7c03, 0xaf5ec300, + 0x00663405, 0x5a8df776, 0x1d3ebdea, 0xd0c5b0c5, 0xc6d8445b, 0xededfa31, 0x5fc62346, 0x6d6f71c1, 0x632b9768, + 0x154e6078, 0xe788003e, 0xcca2f2a4, 0xf1a57f64, 0x989a23cb, 0x318aceff, 0xda5afca4, 0xd3a1f20b, 0x770ca8f8, + 0x4ab20a9c, 0xc9077e30, 0x16e7d17e, 0x39e6946b, 0xdf6609e9, 0xc0f5cd91, 0x4562e0e9, 0x1f0d81f8, 0xa9599c45, + 0x8c6f90f5, 0x1391a439, 0xaa9e537e, 0x5e95c6d1, 0xa310b343, 0x6a35fca2, 0xa72a662f, 0x8e9acadd, 0xce5d1075, + 0x2c799373, 0x8411604b, 0xe305671c, 0x80bdde0c, 0x66cae514, 0x7a2c6a6e, 0xbd122073, 0x54014414, 0x230effb4, + 0xa35d1e22, 0x51c9dbc6, 0x819259cf, 0x387793c1, 0xaccb901d, 0xa9d4fc92, 0x4b3ba5ca, 0xda6efccb, 0xdfa0c005, + 0x09b89eca, 0x9e6c42d4, 0x0d6eb588, 0xf8e7b3a7, 0x8a379ed8, 0x4a55d26e, 0xd7a27775, 0x5729acab, 0xc7d1ed19, + 0xbadacba8, 0x74005c6a, 0xfed26f47, 0x062c92d8, 0xd6a412ca, 0x2908a3e4, 0x082292ae, 0x529fabbc, 0x2e106ab8, + 0x9c306b8f, 0x5b9a6a23, 0x549a250f, 0xa0aa167a, 0x85edc7bb, 0x1c5124c0, 0x740d8507, 0xaaa73f21, 0xc9b8edea, + 0xb0d4f57c, 0xdadb63a1, 0x0621ad98, 0x931eef06, 0xe85a0cdf, 0x9a2e3c68, 0xee399a87, 0x411c0e12, 0x89d067c9, + 0xfb24d164, 0x1e8a8561, 0x45f70cfe, 0x727739d4, 0x7699e7f2, 0x674c1361, 0x4e617257, 0x7746411f, 0x84ae1feb, + 0x20d917c5, 0xf411967e, 0x2ba93fc8, 0x8533b9af, 0x9ba67b38, 0x7429d62a, 0x415082a9, 0xf5da1828, 0x41fb94b0, + 0xd887d201, 0xe5af1ea7, 0x160fd14f, 0x6723a618, 0x2ad7044d, 0x95b6d54b, 0x6937d002, 0x28ddb5a1, 0xd93bcdf8, + 0xee17c155, 0x4cbff72e, 0xcbeceaa5, 0xa287b239, 0x1506a027, 0xe0256112, 0x6539940f, 0x8d5b1932, 0x7957b62d, + 0xba5bdd00, 0x25d58df4, 0x86b58666, 0x1d09cfe8, 0x161e9acb, 0x172ecb83, 0xf86dcddb, 0x8434ef80, 0x8d431a74, + 0x028d945b, 0x86f47285, 0x18669f09, 0xfa777664, 0x58397056, 0xe7ad17dc, 0x5ea0259b, 0x51411381, 0xcd415cef, + 0x09caf3f3, 0x214ae8c4, 0xb6e6e1c9, 0x810c5e01, 0xea7c79f5, 0x56ddf67a, 0xc6b007f1, 0x765bbba5, 0x2310a743, + 0x0b03129b, 0xa22cb695, 0x3f25881f, 0x5d710ab9, 0x5013c5e9, 0x0ea7baf0, 0x84a29a8c, 0x12a433e2, 0x488b6b0d, + 0x8c368b44, 0x637d6d3d, 0x05aa00cc, 0x2580c4d2, 0x5b17ef99, 0xff7da01e, 0x6c751651, 0x6607c9db, 0xdb237c92, + 0x6f97d75a, 0x5e36ebd7, 0x6de2ae72, 0x0b837be0, 0x6d6252c0, 0xd2ba4d9d, 0xdf78340e, 0x3f840abc, 0x831f835d, + 0xf00d0f38, 0xdecd072b, 0x947b51a6, 0x5b611154, 0xc85f8d40, 0xc419ebdc, 0x4209ea4f, 0xbf87e9c5, 0x79647998, + 0xc758e352, 0x0af69be6, 0xf57569ad, 0x7a30fab6, 0x6a2d1298, 0xc0841bd0, 0xd7e530c2, 0x10937c2c, 0x33e5e315, + 0x550f204f, 0x8c1f0d62, 0x2854ee10, 0x0717691e, 0x806f9cec, 0xc9c2f035, 0x645512e2, 0xb89a402f, 0xad90f3b1, + 0x4bf1132e, 0x5f31c7e5, 0x59c481e7, 0x82edbd3a, 0x95df3356, 0xb41366b3, 0xf3237b30, 0x5e32c1a2, 0x8d6067a8, + 0x67b1bd9b, 0x16ad767d, 0xf45dc905, 0xca48217b, 0x0a89791c, 0x548e69cd, 0x1b5e7fba, 0xf5fc1db9, 0xbc50826e, + 0x951877c8, 0x75f56964, 0x56f294a4, 0x736561ae, 0x6131e0e7, 0x86102682, 0x7b717c48, 0xb29586ca, 0xb50152b4, + 0xfc423773, 0x5198a1f8, 0xe4bbf8e2, 0x3d5514c1, 0xcce0c137, 0x7141587f, 0xa69ab46d, 0xbdfa6f7f, 0x6a369965, + 0x7dee7dfd, 0x48930d8f, 0xc1274e0a, 0x31f1eb6f, 0x3aee7fac, 0xa9d72807, 0xa7e8ec06, 0xe650fad6, 0x2b720e4f, + 0x40cef4ea, 0xa1becfa2, 0x9fa195c2, 0x10b838f3, 0x6f9fb79d, 0xdcd6c98e, 0xda5c108c, 0xcbf0a012, 0xfae3453c, + 0x52d730d1, 0xdacdf664, 0x122acfe2, 0x898be4a2, 0xb3f87cf0, 0x76d67c0c, 0xc17b45cd, 0xe556386f, 0x32c32e43, + 0x68b98449, 0x3798ea23, 0xd2aadaa5, 0x97b6a746, 0x894a5898, 0x459e6b9d, 0x4d21e3ae, 0xd051fa6d, 0xa0aeba59, + 0xb72b8d3a, 0x3d11469e, 0xf98918ba, 0x9c796608, 0x1b6e6b0e, 0x93474858, 0x3757987a, 0xb841d050, 0xc6584320, + 0xa00cddd6, 0x46966e79, 0x0915d1a0, 0x6179dc3f, 0xf5cda526, 0x90fd6149, 0xb0aae590, 0x66876c63, 0x8b0b489b, + 0x13f6f67e, 0x9c063326, 0x23d65f21, 0x5620923d, 0x403498c2, 0xf76de9c1, 0x54aedd69, 0x985ae7cf, 0x534c7084, + 0x886ed084, 0x88702520, 0x6708356f, 0x6e77ca06, 0x38f5cef1, 0x3be9e246, 0x1f47c858, 0xbbb14219, 0xc34ed05c, + 0x3cb832d5, 0xe859faef, 0xcb000a16, 0xce2787ff, 0x62efec8e, 0x3a2be460, 0x4b27368b, 0x90b83fe0, 0x8abc442f, + 0x3ee7423e, 0x7e7c104b, 0x9f7b82f2, 0x66ba76de, 0x95cddba1, 0x3919fb15, 0x47dd0407, 0x46445f97, 0x0e914fef, + 0x81d0cf13, 0xe9d3802f, 0x01574bac, 0xa14618c5, 0xf7995d58, 0x6c6ee7bc, 0x9d86ba3b, 0x810d3277, 0x676cf1fc, + 0xb9623a96, 0xae2ba649, 0x5f92dc67, 0x90972ede, 0xa947be62, 0x71288f2a, 0x90d222e7, 0xba63e054, 0x864ea9b7, + 0x9921b3ca, 0xcc1abbfa, 0xf876b331, 0xc18eeffa, 0xef65ea70, 0x53700e89, 0x6be343ae, 0x58b35e32, 0xc8185c40, + 0x0ecf0d50, 0x05b0e6c9, 0xc508de76, 0x9edad763, 0x457e233c, 0x653d4ad3, 0x8c57c47d, 0x77d7ae7a, 0x2256fa38, + 0xeb55c1c4, 0x4a4ec74c, 0x5c8444f3, 0x93f5d14c, 0x5b9f426a, 0xad7f772e, 0x4257466b, 0xdb9d2098, 0x22190a47, + 0x8bd2e1fc, 0x3a769c68, 0xdc71752c, 0xbc9867aa, 0xb96c2848, 0xb31b2ffd, 0xbaf10d56, 0x50cd0ca6, 0x0f24d693, + 0xe038397c, 0x79188a67, 0x06236a7d, 0x22330e30, 0x18e493cd, 0x838c19d0, 0x9789e68c, 0x6bf3f512, 0xd736ba7d, + 0xc7273164, 0xf8ade1c6, 0x48b5cc3a, 0x8df3949d, 0x7ea57d6c, 0xc55bc20f, 0x2dba6c52, 0xba2b39ca, 0x8d4efeb4, + 0x731033d7, 0x29ef4224, 0x035c8f98, 0xf02d01ca, 0xe8373100, 0x90acd0f9, 0xf813add3, 0x75af17f5, 0x2c880653, + 0x996d4151, 0x74c3761c, 0x59e6b2ba, 0xc27289e4, 0x17981edb, 0x0f7df220, 0xe0791b9d, 0xf77c19c5, 0xbc5d27c1, + 0x7198f555, 0x8627db96, 0x1f94f9a0, 0xff9c1e38, 0xe2460f09, 0x37dc53ab, 0x246363cd, 0x3e6b8bd7, 0x947f28aa, + 0xe7fbaa34, 0x43ed1417, 0x9e98e0ea, 0x8d391c53, 0xaa054159, 0x53dbd6c0, 0xbca3f131, 0x4960438a, 0x8e882e18, + 0xe0cf2bd8, 0xa002c284, 0x8d9b4aef, 0xc0e9fa9e, 0x9f5ad4f7, 0xae3c953d, 0xe8cbcc56, 0x76f36d97, 0x19d4bc05, + 0x9f4cf444, 0x5c4ce3a9, 0x50954393, 0x41ec3bc0, 0x09ad5ea6, 0x135692a7, 0xb7b8cf51, 0xcf26b580, 0xba2008c6, + 0xc6bcd262, 0xd2a4fa95, 0x7aec76ca, 0x9dafa0a9, 0x6d9af017, 0xc5fe4490, 0xa20ffaa9, 0xaa6bb56f, 0x0bcfcccf, + 0xb8be3090, 0x117754fc, 0x15080d4f, 0xc483df6c, 0xe17117e1, 0xdcf51ba4, 0xf0525583, 0xd98b1508, 0xb27bdc9f, + 0x2530cdcc, 0xf0e6b8d5, 0xe8ddcc93, 0xbd69acb6, 0x4d4e55eb, 0x75e198f9, 0x334179d5, 0x7f772ecd, 0x2a447ed6, + 0x0b1b19ff, 0xb71996e4, 0xc5b41015, 0x4c450b60, 0x433630be, 0xa3780674, 0x39ebf554, 0x3f6bd02f, 0x29b02fb3, + 0x0224d296, 0x0ed085dc, 0xcd64274f, 0xeb5332ee, 0x8d167b2a, 0xbce082d1, 0x8496c7c8, 0x0b1beafb, 0xe82401bd, + 0x900dedc5, 0xa155b72d, 0x810549e7, 0x7ffdd303, 0x45dcc624, 0xc56c284e, 0x683ca7bd, 0xc960b7e7, 0xcc47379e, + 0xe9b80655, 0xa521cf7a, 0x0ed59046, 0x1cc39a12, 0xdc989774, 0xc46f26ca, 0x952f7ece, 0x17218f8d, 0x03800688, + 0x29165072, 0x86100e91, 0x3fb9b3a3, 0xfa1e7978, 0x7b71c804, 0xbb61a4e2, 0xae075007, 0xa2040455, 0xb3ec1148, + 0xec15904c, 0x838606a4, 0x7d77128c, 0x0da68b35, 0xa654004e, 0x00d1a591, 0xc8b861b2, 0xc67d96fe, 0x56a70aa7, + 0xc7813bd2, 0x01e85490, 0x44b958d5, 0xed3c5b05, 0x082b6403, 0x7f3ea69f, 0xc79ec0cc, 0xedbd1f2e, 0xc06fc295, + 0xb67e9c70, 0x4887b327, 0x5e00a41e, 0xbbfc2435, 0x3e4b27b4, 0x79b36c30, 0x9e2da824, 0xfea4fdcb, 0x8cecd548, + 0x2e559a37, 0xb20bdb91, 0x2e1780d2, 0x79fa1aa4, 0x58119b52, 0x402f8541, 0x27eda479, 0x08f8fdcb, 0x39709ab5, + 0x6fdad74c, 0x5e978035, 0x24cb278a, 0x9d05d495, 0xb60010cb, 0x934c0880, 0x710fd5ce, 0xdb747415, 0xf225ba65, + 0x96fce90c, 0xbd8466ff, 0x28c2f6df, 0x3b401a00, 0x9fc0ed66, 0xa80d284d, 0xedc034d2, 0x80de83de, 0x999e3ca9, + 0xf4834785, 0x6a689ffa, 0x359beb0b, 0xd955199a, 0xf497231b, 0xea88c399, 0x626443fa, 0x5ec9a4bf, 0x7a8f7b26, + 0x455041c0, 0xd8d86a17, 0xa456e4f1, 0x9624854c, 0xa112c524, 0xb2296870, 0xac08f39f, 0x19287b7a, 0xf1c00ee9, + 0x49ade321, 0x8b104574, 0x9f241dac, 0x411bb176, 0x425f4334, 0xadc12c87, 0xda04ff15, 0x92430556, 0x9b342387, + 0x2b467746, 0x5ad4e850, 0x9dce16fb, 0x5a28efad, 0x38e71fa9, 0x05433d3d, 0x84fa935c, 0xe67ba2c0, 0x1e0e1e19, + 0x6bddd6ec, 0x5fa62fd8, 0xf1efd4c8, 0xc7e4a87f, 0xaab89b41, 0xca2e7e9a, 0xeefa19e5, 0x3f1eec82, 0xa15d556a, + 0xd478c2db, 0xe48fa1cc, 0xcbc55f79, 0xd99542a9, 0xdac55cf6, 0x8d8aad6c, 0x528a6748, 0xdb00c5a4, 0xd9f32d0b, + 0xc55df5d8, 0x23b6c379, 0xa4155d79, 0xd3593488, 0x9d6dec77, 0xc6c77d66, 0xe51c4a27, 0xd6120f94, 0xe84a1d4d, + 0xb049aa63, 0xda82dbe2, 0x4526a9a3, 0xa8d41817, 0x23192b5d, 0xb06b48f5, 0x1869b5f2, 0xe60187ac, 0x06cbfa7f, + 0xe5df7a26, 0x3488c6d7, 0xb1eedf86, 0x17eee813, 0xb343e32d, 0x026f3778, 0x3c9dab4c, 0xdbb18137, 0x7e0fbcc5, + 0xed70cf39, 0x5ca0e6f3, 0x1f1467ec, 0xe1c92656, 0x4c22a065, 0x308d2257, 0x3152e2da, 0x510f65d1, 0xa0476032, + 0x3ced34d0, 0x35391abc, 0x563cd093, 0x0cf0a70d, 0x3be64848, 0x53f5fea6, 0x762e2a3b, 0xe46bf1f7, 0x67ebac24, + 0x601ad5be, 0xb27a7c7e, 0xc1d464cf, 0xe1d8c79d, 0x9c169833, 0xed56275d, 0x1a7010d3, 0x7a355b0a, 0x5194db1c, + 0xeedf02f2, 0xe3355c48, 0xa1c2d785, 0x4300cd8b, 0x58883c78, 0xd69b9673, 0x9795d182, 0x6254275c, 0xc9969dbf, + 0x2bdb8b77, 0x3c78bc38, 0x64d86a83, 0x8cb8f3d8, 0xb393fbc0, 0xae9a72e6, 0xfa97a442, 0x1128d27c, 0xb6ca42bf, + 0xacf091b3, 0x537e67fe, 0xb1e2951d, 0x41ecf101, 0xa542dca3, 0x6dd692b3, 0x47835569, 0x6e2488d2, 0xaaa6e4b1, + 0x61e3f0b6, 0x63f119c6, 0xfea36336, 0x15aa2648, 0xa65b8df6, 0xa5fab023, 0xeee2549a, 0x283d0ef1, 0x0b2655dc, + 0x6f2c0b19, 0xf04acc2f, 0xba155a8b, 0xdcefe864, 0xcc2344e4, 0xd8dfd006, 0x00e58732, 0xe0f44f5e, 0x81c32233, + 0x78592582, 0x93a778e6, 0xb4937f94, 0x43850bc7, 0x6d7725a5, 0x41110654, 0x41bcd65f, 0xe0b94ce6, 0x7bfde306, + 0xcf94bb87, 0x0f154dbe, 0x9b892b7b, 0x9d75622f, 0xd8dad0c6, 0x73e07744, 0x5c600af5, 0x31fe4820, 0xdd8ae108, + 0xbb4307e6, 0xe80c9ca2, 0x0ea3720a, 0x666b2496, 0x9dce9000, 0x70451e93, 0x3be6f1a4, 0xa4419ce6, 0xdfed4e8a, + 0x7da27a83, 0x693a4915, 0x565be48e, 0x4afbe531, 0x2487e5da, 0xad4a6516, 0x3594875b, 0xbb74a6aa, 0x7777b307, + 0x31678301, 0x77cd56f1, 0xeecaf994, 0x7034427a, 0xa5a3ee03, 0x30c37429, 0xae67f58f, 0x16da064c, 0xa98004d3, + 0xfb7424ef, 0xad45e4ee, 0xc5c42106, 0x02a32efc, 0x2cc7e0b4, 0x8cc01f7d, 0xd1032edb, 0x6d9eae0c, 0x84c1423b, + 0xb1293f6f, 0x8dde2abf, 0x16bc9706, 0x444426dc, 0xe4106c64, 0x27be2c12, 0xec0a176b, 0x715e6a56, 0xa8ba6b94, + 0x4fa335aa, 0x381de6c6, 0x5c8c069d, 0xadb960e5, 0xacc505e8, 0xc01b7bc1, 0xa925f295, 0x2eb003ad, 0xfdcff642, + 0xc9c27003, 0x47fd254f, 0x9449e25e, 0x93363985, 0xec2d91b9, 0xf4efbd4d, 0x54028b28, 0xb57be9a4, 0x866a6748, + 0x6b901e1f, 0x4d78473f, 0x5565b0dc, 0xbaa779fa, 0xd6f80ca8, 0x92cbdc93, 0x2a065850, 0xf59bdc33, 0x830a4520, + 0x283239e9, 0xbb125cb2, 0x01b8071f, 0xf74a6f4a, 0x87c90d14, 0x4844df74, 0x0064592d, 0x0522df79, 0x72bcf4d7, + 0x0a2c76ce, 0x14b050ec, 0x57aee901, 0x8f08e487, 0x6f74d0f7, 0x13d5591f, 0xf38507df, 0xf25772e1, 0x07f312f1, + 0xaeb0b3b5, 0x0fd1afea, 0xdd3e31a7, 0x45266ec1, 0x66471e91, 0x449c14f1, 0x8baaf9cd, 0x75169bf3, 0xd422087c, + 0x78583d25, 0x3098ad2f, 0x481bb765, 0x1150a59f, 0x1f2bf3ea, 0x18a3fbff, 0xd32e37b2, 0x1df29949, 0x15883b0c, + 0x9b366d13, 0xe5d1bc56, 0x1e5e83c7, 0x9eb95019, 0x541f3d1c, 0xd421ff34, 0xa57069f2, 0xb4c9315a, 0xb00462f2, + 0x64119da7, 0xccc48c78, 0x159fb46f, 0xe9f52c66, 0x8b66d41a, 0xf026f3db, 0x33c80322, 0x41980d1c, 0x3f4fdd66, + 0xea7ec4b2, 0xb3a179a9, 0x5948a825, 0xe2a318cb, 0x2f6f83c9, 0x3b6317d6, 0xa1681ec4, 0x60b97373, 0x9e0ddaed, + 0x07dd36c3, 0x274dd34f, 0x504c2730, 0xb5611e83, 0x21304f28, 0xaf056822, 0xbf941304, 0xa696e447, 0xeb6ab8a6, + 0xcdc79615, 0x69fcbbb0, 0xef75070e, 0xbbb06a3a, 0x33404c87, 0x1376d26d, 0xae98cd6a, 0x5f835698, 0x74c5634a, + 0x7c439ae8, 0x9936bb8c, 0xa04a7465, 0xc82b71d4, 0x13e5cb14, 0x31c5e0df, 0xfc9bca5b, 0xdc58dec3, 0x5a1cdb1b, + 0xcf73c622, 0xa058722f, 0x4e3e1848, 0x003f007c, 0x04bc2c60, 0xbf8fb39c, 0x17d35942, 0xc040f3af, 0x0b9d2ce7, + 0xcc681fd9, 0xdf420863, 0x6a1fd340, 0xb3081815, 0xd25c28e0, 0x0b83736c, 0xfe8296a0, 0x632a6e28, 0xf8aed631, + 0xd91bafc9, 0xd620b775, 0x3db6f350, 0xd437fade, 0xd5dfc0a1, 0x309c1d0b, 0x57cd57c5, 0x58772a27, 0x50fa5ddc, + 0x2373c497, 0xda549202, 0x2af5b4ae, 0xf95872fb, 0x69a9256d, 0xdd9703f8, 0x6b6973f8, 0xf1d036fb, 0x77289ab2, + 0x7bc8d79d, 0x90100a1d, 0xc6698fc8, 0x2086d247, 0x6c6398ca, 0xfc2a0050, 0xe1bd11c8, 0xd9f1c28e, 0x2e70562e, + 0x389bfa59, 0xdb67b155, 0xf2cc259c, 0x4657927d, 0x8c1e670d, 0xa5050265, 0x21c8fc9c, 0x96a690e2, 0x0857e774, + 0x9adce949, 0xd1936e9b, 0x3a8e6794, 0x6d08399d, 0xd5afa1f5, 0x88a96e87, 0x5e0223c1, 0x6ce427dd, 0x4171b477, + 0xd9d467a9, 0xe60f3218, 0x56c287fa, 0xbbd51646, 0xa41ebf7b, 0xbdb57bab, 0xf9705464, 0xafd0762b, 0x1e78c252, + 0x1e6a3947, 0xff5e86b5, 0xcc0d35d2, 0x23e4a6c7, 0x8c4e454a, 0xeb935930, 0x5d8814bf, 0x3d963448, 0x5764a358, + 0x2a471509, 0xbef3d9b0, 0x138bd92b, 0xbe9c738f, 0x097396b2, 0xb2f01f49, 0x4e819cc7, 0x805217ee, 0xb23e8c7f, + 0x6ed62608, 0xad0c9729, 0xc69f4739, 0xfb0fdf37, 0xf90d678c, 0x57008cfd, 0xe4342b8a, 0x4c019fd2, 0x66c0e970, + 0xff289fc8, 0xf4ab7aa8, 0x1864a59d, 0xdc2addef, 0xdb0a050a, 0xe462b4c3, 0xae4bf63b, 0x894ae11d, 0x5d570ea9, + 0x7ec7d415, 0x47857fd6, 0x926bc002, 0x7d286b2f, 0x7fd57460, 0x0ae08713, 0x8e66798d, 0x43562ae1, 0x66297497, + 0x6e2dadb1, 0xdf59d3ea, 0x97650986, 0x51ebedff, 0x0f954631, 0xab8670ce, 0x14e6a0bc, 0x5f44efc0, 0x044e5e73, + 0xf13ffc2e, 0xcca3cb70, 0xf4ee52d5, 0x67f1b63e, 0xf6c50f54, 0x527550f9, 0x0d98b354, 0xd48559d9, 0x5addc942, + 0xac77fe0b, 0x95bae2cc, 0x9b39433d, 0x3419459b, 0x00c7e67f, 0x7682f027, 0xaf0d726b, 0xf36a6f2f, 0xf94fe6ca, + 0x8bb5d3f8, 0x29cacf18, 0x77ec4185, 0x1daba7e5, 0x163294c9, 0x353a7e31, 0x0697de31, 0xbbe9d897, 0x46555f65, + 0xb69424df, 0xbd7f403f, 0xd704592d, 0x108fb6ce, 0xcae12d0e, 0x69e12e72, 0x2fa359c5, 0x7186a49e, 0x0d2bfc9e, + 0x6b877a08, 0xd7eff2db, 0x094f37a5, 0xf247c8d4, 0x2437c270, 0xea8419e0, 0xaa421eac, 0x3054f33b, 0xb9bb45c5, + 0x01aceb0f, 0x2aa69e70, 0xc02a3cbd, 0x41121c4e, 0x023e65dd, 0x16995c5a, 0x1458b2b7, 0x28090d7e, 0xd039d202, + 0xfc896234, 0xc85d0894, 0x19372d74, 0x2549aa94, 0x279a9999, 0x8896e20d, 0x854612bf, 0xe0dafa31, 0xbffe8e61, + 0xc48d0d64, 0x27c60ddf, 0xd194578f, 0x3b943c5a, 0x367cfaf2, 0xa933a11d, 0x251a9947, 0x01cf0d9c, 0x305ea5e4, + 0x85144634, 0x6a6a29e9, 0x96b5477b, 0xc26d0ffb, 0x95e9c609, 0xab0adbf9, 0x51cd7e89, 0x2a402047, 0x2d6406f4, + 0x7db04a21, 0xd736127f, 0x0017c03a, 0xc98c977a, 0x0b2a803c, 0x8a911c7f, 0xd26fbb3b, 0x26e76bba, 0x0f80c6b8, + 0xe2e35ec0, 0x0e1dfae2, 0x285da58f, 0xad47d9a2, 0x917db7fe, 0xcad8b8b8, 0xa8286992, 0xfcb5d0c5, 0x58fed610, + 0x3f9a02c6, 0xaa06b261, 0xf78aeae4, 0x4c7195b6, 0x4da51cba, 0x9c791fe7, 0x0746eeb0, 0x621df261, 0xcb85cf63, + 0x9cfd5795, 0x6bb364ae, 0xe713c53a, 0x37771ffb, 0xe8019cab, 0x58ba3736, 0x231a116d, 0xf09d0c7f, 0x2d4f8847, + 0x5f841cb5, 0x1241f448, 0xcc861c78, 0xd6ded3d8, 0xfcc4e1d3, 0xa6316844, 0x765fafdd, 0xd6eb5bc5, 0xa693f2f9, + 0x37c2bfc1, 0xf185b5d1, 0x3037e769, 0x79f0cc6b, 0xfa8eaf60, 0x36f98dcc, 0xe0b0ad28, 0xdbd9c841, 0x7b094600, + 0x3cfa4130, 0xfade9bc6, 0x3a2fb9b3, 0xbef4f67c, 0x690bb9f7, 0x4aef7df2, 0x5d46bbc2, 0x6131e23f, 0x56267276, + 0xf5a18998, 0x23d7c9d6, 0xbe241b80, 0xe575ea5e, 0x20defa64, 0x393a74d9, 0xb70bd3b1, 0x11994588, 0xd0c5e614, + 0xb23a9622, 0xd87f8cef, 0xaf395c9a, 0x8072a36d, 0x2b5a8e1b, 0x15d7513d, 0x7150d81d, 0xe7e17ba6, 0xef79a8ae, + 0xf90ea04b, 0x95f62631, 0x167f314a, 0xf29087a8, 0x757afdb5, 0x5a7a06b6, 0x0a2ad025, 0x7855af06, 0xa3d8ecda, + 0x01826806, 0x43acf8e5, 0xad9eb4fc, 0x7842edaf, 0x7aa13261, 0xeab8b207, 0xd0996daf, 0x0b447097, 0xc9a40541, + 0x52f98441, 0x3a65c406, 0x9ac2633e, 0x8ef64ed4, 0x8b33172c, 0xf9bf6617, 0x755fb457, 0x9efff501, 0x3826506b, + 0x11e8558d, 0x8b0f41eb, 0x6b8b6443, 0x08fe1678, 0xcafbcad8, 0x7f653966, 0xd8fdf80f, 0x35c29376, 0x42e132ee, + 0xe3f7e141, 0xab4a07dd, 0x7986f261, 0xd84eca9f, 0x4bcd5142, 0x4174a455, 0x395f4430, 0x0a318f4a, 0xa1c49924, + 0x95994e4a, 0xc60f0c07, 0xe5d0adda, 0x32cbc958, 0x6e8204ef, 0xd9e89840, 0x9761af0e, 0x9985dd7d, 0x0b08dd99, + 0xe6055b5b, 0xc5cb2131, 0x1060eb28, 0x0e9d478e, 0xa661d3fe, 0x22c7cadd, 0xc5cd1ea2, 0x7b4f2c83, 0xa17e5dc6, + 0xce9ef9cc, 0x5edf20ac, 0x43495336, 0xea88ccad, 0xee4d92b8, 0xeeb1559c, 0xed1fab74, 0x9d017cf8, 0x69e82098, + 0xb39199d8, 0xe3ecd40c, 0xe30b1209, 0xf8281367, 0x42563033, 0x289373e9, 0x0575563a, 0x828b28d3, 0x5c2927ba, + 0x8cf65821, 0x6f9619a9, 0xd7ca75dd, 0xb0fb76d7, 0x3c4c0cff, 0x3ec70315, 0x64edafcd, 0x3db0037c, 0xf14029fc, + 0xdf81977a, 0x24bbe272, 0x9dad08f3, 0xd04bafe7, 0xc484bdcc, 0x0b398423, 0xde92a1bc, 0x5b8110d2, 0x843f95d8, + 0x7f447588, 0x945c6806, 0x0f69dc2a, 0x5f3b5bc0, 0x5df253a4, 0xc0b23881, 0x45ea8c23, 0x525a7895, 0x69483ee1, + 0x7d182730, 0x611b9d43, 0xcd1e4b45, 0x23f039c5, 0xa27bb450, 0xd790d60a, 0x8efac794, 0xec2e4d44, 0x8158fabf, + 0x894135a5, 0xc4a3e17f, 0x0ee32f3b, 0xa8ef6ea9, 0x47771489, 0xcc55be65, 0x8b3903e3, 0x06641798, 0x209c47a3, + 0x665b039f, 0x603aa105, 0xfedfcd55, 0x78f79cc1, 0xdf905497, 0x60dfc2f7, 0x52275608, 0xee4a81f1, 0x7338556f, + 0xe48a51bc, 0x67dd7e19, 0xc272e2e2, 0xa268340a, 0x71c69c87, 0xf6c9098a, 0x72980ce7, 0x8b7e60f2, 0x58fa7f78, + 0x7f66a669, 0x5decf2dd, 0xc1006988, 0xf84fa08f, 0x18271ce9, 0x3dbaa0fb, 0x8cbf5b6c, 0x95acc498, 0x080ff42b, + 0x88b64e19, 0xc4928f3b, 0x15e560e5, 0xb3895b68, 0x875c02b0, 0x4a0f7d4e, 0x0bcb6a4e, 0xa840f800, 0x3756437c, + 0xc788b777, 0xf372b4ee, 0xe912c267, 0x25ce9ca4, 0x966d8af5, 0x5b73e95b, 0x28a7af59, 0x95e725dc, 0xa7b2c543, + 0x3120b20e, 0x2c425573, 0xd5635161, 0xaca43418, 0x683be2b6, 0x1ed0308b, 0x94cb43e9, 0x0ead1c0e, 0xcdfdf88e, + 0xabfdf333, 0xaf063ad4, 0x1d189d96, 0x3fc17267, 0x6bf1bdb8, 0x06926526, 0xad21877d, 0x2e2f2ec2, 0xdf1a085d, + 0x358d13bb, 0x75bb659b, 0x23cf8151, 0x954ffdc6, 0xaf98ae6e, 0x36ad5f3d, 0x4e4a38af, 0x2e192c54, 0x7b3545bd, + 0xaf727ccb, 0x319d4270, 0x4e6e9db8, 0x442e1be5, 0xee606e24, 0x490f3784, 0x2c4c7ab6, 0x5910fc4b, 0x9b5c4c07, + 0x03aae4dc, 0x97803ed2, 0x0836c983, 0xb59c4153, 0xdd65492a, 0x0ebf6720, 0x984026f4, 0x13b3687f, 0x4c4880ef, + 0x24a99b9a, 0x69055728, 0x2a13bd6f, 0x692417f2, 0xdfe14110, 0x328f77de, 0xe6cf15a9, 0x96c8d3ab, 0x4f15d398, + 0x817ac66d, 0xc6ab686f, 0xf7703439, 0xd295a41a, 0xf9b31fe1, 0xb989fe8e, 0xf69c9e19, 0x40fa64e9, 0xc1e49835, + 0x344683cb, 0xf5eb21a5, 0x0a548ba6, 0x89a45bb7, 0xdb040b3f, 0x250d2b7b, 0xaed14d75, 0xff40596b, 0x4b021812, + 0xf3f21ae8, 0xd222cdfc, 0xd4812489, 0x6b114775, 0xe5efb5d3, 0xd8f65b61, 0xba6bfca2, 0x84ba737d, 0x984989fe, + 0xb8879466, 0xd06e7236, 0x8d3ad3f8, 0x2af91851, 0xcb7226d6, 0xd8125aea, 0x12f8c323, 0x2dc332f5, 0xabb5e8b8, + 0x65b341fd, 0x55bd7867, 0x206bad51, 0x0bcfeb61, 0x52dcab74, 0xa4917372, 0x8667a247, 0x3d6e83c0, 0x24bea030, + 0xaac33012, 0x64dc514f, 0x18dd20c3, 0x02f0d9d2, 0xecd137ce, 0x2524411b, 0x5bacf81c, 0xe01ce0e7, 0x0b660940, + 0xead4d1e8, 0xcdbcccd5, 0x8022f704, 0x5b20ef3e, 0x33ec746f, 0x3ddc1e2f, 0x83ebdae6, 0xc0dede94, 0xfd227b20, + 0x20c7777a, 0x65201308, 0xbeae69e3, 0x12603900, 0x55dac511, 0x209eed22, 0x3199d74d, 0xf580b384, 0x1add85f5, + 0xafda0336, 0x2c08a564, 0x03c35fda, 0x99575710, 0xe76461ba, 0x02912cb2, 0xcbefe1f1, 0x716c2ebd, 0x0b1643c7, + 0x21823823, 0x291b55b1, 0xdd0fea40, 0xeed77969, 0x959db2cc, 0x5e6ff62d, 0xcd2f0ab1, 0xc1d78f16, 0xbb4a68ad, + 0x81fefee9, 0x0dfbd716, 0xfa85ddd8, 0x1674d1aa, 0x63a14172, 0x15de1b6c, 0xea57d43d, 0x3335aecc, 0xccd796ac, + 0x315de7ac, 0x2e20d5d4, 0xc412803d, 0xef90c947, 0xc3f064a9, 0x39839f4f, 0xabc0beb9, 0x4fb3e3ef, 0xe64861bd, + 0x248b7c0a, 0x8f9e5a6c, 0x19b6c4b1, 0x3d98c371, 0x22f5448f, 0xc3de3b50, 0xe1beea15, 0x420f70b8, 0x3b57b7fb, + 0x032bcdef, 0x1fa217b4, 0x64fc2d67, 0x485be435, 0x465144ed, 0xf949dd6a, 0x0cf7146e, 0x7f56a120, 0x6b9001af, + 0xbbf53c10, 0xd0dbc5fd, 0xb4d3dbe1, 0x739e9998, 0x866e12c0, 0xd651c2b2, 0x617fd24d, 0x02f2e7b1, 0xfa56a67a, + 0x94a0bbdf, 0x267f1d9c, 0x632c42cc, 0x7e84e512, 0xa80ed7bb, 0xbf1fa696, 0x00d0016c, 0x50b2eec2, 0x967c1a74, + 0x3905151e, 0xf4f5d6de, 0xfc071930, 0x26490690, 0x210aba63, 0x0135ecc2, 0x1470b745, 0x87154564, 0xa53947fc, + 0xcda5cfeb, 0x40581e02, 0xd81f9018, 0xdafc6dce, 0x504e5608, 0x27ce910e, 0xeda8637a, 0x251dda01, 0xd16e3acc, + 0xa30b9af5, 0x4f51126c, 0x196dcf55, 0x565ea8f8, 0x653d9d4f, 0x34ac04be, 0x16be37e8, 0x1dfc13fe, 0x880f6168, + 0x798a4dc5, 0x74b23197, 0x5e09ecba, 0xc1306912, 0x6e18dadc, 0x82399771, 0x7e692e39, 0xda17c88a, 0x37d419fb, + 0xf65f0d7a, 0xf74ba728, 0x41972248, 0xc8604b85, 0x9ccbd6a3, 0x003098fc, 0x5048838e, 0x621a2aba, 0x7681d711, + 0xa6538799, 0x2697fdcd, 0xff1c5ec0, 0xae8e4b65, 0x4fa1db6e, 0x33465b46, 0x29117dcf, 0x2a4e5fdd, 0xbbabbf92, + 0x8afaff8e, 0x11edf1dd, 0x73d91d02, 0x38b4fe83, 0x5702bf31, 0x67deb0d2, 0x11ab59e9, 0x4ae91933, 0x089a4c96, + 0x4498bb97, 0x3e2b8a00, 0xcbaae95a, 0x9f6758ba, 0x35723dfd, 0x4eb1f976, 0xa6b9e187, 0xb58b4b4f, 0x3eda0032, + 0x556dc5e1, 0xc68f278a, 0xdb4c4b4e, 0xa022a37d, 0x25a332e8, 0x0cca5cc6, 0xa16abc28, 0x6f8e3231, 0x0b505ca7, + 0x962eebed, 0x8a7b2fc4, 0x43866a50, 0x225b2729, 0xa30cc365, 0x295a46f6, 0x495b6b24, 0x02b20939, 0xaa33e4a5, + 0x6ba8a01c, 0x8f6cd0d5, 0x39cf40e2, 0x479ff15c, 0x800dfad8, 0x58a693b5, 0xe60f2536, 0x12b3c859, 0x1c3a4189, + 0x6b32ba21, 0x1d5de349, 0x46512a34, 0xe76c262d, 0x558262f4, 0x4c9ddce8, 0xedeb1ead, 0x721f2860, 0x2279e40f, + 0xe661400e, 0x5e4b80e0, 0x34e51fda, 0x1208c4ab, 0x2c84490e, 0x5e679756, 0x97adcd63, 0xe8f0f6d9, 0x87f88ec8, + 0x16c3eea6, 0x0d18e635, 0x3061a324, 0x2d1c04e4, 0x60a9b93e, 0x5c4de19a, 0xe66bbdb3, 0xf9b6931f, 0x9775ec0b, + 0xccc4b37e, 0x91305b9e, 0x76d989e3, 0xe8e964de, 0x5db55632, 0x0aa25f4e, 0x0d9869d6, 0xd98b7ab3, 0x3140372e, + 0xc6ca0bdb, 0x6bf53528, 0x53b36556, 0x241b632c, 0x12dd748a, 0x14661abc, 0xe87bcd8b, 0x4e2c334c, 0x8597cfde, + 0xd0f7a7bc, 0x458e4cb9, 0x3a0821bb, 0x86821066, 0x73d9bbab, 0x563dec8e, 0x04c49304, 0x29d96de7, 0x7a5f2210, + 0xb48c0318, 0x28fb0a16, 0x0952ffd4, 0x7b33e836, 0xb0b50012, 0x907c2958, 0xdcf2efe9, 0xb76ffe7c, 0x85db81cb, + 0x117e6b03, 0x19975074, 0x124adbb3, 0x3b39f4f6, 0x15600106, 0x93ac393f, 0x0fb33aa8, 0x435eea26, 0xa980f493, + 0xde7ab30d, 0x138e177c, 0x3d103cc3, 0x6c5d1890, 0x56fc747f, 0x24d170e5, 0x0bd5e57d, 0x9f16ebe2, 0xc5794f6b, + 0x3cf36b7c, 0x42dd25d2, 0xc72ca8b9, 0x47fae398, 0x8b49e3fa, 0x7fb59f6a, 0x3e325d87, 0x929c44ae, 0xd12b4555, + 0xe743fdaa, 0x64c4ea50, 0x1d1dac6e, 0x7c05a4fd, 0x762c65ed, 0xc56d8ca1, 0x554ad866, 0x532eafd1, 0x00a8e220, + 0xb8d85b3f, 0xb0244abc, 0xb91dec85, 0x804d8681, 0x32e0eada, 0x6d153708, 0x66fe2e81, 0x3f5a6a1b, 0x1713ef7c, + 0x40df5f8e, 0xd5af4966, 0xae5928f3, 0x4919af57, 0x4377065a, 0x82a61cf4, 0x1be3f97e, 0x0b7bbd6e, 0x5bd2985b, + 0xdd448282, 0x65a7ab0e, 0x7f432b64, 0x856ac6fb, 0xbc301f94, 0xe3807e92, 0x65a4087f, 0x26078a4e, 0xd702c5c3, + 0xe6dd58e1, 0x249bcf4a, 0xcb476407, 0x1bbeaa28, 0x155e4949, 0x70d041f5, 0xb313163b, 0xb5710d4b, 0xeefd7301, + 0x0a29907c, 0xa458d935, 0x7b77b563, 0xd8ba39e0, 0x649af2b4, 0xd3861191, 0x1fa8ac60, 0xa1efe6bc, 0x9dd5a6d0, + 0xe95454ba, 0x89c613ca, 0xd39042a6, 0xf414ba44, 0xcecde752, 0x2bfd5553, 0x3c682d8d, 0x6dbdf807, 0x63d894d5, + 0x0b9b8d94, 0x6b348334, 0x88c25c9a, 0x0f4b28e7, 0x97c6eb97, 0x3b165539, 0x5da3bda7, 0xcff24827, 0xb4713919, + 0xab06d16b, 0x8bea19e7, 0xbd00ea14, 0x90daf473, 0xcee22857, 0x168406fe, 0xdc86c1b7, 0xf525d53b, 0x15a6939e, + 0xfdf510ae, 0x304b38d5, 0xd52f7997, 0xa71c2cff, 0x1fea9bbb, 0x825ceb06, 0x5e64bf65, 0x6bf3484f, 0xc651ce36, + 0x475c8ac8, 0x2e706782, 0xf014d714, 0x8c6b9db9, 0x3cad00b6, 0x6a562c80, 0xc8329188, 0x844c7356, 0x5910bb9a, + 0x1896e7c4, 0x243c6de2, 0x40d3a105, 0xa76129b9, 0x04732d25, 0xeefbf74f, 0x6370999c, 0xc71223fc, 0x0e98bf02, + 0x54b7f735, 0xea038f41, 0x96a76cad, 0x3a3fd45f, 0xed012c1a, 0x807e5505, 0x7da903e8, 0xe06044a7, 0x73556de0, + 0x9f1d1461, 0xce06bc15, 0x7a8e6cc9, 0xef57c07c, 0xa783b3a2, 0x5a8be336, 0x3f2b3e74, 0x17045a26, 0xab5268de, + 0xb04bc465, 0xa2517d52, 0x17a0e024, 0x907c9ab8, 0x6dff057d, 0x260b0b04, 0xb4e3b1d0, 0xc7d79708, 0x9a5a2ca3, + 0xe1856e64, 0xee567fdf, 0x85727f63, 0x88fe1c53, 0xfec39454, 0x43baa763, 0xa7c21c61, 0xd07562d3, 0xa0cd39c6, + 0x3d8987fa, 0x7e31fa68, 0xfc69ede0, 0x00db5359, 0xcfec66ea, 0x717ffb6c, 0x7019269c, 0xe0441948, 0x167e1a7a, + 0xb4c4eefc, 0xb061a2ff, 0xd62c6aef, 0x61c1340c, 0x0c628d56, 0x92524083, 0x560d0e57, 0x9eb96186, 0xba4f38e8, + 0x1c5c3063, 0x2f78ea20, 0x10c40c13, 0xc4816ebc, 0x1d3117c3, 0xc22c6a7d, 0x0fd6745b, 0xe8da9e4d, 0x0a3faee6, + 0x9f653917, 0xd6f03f47, 0x432a7d50, 0xadff9e3f, 0x8708a6bd, 0xd5ff9375, 0xf0d8c749, 0x69e71fac, 0x6e5e0a0b, + 0x9178393b, 0xc116250f, 0x46c1f5b1, 0xff539767, 0xce0ef017, 0x618b73d0, 0xc15eb8eb, 0x0b092bcf, 0x4d3dc230, + 0x4841dc35, 0x66d07ae9, 0x9cc80cb1, 0x21686623, 0x39bcfe27, 0x1c33e091, 0x9e76d223, 0x582d177c, 0x49a833ca, + 0xb5507935, 0xe4a482f7, 0x7f0f9ddc, 0x6a082707, 0x83b8c398, 0xcfd906f5, 0x92994d04, 0xf3f01e1c, 0x2c5e2360, + 0x675c466d, 0x723c7d7e, 0x1135c4bb, 0x090dc476, 0xe5511c83, 0xae654701, 0x8a8f89bd, 0x7a822bb0, 0x5d27ac4a, + 0xd7c3e093, 0x17b2cddc, 0xa0ebc523, 0x069be16d, 0xd8ee9c42, 0xcbca5b58, 0x6966026b, 0x8d8a9768, 0xe6bbcc0d, + 0xdd46ee97, 0x232752e9, 0x51f4dbab, 0x21839d98, 0x6c073716, 0x920a6a4d, 0xa5ab247f, 0xbee7782e, 0xa693ec15, + 0x49c3cc1d, 0x713dfa60, 0xe33280c6, 0x61e3b1f9, 0x1d9af274, 0x22938cf6, 0xecebf5e7, 0xb4b5aa95, 0xa50afd8f, + 0xe78da5f3, 0x5617b5cf, 0x4e153ad4, 0xc7c261d0, 0x1cb36786, 0x4dc3c2a6, 0xea7f599c, 0x5c109fb4, 0x572177d6, + 0x793101c1, 0x936fcebc, 0x0995d0f7, 0xcedddd67, 0xf90bb2b3, 0x1b229051, 0xc521591b, 0x977ac09e, 0x4ff8c29f, + 0xe48873a1, 0x4e49d5a0, 0x11aa2041, 0x333c6773, 0xcfc79467, 0xce0b916c, 0x31d171f4, 0x354b5cf4, 0x67badbb8, + 0x20bdfdf0, 0x7f0bf5cd, 0x01097c24, 0xdb3e9630, 0x1660513b, 0x92aa7845, 0xa812a2da, 0x5b5e2f8a, 0x904f3672, + 0xbc613c38, 0x978065e1, 0x3992abbd, 0xbf88abd6, 0x4ece560d, 0x482fd3c4, 0x6a506052, 0x7a865849, 0x6fcb9170, + 0x2343134b, 0x3a89ae44, 0x15d0d286, 0xf85a18c4, 0x13020d65, 0xa49c1bf3, 0xf8a4b43f, 0xae51a100, 0x5c6c97d3, + 0x4164d0f1, 0x31ba5088, 0xca9d80a5, 0xef326690, 0xea369b9c, 0x0498b3d1, 0xa0de2d8e, 0x9f9a6720, 0xab3e88c3, + 0xd973b346, 0x4d386569, 0x70b2d18c, 0x60f59464, 0x5dbf69c1, 0xc44ea813, 0x6ff9b76b, 0xed0aa722, 0x59beb004, + 0x814c6a6e, 0x5f0b6f58, 0xc0bd4b59, 0x09d63074, 0xe59f34e9, 0xd25ef8a2, 0x231c5ad7, 0x83d3af43, 0x42e72569, + 0xe74c1d11, 0x05ad7ede, 0x502ed4a1, 0x04982d54, 0x9b845462, 0x80eeaf9d, 0x01c31411, 0x96d530ac, 0xa04faa17, + 0x9107a9a0, 0xfac43073, 0x008c142b, 0x67929880, 0xb7e84110, 0x6ccb2c3e, 0x0b5f4a85, 0x1b6ce391, 0x1f60ca89, + 0xe1f979b1, 0x8f720931, 0x3ce63dcb, 0xa3206c2d, 0x534b90f6, 0x71ca3fb0, 0x9a59ada5, 0xf237f73f, 0x07e97973, + 0xc2ec4ad1, 0x0d26e63f, 0x3886019d, 0x60eafb27, 0xba1d053a, 0x80beac38, 0xbf389605, 0x25a731a4, 0x061272ea, + 0x991b5ca6, 0x01f76fa5, 0x910d8c1f, 0xe95996ce, 0x54781f74, 0xab652801, 0x6a036ad3, 0xc91221dd, 0x7b7161a7, + 0xbc1c25ca, 0x38bda16b, 0x1be353c3, 0xd0765fea, 0xfafcf95a, 0x5a6a2901, 0xf438f559, 0x5219bbf8, 0xdd443b33, + 0xa4fc9be7, 0xb7219592, 0x84f1bd34, 0xd15a55f5, 0xa90aacd7, 0xe535ef4d, 0x2fdceb00, 0xd6118e89, 0xfa47d341, + 0x4dc08de4, 0x6792cc68, 0xde8870ca, 0x319da886, 0x69e4de36, 0x937e1e76, 0x919131f1, 0xfeef6651, 0xe87010b9, + 0x3d5af0f5, 0xbf4ad2f5, 0x5c3c709a, 0xe87721c2, 0x50e580fb, 0xcc97348e, 0x8884c2ff, 0xd4aef499, 0x2a63f2e3, + 0x66db5211, 0x05ad1d3b, 0x51edbd49, 0x2ea8ad6d, 0x4d75a915, 0x85949d9d, 0xd374a5ec, 0x1512d3c7, 0xbcc3baf9, + 0xecd1ef5e, 0xfed3b59f, 0xa791dc30, 0x4e202e45, 0xdb06bac2, 0x480869ed, 0xdc730065, 0xfeeed036, 0xce6e90ed, + 0x759d008d, 0xf18e9913, 0x000a44a4, 0x1ef400cb, 0xa1474230, 0xdc78869d, 0x65ce02e7, 0x90f2790c, 0x93631f60, + 0xd8d7cfe2, 0x9bacd4df, 0xc27415d5, 0x991f3cfa, 0xc9559e78, 0xd03f53dd, 0xdc3f563d, 0x7b0e75b4, 0x56dbd812, + 0xfe534b6b, 0xafa6cdb5, 0xf935d671, 0x8a508bd2, 0xf577ddcf, 0xe6d83d7b, 0xaea91b9f, 0x2120bec9, 0xb95aff45, + 0x14f62478, 0xd6155fa7, 0x5e65ac68, 0x33eb45cb, 0x7c5513f9, 0x71850418, 0x2392a1a1, 0x61f85848, 0x0f8e7edb, + 0x4fc7ef39, 0x3d4f7963, 0x9a730f74, 0x0c108e26, 0x1b5709fb, 0x3860b089, 0x521d70fc, 0x95b359bb, 0xbc6a0446, + 0xb3b3173c, 0x3a53259e, 0xc3ba0420, 0x26472e6d, 0xb27741ef, 0xe70d4b6c, 0xbdb03a28, 0x67772f39, 0xd90e11a4, + 0x8156a4d2, 0xa2e36855, 0x17a52b33, 0x7c5ef25a, 0x57e0fbdc, 0xa950c1f1, 0xf9940d57, 0x9d28874c, 0x5faf4e42, + 0xc95ddb46, 0x8dd45252, 0x962ad4f0, 0x41d06f82, 0xb7723926, 0xf6c5afbb, 0xd98302b6, 0x6524d620, 0x19b61793, + 0x72d648de, 0x6fda512a, 0x9032943d, 0x030a5d85, 0xb903b312, 0x056d951e, 0xe1740ba4, 0x8a686d2a, 0xea995ec0, + 0x6d87a149, 0xfd1d0137, 0x5e9fcfca, 0x6c87fe2e, 0xbfeda2fb, 0xf97be6dd, 0x6971b065, 0x75cb668f, 0x1aa7b3af, + 0xcc1ac0e8, 0xb3caee5f, 0x978ea4b0, 0xd97bacb8, 0xcc87b172, 0x71e9b8ed, 0x262aa2cf, 0xd0fbfc8c, 0x6e7192d6, + 0xf4efc174, 0xf04cf777, 0xa52dcad2, 0x2e6fc5d5, 0xfb2ca2ef, 0xdfe9b02f, 0xf8372f93, 0xcf2e670c, 0x5355c589, + 0x17fbca30, 0xa6c604d2, 0x8839e488, 0x438679f4, 0x263a993f, 0x4477a52b, 0xd3e10429, 0xf0e0535f, 0xa0408688, + 0x54d1cc40, 0x9a723cb4, 0x0e971dfc, 0x01647d21, 0x8ea8702b, 0xb7a3576f, 0xf942e13f, 0xef08997a, 0xbe91049a, + 0xa43711f8, 0x242c5ab0, 0x49ea42aa, 0x8ddc30a1, 0x50d9faa5, 0xda8317b3, 0x2ff8d31e, 0x018df9df, 0xaea9fbef, + 0x23fa7bc3, 0x1ff10cdc, 0x059b074e, 0x9236e04f, 0x406d8d9a, 0xa95f7852, 0xd5a66904, 0x8bf86b0d, 0x6c4b4a1c, + 0x4e49b8d9, 0x4afa3445, 0xb830f86b, 0x73142940, 0x224df3ce, 0xd1cee4d2, 0x2ffc463f, 0xd0a373d1, 0x62983244, + 0xcc70ec5e, 0xdb2ab276, 0x7b5d685b, 0x31e9b61f, 0xf151cd2b, 0x4b477473, 0x8988c697, 0x41e27c8b, 0x33822550, + 0xd874ecdd, 0x69503750, 0x5f76e25b, 0x27f035b2, 0xe788e86a, 0xdf2c17f1, 0x78390bfd, 0xa2f242fe, 0xe24838e1, + 0x40ffe986, 0x66d24b91, 0xfb01d988, 0x76151ba8, 0x05208bea, 0x578dc7c6, 0x5f79459e, 0x12fd7076, 0x89625fa3, + 0x13ef7192, 0xd6dd2576, 0xaa30ff88, 0x006eca2c, 0x58bbc5fc, 0x1c401369, 0xde23d4dd, 0x696ecbe7, 0x857266fd, + 0x9777e964, 0x05b748ec, 0x00ee4342, 0x986e98a4, 0x34696d4c, 0x19f024e4, 0x160fd4dd, 0x405e551a, 0x9cb794ba, + 0xd46d1b3f, 0x1aa0e4e4, 0x65cf069e, 0xe1291110, 0x1c54cf59, 0xb6180682, 0xf1104331, 0x5c72d2aa, 0x5435d850, + 0x2af1fbff, 0x159a9637, 0x080d9fa2, 0x1c0ea713, 0x87784ee0, 0x2bfe1ed2, 0xaf1d91de, 0xe1dd7fb7, 0xbc0dd93c, + 0xdf1c8b0b, 0xb9178248, 0x550c7e64, 0xa23dffbb, 0x21b968b4, 0x242a3b8f, 0xc52cba31, 0xdab54a69, 0x8464e94e, + 0x15c18cf9, 0x3ff9cbbc, 0x52e2ed3f, 0xf872dfcc, 0x45f4f40a, 0xe9012865, 0xa630c159, 0xdb1a0a55, 0x7fa3aa97, + 0x93c1ca69, 0x63fe6799, 0x5ff44a44, 0x4e9b416d, 0xfeb4aadc, 0x0f3ee46a, 0x8123925b, 0x23e0869d, 0x7fdce526, + 0xad29747f, 0x71b0db2d, 0x0d4e8569, 0xffd98709, 0x7abe475c, 0x5a54a537, 0xa3b856c4, 0xf9cf419f, 0x9ebed049, + 0x8b21a27e, 0xc4cb60a3, 0x5db1f91d, 0x40094360, 0xe3a07d4e, 0x3da27d36, 0x4b25a2ad, 0x54c802e8, 0x449787c7, + 0x77a4267a, 0x9dd52c92, 0xbd27e5d1, 0x428c8118, 0xd96dc70b, 0x0974c30a, 0x8dbf16b2, 0x64d5977c, 0xa3290902, + 0x5842adb8, 0x4f30a85f, 0xe0962d60, 0x7ce634a2, 0x25d64db9, 0x8b878fd5, 0xeadeb850, 0x002e0842, 0x6b3d6631, + 0x369ea3ae, 0xf6b28a9e, 0x3966bd0d, 0xfbdedb02, 0x4f495bc1, 0xc2da6ae6, 0x7c8bb7ae, 0xc7c3ae81, 0x59f616f1, + 0x29f0b244, 0x74336197, 0x2135f9b0, 0x1da9dc55, 0xb12886fa, 0x43dd07b7, 0x0e7c32a6, 0xbd60f33e, 0xcc904670, + 0xaa87dda1, 0xb9b4d82a, 0x0864e939, 0x1caf1e11, 0x45fff168, 0x2190c038, 0x2f0880c4, 0x1d6fe994, 0xf1b364ef, + 0xcc2e8438, 0x3349d9da, 0xdebbb275, 0x2c9b313c, 0x28eaaf78, 0x609ca5fd, 0xc3733905, 0x09692296, 0x58a833f8, + 0x15f89ec9, 0x6e9734ed, 0xf2946fa4, 0x468f5d57, 0x3b9c1a12, 0xe7e70655, 0xe4bf3c06, 0x88dd1fa8, 0x4fbd06a7, + 0x3963b240, 0x7513cd4c, 0xf3deefa4, 0x4239fd59, 0x46d28e32, 0x6dbca7fc, 0x0987b786, 0x88fb5dca, 0xd3f67b3b, + 0xe5e689a4, 0x38226bcd, 0x9f86269f, 0xef639e71, 0x22eb3ccd, 0x7a573d04, 0x02610ebd, 0x1982b0ff, 0xbf728370, + 0xbabbca4d, 0x1cccee21, 0x740c99e7, 0xc4560ddc, 0x3ab9ef95, 0xd9dd1825, 0xf7dfb9b2, 0xd36c4434, 0x5fbbf7f9, + 0x33c55418, 0x0697abb9, 0x86c52c31, 0xfabb9dd5, 0xc2151983, 0xf53c39a5, 0xdb129c50, 0x3d1c2fa8, 0xa23781c2, + 0x03934390, 0x10efc078, 0x0500d80c, 0x57075b0e, 0x30ad9500, 0xf0672894, 0xe6572382, 0xbf278ef8, 0x27cfbfe6, + 0x7907516a, 0xc175074d, 0xa41165fd, 0x443819cb, 0x65416f62, 0x48e9667f, 0xdc625b26, 0x8ca6f031, 0xcd89c931, + 0x97fbd1a6, 0x3742233a, 0x82559612, 0xca57c679, 0xa7f2a28b, 0x9cf1acad, 0x836075a7, 0x827b59c4, 0x6814f704, + 0xdd0ddc78, 0x83d55307, 0x9cb218f8, 0x110a9356, 0xb5e8e3ca, 0x4819a6b1, 0x95eb3907, 0x78f10360, 0xdb49555c, + 0x85a21cac, 0xaef50e49, 0x165f9030, 0xb216cc20, 0x6f87ebc3, 0xda19b3d3, 0x21813d5d, 0x3c840c8c, 0x4193829e, + 0x5a7785c9, 0x49baf372, 0x08a68b87, 0x3196f41f, 0xb7493372, 0x13f191de, 0x410761e3, 0x1c448e44, 0xcd1988cf, + 0xe2e9498a, 0x71d55015, 0x613582f5, 0xb6408365, 0xf564e2b2, 0x264461f6, 0x43b70a76, 0xdb436bce, 0xdac16af9, + 0x34b28657, 0x3ab48934, 0xff22ea0b, 0x95f535b4, 0xd2e5c543, 0x275769d2, 0x3585440f, 0x0ea2b875, 0x9f699a41, + 0xa3e5f676, 0x969303a2, 0xef828e35, 0x333bdab1, 0x798c1c2d, 0x6526cf7b, 0x2ebcdff5, 0x490fd3bd, 0xa3df1237, + 0xf9c92cdc, 0x8c4386c6, 0x06b86ede, 0x27549694, 0xb5cdc4df, 0x641e1252, 0x6ea655cd, 0x0c6f1abc, 0x3a46bc95, + 0xa990a968, 0xc9c49e9c, 0x3c935a93, 0x76984fe2, 0x903d095e, 0x651a99fd, 0x4eb943bd, 0xb88948ae, 0x5c496f61, + 0x5bdc7749, 0xa1742c34, 0x087d74a1, 0x461ec75f, 0xebfc886f, 0x4407f334, 0xee64aecc, 0x4a3f23d7, 0x44d80a85, + 0x107f355d, 0xfbf0440b, 0x377652f0, 0x54f5321e, 0xc6bd48c6, 0x7abc3ad5, 0xae0e71cf, 0x37ad7e75, 0xe0b53faf, + 0xcedeecfe, 0x78dd45b2, 0x559d8161, 0x1f4c5626, 0x1114ff58, 0xabaa8533, 0x4c3d8ca6, 0xb599dd84, 0xc94d187e, + 0x55265ba0, 0xde8b90d2, 0x9a1d8da6, 0xfd38768a, 0x9c21876c, 0x49b07ac0, 0xa93774d2, 0xbc7348a3, 0x485b592c, + 0xb8cc396b, 0x68d8ab38, 0xf055a7bc, 0x36de7325, 0x6f0d4ef2, 0x3a1fb083, 0x07aff521, 0xf2fc216b, 0x71c3cf7b, + 0x8a727895, 0xe0bdec0e, 0x162a7c86, 0x9681bb82, 0x05f73fe0, 0xc599d5c6, 0x6a7272bd, 0x4d25c6e3, 0x3668b969, + 0x86414589, 0xcd2471d9, 0xb9244745, 0xdd09e4c8, 0x1c19d4cc, 0x65613461, 0xe159ef86, 0x40474dee, 0x035dc59b, + 0xacc2de3d, 0xc418f6e7, 0x8117e750, 0x392d62dc, 0x1e8764de, 0x73369fc3, 0xd9e02896, 0x00b384a8, 0x5f19c928, + 0x199e0f2d, 0x9ba5bfc4, 0x953c9149, 0x50335dbb, 0xaca2466d, 0xc4acdf91, 0x325d6acd, 0xa71b646a, 0x9578b67d, + 0xfcfb0ad2, 0x4c871b63, 0x01dc9184, 0xaef32636, 0xca4c2f42, 0x63649733, 0xcbd2d6b6, 0x6165303c, 0xc5393aaa, + 0xc02c15a9, 0x82d5e934, 0x5e93ee33, 0xc9713ded, 0xf1dff5ac, 0x02353021, 0xc11902b0, 0xea2c3cbe, 0x2450d406, + 0xe6e73618, 0xe70ead0e, 0xdb24ee20, 0x573be60b, 0xf6648f13, 0x57358886, 0x0ac78206, 0x93b08600, 0x592e6c45, + 0xdf39ca70, 0xdc945515, 0xbd8fc3c2, 0x118a8d86, 0x39abf414, 0x76baf17f, 0x289126f6, 0xb4fbcae5, 0x8cc3d9ec, + 0x05157f80, 0xa7b565f4, 0x160375c4, 0x3dc4e6d5, 0xdf3e7353, 0x0dc3fa45, 0x2253dd50, 0x9da0fa14, 0xd62940d9, + 0xa101cc04, 0xc5309b61, 0xd96bb491, 0xf9300f88, 0x76e2ff35, 0x56d7fbaf, 0x75b283dd, 0x71c50993, 0xba5049a3, + 0x8ed54446, 0xaeb6a94b, 0xa227c6cf, 0xaa88a224, 0x9272c1c1, 0xfddf51b1, 0xec136cf9, 0x18b18e1c, 0x5fb7d308, + 0xcab7bdf4, 0xb4bc1315, 0xc48d454b, 0x889b63da, 0xfaae8dbe, 0xca0fea60, 0x3c0a02eb, 0x14936f58, 0x92088e6c, + 0xe8ba582a, 0x43dc6825, 0xd61d8db4, 0x2ff99581, 0xf3e78dca, 0x2498e0f7, 0x79b50a25, 0x185716f9, 0xb4b4a828, + 0xa7fce0c0, 0x83deae38, 0x25405098, 0x8c6ff1f4, 0xf515e837, 0x053da957, 0xd5a2bbe5, 0x77eda5c7, 0xeeb06e7e, + 0x8c38074f, 0x3e9e2703, 0x694f677d, 0x303b0dd7, 0x4e1d4506, 0x0c625c41, 0x34aa0f85, 0x62aefb92, 0x689d5334, + 0x95de46dc, 0x74dbd7b7, 0xffa353a0, 0x359c9d7b, 0x2cd867ba, 0xc92b930a, 0xca304585, 0xa1f5e983, 0xf397dbdc, + 0x5d4933cf, 0x32e54b7b, 0xe8a607ae, 0x0f7138a6, 0xd5d1a287, 0x39632a70, 0x03dfcd59, 0xfe11e3a3, 0x6b4f3eb7, + 0xce9d7976, 0x4345feef, 0x31b67965, 0xe7ccfb2b, 0x45fbd884, 0xc3d2833e, 0xcf14db2d, 0xc8626acc, 0xedb10044, + 0x9d51c249, 0xc1b3f91a, 0xac539fd8, 0x0c882a70, 0x7066e727, 0x68bec4a4, 0x2c9a3c4e, 0xacc3c824, 0x73df1659, + 0xf517d6fb, 0xafc694d7, 0xc01c3ecc, 0x2945cf25, 0x3cac9688, 0x207a9c82, 0xe76e613e, 0xc91e954d, 0x5f987ed3, + 0xcc5b32cc, 0x51470cb6, 0x0357b16c, 0xc4ddb253, 0x521b001c, 0xbf78145b, 0x967bef04, 0xb9fb14a6, 0x1fd3629d, + 0xaf64d079, 0x8c7d75c5, 0xaf0b87ed, 0xd1b4fe92, 0x07e093c2, 0x6dc319d0, 0x9cb45571, 0xc6704ac5, 0xcef53826, + 0x86336eb7, 0xc8622777, 0xef96c666, 0x5538df3e, 0x2babc004, 0xbaecc497, 0xac02259c, 0x73c64a66, 0xfd30e20f, + 0x9a5f0b95, 0xa1471301, 0x09d8f81b, 0x5630f7d3, 0xf523f2be, 0x8eeba68e, 0xc10c69ae, 0x1473b46a, 0xb015523f, + 0x76dda95d, 0x5e606194, 0x9b875641, 0xa1ec16d3, 0xbbe68ac7, 0x11e19b7f, 0x10538f3d, 0xcec6c33c, 0x26a3ef4c, + 0x1ed08596, 0x3dc5ebf3, 0x1ffbe1e9, 0xd3a70a9e, 0xdb5299ab, 0xa93d7429, 0x78d55bdf, 0x52919c2e, 0x353dc50d, + 0xa83b9a86, 0xa6c0339f, 0x901f4b6e, 0xac3b929f, 0x966f5f54, 0x4c66c3b2, 0xe1a73781, 0xaac3ba28, 0x611f227d, + 0xb1b1bbed, 0x747495f1, 0xb86c49de, 0xf1af6c9b, 0xd3d670a4, 0x215e8564, 0xf9e83080, 0x4643dd0a, 0xa46547a5, + 0x9e4e2fdf, 0xad22facf, 0x098c7027, 0x168e5ac5, 0x3b8be059, 0x2d55a323, 0xee40e25d, 0x82087d68, 0x659daac1, + 0xcc0225b9, 0xab798336, 0xb97a4c74, 0xbe621f55, 0x87969848, 0xded97931, 0xd8352e1a, 0xa48ec998, 0x84726e66, + 0xa4f9e948, 0x9bdcab0e, 0xb1172348, 0xdc41cd87, 0x6d677788, 0x370a02bb, 0xd9db3bc4, 0x333d2668, 0x5c178ea8, + 0xa0532e4b, 0x709fb684, 0x06b7d7e8, 0x782dd600, 0xdbf06809, 0x2eaf8da7, 0xfac48840, 0xee32c273, 0x289ac41f, + 0x0908973d, 0x5e014de0, 0xb7850a4e, 0xe0c71afa, 0x183d8db2, 0x6fec2f20, 0x688ba6be, 0xfbe9eda8, 0xbc3c54ce, + 0x09de568c, 0xc01b6ee2, 0xbf57aba6, 0xb2ee5479, 0xe626c9df, 0xb08fc9d5, 0xdc0eb28d, 0xb065c730, 0x41d0b329, + 0xcf6a3562, 0x52b8d1e6, 0xc3879bd2, 0xe1210fd0, 0x73b47f4f, 0xd02ccd4e, 0xae20b342, 0x75f87ca7, 0x25aaad02, + 0xff31f7b1, 0xeee41eda, 0xfdeaf1e0, 0xff76c0f8, 0xa06aa9a8, 0x30c52fba, 0xa018e72c, 0x7b878e69, 0x28ae616a, + 0xdcec8761, 0x92c87497, 0xe0fde579, 0xf13f993f, 0x4a2ca5ae, 0x8f47aa3a, 0x0724f040, 0xe705653c, 0x468a4802, + 0x2801f096, 0x1cf225ca, 0x236f4292, 0x3420e994, 0x596488ea, 0x07ee9043, 0x5da3049d, 0x9e81929c, 0xe90a58e2, + 0x13a644fc, 0xe0da7ff4, 0x35b86250, 0xbd4c2802, 0x6edb2c85, 0xe7b806b6, 0x9ad27bc1, 0xb4076c12, 0x0340ab42, + 0xe4c5bf82, 0xc979ae3a, 0xdfb89759, 0x64393c0e, 0x6e725e62, 0x401afee4, 0x05af606d, 0xb873a4d3, 0x82facfcc, + 0x8bbff973, 0x5e47ce92, 0x9c5809b9, 0x748e2810, 0xfe87def4, 0x69e21b5f, 0x40b86415, 0xcc4b6ca6, 0x0a0cfed2, + 0xf4f21788, 0x18aa9ae4, 0xe391b41d, 0x82bb9feb, 0xa5a21a94, 0x5f72fe7a, 0xd1a8e524, 0x38cdd55a, 0x0a0a9409, + 0x2cb7b71d, 0x676e0fb0, 0x6b1f5d9b, 0x5ba783c5, 0x88933f15, 0x567f5306, 0xdaddb896, 0x3a65de9c, 0x15064c06, + 0xd6d2848c, 0x9d942473, 0x74e18d0a, 0xa8230f36, 0x8edd2c15, 0x7748e074, 0x7ee051f5, 0x36300a91, 0xe4912d18, + 0x01240d53, 0x761ed9c8, 0x69d0b2dd, 0x4bbaf49b, 0xf2577935, 0x97fdfcc4, 0x3f37acd2, 0x32a2625f, 0x286c3d76, + 0x530f1b2f, 0x54b08606, 0xe4580824, 0x1267ea80, 0x8ca4f6c1, 0xcc0f719f, 0x9d1a190f, 0xde89c67f, 0x0fe069ef, + 0x7bc62dd8, 0x3e64c9ce, 0x441343ca, 0xafe27091, 0xbd482c82, 0xd578c86f, 0xfe36c7af, 0xe9ed7025, 0x4f0ba5a6, + 0x006950cd, 0xa38f8d45, 0xb5120046, 0x1ff7b1ae, 0xc1927dba, 0xcff06555, 0x740f9ea9, 0xaaa9a002, 0xe6a18cb4, + 0x3c4353d9, 0xdb243076, 0xbc8cdd0d, 0x1d2457b6, 0x8058975c, 0x82b8c0c8, 0x7900b532, 0x7e4ff56d, 0xf87817c9, + 0x84f6ef2b, 0xb97b6e62, 0x268b1339, 0x608fb44a, 0x39f9d84a, 0x8d5c1403, 0xeff17dba, 0xc320ae40, 0x69e3c28f, + 0xa46c01ad, 0x5d580b99, 0x14ed4695, 0x8a47884b, 0x040362d5, 0x4e7db08d, 0x3ade4aed, 0xd0c195bb, 0x68c4a461, + 0x8455d368, 0xb9203568, 0x942d3b5f, 0xfa498728, 0x5d9eef51, 0x3749de79, 0xad2d1ab5, 0x00be10fc, 0x7be9d90b, + 0x99444d67, 0x34296597, 0x77a19a3d, 0x5d36068a, 0xf2e0d807, 0x8cc72867, 0x1afb0790, 0xf42ff642, 0x1263f8e5, + 0x05bcbf5a, 0xd1fe9ca1, 0x428dfcce, 0xcc480da9, 0x81d6d38d, 0xb6911d89, 0x70a8c80b, 0x05537bf9, 0x1dd59c0a, + 0x52d754af, 0xb5be6434, 0xee6bbb7f, 0xfcd2cb45, 0xbdeab73d, 0x1094901e, 0xfb79378d, 0x5b7224d5, 0xd28fe007, + 0xee739c80, 0x4633c2f6, 0x206d4940, 0x51c516f6, 0xc652e435, 0xeea1c5fd, 0xda4646c8, 0x1dad7e62, 0x7fbe236b, + 0x09b26fb3, 0x40d42af7, 0xf206ae21, 0xc24ea91c, 0xedff9a78, 0x5b64c700, 0x53081222, 0xfed1d569, 0x3663ac43, + 0x224c0a0f, 0x32b26f82, 0x359dbccb, 0x19afe96a, 0x1c4162e5, 0xb72e5ca8, 0x639b2bed, 0x59bf7d2f, 0x1ccdd6bb, + 0xbc5d9b8d, 0xa72362d8, 0x0cdf5258, 0x0633ea47, 0x2da9ab46, 0xf1369760, 0xea70e7fb, 0x1c14c4a3, 0xb14e380e, + 0x7e382ec1, 0xa75b2a20, 0x78b67ba4, 0xf7a78dd3, 0xb21381fe, 0x24074fda, 0x40608727, 0x5267d419, 0x8cedb4d6, + 0xee6ab8cd, 0x4506c3e0, 0x11ac809f, 0x18050ce2, 0xfbfb88f2, 0x59c0b123, 0xaf507d8b, 0x0bb24a60, 0x57941246, + 0x8b9f4322, 0x72ceb96d, 0xa16c3665, 0x188b92f2, 0x86f1a61f, 0xc1883a0d, 0x7c966eb8, 0xe109d60a, 0x252d3b75, + 0x26a963f9, 0x7e11147f, 0xda6a5446, 0xb1b60ce3, 0x447ff5d4, 0x10853f67, 0x43af1b32, 0x1d567b60, 0xaedd4d6b, + 0xda4cd1c9, 0x74f930a5, 0x25a74bd6, 0x60a39c2a, 0xf45907ab, 0x4528a27a, 0xdbd38ae3, 0x3f892cbb, 0xc20aef3a, + 0xc80cf0a3, 0xd1f3cf54, 0x1a6d4c2a, 0x61a60058, 0x789b174c, 0x4eb2a45f, 0x0cdebd3f, 0x0e044a20, 0x14b0b7f7, + 0x9b022462, 0x1a0a551d, 0x0d562b14, 0x32ba38e3, 0x8e8bea22, 0xce017286, 0xafae000f, 0x204be61b, 0x479a4948, + 0xfb3e6a74, 0x2eed72f4, 0x0d18b0a9, 0x75c92f8b, 0x44571b43, 0x210cf873, 0x27b5d26c, 0xf7416baa, 0xb0b137c6, + 0x30b1a12d, 0x8c0eb925, 0x97e59e38, 0x19dcedbd, 0xf06f2ec0, 0xbe537f18, 0x1076f316, 0x4aa3f764, 0xedf88ece, + 0x94972afc, 0xb06bc7f6, 0x29b8c632, 0x19251157, 0xee4df992, 0x36bd2d5a, 0x39c2371c, 0x7fb77e12, 0x0748a566, + 0x55aa91a3, 0xc7bc7283, 0xf1e93cf5, 0xcf79f4c3, 0x30e3cd0a, 0x32cd20fc, 0x2559d46b, 0x695211d9, 0x2f3ad155, + 0x18722463, 0x28f28a15, 0x431be40b, 0x00e32895, 0xca9e495e, 0x649a3feb, 0x6718434f, 0x4c003a8b, 0x488066dc, + 0xcf77d76b, 0x3056989b, 0xb7ae15ad, 0x25486eeb, 0x376f52bd, 0xe3bc751a, 0x51743e99, 0xb9d644ec, 0xdb8be70e, + 0x39c8fe09, 0x7f8a8a87, 0xca0c34e3, 0x09618adf, 0xbf772f02, 0xda9946c4, 0x3ce75d0a, 0x3f082b4b, 0x8faa965f, + 0xc9bd24f9, 0xb65fef9a, 0x9202d996, 0x5f65be38, 0xc86b1f31, 0x28c54ee4, 0x11fccfff, 0x9394ccc6, 0x8866c7f9, + 0x5959279c, 0x59375188, 0xe7d75cae, 0x08f6072e, 0x05da5ed1, 0x30a6ed65, 0x384913da, 0x5cbc2990, 0xae2251f3, + 0x8b9913b7, 0xe66cb0d8, 0x407cc617, 0xb41363f8, 0xc3642cbf, 0x400fbaed, 0xdfdc2db9, 0x19e83b75, 0xe4f8a108, + 0x6fd22d0a, 0x938311f6, 0x4ff0ec92, 0x45c1c765, 0xd4f606db, 0x16da2c5d, 0xc04f3632, 0xf3cbc130, 0xd0f15995, + 0x3fafb61f, 0xb1064484, 0xb739107e, 0x22557bd2, 0x6ba5151c, 0x14effd4d, 0xcb6d5b38, 0xe8629c15, 0x4666bf33, + 0x8932cb80, 0x587e2baa, 0x410765d7, 0x32d34d8c, 0x42eb1354, 0xbfef4129, 0x31aff0a8, 0xb17d0673, 0xb82d99ee, + 0xbc7d024f, 0x347cacec, 0x0d8f7cc1, 0xa6c75131, 0xb800270d, 0xc6cfc4ef, 0x820e555c, 0x547ccaec, 0x5d779244, + 0x17725332, 0x96cde1d2, 0x7d43737b, 0x9f6cd7c0, 0x24eec620, 0x9c5f5c5d, 0xa59ade59, 0x44dbc66e, 0xd40b1d90, + 0x945deb57, 0x5d6167f5, 0x483de819, 0x0b569ad6, 0x8ab00e9d, 0x67241de9, 0x7452c369, 0xbe43ab69, 0x8113745e, + 0xa2593b42, 0xa5203c81, 0x7544a3d3, 0xf920f156, 0x9e690637, 0x25bf0a6f, 0xd6eaca2a, 0x84b29488, 0x5d1ac768, + 0x239a0df1, 0x608c25e6, 0x9b879998, 0x17187e7a, 0xa2f6f3d9, 0x9b6b5b88, 0xb985c48f, 0xcb632242, 0x1fa50385, + 0x325ef1a9, 0x1e599ed7, 0x171d0bc0, 0x0458b6c7, 0x691c0c16, 0x1de346de, 0x7e1eca7b, 0x99d60cd1, 0x858af88e, + 0xc35e2262, 0x87039acd, 0xe4cde388, 0xbadc7211, 0xa9cbca6c, 0xe9727fe7, 0x0b863fa1, 0x17f85668, 0xb0b325a6, + 0xf6252c4f, 0x099562b7, 0xdf474cbe, 0x18599b25, 0xccc20109, 0x29e859c2, 0x34891c4f, 0x7cb3bdb1, 0x4f572eb7, + 0xb334796c, 0xe9b5bc95, 0x18d78e04, 0x0d66271a, 0xbe5f09cf, 0xc856a1f6, 0x9070a575, 0xa93c0bba, 0x462c57f5, + 0xb39cda64, 0x587988b4, 0x645722e0, 0x8e66c523, 0x4603c627, 0x1a9920df, 0x1c3b81f5, 0x4861a5a8, 0x9b3128f9, + 0x3a67f917, 0xeaea8da6, 0xfa8294f5, 0x80c633a3, 0x7cfb5193, 0x860a592c, 0xf0c192fb, 0x643134b4, 0x6b5d14a2, + 0x222d7e84, 0x3587bb78, 0x19dd3778, 0xd59ca952, 0x1b51652a, 0x57e775d6, 0xfbf06e5c, 0x37d71b82, 0x384d0efa, + 0xdd70c43a, 0xb7c0498b, 0x625c883d, 0xf7066b25, 0x2adcc37f, 0x5bdaa4f7, 0x35815c12, 0x533343d5, 0x442d18d2, + 0x09a9d4c9, 0x56c72c3e, 0x68c19d49, 0x261d17c7, 0xf9f692bc, 0x9f2b93b5, 0xf3d45124, 0x50131c51, 0xfab14abe, + 0xf833fac2, 0x15ba1e3f, 0x13bd4778, 0x921ad252, 0x4c2217b1, 0x30dd5a84, 0x751f56c1, 0xc5942ad7, 0x0252d851, + 0x027b6c4d, 0x42e449cb, 0xe61873be, 0x9f52e59c, 0x49e60bf8, 0xa77eb6b4, 0xc52acfaa, 0x11722647, 0x3e6b4954, + 0xc2dbff6d, 0x380c7087, 0x4afc641f, 0x440edf59, 0xa93abb3c, 0x8008683e, 0x8be5019e, 0x084eeed9, 0x19bd433b, + 0xcef52a61, 0x0f39150c, 0xf722ef8c, 0xa882ffda, 0x0bf6ee48, 0xabf2080d, 0x4efe7784, 0x8b571dad, 0x853784c5, + 0x8b7b9687, 0xbd103c24, 0xcdd2eb5c, 0x882b507f, 0x849338e4, 0x51e1e09a, 0x458d76af, 0xd1bbc6b5, 0xd0d51171, + 0x5e7fc061, 0x70f89edd, 0xab2e75e3, 0x0f7ee8f0, 0x16765b96, 0x9884e8a0, 0xad395299, 0x3b012b19, 0xc7f102d3, + 0x26ba649c, 0x2dbe7cb3, 0x8c3b1ae4, 0x1af6021a, 0xc0e84005, 0xc32e1475, 0xf131cc80, 0x97c8fbac, 0x3a7dbe12, + 0x2c2187fe, 0x14f44502, 0x92b6b15f, 0xb223215e, 0x9f70c0bb, 0x73e16c79, 0x1b008431, 0x00b3cb9a, 0xee29fedf, + 0x0559d351, 0x8de1c356, 0xb15e5ee1, 0xf420a27a, 0x37682d90, 0x31104343, 0x9f6f3f0a, 0xd61ad5b5, 0xee60027a, + 0x730df3d7, 0x4fed5054, 0xf879d7b9, 0x25d7ea92, 0xf829701f, 0xfc8d9c19, 0x5986c366, 0x54175fda, 0xb7fe776d, + 0xa346e163, 0xdcc63672, 0x03d866a2, 0x6d10031d, 0x9f2ba5e9, 0xa37b4332, 0xfd81c7d2, 0x0d2af085, 0xe6873bd4, + 0x4517ca23, 0xef2694cc, 0x9beee8a2, 0x08c28259, 0x409830a5, 0x8ea07f6b, 0xd1fff39d, 0x32fb104d, 0x902eabec, + 0x019627c0, 0xa7a9de77, 0x3b2c2809, 0x21ca5409, 0x3153ad98, 0xda79ef70, 0xfa5b64ab, 0x3bfe8861, 0xd1cc99c7, + 0x75670cb0, 0x5465e348, 0xc9ed775c, 0x98d19eec, 0x32e973d3, 0xb095910d, 0x7ca69f94, 0xca2f9663, 0xa81689b1, + 0xf80c7161, 0x1f9533bd, 0xc655abaf, 0x6a57a2c6, 0xe5637725, 0x992db4ff, 0x7e673554, 0xf77e332b, 0x110d2a8e, + 0xf91f0d77, 0xbf0190cf, 0x3f0421cb, 0xb6005686, 0x9f0559ca, 0x191dc68a, 0x21309f8c, 0x658ee55a, 0x53c7324f, + 0xa9b633c9, 0x54d0b396, 0xfd6c114d, 0x998b9e18, 0xf79aad0d, 0x64c59add, 0x6f24843a, 0xf1fcf5cf, 0x1de1a5d7, + 0x61064c50, 0x618f0485, 0x5243dc38, 0x8e921dce, 0x5904e59f, 0x80652e4c, 0xd91cf328, 0xf94a2015, 0x8bd7cb82, + 0x06aa3311, 0x1bb45924, 0x1b142547, 0xbea37b28, 0xf861a858, 0x94c343af, 0x1e02fc6c, 0x0f8602dc, 0x7b96b528, + 0x748de704, 0xea7edcaa, 0xeac76a57, 0x66689f76, 0xad93b52a, 0x0b45cecd, 0x8b34ab57, 0x86dff71a, 0x2325839b, + 0x8b7ec61d, 0x419c1b56, 0xd7d63d58, 0x11990ae2, 0x98c667e5, 0xef4846fc, 0x45c9b6c1, 0xc2419c8d, 0xa65c462c, + 0xaeeae583, 0x9e859375, 0x49d14dda, 0x3aa25af0, 0xbb0e4797, 0x0decbd6b, 0x9cdd074b, 0x99d6ac11, 0xd8bb320b, + 0x5147f8d6, 0xff53481c, 0x61b576cd, 0x7d5f13ec, 0x6855062a, 0x57b5951c, 0x8ce61886, 0xc415e864, 0xc981ea8e, + 0xa0c256b6, 0xe8b3fdeb, 0x56ce56b1, 0x8ee0de2b, 0xd345e77c, 0x6d2c4620, 0x9f6e44c1, 0xaaf3ca0a, 0x442c673d, + 0xee1a3c04, 0xc2da4bbe, 0x4c85b93b, 0x3ffdd11b, 0xbad78190, 0x584f8fff, 0x9bbfc16e, 0x0aeab095, 0xb2434589, + 0xefa73b77, 0xcfc04a86, 0x7df8547a, 0x1cde0866, 0x673172ae, 0x8dd24ed3, 0xb85c6e27, 0xa3ee2476, 0x09ecc397, + 0xbc31f9c1, 0x65852644, 0x12d30e43, 0x443c8611, 0x0c34d26a, 0x2c8913ee, 0xefd78035, 0x7763da7c, 0x6afb1d9e, + 0xda43de2d, 0x689a5aa6, 0xbf4d56e7, 0xdb2a7dff, 0xcc1dd17e, 0x144e5007, 0x86438851, 0x4d362e0d, 0x581190af, + 0xb14a47e8, 0x66302742, 0xe08c7716, 0x44b31d5c, 0xd3446571, 0x812e308d, 0x85a06f7b, 0xd826c8c5, 0x3d79ec6e, + 0xf339d089, 0xf5590b5b, 0x5447ceee, 0xee2abd96, 0x0c8f2cdd, 0xb61abf01, 0xa49ed423, 0xdd422c0e, 0x3e87423e, + 0xea64317c, 0xaaa0c8a8, 0x2f32d384, 0xbdcea858, 0xe0223968, 0xb774cc91, 0x45a22b00, 0x43d390fc, 0x79cb7ce4, + 0xf822a9ef, 0xfd364207, 0xa5e7cfb9, 0x323658a0, 0x19a87e7e, 0x69837002, 0xc311cb3e, 0xdaa777f8, 0x538436c5, + 0x6636d09d, 0x49c524d1, 0x7579e352, 0xb2393e27, 0xb793c9f2, 0xba84257e, 0x39fca6e9, 0xb21c6e37, 0x59b0c1e2, + 0x0f3a7a8a, 0x33789544, 0x75080e73, 0xbe21eb3b, 0xc2c37c9a, 0x9ee5d0ed, 0xabe4a0f8, 0xe6e9fc93, 0xbb57eeb4, + 0x50e3aa6a, 0xd91de30b, 0x259c440b, 0xb2d12463, 0x29df4d56, 0xea6d7541, 0x690c47e4, 0x11a15125, 0x91c1426b, + 0xfe473331, 0x22af7e4d, 0xef01ad10, 0xd4f81b48, 0x1051c40d, 0x91362896, 0x96d8eff5, 0xee7e3b99, 0xe27bc4f2, + 0x1f431afb, 0x4e136e92, 0x26ff6fb0, 0xb8b079ab, 0xfa26b3e6, 0xd0aa079d, 0xdb0bc731, 0xbc21517d, 0x070345b1, + 0x1ccded1d, 0xfc36c327, 0x629c9ff8, 0x3bcb231c, 0xa3b5f021, 0x268e4974, 0xf69f4880, 0x78a0a193, 0x977e36fe, + 0x120d74fd, 0xa7764d04, 0xb756902f, 0xcb5a4e0a, 0x696ae662, 0x600df81d, 0x31ac2b01, 0xb7a9dd6e, 0x050bd249, + 0x4cc2c9a6, 0x76afce94, 0x19ceef19, 0xfbd6ef84, 0xe3b18727, 0x17e90a38, 0x65bb50c0, 0xc287e60a, 0xd7f6cea8, + 0x3bbd9e06, 0xb29cf089, 0x441199dd, 0x89425fe3, 0xb90d7dee, 0x517bded7, 0x5467cfcd, 0x1762376f, 0x613674e7, + 0xf4e9bab1, 0x5cb86c4c, 0xaf75c160, 0x0ee20325, 0x0b3308b5, 0xe9202f0c, 0x1da08a82, 0xbff7d17d, 0x69f05239, + 0x336a7ea2, 0x60bbfb8e, 0xa4788930, 0x954f4ff2, 0x5fdf5554, 0xb040b2ae, 0xadf8a431, 0x65a0ebd0, 0x4a60ffde, + 0xe220ec93, 0x451f560a, 0xab5d3ab1, 0x74b390bd, 0x39f288cc, 0xb232f2c1, 0xcbb69bce, 0x0b59fc12, 0xba7e8ea2, + 0x837dd7f1, 0xb47ee40a, 0x8573912e, 0x36bf6b2d, 0x81fbbd6d, 0xc9527349, 0xb317db42, 0xa809afa8, 0x7b2e5421, + 0x2386d7e1, 0x6d45c0b0, 0x58482690, 0x7df04032, 0xa36bb0c6, 0x75f42435, 0x503080a2, 0x6695c293, 0x99e66347, + 0xcdb971b6, 0x0b7700f5, 0x06818acc, 0x4c5a20cc, 0xdf6d292e, 0x424978d1, 0x987039b2, 0x3a52ce32, 0xcc7b555b, + 0xeec166aa, 0x0022ec2d, 0xa0811156, 0xc0abb7d1, 0xc3a7d3d9, 0x022deb1c, 0xd8dd5f43, 0x532d483b, 0xa66304c8, + 0xd91fe114, 0x86617e70, 0x057b7fde, 0x646a6331, 0x32acfeca, 0x13a883cc, 0x4dd8f55c, 0x18d8cafd, 0x52d39ebd, + 0xbf59f863, 0x380dca5c, 0x34cbd0d2, 0x703353fd, 0x02db8804, 0x8e95dddf, 0x23830f90, 0xc91c41db, 0x97463310, + 0x7497f0ea, 0x4357f855, 0xe0808d8d, 0xa7cdd462, 0x243c491c, 0x50129349, 0xd19b9f18, 0x961431ba, 0x8282a980, + 0x2748c8c2, 0xaf91a2e7, 0xa5211300, 0x5992b88a, 0x3c05c5b6, 0xcdc2aa49, 0xb2e86041, 0xec214816, 0x21890e2f, + 0x97c814d7, 0x7d278895, 0xc95ae4fc, 0x2db50ef2, 0x6a50563a, 0x293d0f26, 0x80f2031d, 0x5556d5b4, 0xa7e24e6b, + 0xd3032f40, 0xf4289c82, 0xeb1d0e2a, 0xd47f9bf6, 0x132ee2c6, 0x4a690b74, 0x7ad2c14b, 0xcace105a, 0x0bf9ca44, + 0x0aedb2aa, 0x86eae09f, 0xd013f4ac, 0x1496f34b, 0x07b47c99, 0xec39934b, 0x885cbffa, 0xad55bf16, 0x8d11c421, + 0x5f9bc28d, 0x89115f90, 0xfe5e7ebb, 0x52a9191f, 0x64544d62, 0x735ec2ef, 0xb956dbb6, 0xc4d6b3f2, 0x04fd6b3c, + 0x226f3bd0, 0x2d9d5b85, 0xd6b349ea, 0x5f42ea90, 0x28a07de3, 0x9f29d3b5, 0x9c589ac5, 0xd964c2cb, 0x5f11ffa5, + 0xfd3dbf36, 0xd4186cac, 0x56af8703, 0xeeaad5a8, 0x0dbb6a1c, 0x1c327309, 0x4d64e3f7, 0x5f3a994f, 0xb4ccddad, + 0x2b38c844, 0x6530f46d, 0x1fb9a42b, 0xb8db736b, 0xef1b093f, 0xd033f67e, 0x1b2d3d0b, 0x1043279f, 0x448759f5, + 0xa77b3a31, 0xdd5f2a2d, 0x11040b33, 0x3789dab0, 0x1dd26b3b, 0xfd8e1869, 0x4ac24ad6, 0xa01f3fef, 0x8b2f6786, + 0xf9481182, 0x53072ce4, 0x89699fcc, 0x4cee78df, 0xc9f55fef, 0x9622046b, 0x9f258661, 0x269ffdec, 0x4a9c2452, + 0x4ddd3acd, 0xc049b7b6, 0xa39ca6c5, 0xc392855d, 0xbf3d291d, 0xb67c61df, 0x249de2bb, 0x420d5805, 0x883664cc, + 0x2beaf1d7, 0x2fd5f926, 0xa02b4119, 0xa7dd60df, 0x1171e59d, 0xf523d2ef, 0x4e7ca351, 0xeb4901c9, 0x6fa15112, + 0x2232e02b, 0xa8fbd328, 0xe7242021, 0xd9680f93, 0x2dbd7544, 0x9dce4cb7, 0x684a32d2, 0xcb947577, 0x9da89df0, + 0x3dd2ffa2, 0x14fab958, 0x42159344, 0x4f37919a, 0xba54fc1d, 0xaf966c7d, 0xa164e785, 0x41cc9b49, 0x231e0e90, + 0xa1661a13, 0x1fd192fb, 0x7e799366, 0x3b139c1a, 0xf22f60d6, 0x3aaac09e, 0xb6251a33, 0x4317f24e, 0xe9423dca, + 0x54ccffa1, 0x4a287c52, 0x7aa7e054, 0x9c76a740, 0x578b4abb, 0x13659226, 0xfe5053f2, 0x9cade552, 0x675b7e3f, + 0xb5442cb1, 0xb9219e7a, 0x297588e3, 0xfd3add3a, 0x3a41b356, 0x92db23f5, 0x690845b8, 0x63239d53, 0x6313c9cc, + 0x348c2ad5, 0xd1f89116, 0x7e2d6078, 0xe5f9631b, 0xdc320d00, 0x64d03e7f, 0xc22ef275, 0x1d15443d, 0xd8384525, + 0x3a1a5e82, 0x2aec51c2, 0xb925670c, 0x3cb39dc6, 0x6799e3c3, 0xaf36a62a, 0x9368ca5c, 0x57c1e9d9, 0xec8b6c76, + 0x52b40a9c, 0xe34f4078, 0xbe3509d9, 0xc2161790, 0xd799c67b, 0xc7fd8acd, 0x42dddfd1, 0xae9b1ed5, 0x4fda60e1, + 0x78ec576e, 0xf9ab3f04, 0x370adde3, 0xd457d0a3, 0x123277aa, 0x4c22d40a, 0x0897e8d6, 0x7a82ff45, 0xa5df1d65, + 0x3793ae80, 0x8573b5e6, 0x35c4af08, 0xcb4f14e0, 0x4cb0696f, 0xc0b5e3e0, 0x879f8e72, 0x47e50b9c, 0x7fc75cc8, + 0x2ddf6401, 0x66cd5b96, 0xf7ed685e, 0xf92153e4, 0xa4a2fec5, 0x66e159af, 0x8eb1a10b, 0x4c53ea38, 0xd4d456f4, + 0x836f632f, 0xfcc4fcc8, 0xaa9594d2, 0x640f7315, 0x99159706, 0xd96b6607, 0xa28071e1, 0x3de9204a, 0xbf67ae74, + 0xd3528627, 0x3521abf4, 0x46bb0e63, 0xae3797b2, 0xb9a45153, 0xa14a6468, 0x141e6357, 0x27113e26, 0x6a1782cf, + 0x9efee02d, 0xea9bef82, 0x47e47f15, 0x92b8ba3f, 0xccf5e552, 0x9e115408, 0x1d6b369d, 0xb379d8da, 0xb6da5ea1, + 0x8b050031, 0x5efa34bf, 0x7b7af133, 0x538b7f12, 0x5b57db49, 0x456f4977, 0x75d1a07a, 0xa1ab6f57, 0x6a0bde33, + 0xaf4b7d7f, 0x5f0b2674, 0xb5e4d91f, 0x851db407, 0x2414a29f, 0x49c95c85, 0xb2de1e63, 0x37949f67, 0xe8866e9f, + 0x57c37d7e, 0x5c89d2fe, 0xc443ec9e, 0xb1e6e116, 0x29c46e14, 0x89bdd864, 0xa71e9593, 0x578f1f62, 0xfeb751ee, + 0x072f679b, 0xc5353d52, 0x23201a85, 0x02014e13, 0x4cd95ac1, 0x0bf612f6, 0x155df7aa, 0x95b99d7b, 0xe07f32b8, + 0x2b0508ec, 0x13de6dae, 0xd91c339a, 0xe8a060fe, 0x4eb4164e, 0xcabcf057, 0xa4aa9a4f, 0x1759d134, 0x9e516705, + 0x8bbb1fbe, 0xc2685252, 0x8946aa40, 0x7632dbd2, 0x1cc267d3, 0xcd28007b, 0x4e278d8e, 0x3199c18b, 0xa5db7675, + 0xe67a3528, 0xe6e99cc7, 0xa837d31d, 0x38cff750, 0xd2dd5642, 0x777ed42a, 0xd06237d3, 0x1e4beea3, 0xe8231ea9, + 0x30cefee8, 0xbf86085e, 0x3648ed88, 0x9f78ae7a, 0x7992c9a5, 0xc9fb4176, 0xb4c3d80e, 0x3cf78af3, 0x11b38f62, + 0xcbcd08ce, 0x196dae68, 0x19b8e38d, 0x3d593cd7, 0x9b10cebb, 0xefee550e, 0xccbbb457, 0x3cc3d9e5, 0x9f58d353, + 0xfc1f4d64, 0x68b7b077, 0x93f3bc04, 0x001e0e66, 0xf1e88c35, 0x67f7a266, 0x33ccb038, 0x59f210c2, 0xd8c46b69, + 0x9116fbf2, 0x3dcfee9e, 0x2d922c51, 0x16e57d36, 0xdd34b9b4, 0xd2eb08e8, 0x2cad83da, 0x18f1d869, 0x0c7595ae, + 0x614ffa5e, 0x597d877f, 0x162c4a74, 0x08398f52, 0x41f2d69b, 0xd089b56a, 0xea7a61b8, 0x7c81c224, 0x2c2b0dae, + 0x1815dfc5, 0x212a4162, 0x133eb9cc, 0xc4d3548c, 0x0a5b97ae, 0xa5564347, 0x40e95a67, 0x372f8040, 0x49a82eed, + 0xb2171808, 0x01142710, 0x07e75876, 0x4d6e5057, 0x65496888, 0x3e82147c, 0xe26656d7, 0x81a41870, 0x0a989d2e, + 0xaeead2b2, 0x2ecdf9b4, 0xe1fe4b40, 0xbcb29426, 0xb3de45c7, 0xaaed782c, 0xbfa2db76, 0x208a3425, 0xa1426e5d, + 0x7480b136, 0x34865713, 0xd7ed64f0, 0x46ca0978, 0x7adf3193, 0xd8050d9d, 0x5b33c70c, 0xc117ea9f, 0x0435899e, + 0x1c7c52b7, 0x95b9941a, 0x571a8bfd, 0x3a56e7b4, 0xd52e06cb, 0x665fec2f, 0x86958c87, 0x1c59feb2, 0xf24cc7ec, + 0xeb47d8c5, 0x37b72c8b, 0xdbc18c8a, 0xc94bff49, 0x52e4ac48, 0x8bb1769a, 0x3392391e, 0x2945c28f, 0x62aca788, + 0x1b292d7b, 0xd3e5d34d, 0x7acf3a8c, 0xc5d43b6e, 0x0f188826, 0x88b08c0d, 0xf6461a51, 0x260778ae, 0xdd55b563, + 0x9ef29100, 0x8f77dcf2, 0x229fbe4b, 0x979f6d6d, 0x4c7ed257, 0x5cdfb65d, 0x1400ff53, 0x0d7787a7, 0x41f2af60, + 0xa5caa0f2, 0x16a74c1f, 0xfc5304f1, 0x235df5d5, 0x7493a3b7, 0xf84760e7, 0x7abbd749, 0x1a46b315, 0x505a102b, + 0x224b6ce9, 0xe78f352b, 0x57ba2c4d, 0xcc72d45c, 0xc99acdb7, 0xb7ad7f41, 0xba60821f, 0x62751cb7, 0xb166cbaf, + 0xb2a25ba0, 0x475b3453, 0x0904cd2e, 0x00dd6141, 0x80b7f86a, 0x2dd078e8, 0x22be6142, 0x6bc0c8b4, 0x4423c6cf, + 0xa29efdd3, 0x73a2bf6a, 0x89e3f8e0, 0xaeace67d, 0x3663ff6c, 0x54217639, 0x8a18b5d1, 0x5339718d, 0x071bb87c, + 0xfbfccb91, 0xe1eef474, 0x5d4ea587, 0x49b2d324, 0x55ae5c05, 0x30901d03, 0xcd9c0969, 0x5061475a, 0x2148f1be, + 0xacbeba73, 0x31ca77ad, 0x1de7a9ae, 0x5abd9baa, 0x811475cc, 0xd2580b2d, 0xe7153b22, 0x7a7a1bc4, 0x88a5cb3b, + 0xde374073, 0x306596fe, 0xa305ac06, 0xf127369e, 0xf347a889, 0xf325087b, 0x532507f9, 0x866eeffa, 0xdaaedfda, + 0x8e34f10e, 0x86416e3c, 0x6402524d, 0xeb4f37d0, 0x0b3f553e, 0xd333b5ae, 0xb29f9883, 0x5c888a0f, 0x51b3769a, + 0xec541a4b, 0x60013e4c, 0x05f02ff1, 0x7479597d, 0xad7c2e1e, 0xdd82715b, 0x6dbd6333, 0xe3c8cde2, 0xe7215a2d, + 0xdae13146, 0xf6d06242, 0x3bbe8508, 0xe801d2f1, 0x9bce1a04, 0xb24e0499, 0xfb49f500, 0x48d33af5, 0x644fadfe, + 0xf0572162, 0x26d3453c, 0xff833b8e, 0x985db2e4, 0xc7e6ef34, 0x04a19ffe, 0xeb43fbec, 0xa80e251a, 0xd16420f3, + 0x5d6c5c61, 0x807fb516, 0xf4ecd609, 0x6d3782cd, 0x0c8a235f, 0xe9888f69, 0xae33e7f7, 0x7d1d2f05, 0x06d21f4f, + 0x2c9d6a7a, 0xa16aaa02, 0xada1fa35, 0x63075c31, 0x038077d1, 0x08304cb6, 0x77294564, 0xf4a67e9b, 0x7b641b35, + 0xa526dcf5, 0x8c69cffa, 0x46f203b3, 0xa43e6dc6, 0xaee2b48f, 0xebd43311, 0x986a90e2, 0xe4353365, 0x26148932, + 0x5493034e, 0x854b5016, 0x93d375a8, 0x882656a0, 0xc60032bf, 0x6b902c0d, 0x4f9a8d67, 0xb072d3a7, 0xe0f2f8c2, + 0x47e47c4a, 0x9ecbffde, 0x45b179b4, 0xdb65d339, 0xfdb58686, 0x3ad66030, 0x38fbf23f, 0x4a8b043e, 0x0932a2f6, + 0x0b6bf564, 0x1c92dcfe, 0x530ab85c, 0x9e82dc9a, 0x6b9742dc, 0x32b0db57, 0xc8cc86ae, 0xa1010be6, 0x5edd7cca, + 0xc8df41d7, 0x7ae7021e, 0xeaf11cca, 0xe167bbbd, 0x6cffc7cf, 0x2d152ae0, 0xffb7ef87, 0xe1b5103e, 0x9602aaf8, + 0x4f5cc6b3, 0x9d0f47a0, 0x0407480b, 0x4719a139, 0xe0c63087, 0xa7631491, 0x3b7070c2, 0xdab82c48, 0xf4ffe30c, + 0x7b3f5f68, 0xdbcf9bb8, 0x549654d5, 0xb1a49d47, 0x36ce0df7, 0x020a9781, 0x2a9ef753, 0xa3f6711e, 0xfec5904e, + 0xe6387534, 0xb6c5a999, 0xc1b5ebda, 0x4460230d, 0x8a6df6d2, 0x88658bc3, 0x19184f52, 0x46f5dee3, 0xd61e266b, + 0x8db50c83, 0xe917b0b7, 0xee4ed849, 0x8b6ea6c4, 0xedca6ac6, 0x3b793f2f, 0x695bf241, 0x1fe58597, 0x337f4743, + 0x7f0d3688, 0x5289b726, 0x8ccde91b, 0xdd92930d, 0x66b63aeb, 0x918b8aab, 0x0702953d, 0xa5798a46, 0x361277d2, + 0x5a3120c4, 0xdb5ad6b2, 0xd091d66e, 0x772ed818, 0x82b90e68, 0xe21f49e2, 0xb093c7bc, 0x1377c616, 0xa13931ff, + 0xf4353a7f, 0x2e0fb070, 0xf5cd2b13, 0x77ce8584, 0xb7e151e8, 0x094e1c02, 0x2b42bc68, 0x0c081125, 0xb652de19, + 0x2556b9b6, 0x98fb73fa, 0x6ddca2f0, 0x0d5d43a1, 0x4842aaa1, 0xcc8353f0, 0x00c0536d, 0xa05f23bb, 0x848bdce5, + 0xbf73f195, 0xb385843c, 0xbf7292e9, 0x50e47706, 0x2d53514e, 0x8a980dee, 0x2960b299, 0x97c68a4f, 0xc1d588f1, + 0x9853ded2, 0x5adb74fc, 0xd17d8c9d, 0x55c1f84a, 0x081926ba, 0x2365bf69, 0x898b326a, 0x1e9546f6, 0x82cf8bcf, + 0x0dd834d3, 0x53a087b1, 0x9ac9399f, 0xbe871e69, 0x508dc451, 0x95c2c473, 0x39647d44, 0x1c826c01, 0x281d5b81, + 0x2514f3ac, 0x2a4fbba3, 0x2bd72ea1, 0x4edd787e, 0xda4d9fab, 0xeda0cb24, 0x70bd075b, 0xb569c27a, 0x2c5abda0, + 0x8b6c0c1d, 0x1f5fa4a3, 0x95d67b14, 0xe1a62492, 0xf0f1b02b, 0x8d06dbb7, 0x27f686ae, 0xa4fa6928, 0x4ccd8591, + 0x0b05fadc, 0x1544c04b, 0xfe369a4c, 0xc8841987, 0x4e24a2c6, 0x654c9050, 0x093283af, 0x1cfc9ddf, 0xb02a615e, + 0x7b105aa1, 0xb573fb7c, 0x4969a9ba, 0xd5f9fcb7, 0xfdc5e478, 0x6c8a8d29, 0x139903b6, 0x1fd82503, 0x13d37e04, + 0x3d1419e1, 0x6b51f7e4, 0x287dd762, 0x2449792f, 0x9210ada2, 0xcde52ad7, 0x06e9b479, 0x0430207b, 0x293645e2, + 0xe17b0eb7, 0xa1ed78e8, 0xecdb6fec, 0x10838731, 0x2db9925a, 0x0cc70ae3, 0x4ca4b52d, 0xed08fb61, 0x73775d7b, + 0xdcdf251d, 0x37a86b73, 0x2d05d77e, 0x0c6f3a84, 0x6bb71986, 0x9cdc7ab3, 0xe0bbfdd6, 0x7844ab21, 0xaed2e343, + 0x789dbc52, 0xeec7ce20, 0xc15bb4e1, 0xafe35cd3, 0x0216951b, 0xf551d571, 0x3ee9052f, 0x1336b298, 0x43fa8cb0, + 0xf39f9e0f, 0xb6ed6368, 0x90443114, 0x49b7bcb7, 0x576460db, 0x72f462d1, 0x7a265af1, 0x0ed276c6, 0x006d5fd1, + 0xf4acf31d, 0x285d9af1, 0x9e713111, 0xebc8ee95, 0xc855a8aa, 0x2e04e962, 0x2fd4f999, 0x95cc3008, 0xdf077be1, + 0xe2f7b128, 0x3e6e28ca, 0x407d94ed, 0x92cf5c47, 0xf479cdfa, 0x72779293, 0x37051bbd, 0xc6f4bfbd, 0xab5d1c52, + 0xb6d997da, 0xc8373c4d, 0xd8b2f1e7, 0x93fd5049, 0xf686e101, 0x8ddefb92, 0x1afa2fe9, 0x11276a42, 0x39608390, + 0xfe42fcab, 0x48a74e33, 0x3261ec9d, 0x586d415e, 0x19eaf045, 0xd0d1a6e6, 0x07d32937, 0x9bfdf340, 0xe06415af, + 0x1f102be2, 0x7333ae91, 0xee88ee64, 0x933c1159, 0x84a7685a, 0x54fc552c, 0xdada0ce6, 0x3da88ec3, 0xe119bda0, + 0x200eb23b, 0x937f91cb, 0x40e55f21, 0x7e8eb961, 0x1f3c1081, 0x8c1a9680, 0xd279d028, 0x1ab382a8, 0xbc7d6361, + 0xf43764e8, 0x17e04369, 0x1582fa03, 0x8c7e672c, 0x24afede0, 0x3c806ebf, 0x65aa375a, 0x942df74a, 0xf65de1d2, + 0x60e84da0, 0x429274da, 0xaf643f9e, 0x72256073, 0x658a20a2, 0x923711b1, 0xdda93621, 0x96101f15, 0x14a9efe9, + 0x155754c0, 0x21768c4b, 0x95a83f03, 0x89a1056b, 0xfcd6500e, 0xa20af21e, 0xdfea5e55, 0xb1e32cdc, 0x8ddaa5ec, + 0xf195677a, 0x1ec0b9ff, 0x660163a9, 0xd54ea42f, 0xcd34d294, 0x04334611, 0x46d5a530, 0xb97e149e, 0x44082757, + 0x0002bfcd, 0x0d697b14, 0xde904a82, 0x8f0e2480, 0x71088b72, 0xa9756d02, 0x933b787d, 0x03b95861, 0x318186fc, + 0x601d4077, 0x678427df, 0x3b6b6561, 0x454c3fd0, 0x33a60c48, 0x5d4310d5, 0x2c8be246, 0xb661c8b9, 0xf76f091a, + 0x4a4daa3a, 0xb0a3a478, 0xe8eae0e0, 0xd2130313, 0x40de4737, 0x812e255d, 0x2cd2a21f, 0x8c3a315e, 0x649a59d2, + 0x7c8f2aa8, 0xb7206b78, 0x35a58672, 0x29fb7873, 0x82392ff1, 0x43601bea, 0xd3ce58d4, 0x54e2d6e0, 0x0a4a8c45, + 0xffe7bab1, 0x4687e1e1, 0x408c353e, 0x2f429a04, 0xe4b853d1, 0x43d9f1f8, 0x643dd50c, 0x3db330c5, 0x6de0cb88, + 0x4910aa85, 0x310abc76, 0xc27dd11f, 0x1dd119b4, 0xf8ddc83e, 0x10e27592, 0xc7cb6eb2, 0xdeaddc58, 0x6062adc7, + 0xa450a86d, 0xf9dfff29, 0x733cd702, 0x2b371c61, 0xc238251d, 0x89445221, 0xe659ba00, 0xa8fd8393, 0x1140c4ed, + 0x4ef0433f, 0x3a7de3d6, 0x20cad5de, 0x0d272f53, 0x35b8c414, 0xd9831b06, 0x2767a285, 0xd7572f33, 0x270fd170, + 0xb27c6256, 0xeeb17baf, 0x93a03c8d, 0xb68f41b0, 0xd98652cd, 0x4602c86c, 0x9bc81ad3, 0x6aa8e252, 0x4d4a294a, + 0x83b0549e, 0x00129251, 0xe46f46b7, 0x36f5400a, 0xbd2e5f36, 0x21422e7c, 0x29461b16, 0x4414dd83, 0xf03ea707, + 0x1e2a6d2f, 0x4982ec19, 0xa97393f1, 0x84bc904d, 0xf5ab59ab, 0x0a21b71e, 0x58c0ce61, 0x5c7dd289, 0xce183882, + 0x494778b1, 0x89df4ede, 0x61c18002, 0x47cc4ecb, 0x4897199d, 0x5da541e0, 0xc98437c9, 0x2c83bdb8, 0xa3f6082b, + 0x75d19c58, 0x71810e34, 0xc764563e, 0xe36c0509, 0x3a44cda4, 0x38c6c375, 0x5dd21024, 0xf5bc8b9f, 0xc908243c, + 0x1d99b371, 0x8589b690, 0x90901127, 0x02edf14f, 0x7155d311, 0x575ebb33, 0x1ab7b352, 0x4eb4edd8, 0x4d753faf, + 0x2d787926, 0x774660f2, 0x451c545b, 0xdb057fcb, 0x18007dc3, 0x0637880a, 0x19e268e7, 0xeffa70c0, 0x61eb1179, + 0xa9b3ad2c, 0x77564d55, 0xfc9d42ad, 0xc26765bd, 0x0a252003, 0xb13d4f85, 0x900df167, 0x3d8df16f, 0x9b406337, + 0x579d4ac9, 0x4fb78605, 0x1c9a5bfb, 0x099ca859, 0x8bd2c930, 0x7724d6e3, 0xf8716082, 0x92aed4c2, 0x61a635c1, + 0x52a10c71, 0x21be0536, 0x126801b4, 0x5acaa27a, 0x1f903f08, 0x3c29281d, 0xd867acea, 0x1a2d2d9b, 0x445b4da0, + 0xbca22438, 0x261af73f, 0xc2a12b8c, 0xffe780c7, 0xabfe126a, 0xc57aff97, 0x269cc42f, 0x7b7f423b, 0x5318c8eb, + 0x11cd21d4, 0x18fb4c32, 0x28eaf894, 0x119c6530, 0x2532f3a3, 0x6ed46323, 0x7c0eda91, 0x7378b441, 0x301d31fc, + 0xb2a2ade2, 0x0ba16c2b, 0xfe7779f8, 0xa14f184b, 0x4c8c89ac, 0xc4db154b, 0xeb891e6f, 0x4b8f7a3c, 0x0e297030, + 0x45c070ee, 0x1764089b, 0x8175f80f, 0x497cdb50, 0x9e339fed, 0x559aff97, 0xeb455c69, 0x0a1f4e24, 0x5f19e88f, + 0x5403280d, 0xa3c6a080, 0xf8ef6097, 0x45860ea5, 0x051b4985, 0x6a69f83b, 0x6b018a85, 0x4829593b, 0x996e1099, + 0xe883cf6f, 0xef107ecf, 0x37d234a7, 0x1cb98013, 0x624730fe, 0x157f18bc, 0xeb3b3720, 0xe48f6a78, 0x7283f15f, + 0x247f16cc, 0x0aa31c2d, 0x626be6e3, 0x479d40c5, 0x453ed9af, 0x689bcbe0, 0x64b8e043, 0x826bfb3f, 0x016c1f08, + 0xfc574675, 0xa07a786a, 0x0f6dfd69, 0xb1cddfa9, 0x0343e6c1, 0xd2f704cd, 0x82b24e19, 0x1ec0d6d6, 0xff1ed257, + 0x8109adca, 0x78e4aeed, 0x1d5c99df, 0xd5aae2eb, 0x6aa6a398, 0x8dfbaf51, 0x0a3fa207, 0x0faf2c34, 0x85f23ee5, + 0xdc61addc, 0xa16ec59e, 0x0476d51f, 0x08b1469b, 0xc71c7efd, 0x19c3d9e6, 0x4fbc6f8e, 0x1d7ef7b5, 0x10aed031, + 0x1b258f4e, 0x0c576743, 0x51d94ec7, 0xcee958e0, 0xe967d2e3, 0xb28cb057, 0xd754c145, 0x772375f3, 0xa1f7025a, + 0x991b7414, 0x6f1e6cad, 0x09b85a16, 0x813d6eb7, 0x959b0aac, 0x2df70cfa, 0x75b86143, 0x6acc3f1f, 0x73843012, + 0x44d70031, 0xde8aa8b5, 0x04eae0f3, 0x9a134bf0, 0x91b138d6, 0xac17e4d5, 0xb4ae73d1, 0x367caab7, 0xd9f57dc0, + 0x24c220a4, 0xa1842b05, 0x0a54cc9b, 0x3e57b388, 0x2454a018, 0x2ae84446, 0x97e1022c, 0xd41a0177, 0xa73e0eb4, + 0xdd82bdb5, 0x80a43883, 0x987837d7, 0x3440c2db, 0xffabfd69, 0xc35f18df, 0xe960b531, 0xf83ade6c, 0x4b57fba4, + 0x70620704, 0xe70af68f, 0x51f2503a, 0xb236680c, 0xb58ad016, 0x3cd158d8, 0x937be624, 0xd5cf26e7, 0x9c169648, + 0x5a02d602, 0xdd61a5f1, 0xbf356bd7, 0x95f37547, 0xf3cb33b7, 0x77a4f314, 0x45298526, 0x4e1832f4, 0x2e2b0bea, + 0xa88c76b9, 0x0b40fb85, 0xc14786ad, 0xc604f43e, 0xa51b8456, 0xb64d3c86, 0xaed1bb10, 0x3382a6cc, 0x1dffc0ef, + 0x1c611f18, 0x42dca268, 0xe3b8c366, 0x376ee881, 0x9e1194e6, 0xd9cd7289, 0x3e0aad41, 0x5c94143a, 0xcf5b362e, + 0xc66b5880, 0x84e05035, 0x4ec411bd, 0xeefee40d, 0x14d7693b, 0xdd0f78c1, 0xa9719040, 0x3e6b2d01, 0x5f3a202a, + 0x692d3d36, 0x32073fb4, 0x8576aa91, 0xa59d3866, 0x6f11253f, 0x1d6280d1, 0x730c6016, 0xb91c90cb, 0x94a45078, + 0x5e14b7c1, 0x967e9d22, 0x1bac1a72, 0xc8bf47a1, 0x23cde2c9, 0x10eb97a7, 0xc3f8d0d4, 0x5bc58e40, 0xad2aae54, + 0x06ae391e, 0x084b5437, 0xbb829214, 0x81c2216b, 0x65f3bb92, 0x45b223db, 0x4a0ef599, 0x3aa8ac25, 0x2f45db9a, + 0xb510aaf5, 0xa8a7e2eb, 0x1413cd10, 0xab9d1244, 0x2cd7b23d, 0xb5c99a98, 0x42be15d8, 0xcbd411f9, 0x4c58ca1d, + 0xf3bbb9db, 0xb1db7a4c, 0xdabe0037, 0x1afeb674, 0x7e6c63ca, 0x64c59fc9, 0x66c5a0df, 0xecf5d7ea, 0xb95c85e9, + 0x21c68221, 0x50b34610, 0x23139a51, 0xdd7abb1a, 0x5fb76f49, 0x6afaf6a3, 0x1c29839b, 0x138b15b0, 0x5150f0bc, + 0x5cbaec32, 0x2bb1045f, 0x909e91ed, 0x67483e76, 0x4f7e3a58, 0x6b8a4bb3, 0x59c5eaf7, 0xfd5ca334, 0xe7259d81, + 0xf03d415e, 0xfdf9754f, 0x77d39af0, 0x5a0c8ed9, 0x33c5b95c, 0x5b11e3ed, 0xedcbe9c3, 0x8966b4d6, 0xc4da7b52, + 0x8a95fcb1, 0x57ea9364, 0xf6b5913e, 0xbb38a770, 0xb0c03b0d, 0x940d9101, 0xb1cabaf8, 0xf956baae, 0xe0d6f1fb, + 0x480c7ef4, 0xc13d27e5, 0x35addd39, 0x3fdeb6d9, 0xf4510755, 0x156b7178, 0xb66b4a43, 0x25e0bc9b, 0x45fc1199, + 0x4933f71b, 0x45cf84b4, 0x0bcf7918, 0x8bfad1fc, 0x7f3c320b, 0x6a6bd159, 0x66ffb3aa, 0x370f3852, 0x62c7cc88, + 0xa02fd72b, 0x8a5a6a30, 0xacd851d7, 0x393f3066, 0x0853fc1a, 0x660f254f, 0x34ce2832, 0x3a4b70f2, 0x4e8db0ba, + 0x6ab2db7e, 0x836bce86, 0x4e387027, 0x7a5c8602, 0x70041fe3, 0xceb34fe6, 0x045f6565, 0x1c072852, 0xaa33fd5b, + 0xdbc8bffe, 0xfb021b13, 0xc6eef9cb, 0x9eefeb73, 0xb4a8c04a, 0xbd0ea0ac, 0x18c26251, 0x9e0940fe, 0xff9103db, + 0x460ffe7c, 0x149dd9d2, 0xcb426b7c, 0x01d19f3d, 0x67495444, 0x87f93abf, 0x3c26ad20, 0xe0e0a11d, 0x1cb5a748, + 0x995f7506, 0x80ae55be, 0x8b0d28c9, 0x45c91bda, 0xfc7526bf, 0x9e0c5480, 0x3835f3c8, 0x5fd9e372, 0xba79797a, + 0x6d7346e4, 0xd5cebbca, 0xaf117d6a, 0x2aa5f431, 0x4a510954, 0x761ec530, 0x6c432ad0, 0xf65bbd49, 0x7918f4dd, + 0x890ec574, 0x405c6549, 0x2937cfa9, 0x5a33dceb, 0x6937ecc5, 0x6793540d, 0xe3c60fda, 0x6e47efce, 0x1042fb98, + 0x5a775d94, 0x49f447c3, 0xa6a4fde0, 0xd1e93d2a, 0x10e576bb, 0x06868891, 0x40b39e66, 0x2efa37d8, 0x94a8692f, + 0xa655aa50, 0x00d71aa4, 0xafe0b9e3, 0x621b41e5, 0x0e425e7a, 0xc8a76346, 0x2d23daf8, 0x7347718b, 0x9e325f33, + 0x83b06f20, 0xaa7f199b, 0x33fb4e30, 0xbd7b0db9, 0x853f1c52, 0xb01ad885, 0x2447755c, 0xf4841649, 0xc7d5727a, + 0xf7a42ff6, 0x4c1203b8, 0xdc5d4e6a, 0x93dd30b4, 0xa9d71974, 0xb65fe837, 0x39f3c535, 0xeb5f274a, 0x39234280, + 0xd5238395, 0x4f1f0eb9, 0x8690b5fc, 0xf21958d1, 0x7c9e666f, 0x7e5b3e21, 0x55fe0c7d, 0x93757f2b, 0x21b96e1a, + 0x1bc6ef6a, 0xce09365b, 0xb0e01840, 0x572907ca, 0xe821092d, 0xd010a433, 0x856863d6, 0xf14f7223, 0x9b359a83, + 0xc6a24415, 0xdbedc9af, 0x061bf39c, 0xea5dae1a, 0x7bea71df, 0x5d5198bf, 0xa54b55fc, 0x9b85bbd1, 0x18e60dc9, + 0x33f30694, 0xe3410a28, 0xa2c29d2c, 0x5381f42e, 0xfdaf5353, 0xdcb74daf, 0x75787300, 0xe17b1101, 0xe3c5b20e, + 0x66c0550d, 0x694bbec4, 0x260252fb, 0x6ccb2578, 0x2202ac41, 0x1c263244, 0xdafb80b0, 0xf7d2565a, 0x53323dbf, + 0xbf5a35d9, 0x271d1a7a, 0x4cb77044, 0x92178d68, 0xaf58fcc3, 0x9034ec20, 0xbf8206f7, 0xc78cf808, 0x545421d6, + 0x9665f2bf, 0x523210b8, 0x19ba97d1, 0x4ef6750b, 0xde74e1ac, 0xbb6818c8, 0x56a4427c, 0xc332077a, 0xb36e5c11, + 0xc467a93b, 0x194b0be0, 0x1fc811f6, 0x4699ee09, 0x3fa5a329, 0x9f321297, 0x986f8d9b, 0x7b74de42, 0x06b626fa, + 0xf0320b28, 0x6142d57f, 0xe21a80e9, 0xe2c34467, 0xcc6e4ca8, 0x97c03d44, 0x14383f3a, 0x2408eb56, 0x2127113f, + 0x2a0a0e66, 0x98e54033, 0x612d0167, 0xbc619e1c, 0xc68b8d0e, 0xaccbcb0b, 0x9a8c0b56, 0x3e75d37d, 0x13557ac1, + 0x528f3ae9, 0x4c752a5b, 0x0dfef8ae, 0xeee3299a, 0xc48d51bf, 0x9f1571f4, 0xa4f59729, 0xaabb9dfe, 0xd013252a, + 0x833a7d61, 0xc410826d, 0x9eb4208d, 0xa8ab71d9, 0x642666af, 0xe4693e1f, 0xbc5a0de2, 0xdea3e790, 0xdd122402, + 0x8484d0cf, 0x1ddc4121, 0x348d46f5, 0x971953ec, 0x62d9f9af, 0xd8cc66af, 0x4a67a541, 0x38ecc2ba, 0x3abc81c5, + 0x4fa5764e, 0x59e6ce21, 0x75d49818, 0xf54b863b, 0xccdbbf6d, 0x1a37af95, 0x47b6edad, 0xf85562b8, 0x53744a81, + 0x44a130f3, 0x4b47bfdf, 0x3a60c284, 0x400f1f62, 0x793b9c83, 0x0fd32e3b, 0xc079e2f0, 0x2ef7b3ae, 0x96327fdf, + 0x56d14c2e, 0xa4a1117a, 0x3e383ec3, 0x0ba22df7, 0x579e178e, 0x329b946b, 0x6451c4bc, 0x27c5ba52, 0x299855f1, + 0xb41d9755, 0x627d9ff3, 0x6c26afde, 0x56dc9a0d, 0x24d8242e, 0x3210069c, 0x6df4f51e, 0x661de7fc, 0xde8ca519, + 0x99eb35af, 0x695d6b42, 0xb34ab44a, 0x9d33b76b, 0x98c2d32c, 0x3cf48560, 0xfababb78, 0x9f2b3bc8, 0xbcb72359, + 0x19aa4a3a, 0x22ac44ce, 0x81d15a38, 0x7fbdd7b2, 0xb12fcfb4, 0x41de9ccf, 0xd36251ec, 0x77e7ac2f, 0x315d8fdb, + 0xbb53a4ac, 0xdf466251, 0x2a8f1cac, 0xaef44463, 0x9b529637, 0xd6bc5f78, 0x3e1780e2, 0x890f1b11, 0xe37e88b5, + 0xe8b4cab4, 0xee2dedf4, 0xaa0b29d6, 0xec2bba74, 0xe1e3530a, 0x8d906f80, 0x27005a29, 0xdb0c17eb, 0x1f6d6f34, + 0xc2791f6c, 0x155fc2a9, 0x9f1e46cb, 0x8acc1894, 0x87287666, 0xa49b172b, 0xdcde6805, 0x65b629ae, 0xcce5c167, + 0x27d6a673, 0x8b34361e, 0x57cdd05a, 0xd7000b89, 0xf282494f, 0x94ff9944, 0x7728710e, 0xa08bef57, 0x4394ed34, + 0x1f55d0df, 0x4619683a, 0xf7d5060b, 0xc6f9dea0, 0x08d4f545, 0x984407f0, 0x6f3b879d, 0xcd39a36d, 0xb9b75be6, + 0x5d3b6127, 0xc6e8ac7b, 0x63dab8b4, 0xfcd2bbd7, 0x57ad8078, 0x5211212c, 0x025ee436, 0x2c44f7fa, 0x463cb6f5, + 0x53979e8a, 0xdbf7edfe, 0x31b37d66, 0xadee4bb3, 0x050ed66a, 0x81c491e6, 0xdbe069f5, 0xfd8d2dee, 0x1cafced5, + 0xa9a65a1c, 0x7520d08b, 0x908659ba, 0x89b58ed1, 0x292f5596, 0x29cd7b20, 0x02ba9675, 0x3a0ea88c, 0x294f24a4, + 0xbd95e73f, 0x33957d5c, 0x4c3b196c, 0xc074bb28, 0x83f8416e, 0x11fb1987, 0xb639a901, 0x4d45bc86, 0xcb09269a, + 0x4753a403, 0x3f38b77c, 0xd5822603, 0x0130245f, 0x43293c7d, 0x6495d923, 0x920eb5c7, 0x4e972a4b, 0xe66de992, + 0xad175730, 0xaf9ec50c, 0xbcdb6da3, 0x648bfe89, 0x691898ac, 0x843f9fb7, 0xbe1073d4, 0x9a3f9853, 0x6f8cf094, + 0x597f19e3, 0x14882dce, 0x3d3e4cb3, 0x8abefe21, 0x5d0e1c01, 0xc8a8c176, 0xbca8b198, 0x6a3d2399, 0x2311b609, + 0x00a180d6, 0x7a8b8265, 0xbc9d3ecb, 0xc3836833, 0x89906789, 0x3dfb887d, 0xe4bd00a1, 0xbf6afcc9, 0x4e19e63a, + 0xe26fe8c4, 0x5aa790de, 0x15de32d2, 0x8f378a8a, 0x8e0c03f9, 0x6ea8e823, 0x3562bc8b, 0xd5e3782c, 0xb6206b83, + 0xbea9459c, 0x5a046eeb, 0xd2cf734d, 0xac45da1c, 0x42ba9e37, 0x123a943f, 0x37de540d, 0xf1660852, 0x5a67c6a2, + 0xdf85c8af, 0x651cbaed, 0x009dbaa7, 0x4f759dae, 0xe4ef7a54, 0xa0d5a1f3, 0x5ef09385, 0x70aecb03, 0x10bcf8e0, + 0xeb6de10b, 0x0213c835, 0xc2e74f2d, 0xea01e028, 0xb378263c, 0xd75b9e49, 0xb595218e, 0xff4d3414, 0x4beffbc8, + 0x70eed209, 0x6da43255, 0x9867a407, 0x5ff42913, 0x79bcc9a6, 0x5338f6c8, 0x9a631c12, 0xf4dcd56b, 0x73cbe8f6, + 0x52683b56, 0xc91389ff, 0xcbed54e0, 0xdf9b1c5c, 0xe0e1ab04, 0xf9ee8ff0, 0xceb94227, 0x0d33b44b, 0x9e133a27, + 0xcaca20bd, 0x81649a82, 0x566c7e86, 0xeb9a6268, 0x23475e61, 0xc424d687, 0x95e2bc52, 0xfde7ebc7, 0xaf6201ff, + 0xb3744335, 0xd1599d22, 0x21568336, 0xcf690878, 0x75a3f31c, 0x10c239fb, 0xe54a41b8, 0xe2901719, 0x729a7fd0, + 0x92f54b9c, 0xdb23b059, 0x3f54d2b4, 0xe92f401f, 0x1915b06b, 0xaf7a9a0b, 0x128073de, 0x14e047b5, 0x2b6a50e5, + 0x09055a1c, 0xa9852c1e, 0x8c5d2bf1, 0x39ea2921, 0x20884f17, 0x9eb42544, 0xeb9a6834, 0x4abb0531, 0x8372a9c0, + 0x99d39b6c, 0x548f0458, 0x211dcd35, 0xac17fa0a, 0xc5fd27b5, 0x58def09d, 0xea9329e4, 0x3c6c868e, 0xb4d8f044, + 0x789136c4, 0xba533424, 0xe168d1ef, 0xc708c20f, 0x8dcf762b, 0x384f3d5d, 0xabbd28c4, 0x737ecaf3, 0xfb6265ef, + 0x8d2c2c08, 0xa5fa26c4, 0x3a8b82eb, 0x03199bee, 0xc4546c7f, 0x0f3f1935, 0xb22a0a83, 0x31a0cf35, 0xe43ea6d0, + 0x840bd7f7, 0x08a1dd44, 0x906ba3d4, 0x7c70168a, 0x23a49cd4, 0x38861517, 0x6bdf8342, 0xb388b3e8, 0x4143f3cf, + 0x2a5fb3d2, 0x55a3794d, 0xfee7be03, 0x46b54004, 0xccc15e25, 0x6fe71677, 0x9e608bda, 0x3f042a8d, 0x108c8293, + 0x23eb28bb, 0x678ed54b, 0xa5b97bdf, 0x4c14ff69, 0xc9ff24ed, 0x69015b41, 0xd019c33f, 0xa4c93b7c, 0xbc61e1fd, + 0x482c4c69, 0x513b592f, 0x36e96ae9, 0xe27617e8, 0xaecfa9da, 0x40f5d0cc, 0x0ec88cea, 0x5e16fdcb, 0x99c19489, + 0x2935d3ac, 0xd8b0030f, 0xf43fc3e7, 0x54d07441, 0x68778691, 0xa2642db4, 0x834aa352, 0x1fb4a145, 0xb972b0ce, + 0x06c0aea2, 0x406a0b8b, 0x59c28f51, 0xb3353e7f, 0xa36d4811, 0xb9e93470, 0xb9d7115a, 0x458e0305, 0x2ca05578, + 0x1b8bb3b1, 0x68ae7ea3, 0x2e0fc469, 0xf10e0530, 0x5c3768c6, 0x53c22697, 0x6c0b1d21, 0x6c676a1c, 0x675a4888, + 0x90f2718c, 0x366781fb, 0x3ba7826a, 0xb920e603, 0x274a92bb, 0xf5fff108, 0x55d8c795, 0x2a69602e, 0x21c5ade0, + 0xa3f1f3b4, 0x6f6f5b83, 0xf7689f05, 0xa4b20661, 0xda8aa532, 0xac88f611, 0xb3e46fc9, 0x11201fc2, 0x29432452, + 0x16b68193, 0x01ad9db2, 0x8e2e813b, 0xa1f2cad6, 0x99843790, 0xd72a885d, 0xb1a61b25, 0x78d7e5ec, 0x2df4c51a, + 0x4a48df90, 0x0d29f1a6, 0x4f129e81, 0x3d3760ca, 0x6cdce46b, 0x2de31395, 0x7c194174, 0x99ccf9b1, 0xbcf4f917, + 0xf1facc87, 0x5c91ced4, 0xf9eb6e7f, 0x1ff97b2f, 0x1eae196e, 0x68560f84, 0x99e3a36d, 0xa9f58096, 0xc9df4e71, + 0xadc2b67d, 0x2849894f, 0xd7d17105, 0x5031be17, 0xbf6e24b1, 0x0970a717, 0x4039d2f6, 0xbb1cf185, 0xe3a4e905, + 0xce2e5728, 0x1675bf8e, 0xa2c8ccc3, 0xc0193997, 0x18d9a77e, 0x1666e111, 0x9286ddb7, 0xc870f9ed, 0x4f9a723b, + 0x4a701baa, 0x1e664c39, 0x06ff3af7, 0x6a4fb56c, 0xd3b63363, 0x51e41cfb, 0xf2d11af1, 0x33ec0bee, 0xb3bc27e3, + 0xf74ccfff, 0x95dad23b, 0x950cde28, 0x3c0baabe, 0x5995b984, 0xd8d8938b, 0x73442276, 0x0d08c087, 0x5f3b54d0, + 0x1f8323c5, 0x69e8959b, 0x6ada84e9, 0x3c1c5791, 0x24bc848d, 0x208c0892, 0x2925711d, 0xcacaa134, 0xb617e368, + 0x32b6819c, 0xfbac9a7e, 0xb907d167, 0xddb2c6e0, 0x32726832, 0xbf5039df, 0x6f0d870c, 0x03a0d3e2, 0x0f68e17c, + 0xd6dc53de, 0x6bebc35b, 0xd2e4092a, 0x1b2bb32d, 0x283d8fcf, 0x7ede2a5e, 0x1a2c7a54, 0x58d157ef, 0x7723172c, + 0x9f4668b5, 0x40634fe2, 0x1bd8d93c, 0x0e7182ea, 0x90811e81, 0x88eee5df, 0x7199e5f3, 0xe86ac5a9, 0xf6a27db2, + 0x89ebafe2, 0x4fde83d8, 0xbcdf3b42, 0xfc087756, 0x1768edcb, 0xa6661fdf, 0xf25b34d3, 0x1940db6e, 0x797af475, + 0x4e8dbcce, 0xee95d05c, 0xe1636149, 0x55521c0c, 0x50b209ed, 0xa728261e, 0x9fbe5e2d, 0xa8c441f0, 0x5bc6b1a4, + 0x94559b29, 0xaedf153c, 0x1752331a, 0x599b9558, 0x9e2ca60f, 0x99d14404, 0xc2bd2918, 0x5bb41e3c, 0xf41c85fb, + 0xca9acfd9, 0x3e15719e, 0x772d3512, 0x58f3106e, 0x4cd2dad0, 0x6cbdf56e, 0xbb9d4b8f, 0x4875b684, 0xb3351e0d, + 0x02cb41c8, 0x225e48f3, 0x53b723a8, 0x6b2a82ef, 0x6b2dca62, 0x9d557706, 0x9facb2f2, 0x47ad9e54, 0x8a10797f, + 0x6d4b46ad, 0xefc3f413, 0x55810273, 0x2557d1d8, 0x0e30ad44, 0x17309b8e, 0x7f1ccb2b, 0x601c1cde, 0xd8b0d8ec, + 0xf7d698b5, 0x616af705, 0x381186c9, 0x75840bec, 0xc3bc6d77, 0x4d18a122, 0xa8ff864e, 0x67c4d33c, 0x7bf09055, + 0xb20c75c1, 0x0067c9c1, 0xffef7a14, 0x59ad2bd6, 0xba30d2eb, 0x017d801e, 0xff9f26ce, 0x1931daa9, 0x72c773af, + 0x1312dcf0, 0xc482c321, 0x8daf3485, 0xd5df7f64, 0x9158a67c, 0xa57a6fb9, 0x2127646b, 0x2b3f63c1, 0x9d7527a5, + 0xfb811a2a, 0xfca91c07, 0x6de2ac72, 0xb7827e48, 0xe56f945c, 0xc61aee99, 0x45c30bf6, 0xd6b7b8bc, 0x8a35501d, + 0xe0e6de76, 0xbadec4ed, 0xcd390395, 0x10e9edf0, 0xb7d8543f, 0x1746d7f7, 0x7deddf27, 0xde96d616, 0x8286e261, + 0x94cfae7e, 0x5ee9b7b6, 0x979d95c5, 0x86204b37, 0xc1532718, 0xa27f1704, 0x35c686ed, 0x67e170de, 0x210eccb7, + 0x072cd48e, 0xa899b207, 0x015e1695, 0x5909ad35, 0x8fc552b7, 0x72d68955, 0x7609d763, 0x9a87b8f2, 0x8753e7c4, + 0x1f173f1e, 0xa18c80ab, 0xe2ccb12a, 0x19923cfc, 0x32284fde, 0xeb183d77, 0x21234853, 0x249180e6, 0x8489031e, + 0xc3d54d69, 0x262b6119, 0xbacb6887, 0x3fc8cb88, 0xb97a214c, 0xa5a3d6d4, 0x55a8c022, 0x13e01ec4, 0x90b022d8, + 0x6f2dc958, 0x9a236275, 0xada142e7, 0xafeb2719, 0xd3f1fc3c, 0xe54db65a, 0x438a8cb1, 0x988690ad, 0x988152c5, + 0x4a2ebc5f, 0xdd6652d1, 0xfa24f620, 0x2aac157d, 0xbf4135d5, 0xe087789e, 0xe700a403, 0x96f3e66f, 0x072f39db, + 0xdee25d42, 0x32a262ec, 0x809128ad, 0xfa78452e, 0x46924dd6, 0xf12bc2b5, 0x70f89b3d, 0xc397fa35, 0x170afec6, + 0x3f2f4ba5, 0x2302594f, 0xb6c440ad, 0xa4a1e189, 0x6c9e485c, 0x735124e0, 0x9e5240c4, 0xdbe4e5b8, 0x227d6398, + 0xdebab2ef, 0x8ac26bad, 0xc749b36b, 0x2236feb5, 0x3e944633, 0x290f0921, 0xdb8c546c, 0xd9a9a399, 0x7feb31e0, + 0x5682a7d2, 0x06ebaa2d, 0x6a420bb0, 0x40b73bed, 0x0b1945af, 0x6bf40e7b, 0x5bf1dd80, 0x718dc2aa, 0x8eef1f7d, + 0xc58f0b01, 0xad4be66e, 0xe55aa1a3, 0x9773881e, 0xb9fd4d65, 0xedf6bf42, 0x3f3dd68e, 0x11f20e8a, 0xcf44dc78, + 0x5e1f55ec, 0x9085e261, 0xe314b738, 0x7eec76ae, 0xb245cc83, 0x098a7ffa, 0xe4d35d32, 0x41847646, 0x8d682f09, + 0x281a1af5, 0xfb6d162d, 0x94654b62, 0x0850413e, 0x17eca55e, 0xc793e893, 0xf25a9a96, 0xc9dca31e, 0x5616ed2f, + 0xe65f2e59, 0xe5ebd463, 0x0e3bb33e, 0xdadf0d46, 0x4db8d494, 0x430682ee, 0xdb63e118, 0x3f7ee70f, 0xecdde80c, + 0xfbc70a58, 0x65734d40, 0x131ac733, 0x6e50242a, 0x77972a5b, 0x9ce17c76, 0x9780e1e3, 0x36ac1fd7, 0x53357f07, + 0xa25daece, 0x1b58a424, 0xe824df11, 0x095316db, 0x50a1e48f, 0x34f9fbe4, 0xa341145f, 0xae2cc9f1, 0xf1f737a1, + 0x4f4d1d3b, 0x1bea541b, 0x7fc9a1b5, 0xb70bbb9f, 0x327c1920, 0xe43367fb, 0x3cb53183, 0x0e05936a, 0x911776ff, + 0x93ddf525, 0x0dfe23fc, 0xd8c0ab62, 0x480f14e3, 0xa0cd2f8a, 0xdedf0e96, 0xac28b364, 0xd58ff404, 0x8fe2daa7, + 0x60b7c32f, 0xf707b0fd, 0xd35614a0, 0x5d880504, 0x429f70a9, 0x355bdb1d, 0x89e56fc5, 0x4e02f94a, 0x19a38ce7, + 0xec1015f9, 0xa155ad91, 0x54e5bd96, 0xdbe130d4, 0x8a4141bd, 0x706a1380, 0xd830fe5b, 0x544d9615, 0xd0096dd1, + 0xa7d552c2, 0xbe039050, 0xd90b0811, 0x0333429f, 0x44f8c6ef, 0xff1e0cce, 0x4dcf6fd0, 0x89130d4b, 0x90df7729, + 0x77428e97, 0x3acde043, 0x8f4e8a5f, 0x20a158bc, 0x27e15284, 0x0278d77e, 0x3c13e327, 0x260ea13d, 0x21d5c25c, + 0xed47d3de, 0xf67f7cd6, 0x7d3851d9, 0xd99ea0c8, 0xfe445913, 0x7ec80639, 0x219fd5e9, 0xcd36306a, 0xfd6f709c, + 0x244432a7, 0xb4d38127, 0x842ac80e, 0x90a55f02, 0xa29b921b, 0x759afee9, 0xfff865bc, 0x4b9a5540, 0xb441636f, + 0xd0613667, 0x1bd39a77, 0x01a029e6, 0x8766e1e4, 0x5b298995, 0xf5412b55, 0x7bcaddbc, 0xe67ffc6e, 0x9ebbdfdb, + 0xb38a72d7, 0x190fe5e0, 0xd73beea9, 0xbf4aa883, 0xaba63acb, 0x6c1df834, 0x2291cc37, 0x2785a109, 0xbd27ebdf, + 0x28dc515d, 0x0fbfa235, 0x0e9914a9, 0x11fb5526, 0x32582580, 0xfd1e41b2, 0xb652c23c, 0x297b0e53, 0x89eb1424, + 0x8c38f1b1, 0x769189f0, 0x37abb683, 0xac01118e, 0xdea87d36, 0x843222ec, 0xa90ca86a, 0x0d1967f3, 0x371f55e9, + 0x164c741e, 0x3c0dbb51, 0x273612fe, 0x193c65f4, 0xecba4449, 0xd3b34752, 0x3a7faf74, 0xc8642188, 0xa2dc47d5, + 0x057aaabf, 0x4b1a4a96, 0x3bd89483, 0x79410ed5, 0x2dbf9512, 0x1c06b6f9, 0x2fabf865, 0x0a3b17c7, 0xa48b7872, + 0x09ae0559, 0x67f66832, 0xbed65b8d, 0x1b5fa9f4, 0x70a00aff, 0xec1615d6, 0x06cc68bf, 0xad95dc5b, 0x5e587e93, + 0xc3f50b8e, 0xdd63cc20, 0x25d1c229, 0x93e8428b, 0x6d72fe55, 0x9d6f5ac0, 0x7f73dd6e, 0x0634880d, 0xceb4562f, + 0x1f348734, 0x4b7463b3, 0xbb8f4f8c, 0x273b73ea, 0x10f54909, 0x8796f1e5, 0x75114d05, 0x0884053f, 0x578227a9, + 0xe56b304a, 0xa70582d2, 0x2ece1842, 0x643c2eb0, 0x8534f9d4, 0x2ed2a5d3, 0xe29f5918, 0x3fd23872, 0x3a950dbd, + 0xf0672e82, 0xafb68a7f, 0xd7f1059a, 0x03622915, 0x4353a988, 0x99def85d, 0x0daaffb2, 0x08879768, 0xeea325dc, + 0xb49bffec, 0xfb6bd31c, 0xb35f9d63, 0x7498ac0c, 0x2b13b923, 0xedc2dc71, 0xb9242926, 0x8b83480b, 0x52bd653c, + 0x76d73500, 0xf90972f7, 0xa0d385be, 0xecab2e28, 0xd3cad84a, 0xd0516dee, 0x82bb8587, 0xcb95fa04, 0x48c30e35, + 0xe2a7f957, 0x2f609fef, 0x3967b185, 0x39ffaf1a, 0x15a89785, 0x71421830, 0xc4923ee6, 0x091a047e, 0x98b9ea0e, + 0xdcbb205d, 0x5a619f2c, 0x9dbb8873, 0x6bc9bbd3, 0xa63fee7c, 0xb26f0df2, 0xd28a6aa8, 0xb3e2da36, 0x2ac88148, + 0xadf3799e, 0x76b1e2ea, 0x7c5965f6, 0x2b9e9a36, 0xd0457b37, 0xf87b3c46, 0x4f0bb999, 0x20bc03fe, 0x27bb8bb9, + 0x42b25118, 0x5f2aea6e, 0x04296917, 0xbc81a247, 0x30258762, 0x70c4a2fc, 0x3128398c, 0xda05cc87, 0xb1593045, + 0x0e618e4d, 0x26a86e85, 0xbc302253, 0xda798503, 0x2b284b3a, 0x5984ffa5, 0x111a0d92, 0x11bea818, 0x0d479bdd, + 0x4ac1cb2d, 0x61009aee, 0x478aa97b, 0x06c04542, 0xbd5c0151, 0x7c8cc9b3, 0xf6fa3863, 0x07d56680, 0x1edbcd7d, + 0x1d6232be, 0xcedf46c5, 0x34249f0c, 0xd78d9cf0, 0xb45e26e5, 0x494b5140, 0xac08bb9d, 0x3c25d8fe, 0xcaa838c7, + 0x07703e78, 0xf3a23eb4, 0x50028c28, 0x3711e5e5, 0x2ae5e22a, 0x5a040c04, 0x1bddeb1e, 0x5ecfe949, 0x8c1ecc73, + 0xc4c4b291, 0x2ce6c4c2, 0xf63a7992, 0x32bd6fcb, 0xf3a4f1ae, 0xce78225d, 0xa6b13fa6, 0x2fbce716, 0xd7444e8e, + 0x11e8f5d1, 0x3c6a1020, 0x084f0c4a, 0x3e06e786, 0x94fdb81b, 0x2036b031, 0x0c686afa, 0x0d4037a3, 0xc8948656, + 0x5057b039, 0xffb9e6e0, 0xac681fc1, 0xb2ed9467, 0x5bb66ba0, 0xade77074, 0xd3f4c0ad, 0x5df6ce4e, 0x110a8b64, + 0x810d4d72, 0x5ae78216, 0xf8055489, 0xa6581b04, 0x42548116, 0xbe56fc11, 0x4a7805fc, 0xc542a96c, 0x5947ea7a, + 0xdf1114e5, 0x1a9212cf, 0x01b1b2ec, 0xd12f0eb7, 0x46c0771b, 0x30e38601, 0xd8161954, 0x408bc929, 0xcd809f78, + 0xd29ae77f, 0xa9b926b6, 0x34043551, 0xd2fb5680, 0x50be12a2, 0x65451b50, 0x82db6a16, 0x5a020499, 0xfa9b9f88, + 0x0b8627ea, 0xd8b5d8b1, 0xa5529cd2, 0xa0127182, 0xc56ab717, 0x1cf730eb, 0x65419de4, 0xc1838767, 0xc8a85ff6, + 0xc2b5d569, 0x48346010, 0xeee24b63, 0x5b6a6b76, 0x414d17bc, 0x9e11b76d, 0x2d2570f6, 0x26a23051, 0xe0852a6c, + 0xfff5a07a, 0x8811161c, 0x1a075814, 0xfbc480ce, 0x9e3d7b70, 0x898d7192, 0x9334e0ca, 0x85de6f33, 0xb16d5a51, + 0x422418c1, 0x15220d3b, 0x1d5c7552, 0x456d9187, 0xde232186, 0xe1a8f833, 0x595e5bb3, 0xb8c36f2d, 0x4f987a8d, + 0xbe49ffb8, 0xab657853, 0x40a0c522, 0xf7710476, 0xf859a458, 0x491e7e8d, 0x1b9d4f75, 0xb5c9affd, 0x47c51e4d, + 0x9b3a7405, 0x132572dd, 0xda5d006a, 0x2bc721c5, 0x675a11ce, 0xf2c7ec9e, 0x44919b2e, 0x626a9396, 0x9fd165ed, + 0x5b265cea, 0x26cce398, 0x952ca1fa, 0x86be4d62, 0x751f350f, 0x6a6816ad, 0xb99d2576, 0x2f3214a6, 0x9a150127, + 0x1112c340, 0x0b925422, 0xafdfc749, 0x804c7ef2, 0xea06f047, 0xb2e2a76a, 0x3a7e9625, 0xb9f967be, 0xac44a38d, + 0xee5774aa, 0x049ad3ce, 0xd19a60e4, 0x89e7577b, 0x06e4cfc0, 0x5024a761, 0x6cffbed6, 0x8a47bc4c, 0x00d33a02, + 0x46e39ad3, 0x82b267a2, 0xf35e6f09, 0xdaeeb428, 0xfc46ee2d, 0x9b200b4c, 0x95a2274c, 0x9d53abb6, 0x0fad0e9b, + 0x408e5a83, 0x90a374ba, 0xd84bdcdd, 0xde97dcf6, 0x6a4ab283, 0xfc3f4337, 0xb9c17af5, 0x4084870c, 0xba5e3aa2, + 0x0663801e, 0xff6a506e, 0x88b4c458, 0x6da3a9f5, 0x5d37be6e, 0x684efc43, 0xf1cc6a2d, 0xeaf0c28e, 0xf2b5e145, + 0x788e7680, 0x36973c9e, 0xa4e2768b, 0xdf98ef55, 0x95d04b68, 0x48ae2d49, 0xe3342c4d, 0xaf94c102, 0x63884388, + 0x5fdd623b, 0x0dff7067, 0xa5595ba0, 0xa3217c54, 0x77068320, 0x6710279f, 0xbcedc90f, 0x774e5c10, 0x51f57570, + 0x34a44355, 0xc3d786bb, 0xb10b88eb, 0xa0622124, 0xfb3e4514, 0xcaebfcef, 0x4ee7accd, 0xde30e974, 0x3cd1e648, + 0x93eee67b, 0xf0b8042e, 0x18f5e188, 0x7b21094a, 0x6587fc96, 0x6952aae6, 0x4ce7bcfb, 0x55c7b693, 0x1ff35b4c, + 0x320c1223, 0xe0a1cc8a, 0xb58afd7a, 0x237244f4, 0x9e9862ac, 0x275294fb, 0xaee39fda, 0x7486e721, 0xfd05140c, + 0x1b160fc3, 0x781eeadf, 0x514fbb57, 0x48bdd246, 0x7220145f, 0x74c224b0, 0xeea9db1a, 0x42c7a5c2, 0xde5473df, + 0x79d441f8, 0x8dc4e95e, 0x2b6cb258, 0x5e7ea791, 0x889206b2, 0x32b4a9c8, 0x1773aefc, 0x9bfa06cc, 0x8058374a, + 0x710fb5a2, 0xdd7e5f50, 0x595b45a1, 0x63831d0c, 0x3c5eab6d, 0x1e643b4a, 0xe7b05527, 0x4ce19761, 0x6bd9ec95, + 0xd5cf03a2, 0x2da61dc7, 0x40903b6e, 0x3457c802, 0x4be7540a, 0x2d385d6f, 0xe190e82e, 0xc6066c7b, 0xbd74c362, + 0x01bfc7a8, 0xdc9bfdf1, 0x5ceff0bf, 0x255d62bd, 0x9f7e71eb, 0xb29f1677, 0xbe261432, 0xe472c406, 0xf810d816, + 0x74b90c76, 0x3e3cddb1, 0xa7321d66, 0x1059da4b, 0x27353b1d, 0x084c4605, 0x4ddd1b3e, 0x6e0c0fe6, 0x29e7fe4b, + 0x051f14c6, 0xbbac03e8, 0xbcd07065, 0x4d6b6248, 0x409f8270, 0x9150fb5b, 0x338d9597, 0xeeb954fe, 0xc764666c, + 0x6b74fd87, 0xcce418d8, 0xc5cbcf8d, 0xafbb0b46, 0x2c5ffc17, 0xd54d5177, 0x794304a5, 0x9a48d736, 0x86b34679, + 0x431c2a15, 0x9aef854d, 0xd6544840, 0xa197ffa6, 0x7b70d13f, 0xe0bf3701, 0xeb5674c9, 0x8c4070bd, 0xbad89407, + 0x4de56223, 0x50b8ece0, 0x315351cc, 0xe1146304, 0x6474a828, 0x76be4e2e, 0xdd8566f9, 0x2afad76e, 0x6bf8b426, + 0x327d9e6b, 0x92375249, 0xaad9e218, 0xe50d429f, 0xdc4adb54, 0x2e6ddd76, 0x8960e9af, 0x4a24afb3, 0xcc4a5adb, + 0x1cdea009, 0x23070d5c, 0x761e4271, 0xd58185d3, 0xa405f8ac, 0x7c276412, 0x3f8bfc53, 0x233b3d14, 0x15c59283, + 0xa2b36815, 0x355ec54f, 0x2a0886e0, 0x2791ef9e, 0x317a327c, 0xb467950e, 0x8b4bc99c, 0x5ebd0767, 0x30282c67, + 0x37422a8e, 0x1c1a7389, 0x2c1fc0bd, 0x242be654, 0x1366bf36, 0x72e8399a, 0x57675864, 0x36aa608c, 0x06b3e973, + 0x855b3063, 0x2cc25698, 0x30b01aef, 0x028f9ff8, 0x9f499388, 0x1c211376, 0xb9d05aae, 0x3285d55e, 0x7194a5c5, + 0xa59e97bf, 0xc8b95d6f, 0x4fdc53ec, 0xa310d354, 0xf8f77408, 0x4692fc1e, 0xc255a69c, 0x5cdc9711, 0xff7af327, + 0x944ed487, 0x0ea3cb75, 0xd11eb3fc, 0xea33dbc1, 0x3a4e1049, 0x0f29ef9b, 0x2f252dd6, 0x7961b716, 0x2d52610e, + 0xa8dbded9, 0xa8458833, 0x2d6f6300, 0xb4dbd718, 0xe26d05f3, 0xddb62c95, 0x4f09d53d, 0xcd4ef484, 0xb4902169, + 0x398963a1, 0x8039d0e3, 0xa699ddbb, 0x9a4c7d61, 0xe9cb7f0d, 0xaf2aeca2, 0xee258866, 0x4748c32a, 0x02868672, + 0xe73ccf6c, 0x43414473, 0x17ed8d2e, 0xcc2137ac, 0x56d97dd0, 0xc334fd9d, 0x28ab3dde, 0x32a5e8d6, 0x40c7b07b, + 0x6905393c, 0xaad86b86, 0x84ff3b56, 0xbcb66b62, 0x1f8d3561, 0xf2d75a0e, 0xb90447c1, 0x08911881, 0xd7519cc7, + 0xead5ca45, 0x3314ef86, 0xdeacf62f, 0xbdd0cfa7, 0x66e43c28, 0x12d5051c, 0xade5804b, 0x5276c587, 0x039e8846, + 0x0fd5f96c, 0x648a584e, 0x8fa5a2a0, 0xfe7ab35f, 0x3b15c7cf, 0x7c37cc2f, 0x2df17f56, 0x08f0ae17, 0x76e33606, + 0x832beff3, 0xe4be8344, 0xcbe48e8b, 0x4bc458e4, 0x7a8d463d, 0x192eec15, 0xac520d17, 0x251a17f2, 0x72bfdc5a, + 0xfe77d3f9, 0x7ace7dbc, 0xd6b8b804, 0x42797bcf, 0x7d44da2c, 0xe6d29184, 0xe2f1b47e, 0x7929a8d7, 0x8bcdab5e, + 0x0415d7d2, 0xd0e1cc58, 0xeb48f3e0, 0xa6a14e26, 0x299d2881, 0x5cdd9f0c, 0xb95e07e3, 0x480cd471, 0x48f5a9d5, + 0x88608b57, 0x9b608746, 0x2c6047eb, 0x07eb6c0f, 0x438fa2e3, 0x5be69b33, 0x72b2b2ed, 0x310ed823, 0x0f821ed3, + 0xd219c9e5, 0x855c0a18, 0x7af0bdc9, 0x8334849d, 0x8d6d440a, 0x66342c95, 0xb5b0bc8d, 0x6d609005, 0x2b92b97d, + 0x6a4f5e28, 0xa629e728, 0x6af64954, 0xae737e56, 0x5577b158, 0x2c3b9ac8, 0xa1791f69, 0x7cc6be57, 0xf9b86b2c, + 0x05569087, 0xf941c582, 0xcdd05f76, 0x3475b09e, 0x9315f1c9, 0xbfb2ddb1, 0x27eb8ef2, 0xdf4afe19, 0x71a46fd2, + 0x0b4c648b, 0x89fa97cd, 0x09908bee, 0xb6826440, 0xb5fd0660, 0xb2bb5489, 0x7ddb5eb1, 0xd8192fbf, 0x99b6937c, + 0x0d13699f, 0x266e826a, 0xc3e74434, 0x9220a006, 0x558a93f2, 0x150d9202, 0x190943b3, 0x1dafcf11, 0x89f41eeb, + 0x5dcf61fb, 0x1974e674, 0x69f10a08, 0x9af138bb, 0x6f2e8fa9, 0xcb6f110f, 0xc3752f51, 0x1fbc3001, 0xeb6aa4a0, + 0xa3bad8b1, 0xa465c0c4, 0x6bde35c2, 0xbb77f0fb, 0xc55c0350, 0xc5224198, 0xd63cd846, 0xf07cc6e2, 0xa388d467, + 0xf02cd48c, 0x587a159e, 0xb4268b1c, 0x6995d86a, 0x96a64ee9, 0x6dbb22bb, 0x9a0636cf, 0x26ee3225, 0xa16732f7, + 0x88b0e918, 0xd8aade59, 0x856762fb, 0x5f6e63ac, 0x92e233ff, 0x0b531ed3, 0x9a8cfa6a, 0x53b3be76, 0xe1c80acc, + 0x75b82f2e, 0xb1adaf98, 0xe76018c8, 0x920a94b6, 0x1aee0b48, 0xa951a8e9, 0xe5fc868d, 0x072f55c6, 0x23ae35a3, + 0x3512d9b6, 0x8ec5dab7, 0xccf92ee9, 0xd02bb9a4, 0x0f1608cf, 0x8db82f1d, 0x053728c0, 0xed7abf92, 0xa13e3144, + 0xe558fc04, 0x3df2b309, 0xe792e9ca, 0xac985393, 0x0afd8dff, 0x86d56f65, 0xaad51823, 0x2ef669e4, 0x012cdbe8, + 0x719dadc4, 0x474c4326, 0x648a7de5, 0x763548e9, 0xe2273c34, 0x58987641, 0xcec0ca3f, 0xf2cba75d, 0xd637b1d5, + 0xd58e8833, 0x08dcc16c, 0x3fdf11f4, 0x76bacd97, 0xf0a58787, 0xc197198c, 0x8a11f6af, 0x2f3e6859, 0x8ce7322e, + 0x91ece500, 0x8a9ca749, 0xe59622c1, 0x05f574fb, 0xd1969d64, 0x69a72f1f, 0x06090b51, 0x0cac305f, 0x7cc987ad, + 0x04da4997, 0x5576b5cb, 0x859c8ee4, 0x1e7eaa08, 0x16c0a9a7, 0x4fbe8a0c, 0x13b62e78, 0xee63e4d1, 0xfa55aa0e, + 0x05b83a34, 0xf31e0b9a, 0x8b512efb, 0xf1ac8668, 0xc425216b, 0x73cb93b8, 0x0e26b272, 0x8fac8955, 0xb8fe4374, + 0xcc101d6f, 0xae78b24a, 0x4501e888, 0x8a568802, 0xbadb9662, 0x23464924, 0x5f0687ed, 0xb72abf06, 0x38fd1def, + 0x45b3c778, 0x2ee0c167, 0xae8a0325, 0x3ec44d27, 0x1d762262, 0x9857ebaf, 0x7686bd44, 0x106068fd, 0x1342c1c3, + 0x39126f3f, 0xc0d59583, 0x518ab36e, 0xff4fb536, 0x4c947dbb, 0xe971607e, 0xc1a3b30a, 0xe46fd0f3, 0x22b2300e, + 0x0fdc252d, 0x3f93e617, 0xa17f3ff5, 0x07d3f2b4, 0x88a22c18, 0x4484bd93, 0xe2352147, 0x425d8434, 0x8557f5f8, + 0xf7b03565, 0xf77724d3, 0x7f7c3520, 0x89a8d1f9, 0xe2775a3b, 0x80276e89, 0xfe782431, 0x8b0b36b4, 0x52803dc6, + 0x2b295093, 0xdfd8788b, 0x76b31f00, 0x190f23fa, 0x62e02d40, 0xd41ccf50, 0xb8a759cd, 0x5a1fd7f2, 0x70587e1f, + 0x421cc34a, 0xa87d456a, 0x430a57dd, 0x97c2effb, 0xa067b324, 0x19a290af, 0xd17c3e58, 0xb1f8c324, 0x7122b845, + 0x014c4691, 0x9d21bff9, 0x88e296e8, 0x71904652, 0xc98a78d3, 0xf2dfa5b1, 0x5aa4c976, 0xf7328e6e, 0x522ccd1c, + 0x13282c62, 0x9b3b1085, 0xa7d36127, 0xb430a245, 0x3c4e8a82, 0x5e4fce80, 0x7cb9ab69, 0x6d68b05c, 0xc29fce36, + 0x69ebb6d6, 0x82026956, 0x48ee0110, 0x043749df, 0xe13d14f2, 0x30ea0039, 0x0618ffcb, 0xdfb99727, 0x335a5d86, + 0x0214c2f7, 0xda8e4db5, 0x28fa7f7a, 0xbfb519af, 0xa4af40cb, 0xaae47da2, 0xcffb3857, 0x7c615aab, 0xed88d73f, + 0x93f711f0, 0xef66ecba, 0xfc7098e8, 0xdcb1eaca, 0xd8acafdf, 0xad518adf, 0x5bae53f8, 0x152c799d, 0xd0dbc666, + 0x0e5c6e8b, 0xfc8b87d8, 0xe689933b, 0x57eddbbc, 0xf8276e1f, 0xc7029b4b, 0xdf0a3154, 0xc771d9a5, 0xa4f9275c, + 0xb20775e4, 0xc249a4fb, 0xa797d9a5, 0x7480be23, 0xa14d4411, 0x1fe4cafc, 0xbc40f499, 0x2a2a3ec7, 0x889abac8, + 0xcd657ff5, 0x93199e56, 0x329a49d4, 0x1ea328e1, 0x6e0ce2f6, 0xd0a13c8f, 0xe78cca24, 0x2583fde5, 0xfacd875b, + 0x5d94bdfb, 0x962b9d7d, 0x85d667cf, 0x62092a4f, 0x2e59bbc8, 0x632f32b3, 0x3b8a6fc0, 0x7657f14d, 0x321f6488, + 0xe4954fd4, 0x68ae22af, 0xcbe98dcd, 0x39487c31, 0xeca007f0, 0xe31b1dad, 0x34297c7a, 0x3012b220, 0x4ca4f159, + 0xbcbe5e46, 0x43a3c7c8, 0x6a0c3de0, 0xbc832eba, 0xa1d4a52b, 0x2525f987, 0x62fc5791, 0xc72ef9ca, 0x3fc020ab, + 0xa394d7b8, 0xc17a1b34, 0x4bebfa0f, 0x38a7c1e3, 0x3774ebfb, 0xe0d6e78b, 0x6e573224, 0x34cf5baa, 0x832be8a7, + 0x62669f03, 0x9fb16cf9, 0xdfd3f0de, 0x3fa1f874, 0x19986cf4, 0xcebd98f6, 0xe4293a78, 0x0c7ea664, 0x2431da91, + 0x103fb2ed, 0x0e3cdf80, 0x0627696b, 0x8fd6e3f6, 0xcabdb1e4, 0xbb72ab32, 0x96bf9277, 0xccc0941f, 0x7eb144d9, + 0xd0557605, 0xa204e602, 0xb96f9141, 0xc9ced197, 0x9dad1d00, 0xfac419fb, 0xf53eda88, 0xd2cd279f, 0xfd1483c7, + 0x9219ca86, 0x335bb08a, 0xd058a8ea, 0x05285b66, 0x528bd19e, 0x95ac5431, 0xb192c529, 0x9a7d6d62, 0x1b554e9c, + 0x67920f7a, 0x6edaf80f, 0x66ef5615, 0x32cd80d6, 0xbe68ff1d, 0xe4fdb5b0, 0x3b80c86d, 0x3e8b5f63, 0xeb1bc898, + 0xa47618e3, 0xd54024aa, 0xd6c4648c, 0x8b5fc8c0, 0x90741240, 0xd5733a1d, 0x0d040d49, 0x90a1f9a7, 0xae10a3ac, + 0xde8fa914, 0x35337d58, 0x1eac2bf2, 0x893c2c83, 0x705327ff, 0xc77bf252, 0xffcd8036, 0xf10f86d2, 0xa53220a2, + 0x37a746c5, 0x1d7795c8, 0x6b0325c6, 0xf20eb5d0, 0x6ea8f146, 0xc67222d2, 0x40d8aff4, 0x7d73ac4c, 0x6a0ce05e, + 0xd7f25aac, 0xa327d7f9, 0x99cf76e4, 0x2aa02ab2, 0x4841e140, 0x254604cb, 0xd0e5ea23, 0x46edbd18, 0x4c391a17, + 0xec395245, 0x7760763e, 0x9764b2a3, 0x7181c5e4, 0x0c28d20c, 0x48763411, 0x4b6f2f9d, 0x1a5e03f6, 0xd33fa700, + 0x22036b54, 0x448cf9f5, 0x77873138, 0x92e682b0, 0xf57fcad0, 0x75a2f463, 0x5538e33d, 0x50de977b, 0xbe0ef22e, + 0x5b071e47, 0x9f4ecd0c, 0x50d9192a, 0xacc5c3cb, 0x20dab14a, 0xfc7516af, 0xb24b3001, 0xe5240b7e, 0xe9ca42d9, + 0x05c36af7, 0xf21f65c7, 0x61e2f1d1, 0x0c68f408, 0x9496fc8f, 0x77e91fb5, 0xe042eda7, 0x144251ad, 0xc7c1c248, + 0x9d79a630, 0x76b209ac, 0x58989e91, 0xf32d9c7b, 0x65d26f81, 0xd532a614, 0x517fa07f, 0xbbdfa9fa, 0x638aa012, + 0xa7716513, 0xb1cad7b8, 0x6f5d6d99, 0xe8016bde, 0xd8731ee8, 0xcee12c83, 0x683d3685, 0x4af58943, 0x7877b5f0, + 0xf3e3dc42, 0xfe144468, 0x4bdf7b18, 0x48b7f9c1, 0x667948c4, 0x158f9a51, 0x96a2e43d, 0xb51ad49a, 0x1bea6c86, + 0xfffe6004, 0x38cf9620, 0xa9a7cbd0, 0x51e8d293, 0x56f11ef0, 0x70c3268e, 0x878fe552, 0x7868f891, 0x211256f5, + 0x51734062, 0xc37e5e6e, 0x3b278249, 0x462d639c, 0xe7fc54a6, 0xb9aa0bdb, 0x2b5671fb, 0xa6ced401, 0x944c6095, + 0x7cfede9c, 0xca00df0d, 0x41c53ba0, 0xbfd50d55, 0xbf2ecbd4, 0x487ca3dd, 0x21607e7e, 0xd9ab1ef6, 0xe628c2be, + 0x7896bdb0, 0x17677207, 0xc2a84511, 0x4762e1a0, 0xd2a46f82, 0xdf134e20, 0xb6c57018, 0x48d7067a, 0xaca46214, + 0x84747519, 0xd38d3d90, 0x4aefde2c, 0x62e20792, 0x9e14d66d, 0x125f0daf, 0x0bc0f929, 0x505471f7, 0xe5b4f97d, + 0xbdb2797c, 0x713c086a, 0x76b5bc78, 0xd4c16c8c, 0x03eb8787, 0x3b14e5be, 0xbb5ce24b, 0xa1be371d, 0xa7432dec, + 0xdbf07011, 0xf88753ff, 0x006f1ca8, 0xacf320ee, 0x6bf1c9f5, 0x8bc16a8c, 0xecc8bb50, 0xfc5ec35a, 0x230695b1, + 0x56486b01, 0xbb47227f, 0xe1dafad7, 0x40672686, 0x8909846b, 0xf99980b7, 0x26189ee9, 0x1383eacb, 0x3736506a, + 0x2d247c6b, 0x8bc8325e, 0x7928246e, 0x3e0b71f0, 0x68c860ea, 0x11716b60, 0x4b876a11, 0x8a19ad3a, 0xb9b20e02, + 0x77b7b5b8, 0xb36bd02d, 0x4cec70d1, 0x73aacca1, 0x4b1d2ca1, 0xb58d7691, 0x8b4c3f52, 0xf1c3bd58, 0xb33098da, + 0xc2a2241d, 0x04cb382c, 0x80d4c1d7, 0x088a2c01, 0x24470574, 0xb119de03, 0xfa869fa9, 0xff0646bd, 0x7acac8bf, + 0x64666d62, 0xf8eef6ff, 0x0239de47, 0x5ab1159b, 0xf284e766, 0x3f06a7ef, 0x85a2aa24, 0x08add9d0, 0xf0479060, + 0xbf124fea, 0x6c78b096, 0x077d1741, 0x22959943, 0x9c9f74a8, 0x2f8b1670, 0x84e43037, 0x414e0629, 0xfab9b57c, + 0x1af8bf6b, 0xfb3cd9e2, 0x208fef77, 0xbe4cd23e, 0xc8dc2155, 0x2340041e, 0x213581ba, 0x06f9d04a, 0xb1eed558, + 0xb39dacb6, 0x93babc57, 0xb32b4992, 0xe9f98f2a, 0x2de6a463, 0x0802d307, 0x18a5cf21, 0x38d09e65, 0x6486d6b5, + 0xdf3eb868, 0x14b42b99, 0x5dee5b45, 0x640d7e72, 0xc4a086d0, 0x3de1fa09, 0xc30c20f5, 0x8c5d5a71, 0x18aaff49, + 0xe588d7ca, 0xbaaab89c, 0x395688a9, 0xa67012d3, 0x2e7532fc, 0x56e648d9, 0x3c91b5d2, 0xc38f1a3e, 0x66bee8b7, + 0x34343a99, 0xc33f49d3, 0x117e4ca6, 0xb8d9947d, 0x2d88cecd, 0x78437860, 0xce5c61d5, 0xdeee78e2, 0x0232d685, + 0x52922b45, 0xaa3718a4, 0xa8fd8e7d, 0x9e057d1a, 0x5b295114, 0xa6f32e3b, 0x26b54ce2, 0x4e13ac09, 0x2fa0433e, + 0x582c3973, 0x38ee9053, 0x2729fc28, 0xf5e38da4, 0x59e22f2a, 0x90cd9452, 0x2548be3e, 0x647e8248, 0x136cfe9e, + 0x74a23ca0, 0xc2d8ba26, 0x9038f371, 0x41ff7a82, 0x6957bd41, 0xea709ba0, 0x02bd2293, 0x83aeaa99, 0x8e54e8df, + 0xf7b7c871, 0x394c8a4a, 0xffd22a6a, 0x29377ffe, 0x8137c563, 0x212cd94f, 0x7e7242e4, 0xc1d9c7d2, 0x7f9d45ff, + 0x586008e7, 0x300b3ae3, 0xdc85d2a2, 0x76f8fd12, 0x9c4be539, 0xef03472a, 0x20801e55, 0x8a62f076, 0x90849376, + 0xcc24203a, 0xf2aee89a, 0xa5b38cd2, 0xf7ebe7ca, 0x9fca59d2, 0xfee83ba7, 0x5621ee10, 0xcfa90d72, 0x9f1399d0, + 0xc3e39695, 0x75780e08, 0xcac73d45, 0x9d3f2f8b, 0x221a2daa, 0xe182a8d1, 0xf9181e71, 0x50f204eb, 0x2eab3c2c, + 0x63d1ad07, 0xc9ed328a, 0x983e7b57, 0x083d63c4, 0x4f734d4c, 0xb67616be, 0xf930ba4c, 0xb330bc03, 0xa3f06757, + 0x0c41ccdf, 0x5fb6ee40, 0xb112dd3e, 0x83f11b36, 0xe7784f6e, 0xfa80e3c6, 0x35f1bc74, 0x50090492, 0x1265188f, + 0x6e9fa755, 0x6f4d51f7, 0x66374be7, 0xb6199976, 0x1281ae6b, 0x20372345, 0x1b017a74, 0x082ae93e, 0xe9795454, + 0x026fd2e2, 0xfbb89142, 0xa30deb68, 0x75e7640f, 0xbe3db876, 0x4fc1122a, 0xba27bf37, 0x9ef845ae, 0x853d7e60, + 0x914d93f7, 0x69432a66, 0x7b3eae69, 0xd7335c37, 0x68971616, 0x10e12558, 0x90cf62a1, 0xd7ba05ca, 0x8dbcc199, + 0x7e2dceda, 0xc1b947b0, 0xb86f4a27, 0xa6c64859, 0x9e95f740, 0xc81e6909, 0x8cf1b1d5, 0x57d28ab0, 0xbea22f13, + 0xe014ee63, 0x5ea75e8f, 0x0dc510df, 0x3d866549, 0x86517f1c, 0xa9684d17, 0x1098542a, 0xcd643137, 0xe8b0a671, + 0xf4ef4c86, 0x27c0653e, 0x6a9c70b4, 0xb29940c3, 0xed3b07c1, 0xc3a0f727, 0x2a309702, 0xaf455416, 0x0190715e, + 0x09038fa3, 0xaef3afa9, 0xc8163469, 0x3917e195, 0x60324de9, 0x2fab179e, 0xf4bd0fe1, 0x950ed058, 0x0d24bdee, + 0x09bb1b7b, 0xf9152f8d, 0x47bae1b2, 0x64e6d9da, 0xb06a2f52, 0xea3afa70, 0xf220532e, 0x0aca8ab7, 0x7336a4ea, + 0xfe14ef52, 0x3b3ff33b, 0x7d096ffe, 0x082ffbb7, 0x1be9e875, 0x5a5dd60d, 0x60977044, 0xec563b18, 0xa54a3179, + 0xa30a9638, 0xe98940e2, 0xde482099, 0x4f576e7e, 0xfb123ed9, 0x1bef977c, 0x8d8c658f, 0xb588b770, 0x3c8a9130, + 0x03eb0950, 0xf250ac1e, 0x9d410ec7, 0x6379d966, 0xb76e2279, 0x4748fe57, 0x8757ca64, 0x92d5f5dd, 0x7f69b318, + 0x3ae90dbd, 0xc1a7f38e, 0x0e959ac7, 0xc3127799, 0x557ec15b, 0x87cd1197, 0x5477c323, 0x13e1a6da, 0x81f27e17, + 0xfb8c9c60, 0x462d297e, 0xca76c9a0, 0x3a7bf8ee, 0x833c2acc, 0x6df6fd09, 0x0def8af7, 0x56a87536, 0x4028ca4c, + 0xc611bf05, 0xd8d3ddfa, 0x769ac429, 0xe119afa7, 0x51c1a656, 0x613954b8, 0x3e1e4575, 0x274f05df, 0xa9b0d89b, + 0x4637073d, 0xe1dc3bb3, 0x2b38e1d4, 0x97c64361, 0x8cbe01ec, 0xba5326f9, 0x2b79bae2, 0xc2d36094, 0x9493f2ca, + 0x88c1c20e, 0x857c2749, 0x6f4e1712, 0x66142e04, 0x5dcccaec, 0xe7cd073b, 0x22943f12, 0xcaea134f, 0xfe335ec7, + 0x47e26af9, 0x045213d5, 0x5d1820ff, 0x4d2157ac, 0x7da3fa03, 0x4542eec7, 0x369b5aef, 0x88b41e11, 0xb4c81bf6, + 0x76bb589d, 0xd705fbc0, 0x4b2bd5cf, 0xe7b033ff, 0x402123c3, 0x8e705b79, 0x7adf93dd, 0xe168e4b8, 0x7a312743, + 0xfcf94e59, 0x9658629c, 0xc39ab1c4, 0xe8e83428, 0x26daf3ce, 0x9e3dd308, 0xaf4c7df1, 0xbe4021aa, 0x352d8c82, + 0x32a8f69c, 0x740a2962, 0xec560434, 0x83924a0b, 0xa137fdcc, 0x9ed79c12, 0xd38117e5, 0x5829b3b1, 0xf95e1561, + 0x8ac5ae33, 0xe529b6ea, 0x984494d0, 0xbed83bdd, 0x7ae8406b, 0x0b932d11, 0x17e06ae7, 0x28169860, 0xc6b6f9f4, + 0xaecf55ba, 0x95763bc9, 0xab2b805b, 0x2a30710c, 0x817c833f, 0x03d1596b, 0x5bee8cc1, 0xea9f7ebb, 0x57e5950d, + 0xb670ecac, 0x2cc81011, 0x6da0bcbf, 0x8a557783, 0x3e328d13, 0xf7dd225f, 0xcef189bb, 0x0776ca2d, 0x2f01b2fb, + 0x3c4f93fa, 0xe630030e, 0x97efc7c0, 0xb18df001, 0x2fb0ce41, 0xae4a50b7, 0xd9fb5ecc, 0x92209419, 0xdd38d1e7, + 0x500956f4, 0xd4a70f63, 0x5d7c9ace, 0x651ec63b, 0x6ae33489, 0xdc548261, 0xcd8f9a0e, 0x0e7c1e0b, 0x7f3f529e, + 0x68eee0b0, 0xa01a590a, 0xf0bafcd2, 0xa3148e02, 0xd9a0626f, 0x4ef7da9b, 0xa06c3e97, 0xd4795a28, 0x8659b9e3, + 0x531da00f, 0x6f39782d, 0xc759e39c, 0x09d23cf2, 0xb79d7879, 0xffe0a47d, 0x0e71b788, 0xa096f563, 0xe67bb1a5, + 0x78ee3262, 0xd9df609b, 0x8095a896, 0xbfb766a8, 0x8bfda125, 0x7c7c88ff, 0x9530d321, 0x8eec92dc, 0xa279f7b7, + 0x27c10ff0, 0x3ec34751, 0x7101d3b9, 0xc3020b3e, 0x06627708, 0x95f08026, 0x7e5c282d, 0xc195442f, 0x647b6bdb, + 0xfb96bbb3, 0xefe4aac1, 0xbed5d875, 0xcec7bd9d, 0x4450857a, 0xcef6f7f0, 0x1ba66da6, 0xc9e37dd6, 0x8b255f66, + 0xd8c751c6, 0x3fde1dcf, 0x1863cb3e, 0x53dacc11, 0xf95a171d, 0x10e900f0, 0xb9e37c52, 0x9c9ca3f7, 0x5455b910, + 0x8664d457, 0xb20cfb05, 0xd9cf9783, 0xb4c8334d, 0x9d0bca9c, 0x513211de, 0x9a397e5f, 0x24be6d0c, 0xa06afb1f, + 0xf5623dda, 0x803e5992, 0x92a9a61e, 0x5e31dca5, 0x28b37e1d, 0xf29f7ae7, 0x99b5c35e, 0x2c527c6c, 0x13638b61, + 0xd0754868, 0x45ca8bf7, 0x26c17032, 0x593cc220, 0x3055ef42, 0x4bbcb58e, 0xe4304ed3, 0x61c4523e, 0x570e98b7, + 0x586661b3, 0xde5ac3af, 0xb640c7b2, 0xa50c8a6a, 0x3ca74a4b, 0x9cb22d16, 0xe789867b, 0xb719d1eb, 0xff192bca, + 0xe63a7aff, 0xad563bf1, 0xc9f904e7, 0x2285faa9, 0xa7998eb1, 0x1987d0f5, 0xc630f2d2, 0x364e2fe6, 0x1fce4f03, + 0x57d405b5, 0x3279a0f2, 0xc7573bac, 0x4243c194, 0xf7c03986, 0x2a0f1aa3, 0x71f2f3f1, 0x5c02e585, 0x91f67388, + 0x48172335, 0x86cd0048, 0x7d92296e, 0x11a45cb2, 0x760082eb, 0xb55bc810, 0x9cb91c40, 0xce7f0a87, 0x77537e73, + 0x7e2924c0, 0xe2aa6d29, 0x04ee0ed1, 0x3c89a44b, 0x6db2daff, 0x6fdca923, 0x3749bb83, 0xd73d2e37, 0xc7d45a9f, + 0xdd3edde6, 0x7fe60f00, 0x17354a42, 0xd727ea3e, 0xdd9a3fae, 0x4a5448ec, 0xa3fd1c2e, 0xd51b9212, 0x54064ce3, + 0x393f0fb3, 0x8871ac38, 0x4ec8448b, 0x28fa41d3, 0x41c6c7da, 0x47214b30, 0x545ac071, 0x8b26ba9c, 0xd737a103, + 0xb36f1d9b, 0xc5061fba, 0x252f9679, 0xad339f0e, 0xce26729e, 0x8f0e3448, 0x473c113c, 0xd7b06762, 0x4dda0fae, + 0xbef9414e, 0xf728b570, 0x54898c76, 0xb49a748a, 0x9ae7fc59, 0x353eed81, 0x8562d18f, 0x7333fcb3, 0x1f458dca, + 0xe8e1b271, 0x792911a7, 0xaeab5f6e, 0xe0852fbf, 0x5fad0a36, 0xffceb9fa, 0xdb0f250a, 0x50098eb5, 0x3b47c4f3, + 0x8b3cc760, 0x10e8d3f9, 0xb1484f3b, 0xabcd56a5, 0x729aec1a, 0xbe0786b8, 0xcd9e2949, 0xdbed77a6, 0xa137c99a, + 0x93145796, 0xecc5aa3b, 0x64cb2972, 0x830cf577, 0x47b52d5e, 0x712ffb23, 0xb0a48e59, 0x34b4b06a, 0x5a404d43, + 0xcad9ce33, 0xb63f8d3f, 0x340ec3fd, 0xb5973a4d, 0xadb894ae, 0x19d0d4e6, 0xe61b13f3, 0x9ebb630d, 0x2e0df2a5, + 0xf24724c9, 0xabd2beee, 0xe006b59b, 0xc97656d9, 0x852128cc, 0xcfe49986, 0x703ccf52, 0x73f73df8, 0x34cf0007, + 0xaa1273b2, 0xce30890d, 0xc1c089a2, 0xc86a62e5, 0x5b225e8e, 0xb0b06405, 0x24755fbc, 0x30ddef34, 0x401a4708, + 0x98de766d, 0x3c6a133d, 0xf4b8165a, 0x0c32e1a5, 0xb014b8fa, 0x6882ae80, 0xa3d6bd8f, 0xff0a4e8b, 0x507162fb, + 0x00da2217, 0xab96c328, 0xf8bfb2cf, 0x1e49053e, 0x3327bc6f, 0xb5c3368a, 0xba97922f, 0x76abe68d, 0x7781c30f, + 0x9d2df558, 0x4f47249a, 0xf4a3eb32, 0xd836460f, 0xb22468dd, 0xbfe9aba1, 0xb9a9c2af, 0x3977ae67, 0x8ff23abc, + 0x40867314, 0x60b862a4, 0x6b4d2bee, 0x146a7167, 0x1d11cefd, 0x03cbad3a, 0xb4fbd77c, 0x0b71a3dc, 0xd785a414, + 0xa642d656, 0xbe57a080, 0x2cb6ce84, 0x2df8a81d, 0xa0729db7, 0x61c06bb7, 0x8e7c938f, 0x339a1cd5, 0x2ba95dd8, + 0x12a0c00c, 0x5d9ce822, 0x907fad77, 0xee060df1, 0xf9b518df, 0xad9d6d74, 0x17056d9e, 0xa8d2c6c5, 0xaf298a59, + 0xfb2629a6, 0xe149b17a, 0x95d2638e, 0xdf48c44f, 0x6f3abd21, 0x5dbc6993, 0x65530e2f, 0xae423500, 0xc4fbbfeb, + 0xfdd7e176, 0xf39f7468, 0x24900562, 0xc1bca88f, 0x4541c5dd, 0xc434064c, 0x87a08336, 0xc908ef97, 0x7e18c2ee, + 0xf1064e71, 0xa7642622, 0x82b8dc03, 0x7f388420, 0x6e6ac701, 0xaa5a16f0, 0x191f3e8d, 0xac9f33a0, 0x1839bf93, + 0x2d5b93b0, 0xac780d96, 0xf48c29e7, 0x79d71ab0, 0x116abd19, 0x8ce67275, 0x0969e901, 0x7ffc3f3d, 0xd61997fc, + 0x7d6328e8, 0x5a16fe0b, 0xa8a3e303, 0x85454aa4, 0xa0471323, 0xe791cb15, 0x6042580e, 0x515abe54, 0xf6a7808d, + 0xd5e771c4, 0x3d07d8a2, 0xdf406248, 0x8da133db, 0xac1892fa, 0x4e8ea890, 0xdbe250c8, 0x1d68caa2, 0x410da178, + 0x3ddacf39, 0x6f81f884, 0xac4a35a1, 0xd84581db, 0xc11be06c, 0xc5f9ecad, 0x1796f0c2, 0x695e40c8, 0x2ca53370, + 0x5693a631, 0x95790b24, 0x964ed2e0, 0x69c51c05, 0x8080dd79, 0x22fc0afa, 0x4f741bc5, 0x1002a92b, 0xb86f4614, + 0xa6e12851, 0x3350c9e7, 0x8a2f2ec9, 0x41c2eaed, 0x07df9d63, 0x447dc144, 0x091c67cb, 0x68e6b110, 0xb702e318, + 0x7eda598b, 0xe191a7c1, 0x4e0ba090, 0x75dcbe98, 0x90b00f04, 0x5b267231, 0xb27f52bf, 0xaf5b2802, 0x38757069, + 0xbaeac964, 0x0b10c27d, 0x5cda3726, 0x8f35cf76, 0x215e5079, 0xf3519ae7, 0x95024bc4, 0x7c35bc04, 0xdcb471fb, + 0xcead1178, 0x285186eb, 0x2434b931, 0x2b55a005, 0xe1962385, 0x2b5ab2ea, 0xfe06bb1c, 0xc116fc54, 0x4821e49d, + 0x1a424cbf, 0x7e572350, 0x757f142a, 0x285973b9, 0xafe7ba16, 0x2f3a73f1, 0x1cde0d33, 0xb945b34c, 0xf6f935ee, + 0x9c6dbe53, 0x4ef886d4, 0xb76cd53f, 0x83be1a04, 0x434e652b, 0x507315da, 0xc4c3d7cc, 0x7bcd6606, 0x434f9fca, + 0x0fe00b49, 0x2a397256, 0xbb52ec89, 0x5c3d05b2, 0x0ab55cf8, 0x03aeaa5f, 0x15da750e, 0x6db7d469, 0x5434248c, + 0x63685c91, 0x900db82d, 0xc8af93a3, 0xc0fac972, 0xd0bcacb4, 0xf06f8360, 0x92b04ce2, 0xf8c6e72d, 0x45997f9f, + 0x4491c99d, 0xc19e0ba6, 0xb3d4efba, 0x7002dc17, 0x5e2e38c8, 0x5e1cdd37, 0x27f96147, 0xb495533f, 0x26449ce3, + 0xfa399425, 0xcf6613e9, 0xc7812398, 0x7bc31d1a, 0xb4a8d5b3, 0x679a2a6d, 0x59c203e2, 0x918147e6, 0x07194fb1, + 0x45f5ac03, 0xc7d5ab8b, 0x63d5f0e4, 0xe6ddf8a7, 0xc77844b7, 0x5aed261d, 0x5fcc4142, 0x75535136, 0xda518c86, + 0x7f0cee9b, 0x951972ec, 0x6a76cb7d, 0x9f5a7760, 0x95ab9216, 0x1e9325dd, 0x8907f8d9, 0xfe8c4fd5, 0xb94faea4, + 0x88afdce8, 0x46376e9d, 0xfe22f3fc, 0x97ea0636, 0xb4ecc54b, 0x738e8f53, 0xd1cacc53, 0x82485ff6, 0x59b7a122, + 0x5bf91593, 0x2f63a0b7, 0x0db68f3c, 0xa3eba1d6, 0x2454568d, 0x690dadf1, 0xda5a560c, 0x13d74317, 0x1d48f01a, + 0xabd3f13b, 0x2834c90d, 0x689e8a2f, 0xa75c2e69, 0x874bb412, 0xfe0e2db3, 0x24d2ee29, 0x9c9ca377, 0x8c5a92b6, + 0x7fa0aa41, 0x5a5f8651, 0x427b1e77, 0x540bb8eb, 0x073a8399, 0xed530c8a, 0x5fed09f0, 0x056b70f2, 0x13b34405, + 0x2a0fad6f, 0x0f362ee9, 0x5d37cb7f, 0x96a64c25, 0xa12922ab, 0x55a6a7b2, 0xe0d5f513, 0x7bd6725f, 0xbfd66228, + 0xcb7df5eb, 0x3e0f4b6f, 0xde596a0f, 0x5e757eb1, 0x6498ae24, 0x52653a62, 0xe9098346, 0xdaa176e3, 0x56fff30a, + 0x7c213b78, 0xc8cd1384, 0x8ff4aebd, 0x7bba66b0, 0xf5ed1cbc, 0xd3d22009, 0x294dd44f, 0x038ddda6, 0x72f5aee5, + 0x3a276c32, 0xd0084b64, 0xa7f1bfd1, 0x6701df88, 0xe78b8d58, 0xbb9166f2, 0x050343d6, 0xdcd9067d, 0x5c32b140, + 0xf170dd4c, 0x3148758d, 0xa74812bd, 0x12880609, 0x16bfda6b, 0x03a8b6f5, 0x9bbdedb3, 0x81dd9dad, 0x76b890cc, + 0x72edd190, 0x5e898110, 0xa85da601, 0xd6900d35, 0x3df2b422, 0xa6fe05a6, 0xb49972b7, 0x5fb262c4, 0xb7c981a8, + 0x0d604346, 0x49270e0e, 0xb5f4818b, 0x3c76e043, 0x929e75cd, 0xe96fba3d, 0xe4b7c54f, 0xec4847f4, 0x6895fa0a, + 0x06a1c192, 0x88850792, 0x6baf6989, 0xdef242d9, 0x60d278fd, 0xb3c77d6d, 0x520f6e60, 0xe65a3bc6, 0x208e8332, + 0x6c615065, 0x035c744b, 0xa8fda3be, 0x3183366b, 0x5eec7c60, 0x39940dfe, 0x17149bbb, 0x86ea7cb6, 0xdb764de4, + 0xe3753fad, 0x6985ff79, 0xf0b5c03c, 0x80475416, 0x9675d549, 0xcb1000af, 0x13e356f6, 0xe2d85167, 0x060c9b4f, + 0x35ebefb2, 0x41796049, 0xa35c6138, 0xc094b827, 0x00307b2f, 0xeabe88d7, 0x4e1656f8, 0x89252918, 0x8fe3e9cd, + 0xa1e88413, 0xfe4206bc, 0x3dea97ad, 0x166d7a76, 0x0166c4a8, 0x2ffa33b8, 0x8744ff76, 0xe4714f2f, 0x9c73b00e, + 0x2fa841fe, 0x07d6d256, 0xf644d0eb, 0x37e8b58e, 0x9027775c, 0x4297fa7c, 0xe98defc7, 0xc51d57ab, 0xad88b4c5, + 0x0761e98d, 0x1e76968c, 0xd025e7e3, 0x79acecbf, 0x2c963fe9, 0x86590b6f, 0xf1096b77, 0x3fe5bc22, 0xef4740f4, + 0x65e4c61f, 0x4a83fffb, 0x53e48e20, 0x3ad102d9, 0x0fb84377, 0x7cba70f6, 0x217a46a3, 0x5443e39a, 0x77b4da59, + 0xfc174021, 0x97959708, 0x852d8afb, 0xa0b36396, 0x570ddb05, 0x284f80b5, 0x502b765b, 0xe84942cc, 0xb770eff9, + 0x6263002a, 0x80019b3f, 0x8cd1ee55, 0x424743d3, 0x2a370b17, 0xa769a94b, 0x7e6503c8, 0x6faf16ce, 0x0891a5bd, + 0x76c25cf2, 0xb468c723, 0xc874162b, 0xf3f7adeb, 0xa9d4c762, 0x9041812b, 0x8fda1bce, 0xcd89bd43, 0x2b4bb46d, + 0x157a9882, 0x7627d408, 0x33e6d895, 0x8f16b4b0, 0x8e1abd26, 0x9f7884e2, 0x7402a8ad, 0xbbb1c7a3, 0xd52e335c, + 0x6f6d18ee, 0xcb6c4b76, 0xb896a407, 0x4538f24f, 0x1f838f07, 0x188f769a, 0x18277848, 0x5e478e03, 0x38533ce2, + 0x74235049, 0xc9eeb7ae, 0x46c4dba0, 0x67093799, 0x9d021c97, 0xe97d67b3, 0x499b43de, 0x25555bb4, 0xda4407eb, + 0x1711816c, 0xf7430816, 0x02460f86, 0x588ca372, 0x4057ecbc, 0xc5095f90, 0x4698e4d6, 0xb5c8f839, 0xf9821ce8, + 0xb57e6ebf, 0x8c254eb0, 0xcd35cd50, 0x67d2be0b, 0x206e16c6, 0xe18770db, 0x2d30c278, 0x4b94e366, 0x51e95ddf, + 0x9a9508c7, 0x379712c4, 0x6f35822e, 0xa4e61552, 0xe1b8b40d, 0xb7c6374e, 0x5af190b8, 0xbd205771, 0xfdc8d9cb, + 0xd29ceade, 0x7792e889, 0xb4d1666c, 0xb5c2ea95, 0xf1363c48, 0x7fd2dba1, 0x7275cccd, 0x23392ec9, 0x060722b1, + 0xc4897c7e, 0x4e0b2580, 0x3cfd7a73, 0xd5a3e393, 0x4fd3357a, 0xaa1f4ade, 0x032583aa, 0x3a3a6baf, 0xb4aa9f25, + 0xc774cf39, 0x41f64470, 0x2947bb9d, 0xeee13965, 0xb735b2df, 0xa9dca530, 0xd851c4b5, 0x28d3e731, 0xfbc11c2c, + 0x7151bcff, 0x64f06d6d, 0x8975a820, 0x028e41c5, 0x5e2f5388, 0x46ceac10, 0x4ee03105, 0xb1759a7e, 0x4db352c5, + 0xa7894144, 0xe2b84fe2, 0x2ee2c5a1, 0xb3cbef83, 0xda82d611, 0x74e22450, 0x62f576f3, 0xba477c46, 0xcbe5310d, + 0x9d7be74c, 0xa34f9fef, 0xb5a9b9a0, 0x5ceb06f3, 0x4174dc19, 0x934bb2cb, 0xb1928eaa, 0x1013e84a, 0xcca6eda1, + 0xfa789d18, 0x0c47e422, 0xd76ea934, 0xe877c68b, 0xe20278cf, 0x8d2f4cb2, 0x6479b8a1, 0x970d9518, 0x940fa1c2, + 0xd204b879, 0xb2854d20, 0xcd189c07, 0x09f2db8f, 0xced16026, 0x45c1c2e1, 0xd9d166dc, 0xffeea3ca, 0x49a7df1d, + 0x410c1b21, 0xd6b1ef63, 0x6c3b31ee, 0x9263442b, 0x4d3ceedd, 0x017fcbd3, 0xac20cc14, 0xb85b39dd, 0xbffa17c9, + 0xdeb565b9, 0xe2201509, 0x4df46247, 0x0b17c39d, 0x9f1cbd5f, 0x301dc9fd, 0xa8104206, 0x71f76596, 0xb67fe62f, + 0x824e1e29, 0x245690ed, 0x4f182b33, 0xbe9d503a, 0xe20a96b8, 0x06262410, 0xb2ec6954, 0x613c52a1, 0x576d7565, + 0xa25aac1d, 0xfeb8651c, 0x067e20f1, 0x539f702c, 0xa23ee4c6, 0xed7772da, 0x15bf3d70, 0x7f87156f, 0x6e454e7c, + 0x5815dc60, 0xa1c036fd, 0x2fadebab, 0x355ccc39, 0xa706ca41, 0x82a27870, 0xcd750e0e, 0x3d7f50e6, 0x2b678d4a, + 0x438317ba, 0x45f16d18, 0xdc901e53, 0x28b79531, 0x812530ca, 0x5ec13d16, 0x71a0a1a0, 0xba3e3342, 0x7037876b, + 0xfe78f808, 0x7e397e1a, 0x75707e0b, 0x13fd5f94, 0x4a6197bc, 0x08a6caa7, 0xbb2e5048, 0x954e7d5b, 0x67a63a74, + 0xd6a41140, 0x6c213a3e, 0xa20e8194, 0x33d0592e, 0xdd80bdc0, 0x47189906, 0xe4ea25fb, 0xcfb1f5c4, 0x10053631, + 0x55682878, 0x3cc9666e, 0xbf0f946a, 0x50af4034, 0xa0b561c7, 0x4caed1f4, 0xe94d38f1, 0xea42590e, 0x62d45a14, + 0x53213783, 0x3799b63b, 0x6d8f019e, 0x1eb48ccc, 0x5344aaa9, 0x7cbe56ee, 0xb9def1bf, 0xce8adec5, 0x33952056, + 0xc6d039c5, 0x053788f9, 0x8d74bca8, 0xbe7d5498, 0x61f005ec, 0xacb65510, 0x71f5a600, 0xa2ce6bad, 0xef2ad802, + 0x7637ddbd, 0x7ea44ce4, 0x935ec57c, 0x57b3e97a, 0xbaaf3010, 0x4e032e5d, 0x2c693263, 0x04c7c32a, 0xb6125053, + 0x75279d04, 0x4a3a3eee, 0x46e73f11, 0xce9988b0, 0xc302a9bc, 0x761fa8a4, 0x36d6a576, 0x3d206445, 0x04470c3f, + 0x1fd35239, 0xfda86395, 0xc3550b4d, 0x9f0c82a2, 0xb08c6d4b, 0xffe45631, 0xd25be98d, 0x1dcd79bd, 0x7bd8a6bf, + 0x2dae31e4, 0xeaed9636, 0x4d460cb7, 0xecfe1caa, 0xdd19505f, 0xe3bbab42, 0xeee08bb8, 0x912f2fec, 0xad448715, + 0xee58053e, 0xbce42f63, 0x852e30d2, 0xf9fa26a5, 0x4f65e06c, 0x731820f2, 0x0a79ddd2, 0x9e3b2675, 0xcb79db88, + 0x0f0060e8, 0x10d581ac, 0x434f9dfb, 0xd4452125, 0x765cca18, 0x20991c1b, 0x64a2c706, 0x2861e1a7, 0x9fe2701c, + 0x0ed3e9fb, 0xf406607b, 0xf5d4243a, 0x657eab08, 0x064dc48f, 0x2d128d9d, 0xbd0c298e, 0xd8dbd748, 0x1fdb387b, + 0x516e94f8, 0xfd0a6fe9, 0xa94d19c6, 0x8e498adc, 0xbd6c825a, 0x134917b0, 0x134ec430, 0x4a9e0cd5, 0xf159065e, + 0x457fb84d, 0x5337fba6, 0xc998b80d, 0x07c4b5ac, 0x10a5bab5, 0xcd8e4ee6, 0xef7d11c4, 0xa6c718cc, 0xe6aa258f, + 0xc4cccc3a, 0xd070fa2c, 0x63faf703, 0x9c0e11ac, 0x48fb56ec, 0x96c8aec1, 0xbf4d2a0d, 0xe468016a, 0x075ba1ba, + 0xedb5a7b1, 0x2cf56a62, 0x830abda7, 0xe1d3edcf, 0x4c2875bd, 0x4a7d98b4, 0x944f9948, 0xa4350e27, 0xe117ea0e, + 0xd172a256, 0xa7a17765, 0x52cee3f8, 0x0b412173, 0xb0aef278, 0x9f6a61f3, 0xf4bd0703, 0xec8ea5b3, 0x036d757e, + 0xa1ee0704, 0x292c823c, 0x005ab03a, 0x335935f2, 0x3bbd1c6d, 0xc08ec8f6, 0x98274126, 0xda1f4cd9, 0xfb401254, + 0xf73ae989, 0x9f949746, 0x4d64d501, 0x42b442b3, 0xcdfa9486, 0x46edfd40, 0x11ea21f8, 0xf20f5702, 0x0e65d9e3, + 0xf42a75ae, 0x9e9e538e, 0x803139de, 0x523d13ac, 0x13474513, 0x0c4f75ec, 0x27cc5ceb, 0x9c4bed26, 0x72531372, + 0x253facf6, 0x03690ee7, 0x8add4d17, 0x022607cf, 0x13eb99f6, 0x931f551c, 0x0b92ba36, 0x7351b37b, 0x148d5c07, + 0xa82dace4, 0x785c35dc, 0xaf750929, 0xb1443ac4, 0xdd1138dc, 0x92b0e180, 0x23abb58c, 0x0fd6954f, 0xb280a525, + 0xcee20bad, 0x58a7a953, 0x801bfcd5, 0x89232d83, 0xf19f9246, 0xb9b30b06, 0x4a05e2db, 0x76ec7feb, 0x879b750c, + 0xd5a3822e, 0x5233d7c3, 0x274ea04a, 0xd049653b, 0xc414a978, 0x7e93cf25, 0x419d5e82, 0x64a53fcc, 0x8ba3ff5b, + 0x9c887e7c, 0x792e2f70, 0xdcdf2c86, 0xcaa1e232, 0x2bf1a2cd, 0xce230f03, 0x218620e2, 0xee98fbdf, 0x87897d24, + 0x4c231931, 0xa17eb4c4, 0x0ec82763, 0x13b35883, 0xc23154db, 0x1e6a4634, 0x382afcf0, 0xb0357dd0, 0xadcd430e, + 0x63de2d05, 0x12e666b4, 0x09a958af, 0x03223fbb, 0xd6345ee4, 0x74d402f5, 0x237119ac, 0x1088c309, 0x700e776e, + 0x89f6df8b, 0xdd38d1e6, 0xeacf7c78, 0x766765aa, 0xbab0ec8e, 0xa2c70075, 0xd0393f4a, 0xfb880b1d, 0x61daf25d, + 0xdf66895a, 0x9aa37207, 0x4537b368, 0x6b6ce888, 0xab03d5a2, 0x7f64674f, 0xb52f38fa, 0xcf85d1bd, 0x702f88ea, + 0xbc4174bd, 0x186dfdee, 0x0e342ba4, 0xc045ff3a, 0x89fee3b1, 0x726e76fc, 0x6739292d, 0x9e047545, 0x7ed94b4e, + 0xf3d89bef, 0x209b2fd6, 0xba20fa41, 0xd851ac74, 0x28da267a, 0xef98dd93, 0x991debfc, 0xaf3d80a8, 0x90a437e4, + 0x0a71f5c8, 0xe4313d6e, 0xc089db82, 0xb02a80fb, 0x5726a5a2, 0x1fb9c1b0, 0xa7b21d79, 0x81ef8c24, 0x27293fc5, + 0x50ef1876, 0x61d35b77, 0xfd589d91, 0xb3d05c3c, 0x8062a647, 0xfbfd65d1, 0x00cee376, 0x35cc46c6, 0x9d0a4aa9, + 0x1f113bf0, 0x6c544b1a, 0x6075b43a, 0xaa914d12, 0x00edf7d5, 0x25427b04, 0xf3850b61, 0xf8eb7f66, 0xb783d7ff, + 0xd245d633, 0xe7dd690e, 0x63c2885f, 0x08fce9ab, 0x50392363, 0xd814fb3e, 0x31daf81d, 0x2d2c5186, 0xfc3cf64a, + 0xf60eabe8, 0xcedcde29, 0xf4648b21, 0x9661e8a4, 0x7629831a, 0x6a21888a, 0xd58c4dab, 0x58a03532, 0xbd3f5e8e, + 0xdcb9e023, 0x8b8148a4, 0xea56b89b, 0xe31bdc66, 0x70b8ab0d, 0x46d1b3bd, 0x43c86012, 0x304b84c6, 0x7646318e, + 0x6b6df343, 0x55047b56, 0xe4eb178a, 0x2740d414, 0x2f062c6c, 0x2bb87ab3, 0xbbe46759, 0x604592fd, 0x28034951, + 0x5a41d5b0, 0xab3cda0a, 0xec016b00, 0x7892a766, 0x69a55747, 0x5efc7560, 0xddc2a900, 0x22eb94af, 0xe60437d1, + 0xee44e8d3, 0xf371cc73, 0x4e5e6e7b, 0xdbcc442f, 0xbb2f778a, 0xc6d98bd7, 0x18538d40, 0xc979f0e9, 0x4f4be0dc, + 0xa638a6cb, 0x5d0983f6, 0x3e3bb206, 0x571d88fb, 0x241c6359, 0xad67b501, 0xb6253cd2, 0x79c59d55, 0xafd3041d, + 0xa62d0004, 0x939d6fb7, 0x92955860, 0x922f19bf, 0x031a3537, 0xddbb38eb, 0xdee7d821, 0x0207fc68, 0xed548b3b, + 0x70886283, 0x79e8ae43, 0x367892f5, 0x871499e9, 0x27cd4b86, 0xec865f04, 0x7ff18368, 0xe629f3aa, 0x624fc9d6, + 0x938a106c, 0x6d8a7a9e, 0x8c804933, 0x3eb5d6f5, 0x536d60a2, 0xc850fc9f, 0x27332521, 0x4c30fb35, 0xb3387981, + 0xc81f3618, 0x6d1dbdb0, 0x2fa4e5aa, 0x3c182f7f, 0xce06706f, 0xa6f76bf5, 0xb8accd9f, 0x859b6f01, 0xd172b494, + 0x172f34c2, 0x846b960c, 0xa75fb178, 0xd6a4d265, 0xa1821835, 0xb6983095, 0x4be9130c, 0xb56711c4, 0xc5f76010, + 0xdd2010a5, 0x8e85fc3e, 0xf5002fe6, 0xb5fcd270, 0xcde65a92, 0xf4f7ebaa, 0xa5171728, 0x596ed1b4, 0x8fe0487e, + 0xb3a452ed, 0x7be9762a, 0x937f6834, 0xb7ccb972, 0x33e38e1b, 0xc4b79540, 0x8d6936aa, 0xb7f57e24, 0x9142146f, + 0xc0aad048, 0x355f47c1, 0x94d67bef, 0x3f5f66f3, 0xa06f3bc5, 0xca821f31, 0xa3d1b427, 0xe09286e0, 0xfbb49e9d, + 0x22cd5984, 0xde3fbaa9, 0xf1228b0a, 0x109a0b9f, 0x7548c33b, 0xe941dbb2, 0x93f95e81, 0xab081a96, 0xdf747884, + 0x45ed0016, 0xbdb948f9, 0x52666432, 0x2294a781, 0x66b25bb4, 0x2335dca4, 0xc636dc96, 0x766687f4, 0x8273259d, + 0x856f58b2, 0xc5311f4e, 0xfa666467, 0xdaaee17d, 0xf5d22468, 0xb94d77e5, 0xe3ccd5cf, 0xf71ff3d5, 0x059c47e0, + 0xa2677a6e, 0x3690bf4a, 0xf7915003, 0x836ffa5f, 0x8a3df18d, 0x838d8411, 0xb6b54740, 0x5b2ba5a0, 0x2d8db59f, + 0x745bf9cd, 0xec9e0e62, 0x8bb57884, 0x5b5f6d82, 0x44be8f59, 0xe3ed39bb, 0x4ef5119d, 0x10c90758, 0x4c3de02e, + 0xcc0dcdcd, 0xae35ebaa, 0x8b079813, 0x707f4cd4, 0xb28ee485, 0x868e1475, 0x98dd2c9f, 0xbf7e4f5b, 0x2f2378c2, + 0x7e997fca, 0x0ae36578, 0x0714380e, 0xf942af1a, 0xdc924a4c, 0xd462660f, 0x73b985b2, 0xb3443ec0, 0xa79c0a43, + 0x74a7a67a, 0xd1d2f722, 0x3e9d04ee, 0x9a4e1195, 0x626273ff, 0xd2403034, 0xc4a06a7b, 0x59830abf, 0xe25c52c7, + 0x835a60fc, 0x74890b67, 0xba57e1c8, 0x16fd9a93, 0x318964d9, 0x73f3c4e9, 0xc8dcb69f, 0x6b19cc12, 0x848795bf, + 0x35bb1c1a, 0x1e328ed7, 0xb0f9eecf, 0xfcf7d0ef, 0x18084914, 0x41866a66, 0x9a53ef73, 0xc80279e4, 0xfaf76d6b, + 0x6bfc3811, 0x806e5e41, 0x939565a3, 0xb3aac7da, 0x8c29ef06, 0x40ee7f8e, 0x158b6c83, 0xff4fde31, 0xeb907b6b, + 0x1cae2e23, 0x0f2ee3c6, 0xb1695a77, 0x7347da79, 0x16ffd074, 0x4ac8b21e, 0xa36836e4, 0x96d832f1, 0x4f52a03b, + 0x87320d38, 0x4a9b3d5c, 0x96156427, 0xe0010793, 0xca4bb547, 0xa85f29a8, 0x85ee6d70, 0x507197f5, 0xc5727a49, + 0x1ca129bb, 0x87b85090, 0xa54860cf, 0x26e5a790, 0xd4b4c87c, 0x32a58dd1, 0xda70783c, 0x6331fe08, 0x6d5cf3c2, + 0x5ea90f67, 0x7b234c8d, 0x82709b2f, 0x6aae16ed, 0xfe8fb430, 0x91aae7a4, 0xa89c8475, 0x9ee038e1, 0x46752770, + 0x607bc2b7, 0x5a43428f, 0x22c889f2, 0xbab3c6ee, 0x0fac61b3, 0x75dffa55, 0x23d02d78, 0x9e425bb5, 0x59b2e2a7, + 0x9840368d, 0x0d7daf83, 0x5038f381, 0x1a2ca12e, 0xb796b6c2, 0xa8f2aaec, 0x08085d45, 0xe666f976, 0xd77c5ea8, + 0xfaa8692e, 0x89b8d180, 0xe3c2705f, 0x16234e9e, 0xcd4e4fc6, 0x870800df, 0xd723a9ec, 0x93aa6197, 0xccb05bc4, + 0xecf009cf, 0x228d7786, 0xcb35fff7, 0xe9dfde8f, 0xaa78f2a8, 0x3bdc97dd, 0xb0e60ac5, 0x8a238fa6, 0xb42b36b0, + 0xd0948639, 0x103bc6e0, 0xb9c624a2, 0x9ac7ee52, 0xe1bb553d, 0x25ba0f2d, 0xec5a50f0, 0x525071c7, 0x32ae5317, + 0x3664176c, 0xfd6e1cea, 0x40da8e5a, 0xfa450d23, 0x75246f3e, 0x2929379d, 0x8e9b60ce, 0xc0bbf00c, 0x2f72727b, + 0xe43257a4, 0x59a0fd18, 0x3a0585aa, 0x14ffc421, 0xa4ac0cad, 0x20346223, 0xac05560e, 0x3260af53, 0x4f0f2911, + 0xb7f749b1, 0x8dcbfebb, 0x6ed1040a, 0x9cf320de, 0xf91b5c8c, 0xe75e20c3, 0x167f9681, 0x6d2bc888, 0xc4fd3e7e, + 0xa6d9b333, 0xa4335f14, 0x6e3a8d38, 0x29812b76, 0x5f52e568, 0x8a9c434a, 0xde78bff1, 0x29a8e2fe, 0x1d19a3dc, + 0x79913344, 0xbb8e2c30, 0x7c5008e1, 0xffdcb3ba, 0x8d89d735, 0x08916038, 0xc72a7f5f, 0xbcc988f6, 0xd5eee570, + 0xec92250c, 0x5a7c4a47, 0x6d2e33a3, 0x24cb0d60, 0xf70685c8, 0xa3c806a0, 0xbdfae84b, 0xa4a67943, 0xe9b91b21, + 0x9e013594, 0xa81e232d, 0xe8e588ad, 0x775119cd, 0xcf750bda, 0x0ece7f14, 0x175b7be9, 0xf32b1a39, 0xc463947a, + 0x3edfb896, 0x0bfb16d6, 0xaf65c608, 0xdc641073, 0x0f7eac7c, 0xd323ac96, 0x4274a6eb, 0xb4292188, 0x5c04680f, + 0x2d95a695, 0xf4c315b7, 0x3316c523, 0x115295a4, 0xc9d3a324, 0x9b7ef8ea, 0xd92832f6, 0x57361199, 0xc0aeaf06, + 0x84240756, 0x603a8729, 0xbdb675e5, 0xb5ee6993, 0xaa403ec0, 0x389ab29a, 0x0479b39a, 0x0c17e0ac, 0x06d9f9db, + 0x8153fc3f, 0xc6f01456, 0x4fcc2b64, 0xee3c4364, 0x592f68c6, 0x63033033, 0x468cb226, 0x98df9e53, 0xff5036ab, + 0x1c0261cf, 0xd05d7071, 0x44465e19, 0x218ddb59, 0x77c47d9c, 0x9c69cb51, 0x1d2d5bfd, 0xbaeae40d, 0x5ea9b1e4, + 0xcf79acb9, 0xdfbecf79, 0x41fcebcb, 0x80dac72e, 0x2c7c1d77, 0x7ecee1f2, 0x72f4ac6c, 0x0b6a4925, 0x8467441f, + 0x14086e24, 0xe4d38856, 0x39702da0, 0xb8d98fef, 0xb98c2fc4, 0xa8e8edbd, 0x7eff0e27, 0xff3961f2, 0xbc14a79b, + 0x1ade7ff7, 0xf7132d2c, 0xb4416c2d, 0x1391c607, 0x233504bc, 0xc101cf9e, 0x576cc7c0, 0xb4fd6643, 0x5b3022fd, + 0xbf7d2f89, 0xddad1e2c, 0x282c78b4, 0x379a1549, 0x829e057d, 0x0572624e, 0x82317a72, 0x30903914, 0x5f9a21d0, + 0x6a4a1f7e, 0xca77d649, 0xd3418bc3, 0x2f29ee21, 0x9b4cafc7, 0x9e341421, 0x37d49fa7, 0xb84eaafd, 0xfd0a27ae, + 0xc4164067, 0x45dc9bed, 0x9eae801f, 0x5ff14c89, 0x545d3e16, 0x9a50bff8, 0xa4b473df, 0x5ba988f6, 0x1cbade3e, + 0x842b2979, 0x9f8e6bf9, 0x4a9985d4, 0xc20fced3, 0x606207c5, 0x0ffa2256, 0xfb44070d, 0x9b0cec7f, 0x4c1e5290, + 0x732e376d, 0x9d57ab15, 0x82965f34, 0x547e001b, 0x423c95ee, 0x87af89c8, 0xeaf9f712, 0x73850839, 0x55806767, + 0xb7c8377c, 0x29e7e714, 0x0516ad4d, 0xc40e9db2, 0x6bfd6dc6, 0x3a673e44, 0x2230a6b4, 0x66252f81, 0xdf4c86a0, + 0xecf42312, 0x5c589a47, 0xbbada40b, 0xfff3876c, 0xbb138b23, 0x979443c6, 0x6d5f1657, 0xda42d439, 0xc07f15dd, + 0xc363ddb9, 0xd33ff22c, 0xf9937c80, 0x38b30d82, 0xa1db1672, 0x2b3eac71, 0x67b4a8c6, 0xd1c19faa, 0x69cfc6ca, + 0x8c3026e7, 0xa188d3d8, 0xa892578e, 0x2161b6a0, 0x50c75ff5, 0xbb382b9e, 0xd22734e0, 0x71a2c96a, 0x80064848, + 0x62541ad0, 0xc59933ca, 0x3802e3a2, 0x7ffebca5, 0xc42fe47c, 0x1f9b0e66, 0x9e467753, 0x3bbaa10c, 0x9e376c80, + 0xc50a17f2, 0xa004f8d3, 0xccf4612c, 0xdcd3fac3, 0xb3404869, 0xcce5465b, 0xf5a8e022, 0x8d65bfbe, 0xc20cf2dc, + 0x4b06c247, 0xa1233135, 0x7e714e25, 0x88c8d7ff, 0x3e1bf788, 0x1256e988, 0x0f1ee492, 0x1ab61db0, 0x7703de3d, + 0x8b06d9e9, 0x56f112cd, 0x9c92dc4d, 0xab4f9bf6, 0x5badc60a, 0x36d9c113, 0x538b686a, 0xcbf9fb04, 0x25486110, + 0xe8164d57, 0xb6399585, 0x0dd561d0, 0x390e448f, 0xbd2738bd, 0x3a6bd084, 0x6e6fd2ce, 0x33eb46dc, 0x9851d49f, + 0x7e8956f2, 0x8a7133d2, 0xcb330bbb, 0xdf5452f4, 0x5cce6b37, 0x192223b5, 0x037890d7, 0x6839bce1, 0xe26e7626, + 0x842a705f, 0x623c3d5b, 0x367124b5, 0xc933a1f6, 0x263a7c9c, 0xe431756d, 0x586b640a, 0xeeadc0f0, 0x8a486fe4, + 0x74a0cc95, 0x94bcd961, 0x587a22d9, 0xf7ea06f6, 0xfdf978a0, 0x779979d1, 0xc667caa9, 0x0d223ca3, 0x31fa3620, + 0xeeeb21ce, 0xcc59875c, 0x0b36e640, 0x13f41cab, 0x58bad0b4, 0xe17f8eae, 0x44385a31, 0x8cba2cf5, 0x6814bf57, + 0xb5024a07, 0x0ae63377, 0x07dc4e7b, 0x28611a81, 0x4bad52c7, 0xe960870e, 0x7d4eab49, 0xe15b0826, 0xd4f5173d, + 0x6477ae2d, 0x419e522c, 0xa0d4c196, 0xec5c0366, 0x1450a111, 0x7fd76067, 0xd733a95a, 0xde2d316c, 0xb129c365, + 0x82326406, 0x86f2aac0, 0xa4b44353, 0x55485008, 0x60787fd6, 0x34022e64, 0x24ad19bd, 0x7533b42a, 0x2f3004ea, + 0xb3e2880e, 0xf34f6bdb, 0x31482889, 0x1cb00ae2, 0x60bf8565, 0x91a44186, 0x4d8cc0f0, 0xb42fae44, 0x71a5b90b, + 0xc9b216c8, 0x14f2b0aa, 0x2538a209, 0xeaa5d60f, 0x1dcd1483, 0x634dbd70, 0x05b036e2, 0x9e732c4f, 0xda05f6cf, + 0xa43365f2, 0xa1707719, 0x3d3ce930, 0xdaa201f0, 0x260142c3, 0xd5f2eaec, 0x26fc10a7, 0xc10f044d, 0x64b4b7e0, + 0x8b092cd1, 0xc5895c41, 0x5000db1f, 0xdf42aa2e, 0x92bffd69, 0x2b6f4b10, 0xfab8fe75, 0x8aabc5f6, 0x6fcf6030, + 0x1d5eb255, 0xc92d1a42, 0x05af67c1, 0x0df3fa0b, 0x1e041187, 0x1cdca169, 0x708bb289, 0x23adeaf5, 0x51b310ed, + 0x5979e282, 0x8acacecd, 0x53edb1ba, 0x5d1b0d71, 0x66fa8b64, 0xca50c67f, 0x6d9a8c51, 0x9bee1f78, 0xa07140b1, + 0x0ff494ac, 0xcffe116b, 0xf83e53f8, 0x11dc38b4, 0xfc0dbcb2, 0xd24d8174, 0x2a655ff1, 0x70f43419, 0x57e3aa8a, + 0x53da271d, 0x1a8b093c, 0x97434db6, 0xe40dffb2, 0x4b483d24, 0x70b51f05, 0x3d25e3cf, 0xe9472a16, 0xab88c55b, + 0x9ed43be3, 0x88d16f4f, 0x3a6b03a8, 0xadba6e7d, 0xd020f1c3, 0xb91e3ba8, 0x80f70de7, 0x2ee87a08, 0x528bcfa9, + 0xbb8d139e, 0xe44eb0fa, 0x3407e146, 0xeab0939f, 0x67bcb76b, 0x126663fe, 0x29682343, 0xa3edf195, 0x9d03ed8c, + 0xa710d32c, 0x0aba1ed8, 0x1f896dec, 0x8087b0a7, 0x15d60007, 0xd5ea6a47, 0x29fa3111, 0xf40375b8, 0x1b9f8988, + 0xc80c56d2, 0x39094020, 0x55b2d0bd, 0x1806b1e7, 0xc60ede03, 0x2e1de5d5, 0x11ca6ff1, 0xe6a5afb8, 0xe522f2e4, + 0x5df4d01f, 0x8e995072, 0xafb69320, 0x52468837, 0xbf4f5fdb, 0x33576ede, 0xad1d994e, 0xe953b081, 0xed2d5aa9, + 0xe89caa77, 0x86a00626, 0x084613b0, 0xc421434c, 0x97feb9b0, 0xadb154a2, 0x75f69eab, 0x874bf2ff, 0x3a0aff49, + 0xfd987a4e, 0x0d18b1b8, 0xb43c6d89, 0x15ce6556, 0xe1225c5d, 0x66de985e, 0x3d2038e3, 0xcd8bcb36, 0x3ada39ef, + 0xf3292eb6, 0x31c80d29, 0x7acfdcd7, 0xab0e8543, 0x9d789e8f, 0x3ef02323, 0xa0369754, 0xfa7f57cc, 0xef623b13, + 0x0698b8ed, 0x7b35142f, 0x8951cf78, 0x34d67a2c, 0xa5170445, 0xbe7c7d09, 0xf63ea350, 0xa4610859, 0x3002c035, + 0x0e30abac, 0xebc2a1df, 0x565ec8c8, 0xe1f78a5f, 0x5eaab708, 0x577dda71, 0x1b21ae97, 0x67d33082, 0x731e1b8e, + 0x9fa4834d, 0x20332fe1, 0x2871ea13, 0xb2506147, 0x3d216fb5, 0xf38852f0, 0x2abac208, 0x47dd73a4, 0x97f5fe0d, + 0xcadf83a4, 0xd2b1e702, 0x11e3c2f0, 0x2319d4ea, 0x7631adb1, 0xdf082a70, 0x030998f7, 0xd19d73f3, 0xbae361de, + 0xa37ca9b0, 0x65dde843, 0x82339586, 0x44191089, 0x83ef815d, 0x6c404b60, 0x69f747ae, 0x2c75627a, 0x6a3d8a76, + 0x54d03afe, 0x0e702436, 0x87618700, 0xa92f594a, 0x785dbcc3, 0x9c762f33, 0x8a35d8b7, 0x8b68856b, 0xf7a72986, + 0x3412720e, 0x4ae419cd, 0x8a7fde4a, 0xefcf02d0, 0x47c51b4e, 0x7e097801, 0x4e5e538f, 0x42ee1e3c, 0x79e9735a, + 0x84ec1d4c, 0xf492ec1d, 0x1e394b3b, 0x5a1df63e, 0xcf41e103, 0x3f424d54, 0x4ae3c55b, 0x3b4bcf51, 0xe006bc85, + 0x6a882dae, 0x07c807ec, 0x8ecd3f6b, 0x510ebde5, 0x40e8ea11, 0x1a947e6b, 0xd829138c, 0x10152437, 0x2867e431, + 0x1ffbab56, 0x12aa1847, 0xc00c7371, 0x46c55518, 0x42d66f3d, 0x7397b1bc, 0xa51db72f, 0x620cd3af, 0xcc51ea2c, + 0xf910d205, 0x325024a8, 0xbedab9f6, 0x847b597e, 0x53153261, 0xf5d301f2, 0x8b30f7b3, 0x967ec7ec, 0x9cc462fd, + 0xcfb4b559, 0x2f0b9835, 0x63d53406, 0x19bf36c7, 0x933e43b2, 0x5b494147, 0xa3f63023, 0x3b64fb54, 0x56787769, + 0x2f1a4f27, 0x07dfeb95, 0x0789b310, 0x3519475b, 0x35bdb28f, 0x4b8f549c, 0xed8b9634, 0x12dfade5, 0x3e484f1b, + 0xee53f86a, 0x7fdedc44, 0xef45cf13, 0xf836a949, 0x0c90b222, 0xca47a7ca, 0x0ab61bae, 0xfdd2ff22, 0x986391db, + 0x02df7ced, 0x58ee6dd1, 0x6ca7e8f4, 0xbf22b223, 0x20909a6b, 0x97bd3ca2, 0x39df16e5, 0x8ae78f74, 0xe326f58c, + 0x794cb404, 0xc1892f8f, 0x322ba43e, 0x205e982e, 0x6c87f5b8, 0x53979612, 0xa16b852f, 0xb8366878, 0x20e9894a, + 0xbe482ca7, 0x4e6e7478, 0x1def935f, 0x765b562d, 0x52f3fce8, 0xc657f8a4, 0xb48f2264, 0x3f208672, 0xa169ae61, + 0xc02164d2, 0x4b94daae, 0x02edafbb, 0xfbd26497, 0x20d9a57d, 0xe1509bf0, 0x451d06e4, 0xc3f102b6, 0xd811cf88, + 0xc3c22be1, 0x256a84bc, 0x10ed841e, 0xe1253333, 0x8ebc1154, 0xc0fe3ec9, 0x261a0cd5, 0x03294586, 0x75e0cd97, + 0x0f46cdfa, 0x84e83ae6, 0x5f54b283, 0x68d913df, 0xcd12c142, 0xe8e9a925, 0xf40818f7, 0x6aa14985, 0xd2975ab8, + 0xf30b256c, 0x04636e74, 0xd738d3dc, 0x73ad7d46, 0x14de12b6, 0x9efe7bdc, 0x525c546a, 0xd5090040, 0xd7bc9785, + 0x572aa464, 0xe8654954, 0xb0c9dce3, 0x48d2e36a, 0x24803cac, 0x989995fd, 0x4d65a34e, 0x3b36f8e1, 0x27703d73, + 0x6504a0cb, 0x587f566e, 0xe067e6e3, 0xd3ce0f64, 0xfd482ad5, 0x449ba984, 0x2d536a80, 0x95f4e22b, 0x36d842c6, + 0x4412332a, 0xa86fb1c5, 0xea6db14f, 0xed0f3b73, 0x7e709a37, 0xaf0ee520, 0x9f9b3aed, 0x9cd9a8a7, 0xd171ab41, + 0xc666a9dd, 0x1b277af0, 0x918debf4, 0x7292386b, 0x0e0407cc, 0x84451046, 0xdf657582, 0x0b1c6750, 0x08f035a1, + 0x600f7988, 0xe7a3a047, 0x86f28e02, 0x73cd2126, 0x3dfeb7d2, 0x6547f858, 0xcca05932, 0x34e98328, 0x89f8ae79, + 0xcfbfcfd7, 0x0a011590, 0x77e0197d, 0x76fd8545, 0x10539b9c, 0x52438e43, 0x3abedbf8, 0x2098b213, 0xd582ba3a, + 0x01117b14, 0x4263361d, 0xaa6ea4a1, 0x03b3682a, 0x84f77bbf, 0x0edd1c00, 0x600a11eb, 0xd43dab62, 0xde64a3a0, + 0x4caad086, 0x5ef5336d, 0x4aa8fa05, 0x40992438, 0xac9c940b, 0xb3d53891, 0x19906f9a, 0x6408f173, 0x662b327b, + 0x4fda62b3, 0xe9600181, 0x518a6df6, 0x85c58453, 0xbb5192ac, 0xe63856eb, 0xa6ed1cdc, 0x20602989, 0x393a61af, + 0xf5579ef4, 0xe20bc1c9, 0x5ad4e14c, 0x198b990c, 0x9c52011d, 0x16e5fbfc, 0xfea51813, 0xc3f90250, 0x571a693c, + 0xbcfed06c, 0xb2f26451, 0x4d8b2cd0, 0x00dbbdc6, 0x85202d13, 0xb810d5ab, 0xb5ba9640, 0x9fa07308, 0x4ac0af6b, + 0xff4c2c24, 0xd09daa0d, 0x9044ab06, 0x964d4175, 0x88f556c7, 0x656e31f2, 0xe0087fe8, 0xc432b408, 0x2ede3bd6, + 0x61c48166, 0x528a872d, 0x8e899bd2, 0xd00d72c5, 0xbf3115d5, 0x67f99831, 0x8cc78a29, 0xecf09b29, 0x217e765b, + 0x270c9319, 0x11837a57, 0x1fc7632f, 0xfe2e7a9e, 0x86cfdffe, 0x70c92ffc, 0x6b441d92, 0x0544e9b8, 0x66a6c138, + 0xac2657c6, 0x3b3cfa95, 0x1b643440, 0x2ac617b8, 0x1bd24ba1, 0xcd53149c, 0x6bedfd32, 0xcaea4f5f, 0xe0f2d53a, + 0x32222cce, 0x62f04f78, 0x281c4aea, 0x92f1d746, 0xddd30925, 0xbce5006b, 0x1964137d, 0x2f339eff, 0x073b06b9, + 0x3806fabd, 0x7cfdd1de, 0x8ea92392, 0xca2bf0c7, 0x6f19258a, 0xf3dfff39, 0x838e7d04, 0x21ee01b5, 0x4f79ad31, + 0xc81dec10, 0x8a021570, 0x032740a9, 0x671404de, 0x64b4f318, 0xe425749a, 0xb9f196ad, 0x752ca164, 0x55918347, + 0xfb3cbd07, 0x4a250a48, 0xf90af985, 0xdf827279, 0x1ff54a6d, 0x73a2e24d, 0x9d8a17a6, 0x22953d50, 0x9ec66708, + 0x21716936, 0x9ff27cd4, 0x66cabc9a, 0x7b15b7f9, 0xafa68161, 0x63ea3760, 0xef7e1f6d, 0x733d72dc, 0xebc902dc, + 0xaa8ecd95, 0xc633714b, 0x77cc13b6, 0x997bfd96, 0x289ab7ca, 0xeba7a264, 0xfd5c5651, 0xc3411a5b, 0x5d834ba4, + 0xd8bf1606, 0xdb24fb68, 0x1b3b9b6b, 0x80bb8791, 0x3f087e8e, 0x41c60f54, 0xe00c8f0a, 0x325554ec, 0xd1a0e434, + 0x4544b041, 0x9c42a29e, 0xb11832d1, 0x5af8ea30, 0xf9a79ab1, 0xb003d5a3, 0x942ca953, 0x582c8920, 0x2db624e1, + 0xe1424060, 0x412a9157, 0xc18d9a94, 0x68a427e4, 0x21cad876, 0xba1be04a, 0xd1ef84a9, 0x08988413, 0xe359ea1f, + 0x4cfe8dbe, 0x59863e1e, 0xf8327125, 0xd9f1753d, 0x77b4a25a, 0xf8b114c3, 0xf4259e25, 0x3d952dfe, 0xa0191376, + 0xe09dcb7f, 0xb761cbca, 0xfede9076, 0xb1404d99, 0xe1fc4db2, 0x00f50f6f, 0x7ae04d6c, 0xb339f845, 0x8ed71398, + 0x3a737281, 0xd04cef9f, 0x57a1615c, 0xef045732, 0x04503c6b, 0xddac7645, 0xa8f9f113, 0x61ef0675, 0xd21eb19a, + 0x0c4d93f9, 0xa485da9c, 0xf2ce65dd, 0xf2245f2d, 0x92090dc0, 0x72d599bb, 0x286d1e79, 0xad640608, 0xc7acf68d, + 0xeda7eb5d, 0x950e6744, 0x3922089f, 0x7b3037f8, 0x9e11b096, 0x7a46bb38, 0x1a15acac, 0x35902c06, 0xcc114eb1, + 0x81e319c8, 0x84c439d1, 0xafc550bf, 0xdc85cf14, 0x696e8ab8, 0x0a2ca729, 0x47c2502e, 0x8cf7732d, 0xb7589765, + 0x076ee187, 0xc4e26443, 0xe1c28f20, 0x8e01fc17, 0x97d32480, 0xcabb61d7, 0x82130285, 0x05aa1ce2, 0x6fd4ffdb, + 0x679b3fe6, 0x3454908f, 0x471e3edc, 0x36336495, 0x0a4739a7, 0x67cbf051, 0x6af0d047, 0x7da98fbb, 0x66174df0, + 0x8f75cbfa, 0xb42d0bca, 0xadceb870, 0x049a5a91, 0xa70439f1, 0xbe5b57ac, 0x856f0055, 0x07805fcc, 0xff4a7940, + 0xba3dd26e, 0xcbe3efbb, 0x90fd3ca6, 0xef180cad, 0xd49a2fe1, 0xeac70e33, 0x47640130, 0xc80fbcfd, 0x60d37b9a, + 0x66157a7f, 0x33b6be90, 0x9b7f1b83, 0x896fbe7d, 0x638886f4, 0x39b0322c, 0x37dcee0c, 0x54771a0c, 0xba7dd17e, + 0x19846706, 0xc08e1d00, 0xe17af913, 0x3221206b, 0x4eab89c7, 0xe589fd1f, 0x42b34450, 0x7fe711da, 0x7d235a38, + 0xbd725ee7, 0x8abcfd6f, 0xff5eb551, 0xdefdf921, 0x11c61d72, 0xc184d800, 0xe0f21ede, 0xbca2053c, 0xd7cce490, + 0x477fd3a2, 0xfef06802, 0xe205b0a1, 0x6796703a, 0x55a826c0, 0x91f7cd58, 0x28fe3da1, 0x68d27f1e, 0xa154309a, + 0xbd85d001, 0x4676e242, 0x2a4df060, 0x48767dfa, 0x7ba2eebf, 0xc3477ae5, 0xaf147174, 0x91fba18a, 0x2784b532, + 0x753a8929, 0xef7923b6, 0x840468d0, 0xee3c5ecc, 0xb98a6df0, 0x6b1977af, 0x59d7d858, 0x044e36dd, 0xc6441e11, + 0x5ab4eb9a, 0xd6954d71, 0xdbeb3110, 0x2ee22ed4, 0x3b09d65e, 0x226ceb8b, 0xf27a3424, 0x09bf27c5, 0xb1c9aac3, + 0x2db6a327, 0x3e15b3f9, 0xaab2e756, 0xd553ed67, 0xb694dba3, 0xee34f592, 0x23381868, 0xbb0d2b4f, 0x20a3cbf8, + 0x31daf122, 0xaf83621e, 0x3f6e3ade, 0x4475370b, 0xd12ddb85, 0x7bb94e5a, 0x970544bf, 0x471571f7, 0x8eecabd5, + 0x448e570b, 0x7e811c48, 0x76705125, 0xf4d7ef8e, 0xdbfa0a3c, 0x9871cfe6, 0xb9f13da2, 0xd06ce447, 0x9bc03f0d, + 0x34a34a38, 0x4b125fda, 0xbcc405cf, 0x3086bfd3, 0xf402de74, 0x693de838, 0x390fb739, 0x0304de02, 0xee05c928, + 0xb9b2b7c5, 0xe8692942, 0xfcff3148, 0xe8b6a95a, 0xba8439a4, 0x94e0ab9d, 0x2b67abe7, 0xf6b887ac, 0xd51d90fc, + 0x0cfe4129, 0x08bedd8f, 0x20aca1e2, 0x2d97f7dc, 0x768baf2c, 0xe070c4cf, 0x887b630a, 0x39226ce3, 0x223d3135, + 0x67087ecc, 0xde71591e, 0x9f449967, 0xe29397da, 0x4c86b95b, 0x9d0e9d46, 0xfd45a499, 0x8dff712c, 0x4b9efb11, + 0x8a7666bd, 0xb34bbc1a, 0xb8edc228, 0xd40a8ef0, 0x1c258871, 0x694cc695, 0x7f4ae6c1, 0x05798857, 0x0b2b387d, + 0xa3eb06f6, 0x26938660, 0xe6be3e7a, 0x9f04da64, 0x280c94cc, 0x88ba3c14, 0xf1eb649e, 0x1fb22abc, 0x3068af2e, + 0xd508d5f7, 0x456a7c1e, 0x755ccda5, 0xab47dfee, 0x37baae20, 0x522d9457, 0xd3bf8559, 0x557a5787, 0x54f484d2, + 0x834f0bf6, 0x90f10bec, 0xc89437f7, 0x40f24d50, 0x7da6c287, 0x85d4673e, 0xf5ef574a, 0x603ad149, 0x776d52f6, + 0xd5ff1c6f, 0x0b6ae110, 0x7f8e75bd, 0x29f34d63, 0x1a591451, 0xb158e06a, 0xb3cbde06, 0x5efa86f8, 0xb750b02e, + 0xa1d7d275, 0x928f8907, 0x7c1a228e, 0x59337335, 0xf7b7d508, 0x0ccea95f, 0xa3425d64, 0xdca257c0, 0xc43ca2f4, + 0xc65aaf40, 0xfee70d4f, 0x2e4112db, 0xbb52a3fd, 0x617d350f, 0x0235fb8d, 0x2738b3a4, 0x94e0034f, 0x57b28e1d, + 0x1eb54cc6, 0xec150a15, 0x4129a4ba, 0xa4e0a2df, 0x9c47a5ed, 0x8d963a28, 0x9b51b089, 0xcdd65aae, 0xc4bc26f6, + 0xeab4f15f, 0xc03f5105, 0xbbf8d7a1, 0xbbedb86b, 0x4ff3abf6, 0x4cf91f47, 0x81e3468b, 0x0203924a, 0x1280b5c1, + 0xfbeafea1, 0xa515e378, 0xa0af03eb, 0xc8ef5d11, 0x0bb01526, 0xae116bd4, 0xfec987bf, 0x455b2152, 0xa573f4cf, + 0xf7080fa4, 0x5186a1df, 0xb680ffe9, 0x18dac264, 0x3fc55505, 0xadc52c04, 0xab52b9a3, 0xb43d0280, 0xbbce7dc7, + 0x85a91ee6, 0x71ef84de, 0x4c0fd9fd, 0x3096c86f, 0x4804c9b7, 0x8c3e5aad, 0xdf5ba9cc, 0x6a8d1d59, 0x17525e19, + 0x85a919f9, 0xe8d2ae05, 0x4fd7bc70, 0x25fb552a, 0x17ed91e4, 0xb1fcf491, 0xd207fadf, 0x987b012a, 0x7570c3e8, + 0x4ab8eee5, 0x120b730d, 0x6ed38b5d, 0xb957464f, 0xd5d803dd, 0xf6b76176, 0x9d5f8513, 0x9a7ebda1, 0x5f4c70cf, + 0x25c56da4, 0x6dc8a442, 0x5eff37d7, 0x509f5861, 0x786958c1, 0x0dd17bda, 0x927069bb, 0xec2889c8, 0xb747b354, + 0x3504c4f1, 0x94258395, 0x05836f5e, 0x12068054, 0x42751853, 0x05859782, 0x784882ad, 0xc3988e94, 0x20c7eb21, + 0x6f5d9be5, 0x23840867, 0xfc160e47, 0xbb3bfe14, 0x2497e7ee, 0x42e5f8c2, 0xbdb0d262, 0x97d52dd1, 0x512c6081, + 0xf2beb1b9, 0xdab5a157, 0x9a86a417, 0x1f9a1932, 0xcf9da6e5, 0xf82d53a0, 0x2b0baa7e, 0x2327b4a2, 0xd71a161a, + 0xdf403475, 0x948bfb49, 0x24fc9862, 0x225123cf, 0xced76b57, 0x755bc1ec, 0xd0a2dc53, 0x64bfa749, 0xeca16661, + 0x61183c53, 0xcbbf1397, 0x49c5459a, 0x18e394b2, 0x1be4f48c, 0xf7d8ec91, 0xd81fc5c6, 0xcdb1c20b, 0xfe3c90b0, + 0x4b836637, 0x556781e5, 0x5af18ba0, 0xf0e454e4, 0x79278ba0, 0xe0c76baf, 0xb36c577e, 0xa23b9489, 0x11305ed4, + 0x1b2cf419, 0x250a4de5, 0xe5cf8de5, 0xc5aba253, 0xaba81623, 0xbf255563, 0x5956abd8, 0x54354af8, 0xae4ae23e, + 0x138d859c, 0xb6ab68ea, 0x28c55e2c, 0x5dc5e110, 0xb467d47c, 0xc3cc8685, 0xe1566c24, 0x322c8890, 0x677857fe, + 0xfe8eb38f, 0x0b61ea66, 0xddd1b4ca, 0x6f1cbf51, 0x44f08357, 0xcbe21396, 0x744fe8b9, 0x143b958b, 0xab05e6fe, + 0x3c54dcd1, 0xa5b694a5, 0x0030a4b7, 0x254a05bb, 0x4214883d, 0xd53902f1, 0xcc0e599a, 0x22298028, 0xa55470d9, + 0xbee9ff6c, 0xaf1e2a5e, 0x0f69d102, 0xfc02aa22, 0x19f1d3c7, 0xb6aa4ebe, 0xf1751cec, 0x8a0ae852, 0xd180a904, + 0xad8605a1, 0xb5f57878, 0x6b6db0ed, 0xaaf42553, 0x64f45bb7, 0x9ff787a7, 0x84e527c0, 0xb2839040, 0x4f044fec, + 0x14cbd950, 0x522ae19f, 0x0030916b, 0x517635ca, 0xc3a74420, 0xf13d6a0e, 0xeadd4b6e, 0x8e20585b, 0x0b36ab20, + 0x5f6b6be3, 0x6126831b, 0xdf84a59f, 0x4dd6380d, 0xb77899f2, 0xbb5e5703, 0xf2086ddc, 0x6532cc3a, 0xdb8aa73e, + 0x6570ee92, 0xf32f68c8, 0x019ddfdf, 0xa57896e4, 0xc10e0c77, 0xe3f15ffe, 0x900e26cc, 0x3cd78e47, 0x14354762, + 0x9d6a699a, 0x3ab5c295, 0x15bd0b3f, 0x751f7fab, 0x134faaa0, 0x70e112a9, 0xad293978, 0xdf35c6f2, 0x4ba653e2, + 0xc4fefeb4, 0x5b4e5baf, 0xefb1d2dd, 0xf79e0d2b, 0xbc488b42, 0xe7f21b7d, 0x5aa9157d, 0x6b86dec9, 0x835312f6, + 0x6adf72e9, 0xf613d479, 0xa2379126, 0xefe91cb2, 0x124d80d8, 0xf810e5b7, 0xa9780fd0, 0x15f06bb7, 0x50145248, + 0x502c59c2, 0xc8271ed4, 0x718152d3, 0xb138b95b, 0xfb031cf7, 0x5c4d4895, 0x7aa222ac, 0x566cacfc, 0x3283df05, + 0xe3b5f754, 0x91288231, 0xeb9b4a58, 0x3ab36dfe, 0xae69ec8f, 0xf9e33e4e, 0xbe85bb36, 0x870dca46, 0x7154ead6, + 0x6c3d6885, 0xde765276, 0x09309ecf, 0x5d1c9e35, 0x7cd844a9, 0xa1252152, 0x9967ff0d, 0xa792dde0, 0x2b5e20c1, + 0xebccd1cb, 0x3ceb2b15, 0x49538aae, 0xc1ae7073, 0x10ea8682, 0x6afbba45, 0xe0973996, 0xda059f47, 0xc5fdac19, + 0x7f0f74b3, 0x424d8f46, 0xfd844473, 0x2a8aebd0, 0x69dc3074, 0x86fe309d, 0x55c9310e, 0x0d7f978c, 0xc6dbee41, + 0x19c6edb1, 0x95c916c1, 0x77110905, 0x17deb9f5, 0x8bd33b28, 0xb483f91c, 0x1121b3cc, 0xf6233cb6, 0xef243748, + 0x9271a226, 0x01d89f4a, 0x2338f83f, 0x215fdd9c, 0xc62470c2, 0x6159032f, 0x7c523bea, 0x1d80e70b, 0x49d67bf1, + 0xbf6fd8c2, 0x6555f052, 0x224ac6ca, 0x1095a7fa, 0xf4161b64, 0xd3023679, 0x97f93cf6, 0xe8d0a971, 0x7355a50a, + 0xed4a763f, 0x977bffbc, 0xde073c28, 0x52826765, 0x97e44e42, 0xaed68ae8, 0x8ace251f, 0x71edc9de, 0x16cab2c1, + 0x96eddbcc, 0xfb734d47, 0x71480c74, 0x84b94b94, 0x6c236c04, 0x4d0c3de6, 0xb562e004, 0x3a986190, 0xadc294cd, + 0x3b006f5a, 0x2146b5c3, 0x196571c0, 0xdc6552e2, 0xfa52b97f, 0x11f974b4, 0x7b966641, 0x23f081fa, 0xae22a48c, + 0x056ebc03, 0x5dbb6742, 0x273b0378, 0x19f09b75, 0x35fc426a, 0x16c0e434, 0x97eb86cb, 0x323f6f61, 0x077820d4, + 0x2ae697d9, 0x2dca47ac, 0xe4b2af3d, 0xb53f500f, 0x7f8e17d1, 0xdcda13a7, 0xc531b97e, 0xdca522c0, 0x226ed058, + 0x90551792, 0x175e9a12, 0x53d3838c, 0x12f4451f, 0x738d2aea, 0xeb18a832, 0x5646355b, 0x8695d90d, 0x2a87de20, + 0x237b5c4d, 0x7d56d740, 0x8696dd8f, 0x0eee469e, 0x0477d2be, 0x76420bfe, 0xbfc3c534, 0x2d734253, 0x14749579, + 0x33a47713, 0xf58375b0, 0x9db44d59, 0x5dd5a550, 0x9594103c, 0x672172b6, 0x9721a601, 0xf22bce5d, 0xc6078ab6, + 0xc214a017, 0x7d2bcd16, 0x4461cdaa, 0xe9fcccc3, 0x9dd03af7, 0x00d0ab31, 0x4044ba0f, 0x079023d6, 0x3356d18f, + 0x07f4cc75, 0x8a15eaca, 0xd7e93425, 0x8f749cb9, 0x7f0da3b7, 0x927a943d, 0x23258aa0, 0xe65189c4, 0x1a97f8e7, + 0xbc772ba8, 0xec579f52, 0x31bca957, 0x0ff87e8a, 0xdba76ad6, 0x98d22cb6, 0xc20f56e0, 0xa647618b, 0xfcafe613, + 0x0b792c28, 0xd0d3d611, 0xb0206927, 0x91bee8e4, 0xe275c131, 0x5eb76a17, 0xb3aa5551, 0xd2709740, 0xbd98bfa9, + 0x82d101bb, 0x17ec637e, 0xa1f440a2, 0x4e8ba3f9, 0x22e2e36d, 0xca6a319d, 0xfbb6696c, 0x14137e4b, 0xfd07b93a, + 0x88187f43, 0xe25ec3c6, 0xeed94802, 0xd3cc9ee2, 0xbf24a2cb, 0x6a135c35, 0x0e03b434, 0x4ec89ccd, 0x6ea06429, + 0xd48a5822, 0x10189fcd, 0x4d8f8ce1, 0x1fb21f86, 0xdd542d32, 0x944bd3ec, 0x6df5785b, 0x588b4182, 0xf9fd1d64, + 0x94ff2b13, 0xd01c64b0, 0x02e8d32f, 0xfb51a649, 0x675b91f2, 0xe468ebcd, 0x0b78ef1b, 0x32bd69e0, 0x977084b2, + 0xedee1dc9, 0x54a06b39, 0xb4c0719d, 0x8b8f4989, 0x608d4eaa, 0x034e4683, 0xb2558cd0, 0x4feb8c0d, 0xc6a764c6, + 0x97c6225f, 0xb90e31e6, 0xcb6f3bcb, 0x29c445da, 0xf445a686, 0x83fdbecc, 0xd968f247, 0x868d2474, 0x9bd3cb08, + 0xa0f84f35, 0x91e211ad, 0x93a8c50a, 0x44a68fa8, 0x05aa1550, 0x1fe3a0b7, 0xe31f0d49, 0x6b7586d5, 0xb259cc82, + 0xf4c1cb1f, 0x942452d9, 0x4ea1beab, 0xa47b1a74, 0x7d1f64d5, 0x4afff063, 0x8533476d, 0x57313806, 0xf63d7c84, + 0xe3b34678, 0x8d5f885a, 0x4b28b571, 0xf975ed59, 0x895c16da, 0x30c3bc0c, 0x8ebbba49, 0x212ec712, 0x189c94ef, + 0xe2de388d, 0x12b13ee8, 0xed353d9e, 0xb62fedf6, 0x1c0c0536, 0x77d7ab11, 0x25b7c9ae, 0x69b40dc5, 0x5bf65ca2, + 0x8e4af743, 0xdee6c528, 0xd9c226e8, 0xddeb659c, 0xfbd87368, 0x0a0c0944, 0x2e1dcc24, 0xd1d71331, 0x6ca6d66d, + 0x9aa7ed35, 0x89f4b92e, 0xebe97071, 0x14f55b49, 0x4bad0750, 0xe692d6b0, 0xe51f95c9, 0xbd618500, 0x0230a9eb, + 0x3b6ee594, 0xba3212db, 0x96e1dc9e, 0xb6a8ed36, 0x0e939743, 0x52fad7e9, 0x3ce8c1b0, 0x31d9ba70, 0x6f0cde45, + 0x162f7ba0, 0x694fcbd7, 0x06d9a23b, 0xecffd9c6, 0xa0ac4b0a, 0x6004d03f, 0x8a6d36d8, 0xa616d57d, 0x9ea25802, + 0x65fe2b0e, 0x0f2c1340, 0xba689a69, 0x03c0caba, 0xc2c2867c, 0x74508495, 0x5d7e5ff7, 0x5f44a6ee, 0xe05a8d92, + 0x20641689, 0x7cefbb52, 0xb3abf4b1, 0x68258b5d, 0xfcab5325, 0x9d01fb49, 0x883ff097, 0xda553543, 0x3a09bd66, + 0x9ec26962, 0x12316d11, 0x9bafc881, 0x453c698c, 0x5b1d47c8, 0x707bf851, 0x7bd92353, 0x8179137d, 0xd6d03391, + 0xd490037d, 0x9265db64, 0x28e997af, 0xa742c9ab, 0xfbc8f9ee, 0x1976804e, 0xd7532d61, 0x0f81c023, 0x53457024, + 0x95ebafb7, 0xa5e16160, 0x7cfb5806, 0x73eaff15, 0x934d782b, 0x0ea9c60e, 0xa1e6b17c, 0x3231b481, 0xdb2f5923, + 0x23207cae, 0x8d5f5867, 0xa2165d07, 0xb312e6ca, 0xfa28b7d8, 0x0bdb5355, 0x73c38cf3, 0x95ed4789, 0x26e8d8af, + 0x38e0e6c3, 0xb7e8cb7e, 0x0cfeeefd, 0xbc8ea901, 0x0030d958, 0xd0d597d2, 0xfcad5b25, 0x5d950693, 0x131f4e81, + 0x421fb3dd, 0x723a94b2, 0x13d1549d, 0x5eff5c43, 0xc7199ac4, 0x06be9094, 0x1345abea, 0x6cecd91d, 0xfc78a14c, + 0x39b505d3, 0x55f77bfc, 0x2f4c8894, 0x00d9ca3b, 0x588a852b, 0x54232571, 0xfa1d3614, 0xce893159, 0xa7eb369c, + 0x1720d0b3, 0xc7493369, 0xe6d03427, 0x7ac9cd9d, 0x225b4f73, 0x4e5c46e3, 0x0326de68, 0x398bd1f6, 0xfd8ae901, + 0xcc027be3, 0xdbd37a6f, 0x1187778e, 0xb80e1e44, 0x3bac8341, 0x4045becd, 0x83678105, 0x361d5b98, 0xc041b4ab, + 0x0ff20c75, 0x6d85769e, 0xcfdf8eba, 0x66ede2b8, 0x7546fabc, 0x31a585d8, 0xd95d8b6c, 0xcd820ba4, 0x17e5f470, + 0x74ebec06, 0x24c2c8ac, 0x58a8324d, 0x88d28336, 0x1d2cb81e, 0xa3737889, 0x83cb6246, 0xb4870a7b, 0x40e7ce15, + 0xe6c2d647, 0x7ce1cda2, 0xf519577e, 0xeb98139a, 0xb188dbcf, 0x410a8fef, 0xb32c0ac0, 0x26934fb0, 0xfe6bb85b, + 0xe6e7e321, 0xfe3815cb, 0x39891e92, 0x9ea928a0, 0x808848c2, 0xaef16ded, 0xf3f5d35d, 0x3f4d699e, 0x61750dc2, + 0xfc61f29b, 0x16949d63, 0xad27b6ae, 0xe7f80937, 0x8d2ccdd7, 0xf0c5575e, 0x27ec8ca0, 0x76f87a58, 0xb4acd187, + 0xbc6eca0c, 0xcdd03f43, 0x1636010f, 0x7c569d41, 0xcf6720a5, 0x5a1e05d3, 0xc88dbbac, 0x537ceaf9, 0xd2d1567c, + 0x471cf798, 0xfc4ea62a, 0x40085c14, 0x8a2f153b, 0xd340d9a4, 0x5e62d588, 0x0b4cbbc4, 0x2af9446b, 0x74a4ec51, + 0x0b60cb45, 0x2880985a, 0x98b7ca90, 0x84884828, 0xd8b729c2, 0x160cf0e2, 0x8b9e0a33, 0xd528ff1c, 0xf3713f27, + 0x53789656, 0xfd8d1603, 0xf199d50d, 0xd76ef7f1, 0x1cd59be4, 0xc1f5f721, 0xc299c87e, 0x9f0378aa, 0x112cfe71, + 0xb0bdbdf6, 0x20e7ea47, 0x0a04f32a, 0xe613f10c, 0x277b4935, 0xb8752a42, 0x456313a4, 0xd7091a19, 0x15c24e40, + 0xb2218afa, 0x1c6fa453, 0x4333f97b, 0x8143703d, 0x4205ffdb, 0xf53435cb, 0x90f06e14, 0x125e7710, 0x3e8b817b, + 0x4efc46c7, 0x220aca2c, 0x29ad3364, 0x209d4a4a, 0xe5fb6179, 0xa2cff83c, 0xdf718e93, 0x8c81498d, 0xaa8486b3, + 0x308de16e, 0x844c793a, 0x7e1e2d40, 0xee069493, 0xa1cc8fcb, 0x21612b7b, 0x9294c821, 0xc640f204, 0x3531fdf6, + 0x2787b76d, 0x98432667, 0x27de809e, 0x71e85079, 0xa68d1b3f, 0xcd155b42, 0xfd2ce635, 0xf85224f4, 0xb3cee050, + 0x45447425, 0xa3bcc3f6, 0x7b391115, 0x6c83c7ef, 0xb372e7b8, 0x6b624482, 0xc9a8beec, 0xcd430082, 0xf1eb550d, + 0xee59781d, 0xd0588afd, 0xf799e61e, 0x54b9434e, 0xdc85c5a8, 0x18dfdd47, 0x128a80f3, 0xdccf26be, 0xeb845176, + 0x93b7d3b8, 0xc4ab1f61, 0x9aa83897, 0x581681f5, 0xf71d557c, 0xcbf9bb05, 0xa1d5817f, 0x1a32e7f3, 0x6af2c6e2, + 0xe69f42d7, 0x2bdef124, 0x17477b10, 0x8daf1655, 0xb66c34c9, 0xd7581a72, 0x136ce945, 0x20d22044, 0xf7b3ce34, + 0xd09db28c, 0xabf654e2, 0xc7bcb6bd, 0x3d3d6f97, 0x42200aaa, 0x6d1f91e3, 0xf184c3d4, 0x89833d4b, 0x28e6804d, + 0x1621d342, 0x2a4bad38, 0x11f41b4b, 0x8fe52cd3, 0x4fa4225b, 0x4ccea7e4, 0x3dd43888, 0x56f9f22e, 0xf3bf36ea, + 0x7838d875, 0xc2ab6978, 0x62b79fa5, 0x04409b8e, 0x8c416081, 0x07aeaecc, 0x2f239e11, 0x84545410, 0x5211d675, + 0x364eb6bc, 0xb789ea7c, 0x9fe64366, 0xf90b449e, 0x062481dc, 0xdf347d37, 0x7dd71cb3, 0xc451d00a, 0xc04dbadf, + 0x18c3df35, 0xdf32c4e8, 0x570372ee, 0xeb5bb1df, 0xbbae95e5, 0x77e7e52b, 0x059718fc, 0x71c41a94, 0x3fcd86e2, + 0x3972c4b6, 0x6de00867, 0xecd860d6, 0x5b4fa575, 0x64fe7e9b, 0xbc2421ee, 0x1b272e20, 0x81f55f73, 0xa4ec1311, + 0xc0c1ca2d, 0x9c11979a, 0x2dc5ab1a, 0x79905742, 0x13b3c373, 0xe4f47f7a, 0x594faf39, 0xa7d76a91, 0xc9c8091d, + 0xf2e79d66, 0xe0909c89, 0x8a05d398, 0x4a52b86f, 0x35fc9e62, 0xca009dfd, 0x2a5f31c0, 0xaa19da7c, 0x9da05481, + 0xf6a03189, 0x12f8c923, 0x36527327, 0x181d6027, 0x775fe5e4, 0x4bf77ef2, 0x2500da96, 0x6be8464f, 0xdac0173a, + 0xf771709c, 0x6e73f62b, 0x25583611, 0x5416bb9b, 0xb8092dfd, 0x72d102a2, 0x8bc34b1b, 0x51c8ca6f, 0x3078be98, + 0x85efe4bb, 0x4d023799, 0x696001e1, 0x45925265, 0xdf08155e, 0xd72f8eea, 0xb9d47b44, 0xcd095557, 0xb762d1d6, + 0x9c514142, 0xcad5396d, 0x744f3676, 0xe7dc649a, 0x6c43812a, 0x801df11e, 0x21421cfd, 0x464353ec, 0xf12a5ced, + 0x0e66b69a, 0x5b1e2274, 0xc52a3263, 0xc1b5f6e9, 0x449fb2b4, 0x832ba657, 0x6462b723, 0xf203e9b0, 0xfcf70f45, + 0x08ba5c5d, 0xcb96b4a0, 0x5985a570, 0x3744a5d8, 0x8f3e40dc, 0x8aee405d, 0xefab98e8, 0xaad27da9, 0xbb608302, + 0x770bdaf0, 0xe5a4c61d, 0x29e211bc, 0xf276b5b9, 0x0570c799, 0x321e508e, 0xdd1abc1a, 0xc8346064, 0x1b803a8c, + 0x9f44ab31, 0x58c83412, 0xcd859c18, 0xb82f1a9a, 0xb2e21376, 0x46a001ec, 0xccc78404, 0x75306cc2, 0x19abe50d, + 0xabcdd001, 0x933ae5ee, 0x29173e05, 0x7f27199a, 0x8b1456ac, 0xcf4fd945, 0xc769ab6f, 0x4125d2e1, 0x8ce679f3, + 0x24440b14, 0xeaa8742d, 0x743fb658, 0x095ac15b, 0x581d1bea, 0x92bd1033, 0x79a1da49, 0x424646c0, 0xe0347bc9, + 0x7dcf0021, 0xb421b43a, 0xc8be6615, 0x652f8cd9, 0x46cb3782, 0xf3bab7a4, 0xa2839090, 0x34c2785b, 0x705fa7a4, + 0xaa1d7083, 0xc732c292, 0x1fef7f0d, 0x474c09aa, 0x4a0355d2, 0xca029351, 0xceca09e4, 0xd8e3ab36, 0xe71efe2d, + 0x37666710, 0x4f32e5be, 0x65345af7, 0x47352116, 0x23535b8c, 0x57927b0b, 0x3e1a39b7, 0xbbcae9b6, 0x45b7e2b1, + 0xc8e2ee92, 0xb937c795, 0x83a0da63, 0x5f560ba0, 0x695dd28a, 0xcb6adf60, 0xfd5036ba, 0x154daa33, 0x15c39118, + 0xa77278bb, 0xe538e188, 0xe6b717b9, 0x11c3b802, 0xfa91bc78, 0x3bd5c85e, 0x089bef8a, 0x2263562a, 0xda4e7b59, + 0xe1698e2a, 0xed472ee2, 0x85268f92, 0x36ae9c0c, 0x2e31b796, 0x47d96081, 0x162c6c0d, 0xf9fe6fc6, 0xb2f21cba, + 0x083b64ac, 0x26991fae, 0x021480da, 0x0a9be338, 0x0cb597d1, 0xf82bdb93, 0x99674c09, 0xc2ef2ee3, 0xea6b9298, + 0x287626c3, 0xceaf5b22, 0xf33625a1, 0xb60b2bfb, 0xd85c6ca5, 0x6a19e7a7, 0x82a3f0ee, 0x089f85b9, 0x97df6de9, + 0x44bdbf1a, 0xa2a96965, 0x7078e4cf, 0x1b2ad738, 0xb4fff8d0, 0xbdff601d, 0x0dac0408, 0x9f9d3f76, 0x9f14276d, + 0x17cf39fa, 0x29228766, 0x52f50e91, 0x9fa7cb0d, 0xe8ae194b, 0xbbf7c1e8, 0x4f4a30ff, 0x8af60b3e, 0x7cd1292d, + 0x33f0c0ed, 0x5f55860f, 0x66dc282f, 0xe8377ef8, 0x5909fddb, 0xdc216942, 0x293b713f, 0xc7ee7977, 0xcac17ff5, + 0xd161ebf6, 0x287e4467, 0x665c78e6, 0xcf99a6e1, 0xd5cc878c, 0xfe8e30db, 0xfd8c31ac, 0x21e6ba64, 0xe59f64ef, + 0x4967b191, 0xb16b7f1c, 0xfa850359, 0xf8cad6e8, 0xec8d08e6, 0x59c82330, 0x86627afd, 0x28e9daab, 0x67d52436, + 0xe2ac95d8, 0xb9015a43, 0x15e80aa0, 0x29721ef6, 0x9677b030, 0x35940848, 0xd63e8c9d, 0x351a0313, 0x7f8fc681, + 0x34e57823, 0x52515564, 0xd834ebbe, 0x8dfa3ce5, 0x6f572947, 0x2f174c8c, 0xd7e919a5, 0xd0d970c8, 0x4fe42fa9, + 0x3214e3e4, 0xd8936f03, 0xd38db567, 0x7c29cb4f, 0xf6257d39, 0x5c065baf, 0xefe6255e, 0x88da2ce9, 0x2e16ec46, + 0xfcef6a1d, 0xe1b02b8a, 0x971e3d83, 0x340ae725, 0xdcd77616, 0x836a6d55, 0xba478746, 0x2abede00, 0xccb94c2e, + 0xd010d04e, 0x154f28db, 0x5461fba8, 0x09666baa, 0x697fae45, 0x1dcff8e9, 0x46b154a3, 0xc7c91ab9, 0xa467715c, + 0x0aa020a4, 0xd075bd9a, 0x7ad8a641, 0x11a9eaa8, 0x6f298a1c, 0xc7303180, 0x4638c946, 0x2e64814f, 0x07937bef, + 0x9b4324a5, 0x8ea76d5c, 0x686e667e, 0xbd83ce6b, 0x394931f1, 0x447a1bfe, 0xa4cc4f0b, 0x72762bd6, 0x4bc9b299, + 0xc21a7c63, 0x025a37b9, 0x7712637c, 0xae402638, 0xed12169c, 0x515e1324, 0xad388867, 0x13c01940, 0x97fea327, + 0x27a09be5, 0xd1a52c37, 0x656fa21f, 0x4ddd40c6, 0xa7c66fe6, 0x1ab2dfd3, 0xd19cb225, 0x1489b389, 0x8f9ae842, + 0xd3da037f, 0x43dfe8c3, 0x1beff226, 0x73a4b143, 0x724052c3, 0xea9b1b0c, 0x133567f0, 0x6dfc58b4, 0x4f78cdc2, + 0x63b217e6, 0x62e2ac32, 0x433ce2cf, 0xcfa7487f, 0x8facf052, 0x8ce4b2b1, 0x6225f7f7, 0x2ab1dabc, 0x1c80bec1, + 0x06eab75e, 0xa586df6e, 0x5bbca8c6, 0x7e10bf8f, 0xf49d5d5c, 0x7b7aa072, 0x66fd9972, 0x4722d3c9, 0x20628631, + 0x920d6e22, 0x337e7dca, 0xd65f451a, 0x6d6eee04, 0x5ad86d55, 0xbde011ce, 0x237b3f36, 0x1ce3c964, 0xe4332869, + 0x5724a4b7, 0x3705a9d6, 0xe7b47b21, 0x8193189a, 0xe9b47c7c, 0xe53d7a0c, 0x93bf2297, 0xb28934af, 0x0eaaac60, + 0x77dcc6ef, 0x11a20fe5, 0xc5eb96b4, 0x5c74927b, 0xe8f4bf26, 0xbb61eafd, 0xe7b74a40, 0x70e588c0, 0xdd3a5f89, + 0x5e69cc54, 0x0f960107, 0xfab1aef0, 0x3e58b1be, 0x87041330, 0xd9e580ef, 0x6f7b3f5f, 0x8d53c2aa, 0x9bfa66eb, + 0x1013d5df, 0x3c4bf1fc, 0xf9a53973, 0x08f1ce49, 0x7f28caa1, 0x56c89ae9, 0x9ec6fa3c, 0x2b28bfef, 0x0b331f11, + 0xd94e1c15, 0x8fe4fe9c, 0xa4879d84, 0x438d0cfc, 0xb6704b5f, 0xfb11ec4f, 0xbb1fa27d, 0xa12406b7, 0x56298c96, + 0x039b145a, 0x8b487338, 0x463c19db, 0x486fe798, 0xe17047d7, 0xc6cb4de7, 0xc17283a2, 0xe8ec6d09, 0x62b52ebd, + 0xfe922652, 0xed1e72f4, 0x56e9d697, 0x6cb2467a, 0xde8dd18f, 0x8d552a2b, 0x1adbe5f8, 0xf5a4684e, 0xb9b87bcb, + 0xe3b63b5a, 0x7dc9e5b3, 0x18c04264, 0xd05db611, 0xc1123931, 0x554c7bfc, 0xb3354e70, 0x15b2bdc0, 0xc13c90de, + 0xb3f9212c, 0x05065064, 0x6f7e4f6a, 0xb230a8ac, 0xafc06196, 0x626578fc, 0x8eaad2c9, 0x5e6012ab, 0x730bdac3, + 0xd7f3e9aa, 0xe2a846e6, 0x776481ed, 0x735e3ebd, 0x77db7192, 0x1b15cd0e, 0xc933cabf, 0xe1b6c906, 0x548c2da0, + 0x8f9363e9, 0x11e6504f, 0x6ef19803, 0x36d2071c, 0xce0966c3, 0x7e811f35, 0x3f87fb13, 0x97771c4b, 0xfc26f57f, + 0xbd0346f0, 0xe839a13d, 0xb5377036, 0x8e0ddee3, 0xa8b416a2, 0x62318f05, 0x08cae41d, 0xe5f2121f, 0x52939d59, + 0x03b33031, 0x8f8ae94a, 0x0184ff8b, 0xac95d623, 0xa181aeee, 0x1a453685, 0x00f0f333, 0x64c25b6a, 0x99259e86, + 0xf5e9fabc, 0x1b1e70d8, 0xd36ad6d7, 0x2063ff61, 0xb111138e, 0x13dbc2cf, 0xfeeb74ce, 0x33b41811, 0x894f12f3, + 0x7952a307, 0xf1abd6ce, 0x4a039bef, 0x8f4cc102, 0x91f47356, 0x7c753fef, 0x0cbe1c94, 0x00493d48, 0x497235b8, + 0x4d85f089, 0x0032a4be, 0x796b81fa, 0x3f235021, 0xab5b18fe, 0xd3cbe040, 0xf87a0217, 0xd3d3dc53, 0x21f9ddc7, + 0xca7ac635, 0xdbd25553, 0x8c958d7e, 0x15cedd71, 0xa9793024, 0x12509b48, 0x888cb7b2, 0x1cd9acae, 0x274e2982, + 0x333b496c, 0xdd64d085, 0x929fc5c7, 0x8f7ffc45, 0x5afddcda, 0x9ecb7fae, 0x09cbfc8a, 0xb6e32db9, 0xdb622118, + 0x444dd377, 0xb3b6a34b, 0xc8857faa, 0x6ced7f5f, 0xbade9c5b, 0x5ddbab3f, 0xeeb6dd39, 0xdd6629cf, 0xeb726db6, + 0x549a94f1, 0x63d3a647, 0xe61454b1, 0x21bbddb4, 0xde185688, 0xd848c30f, 0x61b2e6d5, 0x8fa92e76, 0x4a12dbc4, + 0x7f3f5c5b, 0xd35a7bb7, 0x80b83b62, 0x487f14df, 0xbd768ef6, 0x251b9eb6, 0x88566ac5, 0x951500b3, 0x4897da96, + 0x809c2d56, 0xc76b88b9, 0xef2d6ccc, 0x0170c749, 0xae9c7dea, 0xd1575d93, 0x02a099c5, 0x58e6b760, 0xd3219757, + 0x9cdb4ee1, 0xf0f0ec22, 0x280ee29d, 0xfcfdcba4, 0x91f237bc, 0x85349612, 0x1fd38aee, 0xe3792055, 0x204bce7e, + 0x2f50b539, 0xa2082d5d, 0x68128731, 0x84e1a93e, 0x78e48d85, 0xf9dd0570, 0x59f0681b, 0xa1284be1, 0x543cb643, + 0xa7462589, 0x19905dc2, 0xe20a0cac, 0xcfb815cd, 0x62010ea7, 0x603a5d9a, 0x4dfc7b67, 0xc6104ff2, 0x628835cf, + 0x1ae664b9, 0xbf2529f4, 0xf7b64a26, 0xfaae18ac, 0x6a07d075, 0xf6396e8e, 0xf3181ce8, 0x1f66f06e, 0xbc3d791e, + 0xe68b4cac, 0x6a328b68, 0xcbebfa49, 0xd7f8cf70, 0x094bca45, 0x346edc19, 0xf291b889, 0x2fbcc4d8, 0x4355da3c, + 0x050b9863, 0x430de159, 0x1783245e, 0xc9fb02d2, 0x37dd8ac3, 0xc9ff15e6, 0x04d8b7e2, 0x9a6e011b, 0xd535cee2, + 0x58b189dd, 0x555b6be9, 0xf4163d2b, 0x7f1fc2f1, 0x2d915c6a, 0x1c454c6d, 0x722f0dd6, 0x5084c3fe, 0x95cfe57a, + 0xf43ccc64, 0x4aea8c07, 0x0efe38ee, 0x395629a0, 0xeb481b9d, 0xcff69b54, 0xf55b121e, 0x842542cc, 0x5d947fcd, + 0x10d8fba1, 0xdfe72d91, 0x4ba9e691, 0x2829eafe, 0xe1c7a58b, 0x91d1c5d8, 0x334c1a76, 0xfd8a76b3, 0x098aaa29, + 0x7208b0a7, 0xd218c592, 0x4391c86d, 0x5492be67, 0xfac44e7b, 0x4a87c6ab, 0x9f57521e, 0x6079edfa, 0xc0eecba8, + 0x8ea4658b, 0x9826afe7, 0x16a739fd, 0x323364f5, 0xdbcf0f8b, 0xbab72a26, 0x72e88b4e, 0xcfcf322d, 0x77b781fa, + 0xf7914ec6, 0x13d21517, 0xa680ed44, 0x36b0f5eb, 0x4c9db0c8, 0xdbcc6d16, 0xf53ddcd1, 0x7208d83a, 0x13f086dd, + 0x2ee7684d, 0x73e98701, 0x8aa905c5, 0x82ea2156, 0xe3081ae4, 0xde619f03, 0xa371e0f5, 0x64bd7d0d, 0x18d5d09b, + 0xbbbc7c03, 0xe6a09c22, 0xf8ca08e6, 0x67c06127, 0x4d8b9f91, 0xa3907d27, 0x85fcde07, 0x7673f42f, 0x9c73bc59, + 0x0bf57423, 0xd36d6041, 0x1ba9a920, 0x5bf62d1f, 0xd1b43b6d, 0xc0f66b26, 0xbf91a7e1, 0x3d8cf29e, 0x662919ab, + 0xba5cfad7, 0x1b36a896, 0xfa65809d, 0x251a3cea, 0x8404698d, 0x0b369623, 0x8e1f646a, 0x724c6598, 0xb3fac1ac, + 0xbcded676, 0x0231d169, 0x6282bd49, 0x4a4d72c0, 0x5b83671b, 0xc0520cfa, 0x97e95cea, 0xd46c9aa1, 0x24f1022c, + 0x3bdd4e67, 0xd992e377, 0x42022263, 0x1745f402, 0x0630362a, 0xcbdbb2fc, 0x241c8bdd, 0x69a394fd, 0xfd00d732, + 0x12b58f8d, 0x15930aab, 0x3f84b134, 0x1bc70718, 0x36a6ee7d, 0x0cab7f94, 0x37a5016a, 0x0f8d4c24, 0x605bbf2b, + 0x07dced77, 0x63df0a1d, 0x5de1ab4c, 0xbde15af7, 0x45740088, 0x6a764623, 0xeb2d907a, 0xdba11b38, 0xcc2c9adc, + 0xac5406e4, 0x98e56b32, 0x6c1ba4c7, 0xd1aa0d23, 0x369f05b2, 0xc0b39e86, 0xe4e57dd7, 0x1d07cba8, 0xa7d2fe35, + 0x3402689f, 0x6e19bafa, 0x95a60808, 0x1d950f67, 0x0566e996, 0x10bff093, 0x79bd02c4, 0x5efdfec0, 0x5f720f43, + 0x32905ff8, 0x46b5e254, 0x331095d5, 0xec2a57b8, 0x8d01738b, 0x76a4456b, 0xfeee7136, 0x47bf7fcb, 0xb8ff6125, + 0x982ce0fb, 0x44bbacf5, 0x455c045c, 0xf3bfee37, 0xe640b4ac, 0x5876a207, 0xb094f750, 0x700280f7, 0xcd4e5aaa, + 0x192d32c1, 0x7b88271e, 0x1809ebaf, 0x6d2d1180, 0x29033f92, 0x94f9d2a2, 0x2c4fc7d7, 0x68a6a4d9, 0x0cbc4252, + 0xb630c039, 0x4792c6ce, 0xaec12f46, 0xe19e655e, 0x50b8f263, 0x12924b43, 0x1b1c3fbc, 0x56fd78d9, 0xce4f9c6f, + 0xc97d3a72, 0x57164293, 0x383349e6, 0x4da649c4, 0xa9b07b93, 0x002f0215, 0x8667924d, 0x9678fe5c, 0x5863f10f, + 0x3dac9893, 0x333f3965, 0x1b97f6d9, 0xfc1bd6e3, 0x2f6d4ed4, 0x5ed2146a, 0xc2869c7b, 0xdc8517ee, 0xd93174dc, + 0x7251189a, 0x61a47cf2, 0x1f13f6bf, 0xd60de9d9, 0x8057d6a8, 0x256ea754, 0x76f4c1f6, 0xc226d0f1, 0x348dcd66, + 0xc2c16483, 0x4bccf223, 0x65932c09, 0xf921c760, 0x9701f9c2, 0x6ed64405, 0xc1be4cd9, 0x0482fcaf, 0x67730fd5, + 0x888e7491, 0xed718690, 0x30910aae, 0x096f2b8d, 0x6bbc1aba, 0x306b570c, 0x571efe8f, 0x093d6c01, 0xaccb915b, + 0x99dc5a09, 0xb52f70b8, 0x7648f1c6, 0x2b04e824, 0x2ca77886, 0xbc686f14, 0x8dd47cf9, 0xc5b455a2, 0x6b54c4ff, + 0x435822b0, 0xb363f3f1, 0xaa7b2fe1, 0x183e0d79, 0xbd217836, 0x860a657a, 0xcfaaba5d, 0x4921caf7, 0xe04077cd, + 0x05e08eb0, 0xa1fcef95, 0x5234139c, 0xf7b84530, 0xbd952da6, 0xff58d551, 0x6206e740, 0x22ab63a9, 0x0779e9c3, + 0xfe004d07, 0xa3d3d042, 0x9b676242, 0xbaa2389e, 0xd970c818, 0x5f83ef64, 0x0de0a7d7, 0x0ef6c037, 0x9d4699ac, + 0x5a767b89, 0xaf183388, 0x57f6c505, 0xdf5a7e40, 0xcf9114be, 0x53865a32, 0x15c54f5c, 0x63e27f0c, 0x3de9d1e7, + 0x93eabb84, 0x5b39b8e7, 0x0dfb7aa9, 0xf9c76d31, 0x2a5cf2ef, 0xbe732937, 0xccc6096e, 0x0638b3e4, 0x8d566db0, + 0xd8e9772d, 0x6c382968, 0x4ecb0f98, 0x06523de9, 0xf5244029, 0xac495b9d, 0xa0f71785, 0xa14bbab2, 0x7c350e40, + 0xd1899b1d, 0x9bf2be21, 0x6bfcf76c, 0xe89ba755, 0x4b539ec2, 0x4782b7f8, 0x35bad3e0, 0x0d2afdde, 0xe6e0e887, + 0xd904a9bd, 0x587b79dd, 0x28068eec, 0xf2636924, 0x16b120e2, 0x7a4f8ed3, 0x98c66e8b, 0x760ce279, 0x9cab4acd, + 0x5c98476b, 0x2e6c8733, 0x77363f05, 0x77b4320b, 0xe709738a, 0x6f8e6555, 0x43977b55, 0x5fd66d5d, 0xbacbbacf, + 0x3a01488b, 0x1f7fa3db, 0x1f5c74c7, 0xa2280cb7, 0x6dc23df1, 0x76188040, 0xb7520e98, 0x27f609b1, 0x8464a1f2, + 0x390f131e, 0x00aba320, 0x6993b755, 0xf835e9f5, 0xafb233f4, 0xcb2df6d2, 0xdff73539, 0x4a043a50, 0xab604522, + 0xbd29217d, 0xaa1fd306, 0x25aa3034, 0x8fbe28f0, 0x7b98ce11, 0x2f24af1a, 0x14684ae4, 0x6b25d5ee, 0x34da8373, + 0xf06d6d3c, 0x777e6d18, 0x6ba5eced, 0xc0a4b5a6, 0x5ab0abcc, 0xaf440cf5, 0x896a2d85, 0xe3b11137, 0x77aabcdf, + 0x7bdbb646, 0xc9b9078a, 0xf31e1cc8, 0xdd7d4665, 0x527ff25c, 0x8793d647, 0xaca83a8d, 0x3685ca40, 0x93f8fc43, + 0x2913341d, 0xc7960568, 0x3233122d, 0x808b98d3, 0xd720b914, 0x69ae737f, 0xf87c6d2e, 0x80a2c7fd, 0x0608f2f0, + 0x3680e884, 0x29f6cd01, 0x56187725, 0x2085187b, 0x8913383e, 0x395c450b, 0xf3fc52a2, 0x2e7f27b8, 0x696c019b, + 0xa364bd1a, 0x10f05fd6, 0x728c9fd8, 0x5f06f31d, 0x5d007555, 0xe73ce03a, 0xc4d2a5ee, 0x34be22c8, 0xfad15aba, + 0x168dbf55, 0xa7955245, 0x06c58db6, 0x54e35ce4, 0x73d18f16, 0x04c1bc42, 0x7dc7dd93, 0xd3b72b0a, 0xe6da13c3, + 0x61d6629c, 0x9df21798, 0x23b22f09, 0xb25cf714, 0xb5a08a85, 0xceedb3d5, 0x90e1fe76, 0x8f3f977b, 0x4f700f1e, + 0x80b65b93, 0x9032a160, 0x706224ed, 0xd638c829, 0x8ab32fe4, 0x9b2780d5, 0xcd623098, 0x9755b4b4, 0x9b89c326, + 0x1c85ceb3, 0x32690907, 0x4e3f4733, 0x6f9b9419, 0x4452df1c, 0xfeb4a8cc, 0x50b3656c, 0x0ace5d73, 0x4dab0009, + 0x256dafc4, 0x11625c41, 0x62240a7c, 0xd43cf11a, 0x235e46e6, 0xcce2f4d6, 0x393b77cf, 0x75352a0a, 0xd1461009, + 0x1aee3a6c, 0x6a83821b, 0x486e05f2, 0xc0077ce1, 0x358b6eb1, 0x1371de27, 0xe9420465, 0x6f347ab4, 0xb689fe0b, + 0x8900ad40, 0xe69baec0, 0xf5fbce45, 0xb0122907, 0x4a82560d, 0x84466f4a, 0x4d54d218, 0x0be145ac, 0x131c6b08, + 0xd7e7dcd4, 0x97ffa9bc, 0x4f047a8c, 0x61c20927, 0xd3cde6c6, 0x2f5a4c16, 0xfd49d8fb, 0x31e6a7f6, 0xc62338a7, + 0x68f1678d, 0x27f0bc46, 0xffff55f7, 0x9f382989, 0xef167545, 0xd06393e6, 0xbc6044f2, 0xf2f0c6ce, 0x0ccdd603, + 0x734ae2ec, 0xc0cb2665, 0x043d24aa, 0x8d111b0d, 0x5b70c59c, 0x244c1bd0, 0x6fb1651b, 0xcf4a6e14, 0xdfe8c3ad, + 0x77d4003b, 0x1b08fe4c, 0xffe8c8d9, 0xe67c2e47, 0x4caaf841, 0xb19d3c19, 0x5079d2e7, 0x8ca67dde, 0xe3e4abc6, + 0x097eb1e8, 0x2d42c7f6, 0x3b880c66, 0xb0b6d2d0, 0xf69c1128, 0x7e6c20d6, 0x9d9ba33f, 0x83215307, 0x0a3128ad, + 0x4b4d3793, 0x3eda96eb, 0x4f7efc95, 0x57a11fee, 0x6995eccc, 0x162176a7, 0xd5a2e081, 0x25f43607, 0x0575208c, + 0x18316235, 0x829129c5, 0x30426a56, 0x54c377e7, 0xf992eca4, 0x9d82b911, 0x54cc5f04, 0xe57f8aa3, 0x15edafb3, + 0xa5f5e6c3, 0xd829b472, 0x9123bb6f, 0xa62401de, 0xb053f3e1, 0xd7939a11, 0x4570e3c8, 0xd391f5e8, 0x981a12c0, + 0xe745a6a4, 0x81a5b292, 0x81bc0fa2, 0xf9352ba7, 0x0e1c814c, 0x6a8feda7, 0x8135d245, 0x3a984091, 0xa0e3b97c, + 0xe8599d14, 0xc17f5d04, 0x2c6b12a4, 0x28f9a8ec, 0x956ace3a, 0x27c6589b, 0xe91ca2ff, 0xcee36546, 0xf15bda0f, + 0x9b049dee, 0xfc7cd73e, 0x3051ea52, 0x611eb7bc, 0xcba646f0, 0x3ee641dd, 0x42e7df65, 0xe67249fd, 0x0b62755d, + 0xec6db8f8, 0xc8ff8e54, 0x51fa22cd, 0xad65640a, 0x4da042c2, 0x27fe1b46, 0xe3b9b3a8, 0x8b6df453, 0xd76421e0, + 0x294c74dc, 0x686d33b2, 0xb886e4fa, 0xbdc7ecf2, 0x83794449, 0xf23df42d, 0x202162d1, 0x0d3b3f9c, 0x0fa19e61, + 0x5c944e6a, 0x26b39ffd, 0xbd40f07c, 0x8336c878, 0xf599c93e, 0x8049a9fc, 0xdb9cf234, 0xe3bceca3, 0xe89c769e, + 0xc05e6cb7, 0x5761469b, 0x0842d337, 0x8e5d9c69, 0x595e54d5, 0x714c2d52, 0xda4de357, 0x19d57c12, 0x22f7c405, + 0x8ff37ef9, 0xe59177bd, 0xf40e536c, 0x23b55ca1, 0x670feea4, 0x3b421cbf, 0x80d739cf, 0x1ee8e70f, 0x2c7f8446, + 0xebb55379, 0x5e23760e, 0x2d16d0f9, 0x910274af, 0x3d2fc1c8, 0xcc966ef0, 0x59a197ed, 0xad1065ba, 0xe990ed8e, + 0x55635305, 0x1391af25, 0x247c9058, 0xa4277895, 0xd09bff24, 0x74d9fd5b, 0xf71968b6, 0xaf7b67b6, 0xd0af1523, + 0x3e1c5fc9, 0x00074d21, 0x1451a29c, 0x8a97badf, 0x1bf52541, 0xfdb6dc9e, 0x663a168b, 0xe330a63c, 0x4729420b, + 0xb48957b7, 0xddf6ecc9, 0x4167cab3, 0x8443341c, 0x86aa4cf5, 0x0bbab5de, 0x3ce045c7, 0x6073da9b, 0xc6b96522, + 0x8857c91e, 0xa292b74a, 0xd83ff830, 0x169065e7, 0x82177a3b, 0x959c44f6, 0x265801e5, 0xa8dbf934, 0xb26ff68f, + 0x434975ad, 0xe304bfc5, 0x9f549db9, 0xd27467e5, 0x63816690, 0xeee0e9df, 0xe3764d51, 0x6844089a, 0x2ba9d850, + 0x90d8241f, 0x09bdb75b, 0xeb81562d, 0xbbd0488c, 0x00909f5e, 0x6520ce8a, 0x6db18f5a, 0x0d557742, 0x0044a56e, + 0xe10a79d6, 0xc69ecf9e, 0x0dcfa2a1, 0x7312db05, 0x9651604e, 0x21853664, 0x071959b3, 0xb8b0cb77, 0x406aa1bf, + 0x82d67db0, 0x9352b085, 0x5f36947f, 0xc5c4e62d, 0x1d92307c, 0x28c48035, 0xc0aebfaf, 0x2542b54d, 0xa79d97d7, + 0x54f13fdd, 0xb77054b4, 0xaa461fca, 0x9cd31ef9, 0x38be28a0, 0xd20dc1c2, 0x97be4d9a, 0xfea59699, 0x0c2c6655, + 0x931e9216, 0xec24eeba, 0x264ef044, 0xfa68f997, 0x917a8cc0, 0x47fe0320, 0x9c27e047, 0xa0e383d4, 0xa7a93e3d, + 0xd4b4d4e6, 0x8c78cb6e, 0xcf1172b2, 0x9e53324d, 0xde3fc35e, 0xbd6168a9, 0xa4ed6dd2, 0x40a005e5, 0xea97a1bb, + 0x5197e999, 0xf971e729, 0x6eb6e6c6, 0xf2186f26, 0x956be1c0, 0x198ae0c9, 0xf8837133, 0xc5345061, 0x71523372, + 0x2c740bb8, 0x6382559a, 0x956212c7, 0x09b22bf4, 0x88915936, 0x9e24e4b5, 0x9966e99e, 0x9b23f80e, 0x07ff318a, + 0xd8ef7cb9, 0x986eedaf, 0x10ef8dd3, 0x0cff9089, 0x1f257edb, 0x2c237e15, 0x6a7995fd, 0xc43d4d42, 0x138ad595, + 0x8ffdcb40, 0x55aa67a8, 0x467f1381, 0xe66e83e1, 0xc145d848, 0x34872eb9, 0x3b90edc5, 0x4fd6fcb3, 0x5d3e5045, + 0xbe079412, 0xc5479a0d, 0x79b05534, 0x747e76d8, 0x31e925df, 0xa87e3525, 0xc4414a25, 0x41ef729d, 0xd230ac7f, + 0xbc9ec796, 0xb4727881, 0xc82bf346, 0x78ed3d54, 0x9e32c423, 0x9e1a8127, 0xb9fc08cb, 0xd1348fae, 0x9989f1f6, + 0x5119fa9b, 0x271e6a6f, 0xb501d9f6, 0xbdae23db, 0x02737f5c, 0xc6972fcb, 0xea2252d4, 0x6f02751c, 0xb4a2e2af, + 0x96ec2c6b, 0x0dcb5ea2, 0x11a521d0, 0xa0bea2b1, 0xaa5fbc07, 0xb2b9a6d7, 0xe74ec9d6, 0x101a5a17, 0x0e00bd11, + 0xe18da710, 0x38e34672, 0x344427bd, 0x09b07dee, 0xd9ee80b3, 0x1710f3f4, 0x137cefac, 0x3caddfd0, 0x12fb7527, + 0x4d1e089b, 0xf257478b, 0x1de88770, 0x17626deb, 0x137dda4f, 0x491be67d, 0xac4018ac, 0x44e904fa, 0x71dd7582, + 0xedee4aae, 0x517c902f, 0x722cad2d, 0xaa77d80d, 0x94f732ac, 0x94a66b9e, 0xa815604f, 0xc1095b01, 0x3ccf402e, + 0x3c4ad225, 0x610c054d, 0x5da0f8f0, 0x718b0069, 0x19697713, 0x310bbf3d, 0x2b026413, 0x87ca982e, 0x3c51d3b3, + 0x1c28462f, 0xd9e076de, 0x0a8de2f8, 0x398b5fb2, 0x5e205feb, 0x7f97dc47, 0xf15aea65, 0xf777f2f2, 0xe1cf4860, + 0x50c4825f, 0x775bc143, 0x591b99d9, 0xfe3b3b04, 0xe2b53ee8, 0x84f9c3d0, 0x67879577, 0xd683455c, 0x6311006e, + 0x35874796, 0x260ea5c7, 0x279ee8de, 0x4c260a82, 0xf93c65b0, 0x00a93a7b, 0x9e39c181, 0x73207992, 0x49f84f5c, + 0x0c427642, 0x4a5e3bfa, 0x665e3fec, 0x4a2116f1, 0xb25f4f47, 0xc7187265, 0xbb9976fd, 0x4b5fc70d, 0xaa1ab35c, + 0xc935f9af, 0xeccd4c01, 0x62ab2f83, 0x5d4ab686, 0x429c5981, 0xdcc8ce86, 0x7da2c94b, 0x0bd1f284, 0xe3bd78e5, + 0x1de8f2b9, 0x2ce64b0f, 0x4940c79c, 0xbbcd761a, 0x282e241c, 0xe4b22c83, 0x60fce126, 0x36d207f9, 0x57f8f5b8, + 0xc908ced2, 0xf13f7684, 0x1c16daa9, 0x7881b0dc, 0xcffb4887, 0xeb23ffee, 0x04741745, 0x1a8b440e, 0x2a279e5f, + 0xe8b87ac2, 0x48514447, 0x1faa4cb6, 0x337e3bea, 0x00a0ca68, 0x84c88fc7, 0x58446190, 0x1e1a3f57, 0xce1bbacc, + 0xfea594f0, 0x947acd59, 0x6bafa9e9, 0x6965a3eb, 0x0fc46b0f, 0xe0a8aacf, 0x226a56e5, 0xb202ee77, 0x4f0caba7, + 0x5e9de277, 0x640f1ecf, 0xd758cc98, 0x0f81e2a7, 0xb38f4ac5, 0xd4bb4163, 0x74ed4c82, 0x129beb1d, 0x161cb722, + 0x8e6dced4, 0x2d8a7243, 0xc8e2801a, 0xce153026, 0x5a1d6568, 0x47e1fea1, 0x3bb72b5d, 0xd7040b68, 0xd17c139d, + 0xc1d56ac6, 0x3363dd8a, 0xdc5710b7, 0x7711511e, 0x9cbfe5cb, 0x1d42a34b, 0xc2fab8e5, 0x7c865f6f, 0x0213204b, + 0xfe308333, 0xfb997712, 0xb579ebcb, 0x49c2f396, 0x1bc98a4b, 0xc94935eb, 0x9b84ef17, 0x868bcf75, 0x24012c26, + 0x668f494c, 0x178b9f6a, 0x6140ace4, 0xcb569d9e, 0x082b6dfa, 0xa6b491db, 0x686060ea, 0xc7a149cd, 0xa1496e1c, + 0x7d0011c2, 0xdf3a1f77, 0x658df68d, 0xfec13283, 0x1cd3a05d, 0x6946f477, 0x0cd81f71, 0xdd3238a8, 0x35468f1b, + 0xd09e5e9a, 0x1cd493cc, 0x43c1573f, 0xe020d0e7, 0x6ea79977, 0x77f41bd3, 0xfc6ab36e, 0x1e5b967a, 0x29002d46, + 0x2997ad7c, 0xa36e36ff, 0x6112f679, 0x77b14bd1, 0x137c351b, 0x50985769, 0xfa014f42, 0x581afa04, 0x85e7efab, + 0xb9dad285, 0x864c3b89, 0x5c94964a, 0x578ad33b, 0xa310f863, 0x2b7634b2, 0x63da4928, 0xf5bc388c, 0xc2575509, + 0x221d2fb3, 0x148a2035, 0x9e4eb9d8, 0xc191f057, 0xb2a3325a, 0xbd3e5a38, 0x2427389a, 0x6fd8159b, 0x83ee446d, + 0xce92ea15, 0x7d73f141, 0x57d842e7, 0x85767cd6, 0x73942fe5, 0x966bb3f6, 0xd6713857, 0xa87d1855, 0xf6f8377c, + 0xb499e6a3, 0x669a2a74, 0xcff0f256, 0xb31987b0, 0x3ecc16b2, 0x9002b65e, 0xa30d7242, 0x7f6d8394, 0xc873be87, + 0x9ecf884d, 0x0f809a60, 0x2b06a94a, 0x581c4628, 0xa37088e2, 0xd64a063e, 0xfa366d59, 0x3dbfb501, 0x81b3934c, + 0xe11b4d16, 0x98981945, 0x851d93ce, 0x4e5f73b0, 0x8713cc4a, 0x990c3e88, 0x3f10dde9, 0x2c741b6e, 0x16ca9e62, + 0x8a9574c9, 0x5fddd704, 0x91e0f946, 0xe145b261, 0xd6c8e914, 0xd46a195e, 0x836f2b84, 0x888488f9, 0xa0171075, + 0x5b68e624, 0x69bf7207, 0x97f89c5f, 0xf68bf78b, 0x0e48fcd1, 0xeb49a381, 0xe04b4e48, 0x6c2b4749, 0xa84a84e1, + 0xe7359ec5, 0x651a830b, 0x9d95b25b, 0x65d139ac, 0xd452f94f, 0x28f3612c, 0x61c87396, 0xe429effe, 0x3ea8483a, + 0xac2bf450, 0x450615bd, 0xeb94bf71, 0xa759a259, 0x418fadc4, 0x59734a93, 0x7a47a6f9, 0xe1652560, 0x5afb7d14, + 0xcca9ac68, 0x3516a22b, 0x28d369f3, 0x5d6ea00c, 0xa7c9c0ad, 0x137b9fb3, 0x2c7137c7, 0x733a939e, 0x29a50a01, + 0x3fa44daa, 0x7160a761, 0xac698f11, 0x1653e030, 0x12d99a27, 0x07a9f12d, 0x45df07e3, 0x010fc0fe, 0xfbc7b3da, + 0x6d1e6dad, 0xf992a21f, 0x52f3d632, 0x909eed95, 0xb27215d1, 0x732961e8, 0xdcd541b0, 0x28c21d54, 0x0df2b4ac, + 0xac33143e, 0xa9ea0eaa, 0xcdfa2588, 0xc927571c, 0xca35f8ca, 0xc840a0fc, 0x55b4b757, 0x9434bd7a, 0x2e1ac1e8, + 0x0a9b1162, 0x8aca7625, 0x034f9307, 0x0491ef04, 0x785d0c72, 0x73b299f7, 0xd17861e0, 0x4323eaa2, 0xd7e0aca2, + 0xf989705f, 0xc4f09bb5, 0x99fd7f86, 0x271c30d1, 0x27e92bd2, 0x7286960a, 0x255036df, 0x941e2779, 0xdb8eae4e, + 0xf6adff46, 0x2b49ac54, 0x0a1cef40, 0x1f28d624, 0x8d6162c8, 0xf080d22e, 0xb6bb18f2, 0xa880e3dd, 0xa78846fe, + 0x4d2fa3ed, 0x05378029, 0xc49b8f5b, 0x2905cb26, 0xd3aeb39a, 0x1629690b, 0xdd1757eb, 0x2ff1f673, 0x9a688a6c, + 0x1d4d24c1, 0xc9742446, 0xabda29b1, 0xcdaec5b7, 0x295c0d7e, 0xd90ff9d0, 0x978d435d, 0xaf68329f, 0x38bed6ce, + 0xcff29244, 0xd79a356e, 0x5910c2a9, 0x77e55bd1, 0x505f5a79, 0xd26d9743, 0xe070d255, 0x4e577e72, 0x68f33845, + 0xc18b2566, 0xa83308d5, 0x022b9e46, 0x2b6f4a24, 0x6c7dfc72, 0xf76630f7, 0xb12f83b8, 0xfbc91237, 0xab95158e, + 0xf8aa7ac5, 0xd76a5eba, 0x891fbec4, 0xe1cde14e, 0xf5fd0124, 0x123ce625, 0xb2e43de0, 0x65626d23, 0x3333eaf7, + 0x1f29e299, 0xd6b24c0c, 0x6a6481f5, 0xeb4ad807, 0xd7a16f02, 0x9655eb0b, 0xc22d345c, 0x3bec5fa5, 0xd22848fb, + 0xb9117606, 0x99d8de15, 0xf58f6e56, 0x7533b564, 0x90ad90f7, 0xa114cff1, 0x7fd502b8, 0xac5a34e0, 0x76e2b46e, + 0x3e106b77, 0x01e92323, 0x556d779a, 0x18b1a5ad, 0x2d9d2887, 0x54e1bd94, 0x9994a582, 0x59cf2080, 0xe17b5ab2, + 0xcb1f04ed, 0xd42fe908, 0xcd00aec8, 0x820a5c05, 0x229bee59, 0xc8446595, 0xc9dd9716, 0xdbb9653d, 0xd55f6f4c, + 0x2183da6c, 0xf615fa3d, 0x88b43107, 0x85f645a8, 0x3436b234, 0x7e553a12, 0x2cef38fa, 0xa738eed6, 0x011e4dd9, + 0x915ccf5f, 0x20b174c9, 0x25215972, 0x30b7a4cd, 0x2129f05c, 0x29ea8163, 0x13f81c91, 0x9045309b, 0x2064548b, + 0xf91efa18, 0x579d0262, 0x24c3d838, 0x8b3be565, 0x553939e8, 0x31d0c06b, 0xd314be9d, 0xb6c246d2, 0x114f9e12, + 0x1d8c0eef, 0x57c98e18, 0x50116040, 0x0778bbf1, 0x30d91dd9, 0x948b14f4, 0x1cd63672, 0xd72dbc14, 0x72c165f4, + 0xadfd0381, 0xdfee0594, 0xfd8f9a78, 0x29cf2f71, 0xe25469be, 0xec88ecda, 0xaeda0c7c, 0xa4b9957f, 0x5dc1a43f, + 0x3a77b4e7, 0x62ad807f, 0x04a337ea, 0x9b506605, 0x0379c816, 0xdb7feb21, 0x9702e194, 0x50f3c880, 0x437398f9, + 0xdb172038, 0x19658647, 0x0cad25c4, 0xdac606c6, 0xb84181d5, 0xb0dd73f1, 0x19065c8a, 0x51f1f7f8, 0xbee06590, + 0xc89c841d, 0x0c5e131e, 0x35468f66, 0x99cb53ce, 0x406283a7, 0xb2452b5a, 0xc707ab70, 0x74fe1adf, 0xa0e5107d, + 0x9c00f3bc, 0x24396759, 0xa768b114, 0x5f43e28f, 0x81aa7895, 0x66a389d3, 0xb6fceb34, 0x04ce34fe, 0x3f3905e3, + 0x5b1cfb92, 0x60cb41c7, 0x737fb221, 0x2a083549, 0xbb8d21a2, 0x1cdf9641, 0x79f3099d, 0xb43db075, 0x7ea7dedf, + 0x715888e7, 0xd1e4685a, 0x7287bcf9, 0xccdd9a60, 0xbccecffa, 0xbafb6e86, 0xf14a9b3e, 0x61e07c8e, 0x82918d5e, + 0xeb7d33b8, 0xd556421c, 0x15973a1b, 0xb90c91db, 0xa28faa1e, 0xc75b5121, 0x22dd0094, 0xa1b18fde, 0xc31376fa, + 0x05ca884a, 0xa5ebb379, 0xf63ac40b, 0x8466e9df, 0x40fbe81e, 0xe48eee20, 0x439b3381, 0x49b7ba18, 0x4219a400, + 0x5b54e97f, 0x1f080608, 0x72f70697, 0xead22ab7, 0xc8882403, 0x4a225667, 0x6fed4907, 0x9cc37375, 0xcba56457, + 0x94f85aaf, 0x9530fa6a, 0x3c478d49, 0xbc802dbc, 0x128a1538, 0xfc7e6e7e, 0x56baafa0, 0xeee4137d, 0xe0eaba4b, + 0xf64fcc01, 0x42bcc451, 0x31d11845, 0x3eec0754, 0x14e34422, 0xcf9564f1, 0x14c28626, 0x4c0d2afc, 0x3b7ac641, + 0x2e20cbae, 0xf977574e, 0xad3d0f5c, 0xdaa9c35e, 0x2f2e7b3f, 0x887c91b9, 0xf719e901, 0xd9376c89, 0x08adaa13, + 0xac741cdf, 0x8649efca, 0x8ba0702a, 0xcd6aaa37, 0x2e79f9d9, 0x1b8fbe04, 0xf6749bcf, 0xc5cc75fd, 0xb26605dc, + 0x84c6a553, 0x0c7e811d, 0x4b8181fd, 0x2674568f, 0x94896210, 0x0d6e87a6, 0xe0480f9e, 0xaf0b04f0, 0xaacd4ccc, + 0x18cec985, 0x20969a9e, 0xb190cf4a, 0x7add1f18, 0xc036fbee, 0x4245caff, 0xc344905f, 0x1dfe6053, 0xbf0601c0, + 0xa44ace0a, 0xab6273c9, 0xf2a88c45, 0xd23b8264, 0x34c2ec26, 0xce570e10, 0x0e4630bd, 0xe3eb4789, 0xf665b661, + 0xe057977b, 0xaa193923, 0x3017954f, 0x7a711b1e, 0x20583480, 0x2532da05, 0xad78e090, 0x3667ca4c, 0x066b7657, + 0x2567444b, 0x194ec9e0, 0x2edb827f, 0xb1401823, 0xc26cd9ff, 0x6fd7f641, 0x39d2f320, 0x0f0fe22a, 0x742dfee5, + 0x1ad7277d, 0x6f766d1b, 0xcc88dedf, 0xfa95ff25, 0x67c42dd6, 0x66e510f5, 0x6ed71be4, 0xf265a559, 0x8997aab8, + 0x4a86abbe, 0x4f047175, 0x59b00f4a, 0x82ba7234, 0xd3a81753, 0xac92292b, 0xe3fd3b24, 0xf6b2c4a0, 0x4c596b11, + 0x3f742cd1, 0xbb15f74e, 0x56eea259, 0x8b79eb9c, 0xf1de113d, 0x1c3d3dbe, 0xca8ef39f, 0x61b6293a, 0x4e4b74c7, + 0x319bcb75, 0xf2e48f4b, 0xdb0c8439, 0x285a9edc, 0x97f4e07c, 0xea8c9801, 0xd84438c9, 0xc2def1ce, 0x99f34b3d, + 0xbb37d944, 0xd632c6d3, 0x28044d93, 0xe200c371, 0xaa8479c1, 0xa188b88a, 0x4b2dbfea, 0xb8e34345, 0x8db34bce, + 0x329595cb, 0x2905e1bf, 0x007235a3, 0x2a2acf97, 0x0a3171de, 0x3669135e, 0x987358ce, 0x8d692801, 0x8bd03049, + 0x82a3cecf, 0xbe44d6c5, 0xceb2802e, 0x165d24db, 0x51c801b8, 0x6b84e02c, 0x13261123, 0x46a3ab66, 0xdc50a6f7, + 0x7c4e95cb, 0xc7a14e17, 0xa03965bd, 0x7fb68aec, 0x2f268d3e, 0xcd6f095b, 0x4ced2018, 0x7b7c3c76, 0x36e8a0c4, + 0xa53067cd, 0x9469b12f, 0x86ffd9c7, 0x909e84cf, 0x591fb34d, 0xcbec6274, 0x014513ba, 0x3b5ab3a3, 0x1e0ff7a6, + 0xf99c8df9, 0x41ea2e46, 0xa8124a99, 0x9a61e6c9, 0xd0b0f054, 0xf711d3c5, 0x6214952f, 0xc7bef68a, 0x627ad183, + 0xb624fcaf, 0x63db7bec, 0xc5c62329, 0x718a79a4, 0x4786d2d5, 0xd198f724, 0x92577935, 0xd9905b94, 0xb9ba3a88, + 0xa9acd4ee, 0x51ce62c6, 0x2c8c5296, 0x108c38ac, 0x26a82778, 0x27100ed6, 0xc5e83fd7, 0x2a86e960, 0x411cb773, + 0x5593844a, 0x82586d69, 0x63b05c37, 0x0fd2b681, 0x4de2d032, 0xd40b3d86, 0x1ce8e784, 0x93ed3415, 0x04bb6556, + 0xdf10fdcd, 0x7fbc8586, 0x1d9a55e2, 0xe48c898c, 0x89a26ac2, 0xd598f771, 0x89e57236, 0x472d887c, 0x01757ad2, + 0xe98aea11, 0xea51243d, 0x26ccb359, 0xd7ad5777, 0x856017b1, 0xdbdd8f54, 0x5fd25865, 0xff70f445, 0x5e678fc1, + 0x9143078d, 0xd1001d25, 0x5fb99d91, 0xebdb4a7e, 0x299eed15, 0xf804a8e1, 0x0060b0ce, 0xc8826df4, 0x64fdc4bd, + 0xa20a85a9, 0xabe218a0, 0xbaeb1d06, 0x97454c3a, 0xe73584b3, 0x2ed4d6d0, 0x075bbe2f, 0x2b066332, 0x5057711d, + 0x3ea562de, 0x12f19209, 0xddebb68d, 0x9d86f1c3, 0xe67b0ad3, 0x483837a4, 0x8e24bbc2, 0x821478a1, 0x4504b886, + 0x8581b62a, 0x2602bcd1, 0x22767bf5, 0x3f38761c, 0xd36c62ef, 0x59a75948, 0x5c8770ab, 0xd8c91bae, 0xd58cd2a2, + 0x1f516691, 0xcf073d87, 0xda7b5736, 0x815e48e4, 0xae93d68d, 0x06dda188, 0x31e9a44b, 0x5d2b4be9, 0x59fb358b, + 0xb7651551, 0x25516ad9, 0x5c6db49e, 0x6f313106, 0x2ee99099, 0xb77931d6, 0xac758546, 0x04a8349e, 0xd42ff0ca, + 0x5ac6ca2d, 0x6009589f, 0x4822185c, 0xa06f4d80, 0x4bfec3f2, 0xacd318bb, 0x4e192596, 0x6714b64f, 0xf9825e58, + 0xfe638a1c, 0x5330cd6d, 0x7ffabff3, 0x70e1a4b2, 0x611c1d6a, 0xb89a15fe, 0x5694fa37, 0x4a2ada65, 0x696bb9d0, + 0x1cd3f89b, 0xaeb299d4, 0x7c9a6264, 0xe34b24e8, 0xef82fd0a, 0x37d159b0, 0xbb7e06e7, 0x0331a8b3, 0x154efd07, + 0x11f499e1, 0xb2c94bb2, 0xf2651a86, 0x12263988, 0x628934c1, 0x5f2f7a3a, 0x9a188b7e, 0x18eef4b4, 0xf772ac27, + 0xcb3642ea, 0x85647a9c, 0x92d99844, 0x6243dab1, 0xdb2cc472, 0x5af6e61d, 0x0879293a, 0x289022b7, 0x775dfbd5, + 0x2c88d058, 0x303864d9, 0x31cd279e, 0x99109b7a, 0xe9dbbc82, 0xd9f20e02, 0x35a3f5c8, 0x89bcec41, 0xf9b8e1b5, + 0x7ba2247b, 0x6c36b6c0, 0xff4684a9, 0x20e180d1, 0x1a26f5af, 0x3f029167, 0xc6286578, 0xea671668, 0x7dace0b1, + 0x9fbac223, 0x07bbed79, 0xa5265f64, 0xc9484628, 0xece44e21, 0xdf2b347c, 0x5d82bffc, 0xfd955ff3, 0x4e7ef717, + 0x9d3fe9f9, 0x7f32f83c, 0xf00c221c, 0xb4fd09d2, 0x67a02906, 0x777164a8, 0x32d47c14, 0x63a69faf, 0xd284948d, + 0x0afc1749, 0xf938e7f7, 0xde2679f1, 0x168f8dfd, 0x4783b9d4, 0xf2e3b92f, 0x35006c0d, 0xef93e013, 0x82259e83, + 0x82f4ca07, 0x4e3a1329, 0x2a443a9f, 0xd9353c37, 0xb2379bf8, 0x77bf23d4, 0x566e873d, 0x1bba9d69, 0x39764f4a, + 0xccb87f8b, 0x14e2c0b6, 0x7d0f1de4, 0x0ef8d912, 0xbb53ab97, 0x47669e07, 0xea29ce01, 0x43a79faf, 0xaed6704c, + 0x64868c06, 0xbd82b7ad, 0x629a3f4e, 0x5afa0b51, 0x4ab84053, 0x1a7194be, 0x1b0a8b74, 0xa9d72c5a, 0x75a2e829, + 0x0f9c49b7, 0x44321f10, 0xd37cfe07, 0xc5033924, 0x1f05eea4, 0x171aee5f, 0x549d29e3, 0x4169e2f0, 0x50042885, + 0xbc246839, 0x38873ef7, 0x70e71270, 0x2c89bee7, 0x0b0717c6, 0xe4fce65c, 0x4f759dd4, 0x646cef04, 0x3b91f684, + 0x3a3cb522, 0x52ee1abf, 0xbcdd918c, 0x9b47ceb4, 0xdedf4465, 0x0581d548, 0x04f6a22a, 0x7e3ac534, 0x1ace5460, + 0x292e9b3c, 0x888a7ecc, 0x111bd10f, 0x99a6c0d0, 0x37cdb16c, 0x8b7a4425, 0x4bb67439, 0xc6ff1f52, 0xcdbb6907, + 0xfb2c5f71, 0x3b950fa1, 0x0c2d4968, 0xd22eaf28, 0xa64eea0e, 0xe8f970f3, 0x7fd2e257, 0xb715cde4, 0x7dd46897, + 0xf8289696, 0xbf8a043e, 0x4afa1921, 0x79282c60, 0x23f8c563, 0xac172d8e, 0x400bd37f, 0x9aac6ca3, 0xadff1bf1, + 0xe38bacf5, 0x87996d7a, 0x54a2cec0, 0x2726dcf4, 0x17c7c9d3, 0xe67e7b39, 0x33663023, 0x538177a8, 0xdd0a4e50, + 0x1236c4fd, 0xd2e3dc27, 0xf03115e3, 0x7e2023b1, 0x2f7776f3, 0x43eace5c, 0x4cb71de9, 0x3a578723, 0x96330541, + 0xd66d57a2, 0x79f5e600, 0x1b0bb439, 0x1fed0086, 0x48b9e355, 0xeb8e91f7, 0xabde5122, 0xac4ef5f8, 0xc4594b5b, + 0xae8b0108, 0x9a83c393, 0xc13dce78, 0x86e71171, 0x1ae2b8b9, 0xd99d9607, 0x4632f1c9, 0x43f4892f, 0x96dc92bc, + 0x9c0da8f2, 0xeb8b79f9, 0x4207a730, 0x5b41afb7, 0x52fac629, 0xa78fa6bc, 0x0b43422a, 0xdd67e117, 0xcd3887eb, + 0x40f6f403, 0xbf52d1f6, 0xcd3fde6e, 0x6e201eb3, 0x62038e71, 0x2e4a0950, 0x34794045, 0x66261bf5, 0x91428efc, + 0x8d7d1036, 0x2b72f182, 0xa66c5063, 0xdea7bca6, 0xc8035e3e, 0x06faa4a1, 0x26722e5a, 0x082c86c4, 0x2a20a5d1, + 0xcece0551, 0x843be80b, 0x6a17fac9, 0x2caaaf1a, 0xdd865166, 0xb33d96c9, 0x536f1d97, 0x4763c816, 0x165d9809, + 0x3ad92896, 0x018e14be, 0xe31a780c, 0xe206ea16, 0xb1d37e70, 0x125e4b64, 0xd825cc67, 0x0b065f7d, 0x4e6b7e9d, + 0x4c6a5492, 0xca0726b6, 0x49c15c6a, 0x51402531, 0x803e3a93, 0x786e0349, 0x090fdaef, 0xe5491043, 0x75afc300, + 0x71a6bc29, 0x65efd0e0, 0xa15d5345, 0xfb744e2e, 0xc13dab30, 0x23a06cac, 0x359fe5fa, 0xa9e0d9e8, 0xbc01ce45, + 0xdf7e16a9, 0x5340688c, 0xdd4fe1b6, 0x4ca4ee01, 0xe2dec18a, 0x41caa48d, 0xdd0032ba, 0x71014307, 0xe07bdeb1, + 0x291c3ba6, 0x12620de2, 0x3d5a6519, 0x2343bc8c, 0x7a8c0e28, 0xf2b6e2ff, 0x479e66ee, 0x9a0025b8, 0x77fafe4f, + 0x01a4eba7, 0xc6faa1db, 0xbd4f4ffd, 0xd937e0f9, 0xfdf68d03, 0x1061f0ea, 0x6c8be0ba, 0xeed88a46, 0xa8b9b97a, + 0x2760b9bb, 0x322b6aa0, 0x48052305, 0x7580cc1d, 0xfd19f871, 0xc52bbc84, 0x127ee0d6, 0x2144e28a, 0x9f448e8f, + 0x9b5343ea, 0xa70a7097, 0x5d38cf2f, 0x2d03e9ae, 0x0bb96210, 0xdef9d77e, 0x2b49e626, 0x4fbd0cdc, 0x7eb0a5c9, + 0x6d03d59d, 0xc25d0147, 0x4697a2c0, 0x7cdece15, 0x782ee508, 0xb939f2c5, 0x9e981855, 0x6aca0cad, 0x336cce92, + 0xf030ed89, 0x8cafa7c1, 0xf858c121, 0x2caf1b16, 0xe2dbb97d, 0x6031008a, 0xbb42b6eb, 0x59847b8e, 0xb7debb32, + 0x2c12f199, 0x9a4c7332, 0xfe985aea, 0xc037cbf8, 0x1e33b2d5, 0xc594a03f, 0x641f9d99, 0x7db1568b, 0xa5c947b2, + 0x23b12c1b, 0xbe44d91e, 0xc04a8000, 0x1659ca3f, 0xd8b46e15, 0x068c9405, 0x209dc7ee, 0x4ed8962a, 0x4f8dd62f, + 0x2ede1fc4, 0x244f61de, 0x83daffb3, 0x2b28d968, 0x38dd7b55, 0xd0e6cd0c, 0x1172da17, 0x41f64cbe, 0x3f500d0a, + 0xeaeebf8b, 0x4f80bcf6, 0x29d9172b, 0x2af6b598, 0xe3a18caf, 0x3dfd77e6, 0xa0d941a0, 0xa3fd9f0e, 0xd6dfd70c, + 0x5c3f81b3, 0x3d644f24, 0x60082d32, 0x5d4c0676, 0x3afffe89, 0xc80b5547, 0x9d943943, 0x424430a2, 0xb3a4e5c4, + 0xf5bb2144, 0x1084d92d, 0x7ea3e332, 0x38898888, 0x20cbca4d, 0x18981394, 0x1a26b427, 0x3c5e8685, 0x24715561, + 0x1a295c97, 0x1728a499, 0x1b6bfa0e, 0x1bca92d4, 0xa8fa7663, 0x717bec98, 0xc4853dbd, 0xd66347bd, 0x6463e22c, + 0x7a4285c3, 0xc1e2a6d8, 0x2a0bd15b, 0xee10dd49, 0x778cb87f, 0xeb947afc, 0x1e4b04b1, 0xd266e525, 0x8f135d6b, + 0x19dca368, 0x35abe51d, 0x5d573ee3, 0xfa87b390, 0xece24f0d, 0x3f4dfd79, 0x3a142d98, 0x3ce76539, 0x7987ae45, + 0x1a617d01, 0xf9eb0345, 0x80cd6931, 0xcfc2e446, 0x6f7d679e, 0xd74de4fc, 0xb660598f, 0x02301c57, 0x3dce6e80, + 0x65ddbd03, 0x87cfb833, 0x09e5b257, 0x4c501c23, 0x2b28ac94, 0x285b2e98, 0xc6e0c877, 0x76050f1c, 0xe0072456, + 0x3425366c, 0xc63cc4d6, 0x4d17229f, 0x1f0a4b09, 0x9c7d5a73, 0xf4824cc1, 0x54081524, 0x568fa70a, 0x96635ff8, + 0x334a7f1e, 0xab1e2a6f, 0x8670c1a9, 0x1192fb9c, 0x0ef31f27, 0x48c7c3b5, 0xa5d44259, 0x011ecaed, 0x570ed039, + 0x683d1c5d, 0x7ba418f5, 0x81c26577, 0x6df4b105, 0x242fad3d, 0xcf156af5, 0xfb93105f, 0xa98747d6, 0x9d0f32a6, + 0xbe5f648e, 0x2c9ab4d0, 0x104aa52e, 0x5ccd3fd2, 0x2f59ffed, 0x5611296a, 0x1d66712d, 0x03bac541, 0xaa365585, + 0xc47c8c84, 0xdda5852e, 0x927ed385, 0xadaacd30, 0x4bd93d89, 0x44542438, 0x26f49cf0, 0x217837d6, 0x7921ff3e, + 0xa3015037, 0xeeda0115, 0x2d21c8d0, 0x1a111c99, 0xf9ff1a25, 0xd5d404fd, 0x36e4bd8e, 0x075907a3, 0x540a2cd9, + 0xdd1fce2b, 0x8a88a2bf, 0xf8c1bf16, 0x189c5844, 0xf2020a2e, 0x04b5c0e3, 0x3e574918, 0x3d1dda73, 0xe518d1a1, + 0xc043786e, 0x323a26b2, 0xcec1b5d3, 0x65d87d34, 0x1e7d2702, 0x905dd1bd, 0xa8395ee5, 0x249a5ee7, 0x4fd5e4a2, + 0x0d89e747, 0x56d0b3bf, 0x1e52255c, 0x374a0d96, 0x20715cc4, 0xb7100457, 0x32523fbf, 0x4b4ee063, 0xab73fb91, + 0x24760e62, 0x340091a8, 0x272a129c, 0x03493240, 0xc9d1c52b, 0x40cfb5f9, 0x41bcd22f, 0x23454170, 0x6565c3e2, + 0x177de95c, 0x930d9d2a, 0xca789491, 0x5427787a, 0x7c483e30, 0xb4b4bc0c, 0xe539b3a1, 0x6fc8e8ec, 0xf027efd5, + 0x55975b0e, 0x7ebb63e5, 0xa56acbc4, 0x18278a25, 0xa6f6a9e5, 0xbe14dfdc, 0xd2065f4e, 0x3de7c689, 0x2bc9ced2, + 0x2e5b5983, 0xafbdc2cc, 0xb03596bf, 0x40916d4d, 0xc83a5411, 0xa8c2da53, 0xe6f73f3f, 0xea89ced3, 0xf55dba4a, + 0x1ee6bbb8, 0x0a9892a7, 0xd56006f2, 0xec138a8d, 0xd01d7ed0, 0x1e4ea83d, 0x8be0c1d9, 0xcfa0b005, 0xf532b9f0, + 0x80563984, 0xb3a59038, 0xb23e08cd, 0xa5a470be, 0x4bba6dca, 0x1dd6348f, 0x1c49403b, 0xa1853f27, 0xb7b99d57, + 0x81160a99, 0xe9ea5ec5, 0x08e38190, 0x8ef5f4f6, 0xa8295bee, 0x3011a30f, 0xdd3e6935, 0xb58906e2, 0xd78aa7e2, + 0x4f823fec, 0xb2ad6be8, 0x3873af4e, 0xe489245f, 0x4c7c95d7, 0x64e3e4ce, 0x8f812234, 0xe34e2e8b, 0xb8e0690c, + 0xf93594c2, 0x7c247776, 0x4663978c, 0xdca98fa6, 0xf4fbad3a, 0x3bf1d597, 0x8859952f, 0xf9b7f6ed, 0xb2a31f3a, + 0xb4b93325, 0x379f5037, 0xb905c1bd, 0x19c30685, 0x24e4a7bc, 0x6bf23fa1, 0x95c1100b, 0x519048b7, 0xace71e73, + 0x3a79dabe, 0x2e28741e, 0x81c69dea, 0x21d4fb3c, 0xa0e6f814, 0x24b96f4d, 0xb987ddb7, 0xe7ee4975, 0xc6581e75, + 0x1b9f5be5, 0x45d5c546, 0xb8249841, 0x30c5b565, 0x1cc86c3a, 0x5337600b, 0x83784964, 0x513d5024, 0xbe69f80a, + 0x79790f15, 0x5223ac8b, 0x9f14b51a, 0x6d0a302e, 0x3a403446, 0x5db50618, 0x261660c7, 0xe6f00b11, 0x3977e572, + 0x06d23287, 0xe87aa100, 0x7653d8a2, 0x8ad07029, 0xdc0f04ae, 0x3edec3be, 0x56048113, 0x6f234b20, 0x5e87f1e3, + 0xc782d926, 0x0c265d6a, 0x72d032b6, 0xdd15a724, 0x1c1d52f3, 0xe367698e, 0x4294ef0e, 0x4143e789, 0xe82ee7f3, + 0x212fc9e6, 0x1ad603c5, 0x0f20a3d1, 0x61e50210, 0x0fdc8bcf, 0x5932a583, 0xf1b56bf8, 0x5bb67d8b, 0x8ba45140, + 0x6ee508d9, 0x7fd68f47, 0x23a808c0, 0x4a168099, 0x58e53eea, 0x703eaf95, 0x3ef2658f, 0xade384a4, 0x6138e01c, + 0x4a15a496, 0xd29305a0, 0x9f21018c, 0x93cfb677, 0x662c1ec0, 0x7cd8b90d, 0xfd9af42f, 0xb2248ee2, 0x0e9d53d3, + 0xb0367499, 0xdee4eb92, 0x60e27ac0, 0x815cd91a, 0x8ae80ac4, 0x5ef42cd6, 0x60b28a74, 0x86a6a326, 0x271f96ac, + 0x185b53fb, 0xbb329cdc, 0x75bbb1f3, 0x7a70adae, 0xfca41b74, 0x7a9f7778, 0x3fcd20dc, 0x6bcb966d, 0xae0b1f48, + 0x9c11bb2e, 0x45a6aa0d, 0xb6bb0544, 0x50ea381d, 0xadd09811, 0x34f6f98f, 0x050828cb, 0x15ea3717, 0x424faca8, + 0x0a07673b, 0x449b2062, 0xd7ee65cd, 0x41d2381c, 0x0343e106, 0xeb9f6633, 0xb38be08a, 0x2af63bf3, 0xded57c0f, + 0x24951246, 0xadf66c46, 0xdd2b97d3, 0x0b31f6e3, 0x3fe85ce2, 0x02a157bd, 0x7125b2a6, 0xa8ed921b, 0x8fe635b7, + 0x5675e045, 0xb2484af8, 0x309db473, 0x2d593fe3, 0xfd18c533, 0x5ccbabab, 0x816d939b, 0x3a8d7d2a, 0x18a1046f, + 0xa70f7f07, 0x8ebfd848, 0xdb04cb5d, 0x18679d68, 0xa7c46dc3, 0xaa43d48a, 0x76f0ea38, 0x9f00b75f, 0x4d93ab58, + 0x97a11726, 0x7279dac2, 0xdf4d15da, 0x46713ffc, 0x772e838e, 0x6a741427, 0xea4d6225, 0xbc28a5f2, 0x020c9ed6, + 0x3340a141, 0x1b49858f, 0x0c1a5bbb, 0xc79c5877, 0xe9c40b9f, 0x7c8087ec, 0x50fa6e2a, 0xd71d3ba2, 0x3612d60e, + 0xb32edccb, 0xde625545, 0x9dd1884f, 0x32cdc3b5, 0xec61ac1f, 0xfebd821c, 0x7a172cb5, 0x6e7f9bcb, 0xf45be6f5, + 0x5db0286c, 0x775a8031, 0xfe341cec, 0xcfe4063e, 0x38beb50a, 0x8419ce45, 0x17123771, 0x8400db40, 0xc3efbead, + 0x8f5b9513, 0x95344c32, 0xc6dccf4d, 0xa921693f, 0x7050fef3, 0xc49e00e2, 0xc9f5c993, 0xb5ced0e8, 0xac6ba2e6, + 0xf267773d, 0x63c05f7e, 0xe0ee9f17, 0x2245f10c, 0x829b5bdf, 0x8bc83629, 0x1d3e6a58, 0x1494f0f8, 0xdbea3303, + 0xa0a6cf33, 0x4160089a, 0x74a2d125, 0x52bb0fb0, 0x4c870caa, 0x251d0e27, 0x77785b1f, 0xf170652d, 0x24354645, + 0xb35d8108, 0xc6634f94, 0x7682e399, 0xe2d57a0a, 0x98839a66, 0xa12f68be, 0x88e9a2b7, 0xd9f0f4d5, 0x4bcb26f4, + 0x094c9319, 0x97a12c3d, 0x948b809a, 0x17831f90, 0x7296b7b4, 0xf5e22d34, 0x8108ee08, 0x58283fa2, 0x3f85f63c, + 0x78848d7c, 0x62926dac, 0xa4d6bf26, 0x41de0d3d, 0x8ed651f9, 0x89cf3df5, 0x492f7e33, 0x2065bf13, 0x3dd3439f, + 0x8366c69d, 0xc03505e7, 0x07afc857, 0xcd19bf4c, 0xe95ffcbd, 0x5139567a, 0x52bef3c6, 0x5f9dd084, 0xb5768d78, + 0xf1f4149d, 0x666fc892, 0x932c27d7, 0xec5ff1bc, 0x50d6bac3, 0xbe1aed17, 0xa34e01b8, 0x4aaef768, 0xf3448a73, + 0x55c860bf, 0x106f33c7, 0x48da17d2, 0xd9df6c2f, 0x70b625b6, 0xf9959a38, 0xb47b0ebc, 0x25200988, 0x29d0c4da, + 0x819c572a, 0x2b5100fc, 0xcb44efbd, 0x38693bf2, 0xd4701a28, 0xa6cb31f6, 0x5e048628, 0xfb20df8b, 0x451f55e6, + 0xb1fa0194, 0x5c5632ec, 0xe164d3c0, 0xa91ce4b3, 0x4268adfb, 0x5dd8d8db, 0xf4bdc713, 0x08b68c32, 0x858a64c6, + 0x0f3a6c8a, 0xd31d93ec, 0x33a2ffb5, 0xdd5a453c, 0xfd5ea415, 0x1c7ec15b, 0xa3146722, 0x7b74e9c7, 0x9f3ca02d, + 0x1014cee2, 0x3050bf74, 0x051aa679, 0xa05b36fa, 0x4fca0622, 0x6d4f3eb8, 0xc6fa90e4, 0x06a9e646, 0x1d2378cf, + 0x4d9117a4, 0x684e320e, 0x21be1a49, 0x7c268ab3, 0x7901e6bf, 0x6158ec15, 0x32a261bc, 0xdb41b0fe, 0xb68ff7db, + 0x51420568, 0x51269cab, 0x45553971, 0x3cfc4ab5, 0xe0968f5a, 0xfda23f36, 0x478abac8, 0x4fe0b545, 0x470471f5, + 0x24b1ec26, 0x41a00925, 0xd85e79fe, 0x108eb2c5, 0x964de8ff, 0xcffe493d, 0x417eeabe, 0x8c48badf, 0x2203ad1a, + 0xbc9d7ebc, 0x469a811c, 0xfda71c4c, 0xeb617574, 0x778fa89d, 0x6404ca45, 0xea7eb4e2, 0x75011f37, 0x259f9823, + 0xa95eb2b5, 0x200166d7, 0x929b967b, 0x3dbc6c8b, 0x887e3bbc, 0x0e91ac6b, 0xc927b046, 0xc3a82d99, 0x14a19cc6, + 0x648cc1c3, 0x545c6e37, 0x8c89cbed, 0xec54264c, 0x6cbedefa, 0x6431e9ad, 0x9af873f3, 0x1afa08bf, 0x516852a7, + 0xa7baf26b, 0xc4d35289, 0x3650dc4e, 0x6c83c079, 0x46f19780, 0x2716adcd, 0x268bc16d, 0xd765b804, 0xc4c7d8d3, + 0x6fbbed76, 0xaead230c, 0x2fcd30ff, 0x920d1001, 0xcb199b70, 0x8279380a, 0x8f1e5676, 0x691aee5d, 0x023367a8, + 0x40ce04cf, 0x80b28330, 0xecec8f0e, 0x6ddca04f, 0x1b026ee9, 0x8633dded, 0x503fb2e2, 0x7bc3dea4, 0xc981b9f9, + 0xa38bab35, 0x7bb8521d, 0x6077d00a, 0x1e70f876, 0x445ec589, 0x14eab75b, 0x150140a3, 0x9360a30f, 0xbf687993, + 0x7bfbddbd, 0x634eb082, 0x5ab9a810, 0x98e6eb0e, 0x2df7b610, 0xf434274a, 0x7e1daaac, 0x58fde125, 0x381f1a3b, + 0xddaf7c09, 0x7d1b2c52, 0x929c5f34, 0xc69398aa, 0xb53fb5a1, 0x918b135c, 0xaf8f7f25, 0xef3476ce, 0xafb1afaf, + 0xe5596068, 0x200697de, 0x33be5fc7, 0xa145571b, 0x2c6d26ed, 0x535de201, 0x9e813ece, 0x9128fffc, 0x77d1ad44, + 0x9befde34, 0xea4b41dd, 0xba7a4913, 0x21e95de8, 0x1e96f7ec, 0x9eec5aa6, 0xe07ae5c8, 0x658d87e2, 0x3d4660de, + 0x6265ab64, 0x9ff7f78f, 0x4820939a, 0x08fc266d, 0x462eec75, 0x08fc11f2, 0x7af25830, 0x6ac78ee5, 0xc041f5ae, + 0x69c84975, 0xc51efc7c, 0xc8281c6f, 0x26ade9c0, 0xa6242968, 0x5f10dc76, 0x1db88c5d, 0xff7d9f17, 0x65bbfbca, + 0xd2805666, 0x432e4d9b, 0x8381d503, 0xa76ddbef, 0xdb1964ee, 0x4c029133, 0xd695f2fe, 0xae161af9, 0xc50e05cc, + 0x75c8ed93, 0xe3437ad5, 0x08ae7237, 0xf9675c60, 0x8fe0e99f, 0xcadf4be7, 0x3ebf7612, 0x3550d3db, 0xc7c83ef8, + 0x7c1e1759, 0x00dbc66b, 0x5cbac9d2, 0x3597b922, 0x1e1e3355, 0x10d99744, 0x3f9ea0f7, 0x4ab57ad5, 0xa881ac18, + 0x10e0d659, 0x24ae9767, 0x1c38f619, 0x39aa2d20, 0xf4fd7219, 0x7155a3ff, 0xce8d6dee, 0x4f475409, 0x16f7efc6, + 0x0185c15f, 0x935ecca0, 0x4cf071ef, 0xf3af7b49, 0x70c86b7e, 0x41775d25, 0x5a37ca16, 0x008daef3, 0x5100a039, + 0x2fd53c38, 0x78eaf679, 0x8351fd1e, 0xd7bfe854, 0xac9207b9, 0x87b05ff2, 0xc6f31901, 0xa50f7afc, 0xffde3ca6, + 0xde079fe7, 0xaee223e5, 0x6e23524f, 0x84951bd9, 0x8c64c52c, 0x66774c4a, 0x4925b493, 0xe4b81421, 0x6b0e1383, + 0x3a81a959, 0x284861cc, 0xf4fa345a, 0x5d4d1245, 0xffc68fcb, 0x4e6facdc, 0x188ac395, 0x19b13157, 0xd876951e, + 0xdd995ca1, 0x76549427, 0x2b0b5610, 0x2c1ca852, 0x919a1742, 0x77df8800, 0x7286f2ea, 0x1f4c4b2e, 0xfc014ac7, + 0x2221d628, 0x4200b9d1, 0xa699d550, 0xdecc521e, 0x920481d9, 0xdade7765, 0x75864446, 0x3e6d147a, 0xfe124883, + 0x147d8f51, 0x8de7a9d5, 0x1efccd37, 0x30e0c188, 0x9fd328b7, 0x7e6f8ca4, 0x6ce9253e, 0xe3e20b27, 0x4737676c, + 0x9ea8c3bb, 0x66ac3dcc, 0xc12f6e8e, 0xdb83bd19, 0x77002024, 0x1383a74d, 0x833a1e0b, 0x9f747ade, 0x5d842867, + 0x8a651fe6, 0x660bf5b4, 0x6126caa4, 0xd288949c, 0x0a375ccc, 0xecefdc8c, 0xb86eafbf, 0x72a24aa5, 0x3e0cbdbc, + 0x203f0ff8, 0x6d34682f, 0xfb360c80, 0xad7de30e, 0xbd6469c7, 0xc99281c3, 0x83749f4e, 0x6dd204ed, 0x22df29fe, + 0x3a760d8f, 0xc1d29859, 0xc6f41bcf, 0x426e8dd5, 0x0a78dd67, 0x5697b4cc, 0x54464f5c, 0x4b794a08, 0x629cd208, + 0xba6e9f7e, 0xe45f8d89, 0xaa9990e8, 0x65362efe, 0xb4b0d1a4, 0x4e94c74b, 0xbe4d4b69, 0x80329293, 0x669848a7, + 0xd48f3bae, 0xa2e33679, 0xeeb4e514, 0x1370c897, 0xd5c02f6e, 0xefcb0f04, 0xec9bb166, 0x3f7387fd, 0x0cb5e0d0, + 0xa4e48913, 0x7d21a83c, 0x479b2298, 0xe21c68e1, 0xc4754c09, 0xc712fe03, 0xa06792bc, 0x91b0647c, 0x2917b0b1, + 0xba84f212, 0xfdd43daf, 0x05978ba0, 0x1ba0a877, 0x59295846, 0xf5eb7c20, 0x27f89e64, 0x9b704292, 0x7fe3bc7a, + 0xd64ec3bb, 0x591e3eb7, 0xba4bf60f, 0xa0b4812f, 0xeacdbe70, 0x35eced66, 0xb786faf5, 0x116de8e7, 0x5ffc5824, + 0xdb2b200a, 0xc73fc05c, 0xd6bcaaae, 0x0b4bbf04, 0x788a06ff, 0x63e7a530, 0x6cd36863, 0xd99977df, 0x4a99afd8, + 0x41f3190b, 0x083e4441, 0x4ba88689, 0xfa0ef62d, 0xd9bccb42, 0xfc0797f7, 0xb3dc581d, 0x4cb1892b, 0x2f7e1498, + 0xcd9215ff, 0x79ae278f, 0x59838b3d, 0x7b1737e0, 0x54244f7f, 0xb72a52bc, 0x2372985a, 0x12241d53, 0x6adc8539, + 0x9711abd0, 0xd8b24f36, 0x01980a3a, 0xd8b59f84, 0x75086d69, 0x62b3966c, 0xd01343a6, 0x6eca5c0d, 0x549577f5, + 0xbe111715, 0xd701d42a, 0x05a1bdb0, 0xf278ef4c, 0xae31e504, 0x6ed7bdee, 0xbf4c349f, 0xa74eb3ea, 0xb71274f9, + 0x91a56ca9, 0xbec35738, 0x9739f40b, 0xc005cbfa, 0x82cd5983, 0xee0cf47f, 0x4469cf1d, 0xd2aef6dd, 0xbcd7b016, + 0x986e82fe, 0xfd978861, 0x10c210d2, 0xfcbef2c6, 0x64f9f6ed, 0x15328bf5, 0xd9e50897, 0x457abbdf, 0xc85b4203, + 0x159cdf7d, 0x6fe38deb, 0xbba6e24c, 0x08771461, 0xbefdd29e, 0x5ca06667, 0xcefecb37, 0xc90661ad, 0x5e14f4dc, + 0x74f49c9f, 0xda7c7d89, 0xc54fb68b, 0x043b3db6, 0x4c577d46, 0x5785334c, 0x52fc2178, 0x9a0c4c9d, 0x22a6fb86, + 0x6762809a, 0x916c206c, 0x0be02f2c, 0x0dd94a9f, 0x66ecef06, 0x59a72d52, 0x4d3ddceb, 0x24c99b74, 0xec1bd3ed, + 0x280e6a89, 0x3fde1fe8, 0xc841196e, 0xdcb4ae66, 0x20e61c69, 0x226a87cf, 0x4ab88f39, 0xcdb51598, 0x1007a046, + 0x500958da, 0x46dd3be3, 0x7e9e433a, 0x973e279c, 0x35d9cf50, 0xeb26cffe, 0xc471c52c, 0x039ce931, 0xe0f97b52, + 0x4360a983, 0xf5ce202b, 0x21200db2, 0x32aade18, 0x53afc633, 0x2469d2f5, 0x89d24d88, 0x3bbb8c80, 0xa791e6b9, + 0xbec46474, 0x70f70413, 0x6ffd6368, 0x3c16cf1c, 0x41d2c391, 0x470bbd7a, 0x5f32bbcb, 0xd56672f5, 0x0199fcb1, + 0x21d9bf1a, 0xd03cf321, 0x1369cff2, 0x0ef098db, 0x00eedf16, 0x2e133a49, 0xd7b7de5f, 0xe2eb3b2c, 0xf4519b3a, + 0x0c62b78c, 0x9464783e, 0xdf71e28e, 0xd6bb3b8c, 0xb36cf127, 0xdf5ab111, 0xd0ef39ea, 0xa5721896, 0x3a8b8e81, + 0xa77fc3c0, 0x3eaa5f4e, 0xbf5566ce, 0x95b6d489, 0x24246e76, 0x3bc2d37a, 0xbcdf8d25, 0x3ebe7a59, 0x7f610c91, + 0x7736bcdd, 0x75bc2424, 0x85c70d05, 0xbeb7ba24, 0x4423de3b, 0x228f9f73, 0x7c01c1bf, 0x9f0d29a4, 0x61a80872, + 0x3ec5601f, 0x27ba04c4, 0xd7a5024e, 0x71452235, 0xfb211dc9, 0x61aa93d6, 0xbf25696f, 0x22b2f2a2, 0x969488a2, + 0x82dff5ba, 0xcfe623fd, 0x88329b88, 0x4cccb4ba, 0xb76482cc, 0xe5023477, 0xa46a3894, 0xbe7c5404, 0xd1fd3901, + 0xe6bbe2ce, 0x0c4f1b4f, 0xacc9b278, 0x3db561f4, 0x332dc3b6, 0xf38df13c, 0xeae891c4, 0x8f00c6d3, 0x778f1d35, + 0x99846b91, 0x5f3096ff, 0x4a87ec24, 0x7c7c7bfa, 0x47ee71c1, 0xb372259f, 0x572c7bbb, 0x9fac8e01, 0xbc3e5e7b, + 0x0a98ad4a, 0x8724098b, 0xb65b4238, 0x08816daf, 0x0ba64183, 0x50cc14e1, 0x42895df2, 0x8858e739, 0xcbe17ba9, + 0x1b74d24f, 0x4402d400, 0x5cc6ed20, 0x279a68ce, 0x7127622f, 0xb430e865, 0xe15ef496, 0x0ebe1de7, 0xd28793ef, + 0x1e95ce31, 0x753f0cb8, 0x9bdb6bfd, 0x5ecc4ba1, 0xf4421461, 0xadf6bdfd, 0xc01bd28e, 0x4419125c, 0x2d7d94e3, + 0x5073c54a, 0x96aeece3, 0x840a2b99, 0xb24aa255, 0x38345e2f, 0xf34125d6, 0xc761e37c, 0xb5ef96ce, 0x11d2d1fa, + 0xad59d51b, 0x360870ab, 0xbfcdf45d, 0x480e2047, 0x0dfda9b9, 0xdae944f9, 0x6f03ee85, 0x3b6f8dec, 0xed9fd4ce, + 0x2cfd70f7, 0xcb88d469, 0x5935984e, 0xa8d78801, 0x341df785, 0x020e6c47, 0x65f12cef, 0xdec04f23, 0x03e3fe4e, + 0xdd3008ff, 0xada46c49, 0x85e22f56, 0x278bb9f1, 0xfdcaa6b5, 0xaf47c5c9, 0x01381941, 0x3f60c1f6, 0x67f8da0e, + 0xa5939439, 0x4c0f815f, 0x2a17adbe, 0xed844395, 0xf2574d5b, 0x55e0b113, 0xdc8a1aef, 0x7ec73cd1, 0xb4d868e0, + 0x56f54288, 0x636cab2a, 0x5b33eb1b, 0x1a4f3fda, 0x613a2cb4, 0x5fac0fc4, 0x082f9f9a, 0xddea4a23, 0xc1484a94, + 0xa75a8bf9, 0x5575b1b5, 0x895bf61b, 0x7e3d5b23, 0x0c504c94, 0x8f7002be, 0xbb91b010, 0xe0c0e536, 0xdb74aee7, + 0xb1364dd8, 0x2d7610bc, 0xf0b00272, 0xa69f0300, 0x66e18979, 0x3268085a, 0x4efa9e50, 0xd084d664, 0x360f51fb, + 0x6b7a7c30, 0x2784ab4e, 0x3783c57e, 0xccf4e91d, 0x53b8639e, 0x194c94c8, 0xfe9f1f85, 0x2c3fd121, 0x5f61d770, + 0x5eae06a4, 0x58696c5a, 0xfc6871d1, 0x190701f4, 0x6ea70120, 0x1aabebf6, 0x634f5197, 0xee0233f9, 0xa86fec8c, + 0xf8b401e5, 0x3d41f088, 0xd040ff28, 0x35e174dd, 0x5e62e392, 0x7298867f, 0x4a0141f9, 0x16af8a83, 0xe79ade31, + 0x600f270d, 0xfba0bc80, 0x963ef16f, 0x1d356ea0, 0xfecd8e0f, 0xbe48905f, 0x4e444b91, 0xb00ddb84, 0x50dc11cc, + 0x66dbbdc1, 0x9b70316c, 0xaa65c3cd, 0xe4c95a37, 0x16807f45, 0x1c780fdb, 0xe48d9478, 0x551787d5, 0x5a9f9918, + 0x73d898a7, 0xdfadd8fd, 0x1929933e, 0x68ba46fe, 0x20216b46, 0x8ed90a4c, 0x468398db, 0x3d7c8352, 0x1791921e, + 0xbb5f1e08, 0x7e566151, 0x1c65b9ce, 0xd9a2f352, 0x81d68bd6, 0x80c980f5, 0xc9fd0a8f, 0x536fc6a3, 0x9e9d42bf, + 0x82fa063e, 0xcb52fabb, 0x07be95ad, 0x4677fb89, 0x3e6ce045, 0xa3b66e20, 0xc5061497, 0xffd971db, 0x5f535bc4, + 0x8c327bdf, 0xb1bc1ead, 0xea9cbf9d, 0xcdab1f9a, 0x76b2d7f2, 0xc3c2c476, 0xbffc7ea3, 0x0f2a9fdc, 0x33a14617, + 0x3fd9bb97, 0x07a1f3d9, 0xec3fabfb, 0xa9ff2d22, 0xf777121f, 0xa64456f4, 0xf7d1bd52, 0x411f3c98, 0x0f55fb48, + 0x053eacbb, 0x700c0ed5, 0x83b963ba, 0x97cd7698, 0x6f220158, 0xca43ce0d, 0x6b29fdf8, 0x60f1b4c6, 0xd547b235, + 0x0358ad8d, 0x7ebe869c, 0x5af8778e, 0xe2fbc986, 0xbd1c082f, 0xcd059775, 0x3cabcfda, 0xe2376984, 0x4747e9a9, + 0xd2373caf, 0xf6a5860b, 0xdfa4021d, 0x69ad5b16, 0x2284c521, 0x59d71496, 0x5f9c7000, 0x0c3b6c91, 0xbb9b4879, + 0x97582d54, 0xe0724668, 0xe2aeaa4c, 0x331f51b8, 0x6e2ca429, 0xc016e51e, 0x1c42d62f, 0x8b48d470, 0x271ae05f, + 0x5d90e07d, 0xf8785c52, 0x19a9c1e3, 0x02c97c1f, 0xb78faa43, 0xfbaeb138, 0x10586a10, 0x7dd1bd14, 0x91638d23, + 0xce1b1a7f, 0x30090d9c, 0xfff154b9, 0xdbd388e6, 0xa7ed52f9, 0x7bd0a9f0, 0x413dc608, 0x23475b4c, 0x3c79bb08, + 0x541906c3, 0xc25bfe53, 0x8cb22920, 0x396c9527, 0xc6e96e6d, 0xb1d78e9b, 0x978fb498, 0x36cd5f22, 0xac668ac5, + 0x54dafbfd, 0x593de62e, 0x2e42e635, 0xa881013f, 0xc094af28, 0x0efb8375, 0x11dab52e, 0x2540ed9b, 0xa68eded8, + 0x7abc5440, 0xde98a988, 0x9002bb36, 0xd84f6337, 0x75555601, 0x34586498, 0xd4dc0ef8, 0x7dd5914f, 0x8d99d5ed, + 0x4610e1a5, 0x270a8dec, 0x20dcbc37, 0x573da163, 0xc3de4fdd, 0xfed241c7, 0x5f702fdd, 0x69ef7655, 0x13a1d8ef, + 0xd3b95e3c, 0x1a5980fe, 0xb5319513, 0x9db66136, 0x5087d029, 0xfc5ee0b9, 0x3885f5f5, 0x434657f5, 0x3a93e272, + 0xd9352c83, 0x210a7dac, 0xc94a6161, 0xbecaaf13, 0xa203a2cb, 0xe4b7956e, 0x33a795ae, 0x3013f92d, 0x7017b2a2, + 0xe9648991, 0xf666727d, 0x87254196, 0x425e6c0d, 0xdd6921f2, 0xbaab70e6, 0x1950b964, 0xef38459c, 0xecc8dda3, + 0x0359da52, 0xbf0ea2f3, 0xf13104d5, 0x7013eb29, 0x1527c3a6, 0x8b37e6b6, 0xb6d41338, 0x1d25d8a9, 0x755c097d, + 0x0e7fd790, 0x705c51e3, 0x5d60c463, 0xd33d6222, 0x9d4dce8f, 0xaa62acb0, 0x5299d22c, 0x159978b0, 0x5833d779, + 0x15c0ad78, 0x2f62d6c1, 0xb082ced0, 0x9c46e0d9, 0x7616e78f, 0xe1d1fd35, 0x09b38247, 0xc0f8d1a4, 0xea653faa, + 0xf0d47877, 0x61a6a592, 0x0f2b3c17, 0xe9541ee2, 0x64725e4a, 0x61f2554f, 0xa7d932d7, 0x71792aec, 0xa58d081e, + 0xafc2aeca, 0x2bf1bbf8, 0x011c549c, 0xa3fffe74, 0x1af8f9cd, 0xb8d64e63, 0x0cd99896, 0x99c233af, 0xb7cfedb5, + 0x6a374313, 0x62fadfa0, 0x4c9bb710, 0xc71acdb8, 0xec3f103b, 0xab15765e, 0xc722d7ed, 0xcc3ee52f, 0x6b8547f5, + 0x3086683a, 0xcd5c9934, 0xe66c6b82, 0x4e8ed849, 0x01b333b9, 0x5c229bb2, 0xd9438eb6, 0xebbb298a, 0x83f5346f, + 0x2ca83009, 0xcd6d1575, 0x1d869607, 0xc5844af1, 0xfb1d13bc, 0x0a923b7d, 0x543d836d, 0xce7b47c3, 0x09325077, + 0xddc69fc5, 0xa84fac2e, 0xf1a34dad, 0x037b9aa5, 0x1abb9cb8, 0x9373b949, 0xb990b1c8, 0xa578cf79, 0xe4dcc060, + 0x66c03367, 0xd9be1315, 0x4d555340, 0x11929d56, 0xaef2901c, 0xc57fdc57, 0xb93b1dda, 0x803acd41, 0x0a9d1d5c, + 0xace3a189, 0xb301b223, 0x1bcdef5c, 0xb1e320cc, 0x23f223e8, 0xfd7492d0, 0x8d2de4f2, 0xc9c5a5d7, 0x649a3287, + 0xf215a122, 0xe08f3ffe, 0x65653b50, 0x941fd735, 0xb3d79d1f, 0x7070d2b9, 0x70ce8d7b, 0x67889ef8, 0x9bdc7d28, + 0xcaf4f4f6, 0x05fef23c, 0x48b7dc57, 0x8bd7fa12, 0xa52c4ef4, 0x89a79b8a, 0x3ba605e2, 0xc819c385, 0x9e9f9104, + 0x8d5bcbf2, 0xe4fdf73b, 0x0643276f, 0x790eacaa, 0x13a90024, 0x3f1f28f3, 0xd8bd6ef8, 0xd8f910d2, 0x00c6be15, + 0xe06016f5, 0xaa221402, 0xa029ff77, 0x7817ba1a, 0xf9ed2c16, 0xe0971174, 0x3e7e3b5c, 0x60cdf284, 0xef759e55, + 0x4020458b, 0x182d9540, 0x85a32cab, 0x7be4e579, 0x1ea122b0, 0xd350c4b4, 0x8d44340b, 0xed086e64, 0xd411bff3, + 0xc08503e4, 0x032a0396, 0xd221159c, 0x6f7d68ed, 0x895a623a, 0x0909a5bb, 0xbee06f06, 0xb690e2fc, 0xdbd5cebc, + 0x265deef0, 0x6f2bf00f, 0xacef4f16, 0x09f65401, 0x1aadd1d7, 0x53ae0c18, 0xde0b4424, 0x936b315e, 0x712cb052, + 0xef49abac, 0xa3f4b791, 0xadbf41e5, 0xfaa53a83, 0x15f0595d, 0xd9e2cbb5, 0x6db0d781, 0x08a045f5, 0x34d4343f, + 0xe01bb483, 0x4a069213, 0xf5fbc43e, 0x23769f5e, 0xb305d49f, 0x4afef682, 0x3e557f40, 0xc8f8b987, 0xbe8d4db9, + 0x39704de6, 0x08cacb6d, 0x97c3c23a, 0xfab89da9, 0xe5dffd65, 0x5d11ab26, 0x5985d8b0, 0x8b6f15cd, 0x3731a369, + 0x9e616045, 0xbb07df01, 0x7d63bf86, 0xe457c930, 0x8f322cf0, 0xad0245b8, 0x5ff2b4dd, 0xc61bbdfd, 0x6242de03, + 0xe5b42446, 0xe03362fa, 0x7847fb04, 0x5afb1e6d, 0x0a072803, 0x0d48fc22, 0xa63c500f, 0x6fb7c6c8, 0x539ac025, + 0x55bdd19f, 0xb9b74278, 0x2e29de06, 0x9e71e2c2, 0x3619ca29, 0x8590bc96, 0xa7de08fe, 0x2b6f54cb, 0x34504373, + 0xe5ac41d7, 0x764b6ea5, 0x0418a0dd, 0x886cfe9a, 0xad5e90c5, 0xa87ae68a, 0xfaea2295, 0x70bda1ae, 0x24b9d102, + 0xa05d8bfc, 0x67c23eca, 0x1f9aee2e, 0xb6360e7f, 0x2676e750, 0x62fc7ced, 0xed7e3ed7, 0x61b5e969, 0xa6643ef2, + 0x13f78cec, 0x55d5c9e3, 0x7d0e1837, 0xd73509ce, 0x9ef54531, 0x53c616e0, 0x8debd429, 0x2de3ea22, 0xc498e68e, + 0x7287080e, 0x9aeac5da, 0x6edd1a1e, 0x1d6ec11b, 0x6314a901, 0xaaa84229, 0xb134b896, 0xc9d9f8d9, 0x8ff53af4, + 0xc8bc481b, 0x13ec8911, 0x4236d4eb, 0x975e841d, 0x531f9933, 0xad8706a6, 0x219544fb, 0x1c8dee20, 0x933c2bab, + 0x181b672e, 0xf9720f21, 0xbbe02e5b, 0xf28d5c07, 0x75c60f36, 0x756f764b, 0xb3c19956, 0xa48053d2, 0x14c8d0a9, + 0x3f541528, 0xe08a771e, 0xaa208bd3, 0x48aafb11, 0xb5a34887, 0xed4968af, 0xaf4a2979, 0x6d12f3d2, 0x7bf15781, + 0x3d861eb2, 0xc8d093b5, 0xd4af20f4, 0x8f8bec35, 0x61b78976, 0x6bd7c5e8, 0x1ecf4478, 0x89f76893, 0xdd7fc4f6, + 0x9575c902, 0x353cbd32, 0x122f2f2c, 0x12799078, 0xe115b5b6, 0x300ba238, 0x9641654f, 0x269c8c41, 0x1ba8dfaf, + 0xb58b6115, 0xccf81b09, 0xc484018e, 0x53e7f876, 0x33cb516d, 0xa598cd85, 0x96ff6cef, 0x6a01be51, 0x7e6da28e, + 0xec588f84, 0x50a23131, 0x4705dbea, 0xe4130e37, 0x844f43c1, 0x94a5d756, 0xb28a947b, 0x46b9b710, 0x812b8c04, + 0x08665e95, 0x0bbe6687, 0x3f5db4a7, 0x0d9d6564, 0xb2cd24fe, 0x435c572e, 0x738a8784, 0x734885a8, 0x7ea18bd1, + 0x76536b62, 0xf0b48e79, 0x60e8a486, 0x3a97dac8, 0xc8115663, 0x549d5228, 0x93664af2, 0x4170d3a6, 0x51cc64a3, + 0x47e50f43, 0xfd089994, 0xa7bf3669, 0x27c86218, 0xa2247c34, 0xcb0d4c98, 0xb942ea24, 0x7dafaf03, 0x39c8b291, + 0xa4dae21e, 0xeaff9c6c, 0x9fbe9c1e, 0x5beed636, 0x458721c7, 0x7897d79a, 0x8997ede2, 0x23408af9, 0xa16a6a89, + 0xf0d8d1fc, 0x88e265c8, 0xac9199f1, 0x51a39e4b, 0xe4445e46, 0xec2efde1, 0xd7d72398, 0xed2268b9, 0xbf073032, + 0xb7a5df43, 0x2bfcd0cb, 0x9b0125be, 0x71f9f9c9, 0xcc8182f9, 0xc8df86f3, 0x602761aa, 0x90657a06, 0x6ebd28ae, + 0xafaf29c9, 0xe34694ba, 0x61b2e8c5, 0xce4e7924, 0x657e0afd, 0x763e45fc, 0xc919161d, 0x7901c017, 0x9c411a6e, + 0x4f992658, 0x8dbac46a, 0x6aeec55e, 0x890995f8, 0x6dbf896e, 0xef063d70, 0x6e43a93e, 0x463ccd4b, 0x930b8bf5, + 0xbd0c9edb, 0x1a4f00f2, 0xdad07157, 0x4a53d6f2, 0x4507bdeb, 0x1d66ae55, 0x65cd467d, 0x4457ea6c, 0x7b63a40d, + 0xcc988b9a, 0xc92f1255, 0xb3620de4, 0x20af699c, 0x2d57af04, 0xb8cebe99, 0xca3386c4, 0xcb7064af, 0x250f7d6d, + 0x89daab04, 0x1fd4df63, 0x03cc955a, 0xe7b65b0b, 0x9f308231, 0xfdee35d5, 0x67952ae1, 0xef57ba35, 0x26debae3, + 0x278a27c4, 0xaedad107, 0x029afec4, 0x06be2547, 0x03ccdd16, 0x4ae9edf4, 0x164dc66d, 0x72808858, 0x8266b490, + 0x6371d8da, 0xbbba9710, 0x3a2f8a5e, 0xb7226451, 0xec0e3241, 0x0c013c22, 0xb7635ba2, 0xdb206d85, 0x939de79f, + 0x7b6dd4c8, 0xda7ff402, 0x1a13e32d, 0x304084dc, 0x23b85ad0, 0x2c06c157, 0x1687aca6, 0x865b43ed, 0x7861b813, + 0xb846e388, 0x4ad13c16, 0xb35e3b7e, 0x932870f0, 0xcf4d8779, 0x9bbec694, 0x9544d55b, 0x32d4cfff, 0x151ead2b, + 0x81f3ddf6, 0x4b2f74df, 0xcced2f0a, 0x3ae10a3f, 0x24172442, 0x64b7d114, 0x3ec4d54e, 0xc5e4755f, 0x439b8713, + 0xeb061e09, 0x7a125e49, 0x5df86019, 0x8ff08119, 0x8ebed408, 0x14ff71aa, 0x5424b7b5, 0xa7b754a5, 0x7036b5bd, + 0x75762122, 0x7f42117e, 0x2615c731, 0x4312c4bb, 0xdecee840, 0xedb3e8c9, 0xc3002ec4, 0xac55da69, 0xbd0cf99e, + 0x3e6601cb, 0x47a1a5a2, 0x3576086c, 0x8c625563, 0x06f203b1, 0x314c44c5, 0x9376844d, 0xa30e3fc8, 0xb7607bb6, + 0x2770d2f0, 0x2ed305f8, 0x9c508944, 0x2d28428b, 0xf5791986, 0x0bea0854, 0xe87682a7, 0x8dcdd57b, 0x3c5f7f62, + 0xe2c34ed9, 0x88b943bd, 0x3c526f89, 0xe0a81f06, 0xee7ea8e1, 0x92cfbd53, 0x95106aa8, 0x8d90cd5b, 0x1ba728f1, + 0x9bc67c35, 0x2899f904, 0xa6c6e5e1, 0x226bc9c3, 0x65abe7b1, 0xdce035f6, 0xd2b61238, 0x02e6e2cf, 0x54c12fec, + 0xc161dbf5, 0x859f2828, 0x8c5b9e79, 0xa5df359d, 0xef3f1b55, 0xf8d268d0, 0x7d95c48a, 0xb830f34a, 0xccac243b, + 0x077e7db4, 0x7337f267, 0xffad979b, 0xcf02dbb1, 0x47df9fcd, 0x7463edc0, 0x1709b4a4, 0x133ae09e, 0x18814e26, + 0xda936a79, 0x1c8ebcf2, 0x62817a87, 0xcddbaab2, 0x9bda2a82, 0xbfb6cd6e, 0x9fa115e6, 0x962464f9, 0xeab20517, + 0x9afbcac0, 0x9a3a3d63, 0xfc4353c6, 0x146c20e4, 0x8c077d7d, 0xda9010c3, 0xd0c019d5, 0x90389132, 0xd302a79c, + 0x9cd86849, 0x7c1dcb97, 0xa3c7f285, 0xc08b956d, 0x071dae19, 0x98c219da, 0x8f390315, 0xb646c1fc, 0x868b6c62, + 0x55ac5af1, 0x7cf83310, 0xd20483db, 0x96d87f7b, 0x1fce67a7, 0x1c1a1047, 0xd88e0c66, 0xbd1c41a0, 0x52f19184, + 0xcc52d74c, 0xbaaad1b7, 0x3b6a80b9, 0x8d9e2df3, 0x430b51d0, 0xcc687781, 0xc5ca82e5, 0xa42c7fc6, 0xc2f54339, + 0x28290fc9, 0x8d336d6e, 0xb6d9870c, 0xe855c5e3, 0xb9833e86, 0xf2b92f79, 0xf6471c7a, 0x33d180c4, 0x0905c92e, + 0xb2717f66, 0x3ef96242, 0xe260069e, 0xc8dcaca2, 0x8d93c38a, 0x065984d1, 0x8d4b8cd2, 0x71796a14, 0xa0a27951, + 0xb75c9090, 0xdf711621, 0xe35f81fa, 0xd2b3e4fa, 0x3a0c98e3, 0x0137e6ee, 0x62b63d61, 0xc45ac451, 0x3e477607, + 0xf1aedf18, 0x71141b4b, 0x9a3423c2, 0x0d12214b, 0xf20b8ea7, 0x5c3acde1, 0x912d82b8, 0xcf25a406, 0xfed72e8f, + 0xdf34f620, 0x3bb37f5e, 0xc0d4c85f, 0x22da59d9, 0xed835c03, 0x2215e8ba, 0x4269e829, 0x734232b0, 0xd812550d, + 0xe5fdef06, 0x3adc21a2, 0x03061a83, 0xe0d6b05f, 0x6a50fa60, 0x44aebdca, 0x6a90c92e, 0xea62fbef, 0xa5a19b7e, + 0x53b661d2, 0x2b72b7d5, 0x33217196, 0x76836928, 0x7be63aa0, 0x0f32c773, 0xc868ba8c, 0x02f3820d, 0x8e597e57, + 0x3176f661, 0x9cf5da78, 0xacc37217, 0x1ee68b5c, 0xab67e331, 0xcaa6630b, 0xf0370aac, 0xe91fc5cb, 0x310772de, + 0x631a911c, 0xa8edcaf1, 0xbdfdca5b, 0xe1b183d0, 0x522cdb46, 0xba6f3bca, 0x43d88a3a, 0xae8c81ad, 0x9e747a46, + 0x8d7a6c19, 0x90b234be, 0x62d34c63, 0x46c5166a, 0x39e2f1f8, 0xef97420c, 0xa6ebb2dd, 0x9288a17c, 0xb72f690f, + 0x4e841141, 0xc1445f84, 0x4b9a5daf, 0x2fd649cc, 0x66cf10ec, 0x995d5f95, 0x8c432bca, 0xcb0f1e0f, 0x99f04a1b, + 0x5cf2a0d0, 0x6993d144, 0x661f1e8f, 0x00e76b6a, 0x5dc38c0f, 0x7a17eb6d, 0x1998abeb, 0xd390a265, 0x101fe557, + 0xc371a6f9, 0x1e709856, 0xffabf7fe, 0xa3a9973f, 0x9c2ff899, 0xd8fcbc58, 0x79f04a2c, 0x2d54529f, 0xd5bc8517, + 0x0aa0a55f, 0x81bc1318, 0xf4e78334, 0xdc842b6e, 0x481c2b2d, 0x3cbea61c, 0xc4f8a9e8, 0x7dcabc71, 0x2e0e55d9, + 0xe573c5b4, 0xe1497518, 0x0dc84dcc, 0xe4f638f5, 0x36daa4ec, 0x744f9ff2, 0x50399ac8, 0xe662c96b, 0x0d4277e6, + 0xb0aa3558, 0x946ac393, 0xe17956b9, 0xecae1d0c, 0x391bea36, 0xe4c13366, 0xe348641a, 0x8daca675, 0x8e332d8e, + 0xd4bd9f85, 0xeaa71224, 0x8a3900ff, 0x30c61fe0, 0x4895d297, 0x27affdca, 0xc20c585a, 0x4303af42, 0x927acc3b, + 0x67376595, 0xa084f3be, 0x012907c4, 0x6f9a6af7, 0xc6633020, 0x1e2bc30b, 0xa63a1196, 0x42fd5522, 0xae73ff91, + 0x8755dbef, 0x4d8ac1dd, 0xf597c119, 0x27dfc56a, 0x0fb9fd18, 0xbac68ef1, 0xd6afed34, 0xa1b3cd74, 0x6fb33ab0, + 0x5c72454b, 0x5b8405b7, 0xafbcd4ec, 0x3a2e13b5, 0xa62a1f85, 0x98364004, 0x42924ed2, 0x5d7408f3, 0x772904c1, + 0x6fbcd820, 0xc3e94414, 0x1bdef62e, 0x6b245e4d, 0xfd559621, 0x3bbbdfa5, 0xaa256463, 0x6647ad25, 0x32486223, + 0x2ca43110, 0x3c42f050, 0x47bbcf2c, 0xb57b58cf, 0xed935219, 0x938ce832, 0x6eceb9ed, 0xecab65fc, 0x97089e33, + 0xd969c2d0, 0x50a6e5c6, 0xb1a71397, 0x8dd5c98c, 0xd7e52947, 0xa11fb664, 0x99970615, 0xfd2bee29, 0xf7a61839, + 0x46499e62, 0xa4399d84, 0x0b381a1f, 0xba020db1, 0x3c785925, 0xfaf8c847, 0x541c0e12, 0x805d14e2, 0xe1850c30, + 0xe08f66bd, 0x8ce1bd61, 0x6cad310c, 0x682fcc5c, 0x085cc6f6, 0xaaae460b, 0x2c514000, 0x59d01f17, 0x2ac9a26c, + 0x5a55aa76, 0x4f4733ef, 0x47fef406, 0x41aee863, 0xe75f6460, 0xb5a56e9f, 0x8f4053cb, 0x9ad2c925, 0x98ac87b9, + 0xf0515544, 0x6a9dcc32, 0x7586c933, 0x78211f03, 0xd1a314f4, 0x502a63c1, 0xbec4c465, 0xba90179f, 0xada6268b, + 0x609c949c, 0x6c8a3427, 0xef0e1720, 0x41083b9b, 0x8f3da87a, 0x32154fd2, 0x0f1b1377, 0xce945662, 0x1a5406ef, + 0xcc26381f, 0x174371fe, 0x3d3dd5d6, 0x53ca96e9, 0xc5c50797, 0xd3b387f3, 0xe3d743dc, 0xce7ceb6d, 0x08c27668, + 0x04879d01, 0x460ae430, 0xb8cba93f, 0x3ec26cf3, 0x93c36450, 0x3e72f2c6, 0x71d57414, 0x21997e1b, 0xa08e2d17, + 0xcb4a439e, 0x3c705d2d, 0x3decb54a, 0x0374c52f, 0xbd2843d0, 0x2f176563, 0xce9069c2, 0x38399d82, 0x322adbd6, + 0x69d4b869, 0x29e62ca4, 0x7e7546f2, 0x55d9e41a, 0x9a19b073, 0x9395d32d, 0xaa711c2d, 0xfeee413e, 0xeaa8837f, + 0xa2a5f124, 0x76f65a42, 0x8f408ecf, 0x4ee995a0, 0xd50e0c2b, 0xb5d1912c, 0xa7546e5b, 0x68a35392, 0x590892ce, + 0xe7366e53, 0x8bbe0891, 0x98ef078d, 0x13d0d191, 0x65beb278, 0xf3670a91, 0x2c79024e, 0x136d4540, 0xf8245491, + 0xb948f4ba, 0x30f899e9, 0x5728c3e7, 0x7ef7d995, 0x30f77053, 0x0558febc, 0x242508fe, 0x99cf48fd, 0x66eaa7c7, + 0xedfa9de6, 0x7e0f5c18, 0x5d771121, 0xf5b82db7, 0xa0e429d7, 0x70cd4549, 0x0f3cbef2, 0x69bf8f0d, 0xf47dbf57, + 0x0ca3b928, 0xdc560291, 0xf93603c0, 0x93c6efc3, 0xa160327b, 0x500a3212, 0xca026269, 0x2baf86d7, 0x57373a10, + 0x43347c1a, 0xcc8f56ff, 0xf25f5b6b, 0x8593adae, 0x66dc339d, 0xc774fb14, 0xe5adced6, 0x287bda99, 0x0daaca38, + 0xe68cabe0, 0x379669af, 0x7d7e3878, 0x644a6fd8, 0x30d4c6d3, 0x0330d2a7, 0x60d6389c, 0xabaa502f, 0xa9a9a9e6, + 0x332d8753, 0x9d1eca94, 0xae9193f4, 0xde8cb580, 0x8908e402, 0xe51ffb64, 0x999c63b3, 0xfd617497, 0x05d4adb8, + 0xf9e9031f, 0x0f96d9b1, 0x1efedd55, 0x3539e07d, 0x02ca7918, 0x70bf53af, 0x55c1ea4a, 0xebbd6c23, 0xb0e7c56c, + 0x02407354, 0xd59fae07, 0x9a0e7707, 0x9faee3a4, 0xa9a04740, 0x398df47b, 0x458b95d6, 0xba7d39c7, 0x69b21e3d, + 0x7bd6b6a1, 0xba9ed5c1, 0x3de36cf2, 0x270da498, 0x362c08fc, 0x5e93cb4b, 0x1b874657, 0x54af067d, 0x80cf8b84, + 0x07b3f079, 0x8b78f266, 0x8060fb46, 0xd7138fc1, 0x3dcb1225, 0x74276fe1, 0x35c7ee86, 0x48a58acf, 0x9d4b83ce, + 0x95a15bfd, 0x0d70463d, 0x8daf6d69, 0xaccf4cb0, 0xac6524d4, 0xf01d5696, 0xfef5ad3b, 0x67b3f590, 0x527ca541, + 0xd7154d88, 0xb317fda7, 0x144e5da6, 0xeb9d8888, 0x0b87d22d, 0xa5a25056, 0x550f41e1, 0x13f14b96, 0xdadfd378, + 0xb461c309, 0xce54ef09, 0x628bdf09, 0x1a9fce69, 0x0e31aeb2, 0xa8e6ddd5, 0x9dffea7b, 0x67f2503d, 0xf0998fd3, + 0x53334557, 0x766875ad, 0xf6c524f3, 0x100418c6, 0x80c9fec8, 0xb89acab6, 0x6dd3b788, 0x63e733c5, 0x3873c22f, + 0xa9e3453a, 0x2593fb95, 0x35434968, 0x078da9a4, 0x777320c1, 0xa8f666d8, 0x89cdf324, 0xa0ff45e0, 0x5f2ff9cf, + 0x1669d4e0, 0xaac4d8f8, 0xf9c4427d, 0x925bb311, 0xd125e6db, 0x61077e1b, 0xce1a8041, 0xf42b2418, 0x19819557, + 0x67ca9f2e, 0xdc7efcee, 0x5fafee2b, 0x30e38299, 0x68b11bc4, 0xc87c629a, 0x7cfa493d, 0x2f92c9b8, 0x41874919, + 0x3c5daf5a, 0x321ae89e, 0x35ffd898, 0x5737a9d1, 0xb7e5a503, 0x584a71f3, 0x00f5efe4, 0x7a6856c5, 0x243a8b26, + 0x7e38efe7, 0x8f4cd2c8, 0x5d5c4dc0, 0x49eb0096, 0x717d2e06, 0x0f94759c, 0xc76b5fcb, 0x5e87c011, 0x65b39b41, + 0xbbe46cee, 0x10e6bd8e, 0x36cc3c7c, 0x0edf2409, 0xdfc45c97, 0x7f864545, 0x83531e05, 0x9dcda3d5, 0xfd139fb9, + 0xdba826de, 0xff22c1a3, 0x19037270, 0x3992d5d2, 0x88d0f8bf, 0xdb122b56, 0x0b3dfbfa, 0xc4f12a82, 0x6ab6213d, + 0xdcc4a566, 0x53211da4, 0x8d77d985, 0xd22fab5e, 0x0f795422, 0x3b23a060, 0xebb827f8, 0xb7741643, 0x69b44698, + 0x61ac5fa1, 0x63fc078f, 0xcda4ef6e, 0x6e36ec63, 0x5d978c8c, 0xc5b4aebf, 0xc978b1b0, 0x5b324351, 0x77c96f8e, + 0x890f275e, 0x3bfc5cd8, 0xf34b64df, 0x79e4e6df, 0xc515c0e6, 0xd3f87c5b, 0xadbd2a2c, 0xfca4f093, 0xba468fd8, + 0x793049f2, 0x0b2b3f36, 0x55e5064a, 0x5e6d414e, 0x571258e9, 0x2e8c19ba, 0xeccae93f, 0x70c7da5a, 0x323c636e, + 0xa392dc4c, 0xe1502de0, 0xa659424e, 0x075f3a8c, 0x079bfbab, 0xd139f9ee, 0xc9a3f3a4, 0x3ef73e49, 0x65f8882a, + 0x5c11b2e9, 0xd3c4a12c, 0x7182b037, 0xa9b045db, 0xf3d41e88, 0xfd646014, 0xce405494, 0x14a1c02c, 0x57f9706e, + 0xfe4cdd78, 0xdb1a56df, 0x8ba2dad3, 0xf87a02c3, 0xf1602e0d, 0xa6da06bf, 0x68b73af0, 0x07edfea1, 0x54ac362e, + 0x0b7fa743, 0x201bc12f, 0xa0ef68fe, 0xffd595fb, 0xc39a7b80, 0xe92dc372, 0xca2f3014, 0xce25d36a, 0x3bee1fad, + 0x433b899e, 0xbd03c34c, 0xaa20d8b8, 0xfa3cc39a, 0xaa186323, 0x045e2540, 0x8d51a03c, 0x89f1ebed, 0x926f12dc, + 0x6af80481, 0x2e5d4106, 0xda3cd6ac, 0x35aa0c22, 0xa2a9cd33, 0xbfb9f59d, 0xe5be7a26, 0xa89f9b56, 0xdb7d24c2, + 0x08e72259, 0xb8b587b4, 0x009952f1, 0x0c84cc70, 0x7543c48f, 0x005db3ac, 0x05bc0456, 0x5936869e, 0x6480184c, + 0x4294cffd, 0x6a13da09, 0xd0eac4a4, 0x472019c0, 0x1494d5c2, 0x6dfac15d, 0x77fb0907, 0x33ce55bf, 0x71bacd0d, + 0xcefd40ee, 0x5ae526fa, 0x7e41274c, 0x4bc718a7, 0x081247a9, 0xe6d4c22b, 0xa71410ec, 0x58b5060b, 0xc634d6ec, + 0x3415cdcf, 0x03d92ee6, 0xf8232ba0, 0xd7103111, 0x64521d81, 0xf211fe73, 0x59eddb7f, 0xba6c9a2b, 0x96745125, + 0x77f0e1e8, 0xea9511bd, 0x92cc0877, 0x81b9f02b, 0xc773ce5a, 0xde35c3ca, 0x312875c3, 0x4a644e84, 0x252a2ec9, + 0x8c68f47b, 0x01458907, 0xece5b212, 0x734c0e70, 0x58d790dd, 0xfee2af0c, 0xb83b5f7f, 0x5686bc3b, 0xa7cc4bc7, + 0xbb1d7b0a, 0x958443d6, 0x6640f243, 0x62199cff, 0x85675fba, 0xb7f57540, 0x71e34984, 0x0070d744, 0xc02eddd6, + 0x3801294e, 0x56f82390, 0xcf79ccce, 0xba804b2c, 0x67d04ffa, 0x4d0803ac, 0xc242923b, 0xd5b9ce87, 0x189f92ff, + 0xea7c501e, 0xe9424eac, 0x032aac5a, 0xf7e28b79, 0x2bcf9320, 0x41c117d3, 0xc9c5af5b, 0x611e333c, 0x58577ce9, + 0xed7ffd48, 0x65932ee0, 0xea38375b, 0xb62524cb, 0xa25b2a9e, 0xbcbcb236, 0x2829739f, 0xa726279b, 0x3a2a7cbb, + 0xf1f88c4a, 0x56a64009, 0x7ff05aad, 0xc5abfdbf, 0xf3077f31, 0x897a4f06, 0xe92cb0b6, 0x42e9c786, 0x87e24ce9, + 0xb5543f1d, 0xbd252e8e, 0xb73517e3, 0x27b5dda4, 0xd117e2c8, 0x97a5c47a, 0xf7067bb8, 0x5aa55e69, 0xa7a78e9b, + 0x79be586b, 0x44eb3feb, 0xf3d241d5, 0x1c8d504a, 0x01517b07, 0xfe7bb97d, 0xf52d07de, 0x05bda0c8, 0xbd598dd4, + 0xf03f8006, 0x8c190fc3, 0x008f5d78, 0x2ec70ff0, 0x19654336, 0x61be7850, 0xe2468138, 0xba64722f, 0x8d2b10c8, + 0xe350a236, 0x283bffc5, 0x4f1aed79, 0x5a1beab9, 0x30befbbd, 0x76f3e0a9, 0xd61534d7, 0xcbe36646, 0xb18133de, + 0x98f9c740, 0x430faf4a, 0xfbb70b73, 0x22e48a81, 0x43e6b117, 0x25c243ec, 0x9bbcc190, 0x301a5d67, 0x31d9b732, + 0x01085dd0, 0xca552431, 0xeb4ecf90, 0xef6d2902, 0x63a0950c, 0x6ffdda48, 0x7ae9ba90, 0xa2cd32dd, 0x145cd7cf, + 0xc3890c9a, 0x90bce844, 0xd94e2c3b, 0x533b0551, 0x9884ca03, 0x9e13bff7, 0xc6714b8b, 0x27ed409a, 0x79525871, + 0x42fbdac1, 0xafeaa2c7, 0xe18b6932, 0x4f7d1848, 0x43b37157, 0x5d8af7b2, 0x12540d78, 0x42580dbb, 0x241fd38a, + 0xa7eb52be, 0x0ea95b6d, 0x180a1d48, 0xf1f71cd6, 0xa39eae8e, 0x3da412be, 0x399453f7, 0x7da7769c, 0x4fc32641, + 0xd0b72ece, 0x2a979f87, 0x183878fa, 0x9346bd51, 0x73c836cb, 0xa2817a46, 0xcb380df6, 0x6b37c4c4, 0x2c1e645d, + 0xd800a51f, 0xbabad700, 0xd0c7ef72, 0xba62c9d9, 0xb4def6f9, 0x596bbb6d, 0xeb95046a, 0x330ddf2a, 0x44cff86e, + 0x2b8a527f, 0x34414075, 0xc5770753, 0x04bf64ac, 0x27295346, 0xa493d709, 0x17cc179a, 0x9d25b924, 0x9862b7f3, + 0x503449e3, 0xe9363f9a, 0x44ca2b63, 0xc7578ccf, 0x64a27ac5, 0x84bd8fc5, 0x7d44f1cf, 0xe15e48fd, 0xc5b36a9e, + 0x4875d366, 0xb1633ead, 0x8111fc14, 0x7aacd415, 0x74b9af32, 0x1d011f48, 0x829e131d, 0xcb782946, 0xb71876b6, + 0x0b3659ce, 0xc59140db, 0x5b746547, 0xe4b6b46d, 0x01951b9f, 0xde2c23e4, 0xf6cb80fa, 0x424e7298, 0x66fee481, + 0x20cd804e, 0x86f9b360, 0x14099e53, 0x5081dc5b, 0x70b0bd0d, 0x5c1401c7, 0x6dc8868a, 0xd14e87ec, 0x6127347e, + 0xfe3bc4d8, 0x6bef8539, 0x7c3194c3, 0x223c894f, 0x6714f56a, 0x96ec4886, 0xc5acd0c0, 0xb2c96584, 0x343d7fa6, + 0x6ba99556, 0xcbb48bf2, 0xfc2c3485, 0x80800778, 0xeba7b9d3, 0x3a30afde, 0x465fa90e, 0x6714944a, 0x76baacdf, + 0x02db6595, 0x2fe3547f, 0x3729e399, 0x74ad8d35, 0xe3a4a4e0, 0xf7bd8637, 0x94186302, 0xcef60cd1, 0xd8b7726e, + 0xfad26c8f, 0x3902e352, 0x8ea8871e, 0xc36025cb, 0xf184381e, 0x52dc7ce1, 0xa38666f1, 0x505d087e, 0x603df3ca, + 0x2bdb04e7, 0x8b893469, 0xbe782803, 0x932ebe4b, 0x36522dab, 0xc4aa2ec9, 0x52b8a65d, 0x4c30f589, 0xac7a822b, + 0x40f2088e, 0x1cb45840, 0xe5ca6ceb, 0xf48505eb, 0x945a3b66, 0x3f1d898a, 0xa04c1ed2, 0xc0273a53, 0x30412cb8, + 0x3d859e0f, 0xc226c7b0, 0x4311c779, 0xc33fc307, 0x6aaca797, 0x2df26dfc, 0xb4f11d81, 0xd350dab7, 0x6557c420, + 0x408cf507, 0x5a7a947b, 0x25c74896, 0x7c1df36e, 0x5984d0ee, 0xe536f4f4, 0x13eb0805, 0xa3a615e4, 0xdb411d92, + 0x8c4f5240, 0xb3fb0835, 0x81889744, 0x8b9d9def, 0xbf97acf7, 0xf493f3bd, 0xeb436ad7, 0x52e2d93f, 0x6d5dc7d2, + 0xc1d3136b, 0x3e239a15, 0x82b8c9f2, 0xee96fbd6, 0xc8a28b6a, 0x8ae80e6a, 0x481440ad, 0xa72e2ce6, 0x3c9b9a42, + 0xaa4e92a0, 0x7f5881d7, 0x59921f42, 0x88054d10, 0x2d22f63a, 0x6cf2fc6e, 0x3f289a63, 0x23e3c778, 0xa55309b9, + 0x7e1e80b7, 0xc14f8a9d, 0x6b93b377, 0x42102ef0, 0xe11ab68a, 0x4f5a44bc, 0xc0d303d2, 0x32c34126, 0x82e6f213, + 0x6ea3864a, 0x595c7a93, 0x9e6bed13, 0x87a7edc6, 0xa1a4c120, 0xcbf5e0f6, 0x14c6200d, 0x1bc1adec, 0xe3892e40, + 0x1e33ef6d, 0xe0b68e6f, 0x7d59c3a5, 0x42427f62, 0xa008c84e, 0x7e98291b, 0x4af91dc3, 0x73646ce8, 0x5eba2140, + 0xa9492bae, 0x8c977ffd, 0x45d2675f, 0x557bd37a, 0x2fcef0e9, 0xfb2a6782, 0x46ab030f, 0x609e9951, 0xc94ab1ec, + 0x303dc8d2, 0x02b26212, 0x68668e2c, 0xfadccb3d, 0xe697ec13, 0x587f1601, 0xdf797b6d, 0xf2f4b47e, 0xeb6f86f1, + 0xc8efaf00, 0xcb223019, 0xb2aa9844, 0xf715c5aa, 0x72370ce1, 0xbb739aa5, 0x590dcfd0, 0xd6ceb05f, 0xc35a02aa, + 0x60b742cc, 0xd47bb27d, 0x1dfac348, 0x68260cad, 0x38475e6f, 0xfd848892, 0x7d77d6d9, 0xe47d6217, 0x497765c3, + 0xdd9626ca, 0x98db9723, 0xe0a7bc61, 0x0a85edd3, 0xaf1cf078, 0xf583fdd1, 0x82a2332a, 0xc4cba90a, 0xcd39214c, + 0x725e7acb, 0xeb1f3e26, 0x8c4cf67d, 0x928b6b63, 0xd598001b, 0xc3f0a119, 0x58ad5da6, 0x75f463da, 0x588dfcee, + 0x295d78a2, 0xd7a2a6b5, 0x05f5a03c, 0xf79886a0, 0x76afdd47, 0x00a00138, 0xfe1774f5, 0xbc2fea14, 0x71480902, + 0x4f4fa2cb, 0x37983d13, 0x7f04fb43, 0x6f39745d, 0x23ee578b, 0x07dd1931, 0x64c5589d, 0xfeff2b8f, 0x09216836, + 0x420adb24, 0x0035d31e, 0x960df348, 0xf5f735ca, 0x4b12a919, 0xcd0040b7, 0xbdec818e, 0x2a271163, 0x5625fbb4, + 0xfedf55ca, 0x02110730, 0x58b8ea9b, 0x3bacbdc8, 0x1b16fb3a, 0x1857ce56, 0xf25f967f, 0x091accc4, 0xcd07de20, + 0x1a7ea4de, 0x609269bb, 0x7860286a, 0x6fb0e4e6, 0x7bbb4ebe, 0xdcd94aed, 0x88a9d6e4, 0x492127e8, 0x3117c592, + 0x8d0eba94, 0x46c6b2ae, 0x39510967, 0x9007f1e7, 0xb8a62f85, 0x01f438d6, 0x8090c0d2, 0x2bc62709, 0xbef651be, + 0x286a7d0f, 0xc09430b2, 0x8accaf11, 0xa9c37371, 0xb5949e5f, 0x0fcc3673, 0xc9380994, 0x0b4fbefb, 0x7d94b97f, + 0x7de2a330, 0xbf03ad13, 0xd74013a1, 0xc4f3b335, 0x1d52840d, 0x078f85fe, 0xa31e39ea, 0x5f3e907c, 0x60c8d9a7, + 0x1e277a26, 0x92602c70, 0x0b426392, 0x74d41e5d, 0x3627b418, 0x328d13b3, 0xb8432ed1, 0xe2d0806b, 0xeddaed1e, + 0x46a02c71, 0x29a321c5, 0x3cd7d6d3, 0x85eb09c9, 0x9a551c03, 0xc604c8a3, 0x6d7a8bb9, 0x83cf4754, 0x486339a8, + 0xb93b2323, 0xd98c5613, 0x9acbc531, 0xe66667bf, 0xbf54e54a, 0xdd75d492, 0x961e3775, 0xad9eafea, 0xd75dcd60, + 0xdd3f7db5, 0xf9a3b21b, 0xdec730b6, 0x0851f2d7, 0xd2e4fef7, 0x658504b5, 0xa6893bbf, 0x3bf3a5f5, 0xdf6e28fe, + 0xe16793b8, 0xe0bf5fa7, 0x57c8051c, 0xdc8c315f, 0x80d45439, 0x08a7a04f, 0x0122c8f4, 0xadde44af, 0x9aca2f84, + 0xa96af956, 0xf66aaa98, 0x87c82e86, 0xdc69b199, 0x5cee8cb5, 0xb2edb201, 0xff54fc91, 0xf3368031, 0xc0b39823, + 0x3c2675bd, 0xcf534c28, 0x44cdb9d6, 0xd892ea9b, 0x492724d7, 0x651ea225, 0xf9f72c77, 0x1daa5e90, 0x715408f7, + 0x2a69da36, 0x4a59619b, 0x01dcb4e0, 0x0601e096, 0x3488e54b, 0x75ee353d, 0x82b7ae78, 0xc47d12ee, 0x529d06f8, + 0x92d07f88, 0x7f471b6e, 0x3bbeab7a, 0x39807db2, 0x94824e9d, 0xc9e94219, 0x7a3168a8, 0xab4313bc, 0x9afb8e29, + 0x2e95885e, 0x5d9daf0b, 0x76e5018c, 0x19d96bd7, 0xf751a9af, 0x38f5a1f1, 0x85631108, 0x02b0ae01, 0x244a913a, + 0x4dc6c8d3, 0xaa8eef4f, 0xb44c077f, 0x824a1b79, 0xe35888ac, 0x7d86534d, 0xe52cf404, 0x6fdd7abe, 0xbee2d249, + 0x76299fe3, 0x35e3a244, 0x2383a89f, 0x46c4aff1, 0x09cad952, 0xe72dede0, 0x67e924d1, 0x223eb1be, 0x65d754d4, + 0xb0234f76, 0xe8a649d1, 0x55a8af30, 0xd2426b91, 0x8f97117d, 0x3d0173ef, 0xd84e4dc4, 0xb1b3dd05, 0x6fb4e710, + 0xad02ba62, 0x3ca1b057, 0x7018bbb3, 0xcf40c44d, 0xcbfb4410, 0x3ca5bbb5, 0xeee5651f, 0x0e161659, 0x0090cc4a, + 0xd351072f, 0xddad1cb8, 0xe8601d2e, 0xc05aa289, 0x5922ff92, 0xa6655b9b, 0x5fe4a1cd, 0x4aaeec06, 0x3131b354, + 0x41ae8051, 0x5e3eebda, 0x61bc03fc, 0xd42b009b, 0x6dde50c1, 0x678dd67b, 0x501627a0, 0x84921239, 0xd0d781d4, + 0x3ab98a50, 0xf29392a7, 0x5971cc93, 0xc6b5b8a4, 0xfb185003, 0x5b323513, 0x03196ec7, 0x45623f7d, 0x2b37ab87, + 0x2debf459, 0x2977860b, 0x46cbdb58, 0x5ce8cc8c, 0xaec790c8, 0x736f312e, 0x0a63aecf, 0x9e33da67, 0x3b9ff724, + 0x6f915be4, 0xcb734fce, 0xf1543239, 0xfd18d1b9, 0xf7162e81, 0xb3a90c76, 0xad917a9e, 0x1562501e, 0x5a9f9c5d, + 0x3104f1b7, 0x019cddbb, 0x8c287d17, 0xad617f99, 0xfa88b38e, 0x8b6c609d, 0x56c40754, 0xfa10401e, 0x85a69a6c, + 0x60392124, 0xc02ef463, 0x78c2416c, 0xa73f384c, 0x58dc6105, 0xf26a22d2, 0xb05b6619, 0x15cd1ff9, 0x03096d0e, + 0x3195c0ce, 0x89a0d56a, 0x4c4d269b, 0xdfc82745, 0x918b8495, 0xecc84bbe, 0x905d547c, 0xa2ed6362, 0xc2cee5ed, + 0x30216b6d, 0xd18e5124, 0xf4c6ab8b, 0xa9a327a5, 0xaca23b9e, 0x29fbd7ee, 0x175764da, 0x86efc26c, 0x825de26c, + 0x1c4fe78d, 0x283ce248, 0x4ac10c0c, 0x50bbf3fb, 0x029f6275, 0xe4fa99bf, 0x03e447f9, 0xb58fe8c4, 0xd3ff4b84, + 0x62ceb07a, 0x154821ec, 0x57acf840, 0x820ebc15, 0xdc3634b3, 0x5ded71c6, 0x50b7c917, 0xf45c8e44, 0xfa3d34f6, + 0xac3f72ec, 0x8cddaeba, 0x9fd76792, 0xe8f631cf, 0xec652ab1, 0x4f77b310, 0x8731f203, 0x9b1ca4d4, 0x66bc06b6, + 0xd7bf2a9f, 0xe85e9a7a, 0x3c4b23d9, 0x500c633c, 0xae4c3699, 0xcf603f66, 0x5516d253, 0xce9cb03d, 0x4e4e94ad, + 0x9a6c97c8, 0xf64195a2, 0x4654bfaa, 0xfafcb9b6, 0x19d8950e, 0x5b1e76db, 0xbd65ed3c, 0x9a7c9495, 0x6ae08520, + 0xc5e76655, 0xb8283a1b, 0xa99506f4, 0x9bad69ac, 0x88bd2344, 0xec8462d7, 0x2138c82b, 0xe481c196, 0xfd3f41cf, + 0xe94bae66, 0x5bcb5b13, 0x2898f120, 0x53bfc982, 0x08f986e4, 0xae207148, 0xc22bfc08, 0x8a5020ce, 0x9b58ea3e, + 0x6f72422e, 0xbbe61f89, 0x858581f6, 0xc7b1c6e9, 0x469fb2a8, 0xb4610534, 0x9d58f6fe, 0x26bf4649, 0xf315de28, + 0xcec0f753, 0xeab9d8cb, 0x080fef72, 0x3aeaa30b, 0x66d795c5, 0x4bfdeef1, 0xfc91af88, 0x39416dfd, 0x5bbf1404, + 0x42a017df, 0x68ed4aab, 0xe62ab313, 0x9e9225ef, 0x43f8c595, 0x23287a84, 0xa2eb5953, 0xb8127b33, 0xe77a570a, + 0xa44386f7, 0x29d11f1e, 0x9c790194, 0x3b591abd, 0xca34f643, 0x6d19bba4, 0x375d77f1, 0x0b251032, 0x1b9cad58, + 0x07f75a65, 0xe350bde0, 0x330d51db, 0x9ac02a7a, 0x93850dc4, 0x1c4e38c4, 0x4df16ab4, 0x4d0539b4, 0xbcd073a7, + 0xdedb7462, 0x9a1735f2, 0x3a270ddf, 0x6e84f448, 0xd43ff76b, 0x6c223839, 0xc0146552, 0xc26d2da5, 0x391cd6b5, + 0x366b271f, 0x5c7f49fa, 0x1535d991, 0x7b99ed3f, 0x1268bf4a, 0x8feb08f2, 0xb3147781, 0x73eef8ec, 0x9a3baa11, + 0x471b3d3e, 0x28e15300, 0x2cd29643, 0x7869b033, 0x8ee2e423, 0xeba17e0d, 0x1147e107, 0x10cd31dd, 0xf62b8269, + 0x770ed913, 0x37c9e6bd, 0x71d5a928, 0x534e3ef1, 0xac6f4f8e, 0x12e4986c, 0x0e980054, 0xd82a7b68, 0xa8b65319, + 0x0d789d69, 0x04ee8210, 0x5240cec3, 0x44cdf9eb, 0x3e9be0fc, 0x5b4a29f9, 0x63feb3f8, 0x9cfb2a6d, 0x8511a2af, + 0xa70f0dda, 0x3874ca42, 0x8c1e33ec, 0x5c198862, 0x5d3d2126, 0xca76ab0f, 0x4bcf0901, 0x34634fed, 0x5f2f50d0, + 0x0a62a4c8, 0xfa3f8f9a, 0x6838c4fa, 0x45bcf291, 0x33420971, 0x3b19032f, 0x5a78ab1b, 0x8a2a2d9c, 0xf6e42092, + 0xe932953d, 0x21440e30, 0xc80d9ac9, 0xf4e21c8b, 0x2e304404, 0xb0d8a528, 0x502ec2e0, 0xae02393c, 0x1a7f6fd3, + 0x284f7eae, 0x472e20b4, 0x566fd29b, 0x266e4ffb, 0x094113e4, 0xf89aa4fb, 0x4831b50b, 0xb10d2943, 0xdaaef780, + 0xbc6bddac, 0xb10a66e1, 0x1b4323d0, 0x4709e2e1, 0xb1c94599, 0x7602fe88, 0x6828bd9f, 0x9fe233f5, 0xe500a509, + 0xa3d5179b, 0x6781be15, 0x198b1ac4, 0xbb8d607b, 0x59c3b2c9, 0x640974e5, 0x1bec4641, 0x57bfbe8a, 0xb8ee6496, + 0xa70dc9fd, 0x2d2ef7fe, 0xc8f33ebb, 0x7354232d, 0xb499006a, 0x4753f8cf, 0xbf47144a, 0x15b0f955, 0x08c4d36b, + 0x8f24c18d, 0x86c613b7, 0xee941bc9, 0xe5a4e391, 0x4c14ca0e, 0x5760ddf4, 0xb79cf32b, 0xd3815126, 0xe07e1924, + 0xd7d8b2f7, 0xa607b6b8, 0x8644e7bc, 0xa2df704e, 0x12ef3958, 0xc6fdab8b, 0xeae25855, 0xa19cd609, 0x514b1c09, + 0x51f9fd39, 0xbc71de26, 0xc7be4c41, 0x99a05417, 0xbe634f4a, 0x615edc1b, 0x89f5df75, 0xd933cc15, 0xeda34c06, + 0xf83f96b8, 0x3a28e253, 0xd4d65669, 0x599587c6, 0xdb59fc44, 0xf610a652, 0x5ca01eba, 0x12c68171, 0x504165ce, + 0x1034ca59, 0x69a94ef8, 0xe810b073, 0x3d832886, 0x516e34aa, 0xd729fa0a, 0xe22f63aa, 0xae8bcb90, 0xf4965962, + 0x1750148f, 0x649c4ff7, 0x4417a2ae, 0x574d8c5d, 0xee6368e4, 0x251f2f44, 0x77e9bb1d, 0x4801f2b1, 0x077c927c, + 0x77bda395, 0xb08a6b4c, 0x6c52e0ca, 0x60e769d9, 0xf619855e, 0x7c7652a6, 0xc47a2d6e, 0xf04f973a, 0x9f572aad, + 0xedc49347, 0x8eeea5fa, 0xcfc7b7d5, 0x18d29c3d, 0xfdfdf3c9, 0xd209381c, 0xddfc4ee5, 0x1585dfe1, 0x2859f52c, + 0xd70869fd, 0xd6d6a175, 0xdfe4dec4, 0x0a21b1b5, 0xcfae9b8d, 0x921eb7ad, 0xc9020997, 0x73b44e46, 0xa3bce24a, + 0x3bbbb9b8, 0x4ea918e2, 0x16288893, 0xec331eaa, 0x3ddeea11, 0x6b22a45a, 0x178f2200, 0x543fbbbb, 0x90c223ba, + 0xc167a255, 0x968b52c7, 0x237b45f4, 0x39c9679a, 0x12d07be7, 0xcff443f2, 0x3de08c70, 0xf9eb46bf, 0xecd3696f, + 0xccdd0312, 0x510fd99c, 0x7b075ce5, 0xf2d5972c, 0x13b1a565, 0x647f4407, 0x3dda1c52, 0x0db195b0, 0x2b2f8eff, + 0xfa137377, 0x6caedd85, 0x8fe097e1, 0x10ac8564, 0x72981d2a, 0x08801390, 0x0e3f1ef3, 0x7108f544, 0x6633d426, + 0xc4bd651b, 0x7d06da4d, 0xbc1d9a63, 0x90a067d5, 0x9a7df559, 0x1d0a11b7, 0x1e5da7f3, 0x29fc2c9b, 0xaf70f7dc, + 0xe41b41fd, 0xab9624c3, 0x5d75b435, 0x002621ae, 0x7a9b9919, 0xa33b4861, 0x27d3f2cc, 0x9dd5a907, 0x065640c3, + 0x07086a7c, 0x6ad3c7e8, 0xda61d0fd, 0x997065cc, 0x7ef2b121, 0xeb787574, 0x4d335fd6, 0x32924acd, 0x7a9b34e4, + 0xb141aab8, 0x142c608c, 0x6da52db7, 0x38f48141, 0x3e8c6aa0, 0xb8096c4f, 0x7b861d61, 0xa60fd6b3, 0xc64e4612, + 0x0df0efb5, 0x82a2098c, 0xf58f70cf, 0x090f9316, 0x7adc0c57, 0x89c80d7a, 0x98379e82, 0x07627449, 0xba249bde, + 0xe4071277, 0x335b6e37, 0x10197c05, 0x9806fcf3, 0xd419c50c, 0xa924d154, 0x686a0968, 0x1d4b2dce, 0x5f21ba32, + 0x22a288ce, 0xd46494a9, 0xcacd96f7, 0xd4fb0ef8, 0xb52990ff, 0x4328b4a4, 0xd53e43d5, 0xe17e01ab, 0x22c5f729, + 0xee0e806e, 0xaea91ce4, 0xc9368cf1, 0x3298a441, 0xada607d5, 0x0ce64ea4, 0xb039ee8a, 0xc624916d, 0xce3cb963, + 0x6a21afd7, 0x8bf96410, 0x4618d43b, 0x7def1c9e, 0xcbec3e7e, 0x2fd1e025, 0x87d93d6b, 0x0ff5f5d8, 0x7c21d0d1, + 0xf5ec1657, 0xf4c2190b, 0x2eb3b608, 0x08745f07, 0x6ebf3462, 0xe421705c, 0xe86372f3, 0x49adf1da, 0x5aecc162, + 0x671d0028, 0x1ebbda45, 0xd6d010cc, 0xf5395b97, 0x21df6419, 0x2d4b3d3a, 0x6ad03908, 0x81931219, 0xff65858c, + 0x8e78697d, 0xa9ff5ca6, 0xf2e609c5, 0xccf21be7, 0x83966dfd, 0x8a3cc868, 0x39233e2a, 0xc8902098, 0x69c98dca, + 0xe3ef8e7c, 0xa163b614, 0x14d2a62a, 0xc2c5c281, 0x6cc9b9d8, 0x1062064c, 0x6040cfcc, 0xf92fc8f3, 0xb802811e, + 0xdf2af1db, 0xe8e6f840, 0x1f4ca9cf, 0x6ba56df1, 0xd0ca8462, 0xe37139a6, 0x2fa37f0e, 0x522fb55f, 0xf73269ef, + 0x0a3d8ca8, 0xf16a0a01, 0x1802107c, 0xb4439056, 0x4b0a451d, 0x89ea2c4c, 0xa129618b, 0xceebbdb8, 0x4538462f, + 0x0f0245f3, 0xba48bd00, 0xc35b8aec, 0x87486b26, 0x046413a7, 0x82f0e45f, 0x030c82f6, 0xc8863f3b, 0x5e477d1d, + 0x9c146856, 0x13e2206d, 0x13bf11d4, 0x2be3908f, 0x7a4a1945, 0x1ac7ca96, 0x0c83535e, 0x7390f976, 0x2f2daefb, + 0xf0d7a92d, 0x9fb3f3c2, 0xe1c6de32, 0x834e151b, 0x69ae51f8, 0x4ced1563, 0xec6fb8a2, 0xff68a14c, 0xdc0bf8fb, + 0x01e1bd7b, 0xbc687394, 0x40c2f545, 0xe8af3002, 0xd37a3c35, 0xe7ab8da4, 0xd2096256, 0x838d60da, 0x5e44811f, + 0xe67a6484, 0x272eba23, 0x34568289, 0xe665c623, 0x28e32ebb, 0x380e31e2, 0xec66fa5f, 0x9326ce9d, 0x5d566645, + 0xe60c3eb5, 0x521e1756, 0x5480e735, 0x07b7f520, 0x344470f7, 0xbad01966, 0x435288a1, 0x1b8e3bd3, 0x840bfffc, + 0x06e4073f, 0x5ab23cde, 0xdb0482be, 0xf53e30d1, 0x51d5640e, 0xb5572dcb, 0xad565df8, 0xe60e26c9, 0x03368102, + 0x239bd1df, 0x80cff272, 0x9640352c, 0xa13d9d05, 0xf2e59975, 0x6eb89c1a, 0x081fc914, 0x5fd76af5, 0xb420cc67, + 0xd3941e78, 0x1ad61f76, 0x8fc02d0e, 0xece7be6e, 0x7e13393c, 0xeea6da04, 0xa4a3d76e, 0x3648ad17, 0x8aef288e, + 0xa1ce51e4, 0x64a93a93, 0xfd2f5089, 0x599bac3a, 0x8d3a0170, 0xf8b3cd30, 0x89ab7843, 0x1d3e5db8, 0x06cbb16a, + 0xd28952d2, 0xca284893, 0x8fd1a1e1, 0xecc8aa4d, 0x465de563, 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, + 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, + 0x9e794663, 0xecda4063, 0x4f3c615e, 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, + 0x5bee2390, 0x5bb0ac2d, 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, + 0xcbc03381, 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, 0x5e365ae5, + 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, 0x1da22f3d, 0xbde1988d, + 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, 0xc654b0f4, 0xb3c61edb, 0x34380acf, + 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, + 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, + 0x6ca12b76, 0xca9e521a, 0x3de6ed99, 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, + 0xe3860943, 0xf1f3f4e7, 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, + 0x401dd9b2, 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, 0x9c7c7cab, + 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, 0x68fd2cdb, 0x5b325dc5, + 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, 0xdfeceee9, 0xeff255fc, 0xfc97bd59, + 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, + 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, + 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, + 0x19026be2, 0x106a090e, 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, + 0xfd1119a3, 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, 0x2e43d2db, + 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, 0x24996054, 0xe5fd7518, + 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, 0x19490a6e, 0xbfcc1617, 0x967882fc, + 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, + 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, + 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, + 0x071ae0e6, 0xc3c8d053, 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, + 0x3678e185, 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, 0xb67c5819, + 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, 0xc2222ef2, 0x5a046246, + 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, 0x54a3bc82, 0x5706694c, 0x4664f6db, + 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, + 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, + 0xce8f27be, 0x5a559021, 0x9b1740dd, 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, + 0xe9952168, 0xdc81cac7, 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, + 0xb58b5c72, 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, 0xd99e6ac7, + 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, 0x3635a87c, 0xcee78062, + 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, + 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, + 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, + 0x384ad656, 0x9d824935, 0xec915f03, 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, + 0x4064fbb5, 0x66ad961a, 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, + 0xdbe24543, 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, 0xcadaf946, + 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, 0x628675d3, 0x6b1d569f, + 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, + 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, + 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, + 0x8d3c9334, 0xe5c6c529, 0x20e898db, 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, + 0x0d748033, 0xecc5393a, 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, + 0xf35661c3, 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, 0x5d2efdf7, + 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, 0x69c800e0, 0x5d310e80, + 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, 0xe9811969, 0xc08a7628, 0xe5e44555, + 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, + 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, + 0x80082d96, 0xb5a06d54, 0x1612537d, 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, + 0xf2fac0cc, 0x737aeb61, 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, + 0xaa36609d, 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, 0x0c2f32bc, + 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, 0x6a6777dd, 0xa7029cb3, + 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, 0x59ebc41f, 0x7e55932d, 0xcf78bead, + 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, + 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, + 0xc99944ec, 0x5289e5ff, 0xd64dd767, 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, + 0x4cf9307b, 0x1b6533fa, 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, + 0xe854ce92, 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, 0x408694a5, + 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, 0x24ed6723, 0x0c24fa00, + 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, 0x7db55eaf, 0x0fa8aabb, 0x0e942194, + 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, + 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, + 0x0350d608, 0x54e77f30, 0x866c2575, 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, + 0x3bf7c1bd, 0x5762abb7, 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, + 0xa9a36bdc, 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, 0x5b171723, + 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, 0xe66188ab, 0x4d2b635b, + 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, + 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, + 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, + 0xa31e8408, 0xac80b477, 0x7e7ddefc, 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, + 0x22eb7378, 0x08773858, 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, + 0x65c5fac3, 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, 0x7b9de18a, + 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, 0x804275c8, 0x6ff502be, + 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, 0xf65056f7, 0x18393ab3, 0xbf8c8b96, + 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, + 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, + 0x9685fd96, 0xc354066f, 0x9cdbc452, 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, + 0x328dfdbe, 0x7d168a67, 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, + 0x5fd2e5d7, 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, 0x3fb91263, + 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, 0xca097d3e, 0xa90c478f, + 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, + 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, + 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, + 0x4b823e48, 0x581b2420, 0x4ff2d70c, 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, + 0x476626bc, 0xad5c9d4c, 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, + 0x766880ca, 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, 0x89eac33c, + 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, 0x4eb31945, 0xf2c5d93b, + 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, 0x793fdc45, 0x519a1c15, 0xe31ee96d, + 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, + 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, + 0xd036e501, 0x0cb814a8, 0x06b9ab5d, 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, + 0x9284b162, 0x2cd5b7ab, 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, + 0x6ba484fe, 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, 0xdd4c9f22, + 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, 0x7143f3bb, 0x540b1347, + 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, 0xb2874627, 0x7f0c9a4a, 0xf8106eae, + 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, + 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, + 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, + 0x15aa0461, 0x1bc775e8, 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, + 0x68377d59, 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, 0x90689424, + 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, 0x362b4809, 0xec92588b, + 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, 0x32a14d01, 0xf4f6fec4, 0xada9360c, + 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, + 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, + 0x86428407, 0x45d6c023, 0xc77ebdeb, 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, + 0xf8198b68, 0x881246e7, 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, + 0x9e82681e, 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, 0x2d42e033, + 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, 0x0d1c971e, 0xe7795114, + 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, 0xb31d23cd, 0x8102d36d, 0x51aeed2d, + 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, + 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, + 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, + 0xbd3d8fa0, 0xe798d010, 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, + 0xa956eb79, 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, 0x723065f1, + 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, 0xac794782, 0x002064e9, + 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, 0x344f1195, 0xa7181920, 0xd05fcfd2, + 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, + 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, + 0xb75639f1, 0xadc76771, 0xd3543fd5, 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, + 0x6c95fd6a, 0xc3bb4a03, 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, + 0x045c945f, 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, 0x5acd89f8, + 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, 0x353f926c, 0xe3471231, + 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, 0xd16e5090, 0x9eff66f3, 0xa35ee078, + 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, + 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, + 0xc4062fef, 0x2bd3b757, 0xcbd45594, 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, + 0x2857a67c, 0xce5b2c90, 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, + 0xcd439cd3, 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, 0xbb20e7d2, + 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, 0xee542f36, 0xb0807f6e, + 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, 0x5104928d, 0x047c150a, 0x328cc000, + 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, + 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, + 0xcd61b411, 0xfddd923d, 0x638d0e61, 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, + 0x6bef47aa, 0xf460b130, 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, + 0xdfe4f729, 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, 0x55d094ff, + 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, 0x3161690b, 0x3ffa1fcd, + 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, 0x8a41bcac, 0x38d2f20e, 0x9aac541c, + 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, + 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, + 0x54705c7e, 0xba150347, 0xa80514ec, 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, + 0x7ce59906, 0x577da8f1, 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, + 0xd28382ff, 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, 0xb7bc9a79, + 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, 0xcc0be43f, 0xa606a522, + 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, 0xea4a38b5, 0x76901b4b, 0xe2583ac7, + 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, + 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, + 0x0cfe6db5, 0x5accdc39, 0x3377eaed, 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, + 0xc8bd6a8f, 0x625a6215, 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, + 0xae81db75, 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, 0xfee25664, + 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, 0x8bb3653b, 0x026eedbb, + 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, 0xb5bcee42, 0x6db10b43, 0x9fec55e3, + 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, + 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, + 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, + 0x429e2dc7, 0xc309b30a, 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, + 0x7874b53c, 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, 0xb92b80c7, + 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, 0x3326a1a1, 0x78b01e6e, + 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, + 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, + 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, + 0xc687b587, 0x383f7c40, 0x54830d04, 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, + 0xbf32f0c7, 0x2a796a67, 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, + 0xfd0367d1, 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, 0xc0e35390, + 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, 0xa32b3c81, 0x1d02d66b, + 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, 0x456c5876, 0x4c7a1f7d, 0x8210e535, + 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, + 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, + 0x03826132, 0xf505a1c5, 0x5536b8f5, 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, + 0x743d2b0d, 0xa82aed8d, 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, + 0xafef4d80, 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, 0x6b311848, + 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, 0x129d80fd, 0x18982768, + 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, + 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, + 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, + 0xeaac07b5, 0x0a377949, 0xcea56fc5, 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, + 0x65e46fe0, 0x9a5df9f9, 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, + 0x8358ab8c, 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, 0xdc18fabe, + 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, 0xd48cbb77, 0xcffdb7b0, + 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, 0x8ac94023, 0x11efd6fa, 0x5a6574f0, + 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, + 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, + 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, + 0x743b1a4d, 0xcd7ff202, 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, + 0x18060bb0, 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, 0x4bdc887f, + 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, 0x58f5a07b, 0x3c0266e5, + 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, + 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, + 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, + 0xbbff8af7, 0xaab1617c, 0x596a01d9, 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, + 0xd980aa05, 0x9269bb19, 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, + 0x298eb742, 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, 0x27fd3816, + 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, 0x2ae780c3, 0x7374f385, + 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, + 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, + 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, + 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, + 0xc19f5cac, 0x0bed2aa4, 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, + 0x783cfc66, 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, 0x1628b35c, + 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, 0xb361da26, 0xc0e2aa6b, + 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, 0x10f2492f, 0x231be0f1, 0x2b6fc840, + 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, + 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, + 0x7f6ace2b, 0x21514ebb, 0xc46d4800, 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, + 0xaf2ba637, 0xc4063ea0, 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, + 0xf942657f, 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, 0xea694198, + 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, 0xb453ee10, 0xafe27498, + 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, 0xbb74e075, 0x4408ab02, 0x2eae958a, + 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, + 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, + 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, + 0xfc5ff382, 0xc25ae007, 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, + 0xca5e1ee1, 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, 0x27c57f08, + 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, 0x86952278, 0x2810740c, + 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, 0xabc1d828, 0x05b673a5, 0x93e0c5ce, + 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, + 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, + 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, + 0x9d268a7e, 0x0485322e, 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, + 0x4f7b98f0, 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, 0x9161c085, + 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, 0xd6243501, 0x50f99e78, + 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, 0xe7888474, 0x58967c61, 0x9c2344d8, + 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, + 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, + 0x4a543dd4, 0x72d27f50, 0x794b2c38, 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, + 0xde3dfa58, 0xeac4977f, 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, + 0x4e87a4a4, 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, 0x829272a4, + 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, 0x508ed11e, 0x34f13455, + 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, 0xd435af57, 0x3e86d270, 0x7f04d0f2, + 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, + 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, + 0xfc49bc3d, 0x55757973, 0x84149ef8, 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, + 0xa17f53c4, 0x882c2967, 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, + 0xb340d658, 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, 0x76c9e6a2, + 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, 0xcc17d17e, 0xc52d9ae0, + 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, 0xad9625b4, 0xdbb45f5b, 0xf707fbea, + 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, + 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, + 0x6107a718, 0x83643c4c, 0xf2f96503, 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, + 0x41397ea1, 0x5793b309, 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, + 0x30ed4df8, 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, 0x9e264e70, + 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, 0x3f767c6f, 0xd1c48bab, + 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, 0x50da0980, 0xac96ecf6, 0x008c4910, + 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, + 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, + 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, + 0x49a844d0, 0xbbf5495f, 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, + 0xc41a3c1d, 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, 0xdea90048, + 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, 0xb709b9fe, 0x4549aaea, + 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, + 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, + 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, + 0x17a388b9, 0x78038049, 0xc505ab47, 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, + 0x7e6727d2, 0x9cef5fce, 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, + 0x88bb5013, 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, 0x17261a8e, + 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, 0xf480ab6d, 0x39525194, + 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, 0xdfb74aec, 0x62aae2f0, 0x46b855b3, + 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, + 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, + 0xe260be49, 0x18b01f3b, 0x0a2fc30f, 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, + 0xfb85d9ea, 0x2ddace97, 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, + 0x8c823cb1, 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, 0xf22f9ccd, + 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, 0x769e9c28, 0x65f8905d, + 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, 0x631f0974, 0x3f48dae6, 0x025739cd, + 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, + 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, + 0x5113ea88, 0x72ef2942, 0xd4aa0766, 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, + 0x74798f9c, 0x35e96814, 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, + 0x5ddb2efb, 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, 0xf4ab5191, + 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, 0x88a6c986, 0xdb0e7bbb, + 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, 0x0baad5bf, 0xaed19942, 0x66e4b053, + 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, + 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, + 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, + 0x34268b83, 0xe4bb7d3a, 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, + 0xac836a26, 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, 0xec264fe5, + 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, 0x381f32a7, 0x20a5e8c0, + 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, 0x15470bc2, 0x9ef31ae9, 0xd9e26951, + 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, + 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, + 0x2bf519ed, 0xf57860ea, 0xd69ba992, 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, + 0xccfc8b54, 0x58a93087, 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, + 0x60d94733, 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, 0x8ae04ca7, + 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, 0xca2f0fa1, 0xaac2e3bb, + 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, + 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, + 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, + 0x07796220, 0x0f0f8722, 0xbd6092dd, 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, + 0x17862bac, 0x610b9ce2, 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, + 0xcf3f6b27, 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, 0xff007778, + 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, 0x15a2c929, 0x9263b116, + 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, 0x187b9976, 0xf5ea2689, 0x87e3b151, + 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, + 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, + 0xbaa41197, 0xe5dcc72c, 0xaf16a669, 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, + 0x257e15c8, 0x12fbc35b, 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, + 0x4f1906d3, 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, 0x6d7b3b88, + 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, 0xfc5fbfed, 0x18db2aa6, + 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, 0x4429b1aa, 0x838682ab, 0x5bdfd86b, + 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, + 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, + 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, + 0x5e68e36b, 0x838322dc, 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, + 0xed6bf807, 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, 0xfb7507a4, + 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, 0x532e6654, 0x0c528786, + 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, 0x230b4319, 0xdd780574, 0x58889d79, + 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, + 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, + 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, + 0x73e830ce, 0xb353b81d, 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, + 0xe7929941, 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, 0x45da675f, + 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, 0x52a33502, 0x7d4b918c, + 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, 0x4b0a5e47, 0xce55bc17, 0x09656fd6, + 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, + 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, + 0xfe627e5d, 0x791daf5e, 0x50943665, 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, + 0x3e6a0f21, 0x9dad2288, 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, + 0x72f16cfc, 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, 0x86de5619, + 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, 0x06add0d4, 0xd0c462c6, + 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, 0x494f49bb, 0xcd7f90a5, 0xb6709e40, + 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, + 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, + 0x9bafb81d, 0x62e53468, 0x86ec692b, 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, + 0x8d6632f1, 0x8ba05667, 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, + 0xcfad36f8, 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, 0x526af581, + 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, 0xdea23b22, 0x9f8c78c5, + 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, 0x8d801702, 0x98d2fe2d, 0x3ed6b821, + 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, + 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, + 0xb2ccc077, 0x6162fefd, 0xb3701463, 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, + 0xeabc4ede, 0x82191ff8, 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, + 0x3e457dab, 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, 0x5ecc278f, + 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, 0x0862a010, 0xb3c9a772, + 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, 0xed37dba7, 0x26112057, 0x68c688f2, + 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, + 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, + 0x67c335d0, 0x6981f384, 0x6ca54c87, 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, + 0xf5315cf0, 0x995fb40e, 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, + 0xa571dfbf, 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, 0x1ce39a6b, + 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, 0x33a6d8b3, 0xd9101e64, + 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, 0x13eb0f7c, 0x77b31835, 0x65c53459, + 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, + 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, + 0x0e5f8848, 0xd61ad101, 0xf44c42a4, 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, + 0xd37d5397, 0xeada6952, 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, + 0xfea92813, 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, 0xded23976, + 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, 0x881ccb9e, 0xa1bb6a8d, + 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, 0xe19a859f, 0xfb877d69, 0xc91faf5e, + 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, + 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, + 0xd5e24aec, 0x6731d1b3, 0x48ebc226, 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, + 0x18281991, 0x42588569, 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, + 0x915978fc, 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, 0x4a5faf73, + 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, 0x477d5c34, 0xe2ef3d70, + 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, 0x6db3425d, 0xce451d6f, 0x6f2a53e9, + 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, + 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, + 0x0365098d, 0x013e15ad, 0xc990d5f4, 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, + 0xed216f9a, 0xcb714de5, 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, + 0xf602de55, 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, 0x99029b50, + 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, 0xbd2995e9, 0xd906ec04, + 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, 0xb921c72a, 0x9fc5a234, 0x55d0fbec, + 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, + 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, + 0x84b6ab49, 0x5b3c6835, 0x0015afb6, 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, + 0x89cc97bc, 0x713d3b24, 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, + 0x86363b5f, 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, 0x7368089c, + 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, 0xe516c9a0, 0xeab5aa5d, + 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, 0x614782cd, 0xce169d44, 0x6433de5e, + 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, + 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, + 0xc0ac7573, 0xca381e11, 0xfc5916b6, 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, + 0x332f9714, 0xa3804fc5, 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, + 0x37552b9e, 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, 0xe9b11f94, + 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, 0xcfed5315, 0x27f4a06d, + 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, + 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, + 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, + 0x3c9c2d05, 0x6794edd6, 0xc22cc352, 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, + 0xc045f697, 0xfd090038, 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, + 0x36ae74e4, 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, 0xd85611c1, + 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, 0xb326cc47, 0xe0faa978, + 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, 0xb77eda67, 0xc49052e6, 0xc514a075, + 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, + 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, + 0xf28a6231, 0x9eaa4f64, 0xe9468748, 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, + 0xd8eae4af, 0x46876f0b, 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, + 0xd1daf994, 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, 0x5389bce5, + 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, 0x62a8e0a5, 0x200442ca, + 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, + 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, + 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, + 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, + 0x29bc2f91, 0xac5eaa62, 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, + 0x8bc6cf4f, 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, 0x6bbb33dd, + 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, 0xf708838e, 0x2caf050b, + 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, + 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, + 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, + 0x6746103e, 0xa0eff544, 0x0bba778a, 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, + 0xf1ee2d08, 0x1b100e82, 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, + 0x7ea8c2c3, 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, 0xd1d5c2c0, + 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, 0x5ce3fa8a, 0x2075b595, + 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, 0xdb4a2241, 0x806460ec, 0x183637f9, + 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, + 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, + 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, + 0x724a1e6a, 0x1f49fcfc, 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, + 0xf8481f7d, 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, 0xc548731c, + 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, 0x92d1c238, 0x59503c44, + 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, 0x82172a29, 0x5db3569b, 0x6a0ab6f7, + 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, + 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, + 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, + 0xc2110048, 0xef4c9825, 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, + 0x3d923162, 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, 0xaddd3c63, + 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, 0x20d00302, 0x0718e1f1, + 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, 0xb6747958, 0x6bcb60f5, 0xbce4158b, + 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, + 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, + 0x436ca416, 0x0091a7da, 0xe705853a, 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, + 0x99f5e336, 0x67e6d388, 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, + 0x20fa88af, 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, 0xdeb5cc9a, + 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, 0x112a8ec2, 0x385e89a8, + 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, 0x0c60638a, 0x0c83492d, 0x95d61b20, + 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, + 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, + 0x50f5b110, 0x0c23b119, 0xbc27c7e8, 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, + 0xd1b98d82, 0x632df3e2, 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, + 0xe98733e0, 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, 0x75257595, + 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, 0xf12a2f87, 0x900624fa, + 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, 0xf3be72c7, 0x01ca0052, 0xdf927440, + 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, + 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, + 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, + 0xc226cc77, 0x294e0e4e, 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, + 0xd0489c01, 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, 0x5d6bc3c2, + 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, 0x0c117533, 0x0b70ddeb, + 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, + 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, + 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, + 0x4cd711a6, 0xc46a6a58, 0x2d82b595, 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, + 0x9920ac09, 0x02db13ae, 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, + 0x108cdb88, 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, 0x2944706d, + 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, 0x8ee22fc9, 0x9970baae, + 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, 0x253d5795, 0xa8e3738b, 0x9770975d, + 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, + 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, + 0xacabe801, 0x47952193, 0xd3138e94, 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, + 0x68161660, 0x6365afcf, 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, + 0x96847976, 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, 0xedabeffe, + 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, 0x25d6ba47, 0xec63d289, + 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, 0x671596a0, 0xa08b6a5b, 0x0bca7779, + 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, + 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, + 0x9e283138, 0xb2631843, 0x8c9d46d6, 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, + 0xa4fa2f87, 0x472f5be5, 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, + 0x6fba83bf, 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, 0x7d4f1ea5, + 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, 0x9b0b0ade, 0x6373a3b0, + 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, 0x4c9ca5fd, 0x7f1f3313, 0x30013306, + 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, + 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, + 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, + 0xbed76d66, 0xf5b960da, 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, + 0xad500497, 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, 0xef6e61d8, + 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, 0x4ed7b964, 0xff1f6c98, + 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, + 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, + 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, + 0xbbdb8c62, 0xf6dd386b, 0xe3358787, 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, + 0xce5af4fb, 0x712564e1, 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, + 0x66f6d4a7, 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, 0x499c86a6, + 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, 0xc94b8391, 0x7bd8e512, + 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, 0x449df40e, 0x93f035f8, 0xafd2521a, + 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, + 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, + 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, + 0xf9621d42, 0x77ee21f3, 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, + 0x45317e93, 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, 0x080f5133, + 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, 0xf8ab5684, 0xbd3b8b9a, + 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, 0x428761dc, 0x97459150, 0x709e0a12, + 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, + 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, + 0xac7d020e, 0xa7bf5312, 0x4c6834b7, 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, + 0x03f9e743, 0x3004dfb0, 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, + 0x9ad90bde, 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, 0xa1fc99fe, + 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, 0xfd35ccf2, 0xd2473bb9, + 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, 0x32e8b9f2, 0x103ef0a9, 0x1888642e, + 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, + 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, + 0x8ec2282a, 0x146232d5, 0xf4241f66, 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, + 0x2d03e06e, 0x305c322c, 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, + 0x2c33b686, 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, 0xa9d0de99, + 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, 0xce93f4cd, 0x822382ec, + 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, + 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, + 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, + 0xc83c381c, 0x098d5293, 0xc0738c93, 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, + 0x359fc239, 0x806328f8, 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, + 0x7d0cf9c7, 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, 0x356f9c19, + 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, 0x96e32fe0, 0x142e5994, + 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, 0x702f1422, 0x4008e264, 0xbbf91d05, + 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, + 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, + 0xa6b29bb4, 0x67777742, 0x65b6542c, 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, + 0x86507fb1, 0x26f76111, 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, + 0x658bb0c8, 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, 0x685d4d9a, + 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, 0x30d5acc3, 0x18d236ab, + 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, + 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, + 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, + 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, + 0x37160e0f, 0x9f623018, 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, + 0x99b0115b, 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, 0xc7d5de52, + 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, 0xf080b017, 0x4da4d290, + 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, + 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, + 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, + 0x0d628e03, 0x4a93cdd8, 0x6f643479, 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, + 0x1983f603, 0xd4591b19, 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, + 0x3488b648, 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, 0xde17a435, + 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, 0xc4706c3f, 0xdf14d9ab, + 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, + 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, + 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, + 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, + 0xb8c941ca, 0xe26b9187, 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, + 0x0bbe4840, 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, 0x7fa40f5f, + 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, 0x611a0f89, 0x3a0e5f8a, + 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, 0x01079381, 0xc250fa30, 0xead64afb, + 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, + 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, + 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, + 0xe5b8b32e, 0x9c6261e3, 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, + 0x8f854e38, 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, 0xa8e1a4e5, + 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, 0xff46bbb2, 0xa38e83bd, + 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, 0x6a145a5c, 0x6a41add1, 0xd954c1f0, + 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, + 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, + 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, + 0x5eba32d0, 0x3cc4a69c, 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, + 0xc8013642, 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, 0xe9e313b3, + 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, 0xef679615, 0xc074d215, + 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, + 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, + 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, + 0x208a0b6f, 0x7245f138, 0x352dee4f, 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, + 0x46fc92f6, 0xfcfa9de2, 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, + 0xa44da7f3, 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, 0x35818ebe, + 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, 0x3a03b930, 0x868b0e63, + 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, 0x4d72927a, 0x1b62ae8f, 0xef765353, + 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, + 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, + 0x83b4c653, 0xfd8585e4, 0x23af00e8, 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, + 0x822679ff, 0x695356ac, 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, + 0x9a82734d, 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, 0xccf76bc6, + 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, 0x0e3e6c5f, 0x83452a89, + 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, 0xdadeeb74, 0x7425d656, 0xdcf615c1, + 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, + 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, + 0xc725ecc0, 0x35b295d1, 0x7534f83a, 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, + 0x98a03f22, 0xd70a9952, 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, + 0x7ccba435, 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, 0x771d7fac, + 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, 0x59029f2b, 0xb47ed32a, + 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, + 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, + 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, + 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, + 0xdf2b52bc, 0x0849a8d7, 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, + 0xcca50f90, 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, 0x38d03044, + 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, 0x7ec20957, 0x2e01a0db, + 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, 0x0b90f4dd, 0xa36b8065, 0x31933133, + 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, + 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, + 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, + 0x339b1a9d, 0xcd9c7feb, 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, + 0x85fd0e01, 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, 0x0470618d, + 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, 0x89209a5c, 0x5a60a94e, + 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, 0x22497a31, 0xf3512771, 0xb6adb43b, + 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, + 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, + 0xfc9d64e3, 0x1b454a6d, 0x8b220894, 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, + 0xc66316e8, 0x52366573, 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, + 0x2d196453, 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, 0x6fb6bf96, + 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, 0x3c9257fd, 0x8a3d0140, + 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, + 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, + 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, + 0x615723de, 0xf5fde9a0, 0x96bab4f4, 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, + 0x54f0e2e2, 0x5355cc42, 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, + 0xf6ff9372, 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, 0x0230da46, + 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, 0x26a6191d, 0x83da081c, + 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, + 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, + 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, + 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, + 0x8bf9c71e, 0x1a682b8a, 0x7bbd75b5, 0xb06c035c, 0x9bd1355b, 0x03f15e1b, 0xe1dc6a96, 0x724c12d5, 0x5eeb7abd, + 0x6f1a533d, 0xe4163b97, 0x53963f78, 0xf4bdc4cf, 0x30bc6aa8, 0x55020a94, 0x87424139, 0x7f4e0fc0, 0x0dced4cc, + 0xcc44f761, 0xdc915d5d, 0x5923afae, 0x5fca09df, 0x6da60086, 0x4176cac0, 0x2cd1c0be, 0xeaf4a65a, 0x9a2b0460, + 0xd9adceb3, 0x837911fc, 0x24a064e2, 0xf62aef80, 0x2c72361c, 0xabcea574, 0xc9e8494f, 0x58fdc7fe, 0x19835be7, + 0xe2f50795, 0x22577eee, 0xf37a909d, 0x01085e15, 0x433de341, 0x47e376d9, 0x0bba767a, 0xf77fa338, 0xdaabb9e6, + 0x321bb7de, 0xd9c18914, 0x63c61551, 0x608ac9b2, 0xdc175799, 0xa3b005c1, 0xb30ba812, 0xb8f13ae7, 0x4e6515ee, + 0x63b6e03c, 0x21dc18eb, 0x92116367, 0x912c40eb, 0x67431a9d, 0xa3ac94ae, 0x8778ab34, 0x97d032f9, 0xe363d369, + 0x83361fee, 0xfc13d3ed, 0xa8b81258, 0x3ad31da7, 0xf22b43bc, 0x5e4dc39b, 0xaf3c8d97, 0x4e4f0c56, 0x9ad45750, + 0xce42b7f5, 0xfee1c9dc, 0xda821b40, 0xe112aa6d, 0xc534e246, 0x49278e21, 0xb44895c1, 0xe3d1ab5b, 0x73a79242, + 0x6c9f7498, 0x635ece54, 0x11679e76, 0x2ecfb564, 0x32fac952, 0x9ef53d09, 0xe639b29c, 0x6bc8773e, 0x1bc739cc, + 0x89ba5c0c, 0x4bd2bc26, 0x422ddfd6, 0xfdb0a8e4, 0xcf2f81a5, 0x14841e89, 0xd4f78e53, 0x63013219, 0x359821da, + 0xb02ce75b, 0xac288e79, 0xd6225779, 0xe9c65694, 0x49a11a14, 0x1607727d, 0x5371ef25, 0x6e32e37e, 0x46463aa1, + 0x2f9f3be7, 0x008814a8, 0x4aaeb902, 0xeaf8f5a0, 0x36ff71ae, 0xeda38d7c, 0xc8154fa2, 0xbd72884c, 0xeb83e123, + 0x8c815ce0, 0xe3cec3c1, 0xb7cb6a68, 0x4b2967a5, 0x6f401978, 0xa790036a, 0xd7098ddf, 0xe29bc8fc, 0x990029a6, + 0x03cdb1fe, 0x0dd3e1d0, 0x154d7ad7, 0xf416dee7, 0x5563bc46, 0x724bd24d, 0xc9afafda, 0x15fbdda1, 0xdafbcb38, + 0xd5a26b25, 0x619bed77, 0xba04b927, 0xfd2d6b8a, 0x77894e2e, 0x3a2b2115, 0x4f97c16a, 0x624c5c48, 0x87b8ac99, + 0x52727b94, 0x1e24f7f7, 0x075e8797, 0xf6c0d443, 0x1bbfc65e, 0xaaef1178, 0xc6ee8328, 0x328b718e, 0x6f763df7, + 0xf0198c11, 0xd6cd4bf9, 0x3ee66642, 0x717949cd, 0xd07b2cb7, 0xa023dc26, 0x36fb0e07, 0x833771f3, 0x865405d9, + 0x440f6fbb, 0xaf079d0d, 0x2187a5d8, 0x1c48bf61, 0xd1a3e59f, 0x022d6bda, 0xd6bbf539, 0xf7e1e652, 0xd13cd569, + 0x1953bd8c, 0x2c00848e, 0x15a8bd5e, 0xf1633fe7, 0x56e8f0b5, 0x3b009bee, 0xd18e24a5, 0x06e6be5a, 0x20b080a8, + 0x2b7c3d6b, 0xc9e867d9, 0x013902a6, 0x722d7f90, 0xaa97b1b4, 0x6a72eaa5, 0xa35fb788, 0x02c7801c, 0xf528ad86, + 0xc08e0f90, 0x36013f85, 0xb6507cfb, 0xce50853b, 0xdc81a410, 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, + 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, + 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, + 0xca3c7387, 0x3ebc4e22, 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, + 0x0d609b5c, 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, 0xe964371d, + 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, 0x8549a545, 0x72cd25a6, + 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, 0xfa0f309d, 0x2450505b, 0x7e62d6b6, + 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, + 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, + 0x554de3f7, 0x00236229, 0xb65a8838, 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, + 0x1e0f4174, 0x0e4f84a9, 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, + 0xbecc7016, 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, 0x36f74f81, + 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, 0x49684acc, 0x27ceed4c, + 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, 0xc18462c5, 0x30407eb5, 0x8e18797a, + 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, + 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, + 0x39bc1a46, 0xf4865fdf, 0x22bd8658, 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, + 0xd9382232, 0x947cd63b, 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, + 0x65a5e218, 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, 0x9cff960e, + 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, 0x5da4cf70, 0x861ef098, + 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, 0x2d914387, 0x9ed7f94b, 0xf00b5441, + 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, + 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, + 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, + 0x78603c0a, 0x7c403889, 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, + 0xe1fecec4, 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, 0xee70ca50, + 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, 0x57098afb, 0x744d626d, + 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, 0x5936ff74, 0xc1477a35, 0x3665ecdc, + 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, + 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, + 0x7e1959e1, 0x91787e6c, 0xda51caa5, 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, + 0x8fc78d5d, 0x3ea2142c, 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, + 0xa69d279e, 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, 0xb001c899, + 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, 0x46ebff79, 0xccb7b9b6, + 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, 0xac829629, 0x9ffbf3a3, 0x718c8f7c, + 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, + 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, + 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, + 0xbba13c12, 0xdd02c804, 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, + 0x347c5339, 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, 0x4396ff24, + 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, 0xee7ad3a2, 0xcc436c78, + 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, + 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, + 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, + 0x68c77435, 0x356f1249, 0xec7fe5ec, 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, + 0x8bac2cae, 0x5104a87d, 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, + 0xd5a33292, 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, 0x129c6972, + 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, 0xa54b4c48, 0x667c537f, + 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, 0xe16ab1b9, 0x3d5dd389, 0x5947821b, + 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, + 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, + 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, + 0x8e2665b7, 0xee93572c, 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, + 0x07a80a9b, 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, 0x8a302c05, + 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, 0x9b86cabe, 0x48f7ca80, + 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, 0x79bda240, 0x909fd98e, 0xf49643bc, + 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, + 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, + 0x8821bf49, 0xde5b8005, 0x6e749b41, 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, + 0xc85a975d, 0x00904827, 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, + 0x3ac88c9e, 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, 0xadef941f, + 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, 0x15116dd8, 0xcf51bdc7, + 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, 0xe55e6fbb, 0x43524b5b, 0x12dbc403, + 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, + 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, + 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, + 0xb541d640, 0x84ceb075, 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, + 0xd2f96c90, 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, 0xc9f9d7ed, + 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, 0x3ba18f38, 0xb9d8d6f5, + 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, 0xf818f739, 0x08eaf9e5, 0xc9f08a15, + 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, + 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, + 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, + 0x730d6d4c, 0xb4f2cb42, 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, + 0xfffa9c44, 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, 0xb4ba3765, + 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, 0xf93f4075, 0x9d0ed557, + 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, 0xa5fd92c4, 0x48985b22, 0x9d228641, + 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, + 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, + 0x7e4bb890, 0x1c7739a1, 0xc91fad83, 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, + 0x1eb7fdad, 0xa71313bb, 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, + 0x75bea2bc, 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0xd4fa8fc8, 0x298e3d87, 0x5e472547, 0x494a84d2, 0x647d8034, 0xac4098be, 0x4009c6b2, 0x8f971b24, 0xce15d184, + 0x0fb41b97, 0x193d85a5, 0x8ade3fae, 0x7be5a811, 0x5ad03572, 0x08e7051b, 0x6e2ee2ff, 0xd8345ba1, 0x5443a7e3, + 0x53a2abfe, 0xd4f59d16, 0x9f88e81d, 0xf244115e, 0xf0b2ba6b, 0xb1988699, 0xbb9b5e12, 0x70e87e85, 0x4be3ca07, + 0x2e428baa, 0x1e734902, 0x549f40b9, 0xbab86a07, 0xbb2e300c, 0x8ef685ba, 0xe0895ba2, 0x77767b22, 0x131dfca4, + 0x8da6eb24, 0x1bda5985, 0x6d00ff91, 0x722cb00c, 0xdf308f8d, 0x99829400, 0x4f496a27, 0xdef9fa35, 0xc60f301d, + 0xc8ff73a9, 0xca6e06bc, 0x8983790f, 0xac6bfc5d, 0x60471cac, 0xf0fbfc42, 0x17f53500, 0xf7bfc25d, 0xe327fe31, + 0x05750344, 0xb63ad995, 0xdec9128e, 0xbb672fb5, 0x71c76d58, 0x1ef91ab6, 0x47bfd7e9, 0xddddc7a5, 0xb32b01fb, + 0xe26ebb89, 0xa91d5f4b, 0x9787357d, 0x3b464566, 0x4382b18c, 0xe8cfac56, 0x5cef1081, 0xc01afc3f, 0xa76299d2, + 0x89c35558, 0x6e74f552, 0xfcc20336, 0x7e8bffcd, 0x5d3d2e4f, 0xb6d7afc0, 0x16c6cd4c, 0x1e8f301a, 0x8431800a, + 0x723228d5, 0x4be49662, 0x0e5bae7a, 0xc7c2bdb1, 0x8da96e1e, 0x84f14607, 0x5a50c4d5, 0x50769285, 0x5526702a, + 0x030dfef9, 0x1d3be1a1, 0xcb14ebfe, 0x028a93d4, 0x75b20b6e, 0xe64ca916, 0x4a47f540, 0xf77ba8c4, 0x2d951cef, + 0x7f9a9640, 0x6d4ef4e7, 0x45daa8f0, 0x4c0a46ff, 0x5b98be52, 0xa411dc84, 0x3e48dabb, 0xf6fdc6e2, 0x91cea2dd, + 0x38d25a02, 0xe3b7d79e, 0xa7655d0b, 0x5c8cd063, 0x14de0541, 0xd7228c6f, 0xb23b5084, 0x2a5adac0, 0x5ed77d86, + 0x42c17cbe, 0xbf586e7f, 0x4cc6ec9b, 0x9a39cd6d, 0x7373f3a4, 0x397d645c, 0x0b641d9e, 0x277aacb2, 0x59524c27, + 0xff8f73bd, 0xa10b97b9, 0xd166198a, 0x3b4a25d8, 0xc0ed5d1a, 0xb56746fd, 0x367bb4c9, 0x731a5238, 0x8218ee6a, + 0x612af553, 0xca340189, 0xac01f213, 0x9b3b20be, 0x7ba108cc, 0x3541af79, 0x8fc88951, 0x4a3269c7, 0x0ff70337, + 0xf1a9cedd, 0xac14dc44, 0xa44a8a96, 0x9e5ed0b9, 0x6388cb44, 0xf6e438c5, 0x13c4899f, 0xac37573b, 0xfd9172f4, + 0x18b15ef7, 0x7a495794, 0x451a4b06, 0x367ecddb, 0x4d89a56e, 0xfa69d9c9, 0xe7bcbb4d, 0x6f0dd775, 0x4908d40a, + 0x5ee60a87, 0x42ec1803, 0x7771789e, 0x4d3ffe6d, 0x21ce8f2d, 0x51ba9bd9, 0x331bbde2, 0x69535503, 0xb295a400, + 0x49d93e8b, 0x43920861, 0xa72be34a, 0x0ba77d43, 0x8cf43fa2, 0xd7fb4734, 0xce185cad, 0xa04654fb, 0xadf00e22, + 0x7c033f80, 0x0b5dbbe3, 0xd8f9d875, 0x4af737f8, 0x941b1d2e, 0xc2dc1fbc, 0x2eade5e0, 0x03bb0050, 0x6503f2f9, + 0x6064ef8b, 0x5fb4d7ac, 0x723ea425, 0xdc9182e7, 0xcb44f614, 0xee140310, 0x18b1ad42, 0xce4c46f2, 0xea7b7c10, + 0x0e32b86c, 0xde08244c, 0xa057c218, 0xd5420c94, 0x1cb9737c, 0x637aa739, 0x1d3a19ad, 0x388e26f8, 0x2e517d3f, + 0xc1d0e29e, 0xd70811f5, 0xc844c1f6, 0xcca085c3, 0xccef7e1b, 0x74c8a12d, 0x937aadf6, 0x3a333ce8, 0x615775a3, + 0x3b1d0f0a, 0x9dbf9990, 0x283d9dd2, 0x6612fe9c, 0x4401bf68, 0x5e71b357, 0x473797ea, 0x01364687, 0x426ddb6a, + 0x54b6f856, 0x98ba893d, 0x045a2bf9, 0xf67579cf, 0x8d77774c, 0xbc86e968, 0x0af75a60, 0x87882dc2, 0x8936d638, + 0x6ec83135, 0xa7f8938b, 0x28613b1f, 0x510d8ccf, 0x4b8b3bb7, 0xdd9d705a, 0xd2a87e4a, 0x60959d32, 0x8c7d650b, + 0x812bf858, 0x6d1fde77, 0xce4a4758, 0x26848a2e, 0xa4c520c4, 0x609c8e0e, 0x5b2da861, 0xcfccc726, 0x53b175bc, + 0x27c2356a, 0x43ed152c, 0x8ddbc723, 0x69ce3144, 0x19883c6a, 0x820bb17b, 0x84676b52, 0x1b4724b0, 0x34d61e47, + 0x86058e15, 0x5f3ad5b3, 0xaa9a18b6, 0x7eea420e, 0x6f5e42e5, 0x0e011973, 0xe5351a30, 0x8f50dccb, 0x2bb3a35e, + 0xd5a00dc0, 0x47b7f316, 0xa8ed96ed, 0xfaa0e2f1, 0xfe3f28ce, 0xae7114a4, 0xf7d6dd39, 0x5041de7a, 0xd93a8ab7, + 0x170182ba, 0xe7de179d, 0xbdd60723, 0xcb5e6069, 0x0e2f0d4f, 0xf3cd01f0, 0x7eb3df99, 0x031901f1, 0x3197f476, + 0xe637a162, 0x4e869926, 0xcd987daf, 0x1232e0b3, 0x86f88664, 0x6074a0be, 0xee45c4e8, 0xce5dfdec, 0x37f054e8, + 0xcdda2ff1, 0x2043e65a, 0xbd6f3b6b, 0x6ad1d025, 0x65cad15f, 0xc003e695, 0x0838221c, 0x6c54b2ef, 0x8bb0d7b3, + 0xc3373380, 0xf4217de3, 0xd0da628a, 0xd9641620, 0xe117c48f, 0x2a195bf5, 0xb88fe8ed, 0x257413ae, 0x19692276, + 0x5f81c3f5, 0x1307812f, 0x71599788, 0xbde7ff27, 0x55e3c66f, 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, + 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, + 0x50dd62e5, 0xf2dc2490, 0xb742d94c, 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, + 0x40278377, 0x4f1306d5, 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, + 0x3c727cc6, 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, 0xe3f264d4, + 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, 0xdf701ef3, 0xdbee77ed, + 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, 0x749c5fa2, 0x7bbfac6b, 0x944dc87c, + 0x2937ff1e, 0x87be8ef5, 0xd508b44d, 0x88f9b449, 0x09805e40, 0x747a7907, 0xcd189775, 0xc48c3e04, 0x8e044af2, + 0x69bd5360, 0x4365cd9a, 0x41934cff, 0x49281c0c, 0xac1a3b53, 0x49c1a094, 0xf285cbe6, 0x6939c327, 0xd492ce08, + 0x706fa662, 0x1781b9e9, 0x2ac19678, 0xd518ea0d, 0x7a374775, 0x07be58d3, 0xddccbc1d, 0x4c64df7f, 0x77557313, + 0x78f745bc, 0x7695ad4e, 0x1f199053, 0x44635e86, 0x1401a00d, 0xd443d30e, 0xb250c664, 0x3ec69195, 0xbca388ba, + 0x4be5e051, 0xdbc94cca, 0x58e07f89, 0x56a8747a, 0x8e98e7ac, 0x9267eec3, 0x594c3451, 0x3ebe4422, 0x46a7add4, + 0xdf5512c8, 0x20ae1c95, 0x53f909c4, 0x694f9d54, 0xad7e8f90, 0xdc387260, 0xfa4555ad, 0xa1da14c3, 0x72c56325, + 0x56011855, 0xf136f833, 0x86acff9f, 0xac88ffaf, 0xe9b77aa5, 0xa2501e80, 0x96a89a4f, 0xd5e9bf3b, 0x2efd4983, + 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, 0xc0c97ca0, 0xd6456515, 0x86a49990, + 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, + 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, + 0xab800038, 0x0e5f415b, 0x77d71868, 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, + 0x7999f376, 0x687e76cc, 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, + 0x5d416565, 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, 0xe1bcc050, + 0x58e9dea6, 0x9120a003, 0xaf81ac7b, 0x4bb3258d, 0x81175a7c, 0x9c0dfc15, 0xcc493ff4, 0x310244ca, 0x4744c647, + 0xba4acff8, 0xf7f2c903, 0x4d307533, 0xf3d3d65e, 0xd5f54c63, 0x501d2b16, 0x5fb04a6a, 0x17ef06f3, 0xed6fe1e1, + 0x6b689bd9, 0xcf0b906c, 0xb87f0c05, 0x68e6655f, 0xd2dbbb59, 0x6e7f68dc, 0xcb190ffd, 0xe5ad1843, 0xcf43d3cd, + 0xba9fbb26, 0x7292c37a, 0x2edbfc87, 0xc309ecd3, 0x2296fac7, 0xea11cd74, 0x44a5431a, 0x26eb5e3a, 0xe385b905, + 0x1855bad0, 0x272e3814, 0x03311bc4, 0xbecfc078, 0x43ed13e5, 0xe98431da, 0x1b156977, 0xfd3083ab, 0xc394ebca, + 0xcd25c4b6, 0xc58eee15, 0x0fbbd833, 0xa9e7c061, 0x42a51d37, 0x9919e922, 0x1962d841, 0x9c3e98ee, 0x60e546a4, + 0x688574b0, 0x50a2c84e, 0xd464e24e, 0x96bf6243, 0xf61dc96e, 0x2d9cdd50, 0x6b8117f4, 0x54955da8, 0x8b0998c3, + 0x8baf0db6, 0xf7e6bf89, 0xbecbc735, 0xc39e00de, 0x4e10e4fe, 0x6413f75f, 0x215e8148, 0x2bf72efe, 0x1d7cff6e, + 0xdb08ab8c, 0x6e537eb7, 0x669d59d9, 0x76d10e72, 0xa07aa161, 0x935a11af, 0x7cd7b149, 0xc9e8e540, 0x1db70600, + 0xfaafe3cf, 0x7b4d9f38, 0xb40b6275, 0xb726ceaa, 0x600ddd3d, 0xfa46364f, 0x4606cb16, 0xbaa7fb6a, 0x872a21b8, + 0xa4ce4d82, 0x4268bee0, 0xb0c76c16, 0x28a749db, 0xad5d68e4, 0x8b42ff83, 0x2d9490b8, 0xf8512caf, 0x47b20106, + 0xd5770487, 0x224856cb, 0xcb320805, 0x3a275b81, 0xf8430839, 0x373f3fff, 0x620596c4, 0x01faa3c5, 0x33b031d9, + 0x41e6df6d, 0x588b2df6, 0x321b4649, 0xcd9b3b90, 0x8ada2e5b, 0x67bca81c, 0x17de8242, 0xbec68a95, 0x2d2bea47, + 0xb986a75b, 0xac2456c6, 0x3b9b2ff9, 0x6fd600af, 0x10391225, 0xc5d7b055, 0x5095a20f, 0x09aae2d7, 0x2b12d63e, + 0x51607924, 0x1b10a4a0, 0x21bd699d, 0x962172bf, 0x30849f35, 0xbe9e6c38, 0x5a924cf3, 0x0c2c9279, 0x01ea6a4a, + 0x8201535b, 0x1a43b0af, 0x5a14628e, 0x2a1bd53d, 0xfb2292b1, 0x51cab661, 0xdad91326, 0x70e000e6, 0x64c846df, + 0x46422c08, 0x6ea48374, 0xc7c27c67, 0xc2241288, 0x03833097, 0xfa69432c, 0xa7c40ac5, 0x8ef29f05, 0x8b2599c7, + 0x239748c7, 0x3976582f, 0x7e63b803, 0x2206a2c6, 0x5f7fc961, 0xb8af162d, 0x579e4d70, 0xd53eeeb1, 0x66baa24a, + 0xf2ff8ce9, 0x698b6c1f, 0xca1b9f7d, 0xb06074b0, 0xd19e99d3, 0x545d10cb, 0x039f36e8, 0x9cfb78d6, 0xde0a5980, + 0x0a92866e, 0x3094a27b, 0xdcd07232, 0x50dbafc6, 0x1bb48c02, 0xf3c9be6d, 0xf8854fc1, 0xdc62dbc3, 0x2fd471c3, + 0xd4c5d20d, 0xbde52147, 0x9efdc8cf, 0x68922fc0, 0xb88e333f, 0x01278b3f, 0xb082deaf, 0xcaef9fb6, 0x2e2bd0e0, + 0xc66c96b8, 0x6fda0868, 0xa77e1f7a, 0x1d160a89, 0x85b1487a, 0x61d78902, 0xabee7f67, 0x96549880, 0x0531f910, + 0xf11c1886, 0xc7e97b0d, 0x41e6756a, 0x85f14859, 0xe3f0fc0b, 0x288c0086, 0x0430ba1e, 0x52e7f11c, 0x1c045213, + 0x1f4905be, 0x25f1210e, 0x56052d48, 0xd1dcd8a6, 0x4b6a63c6, 0x789dc29b, 0x9d0ec937, 0x7da8bb3a, 0x6d34fee5, + 0xb0cb417a, 0x79cbae75, 0x771ff408, 0x795efaf0, 0x08bba173, 0x8b087708, 0x31919e61, 0x58fc350b, 0x9724ae94, + 0x63c41461, 0x524803be, 0x1f321398, 0xae180121, 0xfc87c058, 0xba1f7804, 0xb3361eb0, 0xfbd0be38, 0x89a18736, + 0xf3f42412, 0x03b441c3, 0x9abdee97, 0xafd360f9, 0x4f4ea1bf, 0x95c8ba1b, 0x4443be52, 0xe1d07377, 0x0b1a5edd, + 0x6eddede1, 0x8269752c, 0x37e96258, 0x32818b93, 0x4335e781, 0xa7272ced, 0x399f7f83, 0xece7155f, 0x746b491c, + 0x40132011, 0x39cd4600, 0x535de5b8, 0xe585bdc2, 0x3454b808, 0xb8eb525d, 0xf03de612, 0xd3625812, 0x5f9e2734, + 0x538214a7, 0x21f2740d, 0x39cafc80, 0x092f0669, 0xc244c4ff, 0x569c8561, 0x8ce00cec, 0xfad3174c, 0x17a98478, + 0x3fba51e2, 0x7839ccd3, 0xd3cc2942, 0x34459786, 0x9e605d5a, 0x481ee65e, 0x63c01029, 0x97c3b03b, 0x0556943c, + 0x9ca515fa, 0x45ee4c64, 0xfed15ef4, 0x65baabdb, 0x037c4d51, 0x892ea8a2, 0x2de6038c, 0xd8716227, 0x57424e4f, + 0xf1b5ca70, 0x287fcd83, 0x653d548d, 0x2baaa7ed, 0x6af133ba, 0x4bfb12eb, 0x0585c00b, 0x7926e62b, 0x67f71020, + 0x06941d09, 0x3269b9d6, 0x6becf31f, 0x18b598fe, 0x139643a5, 0x9a9160e1, 0xbe2df596, 0x782f8037, 0x9bcce7db, + 0xf3be74bc, 0x4f7f7177, 0xddcacedb, 0xd348bb00, 0x0ef68de3, 0x1ff7d95c, 0x6201a28d, 0x24f67327, 0xa1425633, + 0x48426e5d, 0x3ccfed4a, 0x92baf081, 0x868d6418, 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, + 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, + 0xa4f0c02c, 0x006bdbc5, 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, + 0xd9d19ac8, 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0x40bb52d5, 0x654712b1, 0xd8e940e2, 0x8ff4683c, + 0x2a998600, 0xd4aad8ba, 0xee241d02, 0x94346fe9, 0xc02eb848, 0xc2c91e1a, 0xea843f6c, 0x5bc57c6c, 0xddd8a617, + 0xebf9c3c0, 0x4980bc36, 0x6d334dcf, 0x97a4b3df, 0x2a94b788, 0x83811aca, 0xbbc37422, 0x6292df1d, 0x761131db, + 0xb2d8dbe4, 0x7ff0219d, 0x95d470ee, 0xda8c0e74, 0xcf981bc4, 0x95642758, 0x215c055b, 0x2aaea2f2, 0x28a91766, + 0xe750abab, 0x995e1edf, 0xe39955fc, 0x33af7feb, 0x238315d1, 0x0cc1992b, 0xb2e68405, 0x3813b38f, 0xa380ece2, + 0xee2f0543, 0x60ec9262, 0x3b64b102, 0xeb278114, 0xd72e289b, 0x06c0b20e, 0x7239e577, 0x8613e1c9, 0xf1f5792d, + 0xd4b9c6a3, 0x963ffa00, 0xc8f22d61, 0x4d42a033, 0xdcc72405, 0xb55b7407, 0xd43450b4, 0x4c177200, 0x95b2f572, + 0x79686e33, 0x33eafcc3, 0x16de94f2, 0x3623320c, 0x4f532536, 0x32573813, 0x57c5824b, 0x22645f3c, 0x4662b4dd, + 0x30a54064, 0x6a16359a, 0x22d07103, 0xa94b6786, 0x56603213, 0x41ff6c2f, 0x0e17ba1e, 0xe1a84fff, 0x253f2fa0, + 0x1bca480b, 0x9e21239d, 0x6429e2f7, 0x1bc7bd99, 0x05b70708, 0xa991f02d, 0x1f7febda, 0xf83d3320, 0x7e7fa0a0, + 0xaf06e5f4, 0xe736a11b, 0xe94ddc0b, 0x43ec7b84, 0xe4f8ec31, 0x3589c155, 0x466741f1, 0x98a23ae9, 0x38b8d3d4, + 0x3b70459b, 0xf8c4c021, 0x01b89c7f, 0xd27c63e7, 0xf3c9703c, 0xeed502f6, 0xce92f7b7, 0x47b7ba55, 0x7dede31e, + 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, + 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, + 0x11e80584, 0x3a49181b, 0x01877253, 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, + 0x7b06c1bd, 0x241bb5d3, 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, + 0x6a39fefc, 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, 0xe97476ff, + 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, 0x6bc54667, 0x5da05bd4, + 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, 0xa18cde24, 0xa865edcd, 0x4a0863f2, + 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, + 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, + 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, + 0x9d3fcbd9, 0xa2157e5f, 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, + 0x8430e9fe, 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, 0xcff88a4f, + 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, 0x027ff968, 0x7c059f38, + 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, 0xd8861fcc, 0xa171057c, 0xc650cd2a, + 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, + 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, + 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, + 0xd2063aba, 0x38356c3f, 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, + 0x1c1010ce, 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, 0x52f9037c, + 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, 0x49c20c19, 0x5283a436, + 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, 0xc2223c9d, 0x99554000, 0xcd28bc49, + 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, + 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, + 0x553e3c53, 0x4ff910a9, 0xb16d9d48, 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, + 0x1ead51ac, 0xf531936c, 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, + 0xd81a58c7, 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, 0x5bf25e25, + 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, 0xc806079c, 0xc684f5d5, + 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, 0x4adb2b92, 0xf781402f, 0x870c8ab5, + 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, + 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, + 0x5d7847cb, 0x800a7cd4, 0x2174ea30, 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, + 0x2e1cd1e9, 0xc7308954, 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, + 0xb2b5f06d, 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, 0x8692254d, + 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, 0xdee4891d, 0x83247a45, + 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, 0x3e9a6812, 0xb7981ce1, 0xd48dac33, + 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, + 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, + 0x79d4b7c0, 0x4f0d800c, 0x6615417d, 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, + 0xb2213194, 0x520c5c4b, 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, + 0x4dbd49c2, 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, 0x7fd1b105, + 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, 0xc844714c, 0x83a50459, + 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, 0x795f7841, 0xa403bc22, 0x95959ab1, + 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, + 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, + 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0307.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0307.h new file mode 100644 index 0000000000..081f5f0210 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0307.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1110_transceiver_0307.h + * + * \brief Firmware transceiver version 0x0307 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0307 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[LR11XX_FIRMWARE_IMAGE_SIZE] = { + 0xc4fa791c, 0x7210409f, 0xbf601c2a, 0xb786ae60, 0x6b48ca19, 0x2682a714, 0x02603cb6, 0x18147bc5, 0x1fb8ad43, + 0xcc7aff2b, 0xf5710ccb, 0x68bef368, 0xd3b5223d, 0x8fc2bd69, 0xcceb7a85, 0xa9ec8afd, 0x6665784f, 0xb173117c, + 0x8ca11cb2, 0x81706a1c, 0x78f98c6b, 0xd93674f3, 0x66627f55, 0x1d4164f7, 0xf69c0446, 0x55d03f02, 0x73f64248, + 0xf0815622, 0x34700020, 0x7dd9875a, 0x4a241d20, 0x59cd30af, 0xefd56d14, 0xdb5cb6c6, 0x1f88525c, 0x91215018, + 0x7c8902e5, 0x95a09d6c, 0xf60ec127, 0x74cbcefe, 0xa3ef6b09, 0x24fc3570, 0xe9a66dca, 0x6fbb5472, 0x016cbd9e, + 0x0bd636ac, 0x207ea4a8, 0xe99ecebd, 0x3c6295cd, 0x018e4436, 0x825d9642, 0x0899ca04, 0xcffa7db0, 0x6699b2a6, + 0xfa0b8710, 0xf8a92492, 0x5a3183af, 0x42c2a183, 0xedf46825, 0x8b81e925, 0x5d1689bd, 0xcef114c0, 0xc0afbe27, + 0x456f5ab2, 0x538e8230, 0x3967af60, 0xc8779aa0, 0xef271a3e, 0x7c818870, 0xa5628714, 0xff9f1234, 0xe89ae268, + 0xf51bc726, 0x5b25d311, 0x26e6ee32, 0x2c7fc916, 0xcaf70fa0, 0x0876fcd4, 0x63e2304b, 0xa14ce4f6, 0x9f8ab5b3, + 0x8f48ec72, 0xa19eda11, 0x18ec1bd0, 0xba5f75f9, 0x70f97ce9, 0x2f9e0068, 0x7645bcee, 0x5bb7e36a, 0x5e4ca59f, + 0xc494238f, 0xa113c58e, 0x91bab958, 0x86091804, 0xd4f9c0d3, 0xc35384cd, 0x89eb1fe9, 0xf6052a5c, 0x66a6e9e3, + 0x67462487, 0x743b2ca9, 0x41417340, 0x66bfc713, 0x6a08bbeb, 0x4d47b518, 0xb09e0664, 0x11a9da8f, 0x06be54fc, + 0xef8887dd, 0xaf97facd, 0x6b1c1f54, 0xf3e59f59, 0x01b0f113, 0x0d5f1361, 0xc3b90100, 0x44a7e365, 0x309c3172, + 0x6482ab9f, 0x9a241340, 0xaff96953, 0x7ed33415, 0x00ed9b57, 0x0b075f71, 0x464b157c, 0x6ff2bf08, 0x49cdb8f7, + 0xbd5a5630, 0xe7467471, 0x3e2ce289, 0x3c5bfca9, 0x0f14e557, 0x7f3a74e4, 0xf0b1e7a1, 0x0c6ee4d0, 0x49020688, + 0x63b41799, 0xd2cfaa29, 0xfe0d0b1e, 0x09df95d3, 0xb184d7a5, 0x5f6471c4, 0x75e3fbb6, 0x1601d23f, 0x4403d5a2, + 0x4b3ca6f0, 0xebb2f634, 0x7d3482c5, 0x1873fb97, 0xea32c26e, 0x4472a6bb, 0x261551cb, 0x44be8f44, 0x21983ade, + 0x9c899261, 0xa99b0c4f, 0x847a00ca, 0xd0ab1d06, 0x41a22e19, 0x995a6ad0, 0xbf3922ec, 0x87b2ad90, 0xe1e44396, + 0xdcfda1e6, 0x7449a22b, 0x24b82115, 0x069c010f, 0xf7faac72, 0x585dbba8, 0x53e47687, 0x95fe8186, 0x9e3ea4ef, + 0x0e7f5147, 0x5c9d339d, 0xb000909a, 0x4e37d1fc, 0xe494fa07, 0xa2ac5ce5, 0x9b9ff050, 0x9f9520cc, 0x1b7491d1, + 0x2aecbe4b, 0x81a1b1f0, 0x0f8b6592, 0xe4659b55, 0x68fa9860, 0x43b974ca, 0xb852d566, 0x6a9a4b6d, 0xb9ed1238, + 0x974e5699, 0x57658f69, 0x5dd68ef5, 0x16f76871, 0x9c5d4f83, 0xd9c7aee9, 0x9d307cda, 0x6b7b42ba, 0x6e03c929, + 0xbac87d8d, 0x8bc1abc3, 0xb5442201, 0x50841372, 0xc824a494, 0x854d837c, 0x12678064, 0x080948d8, 0x74adcd86, + 0x70152efa, 0xaefa8cc3, 0x82ba3e14, 0x2d9b4957, 0xd13d3f14, 0x685ea9af, 0xeaaa1a82, 0xed1a4bff, 0x2bd192db, + 0x692d911b, 0x1689eb7c, 0xa36e63ec, 0x692b2a68, 0x53eae6e7, 0x180b20ed, 0x86ccfaa3, 0xc3fc01e3, 0xf7b2f53a, + 0x0a912075, 0x277e6f6a, 0x323e41dd, 0x982bb83d, 0x2215d5f4, 0xe44b4f14, 0x4ed70fa4, 0x4d1647cd, 0x1d1bce5e, + 0x8b9aa675, 0x2137e34b, 0xe9a72595, 0x1789c130, 0x4a231d92, 0x132a7d4c, 0x9b4de577, 0xabf86180, 0x89c35382, + 0x429c2754, 0x738e1779, 0x6a81a518, 0x70fd4533, 0x675f7386, 0x6539c704, 0x0769a7d0, 0x6200b9ee, 0x5d297220, + 0x4cc7e2d1, 0x4a3e96cc, 0x0f529d7a, 0x0a224c4a, 0x440434cf, 0x6577ebf2, 0x8cec08f2, 0x3705d669, 0xf2a4b2c4, + 0xdcfc9e26, 0x012085d7, 0x067db48d, 0x396092fb, 0xad85c405, 0x4759b2eb, 0xe25e8465, 0xef439557, 0x255dd6a2, + 0x63f4b730, 0xa1603f4b, 0xb5ca5af6, 0x6745f487, 0x29f11e98, 0xcb22b5c9, 0x5b78157a, 0xa1bfe900, 0x22197bd4, + 0xc567c5fb, 0x43c1317b, 0x292619f3, 0x12be5e61, 0x6e06676a, 0xe8293e3b, 0x9b4e9318, 0xe78c3935, 0x17239984, + 0x65b99d32, 0x6c0a537a, 0x8efc5862, 0xa489a284, 0x3af99cf6, 0xb2c02160, 0x03fc0a09, 0xb77c7ac2, 0x08907c22, + 0x76b3bec0, 0x6da0ef9a, 0xc5f0bf66, 0x37ac6aa6, 0xf28f296d, 0x57627789, 0xd87412a7, 0xa26752e0, 0xa993f999, + 0x4aa38c31, 0x7d979b9b, 0x99108e20, 0xb9bcfc09, 0x10055cd2, 0x057c8bd1, 0x116e9b47, 0xba810968, 0xfc333307, + 0xc8e1cbc0, 0x345838d6, 0xf579ccd5, 0x14275a2f, 0x2b6fd94e, 0xd7385a71, 0x8a7b88c0, 0x54e4fa2a, 0x245fa79f, + 0x36b7be0d, 0x382e274d, 0xfe708552, 0x30176c2c, 0x962dbb42, 0x6bf547b7, 0x76ec9a64, 0xa9c55ced, 0xd2ebce8a, + 0xdcfd3459, 0x4dc61db7, 0x2307854b, 0x24eb5fab, 0xd3d5ee47, 0xbfbb970a, 0xdd715ee7, 0x488f703b, 0xa0073b3a, + 0xa4ebc8fe, 0x0b3facfd, 0x2057865f, 0x37754e8c, 0x7dd4a391, 0x9a635b95, 0xb8613d01, 0x320da102, 0x35f7ea1d, + 0xe93ab7ba, 0xa8f506f3, 0xd9cc64ff, 0x9d2d1629, 0x39b71887, 0xcd1826d9, 0xef3e41fa, 0x8d9e289b, 0x81a01555, + 0xa42f1239, 0xe4a20174, 0x2abbc8f2, 0x01966ef0, 0xd3118ecb, 0xa2852ec5, 0xaf8b3149, 0x3c205022, 0xdcd1e254, + 0x6bd58cc4, 0x4eebb56d, 0x1833eee6, 0xa7a3da56, 0xedc2de47, 0x5a3262d6, 0xc603d90b, 0x025192ed, 0x8c1cfc9d, + 0x9fe6df2d, 0xfb9ee5ba, 0xe41c7b4e, 0x13fb6522, 0x012121d2, 0x3c1b5add, 0xc6e0bb88, 0x1fa12a8c, 0x5e29dbc6, + 0xb593b5ed, 0xcaf1e4a0, 0xd67e55ff, 0xf64e3105, 0xdf524d6a, 0xeaf123fc, 0x0cb68e6f, 0xf7d69b3a, 0xb634d64e, + 0xf97192c9, 0x7e9dcb21, 0x0da089f9, 0xe57bd463, 0xd50d02a5, 0x8a531b1c, 0x08cb6b05, 0x440d0e01, 0xf71d902e, + 0xb087be47, 0xfae78175, 0x34e53a75, 0x8f90ee2a, 0x1a08a5ac, 0xf3d9a8db, 0xb3f21c46, 0xc56f0999, 0xc4e724ad, + 0x27f6d68a, 0x7d0e8e5f, 0x32e6bf30, 0xcbaeb386, 0xf2dc7d40, 0x89c1929f, 0x8232cbb8, 0xb8160cc6, 0xd6f22cec, + 0x394dbaeb, 0xad273421, 0x986d3a7f, 0x93611bef, 0x4b372876, 0xfebb8d1f, 0x9e102e3a, 0x177e1c58, 0x1730a6ec, + 0x8dff4fb0, 0xd7c80be9, 0x6d4ccbe5, 0xe7945b66, 0x5826f5bf, 0xe36af450, 0xb65f3076, 0x62344f60, 0x80ceefa3, + 0x98e0e4be, 0xc3c44d53, 0x9633dc88, 0x35350c88, 0x09fd933a, 0xe5c19c5c, 0xfe79a633, 0xfb56d6a0, 0xb708b922, + 0xd385feeb, 0xd0c8d0da, 0xf492ee4d, 0x3bebab56, 0xa610fa11, 0x3b46aa73, 0xb9a0ad9d, 0xf25a694f, 0xa3c45b60, + 0x7d7c970b, 0x5fccf602, 0x4349e0bf, 0xed153023, 0x512f3bb5, 0xc21ad95a, 0x19c27a58, 0x49f1398a, 0x7989d837, + 0xc9a6226c, 0x8f00e284, 0x8b3bbaf6, 0xf67ba537, 0x29ac3425, 0x156b4495, 0x29096f9a, 0xe389307d, 0x62215f00, + 0xd48d32bf, 0x6c1f8a3d, 0x14b7e2f3, 0xcbeb71d1, 0xbded9997, 0xa409500b, 0xfe28d63f, 0xbc7649f7, 0x105bd562, + 0xe164c769, 0xce945902, 0xf8db2777, 0xa86ead87, 0x710bf19c, 0x5443219d, 0xc98977b4, 0xf8918811, 0xc124b706, + 0x996145a6, 0xbb573b74, 0x29ee1ee8, 0x1b8c1df4, 0xe6585944, 0xc0d91db5, 0xde35499c, 0x0af8af83, 0xb942f688, + 0x49c59249, 0x2232aa30, 0x6b84d667, 0xb7836911, 0xee42b2e2, 0x9e4a2f19, 0x125622b7, 0x147da1f9, 0x3a29f1f5, + 0xc46febc2, 0x10c37558, 0x39137998, 0xe42effa5, 0xa3c97a13, 0x4f48f6d4, 0x844e85e4, 0xfa8b2b0b, 0x63fed4eb, + 0x7a53f565, 0x8bd60496, 0x99a65956, 0x19878ccc, 0x0164ae49, 0x637e5d5e, 0x7f00156c, 0x91ccdc41, 0xe2662257, + 0xd3fec119, 0x77de22fa, 0x0d5e8b05, 0x7d1f7a13, 0xbda1e703, 0xe5c9d5dd, 0x69fc419f, 0x13bfedfc, 0xaae10cb6, + 0xf0744aec, 0x55a277f5, 0x78539c78, 0xecfad5d5, 0xda9e4a46, 0x6d17b9d7, 0x384e5dfc, 0x62a31052, 0x431b598d, + 0x865f90f7, 0xf1c012cb, 0x49fc2ad2, 0xe28c7397, 0x04e3d7d3, 0xc2c95dd6, 0x404b0f35, 0x1aa9d108, 0xee474d3c, + 0xb859030e, 0x58ecdbe6, 0x05cd7792, 0xa031f730, 0x172bec35, 0x0801dbeb, 0xfc42117a, 0x58a37c51, 0xf8f95d6b, + 0x5beff029, 0x2cc44095, 0x0a609a24, 0xe8a19334, 0x8906639b, 0x4a5137f5, 0x220f9cfd, 0x5e6ef29b, 0x1c963ad8, + 0xea682aaa, 0x4acd39d0, 0x5c48f2d5, 0xfc327a25, 0x2f841f49, 0xe126d9d3, 0x72659669, 0x4aa9090c, 0x162fa6ee, + 0x4158f523, 0x5e3ef6de, 0x412abdb6, 0xc732cd99, 0x6472dcc5, 0x9fd1937c, 0x983b76d9, 0xf3d15adb, 0x36c78dee, + 0x6c20e3d9, 0xe344d28f, 0xaf474be1, 0x9772052f, 0x2db0d013, 0x77558dd1, 0x92e9a135, 0xbcb94a98, 0x54e06205, + 0xee06c3db, 0x65e4940b, 0x9ae54773, 0xf9fb4f96, 0x54cfe1b9, 0x52daad88, 0x35272be4, 0xe38d35ca, 0xf9ee6af9, + 0xbd308f6e, 0xf565d2e4, 0xa9b181e2, 0x8f83fad6, 0xa887a08f, 0xc9fcadda, 0xfc7b5d21, 0xcbf6824b, 0x6e872c88, + 0x08b1cd5c, 0xb2cc2645, 0x8a8c4196, 0xbae3d250, 0x5beedea9, 0xebd0ff01, 0x6e24eea4, 0x3eff7429, 0x7e2a2653, + 0x8645bd22, 0xa6d5bda1, 0xc02f75ac, 0xed261dfc, 0x7f76ce9c, 0xcdac6906, 0x0a7eb46d, 0xdf808b77, 0xd770c4ba, + 0xcc5353dd, 0xfd2c08cc, 0x65e88519, 0x7d4898b1, 0xb490c194, 0x07755768, 0x94e3fc6c, 0x6fe2378b, 0x7bff77e9, + 0x6308fad0, 0xee74827e, 0x4b5d9087, 0xa34be938, 0xfd320a37, 0x914be728, 0x7b6854b0, 0x0a968fad, 0xc369e55f, + 0x4d8a248a, 0xdce28b63, 0xe00de9bb, 0x53f87fb0, 0x2f5e6f12, 0x5742f9cf, 0x7b5161ab, 0xf7518929, 0xc880bca6, + 0xdb6c7f23, 0x6cffae31, 0xfb882c74, 0x3fd960f1, 0x505edefc, 0x44588cb6, 0x0c430604, 0xc14c6d39, 0xbadce9c1, + 0xd426e32c, 0xeafc49c4, 0x04c2c9be, 0x1b91b9c3, 0x12507f2b, 0xcdff114d, 0x971bfe72, 0x5489c2ff, 0xe33cfc93, + 0x7f6e96d7, 0x7adc94ec, 0x62e9fe79, 0xcd617801, 0xe9381623, 0x89619707, 0x8ff24973, 0xb9682714, 0x3b608880, + 0x805f1cd5, 0x7bd6d007, 0x62f414a1, 0x74b05392, 0x8371f590, 0x86594819, 0x86933249, 0x186ee98b, 0xec1550ff, + 0x8349184b, 0xd2243d7e, 0xd0485af1, 0x67078d11, 0x6b95275d, 0xa5d737ec, 0xbd4e07c3, 0x0e5e0b26, 0x945e2cae, + 0xdd7daef1, 0x022c7a2f, 0xeb6b8cd6, 0x284bc377, 0x740f7745, 0xe921563b, 0xfd8bc566, 0x067bdcb8, 0x4fd91418, + 0xfad8141f, 0x89f23bb1, 0x67bdb7a6, 0x213ace90, 0xe9d89160, 0xc9f3fae7, 0x6a0e4865, 0x757fef91, 0x445c61eb, + 0x822ad358, 0x355071cd, 0x429247c1, 0x97458f01, 0x84f82e2e, 0x81c7bfa6, 0x5408f355, 0x0aaea394, 0x07b8916b, + 0x4a4ff2b4, 0x56d5fbec, 0xba4bd7cd, 0x2ff77edc, 0x8dbf8bdd, 0xf2c12fde, 0xfaf116c6, 0xa67f1f77, 0x3048c108, + 0x71f76e1b, 0xcf4b6a23, 0x485c8ddc, 0x2d673cb1, 0xb6932b50, 0xca03a8ad, 0xad3584f7, 0x732fbb57, 0x75204ffa, + 0xd885d06a, 0x54ce36cc, 0x891efe37, 0xc8094ce8, 0x9309638e, 0xa67999b3, 0x13f517a0, 0x07cfb9ad, 0x1e12c9e6, + 0x8a3d242c, 0x06f9e62b, 0xf7e89569, 0xdc26ab49, 0x980f87c0, 0x8a662643, 0xb6a80f25, 0x1d877eb8, 0x7f347898, + 0xd5c0dc91, 0xedb56c83, 0x31e18e3a, 0xb3b2cb8a, 0xaa025285, 0x173f5171, 0xdc6aa954, 0x35c8398e, 0xb6031c39, + 0x404bba76, 0xae4919d3, 0xbedaaf1f, 0xc37d9a54, 0x813f478e, 0xd3801619, 0xad29c1df, 0xd68e1143, 0xe8bc0c70, + 0x513ffee4, 0xc3ff5f19, 0x422fbee2, 0xc48dc0f9, 0x1e708d2f, 0xbb44b00b, 0xb052219b, 0x284c8244, 0xcd998424, + 0x44a42cad, 0xfa7faa81, 0x5c04a9e1, 0xe086efa4, 0xd43399ab, 0xfba43078, 0xd2b081df, 0x54ab7f85, 0x6965e29c, + 0x70894a65, 0x57336996, 0x1c1d1ce0, 0x80b3944f, 0x46c6202b, 0xd3e7c90b, 0x6a86d9c9, 0x30462c43, 0xd79a8db3, + 0x10af7239, 0x6979bc16, 0x659bb567, 0x8b0642fe, 0x784e473b, 0xbcf0567a, 0xe1f07337, 0x39323233, 0x0d8efbce, + 0xc763cd44, 0x37940951, 0xfa118a7f, 0xa03046db, 0x1bc13b51, 0xc24a5db5, 0xdfe9312e, 0x00220f16, 0xe5d91e1a, + 0x35438e02, 0x1d1b41f1, 0x2e483a33, 0x2e00698b, 0x4dd10585, 0xf51327a6, 0xd038ad85, 0x86070183, 0xb34f9099, + 0x27a4c553, 0x995e5f38, 0x42b36584, 0x463f6410, 0x168d3273, 0x6e0fe70a, 0xf38aee92, 0x3b1317bb, 0x1c3ee3bb, + 0x2a2bb18b, 0x32272006, 0x14a71470, 0x94244b21, 0xe9ef2ca0, 0xa20a6ecc, 0x13206cf4, 0x54606d9d, 0x02cbbbaa, + 0xaf8cfa18, 0x43e28da5, 0x76c8aaf5, 0xc4738569, 0x7bba0422, 0x17f47430, 0x1de1e536, 0xffe31fe7, 0xeea64e6d, + 0x5e0a7b75, 0xf9a6dfe8, 0x13010634, 0xab657b76, 0xf1253e34, 0xb81b0684, 0x57f76882, 0x774437b0, 0x70b736c6, + 0x8b7270d2, 0xa61f31fe, 0xad763188, 0xad5a5fda, 0x2df7b88b, 0x33d5bcb9, 0x9550f7a9, 0xaaa0229d, 0x28e88acb, + 0x9234e5e5, 0xd01965b8, 0x08027ba1, 0xd32afaa4, 0x53894061, 0x0429b755, 0xf3b82731, 0xfd767200, 0x998a6421, + 0x68d68956, 0xdd3c6cc1, 0x29a04b23, 0xf97adae1, 0xbe021251, 0x8c46b675, 0x058fa5f7, 0xe436ee1f, 0xb8276afb, + 0x74fbbbae, 0x413cd2a8, 0x6ab94340, 0xd83ed371, 0x92c96626, 0x6d9bd129, 0x930c7f6f, 0x6381390f, 0x3a8c725d, + 0x4727b343, 0xcee730bc, 0xe937929b, 0xf53c201c, 0xc163c8b7, 0x9b1d1b5f, 0xcb657bb9, 0xf900e1c3, 0x119fb088, + 0xb58a34c1, 0x4bbe3514, 0x7af97f64, 0x8f146c23, 0x9ed6cef1, 0xd2c8d79a, 0x30261411, 0x1c97bee9, 0xfaa14760, + 0x0ba71c31, 0x347a36e1, 0xb74910ff, 0x7393cd94, 0xd2afc544, 0x6c4db6f3, 0xba51e12d, 0xd3049ca2, 0x1aa92c68, + 0x266f5bfb, 0x9c2af0b4, 0x77b64f9e, 0x4fd7269b, 0x86615c7f, 0xdebdbd83, 0x8cda3c6a, 0x0a7d79aa, 0xd56c5f0a, + 0xd8c4e56e, 0x4d0a17bd, 0xe33938ea, 0x35722e8a, 0x16bb769c, 0x5fbe5d6d, 0x5aafdaaa, 0x159175ff, 0x2722a46e, + 0x4be492ee, 0xc3fcf92a, 0x13e28dff, 0x7298e2be, 0x8a5ace20, 0x9f160c99, 0x6f5015f1, 0x30b1182f, 0xfdd63e1d, + 0x48ae5d54, 0xe42af1e3, 0x8f8911dc, 0xecf5c962, 0xf06b83de, 0xf572d6b7, 0x3c13d9c4, 0x6d8a2300, 0x6bb35a10, + 0x38fb2fed, 0xc746f6f6, 0x22eb20c9, 0xda3109e8, 0xe6145eb1, 0xa3b00199, 0xc8591951, 0xe930d99f, 0x6618205e, + 0xf7534777, 0x1430e198, 0x3cf2a376, 0x75c9a111, 0x16ef3387, 0x4d279576, 0xef0ca591, 0x42dd6f81, 0xcfe32141, + 0x235394c2, 0xd3565c4d, 0x1807c7a4, 0x2c036ca3, 0xd560e9a9, 0xe1cdd7b1, 0x0c8d0e92, 0x85b8c61c, 0x41a65c9b, + 0xd6e2ed83, 0xbd2a1f05, 0xca5cc960, 0xa3324b02, 0x3197ff00, 0x8f38e69c, 0xf74c8773, 0xd677fc90, 0xdea10704, + 0x7ff0423e, 0x86854dd4, 0x49b90a88, 0xf98dfeaf, 0xee001370, 0xa0862e8c, 0xfc6f90c4, 0x93c94796, 0x66fc7336, + 0x2654161b, 0xb5c1af4d, 0xc15ca32e, 0x26ee653e, 0x16d7c542, 0xaaa6b414, 0x09a7883b, 0xd94a6986, 0x8737dcfd, + 0x97d2625a, 0x0cf1c7e0, 0x97fd0d74, 0xd925bd08, 0x67ee020b, 0x19342be5, 0xe8e828ab, 0x1d892597, 0x141d1c5c, + 0x71186b1f, 0xf897d223, 0x70ffe534, 0xf9b811e9, 0x18b2ddd7, 0x3d74efc2, 0x19df61ed, 0x4d488d0b, 0x4c09656a, + 0xc83711c2, 0x724184c1, 0xef3c6620, 0x94d97bf3, 0x0b17b7bb, 0x4d8086c6, 0x6bb11ec0, 0xd52852bd, 0xa296bc26, + 0x04dd02e9, 0x4bb86d8e, 0x153a3802, 0xd2fb89d9, 0x534a50d7, 0xa60df23f, 0x42ba4cbf, 0x4fa430d3, 0x25b3da41, + 0x004231ed, 0xc19b2616, 0x3eeb646b, 0x85b22227, 0xccdf1ab5, 0x6c2309ec, 0x8a0af86d, 0x3843bc2d, 0x6f83db6d, + 0x1565c15f, 0x3c117e2b, 0xcddaae16, 0x5cf3a105, 0xf1c766ea, 0x4f79f406, 0x2a76f1bd, 0x8aed4525, 0x9fa34ff8, + 0x3fd79236, 0xf7027e0e, 0x726288c1, 0xc00e7cc3, 0x9ccbc366, 0xd931bcea, 0x2d61be3a, 0xa3ce50b8, 0x1923d306, + 0x0d68297e, 0xfd74bd94, 0x5345914b, 0x4b3c5a51, 0x7588a424, 0x097fdc50, 0xcd6b046a, 0x53b39441, 0x03083f35, + 0x8fa6ec26, 0x7bc65a0d, 0x9c075034, 0xe0aa8749, 0x44bd00dd, 0x8f286836, 0xe69ab4ff, 0x0681a0a6, 0x2af40639, + 0x760a060d, 0x13c57db8, 0x24c26672, 0xbae060c3, 0xffb7d395, 0xd4b1f494, 0xbb1a905b, 0x65986f5b, 0x1653c1b8, + 0x5605daeb, 0xe0880f7e, 0xe218aba9, 0xd77477ed, 0x186cd7be, 0x002fa538, 0x2ccf01ea, 0x166f8a89, 0xd90ed1a3, + 0xe300ffe6, 0x3dc3ae58, 0x301ba64f, 0x345f7e34, 0x78edf844, 0x17a23ce7, 0xa4781b4d, 0xebbdb357, 0x0b960aa0, + 0xee63c1ab, 0xa4ca057f, 0x9699c00c, 0x441f6545, 0x9fa6baed, 0x635fed86, 0x9cbedc7a, 0x7dc148be, 0xa1f06d81, + 0x6118a206, 0xc6155f8c, 0x4d185e77, 0x63f8913b, 0x15621d0d, 0xef152c58, 0x9e0e93d0, 0x532cd706, 0xc6ce8ac9, + 0x5c4006ba, 0x2c6e1bcb, 0x6a907056, 0xea84dfcd, 0x6f93d855, 0x34dc4d1f, 0x4dc77b62, 0xa7d4a8b4, 0x7e00250b, + 0xfb02fa58, 0x0c2da933, 0x435fb3da, 0x82cf2875, 0xf663d1bf, 0xb44a6e45, 0x46f6918b, 0x6e731117, 0x84169048, + 0x72e621ac, 0x5419191e, 0x2ac745f8, 0x7b9de817, 0x2361581f, 0x0d468227, 0x900d77ed, 0x3e4ed9ae, 0x516f5fa5, + 0x51cfe4a9, 0x443d7e45, 0x6306fdd5, 0xdab4ea97, 0x30cd08a0, 0x9d821f6c, 0x82ba0b51, 0x96fe46c8, 0x83d49a6e, + 0xf2d08541, 0x8b6aad93, 0x474f6695, 0xedc5bb13, 0xa575361c, 0xb4557417, 0x6ecb61a3, 0x84f7e60c, 0x4a0f5163, + 0x8cdcb3d1, 0xad9124c0, 0x890c3d9e, 0xbf169b3c, 0x720e7602, 0xf1fa54e1, 0x6b818d42, 0x44d8e955, 0x86664bc6, + 0x90377c22, 0x22382fbe, 0xccf418c5, 0xf838c0dc, 0x946b1d66, 0xc11be40a, 0x7a151938, 0xdc4336c2, 0x28c43eb2, + 0xc1f12298, 0x98cd9669, 0x166880cb, 0x84cffc47, 0x37c84d89, 0x1889a4cd, 0xdf2ce016, 0xded06116, 0xfae867c5, + 0x8d23d06b, 0x827dacf8, 0xfd11d25f, 0x68485ddb, 0xed506883, 0x43c5e555, 0x0330a16f, 0x3f7576af, 0x5f70c716, + 0xf298b8ce, 0x9e1df62a, 0x46fa9d88, 0xb06e68d0, 0xc3803412, 0xe8ba5d5d, 0x615d8c71, 0x1b0d6c3c, 0xb638706b, + 0x187d6983, 0x0e33f64f, 0xd9dd7778, 0x12410a8a, 0xcef7eda5, 0xfe74e21e, 0x60b70fc5, 0x8ed94fa2, 0x6cfde259, + 0x8058b411, 0x1ca93807, 0x19625c5a, 0x34215cec, 0x165baddc, 0x0ab44f83, 0xa6363e74, 0x3f7a766a, 0xdd702a61, + 0x3d0ca687, 0xd0909c3e, 0xdc7f7712, 0x3d9001ea, 0xc5d19495, 0x8017b1f6, 0x65da0eed, 0x0d030d48, 0x998c10e6, + 0x06f1c97d, 0x35204b05, 0x1c0da754, 0x777b48fe, 0x01521640, 0x203bfb59, 0x25e83cfa, 0xa3d40b91, 0xf396bd60, + 0x093880c7, 0xd5a77950, 0xe06ddcac, 0x87936f25, 0x12c7d991, 0x16103a0f, 0x4a1ee98c, 0xf70e1c84, 0x2f3f894e, + 0x176c0300, 0x34c08cc6, 0x89eff014, 0xb7d5666e, 0xf7636a27, 0x128ece3c, 0x71e7ddb6, 0x1070d4aa, 0x2dab9a05, + 0x3cdc279b, 0xe88781cc, 0x2771abc8, 0xf01d6e74, 0xe8cc296b, 0xeaafe927, 0xa3b3e542, 0x872acfc7, 0x4033a228, + 0xa922a98c, 0x82b18f3b, 0x6d5efbb5, 0x31d13a83, 0x6c4a1b1e, 0x7d5df44f, 0x539dfd5d, 0xda1e186b, 0x60f6948d, + 0xb4c2bb13, 0xa903a2c4, 0x76a5595b, 0xb85fc368, 0x87e3c57c, 0xeec8ee07, 0x39f42e4b, 0xdc13d659, 0x03ac1daa, + 0x123bab9d, 0x7789dec0, 0x5dba0ba3, 0xcee72d9f, 0xea4aa38f, 0x315633a7, 0xff276fb0, 0x0468ef67, 0x7fb82124, + 0xeb586ed5, 0xcdadda70, 0xb37e12d8, 0xe4411b87, 0xc740e4f5, 0x41ca5e11, 0x8e54997b, 0x023d8b2c, 0xda4cfb4e, + 0xee115485, 0xf9a61a29, 0x98aefaa4, 0x2523432a, 0xcfa165ae, 0xc2b7231b, 0xb3270878, 0xfcd8b8ca, 0x75130771, + 0x016f68fd, 0x67de40fd, 0xc18dd8a1, 0x1930d5ab, 0x073fa402, 0x373ce4a7, 0xb1d4f0e9, 0x9421fdbd, 0x2bb5504d, + 0x37cd1199, 0x6b0fe74a, 0x51dc19bd, 0x91782c2a, 0x510cbfc9, 0xb85063d7, 0x02f51134, 0x1a164af3, 0x94079806, + 0xc94ece34, 0x9694ad5d, 0x039fbc50, 0x0c20c19a, 0xe646ff4f, 0x6ed8c722, 0xf6b19be7, 0xcee7cfff, 0x930c0497, + 0xecf138c1, 0xa7619ca2, 0xb4b4a98d, 0xa3dae328, 0x5a714111, 0x9e572e75, 0x40c91390, 0x47ec08de, 0xe0a42315, + 0x937bf008, 0x07afe71e, 0x99eed66a, 0x17897c8d, 0xd1397e5a, 0xdf6cc230, 0x24848c79, 0xf45201de, 0x6c8c383e, + 0xa985a3c6, 0x00a89e6a, 0x82f1ad0f, 0x407d6e58, 0x54332829, 0xdcec5f28, 0x8f7a7613, 0xe0f0eef0, 0xd324b550, + 0x575ada95, 0xeb54c495, 0xc91295de, 0xf23ac92d, 0x4cd93034, 0x0f8346c5, 0xd7967fa7, 0xd60d4737, 0x11059a87, + 0xa960f675, 0x273a65a8, 0x43e046ff, 0x671cf2a4, 0x2efe1550, 0x65fa1c35, 0x458abcef, 0x13084e27, 0x61857353, + 0xbf197a26, 0xc50fd2ae, 0xd80ba4ab, 0x70d1c0bb, 0x429aa505, 0x2a52ce85, 0x95d4f3a8, 0xfd3120ca, 0x2f4a0833, + 0xee990753, 0x73d0f33c, 0x9a431384, 0xd5a0d805, 0x7fa0d95e, 0x89471774, 0xc2d86118, 0xc655cd3e, 0x9d33fa9a, + 0x173fff8d, 0x9c742927, 0x2c85a838, 0x6e294780, 0x3d80444e, 0xef215f0d, 0x491842a7, 0x2b79dc6b, 0xac58f012, + 0x9867640a, 0x57972d1f, 0x23e3bf51, 0xcd68dd74, 0x9b5c6b4f, 0x74c53647, 0xe85ef904, 0x113e78ef, 0xba43e6e6, + 0x5d0a381a, 0x020b477f, 0xac59177c, 0x026f5099, 0x00f57686, 0x41fb6e86, 0x7e7544d2, 0x8ce2205d, 0x154b4834, + 0x3e32d867, 0xabbe29a1, 0xb3b3e0ff, 0x45eb03dc, 0xd2cacac4, 0xf0a02058, 0x2b018327, 0x7ef5a280, 0x5e52e26c, + 0x93885618, 0x11f9d421, 0x6c351fed, 0xcfd19ae2, 0x73ff6e88, 0x23666077, 0x8493fce9, 0x1955a263, 0x10fa7afa, + 0x0f8bef16, 0xf505ef6a, 0xa750da59, 0x31e36c4e, 0x0e9e529b, 0x6d06c98c, 0x4b41c908, 0x5f7b5c9e, 0xade8b1a3, + 0x848b70d4, 0x2dc440af, 0x54f6b8e0, 0x98bdf486, 0x2b17d2f8, 0x7e78851b, 0x517823a6, 0xcb5cc59b, 0x9d121d60, + 0xea084c6a, 0x7ec5aa65, 0xb5191866, 0x89d67170, 0x93dc647d, 0x82b69221, 0xeaef2941, 0x5fa16e6e, 0xcc0e01d9, + 0x086ab056, 0xf6148c5d, 0x02b73a54, 0xd4a3e0e8, 0x92547049, 0x196cac3c, 0xf8c5aac2, 0x6fdd96a0, 0xcc70de96, + 0xb20e6945, 0xc4b56fe6, 0x89550e08, 0xa72afed7, 0x223f64c8, 0x4ab4b753, 0xee90b0b8, 0x197ff3e3, 0x22a7b3e7, + 0xb8d0bdfb, 0x4bf61271, 0xeece4557, 0xd9d2adc7, 0x1d3ee790, 0x34b1e15d, 0x88d94055, 0xb09344b5, 0xc9262533, + 0xfe221ec5, 0x0a0f7ae0, 0x9d2b150b, 0x009f1c48, 0xe4753351, 0x559e262f, 0x6179e28d, 0x2925ef85, 0x62708e4b, + 0x9ef5e74c, 0x0a95bbc5, 0xa3377372, 0xd4b99a0e, 0xd2b5201a, 0x8c1017d6, 0x6cfda941, 0x71b041a2, 0x93b91828, + 0xfb1d1a20, 0x8836c83d, 0xdac511ed, 0xe5943da5, 0xdb4d42c5, 0x3265d3ca, 0x3320d07e, 0xc04de17c, 0x5ca6b8e1, + 0x1ff9a41e, 0xe04660b8, 0xe979d3ec, 0xb39c8047, 0xa88ffaef, 0xbdf6da7e, 0x0124b958, 0x7dd88383, 0xeae1e3ef, + 0xd73afd1f, 0xc70fc53c, 0x5767cca9, 0x72c7a0bd, 0x9567acf0, 0xa1152406, 0x34a1109d, 0x1528dec9, 0x9fa7bcd0, + 0x73efccce, 0x0b789027, 0x426da0a6, 0x8f114ead, 0xbf228a69, 0x1f9ca904, 0x3dd23b63, 0x2923c2ee, 0xd045e7a5, + 0xe478669b, 0x850c98d6, 0x13e59302, 0xe869d430, 0x7996b811, 0x43001e7b, 0xe0932c9a, 0x637b94ea, 0x2e51a39a, + 0xd73a59e8, 0x4012e6f3, 0xc766d850, 0x92db3d30, 0xdad450f8, 0x4854dcf8, 0xb117549e, 0x1e9271a3, 0x7e3d3fe8, + 0x9c8282b6, 0x88f8fad7, 0xdb46af94, 0xcbe50bf3, 0x5eefe7c7, 0xe06b25aa, 0xb1a41a67, 0xb926a2e1, 0x1965dbfd, + 0x9e0bbf95, 0xd18171b8, 0xa525e61e, 0x3fb72057, 0x87a03655, 0xea0bf35f, 0x01ab1aa7, 0xf707d1ce, 0x440beb68, + 0xfc2870b4, 0x0e8d6843, 0x1be911f9, 0xe9839e0c, 0x9691535c, 0xcd28bf34, 0x3b0cfcfb, 0x99ebd6c6, 0x4c0812db, + 0x873d8362, 0xa22183cd, 0xec6048ad, 0xfe95dd7b, 0xfe9f340c, 0x9d3278e9, 0xf4ea2bb6, 0x12af9311, 0xd3bca0e2, + 0x3ea654e2, 0x38f56b91, 0xaae6068f, 0x6b84e4b0, 0xce8f0967, 0x47d38543, 0xe913df29, 0xe937f6c6, 0x783d6b0a, + 0x7fcf1dfb, 0x462fc09c, 0x805811cf, 0x879baac7, 0x4a33f8ae, 0xcbce6734, 0x87aacf29, 0x1027b540, 0x01523b63, + 0xed76d5a3, 0xbfcc85ae, 0xd08ed0b0, 0x324653a6, 0xf2280154, 0x1758a4b8, 0xef8e4a73, 0xa51591fb, 0xf013391b, + 0x9341396d, 0xe5ffc7b8, 0x23daf1b5, 0x72397f06, 0x018ab35c, 0xe862a5f0, 0x375a1af5, 0x3bb08cde, 0x35a26fdf, + 0xe426e6ef, 0xa9b21d86, 0xd3f98232, 0x89297e0b, 0xa9f0d8b3, 0x57de0af5, 0xa58e1427, 0xbe758737, 0xda15e74b, + 0x29b615c7, 0x1ca1486d, 0xd68aa0a3, 0x5d7cc2fe, 0x08f275cc, 0x356be6a5, 0xf72253c7, 0x22487b39, 0x07254add, + 0x217fb71b, 0xde004c4f, 0x11d00b01, 0x0167830b, 0x565984bb, 0x3e336a70, 0x12bbbb84, 0x85360394, 0xa67eec6c, + 0x574632a2, 0x3fda316d, 0xa8617716, 0x75b9332c, 0x4d8b6a98, 0xe6cfcfc2, 0x5834c3ff, 0x8b312ff8, 0xf4e596af, + 0xd7c03998, 0xec723bc6, 0xe62f1962, 0x85fb402f, 0x5cc9948c, 0x59cfac55, 0x68528eee, 0x875f70b8, 0x7b28094d, + 0xd0f8fca1, 0x72771a92, 0xb51c24e2, 0x1257d17e, 0xa646ae5f, 0x75171beb, 0x212297bd, 0xbfaa9ecd, 0x518c1d65, + 0xe09f7b6a, 0x62ca5758, 0x4442d549, 0x13f67d83, 0x695a59ff, 0xce62eaa2, 0x1de98a77, 0x38149cd7, 0x21d16739, + 0xe7c4a6ff, 0x64a08652, 0x496af47a, 0xf8fab8e1, 0x3abfa465, 0xc9902c26, 0x1ece20d4, 0x6d8d3b31, 0x779584cf, + 0x5d27b862, 0x47f329a6, 0x70aaff3b, 0xfda9db92, 0xaf30ae9b, 0xe4da8c2e, 0x01958b93, 0x4c612363, 0xa04ff51c, + 0x79ee4079, 0x612d503f, 0x03eadf9d, 0x1a0b270e, 0xfecde124, 0x7310320c, 0x4b5ba089, 0xd9b685fa, 0xe1c550b2, + 0x04e9af67, 0xeca9c9cd, 0x8da38f2a, 0x4f9614ca, 0x4b5dc145, 0xd11eeb3d, 0xe6fb9347, 0x179c060d, 0x2d3b49bb, + 0x63ada9c7, 0xa16aef66, 0x0cdd20b9, 0x529d9003, 0x5eb0a267, 0x9347b3fa, 0xf7ded177, 0x3f7d675d, 0x7d75fdf3, + 0x8a030e34, 0x67edd63b, 0x3d6e1f72, 0xec49614d, 0x0d8c5075, 0x74f4a8d3, 0xdf3aac4f, 0x524cb87a, 0xc14fefe7, + 0xc463e881, 0x528b3e91, 0x98e68da4, 0xfd6f71e6, 0x1b12b7b9, 0x662d3844, 0xeac7e74e, 0xe49165f1, 0xf27c697c, + 0x0db04844, 0x619da7fb, 0x589f0285, 0x05cfce0f, 0x8df4249c, 0x2a9d03c3, 0xd1b63979, 0xb5e611ad, 0x4b624e97, + 0x43b79c8b, 0xb8672abc, 0x6e409ba6, 0x4911d9c0, 0x6e62f54c, 0x5a34e837, 0x431226c7, 0xf1c8e58e, 0x335e8461, + 0xc69aab2a, 0x78da21d6, 0xef7440ca, 0xbbd31419, 0x69c1e0f1, 0x63fb6711, 0xb486ff06, 0x78bbace7, 0xdf9eb77e, + 0xb95e8eb3, 0x1e55c898, 0x688c9280, 0xebc41ce1, 0x15cafcd3, 0x8abeaf4f, 0x41e89aa4, 0x23e0604a, 0x9aa45138, + 0x9b68bba8, 0xfe01f604, 0xb53bdbe6, 0x358d0dd8, 0x861a8d09, 0x2b6c7dcc, 0xc846cd56, 0xdd31d254, 0x1877d814, + 0x02f326d6, 0x3e41e83f, 0xb4e152a2, 0x710a1c4b, 0x226ea66f, 0x9293c4dd, 0xbe688b18, 0x82ffab5c, 0xb0fad8b5, + 0x03a830ab, 0x18091aa7, 0x9c43ab9d, 0xfaedef03, 0x9bd475ae, 0xdc3cc059, 0xe27cd917, 0x9f490c89, 0x5fbc5499, + 0x8d256721, 0x8ebf723f, 0x1d2e552e, 0x566400f5, 0x2a4ba337, 0x749ba79e, 0xe9bc98b5, 0x9fe58cc2, 0x950129be, + 0x975323f4, 0x39870aa1, 0x6d567d5b, 0x220738ca, 0x3a269567, 0x3ca5e8be, 0x26765f46, 0xae5311b3, 0x4a55eb7d, + 0x9dbe16e5, 0x46b66b22, 0x3a5efb7d, 0x5d2e1b22, 0xd4d2b098, 0xcaa1428d, 0xef343ed8, 0xb8ec2504, 0x5e8a79d9, + 0x37acbb9b, 0x8a1aaef8, 0x87d7b975, 0xbc4051d8, 0xcbb2d3b0, 0x20cac3be, 0x92017c09, 0xa316da5c, 0x587166b1, + 0xbde4e95d, 0x05833949, 0xf99a1342, 0x0e58c99f, 0xfdc38665, 0x4edf47dc, 0x438678ce, 0x74afff8b, 0x6ad5010b, + 0x10964482, 0x556f1c09, 0x8cf2ea71, 0x5389a76c, 0x8b396a02, 0x297dce9c, 0x7fad20a5, 0xf8aa1da8, 0xc7c08827, + 0x5e006629, 0xcdccdfa3, 0x9c2d4c13, 0xd74d7e6a, 0xd7ab382d, 0x58e3db43, 0x9539cdc0, 0x3e5ab335, 0x37321238, + 0x0acb5de4, 0x3976c379, 0x03803866, 0x555115c2, 0x5e1de1d9, 0x0635798d, 0x14b78615, 0x3eca9c73, 0x42a67320, + 0xbd204f7d, 0x8ce3c9ca, 0x8c1b848a, 0x1e4eb33d, 0x53827415, 0xaade51fd, 0xadbae86a, 0x38a033a8, 0xf2006045, + 0xb9a28f19, 0x2c8e763a, 0xa4b37180, 0x7a55e7dc, 0xf4732a1b, 0x72d0bbfd, 0x5da1dbc6, 0xe19d8b0e, 0x665cb961, + 0x01ed5109, 0xa84306ab, 0x0b22b1af, 0xace6b6aa, 0xc7df48c6, 0x291df667, 0x50ab2863, 0x1f4f708f, 0x6f3f902a, + 0x996fe2b5, 0xa4de7e62, 0x9d764356, 0x42be08eb, 0x8d69ebf8, 0x10ccd93c, 0xe431a555, 0xb25a7d1e, 0x918b5e48, + 0xc671b1e0, 0x93233dd7, 0x0ddad64b, 0xb30ffc9e, 0xb52cdc21, 0xe674c32c, 0x42c01af6, 0xc1c08600, 0xca649a0f, + 0x411ff5e5, 0xf68284f6, 0xbaa0e4e2, 0x9e8bc22c, 0xa5bae69d, 0x3b1b5307, 0xdbbac756, 0xaf548d19, 0xcdeec2c2, + 0xd9a5103a, 0x3cebf639, 0xe782394c, 0x61e3fa2d, 0x0d050246, 0xe2b28258, 0xd2e71d88, 0x9a7d5a20, 0x8e510f9d, + 0x703bb2a6, 0xa89b6aa1, 0x3bb0b2d6, 0x9183a3d2, 0x2ac8e9b6, 0x78900b4e, 0x94a077e5, 0x6fd7480f, 0x8c6a4121, + 0x46285c3a, 0x3ad711a3, 0x30a99e73, 0x5f46411f, 0xc7b790c5, 0xc02ce18b, 0xb32623f1, 0x20ba826e, 0xcbeb5b18, + 0x5ae4d94b, 0x703abe4e, 0x522453ae, 0x401bf49a, 0x5b26bbee, 0xa3edd330, 0xf0bb29a4, 0x2fbd792f, 0xce3efc8e, + 0xa0a84e7e, 0xba4405b0, 0x1744e0b4, 0x2c02a3de, 0x14b52977, 0xd2641c20, 0xfb9455d3, 0x68af6c53, 0xd4c0e45f, + 0xc7c433fb, 0xb6c360f7, 0xc5ff2a45, 0x2b8ff8b6, 0xa94f3f45, 0x53aa867a, 0xb4470875, 0x7dad5823, 0xac4b193c, + 0xac85cc00, 0x02c9ff4c, 0x3d9e2873, 0xf283e05e, 0xa03e01ec, 0x10903df0, 0xf07ff7a1, 0x90eb7104, 0xf7f4a903, + 0x6effdae4, 0x2d0db930, 0xbff3a81d, 0xf4bf5666, 0x97cfadcc, 0xd6f26367, 0x99d79097, 0x4df7e07d, 0x54827302, + 0x3a7c5e47, 0xa5868602, 0x2ba0a9f5, 0x09a9ba17, 0x4609c39f, 0x1ccee71a, 0xcb976a66, 0x3f1123b0, 0x244e3e78, + 0xa5b90431, 0x60af94c3, 0xa17897bd, 0x6c3e4ca2, 0x72f730a3, 0x13b3374e, 0x757aa2dd, 0xeea8c751, 0xccbd62f2, + 0x0233d287, 0x84ace1cc, 0x6d3470a5, 0x932ea574, 0x8ff6e96b, 0x8ee48ddf, 0xfe7bd716, 0x21ad2177, 0x8143820f, + 0x857e0440, 0x6510354b, 0x566edb0c, 0x6fbc8236, 0x7e3f0c31, 0x29f2e083, 0xca96326d, 0x9615f577, 0xe53c5e74, + 0xbb5d484d, 0x148b834c, 0x2b5fe681, 0x21fa9382, 0x51af8936, 0xf46e7d41, 0x4d9dfb93, 0xc6c2aae0, 0x2fa69285, + 0x8e28feb4, 0xf243790d, 0xc9f63860, 0xe3eb2d08, 0x55651524, 0xd8dfb055, 0x5b448984, 0x9036812c, 0xb65e07fc, + 0xe5b42d17, 0xf57c55dd, 0xa311a3eb, 0x6d3e9141, 0x92628cf2, 0x239fc67d, 0xed11c5b8, 0x5fd0a98f, 0xdf515692, + 0x2b737287, 0x7dade8f0, 0x0f8302d7, 0x428a9c55, 0x455407f8, 0x08503541, 0x51458048, 0x8d5922d7, 0xcfc73d63, + 0xc01624f9, 0x866e0ace, 0x2595dbef, 0x01e7b1fa, 0x3f3ebb25, 0xbbb6b5ed, 0x1bb12d7d, 0x85c70f80, 0x15d2ddff, + 0x1019aaba, 0x26bde274, 0xc0dec7b6, 0x8d61752d, 0xec0cc8ea, 0x9b1fa79d, 0xfc7ed61f, 0x7da531af, 0xcb001b5a, + 0x832391b9, 0x1a244a96, 0x8174066c, 0x16b37829, 0xc1494290, 0x2afccc16, 0xdeec3585, 0x79d3bbc0, 0x35bf6244, + 0xadea72a8, 0x64d5cb11, 0xff9881d6, 0xcf9c61fa, 0x06a15b89, 0xb0088279, 0x17b3ea4e, 0x619f8304, 0x9eb270b5, + 0xed56dc6f, 0xe7f2e846, 0xff495ef7, 0xbe375fa6, 0xc957f986, 0x4af241a2, 0x2a6e75af, 0xb99db991, 0xf3ffa1da, + 0x1071077c, 0x8d2fc4cb, 0x9b6cc753, 0xd56a304d, 0x6f188a56, 0x4c77c251, 0x0d4592f5, 0xf915a995, 0x645f1f8a, + 0xdb52c4bd, 0x2f10904c, 0xa42fb181, 0x56d824d5, 0xf0f517a3, 0xf9287caa, 0x7324d21e, 0xc1a1bfb8, 0xb9240d24, + 0x3928de1c, 0xd35a414f, 0x83c7ef08, 0x45e0353b, 0x3d50718a, 0xd7fa215d, 0xcb74dfbe, 0xf1af2f70, 0xa90cee19, + 0x2b8372a8, 0xbbc493fd, 0x38120f60, 0xb5e5505b, 0x3c17b17f, 0x3b33ef05, 0x9e01bdb8, 0x25e3abc0, 0x891c8595, + 0xd73d971b, 0x459232e5, 0xfbeb731b, 0x9603247c, 0x94045cda, 0x13646401, 0x444a9f08, 0x4ac4eef4, 0x07ab6cc0, + 0xe2090535, 0x39ec20a3, 0xf7902a92, 0x10e25e44, 0x6e430e71, 0x6cc86168, 0xf77c895c, 0x14ac7225, 0x40143968, + 0x3efece1e, 0x88e7cef6, 0x14be04cd, 0x6c0c332a, 0x08fbe7ad, 0xeaf4e7e3, 0x81edefc8, 0xccbe51b9, 0xfa9dae05, + 0x1a5777c0, 0xc594937b, 0x39a575d6, 0x6d5f3c0b, 0xc331cfc6, 0x40da7921, 0x4b8e49e5, 0x72873528, 0xccbf92fd, + 0x2f55f0cf, 0x97535637, 0x5e0afa19, 0xd7af81b9, 0xf7719798, 0x383508a5, 0x10b0d403, 0x51b1871f, 0xcb806e1a, + 0x02dc18f0, 0xfa20bb6e, 0x1034e5bd, 0x456c3ae6, 0x8974e47d, 0xcd29d5f2, 0xb92eb8e0, 0x1c265da1, 0x62dbed9e, + 0xd97dda20, 0x98b7732a, 0x60b0897c, 0xa12c3a66, 0x62b85af1, 0xb04fc03a, 0xfe325d31, 0x6d248146, 0x3aaba608, + 0x5c85cbcc, 0xb4868275, 0xbdd01d19, 0x817be816, 0xd54f7eba, 0xc5e62496, 0xc554456e, 0x8bd30fe6, 0x4b38474e, + 0xe0140185, 0x1bf75062, 0xab23302d, 0x31b69bcf, 0xee1c73d1, 0x7d70b0d0, 0x0f6fe336, 0xade755b3, 0x182391cc, + 0x167504f8, 0x60c64afe, 0xbf11acbc, 0x414f3893, 0x16a64913, 0x457a0401, 0x5bf7b068, 0x24a673ed, 0xb11c1990, + 0xca6017b6, 0xb9bd2176, 0x2539c16d, 0xe489a74d, 0xac4062ce, 0xf6b3efa4, 0xe51fa15d, 0xd1790296, 0x219d0ace, + 0xf5c353a5, 0xcdb8a396, 0xdd48b791, 0x6a9a7b53, 0x0918724a, 0x04e39796, 0x6dc63829, 0x9988c6cb, 0x2c6a02b2, + 0x78407e3f, 0x5ec88085, 0xd6e6f886, 0x7f89f216, 0x261e4fcf, 0x84d97eb5, 0x33401ecd, 0xb8f43778, 0x6848a5f1, + 0xa9dcaeee, 0x9cb8364e, 0x70c9863f, 0xee4a5b9f, 0x61a7fbb6, 0x7d343969, 0x8e9f09bf, 0x7f04f372, 0x2636f0b4, + 0x6c4831a4, 0x2c43472e, 0xb6439bdb, 0x08905f0a, 0xd05b635e, 0xa3680d21, 0xc7def6f4, 0xc34c7ee8, 0x477ab0ab, + 0xfba11673, 0xd5a14ca6, 0x0aa009c4, 0x6ef9a2fe, 0xe20b0f52, 0x0ed103e3, 0xd52c7744, 0x08b9878a, 0x704337ed, + 0xdce41422, 0x62fef670, 0x33ce873e, 0x7e006179, 0x8fee1ac6, 0x3b0c006e, 0x0879e102, 0x24d59944, 0xb5e7e385, + 0x6ce722f5, 0xdb3284a4, 0xf15b6bf4, 0x293704b7, 0xc7b33a0b, 0x12c97879, 0x80a406a8, 0x77d7da6c, 0x1745acc9, + 0xafa94b3a, 0x7bd3dc35, 0x72d2e89c, 0xa2c9d253, 0x70cf7180, 0xf4861cda, 0x771da45f, 0xe6fb290f, 0x1788342f, + 0xf717b269, 0x37bf2c9d, 0xdb1f0553, 0xf3cac8f8, 0xa37630ac, 0xfc0801f8, 0xcd4c565a, 0x76e747b7, 0xd7a782ec, + 0xc3c7023a, 0xcdacccdf, 0x82c9d2fe, 0x1662d8a5, 0x2c3a4ed9, 0x448e0981, 0x9d83bd87, 0x253b4ef2, 0xdc272ae6, + 0x85d1e3fb, 0x47796899, 0xf7ac01bb, 0x1c807ea3, 0xdcd0c6ee, 0x3c291d7d, 0xcc1a3413, 0x001b1ec8, 0x2e04a12c, + 0x28aa41b8, 0x6c5ea387, 0x86145681, 0x7934f3df, 0xb5d404d2, 0xb6f48527, 0x9a054628, 0x3189f93d, 0x658961a0, + 0x6a67a0c1, 0x7155a2f7, 0xa6bea257, 0xfb193b21, 0x3084b844, 0xaed2b74d, 0xef1afca5, 0x6770c8cd, 0x09fb778c, + 0xfc0b8d3d, 0xc4b15f6f, 0x961241d0, 0x9fc6a5db, 0x7370af04, 0x29761dcc, 0x265bd685, 0x69e3e9c5, 0x3bd33359, + 0xd05e31c9, 0x29792d13, 0x6ec92cb0, 0xee128dbe, 0xd5b4768d, 0xac1f0b31, 0x7fc60ebe, 0x44520828, 0x55957e98, + 0x1e9fdd6b, 0x3dec9df5, 0x7994430e, 0x5e5fd14f, 0xd533a132, 0xb8ba9fda, 0xa5e26390, 0x90b9ce4e, 0xb26cfeaa, + 0x39cdbff9, 0x2500f9a7, 0x00b1f2b0, 0xb06b4d3b, 0xc0064b97, 0x57ad341f, 0x1c78650b, 0x48a932c1, 0x63fddbbc, + 0x179e66e1, 0x33177a07, 0x8e6c3595, 0x725cad5f, 0x8f006b8d, 0xb055eee9, 0xa48f08d0, 0xf4e93f58, 0xa3bd4e41, + 0x349e5b41, 0x6795c5e6, 0x70039ce5, 0x6e3910f8, 0xa26d7548, 0xb1ff1bd2, 0x16f5d6a9, 0x70f164cb, 0xba7aed1d, + 0xc01acb85, 0xff57b499, 0x91f85675, 0x5d734035, 0x4cbf6956, 0xabb815f1, 0x0a9462ca, 0x7bba0286, 0xebb6b61b, + 0x54d393c0, 0xb926ddca, 0x26d51708, 0x334e593d, 0x74840d92, 0x67ffdcaa, 0x0c3b9bd8, 0x24082421, 0x7d56fd83, + 0x1082dcbc, 0x871e1aca, 0x977936a9, 0x5620725b, 0x9f343be3, 0xb8e87e79, 0xf0f07f5b, 0x361175a0, 0x33d72138, + 0xb4cb973f, 0xec871b9b, 0x7ccf427c, 0x921a3df3, 0xafb2de79, 0x3188b887, 0xe81ebf0a, 0x7e6f6e6b, 0x2566a0db, + 0xa836c5e2, 0x070c7519, 0x47f2f683, 0x47a50f43, 0x69039f4f, 0x98389214, 0x546dd2ff, 0x12b9dd5f, 0x17747fa4, + 0xbdb04498, 0x7a79d1d4, 0xdee5b508, 0xf2c50eab, 0x9cbd5a32, 0x2d0295ac, 0xd2254f36, 0xb5402249, 0x592ddb90, + 0x54656291, 0xd36abe0f, 0x9597bba0, 0xa59ba60c, 0x368c03e0, 0x155436f7, 0xd73a1085, 0x069e9fa8, 0xeb401ccb, + 0x84a22d19, 0x68ca6699, 0xb200deea, 0x71d33d13, 0xbbb5aba5, 0xb645f14f, 0x12f8bdfe, 0xfd76f096, 0x4cd16cb5, + 0x3f52e441, 0x4fa9641d, 0xea457367, 0xdfbdb2c9, 0x2f39b22a, 0xb375b6da, 0xa8efcf3d, 0x512a4fdc, 0xd581a2d1, + 0x1aece8ad, 0xc0440560, 0x9bc98680, 0x2c86b27f, 0x3da8cf4c, 0xf5b930f5, 0x09e4e14a, 0x34fdb8a9, 0xfbb25c0a, + 0x77144c9f, 0x3701173d, 0x513c1532, 0xff1df95f, 0x6af7220e, 0xf35270cc, 0x9960dfbb, 0xa2642b7f, 0x7ce971ad, + 0xa8816831, 0x027f4df6, 0xf8f85972, 0x73d1f59c, 0xa5668f4c, 0x02e49481, 0xdc1b13f6, 0x90e8faea, 0x7c35d713, + 0xf0fb4ffb, 0x223feafa, 0xfe1d7d58, 0xdbbc3f20, 0x1b45fed6, 0x8ad51e43, 0x154aaf3e, 0x97a55157, 0x2d562fd5, + 0x3ed75761, 0xfbffee27, 0xd5301ec9, 0x66344449, 0x020203fb, 0x62123071, 0x5e8158cc, 0xb5391410, 0xad0d892f, + 0x8e19e9e1, 0x86d5bf3c, 0x6cdd77ca, 0xe48227cb, 0x0fa6a7fa, 0xf52e0c80, 0xbe48681b, 0x346df463, 0x1cf35b8b, + 0x09a68871, 0xd44c1ee8, 0xfddd20b2, 0x76216df9, 0xd57db141, 0xd2d17472, 0x8fc9a904, 0x9f5af9c3, 0xcd507078, + 0x1ef15632, 0x8f104847, 0xc89cad98, 0x440a85d5, 0xbdd68c13, 0x10253c4a, 0x932236e2, 0x20c699f1, 0x6a75a723, + 0xf2310466, 0x62576108, 0xbca7d771, 0xe28018f4, 0xc021bbbe, 0xaf62a481, 0x4cc47c5a, 0xe2aac129, 0x3fc260c7, + 0xd65cb74c, 0x24dc8943, 0xdd49e4cd, 0x83145cde, 0xfd7b6203, 0x0e11a129, 0x2ad25bc1, 0x1ee553bf, 0x55303cce, + 0x527ee40a, 0xc231b79a, 0x9c95191d, 0xe5da9126, 0x00ba345b, 0xdc9bbd24, 0x9362fdc9, 0x93e634f6, 0x1da5646c, + 0x1d871e74, 0x27a5626b, 0xc2c3cec1, 0x1340c9db, 0x06a08251, 0x76f2b501, 0xaf9949a3, 0xe5412016, 0x9dd96ce6, + 0x0415f0f4, 0x78891c49, 0xb76aef21, 0x1993f27d, 0x6e9ea6f8, 0x1e356594, 0x4953f739, 0xe4707976, 0x8f35f090, + 0xf061dff3, 0x6dd2ff84, 0x3d9bd396, 0xbbb51795, 0xbb931acc, 0xfd28deec, 0x4c48a4fc, 0x77080c8c, 0x786a2f9e, + 0xd8111cbb, 0x0c15700b, 0xa6bda1a0, 0x8228254b, 0x2268018b, 0x6be9f3d4, 0x3cf08bd3, 0x1eba4d10, 0x3f5901c7, + 0x1419d6f8, 0x759554f7, 0x0959b2fd, 0x8b8f6b98, 0x64227dab, 0xa79af448, 0xfaba2440, 0x9d82f1cf, 0xeca81981, + 0x54d7a592, 0x243673e5, 0xffea63ad, 0xe1578e8c, 0x0fc86186, 0xaa82ad07, 0x738503da, 0xa5d31157, 0x8ac979fb, + 0x4b60a25e, 0x0b55a64d, 0x0f3d2d8c, 0x6b9f10aa, 0x882b9e4f, 0x0f779e79, 0x17c645b4, 0x6127c8c5, 0xa9716bfc, + 0x87232d27, 0x5025bc4b, 0x83b8fb5f, 0x4f9ab754, 0xa7fb7a61, 0x807f51f6, 0xfeb65aeb, 0x4692d6ce, 0x19c26244, + 0xb0ca0f2b, 0x8371beee, 0x217a177f, 0x26ffbb37, 0x9a46a48b, 0x7bcbac08, 0xc0f43a24, 0xe8b74d7e, 0x27f5cef3, + 0x18adb186, 0x0eb0222e, 0x20b8fa45, 0x73d8e45a, 0x25b97237, 0x03d24772, 0xa9cf9e64, 0xef870bf2, 0x3767f6d1, + 0xbf600471, 0xcf9517b7, 0xafdc81c8, 0x075ab769, 0xef4610fe, 0x508d24e9, 0x6c5e1c32, 0xf35a4a83, 0x7432bd3a, + 0xd8123775, 0xc0101c53, 0xd597039e, 0x43129daf, 0xb95e3f32, 0x33153742, 0xc5a7f33f, 0x1db6ecb2, 0x82835187, + 0xb3a65bbc, 0x6606d410, 0xad99314e, 0xafc1de44, 0x4156bdaf, 0xd0742347, 0xbb07f49f, 0x9c503eb9, 0x215c472f, + 0x1c55f967, 0xf312f0d5, 0x193c7aad, 0xc7d5f21a, 0x8d549669, 0x26de409f, 0xe4bc050e, 0xce095d83, 0xe404da2c, + 0xdf4217f0, 0xe641eb91, 0x1e7a2160, 0x94bca97b, 0xd16fc8d2, 0xf364615b, 0xc99e54fc, 0x79fd05d4, 0x91f6c7f9, + 0x89fc85ce, 0x4c6c85a5, 0xe3d8b8ab, 0xacd97a5f, 0xe4524187, 0xdcfb6be7, 0xc29b5dfd, 0xac439eb1, 0x53ab9cd9, + 0xee56c046, 0xaef6b122, 0xcfba047b, 0x41cb4316, 0xf8002c34, 0x8536b897, 0x8cc7ebee, 0x7660406d, 0xf6e1edd1, + 0xb15e2c21, 0x49f48d84, 0x3991d2af, 0x7714dab2, 0xf104d593, 0x1ea5298d, 0xa85b0572, 0x13348fd2, 0x9d10d767, + 0x2ad94bf2, 0xe92035aa, 0x24f1f115, 0xa2722cf0, 0x3e776e51, 0x6e9cfe78, 0x24296999, 0xd6391f0f, 0x4498730c, + 0x53c8966f, 0x29ac9f47, 0x7537da8a, 0xfa68479b, 0xefefdacb, 0x2aec5c57, 0xdc181366, 0x9ffb00f3, 0xde2e97ae, + 0x3c63aafa, 0x03725d50, 0x69430e8b, 0xb9b6efde, 0x95290c9d, 0x1da81e1f, 0x99d11bc2, 0xa2e793a9, 0x80b7abe9, + 0x3536803c, 0xf49084cf, 0xc547b6e3, 0x4e37f3bd, 0x9b6b43e4, 0x36197eaf, 0x1f9c95e2, 0x09b1570b, 0xe6cc8a0f, + 0x0145a472, 0xec61329a, 0xbe42b150, 0x31c1cd1a, 0xe6d8a8fc, 0xccdf781f, 0x932a010d, 0x9b3472a1, 0xa87643ae, + 0x6667c3ad, 0x15b2bbc0, 0x8fb98bf6, 0x13fc1761, 0x85104cb0, 0xfba596b8, 0xae11460b, 0x9a3be097, 0x0bf27e30, + 0xfc7e7302, 0xb3114839, 0xccfc4fa3, 0x45a75e4e, 0xcf81e9d4, 0x9f01348b, 0x66b5e594, 0x8b24d0f8, 0xa68235b1, + 0x96a97247, 0x0cbf0a04, 0x1cc2d3d0, 0x7a685153, 0x1734fac8, 0x2b41100f, 0x0593393c, 0xddd04a88, 0xef6d5748, + 0x2eb96c68, 0xb56d2171, 0xd5d06d5b, 0x18df6ddd, 0xb0ea7cea, 0x6c8bc3c5, 0x0cbb1211, 0x147acb68, 0x5446ec4d, + 0x9971bb02, 0x4d1ff633, 0xb3936049, 0x5c95d5a5, 0x6caa71e5, 0x1e41885a, 0x5afe53d8, 0x1eafdb5c, 0x18ed1bc6, + 0xf044e4b2, 0xaf21a8ec, 0x53ed7fbf, 0xd1105440, 0x47d1e760, 0x8145fc9a, 0xbc3510db, 0x0d23642d, 0xaad4b444, + 0x8e64e12d, 0x4ea922fb, 0x1cdeb164, 0xd14e99c7, 0x7706f07d, 0xc43bf023, 0xe269993e, 0x162471bc, 0xa421ae75, + 0x9d506bb7, 0x7df764bc, 0x3cdb924c, 0xb74b2516, 0x769d6edf, 0x642465bc, 0x6571c43c, 0xc54fdb74, 0x37918819, + 0x49f2c1fd, 0x865c694c, 0x093f1a49, 0x60cf4504, 0xa94e0446, 0x639f2db4, 0xc467ea40, 0xa24d16e0, 0x231611fc, + 0x7e2a30cb, 0x6a0998b9, 0x4d23f84d, 0x622859f3, 0x2c5a7a38, 0xdd597d93, 0xa63ba631, 0xb7699bcc, 0x19f32a44, + 0x6666682c, 0x29c3e95e, 0x2690dcbf, 0xbed3e14d, 0xa20837c5, 0x7c2f53e8, 0xd40fbf7a, 0x0003aa22, 0x6048a058, + 0xedf50d3a, 0x13b5b50c, 0xf05ac58e, 0x845e47a8, 0x2d1c2baa, 0x323ed66c, 0x872ccec0, 0x12f082cd, 0x92761d9d, + 0x00e71964, 0x87daaeae, 0xaebb5003, 0xda3d998b, 0x224872d4, 0x6dc8ea66, 0xc47a6a79, 0xc71f1fb3, 0xb92ea64d, + 0xed6c144e, 0x73dc4929, 0xba5f7e84, 0x4760cb8e, 0xc5b0ff00, 0xdeebfc1c, 0x909761af, 0x9d6d2f1c, 0x74bbe7e6, + 0xf1143375, 0xd07c88d9, 0x720d1031, 0xf524c21f, 0xeea3d46e, 0xce15343c, 0xc947ac77, 0x1adeffcb, 0x8b836281, + 0x02da41ff, 0x1315dd74, 0xfd9ac898, 0x7295ebb0, 0x562e67d1, 0xa67f380d, 0x9f193b22, 0x1937728c, 0xb293a4b8, + 0x6b565bc9, 0xfc07996c, 0x50f149d1, 0xb1447375, 0x1fe764a1, 0x0b263c63, 0x14d20f0c, 0xe69ede5c, 0xea5c246d, + 0x5cde3cb4, 0x4d3e16bf, 0x8784e3d3, 0xc658d1b9, 0x19fc0b03, 0x8695fc1b, 0x4852f33c, 0xb633ae3b, 0x3a211f6f, + 0x6d22df45, 0xedc52563, 0xa12b40d5, 0x493b31ca, 0xc91e109e, 0x94f3cb46, 0x089a4bf4, 0x9a96fad6, 0x26912ec4, + 0x33e5980a, 0x24e32630, 0x7021e2ca, 0x83fa18a5, 0x86808cf4, 0xa5a661fc, 0x1c6100d3, 0x18f4a14e, 0x062734b1, + 0x366d36eb, 0xcacb48cf, 0xb6216dce, 0x971bf42a, 0x52ae4b69, 0x2fc0e3df, 0xa90e6bf6, 0x59c69501, 0xa6734edb, + 0xa0966bab, 0xa341eb2b, 0xc40ee233, 0x38a38f1d, 0x23cc475e, 0x74bb292b, 0x121cca6e, 0xf7918991, 0xb696382f, + 0x6bc60f4f, 0x63c55ace, 0x1ca7cd86, 0x2f51631c, 0x05c4e4b8, 0x32f7d5ae, 0x677e1d28, 0xe18e4e5f, 0x4f44ac92, + 0x67aae84b, 0xa46e708e, 0x8b06a73e, 0x4c5bf73a, 0x34d7c2da, 0x73440518, 0xe86c2bde, 0x84b31b61, 0xbc27371a, + 0x1fc69a1d, 0x2d1bc659, 0x4533e2e0, 0x21c9d8c3, 0x4917311f, 0xb98494c7, 0xc200acae, 0x62dc3a98, 0xe6eda411, + 0xfbb99b45, 0xc5f5cbe3, 0x6fa40711, 0x898864a7, 0x4e7f65c4, 0x6c55a71b, 0x520f6ed1, 0xe177a23a, 0xd28e7765, + 0xfaf9bd4f, 0x72fcb233, 0xe1c49c72, 0x74cf82e8, 0x7b7f18d5, 0x0813d72c, 0x841c2989, 0xbaae36cd, 0x0340d8ed, + 0x98690b2c, 0xf0ec6188, 0x0f827420, 0x28527c84, 0xad143495, 0xf8cc89e1, 0x0363af03, 0xceec544e, 0x69c3b64d, + 0x615d99ba, 0x80c68fbe, 0xc827cfd9, 0x4066e208, 0x4d0e39ab, 0xc960a47e, 0xa24973f1, 0x4b83dd63, 0x3066178a, + 0x6a527a82, 0xad251451, 0x13c8c66a, 0xaae1f939, 0xbdb22ffe, 0xe70c98d8, 0xf7574202, 0x5249e02a, 0x83090ab4, + 0x078a4afd, 0x987bfaaf, 0x3e68486e, 0x7d23a33e, 0x7a7353b3, 0x408c60d4, 0xdfe2e0a0, 0x5172d433, 0x7d990885, + 0xd88b6aeb, 0x65862ceb, 0x1bab40ce, 0xae8c9477, 0x449c2453, 0xf3a97c74, 0xa0689709, 0xf9175686, 0x615487b0, + 0x361b302d, 0xe6b2a6cc, 0xb05f10b4, 0xb63e4d13, 0x5856f51a, 0xe2cf01bb, 0xfbaf4744, 0x54d79196, 0x5f321ee3, + 0xa949bdfc, 0xf1cc051b, 0x470ff9d2, 0x5ed27df0, 0xd3ee4214, 0xc059fa38, 0xbb823e0a, 0xed33b53a, 0x444cecd4, + 0xd720ba3a, 0xcc77fdbb, 0x3ddd79f4, 0xde34cdb0, 0xbd8c5a72, 0xc3d9eac9, 0xb2766d14, 0x6ab55075, 0x0a770e40, + 0x3f5f5d33, 0x191e80d4, 0x36408fb4, 0x45a30593, 0x3095e7ca, 0x9da18eb3, 0xfabcd283, 0xdd26b131, 0x19135cb7, + 0x5cb3559f, 0x5ea217c3, 0x55bf0887, 0x6acfefe4, 0x7691f2d4, 0x688161e5, 0xe0e08a57, 0xb6ab6515, 0x95eedfa0, + 0x95eca399, 0xaf364c3b, 0x78cbfb6d, 0x794d589e, 0x5de9e9bd, 0x39d1e09c, 0x86e26645, 0xf523d1c1, 0xde3d3ac3, + 0xde46b3ac, 0x38951c6f, 0xeb4d6dfa, 0x0710df59, 0x555f67ce, 0xda5dc1b7, 0x09386fbd, 0xd6c63931, 0x4720ee4d, + 0x9c68ab00, 0x0b7b0c5e, 0x15422825, 0x07146261, 0xdd1f156f, 0x96779c83, 0x4ce5aabe, 0x18505b3f, 0xa785d0d9, + 0xedca604c, 0x58323b8b, 0xb46affa8, 0xaf8ea10e, 0xc285e1eb, 0xd00b69fd, 0x8d4de5a0, 0xb6a28ef9, 0x1574c6fe, + 0xd2b5fcac, 0xbd0823e2, 0xaca53243, 0xf2485625, 0x67947ed8, 0x17b3b658, 0xab2d8733, 0xe826b6c5, 0x49df0dad, + 0x1bfc2eee, 0xbe7fbd2a, 0xa824319a, 0xaa17f185, 0xbd101362, 0xfe3b5b7b, 0x660d87d6, 0x6edd0820, 0x3b1292fe, + 0x10e1d649, 0xd472a9a2, 0xe8ed9344, 0x8a065952, 0x91df8f38, 0x54c7c69f, 0x0801e376, 0xa1b7840c, 0x81ff9df3, + 0x06467a4a, 0x8658b130, 0x52cc0697, 0x859a83bf, 0x66caa85b, 0x7acf8200, 0x33eb8614, 0x30dfa4bd, 0x37672b92, + 0x80438eef, 0x7d78c8b3, 0xeb495dd8, 0xe6064d92, 0x679b7e48, 0xc759f50e, 0xb48d33bb, 0xe56c0425, 0xfe5c3a7f, + 0xcc7a628a, 0xa3dec1ca, 0x4a58cc6d, 0xb5684aa8, 0x3f375b91, 0xaf856d23, 0x7399e792, 0x9b52a99e, 0x8a1687da, + 0x54f39c94, 0xabc867f9, 0x93bd20b8, 0x459b9bd6, 0x660f6f54, 0x0a5e655d, 0xd461fb90, 0x88a57b2d, 0x16b73b93, + 0x3e963fa2, 0x134533bc, 0x1b04c96b, 0x7c78ed8d, 0x015da551, 0xec7e15f7, 0x09717917, 0x9765d57a, 0x63ca5929, + 0x31d98ed9, 0x392a1ab2, 0x382edcc7, 0xc3da5f3a, 0x8557d4ef, 0xef64de8a, 0x885b645e, 0x606bd33d, 0x7c19b4f5, + 0x522154f4, 0x1bf36afb, 0xe8e5aeea, 0x9b92007c, 0xa5050633, 0x3014e1c4, 0x0f895bb3, 0x17802fd5, 0x0779897e, + 0x7e5db65e, 0xba9914f9, 0x717ade6b, 0x81d139c0, 0x7518ed8b, 0xa5b8938d, 0xff9a286c, 0x7f17a0d7, 0x80a12b53, + 0x363651a0, 0xc4135ffe, 0x13aad115, 0x721bfbac, 0x80642b1e, 0x00b40041, 0x40682f7e, 0x5be735c0, 0x8f6c36b7, + 0xcb2e5e83, 0x093ba506, 0x22bee282, 0xf32b8c2b, 0xb1c8aeca, 0x840632b0, 0xc15114c8, 0xa0ce6438, 0x541b9a3f, + 0x065c253c, 0x2aaa7644, 0xf1083be1, 0x41789780, 0xcc5dff7f, 0xca8ed9af, 0x8413e6c0, 0xeef44f1e, 0x17a9a4d4, + 0xbd031edc, 0x2ef87401, 0xae3ef575, 0xc61ce860, 0x65008a14, 0x8091a3e4, 0xd83d1095, 0x8285c552, 0xb8b53c29, + 0xdb5432fb, 0x7d862b75, 0x62280f25, 0x4d54a235, 0x99704c81, 0x393dd3c1, 0xdccafe8f, 0xf118d8a9, 0x109003ab, + 0xda0e6d54, 0xd4967b5f, 0xef7707b2, 0xd5b9346e, 0x4d5f398e, 0x84126c65, 0x68e58e2e, 0xfce85ddd, 0x00bc6e24, + 0xd28f10f6, 0x09df7345, 0x5956c772, 0x3c571a18, 0xe2b0aea6, 0x5dca6ba6, 0x86053dae, 0x7773991d, 0x992952b8, + 0x2cddd6e1, 0x23e1a1d1, 0x848958f2, 0xcc8bdd7f, 0x23f8d3b3, 0x9a1ffe92, 0x803949cc, 0x9132c9ee, 0x74949fd0, + 0xbf133e70, 0xa260b605, 0x0004f96e, 0x1323f0f7, 0xd3ee00d1, 0x2935fd72, 0xec7b5dc4, 0x4ad2a359, 0x246dd08e, + 0x12d62137, 0x2f0effac, 0x45bc3b3a, 0xb3417e1a, 0xf0f8f725, 0x9b0aaef1, 0x7173ef1b, 0xa8ec6a67, 0x677eab87, + 0xc9904d98, 0xcfc64386, 0x3b5b2fa8, 0xe7973829, 0xd849dbfa, 0x96b09d40, 0xe6b7fdd5, 0x508d046c, 0xd92536ed, + 0x7569d1f5, 0x7fb174d7, 0xbbea9cda, 0xf59b5d8e, 0xc474e881, 0xfd166b20, 0xae4694e8, 0x2e9fbcbf, 0x1772d322, + 0x8875b947, 0xdf6276db, 0x0233b48f, 0xf6308968, 0xd673a6b0, 0x5ee61fda, 0xa68fcc67, 0xc1a8ee90, 0xfba75e44, + 0xe22b0d23, 0x0c9b5e29, 0xdf53dc3d, 0xb8ab45c5, 0x0b07d82c, 0x4207299f, 0x5c9e3363, 0xc5f8c3d8, 0x13d0dc9f, + 0x28e46e2a, 0x9e29a285, 0xddeae9b3, 0xb1f71436, 0xc83e9fc6, 0xeeb86aad, 0x9c6df887, 0x6d01ac68, 0xd48ff1c7, + 0x0f477ba6, 0x34a03647, 0x113d38a1, 0x471419fc, 0x83b81b90, 0x9566cf93, 0x18c5dafd, 0x6012e69f, 0xd1a03041, + 0x184590e9, 0x7ff0e645, 0x5dd2e9e7, 0x8ee8efd2, 0xeecd03d5, 0xa7cf2e33, 0x1166006a, 0x6c21cf30, 0x7a3d6b52, + 0xd6cb477c, 0xe1a3e608, 0xa1f343c8, 0x8db7ad4c, 0x74871a7b, 0xc2ed176d, 0x971aa7e9, 0x59408b01, 0x6c5899d4, + 0xc8a0839e, 0xd0cf0d90, 0xd17f5260, 0x10fd516d, 0x10b3f484, 0xd78f9953, 0x61a63afa, 0x36dc4836, 0x36aa855c, + 0xb5a9ab42, 0xf8be026a, 0xbe57106e, 0x20c8f464, 0x8b29d2e8, 0x885c68d0, 0x3e85cc9b, 0x140f5c5e, 0x61ec8d09, + 0xa380e164, 0x248a3281, 0x42db57f0, 0x112ffa44, 0x5ff17e7e, 0x6d03b789, 0x26a4b7ad, 0x862890be, 0x1dec2a6e, + 0x076633d8, 0xb2672bc0, 0xee261385, 0x53f56692, 0x3b1e58f4, 0xc202dd91, 0xd3314de1, 0xe23c3f9a, 0x5b171889, + 0x232bdfd2, 0x05e88030, 0x89111fb6, 0x182a39f6, 0x8753cc32, 0x776671a9, 0x8b75ade6, 0x011a8fc8, 0xf12c8855, + 0xe46ca1fa, 0xdb83b5e1, 0xd49dd84c, 0x6d46b39a, 0x1e382b11, 0x982a41c5, 0xba2e6c85, 0xb624fcd7, 0x58e1c0af, + 0x7565c554, 0xdc456b1d, 0xf19bdfca, 0xfcb73995, 0xc0b612ae, 0x8e66fe46, 0x7f07d1c2, 0x2c051eaf, 0x6c40597e, + 0x72b031a7, 0x901194ce, 0xaa920a0f, 0x75def111, 0x41a9abc9, 0x3fe3ff4d, 0xbd458c47, 0x1d8d6732, 0x107eacbe, + 0xc6e4a07a, 0xcea6097f, 0x8b169721, 0x8aaed31f, 0x2e6c1977, 0x1fe64584, 0xfd58f1c8, 0x8eb7b1a0, 0x8bd6b642, + 0xcbe49258, 0xd467e18a, 0x9e6977d1, 0x197efea7, 0x1f51f9b5, 0x1921903e, 0x2b60bfee, 0xac60b352, 0x0b831554, + 0xda92ea7a, 0x0b41597d, 0xabd42b40, 0xb91f83be, 0xdde3f8ab, 0x871e779f, 0xaeabd0e5, 0x9736134f, 0x554b292b, + 0x0e0f82e5, 0xaf28d293, 0xe24c618b, 0xb54726bd, 0x3d92b533, 0xe54911bc, 0x64123038, 0x87ce934f, 0xa6992e81, + 0x0b90005b, 0x28a0d9a7, 0xf13cf423, 0x8cadf7bd, 0x04d55649, 0xa1f662a1, 0x38abc703, 0x23b4db59, 0x38b939a1, + 0x08b93882, 0x9980fc7a, 0x5dec26c8, 0x8c4e556a, 0x40fe1426, 0x5c531150, 0x70960c8c, 0x1d83ad6a, 0x613a5bb9, + 0x82d878ca, 0x7a36085b, 0x673703a0, 0x56cd872d, 0x5ba9cf56, 0x5754d01d, 0x32b2409b, 0xa2bf4c24, 0x587fa9ae, + 0x3e81bf57, 0xb7adc364, 0x2325bba3, 0xf78a6b48, 0x03e4146d, 0x0ef45961, 0xf8d01996, 0x87d7a1ff, 0x85e45e76, + 0xfba2dcad, 0xdc5cdadd, 0x39a81c10, 0x2e36b7da, 0x01565536, 0x86788dc2, 0x144da705, 0x4c52519a, 0xc2482bfc, + 0xc01364ce, 0xebe92ed6, 0x26c03664, 0x8b2c3126, 0x33d7da1a, 0x632c4ff7, 0xbb7293ba, 0x47de66f8, 0x4a1e977a, + 0x15c2bbbf, 0x39f719d7, 0xe61c6944, 0x0a17648c, 0xa000e927, 0x6adab49b, 0xeb485d14, 0xc2a30757, 0xe190290f, + 0x2284ac47, 0x604e35a7, 0x76d6d02e, 0x165b8a58, 0x9fad7ffe, 0x3948a594, 0xb297e567, 0x7b4af055, 0x3a196a8b, + 0x1e7a3a99, 0xcc837c85, 0x563ba850, 0x9ff41234, 0xc35c9c6c, 0x24c22973, 0xe21721fb, 0x75904a72, 0x5d5fb060, + 0x03cb73c5, 0xbe1a5103, 0x444694f5, 0x1e8438b6, 0xdf870cdb, 0x55e2f9dd, 0xb6898367, 0x9af5dfd1, 0x1512309a, + 0xbaf46c53, 0xeeb5a2eb, 0xb8304e8a, 0xd76fbba2, 0xf74ad146, 0x7e566419, 0x028bf671, 0x269fc85b, 0xb17b600d, + 0x7a6e991a, 0xf1852004, 0xc018d9da, 0xf9f56f9b, 0x1c1bc64b, 0x56e21ceb, 0x225fd1da, 0x00dc8c6d, 0x6b3d62ed, + 0xa2533f74, 0x209dd7e1, 0xfb332a6f, 0x358df7ef, 0x5b58e6d8, 0x65c338ea, 0x41316c65, 0x63e68b4b, 0x0b01ecc6, + 0x9bd161c1, 0x7bd52e06, 0xb36229b4, 0xa9e7b79c, 0xa438b718, 0x65d783eb, 0x2f1f5ba4, 0xb9950fcb, 0x8abd4a01, + 0x8f1914b4, 0x55fe63bb, 0x650452bd, 0x44295df4, 0xd9095176, 0x2c27ccd7, 0xfad91842, 0x43a8d1cd, 0xc60ded7e, + 0x54991d4e, 0xd61682a4, 0x3b57f640, 0xde44227f, 0x228d2dd5, 0xc6b307de, 0xb2d5e1a5, 0xef40991c, 0xda0ed5f3, + 0x3014339e, 0xcaa43854, 0x35e1840a, 0xc4be4c7f, 0xc85790fd, 0x4f6e7ce6, 0xae65909f, 0x1ba9259c, 0xd841bf83, + 0xb87ef2b3, 0xcf896f8e, 0xd3b21e86, 0x41700778, 0x3d7f43eb, 0x6a4f8bfa, 0x63e918d2, 0xc3f8da6a, 0xcb05aeeb, + 0x2670abec, 0xcfd2b71d, 0x7542b797, 0x98257bcb, 0xb55497b9, 0x11c54312, 0x0a27546b, 0x478dd99d, 0x6ef915fe, + 0xed6ebc26, 0x138a3441, 0x1992ab77, 0xcf6f3c05, 0x7e7b11ec, 0x9f269fcd, 0xb579a1bd, 0x8291050d, 0x2ca04bb8, + 0x37b9063a, 0x203668f6, 0x1a3e56e1, 0xff761adf, 0x599b44ec, 0xb1715cca, 0x5ab190e9, 0x2a26d793, 0xa7520a70, + 0xc588fd5b, 0x43483345, 0x86c6c63c, 0xb9998e44, 0xaedb3dbe, 0x870c68de, 0x593e1625, 0xea338073, 0xf6a48af0, + 0x0e9d82b9, 0xa97c8544, 0x9b4ce44d, 0xfd481ace, 0x7e044867, 0x21112041, 0x632221c0, 0xfdf12a7b, 0xec80448b, + 0xcfe17659, 0xdcbee8b1, 0xab9bf200, 0x5523e354, 0x9d9cf264, 0x33813b38, 0x11582c71, 0x3201d48b, 0xb9b97319, + 0xad07f112, 0x9bf18b63, 0x1aaf3829, 0xb279da53, 0xdbc005ab, 0x8e3269e8, 0xf27d48fa, 0xdaaecbcc, 0xf386fbb0, + 0x8909a555, 0x2d8c5031, 0x6ba76136, 0x84f41844, 0xa2d45f7d, 0xb45d8f8c, 0xbb93b786, 0x2d798952, 0x11fbb41e, + 0x5f312e3c, 0x27f7c9b3, 0xf1a934bf, 0xe1c914f2, 0x53665e5e, 0x62389366, 0x8ba94d43, 0xb107de62, 0xae62b48a, + 0xe1309239, 0x65dc1f07, 0xd668b1be, 0x1c499a30, 0x28feffb9, 0xdcc46285, 0x27c08f41, 0xaa8f2092, 0x654da3f2, + 0x63f1d514, 0x35502602, 0xd7592eb1, 0xcca637bb, 0x0390a594, 0x94c6fdd4, 0x891babde, 0x601e4ccb, 0xec03a36d, + 0x7775f68e, 0x14cd8d4e, 0xd81c41ee, 0x1a4e2c9d, 0xefde6604, 0xfb958a57, 0x5c09c6fa, 0x6e9e989d, 0xa28cd9f3, + 0x88f137f2, 0xfad02bec, 0x09304b85, 0xf31af939, 0xee3db651, 0x0788e751, 0xe17282e1, 0x1b5fb993, 0xda445bf8, + 0x37d67237, 0x50e69a9c, 0xd1faf401, 0x00d42f9b, 0x3e8ab2e3, 0x4b811668, 0xd6b40468, 0xb9b587a6, 0xb01138ab, + 0x5031bcee, 0x059d06c4, 0x72a6cd00, 0x25909886, 0xdb6ecb35, 0xdb63ef30, 0x13661941, 0x09522440, 0xe83f1ec2, + 0xe5516c5f, 0x278aa8e0, 0x1235898b, 0xbcaabab8, 0x25000e8f, 0xbf7daef6, 0x8868a8f7, 0xab14f3a9, 0xa4d91eb3, + 0x033719a9, 0x833793d7, 0xe3f70f41, 0xe285fc5c, 0x9c72f92a, 0x03ea243e, 0x99bee044, 0x919bf9aa, 0x741d047e, + 0x6b7d92ae, 0xe9a14bce, 0x83c62958, 0x61b94ffd, 0x06f3f53a, 0x466385e9, 0xf9b70d71, 0x4995885e, 0xf712e625, + 0x59adb8dd, 0x0364651b, 0x762e6263, 0x740848f0, 0x49a133e2, 0x3a0e174c, 0x51009038, 0x03534aa8, 0x166bc880, + 0x5fb2a62d, 0x39b25f06, 0x7e0e9b77, 0xf7a07f64, 0x4ec501e1, 0x4252b9a6, 0xf32211f4, 0x1ddedb54, 0x69105af7, + 0x4627a10a, 0x4c07d31c, 0x34414117, 0x466fbda7, 0x5a64e5cc, 0xddbab63d, 0xf8625dcb, 0x0ee66fb9, 0x3d34375b, + 0x60e7f498, 0xe67c4887, 0xf767f2a9, 0x258a55a8, 0x553258a5, 0x3f824cfd, 0xe3643cca, 0x31fdf248, 0xc73489f9, + 0x2b86d8bc, 0xf2225de5, 0xa829e7e4, 0x2d690158, 0x9fd9bec4, 0x49dc9e1e, 0xfdf5bc35, 0xb897ed21, 0xd76e8f6f, + 0x76232345, 0x77d761ed, 0xa533c6ec, 0x04105346, 0x1ca5ae42, 0x0b75d263, 0xef13b5b6, 0x25808052, 0x8633d7a1, + 0xaa8c28e0, 0x7d760b1e, 0xb5e9d85d, 0xb78d4560, 0x27a90d4c, 0xba7125f7, 0x0fb761bf, 0xf1f376b8, 0xb33c3595, + 0xbff5a36b, 0x1b91de81, 0x07545af1, 0xe3ff5703, 0xe4b694f0, 0xd65bfb96, 0x49689732, 0x12c691ac, 0x4e955d03, + 0x274da6cf, 0xeb616168, 0x1f999c9c, 0x6b900b12, 0xfe5cd3aa, 0xf4c40e5e, 0xc2e25420, 0x14b5dfc8, 0xfd60dffa, + 0x9a5b597d, 0xf1cba45b, 0xfe12c108, 0x019ee194, 0x84216e9a, 0x7a95e7a8, 0x06be8797, 0x2d39ae98, 0x0ef5d6cf, + 0x1b953588, 0xaae33688, 0xdc109e39, 0x2249eeb8, 0xd3c5221d, 0xfaed500e, 0xf37b7d34, 0xbed7fb6e, 0xcb98a6ff, + 0x096a0f4b, 0xcb15592e, 0x2d16cd3c, 0x8dcc507b, 0xdc20ed41, 0xc3801170, 0xa531c43b, 0x28871271, 0x0691b7bd, + 0xf60fd38d, 0xf620e422, 0xb3b3eccf, 0xf8d1a1db, 0x980d979e, 0xd9642e15, 0xa465707c, 0xa5257bfc, 0x7a4a0342, + 0x084bcb35, 0x8616f2fb, 0xbe8df8de, 0x5964e550, 0x5e41b6a3, 0x93f8b402, 0x65a9be3b, 0x2197410d, 0x8c57e160, + 0x60739b0e, 0xaa44ddbb, 0xb3a7c4b0, 0xd67d68ca, 0xbbf522bc, 0x8a168564, 0x7e04082e, 0x33d673b7, 0x32139161, + 0x2f9f17c5, 0x71a6ae06, 0x6f8df17e, 0x0c257efc, 0xd5ac6e85, 0x365582d9, 0x401f2c68, 0x437eb27e, 0x8bf770b1, + 0xe3322fa4, 0xad69f976, 0xf27cdd85, 0xf0d75519, 0xd090223f, 0x7c141c52, 0xd50f7685, 0x9b6fb3e0, 0xa6efc67b, + 0x2f437493, 0x74516b4c, 0xadc4ccac, 0x90ed032d, 0xc6e05067, 0x58a9b7af, 0xa1e3d7bf, 0x51938998, 0x46d7531b, + 0x891456e4, 0xe0ff79fc, 0x59773efa, 0x43ee4bae, 0xa021b1b9, 0xaee0cbf7, 0x84afb818, 0xae59ec1a, 0x09991207, + 0x71aaccb5, 0x4a660537, 0x460dba18, 0x70cf2f84, 0x0df86f0f, 0x073648a3, 0xf70f2ac1, 0x3f7550e3, 0x0722a45f, + 0xfeec1239, 0xd9cbbb9f, 0xa98d0baa, 0x42817340, 0x3f4e0237, 0xd798fb8e, 0x3f0c3e28, 0x0d8ebb01, 0x54034106, + 0x39f68f15, 0x961370ca, 0x5a255679, 0x21fd438d, 0x2c88d6d7, 0xa1efa2e8, 0xcb251310, 0x9731e510, 0x152e844f, + 0xd2f61568, 0xfb310fb4, 0xea512c96, 0xbdce51e5, 0x24db0385, 0x705e037e, 0x46811066, 0xde15c418, 0xeb07803b, + 0x3be3e889, 0x146db619, 0x31665488, 0x3fda8522, 0x16cd48a3, 0x90af837d, 0xb27eb86a, 0x9de57474, 0x2908c585, + 0xb9bea3b1, 0x7e0c392d, 0xe6ac3487, 0xb9657735, 0x6ce6de50, 0x35ca73f4, 0xcf858c28, 0x0e30d401, 0x8cd27907, + 0xff5d8b44, 0xac87c6d8, 0x6ac9cb7e, 0xbace7a78, 0x6948c271, 0x47fe460f, 0xabd9da25, 0xcc51acbd, 0xe8f2213a, + 0x0cf5545b, 0xd5884665, 0x3f029b54, 0xf81d8ea2, 0xa419b630, 0xb3ab9cf1, 0x3bbceba9, 0x5a028096, 0x91e0e513, + 0x3385ec3d, 0x62716e2f, 0x89ba77d3, 0xa30d7e01, 0xa50489ee, 0x14fcb017, 0x0724920b, 0x0ac5acd4, 0xa40a0243, + 0x4ce664e0, 0xdfeb2cf3, 0x034b2643, 0xdb65be65, 0xa0497283, 0xe67dd687, 0xee746c4f, 0x600272a7, 0xcff314e9, + 0xab07d9eb, 0xde982447, 0x20db698b, 0x47d6b174, 0xd8934b2a, 0x0f7e083e, 0x362b1de9, 0x4db631fe, 0x56365a37, + 0x1004a53a, 0xd1b4e58e, 0x4ce9d793, 0xeaec8a0b, 0xeb17dab1, 0x513eacc6, 0x3e0eec3e, 0xe0fdc800, 0x248ec6ca, + 0xcbd34742, 0xf7ea29ba, 0xde082b78, 0xbb0d4b03, 0x1b34cc7b, 0x829c7a9f, 0x932ec9a3, 0xa52cb40d, 0x339f1c82, + 0x0278e7c4, 0xb75b4a2d, 0x92cd459b, 0xefeaea50, 0x664224d8, 0x8d829625, 0x9c0ac286, 0x35fa627f, 0xb7ac2706, + 0x66fb528c, 0x349be600, 0xb3917610, 0x0a26ad7c, 0xe3ed34cd, 0x8e5c5d3c, 0xeb887839, 0x29fdd3fc, 0x0e85a4e6, + 0xd613fee6, 0x586a7ac9, 0x15f13b02, 0x1a0c313e, 0x74da557c, 0x3a092549, 0xdcc4dc86, 0x9032c5dc, 0xa1f29d52, + 0xda372300, 0xbdb32c1c, 0xd4cd099c, 0x345ea80a, 0x6687a574, 0x2765790f, 0xb3889931, 0xa64a22cc, 0x908f77d6, + 0x616f03e5, 0x35411e27, 0x255d3d9b, 0x32e51a83, 0x3fea791b, 0x5335d059, 0x56a40224, 0xc9976d7b, 0x59220d56, + 0x448b2907, 0x55df50cc, 0x05ded734, 0xb54ddade, 0x9c0e5226, 0x13911e76, 0x69669a86, 0x91736fd3, 0xd70b77f4, + 0xcde91365, 0x24d0248d, 0xe78175b0, 0x28ae203b, 0xc7647d73, 0x41abfc8b, 0xe4bcfd47, 0xc29cdb36, 0xc92e56b3, + 0x77bfbbc5, 0x151d89cd, 0x1fe59345, 0x243f2d02, 0x2ae78e29, 0x3a973b52, 0xedc8b036, 0xc04c699a, 0xc42f8b80, + 0x270b710d, 0x5ff8dc94, 0xd1335c63, 0x1a4d9565, 0xaea1468a, 0x5d3e3b22, 0x702721a4, 0x246fa1fd, 0xc042ec07, + 0xc5df07e8, 0xdc0220f0, 0x0ea75378, 0x558d1671, 0xe21aab98, 0x1297c692, 0xce40d13d, 0x6bc00d51, 0x2021509d, + 0xec52bec1, 0x5c414db7, 0x851639cd, 0x9fa4cdf0, 0xfa0a134a, 0xd7b85638, 0x7ffaa12f, 0xf1ece4c8, 0x916c02da, + 0x6fb2f607, 0x8ce10ba9, 0x7f75ad08, 0x5979b566, 0x02e14a06, 0x267fdd7f, 0x51e489b0, 0xc659f3ff, 0xbb63c4a1, + 0x77d9eff5, 0xdd888646, 0xf35df43a, 0xbd8e4ff1, 0x015bc7f7, 0x5cd1736c, 0x6fb786d4, 0xf5ded0c8, 0x4b283904, + 0xcc16f66b, 0xba1ea6a2, 0x4e9ec72a, 0x93951eb6, 0xa0035db8, 0x8eb4567e, 0xd452cdc3, 0xd5e45eda, 0xdc98a779, + 0xc6322373, 0xc9ecf096, 0x9b7e4d6d, 0xa8482dea, 0x54220875, 0xf323bf2a, 0x83e0608c, 0xcdddbe4d, 0xba849c75, + 0x5dcf5e4b, 0x27d1e89f, 0x0fae824e, 0x77a4a84b, 0x7a1da1f7, 0xd27c9722, 0xf76cc94e, 0x7522a748, 0xe3fa4c20, + 0x0401e99d, 0x2dc49299, 0xb658c05c, 0x0f4218e8, 0x21da3f1a, 0x4a61ad38, 0x09d8c77f, 0x82e781b6, 0xcf117fb7, + 0x6f383d5f, 0x89a2f828, 0xade2d138, 0x067f6e42, 0x1b023a2d, 0x42db380a, 0x7670fea8, 0x4af5bc58, 0xdca4ca73, + 0x416182c3, 0x59eea079, 0x0fedcdc5, 0x0f3564a4, 0xff749457, 0x3ea15410, 0x3665bdd3, 0x118f451e, 0xa547925c, + 0x82a76bc4, 0xc0394507, 0x6f2b4bda, 0x07c228d7, 0x7fc386ff, 0xed1a3ab1, 0xe18ce5ed, 0x9d399cff, 0x637775fb, + 0xb69f2709, 0xf5e54c18, 0xdf0361fa, 0xd4668f55, 0xfbb83156, 0xef592ad1, 0x4ed310b3, 0x424b0eb0, 0x98d930b2, + 0x3b09ead8, 0x0c1be6ae, 0x00f1fe1e, 0xc4735e02, 0x794c1a2f, 0xe996748f, 0x59435cb7, 0xd3caef63, 0x1b500fc1, + 0x6dadc947, 0xda92971f, 0x7a817e1a, 0x037ae210, 0x334a081d, 0x39dbbd6f, 0xfa6c54a4, 0xaa0d3c2f, 0x8f5391ba, + 0x735f564b, 0x6509a58a, 0x0bc01c4b, 0x5bc06c59, 0x0375c303, 0xe2789eba, 0x26d01887, 0x7807623c, 0x73d39c8c, + 0xc9e77bcb, 0x6ef7f69e, 0xffa38cc4, 0xadac7673, 0xfafd0fcd, 0xc97ab6a0, 0x36a0f03e, 0xa2a82b4a, 0x48744a45, + 0xdf7e6bd4, 0x6d81ee46, 0xc2d6adb1, 0x72f51737, 0x237916e9, 0x93a16d61, 0x2a711beb, 0xdc920757, 0xad2f10c3, + 0x80d3e561, 0x068dfd11, 0xc17c7bd8, 0x4f4e95ea, 0x5ed255c7, 0x75e75575, 0xfc94955c, 0x01d4073c, 0x13d43015, + 0x685bd5b0, 0xa8a3c20e, 0x5d9c4764, 0x85b0e5cb, 0xd1ca96b3, 0xb8e5bc9a, 0xb3bec538, 0x20aa078d, 0xf0c52612, + 0x6fdeae8c, 0x2f5b1446, 0x1f9f9d9f, 0x1b2f5fc6, 0xb4818f07, 0xee1cc0ea, 0x15168d50, 0xe086235f, 0xb1845f2a, + 0xb4104a33, 0x284e213d, 0x8414d437, 0x63192503, 0x0b61fd46, 0x617dadfb, 0xeeda0703, 0xf9e7f602, 0x9585ea7a, + 0x4917fdaf, 0x6cf7835a, 0xf5f4ad1e, 0x05a8bd07, 0x630d1d28, 0xf3da5a86, 0x550bcf30, 0xf0c03522, 0x4e925aa4, + 0x645abb5a, 0x10528c37, 0x624b5242, 0x7d3b8aea, 0xb6cfcb97, 0xb379c994, 0xb7454b0b, 0xd6a64361, 0xfdd4dd19, + 0x08d3f04c, 0xb6ac783a, 0xde364374, 0x77722c7c, 0x4f61fed3, 0x5eb23e2b, 0x7de6b066, 0xd1c28faf, 0xc80fcd50, + 0x47ac9ba9, 0x839c08fc, 0x965fd2c9, 0xf0b2146c, 0xcfed0fb9, 0x5e127dd9, 0x74b90a26, 0x412ccdb4, 0xb77a2eea, + 0xeca43b0f, 0xfc6da2d7, 0x9bb09d45, 0xee89d79e, 0xe3f07124, 0xf77b0e4c, 0xf7ed97ab, 0xe8e27bb7, 0x303edc0c, + 0x4f03fa8c, 0x1059c548, 0x9665f5c2, 0xbce564ac, 0xc38bbe2f, 0x3866dddf, 0x6c99c906, 0x07349450, 0x02b3cf12, + 0xe4a56493, 0xc2637e63, 0x8a459172, 0x45c5871b, 0x7fde1dcf, 0x6b957f1d, 0xf9b06239, 0x1ed28a34, 0x4b63a70e, + 0xd7ae94f6, 0x406b3562, 0xc6b73bbc, 0x72023d2e, 0x70f82df9, 0x8e7433e7, 0xb719fd42, 0xd0718b9f, 0xb9ec38f2, + 0x04434ff1, 0xe0a4cd70, 0xe97f86e9, 0x7eef739d, 0xf6684dee, 0xfae3a587, 0xb14523c1, 0xe7520410, 0x8c4cb654, + 0xb8fe7d2a, 0x88de4674, 0x53117ea2, 0x0e925dd9, 0x5f166417, 0x1fb2daac, 0x31a0c5c5, 0xf085e737, 0x106059b1, + 0x64d19f47, 0x948e1396, 0x3a5e1315, 0x7e9c5339, 0x473defbe, 0x84dfc492, 0xa856addb, 0xda5e4fef, 0x1fc4533d, + 0x371cd3f5, 0xafab5ab4, 0xe7668726, 0xaf53f9ff, 0xe4129d46, 0xf83a93f2, 0x7aa1100e, 0xb5e9dfb3, 0x8599b860, + 0x6753b09f, 0x77fe1167, 0x1546a731, 0x9e807d08, 0xbf05cdd9, 0xf0fbf48d, 0x27f9c07c, 0xbda2e65a, 0x0d8f18ea, + 0x5bb34035, 0x8c4b5567, 0x3958064f, 0xc2a08d28, 0xda662c8a, 0x40fbe8ba, 0x53353d10, 0x4e8a3765, 0xb0247ad2, + 0x57141e02, 0x677d2420, 0xaebecb11, 0xa979bfc2, 0x1774da1e, 0x872e5f8e, 0xee525736, 0xc349a25b, 0x55dfbfa8, + 0x3212d799, 0xc4677d83, 0xa0d40863, 0x5519e732, 0xf95ae25e, 0xd8dc2fc2, 0xe67103bf, 0x1d8d0e6b, 0xa31910bc, + 0x44ad3c97, 0x3d364a68, 0x273fef2a, 0x9dec762d, 0x622ca3a2, 0xa9642944, 0x2394d039, 0x9fc4aa4c, 0xe0d9b8b6, + 0x8360570d, 0x13899aeb, 0x038b850c, 0xb1889899, 0xddbdf96c, 0x74b25c46, 0x724b68de, 0xe18dc3a2, 0xa01f967b, + 0xa3ec74f0, 0x3dd599da, 0x6ddfee24, 0x98f30572, 0x3e77f5a2, 0x4e5553e7, 0x86b2c27e, 0x92eed139, 0xd5ac9daf, + 0x8199275f, 0xd5b59812, 0xd3a21d44, 0xa0fadf4c, 0xd50cf9ea, 0x80d273ad, 0x05204b6e, 0xadfae60c, 0xd2da251a, + 0x63ec5757, 0xd5e9fda8, 0x7db22a36, 0x9b3af586, 0xc8aa06aa, 0xd75ac5ef, 0xe33b888f, 0x507b1e2d, 0x4f44cb65, + 0x3bfa7c2c, 0xc774e051, 0xc4a8e7cf, 0x9a63d334, 0x5121f284, 0xfe660e59, 0xb3ce069e, 0x86c63558, 0x90a03df8, + 0x7eeb03b6, 0x6d49a3b5, 0x12c0627d, 0xf1d5c921, 0x536f0fcf, 0x98dd08b9, 0x1abb1208, 0x2a8ba62a, 0x74224ec4, + 0x92941a59, 0x8bec0861, 0xc36479d5, 0xa822509c, 0xdec9512c, 0xb71ab15f, 0x5a5b0663, 0xeff7579e, 0x12f31e31, + 0x26f8a1da, 0x26894824, 0x78d909b6, 0xf69603d3, 0xaf8a24b7, 0xf744b07b, 0xba18cb22, 0x68d8a867, 0xe0d06dad, + 0xc3691c38, 0x99f92fad, 0x111fc934, 0x1a9c5104, 0x77c494c4, 0x73a08e4f, 0x93f72730, 0x80623836, 0x650952dc, + 0x1aee4f88, 0x38b7816c, 0x5207c359, 0xd387bef1, 0x8e6a7de5, 0xb2ebb7bf, 0x2e80788e, 0xc057d83a, 0x4fc3054b, + 0x26f4d868, 0x4dd8d1bc, 0x63ddbb77, 0x0c24cacc, 0x40f505e3, 0x25fb57d7, 0xc00f7a43, 0xca3c2a7a, 0xc9c1a073, + 0x5f9cd466, 0x5878e45c, 0x6fe19bca, 0x631a68d5, 0x3094c1cf, 0xbf9b6141, 0x2d3db924, 0x13bfbb31, 0x38fe94d6, + 0x89639f2f, 0x8871c587, 0x27cc8554, 0x6385db96, 0x2e645dd6, 0xafc301bd, 0x245a53ce, 0x5bc009d2, 0x2bff1938, + 0x1efc4627, 0x4f1d5127, 0x650c8374, 0x51cd2f8a, 0x970e0fcf, 0x1e39e2ef, 0xac6db5fe, 0x33607941, 0x40a86933, + 0xccf99f4f, 0x2046d1d6, 0x21bd8438, 0x0a3600c9, 0xacf09f54, 0xbc11bf28, 0xdced800d, 0x152edaf4, 0x4d3933a4, + 0x50dc8fe5, 0x3e1f37c8, 0x02875677, 0x02a72461, 0xfe92f9ed, 0x94da8571, 0x8328ad4c, 0xd8fd019a, 0x60b73b6e, + 0x91d5b762, 0x1d295825, 0x5b9ad183, 0xa8bf2359, 0x64c3ee5f, 0x5a14eb29, 0xf659b599, 0x1678cbcc, 0xf16325fd, + 0xe3b455a0, 0xde614a0a, 0x330bacc6, 0x059fec4b, 0xe506fd58, 0xb8de4fa4, 0x4ccb2511, 0x6127a0af, 0x7372f644, + 0xeda46b26, 0x70395afa, 0xdf123b88, 0x3d0a12d0, 0x35560fae, 0x2e564f39, 0x31fae3fa, 0x26651ef8, 0x4141ed9d, + 0xc05d3701, 0xe9e5af9b, 0x430b63dd, 0x6e1b5487, 0xfb3bbf03, 0xff3335ba, 0x5a0617b2, 0x25c9c54b, 0x0f97fb01, + 0x024cd825, 0x1e3bfbc1, 0x9ba464a0, 0x3420dc29, 0xf65372c3, 0xdee1bf88, 0xddc0270f, 0x77189ea8, 0x5d7be09e, + 0x3988a3c0, 0xe99af134, 0x9d04bfe3, 0x1f948bab, 0x118bf99a, 0xb768b491, 0xc7a84bd0, 0x9fd4e49a, 0x2db3b679, + 0xf755fd75, 0x2452d7e4, 0x2923a515, 0xbd0b0020, 0x029d2234, 0x4027486a, 0x7561cdcd, 0xa2ac85ff, 0x5cf75cc3, + 0x0b35d0a5, 0x8a97008e, 0x84fc5dc9, 0xf5eda1aa, 0xbaf5668c, 0xb97d9099, 0x5e6d059b, 0xc021c125, 0x9f229da9, + 0x3b82e84c, 0xfbc70ca2, 0x13aaa2c6, 0x71feefa5, 0xecf83329, 0xaa102ddb, 0x6b0b86f7, 0xcb2adee7, 0x3a479331, + 0x40957309, 0xc614dfd1, 0x3ff01a6e, 0x41718ba8, 0x65d1a654, 0x5a5cc6ac, 0xd4612e93, 0x9267c013, 0x72a5022e, + 0x4b2dc577, 0x61e0f91f, 0xfff315e0, 0x9332f110, 0xe111a63f, 0x90cf699b, 0xd167869c, 0x37a0e6e4, 0x47bc877b, + 0x1b13988b, 0x02c73c2e, 0x5b2d5f2b, 0x18c66a40, 0xaf07aae4, 0xe1bb634a, 0xbca9cd32, 0xb706b04a, 0x289d2392, + 0xa5da1535, 0x27aaa479, 0x753c30e3, 0x5b9c9673, 0xb4612913, 0x380f175b, 0xeb29d668, 0x4af80576, 0xddcb184e, + 0xa96d9d1c, 0x1f93de95, 0xb19abac1, 0x8e23ad37, 0x5bbeeb5e, 0xf793dac3, 0x306ba3df, 0x5c38d75f, 0x2e5a265e, + 0x9cdc66eb, 0x03db194d, 0x71899c6d, 0x1d5e0169, 0x87289e15, 0xa13c1e50, 0x6dc29c11, 0xc36a6daf, 0x858309c4, + 0x6d625cff, 0xb47cebda, 0x87e53a3e, 0x42bc95c4, 0x1c8136bb, 0xf40eb158, 0x32c2c776, 0xb491946a, 0x4bae1e00, + 0xd00adeaf, 0x6e38aa77, 0x2bc3906d, 0x4946101c, 0x163b3bf2, 0xef4623e3, 0x7c30eb68, 0xa93b966f, 0x6af1e849, + 0xa33ad154, 0x895b26c7, 0xcfb44696, 0xb5b3c396, 0x1e6597f4, 0xb80cb16f, 0xcefda122, 0x0796d557, 0xf7ef4ca2, + 0xef746d47, 0x93abf32a, 0xfc9b8ebb, 0xabaafdb2, 0xd2905482, 0x9886a23b, 0xf0d1f2bf, 0x5a7f4c88, 0xfa1758d5, + 0x56ce817d, 0xc22e6ebe, 0x4337036c, 0xa009e3f3, 0x95fbe562, 0x54e53a6d, 0xf3544466, 0x312c47e5, 0x8119ea83, + 0x2a0d1dae, 0x4ad1dc98, 0x80131efd, 0x3092a0fd, 0xcca2b6e7, 0x56459058, 0x4fb27674, 0xac1f194d, 0x0186ae2f, + 0x644e6a7f, 0xecbfc92a, 0xc0cb1ef1, 0x2b0cb62a, 0x73127a0f, 0x879c7258, 0x1baa7d51, 0x30b33de8, 0x25690491, + 0x2c052d21, 0x06972396, 0xbfef25fc, 0x885dd5b8, 0x18af8caf, 0x6c58c6f4, 0x60d34aed, 0x5b20b469, 0x5cee76e8, + 0x5779c15c, 0x31074ebd, 0xee0b2efe, 0x46852cca, 0xed674304, 0xcda16a0d, 0x98bf4820, 0xe395dd90, 0xb6353026, + 0xca9a7fa2, 0x6863c7b5, 0x0c348ccd, 0x32e9d870, 0x1a0ad6a5, 0x94da66ea, 0x98cc1bb2, 0xc9d7a5c0, 0xbbd5b425, + 0x83234e0e, 0xecc172b4, 0x00692e93, 0x5ad36721, 0xa2d03b84, 0xdbdf851b, 0x378c106e, 0xe808c612, 0xe3e7528e, + 0x310bebd1, 0x4e0e2ec7, 0x98c0005b, 0xb8eba8ce, 0x8cb0a003, 0x49cadbd7, 0xcaf579f0, 0x2af9c9dc, 0x2180dab4, + 0x440db0f3, 0x8863a1a3, 0x044a5580, 0x1a7415e3, 0x5f372922, 0x8b826adc, 0x35a5d701, 0x345356af, 0x6144c1d5, + 0x56c501a7, 0xc348018b, 0xd5d2c3fc, 0xc273fd00, 0x3f3a3ad7, 0x9c0e57b4, 0xbf906116, 0x3672a1bf, 0xf8d83799, + 0xd427e048, 0x68652616, 0x812e08d3, 0x8a994bf1, 0x09cd3279, 0x1349c0f3, 0x2575346b, 0xd4e4c994, 0xe881013f, + 0x021d0c74, 0x65427336, 0x1cacbd6e, 0xd91a3fad, 0x885f5987, 0x6e799e84, 0x0bb9cfe0, 0x31c7d0d1, 0x02af9aa3, + 0xcd28cd78, 0x7c6217a4, 0x60c6380e, 0xa0e9c25b, 0x163fac13, 0x58354362, 0xb3364788, 0xa8951488, 0xf9831d0f, + 0x207d88df, 0x3c025e3a, 0x95419da3, 0xcb5f2e3a, 0x13dc67c3, 0x90e628f2, 0xa80187ef, 0x86799300, 0xdbba0494, + 0xcd96cc6f, 0x98528111, 0x10e8ba65, 0x8de4ba8d, 0xffde7fdb, 0x55bb04db, 0x4008e72b, 0xbf10d189, 0xc58ccc06, + 0xd6a64a25, 0xce713e31, 0xf1a671b5, 0x635e84b2, 0x2a0ef69d, 0xa9112469, 0x50ee0818, 0x00e1d3eb, 0xb8afaf1d, + 0x5a921b65, 0xd6daf204, 0x46d58679, 0x4c12502e, 0x017e4621, 0x726dd3a8, 0xeabcd8ad, 0x6d7e4b97, 0x26ad392b, + 0x1618708b, 0x2b1faba5, 0xbe794b8e, 0x3544ad46, 0x4ff51ef1, 0x6b4c6fc1, 0x0f660dab, 0xfb37d4c8, 0x75d148cd, + 0x9b4baab3, 0x1833f6c8, 0xa4b0cabb, 0x4916c91c, 0x6182e0a6, 0x55537f19, 0x8f7b8b36, 0x4275d4fd, 0x49c20216, + 0x6f715589, 0xd9a5c0c8, 0x2a37f7db, 0xa1b2d4df, 0xa1f01905, 0xb3942a90, 0x25747f41, 0xc563b511, 0x759f4d99, + 0x39cdbb76, 0xb02f8765, 0x3f093444, 0xc3cc448c, 0xbab0475b, 0x007d7f36, 0xf54951c0, 0xc57d818b, 0xfdd34934, + 0x80bfd415, 0x75c784ab, 0x8732b286, 0x113a040a, 0x2ebe95d6, 0x6c54087e, 0xd0c57d06, 0x3c031248, 0x05bdbde9, + 0x764b6e11, 0xaa75edc3, 0x1c685028, 0xe02ee912, 0x91b3f33c, 0x0486d1c0, 0x1d94d82e, 0xf62895e9, 0xc445844e, + 0x2d1bbebe, 0x729744cc, 0x13b4cd6a, 0xb663c15f, 0x16770ac8, 0x9029692c, 0x6d0c4ed0, 0xbd0d1a38, 0xc95cc3d9, + 0x04550788, 0x4b0c29d1, 0xe01caead, 0xb40e7a32, 0xa0df8832, 0x8f0620d1, 0x5287f7f5, 0xf1d4d0ad, 0xd261fde1, + 0x91be97dd, 0x6c0f5e7b, 0x5603dac5, 0x555a6182, 0x535b08c3, 0xa7860b42, 0x4a5e7f0e, 0x76df6200, 0x03d81153, + 0xe9da6e52, 0x15f3ab2b, 0x62cb46b6, 0x82af80d3, 0x9a390d9d, 0x3bc0dfb1, 0x50e002c1, 0x172ef870, 0x89da4761, + 0x878f9d48, 0xbc1dd699, 0xd1a2150c, 0x1186de2c, 0x6e4a913a, 0x288e3476, 0x8da88aa2, 0x75c95ab2, 0x7ad3e03c, + 0x452915e3, 0xe2b84d44, 0xb9952edb, 0xaa7bbe7a, 0x4aa0295c, 0xa00096d7, 0x36a1e6cf, 0xf1d31b1a, 0x948714f2, + 0x2a0f177f, 0x0ca6425f, 0x661f1004, 0xecbbd4ff, 0xfa98eb67, 0xf32fb3a8, 0x42a2ceac, 0x47774b58, 0x82a9fee7, + 0x8b33879d, 0x651ba18e, 0xb44d0a5a, 0xcaef3993, 0x7ebb01ea, 0x048c3cac, 0xbd38c2a9, 0x73f760da, 0x97b922f1, + 0xe0bfb420, 0x57ec51ec, 0x5833cea7, 0x154816d6, 0x6412ecb5, 0x7ad427a5, 0x60800b89, 0xbe47b7f4, 0x82d5bed6, + 0xb93bd35b, 0x16b4fe80, 0xffe91d57, 0xbfc23e59, 0x7ad01f42, 0xa08b04cc, 0x68951885, 0x148f1c01, 0x8f4cbf90, + 0x8cb59690, 0x9e4effbd, 0xb0bae505, 0xee8f02fb, 0xf6561add, 0xebea37f2, 0x0bae33d5, 0x99520008, 0xed9d7f3d, + 0x395d2138, 0xab2f772a, 0x6c84b1b5, 0xb3e5cbbb, 0x76fcda7d, 0xfcbabc8b, 0xb5bd3bb2, 0x5889d652, 0xde25532d, + 0x4cbf63aa, 0xdb3571a4, 0x6c54ecdf, 0xfb1c05d7, 0xe7fa0837, 0x0d19a3eb, 0x3402afab, 0x0ac44908, 0xbc82176a, + 0xd4884af0, 0x4b703442, 0xb11de98f, 0x0903905a, 0xe0476ce1, 0x0beb7921, 0x8704ba76, 0x58b1be72, 0x6d2f97b7, + 0xd3c165b0, 0x27ec6aa1, 0xa8465326, 0x8730c1af, 0x46274755, 0x4181c110, 0xf8236c49, 0x13bf8f4a, 0x8e534bbf, + 0xe43c8b8f, 0x1fdc18c1, 0xb9f2fcb2, 0x511c4491, 0x4b409e73, 0x40b3b34b, 0xc0984543, 0xd63bca51, 0xf27cb719, + 0x4fd1d3d5, 0x2382e2c0, 0xd8c6817f, 0xb37dbe46, 0xb98bc6a2, 0xf79083d6, 0x5ade5b9d, 0xf0731cba, 0x695be9fd, + 0xe5572dfe, 0x3ee7fcc0, 0x6621f813, 0x614766f3, 0x77cfe321, 0x9ee5989e, 0xdd2d7b04, 0x9d5c4cf6, 0x63e0e443, + 0x7f1e3484, 0xaba1ec5d, 0x5013144a, 0x9f98877f, 0x805aecbf, 0x607a756c, 0xe4b041f3, 0x8f084ff7, 0xeefabff6, + 0x40a08d5a, 0x16f5268e, 0xf160d9fc, 0x2f0eaa49, 0xfe478ad1, 0xe908fbd5, 0x3b5303c9, 0xc6317fb4, 0x3b291cd1, + 0x021bf110, 0x7c6ee615, 0x6a2ab267, 0x8f16d002, 0x0f2a33fe, 0xe9f00278, 0xbb1bed5b, 0xd0ce1edf, 0x230a1980, + 0xdaed47fb, 0xb2921706, 0xb9e9b123, 0x3c2a084a, 0x20a86d35, 0x926210fa, 0xfdfa2678, 0xfdfb8671, 0x689c918e, + 0xa30094f2, 0xd1264224, 0xc8697493, 0x33ce9980, 0xb1e1b7ba, 0x9860341a, 0x858a0861, 0x62d4e1bb, 0x23ca9199, + 0xd9f35802, 0x60442069, 0xa3b4dab7, 0x391bdeeb, 0x8954bda7, 0xecf30762, 0xa166af63, 0x499ac0e3, 0x963cb345, + 0x984a47d6, 0x54022934, 0x79713ee1, 0x1e1f479b, 0x338e6290, 0x0289b2d9, 0x03dcb7bf, 0x43b80645, 0xd90f6fa8, + 0x28df0438, 0xc190bbcc, 0xdc4fa198, 0xd06d3f55, 0xbfa82f61, 0x8f5270e8, 0xf47a12d4, 0xa024da62, 0x9b6fe4e1, + 0x1813fc2d, 0x5788d8aa, 0x03ea356d, 0xc09a4444, 0x87eb7601, 0x32a698ea, 0x9218736e, 0x41f574f0, 0x64ca8e74, + 0x333925d7, 0xde82b652, 0x44f56765, 0x28fc7a55, 0x3a28740a, 0x3cddce30, 0x10c96e5a, 0x4850e4fe, 0x1b49c681, + 0x61ea1dd9, 0x0bfdb222, 0x998f3726, 0x9ded9abc, 0xa9682d30, 0xc5c56913, 0x082151cf, 0xb1eb49ff, 0xe5ff6d9c, + 0x0b23976a, 0xd7136d9f, 0x20ca92d8, 0x3a26ce96, 0x73cb0558, 0x3a69e2a7, 0x287dac55, 0xa192323b, 0x81ed0b29, + 0x535c8cf5, 0xd4982ee2, 0x8fd6e0e5, 0xd51eedd1, 0x605fba70, 0x98cba414, 0x2cd0b70f, 0xc9636196, 0x491bc08b, + 0x0d0de8a3, 0x0b8693d5, 0xb9ad76c4, 0x0a3789ca, 0xa10574e9, 0x085bafe7, 0xd51f1a25, 0xe7413bcf, 0xf4c90be9, + 0xaa7ba4d1, 0x3d3c6ce6, 0x248ddba9, 0x973288d5, 0x0cdcbba3, 0x77c1f7f7, 0xc40fc558, 0x3b01924e, 0xbf274106, + 0x77d6d641, 0x57a66d8d, 0x7db6544e, 0x262e7582, 0xedfea82c, 0x5ffc1f00, 0x19424ce3, 0x30edf108, 0xf4ddd61c, + 0x9e78f01d, 0x84043884, 0xe9a9cbd4, 0x5660a75f, 0x47d40138, 0x62cd3895, 0x8eb69a12, 0xdab58379, 0xdfcf3f3d, + 0xa0ec268f, 0x836ddc5c, 0x107de591, 0x3ff835ad, 0x4d366685, 0x8bb039aa, 0xd6da73cd, 0x0abdcb0a, 0xac671667, + 0x31a0f353, 0xee5449d6, 0x9892ec69, 0xb10f9eaf, 0x76e9abc1, 0x84daa9ea, 0x2b811469, 0xc77b477c, 0x2e8b1d71, + 0xc312886f, 0x9a79f388, 0x043f42d7, 0x6bfdb93d, 0xe26bc19e, 0xf71bcc1d, 0x991a212b, 0x0e96f940, 0x08c294ea, + 0xdb8ccf20, 0x3f694953, 0x1390c620, 0x8d533c21, 0xe033d1ed, 0xbc49ab0c, 0xdf168c54, 0xc7e96f8f, 0xbc024919, + 0xf7bdcda5, 0x1de88234, 0xd51ba578, 0x34bbd2df, 0xb1697893, 0x8db0df91, 0xde742770, 0xed7eadb5, 0xacac3393, + 0x2da99c1e, 0x8309f118, 0xca06aef9, 0xff274ef2, 0x80b3ae3b, 0xe326fb33, 0x1594fe90, 0x414fdf14, 0x742e3780, + 0x0d2e7260, 0xde4171d2, 0xaafdf507, 0xb483a860, 0x75f611c9, 0x66366ee2, 0x4fe31283, 0x814b1b94, 0x32466db6, + 0x724632a9, 0xf61226b9, 0x53cd459c, 0x42140d34, 0xa2ac74bd, 0x1e26bb50, 0xbd31fbc4, 0xa7005b6e, 0xa35cb294, + 0x224c4660, 0xc7288db6, 0x9ed34a29, 0x8a8cd31c, 0x4e84cf88, 0x29321b18, 0xd3711a8e, 0x7a2837cc, 0xc04d0975, + 0x77457f20, 0xbd38977e, 0xd0ba60b8, 0x7ca572e1, 0x1d5f5e8a, 0x87dcb328, 0x0d34c186, 0x987f8787, 0xeccd72c2, + 0xf2f67086, 0xe151c3fc, 0xeb877d68, 0xc34dc966, 0xee80c03e, 0x34861baf, 0xaecd1e72, 0x60fe4987, 0x6567d1db, + 0xfae26d34, 0xbcaa2e2f, 0x61a875bd, 0xa4ddceba, 0x84952ded, 0xef5940fc, 0xbc166b4f, 0xf47cc225, 0xf532dddc, + 0x3880f326, 0x2b6038a5, 0x7ca43660, 0xfe2c1f34, 0xc54c4268, 0x517f4b4e, 0x704aafa4, 0xbd7dc537, 0x52a144f6, + 0xee99c95e, 0x0f63d520, 0xf13d0147, 0x7289a863, 0x4e262822, 0x9c5ae62a, 0xf6554c79, 0xa0210a29, 0xdc98cc12, + 0x35056fff, 0xdb589cfb, 0xdd8b40f2, 0x05b3d712, 0x79532d20, 0x94f5101c, 0x92a70e7d, 0x75c93aa0, 0xd8ca02d8, + 0x3036a314, 0x0230bfab, 0x71312c70, 0x147c8479, 0x57ae5666, 0xb0b30c1c, 0xf5bf6285, 0x1e170bbf, 0xf98f6c95, + 0x12e315a6, 0xae5b2edf, 0xacc4272e, 0x97767a29, 0xcbc74b69, 0x3ba6575d, 0x0d496a2e, 0x77d44ce7, 0x956182b3, + 0x43402c52, 0xf5555536, 0xc1a97fac, 0xfb44a01f, 0xcf5c3ba1, 0xa268ce45, 0x17a190be, 0x4347222f, 0x8081aa00, + 0x9966663a, 0xda6984b5, 0x4c454a05, 0xe44f0b7c, 0x48e882a5, 0xfd87206e, 0x450e80cd, 0x2629481c, 0x448fba73, + 0x49972d4f, 0xd808981b, 0x37871cd4, 0xc5eb6825, 0xc6fd17d5, 0xd602b8c0, 0x04d9221f, 0x120f7540, 0x9a13a46e, + 0xe6a239fc, 0xdc56768d, 0xf81b4789, 0x54d7bd22, 0xc5e677da, 0xf7c7bb4b, 0xcd7991cd, 0x86bf97d3, 0x12ef7dab, + 0xbba5e546, 0xe4b19e36, 0x95dd64d9, 0xe43a1af2, 0xba842102, 0x67b5ea94, 0x168d3bf5, 0x4e5e2ab1, 0x0709d91c, + 0xf41667fc, 0x03b0c7ba, 0xeed0c02a, 0xf89c10e0, 0xbee66b8e, 0xba74e49f, 0x6a929a5a, 0x25385c5e, 0x5a0fe920, + 0x4762450d, 0xca09eae7, 0x0d084c2a, 0x4d4786cd, 0x5f276338, 0xb44113a8, 0x002b55bb, 0xf670a57b, 0xcfe0e2a7, + 0xc50f5b82, 0x3a3d4ed8, 0x422b0141, 0x9e81edfa, 0x7f586964, 0x4a8d1a49, 0x1b870b4b, 0x255637a8, 0xa9c3ac88, + 0x128a5dc0, 0x61536994, 0xe1a58b68, 0xb7b3e799, 0x4402d07e, 0x9eb5f368, 0xe424ba03, 0xfff34096, 0x8ced5c37, + 0xff7fccbe, 0xc4807e84, 0x79ca7500, 0x371e0ad7, 0xd084ed4e, 0x1c811f92, 0x98a1d351, 0xabf4abb1, 0x77b24b82, + 0x38d76b06, 0xfb91335c, 0xc8931620, 0x949df7f1, 0x656c18f9, 0x18b6631c, 0x5957e6d4, 0x14ce4ad6, 0x71fdddc4, + 0x92fc5ef2, 0x454e0e49, 0x3321f164, 0x271db4e1, 0x6960d8cb, 0x49fc393f, 0x4c1ac816, 0xbf4dfc6a, 0x97910357, + 0x58d728e8, 0x23d77e20, 0x827b1e4b, 0x0b0d8485, 0x99696234, 0xee5779cb, 0xbb7f6259, 0x600297e8, 0x144b00e0, + 0x55442d4e, 0x6f2002cd, 0x7238d5c5, 0xfccaf178, 0x9fc91885, 0xfacb1b0c, 0x1f36ede2, 0xb5946b20, 0x2c829a9d, + 0xddad35bc, 0x6a508f56, 0x263f3d34, 0x7d5a031e, 0x620bf72a, 0xaba2be6f, 0xf76252c8, 0x089d032d, 0xc26b4db8, + 0xdcb7395b, 0x8bd3705b, 0x0906929c, 0xefe09412, 0x0b3177d1, 0x7bb92644, 0xb3a2b0d9, 0xc4b64e4c, 0xe3700e74, + 0x09f20580, 0xc5a601ca, 0x0f44a475, 0x2cf7162e, 0x33d4af48, 0x9a4dc46f, 0x2261af7f, 0x803a2ac0, 0xb9605fca, + 0xa2598e9f, 0xedd49ff1, 0x0af8a891, 0x3885ca9c, 0xb5b13076, 0x227c95c9, 0x9cfd7f8c, 0x6fef3cca, 0x673eed72, + 0xb4cdf225, 0x17d92cbd, 0xd7557f60, 0x3a2d79bc, 0x856a36cd, 0x2c799734, 0x7b0bc8a2, 0x90cf6067, 0xae611b02, + 0x845623b4, 0x0f3fda80, 0xe1b98faa, 0x9b989818, 0xf4d07bcc, 0x22b742bf, 0x0c31f5e8, 0x32019393, 0x7a5fa33b, + 0x21e167ee, 0x5fa12b46, 0x9983a50c, 0xcacb442d, 0xe2d34ee2, 0xca5268d6, 0x00b9d96e, 0x8a055d77, 0x27528d06, + 0x9a39f223, 0x5ca840db, 0x7b949564, 0x0b180832, 0xb03e6703, 0x8ea49bb5, 0x0aaf0348, 0xfa1de6f7, 0xb6dd21cd, + 0x1681a925, 0xfa5eed97, 0x8e5e76ed, 0xa2b7efdc, 0x33e0f051, 0x7aba0f19, 0xbc814c82, 0xad07b80e, 0x50fc65f4, + 0x3933cda1, 0x25c12078, 0xc2a2e1c3, 0x02ea5f04, 0xd9687260, 0x8f53ad34, 0x5dee889a, 0x7ba06c83, 0x536779df, + 0x7ac84cf8, 0x00d392f1, 0x1903bb6c, 0x36883163, 0xfe2b7d99, 0x5df08e3e, 0x7cc1c932, 0xc37afb9e, 0x6bd2dee7, + 0xa54f3355, 0x3f94daed, 0x72e4fc97, 0x00b7c0bf, 0x16eb0f34, 0xaa76c1ae, 0xdaf0e958, 0x64c27dc3, 0x7ed0a9fc, + 0x2b629845, 0x0f2e3a10, 0xe3a5741e, 0xfbee6709, 0x396891c4, 0xa2896d49, 0xf6b49f1c, 0x228ceffe, 0xcb537164, + 0xb7fdc98b, 0x95464214, 0x6c29f1ba, 0xe282ec85, 0x8cc2fded, 0xd760180f, 0xbad09a78, 0x85953c3b, 0x59c27be9, + 0x900081dc, 0x14aa75da, 0x76014b4c, 0x8452d4dd, 0x6a2852d4, 0x9c32da70, 0x9c91611c, 0x2f16ad00, 0x2429394e, + 0x34edbf4f, 0x57903a55, 0xd2c16166, 0xc8488e76, 0x01e6d42e, 0x4307f46e, 0xf253a66d, 0x111df93b, 0x0070c650, + 0x84f1392e, 0xf66b4abf, 0x5a777fd8, 0x10922270, 0xf10686cb, 0xa290412d, 0x963e80eb, 0x906fa0ab, 0xd8f517ef, + 0x6a9ef0a1, 0x7f33b16d, 0x7c7897f1, 0x90764344, 0x24e5d990, 0xfaff6c40, 0x0412ad75, 0xf8acc0b2, 0x654ca8f9, + 0x2e5af20f, 0x187f04f9, 0x4f37fab1, 0xb32405fb, 0xbe1c575f, 0x6d836e42, 0xae4b0267, 0xc10c6389, 0xf7ee8458, + 0xef103650, 0x57b74041, 0xa46bb10b, 0x7403f5b3, 0x2c6fd5b1, 0xd89965b2, 0xda47e9d3, 0xae08ea69, 0xc3d710db, + 0x6a91c5ae, 0x82d81d7f, 0x9ad8912a, 0x4c46f910, 0xe81c1ddc, 0x5785a4bc, 0x8c1ac4b6, 0x2f2ff82e, 0x3512c788, + 0x55939c09, 0xad8fcdf9, 0x3621c69c, 0xe2990462, 0x96049288, 0x14f62653, 0x8d7ac63b, 0x726b8d45, 0x1f2276b9, + 0x2e06b697, 0x3ee5475e, 0xa5d3458b, 0x5607a5dd, 0xf947bd2a, 0x1f366751, 0xcb6a4dce, 0x918b5549, 0x29f9345c, + 0x20aeafe1, 0xc089875e, 0x7894ad3c, 0x8549c125, 0xaa7752d6, 0x9e514af1, 0xc6dbba17, 0x49883723, 0x64ed2a29, + 0xc31db0de, 0x03a0dd13, 0xa8ac03c5, 0xf0acba95, 0xabf71441, 0x3ef3fa19, 0xddeb3e86, 0x8dc0844a, 0xac26ac9f, + 0x56e673ae, 0x35a08abd, 0xec0ac656, 0xdfa04e4a, 0xc03cec97, 0x0bb82c70, 0xa4f05b72, 0x0a720a2b, 0x10c097c3, + 0x6ceab390, 0xb53c989c, 0x046f34bb, 0xe39b1754, 0x732f68cc, 0x5c42d401, 0x6ad947b1, 0xef02a060, 0x433a8cdd, + 0xf20147c7, 0xe8c00451, 0xa408b84e, 0x88fbfe58, 0x18004666, 0xa0ac50fd, 0x89a3ea71, 0x2660e267, 0xad7bed31, + 0x502e5c5a, 0xdc91b59d, 0xf2cf8c68, 0x19acafb1, 0x5079edf3, 0x04804e26, 0xcea0f463, 0x9726ee2f, 0x2bdb7fa1, + 0x75724765, 0x6522ecc7, 0x0127b268, 0xd6f0ab2d, 0xb8422ef4, 0x99f8254a, 0x5a253f7d, 0x8013c1af, 0xaec3837c, + 0xe5484039, 0x1cc2c233, 0x75be48c7, 0x0dd44bf6, 0x9b865642, 0x9b940176, 0x760f354e, 0x6667ab57, 0x7bda4d17, + 0xed597981, 0x25ad6fe6, 0x8b12ff2e, 0xab8619a4, 0x7684a56e, 0xcfe07a17, 0x2820847b, 0x064d4666, 0x1bfa22b9, + 0xfcec74c6, 0x9d139392, 0x26a3637e, 0xa4830e7e, 0xf79d4b43, 0xc9015448, 0x913c537e, 0x59611dd2, 0x47729733, + 0xc9b4455a, 0x2acce935, 0xaed9006a, 0x2c475e90, 0xfee354f7, 0x38f2a128, 0x113d5784, 0x0c30f407, 0x0331fc09, + 0x225ebe9a, 0xb05b5aa9, 0x13f2c9b3, 0x0761b4e9, 0x37fa4e32, 0x80e288e1, 0xac2819ce, 0x098300db, 0xeb59ad5d, + 0xf8878368, 0x643364bb, 0xeebad813, 0x8955a0de, 0xb4695fbc, 0xdcdd68c8, 0x87c76704, 0x6cafbd17, 0x605ae4a4, + 0xa4ebc3de, 0x31140667, 0x820ceccc, 0x623467f8, 0xb2bc3a32, 0x8222c73c, 0xfd1f70ea, 0x2e4e31ff, 0xab9581f7, + 0x71a19176, 0x7f827ac7, 0x227910c0, 0xdfcfa94c, 0xe18a4578, 0xe7dff3fc, 0x5006ae53, 0x01d7e133, 0x2d95487b, + 0x171d1619, 0xff8ae9bc, 0xe5f3dfd2, 0x32f50275, 0x78793085, 0xb9f872fa, 0x4c9e5e10, 0x2c44ae82, 0x3c66550f, + 0xc3b883c0, 0x26473905, 0xc9ff8198, 0xe4906d7f, 0x37d7892e, 0xa84e446d, 0x60cf0e11, 0xd5e04400, 0xd57e3467, + 0xe155fecd, 0x15e5cee4, 0x8ecc97f7, 0x9fefc319, 0xa7dc8e3d, 0x238b54f1, 0xb730382d, 0x63c1816c, 0x7c1757b2, + 0xde87d863, 0xcab4c393, 0x55c6e64d, 0xe1b0a261, 0xc69a7124, 0x754f0070, 0xb40dfd52, 0xca2e12ad, 0xa67d7c10, + 0x059f4838, 0x938164d3, 0x833fb1b1, 0xcadf1b91, 0xad822773, 0x241e16c0, 0x8c6687ad, 0xddc9bc80, 0x75914689, + 0x8460e269, 0x9ed0fd70, 0xfa6e1e45, 0x6e3e0f68, 0xac3d52c3, 0x053bcfa0, 0x9bade9df, 0xd415e6e7, 0x66e55050, + 0x6ea7b49f, 0xd4ee924d, 0x9b27034b, 0xc3a27132, 0x1f0457ff, 0x46da34d3, 0x5d4d5d02, 0x4976554a, 0xc8f899a8, + 0x2b3dc243, 0x9b3c3ff9, 0x03985c32, 0x6c891452, 0xf1db0bcd, 0xbbd93b37, 0xb0a7fa42, 0x8b207a81, 0x260e2b8b, + 0xc16ad371, 0x0d955654, 0x004e3cca, 0xd6735547, 0x3cc95852, 0x3e7ade52, 0xfbc4a2ae, 0x626af39b, 0xeb859c65, + 0x1dc0484f, 0xf915e83d, 0xc95183bb, 0x1e39d1fb, 0x40131542, 0x859ca649, 0x65e9f818, 0x5b6d6bc7, 0x95891654, + 0x3323c755, 0xd8942820, 0xca0a9313, 0x78395f1a, 0x53427d23, 0x59865c94, 0xde2addb3, 0xb1fea6ac, 0x048aa783, + 0xb12cd46f, 0x3f1bf182, 0x168c7b15, 0x60b28928, 0xa93ed3c0, 0x250f9c3b, 0x4818cb22, 0xc6b1aa56, 0x584176ce, + 0xbc643f64, 0xc75d4d05, 0x5d9583af, 0x3db3e323, 0x9106f947, 0xfb3e530e, 0xbe5ef928, 0x2d6d05a4, 0x70f77847, + 0xeae7fc97, 0xbca96ef6, 0x5feb95c4, 0xf17d1309, 0x623e8d2e, 0x077b2ed6, 0x43a7485e, 0xd03bb8bb, 0x7c906509, + 0x2436f5f0, 0x88f1ef28, 0x749c7cb1, 0xf55112b4, 0x6a7775ad, 0x73dca398, 0x76ac2376, 0xb1289267, 0x0a9fa85d, + 0x863a2459, 0x9f5577cf, 0x83b0b7eb, 0xb4fa6205, 0x5fa79f34, 0x9cdb7c05, 0xddea969d, 0x1176f370, 0xc0619ebf, + 0xe7d194ad, 0xcff74ef3, 0x1fb8f870, 0x6bcf08a1, 0x65b51486, 0xf68b2a3c, 0x15ea39e8, 0x6929b45d, 0xea9a51bc, + 0x5679a530, 0x77df2a89, 0x80b8bfab, 0x881445bb, 0x32e8a88d, 0xbed9aa15, 0x2523e6a7, 0x436145e4, 0x51f2e553, + 0x5b429499, 0x8485c3f7, 0xaab7dd65, 0xd064a4d9, 0x5e7f068a, 0x0334e011, 0x22f1eba4, 0x39881bbf, 0x5313970e, + 0x18168cc4, 0x3c8e5b76, 0xa22769fd, 0x94e6c210, 0xbc8e9035, 0x649145d8, 0x9cda1a9c, 0xc8055493, 0x3f4ba518, + 0x80206ebb, 0xca4696e3, 0x1857988a, 0xf621abfa, 0xd5f9aba0, 0xdd2bbca3, 0xae87753c, 0xaa930701, 0xcd4014d5, + 0x41c90716, 0x645a7250, 0x1643d59e, 0x6467c87c, 0x361267cf, 0x00447bd3, 0xf43b9f19, 0x3b32a39b, 0x24b40394, + 0x6efb7124, 0xd178ce22, 0xe14b99ae, 0x48cf10b9, 0x2085183c, 0xea2f211a, 0xab97768c, 0xc1dc78a6, 0x3815bbb9, + 0xdee6053c, 0x8e621c4a, 0xf5609006, 0x98136357, 0xc927083c, 0x866d1040, 0xa26f3877, 0x2dff19d8, 0x3499cbfa, + 0xd164cb57, 0x2c76596f, 0x8630d9cf, 0x36bfaea0, 0x1eb6a16b, 0x5137efda, 0x5bd47f91, 0x0df5a1f8, 0xc23fdedf, + 0x20cddb87, 0x2842b494, 0xecd0bcc6, 0xb9c2a1d4, 0x4637cb1a, 0x5d512633, 0x4d61f995, 0x6cb6569b, 0xb78c284f, + 0x3ebc7e53, 0x8aecbfe7, 0x83665d1b, 0x8ec760d6, 0x1e795bb3, 0xf76bfa12, 0xdab994da, 0x6996ead0, 0x2352e74f, + 0xc4438528, 0xf857a6c6, 0xdc02a2ee, 0x458fbf27, 0x48715b27, 0x614ad6ec, 0xb937a50e, 0xa3db878e, 0x3c462991, + 0xe6a8e49b, 0x0f0cf86d, 0xb3f09b5b, 0x079495f2, 0x0cf43d71, 0x22b3b20d, 0xaf859a88, 0x895656f6, 0x0c3f5458, + 0x5a5ad57d, 0xd3f6e517, 0xb3cc7ef7, 0x8e85974f, 0x1418a922, 0xffdc38f4, 0x02d5b49a, 0x779b3d64, 0x126cfb85, + 0xb71ef543, 0xbc0e7a5b, 0x7609a46a, 0xf43bfb62, 0xa96bb744, 0x20fe39ac, 0xec7842a0, 0x36d158d4, 0x9beba528, + 0x15b8c325, 0x194b67a9, 0x87424ce4, 0xc20d226f, 0xd17a2dd3, 0xb9ed5e43, 0xefb4d1f9, 0xed7f39a0, 0xcceb5193, + 0x5a1e0eff, 0x142d9510, 0x5bb270e2, 0x78565983, 0xf6369e27, 0xffe4c594, 0xc33b35d7, 0xc3ace6b0, 0xb1dd67f6, + 0xcf4ef556, 0x01cedbc5, 0x906e4d6a, 0x54172f53, 0x25f429bf, 0x4c95ac6c, 0x6356d52a, 0x3bc15ca3, 0x761747bf, + 0xac15f91c, 0x8a02dfe4, 0x6e37ad51, 0x5914ea8e, 0x109bc030, 0x1a3b10b1, 0x83e3add8, 0x662fe4ce, 0x1328ce2d, + 0x85186120, 0x4c69ccbc, 0xb7ed52b1, 0x36b3398c, 0xf80bce74, 0x9ddff258, 0x3d0c535b, 0xd85805f6, 0x202a1b83, + 0xd70a8356, 0xf8b87aca, 0xadfbc127, 0x747e6256, 0x6c233d16, 0x088c5613, 0x987fb839, 0x080897f2, 0xadbda886, + 0x3470fad2, 0x18011009, 0x20596446, 0x8646b81b, 0x50f9ba38, 0x9efb457e, 0xaebd1592, 0x644d6a35, 0x4ca2d344, + 0x199cfb33, 0x03ed0752, 0x103b526f, 0x342e8452, 0xb639a234, 0x87ed9b91, 0x6c3d98e5, 0x303eb8a6, 0x57332db5, + 0x2b1e6a59, 0x5fb88951, 0x381f1456, 0x680dec51, 0x5b94c862, 0xfc6270bb, 0x1aee785b, 0x00f42437, 0x23b7884e, + 0xae6d8f67, 0xbc8e6aad, 0x4bd30332, 0x68083997, 0xabc15349, 0x81eaefb7, 0x15a28d5a, 0x1e2180d7, 0x8bf5b7a3, + 0xeaa55d82, 0xdc825883, 0x54ee1b87, 0x95c37c9f, 0x28910899, 0x39d1ac55, 0x3397fcda, 0xb143b20b, 0xdf4e1d99, + 0x6c79edba, 0x75a474cb, 0x166086db, 0x267644ff, 0x17201e49, 0xc8640f00, 0xfa6f24d7, 0x5619d0ac, 0x53f6b0c2, + 0x1107ed9e, 0xe9191dba, 0x4b2ca76e, 0xd77899eb, 0xe99c768a, 0xeb979670, 0x698a97b1, 0x98f78ca3, 0xeafaab61, + 0xf215b0c8, 0x00a99a1d, 0xd566029f, 0xee07f041, 0xf7167adb, 0xd319345a, 0x14ec19f5, 0xc23a08e1, 0xb6132650, + 0x4e14c799, 0x7097695c, 0x6a73061f, 0x4c5fd29a, 0x50c5fe56, 0x722b7fdd, 0xd4e7dbd0, 0x162a7c7f, 0x916f4be7, + 0xf1c3aec1, 0x38b7c67e, 0x8c3981d3, 0xe4472469, 0xa558f4fa, 0xb64459e3, 0xfcdf7b2a, 0x2e9bd971, 0x3bfc2aec, + 0xd8b309e6, 0xae00ab75, 0xc739eeea, 0xd152c343, 0x5e8b3eaf, 0x4d0c4ef3, 0x65274170, 0xad7c79ec, 0xf664446a, + 0xef243f60, 0xa8f47842, 0x7680a709, 0xc6aba273, 0xcbf64071, 0xd4fa8965, 0xe01871a1, 0x67bd3c7f, 0xe0c9fe08, + 0x5da9400e, 0x37aee32c, 0x999568a3, 0x986e9cf8, 0x3618af44, 0xe3f37c0c, 0x61c23ae2, 0x2a0ecee3, 0x8db4d9a4, + 0xdf0f9899, 0x0eba67b0, 0x3f7bfdac, 0x413e790c, 0x75d9bd40, 0x769146e1, 0x244f8bfc, 0xea1d5d5c, 0xa2987256, + 0x4575e794, 0xaacc9168, 0x399dae78, 0x12bf22a1, 0x9c93eb67, 0x16c629ef, 0x3d0fb835, 0x2d15444b, 0x37994a5b, + 0x156759b2, 0x8efd5143, 0x44a091a1, 0xa9eb95f1, 0xe7a0d8ff, 0xc33241b2, 0x970a7686, 0xed1ff70a, 0x908c8d8e, + 0x342c753f, 0x71472f40, 0x8a5eb77a, 0xbeb415a1, 0xff33f311, 0x31e41f08, 0x5da69a07, 0xd70744b9, 0x0ecfca78, + 0x6f02765f, 0xce9161db, 0x22728f9f, 0x0b2acaea, 0x90ccc9e7, 0x24256bc4, 0x729ce6ae, 0x5d7624aa, 0x6c333a89, + 0x868e2aef, 0xdf9f7f60, 0x8c6ed9b9, 0x5ab06b7b, 0x31ea246b, 0x9e7b1f53, 0x96e3c1dd, 0x5d9d28f9, 0x5ab94c53, + 0xea24e476, 0x3b5cb96c, 0x44693f9a, 0xc3befcee, 0xe5a101f6, 0x0f24ea12, 0x368fd03d, 0xc5ecae7c, 0x9507bbc1, + 0x3e8656ff, 0x60f390fb, 0xc9b0edd4, 0x0c6ed4a0, 0xc164aa9b, 0x5c429d78, 0xdd421e96, 0x666a280f, 0xbf4b4f06, + 0xb417c888, 0xe6278c92, 0x9b8415f4, 0xd322e977, 0x28f69c83, 0x0ae55498, 0xef59d585, 0x89387345, 0x1ba4be32, + 0xe8052c41, 0x7fc06538, 0x10027a18, 0x15d36589, 0x86369a33, 0x241e3ebf, 0x2c46cfe0, 0x84c9f37b, 0x73734fc0, + 0x489afa2c, 0x2f154edf, 0x0a6cfa4b, 0xbc088369, 0x591ce377, 0x5da380e7, 0x867e3dd6, 0x46b6d9d5, 0x2ef86ad4, + 0x50aef70b, 0xdbc452aa, 0x396f6976, 0x74222578, 0xbb2f71b8, 0xb7bf76a4, 0x401c0212, 0xdbe46e7f, 0x257b54c5, + 0x3983de7d, 0x93aae1c0, 0x2d8b6c82, 0x12d0e738, 0x58b94992, 0x114644e4, 0x84abaea1, 0x863db751, 0x4e7be75e, + 0x7a98e360, 0x69f6473f, 0xf2d3d629, 0x27ab2949, 0xdf648ef1, 0x1ac9e035, 0x3c559d73, 0x3cdae630, 0x6dcee87a, + 0x2642632e, 0x63851cfa, 0x77bc792e, 0x7e465999, 0x031229cb, 0x62db20e0, 0xc49d8c06, 0xb6e07f87, 0x65d2f081, + 0x60678f07, 0xf039a9aa, 0xb6b6129a, 0x0845d5d4, 0xdc3f7aeb, 0x6c7fa4c4, 0x63bdd94a, 0xc88076fe, 0xe5f3d8d0, + 0xcbe29463, 0x3a771714, 0xb7ab1fb2, 0xd43d0045, 0xe8577c61, 0x8ea6b3eb, 0xc33a70fb, 0x8259f305, 0x58772379, + 0x04d592d7, 0x7ed27a2d, 0xc7a2ea17, 0x47d03b05, 0x05465e8e, 0x8edc061b, 0x58774d72, 0x3f4d5890, 0xee913f86, + 0x26e9d773, 0x2ceabd42, 0x494267a1, 0xb899c62f, 0x19a4f7ca, 0x594f052f, 0xcd4fe61d, 0x91fabc95, 0x4e6fd88f, + 0x3b188662, 0xeccdcfcf, 0x67a6a4a2, 0x04122919, 0x944d0c61, 0x4e285785, 0xbf6b6ff3, 0x05aff69a, 0xe3e7f103, + 0x4158d901, 0x26541693, 0x85825324, 0x2e70498f, 0x5100e656, 0x818ea91b, 0x3c957ea1, 0x51187875, 0xa27ef80d, + 0x71fe01be, 0xd0d6f224, 0x6b0535a7, 0xdcf9f964, 0xce17c985, 0x46aead00, 0x2a3f37ce, 0xd3f4307b, 0xfaf5ed94, + 0x3f12bdf6, 0x6d9109a7, 0x7cefe2c6, 0xb3d631a6, 0x105965f4, 0x4980dc42, 0xe02dbd30, 0x72f9e5e3, 0x7858b484, + 0x4fa15358, 0xb1a6fcff, 0x95ac6acc, 0x47baf94e, 0x2fe56a18, 0xfb5e5f86, 0xe09cf2dc, 0x096935b6, 0x6eb8d1cb, + 0x8d53d2e1, 0x5e00d989, 0xa2e93d16, 0xc38d1d53, 0x98049195, 0x5b9f2e49, 0x91d92407, 0x90cfdab1, 0x232a373a, + 0x6bdf6f63, 0xefc1b640, 0x0a56be92, 0x5a961d1b, 0x522e282f, 0xca223fc1, 0x837e0e79, 0x24c267b9, 0x22808372, + 0x3461a6d9, 0xd5bbe413, 0xefaea99a, 0x9806e085, 0xae1e155e, 0x0bcbe564, 0x8ea1d4cf, 0x0d400022, 0x867da6c4, + 0xe9f9381c, 0x7f147fcf, 0x1ec923f9, 0x879c9743, 0x08c603aa, 0x15c606c3, 0xe95f7e09, 0x3cb71c3d, 0xc8027522, + 0x65162c5b, 0x93982b58, 0x1986533a, 0xee6f9b43, 0x2e25e9a4, 0x2754b310, 0x3412f194, 0x601b398f, 0x743096ee, + 0x2fd318b0, 0xa2c81180, 0xd68da9c6, 0xfdd4cb12, 0x31c11dd8, 0xc5405018, 0x0f5af2cd, 0x97cdd2aa, 0xb25d76ea, + 0xb5b8aa1d, 0x613f1775, 0x86e54bb6, 0x4328b11e, 0xc79aed58, 0x58b96cc3, 0xa504adce, 0xb526d684, 0x772ebdaa, + 0x639d4643, 0x230d2bbd, 0x606ba8f8, 0x4cabf635, 0x6b0b81f9, 0xba7b4ab1, 0x99120690, 0xef9bf6d3, 0x0b3716bd, + 0x6a4460fc, 0x79c17c97, 0xcb095c1b, 0x1375df53, 0x7b9cebc6, 0xbeb56ff6, 0x6b91d002, 0x30e19cb2, 0x1ff98e5e, + 0x6b0c0ec1, 0x6b28e3d6, 0xd4c0d6b8, 0x3137d822, 0xd2d237a3, 0x68b41136, 0x345d7860, 0x54b55ce4, 0x726e7f34, + 0xaed8f2dc, 0x73332fec, 0x252b07ab, 0x3f9c7e0d, 0xea961fb9, 0xafbd6417, 0x314bb27c, 0x3a504807, 0x7ffc178b, + 0x7ce011ec, 0x0ccbbe78, 0x01a8b47c, 0x13a36494, 0xe7e3119c, 0x3ed5b34c, 0x9832b989, 0xf8db2c46, 0x41fc9ca5, + 0x0f584b21, 0x50544629, 0x813c32e4, 0xa9cc3abc, 0xeae317f3, 0xa17d3be3, 0xe61e9e4d, 0xbfbc6447, 0x977ce532, + 0x212b50a6, 0x02abb654, 0x1c0c7718, 0xae844e79, 0x74b2a99d, 0x3f4f42d4, 0x5c117441, 0xc393d84a, 0xdf53762b, + 0x71e1baaa, 0x568ae06b, 0xbf22d57c, 0x6ef1e58c, 0xf1b963fa, 0x528c3316, 0x8e5ab904, 0x137acba3, 0x7e11c8fa, + 0x5a7ade1d, 0x09663057, 0x66bc7c8b, 0x183dd2c7, 0x6024e6bb, 0x532f2680, 0x14d1885a, 0xa65e9c47, 0x5dfaaa0d, + 0x88b6be7a, 0xaa746c4e, 0xdf325d70, 0xe4c41c0e, 0x973bbcb3, 0x50a28a11, 0x2a366188, 0xf98833f1, 0xa3f743ba, + 0x4b977c9a, 0x3879bca7, 0xd233628b, 0x4637eb3e, 0x493b62aa, 0x3d45e7dd, 0xf1a0ef2f, 0x9d69d96d, 0x9dfdb751, + 0xb5b566f3, 0xf321f09d, 0xf7e0b5b2, 0xcee883a9, 0x0fbbdbad, 0x7bbacd4f, 0x8b42c947, 0xc8d537e5, 0x7370af0b, + 0x03cc337a, 0xb87efdf3, 0x51901732, 0x5ba5a2f5, 0xbdb69133, 0x95291d35, 0x01285a2f, 0x40dc23ad, 0xfede2058, + 0x0fe06530, 0x865a6014, 0xf4a26fe9, 0x535934cc, 0x1b111578, 0xc016bd49, 0x0405a565, 0xf347f7ab, 0x06efb881, + 0xe88fbde5, 0x67ee8152, 0xb0c32bce, 0x4b73a9ea, 0x245711e5, 0x09e5e2bd, 0x9c3d6ce3, 0xf367b6a2, 0xe4485402, + 0xfbb21dfe, 0x9ead2780, 0xbbe512ca, 0x8ae6e72d, 0xe140d3a3, 0xfb6c25cd, 0x05aac970, 0xe2342735, 0xcbd48c8b, + 0xe70d64bb, 0xd0e582a8, 0x9a3d097d, 0xc2c48415, 0x5b44caa3, 0xbafd1224, 0xef535d22, 0x193f4080, 0x4656d4f5, + 0xe7a25b73, 0x66512257, 0x4016a5c3, 0x3d1ba36c, 0xaf1b35e9, 0x7027e31c, 0x2c139f2f, 0xff937393, 0xffbd437c, + 0x0e12d927, 0x0fbd9f4f, 0x9d51b53a, 0xeaf69fa9, 0xed650eea, 0x8c6c76fe, 0x5d30e377, 0xc40d161b, 0xdff22d23, + 0x7fd8e9e7, 0x27f92329, 0xcc402921, 0x795931e2, 0x4d142c5f, 0x3d159863, 0x0e940404, 0x031fc25a, 0xc73b738d, + 0x3d6d0545, 0xbd37ed45, 0x9eaa35b5, 0x4cb69c22, 0x15d1ef01, 0xed2f7e58, 0xea039092, 0x6849dcd2, 0xa51aecbf, + 0x2a07bb9c, 0xea1fa4a5, 0x9143fa24, 0xf916d4ee, 0x125fb2a3, 0xb4b9d0c6, 0xd7fb5a51, 0xdacf22a1, 0x7a6cadee, + 0x357d3afc, 0x2d1b5b2e, 0x43048f62, 0x1d5669ca, 0xb817ee46, 0x46d115a4, 0x967213cc, 0xb915df81, 0xd0043a97, + 0x20c33bd9, 0xe9224767, 0x83ea8a3b, 0xd0409785, 0x157d3e85, 0x82810386, 0x94685fbd, 0xd05bd730, 0x224cd855, + 0xe2530547, 0x897ce577, 0x1e3cfb51, 0x4f055268, 0xe96ae027, 0x73e45b88, 0x7cfbc29f, 0x0801f0d1, 0xbb1b6f29, + 0xcd1dfdd6, 0xcfb71f83, 0x2427ccca, 0xa8bc2cb0, 0x18b4b77f, 0xce3eeab0, 0x65196b9e, 0x17c431f9, 0xd5a091fb, + 0x5f2fce00, 0x3b406ec3, 0x1a0d4853, 0x44c0c44e, 0xd7ee64fe, 0x2a84c228, 0x187875d6, 0x2fb485da, 0x0ed1b061, + 0xaf343fbe, 0xed6ffd83, 0xc5dc43f9, 0x2c546720, 0xf135e9a4, 0x7cb8bb5f, 0xbd20a37f, 0x8d43b670, 0xd806883f, + 0x2db650fe, 0x604de27c, 0x21dbe9f4, 0x3cdc7a95, 0xd49541c1, 0xa8213f87, 0x35429ed6, 0x305acd41, 0xeee93933, + 0xbc12fbff, 0x62824e68, 0x6f39280e, 0x00b7240a, 0xb8bcd20a, 0x40ff68d4, 0x0fd401d6, 0x70c6773d, 0xcb5ce22c, + 0x6e411fff, 0xc68d6182, 0x6f99f694, 0x9cacaeb9, 0x2ae09ec9, 0x4ec2adac, 0x3fb4d8de, 0x5715a073, 0x46ee3a5a, + 0x96bc5bbd, 0x9189b14f, 0xbb2af335, 0xfa1e6d04, 0x7bb37160, 0xe38d8a09, 0x7503c504, 0x3018e0e8, 0x834c6acb, + 0x9d97e1eb, 0xf7198062, 0x02873272, 0xdc44d255, 0x2cb1647b, 0x5afdd97c, 0x30bf7425, 0x4946454c, 0x5c3a7953, + 0xd1ca4726, 0x93369765, 0x49fc3ac0, 0x2da737f4, 0x110df2a8, 0x7909938a, 0x2c912931, 0xe5e78178, 0x08e0f003, + 0x649fcdce, 0xd385cdf1, 0x91bfd43d, 0xf21db3d3, 0x9cb06a8f, 0x61c89ba7, 0xde166dc3, 0x7ff66af9, 0x83ee4a01, + 0x996bffd1, 0x0172e7b4, 0x295b0d3d, 0x4ceb8079, 0x888b9329, 0x9964e147, 0xb216aa51, 0x67ca6001, 0x74b2c5d6, + 0x0feba781, 0x876ef973, 0x5b832b01, 0x02f6c244, 0xee355044, 0xe2787c1c, 0x3a936f61, 0xbc2e749b, 0xc410c0f8, + 0x544d36a0, 0x9590c596, 0x4d5b9320, 0x9cbed2a1, 0x6bd155a2, 0x3ab22265, 0x9484d410, 0x0d0ad09f, 0x4a17c278, + 0x665193a4, 0x8e94d489, 0x680605c8, 0x667c9bef, 0x48f36482, 0xc52bf264, 0x3d929179, 0x87685916, 0x12f75bb1, + 0x584de2dc, 0x146ef6b9, 0x4cc2f38f, 0x9711be59, 0xa5c747fd, 0xe214d83b, 0x1ee840cf, 0x9dfbe088, 0x64ce53ac, + 0x577213c5, 0x919aca55, 0x083f1625, 0x603cb8aa, 0x2692fe68, 0x6f7844d6, 0xec54a9af, 0x12702e38, 0x7fb92c9f, + 0xfd512045, 0xf18e3992, 0x453f8429, 0xb26d3d6a, 0x6f5033c5, 0x3b478729, 0x2d77967d, 0x5d4d72b0, 0x65c67973, + 0x934d9aa2, 0xfe4a8d1b, 0xa0258e4d, 0x767421b0, 0x1116975f, 0xc4a88804, 0x329b5437, 0x679f1850, 0x2b5e10fd, + 0x5518ce5e, 0x92dd0566, 0x29e8a2fa, 0x293267a4, 0x3877fd0a, 0xd0dd01d6, 0xcf356a8e, 0x7b49a8b0, 0x93607c3b, + 0x446bd752, 0x9c932943, 0xb424a5d3, 0xfc5f769c, 0xb6a00fb9, 0xdb3d166f, 0x7d3ff79f, 0x08f5f2dd, 0xb401ce8e, + 0x57bd168b, 0x12fae6f3, 0x3e0768f1, 0x35347821, 0x75e8d7d8, 0xa2ba528d, 0x24742eeb, 0x482873c5, 0x9c3a6ab0, + 0x8abcc6e2, 0x16f3e42f, 0xa98fe468, 0x97e2eb6a, 0xd0afd8a8, 0x305b112f, 0x1d973a04, 0xde986a94, 0x24700a80, + 0x75a98d1d, 0x30a2986b, 0x41d88720, 0xe5b07c4b, 0x5a1b4185, 0xb01e8826, 0x66a8515e, 0x33ebb45b, 0x281fac21, + 0x119878d8, 0xcc17e5f5, 0xce4f130d, 0xe2a77536, 0xe58d7221, 0x761c21ce, 0x7446234e, 0x816d721b, 0x13845ded, + 0x73a84fda, 0x69677408, 0xfe941a36, 0xfd7846ea, 0x6f26624e, 0x0909a8dd, 0xd1a62ebb, 0x6b81ec38, 0xe1b7ba42, + 0x5db7d257, 0x9872b12d, 0xa14f28ec, 0xf4b1415c, 0xf9633fa9, 0x570be637, 0x96483b78, 0x087160fa, 0x146366be, + 0xb39e4b37, 0x37e3e387, 0x256aed5d, 0x4533ce08, 0x364939db, 0xd8b3a10e, 0xf922e392, 0x4b7a27ea, 0xf55084ca, + 0x5292f4a4, 0xcbbc5d31, 0x526adad4, 0x9962fa39, 0xc18bdb41, 0xe8171b34, 0xe0fdb695, 0x00ff284a, 0x80eac4c8, + 0x3412952e, 0x16158069, 0xab25f12e, 0x2109ffe3, 0x9bde2bc2, 0x5687f084, 0x9feba034, 0x2d5c6fd1, 0xf6c0d89f, + 0x0ba7bb64, 0x7ad37855, 0x2967f875, 0x9944e653, 0xa4909167, 0x41c0ecc1, 0x5aca1b78, 0xa78f61db, 0xac766181, + 0x07d3d978, 0x03b8cf1f, 0xc2355f98, 0xb27f6ac5, 0x37404eb8, 0x3987816e, 0x7fc3bf53, 0x3d20e5fa, 0x518027d7, + 0x03ad2414, 0x2a331416, 0x520403a8, 0x9fe882f9, 0xcff9836e, 0x827a1225, 0xfaaf1105, 0x2070f6eb, 0x257e92a0, + 0xa37ff802, 0x72e3239c, 0x941c4284, 0x0690c61d, 0xee10f918, 0xf097b417, 0x931a8502, 0xf32041f7, 0xbe563cde, + 0x0d9e9647, 0x1bbfa228, 0xff098c5b, 0xa1cbd943, 0x7aecb7b9, 0x64a40ac4, 0x98571157, 0x221ef03f, 0x4df097f1, + 0x12a7d1f3, 0x6890dee8, 0x3d76a8a6, 0x09d5b7f8, 0x46d20c42, 0x9cefeb69, 0x154bb0cd, 0xd1cdd4d1, 0xd0e9c8d6, + 0xcab6073c, 0x2891c81a, 0xd85f8ef1, 0x90dd67f3, 0x1c2a355e, 0x153f68f2, 0xf2a1ebb2, 0xc9c9b426, 0x6482c0ab, + 0xa5641e68, 0x9ffbfe8c, 0xc974286c, 0x8dedcff0, 0x3c8db60e, 0x68fa2dc7, 0x71446ac5, 0x5a085497, 0x0a954f57, + 0xd050843c, 0xe0ab7733, 0x435901f8, 0x7773200e, 0x3ea698c6, 0x833cf61d, 0xc75b56cf, 0x73daaec6, 0x80f236ec, + 0x06eb56e7, 0x3bc87d41, 0x66e08ebe, 0x75599e3c, 0xac0f2d12, 0x31a8e3a6, 0xf62cba12, 0x1d17aeea, 0x76f56798, + 0x41f953f2, 0x88a18764, 0x0c85a2b5, 0x8d5a2cf7, 0x6db48cfe, 0xfde0ebb9, 0x67a8371a, 0x2668dd00, 0xed96db68, + 0x12c403fc, 0x34f21ada, 0x0091b0be, 0xfec6e0e9, 0xd3faf790, 0x40482783, 0xef742964, 0xdafd273e, 0xf4f088ea, + 0x19d6e9a3, 0x2689aa5c, 0xf8da1409, 0xdc97ea82, 0xd0606f55, 0xc96c2015, 0x80454186, 0xf85eb77b, 0xdc6e1fc6, + 0x15c40cf3, 0x9719cd9b, 0xb932c0d0, 0xd96c56a5, 0x77feffeb, 0xc57b5f19, 0x97dce0f5, 0x8296b766, 0xfdc8f004, + 0x7f348f5d, 0x337ea0e1, 0x976911d4, 0xf72eae74, 0xf3e664f6, 0x121a455f, 0x59f5abea, 0x3740d199, 0xda8580ed, + 0x59a69527, 0x88583f1b, 0x7928345d, 0xc1d1d21b, 0xa4b1e8ff, 0xee477f30, 0x6deb1684, 0x464147e4, 0x30bcbd72, + 0x20a6fecf, 0x217890f0, 0x078dd5e5, 0x63f83d44, 0x15ded733, 0xbc5c6ba3, 0x4e8b970e, 0x1b0c357d, 0x7be0da28, + 0xe683b945, 0x5ee978b0, 0x1e3237e9, 0x058f9a7c, 0xc7462773, 0x3634a30e, 0xd8f8ec9f, 0xf276e87d, 0xf3123927, + 0x6f21a52f, 0x1585038f, 0x1f87365d, 0x9868e0da, 0x57ff2738, 0x81a6b20c, 0xb200285f, 0xd808832c, 0x6a65b57c, + 0xda239ab1, 0xd13ddb3a, 0xb25c06ce, 0xbf384e13, 0x4187455b, 0x1e96f83c, 0xef601c72, 0x04d9ee8a, 0xd1f37ab8, + 0x110bcef9, 0xc6b7050e, 0xb0d5a07f, 0x0534c639, 0xb3bece7e, 0x79893f90, 0x97c81912, 0x2a7271f6, 0xfdab5dc9, + 0xe8076df8, 0x711880cf, 0x4a1d6495, 0x7223fc80, 0x43268197, 0xabf2c66c, 0x36e21f67, 0x4c592237, 0x5ef2c2a1, + 0x3a11c2c6, 0x03ab4101, 0x2ccddcc0, 0x8c348f8d, 0x49587ff6, 0x4b4ca660, 0x211cd6c8, 0x6d61809c, 0x0abeee5e, + 0x5e2f120f, 0x541da6fb, 0x5868287c, 0xc8239110, 0xbd24b039, 0xe91e290f, 0xacb28d6f, 0xb6e1b545, 0x756e0224, + 0x805b10df, 0x1c8f9998, 0x3bec81e0, 0x897c72e1, 0xcd38bdb0, 0x484b5422, 0x03ec0f01, 0x0d495f38, 0xea8e3bb9, + 0xb530ad7b, 0x365a6b6e, 0x36bea876, 0xb682f531, 0x7fc2f99b, 0x9e80af3f, 0x09f3347d, 0xf8cd0bb6, 0x2f67ca96, + 0x0bbb7aa6, 0xd95dcb6f, 0x20a580ea, 0xa36a15cf, 0xed01d8e7, 0xc479136e, 0x3c72c11d, 0xdedc2001, 0xf11d890e, + 0x8bd3b0f5, 0x88060db9, 0x4585f706, 0x5c9c0b3d, 0x50059e93, 0x3a53b9a1, 0x5d774ec0, 0x32bba9f6, 0x0a40c794, + 0x3ee31432, 0x144ecd03, 0xcd2a0e19, 0xee3fb03e, 0xb2df5a3f, 0x2489b09a, 0x716c7c25, 0xb5885c0f, 0x7ffe02ff, + 0xe1a5b7c9, 0xc7039343, 0xea7aec1f, 0x2b35b5de, 0x5efbd3a1, 0xb1605e65, 0x3604d074, 0xa4d4b7a4, 0x3de88c14, + 0x9e643f3e, 0x5793f7e6, 0xccc5fd92, 0xc45a0063, 0xfc4ded1d, 0xdbb3b5fc, 0xdd62fc08, 0x3c041879, 0x719f6fcc, + 0x0bf0b38d, 0x9d60389c, 0xaf964ef7, 0xadbcf7d9, 0xfe7b208f, 0x62b33ee2, 0xa2681199, 0x24e37793, 0x0bdc6fb9, + 0x529917fa, 0x1356f141, 0x3b50db67, 0xc4cfc29c, 0xd8a8fd57, 0x620f2cd2, 0x5733da89, 0x1992e956, 0x5f3832b3, + 0x501bfe15, 0xa762ee91, 0x5cb58087, 0xc7057104, 0x6ebdeb15, 0xd30c0695, 0xbeebf9f2, 0x5a40fac6, 0x4de535ca, + 0x5724447e, 0x7a682fbf, 0x92971a1c, 0x88cb1e4d, 0x1e339ce1, 0x2fec8955, 0x126b2915, 0x345e43fc, 0x92b8641e, + 0xec887ec5, 0x4eaf75e4, 0xf750a796, 0x15a91b37, 0xbb8cabd4, 0x625be9cf, 0x4a53ca52, 0x45485342, 0xb364a502, + 0xb0eb509f, 0x38f849b6, 0x8617e656, 0xd5788d53, 0xb6a0c063, 0xd36fe8da, 0xef7e2f77, 0x2f05c1dc, 0x30fc1f98, + 0x6fe3e1fa, 0xfedc8a18, 0xf4f07253, 0x8ae1269d, 0x9b30c515, 0x66a5b93f, 0xdb55e537, 0x3d4de498, 0xe17d1358, + 0x8126237a, 0x0ffc90c7, 0xa7d16d89, 0x9596d2df, 0x63ad7f47, 0x1f7ad6b5, 0xd0551f8c, 0xf261dbcf, 0x50faddb2, + 0x52303ff1, 0xac69eb2f, 0x08a46fc0, 0xc2751af2, 0xc38c0b01, 0xf1a39171, 0x6f05af01, 0x92fb494d, 0xe41e17bc, + 0xde31d47e, 0xeacfca8b, 0x9e8fb339, 0xc257d2a3, 0xc022c392, 0x011832d6, 0xa9343fae, 0xad9e04ca, 0x983884e3, + 0x7f256f86, 0x79facb1f, 0x42f534a5, 0x8f94ab51, 0x28d1f080, 0x8bd4b4ba, 0x12bc8d34, 0x6aa741c1, 0xe95e7c7b, + 0xe1b3d142, 0x36bc2867, 0x4b7c8fc9, 0x369d3092, 0xad90f90f, 0x105ce85c, 0x1fb91167, 0x07fed270, 0x555f584e, + 0x7c06ce52, 0xa59f6388, 0x2dd1d4d6, 0x7defaa8c, 0x202ecc96, 0xae1ee1fe, 0xaebbc452, 0x041f9fa8, 0xb76fd897, + 0x9a3c5e23, 0xe846452b, 0xc2717a1d, 0x12e7f873, 0x5d0b410e, 0xb5ca564b, 0x4cc291fa, 0x740f2bd6, 0x2a4bcb9e, + 0x8d804412, 0x0d1767f5, 0x53359f60, 0x720608d4, 0x700f357c, 0x35aa0ca7, 0x14fafa7a, 0x46c85958, 0x00a5c2e2, + 0x1cbd7ef9, 0x67887825, 0xd9293d0f, 0xfec19dcb, 0x13ef6f03, 0x7ffa663d, 0xcc174011, 0xef671ff4, 0xf1410da5, + 0xfccd4029, 0xeea5d646, 0x277c7fa5, 0x2845c6b5, 0x275d0daf, 0x1f3fa11d, 0x0bea2248, 0xb3eeca9b, 0xaec73374, + 0x0bee496b, 0x1cd9c1b1, 0xad922cb0, 0x1f4f4ec9, 0xc99db83e, 0xff6c690b, 0xcc9304e3, 0x985d4e30, 0xd597a4ae, + 0xd22cc34e, 0xe6b9e717, 0x984c2cc8, 0x4a5b3f4f, 0x909b22c5, 0xad58e560, 0xd2345e87, 0x7692460a, 0x194549ff, + 0x1f7b2546, 0x2897a935, 0x9374851c, 0x7ace60ec, 0x064be6b1, 0xc0634d0f, 0xc708f557, 0xf2c472b7, 0x56ce8d34, + 0x7c93a8ee, 0x6d1b7248, 0x7f4bb0d7, 0xb6ed218e, 0x49d0def5, 0xb8902d92, 0xa38a6dfc, 0xed1f6d54, 0x4c5c1ccd, + 0xfca907af, 0xfdc01ff5, 0x4f3b9934, 0x752cf2e3, 0xb114e643, 0xe08a1571, 0xcabc7eb8, 0x69ff74ad, 0x8b7beb10, + 0x032dcdbc, 0x9ed08c36, 0xecc93efe, 0xaeb79803, 0x68305bfa, 0xb1fc55af, 0x21fc102a, 0xcb47b8fc, 0x00d8a9ff, + 0x8346e645, 0x12723961, 0xe1f8e936, 0x4f908b2b, 0xd54a4734, 0x6d503d17, 0x76c03dd3, 0x365e55e2, 0x80794524, + 0x79aac794, 0x9596878d, 0x9e460656, 0x3c569c17, 0xf8e9d39c, 0xd1b9374f, 0x4fc10414, 0xf31b3dc1, 0xff8a2d10, + 0x04dce5c7, 0xd08c5cff, 0x3bd6c460, 0xfa77d38e, 0x77308988, 0x05494f97, 0xc98d23ec, 0x168d2767, 0x84c53da9, + 0x8ab1e99b, 0xebaa1bf6, 0xc37f4deb, 0x5f57b719, 0x23d8b727, 0x1d36cb46, 0x3d43d8fe, 0xf78a3526, 0xf832b41c, + 0xc733f705, 0xe79117fe, 0x2ca1b611, 0x9172a0d7, 0xb44bae31, 0x758b8e98, 0x14163aea, 0x67b867be, 0x33d4e410, + 0xca6e6e45, 0x14e846dc, 0xa9119d0d, 0x96cb646b, 0xb13568cd, 0x10444630, 0x60f1cee5, 0xf91bfe4b, 0xa7bf7b64, + 0xafb039b0, 0x9ec73b77, 0x482210b9, 0x10dc9052, 0x72972be9, 0x696af92d, 0xbb1d6aff, 0x97e4630b, 0x6dc623e2, + 0xd38145f4, 0x9f509854, 0x7ce4b373, 0xff3a4079, 0x1be71c80, 0xb0448587, 0x7232f3a2, 0xc13afc06, 0xa5207d87, + 0xf76e38d1, 0x3fe48178, 0x300e5fe5, 0x958dc24c, 0xeab4af76, 0xaab7480b, 0xe7e87979, 0x72379618, 0x03ae26c8, + 0x4b0bafb6, 0x6f7c2e9a, 0xdfe7ab56, 0xf54ac4db, 0xaeb50669, 0x39221738, 0x2a3ae47d, 0xc6665a90, 0xf40336ea, + 0x9ab2e001, 0x2cddfb9e, 0x6ed15f19, 0xfd608b91, 0x265199f4, 0x8e9963ea, 0x4a568b33, 0x2d2d83bf, 0xc3ad613f, + 0x3a1af7ac, 0xe4f063d1, 0x2ee5068f, 0x492ba6a8, 0x55e34697, 0xafc11b26, 0xdbe7e763, 0x744bc6d7, 0xb4de1d89, + 0x31d81a28, 0x1a3f1fc1, 0x21a45c72, 0xaf12ceb6, 0xc710b2a6, 0x8b703a8f, 0x882f6f55, 0xab526895, 0x5865e347, + 0x96014c3b, 0x0d5e5c43, 0x0104b77b, 0xa8348fbf, 0x4f5ff93e, 0xb15f6c9f, 0x9d5dd46a, 0x00484582, 0xfbf4b03f, + 0x9b338872, 0xf1bc7186, 0x84dba715, 0x57f2980f, 0xfdc8530a, 0x1b605b35, 0xff66678f, 0x63510a7f, 0x4fa97cd5, + 0x7907bf26, 0xe33bd93d, 0xd4c513a6, 0x27dfec3a, 0x3a7ff5dc, 0x5bb787cb, 0x5e460c45, 0x1f54bfe7, 0xb7760d41, + 0xd46e02b7, 0x1ca886b8, 0x8cddb73b, 0xa6831143, 0x8ec9cf79, 0x3827a2e6, 0x3932a05b, 0xaff3bcd8, 0x50924ae5, + 0x9f5329b9, 0xe440487d, 0x33acce8f, 0x27da97f3, 0xc2fe1eb5, 0x6d4d7942, 0x52516fca, 0xd7d81473, 0x3b2adf6e, + 0x9a0685d3, 0xe48c2841, 0xe9e22d0e, 0x154ca684, 0x01fd43da, 0xc97487b2, 0xac5f4f2e, 0xc5ccf746, 0x682f15cc, + 0x306d6ed0, 0x81f48442, 0x9c2e56a1, 0x386121fa, 0xa9467b1d, 0x296f56b5, 0xe5b1afef, 0x3011d2db, 0x94e8c41a, + 0x28930f81, 0x0bc05fbe, 0x1026bb0c, 0x2e769623, 0x7151702f, 0x45be817a, 0x4f06c3b2, 0x8d37cd4c, 0xede3ed33, + 0x863d1185, 0x2164a90d, 0x67c57c63, 0x7e3781de, 0x0813265f, 0x187ffce0, 0x2327e341, 0x293f6f84, 0x9ecb400e, + 0xf8d03a2d, 0xaadd37e4, 0x26a4fb3d, 0x9a962539, 0xa3e3ab60, 0x1a7dff64, 0xf24aa979, 0xc8515c38, 0x168552cc, + 0xc5965375, 0xa96ea7c1, 0x8446aab8, 0x7b6638c1, 0xc850608c, 0x658141d2, 0x8c2d3a5d, 0x0de90d3f, 0x53e1bac0, + 0x395e01a5, 0xc9a10579, 0x8afe4a27, 0xc901b8e4, 0x741b1baf, 0xc5099ef9, 0x7650c6ad, 0xe58e45fb, 0x6b9533ca, + 0x22a7233e, 0x50f95082, 0x2ed89f9e, 0xb8c0c710, 0x7d0666ff, 0x67b62499, 0x66798980, 0x5303eea1, 0xaae37702, + 0xffb851a6, 0xb6cd44a3, 0x41495489, 0x6181140e, 0xaf2128b7, 0xd6acb789, 0x9619e2f0, 0xbe432ffc, 0x8b1ff424, + 0x19f3a1bc, 0x26314efb, 0x62001fbc, 0x380abce4, 0xe5a833ac, 0x55bab0b7, 0xa0ebad6e, 0x620c73d8, 0x9b13a0b1, + 0x2b397729, 0x71d90fcb, 0xc14583df, 0x472cd981, 0x43901072, 0xa68da8b6, 0x43afa734, 0xaa3b73d2, 0x3093982c, + 0x8a5a3c6b, 0xa9a0ae02, 0x55cc3e9d, 0xe1d37afe, 0xd445ea90, 0x49c5cbfb, 0x2ea85684, 0x9d4057bc, 0x67b559e7, + 0x4627e9bf, 0x88f4860f, 0x8fba4cda, 0x3c72c0a7, 0xb2376f6a, 0xa2a68e6f, 0x5ab3ef40, 0x2c8a1b82, 0x81d2a747, + 0xdd590d94, 0x44f06e43, 0xbda8b1cc, 0x6dd9b79a, 0x90b2070e, 0x45861c29, 0x2dd9ce28, 0x53b850ae, 0x50e6550b, + 0x00d8407f, 0xcc334680, 0x1398f9ad, 0xb522167a, 0x33f62859, 0x17136d4b, 0xf5c98191, 0xfb5a89e4, 0x718daa2c, + 0x369d8397, 0x294cf96c, 0x0f57dad4, 0x77f52e73, 0x8159263c, 0x76166551, 0x23dc0bad, 0x1bb0b8a8, 0x694c1480, + 0xd087c381, 0xb5add27b, 0x6450e585, 0xcf9a7263, 0x1467df11, 0x65dc3e43, 0x25bd719f, 0xc2817460, 0xc95fcb96, + 0x17baa72d, 0xbc3ce23e, 0x54b87a7a, 0x32b6efa2, 0xac763f6f, 0xdedab773, 0x99c198bb, 0xfd1a8ddc, 0xd48d0d03, + 0x3c2ca0b2, 0xc15cf1e8, 0xde9c37eb, 0x73be643d, 0xfaef6741, 0xab34d73f, 0x3bf4a83d, 0x3b6d381b, 0x9552043e, + 0x1197676b, 0xe71a860d, 0xec606212, 0x64929983, 0xbd95a988, 0x67b7507e, 0x940e5fbd, 0x5ce87b56, 0x7b2e2d4c, + 0xb91555bf, 0xc1ed8967, 0xe3902307, 0x4f65cbdc, 0x2abe8989, 0x3039095f, 0x0808b81f, 0x8875af52, 0xb71df172, + 0xce75d9f5, 0x5a84153a, 0x48b91a73, 0x228c86ee, 0x17575f44, 0xc57efe21, 0x1329d5b9, 0x4223f969, 0x7133385a, + 0xf13d9a1e, 0xa4d2d3e3, 0x546b8464, 0xc0b9dac7, 0xa236ac40, 0x4c4b6858, 0x99435c57, 0x84c042d6, 0xa48129b2, + 0x87432ffa, 0xa83e1a6d, 0xe9302186, 0x13345d8a, 0x76f1d5de, 0xcd98bfef, 0xcdf6d402, 0xd0ad9dde, 0xa949cb93, + 0xa068c6f4, 0x31b07c13, 0x91ec13c3, 0x0f26cd92, 0x2e2da67e, 0x11ce0857, 0xef731a8e, 0x3d878262, 0x801251c9, + 0xd02b7b09, 0xa1095ec3, 0xa8993ea8, 0x36a7553e, 0x712fa520, 0x28a2dc56, 0xc5f10736, 0x0b8bdac3, 0xb170f7c6, + 0xf46fb744, 0xd47c58cb, 0x3ea97536, 0xa2ec61a0, 0x7cd7d642, 0xec858880, 0xf21b213f, 0x9656ac29, 0xd2094552, + 0xf5fb9a99, 0xdb428972, 0x96027fb8, 0x8807bdc3, 0x2e3c3b04, 0xd5d8a7ca, 0x066bd0c5, 0x3722d501, 0xa8f16173, + 0x9badd248, 0x4e191903, 0xa241ea2e, 0xc1d83df3, 0xd5393c33, 0xafd455c4, 0x215b4795, 0x14985f3d, 0x7b8b8a3c, + 0xa79c9c7a, 0x92cde4c1, 0x4bf97f77, 0xf879fa4e, 0xe9277254, 0x5fafcc23, 0x10d87cb1, 0x2c2ee925, 0xd0b8c3ad, + 0x306ef89a, 0x001d2754, 0x7d359945, 0xcf17cd73, 0x51e6b1f1, 0xd16c4969, 0x5574bc53, 0x4f3681c9, 0xe79ba16f, + 0x2b49f647, 0x8ae4d001, 0xe96a0382, 0xc830c318, 0x58f09387, 0x3fb6e2cc, 0xd776f1a3, 0x8dfb9930, 0x077b1629, + 0xd5c17e55, 0x42050fbd, 0xe8170c21, 0x2ab559fb, 0xa8d876f7, 0xd714c413, 0x8c477983, 0xe97f8170, 0xd3ff59bf, + 0x03beac8a, 0x9f7ca02f, 0x5422cebd, 0x30ad5784, 0x967d852b, 0xdfc42130, 0xade6fefd, 0x360a5478, 0x5a79f667, + 0xe130c0cd, 0xe53d24be, 0x73f10a86, 0x956bf7eb, 0xb5ed512d, 0x3dd019ed, 0x36ba62e1, 0x33657fb9, 0x69d023ad, + 0x88c716c7, 0x341b1554, 0x91b87112, 0x79b9f7d0, 0xcdb162e3, 0x2574f26b, 0xd7fe5105, 0x06b56312, 0xfe3da00b, + 0xa4fd1c92, 0xdeaf4a8d, 0x871b2b71, 0x106f904e, 0x3a914a52, 0x7ef405ce, 0xb93ad378, 0x8e78a049, 0xc6fc0b6b, + 0x23f29f40, 0x18cc36df, 0x8398d616, 0xabf6d696, 0xcb96912d, 0x92ff4137, 0xc9d6a31e, 0x46faa89e, 0x68c16c8d, + 0x0f0d0081, 0x39a59961, 0x52a23675, 0xc602b842, 0x4ae50429, 0xe8d48110, 0xe10ea387, 0x45c26927, 0x872a70cd, + 0xe51ee322, 0x5871b1e5, 0x4f5131fe, 0x81ee1b28, 0xbfe6a253, 0xfd83b7c9, 0xee7d7c46, 0xbf60f3d4, 0xe82b014a, + 0xb38f5177, 0xc792d082, 0xfeee31fa, 0x039d6753, 0x28d47d08, 0x2672d7d8, 0x1ccc3781, 0x8c069033, 0x7dd60a65, + 0xa767aa1e, 0xfccff59b, 0x4e08541b, 0x668f9a22, 0xeca2ff9e, 0x6cc740ff, 0x0229fd99, 0xc3ca9fd7, 0x3a305c08, + 0xe023b62b, 0x777b6294, 0x824323db, 0x0c0b67ed, 0x27feb162, 0x51892c36, 0x2a912b01, 0x8e1680b9, 0xc72c4d11, + 0x52cb5cab, 0x01e217b0, 0x7d9fd10d, 0x9a5b7d35, 0x96e51261, 0x9a77c606, 0x317533e2, 0x41ed0649, 0x5ef46cfc, + 0xaf608913, 0x5b2efe09, 0x922f6968, 0xb6863867, 0x823ee505, 0xe9b8f61c, 0xbe7c6676, 0x4c735c08, 0x92459670, + 0xa57c803c, 0x4e46f1cb, 0xf38b4279, 0x55296727, 0x8bee4040, 0x99db8567, 0x781de14e, 0xf4ea83f9, 0xeb004f98, + 0x257375da, 0x483fe409, 0x1c98a71d, 0xd853c688, 0xd571ad24, 0x963a03f2, 0xb1b80306, 0xeadc764a, 0x1b638f47, + 0xe4cd5092, 0x472b0949, 0x94ffe467, 0xd6eff45c, 0xe5906508, 0x7bc1f14a, 0x7b66daf7, 0xaa167dd7, 0x724c2cd5, + 0xb8878420, 0x624d5bf6, 0x6f2363c3, 0x1820929f, 0x5e2b8a53, 0x34cc2c6c, 0x23fd6e04, 0x032b0d05, 0x42063cca, + 0x7cb9df9a, 0xdd74c500, 0x91646772, 0xc9c15acf, 0xc14fbcd9, 0xc6034bef, 0xa6a9dc19, 0xbfd1bb71, 0x6f69b7f8, + 0x172332cc, 0x1034e334, 0x3ef78a8c, 0x3ee4a424, 0xdfd7f872, 0xddfd7d6c, 0xfdd2da5e, 0x83587f64, 0xc7372dfc, + 0x8ddaf748, 0x0413fc89, 0xa7b65a98, 0x75e151bf, 0x0ae5516a, 0xd8434020, 0x4c9dc581, 0xf464bf17, 0x1c9dd445, + 0xa33fcbbd, 0xba2e9096, 0xaa4b5863, 0xb773292e, 0x957c12f7, 0x82595d2d, 0x69eb7177, 0x47cd505c, 0x009e3220, + 0xc860a5d1, 0xce5d67a6, 0x12de20a6, 0xbf81e7b4, 0x54c0ac5d, 0xc25fd6f6, 0x2f5236df, 0xb61dea7e, 0xecb9080a, + 0x2b03c2d2, 0x0b676559, 0x4a6c6caa, 0x8504a71b, 0xc805a0e2, 0x8d1f4c21, 0x010f8083, 0xae67964f, 0x9a58d6cd, + 0x3c9eea55, 0x75aa556b, 0xd7dd90a1, 0x6584aba9, 0xb2041100, 0x8ff314e2, 0xc3e2a273, 0x9fcf7851, 0x408c22b6, + 0x407f5d1f, 0xd9e49276, 0xde8809d4, 0x5ad4c993, 0x90a10e1d, 0xe1696310, 0xb63002c9, 0x8bf3e907, 0xfa6b2e9f, + 0xe866461e, 0x7a14d5c0, 0x57929eac, 0x476f8d6d, 0x852d8696, 0xe6990e0a, 0xbb3ff549, 0x6d527a89, 0xe451ad04, + 0x5b765d21, 0x51b1ccf7, 0x93ed07d4, 0x48b5a49e, 0x725a8ef7, 0x04f87352, 0xe90fd2fa, 0x6f7a758b, 0xcee3a94a, + 0x2cd5e8a2, 0xa6403951, 0xdd171472, 0xca1dc4fc, 0xb0768cd3, 0xbde2f65e, 0x50bdeb1d, 0x2adf28cc, 0x7ece4170, + 0x8f8062a2, 0x9a50cecf, 0xfb35d47f, 0x19951eb3, 0xe20de49a, 0x0d910c2a, 0xbf80ee16, 0xb27084aa, 0x4e0796fd, + 0x905d0916, 0xfbcdcd10, 0xbf3061e2, 0x71ea85b0, 0x16e2080f, 0xb92f4a52, 0x69dacec3, 0x95badf00, 0xd8afc4ba, + 0xc1d57766, 0xb4aedeed, 0x6e49b967, 0x51fd5664, 0xc6b54f26, 0xbbe26c7d, 0x9f823413, 0xc92d459a, 0xcc4c320d, + 0x03d19d22, 0x5c25b44e, 0xa852ab33, 0xd5019c1a, 0xf622f717, 0xf081329b, 0xd35b29b5, 0xd48d56a6, 0x4fdced2f, + 0xb0d2b7f5, 0xfac0940f, 0x530e007d, 0x8be65e0c, 0x56254e62, 0x2b57eee2, 0x46c5f14b, 0xa3ab71dd, 0x3647b3a1, + 0xf52b10fb, 0xa966370e, 0xa66d3df4, 0x1871aee3, 0x39ee0efa, 0xa3d8a258, 0x9833f5fa, 0xcc5bc07a, 0x932679c4, + 0x7d77166a, 0x7f5e4013, 0xe78477a5, 0x3f1e4905, 0x81c91acc, 0x414bcf82, 0x62d3db83, 0xf26c36da, 0x4495a316, + 0x742153f7, 0x4a6f9723, 0xd9dd373e, 0x127927e5, 0x95cb22ad, 0x8b667334, 0xbab2c911, 0xa088bfa4, 0x7d43529b, + 0x9aa85b34, 0x7ef8cd7d, 0xe74d147b, 0x2faeec43, 0xd62acede, 0x9e8328e5, 0x7cf7439a, 0x881c5edd, 0x533f7aac, + 0x84e4a099, 0x11a3696d, 0xf8b3d704, 0x190d3f0e, 0x88ea4bae, 0xa5db6cab, 0xd99d39d2, 0x71ed8fa7, 0xd36fb2cb, + 0x7fa51d4a, 0xe24b7206, 0x82fffd5d, 0x61f1b0bf, 0x751f419f, 0x90eb836e, 0x3a403019, 0x6b509237, 0xcce97175, + 0x97fdc2d7, 0x19170d93, 0x45d54a44, 0xe920924d, 0xd67d42d8, 0x7b314ea2, 0x675ba341, 0x647ab31e, 0x01d7bce8, + 0x2f730b53, 0x114751c2, 0xa0ced504, 0x1f8724df, 0x138ee34b, 0x546d2a3f, 0x50ad2a09, 0x1f4cc742, 0xe9c6c9db, + 0x6173d08b, 0xe6ffeaed, 0xaf32c2a9, 0xf0c90475, 0xfb0f8d74, 0x13d28690, 0x4c695a9f, 0xa70b2540, 0x92f6262c, + 0x2b47cf88, 0xb474c18a, 0x8ba66903, 0xeb64500c, 0x413dbe70, 0xfac39d59, 0xe2bec479, 0x7ab7629c, 0x5b1810f4, + 0x499d8c58, 0x1cf28db7, 0xd14b5fa0, 0x0d1e258f, 0xd8be5043, 0x8480695d, 0xa20ecd13, 0xd52bb9a8, 0x4eca2c4a, + 0x80a59756, 0xda32bf53, 0x4162182b, 0x6799ed8e, 0xbb5ee020, 0x15cfea68, 0xc3f2206f, 0xa4dbe184, 0xf0a817d1, + 0xd35e0287, 0xf575c5b5, 0x84338dc1, 0xf8e524c1, 0x38aa7cce, 0x380d9c38, 0xee927a39, 0xe2a49911, 0xb5607f03, + 0x16eb8fd1, 0xad1b739f, 0x6d9b5e77, 0x9bb1e5a9, 0x29fab415, 0xf6e17c5f, 0xa339d1ba, 0x43a493ef, 0x6e8b9b9a, + 0x09b643d6, 0x5231a755, 0x88d4ff2c, 0x9b1f54d3, 0x24766455, 0xa2931ba5, 0xe0b771d7, 0x6feff0cc, 0xc7ba4c4e, + 0x8b872d22, 0xd7dae5d4, 0x412aec1f, 0x4452b762, 0xa26d5e0a, 0x3e63b071, 0xfad1e326, 0xaa1e2e82, 0x6ea064fb, + 0x4dcda551, 0x511002bf, 0xb6a011e5, 0x74597dc2, 0xb671b7e2, 0x9855a7c4, 0x13cff572, 0x39c13dc6, 0x96300107, + 0x9b013410, 0xa09c6fb6, 0x60c60a13, 0x3d172ef1, 0x94b2dda0, 0x188f97cc, 0xcca037f7, 0x763846bc, 0xbfd1b589, + 0xcc172bdf, 0x33c86108, 0x6cf1106f, 0x8752d785, 0xfd7a7d25, 0x55fec444, 0x3de32255, 0x2032d4a2, 0x89b1316a, + 0x464d6944, 0x06dd56ad, 0x2049534c, 0x4c621f60, 0x5c340856, 0xeb5469cf, 0x1b7e29a7, 0x7783241e, 0xe99c4061, + 0x38f29bbc, 0x5c03ed75, 0x59498028, 0xdf8b6540, 0x127fa4b7, 0x1b92f45d, 0x8c49116a, 0x6947c8c7, 0xc04e0709, + 0x93769174, 0x9487581b, 0x85fce2ff, 0x29531b05, 0x7185ef0f, 0x24b24b05, 0xe8c0fb83, 0xeb5e3c28, 0xa83f5e7b, + 0x178d8010, 0x2d66e4cc, 0xd7acf8d1, 0xd307af4b, 0x0cba7962, 0xc5e91301, 0x93eb2598, 0xdcbbab6d, 0x2a4a10e9, + 0x71f9ac1e, 0x0a5e7e32, 0x31e18068, 0x5df3e53b, 0x94b08d45, 0x03602187, 0xb3ea4656, 0x599565cb, 0x85b6f96a, + 0x6dfffb26, 0xf6466755, 0x243291ca, 0xd516f3bd, 0x6e3ee895, 0xc0e434c9, 0x74a0d934, 0x8d01eaac, 0x43bbe130, + 0x91dfa49d, 0x76cc4ac8, 0x9ff87c56, 0xf1684867, 0xba24d4ec, 0xb258eb69, 0x0e54bbbf, 0xb6792493, 0xbd3816d2, + 0x79500895, 0x1dad0e83, 0xac6360aa, 0xf8a37708, 0x48e86861, 0x6d9aea3e, 0xa60d71d5, 0x34032c6f, 0xcde04cf3, + 0xb5ce8a08, 0x14650177, 0xa9b57a0c, 0x155f4747, 0x85097ecb, 0x6641e5b0, 0x410d86ef, 0x5febbe21, 0x99ecfd23, + 0x278a2b4b, 0xcbbc6351, 0xca93a9dc, 0xac55e127, 0x7f7e8280, 0xd46eb9af, 0x19bd6c3c, 0x431d0efc, 0x2b574fa4, + 0x9a2dfa9a, 0xebb22303, 0x6616b579, 0x9987339d, 0x954e6740, 0xcdcb0346, 0x6b7c79c5, 0x0fc97093, 0x380b7467, + 0xee085250, 0x09db4eba, 0x98d82b8e, 0xb623868a, 0x1954a8fa, 0x10f7a7b0, 0x6bc4c69c, 0xa28e5d58, 0x14696ed9, + 0x624d49db, 0x9c45ea86, 0xf8e1315a, 0x14edba46, 0xffcccec2, 0xb65a8432, 0x7af0f14e, 0x645d2533, 0xd4dc6bee, + 0x78db70d1, 0xd1151672, 0xfcda3a32, 0xe9e6d241, 0x141686ea, 0xf739a726, 0x195c75d2, 0x4068bf33, 0x8aee99e3, + 0xe65d89cf, 0x0f1e9c9a, 0xa27b2574, 0x87bdd0d6, 0x1bc0e885, 0x9198b9c7, 0x096d650d, 0xff6f468d, 0xbfb51012, + 0x31542295, 0x420bbd53, 0xfb632476, 0x72475538, 0xa5b4aa54, 0xb89f2d6f, 0x8e5ac9ae, 0x491fd8a4, 0x2c62ce56, + 0x97000614, 0x0cdca343, 0x6a6521d9, 0x6e7b09a2, 0xdca1005f, 0x29c69b31, 0x89843c61, 0x7ad305cc, 0x9d5308eb, + 0x52be1498, 0xc8c63916, 0xbc050b3a, 0x20f3f93b, 0xdd19a63b, 0x064d5b4b, 0x2ff2ce39, 0x18178f5d, 0x4f40e732, + 0x05fe859d, 0xeb03b375, 0xe55df0f1, 0xe608fe21, 0xb02005f8, 0x3c1f7716, 0xa067bcb4, 0xb3b38931, 0x7f443fb6, + 0x60ae07bf, 0xf3a92721, 0x464e8e14, 0xf618c250, 0x1f31e87b, 0xab1bebe6, 0xf28d08c5, 0xb188cc58, 0xbe7c22a0, + 0x33bcb131, 0x1b7f00c7, 0xfd210229, 0xa8ae5f0f, 0x26e70e78, 0x7add84c4, 0xc313e896, 0xec523da7, 0xaf5b0995, + 0x29824892, 0x1a82902c, 0x413bba43, 0xe89a053e, 0xf8d6d32c, 0xd772d5ed, 0xa439d889, 0x739f5ad4, 0xe27476f7, + 0xf3647567, 0x445d35b0, 0xcff7d503, 0x296ab5ab, 0x33ced0cb, 0xbd3343c2, 0x49729a67, 0xff67db3f, 0xe5aa85d1, + 0xeb4e4ae6, 0x47aff482, 0x12bc4593, 0xa7389b0c, 0x2d19c02d, 0x25dc3bb5, 0x171ca46f, 0xbd73c988, 0x4053711a, + 0x9fbcb6e2, 0xcff34bfb, 0xbc181e98, 0xc58ce2a6, 0xc60b05cb, 0xc8e750d0, 0x73412245, 0x9eb38338, 0xdcdaac5e, + 0x529cd9b0, 0x0dbab37f, 0xa213d2bc, 0x4a7365b3, 0x1e88a561, 0x5db07acc, 0x7bc0ba3a, 0x75a2d30b, 0x1b18e879, + 0xb897b3ed, 0xc8dbfe4d, 0x83f3e4da, 0x7db34ad1, 0x46bbb7f5, 0xe3cf045b, 0xce0be3aa, 0x312c2a21, 0x6c9f8438, + 0xc49c712d, 0xfb982760, 0x5abd36db, 0x894dd944, 0x5662e0f8, 0x6437ea6b, 0x4e594cc0, 0x0e34dcc3, 0x04d46e3c, + 0x96427863, 0x6f07969c, 0xff88baa9, 0x5cad9322, 0x3fae5a55, 0x08d4dd3e, 0x60fc6250, 0x1b26ccd5, 0x8cc10616, + 0x85489ef1, 0xaa217094, 0xecee9b15, 0x6a6e11fc, 0xb2008872, 0xa09ca141, 0xc34dff39, 0x42ee897a, 0x1dd4c5be, + 0xb0496569, 0x34c0cccd, 0x6a805854, 0xe51cfa02, 0xbb56ef8f, 0xc01399b0, 0xa9d08c32, 0x8327ee3e, 0x82d4777e, + 0x0588e37b, 0x4c33c0fe, 0xb46a2fe8, 0x8a7396ce, 0xed301106, 0x32877078, 0xde801906, 0xcfbdea17, 0xdb4461be, + 0x860d8970, 0xfd7b68ca, 0xa01d1608, 0x84833b82, 0x29cb825f, 0x3adc27c9, 0x84a55de5, 0x9d285261, 0x5398cc0e, + 0x47f1b440, 0xbb289ccb, 0xc413163c, 0xdbedf482, 0x470e5c1f, 0x5c4213c5, 0x70b92c53, 0xb68382e9, 0x5754a6c3, + 0x7237c411, 0x41ea4a89, 0xae97f9e8, 0x6ac3144a, 0x7c10c2d0, 0xbdaff7f6, 0x8309b9a2, 0x65e135e9, 0x9dafbec5, + 0x4e51b902, 0x21ef054b, 0xa8abb5be, 0xe7646c12, 0x3f35c6dc, 0xd8d541b3, 0xb4c5e288, 0xd5ff3317, 0x40fe26ec, + 0x13589a29, 0x93845540, 0x79981898, 0x09cf0948, 0xb48b3341, 0xa7330447, 0x2aa015f6, 0x37102a7b, 0x811a80da, + 0xa9ee16f1, 0x2fd4f105, 0x4eed3a04, 0x85459293, 0x865da8ab, 0x6a54a965, 0xeaa13d45, 0x5ca57a7f, 0x9adb9847, + 0x59026625, 0x2ae224e9, 0x2a7d09f4, 0xe036ef05, 0xe2a139d3, 0xd1c38b33, 0xf47b4f4e, 0x8208f0fd, 0x92831957, + 0x5ffcbe15, 0xbd48b225, 0x2be00276, 0xdf028737, 0x37f77fd9, 0xd61c46c9, 0xb94a38a1, 0xdf96a05b, 0x65f9eefa, + 0xf707db2e, 0x26357213, 0xc4242010, 0xbaa340f5, 0x929513ae, 0xc87e156c, 0xd467cb8f, 0x298c3b5d, 0x411eba83, + 0x62d14390, 0x316c4990, 0x423ff991, 0x4a1c2f5e, 0xccfcf06f, 0x2a88184a, 0xd26203df, 0x3542b6ce, 0x03d53e95, + 0x7e6fd93f, 0x783e668e, 0x6204a0b9, 0x0c729a46, 0x6cac49a1, 0x9f6214d2, 0x39ee97fb, 0x5a3e9645, 0x39f986e4, + 0xad4641a7, 0xeace4c4e, 0x9545698a, 0xf547e019, 0xaf56b52f, 0x0e0c0a9a, 0x0c5999d1, 0x4d01e2af, 0xed0bc7a9, + 0x7e19a955, 0x504885b6, 0x1b6e2a4c, 0x1590f992, 0x3c21dc1f, 0xb76c5175, 0x0a3153e3, 0x673f64b5, 0x36b4c3b3, + 0x077860df, 0x10db1bcc, 0x2cf2b503, 0x1a71628b, 0x0e0b31ac, 0xb3e21eaf, 0x2bd1a3ee, 0x6482787b, 0x325b2220, + 0x23b84cae, 0x839bd0aa, 0x4e82fcbc, 0x7f51c2ef, 0x8553c345, 0xd236c059, 0xe1eb73a3, 0x7bdb20cf, 0xb0fe44eb, + 0xef4236c2, 0x78f4bdf9, 0xa1a0dd20, 0xe9fc90cd, 0x65c9b6ee, 0x7ec64c89, 0x7047f563, 0xcd1aee92, 0x58bc596b, + 0x2a834bac, 0x8124fd43, 0xeb1a55fe, 0x4544868b, 0xca8cf3b8, 0x51e1bee4, 0x9bd5225d, 0xdd206504, 0x0653c9b3, + 0xe16e5f0d, 0xebfe80cc, 0x4bee25ce, 0x055fc64e, 0xb16c882e, 0xb2b0f038, 0x670729a5, 0xb5f3db03, 0xe29b373f, + 0x11616d2f, 0x144a6b6f, 0x54dcff78, 0xf4eaa0b1, 0x7944ee08, 0x8b36ded4, 0x59531fb8, 0x5cf4c0a3, 0x018dbcf1, + 0x94f8e5e7, 0x16e2d04e, 0xfeae3664, 0x09887bd4, 0x0ffb8b2d, 0xa4508014, 0x56660578, 0xa2099934, 0xe5fcf2e6, + 0x81213e0b, 0x99250c8c, 0xc988e2c4, 0xb13c6d9a, 0x18d05bfd, 0x5ce79760, 0x4552a671, 0xd7a507b1, 0x8611c55e, + 0x5b3f9b8c, 0x9208b673, 0x3deb0c4a, 0xef4b3bdc, 0xcba1cd47, 0x9cf31970, 0xbc62e514, 0xb9192a04, 0x112d360c, + 0x01cacf5b, 0xbc707076, 0x681a474b, 0xc26dd714, 0xe0d6196f, 0x39e1eb30, 0xb91679d3, 0x1ba48f5d, 0x0287889a, + 0xa9f3b598, 0x054ea6ab, 0x9e7d236f, 0xadbbd83e, 0x15b8b9b1, 0x06e9e69d, 0x58a0fd76, 0x3dcf8aae, 0x97afd43d, + 0x4aea7967, 0x6f1eda39, 0xf33105b6, 0xeec46535, 0xdd4e1211, 0x44dc947d, 0xc3c6d94e, 0x938fe832, 0x634ac1a2, + 0xe3f506ba, 0x45cf6682, 0x612cba91, 0x659e1366, 0x5bdb6c0b, 0x0e3e914e, 0xa1a1bb7f, 0x264e263f, 0xd2773418, + 0x84e469e5, 0x5adc8d2b, 0x604792af, 0x29fdbc39, 0x9f444521, 0x46f00939, 0x4a4a81ae, 0x0d620e3d, 0x0b34e95b, + 0xb1f2f7c5, 0x5d326e50, 0xf6cae2ee, 0x06b8dde6, 0x4c9f79ea, 0xa7636c2e, 0xa2accb85, 0x4ed87795, 0x29113a46, + 0x6078b6d5, 0xa8815f75, 0xdc3479a4, 0xffce9081, 0x17efa48d, 0xf60f5ca5, 0x054ef08e, 0x56311e59, 0xda53f17b, + 0xe80e9c01, 0x983904d0, 0x61e99fad, 0x2de20813, 0x662f4490, 0x159aac02, 0x841b392f, 0xc06f0401, 0x28a89749, + 0x24dfe406, 0x3caba947, 0x50acc40e, 0xd97f6914, 0xf0a9f2d0, 0x268170a1, 0x1818ad2e, 0xaf0a9d54, 0xca312b17, + 0xdeef2742, 0xdc2e75e2, 0xd76a227d, 0xf1d4e462, 0xd2d05350, 0x8f719fc3, 0x68146157, 0xb5cdc047, 0x11a37633, + 0x02e5b229, 0x0db680f4, 0xb206d770, 0x178250a7, 0x185f031f, 0x36f20b09, 0x53a2068a, 0x6da11aad, 0xb7cc55c4, + 0x558ab617, 0xc1afb636, 0x78faf04b, 0xb4b066e0, 0xb3378ffe, 0x4f3761d6, 0x83a2f0b7, 0xff46023c, 0x92e62ca1, + 0x7953606c, 0x47c99610, 0x2a0505d7, 0x48bdb6d1, 0x2afbb5c4, 0xab29e32b, 0x76ef81d6, 0xa30123ec, 0xbbf8687c, + 0x417640a3, 0x6106e349, 0x1374e29f, 0x0c8a5848, 0x4ac55122, 0x4ee3656b, 0x2574281f, 0x2f9bcbfc, 0xf5be55cb, + 0x7789328a, 0xac4fde57, 0xacc2af2e, 0xe40af009, 0x44e88ea8, 0xc2a3e176, 0xa0fba86c, 0x4f18c9d6, 0x66eb407e, + 0xe9a5879f, 0xd2f00670, 0x63f95c03, 0x3b32b852, 0x78e88da0, 0x59000f2a, 0xad003e5e, 0x7a9db31a, 0x093869b4, + 0x4b08b049, 0xdecc11aa, 0x1ccc6322, 0x35da8cad, 0x26203506, 0x89899775, 0x8a4fb73f, 0x44d10963, 0xba95dad7, + 0xfe6092aa, 0xf7a47c80, 0xe3bc9a97, 0x292e52b0, 0x8a49ca7b, 0x08262af3, 0xe1dca5dd, 0x48435cdf, 0x9162d928, + 0x7dba08af, 0xc3e1c0d7, 0x0e5e2691, 0x246f0968, 0x8548bb58, 0x43d2ed5b, 0x89ce3492, 0x93601bbf, 0xff1d756c, + 0xcc76da81, 0xa493c6ba, 0x53a493b2, 0x466da15d, 0xec7b0145, 0x764a6308, 0x0cb94c1c, 0xf4c36100, 0xefaa1b73, + 0x4a729c22, 0x6bd632ec, 0x5e9b3ff6, 0xf4297cc8, 0x60f0245a, 0x91010d1c, 0xaa711938, 0x2a88cd1f, 0x0df23c50, + 0xe1d8d0b5, 0x7cb66265, 0x9cf6b879, 0x3a012ea9, 0xc3a90a08, 0xd0e2eef5, 0x9e3ac38d, 0x3a79f5c7, 0x81a00e37, + 0xebb066fb, 0x4d80b810, 0x6cb6ce5d, 0xe18c4646, 0x44245eb0, 0x5d095bf2, 0x6b1970c8, 0xa3fe825d, 0x8af91e7a, + 0x437144a0, 0xa1212b68, 0x9d4e3083, 0x60a52653, 0xf473ad3c, 0xec6afbfc, 0x167af733, 0x10537841, 0xd97f9c2b, + 0x150294e0, 0x8db3fb3a, 0x3ac64954, 0x924302f2, 0xbe63db44, 0x4dc5b63a, 0x9d2b48e9, 0x9e8d8887, 0xb110eb41, + 0x09a34188, 0x40d06913, 0x6829d646, 0x3afbb9a1, 0xbcc974e0, 0x5991f0c5, 0x223cac2a, 0xc61cab0d, 0xae14de9b, + 0x6f1b4fa1, 0x42048792, 0x4f7bf465, 0x794e0218, 0x44306d72, 0x1babc0e2, 0xd58e676c, 0xf884a69c, 0xe0395d28, + 0x4116d5ea, 0xd40f49c8, 0x26450263, 0x75dd99c6, 0x86861cc5, 0x262ca01a, 0x8898e30f, 0x75afa9f0, 0x082a1c6b, + 0xd92e2885, 0x23b6d7ba, 0x5c902cbe, 0x62a250c3, 0x1ccbfcd7, 0x59b35269, 0x8f3205fd, 0x08aa6242, 0x2924b87e, + 0x0a07ea30, 0xf62957dd, 0x237467a3, 0x38731377, 0xaa9e2f76, 0x99d5292b, 0x1b1fcbb1, 0x4570b974, 0xece5cf10, + 0xc40ac4a5, 0xefee6ed0, 0x89f16173, 0x545d2180, 0x52b31c59, 0x5bab4289, 0x83233adc, 0x56a3cf8e, 0x5516fb7d, + 0x583b3517, 0xd988f759, 0x167686ee, 0x9a073867, 0xc6857dff, 0xb905d194, 0x1a2777bb, 0x62a6f7f6, 0x6524ffb2, + 0xbfca027b, 0xfaf45d22, 0xe6a9d323, 0x990ebaf3, 0x948c0d18, 0x0e9b6ed1, 0x5525b865, 0x0550b054, 0x0a73c672, + 0xbc61cfe2, 0xd33dba52, 0xbfa1be78, 0xe486dd77, 0x2f0e6679, 0xee5fd562, 0xa5d33295, 0x68d6f5b3, 0xd84c211e, + 0xfa610872, 0x9e7c34d3, 0xac48b1a9, 0xbc81fc61, 0xe3395058, 0xa518a88f, 0xd9bd45cb, 0x399d118c, 0x6eff16f0, + 0x8792e5fa, 0x869c6b83, 0x1ec03a2a, 0x2bdd16f5, 0x8ebf5930, 0x9f21a997, 0x723e84e8, 0xdedb54b9, 0xb3c48178, + 0x0948f97b, 0x01fa96f6, 0xb38a5a72, 0x9d735c98, 0xe4056c98, 0x195da29d, 0xfa860838, 0x671fcafd, 0xc759cf7e, + 0xf112d0f9, 0x2e2a4301, 0xa1417a0a, 0xcdab8979, 0x7865f2e0, 0xe2bff117, 0x0ccb19b3, 0x1e45b20e, 0xfdb57a7d, + 0x9a2d0bef, 0x2b02661d, 0x7c6e0e92, 0xed5dea23, 0xf7cf17e0, 0x9e1feafb, 0xa1422ef4, 0xce6e60fa, 0x7728c023, + 0xb4cb5644, 0x3070e1f8, 0x50ca11f4, 0x7b12ab30, 0xda17e43c, 0x49059118, 0xdcf9e9a8, 0xe6b8eb7d, 0x363b8bfb, + 0x7ad2e8c4, 0xb7009573, 0x52ee214d, 0x9fe3004e, 0xbd0ae598, 0x32ce7105, 0x5d015314, 0xfb52ee5e, 0x278ca10c, + 0x31d0f055, 0x7303b8e6, 0xa03bca9b, 0x87c298ff, 0xc5bb90a6, 0x84ce4951, 0xebd1c878, 0xc1b01d47, 0x371a4e42, + 0x348b3cd2, 0x51ee6da1, 0xad5632f9, 0xa55485a6, 0x5fc8e0ed, 0x65b4b569, 0x44f1c519, 0x938b7a84, 0x13f8de47, + 0x356445a1, 0xa090a7aa, 0x7eac3a1f, 0x86985c94, 0x63a0e3b1, 0xc3c534c8, 0xaecdee4f, 0x3a6fa9b1, 0x04edc53f, + 0x318fd1af, 0x1b3414f3, 0xdc8cbf73, 0x7df7adde, 0x462cdb5d, 0x06d29ed1, 0x03bd4143, 0xd16e195d, 0x625962db, + 0x9a9eb6b7, 0xbd3be3ad, 0xd4850359, 0xe073d736, 0x3b3f6232, 0x890cd18b, 0x510ee11b, 0xd0fb2963, 0x296bab7f, + 0xdc9d3af7, 0xf27fa407, 0xb9706d52, 0xe351da16, 0xd7c7ad01, 0x6abfda70, 0xc32d64c2, 0xfd38462d, 0x0bfa46c6, + 0x95229192, 0x8028df4d, 0x2e249fce, 0xb75122b1, 0x635c0e38, 0xee350d8b, 0xce5247ec, 0x7fe13d45, 0x9f3ff957, + 0xdeb8987e, 0x2c071e93, 0x196d17fc, 0x16ddda48, 0xe47e0402, 0xb4c2bf04, 0xb95bd678, 0x5ac02c70, 0xf71da685, + 0x3cc0a4ac, 0x9a159f0d, 0xbc019a90, 0x36033db8, 0x5e6d552b, 0xdcaa37f4, 0xa2b8d88c, 0xb642ac1c, 0xc5383145, + 0xb0826df0, 0xe5e9f27b, 0x22c542d2, 0x1b05d660, 0x3cedd305, 0x6983f74d, 0x8a8d2d7a, 0x636ad23f, 0x59661e05, + 0xfeabb055, 0x550bce00, 0xd773bf61, 0x408c5f9c, 0x9b9f28b8, 0xf8159376, 0x20639b3a, 0xbb2275af, 0xdf199ea7, + 0xd97b46f0, 0x2067bb11, 0x2928f17e, 0x8718e349, 0xbbdc290f, 0xc1140c1f, 0x077418e9, 0x61a4df26, 0x5bde182a, + 0x0d6c7e7c, 0x12a80c58, 0x05da4e75, 0xf781fb1e, 0x353c523e, 0xaec1658f, 0x1546b275, 0xf8a4a1d7, 0x24d43146, + 0x294c2386, 0x742f124d, 0x7e2c681d, 0x247a2dc9, 0x6656516b, 0x40c71a15, 0x452255d7, 0xab5aa9b8, 0x48d331b9, + 0xf1e28b85, 0x70c12587, 0x269cd5cb, 0x858774bd, 0x279a0947, 0xdbe9fbe1, 0x58007236, 0xf4fede1f, 0x2e01c5d1, + 0x19e066cc, 0x630fa8ec, 0x3055a4e3, 0x7f44ccfc, 0x17da6299, 0x0bfba10a, 0xf305aeb3, 0xdc38839f, 0x8bac6bbe, + 0x6c1e9c16, 0xefc58b54, 0x93ed783c, 0x61afbb9d, 0x6f6605e4, 0x96a5e71e, 0x1cc148ac, 0x89a2c1ce, 0x56443083, + 0x80b97e2f, 0x338fb1b7, 0x9c7327cc, 0x68daecf6, 0x747ea46f, 0x3a48826e, 0x02eb91a9, 0xbae091a8, 0x4f36c6b3, + 0xbb6f8e30, 0x38e2bfaf, 0x1f495a35, 0x106767d9, 0xfc84192f, 0x7ab3b3e9, 0x3e2a6e86, 0x7255935a, 0x180ccd03, + 0x656440aa, 0x72109045, 0x3604f600, 0x8d805a0f, 0x78a95dc3, 0x45022738, 0x7d34c3e9, 0xcf51e478, 0x1c65efc3, + 0x3885612a, 0xed54c698, 0x789549e7, 0xa354ea20, 0xa4c607af, 0x8001e920, 0xc55af694, 0x7e838c8d, 0x1411cc39, + 0x14eff59e, 0x5d720127, 0xc677c9d3, 0x832396da, 0x9157ab50, 0xeb670706, 0xcbc14ff6, 0x91aab4a2, 0xfa4d4dfd, + 0x062dd6c2, 0x1c702ae1, 0x24dfd175, 0x9b58e8f1, 0x54ecba0b, 0x424ef9b7, 0x90024f71, 0xed4bc082, 0x8c1b262c, + 0xadf8dbed, 0xa14514eb, 0x9464fafa, 0x2cc4b1ca, 0x1c997000, 0xa4d55dc1, 0x585b015f, 0xf5c94931, 0x6b30369b, + 0x29b503fa, 0x9214e5df, 0x9f47771e, 0x20f98d23, 0xcdf63260, 0x0283dfb1, 0x10fcdfc1, 0x1c1be8b4, 0xc9f1a6ce, + 0x0775c65a, 0x4284e053, 0x28cbf472, 0x3fb75ec8, 0x3431fc92, 0xd3d36ccc, 0xda718bbd, 0x58176ddf, 0xec86636e, + 0x301f2acd, 0x4da46cef, 0x3f47308a, 0xb52aa154, 0xaa427bce, 0x951ec77a, 0x2647d3e6, 0x440cbd98, 0x60aaf581, + 0x628708a1, 0x5313f6c3, 0x5590592b, 0x34229276, 0xc9bbb3c4, 0x2a58ada6, 0x35e35999, 0x78852e49, 0x1a3a57a5, + 0x2b251668, 0x6cbcaf75, 0xa46e9e97, 0xb7e51e2b, 0x91bb4978, 0x2f551ef9, 0x02afce2f, 0xc8425376, 0x9de74aea, + 0xc44ebba7, 0x1b66d3ab, 0xadb9d9ac, 0x7938a3f8, 0xb4f16f68, 0xcfe0d1b8, 0x0842feca, 0xa3c413b0, 0x35733259, + 0x37128375, 0xfb476f9b, 0x035288f4, 0x23a42920, 0x3866f9ec, 0xe630dfb4, 0xa7f7f36c, 0x608d0adb, 0xaa389b28, + 0x4958a701, 0xce88eb4d, 0xcfe60b90, 0x32f98700, 0x67761d7c, 0xdaece8b3, 0xb22d1a65, 0xb6a17c9a, 0x498f6cf7, + 0xf4164ac1, 0xd2769765, 0x16344f8a, 0xc85b15d1, 0xb3d9bf78, 0xfac20063, 0x2c1659ef, 0xadbe98b3, 0x01bd9a08, + 0x5b651e1c, 0x5d88809c, 0x290f3a68, 0x3c02c929, 0x8afad13c, 0x1bdca36c, 0xea881073, 0xe15db66e, 0x53b7a66e, + 0x90da21d3, 0xb991d9d4, 0xea28d430, 0xd3ecc069, 0x72613dd4, 0x682de43d, 0xf43ded5d, 0xb0009a71, 0xe3e779f2, + 0xa2f580ab, 0xcc30c1e5, 0x4df0acc6, 0x546f4930, 0x0267a185, 0xadc20ead, 0x1fa588b9, 0x0d1b94d5, 0xc301cab1, + 0x321ccc80, 0xf078178f, 0xee4b2393, 0xedf78c71, 0xec5fd60f, 0xf08c761e, 0x8492303e, 0xbb2158c9, 0x0d2079e0, + 0x73de44d5, 0x6c1c25ca, 0xb3edcf58, 0x1643cb33, 0xc2377333, 0xeffe649d, 0x3210f0ea, 0xfa138c5f, 0x6a5199d0, + 0x6acc3ab0, 0x8a40c818, 0x0135d065, 0x9cb4dbfa, 0x910b1b4c, 0x9cdba2e7, 0x8cbaf935, 0x9e1c0fc2, 0xa1e4faa2, + 0x250c1108, 0x57dd210c, 0x7813870a, 0xecf00997, 0x671cbfe9, 0x9a2393bf, 0x7487bde7, 0x265c21e0, 0xe4cf1582, + 0x1619daa1, 0x1c66b41c, 0x00a4d14f, 0x43761ee5, 0x5edc04b9, 0x0f3835d1, 0x3075695b, 0xc41cac43, 0x3ab5acf0, + 0x5ec74a39, 0x32ce189a, 0xb5681306, 0x2b5fbeba, 0xfc639649, 0x87d04db9, 0x45f95311, 0x7e5b3f6d, 0xdd46595a, + 0xd5f6f608, 0x24011920, 0xe739def3, 0x2de511f9, 0x1232133f, 0xf8f3230c, 0x98fa1663, 0xd06c9884, 0x2548f660, + 0x271a790f, 0xec123c36, 0xf7903c46, 0x7c9d09d5, 0xe694b812, 0xa132a6d1, 0xb305c74d, 0xb6bdddb1, 0x27703d92, + 0xdf773642, 0x9f030fb7, 0xb9e39e60, 0xea1cd007, 0x93f9632c, 0x4a9c375e, 0xcd3b0181, 0x42d9cf6a, 0x7e5b3eac, + 0xf1f34be4, 0x45bda88e, 0xe22327d0, 0xb32d5b30, 0x44cc4ea4, 0xa3119872, 0x537f97c5, 0x486722d1, 0xb56e5f42, + 0x2370b7fd, 0x2f6373ed, 0x09ab544a, 0xf7eac66d, 0x30e8d146, 0x526de21c, 0x462bd581, 0x054b8a07, 0x844ed10a, + 0x53628d05, 0x73d7b553, 0x352a0cb7, 0x3a0756c2, 0xfef3db2e, 0x38026324, 0x39e48d1f, 0x1565fc5c, 0xe2c7ee47, + 0x088723fc, 0xcd3d119e, 0x8e079f59, 0x17068649, 0xbdf47e4c, 0xafe4721f, 0x5061a822, 0x3d931d0b, 0x71a39caa, + 0x3ac29a2d, 0x4fca6cc0, 0xfb06abba, 0xd09159a4, 0x1d793986, 0x93342b89, 0xda27c569, 0x5df782f0, 0xa5c4e5c8, + 0x0638f911, 0x2f63d8f3, 0x15e530af, 0xeccbda37, 0x7112dfaa, 0x5c619e97, 0x5dcd9279, 0x3524550e, 0xe7424191, + 0x41b8ecdc, 0x5648ace8, 0x8d5395c2, 0x486b7f4b, 0x6eb1c69b, 0x296c2450, 0x9dd57326, 0xaae21dbd, 0x482fcd18, + 0x20512c87, 0x14a2bf0d, 0x6b5b4223, 0x87e2181f, 0xb504ddd7, 0xf7a8417e, 0xabc2f082, 0x7bab08be, 0x1aca9262, + 0x40fd13ef, 0x3bb09239, 0x74e8f497, 0xcf66c052, 0xe3082c9c, 0x30e9ae36, 0x9b31bed5, 0xa0bd978d, 0xeeedd7fc, + 0xa4099876, 0xc83350ab, 0xd2d4afec, 0xa9250451, 0x0d687458, 0xf5e66d3f, 0x8c74b816, 0x43366301, 0x9ab6a8eb, + 0x2e6fddff, 0xd5e420c2, 0x94ca46e0, 0x466c1377, 0xcced4dbf, 0x9642c682, 0xe8c0af77, 0xe744c956, 0xc9f924e2, + 0xa895faf1, 0x155b0339, 0xa49faa14, 0xd0d86fcb, 0xc1be7116, 0xe5ea4e9f, 0x08a4242b, 0x0079616a, 0x43d72141, + 0x2d8b233c, 0x7a9f38af, 0x72779f44, 0x712d966a, 0x1a77bf93, 0x9fff4f70, 0x84907fde, 0x4177cb14, 0xfeb2de97, + 0xa9198878, 0x6632c89f, 0xd7353982, 0x82187c99, 0x319f2fab, 0xc8d0a6aa, 0x4210f4f7, 0xbf0cd195, 0x8d0d87d5, + 0xde7d61a1, 0x77d0d1b0, 0xf81d4630, 0x1527825a, 0x93365fb1, 0xb2362ada, 0x9ad10c15, 0x77e34973, 0x1c7a4033, + 0xb17562f7, 0x63d2ceed, 0x93998be7, 0xb52bf587, 0x4169bec1, 0xda15c721, 0x8b93eb9e, 0x2feb7afc, 0xd7727913, + 0x54c0a9f5, 0x3679cd8c, 0x4f3a8a3f, 0x9e1873e6, 0x664c1086, 0x165aa296, 0x9d5cf2c4, 0x5f029eb4, 0xd4494b3d, + 0x73f49a75, 0x8b7a530c, 0x1b62ec2c, 0x227d6e3d, 0x6962a9af, 0x0e269562, 0xf5c4cdf3, 0xce0de957, 0x73022752, + 0x0b7396fe, 0x9b5c70d4, 0x6a20e512, 0x3f73ced5, 0x5ce5e750, 0x00ef21e6, 0xb0a4158c, 0xd931c0d6, 0x66a16916, + 0xc8c1ca26, 0xe08611d9, 0xa7a7f502, 0x4042a716, 0x37a72c68, 0x1be76f39, 0x1fb44744, 0xe426cec9, 0xc544be75, + 0x73692057, 0x4f7e51f2, 0x62523430, 0xa4cd6cce, 0x55351e87, 0x9f21c0e9, 0xb5dbb99e, 0x68263177, 0x04088baf, + 0xa482262b, 0x1f0af701, 0xc68ffc19, 0xb689b635, 0x7cd85758, 0xf1fdd890, 0x10822714, 0xb623bfff, 0x0553f9d3, + 0x73a2f0a1, 0xf27ee139, 0xeb9ae79c, 0x826f47ff, 0xfd85edf2, 0xa11f46d4, 0xdf0688b4, 0x3e6b1b5f, 0xe0671882, + 0x2c731d6e, 0xa600de8a, 0x064697ea, 0xb87f1842, 0x0edd6bdd, 0xe328c788, 0xdeaa2231, 0x6b559012, 0xcf582dac, + 0xc9e1ae07, 0x7fb42be3, 0x73e28c95, 0x9ca90962, 0x7f71ca7d, 0x14e03c3a, 0x8631b8a9, 0x9fe6fe90, 0x559655d2, + 0x775a9839, 0xc352d6c9, 0x854d800d, 0x321ae197, 0x73c332d4, 0x62b501ac, 0xfca3f2aa, 0x4fc781b7, 0x76e771cd, + 0x6e3bbe51, 0x4cf9c465, 0xcaf65208, 0xda734b85, 0x0d70e91f, 0x77c847c7, 0xea5af938, 0xfe108234, 0x73131d71, + 0xd46ce7a2, 0x8021e7f5, 0xa852dcac, 0x18be534c, 0xe5c53a7f, 0x55bd2d28, 0xd35e049c, 0x81161382, 0x6e013dbd, + 0x08a87494, 0xb909e602, 0xd21f9632, 0x09bc2944, 0x63a4b923, 0x38c6c926, 0x6acdb94b, 0xcae5baa5, 0x2e9e72ea, + 0x950aa217, 0xdcf74fc9, 0x87198c06, 0x4ac37d65, 0x329bd6ba, 0x6d996330, 0x4e2ba988, 0x19a79204, 0x41128bea, + 0xed6b7a0c, 0x0464e5ad, 0xb1502bf8, 0x7b966195, 0x63eb8d55, 0x6de9a7d7, 0xcbae5cda, 0x24c0c0dd, 0xa4c02c32, + 0x04f1532b, 0xdb37bbee, 0x8aaf2509, 0xde311874, 0x1d7d7d89, 0xbda32bff, 0x5af375db, 0xcae0ce0d, 0x1b12c8f0, + 0x3f18a096, 0xae83adb1, 0x9accc82a, 0x02633ce6, 0x87466226, 0xbe18e219, 0x577427ee, 0x2b539ad9, 0x10caf78a, + 0x2bd3ee4b, 0x28bf80d3, 0xe18e9b56, 0xd48a455e, 0xda71524b, 0x6ff96c40, 0xea3f0212, 0xaef75a28, 0x795a4d7d, + 0xbcb91735, 0x75c99247, 0x8527cc83, 0x3f98574e, 0x65e55e4b, 0x1063dbda, 0xea349f8a, 0xc4d5e75a, 0x2b30c8e6, + 0x69973cdf, 0xd805d661, 0xdb83cea5, 0x0d65d236, 0x47b5679a, 0x3d69916f, 0xa338936d, 0x8e9a3dcf, 0x2aa49cfe, + 0x5ea32b6e, 0x5001b97d, 0xd7fbbc4e, 0xefb66f7c, 0x1cf21c11, 0xd244046c, 0x7c7f16cb, 0xe191f496, 0x29d63523, + 0x42d51751, 0xe94140fc, 0x49b170e2, 0x111c9bbb, 0xe1b14086, 0xb1fc7827, 0x856bf1f7, 0x595adecb, 0x147a42b6, + 0xd6033f4b, 0x38171a66, 0x90015b75, 0xbf5538df, 0x2305770b, 0x9cfc898a, 0xb2fbd217, 0x083f0b55, 0x07c45baf, + 0xfe1b1619, 0x6e4b2cf3, 0x2b792c62, 0x7ba44695, 0xea38befb, 0x77e5d5ca, 0x1e2c8fdd, 0x508ff52b, 0x629837b6, + 0x02446078, 0xadfb55d1, 0x9c6906e1, 0x21d1a512, 0x01d59ab8, 0x1d9d3939, 0xe696e711, 0xfdac2113, 0xae783f44, + 0x58659d93, 0x6f64c281, 0x3af3dce9, 0x336cf438, 0x3e8f6738, 0xdcd365db, 0x92e96bf6, 0x64880490, 0x08c769e3, + 0x1ee74649, 0x9a14ac90, 0xace4af16, 0x44a27d0d, 0x4ecf6a17, 0x6d396624, 0xf5a2d6fe, 0x830db873, 0x48fd1d9f, + 0xea56afcb, 0x8e3d976c, 0xc78b8de1, 0x2780b27c, 0x4e069561, 0xc0f96665, 0x8cbd13ec, 0x139bae8e, 0x7f59e442, + 0xbaebed4c, 0xfe0db691, 0xf6dc1575, 0x4a7415a9, 0x53cb9426, 0xa3dc00ad, 0xdb8cd887, 0xa1c3240a, 0xaf712907, + 0xdf9a28d1, 0xdc109698, 0xc6404925, 0xfa9d023c, 0x4251676d, 0xc29b75e9, 0xc6e73429, 0xdda0ab04, 0xfe719a99, + 0x2d4971cb, 0xfb3da210, 0xba095b76, 0x4b8ed0d8, 0x94e49092, 0x7c98f91b, 0x663af4e4, 0xe3a15afb, 0x9feaa88e, + 0x62857b93, 0x758a0d29, 0x25277f8e, 0x24b0a525, 0x4f301ae0, 0xbe8600be, 0x3b8a2555, 0x52994a4a, 0xfbf0e500, + 0xd62fdfde, 0x835c005b, 0xf11481d8, 0x7948ef6d, 0xa472301c, 0xf0901fb1, 0x53b619d6, 0x4536a38e, 0x841de13b, + 0x7009b683, 0xbfa8cc62, 0x9317eb02, 0x69ea81f6, 0x6174a6c8, 0x80bec886, 0x20037f68, 0xa2581bf5, 0x1b68183a, + 0xb9384b73, 0x0a9bef95, 0xbe8fe629, 0x38b1f762, 0x66e3a5cf, 0xec857d62, 0x1b2577ff, 0xfddd40a2, 0x608ae68a, + 0x9ed9828b, 0x87b0cc3a, 0x039072cb, 0xb6e40dad, 0x999b1c60, 0x57f3ed2a, 0x890c076d, 0x085890f7, 0x93fce307, + 0xa6ea735e, 0x0eb93290, 0x0cebb0d0, 0x4dbd999a, 0xb9a9cc97, 0x263f7950, 0xce18f38e, 0x11eae79c, 0x37dd01d5, + 0x918de382, 0xdf72f81a, 0x00d026b5, 0xc19c0e54, 0xa264de41, 0x76a774bf, 0xcfad3ac7, 0xc135c244, 0xd2827c56, + 0x17a77fa8, 0x9b5c2cae, 0xef83877f, 0x0eeea6ab, 0x258d1057, 0xe3eecf00, 0xb63e4ea6, 0x8af1fe17, 0x0f1666b6, + 0x8f2eadc5, 0xf2d5bd84, 0xc75c100b, 0x42ceb64c, 0x259a7add, 0x123e569f, 0xfd1bd08e, 0x8203aba4, 0xe226cdb5, + 0x8818c4d6, 0x766171c0, 0x93ce3a48, 0x32574fb7, 0xc785800a, 0x2acf6919, 0xe43ecee3, 0xc96ceeb5, 0x8be033a6, + 0x67b9525d, 0xabef7212, 0x2cd929d8, 0x0a55c8a7, 0xedc507b2, 0x5557e739, 0x7fb4688c, 0x6ad45b87, 0xb378f8d2, + 0xe1d7feed, 0xeb9f31ff, 0xf09d99bf, 0xb0f057fc, 0xd886ba06, 0x0158554c, 0xa6d3496c, 0x115d120f, 0x23a9da37, + 0x32ce63a8, 0x4ee9b89c, 0x55ed9a9b, 0x39f11a04, 0x83cebacc, 0x99336ecf, 0x7cf901ba, 0xaa86c3c6, 0xc89106f0, + 0x26de7a18, 0xe0d2806d, 0x6e5e3a97, 0xa168bda0, 0xa5a0fb3e, 0x3a0349b9, 0x9b1ef566, 0x355b1167, 0x244fb093, + 0xef360dcc, 0xd288c6c0, 0xf726a08e, 0xa6767150, 0xcc35aea9, 0x38ca40e4, 0x47fd8eba, 0x857598d0, 0xf67d249d, + 0x4eb4b6f7, 0x4a8914aa, 0x4111508f, 0xdcd171d9, 0xad010c6b, 0xd833f561, 0x95e43bfa, 0x7bb59265, 0x61eab678, + 0x75c7fd6f, 0x0160f367, 0xd1777347, 0x91021097, 0x76d88fd1, 0x6ba99e37, 0x2b284ab2, 0x14deead7, 0x0ed50419, + 0x7e95da0c, 0x204d2004, 0x7157be94, 0x40a8a328, 0x54b9e7ed, 0x84cb17b2, 0x3b97cd58, 0x02f41542, 0x1f2ac79a, + 0xc79d6581, 0x8536e121, 0xebf65d03, 0xe667a98a, 0x36301881, 0x2cea8eb0, 0x884578ed, 0x9e00da5c, 0xf6b0819c, + 0x6b55bcc4, 0x20fe3543, 0xad9a3dca, 0xf0de827b, 0xd6ef1db6, 0xb23674dc, 0xe045f720, 0xf4e44293, 0xeb3a0a16, + 0x90da5a16, 0x7792c3ee, 0x6addd9cc, 0x209ed2db, 0xd095f890, 0xc52e1aaa, 0xf34d7565, 0x6e59bca3, 0xf4f6bd81, + 0x186c0a16, 0xf435460c, 0x2eb795a0, 0x6ef3f624, 0x1c5be6cd, 0xf43c0572, 0x27c3b93a, 0xf8c2dedd, 0xd3744fb0, + 0xc57ca9e0, 0x50049c5b, 0x3bda3482, 0x43462c3f, 0xeb53fc1d, 0xaa0f3cff, 0x5b9c0259, 0x7c858e26, 0xa1c17cf7, + 0xaf3b6f93, 0x0a83e7c0, 0x63eab7bd, 0x80f16999, 0xcb9817f3, 0xb724b656, 0x0f2b506b, 0x5ebc5d01, 0xcd26f386, + 0xdea1cabb, 0x41dee0e2, 0x24bd2a49, 0x4c6c6c5b, 0x9e5582ec, 0xa8488fe1, 0x77dcbef1, 0x6381ed95, 0x51f1263e, + 0xe793e58c, 0xe83b2be6, 0x4b0c64cf, 0x9088c4fa, 0x25067681, 0xf7345b86, 0xd2d6d7c9, 0x5ce0741c, 0xc4e24e32, + 0x19e5f7da, 0xcc8cb27b, 0xf0704252, 0xce938b64, 0x6e73d3f3, 0xaecddd62, 0x34ffaa5f, 0x03129afa, 0x3748d99b, + 0x084196a4, 0x77a04751, 0x0895e434, 0x40e779ab, 0x67901c8a, 0x2ccd938d, 0xa88f3f27, 0x4cac9909, 0x888ecd17, + 0x7ec5a91f, 0x71ad678c, 0x03dae614, 0xa6c778ee, 0xb49aacf4, 0x98c0ece0, 0xb2fb78db, 0x0e1fb29f, 0x0d9dd6b1, + 0x96dd18c1, 0xde7a5b55, 0x1d89c06e, 0x5de105c2, 0x4ab8ebfb, 0xbe1d0233, 0x3b086ce7, 0xe5101b56, 0xa77366fe, + 0xc88397dd, 0x928dfe00, 0xee4f5409, 0xf45e7e65, 0xccf311d3, 0x6073e99b, 0x9c52e3ee, 0xe0a5b0a7, 0xe63e8b57, + 0x38137bf8, 0xdc0d90b1, 0xfdaeda36, 0xbe0dbe6e, 0xdfcc2571, 0x980b7f06, 0x8e11052e, 0x84a7b3db, 0xe7acd342, + 0x25c3125e, 0xe2052aaf, 0x5d262623, 0xc082af6b, 0xf58f368c, 0x242a6625, 0xdb6f60d4, 0x50b0860c, 0x2ecb125b, + 0x32dd8acf, 0xb8a479ab, 0xa58edb85, 0x98c9d093, 0x2985088b, 0xb0d5007d, 0x891c3a46, 0x8ee96bb1, 0xe87c2d26, + 0x749c2fed, 0xb0f54d9c, 0xae438879, 0xe27c0e6e, 0x4e1c778c, 0x3016df38, 0xb053fc27, 0xec56a326, 0x8e1cf743, + 0x7f2d079e, 0x0bdaaa1f, 0xd5b93a0c, 0x98e98be8, 0x630506ce, 0x9ae195c9, 0x9ded57cc, 0x0debf119, 0xc8c8b611, + 0x738edcd6, 0xdc017b67, 0x2a7c20a8, 0xebfcefce, 0x0921155f, 0xa69467a4, 0x8fec0d42, 0x9e6fd520, 0x7ab8b658, + 0x1cfd75a4, 0xd1d44c93, 0x59d79f93, 0x2fd45241, 0x99d6cbb7, 0x27d496a9, 0x8e95a2ae, 0x48a47a9d, 0xd53c4fc7, + 0xe78168a2, 0x324092d5, 0x75cd16ff, 0x4fccfddb, 0x678c7fad, 0xa0fa70e6, 0x181d7f5b, 0x33f0dd1b, 0x2adb2497, + 0xf9ba862e, 0xb7f7d19c, 0xa2c7a26b, 0x92da9797, 0xcdd95a7d, 0xe823533a, 0x1d237ce3, 0xca86daa8, 0xa1d11b3d, + 0x2edb2716, 0xb34d6447, 0x749665f9, 0x116f69cc, 0xda05add0, 0x9a9d39fb, 0x6a02d6f9, 0x5f6f5bd9, 0xdcb26bb0, + 0x918d63d7, 0x25ce2e71, 0xbd368ced, 0xe38087a2, 0xdb281a7c, 0x0e49cd4e, 0x6bed1469, 0x89e20dee, 0x39770390, + 0x2329e260, 0xfd426202, 0x371cbd74, 0x87ee4c5d, 0x16b06898, 0xb00dd49f, 0x7e149cc2, 0x9eb23db0, 0xec09745f, + 0x4422dca1, 0x4795f580, 0xb1ec8f9c, 0xb9509f87, 0xaaf885dd, 0x100b5268, 0xe8b410ad, 0xbc404067, 0xd5a22ff6, + 0x88cd8f38, 0xe8e6e137, 0x52eb5a96, 0xd63733ee, 0xb311197b, 0x26a90d40, 0x18cf1bf5, 0x57b31bff, 0xc7ef42ee, + 0xe8fbb089, 0xdfbd02df, 0xabd1ae05, 0x33040a26, 0xa7298973, 0xb5d0265b, 0x35a56c1b, 0xf77807ad, 0x7367fb8d, + 0x190e4aaf, 0xb14b52f9, 0x7b36b328, 0x372f57ce, 0x40e7efb0, 0x5cc0e956, 0x3f9dc0cf, 0x77091d4c, 0xf85ccd5b, + 0xdc9ae51c, 0x7b89a3ae, 0x202f5541, 0x3ee89b0e, 0x2db132ca, 0xbda4446a, 0x17b1a406, 0xd56dbf6d, 0x9b6daf56, + 0x506da8f4, 0x0cd9d44b, 0xdcfcdf64, 0x9dd37414, 0x544ea485, 0xea8bf078, 0x7295206c, 0x5bb53e20, 0x6cedb97a, + 0xc3cbb07d, 0x77d641d8, 0xdf56b849, 0xa58cf27e, 0x8bc7ee53, 0x0d8f7d94, 0x695cee38, 0xd1b49d27, 0x76f60e48, + 0x50a7ca0d, 0x448fb917, 0x1bf5a305, 0x30cddee5, 0x6fe5c230, 0xf3768356, 0xfd5e972e, 0x0658c7b1, 0x875d9dd9, + 0xb3c12ed9, 0xb1ffcf43, 0x825d5644, 0xe3e536d2, 0x49ebebbb, 0xadbb3a74, 0x8d401134, 0xd9afdeac, 0x8fe958aa, + 0xbb6ff5c0, 0xea1a5f87, 0xd532c494, 0xd086de4c, 0xe32e20bb, 0xe683ce3d, 0x1388f86b, 0x4944de0f, 0x2753acce, + 0xb8f6e4f5, 0x5f425566, 0x030ab5ee, 0xa06c51af, 0x5089ad0f, 0x33b4a085, 0x3e4bdf15, 0xb70d0f10, 0x1c84ae81, + 0x0e41e21b, 0x31391747, 0xb555809d, 0xb246ed36, 0xda5f70ba, 0x3bb87931, 0x15d7e501, 0xc466df51, 0x1e60db10, + 0x7bbc684d, 0x1fca6f71, 0x755dd451, 0xd8308401, 0x601400b3, 0x808a20b3, 0x923ea793, 0x33db2c8a, 0xe7e23958, + 0x2f1b6e73, 0xb60ab944, 0xe4b2f458, 0x9559f367, 0xea2a2c56, 0x3f3f7a5a, 0x5ee8d9e5, 0x772c70ae, 0xf4f0b004, + 0xb30ef0c1, 0x62d66462, 0x1043ca8f, 0x7a21fabc, 0x50ac9ada, 0xbcdf48b3, 0x12083e12, 0xafa9334b, 0x9ec01b3c, + 0xa28f696d, 0x37364dcf, 0x5d4783bd, 0x2a49d2ff, 0xe28dcdd5, 0xee897650, 0xc8b60d12, 0x5efd3438, 0x9b8a390c, + 0x4d0dda29, 0xd2027b40, 0x19702140, 0x02ddd4b5, 0xabb15685, 0x00d5d692, 0x2efefe0f, 0xc197aa5a, 0x86938c02, + 0xfd9f30a6, 0x5242552f, 0x0b32a708, 0x62051d60, 0xb266e600, 0xa10742a8, 0x9b974168, 0x7bea7d9e, 0x476a74d1, + 0x98200feb, 0x3d00825d, 0x20798686, 0xec30667f, 0x241b457d, 0xe87c70bb, 0xc80404a5, 0x0d5859fd, 0x546b08fa, + 0x486c005f, 0xda9125a0, 0x869c741a, 0x916601c3, 0x764959ec, 0x39225a6f, 0x3becb995, 0x7333174f, 0x2c7df4bd, + 0x34eb06d7, 0xd10ed64f, 0x8e65627d, 0x48b8680b, 0x22486ec4, 0x91e94f3f, 0x75be690d, 0x2de101b1, 0xca3587f5, + 0x33abeb74, 0x963cf20e, 0xa13d7bd5, 0xffabaf88, 0x214d797e, 0x7666e69b, 0x9d25db65, 0x658460ae, 0x75879a0f, + 0xea007ca6, 0x6023b42b, 0x35af5993, 0x0f22bc7a, 0x505b48fa, 0x0597ec1b, 0x0bac2d45, 0x47e3f3b2, 0x51e08afc, + 0x3eee91d8, 0x4fb02fdb, 0x0e14d925, 0x9e42c461, 0xafeda57e, 0x51451a48, 0x121a5198, 0x14bfadc7, 0xb37d973f, + 0x1bc8eca8, 0xd727518b, 0x9f363e08, 0xe5141f8c, 0xd45215ed, 0xb35339b3, 0x64cd1649, 0x103e8628, 0x04b52d22, + 0xa19ab228, 0x8ebc6610, 0x390778b8, 0x9d3767f0, 0xa66c1893, 0x5d2d0269, 0xfe3c9ba0, 0x3efba4b8, 0xd0dfb5b9, + 0x44f3cc0d, 0x55e912df, 0x00b2e674, 0x91e877c8, 0xfb2025eb, 0x74aa8a7d, 0x0667fe56, 0xf912a8a5, 0x5b091e86, + 0x0d48358e, 0x39fb1afa, 0xc6aca8d0, 0x5c2c9381, 0xa7fe7196, 0xe5a386cf, 0xed642ed1, 0x6519a43c, 0x6a65a322, + 0x0647346c, 0x5ddeea48, 0x809e6d31, 0x3cc20bb4, 0x92c179b5, 0x7bad9e11, 0xbdc75b5c, 0x404ae327, 0x556d3b68, + 0xdb5bf2ff, 0x3d34b2cf, 0x0b32f867, 0x330fa9a4, 0xe47caf7a, 0xf089c0b3, 0xf333fb2f, 0x9d5a2dd6, 0xc292c89d, + 0x7d140219, 0x2ae20f43, 0x60e8bbad, 0x731c957d, 0x51da1fd7, 0xef8456ca, 0xb88dc9a0, 0x768b7737, 0xe3fb843f, + 0x2a132018, 0x4e8454a2, 0x3edee305, 0x0f6d5b59, 0xe6ec4d5d, 0x3f572b98, 0xf80ddeb3, 0x4d557811, 0xe951880e, + 0x6e56a814, 0x790c828b, 0x7515f4a8, 0x15e33c3c, 0x5b8521ce, 0xaeac2307, 0xdc8825bf, 0x302d105f, 0xabba1c0f, + 0x25157821, 0x003dd1ba, 0xf1753527, 0x7be76e7c, 0xc229682d, 0xb6afa697, 0xb4e46b15, 0x7d1789a4, 0x7eafeabc, + 0xd3349ddf, 0x87a73d88, 0x2e188115, 0x61639634, 0x230243ef, 0x7bbe1764, 0x48e20d52, 0x67d29050, 0xb55c36de, + 0xe31f8fea, 0x116d19ac, 0x1403d6a9, 0x0e32cd4b, 0xe98b771e, 0x57fb9fe1, 0xeaa5aa5f, 0xa8a8fdab, 0x21af4420, + 0xbd5ed5fe, 0x98087300, 0x2dc6720f, 0x40f6040f, 0xfe155784, 0x2a72c1c1, 0xa48d2d03, 0x3045d0f4, 0xe47639f8, + 0x84c392a0, 0x2170db34, 0x48850927, 0x92f55b71, 0xf374cc55, 0xf87ef2dd, 0xede9e7f6, 0xc9ef1442, 0x6dc74775, + 0xa1a2e76a, 0x2f4ef3ea, 0x1aa431ab, 0x1f560720, 0x13f63e6c, 0xe1c048ba, 0x34c7ea8e, 0x13ca8c7b, 0xe8668005, + 0x2bc13871, 0xc86afecd, 0x86bcbb92, 0x1f2877bd, 0xa5a94025, 0x696ba668, 0xf7038379, 0x63bf95cd, 0x90c160ce, + 0x7cfb7a92, 0x994c01df, 0x0e54ac64, 0x8129c59f, 0x7fdfe8fd, 0x0a288cc4, 0x857667d8, 0xb856751e, 0x5e2bdb7d, + 0x9e9f30e3, 0xe6aabf03, 0xf180dd4d, 0x75312b42, 0xba3a75a5, 0x4d7c57c0, 0x0516414a, 0xbb4b2591, 0xaf8be91a, + 0xcaba7174, 0x83d4cefa, 0xfd0f0e71, 0x879e9d8f, 0x649dc1a1, 0xdf4ad981, 0x567f5d7f, 0xc0123a8b, 0x83a42039, + 0xa0e93498, 0x7403ae7f, 0x02b767d0, 0x5f608ef6, 0x2a6f82e0, 0x7f18c800, 0x03336395, 0xf02dc79c, 0x63b2b1ba, + 0xdd13cc01, 0xd0c42ede, 0x53f7f344, 0xc81ffedd, 0x09ef7740, 0xd4a02a0d, 0xe2701b7f, 0xb070eaad, 0x8bb78903, + 0x97704178, 0xbccd311b, 0x13130e96, 0x7d38b6af, 0x5fcfd513, 0xba8f1be8, 0xc6ae3f39, 0x045f5c78, 0x1defe0c3, + 0xe6e1b4fb, 0x2a505a24, 0x1b09b8fb, 0xfdcc7c0d, 0x1c4479a1, 0xa8b6a8f8, 0x6c2de89f, 0xb80a8251, 0x3f5cb93a, + 0x608bbc84, 0x853d0df9, 0xe31899aa, 0xca405ff0, 0x2e05d87e, 0x6f31d06f, 0xf4256284, 0xd7f8f880, 0x0168ca6b, + 0x24f6eb09, 0xd540c2ad, 0x146c97d7, 0x1a81fabe, 0x893b6bee, 0x086e7bdc, 0xe67142eb, 0x2e199fce, 0x189ce61b, + 0x42c49680, 0x602443d9, 0xa34faa1a, 0x4346273b, 0xcbf14d9c, 0xf4740dcb, 0xc3471f5a, 0x6fae556c, 0xeded8629, + 0xfd920403, 0x5de6a003, 0x7d05e150, 0xc64a5e2b, 0x1ddb9f11, 0x31811f5c, 0xff875a47, 0x4ec71dc7, 0x2ebb84bb, + 0x6b6dfc18, 0xacc44fac, 0xa1777936, 0x9c9f76fb, 0x9d6fba0f, 0x719f69ad, 0x93f27fdc, 0x44150aaf, 0x1e2805f1, + 0x828c9e26, 0xe865a6a9, 0x14597afa, 0x7d1d9e4c, 0xf049e042, 0x2072b8df, 0x63b25923, 0x5ff76c7c, 0xb229ed30, + 0x5e666cc9, 0x42e9ec90, 0x0229fc4c, 0x2a953a56, 0x91e56ebd, 0xfb40aa3a, 0xb1b59e79, 0x23d4d28f, 0xda9b9c3d, + 0xb1676cd7, 0xe80b8edd, 0xf335bca1, 0x815ddb5c, 0x8a41127e, 0x74578c51, 0x437a96f7, 0x5cf30745, 0xfd2b7e59, + 0xdd2eba5b, 0xd740b848, 0x6772b168, 0x1d7bfd97, 0x0eff7eaf, 0x428939f7, 0x352fcb69, 0xf6c10a1c, 0x927fe808, + 0x2d28e0c8, 0x826b8fb2, 0x0f0f48e6, 0xf27d094d, 0xb634ae2c, 0x208fcf15, 0xb068e4fc, 0xc1adb467, 0x5c5dda22, + 0x4b885b0b, 0xc750b6db, 0x12b20703, 0x49dddda6, 0x0d7deeb0, 0x3b6d0e51, 0x51366736, 0x364915dd, 0xdde63a1a, + 0xb9d46704, 0x046986a1, 0xf93b53bd, 0x7909e471, 0xf6f08347, 0xbd5b37a8, 0x34ae690b, 0xbdd8b580, 0xb16afe7f, + 0x5a3375b9, 0x819c12e0, 0x9db7f2bf, 0x9b189958, 0xee82f348, 0x77caa475, 0xf13801fc, 0x33a3a77d, 0x2dd67d06, + 0x5467228b, 0x79a34b3d, 0xce3e71c0, 0x384228c1, 0x70a2bfc5, 0xd3da0923, 0x0875c08e, 0xd3c72bbe, 0x19751853, + 0x5536f4bd, 0xef89bca4, 0x11005c19, 0x6527051d, 0xaea9dea6, 0xde85d3bf, 0xf8635257, 0x3a2fb14e, 0xa848ab6c, + 0x32465f1d, 0x21fd84fb, 0xb6782d12, 0x5ee62941, 0xca55571a, 0xceea87b0, 0xe0bfbfe7, 0x4c9d15af, 0xdc9f16f2, + 0x33e0ec1f, 0x9734620b, 0xdf3f3aa2, 0x3568d0ac, 0x4a1aecbc, 0xa122e509, 0x5a6e88b9, 0x0978b394, 0x4437b2d5, + 0xa00b4950, 0x3e617f6b, 0x0b972265, 0x00191f4b, 0x3e434e66, 0x4857cfa7, 0x14ced719, 0xea4aa3fa, 0x030f00a0, + 0xa94e485e, 0xb42c071e, 0x383a38fb, 0x76cd721e, 0x850889c8, 0xf5d22e6c, 0x2b74bde3, 0x76e2150d, 0x97d9b45b, + 0xa90adcfb, 0x90f1f5a2, 0x8f18f8b0, 0x98aae7d9, 0xf12bbf59, 0xd5f36940, 0xd7df9175, 0x4676356f, 0xd252029a, + 0x3a56b1b7, 0x2c9498b1, 0x11770850, 0xac1b7b15, 0xd0e74dcd, 0xf6991314, 0xd3325fb0, 0x086217da, 0x01bd0741, + 0x5934b0fd, 0x231c35c6, 0x49230aac, 0x347b102a, 0x9610438d, 0xe5e41139, 0x38b2380d, 0xd6a33d39, 0xa7752463, + 0x4060365e, 0x61fb62ad, 0x6fde634c, 0xd0dc93fc, 0x23fb1a5c, 0xac057447, 0xa448ca81, 0xb40b9ee3, 0xa622b389, + 0xa078b242, 0xe34a00b8, 0x8ac89acb, 0xda12dbff, 0xbfa03853, 0x82b219f1, 0xe40519c0, 0xaa3ff5f4, 0x8bd48540, + 0xde4f3f21, 0x974fcfb6, 0x878fbabc, 0xcdff5962, 0x4a2d4d1e, 0xdab18e56, 0xef067269, 0x256162ce, 0xce54df90, + 0x340d9f42, 0x55ac5d2a, 0x2ee2e464, 0xc1ec69ed, 0x95673af3, 0x7e1cc40d, 0x612dfa4f, 0x6bf35ab5, 0x10af3436, + 0x01c011d3, 0x4e404082, 0xfe6516cd, 0xcbe877f5, 0xf2ebd4e9, 0x8e2397e1, 0x3e6b724c, 0xfbcd51cc, 0x638d3868, + 0x2ea5792e, 0xd7bce8f4, 0xceba03a8, 0x1c7a1eb8, 0xaa41425c, 0x8f81a319, 0xb5a2bdf0, 0x13f6a0ce, 0xc1c001c0, + 0x75d6e754, 0xcf76bf65, 0xbae98012, 0xd6caf96e, 0x66ebb8cc, 0xbfd14c57, 0x72ec0b2c, 0xd78499cf, 0xce65a19f, + 0x0dc4ad19, 0xbaede5d8, 0x5a0cc7ad, 0x866fa301, 0xb238efc4, 0x1b7ad734, 0x63068358, 0x25f04457, 0xcc833439, + 0x826ee65a, 0x12546cd3, 0x3882f87a, 0xaf428fae, 0xe302280a, 0x0f6306a6, 0xdf94866e, 0x090f2056, 0xa070f0d7, + 0xd8b02a19, 0x65316947, 0x34d284e1, 0x8e38c05a, 0x47a26a48, 0x647fff73, 0x3f125420, 0xbae51837, 0xbf1dba70, + 0x1d38d841, 0xc8f323af, 0xd8bd0656, 0xfe8c7a8f, 0xb4dee497, 0xa184cfca, 0x6c98944f, 0x4f082204, 0xdc394378, + 0xda7e368a, 0x8554459b, 0xe1c7a3c8, 0x33f3c48c, 0xb2e25e92, 0x411d2d21, 0xcea93403, 0x5b4f03fa, 0xf42aacc1, + 0xc5c24b9a, 0x07831618, 0xae867b3b, 0xf475896e, 0xb78db0ca, 0xc077bcdc, 0x02f24a54, 0x8e1b4923, 0x3e59ec4d, + 0x84e4f017, 0x479c81c1, 0x293ed671, 0xe43f510a, 0x249b27a7, 0xe30ffc0d, 0x89f1cef4, 0xa543fe3b, 0x69d9d90c, + 0xf59e6401, 0x5e37c3ae, 0x3c57f90c, 0x1f9e083d, 0x9315188f, 0xc6062135, 0x8e592387, 0x0ce348c6, 0xa7f22fc0, + 0xce57cb4f, 0xaff8c8db, 0x1645e3e2, 0x17ff9993, 0xede8ace5, 0xc5f35828, 0x39b329c8, 0xebfb669c, 0x3a909fff, + 0xd2a0f572, 0x9fe1fb3d, 0xb0354d63, 0x05279661, 0x8da3c406, 0x3a790954, 0x6a02d492, 0x2669351f, 0x556a4147, + 0x5f2323f5, 0xf787caf0, 0x743816b1, 0x5d169f68, 0xc3702c1d, 0x4db7e9f1, 0x34428836, 0xe3527696, 0xc4a3f370, + 0xf1206965, 0xc1c9a2bb, 0x978b5911, 0x1059401d, 0x3bf47c72, 0x952477f2, 0x8e210c53, 0xfa61a7f0, 0x35f430c1, + 0x093f954b, 0x28b9b19d, 0x52b6fe08, 0x0f3b5c78, 0x058e3762, 0x2bcf4005, 0xcd27ded6, 0x6d3e1cc8, 0x7fbcf24c, + 0xd341ee1b, 0x8a0a41c8, 0xeba8bf26, 0x4235c927, 0xaeb62ef0, 0x290e8314, 0x5e1d0511, 0x4c75c44d, 0x70c31785, + 0x348428e3, 0x6c5697a1, 0x0ec65a38, 0x7ef978e4, 0x8fd16929, 0xf7cf41a0, 0xe26a4e48, 0x650d69e1, 0xf3df4fcc, + 0xa6d7b35a, 0x5d79ca92, 0xad98f895, 0x65fc7fff, 0x29303e88, 0x9c426f48, 0xc4ac0312, 0x90187cf7, 0x117a971b, + 0xabac5567, 0x98d51759, 0x6aa8291d, 0x9891d29f, 0x66cee801, 0xd11fd1d0, 0x2e917ddb, 0x9563b386, 0x9783e8a5, + 0xe316bb45, 0x4e0f386e, 0xfa0f5111, 0x1b902dbe, 0xf90a707a, 0x9ed9d6c3, 0x6d28b92a, 0x12bed832, 0x3ec7324a, + 0x29897e2a, 0xaf451475, 0xd4f6ef2b, 0xf3945c3c, 0x06e44b38, 0xca2d2cfa, 0xc2b015d4, 0xbef629d1, 0x51626a40, + 0xd53417c4, 0xd2049e64, 0x648f7472, 0x5164a910, 0x3256c259, 0xd29d15f0, 0x668d6373, 0xf772d339, 0x07c5558c, + 0x011a6125, 0x02585eda, 0xc9518b89, 0x10be5cb3, 0x7a8fba95, 0x86288c56, 0x9e1d47f7, 0x489984ef, 0x0ba6cd57, + 0xe08c0ca8, 0x23511d24, 0x43e2ff2f, 0x4afb4fbc, 0xa50efdb1, 0xedf9a8cd, 0x88251cf6, 0x9eb96767, 0x9db3d467, + 0xf05d8b46, 0x8201e709, 0x919baa5a, 0xcdbd9db5, 0xb568b43e, 0x32b7dfdd, 0x619208fc, 0xbd283477, 0x9c7f3502, + 0xd426abf5, 0x9949b225, 0xd53ef69c, 0x0a923b07, 0xb970812c, 0x3602e884, 0xed01dd39, 0xc4cbc72f, 0xfe81e568, + 0x42c48a09, 0x0f2097be, 0x6c0ae674, 0x838c8b29, 0xb01dd11b, 0x849ea60d, 0xd3e0c723, 0xa3a33f9a, 0x020f7b10, + 0xbae119b2, 0x0ae750b8, 0xcd4f060f, 0x20e5e3b6, 0x58f06e7e, 0x4bb96446, 0x35a95e4f, 0xd5a7edd0, 0x9f656022, + 0x3ec3153c, 0xf7087a02, 0x07411654, 0xa75fe8f8, 0xfca58598, 0xecaa743a, 0x98df2a1c, 0xbb5ce6f8, 0xd23b550c, + 0x45653d0b, 0xe00c1aec, 0x55999812, 0xfe3005e8, 0x3a0437ee, 0x96a88ea0, 0x97e1d1c5, 0xf19a7419, 0x8076a458, + 0x2f959c8b, 0xb7ccbf87, 0x1fc4254e, 0xfc58e632, 0x96704cc4, 0xe468d98c, 0x12359b86, 0x85837c96, 0x40cf3a84, + 0x4fa87772, 0x4a6e04d6, 0x708566e8, 0xa4890ab7, 0xb320a67c, 0x1e0ca7bc, 0xa1d12bbc, 0x9d5c99e2, 0xce92337d, + 0x1045e3ac, 0x6ebe7a1f, 0xe38d4758, 0xbc8785e6, 0xd40b181b, 0x5c416927, 0xd46ebec4, 0xac696797, 0x2b65614e, + 0x2893fc6a, 0xe04c3d9e, 0x1e2b8f4d, 0x2e1d4dcd, 0x1f917d8c, 0x3be434e1, 0x87b193fc, 0x105c73e0, 0xc95c8658, + 0x81434953, 0x72b0ad51, 0x59854a18, 0xddb697f8, 0x325f7ae5, 0x3e8f53c6, 0xa3f6c358, 0xb9f480a7, 0xfdd58cec, + 0x2d66a7e4, 0xe0a2ab5a, 0x5a0b845b, 0x1fbf2de4, 0x15d8022a, 0x19eb8315, 0x19239978, 0x4a05109e, 0x7bc6af3c, + 0x7c9f7b36, 0x90f110d4, 0x37cf8c61, 0x1bb8f969, 0x3d8a87be, 0x22f6320f, 0x4c3c086b, 0xb249b2ee, 0xe4320a94, + 0xb6043168, 0xb859c197, 0xbf3caf65, 0xf4654488, 0xaca87899, 0x7b7806a8, 0x12ffebed, 0xe5579cff, 0x22160cf5, + 0x2ba96a6c, 0xab70a5f7, 0x63f08f56, 0x8ee840fe, 0x15f4f328, 0xc15c15e2, 0x7fe4d5ae, 0x8f980025, 0xfe4dd206, + 0x902239d2, 0xdc73c5ff, 0x7661b64d, 0x30550f80, 0xcebea865, 0x3c496287, 0x885b5491, 0x3193cb57, 0xf7e8d1c2, + 0x666cae50, 0xb14d195a, 0xdce9f15c, 0x37882569, 0x12e773cb, 0xe9c71a75, 0x58c10742, 0x41db15e4, 0xe5024a42, + 0xc3d2d105, 0xf7e7567d, 0x561db69b, 0xc0b28dd8, 0x3fa9d028, 0xd7d5d04e, 0x222ce47a, 0x477caf61, 0x930a8fd6, + 0x2bb99f94, 0x3a16be09, 0x9713984f, 0x3f8d1128, 0x28d8a214, 0xf219c82c, 0x1c72095d, 0xcc93dd7a, 0x29d506a1, + 0xb7eac69e, 0xd9ac9d28, 0xbed272e2, 0x8b4bad16, 0xb6719fec, 0x1a6df62d, 0xaeed4bd9, 0x4d733612, 0x835a9dcc, + 0xd216a59e, 0xc71eed61, 0x88b83e96, 0x53880dbf, 0xdb6a0065, 0xbe49b7d6, 0xae4b7ba4, 0x0e8ebd56, 0xaf5a6d1b, + 0x31ac500e, 0xa66af841, 0x6c71467f, 0xd5d0ad7c, 0x4e2b81c4, 0xfc003475, 0x93e65849, 0xdd967ca7, 0x42f773f9, + 0x5b5b6375, 0x1107fbed, 0xa22fbb2f, 0x2dace88a, 0x51a41c6b, 0x79b7dbcf, 0x271217b9, 0x5328b1a0, 0x0a1da9af, + 0x34977b1b, 0x98eec6c5, 0x3b81d9e1, 0x72c44bed, 0xbc1c11bb, 0x1e8ae36c, 0x577b4d0d, 0x75ddff1b, 0x950131ad, + 0x11562497, 0x4669ecd5, 0xb0b0a796, 0xe024d0ac, 0xe1fb6d86, 0x4ceb5280, 0x42329fd6, 0x953c3fdf, 0xcce61f6e, + 0x537d96f4, 0x87a1a3b5, 0x9e1d102a, 0x7a3c4d16, 0xecc9fd02, 0xb6aa0cb4, 0x5cd77850, 0x9bf9ccdb, 0x0ebe5543, + 0x544fb3f4, 0x2d65ba54, 0xb0ff05c0, 0x6605ae26, 0x02503927, 0x6803d1fe, 0x783dd792, 0x69e2610e, 0xbd47679a, + 0xcb3d8099, 0xefdbc7a0, 0x69851a74, 0x9aba1b2d, 0x6dd1e02b, 0x25b11e12, 0xf975bfd0, 0x9cbef634, 0x4a294340, + 0x4071fc48, 0x9b88574f, 0xfcbf48cf, 0x7990ae78, 0x3d6aaef7, 0x1867a384, 0xf5dd681f, 0xd6849e23, 0x1c30f6e1, + 0x8adb353f, 0x43e06c81, 0xb0e32316, 0x040cb60b, 0xf8e7c764, 0x01e9c39c, 0x83bd1a14, 0xfeedbdb7, 0xa9600a38, + 0xe1aa62be, 0x37917194, 0x9055d851, 0x99685973, 0xb58323a0, 0x42acbb4f, 0x4592d69c, 0xbb139b9c, 0x2543cbe7, + 0x46f162df, 0x1dde8965, 0x99ca7e68, 0x7bd33877, 0x528d7b07, 0xfaedb869, 0x5c2d3694, 0x73109185, 0x678697f7, + 0x87da8df6, 0xb6412cf3, 0x730ce986, 0x9ee7caae, 0x60c8aeab, 0x9f71589e, 0x7f4a1745, 0x4a22ea3e, 0x819661ad, + 0xbf79bed8, 0x4ab18531, 0x40c346d8, 0x9e4e71f7, 0x92e4cf4e, 0x8d8b4af3, 0x98be2f2f, 0x52b70a3f, 0x24e9facc, + 0x1f8f2914, 0x4652571e, 0x795a175b, 0x94d7e11d, 0xef43c602, 0x6de4e7e1, 0xda0c6f5b, 0x7feca59d, 0xe9d43881, + 0xade0cdb5, 0x3c9faea8, 0x0e42233f, 0xc5640b82, 0x2c6e2d66, 0x90642ed2, 0xcdad059e, 0x61664478, 0xbeec809c, + 0xbf2c2971, 0xcf660ed3, 0x9e72782e, 0xd99bc4aa, 0xccd29666, 0xfadb5518, 0x89c264ed, 0xfe1d5f2e, 0xcab609b6, + 0xbc8d8b3e, 0xf4d312c3, 0x222b0054, 0xf578615f, 0xabefabe4, 0xe584e42e, 0x3ad2259a, 0x65ef72a0, 0x98605d3e, + 0xa9f60b68, 0x344d462d, 0x66e69fe8, 0x9852a4cb, 0xdf2b607a, 0x24bcb8fb, 0xd2e62c20, 0x67449497, 0x197cb5d9, + 0x816c2e9a, 0x8d23fcc8, 0xfce97a64, 0x04591f7a, 0x84410513, 0x449f8fa8, 0x0e851723, 0xffeccc18, 0x3fa62036, + 0x65d38c1b, 0xf4666232, 0xd4cc0b33, 0x55dab14b, 0x276af5d7, 0xbacf7e8b, 0xe07e434f, 0xe3316772, 0xad8b46d0, + 0xb938addf, 0x1c203d58, 0x5ffbe02c, 0xe9d62992, 0x28c446b2, 0x09b96d09, 0xc448d091, 0xd65c699b, 0x45dbd548, + 0x4b85a604, 0xde9eb6d4, 0x79b8b22f, 0x8a7388c4, 0x45c66a59, 0x037014c4, 0xf65e4671, 0xdf9e9310, 0xb2910e43, + 0x7ad57aef, 0x66b90e5c, 0xa7a52233, 0xe753fd66, 0xb96a09d4, 0x8e1b6e6f, 0x75eb692d, 0x1e52b77a, 0xc559ad45, + 0xbcdb57ea, 0xc7b04607, 0x316e6186, 0x49e81318, 0x5fa6a512, 0x80fbe0dd, 0xe89b66ad, 0x544bb5f7, 0xe23420ce, + 0x45179c9d, 0x72b96972, 0x5fdfc7b5, 0x1ca9919f, 0x5abfd4c4, 0x2b013aab, 0xb86b20d3, 0xdc0d8d55, 0x8a458f61, + 0xb85403ef, 0x32b5f92b, 0x2568ecb2, 0x7a6427f6, 0x67f5a385, 0x63df7b6e, 0x09855174, 0xd4acfeb3, 0x84f230c3, + 0x2c1e1f24, 0x90b2a009, 0xa7eb438f, 0x4b992c6c, 0xab2c20a9, 0x6af7f4af, 0x08bf5aa5, 0x75be69fd, 0x06e2afda, + 0xdd5e6894, 0x2f85f4cb, 0x53b4a27c, 0x8f4e89c5, 0xa08fe751, 0x80f57826, 0x47b159e1, 0x135fa947, 0xeadf1865, + 0x49d9a946, 0xdcb6347f, 0x728e8b2d, 0x85185e54, 0x9fb13b9b, 0x27189fcb, 0x2eb59e07, 0x9c0c6a5e, 0x4b479a9f, + 0xafc29605, 0x99650401, 0xc42fd039, 0x8585ae9a, 0xc1380e55, 0x543f734c, 0x01386b83, 0x605a58ea, 0x556a690b, + 0xed22663a, 0xfa40b39a, 0xa9ad281f, 0xf525163f, 0x39ac370b, 0x91c5343d, 0xa881c838, 0x2b5b68e3, 0x97db17b1, + 0x05beaf31, 0x948c3f01, 0x99903cda, 0xae0ed8a9, 0xe05f5e3f, 0xf40b7e14, 0x662f57f1, 0x5b62e3b2, 0xf20205d3, + 0xd5f38f57, 0xd49d5e63, 0xd340b934, 0x1252fe29, 0xb6342b26, 0x3f2e207c, 0x724d5acb, 0x8fe3c1a0, 0x9f5f662d, + 0x4f50c315, 0x49e5d46d, 0x6391b194, 0xd4c57f48, 0x8c2cb82f, 0x775a689a, 0x75c7eae1, 0x11285b99, 0xef94348a, + 0x232802f7, 0xfb1ec02f, 0xe8cb6535, 0x837dd2be, 0x5c89e0ae, 0x47c6e2ef, 0xb0b1a2c9, 0xfaacaf92, 0xb3722ccf, + 0x8e3615f2, 0xf5aa3535, 0x5a93d331, 0xa64408a5, 0x6b164222, 0x9dea4b17, 0x1d07865d, 0x9a8fc189, 0x62abb2fa, + 0xd7779e46, 0xba2bf3d2, 0xf73d843a, 0xd81a940d, 0x07c17b68, 0x43dc101a, 0x6e368158, 0x258e2998, 0xbf9d44c7, + 0x5217f7a5, 0x2694cb55, 0x8ff8de6c, 0xed37f6d7, 0x70857424, 0x7922cee4, 0x78af8c2b, 0xaa745d73, 0xa3321c59, + 0x5469e9fb, 0x9065133c, 0x803c1d6b, 0x22a4e701, 0x0066dc64, 0x66ce7e58, 0x75dae4c2, 0xcdcfef96, 0xf6fc248a, + 0x66cfba43, 0xb8359a7c, 0xe5001560, 0x003bed5c, 0x31511856, 0x2f751aa3, 0xb4f5e846, 0xa1ae127b, 0x35a81936, + 0xe0aad9df, 0x643cea03, 0x3985e5d4, 0x15657444, 0x14dabf3a, 0x772712cb, 0x48c804b2, 0x20532404, 0xd53ab165, + 0x01169010, 0xf6990949, 0xd3202695, 0x80e22fba, 0x904d3428, 0x38b95928, 0x4b875a8a, 0x320ad88d, 0xafe6fb43, + 0x45ef421d, 0xb1a40a39, 0xc067bae5, 0x2a4a6dc8, 0x0d046b1a, 0x1f62c771, 0x4a7fc45d, 0x8fa66755, 0x8c80dfc6, + 0x9f856f25, 0xf3e0a669, 0x4722e6cd, 0x94b98bb0, 0x5886c3cf, 0x8760465e, 0xdd8b431c, 0x98a229f5, 0x7346c0c2, + 0xb96af2f1, 0x951d68f3, 0xeecf34f5, 0x96919de9, 0x958d2a56, 0x50a0d4df, 0x5489c551, 0x38f02d97, 0x33d048e7, + 0x9521ec3d, 0x2b327e2c, 0xdfbf512f, 0x3fee071e, 0x2f4b4bd0, 0xf9f6bbd2, 0x6e936ba2, 0x21831933, 0x6a062cdb, + 0xfe9135e2, 0xff24e00b, 0x57adfc1a, 0x0958a724, 0xfb9e69d6, 0x476ad8d6, 0xb8c074e9, 0x7cd43756, 0xa7788079, + 0x5c2c8b58, 0x1a6a6d1c, 0x381ce3bb, 0xafac145f, 0xb5de34c6, 0xad51d354, 0x8112fd7b, 0x44142cc2, 0xae78dc57, + 0x8b425627, 0x815b499a, 0xab057e08, 0x3c842c24, 0x9c502b1d, 0xa485a2f6, 0x246c3d8a, 0x0223717e, 0xd5607944, + 0x3bf06bba, 0x744d3b13, 0x0fd73251, 0x14358bef, 0xba965856, 0x6cca6cd0, 0x7247b387, 0x89a6eed2, 0x198af972, + 0xc1a376dd, 0xe9ca50a0, 0x9a87b4a9, 0xe72f2ee4, 0x0baa2360, 0x3e988379, 0x190430b5, 0x7fde9738, 0x1a6e484f, + 0x9db69403, 0x59e15719, 0xb180e9c2, 0x298e2617, 0x3eb230c6, 0x08051349, 0x5ff51666, 0xc3ee0629, 0xb8f83b91, + 0xfc78ae94, 0xf6f5a4ac, 0x4155745c, 0x7bcf9aaf, 0xc2c91ec7, 0x81df5f16, 0xc2a8f722, 0xa9c6fed3, 0x1f1e1c4f, + 0x8a4dcf0a, 0xac4bb98f, 0x5f23eaaa, 0x8b78b4ca, 0x114d281e, 0xea71e8e5, 0xa2f3a284, 0x8bd3fde0, 0x8d0ab3dd, + 0x8e34ceeb, 0xc2fdffab, 0x9ff2cb60, 0x0fd6bc96, 0x7aa8f982, 0xd2ca34a6, 0x11a2af01, 0xaacfb21a, 0x69be5a63, + 0x61be8b0e, 0x449f40d5, 0x42f6088f, 0xbd2e94b0, 0xf35863e4, 0x258f8404, 0xd077c0bc, 0x91840a82, 0x40356326, + 0x308c3fd7, 0x05691fb2, 0xd64eb634, 0x82c17b11, 0xe4632f6a, 0x85ea0537, 0xfbbe4e37, 0x05544b53, 0xb1a305a3, + 0xe9ae07d9, 0x89259cc1, 0xf0eb30a8, 0xffa951bb, 0xeb10fb75, 0xb13f8ef5, 0x3aa3a64e, 0xe27436eb, 0xcd9927d9, + 0xf6bbd458, 0xfeb39480, 0xd203c0a1, 0x0fb44861, 0x3d831bf9, 0xbdd27f9d, 0x02845cca, 0xa70775a8, 0x4ff54530, + 0xc4da9d39, 0xd20abb14, 0xa7289458, 0xf7c2ec18, 0x64876d1a, 0x1508a2cc, 0x1fff93b5, 0xa6916341, 0xb140c891, + 0xd3153e9d, 0xa58168e8, 0x23940cb9, 0x3281c653, 0xe4a9e191, 0x562b2c73, 0xf5fb8432, 0x629d2f28, 0x55a49485, + 0x0bbbb236, 0xfc33c49c, 0x426bd136, 0x1df67c1f, 0xdc03948f, 0x250e1563, 0x7f1b8584, 0x39a005f1, 0x58fa11b1, + 0x1f58e622, 0xf2161d7c, 0x19e3b990, 0x17d3b455, 0x3ae2ee60, 0xec48d080, 0x1346f4fd, 0x5f8cd24c, 0xf0ac8c35, + 0xd7e87c26, 0xfdffddc0, 0x74814d78, 0xe9c1f583, 0x1c11e565, 0xbba43325, 0xb4c0f738, 0x6fe55e8c, 0x61e0f810, + 0xf837ef8d, 0x46688755, 0x80a5aff1, 0x34433af0, 0x38460c69, 0x26f90724, 0x870e0557, 0x656276e4, 0xd367b1ea, + 0x9c331325, 0x6ec5ecca, 0x8aa0c06c, 0x24e40ef2, 0x0f9e936e, 0x12115fad, 0xac89aa30, 0x0ed4ff33, 0xf9cfea6a, + 0x93ae0385, 0xb1a50661, 0xa4a641a3, 0x4618f207, 0x4b35e8bc, 0xaf63ff27, 0xfa4ac51d, 0x4355b5f8, 0xc7f54353, + 0x21890a65, 0x5c61cbcd, 0x99150cf3, 0x0d86d942, 0x5c6dd165, 0x2f740c7c, 0x93b8843e, 0x1af0e290, 0x153914ba, + 0x61a52eb7, 0x38b7b9f5, 0x724a9f98, 0x489b357b, 0xf0d37afc, 0x27460447, 0x41114737, 0x430c837b, 0xfc6b6ab9, + 0xd7f0ced0, 0xb1f30a07, 0x657a094d, 0x21ace385, 0x2a40e0c4, 0xf2533a2b, 0x22345e4d, 0xaf838ad4, 0x223b4248, + 0xbd993ba7, 0xc7d73101, 0xd3980304, 0x3086dd77, 0x34c92784, 0x9c82c3e4, 0x5288518b, 0x9b40f3d0, 0x7465f8fe, + 0x46b504f3, 0x0fe81c00, 0x5914c4f4, 0xa47a29af, 0x7d6655d6, 0x3876800c, 0x05bec6ff, 0xa9b51f55, 0xc28ed710, + 0x9b510da0, 0x0226654a, 0x15ecbca4, 0xeff9296f, 0x3226a052, 0xb7e3f01f, 0x67f6ba37, 0x59a2feec, 0x6d638c2a, + 0x030643d7, 0xed0470b2, 0x14b7a6f5, 0x9dc9e4bf, 0xcd47dbce, 0xc5542ca9, 0x73f79b88, 0x05dda1ae, 0x238fc4fb, + 0x0f4f732d, 0x4a31bf7f, 0x0c1ad58c, 0x667a3f16, 0x19e9661a, 0x41d9f2d3, 0xef06d4db, 0xd529f421, 0x70e883fb, + 0x4875c4aa, 0x70dc6667, 0x430a7dcc, 0x00bc1579, 0xce88e585, 0x56f15838, 0xd4b18e30, 0x55966a14, 0xc86db8af, + 0xb9001b8a, 0x4d48093d, 0xf73492d7, 0x350dab67, 0x70f3fdda, 0x036b4f4c, 0xde506e80, 0xcef97a4a, 0x9f3dab78, + 0xfda5b8b2, 0x679b6211, 0x20e67903, 0x9badce4b, 0xbafa7d14, 0x509d0541, 0xf81625f1, 0xea270c3d, 0x75e0a2b0, + 0xf2705d06, 0x64d90e90, 0x212a4ae1, 0x57d6db59, 0xa2a72161, 0x7903f498, 0x4ec10ff9, 0x63103b7d, 0x83e08c8b, + 0xb82fd74d, 0x52e930e5, 0xf75c1fd7, 0xbb93e5fa, 0xe327f306, 0xa0086d8f, 0xf5603b7d, 0x92773fd0, 0xefd0b445, + 0x7067974c, 0xbfedeae0, 0xf9538fb5, 0xd30d9f9a, 0x813f4e59, 0x9852642c, 0xcf46eb38, 0x9945c1a3, 0x8edce629, + 0xf0783798, 0x69b7e032, 0x3dfcc9d6, 0x2b588290, 0x0bc8a842, 0xb88ac782, 0x672a5200, 0xff408884, 0x1278aa86, + 0x0c570615, 0x918bf4df, 0xdb0e2fdd, 0xd99ff78f, 0x6fad1898, 0xd2e1cfa9, 0xd14ed6a2, 0x4d51b679, 0xacf295bc, + 0xacc75e7a, 0x1e938df8, 0x7e8ae7f8, 0xfcfbc1c9, 0x13dbe4e9, 0x2731ad2d, 0xf23b8d8a, 0xbf7e8ed6, 0x16f6d73e, + 0x4af246ff, 0xb313f556, 0x4dcf0109, 0x64764b1d, 0x4ae055bd, 0x7373cb0c, 0xae5c0ad4, 0x2665e0fd, 0xf04f1c92, + 0x390dfe68, 0x248d51e5, 0xab3fc5ed, 0x9150eb15, 0x4fed6b8f, 0xee5db887, 0x159db73d, 0x0af11aa3, 0xac8a518c, + 0x58188a0b, 0x689685d0, 0xb8e2c723, 0x9510ba81, 0x19d79e93, 0x746ee6bd, 0xb920cc99, 0x789a5f50, 0x025ecd1d, + 0xf4ec93b7, 0x6a2010d6, 0xc8528bb9, 0x67588256, 0x0a038bbe, 0x533e1d40, 0xbcf50ad4, 0x4db7ed75, 0x006434de, + 0x083903bb, 0x6541d54a, 0x299dfbee, 0x63bcf350, 0x4df80508, 0x1130105a, 0xde0ed556, 0x79131ae3, 0x6258059e, + 0x16a55fc9, 0x4760e45c, 0xfc2280db, 0xd372abc7, 0xf7bcbdbe, 0x4de194c9, 0x2193f118, 0xdd281b4a, 0x9521fc40, + 0x0b64a52f, 0x495bdc70, 0x5b626b13, 0x625a4e27, 0x80899dd3, 0x19afe38b, 0x9f2fa422, 0x4dbfc289, 0xb3bca32a, + 0x76e559e0, 0xdd5d7e0b, 0x80d3839c, 0x11eaa4f7, 0xdb31704e, 0xc238be82, 0x57064118, 0xd7f3ecbd, 0x6b2c7a14, + 0x516b2f31, 0x713847a5, 0xf1653c16, 0xaaba592a, 0xd38c0714, 0x1304dc64, 0x434163f2, 0xae6dd759, 0xb325ead1, + 0x35a4983c, 0xbeeea7f9, 0x489f349d, 0x0d375bf1, 0x20300497, 0x6ce901e1, 0xfec43492, 0xb816d7ef, 0x78e6b0eb, + 0x5559dbb9, 0xc1f75a04, 0xaa6faf09, 0x8b43e375, 0x1c47fff9, 0xc22d4b06, 0xd7545947, 0xb35d8b94, 0xb3d3a75e, + 0x07df8370, 0x424cfcc9, 0x74a0025c, 0x628fff0d, 0xd0478835, 0x5f7ab71c, 0x18075458, 0xd508723d, 0x88cfee23, + 0xbe82b7b4, 0x9331b15d, 0xa1e073b8, 0x904c231b, 0xaf2a7759, 0x361654b3, 0x25987557, 0x3ed1a6b6, 0x7e28c3e5, + 0xf2327ccd, 0x86b210ee, 0x4084a53d, 0x016ae23f, 0xe16adec8, 0xabde7f33, 0x05b6321a, 0x981f6987, 0x7ee8d494, + 0x2c888a28, 0x72709940, 0xa415ccc9, 0xed05b996, 0x082c0330, 0x2d764350, 0x8462155f, 0xd6890b29, 0x12d32413, + 0xe927155a, 0xe6c11797, 0x1754e720, 0xc85721f0, 0x9d281ec7, 0xfa014af9, 0xa7b687fa, 0x497c7849, 0xe3d64b9f, + 0xcabb9320, 0xaaffbf93, 0x55b0b3b3, 0x085cfa05, 0x15b62700, 0x12d49f51, 0x46fda5bf, 0x0c082352, 0x53f6af68, + 0x01663f0e, 0xc7d8dfc9, 0x6f260b78, 0x253db4b2, 0x8d771237, 0x8cf605ff, 0x0ed27924, 0x93b36858, 0x61e6cb78, + 0xe4a63dda, 0xa18a21b4, 0x07d0e6e7, 0x9ed41198, 0xa3e5b0a7, 0x4d758a3e, 0xe6443e24, 0x31b7daf4, 0x32c974d2, + 0x93f0b060, 0xeea6bd2b, 0xc8000c1b, 0x8d65bd8a, 0xb7eb6e55, 0x615d1dae, 0x32531589, 0x53dbbf9d, 0x98bd7d57, + 0x2d8cdcbe, 0xe56e7363, 0x921849b9, 0x3dc705c0, 0x910f4dac, 0xcffaaeb7, 0x03da07d2, 0xeb65ac7a, 0x19caeaa5, + 0x04b64842, 0x91722a43, 0x64f90bb1, 0x2b6a81cb, 0x2e2bcd7c, 0x1d219a63, 0x1ed1dff1, 0x8ddba3b4, 0xf974d869, + 0xf3e13b91, 0x258cf126, 0xbf624f6c, 0xa5be8815, 0x15277939, 0x56d1bdc2, 0x66b2c51d, 0xabf30e75, 0xc445135e, + 0x122e5f7b, 0xf06e8bf8, 0x018d20b1, 0x5654e008, 0xd9f8d5d8, 0x0ca0c18f, 0x996ba551, 0xf1a0c6e2, 0xd28c9054, + 0x48ad9b8e, 0xb00712e8, 0x4d0d4c03, 0x8bf42145, 0x231bbd42, 0xa128f76f, 0x17ae6fec, 0xb826c5f0, 0x8aae1372, + 0x91011080, 0x640e99a8, 0x1cc3b8c4, 0x34917afd, 0x4ff60239, 0xcacb5981, 0x6a4e262b, 0x0bf11656, 0xbf81e2e8, + 0xa0223a24, 0xfaaffe10, 0xb0e77f51, 0x54c52d19, 0x2e3daef8, 0x1709bc05, 0xa158f2b9, 0x5664aad1, 0x532f4171, + 0x91caba6f, 0xfe05aaef, 0x9c379d92, 0x62805c9c, 0x7cd33433, 0x7c4e3171, 0xa8f76a23, 0x90d67d6d, 0x62218014, + 0xb63dc2a4, 0xef2b2f7d, 0xca38978e, 0x56f7bd47, 0x0558d41e, 0xe1c94492, 0xae4b6301, 0x874ad3e4, 0xada13b00, + 0x338bb07d, 0x3bde667d, 0x1ac7172d, 0x7844a6b2, 0xb5296c23, 0x2f555a73, 0x382616c1, 0x590d24dd, 0x2d7f10d3, + 0xc0a7bff7, 0x6664cdcd, 0x7b55d8cd, 0xa414c6f1, 0x4f4d0ff9, 0xac6dc715, 0x910225d6, 0x517787dd, 0x55a08e78, + 0x48034aa3, 0x3a281954, 0x5e914b1f, 0xcfe38bcf, 0x49e6ac8b, 0xbcc05af4, 0x4f6b6e69, 0xc878c498, 0xd8e1bab5, + 0xecdb081f, 0x1f0549fd, 0x2e2e8629, 0x2b78482e, 0x08a39fde, 0x91415ff1, 0x03602145, 0xd9a89fe6, 0x54529c71, + 0x5c324d2e, 0x0f94465f, 0xdbed71fd, 0xf2798e7d, 0x11fef4a7, 0x6453cbbb, 0xc3231e65, 0x919c8afc, 0xde145249, + 0x47a764d4, 0x61b2c771, 0xcadd64b6, 0x995ce71a, 0xb73627eb, 0x58d38f7c, 0xb0b79182, 0x77d9b258, 0xea912653, + 0x5243ba27, 0x03c58a1a, 0x16e07c73, 0xd6519e51, 0xe0a2ad36, 0xf985c605, 0xcfce50cf, 0xc151d860, 0x57f16b45, + 0x298ecb05, 0x52df2fa8, 0xa9586824, 0x7a6d1d62, 0x30a85226, 0x38262654, 0xbe988fe2, 0x89c5b4b7, 0xc1391e3d, + 0xbfb6b858, 0xd7aa3a7a, 0x7854f053, 0xd8f0fa9d, 0x4a4c5010, 0xc35bca74, 0x2b0179a9, 0x1a887b3a, 0x503e08de, + 0x382f3e96, 0xb3382c34, 0x744d0056, 0xfe7ed0c7, 0xcee9e6a3, 0xca52b24f, 0x0a3e8d33, 0x6a81dc7d, 0x74108c0f, + 0x2d5970bb, 0xfae6b8ce, 0xcfb8f81a, 0x82f70b90, 0x93885857, 0x8d7ecdbd, 0x4705457c, 0xa2cb93e6, 0x33ceb8dc, + 0xb192a4fc, 0x6e6033b7, 0xb8e187f0, 0x5dfa4d1b, 0xba622275, 0xd38825a8, 0x27ca2d26, 0xabb4f022, 0x64bcb1b9, + 0x36eeb47a, 0x13a8adf5, 0xe65fec56, 0x08975986, 0xcb14bc9b, 0x65076745, 0x6c32c45c, 0xa7038f90, 0x16810aff, + 0x5643014f, 0x304cace9, 0xdbb91d6f, 0x390fad07, 0xea8a2e15, 0x541dde68, 0x7a352842, 0x4319f851, 0x76d0be98, + 0x9725dd2a, 0x63e12a9e, 0xdd83d9c0, 0x81f44fb8, 0xf7540b72, 0x31fa5978, 0x7c702b6f, 0x6c2cfd42, 0x940cbe18, + 0xd8da2409, 0xee533fb1, 0x527f6794, 0xfc48cc41, 0xa2d53a91, 0x2ec8f54b, 0x5e2698b5, 0xc3d27727, 0xb7c0bdf0, + 0xc538a10a, 0xb11307ad, 0x9478ca86, 0x4f954e69, 0xca4c3b7d, 0xb997e867, 0xad4f9a4a, 0xb9e7bcdd, 0x263f49bf, + 0x9aa2d518, 0xca18be82, 0x658f43ba, 0x2b539d88, 0x74fac92b, 0xc3f82433, 0x937d9bfd, 0xeb7a8921, 0x4c5fc8af, + 0x78cde522, 0xa0228add, 0xb271eb8e, 0xdbe540ba, 0x6cf6f338, 0x7e0b13bd, 0xdc434d9d, 0x5f6fad04, 0xc50c7c52, + 0x9b281bbe, 0x5a729151, 0xe9236c8c, 0xff2ee4b3, 0xbb6ec31b, 0x9e1d5325, 0xaa8433b7, 0xd6492050, 0xd51d5379, + 0x9a241110, 0x1191ba19, 0x37100433, 0x409d80e4, 0x99692e05, 0x9f5c433f, 0x7f4c2602, 0x5e142987, 0x61e588ee, + 0xd4ea3638, 0xc9e1a2f8, 0x99cb5844, 0x60ea5d5e, 0xbe1131b0, 0x02efed7f, 0xa76155d6, 0xacf0f82a, 0xcd2c9b4a, + 0x02596e61, 0x205bb2b9, 0xb7523a4b, 0x427bdf61, 0xe1201469, 0x290e1fb6, 0x192d0617, 0xfe2b3ad0, 0x87f60b08, + 0x2fd48550, 0x28a1c7e1, 0x2ab6c758, 0x05e909bc, 0x162a1b85, 0x158de7bc, 0x6976ca01, 0xc15353a6, 0xe6fcc882, + 0x5e624c9f, 0x46dc5194, 0xb4f1ae92, 0x06e8f4e9, 0x46c8f466, 0x7d150ccf, 0x6cf1636b, 0xa75746c3, 0x947d34e5, + 0x66aba2e8, 0x98fe8c7c, 0x84ab6533, 0x09174881, 0xe171c563, 0x2b629071, 0x51a39bfd, 0xfd7d8951, 0x759dc43a, + 0xeaf8b050, 0xa12b436a, 0x0e795066, 0xd63ce2e4, 0xf91c2f2f, 0x8e84f800, 0x2923c5bd, 0x6eabbbf9, 0xaf98537e, + 0x93ab0fd7, 0x94fe9b82, 0x7fdcf061, 0x59308c7d, 0x6a74f093, 0x5de79855, 0x0bba3097, 0x58b7e203, 0x326a27da, + 0x08524939, 0x4a0a136e, 0xda6dd051, 0x5f5ca0ff, 0x4251cbf5, 0xb689227a, 0xc5d23e7f, 0x27aab554, 0xd0d05517, + 0xfa49e19b, 0x63298f4c, 0xd094f4fc, 0xdb8ba47e, 0xa4bbb732, 0x1769f19f, 0x87aa8dd1, 0x079271fc, 0xfc9e49ae, + 0x2598f9de, 0x478385f2, 0xed705c1a, 0x15db4e6f, 0x1192e87e, 0x84a8171c, 0x4b260c67, 0x341dab3b, 0x3c3fd7d0, + 0xbd4b0047, 0x3ccbbd10, 0x6f816a83, 0xe4f1433d, 0x066ff750, 0x90fd0247, 0x25919eba, 0x40f7b3ce, 0xc4900c9f, + 0xfc4e2269, 0x14de906a, 0x559fbb8a, 0x31543620, 0x33cd9ae3, 0x87b13e2a, 0xd704f04b, 0x7a6f921d, 0xfea0fa9a, + 0xb69f19f1, 0x9367e3af, 0xd6b539d5, 0x8391ca58, 0xb97d08d8, 0x0c3f2f64, 0x200d7815, 0x1ca10ab6, 0x57dcaab0, + 0x5490b0b8, 0xc365c6a3, 0x0339dc8c, 0x397f08c9, 0xacdbd3a2, 0x249d1702, 0xa4aa3dea, 0xb1edc230, 0xf9d2d949, + 0xea0dab89, 0x02f89754, 0x7364d547, 0x399e5d9a, 0x58ccc9c5, 0xf21f42d3, 0x210ce420, 0xb0a897c7, 0x03f06285, + 0x2f866004, 0x6b55d1fe, 0xea52bd81, 0x9f2476ff, 0xacb5fde7, 0xf070b0a2, 0xa9bbb8c3, 0x4772f69c, 0xe442cf84, + 0xeb57e40b, 0x1f62c981, 0xfd3cf9fe, 0xdee63a80, 0xdebbad8f, 0xfabb76f1, 0x427c682f, 0x91ac8119, 0x559bbd21, + 0x361b8ff6, 0x5e1f7a20, 0x454591ec, 0x117f89f5, 0xf81dc57d, 0x40bcea22, 0x7560e694, 0x74024608, 0xaaa7f7e3, + 0xc9eb7af3, 0xda905b8a, 0xd90728ee, 0x85f42721, 0x7efbfd33, 0xa36e1b6a, 0xebe038f7, 0x10a7bf6b, 0x388a2dfb, + 0x3be767fc, 0x451544cf, 0x83c0481a, 0xcf24c9d7, 0x6e58cb94, 0xc8be2483, 0xa0e4077f, 0x5fb7197b, 0x8318799c, + 0x362c1ab5, 0xf7026536, 0xe62909ca, 0x93a73da5, 0x8ec92a6b, 0x72d9c9ed, 0xd4044805, 0xe5384ce0, 0x684c9bf5, + 0xe535e0fe, 0x91949cf2, 0xe1f740e1, 0x3a8d2176, 0x73ef0efd, 0x8e3228f4, 0x1e81ea44, 0x5e351594, 0x72ddd9b2, + 0xeed5104d, 0x1024fa88, 0xfd333204, 0x044d5673, 0xf4a3ff16, 0x741904c4, 0xe2432eb8, 0x61753a13, 0xed8f9d28, + 0x4c447724, 0x7da631ba, 0xe5bcfe58, 0x3d87eda8, 0x6b50f64b, 0xfa9cbf84, 0x42a66739, 0xf15a4e47, 0xa64bd7fa, + 0x174f8a6f, 0x6253e8e3, 0x618339ea, 0x619d6105, 0x4f2486e6, 0x30aaf79c, 0xa78747c0, 0x2f4c27cc, 0x188a9898, + 0xf9be2538, 0x19b3198a, 0x511319d8, 0xe00fad2c, 0x0f1f8bd9, 0xc880f233, 0xf14002ea, 0xf8adc36c, 0x4de7ce1f, + 0x8439b24f, 0xd1601d95, 0x728006d0, 0xef482bbc, 0x2051d90a, 0xb1553a16, 0xc77794b7, 0xae8c1e43, 0x78d329d9, + 0xe3b5cf91, 0x03cca900, 0x19bee45f, 0xd49f990c, 0x5b2371da, 0xa1c8fb8b, 0x62218a98, 0xc7f1394e, 0x760021a7, + 0xef45481f, 0x4a90b9de, 0xb14bd4f3, 0x63826b90, 0x01c971a1, 0xae3552b5, 0x04384608, 0xf47b364a, 0x3f48bbfc, + 0x08aa185d, 0xa3956f09, 0x4afdb947, 0x5b7f16d3, 0x509d22c0, 0x0cd3b2d8, 0x6883eeb6, 0x676a64c6, 0x1a322a73, + 0x3fafabcf, 0x0e35a0a1, 0x1c459b67, 0xb0cd09a6, 0xbb3ef586, 0xa691e32c, 0xf689b169, 0x13435c11, 0xfb75cfdc, + 0x53363036, 0xa1a76160, 0x477561d4, 0x1f966299, 0x01dbef0a, 0x8ca44f85, 0x53b7c8a1, 0x1f6e1751, 0xcd7e4a93, + 0xf2f48620, 0xedab5f95, 0xbbef5acf, 0x46c01d72, 0x98be4337, 0x79c5c73c, 0xd9cc76d0, 0x73b253c0, 0x43252717, + 0xebe8ecfd, 0xc4be5d02, 0x24ebb987, 0x2c221f7a, 0x881eab2a, 0xb50b1a1a, 0xa66fa54f, 0xf3be6253, 0x47cf3553, + 0x737f50a0, 0xfe7bf80a, 0x650a48d6, 0x32cc0ef4, 0x1e3f85ad, 0x708e2719, 0xeae38fef, 0xbd9e2b23, 0xfece663b, + 0xd537b833, 0x300412eb, 0x1fcbebb6, 0x6154face, 0xa6e40e59, 0x2aa8558a, 0xcaaad4f2, 0xf92d3295, 0xab940b2d, + 0x458239f6, 0x2377362c, 0xef608b1a, 0x491cb421, 0x5d7fadd6, 0xaa344c26, 0x3b026cf2, 0x816c2930, 0x70fd564d, + 0x76c668d6, 0x13c50a4b, 0x33aaec0f, 0xcd22eb43, 0x4ddd2917, 0xfb00f391, 0xce24d2eb, 0x430e0cf0, 0xc65735ce, + 0x732b82fd, 0x4206a4a8, 0x538dcb81, 0xc37e74f4, 0xbb5f7799, 0x6fd4b0c7, 0x0b6a0c7b, 0x88151ff2, 0x17b287fa, + 0x461da0e9, 0xb9d1b09c, 0xbab920eb, 0x1e25311c, 0x80c27376, 0x6c9efb62, 0x65640cd3, 0x12820149, 0x51d3cefe, + 0xd9f454e7, 0x292cfd3b, 0xee6a3812, 0xcbd3d75e, 0xbd9da9ae, 0x79f76669, 0x6939701f, 0x05b1c80f, 0xca182415, + 0x1212a2a3, 0x1fa77993, 0xb5c67101, 0xa04bc6a2, 0xf2980837, 0x21cf04f7, 0x951b7f99, 0xe4f198ac, 0xf0b81a66, + 0x313d7cd3, 0x9f5cabab, 0x5e88e403, 0x8a35362c, 0xf4a7e982, 0xab285a27, 0xe5e56c32, 0xe1c5872c, 0x47f80e4f, + 0xabd2d66a, 0xc0c8cddb, 0xa771de46, 0xdb025f0a, 0x7480ff33, 0x0e86cc86, 0x4aa0400e, 0x206fb466, 0x3acc8978, + 0x1f7907b9, 0x9d6b8731, 0x1108bcab, 0x784d507a, 0x004c89d5, 0xa955805a, 0xa7aa6379, 0xa47c4c02, 0x39a5677e, + 0x5d8a299f, 0x1718f4be, 0xd5088f64, 0x75faf554, 0x061e6f28, 0x7a588872, 0x70a143d1, 0xc04540aa, 0x7c812744, + 0x6af6d159, 0x9e73fc46, 0x8cd9ca69, 0xf3c2ca84, 0x40aa06a2, 0xa438f1f5, 0x7767e6f3, 0xa9ed498c, 0xa97994a0, + 0x85b06c91, 0xdada568d, 0x8f7f9275, 0xb3deffdc, 0x7a0f0917, 0xd3dc0579, 0xbbfa7b9b, 0x23591441, 0x4f37d975, + 0x3b7ad5fc, 0xd7e5fbf7, 0x13f39bcb, 0xe6e4ec92, 0xeaa7ed20, 0x1911d127, 0x47e55ef4, 0x4cc4f218, 0xe1227f63, + 0x15953403, 0x197db356, 0x210aef56, 0x85247750, 0xcb5e826b, 0x23781bad, 0xee47a2cf, 0x57f42ee8, 0x7ec713aa, + 0x39162f6d, 0x3004e5f3, 0xe8136dba, 0x092a87a5, 0x372b109b, 0xdbd24644, 0x4ad64ecb, 0x8d292c8d, 0xf749fe86, + 0x6a198474, 0xae92bd1f, 0x35fb244b, 0xc6834be7, 0x26293482, 0x20c5c83f, 0xb6e8bc3a, 0x0cdaf3f7, 0x02c0049f, + 0xc613d5e4, 0xff576714, 0xb9468246, 0xda0bd54d, 0xcb528866, 0xa2a0822d, 0x8225bd2c, 0xdd696563, 0x27ee4bac, + 0x725c5187, 0xe67d295d, 0x2fb62731, 0x3a35ca7d, 0xede93ad7, 0x3e515e6f, 0x875daed4, 0x8e846d49, 0x676a2cb6, + 0x7d876336, 0xba84ca11, 0x72a4f577, 0xbbe7e447, 0x9509b985, 0xaeb943c0, 0x360c0c69, 0xffa5845a, 0x683db281, + 0x3b1249ad, 0x6ad4e80a, 0x5fc62181, 0xc050249f, 0xd3200742, 0x336ab3e9, 0x68ab264a, 0x737f370c, 0x52e5c5ae, + 0x04fb6a32, 0xa9430ad0, 0xf58da1a8, 0x3c3cf401, 0x50d1d573, 0x065e26ce, 0xcad55c46, 0x5b692d7d, 0x82467bff, + 0xebb6936e, 0xba2e5fd4, 0x8bbb5e05, 0x8e013ba8, 0x3d8c4955, 0x4b48f8e9, 0x4ae36f4b, 0x170c72b3, 0xdfc22846, + 0xe2b98654, 0x977cb72c, 0x715dca20, 0xf0d1b24f, 0x4bb5629f, 0x70cdd4cd, 0xf687ae42, 0x7c77e5f6, 0xd733d147, + 0x4ac1aed1, 0x2f8a595b, 0xa86007e2, 0xff6a057d, 0xebbd8f80, 0x7acefb99, 0xa68f6f0d, 0x64ceb9f0, 0x2a3266f5, + 0x253f42ba, 0xad1f23a9, 0xc45cc096, 0xd0e1bea0, 0xa93eae47, 0x0bb9c76b, 0x378390ba, 0x73d2f481, 0x89bdab3e, + 0xc4b0c67f, 0x929ec260, 0x3f186af9, 0x4d8e8027, 0x75201618, 0x0616d871, 0xd307d663, 0x661d5560, 0x7e2274e1, + 0x05adee37, 0xfdaacb89, 0xe41f686a, 0xc0bdaa61, 0x667db669, 0x1149b8ec, 0xdab81bec, 0x412bd802, 0x67f1cf71, + 0x8dd23935, 0x2e1d0894, 0x05bc25a4, 0x17ce392f, 0x7ca0be16, 0x6ef0c8d5, 0x8c4ef117, 0x5aee30c2, 0xee0efd00, + 0xd98ef9ec, 0xb20943ce, 0xc003b2d0, 0x085a5715, 0xe18bea24, 0xbcafca9b, 0x8d09ce8f, 0x11caa30b, 0x87668b7b, + 0x75b63209, 0x619dad51, 0xb21e5f3a, 0x631faf77, 0xc9d7f538, 0x754c8169, 0x2e798911, 0x19a7f16e, 0x981078f6, + 0x05f5746f, 0x38277879, 0xab403591, 0x7eeb429b, 0x0b845580, 0x02ee826e, 0x9c825cd9, 0xcc054b61, 0xd7a7d789, + 0xa70e1d74, 0xc6a27b1d, 0x7176cf08, 0x35ad5b09, 0x2695e22c, 0x923345ac, 0xb678377e, 0xf6013669, 0x7432e31b, + 0x9d0665ff, 0xbe02d8b7, 0x060672a3, 0x7bcb3392, 0x12c10993, 0xd12a7faf, 0x85c4fa20, 0xf9c3a29c, 0x6a872164, + 0xa63c573b, 0xbb4f2b8a, 0xe3b82822, 0xb8e015ab, 0x8a92a0ec, 0xb3361b7a, 0x6ce15bcc, 0x57b19aba, 0x9adaf2ae, + 0x0e424cd3, 0x2dff1f23, 0x586801ab, 0x8ab93adb, 0x2a1c2c85, 0xa3664733, 0xd0bfbd84, 0x006f92b6, 0x81ddd0e1, + 0x7e479c14, 0x693960e7, 0xfa86fe1e, 0x1743ec04, 0x5ea70c30, 0x1c9213fc, 0xbc63b8ee, 0xfc364565, 0x9a42921b, + 0xed03420c, 0xcc01858f, 0xb3fca8da, 0x26912762, 0xb835afe5, 0x49bb1f8b, 0x3fbb388f, 0x343e3ede, 0x99083f5d, + 0x83494185, 0xce3f0e3e, 0xc5029196, 0x0ac85544, 0x99ee0657, 0x0b851bf7, 0x22df4487, 0x39568eec, 0x27db0193, + 0x8c0e191c, 0x38d57b2d, 0xdefc8f82, 0x151fae01, 0x33107264, 0xcee207cc, 0x81363414, 0x31948f20, 0x1097644c, + 0xd59ff882, 0x798a867f, 0xc5c949f7, 0xca4b69ce, 0x58cbc2dd, 0x5133e7d6, 0x28ddb9f3, 0x1e58e5f3, 0x971ce93f, + 0x783e7fd4, 0xd5e563a6, 0x1e9c258b, 0x217cbcc8, 0xa92402b7, 0xb4a25414, 0x4a408dd6, 0xd7bd0362, 0xab098e80, + 0xb5fd2703, 0x21aafca3, 0xba5e4b9b, 0xb27af0f7, 0x2d4859c2, 0xdfff9511, 0xbd050cfd, 0x6d4fc066, 0xb86a11c4, + 0xb3fd5ba4, 0x26dc0f9e, 0x9ad5b74a, 0x855c73ef, 0x83867ea9, 0x92fbd30e, 0xee130fa5, 0x77fbea26, 0x610311bd, + 0x8d89a9fc, 0xab9efac6, 0xa6bf2bbb, 0xe320aec5, 0x28525810, 0x74125f3f, 0x267fda5a, 0x851cc0a7, 0xbbb43465, + 0x7c5a732d, 0x8f61f301, 0xdd29ff4a, 0xd8e312ef, 0xc45fd6ea, 0xc79df9be, 0x574c6834, 0x92e196be, 0x320ac99d, + 0x9a02ecc0, 0xacadf745, 0x5678d660, 0xabdf94aa, 0x44614f5a, 0xdcac5327, 0xb35c24d5, 0x5ad306c4, 0x8d1b9a66, + 0xcfd1179b, 0x57c9a91a, 0x384aeac0, 0x2e21dd85, 0xa5da3491, 0xfcb1bcaa, 0x3bb3f557, 0xf3afe0a2, 0x192f5e8c, + 0x1c4c5f45, 0x7b68b86e, 0x1e89fbea, 0xe8a6cf67, 0x866969e3, 0x87ed97e1, 0x7a6003b6, 0x3cbc0229, 0x6f29119e, + 0x938f18e6, 0x2d8c6a00, 0x06472190, 0xe140e395, 0xfb7be6cc, 0xfab5fa8c, 0x6f22319c, 0xdf8ef712, 0x3aeb7bcf, + 0x0976ad11, 0xe535276c, 0xfb71607a, 0x265b3633, 0xf8c407ee, 0xb1f9462f, 0x6ec425c1, 0x7b957cda, 0x3823a58d, + 0x3fd67853, 0xba00b141, 0xf06a532a, 0xf57eebe3, 0xcc63d05e, 0xb4226d5f, 0x3ecdac59, 0xc5092528, 0x89f0a868, + 0xe60ccfb6, 0xab713b19, 0x562e274b, 0xfa4ee2c4, 0xe5ad4120, 0xd9f72130, 0x2fb15543, 0xd5b1d23f, 0x4906f2b8, + 0xeffcc5e3, 0x700f4eef, 0x62959c4a, 0x541d0e14, 0x1793d498, 0xc11ba35e, 0xaabc4afa, 0x219dd78f, 0x795253a0, + 0x373d0128, 0x4fb96f35, 0x8b06e2fd, 0x29b1fabf, 0xa334524f, 0x298ad114, 0x28fa0646, 0xf0ef617b, 0x9a61fb63, + 0xbbe723d1, 0x71531e48, 0xb7e4f151, 0x0389c5da, 0x2d88cc84, 0xb9b96be3, 0x9cb0e62d, 0x0bc9d216, 0x1a082b67, + 0xf8ccadd4, 0x6510ccf3, 0x4674b37a, 0x53ddf342, 0xb1e5f68d, 0xade1ee1b, 0xbd0079ea, 0xc7c5495d, 0x6f7f37c2, + 0xc3f31884, 0x325cc40f, 0xb4b13498, 0x582fd4e0, 0xa381863e, 0x89fa31af, 0xfd2135c6, 0x98bf1130, 0xde389a78, + 0x4fa3a061, 0x49e9d7e7, 0xa19d5c7b, 0xdc1dacfc, 0x767cc82a, 0x5933dce5, 0x34b2a5ff, 0xac3c5cff, 0x73f9a7e7, + 0x5427b6b9, 0xe3c93c5d, 0xe9d7ce66, 0x555c7a30, 0x9fa1c36d, 0x66b59103, 0x40a7a94c, 0x304f4fda, 0x7229c5a5, + 0xae25a8c4, 0x72ae9ddc, 0x32f180d7, 0xfc4b20ff, 0x74efbdc8, 0x3c7b7e7f, 0xe5772475, 0x5c27466f, 0x1ad7ec9a, + 0x5223d635, 0x691f056c, 0x1e3f49f1, 0x682c415a, 0x758c913d, 0xceaaabb5, 0xce6e809e, 0x9d48eb08, 0x584ac0cf, + 0x79917a94, 0xfc4290bb, 0x326101db, 0x3e3290b0, 0x6a64202a, 0x177c9def, 0x887f5e52, 0xb7bb07c1, 0xd6e412d1, + 0x050c963b, 0xa2cdb24e, 0x7781871c, 0x2fbc3e18, 0xea6f7be3, 0x95159aa4, 0xda8aa599, 0x745dd08f, 0xfa565ad8, + 0x4156eac3, 0x1fbe5632, 0x84854925, 0x69bff42a, 0x3447a527, 0xd9abf9d3, 0x48101582, 0x4e06fac8, 0x13c5107e, + 0xd373bf2d, 0x1e4c1bc8, 0x5d44e604, 0x5c458eff, 0x09640b09, 0x34d6d8c6, 0x4851fcd3, 0x5aa2c3b4, 0x8a84de86, + 0x40f8e0c7, 0x4662c9bc, 0x26539f5b, 0xab70f63c, 0x8257f412, 0xfb9992ed, 0xdc1e8eaa, 0x55129d81, 0xe0218f39, + 0x6f8ec26f, 0xd769a509, 0x76027399, 0x978d0dd7, 0x7fe4101f, 0x8308be72, 0x901f3539, 0xcd41d4b6, 0x2974185d, + 0xe49eed92, 0x1d490ece, 0x26fb693e, 0x84d04133, 0xa5f7c270, 0x90d7d958, 0x871f95cd, 0x0c3d9333, 0x12a7e951, + 0xb2703b0d, 0x17f445da, 0x83c89af8, 0x86b480e1, 0x7d141ca8, 0x369587a8, 0x969eda37, 0x9d25d57f, 0x5564410e, + 0xc6ed2cde, 0x53c0b99c, 0x63620b2b, 0x47c55b6d, 0xfe82d53c, 0xe55426ba, 0xbbfcc686, 0x6521f2a3, 0x8e02fc4b, + 0x0b719328, 0xa6617107, 0x87e8a11c, 0x458c286b, 0xc4cbf91c, 0xefac8eca, 0x7836e5e7, 0x370b0d54, 0x40b98c7a, + 0xd6cf89da, 0x650a0af7, 0x688d23f7, 0x810d67ba, 0xdda1921a, 0xa5666ed4, 0x975dbc9c, 0x0943ebc7, 0x1122178e, + 0x28d05fac, 0x61abc151, 0x7f94316b, 0xae9778d2, 0x1caf804c, 0x5c4302ac, 0x835cc5a1, 0xfdd9d36d, 0x55b5573e, + 0x1c467ba9, 0x99ac1248, 0xc6695248, 0x3df19b16, 0xcfed2b9d, 0xd5e3d5ed, 0x46002fc4, 0x15dd6bec, 0xedb98f02, + 0x53b0cd1b, 0x109905c9, 0xaa6a93da, 0x9f3d5378, 0x63064154, 0xf97a4ac7, 0xab5503c8, 0x38d4d4cf, 0x75d263e7, + 0xffcb9384, 0x6c937fad, 0x05d391b2, 0x4ec6a4ea, 0x27dc4bc1, 0x61f73a66, 0x63f422ff, 0x5213171c, 0x4fa1acec, + 0xb27f4a39, 0x9d3fe7a9, 0x7394dc74, 0x51b550bb, 0x00a1a028, 0x1afcce6d, 0x911888b6, 0xd853e894, 0x3fcf46b0, + 0x140f414d, 0x3ca1ea66, 0x67c67ce1, 0x086e7021, 0x840446d9, 0x0c824c87, 0xc4e488f3, 0x91d337a4, 0x26b83e76, + 0x92e30dd4, 0x89f96c72, 0x48799de9, 0x1db03d9f, 0x67dc3dc8, 0x204fa4f8, 0xef8c9561, 0x1ba7d6ec, 0xb3afbc15, + 0x27b9e581, 0xa351ac10, 0xac2b1a78, 0x3862f87a, 0x22762479, 0x4f2b9bcc, 0xc3ab1f24, 0xe4e0f101, 0x502b4cea, + 0x721e5b5f, 0xb551b2d4, 0xa638c59a, 0x34bd6f97, 0x5dd8f21e, 0x6579ca38, 0x94bc4252, 0x56bc976f, 0x5c6bfcb3, + 0x63a81bef, 0x68220da2, 0xfac02839, 0x93cd121f, 0x75851b33, 0xeadf4101, 0xa1729ef0, 0x1768c7a3, 0xc76f5e04, + 0xb458a7a7, 0x80c6e5bc, 0xf86ff90d, 0x9e896215, 0x2042da4f, 0x864126af, 0xdc281bd5, 0x1f50a1a9, 0x08a82577, + 0x6df8b9ac, 0x9c491047, 0xe247b1ff, 0x90c81f63, 0xcdb1fa43, 0xc74fad5d, 0xf6564334, 0xb0107d55, 0x80c97cb1, + 0xdc594cfd, 0x9cdb9bbb, 0x787f600d, 0x0afabf09, 0x5aafb484, 0x698e7cf1, 0xae80b0e4, 0x35fff815, 0x4b69ca7e, + 0x5b97a4f0, 0x0dc546fd, 0x289ac7b2, 0x642c361a, 0x144c539b, 0x42fef79c, 0x3b754a28, 0x5baab259, 0x34f27f10, + 0x77694989, 0x835a4be3, 0x192ba83c, 0x86f9a32c, 0xe6f8027c, 0xe4fd8a68, 0xe1f4d723, 0x92fd1c41, 0xea9abb94, + 0x9c9b6436, 0x529d4784, 0x20ac2e79, 0x9454e290, 0xf9c16780, 0x5cf6c669, 0xd80d2bec, 0x0c5f9ef3, 0xaeb47ff1, + 0x966fae71, 0xeff6d980, 0x560bf522, 0x1e01b421, 0xbbcead81, 0x3c72a1e0, 0xbbc3ef68, 0x825f1df5, 0xb0e04bd4, + 0x1c35c1cf, 0xebd6e275, 0xe0d1bb0f, 0x6e9ad845, 0xf79ce509, 0x4c485668, 0x8c022fdb, 0xe69d1977, 0xdaeb1ccf, + 0x23e36eb4, 0x290640e1, 0xa2da2e2b, 0x670546d4, 0xb492285c, 0x23b10d77, 0xa9fdec62, 0x9aecd119, 0x86412196, + 0xaed4cdcd, 0x325245a4, 0x19bc6101, 0xa13f5b2a, 0xb3e1d911, 0xb025623a, 0x67798ed7, 0xea2c0cad, 0x02959d4d, + 0x81d0092f, 0xff76883f, 0x17d95f87, 0xf92b71eb, 0xcf38ac70, 0x5e3821b4, 0x0a61f88a, 0x369d01df, 0x2b505d37, + 0x57acf799, 0x7f1612af, 0x61a06321, 0x3c1e92b6, 0xb13b89b3, 0x19a61bf2, 0xb550f39b, 0x8547318b, 0xaa06bdde, + 0xaf5dbef3, 0xf8983676, 0x6e2991ec, 0x87ff0842, 0x09659ac3, 0x23c2d05b, 0x0593ec06, 0x461d0ba0, 0xdee4af30, + 0x61c4aa61, 0x4afc8a3b, 0x15b49715, 0x31e3d73c, 0x633b9880, 0x8826fe1d, 0x5f94e1d9, 0xc6f456d9, 0x64a976fa, + 0x271c5d5a, 0x76f20b76, 0xfce2f4f9, 0x0a4187d1, 0x518dc14f, 0xc9967e47, 0x55bc81e8, 0x7b814ca0, 0xff4fc072, + 0x5e33d3d1, 0x7bb8bfad, 0x92fb09dd, 0x244ebf2f, 0x45f85eac, 0x7853c1cd, 0x7d935b19, 0xa6a80b07, 0xbd82f6a7, + 0xc0b774ba, 0x2c78829a, 0xe6b46d18, 0xe0ddd0de, 0x98776927, 0x36690f27, 0x01ba45ca, 0x25702698, 0x9a1b3115, + 0xb6720415, 0xc1dafd60, 0x4609c46c, 0x3c09af43, 0xaa7115b4, 0xe43b37ad, 0xeaaad624, 0x13dca69e, 0x386a51f5, + 0xc3212175, 0xb3414ba3, 0x92b1cd85, 0x8f08f53e, 0xa42766f9, 0xc87e6bc0, 0xdfba8f0f, 0xec6e447b, 0x0a7ae1ce, + 0x2a8cbbf4, 0x7fd9501f, 0xb9fe1419, 0x5bbbdda0, 0xa3becee1, 0x9b70b526, 0xa5702be6, 0x503afa65, 0xbdd35a6a, + 0xa37f263c, 0x70a4fab4, 0x42c3a625, 0x7103445e, 0x01f5c513, 0xebc28f63, 0x7195e7a3, 0x1401f243, 0xe5e8a6fe, + 0x5664fa16, 0xe0b35da0, 0x677d8b4e, 0xbb00573c, 0xb1d3d146, 0x46f82b54, 0xf5f40f1e, 0xc455e012, 0x75b427d5, + 0x1b4a0c1d, 0x3d1b76b0, 0x6ce2cc53, 0x717a5a36, 0xc22b0574, 0xc2b96ca2, 0xa829cda8, 0xbfb2e615, 0xb921691c, + 0x8b54665e, 0x271339a3, 0x45c9fb86, 0xfcbaae24, 0x6be1ec1b, 0x5e97d9e6, 0x00f87bad, 0x10f265d4, 0xb7487dfc, + 0x9ba476c3, 0x2651a136, 0xf320cb30, 0x68ed32b3, 0xd4fbb332, 0x6a1fc225, 0x41c5fd7a, 0x75a59fb8, 0x1074fa18, + 0xeb02ae1b, 0xd99b5d14, 0x5ae5edfe, 0x180ae9a8, 0xf92acd7e, 0xe03b6310, 0x2609deb4, 0x02f962d9, 0x2e196a4a, + 0xe2b5f494, 0x9b410953, 0xc27e54fe, 0xee647597, 0x4982f3e3, 0x2c2a8cbf, 0x06eba59a, 0xab037aea, 0xe4e25c43, + 0x329b0b89, 0x9285e545, 0x9d29307c, 0xdeaca929, 0x85254c03, 0xde7034d3, 0x1391a718, 0x79041e7c, 0xcbcd3625, + 0x527f7850, 0x29b56c46, 0xb527cc10, 0x02acbac5, 0x3d4e0ac2, 0x584fa708, 0x8c79cf37, 0x74689d34, 0xa4685357, + 0x33393fec, 0xe6b98da5, 0xa98975c6, 0xf920a78b, 0xd62aacb8, 0xb68a8993, 0xa63d349c, 0x74dd256a, 0xea4189d7, + 0x1976adf6, 0x3c7a69e1, 0xc5a6914e, 0x1d293d95, 0x41e57473, 0x202c1cff, 0x3a5784be, 0x3c10d343, 0xec9c47ab, + 0x36d7a346, 0x43364927, 0x2d832621, 0x90dd300b, 0x41e2d993, 0x34705cd7, 0xdfbb3984, 0xb15a344e, 0x38a79b71, + 0x78207065, 0xfae170fe, 0x4784f0a9, 0xd9f260da, 0xac7243b6, 0x4272c7c5, 0x038812e4, 0xeb341496, 0x8d1e2f80, + 0xc7958946, 0x596d3461, 0x1268bf85, 0xd7c66002, 0xa9843888, 0xd3d82985, 0xd644047e, 0xd25e6d6e, 0x35bdf55d, + 0xac7e7edd, 0x636d0f13, 0xac8b0386, 0xb58f6d32, 0xec8cdf23, 0xa956bf23, 0xf5dc1fc7, 0x863384a7, 0x29d3d649, + 0x08b22773, 0xe7ae31fa, 0x4b206e2a, 0xc0ae9d1f, 0x1d45752c, 0xec4c3940, 0xd099a370, 0xe4c3a5a9, 0xdd8b6936, + 0x47d57236, 0x501d5550, 0x6ade0b62, 0x07cbff77, 0xf1626e2d, 0xc5f110b8, 0x8fa9bb0e, 0x2c6b5de4, 0x9433ec4f, + 0x2499a1e5, 0x013ca7af, 0x026b0c47, 0xb808692a, 0xc741b4f9, 0x5372d15f, 0x1603ef8b, 0x53a29544, 0xcda9c61d, + 0x90d5362a, 0x0e5474fe, 0x11cb0d97, 0xeefd9aef, 0x01096333, 0xda423361, 0x0b5ec41b, 0x4b3cf901, 0x04333457, + 0x1cba9ba0, 0x82c22960, 0xc3812e47, 0x09947ab7, 0x492b3c88, 0xc3df1482, 0x8b92e723, 0x88de6700, 0x6b8d7ae7, + 0x5e697b4c, 0x758a9f0f, 0xd8a4dfae, 0xb2f45aaf, 0x75d99707, 0x8ae59b3c, 0x5ddebde6, 0xc9da06a0, 0x45907d61, + 0x90defc35, 0xe5b26f33, 0x8df3870c, 0x57ce9eda, 0x0b2204e7, 0xe0f70321, 0xc1caa1a3, 0x6ea7bab1, 0xb65a018f, + 0x79783a9c, 0xa3ea1b46, 0x129b710b, 0x443ae4d8, 0x9dd91c54, 0xc4407280, 0xc487bb02, 0xabe91905, 0x4d18f81b, + 0x8c56364d, 0x5465232c, 0x8a77a474, 0xe1eac44d, 0xab219e0c, 0x23c7e347, 0xd11ad609, 0x28bd551b, 0xbf308f7e, + 0xdd4b419a, 0x61144e41, 0x793061a6, 0xe0fda99b, 0x92bb08d6, 0x1b10487f, 0x98478997, 0xd935516e, 0x72eb8381, + 0x98774656, 0x34eb65bf, 0xc1ba88d3, 0x2d8f7d8c, 0x74e80f62, 0xbdd1bd98, 0x9d5c20b2, 0xc7591e88, 0x20e28978, + 0x820ad63f, 0x73a77383, 0x87e4b51c, 0x5d13d728, 0x6ffd7aeb, 0x9b490964, 0x8c9bcf77, 0x675ee58f, 0x428c53f7, + 0x1cd79856, 0x61f73f5f, 0xb2078c97, 0xa970290c, 0x60d5885e, 0xe1bf9424, 0xc784d9d7, 0x5faa205c, 0x5f9e9345, + 0x713b145d, 0xd72ac2df, 0x4f11ee3d, 0x6799c44a, 0x8f9801d2, 0x5b53be4d, 0xa48dd466, 0x6c11e64c, 0xe950b85b, + 0x6d03912b, 0x29f3ba33, 0x79089aaf, 0x9159da91, 0xfb313d61, 0xdecaffa9, 0x1f0da900, 0xb07553c9, 0x8b92d802, + 0x61a7fb21, 0x0f2996ec, 0x6e2482c7, 0xaf0e6c98, 0xab79e95d, 0xbd098518, 0x2bf617e2, 0x4aaaf1d6, 0x2b52aef2, + 0x2b89e2e6, 0x7359069f, 0xe7a49c5e, 0xba9b4b0e, 0x5e6f4775, 0x375e60e0, 0xd6cd107d, 0xfa78b02a, 0x57cb6558, + 0xf0c74576, 0xa8cacd3f, 0xe7971414, 0xb2089528, 0xb6a2c919, 0x8508da96, 0x601da0f3, 0x4494d8dc, 0x37d2f68f, + 0x2ef5b3d8, 0xa6557a47, 0x31a03551, 0xeb5f2528, 0x90821cd3, 0x426de40e, 0x15e03569, 0xe472acb0, 0xade3ffe3, + 0xdcbeb9c7, 0xd00289c9, 0x9c86908f, 0xc5d21bef, 0x5247e789, 0x0858b270, 0x009d6f77, 0xe13ec0b3, 0x2382ec70, + 0xc690744d, 0xe6e91622, 0x46df9ef7, 0x47eb527a, 0x95e92b51, 0x445f3bc6, 0x19451e87, 0x55101794, 0xac768e77, + 0x6fc6adde, 0xf0517f7c, 0x67c6c8ff, 0x40251fa7, 0x5b158f2b, 0xa7aeafae, 0x572b27b7, 0x40637978, 0xfa945797, + 0x9c82aadb, 0x27f42078, 0xa460687b, 0x754eaa16, 0x2223715a, 0x1e902c6d, 0xa4c69ade, 0x561719f4, 0x6c7ac75a, + 0xaca90993, 0x0e2792ac, 0x4b856027, 0xeb532828, 0xa07c7f92, 0xf673e3b5, 0x564c4cd9, 0x34428751, 0xd2230ced, + 0x7b2b021b, 0xdc44b62d, 0x4dab25b9, 0xb7672dc8, 0x786fdeff, 0x93dc046d, 0x5a27b3f3, 0x8dea38a5, 0x7aafb180, + 0x0ad016ec, 0x5104f5fa, 0x18da90f5, 0x0ebcc7a7, 0x4ad1ce2e, 0xe374ff01, 0x927f62d2, 0x8a480f91, 0xba9864a2, + 0xd863bcf4, 0xd45488d3, 0x9070d4dd, 0x4b582f8c, 0x67fb5d1f, 0x210d583c, 0x9918b38e, 0xdd2adc2c, 0x18b28e8e, + 0x9a8ec6fb, 0x054595e3, 0xd7d63f0c, 0x90bc0cab, 0x66eef2d6, 0x53ff89d6, 0x3a1e9bfc, 0x24770592, 0x49370179, + 0x1b12a0c0, 0x27262b61, 0x921babb8, 0xa31fa69d, 0x2cad3a1a, 0xe0f2fe35, 0xb21c54b6, 0x253c39ba, 0xc862fb09, + 0x60848614, 0x323d8d14, 0xb610ea38, 0xc752c636, 0x5c75453e, 0x7f29e786, 0xd1815c3b, 0x185d6a3e, 0x0d782219, + 0xbe49ef48, 0xcbbe21dd, 0x32e41e8e, 0xe63119df, 0x1a519f79, 0xd8ba26a3, 0xd4ae4ef6, 0xb26217a2, 0xe8dd01c5, + 0x3527766f, 0x110132ba, 0x2736514a, 0x0014a771, 0x4c836728, 0xe057e13b, 0x2ee8a253, 0x021ccc96, 0x79f61041, + 0x97f23ff3, 0xc695e38d, 0xbcacced9, 0xf11356f9, 0xf72f60a3, 0x9ca22b4d, 0x51e99329, 0x015960df, 0x75e0dcc0, + 0x219376ca, 0xe8bc1c3d, 0x3e1b5209, 0xb1bb5aca, 0xf5e4c6b5, 0x2f8b3575, 0x29cd83a7, 0x3f9fc0d0, 0x2381162b, + 0xa01b461a, 0xb9a068bd, 0xefb56d6a, 0x03924ed7, 0x87a86dc9, 0x905ad2d4, 0x2ca9c07d, 0xd90a1fae, 0xd5c470ca, + 0xfc4f1ba0, 0x9f1c0692, 0x5fcd7b57, 0x59f38a9c, 0x35bd0df3, 0xba4e07b4, 0x3e2cdc6f, 0x9dc6c98b, 0xeba53b14, + 0xa1dbeaae, 0xb37a13fe, 0x4095c88a, 0x56de6282, 0x7d7a9af9, 0x86c2eb73, 0x9feed5c0, 0xa9619cde, 0xfe3085a9, + 0x39026b35, 0x6e8c8f5c, 0x855d5a13, 0x8e658bf4, 0xe1613896, 0xa6e5c5e4, 0x6c8893da, 0x9b4a7dee, 0x38e68082, + 0x1ce5f4bb, 0x0a2394b3, 0x0e9d575b, 0x79c146fc, 0x22a69095, 0xff1527de, 0xd62f052b, 0x8d588fe5, 0xbe1fbc3e, + 0xc871ebc5, 0x02314612, 0xdd5b4198, 0x9731d002, 0x92ae61d9, 0xa90e4609, 0x21fcd1e0, 0x07d0e2bd, 0x77da8c19, + 0xe3104244, 0x31d6cafa, 0x3bd73cbf, 0x263dade6, 0x2b3128dd, 0x94409695, 0xa97e18bc, 0x99a376e9, 0x2b239219, + 0x3899eb09, 0x42767dd3, 0x67e40762, 0xe467353a, 0xafe01198, 0xa76acca1, 0x5f257b22, 0x77318b5b, 0xc85c5996, + 0x4b677604, 0x24fbab57, 0x84c5c554, 0xfd3e1c91, 0x675094d7, 0x3e6eb7d5, 0x084a76af, 0x7493db60, 0xcd1417ed, + 0x9acf6d37, 0x118c429f, 0xc0dedee0, 0x26506c7f, 0x86a65e4c, 0x79873dc0, 0xa43dc7bb, 0x53f40a3b, 0xf07dec48, + 0x1713a5c8, 0xc733faab, 0xe71c46bc, 0x194f529f, 0x13af1221, 0x6a7fc9eb, 0x06b4e170, 0x83aa6af0, 0x6a6edbcb, + 0x375092d0, 0x50656cfc, 0xcdfc9858, 0xd4522561, 0x4753f949, 0xaafbcf70, 0x5f9f96f2, 0xa1f05c12, 0xd3cee8dc, + 0xbf3912e0, 0x5aca56b5, 0x14e22839, 0xf5ec60ba, 0x8edb6a74, 0xeb0a0fe6, 0x9a35e0bc, 0x72b2e29f, 0x10abb213, + 0xa1d9e027, 0xcbf2b205, 0x40f5e2c2, 0x7c3777be, 0x2deedbe0, 0xe56e764e, 0x7888a4ce, 0x2d8416a4, 0xcce32db5, + 0x6a553b17, 0x6035e635, 0xc62219d2, 0x03fe2284, 0x948b731a, 0x2603530b, 0xf32efd36, 0x544508b7, 0x68cbf615, + 0xbc7ea8d0, 0x3a6fa3c5, 0x5e7afef0, 0x2fb868f9, 0x233ec7bd, 0x37ce2c5a, 0x8f367046, 0x2127dfe4, 0x687fec0b, + 0x086abf2b, 0xed819f27, 0x3feb599c, 0x889f3f60, 0xd94a50a8, 0xbcab7509, 0x5921538d, 0xa83048af, 0x63bf87e7, + 0x5fcc388d, 0xf5953c51, 0xf5387b7d, 0x05b5f27d, 0xddebeb54, 0xe4d5da4f, 0x8443eb1b, 0xddc034ee, 0x25a3120f, + 0xd97badd5, 0x5efd094f, 0xca91b439, 0xe1eb79a3, 0x899d88bb, 0x694439a2, 0xb5c3578c, 0xd3f236e3, 0x390838be, + 0x3414c796, 0x51eb6ada, 0x1ca92d0d, 0x6fbe93bf, 0xbc86e099, 0xf291e1b3, 0x71cd11f5, 0x495703ac, 0x3d44882c, + 0x7396d059, 0xc7e4ea1a, 0x05857406, 0x475d1ebb, 0xc327621d, 0xcdb74a06, 0x8c6404b7, 0x60e1ee0a, 0x8f557f2c, + 0x078c3733, 0xe7740b30, 0xedb78226, 0x663ee8c7, 0xd292b259, 0xf30cc85b, 0xd0012803, 0xd4897f48, 0xe1e44edc, + 0x6af3f2bb, 0xc29463d7, 0x3024a03c, 0x1584f8fd, 0xc18c155d, 0xe7d29e42, 0x441dec44, 0x7826f0c2, 0x2556f9e1, + 0xd3ce1598, 0x3bf73a2f, 0x28fa5e0a, 0xf557681f, 0x57c04fa9, 0x6890a852, 0xb47bfd60, 0x8b091950, 0xc5b4ac00, + 0x29139aee, 0x89b6155d, 0x7c3c8684, 0xc38fce63, 0x595fec02, 0x1d810765, 0xb71185c0, 0x0e1f4e9f, 0x46279d43, + 0x51b00b6a, 0x3e678462, 0xa5b70d8c, 0x705be65f, 0x7fcee956, 0xdcfa642b, 0x4daa9d1d, 0x7f7932a9, 0x8aa13720, + 0xc904061c, 0xb03674a3, 0xbff9d33d, 0x581c48f0, 0x9d1a4a6d, 0xbe5eda5a, 0x83e06220, 0x783c11a3, 0x9dc646d7, + 0x5e1245ea, 0x0c93d72b, 0xd2eee20b, 0x463f5213, 0x6b2945e1, 0x86c81f5f, 0xf98032c1, 0x014704ef, 0x59c19e23, + 0xdfefdb39, 0x8b1598cc, 0x57ddd838, 0x0c3c312d, 0xc0874944, 0xee54421b, 0x3c4c8585, 0xf5cbc78c, 0x72615240, + 0xe9e445fe, 0x420ba106, 0x179a2785, 0x3150fd26, 0x0048226b, 0x1e4ae54e, 0x0aa255c1, 0x80e87250, 0x78d2a733, + 0xf1a8a9b6, 0x2dac0e13, 0xa573992e, 0x8672668f, 0x671f8c0a, 0x99fba642, 0x875c0176, 0xb387b922, 0x75cd869c, + 0x7a30f620, 0xdc138ec4, 0x85429ff5, 0x665b2ac3, 0x8a5c8d3d, 0x2171d49b, 0x887f6fc2, 0x6ce8ba14, 0x70aad40d, + 0x221799fd, 0xd50faa98, 0x88e84676, 0xb61c8c54, 0x8a9689e8, 0xc443ae75, 0xd6b71624, 0x55ba6be9, 0x58bce1d7, + 0x1a82e6b3, 0x8cb29ee5, 0x5e55b40c, 0x189deda0, 0xc59e8547, 0x53f8151e, 0x71231851, 0xbf930d7a, 0x1caa5d93, + 0xb29e130c, 0x5a99040a, 0xe986c387, 0x698a5a56, 0x308da8ba, 0xd2bccee0, 0x8c6b7c87, 0x2dd0524d, 0x1ec40a38, + 0x73ec08c2, 0x179f8a35, 0x577bff31, 0x4aa584a3, 0x598abdf5, 0x86a79cc9, 0x088e3adc, 0x3d905fe8, 0xf8f7c3e3, + 0xb05331d3, 0x340fae86, 0xdb9afe65, 0x8522db2a, 0xa67b0d35, 0x0e9bdfe0, 0x572c4acb, 0x60dcd79b, 0x1af6fa32, + 0x0dfc51d9, 0xf0cfd75c, 0x431d78b5, 0xa140a369, 0x9e1be2ea, 0xcaab1174, 0x7f6652b9, 0x7ade1def, 0x6585a904, + 0x8c2511d0, 0x4e367c92, 0xf427d0cd, 0x2c46bb4a, 0xe911aa84, 0xd5a54d9c, 0x69131a8f, 0x86ea7e6a, 0x2599bf02, + 0x2d5b1514, 0xed66f763, 0x3ef6e947, 0xa03318cf, 0xbe6a62d4, 0x3954187e, 0x523f5ae9, 0xefca0f50, 0x2b407ab4, + 0x45770b9e, 0xa462b6d7, 0x6f662aa9, 0x6bb0c447, 0x5a374c76, 0xc21bf471, 0x65a18de8, 0x7292afc7, 0xe2e27aad, + 0xb5830a43, 0xa8ffee6a, 0xd325ee60, 0x3e528264, 0x0f304c7e, 0xf1acea0e, 0xf6cf5aa9, 0x620568d2, 0x0d4cc12e, + 0xc49a7205, 0x57e5cd3e, 0x77f79f69, 0x4ca3ace8, 0xfae41154, 0x80c38856, 0x7ec5ffd8, 0x709b423f, 0x3f9eda89, + 0xb4857b0f, 0x7c75ceeb, 0x2f97396e, 0xa3be01a5, 0xaaeaf160, 0x5e222c4b, 0x0166903a, 0x8a292afe, 0x40b4a2d5, + 0xd0650101, 0x5911e310, 0xdca17135, 0xf47ee2fc, 0xac46452d, 0x866928db, 0x63df127f, 0x343b69a2, 0x04687e2a, + 0xc19efe03, 0x8b2f19e9, 0x205a3ef4, 0x304c389b, 0x7a29d434, 0xd3fdee4e, 0x73491631, 0xdde24dda, 0x9d79500b, + 0xbf9a1db6, 0xdfd80cff, 0x8e6d53af, 0x1c80aaba, 0xe6505434, 0x24a3d75f, 0xfb69d8a3, 0x1ec420f4, 0x33e5f8ff, + 0xd84363c3, 0x6f829742, 0x20bd2b93, 0x0190385f, 0x70f4e910, 0xa84bfbf7, 0x4692a9c3, 0x9832adce, 0x6d48a07c, + 0xd42e20f1, 0xa1d1317c, 0xe8c900b6, 0x1d51fda2, 0x9017bb44, 0x611e515b, 0xca8473c5, 0xb9343900, 0x9cbde904, + 0x3a01d62b, 0x7b3afd32, 0xf0e77739, 0xc246b60d, 0x7882e3b0, 0x004d32ac, 0xca1246f9, 0xc4112afb, 0xbe5711dd, + 0x4b854659, 0x02d9ea60, 0xf699f883, 0x5c025a54, 0xf6b636d8, 0x75dc3127, 0x245bc043, 0x4427a9cd, 0x219aa818, + 0x13e8a890, 0x1c35ee3c, 0x7f74bd6f, 0x732a55e5, 0xe50be884, 0x83fd0ba0, 0x0ecf1956, 0x4b7b8a02, 0x6e06d6e3, + 0xccb2272a, 0x6e36b78d, 0x82af551a, 0x3447aa51, 0xc487027b, 0x256e3288, 0x3467d296, 0x52b3b641, 0xb969dbc0, + 0xe61986ae, 0x98eb8f4f, 0xd83419d1, 0xd622fc50, 0x2df968bb, 0x73ec9877, 0xc1cdeaa9, 0xa65581eb, 0xb2c4ddb7, + 0xe377d078, 0x39466727, 0xe1362e77, 0x8fc14f0f, 0xc1c45a15, 0x8293616f, 0xa154cac5, 0xd7573649, 0x0c46280f, + 0x230bdd4e, 0x87c5e270, 0x0ee8892b, 0x61cc4c35, 0x2f6df8e6, 0x192670c8, 0x14b3d418, 0x8cfcc4c0, 0x68d941da, + 0x9d401af4, 0x560fdc52, 0x362244cf, 0xf91f16c2, 0xe58a7023, 0x5deb62de, 0x07deaa8e, 0x51880a6e, 0x4924590f, + 0xde3d7af9, 0x8eb5c683, 0xe92aeeb0, 0x2ec07df1, 0xe48d0786, 0x42a45e89, 0x96184835, 0x89539d9f, 0x93802d9c, + 0x1831fdae, 0x35a5cc72, 0x222661c3, 0x146c64b4, 0xf4a99f73, 0x9cbdd405, 0xb11f1ec9, 0x20b60edc, 0x3a34855e, + 0xd1710ab3, 0x39de8fc3, 0x5a892022, 0xd8dad971, 0x646a7b59, 0xfaac6474, 0xd385037f, 0x2941c288, 0xcff77cd6, + 0x87f91471, 0x2c4648da, 0xb16d0efa, 0x4385eb5d, 0xe1e9ec4b, 0x0728bad5, 0x38104b49, 0x6623c9ea, 0xbddfad59, + 0xfb8a8b89, 0xd52cd088, 0x87d8433c, 0xbde9961e, 0x15ac6408, 0x917aa8c3, 0x2f145d64, 0x0f4dfc10, 0x194f33f0, + 0xd59ca855, 0x046cf51e, 0xf92d7978, 0x8bba2025, 0x236c0ff5, 0xf3bfab88, 0x07cfa524, 0x1a64c4e3, 0x750afd20, + 0x18c6f505, 0x3e51e2aa, 0x0c0e163a, 0x1bf99fdf, 0x295918f5, 0x44cfcff9, 0xd83e769a, 0xc2aae940, 0x504895ac, + 0x38f02821, 0x2febcd28, 0x650ac971, 0x40fa0b70, 0x96133e8d, 0x11a6d004, 0x052b83a8, 0xfefe2287, 0x304e1cb8, + 0x4c715ad2, 0x53caab8b, 0x3cd30ce1, 0x9bdfb1c6, 0x465984a5, 0x7601ab95, 0x16d0c783, 0x92d7fb88, 0x8510c0b6, + 0x44d397ab, 0x90ccfeee, 0xb9906c46, 0x92051d06, 0xc8129b59, 0x3e858b01, 0x2d51493c, 0x983aeb50, 0x8e55a0e2, + 0x2ac892b2, 0x06807edd, 0x16230c35, 0xa965167a, 0x1d29d4ea, 0xdc7c38c2, 0x71c44109, 0xd10a91d7, 0x5a8bf5f5, + 0x1f5197eb, 0x9897af35, 0x652be01a, 0xadb599e6, 0x694959f2, 0xd944aa56, 0xc474911d, 0xbf2bed51, 0x115d6649, + 0xdff04efc, 0x8cb461f8, 0xe4519551, 0x1fa6efbe, 0xf2ebd9ba, 0xc0aa262b, 0x7155d22d, 0x43d6e0ae, 0x25a79224, + 0x62a8d61b, 0x54c1f883, 0x3dbf9b8e, 0x45e3a30a, 0x7670e2c8, 0xba3ae3fd, 0xf767d885, 0xc656be79, 0xf695be00, + 0x5085edd0, 0xd6911c27, 0x7e5e6f0d, 0x2841475d, 0x98da7cbd, 0xf3c1e79c, 0x99ad4628, 0xa972e294, 0x7ca14df3, + 0x256473e8, 0x564e816d, 0x83ac06d8, 0x6b3837fd, 0xb3519e2e, 0x60e3aac9, 0xa530d471, 0xbc01bdcc, 0x97843937, + 0xd72388d1, 0x59b3572a, 0x743a023b, 0xe9b9c3f7, 0x227d0435, 0x97ae513c, 0xf84f5876, 0x393101e6, 0xa0db523f, + 0xf367382c, 0xc0177ef4, 0x3f365e00, 0x2e3f68ff, 0x0070b044, 0x14c2dcbe, 0x1dfe0eb5, 0x12772508, 0xcf74b7fe, + 0xeccf02b3, 0x025ef56b, 0xb9b087a9, 0x26740438, 0x30dc48a1, 0xbfb49961, 0x107d47c2, 0x17de87c0, 0xdb805767, + 0x2fa506a7, 0xb01d6538, 0xf4e491ad, 0xa0812f73, 0x67cc9dd7, 0x12f7e343, 0x7aa67a6d, 0x57818936, 0xc9a6227f, + 0xc74916f4, 0x0da2eb67, 0x77c81a25, 0xa8ac3eeb, 0xe1dd85cc, 0xc0c012e9, 0x845a67e7, 0x5d5739d8, 0x4fb751a3, + 0xcedc225d, 0xa13beb0f, 0x43329f1f, 0x3c8a499c, 0x67a6bd31, 0x8af84ff3, 0xec6b04e2, 0x3a6e47ee, 0xc2be3e03, + 0xbc6f5f47, 0xbf658438, 0x1714f1c4, 0x5cb0cffe, 0x5cc9648e, 0x3f368d1d, 0x8b27cc27, 0x6780f615, 0x7254bf63, + 0xb766483e, 0xe6a69b7c, 0xd716f1e5, 0x4097c81a, 0xec0b67a8, 0x341672ec, 0x6dbc2197, 0x06d5f7e3, 0x803fb1cd, + 0x1a13a330, 0x1c8d9b53, 0xd65d0ed7, 0x14fb3128, 0xd9051572, 0x73b9523f, 0x7ac808d0, 0xb697f434, 0xc5c60ea1, + 0x5c511f34, 0x6df9d59f, 0x87247a59, 0xda2fa08b, 0x3d5541f2, 0x2d11ecd0, 0x5c6fa7c8, 0x49651658, 0x80433303, + 0xc352c72d, 0x3b728341, 0xf8f9a6d7, 0x06f9ce96, 0x79e5c704, 0x00bc2f00, 0x9a55534d, 0x36497293, 0x412930d6, + 0x8a0d8c12, 0x3e27c2ae, 0xf39550ac, 0xd3f4ed45, 0xb7dcc191, 0xd7bc5d99, 0x16e2489f, 0x00563e27, 0x49c9f6bd, + 0x6a00f930, 0x4e6c70c0, 0xa574406c, 0xeca43a9c, 0xae780648, 0x892fdc08, 0x3732e4e4, 0xa69b1a10, 0x63fbfc27, + 0x927c4906, 0x37bba512, 0x6df2d8a7, 0xd1fed0e7, 0xca7495ca, 0xb6392c28, 0xdedcb181, 0x79abd84d, 0x719f8e0a, + 0xd4a8728d, 0xadc81e8f, 0x42aed309, 0xd0ac5b4e, 0x4b5df1cd, 0x6b98d556, 0xa6519b8c, 0xdb103d6f, 0x0a689840, + 0x10d686a1, 0x904229a2, 0x7c5f0b5c, 0xed3c8261, 0x1f212d3a, 0x86acf0ef, 0x6ad4def0, 0xcd90511f, 0xe41b54c9, + 0x0c5f6557, 0xacad9143, 0x15c08a50, 0xc8de34bc, 0xbe70bd31, 0x40405b43, 0x0deb24b4, 0xeeb750d8, 0x491f283b, + 0xa71359a8, 0x16eab99e, 0xab77be92, 0x21eec74c, 0xdc857e0d, 0x7753f16f, 0xddf687ad, 0x784c3627, 0x93459eb9, + 0xa1bc4b1a, 0xd232562a, 0x5580d6f1, 0xf274f132, 0xa067e24a, 0x9bf6fd6b, 0x9b4b95e8, 0x2de3ae60, 0x79a5d850, + 0xfa90882b, 0xb4608851, 0x3af3d9c0, 0xa0fb4887, 0xf0ae832b, 0x8d306809, 0xd798ddd7, 0xd3268a13, 0xa6e62b53, + 0x80f4f29e, 0x40ed9af6, 0xf6a768f7, 0x0d96b775, 0x162ce0f5, 0xb1022d71, 0xa0586f04, 0xcaab63bc, 0x465f9e5d, + 0x65f0f3f4, 0xc67ceb27, 0xb67dc737, 0xe5f4e1fe, 0x63eb904f, 0x292d343c, 0xa50ff5d9, 0x002cd68e, 0x4cb0ecdc, + 0x3218aab3, 0x645669c1, 0xcf91bab0, 0x7da8b9f9, 0x4da09097, 0x2c0a573b, 0x2bb008b3, 0x91939b14, 0x5ecf1bd1, + 0xbab00271, 0x18f3680a, 0xeee138bf, 0x624c5fe8, 0x593b2fcb, 0xfefce7e6, 0xb4458713, 0x1ecbda14, 0xbc7bfbf2, + 0x37732ae6, 0x3efd1550, 0xf2aafe3b, 0x5f69709a, 0xc21118ae, 0x13949fcf, 0x04edaecb, 0x1c14a028, 0x498684dc, + 0xb3abdc46, 0x38ddc114, 0x6cbdc7fe, 0x144a2053, 0x40ba2fa6, 0x2909a6f1, 0x3dbdf890, 0x57524446, 0x818e975b, + 0x9231a770, 0xe7682395, 0x6ca3935d, 0xe6d7293c, 0xb1ae0110, 0x5692aeec, 0xe4d48af5, 0x20e75263, 0x2a7f691e, + 0x422aa033, 0x8e3454bd, 0xfa9cc2ae, 0xf63f3478, 0xc2e689b1, 0x4a55de9b, 0x4a409e85, 0x8e4ffb5c, 0x704cd89c, + 0x9dac042f, 0xa728e880, 0xe660f4a4, 0x4d626570, 0xdc36c081, 0x17bd1a00, 0x77921346, 0x0da3dce7, 0xdb3e1b0d, + 0xb8e17bf6, 0x868df787, 0x3955ade5, 0xc4af6e78, 0xcc8b0029, 0x3875428a, 0x42986404, 0xca1b40d8, 0x6f4b7d0d, + 0x78ac8e0a, 0x9d888d80, 0x1fb70436, 0xb1577d66, 0x8781a497, 0x8a2296fd, 0x9e28c2af, 0x68ecefc7, 0xcfd1e85b, + 0xa1e82fff, 0x626ab023, 0xf210bd0b, 0xce146394, 0xb3f17e44, 0x7384ebe4, 0x5d319ab8, 0xccb21228, 0xaf9c3a7a, + 0x3107c1bc, 0xfb487f69, 0x1a67b575, 0xbda50a82, 0xa9940e18, 0x8de1ac76, 0x31f29d9a, 0xafcc2878, 0x8c4f2699, + 0x858a6a5d, 0x4bd361dd, 0x03ad3f14, 0xfbbb27fd, 0x1a9ba089, 0x80b02a92, 0xaa72fa3b, 0x1aef7145, 0xc79cb8d8, + 0xc1a518cd, 0x3087ea31, 0x9a979419, 0xd959d4e1, 0x69f88525, 0x551d091c, 0x53167ca4, 0x33e4340e, 0x4afd3c4d, + 0xf281f8b9, 0x3729d820, 0xe6664897, 0x1c763195, 0xb5ebe7ad, 0x93e3e98a, 0x2fe5e89e, 0x2c0b617e, 0x299a5051, + 0xf74b0710, 0xd5887865, 0xa465832b, 0xa547eb09, 0xd8bc3c76, 0xf30e79af, 0x66a91b98, 0x33272ca6, 0x7567366b, + 0x4aa4b1ba, 0x711c85f1, 0x75ed0a32, 0x83356f8f, 0xbfd4f076, 0x6f7753e8, 0xbbec8210, 0xcf9bc0a3, 0x15867076, + 0x791de324, 0x9ae7a1f0, 0xcd3fcddc, 0x1598e9c4, 0xf0d2d636, 0x27816339, 0xb0f23353, 0x16a65b69, 0x559a9130, + 0xb07150d6, 0x650fb336, 0xbdb8dfad, 0x680debbe, 0x9e9e97eb, 0x036b0af8, 0x39878d6f, 0xb97f4656, 0xef870a9a, + 0xe5c37578, 0x86128219, 0xfed9cef4, 0x1cb2728e, 0xe000bacb, 0x5751600e, 0x94150684, 0xb524ba88, 0xedc95aee, + 0xe3900d1f, 0x6e84b4af, 0xf85827b7, 0x11fa2681, 0xa845eeeb, 0x2cfec940, 0x5198eaf3, 0xa01309be, 0xdd968b28, + 0xeed57463, 0xbccf4ab5, 0x32933f5a, 0x545edc2c, 0x2596c2cc, 0xb09f771e, 0xb55d7fac, 0xd3a48a69, 0xd54a6faf, + 0x4ab7fd8c, 0x3175fd72, 0xdf741a1b, 0x1791aa07, 0x80827fb4, 0xe1f3a1c7, 0x0208eb65, 0x05bc545f, 0xa27e0a77, + 0x19a5a0bc, 0x35b89136, 0x82a995ab, 0xb836a9c7, 0x682769c3, 0x8cbbbda0, 0xa70995d1, 0x93d69d6d, 0x2a5406d6, + 0x37961c53, 0x83f785b0, 0xc7c4567d, 0xeed03e73, 0x92d9d7f1, 0xe6652369, 0xc9961a03, 0xcb4e28a9, 0x598e6960, + 0x372b6279, 0x7bf5aa52, 0x9450f435, 0xdd4cb9a2, 0x54228417, 0xc69c25d0, 0x61be49ff, 0xf6fc3761, 0xb7d7fe27, + 0x49df7daf, 0x946ea718, 0x698ee290, 0xc3ce7a5b, 0x90620c99, 0x18f502d5, 0x7516dc0a, 0x04eacf09, 0x389b4c51, + 0x92678fee, 0x87f98e1e, 0xf8f8691f, 0xe7febe16, 0x97827449, 0x0bf494f7, 0x41e23106, 0x8af088f8, 0x122f336d, + 0x57b94dd2, 0xe8912916, 0x5d871d3d, 0x7674d410, 0x04ab69da, 0x628e2860, 0xca77b572, 0xfcabc34e, 0xca61e933, + 0x381ec8e8, 0x83517d11, 0x2c2bfe6d, 0x96939d4c, 0xd058a528, 0xa3cacc79, 0x721332fd, 0x297e6fba, 0x05050131, + 0xca768fad, 0xae75dc1e, 0xef6770a5, 0xe25faf3a, 0x2ab04b0d, 0x1f3cd497, 0xc4bd1537, 0x19c2de6e, 0x760f55e4, + 0xc892ebd9, 0xef51ba6e, 0x573354ad, 0xeaeace05, 0x8e8ac1d4, 0x3835a622, 0xf6995297, 0x3f0ca336, 0x1a22662d, + 0xbdeddc65, 0x80d49423, 0xf86d790b, 0x1889b468, 0x21fc77d3, 0x6923b6f0, 0xa76e39af, 0x9e094b5e, 0x87f5f385, + 0xa9277735, 0x68d18afa, 0x3c73c2d5, 0x4d102fa4, 0x1282bb5a, 0xdd216cb6, 0x445830f1, 0x849c975d, 0x19d3120d, + 0x1300e85b, 0x251d1b6c, 0x4a260c7b, 0x7f931809, 0xfb77a409, 0x59fb13e1, 0x1107b778, 0x4a9f944f, 0xedbe4758, + 0x9cd20a7f, 0xcdc81bb2, 0x7a40d414, 0xdcc99102, 0xb19bc3e3, 0x76761235, 0xb5255406, 0xc8fe7e7c, 0xe233e12e, + 0x30d35bae, 0x42b6b811, 0x4df2fa0d, 0xf3699592, 0xf2660945, 0x9a5d6e42, 0x8b9240ed, 0x70e232c2, 0x8b8e8493, + 0x05e1a1fb, 0xa01aa377, 0xf1926050, 0x3e2faf96, 0xe00576e8, 0x9de30671, 0x7fc56ec6, 0x7e04dbd1, 0xae4a3958, + 0xa68da494, 0x72d1d12c, 0x6c700363, 0x16bedfac, 0x245bfd07, 0x78af3ae1, 0xb212b27c, 0x318ef732, 0x8c1c632a, + 0x23b93911, 0x6eb25273, 0x395fed06, 0x6c87eae7, 0x5074d18b, 0x4611ff9e, 0xb4f7e7d2, 0xeea58abc, 0xccf346e3, + 0xa4a967b8, 0xcd3f1a8a, 0x12899308, 0x578fa751, 0x494e81e4, 0xbf75a2eb, 0xe96be93a, 0xcd270026, 0x86698132, + 0x781f4ac6, 0x0dd6816d, 0xa172cc6b, 0xd24e1920, 0x48a762c9, 0x133dcb87, 0xa99dc3b5, 0x9cf3e48c, 0x23f7d122, + 0x3a07ecef, 0x79f6d059, 0x1f8f403d, 0xaabcf988, 0xbcca2a46, 0xcd7d36b1, 0x0cbd715e, 0x1efd6d42, 0xa950ee31, + 0xd2956d74, 0xcc4a117b, 0xaefa1ca7, 0x3e8ac15c, 0x68186bd1, 0xb5fff7d8, 0x3b5cfbda, 0x55453d63, 0x6cd595d0, + 0xd6c7acd6, 0xede4f703, 0x1e3a81b1, 0xc5d0dbfd, 0x551d68ef, 0xf893db24, 0x8f97acec, 0xdd0b7e65, 0xfaa515fc, + 0xcb5130c9, 0x60741729, 0xc68d34eb, 0x6f32ff4a, 0x24b7a71b, 0xccce40dd, 0x5efdf81f, 0xcd5f0624, 0x16d9870f, + 0x45f37c10, 0x4951ce5c, 0x39e94d76, 0x5d3d6754, 0x36565345, 0x44271ccb, 0x4492cdaa, 0xb2fe50eb, 0xfcf53c1b, + 0x6095e2d3, 0xd61414de, 0xc8361f07, 0x67434c92, 0x62db3e62, 0x9e35d3e0, 0x294af5a4, 0xd5f0c222, 0xb584e27c, + 0x37384fdf, 0xba199693, 0xdb7284ef, 0x874bb865, 0x71f8c674, 0xed33ab3b, 0x609b6bad, 0xb37b1213, 0x98dabf78, + 0x987fc41d, 0xd831f5f6, 0xcaaed9b0, 0x479959bc, 0x2dccaf8e, 0xb30c8436, 0x1877637d, 0x3673f319, 0x524a25e5, + 0xb5158f92, 0xfc51e49e, 0x025fc853, 0x50c9eb01, 0xce91256f, 0xed82370b, 0x9e9dcbf4, 0x9532424f, 0x570b66c1, + 0xa8deb7bf, 0xc4222cfe, 0x511220ec, 0x39235078, 0x32f6ea71, 0x62c97087, 0x209a9d7b, 0x23bff470, 0x132362cf, + 0xca78aff8, 0xa1def2be, 0x84a0d09f, 0xb5912447, 0x8a91a18e, 0xf7e5b835, 0x06224d13, 0x1163776c, 0xcc530dbd, + 0x101adeb8, 0xb12796e7, 0xf04304b2, 0xc9c4d766, 0x62920b14, 0xe382d5d2, 0xbf685cdd, 0xca3b2214, 0x2c9f110a, + 0x561510f0, 0xf98c7107, 0xdf235897, 0x42ae8b76, 0x3b27052d, 0x97597934, 0xa2a47390, 0x142777f7, 0x0fc1cff2, + 0x3527fa32, 0xf5f2cdbb, 0xa4e02866, 0x3fe63ca3, 0xa6458bff, 0xb8f03151, 0x658a2848, 0x31bdfb29, 0x425c29c8, + 0x422765a9, 0x7fffc63e, 0x1c573c30, 0xd9fa7f45, 0xb422ac76, 0x989134af, 0x9e2c67d7, 0x5e52ca38, 0x26ce32c8, + 0xf337c185, 0x26641721, 0xace6b96c, 0xde07a59e, 0x8fa76286, 0xc90b2e52, 0x30a7f18a, 0xa8407851, 0xad74aa26, + 0xfba2ede9, 0x9f574507, 0x2e6ff4bd, 0xcaad6671, 0xa1150b30, 0x9618c56a, 0xe52ef87a, 0x32c3de16, 0x1b0c411b, + 0xe3803677, 0x6d26f64e, 0x8feaa1ac, 0xe2a4b1f4, 0x5234e908, 0xe6abf56e, 0xf91ca963, 0x0082da6e, 0xcb3a148b, + 0xd6582ac0, 0xc7aef95d, 0x751e67b5, 0x3e945939, 0x1f3bc140, 0xc5745ee5, 0x072b0948, 0x0787d0e6, 0x774ebb19, + 0x5890986d, 0xbf2fdc8c, 0xd9b42f29, 0x374494d7, 0x30658b8b, 0xe6330cf0, 0x7ad8b17e, 0x806576e6, 0x8f49a1d0, + 0x1e50471a, 0xa5bd56fa, 0x49909999, 0x2e79b29c, 0xd8beb743, 0x5e61cb2f, 0x164d61ea, 0x7ae86da9, 0xb119c5c7, + 0x4a5d07ae, 0x76ceb918, 0x4aed5275, 0x56b241fc, 0x14fbe59b, 0xb2d0de09, 0xec7138b5, 0x1091577a, 0x15adb7c6, + 0xf6490aba, 0x2446ce47, 0x50534466, 0xfd712438, 0x69ccbf9c, 0x7e81d5d5, 0x5fc38812, 0x21289088, 0xa251a853, + 0x41a456bc, 0x391d27db, 0x507600e3, 0xf3214f52, 0xc18fce67, 0x9bc8dd54, 0x0eb98ba7, 0xec45bb64, 0xf28df3b9, + 0xdcb286ec, 0x714f9c8f, 0x50dd3a79, 0x70687298, 0x88d4f2cc, 0xc117e04e, 0x35abdf35, 0x3f10d635, 0xa9bc3bf9, + 0xad7621be, 0x9504558d, 0x6e56548a, 0xa9f612b3, 0xcbffa798, 0xff7bf518, 0x134287bd, 0x6e6e9ad2, 0x19b948a8, + 0x584344c4, 0x4c076a16, 0xc4782a19, 0xfebbf8fb, 0xde453afe, 0x770f71bc, 0x088d2e3a, 0x2c1688ed, 0x8239d813, + 0xeab566a2, 0x84c05853, 0x900b10d4, 0xc174b5ce, 0x072c0cbd, 0xaf42d9c7, 0xd1b57ad5, 0x3d1640d0, 0x4e352753, + 0xb2956daa, 0xaed057c3, 0x4ec9e19b, 0xe5262aba, 0xe2ba99bf, 0xa3b8e2e6, 0xd3a538b2, 0x1c5ea938, 0x6ded9dac, + 0x4168aa81, 0x9a4db701, 0x133b9dc6, 0x8d0c7e0a, 0x618d9332, 0xd798b702, 0xc627cef6, 0x51b6aae3, 0xb760e6b7, + 0x1046783d, 0x6edf6364, 0x169dadb5, 0xd89bdbb1, 0x9adb08e6, 0xf62c2be0, 0x069e55cc, 0x70727db1, 0xd2e9eb17, + 0x6bbcde98, 0xcdbd7172, 0x0cf2ae4e, 0xe55858ac, 0x13f2ac0b, 0x2c914ce9, 0x3317906a, 0x87a0829a, 0x6d721eff, + 0x6f5d808b, 0x5d310816, 0x85bf89c0, 0xa6978b19, 0x95f4ca09, 0xb18da60b, 0xfb4dd63f, 0xbcf3837f, 0x1343a9e5, + 0xb3a2f787, 0x0668e4d8, 0xb35ce7e9, 0xc62a77f3, 0x29e51a05, 0xd2870bea, 0xed9ea313, 0x18848e37, 0x860e9281, + 0x210992c7, 0xd21460ff, 0x21c7fa6b, 0xb335a597, 0x37c30725, 0x7869235e, 0x77eee6f0, 0xeb58fa9e, 0xcee79762, + 0xd23de9d0, 0xe463fe09, 0x63633077, 0xc9a51bfe, 0xcab80c15, 0xda62b45e, 0x43c48710, 0x2b463e8c, 0xc4c6e5bb, + 0x9dc436b9, 0xcec3e307, 0x2dd51041, 0x502759f0, 0x8669a031, 0x83dd3322, 0x81f7b4eb, 0xcdb40b65, 0x141ff628, + 0xbfda9798, 0x39f38867, 0x9a93c9ed, 0xbc63131f, 0x7ce5c3a3, 0x15494443, 0x4ddf0e79, 0x75984776, 0xa49366b5, + 0x53296957, 0x405d51d4, 0xa4ef37da, 0xf6aeaa63, 0xc8bc3374, 0x9853fd50, 0xd2537d6b, 0x717eb9df, 0x1a4834f0, + 0x25f06f68, 0xe5bc504d, 0x7b330d65, 0x62e48fd0, 0x61b87e31, 0x54ff26de, 0xa20cb91f, 0xcfd82ac4, 0x99370178, + 0x3a48db92, 0x885aefc4, 0x3d25259c, 0x06cc95a3, 0x47545ca4, 0x91d02319, 0xcf675f32, 0x67430080, 0x3f70b219, + 0x5fb7181c, 0x16f3d44b, 0x5035ab7b, 0x71d9a297, 0x7fadd279, 0xd084eefa, 0x8bb6a620, 0x2907f1d0, 0x783aef4c, + 0x7d2f6764, 0x97e729ee, 0x17cb9fc6, 0x7f5a2dbf, 0x44121ff8, 0xa89258c7, 0x380ee94e, 0xcf6ab93f, 0x3e141e72, + 0xfcd4f1c7, 0x534ebaca, 0x10f8056a, 0xd12218c1, 0x1226d04a, 0xe5e130eb, 0xaf179f9f, 0x8a4566a9, 0xb3f20bf9, + 0x94fccb5f, 0x5588d0c3, 0x680566fc, 0x21be4f4d, 0xaa6d71ac, 0x2797ce5a, 0x9a3b6134, 0xbc962ec8, 0x6b2c6959, + 0x11bdbfc2, 0x34a46331, 0xd140d217, 0xaf8172bc, 0x6c7e3938, 0xf06eb461, 0x58db7488, 0x05c9ee68, 0x72c00f95, + 0xd107f75d, 0x27e85442, 0xc2bd3c54, 0x46f04a44, 0x1041ba00, 0xc6f13afc, 0x0a55f672, 0x8f2fb7f8, 0xc555eaf2, + 0x798cc7f0, 0x15421162, 0x4179d8ef, 0xaa7265a9, 0x9b9b0c54, 0x9c900e45, 0xfcda2704, 0x214b8a17, 0x4d2c7e4b, + 0x66258a9a, 0xf285d50b, 0x41b3b5c5, 0xd7b978af, 0x5cf9f1f4, 0xbb91e463, 0xfd60b5c0, 0x8248aefd, 0xf06e64d6, + 0x7b10800f, 0x43bcee34, 0x0d5c5f60, 0x2a1fab7a, 0xd75b88eb, 0x499f32a0, 0xc49554bd, 0x7d25a4f5, 0x868853be, + 0xa3d5680e, 0x4674d134, 0xf5e384c7, 0x036c88ac, 0x34e8f943, 0x9324ee11, 0x1412ab34, 0x9d5220ef, 0xd36a74cf, + 0xf5b689ed, 0x2d5f1c32, 0x294279a7, 0x576cf97c, 0x17e3b49f, 0xfb8246f2, 0xd18ab1a7, 0xd2db5249, 0xde6f7120, + 0xe21a6957, 0x591c60fc, 0x93968a0f, 0xeb6a3a87, 0xe098fbae, 0xcc6757e3, 0x570c5908, 0x25a9b5a4, 0xb527304a, + 0xed5ff4d8, 0xa96e3e2d, 0xf4090f16, 0x11092f98, 0x8d4c698c, 0xadb93a83, 0xb9c77536, 0xd7d6a549, 0x9f804a94, + 0x78fd7835, 0xa3d50f65, 0xd218bd62, 0x7feced2f, 0x1fe04ea8, 0x6ce68677, 0xaabbf90f, 0xe7de3ead, 0x435e3722, + 0x26b36677, 0xaeee8be8, 0xe68702b5, 0x1904c95a, 0xa0ba1199, 0x8a6da51d, 0x6dafcd22, 0x31021110, 0xd1af04e6, + 0x8432bc38, 0x1bd91f11, 0xd5d8bd60, 0x4da8588a, 0x72f8e217, 0xac826695, 0x77ecc615, 0xf81395c0, 0x268f3e2d, + 0x02fb500a, 0x3aadae14, 0x1f2e4bc5, 0x5a35d43c, 0xc68761e6, 0x067914a3, 0x14b01e00, 0x7e50ff16, 0xd76cccfd, + 0xa45956d0, 0xaa17674f, 0x39d6a3b6, 0xf3e1b12b, 0xca84cb26, 0x0aaee60c, 0x98b2c43d, 0xb7f51786, 0x53da02f7, + 0xbe68e7db, 0x90ff3b5a, 0x8d259df6, 0x6fb9f4c5, 0x3bc109a8, 0xc0353db8, 0x767d6204, 0x1bdd0785, 0x0eef64ae, + 0xa8590a27, 0x2b7eb800, 0x560acb3f, 0x9df47ab7, 0xe2237e9d, 0x76b17285, 0xb1fe4dea, 0x77f88b02, 0x34401275, + 0xf23d8b05, 0xd0d2c45e, 0x9778ebaf, 0xdcdcfda3, 0x45305ebf, 0xe5b3b6c2, 0x26ade24f, 0x5876c0b7, 0xf52b5007, + 0x50808749, 0xa7ae1ad1, 0x4eb894b8, 0x9a12b35b, 0x832913ad, 0xdb1d667f, 0x49fcc4ae, 0xe4b60927, 0x580af846, + 0x7e03908e, 0x3afa972b, 0xc987e7b0, 0x11d67a5c, 0x2446a7d7, 0x66393173, 0x9cb8bfc0, 0xd87fcdc0, 0x04681a18, + 0x0a0d434c, 0x05d3e79a, 0x406b1ea9, 0x68b08f9a, 0x75e15220, 0xc6d85132, 0xf071c445, 0x51f3f925, 0xf60b4276, + 0x0695cb68, 0x9f7f4776, 0x7dada579, 0xb532dcd6, 0xf48bd5b7, 0xdb05a7d7, 0x7f41990f, 0x4a5c2687, 0xba632aef, + 0xb5fb0460, 0xaecfb7eb, 0x0060c1ff, 0xabe246b3, 0x25922f75, 0x7e072b4c, 0xf816eec5, 0x0b7e3b51, 0xfbb87072, + 0x56849549, 0xf92a721f, 0x5ac68d7a, 0x50f79175, 0x247f69a9, 0x4403337d, 0x0487d60d, 0xde0716b5, 0x15c7c6cd, + 0xbb229652, 0x18f11dd4, 0xa318faba, 0xf0e011d3, 0x04539c72, 0x4e9b1435, 0x92dabdb4, 0x12f3b72a, 0x86412479, + 0xa7b35b4c, 0xec961de3, 0xbbd886c2, 0xce4d2daa, 0x94c50658, 0xb051685d, 0x8bde12d1, 0x39d715c6, 0xeaa41207, + 0x0f86c8a6, 0x79171789, 0xa9eb71c4, 0xe80f5b9e, 0x3243d1d5, 0x5a678af0, 0x80a4c12d, 0xa0e1ff5c, 0x80eb4f73, + 0x176d22ab, 0x896ca36a, 0xc2ac4bab, 0x9f910683, 0x277e3201, 0x8e0e1ddb, 0x4834d338, 0x0ca85a96, 0x7985d0af, + 0xeb977afb, 0x65181dec, 0x32537376, 0x2c498525, 0x152ec29c, 0x27903a23, 0x9bcd1a60, 0x4f86fe17, 0x70f3d281, + 0xe67bed3a, 0x04046b43, 0x93127ee2, 0x9c75e35a, 0x6b21efd1, 0x99c1ce7b, 0xec6fd3a9, 0x02ad896f, 0xc8f7fb85, + 0x9f102bbd, 0xc6ad7d1d, 0x18c5be54, 0x594736d2, 0x3f82044e, 0xa1c56ea9, 0x75d928fa, 0x9d63e4d0, 0xb336a17f, + 0x84b3d59a, 0x3c286814, 0xab5b7e7b, 0x90ce17ab, 0x4fcea9b4, 0xc64bcb2e, 0x2cfd884a, 0xbe1ea8c3, 0xfe753681, + 0x8bdcb3f4, 0xb9782c69, 0x9835cf43, 0x3d7f99b4, 0x86f59d12, 0x795e1a59, 0x78f5b71c, 0xa90741b5, 0x2f645ff8, + 0x5721a6e3, 0x2a87e8ea, 0x19101d42, 0x084e0f42, 0x6a2d8605, 0x622422f4, 0xa8731136, 0xe6236c0f, 0xc09e384b, + 0xb6038e4f, 0x77893b00, 0xe068961f, 0x566aa831, 0x86ded82f, 0xd67f8636, 0x79428b5a, 0x2d6132da, 0x503f1c11, + 0x06b4bf62, 0x22d4e8c9, 0x051eb82d, 0xa1cc358e, 0xe989f0e6, 0x1a04e2ae, 0x9d7681db, 0x8de9e7df, 0xb2752524, + 0x60ea1895, 0xdad9f350, 0x2fbdbef8, 0xf01a4058, 0x3459939a, 0x0985fb6a, 0xb7bbd145, 0xfe3412c0, 0xa71b4b05, + 0x911451e7, 0xe2b1d843, 0xef75cd23, 0xe6a2d62f, 0x26281f31, 0x17b20b3a, 0xe6dabe06, 0xd393d9b1, 0x32613237, + 0x2276dc50, 0xe3af935d, 0xf8c0d60d, 0xf3180aa6, 0x2d8d15b0, 0x200499de, 0xb1bb5041, 0x2ed00a48, 0x836d2646, + 0x25fa1155, 0x2228993d, 0xb7db3d75, 0x254ca8bb, 0x34f2eb9f, 0xa11bce3f, 0x7b1821f1, 0xafc17901, 0xa78c578b, + 0x8dc0d917, 0x74bbf7e3, 0x8dd985ca, 0x15cea9e2, 0x12d6bfd8, 0x32e5e492, 0xc0e331d9, 0x52e8ade3, 0xa1606e10, + 0x32951b91, 0xf1f86e73, 0x6309fec4, 0x6e886a78, 0xeb229c7b, 0x639f4a03, 0xdd1f0728, 0x3aaa8b87, 0x1337ce2f, + 0x56bfc5ba, 0x48044b3f, 0xc6e42993, 0x91864871, 0xdde69113, 0xa9dcc3fe, 0x25089cb9, 0x51c3672f, 0xd56b39ed, + 0xcbbe9627, 0x67b88807, 0x54ec54ba, 0xfbc2835d, 0x0ad0cb47, 0xaf90b50c, 0x5c51462f, 0x67098e24, 0xe9ccc796, + 0x8dead855, 0xf6f7431f, 0xd0205547, 0x4f416f81, 0xaf99b6b8, 0xa0dd1714, 0xeed920e5, 0x484a345d, 0x24e1e00a, + 0xb4a8d244, 0x7f1bb9d8, 0x5e0ad587, 0x8f6fec73, 0xd8d95862, 0x9dda0b81, 0x6982aa5d, 0x1c59a882, 0x722dc997, + 0x3ddfda3a, 0x420a9911, 0x21db706d, 0xd66633e5, 0xe23f5bca, 0x688e2460, 0x3ba4a13b, 0x6ecd06b4, 0xdb2e2e69, + 0xfbc88fb8, 0x51835ec0, 0x986dd377, 0x92dcbb72, 0x560852b1, 0x95c01c91, 0x9c8224f8, 0x0fa515b7, 0x5fb74522, + 0xcaef016c, 0xd3a296a8, 0x57b1db26, 0x48a7d211, 0x53a2dfc5, 0x68872cea, 0xf1753441, 0x82054c29, 0x7cbc5f95, + 0x10da99b7, 0xdbef86b4, 0x4d5dec1b, 0xc5524f95, 0xa8704d67, 0x72f3e7ea, 0xe41d41b6, 0xb31a47e7, 0x20d7b31e, + 0x87296840, 0xa2541de6, 0xa593d06b, 0x668cc366, 0x693481e6, 0x5d0a86a0, 0xb259740d, 0x5eb82c41, 0xa3f000c1, + 0xf201f482, 0x3c249bc8, 0x8ef9dd6c, 0x0243d327, 0xe3cd1777, 0xce2543de, 0x1c19ebac, 0x0ad381fe, 0xcb4b140e, + 0xc897dcda, 0x841d89a4, 0xe35a5658, 0x9a67f22b, 0xa795862e, 0x87f338cc, 0x0e4e89f1, 0x0e7f9721, 0x0822d645, + 0x08a95edf, 0x934359f6, 0x57e1ce3d, 0xa19a5548, 0xfd085c5f, 0x1a421fc3, 0xc2682ee3, 0x33cd3dc4, 0x90c1c54c, + 0x6e2fe1cb, 0x22ee426f, 0x8245ef12, 0x6114a8eb, 0x727d4acd, 0xc11ba3db, 0x6413306c, 0xa26fd4ba, 0xe02b1f47, + 0xf0906752, 0x82f81f66, 0x7e7329fe, 0x7bc85124, 0x686d64c8, 0xe4a43949, 0x63f92c19, 0xf0f52aa3, 0xb44ab347, + 0xdfef0da1, 0xb1b698ca, 0x02d298f2, 0x77a7b35f, 0xbe880ca8, 0x4a5f4701, 0x47ea58a2, 0x5216a4a1, 0xb16b7812, + 0xde43819d, 0xc3779382, 0x7f03a9da, 0x8cb867ae, 0x1779cbf4, 0x7b0bb609, 0x75c707a0, 0xc20cecc0, 0xa6542f25, + 0x7a65d5d1, 0xb5022eb5, 0x1c7cc7b8, 0xb8155980, 0x48aa5c63, 0x76cd81b4, 0xcddee076, 0x8edbd923, 0x389391fc, + 0x9a4b6666, 0x2cc6a3a2, 0x5c89baaf, 0x78375212, 0xe48efdc2, 0x48bfa682, 0xb6765021, 0x964443b2, 0x5ae5010d, + 0xda628ab8, 0x41123d56, 0x002701f1, 0x64bce684, 0x26e3cd6a, 0xf563c0ec, 0xcaedefa0, 0x5e05515a, 0x38f02d17, + 0xe674d861, 0x71744271, 0x9b6a3596, 0x4d5bb10e, 0x850cddeb, 0x1d992d78, 0xe4211fec, 0xf9b3ed5e, 0xeb9baa33, + 0xcacf66d7, 0xf7d84cf0, 0xd6463d1d, 0x62dd04b6, 0x30fd3abb, 0x7509eca3, 0x69fd9e57, 0x0c9511da, 0xe972fb8c, + 0xb14abb49, 0xc3c74f06, 0x7eb7caf9, 0x65b8b63c, 0xf13093f3, 0x25691398, 0xe39be006, 0x1bba3c06, 0xbad3a4f6, + 0xda72104c, 0xf40ba08b, 0x01baa9f7, 0xbfa7ecad, 0xe604b34d, 0xc6656cfa, 0x105c724c, 0xe98f3c8c, 0x7098c94b, + 0x33d236f7, 0xa198af51, 0x407fc4ec, 0xf52f3b2a, 0x36766243, 0x57b7bd36, 0x7e859ad6, 0x13eb0274, 0x731af3e5, + 0x5d7d9db2, 0x9f3bd9ca, 0x1fd72dfc, 0xb89d6854, 0xc3aaa305, 0x4efe0672, 0x72a101c3, 0xd2b94510, 0x54a1d389, + 0x1a96370d, 0x811d3467, 0x6f86fe28, 0xd1716bc2, 0xb37eb371, 0x76904e12, 0x01e8fcdd, 0x9c109890, 0xd71a0403, + 0xc14318e1, 0x89b4be62, 0x0df98bc7, 0x913271cd, 0x84a51f96, 0x5b19b2b5, 0xda72a460, 0xcb6d406a, 0x2cca0ddc, + 0xe0d26004, 0xb62b310d, 0xc105ccec, 0x7b1982f5, 0x1b2e0411, 0x808ecc7f, 0xe0c7c560, 0xbb4764ce, 0xd2ea1657, + 0xec69184a, 0x49a40ff0, 0xfd1ff646, 0x89e21c5b, 0xa2388b21, 0xed528f9a, 0x67d2543b, 0x88ee2b59, 0x2c2bc584, + 0xbff7f5f3, 0x2f51ded3, 0x99a55e7a, 0xc0d8c481, 0x49fc6577, 0xe578a8f3, 0x0fca10e0, 0xe5d55e61, 0x4888953a, + 0x83a2d3d1, 0x6b07e4ca, 0xabad0252, 0x18579c70, 0x9c910a2f, 0x0a565570, 0x59936fa4, 0x023d5c54, 0x019e7bc2, + 0xedf1c2a4, 0x9b02b529, 0x28307bf6, 0x864b4e0a, 0xc5d54cca, 0xfe8c1cc4, 0xac6a5d15, 0x54781fa2, 0x575a74e6, + 0xeb63e1e3, 0x5a6ae906, 0xba1f0430, 0x41d459ef, 0x33d17cd5, 0xeafce8a9, 0x2a36be85, 0x460b59c0, 0xae949bc2, + 0xbb48e7e9, 0xf046476d, 0x37fdd938, 0xb8ceadd6, 0x1de01835, 0x95a70be9, 0x095d90ca, 0x884012d6, 0x273e451e, + 0x645c11e2, 0x74d9bc42, 0x0b56db4d, 0x4842e2ea, 0x8116cddf, 0x7d134f86, 0xbfd38d6d, 0x7ff0da52, 0x4cab0620, + 0xfd2df4b2, 0x503fb5c5, 0x560613a2, 0xfa4d98a4, 0x9143f4d3, 0x915f3006, 0xf97a4e93, 0x051a0036, 0xd45a9f88, + 0x63e44e60, 0xfb88ed90, 0x44946df1, 0x82de9418, 0x49102584, 0x6cfb8eff, 0x6a209bfe, 0xfd7b1d8e, 0x67a874eb, + 0x79165c13, 0xfb1dae19, 0xb20f7447, 0xb4d70c14, 0x80d63804, 0x287f8910, 0x8509e13f, 0xfac6b989, 0x8a3bc534, + 0x25bbb08f, 0x520383d3, 0x5c659ac1, 0x7d4471bc, 0x967b7e1b, 0xf94b5181, 0xc9beffb3, 0x8dd37b69, 0x29b12ad7, + 0x740024fb, 0x2ae5145e, 0xd9edccbd, 0xf2d7b099, 0x34f46f09, 0x219b41fd, 0x755234be, 0x14fc87ba, 0x52d5fcc7, + 0x02a1eb27, 0x8718cc60, 0xc2d61d83, 0x215def64, 0x8ad99750, 0xe5ab2023, 0xefeea82c, 0xc496b938, 0x56382e6c, + 0xd6690a78, 0x3c9f4831, 0x45fe399e, 0x9a783627, 0xef839541, 0x0e7c0845, 0xedf2f0d1, 0x59a3ac58, 0xfc80743e, + 0xf7db7fb0, 0xab9928e0, 0xad9e3e00, 0xcc97809a, 0x39e204ee, 0x5dfc000c, 0x596a4d01, 0x54602c45, 0x51eedf0a, + 0x817cf9ec, 0xa0796ffa, 0x1b9b2390, 0x5a3840dc, 0x44ffe5b9, 0x588214cc, 0x498372b5, 0x997acb8b, 0xba710265, + 0x1cac3f28, 0xb8b47f4f, 0x3dd3d17e, 0x02a29ba7, 0xb79bd19b, 0x5ed43eec, 0xccd91c00, 0x3669edaf, 0x93ecf889, + 0x5d6993ff, 0x86a0f90b, 0x1c64ba9f, 0xc62f7249, 0xe2a42db7, 0x7b1bdee3, 0x2bcc579d, 0x12d01297, 0x5402592f, + 0xa8355bd8, 0xed00d137, 0x78499430, 0x065d455a, 0x8452f236, 0x71914404, 0x0e3adf44, 0x67613c42, 0x2a70d7b3, + 0x3da41220, 0xd81c1834, 0x7073d332, 0x21e603c0, 0x16912087, 0xf3f877dc, 0xb7282383, 0x44dff2d9, 0x86be1557, + 0xe5e57424, 0x3fb4e29b, 0xd60ebe34, 0xb08e072b, 0xa4242cba, 0x526f12dc, 0xa8890ad1, 0xb72cd8ef, 0x188d03e6, + 0x6a67d184, 0xa7f92449, 0x349c143c, 0x9b457ce7, 0x57dbd6cf, 0x5cb96447, 0x4567f30f, 0x340954c8, 0x5227699c, + 0xeef0a6d0, 0x2967565e, 0xe1dfa555, 0xdefc250f, 0xe542f90a, 0xef53a09e, 0x8b0e89f1, 0x6e27575b, 0x4c88c6a0, + 0x6249a648, 0x6836b60b, 0xa706cba4, 0x53606e3d, 0xc446e173, 0x4be55c55, 0xa4c1a982, 0x7d5e8e74, 0x2a154049, + 0x551ba6f4, 0x7cade718, 0xc496fb98, 0x0fb2bab7, 0x84d6c692, 0x332f6f83, 0x48c6ffd0, 0xd44a301f, 0x72eb5e14, + 0x47e5d5ce, 0x583f229a, 0x6e480e2f, 0x179277a4, 0x53b5c990, 0x2fd8feb0, 0xeab09338, 0xd1d808e9, 0xdd3369e0, + 0x83554af5, 0x0b38dff7, 0xfa2507ed, 0x308ac592, 0xe2aefd44, 0x9686cd81, 0x12cd7494, 0x642e78be, 0x6133a66d, + 0x17e3eb72, 0xf46069cb, 0xa07e3d6e, 0x2624b6bf, 0xba7da7ac, 0xe9461905, 0xf51117a8, 0xfe5fd354, 0x0a11b742, + 0x3499458c, 0xa41e2bca, 0xc3af88fd, 0xa3f1fd7d, 0x53c5d8d2, 0xc8761f9e, 0x798e69ed, 0xa5dba4e3, 0x014f511e, + 0x0a684760, 0xcb3b141f, 0x0d4f7586, 0x86307386, 0x0492acab, 0xa8f4c23c, 0xd98b0ca5, 0xcbbaf285, 0x379362e1, + 0x6e94c950, 0x80ab38d7, 0x5c32f542, 0xba1264b9, 0xce312f5e, 0x9878f2b0, 0x0f36e576, 0x89c2f354, 0x35051a53, + 0xa88b016c, 0xfc1de041, 0xe07ec25b, 0xd8b63903, 0x077e3cca, 0xa71913b2, 0x0f66ca23, 0x7e5a9808, 0x0699e5da, + 0x4aecff45, 0x4f9d0558, 0x8d31a8cf, 0xcd0055fa, 0x87a78346, 0xf1009160, 0xc95ae507, 0x7bf791e4, 0xc8f363a9, + 0x73e29306, 0x9d99b234, 0x3941579b, 0x2687f78e, 0xf2fe0446, 0x54a7d0e2, 0x9dab3744, 0x47b24962, 0x841bd749, + 0x2b116485, 0x0ea7b55e, 0xf14860f7, 0x3cc26636, 0x9927d6ab, 0x2e03a585, 0x2d07db22, 0xc5ce3c75, 0x7767f26c, + 0x76e6d261, 0x21c37c3d, 0x0f6f17a7, 0xd80a2116, 0x5ad9e552, 0x89da7b03, 0x3d98b10c, 0x6359daec, 0xe41573c5, + 0x203ee0d6, 0xf2bb75a0, 0xb7415e4e, 0xc1899ac7, 0x7b9f0437, 0xbfa96ec3, 0x9d554fa5, 0x3db63a07, 0x3a8bd51c, + 0x96fa0295, 0x69c0d2ad, 0xb405e4b8, 0x3b648ec1, 0xf8309dbf, 0xd2664180, 0x395916bb, 0x856d89a5, 0x66d8527c, + 0x79ddcb9f, 0x6417c6ef, 0xba76986d, 0xc355fbe8, 0x8019e181, 0xce0f786a, 0x36b43269, 0xd539fb75, 0x7545e1ac, + 0xbfb55c6f, 0xfbaca6be, 0x374cabca, 0x0921364e, 0x160b411a, 0xd4447d1e, 0xeb0d3106, 0x0b64510f, 0xde618d6b, + 0x1d87758a, 0xd28c3610, 0x3c8fc0ac, 0x83b3f5c7, 0xe3588439, 0xd1342c3b, 0xbefd8cae, 0x1005c35c, 0x8738eb4e, + 0x53bf2c50, 0x14c64cf3, 0x57dc8df4, 0xab6d2486, 0x00646d11, 0xf0648a6a, 0xb97fe1da, 0x94900ab2, 0x6edfdb4d, + 0x8f8e9d9e, 0x4e013698, 0xe2ae25e1, 0xb6434d2b, 0xe30414e7, 0x9898d2f6, 0x1648e8bb, 0x2c8cad60, 0x425f7bf8, + 0xdcc74cca, 0xb3ab2e34, 0xe1603a38, 0xf0658058, 0xe7f445a4, 0x71b5d158, 0x5fd41958, 0xedf592ce, 0x73ed11d8, + 0x0b87f518, 0xf90becc8, 0x6ffa5984, 0xbcf7bf8b, 0x4938bcd1, 0x05dad962, 0x46f6b82e, 0x9f91aa82, 0x215d7dfb, + 0xb5034536, 0xb80859a2, 0xc646399a, 0xb0c946e2, 0xe08b255f, 0xed9622ad, 0x41b094d5, 0xa03942c0, 0xa0a65e92, + 0x4a8b19c2, 0x97da21fd, 0xbb23dc90, 0x7419d843, 0x91cf9388, 0x287cdf16, 0xd3fd3572, 0x745132af, 0xa7032d71, + 0x46b88b86, 0x3f1c25e1, 0x688e871f, 0x9a2d4ad4, 0xc294478b, 0xbb794f5f, 0x49761c39, 0x0ae6ab5d, 0x10a6ab60, + 0x3877c517, 0xd32502ec, 0xc50f0c09, 0xf0fa5073, 0xa23a7606, 0x2bbcc7fe, 0xfc760ee8, 0x0de433be, 0x08e2382a, + 0xbf64c9ee, 0xa0aaca2d, 0x813e7b9f, 0x411549b3, 0xede578f5, 0x4810fccb, 0x6e62decb, 0x7a3b5459, 0x0ef8ab01, + 0x54537cd3, 0xe8e0eb74, 0x1e658ad3, 0x2169b467, 0x96aa0e1a, 0xa32493f6, 0x17a9dffc, 0x0d9ab843, 0xb6b1bb23, + 0x61b3ce39, 0x3fbc3d5c, 0x775781ce, 0x688e4dff, 0x8085925e, 0x1c91fc6a, 0xd6206d2e, 0x9f659eb7, 0x9737e7ff, + 0x5c185534, 0x38b0fa42, 0x012d754a, 0x8059b981, 0xd521c7f4, 0x86ad5025, 0xbce80d53, 0x56a29158, 0xace85bd5, + 0x483dc807, 0x0a7f97d3, 0x44778a9c, 0xa7d3bac0, 0x1037f2c8, 0xa1a1b9d1, 0x5f6c7635, 0xc2625da7, 0xb161b455, + 0xadb43aac, 0x9adbf1d2, 0x5f6e671c, 0xb05371df, 0xa9fdf51b, 0xce4993d8, 0x25585c66, 0xe3473dd6, 0xaa3c8760, + 0x83efce69, 0x68ec1bc7, 0x48be7df9, 0x13a80224, 0x4c10a929, 0x19d93750, 0xd361e0f6, 0x682d984a, 0x3490ceba, + 0x94921500, 0xd1555923, 0xb5984701, 0x7aef2b4d, 0xab5894c5, 0x51ee6d99, 0x529e1e2b, 0xd754449a, 0xac683e88, + 0x494b6a1d, 0xe2c9bdf6, 0x768ea81b, 0xbf2e59f9, 0xa3c053a2, 0xc9e58f25, 0xafd258cd, 0x97424de9, 0x1a5dd31b, + 0x2f4b36e4, 0x71071b7b, 0x3bed475b, 0x2b5c4244, 0x53c7e5b3, 0x7bb1fe0c, 0x4fb9cfea, 0xf33dbfbb, 0xbc601c57, + 0xef30d48e, 0x381e6407, 0xc090a610, 0x01889ce5, 0x4892f4bc, 0x812b1a6f, 0xe4880a06, 0x66d170a4, 0xe97121a8, + 0x2e8dac21, 0x5f0258b1, 0x04839d6f, 0xb6906bdc, 0xc0c611cf, 0xf59d5d62, 0x2b19b162, 0x7925910d, 0x872847f7, + 0x4d935ba6, 0x80c57122, 0x3cb083f4, 0x9afedc2a, 0x88460846, 0x0414dd6b, 0x8d0efd07, 0x5e534ccc, 0x2d594bcd, + 0x488b9eea, 0xc10b0328, 0xd59b317f, 0x77fe0912, 0xfb43d25c, 0xb63ce908, 0x200ccbb2, 0x840849b6, 0x1fd1e45c, + 0x975ac72d, 0x81e20ff9, 0xb199cb50, 0xd0af48a3, 0x5e940fa4, 0x46f3ddd7, 0xbf8e94ac, 0x78979f48, 0x16b01046, + 0xf2013866, 0x835ca851, 0xc133838a, 0xa972a70a, 0xde7e0e06, 0x806d3e32, 0x69e5c801, 0xd2cd6369, 0x9e65c392, + 0x34c7cc74, 0x51405862, 0x207c8028, 0xedec62b9, 0x57001e76, 0x0607b202, 0x4a3fb300, 0xce66cb4a, 0x4aac9137, + 0x6d24721a, 0xad4abff4, 0x70a595ef, 0x094e78f3, 0x62dac55c, 0x7e2a0b09, 0x98122849, 0x866d4580, 0xdf39dc93, + 0x8400487f, 0xca682c57, 0xaee7cbcd, 0xf6f2e881, 0x3138390f, 0x01a06580, 0xa15b9f2d, 0x8e1e7727, 0x60681742, + 0x36db2e38, 0x78c7dff8, 0xcb361fa9, 0xfee83aea, 0xac41fe05, 0x5b302b12, 0x7c644e0a, 0xf5499228, 0x357c1b19, + 0xe213999b, 0xbea6ed6e, 0xccbb8cc9, 0xecfcdd74, 0x6ed6b24e, 0x125fda26, 0x0203221b, 0xbe26ad42, 0x52b1688f, + 0x62ea2de7, 0xd47b32bf, 0x262466a8, 0x1dd2a1d1, 0x928b8e6e, 0xe439a672, 0x51bcef91, 0x57fb0c96, 0xac2d9ae4, + 0x4bcfbcfb, 0x3d555bfe, 0x1f864895, 0x9bcc3e52, 0x7449802b, 0xc6b9912b, 0xe98a51f1, 0x96d7c95f, 0x3d8331a9, + 0xec4e5380, 0x32208e1c, 0x117ce696, 0xd3d32f28, 0x7070a8ae, 0x9f58fac3, 0x4c0fc458, 0xdc109ed3, 0xb1e233d4, + 0x04a31442, 0x00c86587, 0x3d4e78f7, 0x46a48161, 0x6bd4a3e5, 0x8e8be20c, 0x5c6ceccd, 0x06c8c032, 0x9b5b63c9, + 0x4ce2e78c, 0x928ae332, 0x5a1dcfc4, 0xb500edcf, 0xf4cf740a, 0xd7bff677, 0x3299f6d1, 0x43bfd95d, 0x3f67edfb, + 0x8f135913, 0xecd43ed5, 0xde3b9f4b, 0xa0f316d7, 0x71dd400f, 0xb28b4803, 0xe72aa9e9, 0xb4512cee, 0x4b801579, + 0xe66e3ea9, 0x81d8eb05, 0xa05f1600, 0x7abdcfbd, 0x23b439f6, 0x58517a2e, 0xbeef65ca, 0x21416a5f, 0x6f4d7079, + 0x05e8f749, 0x8c79dcc8, 0x2caa8346, 0x874bae96, 0x5500a5aa, 0x8dd8b912, 0xd2145254, 0xf03a539e, 0x2f6ccc7d, + 0x225175d4, 0x9b20c249, 0x0031ddd9, 0xcea9df09, 0x38b9b38c, 0xb3fbdf40, 0x59bf0d42, 0x8a2fe5f9, 0x587d37ec, + 0x856fd224, 0x9185be77, 0x57e90bb3, 0x9201e18f, 0xe1aaba85, 0x64d9c2a9, 0x74c6c7f7, 0x5ce67588, 0xc6234743, + 0x122dcf7c, 0x4a0b2e78, 0x0d268046, 0x20b77abc, 0x88afcc62, 0x27f32328, 0x2ef69763, 0xae641365, 0x686a616a, + 0x01b6d96e, 0x23765b4f, 0x852113d7, 0x6cb28805, 0x56f46cb9, 0x89722be7, 0x17c0cf95, 0xdd3702cf, 0x54fc6379, + 0xbcb159fd, 0x46671940, 0x35ffab4e, 0xa63e1d61, 0xbc702da5, 0x467e2977, 0x900cc3b5, 0x9d62cd0b, 0x3933e353, + 0x7069de65, 0xa0c32183, 0x00b39972, 0xab744d6d, 0x9181db44, 0x7856b793, 0x5817e7a0, 0xa6204cad, 0x40aaaf77, + 0xd4b3d962, 0x7bc3172f, 0xc60cf754, 0x519662eb, 0x9909dda2, 0xdab82651, 0xb55a7173, 0x5216fd05, 0xcfc6c4d8, + 0x59475932, 0x886c87e0, 0xe78b167e, 0x9c20c657, 0xe088a78f, 0xbf184d8d, 0x886c9acf, 0x3bf25af2, 0x592c32f1, + 0xbc4d859c, 0x70923222, 0xa2be9d17, 0xcc043cbd, 0x3cdb8bed, 0xa72d9cde, 0x7a29aba6, 0x98405322, 0x66ac3b60, + 0x0070e806, 0xa944f8d6, 0x0c243ed3, 0x7c04b4e3, 0xb608ba09, 0xf02bb371, 0x97507ac0, 0xbf912bea, 0x626566d0, + 0xcf993c8c, 0x546ef509, 0x2e870bb6, 0xf2e720c2, 0x6f9bffb5, 0x6e9cf7e4, 0xd938b068, 0x12e6db31, 0x21c2e1a1, + 0x92584001, 0xd3a03d89, 0x57fdb529, 0xafc50d91, 0x91ffecc4, 0x72491a25, 0x97e1a012, 0xd7b4bbd6, 0xc8442f24, + 0x150495a7, 0x8befd10c, 0x392eb2af, 0xf59271bf, 0x15b69501, 0xe3de3790, 0xaf2df704, 0xbec8fbc0, 0xef0044e4, + 0x942ba4a7, 0xa65ac52c, 0xba9b04c9, 0x752cb601, 0x4d28abaa, 0x22d4bb0b, 0x941767a0, 0xf7aef2b8, 0xa4bf89ce, + 0xcb356adb, 0xa5476696, 0x2fc7a098, 0xdc012913, 0xe0ca6c69, 0x7af314bc, 0x8beefdf0, 0xbbad1550, 0xae3153a9, + 0xeeb9c9f8, 0x54f5f74b, 0xc3ff082a, 0x3e73a599, 0x717a0261, 0x955add42, 0x059820ed, 0xc19f455b, 0xa7272e72, + 0x9bae20db, 0x9048ebc8, 0x5f0b9452, 0xd3854693, 0x67a1af31, 0x33bda751, 0x44aec731, 0x15ca013b, 0xbc7f8b3d, + 0xc8b79ea2, 0x9df05278, 0xbdf14914, 0x13ffbb06, 0xaa0dd7da, 0x9e1e864a, 0xfb8fe130, 0x6a9d5d76, 0x27723a05, + 0x7d15b999, 0x40cd712e, 0xe331d0c9, 0x6702102e, 0x5dcc9dcb, 0x22240cf9, 0xaec63de3, 0xa4b343a6, 0xd33b25d0, + 0x0083da06, 0x686840d1, 0xaffcc47c, 0xdc8eae24, 0xfcf2cec8, 0xbed884c2, 0x4d9f96f1, 0x36d07a47, 0x4184cfc0, + 0xc4b5b81c, 0xcffdb51b, 0x3984efec, 0xb3f09967, 0x07eeca21, 0xc75e5462, 0x0a7638b3, 0xe7f54586, 0x49356bf1, + 0x5f8a7f3d, 0xe4c1fa52, 0x91afc072, 0xae25aaa9, 0x10debb34, 0xd1a91346, 0x81ece282, 0x7c87c000, 0x3606d70f, + 0x54534228, 0xda263672, 0x32e51fbd, 0x0b40db91, 0x2cdcc0db, 0x8cd9f6e0, 0xe2aa2e5e, 0x21f6c5be, 0xa0ff94dc, + 0x0d6599b4, 0xe7bdf895, 0x88153daa, 0xd9e734ae, 0xfaf2e85e, 0xfbf96cac, 0xb17f57b4, 0x2b1ca54d, 0x96f87b7c, + 0x9e785b1f, 0x4dafbf83, 0xea9c28f6, 0xfd78d0cf, 0x3aabbc9a, 0x4abf5138, 0xf186f9b5, 0x9525734f, 0x6fd3cc96, + 0x612e87b4, 0xc4eb2c4a, 0xac77bff7, 0x8bc54910, 0x80f0c9d3, 0xf768c55b, 0x3a0ef658, 0x9642e2ed, 0x01af8caf, + 0x7759a0bb, 0x7653f128, 0xbd088afa, 0x2fd4f6e0, 0x3262d4c3, 0x5264819d, 0xbd45f9d7, 0xa2eddcff, 0x58672b73, + 0xab6ee349, 0xbde5cc1c, 0xdaf89279, 0x41f5c587, 0x635de87f, 0xd3c6d12d, 0x412332c9, 0x2bd81188, 0x9c53adc3, + 0x7b5afd90, 0x30bd339a, 0x06585046, 0x99154b03, 0xb265cbae, 0x8c80a4fb, 0x768ebc24, 0x1aecce80, 0xe04d2eb5, + 0x046193f2, 0x54f80a37, 0x822446c5, 0x73a43a81, 0x344dbc98, 0x4182f55b, 0xb324ba48, 0x1cd095d3, 0x5d2f5e35, + 0x3cf3a8e6, 0x3649f876, 0xbc33b9b3, 0x5ac6ded4, 0x2a97eb40, 0x1ef83e73, 0x32d01d22, 0xa26e5ae5, 0x49111a2a, + 0x7c3e6e06, 0x4bd640d7, 0xaf369fca, 0x46cfaed2, 0x8f6bc2c8, 0xa8b8524e, 0xf7a2383a, 0x6a0146fc, 0x32a59b97, + 0xdea7d991, 0xb960aa31, 0xa2052a64, 0x1bcb9936, 0x46f2aa8b, 0x5c9effe5, 0x99c9b80f, 0xcba68800, 0xcaf62e24, + 0xe9b2ed7b, 0x6a160333, 0x1dde0cb1, 0x4d3e4f92, 0x7ebcc6b1, 0x8792e3a2, 0xb8dd8b4b, 0xfa34d5de, 0x3ba6767d, + 0x017234fe, 0xa2a12aee, 0x91169a6f, 0x43670fd5, 0x3115efda, 0x438c8ea6, 0x0d64c09b, 0x52d3372a, 0x543df813, + 0x5cb9147f, 0x1e24cd0a, 0xd3f7b0d3, 0x98394df4, 0x94d39f59, 0xcae84650, 0xa4d539d9, 0x20c54494, 0x862f910b, + 0xd5d47e5c, 0xa99b77b2, 0xe0b478b0, 0x4b319de5, 0x4be2139b, 0x7fd70675, 0x8a1ee51c, 0x69951fab, 0x470b02ae, + 0x086adeac, 0x9fcbd61e, 0xfcb59233, 0xa08c74c8, 0xab9a7931, 0x75f831c0, 0xcb5a06c6, 0x2a87e52a, 0x1ba0fd9b, + 0xaceb965a, 0x3ecd7cf8, 0x30805b46, 0x79088fad, 0x0dd4b46e, 0x0bba80ce, 0x847807c3, 0x996c0942, 0xc1cb4f19, + 0xa235f4d7, 0xc4dab618, 0x2863b9c0, 0x13ebce7d, 0x6c5d2db8, 0x6f939510, 0x36a795ba, 0x15fa9aca, 0xf68a521e, + 0xfe3cf461, 0x00122b3a, 0xe928918e, 0xc187bedc, 0x152b36d6, 0xb48295fe, 0xc670d3bd, 0xc72bbde8, 0x00c721fc, + 0x9fc2ed40, 0xd6fce032, 0x01428e38, 0xcbd3ed9c, 0x0bedd529, 0x5c6362fd, 0xe406d016, 0x0721a727, 0x5c70a4a7, + 0x615f029a, 0x3a2bcffb, 0x4ed0da34, 0x4f207680, 0xecb2ae82, 0x3dd9b051, 0xcc40090c, 0x3782adbc, 0x0db74f81, + 0x08d04d12, 0x08b7b389, 0x6cd1eb07, 0x94b6adaf, 0xc47639eb, 0xf82965c1, 0x5cd18711, 0xce797398, 0x0b4919f8, + 0x074e609c, 0x3b1980f9, 0x353382ab, 0xcc1a6a02, 0xa6949f0e, 0x0301115f, 0x1eaea79f, 0xbaf38d1b, 0x72ab3a53, + 0x805256a1, 0x06abc9f7, 0x75548d25, 0x26e609b5, 0x53e0c436, 0xd5ca88ed, 0x559d3c4a, 0xe5d5680b, 0x63ff09bd, + 0x60c2c109, 0x76e9f6ea, 0xf0a16a89, 0x01a156d6, 0x49999d31, 0xef02a749, 0xfba7ea1b, 0xfb044e78, 0x1cabb1df, + 0xfe5f71f7, 0xa80c12da, 0x6df5d96b, 0x4e1032cd, 0xb4e02f0d, 0x36c3d15f, 0xe5621af7, 0xa69f87c5, 0x39c1d8af, + 0x1e803748, 0x4567f8d9, 0x922d0758, 0xe34d3436, 0x8f553c33, 0xdcf15cd9, 0x070cda70, 0x04f62d99, 0x3d4948be, + 0x386568a0, 0x1231d2ac, 0x70d4da15, 0x47f073e0, 0xb5b744d5, 0xec39cbbf, 0x8c0fc842, 0x1ff3ea56, 0x989222cf, + 0x7ecc7e4c, 0x644bf57b, 0x7940e418, 0x5ea28a31, 0xa2a592f4, 0x232f8a98, 0x21287881, 0xc38a37cb, 0xf45e6e64, + 0x044e9261, 0xa92711f9, 0xbfc2ebc7, 0x18b6650a, 0xe808c5b7, 0x2896e0ab, 0x9fafe5b4, 0xde6d3f09, 0xae3df070, + 0x1095eb18, 0xdb0e6542, 0x3d44eff7, 0xe146ea6a, 0xc7f0a14a, 0x98661aa4, 0x7540b32c, 0xf91d9776, 0x6468013d, + 0xedf93877, 0x6dbdb3fa, 0x0d36939a, 0x6d81cf95, 0x291787b4, 0xf9dd7eb4, 0xcdf8f870, 0xebd6f9fb, 0x68213598, + 0x10dd2c24, 0x9aada20d, 0x6852765b, 0x3521d4a5, 0x86bcdee4, 0x4d8a4df8, 0xc1602367, 0xcdf1e919, 0x9ac0a475, + 0x861e437c, 0x49d81d15, 0x58de855e, 0x026df29c, 0xd87f7095, 0x6516818a, 0xeb03784d, 0x5fd30046, 0x06382d95, + 0x339eea02, 0x26f7a802, 0x627e25b4, 0x16ee7bbb, 0x23772db4, 0x9c845a86, 0x58f687da, 0xfe4e4fa4, 0x930244c8, + 0x4ddd4e92, 0xf936f7b5, 0x258afea8, 0xf989d09c, 0x78598b78, 0x36bc4467, 0x3c977f3e, 0x1afeeda5, 0xddd849af, + 0x2e05aa91, 0x9b86010b, 0x0fce5d8a, 0xd11094d9, 0xb4aa9330, 0x2f705f4b, 0x392cccc3, 0x55a8e726, 0xf7b9f760, + 0x2ec67586, 0x629191f2, 0x8253cf04, 0xb956f9a8, 0x47746c2e, 0x691c5f01, 0x646db559, 0x3a2056ab, 0x31b293e4, + 0x1d52e894, 0xe76b9920, 0xa65204ab, 0x8d375fd9, 0xe749bda3, 0x15b55788, 0x0c468315, 0x1f66fe49, 0x11d08438, + 0xe300e001, 0x3698be13, 0x3ca03627, 0xd27adbd0, 0x0ceb78e2, 0x63d73421, 0xb255fd82, 0x6e65a74f, 0xc25e06de, + 0x8120e55e, 0x651185da, 0x78df5d63, 0xcf37dd87, 0xbf26f21c, 0xb655a888, 0xa40b122f, 0xe5e22efc, 0xfb273b24, + 0xbf027486, 0xabd6383b, 0x690656bd, 0x3aa6a493, 0xe0c2f710, 0x199480f8, 0xdb204930, 0xecd88891, 0x0dfd5830, + 0x4cd83b3f, 0x9a3f20d4, 0xeb467721, 0xf694b437, 0xf89da4e9, 0x9e91d210, 0x9f9101d2, 0xb94bc9b6, 0xb1bf7d7c, + 0xfa2a3ed2, 0xdb08b59a, 0x52e3a8c6, 0x7a8bb482, 0xfc746319, 0x0e38e00b, 0xf0830a6e, 0xc7f8e341, 0xb59220b4, + 0x6c8b2ac4, 0x2f98f0d5, 0xfad1e473, 0xde81560e, 0x4ccac373, 0x780b2f4b, 0x86630755, 0x5e7edc75, 0xc9ec4d7d, + 0x94928fb9, 0x6528d9ca, 0x28d32ba9, 0xf8283df9, 0xe0a5baeb, 0xfa9e123e, 0x3eb58dc3, 0xa5603454, 0x60fd1e45, + 0xd3603a19, 0x52fc547e, 0xfac1ae17, 0xe52007fd, 0x4ae31302, 0x99e89c72, 0x87e07e29, 0xa2c3a989, 0x6b0a5ef0, + 0xe976c85a, 0xb8fa48d2, 0x915d7ae1, 0x5d5e8da0, 0x0b1c2379, 0x2093d922, 0x6e41807f, 0x106092e5, 0xaa0a5eef, + 0x9de5820f, 0x9c0694a9, 0xf4fcff24, 0xdb55a986, 0xb6fed380, 0x74575d39, 0xea662538, 0x37efa848, 0xf109fb1f, + 0xb4283a01, 0x2d81cb28, 0x32bb8380, 0xd583230e, 0x9f0acaa3, 0xeac070c8, 0x61d9566a, 0x2dccc5a0, 0x1e48db22, + 0x4874a734, 0xa0006436, 0x33ad31fa, 0x8e29999c, 0xa1e656fe, 0x18ea2c71, 0x379475ab, 0x0802fa7c, 0xa1a3597d, + 0xf7c0eb25, 0xdf79ffb6, 0xfe27c373, 0x4bd9ef5d, 0x022ced70, 0x7c1b075d, 0x22b9a48d, 0xf6162b7a, 0x214387ac, + 0x32609bb8, 0x1414d5ee, 0x38c57d66, 0x02791777, 0xb9ab1953, 0xe19f3901, 0x6fda85ad, 0xf82c78e3, 0xf4c664af, + 0xb180fbb1, 0x46149085, 0x200ae4d3, 0xe363b6ae, 0x510f2c0a, 0x97508de8, 0x7a28ef66, 0x00e84ccd, 0x39cfd0be, + 0x679d82db, 0x4ac68b25, 0x41d4b979, 0xfaec3c14, 0x69e4f70e, 0x8a69b20b, 0x480a41f4, 0xe2cb58d1, 0x94a87a9d, + 0xb0a21d07, 0x362d8737, 0x602900ac, 0xa8e46bc0, 0x9a64347a, 0x9e337b0c, 0xacbbdf81, 0xb831a3f6, 0xfa505704, + 0x6100159b, 0x89a027dd, 0xac3156cb, 0xd948b80b, 0xb931f831, 0xcb9ce62c, 0x4263f7bc, 0xb72a7efb, 0x0a653075, + 0x025fef64, 0x5b084013, 0xaa9f032d, 0x50a33b55, 0x789a17a0, 0x2b03ee27, 0x3405bdfb, 0x23bd6ac1, 0x5f8e1ba3, + 0x783d8a6c, 0xae338fd1, 0xf3557033, 0xcc35563b, 0x9e43ee67, 0x79151b7f, 0xda3bc367, 0x7eb67e49, 0x1331a027, + 0xafe0e3fe, 0xb40d9df5, 0x2fa30422, 0xa70f74e4, 0x705449c8, 0x283c3dd7, 0xa64f10d0, 0x6f96f05d, 0x030ab8b6, + 0xe890f72f, 0xa342576b, 0x4d6a3f62, 0x5a2badcb, 0xf14dd922, 0xd544af42, 0x4b09d615, 0xb7b07459, 0x2e6a22c1, + 0x7be9d378, 0x1462b464, 0x72f76ac4, 0x29620a28, 0x04e7cb0e, 0x660ec97c, 0x575f75cc, 0xd6b37bfd, 0x63ae985b, + 0x2a52f1e2, 0xa3605381, 0xb0726116, 0x13c113ee, 0x68ed1aae, 0x55328ef1, 0x2443e164, 0x2c34298c, 0xcacf9a21, + 0xce0c583a, 0xb6b66560, 0x1d653179, 0xd8912a7a, 0x781c747e, 0x4cdb48f6, 0x308fc124, 0xff88c0cd, 0xb38d7ac7, + 0x4f24f9c3, 0x21caaa97, 0x5af509fc, 0x5b42e271, 0xc04b8d0a, 0x46d2fb5e, 0x0461399b, 0x3c95d599, 0x6949b03d, + 0x9ba93f52, 0xc17ce62a, 0xca1bbbe5, 0xc34bccce, 0x3a66268c, 0xa96ce407, 0xae2f9397, 0x2c6f4e88, 0xd67e1854, + 0x567987be, 0x0555d928, 0xe2c8a4b0, 0xc70c23d5, 0x036dde0d, 0xfb9e4dff, 0x2ef223f3, 0x68d88c3c, 0x65cebc91, + 0x88dcf35f, 0x02a58cc6, 0xbc05b736, 0x40c8d374, 0xc651d8f0, 0xd4354d18, 0x7318c4d2, 0x5a03ceda, 0x0b245f86, + 0x8c16deb5, 0xdfea85b9, 0xe143d761, 0x675eac04, 0xbeb98e98, 0xeafd0725, 0x3ab2ea7e, 0xb5d9edb9, 0xe6706e02, + 0xc41586c0, 0xc57451d5, 0x8cd82bf6, 0xfab5c526, 0xcae48e3b, 0x67b0361b, 0x2072344c, 0xdf646170, 0x9175327b, + 0xac657f3c, 0x27d91a80, 0xc1c9944c, 0x7c008502, 0x6c4db20f, 0x76df42a3, 0xfd04e89f, 0x2741e9c9, 0xd43d795a, + 0xf1e4d482, 0xcabe02bc, 0x626141b1, 0xae1ec5ee, 0x430429d7, 0x35ffd10d, 0xa44434b5, 0x2af1ea19, 0xd2449727, + 0x56218e69, 0x7385c425, 0xaeb33442, 0x070c58ac, 0x5f6a5187, 0xd8259985, 0x3a5cfb3c, 0x1faf4e79, 0xbf622990, + 0x916dcd2a, 0x62ce5d5b, 0xc793d44a, 0x12c32d08, 0x5c917353, 0x16d6c996, 0x58ac6de7, 0xe2569ca9, 0xf258162f, + 0xcb15bff8, 0xf3677f19, 0x499383df, 0xbb0486fd, 0xe1b9fea7, 0x1fcb8a67, 0x42fc7f61, 0x914fbb70, 0x5f72293d, + 0x71f27df4, 0x29ebf5dc, 0x4921b885, 0xa4970aaf, 0x1adeb314, 0xffc2cbbc, 0xa7b17b62, 0xcd2f6cdb, 0xf7b01f97, + 0x571bee1a, 0x69e84576, 0xb0d80456, 0x9a37d6f7, 0x8e213f4a, 0x583f36a3, 0xace4433f, 0x1cac4f0b, 0xcc156ca8, + 0x0b641bbc, 0xacb92457, 0xcaba7be3, 0x20dfc777, 0xf904afda, 0x26a45983, 0x8351329c, 0x4ec1ae45, 0x5316c032, + 0x7c5a623a, 0x3866270f, 0xfbff5835, 0x4b35d834, 0x710952ec, 0x92d1d67c, 0x766f2c44, 0x1790ee70, 0x18187988, + 0x3874ab04, 0x509fd04e, 0x816d3445, 0x7d3047b2, 0x789622a6, 0xcf61e620, 0xe936d8ac, 0xed40379e, 0xc322d987, + 0x7a3edd80, 0x3b615dc8, 0x613dee0f, 0x1c8b472b, 0x8afe0d2f, 0x3c12b1b7, 0xafaa730f, 0xa6c3506b, 0x1472df0d, + 0x2fb6abd4, 0x93e97871, 0x80fd1307, 0x9e8c7c4b, 0x5824beb8, 0xd7293416, 0x5a9b21e5, 0x0ba63513, 0x0b726292, + 0x8626af3c, 0x25a09adc, 0x53d9867f, 0xec4c53ae, 0x6f9557b6, 0x8fc62f57, 0x1e3ca801, 0x2de1b354, 0x00d06fd0, + 0x55d3bf2f, 0x64ee2008, 0x55cf635b, 0x5c752253, 0xe2a5039d, 0xc824224b, 0x91c280d6, 0x7fbee70c, 0x1af0b2f2, + 0xb911f5bd, 0x89ef72c6, 0xdf7c7530, 0x6e87d271, 0x8fd01b62, 0x77cf79f9, 0x16dc3e96, 0xf4276549, 0x7b3ef66c, + 0x097fb33d, 0xeff11dcc, 0x1fc84cce, 0x8ef39ff9, 0xd298e624, 0x2c617750, 0x985224d1, 0xb8844a7f, 0xd261bf29, + 0x7cf997fb, 0x79a446e1, 0x59289cd8, 0x1227d0a9, 0xb6a63815, 0x2040fd5d, 0x95b630bb, 0xedb08b0f, 0x432a58b3, + 0xd99c0c06, 0xc63ea0eb, 0x2d01bf4a, 0xf80f8ed4, 0x5932bcf1, 0x09426d52, 0x2492f38c, 0xd558620a, 0xcbad6346, + 0x70808ec7, 0x9ca6a7cd, 0x490b4542, 0x488bdd43, 0x33a9699b, 0xfd2d6846, 0x5d01f706, 0x90b5695d, 0x0f2a22c5, + 0x21eed0b2, 0xfe644109, 0x0c28ac17, 0x039f8d2d, 0x28247c3c, 0x74400088, 0xf2d0a7fe, 0xeaaee15a, 0xabc90e4f, + 0x4ef85f01, 0x0eb8810c, 0x173aadcc, 0x3d1ab961, 0x9740c62e, 0xd02ba5b6, 0xe54f73d7, 0xc6bd28df, 0xc937e703, + 0xd9f6b89d, 0xea80998e, 0xaf66fd04, 0x7a6e320c, 0xe641c431, 0x92f5ad8c, 0x88ed0608, 0x7468d433, 0x45646858, + 0x1f4786fa, 0xc3c1bb24, 0x2b738885, 0x1d55be13, 0xec0a9c7f, 0x58571be0, 0xf94c50c2, 0xb84e129a, 0xcdfcb030, + 0x6ac72c1a, 0x3cd58f3f, 0x1eea68c2, 0x5aea421b, 0x73abb488, 0x2445cfbf, 0x87f4937b, 0xbc3620cf, 0x77b9999b, + 0x82e3b8da, 0x37b061d0, 0xf6fd7c4f, 0x7df3a861, 0x94c876d0, 0xf6a174c1, 0xce20e6c9, 0x03875618, 0x9af1971e, + 0xe8226a99, 0xb5282c7b, 0x42d252c1, 0x5d6abc7d, 0xaa79b881, 0x4ed9261b, 0x3af656be, 0x5a0fafac, 0x66c86331, + 0x243f9073, 0xe904694b, 0x60bf0e61, 0x237e4771, 0x14eb1f6c, 0xf6e87f6b, 0x1415c925, 0x2d1d0509, 0xbd597cba, + 0xbef181cf, 0xa57db4fb, 0x60987774, 0xf7c0a71a, 0x0ff37d5d, 0xa3eb7413, 0x542db53a, 0xb2459496, 0x8c6d82bd, + 0xec7e2547, 0xce3fed8c, 0x4c3bb09b, 0x98617bd3, 0xf8041330, 0x680e6929, 0xcf638ec1, 0xfa0f3430, 0xb315239c, + 0x4605d9dd, 0x9313eeee, 0xb6d2de66, 0xf2e989e2, 0xc18f1ff6, 0xe8e71c81, 0xad7c6e01, 0x7ad8c587, 0x210e482d, + 0xb60df7d1, 0xbffe95fa, 0x5f924bdf, 0xbd551508, 0x0f6116cd, 0x3aaabc4e, 0x57057831, 0x8cfb7699, 0xca046456, + 0x2151d3b4, 0x05fe854b, 0x2d24f700, 0xd67ee948, 0x6c2eb4d5, 0x0a65393e, 0x27598268, 0xe15fd2e9, 0x2ebf9e36, + 0x6b0665cb, 0xd07bb404, 0xea0d33ff, 0x538bea27, 0xcbc41c0f, 0x9d5bb273, 0x9665f064, 0x92bd8846, 0xd67d5ea0, + 0xf9e206a2, 0x7dcd9dd6, 0x85b560ae, 0x62de63ab, 0x3609451e, 0x5b922792, 0xb53b8d5b, 0x8fe44d6e, 0xe9519b3c, + 0xec55fbe5, 0x98102f20, 0xf18804f1, 0x51adc541, 0x6bb7ec57, 0xa349ba73, 0x2a4649cc, 0x2980616f, 0xa20c88aa, + 0xb2e86647, 0x2e6dd589, 0x287b8dbb, 0xe1bab02b, 0x9765f398, 0xa02d7f9b, 0xb87d3970, 0x2cfc5ce1, 0x453d0341, + 0x748d891c, 0xd6739245, 0x6205ecce, 0x1b02fb10, 0x5d8b0a60, 0xbde95562, 0x936e103d, 0x4f518cf3, 0x497ea084, + 0x052d67d1, 0xe556bdaf, 0x8a57b65e, 0x07b63fb5, 0xfc471984, 0x8e520a2d, 0xb5c20a0f, 0x1433e185, 0xca3eb86c, + 0xb5d2321c, 0xdbceb102, 0xa872c741, 0x1969e594, 0x76e24eaa, 0xb546046e, 0x288ab0ec, 0x96e98cab, 0x60ec35e6, + 0x1b1ba7ed, 0xc2286806, 0xa1ba9a3a, 0x66c0c134, 0xce43859b, 0x3cdc9e52, 0x3a13630e, 0x4f02eb34, 0xb1686ca2, + 0x0fd7b1b8, 0xb7b47dab, 0xe3362942, 0x46bb8b92, 0x3a24ce60, 0x197cc190, 0xc2849384, 0xc545bfff, 0x91c2bdf8, + 0xa61d86fe, 0xcd549563, 0xf3389bba, 0x50dd26e6, 0x6f736ac9, 0x2d7f1f98, 0x6fb39706, 0xaea99a1a, 0x37817333, + 0xf93a909f, 0xe847788d, 0xfa5d7750, 0xef744a17, 0x28356604, 0x4e253c53, 0xe7653431, 0x364cae4f, 0xd3c41cd3, + 0x71711275, 0xbed9a4c3, 0xd69e74bb, 0x1435296f, 0xc2c03905, 0x26b17163, 0x878143b7, 0xa74f5992, 0xaae14f41, + 0x13821afb, 0xc3335398, 0x846d4020, 0x481f4d74, 0x50e899ad, 0x0c89f31c, 0x58468b81, 0xf215c957, 0x546ed0e5, + 0x37f2204c, 0xcb123a97, 0x9e46fd68, 0x3b97e5d6, 0xc9800a80, 0xe51f45fe, 0x16f7d741, 0x55d3a841, 0x531b67ad, + 0x3b6c8c67, 0xc9b18663, 0xa764f5f5, 0x5a1bdb19, 0x64c37c0d, 0x5c434a86, 0x8a7909a0, 0x089959da, 0x6d3851ef, + 0xac5ab6ec, 0x4231411e, 0x6b3f8b74, 0x19aad303, 0x5bf66073, 0x5c9db185, 0x4530b84b, 0x53c33684, 0x7dda9f4d, + 0x8835665c, 0x752a0753, 0x1bf49979, 0x97805e5b, 0x654a8c4e, 0xba49b815, 0x8fbabe59, 0x40d6519a, 0x9a55491c, + 0xfa4b6184, 0x3c366b2c, 0x5992b089, 0x815f2f37, 0x9568bd91, 0x49768b55, 0x4458d93d, 0x6b842e61, 0xdd490be2, + 0x7fd3eceb, 0xf5687c68, 0x199fabbf, 0x868e67f0, 0x9ac8fc63, 0x58e53bee, 0x4698378b, 0xbc729669, 0x90f97474, + 0xc7d8d102, 0xd941612c, 0xd70a2305, 0xdf661b47, 0xf287b230, 0xc3d1a2b8, 0x0b43007a, 0xa43778f9, 0x0a61f20d, + 0x353f316a, 0xd0d28e74, 0x6a20fd51, 0x227fe0a1, 0x58df4873, 0x88d11239, 0x587cc758, 0x52aa5bbd, 0xfff1933e, + 0x5726ba39, 0x6275b626, 0x14d207aa, 0xb196ce46, 0x22e80430, 0xdb50f4cd, 0x3800fe51, 0x51f373fe, 0x74fe3245, + 0x0a6633a0, 0x17610a28, 0x49487d3c, 0x7182a9fa, 0xf2e7c4bd, 0x2e053b25, 0x564484b7, 0x233f29f6, 0xceeb8121, + 0x4f32390d, 0x9e9d2136, 0xcd4df213, 0x1fe49bf8, 0xeea217be, 0x5bbdddf4, 0xa8266acf, 0xdc26e19f, 0xd3a3714c, + 0xfc5b2b28, 0x278a8328, 0x91460549, 0xffe1d480, 0x82dafdb1, 0xbdad704e, 0xfcac4c94, 0x85d4ea75, 0xd6373026, + 0x997b16fa, 0x7d7c7078, 0x01ec06d7, 0xcd851426, 0xf04297d1, 0x6900d554, 0x2fe485a4, 0xcbd77d03, 0x6f0d2b11, + 0x99ba9306, 0x8f05cf43, 0x4e8495b9, 0x331f9188, 0xfe9c6294, 0x6f330d48, 0x9a83bc42, 0x53c42eab, 0x00c6accf, + 0xe8d9417a, 0x8db6fa90, 0xc3f2bd62, 0xfa67d9f9, 0x2797b121, 0x59e5d932, 0x498ad99a, 0xcbe0041e, 0xc4bf13f5, + 0xa5c93255, 0xc2be7ac7, 0xe03a2bc8, 0xf2b411ef, 0xa5e36a1d, 0x86f8c060, 0xb5f00fb5, 0x44f1efea, 0x8e5f8be5, + 0x2810183d, 0x0b7e7578, 0x9f209f8e, 0xae9c8f9b, 0x030badaf, 0xecbd7aaa, 0x344512f9, 0x7a5f7a7a, 0x0f08b1f4, + 0x2b10b024, 0x8c25944a, 0xd2eae58c, 0x23c76ebd, 0x74c00244, 0x4f2a8668, 0x7027d8fc, 0x123e51c3, 0x99c81297, + 0xfee2e64c, 0x861a1968, 0xc9473b40, 0x01ff1668, 0xa0147d3e, 0x3b90ebb7, 0xfca1015f, 0xeb731533, 0x1ac749ea, + 0x326eebaf, 0xe65f531d, 0x3f0eb293, 0xfab39eb4, 0xba365c00, 0x1896d3f4, 0xfd58f913, 0x3adbdc13, 0xe6478d9b, + 0xacabae6b, 0x9470afe0, 0x6985e892, 0x8c658370, 0x773cf197, 0xbf4819c7, 0xcfd5cc08, 0x440b86af, 0x9b6a1a41, + 0xccb17a77, 0x0032d4bc, 0xb9b030fe, 0xe7f5f2f6, 0xeda2a230, 0x656ae22b, 0x08033ae6, 0xce64f324, 0x350a9726, + 0x39f7c8ba, 0x8273566d, 0xb99d6f79, 0x2a7bd569, 0x15800786, 0xeb61e173, 0xa4af679d, 0xf71db54e, 0xcd7b4833, + 0x45fc335b, 0xf768a5ef, 0x81fc052a, 0xd1a7c520, 0x5c9a3882, 0xc4c25664, 0x6c0305c6, 0x8c4d31ce, 0x1416c1b0, + 0x7943b728, 0x6acab9ad, 0xacb9c588, 0x2c91ca98, 0x6696956e, 0x7a020427, 0x4aec475e, 0xde81017d, 0xaaa167c7, + 0x2375e180, 0xafb0fc73, 0xa4664492, 0xffdc9b34, 0xc4b09b3b, 0x51cf0073, 0x463bf244, 0xb74d486b, 0x4d5a4b9d, + 0x0f9f4270, 0xb3a8108b, 0x525614fb, 0x8d09b4b6, 0x8fe11c84, 0x3f1cc328, 0xe5b243a7, 0x641ff871, 0xcae516ba, + 0x1f554376, 0x42ce0f5b, 0x34fb14ea, 0x53cb265a, 0x60920e3e, 0xe89b0716, 0xd17481ad, 0x867a34c6, 0x23c74ae5, + 0xa429e3ec, 0xa348472d, 0xe291ca4d, 0x00717b27, 0x70207690, 0xb47b78e7, 0x66f05bee, 0xe460ba25, 0x300ff9a5, + 0x58715e14, 0xc283632a, 0xb3bfae96, 0x1a120e2b, 0x40928ff6, 0x71736db4, 0x4035781a, 0x725c0825, 0xcba312c5, + 0x3acd37fd, 0xe121144f, 0xd66d227b, 0x1157a377, 0xccdc32d8, 0xf4db3634, 0x2337b399, 0x066ea621, 0x5fad1d30, + 0x3a283ffe, 0x36e83e9b, 0xfe39231e, 0x6c6d7b8e, 0x873da86d, 0x5e93916c, 0x8d589d4a, 0x76477212, 0xc2b327f3, + 0x2d3dffba, 0xbd3ae522, 0x9a7215f5, 0x36b6870f, 0x4399adc9, 0xe93cd91c, 0xc0af7e8a, 0xdc4ba6c6, 0x11103f5a, + 0xc62dec02, 0x202fb919, 0xc42184e4, 0x4ee51a10, 0xb0b234f5, 0xfe379c9b, 0x882283bb, 0xb369a91a, 0x78f0a0f2, + 0x38c58fac, 0x8eb86a37, 0xc5a22e56, 0x31c3aab5, 0x7504f617, 0xba236256, 0x373b27ba, 0xfedc4d70, 0xa20a9013, + 0x6308e85c, 0x777d5de2, 0x1c2bfd05, 0xa566e215, 0x07bd0324, 0x1254e9c0, 0xfd52eb87, 0x2e3ab35a, 0x475fcd73, + 0x107ae3e1, 0xdacd8017, 0xe0090f16, 0x91437faa, 0x7aaba5b6, 0xed82a7f4, 0x83316760, 0x79a55ebe, 0xa79732de, + 0xcefff099, 0xce65c41e, 0x15c5e98d, 0x7f4779ae, 0xc9242238, 0x341f3db1, 0x4200e694, 0x8a10a9e0, 0xc8424179, + 0xe19bb156, 0x30096585, 0x93d814c8, 0x9ea7a784, 0xf8ce90e7, 0xb93fcb74, 0x58c4dca0, 0xffb32b1a, 0x946c2f78, + 0x147473b9, 0xbd04ac89, 0xd4d4590f, 0x61e83674, 0xa217b46b, 0xb33031c1, 0x81c90143, 0xbaa5d511, 0x3f3317cb, + 0x274a72f9, 0x1ce687da, 0xce66abeb, 0xcc85c638, 0x427be860, 0xc370b490, 0xa441c0d8, 0x9d699ef2, 0x4a164851, + 0x6a736607, 0x535fbf26, 0x0b978805, 0x908db72d, 0x561b9fde, 0x2ad5f002, 0x00df3171, 0xc395ce80, 0xfe32c86b, + 0x49927e0f, 0xf197debf, 0xc01a012d, 0x39cbaa7d, 0xe36f0ae1, 0x1e92c1d1, 0x119457c2, 0xd7425625, 0x7de626d0, + 0xa954494d, 0x3ba922fe, 0x0d39507d, 0xcec78c8b, 0x35843a9b, 0x337a5078, 0x01fc64d7, 0xa6ddee95, 0x0ac0a66b, + 0x420037f5, 0xfcd5df83, 0x249d7601, 0x376cf92d, 0x3aa59178, 0x6bb17793, 0x4b55b047, 0xf58cfbea, 0xf8bfa019, + 0x50c674a9, 0xdcbbbc4e, 0x417a7aee, 0xc95ed9e5, 0xcf03e1c7, 0x8ff6e576, 0x7dd95e6d, 0x2199d379, 0xb07e93a4, + 0xe82ff81d, 0xc0cd631f, 0xf579911f, 0xec7c6b47, 0x853f3486, 0x227e9f4b, 0x25370bb5, 0x07cbd443, 0x83b048f3, + 0xb95299ea, 0xdfa022cc, 0xa4838a53, 0xc75d7fdc, 0xb074f589, 0x8f1c14f2, 0xead16dd9, 0x26d37864, 0x4a24ef0d, + 0x2328315f, 0x2427c326, 0x1a4c2d95, 0x0f06a9d9, 0x16609930, 0xc9a65a9b, 0x556a46dd, 0xc0d6699c, 0x9ce0e293, + 0xf52196e6, 0x697b4485, 0x454177a9, 0x4265f618, 0xb717a53d, 0xbd230bf8, 0xd5004811, 0x205bf7ce, 0xcf4edcd0, + 0x5aba8ec4, 0x06300404, 0x2fa0a4b8, 0xe2d279b2, 0xb36d96f0, 0x7faeb3aa, 0xc71f082b, 0x4d8b19cb, 0x7252b0d6, + 0xd69cdb3b, 0x78de809c, 0x5f609c3b, 0x944993a4, 0xc87c7da1, 0x3912a12d, 0x7c8ac5da, 0x60915682, 0x35bbec7b, + 0x89cbbb08, 0x25da14f3, 0xdd185b0a, 0xe63c223f, 0x3886daaa, 0xd14359f8, 0x533f8b01, 0x850e7d99, 0xcb5e6289, + 0x58c9823e, 0xeb135302, 0x51925f96, 0xd25026c9, 0x57e8d337, 0xb6389eea, 0xdd6dd60d, 0xbfc5a129, 0x5bbbd53d, + 0x583638bc, 0xc12604be, 0x6ceca3e6, 0x6ace427b, 0x32bf9193, 0xb08a16f8, 0x6c10592c, 0x8a5669bd, 0x4e2a2da8, + 0xf0c9827d, 0x735ba93e, 0x9912fc3d, 0xcac311e6, 0xf7722a07, 0x4fb4dda4, 0xa4ffbef3, 0xd6eb5ee3, 0xa8731066, + 0x53dffdf3, 0xa0ef397b, 0x4df2b047, 0x08a8998b, 0x57278748, 0xd6ecae7a, 0x8889179c, 0x54bd4ba5, 0x10fea964, + 0xf6937b25, 0xd15a07e3, 0x49b08274, 0xc90410eb, 0x93280a9e, 0x17c4216a, 0x990e0116, 0x74f96c6a, 0xc8a6a443, + 0x5521a1fb, 0x399f0169, 0x9ee1825c, 0x9fcc73a7, 0x88d7897f, 0xec0f2d01, 0xe9b4cbcf, 0x1e7bc0ef, 0xee83fce6, + 0x56dffe43, 0x1e74b643, 0x34c6998d, 0xe22824cc, 0x1a5dfef2, 0x5711055b, 0x36603e89, 0x392a08a2, 0xb9fffcd7, + 0x6384cf15, 0x578850c9, 0x2c0c5eef, 0xbf5b12ee, 0xc4607343, 0x525c8af2, 0xeb09ab4b, 0xfd019eec, 0x5ba179be, + 0x35c58081, 0x4888b0f1, 0xccd0d805, 0x3b360af4, 0x2ddb6652, 0x76f625e3, 0x71eef894, 0x9a88f6bc, 0xd83bda25, + 0x6bf0593a, 0x9d62ab5b, 0x1b9a9e06, 0x927e861a, 0xcb05f5ef, 0x501b704a, 0xb0d385d9, 0x0de52aba, 0xc203fb7b, + 0xcf06669a, 0x11f38341, 0xf823357f, 0x093a8b80, 0x46915b06, 0x59b8c8e4, 0x10c6045d, 0x328bad89, 0x1f3de084, + 0xe0618a73, 0x22cc9c37, 0xc7f28572, 0x94849bcf, 0x8efa0348, 0x4e3acd50, 0xef954f19, 0x2431c8b5, 0x88fb1d67, + 0x71d95ba9, 0x8ef372dd, 0x6bc4a5f6, 0xfb275c39, 0xbd4cbaec, 0xc3c34273, 0xcf212783, 0xa6af8c3d, 0x0d28ceff, + 0xcea1f458, 0x6db004c4, 0x7840a33e, 0xa4e94d80, 0x3ff26d8e, 0x42ae8961, 0x3b18a3d1, 0xfaf271b3, 0xbc1dc459, + 0xd7e90b56, 0xa93493af, 0x908d6c2e, 0x036b9799, 0x43aa3cd1, 0xb019c32e, 0xc077844d, 0x056bf5a3, 0xa39d4412, + 0xb0a3c4a2, 0x50abada0, 0xa3a62f0e, 0x06970270, 0x82ff3e33, 0x00b23c38, 0xd443c6e3, 0xcb1c0066, 0x41f0699a, + 0xe87a62f9, 0xa6499183, 0x5f878f96, 0x388f0217, 0x65a2838b, 0x89ad9e5d, 0x1b2cf897, 0xbea3136c, 0xc300f949, + 0x052aba44, 0x74287658, 0xad66a4a6, 0xf320b9a6, 0xfd9ceaa0, 0xd99a22df, 0x9e8a433c, 0x141edb84, 0x95349d27, + 0x64c07d03, 0xde69c4e0, 0x5918dff5, 0x24675df1, 0xe39f797f, 0x2231f3da, 0x65648cea, 0xa3ade580, 0xc426ab76, + 0x5676bb80, 0xf671d6b8, 0xc5036d7a, 0x69cda7f7, 0x4429a64d, 0x5eb16cc6, 0xe4aaa923, 0x3d5ad2e9, 0xd0fa1b10, + 0xf6f693b0, 0x5ab88bd0, 0x99c839a5, 0x216fa9a2, 0xbaa15d73, 0xdd0c6155, 0x5ff276b2, 0xdfe83bfd, 0x166add96, + 0xbd600c52, 0xa369bcb9, 0x071d436c, 0xbb0727ac, 0x7c2b82a8, 0x41ab4f89, 0xc0373f51, 0x1ed8c401, 0x7e431de3, + 0xb2637b38, 0xfc9d356c, 0x69b1b3d6, 0x0e594516, 0xb32cb2f8, 0x8d1474da, 0x4dca4573, 0xd55178d8, 0x21b0d87a, + 0xe860a4a7, 0xc6eda890, 0x5756e399, 0x80e0c1cc, 0x62be3120, 0xadf313d4, 0x6a3db3c8, 0x71e4ad03, 0xe9382a67, + 0x35b3fc82, 0x382defaa, 0x22dd85af, 0x6bc400c1, 0x553b5832, 0x0dc4a9ac, 0xdc0c488f, 0x66ca66fe, 0x98c8868d, + 0x2d736c50, 0xfb404f94, 0xb85b5a22, 0xb73cc1e5, 0xe3e4d050, 0x898628a9, 0x0b22c9ca, 0x9ddf3835, 0xbdb80a15, + 0x613ea532, 0xa422975e, 0x3600c98f, 0xafa9847b, 0xeb8af509, 0x2ec60ff0, 0xb01a30fc, 0x241f0b40, 0xb42cccbe, + 0x1361eee5, 0x2aa880ba, 0x63a56bc8, 0x943e8405, 0x8cee3c61, 0x2dde7aa0, 0xcc7248c0, 0x99fbb47d, 0x3fba39e0, + 0x92d673db, 0x30d9eede, 0x01ab0323, 0xf489356a, 0x0d053314, 0x3dbd4306, 0x8126c5bb, 0x800ebc9c, 0x55c08317, + 0xfc57be9a, 0x5c982dfe, 0x20e4a231, 0xaf6303bf, 0xabd6e84d, 0x37ea2a13, 0xcf438621, 0x5555c545, 0x8d812054, + 0xfc5b54c6, 0x41a2e462, 0x5d675570, 0x64eac043, 0xa8831eac, 0x6f1c2439, 0x0ce02503, 0x64615e8b, 0x65f685fc, + 0x8273d512, 0x1638d3eb, 0xb48abf32, 0xa268c76e, 0x208a2374, 0x03beacaa, 0x77c17c4b, 0x73e961ca, 0xca2d1344, + 0xb0d10bb8, 0x272b54e1, 0x553d35ba, 0xb2e77ebd, 0xae1e7526, 0xa6ace50c, 0x59695e38, 0x16cc3a79, 0x9ee57ab6, + 0x5df8d096, 0x9ea99bda, 0x008480d3, 0x680bb5f4, 0x49566ba2, 0x4151fb05, 0xb18aa96d, 0xb755f4b5, 0xef0d727e, + 0xac1ecbae, 0x97a36656, 0x5bdfda11, 0x912432c4, 0xc5bee69a, 0xad72fda9, 0x0eb575be, 0x7ad42427, 0xb1be10bb, + 0x593349d5, 0xb26b14f3, 0x672e630c, 0xa9ea446f, 0xd8cfa8ee, 0xcf5eb521, 0x4e6881bc, 0xc926c238, 0xf193ecf2, + 0x2025b3d9, 0xa6c97496, 0xe51cf3c9, 0x0a92dcac, 0x9ad9334c, 0xd74274ae, 0x5a73ff3a, 0xd8292d63, 0x436be20f, + 0xc6e585a6, 0x82660d00, 0x69e6b994, 0x661e2b8c, 0xc85c602f, 0x9daf5f0e, 0xfffa1546, 0x83a11b4e, 0xe9f3d57d, + 0x12927005, 0xfb78d5a6, 0x85d0f634, 0xaecde0f6, 0xd049f046, 0x3378d97a, 0x148c36cf, 0xb761bcae, 0xb5523f8f, + 0x32858a6e, 0x842d86be, 0xa9cba644, 0x9b0fe6bc, 0x67db8207, 0x24e9c2a4, 0x80c2ccde, 0x3da78a00, 0xaed24142, + 0xeb9117bf, 0xb7c61fb6, 0xd21157e9, 0xa23a33ea, 0x0f662c27, 0x6616a401, 0xf8aea11b, 0x9aacf166, 0x837501a3, + 0xe17459af, 0x58bd1279, 0x7ace1193, 0x1e435695, 0x57b20948, 0xc2a0877c, 0x991b4188, 0xf9b32a8e, 0x7a97ccac, + 0x0300fa00, 0x2aa55b9c, 0xb57da59a, 0x4a537d52, 0x43cd62ba, 0x1eca3261, 0x279e70a7, 0x6a150816, 0xeafd4cbf, + 0x718cd66d, 0x3cc752e6, 0x4af05c9e, 0xa938d29f, 0x48a03b38, 0x0e987068, 0xe178815d, 0xedf6c9e8, 0xb2c12dca, + 0xa46ed5ba, 0x1b40e3fe, 0x7ce86cc2, 0x6a2bdd72, 0x6d220d15, 0x2292f925, 0x7f6cd409, 0x0f53fd48, 0xd066e52e, + 0x311eca99, 0x1b6913b1, 0x42193108, 0x018ed38c, 0xa90dc55b, 0x2d64d54c, 0x96b74e03, 0x13cd7b80, 0x6397c81e, + 0x000de3ef, 0x4811987c, 0x619fda69, 0x933412b0, 0x7c614731, 0xaf44a1d7, 0x6010e754, 0x4844e735, 0x1dfc6afa, + 0x160cc70e, 0x1e56d6ec, 0xd71065a2, 0x2b24404f, 0x5c9a62ed, 0xa7eb5add, 0x7a8096a8, 0x019a6cbe, 0xcd61c110, + 0x49c65746, 0xc59297a9, 0x220241ab, 0x01b9e7a8, 0x86d63017, 0x325d92ee, 0x47f2dff4, 0xdb8cf099, 0x995d873f, + 0x75fe5e06, 0x79d00390, 0xb2a460a5, 0x61dcdcab, 0xcf81cece, 0xe7e10490, 0xe29b710e, 0x02ec6bd4, 0x5a700590, + 0x79afcbc5, 0x99296b84, 0xaee95b68, 0xc5a9fe94, 0x343ef0f6, 0x95768806, 0xf84af277, 0xfd2ffc0c, 0x0b00eb12, + 0x32faf54f, 0x78b5c462, 0x64296a4c, 0x48e717ed, 0x077b7054, 0x5354644c, 0xf302d36b, 0xeb3fa732, 0x961732c3, + 0xe25bc670, 0x89cff261, 0x66abc2ec, 0xb66112c4, 0x4916a5fb, 0x227cfcb4, 0xd7307b5e, 0xe12b3b64, 0xbc367346, + 0x1aa6d287, 0x8bfbddaf, 0x7d5f6ff9, 0x7cdf61a4, 0xd3848030, 0xa5d19109, 0x84e9834a, 0x4610dab5, 0xcf22716d, + 0x4812f58b, 0x0d5b5205, 0xdf7fb74a, 0x67cbe11f, 0xed3e53b6, 0x15d6bc1d, 0x5ee9b1bc, 0x35d696c2, 0x34afb0ab, + 0x84ae83b6, 0x1137d9f4, 0xe332f248, 0x68a9d658, 0xd37d2aa4, 0xd5106aa7, 0x003c7673, 0x9ab8f412, 0xa78bdb52, + 0xfeeb47a4, 0x80e61959, 0xcb477c2e, 0x6476bc43, 0x27e81d8f, 0x1865255a, 0xd9250900, 0xa05cc457, 0xf5e12541, + 0xa5fafcfa, 0x8ad4a036, 0xfe8c6051, 0x4d78474b, 0x162de9c8, 0xc49f0591, 0xfff56e90, 0x7ff6e839, 0x20fdd536, + 0xe9ea9efd, 0xec175e1f, 0x5a64972d, 0x28353584, 0x43a136a5, 0xa5111b01, 0x488d5746, 0xdcf66300, 0xe0f751c1, + 0x4bed62c4, 0xc58a6aae, 0x8facd5e7, 0xb3f37c81, 0x93fea56f, 0x249da492, 0xee63b5b3, 0x5b901631, 0x4cbb9997, + 0xb4fefbf1, 0x748b98d5, 0xfac9b465, 0x56fc82e6, 0x7e956786, 0x0c3d31c3, 0xfba5096f, 0xf4cae323, 0xbfd34ec3, + 0xd4635fcc, 0x16885129, 0x632731fb, 0xd9d9b1ea, 0x66cce756, 0xcd42c331, 0xed261564, 0x602b247b, 0xe59dee8e, + 0xfd5d5303, 0xd1aa00a6, 0xe2006315, 0x77964c77, 0xf5f21011, 0x492f0bdd, 0xc958ba4f, 0x34878d4b, 0xaea7ce93, + 0x60e0743a, 0xe328d817, 0xeef4698a, 0x4a784e9c, 0x2232e3a6, 0xf5ca39b5, 0x0a679909, 0xd3bf1aaf, 0xb2bb26cf, + 0x57fc6be5, 0x9bc365bd, 0x1b41c83e, 0x44b06a8e, 0x3e90253e, 0xdc5cb19b, 0x50876f6b, 0xd7df921e, 0x43103f7b, + 0x9fe4cda3, 0xbd656c6c, 0x2e4843cd, 0x013355cf, 0x6e3cc0f9, 0x93e60f83, 0xb143d756, 0x29cb87cd, 0x9cd2bb3b, + 0x06319dff, 0x171625fa, 0x5cb104df, 0x08c9ecde, 0x153d47e0, 0x83030da2, 0x66fa6f1c, 0x771dd239, 0x5201293f, + 0x0d7a3699, 0x36d79685, 0xec71d05f, 0x8fda5126, 0x2c0e7ab7, 0xbb1224cb, 0x296a3cce, 0xf03730e4, 0xb9948ac8, + 0x68cb3b65, 0x580051fc, 0x940048e8, 0x80ce885f, 0x610e60db, 0x4d9ca75e, 0x2d066575, 0xe800c329, 0x3b7bb3ec, + 0x7d76475c, 0xd2bdf51d, 0x7608a66d, 0xfc777296, 0x850a0e46, 0xad637011, 0x43112d2c, 0x9e0d6133, 0x7e302fc1, + 0x94d6fc00, 0x80c24be5, 0xd33608e4, 0xfc7482e6, 0x8e8e4f35, 0x3293c8f5, 0x68382b61, 0x3eabe916, 0xab251b12, + 0x68611bed, 0x74610824, 0x25a1b76b, 0x04ef24d7, 0x15a2a998, 0x52ab171b, 0x022b24a2, 0xb88d04e2, 0xcd520d58, + 0x212726b5, 0x1286b8bb, 0x653d89f5, 0xbff46acd, 0xb10e95f5, 0xe6810702, 0x7f727768, 0xe9d2f532, 0x1dd4c0ed, + 0xb05fda61, 0x2d1581bb, 0xae7bce6d, 0xfea414c6, 0x40b673ea, 0x14c5ba03, 0x37d6d05a, 0x547371be, 0x6df72f80, + 0x46456415, 0x36425f95, 0xf00a8757, 0xa60b7a8f, 0xc517babd, 0x456ec276, 0xf742ef89, 0x03dcc183, 0xb1eee0e1, + 0x4ec1bfcf, 0xb7b7a029, 0x2c8cd9dc, 0x2f2eb043, 0xe0f4b3fe, 0x568a0ede, 0x01d851e0, 0xc9fadd1e, 0x077860e7, + 0x645777da, 0x0ac1d596, 0xeba83898, 0xc69e1358, 0x7e660775, 0x20c24ca8, 0xd93abc41, 0xd73b0dea, 0xbee53fa2, + 0x22b70e88, 0xa565700a, 0xe86e883e, 0x1ea2240b, 0x829ec299, 0x49bfd3d7, 0x32fd54d9, 0x58021814, 0x3ae0a881, + 0x3edccc75, 0x2ae099e9, 0x64a6adbf, 0x0ce23160, 0x792c9fcb, 0x9327eb3d, 0x0560522c, 0x0d7b3329, 0x09b89748, + 0xd55f6a0d, 0x5ce6b3d5, 0x800a69e5, 0xfd36c767, 0x226db327, 0xce7775e9, 0xc6727d22, 0x2439effa, 0x08f63308, + 0xc60d21a1, 0x8a085964, 0x8a8ac999, 0x5f5da3ed, 0xe42c9e60, 0xcf0835bc, 0x7a5217dc, 0xaf707fd1, 0x5ff75a7b, + 0xe20dc6c5, 0x665abd96, 0xb81a070a, 0xaaa28898, 0x2a04de08, 0x5431fea4, 0x6fa0cd5c, 0x50cd1884, 0xe796fb20, + 0x712e6ffd, 0x728a7246, 0x3c9e8d97, 0xea4316e9, 0xb10ab467, 0xce63e992, 0xa21ec86e, 0xae4f3989, 0x5c6f8882, + 0xa4b0e7ce, 0x0547d8ee, 0xd875d7a1, 0x9edb6b91, 0xe48f7535, 0x2592eb6c, 0xa22d310c, 0x3ef657e0, 0xddc57831, + 0xda7b50ae, 0xbcff1f97, 0xbeebfbed, 0x833f647b, 0x9267021e, 0x96f897d6, 0x65a644cc, 0x3cb1d317, 0xc4ff28b3, + 0x32cfd8af, 0x945354fa, 0xd3496d03, 0xce92c26e, 0x4f894477, 0xd2dd0a35, 0x85b371f0, 0x03174c29, 0x591a6b3d, + 0x020e2f53, 0xc6b70028, 0x5622545a, 0xcbc5d99f, 0x1293a59e, 0xf598e8c5, 0x3f51091c, 0x17341137, 0xf8434b00, + 0x52f89e7c, 0x742de39a, 0xed411654, 0x3f37f830, 0x9e9d2b5d, 0x7dd17175, 0x5aa30384, 0x04fe1f17, 0x8ff2db58, + 0x1e4385a9, 0xf43b23db, 0x5ddcacc9, 0x5260cfb4, 0x121c4331, 0xb29ca3b0, 0xe36501f5, 0x9b1d0bbc, 0xd9827ae4, + 0x49a73d05, 0x10e2c7d4, 0xfc116fa2, 0xfe7df533, 0x7cfb0f52, 0xab6853d1, 0xe049aad4, 0xe6a5755a, 0x8530a941, + 0x20132c52, 0x76e4e500, 0x204ec8a3, 0x84fb7c2f, 0x9525c427, 0x70a5da6f, 0x5970cfab, 0x038df4f0, 0x273d893c, + 0xfb54d8f7, 0x8181ab56, 0x562dd26c, 0x453892b9, 0x1d49a975, 0xc039ca87, 0x7e4ab821, 0x29a868e3, 0x55da4bc0, + 0x4fb6babf, 0x7e482c37, 0x68ed72d5, 0x268e9c51, 0x3b02adbf, 0x0eacede2, 0xe2f6cb1a, 0x8d4448d8, 0xe2810e6e, + 0xf9759d83, 0xfa0b87e2, 0x5b6774e6, 0xd6a56180, 0x4af18c85, 0xb267373d, 0x44a13e0d, 0x0a41af96, 0xda0f2e92, + 0x0f826b51, 0x986ff8b0, 0x690cd3b5, 0x358f9b63, 0xc9d206c6, 0x9c0330dd, 0x21f4302f, 0x5c66589b, 0xf26f9481, + 0x1402f26c, 0x8dcef613, 0x35024c7b, 0x2899ec30, 0x358b79fc, 0x5fa7bd63, 0x05d782ee, 0x3a97433b, 0x91ae21d3, + 0x16cea925, 0xc5638318, 0x12c44e2f, 0x752bc76b, 0xbfef2c06, 0xe9a041d3, 0x6048c188, 0xa2da6237, 0xdc371519, + 0xe44f6e39, 0x2d7a088b, 0xf57f3345, 0x6b416a10, 0x3c9583a9, 0x7d05c13a, 0x6c48b5e4, 0x8ab95bb2, 0x8681e790, + 0xa333573b, 0x33d5f717, 0x33b8e304, 0xe9ade4a3, 0x0ef870a9, 0x7c8a8dca, 0x017e3523, 0xb7f96a31, 0xc704382f, + 0x4ecc5a85, 0xfb6d8f26, 0x0f1303ac, 0x3f057099, 0x830c34a7, 0x1ca290a8, 0x7ba5af81, 0x644800d8, 0x4d970cbf, + 0x24a1b330, 0x51646771, 0x6253f341, 0x51fa662d, 0x2fa95a76, 0x98babef9, 0x3b6193ba, 0xbb5721a2, 0x48f5a90a, + 0x7e515045, 0x75a7871c, 0x76f52e18, 0x0b71d7f6, 0x2e5bb96e, 0x3cd211d7, 0x648e6be5, 0xd367b307, 0xb9a2f9a6, + 0xd1c427f1, 0x5a1dedd9, 0xdb5daa0a, 0xb99092eb, 0xb8ec6742, 0x811e2592, 0xc4099cdc, 0xccd2af66, 0x5fe81c30, + 0x778c7e95, 0x0104e00a, 0xd32b460b, 0xcc27bf29, 0xea31f3ec, 0x35bcf52a, 0x55ea721e, 0x6a8b1149, 0x909cce08, + 0xb0fec3c4, 0x7ab33071, 0x9adadda8, 0x276b0446, 0x9a5041d6, 0x752e8466, 0x9b1587d1, 0x02962f4b, 0x70c06e0c, + 0x67bf442a, 0x1c08be47, 0xe7b5ff73, 0x03841613, 0x01c68f6c, 0x5a5f6787, 0x9aee688e, 0x4900684c, 0xa1a34940, + 0xb40b740e, 0x2df489f1, 0x5c875e4c, 0xc0dbd58e, 0x2fbf677a, 0x74a428d2, 0x50453565, 0xe6a4b498, 0xfa5f6d2c, + 0xee236fc0, 0xccb9c6d6, 0x8e1b40d8, 0xa7ef0bc7, 0xe0f4e15d, 0xf83c6381, 0x2c486c3c, 0x24b1d446, 0x559470fc, + 0x056fb16f, 0xf6dda543, 0xa2b4c39c, 0x69c437ce, 0xc0b1e716, 0x2eccb3a5, 0x6ff66e1a, 0x6c112936, 0x047d920e, + 0xf917ccca, 0x50c1bf18, 0xef5680dd, 0x14d47cac, 0xd3ee2fc3, 0x5203994e, 0x0e7da6be, 0xea6bb39d, 0xc8da89f0, + 0xcbed8194, 0xfeaa0e69, 0xb43ab729, 0xbef37fa8, 0x3abb850e, 0xfa838878, 0x9356c784, 0xd8f981cd, 0x553dc6d4, + 0x881c2f73, 0x94efd97b, 0xc98d7d66, 0x3471d0bd, 0x8678692b, 0x224748fd, 0xb8edac4a, 0x4b855393, 0xb93176ad, + 0x989b763f, 0x6d3e3937, 0x2593cfdf, 0xb524f2fa, 0xbceff2bb, 0x8bd496aa, 0xf8ed2444, 0x88c454e1, 0xe104e560, + 0xab87e817, 0xeb158350, 0xcd5efd3b, 0x46525919, 0xe6cfbe69, 0xbdd02ea5, 0x1e81150e, 0xe6f2e1bf, 0xb4872e7e, + 0xad266ebd, 0xca09036f, 0x41b8b40b, 0xcc32c43c, 0x1475ccb5, 0x54916930, 0x28d897d8, 0xa68f0559, 0x102e9e5c, + 0xd28fbeba, 0x199efcf1, 0x6d94f197, 0xd58a48c2, 0xd9fa67b6, 0x58a84102, 0xb4c996b1, 0x1a7d8922, 0xb3a8e947, + 0x45db7526, 0xe40670a1, 0x3027d215, 0xe7e5649a, 0x54f2125a, 0x123763dc, 0xbfbe6e24, 0x3a5062a5, 0x1b848e62, + 0x5da4e0a3, 0xf1204533, 0x62df24b4, 0x388c2c1a, 0xaffd2f64, 0x1c65cd4b, 0x0875d5e7, 0xf7a8dc45, 0xd0c47d4e, + 0xb2aea2c2, 0xdbc6c30f, 0x7d69447d, 0xb32b9e9e, 0xfaad5da2, 0xaef767f2, 0xcf5bc8c1, 0x33797ddb, 0xe0a5c7a8, + 0xf8319c66, 0x02232a6a, 0x13e31528, 0x4b4c082e, 0xb27ca295, 0x7084da19, 0x102cee0d, 0xe865aa22, 0x29d33a3e, + 0x98b33598, 0xb4ff7d3c, 0x189e9317, 0xdf0e6a57, 0x625215b0, 0x1a93148e, 0xfe611fff, 0x3a7ae45b, 0x293e4caa, + 0x9110ac94, 0x580c3e8b, 0x021ce64e, 0x2bfb9489, 0x784c1ca2, 0x0cf2352d, 0xb99167d1, 0x2b84c494, 0x7bd5b0b5, + 0xc842f325, 0x6d82792a, 0xd3cbae40, 0x8542c7e6, 0x2a045d4c, 0x855ac21e, 0x830d027f, 0x12bf6536, 0x0b3ea589, + 0x3b3f5d0b, 0x4eb16d2c, 0x8181a67a, 0x50373082, 0xa99cf887, 0x010fddd4, 0x19289788, 0x7791fe32, 0x8471c098, + 0xa5f2cf62, 0xd1eae5b0, 0x7e72a0e2, 0x0d0d620d, 0xd88a0371, 0x3c84096a, 0xdc1ec43d, 0xb45c2972, 0x55bbcd2c, + 0x378d93a9, 0xaba6db26, 0x56bea573, 0x116861d5, 0xcd77d6ea, 0xcf4f7cfd, 0x66f30248, 0x4f1808a8, 0xa5a08dc1, + 0x9521e565, 0x37d1ebbf, 0xb55afee5, 0x7220a70b, 0x529fd7dd, 0x2d6ec835, 0x14ead7ca, 0x3b63f507, 0xff014826, + 0x495b2e49, 0x55f302b3, 0x995c8d8f, 0xe2085ebb, 0xc129464c, 0x8483c28b, 0x4afff7f9, 0x54fe77e3, 0x2980f4b0, + 0x0a6d9fa1, 0xecfe03cc, 0x59aefe4a, 0xc7dfbcf8, 0xb433027b, 0x1d27d04e, 0x7376a4c4, 0x8d8cb899, 0xfce8cd58, + 0x4267cf72, 0x30e842fe, 0x76d2e522, 0xfa28982b, 0x264098b5, 0xb1f0eb48, 0x84a0078d, 0x51555fae, 0x31c08ce3, + 0x55322057, 0x5fa2fb3b, 0xea536f69, 0x3c6b00b6, 0x5ce931be, 0x88d4b503, 0x67ef2f39, 0x8afc82a7, 0x33c14762, + 0x0a03789c, 0x0055ba4f, 0x5e0107d5, 0x3747cb8c, 0x70a445e1, 0xb940c1b5, 0x8ee0bb51, 0xaa46506e, 0x84882681, + 0xc45a8805, 0x5d99ff00, 0x36769d4b, 0x24bbda15, 0x4d70cb56, 0xf00bf9e5, 0xd2939a39, 0xe026ed55, 0x9d54d0b0, + 0x559fc257, 0x3c352cf5, 0x436de399, 0x5ddc1b47, 0x2bb21450, 0xd7dc7873, 0xe9cfd209, 0xd4c0c121, 0x08a6bd08, + 0x534ea6ce, 0xc02cb453, 0x14c5bc8d, 0xd2541e48, 0xda5be7f9, 0x04f161a4, 0x4ab4e205, 0x456d0261, 0x3dbeaf82, + 0x3193a784, 0x7bf0af29, 0x78f98dff, 0xfc45e16c, 0x3fa9fc74, 0x04b62084, 0x7f26550b, 0xa611e4a8, 0x43bfafc2, + 0x544b28f7, 0x57a37990, 0x03168868, 0x4ef1973f, 0x7648a524, 0xa7cbc3dc, 0x8cf4e9be, 0x3b610e7e, 0x08b4cf8f, + 0x2b59228c, 0x8d9d6ea1, 0x805de47f, 0x531c76fc, 0x250079b4, 0x094550bd, 0xd4c1e646, 0x19d90b67, 0x2acc5b98, + 0xbaf29847, 0x0b88817c, 0x1a5370f4, 0x76676590, 0x2b199df5, 0x29a4be6b, 0x8c95e765, 0x45e44182, 0x5e5cfb6e, + 0x18bfaceb, 0x1b7328c8, 0x542b038c, 0xcb79e3cd, 0xbb62b3fa, 0x91c3fe5c, 0x71e522c8, 0x01242509, 0xb9e1421e, + 0x201ddbd8, 0xd8190dbc, 0x15a3c86d, 0x52d12331, 0x5e9bc349, 0x76daf358, 0x9e7212bc, 0xdf8ec5cb, 0x34ce601c, + 0x0d423552, 0x63be8003, 0x807c479c, 0x0fd8d2e2, 0xd885337d, 0x050ccf8b, 0x9e38bab0, 0x5a68b973, 0x3f0982d8, + 0x97e3d82e, 0x0c09a35d, 0x1fa766e9, 0x08be34c0, 0xc63422de, 0xcbaeebb9, 0x985fc11b, 0xdfad20e3, 0x5a7bd17e, + 0x106e7453, 0x81d320f0, 0xb39106ed, 0x81f9eae8, 0xeb442019, 0x2752dcdb, 0x1af7cde9, 0xd9dfea61, 0x5861b8cb, + 0x35656ade, 0xc7881d51, 0xf316e97c, 0x3de0e4de, 0x9decbfd1, 0xa1aa73dd, 0xe3491726, 0x80c72e46, 0xc07f2ab0, + 0xeb7a3876, 0xc14e00ab, 0x8623ce30, 0xb9a23060, 0x83a161ac, 0xd7a47e1b, 0xb59a88b1, 0x7586e80d, 0x2bfeb233, + 0x1e78b11b, 0x1b90aeec, 0xccc60c43, 0x7d976156, 0x40df4c9c, 0x008e62b3, 0x4a72bcb6, 0xdcd93ba8, 0xbf12c9cf, + 0x202ee441, 0x7448a18a, 0xae07b354, 0xfa042985, 0x24262da3, 0x4968ebda, 0x61b0e826, 0xa49497f4, 0x504313a6, + 0x47e9134c, 0x3bd197a3, 0x577cb93e, 0xb7d2dc04, 0xc9fa8c71, 0x24112120, 0xde3c7eed, 0xd885cd21, 0xc802a81a, + 0xb64c9097, 0x516ededf, 0x9f6f08a4, 0x6b54bfb7, 0xb618c953, 0xc8185d11, 0x734e4d90, 0xbbcbb3bb, 0xf740482e, + 0x9faa1e71, 0x359a75aa, 0xe4817ff4, 0xfb5a5207, 0x11d9bb32, 0xf9c573b0, 0x4c9d5ecd, 0x87a6a80d, 0x9450dd8e, + 0x2191b691, 0xae7db4bd, 0x8599e479, 0x006bf90d, 0x2db66c06, 0xc589ec6b, 0xe3d8c35c, 0xe200fa78, 0x35bc6892, + 0x7b283729, 0x23ed73e4, 0x6488f643, 0x11495d76, 0x18f2bf23, 0xfb15c0a5, 0xec22f4a4, 0x34d8a90a, 0xa313f866, + 0x4b458d76, 0xf266da9e, 0x3a79dad4, 0xc08ed2a1, 0xeea708ed, 0xa18312a5, 0x32a8c9c3, 0xccd9fc7d, 0x59204ad1, + 0x1233571d, 0x14a87762, 0x3fac8276, 0x29dac6ef, 0xe1578481, 0xb3305342, 0x58c826de, 0x9b5ce418, 0x48b5c248, + 0x136d3584, 0x65892fb3, 0x2af40d0a, 0x0ee0aa9a, 0x6e41006a, 0xac6e583d, 0x0ee88838, 0x4577b7cd, 0x313aaf25, + 0xd6efe694, 0x58bb38db, 0x1bd9c04d, 0x1fadff01, 0x69f68b2f, 0x2ea625bb, 0x2a615245, 0xb609a01b, 0xac0d84e9, + 0xc8b1f9f5, 0xde23f9a4, 0x4200b14d, 0xfb5cb5fc, 0xdf381a85, 0xe9d61fbe, 0xbca43440, 0xeb5aa53e, 0x3ae02998, + 0x6cc36f87, 0x7308f8fc, 0xe34697b5, 0xfc090b98, 0x910b31ff, 0xd7c708b9, 0xbdf0cd6c, 0x33a7d593, 0xc7ab4735, + 0x3ca473e4, 0xf25c30c6, 0x35d8652f, 0xbe260ec9, 0xc3c4f63b, 0x90d80e88, 0x7f15281a, 0xce38d2f3, 0x6219fb60, + 0x14834084, 0xc484497f, 0x8e72187a, 0x64cfa999, 0x66694774, 0x413bfc9d, 0xa1e55385, 0xd4304fcd, 0x495c0a8c, + 0xefa1fbf1, 0x965fd2d9, 0xfaf8900f, 0xbfe92213, 0x6a11e8b6, 0x214c7efb, 0xc22192a7, 0xde664796, 0x4e456226, + 0xf80c88ee, 0x40818d8a, 0x61aa0b2c, 0x659ec9b0, 0x4df0972b, 0x81664e2f, 0xc9005445, 0xf8b6cf53, 0x1843ef1f, + 0x4f45d67d, 0xd0e5616d, 0xddb603ac, 0x31b108de, 0xb321b32b, 0x8d6df76b, 0x2afa758b, 0xc8a197a5, 0x8314794f, + 0xdde142b2, 0x4476d2b1, 0xa8bee81e, 0xd4581380, 0xa759850f, 0xeae44f55, 0x59bbc05e, 0xe9a0855c, 0x8c4fdade, + 0xc0cc24a2, 0x2a52fecf, 0x29509a52, 0x7ad8ced4, 0x94221eff, 0x4b6d2fb6, 0xc2bda2b2, 0x63d93ba7, 0x1c04b6e3, + 0xa5e2343e, 0x90bae978, 0xd7610284, 0x3977ce36, 0xa1680d9b, 0xc37ec704, 0x465c4dc2, 0x6f882a8b, 0x15f4b660, + 0xc2e15295, 0xaeb10d29, 0xdac64c61, 0xc0b3408c, 0x439973de, 0xbfc5bf2c, 0x23421531, 0xb76d79dc, 0xf902e672, + 0x774c6689, 0xa49cf224, 0xc87a829e, 0x5876c089, 0x34fc109c, 0xff91f6c6, 0x2e716924, 0x502894cd, 0x34d26d86, + 0x0f994f60, 0x6e178aa9, 0xe5164721, 0xf7bd2e41, 0x7dacbc73, 0x9a285996, 0x76d90a46, 0x829811f5, 0x2a2a781c, + 0x764e73ea, 0x869972b7, 0x63f5ef45, 0xe8ebf494, 0xa8faffbd, 0x5c7ab779, 0x3ed11f67, 0x01e217d9, 0xf91a7b55, + 0x9f0f6df3, 0x5593c2b5, 0xc8c74990, 0x80579194, 0xd2a62f72, 0x5bb9329d, 0xaf1d02aa, 0xb4f9e0bc, 0xfbfa064c, + 0x7baeebf0, 0x7bba8f6a, 0x6a90f1c3, 0x72e53dba, 0xfdb51268, 0x5ff33805, 0x9397df9b, 0xd903780e, 0xd25f2f34, + 0xb3b0982f, 0x8e08fb8e, 0xb4f383da, 0xd7bc4467, 0xd46775a4, 0xdbdca38e, 0xed4b5a5d, 0x8aea16c9, 0x4c5aa20a, + 0xd31e9451, 0x329398d3, 0x972f4c0c, 0x951920bc, 0x1ad58654, 0xab894095, 0xb938b93c, 0x777e40dd, 0xff22f2e6, + 0xe77729c6, 0x28c3544a, 0xfcda6d81, 0x3f09e2fc, 0x334bd857, 0x99793a8c, 0x9fa3959b, 0xa2d6501d, 0x324206b4, + 0x3e3036a2, 0x62c4fdf6, 0xb7a11cf9, 0xaca0eb45, 0x36510dc1, 0x81053088, 0xa78f0721, 0x345e4dd0, 0x60b03c75, + 0xc57a651e, 0x61302c9e, 0xde81c1b1, 0xd5355cd0, 0x567a7775, 0x6e371b1a, 0x208d63dd, 0xd11e9306, 0x51d1bf3b, + 0xea153541, 0x5da4eab3, 0x3bae8ba2, 0xa392c350, 0x43a1a526, 0x403da248, 0x7a9cb301, 0x089b61a0, 0xe4d9860a, + 0x2dff22d0, 0x90311820, 0xd9b534e2, 0x5cff838c, 0x8298fc6a, 0x16ef9bdd, 0x9a917778, 0x182e5b48, 0x6781cb31, + 0x7a0d6591, 0x0be39d3e, 0xcca08b46, 0xa8191ecb, 0x0a85f579, 0x8821bf03, 0xc143e83f, 0xb2c3d67d, 0xc8b96994, + 0x863501fc, 0x092fd774, 0x2a52ce09, 0x30a9fa67, 0x19d79fe2, 0xacad5ae0, 0xbf9292ce, 0x4246bf2d, 0x725c41c7, + 0xe44bc8e2, 0xa4881172, 0xfb6783e0, 0x1cbc40d6, 0x35255b52, 0x5c24ba9d, 0x3c25b2ee, 0x10b6ae52, 0x25574809, + 0x46eab827, 0x4a09c936, 0xe241d60c, 0xaf384e40, 0x23be90c7, 0xd3feae87, 0xa93e63fa, 0x8189130a, 0xf8512b30, + 0x9a83e910, 0xc2e498de, 0xe5a7cd26, 0xf8c6d584, 0xaf707392, 0x65b36345, 0x069fbfd6, 0x6f2a6bc0, 0xcca8e498, + 0x9a6cb247, 0x530c2807, 0xac883c6b, 0x45c6b9b9, 0x96710ad8, 0x126e866b, 0x572f9576, 0xdf494109, 0x125a9f3b, + 0x4d045bb5, 0x38fe927e, 0x0ba1914b, 0x4e539fee, 0x6fdeca16, 0xe74ad99c, 0x78856014, 0x534277a5, 0x4edbcb1d, + 0x4206616d, 0xe06e08ad, 0x33460435, 0x5626e16f, 0x5ce7c9dc, 0x7ce4050e, 0x0b51fe88, 0x91748758, 0x3384d1cd, + 0xfbf0bbed, 0x21b2b361, 0xed87dd8b, 0xb24f0315, 0xb083832b, 0x7d491ed1, 0x3838881c, 0x8e2f9695, 0x44f56fae, + 0x55a147c6, 0x4cfc058a, 0xf60fb621, 0x265fb9e2, 0x38a86cc3, 0xd978e9e6, 0x845c7397, 0xa5e418e7, 0x67451be5, + 0xba81f3a0, 0xea1a71b2, 0x62265218, 0xd57eeeda, 0x38decbc0, 0xfb53072e, 0x1909ffa6, 0xe5100a6a, 0x1fc658dd, + 0xf101f8a9, 0x694b1514, 0xb721683e, 0xb0a80e82, 0xad69f417, 0x7231c0bb, 0x8b04e8bc, 0xefece11b, 0xebe879b3, + 0x1dbc73e1, 0xfda52580, 0x2e31894d, 0x4ab1d004, 0x9d0558cc, 0xa02e3ded, 0x16de3dd2, 0x87fe2de5, 0xbb1e5e48, + 0x61acc456, 0xbb729dee, 0x6376cc59, 0x323b6f2d, 0x22fa6da4, 0x8d88cc32, 0x5d1a1f8e, 0x1041e7eb, 0xd136fa33, + 0x6a03385f, 0x5974d110, 0x935b775f, 0x20d5e3c8, 0xf4362e63, 0xeed7c564, 0x3e4b7f32, 0xfb34ddc5, 0x9f9fbe37, + 0xc7873740, 0x185cbbcd, 0x3cbfb853, 0x7a17e605, 0x1a113035, 0x13e2d5f6, 0x3368237e, 0x0de5ea6a, 0x71c9f6cc, + 0x1c053e0a, 0x2a39a261, 0x9a292982, 0x2a1cb955, 0x18524519, 0x23ffffd2, 0x8d9a5f2f, 0xb2e585b8, 0x05e2d419, + 0x63c4e597, 0x943993cb, 0xe12f861c, 0x29be1699, 0xa4a2dc0e, 0xf9a69d1a, 0xab64ff56, 0xfa016c26, 0xb0506134, + 0x0df07d9c, 0xdcec08c3, 0x78b82924, 0x6d53a1b7, 0x7d5944a0, 0x250759de, 0x0502f41b, 0xbb6b6268, 0x09b7a51a, + 0xb957d705, 0x39bbebab, 0xb0796d0a, 0x8bcfbae5, 0x29bad47d, 0xef8aad91, 0x2909213b, 0x2fa908be, 0xb681791f, + 0x54d00802, 0xf74f71fa, 0xb44d335e, 0xa4a45be7, 0xb8e2191e, 0xb7055198, 0x255df6e4, 0x044bc5d7, 0x837434aa, + 0xba70e76f, 0xecd05b6d, 0xf9875926, 0x101aac2d, 0x4b1140da, 0x1f4c5cab, 0x783cb778, 0xa47cfc76, 0xf8b8f9f3, + 0x10358cce, 0x8f7dcc61, 0x7c5856ad, 0xe219d197, 0x8d891bff, 0x8a851425, 0xd48a19f1, 0xb09313f4, 0xb0d460de, + 0x8967e672, 0x1f2b6a0d, 0xd61be705, 0xece64468, 0x9a21b009, 0x1d578151, 0xae2550ca, 0x7fab4fa7, 0xe84c9035, + 0xa8a1e8ff, 0x85d23e7c, 0x420f649e, 0xa75a15cb, 0x18fb40c2, 0x3cffe918, 0x286ac38c, 0x30b3e0db, 0x3dc9ed39, + 0x28439675, 0x0a6f36d9, 0x73598a2c, 0xef793dc6, 0x52ba6e89, 0x8620ace6, 0x4d65942a, 0xc45dd5f4, 0xaecfde9e, + 0x014bacaa, 0x54d3e5a5, 0xd870b6ca, 0x0a44dd1d, 0x0a990f93, 0x03f57a87, 0xb5b88a58, 0x84e5c902, 0x9c459bfa, + 0xd778f0b0, 0xbb7022bc, 0x2e1a7f8b, 0xa650f270, 0x34912f2e, 0xad590b1c, 0xe38d8af5, 0x71007d87, 0xd08adb46, + 0xb5a56a50, 0x05dcaa7b, 0xc327a2f8, 0x4a5d67b1, 0x935b50ae, 0x411880c5, 0x55f301e1, 0xc53b88b9, 0xd8d128f2, + 0x02d96985, 0x87c95f77, 0xd0e75ca4, 0x67f8b56d, 0x01ca8165, 0x04c956dc, 0x3b86e13f, 0xb1b173bf, 0x48b5cd30, + 0x967fb2ee, 0x3fa2f2ea, 0xee7f9905, 0x9572496b, 0x1fe25e3d, 0xca395fb4, 0x19b425c3, 0xf74d80f5, 0x25f0cbe9, + 0x27ec1b44, 0x4ea77c83, 0x6ac71117, 0x00ab6267, 0x388f53fe, 0xac5817f6, 0x8518c69a, 0xcd8a738f, 0x2aa775cb, + 0x901d78d2, 0x067d6734, 0xe7357221, 0x01316b36, 0x81a7fcb4, 0x16d6f2dc, 0x412b5f91, 0x806f2a4f, 0x933e8fc0, + 0xe26c023a, 0x9142a555, 0x99fd780e, 0xc8e1b55e, 0x25437751, 0x3e96b177, 0x885bc6f0, 0x59e9799c, 0x0ddf3e42, + 0xa06409a2, 0x5ff49560, 0x47387b06, 0x79f253c4, 0xb381989b, 0x469fbbf1, 0x5ccb7b77, 0x0882bad1, 0x6cd9a3a0, + 0xea46cf9f, 0x0e2370d8, 0x0248eb56, 0x21e5bfbd, 0x207193a6, 0x0fed6896, 0x64b85024, 0x38a19e18, 0x91e3ba64, + 0x199ed87f, 0x65c2fe78, 0x6ac2f4e6, 0xd571045f, 0xbc8963d4, 0x250f1638, 0x8321ebcb, 0xc6f12ea0, 0x01d42c67, + 0xb65f0771, 0x93925bf1, 0x5dd4eb74, 0xf8a2d3cb, 0xfb713196, 0xb99b88b0, 0x20dfc415, 0xafe5db10, 0x605cda3c, + 0xd761c306, 0xf4376c49, 0x277f779b, 0x6a61011b, 0xbefe7a0f, 0x6b72c95e, 0x1e49a309, 0x84ba6fb2, 0xfa5ac8f5, + 0x7bc156dc, 0x0e024c34, 0x874addfa, 0x8eb3505d, 0xbdea7aac, 0x6b9b3abc, 0x3e3b4a9e, 0x0c9798de, 0xe439c517, + 0x76c481d9, 0x4dfb96b3, 0x81ac4022, 0xaaf30a70, 0x00b8bbec, 0xf4d49742, 0x14763f04, 0x5d3da5fc, 0x8f4c3419, + 0xaacf206f, 0x0ea61e5a, 0x7d9e6228, 0xa65d618f, 0x19f7b89b, 0xf8a6ec5b, 0x51b2e112, 0x3340ba5b, 0x416257f2, + 0xca006ec7, 0x23d25ee1, 0x9d509c31, 0xe878a62a, 0x468f08e5, 0x2e3d7f05, 0xee38f663, 0xa6e95181, 0x1d993cd8, + 0xb3100810, 0x1b5a4ae6, 0x526f7ee7, 0xbae99961, 0xffa36767, 0x892199b2, 0x73dd956a, 0xc0cae040, 0x1bc1bfb3, + 0x94fa8e24, 0x2a10afa4, 0xe9a072d5, 0xf80ea6b5, 0x1affed1a, 0x532676e6, 0xeca9669e, 0xd456a74a, 0x7615c8db, + 0xe80715da, 0xcf708f10, 0xbc6e0ef5, 0x24d3b765, 0xffeb6aa9, 0xbf1c1f8f, 0x15bed1ea, 0xab2b6164, 0x548e4bf6, + 0xd1575a71, 0x94e55b4f, 0xdd103f67, 0x76d8fa34, 0xf134df27, 0x74737640, 0xead5863c, 0x3ecb4b15, 0x2f1b90eb, + 0x26336703, 0xd8a77098, 0x18b5b72c, 0x4cfba011, 0xcccbe410, 0xb9f18d13, 0x89fbffd5, 0x833474b4, 0x7392b5cf, + 0x96336edc, 0xbb8999e2, 0x7cd5d3a9, 0x5d7e771e, 0x7df3baa2, 0xf1481254, 0xecc764a9, 0x6c44524a, 0xe022fb26, + 0x231a6f0e, 0xd3e50d0c, 0x0cba74b4, 0x52d6126e, 0x960a23e5, 0xe91b92cd, 0x6b08b3db, 0x79603522, 0xd421c104, + 0x23a2242c, 0xe14cec69, 0xe8cc529f, 0x2a003d74, 0x756b4015, 0x0343757c, 0x660e3766, 0x86778396, 0xa87ac690, + 0xc296ea61, 0xfd8db656, 0x12d20c23, 0x44a06cfa, 0xf62de803, 0xb9af9e33, 0x25aee82d, 0xf7477237, 0x0bf97ce7, + 0xd8c474ea, 0xcd0f2132, 0x75746df1, 0x1671307b, 0x85aa9946, 0x1d64d8b2, 0x748ed3dc, 0x93cc5bec, 0xe6a150c7, + 0x1ff951c6, 0xb9fccd2c, 0x1056cfd0, 0xbfe0678e, 0x3fd76102, 0x2b1de8a3, 0x502854ba, 0x97f83fcf, 0x45f47c69, + 0x5eec7d91, 0x8bf5c5fe, 0xd1a23d32, 0xf9dd9770, 0x187556a0, 0xc786fe31, 0x71cd8650, 0xbba00316, 0x427c057c, + 0x26de3643, 0x4241b31b, 0xe33205f5, 0x01ec1446, 0xa3496d2f, 0xfb99db7b, 0x71393d6b, 0x08af143c, 0x12896fd0, + 0x052dcf6b, 0x7c33505f, 0xc8c7575a, 0x5d345554, 0xe5c8f6e5, 0xcb601e4c, 0xb676922e, 0x5fce9d94, 0x4431d194, + 0xa4fa5cdf, 0xa29dcef0, 0x0061964d, 0xc23123b2, 0x95618166, 0x1ab67959, 0xac5e5f76, 0x22c58ba5, 0x19382b1a, + 0x339f35b5, 0xf98242b0, 0x13644ba7, 0x2afb3dd3, 0x29777266, 0xfcdd0bf8, 0x7a4bb718, 0xfd449baa, 0x5919efa6, + 0x30320e87, 0x4efd003a, 0x4c441f28, 0x68764b67, 0x90c24572, 0xfbd6df70, 0xe64802a8, 0x5d85a9d2, 0xc163d67b, + 0x8b1738c3, 0x516f4272, 0x5d965d0e, 0x141f8a8d, 0x9540c631, 0x7d66549f, 0x39d9b344, 0xfe04f713, 0x636206e4, + 0xdf4e4675, 0x6d67c5aa, 0x62f933ff, 0xeebd8f30, 0xc40b5e01, 0xf5bdf03d, 0x01b776a4, 0x61aa9553, 0xba30360c, + 0xe996c3cc, 0x78629b1a, 0x6a5adbb0, 0xf43ba46b, 0xabfb6192, 0x3fed81c1, 0xdcda54d9, 0x62d301a5, 0x8dc54125, + 0xfb962ac5, 0x8c452c6f, 0x29fdfe08, 0xcaaecea7, 0x01cdda4e, 0xaed661e2, 0xc3aaeba3, 0xc2a4e9d0, 0xdbabb77b, + 0x4535b6e6, 0xd052221d, 0xe74a5ef6, 0xdd94c113, 0xdfa08f2f, 0xa66e11d4, 0xd53384b9, 0xefa393a1, 0x18252ec3, + 0x78812bda, 0xedd07423, 0xb737b1bc, 0x359bae25, 0xfb8f7e68, 0xb4e60ef1, 0x8cf20b81, 0x6b53a06e, 0x68bf8ee0, + 0x34645ebb, 0xb8e66b36, 0xe85c61d0, 0x09b053f0, 0xa00fdc09, 0x68830b27, 0x33bbe80e, 0xc269959e, 0x3a3c350a, + 0x392a6360, 0xc322e56e, 0x658804fa, 0x58c610a2, 0x9b2cbeb8, 0x7eda9f45, 0x45251887, 0x6f657cca, 0xe5868633, + 0x9f15657e, 0xfb8aeb79, 0x0ea3119a, 0xb50811bd, 0x370095e0, 0x9e23e1fe, 0x58cec97d, 0x2966b593, 0x2672fa86, + 0xf4b0ffed, 0xc9c277d9, 0xcefff7d8, 0xf2cbd8a9, 0xe41be250, 0xaf73199f, 0xb0104592, 0xc5ab8575, 0xc8387cd8, + 0x6798eae5, 0x7af605a2, 0xf16d4a70, 0xca601a8c, 0x9b840a6d, 0xd5c7d7da, 0xa5a999e1, 0x7c2b825f, 0x333b6df0, + 0x88a17ca8, 0xe8d57ac9, 0xe79f90b9, 0x8c734afc, 0x75c08647, 0xc1a05dc7, 0x0b32a16c, 0x47621ef8, 0x47fe0f00, + 0x6b69990a, 0xe0adf1bf, 0x9d33362c, 0x44d980e5, 0x03c039f7, 0x62aaf297, 0x556471a1, 0xc4ea1625, 0xa938c959, + 0x59e2bc47, 0x85909faf, 0xcf6ffb1f, 0x1e64fbe9, 0x7860786b, 0xc253f0a8, 0x2636d084, 0x6badbbc7, 0xff5638b3, + 0x0eb7acf1, 0x1d51bdd8, 0x7ac0df5d, 0x4a7161df, 0xd82ccaa2, 0x172e702f, 0xbf76c95e, 0x5321067f, 0x81bb08f9, + 0xc7d84bdb, 0x1fd11510, 0x998d1779, 0xb65efc26, 0x858743b9, 0x779bf006, 0xc6d96dd9, 0xc3c3408d, 0x89261541, + 0x8c29d88a, 0xa55b99d3, 0x5d4bef1a, 0x84f4f7e3, 0x64bc6fb7, 0x7b463ef9, 0x9673311b, 0xa73c92b5, 0x1f6a7bc6, + 0x0699989a, 0x859957cc, 0x4e27bcc6, 0xc24361d9, 0xde258c27, 0x95e9883f, 0xa94ae690, 0x0345b712, 0x9222de70, + 0xa33ff35c, 0xfa79363d, 0x4a3a9e3b, 0x1584134f, 0x9d7d0507, 0xf31dd63d, 0x3d77ecdc, 0xe92c76bf, 0x07400638, + 0xe3eff2a3, 0x948efc27, 0x5e0708fc, 0x915a34bf, 0x66720266, 0x3be607bb, 0x49eb2e8d, 0x961ac285, 0x1ed3c03d, + 0xace6b610, 0xfe0995d2, 0x78860e5f, 0xe0e3bdea, 0xb3fcdb5e, 0x758a726b, 0x1d8c34ef, 0x33063800, 0xaf9111fd, + 0x1c8df808, 0xb7d95051, 0x35c66727, 0x73d1bf66, 0x74d2c34b, 0x9079cc34, 0x86475cf2, 0x292c23ce, 0xbbea7ac7, + 0x0e187ea8, 0x7722d4b8, 0xef25bbf1, 0xd79457b9, 0xfed08d24, 0x9598fb40, 0x04621d1c, 0xc087e84b, 0xb261a9bb, + 0xa159b26b, 0xa7c2efe8, 0x94cc18b6, 0x40a92a85, 0xc557d128, 0xfa2e6f3c, 0xa00b3476, 0xe7b39520, 0x7b5ebe3d, + 0x064764d6, 0x973926cf, 0x2795705a, 0xa58b484e, 0x2e4b3494, 0x17ecac35, 0x490985f4, 0xde7f840f, 0x24422182, + 0xfa11138a, 0x47a3e771, 0xb8e5368a, 0xd103fd62, 0xc7ef7126, 0x7dbf3f2f, 0x6cf0ffc4, 0x2f77ab10, 0xe5ad958a, + 0x01c595ad, 0xc9f1fbc7, 0xafc38b1f, 0x6336a14b, 0xdb0bd125, 0xbddd2276, 0xdd49a489, 0x7149fe48, 0xdc7fa1f5, + 0x64914d40, 0xb7e91cbe, 0xea4cd60c, 0x2d85bfc7, 0xb8ce8a94, 0xa65c5a6f, 0x977c81a2, 0xaff3692c, 0x06913e32, + 0x096f4d56, 0xada690f1, 0x0444be67, 0xda104903, 0x9667bd2d, 0x9f491c39, 0x10f23ad0, 0x66b3883c, 0x859177ad, + 0xb9c549db, 0x947123e0, 0x3a329106, 0x320347f3, 0xaa476f5b, 0x47a26af0, 0x94e4232a, 0x29c7cd45, 0x31244e7e, + 0x390f8c1c, 0x3bf3f9ee, 0x7598a843, 0x66873564, 0xeaeca000, 0xc598e41a, 0xa136acce, 0xcb4a22e5, 0x0bad59ce, + 0x5c1bdf7d, 0x9dc71e44, 0xf4648325, 0x61e10ca9, 0x46baf497, 0xf7f9b5ef, 0x41590f79, 0xffbd15b2, 0x612d38a9, + 0x78183a19, 0x66e23e55, 0x80928828, 0x6377e601, 0x76e3e653, 0xce66211d, 0x1f8defef, 0x8de2c5ed, 0x7c33254c, + 0x29a3dde8, 0x4a495b79, 0x2cf2331f, 0x8b6ff433, 0xc7eda4e4, 0x07a46c00, 0x5f03ea09, 0x5e2f66af, 0x2b21e29d, + 0x43c4e743, 0xc0cc1ba4, 0xf819d7c3, 0xd7f4cf7d, 0xa1c8ef4b, 0xbdd80f5f, 0xb99427bd, 0x46175a85, 0x1de4e4d6, + 0x12d0ca1c, 0x30bcad8d, 0x3ee42025, 0x60ad041e, 0xd8be7833, 0xa0f501c5, 0xb6ea9815, 0xbd788d00, 0x2708e157, + 0x9463635f, 0x6fb8d635, 0xd7c05e41, 0xb1f28999, 0x67ac6f7f, 0x39d9ae0d, 0x2772075d, 0xe26ffbd2, 0x3405708a, + 0x10836ff9, 0x936c1fe9, 0xaede06fc, 0x647470c1, 0xb6a1cab1, 0x02da322e, 0xdd4fe4e7, 0x6210e9cf, 0x78e42952, + 0x42b07124, 0xe1bc0653, 0xd8c0aab5, 0xbfe921df, 0x1e4d60f4, 0xe89fc5ed, 0xcb5dc143, 0x559bed07, 0x742e4c98, + 0x244604a9, 0x972f17a5, 0x8c8199ab, 0xafb791e8, 0xd72ca480, 0x96d116cd, 0x1eab010d, 0x21a80b80, 0xc2c3140c, + 0x3893feb5, 0x54d07521, 0x2af16488, 0x0baf1725, 0xa4061d3b, 0x6978c8ce, 0xe9a1feb7, 0xd5e95c38, 0x9ea206eb, + 0x617482a8, 0x74693644, 0x5850b0bd, 0x10a91c91, 0xc4c27773, 0x56fd35b2, 0xf3a076ce, 0x35f7ff61, 0xa1b4660c, + 0x925bc8e9, 0x3f1d8946, 0x07b178ab, 0x1c8c988c, 0x7b1a964e, 0xe05e7391, 0x7289d32d, 0xadbff339, 0xd2d38344, + 0x2211934a, 0xd4257feb, 0x9f9da7b1, 0x7e6961e3, 0x6f5b03a4, 0x2ea9271c, 0x4ea22053, 0xc9feeb87, 0xe2fcff23, + 0x0b6d8b8b, 0xc9c99237, 0x5a30054b, 0x2b367086, 0x852dc2fb, 0x776be328, 0xa223b91f, 0x682caf18, 0x4b6dd86a, + 0x0962686a, 0xd31fcaef, 0xf3fe455b, 0xc23ffcdc, 0x29eb6dba, 0x1f66fece, 0x91dd0906, 0x29f88433, 0x8f911bcb, + 0x5d291d60, 0x3bfe46d8, 0xd6eb4a95, 0x0dcfef37, 0x1b9c3730, 0xb1682093, 0xc6d1f4fe, 0x95138fa2, 0xa71c76be, + 0x8eebdb74, 0xf20c93f0, 0x188f1427, 0xf7ed6f7e, 0x9638c8f0, 0xe4de0cf0, 0x60ba9b67, 0x6ae3a820, 0x1e4b008e, + 0x12e69e56, 0xa77f8cc0, 0x8ad8488b, 0x05f12b2b, 0xf71b9c63, 0x4d4ee7ff, 0x252f6283, 0xbc2ca35b, 0xfcc82fdb, + 0xe6229e64, 0x7ab11376, 0xc2d38426, 0xe1d3925d, 0x42a6d406, 0x3264186e, 0x23209d8d, 0x0afcf137, 0xe559b777, + 0x92d721a2, 0x0739f09d, 0xb3f16f03, 0x38de2ddb, 0x18df166c, 0xa71c5ef2, 0xefd3eb55, 0x7c2c263d, 0xe49d9d73, + 0xdf9f2a91, 0x6260477b, 0x82fab19d, 0x044c5f77, 0x2f1b952f, 0x2ca5fa02, 0xc891cd27, 0x7f3aea1f, 0x5a747d80, + 0x09d7aa5c, 0x23501889, 0x731fc800, 0xeeb6c13b, 0xbdc44e25, 0x1d4630a1, 0xcc16b8bd, 0xa09f6810, 0x926686f8, + 0x2e30c54b, 0xfe848463, 0x0a05284f, 0x24c16524, 0xf65604cf, 0xc2174928, 0x6c27eab8, 0x432a343f, 0x358eb3f8, + 0x4d407287, 0x7f023015, 0x28a9257e, 0x700fedf8, 0xa1f00b06, 0x37d7d372, 0xb240d0e8, 0x76abf5a3, 0xd46d156c, + 0x9f87749e, 0x237ba8f3, 0xd34f2bb5, 0x04f0c199, 0xb9e61635, 0x187544da, 0x61c160a0, 0xcb320d80, 0x1b4c1b69, + 0x88fca26a, 0x5e6fd51e, 0xfe2fd684, 0x70cf3121, 0xbc5f68e4, 0xdb3f0e6e, 0xb7bf832e, 0x3dda7c2b, 0xc31f60e4, + 0xd9d1259a, 0x02c23891, 0x8ed27a84, 0x1e44aa17, 0xc5cf2b97, 0xf37c9ea2, 0x9322eca3, 0x958eb779, 0x394166ed, + 0xf4d0c621, 0x603053c4, 0x3fc313d0, 0x5297a2b8, 0x71717930, 0xc4741651, 0x9295a3ed, 0xf7a878ba, 0xb73f6cc3, + 0x2db6f418, 0x3ab0b4eb, 0x44511d38, 0xcf82e995, 0xf17e3a86, 0xce67e634, 0x89626a16, 0x42c7543e, 0xcf8abe14, + 0x1774895b, 0x7131fb9e, 0x56196290, 0xd8600200, 0x5cc8bc9c, 0x3c238223, 0xdee6efb6, 0x8ac4ced0, 0x3cf61ca8, + 0x55d3087e, 0x32ec0573, 0x40ff6ea0, 0x0d0fde3b, 0x38f58335, 0xaeef4550, 0x56295611, 0xde3615b9, 0x77b0f019, + 0xf405d3d8, 0x8da537d6, 0x15d204fe, 0x23a82010, 0x903882a8, 0xc98f4043, 0x57d949ed, 0xf4d40153, 0x9a71e7e1, + 0x90f61ef9, 0x09e2497d, 0x979eb11d, 0x5611bedd, 0x37f32b90, 0xf35b3669, 0x2a0fc01c, 0xd371c364, 0x8d8f6497, + 0x4891dacf, 0x8493091b, 0x24326688, 0x4f9fa25f, 0x3e66a3a7, 0x72e45099, 0x588859f0, 0xeb593048, 0x8b89649d, + 0xe593824a, 0x41f3b050, 0xfa328471, 0x3f133ffc, 0xb855951b, 0x23e713b6, 0x225c0ac9, 0x7f612fba, 0x1386e121, + 0xd51aa919, 0x8a74b281, 0x35e8b2fc, 0x34fd0691, 0x3e39b36f, 0x3a12fbdf, 0xd6021ba4, 0xc6a7e7e7, 0xb2228f13, + 0xded35a60, 0xcbfd5629, 0xf11d62b3, 0x58279e58, 0xd3ac4870, 0x084bb713, 0x901990a3, 0x51351434, 0x64bafce6, + 0x2fae0187, 0xcd5e5523, 0xf3148843, 0xedc181df, 0x1c36098e, 0x32c64c04, 0xe66e5d1a, 0x6381fe55, 0xb8a218e7, + 0xa91d5c2c, 0xe429b11b, 0x645437ef, 0xd691bde4, 0xe7c88a6a, 0xfc5e1a52, 0xdb326610, 0x249473b3, 0x64d13e37, + 0x6b6e1ea3, 0xb5276aac, 0x7e90558b, 0x8aeb08d9, 0xa6dddd69, 0x075c73db, 0x893ffe3d, 0x2bab1339, 0xd62b9feb, + 0x95c43680, 0xba2d0791, 0x5b8ed91d, 0x50476667, 0x9e1b608e, 0x3c4853ee, 0xd24a5ee9, 0x153dbb72, 0xa0536bd9, + 0x9dea889c, 0x586ce8f3, 0xccb890ed, 0xe5a7bf7c, 0x4aa37ed5, 0xa1fdb829, 0xcb203560, 0x0657d883, 0x972d8eb8, + 0x9939e575, 0x6e8f1a34, 0xac6d77b5, 0xa35714c4, 0xcc7912ce, 0x3472020f, 0x526df231, 0x5e340986, 0xd8e0e000, + 0x45b1cc01, 0x859d261b, 0x9e91dd89, 0x4a3010dc, 0x32918cd2, 0x0e6501c9, 0xcc6eff4a, 0x4fa473b1, 0x1029242f, + 0xd340c562, 0xac1dadd1, 0xf91f9750, 0xcedc0b50, 0x72d261bc, 0x2246e012, 0xdb32277d, 0x289b226d, 0x9eec9175, + 0x2cdb12d1, 0xb012c41e, 0xad19f611, 0x7a1e9177, 0x61fe4be9, 0x60c23fd4, 0x8f674e69, 0x6c36059f, 0x5bee2730, + 0x1c31ddb8, 0x5d17904c, 0xdb95581d, 0x9a187aa0, 0x8edfa055, 0xa7944afa, 0x48d00a61, 0x6d9ffc3c, 0x57e7924f, + 0x5e6a5b8f, 0xb4700148, 0xf15cc9f2, 0x4f158d97, 0xc194bd10, 0xed55cd5f, 0xbc599faa, 0x95dc9ad4, 0xf7bb4af6, + 0x2bddc911, 0xf4029cef, 0x8ab0bf37, 0xe3deee07, 0x736ca8d8, 0x8d9fb6d4, 0x96e9ad4e, 0x6a48348f, 0x394f2dab, + 0xcc82603b, 0x0f58e1ac, 0x74df39e8, 0xfcc98460, 0x8890856d, 0x986f594b, 0x1e79f183, 0xbe534b79, 0x34773dff, + 0x3328a950, 0xb23bfd89, 0xb3e7338c, 0xb9fa2cb1, 0xb2be713e, 0x7bcc4295, 0x713c06f9, 0xfb34f937, 0xba470cc6, + 0x5b0fda90, 0x81a7735d, 0x120e96a8, 0x85e8934d, 0x592eaf69, 0x99d7de13, 0x6c4853c2, 0x37d16e1e, 0x72b2f39b, + 0x05fca8bd, 0x6d6d3446, 0x9631e05e, 0xd5f3414f, 0x41f9a31b, 0xbf257d2a, 0x05660f2d, 0xece3622e, 0x6809da81, + 0xd14175fc, 0xc884f304, 0x52b90afd, 0x1a9e33ef, 0x26835778, 0x114c19fb, 0x7248cd9a, 0xd8c68888, 0x270de860, + 0x87f2b967, 0x24e6577b, 0x7e7d6e00, 0x228a449a, 0x04ebad66, 0xb7ab8b28, 0x13b10acf, 0x3e26e18e, 0x0c3fd590, + 0xfac09e06, 0xe2c084f3, 0x5029927e, 0xe4567c42, 0x6f3426df, 0x19eb1b47, 0x7953c368, 0x8d9e02e2, 0x06f73bb5, + 0x12f35026, 0x464ee3ab, 0xebed7de3, 0x69ba4cb1, 0xe658803f, 0xbc78a668, 0x91964883, 0xc15f72f6, 0x38bda956, + 0xf2b700c7, 0xa7e7802f, 0x9e587395, 0xa91ce671, 0x40d29ce1, 0x0e7e58ab, 0x8d9977c1, 0x540480b5, 0x78944fdd, + 0x6fe21973, 0x46d57ab4, 0x7843bec4, 0x2d4a8205, 0xb18e5f85, 0x616d4d90, 0xaf6bb851, 0x589a5954, 0xe80703ef, + 0xa4aadf2a, 0xf3701367, 0xb19758a7, 0xd107dcd4, 0xeda6e979, 0xff508896, 0x27b1d163, 0xfc0ae017, 0xc8cfaffc, + 0x265e392c, 0x2cd2d47a, 0x9a029783, 0xe3c1760b, 0xa3607ad3, 0x027cfa05, 0x308ea776, 0x69479cd5, 0x2140e08b, + 0x253866d1, 0x2b81e22e, 0x5e8ee8a4, 0xc8d47287, 0xac555ad7, 0x196b8c00, 0xf50edd52, 0xfd5ac894, 0x1d9233dc, + 0xd5d9d2c1, 0xa374e731, 0xb690dc17, 0x4a4c8d93, 0x75312018, 0x0009170b, 0x5b396d4a, 0xca74df82, 0xd8897a15, + 0xe12a9ac0, 0xa6fee5da, 0x0cc4dfd2, 0x08fac7d8, 0x2f31a8b7, 0x0048eac9, 0x3066fa9b, 0x01af82ee, 0x1601fdbc, + 0xf8136b51, 0x14e43dac, 0xc207c3e4, 0xdb030ba0, 0x0e08f043, 0xd2b9531f, 0x5ae2c15c, 0xf3987181, 0x4b64e121, + 0x9fd2c66d, 0x56351c54, 0xc99fcfbf, 0x9aa6d550, 0x6f48d856, 0xf6539d1c, 0xae324798, 0x33f8ad90, 0x284a7554, + 0xa39688b8, 0xddc1d2ac, 0x105cfa2c, 0xdcec1913, 0xa3689e24, 0x2b0fb306, 0x1cb4444e, 0x7bb5ef98, 0x42423586, + 0x6a7f54dc, 0x64325cbc, 0xf1c47402, 0x18422ab7, 0xfd33e014, 0xb71e5751, 0x8b6c89ba, 0x5c5febd2, 0x89766f1b, + 0x1665434a, 0x1ad8a8e4, 0x9ce059ac, 0xb3dbb124, 0x1b8164a8, 0xa9ab8112, 0x98aa6abc, 0x5dc0fb71, 0x5160b5aa, + 0x76f032d0, 0x611a43e6, 0x7724fa21, 0xe74f7a74, 0x58a77717, 0x3cd96a9a, 0xb438c2ac, 0x91d776ac, 0xc52be751, + 0x1b025899, 0xbe042bc9, 0x50084b0b, 0xbcaa8618, 0x497e83e2, 0x5d23e642, 0xec4e9bae, 0xdd93fab7, 0x0128cf7e, + 0xde8969e0, 0xd230b46b, 0xb60de466, 0xe9acd741, 0xc3d120d5, 0x865f0da2, 0xdaf30bd8, 0x20b87bd9, 0x39cb6379, + 0x8d82a442, 0xcd74b2d3, 0x839069d3, 0x5977a3f4, 0x333e76a0, 0xb54b5a92, 0xb1f9c635, 0x7060b408, 0xe1b0d0a6, + 0x526e3beb, 0x39331ec7, 0x1dc23cd2, 0xeb8bf9e7, 0x5303d74b, 0x1d3b21b7, 0x32c4d8d0, 0x682c7122, 0xc7f01be3, + 0xa8449137, 0x48205310, 0x94508e8d, 0xa1d60f23, 0x371640fd, 0x5e48e0a4, 0x546ec691, 0x0d24db3b, 0x5fcd5e2f, + 0xe955c926, 0x131642f7, 0xb23ec5cc, 0xca2ecf58, 0x422639d2, 0x0362b16a, 0xc958041e, 0xed7890a7, 0xb437a295, + 0xa396a13d, 0xdec02f4f, 0xfd1282ba, 0xe329b9ae, 0x2d99b6bd, 0x8c7c8313, 0x29ed4909, 0xf6b19956, 0x9be0867a, + 0x974448c2, 0xa1fdd881, 0x9d92f149, 0x6887b4bd, 0x6b7dd2d7, 0xafd9886b, 0x161dbf04, 0x462fa129, 0xa6005170, + 0x85f0858f, 0xb3b5b091, 0x16c35ce8, 0x31e60741, 0x5000e5f5, 0xd2186593, 0xabf798c7, 0xfd7ef147, 0x75338703, + 0xd7ae0f88, 0x0dd3b2c0, 0x5ab90f57, 0x3f679357, 0xc028af24, 0x2b147887, 0x0d9eac8e, 0x4c2a579a, 0xca9a37fb, + 0xaa2a6330, 0x18cb0a48, 0x6deae619, 0xdb6ccca8, 0xcd1e69df, 0xc74d8812, 0x4d633266, 0xe28fbee5, 0x7c9530f7, + 0x562cacc9, 0xe13fab5d, 0x7bb79903, 0xf3eda814, 0xae067ffb, 0x52ba2e0a, 0xd3c5e952, 0x2b521d64, 0xdb76d525, + 0xc707ad54, 0x4b10c341, 0x779714ee, 0x1cb4ee05, 0x00294582, 0x3363da8e, 0x39cdb14e, 0x8719b64c, 0x96b7b10b, + 0xda63365c, 0x92fed084, 0x7535e02d, 0xfd7c604a, 0xbe3e93b0, 0x24e5f5ca, 0x2358df28, 0x01afd003, 0x680df67b, + 0xac384f4f, 0x04c0952a, 0x534349ec, 0x28ebfd46, 0x06012719, 0x3374bc1b, 0xb8bd5b07, 0xb0a71caa, 0x7f05227b, + 0x41147c2f, 0xcdcb30e8, 0x5e08973d, 0xcdaed15a, 0x4d9fe7c3, 0xa882431c, 0x2d1d239f, 0x5ac6df8e, 0xb6b3cb3b, + 0x4000ed47, 0x229fcaf7, 0x65ed373d, 0xd57b733b, 0x7761ef20, 0xc28d3b01, 0x85105357, 0xa5168476, 0xa6009936, + 0x71883959, 0xe8f9c15e, 0xbd1a0d9d, 0x32d9bfe9, 0x5c68fbda, 0x572b9313, 0x70b955b8, 0x29fbab58, 0x0ba78de3, + 0xba5246a4, 0xfac75c8f, 0xb3b8de5e, 0x20ad85b8, 0xb1450a4d, 0x00ecba33, 0x5991f099, 0x2803f91b, 0x15fd5594, + 0x9e0a6eda, 0x9d273151, 0x372281ea, 0x0143f2ab, 0xc61a489e, 0x448adcad, 0xf547b414, 0x1714c73e, 0x899d92bd, + 0xb1e33831, 0x117b32b2, 0x0eb103ed, 0x664f7de6, 0x00035ba9, 0x825a8fdf, 0x4cff38bb, 0x6757d406, 0x8991fa67, + 0x006ab8c4, 0x56b9afd4, 0xf1963307, 0x649306ba, 0xf5b1b1c0, 0xfed515c5, 0xd5d9fa8c, 0x36a22967, 0x12512d42, + 0x39dfd465, 0x8e1f33ce, 0xbd5e6a98, 0x4b4d60bf, 0xa2eee13b, 0x3f997b28, 0xff7411d2, 0xb753d762, 0xc756e9e1, + 0x7313fac1, 0x7956f0f0, 0x6544a03d, 0xbb83b6a6, 0x1a01eb7e, 0xa3c3bc49, 0xae4afaba, 0xe7205e05, 0x08214f1c, + 0xc7d18d5e, 0x534e480a, 0xa548a74e, 0xde7784e9, 0x340e65df, 0x766b9b7f, 0xc2f3f521, 0x5df5c7a1, 0xa3bd15f5, + 0x82bc1842, 0x1c0ce217, 0x7edb9115, 0x54e128d3, 0x1bb386db, 0x6512fa8e, 0x0199239b, 0x9642f884, 0x6d223e71, + 0xbf56e1ed, 0x43d6e89c, 0x6ca9bbc4, 0x48f91223, 0xa3d99266, 0x8635e8fa, 0x2fb6fe28, 0x348d97f0, 0xf768df01, + 0xbf655701, 0xe961a274, 0x86c2758d, 0x5193c2e6, 0x9da524a6, 0xd97c1184, 0xdabd8bcd, 0x81caaf0c, 0x086ec405, + 0xe0b4f439, 0xbd4e6910, 0xd09c15db, 0x72b79a50, 0xa4324f43, 0x034582e5, 0x0744f465, 0xd3c49f32, 0xb7f9f7ac, + 0x51c87d6f, 0xc39e6adf, 0xf16cef4b, 0x2a92ec23, 0x962d689a, 0x3be041e2, 0x20c5714b, 0x480d5a6a, 0xdb1c6a5c, + 0xe2dc2e00, 0x72b69ab9, 0x3ff861ed, 0x21892ce1, 0x3905632e, 0xf2b68bd9, 0xf7706c9f, 0x78c5729f, 0xd9c69e29, + 0x64fd0853, 0x733859d9, 0xb65e42a4, 0xc7288720, 0x30f324b7, 0x5f99287c, 0x0c4909b5, 0x392dfb54, 0x21edea4c, + 0x88558b3d, 0x78f5c404, 0x2d7e22a8, 0x2de6e1f4, 0x896bee15, 0xf24fd912, 0x8679231a, 0x590c6c9c, 0xcf8a4e7a, + 0x6f1f25c3, 0x2e93bf0b, 0xda8beee2, 0x281eaa5e, 0x66ba13ac, 0x54e9c36a, 0x8d802d6a, 0x2807e2e6, 0x0b1fb595, + 0xc0e5f258, 0xe27b87c6, 0xd43f75df, 0x2f3820a9, 0xfbeb2cde, 0x8a8d9d1c, 0x48e1210d, 0x5004a1fb, 0x1dbface6, + 0x360f410a, 0x74391e5d, 0x1f19bc53, 0x648ce7c1, 0x4d654152, 0xa6a47ac5, 0x52a027de, 0xe29b7764, 0x78d6d593, + 0x8d434d6f, 0xc81b72f9, 0x40c34889, 0xd9797c77, 0x590f29ea, 0xa37a309e, 0xa677033a, 0xe2beb375, 0xf409264f, + 0x014d3cb1, 0xd81c0669, 0x9d20c307, 0x1cd1323a, 0xecb2cd49, 0xbc6ec039, 0xaadf8e56, 0xbb25bb0f, 0x6ca17e33, + 0x125f73da, 0xca1bd041, 0x5d39d98a, 0xa85cbd4b, 0x642e5efb, 0x987c5c37, 0x768ab44d, 0x51bac490, 0x5934fa60, + 0x8c2fe038, 0x959662a8, 0x8e5e87a2, 0xc08c59b3, 0xeffda3ad, 0xd6ec2582, 0x4446936f, 0xf7cfdeed, 0xb3be55a0, + 0x2784e2f0, 0xd2b37766, 0xfa6275e6, 0x9400781a, 0x91f89bbd, 0xe82698e2, 0x70a0b404, 0xa9266c63, 0xb2aac309, + 0x233912fd, 0x54d31dc0, 0x340a5a7e, 0x7c3d1f6d, 0xa7a874a4, 0xc8389ea1, 0x32e7fa61, 0xd1148326, 0xa9b1ecbf, + 0x26de3b90, 0x578df844, 0xd3e8416f, 0x917010cc, 0xa5f302d1, 0x987b368a, 0x58442834, 0x11aa6838, 0xeeba353a, + 0x17ef611c, 0xaa869f70, 0xf9472c8b, 0x5053767e, 0x2ec423a4, 0x133de510, 0x9f4d3d7b, 0x13674054, 0x1ee318cb, + 0x3ff15bbb, 0x0094128b, 0x9043ed5e, 0xa45a0587, 0x0307519d, 0xabfd7677, 0x261c3bf0, 0x6edebf95, 0x76f376d5, + 0xa05fc790, 0x4eb6d13b, 0x861362ad, 0xebbb0d96, 0xea17b34b, 0x53329982, 0x8cc94a2a, 0x5f0c9604, 0x382cac31, + 0x47fbf1c0, 0xaabab045, 0x8a2d59a9, 0x559590f9, 0x88b16b4e, 0x4424867c, 0x2d909762, 0x8a339b87, 0x3d86cbdd, + 0x7c004f76, 0xebeb99da, 0x154ef105, 0xac75a3bd, 0x712379a3, 0x37daea56, 0x3b31f5fa, 0xbbe0f6fe, 0x7da35746, + 0x3f87f148, 0xc170777e, 0xc6934459, 0x41cc27eb, 0x37274b78, 0x65dc8703, 0x1f2909b9, 0xe7a8aada, 0x79922e32, + 0x6ec87fcb, 0x7c64a065, 0xfc8d1954, 0xbdcb6f15, 0xb3f31490, 0xf20cf576, 0x2d18b843, 0x580aaa88, 0xe6cf10d9, + 0x6444aa27, 0x1a554d2c, 0x81a11e3b, 0x657db55b, 0x4979ffba, 0xdee1d585, 0x2e7ff7ae, 0xb7694975, 0xfe332ed8, + 0x96cb58e3, 0x116943c6, 0xfd384005, 0x7c494001, 0x50b95f41, 0x8d9dbd72, 0x28b9a034, 0x2aad537f, 0x668d7c56, + 0x6aa90fe5, 0x95d75b06, 0x521e8a10, 0xb5404173, 0x099e7da8, 0x3420d4ec, 0x01daee53, 0x022bca28, 0x7083d258, + 0xd1d96f93, 0xd7175f1a, 0x002adab5, 0xb39e00da, 0x194efabd, 0x4f981125, 0x5d8e4e07, 0x16bbdcca, 0xa9032b17, + 0x6603a169, 0x583a4d36, 0xd23cb145, 0x3627abc1, 0x5a7d5877, 0xbc6a5bda, 0x9eceaccf, 0xa0290b94, 0xefbd0442, + 0xe80aa2cc, 0x91694aa4, 0x09982462, 0x11490b91, 0x65a73db4, 0x8cea31c1, 0x0fad4be6, 0xfd147590, 0x949e0da0, + 0xbf6a13ff, 0xd429a387, 0xd0b1d81b, 0x1c0758de, 0x771324e0, 0x592d574f, 0x04009aa2, 0x74ce26fa, 0x5eef943d, + 0x3034861c, 0xa8989b4d, 0x8060a537, 0xb2e78986, 0xc542dbd2, 0xa082146b, 0x1a937aef, 0x28c1733b, 0x6297731e, + 0x9e04bfb7, 0x46824a29, 0xb1dcd882, 0xef20371b, 0xf1ea2de5, 0x7cfd1c08, 0x4c8bed49, 0xa7f46f5a, 0x30afce4b, + 0x6a78af0f, 0x811106ff, 0x35451d85, 0x0b229dd4, 0x67d19aff, 0x92cab0e1, 0xbf518fc7, 0x5b461bf5, 0x53c5fe7c, + 0x5da91e5e, 0xbc478286, 0x56ed1b37, 0x9888021a, 0x37417774, 0x2e89cabc, 0xa66990a6, 0x5c271b76, 0x8a1734aa, + 0xba4353da, 0xa7c7780a, 0x7748d189, 0xad43d77d, 0x0c047582, 0xad9987a9, 0x07e677b3, 0x85c12445, 0x8ce6d0e0, + 0xceac54a7, 0xf056df18, 0x3f86708b, 0x2cece841, 0x42f04cd0, 0xba4c887a, 0x51ff145c, 0x5c37b874, 0x146af406, + 0x3ae44a24, 0x2cf0f1c5, 0x425b5bb2, 0xf1797db0, 0xd9cf6f33, 0x7d71b357, 0x2956480e, 0xfd3f7ffa, 0x7d030e13, + 0x524bbec2, 0xd0689873, 0xc5962f7b, 0x3d11c471, 0xcf36288b, 0x6d9ac4d1, 0x4a2cda11, 0xdcdcfe95, 0x4671aa64, + 0x721e2783, 0x22678078, 0xa0f201c9, 0x5e9019fa, 0x067edf44, 0xe9cfbf78, 0xc85476b7, 0x9c3ed7d8, 0x7d3878a1, + 0xdcadb163, 0xc8d5a963, 0x374c1169, 0xd61d5686, 0x8cd2b43d, 0xa4d9e235, 0x1b36bd2b, 0x2319e213, 0xc38c20b6, + 0x0960503f, 0xe5ffe449, 0x677cb08a, 0xb57f40ee, 0x0cfcfe3c, 0x2d50e41e, 0x5cf2f8b9, 0x851abeeb, 0x496fa12e, + 0x838fae48, 0xcc720c89, 0x4a5c1791, 0xf38eab83, 0x17ed3afa, 0x211de553, 0xbdac47f3, 0x2c29e9b8, 0xdc7f29a6, + 0x5ce5c972, 0x2dc05929, 0x80f653b5, 0x53e4d843, 0x7c8b0c26, 0xfc451efc, 0x5a4e1c3a, 0x2c5e3829, 0xe1f04306, + 0xbd0e8926, 0xed478c96, 0x596aaf1c, 0xd4fd0183, 0x44545968, 0xe4791b29, 0x16f2cd8a, 0x4147f28b, 0x998a0392, + 0xcf539af6, 0x596ec90c, 0x5cdb4407, 0x52d5689a, 0x0b1a8ab3, 0x8145bd90, 0xc87b14c7, 0x355d93a4, 0x62acc95e, + 0xe789b6a3, 0x5d4538ef, 0x6739c4bf, 0x1d477957, 0x50dca439, 0xb93e5f25, 0xf9892f43, 0xa011699a, 0x7dc9bf64, + 0x677e106c, 0x7cf178d6, 0xb375c356, 0xcefc9742, 0x5a8a5806, 0x7588198b, 0x61274741, 0x832d31b4, 0x6c8e34ef, + 0x26afdce3, 0x3f6adfa8, 0xc94691aa, 0x542d44f7, 0x80897847, 0xe237c2e2, 0x9660d2e8, 0x876db5d6, 0x93ea8c25, + 0x264b93a5, 0xb9f7653c, 0x0f79e00f, 0xfd30b4dc, 0x219f7bbb, 0xf4d2d361, 0x60a0d204, 0xd6a3c53b, 0xc9e5fa37, + 0xfd5f6d8b, 0x8119fc7d, 0x7ae0f8c7, 0x2f0c0a71, 0x14e78d04, 0x0858ab12, 0x5942c6d9, 0xb3400ad5, 0xe6290e0a, + 0x3a0318b2, 0xa3bfc81d, 0x08a8e7ea, 0x68eb7004, 0x2aadb813, 0x811135ff, 0xfc296937, 0x48739887, 0x75ea49c6, + 0x9340c9e0, 0x7a46f36b, 0xa5bd4113, 0x36bf622a, 0x38062a8f, 0x7d068f1e, 0xce9f2826, 0x908b1240, 0x47acf9e0, + 0xc8c7b90a, 0x1e000261, 0xb07e4238, 0x96483ffc, 0x2102719f, 0x0c5d301c, 0xdcc81532, 0x433de52d, 0xbdccb326, + 0xc44345dd, 0xc3030a03, 0xdba8c079, 0x16f57066, 0x9f67933b, 0xf38b3e5f, 0x7756c0db, 0x208d9e3c, 0x56de26be, + 0x5806222a, 0x9a63e3cd, 0x4e618d92, 0xcfa3e2ca, 0xff39c175, 0x0dbe3cd0, 0x0cceee85, 0x11a17a93, 0x9ebb4f40, + 0x6988c92a, 0xadcec6bf, 0x124002da, 0xfe364654, 0x60920860, 0x0c8856ec, 0xfec5f186, 0x1b695e57, 0x8adf36e8, + 0xa57a2661, 0xd7d3eb80, 0x99202974, 0x5a915af1, 0xf8b6fa0f, 0xda844e9a, 0xf5e98336, 0x28d021d8, 0x41c26b32, + 0x1202930f, 0xc649e495, 0xa1d23660, 0x0db21491, 0xc179f625, 0xa1578aed, 0xa872531e, 0xdb5e22de, 0x34594b9c, + 0xe008494d, 0x170ab4fb, 0x3a5067e3, 0xc71328fc, 0x60685ed4, 0xb13c07e4, 0x25965a6f, 0x3411da84, 0x41c5b34d, + 0xcf656a89, 0x0525cb17, 0x35e2711b, 0x1cc8ff37, 0x270a5563, 0x9f97997f, 0x091c2a42, 0x8d44cbde, 0xe81ae8d8, + 0xf49bd24c, 0xaf59f4bc, 0x3c2d89e6, 0xaf477e97, 0x15360096, 0x96a19437, 0xb7e517fa, 0xd0466a1b, 0x971d869d, + 0x8a8a2065, 0xeffb4b39, 0x380e1f3d, 0xed0dee6f, 0xea183491, 0xf5b4bb98, 0x2133ef14, 0x9112a977, 0x1687f435, + 0xa0fe6d7b, 0xb51b451a, 0x6e4e3424, 0x4d2330f9, 0xbd9aaa8b, 0x4f375056, 0xa3d5d83c, 0xf43fbddf, 0xe050506a, + 0xf21a8e15, 0xe2ebd078, 0x25973820, 0x25007f0a, 0xe01ed3b5, 0x36620bcb, 0xea136040, 0x56d446d2, 0xa2aaf590, + 0xd9235da4, 0xefdc51f9, 0x8b8c2eee, 0x11a60bb5, 0xbad202f7, 0x4a4a7bad, 0x0c48c8f1, 0xfe15c41c, 0xb8c9f442, + 0xfd022452, 0xdd1b9aa8, 0xdba3656b, 0x571c890f, 0xd3ab6d58, 0x768a009c, 0x0a0591a2, 0xe7e9ee89, 0x100d0aab, + 0xfa8fcb3a, 0x1ad1b638, 0x539cdc18, 0x7a765518, 0x0f6f561c, 0x7e1f88ab, 0x5bb8b992, 0x52ba7767, 0xa7971a6d, + 0xa8d23bb7, 0x04ab26e2, 0xb84f7751, 0x207d40e6, 0x367000a8, 0x33194621, 0x5e365208, 0xc9039c50, 0xf748a15e, + 0xc8116f75, 0x6a06aaf4, 0x0c105c38, 0x73af8f02, 0x4e9bb801, 0xd41076ba, 0x816fa9a7, 0x9a095abd, 0x10ab7fab, + 0x93dd7f47, 0xd3942dcb, 0x04d3575a, 0x88fdeb05, 0x136f791f, 0xc4837ea5, 0xa0edce3d, 0xcbe6e0ef, 0xa69b4b18, + 0x0107a12f, 0x6a525a52, 0x3af03fd2, 0x8e48642f, 0xc059232f, 0x4b1cb99e, 0xc5ef5079, 0x813ad787, 0xb0dab738, + 0x27f419ba, 0x04e11b09, 0x66369776, 0x1e72deb0, 0x0cde5352, 0x3f8f4ee0, 0xf557d991, 0xd662ac58, 0xf1df3889, + 0x5e3544b6, 0xb3f663dc, 0x09ed7e64, 0xf6248545, 0x7ab1a1d4, 0xc4dfb6ee, 0x76f2beca, 0x8e7fa85e, 0x424663cf, + 0x73d44d09, 0x3cb665b7, 0x9d67252c, 0x9b89aa3d, 0xbf552974, 0x7d69593e, 0x1aafb44e, 0xfd22f8fd, 0xd5de8edf, + 0x6265c563, 0x0a8d5274, 0x8cf85a3f, 0xe9fb89ca, 0x8a2f2318, 0x22609188, 0xd4a9d585, 0xc6cdec7d, 0xcf697132, + 0x37e32eaa, 0x7ed8561e, 0xce5c2acd, 0xbc263fcb, 0xf88677d7, 0x05e830ba, 0x09535461, 0x6d578aab, 0x72c804ca, + 0x523ebd53, 0xc29d9066, 0xded49d0c, 0x05e38274, 0x8435bdc7, 0x7567ac44, 0x69f1175d, 0x1e4bb079, 0x20d4de56, + 0x457ac8c2, 0x6b956cfc, 0xe9fda7dc, 0xb41353ae, 0xe27e938e, 0x7ed3b72a, 0x163157e9, 0x4ae6cff3, 0x0a4e87e7, + 0xed4492d6, 0xd385599e, 0x6f4b117e, 0x675e2dbd, 0xa1d0698c, 0x725c3e0e, 0xe0ddf633, 0x39998583, 0xc3fb2aea, + 0x48cecd2c, 0xda928dc4, 0x6195adf6, 0xc81523cc, 0x884ab720, 0xacd83a6b, 0xe0eb3598, 0x4c08585e, 0xe87f1394, + 0x2f5124b3, 0xef8a3729, 0xa7e74ef7, 0x51b912af, 0x983f22d9, 0xfe4f3793, 0x01169da2, 0xe65c8507, 0x1ff03ba8, + 0x4818209d, 0xe139aff1, 0x3f6585b8, 0x5a18ecbc, 0x417f9beb, 0xf6b6214a, 0x0ea54afe, 0x169027fb, 0xf587d9b1, + 0x8e2cd060, 0x3f5ac398, 0x0f93d0bf, 0x5f7701aa, 0xc13c0932, 0x30769916, 0x410e0ea2, 0xb533f983, 0xfe02a641, + 0x4bcde7a6, 0x5f6e24fc, 0x5a805871, 0xe5650d5a, 0x89de1c32, 0xbed101d6, 0x264a43ac, 0x97340a4b, 0x7636f1d1, + 0x4d8b5ac4, 0x260ed7a9, 0xdd2e1011, 0xca65c41c, 0x8a606249, 0x6b834f7d, 0x3ca64e80, 0xea394583, 0xdbd0373f, + 0xbf7d1295, 0x184775c1, 0x0188b473, 0x6e940c17, 0x6d955e9b, 0x89a36456, 0xf14aaf33, 0x169ea3e8, 0xe15bc19d, + 0x96d4df41, 0x10f24f44, 0x4d7d5a7c, 0x28ab8575, 0x95d96cfd, 0xfbb90e13, 0x07a7b8bb, 0x66b5d59e, 0x8d5101dc, + 0x84b12c98, 0xc6e712e9, 0xf59beeb5, 0x47843b7d, 0x275f586c, 0xa4fb6e5b, 0xf71cdaac, 0x9b5a8dc4, 0x6bbd0c7a, + 0x6ed1a359, 0x5ed5c974, 0xfb753ebd, 0xf8327ce8, 0x37e32830, 0x2bacfb44, 0x43a7d1aa, 0x44c5cfc7, 0xee6cd97d, + 0x1ba36f41, 0xf2b20f78, 0xebeee406, 0x4c61fc89, 0xf0a7ce30, 0x2a995138, 0xfa8572d1, 0x61aeb3be, 0x47d967d8, + 0x18d9dfdd, 0xa8b583f7, 0x14eca666, 0xb4f58813, 0x4f373c0c, 0xe79e0186, 0xc23340f2, 0xfaf0b134, 0xa752070b, + 0xd201751a, 0xf8d7c86f, 0xa419ef19, 0x92874b83, 0x842793ec, 0xfefbbcc4, 0xa0e336f6, 0xbc1602c8, 0xd9bcdda9, + 0xf674dcd4, 0xd1b1f539, 0x21dc8f1e, 0xc6eb1776, 0x4f5f578e, 0xdae5550b, 0x10be9c2e, 0x06032a07, 0x0bd5f6e0, + 0x75677b58, 0x07d48679, 0x36d0bcff, 0x21d70e9e, 0x6748b408, 0x65da7401, 0x8f5e9b9b, 0x6af00616, 0xee4e4daa, + 0x6e7e2866, 0xbcca8e9d, 0x1149b788, 0xf1d238f8, 0x190452e5, 0x6b8ea3c8, 0xdfc050ff, 0x99ec3dd2, 0x233550ba, + 0x5fa6d7a9, 0x7bc0fb00, 0x2a6d80ee, 0x75e825fb, 0xd3eec255, 0x00933002, 0x12107f27, 0x12105dc7, 0xc2dc743a, + 0xa4b247b9, 0x2119ca8d, 0xae11ee91, 0x9e2cca96, 0xea718046, 0x46e3e693, 0x4d826049, 0x582dc7a7, 0x79df3cd2, + 0x5ad9e9fe, 0xc3370f10, 0x60656174, 0x6014b600, 0xe95fd1d6, 0x228d0099, 0xfdfcab77, 0xc2bbd89c, 0x781b37c7, + 0xae2065a8, 0xe90d9e7c, 0xefd55d5c, 0xd3995844, 0x7f4cb810, 0x5037b706, 0x097634fa, 0x21c0ff65, 0x967f12f0, + 0x4ab01b25, 0xaa0f69f3, 0x7122088b, 0x473379e8, 0x1c671709, 0x973f94a1, 0x7577c679, 0x0c15ddfd, 0x286a299d, + 0x011b2010, 0x9fdd119a, 0x91b5799b, 0x622bd3c4, 0x84674da9, 0x6c461875, 0x8e0ea354, 0x6ab4dd95, 0xd309b73e, + 0x254b0913, 0x62889ed9, 0xaff73ab0, 0x34cb39e7, 0x6b5b8a77, 0x7b18383d, 0x1e4ae664, 0x2ce2e70a, 0xf48145be, + 0xf5667399, 0xf4706071, 0x16ca7466, 0x3922695c, 0xbd4f15aa, 0x8ec23228, 0x9fad1f03, 0x8ad10a44, 0x73a9105b, + 0x08bf84f7, 0x5e0432a4, 0xd499159c, 0x08fae308, 0xb38ef96d, 0x3810e5dc, 0xc59f1c11, 0x2868f8ef, 0x9bac7211, + 0x5ce3db26, 0x28066ad6, 0x0448780b, 0x381d4e74, 0xaab36cf9, 0x1aa75ff3, 0x201f61e0, 0x14f0ffd8, 0x0f9b1b1a, + 0x7f0d1d61, 0xdd4f7af0, 0xead96841, 0x258df5e4, 0x96d50031, 0x2df2b250, 0x8474bfda, 0xe76375b3, 0xe73fd8d5, + 0xd7226cbc, 0x7e99052e, 0xd5110d27, 0x1426b941, 0x6b242f24, 0xb58cdadb, 0xd2e2e388, 0x04cf79a1, 0xae134700, + 0x0577352c, 0x7ccb4025, 0x4c10c6a3, 0xe3ad69f6, 0xb0a5f9e1, 0xa06395f9, 0x082a284c, 0xde544683, 0x07d06f69, + 0x0e5d6c13, 0x9a835a2f, 0xe5af3487, 0xcb4ae8b9, 0x4ff4a0d5, 0x087f0112, 0x7cfc5e27, 0x0f14d8f2, 0x20607f6b, + 0x4534acca, 0x5d63a4ac, 0x3726f76a, 0x8fcca1b7, 0x1b18b71a, 0xb56891cb, 0x7696f0db, 0x7fb748a8, 0x74da59a0, + 0xae25b2c4, 0x031c4da2, 0x493d672e, 0x83ce013a, 0x7c49e770, 0xbccb5c6f, 0xf9d4a906, 0x69bc99df, 0xe5cd3535, + 0xe98515a9, 0xf7f39f81, 0x4a80732a, 0x1612f100, 0xc63b4cfe, 0xb5e07764, 0x2c8fbc7f, 0x6af85424, 0x2ac3e633, + 0x5daad258, 0xdff2c509, 0xd88c85de, 0xaae4d7bc, 0xe970f333, 0xbff8a109, 0xc49381e8, 0x252071f6, 0x377b7f70, + 0xf7d2ead1, 0x075a7611, 0x91a8ffc2, 0x30e1db76, 0x62eed668, 0x9a015596, 0x41f741c3, 0x0be95e9f, 0x6001ea9a, + 0xebbca82b, 0x9f4dcddd, 0x366a44c6, 0x15401d58, 0x59227fc7, 0xb641ae3d, 0x01dc9386, 0x89d3ff9c, 0x1072ceb6, + 0x2dfbe3eb, 0x50128af4, 0x8fa8f649, 0x51234fb6, 0x89a63b86, 0x4ca43f08, 0xb2c302fa, 0xdb34b7c7, 0xea8ec750, + 0x3497e651, 0x4c457420, 0x1d0f5abd, 0xb94d6a34, 0x70b256c3, 0x144faf51, 0xd3542ba9, 0x0234fb0f, 0x048a278c, + 0xd8f56ca9, 0x03721621, 0x8cfa9701, 0xd85bc7f1, 0xcde480fd, 0xca19f1fe, 0xa73f33f3, 0xb1f5c4b3, 0x717dd055, + 0xde9dad7a, 0x3bd25cae, 0xb4f0b0d8, 0x856701fa, 0xd366869d, 0xc1d599ee, 0x4c9d1e54, 0x8881b457, 0x2e3e4f70, + 0xd668c620, 0x90dc610c, 0xbea265c4, 0xdd4e9aad, 0xf032cfce, 0xf5340113, 0xe86d8f12, 0xba346a21, 0x4d38d8da, + 0x98ed8596, 0x9d355003, 0xe5b12edd, 0xb4083e3a, 0x4a7b54b4, 0x30a54fa0, 0xbf91a229, 0x1fc6dd38, 0x3086626b, + 0xf279ff79, 0x96bd3154, 0x31844d9a, 0xd3f92612, 0xad484ef0, 0x1a7dd952, 0x16c3c142, 0x97ec4c95, 0x7f070ce1, + 0x684cd476, 0x1eb893bf, 0x990ffb5e, 0x87405504, 0x148a7ff3, 0xfb4e17c7, 0x1722ea3b, 0x88f67e93, 0x3a75b822, + 0xb705ce22, 0x2755be21, 0x2f2a10e7, 0x11e17dda, 0x5c311711, 0x1ef07545, 0x430c3998, 0xd8fcdaa2, 0x1a40c64e, + 0x33988700, 0x5c7e6a9c, 0x5baa87ae, 0xe4d12d91, 0xb3f5c15e, 0xb4b125c4, 0x154c29c9, 0xc8bc5911, 0x99b49565, + 0x456a305b, 0x19d33b00, 0x3d138a01, 0x79c3749a, 0x325db8ed, 0xf8c21565, 0xad37beda, 0x8a85174b, 0x57d24878, + 0x7eb32038, 0xb07b3a90, 0xaf8c4142, 0x9c80a5f8, 0x27a6a01b, 0x5415bbe5, 0xa7a6ad3d, 0xfdd7c938, 0x7b956608, + 0xd527566b, 0x835e0c10, 0xedb02e97, 0x8740abab, 0xab9f1a92, 0x35ddb2d3, 0xa0460caf, 0x92ba3c2e, 0xc392c8f6, + 0x7d20e903, 0x82f49409, 0xe418c7c9, 0xd77b93f8, 0x0ba58fd6, 0xd1c37b3c, 0x21959234, 0xb92ec440, 0xfe49c213, + 0xe636b554, 0xca7bc9ee, 0x3114ab0e, 0x978dc22e, 0x083d64cb, 0x1db3613e, 0xdfc6fb52, 0xabd73724, 0x0a2e036c, + 0x8950331d, 0x5aac00bd, 0x2ade9706, 0xd5f872db, 0xe4f66912, 0x54387a1f, 0x11e950b7, 0x58d48dda, 0x466723c1, + 0x764456a3, 0x83cfa79d, 0x257c25f3, 0x470a2b21, 0xd3a57342, 0xd75ecbb7, 0x6888b8c5, 0x351eb62f, 0x3e3268d4, + 0xb93c244f, 0x57a9340d, 0x4b6353c7, 0x87a92c7a, 0x10c1a987, 0x9604a985, 0x1c4a19a3, 0x3f55dd2d, 0x517056e1, + 0x9dbd397d, 0x5fbd8bf4, 0x56e129c6, 0xc441af58, 0xd344c451, 0x056a23d3, 0x10874ebc, 0x5561da80, 0x1cda163f, + 0xcf88628d, 0xd4c4194e, 0xefdde2ee, 0xef12335e, 0x60da0371, 0x602bbdb5, 0x1d348adb, 0x718308ad, 0x374e76d5, + 0xc6a1f5a0, 0x4fc7e983, 0xe1b5db57, 0xbbe9c734, 0x3bf5560b, 0x02cf98fa, 0x8126f958, 0x68037c0b, 0xd18bd26d, + 0x45f4790e, 0xf0b45967, 0xd418b4e6, 0xac860beb, 0x176cf5a2, 0xa73563eb, 0xf46d1d53, 0xeea3ee88, 0x6abbce8c, + 0xa10d70ab, 0xc5233e9b, 0x95dd058b, 0x976b3dbb, 0x53813c70, 0x96a521d3, 0x06385525, 0x9f26b26b, 0x55560979, + 0x6686a832, 0xff551a8d, 0x5de434ed, 0xf942fb1f, 0x1c02c044, 0x21119333, 0x33c89438, 0xcc35a0a6, 0x84d02be2, + 0xfacbd21a, 0x9217b0da, 0xdb1278f7, 0x644c463d, 0x951e76a1, 0xf8cd3016, 0xa36cc475, 0xaa188581, 0xdc58e30d, + 0x519b69a3, 0x3f2293eb, 0xe1a8a422, 0x8b202418, 0x9e4a41f2, 0xf499d14e, 0x6a3be055, 0x1f3e02ce, 0x5de6dbd3, + 0xd2698ac0, 0xe082be84, 0x53ab6f80, 0xd76ca21c, 0xc1de2136, 0x54a44a0b, 0x7472c766, 0x381a89f6, 0x802f945b, + 0x8a8a4afa, 0x184ef6fc, 0x7e044fd3, 0xb635ff20, 0xa6c6e30c, 0xab91079c, 0x34d6f48a, 0xdc66f1d8, 0xa4d41ddf, + 0xb73fce20, 0x94f851cc, 0xf2b17aab, 0x6c53f020, 0xa7acd04a, 0x2d2394ea, 0x3fbbc5ee, 0x44ac1625, 0xe2af74c2, + 0xdb6b353f, 0xd06f2924, 0x1f244f10, 0xebf63da2, 0x211247cf, 0xf38dd4f7, 0x87a5dea5, 0x7710e05a, 0xa112ba0d, + 0x25d3f0c1, 0x6f21143d, 0x96cb4c32, 0xfcb3890c, 0xa877c2c5, 0x30b75a65, 0x9ecc0159, 0xd52049f8, 0xc9c059fd, + 0x921dd98a, 0x13660d7a, 0xfafb19b7, 0x7e256e58, 0xe8eeb42f, 0xa505372c, 0x9061869a, 0x477e3854, 0x0faeed71, + 0x5b45f989, 0xb658aeb7, 0xa4fa7109, 0xa560cdb5, 0x8b50f55a, 0x30873f8f, 0x7b40fe18, 0xf1f65511, 0x821f3a37, + 0xe01332a7, 0xe1dd8f5b, 0x1912fa19, 0xab510736, 0x53257eee, 0x48efc5c6, 0xb37a5687, 0x7d6d9b4a, 0x15b656a6, + 0xa815a823, 0x1819674c, 0x77fa516e, 0x537c8e23, 0x86d8bfc4, 0x1b7d41e4, 0x6baab455, 0x2f111032, 0x6a7f1cc9, + 0x497a3d6a, 0xd8fe982b, 0xb1797367, 0x488a6d6c, 0xf69a5145, 0xf2ef7703, 0xc4dc38a8, 0x0ca55f78, 0x7b9c95e5, + 0xc98f3fb7, 0x3a591d2d, 0x7390dbdb, 0x80c4216b, 0x93fac35a, 0xe93e9011, 0x81ff4696, 0xf212c0f5, 0xee7dd566, + 0x908e0a89, 0x600b9fd5, 0x3502b9c1, 0x8f88e798, 0xac1cc385, 0x4629d954, 0x2185f247, 0xf270b0de, 0x96c76c47, + 0xb1b6c1b6, 0x4ba3a6ba, 0xf8246cf4, 0x34704583, 0x91449979, 0x7974d5ac, 0xc05d6aa5, 0x62e6d87d, 0xcc2afd9a, + 0xc837bfda, 0x8ea900b5, 0x2b510b46, 0x9a26e5db, 0x47fd6a2a, 0xd7e798b2, 0xb68ed376, 0x44a41c6b, 0x39f30ee9, + 0xc5caaf66, 0x1f49497e, 0xa17e4fe2, 0x8f7e5560, 0xfd58702d, 0xb0a025ce, 0xe32af9f4, 0xb70d32c1, 0x514b6ac3, + 0xa7ac32cc, 0x8583332d, 0x6ccb7d03, 0x9f6a9df1, 0x2deab90e, 0x989c7476, 0x7874511d, 0x9c13f9da, 0xf6a7a592, + 0x43c39ca7, 0x8528d0b7, 0x159e2ef8, 0x435a6f6b, 0x853fdc0e, 0xd095bc7e, 0x75d88c15, 0xf7239213, 0x87d0a061, + 0xac5efc2f, 0x1541435f, 0xd244daa1, 0x2411f6b3, 0x49299b14, 0x854854cc, 0x7545f308, 0x791e2b73, 0xf7d3df03, + 0x38103391, 0xd705b7c3, 0x12ada078, 0x5d81902d, 0x4fb912f2, 0xa34d042b, 0x09d87f7b, 0x3182bfc3, 0xd307b106, + 0xe44ef29f, 0x67f4edd5, 0xec33d386, 0xdc5543ed, 0xa72fe23a, 0xb817e2b6, 0x009f43b1, 0x84af61af, 0xbd52a0b3, + 0x6ebaeffe, 0xcba106e8, 0xdbcf145c, 0x91500e25, 0x56fdcfb6, 0x23a562eb, 0x040d1c0c, 0xd675c699, 0x75a19903, + 0xa48f0912, 0x48c8d24b, 0x777832fe, 0x4d83b53b, 0x8eb92bf0, 0xe7b0d233, 0xaa844eb4, 0x2fed6a0f, 0x7144f1bc, + 0x300221a6, 0x9f1452cb, 0x3c3eb4f0, 0xd4f716e7, 0x5628811d, 0x80421f6e, 0x4030b784, 0x906119e3, 0xbd9ffabd, + 0x4ee3aad9, 0xb0ca18f3, 0xee1e4412, 0x7f5f1905, 0x51e2a5b5, 0x765c5d4a, 0xcfd4ab22, 0xfc050841, 0x0fbc5980, + 0xbe07e4b7, 0x0b42352e, 0x63359491, 0x5955abb0, 0x18f40c0b, 0xe52f6872, 0x6f01a2ab, 0xdc72218a, 0x2f03bcba, + 0xc2fcfc47, 0x8776ccef, 0xb8e41a00, 0xe0ef240a, 0xa66299a1, 0x6ebdd499, 0xe36911f6, 0x8bcb3d4a, 0x00fd48be, + 0x7d1e2e92, 0x846311ed, 0x2c098255, 0x2c742eff, 0x5954d911, 0xee03e459, 0x1e73b558, 0x2a78555c, 0xba71f281, + 0x16f0c215, 0x58399438, 0x049eda9d, 0x633efab4, 0xc39e8c46, 0xe9a3bdc9, 0xf85e15be, 0xff6e39ca, 0x70cf399b, + 0x7327ed8d, 0xdb02f588, 0xd0a06c80, 0x3d12e316, 0x7cd7e42a, 0xa92b5e78, 0x154c35c5, 0x85e78e79, 0x538e4c76, + 0xc0ab6054, 0x5c0c17ee, 0x465d6c85, 0x6236bafc, 0x15cc72bb, 0x70c8a440, 0x89f46ada, 0xb01b87ea, 0xa39fe5d7, + 0xff119224, 0x900b1ea7, 0xb108d264, 0x3c28f88d, 0x8ec9082b, 0x973902c3, 0x996f1d12, 0x7344e2ea, 0x54abde36, + 0x840022b5, 0x3e7de6dd, 0x12496b7f, 0x7ee08312, 0x5a903455, 0x1b282615, 0x2afe4fd0, 0xba817147, 0xaeab91e3, + 0x0ea1f145, 0xc32e83af, 0xe1cd9259, 0xa0d14ffc, 0xf2d86c7a, 0x972b8851, 0x38f87255, 0x4b6e0def, 0xd84ba0f6, + 0xd3054efc, 0x4ea0ee92, 0xa1d85de9, 0xba50ba99, 0xdcf9758e, 0x554f76f2, 0xf5ae58b0, 0x0a1b25cf, 0xc0464d61, + 0x6345df61, 0x6fec4f07, 0xf39b16fd, 0x9dafbad4, 0xed422aed, 0x56bd1756, 0xbb566420, 0x66a3b82a, 0xe295fb0b, + 0xc3855bab, 0x9ca3c350, 0x55c050b7, 0x37400c4f, 0x7a8a1b37, 0x485a3c1c, 0xf5609a8b, 0x21665d2f, 0x4acf0178, + 0x09114fe4, 0x6ea22ab7, 0x8d5089e8, 0x16695ace, 0xf870767b, 0xc86cd55d, 0x48ce0e6a, 0x4c0006da, 0xb366194c, + 0xd6b3ce92, 0x5ec9b566, 0x9d3e78e8, 0x4b3ddc11, 0xc797f351, 0x232c7089, 0xc488548a, 0x469cf1c9, 0x3bf88fa8, + 0xf1fa0125, 0x84bd52fb, 0xef2e327d, 0x19237b2c, 0x9dcfa4fe, 0xc3e498cf, 0xc0e71604, 0x0c978f68, 0x86ec952c, + 0x09a34315, 0x66b1bd43, 0xd850a6e1, 0xec4ad9b8, 0xf406d5a3, 0xef706cdf, 0x63d015d3, 0x8a6ccd30, 0xe8f44662, + 0xba8c0530, 0xeb429c37, 0x4eda8caf, 0xc82cc4f8, 0x384710c5, 0x7a548866, 0x57197e19, 0x63a07658, 0xf2bb6094, + 0x98970722, 0x48a10ae9, 0xc916b374, 0x40d08cdc, 0x07b6ee42, 0xe0b4d82c, 0xdf32011e, 0xc9ff5c53, 0x18ae25cb, + 0xc2a968bc, 0x76554d70, 0xd19243dc, 0xdddda691, 0x083686bf, 0x0fb5051c, 0x0b717df9, 0x06b0d648, 0x5d096ff0, + 0x31c5d742, 0x83f4e254, 0xea605537, 0xb9d8e6fc, 0x2596c1d5, 0x8aabd63e, 0x9e41dcb6, 0x23683dd6, 0x09bdac0c, + 0x6f4d17ec, 0x52a3f2fb, 0x48c26c3d, 0xdeef0969, 0x1067e80a, 0x12054206, 0x21851921, 0x65a26b99, 0xc8f8774f, + 0xe44db5ed, 0x759c3e06, 0xd43f27d7, 0x46d1973c, 0x70c2480d, 0x0602f485, 0x64e9ca68, 0x235f0be4, 0xa7f29f85, + 0x71198ee0, 0x88ad4336, 0x30bd9c33, 0x453f4b17, 0xd1b6001f, 0x08712b52, 0x67cf4de3, 0x6e9342e8, 0x36e2761b, + 0xade7ffc7, 0xd5f4d488, 0x0d1946ff, 0x4a607c24, 0xa4e886ee, 0xde6d5592, 0x279890aa, 0x9ed914c7, 0x34324fe4, + 0x65745d4d, 0x98c323c3, 0x3652c81b, 0xcbac96a4, 0xa37c4051, 0xf04e8376, 0x3498d7ec, 0xa067e02f, 0xb49a9b29, + 0xaf0fe586, 0x7b9dcfe6, 0x3e023cc5, 0x773da834, 0xbfcbb160, 0x9f6b2986, 0x0737b7c0, 0x867b3302, 0x57afaf8e, + 0xa6d1401d, 0xf71f29b8, 0x1edaf8eb, 0x103349d2, 0xfdda4226, 0xe247ab62, 0xbc8a4308, 0x84056220, 0xd543a8ec, + 0x77154dee, 0xc24c8f8d, 0xe74bb42c, 0xbacf396e, 0x646526de, 0x3b963b34, 0x408bd3bf, 0xf4a2ff10, 0x43f9524b, + 0x1112c3fa, 0x0a152f38, 0x45688bd1, 0x28442bb7, 0x18b92621, 0xf42eadb7, 0xf6baeec3, 0x79112aaa, 0x24fe8452, + 0x21f0d6e7, 0xfd383757, 0xa867c0c8, 0x2fb4404e, 0xc4722c95, 0xf9d00b19, 0x4f7aede3, 0x50a14b35, 0xeb85ab6a, + 0x7ea22c95, 0x703fcd2e, 0x7ffd7d35, 0x982d6bd7, 0x1f9a69e7, 0x4305ea17, 0xeab1571d, 0x488f113b, 0x8669ae1a, + 0x9c41fdf3, 0x849cfe7d, 0xb0320bbc, 0xf92e6634, 0x5885789f, 0x6e031cd5, 0xede73c1f, 0xb4052bd2, 0xf9b3e9cf, + 0x51a6cad2, 0xda6ccddb, 0xe8e2a74b, 0x717d1680, 0x8ff3902a, 0x3d701279, 0x5ebd95cc, 0xa1b03372, 0x291e153d, + 0xb56162e6, 0x53a9a048, 0x70e988ce, 0x26a2b703, 0x21703be2, 0xb1f454bd, 0x853b97d3, 0xc676223b, 0x0faaf6dd, + 0x0a624198, 0x73fd23d3, 0xb8dac9f1, 0x7bff0582, 0xbb3793ec, 0x9f5ee15e, 0xc8962c5e, 0xa7a0f7fd, 0x2c661148, + 0xf8bf5b7d, 0x5ac9a1b0, 0xaf9fdbf5, 0xf9a56db1, 0x753a664f, 0x35f89f2e, 0xf7d7fefd, 0x54b142cb, 0xbaee68a3, + 0x89dd932f, 0xe13c1c1d, 0x8a3bcf59, 0x539eee6a, 0x7b5b0097, 0x190daf36, 0x042c828e, 0xdec84aed, 0xaee06008, + 0x8f2d4408, 0x90859f6b, 0xd2b4044f, 0xfe1e0da9, 0xe06a815c, 0x915b639c, 0xfb0eb354, 0xb5df2d83, 0xf2dcd60b, + 0xe2d172f6, 0xfe1a0496, 0xd9d4da18, 0xde8bf3cb, 0x6620765f, 0x7182d4bc, 0xc0c2072d, 0x2cef18a7, 0x1c41cc86, + 0x537d1fd0, 0xbf887d45, 0x00e2ff73, 0x6ef7b036, 0xed593b2e, 0x985cea32, 0xed59bdf5, 0xc1300268, 0x98c26f18, + 0x423bacc2, 0x1eab5368, 0x56f1f56a, 0xd513e4de, 0x26e17fc2, 0x15fb7909, 0x9babb7cc, 0x0f480dd8, 0xdaf553c5, + 0xe110822a, 0x2c638902, 0x7e6321e7, 0x3dbc9fc4, 0x5038599a, 0x51b83644, 0x39c653b9, 0x1defff4e, 0x2d1489db, + 0xca006f9d, 0x66b8cc8f, 0x5da59905, 0xa797456d, 0x09b64f2c, 0xba670f16, 0x22896d3d, 0xe5d24c3c, 0xb1097871, + 0xa3fb8ae8, 0xd1038b6b, 0x5fd29dbe, 0x38e4013f, 0xd9e7aeca, 0x2469a63d, 0x20dbea27, 0x3cc58a0f, 0xac68d64e, + 0xea8b161c, 0xab537486, 0xf9ebe71c, 0xcdd96b54, 0x5d2a2c7d, 0x8b0fa247, 0x67e33dfb, 0x68aa5058, 0xd86e8e4a, + 0xdc2a308a, 0x57879bf7, 0x60489189, 0xe2b0adb2, 0xdff18e92, 0x2a60dd12, 0x2ca6ba80, 0x1c6c8802, 0xa4759ada, + 0x6b94a77e, 0xc2cf362c, 0xca6bee91, 0xbbf9f439, 0x38b0c272, 0x54bf0385, 0x5f9fe81d, 0x0b07bf37, 0x286548b9, + 0xda6d259e, 0xc05b3236, 0x95365c68, 0xeddc4a7a, 0x4b6d6e9f, 0x242cb4dc, 0x37d5faac, 0xa6c309f2, 0xfa925040, + 0x8f49d60e, 0x923eae02, 0x65d56039, 0x889ac21f, 0xeccd01c4, 0x8aff0521, 0x43881ff1, 0xd59fddbd, 0xf0531eed, + 0xb96358bf, 0x7e1fd165, 0xecc0b686, 0xc537d839, 0x5f40f92c, 0xc47acb04, 0x3e2b1bfe, 0x56e5ba6b, 0xd37ad707, + 0xf09f4a39, 0x61b12a44, 0xaef997db, 0x6bb5b982, 0x50cfb5ea, 0x46054bd8, 0xc803baf7, 0xaa2b848d, 0x148a1d33, + 0x476d0ea5, 0x2d5a205e, 0x42b889e9, 0x22dc7d2f, 0x842d41cd, 0xf5a43eaa, 0xd2e093c8, 0x37d39b31, 0x6ccb79d9, + 0xf254efe7, 0x6c895dce, 0x134999d2, 0x453ff9eb, 0x2247ed34, 0x7db82db3, 0x87283c37, 0x59f82acb, 0x949f329e, + 0xd2685cf4, 0x4f07b04b, 0xe5242896, 0x62f2462d, 0x5b3f840e, 0xb9787aeb, 0xb4deede1, 0x304e82ca, 0xc65b0cc8, + 0x2c5adc2f, 0x2bb8b17e, 0xde805bcd, 0x77e55215, 0x1c41bbd3, 0x67527d54, 0x8bde8d79, 0x71f9b41a, 0xa57475d0, + 0x8f7f6304, 0xb3276256, 0xa8484bc5, 0x4c84293a, 0x6c7e9465, 0xfa87d161, 0x6e0b89a7, 0x7f81769c, 0x8945eed9, + 0x6176d8f0, 0xa0edfc14, 0xcc03f2c7, 0x57c1424c, 0xb8e65008, 0x12660047, 0xd8488b6a, 0x8cfbc9c8, 0xb1d7e7c9, + 0x19092baa, 0x2581874f, 0x8cb0314b, 0x051089ac, 0x446fcbf8, 0xb8df565c, 0xf48b1f8c, 0x979632ee, 0x69a8b74e, + 0x3a4268c3, 0x1a38dec8, 0x22199ad4, 0xcffdb9d9, 0xfaed414c, 0xbf20aff1, 0x880f578a, 0x258f22fd, 0xbd84f708, + 0x4672a7ec, 0xf5d6159a, 0x324b7a5e, 0x5ef9ba43, 0x1ca4ca5b, 0x6bc4b187, 0x4db3c7fd, 0xf4148da4, 0xdbf22097, + 0xa42b1497, 0x423a43dc, 0xd10daefb, 0xd2019658, 0xda2818ba, 0x4c1ed037, 0x386a440c, 0x6bbf494d, 0x6904a2c6, + 0x5b2425b6, 0x50947e48, 0xd4e94c44, 0x7df7836a, 0x5c3623d0, 0x899e4432, 0xdd76007a, 0x4985c0b8, 0x3183ea39, + 0x74e53cd8, 0x9e9a92fa, 0xe1f7ec19, 0xe6be60f5, 0xda7a83b8, 0xab296d3f, 0x88c51b2d, 0x2cb2138b, 0x6c703d2d, + 0x92df3c90, 0x7a1b5d5d, 0x4e14399b, 0xc51861f3, 0xf776c2d4, 0x4cfea0d5, 0x48b2059d, 0x5f572003, 0x28bacffb, + 0xa1eff6de, 0xe411b523, 0xb20170ee, 0xb41659c8, 0xec76ed73, 0x610cd689, 0x890786b9, 0x799410f0, 0x06d95efa, + 0x7c3c00f8, 0x250cbd5b, 0xfe818cbe, 0xa5e0e578, 0x0c7131e0, 0x068dcff9, 0x1cb01886, 0x589cce2b, 0x3c05cd68, + 0x202d6863, 0xacba0c87, 0x89ad4bc9, 0xd3ef54cd, 0x1250ff2d, 0xd023e6d8, 0x7896bfd2, 0x3961e29b, 0x2623afd0, + 0xa2fac8b9, 0x7a6ab204, 0x80e22ea1, 0xef5f3ae2, 0xb696bb64, 0xedbf1591, 0x5f5270dd, 0x8e4cf301, 0x62feb467, + 0xecc4570f, 0xb20ab3ac, 0xb4a66aab, 0x77302b00, 0x17409829, 0x6184d2a9, 0x2a1aa43d, 0xe70e4b10, 0xb5ea9835, + 0xc14a304f, 0xbcc0cda4, 0xf3c001e7, 0x358dda44, 0xe500abe8, 0x44b2b3cb, 0x903f6b5b, 0xbdaee451, 0xf20c2653, + 0xfd922e32, 0x4a9dcbec, 0x23326955, 0xc9252526, 0xa885e935, 0x6704e642, 0xc554bf2f, 0x359ed616, 0x3d3b0ac5, + 0x19bd1590, 0x49817f20, 0xf55b7f9a, 0xd4ebbca1, 0x5a1b0b5c, 0xd224c09d, 0x28c24b9f, 0xe19a3853, 0xf1797cb7, + 0x29f56f53, 0x6eda0e20, 0x12fe8f4e, 0x14331d33, 0x142bd5f8, 0xdea8da2b, 0x6181642f, 0x0af6bac0, 0x60aeceb9, + 0x96e8df51, 0x12c25d18, 0x1c1f892f, 0x7f2d06c1, 0xd8447b57, 0x18f8c526, 0xe833fd0a, 0xfaabf371, 0x817d4b20, + 0x75ec4adc, 0xb422f5f0, 0x184713e6, 0x37efc0d4, 0x0c201f1d, 0x8bda9174, 0x45ffbb90, 0xb131b92c, 0x16e1a2ab, + 0x57a10b23, 0xb70fd260, 0x6dd7384d, 0xd0237b66, 0x221b2104, 0xc7c0d7ea, 0x89e9abcf, 0x5603db28, 0xd362cb12, + 0xeb8fe03a, 0x8120027a, 0x9791796e, 0xfe036646, 0x9c2bb3ee, 0xcc197537, 0xaab271eb, 0xcdcf7f2a, 0xaa2b6bf6, + 0x0fc17ecc, 0xb04f1b28, 0xcadf6bdc, 0x82329272, 0xe65de02c, 0x12829511, 0x5705715b, 0xc3746c35, 0x1c450f25, + 0x5374e434, 0xd528ffea, 0x07f20117, 0x4778714e, 0x694bc014, 0xa5976ab2, 0xcf428ae5, 0x217d6592, 0xbf84eca3, + 0xa0691d9b, 0x1f413686, 0xc99b4f42, 0x06f4613b, 0xf4d349f7, 0x57541379, 0xd8c5dde8, 0xd3ccb936, 0x52a15528, + 0x72d76b65, 0x02366c07, 0x285c7f30, 0x7408c9e1, 0xc2443184, 0x0e69d22e, 0x2757249c, 0x566e14a0, 0xd52857c5, + 0x7346d11d, 0x1cbfed0e, 0x2d206b0f, 0x266a7b4e, 0xde26d155, 0x97ed6ea3, 0x360cfaba, 0x0c302bf4, 0x2e9f93aa, + 0xc072f226, 0x3c9d8624, 0xfe5378fe, 0x93d32595, 0x5a6fe3e4, 0xa196787a, 0x09da225e, 0xe913cef0, 0x0be892e7, + 0x1e326e54, 0x1a1e631d, 0x78daf6de, 0x6b2c7e30, 0xa1b06e3a, 0xa5998b23, 0x15b5d741, 0xee6affc6, 0x7f33644e, + 0xde956f1d, 0xe4290b62, 0x5ebd14a9, 0xefef61ed, 0xb5eb49c7, 0x6152a87f, 0x5d6ce7ad, 0x2ed94d2c, 0xf6ef02f3, + 0x06423085, 0x17a0a1b0, 0x991f7c4d, 0xe4216b19, 0xf330537e, 0x8bcf0736, 0x88b1c8ab, 0x3084ec82, 0x7e97e740, + 0x5646e1bd, 0x44de2bd0, 0xa1962338, 0x0573136c, 0x9d4acaa3, 0x594900f7, 0xb728500d, 0xc084c211, 0x2b2f73c4, + 0xd0326b24, 0x3afe036d, 0x8d909022, 0xf073de20, 0x54b9499f, 0x4db171b8, 0xc41f5c57, 0xde76cb70, 0x59d6de8c, + 0x9b1337e1, 0x03e065f7, 0x9e2ea92a, 0x2353f3bf, 0xf508e9bd, 0xc96eef98, 0x33a06860, 0x50a76e2f, 0x4cbf0925, + 0xe77d2cc6, 0x493896d1, 0xcfc77501, 0x4a636e16, 0xd63e305a, 0xc1ac8e5f, 0x9f69c2dd, 0x481198d0, 0xc69775a9, + 0x2772a002, 0xa1f509aa, 0xcd40a466, 0x40acfdfc, 0xbd6cc45c, 0x107a942b, 0x4ca928f2, 0xfcb14248, 0x9ae56779, + 0x44b73d3d, 0xb0f6a65b, 0x6c2b13ec, 0x849bd356, 0xc49868c0, 0xd234538b, 0x032df9c3, 0x0543b454, 0x5aef7a6a, + 0xcf2a7f2a, 0x4970930c, 0x3efea2f1, 0x059cdc9b, 0x3530f37a, 0x24b803ec, 0x97b8ea5c, 0x647a573c, 0x85e67a33, + 0x09d09489, 0xdb975a84, 0x3afad07c, 0xfcbd4b5d, 0xf70745e1, 0x6a6bccee, 0x9e1ccd0d, 0xe3387d02, 0x7984218e, + 0x00f265c7, 0xd1319afe, 0x033f5a68, 0xba56ae4c, 0x2a941588, 0x191bc52f, 0x51d71015, 0x59935de2, 0x8e45316b, + 0xc8038953, 0x970a415f, 0x32bebdfc, 0x59281515, 0x8f267162, 0xb0f0fe04, 0xa76f6945, 0x45990031, 0xb96289da, + 0xad5b26a6, 0xef4b7832, 0xacf13f55, 0x203f811c, 0x557778e7, 0xf0a64554, 0x16481b76, 0x2e6a9fe9, 0x6ba260b5, + 0x5a979463, 0x79ede359, 0x017dea11, 0x20f9fec3, 0xc933d809, 0xe4aa25e9, 0x8a91e8b5, 0x9f2c9ccb, 0x859aefd9, + 0x0abe3189, 0x980e7e4c, 0x7403c246, 0x0eeddab6, 0x3304477b, 0x32eb3b75, 0x5acdd026, 0x73fa67f4, 0x9c7065a8, + 0x5ea6d1eb, 0x95a3f91c, 0x2e5e9c50, 0x987fc114, 0xa49e2073, 0x94f911e7, 0x6d20052c, 0x405eb79d, 0x97ceb95c, + 0x3d137769, 0xda97f481, 0x891a1ae4, 0xcefdf21b, 0x67edd48c, 0xe8e332c6, 0xfb36dc44, 0x10148e0c, 0x095ec964, + 0x8a242913, 0x3f4a3018, 0xed75023f, 0xb8825faa, 0x11ddef82, 0xa06ae057, 0x3759ab58, 0x86e08f6a, 0x7a70d323, + 0xf146fcfe, 0x93834ffe, 0xbb4a631e, 0x5107d30c, 0x95eb8e72, 0x34ff297d, 0xcc099af3, 0x3b6650e1, 0x04422225, + 0xcf201c6c, 0x6cd5dd7a, 0xf3795ed9, 0x273b7b74, 0x99cea9a4, 0x600f0575, 0xa569487b, 0x9c803e46, 0x27da7546, + 0x10615e7d, 0xe94f17fe, 0xab03d602, 0xb96ac2fe, 0x6aed01c5, 0xc96ac71f, 0x2ec03236, 0x66a8a322, 0x19aef0b6, + 0x53e5031a, 0x1790c9c4, 0x043eb258, 0x95aec69d, 0xd38fa5b2, 0x39f8dc98, 0xf29d4086, 0x656c9136, 0x5fda0036, + 0x8e2790d6, 0x87979845, 0xe0675253, 0x7020d8ca, 0xa8c8c170, 0x8594acbc, 0x79bccf41, 0x3bd6b842, 0xe2b7f444, + 0xef6e2e73, 0xbaa701a8, 0x31db3a93, 0xb653c5ac, 0x813a74ba, 0x25374163, 0x6f27e017, 0x0bbc4886, 0x1ff64538, + 0x2087da23, 0x77d886c7, 0x512a617b, 0x87fa728f, 0xf229841e, 0x2d1b7211, 0x392315fe, 0x52fa6255, 0x97dacef8, + 0x9c13480d, 0x359da6f0, 0x6c5d1876, 0x52c176dd, 0xfa9a64d1, 0x6e1c47c9, 0x74a0e5df, 0xcf82cb5e, 0xca9632a2, + 0xc6c6e3b0, 0x641bb694, 0x9fe06b0e, 0x8bb1301e, 0xf70e66f5, 0x7daccc1f, 0x1a782fe7, 0x1483c9de, 0xe0b5acb3, + 0x0816886a, 0x9436d3f6, 0xc3fffd5f, 0xa6b8ac25, 0xd903f07c, 0x6d5b6138, 0xb50962c0, 0x4a3f36f5, 0xdf161f33, + 0x6cc2e3e0, 0x79d0a640, 0x370a8c5e, 0x624c0aee, 0xb7f51cf4, 0x7ed86b08, 0x08bda660, 0x32212a8c, 0xfd65d19a, + 0x63d36b2d, 0xf8d89112, 0x0850cf0c, 0x9300374a, 0x8d8acaa4, 0x7176000b, 0xf335ce5e, 0x477273c5, 0x9ffe177c, + 0xc19cb057, 0x8ddd876a, 0xed74f834, 0x618f6e7c, 0x889f1f6a, 0xd9d8dc4a, 0xe25222d0, 0xa2f8bcf0, 0x40973b66, + 0x2e7feaa5, 0x92457936, 0x8026e483, 0x47e07d3d, 0xb8373971, 0xcb45f068, 0x0c408804, 0xb97c282c, 0x6e41399f, + 0xc7c3f861, 0x0792d633, 0x3e90be74, 0xf3dacfba, 0xc0e14278, 0x0a48fc37, 0x2602d7c4, 0xbf2c7e0d, 0xbdc6c547, + 0xecee8a67, 0xad8f8250, 0xef6b90c0, 0x61aad99d, 0xb6275b1f, 0x1ba737e3, 0xcd2bad82, 0x1657e400, 0x4dce237a, + 0x79603794, 0x5e301441, 0xbcc76155, 0x143a185d, 0x0b37aa55, 0xe67e3158, 0xa004e36d, 0x3d0cf96a, 0x8eb817fc, + 0x2c2a93d3, 0x1f724437, 0x6625ca41, 0x68cbd162, 0x6f8629ec, 0xbdcbcd23, 0x72ad2f68, 0xbf57ce0c, 0x954a92bf, + 0x22306139, 0x993c8af0, 0x42a720fa, 0xc6d4e32e, 0x98af0220, 0xd075c3a3, 0x2b740e24, 0xa015e3af, 0x03063df2, + 0x6ecca85c, 0x3adbc719, 0x067c371b, 0x2cea1c70, 0xb43353ca, 0x6edb1a26, 0x84613603, 0x6f471576, 0xc51195ac, + 0xa8da3338, 0x21b95ec7, 0x677390d8, 0x44c37857, 0x9c8b2aeb, 0x28423e89, 0x0a705240, 0xd3a044ce, 0xac5b3c75, + 0xfa5898ac, 0xe8d969d1, 0x31502264, 0x0c1ceab0, 0x7b839b6d, 0x38ccc18b, 0x11042c84, 0x7a8984c3, 0x0834efad, + 0xc61c1292, 0x8ac1dd36, 0xe6a32372, 0x13b50fe7, 0xbb134788, 0x158d0d01, 0x678793b9, 0x9f6b113c, 0xc4b89707, + 0x88cf7b01, 0xb08687a6, 0x79003171, 0xcee2ce4f, 0x4a03ea5e, 0xc8b69243, 0x5fc31c8b, 0xb85bd14c, 0x13d67694, + 0x777529d3, 0x455cfd09, 0x98d6ad45, 0x73994f0a, 0xa14967ab, 0x639df92c, 0x7e433347, 0xd152a01a, 0x481f621d, + 0x326616cd, 0x650a4175, 0xc687fea5, 0xc27c4e8c, 0x129c0b98, 0x96d98c6a, 0xb7955320, 0x03ce5798, 0xb808792d, + 0x2d12bddc, 0xac104f11, 0x17bb0173, 0x225dcf61, 0xc83c646e, 0xae229d54, 0x80314356, 0x9da8bd09, 0x0f1f3031, + 0x7d7828b7, 0x1a550593, 0xc8dbfae8, 0xc3c10e1d, 0x3411de13, 0x14406ed5, 0xbff4a4df, 0x862d3a9d, 0x80fdbf85, + 0xcb611fac, 0x877827e5, 0x95151c77, 0x75d8e9da, 0x2ddc0124, 0xcfd9f01d, 0x5d9ecd3e, 0x7b604c17, 0xe7a7da48, + 0x4fafd14c, 0xaa4d90c6, 0x86a04945, 0x888c2402, 0x9aa669d0, 0x566ffa1d, 0xaed0993f, 0x6990a74b, 0xcfb6500d, + 0x8130f6ee, 0x739951bc, 0xc9036a49, 0x967dc988, 0x5dbe90ce, 0x36816485, 0x9e62b072, 0x0a86075f, 0xc2386956, + 0x2106eaf6, 0xecb772d6, 0xb38ab9d3, 0x0467e475, 0xe8146669, 0x697cf0d0, 0xd913c607, 0x18154890, 0xe3b1c6f2, + 0x06677d73, 0x84f29ce7, 0x9d18bf5c, 0x630d4e98, 0x263f3494, 0x38be4d9f, 0x1b450c2d, 0xfecfd09f, 0xecc35b4c, + 0xcda97e16, 0xf6aae15d, 0x3ffaaaa8, 0x86d598e4, 0x8967f0a9, 0x084ac962, 0x82e29c88, 0x2395b1ce, 0x7ce27e37, + 0x175e9044, 0xc691e850, 0x63c97f18, 0xa18dce31, 0xb9304f95, 0xe04e5e1b, 0x8c25bff4, 0x2f77254a, 0x1c169b09, + 0x784c63fc, 0x66fcecc2, 0xe3ae6f60, 0x6d3e31ea, 0xad613aaa, 0x633f4a2e, 0xf22f1ea4, 0xee3a4c12, 0x02c32808, + 0xf195aed6, 0xbdab93b5, 0x54f33109, 0x4f7e420b, 0x6d8e1240, 0x3e1ee34e, 0x1964b851, 0x8be9432b, 0x9b8773ba, + 0xe0e73179, 0xf7f57e54, 0x0bbf630a, 0xe77154a6, 0x58a39781, 0xfa633ce5, 0x042a1886, 0xe5a6e365, 0xe5deb157, + 0xb6782eb9, 0xe5e4b4f2, 0xbca12e67, 0xb1649b66, 0xcb1e0210, 0xaedb31d9, 0xa1fd5893, 0xe62316f5, 0x8e45927e, + 0x70f3c600, 0x9aacac29, 0x3c224ec3, 0x2223b8b3, 0x558343c8, 0xd9867a84, 0xf284b4fe, 0xc583b2ef, 0xf83354fc, + 0xa61d7337, 0x5d7791ce, 0x674082f5, 0x6950a136, 0xa73e8b3f, 0x23d3150c, 0x4d38e4d5, 0xeedbf3c6, 0x48a69e88, + 0x64151cc8, 0xdfab1ca9, 0xef2bbdc2, 0x2002ce92, 0xe0740ed7, 0x25c71486, 0x1ca2048f, 0x84a3501c, 0x448f1755, + 0x8711f401, 0x2ee27c01, 0xd265f900, 0xe0defd48, 0xf4610978, 0x191110a0, 0xbc79d563, 0x74eb44bc, 0xab1dbdce, + 0xe76c093a, 0xc45fb11e, 0xca074a30, 0xbe8b9393, 0xabf3a6cf, 0xb926c240, 0x28056c99, 0x5ef3f89d, 0x665e5276, + 0x208a5fb5, 0x03c5ac25, 0x380d7b02, 0x07ec1346, 0x69c7e4f9, 0x57699605, 0xed08f285, 0x1fe5fd40, 0x5c32238c, + 0x5b1d00c8, 0x77ddcb14, 0xc07e2085, 0x2ebb3a40, 0xc8c1a34b, 0x47fd93d4, 0x8bef89f5, 0xb4e88e6c, 0xb9a7903d, + 0x72564d7a, 0xeebf21d1, 0xdff7943a, 0xba65b95e, 0x6b1a4478, 0x16ffa106, 0x98fa1f02, 0x320a3532, 0xc1ed073b, + 0x39d5430a, 0x063abdb2, 0x9c9a43b0, 0xe3b15787, 0x3c5c7b9c, 0x023138ae, 0x751d7f38, 0x8abff9d9, 0x01175fc4, + 0x2c61e6aa, 0x9e4e56c0, 0xe7caf163, 0x11846ea7, 0xa0424721, 0x6a1aceaa, 0x6de6d286, 0xaaa10a41, 0x69adcca8, + 0x6cf5c319, 0xaaa5e0b5, 0x9ecd3318, 0x4ce9c468, 0x44ff0e7b, 0x783c6d7a, 0x9e45ecc3, 0xf5d5b966, 0x6cb4a494, + 0xf81ecb45, 0xe0940cd2, 0x7941a003, 0x13070e3c, 0x3cccbfb2, 0x29a8eede, 0x552bbd87, 0x5b94076b, 0x97d20b08, + 0xd3f1f254, 0x95439904, 0xa95307a0, 0xd31cf8af, 0x3d80c6a2, 0xdf207acb, 0xad2638ad, 0xe0a6215a, 0xb41cb66a, + 0xf6b9783d, 0x1964233f, 0x5c97b9ac, 0x84dad546, 0xb42e8e54, 0x9c337879, 0x141ebac8, 0x6cd6f882, 0xa3e96b56, + 0x69f9ebd3, 0xacf34708, 0x23d76bd5, 0x44eba862, 0x89ccb30c, 0x2de96370, 0x6a6de7e2, 0x9649353c, 0x0e04302c, + 0x0f543e4f, 0xc9d5ecbe, 0x641f7100, 0x249d08c0, 0xab7ad3cc, 0x242c9312, 0x77726875, 0xc9188ba9, 0x8ffad41d, + 0x369922b0, 0x4dbe2e26, 0x9101b683, 0x53c642ab, 0x1751d9c6, 0x7b390511, 0xf872ad9c, 0x48c0c172, 0xfbaee34f, + 0xbc927cf9, 0x082f70b9, 0xf6f24845, 0x7383e873, 0xf4a66a97, 0xbc8a6709, 0x234623ec, 0x3ff130d2, 0xad588e36, + 0x0e69c822, 0xdb850b49, 0xb613e5a4, 0xd1a8797e, 0x7eb6cb33, 0x5f893d55, 0xab6c0580, 0xf39615f9, 0x00d174b9, + 0x45708524, 0x5285e52d, 0x432b1b4e, 0xbdf82e24, 0x1e55ac18, 0x8c8423cb, 0x889d906f, 0x2b002322, 0xe240b49c, + 0x20be93b6, 0xce9bbd31, 0x762f8166, 0x1644bd63, 0xe7ea6485, 0x92ff9744, 0x7d1b660b, 0x1a179523, 0x5f3531c7, + 0x10f1d7f7, 0x65ca6d12, 0x03ae9249, 0xdebb0b8f, 0x13d1d5fc, 0xa33bce75, 0xc1bf0220, 0xfa338266, 0xb3526b70, + 0x522c1a95, 0x6144109b, 0xb22c4572, 0x52c161fc, 0x59a6404b, 0xfd2dcc31, 0x6251147e, 0x159bf1ed, 0xb1f91444, + 0xea17d283, 0xbdae6e2d, 0x16b2c226, 0x218a9c15, 0x3a3e013b, 0x09c28bac, 0x1286539a, 0x5d095077, 0x1f00710c, + 0x55ae6138, 0x8176cf66, 0x80ef9e69, 0x23bfbbef, 0x62b6d71f, 0x2ff580ff, 0xc1fe7173, 0xb77e6ec4, 0xb8fea85b, + 0x1eee4bb1, 0x971800af, 0xcc47275d, 0x7e53f190, 0x71c81b10, 0x6693b9df, 0x113a663c, 0x33cc7e4a, 0xb8eea515, + 0x983f8ab5, 0x6364ef38, 0x9c701fb3, 0xbe388079, 0x2abf97e0, 0xf064b225, 0xd1f78f11, 0xc3da2366, 0xcf1bab25, + 0xd6b1052c, 0xd702b631, 0x44ecbd75, 0xf6626a83, 0xf431f1c2, 0x60292c84, 0x7dedb55c, 0xc4f54875, 0x15c1c4b5, + 0x97cf24f8, 0x42d23c20, 0x78d7bb7b, 0x01724941, 0x515c3986, 0x1e975454, 0x335bab01, 0x75b3958c, 0xa899470d, + 0xa575105f, 0x6f1bfbd1, 0x2e66a76f, 0x77c14f49, 0xc1400118, 0xd146f4a9, 0xdc36236a, 0x36524a9c, 0x59e2cffc, + 0xd6d07ef6, 0xa96831b4, 0x8670d224, 0x65e5fd23, 0xa6192278, 0x15ec1dbf, 0x8ee21dea, 0x7c8a064e, 0x3390b8fa, + 0xb2c69a91, 0x1c24bc4e, 0x1c96150b, 0x2d323f67, 0x6df3e149, 0x27bc6970, 0x316abc2e, 0x184b475d, 0x8cfc80f3, + 0x7be2332d, 0x4dc71eaa, 0x9c7a4c2c, 0xfca0aa48, 0xfe51b3b6, 0xb3f68f6e, 0x2bb506d1, 0x11495dd7, 0x091c52a8, + 0xe492475c, 0x8fac7ac3, 0xf883dd2d, 0xd579a8ea, 0xec04d1b9, 0x2b19b504, 0x29bf83ab, 0x0161a4f7, 0x67d22295, + 0xf36adf73, 0x3299f5de, 0x6b7a3a32, 0x671c6af2, 0x3e84c1f3, 0xd759fdab, 0x1cc7aa6f, 0x7b4e66cc, 0xbccdb2d0, + 0x5b8022a3, 0xb348d1a1, 0xdd99ffc3, 0xd9081cc8, 0x2f4dd1c3, 0x696e6744, 0x7d22d9ff, 0x4e0c92a3, 0x5c79caee, + 0xca6b2035, 0xc1f27fa4, 0xed3b64d9, 0xd9b27517, 0x3432f118, 0x0c254de8, 0xf7ea9712, 0xd124c75c, 0xc0bf4535, + 0x7126589b, 0x31dca9c8, 0x0369509e, 0xd5b96823, 0x6f21f697, 0x46480038, 0x51c58859, 0x60b7e7ec, 0x81b605cd, + 0xc0f1cae9, 0x084db535, 0x08f6bf4a, 0x2240dbb2, 0x089a8aad, 0xb9f7db29, 0x57f90800, 0x3171faa7, 0x8b4f354f, + 0xa0ea02f1, 0xf37664a8, 0xed95d554, 0xc13595b5, 0x35300926, 0x04ba10c8, 0xc52e47d7, 0x886c9746, 0xcf654245, + 0xffc28f1c, 0x11e51f8f, 0xc6ba8c73, 0x37ff9ace, 0xe6e1f26d, 0x1f9a3aab, 0x5eabb684, 0x5dcc809c, 0x26bf7f18, + 0x30082656, 0x73802e30, 0x97d364bd, 0xa4d38776, 0x46fbf7f8, 0x8dce9bba, 0xc0c70399, 0x96b17a52, 0x7f1a2a7d, + 0x040c27e7, 0xbe5a2cc5, 0x6d6319c9, 0x78350f3a, 0x41f52cd3, 0x067a59ba, 0xcc03fa47, 0xa5b4b840, 0x855d9fe4, + 0x53c32e14, 0xa73effff, 0x19e57f64, 0x020ba138, 0x6472e691, 0xdffaa14d, 0x7e81be06, 0xc75764ce, 0x17e40842, + 0xe67281ff, 0xb582e23f, 0x43ed00ce, 0xebcd095e, 0x436bb86e, 0x5bd5f55c, 0x8a9ff7bf, 0x33b7a023, 0x091d62bb, + 0x02c9cbfd, 0x3d7d7517, 0x4c6733ee, 0x6d88d8e4, 0x9ec66309, 0xfa74e85a, 0xa8ccbdd8, 0x5ff4143b, 0xdff00e97, + 0xb33a89cc, 0x98fc6d87, 0x5cb9a903, 0xafcd8985, 0xe8774c5f, 0x700a0f10, 0xe8d87c53, 0xd1ba1c38, 0x368e6727, + 0x1becd6e7, 0xb8c73e67, 0x1eb555c2, 0xa837c38e, 0x4ef5fabd, 0x6e258a2b, 0x70c49ee6, 0x884fbb52, 0xd96a452e, + 0x562e0184, 0x921c569d, 0xd04ec66f, 0x92c08dda, 0x29e3133f, 0x22df7bd3, 0x0475338c, 0x4e2d831d, 0xe75d8db7, + 0xba2a0773, 0x1b41acde, 0x98ce4872, 0x105ecef6, 0x91a4c36d, 0x8ab27b8f, 0x68f0f85b, 0x2a709604, 0xa60c7801, + 0xde500fdd, 0x07ca5a26, 0x44321aec, 0x8e30b324, 0xa2d393da, 0xf575916b, 0x996f4381, 0xce508d1b, 0x8912f6dc, + 0xeb76dc5b, 0x837753c8, 0xcfbff0da, 0xc6dfefcb, 0x71c7eb7b, 0x2989a01f, 0x467975ce, 0x0ab7ac1f, 0x28e916d7, + 0xb1966160, 0xea4460e3, 0xef2049c0, 0xec9f9755, 0x737f2e7d, 0x3081e790, 0x8f25e937, 0xfb897b7d, 0xbfda68c6, + 0x096a3d3b, 0xd6710801, 0x198cbca0, 0x37b1beb6, 0xd61d90c6, 0x29be94cf, 0x18020ca1, 0xa82812d1, 0xd461735a, + 0x9a227959, 0x076bb83c, 0xcae38349, 0xd0d41a5a, 0x23a835d2, 0xa98b1b1a, 0xdc0b97c7, 0x8324dd2f, 0x32778dbb, + 0x9bb8d67d, 0x43f2ae94, 0x98d7d6a9, 0xb91b3b3a, 0xa6fa0840, 0x16714367, 0xa0256dd9, 0xaae10311, 0xc981dbd1, + 0xd5913fe2, 0x1dbbe0ca, 0xc8493360, 0x829a2042, 0xf1a6824a, 0x53f78c25, 0x4cabbca9, 0xac9d11a6, 0xeaf61204, + 0x9bd7113a, 0x02b3c4e1, 0x4ec037eb, 0x89911b1e, 0x2aa07312, 0xc35e1d94, 0xd1bdf239, 0x11eee6c8, 0xd5cd69dd, + 0xd15034b4, 0x8e51a972, 0x5c5db062, 0xd764c3eb, 0xedf5d12c, 0x3b050c0a, 0xde176371, 0x0ea4948f, 0x5e3ddac4, + 0x3ab493c4, 0x030b8816, 0x44e700dc, 0xfde87cfb, 0x20aecf98, 0x3a4c49b4, 0x4e174c9b, 0x5f6ce184, 0x2270af04, + 0x67cf7b87, 0x486d37ba, 0x20455a63, 0x65dc0ea1, 0xbdccac13, 0x0d273468, 0x51d1cf11, 0x9397b225, 0xe29937b6, + 0xa7e698fd, 0x591b2c2c, 0x940216d5, 0x6be8826d, 0x1c883658, 0x7a14dd8f, 0x0235ce1a, 0x82ddf167, 0xeda689c8, + 0x35c15489, 0x8426c871, 0xbfabdc6b, 0xd5ec12a6, 0xe55fc257, 0x48c24f0e, 0xf9db14a2, 0x25187fc3, 0xaa0df18c, + 0x0b643992, 0x5bf391a0, 0xb259bb0d, 0x64b83078, 0x3de9a8cd, 0xcb1086cb, 0x73c0cb8d, 0xa7723a84, 0x1f5bd907, + 0xcf204ec2, 0xe7cc50e8, 0xc75d2e56, 0x852ce110, 0xa3eb2877, 0xfe398f10, 0x2f7bed6a, 0x87b13a03, 0x876e1ef0, + 0x3fb90d40, 0x233c8bbf, 0x48663411, 0x05a110c8, 0xc6df8caf, 0xba32725f, 0xa7484ee9, 0x84f19f4a, 0xc89cedb1, + 0x37a2ccf9, 0x971229d1, 0x0ca373a4, 0x8013fa9f, 0x7a52f43e, 0x2e553d7d, 0xcea599d0, 0x12c02d95, 0xc2312aa7, + 0xf7e79bb1, 0xfc21fb5a, 0x9fd610f0, 0x4f5b8af0, 0xe7c29fa6, 0x7a8c44b4, 0xabd19c2b, 0x34216415, 0x731e5688, + 0x0fd2a910, 0x294879a1, 0x6ac4e77a, 0xd19e9152, 0x3db486b3, 0x52260eb6, 0x333abbaa, 0x9f1ee206, 0x64124118, + 0xf22d65b4, 0xe724bb37, 0x13e7fd22, 0x117cd628, 0x97d3671e, 0xb7468fd3, 0xb1b8741a, 0xca200c02, 0x454d1749, + 0xc40eff74, 0x4819e524, 0x7c20095f, 0x2e36c3a4, 0x92622b81, 0x76af6bc2, 0xc4ec1ca7, 0x71fa7d55, 0x6198b368, + 0x27a2f90a, 0x48d481a0, 0x4acbb6f7, 0x844a254d, 0x94519958, 0x01f1a8d7, 0xde1ad8db, 0xf8a1b41e, 0xa2265f1b, + 0x40068236, 0x35078481, 0x0eb16da2, 0xd9d7d679, 0xd0ada639, 0x0a6575c6, 0x925f00b4, 0xe633b47b, 0x9f4df483, + 0x44f15b21, 0x9058357e, 0x75ba2e73, 0x93eb3393, 0x6f9f0759, 0xd99fa703, 0xa6907c16, 0x0c6f978a, 0xd2347fe6, + 0x99d32ce2, 0xb534844a, 0x2835d97c, 0x0aa14a3e, 0x09ea02b8, 0x133d0b94, 0x357a5219, 0x42a0bc61, 0xbf7722ef, + 0xf2edcd43, 0x8f459081, 0x426899b4, 0x065eb3e5, 0x2675d2c5, 0xb3d4ea17, 0x79a2df47, 0xa92505e4, 0xcaab6caa, + 0xff93d5dd, 0xea21fb57, 0x5cfb5377, 0x6ff6ca09, 0x0f322aeb, 0x043dafb4, 0xb44a4372, 0x0dcd5f5d, 0xd7a44852, + 0x69fd6fd8, 0xedf6dbf7, 0x5590a454, 0xef2b7d3c, 0x5ae35c09, 0x7f82e73e, 0x2016ef3f, 0x747c9807, 0xacecb844, + 0x8a148119, 0xaa765c7b, 0x550a8b84, 0xaf33f3d0, 0x4a636432, 0xab38b34e, 0x60180f2b, 0x992568af, 0x2f4b9a8e, + 0xb8b2a64c, 0x1314cc1b, 0x4eacbe96, 0xa0ba2308, 0x5a261fbc, 0x21f09fe9, 0x15f15f59, 0xf092e49d, 0xb615d82a, + 0xe556a217, 0xed536282, 0x2cfe3a71, 0x6acc5d03, 0x5cc5bc05, 0xa5860f94, 0x0975eaff, 0xb5e023b9, 0x33a51ec9, + 0x22e3ac94, 0x8d3e3049, 0x18acd455, 0xb185281a, 0x05bfc3b0, 0xff46379d, 0xce739c98, 0x8feeca18, 0x64ea2747, + 0xe163b9a9, 0xc4cb93e0, 0xd4f4239a, 0x5e8f77f5, 0xb38cfb59, 0x961d4374, 0xf5ec1f3a, 0xabaceaef, 0x20e705da, + 0x35ce7678, 0x46fa043b, 0x60af4885, 0x01398005, 0x377e9830, 0x05f2e02f, 0x11c14535, 0x607fc172, 0x7a8c5a27, + 0xbbd3348b, 0x8eb8e257, 0x0181a507, 0xae3aa88b, 0xf53014ad, 0xf280c800, 0x707ba745, 0x7e829c72, 0xfb6c4d09, + 0xcf1c8490, 0xd5d60098, 0x06686b5e, 0x351db75c, 0x083ccb08, 0x54917301, 0xe17489ad, 0x581877e2, 0xe2428e5b, + 0x084578f5, 0xda632a42, 0x2e403377, 0xbdd92e51, 0x8a7ca57c, 0xcb6258ea, 0xe6fc80d1, 0x8f21df6a, 0xd2b2c451, + 0xd5a15d09, 0x72f55313, 0x2e77d721, 0xa401c2c2, 0x13f3b4ab, 0xebbe5496, 0x6393c9fe, 0xa91978c0, 0xe070c436, + 0xbb604747, 0xd4c839de, 0x14181a5e, 0x62afa9fa, 0xf58d6298, 0xd84625cd, 0x50a6007c, 0x9db82681, 0xa1709fd6, + 0xe8b85ef5, 0x61569c02, 0xcdd7297b, 0x95711e80, 0x2acbdbfa, 0xf6893684, 0x383cad14, 0x1b5567f5, 0x1cc5a101, + 0xc5406ab6, 0x2265c0d9, 0xfa89c1d9, 0x2262dad5, 0x29f8d7ef, 0x933ea605, 0x971acb42, 0x767c8262, 0xe0d01020, + 0x085129c9, 0xbe9e52d2, 0xebaaef41, 0xa724fcff, 0x3db297fd, 0x06fcd9f2, 0xe2177406, 0xdcbdf551, 0xca82a42f, + 0x78d057ca, 0x3b77fd15, 0xa5267d0e, 0xb0dddaca, 0x83717871, 0x09dbc237, 0x5188891c, 0x974582fc, 0x2de87af0, + 0x11490d89, 0x53c9ccc8, 0x5ea46000, 0xef070c49, 0x491bd2b2, 0xc82f3536, 0x5a1c35e4, 0x3cb4787c, 0xdb28e9b1, + 0x76dbed9c, 0x15c76c2b, 0x36c35cc1, 0x9a2ea792, 0x71ddc52d, 0xc088d9a1, 0x0cfee225, 0x1f3c9120, 0x845d1414, + 0x20ca7048, 0xa711ec9a, 0x8cda4fc6, 0xcf85dd61, 0xfea18692, 0x3288aa90, 0xb7bf6e1a, 0xbc42f824, 0xaf392177, + 0xfd17dc63, 0x47ec9e5d, 0x8707e7c5, 0xfb068f4f, 0x4dca70fe, 0x850e06b6, 0x33bc5700, 0xf5541715, 0x9296b301, + 0xa2840ff9, 0x28c8c7a1, 0x1e9dd545, 0x2b85246f, 0xb9dfed7e, 0x48c37e86, 0xc11e9c05, 0x66f506e1, 0x4099db37, + 0x9f58d0dc, 0xf4231ecc, 0x14aa40ee, 0xd214781c, 0x5eac4f15, 0xbc50d8a8, 0xf4f1ee4f, 0xca8c9ca8, 0x5501341a, + 0x53d86514, 0xa435554b, 0xfde2fa1e, 0xe289e2c2, 0x50e651b6, 0x7b36a84f, 0x23a9ca58, 0x870ebc23, 0xa0a87733, + 0x60b230e5, 0xd2761c62, 0x88a4d596, 0x6165c78e, 0x78fe32e9, 0x91c76aba, 0xb684a220, 0x8fb09512, 0x3d2638ca, + 0xafd219db, 0xf75b179c, 0x576e598c, 0x0026b88c, 0x1a97346b, 0x97a63b2e, 0x8c19b893, 0xd8390128, 0x4122bb41, + 0xb7c5e3af, 0xa72340cc, 0x2068b5b2, 0xfe3b152f, 0x9761030e, 0x34474713, 0xec21c4a2, 0xaec8674c, 0x0d767a4c, + 0x9974af9b, 0x668db948, 0x2cc1c949, 0x27828672, 0xe153d0f0, 0x1a10af2f, 0x8675344f, 0x112263b0, 0xffc11b4c, + 0xf09a7bad, 0xf481a744, 0x16808ab3, 0xff0d2c3a, 0x38bab4c3, 0xc8e40931, 0x3b4fa3c5, 0x1e82f647, 0x643f3965, + 0xb596458c, 0x2bfa01d0, 0x32bfa2a0, 0xc7d8d8d8, 0xcc50bd33, 0x1b048499, 0xc335bcac, 0xb9d8c862, 0x8050a301, + 0x6a8ca36b, 0x25ca35f9, 0xc2fdcdac, 0x5813697e, 0x27605af5, 0x1f0475e1, 0x4c0a8b9c, 0xde1b2599, 0x6b453281, + 0xdf792498, 0x5192f508, 0xfceb457c, 0x0e1e7f2b, 0x7b60741f, 0x1fa41314, 0xd1aaabfa, 0x64513d58, 0x31ba3085, + 0x91912e0d, 0xd869ffe7, 0xa401aa5e, 0x099e8e6a, 0xa97d89d3, 0xaba2cdfb, 0xfc681e67, 0x70ba5bd3, 0x309ee250, + 0xb293d303, 0x62d52275, 0xe4198b17, 0x0e6b944e, 0xdba3d592, 0x6a474672, 0xc6625316, 0xa72de301, 0xf0fee397, + 0xb67b7ebb, 0x8f046f24, 0x83af961b, 0xf8593c7e, 0x2d7a1696, 0x496e5356, 0xbb14801b, 0xbd04e5fa, 0x197ad627, + 0xd2a42275, 0x1670272d, 0xcf38f397, 0xe6b41912, 0xe6ee1c01, 0xf239dfd9, 0x7d9bb25c, 0xfc5e4935, 0x9e7e2e43, + 0x6d9e98d6, 0x38529cfc, 0xe0b3b436, 0x1ebbbac8, 0x0c52f078, 0x821c1cbf, 0xbc0a8b71, 0x5b5a29a0, 0x5c408bcd, + 0xca6338b6, 0xca47b528, 0xf437f888, 0x735f1c78, 0x6a7e8e8b, 0xc749eaf4, 0x346515e9, 0x8bcf390a, 0x984d8aad, + 0xc3d74c31, 0xab64c95d, 0x59f25290, 0x765dcf57, 0x46dcb0f8, 0xaa6c53a9, 0xa0bba649, 0x71a30dca, 0xcb8e205c, + 0xbf166e1f, 0x2a0bbcd4, 0x47d69d52, 0xe861c922, 0xa940891f, 0xc06ad952, 0xc9b127b2, 0x72444e05, 0xfec5e177, + 0x3a7997c5, 0x09c9ef22, 0x8f042d1e, 0x4b231e6f, 0x154e17e3, 0x269d3bdd, 0x6fdb674f, 0x92222cb3, 0xd0991104, + 0xebd23eab, 0xd2f1c378, 0x39a5e26b, 0x05785e01, 0x196bf4c1, 0xe8406a68, 0xef9fc9ae, 0xaff2ab47, 0x1c147fce, + 0x75d11ef3, 0xb852de33, 0xf90e1bb5, 0x44dd5849, 0x7ce64655, 0xcdf83a91, 0xfd6fc848, 0x961f9d42, 0x945bf5a0, + 0xa5bfb8a1, 0x927a1988, 0x02670fbb, 0xf1ccdc9a, 0x5387d112, 0xdd916932, 0x0eb1c2a7, 0xd8eb5e07, 0x0003388b, + 0x98173c95, 0x853a3954, 0xfdc22e11, 0xa099b478, 0x0af69fba, 0x4dbab0de, 0xc55319e6, 0x8d612da4, 0x80c7b31e, + 0xa5e96e30, 0x10d4a6f9, 0x9bd1fd6a, 0x8c6d9ec1, 0xa87d9f7b, 0x4d36d292, 0x6945404a, 0xe6661785, 0x17715db1, + 0x7f314ddf, 0xdf352016, 0x7cacc5d6, 0x02fc547f, 0x1e7feb77, 0x3fdea66e, 0x2477f19b, 0xafb8fdf5, 0xe3a6d28c, + 0x31233bcf, 0xd363771b, 0x1e408a7d, 0xa3d61af0, 0xd4a5a43f, 0x880339cd, 0xe91f7108, 0x66bd9515, 0x5482e38f, + 0x88ea5b8b, 0x3a85495f, 0x894db6a7, 0x7b2c9923, 0x6f4e8474, 0x33beaa06, 0x362f5fe4, 0xbf7eedb7, 0x0adfd991, + 0xf9a00751, 0xc49bedb7, 0x9447548b, 0x9942b720, 0xd63d48e3, 0x851fb135, 0xde62e8d5, 0x9f8e36a4, 0x46421bc9, + 0xd6d06ede, 0x1d2f6b4b, 0x2262a49e, 0x0f16fb8d, 0x02bf0ac1, 0x36178fb4, 0x78138f74, 0x6aeec04e, 0x5938da02, + 0x1adb0c2f, 0x3a30f4cd, 0x5102bea4, 0x0b779433, 0x74513b47, 0x599e95bc, 0xa58967a5, 0xd5169520, 0x4d1bec2e, + 0xb4550c1f, 0x1b42b974, 0x30c066f1, 0x02303a33, 0xd5ef4e05, 0x0730db3b, 0x6daafe49, 0x7b1b9182, 0x3c63172b, + 0xfd218627, 0xdec316f9, 0x464aabc5, 0xfb79392f, 0x0cba51b1, 0x553a996a, 0x803f94a2, 0x4551cb17, 0x767bb1f3, + 0x4ad42bbe, 0x97e6b589, 0xed9a65cf, 0xf537129c, 0x797786fe, 0xdbaa9f30, 0xff87288a, 0xb13ea766, 0x25942fb1, + 0x58a8595e, 0x24b6020e, 0x18994d97, 0xc70bc687, 0x530119af, 0xed885de5, 0x7777a1e4, 0x685bbe79, 0x18dcdc63, + 0x90fa716c, 0xc9d308b8, 0xe30e6440, 0x88b383bd, 0xb38502f0, 0x6f7bd451, 0x3db0bbb6, 0x59c3be37, 0xbb3def7a, + 0xbb782081, 0x7253a01d, 0x8362798c, 0x28ae5466, 0x09638d41, 0x680286f3, 0x553d2543, 0x6ebef289, 0x9a30f172, + 0x5f3dc0db, 0x54f41574, 0xfbef0c9d, 0x64e49af5, 0xe93955da, 0xcc7b67ca, 0x8b2ed1f9, 0xa66a5675, 0x33d199e9, + 0x12e84bd6, 0x5e1c464f, 0xc339e39d, 0xdb0a3d6e, 0xdddb5c45, 0x3a39696a, 0xddb4cc5d, 0x15b5ecc0, 0x720a6534, + 0x48a3295c, 0xbc0f250e, 0x3eb8bfd5, 0x7e3ad6c0, 0xf32bac38, 0x9a7941af, 0x61b6fcaa, 0xd3f33627, 0xa484efb7, + 0x56550a32, 0x2cc442e9, 0xc4f5efc4, 0x4ff87c65, 0xe4534fb6, 0xff62dc63, 0x76557c7c, 0xe16e57ac, 0x258f02fb, + 0xaa1f330b, 0xe8f568cb, 0x81b50b99, 0xab9c4839, 0x251a24bb, 0xa05c23a5, 0x643c7823, 0x2d7788c4, 0x827c2f4a, + 0xd57c0e43, 0x7947a10e, 0x621f1850, 0x9381c163, 0xf7d62ee1, 0x5c14962f, 0xb31916ab, 0x18343a28, 0x080aa54b, + 0x28b799a3, 0x9b727ff8, 0xdbc01963, 0x4e2bebe6, 0x599403c3, 0x3e50aced, 0x87fe3f7a, 0x35ace13f, 0xe17c7514, + 0xde0d8efc, 0x7d17c8d2, 0xb2fae4ad, 0x0fe74aa5, 0x9c65d2ab, 0x8db37259, 0xa646d247, 0x6e4d900b, 0x517222dd, + 0xecb3ac98, 0xf9806080, 0xcb22f8ff, 0x6f553fd4, 0x185ab8d7, 0x63618f0d, 0x792374d1, 0x7adeea3f, 0x7507268e, + 0x4cbc1da4, 0x3493d2b1, 0x2efdabad, 0xeb379797, 0x539faba2, 0xf1e80908, 0x38bdc081, 0x7c161e58, 0xabd36760, + 0x55b655b9, 0x116a5d9e, 0xd524fb1f, 0xbaec5d19, 0x73c47918, 0xcb81dcac, 0x3e142219, 0x0d9e40b4, 0x23236125, + 0xf95e05b6, 0x6a11bf40, 0x392c6a07, 0x88ddc6fa, 0xd1d6aa11, 0x25492a26, 0xe372d685, 0xe99bd7cd, 0x506d6ad1, + 0x77251b86, 0x9c87e898, 0x70df5455, 0x0c4dc863, 0x4c3e69bb, 0x8d3b9a93, 0x3f5cf8e5, 0x3193b0a0, 0x3292e095, + 0xda3441b4, 0x5e08b1aa, 0xbe7b9b9e, 0xdfb9822b, 0xee4b0d17, 0x7a636f58, 0x75494d45, 0xeb171de0, 0xf793c913, + 0x3f599040, 0x136ac72f, 0x02dadf3e, 0x7bec3d2e, 0x76358f18, 0x0e7c653b, 0xecf994fd, 0x6c9c9ad0, 0x1bd8637c, + 0x6c97585c, 0x45de2b9b, 0x2c6fb070, 0xdb499c2b, 0xec7cad9b, 0xb4b1225c, 0x43355da0, 0x4c1971f4, 0x3b0ef2f6, + 0xa440333b, 0x6f3dcd46, 0xdbd36ce0, 0xc0c5a26b, 0x20b9ecff, 0x71d20042, 0x216aee19, 0x2cd4de71, 0x16ed791e, + 0x4b65a3f2, 0x347faefe, 0xb12b9a52, 0xc6dc95ca, 0x91d91c08, 0x3ee9dafb, 0xfdfea36a, 0x23c77af2, 0x92b1baab, + 0x5970900f, 0xe35a3e3b, 0x1662f548, 0xeb2b48f1, 0x85beb58d, 0x2c64f39a, 0xcb1a5918, 0x471bd4ad, 0xa1158591, + 0xbcdc53fe, 0x127d0fca, 0x17c90218, 0xb117f576, 0x51912986, 0x33ea2ab4, 0x98b85997, 0xe09f5cad, 0xdb62d570, + 0xca12e929, 0x92256b35, 0x30d77bfb, 0x5b549dde, 0xd77b6e31, 0x169f1a71, 0xecf21667, 0x5ab3ab06, 0x04c72e50, + 0xe73bfbd1, 0xa049795d, 0xb4a68090, 0x930cbc6d, 0x57fbd803, 0x64ebdb93, 0x27eae131, 0x47786140, 0x01007e21, + 0x24a01351, 0x5e5a675e, 0xf0c868f6, 0x00feb2d9, 0x3451033b, 0x72a689fb, 0xb6024f54, 0x21be446d, 0x71d10b7c, + 0xa42e2b5e, 0x8868c740, 0xdd6cb27b, 0xde41a6a9, 0x34ba4c80, 0x81bca8b3, 0x3eec0bbb, 0xe5863dbe, 0x4ba35443, + 0xa016eebf, 0x9409bd0c, 0x1fabeb2f, 0x92d7dbbc, 0x1b18a01e, 0x6f70e1ae, 0xedbd263b, 0xda1237c5, 0xbca0e73c, + 0x1db07936, 0x6ce680d8, 0x25a00a6c, 0x85203ef8, 0xebe23aec, 0x014008bb, 0x07eaa242, 0x37c8add9, 0x178da921, + 0xd9371269, 0x3caef6ee, 0x4e7a9543, 0x7e6cd44b, 0x7a9e2888, 0x63386686, 0x60dbdd62, 0x5e7790c9, 0xbe527cf7, + 0xe7fa442a, 0x247b737d, 0xf216aaeb, 0x4f3d1a6a, 0xb76dc7fe, 0xe444c179, 0x83fc9195, 0x4c2cfdca, 0x45f0665b, + 0x514de281, 0x71280646, 0xccfea7f7, 0xe1d7a607, 0x7b77472d, 0xb57adb3d, 0xc8ac7cf2, 0x0b2beb48, 0xc69413de, + 0xb2cca6d6, 0x2c74ed8a, 0x29853b4c, 0x2618e36f, 0x0e73baa7, 0xa89d8297, 0xb7a97c76, 0x02243796, 0xfe1e35ca, + 0x313a3520, 0xd87461bb, 0x19c3f23e, 0xe6cc567e, 0xc21a44dd, 0x8194e436, 0x66f7dbbe, 0x826c216c, 0x8e5ba332, + 0xb81e3ad8, 0x2ab3a24c, 0xe50f15b2, 0x294baf54, 0xef2aa8af, 0xe6de42da, 0xe109c68e, 0x6360f216, 0x2b1d9877, + 0xc4ea3ba8, 0xb5241f6b, 0x54385fe2, 0x4c21d6cf, 0xa6482fd1, 0xa9c2e812, 0xff47c190, 0xe06b2a50, 0xa6002f25, + 0x04b07e80, 0xe41ab1f4, 0xf11b10be, 0x630b51d9, 0xfa69c16b, 0x92ead875, 0x03fe6b20, 0x9dbbaaf6, 0xda8b3705, + 0xb100db7e, 0x80ad8b4f, 0x6354f192, 0x87702693, 0x361e9cdd, 0x8e46ac50, 0x82d20812, 0xa14bf67f, 0x9f148d13, + 0x0656ffa7, 0xd15d1e90, 0x6d727c6e, 0xcf5396a3, 0x7be71921, 0xdfad0195, 0x3825de07, 0x887a6d75, 0x3ddec590, + 0x0b56a4b8, 0xda179f0c, 0x1c651a3d, 0x9bfa1135, 0xc1852d80, 0xd02cd4f1, 0x1b6e83fe, 0x354a7e3b, 0x6571fe08, + 0x67ea6283, 0x07ea890d, 0x8936a4ca, 0x6a69b3a1, 0x9f91b213, 0x1f63ed3c, 0xc1a80eba, 0x49190bbe, 0x6b2dad22, + 0x5504bc1a, 0x5a310ffd, 0x09f10ef4, 0x83bd67e1, 0x56d1652c, 0x6ce3feee, 0x23bcebb5, 0x77c16a53, 0x56f6e3f9, + 0x0c34e8ce, 0x4af7e2e1, 0x7338c2a9, 0x67d6d080, 0xb90036fa, 0xccc9e8f8, 0xc3b6aee3, 0xe3594c1b, 0x4c0991ef, + 0x196de054, 0xafc8c5d7, 0xdbdb2327, 0xa7ebbacd, 0xe01f01b9, 0xf5b02860, 0x6181a62f, 0x7848e6d9, 0xde92a75f, + 0xebced2f1, 0x602a0a92, 0x1c06a5a4, 0x6d60dbe1, 0x46512263, 0xf0a3c00f, 0x320e2e0f, 0xd1f7d411, 0xf295b22b, + 0x8d7f1f43, 0x6979c72f, 0xff49a183, 0x0954df20, 0x27632fd3, 0x5e4703bd, 0x220ec6b7, 0xe0932580, 0xf39e8413, + 0x1d05c53b, 0xced8e9bd, 0x7c24f501, 0x6a2f87b6, 0x92abbb07, 0xf631e332, 0x173a708a, 0x0f105722, 0xf1806fd0, + 0x7e247db2, 0x90aa4e2b, 0x78c853ed, 0xd1a39843, 0xf142c1c7, 0x82236dfb, 0xe7ca89bc, 0x8a35dcc2, 0xd9cfe9a1, + 0x5d201cf4, 0x146367be, 0x9313c862, 0xcc7c3bff, 0x836439c6, 0x62292814, 0xfd461501, 0x9ac7f74b, 0x5a85bdef, + 0x7c9cf5e2, 0xb39d3da1, 0x94b6b7f7, 0x951907ae, 0xee64a828, 0xa5914a71, 0x012b0757, 0x3fa75d3a, 0x69a16228, + 0x93be9b7d, 0xec367ded, 0x016593b1, 0x36fd9ba1, 0x1ae457e4, 0x1cd8e4d6, 0x19cd38ba, 0x5a618973, 0xcb35af8c, + 0xb04dda7e, 0xd6aa1147, 0x5e0bc222, 0x315f935f, 0xbec6a4f3, 0x74e38c0a, 0xc31f85ed, 0x20c71621, 0xc569846b, + 0xd68f5f14, 0xf441aa68, 0xdf17c6ca, 0x4951b7b7, 0xa20fbd86, 0x40c3f0e4, 0x09047dfc, 0xa8eda50a, 0xfc4e5ce3, + 0x9dcf9c5e, 0xfff861ae, 0xdf7ed781, 0x925e9b74, 0x6a86514c, 0x8f2e9442, 0xc0f3c9f6, 0x4a88b99e, 0xc9131da9, + 0x1440ba2e, 0x9e2a6c5b, 0xd187440d, 0xa581665b, 0xce20b3f8, 0x472e60b1, 0x71cfc533, 0x99d37feb, 0x1859128f, + 0xc0aa84c5, 0x9191c989, 0x42901e6a, 0x0610b4bd, 0xb6e0c012, 0xa629cd74, 0x88f38247, 0xa84049b5, 0x3eac3833, + 0xd3ab5940, 0x44685223, 0x77005b11, 0x641eb73b, 0xf5f8a75d, 0x1d80a90b, 0x44128496, 0x5bf47740, 0x74add6ba, + 0x82f2c72b, 0x7f1da202, 0xbfa38e49, 0x96e6a53b, 0xc7a4bac3, 0x2417d4da, 0x9c5bdb3a, 0xf210b350, 0xbcea5be8, + 0x9734c3d4, 0x5f417144, 0x1e2204d3, 0xe928ccb0, 0x4ebf3b6c, 0x5bfeac52, 0x62f94cf3, 0x10c3edea, 0x51c1a4eb, + 0xf5ce14c0, 0x3d025ff8, 0x79a86932, 0x8379feeb, 0xd13f8e31, 0xe96bfa5d, 0x26a6e396, 0xcc179e7c, 0xebf01213, + 0x616cd61b, 0x769845bb, 0xae66cdf9, 0x7bd8bf85, 0xd778bf1c, 0x58cab792, 0x2ec7acd7, 0x3d91b6fa, 0x86a52e88, + 0x7062eb22, 0xb0cd94d0, 0x7fd4c4ee, 0x2b250100, 0x6b580a11, 0xbab39f90, 0x7083e06e, 0x160d3917, 0x4b4bac88, + 0x750b6050, 0x51315c64, 0xcb6e8162, 0x76716710, 0x9773440c, 0xdb720298, 0x10f7bc61, 0xd84f59aa, 0x4d7103fb, + 0x1fd684f3, 0x596ddc35, 0x30ea7c7a, 0x2dfd6816, 0x62f0a273, 0x7105f6f1, 0x7ff6e8f8, 0x7529eec9, 0x99b62068, + 0xa69b1a33, 0xf130e604, 0x681ae6e1, 0xcf9faa6e, 0x6db2f3af, 0xe254ab45, 0x6e5f7066, 0xf4452ab1, 0xc1eea790, + 0xd83a9285, 0x38bd32f7, 0x0dad8a58, 0xf5827c37, 0xbbc30d2a, 0xe1a01986, 0x35cc5e17, 0x2bcb319d, 0x3c15a306, + 0xbceb1d7c, 0x596cad9a, 0x7dafbd63, 0xb3b2916a, 0xaa344d1b, 0x215d749a, 0x345d7075, 0xf17a215d, 0xd5b101d5, + 0x647ec761, 0xf8a09e1e, 0x03525790, 0xaf726cb6, 0xaf0cb6f2, 0x4e1c4afb, 0x6cddfcee, 0xf1b024c9, 0xb005b80d, + 0x782dfc18, 0x99c30e66, 0xb7bc414c, 0x6dfc3fe2, 0x5ba65de9, 0xa0839c9c, 0x143cb1f0, 0xb0724aa5, 0xa25b11b6, + 0x8cccf139, 0x7fc743c7, 0xbda0224b, 0xf1014148, 0xcaf090f4, 0xc1dc7321, 0x58c4d74d, 0xef98f75a, 0xd0c33151, + 0x3caa1398, 0x97fab1a3, 0x29f1499a, 0x0ea3c3e0, 0xd7cbe563, 0xbebfa083, 0xc8863856, 0x778083d4, 0x7cded11a, + 0xa82271a7, 0x976fecde, 0x5a5e48d0, 0x4808e581, 0xe2e3feca, 0xe982d5f8, 0xef3f58b9, 0xf424fba3, 0x183da5c8, + 0x12682990, 0xd80a7276, 0xbd95a08a, 0x08e49259, 0xf8fc593e, 0xbd5254a0, 0x22710fcc, 0x6b394750, 0xd3d2ae03, + 0xa22b1014, 0xfe5480ff, 0x248eed17, 0x72ddb48c, 0x7f01e206, 0x9557b63a, 0xd51b1d21, 0x479dbf61, 0x1e7e3e12, + 0x281c8e46, 0xa3134938, 0xcf80d1ba, 0xfe30013a, 0x08c42914, 0xbfd12300, 0xac33f8e6, 0xe9951acf, 0x59e8bc12, + 0xc2fb2e2b, 0x861c4ade, 0xc1d9613d, 0xa1009cca, 0x3d6c24b9, 0xcde9277b, 0x2bb6fc1e, 0x6c47c5c2, 0xf2cc5181, + 0x9ce5cdc5, 0x706dd22e, 0x80c9d9d3, 0xe3c96b50, 0xc878dc86, 0x6b2e7bd5, 0x4b180aaa, 0x98290393, 0x863277da, + 0x7b8e3d8c, 0x3725f738, 0x39ef2279, 0x6a5c0029, 0xeef85116, 0x09170cda, 0xca527a7f, 0x88dd0e6a, 0xa6b4357a, + 0xdb92c0af, 0x89a16ffd, 0xa7d652f0, 0x2f8bc7ed, 0x49217ee9, 0xed51408b, 0xa6af541d, 0x531f981c, 0x5501bc76, + 0xe18ffe70, 0x3dee570e, 0x819a7335, 0xa65c5a17, 0x038a73f7, 0x8cfab962, 0xe29c8447, 0x525d2de5, 0x18bdb336, + 0xf915cea1, 0x001ce325, 0x51d545a3, 0x5e806394, 0xfee68af3, 0x773f7878, 0xace6e731, 0x49ccc423, 0x2386669e, + 0x1618fe24, 0xfc94b745, 0x8bc36e9e, 0xa604bee8, 0x5e0a6100, 0x36566a74, 0x707fdcf8, 0xcb267338, 0x5bac96ab, + 0x497f7edc, 0xde0461f0, 0x7e749d40, 0xe61db3c8, 0x451f11e4, 0x71fa05a6, 0x3d35251e, 0xf93337b8, 0x77624436, + 0xb935eea5, 0x907ec506, 0x3ce3158e, 0x8d6cfa14, 0x56044749, 0x24507d71, 0xa514d8fe, 0xe9ac4234, 0xf119862b, + 0x38bac615, 0xbb39ff77, 0xda840f52, 0x5378fd55, 0x6378e846, 0x75dfc67e, 0x5f75839b, 0xe1a7189a, 0xc82af23f, + 0x30eb3bfe, 0x777a4d4c, 0x42683b6e, 0x287610ff, 0x51c9afad, 0x2ca738fd, 0xbfcf3a93, 0x57750169, 0xb2d2b4ea, + 0x7c678a69, 0x706f96f3, 0x4ed2acd0, 0x46990331, 0x5860dcc0, 0x2774370e, 0x3c958102, 0x6deda902, 0xc4e6f9c3, + 0xd8ce04f3, 0x980667ff, 0x2c2e4cc5, 0x183a33fe, 0x7249bd24, 0xb718a1e1, 0x239f8d41, 0xa8f85977, 0xcca0f2ec, + 0xaa661983, 0x842833e4, 0x0e87bc6d, 0xe61c14f7, 0x7fb5ff13, 0x8786dcb3, 0xd741de27, 0x7dd62573, 0x50c2642f, + 0xba98a418, 0x6759c5a7, 0x0fa5cc23, 0xf70e4c3a, 0x8d00dacd, 0x01d55aa2, 0x2a474895, 0xa885c1b2, 0x7fcd084d, + 0x529a382c, 0xd2a98849, 0x6c0fa18b, 0xaf3256f3, 0xd7f014ef, 0x08119cab, 0xd89c42d6, 0x1d55c12f, 0x19a12320, + 0xab97f292, 0x068e140a, 0xfdcd3054, 0x1e4a15ba, 0x4f3ffff5, 0x2f12dfc4, 0x70af5892, 0xb5b0bc7d, 0xa6524bc9, + 0xfe8b09f6, 0x63722cb3, 0xe6f94477, 0x7c8d7316, 0x5138adab, 0x66fa9ce1, 0x68fec479, 0x071ad079, 0x9cffc13e, + 0xec1fd174, 0xc8055e68, 0x2b54db29, 0xd206693b, 0x6108016a, 0xf7665922, 0xc16b78be, 0xfb29e7ff, 0x88c229ee, + 0x12a9d086, 0xae50fdee, 0xaf6fb323, 0xd9e77cf2, 0x236df4f7, 0xbff25582, 0x7a2fba09, 0xe7a23a85, 0x66f772ab, + 0x0afd3298, 0x76d82fdb, 0xc5b5f38d, 0xd2372f92, 0x0d82cffe, 0x10ee880e, 0x00be050d, 0x7f84bccb, 0xf27834af, + 0x890279c0, 0x2f17bcd3, 0xadccc693, 0x566cd180, 0xb47b1bd9, 0xfc68a18e, 0x32eee3a4, 0x6fac9149, 0x784123bb, + 0xb11ee25e, 0x4fe1382a, 0xcea0a32c, 0x73bf148e, 0x66082395, 0x4fd018a9, 0xc9c8fa33, 0x17041d2d, 0x016f200e, + 0x1dce9c63, 0x6e2aed71, 0xf2f39208, 0xd28365af, 0x39b26cbf, 0x3b72cbc0, 0xf35b3bbb, 0xd57e1f6c, 0x9490f5b4, + 0x2e320391, 0x48eec2ab, 0x4bb474f2, 0x033a7ab8, 0xbdddd760, 0xf02e5672, 0x5cbee2de, 0xc44c1c67, 0x272d1507, + 0x3e7602a6, 0x74c33245, 0x3026c4b0, 0xb2843d9d, 0x7cc622c5, 0x21ce7fc1, 0xb0b3b478, 0xc710c127, 0xfc13fd33, + 0x0c62b4ce, 0xf1ebfaff, 0xcdfc4e3c, 0x4e183d56, 0x718ea2f2, 0x9d67e096, 0x510bb309, 0x7f6ea7d6, 0x4ade6d40, + 0x001e77d5, 0x76ecc5d9, 0x39ce0f5a, 0x0ab84234, 0xea5ce638, 0x2f5f5dc0, 0x86b80b97, 0x741da541, 0xc7bbd991, + 0x821218a0, 0xf787cb25, 0x0ef9aa1e, 0xbfda788a, 0x4dbd198d, 0x321c1476, 0x048035b9, 0xa24589e5, 0x6dfca745, + 0x595159d6, 0x4a59cb20, 0x178bb139, 0x6fe6a2cf, 0xbaa6575b, 0xbe11c7bf, 0x20a530fc, 0x5343419e, 0x998fe383, + 0xbec2da0f, 0xf0196f6d, 0x86788a00, 0xedd734cd, 0xa449453b, 0x455b10e8, 0xbdef0323, 0xee20d57c, 0xbba310fa, + 0x68b21f39, 0xec741bd6, 0x96c15311, 0x680f6ef2, 0x5859198c, 0x241d39e8, 0xabbea847, 0xeedb23e4, 0xbfccf2d8, + 0xab703e79, 0x8b4e8fc6, 0x9074d49b, 0xa52e146d, 0x8ff1fa33, 0x19866f26, 0x8e391b6f, 0xb29b4549, 0x66881778, + 0x2fb51b3c, 0xea2b6fcc, 0x4695c95c, 0x8a5f5d63, 0xe886f70e, 0xf9b0ccb8, 0x24b88582, 0x292c6eb0, 0x9d87d027, + 0xe6ba40ef, 0x1b2c95aa, 0x2ea0ea3f, 0xa95cd945, 0x1901816d, 0x753f04f3, 0x73f00d6f, 0x2f81fb88, 0x3ef6f347, + 0x7dd70be1, 0xb8c3c536, 0x5da0dffc, 0xc9898dea, 0x2c372412, 0x47c8cb24, 0x36410ef0, 0x65618ac1, 0x1413ed6d, + 0xcd9f2592, 0xce927c3c, 0x6a098148, 0xc9035b12, 0xbfcb78d1, 0xbaa6c1c0, 0xe5f46a0e, 0x34872758, 0x748dced8, + 0x04e2b9c8, 0xb5856e15, 0x52970c6b, 0x4037fdcf, 0x81975867, 0x89ef25b4, 0x15ed1974, 0x3320a60f, 0x94b8584e, + 0xef2ff24e, 0x0c563dc4, 0xb967b79e, 0xe40035a5, 0x69e101ad, 0xf5de8565, 0x4d9f8586, 0xdc691606, 0x83923e77, + 0xadf9b9cf, 0xdced6717, 0x4e704198, 0xe9663e6f, 0x6365e5a6, 0xae1e950e, 0x0ed67478, 0x1383a500, 0x04b40a81, + 0xb9fa78c6, 0x3eb7454d, 0xad5fc76b, 0xbecb8578, 0xe94c4745, 0x046acbcf, 0x621371fc, 0x20e207a1, 0x8b37ec69, + 0xd9125ab1, 0x25d38d48, 0x43a05c1b, 0x6df31de7, 0xccabcd59, 0xaf43282e, 0x4bd56358, 0x5bc89c46, 0xa61ce666, + 0x5a189b55, 0xc5c71726, 0x6e087506, 0xc01cdbe7, 0xa3916002, 0xd765f70b, 0xebcdf292, 0xcbe7944c, 0xfbc9825c, + 0x557d41b1, 0x58fee58e, 0x52312367, 0xb526be44, 0x86702772, 0xa7c8531a, 0x576b7886, 0xf2f08612, 0xa8a7ea0b, + 0x274eb565, 0xcbf300ce, 0x79d93369, 0xf368b091, 0x669412d2, 0xbd1c3da6, 0x178b1246, 0xe0a32b8d, 0x0edd3768, + 0x262641de, 0x94eb5206, 0xd08f6519, 0x9c5d5b78, 0x3fa2d5ae, 0x7d9d3135, 0xd38c04f8, 0x963aa6e0, 0x92b7d30a, + 0x2b4af369, 0xce7364bb, 0x9b8719d6, 0xf180eb7b, 0x57b503a1, 0x341d8cbe, 0x56144af8, 0x3864879c, 0xab538e7f, + 0x12b0b1ec, 0x13a80144, 0x56e2ec64, 0xf0853b51, 0xadc2d9b4, 0x537b19b5, 0x04ed96db, 0xf858c4d4, 0x5a2ea22c, + 0xc665bb19, 0x5806284c, 0xccd15670, 0xa9f2312a, 0xfb39ffd8, 0x16ba39dd, 0x21e8d38e, 0x377090ae, 0x1c783a8b, + 0xa558405e, 0x12045b83, 0xf291e041, 0xe6489fec, 0xc5b552ee, 0x5f1df6ad, 0x1162b8ed, 0x5286b2b0, 0x75772819, + 0x759257b8, 0xedb17c00, 0x291b924a, 0xa774d45b, 0x034a4685, 0xb9f8b63a, 0x8e00e7f6, 0x60250bb0, 0x16a85fc0, + 0x37fea0be, 0x6e1a6d3b, 0xebf75dea, 0x37e532b7, 0xfea6d1e9, 0x4b152e8b, 0xe2e5de52, 0xe3eb3402, 0x7fef2b54, + 0x4898c63c, 0x79e9ef67, 0xd2158e76, 0x77c8b02a, 0x39ea5642, 0x0f260703, 0xe4a5a353, 0xc6996284, 0x16b22074, + 0xf8f3e610, 0xf540ab58, 0x2fa62305, 0x5db60465, 0xd4e01140, 0x18295852, 0x894c970b, 0x0655d4d2, 0xac9e07ad, + 0x9ec18493, 0xe50d2a68, 0x81d81699, 0xb7a906f6, 0x1bb0ec92, 0x6f73cdba, 0x334ea2d6, 0x397207fb, 0xf41efba3, + 0xc3c0d9f2, 0x5c2a023d, 0xc58a8e42, 0x54d65b2b, 0x507761ca, 0x73629035, 0x03a22cf7, 0xcada01c8, 0xe37f7185, + 0x9b88d11b, 0xd52a0f7d, 0xea74fee0, 0xd8d49431, 0x8409e259, 0x20bcd579, 0x5e3ea6bc, 0x73fdcea4, 0xb99cd274, + 0x49b41d95, 0xbdb2822c, 0xb8b756a4, 0x03457207, 0xaab9433a, 0xc5c0465a, 0xfe398ce3, 0x84bed922, 0xaa3e2f38, + 0x1f539c1b, 0x6e296012, 0x29d6a8dd, 0x27254bc4, 0x6304d447, 0xd790d52b, 0x66ae652f, 0xe715ae35, 0x71cec7e7, + 0xadd015b5, 0xb39b7f6f, 0xd44d54ef, 0x8f8f148d, 0x7ef2a5ef, 0x32ecc25f, 0xee28bcde, 0x0aae5ebe, 0xe2e46e49, + 0x70e09c78, 0x0d5fe1d7, 0x2cd1a1ca, 0x0d528ed1, 0xad82a3a2, 0x24cc7edd, 0x07e186a4, 0x216d7934, 0x045f2309, + 0xec96c63c, 0x02c6bad4, 0x2da57ade, 0x4bf2a486, 0x32a64c9b, 0x8310dc29, 0xd1150958, 0xf464d229, 0xe9160a5b, + 0x777503b6, 0xe4851dc2, 0x1aaf3e9b, 0x7556aa9f, 0xf85f9450, 0x5d502fd3, 0x8de92f8f, 0x77380f8f, 0xb3a162cb, + 0xa27f6659, 0xfb3e88f3, 0xeae6f6bd, 0xaaa362ed, 0x0ef52a52, 0xc5de17c8, 0x15225a97, 0xbebcc43b, 0xb32611a4, + 0x223f4b5a, 0xaf40dc1d, 0x0a6bce4a, 0x69691e6d, 0x96cee603, 0xa4555970, 0x07cfaec9, 0x341ca867, 0x27b7c9d3, + 0xa5f11318, 0xd1c02076, 0x39d2afe9, 0x50998722, 0x8bd4f3ed, 0xe113007f, 0x0d67ab3d, 0xda02c56e, 0xaedacc60, + 0x3fb6555f, 0xad22da2b, 0x6d45e8b7, 0x554757e4, 0xca01e053, 0xcf0f0981, 0x345c1139, 0x81d70aeb, 0x8ef0041b, + 0x2b167dd3, 0x2315456e, 0xe1c1bfab, 0xff2b14c8, 0xdc28b14f, 0xc40294b2, 0x7dfa5acf, 0x9d8b16c4, 0x237c16a7, + 0xec751b66, 0x560de873, 0xdd5aa868, 0xc6359b5d, 0xe7f70f5e, 0xb587a4c0, 0x5e0f1a9f, 0x350631e0, 0xe65e0efc, + 0x3b3c8c0b, 0x7df3a2dd, 0x36973075, 0x00d2bf3c, 0xad681915, 0xa059a2f8, 0x39560249, 0x028e5c37, 0xc252e182, + 0xdff11825, 0x3c03e1bf, 0x14913082, 0xe10f711f, 0x7837207d, 0x5efb4dd8, 0x0ce4b2d4, 0xe6e7eb47, 0x9bfe86c1, + 0x29629d59, 0xbb9cc941, 0x1d6ea624, 0x1f038cb0, 0x9f0b9319, 0x7a255475, 0x137113cf, 0xade30ba8, 0x66d8a648, + 0xa2941a0b, 0xcaa7be44, 0xb502cf64, 0x9871b06f, 0xc6205323, 0x5b660b81, 0x0afc4530, 0xed98b3db, 0x7d7efb82, + 0xc92fc36e, 0x06e749eb, 0x6f9dadaf, 0xf7f6015c, 0x8ef5d9e0, 0x5bb50b73, 0x00ec5e4a, 0xa4501df0, 0x53bfadea, + 0x837b3e61, 0xd23930c6, 0x38af6ba1, 0x2fadd9b8, 0x92ce629e, 0xd3d0411f, 0xa55daa35, 0xfbe5fa5a, 0xde537798, + 0x90bbc4d1, 0x15455334, 0xb34613b5, 0xe7d1d7e1, 0x9789d2f6, 0x979457a0, 0x5150ffeb, 0x9d538c60, 0x3d6870ec, + 0xd0739f95, 0x2864d941, 0xaa200aba, 0x1439435e, 0xeec5368c, 0x255f276e, 0x7e4190c6, 0xf3205b57, 0x8471aa40, + 0x7e19566e, 0xd0bb24c5, 0x9cd8d8f2, 0x76c61390, 0x5e1525ba, 0x560167b8, 0x7c55c7da, 0xcfcdb928, 0x2f1933e1, + 0x2118d750, 0x5652e250, 0xdfbb9d5f, 0x44014da6, 0x6a519ae7, 0x7fdec7d4, 0x0805c7de, 0x26277436, 0x2b73bda3, + 0xd9ae72b7, 0x584e87e1, 0x333ba5a3, 0x09093a0b, 0x425f40aa, 0x664dfc55, 0xd644db68, 0x90ed8650, 0x4aad84bc, + 0x426dbcf4, 0x7a960b01, 0x912d1c3e, 0xc4842be6, 0x58d6bc70, 0x77fc7192, 0x9de5ac01, 0x5dbc0b26, 0x817d640b, + 0x8d5c3e93, 0x379972f1, 0xbe0a2863, 0x17027e0f, 0xdbd33b5b, 0xa7f5f914, 0x20e31229, 0xd820a533, 0x1c6d5c8d, + 0x173b6eab, 0x808af512, 0x3168fb29, 0xd0cfa830, 0x7d1995f0, 0xdaa22d16, 0x20e1aba0, 0x643083c7, 0x1773053b, + 0x6211919a, 0x3544a617, 0xa57f733c, 0x7c599c26, 0x26bd50e3, 0xd1ae0fe8, 0x5f2b1d45, 0x020e9ad5, 0xbd3972bc, + 0x20423941, 0x99cb61e3, 0xf53d1ddd, 0xc88365c2, 0x62600f40, 0xa0cb1540, 0x3fdc185d, 0xe51c3e6e, 0x8ce4e0e1, + 0xf7982b6b, 0x59e1308d, 0x69397ebb, 0x1557bb8b, 0x9a40d473, 0xc34484af, 0x29feabb5, 0x95220a7e, 0x54da36f4, + 0xc369888a, 0x1e9fb52c, 0xfc3c4638, 0x76a685f7, 0xfd2403f0, 0xc30ebece, 0xb8f9e68f, 0xb5908772, 0xd3fc9464, + 0x76fe62fc, 0x69164eb4, 0x74e7416b, 0x88596c7a, 0x2ce6c55b, 0x364f7034, 0xf89f1491, 0x839de1c9, 0x9a924c97, + 0x78aa46a1, 0xef6475a8, 0xe044a142, 0xf3eab4f1, 0xedaa6fd6, 0x31c52615, 0x8f8da078, 0xb9e82075, 0x790c3f1d, + 0x636ec201, 0xdd111ae3, 0x5e5feb7d, 0x93bafae6, 0xfdba9bbd, 0x79622ee9, 0x9f0a2797, 0x39213089, 0x8e0570b7, + 0x1aa70d6f, 0xb384161c, 0x5d4901a8, 0x01f9590d, 0x806d3ec8, 0xf592b130, 0x43359ed1, 0xc7422085, 0xee883fbc, + 0xfb40adcb, 0x5b0e774c, 0x88a4e082, 0x229b348d, 0x937ea6d6, 0xed004ab1, 0xed1fcd19, 0x581dbbdb, 0xf0c3d73d, + 0xf85138ce, 0xecfe1057, 0xb9c7b8ba, 0xe8204b8a, 0x5e5fc19b, 0xe5fe7e00, 0xf101cf80, 0xdfa4190d, 0xc45f45fc, + 0x990796c5, 0x0dcc6545, 0x85ad3f4a, 0xc650c5e1, 0xb2b08635, 0x9ce89b16, 0xec55ce35, 0xfddd66d5, 0xb2d35a31, + 0x64af8fa3, 0x63ccf2df, 0x4cafad64, 0xe5d0f35f, 0x9c279b03, 0xce794844, 0x0cefd504, 0xf50e2305, 0xf1b43df6, + 0xa59262d7, 0x04a4ea2b, 0xe80ab670, 0xd5dd8f93, 0x32e808ed, 0x95dd3436, 0x7003ad52, 0xd0400fc6, 0xa296841b, + 0x679d6549, 0x5454986e, 0xb82210f7, 0x7fa33ea5, 0x74a75b7d, 0x0b479e4b, 0x6c19bc03, 0x983856a8, 0xe7daa414, + 0x8d619b27, 0x57c66e10, 0x8099cdff, 0xe093e728, 0xc93ef328, 0x3c8d9f44, 0xa63e1e62, 0x365ab3e0, 0x27105e8c, + 0xba1d4e97, 0x5c0be5ab, 0x16e4d824, 0xbab90427, 0x65868546, 0x5f38385a, 0xdc1efff5, 0x796c3c9c, 0xaa00b3a4, + 0xaeff5fbe, 0x707bba03, 0x0908882f, 0xcebdcafc, 0xc6a67821, 0x38fd901e, 0xbda45dd7, 0x027bb5a3, 0x649266d4, + 0x8d750488, 0x9633646e, 0x6bb1c70f, 0x5c008cbb, 0xfead8d07, 0xe2b879ba, 0x9a5b7305, 0x5bccdcab, 0xb7e6626d, + 0x436f557e, 0x32d818da, 0x24d35a3b, 0x5d4112fb, 0x23e57889, 0xcbe39e9f, 0x4a3190de, 0x7b687872, 0x3e159baf, + 0x2682af72, 0x142fed62, 0x526d20f3, 0x10a2b99d, 0x691c93eb, 0xed0b2d92, 0x1edd4739, 0x30420abc, 0x69dabd4d, + 0x65d4dd79, 0x887acf44, 0x8e071804, 0xec27d2f6, 0x5c813b05, 0xd91a8eaf, 0xf753f121, 0xd18ae156, 0x3ca9b6c3, + 0x984e9bd4, 0x4811ea2a, 0x60afdd36, 0x88f1d564, 0x5d79af52, 0xe36c3b74, 0xb322d908, 0x03508ed0, 0xe2a8584c, + 0xd5f550b7, 0x4536d399, 0x4ff24646, 0xc5d35b59, 0x9ac1ab3b, 0x974d5f2d, 0x83f22556, 0xf8645ac1, 0x8cdae595, + 0x9ff2423d, 0x92bf5e5b, 0x716ea085, 0x9892c49a, 0x90bcc99f, 0x98757665, 0x9de46e98, 0x520a0103, 0xba8ab8f7, + 0xff53b0e8, 0xe8140dd6, 0xaf276f95, 0xa3487737, 0xc556dd90, 0xb458ece0, 0xc0cccb90, 0x78acc557, 0xedbf258f, + 0xd4cd6dd2, 0xd423cabe, 0x49e9f980, 0xdd61f0dc, 0xcc6cd735, 0x053ca54c, 0xb5e398a8, 0xed06824f, 0x02c9cbae, + 0xc4a8c240, 0x408aca64, 0x61a3d8c8, 0xe2f2b0e2, 0x42647bc7, 0xae639bca, 0xd05c8fdb, 0xc877bc3f, 0x51bfd8b9, + 0x79d581d9, 0x929b55a2, 0xfb92f860, 0x8e027997, 0x9346c416, 0xbd12c785, 0x3536f97e, 0x6cdeed51, 0x2c492596, + 0x782715cc, 0x0e122a5b, 0x189cc97c, 0x2da2bd42, 0x9a6220b4, 0x1c0b634a, 0x916ae6ac, 0x14ff8ec3, 0x35ff31f4, + 0x0255705c, 0x223bb18c, 0x503e6bf2, 0x64d3ad70, 0xa66cc35d, 0xf1f8374f, 0x70addf58, 0x98bc06d0, 0x28fefeb1, + 0xa318c8f5, 0xd1c969e3, 0x081d9fef, 0x028eb14f, 0x55d6bdc8, 0x0cb70836, 0xc3af1092, 0x0a3c8983, 0x34a7a7fc, + 0x611062f6, 0x35bf2289, 0xe1df10e9, 0xea605d21, 0x29c0ca9e, 0xae90e5d5, 0x339611d3, 0x36fd293b, 0x69a3037c, + 0x642b2fd0, 0x41b3fad4, 0x20ea3cf5, 0x78c88072, 0x608d6232, 0x1fd7e5ac, 0xdbc68628, 0x4bac2f80, 0x25b68d39, + 0xd06c5935, 0xbb9fab89, 0x3385ce7a, 0x01b48473, 0xfb70a568, 0xe1b5cb8d, 0xb458c34d, 0x604002b5, 0x88eff0fc, + 0x88b6a87e, 0xba083764, 0xd4dc2cf5, 0xeb5a90a6, 0xd4ccdcf1, 0x9b43ab13, 0xac5f003d, 0x1f6703d8, 0xace5f76d, + 0x32f065fb, 0x16fa734b, 0xfd200e97, 0x26693296, 0xec3a48f2, 0x11894ffb, 0x6ba45f4a, 0x22c0daa5, 0x0a05f0c7, + 0xb6c0dcbe, 0x06bb7c6e, 0x513cda12, 0x3695cac7, 0x2548c272, 0x9eb5a99c, 0x7f14565c, 0xc59f1be3, 0xb060bf88, + 0x7cfd0f52, 0xb1127fcc, 0x821b0ac4, 0x01cf8b94, 0x27d6d254, 0x1733dc46, 0x2d56db77, 0x2b3b36f9, 0x59793634, + 0x8871f90a, 0xc0d59886, 0x3ad9ac0d, 0xf31e706b, 0x9c22b254, 0x57d74ad9, 0x9fc139e7, 0x9598a9f1, 0xc8d566bf, + 0x76aff9b1, 0xc59a4650, 0xa26d5492, 0x2da56e2a, 0xe0495fc7, 0x122e631d, 0xe27fa06b, 0xf219cc28, 0x10503f67, + 0x281e3666, 0x5387918f, 0x98f71c02, 0xe8fa9bdd, 0x427d2e08, 0xadaa2cd5, 0x09661f6b, 0x7a183665, 0x003f8dc4, + 0xb74fa6f5, 0x92d3d4ba, 0x7a494f5a, 0x3ad5683f, 0xe0d6d4e9, 0x45762b98, 0xfb5c13b5, 0x0e981ad0, 0xd2f5573a, + 0x3d847dc4, 0x4af1e4bf, 0x6bbcd7ed, 0x20d00228, 0x89f139fb, 0xb156a727, 0x49a64b25, 0x30722d58, 0x3be9e9ad, + 0x32da91c6, 0x97b8f7a1, 0x61ae787e, 0x7f977a09, 0x552fd314, 0x2367730d, 0xe0667ea0, 0xcf4d626c, 0xca4c2c40, + 0xa89437b1, 0x4e4e2d25, 0xbe1cece8, 0xc538df11, 0xf420741a, 0xe764bf59, 0x2599cd96, 0x65c7938d, 0xaf13ba96, + 0x6057d2d0, 0xd1d13309, 0x17c18ca7, 0xfe879d84, 0xd1026108, 0x069775fa, 0x99069fa4, 0x9afda342, 0xc02aea8a, + 0x8a2e3d60, 0x2a52e72e, 0xc35a7b4a, 0x2b3b8a15, 0x5a166585, 0x3a00c0ed, 0x0aed8324, 0x0ebf66f3, 0x359a92d3, + 0x98b54379, 0x73b6fbbf, 0xdd377d4e, 0xfcd44094, 0xb86adfe2, 0xc0394828, 0x01c139df, 0xa1ce1501, 0x81355ede, + 0x3652fb01, 0xd2462c69, 0xb20c6e0c, 0x7d006db2, 0x4121712b, 0x66a5f75e, 0xb300cc2b, 0x0183b3ca, 0xe93f757d, + 0x53f82023, 0x737f69fd, 0x7ec7f81a, 0x0b390730, 0x33115368, 0x533b2844, 0xb1ef1cfd, 0x74fce20d, 0x29299aa2, + 0x1adb79bf, 0xdcdeecd7, 0x4df80cd9, 0x79f4e3f9, 0x54dc4ae3, 0x34fd0220, 0xaee6a316, 0x2cd1aa1a, 0x27ad9072, + 0x7f19fae8, 0xe9efddfd, 0xcd7ca4ac, 0x6c24bad2, 0x11038db3, 0x6aa2ba46, 0xb176518d, 0xf850e08c, 0x3d1a105c, + 0x69097a92, 0x97b80f0a, 0x7dac085c, 0xba91857b, 0x637ff7eb, 0x3b39e439, 0xab1f9f46, 0x5b74e5f0, 0x7984b53f, + 0x5d0b334c, 0x4fc234b4, 0x8d18567d, 0xe6626cd1, 0x54ba4f80, 0x0208cfb5, 0xfad9f886, 0x75dc05e4, 0x101c8237, + 0xc7819dd0, 0xc279f009, 0xb9d655b5, 0xbe0ddf49, 0xf1964771, 0xe9ab9240, 0xfb77ace7, 0xc4d3aef4, 0x0ecf27d7, + 0x42637e55, 0xace4ea12, 0xea2efee9, 0x8d614c25, 0xde6ab6e4, 0xa6d8569f, 0xbe6c9dd8, 0xcf11ee80, 0xffc9939f, + 0xf6ab857d, 0xd8348f25, 0x33c90e92, 0xfc6f29de, 0xcddce697, 0x96e60dae, 0xc7ae44af, 0x6051ce11, 0x4710ff99, + 0x10ebafdf, 0x972a7faa, 0x4b4b89a9, 0x39835947, 0xdd070805, 0xf6bdb665, 0xc74bb634, 0x6b58f997, 0x7b2d83a0, + 0x592c7bfb, 0x4d0e1d7c, 0xe8e59bec, 0x9b48cc6d, 0x73c346a0, 0x3a6387d1, 0x237f8306, 0xc65483d3, 0x5ae5b8c6, + 0xfb6ebf6f, 0x277d4d91, 0x5ef7753b, 0x40578baf, 0xad450f02, 0x09574e73, 0x1b7b08eb, 0xa6ed6091, 0x83d22dee, + 0x8efe1ff1, 0xf033497a, 0x7e03ea51, 0x4d6d845d, 0x8de8e100, 0x75a91e1f, 0x49e8d159, 0x640af563, 0x2abd90b5, + 0xe6adf359, 0x6f36938b, 0x5f546365, 0xfa7fa673, 0x19fb64ff, 0x645159ec, 0x014684eb, 0xecd242f8, 0x579b9d7c, + 0x6cbbad8d, 0xdbceb26f, 0x78dfa539, 0x4e819426, 0xb23d7609, 0xfff64a2c, 0x3cd66ea5, 0xa9b688a2, 0x971d98b0, + 0xbbc9c5ad, 0x224010da, 0xaf63ae58, 0x1e1ff5ed, 0x2d13784e, 0x67d32c84, 0xdfc77df8, 0xf20ed363, 0xaad75340, + 0x6d4944f1, 0x6005b1f4, 0xea527631, 0xaf6010e1, 0x29a28a32, 0x7d338b84, 0x334b479f, 0x82aa1432, 0x04e3205a, + 0xc300a30e, 0x82165bd5, 0x785a66a9, 0x6829d0aa, 0x02a0d871, 0x27817233, 0x9ae5c7f1, 0x6cd8c541, 0x5eedb54c, + 0xedf70ed5, 0x0a09a4e2, 0x540e815d, 0x6444af93, 0x648f898f, 0x6b0c0c44, 0x52d76fee, 0x5433587c, 0xf27de132, + 0xe3c3a8c5, 0x4262a02b, 0xe66d30a9, 0xaca73ef1, 0xbf13f5d7, 0xb87b2c21, 0x9a11c84b, 0xea3cbe99, 0x24cd55a0, + 0x71bf91b0, 0x0d6c92af, 0xcfe197f1, 0x76045b3a, 0xe7d089a3, 0x9b466f49, 0x1766ad7b, 0xd5337905, 0x6a14864b, + 0xc8ee407f, 0x9ab850e2, 0xee1d82b9, 0x1b133a0a, 0xd061da19, 0x38fa88b1, 0x9e86b62f, 0xbf01a3b7, 0x951c1683, + 0xcd8861f5, 0x4839c79a, 0x85912c8b, 0x26109ce7, 0x0e5cac5c, 0x6a7de3c7, 0x60188ac1, 0xed88648a, 0x4ebe28b6, + 0xf120ed42, 0x718208f3, 0xcfb02969, 0x02748f47, 0xf56ea56d, 0x0f9ab7de, 0xcd9e2121, 0xa6eec0bd, 0x6356080d, + 0x98fd3714, 0x187d48db, 0x35859ca5, 0x944285cb, 0xe8daaf55, 0x5c24c18f, 0x5898f7d1, 0xc80f335e, 0x4a0394e9, + 0xadd3dc30, 0xb336b5b5, 0x225b0410, 0xfe36f181, 0xf3a5335c, 0x11269dbc, 0x932e3187, 0xe968bbb8, 0x8fcd1a08, + 0x62bbfa7f, 0x785faf41, 0xf5f890df, 0x184ca9de, 0xee37507e, 0x070a459e, 0xe005726d, 0x5e04e56c, 0x35d0a7ac, + 0x5d9b226d, 0x9f76574f, 0x09a298e6, 0xa838ca94, 0xf0a68fe0, 0x7d915dcc, 0x098cb057, 0xbbb3b0b6, 0x220812eb, + 0x2756cee8, 0x85d22f0d, 0xe4d1bfaa, 0x92eece30, 0xdb340f3a, 0x7f269c58, 0xbc1f7cf0, 0x2aac98a6, 0x28a57579, + 0x82a1b908, 0x33007b99, 0x7794b10f, 0x522e8fcc, 0xaa4c0c6e, 0xb7904f5d, 0x4a27725e, 0xe6ddd868, 0x96b8d2ed, + 0xdabdce91, 0xbc9a8133, 0x75dc07fb, 0x9dcc8f1b, 0x9012994d, 0xcfc87b03, 0x8f0c34dd, 0x7d021188, 0xa0b71369, + 0x341615f1, 0x9876ccb9, 0x982a363b, 0x7b9eafb0, 0x98aee476, 0xbfc39d6d, 0x071983f4, 0x714e4d7e, 0xb4c27c58, + 0xe8a61688, 0x571e027f, 0xceb51484, 0x24e7157e, 0x0cba20c3, 0x0c753a07, 0xd21403b5, 0x17cf4714, 0xa564bf27, + 0x9e6f2a39, 0x81afa367, 0x07ec85b8, 0x6839c450, 0x904d06cb, 0x57981ece, 0xee3fde64, 0xa27f2d9b, 0xdeffe50d, + 0x029cc486, 0x6a658194, 0xca01e05f, 0x41fe5af3, 0xa81d3489, 0x6c51bebd, 0xea275ca6, 0x775e0842, 0x485e6651, + 0xf9e1d9eb, 0x00f5e991, 0x371f18cd, 0x71a3ddb6, 0xac78e1ba, 0x22f41bb6, 0x2312824d, 0x5b5dbdd6, 0x1716f40e, + 0x20f6331f, 0xa1052674, 0x45984804, 0x6e479c9e, 0x5268f9fb, 0x461c3789, 0xd1207683, 0x0aed9fe8, 0x8454829f, + 0xb2dc5ede, 0x3f7f4e12, 0x4ea0bcca, 0x6b673092, 0x4e0d20d5, 0x97854045, 0xe27f7e70, 0xe0e80d0e, 0x3c21bca4, + 0x9bfc7628, 0x1ec075a0, 0xe9d68654, 0xc7364375, 0x0fb049fa, 0x82d45c88, 0xc604a1bd, 0x150a7372, 0xb9f87eeb, + 0x0573f5d7, 0x39abd178, 0x5f2112d1, 0x85657044, 0xdbbeb7cc, 0xd6480c14, 0x22943a3d, 0xd71a62c5, 0x4196cca9, + 0x885127b9, 0xe077f2da, 0x84782e76, 0x017e465e, 0x965df9bb, 0x1e7b5d4f, 0x1058aee8, 0x19939a23, 0x1020c7b7, + 0x00bc6d9b, 0xbb9071d7, 0xdd20d581, 0x3a11db24, 0x35fa0a82, 0xe55e5a77, 0x7ad949db, 0xfe52e9f7, 0x7eab1349, + 0x4bc3858a, 0x0e47a6f4, 0x42d2bd28, 0x1f8696a8, 0x928f4449, 0x317989ee, 0x41322087, 0x70796cfd, 0x6e9f5262, + 0xbd4a162e, 0xb3fbcfb5, 0xb76f516d, 0xc36a7572, 0x838b5a90, 0xbf458402, 0x4f6090c4, 0xc5ed8f15, 0xc33ffe3c, + 0xbc982f93, 0xd26a1897, 0x53d81ea2, 0xd846c263, 0xd5c15c6a, 0x3d03781a, 0x273f5084, 0xa0f279fb, 0xaff98e2e, + 0x85c422a9, 0x312eacd8, 0xcc1ff418, 0xede3fa04, 0x0e3b3a8d, 0x2a6c75e2, 0x57247fc5, 0x6c7523f5, 0x0aeaadeb, + 0x66e7f4f7, 0x1a094730, 0x12bc570f, 0xb2330a1a, 0xa16583d1, 0xb8453717, 0xe40490f1, 0x08da7cfe, 0x3b065026, + 0x10b35bab, 0xfa36c213, 0xebb59f15, 0xd9b158e6, 0xe8a8b0fd, 0xc00fb56b, 0xe20ab53a, 0xda21c5aa, 0x75925ff3, + 0x024c0544, 0xdc3b4d65, 0x592d1469, 0xd885ab91, 0x03179996, 0xd666f46f, 0xe8f52ce0, 0xcfa9a10c, 0xe802713d, + 0x99039a5f, 0xfdab06da, 0x8283cf08, 0x41db7bcb, 0xa6e8c0d1, 0x50e98827, 0x37526936, 0x146ddedd, 0xaadab003, + 0x00bd0f8b, 0xaae3f76c, 0xee559231, 0x103319ed, 0xf756dc44, 0xdc477774, 0x7c499566, 0x7b453e15, 0xb85895a6, + 0x56ad402c, 0x953d294f, 0x0dc8384a, 0x0f7327db, 0xbdfacb91, 0xb0a04fbc, 0x8f2a68de, 0x6b92ec77, 0x9fed5bad, + 0x2e581931, 0x85479e82, 0xecdb2c8d, 0xae3e41d7, 0xfff4f3ad, 0x2dc6b209, 0xaea7aa48, 0xf83f681e, 0xf33a6bb8, + 0xe14ee4a9, 0x4cae8ac5, 0x4fe2ecb5, 0x88ffd11c, 0x9db13ad8, 0x523dc462, 0xf48b7c7a, 0xbcb42464, 0xdbd36261, + 0xf62e0f80, 0xa9cecc08, 0x573cbfed, 0xde8d0737, 0xa3a73efa, 0x39a433c5, 0x6e301018, 0xc3c5fbfd, 0x1287f735, + 0x202ccfd9, 0x8c0f3130, 0xecb081c7, 0x677979e9, 0x65db401e, 0x4e0dc038, 0x5d827c3f, 0x9a261d64, 0xa3b0ae9a, + 0x44dcc477, 0x4ea17467, 0x2a07982a, 0xb927267a, 0x202135ba, 0xd463188d, 0x10ccc44f, 0xc40e44ee, 0x19a35ade, + 0x1f1d28de, 0xf73146bb, 0xc7c08e4b, 0xc675dacf, 0x5fb4236f, 0x223e6792, 0xff8b8535, 0x4312cbc3, 0xea1f85d2, + 0x160c3f25, 0x3840e519, 0x61ffcc13, 0x2a296e1a, 0xe8b100aa, 0xb13d16ed, 0xc09d8f04, 0x4e7f5f15, 0x2a89ad48, + 0x7dc879f3, 0x8b27ed0d, 0x55188e7d, 0xb563127a, 0xcae9a5ad, 0x4c14c8ac, 0x784b8ab9, 0xfba6de05, 0xade4b7b9, + 0x35349715, 0x19c3d556, 0x48cde0ad, 0x5de0a923, 0xebfb02f5, 0xe6ac50c2, 0x595f3156, 0x9caab8d0, 0xfa7916b5, + 0x80547f9d, 0x25c3ccdc, 0xa9f037d2, 0xb3c666e1, 0x055640a7, 0x6f7cd046, 0x036f4a86, 0x4ef4e397, 0x17d2abcf, + 0xfe666ec6, 0x49e0e193, 0xab249c17, 0x20e51605, 0xba0d6b18, 0xf4f5dfed, 0x99f19864, 0x9eebe72a, 0xc89c5e9f, + 0xc28ea5f1, 0x67eeda83, 0x71a92aa8, 0xa59de2f6, 0xcf0b5e04, 0xeadd7698, 0xe9c54c68, 0x4d0e3a94, 0xeed2bd59, + 0x73312833, 0x25d59a59, 0x7f4ba886, 0x291a8013, 0x6b84392a, 0x9713a0d2, 0x39922604, 0x4c77d96d, 0x7d7b5711, + 0xf5171ea6, 0x89e70fc1, 0x55f97b32, 0x00a210a1, 0x17ad5fa4, 0x303ae39e, 0x72e5f5a7, 0x50adfb9c, 0xd6f73d4a, + 0x26211f81, 0x580884c5, 0xbf22b941, 0xe93072cf, 0x30f97030, 0x334de58f, 0xf9d6f224, 0x89cd9b08, 0x147db083, + 0xa358c447, 0x4236dc56, 0x759cf335, 0xb8e5a78e, 0x3e5680a4, 0x626b5a81, 0xcbdae707, 0xdafb5a86, 0x6984d045, + 0xb76fd25e, 0x7a0b217d, 0xa4c58d3b, 0x3c11c85a, 0xcbef267e, 0x874be451, 0x0d9ddcf3, 0x5d25805c, 0xfe2e5ad6, + 0xd91c80c8, 0x0875c177, 0x9c888618, 0x0680f259, 0x9d356e2d, 0xc98678d0, 0x82a62c6b, 0x7d8ad70c, 0xf48ab402, + 0xae558623, 0x29ad8f5e, 0x6f908afc, 0x6532ed97, 0xfb36f624, 0xa456879a, 0xf5bc0659, 0xbd6f579d, 0x79a74f5a, + 0xfff1e1ea, 0xdb0b4a7e, 0xe3672e36, 0x04cc9e22, 0x8003c821, 0x529bc4ea, 0xf552bca2, 0x22e26126, 0x196e9fcb, + 0x53609649, 0x13ba489b, 0x4ceb380e, 0x5591a2d1, 0x4a48b040, 0xfd771e05, 0x1e514ba6, 0xa06e798d, 0x187844aa, + 0x8ae37f1f, 0x6692e87a, 0x0ad7406a, 0xd1d5f728, 0x2743da43, 0xd2362f46, 0x906fa616, 0xbf62169f, 0x53f8aacf, + 0x817d3516, 0xab7ee201, 0xb729857b, 0x7c8952ba, 0x65fedee5, 0x58f9f888, 0x81bc1c6f, 0x6b20587e, 0xc470cdd7, + 0x2f699542, 0xa7ae4bde, 0xed521841, 0xba4f22d7, 0x1044ae93, 0xadf0c8f2, 0xcf368281, 0x5013cba3, 0x79c15bd3, + 0x9736691c, 0x89735b0d, 0x333c232c, 0xa713bad1, 0x845a5135, 0x138dd734, 0x0a9eb8ef, 0x894a1935, 0x8ae4f6cc, + 0x0c3bcbe6, 0xfefe5ae6, 0xb2c42fa7, 0x79d311de, 0x6edb300c, 0x83d37c70, 0xd11ba873, 0x70510501, 0x78bc23f2, + 0x173ae25a, 0x7e107a1e, 0x51744bf6, 0x15ef1fd8, 0xa958e357, 0x5709be14, 0x853dbc95, 0xdc2a8a51, 0xf06d45ed, + 0x01f1f452, 0xe5915e63, 0x15b19594, 0xff3be3da, 0x47696aa3, 0xe1be8592, 0x0526be25, 0x52dab0b8, 0xfe95b35f, + 0x2f61f474, 0x76afb747, 0x6556b314, 0x92ea6b5e, 0xb7f2687e, 0x28b774e3, 0xfd6b0bbc, 0x2a77361b, 0xb9338dfd, + 0xe907edc6, 0x57e5d7c9, 0xd5b6c43a, 0x7748b8ae, 0xab77774b, 0xb5d49000, 0xb571b464, 0x95ec0846, 0x86e7485b, + 0x08eb4dd8, 0xdcd0d7f6, 0x302a2ff9, 0x39d8203d, 0xf50d625b, 0xfc669184, 0xbda91666, 0xdd77ab1d, 0xc9696bff, + 0x69dd4623, 0x0a059c0d, 0x670e70c7, 0xe19b167e, 0xd7700dc3, 0xab0105e4, 0xf5799642, 0x9365f833, 0x9378004b, + 0x17a8be9b, 0xaa13db81, 0x0279971d, 0x6a2a2c5f, 0x3099029f, 0xd65bfdc4, 0x8341a6e2, 0xb0555ac3, 0x7fff16ae, + 0xaa3594f9, 0xa96c70bb, 0xfdd92b16, 0x9a6cfdfa, 0x0280ffbb, 0x848e5ee4, 0x661391e5, 0xc56a3d39, 0x98400e18, + 0x8bfbfa5a, 0x64829eaa, 0x1151979a, 0x5acf90c6, 0x8dddab99, 0xdb197ad6, 0x37eee2ee, 0xf111b148, 0x212e7e09, + 0x0838db2e, 0xc11a1456, 0xc8e43136, 0x1d5f26da, 0x8c298fb2, 0x79c64990, 0xd08d4645, 0xded28893, 0xc0e8d6a5, + 0x67879c54, 0xf34f34bb, 0xaafe9542, 0xd68fc63e, 0x9a3cafd5, 0xcec27e59, 0x0599a24e, 0xbf7e28ac, 0x4e06dbb1, + 0x7448175f, 0x31193124, 0xa597016c, 0xe63a0b28, 0xa5382a4b, 0xb69949ba, 0x86acd0c6, 0xfa9708d5, 0x60682cf1, + 0x80343bff, 0x0fe5251f, 0x88d68cd6, 0xe2dc8181, 0x66484d9e, 0x76738eb1, 0x244af777, 0xcad2ef0d, 0xb581b1f3, + 0xec6f0727, 0x2d74ebd8, 0x39d9863a, 0xf56278ff, 0xbfb0aee7, 0x0676ca92, 0xb77d0d9e, 0xd68c869e, 0x2544f7b9, + 0xb6efb519, 0xf807253e, 0xf9bbd086, 0xe65162b3, 0xd4efbb46, 0x95e4235a, 0x66fb013d, 0xc3503400, 0xfaaf023a, + 0xa6759dc2, 0xfed2b180, 0xec3228da, 0x6ec71f86, 0x65bc644e, 0xadfdeeeb, 0xbcf4d886, 0x69d83eb9, 0x66137722, + 0xa90e5a30, 0xdb4b1578, 0x36800e5d, 0x8caaae89, 0xb645f47c, 0xe16d692b, 0x21aa216f, 0xad818fe4, 0x1c50a0ca, + 0x4a9fa45a, 0x4e12828b, 0x246c912b, 0xcf3d21b2, 0x1726627f, 0x37b73237, 0x710b0ee7, 0xd4914dea, 0xa3d2d1e4, + 0x073555af, 0x0e8e9d39, 0x3392c84c, 0x64df1ed3, 0xa1887ad4, 0x3f0e8775, 0x6eedd43d, 0x72395146, 0xea199dfc, + 0xba2cc28e, 0x5e4de6c4, 0x5edce935, 0xdd7d2f6c, 0xfcd40c5a, 0x86608db6, 0xeb0737f4, 0xb8243ec2, 0xf22c7f57, + 0x31d156c0, 0xfc143494, 0xe57736dd, 0xfb8795a1, 0x4d1e2292, 0x4a04d89a, 0x8dc0cbaf, 0x6c9c809f, 0xeb89470e, + 0x6b39e42d, 0x19934e4b, 0xf21e1b45, 0x96fb8133, 0xd55a1492, 0x9b43a93e, 0xfa61f88b, 0xca33902e, 0xf6702e72, + 0x9399fce8, 0x9a6df54e, 0x19c7bf63, 0xe337a3bd, 0xe31470b0, 0xaf497f8e, 0xeaecd17d, 0x84df0829, 0x1cb71853, + 0x096e7f75, 0x5123103d, 0xa619b2c7, 0xbe4d96fe, 0xf75117fd, 0x01ee6c17, 0x7b7586ae, 0xfcabdf45, 0xccad9073, + 0x09e00d0c, 0x5c262108, 0x9865edcc, 0x5297efc3, 0x471365e3, 0xddecf4f4, 0xd697af2b, 0x5a7c3e8a, 0xfb0ae635, + 0xfb25cbe1, 0x67c08390, 0xfe4b5c36, 0xe326e197, 0x9b24874d, 0xb6b74bb8, 0xd93ee25a, 0x213d6d69, 0x28a36e4f, + 0x1439e58e, 0xb4a1abc5, 0x6454562f, 0x9737d1d6, 0xb4060d3b, 0x2ede95e5, 0x7081851a, 0x7dae60bc, 0x47f49d42, + 0x335b5fff, 0x1637685c, 0xc92145c9, 0x316440d5, 0xbf2f96d3, 0xf1fdc572, 0x2345136b, 0x883f8e63, 0x1547930d, + 0xdf02e44c, 0xd817df77, 0xf99559d6, 0x2b847475, 0x86d3562f, 0xc369540d, 0x9518c2ea, 0xc81e541b, 0x2d2f54a2, + 0xb1a2c018, 0x08fa50da, 0x25889aae, 0xfc8ade27, 0x509d7a5d, 0x990e2e29, 0x82ad3691, 0x967c6422, 0x5c4628d2, + 0x4aaaea2a, 0xf8a56690, 0x25c527f9, 0x86d1c3ed, 0x25c35c96, 0x1c95fb8b, 0x0089d225, 0x61c2c10b, 0x28dfe859, + 0x270885d0, 0xd80a034e, 0x48102cbd, 0xee6b7a74, 0xbec33111, 0xfd91a8cb, 0xbb6f228e, 0x9dac422a, 0xd5534dd0, + 0xa89ed079, 0xbe2f3498, 0x75527a01, 0x2684f3af, 0xc3c49e09, 0x0002a199, 0x2a240ebc, 0x005433d2, 0x07d2b355, + 0xccd65e04, 0xafe699a1, 0x8ef3d47a, 0xb3bdc6be, 0x370f1ffd, 0xfd585960, 0xabcf0d89, 0xbcad2671, 0xcf903980, + 0xd3e01e1b, 0xde02fd8f, 0xa88afb4d, 0x19fdf54a, 0x2789defc, 0x5ea6d120, 0x8dc53c3b, 0x86443893, 0xb3464d7c, + 0x4297b4dd, 0xf16e5afa, 0x8088cc75, 0xeac4f4d9, 0x70b079dc, 0x658a37f9, 0xf0e38106, 0x12c940e8, 0x7b1943ea, + 0x0f99486d, 0x75f4c251, 0x1b0fe2e3, 0x6467f9cf, 0xdd1e3323, 0x63112fed, 0x290d4d63, 0x649c3376, 0xf2491232, + 0x45fd5dce, 0xc8e39336, 0x29857eea, 0x10333722, 0x551acf6c, 0x56370625, 0xebe40cb9, 0x6a4a3abf, 0x9738afea, + 0x00094354, 0x9485814e, 0xbf382894, 0x7370501b, 0x35f01996, 0x6fa56a5a, 0x723dbc00, 0xf04e044f, 0xd7d9e080, + 0xc058acca, 0x8335633a, 0xedd3c5de, 0xc8e7b97a, 0x605637f0, 0x30af99ec, 0x1af2df7d, 0x1396a1c8, 0x0835c11a, + 0xeb5efa30, 0xc9b10c4f, 0xb5ffb345, 0xf61a26b5, 0xf9957ee7, 0x8e87382f, 0xc7facb20, 0x4eea1e92, 0x1af5afba, + 0xa6f2df00, 0xefdd2214, 0x7d67eeb8, 0x73f93cc5, 0xaa2ee54c, 0x1b1508c2, 0x40090e6b, 0xeedfdd97, 0xc86d83a6, + 0xcf9736ef, 0x6e4f4f91, 0x7bef7f44, 0xaac38480, 0x70aff283, 0xd87f86f1, 0x98bf42c1, 0x5b021b34, 0x4947121b, + 0xd0d21d92, 0x36d11212, 0x59a001ef, 0x2eaef33b, 0xd07ed790, 0xcbafe3b3, 0xf0608e05, 0x3bfe8661, 0xc57f392c, + 0x5703acf4, 0xf8f3df98, 0xf129dcae, 0x2119d1bf, 0x1aa82738, 0xe0d7a3fb, 0x35affe20, 0xb196944b, 0x914722d4, + 0xf3219709, 0xab39e416, 0x8138a52a, 0x191306de, 0xf09044b6, 0xa939e664, 0x82ad176e, 0xa978897d, 0x87b57927, + 0x3dae9a52, 0x1e041e09, 0x341bcd15, 0x20e8ce0a, 0x5a7e7de3, 0x7a7f90db, 0xa4278565, 0xf0f688f1, 0x50cffd3d, + 0xf70a39dc, 0x972670d4, 0xc4867676, 0xef69814c, 0x2db6395a, 0x4334c37f, 0xa8bac188, 0xdd46c66e, 0x8c22d461, + 0xd3b65d0c, 0x35db8403, 0x415c67f1, 0x331b2d51, 0x0bea79a9, 0x6fd142b0, 0x54ef27c7, 0x6cd9f378, 0xfaab976c, + 0x704df0fb, 0xe60777ef, 0x13e76e72, 0xca55e94a, 0xe61f52f0, 0x151bae61, 0x99e23304, 0x58ced973, 0x9ae2b17b, + 0x280d7e5d, 0xec9794dc, 0x31581e5f, 0x47a5ebfa, 0xb8e54f18, 0x8ccce6e5, 0xe3d500b5, 0x78ff2804, 0x1b5bfc52, + 0xc6175164, 0xa150d0b1, 0x1ca13e10, 0xcc678766, 0x684bba6e, 0x85cb6d01, 0x92057f98, 0x913ae002, 0xf6ac47a1, + 0x3d26e0ea, 0xa9d5a585, 0x578e0627, 0x2f79ced6, 0x90f64345, 0x9c77a64b, 0x55247e1c, 0xe59f04c9, 0x555dbadf, + 0x360b6ea6, 0x1ecbc4d9, 0x1db81cc2, 0xca4ec579, 0xe80c0106, 0xcc544da4, 0x5b7dd996, 0x265d88b4, 0xc43ee372, + 0xff9556c3, 0xf2f228cc, 0xcd2e3e15, 0xd9041015, 0x95cfa61a, 0xb1300ee8, 0xf80244d1, 0xcc5cc84b, 0x0acd412c, + 0x50f76f61, 0x0cf6392c, 0x76dc5e96, 0xe4d85380, 0x8da668a4, 0x13a0b128, 0x8acb99ae, 0x4dc1bbff, 0xae44ac82, + 0xeac816a9, 0xd3fa406b, 0x0ce0294c, 0xed286775, 0x2df009f0, 0xf4073f80, 0x3164a868, 0x3e19e7f8, 0x23904967, + 0xa588f0cf, 0x6c09cc07, 0xbdd7edc6, 0x93d13e2c, 0x78f43e38, 0x0a569a03, 0xbbb4258d, 0xbc3346c7, 0xba8f6b65, + 0x02503c78, 0xa1ea0b6c, 0xda719913, 0xb0368f0d, 0x6ad0a76c, 0x2b4c7348, 0x8a0d76c6, 0x95e97c65, 0x75766701, + 0x92e7d23b, 0xd53fa1d6, 0xf16854bb, 0x54d79fda, 0x1127a80e, 0x8015ea78, 0x61acd0df, 0x41ecad0b, 0xaad7ad84, + 0x1e2e4dec, 0xc6192662, 0xb9963fc9, 0x27015067, 0x909399f8, 0x059ca9b0, 0x3a09f689, 0xbd7190dd, 0x99e0d16d, + 0xb89119dd, 0xe456775b, 0x7db37738, 0xf2aa72fc, 0x43c37d14, 0x7c3a0e06, 0xb5676d37, 0xd4d95f16, 0x2e8d07c4, + 0xad72864b, 0x70f098bc, 0xa5c37543, 0xb43c4288, 0x4d73ba82, 0xf00985bc, 0x2b2cb60d, 0xf61e4e69, 0x9eac12e9, + 0xea927279, 0xaa136c84, 0x3af0ae7a, 0x3b5739ee, 0x21d73107, 0xc28e603f, 0x0c1f7d21, 0xb4379b83, 0x8a1081c5, + 0xa6204fdd, 0xb04f787e, 0xbab08657, 0x72a1cc3e, 0x2c6eb7d1, 0xf8d37cac, 0x842a13bf, 0x36ca3610, 0xbf150fc8, + 0x86322335, 0x0541701a, 0x5f33c710, 0xe4cc7002, 0x53025b48, 0x315f817d, 0x13433349, 0xbb2fe355, 0xc13b64a8, + 0x7699e23b, 0x9bf38246, 0xbda069b5, 0x2a2f6169, 0xe2064f5c, 0x3273d617, 0x31946c53, 0x72bb8161, 0x0b78d0fc, + 0xacca8f5a, 0xab245665, 0xf41e9b7e, 0xb43f2d36, 0xc7255ef7, 0xe2ddc257, 0x822a2c41, 0x55817b7a, 0xaaa30538, + 0x3bba5366, 0x89cb49e3, 0xbf13a501, 0x1a034142, 0x821457c2, 0xb68836a6, 0xfbe94d16, 0x11146d39, 0xc08e6513, + 0xac933214, 0xd7a6a265, 0x515699a7, 0x7bf1d02a, 0x480f9bea, 0x31da1de4, 0xbc6dfb0d, 0xf0c53e76, 0x28a9409e, + 0x17784fa6, 0x003415fb, 0x6ee2a027, 0x35e2c7fb, 0xf0a24f5c, 0x7b7508a7, 0x02526abe, 0x5c64b2b3, 0xe790e8b2, + 0xb1ddf727, 0x56cf473c, 0x7ad8bfc3, 0xf0cf8f7b, 0x9437d25b, 0xdac055f9, 0xc427f3f4, 0x5683564f, 0xde98d44b, + 0xac798ca0, 0x0d257377, 0xf8e63e2b, 0xe69e9678, 0x85ac3f50, 0xcf3706b6, 0x90f987d7, 0x83f4bec2, 0x8b96e334, + 0xc323551f, 0x5a12d3d3, 0x9fd2235e, 0x212fcff2, 0xfb202a02, 0xec091fbc, 0x65908735, 0x1d7aa6e0, 0xbe5c75b2, + 0x36128031, 0x6d31d8fd, 0x2da15ce6, 0xd972d37e, 0x8b8fde16, 0x81541775, 0xac68ec7a, 0x2ded5353, 0xdcb858ec, + 0x0ef92594, 0x39288542, 0xf5503469, 0xf40319b3, 0xee9187a5, 0xc64a2b5b, 0x368fc4e5, 0x08d33f6b, 0x09ab85af, + 0x7505a063, 0x8193371d, 0x925d055e, 0x712d4f40, 0xe0abf8b5, 0x68602e64, 0x890866dd, 0x57ca5b26, 0x6d682e2e, + 0xf39c6f1b, 0x7a5eacde, 0xbf0c304c, 0xb6f8e975, 0x9b6f47be, 0x496026f1, 0x8ad6915f, 0x1275018e, 0xfb503c4f, + 0x615f317e, 0x763ca870, 0x0e78a843, 0x973bfb8f, 0x448cf5bc, 0x3aa1da5f, 0x6b04ea76, 0x950d3d41, 0x5813c1e5, + 0x01fed574, 0x74bdc327, 0x2bbba545, 0x996311c0, 0xdd03bb1e, 0x98ae47e6, 0x268739ca, 0xb0693ed4, 0x7a4da479, + 0xaced2edd, 0xf186f51c, 0x602e3df8, 0x08057732, 0x68b5bae2, 0x34e7d20c, 0x089d540f, 0x7e55c83f, 0x90c4a212, + 0xaf1b5d40, 0x84dc48c2, 0x3953553d, 0x358bd945, 0x3fc1b08b, 0xeb010569, 0xa498437f, 0xf4a8aa53, 0x7ab92adb, + 0x5cf55723, 0xfad4990c, 0xa1cfca42, 0xfc64fce4, 0x844330df, 0x2e6857ae, 0x91b5f8d6, 0x742a38ca, 0x9526fd71, + 0x7bfc2d56, 0xc206e0b3, 0xbdcb1632, 0xff96e36f, 0x69581b6c, 0x93006bbe, 0xba5bc13a, 0x3ea2b218, 0x18df2356, + 0x3c4f4ddc, 0x935b702c, 0x93aba8d0, 0x4edd597b, 0x8f9aaed2, 0xca6ecc0f, 0x9d396456, 0xbbfe6007, 0x0bb10daa, + 0x488bef93, 0x44c6f3a6, 0x29b92e42, 0xf8af1cf7, 0xb4bf267b, 0x61ba9793, 0x62385b5f, 0x069b3f1b, 0xa2de9b9f, + 0x8bf7ca1e, 0x013d8765, 0xac683932, 0x2372312e, 0xe704a732, 0x0576fea6, 0x63fba9be, 0x0779f49c, 0x8290d8aa, + 0xa52b2dc6, 0xbc229d42, 0xecaba7f4, 0x806c8a01, 0x311782c4, 0x1248288b, 0xe3faa15e, 0xde6ad331, 0xe3c552e9, + 0x17ff38b4, 0xea02f952, 0x1e6f009e, 0x8731825b, 0xabb75e50, 0x8a46d707, 0x83c83cc3, 0x21d3bcce, 0xe4b006fd, + 0xb557b4fb, 0x27d84501, 0x83ae3db1, 0x856193c5, 0xc95db761, 0xa6c6dc16, 0x43c019e1, 0x0ae50518, 0x4d46c891, + 0x5d779e43, 0x8641941d, 0x5bab28fd, 0x73610319, 0xc985d95f, 0x200f361f, 0xbd43aa71, 0x107d59bb, 0x6ec9c4f6, + 0x5745f262, 0xcf6c1034, 0xc1e0256c, 0x26808c6d, 0xdacf2d00, 0xee75af1f, 0xc40c66d3, 0x1e3da918, 0xf984d154, + 0x54014d39, 0x154b6aa0, 0x057d5061, 0xfbff5ff1, 0x6570c97a, 0xd5b078f9, 0x75597177, 0xcf94b48e, 0x49b800b9, + 0xdf04ce6a, 0xee7f3b4d, 0x78cfa4da, 0x2a2e013a, 0xa0348e99, 0xee5411a9, 0x8e9440cf, 0xfc17c533, 0x84ce8a09, + 0x315ab64e, 0x715b505d, 0x6e7430a0, 0x0157430c, 0xee7838e2, 0xade4bedb, 0xdf3c2ba3, 0x1ea41e2c, 0x596a57e3, + 0xfb5be2c6, 0xd73d75f8, 0x409c98cd, 0xb22b9fc6, 0xa57dccaa, 0xc2782fdf, 0x3c7fc0aa, 0x1a5d8d10, 0xc321447a, + 0xe14b0004, 0x7bbaaa04, 0xa1968db7, 0xf042abb3, 0x42a88f8b, 0x0e91984d, 0x2382a93a, 0xd21af120, 0x8604f13f, + 0xa5b107fd, 0xe7097257, 0x494ecf10, 0xe0660a4e, 0x7c605cb7, 0x3f6ad235, 0xfc1a380d, 0x63c15c00, 0x58f565fb, + 0x7dee1059, 0xbc5c6557, 0x75966461, 0x13a48481, 0xe186d6b1, 0xda769603, 0x02ad7ea4, 0x655e7514, 0xe49e56cf, + 0x710d1a58, 0xba33f2a9, 0x852e2e70, 0x1e506048, 0x44804780, 0xf1656f90, 0xf925ab0b, 0xdfda3e5d, 0x8845dbd3, + 0x18621083, 0xb1489a79, 0xd2947f73, 0x71f6c205, 0xc0365206, 0x631f3740, 0xceea37e1, 0x18a8819c, 0x1958ea59, + 0x95a7ff5a, 0x85f0e419, 0xf31beae7, 0xf5119189, 0x1005bdf9, 0x880f40bc, 0x50fa058f, 0x6a0aadc4, 0x91c4a03f, + 0x462e6f2c, 0x8d7fddb2, 0x29125e88, 0x9e1d7b09, 0xc9d6df75, 0x1ce09b8b, 0xe2def664, 0xc8f8539b, 0x16fbbda1, + 0x0fae9dd1, 0x5fd0267b, 0x14273f72, 0xd3b8210a, 0xbd5f1e9f, 0x417333ce, 0xd0d13eba, 0xfd916083, 0xbb1b69e9, + 0x7ffcc144, 0x48df03de, 0xda5685d6, 0x3a385d17, 0x22c482f7, 0x45c6dad7, 0x6236d690, 0x28973605, 0x21fd8c97, + 0xce8dd2e3, 0xa5bae182, 0x011e22a5, 0xc6172f9c, 0x600e19ac, 0xc28621e3, 0x46d6b454, 0x714e24e9, 0x3cc846f6, + 0x587b0e49, 0x0ac04e27, 0x3aaae49b, 0xcfdeaea5, 0x6d4c756b, 0xf83f032a, 0x238d6117, 0x01e7c744, 0x965b97f7, + 0x44e6d0db, 0x43b9a06f, 0x2912e297, 0xaa0c93b5, 0x35a8d548, 0xd3e7ad95, 0x66ae924a, 0x3f9710f7, 0x595545c1, + 0xc69bbe4f, 0xa45e3f68, 0xb1b76d09, 0x61396b89, 0xd4176918, 0x70d398db, 0xfac5b6ac, 0x45bca8e1, 0x56575a83, + 0x2f4329d6, 0xc71db646, 0xdb7181a9, 0x8d1b6182, 0x3d3297f5, 0xa00bd539, 0xcc8119e8, 0x8132791d, 0x6fad74c2, + 0x0e02ab22, 0x44c719b1, 0xfa639962, 0x48ec9a87, 0x0c5ced82, 0xed72b9e9, 0x7d3f1aef, 0x6e968ac3, 0x8ab111ae, + 0x580cab76, 0x8cf8ae91, 0x1b5c47f6, 0x31dbe250, 0x8a22c8fd, 0xd288b1ab, 0x22dd7b58, 0x15e9fc28, 0x2b156bd1, + 0x77702f1a, 0xbe73a844, 0xf88f00b2, 0xf87fc0d0, 0x89a42879, 0xa4cb16fc, 0xcef9386c, 0x31c1989f, 0x91c2d11d, + 0x91799b3f, 0x4f73213f, 0xd280db7e, 0x663011c0, 0xac13f372, 0x144c2dc9, 0x55cc0cc6, 0x57838772, 0xcebff0cf, + 0xb044553b, 0x3bad8167, 0xe5833c4c, 0x37a6fd66, 0x12f8627a, 0x1525f0ae, 0xa645c0f1, 0x33592a5b, 0xde031380, + 0xfc2ed434, 0xb4438296, 0x64d3f4b2, 0x801bac6b, 0xade25682, 0x5d196c5b, 0xb33a3bba, 0x06a481b3, 0xf2fa78e3, + 0xffee298d, 0xd0474a7c, 0x87e889a4, 0x643e0733, 0x2919b643, 0xea4826c0, 0xa4264d33, 0xfb593fe2, 0x1be44707, + 0x6a3f255a, 0x437066cf, 0xe2b7249d, 0xadf89268, 0x2e66793a, 0xe2f832d0, 0x2e66bdd3, 0x3507f60d, 0xae6097b5, + 0xaf0b71d5, 0x744f481e, 0x382b67ea, 0xbff927db, 0x035f3c37, 0xc9af9903, 0x00330b69, 0xfd8150f1, 0x2e07abf8, + 0xb6896f39, 0x35b188c0, 0xb5f9a4bf, 0x9387b7d9, 0xc820e7f9, 0xd3ae6848, 0x90f86c34, 0xa466e094, 0x0ccb90da, + 0x268edc9e, 0xcc6c2039, 0xb8189338, 0xd0b293da, 0x5a8a64ca, 0x1f9a8f7d, 0x6f46c3cf, 0xcb34bd12, 0x7446d14d, + 0xeab90f66, 0x93299a6c, 0xe02dc9dc, 0xfda44632, 0x6e382cd9, 0xfe7a3555, 0xce8290d7, 0xf36aea59, 0x833c03bc, + 0x13d06db0, 0x6a30b714, 0xb5abb839, 0x59a45297, 0xcb707c5d, 0xefcc1cef, 0x8e4b7ece, 0xe54eca89, 0x0fdf4a19, + 0x97fdef9e, 0x6c1d41de, 0x2dba088a, 0x5fbf432e, 0x20190f44, 0xc981ba90, 0x5712b1fc, 0xed6f5132, 0x0f3aa706, + 0xce997951, 0x995ddfbd, 0x95ce010f, 0x736510ef, 0xb53cdb04, 0xd4ea58d7, 0xbc43213c, 0x10ac5a52, 0xde84d195, + 0xf3bfb262, 0x6997e70e, 0xc966179e, 0xd3f15f6a, 0x6de775bc, 0xf0cfe45d, 0xf5ad00ec, 0x56d96213, 0xb8d61219, + 0x1531cf30, 0x96d1b007, 0x70ae1b58, 0x4a1e1a87, 0xab65f3c9, 0x93e836a5, 0xf39df4a8, 0xedc2ac62, 0xc6b2fad5, + 0x889c8a7e, 0x06c1031b, 0xa1f068e8, 0x1444a451, 0x5ff559a2, 0xa0830592, 0xb8bfd501, 0x5816b542, 0x68f3bcba, + 0x3c6b8887, 0xc7d86940, 0x0827b687, 0xb069ea41, 0x86dccbcc, 0xa65ac588, 0xa3a8636d, 0xd332eb3b, 0xe0ff70f1, + 0xa68286c7, 0xa2fd99ee, 0x00c92afb, 0xedb8c2cf, 0x5bf74f38, 0xc8560660, 0xaec8ad87, 0xac7f229f, 0xe211d359, + 0x228b0f90, 0x83bf36ad, 0x3f46c8cc, 0x37180efd, 0xe8a1bb6a, 0x58013f2c, 0x2f5952d5, 0xabd23f8a, 0xa18795f9, + 0xa7148df9, 0x1681bef5, 0xfbc46f86, 0x8f41b895, 0x50c0c8af, 0xab8e4a44, 0x78f11d7e, 0x3e928c8e, 0xb1a679c7, + 0xd991cf27, 0xe4de58f5, 0x8093a38f, 0x16afb520, 0xc5591927, 0x86deef8a, 0x2776b0d9, 0x2b5d09bc, 0xcf71b994, + 0x1f0ff38e, 0x5fea073a, 0xb7858c5d, 0xfb849733, 0x1babe142, 0x0a40c8dc, 0x03ef597d, 0x14e5d84e, 0xa286bdec, + 0xaa2253ea, 0xc040d822, 0x45f5886a, 0xd150e0de, 0xfc459aac, 0x4aab1940, 0x44a9837e, 0x97dbbafc, 0x32b24711, + 0xb179a858, 0xea65c7c2, 0xd3118fef, 0x23b1272d, 0x1c2cf76c, 0xd84ab694, 0x27d14f8b, 0x3d9b2710, 0x29238cd0, + 0xee7fdf9f, 0x84705ed0, 0x181a05e8, 0xed5ee5ac, 0xbf543f24, 0xba3afed4, 0xf831bfa3, 0x344fc0f2, 0xa52a0191, + 0x8d925c04, 0x57420afa, 0xf937d85c, 0xfc0d0d97, 0xdc8a65fc, 0xe2954915, 0x554bf2a7, 0xf463bedd, 0x0af66e3a, + 0x9ecf105c, 0xf513ccd9, 0x578971fa, 0x00cef63a, 0xb8be1ff5, 0x17652d5a, 0x374d28c5, 0xbded79c3, 0x0497ab4e, + 0x40e041eb, 0xddcfdba7, 0x9d9232ee, 0xa60913c8, 0x89534098, 0xb1deb3eb, 0x05c7473b, 0x9e74af04, 0x3591856c, + 0x1339ee16, 0x26e88665, 0x3b87f75a, 0x45979354, 0x9d1f3229, 0x7e11094d, 0xd09c6de7, 0x3b35976a, 0xa15148e3, + 0xe8ba44f8, 0xfeecb381, 0x44d94e33, 0x41a6c895, 0x9c3d1256, 0x3825056b, 0xb883464b, 0xc8a9966f, 0x484fa951, + 0x4ce47554, 0x9359ab69, 0xef16f05b, 0xd804b363, 0x3dfc07ef, 0x59fb5bd0, 0x4b54c94c, 0x296c06cb, 0x07272e54, + 0xf8e4f64d, 0x24efaeff, 0x8da037bc, 0x9981814e, 0x6061daa3, 0x894c9438, 0xa93c7562, 0x397cde25, 0x397dffd7, + 0x4c6e7bfe, 0x040110d4, 0x6c87f5bd, 0xa0fa7e6b, 0x7054f0d4, 0x4b97887b, 0xb0bc1b27, 0xc7513101, 0x6e5644af, + 0xd4319f12, 0x7342e891, 0x943c7879, 0xc71c8482, 0x833f27f6, 0xb740b4d1, 0x40b46555, 0xa228a0a3, 0x3cdd01ec, + 0x77bdb561, 0xb128a690, 0x636836be, 0xf1f39ce0, 0x72fbdefc, 0x4ccd4371, 0xab631704, 0x8ae5ec5f, 0x072e3498, + 0xe8ad3e79, 0x291aa5c9, 0x68d24ee5, 0x718839ad, 0x382b65fa, 0x81bd1f0d, 0x57469781, 0x125530e1, 0x04b9b6df, + 0xcce90ba0, 0x1c110a34, 0x4923a8a7, 0x75035550, 0xe58c9aba, 0x9e16e7ba, 0xe7fcea48, 0x67c1fcb6, 0x4135d75b, + 0x64577655, 0xfadeb368, 0x5dd8d3b2, 0xbaadc197, 0x3de61568, 0x57dbffb3, 0x930779aa, 0x280a9312, 0xc32bffda, + 0xd67847c7, 0xfa37f88a, 0xb008769f, 0x2212a5b2, 0xdda52f77, 0x509c9641, 0x148b8bbd, 0xceaa447a, 0x1842c64b, + 0x894b15c8, 0x1640a551, 0x41188a2f, 0xf4a09d66, 0xb18478da, 0x915327ea, 0xb3da4639, 0xa9ca4870, 0xa64ead12, + 0x0f378278, 0x04beeca9, 0x1b22b4eb, 0xb5a44f3e, 0x8ca34660, 0xa746d675, 0x57547da1, 0xa8c1d403, 0x27c9e4d0, + 0x4d5b449c, 0x159bdbe7, 0x2bebfe98, 0x980ee23e, 0x56f0b395, 0x7dbc3687, 0x05d6cb9f, 0xf0f56751, 0x4afb7dc7, + 0xdc6fcc6d, 0x1240ace0, 0xb6cd3750, 0x88ba3670, 0x145ebc69, 0x7dbe28a9, 0xd337d01c, 0x7def4573, 0x4ff24d31, + 0x3c00c1a2, 0x5fc74c98, 0x68fee3c8, 0x1fe84b78, 0x567716d8, 0xf2dbd94e, 0x49ba6539, 0xa4de7942, 0xb1b2f5f3, + 0x7163cf39, 0x9664e712, 0x5eccf2b1, 0xb0dafc95, 0x877a4bd3, 0x7cb6982b, 0x80f4dfe7, 0x6e38356d, 0x1afb8f8c, + 0x994a705d, 0x8d66be25, 0x5e89c1e4, 0x4237ca22, 0x11f11bbf, 0x616a0dfa, 0xb014c7be, 0x05f48b59, 0xaa6b14dd, + 0xa3f59bfb, 0x6e50e231, 0xe77a42c0, 0x3cf426d9, 0x83b2520c, 0xd16abe84, 0x02c6dcc0, 0x2e391dcd, 0xbeebdc57, + 0x2e6f31d0, 0xc8fd2d95, 0x815980c8, 0x6e853d8f, 0x8af72d14, 0x2b563a0b, 0xfd766419, 0xed8cb3cb, 0x28df81a1, + 0x882035a8, 0x90f74c83, 0x2000028f, 0xdf66e2de, 0xf73f002a, 0x2abed4a6, 0x942340d8, 0x62ed4ae0, 0x119198dd, + 0xeed36517, 0xed070061, 0x2a638551, 0xa0fd8f29, 0x52d7b0d4, 0xefea945f, 0xfd79c215, 0xdc38589a, 0x8bd3a04d, + 0xfe775e70, 0x079f7d96, 0xb060327a, 0x6e734b3d, 0xb4491317, 0x602c676a, 0x25ecf8cd, 0x7e5ee8e5, 0x04eb4125, + 0xa21f678c, 0xad890d31, 0x4e3b2158, 0x9ff62677, 0xcc4f9f73, 0x3b593157, 0x590c2aa5, 0xf9db77b8, 0x2e0ceb5e, + 0x1a2259b3, 0xeefd6b1a, 0xd6c7a8df, 0xe8d69f59, 0xe96fd95a, 0x33502e4d, 0xd755ee30, 0xead90f5a, 0x579ad608, + 0x1c614359, 0xda956e9b, 0x6a1779d6, 0x124f4abc, 0x983df470, 0xd1511224, 0xdf34085f, 0xb44150e3, 0x1ee14a06, + 0x8c54620a, 0x81243f30, 0x9b599315, 0xae7b234c, 0xeccc0ec4, 0x4ecad253, 0xad07fb39, 0x631e4eb3, 0x2686fa72, + 0x745e18ff, 0x18e009f7, 0x6dd6e0a3, 0x58ae4fba, 0x0f47d996, 0x7b16d7bd, 0xf5c21491, 0x7daf378f, 0xce645829, + 0xfcdadb1f, 0xfc615668, 0xc31ea30c, 0xb490e090, 0xefa04567, 0xa95badde, 0xa9773b74, 0xc922fd3f, 0x77a8915e, + 0x96b8e362, 0x6d2da03c, 0xa2470ba7, 0x96ed677a, 0xaa3467e0, 0x596995d2, 0xf4a0532a, 0x962ee8bb, 0x24f0397d, + 0xfe8d972f, 0x65718bed, 0xe051db30, 0xd6661b1d, 0xb81bcaea, 0xee0c895e, 0x94e3bb63, 0x18b632c8, 0xe683a9c0, + 0x1339f44c, 0xcfa5c8a0, 0x006cdf21, 0xbdd25456, 0x417cd5af, 0xa434b19c, 0xfd0af5f2, 0xb17a6c16, 0x5f34b102, + 0xadd4f7d3, 0xfb0549b4, 0x656a9528, 0x49d6dda7, 0x4c9a792a, 0x5371063d, 0x15187fc6, 0xe8608595, 0x6aae589f, + 0x030f0370, 0x834227e6, 0x598cd4d9, 0x8d57eaa0, 0xe20775a3, 0x654758a0, 0xd87d4a82, 0xeb3745f6, 0xfb77d994, + 0xdf82f26b, 0x73406bdc, 0xc175dfc1, 0x632176fa, 0xa68eefc1, 0x34eeb566, 0xca37430c, 0xe7eaa6b7, 0xfd1d61e2, + 0x9b579451, 0x7f98b707, 0x0efd8e5c, 0xcf1b6cfe, 0x805d05cc, 0xa29553bf, 0x306b6a71, 0x680b083a, 0xa3d4f453, + 0x713959df, 0x597b3464, 0x349f070c, 0xd3efe809, 0xd84634aa, 0x00184cda, 0x4d43cd5d, 0x868eda36, 0x2b94e28b, + 0x3584ab88, 0x50a329e4, 0x4bda1989, 0x8abcb05f, 0x07f99d23, 0x7798960b, 0x27fbd9fc, 0x9b5d0130, 0x69355a12, + 0x7e87b269, 0x545e1153, 0x845c0d1d, 0xc293ccd3, 0x42470361, 0xa349fb7d, 0xf34e73b9, 0x4292d82b, 0x00884b4f, + 0x16c3921d, 0xbfa0f02f, 0x1ba26542, 0xf8cf43e1, 0xafc5e60c, 0x5b379041, 0x82090a4e, 0x0e2e6713, 0x8be7b9c9, + 0xa858a24c, 0x09549d63, 0x117a772e, 0xc9350f3a, 0x5a57f836, 0x5d158a05, 0x0d3648a9, 0x3b654df4, 0xae39b119, + 0xdeb53850, 0x6ab1aae3, 0x589ab8b9, 0x679e4234, 0x9ed8f0ca, 0xb51921ec, 0x93f84c8f, 0xa63aaafe, 0xe68b9dfe, + 0x745dbe18, 0x1352c55f, 0x1ccb5bb8, 0x82b62bb9, 0x35d16616, 0x5f44fbc2, 0x386652e1, 0x9d2a793d, 0xc74ca82a, + 0x205ecde7, 0x01a65d2a, 0xfee09d2d, 0x5e6662c1, 0xf2963d1c, 0x5f265bdd, 0xe5110026, 0xc911ce4d, 0x6077e75e, + 0xadc1937a, 0x9a9a0aaf, 0xd0eaba3c, 0x9299618e, 0xbd538fc1, 0xa911d335, 0x56f6811a, 0x140f9f7c, 0x1b9ee5b7, + 0xdc6ab8bb, 0x3f049ad1, 0xfe15fb11, 0x64b1f85f, 0xa40f5c23, 0x60683115, 0x8d75b0b2, 0xefb8103c, 0xbea9e0d4, + 0x24034050, 0x3ec22d62, 0x6ff337a8, 0x52629d71, 0x9733f8b5, 0x50bb6761, 0x3199e9be, 0x605dee18, 0x7a494009, + 0x92298fa8, 0x91fcfd39, 0x0512c3a1, 0x6ea58ecd, 0x239dc605, 0x4d9c8d30, 0x9c176716, 0xcf796401, 0x24a843a1, + 0xd40e1591, 0x95852fc7, 0x12144c97, 0x6d818b6e, 0x9c83e73b, 0x6f0d8c18, 0xb378ff28, 0x6474c0bf, 0xdfd8cd35, + 0x76490bdd, 0x8aac88fd, 0xa2c3f58a, 0x5ea7179e, 0xd75994fe, 0x100bc3b4, 0xbe14aaa7, 0x41a11cb1, 0xd6fc6f3c, + 0x56053a40, 0x28e2def4, 0x82c32735, 0xaf628b45, 0x5fa84f20, 0x34ca7790, 0xa05bffed, 0x7069674a, 0x02222edf, + 0x1a1db12e, 0x64bf526a, 0x7fe41c8c, 0x00b7137e, 0xa3951fe6, 0x33012702, 0xb3cde06a, 0x3ab13711, 0x82003f24, + 0x18293587, 0x07446df1, 0x2ef44012, 0xaefa8560, 0xd7d24bc2, 0xf46cf299, 0x195dbeca, 0xc41308d8, 0x3ec56c8d, + 0x40fde8fa, 0x8d29a0f5, 0x185e3293, 0x05caf6ed, 0x9482520a, 0xdce68d55, 0x5ef5b459, 0x274977ff, 0xfb7c16bb, + 0xe43aaca1, 0x2ebbcb23, 0x40990e64, 0x7f4759e6, 0x5296b00c, 0xbb11f7bc, 0xdadf546e, 0xbe7283b7, 0x39fa09fe, + 0x9d529337, 0x417087c8, 0xc8daef0b, 0xb62328ff, 0xa86ee35d, 0x361b250f, 0x17d575cc, 0x78037d51, 0xb4a9d09f, + 0x35feed22, 0x6038599c, 0xa985209e, 0x742cf1d4, 0x58a503c3, 0x48c9b112, 0x683fb564, 0xebaeeabd, 0x7bc34156, + 0xcbaf8f09, 0xf9cccd9d, 0x56e120f8, 0x7dd43083, 0x89e12af5, 0x63ac19d4, 0xf3c005b9, 0x1f9dd50d, 0x832ab9ed, + 0xcc51f7a2, 0x701bcb4b, 0x9345ce7f, 0xb898e091, 0x4e3520b3, 0xb468316c, 0x34e58595, 0xae4e88b5, 0x8056e6b8, + 0xc18486d6, 0x1a4f2c8e, 0xa8a85282, 0x04e9dea2, 0xa705ee4a, 0xe7aa743f, 0xbadb36d4, 0x7ccc2adc, 0xe29c9039, + 0x4b488d1c, 0x4c0a2448, 0xc2cabfc2, 0x262ce5a7, 0x08043168, 0xddc2ef95, 0x3a4dd60b, 0x7a1fd824, 0x5c52bcff, + 0xcf5ea5a3, 0x3b616cf9, 0xcd369a63, 0xfb6adc64, 0xd527f9b6, 0xe0fa526e, 0x45b73b54, 0x09a47c83, 0x65707293, + 0x183c2e59, 0x875cbd59, 0xbd0a3c7d, 0x8a5e1c94, 0x8dade702, 0x3f76d8f5, 0x814ddcf4, 0xfa51bcb9, 0xcde50af8, + 0x1c5cdf77, 0xc5b7b4ed, 0x6e6ebadf, 0xe8209f2b, 0xfba89f42, 0x2fdf7cbd, 0x4cd1e00c, 0xd58867ea, 0x24449d6c, + 0x7ba85225, 0x0608e99f, 0xb970a63c, 0xf52c0fba, 0x0fc0c4e8, 0x85f155f4, 0xc0914146, 0x415cee42, 0x4249f75f, + 0x6ebd64c0, 0x12a59355, 0xf3ee3428, 0xe4bca2b6, 0x13ab0161, 0xa85a1afc, 0x016a3239, 0xc6eacad0, 0xfe216cf2, + 0xeac0c2c2, 0x521badac, 0x7230b62e, 0x44dcc8b4, 0xd7aae80a, 0xed77a2ce, 0x29e9ef49, 0x8e625ce3, 0x24c50a4c, + 0xa6e2c1e9, 0x6aa1ca2b, 0x80359cab, 0x24316679, 0x07cee1c1, 0x9edb20b8, 0x30b8527c, 0x2f5bcb8e, 0xe0fedf0c, + 0xb803ad81, 0x9f244daa, 0xea866d6a, 0x335c5a0c, 0x8025b34a, 0x09a4c547, 0xe2727670, 0x453cb633, 0xed23a334, + 0x4a569870, 0xa8bcd1c9, 0x1afa32dc, 0xed40e273, 0xd308e0ff, 0x6af11efb, 0x022d3104, 0xd2b185c1, 0x34b8cab8, + 0x62213b92, 0x14507d39, 0x5633f422, 0x899b88d0, 0xcec32cc6, 0xb5f0a84e, 0x3a88ec77, 0x0c178bae, 0x9bf252bf, + 0x3e9ba133, 0xc266f6fb, 0xfed1629b, 0x2b1c5c27, 0x3d90f765, 0x6b705f7b, 0xe46250b9, 0xbdad8f1a, 0xc7a8319a, + 0xab927c2e, 0x491926ae, 0x5ea7b7c9, 0x73a29a42, 0x9dff41ee, 0x7762c3fa, 0xc6f465c4, 0x9548793d, 0xe56b1a65, + 0x9a1dcae7, 0xcd04f66c, 0x27336c01, 0xb19bbb33, 0x359a7e5a, 0x8a73197d, 0x191a488c, 0x376bdd96, 0x150933df, + 0xd4092442, 0x0da94c24, 0x9a0da385, 0x23be4d21, 0xb85ba9a6, 0xd2ec9cee, 0x216d9aae, 0x4da14ed5, 0xd00df60c, + 0x2673ae2a, 0x811c1040, 0xbec80f69, 0xee1af632, 0xffeb83cb, 0x5f0a122b, 0xd72f6f4b, 0x3797bde7, 0xfe336dae, + 0x6f74d42a, 0x23c12a9c, 0x99179af0, 0xb89f2653, 0xf846a5fa, 0x2af811b0, 0xa0ef3e99, 0xdf540f15, 0x07fdbc66, + 0xde8869ed, 0xd2d67ab4, 0xe4c26880, 0xe0b3717d, 0x51cd1852, 0x4f772acd, 0x3a1f95cd, 0xefc5bdd4, 0xe978a7b7, + 0xa95d4925, 0x43a35e90, 0xf2b0a8b9, 0xe777c669, 0x8b0e8150, 0x5544f9c6, 0x041caab9, 0xf417f167, 0xadd38d32, + 0xf2c2ed40, 0x9aae3fe0, 0xc3d71f1c, 0xce78a9fb, 0xfb812bd3, 0x457b3a04, 0xe77e4ea8, 0xea7cb803, 0xb7132f01, + 0xad720a76, 0xe788f4c1, 0x31ab673c, 0xc3d8124f, 0xdab5b378, 0x61c21f0d, 0x3ed32485, 0xcb2b48f8, 0x36425cfa, + 0x428facbb, 0x56b3792c, 0x706521df, 0x66613c5e, 0x77ad60d3, 0x9cd7022e, 0x3190f6b1, 0xf96b4d97, 0xc6cdf26e, + 0xba85ec24, 0x6527777b, 0xa334ccfd, 0x87eb0550, 0xde2dbf15, 0xb0876fa3, 0x4748199a, 0xd7d30060, 0xd5001e23, + 0x5cd53129, 0xa18e87b3, 0xb809146a, 0x1fa1546f, 0x62164b4e, 0xb719a2a3, 0x5c40b949, 0xf9ff26a2, 0x56c7c207, + 0xdf7f5bda, 0x81194cb9, 0xafa9e9ca, 0x2e03fcc9, 0xa2ea4840, 0x9cf7729f, 0x00149fc0, 0x2ae91e65, 0xdf37d4a1, + 0xec868d90, 0x60073689, 0x8ab32c1c, 0xb26c8659, 0xa99ea571, 0x8fee0828, 0xf8436961, 0xf7e55a76, 0x7f23d3d7, + 0xc5ea524a, 0xcc4fe279, 0x04c6d820, 0x4fc6ade7, 0xcf6c82f1, 0xbb0d4f07, 0xc4534346, 0x766891d0, 0x05379cd8, + 0xa3ad2928, 0xc9677025, 0xcb185618, 0x0bd46af0, 0x44e4abd5, 0x525a0f9b, 0x63353cb1, 0x6fc4ddcd, 0xe9432cdc, + 0xe3fb5ec8, 0x6a18c469, 0x744b04f7, 0x4f33b17b, 0xc7df9fe5, 0x46718efc, 0xcc9a5b08, 0x582a2aa7, 0x7c5b0baf, + 0xee56248f, 0xdeab5d0a, 0x5a48b598, 0x75447d64, 0xf9b54f07, 0xefbcd161, 0x0b390826, 0xef505a81, 0xf3844b32, + 0x62eba412, 0x3953b170, 0x3644fe25, 0x2d438152, 0xf734c0fc, 0x2231affc, 0xac514341, 0x7c46f29e, 0x82a498fc, + 0xe7ae7e99, 0x1d445f7b, 0xfce36134, 0x2d38d784, 0x0026c875, 0x7048c15d, 0x06a7c975, 0xea4d304b, 0x5cd9a6a5, + 0xc23232bf, 0x7f7a2b7f, 0x0bba2267, 0x4a2ed453, 0x5b91499c, 0x89d2dd77, 0x3fa2a3ef, 0x667c6419, 0x17a4f4c5, + 0x88a26006, 0x3adff8ba, 0x89db88cc, 0x106ad316, 0xeee5a23a, 0xc2cc3b2c, 0x25dc111a, 0x4b3024c6, 0x146bfdc7, + 0xe370f479, 0xa0319ca1, 0xfbde4649, 0x3b9ca3a3, 0x80971a81, 0x65bf8c87, 0x2e773a0c, 0x111dbc52, 0x8e42c10e, + 0x53e6e669, 0xe39e5bd7, 0x5ead2be0, 0x13c567a4, 0x3de85e38, 0x0fe6792b, 0xa8985323, 0xbbb424c0, 0x5935cc39, + 0xab55a450, 0xc62e488a, 0xcb97fbc3, 0xbc209f01, 0x7773329e, 0x5f152af4, 0x45944d94, 0x4a193706, 0x415d95a8, + 0x4bb95f4b, 0x15efdc21, 0x6c95f97b, 0x3008c16c, 0xf2786e2a, 0x52651b1a, 0xa4b22d13, 0x6c223d0e, 0xcb6fc45d, + 0x950ae2a9, 0xa63073b1, 0x250a5b60, 0xaa58755b, 0x8ea69edf, 0x4460b26a, 0xae1a010e, 0x23d72666, 0x3e92a779, + 0x84af09b6, 0xadf47e5e, 0x9d7e7131, 0xf1c19c51, 0x617e0912, 0xa819d101, 0x05858d0e, 0x1eb49510, 0x706f6a2b, + 0xd012c9af, 0xf75a90f7, 0x84376e94, 0x65cdc111, 0xca4f2c17, 0xceff238a, 0xd5c8ccaa, 0x8caa4046, 0x92b95e76, + 0xc7eaa1d2, 0xdcbbd41c, 0x4fc18bb2, 0x1a4f9332, 0xd8707e89, 0x66794a59, 0xfb08e73a, 0x4701b625, 0xca93e9e6, + 0x871cc992, 0x08c80a58, 0xb92bc9db, 0x2030e03c, 0xdc38bf42, 0x8cb0d7ba, 0x971549e7, 0xbcc19452, 0x2eb58363, + 0x7da0f50f, 0x7973429a, 0x80a33f00, 0x03ea5e00, 0x3e3f6ff2, 0x5a4bd2f3, 0x5f151c67, 0x722a570d, 0x30526076, + 0x0d559a74, 0x52f6f11f, 0xa2bdd94d, 0x8f3c986d, 0x202b74b3, 0x1c5e4f1c, 0x7638f314, 0x3bf363c1, 0x199d3733, + 0xca7518ff, 0x8bd6a661, 0x3d3847a2, 0x39f66987, 0xaea11ceb, 0x6377f546, 0x2d937798, 0x8b1ef0eb, 0x1804530b, + 0x76b7713a, 0x42a39da0, 0x91af0648, 0x07624df5, 0x9236f68d, 0x17c672b7, 0xb8afb316, 0xd450cbc2, 0x03af8b2c, + 0xed8870b1, 0xe28902bd, 0x934a7063, 0x38bc206f, 0xe7613246, 0x623e4405, 0x67a18472, 0x718a2ab9, 0x36ffdffc, + 0x7c91a1aa, 0x99a766d3, 0x6b1b84b5, 0x7f2172e4, 0x6f143d6b, 0x314beb44, 0x9f468ebe, 0xba442770, 0xfedfdac1, + 0x80e9fb22, 0x89372289, 0xcb1bfb7e, 0xcc14c10c, 0xdff222a6, 0x8fedd7f2, 0x35f20cc7, 0x29dcb16a, 0x050f4dec, + 0xd8437dc4, 0x6c7cc421, 0x87eb3a4d, 0x1ab57033, 0x65b04191, 0x478fe73b, 0x1b3fcbff, 0x16b45a77, 0xf4a65dac, + 0xd54701f3, 0x1f0cb20c, 0xb1f617af, 0x27714f80, 0x4c06615e, 0x1765c36b, 0x4fe9df7a, 0x2e4482d6, 0xeabfc23e, + 0x2df3d13e, 0xd8b69f4c, 0x71767ddc, 0x5d5c5605, 0x81e323f2, 0xe5c83294, 0xb99075d7, 0x6552002d, 0xe226c21a, + 0x90723cfd, 0xf6288a5b, 0x7b5abc74, 0xa73d2137, 0x0b37baf3, 0xb0acec8c, 0x8dc4b363, 0x9b339a52, 0x30aaaaa7, + 0xf5fdd221, 0x251456a6, 0xb4e2d76b, 0xcbf1619d, 0xfd3097d7, 0x2b1ddb23, 0x814c81ba, 0x2b1b84ea, 0xa7b11396, + 0x173015fc, 0x4b5752aa, 0x2a15ab56, 0xd619e8af, 0x495f2b53, 0xc0ca738c, 0xe44d9c40, 0x06be2988, 0xe5f688c4, + 0xc3e82542, 0x00fd96bb, 0x00bd9eb6, 0xb4775b5d, 0x739a6a5d, 0xb412bd3d, 0xa3b5838c, 0x363c4a82, 0x2502b6ca, + 0xba46f0bd, 0x3d69fcf6, 0xb5c3cb9f, 0x24d50228, 0x8b27f2b1, 0x7b263c54, 0xab5164bd, 0xfec995cd, 0x5042ad2b, + 0xa6e34e26, 0x278723a4, 0xb59c2ded, 0x632e98f9, 0x7006c46c, 0x34a11ef6, 0x3c630b66, 0x6e445f8d, 0x572b2260, + 0x1a8ed0b8, 0x8cea4db1, 0x1a800099, 0xa89d8db5, 0x4587ad86, 0xadd921ae, 0x8413c55a, 0x9cd5f9f7, 0xe1499646, + 0x27a2f94c, 0x8d76ea7b, 0x08a0c3c5, 0x17b6b683, 0x82feef69, 0xabccd300, 0x231da172, 0x82fd32ed, 0x627a1f10, + 0x0905d7ba, 0x1e1dc8c5, 0xb5f1158e, 0xe25d028e, 0xbe50c55a, 0xde5cad0a, 0x14e164cf, 0x40bf0b41, 0xa625c2cc, + 0x1b34e47f, 0x7ed60378, 0xb231eb6b, 0x50d51186, 0x0b84a10d, 0x5932875e, 0x3616481f, 0xa1b10be5, 0xbbdd2fe6, + 0xbe7cd959, 0x83802317, 0xeba5eb1f, 0x5b824ca5, 0x361235a6, 0x74c01230, 0xdcfe4610, 0xdf6e9e65, 0x72f08c5c, + 0x844860ad, 0x6b141370, 0xcf60794a, 0x7d26fbb3, 0xf96eed0d, 0x289bd7ab, 0x12a4b4f3, 0x3af52b8c, 0xaa389997, + 0x6721b61e, 0x7a35652e, 0x80d2ab88, 0x0c5a8120, 0x27d7ff3b, 0x13a8cbc7, 0xe4fadd39, 0x880527f9, 0x45358fd9, + 0x86901fb1, 0x623482d8, 0x607becb3, 0xc3b4513e, 0xa8aec902, 0xfa87cff9, 0x0e133dd8, 0x625fe38e, 0x04bbb65d, + 0xa1e359b1, 0x14fa9439, 0x5373a3a4, 0xa045d7ef, 0x0e89af1b, 0xfd4f6620, 0xdc41d4c8, 0x9166c69b, 0xf742837f, + 0x98957a16, 0x7541bc91, 0x9479ed66, 0x04205805, 0xb44f47a4, 0x48f26df9, 0x240a9c09, 0x2dd28b0e, 0xf40b69d5, + 0x0e53d505, 0x3f08b1ec, 0x827abef2, 0x2459c5af, 0x0eb73d03, 0xa1e1627e, 0x6ff6f65b, 0x9b50ba35, 0xea379ef3, + 0x07a4e62f, 0x18f86173, 0xbd672e04, 0xa240952a, 0xb03d71cf, 0x1d5e07b7, 0xcf4a9ba0, 0x2620490b, 0xe3b695ab, + 0x3a5c4121, 0x049bcac7, 0x177e7729, 0xcae1adea, 0x06c80991, 0x43f1aeb2, 0xa0a53d5d, 0xfb5b641d, 0x8a367d25, + 0xe1732055, 0x995bfa01, 0x1bac205a, 0x9ea1676d, 0x77a9f607, 0xd2699d39, 0x194c549e, 0x541ab81f, 0x28df3cff, + 0x4a6735fa, 0x2fd653de, 0x795abf3c, 0x0873cce7, 0x360ac7a2, 0x29759d57, 0x3e272a42, 0xc5768c54, 0x3bebca71, + 0xd0c17483, 0x6dfabf9e, 0xe064204f, 0x5a69835c, 0x61e063b1, 0x0292bd22, 0x53d299db, 0x18d0a891, 0x8330703c, + 0xc6e815ab, 0x5d351f13, 0x2654bb46, 0x65015bd5, 0x5dccabd8, 0x890cd9c9, 0x849f92fa, 0x9717658c, 0xe0b29669, + 0xeca102f0, 0xd4dd2dd3, 0xb232f6dd, 0xafda4e26, 0x75078980, 0x65809e94, 0x6a1c466a, 0x1a353906, 0xcc181fec, + 0x73376775, 0xb31daa7c, 0x815d23d5, 0x66cf937a, 0x3c038fa4, 0x43255ec1, 0x22372b35, 0xfd621c66, 0x40546122, + 0x35d71b96, 0x28597eeb, 0x468fe74e, 0xc657e79a, 0x8c918f7e, 0xc8d397de, 0x904460ff, 0x5696f5f8, 0x5a194e7b, + 0x423de76e, 0xa7e36a72, 0xd774731d, 0x2bc45327, 0x5b444cdd, 0x6696c97e, 0x3a7e3446, 0x65fdab78, 0xb486dff7, + 0x23ea6be9, 0x3a02b869, 0x0fa58cf2, 0x221f832d, 0x9e402d85, 0xa41429b7, 0xf29c956e, 0xa8822b23, 0x85979fd8, + 0xe2eaccac, 0x919bb942, 0xf4795f2c, 0x1ec32415, 0xe03b515a, 0xcda028f6, 0xcfd36199, 0x2d6b8dca, 0xb8d9e719, + 0x1f2247fd, 0xd9e1740a, 0xaa7704fd, 0xe5556b6f, 0x4917ab9b, 0xfe807452, 0xb5221fdd, 0xcd9df516, 0xc2fd6695, + 0xdd33a5cc, 0x35270859, 0x51e8a596, 0xe6f17b72, 0x0eadf8ad, 0x3ebf176e, 0xa44c8ef2, 0x543f2ea3, 0xfc96cbbe, + 0x2f282ec6, 0xfa8c9fc3, 0x69482247, 0x45844279, 0xc95faf2f, 0xce27c6ee, 0x500b0b35, 0x8f5e6129, 0xb8189026, + 0xf5572f18, 0x5a59a378, 0x289df76d, 0xa6c84596, 0xf300d7b6, 0x26edfacb, 0xa798d878, 0x0995fed6, 0xda185e7e, + 0x3ed5ed3c, 0x90c32811, 0xa9c055b0, 0x34f5e18d, 0x1e24afce, 0x20c2f13d, 0x1004f16e, 0xfd1439dc, 0x66ced515, + 0xd5f60d74, 0x2cd90f09, 0x85f56903, 0x404e6a2a, 0xb63b9636, 0xec49f933, 0x421de3c1, 0x953dd493, 0x98fee60f, + 0x41554ab6, 0xb2890967, 0x41b873fa, 0x889442cc, 0x2693eae8, 0x441533e3, 0x4e103ba7, 0xdd3f66ea, 0x4819627a, + 0x9d6849ad, 0x2e24e94a, 0xf5d34ca4, 0x541eba7f, 0x3eb68299, 0x179c0137, 0xa4441027, 0x6d50fd4c, 0x71554262, + 0x55eae50a, 0x50e7d713, 0xf8220f98, 0x7db50cf4, 0x88b06043, 0x6b68a4ab, 0x54929858, 0x34459959, 0x6a06a6d9, + 0xdc495ce7, 0x1283f7bf, 0x426f08a1, 0x0ef1d6d2, 0x12e2494f, 0xf4e271ce, 0x6245ccd3, 0xf61569b9, 0x3150ec9d, + 0x00bf43ae, 0x11a5c64e, 0xfb42a532, 0x830153b0, 0xc66a72ee, 0xe983f6a8, 0x848158f9, 0x5994a7a1, 0x354539dd, + 0xfd8a1e46, 0x0821d327, 0x5a44731e, 0xf7bed4e7, 0x7d1ee8f2, 0x0e4f14c2, 0xf5ebba91, 0xb5f3abfc, 0x01079527, + 0x814fd715, 0x4f511140, 0x0c93d171, 0xc978bda1, 0x576d1c51, 0x9c5cf146, 0xef546bf0, 0x1763364c, 0xcac96ffe, + 0x4ea7b092, 0x76a55c9c, 0xf5b59050, 0x4578b0d7, 0xb4a4322a, 0x63205d54, 0x4d058869, 0x2ee838e8, 0x17c1db9d, + 0x3f4ed034, 0x23c08bcd, 0x7cab6eb0, 0xf1419a19, 0xd1db302b, 0xd0a96706, 0x8bd7c7fb, 0x85e3b78b, 0xdbafd454, + 0x791f01a3, 0xcfe0062b, 0x51167c44, 0x99c71031, 0xa5fc462e, 0x839832cb, 0x4ca76f46, 0xfc92b5f1, 0x34b936df, + 0x8c9d61d9, 0xfa0489de, 0x5acdf15c, 0xd2cfe957, 0x8150a310, 0x9b762d8c, 0x749ba278, 0x8e2faccc, 0xd18ae2dd, + 0x29b356d0, 0x20e6b438, 0x48caf16a, 0x5ec7d7a9, 0xb29f6fe1, 0x448d6283, 0x2bf138cc, 0x24bb1812, 0x2851f914, + 0x3f951ac9, 0xc14a6d78, 0xe354d1c6, 0xe4b302a5, 0x1f9cfd3d, 0x759769a7, 0x06783528, 0x85d2d2c8, 0x3101ae94, + 0xf43f901d, 0xd8e94940, 0xa4817090, 0x93bd46e6, 0x00e56110, 0x97e053de, 0xfd2f20cc, 0x04127074, 0x76157a0b, + 0xace5bfdb, 0x09340839, 0x41eb319a, 0x95f448b2, 0xf54e2b5a, 0xb104579c, 0xd93f7cdb, 0x6ecf9f1c, 0xe6a9b8bd, + 0x94ccda5a, 0x4501ddc9, 0x06ed6534, 0x383a848c, 0x58196287, 0xb2456102, 0xa3e53bbd, 0x32dd0a93, 0xd339e936, + 0x7fb2fd5f, 0xa8761db6, 0x15d6e7cd, 0xaf98293d, 0xad0b3f63, 0x740263e4, 0x3d6724b5, 0xdc4de62a, 0x575f0d4a, + 0x9f29bbeb, 0xdc501f60, 0xf88f1f1e, 0xad6b2868, 0xa7e7d7b4, 0xb0e44aca, 0x07e232f3, 0xada00512, 0x331ab87c, + 0xbda17402, 0xfd9bd943, 0x829476e6, 0x50c1c668, 0x1eb1d3b8, 0x03fbf294, 0x8569ed96, 0x5308c8f6, 0x74387bf6, + 0x950770f0, 0x6b7589ac, 0x127a7772, 0xa4429995, 0xdd2f2689, 0x7c7225c6, 0x5eb8f139, 0xc614ff4a, 0x9ecfacb7, + 0x20e640a0, 0x305ed42d, 0x30fc704b, 0x953cd017, 0x96d5f16d, 0x294fc4ae, 0x320c2d5d, 0xfb5a9da2, 0x886a49c8, + 0x6c1cf0ce, 0xeabe9223, 0xf2f1a143, 0xca178ede, 0x63b0a806, 0x0884c9ef, 0x974f4d10, 0x61c9ba5d, 0x5dc4a772, + 0xceb1ed00, 0xe6c23573, 0xdb928463, 0x9fb0a691, 0xad8c7987, 0x951375ea, 0x76e283ba, 0x7fee21b4, 0x14f7636f, + 0xac473e01, 0xa720ef2c, 0xe7153c13, 0x7fbd6d5b, 0x79213157, 0xa8fd4302, 0x037de3e4, 0x034be739, 0x31a17baf, + 0x38650af5, 0xbcf30120, 0x6cade9ad, 0x9b1bb19c, 0x8a7d1da2, 0x3f4090f8, 0x8ffc5753, 0x4fdb4fd6, 0x8f89eaa9, + 0xf5e38ea2, 0x88ca4b9a, 0x8daee05e, 0x8108e84c, 0x0a629296, 0xe3f0fe2e, 0xaed524c0, 0x018aeefc, 0xe5b556bc, + 0x6bf70e4b, 0x69541752, 0xa43451f2, 0x6ea3d6d3, 0xdf708281, 0xc5ec18ee, 0xa5bfc0f2, 0x59175ce7, 0xf5854b3b, + 0x10e50e27, 0x6710c714, 0xe69f5565, 0x4e7da80f, 0xabe62f57, 0x7ee1bff5, 0xcffbdead, 0x02451127, 0x36ede78a, + 0x14c9df85, 0xf66ac376, 0x869ccd94, 0x45db9ff0, 0xef4417ff, 0x02c00e6c, 0x8e9dd7f3, 0xea0369c4, 0x24052421, + 0x3b38c25b, 0x10ab1b95, 0xaeac854f, 0xfed0a0e3, 0xdba2799e, 0x4e070c49, 0x17892816, 0x4ab4ae06, 0x778bd2f3, + 0xd184377f, 0x6028613e, 0xc29b65d1, 0x0e96ae35, 0xd36ecfef, 0x7fdd1671, 0x9e7504e7, 0xb6af8ce8, 0xe72a60b7, + 0x2f89401d, 0x2655efa9, 0x95e82d1d, 0x64fe8090, 0x9a26a05f, 0x32d029d0, 0x125d887e, 0x06a48b47, 0xc1d79127, + 0x6f69de99, 0xaf03a00e, 0x9c153ae9, 0x26c60795, 0xca6e1c77, 0x377803f2, 0x93d15311, 0xb684487d, 0x9478b01d, + 0x49281590, 0xb1b5908a, 0x0e443e42, 0x7eb197d4, 0xeae757bf, 0x8b86db28, 0x256b2e3c, 0x022aeb1f, 0x486bc80d, + 0xd1431269, 0x5f461c13, 0xb81212dd, 0x5412e51b, 0xd2bae795, 0xe29d72a3, 0xdb21f5da, 0xe2e69984, 0x83eafd77, + 0x7bb04333, 0xc14b7a81, 0x49620487, 0xc7e27395, 0x2cdeb6e0, 0x1b5cde9a, 0xc636ad5a, 0xcfe58039, 0xcb03004a, + 0xd45476c5, 0xd345557e, 0xba3b377d, 0x8d47cc50, 0xf7981574, 0x9b9726a8, 0x4a0deee3, 0x64569012, 0x116d7f6a, + 0x8466eceb, 0x67c3424e, 0x78111fdb, 0x3c126657, 0x456b2764, 0xafc21785, 0x9ed91fe9, 0x57ad1116, 0xd606fdfd, + 0x4f91b5c4, 0x4808d384, 0xf3a4b70a, 0xdf3501f7, 0x857c5140, 0xd5f5bac7, 0x02736aec, 0x4793f462, 0xc4888a70, + 0xb6acea05, 0xa908c850, 0x163c87ae, 0x04768dfe, 0x76bd3500, 0x4ca8dc43, 0x634e2d82, 0x9301ad07, 0x70982afa, + 0x878e8d17, 0xcd141d92, 0xfc65324c, 0x40fafd51, 0x694b0b8f, 0x9513a2a7, 0x10a693e1, 0x497b2f9b, 0x7a2a2fb0, + 0x0e7fa18b, 0xd8b5cf21, 0x1c037523, 0xf2076143, 0xaaf327ea, 0x2e8dbeaf, 0xe2931d90, 0xce924d00, 0x8596a3ed, + 0x8ef14966, 0xfdf379ee, 0xfea3a2dc, 0xcc2c277f, 0x2c4ae7ce, 0x3c45909c, 0x267c5904, 0x852fdb27, 0xb9a3c3a2, + 0xe0240e7d, 0x542179a4, 0x70244534, 0x74abb0b8, 0x48a90b02, 0x737e277b, 0x711ce31d, 0x4ec87d5d, 0x3fdcd47c, + 0x7c8c5e14, 0x160d24d8, 0x9cab4843, 0xfe268527, 0x8d251464, 0xe51b29b1, 0x1b697443, 0x530f4dc7, 0xa6aedbd2, + 0x938c55ee, 0x254ed0b1, 0xb3b25904, 0x81b52151, 0xe55486a0, 0xf8c0fc1f, 0x454991e5, 0xdb9de36b, 0xd3544bdb, + 0x85d859c0, 0x56510f59, 0x1a886971, 0x4e500a81, 0x8862b833, 0x215ec98a, 0x00fbaab3, 0xa3d0795b, 0x078b6395, + 0x662c5036, 0xcffa53bc, 0x03b7fd54, 0x9917bcc2, 0x0665651c, 0x3c641032, 0x0abd9aae, 0xe5aaabcb, 0x2ccfad0c, + 0xb473a0fe, 0xf69c06a5, 0x5e50b7c1, 0x2fcff2ba, 0xbbe14d8e, 0x688b5b20, 0xe80dcfbe, 0x0a7ab7f7, 0x9ac3cd63, + 0xcdd710d7, 0x91a7f987, 0xadebf860, 0x714b8d42, 0x8e6a148e, 0x7bafb49c, 0xbe97e775, 0x9730a906, 0xfc4c2f20, + 0x65ee1da1, 0x7de1136e, 0x0830c4d6, 0xfc5ab116, 0xe07cdbb3, 0xdfb43e84, 0x38d85313, 0x06186ef4, 0x16412528, + 0x1475d0f1, 0xaf5486f8, 0xb57ee75e, 0xc4948b8b, 0xf2b794b3, 0xb9fea5f7, 0x51d9298b, 0xf37251db, 0xfb734281, + 0x3796f089, 0x752548fb, 0xe4c19cd3, 0xcc273700, 0xaa175f6a, 0xad3e8f5b, 0x029d6d14, 0x02ee5237, 0xc15c59fe, + 0x72f15fc3, 0x6e6aac5c, 0xae1cb4ac, 0x156c7efe, 0xa985c324, 0xac85ca77, 0x6cde671f, 0x50542992, 0xc935669c, + 0xda60ed94, 0x1dc67b40, 0xed338151, 0x5187c66c, 0x72db202c, 0x59d50489, 0x67d63044, 0xe66f7bc7, 0x169bda51, + 0x433176e1, 0x201a97aa, 0xfe86021d, 0x6155f8d2, 0xe285b596, 0xb17eda99, 0x0137ee67, 0x50b6cad9, 0x1b222f65, + 0x0810ff82, 0x557bef78, 0x9ed94e20, 0x22c204b5, 0x76d8297e, 0x1edc8b9d, 0x08263435, 0x79e4c147, 0x0aee6eee, + 0x3aa93bea, 0x789eac9b, 0xf07dc554, 0x9a8a6408, 0xf6634aa2, 0x7d073532, 0xbbe825f4, 0x89677c26, 0x55b06789, + 0xf00f48f9, 0xc8ade1b4, 0x8deaf5a7, 0x8787c5b8, 0xbaf2f2e9, 0xd79b0f22, 0xd9f07228, 0xb363a069, 0x148172e2, + 0x7d3c685a, 0xe591bab9, 0x2a1c2f99, 0x81ed3844, 0x831d0cb4, 0xd04337c5, 0x11652cc6, 0x588f2763, 0xf3415c2b, + 0xeeab0f23, 0x576a2aff, 0xb3190016, 0x8f63d298, 0x05f936e7, 0x37b20404, 0x49eb748c, 0xba75207b, 0x31e12e9c, + 0xa68df773, 0xd37addb7, 0x6d0cd9f4, 0x3df9ddb1, 0x89793686, 0xb8c5a389, 0x317cd6a4, 0x463c82fd, 0x4e280565, + 0x8ca2b47a, 0x202407d2, 0x35452486, 0xb205d7bd, 0xa8866b27, 0x4054175b, 0x2ee133e8, 0xbe9df70e, 0x5e623200, + 0x3a2934fa, 0x4cffdef9, 0xf36b9982, 0x0086f09d, 0x12a57783, 0x95e3250b, 0x30370fa9, 0x7fe117ba, 0xb330c364, + 0x012437e0, 0xc3c31c45, 0xeb6f5b03, 0x41c84201, 0xcfef9133, 0x0212b6e6, 0xb0185340, 0xdae2507c, 0x5c0bce2c, + 0x3d933e34, 0x6490539c, 0x04719cdb, 0xdd469430, 0x6600510f, 0x330b67a8, 0xb69f8307, 0xfd45bbed, 0x3406b685, + 0x651ecb40, 0xd09120a0, 0x323543ab, 0x0e6da20b, 0xbaafc945, 0x76f2f526, 0xc7cea40c, 0xcabbb727, 0x745df9c5, + 0x5d2e3833, 0xed697d80, 0x94f8b009, 0x5fb08f70, 0xe9a920d7, 0xf0ebd5cf, 0xacf9db85, 0xb6d5ea5e, 0xa9bd2338, + 0xff6eedf5, 0xb8faf58a, 0x04aa660a, 0x4d323268, 0x62bd66be, 0x5e13c950, 0xf29cec81, 0x78f43869, 0x797fd2ab, + 0x925f1d11, 0xbb47bc49, 0x40241888, 0xb6ec586c, 0x665c8e07, 0x0d140371, 0x9892078d, 0xb63113d6, 0x41f64607, + 0x8992fd6d, 0x88df7038, 0x48a32cbf, 0x9f5a1445, 0x2b96ee06, 0x0774eb34, 0x66e72050, 0x14996796, 0x6f9d41a4, + 0xecb77f3d, 0x91792dec, 0x76803b2f, 0xa5b36a2c, 0xd22e2525, 0x09d9631e, 0x1edbad4d, 0x4ff1ca20, 0xec982117, + 0x47f47fd7, 0x60407369, 0x17ffbc15, 0xb2d1e23f, 0x5cc24a1a, 0x2ce735f2, 0x82e2cda4, 0x3f5fc130, 0x60ae06fd, + 0x7fc95682, 0x961afff5, 0xd4789ae5, 0x120df1c0, 0x752f1709, 0x5a0fab94, 0x096e0928, 0x60f3639f, 0xc7a09199, + 0xbae8ac87, 0xfbf108d2, 0xee58e10f, 0x43950f69, 0x6f691501, 0xe97eee83, 0xa8443759, 0xcc93ad1c, 0x031d6ced, + 0x1e57f69f, 0xe69b2d69, 0x0c5fae88, 0x0722af5d, 0x9177d889, 0x66cf2c2e, 0x7fe47b51, 0x54e94011, 0x0f428ad5, + 0xa4d69c13, 0x0d11eb0c, 0x8aff2477, 0x8c6ea1c5, 0x3368b9bf, 0xd868536d, 0x9161a79c, 0x10275a2d, 0xbc41757a, + 0x4f625504, 0x8ab75360, 0xbb97b725, 0xa088d365, 0xd2a3a01d, 0x21ca4d58, 0x97e6278f, 0x16d08233, 0x4ba419bd, + 0xf75a22c1, 0x59bd7760, 0xbdae1083, 0xa74d0191, 0x4af54d06, 0x856a35b2, 0xceff3385, 0xdb7a10c2, 0xdf239294, + 0x77c2ce02, 0x46c48cd9, 0x3bef1a7b, 0x3e7d181e, 0x532929d9, 0x17b3b7c9, 0x5f62a091, 0x29684484, 0x49d64a0f, + 0x617a1a19, 0x3d2df573, 0x7f314a8a, 0x8e6172e1, 0x5eb923eb, 0xbb52028f, 0xbde08382, 0x3a23c16d, 0x735406f2, + 0x47e7f5c8, 0x831c1c40, 0x732c83a0, 0xc02abbb7, 0x5fe7baa2, 0xeece020e, 0x73587d88, 0x15e7a17a, 0x7dd75338, + 0xe22a7eaf, 0x05d9b879, 0xf0cc8606, 0xa608756f, 0xed1d54ee, 0xb55d0928, 0x3c27ea72, 0x2fcfbd17, 0xa303a4cb, + 0x0b8883c2, 0x80d691b6, 0x508b0a80, 0x546a09be, 0x80c74f23, 0x65b0d4d5, 0x7dcf111e, 0x99b8c43a, 0xe487e54f, + 0xef5983b8, 0x73bd3bd4, 0xb20c01e0, 0xee94120a, 0x14aac48d, 0x61ee87ab, 0x349feda9, 0x0b29a849, 0x2468f7a0, + 0x1b225cac, 0x8f5b7a73, 0x78afaef8, 0x9240c4cb, 0xda946a66, 0x78614249, 0xb31a538c, 0x848f2018, 0x32105f3b, + 0x4a7c3378, 0x707d25e4, 0xd4192270, 0xe05a4813, 0xcd2517b2, 0x522af42d, 0xf37d4138, 0xc7549782, 0x6fea4f32, + 0xde9f981f, 0xb1d89a6a, 0x8304567a, 0x94856b0c, 0xda4d8c52, 0xd8be4d0f, 0x2445aa30, 0xd8ba57cb, 0x4807c99e, + 0x6a2f5491, 0xdc77607b, 0x970175f3, 0xc37499a1, 0x018e584a, 0xed79c95b, 0x13c9dedb, 0xe2e72eaf, 0xa571d04d, + 0x1dd1ce92, 0xd8b898ae, 0x80db8d46, 0xba2e00f1, 0x6721a075, 0xdd463249, 0x1954cdf8, 0x152a8d70, 0x9ecc45de, + 0x8bf5de0d, 0x7243de61, 0xc4f2e266, 0x80537b4f, 0x04f24c7c, 0xb07b9c11, 0x47b31466, 0x196fce2e, 0x9ffce3fb, + 0x3ee419f5, 0x71bdf1f6, 0x379db466, 0x9584ab94, 0xa3387fe0, 0x9f2e9eb8, 0xc5ec2c39, 0x38e5a141, 0x2da14af3, + 0xb9f4b7f8, 0xc4c8a66c, 0x234727c9, 0xbc83f8ab, 0xfc1f7a3a, 0x8b670684, 0xcd293608, 0xf0abd928, 0x64657e93, + 0x07fe24b3, 0xe08c8117, 0x1ae0b993, 0xcf5d10f7, 0x17199a32, 0x6723e7dc, 0x701bc72d, 0x23f1944b, 0xc5c47c3a, + 0xbd6e6a58, 0xd2e935e0, 0x38a69425, 0xa5f1b956, 0x15fa870c, 0x0d7be43d, 0x19edfbd3, 0x5120b6a9, 0xcd18378d, + 0xc4308384, 0xb6629820, 0x1e70df9d, 0x4018c64c, 0xb1043ed3, 0xc632c4c3, 0x758710b1, 0x97bf4835, 0xd2fc5d7b, + 0xfc54f506, 0xa0ea3f6c, 0x8037bfde, 0xebd9276c, 0xc7a5f5a5, 0x3b5e1baf, 0xe60541e8, 0xe551e77a, 0x0f6a5b28, + 0x08802dbc, 0x12e5217d, 0x33175a18, 0xf170320b, 0x1ce83cac, 0x9139a303, 0x228847e3, 0x29d6a037, 0x27cfd180, + 0xb03adc53, 0x304c521a, 0x40b668d0, 0x5f1d21a9, 0xe8eaa959, 0xa99b581d, 0x7f7d6501, 0x81532e54, 0x53c805f0, + 0x09fae09d, 0x18b4ee17, 0x0632d8b5, 0x96248930, 0xe77b0c23, 0xe2bb5e4c, 0x0e33c34f, 0x984df1dc, 0x146289b4, + 0xa5b1e652, 0x04106c1b, 0x12db2da6, 0x7d42dd40, 0x9d2c2795, 0x403ed38a, 0xdcc4f7ac, 0xa04f1397, 0xfb64737f, + 0x27583963, 0x00427b6b, 0xb65d1028, 0xb98b0c06, 0x98999cb1, 0xa57b5b91, 0x727b0372, 0xca1d29b9, 0x9ae72587, + 0x7800d4d4, 0x35bb4684, 0x23ad45c7, 0xee8d4709, 0x03f556a5, 0x439a3a92, 0xf4c60181, 0xf2916d81, 0xf66469f8, + 0x4623b7a4, 0x7d8bb80c, 0xa1468d6f, 0x1e416a7e, 0x57ea82f8, 0xe0744768, 0x368fc4db, 0x7033b43c, 0x57c1fa77, + 0x9e91701e, 0xc78a6381, 0x23f395d7, 0x11d0d02e, 0x596c3f88, 0x6529cb3d, 0x65a89770, 0x028d8f16, 0x885c09a0, + 0x7a977e6e, 0xbd8ef62f, 0x9bd27782, 0x3bd11eb4, 0xd9af3c37, 0x9f46e5eb, 0x57b54226, 0xc2cd97b6, 0xa6f7a1e1, + 0x2460143a, 0x70ab201d, 0x7d5c5be0, 0x57425f14, 0x82ff5c8b, 0x06ca0289, 0xfcda589d, 0xde063abe, 0x259abf9c, + 0x0ec21372, 0xb50f2e8e, 0xdae2b179, 0x14f82014, 0x9eb90d12, 0xb770d410, 0xa4318e52, 0x20a44db8, 0xef2b2bdc, + 0x72655b9b, 0x97303d4b, 0x8bd04fd6, 0x542755d7, 0xa36ce0e3, 0x24dd6d34, 0x4e9eafb5, 0xf50d0be1, 0xc17497c1, + 0x345a5e74, 0x9ff59f12, 0x49bd29a0, 0xdf5235ed, 0x5e4b89a0, 0x1c8e82ec, 0xa0b29a84, 0x4af44cf5, 0x13176415, + 0x094b754b, 0xdfd6354b, 0x11cffd01, 0x54fcb4f9, 0xba95f751, 0x83cf3f91, 0xd052b0f7, 0xbb9d49dc, 0x3642c536, + 0x42bd5c41, 0x0018f4b3, 0x8d11d90c, 0x76aa8391, 0x6e52f26f, 0xd458ddd1, 0x86e54df8, 0x44272308, 0xe4a4c16a, + 0x04eda051, 0x663221f8, 0x4971612b, 0xc7313d78, 0x98c46b3c, 0x5066691a, 0x80c359d7, 0x2bc154d3, 0x2dd9506f, + 0xd105e930, 0xec918046, 0x4db52b80, 0x11b99857, 0x658705fd, 0x23a3c35d, 0x00e0c74d, 0x39113e5a, 0x60c30b05, + 0xd7bffb69, 0x6897033d, 0xec22df78, 0x4eb172ca, 0x0623d6a2, 0xa9cfdd07, 0x4701da47, 0x87871f45, 0x70ce0770, + 0x396ac597, 0xa7c7e0ad, 0xd1c5f760, 0xbcec3e6c, 0x1945cb32, 0x501feba9, 0x72b5c56c, 0xfb121aa6, 0xf47855ad, + 0xad769c4f, 0x617ce02d, 0xcd043fe7, 0x6a58e942, 0x536c729e, 0x5365dce4, 0x4711b7da, 0xa1b57861, 0xa4afd24b, + 0x7c5f67e8, 0x1174528b, 0x575a032d, 0xd6f35b49, 0x76feaa51, 0xd734f898, 0x6fd208b7, 0x93cf1457, 0x840a41a1, + 0xb4d63373, 0x3314b094, 0x2eb8ddff, 0x574e12f6, 0x396e2a82, 0x29246a48, 0xdd318e4a, 0xcffb2feb, 0x0af03eb4, + 0xcfa48d63, 0x1a6631ff, 0xeab49188, 0xab3f55f6, 0x9811eae8, 0xf67b0e30, 0x778ec898, 0x4c66f9ce, 0x5fbff70b, + 0xed415abf, 0x19cf1f36, 0xe2031015, 0xeb873014, 0xf831b2bf, 0xf6d15fd3, 0x83164daa, 0xbd148126, 0xd007c8fe, + 0x31b9c249, 0x887edfc2, 0xc85bcfbc, 0xf86f90e1, 0xccf3a90a, 0x4ce2fb98, 0x907cd168, 0xe8b604e7, 0xc1e5403a, + 0x82ab4013, 0x25578b18, 0x13c077b1, 0x74eee3e0, 0x4cc26315, 0xbf5fc5b7, 0xb3d1279f, 0x56cecb78, 0x165b99be, + 0x3f3f7be2, 0x80d694e4, 0x422df993, 0x6e139733, 0x38aa0b79, 0x411d9fb4, 0x49e5311a, 0x0f677e95, 0x161a2baa, + 0x782c3548, 0x181012c8, 0x7af8bbc1, 0x59a3a16c, 0xfbdb36d5, 0x9d275a3c, 0xaf8369d6, 0xf3f7fcee, 0xc37d76e6, + 0x877cc4a5, 0x09f3b955, 0x1c2b6fb5, 0xcd51e06f, 0x5c346d63, 0xaeeb8ebd, 0xced67872, 0xcb9e3087, 0x165fe492, + 0x59e4c6e4, 0xc8a10797, 0x12de8d89, 0x71bb36c4, 0xe063771a, 0x4129c31c, 0xe098c716, 0x1101607c, 0x1d6f9628, + 0xae306db5, 0x510c1d32, 0xefda3688, 0x63bb148b, 0xfea280c5, 0xa9648deb, 0xa33523a0, 0x20c80d44, 0xfc1c5648, + 0x81fefae5, 0x9e9d3a91, 0xa0ecccb1, 0xcdf8acb6, 0xbd285be0, 0xfc0a4df4, 0x4f7150d3, 0x5b7d9290, 0x6bdb134b, + 0x753fb62a, 0xc04b5caf, 0x1086ea82, 0xe7c5b541, 0x6d032ffb, 0x4d4b6a2f, 0xe08ed7eb, 0xfb78e261, 0x3bd70fea, + 0x368a7a25, 0x8c560bc9, 0xb039ccea, 0x24f1ed01, 0x79275c97, 0x35cd5798, 0x98f453cc, 0xfd3a935b, 0xb415c33f, + 0x8fbe41dc, 0x16e4ba37, 0x1f0ff34f, 0x66be2508, 0xa2c03568, 0x190dde71, 0xa53efe38, 0xb7e83b9a, 0xb1b9c87d, + 0x99baf5e6, 0xdfaf4c7a, 0xbe2d246e, 0x2b65ba24, 0xea7d920a, 0x4cadb403, 0x433b30f0, 0x18a68250, 0xab2886fe, + 0x680edecd, 0x3b7eac7a, 0xeb898913, 0xaabe71de, 0xa2e31bdf, 0x453765d5, 0xf2f26b46, 0xd96beeea, 0xda3c8347, + 0xebabbd98, 0x9549fc64, 0x32753e60, 0xb02658e8, 0xa48ff5eb, 0xd2ff9893, 0x90f92144, 0xf2a90b38, 0x2a530357, + 0x214d08b1, 0x28b979fd, 0xb7d53c89, 0x915faafe, 0xdf1ff567, 0x1f325444, 0x3433c470, 0xc7df1fea, 0x457e7d4c, + 0x7476cbcc, 0xd76eeb68, 0x482809f9, 0xe8f1e5f9, 0xed09ef71, 0x0dfef910, 0xf2dc05b1, 0x54f515da, 0x8427718f, + 0x73306d26, 0xa329a6a8, 0x4a13f11f, 0x9d4e1486, 0x3635c4e2, 0x3269ec87, 0xa722b376, 0xcea40ee3, 0x7f22b615, + 0xda32977c, 0x7df19cbb, 0xd4ffcb98, 0x60e4df70, 0x865b30f3, 0x7e719152, 0x67400562, 0xb0a0f3b4, 0x0c4434a3, + 0x37618e76, 0x7ce5a61b, 0x021a3160, 0x3369ea2a, 0x5584449e, 0x26f8f52b, 0x7b4512c0, 0x4b724838, 0xec2531ed, + 0x33811913, 0xd6111795, 0xe4fa4075, 0xea9bcafe, 0x68ffe8fd, 0xeb339e83, 0xb68d5d6f, 0x2797e439, 0x771b3685, + 0xeb2f80cd, 0x106780a3, 0x770415a9, 0xa4543ec3, 0x736f903b, 0x640a06ff, 0x698db54c, 0xab885d65, 0xed4df3ea, + 0xfb300e7a, 0xa0225af4, 0xe5bad227, 0x658f68e8, 0xb0219c76, 0x22d6fdac, 0x5f4d179e, 0x79e2cb31, 0x964c367e, + 0x4a5d9a38, 0x9f3572df, 0x56ac8aca, 0x39d1ffed, 0x15c51f91, 0x9c147789, 0xdc01de39, 0xe4cd13c3, 0x635fe1cc, + 0x0ec15eec, 0x474531c0, 0x49dbed7f, 0x84abe26e, 0x58826ccb, 0xb9f1409a, 0x87e943bb, 0x10b903b6, 0x74de1bd2, + 0x5fcee584, 0x3b172465, 0xd945d83d, 0xd6604a3b, 0x3a85ed69, 0x2dcbe556, 0x5479535b, 0x70af28f9, 0x2dc2fbe8, + 0xc35870e6, 0x850cddd5, 0x1621d9c3, 0xa6a27b10, 0xc84b56c3, 0x82dc6eef, 0xdffae4c4, 0x2f301a47, 0xb44dbe29, + 0xacab8fa9, 0x9891e2f5, 0x2fe071f3, 0xb5f28fa7, 0x6161ebb8, 0xc2a6a0f9, 0x648787f5, 0x359bf1f5, 0xca73016f, + 0x7e296619, 0x1c9cb4df, 0x7b92a799, 0x9e26271d, 0x509be01b, 0x77d4685c, 0x994ecb03, 0xfe721384, 0x4b202551, + 0x0b5c54ea, 0x3ceea66b, 0xf122c58e, 0x04ce1535, 0x6fbf0b1c, 0x5c7a923d, 0xb2f7c709, 0x886aee08, 0x6f4c386a, + 0xa0c55be9, 0xdccee137, 0xde99557b, 0xca2a2e06, 0x4c9fb378, 0xa7e423ab, 0x91aed86d, 0x2222c558, 0xba70fb88, + 0x2490793f, 0x7763db78, 0xda56c753, 0xf1f82cf1, 0xd3815298, 0xeaa44eae, 0x3992c3e4, 0xf2e80410, 0x185a3fe0, + 0x6a42a979, 0x6f80b0bc, 0x6cea1c1a, 0xbd9c0e68, 0x300c42ac, 0x4c3ebdc5, 0xd9f65061, 0x94c1a052, 0x9ea32f85, + 0x12e53678, 0x502c3b09, 0xe67e42a5, 0xadb2b24f, 0x3190cbc6, 0xecf2729c, 0x693a985c, 0xd16b9682, 0x348e88ff, + 0xff011aa3, 0x28008464, 0xc3edfbe6, 0xfd379fd7, 0x81ca36d0, 0xe4cf5c72, 0x16d3dc24, 0xda7e8a4d, 0x3ae628ea, + 0x677e156e, 0xd7991f9f, 0x03a2448f, 0x497c554a, 0xdaa08ae5, 0x59bec612, 0xa859f548, 0xec5c235c, 0x2f189597, + 0x787cf5c6, 0xf2196154, 0x22263134, 0x89ac8bd4, 0x1f2cf5ab, 0x7f3189ca, 0xde6a20cb, 0x59024dcb, 0x0b0c0b84, + 0x793c8f52, 0x471d3e97, 0x6f2b9f63, 0x1c6d1260, 0xcecf0a7c, 0x511920c1, 0x9c5a02b0, 0x37e7f378, 0x8df9678c, + 0xb466dc28, 0xe5e52a00, 0xbd930cdb, 0x178150e2, 0x49a065fd, 0xb2d634e4, 0x30b2d524, 0x4f59038e, 0xda470e89, + 0x17f8790c, 0x2ad4123d, 0x80ec947e, 0xf529bffd, 0xaa8ab25a, 0x14ab085d, 0x297236c0, 0x676c5008, 0x2b8ad6c5, + 0x50f54dd3, 0x5a4156e9, 0xc4bfac11, 0x5e3aa7cf, 0x63920144, 0xc7ee3d62, 0x6a89e707, 0x0f268be1, 0x95b89d85, + 0xeecada70, 0x84715568, 0xfbfb26c4, 0xac8e17be, 0x34e3e416, 0x68bb1f0c, 0xbec47391, 0x2654fbff, 0x85313915, + 0xc09854cf, 0x25e8cf7f, 0x67f40b9a, 0xb73602c4, 0xa29964f7, 0x15502a47, 0x4b781cde, 0xf6cb47de, 0x97c5a971, + 0xe3c9d095, 0xd24030c2, 0xbc2a709a, 0x5ec81862, 0xece1dcf8, 0x2992a5bb, 0x726fe4ca, 0x638b78c6, 0x4ba8a683, + 0x50275313, 0x65a4fec4, 0x13520e94, 0x41b914eb, 0x484df8b2, 0x2c69b236, 0xb44cd489, 0x0e3968eb, 0x98051651, + 0xe969f44f, 0xc062eb78, 0x39fc1fdb, 0xc2bde937, 0x9b878d90, 0x5eb17d70, 0x2bf4015f, 0x83b8144a, 0x429ef77b, + 0xedc00bed, 0xc8b18985, 0x00cefe5c, 0xbd298455, 0xfd4656e4, 0x7425c5e2, 0x2785a3e7, 0x389878e5, 0xa16be2d8, + 0x7bc67cea, 0x02be53ee, 0x2d8107ba, 0x7b1fea21, 0x5902ad3c, 0x23e2a489, 0xea1b4f14, 0xabef77a0, 0xd2e3aff3, + 0x972fde13, 0x7f501c4e, 0xec8c2f79, 0xcf9db784, 0x7a00994d, 0x911fe152, 0x04d0d384, 0xfdeb2a2d, 0x807a526c, + 0xc2679af2, 0xe9e029b3, 0x8ac6e0e4, 0xdef7729c, 0x6bcd251a, 0x5d473e44, 0xeacb92db, 0xf2d2a6a9, 0xc06f1cf1, + 0x13e4728c, 0x590361ff, 0x212860a1, 0xdcc4d6af, 0x67cbbe04, 0x61d95bd2, 0xa852fab4, 0x6239a075, 0xa1d7b647, + 0xe702be56, 0x080e22e1, 0x4d51b768, 0x9bf7f07a, 0xc56b7b3e, 0x6c62a4a8, 0xba94e793, 0x388660b5, 0x509a7bf0, + 0x5420a903, 0x346e9e14, 0x28350b32, 0xdb0d61d3, 0x14845b2a, 0x24e3ea51, 0xc16bc91a, 0x90626571, 0x811c9389, + 0x9044732f, 0xe9217974, 0xf15826cd, 0x38b23089, 0x991b077f, 0x183ec9f0, 0xb2b3abab, 0x2609a072, 0xd2d30962, + 0xdcfa309a, 0xf7b40ca9, 0x297d26d7, 0x68e3ab20, 0xcef55aa2, 0x72fb58cb, 0x5358937c, 0x4a0e1c92, 0x1bbdc6e5, + 0x1e91abbe, 0x34d612c0, 0x5c68aa4c, 0xb5b24e25, 0xcb885e84, 0x6a643eb5, 0x41ff8706, 0xd02aa364, 0xd5f645a1, + 0x6e0d36e2, 0xd4be12ea, 0xd182f5d0, 0x5fc4ad44, 0x771ad3b3, 0xf231bac2, 0x65576aaf, 0x4cd19c54, 0x0128d258, + 0xec1d7ee1, 0x48881f9e, 0x2f15a48b, 0x569103bb, 0x634b0c7c, 0x79b6a16b, 0x70a443e1, 0xf410b74e, 0xd348c3b2, + 0xe7ed1d3b, 0xa79643f3, 0x0c58c47b, 0x62586cd3, 0xcd8ec05d, 0x826a803b, 0xbbdd4594, 0x5899c944, 0x36fc0d57, + 0x80fbe6af, 0xd6d8b317, 0xc1fa1be1, 0x5c078129, 0xeab6472a, 0x41e8d380, 0xcbb4ba26, 0xa1c7fd34, 0x619cca96, + 0xe7fb6d53, 0x08f1a944, 0x85369332, 0x7f88d024, 0xaab92fad, 0x418f0694, 0xcd1f58b0, 0x43d67aa2, 0xf4cc0df9, + 0xd746a828, 0x59aafdca, 0xe099826f, 0xf4e8667d, 0xea5d1576, 0xad7db801, 0x6201cb46, 0x143b030a, 0xe7b14f8c, + 0xbe62fb4f, 0x0de0f6ab, 0xb8a6dad9, 0xf651e513, 0xe0f95d9b, 0xe00ab527, 0x41c5054c, 0x268ec183, 0xce896051, + 0x462dec91, 0xbefdd081, 0x4fdd71ae, 0x25a18c81, 0x9b4b0352, 0x633ba070, 0x62f5532d, 0xe673e55e, 0xc7a49f06, + 0xde140f69, 0x7b87121d, 0x26a56423, 0x56856882, 0x21820ce3, 0x25a9d7f1, 0xfa4bd225, 0xad7a0830, 0x92650aeb, + 0xc9a2b254, 0x78273fbb, 0x83e2c610, 0x69288063, 0xed78c0c9, 0x9e9ccdfd, 0x7f741734, 0xa9ddbb8f, 0xf3725b0d, + 0x48fce240, 0x3095efc3, 0xf3582c5c, 0xd2f389ee, 0x54003b5a, 0x2d511683, 0x2a8b5f42, 0xa9920913, 0xc17f6c96, + 0x6e5a590b, 0xfdac7aaf, 0x1f0dd0c0, 0xe4d16676, 0x27199e21, 0xb5b0f736, 0x2a10778d, 0xf87a56bd, 0x2613d028, + 0x5419a63d, 0xd5d80dbd, 0xc46d908c, 0xea5da3a9, 0x99ccbe7a, 0xb734043f, 0x1a5c00dd, 0x07030426, 0x0022ff74, + 0x8b82369f, 0x824d39d6, 0x23a8d675, 0xde372896, 0x345e4e60, 0xae4551da, 0x3d5af0e0, 0xcc918181, 0xa429d48a, + 0x4e13b913, 0xae0a3798, 0x4cdf581c, 0x2827df7f, 0xec15d41d, 0x70aadbc9, 0x4bae49b6, 0x6e5e5267, 0x03b71afd, + 0x5b7f32f1, 0xfe7813fd, 0x254cb67a, 0x9f501f37, 0x81e6efc2, 0xa0a9803b, 0xdce0058d, 0x22809f24, 0xb0117b3d, + 0x47053800, 0x81c4e81c, 0x5c53cc96, 0x5ade6ae6, 0xcd533dae, 0x60eb8314, 0xda42fb9e, 0x2dabfca1, 0x1d78f204, + 0x880f04a6, 0x78075e45, 0x13e0e2f9, 0xef24ac5c, 0x6b7142a4, 0x532e1d5e, 0x681c007a, 0x74fd1bc9, 0xa6c88e3f, + 0x5b9b9d06, 0x1ba284a0, 0xb00d2a60, 0x885e1e46, 0xc1b5c80e, 0xa8a46a2a, 0xae38c6c2, 0x210142d6, 0x3736f4dd, + 0x902af423, 0xda0a9d15, 0x6aded27c, 0x3157ee8f, 0x44c7ece1, 0x76ca8437, 0xec354911, 0x388166a5, 0x73398c43, + 0xae42689b, 0x3a25ce8b, 0x6c143479, 0x2d34f735, 0x871617e7, 0x525e3f46, 0x687aae91, 0xd46ad246, 0x9f8ebf69, + 0x5a385502, 0xcacefaac, 0x22b0a1f3, 0x2754455b, 0x0cf72e15, 0x21719df5, 0x79236d1f, 0x685448a3, 0x447ed8d8, + 0x6266afeb, 0x2d29546d, 0x1dddddfd, 0xea5e4bae, 0x898753d8, 0xa40b986c, 0xe9db8120, 0xb5dd016f, 0xb17c1894, + 0xe8602110, 0x10ac7a5f, 0xc1dce01d, 0x02e65f01, 0xfc09b12f, 0x4400fa06, 0x1bfb844a, 0x75cfccf6, 0x586ab4d9, + 0xccb3ef14, 0x56b735f7, 0x4dd9b1e2, 0xc6274403, 0x5a2664ac, 0x8525662a, 0xd4e4fd8b, 0x7ae79d6e, 0xe656faf5, + 0x809f4d05, 0x3c5f7172, 0x4d08b32e, 0x2e0e4efb, 0x1e6cd34c, 0xf61135b1, 0x444ef3b7, 0x3fd6cfb1, 0xa5ea627e, + 0x62dd07e9, 0x92df8ee9, 0xdda27be4, 0xcdba9238, 0xddcc9e06, 0x9b88a39a, 0x2018de6e, 0xef6a79a8, 0x1e72e3f0, + 0x3f7115de, 0xf1f6ca39, 0x0a5435f4, 0x81b02ffb, 0xdec4b52f, 0x02d03454, 0xc72fc004, 0xe7eba77a, 0xbe9eedf8, + 0xa1a1c9fe, 0xf36e27f6, 0xcaff17dc, 0x4dad1784, 0x9457619e, 0x5ca307d0, 0x5d6ba6ea, 0x7dc2959b, 0x35ddfc26, + 0x7308824c, 0xd0aa21f8, 0x76e6222f, 0x899876df, 0xe75e5476, 0xe0f98ef9, 0x0aa51b6a, 0x24299de8, 0xc62c41cd, + 0xa955de7e, 0xeb5e01b7, 0x28726c76, 0x2cef7022, 0xaf33a6c1, 0xd5cb7cdc, 0x021f7662, 0xc2ebb333, 0x729f9040, + 0x5ac4e550, 0xa3338127, 0x17098a08, 0x8ff9fa84, 0x2fa8b684, 0x74ae815d, 0x34af0e39, 0x404e2a0e, 0xedbabc55, + 0x25084973, 0xf964ad6c, 0x161b9e26, 0xecfd86d8, 0xae2261e0, 0xe0074663, 0x3d0caf36, 0x36a2a588, 0x4d86d203, + 0x6525c956, 0xdc0584bb, 0x08aada08, 0x8c9aed7b, 0xff6187af, 0x8aa6a227, 0xf3f63941, 0x4f6d863f, 0x37df2bc1, + 0x91d5ca96, 0x3a8a172f, 0x98ba045b, 0x21f6f915, 0x4709643c, 0x20032a67, 0x5467d5e4, 0xc7040af3, 0xf57a1477, + 0x50399542, 0x4bde5c18, 0x8b95e90e, 0x3d739b04, 0x38ab903d, 0x48ddf16c, 0xb347d213, 0x264510f3, 0xdffc2756, + 0x1c36924c, 0x70676a64, 0x9079c487, 0xc62f4816, 0x0150ae5f, 0xd6c537ca, 0x26cd2a96, 0x02f50df3, 0x1570e171, + 0x5526af78, 0x22144b09, 0x162424d3, 0x1df5c47d, 0x788b68c1, 0xe15e966c, 0x84c88130, 0x88bffc72, 0xe79f41c9, + 0x21c385b2, 0x8cdb72d6, 0xa5935ebf, 0xd2749ebe, 0x05f3ffe5, 0xfb55f69d, 0x3362581f, 0x09016b18, 0x20b5b083, + 0xb16adf0d, 0xdfd46087, 0x4073023f, 0x80bbdc38, 0xc35474ec, 0x0abb4095, 0x53467f4d, 0x9d4d30ee, 0x84b4ddd3, + 0x6dc8c4e3, 0xff4aa8f6, 0x6f999404, 0x644d7e85, 0xd5dea46c, 0xb6e96c7b, 0x2a19d4fa, 0x34dac1e0, 0xa4a0b534, + 0x101f7e45, 0x82ac1032, 0x989b22c3, 0x46baaf5e, 0x4d55041b, 0xfd9bba3f, 0xf9d360ea, 0x090b3cfd, 0xebf39540, + 0xe4bda70e, 0xc2408c72, 0xc07c79cd, 0x2ce533a4, 0x487a37ae, 0x6bfa067f, 0xff4da59b, 0xffaee2e6, 0x3cb40218, + 0xadd19bf8, 0xf181df2b, 0xc7c036d7, 0xc56e46e0, 0x01a923a7, 0xe2c5977b, 0x78bacac0, 0xfd07b750, 0x2b18cba5, + 0x26c51504, 0xb21c656a, 0xf3015169, 0xcb77f39c, 0x1fef1d55, 0xfcd4b85d, 0x09a7b26c, 0x7992e41b, 0xa78a5c11, + 0x910ff301, 0x3e2e22db, 0xc1278f01, 0x73af632c, 0x55482716, 0xe047f8b7, 0x72ddba6e, 0x5b5a9ed6, 0x12e46cd5, + 0x341273fa, 0x25753c27, 0xf2c34981, 0x433e574f, 0x55122f75, 0xb2bc0820, 0x386da179, 0xcf26201f, 0x3c22ee39, + 0xb85dc13b, 0xe6791251, 0x52f8b599, 0x89332d80, 0x7c943c80, 0xf53f971d, 0x159007d4, 0x43ef97da, 0x183bbb3b, + 0x45beda69, 0x8c7c189e, 0xf7ee3155, 0x8224a869, 0x2bd68f57, 0x84371b55, 0xbc3e40d5, 0x5916f594, 0x99d71d61, + 0x303cc2e9, 0xb5b9801c, 0x6aff7bf9, 0x491168b8, 0xbe90c963, 0xa85a6dfa, 0xb3726efd, 0x007433f6, 0x0dd33f04, + 0x3b068e7e, 0x44856e41, 0xb255e9c6, 0x4825b514, 0xf57dba35, 0xf8fa9bd5, 0x4a2cb08d, 0x18f4b479, 0x9730b502, + 0x0db69fc1, 0xe3463241, 0x6675e1e0, 0xe35ce645, 0xd680a16f, 0x7b424476, 0xa2631a48, 0x1117b22c, 0x04fec3b1, + 0x0bcce80c, 0x4996d224, 0xdaef69f3, 0x3eec9770, 0xda58c348, 0x24578931, 0xec121542, 0x21c1b4b5, 0xca6ac4ca, + 0x1c1af43b, 0x2c0c71cb, 0x4632ab5b, 0x6462dd68, 0xbf5d69eb, 0x211b3780, 0x8c2932ac, 0x11478d49, 0x31664fbf, + 0x4f772313, 0xdb1a5127, 0x85d63c5d, 0x64a7e2d2, 0xd8e24933, 0x794126f6, 0x9b1a7b52, 0x31e02f4a, 0xe88e71b0, + 0x52f5ceff, 0xd321fa31, 0x967e9363, 0x40b3940e, 0xa6d4f639, 0xff509fbb, 0x3941f3f0, 0x30ca367d, 0xdd492e9c, + 0xd4435199, 0xe29179bb, 0xa420bd44, 0xee90bfd7, 0x76340505, 0x141afe74, 0x1c9228b9, 0xe282b8b7, 0x79fc7220, + 0xc6da80da, 0x243980ae, 0x44017c1b, 0xdcfa9ecf, 0x2d767630, 0x9b9b03cf, 0x9995760f, 0xb410a5f5, 0x3ed2566f, + 0x3a3943f0, 0x5a86394c, 0x40f07f3f, 0xf732fa14, 0x2cffcabe, 0x7a039e0e, 0xe901c08d, 0xc0284080, 0xdcf41716, + 0xe90810e8, 0x0760c29f, 0xcea01550, 0x2894200f, 0x0ae2a0b5, 0x5db96a5a, 0x2f688cdb, 0x37e7f6ca, 0x9f809c93, + 0xb7270beb, 0x764b7501, 0x9f9de9af, 0xf624bff9, 0xc4f969c5, 0xd773ce48, 0x67f287da, 0xa2738b5d, 0x9989439b, + 0x8a0e705d, 0xbb50ef15, 0xb2b57b3f, 0x486e1b0f, 0x8c7f64b5, 0x0bff8c9e, 0x3f20a656, 0x0bc3c6c9, 0x91b13a17, + 0xbff6cad4, 0x92f3ab96, 0x166016b1, 0x771474e4, 0x0a8cd4af, 0xa2ccf3ed, 0xbf64b684, 0xc2142e8d, 0x6c50d653, + 0xa564bd43, 0xe29906b2, 0xb6448f34, 0x92c3226f, 0xd7b282de, 0x70ef7855, 0xa98b80b9, 0x2fcd7f61, 0xce068f7f, + 0x2bdf135d, 0x1f57b249, 0x62f5ff42, 0x660fd538, 0x3d88863a, 0x0c2f6fa7, 0x70895d31, 0x0d5df47b, 0x3f527394, + 0x31f6c347, 0x070443f2, 0xb23b3a21, 0x6793739c, 0xfd9ef6ae, 0xd6795aea, 0xfbef37e2, 0x6f5efde3, 0x252a6c1b, + 0x1bd9de28, 0x4330fbd5, 0x3574160c, 0xd3476d41, 0xf0e2e362, 0xaf2baab6, 0xc8937efc, 0xc4520d52, 0xfdca37ed, + 0x53d8e5d7, 0x9c41f9c4, 0x77051e29, 0x87f6cf14, 0x7ba03505, 0xe386ac55, 0x31304d2c, 0xdf6a8974, 0x3b6deab6, + 0x375a52e4, 0xf423744e, 0xbdda8d64, 0xa886b342, 0xbd567133, 0x72068b92, 0x51bb2e6b, 0x72b9042f, 0x6581249f, + 0xfac97ddd, 0xaee0335d, 0xa17855bd, 0x0aded706, 0xe9ad66d1, 0x94f48973, 0xb2ba190b, 0x5f0a3a05, 0x97f3e442, + 0xa715b985, 0x57d65bc1, 0x99b8e622, 0x9d5365c6, 0xf86049a9, 0x7e14b327, 0x7ba93876, 0x9af6e014, 0xe070cfdb, + 0x2a87eb84, 0x31f08c13, 0x2e200d0f, 0xd52572e3, 0x710bff11, 0xde7351b7, 0xf142ed7e, 0x3475fa83, 0xa1fa36ba, + 0x7c59bb91, 0xa3b6c836, 0x14e51dda, 0x5c8e08b4, 0x7fe42533, 0x5abbe178, 0xefee1a22, 0x7eed49c3, 0x72bc5118, + 0xadafb8a6, 0x22bc4ef5, 0x5fb21897, 0x7883a27f, 0xf4b141c3, 0x014f8a28, 0x63a7bce8, 0xe7506969, 0xf824e7b4, + 0x681819cf, 0x51e4998f, 0x8a480cfa, 0xe5fa0632, 0x310c6de8, 0xbbfef441, 0x9b6a499f, 0x2fcbba16, 0x5d8120eb, + 0xa0c618e9, 0xecb0fb22, 0x5f8fae1d, 0x0ec72bf8, 0x6e2bfdcd, 0x9c96f294, 0xf93a23f0, 0xc7a7acab, 0xc8516ead, + 0x13ae4eb6, 0x38b527e5, 0xa3efb1ba, 0x06e907f4, 0xa43dc03d, 0x218e5d19, 0xe584171f, 0x629d3a38, 0x27a2474d, + 0xf3bec9b1, 0x5367abc3, 0x5b86442b, 0xc54b9815, 0xa4a050ec, 0xc5fb5bbf, 0x3238eba0, 0x646ef235, 0x811b7845, + 0xe76e355a, 0x547b0850, 0xf200b03b, 0xf2d15e8d, 0x625d1be8, 0x732ced42, 0x073ce66d, 0xe1e97efd, 0xf90a0a57, + 0x157b032f, 0x8baf2b01, 0x25ea41a3, 0x4b71c76e, 0x5a6fc8c7, 0xb46b6dd5, 0xf07d0868, 0x607fbab8, 0x0cd1965d, + 0xe5e2bdd4, 0x0ff280a5, 0xb683f694, 0xa4346132, 0x7eb48d97, 0x4a4e6c5d, 0x9b25f0e4, 0x3ae6c76d, 0x680de781, + 0x85a71ae9, 0xe8bd15c4, 0x9bfc5c03, 0x61a54deb, 0xacca0715, 0x95310a94, 0xe29a1ebd, 0xa3050021, 0x0ee0f340, + 0x6a0cbfd1, 0x1d7cb351, 0x774e8d0b, 0x0d59682a, 0x1d80ec48, 0x979d0f9e, 0xa994b2e5, 0x88670354, 0xc309f6e2, + 0xc607c624, 0x06020473, 0x1fb0ddfd, 0x9083f727, 0x5a462167, 0xee80acb3, 0x06b44e2c, 0xb9f2c131, 0xbdddceb2, + 0x11417162, 0x34c0b7fd, 0x2f2027bf, 0x050e473f, 0x48ec13ce, 0x202a834c, 0x6760d32a, 0xdfd2a075, 0xfafa33e0, + 0xfdc7f4c1, 0x2582911f, 0xe09bf121, 0x2aa1698c, 0xf8132c56, 0x4c01cbbc, 0x29c9d3b0, 0x81788f20, 0x5317c6ba, + 0x1a9801c0, 0x13089a0d, 0x8326c519, 0x5e8e4903, 0x22d8ac66, 0xd7aade64, 0x18d1f8d0, 0x598d8a10, 0x67cb6e8f, + 0xa5f2850a, 0xe3853814, 0x8354866e, 0xdc4577c1, 0xa3917321, 0x20691e4c, 0x18bcbc07, 0xa5cf2094, 0x0267ea43, + 0xcb285036, 0xa52c7269, 0x2dda6d9d, 0x1441a39c, 0xf9a16f9f, 0x25099865, 0x6b36c13e, 0xd3765209, 0xf87f0d31, + 0xc879f568, 0xda3315b0, 0x66578e2c, 0xf5120cf8, 0x6bfcb361, 0x6605ad35, 0x1bf594d9, 0xdc7aaeb7, 0x188b69da, + 0x960e2297, 0x1f22e163, 0x2a62fbf6, 0xfa442ef7, 0xcc548fa0, 0xf317387d, 0xb3160a75, 0xf9ec40a4, 0xe54b8ee7, + 0x76e9e7ca, 0x73245292, 0x046da4f3, 0xb75e3e27, 0x6a5eeed3, 0x7a2dbef2, 0x65369711, 0x98b65f97, 0xffbfd095, + 0x0b684562, 0x2773cd38, 0x110f0f67, 0xf6feca2b, 0xac93ca7c, 0x5fb8dcf8, 0xce9462f9, 0x29109608, 0x11598ca6, + 0xb40ae69d, 0x179e508c, 0x50dfd1cc, 0xbcda6e75, 0x1981d249, 0xd454f142, 0x034633f1, 0x68d866e6, 0x94701440, + 0xdf826937, 0x606fbebd, 0x2d25e0f4, 0x27f823a9, 0x25bbb4ae, 0x9a662476, 0xefaca4ee, 0xa5224af3, 0x8c476874, + 0xfbe95d70, 0x007038ce, 0x4123d2d1, 0x6c37c9be, 0x40e47ecd, 0xeb4125af, 0x806f0aff, 0xc9a0f7e8, 0x3681cc8a, + 0x8bb24c07, 0xe4daa3c3, 0x49c811f9, 0x0488219a, 0x2f440eca, 0x1bea5caf, 0x52a67c61, 0x5b8c2360, 0xb5e4e03a, + 0x3f90ba0b, 0xc02a146d, 0xfcf163d4, 0xab9d0dd9, 0x3190d513, 0x08a85834, 0xf742f184, 0xdc985ce8, 0xc23676b4, + 0x8cadbcfb, 0x8f9ed9c3, 0xd1d4b751, 0xc6efb12c, 0x04e6fc86, 0x3da04d1a, 0x8982af38, 0x53503aa8, 0x9b11ebd1, + 0xa80793d7, 0x548a22e2, 0x3087b359, 0xdce55f0c, 0x5fac636e, 0xcd9339e2, 0x0961b72e, 0xbd5d4b85, 0xccc99eb1, + 0x6d5bfd0e, 0xc716de8f, 0x8446ec36, 0x98033cf3, 0xcc6d2029, 0x999505a5, 0x6c9237be, 0x384b561c, 0x4cb95fdf, + 0x95f8d0e7, 0x778a1e79, 0x2b1c754e, 0xc275c3bc, 0x272b9ca8, 0x184f6584, 0x89cd5a3f, 0x5335eb96, 0xf7dad584, + 0xc8fe5d4c, 0x7181e623, 0x32acb8b7, 0x3208b61d, 0xf71c5f1d, 0xa91d3cf6, 0x65b058f2, 0xe8b598f9, 0x2c82dd93, + 0x639d70aa, 0xc705819d, 0x553842c6, 0xa689f4e9, 0xd7220a76, 0xff70c705, 0x9b9ea6a1, 0x94582ebc, 0x6a961947, + 0x2d1060fb, 0x609fad70, 0xd41bccff, 0x292ad853, 0xc9ffde76, 0x5dad8316, 0x44161ac9, 0x55484edc, 0xb6fde464, + 0x35f14430, 0x1a1668ef, 0xb70c3d1f, 0x521bef84, 0x9383a8b6, 0x5b92d569, 0xc3b001e8, 0x3dffaf95, 0x0f727ed7, + 0xc3e474c9, 0xfa7264cc, 0x8c4586c9, 0x6729dd1c, 0xc2d5d132, 0x8ed711d1, 0x6c336506, 0x0589ccbc, 0x974fab93, + 0x8db3a7ea, 0xd0026fae, 0x05b6a2b4, 0x2db1de2f, 0x05ebb04d, 0x139c441f, 0x6cd7f067, 0xe77e7a9a, 0x14ad0a82, + 0x6a6360cf, 0x6ee010fc, 0x009df3ef, 0x580704a5, 0xda20b94c, 0x8b5d3657, 0xd7f60133, 0x5b990e9f, 0x3cc80bd0, + 0xe1c7bc9b, 0x19f52b70, 0x2ee7f053, 0xce95e194, 0x7881dd8a, 0xbce020fc, 0x963037f6, 0x0a0a51d1, 0xa01970de, + 0x50eef89c, 0xad33d90c, 0xbb0c014e, 0xe495578f, 0x23b5d5cd, 0x5fe3b8aa, 0x3802f60f, 0xac82a769, 0x7ab1f985, + 0x5286f7e0, 0xddf6ba4b, 0x73920f8c, 0x59f115b3, 0x9e4c2767, 0x562dfffa, 0x51dee4e6, 0x92501b2a, 0xa48990ba, + 0x993a397f, 0x5eb9bf9b, 0x7343ff95, 0xff6e3605, 0xecb3e0cf, 0xb7f61c41, 0xb5f2fd41, 0xd58f35ef, 0x216f13fd, + 0xf313f2a1, 0xb3178b4e, 0xca3840e3, 0x11c20101, 0x37eb3b3e, 0x07a1b1c0, 0x57c3b184, 0xa320ea0f, 0x31b7541e, + 0xbb660e0d, 0x6ed13c9e, 0xe3f5162e, 0x5ef20193, 0xd7a95d0e, 0x58a478bc, 0x0266ab71, 0x3c89f927, 0xf87ed1b2, + 0x56e54f1c, 0xc7a4ddb7, 0x5e93e884, 0x35f2e7ff, 0x8a18b024, 0x56f77299, 0xab262946, 0xa2f39cfb, 0xce647335, + 0x92fc9ba9, 0x52456ae1, 0xda13ecc5, 0xf14ae5b3, 0xe6d9fcfe, 0xd347df12, 0xe2b3cbec, 0xb696e6e2, 0x1bb6ce9b, + 0x20f91ef8, 0x61ff8c4f, 0xcc3f9638, 0x8c4b8f92, 0xf1cdb053, 0x987d77da, 0xa9adb887, 0x8c3cf550, 0x2f483971, + 0xf0b53460, 0x203a0795, 0xddf18297, 0x353e6d44, 0x28d5f340, 0xb249e94e, 0xc5a16fa4, 0xa21c242c, 0xf79eb621, + 0xf1f4f690, 0x0939dbab, 0x0544fac1, 0xcd160118, 0x4a013ac0, 0x42c89faa, 0x4ec371fc, 0xb926b8f6, 0x2dd89286, + 0xa53c353c, 0xe98aaf3e, 0x31791863, 0xc8e170d8, 0x80ac5649, 0x24db790e, 0x1b034014, 0xbaba3ea3, 0x511aa180, + 0xce77208c, 0xe22935c6, 0x45935951, 0x05526b09, 0x0681354a, 0x044067cb, 0x0723e183, 0xa3758019, 0x9a608a37, + 0xd0f29422, 0x5add2346, 0xa6d61176, 0x86fca6a6, 0x9b9f4896, 0x080a6ca9, 0x1eda4391, 0xf6c27b1a, 0xc631d5ee, + 0xb964516e, 0xaae88c4e, 0x3612770e, 0xadabbec5, 0x060f1cd6, 0xc7411a15, 0xf4f76c47, 0x85ec676f, 0x83de86a7, + 0xbd22b1af, 0x9b880fa1, 0xfb50cbd2, 0xcc623bda, 0xadf0ac7d, 0x3c32639d, 0xb7a4b610, 0x39a4f368, 0xbaa6326d, + 0x5e865c2a, 0x43643a38, 0x2d1aef17, 0xb261f0a3, 0x6528f8f1, 0xc6f1d688, 0xb8fde187, 0x16f7172d, 0x20bc2f45, + 0xbbd3a13e, 0x03ff3a0d, 0xcf181eb1, 0x313dc625, 0x9102d0d2, 0xb14dff1f, 0x4d4b2631, 0xf5a9bee6, 0x75bdca98, + 0x13633202, 0x7ba403f7, 0x91e15a62, 0x613bdd5f, 0x380a20c8, 0xb3037c21, 0xd1a4c1af, 0x1fa68ec2, 0x3e39723b, + 0xe00872d1, 0x5f74b489, 0x5da5b1c6, 0xbcb2b48a, 0x7e1166d2, 0xb3e6f6cc, 0x8858da41, 0x8ea14a5b, 0x9c3701a6, + 0xca88508c, 0xcb77356f, 0x106cdc65, 0x1dce0614, 0x68fb83d8, 0xad6cedfc, 0xc64c387d, 0x737fa017, 0x6bf3d6dd, + 0x8dfaf312, 0x11de5339, 0xa27a6000, 0xc075730e, 0xef7ac5b3, 0xc7c0023b, 0xa47beb81, 0x38b7d298, 0xc60ae882, + 0x14e1c6d8, 0x932043a2, 0x2fa50b6d, 0xe58006e3, 0x6bee1976, 0xbae09f9f, 0x36a54fee, 0x76c64585, 0x67fd37a0, + 0xad8fe37f, 0x2d5d24cb, 0x154225a8, 0x38dd5b1f, 0xc34e4ee3, 0xe996b038, 0x9118fae3, 0xc8653e17, 0xc34843a0, + 0x9491bc3c, 0x3168cfc0, 0x04cc41cd, 0x07aaddaa, 0xb4126284, 0x4e523cbf, 0xfe26944b, 0x87e6d273, 0x447b889e, + 0x3c6536b6, 0x65d69308, 0xfaf2648e, 0x7fbfd7a1, 0xa2826d8f, 0xe5091d49, 0x015d7c61, 0xab81f0c8, 0x36dbaadb, + 0xf743a622, 0x8cd0a362, 0x191149fe, 0x1dba2071, 0x1188bf53, 0xdebeb7ff, 0x45a64aab, 0xa066f3d1, 0x084fc7ec, + 0x9c4b1c3d, 0x2b7a166f, 0xf663e699, 0xc34dd272, 0x308c9c6b, 0xd47acbd1, 0xfb7852f1, 0x4ef4d0ce, 0xd0bd9e19, + 0x86a1449d, 0x5f0c4f8b, 0xa44bc260, 0xfba16e5f, 0xe78e5aa7, 0xdd13ca1a, 0x3c9a02d0, 0x1c38c4be, 0x97dfa493, + 0xf2440994, 0xdce28521, 0x5d7d6f85, 0x5fb1b01f, 0x1b82d947, 0x18b39315, 0xeeb524b6, 0x35922fcc, 0x677456f8, + 0x83b5a548, 0x32f156f6, 0xfad894ba, 0xacb63714, 0x12e37b2d, 0x0b0e1aab, 0x865b5476, 0x4ea8b1b6, 0xefae402c, + 0x7a774d46, 0x8ad56309, 0x95c74915, 0x5a7d4257, 0x4367031b, 0x015e0132, 0x30134514, 0x5ec0e9df, 0x75a79bd3, + 0x7180c7ec, 0x8470ff47, 0xecdd814a, 0xe9ea265f, 0xb7a852c1, 0x0be7f9f5, 0xb8616d63, 0xf2acaa6d, 0x411ed9af, + 0xd7d34426, 0x6f69099b, 0x7f42fcb7, 0x18d0595d, 0x06873ef7, 0xa6a94b8d, 0x3aa44927, 0x04d9fe55, 0x3e15fa9f, + 0x84240d46, 0x19f97fd1, 0xd09b3395, 0x516c85ef, 0x7ea1b0af, 0xedcca878, 0x7ab0d161, 0xe0905974, 0xce3d2563, + 0x05f96547, 0xcb006b1c, 0xa1d6a801, 0x93fdbf54, 0x5bc9e012, 0xd2d03d6e, 0xbe881284, 0x2cdd626d, 0xf1316b83, + 0x86471bf0, 0xfd59f4bb, 0xa174f0a9, 0x0d69b348, 0x0f9d8c15, 0xe9ef79ac, 0xe3ee55d8, 0x2a4e2c23, 0x11d710aa, + 0xd1196ab0, 0xe5ee9420, 0xf7352113, 0x18486785, 0x7e1c4954, 0xb7b20c95, 0x40c294c1, 0xa4fa74d6, 0x4b13be17, + 0x253b4d8e, 0x0d2f9e78, 0x598224b5, 0x281b6c63, 0x24e9a147, 0x8502b01c, 0x9d038f03, 0x04087ffe, 0xaaeb83be, + 0xeed4d27e, 0xbbf653e4, 0x72aaf5dd, 0xad99c2cd, 0x94480b9d, 0xbdd71ce3, 0xe3c6a111, 0xcebf4450, 0x9bd84d2a, + 0x34664d17, 0xb9de3e4a, 0xbe241c79, 0x1605e894, 0x2b39bcba, 0xadb9414f, 0xb412dbed, 0x78d51acf, 0x256a28c4, + 0xd5d283bb, 0x6c06df90, 0xd442b289, 0x070c1701, 0x56d7f674, 0x35f05786, 0x69d57469, 0xcd3ceece, 0x0d291b64, + 0x7d759ed7, 0x185f98be, 0x7d2f385d, 0x6b3dcab4, 0x0b2d791e, 0x4451bbcc, 0xd570f618, 0xefa38a64, 0xcede9c42, + 0xd17ade7f, 0x10b0f6cd, 0x3d036e1b, 0x5fddc238, 0x54f268ee, 0x1d6fe9dc, 0x01cdbf9b, 0xbc7e67a9, 0xab90d4d9, + 0x109dfcbd, 0x0c9e7684, 0x1e100611, 0xf0273c3b, 0x89b97ec7, 0x689a442d, 0xfd4fa05d, 0x016bd13b, 0x93a5c64c, + 0x6154001e, 0xe90219a0, 0xe4c6f20a, 0xfa25058b, 0x2d1a02cc, 0xac79d2a3, 0x1e72bb96, 0x27b6807e, 0x2e1f1dcc, + 0x4f832194, 0x48e035f4, 0xb590ac6d, 0xf6dd5790, 0xc612cae3, 0x2a1f17be, 0x09ac068c, 0x13bf0b89, 0xa68797c5, + 0x67bf2ae6, 0x4a2795ec, 0x072a8770, 0x6416bbc7, 0x33051735, 0xd5b438a4, 0xa3cf1ec3, 0x68814dde, 0xa70018e3, + 0x590e2518, 0x5106c87c, 0x9ad9e686, 0x54eadab3, 0x048c9e70, 0x9b7e8617, 0x66bf3587, 0x7cc08cc4, 0x04bf54b3, + 0x14d89d65, 0x236579f5, 0xcd9b0969, 0xa764ae13, 0x0dc4615b, 0x25f5bfe9, 0x6bca6115, 0xde5d5500, 0xa5fba811, + 0x5010652d, 0x774da5fd, 0xc19132a6, 0x12c5d107, 0xd8d6f81a, 0x1fe7a961, 0xb9fcc040, 0xbc69c0a7, 0x18352178, + 0x78ebf097, 0x02bcdf33, 0x03032b86, 0x11f3ce3a, 0xdb4d8469, 0x329d41ac, 0xd67b2165, 0x28ff6419, 0xf46550d5, + 0xd17f385a, 0x016e68b9, 0xf814a5f2, 0x1a6b3f3f, 0x92a9deb1, 0x4754805a, 0x5cb3af68, 0x2ac1f672, 0x0daf1b54, + 0x3b269908, 0x3a305ba4, 0xb29fc981, 0x2f8de1b5, 0x57297e9c, 0xf8282066, 0x19b92442, 0xaebefa71, 0x5be1bad7, + 0x56f1f70c, 0x760ebda5, 0xb59efc42, 0x8d4dad4b, 0xba66d22a, 0x53d70c8e, 0xfc89b0be, 0xbc5dbfc6, 0xfa16f1b6, + 0x8ccef11b, 0x83c80748, 0x97cbc662, 0xb13caafd, 0x8e5e1231, 0xd74ce827, 0x77ac2594, 0xc972e58b, 0xc881f2f8, + 0xb8028339, 0xe91d0c99, 0xd61d5498, 0xa4487083, 0x3d646c7a, 0x944937a2, 0x939f28b4, 0x82f6f6bc, 0x07c6d6f2, + 0xdeed647d, 0x9a56eaed, 0x80e17408, 0x5db30595, 0x0c514367, 0x87b17e55, 0xa4e2d2eb, 0xec4e1988, 0xebf558a6, + 0xcef36b05, 0x1c497f8d, 0x27b065d7, 0xf1d79c57, 0x7c75db21, 0xd2204f7d, 0x3bea457b, 0xa2171b7f, 0xb797b983, + 0x64c36185, 0xaa32701e, 0x3618ae85, 0xa9b81aa7, 0x8e2d7662, 0xa27b982b, 0xb4ada97f, 0x9163859d, 0xa1bbaf7a, + 0x0239a8af, 0x010e82e4, 0xa03dc20c, 0xfb2c16ed, 0x7b32397b, 0xc207e619, 0x41008b96, 0xb99c51c9, 0x8769ec35, + 0x380f93df, 0x08aff678, 0xfe7724e8, 0xefa89cd8, 0x58c0a144, 0xf91c826e, 0xbc7e518a, 0xb926192e, 0x59acc11c, + 0x6e97b3de, 0x75274cd0, 0x5a0a1fd2, 0xc523c0e3, 0xd9134777, 0xb3e4ca86, 0xea264059, 0xe36e2352, 0xf3c48a15, + 0x28743087, 0x96ef0130, 0x604476fe, 0xf7ee5267, 0x8602c274, 0x905940a9, 0x48dde03c, 0x71f84641, 0x8a9f347f, + 0x57f62d70, 0x03c81f45, 0xc056b502, 0x5156621b, 0xd409b985, 0xfbe0f08b, 0x5d2c9ba3, 0xd59b2fd6, 0xf58a203e, + 0xf0bd4c02, 0xefaa8b04, 0x1e64b80d, 0x1fd97754, 0x9d1b38a1, 0x04fc2608, 0xaf9d0212, 0x26c01741, 0x30be5fb7, + 0x5305d7b4, 0xb935a058, 0xa06c6438, 0x089d6fb0, 0x1b5caac2, 0xf104c2e3, 0x2419fd8d, 0x32e626f9, 0x19355a53, + 0x29198611, 0x303c2116, 0xca880654, 0x5b549133, 0x6765f12f, 0xd464fe3c, 0x303c8d46, 0xee66e39a, 0x144cd265, + 0x4b68dfee, 0x7c500347, 0xc67676ef, 0xa4a1fbfa, 0xc588adc0, 0x70e4e5ec, 0x79de201a, 0xbda24c6f, 0xf0474db5, + 0x9537241a, 0x4a19b8c4, 0xca52949a, 0x3a84a82e, 0x5d4fb96e, 0xdc9ae8e9, 0xd07af9f0, 0x383e92e2, 0xcd92f69e, + 0xf8b48934, 0x0d1b4f20, 0xe2cd83a4, 0x130a1c03, 0xc383e3d2, 0x7892e495, 0x15bec79a, 0xa5fd2452, 0x304d52d8, + 0xec54aa89, 0x7e003523, 0x71ff9d9b, 0x8f23380b, 0x5ecf78f3, 0x6fed6453, 0xd4837a3d, 0xeb39af2e, 0xb23f0220, + 0x5d2297f1, 0x1af42a76, 0xcd67003e, 0xe7277f46, 0xc2a710ec, 0x1cfb7c2d, 0xb57c64a7, 0x189218d8, 0x1c1feaaa, + 0xe2751b08, 0x2bc5ad9b, 0xf8cfe742, 0x9f93c1ba, 0x51cab95d, 0xf38e9cac, 0x598fa26d, 0xe0531a9d, 0x72719948, + 0xb5e84aa1, 0x06927b58, 0x295c2a6f, 0xf4e472ba, 0xefe679f3, 0xbae2e134, 0x3a757615, 0x87744ab1, 0x523e28fe, + 0xe22af627, 0xfb40cfca, 0x38363d81, 0x210943cc, 0x07dfc17f, 0x3d4fe33e, 0x94d0b8c8, 0xc01c71a9, 0xd238fe17, + 0x2b66d078, 0x6f2f416a, 0x8da15ee1, 0x61935f0a, 0x8128d6b5, 0x1e43c5ca, 0x88f621a9, 0x5a5e1589, 0x0c420f4c, + 0x7f55bac3, 0xb18c1951, 0x79133b75, 0x2b5a8bf0, 0x2981981f, 0x3b5f4275, 0xad04be4f, 0x2108bbf0, 0xae60ee0e, + 0xeb4e8d43, 0x316e2e1e, 0x7dae6069, 0xd1539164, 0x875677fa, 0x34428926, 0xbae3b777, 0x4d598a08, 0x2e1dc588, + 0x17099af6, 0x7bbc5d10, 0xaac7fea9, 0x7e29f961, 0x93396263, 0x0b412a47, 0xb1744e71, 0xf91b6d94, 0x2db85923, + 0xff3743c8, 0x1256cdf5, 0x54a32d68, 0xdd4153d8, 0xd04af1ff, 0xa1a656a2, 0x5b2bb5cf, 0xeddd7442, 0xc716183b, + 0xa237d28e, 0x299f6470, 0x9e74c399, 0x376a4228, 0xaf368827, 0xbc15e661, 0x1da8ffec, 0x240d575a, 0x25502072, + 0xec9c4a3a, 0x945a4029, 0xe2ae2f10, 0xb2c4b656, 0x4e100153, 0xa35eeadc, 0xbd227623, 0x492546cc, 0xfbea678d, + 0x18568d1c, 0xf3fa8ac9, 0x523e38da, 0xabfdf6ff, 0x6c283bae, 0xa5e7359f, 0x6135bcdd, 0x7fd73830, 0xb4b80099, + 0xc0307e8a, 0x3dd343b5, 0xf385eb8c, 0x8d5531fc, 0x031d1965, 0x37d2d727, 0xbe51b2c0, 0xd3d26611, 0x155dfa72, + 0x1437d445, 0x1aa68294, 0x9130c9ad, 0x2b653b38, 0x53ea0f66, 0x09c97af7, 0xceebec0b, 0xa0e02ee3, 0x54f14d9c, + 0x6387f7ef, 0x41bc2749, 0xd5fc7646, 0x47ad50a7, 0xedcb2e4d, 0xcac30a50, 0x6fb433de, 0xc60f13c7, 0xc1e175c5, + 0xfc426a6b, 0xc3abdff9, 0x7b00d84c, 0xd9d2d371, 0x50446d7e, 0x63c1bd1c, 0x438d7601, 0x85d39365, 0xc248d4bd, + 0x651304ba, 0x9285ca98, 0xc567ef70, 0xf83a35ec, 0x028ed6fe, 0x05919bc0, 0xbbbfb38e, 0xd8b1bc13, 0x5f362830, + 0xee620167, 0xe204808b, 0x7c9271cd, 0xe51f82b8, 0x6c6c95e5, 0xa4fd2841, 0x1375dd5f, 0x102170d8, 0x2ef5eea2, + 0x195ddda2, 0x8121808a, 0x7cfaa5a2, 0xc51b737c, 0x91c68d60, 0xe4f91f50, 0xe4f64119, 0x81eb55e1, 0x96e4d9f3, + 0x94597051, 0xc3799038, 0x509e5531, 0xde0258a4, 0xb6ba66db, 0x446a0e6c, 0xe1afd261, 0x5d503a8a, 0x243da6ef, + 0xea84cc66, 0x7906f0a9, 0xf2d85fa8, 0xc2d8d30d, 0x5c3ecefb, 0x2e68bdf5, 0xa5657983, 0x5d8ae937, 0x9ac8c37c, + 0x42c62e19, 0x976960ee, 0x173befc3, 0x0afe3517, 0x5cda3265, 0x16ab70dc, 0x563699e8, 0x0bcec0e5, 0x357e43ca, + 0x713452d1, 0x84207e24, 0x00cfcedd, 0xb65296e8, 0xc7dab649, 0xf96c3262, 0x375f0320, 0xd7cfa9ae, 0x7602a883, + 0xa1f63b32, 0xc423444b, 0x0df18951, 0x5e34eb6a, 0xbcd04941, 0xca3e477a, 0x80dd04f7, 0xc7916b9d, 0x954f9f8e, + 0x9edbc2bb, 0x54bf0b24, 0x8b3b18fe, 0x2dfc37c4, 0xcc4f72b1, 0xec5fe285, 0x7db84625, 0xb673f936, 0xb1da3343, + 0x457b67a8, 0xc9a59fbe, 0x53f2136a, 0xd08d35ea, 0xd9cb5f1c, 0x85b4d0b4, 0x72e7f6fc, 0x2a5a0969, 0x425f3917, + 0x64d264be, 0xa87a64da, 0x823af109, 0xfdc88e54, 0x35ac183a, 0x2f82217e, 0x18a6bc77, 0xba571767, 0x6ce50806, + 0x0bb39da0, 0x6388f72e, 0xdf1fb793, 0x41683df5, 0x34f8fde5, 0x97c0de00, 0x98279df7, 0xdfae5808, 0xf248a735, + 0xf5870ac3, 0x89e534d9, 0x32424833, 0x7bbecf69, 0x4d52d086, 0x4531c147, 0x35580af3, 0xf5206712, 0xb88a89ae, + 0x4ff0941e, 0xfa1a0589, 0x90cd8195, 0x1163c6a0, 0x52583d8a, 0x1df65ae6, 0x66e4143d, 0xc7d6b5d6, 0x8da0e7c1, + 0xbc3cb930, 0xb212f87d, 0xb92d1557, 0x9f674f6a, 0xcb590540, 0xfebc6cd7, 0x2c1478d3, 0xe7ba1049, 0x4551847b, + 0xb585e81f, 0x3986cc8f, 0xcb8b3545, 0x6ee8045d, 0x0572d37c, 0xa960e902, 0xf4b1ee0d, 0xded0d1ea, 0xdd0de455, + 0xcd5b51b6, 0x4d44aed2, 0x09e7a715, 0x0be98fed, 0x74ae52c7, 0x2f7f48ad, 0x5a40000e, 0xa41499e4, 0x601318e2, + 0x0a418e42, 0xa09a08b7, 0xd8c302ca, 0xbc614d18, 0xa11ea074, 0x5a48ff2a, 0x9e72e473, 0x2bbced82, 0xeaf29d58, + 0x7f1a69a1, 0x896c8756, 0x2b28a8a9, 0x79788e7b, 0xdc8eca0a, 0x3e28dcd8, 0x878a9f61, 0x959bdda1, 0xc616e468, + 0x376c8755, 0x8a7ee1b1, 0xccb3e99a, 0xa7fbd8a4, 0x2db1a088, 0xee191d00, 0xc3d5542b, 0x374a42b0, 0x311c48cc, + 0xde504c93, 0x3d88368c, 0x3c9ecbc5, 0xfbc436f9, 0xf0f3acbb, 0x7f34e449, 0x6a04a830, 0xe0dbc638, 0xe5fc9cec, + 0x78a52135, 0xa323217d, 0x756c59e8, 0xd6d5e9b0, 0xcab74af8, 0x144ef787, 0xa0a594e7, 0x4ae025ec, 0x8728ab33, + 0x84c1b8f3, 0x4b57470d, 0x34206f7e, 0x13249100, 0x14dd0d0a, 0x90a382b4, 0xee4b2b6e, 0xf6d9cf14, 0x01c828a3, + 0xe5bb97f3, 0x61600a8e, 0x796d23b5, 0x827a334c, 0xb49028fa, 0x927c5696, 0xedfdad7f, 0x4ac9762a, 0xc385874a, + 0x88c77421, 0xe9c013b6, 0x15e3f664, 0xf1252f3e, 0x16f2c0d5, 0xaf3260cc, 0x2872b8e4, 0x72723a93, 0x1a9e004b, + 0x8043422c, 0x0f0f0d6d, 0xe2d5b81b, 0x79bf0bbf, 0xfea6a722, 0x36d5897b, 0x811d739c, 0xe5daffa1, 0xb7794775, + 0x526d5d60, 0x58d788af, 0xa5b954d3, 0x71d5977c, 0x172a2e0a, 0xabf44fb0, 0x8cdec08d, 0x513820a4, 0x8d4913ca, + 0x7bd0fc23, 0xa66f8b9a, 0x51225f63, 0x3a665b71, 0xa02e8c3c, 0x8bef3450, 0xee94703e, 0xf0a8eb03, 0x4cadf310, + 0xc55970d4, 0x416ee75a, 0x0f84c6b3, 0x468ef35a, 0xc6899b98, 0x192d6a44, 0x64c59028, 0xc3b35d85, 0x61ff9334, + 0x7f345255, 0xcec0af8a, 0xa027409c, 0xc546900a, 0x22d1f213, 0xfaa77223, 0x1119f52f, 0x436ef7a5, 0x6f5e37eb, + 0xf1831b8d, 0x7f36b67f, 0xf71a489e, 0x8df53f0e, 0x4311034d, 0xbec0c8f9, 0xdcb955bf, 0x270c5df6, 0x55ff9074, + 0x348e6756, 0x026b612b, 0x9827a103, 0xdac2c2b0, 0x5ff4e2e9, 0xd8c714b9, 0xc0c324d3, 0x0c486bb2, 0x3c617c43, + 0x485a58b6, 0x6ca3cb8a, 0xbab76945, 0xcdd0972b, 0x41202c87, 0x2bf9569c, 0x1587b7df, 0x76316a20, 0xa5caa53e, + 0xf9749c8d, 0xdd220722, 0xc18c3b51, 0x47820494, 0xd50e9f1b, 0x1f0036f1, 0x90ff9912, 0x34eb6a87, 0x4709a3df, + 0x6b1c8ef5, 0xed4c9858, 0xe506e711, 0x059222f4, 0xbbe4e54d, 0x64130447, 0x2409a219, 0x379758c0, 0x90ea24cb, + 0x195838c3, 0x53a51f76, 0x492304f3, 0xa4c1ba27, 0xc28393e5, 0x99de8664, 0x453060e9, 0x1d319b7d, 0xb1f8996e, + 0xe14f816e, 0xb2de2ac5, 0xe594bd6c, 0x55bf3412, 0x5ac45ebe, 0x2c2329db, 0x1579e537, 0xc6f2ad00, 0x77452e17, + 0xaba154fc, 0xad112567, 0x7c07040f, 0x90929d0c, 0xf23e81ca, 0x6dc7b26a, 0xfbbf1de8, 0x933b3309, 0xc11e0e44, + 0xa37ec5c2, 0x544f2aab, 0x98362bf0, 0x73f3e158, 0x3f0d8c92, 0x14f678df, 0x638c5087, 0x73efd042, 0x89bc7cf2, + 0x993ee68a, 0x55e92561, 0x9dc28613, 0x9281d5c8, 0xd01ceec1, 0x7f9acfb3, 0xeb43f1e8, 0x78abfe2f, 0xa7da54a7, + 0x82771e50, 0x2e318dec, 0xb07a40af, 0x2fb4ee5d, 0xc2548e4a, 0xa67b5640, 0x8138ced8, 0xe7d0aa0e, 0xfcddccaf, + 0xde4ae26e, 0x19055c02, 0xf09c502e, 0x92f095b1, 0xa2fff0e0, 0xd629f6f7, 0xe2e31935, 0x575b91ca, 0x6f6260a8, + 0x74f1dc1f, 0x12a2c946, 0xef659d9d, 0xb2e65668, 0x73e640ca, 0xdea7f665, 0x2a1cfa49, 0xd85b31d3, 0x14e735d3, + 0x27c102db, 0xbedcef40, 0x70073ce0, 0xa639d551, 0x79bc59a6, 0xb939d351, 0xbb7d83c6, 0x8a10a81e, 0x7ab326cb, + 0xd134c4d6, 0x78fe1ed7, 0x14aeafd9, 0x408c0b04, 0xe01d739d, 0x0f60c4f7, 0x476da580, 0x61c9c5bd, 0xfd1aa5f3, + 0x2a6f1675, 0x83daa660, 0x91749e83, 0x3e70d279, 0x8042df81, 0x449f549e, 0xbb236ca5, 0x14d72ecf, 0xe74a0bbc, + 0x6874a862, 0x1e578ae9, 0x67fefc52, 0x9affa928, 0x29a14874, 0x1946f94e, 0x572ddb28, 0xd8147d7b, 0x60d6ad2f, + 0x5893694f, 0xd8eaa6a8, 0x5cb1dea0, 0xb72b829f, 0xf47c6ca1, 0xca22f475, 0x3614dd11, 0xeaff8079, 0x1c49f24d, + 0xcf361087, 0xba208ffa, 0x21cc92fc, 0x3477ae15, 0x4cc8e473, 0x3dec4aae, 0xcabff0eb, 0xcd881ffe, 0x5ebd4911, + 0x3c2cc648, 0xac16ad5e, 0x4bf3b79e, 0x728e4ec3, 0xe2c8f4f3, 0xbd585a90, 0x45a78375, 0x81f0a631, 0x4e7f9faa, + 0x2e09ed0e, 0x89805de0, 0xd0651c79, 0xa2d3d95e, 0x27da96c2, 0xb730f85c, 0x34dfe682, 0x42459e35, 0xaf2c229a, + 0x7e4473c6, 0x6be72157, 0xa0a766e1, 0x40ee0bdf, 0xf12c99d2, 0xa3c42415, 0x06ccabc4, 0x1379fb63, 0x72f23a78, + 0x8872e87b, 0xd4fc15fc, 0x1fe62a4a, 0xc838b690, 0x38ce2f15, 0xb8fbd1dd, 0x0c301f55, 0xc5278cb7, 0xe0466681, + 0xc62a6676, 0x2f083fdf, 0xbf0291a9, 0xbe8fea71, 0xa7397a44, 0x2c60e6f8, 0x3c3137d4, 0xbda3407c, 0x6358323d, + 0xe9824eb3, 0xc5e518db, 0x96a14bf6, 0x79958c81, 0x95714d8c, 0x630fba23, 0xe7574f9d, 0xfdd518cb, 0xe7c9573b, + 0x0679ae12, 0xab28c477, 0x5067dd9b, 0x01d4ed87, 0xeb40c034, 0xe287b8aa, 0x8262fcfa, 0xe082b7ac, 0x0f5e88e0, + 0xe352e995, 0xa18b29fd, 0xc717b3b1, 0x223cb0d9, 0xc2b6754f, 0xe831db28, 0x975731b4, 0xa8f81a02, 0xdf5a104a, + 0xd93001c5, 0x7c1dbd02, 0x8bd46d1a, 0x9b59410a, 0x1a702cb6, 0xeae3bb0c, 0xe9629a12, 0x8fe9b3a8, 0xc060a27d, + 0x821e9511, 0x00e50581, 0xd04e599b, 0x3aeba8a9, 0x997a249a, 0xbc1f66b8, 0x5f439d81, 0x32f7b838, 0x2dc7f744, + 0x89864ed1, 0xa83da24e, 0x4518f52e, 0xd7dd6b3d, 0xbba895d9, 0x8e8fd04e, 0xa4289e07, 0xb8c2505b, 0xc02103e5, + 0x5ed7fea8, 0x1679f0a9, 0xa925873d, 0x6b90f261, 0xed4917d0, 0xc7d38d75, 0xeac0c5aa, 0x8055613b, 0x0d4fbc33, + 0xde1d9f18, 0x2ee96e5c, 0xb3810d0c, 0xae2bde26, 0x8e7ca2d4, 0xf08e8313, 0x6fb407b1, 0x18f7c303, 0x981920ed, + 0x5f0b1502, 0xf85b95a9, 0xb357845b, 0x079db480, 0x6465689b, 0x8cb34b2f, 0x20391cb0, 0x443f4a2a, 0xc10f9361, + 0x4a545ec0, 0xb964bbb7, 0xd939f3bd, 0x92c75772, 0xa643a576, 0x27636622, 0x82963e27, 0x3fa4db31, 0xb50e9fd1, + 0x6194d8aa, 0x1edd45fe, 0x7f563cf5, 0x9c15a53d, 0x12cbb9b7, 0xee71b690, 0x0d75160f, 0x1111b8e5, 0xa6d30c84, + 0x1c79a834, 0xa7a55e21, 0xde7f0da7, 0x3befd87c, 0xbd703167, 0x326caf8a, 0xbbdb03b5, 0x1a67652c, 0xeee58377, + 0x7eb9e826, 0x7fa34e60, 0x9e60e45d, 0xee9c2b98, 0xc70fb039, 0xd6ef1928, 0x0aa93193, 0x08bac5d2, 0xcb9121a4, + 0x869a3558, 0xeab4ac90, 0xda33fef4, 0xb9b851c4, 0x2ea4f838, 0xad0b8993, 0x9dd78bc5, 0x23277d5f, 0xd4761e4b, + 0x09844667, 0xa32de5f1, 0x408883b8, 0xdd9a62fb, 0xec3145d1, 0xc40310ef, 0x6ff38add, 0xcfa9da9c, 0x17c95fc5, + 0x638192e4, 0x3e555ff8, 0xe1f4b7cc, 0x51d12175, 0x16624768, 0xaef5cc57, 0x48495ed1, 0xc245c230, 0x057d1357, + 0xa518388c, 0xd62e37f1, 0x6fbe43fb, 0x3d4c1006, 0xc57dd122, 0x3c4eb61a, 0x166276a8, 0x03e9bf55, 0x241b325a, + 0x2d3aed73, 0xc93c5b8c, 0xa94c9ba2, 0x4d29e5d7, 0x0406844e, 0x7b9e19af, 0x068a726a, 0xd67563ea, 0x2a75f15b, + 0xe55133cf, 0x318019f4, 0x8c176ba7, 0xe808b4c7, 0x877c39d7, 0x0f61672e, 0xad00ef3a, 0xcc6c5aaf, 0x4d64b13a, + 0xa31d93e2, 0x02072805, 0xc73f1199, 0x458cf7e3, 0x7d2d2e36, 0xe0e84021, 0x31c1ee43, 0x5f5e49c8, 0x8b24690b, + 0xa179d655, 0x76ffb1f1, 0x2fe92e49, 0x7243d2a8, 0xd7d5d4af, 0x1f245afc, 0x1169650d, 0x0bbc8287, 0xae8ad91b, + 0x99c32936, 0xbf01c52f, 0x80abc23d, 0xeed6dc70, 0x9dfe0845, 0x39160b7b, 0x8bc24681, 0xeafd1618, 0xad84c0ab, + 0x8e41cf85, 0x8361a31b, 0x6d1531dc, 0xcb2057ee, 0x23be48b1, 0xaf718ca2, 0xb341de7b, 0x72f0f18e, 0x43173d62, + 0x403d342a, 0xcb94cb63, 0x4e0f1cf9, 0x3690ec5c, 0x882f3b79, 0x4998c8fe, 0x8c297fe8, 0x78c72467, 0xc6570a53, + 0x4697389e, 0x66cf81ec, 0x33717ac7, 0x81a79f11, 0x5c38ee00, 0x7f650e46, 0xb5c7ac45, 0x92ed353f, 0x054a829a, + 0xdca6d848, 0xb5a0910b, 0x8b2a0c71, 0xb7f7b48f, 0x2c2df8b1, 0x66196aa5, 0x3565b2f3, 0x0c814332, 0x78bfa005, + 0xceb40a59, 0xb8779315, 0x00ade92f, 0x004629d3, 0x8213affc, 0xfad310b3, 0x67ec8c04, 0x3d7e42b8, 0xc9cb7585, + 0x5affbe7d, 0x55f7643c, 0xbe0ea9dd, 0x0055a2a7, 0xef56acc5, 0x62f47807, 0x39a3b0ed, 0x0f201be9, 0xf3c54bbd, + 0x539b2c3c, 0x0eb84464, 0x94b1a249, 0x98a7fbb8, 0xdf0ad296, 0x9014eeee, 0x19a31a8c, 0xd85ef1b2, 0xec0fb5ec, + 0x0ad290b7, 0x284bc9e2, 0xfbdda03c, 0xef4cb84f, 0xb6d83f1c, 0x2aebf783, 0xc92ebdd6, 0x5221d98c, 0xc2d8611a, + 0x41cd3f13, 0x3acebe26, 0x6b174b7e, 0x4b568a89, 0x3319e275, 0x560bdd51, 0x38e740fc, 0x75269dd9, 0xc17b0298, + 0x940ffa5a, 0x7447dbe7, 0x74004dc3, 0xb17dccc2, 0x505bb197, 0x67e165f1, 0x48487cd3, 0x19e8400d, 0x75ff7a00, + 0xcb1071c7, 0x4d6ad910, 0x02eb3d6e, 0xe6a2f6ed, 0xd6f65403, 0xfc2642ba, 0x78d8703f, 0xe2d1b278, 0xab4dc71c, + 0x0a4f531d, 0x7f145904, 0x1edcf94a, 0xf0493d29, 0xb07c7be7, 0x18ab2cd9, 0x090328f7, 0x8b60632f, 0x0a4995ca, + 0xeefe964e, 0x2562a38a, 0x52121b50, 0x559c7f48, 0x9a956b71, 0x9323f3b6, 0xe481c01a, 0x4665e92b, 0x462ec8df, + 0xa4b665b6, 0xf749fce4, 0x6f0cbfd7, 0xc69f825a, 0xc78823de, 0x9f09442f, 0x55108e24, 0xfe86b706, 0xa838275e, + 0x99297a71, 0x085da86e, 0xae86af18, 0x4576c929, 0xcb656beb, 0x15595a63, 0x5f405e4b, 0x95c45639, 0x4ca48e0c, + 0x4a7bb8ba, 0x9aea064e, 0xd735c29b, 0xcc1da285, 0x8dbb9b0c, 0xe7b3e598, 0x1639f0ce, 0x2afa321f, 0xc12e0856, + 0x8c4d6663, 0xbba5562d, 0x62ed043a, 0x2c62d6fb, 0x3744a1a3, 0xcade28ee, 0xde3e1b33, 0xe73cee28, 0x10df3cbb, + 0xf7b06b58, 0xfd07bee3, 0xa142c285, 0x9d2b50ce, 0x178ca905, 0xe1afe346, 0xa6409f1e, 0x3689d2e8, 0xdf1fd953, + 0xf7b8b42d, 0xce71fbab, 0xbb42d854, 0x642db27d, 0x851be0cd, 0x548cceb4, 0x134d2825, 0xe3da3b74, 0x47a89ddd, + 0xb37d68c6, 0x6482e6aa, 0x7b663bcf, 0xf2329233, 0x1c56275d, 0x12eb565e, 0x274c5367, 0xda292421, 0x0086ee73, + 0x10b19ff0, 0xfa6e5641, 0xaeca014b, 0x12634539, 0x63d5f9c0, 0x22d573c7, 0x320dd3b3, 0x478e73dd, 0x32cc6058, + 0x3ad6ab03, 0x74365133, 0xa2c2381f, 0x26099518, 0x7bbb1076, 0x928a7a9e, 0x3468b73c, 0x024f8941, 0xa130c8da, + 0x5d30f93a, 0xba4584d5, 0x0d7e3d7f, 0x32ba8aae, 0xef0766a5, 0x54c1cb2a, 0x6f857217, 0xd2e2109e, 0x24ab69bc, + 0x11bddd06, 0xf0ed50b3, 0x891d4cb2, 0x47ba8973, 0x7a4f84ef, 0x32bc1aa4, 0xcd0e1f5f, 0x13d3ac5a, 0x47d6e8e2, + 0xf26f0000, 0x539ecce2, 0xe6152e7e, 0x06253bd4, 0x563f1a82, 0x101c19ee, 0x963ee41e, 0x40ffdcf8, 0xcb2c5f4d, + 0x6f275a2d, 0xdc1e8641, 0xe550477f, 0x8de81325, 0x6da33ada, 0xc3c54bca, 0x6e920e68, 0x2812561b, 0xf46158df, + 0x72027f08, 0x5f2d121f, 0x289eb201, 0x4abbe32b, 0xcceef7c1, 0x921ee3da, 0x9502ad8d, 0x21289dbb, 0x5562a846, + 0x5b7bfcc6, 0x05a4109a, 0x90b3d8f5, 0xaf9934a2, 0xd19ec70b, 0xe96cb289, 0xf32c6f33, 0x85a50367, 0x5df411bf, + 0x0dec992f, 0x0ac87358, 0x8b067a1b, 0x2ec598d0, 0x3fa13113, 0x09eecd99, 0xd2927433, 0x8dc8c458, 0x8592ef45, + 0xa8629dd7, 0xa5a71c37, 0x94b741d4, 0x56820fd7, 0xb9c2e913, 0x361f9510, 0xe1e0aa95, 0x13ec48e4, 0xf7bd90da, + 0x973308ef, 0x1e94f86c, 0x9e9d7d62, 0xf213a78c, 0xeb608e82, 0x7d11b2c5, 0x91c69767, 0xc27c6ddc, 0x5aba2538, + 0x31681209, 0xf5592622, 0xed294f44, 0x86baf63f, 0xcf7cd685, 0xf6527724, 0xf7baf149, 0xb09d1b4d, 0x5e393e75, + 0xc8c04074, 0xce2dd32c, 0x32e44f95, 0xcac3eb48, 0x8ddb7791, 0x56db91f8, 0x60794023, 0x499bc506, 0xcd26fe11, + 0xae2a7a86, 0x5c391e03, 0x1f7e6f34, 0xdbc9bd0d, 0xd02ae874, 0xd43489ac, 0xc2c60ecc, 0x3228b340, 0x94027c77, + 0x609102a9, 0x485908c7, 0xfc86049f, 0xf09936aa, 0x16dec2a4, 0x8a43465e, 0x3ffa7e97, 0x7439b0ad, 0x8a2733a5, + 0xb23074da, 0x7971481a, 0x5db0ff22, 0x1a8eebe5, 0x6d78460c, 0xa3a6c225, 0xf6cfeae3, 0x6efc5589, 0xa5420c52, + 0xcb239b69, 0x765a08ab, 0xd953614f, 0x6bc43469, 0x22a41c2c, 0x9a5de627, 0xf37703de, 0x3c0b7486, 0x7d5612ba, + 0xfe41ff63, 0x9300f66d, 0x402f0da2, 0x6a8cd03a, 0xb2a941e5, 0xebe613ed, 0x2f6b5889, 0x0d3bf80e, 0x44f1e789, + 0xbcd8dd0c, 0x30478ccb, 0xbfe2af84, 0xd8c68024, 0xc3d3dc19, 0xd0a042fa, 0xc918d3e0, 0xf9e35e00, 0x95aa1cc2, + 0xe7c49f39, 0xd3cd0716, 0x941d63f7, 0xd436317e, 0xdb5e1e35, 0x7e2e219b, 0x9e2c6a69, 0x52a5a1fc, 0x8d83d705, + 0x2c78cc87, 0x160e8933, 0x164dfd79, 0x1ee5376b, 0x2e87acd0, 0x9504c7ba, 0x6b5e94ef, 0x8eea8b8b, 0x90c29164, + 0xd16904c3, 0x2828fcbd, 0x1368e270, 0x5297e0c1, 0xc59e58ef, 0x1adf3ec8, 0x51c0b581, 0x1863a7df, 0xad55d7d7, + 0x4c9d8b72, 0xffaaeaeb, 0x3bc0d4e5, 0x8a18e4c2, 0xdb7d3d4c, 0xc9ad1012, 0x205f1042, 0x380534e3, 0x36a6442d, + 0x4bb1223b, 0xb38df93e, 0x48bda743, 0x8546a540, 0x4d15cdaf, 0x7f7457d3, 0xf4cf648f, 0xc82c5c33, 0xc404851e, + 0x657eba00, 0x83978f55, 0x898d515b, 0x234e017d, 0x78e3a4c8, 0x59ac8e2b, 0xf5eeceee, 0x96a2b274, 0x8c93c846, + 0x3062fbab, 0xfac3ece8, 0xbfe26d27, 0x7947e84e, 0x681eca1e, 0xe338fa66, 0x69385df9, 0xb993b0ea, 0xecdebaa1, + 0x51a7eebe, 0x35700b17, 0x757c16ea, 0x5cfa80da, 0xa308e60b, 0x7dc9ac3b, 0x2cd558d9, 0xbd3c87b0, 0xd5cffd4a, + 0x9bec7168, 0xd10dacaa, 0xbb1aa82f, 0x08566481, 0x9eb3924d, 0x87451e75, 0x5fae461a, 0xa2be7842, 0x7095ff2b, + 0xd945ee4e, 0x6d55c3cb, 0x19f69086, 0xc98086d9, 0xac228e94, 0xdf84e976, 0x42891860, 0x3ae5ccc4, 0x7abf1938, + 0x4595f8ea, 0x0a4acb46, 0x661281e1, 0xfa721be3, 0x24cd7cb8, 0x71bb0a06, 0xb836fef7, 0x29ac71b4, 0x8ea8b032, + 0x0a9593f1, 0xf0624e8b, 0x30029153, 0x1bdfeb06, 0x630650b1, 0x3d4379a4, 0xe1847d4a, 0xf002bb4c, 0x0536c611, + 0x2ac7a183, 0xbe3d77bb, 0x37724c18, 0xbd277960, 0xad710738, 0xd282eae1, 0x25540813, 0xc6b646de, 0x5e6f0add, + 0xd27afbdc, 0xe5bc4a48, 0x01f8d1c9, 0x790984cd, 0xcd686c77, 0xf3076729, 0x14f69ccb, 0x44f0fd2d, 0x2cf79c80, + 0xe6093684, 0x9c9a6653, 0x330a4e02, 0x3d7de8fd, 0xcc962443, 0x1a16dc86, 0xd7f15cc0, 0x27209a5d, 0xb929f65d, + 0x6de395cf, 0x9487061c, 0x149a89c5, 0x7e154cfe, 0xdd14246c, 0xb09e20b8, 0x612d7c04, 0xe4789e93, 0x10250ca7, + 0xf051408b, 0xc562b4cc, 0x5d3deec4, 0xab48783e, 0x6eb55611, 0x67f1de4d, 0x96334bea, 0x9fa43cce, 0x71f62414, + 0x8c28f64f, 0x3fc13f13, 0x442e4466, 0x5127003f, 0x5661e395, 0x12509c77, 0x4e7ba787, 0xe8300fbe, 0x4c83413b, + 0x0d84974a, 0x2076e33f, 0x78033200, 0x6195fae2, 0xb5e85f87, 0x65dba0e8, 0xc5bd8f7f, 0x890a8f1c, 0x06b83a30, + 0x7803a7ec, 0xcafaf3ec, 0xdcda8c99, 0x50eabe94, 0x289dae24, 0x23ddf63f, 0x49f712f6, 0xfbcb84ee, 0x25a69e2c, + 0x7020dac6, 0x26d9c62d, 0xcc3d77a8, 0x610f0d3f, 0xbe5cb022, 0x40f75390, 0x9821ba0d, 0xf592aa97, 0x891a5e6b, + 0x9144dc9a, 0x038aaf1b, 0x40487367, 0xc40b3ad6, 0x24134b70, 0x3953e3a6, 0xac52bd53, 0xea3585f1, 0x13284157, + 0x2ec4dc34, 0x2ed13139, 0x009cdbfb, 0xc0ca355d, 0x75ad87cb, 0xa26a047f, 0xa6c02904, 0xb3a76251, 0xee5b80ff, + 0x5154ec92, 0xd40f9067, 0xc7ebdc15, 0x790b71ff, 0x2ee9ea3d, 0x790601b6, 0xdbdb8c06, 0xdf6bbfa0, 0x83277ef3, + 0xe6b6f1f0, 0xd61b15da, 0x67af7958, 0x42dbf2d6, 0x0c7851ac, 0x570be063, 0x709636d5, 0x74da81ed, 0x0b932a64, + 0x9bd5e0e0, 0x0bba5d45, 0x6ed8238b, 0x030584ee, 0x0585d03d, 0x80348247, 0xa8a3f1d9, 0xa52cb386, 0xb67081c1, + 0x1014d84b, 0xcd821a3c, 0xad90d4f7, 0xa9f3ed06, 0x943ab75b, 0x23c53088, 0x437d054c, 0x9bd77370, 0x3c42e08b, + 0x75c8de01, 0xb642576f, 0x2df3f2e4, 0x63979cf2, 0xaa0592ae, 0x2b3f2178, 0x942ded3f, 0x6304f37b, 0x1648a88c, + 0xe1b023ea, 0x5f5f95ab, 0xc214cf73, 0x186bea94, 0xee7e4dd3, 0x16564044, 0x7bb5aef9, 0x4cdc92da, 0x9599d016, + 0x0ba88493, 0x17443f28, 0xb0449f7b, 0x33da4ba2, 0x3662c32c, 0xcad30270, 0x99478665, 0x562f4f47, 0x6befb315, + 0x91d4db58, 0xd911f75e, 0xcf848941, 0x89c7c8dc, 0x525f024d, 0x8b12a7b5, 0x08320582, 0x2f24a58c, 0xad7bbdd1, + 0x708fb518, 0xa3b64276, 0x28585c26, 0xd295ed17, 0xc8c453e0, 0xb0771473, 0x681d2dcd, 0x1ab3f80e, 0xe9d2ae2e, + 0x9801c250, 0x23941586, 0xaf27f7c9, 0x37e7c24e, 0x0934dc66, 0x119037cd, 0xae4f795c, 0xcb048b4f, 0x339abbe8, + 0x3fbdf5ba, 0x6a5e346d, 0xc74a155d, 0xd1440084, 0x5db33bc0, 0x33f3cc15, 0x05a5c6a4, 0xd4879b9f, 0x15569d76, + 0x424d25fa, 0xa86fc49d, 0xaf5c9685, 0xc3aec766, 0x066e323c, 0x51b7abed, 0x5c594335, 0x2a840047, 0x4cd58727, + 0x91a400e6, 0x4a075d3f, 0x08fb4295, 0xba85d64b, 0x1f1e4af1, 0xd5bca7a1, 0xd2adc494, 0x895f769a, 0x4cb8bf8a, + 0xfb8d5dd8, 0xbeb6f0ce, 0xa2de335b, 0x116e5127, 0x68556bc3, 0xfc12f413, 0x8a51890a, 0xca192022, 0x59a1666c, + 0x65f11832, 0xb135c38a, 0xcf792b63, 0x648a14e0, 0xf0f392d5, 0xe736d938, 0xf6023442, 0xd2e2c317, 0x7843e30d, + 0x089b719a, 0x185f279c, 0x10b8c0dd, 0xf2c1b472, 0xb34cd435, 0x56f239ba, 0xc962ff43, 0x998dafb9, 0xe70c0711, + 0xdb2e1a4c, 0x7d4442ae, 0x19062d71, 0xef8656c1, 0x0730b433, 0xc7202320, 0xe52c90c8, 0x7ec80a71, 0xc9ef1037, + 0x545eadb7, 0xc1e24d45, 0x385905cc, 0xa92830e1, 0x0b16eb0e, 0xf4c1055f, 0x17b85146, 0x283cbe76, 0x57021b66, + 0xf619fd54, 0xcbbdc19c, 0xf38d21cb, 0x874ab783, 0x55700879, 0xd2653fe9, 0xc733f8da, 0x74e69765, 0x792b4478, + 0x10481d49, 0x36f16093, 0xd50054ae, 0xb2187cd1, 0x945cfc4d, 0x8334d4b5, 0xf29574c9, 0x2cee2bc4, 0x415abf3e, + 0xc2d3b6a7, 0x2f09bdcd, 0xd7afd3fb, 0x81e6283e, 0x7236dc3d, 0x32d9e0bd, 0x6c351a17, 0xedc93ab2, 0x9ed539a6, + 0x3644d519, 0x32a224d8, 0x1b203dd5, 0x1f9a93a9, 0xc1f6f947, 0xb2aeb081, 0xeacc1aa8, 0x41db8bc4, 0x666fdd0d, + 0xf295a774, 0x07d1fab6, 0x78142b25, 0x29e77cf6, 0x4805f61e, 0x0f950675, 0xcb72d86d, 0xf8011c68, 0xe8511be5, + 0x03db9d32, 0x1b7b636a, 0x6b44edab, 0x7182a570, 0x5e249bd5, 0x4802f2fd, 0x074a493d, 0x79f20de7, 0x3dbbe950, + 0x3ad2b297, 0xbc881f2b, 0x2ab95d48, 0x09a86b60, 0x7830e9f1, 0x6e9da11d, 0x3cd3ed36, 0xde7a36dd, 0xfcc4db03, + 0xea53a861, 0x0667c6f6, 0x8f890cd3, 0x08e95947, 0x6e9bb52d, 0x618b6c0f, 0x54cfd97c, 0x44418afe, 0xad2ebcf4, + 0xb247a8f2, 0x831c0094, 0x44716548, 0x796f061a, 0xd6ad5f8a, 0x30680c08, 0x45cc39a4, 0xbc105c3c, 0x21831bff, + 0xfb722bfa, 0x27445138, 0x2ad97ad7, 0xef2d66e6, 0x06c0e4ce, 0xc57f15a4, 0x576aacc5, 0x9c8a005a, 0x8d1dd28c, + 0x40c754bc, 0x0dcca020, 0xb56a68d5, 0x087048b8, 0x109c2390, 0x6574135d, 0x1cca52d7, 0xa9d47d7a, 0x9bc7ad60, + 0x6ea01d88, 0x99919d5f, 0x6b9fad56, 0x6e5784b7, 0xd5253df1, 0x67258e76, 0x7d11221f, 0x73c7df3f, 0x1d5b9309, + 0x83187b4d, 0x2e69f521, 0xc59e177a, 0xa3b740dd, 0x8d64e531, 0x0f22df67, 0x8cbb1bee, 0xb0e6d269, 0x685d6ca4, + 0x3c40d73e, 0x4b08c305, 0x36ea92d6, 0x4159182f, 0xc1cac3e4, 0x0fac06c3, 0x5e6356f9, 0xb0cb9ce7, 0xbafc3bf8, + 0x9a61f9c9, 0xb94ba4a1, 0xaf2da6b0, 0x28a025a4, 0x604a832a, 0x1dc12781, 0x987ef7bf, 0x693d0cc0, 0xade768fb, + 0xa0ea6f8e, 0x1a7eb49f, 0xfbf93ddf, 0xec5c116a, 0x47278380, 0x4a177687, 0x0e08b9b2, 0xedee3e51, 0xa0d07a54, + 0x5228c5f3, 0x25cf3a1e, 0x6ad4219c, 0xa23e11c2, 0xcdbd818a, 0x0b19b118, 0xe902e912, 0xde62aa94, 0x6f650f7c, + 0xd0932b06, 0x81b3077c, 0x4a7a754f, 0xf6032e0c, 0xf1f104e3, 0x5f8439ca, 0xe11a5c80, 0xa03b29a8, 0x154b1823, + 0x39a42130, 0x689de830, 0x1ed906af, 0xc2d3f0bf, 0xddda157a, 0xc63a7484, 0x61ee42c5, 0x1463fb8b, 0xeef9abd6, + 0xae33d3f2, 0xbdc01ff2, 0x8f1ad1e2, 0x77b93ac1, 0x4a045dd1, 0x8aca5c66, 0x73843987, 0xefa65b2a, 0x8d67aac9, + 0x5faaa557, 0x3fd1c542, 0x960c104b, 0x31fda7e6, 0x9fecd4ea, 0xd162c3f7, 0xc2b06c94, 0x823c8aaa, 0x8ce449de, + 0x56adec88, 0x8d295136, 0xbd5018f7, 0xdf22cb4e, 0x46b27bb8, 0x105a7ef2, 0xc9479833, 0x5b120f48, 0xd09235a8, + 0x2b8a7e29, 0x66b33adf, 0x546cfe2d, 0x558bd2ee, 0xbf063a72, 0xd7145277, 0xa88f953e, 0xc79ca609, 0x2ec79b45, + 0x2c5b2125, 0xc3cb0c91, 0x73083a2a, 0x7127271e, 0x76a4228d, 0xe2acab5d, 0xb0406009, 0x3ab07a39, 0x30d6481e, + 0x57ba87c4, 0x08465861, 0xfedd27fa, 0x74334ed7, 0x3aa9dd59, 0x9633de2c, 0x9253e4c8, 0xc612be76, 0x5facf731, + 0x302cf967, 0xce337e2a, 0xe7193d1b, 0xa81a9a47, 0x680349c7, 0xd0f1da2d, 0xa04e2dbb, 0x8552d74e, 0x43c41d3c, + 0xb8d986c8, 0x1e660a6b, 0x3db06fb4, 0x6a13eaa9, 0x3bc3bb14, 0x2c565494, 0x71776dda, 0x7b5dcfcc, 0x69717b4e, + 0x84851c58, 0x12cf1e6c, 0xc320caf8, 0xf0d8808c, 0x0961e655, 0x455b9f9c, 0x252b5cf4, 0xe820eeb1, 0x14a0625c, + 0x811d0007, 0xdca81bb4, 0x642bd007, 0xdc58b505, 0xe9d28345, 0xae096d1f, 0xed261dee, 0x57ee575e, 0x9bb46376, + 0x27387f89, 0x7d23c46c, 0x0abb0fb9, 0x51d8510e, 0xeb8a4d6f, 0x8efbd59a, 0xc5be01e2, 0xd80ae020, 0xc5ab8f84, + 0x9f34f9de, 0xf68b7695, 0x80fd7fdb, 0x66fd7f31, 0x0f5cc610, 0x6c20fbed, 0xc7eb349e, 0x2055cdc0, 0xfae209dd, + 0x33af199c, 0xffcf38f5, 0x4294bfd4, 0xddd24952, 0x8175c510, 0xc38ec919, 0xed914519, 0x1f5e103e, 0x5237df3b, + 0xc35813be, 0xef352fa5, 0x7c500ef7, 0x36816b92, 0x08e71e93, 0x820d4617, 0x59a264ca, 0x4324f836, 0x2a9e5c90, + 0xc5163307, 0xf25738c8, 0xf8fb576d, 0xee809ce5, 0x534c662d, 0x315f7e39, 0x3ca62446, 0xc60512f7, 0x803644f3, + 0xca50746a, 0x8c8eb135, 0x05461157, 0xd2ea2bb4, 0xd83a9608, 0x9c4069a4, 0x48e5614f, 0xcf030af0, 0x1e97a726, + 0xfe5db970, 0x1b7b41af, 0x2c4ca452, 0x43276316, 0xb486bd13, 0xbced5189, 0xf04c4102, 0xc2822c5f, 0xd4d85171, + 0xe1f0f751, 0x8763c651, 0x9e49c5bc, 0x5dab126f, 0x188b931f, 0x39a2ee60, 0x80fababd, 0x49d6ee8c, 0x9dffdfdb, + 0xacadd71d, 0x7634918c, 0x90094a25, 0xa416ce01, 0x11eb5962, 0xc85fde9c, 0x467119d2, 0x4be567cb, 0x0b149c1b, + 0x34bb9c6f, 0xbe76708b, 0x90d14e68, 0x5b047755, 0xfd3c7def, 0xe8f2ec58, 0x29290c1c, 0xc01d18f3, 0x5c1e83a5, + 0x11c17c2f, 0x8938c94d, 0xaafb9864, 0x73e603ad, 0xbbb741d7, 0xafa2e7c0, 0x5b4de112, 0x449ff8a7, 0x88fbe416, + 0x989b13ec, 0x6c97a49a, 0x97025f6a, 0x3f8829b2, 0x1e4fb30d, 0x9f61dff9, 0x65414a5c, 0x3d3c2276, 0xb498bcf2, + 0xea757c35, 0x2fe262f7, 0x942e8434, 0xb875a025, 0xecc02766, 0xebf97914, 0xd82e3aae, 0xf051f0c7, 0x47cb077f, + 0x54f8fb0f, 0x2c26f917, 0x3492d8bd, 0xff62588a, 0x1660332e, 0x81062ce5, 0xd4621509, 0x7e5501aa, 0x693106b9, + 0xeb7dc346, 0xd5dad256, 0xd552c472, 0x2f680c76, 0xa42ee782, 0xd1d453a2, 0xafce40cf, 0xe77f58dd, 0x9339a676, + 0x9aec0d3a, 0xaa83ced3, 0x27ec8c69, 0x967ce46d, 0x09d7cc8d, 0x73df0f5f, 0xd137f97d, 0x24ebe8fc, 0xb295e735, + 0x39181099, 0x24dd7238, 0x294d7f0e, 0x75592647, 0xa2753587, 0xcfeb7b2b, 0x1b5d79c7, 0x67cfacd9, 0x4931db42, + 0xb8a24099, 0x3d9141b5, 0x31f9cbc4, 0x395d50b1, 0x2a95d608, 0x9bbe6add, 0xe28dd9ba, 0xb3f2e19a, 0x9f3c2aeb, + 0x38527f78, 0x8ed200db, 0xdf3b31c9, 0xa9e1e0c8, 0xe447c058, 0x514bed5b, 0x9ee2217f, 0x3c4e2d23, 0xcd5b6c5a, + 0xee2733c5, 0x21f89404, 0xe75708e4, 0x04840eba, 0xa80735d0, 0xcdfcfa95, 0x2f25fc67, 0x9d524430, 0x383be4db, + 0xa2bea217, 0xe0947a53, 0x34014db3, 0x64e02a6d, 0x76126ab7, 0xfaaf8781, 0x115efda2, 0x38fb35fc, 0x2448be3b, + 0x5eee2044, 0xfac1fb3e, 0x9997534e, 0xda187a15, 0x8a378928, 0x0eae14a0, 0x8ea5c6b0, 0x31124aff, 0xa43ba09d, + 0x04570805, 0x6f65d82f, 0xe2bf1977, 0xe4b55d6e, 0x076047ad, 0x854d29ea, 0x13232496, 0xc1207cda, 0x121018ac, + 0xa8fd1c99, 0xc87090c4, 0x1ff50b38, 0x22ebfdb9, 0xe8d43448, 0x877a6736, 0x57995879, 0xfd04eecb, 0x13cdb309, + 0xd0b8a870, 0x01a09abf, 0x8718ef62, 0xd19c255a, 0xb0488ae1, 0xa5d7c396, 0xa5ed0462, 0xa5de0629, 0x2f30d669, + 0x422df23f, 0xccced628, 0x94cae55a, 0xd0385cec, 0x669c2cce, 0xb04c56ac, 0xb4cfec54, 0x0d02ede3, 0x7d25ee16, + 0x4d66d992, 0x783cdab8, 0xb47ba02e, 0x55d2bfac, 0xa3d9a854, 0xa7b8a2ff, 0xa71ee807, 0x9539b035, 0xc40c73e0, + 0x2ace7f9f, 0xd2749433, 0xc4d91146, 0x06cc7025, 0x54aa18f7, 0x7eef458c, 0xef131b0f, 0x44ad989e, 0x8f817f15, + 0x0467fede, 0x3091e238, 0x3be806bc, 0xffd75f86, 0x0a9b9ed1, 0xae9eff73, 0x5993e137, 0xad6fc428, 0x4cd97259, + 0x1501fa46, 0x41eebba1, 0x77f171e3, 0xaba94723, 0x106a454f, 0x15c63da0, 0x09b22f14, 0x3165e168, 0x55be7e8d, + 0x5d371925, 0x675b16b9, 0xcd2ebf73, 0x8c07f94b, 0x645f7ad0, 0x9b3a4d69, 0x60cb7685, 0x61c294ec, 0x9c453f5f, + 0xadb2081d, 0x9f648e0e, 0x4d2fe297, 0x6a01d3af, 0xecadcfe1, 0xc9c1b7f5, 0x418d21c2, 0xaee1ee00, 0xfa7d4874, + 0x6756ecd0, 0xc52a9087, 0x23fed0b4, 0xe352f071, 0xc88bab8d, 0xc9e6e65a, 0x5d447f10, 0x35b4a375, 0xb85fefb4, + 0xf3a6f37c, 0x14b48f1d, 0xb4d49ea1, 0x4a5473e9, 0xd8236f79, 0xbf7a71c6, 0xf5599b36, 0x1fa1405e, 0x1c437995, + 0x1652d52c, 0x17b353be, 0x93a6b7ce, 0xa690f599, 0x9ff1ef85, 0x102faaba, 0x8ffa56e1, 0x61e9b9a1, 0x2ea42974, + 0xb031fc6a, 0xc9dcf503, 0x0598de91, 0x6a7e7350, 0xdbc24b11, 0xe817a151, 0x00ee9e1a, 0xb9a17f8a, 0x74d9ca6b, + 0xa3fdd4e9, 0x5c0a77c6, 0x6f38aa96, 0x6392a38e, 0x45de2681, 0xbf6cac78, 0x08cc8e8e, 0xa72c17f7, 0x81201c20, + 0x51557ac7, 0xee2cb75f, 0xdec62a5b, 0x16e64f51, 0x5c4d2277, 0x0e0c36b3, 0xecc38f88, 0x47c019b5, 0xd12e46bf, + 0x90d65b7c, 0x5f0c1fd6, 0x0194f500, 0x3f342a63, 0xa4e92ae0, 0x49d98392, 0xff9a8862, 0xaae7f7cc, 0x7366f3f3, + 0x82f047d5, 0x35bf32b7, 0xf066f7af, 0x787b926c, 0xba31a8b0, 0x2eda0067, 0x66709738, 0x9764e26a, 0xaf490104, + 0x543596b0, 0xeb27dfd3, 0x0a25032f, 0xe5896d0d, 0xb1bad9c0, 0x5cf7381a, 0x9b2ac676, 0x2ebd9d98, 0xd72afe47, + 0xe11f23b3, 0xc475fab6, 0xee0c2a95, 0xb5f738e0, 0x8824fc1a, 0x7afd9c27, 0x70a80004, 0x952a1fd7, 0xb1a93973, + 0x62415f88, 0x474a422f, 0x4669a708, 0xcc01fca3, 0xdd9ab86e, 0xd829800c, 0x76c2c0fa, 0xe423ed01, 0x9fd12470, + 0x3feeecaa, 0x39b1d8db, 0xdf57d18c, 0xc9b8a6b0, 0x573f115a, 0x233645c1, 0x7d598fea, 0xda3129a8, 0xa5b36576, + 0x6b6be846, 0xe54ebd9a, 0xd66a7fa9, 0x6adbfb1c, 0xdde4d791, 0x385859e5, 0x6f3f684e, 0x5827c93d, 0x409df2a2, + 0x7c66e348, 0xed6cd8b3, 0x8661067e, 0x8b3324ea, 0x0b875a6f, 0x41058e82, 0x93ff1a2f, 0x62a4ff51, 0x08ad1bb1, + 0x7f0c8ab3, 0x91c5fa89, 0xcab5fd78, 0x31be9455, 0x4da30407, 0x4e810856, 0xc83a67b6, 0xba5237c9, 0x600a619c, + 0x64545227, 0x0c77219b, 0x5cc7dd66, 0x5e6f5666, 0x4cb76db5, 0x2cca073e, 0xeca231f3, 0x35e16fc5, 0x169b5230, + 0x87300494, 0x04a2bf41, 0xa731bb7d, 0x3b75f04f, 0xab1dc8e8, 0x59707354, 0x24a48567, 0xd6b7a1d1, 0x5b292e3c, + 0xce1c1b7a, 0x051b34c4, 0x4f0de0e6, 0x1f28af99, 0x4c3f07f2, 0x90d97174, 0x1a9738eb, 0xdfa8b92a, 0x53bb02cc, + 0xaaf35da9, 0x1f3c02f5, 0x0ece948f, 0xe572378c, 0x986fc903, 0xed4185d1, 0x19a1a0c0, 0xf3a430c0, 0xf00c4f66, + 0xed4868e5, 0xaa67724e, 0x653475bb, 0x7322b6f9, 0xcaa9eda0, 0xe289ac5e, 0x482fe8b4, 0x8d517010, 0x7069fbcf, + 0x1415500e, 0x3e50beb5, 0x0c1a6ed8, 0x7dc7ab37, 0x3304089f, 0xbed19e15, 0xfad60af3, 0x2d3bf329, 0x05b2e8da, + 0x21c0bcd9, 0x20c35ea1, 0x35d985aa, 0x654eb9cf, 0x9c4e60c0, 0x54a7badc, 0x159ad08c, 0x73e1a168, 0xe3cd6f60, + 0x3c9a7a05, 0x05699d21, 0x27dee3a6, 0x8bfda379, 0xacf2f745, 0xa2bff1b1, 0x7518f078, 0x1d464481, 0x4407e7b9, + 0xd08b6e37, 0x016b47b7, 0x33804604, 0xfd586477, 0xab41994b, 0xb6724053, 0x70502129, 0x723f2625, 0xcf975a36, + 0x426a7175, 0x07744ba1, 0x69e78cb3, 0x1f6b53e0, 0x6aa7eb35, 0x19602f75, 0x1bfc5c1a, 0x325e0068, 0x20fdd256, + 0x9a8431a1, 0x0d471ab3, 0x1d0c5b4d, 0xccbebdfd, 0xf7289358, 0x0fa7d9fb, 0x7006e39a, 0xb5710b57, 0x3ad8eadc, + 0x3f3f5593, 0xbc5b83fc, 0x945f812f, 0x21ac8c30, 0x2df5ede2, 0x9c760b4b, 0xd847cea1, 0x90b7135e, 0x8e73cc9a, + 0x3eace86e, 0x916ed5c5, 0x22eb15c5, 0xb568aa01, 0x217eaea8, 0x5bac58ba, 0x27e49bf7, 0xab084bc8, 0x76d9bbb8, + 0x7d37629f, 0x4b020a8a, 0xf332530d, 0x1e8e390e, 0x08ab0d45, 0x46d6a220, 0x1e39818e, 0x55769ed9, 0x38725f4f, + 0x0f9394e4, 0x18629fd8, 0x87a0b018, 0xc65c1694, 0x786375ca, 0xf5388476, 0xa386c5a1, 0x068b97f9, 0x1bdb3016, + 0x5de3716e, 0xc53449a7, 0x3fb60bb3, 0xc97f6fbe, 0xf48a44be, 0x08a84d58, 0xd1e6c7d8, 0x1d53bdb6, 0x2ad97b17, + 0x6caf7ebf, 0x60185284, 0xfad13877, 0xc2488183, 0x5bba2299, 0x4f6be581, 0x7d7cddf6, 0x032b45da, 0x5280d68d, + 0x3c282f48, 0x565fa9d6, 0x3e4c918a, 0x760d33d1, 0xe9adaf18, 0xc1cb30a0, 0xd855d09f, 0xb7bd07c2, 0x2e35f816, + 0x9408bad1, 0x984b2e36, 0x07da4a5c, 0x27e0708b, 0x1f66693a, 0xf837e34e, 0xb88f8328, 0x7123da19, 0xb50a8653, + 0xe1d7b252, 0x6bdf0069, 0xa71f5e83, 0x2248995f, 0xc5767320, 0xf157b2af, 0x93794fa0, 0x97ccc56f, 0x3e2b5741, + 0x6d12702e, 0x5b08064e, 0xa0e6ad13, 0x32bbd312, 0x8ab74f34, 0x3d049dfc, 0x70021016, 0x19d96a82, 0x821b64b0, + 0x89c4af33, 0x0b278c33, 0xf63493ab, 0xfd661d7b, 0xd3b3728c, 0xe06839ac, 0x9d4cb964, 0x07151580, 0x305e37c6, + 0xda7a66f3, 0x1c6604d9, 0x038f2b3b, 0x1c352bbb, 0x63d2db01, 0x96df9099, 0x86c11097, 0x031d97dd, 0xa52006f7, + 0x75b8c62d, 0x70bbdd72, 0x6ab3c651, 0x09b30cea, 0xaf35fce0, 0xc3984728, 0x2ab26cd5, 0xd1e245fa, 0xa5f565e8, + 0x7b35ceae, 0x8c6884ec, 0x8826ae2a, 0xbe7ae791, 0x3188169f, 0x0b7caa6d, 0x8296a12c, 0xf432d088, 0xf07418e2, + 0xee47d8e9, 0x1be5e327, 0x6725f2f8, 0x4d362dd0, 0xbfc6b96b, 0x60bfacd2, 0xc69ab988, 0x95e436a7, 0xc6e10e28, + 0xddeab8d7, 0xc3ec8bbd, 0x2fff12ad, 0xc7c0a333, 0x52cbe3d6, 0xe77426dc, 0x6bd423d7, 0x50b27bea, 0x5db7ec00, + 0xaf57f087, 0xd04735e0, 0xf7cbe9c2, 0x908c4e87, 0x88572560, 0xd34917a5, 0x3035c911, 0x070057fa, 0x307c6654, + 0xa03d42a8, 0xf8dd8b2d, 0x165f51d4, 0xab386b88, 0x574ef7cd, 0xba5ef5ff, 0x51866bce, 0x7a8257c4, 0x74c723ee, + 0x0c56d962, 0x8057ba18, 0x12bb898e, 0xe7c793a9, 0x872ba618, 0x35c11f64, 0x4efc938f, 0xd12b01c7, 0x6b75a888, + 0x178d7556, 0x0c3b94d4, 0x6b978869, 0xc58f81df, 0xce033a45, 0x031c5bc3, 0xf4c9fd86, 0x13a8b911, 0xe7a62e22, + 0xf4752533, 0x8f923d81, 0x5cd2b596, 0xa8ddb8fe, 0xdd14baba, 0x32773602, 0xbae37795, 0xe44bfafb, 0xe4a9301e, + 0x75968627, 0x1d8e2427, 0x918188eb, 0x22636f78, 0x55b6da24, 0x304da31f, 0x99140efb, 0x0e8bf635, 0x5c56d070, + 0x7d32c2d8, 0x02e6237a, 0xc9cb82d0, 0xd109e785, 0xbaf4d70e, 0x6622c499, 0xde73c4ae, 0x2ab7334b, 0xf54347fb, + 0x40d31a5a, 0x922fcb5d, 0xbc7a5c3d, 0xf2f0c380, 0x0b3ead67, 0x88d960ed, 0x6dbdcabb, 0x3e4f52b5, 0xbf44b9ae, + 0xcc6b55aa, 0x262c8d4e, 0x585b5d88, 0xbc5c5590, 0xf8cac72b, 0x9fcc83f3, 0x0e3ccc3d, 0x5c23144a, 0x69428d3f, + 0xe47c3005, 0xcebcc7a2, 0x6592c7c1, 0x765e71fd, 0x8a9890e0, 0xa9405d6f, 0x74fa215a, 0x67e1ed29, 0x60b75329, + 0x4667a8db, 0x0475d885, 0x21619dba, 0x4c32b5a9, 0x2d22197c, 0x357bcf7c, 0xd7520a97, 0x989173a6, 0xab4d355c, + 0xeda4ec62, 0x5fc90ab3, 0x726338ad, 0x4b8ed824, 0x1fbfa591, 0xbe9fb766, 0x54833227, 0x81fcb4f5, 0x4439811f, + 0x0740961b, 0xa1b04f24, 0x57dcb1fb, 0x3f0ba2b0, 0x729e43cd, 0x53718a9d, 0xc4d5d8b6, 0xfd53507c, 0x35777656, + 0xaf2229fe, 0x59f4e5da, 0x81d21e37, 0xc2d038fe, 0x64a2ba8e, 0x64ae3f48, 0x3dd75ea1, 0xdfec6585, 0xdf0426b1, + 0x388bdeda, 0xf83bc8a7, 0x7e32463a, 0x8ce9db67, 0x5a87f8d5, 0x25943d2c, 0x29d40adf, 0xfa2f7c47, 0x600add70, + 0x24d24186, 0xd9f269ab, 0xebbab1ab, 0xeaccf365, 0xdb603833, 0xd058b50f, 0xd820acd1, 0xc87400c5, 0x11d76fbb, + 0xd42ce398, 0x3bdfa4b1, 0x4a919984, 0x90a4948e, 0x47eb7cef, 0x51dde3e4, 0x0eaba152, 0xe56d73f0, 0xde0fb712, + 0xa6268854, 0xab5a3e04, 0x976bc5a7, 0x931c8a3e, 0xcc271a7f, 0x06a31475, 0xe54ceb80, 0x5bfd4b21, 0xb85820bd, + 0x389804e9, 0x918db14d, 0xcc8d7a09, 0x3d96d12a, 0x3c50eb04, 0x0ef0d3ad, 0x2ddc918e, 0x04e58107, 0xe07c0392, + 0x48d3b169, 0xef8e3222, 0x52b17c63, 0xc7e6f430, 0xcde45ab1, 0xe8914744, 0x17163635, 0xd97649f2, 0x4de84ab4, + 0x7d79d791, 0x3eca139f, 0x88c18368, 0xaa2a2b8e, 0xcfc77cf9, 0xb30ce64b, 0xc35ed259, 0x8a9c35c6, 0x0e07b3ec, + 0x63129770, 0x942fbcd2, 0x8a2090fe, 0x6b03ae1b, 0xe88d7820, 0x60a898d3, 0xc501a414, 0x99bde4ea, 0x4373e656, + 0xe4fd2888, 0x1b6b4cad, 0xad5bf586, 0x13c72bd6, 0xb3f9d4e8, 0xcfc8f6aa, 0x4f8b63bd, 0x0c56e1b9, 0x26c38cb1, + 0xabebede4, 0x4566c5dc, 0x0ad5d366, 0xf138b985, 0x559a8dd3, 0x5962940a, 0x8fc287a5, 0xc08b48b5, 0xa8e6b5de, + 0xb0b07a34, 0x107d7c91, 0xe143269d, 0x86c6cbe2, 0x28da1438, 0x4a3d9eed, 0x1d9715d5, 0x56cc31e0, 0xfdd616de, + 0xa7db9714, 0xc1095c90, 0x858a1c3a, 0xa661a9af, 0x71e29a57, 0xe13b56dc, 0x00b47f11, 0x01633bee, 0xeba51f85, + 0xfa9721c8, 0x46aeaab9, 0x1c5e78e2, 0x9d495c95, 0x5c111d98, 0x1d7b5c9a, 0x7ed2036c, 0x6838739d, 0xd4decdc2, + 0x07adb912, 0x1ae22627, 0x6a3a03f9, 0x7ec11941, 0xa7238dfe, 0x01de5142, 0x1221296e, 0x5ee6a9e6, 0x40138420, + 0x29cb98e4, 0x03a46c2f, 0x9418043f, 0x50c32d43, 0xfb5c7218, 0xad934398, 0xa9a7a300, 0x9976a0aa, 0x1f77a604, + 0xe6a9d7dc, 0x9b26b6c3, 0x4d5f0d3e, 0x8efbe0d9, 0xc3d032f7, 0x15e43140, 0xc51b57e8, 0x9b7bc03c, 0x49f2e43d, + 0xd7050697, 0xeec392aa, 0x60388a25, 0xa9c9b29f, 0x420d657d, 0x70ee5241, 0x280e9c9e, 0xbe32f315, 0x39738571, + 0x69b5f1f3, 0x12239f4e, 0x6589bf3e, 0xf664c0cc, 0xa5f7da60, 0x79a26b61, 0xb6494347, 0x457ff86b, 0x2acc5324, + 0x4b1f01d3, 0xa4e45dc7, 0x5f942970, 0x24e87fba, 0xfa7ec672, 0xf1bb52bb, 0x731bc7ec, 0xba36000e, 0xa8f85b62, + 0x0baa18b5, 0xaf2ad0de, 0x32fb8795, 0xa6175f3c, 0x9e266982, 0x196d74cc, 0x6523ce6d, 0x2690a4b1, 0x5641b151, + 0xbe8dea83, 0xc797c1f7, 0xde2fd319, 0xec36b287, 0x9ed3ab89, 0x679e6dac, 0xf9950a72, 0xcd43352e, 0xadebccac, + 0xb243c694, 0x71c39e5e, 0xce095fc6, 0xbc589dd2, 0xc79edbdd, 0x6dbb20db, 0x43569f9d, 0x7c0b303e, 0x2014cd5b, + 0xc762a354, 0xdfc1483a, 0x63bd53fd, 0xdddc9a77, 0x782bd610, 0x9f3d4ae5, 0x03946c0e, 0xb82bdb70, 0x94e2fa9f, + 0x47d8d707, 0x144a7cae, 0x530fcf77, 0x76dbbbc9, 0x8fc75f8b, 0xf81aeee5, 0x83c9baac, 0x6da771eb, 0xaf55ecf6, + 0xa6f6a060, 0x42e438ff, 0x783f54da, 0x91f33452, 0x8bb5e8fd, 0x3991bc72, 0xb1af03c3, 0x59e6cff6, 0x70527a8c, + 0xb684e7cd, 0xc8f5fca8, 0xa52a25ad, 0x8bbcdafe, 0x30682187, 0x0b51dee0, 0x274da48f, 0x2b562113, 0xeee0849f, + 0xdccc69ef, 0x9c6fc2e5, 0x3fbc82f4, 0xc8f4a8a1, 0xd5ef7ca9, 0x2e1c4902, 0xc9005b28, 0x48e2582e, 0x3829c112, + 0xe7d3fa6f, 0xd877e8c4, 0xdacea8a4, 0xa805d044, 0x7d80a224, 0xc4be56bf, 0xc7df28d0, 0xaafb5b34, 0x98369be1, + 0x3e2976b6, 0x31bfe452, 0x0d038735, 0xfdc68a29, 0x0d201ead, 0x4bd3841a, 0xdf9b2535, 0xab1a71fd, 0x63826140, + 0xc6be3d0a, 0x36ce4359, 0x9212844e, 0x13a417d3, 0x6cddef40, 0x315d4971, 0x83a0ebb6, 0xacf8e236, 0xd27f82e7, + 0x6a3244ee, 0x0f7d1905, 0x2510a07d, 0xa1603610, 0xaef69b45, 0x2260e370, 0xb6fede1d, 0x51e5aeae, 0x122d3434, + 0x7bacb575, 0xf9de0b93, 0x1ee87863, 0xe967ee81, 0x5d466be5, 0xf0739caf, 0x04398abb, 0xf15bce22, 0x39c7678b, + 0xb5079581, 0x5cf23df4, 0xc703a0fd, 0x936a89f9, 0xb07e4691, 0x1204ee30, 0x60f6fc98, 0xd3c5ffe3, 0xda2cd1ef, + 0x936bfa39, 0xfb40ed0f, 0x6735c6bf, 0x06d2a6e4, 0x9fe10f1e, 0xe298d1f7, 0xc2d8392e, 0x7703b675, 0xedf2825e, + 0xe57e897d, 0x186c184e, 0x77a9605e, 0xc43c5d31, 0xa5611529, 0x48a48269, 0x1253f6d1, 0x4a97e5d3, 0x1eb11e99, + 0x36d3dba9, 0xd2105b5e, 0x6e471647, 0x779eb4ba, 0xedd56120, 0xea9aa718, 0x4fb719d8, 0x8d3216d3, 0x59597a61, + 0x87988bd9, 0x1a003974, 0xd030eaef, 0xe449b65b, 0x06053e91, 0x511b5839, 0x0e7f933c, 0xfae5b5f8, 0x7190e9c8, + 0xc5e06c3c, 0xc09f5f85, 0x1bed37b8, 0x30bdc2b4, 0x61dba916, 0xf249f113, 0x5285e342, 0xfa1b3b2c, 0x640729a8, + 0x613facb1, 0x455dedb6, 0x6bf8fc16, 0x491a6707, 0xcd2cf0a7, 0xc2c711cb, 0x3518297d, 0x4d27a57a, 0x160ab2f1, + 0xd8a01844, 0x35b2bede, 0x6282577b, 0x4b4048c4, 0x04bb0b7c, 0xf6225b9e, 0x1121b9e8, 0xea8d47ea, 0xfb5f5ae3, + 0x7c10e5c0, 0x8529c1a3, 0x87f751cb, 0x55507961, 0xa42704cf, 0xed15f774, 0xa07cc5ea, 0x431537ae, 0x4eb18fe3, + 0x48f1b62e, 0xae735975, 0xefbdbb9c, 0x483f0be2, 0x1c070c41, 0x34e2b3d0, 0xc71c5c3b, 0xf20f5aad, 0x7199f0c5, + 0xa386ed47, 0xa4f1678a, 0x190ac227, 0x57580675, 0xecd3f917, 0x9e004d43, 0x40fc76cd, 0x81b5ddc3, 0xab9f36e3, + 0xaa032d44, 0x58556741, 0xdb99dcef, 0x130ea921, 0x89f45b74, 0x5d5615b7, 0x9dac6829, 0x6d089cd7, 0x21116b51, + 0x8405f0c2, 0x0cc82dba, 0x58cc2ccf, 0xc8094b1f, 0xa5a8a8d1, 0x68efdbfa, 0x88d27a54, 0x1c646b54, 0x0c5dbd7d, + 0x2e3e1126, 0xaf37015c, 0xd1f5d87e, 0x578f2fcc, 0x505ed944, 0xb2681cd9, 0xe36a1173, 0xbd9969c2, 0x5e72a0f4, + 0x42a698d9, 0xed761a25, 0xb78944c8, 0x32880fe3, 0x4270e75b, 0x0dc8378c, 0x923fea28, 0x187b54c5, 0x80ecabee, + 0x29451d68, 0x83fed778, 0xd8cdc19e, 0x946c465e, 0x449d7298, 0x93a73d29, 0x0729423c, 0xf191b26b, 0xf3b9e173, + 0x4c9fbf10, 0x55dd5f3e, 0xdd6207c5, 0x9242f6d2, 0x2f11be6e, 0x53233461, 0x847f0963, 0x12c66e3f, 0x78f6a17f, + 0x8cf123ae, 0x38b614a3, 0x50c43205, 0xefb59b91, 0x90867e50, 0x22aff92a, 0xf27a9986, 0x1818fdcc, 0xa3145683, + 0x0342f6a5, 0x3e06004c, 0x0d53fac7, 0x1190a6f8, 0x76f5f356, 0x3578c52f, 0x408c87df, 0x48fc28d9, 0x43d4776c, + 0xf3213a63, 0xe44746e1, 0x04d1ca77, 0x1d87c7a8, 0x0d7565d1, 0xb86c5b2f, 0x589cdd57, 0x575b41ee, 0xcb4fb0d6, + 0xe74298c2, 0xb031f89d, 0x618f62d2, 0xf86631ae, 0x89c2e633, 0xd5c8f20e, 0xea9f9a90, 0xbb829455, 0xd7e5cc2e, + 0x907f288a, 0x3d6e5bed, 0x6db94c99, 0xcb80c100, 0x0dfe8580, 0x22a0d191, 0xae99f1eb, 0x0146b7d8, 0xe46f9f55, + 0x83d42898, 0x57d29b00, 0xbad6733c, 0xecbd28c3, 0x74081ea3, 0xbbab0fd9, 0xbe036c6d, 0x953aac20, 0xb997033f, + 0xa00f59c7, 0x7d057cc9, 0x30353f55, 0x6447827b, 0x066ba0e1, 0xe83d747e, 0xe2b1acbc, 0x9b700e2b, 0x5c6cf44c, + 0x64b17b30, 0xb89b67b5, 0x20b8f2a4, 0x718f9cbc, 0xd1dd4239, 0x46dee6ed, 0x78386605, 0x502369b5, 0x2abeebff, + 0x6c1397c7, 0xe98589fd, 0x7434020a, 0x0566ba54, 0x0956fc04, 0xa3af536b, 0x48093371, 0xfcd3728e, 0xdf06bc08, + 0x52e4d3de, 0xd7a7cac9, 0x037f3f05, 0xf0eb2f0b, 0x81d5ed61, 0x50fa2a85, 0x7c3d064e, 0x72c392b4, 0x0f1f6d94, + 0x950e7b11, 0x20ed40ce, 0x77c6670e, 0x3d6b1411, 0x2b5360d1, 0x41cde272, 0x3d53b09e, 0x2190d84a, 0x586584e6, + 0x5cb4bb9b, 0xf822b6b5, 0x5f9dc3fe, 0x1c3e3999, 0xe40bf654, 0x1661b8b2, 0x915d912c, 0xd97ae5a7, 0xde1c81a1, + 0x66629aac, 0x0f579d5d, 0xc707cdfa, 0x2902ee91, 0xefc809c5, 0xcf805be4, 0x662f7737, 0xb8bbcc14, 0x0ef98a0e, + 0x525ae7c8, 0x6b1bbb8f, 0xa4b546ac, 0x9386a73e, 0xdc994289, 0xa6e68500, 0xe12bafd2, 0x3bca130f, 0xb78434a7, + 0xe30d4fb8, 0xd74fdb0e, 0x77cde5f0, 0xa4d35d5d, 0xa61fbb32, 0xccee4336, 0x94e65fd3, 0x31847e8a, 0x6e5dad8d, + 0x431d7041, 0xa5627f79, 0xf6677d19, 0xff80bba5, 0x972f7869, 0xbf9b29b2, 0x9571490a, 0x3c28adca, 0x86c712aa, + 0x1d96d16a, 0x248d89f7, 0x452810d8, 0x65a52b46, 0x10ecb8e3, 0xdc01449c, 0x7bf826ef, 0xf7fc0521, 0x11f1abd3, + 0x010c6ccd, 0x4df6f2b8, 0x9ad7a869, 0x4aacfce7, 0x47526e46, 0xe721d91f, 0x1b8e5d90, 0x50394de3, 0x80deb154, + 0x606dc4ad, 0x4b84e161, 0x1ac9de41, 0xd482debc, 0x9e0320ed, 0x62134cab, 0x046399f6, 0xbd945525, 0xd975a433, + 0x48082eaa, 0x0b6eb019, 0x361e9841, 0x39d875cb, 0x0dae2b8c, 0xcbe556a6, 0x1a0fe2f7, 0x6ae8bdd7, 0x5645ec6c, + 0x10ff1f5d, 0xb36dae0f, 0xc7fb3aec, 0x8c2696e8, 0x59680543, 0x72323ca1, 0x13f55150, 0x45123aa9, 0xaf39c8eb, + 0x7f89a6c6, 0xb8f0d799, 0x3315ceaa, 0xa56444ee, 0xa0a28f8f, 0xb49e78e1, 0x3ce946fc, 0x1e29e7d7, 0x5416a150, + 0xfaf9ba8b, 0xe32992c3, 0xb1c7099f, 0x9140ad0d, 0x7391bcd9, 0x759e6524, 0x1fdb5cc5, 0x0643749b, 0xbfee1852, + 0x58e033c4, 0x49f42b80, 0x6cf17966, 0x527cbec3, 0x1e0e3fe8, 0xd872768f, 0x4ad82a69, 0x0cfec3ba, 0xa08d60bc, + 0x59424df4, 0xa1ac9560, 0xca145017, 0x52496c89, 0xabc8091c, 0x33fca59b, 0xcee4d8d7, 0x0b0bbd6b, 0xcbea3758, + 0xf7c01641, 0xe55e6609, 0x2b41dfb2, 0xbd785e2b, 0x60641ec1, 0x0b30390c, 0xb43b84e5, 0xfd55b5b6, 0xf0e4d667, + 0xd326d45e, 0x280945e2, 0x5a635620, 0xd5941413, 0x4b7f942c, 0xa9c22228, 0x6ccdbc32, 0x13e950ec, 0xda47b2df, + 0xbe925fdb, 0x47c83fb9, 0x5b7f530b, 0xa9748eee, 0x078e4b6e, 0x5cdcb2f6, 0x0162fd16, 0x83d99de3, 0xc62f8868, + 0x03ef2d89, 0x8a328a89, 0x7148adb8, 0x7f62c9e6, 0xaaee5675, 0x6d000b0b, 0xcd09e759, 0xa39b748e, 0x8d974242, + 0x4e2540d6, 0xa5970a06, 0xa6385aba, 0x6a0d4bcb, 0x58a91705, 0xee44d6ee, 0xd0d95d98, 0x8f8828b0, 0x9adc00c9, + 0xdb6e7789, 0xa741e5ff, 0x9e3547a6, 0x114d7e93, 0xdde12332, 0x1c70c92f, 0x241287db, 0x2b1f291f, 0x73551cf0, + 0xfaa81f61, 0x93303299, 0xdaa045e6, 0x832c8239, 0x547685ec, 0x41657823, 0x798b459c, 0xcda69c9d, 0x8494a3e8, + 0x69f1fd68, 0x1c110718, 0xac3dc157, 0x6768f7e5, 0x9fb74992, 0xbe0cc5a4, 0x4e013c55, 0xcd975a85, 0x0d41d200, + 0x5e00fad5, 0xe2c369ae, 0x2af6b661, 0xa5d5b667, 0x43c129d7, 0xd4eb02d6, 0x7c95ecc0, 0x6f848996, 0xdd9510b2, + 0x77a66705, 0xc9f085a9, 0x4ab2a268, 0xa1029475, 0xad635922, 0x66dce664, 0xa1583a47, 0x7631d0e9, 0xa2a30473, + 0xf682b435, 0x85808a81, 0x8b9f157f, 0xdfdddb6c, 0xff82f79b, 0xf8420537, 0x3e1eda2f, 0x3937a017, 0x1cb434b5, + 0x25f8acb8, 0x7c62f7ca, 0xbaf25d6b, 0xb8337332, 0xd605efce, 0xa9a378ec, 0x9987a3bc, 0x54842ed4, 0xcea765b0, + 0x1b382c30, 0xd6efd72a, 0xbcdb739b, 0x657ba0db, 0x0b606b59, 0x141cd349, 0xc32b3a4c, 0x97c458d3, 0x2e25372a, + 0x82ae74de, 0xdb8d7593, 0x0bddadbe, 0x4c6d0001, 0x8425c3d9, 0x1ebf25a1, 0xd2d2b8dd, 0xac0ed4cd, 0x1e5c02fb, + 0xcbacdb20, 0x6011b0c8, 0x9a3d82b1, 0xca33b572, 0xd315cf8f, 0xb73d33e0, 0x236ea841, 0xafafe9e2, 0xefda2e08, + 0x30bc66bc, 0xc90db05a, 0x57b03d47, 0x4c118a66, 0xa43aaa47, 0x5ee048b7, 0x0a92ce87, 0x50102e50, 0xd1093f51, + 0xb583adfd, 0xc22619bb, 0x3a71d48d, 0xb52f9b5e, 0xc3c14a91, 0x2612d93c, 0xb650729c, 0x739dd4c9, 0x9a884d0f, + 0x0c83cef8, 0x13bebb2a, 0x01c5f93e, 0xcea9479c, 0x86accba5, 0x892794da, 0x164e4c5e, 0x3ffb0f78, 0xaa040140, + 0xe9d7c34a, 0x1a2f3b47, 0x216d1677, 0x00e61c4f, 0x0408e05d, 0x77f03e84, 0x50c560b9, 0x581e408d, 0xc0d9d717, + 0xf364ca45, 0xba88bd4f, 0x11cb2890, 0xb63ca3af, 0x00f46656, 0xfbf6a798, 0x7bc200e9, 0x4206d1d7, 0xe8599b8c, + 0x08b21832, 0x4a0eb049, 0x50acac6b, 0x586c3b6d, 0x64dc6f63, 0x47dbbbc0, 0x6d08232a, 0x43bdabd7, 0x1c107f20, + 0x587dac14, 0xaec1b10f, 0xd815d422, 0x269362e0, 0xc5969025, 0x66465ca8, 0x5016d41a, 0x872854a5, 0x5ed3a2d2, + 0x550f65ec, 0x1af01793, 0x3efc9cbe, 0x2ab8cfb0, 0x03430e78, 0x94b7125c, 0x3f5aa931, 0x646b8ed2, 0x98ffc2b4, + 0xc482d525, 0x264c64e9, 0xafe916be, 0x17463d74, 0xa13bbe49, 0x76eabca6, 0xa9d58ae3, 0x027d8bb1, 0x74f6c5d8, + 0x7d757545, 0xdf756d3d, 0xfeea30e9, 0xf26a2949, 0x83abc391, 0x37391d01, 0xe8492635, 0x05566aae, 0x81017fc4, + 0xe83f9cca, 0x2b370e82, 0xf9df6351, 0xd9b21a12, 0x388b2785, 0x0fa567a5, 0xfe60c6e5, 0x8743f77a, 0xabaa9635, + 0xc0e7aa66, 0x81f55c4d, 0x90f67f76, 0x56534ee0, 0x8265a91e, 0xe027a38f, 0x9301d100, 0x2c8f940e, 0xe44a2592, + 0x84b4b57c, 0xed608331, 0xb422967f, 0x273e578a, 0xf7e10536, 0xde7411ae, 0xe4dff145, 0xb6f5d00e, 0xe907b963, + 0xcd910e6e, 0x7bde4b62, 0x4ed4fb21, 0xd544e05a, 0x8df589d0, 0xde07aff1, 0x989a4202, 0x8dc5ba78, 0xf3ee0cf7, + 0xe72e6174, 0xce60a447, 0xb34669df, 0xb84307de, 0x2817fcde, 0x97144a26, 0x9460937b, 0x4159ca5d, 0x3c5c5f68, + 0xa962ea9a, 0xe94e2e5b, 0x46baca27, 0x8f25d746, 0x6924b67e, 0x49612181, 0x4449ac19, 0xce87accb, 0x87ce463f, + 0x183a750b, 0x7e41ab21, 0x24af22d6, 0xd70801ad, 0x958363d3, 0x2dafb25b, 0xe26484f1, 0x190dbc10, 0x4c2cb298, + 0x6a3411f4, 0x819e1239, 0x94f012e1, 0x4d8cdc9e, 0x8575b3be, 0xfde05f5d, 0x30dbd932, 0xd70e0f20, 0x7453dff2, + 0x0ff8a350, 0xfebd03c5, 0x53372308, 0xdcad527e, 0xe73e4b4b, 0x6b599d31, 0xb3fc3371, 0x3c6c6848, 0x77293b19, + 0xe7874a87, 0x2a8b2ed8, 0x64d4662a, 0x2e49baf8, 0x8daf0d38, 0xd3f38580, 0x19edd4e2, 0x097ae38d, 0x61882553, + 0x9f7660a3, 0x01cfd6c9, 0xbdb9ec9f, 0xddccde07, 0xb3bd9845, 0x98d98c76, 0x83d804a6, 0x17019627, 0x801dc912, + 0x877dcffa, 0x6e912384, 0x11f357ed, 0x648079d5, 0x42295e51, 0xff8dea1f, 0x474fae3f, 0xcf1b6667, 0xbb9e5a59, + 0xef35af28, 0xa2abf7d0, 0x02153ddb, 0xad1d6ad2, 0x7442eb0f, 0x402d2526, 0x18f05dc9, 0x0ccfe394, 0x0771c39c, + 0x5aef88a8, 0x4e64ab54, 0xd93d7c63, 0xc9565550, 0x0e339fe9, 0xca8ce6e7, 0xc92f8d18, 0xbf5fb5d1, 0x35d7ee60, + 0x767daaa8, 0x3fa93176, 0xae62bcba, 0xc1f0ccae, 0x578ed52e, 0xc94e5797, 0x86f92220, 0xa03aeeaf, 0x89e10fef, + 0x0319fd61, 0xe8f73bf8, 0x8c17c08a, 0x98c02ad6, 0x0f27346f, 0x7dc7e8d6, 0x2af8afad, 0xa846c263, 0x19f1df52, + 0xc0339f1e, 0xbb0cd9e4, 0x6882d5b4, 0x2258f5e7, 0xadba316c, 0x606050b8, 0x298f4e6f, 0xea48497e, 0xb0973193, + 0x9940e49e, 0x6de218f3, 0x6de7ba23, 0x16030c4f, 0x0d92cdb0, 0x8b1cd027, 0x30324e0c, 0x10610b1f, 0x5560ed1b, + 0x7ed35eb8, 0xd994b626, 0x0a4045a9, 0x29d9457e, 0x2d2eb5f3, 0xf57c7810, 0xb5fcfd6b, 0xf15cf13a, 0x01805717, + 0x982ce989, 0x971829a0, 0xcf14f93f, 0xd3455c0d, 0xa22d2537, 0x4bf06176, 0x4e77ea4b, 0xd3258cbe, 0xe93844a1, + 0x0c10c899, 0x7374c3dc, 0xf89c236f, 0x770b097e, 0x985e82fb, 0x3355f88f, 0xf8002b5e, 0xbf2039e6, 0xe0f25e3e, + 0x11025e39, 0x9ec53aad, 0x831149a3, 0x6b428adb, 0x99fa4212, 0xe95e6687, 0xce20cb5d, 0x07119354, 0xac395640, + 0x9705f085, 0x24dcf89a, 0x3338d268, 0xa5876cbd, 0x85821e83, 0x61ba5785, 0xf1f8a88f, 0x64cc2c99, 0x0e0acab4, + 0xa398d491, 0xb7e64519, 0x2bfd7586, 0x4f8357d7, 0x45f45524, 0xae9c3e2f, 0xab22d6fc, 0x7d3d0a10, 0x50e6cef3, + 0x746058dd, 0xb8f375ed, 0xe5b92783, 0x0b94482d, 0xd326d3a0, 0x739dd7b5, 0xfc0f360a, 0x3964394c, 0x0f427609, + 0xa3f6aea0, 0x6dde5487, 0xc8c525e6, 0x12c22376, 0xe2818dbd, 0x948493fd, 0x68a36c60, 0x97289a1b, 0x6c3edc9c, + 0x3c30100e, 0x66e1788d, 0x49fe51ab, 0xb3a8961f, 0x2e77c45c, 0x86b463ff, 0xf72a8ac5, 0x8c9aade8, 0x2d41a53b, + 0x8f6956f8, 0x8f168aa3, 0x16189fe0, 0x97fd1613, 0x9d68253c, 0x89f533ba, 0x76c1d051, 0xcc21dc55, 0xf123c08d, + 0x0dcba359, 0xab443a48, 0xbdfacc8b, 0x2a036098, 0xae3a4741, 0x3cb3f9eb, 0x572ac3e5, 0xd0a5b224, 0x17f92f42, + 0x31196419, 0x2025298a, 0xbe651fc7, 0x2207a2db, 0xc1429dbb, 0x9b73693e, 0x40b9cf74, 0xe6ac3e41, 0xdc5a5714, + 0x2559b8b2, 0x11c0fd36, 0x2aa76b4c, 0x9c0da2ec, 0x7c60574e, 0x3721f682, 0xa2f7e4f5, 0xacd648c3, 0x23ce77e8, + 0x6c0fffbf, 0xa58d97c4, 0xde28b60d, 0x7192882c, 0xc729292e, 0x75d49179, 0xe96e9b2f, 0xa5fa70b5, 0xb126c561, + 0x5ad5e712, 0x5fcdce5a, 0x66b0dab7, 0x22ccfe2c, 0x7e5301f5, 0x3b9483a9, 0x77b59711, 0xef5a9f4c, 0x581d4ae9, + 0xb3c9a47b, 0x0228446c, 0x5a5d3b08, 0x35c99738, 0x388548a4, 0x3b558f27, 0x9b429d59, 0x698fe36c, 0x9a03e329, + 0x41a62fff, 0xa6964441, 0x5a9033b8, 0x0f6930f2, 0xfdb63bc5, 0xa822ea8e, 0x38827994, 0xcaa55531, 0x0d592f22, + 0x41531452, 0xb84f7a86, 0x1cc61956, 0x4dc0cad9, 0xa3a36a88, 0x2a3e6273, 0x8765ed31, 0x3cb4d9b4, 0x7cdd534a, + 0x6737ee22, 0x9bb0bc78, 0x172604d0, 0xea4a246d, 0x6c904d76, 0x97b876f1, 0xa06bc8f7, 0xd79072c1, 0x33eeb668, + 0xcd53026c, 0x816faef3, 0x03d290f5, 0x1d12463b, 0x0f290b22, 0x1ef180b9, 0x4660340a, 0x73b07310, 0x8b79541f, + 0xa5614d79, 0x9f5c8244, 0x58ac5369, 0x6f8f0c5c, 0x48355b1c, 0x97ac9a95, 0x5c18013a, 0x3b7985cb, 0x40d528d5, + 0x993d77f3, 0x9f1da77e, 0xc4c1a879, 0x2e234e9a, 0x2671902c, 0x1f45f2c7, 0x40d70e12, 0xba3e6efc, 0x6739ec4e, + 0x318b9e80, 0x4d0e0e4f, 0x194edfce, 0xa4b20f13, 0xa26277b3, 0x1f80b6a1, 0xb2fd2e41, 0x7dea1265, 0x411c7152, + 0x10f290ca, 0x7bf036bc, 0xf31d10d8, 0x0996f3a0, 0x4abd3ee1, 0xc3cb39ae, 0x3884c82c, 0x9cecaba3, 0xcb2606d7, + 0x0b7978a3, 0xc87f0568, 0x86f92fad, 0x21925f24, 0x616c9d04, 0x0913f8fa, 0x8528fbd7, 0xd2a09bb1, 0xc5a1a956, + 0x9d6721b7, 0x29b45acf, 0xea8da72e, 0x336001ab, 0x2c2f6e2d, 0x9f1cedbb, 0x8ffedb2e, 0x7c1cd5f6, 0x570a3d84, + 0x6635862a, 0xfa3e9ea8, 0xf343478b, 0x15888548, 0x8775378f, 0x75319792, 0xd2f8c960, 0x817c97ec, 0x1abfe825, + 0x822e09e9, 0xf3c38fe9, 0x6c44ee1a, 0x69afcacf, 0x9d8543c0, 0x116c22fb, 0x0975e381, 0xdb1719af, 0xbf6330ff, + 0x662c42f4, 0x548a4b5e, 0x741ce1af, 0x6ef0f5fa, 0xdb3bf8a3, 0x3f8fee08, 0x7ff00b2e, 0xc4f55f37, 0xf4f68b28, + 0x4832ec1d, 0x5e72c6db, 0x3cbd3d9f, 0xda490993, 0x7d784067, 0x2abe431e, 0xdf24aaf9, 0xe4418884, 0xc8f57aef, + 0xf4281e29, 0x97a70bd6, 0x55167665, 0xeb6a28f9, 0x8adfceed, 0x8d3e546f, 0xfe6efa43, 0xd2439e7b, 0xa5668284, + 0xc6a36ac4, 0x6054e807, 0x282ce9ea, 0xa7b0f99f, 0xfc6113f1, 0x15d84b62, 0xe3a2257b, 0x693300f1, 0xe18264d3, + 0xa6362dd1, 0x78956436, 0x163486b4, 0xeb3b4690, 0xb6d8a4a3, 0x5ef45ded, 0x2cb40eb5, 0xfa281328, 0x34ac81c6, + 0x513887a3, 0x43cae6c8, 0xafe8e7b2, 0x63e074ca, 0x8546a331, 0x2ddd762b, 0x7aa5de0b, 0x1c072580, 0x9f42cf92, + 0x465a9b35, 0x9a8abe92, 0x22520b49, 0xd500eb33, 0xc36c83da, 0x77efa944, 0xbbb0e0a0, 0xd0a03a3b, 0xd34aa54f, + 0xacf58d67, 0x6cdd5bfa, 0x9f7fa631, 0x47a99623, 0xaff55116, 0x3fff4cdb, 0x2d73b6a6, 0x22e18df0, 0x77328df4, + 0x736a1484, 0x3ca1bbcf, 0x315699d0, 0x48690e68, 0x9f769a5c, 0x192a38f3, 0xf9f95075, 0x49726022, 0x206dbc36, + 0x47a6f397, 0xc66d5e54, 0x3c7cb4c4, 0x63c8cf8d, 0x21400688, 0xea16a7d7, 0xe993179c, 0x000d1e5a, 0x5f3d3273, + 0x929e068d, 0xa7d48ef5, 0xcabb71a0, 0x0f942de9, 0xf01c888c, 0xf742645a, 0x88fe695e, 0x0a84408a, 0xc39715de, + 0xe81668fb, 0xf4b2fce5, 0x2cd293b9, 0x4db3f65f, 0x2ea0e59b, 0x86f6899a, 0x1201f7d2, 0x4346e034, 0xed937103, + 0x3ffe1a06, 0xb427c064, 0xb1c3e043, 0x962994ce, 0x7de2c842, 0x9f2a658c, 0xc7ac8250, 0xed18ed71, 0xe240408c, + 0x2aa3018e, 0x01bfdcd9, 0xb68e0811, 0x74a29b3d, 0x0a5674a8, 0xf9dd6c0b, 0x86fab0d8, 0xa9037154, 0x9e615597, + 0xfabe3c16, 0x0ed35fe9, 0x517ef136, 0xeb9ca8fd, 0x54b38d85, 0x1e7d7bd8, 0xe63599d1, 0x5a72f8f7, 0xf707173c, + 0xb538b726, 0x319f3e32, 0xe8731e52, 0x34844751, 0xb7fa66e7, 0xda0cda48, 0xd8872117, 0xc3657fdc, 0x1e2851e5, + 0x6a983441, 0xf7dfe72f, 0xc60ef62f, 0xe7d673f3, 0xae17196b, 0x452477bc, 0x84338767, 0xf99257b5, 0x863b3fc8, + 0x94e2a261, 0x99d79d42, 0xdc6d89b6, 0x4d41f15f, 0x7b57d818, 0x693d1f36, 0x7cfe8633, 0x49c10b72, 0x0b3c4996, + 0xeca18750, 0xd0c578a1, 0x1f38b24a, 0xa869f861, 0x9b75b6b2, 0x836fe237, 0x63bd1fce, 0xa92ff05c, 0x4fa6a2d8, + 0x21dfa044, 0x09d99c66, 0x550aa1fd, 0x3c25521d, 0xac87edb1, 0xf05bc6a5, 0x1d98f372, 0x86e62002, 0xc314878d, + 0x1159019f, 0x77e431cf, 0xb5561984, 0x3c5e82a1, 0x13e9d643, 0x40638a71, 0xf6a0a1b2, 0x173103e8, 0x0cd7ec03, + 0xb017a80e, 0xc976fc56, 0x970f02d5, 0x297a8e7a, 0xd6541200, 0xbc9b2b7a, 0x33ca6162, 0x5f7487d3, 0xe98f6a87, + 0x1b68c5e0, 0x3fc6f1b6, 0x1f235df5, 0x9e9d7e4e, 0xa65df16e, 0x048cec9b, 0x27baf0aa, 0x6f9c269f, 0xde10a86d, + 0x1236936c, 0x80bac871, 0xa447e203, 0xf0dc85cb, 0xd996e42b, 0x24f2259d, 0xc4ecd6b1, 0x9440b306, 0xe9f8bd8d, + 0x6e1df3ce, 0x06a7dd0d, 0x7d9f435b, 0xe2073b88, 0x5fe8e4a7, 0xf6ee8c12, 0x51326a11, 0x7ee4270e, 0x73e352ae, + 0xb44fb774, 0xa7fb4929, 0x160a429f, 0xcc13fec0, 0x9a9dbd99, 0x8022dcfc, 0x95ab9789, 0x80f8f0f7, 0x01e861de, + 0xff033bde, 0x7ee98bf3, 0xb0eb43f2, 0xec40f473, 0x555dca5f, 0xef6909f9, 0xa8e09d73, 0x8fd21d71, 0xe39dd21f, + 0x62f2be4d, 0xf247c831, 0xa707ac87, 0xb45bbd5b, 0xfa5100ee, 0x60fcddd2, 0x4e28eda8, 0xb008aa60, 0xf8974474, + 0xfe953330, 0x9be0531f, 0x027a5a4e, 0xc12f3d32, 0xe2e2d846, 0xa4bb9299, 0x6b31c82c, 0xcb2540fb, 0x6617298b, + 0xbb4a66de, 0x23d7a82a, 0xe35642f4, 0x7280b2e1, 0xaecc0370, 0x9d4c9c08, 0xb535934c, 0xb6ec778b, 0x8836d8f0, + 0x64a1accf, 0xf262ecc1, 0x4d40ac67, 0x4d9a7ce9, 0x1caca482, 0xfb227eb9, 0x7943edbe, 0x2997e92b, 0x705621c1, + 0xce3d0a18, 0x45ae90b7, 0xf9941840, 0x4cd45aec, 0xfd071c4e, 0x1a3636eb, 0x4030388b, 0xd7c719b0, 0x3089cb14, + 0x52e257f8, 0xd7c157ac, 0x17889b7b, 0xdcbd53ba, 0x97efdce3, 0xab4f1c75, 0xc0722a9c, 0x242b76c2, 0xec51193b, + 0x90593ea2, 0x1e0f3759, 0xb006ee9e, 0xbbcd7ae8, 0xc3574f0f, 0xada3877f, 0xb8feb450, 0x55ed146e, 0x779973ec, + 0xa81016f2, 0xac9face3, 0xae95a4f4, 0x9bef0faa, 0x4ea569dc, 0x98a7c1b8, 0x30b16a24, 0x1294904a, 0x85a21a31, + 0x1fbd64e8, 0xe3548090, 0x9e146f56, 0x1b412706, 0x6c6de6a2, 0xe1183a8c, 0xfa828c55, 0x7d2eed10, 0x278dd067, + 0x7d7a3c0b, 0x81f22ec9, 0x973470f3, 0x85ee1a8a, 0x51715504, 0x02884105, 0xa4c290b2, 0x9b4ba311, 0xd312296e, + 0xb6031014, 0x6d4af8ad, 0xd8988361, 0x09492d26, 0x40229228, 0x881d503f, 0x6c18b2f7, 0xc731a948, 0x20b04b2c, + 0x94b60659, 0x905193a1, 0x2ca186aa, 0xe4c2ec2c, 0xf4faeb8d, 0xa2f2dd98, 0x61b84a5e, 0x0b4ee3bd, 0x6e4a4c26, + 0xa84b0fa2, 0x791b6f3b, 0x2f852cae, 0x9d25dd47, 0x69b60ac2, 0xd1b4a0b4, 0xfc60a4d5, 0x87eaa14a, 0x5f510357, + 0xef2b8a42, 0xf5bee514, 0x47ba9ead, 0x208422e2, 0x11b941c8, 0x4318688c, 0x6c7e1ee3, 0x850a6d67, 0x8d326448, + 0x39a234e3, 0xe13310fb, 0xfe44e9da, 0x7a63ba1a, 0x66430c61, 0xb0d34812, 0xe325d4c7, 0x40d4e65a, 0x1f5f31e7, + 0x556f8d56, 0xf2be4030, 0x0833ca2d, 0xe187f214, 0x32ab9ecb, 0x37931717, 0xbf0026f2, 0xd0685aaa, 0xf3e86644, + 0x09a17668, 0xa18d8b82, 0xb28435a7, 0x45126354, 0xe035802a, 0x7d6fa989, 0xae0bc7b6, 0x9c90847b, 0x0fd73c2a, + 0xa29819df, 0x7bb648a2, 0x3522ac91, 0x1b787b13, 0x9f65f1b6, 0x121ce0ec, 0x44c038a5, 0x885acbf6, 0xfa956587, + 0x3af6bb0b, 0xf241717f, 0x8a97e009, 0xfaf2782b, 0xfe9688c9, 0x4d2b88e2, 0xb01c6ad0, 0x7469a24e, 0x3d9aad0c, + 0x004f450e, 0xe4c7f56c, 0xedc600ab, 0x524c5a48, 0x50789756, 0x88319a5f, 0x53d1bbb7, 0x864ea0bc, 0xe0f0936f, + 0x6cbd267a, 0xe7568537, 0xc44fb35a, 0x1c14829a, 0x4581b33c, 0xc3f7ffa0, 0x9cfcb977, 0xd5e44c4f, 0xb96f6d08, + 0x99b021e8, 0x0fd9c391, 0xb7f73d93, 0x676ebbb1, 0x7c07ab31, 0x1c6e88c2, 0x00ca564c, 0x31007ca2, 0xea515849, + 0x65b799bf, 0xedd33e3f, 0xc9dd18aa, 0x1ecd81e5, 0xbfe86292, 0x734b3be4, 0x8c5c0b10, 0xbacd062f, 0xa5fbeb28, + 0x188cc84b, 0xd675674b, 0xa4f3ab48, 0x9dbb4a34, 0xe1aa83dc, 0x98e0263d, 0xce6a54fa, 0x5154b0bf, 0x4a4c164a, + 0xb78c9f5d, 0x8de41189, 0x3f4214c6, 0x550a2425, 0x34cbc2da, 0x04c8b820, 0x056b82f8, 0x42298606, 0x9506a753, + 0x4a8c8999, 0x74d761ed, 0xe654610c, 0xc95132f8, 0x04b0dca4, 0xb71b529f, 0x54fe7818, 0xf4633302, 0xd7048eb8, + 0xe2eb575c, 0xa04bcc75, 0xa8a175e8, 0xfb2c45cc, 0x5a0e4e3e, 0xeb48985b, 0xbabe3d91, 0x81f10272, 0xbc975da7, + 0x8fe8d000, 0xc6d8a53d, 0x7c9b10fd, 0xb1e9d51e, 0x0e791b51, 0xab404448, 0x0d348fe5, 0x9937c9ce, 0x75a026f0, + 0x05372d38, 0x9028f875, 0xfecaa5e3, 0x38fc274a, 0x2f00cdec, 0x1556c7e9, 0x9f1fa7bb, 0xfb7343e6, 0x2ffd4f81, + 0x0906b06f, 0x0a215b7d, 0x68384243, 0xc1b0b396, 0x5631bc13, 0x6c2c3ff7, 0xa46b8755, 0x056fcfe5, 0x26b83398, + 0x92f6a61a, 0x02452014, 0xbbfe3415, 0x306a66d2, 0x9b0b44e9, 0xbb8dd3c1, 0x2275e118, 0x42554a11, 0x59b1748c, + 0x73b367be, 0xd655b5b0, 0xe6b8d81d, 0x9865a04c, 0x15ec2e26, 0xcee71ab7, 0x929c566a, 0x8a85b9ce, 0x3ffac97a, + 0x9a7a7f94, 0x8b84617e, 0x2be40e7d, 0x21a73021, 0x958cd6e5, 0x74e6099b, 0xe1cb0caa, 0x2b87abd3, 0x065eed62, + 0x29127767, 0x98fdb419, 0x9a47091f, 0x8f8d97b0, 0xd201bd52, 0x4b6b599d, 0xd4c26ac6, 0x8cb884a7, 0xf79e029d, + 0x432867a2, 0x7ebac41f, 0x1ef38d41, 0x91aec4dd, 0xf309a167, 0xd6e49c0c, 0xee15843c, 0xc3d90edc, 0x2382d703, + 0x30243423, 0x5acfe070, 0x83aee495, 0x64307892, 0xca5bb69c, 0xbebcbdb2, 0x3839d35f, 0x19e770c6, 0x32178190, + 0x1f62d395, 0x3d7d04a4, 0xcafeec89, 0x6eb2434c, 0xa621b20f, 0x3d764df0, 0xe8159abd, 0xa985ba49, 0x92bd946f, + 0x27db684a, 0xa268012e, 0xd9e03127, 0x6355df7e, 0x14d16c2c, 0x5d3ad69e, 0x2055216b, 0xaa90a928, 0xe200cb66, + 0x43df925b, 0x3793993a, 0xce42d4f9, 0xdeb2ebb9, 0xc88d80d3, 0xa6f60172, 0x74d26f2e, 0x4e63eebe, 0x71209f7b, + 0x36beb423, 0xa231dfa0, 0xd4c65c07, 0xff05cd17, 0xd8641346, 0x12f7259b, 0xc3a93ff0, 0x76fbac19, 0x1630fad1, + 0x33dde3bf, 0xf2df2253, 0x460c7c63, 0xff5303a1, 0xee533520, 0x7ed656ac, 0x73a89a3d, 0x190d0e59, 0x93401a30, + 0x312a893e, 0xf39b56bf, 0x49f6371b, 0xe977a726, 0xbeff8806, 0x363410d2, 0x4204593b, 0x34160aad, 0x05f4fd29, + 0x886a53e3, 0xf3700566, 0x2d72f90f, 0x567ffee0, 0xa8cb4e8c, 0xbd21a7d6, 0xd6c33f55, 0xbb19cce6, 0x9cbd1a78, + 0xc9fd8d8e, 0x5ee86c13, 0x55279b75, 0x2871c1c1, 0x3fc16cb8, 0xd0aa3cbf, 0xdb4e5820, 0xce7eea12, 0xdf8c7cf7, + 0x5da0da3e, 0xb4ee4410, 0xc48b76a4, 0x08465659, 0x87c2db45, 0x91824399, 0x1efd1dfd, 0x6c583a95, 0x1daae570, + 0x3a889d1b, 0x1221e3c2, 0x47068c50, 0x27853940, 0xb9f7450b, 0x071a57b5, 0x96b933c8, 0xdd49d2fb, 0x3dadaa64, + 0xb55ad265, 0xb65e4dd6, 0xc49092a1, 0xa4da5c99, 0xaa867c06, 0xe95edbd1, 0x19c6bf88, 0x3aea6d2e, 0x0e0bf391, + 0x18dab85c, 0xac88fb33, 0x486aa267, 0x332a6f34, 0x1f34a974, 0x21eb25f0, 0xcf9cc5bd, 0xbaca2697, 0x0a827db3, + 0x1cb73664, 0x49860c03, 0x1fe1d26f, 0xfcfb6a45, 0xcb70604b, 0x1a1bdd3f, 0x249b430f, 0x346083cf, 0x2aae3bd0, + 0xf5f22a38, 0x36a42446, 0xc27f3b89, 0xd981b0ad, 0x4a3d0265, 0x809c1b01, 0xa49e4d87, 0x512efd1d, 0xd1845c2e, + 0x0ae8854d, 0x7edcebd5, 0x2107040b, 0x33d46f19, 0x4dc4ef9f, 0x438b9ed3, 0x92e0b28c, 0x6d1d05ed, 0xcb37656a, + 0xe2e9165a, 0xe471465c, 0x48f0204e, 0x35b0cd6a, 0x006e20cf, 0x2fb0045b, 0x03caec30, 0x46f0fafb, 0x81a9c64b, + 0xbde83d0b, 0xf91bfdfb, 0x132dfa03, 0x474e5850, 0x39355902, 0x986eba7d, 0x588173f3, 0x7006be5e, 0x02bdd691, + 0x7b2b940a, 0x9c60a11b, 0xf35d2a30, 0xab95405e, 0x093cd1ac, 0x072ad641, 0x9dae8dac, 0x7e86571b, 0x05b1f805, + 0xb62aedc6, 0xc557f7fb, 0xdcec4f05, 0xc06913dd, 0xf30d838a, 0x8ef81d6d, 0xd47b08b0, 0xca47d775, 0x86203890, + 0x2a546ad1, 0x22fd83f3, 0x591ae55c, 0xdf36fa98, 0xb6042cad, 0x057b5044, 0x0989653e, 0xaa16ec08, 0xd13a098b, + 0x0d0bf27f, 0x49992cbb, 0xa66da3b5, 0x8c1672e0, 0xb5395a68, 0x60b3274f, 0x4a2d5dc9, 0x2b9b5e0b, 0x122b85dc, + 0xd9af134b, 0xcc7d259c, 0x9414cdbf, 0xfe1458d9, 0xa7a29175, 0xa6428a45, 0xef3095e8, 0xb1e4846e, 0xc89c87ce, + 0x085d902e, 0xff31eb73, 0xcc481c79, 0x03ac6a5a, 0x64eb3969, 0x1df03c0f, 0x1b495db2, 0xbae802fc, 0x48ed8d95, + 0x4822dae1, 0x19ee9a32, 0x517e75e6, 0x15c5bb50, 0x03fc7e26, 0x43a15e32, 0x189460b2, 0x690d2f7a, 0x90b91715, + 0x60b6feaa, 0xa1318a36, 0xdfc906df, 0xa1112049, 0xae5713cf, 0x6add9503, 0x127ba550, 0x70182aa2, 0x134a8cf1, + 0xc6ee3bd2, 0xf7c75474, 0xa9b7cc24, 0x621159e3, 0x2441cd67, 0x151d533a, 0x2dac76a7, 0x6c161280, 0x24b70916, + 0xf44ad27d, 0x14c40bcd, 0xc2029e06, 0xfabd6069, 0x95fc8d56, 0x0eb9085b, 0x60d41559, 0xd8fe1f62, 0xe5797a51, + 0x34a55ebc, 0x4e3dfae9, 0xbeec8073, 0x65a55e66, 0x0e327763, 0xf7278e5a, 0x0733ce58, 0x91a516d2, 0xd35c7b67, + 0xe24b75dd, 0xc98378b9, 0xa06d7c89, 0x3d6d45c3, 0xb62e3163, 0x04b3914b, 0x53ccdf8f, 0xb602671e, 0x46c7da28, + 0xb88612b3, 0x78c4353f, 0x08a7921b, 0x4ddbcd04, 0x6420cea5, 0xa5453940, 0x1bd6e2af, 0xd06afe97, 0xb28c780e, + 0xc256cef8, 0xddc55144, 0x1c630796, 0x428f8586, 0xf9779ddf, 0x75657c07, 0x8b992516, 0x362ff8ea, 0x75ed54d7, + 0x1341e3b2, 0x9bc8ad6e, 0x665f0469, 0x2e966c8b, 0x4ffe4013, 0x48c7a6ef, 0x8afe691e, 0xb3bb6717, 0x89691ae7, + 0x9e4104ca, 0x8ae5fffe, 0x885d19d0, 0xd8a2bfb3, 0x21e6f277, 0x08f00812, 0x2dcc78a1, 0x9508f648, 0x0b8d10dc, + 0x32cf16fa, 0xda0607ae, 0xaa9002a8, 0xaa61dd0b, 0x5c85ac11, 0x6ce6f0b7, 0x925a4baa, 0x8c30a694, 0xd73a4332, + 0xaddbcb5e, 0x1419b188, 0x50496a31, 0x68c5d753, 0x3742e38e, 0x619db8f0, 0xf78d7823, 0x6fe67754, 0xe86cdd53, + 0xcbcb6061, 0x4edb930f, 0xc242f432, 0x5d9c059b, 0xbf134e67, 0xee9cf3d2, 0x95be84e5, 0xe7c6926a, 0x4b99d5a0, + 0x0db91801, 0x1a96a3bc, 0x99fdfbf4, 0x0a3833db, 0xd5ed709f, 0x911edd39, 0x89e3e99a, 0xd863af89, 0x1a23f67d, + 0xb9a62a85, 0xf9bb2f28, 0x7165ec4e, 0x55fadd06, 0x2182de6c, 0xa1100b27, 0x67df208f, 0x3c0db7c1, 0x582e9907, + 0xeb7b2f09, 0x6d01ff47, 0x6a67c6a2, 0xe75b6b08, 0xc70bc443, 0x8a860d43, 0x0ae3d414, 0xece3fccd, 0xaaa85831, + 0xee1d419d, 0xf0b3cd4d, 0xc92a0731, 0x8add5296, 0xa1c65403, 0xfa22e237, 0x6162aae6, 0x795da4af, 0x07081c3d, + 0x4608627f, 0xb284c0ac, 0xd863da99, 0x8b850206, 0x75881f3b, 0x2819a85f, 0x14cf10ab, 0xd74bbb91, 0xf3a50601, + 0xd2fbec81, 0x24c38cd3, 0x39ee2583, 0x32ab66cf, 0x21332a29, 0x2edf55c4, 0x3c31a47c, 0x5b7c413b, 0x5c2c7ef8, + 0xa9f10c0f, 0x7bbf4156, 0x9f64fd0d, 0xe96fb983, 0x0bab8e09, 0x9d349467, 0x0ac3cad6, 0x19b71830, 0xb7e60656, + 0x07e3ea31, 0xb136b949, 0x9a6a0e07, 0x61adedcf, 0xe2bdd0f6, 0x4ff465d1, 0x9f5ec5f8, 0x39cb87e7, 0x0b28d67e, + 0x8689cb1a, 0x1c9e3d20, 0x7b22bd2b, 0x1f8cbb87, 0x78b72f73, 0x40eb8dfe, 0x3e5b491f, 0x20344ca4, 0xd23fb21a, + 0x27730015, 0x4eb6ea35, 0xba01b489, 0xda055a20, 0x1da43883, 0xa936d9e3, 0xfd6adee2, 0x6fbf4827, 0x76c34655, + 0xa4e37181, 0xb7b06c5d, 0xa09cbf45, 0x90bae1c9, 0xf6f8436a, 0xed7930e4, 0xfc58dfea, 0x564fadff, 0xc8aebf75, + 0x44761ce0, 0xcc13c61a, 0xea2582a2, 0x473df72f, 0x96418c32, 0x9ad9ca96, 0x70037daf, 0xa46515c3, 0x0f1a1122, + 0xf5fc4e6f, 0x26d86e80, 0x0a30a105, 0x91fc0fac, 0x3b91371b, 0x897a827a, 0x7aad136b, 0x7fc6f7c2, 0xde7e3724, + 0x24a21409, 0x9311531b, 0x52d1455b, 0x488ff479, 0x33cf748f, 0x759ba887, 0x61481510, 0xceb94ff9, 0x1dcd3069, + 0xcc8b2627, 0x206886d5, 0xe724114a, 0x75ab2102, 0xe5b04c9d, 0xa7d9d08f, 0x8d9a9ebd, 0x52cdbc6a, 0x72cc5c59, + 0x039ff56e, 0xd3faacac, 0x3e40b45d, 0xf016c579, 0xb6814c07, 0xbc3217c8, 0xa31aa1a4, 0x48848ce6, 0xa7216d75, + 0xff0e49bb, 0xd36de7a4, 0xdb7e6668, 0x50d0eba6, 0xe8571bb9, 0x63fcf992, 0x9d630eb5, 0x95e6135e, 0x129b2cb9, + 0x267e63d8, 0x5e66c6e3, 0xa101f7ee, 0xc264f48d, 0x161e019f, 0x1043bfff, 0x629967d4, 0xb60294a4, 0x6a177bb5, + 0x1ab8b333, 0x9e5f1c30, 0xae1ca27c, 0x65fe2cb1, 0x85a1526b, 0x9df4f376, 0x82faac51, 0x94e115e1, 0x4b22d176, + 0x4db13d00, 0x950eabee, 0x30185199, 0x42b6d598, 0xdf7bfcc4, 0x46d13432, 0x867beaf5, 0x092a166a, 0x4692c7ea, + 0x9470c90a, 0xa5f77481, 0xc6dedd3f, 0x122c1f5f, 0x8aff17c7, 0x2fb3f3d2, 0x34fdaf49, 0x7e89c5c0, 0xb413e4df, + 0xb40567b5, 0xa97cb50f, 0x619f42a3, 0x228e39e3, 0x19172b59, 0x6a730703, 0xf2d22a96, 0x40405d38, 0xbcf67939, + 0x5ddb420b, 0xcc996027, 0x98ec7eff, 0x113e93a4, 0xfb4691ab, 0x30e5a1ff, 0x1d054b9f, 0x7f4538d4, 0x569b5c9c, + 0x665e8a2b, 0xd6028edf, 0x0a43c533, 0x9da78fb6, 0x02e32461, 0x506b0caf, 0xdc6b5d79, 0xaff33d56, 0x7c883cfe, + 0xb8f360b1, 0x0f289636, 0xf46358e3, 0xea9b5e62, 0xd0f57f86, 0xc2738f32, 0xf637eaac, 0x9badcdda, 0x9bb3354d, + 0x2f22ec04, 0xe0779131, 0x700d578b, 0xfcca5393, 0x748909fe, 0x99f2309a, 0xea5b8806, 0xe06b77e1, 0xdd866b9f, + 0x2dec0693, 0x8a700d58, 0xee1d363a, 0xe7b5bcb3, 0xf8544a50, 0xdac733d9, 0x73e94ef7, 0x1bc908c8, 0x06b5a596, + 0xb4ad4dbb, 0xcf235a37, 0x869ca864, 0xc6e171a3, 0xba8c1c0f, 0xf3a8685a, 0x2f8d7cc9, 0x3ce2c502, 0xc418bdc4, + 0xd7d8dfaf, 0x66266b68, 0x39debf88, 0xcaaeae91, 0x18cbe2f4, 0x25cf301d, 0x9a77db05, 0x6d651070, 0x2dafca41, + 0x2e866eb0, 0x903d321a, 0x9acc4b60, 0x43f24c0a, 0x6968ac79, 0xc2c8d762, 0x108618d0, 0x981b4222, 0x1c1d85d0, + 0x1f3a667c, 0xfd24b8e8, 0xa5a71f9a, 0x8885dd78, 0x7e35b82c, 0xb5638536, 0x203ff890, 0xd8c17caa, 0x714fd1d5, + 0x2579185b, 0xdfbd8be2, 0x3701e5ed, 0xda90997d, 0xff5c8150, 0xae6476d0, 0x77ededf8, 0x5822e6c1, 0x18e5a035, + 0x78b21ca3, 0xa8c04836, 0x4eeb16cf, 0xeb3dda39, 0xc97e39ee, 0x94649af3, 0x518898eb, 0x5fac8571, 0xde34003b, + 0xeb576c9c, 0x5b8bad0e, 0xf8ebe61e, 0x7b0253da, 0x5bf1da86, 0x2e173dff, 0x9f0ba780, 0xaf07fe89, 0x104bd7b6, + 0x98ab4057, 0xb36e9381, 0xbbd8bfaf, 0xe70c2437, 0xd6be2bc3, 0xe9d0584f, 0xbe07d106, 0xdc37f74f, 0xf39aa9da, + 0xda06a357, 0x1579bff5, 0x1c9821df, 0x84f7afae, 0xb957e333, 0xb9bf7f97, 0x32f27409, 0x9e644bb0, 0x789fd7cc, + 0xda95826b, 0xbf176f93, 0xc527e771, 0xeaedafeb, 0xa3aab248, 0xa136ed36, 0x3efcb4e3, 0x557e8936, 0x10448c1a, + 0x571bf0e6, 0x687b9907, 0xbcd68388, 0x3aaf7fb3, 0x1131f98c, 0x3d5e2ec4, 0x382f8e81, 0x744777a1, 0xff9a0514, + 0x029baff5, 0xe954abbf, 0x54540541, 0xd7e1d693, 0x57eaff1e, 0x9a88c51c, 0xcde04730, 0x4daf5e3d, 0xf712c830, + 0xac705ae5, 0x7457a4a8, 0xd3e5fea1, 0x3002a976, 0xe6792ed4, 0x0171cb0a, 0xba2c142e, 0x39bd5377, 0x754808a6, + 0x44ab9dd6, 0xdf113bbd, 0xb6c2fbe3, 0x3ed6359a, 0x331f0908, 0x9978af83, 0xe5d74407, 0xb51f0042, 0x35e938da, + 0x33e4394f, 0x8ba1e158, 0x53c8f713, 0xc4b8a1e2, 0x81841794, 0xa96243e2, 0x9d8734d1, 0x6c7abcfa, 0x7fe84bef, + 0x8029c16a, 0x0848c60f, 0xf65b96f4, 0xff6c9479, 0x22f844b5, 0xd7bb90f2, 0x82d98dbd, 0x4640837d, 0x4912ce41, + 0xbdbbfaa0, 0x7661902c, 0xb4fb324f, 0x1eb2e5eb, 0x55bd65e0, 0x9b9b0f6d, 0xb0c06ac0, 0xb37e3e04, 0x20faeff7, + 0x55b15f0a, 0x50541bbd, 0x8eb9fa7b, 0x93f2106c, 0xc898803e, 0x523fbbba, 0x07ed609c, 0x85f0eef2, 0xfa8c1c1b, + 0xff8150ee, 0xb2cfb451, 0x3ceaa513, 0x9c3031cf, 0xa6d6bec7, 0x999eab79, 0xcff22a98, 0x1087705e, 0x35365a1b, + 0x7471c0b3, 0x465de3bb, 0x899479bb, 0x3ddce8e1, 0x48b26ee9, 0xd4a3bb40, 0xc72140b3, 0xebf8bfb5, 0x2d46a36c, + 0xf7f9390a, 0x3f1007b6, 0x40c5beaa, 0xb1333966, 0x70e77a3d, 0x1ffec19b, 0x885ccc12, 0x121de2bf, 0x82967894, + 0xa4317e56, 0x65158a18, 0x621e067d, 0x0ef5cc6e, 0x9e061e60, 0xe9eef2b5, 0x7504de2a, 0xfe899cf5, 0x6ed82f58, + 0x988af408, 0xffc00a16, 0x48e699df, 0x500d4321, 0x2c53098f, 0x5c5ed004, 0xbbb640b0, 0x9d83657e, 0xa06b025d, + 0x39aa4511, 0xb5d1d5e6, 0x924cf575, 0x130afe0f, 0xb5281ebf, 0xdcae6173, 0xe90b4fbb, 0x251a7d19, 0xa9a47464, + 0x1ce0be4b, 0xf62573ca, 0xb8ba6a1f, 0x6a1f132a, 0xc5fe5f03, 0x9dc75f2f, 0x18370a10, 0x4d936aba, 0xfeed420a, + 0x9d1871a2, 0xbc591ed4, 0x2df364b3, 0x3d405ae7, 0xc7c5e790, 0x94a82e33, 0xe7a8f0f6, 0xa07d62d6, 0x8b54b9c9, + 0x82ae38d9, 0xd97dce80, 0xc29197c0, 0x867c2580, 0x99d82617, 0x785a839d, 0xd4539112, 0x9960bbb9, 0xae455380, + 0x2959ebfc, 0xa6f71f1d, 0x5ae0c8ef, 0x98ba0dea, 0x7cba98ac, 0xf35c8e70, 0xed2a3f55, 0x5bb8377c, 0x1f9d2eb1, + 0x4e3c27d5, 0x5c44d488, 0x7f1833a2, 0x40a98b2e, 0x455e684b, 0x29b0785e, 0x8962d842, 0x6635a037, 0xdc2f8d00, + 0x45fd0237, 0xe40b2902, 0x5f40d253, 0x433efc86, 0xaebdfb61, 0xf6edce0e, 0x034952cb, 0x240d401b, 0x4fc89140, + 0x5130daf9, 0xd2966f8c, 0x09db7d43, 0x10005a2b, 0xe3b64586, 0xe725b181, 0xad89d745, 0xd4c4a5ba, 0xecb9732e, + 0x165482b6, 0x1155f6bf, 0x932266e6, 0x9b607143, 0xd3b91966, 0x7b3767db, 0x85b37a30, 0xdf1c65ac, 0x554f5f92, + 0x4572fcc5, 0x0aa8ca41, 0x6861085e, 0xf51168e5, 0xd66bd289, 0x6a946ae0, 0x04a077f0, 0xe649b5cd, 0x0ebfe762, + 0x7e59cea1, 0x68616a5a, 0x67a6ec34, 0x7705b9ad, 0x2cd87c1b, 0xa94a9192, 0x7c96dee7, 0x54aa8de1, 0x48444c88, + 0x7f6bedbe, 0x1fd05041, 0xf2282b60, 0x808db15e, 0x951b83c3, 0x00659d9c, 0x9b46045e, 0xde831ccb, 0xc9f225b9, + 0xada4e200, 0xc8e56e41, 0xedbbdac6, 0x38e8da02, 0x096047c9, 0x36b0fe8e, 0x685ebd89, 0x75e2f6b0, 0x3d2065c8, + 0xbfbb11a5, 0x91b498e4, 0x3a82876f, 0x1c08eabc, 0xaa748331, 0xd90b2b96, 0x0b3c506f, 0xe065929c, 0xe6c02138, + 0xb2d8c849, 0xc86fabae, 0x0b0af2df, 0x85398d9c, 0x1fea0623, 0xe84dae52, 0x4699d4c2, 0x7cc0cd59, 0x67d1c500, + 0x5f032a54, 0x145aa19b, 0xedc475cc, 0x73d3865b, 0x2d7f768e, 0x9a9453a3, 0x95713478, 0x106bd6d5, 0xf6fded2e, + 0x41457cad, 0x5cb01c14, 0xc01b7d2a, 0xc20025fa, 0x6fd5700c, 0x1ff626b3, 0x0e322f52, 0x582ce43c, 0x8c978451, + 0x261e806a, 0x1e7643a9, 0xda2a8f69, 0xd06f2972, 0xcf3c992d, 0x0ac8a0cc, 0xe3bbc0eb, 0x5bbd779c, 0x56a0944c, + 0x3262d02b, 0x17533f50, 0x4b90f414, 0x763af541, 0xea764500, 0xa06af9f7, 0x4851ad0c, 0x535a46b1, 0x6a9e23b6, + 0x57da3be6, 0x071a107b, 0xec78c542, 0x6cdddab8, 0x71ac7f10, 0xbb749f2a, 0x994b4a20, 0xb49a6e1d, 0xe3b553ba, + 0x6cb2118f, 0xa8106d5a, 0xf35646e4, 0x49b502ac, 0x3cd422bd, 0x80d30219, 0x1bf95771, 0xada31b00, 0x69edad03, + 0xab2d2ab5, 0xddd4847d, 0x52a0f79b, 0x25962503, 0x629235ff, 0xdf6ab6a8, 0x64a11c28, 0x4ad13529, 0xffc321c6, + 0x43b038e6, 0xfabd2d9c, 0x4d766cfc, 0x2dc8fbcb, 0x4addfa35, 0x892944cc, 0xc39d74c1, 0x5c064b14, 0xd9930842, + 0x7d0d706a, 0xa8982c1b, 0x8e69c9c4, 0x0dc5266b, 0x7a95971e, 0x5f9c8dde, 0x523a1633, 0x0f203b8c, 0xc26feab2, + 0x46067f74, 0xf3abd250, 0x9e24c2a2, 0xc7191c19, 0x306630a5, 0x66f29958, 0xbb85ef6b, 0x3596804e, 0xc4161492, + 0x4489818b, 0xfb094f97, 0x47d843ab, 0xe967b26b, 0x10bac100, 0x6cebb37a, 0xb327aca6, 0x67343816, 0xdb680036, + 0x43511417, 0x741e9300, 0x7351107c, 0x8739c3e8, 0xc377a0c7, 0x309f49a6, 0x7c2f0746, 0x9eeb0380, 0xeb1dfdb5, + 0x250e6261, 0xb3cf1493, 0x8b96367f, 0x9c96ba34, 0x6c37e142, 0x1f333ab1, 0x43520b5d, 0xc1f176d9, 0x26736574, + 0x74c3e491, 0x9d26e7a6, 0x7a2d9469, 0x5095003a, 0x79320ec1, 0x8bd68057, 0x9bdd2dff, 0xa8ac2268, 0x9c252a61, + 0xac3c801c, 0xeb982b0a, 0x5448acc3, 0x312760b6, 0x273ec2cb, 0x6c6d0b89, 0xfab373d4, 0xaea3c2f7, 0x875e428c, + 0x3021130e, 0xe148057e, 0xe08054d1, 0xb0964a40, 0x8c08d577, 0x21f58e2a, 0xa3eb940d, 0x91e2477b, 0x4f6e72ea, + 0x733ea98e, 0x7eab262b, 0x9b1a8e84, 0x8168de3f, 0xb0b8a27b, 0x0a5608d0, 0x9de9de27, 0xddd707b9, 0x7f1fccab, + 0x93304113, 0xfd1a2e3f, 0xa61ec9b9, 0xbb3e82c3, 0x1a534ff7, 0x68c9ef72, 0x37dc4351, 0x606e975c, 0x95fdf4a7, + 0xb88d9e6e, 0x45d4786f, 0x8f64ed4e, 0xd01784ce, 0x8dedd8ee, 0x95121254, 0xc96e630c, 0x5e5f32e1, 0x25ba2708, + 0x10411385, 0xc2b3cff0, 0xc8688767, 0xcdec88b2, 0x2a1f771b, 0xf1fbba4f, 0x3e285263, 0x7420579a, 0x07366cd8, + 0x84ef8c6d, 0xdfe6cc11, 0x440e81b1, 0x23bc3537, 0x572be06a, 0xad2888c2, 0x110d5dae, 0x111204ca, 0x0d54353b, + 0x539089e2, 0xe547a1c9, 0x353e7cc0, 0xe0faeb7e, 0xee595223, 0x4868e0ef, 0x02bcba94, 0x58ea3a07, 0x5fddcd3e, + 0x3a65660e, 0xf9a0de13, 0x5e7cb590, 0xacdbf613, 0x42730853, 0x8c087d08, 0xe0ed8d81, 0xac411bd8, 0x8447b83d, + 0xe6c8cf72, 0xd651613f, 0xf3737239, 0x0c68ae0b, 0x9ff65fbd, 0xe80d4204, 0x84e3a3cb, 0x01b7c9fa, 0x7f467aa4, + 0x2b38da57, 0x30551dbc, 0xd8dd6d2f, 0x2772d854, 0x642f668a, 0x492eeeb6, 0xc086e54e, 0xf3ce070c, 0x934ae87c, + 0x1b3b00ad, 0x7a6c2274, 0xe9bb5417, 0x78d95fd1, 0x930d5342, 0x175bca29, 0x2d74ab77, 0xc5def2a9, 0x4be27a63, + 0xb4a1a1db, 0x889b3c8c, 0xaf7991c5, 0x711f9b5d, 0x05a78955, 0xf7d6aa5b, 0xbd2ea2f2, 0xbed55cbb, 0xeb0a32ae, + 0xa8bbc716, 0x9e32ddc5, 0x767dfbe9, 0x9a89702e, 0x74e8de46, 0x52aafb9f, 0x41ecd195, 0x57eb8a0c, 0xb6076742, + 0x60dced6e, 0x2b81aaee, 0x6379b89a, 0x88067489, 0x801b92e1, 0x56839893, 0xf3297eef, 0x75138691, 0x3698e088, + 0x71b225b2, 0x9b52cc52, 0x40d1b977, 0x5814ad6f, 0x5dda2add, 0x7abe9ff6, 0xedb9d459, 0x35cf99e9, 0xd97ec25b, + 0x1018ac0c, 0x5ca794ac, 0x7349e741, 0x64971d38, 0x4a021fb4, 0x9781e527, 0x4b521128, 0xca580e08, 0x079bbe24, + 0xbe2a8802, 0xecefe0bb, 0xea89bff7, 0x65c01574, 0x689d0543, 0x08eada0f, 0x22b95b6c, 0xf0040dfa, 0xad4e14f7, + 0xaa3d29a2, 0x6058e8fc, 0xfa29819f, 0x40227844, 0x1d12f9f9, 0xf6d23f33, 0x7d9d92e0, 0x8f90ed92, 0x02d1379d, + 0x2f1ca204, 0x13790465, 0xab5f1a8d, 0xb5f92f9a, 0xc29c6b9e, 0xb8462492, 0x0b8abd25, 0xbab1a15f, 0x88b4e202, + 0xc4a0a61b, 0x7bf7877d, 0x7a7f8cef, 0x6d434120, 0x2061680f, 0xd68016fc, 0xaac68b21, 0xe892416f, 0xb1b85f1a, + 0x52bea8e1, 0x063d615e, 0xb32b152e, 0x57b634fb, 0x120bd5d7, 0x031eafa2, 0xf7d135f1, 0x8c27f3e8, 0x57392906, + 0xd7190aaa, 0x9bcd68f6, 0x5762e577, 0x127fd662, 0x135fb3fa, 0xcd1d9c0a, 0x38e9c740, 0xd72e97a7, 0x1232cae9, + 0x4854e121, 0x9e10a724, 0x2f4f8cd6, 0x64fa5b4c, 0xbf951692, 0xb5843408, 0x98733410, 0x20589a55, 0x40e4380e, + 0xbeffeaa8, 0x43606d12, 0xe980e2a8, 0x65b9f76f, 0x2f2c828a, 0x1fed5725, 0xa8feb423, 0x19b73b9b, 0xae285af7, + 0x42ba1cf1, 0x92f1300e, 0x43e81f39, 0xe6a445d3, 0x5d21c897, 0x465936ba, 0x72551647, 0x3fe1535e, 0x3a933ad3, + 0xbb737a35, 0xd2d804ba, 0x112f159d, 0x73a84479, 0x2c9477ed, 0x19d679cd, 0x1f50c46e, 0xab298217, 0xd6634a85, + 0x74fd6691, 0x05a50299, 0xcfcf6bb2, 0x7d3bdcf3, 0x90235d90, 0xca03e93c, 0xfbc950ba, 0x1e7f848c, 0x384a3de0, + 0xe3d47df1, 0x09fbeec6, 0x083ddfdc, 0x6a480655, 0x161e6e55, 0x9eaaa66c, 0xa7bf899d, 0xe16bb062, 0xf352a29a, + 0xaa37be06, 0xd47d0065, 0xd743c790, 0xfed7838d, 0x4adb1fea, 0x14948021, 0x0c41ee7f, 0xec7573f7, 0x8f8aeb95, + 0x853ab721, 0x75b50708, 0x3cd34226, 0x7832cc35, 0x8a0bd271, 0x8e1f0646, 0x7d5675fc, 0xc84d63a2, 0x44d48173, + 0x7b31d6ec, 0x3698ac1e, 0x89bf76d3, 0xef391c6d, 0x7b79d880, 0x3d8ba780, 0x8d1efdfb, 0x174dad7e, 0xb5d2dddf, + 0x39caf9b4, 0x3a716ef8, 0xc7171bf4, 0x79662a07, 0x8d3321c7, 0xd8202fe2, 0x2c4c708b, 0x641d22be, 0x7818369c, + 0xfb38ed20, 0xd0be68a6, 0x9d75f8e8, 0x34cd16c3, 0x6c7ded05, 0x9926e266, 0x0731c158, 0xa7885321, 0x7903f5b1, + 0x55ff1fad, 0xd2b0bc2a, 0x4181e1da, 0x55b0ad9b, 0xb1605af7, 0x4c06c33b, 0x06efdb5e, 0xac5d2659, 0x79ac2063, + 0xdc3e2759, 0x74d105dd, 0x3ef1faff, 0x70bd16c6, 0x4f710f8b, 0x3b732424, 0x5095adda, 0x2c0e85b7, 0x19207922, + 0x164e6b65, 0x6301ccb6, 0x2e736850, 0xc7a93311, 0xd4e4ec42, 0x80cdde01, 0xcd33389e, 0x8c40ddf8, 0xa8f82f6f, + 0x00b9f7b2, 0xa73fb25e, 0xc389d1d2, 0xe04eeeb9, 0xfaf397a0, 0x09888624, 0x4c208169, 0xb2f8acac, 0x5c10d3ac, + 0x3d903f9f, 0x1e09208b, 0x44210dd7, 0x659da071, 0x40adf7ba, 0xeebd9461, 0x7332ba69, 0xdfcb692b, 0xc5523f3d, + 0x84df4c87, 0xb148b5f1, 0x19bfd8d1, 0x84019532, 0xa01a0c7b, 0x427cf0e3, 0x5f73ce4f, 0x636deadc, 0x3e615f9d, + 0xee424359, 0x315659ed, 0xf08bbd2c, 0x220a63b9, 0xad89a7db, 0x6a19dc8d, 0x30c1b87a, 0x340438a4, 0x9925026b, + 0x3ba0827a, 0x021d04c0, 0x890af47a, 0xd2b1273a, 0xb91ba53a, 0xc3cfd390, 0x1c048ca8, 0x717cddd2, 0x9cc7fb93, + 0xf438c94c, 0x50243648, 0x4d88341e, 0xabb5ac20, 0xa6388e74, 0xba310476, 0xc4e31678, 0x9911973f, 0x2f261c0d, + 0xf1bff306, 0x3c5b3dba, 0x5264c8d2, 0x3e74aa0a, 0xa8c3da19, 0x91c0eb60, 0x934eb002, 0x3bf2286d, 0x987ee361, + 0xa74e55ec, 0xd6ba8dab, 0xb00457ac, 0xdeee4e24, 0x6a8f676e, 0xd380fc2d, 0x72a81b02, 0xc0f9884e, 0x245b353f, + 0x738c922d, 0x5f6338a9, 0x39aba4f6, 0xa4b78fa7, 0xc057ff09, 0xbf4c0286, 0xd921d79f, 0x6764ef88, 0x9642babc, + 0x3e4a7cc4, 0x11457b7d, 0x236556f8, 0xfd1e6412, 0x46a44c5b, 0xd54c7755, 0x39e7378b, 0xe11f5cf3, 0x6301b821, + 0xb56ab5d7, 0x5a4610ca, 0xf99ba146, 0xd19774ca, 0x484ecb1b, 0x6a45f2a5, 0x93e10ad0, 0xb206228e, 0x358b0f13, + 0x05c806d3, 0xcba0c0d0, 0x6c45552b, 0x7d44e25d, 0x3a1ca1e0, 0x034ee0f8, 0x7957db1c, 0x7cad4eef, 0x860e2e9a, + 0xa748f5c9, 0xb611af70, 0x2146195c, 0x82d2d774, 0x24959fce, 0x29005309, 0xa3f8c5d0, 0xb3faf525, 0x0d17c202, + 0xe18236ea, 0x52985085, 0xa70c534f, 0x02e8a30c, 0x9fac6fb0, 0xd74f8b2d, 0x4eaeb211, 0x32a4fdb9, 0x953768c3, + 0x31630502, 0x528ea70c, 0x0824abd5, 0x19d12155, 0x11a0aa9a, 0x2ff2eb87, 0x7e13b5f6, 0x0a350908, 0xa89cd351, + 0x3a759382, 0x9460d6db, 0xc278d7c6, 0xb985049a, 0x1e7b0316, 0xa7e5eadf, 0x0e4412fd, 0x07fe413a, 0xa69ef060, + 0x4dc83367, 0xe61ecedd, 0xd4cb83a5, 0x69df5c3f, 0xc8cc0a51, 0x013caf9a, 0xfaf76cbc, 0x8e60c3bc, 0xd3cb1c86, + 0xc0aee3fb, 0x890cdb6a, 0x1043a9f0, 0x1ba197ea, 0x8c81c3bd, 0x1361d947, 0x0733acb8, 0xbe2d0dda, 0xdb9b2c58, + 0x0e7b51ea, 0xddc9bb36, 0x421cf245, 0xc71d01db, 0x1ac29524, 0x3a0ae093, 0x395302cb, 0xbd622087, 0x26eb7eb7, + 0xc2a21199, 0x45edf745, 0x5f8051e4, 0x7705c044, 0x021508e8, 0xfeac67b7, 0x9e11849d, 0x1df47899, 0x4e303f91, + 0xb3300788, 0xab3897e1, 0x18874ee7, 0x4641e9c8, 0x81b8c744, 0x7310ea7e, 0xe51d4c7e, 0x26ab3eef, 0xf9cdd18b, + 0x17711afb, 0xef524762, 0x6eac9a1c, 0x4d388507, 0x73e5927e, 0x4219af2d, 0xa70e28a0, 0x272b2c13, 0x2315593b, + 0xd2bd0a2e, 0x6e322041, 0xac4243e0, 0xc28031ee, 0x4076d971, 0x59428b99, 0x91171173, 0x18c2d906, 0x41b9eed7, + 0x492aa1f2, 0x0b3b6093, 0xf51e9263, 0x53e4dceb, 0xa04d0a06, 0x242f0f49, 0x3f653758, 0x7d3b870c, 0x03a2c301, + 0xce5ff9e8, 0x771bdcc9, 0x47aae638, 0x4326942f, 0xd7bd6a4c, 0xd29e4733, 0x6e1a0d34, 0xbbb98b7a, 0xb4e9ed24, + 0xdfd4dcf6, 0xd05cfde3, 0x5abffe45, 0x3e878b8e, 0xce42f0ee, 0x6b281022, 0x6e783d2e, 0x61b0a1e9, 0xaaf0f6bd, + 0x1e672c10, 0x824fe4d5, 0x21ec72a0, 0xd621d516, 0xaf4ebbbd, 0xa8a92d42, 0xbaf5a65a, 0x323b79c6, 0x77b1c5d3, + 0x2d370ae4, 0x2b590bec, 0x3c65566c, 0x47f6e7c5, 0xd8eaf7bd, 0x128e1f9f, 0x8930582b, 0xf11bb635, 0xf6d92276, + 0xf3d0bbc0, 0x711954a1, 0xf1597853, 0x94d6d026, 0xa648eb74, 0x2214fe0d, 0xadf84969, 0x0290b9af, 0x44492625, + 0xf483dead, 0x6a8b1dee, 0xd20a37b3, 0x766dc783, 0xe559deaa, 0x12cce67f, 0x3977c888, 0xf6620b6c, 0xb28d6fae, + 0x9525c20b, 0xf1f5c735, 0xf4af3d83, 0x1025db11, 0x0fd0522d, 0x1c4fac80, 0xfa604bbf, 0xaa439a4c, 0x24cd2513, + 0x73ed1a2a, 0x79fffe26, 0x437f6b4b, 0x934d381d, 0x30635b67, 0x80e3f3a2, 0x925e1f15, 0xe1a2e11d, 0xf511c0f0, + 0x7bbbe026, 0x3e522873, 0x73678f2c, 0x3e44152b, 0xd5d71d58, 0x33cb43d7, 0x489a3172, 0xcbac6a11, 0x1728796d, + 0x0d91e6d4, 0xdf406a00, 0x973afe2b, 0x06dbf0fb, 0x59b25662, 0xf19ea580, 0xf5cc3e8f, 0xf29475c2, 0x6c818969, + 0xd222eae2, 0xea15701d, 0x952e1191, 0xd82ab72f, 0x841fbca1, 0x07dba97d, 0x992e0334, 0xac14c9c7, 0xa5d7426b, + 0x93c8466e, 0x9e958935, 0x7a82785e, 0x091d7b9b, 0xb6a76b6d, 0xc88eea67, 0x49095c9c, 0xcc4886e2, 0xb7e99bb4, + 0xed3c89d7, 0xe02ec2e1, 0x75435abb, 0x088d2913, 0xb1454dd5, 0xcdb03ff9, 0x02e60294, 0x26bb29a3, 0x47ea96e4, + 0xe460aecd, 0x505312ed, 0x38f483ee, 0xc23d558f, 0xb576365d, 0xb864974f, 0x745e20d7, 0x04ae0820, 0x58e3f2a8, + 0xd707b16c, 0x44fa69ae, 0x9aca1463, 0xa597abed, 0xe5c10ef7, 0x9f841eee, 0x65683158, 0xf0074fe2, 0x0ce02afe, + 0x5b5e2b7f, 0xcbf586ca, 0x42d3ab26, 0xcdc8bc7b, 0x1fa06880, 0xfc89dd77, 0xb2e68c1b, 0xc23066a5, 0xc8f46d32, + 0xf58f079b, 0x6cbdad6e, 0x4607f840, 0xfbdaaac4, 0x523e7c77, 0xcf9cde7d, 0xd923a026, 0xf7d71514, 0xd8aefa1f, + 0x23ff7239, 0xebe06247, 0x6bd0a74e, 0xdf865692, 0x98a8f58e, 0x01da8066, 0xbb15f5b4, 0xabc27999, 0x96d96012, + 0x0b9ce28a, 0x84560b63, 0x172718e5, 0x2621b3e7, 0xfc1bbb02, 0xa585c119, 0x5fc2e3cc, 0x311f2ad3, 0x956f6408, + 0x6aa82fd2, 0xcf705312, 0x6f043074, 0x239d3761, 0x5014d0c8, 0x2ffb75b6, 0xfba56d29, 0x974b61ca, 0xb7fde22d, + 0x6b26fa21, 0x50a2d80b, 0x43658618, 0x69c9dfd9, 0x2700b126, 0xd0a89e0b, 0xc864e820, 0x74371a9e, 0xfbd12b5a, + 0x0b2c63e4, 0xc79c10dc, 0x3f24d0a6, 0x47beaad7, 0xf45aa356, 0xa7774316, 0x1f8f3699, 0xb63d4c01, 0xc26b009e, + 0x52e0bb09, 0xd314d3f2, 0xbe79f02c, 0x1ebedf54, 0x0f1b7125, 0xe4d8f213, 0x03ccb55b, 0x954b2dfc, 0x4670e93c, + 0x11acd344, 0x74098d17, 0x3febaf7f, 0xcc782f70, 0xa63a50b7, 0x52c5c288, 0x3939d44b, 0x115717a1, 0xd6f6c798, + 0x85233d7b, 0x96496fac, 0x63399d2e, 0x9c65e9a6, 0x67b05947, 0x4f0b6ca2, 0x3ba453da, 0x95d45cc8, 0xae7524fc, + 0x6791f616, 0x57e049ea, 0x6c289d36, 0x6ab5f4a2, 0x4fcf3049, 0x52888ba9, 0x35a7f051, 0x75aaa734, 0x4496714a, + 0x8f702bdf, 0xfd8143e3, 0xd57824a0, 0x697c7d56, 0xc788895a, 0x454595e3, 0xcd4ac1aa, 0xa61d6a2c, 0xed8ddd66, + 0x8c4cd1d3, 0xaa56ef09, 0x347d190d, 0x1c710297, 0xec382ec8, 0x2060c885, 0xdc78696d, 0xee8912d9, 0x8f5eadda, + 0x16cd6999, 0x1e56297f, 0x1182a325, 0x116e8c6a, 0x845468be, 0x343dc793, 0x734e428b, 0x10a4add3, 0x1be06eaf, + 0x9f50cf0b, 0x98422c98, 0x627261c1, 0x8474a046, 0x3a41db10, 0x10f4d433, 0x97bfa22a, 0x82876afe, 0x9f177170, + 0x0dd9a852, 0x728f42e6, 0x471423bf, 0xdc1b94b4, 0x4e26907f, 0xe84bf259, 0xdc8f5117, 0x3465a0a0, 0xb759ccfc, + 0xc28c3fe1, 0x92862be1, 0x3f18512f, 0xc74dd9b4, 0x7204c717, 0x6663faee, 0x51faa896, 0x5ff9e59f, 0x425708d8, + 0xdfc2d241, 0x114a6e87, 0xfe9e7c68, 0xbad0e567, 0x3fdac147, 0x90c91976, 0xd94fe402, 0x9757c022, 0xdef6ff3d, + 0x11315fa2, 0xa424ba26, 0xd26eb78f, 0x1234cefc, 0x97514186, 0x366dd781, 0xa351dfb9, 0x285f0672, 0x22a7e64f, + 0x1738b595, 0x31b3437f, 0xc17c6fd5, 0xdbe4509f, 0x13a8ca97, 0xb3fb1f23, 0xa4ceb25c, 0x14f0d37a, 0xe0a2696a, + 0x7087a44f, 0x6c44bc8b, 0x32c07f58, 0x9a8bbecc, 0x8373ccc0, 0xaf734020, 0xb9efc13b, 0x775c6dbb, 0xaf1382c8, + 0xa0cb3fef, 0x71a9b81c, 0x5a25ce6f, 0xe0aca968, 0x19633b64, 0x78f8742a, 0x40b35451, 0x6ea73574, 0xb5c2b61b, + 0x3d222dd3, 0x666d51a2, 0x7078f36a, 0xa9f370c1, 0x964149d4, 0x75364fcd, 0x78fbfd63, 0x40da5459, 0xf36777c9, + 0x2255db7c, 0x08836df7, 0x8d6933d5, 0x102dd292, 0x41dcbae5, 0x231e8827, 0x637dabd9, 0x90f09f20, 0xddd669d8, + 0x2f99acb0, 0xc1800386, 0xcb28bb2b, 0x533980b8, 0x3a35b74e, 0x557040c4, 0x202ab248, 0x6135011f, 0x6f9891c0, + 0xa65c9d7c, 0x11c8f2e8, 0x6ccfea49, 0xfb335b29, 0x10d3ee85, 0x2c7e51b0, 0xd7388374, 0xfc51089f, 0x5a932633, + 0x984109e6, 0x40dc82e2, 0x2ea8a7cd, 0x2f0000fa, 0x87384bb8, 0x3aedd754, 0xbb61925d, 0x8d7d8b0f, 0xc95e81d4, + 0x45b274e3, 0xca438bd9, 0x3b4db354, 0x92ff6bb7, 0xa0075e69, 0xbf3ffa8a, 0x634cfea5, 0xad1b3f87, 0xee86c523, + 0x7ad94b7d, 0xb1b48622, 0x84be6b8d, 0xe8eedb9c, 0xba2051f5, 0x8b3b1f93, 0x4354063b, 0x16ffc440, 0xe17f60e4, + 0x11aeef62, 0x0813d869, 0x26d41806, 0x52bc2613, 0xab54b4c1, 0x4e33ebf6, 0x0b3a7b07, 0x6c151e15, 0x629a18ef, + 0x6c3b8f70, 0xc5842399, 0x627232a6, 0xb12405a5, 0xc2d7c229, 0x8f7f4c04, 0xaf7a0a65, 0x1c786e93, 0xb8b34a86, + 0x2b04b61b, 0x9ba3fbe7, 0xd463b299, 0xf95f32a0, 0xed1894bc, 0x6db75189, 0xc0c7d832, 0x380d50d9, 0x1189cac9, + 0x4963ed7b, 0x0a19f1fb, 0xf1be0e6a, 0x26a71487, 0x39a8ad03, 0x657c7974, 0x3f736ccb, 0xb34c5a40, 0x7f80ce5d, + 0x2bf1e452, 0xc71bfebf, 0x61562305, 0xa8c99ff5, 0xcc73f853, 0x68323456, 0xa7ebeaa3, 0x99fe3d98, 0x4ccd56c5, + 0x00a5e73a, 0x0a9778af, 0x3369d177, 0x53fd14eb, 0x55821ada, 0xd8f59160, 0x8319f954, 0x965ad55f, 0x0f8b935a, + 0x41921bc1, 0x8f8b0c10, 0xe06bd1e5, 0xdbb94f86, 0x6375acca, 0x1ad5147b, 0xae9bad15, 0x9c76f550, 0x17326974, + 0x42a991c9, 0xb5bbe6cb, 0x2a5687f0, 0x56bd7078, 0xf703d53b, 0x1ae752fb, 0x51d684ad, 0x94d56f59, 0x2e1c7b3f, + 0xbb02652f, 0x372c26ba, 0x4466bdd7, 0xb95f3f99, 0xc88638a4, 0x77168e9e, 0x5ff84f8a, 0xdaa391ee, 0xb3bace24, + 0x88707d79, 0x20a1dea9, 0xb67a67f8, 0x7a3fd9c6, 0x7ea93ec7, 0x42e30bf9, 0xfd5e813b, 0xa6f07d98, 0xb26a4822, + 0x3fcbc250, 0xdad7b63e, 0x8ba44249, 0xc6d6b9a5, 0x38385490, 0x5f9a7351, 0x517705eb, 0x4c957092, 0x7c1d03bc, + 0xba0f6599, 0x1637e7ff, 0x1c2d5d3b, 0x2ae87c6b, 0x099b9272, 0xa10c0096, 0x7cf62a3c, 0x218537f8, 0x50fe7392, + 0x2c4b6f29, 0x606e8b19, 0x149999c2, 0x99bba4c6, 0x472b5d2e, 0x36f14959, 0x6a9721b8, 0xf7750a61, 0x4731b519, + 0x7ad3cdb8, 0x80084937, 0xd0f909c6, 0xa6265ae0, 0xe593c4e4, 0x52240370, 0x6b7286da, 0x888d6dea, 0xb18adf47, + 0x72ced818, 0xc35d7a4d, 0xdbfc4190, 0x8008a834, 0x84a00db0, 0x649ddd94, 0x9ebc104c, 0x58fa6c29, 0x99c8c666, + 0x50e2da70, 0x18713b2e, 0xe6cf3b5d, 0x0afffdc9, 0x55b35778, 0x0c23e471, 0x3c690ca5, 0x10eb2d50, 0x7e55c5a1, + 0x4fc404f2, 0x1a591adf, 0xc81c2960, 0x828766e8, 0x152043a9, 0xfac460c2, 0x89657620, 0xbee4bc7f, 0x7df6338a, + 0x82d7cfe7, 0xc5627276, 0x5ed7a4e2, 0xa327a0dc, 0xdae41bcd, 0x72424b07, 0x0ecbc282, 0x2a38ad07, 0x7a703e6b, + 0x86987868, 0xfb6292e7, 0xf34e619d, 0x23c801ec, 0x3f9bf178, 0x911f76f9, 0xb599462b, 0x3d06c44c, 0x9d3f0fc5, + 0xe32cdf57, 0x18d19049, 0x5a21a6a0, 0x4f632c08, 0x5f188b85, 0x119a7acd, 0xd3bf10c5, 0x4b455b0e, 0x61395e92, + 0x58b78406, 0x6b78145c, 0xec6e9132, 0x5bf4427e, 0xe018c963, 0xebfbc575, 0x782f7436, 0x9c76e913, 0xe4552898, + 0x0c3e637a, 0x358b595c, 0xce7678dd, 0xf84e7221, 0xa6854c18, 0xe000d803, 0xe4998f43, 0x6f4b216a, 0xe6d0f1b2, + 0x93204e90, 0x15a2ee5f, 0x4f7b16ee, 0x50c350ec, 0xfe828d8a, 0x94755f0a, 0xb82cde2c, 0xc104c674, 0x2d4d3bfc, + 0xc67066d8, 0xbed09b66, 0x63b58e01, 0x598dacae, 0x280e942d, 0x098a5109, 0x955118e1, 0x72ed8b64, 0x58784951, + 0x2885139c, 0xb34f895b, 0x59de07fd, 0xd6ca4c91, 0x2a381402, 0xf6e684df, 0x21fee273, 0xdb20c3d9, 0xac4ef76b, + 0x23ec351a, 0x22002cd7, 0xdf6be357, 0x6ba68119, 0xfcf5fe58, 0xa5b7b870, 0x83df1ee4, 0xd5527018, 0x379c810e, + 0x2703cb1c, 0x52f8d6bb, 0xe0eaf56c, 0x86d2ac5b, 0x83d19e9a, 0x545a4f26, 0x36043959, 0x7595655f, 0x388a75b0, + 0x4d92e256, 0x32d84ed4, 0x44f1f9bc, 0x50f598e9, 0xd619d78f, 0xc42574dc, 0xa57f7a52, 0x1989277d, 0x88f19730, + 0x0dcd054f, 0x573c007c, 0x864f7ead, 0x0c39b15f, 0x0597179e, 0xb31a060f, 0x4578a128, 0xc92153d0, 0x9550db44, + 0x835c7e9f, 0x08f05e90, 0x3b86cbc1, 0xbc98724a, 0x7f5c923c, 0xcf4acde6, 0x9516d4c2, 0xa0672927, 0x83e16ec1, + 0x018a8810, 0x55a26d6f, 0x6dcd5688, 0x0296d50c, 0x5cadf70d, 0x96ac9719, 0x532ce54a, 0xf69b3454, 0x1040e4a2, + 0x6cf20f95, 0xf23342cc, 0x06e4ed26, 0xaac4b604, 0xa25d170f, 0x20e57100, 0xa84bc8bd, 0x137aa083, 0xb028ddef, + 0x2a32fb97, 0x6cf9930a, 0xf994cf00, 0x0fde6ea3, 0x809f969f, 0x2bc5117e, 0x2f83b894, 0xcd74ec98, 0x57fcc4df, + 0x18786ce2, 0x17c10b23, 0xa6ca4a48, 0x09c57cff, 0xcdfb04aa, 0x72942c0e, 0xe742b02f, 0xad9a84ed, 0x25280c09, + 0xcba07616, 0x812f1d06, 0x000c7b65, 0x6fde7591, 0xd07cc4a9, 0xb6e9b5fe, 0xb7bfd33a, 0x3f3b701d, 0x5c4cdb3b, + 0xc35cce49, 0x0526ef56, 0x7de540de, 0x90726247, 0x2d0166d6, 0xfbcc6ab8, 0xc5b6b3e0, 0x8a2d6bca, 0xfa3c512c, + 0x6b817e1b, 0x033166cb, 0x49d8920d, 0x50c23271, 0xe6cf40ca, 0x5daa6137, 0xccc761d2, 0x3f9be328, 0xb1726052, + 0xe6c1abc9, 0xadd1a51b, 0xe5c9f93d, 0x234db63c, 0x3091ea80, 0x456da2cd, 0x6434afff, 0xd985fa7f, 0x2b69b28e, + 0x0874618a, 0xf97b9c16, 0x3121452a, 0x9fd77889, 0x1290bce4, 0x016b4e62, 0x99903919, 0x24bf7ad3, 0xa2c3ea65, + 0x631ed9ad, 0x583ae5d1, 0x7584e54c, 0xff8bf6b6, 0xd6dd784c, 0x6e017de8, 0xd8a84980, 0x3be7822f, 0xb4b343ac, + 0x7ad71b0e, 0x55bfd080, 0xab94a20b, 0x23d3932d, 0xb985490f, 0x49522975, 0xa0967cb5, 0x14e37b15, 0xe998cfbd, + 0xb69711f4, 0xa3bded67, 0x11ff7c85, 0x140d84de, 0xeb893047, 0x4a1f3fe6, 0xc4d2ddee, 0xf1a81fee, 0x0bf298c5, + 0x979dd4e0, 0x17394da7, 0x78de0554, 0x9ecbd83e, 0x512a5049, 0x91d8498c, 0x3b437ae2, 0xe2bc6781, 0x60c6f97b, + 0xd15ab0ce, 0x9091b25a, 0x80d6e944, 0xd56bcf85, 0xf15aa1ce, 0x1873735c, 0x4aa64b0b, 0x68494579, 0x5bd455a3, + 0x1f57ac5e, 0x3ccfc051, 0xd467fb47, 0xc13bde93, 0x37d5c6d2, 0xcb583320, 0xeb40ef36, 0x92145e19, 0xac3804d2, + 0x7d82e4d9, 0x36c4ad7f, 0x47bc9454, 0xe36f7dd2, 0x18e761bb, 0xbc652e97, 0x5b4f7ce6, 0xf07616cf, 0xbb6aca61, + 0x44ece74d, 0x11415b6c, 0xba55002f, 0x95e6b7fd, 0xc9f6ffaa, 0x4761baf0, 0xea1dd98a, 0xfa0c94ff, 0xa720b1c1, + 0x976b7286, 0xb47ee509, 0x3fe77466, 0x17fa0b8c, 0xd639e1e2, 0x22767f5f, 0xecf2db09, 0x2afa98ae, 0xf73f287b, + 0x6f28ac29, 0xcb765578, 0xb3625e55, 0xc74aaeee, 0x522ff17d, 0x10e131db, 0xd6f17538, 0x0dd946c9, 0x28e6aedb, + 0xf1604bd2, 0xfc636cfe, 0xcc191704, 0x95296086, 0x29487b6c, 0x79decf90, 0x61944f00, 0xfb48bcb9, 0x04c7af75, + 0xb1d09c17, 0x06c588ca, 0x04d208d9, 0x42ae389a, 0x5f9926c7, 0x77f8ebe3, 0xa43f5523, 0xcd021e7e, 0xec6ed9a9, + 0x81548a9f, 0x78d8eb34, 0x2344504a, 0x884a25bf, 0x5ca5e386, 0x90634c40, 0x03efb4ac, 0xe7390087, 0xf8cd957e, + 0x038b3927, 0x404c77ba, 0xa37922cb, 0x84488d70, 0x56f9d0cb, 0xd7e7544c, 0x74a63b3b, 0x66930e9a, 0xea5fb2d3, + 0xf00b1cc5, 0x661350bb, 0xe4fec0b7, 0x8421c3d0, 0x9abcd7ba, 0xb82ef632, 0x33282fc5, 0x5f05e7c8, 0x054176d0, + 0x7bee0157, 0x55f4118b, 0x85bcf999, 0xb6c0894b, 0x84dff419, 0xa5f7d3c4, 0x1d962b6b, 0x32441fa0, 0xe38c12f5, + 0x38a0d76b, 0x595437e8, 0xf7f3940f, 0x5915dc07, 0xe3f191ae, 0xb60f29ad, 0x97d79775, 0x57e6b854, 0xe250e090, + 0x9b95e058, 0x87b4d57b, 0x1d845850, 0x00036f7f, 0xab602487, 0x827cd7d5, 0xc7346334, 0xbb4e6af3, 0x3132b34b, + 0x7f16eb4e, 0x8bc17e7b, 0xc4f54d5a, 0x30393b4b, 0x789f64af, 0x2fb511fc, 0xb7f25043, 0x387366f6, 0x23e5ee67, + 0x0c002282, 0x07162943, 0x3f3ddcdf, 0xe7a0aeaf, 0x9120e7a0, 0x9a0f4082, 0x00556cfa, 0xa52a1c6d, 0xa95b0c54, + 0xbb9750d0, 0x2bc6c0c6, 0x63a3cac4, 0xf611d1bc, 0xe2b6644b, 0xff02b61b, 0x3a5f8c43, 0x89a967c4, 0x566b4c12, + 0xdeff23fa, 0xd5fed9e8, 0x19053fdc, 0x33e81223, 0x4f48ff84, 0x90901113, 0x1aa2b549, 0xf2e3c033, 0xfa069e9d, + 0x0e01a767, 0x97ae30a4, 0x84b28b78, 0x7b7957f3, 0x3c09b6e1, 0x2c1510f8, 0x1f742fc1, 0x5b665460, 0xaad433c4, + 0xef8878cf, 0x3fffc427, 0xeec0d635, 0x67a4cfd7, 0xa59852d9, 0x2ce095e5, 0xa5ccd5b9, 0xb5f3407d, 0x10907c66, + 0xe297946a, 0x9eee5de7, 0x1d2a6c0e, 0x1528159b, 0xdaf4455e, 0x56957adc, 0x179e4f92, 0xa65308bf, 0x3e35f92b, + 0xb97572a5, 0xfc0841a8, 0xcc61e2db, 0x41d8355d, 0x40f96883, 0x78cec9dc, 0x7902f533, 0xad92322e, 0xfd17a16b, + 0x9e66b81a, 0xaef7f3df, 0xa19efb98, 0xd3ec8400, 0x39030731, 0x942cb129, 0xf3526a3d, 0xdff0d0a7, 0x02661c3d, + 0xdf0d90f8, 0xbc092fad, 0xf92ff130, 0x7e300121, 0xb45b2063, 0x83e525c4, 0x8d5a46f4, 0xc50e4e1a, 0x72a3e2ad, + 0x212fc87b, 0xac68cc6d, 0x19a9ff10, 0xdaba32bc, 0xb0f3a75a, 0x523669c5, 0x3ed6f257, 0xf5f551ab, 0x7899a3b2, + 0xb5aa257f, 0x93589ddf, 0x1b6a16b1, 0x99c63e91, 0x80e90c53, 0xd213c372, 0x295fc8f5, 0xfc7e47c2, 0x1c264d6a, + 0x90b94219, 0x0f9a530f, 0xe1224b4d, 0x9b006e27, 0x67a3107f, 0x738dbb53, 0xa413b182, 0x83b93901, 0xc0267c40, + 0x7d927380, 0x2cd67861, 0xe9fba57c, 0x17d79cba, 0xedb97414, 0x91dee3f9, 0x8ceeba80, 0xad38fe45, 0xdf38302d, + 0x8f84e1a9, 0x36f26859, 0x5121e982, 0x55afe4d1, 0x278b780f, 0xbbead3d5, 0x7eee7d0f, 0xb8c792c1, 0x344bae66, + 0x72f1cb2e, 0x26529ad9, 0x915e8651, 0x51149ad5, 0x76e0a852, 0x9d9ad373, 0xa1046b72, 0xc1e1f904, 0xee5ad192, + 0xbd1ed780, 0x9d83c6ca, 0x95048009, 0x791fa206, 0x67c53163, 0x8ea9adfc, 0x0029989c, 0xf1710d28, 0xae0de548, + 0x5a633c57, 0x463783e0, 0x32ce931b, 0x58799bf1, 0xd41b260c, 0x21b3568a, 0xb6036abb, 0x65c4f497, 0x100bbb07, + 0xe600437b, 0xfc99ed17, 0xce681679, 0x06f3c211, 0xd4278fb5, 0xdef8433c, 0xf0d36e84, 0x459a1c8e, 0x1cc37f61, + 0x8305298d, 0x029e027e, 0x19a4b755, 0x8c770ffd, 0xa13e9f36, 0x9c195167, 0x556d1759, 0x4999a3ed, 0x0d7e51ac, + 0x74c4d17a, 0xd6c5f289, 0x3e2b7a3b, 0xe93f062a, 0x0cc9c85f, 0x4dd0f5ad, 0xbc6a8493, 0x0cd716c5, 0xdf10af68, + 0x72e2619e, 0xf9316c2a, 0x334105a8, 0x3e11c99e, 0x7f1420bf, 0xfd1baa86, 0xedfc5b1e, 0x34917f7b, 0xfc397533, + 0xb09c61bb, 0x64f808e8, 0xf6c7f20e, 0x5ffdfe73, 0xd2ac4a2b, 0xa181a491, 0xc88c39fa, 0xc996c497, 0x16f860da, + 0x1ae153da, 0x552f624d, 0xa86858ad, 0x3c29bc8f, 0xedbd4bb7, 0x891fd355, 0x86610a1f, 0x37b9a8de, 0xa35dcc11, + 0xf9c372dc, 0x41e270ab, 0xa5eee27c, 0x3c659918, 0x01e4012a, 0x33a618a3, 0x65f0e42d, 0xa3574f0e, 0xe6e04f79, + 0xd5ccc0fa, 0x9bb3f9f6, 0xd6b32bb6, 0x7ca6fda8, 0xeae61458, 0x6183a371, 0xbf75f917, 0x447af391, 0xe75f9b1c, + 0x6a353878, 0x317b329e, 0x652a46c4, 0xb74223eb, 0xb0f607e5, 0x307289a2, 0x2f094fb5, 0x89bb14d5, 0x9d97ba44, + 0xb70ac85f, 0x8eb4813c, 0x3c533bec, 0xf5563446, 0x3d09d3cd, 0x00f0ebb2, 0x17c16ce6, 0xf5d7fbf4, 0xb5cb2c33, + 0xed2787d9, 0x8d59ba4e, 0x54a6b30a, 0x0d505034, 0xd3b40512, 0xbe240946, 0xb62944c1, 0x8e7ea028, 0x95f4a1ce, + 0xc4b49808, 0x6bb0ddd2, 0x00a15eb4, 0x1ffb3801, 0xcc0215da, 0xeef1db98, 0xc3d4a711, 0x0616b0cc, 0xe4f64475, + 0x0de09954, 0xb4ef69cb, 0x3af32997, 0x06d754b9, 0xc1d1af96, 0x5af5c02c, 0x057bd504, 0xe86127d0, 0x39de08c9, + 0x2234a33a, 0x6d9b0769, 0x3a05c1d5, 0xed9984ef, 0x3afff6cc, 0xf02073f7, 0xcfaa3cc4, 0xaac2c622, 0xb0b35564, + 0xcdbcf605, 0xba6d4aa5, 0x823fea53, 0x4f11b89f, 0x44f09824, 0xe77fe7c7, 0x3519fac7, 0x2d46845a, 0x4323904b, + 0xa6400d31, 0xfe4ea946, 0x6b79e268, 0x99a32244, 0x9f8990ca, 0x1a84f405, 0xc7b712f9, 0xbe49880d, 0xc66d7f77, + 0xd7bc3543, 0xe18aae03, 0xbc3e34c1, 0xc61215b2, 0xf6d2e636, 0x4b90e9d4, 0x9108270c, 0xa6c325ae, 0xbc210730, + 0x25800547, 0x90c76e22, 0x094d3fdc, 0x6f57540b, 0x1c9089cf, 0xb7a92ffd, 0xb2c1f85c, 0xdfce4ec8, 0x682be453, + 0x9bd8687d, 0xa508383a, 0x2364029b, 0xfdf9aa71, 0x504e2045, 0x8a8d5e87, 0x43d75192, 0x7482fd27, 0x282ad48b, + 0x20ed9030, 0xc0e09e02, 0xb7e1b935, 0xc0f98404, 0x8daaa1b6, 0x0082b8cc, 0xd910cdee, 0x438a5885, 0x5fe03d0d, + 0xc5230c21, 0x63209a50, 0xba00ff27, 0x42dca978, 0xfec91753, 0xeca855bb, 0x78d88de5, 0x2bc3bde9, 0x544c1ed4, + 0xde0e1818, 0x0ac6def1, 0x060ca4d9, 0x4e0414b6, 0x7e01d078, 0x23658af0, 0x21c9bced, 0x50e15066, 0xafeb797a, + 0x592de786, 0x0d8c3315, 0xd7f52902, 0x3d7e907f, 0xa7f5eea3, 0xfc88f85c, 0x686e179b, 0x27db73e8, 0x300b4fe4, + 0x46e51498, 0x4d66fdc5, 0x06d759f0, 0xa1b55434, 0x30d61b2c, 0xed0ddc9f, 0xf8d28982, 0xd9a9b300, 0x5cdb717e, + 0x71ad8624, 0xab63aff3, 0x080e1ef2, 0x8c6351c2, 0x48de0c3c, 0xa8edd822, 0x454c08de, 0x1ea96917, 0x0061ff1a, + 0x8ae7e848, 0x3cd6bc1b, 0x2a25037c, 0x03d9680e, 0xc9e683b9, 0x6ab3a852, 0x1ee4272b, 0x9138606a, 0x8dbe9030, + 0xa6ce68d5, 0xec968bba, 0xcc708201, 0x315db9f0, 0x4f65f9e5, 0xde221998, 0x41f37bf0, 0xfbd6bedf, 0xec709a8c, + 0xca670c15, 0x12de161d, 0x03f5ea04, 0x2336d506, 0xca25a730, 0xecad4bdb, 0xc6ed1002, 0xe8e892a9, 0x613eb814, + 0x03c60726, 0xa4001127, 0x976fec06, 0x7725be9f, 0xc530e6cd, 0xab90ff7c, 0xb8b4baed, 0x6f832b26, 0x6e0f2de8, + 0x22fb3682, 0x3f237581, 0x9d5823ac, 0xd63c9db6, 0x1c05c908, 0xa24335b2, 0xda2d829e, 0x47482711, 0xed36c9a2, + 0xe1bb9171, 0xff686531, 0x9eebfb0a, 0x69b57e85, 0xabbda6d3, 0x68e88827, 0x5bb1e7e0, 0x0af8c6f1, 0x63206b47, + 0x90d26098, 0xabbce6c2, 0x3621ea97, 0x14f144eb, 0xc8dbd213, 0xd1ab6935, 0xc9b560f9, 0x78ec6490, 0xddfec645, + 0x6241ee4e, 0xfc01ce5c, 0x6e6ae5b4, 0x6429f978, 0x0b11811b, 0x09d54dd9, 0x3a7f6501, 0x2bb3cdf4, 0x2038a009, + 0xce3b5a2c, 0x0ead337e, 0x7e7cb2cc, 0xf92f3279, 0xad7badf5, 0x813c9ac6, 0xa4ae6994, 0x04935ebf, 0xff56992d, + 0x66640eff, 0xeb71f469, 0xc59c48ab, 0xc1707e8a, 0x50723729, 0xa961070c, 0xf90473f4, 0x58c7c8b6, 0x01da21dc, + 0x6cac54f2, 0xc3ae5449, 0xff70afe1, 0x9820926b, 0x130a90c0, 0xb2846f26, 0x62145724, 0xd9b312a3, 0x9f479904, + 0xfd71c417, 0x728ead99, 0x5ccc7e34, 0xe70a0700, 0xc8928b6e, 0x151d63ef, 0x6310db77, 0x0b3882b6, 0xa0e598ef, + 0x8e611c1c, 0xadcd2591, 0x1f181640, 0x05bdf26f, 0x622f97db, 0xd3356e8d, 0xc9762bbc, 0x408dbae2, 0x1c56a797, + 0x4bb6fced, 0x095b73dc, 0x2249d8ad, 0xf3f91f15, 0x2c6b8de5, 0x96caea15, 0x513d0399, 0xcffd1853, 0x9910c8f5, + 0xaf11ef2e, 0xa994f207, 0xd34abd25, 0xb7c2a0a3, 0x957696d4, 0xb7ea1f48, 0xf51299fd, 0xf20e9e8a, 0xf856c205, + 0x48e8bace, 0x03b5c70e, 0xba9dec35, 0xcb9af36d, 0x5754bb38, 0xa53c313a, 0x5b96b3e7, 0x16cd9109, 0xfa73d749, + 0xf9df5555, 0xd7d3af0a, 0xe7d054c1, 0xa4616511, 0x2258103f, 0x844afdba, 0x22c5e99f, 0x9c636bd7, 0xb34a61d0, + 0x95bf6450, 0xc5be2864, 0xfa39342a, 0x3b741a7a, 0x8d058c3a, 0x24fed970, 0x0c7b7aac, 0x1a838839, 0xa1a939df, + 0x75048a56, 0xf5abd25e, 0xde64220d, 0xb0497ef4, 0x9b1fd1da, 0x3aa74cdc, 0x5396c417, 0xd1f22408, 0x98455a23, + 0x40d02c5b, 0xb4784a7e, 0x5678565f, 0xf819f29f, 0x79500a6d, 0x98390357, 0x513c4df6, 0x18dfbd52, 0x3daf3788, + 0xa9d76aee, 0xf09ca6d3, 0xa42ccef0, 0x7584cb4b, 0xdf9653db, 0x256dc90e, 0xdef9a126, 0x9ddc1bfd, 0xa590adf1, + 0xe9ce3258, 0x197f22c2, 0xa0a4084a, 0xdbf8152f, 0x34b93469, 0x91fde3a1, 0x90e8d5c9, 0x30c3d3a8, 0xe326ddef, + 0x6bed161b, 0x6f9ab5dd, 0x3b51fbff, 0x64d5c8e4, 0x2b82190f, 0x2f22fd8a, 0xec6d706d, 0x0285043b, 0x1f3dc18b, + 0x22253942, 0xbe163d89, 0x84cd4a4a, 0x62e8d6b5, 0x62c1f58b, 0x0dc6e532, 0x785c4968, 0x14e911ff, 0x8313c512, + 0x33391af0, 0x464c1b0b, 0x65888928, 0x6ed12634, 0xde7d1e31, 0xc8965319, 0xb2581012, 0x33cc310c, 0x3e09e32d, + 0xcdf45efa, 0xefdc5303, 0xca27bba2, 0x0b03a25a, 0x4d375eae, 0x4a039fc6, 0x989cb552, 0x97419a1e, 0x833ff2be, + 0xe8965472, 0x88d5d717, 0x4a833e35, 0xc97a9380, 0x04c4095b, 0x3cc3a8df, 0xb160d4d1, 0xc09b1c15, 0x94a38dc9, + 0xa5842e56, 0x2d015607, 0xa9432607, 0x8405b389, 0x774f5f57, 0xb06978e5, 0xe152182b, 0x308da54b, 0x43e71863, + 0xf53873c3, 0xb24e046e, 0x35f0c147, 0x4bdae86a, 0x8e34b099, 0x717f16f5, 0xc4975749, 0x36662146, 0x89878e31, + 0x588b58f9, 0x02e5068a, 0x193cc8c4, 0x788cdd68, 0xc2aa8e8f, 0x1e2f7210, 0xd408bc4f, 0x31d88bf5, 0xe0f226d8, + 0x1493afa8, 0xb2fee7fd, 0x99466045, 0xc95b03c6, 0x37464415, 0x762f4511, 0x23e25d13, 0xbbe5af23, 0x61e6ede6, + 0x8255436a, 0x19a967a0, 0xf8987637, 0xac9cb69c, 0x30573e51, 0x77704f48, 0x804ca9ee, 0x01968c05, 0xfcec61da, + 0x8eca1732, 0xb599ea2b, 0x450c2688, 0x9d2c2371, 0x168295d6, 0x970b0c6f, 0x3fb4d149, 0xe1a1e90e, 0xe8894791, + 0x4e7e4cde, 0xf2c6d86f, 0xca447241, 0xf9dcbfd5, 0x0547f7a4, 0x8c943141, 0x7a3191ea, 0xe9a57ab0, 0xcab444b1, + 0xd59f0af9, 0xb5a536c0, 0xeaa695c5, 0x2b2f4ba9, 0x173a66bf, 0x949ce3ee, 0xb19f1ae9, 0x541a825e, 0xb5a2ec2c, + 0x09c4b473, 0xe3db0c6d, 0x86e74b97, 0xe2df7257, 0xf3fb1d90, 0xe4340112, 0x475cf6f3, 0x6dbe212c, 0x2acdc751, + 0x78d2940e, 0x3dabc1f9, 0xb3fe4a92, 0xc0709e05, 0x0de5e237, 0x4b71d78a, 0x0a31686d, 0x74594d6e, 0xf70d5a1e, + 0xef77fd5e, 0x30402fb2, 0x922c8b53, 0x2cf24f46, 0x4ec53f3c, 0x460d98cc, 0x5d2d50df, 0x12eb1084, 0x11130958, + 0xd76f5096, 0xb42cc977, 0xb6e1da85, 0x43db7cce, 0xef03d5e3, 0xc4d72c1a, 0x9ce3ecbe, 0x199ad9ce, 0x2401a5ca, + 0x5ed39680, 0xac147a40, 0xa71ca27a, 0x52ff1751, 0xa093a2ba, 0x03701c62, 0x2c7b8ad7, 0x5460fbfa, 0xd26f046e, + 0x601a0b6a, 0x0d404f1c, 0x296472ce, 0x90da3abb, 0xd540ece5, 0xfcd76860, 0x80422a2c, 0x2884f205, 0x2b2287af, + 0xd8ac1394, 0x97d5317f, 0xa3e4e509, 0xd8703da8, 0x0e31dab9, 0x99923dae, 0x9bb55281, 0x755d370b, 0x704291ea, + 0x55653c2d, 0xb4ab39e2, 0xb092315d, 0x0c71d786, 0xc464aa34, 0x2b771d83, 0xed2920bc, 0x280086e3, 0x457d830d, + 0xead19ac5, 0x8cda51bd, 0xf8d93c52, 0xd2f3b268, 0x15a87f5c, 0x6bddd107, 0x595a6f12, 0xad818dc7, 0x01d40b64, + 0x6fe43664, 0xe7df3ab5, 0xd45fd186, 0x73ee1e85, 0xedae7a40, 0x836efc04, 0xd29db143, 0xa8c44061, 0xa635e7a7, + 0x1f87d081, 0x05007f74, 0x38168b96, 0xbeb08447, 0x379dd00c, 0x83f2b89a, 0xcd267eb7, 0x9ff59be0, 0xb810bb55, + 0x4c73db9f, 0x0e3ef03e, 0x4fadfd55, 0xdb2bf27f, 0x6acce5fe, 0x217483ac, 0xf136674f, 0xa7b55aee, 0x16c7c3e0, + 0x09d60b99, 0x083c6ecf, 0xcec6150e, 0x6e63ff5c, 0xdc10b334, 0x7716f681, 0xac239906, 0x34f4a4e4, 0x28847c8d, + 0x0021ac1c, 0x3a33b8ad, 0x59af9ae3, 0x11d106aa, 0xcdeb1d74, 0xfd4ec4ab, 0x11fb79c4, 0x8e93fbc0, 0x082663ca, + 0xd9aeb3ff, 0x7f6af7e1, 0x6c728edb, 0x9fab7c55, 0xc9043185, 0xb99ecb87, 0x834c9042, 0x6ed5049d, 0xf63795b1, + 0xd24db791, 0x2093c9d5, 0xb4c48d37, 0x46baadef, 0x3788876c, 0xc0ac4a77, 0x1bb89da4, 0x3cb1bbbb, 0x71bb52e8, + 0x2323c80f, 0x8f891436, 0x20764764, 0xf13d4406, 0x6ba48956, 0x9ccc5fc6, 0x3adecd5f, 0xa6806b31, 0xa0177f40, + 0x6ef5a042, 0xd424e1de, 0xb6b865b2, 0x4f6d6708, 0xefdbc5ed, 0x1f382776, 0x172997e5, 0x8b779554, 0xebbee858, + 0x2dab280f, 0xb0d9d517, 0x0ef2026c, 0x3af345f6, 0xfc02e577, 0x0dd1cda8, 0xc1221760, 0x0eff148c, 0x6d41b6ad, + 0x3d423b21, 0x728a68dd, 0x7e41797a, 0x2aeb5c5a, 0x5d970c0a, 0x11277ce7, 0x226fc68f, 0xbfb47634, 0xf1bc3e7a, + 0x8313b7fd, 0x7e87e49f, 0x73d4cdff, 0x67386c54, 0xb109a3a1, 0xdd037089, 0x2e86d769, 0xed1bc9c5, 0x394afb42, + 0x554f008d, 0x8758e73a, 0xa3287cb5, 0x4cf9a505, 0x5130685e, 0x26a7e92f, 0xf52b1f30, 0x4f2dd7ec, 0x1a592ce3, + 0xc1a30c5c, 0x05521ad9, 0x4722245d, 0x49dd1997, 0x0f2f75dc, 0xfc92361d, 0xcd1b38b6, 0x68ff61b5, 0x94fcce58, + 0xaf71c41a, 0xcc0e4cb2, 0x33e52b23, 0x8cab526b, 0xb2d524b3, 0x19f69591, 0x67dfb4a6, 0x92f7f7b2, 0x818a8209, + 0xf228f78e, 0x9ad33ef6, 0x478b393f, 0x12339837, 0xff79c93d, 0x8729ee2f, 0x6515f203, 0x729cb1d2, 0x3b717049, + 0x35545078, 0x674c29f3, 0x107e71fe, 0x5909a047, 0xe55173ab, 0x25755007, 0x9ec6bbcc, 0xbd9bb262, 0x77ff2f4f, + 0xc59b9f03, 0x2f4bd512, 0x44af5457, 0x6e80a991, 0x00bebc0e, 0xf48dd245, 0x1536ab9c, 0x4ba61724, 0x6bf9bc42, + 0x656a5326, 0xf777ac44, 0x2a425bdd, 0x311eeef8, 0xc3d8be87, 0xdde123b7, 0xec72c9ba, 0x3da0acee, 0xa84f4b42, + 0xd84e40c1, 0x335d9fee, 0x61dfd6d0, 0xd57575f9, 0x587a45d7, 0x0f15aed8, 0x1a6501ca, 0x15265f48, 0xe5a979e7, + 0x29b02eda, 0xa71f27a4, 0xd37072dd, 0x9991d57b, 0x38474e20, 0x79409d14, 0x8760a036, 0xf0536cea, 0xa186ecd3, + 0x4ab64250, 0x50b8c89a, 0x2ebef030, 0x89f8de38, 0xca2e45ae, 0xed6a115c, 0x308e9322, 0x36f9a189, 0x14c579b2, + 0xf82f6561, 0x08aa969a, 0x2213d03a, 0x520ea1c5, 0x8904b8b9, 0x56390510, 0x7a510a17, 0xdaf63c33, 0x40af621a, + 0xba4953e3, 0x096186fd, 0xc4fbfcef, 0x68bf4665, 0x87225e42, 0x97538c5e, 0x554a2a59, 0x13b51fb2, 0x416225c5, + 0xa2a9a25e, 0xdc0d9bf9, 0xc7378736, 0xd38cf76e, 0x7619da76, 0x9e134cd2, 0x4e2950bc, 0x04ef7a22, 0xaad42fbe, + 0x19f426f7, 0x0ed0256e, 0x869abe66, 0x7838bfef, 0x81865921, 0x286bdf99, 0x2363e9f2, 0x9676afaf, 0x96d3393c, + 0x51a3f764, 0x731aff46, 0x2df18142, 0x35383596, 0x5432b982, 0x0bd889a8, 0x43acade7, 0x2c03458a, 0x6a52bdd0, + 0x2efc16ed, 0x92154f2f, 0xeaf96394, 0x9ad05c3f, 0xd268adfc, 0xdda077bc, 0xcfb23d2b, 0x822e1422, 0xccfbadf8, + 0xc1f8c5d4, 0x0ef5944c, 0x1617ec69, 0x0ea28455, 0xd04c75f0, 0xb0d94e4e, 0x7a5be4d5, 0x89198894, 0xb6826bd3, + 0x80882a80, 0x6e2ad1da, 0x0de65a94, 0x22c3ea6c, 0x17547ffe, 0xa748cc33, 0xd7e64b79, 0x4c41e61a, 0x55123f50, + 0x91b5101a, 0xbfed1f1e, 0x301efe29, 0x68ef02c2, 0x0b21d84e, 0x5b2fc1e3, 0x13ae52ab, 0xd858c176, 0x1f7b11fc, + 0x10efca81, 0x6e8151e8, 0x152921c2, 0x8a5e5ce9, 0x9be2f048, 0xbf3ae542, 0x1f0f9c43, 0xf736dd2f, 0x3d019a3a, + 0x289c0771, 0x35b3fdff, 0xb4f7f992, 0x9af3675f, 0x81b8d30c, 0xa7fb20cc, 0x2df2e492, 0xe8ea5293, 0x764b4858, + 0xa31ef404, 0x7a6f0364, 0x1542ce34, 0x7830f408, 0x6693fad0, 0x1a56f79d, 0xa01b5662, 0x93c35177, 0x5be90cfb, + 0x707363c0, 0x842be94c, 0x0c4fa78a, 0x03d7287c, 0xd6e5b5f1, 0x5eb7cce3, 0x34faadd0, 0x3c299994, 0xc4eee64b, + 0x2dcc42ec, 0x6c491fb2, 0xc9e48798, 0xe671e78e, 0x3300b21c, 0x079cbfcc, 0xf495b672, 0x4e72295a, 0x106c2e8e, + 0x250eed6f, 0xb5d033ff, 0xb1067e77, 0x4d86dbec, 0x42293667, 0x9383ac9b, 0xaacdaa65, 0x61830491, 0xb9b2bf01, + 0x844db7b5, 0xb39d20da, 0x8e881292, 0xe0a33948, 0x62b80215, 0xf86d014f, 0x299cd3b8, 0xaf4a895a, 0x1c56d6f1, + 0x2de7c67e, 0xacc6324d, 0xc05fec3d, 0x9b1dfdcd, 0x1bb42379, 0xae89502f, 0x7794dbbb, 0xd177ab08, 0xc7ce2596, + 0xf901be5e, 0x01b591a4, 0x14104edc, 0x47de279c, 0xc69143ca, 0x87a84f4f, 0x7f3c6e58, 0xd54c36f3, 0xb94f037b, + 0xf73b655b, 0x69957dab, 0xbcec6587, 0xea5526a9, 0x0e1c1d60, 0x160ad8cb, 0x8a493312, 0x006cc4d9, 0xa77622a7, + 0x4d0e0bb1, 0x15feb274, 0x9cfcb657, 0x7bbbf000, 0xb6be415b, 0x27e29240, 0x3a32b02f, 0x5cf3ecd2, 0x78309cb5, + 0x6c9a18a1, 0x3c3d7fd6, 0x2493ba13, 0xffffa699, 0xf68cb56a, 0x68ecf3e9, 0x3fb051fc, 0x6809ea2c, 0x770f20bb, + 0xda1bb576, 0xfc5709ea, 0xa0189091, 0x8247da55, 0xd93780bd, 0x118fb151, 0xbcde7845, 0x595d1d79, 0x9eb7a4d1, + 0x74111b4e, 0x32dbd219, 0x82be5660, 0x3dac1362, 0xf31be3c9, 0x909e21fd, 0x02be061b, 0xb80bf458, 0xb2462803, + 0x26c0bf35, 0xdde6a9e7, 0x57c239d2, 0x89a9b84a, 0x6ecebc62, 0xc1d72fc6, 0x601bd9e0, 0x308b90a0, 0x5350459e, + 0x4f151bfc, 0xb35fab25, 0x91fc4734, 0x3040210c, 0xa1d985f8, 0xc6cc0047, 0xf473119d, 0xd0dd93ce, 0x5c8bbedc, + 0xb2be5d7d, 0x335d9e96, 0x049734a4, 0xcc3da9c1, 0xa40097f0, 0x3e4f51bd, 0x5fb10839, 0xa706397e, 0x9257cf42, + 0x55a960ef, 0x171ea906, 0x9a620ce4, 0xdc442d70, 0xcdc4d9ce, 0xe58a0891, 0xe80420be, 0x67025174, 0x99c627c4, + 0x1105baa4, 0xa18baf36, 0x64d3383a, 0x97d9ab35, 0x0d9a5fbe, 0x9da69bc4, 0x97a28ffe, 0x9cd1fbd1, 0x77a6ba23, + 0x3c958a9e, 0xbf7c6320, 0x39d8df66, 0xf4acbf22, 0xdb325bb7, 0x52e86cb7, 0xfc42f671, 0x2940bd5c, 0x09066f6d, + 0xdfa50f0d, 0xc6b3f018, 0xc63c9d2f, 0x49c96552, 0x1bc1615e, 0xe4d010a5, 0xa9e01f08, 0x66d3a184, 0x80d78a98, + 0x5ca11614, 0x40dda163, 0xac20072f, 0x6adc4390, 0x045b15d2, 0x2f4e7cf8, 0xf7c994b3, 0x4380e601, 0x6aeed653, + 0x67b75e47, 0x8ea9e52f, 0x86a0657f, 0xca85b80f, 0xe8cc3ba7, 0x44818e4b, 0x226ea96f, 0xd362de77, 0xf3ad534d, + 0x204dfcd2, 0x305ec254, 0xeee3869f, 0xaa64a100, 0x5e130417, 0xf184e312, 0x59848ce1, 0x1d5f9adf, 0xc4eda38d, + 0x1a8aa7cd, 0x8ba3db60, 0xbbfd214b, 0xbd8b9994, 0x95c0363a, 0x8713bb8d, 0x6f449b68, 0x1ac663ab, 0xa9636fdd, + 0x4827d992, 0x84a6d4e2, 0xe15b4011, 0x748fdc05, 0xf1ee8f72, 0x836bd036, 0xb2a9e775, 0x7a29b033, 0xa4584ee1, + 0x2457a845, 0xa98965ca, 0xd3438eb5, 0x719d7126, 0xc09f8b7a, 0xc8d17043, 0xd948598d, 0xb409a329, 0x9f9fcb3e, + 0x5f9f8a0f, 0xc58ecddd, 0xdb46af24, 0x1f5d440a, 0x7a2de83a, 0x5cb0f961, 0xc0142322, 0x8e570ac7, 0x94fb81fc, + 0x41be6149, 0xde4e34f1, 0x6465cd60, 0x8da59507, 0x5c39ce04, 0xe097d0ea, 0x3b28525f, 0x6867bb9a, 0xa5b15e95, + 0x2f4fccbd, 0x663d7b73, 0x22d61dd5, 0x81617f0f, 0x093c1490, 0x280ffeaf, 0xedfde6ae, 0x9572021c, 0xc7b64826, + 0x67f72ce0, 0x5f23a713, 0x1e4d4176, 0x30798e0d, 0x4628d28d, 0xd94d334d, 0x73602ab0, 0x8939b3f4, 0xe6faca0e, + 0x878f446e, 0x89d18435, 0x237cbb4e, 0x7d8e0fc2, 0x281b81f3, 0x28ddcc36, 0xbc92ea20, 0xf850aa81, 0xa55eb844, + 0xfc151f41, 0x6769a33c, 0x70c0a8ac, 0x58652913, 0xe3e2f5d1, 0xcd75b418, 0xbbdebbc4, 0xf4bcf942, 0x87977615, + 0xd246e872, 0xc75d2041, 0xb8c66943, 0x07298437, 0x5d55cd41, 0xa229df8c, 0x0eb57b2e, 0xa78f91c9, 0xf757fec6, + 0xc4383492, 0xda34b279, 0xde017835, 0xe4345fb9, 0xeac5548b, 0xde84d412, 0x040b745f, 0xec681c33, 0x34d20f39, + 0x70c5d304, 0x476dfa7a, 0x8ffe425f, 0x559635d7, 0xa86ce60c, 0x539312ba, 0x1380b2f6, 0xe2a8068a, 0x088ec754, + 0x2625ad77, 0x8fef0d37, 0x8383a8b3, 0xb26a3960, 0xbe9e61c7, 0x1705994b, 0xed236483, 0xf1fa3033, 0x735729b5, + 0x6f62bfd0, 0x09d6f246, 0xc2c5943b, 0x0b33e17b, 0xbf018dca, 0xc5151a0d, 0xe7d8a200, 0xf3e48a94, 0xf226dbcd, + 0xc02b79c3, 0xb2a1613a, 0xbc6bd4cc, 0x6ca44d0b, 0x418d0885, 0xed2c932f, 0xad2d0230, 0xabd13938, 0xf84f60cb, + 0x3b5c576e, 0x6532dfea, 0xefc263e4, 0xfcf85ffa, 0xe13215f9, 0x533c832c, 0x67807d41, 0xaf83eee3, 0xa69a14af, + 0xf5e0d18f, 0x2501b389, 0x0145289f, 0xd3f5aebe, 0x8ee292bb, 0x283962e4, 0xc22b5eb7, 0xe1eab529, 0xe00f2259, + 0x5a3712ed, 0x9e81b388, 0xcf2e0a83, 0x71f60075, 0x1844c94b, 0x43cc1f3d, 0x7e03dc88, 0x83404372, 0x830f25de, + 0x029cb4e0, 0x8bfb2891, 0x833d806c, 0xdbdc946f, 0x86ea91b7, 0xfc81e091, 0xee303271, 0x6d216994, 0x5ea18732, + 0x11cc991c, 0xcc062e01, 0x45caff3e, 0x62133a9a, 0x878f765b, 0xf1732d66, 0x5f1984d9, 0xd3b2afa3, 0x639dd9fb, + 0xbbcd81fc, 0xfcd97446, 0x847144c8, 0x09799652, 0x04216f42, 0xf2a97fb6, 0x89d40b2a, 0x0c450f52, 0xc244bf9b, + 0x0bc87c6d, 0xccbb118a, 0x01cf9c10, 0x292bcb6c, 0x10f68eda, 0x8a7c8fab, 0x797e7041, 0x9f746cb1, 0xc547facb, + 0x1a3df227, 0x17641d64, 0x5802a0b2, 0x68ff0e77, 0x91b32b5f, 0xb607502c, 0xf76ed598, 0x608e8787, 0x20c58fc9, + 0x3273a842, 0x5ec6e98d, 0x57a57bed, 0xc743731a, 0x01f74d3f, 0x1c560ca9, 0x407a3c70, 0xbda08282, 0x8bb24626, + 0x4606775d, 0xd9f6f004, 0x6f113aa6, 0x66696104, 0x9b9373cc, 0x549346d5, 0x5d2e3bde, 0x540c7a9c, 0x5f790514, + 0x1ff85107, 0xbc8ec35a, 0xc3f2a355, 0xd0cffeab, 0x63bfb087, 0x3b4e3232, 0x6a6a1a49, 0x790501f6, 0xa5d42b10, + 0x042e1f25, 0x2d33ec20, 0x3b108ea2, 0x4f2f6cb0, 0x97382a75, 0x332bb755, 0xf66f04c4, 0x583772a7, 0xd7b756e8, + 0x2c11e55a, 0x2b54ea80, 0xe08be240, 0xf269561d, 0x1443c206, 0x486b4201, 0x678cb976, 0xf18b876a, 0x4c4cd28d, + 0x2841cc81, 0xc1684874, 0x97c76377, 0x86532134, 0x85dfb2cf, 0xf19484a0, 0xfd9785d2, 0x1cbe6c6c, 0xb08b483a, + 0x73b220f9, 0x72ac000a, 0xe2347ab7, 0x4f25eda4, 0xdc53de0c, 0x3495eb4c, 0x99629dbf, 0x08aac78c, 0xdf04c1b2, + 0x96a07a5f, 0x5538e692, 0x3e16e189, 0xc0722c24, 0x63f6cc3e, 0xc97378b6, 0x8b3008e5, 0xf7574407, 0x22eb36fa, + 0x4e81f65a, 0x06f52432, 0xe2058a54, 0xaac3dec6, 0x43225583, 0xfcef8670, 0x020b73d7, 0x2058acb6, 0x70041ea4, + 0xeddc7a8b, 0x7afe2026, 0x64f30634, 0x36a3416e, 0xd1377c34, 0xb1051acb, 0x0393a9f1, 0xb74b7b9c, 0x1e22ab94, + 0xa90b612d, 0x7a02f97f, 0x456e5b6c, 0x4f756410, 0xb1135354, 0xe2a2b1fb, 0x8fbf16a7, 0x63fe47df, 0x65b82f71, + 0x041910c4, 0x39152843, 0x571baddf, 0x4d906174, 0x59ae2d0d, 0x60b0f4ba, 0xf1bd43f8, 0xbed0a2ed, 0x3691847d, + 0xf50c3570, 0x8bff5d09, 0x0bbdcdfc, 0xd8c31f9b, 0xf88d8363, 0x31e71f7c, 0xb4db3f77, 0xb5e96cf1, 0x4b5f60b2, + 0xb8bbdb67, 0xcc1a4c0f, 0x1e8566f9, 0xe777f23d, 0x282b4960, 0x24cc45f4, 0x5799ddf4, 0xd34a1de9, 0x8721a754, + 0x2e7493fd, 0xc1fa3024, 0x76667d00, 0xa02f608e, 0x455b2c39, 0x85340344, 0xdfd1c0da, 0x25cafcb5, 0x76ffb78b, + 0x382fe362, 0xf082479e, 0x123415bf, 0x96cf95f7, 0x846019ab, 0xf4f705b6, 0x96e52c35, 0x036dfcaf, 0xa125bd4e, + 0x6df63fd6, 0x0f14cf84, 0x23ea97f4, 0x13e212d5, 0x8b55c25a, 0x155d23fc, 0x2b0f985f, 0x8bb1dff4, 0x28ba7bb8, + 0x3ed060a8, 0xfdefd1cc, 0x10a47b2b, 0xea987696, 0x097405c1, 0x0ba14ea9, 0x7352a1ea, 0xbd205771, 0xfdc8d9cb, + 0xd29ceade, 0x7792e889, 0xb4d1666c, 0xb5c2ea95, 0xf1363c48, 0x7fd2dba1, 0x7275cccd, 0x23392ec9, 0x060722b1, + 0xc4897c7e, 0x4e0b2580, 0x3cfd7a73, 0xd5a3e393, 0x4fd3357a, 0xaa1f4ade, 0x032583aa, 0x3a3a6baf, 0xb4aa9f25, + 0xc774cf39, 0x41f64470, 0x2947bb9d, 0xeee13965, 0xb735b2df, 0xa9dca530, 0xd851c4b5, 0x28d3e731, 0xfbc11c2c, + 0x7151bcff, 0x64f06d6d, 0x8975a820, 0x028e41c5, 0x5e2f5388, 0x46ceac10, 0x4ee03105, 0xb1759a7e, 0x4db352c5, + 0xa7894144, 0xe2b84fe2, 0x2ee2c5a1, 0xb3cbef83, 0xda82d611, 0x74e22450, 0x62f576f3, 0xba477c46, 0xcbe5310d, + 0x9d7be74c, 0xa34f9fef, 0xb5a9b9a0, 0x5ceb06f3, 0x4174dc19, 0x934bb2cb, 0xb1928eaa, 0x1013e84a, 0xcca6eda1, + 0xfa789d18, 0x0c47e422, 0xd76ea934, 0xe877c68b, 0xe20278cf, 0x8d2f4cb2, 0x6479b8a1, 0x970d9518, 0x940fa1c2, + 0xd204b879, 0xb2854d20, 0xcd189c07, 0x09f2db8f, 0xced16026, 0x45c1c2e1, 0xd9d166dc, 0xffeea3ca, 0x49a7df1d, + 0x410c1b21, 0xd6b1ef63, 0x6c3b31ee, 0x9263442b, 0x4d3ceedd, 0x017fcbd3, 0xac20cc14, 0xb85b39dd, 0xbffa17c9, + 0xdeb565b9, 0xe2201509, 0x4df46247, 0x0b17c39d, 0x9f1cbd5f, 0x301dc9fd, 0xa8104206, 0x71f76596, 0xb67fe62f, + 0x824e1e29, 0x245690ed, 0x4f182b33, 0xbe9d503a, 0xe20a96b8, 0x06262410, 0xb2ec6954, 0x613c52a1, 0x576d7565, + 0xa25aac1d, 0xfeb8651c, 0x067e20f1, 0x539f702c, 0xa23ee4c6, 0xed7772da, 0x15bf3d70, 0x7f87156f, 0x6e454e7c, + 0x5815dc60, 0xa1c036fd, 0x2fadebab, 0x355ccc39, 0xa706ca41, 0x82a27870, 0xcd750e0e, 0x3d7f50e6, 0x2b678d4a, + 0x438317ba, 0x45f16d18, 0xdc901e53, 0x28b79531, 0x812530ca, 0x5ec13d16, 0x71a0a1a0, 0xba3e3342, 0x7037876b, + 0xfe78f808, 0x7e397e1a, 0x75707e0b, 0x13fd5f94, 0x4a6197bc, 0x08a6caa7, 0xbb2e5048, 0x954e7d5b, 0x67a63a74, + 0xd6a41140, 0x6c213a3e, 0xa20e8194, 0x33d0592e, 0xdd80bdc0, 0x47189906, 0xe4ea25fb, 0xcfb1f5c4, 0x10053631, + 0x55682878, 0x3cc9666e, 0xbf0f946a, 0x50af4034, 0xa0b561c7, 0x4caed1f4, 0xe94d38f1, 0xea42590e, 0x62d45a14, + 0x53213783, 0x3799b63b, 0x6d8f019e, 0x1eb48ccc, 0x5344aaa9, 0x7cbe56ee, 0xb9def1bf, 0xce8adec5, 0x33952056, + 0xc6d039c5, 0x053788f9, 0x8d74bca8, 0xbe7d5498, 0x61f005ec, 0xacb65510, 0x71f5a600, 0xa2ce6bad, 0xef2ad802, + 0x7637ddbd, 0x7ea44ce4, 0x935ec57c, 0x57b3e97a, 0xbaaf3010, 0x4e032e5d, 0x2c693263, 0x04c7c32a, 0xb6125053, + 0x75279d04, 0x4a3a3eee, 0x46e73f11, 0xce9988b0, 0xc302a9bc, 0x761fa8a4, 0x36d6a576, 0x3d206445, 0x04470c3f, + 0x1fd35239, 0xfda86395, 0xc3550b4d, 0x9f0c82a2, 0xb08c6d4b, 0xffe45631, 0xd25be98d, 0x1dcd79bd, 0x7bd8a6bf, + 0x2dae31e4, 0xeaed9636, 0x4d460cb7, 0xecfe1caa, 0xdd19505f, 0xe3bbab42, 0xeee08bb8, 0x912f2fec, 0xad448715, + 0xee58053e, 0xbce42f63, 0x852e30d2, 0xf9fa26a5, 0x4f65e06c, 0x731820f2, 0x0a79ddd2, 0x9e3b2675, 0xcb79db88, + 0x0f0060e8, 0x10d581ac, 0x434f9dfb, 0xd4452125, 0x765cca18, 0x20991c1b, 0x64a2c706, 0x2861e1a7, 0x9fe2701c, + 0x0ed3e9fb, 0xf406607b, 0xf5d4243a, 0x657eab08, 0x064dc48f, 0x2d128d9d, 0xbd0c298e, 0xd8dbd748, 0x1fdb387b, + 0x516e94f8, 0xfd0a6fe9, 0xa94d19c6, 0x8e498adc, 0xbd6c825a, 0x134917b0, 0x134ec430, 0x4a9e0cd5, 0xf159065e, + 0x457fb84d, 0x5337fba6, 0xc998b80d, 0x07c4b5ac, 0x10a5bab5, 0xcd8e4ee6, 0xef7d11c4, 0xa6c718cc, 0xe6aa258f, + 0xc4cccc3a, 0xd070fa2c, 0x63faf703, 0x9c0e11ac, 0x48fb56ec, 0x96c8aec1, 0xbf4d2a0d, 0xe468016a, 0x075ba1ba, + 0xedb5a7b1, 0x2cf56a62, 0x830abda7, 0xe1d3edcf, 0x4c2875bd, 0x4a7d98b4, 0x944f9948, 0xa4350e27, 0xe117ea0e, + 0xd172a256, 0xa7a17765, 0x52cee3f8, 0x0b412173, 0xb0aef278, 0x9f6a61f3, 0xf4bd0703, 0xec8ea5b3, 0x036d757e, + 0xa1ee0704, 0x292c823c, 0x005ab03a, 0x335935f2, 0x3bbd1c6d, 0xc08ec8f6, 0x98274126, 0xda1f4cd9, 0xfb401254, + 0xf73ae989, 0x9f949746, 0x4d64d501, 0x42b442b3, 0xcdfa9486, 0x46edfd40, 0x11ea21f8, 0xf20f5702, 0x0e65d9e3, + 0xf42a75ae, 0x9e9e538e, 0x803139de, 0x523d13ac, 0x13474513, 0x0c4f75ec, 0x27cc5ceb, 0x9c4bed26, 0x72531372, + 0x253facf6, 0x03690ee7, 0x8add4d17, 0x022607cf, 0x13eb99f6, 0x931f551c, 0x0b92ba36, 0x7351b37b, 0x148d5c07, + 0xa82dace4, 0x785c35dc, 0xaf750929, 0xb1443ac4, 0xdd1138dc, 0x92b0e180, 0x23abb58c, 0x0fd6954f, 0xb280a525, + 0xcee20bad, 0x58a7a953, 0x801bfcd5, 0x89232d83, 0xf19f9246, 0xb9b30b06, 0x4a05e2db, 0x76ec7feb, 0x879b750c, + 0xd5a3822e, 0x5233d7c3, 0x274ea04a, 0xd049653b, 0xc414a978, 0x7e93cf25, 0x419d5e82, 0x64a53fcc, 0x8ba3ff5b, + 0x9c887e7c, 0x792e2f70, 0xdcdf2c86, 0xcaa1e232, 0x2bf1a2cd, 0xce230f03, 0x218620e2, 0xee98fbdf, 0x87897d24, + 0x4c231931, 0xa17eb4c4, 0x0ec82763, 0x13b35883, 0xc23154db, 0x1e6a4634, 0x382afcf0, 0xb0357dd0, 0xadcd430e, + 0x63de2d05, 0x12e666b4, 0x09a958af, 0x03223fbb, 0xd6345ee4, 0x74d402f5, 0x237119ac, 0x1088c309, 0x700e776e, + 0x89f6df8b, 0xdd38d1e6, 0xeacf7c78, 0x766765aa, 0xbab0ec8e, 0xa2c70075, 0xd0393f4a, 0xfb880b1d, 0x61daf25d, + 0xdf66895a, 0x9aa37207, 0x4537b368, 0x6b6ce888, 0xab03d5a2, 0x7f64674f, 0xb52f38fa, 0xcf85d1bd, 0x702f88ea, + 0xbc4174bd, 0x186dfdee, 0x0e342ba4, 0xc045ff3a, 0x89fee3b1, 0x726e76fc, 0x6739292d, 0x9e047545, 0x7ed94b4e, + 0xf3d89bef, 0x209b2fd6, 0xba20fa41, 0xd851ac74, 0x28da267a, 0xef98dd93, 0x991debfc, 0xaf3d80a8, 0x90a437e4, + 0x0a71f5c8, 0xe4313d6e, 0xc089db82, 0xb02a80fb, 0x5726a5a2, 0x1fb9c1b0, 0xa7b21d79, 0x81ef8c24, 0x27293fc5, + 0x50ef1876, 0x61d35b77, 0xfd589d91, 0xb3d05c3c, 0x8062a647, 0xfbfd65d1, 0x00cee376, 0x35cc46c6, 0x9d0a4aa9, + 0x1f113bf0, 0x6c544b1a, 0x6075b43a, 0xaa914d12, 0x00edf7d5, 0x25427b04, 0xf3850b61, 0xf8eb7f66, 0xb783d7ff, + 0xd245d633, 0xe7dd690e, 0x63c2885f, 0x08fce9ab, 0x50392363, 0xd814fb3e, 0x31daf81d, 0x2d2c5186, 0xfc3cf64a, + 0xf60eabe8, 0xcedcde29, 0xf4648b21, 0x9661e8a4, 0x7629831a, 0x6a21888a, 0xd58c4dab, 0x58a03532, 0xbd3f5e8e, + 0xdcb9e023, 0x8b8148a4, 0xea56b89b, 0xe31bdc66, 0x70b8ab0d, 0x46d1b3bd, 0x43c86012, 0x304b84c6, 0x7646318e, + 0x6b6df343, 0x55047b56, 0xe4eb178a, 0x2740d414, 0x2f062c6c, 0x2bb87ab3, 0xbbe46759, 0x604592fd, 0x28034951, + 0x5a41d5b0, 0xab3cda0a, 0xec016b00, 0x7892a766, 0x69a55747, 0x5efc7560, 0xddc2a900, 0x22eb94af, 0xe60437d1, + 0xee44e8d3, 0xf371cc73, 0x4e5e6e7b, 0xdbcc442f, 0xbb2f778a, 0xc6d98bd7, 0x18538d40, 0xc979f0e9, 0x4f4be0dc, + 0xa638a6cb, 0x5d0983f6, 0x3e3bb206, 0x571d88fb, 0x241c6359, 0xad67b501, 0xb6253cd2, 0x79c59d55, 0xafd3041d, + 0xa62d0004, 0x939d6fb7, 0x92955860, 0x922f19bf, 0x031a3537, 0xddbb38eb, 0xdee7d821, 0x0207fc68, 0xed548b3b, + 0x70886283, 0x79e8ae43, 0x367892f5, 0x871499e9, 0x27cd4b86, 0xec865f04, 0x7ff18368, 0xe629f3aa, 0x624fc9d6, + 0x938a106c, 0x6d8a7a9e, 0x8c804933, 0x3eb5d6f5, 0x536d60a2, 0xc850fc9f, 0x27332521, 0x4c30fb35, 0xb3387981, + 0xc81f3618, 0x6d1dbdb0, 0x2fa4e5aa, 0x3c182f7f, 0xce06706f, 0xa6f76bf5, 0xb8accd9f, 0x859b6f01, 0xd172b494, + 0x172f34c2, 0x846b960c, 0xa75fb178, 0xd6a4d265, 0xa1821835, 0xb6983095, 0x4be9130c, 0xb56711c4, 0xc5f76010, + 0xdd2010a5, 0x8e85fc3e, 0xf5002fe6, 0xb5fcd270, 0xcde65a92, 0xf4f7ebaa, 0xa5171728, 0x596ed1b4, 0x8fe0487e, + 0xb3a452ed, 0x7be9762a, 0x937f6834, 0xb7ccb972, 0x33e38e1b, 0xc4b79540, 0x8d6936aa, 0xb7f57e24, 0x9142146f, + 0xc0aad048, 0x355f47c1, 0x94d67bef, 0x3f5f66f3, 0xa06f3bc5, 0xca821f31, 0xa3d1b427, 0xe09286e0, 0xfbb49e9d, + 0x22cd5984, 0xde3fbaa9, 0xf1228b0a, 0x109a0b9f, 0x7548c33b, 0xe941dbb2, 0x93f95e81, 0xab081a96, 0xdf747884, + 0x45ed0016, 0xbdb948f9, 0x52666432, 0x2294a781, 0x66b25bb4, 0x2335dca4, 0xc636dc96, 0x766687f4, 0x8273259d, + 0x856f58b2, 0xc5311f4e, 0xfa666467, 0xdaaee17d, 0xf5d22468, 0xb94d77e5, 0xe3ccd5cf, 0xf71ff3d5, 0x059c47e0, + 0xa2677a6e, 0x3690bf4a, 0xf7915003, 0x836ffa5f, 0x8a3df18d, 0x838d8411, 0xb6b54740, 0x5b2ba5a0, 0x2d8db59f, + 0x745bf9cd, 0xec9e0e62, 0x8bb57884, 0x5b5f6d82, 0x44be8f59, 0xe3ed39bb, 0x4ef5119d, 0x10c90758, 0x4c3de02e, + 0xcc0dcdcd, 0xae35ebaa, 0x8b079813, 0x707f4cd4, 0xb28ee485, 0x868e1475, 0x98dd2c9f, 0xbf7e4f5b, 0x2f2378c2, + 0x7e997fca, 0x0ae36578, 0x0714380e, 0xf942af1a, 0xdc924a4c, 0xd462660f, 0x73b985b2, 0xb3443ec0, 0xa79c0a43, + 0x74a7a67a, 0xd1d2f722, 0x3e9d04ee, 0x9a4e1195, 0x626273ff, 0xd2403034, 0xc4a06a7b, 0x59830abf, 0xe25c52c7, + 0x835a60fc, 0x74890b67, 0xba57e1c8, 0x16fd9a93, 0x318964d9, 0x73f3c4e9, 0xc8dcb69f, 0x6b19cc12, 0x848795bf, + 0x35bb1c1a, 0x1e328ed7, 0xb0f9eecf, 0xfcf7d0ef, 0x18084914, 0x41866a66, 0x9a53ef73, 0xc80279e4, 0xfaf76d6b, + 0x6bfc3811, 0x806e5e41, 0x939565a3, 0xb3aac7da, 0x8c29ef06, 0x40ee7f8e, 0x158b6c83, 0xff4fde31, 0xeb907b6b, + 0x1cae2e23, 0x0f2ee3c6, 0xb1695a77, 0x7347da79, 0x16ffd074, 0x4ac8b21e, 0xa36836e4, 0x96d832f1, 0x4f52a03b, + 0x87320d38, 0x4a9b3d5c, 0x96156427, 0xe0010793, 0xca4bb547, 0xa85f29a8, 0x85ee6d70, 0x507197f5, 0xc5727a49, + 0x1ca129bb, 0x87b85090, 0xa54860cf, 0x26e5a790, 0xd4b4c87c, 0x32a58dd1, 0xda70783c, 0x6331fe08, 0x6d5cf3c2, + 0x5ea90f67, 0x7b234c8d, 0x82709b2f, 0x6aae16ed, 0xfe8fb430, 0x91aae7a4, 0xa89c8475, 0x9ee038e1, 0x46752770, + 0x607bc2b7, 0x5a43428f, 0x22c889f2, 0xbab3c6ee, 0x0fac61b3, 0x75dffa55, 0x23d02d78, 0x9e425bb5, 0x59b2e2a7, + 0x9840368d, 0x0d7daf83, 0x5038f381, 0x1a2ca12e, 0xb796b6c2, 0xa8f2aaec, 0x08085d45, 0xe666f976, 0xd77c5ea8, + 0xfaa8692e, 0x89b8d180, 0xe3c2705f, 0x16234e9e, 0xcd4e4fc6, 0x870800df, 0xd723a9ec, 0x93aa6197, 0xccb05bc4, + 0xecf009cf, 0x228d7786, 0xcb35fff7, 0xe9dfde8f, 0xaa78f2a8, 0x3bdc97dd, 0xb0e60ac5, 0x8a238fa6, 0xb42b36b0, + 0xd0948639, 0x103bc6e0, 0xb9c624a2, 0x9ac7ee52, 0xe1bb553d, 0x25ba0f2d, 0xec5a50f0, 0x525071c7, 0x32ae5317, + 0x3664176c, 0xfd6e1cea, 0x40da8e5a, 0xfa450d23, 0x75246f3e, 0x2929379d, 0x8e9b60ce, 0xc0bbf00c, 0x2f72727b, + 0xe43257a4, 0x59a0fd18, 0x3a0585aa, 0x14ffc421, 0xa4ac0cad, 0x20346223, 0xac05560e, 0x3260af53, 0x4f0f2911, + 0xb7f749b1, 0x8dcbfebb, 0x6ed1040a, 0x9cf320de, 0xf91b5c8c, 0xe75e20c3, 0x167f9681, 0x6d2bc888, 0xc4fd3e7e, + 0xa6d9b333, 0xa4335f14, 0x6e3a8d38, 0x29812b76, 0x5f52e568, 0x8a9c434a, 0xde78bff1, 0x29a8e2fe, 0x1d19a3dc, + 0x79913344, 0xbb8e2c30, 0x7c5008e1, 0xffdcb3ba, 0x8d89d735, 0x08916038, 0xc72a7f5f, 0xbcc988f6, 0xd5eee570, + 0xec92250c, 0x5a7c4a47, 0x6d2e33a3, 0x24cb0d60, 0xf70685c8, 0xa3c806a0, 0xbdfae84b, 0xa4a67943, 0xe9b91b21, + 0x9e013594, 0xa81e232d, 0xe8e588ad, 0x775119cd, 0xcf750bda, 0x0ece7f14, 0x175b7be9, 0xf32b1a39, 0xc463947a, + 0x3edfb896, 0x0bfb16d6, 0xaf65c608, 0xdc641073, 0x0f7eac7c, 0xd323ac96, 0x4274a6eb, 0xb4292188, 0x5c04680f, + 0x2d95a695, 0xf4c315b7, 0x3316c523, 0x115295a4, 0xc9d3a324, 0x9b7ef8ea, 0xd92832f6, 0x57361199, 0xc0aeaf06, + 0x84240756, 0x603a8729, 0xbdb675e5, 0xb5ee6993, 0xaa403ec0, 0x389ab29a, 0x0479b39a, 0x0c17e0ac, 0x06d9f9db, + 0x8153fc3f, 0xc6f01456, 0x4fcc2b64, 0xee3c4364, 0x592f68c6, 0x63033033, 0x468cb226, 0x98df9e53, 0xff5036ab, + 0x1c0261cf, 0xd05d7071, 0x44465e19, 0x218ddb59, 0x77c47d9c, 0x9c69cb51, 0x1d2d5bfd, 0xbaeae40d, 0x5ea9b1e4, + 0xcf79acb9, 0xdfbecf79, 0x41fcebcb, 0x80dac72e, 0x2c7c1d77, 0x7ecee1f2, 0x72f4ac6c, 0x0b6a4925, 0x8467441f, + 0x14086e24, 0xe4d38856, 0x39702da0, 0xb8d98fef, 0xb98c2fc4, 0xa8e8edbd, 0x7eff0e27, 0xff3961f2, 0xbc14a79b, + 0x1ade7ff7, 0xf7132d2c, 0xb4416c2d, 0x1391c607, 0x233504bc, 0xc101cf9e, 0x576cc7c0, 0xb4fd6643, 0x5b3022fd, + 0xbf7d2f89, 0xddad1e2c, 0x282c78b4, 0x379a1549, 0x829e057d, 0x0572624e, 0x82317a72, 0x30903914, 0x5f9a21d0, + 0x6a4a1f7e, 0xca77d649, 0xd3418bc3, 0x2f29ee21, 0x9b4cafc7, 0x9e341421, 0x37d49fa7, 0xb84eaafd, 0xfd0a27ae, + 0xc4164067, 0x45dc9bed, 0x9eae801f, 0x5ff14c89, 0x545d3e16, 0x9a50bff8, 0xa4b473df, 0x5ba988f6, 0x1cbade3e, + 0x842b2979, 0x9f8e6bf9, 0x4a9985d4, 0xc20fced3, 0x606207c5, 0x0ffa2256, 0xfb44070d, 0x9b0cec7f, 0x4c1e5290, + 0x732e376d, 0x9d57ab15, 0x82965f34, 0x547e001b, 0x423c95ee, 0x87af89c8, 0xeaf9f712, 0x73850839, 0x55806767, + 0xb7c8377c, 0x29e7e714, 0x0516ad4d, 0xc40e9db2, 0x6bfd6dc6, 0x3a673e44, 0x2230a6b4, 0x66252f81, 0xdf4c86a0, + 0xecf42312, 0x5c589a47, 0xbbada40b, 0xfff3876c, 0xbb138b23, 0x979443c6, 0x6d5f1657, 0xda42d439, 0xc07f15dd, + 0xc363ddb9, 0xd33ff22c, 0xf9937c80, 0x38b30d82, 0xa1db1672, 0x2b3eac71, 0x67b4a8c6, 0xd1c19faa, 0x69cfc6ca, + 0x8c3026e7, 0xa188d3d8, 0xa892578e, 0x2161b6a0, 0x50c75ff5, 0xbb382b9e, 0xd22734e0, 0x71a2c96a, 0x80064848, + 0x62541ad0, 0xc59933ca, 0x3802e3a2, 0x7ffebca5, 0xc42fe47c, 0x1f9b0e66, 0x9e467753, 0x3bbaa10c, 0x9e376c80, + 0xc50a17f2, 0xa004f8d3, 0xccf4612c, 0xdcd3fac3, 0xb3404869, 0xcce5465b, 0xf5a8e022, 0x8d65bfbe, 0xc20cf2dc, + 0x4b06c247, 0xa1233135, 0x7e714e25, 0x88c8d7ff, 0x3e1bf788, 0x1256e988, 0x0f1ee492, 0x1ab61db0, 0x7703de3d, + 0x8b06d9e9, 0x56f112cd, 0x9c92dc4d, 0xab4f9bf6, 0x5badc60a, 0x36d9c113, 0x538b686a, 0xcbf9fb04, 0x25486110, + 0xe8164d57, 0xb6399585, 0x0dd561d0, 0x390e448f, 0xbd2738bd, 0x3a6bd084, 0x6e6fd2ce, 0x33eb46dc, 0x9851d49f, + 0x7e8956f2, 0x8a7133d2, 0xcb330bbb, 0xdf5452f4, 0x5cce6b37, 0x192223b5, 0x037890d7, 0x6839bce1, 0xe26e7626, + 0x842a705f, 0x623c3d5b, 0x367124b5, 0xc933a1f6, 0x263a7c9c, 0xe431756d, 0x586b640a, 0xeeadc0f0, 0x8a486fe4, + 0x74a0cc95, 0x94bcd961, 0x587a22d9, 0xf7ea06f6, 0xfdf978a0, 0x779979d1, 0xc667caa9, 0x0d223ca3, 0x31fa3620, + 0xeeeb21ce, 0xcc59875c, 0x0b36e640, 0x13f41cab, 0x58bad0b4, 0xe17f8eae, 0x44385a31, 0x8cba2cf5, 0x6814bf57, + 0xb5024a07, 0x0ae63377, 0x07dc4e7b, 0x28611a81, 0x4bad52c7, 0xe960870e, 0x7d4eab49, 0xe15b0826, 0xd4f5173d, + 0x6477ae2d, 0x419e522c, 0xa0d4c196, 0xec5c0366, 0x1450a111, 0x7fd76067, 0xd733a95a, 0xde2d316c, 0xb129c365, + 0x82326406, 0x86f2aac0, 0xa4b44353, 0x55485008, 0x60787fd6, 0x34022e64, 0x24ad19bd, 0x7533b42a, 0x2f3004ea, + 0xb3e2880e, 0xf34f6bdb, 0x31482889, 0x1cb00ae2, 0x60bf8565, 0x91a44186, 0x4d8cc0f0, 0xb42fae44, 0x71a5b90b, + 0xc9b216c8, 0x14f2b0aa, 0x2538a209, 0xeaa5d60f, 0x1dcd1483, 0x634dbd70, 0x05b036e2, 0x9e732c4f, 0xda05f6cf, + 0xa43365f2, 0xa1707719, 0x3d3ce930, 0xdaa201f0, 0x260142c3, 0xd5f2eaec, 0x26fc10a7, 0xc10f044d, 0x64b4b7e0, + 0x8b092cd1, 0xc5895c41, 0x5000db1f, 0xdf42aa2e, 0x92bffd69, 0x2b6f4b10, 0xfab8fe75, 0x8aabc5f6, 0x6fcf6030, + 0x1d5eb255, 0xc92d1a42, 0x05af67c1, 0x0df3fa0b, 0x1e041187, 0x1cdca169, 0x708bb289, 0x23adeaf5, 0x51b310ed, + 0x5979e282, 0x8acacecd, 0x53edb1ba, 0x5d1b0d71, 0x66fa8b64, 0xca50c67f, 0x6d9a8c51, 0x9bee1f78, 0xa07140b1, + 0x0ff494ac, 0xcffe116b, 0xf83e53f8, 0x11dc38b4, 0xfc0dbcb2, 0xd24d8174, 0x2a655ff1, 0x70f43419, 0x57e3aa8a, + 0x53da271d, 0x1a8b093c, 0x97434db6, 0xe40dffb2, 0x4b483d24, 0x70b51f05, 0x3d25e3cf, 0xe9472a16, 0xab88c55b, + 0x9ed43be3, 0x88d16f4f, 0x3a6b03a8, 0xadba6e7d, 0xd020f1c3, 0xb91e3ba8, 0x80f70de7, 0x2ee87a08, 0x528bcfa9, + 0xbb8d139e, 0xe44eb0fa, 0x3407e146, 0xeab0939f, 0x67bcb76b, 0x126663fe, 0x29682343, 0xa3edf195, 0x9d03ed8c, + 0xa710d32c, 0x0aba1ed8, 0x1f896dec, 0x8087b0a7, 0x15d60007, 0xd5ea6a47, 0x29fa3111, 0xf40375b8, 0x1b9f8988, + 0xc80c56d2, 0x39094020, 0x55b2d0bd, 0x1806b1e7, 0xc60ede03, 0x2e1de5d5, 0x11ca6ff1, 0xe6a5afb8, 0xe522f2e4, + 0x5df4d01f, 0x8e995072, 0xafb69320, 0x52468837, 0xbf4f5fdb, 0x33576ede, 0xad1d994e, 0xe953b081, 0xed2d5aa9, + 0xe89caa77, 0x86a00626, 0x084613b0, 0xc421434c, 0x97feb9b0, 0xadb154a2, 0x75f69eab, 0x874bf2ff, 0x3a0aff49, + 0xfd987a4e, 0x0d18b1b8, 0xb43c6d89, 0x15ce6556, 0xe1225c5d, 0x66de985e, 0x3d2038e3, 0xcd8bcb36, 0x3ada39ef, + 0xf3292eb6, 0x31c80d29, 0x7acfdcd7, 0xab0e8543, 0x9d789e8f, 0x3ef02323, 0xa0369754, 0xfa7f57cc, 0xef623b13, + 0x0698b8ed, 0x7b35142f, 0x8951cf78, 0x34d67a2c, 0xa5170445, 0xbe7c7d09, 0xf63ea350, 0xa4610859, 0x3002c035, + 0x0e30abac, 0xebc2a1df, 0x565ec8c8, 0xe1f78a5f, 0x5eaab708, 0x577dda71, 0x1b21ae97, 0x67d33082, 0x731e1b8e, + 0x9fa4834d, 0x20332fe1, 0x2871ea13, 0xb2506147, 0x3d216fb5, 0xf38852f0, 0x2abac208, 0x47dd73a4, 0x97f5fe0d, + 0xcadf83a4, 0xd2b1e702, 0x11e3c2f0, 0x2319d4ea, 0x7631adb1, 0xdf082a70, 0x030998f7, 0xd19d73f3, 0xbae361de, + 0xa37ca9b0, 0x65dde843, 0x82339586, 0x44191089, 0x83ef815d, 0x6c404b60, 0x69f747ae, 0x2c75627a, 0x6a3d8a76, + 0x54d03afe, 0x0e702436, 0x87618700, 0xa92f594a, 0x785dbcc3, 0x9c762f33, 0x8a35d8b7, 0x8b68856b, 0xf7a72986, + 0x3412720e, 0x4ae419cd, 0x8a7fde4a, 0xefcf02d0, 0x47c51b4e, 0x7e097801, 0x4e5e538f, 0x42ee1e3c, 0x79e9735a, + 0x84ec1d4c, 0xf492ec1d, 0x1e394b3b, 0x5a1df63e, 0xcf41e103, 0x3f424d54, 0x4ae3c55b, 0x3b4bcf51, 0xe006bc85, + 0x6a882dae, 0x07c807ec, 0x8ecd3f6b, 0x510ebde5, 0x40e8ea11, 0x1a947e6b, 0xd829138c, 0x10152437, 0x2867e431, + 0x1ffbab56, 0x12aa1847, 0xc00c7371, 0x46c55518, 0x42d66f3d, 0x7397b1bc, 0xa51db72f, 0x620cd3af, 0xcc51ea2c, + 0xf910d205, 0x325024a8, 0xbedab9f6, 0x847b597e, 0x53153261, 0xf5d301f2, 0x8b30f7b3, 0x967ec7ec, 0x9cc462fd, + 0xcfb4b559, 0x2f0b9835, 0x63d53406, 0x19bf36c7, 0x933e43b2, 0x5b494147, 0xa3f63023, 0x3b64fb54, 0x56787769, + 0x2f1a4f27, 0x07dfeb95, 0x0789b310, 0x3519475b, 0x35bdb28f, 0x4b8f549c, 0xed8b9634, 0x12dfade5, 0x3e484f1b, + 0xee53f86a, 0x7fdedc44, 0xef45cf13, 0xf836a949, 0x0c90b222, 0xca47a7ca, 0x0ab61bae, 0xfdd2ff22, 0x986391db, + 0x02df7ced, 0x58ee6dd1, 0x6ca7e8f4, 0xbf22b223, 0x20909a6b, 0x97bd3ca2, 0x39df16e5, 0x8ae78f74, 0xe326f58c, + 0x794cb404, 0xc1892f8f, 0x322ba43e, 0x205e982e, 0x6c87f5b8, 0x53979612, 0xa16b852f, 0xb8366878, 0x20e9894a, + 0xbe482ca7, 0x4e6e7478, 0x1def935f, 0x765b562d, 0x52f3fce8, 0xc657f8a4, 0xb48f2264, 0x3f208672, 0xa169ae61, + 0xc02164d2, 0x4b94daae, 0x02edafbb, 0xfbd26497, 0x20d9a57d, 0xe1509bf0, 0x451d06e4, 0xc3f102b6, 0xd811cf88, + 0xc3c22be1, 0x256a84bc, 0x10ed841e, 0xe1253333, 0x8ebc1154, 0xc0fe3ec9, 0x261a0cd5, 0x03294586, 0x75e0cd97, + 0x0f46cdfa, 0x84e83ae6, 0x5f54b283, 0x68d913df, 0xcd12c142, 0xe8e9a925, 0xf40818f7, 0x6aa14985, 0xd2975ab8, + 0xf30b256c, 0x04636e74, 0xd738d3dc, 0x73ad7d46, 0x14de12b6, 0x9efe7bdc, 0x525c546a, 0xd5090040, 0xd7bc9785, + 0x572aa464, 0xe8654954, 0xb0c9dce3, 0x48d2e36a, 0x24803cac, 0x989995fd, 0x4d65a34e, 0x3b36f8e1, 0x27703d73, + 0x6504a0cb, 0x587f566e, 0xe067e6e3, 0xd3ce0f64, 0xfd482ad5, 0x449ba984, 0x2d536a80, 0x95f4e22b, 0x36d842c6, + 0x4412332a, 0xa86fb1c5, 0xea6db14f, 0xed0f3b73, 0x7e709a37, 0xaf0ee520, 0x9f9b3aed, 0x9cd9a8a7, 0xd171ab41, + 0xc666a9dd, 0x1b277af0, 0x918debf4, 0x7292386b, 0x0e0407cc, 0x84451046, 0xdf657582, 0x0b1c6750, 0x08f035a1, + 0x600f7988, 0xe7a3a047, 0x86f28e02, 0x73cd2126, 0x3dfeb7d2, 0x6547f858, 0xcca05932, 0x34e98328, 0x89f8ae79, + 0xcfbfcfd7, 0x0a011590, 0x77e0197d, 0x76fd8545, 0x10539b9c, 0x52438e43, 0x3abedbf8, 0x2098b213, 0xd582ba3a, + 0x01117b14, 0x4263361d, 0xaa6ea4a1, 0x03b3682a, 0x84f77bbf, 0x0edd1c00, 0x600a11eb, 0xd43dab62, 0xde64a3a0, + 0x4caad086, 0x5ef5336d, 0x4aa8fa05, 0x40992438, 0xac9c940b, 0xb3d53891, 0x19906f9a, 0x6408f173, 0x662b327b, + 0x4fda62b3, 0xe9600181, 0x518a6df6, 0x85c58453, 0xbb5192ac, 0xe63856eb, 0xa6ed1cdc, 0x20602989, 0x393a61af, + 0xf5579ef4, 0xe20bc1c9, 0x5ad4e14c, 0x198b990c, 0x9c52011d, 0x16e5fbfc, 0xfea51813, 0xc3f90250, 0x571a693c, + 0xbcfed06c, 0xb2f26451, 0x4d8b2cd0, 0x00dbbdc6, 0x85202d13, 0xb810d5ab, 0xb5ba9640, 0x9fa07308, 0x4ac0af6b, + 0xff4c2c24, 0xd09daa0d, 0x9044ab06, 0x964d4175, 0x88f556c7, 0x656e31f2, 0xe0087fe8, 0xc432b408, 0x2ede3bd6, + 0x61c48166, 0x528a872d, 0x8e899bd2, 0xd00d72c5, 0xbf3115d5, 0x67f99831, 0x8cc78a29, 0xecf09b29, 0x217e765b, + 0x270c9319, 0x11837a57, 0x1fc7632f, 0xfe2e7a9e, 0x86cfdffe, 0x70c92ffc, 0x6b441d92, 0x0544e9b8, 0x66a6c138, + 0xac2657c6, 0x3b3cfa95, 0x1b643440, 0x2ac617b8, 0x1bd24ba1, 0xcd53149c, 0x6bedfd32, 0xcaea4f5f, 0xe0f2d53a, + 0x32222cce, 0x62f04f78, 0x281c4aea, 0x92f1d746, 0xddd30925, 0xbce5006b, 0x1964137d, 0x2f339eff, 0x073b06b9, + 0x3806fabd, 0x7cfdd1de, 0x8ea92392, 0xca2bf0c7, 0x6f19258a, 0xf3dfff39, 0x838e7d04, 0x21ee01b5, 0x4f79ad31, + 0xc81dec10, 0x8a021570, 0x032740a9, 0x671404de, 0x64b4f318, 0xe425749a, 0xb9f196ad, 0x752ca164, 0x55918347, + 0xfb3cbd07, 0x4a250a48, 0xf90af985, 0xdf827279, 0x1ff54a6d, 0x73a2e24d, 0x9d8a17a6, 0x22953d50, 0x9ec66708, + 0x21716936, 0x9ff27cd4, 0x66cabc9a, 0x7b15b7f9, 0xafa68161, 0x63ea3760, 0xef7e1f6d, 0x733d72dc, 0xebc902dc, + 0xaa8ecd95, 0xc633714b, 0x77cc13b6, 0x997bfd96, 0x289ab7ca, 0xeba7a264, 0xfd5c5651, 0xc3411a5b, 0x5d834ba4, + 0xd8bf1606, 0xdb24fb68, 0x1b3b9b6b, 0x80bb8791, 0x3f087e8e, 0x41c60f54, 0xe00c8f0a, 0x325554ec, 0xd1a0e434, + 0x4544b041, 0x9c42a29e, 0xb11832d1, 0x5af8ea30, 0xf9a79ab1, 0xb003d5a3, 0x942ca953, 0x582c8920, 0x2db624e1, + 0xe1424060, 0x412a9157, 0xc18d9a94, 0x68a427e4, 0x21cad876, 0xba1be04a, 0xd1ef84a9, 0x08988413, 0xe359ea1f, + 0x4cfe8dbe, 0x59863e1e, 0xf8327125, 0xd9f1753d, 0x77b4a25a, 0xf8b114c3, 0xf4259e25, 0x3d952dfe, 0xa0191376, + 0xe09dcb7f, 0xb761cbca, 0xfede9076, 0xb1404d99, 0xe1fc4db2, 0x00f50f6f, 0x7ae04d6c, 0xb339f845, 0x8ed71398, + 0x3a737281, 0xd04cef9f, 0x57a1615c, 0xef045732, 0x04503c6b, 0xddac7645, 0xa8f9f113, 0x61ef0675, 0xd21eb19a, + 0x0c4d93f9, 0xa485da9c, 0xf2ce65dd, 0xf2245f2d, 0x92090dc0, 0x72d599bb, 0x286d1e79, 0xad640608, 0xc7acf68d, + 0xeda7eb5d, 0x950e6744, 0x3922089f, 0x7b3037f8, 0x9e11b096, 0x7a46bb38, 0x1a15acac, 0x35902c06, 0xcc114eb1, + 0x81e319c8, 0x84c439d1, 0xafc550bf, 0xdc85cf14, 0x696e8ab8, 0x0a2ca729, 0x47c2502e, 0x8cf7732d, 0xb7589765, + 0x076ee187, 0xc4e26443, 0xe1c28f20, 0x8e01fc17, 0x97d32480, 0xcabb61d7, 0x82130285, 0x05aa1ce2, 0x6fd4ffdb, + 0x679b3fe6, 0x3454908f, 0x471e3edc, 0x36336495, 0x0a4739a7, 0x67cbf051, 0x6af0d047, 0x7da98fbb, 0x66174df0, + 0x8f75cbfa, 0xb42d0bca, 0xadceb870, 0x049a5a91, 0xa70439f1, 0xbe5b57ac, 0x856f0055, 0x07805fcc, 0xff4a7940, + 0xba3dd26e, 0xcbe3efbb, 0x90fd3ca6, 0xef180cad, 0xd49a2fe1, 0xeac70e33, 0x47640130, 0xc80fbcfd, 0x60d37b9a, + 0x66157a7f, 0x33b6be90, 0x9b7f1b83, 0x896fbe7d, 0x638886f4, 0x39b0322c, 0x37dcee0c, 0x54771a0c, 0xba7dd17e, + 0x19846706, 0xc08e1d00, 0xe17af913, 0x3221206b, 0x4eab89c7, 0xe589fd1f, 0x42b34450, 0x7fe711da, 0x7d235a38, + 0xbd725ee7, 0x8abcfd6f, 0xff5eb551, 0xdefdf921, 0x11c61d72, 0xc184d800, 0xe0f21ede, 0xbca2053c, 0xd7cce490, + 0x477fd3a2, 0xfef06802, 0xe205b0a1, 0x6796703a, 0x55a826c0, 0x91f7cd58, 0x28fe3da1, 0x68d27f1e, 0xa154309a, + 0xbd85d001, 0x4676e242, 0x2a4df060, 0x48767dfa, 0x7ba2eebf, 0xc3477ae5, 0xaf147174, 0x91fba18a, 0x2784b532, + 0x753a8929, 0xef7923b6, 0x840468d0, 0xee3c5ecc, 0xb98a6df0, 0x6b1977af, 0x59d7d858, 0x044e36dd, 0xc6441e11, + 0x5ab4eb9a, 0xd6954d71, 0xdbeb3110, 0x2ee22ed4, 0x3b09d65e, 0x226ceb8b, 0xf27a3424, 0x09bf27c5, 0xb1c9aac3, + 0x2db6a327, 0x3e15b3f9, 0xaab2e756, 0xd553ed67, 0xb694dba3, 0xee34f592, 0x23381868, 0xbb0d2b4f, 0x20a3cbf8, + 0x31daf122, 0xaf83621e, 0x3f6e3ade, 0x4475370b, 0xd12ddb85, 0x7bb94e5a, 0x970544bf, 0x471571f7, 0x8eecabd5, + 0x448e570b, 0x7e811c48, 0x76705125, 0xf4d7ef8e, 0xdbfa0a3c, 0x9871cfe6, 0xb9f13da2, 0xd06ce447, 0x9bc03f0d, + 0x34a34a38, 0x4b125fda, 0xbcc405cf, 0x3086bfd3, 0xf402de74, 0x693de838, 0x390fb739, 0x0304de02, 0xee05c928, + 0xb9b2b7c5, 0xe8692942, 0xfcff3148, 0xe8b6a95a, 0xba8439a4, 0x94e0ab9d, 0x2b67abe7, 0xf6b887ac, 0xd51d90fc, + 0x0cfe4129, 0x08bedd8f, 0x20aca1e2, 0x2d97f7dc, 0x768baf2c, 0xe070c4cf, 0x887b630a, 0x39226ce3, 0x223d3135, + 0x67087ecc, 0xde71591e, 0x9f449967, 0xe29397da, 0x4c86b95b, 0x9d0e9d46, 0xfd45a499, 0x8dff712c, 0x4b9efb11, + 0x8a7666bd, 0xb34bbc1a, 0xb8edc228, 0xd40a8ef0, 0x1c258871, 0x694cc695, 0x7f4ae6c1, 0x05798857, 0x0b2b387d, + 0xa3eb06f6, 0x26938660, 0xe6be3e7a, 0x9f04da64, 0x280c94cc, 0x88ba3c14, 0xf1eb649e, 0x1fb22abc, 0x3068af2e, + 0xd508d5f7, 0x456a7c1e, 0x755ccda5, 0xab47dfee, 0x37baae20, 0x522d9457, 0xd3bf8559, 0x557a5787, 0x54f484d2, + 0x834f0bf6, 0x90f10bec, 0xc89437f7, 0x40f24d50, 0x7da6c287, 0x85d4673e, 0xf5ef574a, 0x603ad149, 0x776d52f6, + 0xd5ff1c6f, 0x0b6ae110, 0x7f8e75bd, 0x29f34d63, 0x1a591451, 0xb158e06a, 0xb3cbde06, 0x5efa86f8, 0xb750b02e, + 0xa1d7d275, 0x928f8907, 0x7c1a228e, 0x59337335, 0xf7b7d508, 0x0ccea95f, 0xa3425d64, 0xdca257c0, 0xc43ca2f4, + 0xc65aaf40, 0xfee70d4f, 0x2e4112db, 0xbb52a3fd, 0x617d350f, 0x0235fb8d, 0x2738b3a4, 0x94e0034f, 0x57b28e1d, + 0x1eb54cc6, 0xec150a15, 0x4129a4ba, 0xa4e0a2df, 0x9c47a5ed, 0x8d963a28, 0x9b51b089, 0xcdd65aae, 0xc4bc26f6, + 0xeab4f15f, 0xc03f5105, 0xbbf8d7a1, 0xbbedb86b, 0x4ff3abf6, 0x4cf91f47, 0x81e3468b, 0x0203924a, 0x1280b5c1, + 0xfbeafea1, 0xa515e378, 0xa0af03eb, 0xc8ef5d11, 0x0bb01526, 0xae116bd4, 0xfec987bf, 0x455b2152, 0xa573f4cf, + 0xf7080fa4, 0x5186a1df, 0xb680ffe9, 0x18dac264, 0x3fc55505, 0xadc52c04, 0xab52b9a3, 0xb43d0280, 0xbbce7dc7, + 0x85a91ee6, 0x71ef84de, 0x4c0fd9fd, 0x3096c86f, 0x4804c9b7, 0x8c3e5aad, 0xdf5ba9cc, 0x6a8d1d59, 0x17525e19, + 0x85a919f9, 0xe8d2ae05, 0x4fd7bc70, 0x25fb552a, 0x17ed91e4, 0xb1fcf491, 0xd207fadf, 0x987b012a, 0x7570c3e8, + 0x4ab8eee5, 0x120b730d, 0x6ed38b5d, 0xb957464f, 0xd5d803dd, 0xf6b76176, 0x9d5f8513, 0x9a7ebda1, 0x5f4c70cf, + 0x25c56da4, 0x6dc8a442, 0x5eff37d7, 0x509f5861, 0x786958c1, 0x0dd17bda, 0x927069bb, 0xec2889c8, 0xb747b354, + 0x3504c4f1, 0x94258395, 0x05836f5e, 0x12068054, 0x42751853, 0x05859782, 0x784882ad, 0xc3988e94, 0x20c7eb21, + 0x6f5d9be5, 0x23840867, 0xfc160e47, 0xbb3bfe14, 0x2497e7ee, 0x42e5f8c2, 0xbdb0d262, 0x97d52dd1, 0x512c6081, + 0xf2beb1b9, 0xdab5a157, 0x9a86a417, 0x1f9a1932, 0xcf9da6e5, 0xf82d53a0, 0x2b0baa7e, 0x2327b4a2, 0xd71a161a, + 0xdf403475, 0x948bfb49, 0x24fc9862, 0x225123cf, 0xced76b57, 0x755bc1ec, 0xd0a2dc53, 0x64bfa749, 0xeca16661, + 0x61183c53, 0xcbbf1397, 0x49c5459a, 0x18e394b2, 0x1be4f48c, 0xf7d8ec91, 0xd81fc5c6, 0xcdb1c20b, 0xfe3c90b0, + 0x4b836637, 0x556781e5, 0x5af18ba0, 0xf0e454e4, 0x79278ba0, 0xe0c76baf, 0xb36c577e, 0xa23b9489, 0x11305ed4, + 0x1b2cf419, 0x250a4de5, 0xe5cf8de5, 0xc5aba253, 0xaba81623, 0xbf255563, 0x5956abd8, 0x54354af8, 0xae4ae23e, + 0x138d859c, 0xb6ab68ea, 0x28c55e2c, 0x5dc5e110, 0xb467d47c, 0xc3cc8685, 0xe1566c24, 0x322c8890, 0x677857fe, + 0xfe8eb38f, 0x0b61ea66, 0xddd1b4ca, 0x6f1cbf51, 0x44f08357, 0xcbe21396, 0x744fe8b9, 0x143b958b, 0xab05e6fe, + 0x3c54dcd1, 0xa5b694a5, 0x0030a4b7, 0x254a05bb, 0x4214883d, 0xd53902f1, 0xcc0e599a, 0x22298028, 0xa55470d9, + 0xbee9ff6c, 0xaf1e2a5e, 0x0f69d102, 0xfc02aa22, 0x19f1d3c7, 0xb6aa4ebe, 0xf1751cec, 0x8a0ae852, 0xd180a904, + 0xad8605a1, 0xb5f57878, 0x6b6db0ed, 0xaaf42553, 0x64f45bb7, 0x9ff787a7, 0x84e527c0, 0xb2839040, 0x4f044fec, + 0x14cbd950, 0x522ae19f, 0x0030916b, 0x517635ca, 0xc3a74420, 0xf13d6a0e, 0xeadd4b6e, 0x8e20585b, 0x0b36ab20, + 0x5f6b6be3, 0x6126831b, 0xdf84a59f, 0x4dd6380d, 0xb77899f2, 0xbb5e5703, 0xf2086ddc, 0x6532cc3a, 0xdb8aa73e, + 0x6570ee92, 0xf32f68c8, 0x019ddfdf, 0xa57896e4, 0xc10e0c77, 0xe3f15ffe, 0x900e26cc, 0x3cd78e47, 0x14354762, + 0x9d6a699a, 0x3ab5c295, 0x15bd0b3f, 0x751f7fab, 0x134faaa0, 0x70e112a9, 0xad293978, 0xdf35c6f2, 0x4ba653e2, + 0xc4fefeb4, 0x5b4e5baf, 0xefb1d2dd, 0xf79e0d2b, 0xbc488b42, 0xe7f21b7d, 0x5aa9157d, 0x6b86dec9, 0x835312f6, + 0x6adf72e9, 0xf613d479, 0xa2379126, 0xefe91cb2, 0x124d80d8, 0xf810e5b7, 0xa9780fd0, 0x15f06bb7, 0x50145248, + 0x502c59c2, 0xc8271ed4, 0x718152d3, 0xb138b95b, 0xfb031cf7, 0x5c4d4895, 0x7aa222ac, 0x566cacfc, 0x3283df05, + 0xe3b5f754, 0x91288231, 0xeb9b4a58, 0x3ab36dfe, 0xae69ec8f, 0xf9e33e4e, 0xbe85bb36, 0x870dca46, 0x7154ead6, + 0x6c3d6885, 0xde765276, 0x09309ecf, 0x5d1c9e35, 0x7cd844a9, 0xa1252152, 0x9967ff0d, 0xa792dde0, 0x2b5e20c1, + 0xebccd1cb, 0x3ceb2b15, 0x49538aae, 0xc1ae7073, 0x10ea8682, 0x6afbba45, 0xe0973996, 0xda059f47, 0xc5fdac19, + 0x7f0f74b3, 0x424d8f46, 0xfd844473, 0x2a8aebd0, 0x69dc3074, 0x86fe309d, 0x55c9310e, 0x0d7f978c, 0xc6dbee41, + 0x19c6edb1, 0x95c916c1, 0x77110905, 0x17deb9f5, 0x8bd33b28, 0xb483f91c, 0x1121b3cc, 0xf6233cb6, 0xef243748, + 0x9271a226, 0x01d89f4a, 0x2338f83f, 0x215fdd9c, 0xc62470c2, 0x6159032f, 0x7c523bea, 0x1d80e70b, 0x49d67bf1, + 0xbf6fd8c2, 0x6555f052, 0x224ac6ca, 0x1095a7fa, 0xf4161b64, 0xd3023679, 0x97f93cf6, 0xe8d0a971, 0x7355a50a, + 0xed4a763f, 0x977bffbc, 0xde073c28, 0x52826765, 0x97e44e42, 0xaed68ae8, 0x8ace251f, 0x71edc9de, 0x16cab2c1, + 0x96eddbcc, 0xfb734d47, 0x71480c74, 0x84b94b94, 0x6c236c04, 0x4d0c3de6, 0xb562e004, 0x3a986190, 0xadc294cd, + 0x3b006f5a, 0x2146b5c3, 0x196571c0, 0xdc6552e2, 0xfa52b97f, 0x11f974b4, 0x7b966641, 0x23f081fa, 0xae22a48c, + 0x056ebc03, 0x5dbb6742, 0x273b0378, 0x19f09b75, 0x35fc426a, 0x16c0e434, 0x97eb86cb, 0x323f6f61, 0x077820d4, + 0x2ae697d9, 0x2dca47ac, 0xe4b2af3d, 0xb53f500f, 0x7f8e17d1, 0xdcda13a7, 0xc531b97e, 0xdca522c0, 0x226ed058, + 0x90551792, 0x175e9a12, 0x53d3838c, 0x12f4451f, 0x738d2aea, 0xeb18a832, 0x5646355b, 0x8695d90d, 0x2a87de20, + 0x237b5c4d, 0x7d56d740, 0x8696dd8f, 0x0eee469e, 0x0477d2be, 0x76420bfe, 0xbfc3c534, 0x2d734253, 0x14749579, + 0x33a47713, 0xf58375b0, 0x9db44d59, 0x5dd5a550, 0x9594103c, 0x672172b6, 0x9721a601, 0xf22bce5d, 0xc6078ab6, + 0xc214a017, 0x7d2bcd16, 0x4461cdaa, 0xe9fcccc3, 0x9dd03af7, 0x00d0ab31, 0x4044ba0f, 0x079023d6, 0x3356d18f, + 0x07f4cc75, 0x8a15eaca, 0xd7e93425, 0x8f749cb9, 0x7f0da3b7, 0x927a943d, 0x23258aa0, 0xe65189c4, 0x1a97f8e7, + 0xbc772ba8, 0xec579f52, 0x31bca957, 0x0ff87e8a, 0xdba76ad6, 0x98d22cb6, 0xc20f56e0, 0xa647618b, 0xfcafe613, + 0x0b792c28, 0xd0d3d611, 0xb0206927, 0x91bee8e4, 0xe275c131, 0x5eb76a17, 0xb3aa5551, 0xd2709740, 0xbd98bfa9, + 0x82d101bb, 0x17ec637e, 0xa1f440a2, 0x4e8ba3f9, 0x22e2e36d, 0xca6a319d, 0xfbb6696c, 0x14137e4b, 0xfd07b93a, + 0x88187f43, 0xe25ec3c6, 0xeed94802, 0xd3cc9ee2, 0xbf24a2cb, 0x6a135c35, 0x0e03b434, 0x4ec89ccd, 0x6ea06429, + 0xd48a5822, 0x10189fcd, 0x4d8f8ce1, 0x1fb21f86, 0xdd542d32, 0x944bd3ec, 0x6df5785b, 0x588b4182, 0xf9fd1d64, + 0x94ff2b13, 0xd01c64b0, 0x02e8d32f, 0xfb51a649, 0x675b91f2, 0xe468ebcd, 0x0b78ef1b, 0x32bd69e0, 0x977084b2, + 0xedee1dc9, 0x54a06b39, 0xb4c0719d, 0x8b8f4989, 0x608d4eaa, 0x034e4683, 0xb2558cd0, 0x4feb8c0d, 0xc6a764c6, + 0x97c6225f, 0xb90e31e6, 0xcb6f3bcb, 0x29c445da, 0xf445a686, 0x83fdbecc, 0xd968f247, 0x868d2474, 0x9bd3cb08, + 0xa0f84f35, 0x91e211ad, 0x93a8c50a, 0x44a68fa8, 0x05aa1550, 0x1fe3a0b7, 0xe31f0d49, 0x6b7586d5, 0xb259cc82, + 0xf4c1cb1f, 0x942452d9, 0x4ea1beab, 0xa47b1a74, 0x7d1f64d5, 0x4afff063, 0x8533476d, 0x57313806, 0xf63d7c84, + 0xe3b34678, 0x8d5f885a, 0x4b28b571, 0xf975ed59, 0x895c16da, 0x30c3bc0c, 0x8ebbba49, 0x212ec712, 0x189c94ef, + 0xe2de388d, 0x12b13ee8, 0xed353d9e, 0xb62fedf6, 0x1c0c0536, 0x77d7ab11, 0x25b7c9ae, 0x69b40dc5, 0x5bf65ca2, + 0x8e4af743, 0xdee6c528, 0xd9c226e8, 0xddeb659c, 0xfbd87368, 0x0a0c0944, 0x2e1dcc24, 0xd1d71331, 0x6ca6d66d, + 0x9aa7ed35, 0x89f4b92e, 0xebe97071, 0x14f55b49, 0x4bad0750, 0xe692d6b0, 0xe51f95c9, 0xbd618500, 0x0230a9eb, + 0x3b6ee594, 0xba3212db, 0x96e1dc9e, 0xb6a8ed36, 0x0e939743, 0x52fad7e9, 0x3ce8c1b0, 0x31d9ba70, 0x6f0cde45, + 0x162f7ba0, 0x694fcbd7, 0x06d9a23b, 0xecffd9c6, 0xa0ac4b0a, 0x6004d03f, 0x8a6d36d8, 0xa616d57d, 0x9ea25802, + 0x65fe2b0e, 0x0f2c1340, 0xba689a69, 0x03c0caba, 0xc2c2867c, 0x74508495, 0x5d7e5ff7, 0x5f44a6ee, 0xe05a8d92, + 0x20641689, 0x7cefbb52, 0xb3abf4b1, 0x68258b5d, 0xfcab5325, 0x9d01fb49, 0x883ff097, 0xda553543, 0x3a09bd66, + 0x9ec26962, 0x12316d11, 0x9bafc881, 0x453c698c, 0x5b1d47c8, 0x707bf851, 0x7bd92353, 0x8179137d, 0xd6d03391, + 0xd490037d, 0x9265db64, 0x28e997af, 0xa742c9ab, 0xfbc8f9ee, 0x1976804e, 0xd7532d61, 0x0f81c023, 0x53457024, + 0x95ebafb7, 0xa5e16160, 0x7cfb5806, 0x73eaff15, 0x934d782b, 0x0ea9c60e, 0xa1e6b17c, 0x3231b481, 0xdb2f5923, + 0x23207cae, 0x8d5f5867, 0xa2165d07, 0xb312e6ca, 0xfa28b7d8, 0x0bdb5355, 0x73c38cf3, 0x95ed4789, 0x26e8d8af, + 0x38e0e6c3, 0xb7e8cb7e, 0x0cfeeefd, 0xbc8ea901, 0x0030d958, 0xd0d597d2, 0xfcad5b25, 0x5d950693, 0x131f4e81, + 0x421fb3dd, 0x723a94b2, 0x13d1549d, 0x5eff5c43, 0xc7199ac4, 0x06be9094, 0x1345abea, 0x6cecd91d, 0xfc78a14c, + 0x39b505d3, 0x55f77bfc, 0x2f4c8894, 0x00d9ca3b, 0x588a852b, 0x54232571, 0xfa1d3614, 0xce893159, 0xa7eb369c, + 0x1720d0b3, 0xc7493369, 0xe6d03427, 0x7ac9cd9d, 0x225b4f73, 0x4e5c46e3, 0x0326de68, 0x398bd1f6, 0xfd8ae901, + 0xcc027be3, 0xdbd37a6f, 0x1187778e, 0xb80e1e44, 0x3bac8341, 0x4045becd, 0x83678105, 0x361d5b98, 0xc041b4ab, + 0x0ff20c75, 0x6d85769e, 0xcfdf8eba, 0x66ede2b8, 0x7546fabc, 0x31a585d8, 0xd95d8b6c, 0xcd820ba4, 0x17e5f470, + 0x74ebec06, 0x24c2c8ac, 0x58a8324d, 0x88d28336, 0x1d2cb81e, 0xa3737889, 0x83cb6246, 0xb4870a7b, 0x40e7ce15, + 0xe6c2d647, 0x7ce1cda2, 0xf519577e, 0xeb98139a, 0xb188dbcf, 0x410a8fef, 0xb32c0ac0, 0x26934fb0, 0xfe6bb85b, + 0xe6e7e321, 0xfe3815cb, 0x39891e92, 0x9ea928a0, 0x808848c2, 0xaef16ded, 0xf3f5d35d, 0x3f4d699e, 0x61750dc2, + 0xfc61f29b, 0x16949d63, 0xad27b6ae, 0xe7f80937, 0x8d2ccdd7, 0xf0c5575e, 0x27ec8ca0, 0x76f87a58, 0xb4acd187, + 0xbc6eca0c, 0xcdd03f43, 0x1636010f, 0x7c569d41, 0xcf6720a5, 0x5a1e05d3, 0xc88dbbac, 0x537ceaf9, 0xd2d1567c, + 0x471cf798, 0xfc4ea62a, 0x40085c14, 0x8a2f153b, 0xd340d9a4, 0x5e62d588, 0x0b4cbbc4, 0x2af9446b, 0x74a4ec51, + 0x0b60cb45, 0x2880985a, 0x98b7ca90, 0x84884828, 0xd8b729c2, 0x160cf0e2, 0x8b9e0a33, 0xd528ff1c, 0xf3713f27, + 0x53789656, 0xfd8d1603, 0xf199d50d, 0xd76ef7f1, 0x1cd59be4, 0xc1f5f721, 0xc299c87e, 0x9f0378aa, 0x112cfe71, + 0xb0bdbdf6, 0x20e7ea47, 0x0a04f32a, 0xe613f10c, 0x277b4935, 0xb8752a42, 0x456313a4, 0xd7091a19, 0x15c24e40, + 0xb2218afa, 0x1c6fa453, 0x4333f97b, 0x8143703d, 0x4205ffdb, 0xf53435cb, 0x90f06e14, 0x125e7710, 0x3e8b817b, + 0x4efc46c7, 0x220aca2c, 0x29ad3364, 0x209d4a4a, 0xe5fb6179, 0xa2cff83c, 0xdf718e93, 0x8c81498d, 0xaa8486b3, + 0x308de16e, 0x844c793a, 0x7e1e2d40, 0xee069493, 0xa1cc8fcb, 0x21612b7b, 0x9294c821, 0xc640f204, 0x3531fdf6, + 0x2787b76d, 0x98432667, 0x27de809e, 0x71e85079, 0xa68d1b3f, 0xcd155b42, 0xfd2ce635, 0xf85224f4, 0xb3cee050, + 0x45447425, 0xa3bcc3f6, 0x7b391115, 0x6c83c7ef, 0xb372e7b8, 0x6b624482, 0xc9a8beec, 0xcd430082, 0xf1eb550d, + 0xee59781d, 0xd0588afd, 0xf799e61e, 0x54b9434e, 0xdc85c5a8, 0x18dfdd47, 0x128a80f3, 0xdccf26be, 0xeb845176, + 0x93b7d3b8, 0xc4ab1f61, 0x9aa83897, 0x581681f5, 0xf71d557c, 0xcbf9bb05, 0xa1d5817f, 0x1a32e7f3, 0x6af2c6e2, + 0xe69f42d7, 0x2bdef124, 0x17477b10, 0x8daf1655, 0xb66c34c9, 0xd7581a72, 0x136ce945, 0x20d22044, 0xf7b3ce34, + 0xd09db28c, 0xabf654e2, 0xc7bcb6bd, 0x3d3d6f97, 0x42200aaa, 0x6d1f91e3, 0xf184c3d4, 0x89833d4b, 0x28e6804d, + 0x1621d342, 0x2a4bad38, 0x11f41b4b, 0x8fe52cd3, 0x4fa4225b, 0x4ccea7e4, 0x3dd43888, 0x56f9f22e, 0xf3bf36ea, + 0x7838d875, 0xc2ab6978, 0x62b79fa5, 0x04409b8e, 0x8c416081, 0x07aeaecc, 0x2f239e11, 0x84545410, 0x5211d675, + 0x364eb6bc, 0xb789ea7c, 0x9fe64366, 0xf90b449e, 0x062481dc, 0xdf347d37, 0x7dd71cb3, 0xc451d00a, 0xc04dbadf, + 0x18c3df35, 0xdf32c4e8, 0x570372ee, 0xeb5bb1df, 0xbbae95e5, 0x77e7e52b, 0x059718fc, 0x71c41a94, 0x3fcd86e2, + 0x3972c4b6, 0x6de00867, 0xecd860d6, 0x5b4fa575, 0x64fe7e9b, 0xbc2421ee, 0x1b272e20, 0x81f55f73, 0xa4ec1311, + 0xc0c1ca2d, 0x9c11979a, 0x2dc5ab1a, 0x79905742, 0x13b3c373, 0xe4f47f7a, 0x594faf39, 0xa7d76a91, 0xc9c8091d, + 0xf2e79d66, 0xe0909c89, 0x8a05d398, 0x4a52b86f, 0x35fc9e62, 0xca009dfd, 0x2a5f31c0, 0xaa19da7c, 0x9da05481, + 0xf6a03189, 0x12f8c923, 0x36527327, 0x181d6027, 0x775fe5e4, 0x4bf77ef2, 0x2500da96, 0x6be8464f, 0xdac0173a, + 0xf771709c, 0x6e73f62b, 0x25583611, 0x5416bb9b, 0xb8092dfd, 0x72d102a2, 0x8bc34b1b, 0x51c8ca6f, 0x3078be98, + 0x85efe4bb, 0x4d023799, 0x696001e1, 0x45925265, 0xdf08155e, 0xd72f8eea, 0xb9d47b44, 0xcd095557, 0xb762d1d6, + 0x9c514142, 0xcad5396d, 0x744f3676, 0xe7dc649a, 0x6c43812a, 0x801df11e, 0x21421cfd, 0x464353ec, 0xf12a5ced, + 0x0e66b69a, 0x5b1e2274, 0xc52a3263, 0xc1b5f6e9, 0x449fb2b4, 0x832ba657, 0x6462b723, 0xf203e9b0, 0xfcf70f45, + 0x08ba5c5d, 0xcb96b4a0, 0x5985a570, 0x3744a5d8, 0x8f3e40dc, 0x8aee405d, 0xefab98e8, 0xaad27da9, 0xbb608302, + 0x770bdaf0, 0xe5a4c61d, 0x29e211bc, 0xf276b5b9, 0x0570c799, 0x321e508e, 0xdd1abc1a, 0xc8346064, 0x1b803a8c, + 0x9f44ab31, 0x58c83412, 0xcd859c18, 0xb82f1a9a, 0xb2e21376, 0x46a001ec, 0xccc78404, 0x75306cc2, 0x19abe50d, + 0xabcdd001, 0x933ae5ee, 0x29173e05, 0x7f27199a, 0x8b1456ac, 0xcf4fd945, 0xc769ab6f, 0x4125d2e1, 0x8ce679f3, + 0x24440b14, 0xeaa8742d, 0x743fb658, 0x095ac15b, 0x581d1bea, 0x92bd1033, 0x79a1da49, 0x424646c0, 0xe0347bc9, + 0x7dcf0021, 0xb421b43a, 0xc8be6615, 0x652f8cd9, 0x46cb3782, 0xf3bab7a4, 0xa2839090, 0x34c2785b, 0x705fa7a4, + 0xaa1d7083, 0xc732c292, 0x1fef7f0d, 0x474c09aa, 0x4a0355d2, 0xca029351, 0xceca09e4, 0xd8e3ab36, 0xe71efe2d, + 0x37666710, 0x4f32e5be, 0x65345af7, 0x47352116, 0x23535b8c, 0x57927b0b, 0x3e1a39b7, 0xbbcae9b6, 0x45b7e2b1, + 0xc8e2ee92, 0xb937c795, 0x83a0da63, 0x5f560ba0, 0x695dd28a, 0xcb6adf60, 0xfd5036ba, 0x154daa33, 0x15c39118, + 0xa77278bb, 0xe538e188, 0xe6b717b9, 0x11c3b802, 0xfa91bc78, 0x3bd5c85e, 0x089bef8a, 0x2263562a, 0xda4e7b59, + 0xe1698e2a, 0xed472ee2, 0x85268f92, 0x36ae9c0c, 0x2e31b796, 0x47d96081, 0x162c6c0d, 0xf9fe6fc6, 0xb2f21cba, + 0x083b64ac, 0x26991fae, 0x021480da, 0x0a9be338, 0x0cb597d1, 0xf82bdb93, 0x99674c09, 0xc2ef2ee3, 0xea6b9298, + 0x287626c3, 0xceaf5b22, 0xf33625a1, 0xb60b2bfb, 0xd85c6ca5, 0x6a19e7a7, 0x82a3f0ee, 0x089f85b9, 0x97df6de9, + 0x44bdbf1a, 0xa2a96965, 0x7078e4cf, 0x1b2ad738, 0xb4fff8d0, 0xbdff601d, 0x0dac0408, 0x9f9d3f76, 0x9f14276d, + 0x17cf39fa, 0x29228766, 0x52f50e91, 0x9fa7cb0d, 0xe8ae194b, 0xbbf7c1e8, 0x4f4a30ff, 0x8af60b3e, 0x7cd1292d, + 0x33f0c0ed, 0x5f55860f, 0x66dc282f, 0xe8377ef8, 0x5909fddb, 0xdc216942, 0x293b713f, 0xc7ee7977, 0xcac17ff5, + 0xd161ebf6, 0x287e4467, 0x665c78e6, 0xcf99a6e1, 0xd5cc878c, 0xfe8e30db, 0xfd8c31ac, 0x21e6ba64, 0xe59f64ef, + 0x4967b191, 0xb16b7f1c, 0xfa850359, 0xf8cad6e8, 0xec8d08e6, 0x59c82330, 0x86627afd, 0x28e9daab, 0x67d52436, + 0xe2ac95d8, 0xb9015a43, 0x15e80aa0, 0x29721ef6, 0x9677b030, 0x35940848, 0xd63e8c9d, 0x351a0313, 0x7f8fc681, + 0x34e57823, 0x52515564, 0xd834ebbe, 0x8dfa3ce5, 0x6f572947, 0x2f174c8c, 0xd7e919a5, 0xd0d970c8, 0x4fe42fa9, + 0x3214e3e4, 0xd8936f03, 0xd38db567, 0x7c29cb4f, 0xf6257d39, 0x5c065baf, 0xefe6255e, 0x88da2ce9, 0x2e16ec46, + 0xfcef6a1d, 0xe1b02b8a, 0x971e3d83, 0x340ae725, 0xdcd77616, 0x836a6d55, 0xba478746, 0x2abede00, 0xccb94c2e, + 0xd010d04e, 0x154f28db, 0x5461fba8, 0x09666baa, 0x697fae45, 0x1dcff8e9, 0x46b154a3, 0xc7c91ab9, 0xa467715c, + 0x0aa020a4, 0xd075bd9a, 0x7ad8a641, 0x11a9eaa8, 0x6f298a1c, 0xc7303180, 0x4638c946, 0x2e64814f, 0x07937bef, + 0x9b4324a5, 0x8ea76d5c, 0x686e667e, 0xbd83ce6b, 0x394931f1, 0x447a1bfe, 0xa4cc4f0b, 0x72762bd6, 0x4bc9b299, + 0xc21a7c63, 0x025a37b9, 0x7712637c, 0xae402638, 0xed12169c, 0x515e1324, 0xad388867, 0x13c01940, 0x97fea327, + 0x27a09be5, 0xd1a52c37, 0x656fa21f, 0x4ddd40c6, 0xa7c66fe6, 0x1ab2dfd3, 0xd19cb225, 0x1489b389, 0x8f9ae842, + 0xd3da037f, 0x43dfe8c3, 0x1beff226, 0x73a4b143, 0x724052c3, 0xea9b1b0c, 0x133567f0, 0x6dfc58b4, 0x4f78cdc2, + 0x63b217e6, 0x62e2ac32, 0x433ce2cf, 0xcfa7487f, 0x8facf052, 0x8ce4b2b1, 0x6225f7f7, 0x2ab1dabc, 0x1c80bec1, + 0x06eab75e, 0xa586df6e, 0x5bbca8c6, 0x7e10bf8f, 0xf49d5d5c, 0x7b7aa072, 0x66fd9972, 0x4722d3c9, 0x20628631, + 0x920d6e22, 0x337e7dca, 0xd65f451a, 0x6d6eee04, 0x5ad86d55, 0xbde011ce, 0x237b3f36, 0x1ce3c964, 0xe4332869, + 0x5724a4b7, 0x3705a9d6, 0xe7b47b21, 0x8193189a, 0xe9b47c7c, 0xe53d7a0c, 0x93bf2297, 0xb28934af, 0x0eaaac60, + 0x77dcc6ef, 0x11a20fe5, 0xc5eb96b4, 0x5c74927b, 0xe8f4bf26, 0xbb61eafd, 0xe7b74a40, 0x70e588c0, 0xdd3a5f89, + 0x5e69cc54, 0x0f960107, 0xfab1aef0, 0x3e58b1be, 0x87041330, 0xd9e580ef, 0x6f7b3f5f, 0x8d53c2aa, 0x9bfa66eb, + 0x1013d5df, 0x3c4bf1fc, 0xf9a53973, 0x08f1ce49, 0x7f28caa1, 0x56c89ae9, 0x9ec6fa3c, 0x2b28bfef, 0x0b331f11, + 0xd94e1c15, 0x8fe4fe9c, 0xa4879d84, 0x438d0cfc, 0xb6704b5f, 0xfb11ec4f, 0xbb1fa27d, 0xa12406b7, 0x56298c96, + 0x039b145a, 0x8b487338, 0x463c19db, 0x486fe798, 0xe17047d7, 0xc6cb4de7, 0xc17283a2, 0xe8ec6d09, 0x62b52ebd, + 0xfe922652, 0xed1e72f4, 0x56e9d697, 0x6cb2467a, 0xde8dd18f, 0x8d552a2b, 0x1adbe5f8, 0xf5a4684e, 0xb9b87bcb, + 0xe3b63b5a, 0x7dc9e5b3, 0x18c04264, 0xd05db611, 0xc1123931, 0x554c7bfc, 0xb3354e70, 0x15b2bdc0, 0xc13c90de, + 0xb3f9212c, 0x05065064, 0x6f7e4f6a, 0xb230a8ac, 0xafc06196, 0x626578fc, 0x8eaad2c9, 0x5e6012ab, 0x730bdac3, + 0xd7f3e9aa, 0xe2a846e6, 0x776481ed, 0x735e3ebd, 0x77db7192, 0x1b15cd0e, 0xc933cabf, 0xe1b6c906, 0x548c2da0, + 0x8f9363e9, 0x11e6504f, 0x6ef19803, 0x36d2071c, 0xce0966c3, 0x7e811f35, 0x3f87fb13, 0x97771c4b, 0xfc26f57f, + 0xbd0346f0, 0xe839a13d, 0xb5377036, 0x8e0ddee3, 0xa8b416a2, 0x62318f05, 0x08cae41d, 0xe5f2121f, 0x52939d59, + 0x03b33031, 0x8f8ae94a, 0x0184ff8b, 0xac95d623, 0xa181aeee, 0x1a453685, 0x00f0f333, 0x64c25b6a, 0x99259e86, + 0xf5e9fabc, 0x1b1e70d8, 0xd36ad6d7, 0x2063ff61, 0xb111138e, 0x13dbc2cf, 0xfeeb74ce, 0x33b41811, 0x894f12f3, + 0x7952a307, 0xf1abd6ce, 0x4a039bef, 0x8f4cc102, 0x91f47356, 0x7c753fef, 0x0cbe1c94, 0x00493d48, 0x497235b8, + 0x4d85f089, 0x0032a4be, 0x796b81fa, 0x3f235021, 0xab5b18fe, 0xd3cbe040, 0xf87a0217, 0xd3d3dc53, 0x21f9ddc7, + 0xca7ac635, 0xdbd25553, 0x8c958d7e, 0x15cedd71, 0xa9793024, 0x12509b48, 0x888cb7b2, 0x1cd9acae, 0x274e2982, + 0x333b496c, 0xdd64d085, 0x929fc5c7, 0x8f7ffc45, 0x5afddcda, 0x9ecb7fae, 0x09cbfc8a, 0xb6e32db9, 0xdb622118, + 0x444dd377, 0xb3b6a34b, 0xc8857faa, 0x6ced7f5f, 0xbade9c5b, 0x5ddbab3f, 0xeeb6dd39, 0xdd6629cf, 0xeb726db6, + 0x549a94f1, 0x63d3a647, 0xe61454b1, 0x21bbddb4, 0xde185688, 0xd848c30f, 0x61b2e6d5, 0x8fa92e76, 0x4a12dbc4, + 0x7f3f5c5b, 0xd35a7bb7, 0x80b83b62, 0x487f14df, 0xbd768ef6, 0x251b9eb6, 0x88566ac5, 0x951500b3, 0x4897da96, + 0x809c2d56, 0xc76b88b9, 0xef2d6ccc, 0x0170c749, 0xae9c7dea, 0xd1575d93, 0x02a099c5, 0x58e6b760, 0xd3219757, + 0x9cdb4ee1, 0xf0f0ec22, 0x280ee29d, 0xfcfdcba4, 0x91f237bc, 0x85349612, 0x1fd38aee, 0xe3792055, 0x204bce7e, + 0x2f50b539, 0xa2082d5d, 0x68128731, 0x84e1a93e, 0x78e48d85, 0xf9dd0570, 0x59f0681b, 0xa1284be1, 0x543cb643, + 0xa7462589, 0x19905dc2, 0xe20a0cac, 0xcfb815cd, 0x62010ea7, 0x603a5d9a, 0x4dfc7b67, 0xc6104ff2, 0x628835cf, + 0x1ae664b9, 0xbf2529f4, 0xf7b64a26, 0xfaae18ac, 0x6a07d075, 0xf6396e8e, 0xf3181ce8, 0x1f66f06e, 0xbc3d791e, + 0xe68b4cac, 0x6a328b68, 0xcbebfa49, 0xd7f8cf70, 0x094bca45, 0x346edc19, 0xf291b889, 0x2fbcc4d8, 0x4355da3c, + 0x050b9863, 0x430de159, 0x1783245e, 0xc9fb02d2, 0x37dd8ac3, 0xc9ff15e6, 0x04d8b7e2, 0x9a6e011b, 0xd535cee2, + 0x58b189dd, 0x555b6be9, 0xf4163d2b, 0x7f1fc2f1, 0x2d915c6a, 0x1c454c6d, 0x722f0dd6, 0x5084c3fe, 0x95cfe57a, + 0xf43ccc64, 0x4aea8c07, 0x0efe38ee, 0x395629a0, 0xeb481b9d, 0xcff69b54, 0xf55b121e, 0x842542cc, 0x5d947fcd, + 0x10d8fba1, 0xdfe72d91, 0x4ba9e691, 0x2829eafe, 0xe1c7a58b, 0x91d1c5d8, 0x334c1a76, 0xfd8a76b3, 0x098aaa29, + 0x7208b0a7, 0xd218c592, 0x4391c86d, 0x5492be67, 0xfac44e7b, 0x4a87c6ab, 0x9f57521e, 0x6079edfa, 0xc0eecba8, + 0x8ea4658b, 0x9826afe7, 0x16a739fd, 0x323364f5, 0xdbcf0f8b, 0xbab72a26, 0x72e88b4e, 0xcfcf322d, 0x77b781fa, + 0xf7914ec6, 0x13d21517, 0xa680ed44, 0x36b0f5eb, 0x4c9db0c8, 0xdbcc6d16, 0xf53ddcd1, 0x7208d83a, 0x13f086dd, + 0x2ee7684d, 0x73e98701, 0x8aa905c5, 0x82ea2156, 0xe3081ae4, 0xde619f03, 0xa371e0f5, 0x64bd7d0d, 0x18d5d09b, + 0xbbbc7c03, 0xe6a09c22, 0xf8ca08e6, 0x67c06127, 0x4d8b9f91, 0xa3907d27, 0x85fcde07, 0x7673f42f, 0x9c73bc59, + 0x0bf57423, 0xd36d6041, 0x1ba9a920, 0x5bf62d1f, 0xd1b43b6d, 0xc0f66b26, 0xbf91a7e1, 0x3d8cf29e, 0x662919ab, + 0xba5cfad7, 0x1b36a896, 0xfa65809d, 0x251a3cea, 0x8404698d, 0x0b369623, 0x8e1f646a, 0x724c6598, 0xb3fac1ac, + 0xbcded676, 0x0231d169, 0x6282bd49, 0x4a4d72c0, 0x5b83671b, 0xc0520cfa, 0x97e95cea, 0xd46c9aa1, 0x24f1022c, + 0x3bdd4e67, 0xd992e377, 0x42022263, 0x1745f402, 0x0630362a, 0xcbdbb2fc, 0x241c8bdd, 0x69a394fd, 0xfd00d732, + 0x12b58f8d, 0x15930aab, 0x3f84b134, 0x1bc70718, 0x36a6ee7d, 0x0cab7f94, 0x37a5016a, 0x0f8d4c24, 0x605bbf2b, + 0x07dced77, 0x63df0a1d, 0x5de1ab4c, 0xbde15af7, 0x45740088, 0x6a764623, 0xeb2d907a, 0xdba11b38, 0xcc2c9adc, + 0xac5406e4, 0x98e56b32, 0x6c1ba4c7, 0xd1aa0d23, 0x369f05b2, 0xc0b39e86, 0xe4e57dd7, 0x1d07cba8, 0xa7d2fe35, + 0x3402689f, 0x6e19bafa, 0x95a60808, 0x1d950f67, 0x0566e996, 0x10bff093, 0x79bd02c4, 0x5efdfec0, 0x5f720f43, + 0x32905ff8, 0x46b5e254, 0x331095d5, 0xec2a57b8, 0x8d01738b, 0x76a4456b, 0xfeee7136, 0x47bf7fcb, 0xb8ff6125, + 0x982ce0fb, 0x44bbacf5, 0x455c045c, 0xf3bfee37, 0xe640b4ac, 0x5876a207, 0xb094f750, 0x700280f7, 0xcd4e5aaa, + 0x192d32c1, 0x7b88271e, 0x1809ebaf, 0x6d2d1180, 0x29033f92, 0x94f9d2a2, 0x2c4fc7d7, 0x68a6a4d9, 0x0cbc4252, + 0xb630c039, 0x4792c6ce, 0xaec12f46, 0xe19e655e, 0x50b8f263, 0x12924b43, 0x1b1c3fbc, 0x56fd78d9, 0xce4f9c6f, + 0xc97d3a72, 0x57164293, 0x383349e6, 0x4da649c4, 0xa9b07b93, 0x002f0215, 0x8667924d, 0x9678fe5c, 0x5863f10f, + 0x3dac9893, 0x333f3965, 0x1b97f6d9, 0xfc1bd6e3, 0x2f6d4ed4, 0x5ed2146a, 0xc2869c7b, 0xdc8517ee, 0xd93174dc, + 0x7251189a, 0x61a47cf2, 0x1f13f6bf, 0xd60de9d9, 0x8057d6a8, 0x256ea754, 0x76f4c1f6, 0xc226d0f1, 0x348dcd66, + 0xc2c16483, 0x4bccf223, 0x65932c09, 0xf921c760, 0x9701f9c2, 0x6ed64405, 0xc1be4cd9, 0x0482fcaf, 0x67730fd5, + 0x888e7491, 0xed718690, 0x30910aae, 0x096f2b8d, 0x6bbc1aba, 0x306b570c, 0x571efe8f, 0x093d6c01, 0xaccb915b, + 0x99dc5a09, 0xb52f70b8, 0x7648f1c6, 0x2b04e824, 0x2ca77886, 0xbc686f14, 0x8dd47cf9, 0xc5b455a2, 0x6b54c4ff, + 0x435822b0, 0xb363f3f1, 0xaa7b2fe1, 0x183e0d79, 0xbd217836, 0x860a657a, 0xcfaaba5d, 0x4921caf7, 0xe04077cd, + 0x05e08eb0, 0xa1fcef95, 0x5234139c, 0xf7b84530, 0xbd952da6, 0xff58d551, 0x6206e740, 0x22ab63a9, 0x0779e9c3, + 0xfe004d07, 0xa3d3d042, 0x9b676242, 0xbaa2389e, 0xd970c818, 0x5f83ef64, 0x0de0a7d7, 0x0ef6c037, 0x9d4699ac, + 0x5a767b89, 0xaf183388, 0x57f6c505, 0xdf5a7e40, 0xcf9114be, 0x53865a32, 0x15c54f5c, 0x63e27f0c, 0x3de9d1e7, + 0x93eabb84, 0x5b39b8e7, 0x0dfb7aa9, 0xf9c76d31, 0x2a5cf2ef, 0xbe732937, 0xccc6096e, 0x0638b3e4, 0x8d566db0, + 0xd8e9772d, 0x6c382968, 0x4ecb0f98, 0x06523de9, 0xf5244029, 0xac495b9d, 0xa0f71785, 0xa14bbab2, 0x7c350e40, + 0xd1899b1d, 0x9bf2be21, 0x6bfcf76c, 0xe89ba755, 0x4b539ec2, 0x4782b7f8, 0x35bad3e0, 0x0d2afdde, 0xe6e0e887, + 0xd904a9bd, 0x587b79dd, 0x28068eec, 0xf2636924, 0x16b120e2, 0x7a4f8ed3, 0x98c66e8b, 0x760ce279, 0x9cab4acd, + 0x5c98476b, 0x2e6c8733, 0x77363f05, 0x77b4320b, 0xe709738a, 0x6f8e6555, 0x43977b55, 0x5fd66d5d, 0xbacbbacf, + 0x3a01488b, 0x1f7fa3db, 0x1f5c74c7, 0xa2280cb7, 0x6dc23df1, 0x76188040, 0xb7520e98, 0x27f609b1, 0x8464a1f2, + 0x390f131e, 0x00aba320, 0x6993b755, 0xf835e9f5, 0xafb233f4, 0xcb2df6d2, 0xdff73539, 0x4a043a50, 0xab604522, + 0xbd29217d, 0xaa1fd306, 0x25aa3034, 0x8fbe28f0, 0x7b98ce11, 0x2f24af1a, 0x14684ae4, 0x6b25d5ee, 0x34da8373, + 0xf06d6d3c, 0x777e6d18, 0x6ba5eced, 0xc0a4b5a6, 0x5ab0abcc, 0xaf440cf5, 0x896a2d85, 0xe3b11137, 0x77aabcdf, + 0x7bdbb646, 0xc9b9078a, 0xf31e1cc8, 0xdd7d4665, 0x527ff25c, 0x8793d647, 0xaca83a8d, 0x3685ca40, 0x93f8fc43, + 0x2913341d, 0xc7960568, 0x3233122d, 0x808b98d3, 0xd720b914, 0x69ae737f, 0xf87c6d2e, 0x80a2c7fd, 0x0608f2f0, + 0x3680e884, 0x29f6cd01, 0x56187725, 0x2085187b, 0x8913383e, 0x395c450b, 0xf3fc52a2, 0x2e7f27b8, 0x696c019b, + 0xa364bd1a, 0x10f05fd6, 0x728c9fd8, 0x5f06f31d, 0x5d007555, 0xe73ce03a, 0xc4d2a5ee, 0x34be22c8, 0xfad15aba, + 0x168dbf55, 0xa7955245, 0x06c58db6, 0x54e35ce4, 0x73d18f16, 0x04c1bc42, 0x7dc7dd93, 0xd3b72b0a, 0xe6da13c3, + 0x61d6629c, 0x9df21798, 0x23b22f09, 0xb25cf714, 0xb5a08a85, 0xceedb3d5, 0x90e1fe76, 0x8f3f977b, 0x4f700f1e, + 0x80b65b93, 0x9032a160, 0x706224ed, 0xd638c829, 0x8ab32fe4, 0x9b2780d5, 0xcd623098, 0x9755b4b4, 0x9b89c326, + 0x1c85ceb3, 0x32690907, 0x4e3f4733, 0x6f9b9419, 0x4452df1c, 0xfeb4a8cc, 0x50b3656c, 0x0ace5d73, 0x4dab0009, + 0x256dafc4, 0x11625c41, 0x62240a7c, 0xd43cf11a, 0x235e46e6, 0xcce2f4d6, 0x393b77cf, 0x75352a0a, 0xd1461009, + 0x1aee3a6c, 0x6a83821b, 0x486e05f2, 0xc0077ce1, 0x358b6eb1, 0x1371de27, 0xe9420465, 0x6f347ab4, 0xb689fe0b, + 0x8900ad40, 0xe69baec0, 0xf5fbce45, 0xb0122907, 0x4a82560d, 0x84466f4a, 0x4d54d218, 0x0be145ac, 0x131c6b08, + 0xd7e7dcd4, 0x97ffa9bc, 0x4f047a8c, 0x61c20927, 0xd3cde6c6, 0x2f5a4c16, 0xfd49d8fb, 0x31e6a7f6, 0xc62338a7, + 0x68f1678d, 0x27f0bc46, 0xffff55f7, 0x9f382989, 0xef167545, 0xd06393e6, 0xbc6044f2, 0xf2f0c6ce, 0x0ccdd603, + 0x734ae2ec, 0xc0cb2665, 0x043d24aa, 0x8d111b0d, 0x5b70c59c, 0x244c1bd0, 0x6fb1651b, 0xcf4a6e14, 0xdfe8c3ad, + 0x77d4003b, 0x1b08fe4c, 0xffe8c8d9, 0xe67c2e47, 0x4caaf841, 0xb19d3c19, 0x5079d2e7, 0x8ca67dde, 0xe3e4abc6, + 0x097eb1e8, 0x2d42c7f6, 0x3b880c66, 0xb0b6d2d0, 0xf69c1128, 0x7e6c20d6, 0x9d9ba33f, 0x83215307, 0x0a3128ad, + 0x4b4d3793, 0x3eda96eb, 0x4f7efc95, 0x57a11fee, 0x6995eccc, 0x162176a7, 0xd5a2e081, 0x25f43607, 0x0575208c, + 0x18316235, 0x829129c5, 0x30426a56, 0x54c377e7, 0xf992eca4, 0x9d82b911, 0x54cc5f04, 0xe57f8aa3, 0x15edafb3, + 0xa5f5e6c3, 0xd829b472, 0x9123bb6f, 0xa62401de, 0xb053f3e1, 0xd7939a11, 0x4570e3c8, 0xd391f5e8, 0x981a12c0, + 0xe745a6a4, 0x81a5b292, 0x81bc0fa2, 0xf9352ba7, 0x0e1c814c, 0x6a8feda7, 0x8135d245, 0x3a984091, 0xa0e3b97c, + 0xe8599d14, 0xc17f5d04, 0x2c6b12a4, 0x28f9a8ec, 0x956ace3a, 0x27c6589b, 0xe91ca2ff, 0xcee36546, 0xf15bda0f, + 0x9b049dee, 0xfc7cd73e, 0x3051ea52, 0x611eb7bc, 0xcba646f0, 0x3ee641dd, 0x42e7df65, 0xe67249fd, 0x0b62755d, + 0xec6db8f8, 0xc8ff8e54, 0x51fa22cd, 0xad65640a, 0x4da042c2, 0x27fe1b46, 0xe3b9b3a8, 0x8b6df453, 0xd76421e0, + 0x294c74dc, 0x686d33b2, 0xb886e4fa, 0xbdc7ecf2, 0x83794449, 0xf23df42d, 0x202162d1, 0x0d3b3f9c, 0x0fa19e61, + 0x5c944e6a, 0x26b39ffd, 0xbd40f07c, 0x8336c878, 0xf599c93e, 0x8049a9fc, 0xdb9cf234, 0xe3bceca3, 0xe89c769e, + 0xc05e6cb7, 0x5761469b, 0x0842d337, 0x8e5d9c69, 0x595e54d5, 0x714c2d52, 0xda4de357, 0x19d57c12, 0x22f7c405, + 0x8ff37ef9, 0xe59177bd, 0xf40e536c, 0x23b55ca1, 0x670feea4, 0x3b421cbf, 0x80d739cf, 0x1ee8e70f, 0x2c7f8446, + 0xebb55379, 0x5e23760e, 0x2d16d0f9, 0x910274af, 0x3d2fc1c8, 0xcc966ef0, 0x59a197ed, 0xad1065ba, 0xe990ed8e, + 0x55635305, 0x1391af25, 0x247c9058, 0xa4277895, 0xd09bff24, 0x74d9fd5b, 0xf71968b6, 0xaf7b67b6, 0xd0af1523, + 0x3e1c5fc9, 0x00074d21, 0x1451a29c, 0x8a97badf, 0x1bf52541, 0xfdb6dc9e, 0x663a168b, 0xe330a63c, 0x4729420b, + 0xb48957b7, 0xddf6ecc9, 0x4167cab3, 0x8443341c, 0x86aa4cf5, 0x0bbab5de, 0x3ce045c7, 0x6073da9b, 0xc6b96522, + 0x8857c91e, 0xa292b74a, 0xd83ff830, 0x169065e7, 0x82177a3b, 0x959c44f6, 0x265801e5, 0xa8dbf934, 0xb26ff68f, + 0x434975ad, 0xe304bfc5, 0x9f549db9, 0xd27467e5, 0x63816690, 0xeee0e9df, 0xe3764d51, 0x6844089a, 0x2ba9d850, + 0x90d8241f, 0x09bdb75b, 0xeb81562d, 0xbbd0488c, 0x00909f5e, 0x6520ce8a, 0x6db18f5a, 0x0d557742, 0x0044a56e, + 0xe10a79d6, 0xc69ecf9e, 0x0dcfa2a1, 0x7312db05, 0x9651604e, 0x21853664, 0x071959b3, 0xb8b0cb77, 0x406aa1bf, + 0x82d67db0, 0x9352b085, 0x5f36947f, 0xc5c4e62d, 0x1d92307c, 0x28c48035, 0xc0aebfaf, 0x2542b54d, 0xa79d97d7, + 0x54f13fdd, 0xb77054b4, 0xaa461fca, 0x9cd31ef9, 0x38be28a0, 0xd20dc1c2, 0x97be4d9a, 0xfea59699, 0x0c2c6655, + 0x931e9216, 0xec24eeba, 0x264ef044, 0xfa68f997, 0x917a8cc0, 0x47fe0320, 0x9c27e047, 0xa0e383d4, 0xa7a93e3d, + 0xd4b4d4e6, 0x8c78cb6e, 0xcf1172b2, 0x9e53324d, 0xde3fc35e, 0xbd6168a9, 0xa4ed6dd2, 0x40a005e5, 0xea97a1bb, + 0x5197e999, 0xf971e729, 0x6eb6e6c6, 0xf2186f26, 0x956be1c0, 0x198ae0c9, 0xf8837133, 0xc5345061, 0x71523372, + 0x2c740bb8, 0x6382559a, 0x956212c7, 0x09b22bf4, 0x88915936, 0x9e24e4b5, 0x9966e99e, 0x9b23f80e, 0x07ff318a, + 0xd8ef7cb9, 0x986eedaf, 0x10ef8dd3, 0x0cff9089, 0x1f257edb, 0x2c237e15, 0x6a7995fd, 0xc43d4d42, 0x138ad595, + 0x8ffdcb40, 0x55aa67a8, 0x467f1381, 0xe66e83e1, 0xc145d848, 0x34872eb9, 0x3b90edc5, 0x4fd6fcb3, 0x5d3e5045, + 0xbe079412, 0xc5479a0d, 0x79b05534, 0x747e76d8, 0x31e925df, 0xa87e3525, 0xc4414a25, 0x41ef729d, 0xd230ac7f, + 0xbc9ec796, 0xb4727881, 0xc82bf346, 0x78ed3d54, 0x9e32c423, 0x9e1a8127, 0xb9fc08cb, 0xd1348fae, 0x9989f1f6, + 0x5119fa9b, 0x271e6a6f, 0xb501d9f6, 0xbdae23db, 0x02737f5c, 0xc6972fcb, 0xea2252d4, 0x6f02751c, 0xb4a2e2af, + 0x96ec2c6b, 0x0dcb5ea2, 0x11a521d0, 0xa0bea2b1, 0xaa5fbc07, 0xb2b9a6d7, 0xe74ec9d6, 0x101a5a17, 0x0e00bd11, + 0xe18da710, 0x38e34672, 0x344427bd, 0x09b07dee, 0xd9ee80b3, 0x1710f3f4, 0x137cefac, 0x3caddfd0, 0x12fb7527, + 0x4d1e089b, 0xf257478b, 0x1de88770, 0x17626deb, 0x137dda4f, 0x491be67d, 0xac4018ac, 0x44e904fa, 0x71dd7582, + 0xedee4aae, 0x517c902f, 0x722cad2d, 0xaa77d80d, 0x94f732ac, 0x94a66b9e, 0xa815604f, 0xc1095b01, 0x3ccf402e, + 0x3c4ad225, 0x610c054d, 0x5da0f8f0, 0x718b0069, 0x19697713, 0x310bbf3d, 0x2b026413, 0x87ca982e, 0x3c51d3b3, + 0x1c28462f, 0xd9e076de, 0x0a8de2f8, 0x398b5fb2, 0x5e205feb, 0x7f97dc47, 0xf15aea65, 0xf777f2f2, 0xe1cf4860, + 0x50c4825f, 0x775bc143, 0x591b99d9, 0xfe3b3b04, 0xe2b53ee8, 0x84f9c3d0, 0x67879577, 0xd683455c, 0x6311006e, + 0x35874796, 0x260ea5c7, 0x279ee8de, 0x4c260a82, 0xf93c65b0, 0x00a93a7b, 0x9e39c181, 0x73207992, 0x49f84f5c, + 0x0c427642, 0x4a5e3bfa, 0x665e3fec, 0x4a2116f1, 0xb25f4f47, 0xc7187265, 0xbb9976fd, 0x4b5fc70d, 0xaa1ab35c, + 0xc935f9af, 0xeccd4c01, 0x62ab2f83, 0x5d4ab686, 0x429c5981, 0xdcc8ce86, 0x7da2c94b, 0x0bd1f284, 0xe3bd78e5, + 0x1de8f2b9, 0x2ce64b0f, 0x4940c79c, 0xbbcd761a, 0x282e241c, 0xe4b22c83, 0x60fce126, 0x36d207f9, 0x57f8f5b8, + 0xc908ced2, 0xf13f7684, 0x1c16daa9, 0x7881b0dc, 0xcffb4887, 0xeb23ffee, 0x04741745, 0x1a8b440e, 0x2a279e5f, + 0xe8b87ac2, 0x48514447, 0x1faa4cb6, 0x337e3bea, 0x00a0ca68, 0x84c88fc7, 0x58446190, 0x1e1a3f57, 0xce1bbacc, + 0xfea594f0, 0x947acd59, 0x6bafa9e9, 0x6965a3eb, 0x0fc46b0f, 0xe0a8aacf, 0x226a56e5, 0xb202ee77, 0x4f0caba7, + 0x5e9de277, 0x640f1ecf, 0xd758cc98, 0x0f81e2a7, 0xb38f4ac5, 0xd4bb4163, 0x74ed4c82, 0x129beb1d, 0x161cb722, + 0x8e6dced4, 0x2d8a7243, 0xc8e2801a, 0xce153026, 0x5a1d6568, 0x47e1fea1, 0x3bb72b5d, 0xd7040b68, 0xd17c139d, + 0xc1d56ac6, 0x3363dd8a, 0xdc5710b7, 0x7711511e, 0x9cbfe5cb, 0x1d42a34b, 0xc2fab8e5, 0x7c865f6f, 0x0213204b, + 0xfe308333, 0xfb997712, 0xb579ebcb, 0x49c2f396, 0x1bc98a4b, 0xc94935eb, 0x9b84ef17, 0x868bcf75, 0x24012c26, + 0x668f494c, 0x178b9f6a, 0x6140ace4, 0xcb569d9e, 0x082b6dfa, 0xa6b491db, 0x686060ea, 0xc7a149cd, 0xa1496e1c, + 0x7d0011c2, 0xdf3a1f77, 0x658df68d, 0xfec13283, 0x1cd3a05d, 0x6946f477, 0x0cd81f71, 0xdd3238a8, 0x35468f1b, + 0xd09e5e9a, 0x1cd493cc, 0x43c1573f, 0xe020d0e7, 0x6ea79977, 0x77f41bd3, 0xfc6ab36e, 0x1e5b967a, 0x29002d46, + 0x2997ad7c, 0xa36e36ff, 0x6112f679, 0x77b14bd1, 0x137c351b, 0x50985769, 0xfa014f42, 0x581afa04, 0x85e7efab, + 0xb9dad285, 0x864c3b89, 0x5c94964a, 0x578ad33b, 0xa310f863, 0x2b7634b2, 0x63da4928, 0xf5bc388c, 0xc2575509, + 0x221d2fb3, 0x148a2035, 0x9e4eb9d8, 0xc191f057, 0xb2a3325a, 0xbd3e5a38, 0x2427389a, 0x6fd8159b, 0x83ee446d, + 0xce92ea15, 0x7d73f141, 0x57d842e7, 0x85767cd6, 0x73942fe5, 0x966bb3f6, 0xd6713857, 0xa87d1855, 0xf6f8377c, + 0xb499e6a3, 0x669a2a74, 0xcff0f256, 0xb31987b0, 0x3ecc16b2, 0x9002b65e, 0xa30d7242, 0x7f6d8394, 0xc873be87, + 0x9ecf884d, 0x0f809a60, 0x2b06a94a, 0x581c4628, 0xa37088e2, 0xd64a063e, 0xfa366d59, 0x3dbfb501, 0x81b3934c, + 0xe11b4d16, 0x98981945, 0x851d93ce, 0x4e5f73b0, 0x8713cc4a, 0x990c3e88, 0x3f10dde9, 0x2c741b6e, 0x16ca9e62, + 0x8a9574c9, 0x5fddd704, 0x91e0f946, 0xe145b261, 0xd6c8e914, 0xd46a195e, 0x836f2b84, 0x888488f9, 0xa0171075, + 0x5b68e624, 0x69bf7207, 0x97f89c5f, 0xf68bf78b, 0x0e48fcd1, 0xeb49a381, 0xe04b4e48, 0x6c2b4749, 0xa84a84e1, + 0xe7359ec5, 0x651a830b, 0x9d95b25b, 0x65d139ac, 0xd452f94f, 0x28f3612c, 0x61c87396, 0xe429effe, 0x3ea8483a, + 0xac2bf450, 0x450615bd, 0xeb94bf71, 0xa759a259, 0x418fadc4, 0x59734a93, 0x7a47a6f9, 0xe1652560, 0x5afb7d14, + 0xcca9ac68, 0x3516a22b, 0x28d369f3, 0x5d6ea00c, 0xa7c9c0ad, 0x137b9fb3, 0x2c7137c7, 0x733a939e, 0x29a50a01, + 0x3fa44daa, 0x7160a761, 0xac698f11, 0x1653e030, 0x12d99a27, 0x07a9f12d, 0x45df07e3, 0x010fc0fe, 0xfbc7b3da, + 0x6d1e6dad, 0xf992a21f, 0x52f3d632, 0x909eed95, 0xb27215d1, 0x732961e8, 0xdcd541b0, 0x28c21d54, 0x0df2b4ac, + 0xac33143e, 0xa9ea0eaa, 0xcdfa2588, 0xc927571c, 0xca35f8ca, 0xc840a0fc, 0x55b4b757, 0x9434bd7a, 0x2e1ac1e8, + 0x0a9b1162, 0x8aca7625, 0x034f9307, 0x0491ef04, 0x785d0c72, 0x73b299f7, 0xd17861e0, 0x4323eaa2, 0xd7e0aca2, + 0xf989705f, 0xc4f09bb5, 0x99fd7f86, 0x271c30d1, 0x27e92bd2, 0x7286960a, 0x255036df, 0x941e2779, 0xdb8eae4e, + 0xf6adff46, 0x2b49ac54, 0x0a1cef40, 0x1f28d624, 0x8d6162c8, 0xf080d22e, 0xb6bb18f2, 0xa880e3dd, 0xa78846fe, + 0x4d2fa3ed, 0x05378029, 0xc49b8f5b, 0x2905cb26, 0xd3aeb39a, 0x1629690b, 0xdd1757eb, 0x2ff1f673, 0x9a688a6c, + 0x1d4d24c1, 0xc9742446, 0xabda29b1, 0xcdaec5b7, 0x295c0d7e, 0xd90ff9d0, 0x978d435d, 0xaf68329f, 0x38bed6ce, + 0xcff29244, 0xd79a356e, 0x5910c2a9, 0x77e55bd1, 0x505f5a79, 0xd26d9743, 0xe070d255, 0x4e577e72, 0x68f33845, + 0xc18b2566, 0xa83308d5, 0x022b9e46, 0x2b6f4a24, 0x6c7dfc72, 0xf76630f7, 0xb12f83b8, 0xfbc91237, 0xab95158e, + 0xf8aa7ac5, 0xd76a5eba, 0x891fbec4, 0xe1cde14e, 0xf5fd0124, 0x123ce625, 0xb2e43de0, 0x65626d23, 0x3333eaf7, + 0x1f29e299, 0xd6b24c0c, 0x6a6481f5, 0xeb4ad807, 0xd7a16f02, 0x9655eb0b, 0xc22d345c, 0x3bec5fa5, 0xd22848fb, + 0xb9117606, 0x99d8de15, 0xf58f6e56, 0x7533b564, 0x90ad90f7, 0xa114cff1, 0x7fd502b8, 0xac5a34e0, 0x76e2b46e, + 0x3e106b77, 0x01e92323, 0x556d779a, 0x18b1a5ad, 0x2d9d2887, 0x54e1bd94, 0x9994a582, 0x59cf2080, 0xe17b5ab2, + 0xcb1f04ed, 0xd42fe908, 0xcd00aec8, 0x820a5c05, 0x229bee59, 0xc8446595, 0xc9dd9716, 0xdbb9653d, 0xd55f6f4c, + 0x2183da6c, 0xf615fa3d, 0x88b43107, 0x85f645a8, 0x3436b234, 0x7e553a12, 0x2cef38fa, 0xa738eed6, 0x011e4dd9, + 0x915ccf5f, 0x20b174c9, 0x25215972, 0x30b7a4cd, 0x2129f05c, 0x29ea8163, 0x13f81c91, 0x9045309b, 0x2064548b, + 0xf91efa18, 0x579d0262, 0x24c3d838, 0x8b3be565, 0x553939e8, 0x31d0c06b, 0xd314be9d, 0xb6c246d2, 0x114f9e12, + 0x1d8c0eef, 0x57c98e18, 0x50116040, 0x0778bbf1, 0x30d91dd9, 0x948b14f4, 0x1cd63672, 0xd72dbc14, 0x72c165f4, + 0xadfd0381, 0xdfee0594, 0xfd8f9a78, 0x29cf2f71, 0xe25469be, 0xec88ecda, 0xaeda0c7c, 0xa4b9957f, 0x5dc1a43f, + 0x3a77b4e7, 0x62ad807f, 0x04a337ea, 0x9b506605, 0x0379c816, 0xdb7feb21, 0x9702e194, 0x50f3c880, 0x437398f9, + 0xdb172038, 0x19658647, 0x0cad25c4, 0xdac606c6, 0xb84181d5, 0xb0dd73f1, 0x19065c8a, 0x51f1f7f8, 0xbee06590, + 0xc89c841d, 0x0c5e131e, 0x35468f66, 0x99cb53ce, 0x406283a7, 0xb2452b5a, 0xc707ab70, 0x74fe1adf, 0xa0e5107d, + 0x9c00f3bc, 0x24396759, 0xa768b114, 0x5f43e28f, 0x81aa7895, 0x66a389d3, 0xb6fceb34, 0x04ce34fe, 0x3f3905e3, + 0x5b1cfb92, 0x60cb41c7, 0x737fb221, 0x2a083549, 0xbb8d21a2, 0x1cdf9641, 0x79f3099d, 0xb43db075, 0x7ea7dedf, + 0x715888e7, 0xd1e4685a, 0x7287bcf9, 0xccdd9a60, 0xbccecffa, 0xbafb6e86, 0xf14a9b3e, 0x61e07c8e, 0x82918d5e, + 0xeb7d33b8, 0xd556421c, 0x15973a1b, 0xb90c91db, 0xa28faa1e, 0xc75b5121, 0x22dd0094, 0xa1b18fde, 0xc31376fa, + 0x05ca884a, 0xa5ebb379, 0xf63ac40b, 0x8466e9df, 0x40fbe81e, 0xe48eee20, 0x439b3381, 0x49b7ba18, 0x4219a400, + 0x5b54e97f, 0x1f080608, 0x72f70697, 0xead22ab7, 0xc8882403, 0x4a225667, 0x6fed4907, 0x9cc37375, 0xcba56457, + 0x94f85aaf, 0x9530fa6a, 0x3c478d49, 0xbc802dbc, 0x128a1538, 0xfc7e6e7e, 0x56baafa0, 0xeee4137d, 0xe0eaba4b, + 0xf64fcc01, 0x42bcc451, 0x31d11845, 0x3eec0754, 0x14e34422, 0xcf9564f1, 0x14c28626, 0x4c0d2afc, 0x3b7ac641, + 0x2e20cbae, 0xf977574e, 0xad3d0f5c, 0xdaa9c35e, 0x2f2e7b3f, 0x887c91b9, 0xf719e901, 0xd9376c89, 0x08adaa13, + 0xac741cdf, 0x8649efca, 0x8ba0702a, 0xcd6aaa37, 0x2e79f9d9, 0x1b8fbe04, 0xf6749bcf, 0xc5cc75fd, 0xb26605dc, + 0x84c6a553, 0x0c7e811d, 0x4b8181fd, 0x2674568f, 0x94896210, 0x0d6e87a6, 0xe0480f9e, 0xaf0b04f0, 0xaacd4ccc, + 0x18cec985, 0x20969a9e, 0xb190cf4a, 0x7add1f18, 0xc036fbee, 0x4245caff, 0xc344905f, 0x1dfe6053, 0xbf0601c0, + 0xa44ace0a, 0xab6273c9, 0xf2a88c45, 0xd23b8264, 0x34c2ec26, 0xce570e10, 0x0e4630bd, 0xe3eb4789, 0xf665b661, + 0xe057977b, 0xaa193923, 0x3017954f, 0x7a711b1e, 0x20583480, 0x2532da05, 0xad78e090, 0x3667ca4c, 0x066b7657, + 0x2567444b, 0x194ec9e0, 0x2edb827f, 0xb1401823, 0xc26cd9ff, 0x6fd7f641, 0x39d2f320, 0x0f0fe22a, 0x742dfee5, + 0x1ad7277d, 0x6f766d1b, 0xcc88dedf, 0xfa95ff25, 0x67c42dd6, 0x66e510f5, 0x6ed71be4, 0xf265a559, 0x8997aab8, + 0x4a86abbe, 0x4f047175, 0x59b00f4a, 0x82ba7234, 0xd3a81753, 0xac92292b, 0xe3fd3b24, 0xf6b2c4a0, 0x4c596b11, + 0x3f742cd1, 0xbb15f74e, 0x56eea259, 0x8b79eb9c, 0xf1de113d, 0x1c3d3dbe, 0xca8ef39f, 0x61b6293a, 0x4e4b74c7, + 0x319bcb75, 0xf2e48f4b, 0xdb0c8439, 0x285a9edc, 0x97f4e07c, 0xea8c9801, 0xd84438c9, 0xc2def1ce, 0x99f34b3d, + 0xbb37d944, 0xd632c6d3, 0x28044d93, 0xe200c371, 0xaa8479c1, 0xa188b88a, 0x4b2dbfea, 0xb8e34345, 0x8db34bce, + 0x329595cb, 0x2905e1bf, 0x007235a3, 0x2a2acf97, 0x0a3171de, 0x3669135e, 0x987358ce, 0x8d692801, 0x8bd03049, + 0x82a3cecf, 0xbe44d6c5, 0xceb2802e, 0x165d24db, 0x51c801b8, 0x6b84e02c, 0x13261123, 0x46a3ab66, 0xdc50a6f7, + 0x7c4e95cb, 0xc7a14e17, 0xa03965bd, 0x7fb68aec, 0x2f268d3e, 0xcd6f095b, 0x4ced2018, 0x7b7c3c76, 0x36e8a0c4, + 0xa53067cd, 0x9469b12f, 0x86ffd9c7, 0x909e84cf, 0x591fb34d, 0xcbec6274, 0x014513ba, 0x3b5ab3a3, 0x1e0ff7a6, + 0xf99c8df9, 0x41ea2e46, 0xa8124a99, 0x9a61e6c9, 0xd0b0f054, 0xf711d3c5, 0x6214952f, 0xc7bef68a, 0x627ad183, + 0xb624fcaf, 0x63db7bec, 0xc5c62329, 0x718a79a4, 0x4786d2d5, 0xd198f724, 0x92577935, 0xd9905b94, 0xb9ba3a88, + 0xa9acd4ee, 0x51ce62c6, 0x2c8c5296, 0x108c38ac, 0x26a82778, 0x27100ed6, 0xc5e83fd7, 0x2a86e960, 0x411cb773, + 0x5593844a, 0x82586d69, 0x63b05c37, 0x0fd2b681, 0x4de2d032, 0xd40b3d86, 0x1ce8e784, 0x93ed3415, 0x04bb6556, + 0xdf10fdcd, 0x7fbc8586, 0x1d9a55e2, 0xe48c898c, 0x89a26ac2, 0xd598f771, 0x89e57236, 0x472d887c, 0x01757ad2, + 0xe98aea11, 0xea51243d, 0x26ccb359, 0xd7ad5777, 0x856017b1, 0xdbdd8f54, 0x5fd25865, 0xff70f445, 0x5e678fc1, + 0x9143078d, 0xd1001d25, 0x5fb99d91, 0xebdb4a7e, 0x299eed15, 0xf804a8e1, 0x0060b0ce, 0xc8826df4, 0x64fdc4bd, + 0xa20a85a9, 0xabe218a0, 0xbaeb1d06, 0x97454c3a, 0xe73584b3, 0x2ed4d6d0, 0x075bbe2f, 0x2b066332, 0x5057711d, + 0x3ea562de, 0x12f19209, 0xddebb68d, 0x9d86f1c3, 0xe67b0ad3, 0x483837a4, 0x8e24bbc2, 0x821478a1, 0x4504b886, + 0x8581b62a, 0x2602bcd1, 0x22767bf5, 0x3f38761c, 0xd36c62ef, 0x59a75948, 0x5c8770ab, 0xd8c91bae, 0xd58cd2a2, + 0x1f516691, 0xcf073d87, 0xda7b5736, 0x815e48e4, 0xae93d68d, 0x06dda188, 0x31e9a44b, 0x5d2b4be9, 0x59fb358b, + 0xb7651551, 0x25516ad9, 0x5c6db49e, 0x6f313106, 0x2ee99099, 0xb77931d6, 0xac758546, 0x04a8349e, 0xd42ff0ca, + 0x5ac6ca2d, 0x6009589f, 0x4822185c, 0xa06f4d80, 0x4bfec3f2, 0xacd318bb, 0x4e192596, 0x6714b64f, 0xf9825e58, + 0xfe638a1c, 0x5330cd6d, 0x7ffabff3, 0x70e1a4b2, 0x611c1d6a, 0xb89a15fe, 0x5694fa37, 0x4a2ada65, 0x696bb9d0, + 0x1cd3f89b, 0xaeb299d4, 0x7c9a6264, 0xe34b24e8, 0xef82fd0a, 0x37d159b0, 0xbb7e06e7, 0x0331a8b3, 0x154efd07, + 0x11f499e1, 0xb2c94bb2, 0xf2651a86, 0x12263988, 0x628934c1, 0x5f2f7a3a, 0x9a188b7e, 0x18eef4b4, 0xf772ac27, + 0xcb3642ea, 0x85647a9c, 0x92d99844, 0x6243dab1, 0xdb2cc472, 0x5af6e61d, 0x0879293a, 0x289022b7, 0x775dfbd5, + 0x2c88d058, 0x303864d9, 0x31cd279e, 0x99109b7a, 0xe9dbbc82, 0xd9f20e02, 0x35a3f5c8, 0x89bcec41, 0xf9b8e1b5, + 0x7ba2247b, 0x6c36b6c0, 0xff4684a9, 0x20e180d1, 0x1a26f5af, 0x3f029167, 0xc6286578, 0xea671668, 0x7dace0b1, + 0x9fbac223, 0x07bbed79, 0xa5265f64, 0xc9484628, 0xece44e21, 0xdf2b347c, 0x5d82bffc, 0xfd955ff3, 0x4e7ef717, + 0x9d3fe9f9, 0x7f32f83c, 0xf00c221c, 0xb4fd09d2, 0x67a02906, 0x777164a8, 0x32d47c14, 0x63a69faf, 0xd284948d, + 0x0afc1749, 0xf938e7f7, 0xde2679f1, 0x168f8dfd, 0x4783b9d4, 0xf2e3b92f, 0x35006c0d, 0xef93e013, 0x82259e83, + 0x82f4ca07, 0x4e3a1329, 0x2a443a9f, 0xd9353c37, 0xb2379bf8, 0x77bf23d4, 0x566e873d, 0x1bba9d69, 0x39764f4a, + 0xccb87f8b, 0x14e2c0b6, 0x7d0f1de4, 0x0ef8d912, 0xbb53ab97, 0x47669e07, 0xea29ce01, 0x43a79faf, 0xaed6704c, + 0x64868c06, 0xbd82b7ad, 0x629a3f4e, 0x5afa0b51, 0x4ab84053, 0x1a7194be, 0x1b0a8b74, 0xa9d72c5a, 0x75a2e829, + 0x0f9c49b7, 0x44321f10, 0xd37cfe07, 0xc5033924, 0x1f05eea4, 0x171aee5f, 0x549d29e3, 0x4169e2f0, 0x50042885, + 0xbc246839, 0x38873ef7, 0x70e71270, 0x2c89bee7, 0x0b0717c6, 0xe4fce65c, 0x4f759dd4, 0x646cef04, 0x3b91f684, + 0x3a3cb522, 0x52ee1abf, 0xbcdd918c, 0x9b47ceb4, 0xdedf4465, 0x0581d548, 0x04f6a22a, 0x7e3ac534, 0x1ace5460, + 0x292e9b3c, 0x888a7ecc, 0x111bd10f, 0x99a6c0d0, 0x37cdb16c, 0x8b7a4425, 0x4bb67439, 0xc6ff1f52, 0xcdbb6907, + 0xfb2c5f71, 0x3b950fa1, 0x0c2d4968, 0xd22eaf28, 0xa64eea0e, 0xe8f970f3, 0x7fd2e257, 0xb715cde4, 0x7dd46897, + 0xf8289696, 0xbf8a043e, 0x4afa1921, 0x79282c60, 0x23f8c563, 0xac172d8e, 0x400bd37f, 0x9aac6ca3, 0xadff1bf1, + 0xe38bacf5, 0x87996d7a, 0x54a2cec0, 0x2726dcf4, 0x17c7c9d3, 0xe67e7b39, 0x33663023, 0x538177a8, 0xdd0a4e50, + 0x1236c4fd, 0xd2e3dc27, 0xf03115e3, 0x7e2023b1, 0x2f7776f3, 0x43eace5c, 0x4cb71de9, 0x3a578723, 0x96330541, + 0xd66d57a2, 0x79f5e600, 0x1b0bb439, 0x1fed0086, 0x48b9e355, 0xeb8e91f7, 0xabde5122, 0xac4ef5f8, 0xc4594b5b, + 0xae8b0108, 0x9a83c393, 0xc13dce78, 0x86e71171, 0x1ae2b8b9, 0xd99d9607, 0x4632f1c9, 0x43f4892f, 0x96dc92bc, + 0x9c0da8f2, 0xeb8b79f9, 0x4207a730, 0x5b41afb7, 0x52fac629, 0xa78fa6bc, 0x0b43422a, 0xdd67e117, 0xcd3887eb, + 0x40f6f403, 0xbf52d1f6, 0xcd3fde6e, 0x6e201eb3, 0x62038e71, 0x2e4a0950, 0x34794045, 0x66261bf5, 0x91428efc, + 0x8d7d1036, 0x2b72f182, 0xa66c5063, 0xdea7bca6, 0xc8035e3e, 0x06faa4a1, 0x26722e5a, 0x082c86c4, 0x2a20a5d1, + 0xcece0551, 0x843be80b, 0x6a17fac9, 0x2caaaf1a, 0xdd865166, 0xb33d96c9, 0x536f1d97, 0x4763c816, 0x165d9809, + 0x3ad92896, 0x018e14be, 0xe31a780c, 0xe206ea16, 0xb1d37e70, 0x125e4b64, 0xd825cc67, 0x0b065f7d, 0x4e6b7e9d, + 0x4c6a5492, 0xca0726b6, 0x49c15c6a, 0x51402531, 0x803e3a93, 0x786e0349, 0x090fdaef, 0xe5491043, 0x75afc300, + 0x71a6bc29, 0x65efd0e0, 0xa15d5345, 0xfb744e2e, 0xc13dab30, 0x23a06cac, 0x359fe5fa, 0xa9e0d9e8, 0xbc01ce45, + 0xdf7e16a9, 0x5340688c, 0xdd4fe1b6, 0x4ca4ee01, 0xe2dec18a, 0x41caa48d, 0xdd0032ba, 0x71014307, 0xe07bdeb1, + 0x291c3ba6, 0x12620de2, 0x3d5a6519, 0x2343bc8c, 0x7a8c0e28, 0xf2b6e2ff, 0x479e66ee, 0x9a0025b8, 0x77fafe4f, + 0x01a4eba7, 0xc6faa1db, 0xbd4f4ffd, 0xd937e0f9, 0xfdf68d03, 0x1061f0ea, 0x6c8be0ba, 0xeed88a46, 0xa8b9b97a, + 0x2760b9bb, 0x322b6aa0, 0x48052305, 0x7580cc1d, 0xfd19f871, 0xc52bbc84, 0x127ee0d6, 0x2144e28a, 0x9f448e8f, + 0x9b5343ea, 0xa70a7097, 0x5d38cf2f, 0x2d03e9ae, 0x0bb96210, 0xdef9d77e, 0x2b49e626, 0x4fbd0cdc, 0x7eb0a5c9, + 0x6d03d59d, 0xc25d0147, 0x4697a2c0, 0x7cdece15, 0x782ee508, 0xb939f2c5, 0x9e981855, 0x6aca0cad, 0x336cce92, + 0xf030ed89, 0x8cafa7c1, 0xf858c121, 0x2caf1b16, 0xe2dbb97d, 0x6031008a, 0xbb42b6eb, 0x59847b8e, 0xb7debb32, + 0x2c12f199, 0x9a4c7332, 0xfe985aea, 0xc037cbf8, 0x1e33b2d5, 0xc594a03f, 0x641f9d99, 0x7db1568b, 0xa5c947b2, + 0x23b12c1b, 0xbe44d91e, 0xc04a8000, 0x1659ca3f, 0xd8b46e15, 0x068c9405, 0x209dc7ee, 0x4ed8962a, 0x4f8dd62f, + 0x2ede1fc4, 0x244f61de, 0x83daffb3, 0x2b28d968, 0x38dd7b55, 0xd0e6cd0c, 0x1172da17, 0x41f64cbe, 0x3f500d0a, + 0xeaeebf8b, 0x4f80bcf6, 0x29d9172b, 0x2af6b598, 0xe3a18caf, 0x3dfd77e6, 0xa0d941a0, 0xa3fd9f0e, 0xd6dfd70c, + 0x5c3f81b3, 0x3d644f24, 0x60082d32, 0x5d4c0676, 0x3afffe89, 0xc80b5547, 0x9d943943, 0x424430a2, 0xb3a4e5c4, + 0xf5bb2144, 0x1084d92d, 0x7ea3e332, 0x38898888, 0x20cbca4d, 0x18981394, 0x1a26b427, 0x3c5e8685, 0x24715561, + 0x1a295c97, 0x1728a499, 0x1b6bfa0e, 0x1bca92d4, 0xa8fa7663, 0x717bec98, 0xc4853dbd, 0xd66347bd, 0x6463e22c, + 0x7a4285c3, 0xc1e2a6d8, 0x2a0bd15b, 0xee10dd49, 0x778cb87f, 0xeb947afc, 0x1e4b04b1, 0xd266e525, 0x8f135d6b, + 0x19dca368, 0x35abe51d, 0x5d573ee3, 0xfa87b390, 0xece24f0d, 0x3f4dfd79, 0x3a142d98, 0x3ce76539, 0x7987ae45, + 0x1a617d01, 0xf9eb0345, 0x80cd6931, 0xcfc2e446, 0x6f7d679e, 0xd74de4fc, 0xb660598f, 0x02301c57, 0x3dce6e80, + 0x65ddbd03, 0x87cfb833, 0x09e5b257, 0x4c501c23, 0x2b28ac94, 0x285b2e98, 0xc6e0c877, 0x76050f1c, 0xe0072456, + 0x3425366c, 0xc63cc4d6, 0x4d17229f, 0x1f0a4b09, 0x9c7d5a73, 0xf4824cc1, 0x54081524, 0x568fa70a, 0x96635ff8, + 0x334a7f1e, 0xab1e2a6f, 0x8670c1a9, 0x1192fb9c, 0x0ef31f27, 0x48c7c3b5, 0xa5d44259, 0x011ecaed, 0x570ed039, + 0x683d1c5d, 0x7ba418f5, 0x81c26577, 0x6df4b105, 0x242fad3d, 0xcf156af5, 0xfb93105f, 0xa98747d6, 0x9d0f32a6, + 0xbe5f648e, 0x2c9ab4d0, 0x104aa52e, 0x5ccd3fd2, 0x2f59ffed, 0x5611296a, 0x1d66712d, 0x03bac541, 0xaa365585, + 0xc47c8c84, 0xdda5852e, 0x927ed385, 0xadaacd30, 0x4bd93d89, 0x44542438, 0x26f49cf0, 0x217837d6, 0x7921ff3e, + 0xa3015037, 0xeeda0115, 0x2d21c8d0, 0x1a111c99, 0xf9ff1a25, 0xd5d404fd, 0x36e4bd8e, 0x075907a3, 0x540a2cd9, + 0xdd1fce2b, 0x8a88a2bf, 0xf8c1bf16, 0x189c5844, 0xf2020a2e, 0x04b5c0e3, 0x3e574918, 0x3d1dda73, 0xe518d1a1, + 0xc043786e, 0x323a26b2, 0xcec1b5d3, 0x65d87d34, 0x1e7d2702, 0x905dd1bd, 0xa8395ee5, 0x249a5ee7, 0x4fd5e4a2, + 0x0d89e747, 0x56d0b3bf, 0x1e52255c, 0x374a0d96, 0x20715cc4, 0xb7100457, 0x32523fbf, 0x4b4ee063, 0xab73fb91, + 0x24760e62, 0x340091a8, 0x272a129c, 0x03493240, 0xc9d1c52b, 0x40cfb5f9, 0x41bcd22f, 0x23454170, 0x6565c3e2, + 0x177de95c, 0x930d9d2a, 0xca789491, 0x5427787a, 0x7c483e30, 0xb4b4bc0c, 0xe539b3a1, 0x6fc8e8ec, 0xf027efd5, + 0x55975b0e, 0x7ebb63e5, 0xa56acbc4, 0x18278a25, 0xa6f6a9e5, 0xbe14dfdc, 0xd2065f4e, 0x3de7c689, 0x2bc9ced2, + 0x2e5b5983, 0xafbdc2cc, 0xb03596bf, 0x40916d4d, 0xc83a5411, 0xa8c2da53, 0xe6f73f3f, 0xea89ced3, 0xf55dba4a, + 0x1ee6bbb8, 0x0a9892a7, 0xd56006f2, 0xec138a8d, 0xd01d7ed0, 0x1e4ea83d, 0x8be0c1d9, 0xcfa0b005, 0xf532b9f0, + 0x80563984, 0xb3a59038, 0xb23e08cd, 0xa5a470be, 0x4bba6dca, 0x1dd6348f, 0x1c49403b, 0xa1853f27, 0xb7b99d57, + 0x81160a99, 0xe9ea5ec5, 0x08e38190, 0x8ef5f4f6, 0xa8295bee, 0x3011a30f, 0xdd3e6935, 0xb58906e2, 0xd78aa7e2, + 0x4f823fec, 0xb2ad6be8, 0x3873af4e, 0xe489245f, 0x4c7c95d7, 0x64e3e4ce, 0x8f812234, 0xe34e2e8b, 0xb8e0690c, + 0xf93594c2, 0x7c247776, 0x4663978c, 0xdca98fa6, 0xf4fbad3a, 0x3bf1d597, 0x8859952f, 0xf9b7f6ed, 0xb2a31f3a, + 0xb4b93325, 0x379f5037, 0xb905c1bd, 0x19c30685, 0x24e4a7bc, 0x6bf23fa1, 0x95c1100b, 0x519048b7, 0xace71e73, + 0x3a79dabe, 0x2e28741e, 0x81c69dea, 0x21d4fb3c, 0xa0e6f814, 0x24b96f4d, 0xb987ddb7, 0xe7ee4975, 0xc6581e75, + 0x1b9f5be5, 0x45d5c546, 0xb8249841, 0x30c5b565, 0x1cc86c3a, 0x5337600b, 0x83784964, 0x513d5024, 0xbe69f80a, + 0x79790f15, 0x5223ac8b, 0x9f14b51a, 0x6d0a302e, 0x3a403446, 0x5db50618, 0x261660c7, 0xe6f00b11, 0x3977e572, + 0x06d23287, 0xe87aa100, 0x7653d8a2, 0x8ad07029, 0xdc0f04ae, 0x3edec3be, 0x56048113, 0x6f234b20, 0x5e87f1e3, + 0xc782d926, 0x0c265d6a, 0x72d032b6, 0xdd15a724, 0x1c1d52f3, 0xe367698e, 0x4294ef0e, 0x4143e789, 0xe82ee7f3, + 0x212fc9e6, 0x1ad603c5, 0x0f20a3d1, 0x61e50210, 0x0fdc8bcf, 0x5932a583, 0xf1b56bf8, 0x5bb67d8b, 0x8ba45140, + 0x6ee508d9, 0x7fd68f47, 0x23a808c0, 0x4a168099, 0x58e53eea, 0x703eaf95, 0x3ef2658f, 0xade384a4, 0x6138e01c, + 0x4a15a496, 0xd29305a0, 0x9f21018c, 0x93cfb677, 0x662c1ec0, 0x7cd8b90d, 0xfd9af42f, 0xb2248ee2, 0x0e9d53d3, + 0xb0367499, 0xdee4eb92, 0x60e27ac0, 0x815cd91a, 0x8ae80ac4, 0x5ef42cd6, 0x60b28a74, 0x86a6a326, 0x271f96ac, + 0x185b53fb, 0xbb329cdc, 0x75bbb1f3, 0x7a70adae, 0xfca41b74, 0x7a9f7778, 0x3fcd20dc, 0x6bcb966d, 0xae0b1f48, + 0x9c11bb2e, 0x45a6aa0d, 0xb6bb0544, 0x50ea381d, 0xadd09811, 0x34f6f98f, 0x050828cb, 0x15ea3717, 0x424faca8, + 0x0a07673b, 0x449b2062, 0xd7ee65cd, 0x41d2381c, 0x0343e106, 0xeb9f6633, 0xb38be08a, 0x2af63bf3, 0xded57c0f, + 0x24951246, 0xadf66c46, 0xdd2b97d3, 0x0b31f6e3, 0x3fe85ce2, 0x02a157bd, 0x7125b2a6, 0xa8ed921b, 0x8fe635b7, + 0x5675e045, 0xb2484af8, 0x309db473, 0x2d593fe3, 0xfd18c533, 0x5ccbabab, 0x816d939b, 0x3a8d7d2a, 0x18a1046f, + 0xa70f7f07, 0x8ebfd848, 0xdb04cb5d, 0x18679d68, 0xa7c46dc3, 0xaa43d48a, 0x76f0ea38, 0x9f00b75f, 0x4d93ab58, + 0x97a11726, 0x7279dac2, 0xdf4d15da, 0x46713ffc, 0x772e838e, 0x6a741427, 0xea4d6225, 0xbc28a5f2, 0x020c9ed6, + 0x3340a141, 0x1b49858f, 0x0c1a5bbb, 0xc79c5877, 0xe9c40b9f, 0x7c8087ec, 0x50fa6e2a, 0xd71d3ba2, 0x3612d60e, + 0xb32edccb, 0xde625545, 0x9dd1884f, 0x32cdc3b5, 0xec61ac1f, 0xfebd821c, 0x7a172cb5, 0x6e7f9bcb, 0xf45be6f5, + 0x5db0286c, 0x775a8031, 0xfe341cec, 0xcfe4063e, 0x38beb50a, 0x8419ce45, 0x17123771, 0x8400db40, 0xc3efbead, + 0x8f5b9513, 0x95344c32, 0xc6dccf4d, 0xa921693f, 0x7050fef3, 0xc49e00e2, 0xc9f5c993, 0xb5ced0e8, 0xac6ba2e6, + 0xf267773d, 0x63c05f7e, 0xe0ee9f17, 0x2245f10c, 0x829b5bdf, 0x8bc83629, 0x1d3e6a58, 0x1494f0f8, 0xdbea3303, + 0xa0a6cf33, 0x4160089a, 0x74a2d125, 0x52bb0fb0, 0x4c870caa, 0x251d0e27, 0x77785b1f, 0xf170652d, 0x24354645, + 0xb35d8108, 0xc6634f94, 0x7682e399, 0xe2d57a0a, 0x98839a66, 0xa12f68be, 0x88e9a2b7, 0xd9f0f4d5, 0x4bcb26f4, + 0x094c9319, 0x97a12c3d, 0x948b809a, 0x17831f90, 0x7296b7b4, 0xf5e22d34, 0x8108ee08, 0x58283fa2, 0x3f85f63c, + 0x78848d7c, 0x62926dac, 0xa4d6bf26, 0x41de0d3d, 0x8ed651f9, 0x89cf3df5, 0x492f7e33, 0x2065bf13, 0x3dd3439f, + 0x8366c69d, 0xc03505e7, 0x07afc857, 0xcd19bf4c, 0xe95ffcbd, 0x5139567a, 0x52bef3c6, 0x5f9dd084, 0xb5768d78, + 0xf1f4149d, 0x666fc892, 0x932c27d7, 0xec5ff1bc, 0x50d6bac3, 0xbe1aed17, 0xa34e01b8, 0x4aaef768, 0xf3448a73, + 0x55c860bf, 0x106f33c7, 0x48da17d2, 0xd9df6c2f, 0x70b625b6, 0xf9959a38, 0xb47b0ebc, 0x25200988, 0x29d0c4da, + 0x819c572a, 0x2b5100fc, 0xcb44efbd, 0x38693bf2, 0xd4701a28, 0xa6cb31f6, 0x5e048628, 0xfb20df8b, 0x451f55e6, + 0xb1fa0194, 0x5c5632ec, 0xe164d3c0, 0xa91ce4b3, 0x4268adfb, 0x5dd8d8db, 0xf4bdc713, 0x08b68c32, 0x858a64c6, + 0x0f3a6c8a, 0xd31d93ec, 0x33a2ffb5, 0xdd5a453c, 0xfd5ea415, 0x1c7ec15b, 0xa3146722, 0x7b74e9c7, 0x9f3ca02d, + 0x1014cee2, 0x3050bf74, 0x051aa679, 0xa05b36fa, 0x4fca0622, 0x6d4f3eb8, 0xc6fa90e4, 0x06a9e646, 0x1d2378cf, + 0x4d9117a4, 0x684e320e, 0x21be1a49, 0x7c268ab3, 0x7901e6bf, 0x6158ec15, 0x32a261bc, 0xdb41b0fe, 0xb68ff7db, + 0x51420568, 0x51269cab, 0x45553971, 0x3cfc4ab5, 0xe0968f5a, 0xfda23f36, 0x478abac8, 0x4fe0b545, 0x470471f5, + 0x24b1ec26, 0x41a00925, 0xd85e79fe, 0x108eb2c5, 0x964de8ff, 0xcffe493d, 0x417eeabe, 0x8c48badf, 0x2203ad1a, + 0xbc9d7ebc, 0x469a811c, 0xfda71c4c, 0xeb617574, 0x778fa89d, 0x6404ca45, 0xea7eb4e2, 0x75011f37, 0x259f9823, + 0xa95eb2b5, 0x200166d7, 0x929b967b, 0x3dbc6c8b, 0x887e3bbc, 0x0e91ac6b, 0xc927b046, 0xc3a82d99, 0x14a19cc6, + 0x648cc1c3, 0x545c6e37, 0x8c89cbed, 0xec54264c, 0x6cbedefa, 0x6431e9ad, 0x9af873f3, 0x1afa08bf, 0x516852a7, + 0xa7baf26b, 0xc4d35289, 0x3650dc4e, 0x6c83c079, 0x46f19780, 0x2716adcd, 0x268bc16d, 0xd765b804, 0xc4c7d8d3, + 0x6fbbed76, 0xaead230c, 0x2fcd30ff, 0x920d1001, 0xcb199b70, 0x8279380a, 0x8f1e5676, 0x691aee5d, 0x023367a8, + 0x40ce04cf, 0x80b28330, 0xecec8f0e, 0x6ddca04f, 0x1b026ee9, 0x8633dded, 0x503fb2e2, 0x7bc3dea4, 0xc981b9f9, + 0xa38bab35, 0x7bb8521d, 0x6077d00a, 0x1e70f876, 0x445ec589, 0x14eab75b, 0x150140a3, 0x9360a30f, 0xbf687993, + 0x7bfbddbd, 0x634eb082, 0x5ab9a810, 0x98e6eb0e, 0x2df7b610, 0xf434274a, 0x7e1daaac, 0x58fde125, 0x381f1a3b, + 0xddaf7c09, 0x7d1b2c52, 0x929c5f34, 0xc69398aa, 0xb53fb5a1, 0x918b135c, 0xaf8f7f25, 0xef3476ce, 0xafb1afaf, + 0xe5596068, 0x200697de, 0x33be5fc7, 0xa145571b, 0x2c6d26ed, 0x535de201, 0x9e813ece, 0x9128fffc, 0x77d1ad44, + 0x9befde34, 0xea4b41dd, 0xba7a4913, 0x21e95de8, 0x1e96f7ec, 0x9eec5aa6, 0xe07ae5c8, 0x658d87e2, 0x3d4660de, + 0x6265ab64, 0x9ff7f78f, 0x4820939a, 0x08fc266d, 0x462eec75, 0x08fc11f2, 0x7af25830, 0x6ac78ee5, 0xc041f5ae, + 0x69c84975, 0xc51efc7c, 0xc8281c6f, 0x26ade9c0, 0xa6242968, 0x5f10dc76, 0x1db88c5d, 0xff7d9f17, 0x65bbfbca, + 0xd2805666, 0x432e4d9b, 0x8381d503, 0xa76ddbef, 0xdb1964ee, 0x4c029133, 0xd695f2fe, 0xae161af9, 0xc50e05cc, + 0x75c8ed93, 0xe3437ad5, 0x08ae7237, 0xf9675c60, 0x8fe0e99f, 0xcadf4be7, 0x3ebf7612, 0x3550d3db, 0xc7c83ef8, + 0x7c1e1759, 0x00dbc66b, 0x5cbac9d2, 0x3597b922, 0x1e1e3355, 0x10d99744, 0x3f9ea0f7, 0x4ab57ad5, 0xa881ac18, + 0x10e0d659, 0x24ae9767, 0x1c38f619, 0x39aa2d20, 0xf4fd7219, 0x7155a3ff, 0xce8d6dee, 0x4f475409, 0x16f7efc6, + 0x0185c15f, 0x935ecca0, 0x4cf071ef, 0xf3af7b49, 0x70c86b7e, 0x41775d25, 0x5a37ca16, 0x008daef3, 0x5100a039, + 0x2fd53c38, 0x78eaf679, 0x8351fd1e, 0xd7bfe854, 0xac9207b9, 0x87b05ff2, 0xc6f31901, 0xa50f7afc, 0xffde3ca6, + 0xde079fe7, 0xaee223e5, 0x6e23524f, 0x84951bd9, 0x8c64c52c, 0x66774c4a, 0x4925b493, 0xe4b81421, 0x6b0e1383, + 0x3a81a959, 0x284861cc, 0xf4fa345a, 0x5d4d1245, 0xffc68fcb, 0x4e6facdc, 0x188ac395, 0x19b13157, 0xd876951e, + 0xdd995ca1, 0x76549427, 0x2b0b5610, 0x2c1ca852, 0x919a1742, 0x77df8800, 0x7286f2ea, 0x1f4c4b2e, 0xfc014ac7, + 0x2221d628, 0x4200b9d1, 0xa699d550, 0xdecc521e, 0x920481d9, 0xdade7765, 0x75864446, 0x3e6d147a, 0xfe124883, + 0x147d8f51, 0x8de7a9d5, 0x1efccd37, 0x30e0c188, 0x9fd328b7, 0x7e6f8ca4, 0x6ce9253e, 0xe3e20b27, 0x4737676c, + 0x9ea8c3bb, 0x66ac3dcc, 0xc12f6e8e, 0xdb83bd19, 0x77002024, 0x1383a74d, 0x833a1e0b, 0x9f747ade, 0x5d842867, + 0x8a651fe6, 0x660bf5b4, 0x6126caa4, 0xd288949c, 0x0a375ccc, 0xecefdc8c, 0xb86eafbf, 0x72a24aa5, 0x3e0cbdbc, + 0x203f0ff8, 0x6d34682f, 0xfb360c80, 0xad7de30e, 0xbd6469c7, 0xc99281c3, 0x83749f4e, 0x6dd204ed, 0x22df29fe, + 0x3a760d8f, 0xc1d29859, 0xc6f41bcf, 0x426e8dd5, 0x0a78dd67, 0x5697b4cc, 0x54464f5c, 0x4b794a08, 0x629cd208, + 0xba6e9f7e, 0xe45f8d89, 0xaa9990e8, 0x65362efe, 0xb4b0d1a4, 0x4e94c74b, 0xbe4d4b69, 0x80329293, 0x669848a7, + 0xd48f3bae, 0xa2e33679, 0xeeb4e514, 0x1370c897, 0xd5c02f6e, 0xefcb0f04, 0xec9bb166, 0x3f7387fd, 0x0cb5e0d0, + 0xa4e48913, 0x7d21a83c, 0x479b2298, 0xe21c68e1, 0xc4754c09, 0xc712fe03, 0xa06792bc, 0x91b0647c, 0x2917b0b1, + 0xba84f212, 0xfdd43daf, 0x05978ba0, 0x1ba0a877, 0x59295846, 0xf5eb7c20, 0x27f89e64, 0x9b704292, 0x7fe3bc7a, + 0xd64ec3bb, 0x591e3eb7, 0xba4bf60f, 0xa0b4812f, 0xeacdbe70, 0x35eced66, 0xb786faf5, 0x116de8e7, 0x5ffc5824, + 0xdb2b200a, 0xc73fc05c, 0xd6bcaaae, 0x0b4bbf04, 0x788a06ff, 0x63e7a530, 0x6cd36863, 0xd99977df, 0x4a99afd8, + 0x41f3190b, 0x083e4441, 0x4ba88689, 0xfa0ef62d, 0xd9bccb42, 0xfc0797f7, 0xb3dc581d, 0x4cb1892b, 0x2f7e1498, + 0xcd9215ff, 0x79ae278f, 0x59838b3d, 0x7b1737e0, 0x54244f7f, 0xb72a52bc, 0x2372985a, 0x12241d53, 0x6adc8539, + 0x9711abd0, 0xd8b24f36, 0x01980a3a, 0xd8b59f84, 0x75086d69, 0x62b3966c, 0xd01343a6, 0x6eca5c0d, 0x549577f5, + 0xbe111715, 0xd701d42a, 0x05a1bdb0, 0xf278ef4c, 0xae31e504, 0x6ed7bdee, 0xbf4c349f, 0xa74eb3ea, 0xb71274f9, + 0x91a56ca9, 0xbec35738, 0x9739f40b, 0xc005cbfa, 0x82cd5983, 0xee0cf47f, 0x4469cf1d, 0xd2aef6dd, 0xbcd7b016, + 0x986e82fe, 0xfd978861, 0x10c210d2, 0xfcbef2c6, 0x64f9f6ed, 0x15328bf5, 0xd9e50897, 0x457abbdf, 0xc85b4203, + 0x159cdf7d, 0x6fe38deb, 0xbba6e24c, 0x08771461, 0xbefdd29e, 0x5ca06667, 0xcefecb37, 0xc90661ad, 0x5e14f4dc, + 0x74f49c9f, 0xda7c7d89, 0xc54fb68b, 0x043b3db6, 0x4c577d46, 0x5785334c, 0x52fc2178, 0x9a0c4c9d, 0x22a6fb86, + 0x6762809a, 0x916c206c, 0x0be02f2c, 0x0dd94a9f, 0x66ecef06, 0x59a72d52, 0x4d3ddceb, 0x24c99b74, 0xec1bd3ed, + 0x280e6a89, 0x3fde1fe8, 0xc841196e, 0xdcb4ae66, 0x20e61c69, 0x226a87cf, 0x4ab88f39, 0xcdb51598, 0x1007a046, + 0x500958da, 0x46dd3be3, 0x7e9e433a, 0x973e279c, 0x35d9cf50, 0xeb26cffe, 0xc471c52c, 0x039ce931, 0xe0f97b52, + 0x4360a983, 0xf5ce202b, 0x21200db2, 0x32aade18, 0x53afc633, 0x2469d2f5, 0x89d24d88, 0x3bbb8c80, 0xa791e6b9, + 0xbec46474, 0x70f70413, 0x6ffd6368, 0x3c16cf1c, 0x41d2c391, 0x470bbd7a, 0x5f32bbcb, 0xd56672f5, 0x0199fcb1, + 0x21d9bf1a, 0xd03cf321, 0x1369cff2, 0x0ef098db, 0x00eedf16, 0x2e133a49, 0xd7b7de5f, 0xe2eb3b2c, 0xf4519b3a, + 0x0c62b78c, 0x9464783e, 0xdf71e28e, 0xd6bb3b8c, 0xb36cf127, 0xdf5ab111, 0xd0ef39ea, 0xa5721896, 0x3a8b8e81, + 0xa77fc3c0, 0x3eaa5f4e, 0xbf5566ce, 0x95b6d489, 0x24246e76, 0x3bc2d37a, 0xbcdf8d25, 0x3ebe7a59, 0x7f610c91, + 0x7736bcdd, 0x75bc2424, 0x85c70d05, 0xbeb7ba24, 0x4423de3b, 0x228f9f73, 0x7c01c1bf, 0x9f0d29a4, 0x61a80872, + 0x3ec5601f, 0x27ba04c4, 0xd7a5024e, 0x71452235, 0xfb211dc9, 0x61aa93d6, 0xbf25696f, 0x22b2f2a2, 0x969488a2, + 0x82dff5ba, 0xcfe623fd, 0x88329b88, 0x4cccb4ba, 0xb76482cc, 0xe5023477, 0xa46a3894, 0xbe7c5404, 0xd1fd3901, + 0xe6bbe2ce, 0x0c4f1b4f, 0xacc9b278, 0x3db561f4, 0x332dc3b6, 0xf38df13c, 0xeae891c4, 0x8f00c6d3, 0x778f1d35, + 0x99846b91, 0x5f3096ff, 0x4a87ec24, 0x7c7c7bfa, 0x47ee71c1, 0xb372259f, 0x572c7bbb, 0x9fac8e01, 0xbc3e5e7b, + 0x0a98ad4a, 0x8724098b, 0xb65b4238, 0x08816daf, 0x0ba64183, 0x50cc14e1, 0x42895df2, 0x8858e739, 0xcbe17ba9, + 0x1b74d24f, 0x4402d400, 0x5cc6ed20, 0x279a68ce, 0x7127622f, 0xb430e865, 0xe15ef496, 0x0ebe1de7, 0xd28793ef, + 0x1e95ce31, 0x753f0cb8, 0x9bdb6bfd, 0x5ecc4ba1, 0xf4421461, 0xadf6bdfd, 0xc01bd28e, 0x4419125c, 0x2d7d94e3, + 0x5073c54a, 0x96aeece3, 0x840a2b99, 0xb24aa255, 0x38345e2f, 0xf34125d6, 0xc761e37c, 0xb5ef96ce, 0x11d2d1fa, + 0xad59d51b, 0x360870ab, 0xbfcdf45d, 0x480e2047, 0x0dfda9b9, 0xdae944f9, 0x6f03ee85, 0x3b6f8dec, 0xed9fd4ce, + 0x2cfd70f7, 0xcb88d469, 0x5935984e, 0xa8d78801, 0x341df785, 0x020e6c47, 0x65f12cef, 0xdec04f23, 0x03e3fe4e, + 0xdd3008ff, 0xada46c49, 0x85e22f56, 0x278bb9f1, 0xfdcaa6b5, 0xaf47c5c9, 0x01381941, 0x3f60c1f6, 0x67f8da0e, + 0xa5939439, 0x4c0f815f, 0x2a17adbe, 0xed844395, 0xf2574d5b, 0x55e0b113, 0xdc8a1aef, 0x7ec73cd1, 0xb4d868e0, + 0x56f54288, 0x636cab2a, 0x5b33eb1b, 0x1a4f3fda, 0x613a2cb4, 0x5fac0fc4, 0x082f9f9a, 0xddea4a23, 0xc1484a94, + 0xa75a8bf9, 0x5575b1b5, 0x895bf61b, 0x7e3d5b23, 0x0c504c94, 0x8f7002be, 0xbb91b010, 0xe0c0e536, 0xdb74aee7, + 0xb1364dd8, 0x2d7610bc, 0xf0b00272, 0xa69f0300, 0x66e18979, 0x3268085a, 0x4efa9e50, 0xd084d664, 0x360f51fb, + 0x6b7a7c30, 0x2784ab4e, 0x3783c57e, 0xccf4e91d, 0x53b8639e, 0x194c94c8, 0xfe9f1f85, 0x2c3fd121, 0x5f61d770, + 0x5eae06a4, 0x58696c5a, 0xfc6871d1, 0x190701f4, 0x6ea70120, 0x1aabebf6, 0x634f5197, 0xee0233f9, 0xa86fec8c, + 0xf8b401e5, 0x3d41f088, 0xd040ff28, 0x35e174dd, 0x5e62e392, 0x7298867f, 0x4a0141f9, 0x16af8a83, 0xe79ade31, + 0x600f270d, 0xfba0bc80, 0x963ef16f, 0x1d356ea0, 0xfecd8e0f, 0xbe48905f, 0x4e444b91, 0xb00ddb84, 0x50dc11cc, + 0x66dbbdc1, 0x9b70316c, 0xaa65c3cd, 0xe4c95a37, 0x16807f45, 0x1c780fdb, 0xe48d9478, 0x551787d5, 0x5a9f9918, + 0x73d898a7, 0xdfadd8fd, 0x1929933e, 0x68ba46fe, 0x20216b46, 0x8ed90a4c, 0x468398db, 0x3d7c8352, 0x1791921e, + 0xbb5f1e08, 0x7e566151, 0x1c65b9ce, 0xd9a2f352, 0x81d68bd6, 0x80c980f5, 0xc9fd0a8f, 0x536fc6a3, 0x9e9d42bf, + 0x82fa063e, 0xcb52fabb, 0x07be95ad, 0x4677fb89, 0x3e6ce045, 0xa3b66e20, 0xc5061497, 0xffd971db, 0x5f535bc4, + 0x8c327bdf, 0xb1bc1ead, 0xea9cbf9d, 0xcdab1f9a, 0x76b2d7f2, 0xc3c2c476, 0xbffc7ea3, 0x0f2a9fdc, 0x33a14617, + 0x3fd9bb97, 0x07a1f3d9, 0xec3fabfb, 0xa9ff2d22, 0xf777121f, 0xa64456f4, 0xf7d1bd52, 0x411f3c98, 0x0f55fb48, + 0x053eacbb, 0x700c0ed5, 0x83b963ba, 0x97cd7698, 0x6f220158, 0xca43ce0d, 0x6b29fdf8, 0x60f1b4c6, 0xd547b235, + 0x0358ad8d, 0x7ebe869c, 0x5af8778e, 0xe2fbc986, 0xbd1c082f, 0xcd059775, 0x3cabcfda, 0xe2376984, 0x4747e9a9, + 0xd2373caf, 0xf6a5860b, 0xdfa4021d, 0x69ad5b16, 0x2284c521, 0x59d71496, 0x5f9c7000, 0x0c3b6c91, 0xbb9b4879, + 0x97582d54, 0xe0724668, 0xe2aeaa4c, 0x331f51b8, 0x6e2ca429, 0xc016e51e, 0x1c42d62f, 0x8b48d470, 0x271ae05f, + 0x5d90e07d, 0xf8785c52, 0x19a9c1e3, 0x02c97c1f, 0xb78faa43, 0xfbaeb138, 0x10586a10, 0x7dd1bd14, 0x91638d23, + 0xce1b1a7f, 0x30090d9c, 0xfff154b9, 0xdbd388e6, 0xa7ed52f9, 0x7bd0a9f0, 0x413dc608, 0x23475b4c, 0x3c79bb08, + 0x541906c3, 0xc25bfe53, 0x8cb22920, 0x396c9527, 0xc6e96e6d, 0xb1d78e9b, 0x978fb498, 0x36cd5f22, 0xac668ac5, + 0x54dafbfd, 0x593de62e, 0x2e42e635, 0xa881013f, 0xc094af28, 0x0efb8375, 0x11dab52e, 0x2540ed9b, 0xa68eded8, + 0x7abc5440, 0xde98a988, 0x9002bb36, 0xd84f6337, 0x75555601, 0x34586498, 0xd4dc0ef8, 0x7dd5914f, 0x8d99d5ed, + 0x4610e1a5, 0x270a8dec, 0x20dcbc37, 0x573da163, 0xc3de4fdd, 0xfed241c7, 0x5f702fdd, 0x69ef7655, 0x13a1d8ef, + 0xd3b95e3c, 0x1a5980fe, 0xb5319513, 0x9db66136, 0x5087d029, 0xfc5ee0b9, 0x3885f5f5, 0x434657f5, 0x3a93e272, + 0xd9352c83, 0x210a7dac, 0xc94a6161, 0xbecaaf13, 0xa203a2cb, 0xe4b7956e, 0x33a795ae, 0x3013f92d, 0x7017b2a2, + 0xe9648991, 0xf666727d, 0x87254196, 0x425e6c0d, 0xdd6921f2, 0xbaab70e6, 0x1950b964, 0x12cc95f3, 0x8588ea02, + 0x9c309889, 0x226d5346, 0x08c0422d, 0x4aaff038, 0x318e1ed1, 0xb1250842, 0x2eb6550d, 0x01379a63, 0x909f9b09, + 0xd10d356f, 0xb20eac9f, 0xec240a8e, 0x560d1f78, 0xced6a2b4, 0x369d5a33, 0x0058f68c, 0x1b5bc0be, 0x02cab57f, + 0x504c0ccd, 0xb2a29dc8, 0xfb3e6b00, 0xbc02104d, 0x0140d7ac, 0xec3e5467, 0xb7dd91dc, 0xed1e2532, 0x5b1bb10a, + 0x69319c3f, 0xa13ddb3a, 0x1feb5ce8, 0x566968fe, 0x990986b9, 0x98984793, 0x7c22e8b5, 0xfed391a0, 0x55f11cb2, + 0xe63ed993, 0xcf3460b8, 0xd8c084a5, 0xdb012b09, 0x0f4bd488, 0x97d1dd80, 0xdb83bb21, 0x8a4db82a, 0x2f2934c5, + 0xca796b00, 0x1154649f, 0x9d6ef15c, 0x130e2934, 0x8b21e9fd, 0x39ace953, 0x902b07ab, 0x4c1c153b, 0xe63eafe8, + 0xfa7f9d56, 0x6eca6dfc, 0x6b904383, 0x064993b6, 0x01b333b9, 0x5c229bb2, 0xd9438eb6, 0xebbb298a, 0x83f5346f, + 0x2ca83009, 0xcd6d1575, 0x1d869607, 0xc5844af1, 0xfb1d13bc, 0x0a923b7d, 0x543d836d, 0xce7b47c3, 0x09325077, + 0xddc69fc5, 0xa84fac2e, 0xf1a34dad, 0x037b9aa5, 0x1abb9cb8, 0x9373b949, 0xb990b1c8, 0xa578cf79, 0xe4dcc060, + 0x66c03367, 0xd9be1315, 0x4d555340, 0x11929d56, 0xaef2901c, 0xc57fdc57, 0xb93b1dda, 0x803acd41, 0x0a9d1d5c, + 0xace3a189, 0xb301b223, 0x1bcdef5c, 0xb1e320cc, 0x23f223e8, 0xfd7492d0, 0x8d2de4f2, 0xc9c5a5d7, 0x649a3287, + 0xf215a122, 0xe08f3ffe, 0x65653b50, 0x941fd735, 0xb3d79d1f, 0x7070d2b9, 0x70ce8d7b, 0x67889ef8, 0x9bdc7d28, + 0xcaf4f4f6, 0x05fef23c, 0x48b7dc57, 0x8bd7fa12, 0xa52c4ef4, 0x89a79b8a, 0x3ba605e2, 0xc819c385, 0x9e9f9104, + 0x8d5bcbf2, 0xe4fdf73b, 0x0643276f, 0x790eacaa, 0x13a90024, 0x3f1f28f3, 0xd8bd6ef8, 0xd8f910d2, 0x00c6be15, + 0xe06016f5, 0xaa221402, 0xa029ff77, 0x7817ba1a, 0xf9ed2c16, 0xe0971174, 0x3e7e3b5c, 0x60cdf284, 0xef759e55, + 0x4020458b, 0x182d9540, 0x85a32cab, 0x7be4e579, 0x1ea122b0, 0xd350c4b4, 0x8d44340b, 0xed086e64, 0xd411bff3, + 0xc08503e4, 0x032a0396, 0xd221159c, 0x6f7d68ed, 0x895a623a, 0x0909a5bb, 0xbee06f06, 0xb690e2fc, 0xdbd5cebc, + 0x265deef0, 0x6f2bf00f, 0xacef4f16, 0x09f65401, 0x1aadd1d7, 0x53ae0c18, 0xde0b4424, 0x936b315e, 0x712cb052, + 0xef49abac, 0xa3f4b791, 0xadbf41e5, 0xfaa53a83, 0x15f0595d, 0xd9e2cbb5, 0x6db0d781, 0x08a045f5, 0x34d4343f, + 0xe01bb483, 0x4a069213, 0xf5fbc43e, 0x23769f5e, 0xb305d49f, 0x4afef682, 0x3e557f40, 0xc8f8b987, 0xbe8d4db9, + 0x39704de6, 0x08cacb6d, 0x97c3c23a, 0xfab89da9, 0xe5dffd65, 0x5d11ab26, 0x5985d8b0, 0x8b6f15cd, 0x3731a369, + 0x9e616045, 0xbb07df01, 0x7d63bf86, 0xe457c930, 0x8f322cf0, 0xad0245b8, 0x5ff2b4dd, 0xc61bbdfd, 0x6242de03, + 0xe5b42446, 0xe03362fa, 0x7847fb04, 0x5afb1e6d, 0x0a072803, 0x0d48fc22, 0xa63c500f, 0x6fb7c6c8, 0x539ac025, + 0x55bdd19f, 0xb9b74278, 0x2e29de06, 0x9e71e2c2, 0x3619ca29, 0x8590bc96, 0xa7de08fe, 0x2b6f54cb, 0x34504373, + 0xe5ac41d7, 0x764b6ea5, 0x0418a0dd, 0x886cfe9a, 0xad5e90c5, 0xa87ae68a, 0xfaea2295, 0x70bda1ae, 0x24b9d102, + 0xa05d8bfc, 0x67c23eca, 0x1f9aee2e, 0xb6360e7f, 0x2676e750, 0x62fc7ced, 0xed7e3ed7, 0x61b5e969, 0xa6643ef2, + 0x13f78cec, 0x55d5c9e3, 0x7d0e1837, 0xd73509ce, 0x9ef54531, 0x53c616e0, 0x8debd429, 0x2de3ea22, 0xc498e68e, + 0x7287080e, 0x9aeac5da, 0x6edd1a1e, 0x1d6ec11b, 0x6314a901, 0xaaa84229, 0xb134b896, 0xc9d9f8d9, 0x8ff53af4, + 0xc8bc481b, 0x13ec8911, 0x4236d4eb, 0x975e841d, 0x531f9933, 0xad8706a6, 0x219544fb, 0x1c8dee20, 0x933c2bab, + 0x181b672e, 0xf9720f21, 0xbbe02e5b, 0xf28d5c07, 0x75c60f36, 0x756f764b, 0xb3c19956, 0xa48053d2, 0x14c8d0a9, + 0x3f541528, 0xe08a771e, 0xaa208bd3, 0x48aafb11, 0xb5a34887, 0xed4968af, 0xaf4a2979, 0x6d12f3d2, 0x7bf15781, + 0x3d861eb2, 0xc8d093b5, 0xd4af20f4, 0x8f8bec35, 0x61b78976, 0x6bd7c5e8, 0x1ecf4478, 0x89f76893, 0xdd7fc4f6, + 0x9575c902, 0x353cbd32, 0x122f2f2c, 0x12799078, 0xe115b5b6, 0x300ba238, 0x9641654f, 0x269c8c41, 0x1ba8dfaf, + 0xb58b6115, 0xccf81b09, 0xc484018e, 0x53e7f876, 0x33cb516d, 0xa598cd85, 0x96ff6cef, 0x6a01be51, 0x7e6da28e, + 0xec588f84, 0x50a23131, 0x4705dbea, 0xe4130e37, 0x844f43c1, 0x94a5d756, 0xb28a947b, 0x46b9b710, 0x812b8c04, + 0x08665e95, 0x0bbe6687, 0x3f5db4a7, 0x0d9d6564, 0xb2cd24fe, 0x435c572e, 0x738a8784, 0x734885a8, 0x7ea18bd1, + 0x76536b62, 0xf0b48e79, 0x60e8a486, 0x3a97dac8, 0xc8115663, 0x549d5228, 0x93664af2, 0x4170d3a6, 0x51cc64a3, + 0x47e50f43, 0xfd089994, 0xa7bf3669, 0x27c86218, 0xa2247c34, 0xcb0d4c98, 0xb942ea24, 0x7dafaf03, 0x39c8b291, + 0xa4dae21e, 0xeaff9c6c, 0x9fbe9c1e, 0x5beed636, 0x458721c7, 0x7897d79a, 0x8997ede2, 0x23408af9, 0xa16a6a89, + 0xf0d8d1fc, 0x88e265c8, 0xac9199f1, 0x51a39e4b, 0xe4445e46, 0xec2efde1, 0xd7d72398, 0xed2268b9, 0xbf073032, + 0xb7a5df43, 0x2bfcd0cb, 0x9b0125be, 0x71f9f9c9, 0xcc8182f9, 0xc8df86f3, 0x602761aa, 0x90657a06, 0x6ebd28ae, + 0xafaf29c9, 0xe34694ba, 0x61b2e8c5, 0xce4e7924, 0x657e0afd, 0x763e45fc, 0xc919161d, 0x7901c017, 0x9c411a6e, + 0x4f992658, 0x8dbac46a, 0x6aeec55e, 0x890995f8, 0x6dbf896e, 0xef063d70, 0x6e43a93e, 0x463ccd4b, 0x930b8bf5, + 0xbd0c9edb, 0x1a4f00f2, 0xdad07157, 0x4a53d6f2, 0x4507bdeb, 0x1d66ae55, 0x65cd467d, 0x4457ea6c, 0x7b63a40d, + 0xcc988b9a, 0xc92f1255, 0xb3620de4, 0x20af699c, 0x2d57af04, 0xb8cebe99, 0xca3386c4, 0xcb7064af, 0x250f7d6d, + 0x89daab04, 0x1fd4df63, 0x03cc955a, 0xe7b65b0b, 0x9f308231, 0xfdee35d5, 0x67952ae1, 0xef57ba35, 0x26debae3, + 0x278a27c4, 0xaedad107, 0x029afec4, 0x06be2547, 0x03ccdd16, 0x4ae9edf4, 0x164dc66d, 0x72808858, 0x8266b490, + 0x6371d8da, 0xbbba9710, 0x3a2f8a5e, 0xb7226451, 0xec0e3241, 0x0c013c22, 0xb7635ba2, 0xdb206d85, 0x939de79f, + 0x7b6dd4c8, 0xda7ff402, 0x1a13e32d, 0x304084dc, 0x23b85ad0, 0x2c06c157, 0x1687aca6, 0x865b43ed, 0x7861b813, + 0xb846e388, 0x4ad13c16, 0xb35e3b7e, 0x932870f0, 0xcf4d8779, 0x9bbec694, 0x9544d55b, 0x32d4cfff, 0x151ead2b, + 0x81f3ddf6, 0x4b2f74df, 0xcced2f0a, 0x3ae10a3f, 0x24172442, 0x64b7d114, 0x3ec4d54e, 0xc5e4755f, 0x439b8713, + 0xeb061e09, 0x7a125e49, 0x5df86019, 0x8ff08119, 0x8ebed408, 0x14ff71aa, 0x5424b7b5, 0xa7b754a5, 0x7036b5bd, + 0x75762122, 0x7f42117e, 0x2615c731, 0x4312c4bb, 0xdecee840, 0xedb3e8c9, 0xc3002ec4, 0xac55da69, 0xbd0cf99e, + 0x3e6601cb, 0x47a1a5a2, 0x3576086c, 0x8c625563, 0x06f203b1, 0x314c44c5, 0x9376844d, 0xa30e3fc8, 0xb7607bb6, + 0x2770d2f0, 0x2ed305f8, 0x9c508944, 0x2d28428b, 0xf5791986, 0x0bea0854, 0xe87682a7, 0x8dcdd57b, 0x3c5f7f62, + 0xe2c34ed9, 0x88b943bd, 0x3c526f89, 0xe0a81f06, 0xee7ea8e1, 0x92cfbd53, 0x95106aa8, 0x8d90cd5b, 0x1ba728f1, + 0x9bc67c35, 0x2899f904, 0xa6c6e5e1, 0x226bc9c3, 0x65abe7b1, 0xdce035f6, 0xd2b61238, 0x02e6e2cf, 0x54c12fec, + 0xc161dbf5, 0x859f2828, 0x8c5b9e79, 0xa5df359d, 0xef3f1b55, 0xf8d268d0, 0x7d95c48a, 0xb830f34a, 0xccac243b, + 0x077e7db4, 0x7337f267, 0xffad979b, 0xcf02dbb1, 0x47df9fcd, 0x7463edc0, 0x1709b4a4, 0x133ae09e, 0x18814e26, + 0xda936a79, 0x1c8ebcf2, 0x62817a87, 0xcddbaab2, 0x9bda2a82, 0xbfb6cd6e, 0x9fa115e6, 0x962464f9, 0xeab20517, + 0x9afbcac0, 0x9a3a3d63, 0xfc4353c6, 0x146c20e4, 0x8c077d7d, 0xda9010c3, 0xd0c019d5, 0x90389132, 0xd302a79c, + 0x9cd86849, 0x7c1dcb97, 0xa3c7f285, 0xc08b956d, 0x071dae19, 0x98c219da, 0x8f390315, 0xb646c1fc, 0x868b6c62, + 0x55ac5af1, 0x7cf83310, 0xd20483db, 0x96d87f7b, 0x1fce67a7, 0x1c1a1047, 0xd88e0c66, 0xbd1c41a0, 0x52f19184, + 0xcc52d74c, 0xbaaad1b7, 0x3b6a80b9, 0x8d9e2df3, 0x430b51d0, 0xcc687781, 0xc5ca82e5, 0xa42c7fc6, 0xc2f54339, + 0x28290fc9, 0x8d336d6e, 0xb6d9870c, 0xe855c5e3, 0xb9833e86, 0xf2b92f79, 0xf6471c7a, 0x33d180c4, 0x0905c92e, + 0xb2717f66, 0x3ef96242, 0xe260069e, 0xc8dcaca2, 0x8d93c38a, 0x065984d1, 0x8d4b8cd2, 0x71796a14, 0xa0a27951, + 0xb75c9090, 0xdf711621, 0xe35f81fa, 0xd2b3e4fa, 0x3a0c98e3, 0x0137e6ee, 0x62b63d61, 0xc45ac451, 0x3e477607, + 0xf1aedf18, 0x71141b4b, 0x9a3423c2, 0x0d12214b, 0xf20b8ea7, 0x5c3acde1, 0x912d82b8, 0xcf25a406, 0xfed72e8f, + 0xdf34f620, 0x3bb37f5e, 0xc0d4c85f, 0x22da59d9, 0xed835c03, 0x2215e8ba, 0x4269e829, 0x734232b0, 0xd812550d, + 0xe5fdef06, 0x3adc21a2, 0x03061a83, 0xe0d6b05f, 0x6a50fa60, 0x44aebdca, 0x6a90c92e, 0xea62fbef, 0xa5a19b7e, + 0x53b661d2, 0x2b72b7d5, 0x33217196, 0x76836928, 0x7be63aa0, 0x0f32c773, 0xc868ba8c, 0x02f3820d, 0x8e597e57, + 0x3176f661, 0x9cf5da78, 0xacc37217, 0x1ee68b5c, 0xab67e331, 0xcaa6630b, 0xf0370aac, 0xe91fc5cb, 0x310772de, + 0x631a911c, 0xa8edcaf1, 0xbdfdca5b, 0xe1b183d0, 0x522cdb46, 0xba6f3bca, 0x43d88a3a, 0xae8c81ad, 0x9e747a46, + 0x8d7a6c19, 0x90b234be, 0x62d34c63, 0x46c5166a, 0x39e2f1f8, 0xef97420c, 0xa6ebb2dd, 0x9288a17c, 0xb72f690f, + 0x4e841141, 0xc1445f84, 0x4b9a5daf, 0x2fd649cc, 0x66cf10ec, 0x995d5f95, 0x8c432bca, 0xcb0f1e0f, 0x99f04a1b, + 0x5cf2a0d0, 0x6993d144, 0x661f1e8f, 0x00e76b6a, 0x5dc38c0f, 0x7a17eb6d, 0x1998abeb, 0xd390a265, 0x101fe557, + 0xc371a6f9, 0x1e709856, 0xffabf7fe, 0xa3a9973f, 0x9c2ff899, 0xd8fcbc58, 0x79f04a2c, 0x2d54529f, 0xd5bc8517, + 0x0aa0a55f, 0x81bc1318, 0xf4e78334, 0xdc842b6e, 0x481c2b2d, 0x3cbea61c, 0xc4f8a9e8, 0x7dcabc71, 0x2e0e55d9, + 0xe573c5b4, 0xe1497518, 0x0dc84dcc, 0xe4f638f5, 0x36daa4ec, 0x744f9ff2, 0x50399ac8, 0xe662c96b, 0x0d4277e6, + 0xb0aa3558, 0x946ac393, 0xe17956b9, 0xecae1d0c, 0x391bea36, 0xe4c13366, 0xe348641a, 0x8daca675, 0x8e332d8e, + 0xd4bd9f85, 0xeaa71224, 0x8a3900ff, 0x30c61fe0, 0x4895d297, 0x27affdca, 0xc20c585a, 0x4303af42, 0x927acc3b, + 0x67376595, 0xa084f3be, 0x012907c4, 0x6f9a6af7, 0xc6633020, 0x1e2bc30b, 0xa63a1196, 0x42fd5522, 0xae73ff91, + 0x8755dbef, 0x4d8ac1dd, 0xf597c119, 0x27dfc56a, 0x0fb9fd18, 0xbac68ef1, 0xd6afed34, 0xa1b3cd74, 0x6fb33ab0, + 0x5c72454b, 0x5b8405b7, 0xafbcd4ec, 0x3a2e13b5, 0xa62a1f85, 0x98364004, 0x42924ed2, 0x5d7408f3, 0x772904c1, + 0x6fbcd820, 0xc3e94414, 0x1bdef62e, 0x6b245e4d, 0xfd559621, 0x3bbbdfa5, 0xaa256463, 0x6647ad25, 0x32486223, + 0x2ca43110, 0x3c42f050, 0x47bbcf2c, 0xb57b58cf, 0xed935219, 0x938ce832, 0x6eceb9ed, 0xecab65fc, 0x97089e33, + 0xd969c2d0, 0x50a6e5c6, 0xb1a71397, 0x8dd5c98c, 0xd7e52947, 0xa11fb664, 0x99970615, 0xfd2bee29, 0xf7a61839, + 0x46499e62, 0xa4399d84, 0x0b381a1f, 0xba020db1, 0x3c785925, 0xfaf8c847, 0x541c0e12, 0x805d14e2, 0xe1850c30, + 0xe08f66bd, 0x8ce1bd61, 0x6cad310c, 0x682fcc5c, 0x085cc6f6, 0xaaae460b, 0x2c514000, 0x59d01f17, 0x2ac9a26c, + 0x5a55aa76, 0x4f4733ef, 0x47fef406, 0x41aee863, 0xe75f6460, 0xb5a56e9f, 0x8f4053cb, 0x9ad2c925, 0x98ac87b9, + 0xf0515544, 0x6a9dcc32, 0x7586c933, 0x78211f03, 0xd1a314f4, 0x502a63c1, 0xbec4c465, 0xba90179f, 0xada6268b, + 0x609c949c, 0x6c8a3427, 0xef0e1720, 0x41083b9b, 0x8f3da87a, 0x32154fd2, 0x0f1b1377, 0xce945662, 0x1a5406ef, + 0xcc26381f, 0x174371fe, 0x3d3dd5d6, 0x53ca96e9, 0xc5c50797, 0xd3b387f3, 0xe3d743dc, 0xce7ceb6d, 0x08c27668, + 0x04879d01, 0x460ae430, 0xb8cba93f, 0x3ec26cf3, 0x93c36450, 0x3e72f2c6, 0x71d57414, 0x21997e1b, 0xa08e2d17, + 0xcb4a439e, 0x3c705d2d, 0x3decb54a, 0x0374c52f, 0xbd2843d0, 0x2f176563, 0xce9069c2, 0x38399d82, 0x322adbd6, + 0x69d4b869, 0x29e62ca4, 0x7e7546f2, 0x55d9e41a, 0x9a19b073, 0x9395d32d, 0xaa711c2d, 0xfeee413e, 0xeaa8837f, + 0xa2a5f124, 0x76f65a42, 0x8f408ecf, 0x4ee995a0, 0xd50e0c2b, 0xb5d1912c, 0xa7546e5b, 0x68a35392, 0x590892ce, + 0xe7366e53, 0x8bbe0891, 0x98ef078d, 0x13d0d191, 0x65beb278, 0xf3670a91, 0x2c79024e, 0x136d4540, 0xf8245491, + 0xb948f4ba, 0x30f899e9, 0x5728c3e7, 0x7ef7d995, 0x30f77053, 0x0558febc, 0x242508fe, 0x99cf48fd, 0x66eaa7c7, + 0xedfa9de6, 0x7e0f5c18, 0x5d771121, 0xf5b82db7, 0xa0e429d7, 0x70cd4549, 0x0f3cbef2, 0x69bf8f0d, 0xf47dbf57, + 0x0ca3b928, 0xdc560291, 0xf93603c0, 0x93c6efc3, 0xa160327b, 0x500a3212, 0xca026269, 0x2baf86d7, 0x57373a10, + 0x43347c1a, 0xcc8f56ff, 0xf25f5b6b, 0x8593adae, 0x66dc339d, 0xc774fb14, 0xe5adced6, 0x287bda99, 0x0daaca38, + 0xe68cabe0, 0x379669af, 0x7d7e3878, 0x644a6fd8, 0x30d4c6d3, 0x0330d2a7, 0x60d6389c, 0xabaa502f, 0xa9a9a9e6, + 0x332d8753, 0x9d1eca94, 0xae9193f4, 0xde8cb580, 0x8908e402, 0xe51ffb64, 0x999c63b3, 0xfd617497, 0x05d4adb8, + 0xf9e9031f, 0x0f96d9b1, 0x1efedd55, 0x3539e07d, 0x02ca7918, 0x70bf53af, 0x55c1ea4a, 0xebbd6c23, 0xb0e7c56c, + 0x02407354, 0xd59fae07, 0x9a0e7707, 0x9faee3a4, 0xa9a04740, 0x398df47b, 0x458b95d6, 0xba7d39c7, 0x69b21e3d, + 0x7bd6b6a1, 0xba9ed5c1, 0x3de36cf2, 0x270da498, 0x362c08fc, 0x5e93cb4b, 0x1b874657, 0x54af067d, 0x80cf8b84, + 0x07b3f079, 0x8b78f266, 0x8060fb46, 0xd7138fc1, 0x3dcb1225, 0x74276fe1, 0x35c7ee86, 0x48a58acf, 0x9d4b83ce, + 0x95a15bfd, 0x0d70463d, 0x8daf6d69, 0xaccf4cb0, 0xac6524d4, 0xf01d5696, 0xfef5ad3b, 0x67b3f590, 0x527ca541, + 0xd7154d88, 0xb317fda7, 0x144e5da6, 0xeb9d8888, 0x0b87d22d, 0xa5a25056, 0x550f41e1, 0x13f14b96, 0xdadfd378, + 0xb461c309, 0xce54ef09, 0x628bdf09, 0x1a9fce69, 0x0e31aeb2, 0xa8e6ddd5, 0x9dffea7b, 0x67f2503d, 0xf0998fd3, + 0x53334557, 0x766875ad, 0xf6c524f3, 0x100418c6, 0x80c9fec8, 0xb89acab6, 0x6dd3b788, 0x63e733c5, 0x3873c22f, + 0xa9e3453a, 0x2593fb95, 0x35434968, 0x078da9a4, 0x777320c1, 0xa8f666d8, 0x89cdf324, 0xa0ff45e0, 0x5f2ff9cf, + 0x1669d4e0, 0xaac4d8f8, 0xf9c4427d, 0x925bb311, 0xd125e6db, 0x61077e1b, 0xce1a8041, 0xf42b2418, 0x19819557, + 0x67ca9f2e, 0xdc7efcee, 0x5fafee2b, 0x30e38299, 0x68b11bc4, 0xc87c629a, 0x7cfa493d, 0x2f92c9b8, 0x41874919, + 0x3c5daf5a, 0x321ae89e, 0x35ffd898, 0x5737a9d1, 0xb7e5a503, 0x584a71f3, 0x00f5efe4, 0x7a6856c5, 0x243a8b26, + 0x7e38efe7, 0x8f4cd2c8, 0x5d5c4dc0, 0x49eb0096, 0x717d2e06, 0x0f94759c, 0xc76b5fcb, 0x5e87c011, 0x65b39b41, + 0xbbe46cee, 0x10e6bd8e, 0x36cc3c7c, 0x0edf2409, 0xdfc45c97, 0x7f864545, 0x83531e05, 0x9dcda3d5, 0xfd139fb9, + 0xdba826de, 0xff22c1a3, 0x19037270, 0x3992d5d2, 0x88d0f8bf, 0xdb122b56, 0x0b3dfbfa, 0xc4f12a82, 0x6ab6213d, + 0xdcc4a566, 0x53211da4, 0x8d77d985, 0xd22fab5e, 0x0f795422, 0x3b23a060, 0xebb827f8, 0xb7741643, 0x69b44698, + 0x61ac5fa1, 0x63fc078f, 0xcda4ef6e, 0x6e36ec63, 0x5d978c8c, 0xc5b4aebf, 0xc978b1b0, 0x5b324351, 0x77c96f8e, + 0x890f275e, 0x3bfc5cd8, 0xf34b64df, 0x79e4e6df, 0xc515c0e6, 0xd3f87c5b, 0xadbd2a2c, 0xfca4f093, 0xba468fd8, + 0x793049f2, 0x0b2b3f36, 0x55e5064a, 0x5e6d414e, 0x571258e9, 0x2e8c19ba, 0xeccae93f, 0x70c7da5a, 0x323c636e, + 0xa392dc4c, 0xe1502de0, 0xa659424e, 0x075f3a8c, 0x079bfbab, 0xd139f9ee, 0xc9a3f3a4, 0x3ef73e49, 0x65f8882a, + 0x5c11b2e9, 0xd3c4a12c, 0x7182b037, 0xa9b045db, 0xf3d41e88, 0xfd646014, 0xce405494, 0x14a1c02c, 0x57f9706e, + 0xfe4cdd78, 0xdb1a56df, 0x8ba2dad3, 0xf87a02c3, 0xf1602e0d, 0xa6da06bf, 0x68b73af0, 0x07edfea1, 0x54ac362e, + 0x0b7fa743, 0x201bc12f, 0xa0ef68fe, 0xffd595fb, 0xc39a7b80, 0xe92dc372, 0xca2f3014, 0xce25d36a, 0x3bee1fad, + 0x433b899e, 0xbd03c34c, 0xaa20d8b8, 0xfa3cc39a, 0xaa186323, 0x045e2540, 0x8d51a03c, 0x89f1ebed, 0x926f12dc, + 0x6af80481, 0x2e5d4106, 0xda3cd6ac, 0x35aa0c22, 0xa2a9cd33, 0xbfb9f59d, 0xe5be7a26, 0xa89f9b56, 0xdb7d24c2, + 0x08e72259, 0xb8b587b4, 0x009952f1, 0x0c84cc70, 0x7543c48f, 0x005db3ac, 0x05bc0456, 0x5936869e, 0x6480184c, + 0x4294cffd, 0x6a13da09, 0xd0eac4a4, 0x472019c0, 0x1494d5c2, 0x6dfac15d, 0x77fb0907, 0x33ce55bf, 0x71bacd0d, + 0xcefd40ee, 0x5ae526fa, 0x7e41274c, 0x4bc718a7, 0x081247a9, 0xe6d4c22b, 0xa71410ec, 0x58b5060b, 0xc634d6ec, + 0x3415cdcf, 0x03d92ee6, 0xf8232ba0, 0xd7103111, 0x64521d81, 0xf211fe73, 0x59eddb7f, 0xba6c9a2b, 0x96745125, + 0x77f0e1e8, 0xea9511bd, 0x92cc0877, 0x81b9f02b, 0xc773ce5a, 0xde35c3ca, 0x312875c3, 0x4a644e84, 0x252a2ec9, + 0x8c68f47b, 0x01458907, 0xece5b212, 0x734c0e70, 0x58d790dd, 0xfee2af0c, 0xb83b5f7f, 0x5686bc3b, 0xa7cc4bc7, + 0xbb1d7b0a, 0x958443d6, 0x6640f243, 0x62199cff, 0x85675fba, 0xb7f57540, 0x71e34984, 0x0070d744, 0xc02eddd6, + 0x3801294e, 0x56f82390, 0xcf79ccce, 0xba804b2c, 0x67d04ffa, 0x4d0803ac, 0xc242923b, 0xd5b9ce87, 0x189f92ff, + 0xea7c501e, 0xe9424eac, 0x032aac5a, 0xf7e28b79, 0x2bcf9320, 0x41c117d3, 0xc9c5af5b, 0x611e333c, 0x58577ce9, + 0xed7ffd48, 0x65932ee0, 0xea38375b, 0xb62524cb, 0xa25b2a9e, 0xbcbcb236, 0x2829739f, 0xa726279b, 0x3a2a7cbb, + 0xf1f88c4a, 0x56a64009, 0x7ff05aad, 0xc5abfdbf, 0xf3077f31, 0x897a4f06, 0xe92cb0b6, 0x42e9c786, 0x87e24ce9, + 0xb5543f1d, 0xbd252e8e, 0xb73517e3, 0x27b5dda4, 0xd117e2c8, 0x97a5c47a, 0xf7067bb8, 0x5aa55e69, 0xa7a78e9b, + 0x79be586b, 0x44eb3feb, 0xf3d241d5, 0x1c8d504a, 0x01517b07, 0xfe7bb97d, 0xf52d07de, 0x05bda0c8, 0xbd598dd4, + 0xf03f8006, 0x8c190fc3, 0x008f5d78, 0x2ec70ff0, 0x19654336, 0x61be7850, 0xe2468138, 0xba64722f, 0x8d2b10c8, + 0xe350a236, 0x283bffc5, 0x4f1aed79, 0x5a1beab9, 0x30befbbd, 0x76f3e0a9, 0xd61534d7, 0xcbe36646, 0xb18133de, + 0x98f9c740, 0x430faf4a, 0xfbb70b73, 0x22e48a81, 0x43e6b117, 0x25c243ec, 0x9bbcc190, 0x301a5d67, 0x31d9b732, + 0x01085dd0, 0xca552431, 0xeb4ecf90, 0xef6d2902, 0x63a0950c, 0x6ffdda48, 0x7ae9ba90, 0xa2cd32dd, 0x145cd7cf, + 0xc3890c9a, 0x90bce844, 0xd94e2c3b, 0x533b0551, 0x9884ca03, 0x9e13bff7, 0xc6714b8b, 0x27ed409a, 0x79525871, + 0x42fbdac1, 0xafeaa2c7, 0xe18b6932, 0x4f7d1848, 0x43b37157, 0x5d8af7b2, 0x12540d78, 0x42580dbb, 0x241fd38a, + 0xa7eb52be, 0x0ea95b6d, 0x180a1d48, 0xf1f71cd6, 0xa39eae8e, 0x3da412be, 0x399453f7, 0x7da7769c, 0x4fc32641, + 0xd0b72ece, 0x2a979f87, 0x183878fa, 0x9346bd51, 0x73c836cb, 0xa2817a46, 0xcb380df6, 0x6b37c4c4, 0x2c1e645d, + 0xd800a51f, 0xbabad700, 0xd0c7ef72, 0xba62c9d9, 0xb4def6f9, 0x596bbb6d, 0xeb95046a, 0x330ddf2a, 0x44cff86e, + 0x2b8a527f, 0x34414075, 0xc5770753, 0x04bf64ac, 0x27295346, 0xa493d709, 0x17cc179a, 0x9d25b924, 0x9862b7f3, + 0x503449e3, 0xe9363f9a, 0x44ca2b63, 0xc7578ccf, 0x64a27ac5, 0x84bd8fc5, 0x7d44f1cf, 0xe15e48fd, 0xc5b36a9e, + 0x4875d366, 0xb1633ead, 0x8111fc14, 0x7aacd415, 0x74b9af32, 0x1d011f48, 0x829e131d, 0xcb782946, 0xb71876b6, + 0x0b3659ce, 0xc59140db, 0x5b746547, 0xe4b6b46d, 0x01951b9f, 0xde2c23e4, 0xf6cb80fa, 0x424e7298, 0x66fee481, + 0x20cd804e, 0x86f9b360, 0x14099e53, 0x5081dc5b, 0x70b0bd0d, 0x5c1401c7, 0x6dc8868a, 0xd14e87ec, 0x6127347e, + 0xfe3bc4d8, 0x6bef8539, 0x7c3194c3, 0x223c894f, 0x6714f56a, 0x96ec4886, 0xc5acd0c0, 0xb2c96584, 0x343d7fa6, + 0x6ba99556, 0xcbb48bf2, 0xfc2c3485, 0x80800778, 0xeba7b9d3, 0x3a30afde, 0x465fa90e, 0x6714944a, 0x76baacdf, + 0x02db6595, 0x2fe3547f, 0x3729e399, 0x74ad8d35, 0xe3a4a4e0, 0xf7bd8637, 0x94186302, 0xcef60cd1, 0xd8b7726e, + 0xfad26c8f, 0x3902e352, 0x8ea8871e, 0xc36025cb, 0xf184381e, 0x52dc7ce1, 0xa38666f1, 0x505d087e, 0x603df3ca, + 0x2bdb04e7, 0x8b893469, 0xbe782803, 0x932ebe4b, 0x36522dab, 0xc4aa2ec9, 0x52b8a65d, 0x4c30f589, 0xac7a822b, + 0x40f2088e, 0x1cb45840, 0xe5ca6ceb, 0xf48505eb, 0x945a3b66, 0x3f1d898a, 0xa04c1ed2, 0xc0273a53, 0x30412cb8, + 0x3d859e0f, 0xc226c7b0, 0x4311c779, 0xc33fc307, 0x6aaca797, 0x2df26dfc, 0xb4f11d81, 0xd350dab7, 0x6557c420, + 0x408cf507, 0x5a7a947b, 0x25c74896, 0x7c1df36e, 0x5984d0ee, 0xe536f4f4, 0x13eb0805, 0xa3a615e4, 0xdb411d92, + 0x8c4f5240, 0xb3fb0835, 0x81889744, 0x8b9d9def, 0xbf97acf7, 0xf493f3bd, 0xeb436ad7, 0x52e2d93f, 0x6d5dc7d2, + 0xc1d3136b, 0x3e239a15, 0x82b8c9f2, 0xee96fbd6, 0xc8a28b6a, 0x8ae80e6a, 0x481440ad, 0xa72e2ce6, 0x3c9b9a42, + 0xaa4e92a0, 0x7f5881d7, 0x59921f42, 0x88054d10, 0x2d22f63a, 0x6cf2fc6e, 0x3f289a63, 0x23e3c778, 0xa55309b9, + 0x7e1e80b7, 0xc14f8a9d, 0x6b93b377, 0x42102ef0, 0xe11ab68a, 0x4f5a44bc, 0xc0d303d2, 0x32c34126, 0x82e6f213, + 0x6ea3864a, 0x595c7a93, 0x9e6bed13, 0x87a7edc6, 0xa1a4c120, 0xcbf5e0f6, 0x14c6200d, 0x1bc1adec, 0xe3892e40, + 0x1e33ef6d, 0xe0b68e6f, 0x7d59c3a5, 0x42427f62, 0xa008c84e, 0x7e98291b, 0x4af91dc3, 0x73646ce8, 0x5eba2140, + 0xa9492bae, 0x8c977ffd, 0x45d2675f, 0x557bd37a, 0x2fcef0e9, 0xfb2a6782, 0x46ab030f, 0x609e9951, 0xc94ab1ec, + 0x303dc8d2, 0x02b26212, 0x68668e2c, 0xfadccb3d, 0xe697ec13, 0x587f1601, 0xdf797b6d, 0xf2f4b47e, 0xeb6f86f1, + 0xc8efaf00, 0xcb223019, 0xb2aa9844, 0xf715c5aa, 0x72370ce1, 0xbb739aa5, 0x590dcfd0, 0xd6ceb05f, 0xc35a02aa, + 0x60b742cc, 0xd47bb27d, 0x1dfac348, 0x68260cad, 0x38475e6f, 0xfd848892, 0x7d77d6d9, 0xe47d6217, 0x497765c3, + 0xdd9626ca, 0x98db9723, 0xe0a7bc61, 0x0a85edd3, 0xaf1cf078, 0xf583fdd1, 0x82a2332a, 0xc4cba90a, 0xcd39214c, + 0x725e7acb, 0xeb1f3e26, 0x8c4cf67d, 0x928b6b63, 0xd598001b, 0xc3f0a119, 0x58ad5da6, 0x75f463da, 0x588dfcee, + 0x295d78a2, 0xd7a2a6b5, 0x05f5a03c, 0xf79886a0, 0x76afdd47, 0x00a00138, 0xfe1774f5, 0xbc2fea14, 0x71480902, + 0x4f4fa2cb, 0x37983d13, 0x7f04fb43, 0x6f39745d, 0x23ee578b, 0x07dd1931, 0x64c5589d, 0xfeff2b8f, 0x09216836, + 0x420adb24, 0x0035d31e, 0x960df348, 0xf5f735ca, 0x4b12a919, 0xcd0040b7, 0xbdec818e, 0x2a271163, 0x5625fbb4, + 0xfedf55ca, 0x02110730, 0x58b8ea9b, 0x3bacbdc8, 0x1b16fb3a, 0x1857ce56, 0xf25f967f, 0x091accc4, 0xcd07de20, + 0x1a7ea4de, 0x609269bb, 0x7860286a, 0x6fb0e4e6, 0x7bbb4ebe, 0xdcd94aed, 0x88a9d6e4, 0x492127e8, 0x3117c592, + 0x8d0eba94, 0x46c6b2ae, 0x39510967, 0x9007f1e7, 0xb8a62f85, 0x01f438d6, 0x8090c0d2, 0x2bc62709, 0xbef651be, + 0x286a7d0f, 0xc09430b2, 0x8accaf11, 0xa9c37371, 0xb5949e5f, 0x0fcc3673, 0xc9380994, 0x0b4fbefb, 0x7d94b97f, + 0x7de2a330, 0xbf03ad13, 0xd74013a1, 0xc4f3b335, 0x1d52840d, 0x078f85fe, 0xa31e39ea, 0x5f3e907c, 0x60c8d9a7, + 0x1e277a26, 0x92602c70, 0x0b426392, 0x74d41e5d, 0x3627b418, 0x328d13b3, 0xb8432ed1, 0xe2d0806b, 0xeddaed1e, + 0x46a02c71, 0x29a321c5, 0x3cd7d6d3, 0x85eb09c9, 0x9a551c03, 0xc604c8a3, 0x6d7a8bb9, 0x83cf4754, 0x486339a8, + 0xb93b2323, 0xd98c5613, 0x9acbc531, 0xe66667bf, 0xbf54e54a, 0xdd75d492, 0x961e3775, 0xad9eafea, 0xd75dcd60, + 0xdd3f7db5, 0xf9a3b21b, 0xdec730b6, 0x0851f2d7, 0xd2e4fef7, 0x658504b5, 0xa6893bbf, 0x3bf3a5f5, 0xdf6e28fe, + 0xe16793b8, 0xe0bf5fa7, 0x57c8051c, 0xdc8c315f, 0x80d45439, 0x08a7a04f, 0x0122c8f4, 0xadde44af, 0x9aca2f84, + 0xa96af956, 0xf66aaa98, 0x87c82e86, 0xdc69b199, 0x5cee8cb5, 0xb2edb201, 0xff54fc91, 0xf3368031, 0xc0b39823, + 0x3c2675bd, 0xcf534c28, 0x44cdb9d6, 0xd892ea9b, 0x492724d7, 0x651ea225, 0xf9f72c77, 0x1daa5e90, 0x715408f7, + 0x2a69da36, 0x4a59619b, 0x01dcb4e0, 0x0601e096, 0x3488e54b, 0x75ee353d, 0x82b7ae78, 0xc47d12ee, 0x529d06f8, + 0x92d07f88, 0x7f471b6e, 0x3bbeab7a, 0x39807db2, 0x94824e9d, 0xc9e94219, 0x7a3168a8, 0xab4313bc, 0x9afb8e29, + 0x2e95885e, 0x5d9daf0b, 0x76e5018c, 0x19d96bd7, 0xf751a9af, 0x38f5a1f1, 0x85631108, 0x02b0ae01, 0x244a913a, + 0x4dc6c8d3, 0xaa8eef4f, 0xb44c077f, 0x824a1b79, 0xe35888ac, 0x7d86534d, 0xe52cf404, 0x6fdd7abe, 0xbee2d249, + 0x76299fe3, 0x35e3a244, 0x2383a89f, 0x46c4aff1, 0x09cad952, 0xe72dede0, 0x67e924d1, 0x223eb1be, 0x65d754d4, + 0xb0234f76, 0xe8a649d1, 0x55a8af30, 0xd2426b91, 0x8f97117d, 0x3d0173ef, 0xd84e4dc4, 0xb1b3dd05, 0x6fb4e710, + 0xad02ba62, 0x3ca1b057, 0x7018bbb3, 0xcf40c44d, 0xcbfb4410, 0x3ca5bbb5, 0xeee5651f, 0x0e161659, 0x0090cc4a, + 0xd351072f, 0xddad1cb8, 0xe8601d2e, 0xc05aa289, 0x5922ff92, 0xa6655b9b, 0x5fe4a1cd, 0x4aaeec06, 0x3131b354, + 0x41ae8051, 0x5e3eebda, 0x61bc03fc, 0xd42b009b, 0x6dde50c1, 0x678dd67b, 0x501627a0, 0x84921239, 0xd0d781d4, + 0x3ab98a50, 0xf29392a7, 0x5971cc93, 0xc6b5b8a4, 0xfb185003, 0x5b323513, 0x03196ec7, 0x45623f7d, 0x2b37ab87, + 0x2debf459, 0x2977860b, 0x46cbdb58, 0x5ce8cc8c, 0xaec790c8, 0x736f312e, 0x0a63aecf, 0x9e33da67, 0x3b9ff724, + 0x6f915be4, 0xcb734fce, 0xf1543239, 0xfd18d1b9, 0xf7162e81, 0xb3a90c76, 0xad917a9e, 0x1562501e, 0x5a9f9c5d, + 0x3104f1b7, 0x019cddbb, 0x8c287d17, 0xad617f99, 0xfa88b38e, 0x8b6c609d, 0x56c40754, 0xfa10401e, 0x85a69a6c, + 0x60392124, 0xc02ef463, 0x78c2416c, 0xa73f384c, 0x58dc6105, 0xf26a22d2, 0xb05b6619, 0x15cd1ff9, 0x03096d0e, + 0x3195c0ce, 0x89a0d56a, 0x4c4d269b, 0xdfc82745, 0x918b8495, 0xecc84bbe, 0x905d547c, 0xa2ed6362, 0xc2cee5ed, + 0x30216b6d, 0xd18e5124, 0xf4c6ab8b, 0xa9a327a5, 0xaca23b9e, 0x29fbd7ee, 0x175764da, 0x86efc26c, 0x825de26c, + 0x1c4fe78d, 0x283ce248, 0x4ac10c0c, 0x50bbf3fb, 0x029f6275, 0xe4fa99bf, 0x03e447f9, 0xb58fe8c4, 0xd3ff4b84, + 0x62ceb07a, 0x154821ec, 0x57acf840, 0x820ebc15, 0xdc3634b3, 0x5ded71c6, 0x50b7c917, 0xf45c8e44, 0xfa3d34f6, + 0xac3f72ec, 0x8cddaeba, 0x9fd76792, 0xe8f631cf, 0xec652ab1, 0x4f77b310, 0x8731f203, 0x9b1ca4d4, 0x66bc06b6, + 0xd7bf2a9f, 0xe85e9a7a, 0x3c4b23d9, 0x500c633c, 0xae4c3699, 0xcf603f66, 0x5516d253, 0xce9cb03d, 0x4e4e94ad, + 0x9a6c97c8, 0xf64195a2, 0x4654bfaa, 0xfafcb9b6, 0x19d8950e, 0x5b1e76db, 0xbd65ed3c, 0x9a7c9495, 0x6ae08520, + 0xc5e76655, 0xb8283a1b, 0xa99506f4, 0x9bad69ac, 0x88bd2344, 0xec8462d7, 0x2138c82b, 0xe481c196, 0xfd3f41cf, + 0xe94bae66, 0x5bcb5b13, 0x2898f120, 0x53bfc982, 0x08f986e4, 0xae207148, 0xc22bfc08, 0x8a5020ce, 0x9b58ea3e, + 0x6f72422e, 0xbbe61f89, 0x858581f6, 0xc7b1c6e9, 0x469fb2a8, 0xb4610534, 0x9d58f6fe, 0x26bf4649, 0xf315de28, + 0xcec0f753, 0xeab9d8cb, 0x080fef72, 0x3aeaa30b, 0x66d795c5, 0x4bfdeef1, 0xfc91af88, 0x39416dfd, 0x5bbf1404, + 0x42a017df, 0x68ed4aab, 0xe62ab313, 0x9e9225ef, 0x43f8c595, 0x23287a84, 0xa2eb5953, 0xb8127b33, 0xe77a570a, + 0xa44386f7, 0x29d11f1e, 0x9c790194, 0x3b591abd, 0xca34f643, 0x6d19bba4, 0x375d77f1, 0x0b251032, 0x1b9cad58, + 0x07f75a65, 0xe350bde0, 0x330d51db, 0x9ac02a7a, 0x93850dc4, 0x1c4e38c4, 0x4df16ab4, 0x4d0539b4, 0xbcd073a7, + 0xdedb7462, 0x9a1735f2, 0x3a270ddf, 0x6e84f448, 0xd43ff76b, 0x6c223839, 0xc0146552, 0xc26d2da5, 0x391cd6b5, + 0x366b271f, 0x5c7f49fa, 0x1535d991, 0x7b99ed3f, 0x1268bf4a, 0x8feb08f2, 0xb3147781, 0x73eef8ec, 0x9a3baa11, + 0x471b3d3e, 0x28e15300, 0x2cd29643, 0x7869b033, 0x8ee2e423, 0xeba17e0d, 0x1147e107, 0x10cd31dd, 0xf62b8269, + 0x770ed913, 0x37c9e6bd, 0x71d5a928, 0x534e3ef1, 0xac6f4f8e, 0x12e4986c, 0x0e980054, 0xd82a7b68, 0xa8b65319, + 0x0d789d69, 0x04ee8210, 0x5240cec3, 0x44cdf9eb, 0x3e9be0fc, 0x5b4a29f9, 0x63feb3f8, 0x9cfb2a6d, 0x8511a2af, + 0xa70f0dda, 0x3874ca42, 0x8c1e33ec, 0x5c198862, 0x5d3d2126, 0xca76ab0f, 0x4bcf0901, 0x34634fed, 0x5f2f50d0, + 0x0a62a4c8, 0xfa3f8f9a, 0x6838c4fa, 0x45bcf291, 0x33420971, 0x3b19032f, 0x5a78ab1b, 0x8a2a2d9c, 0xf6e42092, + 0xe932953d, 0x21440e30, 0xc80d9ac9, 0xf4e21c8b, 0x2e304404, 0xb0d8a528, 0x502ec2e0, 0xae02393c, 0x1a7f6fd3, + 0x284f7eae, 0x472e20b4, 0x566fd29b, 0x266e4ffb, 0x094113e4, 0xf89aa4fb, 0x4831b50b, 0xb10d2943, 0xdaaef780, + 0xbc6bddac, 0xb10a66e1, 0x1b4323d0, 0x4709e2e1, 0xb1c94599, 0x7602fe88, 0x6828bd9f, 0x9fe233f5, 0xe500a509, + 0xa3d5179b, 0x6781be15, 0x198b1ac4, 0xbb8d607b, 0x59c3b2c9, 0x640974e5, 0x1bec4641, 0x57bfbe8a, 0xb8ee6496, + 0xa70dc9fd, 0x2d2ef7fe, 0xc8f33ebb, 0x7354232d, 0xb499006a, 0x4753f8cf, 0xbf47144a, 0x15b0f955, 0x08c4d36b, + 0x8f24c18d, 0x86c613b7, 0xee941bc9, 0xe5a4e391, 0x4c14ca0e, 0x5760ddf4, 0xb79cf32b, 0xd3815126, 0xe07e1924, + 0xd7d8b2f7, 0xa607b6b8, 0x8644e7bc, 0xa2df704e, 0x12ef3958, 0xc6fdab8b, 0xeae25855, 0xa19cd609, 0x514b1c09, + 0x51f9fd39, 0xbc71de26, 0xc7be4c41, 0x99a05417, 0xbe634f4a, 0x615edc1b, 0x89f5df75, 0xd933cc15, 0xeda34c06, + 0xf83f96b8, 0x3a28e253, 0xd4d65669, 0x599587c6, 0xdb59fc44, 0xf610a652, 0x5ca01eba, 0x12c68171, 0x504165ce, + 0x1034ca59, 0x69a94ef8, 0xe810b073, 0x3d832886, 0x516e34aa, 0xd729fa0a, 0xe22f63aa, 0xae8bcb90, 0xf4965962, + 0x1750148f, 0x649c4ff7, 0x4417a2ae, 0x574d8c5d, 0xee6368e4, 0x251f2f44, 0x77e9bb1d, 0x4801f2b1, 0x077c927c, + 0x77bda395, 0xb08a6b4c, 0x6c52e0ca, 0x60e769d9, 0xf619855e, 0x7c7652a6, 0xc47a2d6e, 0xf04f973a, 0x9f572aad, + 0xedc49347, 0x8eeea5fa, 0xcfc7b7d5, 0x18d29c3d, 0xfdfdf3c9, 0xd209381c, 0xddfc4ee5, 0x1585dfe1, 0x2859f52c, + 0xd70869fd, 0xd6d6a175, 0xdfe4dec4, 0x0a21b1b5, 0xcfae9b8d, 0x921eb7ad, 0xc9020997, 0x73b44e46, 0xa3bce24a, + 0x3bbbb9b8, 0x4ea918e2, 0x16288893, 0xec331eaa, 0x3ddeea11, 0x6b22a45a, 0x178f2200, 0x543fbbbb, 0x90c223ba, + 0xc167a255, 0x968b52c7, 0x237b45f4, 0x39c9679a, 0x12d07be7, 0xcff443f2, 0x3de08c70, 0xf9eb46bf, 0xecd3696f, + 0xccdd0312, 0x510fd99c, 0x7b075ce5, 0xf2d5972c, 0x13b1a565, 0x647f4407, 0x3dda1c52, 0x0db195b0, 0x2b2f8eff, + 0xfa137377, 0x6caedd85, 0x8fe097e1, 0x10ac8564, 0x72981d2a, 0x08801390, 0x0e3f1ef3, 0x7108f544, 0x6633d426, + 0xc4bd651b, 0x7d06da4d, 0xbc1d9a63, 0x90a067d5, 0x9a7df559, 0x1d0a11b7, 0x1e5da7f3, 0x29fc2c9b, 0xaf70f7dc, + 0xe41b41fd, 0xab9624c3, 0x5d75b435, 0x002621ae, 0x7a9b9919, 0xa33b4861, 0x27d3f2cc, 0x9dd5a907, 0x065640c3, + 0x07086a7c, 0x6ad3c7e8, 0xda61d0fd, 0x997065cc, 0x7ef2b121, 0xeb787574, 0x4d335fd6, 0x32924acd, 0x7a9b34e4, + 0xb141aab8, 0x142c608c, 0x6da52db7, 0x38f48141, 0x3e8c6aa0, 0xb8096c4f, 0x7b861d61, 0xa60fd6b3, 0xc64e4612, + 0x0df0efb5, 0x82a2098c, 0xf58f70cf, 0x090f9316, 0x7adc0c57, 0x89c80d7a, 0x98379e82, 0x07627449, 0xba249bde, + 0xe4071277, 0x335b6e37, 0x10197c05, 0x9806fcf3, 0xd419c50c, 0xa924d154, 0x686a0968, 0x1d4b2dce, 0x5f21ba32, + 0x22a288ce, 0xd46494a9, 0xcacd96f7, 0xd4fb0ef8, 0xb52990ff, 0x4328b4a4, 0xd53e43d5, 0xe17e01ab, 0x22c5f729, + 0xee0e806e, 0xaea91ce4, 0xc9368cf1, 0x3298a441, 0xada607d5, 0x0ce64ea4, 0xb039ee8a, 0xc624916d, 0xce3cb963, + 0x6a21afd7, 0x8bf96410, 0x4618d43b, 0x7def1c9e, 0xcbec3e7e, 0x2fd1e025, 0x87d93d6b, 0x0ff5f5d8, 0x7c21d0d1, + 0xf5ec1657, 0xf4c2190b, 0x2eb3b608, 0x08745f07, 0x6ebf3462, 0xe421705c, 0xe86372f3, 0x49adf1da, 0x5aecc162, + 0x671d0028, 0x1ebbda45, 0xd6d010cc, 0xf5395b97, 0x21df6419, 0x2d4b3d3a, 0x6ad03908, 0x81931219, 0xff65858c, + 0x8e78697d, 0xa9ff5ca6, 0xf2e609c5, 0xccf21be7, 0x83966dfd, 0x8a3cc868, 0x39233e2a, 0xc8902098, 0x69c98dca, + 0xe3ef8e7c, 0xa163b614, 0x14d2a62a, 0xc2c5c281, 0x6cc9b9d8, 0x1062064c, 0x6040cfcc, 0xf92fc8f3, 0xb802811e, + 0xdf2af1db, 0xe8e6f840, 0x1f4ca9cf, 0x6ba56df1, 0xd0ca8462, 0xe37139a6, 0x2fa37f0e, 0x522fb55f, 0xf73269ef, + 0x0a3d8ca8, 0xf16a0a01, 0x1802107c, 0xb4439056, 0x4b0a451d, 0x89ea2c4c, 0xa129618b, 0xceebbdb8, 0x4538462f, + 0x0f0245f3, 0xba48bd00, 0xc35b8aec, 0x87486b26, 0x046413a7, 0x82f0e45f, 0x030c82f6, 0xc8863f3b, 0x5e477d1d, + 0x9c146856, 0x13e2206d, 0x13bf11d4, 0x2be3908f, 0x7a4a1945, 0x1ac7ca96, 0x0c83535e, 0x7390f976, 0x2f2daefb, + 0xf0d7a92d, 0x9fb3f3c2, 0xe1c6de32, 0x834e151b, 0x69ae51f8, 0x4ced1563, 0xec6fb8a2, 0xff68a14c, 0xdc0bf8fb, + 0x01e1bd7b, 0xbc687394, 0x40c2f545, 0xe8af3002, 0xd37a3c35, 0xe7ab8da4, 0xd2096256, 0x838d60da, 0x5e44811f, + 0xe67a6484, 0x272eba23, 0x34568289, 0xe665c623, 0x28e32ebb, 0x380e31e2, 0xec66fa5f, 0x9326ce9d, 0x5d566645, + 0xe60c3eb5, 0x521e1756, 0x5480e735, 0x07b7f520, 0x344470f7, 0xbad01966, 0x435288a1, 0x1b8e3bd3, 0x840bfffc, + 0x06e4073f, 0x5ab23cde, 0xdb0482be, 0xf53e30d1, 0x51d5640e, 0xb5572dcb, 0xad565df8, 0xe60e26c9, 0x03368102, + 0x239bd1df, 0x80cff272, 0x9640352c, 0xa13d9d05, 0xf2e59975, 0x6eb89c1a, 0x081fc914, 0x5fd76af5, 0xb420cc67, + 0xd3941e78, 0x1ad61f76, 0x8fc02d0e, 0xece7be6e, 0x7e13393c, 0xeea6da04, 0xa4a3d76e, 0x3648ad17, 0x8aef288e, + 0xa1ce51e4, 0x64a93a93, 0xfd2f5089, 0x599bac3a, 0x8d3a0170, 0xf8b3cd30, 0x89ab7843, 0x1d3e5db8, 0x06cbb16a, + 0xd28952d2, 0xca284893, 0x8fd1a1e1, 0xecc8aa4d, 0x465de563, 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, + 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, + 0x9e794663, 0xecda4063, 0x4f3c615e, 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, + 0x5bee2390, 0x5bb0ac2d, 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, + 0xcbc03381, 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, 0x5e365ae5, + 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, 0x1da22f3d, 0xbde1988d, + 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, 0xc654b0f4, 0xb3c61edb, 0x34380acf, + 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, + 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, + 0x6ca12b76, 0xca9e521a, 0x3de6ed99, 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, + 0xe3860943, 0xf1f3f4e7, 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, + 0x401dd9b2, 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, 0x9c7c7cab, + 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, 0x68fd2cdb, 0x5b325dc5, + 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, 0xdfeceee9, 0xeff255fc, 0xfc97bd59, + 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, + 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, + 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, + 0x19026be2, 0x106a090e, 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, + 0xfd1119a3, 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, 0x2e43d2db, + 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, 0x24996054, 0xe5fd7518, + 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, 0x19490a6e, 0xbfcc1617, 0x967882fc, + 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, + 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, + 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, + 0x071ae0e6, 0xc3c8d053, 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, + 0x3678e185, 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, 0xb67c5819, + 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, 0xc2222ef2, 0x5a046246, + 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, 0x54a3bc82, 0x5706694c, 0x4664f6db, + 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, + 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, + 0xce8f27be, 0x5a559021, 0x9b1740dd, 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, + 0xe9952168, 0xdc81cac7, 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, + 0xb58b5c72, 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, 0xd99e6ac7, + 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, 0x3635a87c, 0xcee78062, + 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, + 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, + 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, + 0x384ad656, 0x9d824935, 0xec915f03, 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, + 0x4064fbb5, 0x66ad961a, 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, + 0xdbe24543, 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, 0xcadaf946, + 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, 0x628675d3, 0x6b1d569f, + 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, + 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, + 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, + 0x8d3c9334, 0xe5c6c529, 0x20e898db, 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, + 0x0d748033, 0xecc5393a, 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, + 0xf35661c3, 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, 0x5d2efdf7, + 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, 0x69c800e0, 0x5d310e80, + 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, 0xe9811969, 0xc08a7628, 0xe5e44555, + 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, + 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, + 0x80082d96, 0xb5a06d54, 0x1612537d, 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, + 0xf2fac0cc, 0x737aeb61, 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, + 0xaa36609d, 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, 0x0c2f32bc, + 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, 0x6a6777dd, 0xa7029cb3, + 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, 0x59ebc41f, 0x7e55932d, 0xcf78bead, + 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, + 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, + 0xc99944ec, 0x5289e5ff, 0xd64dd767, 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, + 0x4cf9307b, 0x1b6533fa, 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, + 0xe854ce92, 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, 0x408694a5, + 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, 0x24ed6723, 0x0c24fa00, + 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, 0x7db55eaf, 0x0fa8aabb, 0x0e942194, + 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, + 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, + 0x0350d608, 0x54e77f30, 0x866c2575, 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, + 0x3bf7c1bd, 0x5762abb7, 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, + 0xa9a36bdc, 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, 0x5b171723, + 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, 0xe66188ab, 0x4d2b635b, + 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, + 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, + 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, + 0xa31e8408, 0xac80b477, 0x7e7ddefc, 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, + 0x22eb7378, 0x08773858, 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, + 0x65c5fac3, 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, 0x7b9de18a, + 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, 0x804275c8, 0x6ff502be, + 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, 0xf65056f7, 0x18393ab3, 0xbf8c8b96, + 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, + 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, + 0x9685fd96, 0xc354066f, 0x9cdbc452, 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, + 0x328dfdbe, 0x7d168a67, 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, + 0x5fd2e5d7, 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, 0x3fb91263, + 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, 0xca097d3e, 0xa90c478f, + 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, + 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, + 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, + 0x4b823e48, 0x581b2420, 0x4ff2d70c, 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, + 0x476626bc, 0xad5c9d4c, 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, + 0x766880ca, 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, 0x89eac33c, + 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, 0x4eb31945, 0xf2c5d93b, + 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, 0x793fdc45, 0x519a1c15, 0xe31ee96d, + 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, + 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, + 0xd036e501, 0x0cb814a8, 0x06b9ab5d, 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, + 0x9284b162, 0x2cd5b7ab, 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, + 0x6ba484fe, 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, 0xdd4c9f22, + 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, 0x7143f3bb, 0x540b1347, + 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, 0xb2874627, 0x7f0c9a4a, 0xf8106eae, + 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, + 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, + 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, + 0x15aa0461, 0x1bc775e8, 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, + 0x68377d59, 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, 0x90689424, + 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, 0x362b4809, 0xec92588b, + 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, 0x32a14d01, 0xf4f6fec4, 0xada9360c, + 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, + 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, + 0x86428407, 0x45d6c023, 0xc77ebdeb, 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, + 0xf8198b68, 0x881246e7, 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, + 0x9e82681e, 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, 0x2d42e033, + 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, 0x0d1c971e, 0xe7795114, + 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, 0xb31d23cd, 0x8102d36d, 0x51aeed2d, + 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, + 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, + 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, + 0xbd3d8fa0, 0xe798d010, 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, + 0xa956eb79, 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, 0x723065f1, + 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, 0xac794782, 0x002064e9, + 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, 0x344f1195, 0xa7181920, 0xd05fcfd2, + 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, + 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, + 0xb75639f1, 0xadc76771, 0xd3543fd5, 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, + 0x6c95fd6a, 0xc3bb4a03, 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, + 0x045c945f, 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, 0x5acd89f8, + 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, 0x353f926c, 0xe3471231, + 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, 0xd16e5090, 0x9eff66f3, 0xa35ee078, + 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, + 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, + 0xc4062fef, 0x2bd3b757, 0xcbd45594, 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, + 0x2857a67c, 0xce5b2c90, 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, + 0xcd439cd3, 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, 0xbb20e7d2, + 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, 0xee542f36, 0xb0807f6e, + 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, 0x5104928d, 0x047c150a, 0x328cc000, + 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, + 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, + 0xcd61b411, 0xfddd923d, 0x638d0e61, 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, + 0x6bef47aa, 0xf460b130, 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, + 0xdfe4f729, 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, 0x55d094ff, + 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, 0x3161690b, 0x3ffa1fcd, + 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, 0x8a41bcac, 0x38d2f20e, 0x9aac541c, + 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, + 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, + 0x54705c7e, 0xba150347, 0xa80514ec, 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, + 0x7ce59906, 0x577da8f1, 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, + 0xd28382ff, 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, 0xb7bc9a79, + 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, 0xcc0be43f, 0xa606a522, + 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, 0xea4a38b5, 0x76901b4b, 0xe2583ac7, + 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, + 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, + 0x0cfe6db5, 0x5accdc39, 0x3377eaed, 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, + 0xc8bd6a8f, 0x625a6215, 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, + 0xae81db75, 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, 0xfee25664, + 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, 0x8bb3653b, 0x026eedbb, + 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, 0xb5bcee42, 0x6db10b43, 0x9fec55e3, + 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, + 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, + 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, + 0x429e2dc7, 0xc309b30a, 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, + 0x7874b53c, 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, 0xb92b80c7, + 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, 0x3326a1a1, 0x78b01e6e, + 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, + 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, + 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, + 0xc687b587, 0x383f7c40, 0x54830d04, 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, + 0xbf32f0c7, 0x2a796a67, 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, + 0xfd0367d1, 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, 0xc0e35390, + 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, 0xa32b3c81, 0x1d02d66b, + 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, 0x456c5876, 0x4c7a1f7d, 0x8210e535, + 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, + 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, + 0x03826132, 0xf505a1c5, 0x5536b8f5, 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, + 0x743d2b0d, 0xa82aed8d, 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, + 0xafef4d80, 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, 0x6b311848, + 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, 0x129d80fd, 0x18982768, + 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, + 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, + 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, + 0xeaac07b5, 0x0a377949, 0xcea56fc5, 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, + 0x65e46fe0, 0x9a5df9f9, 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, + 0x8358ab8c, 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, 0xdc18fabe, + 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, 0xd48cbb77, 0xcffdb7b0, + 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, 0x8ac94023, 0x11efd6fa, 0x5a6574f0, + 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, + 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, + 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, + 0x743b1a4d, 0xcd7ff202, 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, + 0x18060bb0, 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, 0x4bdc887f, + 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, 0x58f5a07b, 0x3c0266e5, + 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, + 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, + 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, + 0xbbff8af7, 0xaab1617c, 0x596a01d9, 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, + 0xd980aa05, 0x9269bb19, 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, + 0x298eb742, 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, 0x27fd3816, + 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, 0x2ae780c3, 0x7374f385, + 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, + 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, + 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, + 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, + 0xc19f5cac, 0x0bed2aa4, 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, + 0x783cfc66, 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, 0x1628b35c, + 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, 0xb361da26, 0xc0e2aa6b, + 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, 0x10f2492f, 0x231be0f1, 0x2b6fc840, + 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, + 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, + 0x7f6ace2b, 0x21514ebb, 0xc46d4800, 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, + 0xaf2ba637, 0xc4063ea0, 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, + 0xf942657f, 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, 0xea694198, + 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, 0xb453ee10, 0xafe27498, + 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, 0xbb74e075, 0x4408ab02, 0x2eae958a, + 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, + 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, + 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, + 0xfc5ff382, 0xc25ae007, 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, + 0xca5e1ee1, 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, 0x27c57f08, + 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, 0x86952278, 0x2810740c, + 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, 0xabc1d828, 0x05b673a5, 0x93e0c5ce, + 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, + 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, + 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, + 0x9d268a7e, 0x0485322e, 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, + 0x4f7b98f0, 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, 0x9161c085, + 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, 0xd6243501, 0x50f99e78, + 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, 0xe7888474, 0x58967c61, 0x9c2344d8, + 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, + 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, + 0x4a543dd4, 0x72d27f50, 0x794b2c38, 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, + 0xde3dfa58, 0xeac4977f, 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, + 0x4e87a4a4, 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, 0x829272a4, + 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, 0x508ed11e, 0x34f13455, + 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, 0xd435af57, 0x3e86d270, 0x7f04d0f2, + 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, + 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, + 0xfc49bc3d, 0x55757973, 0x84149ef8, 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, + 0xa17f53c4, 0x882c2967, 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, + 0xb340d658, 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, 0x76c9e6a2, + 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, 0xcc17d17e, 0xc52d9ae0, + 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, 0xad9625b4, 0xdbb45f5b, 0xf707fbea, + 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, + 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, + 0x6107a718, 0x83643c4c, 0xf2f96503, 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, + 0x41397ea1, 0x5793b309, 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, + 0x30ed4df8, 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, 0x9e264e70, + 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, 0x3f767c6f, 0xd1c48bab, + 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, 0x50da0980, 0xac96ecf6, 0x008c4910, + 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, + 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, + 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, + 0x49a844d0, 0xbbf5495f, 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, + 0xc41a3c1d, 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, 0xdea90048, + 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, 0xb709b9fe, 0x4549aaea, + 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, + 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, + 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, + 0x17a388b9, 0x78038049, 0xc505ab47, 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, + 0x7e6727d2, 0x9cef5fce, 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, + 0x88bb5013, 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, 0x17261a8e, + 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, 0xf480ab6d, 0x39525194, + 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, 0xdfb74aec, 0x62aae2f0, 0x46b855b3, + 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, + 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, + 0xe260be49, 0x18b01f3b, 0x0a2fc30f, 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, + 0xfb85d9ea, 0x2ddace97, 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, + 0x8c823cb1, 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, 0xf22f9ccd, + 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, 0x769e9c28, 0x65f8905d, + 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, 0x631f0974, 0x3f48dae6, 0x025739cd, + 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, + 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, + 0x5113ea88, 0x72ef2942, 0xd4aa0766, 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, + 0x74798f9c, 0x35e96814, 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, + 0x5ddb2efb, 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, 0xf4ab5191, + 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, 0x88a6c986, 0xdb0e7bbb, + 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, 0x0baad5bf, 0xaed19942, 0x66e4b053, + 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, + 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, + 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, + 0x34268b83, 0xe4bb7d3a, 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, + 0xac836a26, 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, 0xec264fe5, + 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, 0x381f32a7, 0x20a5e8c0, + 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, 0x15470bc2, 0x9ef31ae9, 0xd9e26951, + 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, + 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, + 0x2bf519ed, 0xf57860ea, 0xd69ba992, 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, + 0xccfc8b54, 0x58a93087, 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, + 0x60d94733, 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, 0x8ae04ca7, + 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, 0xca2f0fa1, 0xaac2e3bb, + 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, + 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, + 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, + 0x07796220, 0x0f0f8722, 0xbd6092dd, 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, + 0x17862bac, 0x610b9ce2, 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, + 0xcf3f6b27, 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, 0xff007778, + 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, 0x15a2c929, 0x9263b116, + 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, 0x187b9976, 0xf5ea2689, 0x87e3b151, + 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, + 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, + 0xbaa41197, 0xe5dcc72c, 0xaf16a669, 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, + 0x257e15c8, 0x12fbc35b, 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, + 0x4f1906d3, 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, 0x6d7b3b88, + 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, 0xfc5fbfed, 0x18db2aa6, + 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, 0x4429b1aa, 0x838682ab, 0x5bdfd86b, + 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, + 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, + 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, + 0x5e68e36b, 0x838322dc, 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, + 0xed6bf807, 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, 0xfb7507a4, + 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, 0x532e6654, 0x0c528786, + 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, 0x230b4319, 0xdd780574, 0x58889d79, + 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, + 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, + 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, + 0x73e830ce, 0xb353b81d, 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, + 0xe7929941, 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, 0x45da675f, + 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, 0x52a33502, 0x7d4b918c, + 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, 0x4b0a5e47, 0xce55bc17, 0x09656fd6, + 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, + 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, + 0xfe627e5d, 0x791daf5e, 0x50943665, 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, + 0x3e6a0f21, 0x9dad2288, 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, + 0x72f16cfc, 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, 0x86de5619, + 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, 0x06add0d4, 0xd0c462c6, + 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, 0x494f49bb, 0xcd7f90a5, 0xb6709e40, + 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, + 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, + 0x9bafb81d, 0x62e53468, 0x86ec692b, 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, + 0x8d6632f1, 0x8ba05667, 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, + 0xcfad36f8, 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, 0x526af581, + 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, 0xdea23b22, 0x9f8c78c5, + 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, 0x8d801702, 0x98d2fe2d, 0x3ed6b821, + 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, + 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, + 0xb2ccc077, 0x6162fefd, 0xb3701463, 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, + 0xeabc4ede, 0x82191ff8, 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, + 0x3e457dab, 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, 0x5ecc278f, + 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, 0x0862a010, 0xb3c9a772, + 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, 0xed37dba7, 0x26112057, 0x68c688f2, + 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, + 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, + 0x67c335d0, 0x6981f384, 0x6ca54c87, 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, + 0xf5315cf0, 0x995fb40e, 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, + 0xa571dfbf, 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, 0x1ce39a6b, + 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, 0x33a6d8b3, 0xd9101e64, + 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, 0x13eb0f7c, 0x77b31835, 0x65c53459, + 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, + 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, + 0x0e5f8848, 0xd61ad101, 0xf44c42a4, 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, + 0xd37d5397, 0xeada6952, 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, + 0xfea92813, 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, 0xded23976, + 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, 0x881ccb9e, 0xa1bb6a8d, + 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, 0xe19a859f, 0xfb877d69, 0xc91faf5e, + 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, + 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, + 0xd5e24aec, 0x6731d1b3, 0x48ebc226, 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, + 0x18281991, 0x42588569, 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, + 0x915978fc, 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, 0x4a5faf73, + 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, 0x477d5c34, 0xe2ef3d70, + 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, 0x6db3425d, 0xce451d6f, 0x6f2a53e9, + 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, + 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, + 0x0365098d, 0x013e15ad, 0xc990d5f4, 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, + 0xed216f9a, 0xcb714de5, 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, + 0xf602de55, 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, 0x99029b50, + 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, 0xbd2995e9, 0xd906ec04, + 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, 0xb921c72a, 0x9fc5a234, 0x55d0fbec, + 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, + 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, + 0x84b6ab49, 0x5b3c6835, 0x0015afb6, 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, + 0x89cc97bc, 0x713d3b24, 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, + 0x86363b5f, 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, 0x7368089c, + 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, 0xe516c9a0, 0xeab5aa5d, + 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, 0x614782cd, 0xce169d44, 0x6433de5e, + 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, + 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, + 0xc0ac7573, 0xca381e11, 0xfc5916b6, 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, + 0x332f9714, 0xa3804fc5, 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, + 0x37552b9e, 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, 0xe9b11f94, + 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, 0xcfed5315, 0x27f4a06d, + 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, + 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, + 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, + 0x3c9c2d05, 0x6794edd6, 0xc22cc352, 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, + 0xc045f697, 0xfd090038, 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, + 0x36ae74e4, 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, 0xd85611c1, + 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, 0xb326cc47, 0xe0faa978, + 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, 0xb77eda67, 0xc49052e6, 0xc514a075, + 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, + 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, + 0xf28a6231, 0x9eaa4f64, 0xe9468748, 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, + 0xd8eae4af, 0x46876f0b, 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, + 0xd1daf994, 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, 0x5389bce5, + 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, 0x62a8e0a5, 0x200442ca, + 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, + 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, + 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, + 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, + 0x29bc2f91, 0xac5eaa62, 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, + 0x8bc6cf4f, 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, 0x6bbb33dd, + 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, 0xf708838e, 0x2caf050b, + 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, + 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, + 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, + 0x6746103e, 0xa0eff544, 0x0bba778a, 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, + 0xf1ee2d08, 0x1b100e82, 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, + 0x7ea8c2c3, 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, 0xd1d5c2c0, + 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, 0x5ce3fa8a, 0x2075b595, + 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, 0xdb4a2241, 0x806460ec, 0x183637f9, + 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, + 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, + 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, + 0x724a1e6a, 0x1f49fcfc, 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, + 0xf8481f7d, 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, 0xc548731c, + 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, 0x92d1c238, 0x59503c44, + 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, 0x82172a29, 0x5db3569b, 0x6a0ab6f7, + 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, + 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, + 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, + 0xc2110048, 0xef4c9825, 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, + 0x3d923162, 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, 0xaddd3c63, + 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, 0x20d00302, 0x0718e1f1, + 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, 0xb6747958, 0x6bcb60f5, 0xbce4158b, + 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, + 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, + 0x436ca416, 0x0091a7da, 0xe705853a, 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, + 0x99f5e336, 0x67e6d388, 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, + 0x20fa88af, 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, 0xdeb5cc9a, + 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, 0x112a8ec2, 0x385e89a8, + 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, 0x0c60638a, 0x0c83492d, 0x95d61b20, + 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, + 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, + 0x50f5b110, 0x0c23b119, 0xbc27c7e8, 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, + 0xd1b98d82, 0x632df3e2, 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, + 0xe98733e0, 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, 0x75257595, + 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, 0xf12a2f87, 0x900624fa, + 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, 0xf3be72c7, 0x01ca0052, 0xdf927440, + 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, + 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, + 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, + 0xc226cc77, 0x294e0e4e, 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, + 0xd0489c01, 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, 0x5d6bc3c2, + 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, 0x0c117533, 0x0b70ddeb, + 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, + 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, + 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, + 0x4cd711a6, 0xc46a6a58, 0x2d82b595, 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, + 0x9920ac09, 0x02db13ae, 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, + 0x108cdb88, 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, 0x2944706d, + 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, 0x8ee22fc9, 0x9970baae, + 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, 0x253d5795, 0xa8e3738b, 0x9770975d, + 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, + 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, + 0xacabe801, 0x47952193, 0xd3138e94, 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, + 0x68161660, 0x6365afcf, 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, + 0x96847976, 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, 0xedabeffe, + 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, 0x25d6ba47, 0xec63d289, + 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, 0x671596a0, 0xa08b6a5b, 0x0bca7779, + 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, + 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, + 0x9e283138, 0xb2631843, 0x8c9d46d6, 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, + 0xa4fa2f87, 0x472f5be5, 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, + 0x6fba83bf, 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, 0x7d4f1ea5, + 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, 0x9b0b0ade, 0x6373a3b0, + 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, 0x4c9ca5fd, 0x7f1f3313, 0x30013306, + 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, + 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, + 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, + 0xbed76d66, 0xf5b960da, 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, + 0xad500497, 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, 0xef6e61d8, + 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, 0x4ed7b964, 0xff1f6c98, + 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, + 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, + 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, + 0xbbdb8c62, 0xf6dd386b, 0xe3358787, 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, + 0xce5af4fb, 0x712564e1, 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, + 0x66f6d4a7, 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, 0x499c86a6, + 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, 0xc94b8391, 0x7bd8e512, + 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, 0x449df40e, 0x93f035f8, 0xafd2521a, + 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, + 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, + 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, + 0xf9621d42, 0x77ee21f3, 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, + 0x45317e93, 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, 0x080f5133, + 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, 0xf8ab5684, 0xbd3b8b9a, + 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, 0x428761dc, 0x97459150, 0x709e0a12, + 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, + 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, + 0xac7d020e, 0xa7bf5312, 0x4c6834b7, 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, + 0x03f9e743, 0x3004dfb0, 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, + 0x9ad90bde, 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, 0xa1fc99fe, + 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, 0xfd35ccf2, 0xd2473bb9, + 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, 0x32e8b9f2, 0x103ef0a9, 0x1888642e, + 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, + 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, + 0x8ec2282a, 0x146232d5, 0xf4241f66, 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, + 0x2d03e06e, 0x305c322c, 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, + 0x2c33b686, 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, 0xa9d0de99, + 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, 0xce93f4cd, 0x822382ec, + 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, + 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, + 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, + 0xc83c381c, 0x098d5293, 0xc0738c93, 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, + 0x359fc239, 0x806328f8, 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, + 0x7d0cf9c7, 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, 0x356f9c19, + 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, 0x96e32fe0, 0x142e5994, + 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, 0x702f1422, 0x4008e264, 0xbbf91d05, + 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, + 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, + 0xa6b29bb4, 0x67777742, 0x65b6542c, 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, + 0x86507fb1, 0x26f76111, 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, + 0x658bb0c8, 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, 0x685d4d9a, + 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, 0x30d5acc3, 0x18d236ab, + 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, + 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, + 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, + 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, + 0x37160e0f, 0x9f623018, 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, + 0x99b0115b, 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, 0xc7d5de52, + 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, 0xf080b017, 0x4da4d290, + 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, + 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, + 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, + 0x0d628e03, 0x4a93cdd8, 0x6f643479, 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, + 0x1983f603, 0xd4591b19, 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, + 0x3488b648, 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, 0xde17a435, + 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, 0xc4706c3f, 0xdf14d9ab, + 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, + 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, + 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, + 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, + 0xb8c941ca, 0xe26b9187, 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, + 0x0bbe4840, 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, 0x7fa40f5f, + 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, 0x611a0f89, 0x3a0e5f8a, + 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, 0x01079381, 0xc250fa30, 0xead64afb, + 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, + 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, + 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, + 0xe5b8b32e, 0x9c6261e3, 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, + 0x8f854e38, 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, 0xa8e1a4e5, + 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, 0xff46bbb2, 0xa38e83bd, + 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, 0x6a145a5c, 0x6a41add1, 0xd954c1f0, + 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, + 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, + 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, + 0x5eba32d0, 0x3cc4a69c, 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, + 0xc8013642, 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, 0xe9e313b3, + 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, 0xef679615, 0xc074d215, + 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, + 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, + 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, + 0x208a0b6f, 0x7245f138, 0x352dee4f, 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, + 0x46fc92f6, 0xfcfa9de2, 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, + 0xa44da7f3, 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, 0x35818ebe, + 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, 0x3a03b930, 0x868b0e63, + 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, 0x4d72927a, 0x1b62ae8f, 0xef765353, + 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, + 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, + 0x83b4c653, 0xfd8585e4, 0x23af00e8, 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, + 0x822679ff, 0x695356ac, 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, + 0x9a82734d, 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, 0xccf76bc6, + 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, 0x0e3e6c5f, 0x83452a89, + 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, 0xdadeeb74, 0x7425d656, 0xdcf615c1, + 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, + 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, + 0xc725ecc0, 0x35b295d1, 0x7534f83a, 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, + 0x98a03f22, 0xd70a9952, 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, + 0x7ccba435, 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, 0x771d7fac, + 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, 0x59029f2b, 0xb47ed32a, + 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, + 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, + 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, + 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, + 0xdf2b52bc, 0x0849a8d7, 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, + 0xcca50f90, 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, 0x38d03044, + 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, 0x7ec20957, 0x2e01a0db, + 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, 0x0b90f4dd, 0xa36b8065, 0x31933133, + 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, + 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, + 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, + 0x339b1a9d, 0xcd9c7feb, 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, + 0x85fd0e01, 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, 0x0470618d, + 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, 0x89209a5c, 0x5a60a94e, + 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, 0x22497a31, 0xf3512771, 0xb6adb43b, + 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, + 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, + 0xfc9d64e3, 0x1b454a6d, 0x8b220894, 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, + 0xc66316e8, 0x52366573, 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, + 0x2d196453, 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, 0x6fb6bf96, + 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, 0x3c9257fd, 0x8a3d0140, + 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, + 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, + 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, + 0x615723de, 0xf5fde9a0, 0x96bab4f4, 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, + 0x54f0e2e2, 0x5355cc42, 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, + 0xf6ff9372, 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, 0x0230da46, + 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, 0x26a6191d, 0x83da081c, + 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, + 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, + 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, + 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, + 0x8bf9c71e, 0x1a682b8a, 0x7bbd75b5, 0xb06c035c, 0x9bd1355b, 0x03f15e1b, 0xe1dc6a96, 0x724c12d5, 0x5eeb7abd, + 0x6f1a533d, 0xe4163b97, 0x53963f78, 0xf4bdc4cf, 0x30bc6aa8, 0x55020a94, 0x87424139, 0x7f4e0fc0, 0x0dced4cc, + 0xcc44f761, 0xdc915d5d, 0x5923afae, 0x5fca09df, 0x6da60086, 0x4176cac0, 0x2cd1c0be, 0xeaf4a65a, 0x9a2b0460, + 0xd9adceb3, 0x837911fc, 0x24a064e2, 0xf62aef80, 0x2c72361c, 0xabcea574, 0xc9e8494f, 0x58fdc7fe, 0x19835be7, + 0xe2f50795, 0x22577eee, 0xf37a909d, 0x01085e15, 0x433de341, 0x47e376d9, 0x0bba767a, 0xf77fa338, 0xdaabb9e6, + 0x321bb7de, 0xd9c18914, 0x63c61551, 0x608ac9b2, 0xdc175799, 0xa3b005c1, 0xb30ba812, 0xb8f13ae7, 0x4e6515ee, + 0x63b6e03c, 0x21dc18eb, 0x92116367, 0x912c40eb, 0x67431a9d, 0xa3ac94ae, 0x8778ab34, 0x97d032f9, 0xe363d369, + 0x83361fee, 0xfc13d3ed, 0xa8b81258, 0x3ad31da7, 0xf22b43bc, 0x5e4dc39b, 0xaf3c8d97, 0x4e4f0c56, 0x9ad45750, + 0xce42b7f5, 0xfee1c9dc, 0xda821b40, 0xe112aa6d, 0xc534e246, 0x49278e21, 0xb44895c1, 0xe3d1ab5b, 0x73a79242, + 0x6c9f7498, 0x635ece54, 0x11679e76, 0x2ecfb564, 0x32fac952, 0x9ef53d09, 0xe639b29c, 0x6bc8773e, 0x1bc739cc, + 0x89ba5c0c, 0x4bd2bc26, 0x422ddfd6, 0xfdb0a8e4, 0xcf2f81a5, 0x14841e89, 0xd4f78e53, 0x63013219, 0x359821da, + 0xb02ce75b, 0xac288e79, 0xd6225779, 0xe9c65694, 0x49a11a14, 0x1607727d, 0x5371ef25, 0x6e32e37e, 0x46463aa1, + 0x2f9f3be7, 0x008814a8, 0x4aaeb902, 0xeaf8f5a0, 0x36ff71ae, 0xeda38d7c, 0xc8154fa2, 0xbd72884c, 0xeb83e123, + 0x8c815ce0, 0xe3cec3c1, 0xb7cb6a68, 0x4b2967a5, 0x6f401978, 0xa790036a, 0xd7098ddf, 0xe29bc8fc, 0x990029a6, + 0x03cdb1fe, 0x0dd3e1d0, 0x154d7ad7, 0xf416dee7, 0x5563bc46, 0x724bd24d, 0xc9afafda, 0x15fbdda1, 0xdafbcb38, + 0xd5a26b25, 0x619bed77, 0xba04b927, 0xfd2d6b8a, 0x77894e2e, 0x3a2b2115, 0x4f97c16a, 0x624c5c48, 0x87b8ac99, + 0x52727b94, 0x1e24f7f7, 0x075e8797, 0xf6c0d443, 0x1bbfc65e, 0xaaef1178, 0xc6ee8328, 0x328b718e, 0x6f763df7, + 0xf0198c11, 0xd6cd4bf9, 0x3ee66642, 0x717949cd, 0xd07b2cb7, 0xa023dc26, 0x36fb0e07, 0x833771f3, 0x865405d9, + 0x440f6fbb, 0xaf079d0d, 0x2187a5d8, 0x1c48bf61, 0xd1a3e59f, 0x022d6bda, 0xd6bbf539, 0xf7e1e652, 0xd13cd569, + 0x1953bd8c, 0x2c00848e, 0x15a8bd5e, 0xf1633fe7, 0x56e8f0b5, 0x3b009bee, 0xd18e24a5, 0x06e6be5a, 0x20b080a8, + 0x2b7c3d6b, 0xc9e867d9, 0x013902a6, 0x722d7f90, 0xaa97b1b4, 0x6a72eaa5, 0xa35fb788, 0x02c7801c, 0xf528ad86, + 0xc08e0f90, 0x36013f85, 0xb6507cfb, 0xce50853b, 0xdc81a410, 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, + 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, + 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, + 0xca3c7387, 0x3ebc4e22, 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, + 0x0d609b5c, 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, 0xe964371d, + 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, 0x8549a545, 0x72cd25a6, + 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, 0xfa0f309d, 0x2450505b, 0x7e62d6b6, + 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, + 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, + 0x554de3f7, 0x00236229, 0xb65a8838, 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, + 0x1e0f4174, 0x0e4f84a9, 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, + 0xbecc7016, 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, 0x36f74f81, + 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, 0x49684acc, 0x27ceed4c, + 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, 0xc18462c5, 0x30407eb5, 0x8e18797a, + 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, + 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, + 0x39bc1a46, 0xf4865fdf, 0x22bd8658, 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, + 0xd9382232, 0x947cd63b, 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, + 0x65a5e218, 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, 0x9cff960e, + 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, 0x5da4cf70, 0x861ef098, + 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, 0x2d914387, 0x9ed7f94b, 0xf00b5441, + 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, + 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, + 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, + 0x78603c0a, 0x7c403889, 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, + 0xe1fecec4, 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, 0xee70ca50, + 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, 0x57098afb, 0x744d626d, + 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, 0x5936ff74, 0xc1477a35, 0x3665ecdc, + 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, + 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, + 0x7e1959e1, 0x91787e6c, 0xda51caa5, 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, + 0x8fc78d5d, 0x3ea2142c, 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, + 0xa69d279e, 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, 0xb001c899, + 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, 0x46ebff79, 0xccb7b9b6, + 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, 0xac829629, 0x9ffbf3a3, 0x718c8f7c, + 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, + 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, + 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, + 0xbba13c12, 0xdd02c804, 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, + 0x347c5339, 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, 0x4396ff24, + 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, 0xee7ad3a2, 0xcc436c78, + 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, + 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, + 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, + 0x68c77435, 0x356f1249, 0xec7fe5ec, 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, + 0x8bac2cae, 0x5104a87d, 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, + 0xd5a33292, 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, 0x129c6972, + 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, 0xa54b4c48, 0x667c537f, + 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, 0xe16ab1b9, 0x3d5dd389, 0x5947821b, + 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, + 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, + 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, + 0x8e2665b7, 0xee93572c, 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, + 0x07a80a9b, 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, 0x8a302c05, + 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, 0x9b86cabe, 0x48f7ca80, + 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, 0x79bda240, 0x909fd98e, 0xf49643bc, + 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, + 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, + 0x8821bf49, 0xde5b8005, 0x6e749b41, 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, + 0xc85a975d, 0x00904827, 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, + 0x3ac88c9e, 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, 0xadef941f, + 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, 0x15116dd8, 0xcf51bdc7, + 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, 0xe55e6fbb, 0x43524b5b, 0x12dbc403, + 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, + 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, + 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, + 0xb541d640, 0x84ceb075, 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, + 0xd2f96c90, 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, 0xc9f9d7ed, + 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, 0x3ba18f38, 0xb9d8d6f5, + 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, 0xf818f739, 0x08eaf9e5, 0xc9f08a15, + 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, + 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, + 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, + 0x730d6d4c, 0xb4f2cb42, 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, + 0xfffa9c44, 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, 0xb4ba3765, + 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, 0xf93f4075, 0x9d0ed557, + 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, 0xa5fd92c4, 0x48985b22, 0x9d228641, + 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, + 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, + 0x7e4bb890, 0x1c7739a1, 0xc91fad83, 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, + 0x1eb7fdad, 0xa71313bb, 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, + 0x75bea2bc, 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0x9c315fcc, 0x8b0762de, 0xf28b8010, 0x4bcdda72, 0x45ac9a18, 0x9083961d, 0xf6958e74, 0xa0fcd93e, 0x27592fb4, + 0x04a62c4f, 0x166d4f24, 0x51f0c2cd, 0xb0eb792d, 0x16f78963, 0xa8bb6ccd, 0xf337352d, 0x9f43e39f, 0x3d97dd79, + 0x6ead7f57, 0x52b3c51c, 0x3f796edd, 0x6aa1f5c0, 0xeb1a2a90, 0x3ac20033, 0x102f3f16, 0xf23ddf24, 0xc687bd96, + 0x8af2126c, 0x4d291b91, 0xa561894d, 0xbe645b50, 0xcbd4e08a, 0x69d2d86d, 0xa968161e, 0x5151bc96, 0x753c3dc2, + 0xef4d59c0, 0xd30c1862, 0x6ccbf7d2, 0xafb953d5, 0xdb56b7c4, 0x4665df3e, 0x2d3e6768, 0xf53d533b, 0x827a8867, + 0x657544bf, 0x0cb9eb01, 0x0b31a06d, 0x3fb9c37d, 0xd10ccba4, 0x04ac9226, 0x73947d16, 0xaf488ad5, 0x5fd80905, + 0x442651bc, 0xbb74c336, 0x0fb4191b, 0x83b43e90, 0xa503f9e8, 0x0a4b69b2, 0x1cdd641a, 0x4f9f87ea, 0x2782d210, + 0x9f5af7c3, 0x4c4596be, 0x6a2c6b98, 0xde3bce9b, 0xded33cd5, 0x98a997c8, 0x33d5dc67, 0x1cd9e6f1, 0x183daa74, + 0xb6bb9348, 0x7eacd48e, 0xc404584b, 0x7fb9c568, 0x1a22c0f9, 0xbaa07503, 0x9ab52d6d, 0x655b1ae9, 0xddc911e0, + 0xf40c5d15, 0xa0ce92f6, 0xd0ba6bde, 0x424811c6, 0x0af474a4, 0x87bddd1b, 0xa7d730be, 0x565d365e, 0xbe345362, + 0x5f09e609, 0xf19b5a91, 0x0105b2d2, 0x54bc661b, 0xcacb5c1c, 0x18cb8dc7, 0x4f313730, 0x74d26f5a, 0x629e3a50, + 0x9bfb6788, 0xe45c47bd, 0x75a9e66d, 0x5d2a6d46, 0xb2922a49, 0x3a4564c4, 0x6b3e0469, 0xc931f54b, 0xf37af5fc, + 0xae0a9227, 0xb495eaf6, 0x4dcae07c, 0x41899421, 0xc0b25903, 0x0d66040c, 0xe968c1be, 0xe0cf525c, 0x538b1867, + 0x58b4e4ad, 0x556532e1, 0x67069e3c, 0x2bc5f09b, 0xa7a6f446, 0x2b3ea3b8, 0x1625a485, 0xb9e3f4aa, 0xa5d1eb62, + 0xc40580bc, 0x3471d078, 0x4ed73918, 0x7bffd923, 0xe98f7931, 0xd24b8474, 0x3b60ed38, 0x5388f377, 0xb8e97998, + 0x13cd4c75, 0xb6998008, 0xfcf5f0b7, 0x262d1baf, 0x7772c989, 0xceef466d, 0xc88ecaa3, 0x1b61fb05, 0x1d10b579, + 0x57d2b7a7, 0x2127f2e2, 0x41213721, 0x2bfdfaa4, 0x6b8f20d6, 0x664d62a8, 0x8290a4ff, 0x5cb567c4, 0x8bbbf9a0, + 0x10800312, 0xa842463e, 0x0014f612, 0x9f8a4c0d, 0x08b15b33, 0xf3f6ddea, 0x1f5d3371, 0x1e15d7f3, 0x0b75ade1, + 0x400bb658, 0x2c51e379, 0xcb93de39, 0x91c2b362, 0x8be75e76, 0x2ca0f9c5, 0x32552d87, 0xd3b81d28, 0x8aa8c570, + 0xb27eab78, 0xaa1e51ac, 0x89502bb5, 0x2c588630, 0x95eae621, 0xf58ed713, 0x3d47e807, 0x175601c8, 0x41b46760, + 0xa112459c, 0x5549b1b9, 0x3a6791b0, 0x262d42fd, 0xf57fc215, 0xac17daad, 0x02d5c2c7, 0xc60e0e5b, 0x78928fee, + 0x96e4d6de, 0x4da13de6, 0x063b4d3c, 0xdc9182e7, 0xcb44f614, 0xee140310, 0x18b1ad42, 0xce4c46f2, 0xea7b7c10, + 0x0e32b86c, 0xde08244c, 0xa057c218, 0xd5420c94, 0x1cb9737c, 0x637aa739, 0xc3cc6ef6, 0xad0743ff, 0x8dea9f18, + 0x2f9294d8, 0xda03f866, 0x4e0ad156, 0x25bf86f7, 0xe9d33974, 0x07dab60a, 0xaa2f2e5a, 0x960f77b3, 0x6d39077f, + 0xc7c8a305, 0x1f362db8, 0x72c4e115, 0x81d9e5eb, 0x8d2dd534, 0x9773bd76, 0x6add1c6c, 0x831a3319, 0xa54c3c87, + 0x281786f2, 0x6b1e4b54, 0xe3ea1078, 0xb2b42daf, 0x228bd531, 0x269b2881, 0x53d4263b, 0x66f9a018, 0xf54306c2, + 0x6df72f95, 0x3b61772d, 0x3bb738fc, 0x3fbfd11e, 0x6d142675, 0xbe678e5f, 0x199033cb, 0xaaa59bf8, 0xf690a05b, + 0xf37a38f4, 0xcb1f42f8, 0x48fd71e8, 0x63744120, 0xd3b70a40, 0x230841c6, 0x26a2aa52, 0xeac69c20, 0x06897036, + 0xa51ba165, 0x89e2af8c, 0xe0844bc8, 0x45825e86, 0x097ee7ce, 0xc67d7b6c, 0x0add7597, 0xe9e57e68, 0xd5f41e91, + 0x186dae46, 0x61d420c6, 0xa6b8e835, 0xc5c03608, 0x20438f99, 0xb70bbc5a, 0x024dfabd, 0x50027d4c, 0x28e80eec, + 0x199bc40c, 0xf2aa0a80, 0xcf747795, 0x1be27e32, 0xdde4944c, 0x2a24835c, 0xc1a4c273, 0x2de341ea, 0x45e2f7d7, + 0x2212ee19, 0x07064028, 0x800f7391, 0xf7635268, 0xff37d87d, 0x77296d3d, 0xe1f57f41, 0x89ae2512, 0x2b0783e2, + 0x66cf66af, 0xf575fa25, 0x793f314e, 0x78b2aa5a, 0x88bfdb84, 0xfaa2cc1c, 0xd6b151e2, 0x35f3e5b4, 0x1b2fc6e8, + 0x70f3c9a7, 0xb4aca44a, 0xe0f19973, 0xbb272e6d, 0x13ca151f, 0x2412e5cd, 0x339f58fb, 0x029ee9d5, 0xb87c2f2e, + 0x672ab382, 0x7e1767e2, 0xa541937d, 0x14012db9, 0x86d4886f, 0xa6dec976, 0x74c8deb4, 0xb054503e, 0x38435210, + 0x35231ece, 0x41ad6f71, 0x58334381, 0x35880b60, 0x1844cccb, 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, + 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, + 0x50dd62e5, 0xf2dc2490, 0xb742d94c, 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, + 0x40278377, 0x4f1306d5, 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, + 0x3c727cc6, 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, 0xe3f264d4, + 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, 0xdf701ef3, 0xdbee77ed, + 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, 0x6bd1ccab, 0xdd2cbbd4, 0x6d4849d8, + 0xd98b154c, 0x0ab4f750, 0x47356874, 0xebf27a2a, 0x0d4fb4c3, 0x6a0a8af7, 0xf7ed0b0a, 0x37c2fb35, 0x71fca686, + 0xc13423d9, 0xc6ee8987, 0x5c82b6f2, 0xcc976d72, 0xdce65764, 0x484ef5d9, 0x90092ebd, 0x0cf8d8e8, 0x5d5ce0a2, + 0xcd6aa7de, 0xf9ce34a4, 0x8dd070c3, 0xb19a0b57, 0x337139a4, 0x3eb26084, 0x15dde756, 0x9f1bad7a, 0x345a8b88, + 0x5be24d48, 0x3535a045, 0x46701866, 0x56cf8a71, 0x90a1aa98, 0x60163285, 0xd6a03320, 0x16407c3f, 0x7b04325e, + 0x4f36731e, 0x9179afbe, 0xaee15ca5, 0x153b788e, 0xd682291b, 0x2473cd31, 0x0395c9bb, 0x360b4089, 0xb8f41c41, + 0xd61b957c, 0xb1d3601d, 0x285c0134, 0x2611a026, 0xe30cd2e9, 0x8d0b77c5, 0xef5fd3ac, 0xbacd2083, 0xcce26409, + 0xdfa29eca, 0x7e300ef1, 0x183b8cac, 0x9b02c4c2, 0x6c06ad46, 0x2ec94baf, 0x6725545c, 0xd5e9bf3b, 0x2efd4983, + 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, 0xc0c97ca0, 0xd6456515, 0x86a49990, + 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, + 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, + 0xab800038, 0x0e5f415b, 0x77d71868, 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, + 0x7999f376, 0x687e76cc, 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, + 0x5d416565, 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, 0x78b1dad5, + 0x1f27e9b9, 0x98b6e1ea, 0x81687e81, 0x886fb026, 0x5e10e71f, 0xcabc6180, 0x2909b195, 0xc01d1672, 0x0fa6344b, + 0x3239c578, 0x979c5f26, 0x5f02cf6d, 0x1cec8e40, 0x6ba2d9aa, 0x4f33d4e1, 0xd372c5d0, 0x7c4e2487, 0xe83452b8, + 0x503f00db, 0x20f1c459, 0x52ff0f41, 0x6b4d7ca2, 0x5094973a, 0xf6c5c4eb, 0x7e907c43, 0x3fa6e0b9, 0x663b8a61, + 0x23cf5760, 0xb204aa05, 0x7ad97512, 0x0230a11f, 0xa1a1b1e3, 0x02904261, 0x9a59b732, 0x81eea9f7, 0x2cf2e047, + 0xcac406ab, 0x6040d630, 0xaca48454, 0x0c87baca, 0xaf25f28b, 0xbacb8233, 0x988e8592, 0xab788159, 0x4a0c1bbf, + 0xf054ac4c, 0x5a2ef885, 0x3d489b41, 0x97a17e02, 0x0acfc836, 0x2d8f23fc, 0xe4c15510, 0x467ff8fa, 0x3532bd03, + 0x3992d5b2, 0x5bffe9fa, 0xc1b55be7, 0xb911132a, 0xbf0cf669, 0x8b2100c3, 0x498a3dfc, 0xf14db0e7, 0x8116f826, + 0xf2b491bf, 0xf91bc9c7, 0xab237142, 0xb80ddc3e, 0x5761abc3, 0x93aa4ced, 0x5d99ea4d, 0x8dc34690, 0x28f34916, + 0xf1528cfb, 0xf79a38cd, 0x5c71d094, 0x2878672e, 0x62e3d8ab, 0x2c4fc9f6, 0x7e22e107, 0x64f9509f, 0xbb52265b, + 0xc297147d, 0x8788dd32, 0x62ccc36e, 0xa8c3738d, 0x40feaab4, 0xe5e66e66, 0x876256f2, 0xf7bfbaad, 0x52ea5a26, + 0xab326551, 0x5999a1f7, 0xf5ac042b, 0xce8e4683, 0x6330dd47, 0xba9e63d8, 0x8338d24c, 0x194890a6, 0x7497f838, + 0x7749e986, 0x7774cb6a, 0x5cc0dbc4, 0xf6763737, 0x394efffa, 0xbd7c14a2, 0xc5264914, 0xcaf27fb8, 0x48a66129, + 0x01919ed6, 0x01093bce, 0x6e5f244f, 0x01c7f1d9, 0xe3bc7804, 0x5141def9, 0x9bcbe40e, 0x30ec2e4c, 0x251b2f34, + 0xd31af56e, 0x37fa3f6b, 0xb1e569ef, 0x7865efc8, 0xc038eef6, 0x5ab6dbea, 0x309d5530, 0x5b6f8abf, 0x58bcf70f, + 0xfc20c388, 0xd8e1eea2, 0xad21bfef, 0x5b1b9234, 0xbf44f6e7, 0xa8f11aaa, 0xc2f75f34, 0x2f5ddc74, 0x2236410b, + 0x8b13ca61, 0x89e973f4, 0xce916d12, 0xe4382a60, 0xa1419bf6, 0x1716c2dd, 0x363e3a65, 0xabb42af5, 0xf1e6aa4f, + 0x057db65e, 0xf56c1511, 0xa3bcccc8, 0xb7a257f2, 0x229ae0e6, 0xc9c2de2d, 0xbd5a0400, 0x1c40074f, 0x4b6dc5dd, + 0xaf0a4310, 0xacbf48bf, 0x2feb142b, 0x130a9037, 0x5c530c69, 0xb77f369e, 0xbd8160b0, 0xae8c4405, 0x6893368e, + 0xd4e51c6f, 0x3a7c54a3, 0x78c68b79, 0xf1ba8fce, 0xdd24712e, 0x11043f49, 0xb2b0b6e9, 0xae647902, 0x2f0371a3, + 0xb980fde0, 0x7e18d7c8, 0x2c88c7a1, 0x69c12990, 0x024df51f, 0xad269cf9, 0x20d07c08, 0x46dd7e5d, 0x8b9164d3, + 0x94db4bf8, 0x197cbfdd, 0xd6468cb3, 0x2eeb6901, 0x8c44979c, 0x1d81e0f7, 0x9f946bbc, 0xedfde6b7, 0x2486f2a7, + 0xd8c9af8e, 0x4c0a6f94, 0xd5944971, 0x00fab05f, 0x5426b324, 0x4afb07e3, 0xdfb43f92, 0xe40171d5, 0x4486b8a8, + 0xbc6870e7, 0xc95d18f4, 0x1ca8b3c6, 0xea1c1852, 0x5ca2e2a8, 0xe8da3dab, 0x17612271, 0x2ab72b95, 0x9c15d202, + 0x5c6d5389, 0x85da1da4, 0x429919c2, 0xbdbc5233, 0xb622137b, 0xd7acde34, 0x7cef7a78, 0xb7da1755, 0xef672b63, + 0xfee2f710, 0x03236b0b, 0xc92fc557, 0x8e574b88, 0x2805ba96, 0xc81c866b, 0xad184d45, 0xb836c91f, 0xbeab9200, + 0xc41b82eb, 0xee8ab2af, 0x81160ca3, 0x37fc7eec, 0x83437c12, 0xb86f9be4, 0x44f2d5af, 0x24be3b99, 0x21add5ca, + 0xd0d168c4, 0x32560890, 0x6f698ad0, 0xc5c3ca2c, 0x957eb6e0, 0xa3de6166, 0x09934285, 0xd88381e5, 0x176ff5b3, + 0x493f9565, 0x39f6d3a6, 0xf695c64f, 0x632e92f8, 0xef7404ce, 0xe1466f18, 0x34c0cf9f, 0x5d81884b, 0xa6605610, + 0x56f84ee2, 0xa881494f, 0xa133dee5, 0xe585bdc2, 0x3454b808, 0xb8eb525d, 0xf03de612, 0xd3625812, 0x5f9e2734, + 0x538214a7, 0x21f2740d, 0x39cafc80, 0x092f0669, 0xc244c4ff, 0x569c8561, 0x8ce00cec, 0xfad3174c, 0x17a98478, + 0x3fba51e2, 0x7839ccd3, 0xd3cc2942, 0x34459786, 0x9e605d5a, 0x481ee65e, 0x63c01029, 0x97c3b03b, 0x0556943c, + 0x9ca515fa, 0x45ee4c64, 0xfed15ef4, 0x65baabdb, 0x037c4d51, 0x892ea8a2, 0x2de6038c, 0xd8716227, 0x57424e4f, + 0xf1b5ca70, 0x287fcd83, 0x653d548d, 0x2baaa7ed, 0x6af133ba, 0x4bfb12eb, 0x0585c00b, 0x7926e62b, 0x67f71020, + 0x06941d09, 0x3269b9d6, 0x6becf31f, 0x18b598fe, 0x139643a5, 0x9a9160e1, 0xbe2df596, 0x782f8037, 0x9bcce7db, + 0xf3be74bc, 0x4f7f7177, 0xddcacedb, 0xd348bb00, 0x0ef68de3, 0x1ff7d95c, 0x6201a28d, 0x24f67327, 0xa1425633, + 0x48426e5d, 0x3ccfed4a, 0x92baf081, 0x868d6418, 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, + 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, + 0xa4f0c02c, 0x006bdbc5, 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, + 0xd9d19ac8, 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0x40bb52d5, 0x654712b1, 0xd8e940e2, 0x8ff4683c, + 0x2a998600, 0xd4aad8ba, 0xee241d02, 0x94346fe9, 0xc02eb848, 0xc2c91e1a, 0xea843f6c, 0x5bc57c6c, 0xddd8a617, + 0xebf9c3c0, 0x4980bc36, 0x6d334dcf, 0x97a4b3df, 0x2a94b788, 0x83811aca, 0xbbc37422, 0x6292df1d, 0x761131db, + 0xb2d8dbe4, 0x7ff0219d, 0x95d470ee, 0xda8c0e74, 0xcf981bc4, 0x95642758, 0x215c055b, 0x2aaea2f2, 0x28a91766, + 0xe750abab, 0x995e1edf, 0xe39955fc, 0x33af7feb, 0x238315d1, 0x2ffeef88, 0xe8b6f798, 0x35eeeabc, 0x8368340f, + 0x81dcaf0b, 0x9313abd6, 0xf0c7b961, 0x87cc331b, 0xcece3df4, 0xcb90e2fd, 0xfc2850ab, 0xc5e37ef3, 0xf727bba5, + 0x97c7f994, 0x283e5938, 0x513bd493, 0xb5d182fa, 0x4e8d6fb8, 0x83686263, 0x1cae22db, 0xcc923e99, 0x074cad57, + 0x8938a877, 0x12338d86, 0xd558d946, 0xb28895e3, 0x5a000780, 0xbe031e1c, 0xd33b3dc1, 0xdffdebe3, 0xd234f8ea, + 0x1523c8ba, 0x68a0608b, 0x8b615bd6, 0x2930eeda, 0x28cad819, 0x7c3e8c7e, 0x0aec3b74, 0xc92b4e33, 0x6278a8dd, + 0x1df2fd4f, 0x90a5a45b, 0x34354809, 0x597f9b39, 0x8d1c5736, 0x73d3f226, 0x8bc263d5, 0xe5cd9545, 0x800db58a, + 0xc23bc076, 0x1be19e52, 0xca477b42, 0x15007281, 0x0f687cc9, 0x6a31c769, 0x1d75c0f7, 0xe34730f6, 0x74540689, + 0x38f67674, 0xaa46a55a, 0x6cc6f2de, 0x6762be31, 0x74e55f6b, 0x8dea8bf6, 0xce92f7b7, 0x47b7ba55, 0x7dede31e, + 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, + 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, + 0x11e80584, 0x3a49181b, 0x01877253, 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, + 0x7b06c1bd, 0x241bb5d3, 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, + 0x6a39fefc, 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, 0xe97476ff, + 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, 0x6bc54667, 0x5da05bd4, + 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, 0xa18cde24, 0xa865edcd, 0x4a0863f2, + 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, + 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, + 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, + 0x9d3fcbd9, 0xa2157e5f, 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, + 0x8430e9fe, 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, 0xcff88a4f, + 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, 0x027ff968, 0x7c059f38, + 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, 0xd8861fcc, 0xa171057c, 0xc650cd2a, + 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, + 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, + 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, + 0xd2063aba, 0x38356c3f, 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, + 0x1c1010ce, 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, 0x52f9037c, + 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, 0x49c20c19, 0x5283a436, + 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, 0xc2223c9d, 0x99554000, 0xcd28bc49, + 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, + 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, + 0x553e3c53, 0x4ff910a9, 0xb16d9d48, 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, + 0x1ead51ac, 0xf531936c, 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, + 0xd81a58c7, 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, 0x5bf25e25, + 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, 0xc806079c, 0xc684f5d5, + 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, 0x4adb2b92, 0xf781402f, 0x870c8ab5, + 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, + 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, + 0x5d7847cb, 0x800a7cd4, 0x2174ea30, 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, + 0x2e1cd1e9, 0xc7308954, 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, + 0xb2b5f06d, 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, 0x8692254d, + 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, 0xdee4891d, 0x83247a45, + 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, 0x3e9a6812, 0xb7981ce1, 0xd48dac33, + 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, + 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, + 0x79d4b7c0, 0x4f0d800c, 0x6615417d, 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, + 0xb2213194, 0x520c5c4b, 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, + 0x4dbd49c2, 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, 0x7fd1b105, + 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, 0xc844714c, 0x83a50459, + 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, 0x795f7841, 0xa403bc22, 0x95959ab1, + 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, + 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, + 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0308.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0308.h new file mode 100644 index 0000000000..20aa4ff739 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0308.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1110_trx_0308.h + * + * \brief Firmware transceiver version 0x0308 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0308 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x8ec3b951, 0x63c99646, 0x6806da09, 0x8cb28e89, 0x54761fb2, 0xb61cdecc, 0x56d0146e, 0x0f0ec5f0, 0xab386cd5, + 0x47785e28, 0xd1e5e9e0, 0xaecfdbc8, 0xdaa520c1, 0x664bedb6, 0x42e2b9e0, 0x7b4e8486, 0x5e4c48ed, 0x5f6c1a43, + 0x24d3a08b, 0x6fc17098, 0xb9ad3a15, 0x39988e8e, 0xb3666c4f, 0xd62428b5, 0x3201c3e7, 0x6c68a618, 0xa7d2809f, + 0x0c8069ed, 0xe2d92c92, 0x8654e916, 0x547844c3, 0x927090d3, 0x89ea9e36, 0x14cb9ca2, 0x9a7e1e4f, 0x1b306a1c, + 0x899a6518, 0x30d224cb, 0x39cb398d, 0x3e4b2daa, 0xc852b069, 0xe3c170b2, 0xcd488ad3, 0x42b55353, 0x11f84ab5, + 0xa4e914b6, 0xe3d5c496, 0xd8c7c724, 0x24815d94, 0x35fc4f48, 0x08117bd5, 0x9b7973f7, 0x93efdc68, 0x46210a66, + 0x3abef3d0, 0x90738b0a, 0x2f52fbcb, 0x0ce35a92, 0x3dd2df14, 0xaa27b561, 0xc30530e2, 0x4076289b, 0x6db7358a, + 0xc9917a13, 0x1990bc7f, 0x1f9dcb24, 0xbea6a6f9, 0x6e970084, 0x0b9981dd, 0xba67d2fd, 0x0ad0f3f7, 0x60a98c51, + 0x84d84b20, 0x5710125c, 0x925b6d6b, 0x1b502d0f, 0x0f3406c1, 0xcec6137c, 0xea03851e, 0xab4649f9, 0x94a22871, + 0xcf5e83dd, 0x03e336dd, 0x3d5b2643, 0x09a02efa, 0xfe52e184, 0xfef3c9c6, 0x9dbdb0c0, 0x27c8e9bb, 0x01d3980f, + 0xbfac588c, 0x06d2c35e, 0x7e432624, 0x5e66be47, 0x015f831a, 0x238f7e8e, 0x52d33a40, 0x3e5c931f, 0x66258a64, + 0x25bdc79f, 0xa18ff402, 0x296df700, 0xd79d1744, 0x97b54b09, 0x2c84d3c8, 0x6866a632, 0x0b7da0c3, 0xda16ebce, + 0x05a9a1a9, 0xc2be3546, 0x09c96f06, 0xf060763c, 0x15de09c1, 0x071c18b3, 0xf481e672, 0x8f980b05, 0x828efb6d, + 0xf35f5ad6, 0x990fc5f3, 0xfe9784de, 0x08b85ca2, 0x6de86313, 0xe992cd47, 0x0cb6cd80, 0xe468d778, 0xb4fe4750, + 0x3d99006d, 0x13fc2f72, 0x3e2ce289, 0x3c5bfca9, 0x0f14e557, 0x7f3a74e4, 0xf0b1e7a1, 0x0c6ee4d0, 0x49020688, + 0x63b41799, 0x4f81cd89, 0xcebc4e4a, 0x4f61a455, 0xca537cbe, 0x6dfc5d84, 0x40708aa4, 0x4de5e023, 0xbd1e70f8, + 0x5e069a74, 0x1d73a432, 0xd936889e, 0x29a88d3b, 0x81bdcea6, 0x5af3b5e8, 0x84d2aa54, 0x2e6fe3ba, 0x301c07e6, + 0x710c4612, 0x0c90803e, 0xd2cb9589, 0x57d3f5d6, 0x2745db0a, 0x94fe5e39, 0x450f73aa, 0x300097f6, 0x632a34b6, + 0x28177c39, 0xe32293b6, 0x49c19ed7, 0x3f3e2112, 0x6b71cafd, 0x56442901, 0x222e7938, 0x6da85c83, 0x8f69d6aa, + 0x25d9a87d, 0x28927ae5, 0x55ea48be, 0xac0d050d, 0xb6bc6f26, 0x307aa2fa, 0xa1299e82, 0xd380aab1, 0x4e4ff021, + 0x4e345f83, 0xbc3e592a, 0x0a1e4cbf, 0xe9369fd0, 0xd23940bf, 0xb6edf36c, 0x7b6fe400, 0xb2f26b25, 0x7c5c88e1, + 0xd377f0a5, 0xb5b65718, 0x96a50104, 0x16f76871, 0x9c5d4f83, 0xd9c7aee9, 0x9d307cda, 0x6b7b42ba, 0x6e03c929, + 0xbac87d8d, 0x8bc1abc3, 0xb5442201, 0x50841372, 0xc824a494, 0x854d837c, 0x12678064, 0x080948d8, 0x74adcd86, + 0x70152efa, 0xfbfe30fd, 0x27eeef18, 0x0ee68f71, 0xddd00e0d, 0x0b4f1483, 0xdc6945e0, 0xd0f7563e, 0x4e5d0043, + 0xba12e21b, 0x65b67071, 0x7fbfde91, 0x52273a60, 0xda1cc748, 0x91650bb6, 0xde36898a, 0x68beda16, 0x6d9bd9fb, + 0x00c2897d, 0x44f6d148, 0x7a906225, 0x8221f50e, 0x025c7168, 0x90587c95, 0x9f2f37b8, 0x7eb3f648, 0x91d4a824, + 0xe1bc153c, 0x6800f6be, 0xeccf429a, 0xb794f11a, 0x782718d6, 0x20c8a08e, 0x744ffdac, 0x0276ca0c, 0x0afbe865, + 0x2f78f594, 0x07d3f3c9, 0x401d83c0, 0x79310f05, 0x3142ee2e, 0xa0cc2ec6, 0x17630723, 0x0c7f686d, 0x50b6ed71, + 0xaa59c845, 0x1c50c801, 0xa0d507ac, 0x58507d43, 0x440434cf, 0x6577ebf2, 0x8cec08f2, 0x3705d669, 0x8b713a8d, + 0x55b839f8, 0x8f5d42ab, 0xbfe754d1, 0x44bb8656, 0x5c38130b, 0x8dda1a66, 0x96ad676d, 0x2713dce8, 0x91347be7, + 0xf97dbb69, 0x6d0298dc, 0xf88ae546, 0xdc5bf75f, 0x6be9ef2e, 0xbc9b4058, 0x95d22f21, 0xc34abf5e, 0x71b7059c, + 0x02e7c25a, 0xb9d9e240, 0x204580f9, 0x3afad3ab, 0x75a9f9a9, 0xa3bc4505, 0x5f499ca7, 0xd8c961d0, 0xc562e772, + 0xccbc4b93, 0xf3e6778c, 0x210df615, 0x0ec3f767, 0x831f3206, 0x9cfeb0a9, 0xe7f0d661, 0x2018c171, 0x6db617b3, + 0x91712e53, 0xc2467db2, 0x4c1628a1, 0x9ca4f367, 0x428d5b84, 0xa35095ac, 0xf1248596, 0x75ed083f, 0x1f131ead, + 0x7fe3fdcf, 0xf1d97dd5, 0x0cba6c5f, 0x9acbae99, 0x19d32f53, 0xcc9d8408, 0x9f0117c7, 0x3111edfb, 0x61f9b08a, + 0xe87dc785, 0xee303195, 0xadb2afbd, 0x5b6c4e66, 0x7d298555, 0xd7385a71, 0x8a7b88c0, 0x54e4fa2a, 0x245fa79f, + 0x36b7be0d, 0x382e274d, 0xfe708552, 0x30176c2c, 0x962dbb42, 0x6bf547b7, 0x76ec9a64, 0xa9c55ced, 0xd2ebce8a, + 0xdcfd3459, 0x4dc61db7, 0x2307854b, 0x24eb5fab, 0xd3d5ee47, 0xbfbb970a, 0xdd715ee7, 0x488f703b, 0xa0073b3a, + 0xa4ebc8fe, 0x0b3facfd, 0x2057865f, 0x37754e8c, 0x7dd4a391, 0x9a635b95, 0xb8613d01, 0x320da102, 0x35f7ea1d, + 0xe93ab7ba, 0xa8f506f3, 0xd9cc64ff, 0x9d2d1629, 0x39b71887, 0xcd1826d9, 0xef3e41fa, 0x8d9e289b, 0x81a01555, + 0xa42f1239, 0xe4a20174, 0x2abbc8f2, 0x01966ef0, 0xd3118ecb, 0xa2852ec5, 0xaf8b3149, 0x3c205022, 0xdcd1e254, + 0x6bd58cc4, 0x4eebb56d, 0x1833eee6, 0xa7a3da56, 0xedc2de47, 0x5a3262d6, 0xc603d90b, 0x025192ed, 0x8c1cfc9d, + 0x9fe6df2d, 0xfb9ee5ba, 0xe41c7b4e, 0x13fb6522, 0x012121d2, 0x3c1b5add, 0xc6e0bb88, 0x1fa12a8c, 0x5e29dbc6, + 0xb593b5ed, 0xcaf1e4a0, 0xd67e55ff, 0xf64e3105, 0xdf524d6a, 0xeaf123fc, 0x0cb68e6f, 0xf7d69b3a, 0xb634d64e, + 0xf97192c9, 0x7e9dcb21, 0x0da089f9, 0xe57bd463, 0xd50d02a5, 0x8a531b1c, 0x08cb6b05, 0x440d0e01, 0xf71d902e, + 0xb087be47, 0xfae78175, 0x34e53a75, 0x8f90ee2a, 0x1a08a5ac, 0xf3d9a8db, 0xb3f21c46, 0xc56f0999, 0xc4e724ad, + 0x27f6d68a, 0x7d0e8e5f, 0x32e6bf30, 0xcbaeb386, 0xf2dc7d40, 0x89c1929f, 0x8232cbb8, 0xb8160cc6, 0xd6f22cec, + 0x394dbaeb, 0xad273421, 0x986d3a7f, 0x93611bef, 0x4b372876, 0xfebb8d1f, 0x9e102e3a, 0x177e1c58, 0x1730a6ec, + 0x8dff4fb0, 0xd7c80be9, 0x6d4ccbe5, 0xe7945b66, 0x5826f5bf, 0xe36af450, 0xb65f3076, 0x62344f60, 0x80ceefa3, + 0x98e0e4be, 0xc3c44d53, 0x9633dc88, 0x35350c88, 0x09fd933a, 0xe5c19c5c, 0xfe79a633, 0xfb56d6a0, 0xb708b922, + 0xd385feeb, 0xd0c8d0da, 0xf492ee4d, 0x3bebab56, 0xa610fa11, 0x3b46aa73, 0xb9a0ad9d, 0xf25a694f, 0xa3c45b60, + 0x7d7c970b, 0x5fccf602, 0x4349e0bf, 0xed153023, 0x512f3bb5, 0xc21ad95a, 0x19c27a58, 0x49f1398a, 0x7989d837, + 0xc9a6226c, 0x8f00e284, 0x8b3bbaf6, 0xf67ba537, 0x29ac3425, 0x156b4495, 0x29096f9a, 0xe389307d, 0x62215f00, + 0xd48d32bf, 0x6c1f8a3d, 0x14b7e2f3, 0xcbeb71d1, 0xbded9997, 0xa409500b, 0xfe28d63f, 0xbc7649f7, 0x105bd562, + 0xe164c769, 0xce945902, 0xf8db2777, 0xa86ead87, 0x710bf19c, 0x5443219d, 0xc98977b4, 0xf8918811, 0xc124b706, + 0x996145a6, 0xbb573b74, 0x29ee1ee8, 0x1b8c1df4, 0xe6585944, 0xc0d91db5, 0xde35499c, 0x0af8af83, 0xb942f688, + 0x49c59249, 0x2232aa30, 0x6b84d667, 0xb7836911, 0xee42b2e2, 0x9e4a2f19, 0x125622b7, 0x147da1f9, 0x3a29f1f5, + 0xc46febc2, 0x10c37558, 0x39137998, 0xe42effa5, 0xa3c97a13, 0x4f48f6d4, 0x844e85e4, 0xfa8b2b0b, 0x63fed4eb, + 0x7a53f565, 0x8bd60496, 0x99a65956, 0x19878ccc, 0x0164ae49, 0x637e5d5e, 0x7f00156c, 0x91ccdc41, 0xe2662257, + 0xd3fec119, 0x77de22fa, 0x0d5e8b05, 0x7d1f7a13, 0xbda1e703, 0xe5c9d5dd, 0x69fc419f, 0x13bfedfc, 0xaae10cb6, + 0xf0744aec, 0x55a277f5, 0x78539c78, 0xecfad5d5, 0xda9e4a46, 0x6d17b9d7, 0x384e5dfc, 0x62a31052, 0x431b598d, + 0x865f90f7, 0xf1c012cb, 0x49fc2ad2, 0xe28c7397, 0x04e3d7d3, 0xc2c95dd6, 0x404b0f35, 0x1aa9d108, 0xee474d3c, + 0xb859030e, 0x58ecdbe6, 0x05cd7792, 0xa031f730, 0x172bec35, 0x0801dbeb, 0xfc42117a, 0x58a37c51, 0xf8f95d6b, + 0x5beff029, 0x2cc44095, 0x0a609a24, 0xe8a19334, 0x8906639b, 0x4a5137f5, 0x220f9cfd, 0x5e6ef29b, 0x1c963ad8, + 0xea682aaa, 0x4acd39d0, 0x5c48f2d5, 0xfc327a25, 0x2f841f49, 0xe126d9d3, 0x72659669, 0x4aa9090c, 0x162fa6ee, + 0x4158f523, 0x5e3ef6de, 0x412abdb6, 0xc732cd99, 0x6472dcc5, 0x9fd1937c, 0x983b76d9, 0xf3d15adb, 0x36c78dee, + 0x6c20e3d9, 0xe344d28f, 0xaf474be1, 0x9772052f, 0x2db0d013, 0x77558dd1, 0x92e9a135, 0xbcb94a98, 0x54e06205, + 0xee06c3db, 0x65e4940b, 0x9ae54773, 0xf9fb4f96, 0x54cfe1b9, 0x52daad88, 0x35272be4, 0xe38d35ca, 0xf9ee6af9, + 0xbd308f6e, 0xf565d2e4, 0xa9b181e2, 0x8f83fad6, 0xa887a08f, 0xc9fcadda, 0xfc7b5d21, 0xcbf6824b, 0x6e872c88, + 0x08b1cd5c, 0xb2cc2645, 0x8a8c4196, 0xbae3d250, 0x5beedea9, 0xebd0ff01, 0x6e24eea4, 0x3eff7429, 0x7e2a2653, + 0x8645bd22, 0xa6d5bda1, 0xc02f75ac, 0xed261dfc, 0x7f76ce9c, 0xcdac6906, 0x0a7eb46d, 0xdf808b77, 0xd770c4ba, + 0xcc5353dd, 0xfd2c08cc, 0x65e88519, 0x7d4898b1, 0xb490c194, 0x07755768, 0x94e3fc6c, 0x6fe2378b, 0x7bff77e9, + 0x6308fad0, 0xee74827e, 0x4b5d9087, 0xa34be938, 0xfd320a37, 0x914be728, 0x7b6854b0, 0x0a968fad, 0xc369e55f, + 0x4d8a248a, 0xdce28b63, 0xe00de9bb, 0x53f87fb0, 0x2f5e6f12, 0x5742f9cf, 0x7b5161ab, 0xf7518929, 0xc880bca6, + 0xdb6c7f23, 0x6cffae31, 0xfb882c74, 0x3fd960f1, 0x505edefc, 0x44588cb6, 0x0c430604, 0xc14c6d39, 0xbadce9c1, + 0xd426e32c, 0xeafc49c4, 0x04c2c9be, 0x1b91b9c3, 0x12507f2b, 0xcdff114d, 0x971bfe72, 0x5489c2ff, 0xe33cfc93, + 0x7f6e96d7, 0x7adc94ec, 0x62e9fe79, 0xcd617801, 0xe9381623, 0x89619707, 0x8ff24973, 0xb9682714, 0x3b608880, + 0x805f1cd5, 0x7bd6d007, 0x62f414a1, 0x74b05392, 0x8371f590, 0x86594819, 0x86933249, 0x186ee98b, 0xec1550ff, + 0x8349184b, 0xd2243d7e, 0xd0485af1, 0x67078d11, 0x6b95275d, 0xa5d737ec, 0xbd4e07c3, 0x0e5e0b26, 0x945e2cae, + 0xdd7daef1, 0x022c7a2f, 0xeb6b8cd6, 0x284bc377, 0x740f7745, 0xe921563b, 0xfd8bc566, 0x067bdcb8, 0x4fd91418, + 0xfad8141f, 0x89f23bb1, 0x67bdb7a6, 0x213ace90, 0xe9d89160, 0xc9f3fae7, 0x6a0e4865, 0x757fef91, 0x445c61eb, + 0x822ad358, 0x355071cd, 0x429247c1, 0x97458f01, 0x84f82e2e, 0x81c7bfa6, 0x5408f355, 0x0aaea394, 0x07b8916b, + 0x4a4ff2b4, 0x56d5fbec, 0xba4bd7cd, 0x2ff77edc, 0x8dbf8bdd, 0xf2c12fde, 0xfaf116c6, 0xa67f1f77, 0x3048c108, + 0x71f76e1b, 0xcf4b6a23, 0x485c8ddc, 0x2d673cb1, 0xb6932b50, 0xca03a8ad, 0xad3584f7, 0x732fbb57, 0x75204ffa, + 0xd885d06a, 0x54ce36cc, 0x891efe37, 0xc8094ce8, 0x9309638e, 0xa67999b3, 0x13f517a0, 0x07cfb9ad, 0x1e12c9e6, + 0x8a3d242c, 0x06f9e62b, 0xf7e89569, 0xdc26ab49, 0x980f87c0, 0x8a662643, 0xb6a80f25, 0x1d877eb8, 0x7f347898, + 0xd5c0dc91, 0xedb56c83, 0x31e18e3a, 0xb3b2cb8a, 0xaa025285, 0x173f5171, 0xdc6aa954, 0x35c8398e, 0xb6031c39, + 0x404bba76, 0xae4919d3, 0xbedaaf1f, 0xc37d9a54, 0x813f478e, 0xd3801619, 0xad29c1df, 0xd68e1143, 0xe8bc0c70, + 0x513ffee4, 0xc3ff5f19, 0x422fbee2, 0xc48dc0f9, 0x1e708d2f, 0xbb44b00b, 0xb052219b, 0x284c8244, 0xcd998424, + 0x44a42cad, 0xfa7faa81, 0x5c04a9e1, 0xe086efa4, 0xd43399ab, 0xfba43078, 0xd2b081df, 0x54ab7f85, 0x6965e29c, + 0x70894a65, 0x57336996, 0x1c1d1ce0, 0x80b3944f, 0x46c6202b, 0xd3e7c90b, 0x6a86d9c9, 0x30462c43, 0xd79a8db3, + 0x10af7239, 0x6979bc16, 0x659bb567, 0x8b0642fe, 0x784e473b, 0xbcf0567a, 0xe1f07337, 0x39323233, 0x0d8efbce, + 0xc763cd44, 0x37940951, 0xfa118a7f, 0xa03046db, 0x1bc13b51, 0xc24a5db5, 0xdfe9312e, 0x00220f16, 0xe5d91e1a, + 0x35438e02, 0x1d1b41f1, 0x2e483a33, 0x2e00698b, 0x4dd10585, 0xf51327a6, 0xd038ad85, 0x86070183, 0xb34f9099, + 0x27a4c553, 0x995e5f38, 0x42b36584, 0x463f6410, 0x168d3273, 0x6e0fe70a, 0xf38aee92, 0x3b1317bb, 0x1c3ee3bb, + 0x2a2bb18b, 0x32272006, 0x14a71470, 0x94244b21, 0xe9ef2ca0, 0xa20a6ecc, 0x13206cf4, 0x54606d9d, 0x02cbbbaa, + 0xaf8cfa18, 0x43e28da5, 0x76c8aaf5, 0xc4738569, 0x7bba0422, 0x17f47430, 0x1de1e536, 0xffe31fe7, 0xeea64e6d, + 0x5e0a7b75, 0xf9a6dfe8, 0x13010634, 0xab657b76, 0xf1253e34, 0xb81b0684, 0x57f76882, 0x774437b0, 0x70b736c6, + 0x8b7270d2, 0xa61f31fe, 0xad763188, 0xad5a5fda, 0x2df7b88b, 0x33d5bcb9, 0x9550f7a9, 0xaaa0229d, 0x28e88acb, + 0x9234e5e5, 0xd01965b8, 0x08027ba1, 0xd32afaa4, 0x53894061, 0x0429b755, 0xf3b82731, 0xfd767200, 0x998a6421, + 0x68d68956, 0xdd3c6cc1, 0x29a04b23, 0xf97adae1, 0xbe021251, 0x8c46b675, 0x058fa5f7, 0xe436ee1f, 0xb8276afb, + 0x74fbbbae, 0x413cd2a8, 0x6ab94340, 0xd83ed371, 0x92c96626, 0x6d9bd129, 0x930c7f6f, 0x6381390f, 0x3a8c725d, + 0x4727b343, 0xcee730bc, 0xe937929b, 0xf53c201c, 0xc163c8b7, 0x9b1d1b5f, 0xcb657bb9, 0xf900e1c3, 0x119fb088, + 0xb58a34c1, 0x4bbe3514, 0x7af97f64, 0x8f146c23, 0x9ed6cef1, 0xd2c8d79a, 0x30261411, 0x1c97bee9, 0xfaa14760, + 0x0ba71c31, 0x347a36e1, 0xb74910ff, 0x7393cd94, 0xd2afc544, 0x6c4db6f3, 0xba51e12d, 0xd3049ca2, 0x1aa92c68, + 0x266f5bfb, 0x9c2af0b4, 0x77b64f9e, 0x4fd7269b, 0x86615c7f, 0xdebdbd83, 0x8cda3c6a, 0x0a7d79aa, 0xd56c5f0a, + 0xd8c4e56e, 0x4d0a17bd, 0xe33938ea, 0x35722e8a, 0x16bb769c, 0x5fbe5d6d, 0x5aafdaaa, 0x159175ff, 0x2722a46e, + 0x4be492ee, 0xc3fcf92a, 0x13e28dff, 0x7298e2be, 0x8a5ace20, 0x9f160c99, 0x6f5015f1, 0x30b1182f, 0xfdd63e1d, + 0x48ae5d54, 0xe42af1e3, 0x8f8911dc, 0xecf5c962, 0xf06b83de, 0xf572d6b7, 0x3c13d9c4, 0x6d8a2300, 0x6bb35a10, + 0x38fb2fed, 0xc746f6f6, 0x22eb20c9, 0xda3109e8, 0xe6145eb1, 0xa3b00199, 0xc8591951, 0xe930d99f, 0x6618205e, + 0xf7534777, 0x1430e198, 0x3cf2a376, 0x75c9a111, 0x16ef3387, 0x4d279576, 0xef0ca591, 0x42dd6f81, 0xcfe32141, + 0x235394c2, 0xd3565c4d, 0x1807c7a4, 0x2c036ca3, 0xd560e9a9, 0xe1cdd7b1, 0x0c8d0e92, 0x85b8c61c, 0x41a65c9b, + 0xd6e2ed83, 0xbd2a1f05, 0xca5cc960, 0xa3324b02, 0x3197ff00, 0x8f38e69c, 0xf74c8773, 0xd677fc90, 0xdea10704, + 0x7ff0423e, 0x86854dd4, 0x49b90a88, 0xf98dfeaf, 0xee001370, 0xa0862e8c, 0xfc6f90c4, 0x93c94796, 0x66fc7336, + 0x2654161b, 0xb5c1af4d, 0xc15ca32e, 0x26ee653e, 0x16d7c542, 0xaaa6b414, 0x09a7883b, 0xd94a6986, 0x8737dcfd, + 0x97d2625a, 0x0cf1c7e0, 0x97fd0d74, 0xd925bd08, 0x67ee020b, 0x19342be5, 0xe8e828ab, 0x1d892597, 0x141d1c5c, + 0x71186b1f, 0xf897d223, 0x70ffe534, 0xf9b811e9, 0x18b2ddd7, 0x3d74efc2, 0x19df61ed, 0x4d488d0b, 0x4c09656a, + 0xc83711c2, 0x724184c1, 0xef3c6620, 0x94d97bf3, 0x0b17b7bb, 0x4d8086c6, 0x6bb11ec0, 0xd52852bd, 0xa296bc26, + 0x04dd02e9, 0x4bb86d8e, 0x153a3802, 0xd2fb89d9, 0x534a50d7, 0xa60df23f, 0x42ba4cbf, 0x4fa430d3, 0x25b3da41, + 0x004231ed, 0xc19b2616, 0x3eeb646b, 0x85b22227, 0xccdf1ab5, 0x6c2309ec, 0x8a0af86d, 0x3843bc2d, 0x6f83db6d, + 0x1565c15f, 0x3c117e2b, 0xcddaae16, 0x5cf3a105, 0xf1c766ea, 0x4f79f406, 0x2a76f1bd, 0x8aed4525, 0x9fa34ff8, + 0x3fd79236, 0xf7027e0e, 0x726288c1, 0xc00e7cc3, 0x9ccbc366, 0xd931bcea, 0x2d61be3a, 0xa3ce50b8, 0x1923d306, + 0x0d68297e, 0xfd74bd94, 0x5345914b, 0x4b3c5a51, 0x7588a424, 0x097fdc50, 0xcd6b046a, 0x53b39441, 0x03083f35, + 0x8fa6ec26, 0x7bc65a0d, 0x9c075034, 0xe0aa8749, 0x44bd00dd, 0x8f286836, 0xe69ab4ff, 0x0681a0a6, 0x2af40639, + 0x760a060d, 0x13c57db8, 0x24c26672, 0xbae060c3, 0xffb7d395, 0xd4b1f494, 0xbb1a905b, 0x65986f5b, 0x1653c1b8, + 0x5605daeb, 0xe0880f7e, 0xe218aba9, 0xd77477ed, 0x186cd7be, 0x002fa538, 0x2ccf01ea, 0x166f8a89, 0xd90ed1a3, + 0xe300ffe6, 0x3dc3ae58, 0x301ba64f, 0x345f7e34, 0x78edf844, 0x17a23ce7, 0xa4781b4d, 0xebbdb357, 0x0b960aa0, + 0xee63c1ab, 0xa4ca057f, 0x9699c00c, 0x441f6545, 0x9fa6baed, 0x635fed86, 0x9cbedc7a, 0x7dc148be, 0xa1f06d81, + 0x6118a206, 0xc6155f8c, 0x4d185e77, 0x63f8913b, 0x15621d0d, 0xef152c58, 0x9e0e93d0, 0x532cd706, 0xc6ce8ac9, + 0x5c4006ba, 0x2c6e1bcb, 0x6a907056, 0xea84dfcd, 0x6f93d855, 0x34dc4d1f, 0x4dc77b62, 0xa7d4a8b4, 0x7e00250b, + 0xfb02fa58, 0x0c2da933, 0x435fb3da, 0x82cf2875, 0xf663d1bf, 0xb44a6e45, 0x46f6918b, 0x6e731117, 0x84169048, + 0x72e621ac, 0x5419191e, 0x2ac745f8, 0x7b9de817, 0x2361581f, 0x0d468227, 0x900d77ed, 0x3e4ed9ae, 0x516f5fa5, + 0x51cfe4a9, 0x443d7e45, 0x6306fdd5, 0xdab4ea97, 0x30cd08a0, 0x9d821f6c, 0x82ba0b51, 0x96fe46c8, 0x83d49a6e, + 0xf2d08541, 0x8b6aad93, 0x474f6695, 0xedc5bb13, 0xa575361c, 0xb4557417, 0x6ecb61a3, 0x84f7e60c, 0x4a0f5163, + 0x8cdcb3d1, 0xad9124c0, 0x890c3d9e, 0xbf169b3c, 0x720e7602, 0xf1fa54e1, 0x6b818d42, 0x44d8e955, 0x86664bc6, + 0x90377c22, 0x22382fbe, 0xccf418c5, 0xf838c0dc, 0x946b1d66, 0xc11be40a, 0x7a151938, 0xdc4336c2, 0x28c43eb2, + 0xc1f12298, 0x98cd9669, 0x166880cb, 0x84cffc47, 0x37c84d89, 0x1889a4cd, 0xdf2ce016, 0xded06116, 0xfae867c5, + 0x8d23d06b, 0x827dacf8, 0xfd11d25f, 0x68485ddb, 0xed506883, 0x43c5e555, 0x0330a16f, 0x3f7576af, 0x5f70c716, + 0xf298b8ce, 0x9e1df62a, 0x46fa9d88, 0xb06e68d0, 0xc3803412, 0xe8ba5d5d, 0x615d8c71, 0x1b0d6c3c, 0xb638706b, + 0x187d6983, 0x0e33f64f, 0xd9dd7778, 0x12410a8a, 0xcef7eda5, 0xfe74e21e, 0x60b70fc5, 0x8ed94fa2, 0x6cfde259, + 0x8058b411, 0x1ca93807, 0x19625c5a, 0x34215cec, 0x165baddc, 0x0ab44f83, 0xa6363e74, 0x3f7a766a, 0xdd702a61, + 0x3d0ca687, 0xd0909c3e, 0xdc7f7712, 0x3d9001ea, 0xc5d19495, 0x8017b1f6, 0x65da0eed, 0x0d030d48, 0x998c10e6, + 0x06f1c97d, 0x35204b05, 0x1c0da754, 0x777b48fe, 0x01521640, 0x203bfb59, 0x25e83cfa, 0xa3d40b91, 0xf396bd60, + 0x093880c7, 0xd5a77950, 0xe06ddcac, 0x87936f25, 0x12c7d991, 0x16103a0f, 0x4a1ee98c, 0xf70e1c84, 0x2f3f894e, + 0x176c0300, 0x34c08cc6, 0x89eff014, 0xb7d5666e, 0xf7636a27, 0x128ece3c, 0x71e7ddb6, 0x1070d4aa, 0x2dab9a05, + 0x3cdc279b, 0xe88781cc, 0x2771abc8, 0xf01d6e74, 0xe8cc296b, 0xeaafe927, 0xa3b3e542, 0x872acfc7, 0x4033a228, + 0xa922a98c, 0x82b18f3b, 0x6d5efbb5, 0x31d13a83, 0x6c4a1b1e, 0x7d5df44f, 0x539dfd5d, 0xda1e186b, 0x60f6948d, + 0xb4c2bb13, 0xa903a2c4, 0x76a5595b, 0xb85fc368, 0x87e3c57c, 0xeec8ee07, 0x39f42e4b, 0xdc13d659, 0x03ac1daa, + 0x123bab9d, 0x7789dec0, 0x5dba0ba3, 0xcee72d9f, 0xea4aa38f, 0x315633a7, 0xff276fb0, 0x0468ef67, 0x7fb82124, + 0xeb586ed5, 0xcdadda70, 0xb37e12d8, 0xe4411b87, 0xc740e4f5, 0x41ca5e11, 0x8e54997b, 0x023d8b2c, 0xda4cfb4e, + 0xee115485, 0xf9a61a29, 0x98aefaa4, 0x2523432a, 0xcfa165ae, 0xc2b7231b, 0x903e24dd, 0x51e1eadc, 0xa3c13481, + 0x706e7ca4, 0x91b49529, 0x9054a71c, 0x233aba6b, 0x71f936a9, 0xa4d9dd36, 0x28e1ac78, 0x3a11d6aa, 0x64d29cf6, + 0x13b8ab63, 0x5d79238c, 0xf32a4dc7, 0x0727decf, 0x28a07a6b, 0x93c87398, 0x3f38edc0, 0xa55183ee, 0x9d16dbcf, + 0x4f036f09, 0x18204e85, 0xbec37c86, 0xf9495b14, 0xea5f2985, 0xde66be29, 0xc2904053, 0x33b3b123, 0x74a7e8d6, + 0x4eb18918, 0xe09cee53, 0x0e78167c, 0xe178d616, 0x4e4c4040, 0x58f65173, 0x5f75567d, 0x93c49a0a, 0x85841b06, + 0x0a5d96ca, 0x334f19a1, 0xefbee2ae, 0x3bb40e65, 0x0f423c37, 0x4ee85403, 0xf808babd, 0xa0fd3afb, 0x8c41724c, + 0xab131c43, 0x3b37c1b6, 0x0def72d9, 0xf246dcc8, 0xfc882e51, 0x410eee00, 0x74f3890c, 0xa1173d0a, 0x3591d9c1, + 0x178b1342, 0xdbdaac95, 0x803d14c8, 0x2f85d66f, 0x2232e606, 0x5ff7e268, 0x48cd827a, 0x8efccf0b, 0xa2764d6a, + 0xadfd84a5, 0x00cf4e81, 0xebc1dd35, 0x507b20fa, 0xc83b94b8, 0x14f827be, 0x674b5b0c, 0xdf509dcf, 0x22fb0f6a, + 0xf57e3d4c, 0x9b0ac7f8, 0x788cda17, 0xe4e2d74f, 0xea6bf365, 0xfd81a21c, 0x9b0cc7c7, 0x528abb76, 0x85afe6e5, + 0x467f59ef, 0x176345c9, 0x01aeb8ec, 0x0ac99080, 0xcef5c1a2, 0x35d3d8c3, 0xc594045a, 0x0c24212e, 0x64f2bfe8, + 0x28c4ad41, 0x1d9b420a, 0xf2f3384a, 0x6f31d111, 0x0cf933ce, 0x2c02664d, 0x410bb5a8, 0xd53f3a9d, 0x41026d01, + 0x413542fe, 0x04ec0bfe, 0xa93a938c, 0x52d0f93e, 0x85be523d, 0x0548edbd, 0xb39e120a, 0xdefda9ad, 0xf786edf3, + 0xada97dc7, 0x2881915c, 0x31b6bd07, 0x562eadf5, 0x5f99c623, 0x44aa87ce, 0x2ce0fcad, 0xa90e0761, 0x26a979d7, + 0x59c707da, 0xd06da796, 0xb5e3065d, 0x3072d897, 0x210a5209, 0xc3ee212b, 0xf5477368, 0x0aff322a, 0x47005eb9, + 0x52e83ba8, 0xad7a9b2b, 0x6757b753, 0xabf47686, 0x58eca24d, 0x0331d06a, 0xb6c34c97, 0x4d62de86, 0x026c13e1, + 0x6df33ac8, 0xc7781674, 0xdfe45142, 0x2d2fa855, 0x78d27b19, 0xdcf5d3fd, 0xf74ca47a, 0xfeed03e0, 0x9c2c28fc, + 0xc130aa4f, 0x022fa67f, 0xe0c298ea, 0x5eacafeb, 0xb4622b7c, 0x88bc7c56, 0x9715968d, 0xe5501291, 0xea408c5b, + 0xf89242d0, 0xb447000b, 0xa5ed47de, 0x7086510c, 0xdcddc6c8, 0xe952bf1b, 0x53783a22, 0xe01cf03e, 0x3c1af3e8, + 0xc41733a7, 0xa6a90745, 0xef737442, 0xe1a52998, 0x119f3b25, 0xc175fdc8, 0x8a6e92ce, 0xfd38376a, 0xac8c3bd0, + 0x1e92971b, 0x6972bb0f, 0xd0bbef0e, 0x15ffb52c, 0xfbb1387e, 0x68ca1382, 0x2d00e29d, 0xcca4821f, 0x75947a4c, + 0x06e2ffb6, 0x09ab8d3e, 0x5428bc20, 0xfece9022, 0x32244d94, 0x19e7e9b3, 0x829e3deb, 0x2fd89bd7, 0x999185ec, + 0xb509be64, 0xbf8eee61, 0xaca1a0de, 0xf58ccea1, 0x3574251b, 0x1b9ed91f, 0xdefbbc92, 0x985d7074, 0xec5ac844, + 0x9fea6ec0, 0x02772d38, 0xf5661c24, 0xbbb2029e, 0xff1acac7, 0xbaff5e32, 0x1d08869f, 0xde45d178, 0xfb9aa8fa, + 0x2e1fded8, 0x7954ef8b, 0x8c46e3fc, 0x3f65f051, 0xc19f02ea, 0x3dcc6ef8, 0xab180ecb, 0x301e0be7, 0x4a237014, + 0xee8cda26, 0xa3cafe2b, 0xe356d56c, 0x275ca8c4, 0xae6bd8d1, 0x2447e93e, 0x363996cd, 0xa9fa08b2, 0x3f8504e7, + 0xe7efabb1, 0x00ef7ded, 0x86357a05, 0x9c31a1a8, 0x6b75a8e7, 0x6d32df9b, 0x05e20013, 0xc0bdb066, 0xe79ce531, + 0x49734f2d, 0x493c237b, 0x526d2c7b, 0x1f6769ce, 0x1eb8a6aa, 0x85792754, 0xd30cf571, 0x9b8bce2e, 0xae17cf7e, + 0xc06860ab, 0x384d7760, 0xfc22f580, 0xb1911555, 0x8cc3504c, 0x7a6dfb12, 0xb6ac8ea2, 0x9540b403, 0x5f9c0a11, + 0xc9e5502b, 0x0cbb80c9, 0x33396395, 0xc071d3bf, 0x14db2e40, 0x8888bacf, 0x5e2406f3, 0x81337f60, 0xf0a2f854, + 0xb2549d2f, 0xd80a2ac2, 0x901a768f, 0xf43c9495, 0x7c52acc7, 0xa27df639, 0x0aee6e34, 0x5610a037, 0xa8be06a8, + 0xc0a419c7, 0xdbdfc2f8, 0xa35c5506, 0xeb3a1489, 0x2e1bc0e2, 0x55ace85e, 0x17ff5559, 0xbabe86e5, 0x92232fb7, + 0xfd23a956, 0x7efa2a66, 0x265b9085, 0x731d6cc5, 0x41d2416d, 0x8a8bbbf4, 0x3eab1fe7, 0xc4129b46, 0xbf84be46, + 0x8e535093, 0x7aaf0ba8, 0x04ffda67, 0xd477905d, 0xe5ea27f1, 0xdbb1beed, 0xcc18745f, 0x61be9320, 0x6cd8d5ce, + 0xb9d2ea34, 0x64600df6, 0xb0f750d0, 0x063eff47, 0xb87cd72d, 0x8ea821bd, 0xe262fb60, 0x82fc6f07, 0x336ae518, + 0x2e15e625, 0xffc24baf, 0x2a92fa83, 0x8d096b5a, 0x5e0a819f, 0x91462f1d, 0x813d36b4, 0x0dfafc44, 0x336d1c0a, + 0xac85ccd4, 0x259ec127, 0xec944b04, 0x3f1d28a8, 0xb2eca469, 0x9b36873b, 0x460b00fa, 0x6cf9878e, 0x07959e18, + 0x807d6d8d, 0xe171fd33, 0xee2c2d4f, 0x9c6bef8a, 0x2985439d, 0xa7c3d46e, 0xc3854843, 0x06da3591, 0x18def60a, + 0x3269a1eb, 0xe98cc00e, 0x318faffe, 0x9cfccdc2, 0x7415a0f8, 0x8f53a1c0, 0xe3ddaf89, 0xc57be40b, 0xdb54e71c, + 0xf06515d0, 0x8403d476, 0x87c1415c, 0x25216032, 0xf676e758, 0xf46cd116, 0x70dde003, 0x0e610131, 0x92260e89, + 0xd69fd79f, 0x51d11438, 0x3aaad517, 0xaf443748, 0xffe90976, 0xd8de8abf, 0x0de68a96, 0x6aa20495, 0xc2dfc02f, + 0x5b733ac5, 0x65163218, 0xc3003e14, 0xa6f200da, 0x053287dc, 0x25b7ae62, 0x052fc2ff, 0x4847fc19, 0xa0e560ee, + 0xcaf44edc, 0xa2658249, 0xbd85f71b, 0x8c438cce, 0x46815c41, 0xd07fb5f9, 0x61ceecd0, 0x9289838b, 0x8d88d3ef, + 0x87b8695a, 0xa9e63e56, 0x16716eb5, 0x52cc0e72, 0x8b5ea058, 0x8f2bf739, 0xeafee539, 0x0dfec59d, 0xc6bc22af, + 0x89aab9c4, 0x7b1ff956, 0x8f804144, 0xd1671c9d, 0x599ef42d, 0xb2385ca0, 0xdee50170, 0xdc6a6285, 0x976e393b, + 0x73a889ee, 0xb1ecfda6, 0x9eef5b52, 0xc6b7b2a4, 0x680e28f7, 0xde0d0c74, 0x3636bd88, 0x0a7a643f, 0xf4042f15, + 0x9475f84c, 0x04b6675f, 0x7c179c77, 0x24eda6f5, 0x386ee567, 0x8593d5b1, 0xe315664a, 0x0f143deb, 0xe766c503, + 0x940b9002, 0xb4986f13, 0xfb95a1df, 0xaf68fd7c, 0x4eb016a6, 0x43767999, 0xe326ec22, 0xb5ab2bbb, 0x58897cac, + 0x2eb9b599, 0x6ff46028, 0xdb025b26, 0xbce90f0c, 0xd362cca8, 0xce99d33e, 0xbe18c85f, 0x245d9e77, 0xbf5d1935, + 0x7371fbf4, 0x7907595d, 0xe4fa4307, 0xcf94f929, 0x0206efb2, 0x7ba3e6a9, 0x8de799e7, 0x09c0ac59, 0x9915b8b4, + 0xaab86e58, 0x41d533bc, 0x5fc5f0a9, 0x21fb2827, 0x8f2bf72a, 0x7d0d2161, 0x202fab67, 0x4bd169e4, 0x37dfdd57, + 0x26ba3a55, 0xbecfb91c, 0xd8dafb2c, 0x38afb9bf, 0xc936f2c6, 0x4fc1a008, 0x1c57375f, 0x5f83d3f5, 0xc1b5819d, + 0xb21271b8, 0xa0493baa, 0xda46e79a, 0xb5d6f724, 0xaf247ef9, 0x0e2210dc, 0x9a178dd7, 0x2c66e199, 0x3d94e075, + 0x03e60148, 0xe3208a00, 0xc77fbbad, 0xae7ad547, 0x0937f817, 0x01fb4643, 0x6123b98c, 0xce2192b0, 0x3fcffd08, + 0x42b6d7a3, 0x899a6b01, 0x09905f7b, 0x15a303bc, 0xbfbf88e2, 0xfa062d7b, 0xf6d5d699, 0x216f6f56, 0xcee98af1, + 0x2242f881, 0xb613defd, 0x3ca1a9c2, 0x1d05be3f, 0x9ece8d3c, 0x2cc070b1, 0x6caf3274, 0x0c46851b, 0xe28d59a7, + 0x1f4af6a6, 0xb71c38f3, 0x6cb38ad3, 0x4450f01e, 0x24ac4256, 0x698c0285, 0xe7d968a9, 0xd1613c58, 0x3e41127e, + 0xa5623490, 0x3b0636c0, 0x2f766d95, 0x24a75e01, 0x443732b2, 0x7169a89b, 0x32ad22be, 0xaea81cd4, 0xbed9eebf, + 0xd69bccb4, 0x469f4ffe, 0xdebe0d7c, 0x9803f37b, 0x54128341, 0x12b15873, 0x97cefcee, 0x4733ac2e, 0x5d0cdc73, + 0x2c9e8e92, 0xc3473526, 0x460ac8cb, 0x2b359e4c, 0x3c2caf58, 0x2f1f4f47, 0xa98d20f2, 0x75b85667, 0x8a3d6c1e, + 0x8379a780, 0x13f5ba3b, 0xbf42ee10, 0x4a12beca, 0xf34ea3d7, 0x3dfe749d, 0x9c5170ad, 0xee189d13, 0xae6ff269, + 0xd580c8bb, 0xb7f98032, 0xa4f919a8, 0xe0065454, 0xe36b998e, 0x52922b76, 0xdd1f05c0, 0x21865b4d, 0xdae82d7c, + 0x9e1e03ac, 0xda8e373c, 0x2ada856c, 0x8bb27220, 0x59880699, 0x65179fbf, 0xbad07691, 0xd1234227, 0xc7436630, + 0xf42c41a5, 0x4895fd1f, 0xcdc2af11, 0x583b96c4, 0x50133261, 0xecd91731, 0x80260cb0, 0x5282916f, 0x9ef548ed, + 0xcb6f0cd5, 0xccdf045d, 0x505d754a, 0xa59ed9d9, 0x1aaa273f, 0x57f64f2d, 0x10acc4be, 0x4cd09a18, 0xd2656e8f, + 0xba1a42a7, 0xcd6d84c6, 0x1c4970fc, 0x967aec9b, 0x9084706b, 0xe2045835, 0xa6f87e00, 0xf686989f, 0x6ee12411, + 0xf041b481, 0xba4272c4, 0xc5eba89c, 0x2da87e67, 0xa01146cd, 0x8aa3cd1b, 0x50c003f0, 0x77e8adc6, 0xa5fd7936, + 0x6c141938, 0x10202f76, 0xb8f0e650, 0xb1ee7973, 0x1985293c, 0x4f902b5c, 0x43ec3bbe, 0x4ac63675, 0xcafbe327, + 0xc41ba188, 0xbffd8ce4, 0x25cccba3, 0x2488b869, 0xf80a6aba, 0x6495b217, 0xb30c4004, 0x8969cb31, 0xd09f3531, + 0x2fc6dea2, 0x225a00ad, 0x0aeac1c0, 0xbd8df1fd, 0xf330b114, 0x4119828a, 0xeed30df9, 0xda9bce74, 0x9999d603, + 0x2099d44b, 0x206b4fe8, 0xd0820e3c, 0xc4d0f49c, 0xce5ffc56, 0xcbb5a4c6, 0xa8dbaf51, 0x726f0b5c, 0xa34b2da9, + 0x05c37b69, 0x0eee7d00, 0x25451f33, 0x74562e93, 0x8742f821, 0x76d7d99d, 0x7a406743, 0x5ec72ccd, 0x6955940c, + 0xcf05b3bd, 0x7e44ecea, 0xf8aa988a, 0xb2d64d59, 0xb1109fe3, 0xc3ee274d, 0x9d8eaf68, 0xf51213e8, 0xe173ba2c, + 0x82d5fb37, 0x602e2f31, 0x09d3c258, 0x7de1e7c3, 0xe30b8c21, 0x3a6679c1, 0x8b5a8366, 0x8ce6e0ed, 0x06c009b3, + 0x6b0abb4f, 0x34a11af5, 0x203117ff, 0x090c9b49, 0xc62a6882, 0x35656bdb, 0x3e16c550, 0xec4acb03, 0x306e82ca, + 0xf2cbf0ab, 0x0403efa5, 0x2584b92c, 0x22b9c44b, 0xe6cadd83, 0xafe60cc0, 0x6786feda, 0x9a5e8e6b, 0x7bc6d641, + 0xc57a108f, 0xce77748c, 0x055f4452, 0xe40bd882, 0x3e0b24a4, 0xc27bc480, 0xdc04ee0d, 0x28d96211, 0x00b1122b, + 0x2cfc49df, 0xc101a256, 0x0c1dab26, 0xc94c9eed, 0xadf60651, 0x163743dd, 0xe6691b27, 0xcc623c4c, 0x0256c6bb, + 0x12471d05, 0x3a07c8d0, 0x56eb0fba, 0x7d03150f, 0x4b04b9db, 0x725a2251, 0x25b09e0c, 0x4cb466e0, 0x38daba83, + 0x70832213, 0xbbb35999, 0x58884a7c, 0x01e9f367, 0x0e3c3a64, 0xaf957a63, 0x251cbd06, 0x3b12ddb0, 0x0b9ea786, + 0x163ef441, 0x057f702b, 0x3400fadc, 0xb122a5ec, 0xf1340564, 0xcca35c92, 0x69dc9493, 0x34fdfade, 0x016b07b4, + 0x9ad8ba4c, 0x1fa72b25, 0x154c8684, 0xd6f2ec4a, 0x1a48b8d9, 0x5d9ae004, 0x1ef49fcc, 0x8f73b724, 0xb5b59cf2, + 0x35b671d4, 0x8e2714be, 0x8a830694, 0xd12e2760, 0xcd9702b3, 0x675abd55, 0x426a472a, 0x5a90be16, 0x88434941, + 0x9bc59d79, 0x809f7e27, 0xd636f6ab, 0x61235810, 0x39367e05, 0x74bf224c, 0xa9191a98, 0xa60fa1ba, 0x1d0d8a0b, + 0x9db73cf1, 0xaf87fe9f, 0x19063639, 0xed218a0f, 0x82bb93dd, 0x42148a35, 0xe207fdd6, 0x9741efd5, 0xd42a115d, + 0x2b3ec4e9, 0xba5bc18e, 0x4ed01e76, 0x66250c8f, 0x647f61f4, 0xf4fee8b9, 0xf50cac0c, 0x7538caa8, 0xfb32e57f, + 0x84bc9b2a, 0x36b4c72b, 0xef05a44a, 0xdae0af19, 0xbe87ada7, 0xe621c9c9, 0x33693fd0, 0x2fda478b, 0x91596f49, + 0x70b5041b, 0x6b7d4426, 0xaa354c42, 0xab323da4, 0xaec4ed43, 0xcd27b6df, 0xf050760b, 0x393b5bbe, 0x4ad47a73, + 0x936a357f, 0x7ae5c9d1, 0x5b436a3d, 0x4360ef8a, 0x941c5db7, 0x82f75b55, 0xc03bced9, 0x08999305, 0xd247caf1, + 0xd5b079ea, 0x7ed786ab, 0xf644f0b7, 0x915ccaa7, 0xabc7cc4d, 0x05e4cc2b, 0xf59e3f01, 0xe319afd6, 0x0558be86, + 0xb38de8cd, 0x4d72f36d, 0xb050877b, 0xa79c9dd5, 0xa1c6e4d3, 0xd7b0f1b6, 0xe366d998, 0x3205ab7d, 0xc3bb58d1, + 0xa2b3cb9d, 0x43d9cf9c, 0xcad86c46, 0xb75e3d31, 0x98a10f80, 0x6ab0ffc6, 0x4a45f958, 0xa915164c, 0xf17ddfed, + 0x5a223f26, 0xcd01cdac, 0xab6e5cda, 0x0d76896e, 0x6e67f1fb, 0x2f0cf10d, 0x6780b077, 0xed43ff8c, 0xa8c6fc8c, + 0x99afe121, 0xbcb3f216, 0x9666cce6, 0x4580aef9, 0xba8c131c, 0x7adfe0f3, 0x1f557951, 0x419d1da6, 0xaddb9044, + 0x27dafd09, 0x413a8bc2, 0xbfb64f22, 0xe288d036, 0x138de8d8, 0xf960301c, 0x3ec6b646, 0xfc68b48e, 0xe2afa893, + 0x1e4a9e31, 0x8bb3a108, 0x67dfd0a2, 0x8bb31e8f, 0x90601a46, 0x984bf2d8, 0x82669037, 0x93a1b264, 0xccf35911, + 0x107240b8, 0x0fcfb435, 0x33547dbc, 0x105e8f56, 0xdc8d07fe, 0xe6d320f9, 0x19c3b3c5, 0xd5563912, 0x46fb9d41, + 0xd6c30403, 0x0f39b980, 0xa62c6889, 0x68d9bbaa, 0xa3d16444, 0x911fa4ac, 0x104349bd, 0x24ff6402, 0x9f760b5f, + 0xb69a307e, 0xa0189a29, 0x3309536c, 0x690b739d, 0xb765e9e1, 0x47bdaf4d, 0xc279f6e0, 0xafe394f3, 0xb3ea6b58, + 0x9377a868, 0x7872ffee, 0x523432c9, 0x53a76eed, 0x26b99289, 0x453e78f2, 0x16e80027, 0x0875e2dc, 0xf3963da2, + 0x2fa46c61, 0x5e52a8ce, 0x12cbef05, 0x82abb041, 0x8dba534f, 0x595635b6, 0xe703bd12, 0xbc9e04cb, 0xfd1bacb7, + 0xd0c1e664, 0xefe00090, 0xd35600e2, 0xa1a01efb, 0x59738496, 0x3015bc63, 0x5bf4fdb9, 0x36801b49, 0xd0c91562, + 0xae14f82f, 0xc6069e4c, 0xc95f4ff4, 0x7777a39e, 0x637d3d98, 0x955bafa2, 0x8058c9b0, 0x06814113, 0x309d9a35, + 0x5d5a5cef, 0xcba0c35c, 0x68c54cf2, 0xf8329a4d, 0xc2e71fc6, 0x43e955db, 0x1c7fdaea, 0x850e07ba, 0x948bf8b2, + 0x4ebdbcd0, 0xc73e7fa9, 0x7221ad96, 0x947bd9eb, 0x8197c88c, 0x69c200eb, 0xbdc094e0, 0x89b9a4ea, 0x610e7f24, + 0x20b28732, 0x5f755686, 0xdc4dce14, 0x5b1b88cb, 0xf9c4cee1, 0xda0cfbc4, 0xbd977705, 0xf2158da5, 0xb128bded, + 0x04ba3999, 0xf2ec978e, 0x2b4faa82, 0x69094a77, 0x651fe6c1, 0x9f8cbabe, 0x28dad03e, 0xe7f98b85, 0x9a9971bc, + 0x3d09767d, 0xfbca3f8e, 0x75925391, 0x313d8156, 0x1476bd4b, 0xea7bcbfe, 0x453220b7, 0x7e0b2525, 0x6b7ce7d0, + 0x30add434, 0xf429999e, 0xfc8f562a, 0x8c2975ea, 0x7abc4fc2, 0x1aa4bd35, 0x2f84d99b, 0xcd4a8a76, 0xc2608c16, + 0xc94841e0, 0x00d3279c, 0xa765040b, 0x06432f26, 0x10359a54, 0x08b1f5cc, 0xfd38c2ea, 0x5259897d, 0x1356f40e, + 0x8d8553c0, 0x605810fb, 0x2ab911e5, 0x08696317, 0x650bbb25, 0x64fc73b0, 0xfbf18c96, 0xad5845bb, 0x46c15fb6, + 0x9f340d33, 0x951a8b1c, 0x49e93535, 0x2b83b2fb, 0x9993e8a4, 0x34daf845, 0x16121678, 0xfdb4ec33, 0x4b0e2476, + 0x03fe549d, 0x49a361f9, 0xc78cf0db, 0x5c04ccc6, 0x51f3350d, 0xebd59857, 0x68167361, 0x3375cee5, 0xbe0706dc, + 0x9114c3dc, 0xf8807408, 0xcb88c89b, 0xa0682e1f, 0x80217788, 0xfcf96ec7, 0x6be76e6f, 0xd50c0fb2, 0x696c5f54, + 0xcfa65fbc, 0x9308cb0a, 0x36717b06, 0x7f591666, 0x2888184f, 0xf07a342a, 0xd7f3be51, 0x95fe7fca, 0xea53a152, + 0x505637c9, 0xe1b0ea68, 0x7bf049ca, 0xb65a893a, 0xfbf06c7b, 0xe18f0ecb, 0x93c03900, 0x1b5c0435, 0x7844ca52, + 0x05688477, 0x6d42e7ff, 0xac33c911, 0x63f4b842, 0xccb7bad6, 0xec3f957f, 0x8852fdfd, 0x0ba5de95, 0x41438d07, + 0xcc1d3ce0, 0x7131eec0, 0xca715849, 0x58ac56bb, 0xf1437da1, 0xf9268b3b, 0xfcdc6254, 0x7d25f2be, 0x77adc912, + 0x7e12d43f, 0x778df631, 0x23c8ea81, 0xc7c8839c, 0xe397cebf, 0x5f63cc8e, 0x79168a66, 0xa571f8c0, 0x1cdc963e, + 0xf23c18de, 0x4159b3b8, 0x93a631f1, 0xb2301625, 0x604d4b24, 0x515ec858, 0x051e4f61, 0xb5255ec7, 0xedcafe17, + 0x0c5b2fef, 0x314fda81, 0x02c418a7, 0xdbb576a8, 0x5eb5e1bf, 0x01182d2a, 0x483f14a4, 0x343fa67c, 0x2a45f974, + 0x31468011, 0xfe88e3f9, 0xdf79c9cd, 0xb8ab6bd3, 0xb6e85f09, 0x20425f2f, 0x83fba877, 0xd171140c, 0xe8738a5c, + 0xf2460115, 0x1a0708fd, 0xb841d952, 0x5668d715, 0x13a3b09f, 0xa2e280af, 0x262d95db, 0x09528a9a, 0x2c8ee10c, + 0x8e5c8d9f, 0xefd1c038, 0x27af8753, 0xd1dc942f, 0x5649d8a6, 0x612504db, 0xaecb301f, 0x98458b05, 0xb28ef831, + 0xdc92414a, 0x1f377173, 0x8ef9779e, 0x906040e0, 0xd6db4ec0, 0x21c19db7, 0x62591a07, 0xe711b1dc, 0xf90f8575, + 0x901e14cd, 0x960c09ed, 0xa4eee650, 0x503d762b, 0xec76f352, 0x7a4f0792, 0xdb342ae7, 0xb35a36e1, 0x6407b767, + 0x07b53ca4, 0xf8014922, 0xe2b18354, 0x49f19423, 0xc3ba6d60, 0xa14340dd, 0x30271933, 0x3f53910c, 0xae747e55, + 0x98902158, 0x9f827f6d, 0x76ae6242, 0xac725ee2, 0x893c025e, 0xa63ca569, 0xb798f9d9, 0xb9224cca, 0xe0e934c1, + 0x26522ecd, 0x1768352e, 0x136e98a9, 0x06990b4f, 0xa51fd2d9, 0xaf5233aa, 0xb409ca0d, 0x8da10490, 0x9a92f748, + 0xfaa19c85, 0xf8a592ce, 0xbda798a4, 0x638be21e, 0x7a68243d, 0x4f31e849, 0x9825c810, 0xdcaa0210, 0x7f1ab343, + 0xe2aed4c1, 0xeb2958ce, 0x6b2056a2, 0xcb050e54, 0x1594bea0, 0x1b081048, 0xb7a518bd, 0x3d6914b2, 0xca9797b5, + 0xe5e79c98, 0x31f43fff, 0xf11ff758, 0x5e9bcaa0, 0x4c4c6c2a, 0x0ad211ec, 0x08951766, 0x08276b7c, 0xede16f75, + 0x420a6e57, 0x6d91eb4b, 0xf3a0909e, 0xb5090c65, 0x1fdcdbbf, 0x6dc13359, 0xd09a4b0e, 0xba818018, 0x0eb3facf, + 0x77535c27, 0x45355458, 0x1e035e04, 0x97d4e0bd, 0x6e186916, 0xff958dc4, 0x95bfdf93, 0xa97f2d5c, 0x7015b8b9, + 0xa91836f0, 0x4cc7829e, 0x6e00dd38, 0xc1753ca4, 0x3061d15a, 0xe0e15f8c, 0xb494bafd, 0x566321a9, 0xe1da84f5, + 0x5ba20d30, 0x87ce2176, 0x85844ebf, 0xc9310a42, 0xa08ad896, 0xc680d594, 0x591618d3, 0x83a4b0d4, 0x3d29edaa, + 0xa2c49dd6, 0xabd27a9a, 0xbbc8b5f5, 0x4cebab0a, 0x2baf9196, 0xd6cc052f, 0x7aa6bf76, 0x94fab615, 0x73e880a6, + 0x6a76bb2f, 0x34cd4281, 0x052664a8, 0xbf809d61, 0x4f694a14, 0xcf612a9d, 0x25c81ce7, 0x4a748695, 0x537876be, + 0x22053552, 0x04301521, 0xc6ec48b2, 0x54868952, 0x85c559d6, 0x62d5c19f, 0x3c8eb2a5, 0x3465dabc, 0x7dd38962, + 0x1398d744, 0x851fdbd3, 0xeeeca8fe, 0x216e4da5, 0xa12cc7e7, 0xf9173f62, 0x690aab66, 0xd79b9b6a, 0x782a849b, + 0x14135aae, 0x2cefa5cf, 0xc71accc6, 0xa27efd1d, 0xc90203e6, 0x1aa07be6, 0x61efe573, 0x1669fcb5, 0x36c352cc, + 0xc62432b6, 0xfc4dd73e, 0xdb322c31, 0x6a490e2d, 0x84eaf745, 0xe68955b5, 0x1d0f84b9, 0xe311a123, 0x5f65a2cb, + 0x573fb3c6, 0x806d49d7, 0x8c29e82c, 0x944d278b, 0xad17ca13, 0xc28dbfb5, 0xa9058ee1, 0x623976f7, 0xa4650d0b, + 0xcf684767, 0xb5901f1a, 0x750aa305, 0xead2a421, 0x3d621c15, 0xfe32023a, 0x00490cbd, 0x3c1ffeaa, 0x006c2772, + 0x9be8b9da, 0x91f44d4f, 0x662c8a97, 0x0acbbe18, 0xe81225f9, 0x0bf14ab7, 0x84f68466, 0x1a009d10, 0x637b10cc, + 0x33267881, 0x594e6c49, 0x946d3b46, 0x7f7568fc, 0xca9c2662, 0xc1e5440a, 0xe4451def, 0xc8d4415c, 0xeb09c8da, + 0xe9fa3495, 0xc6d90bf0, 0xc22f549d, 0x38f8533b, 0x91d9b8be, 0x0b0530af, 0x22fad1af, 0x47f41cc8, 0xd6377b72, + 0xe87b4e07, 0x8a5f3842, 0x4f080060, 0x820e9307, 0x45d90ad6, 0x7bcbc653, 0x316eee99, 0x8e6abefd, 0x279d9d44, + 0x8c450ea2, 0x0a4f99f1, 0x1f9c9dec, 0x80c1b1c6, 0x11edce85, 0x583787d1, 0xe7e06dd5, 0xf3a3e420, 0x186df41b, + 0x72edb1b8, 0x2bca18c3, 0xb4c292f6, 0xd31cdf36, 0x5b47465b, 0x2edc1d26, 0x068e2de4, 0x7bff009c, 0x285e3a20, + 0x098d4881, 0xa948722f, 0x52354f16, 0x21d5b20d, 0x1c3236bd, 0x0a79785c, 0xbbfa1b99, 0x01448139, 0xfeff03b4, + 0x333931c6, 0xbcb21df4, 0xc4d30118, 0x8f38a438, 0xef8598e0, 0x825b7c30, 0x0ae0994e, 0xabe54dd4, 0x82dbda10, + 0xf179dfcc, 0x870505bc, 0x151180e3, 0xeb39c429, 0x593d94ab, 0xd2097437, 0x081f1890, 0x194c53bf, 0xe2ed211c, + 0xdc9eaad0, 0x138b1c38, 0x0f1ef7fa, 0x007df4f0, 0x1b56c716, 0xdea94cf2, 0x82d2d9dc, 0x24608b4c, 0x41b03699, + 0x00df3384, 0x57d647b2, 0xf7e949ed, 0x17570d8f, 0x059b26f8, 0x7304071b, 0x505974d1, 0x376b3ffc, 0x7b7cbed1, + 0xb33ecbb5, 0x83d32209, 0x0ba726b2, 0xb7ddc418, 0xb31fdc6c, 0xcd5ab25c, 0x454e720b, 0x08fe5ac7, 0x6807bcbd, + 0x8c7befaf, 0x5024ed87, 0x9f243747, 0xbad115f8, 0xc76c5dc2, 0x6ffc880d, 0x199872f7, 0x88fa3d35, 0x6fc2df82, + 0x96f203a0, 0x145e7ba5, 0xc23ed683, 0x9a8013bb, 0xff350014, 0x51b4a658, 0x76f65e03, 0x0f1731d6, 0x018acd77, + 0x9bd87402, 0x008d9544, 0xb8d3a29f, 0x4ef88ac0, 0x1d59d394, 0x13717ee1, 0xeeb08d95, 0xb08e2009, 0xc1a9aee3, + 0xa5d54182, 0x578b030a, 0x289dfab0, 0xbb01813c, 0xbc8f3908, 0x1797d2f3, 0xbe399f47, 0x24536829, 0x931a0aba, + 0xc4fb6e78, 0xdc2f6f09, 0x5b400c32, 0x3332d985, 0x1154c11f, 0x9e4fda9d, 0x14ba579f, 0xca8bf902, 0x6f52804a, + 0x92c28d7b, 0xd811774b, 0x065c4132, 0xb88574fc, 0x2861c523, 0x582b1866, 0x428f5dc2, 0xad2ddc4d, 0xa41c4085, + 0x17a8092e, 0x3466aa60, 0xad7f1f3b, 0xa4c03ccb, 0x61a5f758, 0x5382c319, 0xa3a6dd81, 0x9c9dae9d, 0x7fba4b26, + 0x3ad0d10d, 0xd7064b08, 0xd0421f9b, 0xae5d9468, 0x6c2b6c8d, 0x9a82bdd3, 0x3600fbd9, 0x3dd9410d, 0xf2b5f721, + 0x5514bf64, 0x4f29c052, 0x48221978, 0x4b743f9a, 0xdbff6cf8, 0xe371f36f, 0xb6c2840b, 0x35ae13d9, 0x3c6181b3, + 0x7945c931, 0xcb6182aa, 0xcf5f28e3, 0x310e641f, 0xc51b8a15, 0x10631dfa, 0x26236d4a, 0x2c149a10, 0x2491709b, + 0x514cbc80, 0xf3552516, 0x6e42955e, 0xecb1edb8, 0xed217d47, 0x7c95a633, 0x7af232f9, 0x1fd0bd5e, 0xde153e6d, + 0xb22d3c63, 0xb4a26391, 0x89d88b13, 0x22d9be33, 0x762a9649, 0xd12c401d, 0xcf262869, 0xe7dd1bcd, 0x020e7d57, + 0xe3fb2898, 0xb3dc63f1, 0x71672578, 0x43cb89a1, 0x7b8b89b1, 0x0c8fb989, 0xfe5999c3, 0x626847c9, 0x52335341, + 0xefd87706, 0x7e72e0cb, 0x704e1f7b, 0x668025ef, 0x1fe9650b, 0x0c876b68, 0x3e66bbc0, 0x37e81b26, 0x78d2fe8d, + 0x0a51a6f7, 0xd3d38807, 0x1b5ea47b, 0xaf2a3d02, 0xccf6bc28, 0x83491383, 0x555e1155, 0xfa5cbe5d, 0x8060f580, + 0x70d31402, 0x24cd0e85, 0x718ff533, 0x3a3026a0, 0xc970be04, 0x423e5e6c, 0x8b1c7493, 0xe337e7c4, 0xa8fbe62d, + 0x2c992123, 0x4aecca4b, 0x9319ff51, 0x6246f201, 0xac87c6ad, 0xbb060b79, 0x21d1f354, 0x9b5a11b2, 0x567319fb, + 0xefdf9bf1, 0x878d0199, 0x1a6f1152, 0x37544990, 0xbe893385, 0x2d67a6ed, 0xb6567bc9, 0x3cebe577, 0x4aea8030, + 0xeead0e51, 0x4da346ff, 0x783d607d, 0xfb7aba58, 0xf69e8493, 0x65ce9884, 0xee28515d, 0x86cc0899, 0xb728e6d0, + 0xd32ae13b, 0x74f3edcc, 0x91c3177b, 0x725e6af1, 0x99ff6fbf, 0x4ab59678, 0xc9287b3d, 0xd5c68ee8, 0x35ac62e2, + 0x2f7cc958, 0x2847f1f1, 0xca3ff287, 0x13591208, 0x0d14f051, 0xd7b43f48, 0x823643fc, 0x32abff94, 0x3b126959, + 0x2bc62a73, 0xb66767d2, 0x43d0b1c4, 0x6fcb526f, 0xc224d156, 0x5805c704, 0x2c0f58bf, 0x5241d2fd, 0xa04b350b, + 0xb34d64b7, 0x427930af, 0xcda3a32b, 0xeb346d33, 0x6e3627dc, 0xea87aae2, 0x811abb9a, 0xd14bdb0b, 0x070e2db9, + 0xa3a89b8c, 0x76644f6c, 0x0c1fd8a8, 0xdb247ab5, 0x5c194523, 0x11a05c03, 0xde5868e0, 0x1f20a518, 0x0e79f141, + 0x56ad6163, 0x4e2751f1, 0xa1f92c9b, 0x244528c4, 0x48e5e9f7, 0x9425760a, 0x1835e390, 0xae1e51e4, 0xe311cb16, + 0xfecfbcbc, 0x5774f507, 0xa4ca1bfe, 0xe72ff201, 0x9c514865, 0x2b238d48, 0x83f09396, 0x5ac8a82f, 0x317f53fc, + 0x14b2a2f7, 0xc6f81467, 0x44d35ef5, 0x0d4fc7d6, 0x1defcd8c, 0x64c740c6, 0x8117319a, 0x0ae33991, 0x6a56994e, + 0xb7523909, 0x22746d78, 0x86bd80d7, 0x2086d016, 0x4a6cf95b, 0x200e2fc8, 0x0a29a390, 0x72db7499, 0xe54b56a0, + 0x48ae5834, 0xbedce49e, 0xdabbf8df, 0x4b5ac9ae, 0x708b68c2, 0x0a82c244, 0x865cdf19, 0x9a36759f, 0x742aebe3, + 0xf8c7d285, 0x47874ca8, 0x12a5f3fc, 0x88f8c61b, 0x360d53d1, 0x278de231, 0x18b3365e, 0x124d5b71, 0x0a7f3dc8, + 0x083496a1, 0x7e8b033c, 0x6a8b57e4, 0x420de4da, 0xdc91f405, 0x2a7b3d2a, 0x696a466c, 0x47cb1436, 0xf5fce6c2, + 0x476f94bf, 0xa1b81b6d, 0x7dbdf959, 0x82c73562, 0xe294e4d9, 0x231208fa, 0x6d74727a, 0x9948ecee, 0xd7686046, + 0x4d563a81, 0xfe91b8c8, 0x356cc769, 0x3fa92121, 0x4bdca304, 0xdc5fea36, 0x3548666b, 0xc44b432c, 0x6f141bf6, + 0xa8acb0f0, 0x6447818c, 0xdc068755, 0x87c8f864, 0x0da662f7, 0xba7775b8, 0x49acb420, 0xe6a21bd2, 0x5ae57bb6, + 0xdb6028f1, 0xa17f7d76, 0x283ef33b, 0x02954214, 0x9b60839a, 0xb8f0e04e, 0xcf3a01f1, 0x33299063, 0x91ebdf18, + 0x3a675ccb, 0x9a013ccb, 0x27c83796, 0xefd9632f, 0xda4272e2, 0x0770ed40, 0x1b03552b, 0x5a1d3793, 0xc3073898, + 0xad2ead5e, 0xe6c6ad93, 0xd9d0ca87, 0xdcc17094, 0x51c47529, 0xab888dad, 0xb02daf89, 0x0d7b35c9, 0x606ecf96, + 0xc4eb7f1f, 0xb14d9b19, 0x19e9cf46, 0xf36f3003, 0xbb897790, 0x8bb154ec, 0xd0dce8ef, 0x88faf447, 0x09581749, + 0x98a975b0, 0x94f45c0a, 0xa0cb3192, 0x06bf99aa, 0xf2f55eb0, 0xb2afac8e, 0x5f1d6c09, 0x34d607f0, 0xa98d6e75, + 0x04cee39b, 0x898cf5df, 0x4d236bcf, 0xdb93c83b, 0x4dad1435, 0x3fd9c3f3, 0xc2bd2bba, 0x05ff7309, 0x1b1f8787, + 0xe23cc641, 0xc8539400, 0x4ded0afc, 0x45fde2a3, 0xf328907e, 0x660b0efc, 0x350ef5a1, 0x9cf955bc, 0xdcf1c59d, + 0xe7b25070, 0x35039702, 0x634bf7c7, 0xe7eabbec, 0x64c1ab0b, 0xd2bfa0ec, 0x90f27353, 0x8c684ad7, 0x3614d9e7, + 0x24fc2b58, 0x43fdaee7, 0xc7e4f766, 0x0b1d900d, 0x1abbd123, 0xe5a677f0, 0xb7cb2321, 0x0db23f2f, 0xfa1aa4a5, + 0xc404aad3, 0xbbdae717, 0x4f365e7d, 0x18a93441, 0x807efc7d, 0xaa1d6ff4, 0xb90adffd, 0x2605b775, 0x999ff91c, + 0xc2c83406, 0x634dbd8c, 0x72a52ee0, 0x53a0caf6, 0x77ea69f4, 0xb1e49556, 0x592e4052, 0xf3ed43cc, 0x97cdaaff, + 0x13036129, 0x2271bde6, 0x8a36dc44, 0x92dd316c, 0xf7f1b43f, 0xd5ce4d16, 0x9c32cbfb, 0x7f712fc8, 0x81b8de18, + 0x094ee18a, 0x762f6c13, 0x0d09d818, 0xdf3ccaa8, 0xc5ceb091, 0x646182fa, 0xa1cdf2f9, 0x11c49093, 0x600736ea, + 0x304d0a38, 0x9a54dd54, 0x48f009da, 0xbbb0f204, 0xfcfce7e3, 0xdba85408, 0xa3b54fc5, 0x7aad2b5f, 0x9bc49bed, + 0x46fd9f6b, 0xfc4c9d63, 0xbb589240, 0x308fa075, 0x013d16da, 0x4f370964, 0x7e44f438, 0xcc03af9c, 0x0256fba3, + 0x52425829, 0xf2712502, 0x9d411112, 0xfdfd2684, 0x90d0f959, 0x6a0edb92, 0xd78802a6, 0xdc1a5bfe, 0x03290b3d, + 0xcac9a39b, 0xfd2a8d7c, 0x335719b4, 0xe4bccf05, 0x89e3d4f3, 0xf50b586b, 0x76de3792, 0xabde194c, 0x8cecfbf5, + 0xabe4fbc0, 0x2a11dca3, 0xe59d8279, 0x1993268d, 0x2cc6575b, 0xd8e9b11c, 0xec14a2cf, 0x34c77745, 0xa07758c2, + 0xed1a15e9, 0x587c6a95, 0x1d510df5, 0xbf6762a6, 0xd72cd264, 0x4e4b7a7b, 0x46323819, 0xdbd8df74, 0xda3a5bc4, + 0x6c86690a, 0x4ed36819, 0xb0ee3d59, 0x7db7840a, 0xf5b2ff24, 0xc25d03b7, 0x3bab9f7a, 0x89d2517b, 0x6e8551f9, + 0x6986b25b, 0x518dfdca, 0x90d08965, 0x2ee70253, 0xf27f58a8, 0x40b89416, 0xeac10bce, 0xf08b9aa2, 0x96848009, + 0x23b5cb5f, 0x9328668f, 0xdc62aaed, 0x036b2e60, 0xc34c48e6, 0x9be34676, 0x10f1bcb0, 0x36ef35dd, 0xed09397e, + 0xc4fdfc57, 0x1b4e95d0, 0xe8dba564, 0x046a4ce9, 0x888efed4, 0x492c1b73, 0x2558062d, 0xad7fa3a5, 0xd5f5c44f, + 0xc77c3255, 0x7ddce913, 0x0f3dc3c1, 0xcbee9bec, 0xf27bcb2e, 0xd013393a, 0xdd4c442d, 0xca816257, 0x266770d4, + 0x71c7cbea, 0x7b120570, 0xdf15c212, 0x90122506, 0x0b538e9f, 0x54138edd, 0xad2b4ed4, 0x8bae6055, 0xa022866f, + 0x32410014, 0x8222ea01, 0x383f8142, 0x3ed9d3d7, 0x60c1d2db, 0x0d260926, 0xabcb4285, 0xff101102, 0xb01413ec, + 0xe22e5ec9, 0x46958e87, 0x65445b81, 0x1a87db70, 0xfa159a80, 0xc94d2cea, 0x600b4e4c, 0xc3e754fb, 0xb3cc5f49, + 0x794f8ed9, 0x5585544e, 0xee186fa2, 0xa42c8955, 0xe21e07a6, 0x88d1fd8e, 0x52093ffe, 0x478ea775, 0x6597a2bb, + 0x775d0d17, 0x80aa87ff, 0xd4dd6d54, 0x88a6af6d, 0xe3b63696, 0xdf22b5b9, 0x36c84c2e, 0x4cf35a14, 0x16534d4a, + 0xad3436de, 0x398d6c7a, 0x36f795fb, 0x1d8a82c3, 0x064c31dc, 0xe7937fc1, 0x854e2a6d, 0xfa9578ee, 0x5683017c, + 0xad1aed5c, 0x859c7eb7, 0xf8a26d4b, 0x09d02e97, 0xea5064e2, 0x41c71b44, 0xdd299faf, 0x84fdb6e9, 0x2ca8bb9a, + 0xdb46a9f5, 0x370c37fc, 0xd4a1b85d, 0xedb1b08b, 0x498cce69, 0xa92303c7, 0xfaa61d31, 0xe8923cc1, 0x8dd2eb02, + 0xf5844bcd, 0xede641e4, 0x9447e0ec, 0x5445f93d, 0x54044755, 0x1d0a1d84, 0x8bd4bab8, 0xfe0ac7d2, 0x806f51df, + 0x2d701e22, 0xc471b722, 0x0a59be9b, 0xc97556dc, 0xbd52596b, 0xe910ec5d, 0x4b774ce0, 0xba0c8434, 0xe9d9a212, + 0xa197f055, 0x16c91654, 0x04922bb4, 0x4361f249, 0x10f47457, 0x25a32bb2, 0xf438df1d, 0x88a3afa8, 0x3a3b0071, + 0x9f8811ff, 0x92901f00, 0xac9e38b5, 0x599ce929, 0x80f8a1f4, 0x3ac56fe9, 0x60a58a38, 0xbe8fcc0a, 0x400f73e4, + 0x29d586b7, 0xf6bfeb87, 0xee452a7b, 0x356d2395, 0x17be8165, 0xb24fbe3e, 0x155c622d, 0x2e436369, 0xcc81ee19, + 0xc6ece564, 0x002830c1, 0x3809c98d, 0x71cc63b8, 0xfd96f65f, 0xb3f17f97, 0xd7fe17ac, 0x75373658, 0xfcd7d314, + 0xe47808f1, 0x9195a7a8, 0x4e5c402a, 0xcf02a039, 0x06b5fcee, 0xa8e4ef6b, 0x5d1cc33a, 0x5e75d3a3, 0x48812098, + 0x68badf89, 0x4238127d, 0xbc45dc61, 0x3bb54714, 0x2b93323a, 0x321bf367, 0xba1f9b51, 0xe3509369, 0x5e6a70e4, + 0x5ec825a5, 0x1b8bef3d, 0x6eac676a, 0xb0f6ff3a, 0x2124e306, 0xaa273e07, 0xbabfceda, 0xd3f6c362, 0x3e3a0ec9, + 0x42d2809e, 0x8c48352a, 0xfe3873f0, 0xde8064eb, 0xb8ce75c8, 0x03a28c39, 0x2f2d2ef0, 0x27583bdf, 0x1943b3e4, + 0xaf1ed277, 0x73a7a295, 0x325c8d1b, 0x287dce7b, 0xf4828c5e, 0x0e94bf5f, 0x9a031f4e, 0xdd636996, 0xb7a937a9, + 0xd31a0bff, 0xd8f7ebd4, 0xc578b5cc, 0xb0f8d4a0, 0x5b133b90, 0x85c7c388, 0xca593057, 0x4ca39fbe, 0xaca531e7, + 0x9c7bff41, 0x35e52f92, 0xf279f2bb, 0x9438d63d, 0x0b2485d7, 0xcb402353, 0x06621999, 0x93952861, 0x6e7014bd, + 0xa599754d, 0x7987b3a5, 0x7eb5184d, 0x5ea21841, 0x34ea7c0b, 0x383f57a8, 0x870fba66, 0x6c05442c, 0x1302f627, + 0xff15cbfa, 0x1ebc4623, 0x587e2eaf, 0x2de3bf21, 0x557f1def, 0xf9d9067c, 0xdef9ac57, 0x432aa280, 0x63f1cdae, + 0x14a0f50e, 0x0a43c459, 0x6af1346a, 0x58c6a871, 0x253651ab, 0xd9f8e770, 0x1c45868d, 0x9eb40f1b, 0x36df200d, + 0xb7428e57, 0x793fe828, 0x872b3f39, 0x72eb1dbb, 0xc1d2b60b, 0xc5281493, 0x70f85721, 0x99c792e6, 0x994e3498, + 0x20ff11fc, 0x90e032fa, 0x8684c89d, 0x3cdf52eb, 0x49ea7a0b, 0x2981a09a, 0xf3f75812, 0x377c05ae, 0x4a913e3b, + 0x1852d160, 0x83092fbd, 0x308e9871, 0x0ff4114c, 0x467fbc40, 0x06530207, 0xc907cd9c, 0xef12bdaa, 0x4aa76a3e, + 0x8e636dae, 0x8b7db755, 0xdfd0d4e6, 0x49d9ed13, 0x651e2cef, 0x834a796a, 0x156d3956, 0x122cf73d, 0xc0c6531f, + 0x9677d413, 0xff34fb1c, 0x4146b7b5, 0x54bab231, 0x56e0e11b, 0xd852dda1, 0xf18b2adb, 0xfad7232a, 0x012d3f52, + 0x86425379, 0x7cca1e92, 0xfdd664f3, 0x9fa92a4f, 0xabdfc5a2, 0x1c643c46, 0x1f4ef696, 0xd97a47a8, 0x9d6f4dd5, + 0x220767e9, 0x300d42aa, 0x0288dc7b, 0x6476532e, 0xcd297632, 0xf148f764, 0xb29dfe0d, 0xf28220c3, 0xb0fbad30, + 0x7b70cc89, 0xd21d2865, 0xbfeb3791, 0xa35155b1, 0x90b75177, 0xe7a9feda, 0x85e8c878, 0xec5c006d, 0x251ee487, + 0x10c51877, 0x93a241f7, 0xce4ff7da, 0x4e3620b5, 0x5e5e7e6f, 0xf50f69dd, 0x11b179e7, 0xe37f59fa, 0x4d872b3e, + 0x4288d063, 0xf191bb99, 0x240fdbaf, 0x1215b1c0, 0x15725b2e, 0x04789d0f, 0x12b6b6a0, 0xbb86fdcc, 0x6d52791e, + 0x0c4873de, 0x79c4b1ab, 0xfde7116d, 0x1132cfc9, 0x16d4cf34, 0x8b0f6e35, 0xa1b7d947, 0x825d1dae, 0x1a7f3e6e, + 0x5eaf3071, 0x7f715e6a, 0x4ad400ff, 0xf100ec43, 0xfdc832fb, 0x98ed5596, 0xd3c5306f, 0xdb8aebaf, 0xaa6cd385, + 0xa1e13997, 0x67c03945, 0x87fbb40d, 0x4701d33e, 0xc135576d, 0x1c0744e9, 0x7c8024fe, 0x59d8c5df, 0x249dcf6e, + 0x9a2e9ea8, 0x901921ff, 0x52efb0b9, 0xdd656992, 0x0aef9cc2, 0x05968d17, 0x5e62a6e1, 0x03957625, 0x7de5b447, + 0x5436ffb9, 0x2676cd65, 0xb5a86420, 0xbffbd0bf, 0x547b1d7c, 0xa2032995, 0x9bcdadc8, 0xbac37e74, 0xbcb1299a, + 0xde390a28, 0x79aa6120, 0xfd18c5cc, 0x1fb3a4ad, 0xefab2337, 0xe73ced2c, 0xee1e88f6, 0x91425b3e, 0x54ffa8da, + 0x9590bdbb, 0x9d94fe36, 0x9f3a3352, 0xf28aaf46, 0xf066d0ff, 0xcd98d9bd, 0x84d53d86, 0xdef46e1f, 0xfb7d8172, + 0xa87db4d3, 0xdfa47e85, 0xc4e2e25c, 0xb46f8895, 0x41300ef3, 0x9f837ad4, 0xda1ba381, 0x3c87baff, 0xcc8fddcb, + 0xe1de8241, 0x7a57e20a, 0xdb18d7b9, 0xda9f54c1, 0x8e0e2216, 0x18c90869, 0xb851d97d, 0x1bc8f4df, 0x935d2446, + 0xf2382177, 0x60cf7efb, 0x31a466d8, 0x02d0f343, 0xac22ce7f, 0xe67c3b48, 0x4209ecbf, 0xf00fdfbd, 0xd896c9c0, + 0xf9adcc1a, 0xb1e536d8, 0xab641f64, 0xc9445a64, 0x0d577af5, 0xb5192130, 0x508eed4c, 0x62e65958, 0x9aacf865, + 0xe9d2258b, 0xd694758e, 0x616992e7, 0xcf1c9018, 0xe2967e07, 0x3001424e, 0x9eb1a9f5, 0xe8d6057e, 0x77bad72f, + 0x788a1077, 0x50688c00, 0x1cc7d5e2, 0x3060730f, 0xeaeb5e65, 0xd87f0518, 0x0afc57b0, 0x0ffc9472, 0xd1fd9d2b, + 0xa8cfff40, 0xcc6f1b45, 0x8346975b, 0x5a0ea37e, 0x46ade0bb, 0xac10e341, 0xad045320, 0xfb022a75, 0x9c4a7634, + 0x4b3e1122, 0x4759094d, 0x8ace0861, 0x50820dcc, 0x39e9a816, 0xea3be0e7, 0x297c9dec, 0x0b38f2cd, 0x75a30195, + 0x9fbfe5ce, 0x3d6e20aa, 0x06f4a083, 0x5ddef790, 0xf0a49b51, 0xb79ddf1e, 0x2eee5c9e, 0x5ab717e7, 0xeaab27d8, + 0xe9753a65, 0xa400cf9e, 0x0e46de2b, 0xf75545e3, 0x58ad0710, 0x5237501c, 0xd6e82374, 0xeb1d8ce6, 0x24304514, + 0x52ff45f9, 0xdde47865, 0x939fd35c, 0xe492d7e4, 0xc444d34f, 0xd38bed87, 0xf689d17c, 0x4094b24f, 0x36cae910, + 0xfe99093d, 0x008277bf, 0x2ac00c5a, 0x41c7b681, 0x9bb2974c, 0xc3852956, 0x7eda43de, 0x3aaf4929, 0x365cec52, + 0x6254574d, 0xbdd8e7cd, 0x27223e8d, 0x3cc66f12, 0x75c5da5c, 0xb486824e, 0x9d8a5ee1, 0x3dea7b65, 0x3f71e1a9, + 0x2f97232a, 0xe57134c2, 0x7f8290d0, 0x5767d834, 0xf48329eb, 0x510cbdd0, 0x622cc2e9, 0x14d489d0, 0x9f6d3e2c, + 0xcd5aee7a, 0x93846531, 0x30171290, 0x6342f7d8, 0x1185cdf1, 0x66565046, 0x69125c68, 0x53ed326d, 0xf8b876ca, + 0x9720fa9f, 0x329fd9b0, 0x8361ca49, 0xf077f6ed, 0x5649a56c, 0xb0e89721, 0x38de44a1, 0xea99a79d, 0x68d20584, + 0x2fd806dc, 0xed20b8c9, 0x9cfd536a, 0x54569d6b, 0x2de9f725, 0x4fd18d59, 0x90fc67b4, 0x6d74e468, 0x82fb9188, + 0x37c159ed, 0x62d89409, 0xf6f14593, 0xccac01ca, 0x9f0c2a0e, 0xb402c74a, 0x6c9e2c9e, 0x0b8946f5, 0x4749e88d, + 0x9b76b9df, 0x77be5a78, 0xdaee67e1, 0x7ddcd612, 0x6eb7dca8, 0x6b21dbb0, 0x808b196f, 0x85d15510, 0xbb80b864, + 0x6d0a7939, 0x7cace2ff, 0x47b22725, 0xa290357f, 0x18e25a7e, 0x831ee58b, 0x82f1cb11, 0xf60e8831, 0x0f404772, + 0x5a2747b1, 0x453a7fd4, 0x0f3a3f9e, 0xeddddd97, 0x9deba034, 0x60bb1f2c, 0xa6597124, 0x0f06ded2, 0x814be741, + 0xab22be89, 0x0ad18c45, 0x298bb882, 0xc4beee9c, 0xd7c54c22, 0xbe523f6d, 0x0d4b6995, 0x04c2d761, 0x61b482a7, + 0x816b9bee, 0x686fee47, 0x55092510, 0x0f24a0aa, 0x97735989, 0xcfea65fd, 0x1c770fd6, 0x2283d8ac, 0x0a3d86ea, + 0x9a8c9f81, 0x2a71ae6a, 0x10a440f1, 0x08c074e3, 0x55a75294, 0x4ae9de8c, 0x8b2c8bc0, 0xa4bfff55, 0xa4d0b214, + 0x231be88d, 0x16e7bf58, 0x912d54d1, 0xdfe5e4db, 0xac8cb59e, 0xa9a9c3d6, 0xe5b2658b, 0x79e57898, 0xbe5f2597, + 0x60499013, 0x065c7fe8, 0xcd35488c, 0x7643fb54, 0x52dca8cc, 0xeea346d9, 0xe9643547, 0x049f2dcf, 0x10db2868, + 0x46eea6e7, 0x4b71850a, 0xf945bcfb, 0x1caf63b7, 0x5a58e2f9, 0x9acb8fcd, 0x226c35f9, 0x48fc34a2, 0xa069a9d6, + 0xcb4eeb0f, 0x8b76697d, 0x229f50ee, 0x63b13256, 0x6c38e480, 0x25665887, 0x701895ac, 0x0911a6b9, 0x6ee236a0, + 0x78919fe0, 0xe112d6eb, 0xaf9743c1, 0xfeb018be, 0xce8464d9, 0xb941722d, 0x42e6757e, 0x7a99afcd, 0xde8164fa, + 0x7c307e22, 0x288e22b1, 0x1d57f8dc, 0xf35fac2d, 0x2996f8de, 0x02be78a0, 0xcd14e821, 0x0a207a7b, 0x5f49348f, + 0x0627379c, 0x9176ce9b, 0x895b008c, 0x3fc37a38, 0xc46ed145, 0x573fb2e2, 0x52fba4b1, 0xd034d988, 0xc9ad100a, + 0xbad553c9, 0x9f261cfa, 0xa6589a8c, 0x60787a4b, 0x57523d76, 0x59233954, 0x84e26863, 0x9abcabf5, 0xc35b1e3a, + 0x2c740e4e, 0x090e2f6d, 0xb3367b91, 0xf39a53f2, 0x03821629, 0xdd54747f, 0x2b6de7c7, 0x9b04ec43, 0x17e42c1b, + 0x40b8e439, 0x4cbdf181, 0x46547606, 0xf2f7616d, 0xde30cb61, 0x6280879e, 0x1ead24e6, 0x24ba2e38, 0x5765acde, + 0xeb6273d5, 0x32ebdbf8, 0x530fa02d, 0x0d9b7204, 0x1b37576e, 0x89408e76, 0x8dca91fb, 0x2d9bb372, 0x56be6ff2, + 0xe312826e, 0xb1ca4e78, 0x84298f5e, 0x25b29346, 0x9aa7754f, 0xb01ab1f2, 0xb22842f9, 0xbf720976, 0x0188eaed, + 0xd064be52, 0x50e6e5fe, 0x19f3bd74, 0xffdf3497, 0x040f62e3, 0xa263857e, 0x668dc458, 0x3469394d, 0x2521d602, + 0x11dc89e1, 0x00a50a2e, 0xf35de62c, 0x026310d7, 0xb28b93d6, 0x90647e03, 0x2ace9da1, 0xed32f295, 0xe215a20f, + 0xd2846899, 0x0d9d71a2, 0xe7783710, 0x15cbdb2b, 0x6901a726, 0x54561d67, 0x963e979d, 0x7603c33a, 0x6f959b12, + 0xf8ef0765, 0x80feefd4, 0x10330db5, 0xc29305a5, 0x6491a610, 0xb5025ceb, 0x00790264, 0x21eaaa74, 0xc1bf08cb, + 0xf93183ba, 0xdf1bd8b7, 0x4a8c5095, 0xffb24a69, 0x6677c168, 0xf0b7bf5d, 0xdf0ee06c, 0x24c39fa2, 0x4b0ce480, + 0xf073d4a2, 0xf5a33189, 0x25b33f27, 0x347b332f, 0x7598ead5, 0x55fd49c8, 0x0689d818, 0xa4c91c07, 0x9cb2e4d1, + 0xe93718ca, 0x2489a4f6, 0x71a51a04, 0x0ba312c6, 0x3761ca26, 0xc8c57294, 0x3727eefb, 0x7c4783e9, 0x462c5d23, + 0xd28e318c, 0xa72e0e49, 0x1f33d3c1, 0x83b1035d, 0x42d6c3ea, 0xab247299, 0xd14820ba, 0x4deb43c5, 0x90575cf3, + 0x45c18a1c, 0x6ea7a746, 0x2f181a75, 0xd50cae2f, 0xc61b6369, 0x19741001, 0x5e2542fd, 0xa18334b0, 0x4cfb545e, + 0xe75994c3, 0xfa64f422, 0x802556c2, 0xcdb3aa5f, 0x5e5312c1, 0xfd50e641, 0x71c56a42, 0xc086a3b1, 0x78acf9de, + 0x3e70d6a1, 0xa550af3a, 0x166abc4b, 0x38927f79, 0x45f9892d, 0x540f0004, 0xb02cf1ad, 0x98f148c4, 0x305d95b8, + 0xedc101da, 0x3cc9b1f3, 0xbdffb26b, 0x12907b48, 0x6dae43a0, 0x8ee644b4, 0x9a888f6f, 0x05454c25, 0x6f5b62cd, + 0xe35c439f, 0xe6f12edb, 0xbf5e7ab0, 0x25b42abe, 0x54d9e251, 0xe487d1d1, 0x2d0947b0, 0x0f0644e0, 0x9eca6512, + 0xed5687de, 0xdf4407c9, 0x4660f33e, 0x31b2e1cb, 0x13530cd1, 0xb688a2b8, 0x0fbf0cf2, 0xa7480d41, 0xe3e20489, + 0x606984db, 0xef6566dc, 0x96f2a02c, 0x97c1b639, 0x2eb6c5f1, 0xd6bba352, 0xd13363cf, 0x1965a36b, 0x8fcde1bf, + 0x215ba830, 0x529ef662, 0x309ac8ec, 0x8faaa9dd, 0xb55391c2, 0x063d620d, 0xaefe885f, 0xd6c12672, 0x527eecc9, + 0xb18b20ec, 0xce87d39a, 0xf951f65b, 0xa0e8994f, 0x325160ad, 0x54fee849, 0xb17be680, 0xc3b6e015, 0xdf7a8be4, + 0x2cc25391, 0x70fea8da, 0xcd746662, 0xcc3f19b2, 0x79fefe54, 0x765b0b27, 0x45c3321a, 0xf1922f6b, 0x71d6d474, + 0x570fd842, 0xd275e16c, 0x58f7502b, 0x819a06d3, 0xd5021dca, 0xece544c6, 0x699aaa3d, 0x07887f0f, 0x31a08325, + 0x7048f335, 0x4e43e6f0, 0xfc2b7fd2, 0x21caa6a9, 0xcf11f81c, 0x74197912, 0x45b8317f, 0x88dfd5a1, 0xb97b9dab, + 0x65185594, 0x5a20cebe, 0x0037f330, 0xe62576fd, 0xa7693f67, 0x3a484f6e, 0x10b2222a, 0xd3de6878, 0xbf6eb6e8, + 0xcf1b3da8, 0x37a06a5b, 0x517f1b68, 0x63cf4f9f, 0x2d1d2e43, 0x0798415a, 0xdfc5ba9d, 0xcf3a2eb2, 0x637d2aee, + 0x8d866088, 0x96ad1fab, 0x128e27e1, 0x8cc255fe, 0x98a0e149, 0x552bf9ae, 0x5c1fbb18, 0x3d406eab, 0x699cb1e6, + 0x5d69ea32, 0xd6056cc2, 0x651d37af, 0x0a53a987, 0x95fec709, 0x6c4ebec6, 0x5b7f8008, 0x40a726d1, 0x2718af1f, + 0x4ef2baf7, 0xd7356390, 0x39924cc7, 0x04c217fa, 0x70bb882f, 0x2ce9d986, 0xe124a885, 0x14e110b3, 0x8a6cbf20, + 0xf86d9e1b, 0x54d3d387, 0xabed1633, 0x0fc0191e, 0xa451fa31, 0x34527b63, 0x680cd1f5, 0x5b8d0033, 0x833f4238, + 0x8c4646e4, 0xab2a171f, 0xc4be2112, 0xaf50ec8f, 0xdcad43d1, 0x08d5312b, 0x1a213480, 0xa03dad07, 0xdfc84cfc, + 0xcd601943, 0xa32f6a40, 0x81f85e9c, 0x989c0583, 0xe22f1ba1, 0x7d39dc00, 0x660796e3, 0x27bac35a, 0xde647925, + 0xcd9c6fd2, 0xe89c9a49, 0xd8d2a0d0, 0x8733643f, 0x19c8f7b6, 0xca5bd09e, 0xba234d21, 0x468806b9, 0x9843857c, + 0x43fc6901, 0xb8dc9a8e, 0x37a923fa, 0x490ca02a, 0x831f7e6d, 0x5d90e4e5, 0x7eeb7549, 0xfa68d692, 0x205070da, + 0x1600d435, 0x4edb6892, 0xde8ed196, 0xeef703b6, 0x69eca985, 0xbbc713d2, 0x8bc8b3fe, 0x61e81818, 0x2934cbb8, + 0x74f5f9c9, 0xd2407bce, 0x948fc904, 0xfff2e7d7, 0x294411a0, 0x562ea1d1, 0x0d13950d, 0xe8c6b04b, 0x57af7ad0, + 0x44e3a773, 0xcbc00bcd, 0x92b37925, 0x19f5d462, 0x479a4f91, 0xb35b5e6b, 0xcad939c5, 0xf9b0892e, 0x0936c8d4, + 0xdbfb3343, 0xe33eecb3, 0xf928702d, 0x55a52c79, 0xd8f6c180, 0x7adbb298, 0x9881505c, 0x79fa5706, 0x27b5d0f5, + 0x813833ae, 0xd107a386, 0xec63906c, 0x4f51c3ab, 0xeb5b4e03, 0xeba01228, 0x99df547b, 0x22638817, 0x5d8519ce, + 0x2afb6ed6, 0xe63cdb2f, 0x5099d670, 0x8ec9e0d3, 0x57b874c3, 0xd18cf2a6, 0x1b295abb, 0xe2220b01, 0xe89cdecc, + 0x2166b6a8, 0x9378b5de, 0xbc0e66aa, 0xbd4b730b, 0x6ed412c2, 0xbd2cb3c5, 0x616ed22b, 0xc958e1fd, 0xe85f6573, + 0x48f214ff, 0xd5a67390, 0xb0760dd1, 0x5757ca41, 0x207a4a52, 0xfc3419c3, 0x6742a0a0, 0x6ebc2805, 0xde97bc59, + 0x9c870230, 0x9c45a8b6, 0xe6d81122, 0xca71c419, 0xd4c0b2ac, 0x1546db6d, 0xf59e6e0e, 0x73dbda8a, 0xf1501447, + 0x9ca32321, 0x28aa2ad3, 0x6196538a, 0xd09c0082, 0xacc446c3, 0x7619b494, 0xedda1b8b, 0x2ee817ec, 0xac4d8c67, + 0x6f3f94ed, 0xed5911c5, 0x7a861f64, 0xf1ef3832, 0xefc53090, 0x029477e9, 0x13a48327, 0xb69c32ce, 0x511cb7bf, + 0x991824b1, 0x108834a6, 0x155d0050, 0xcdf6a44b, 0x10908041, 0xa7085f35, 0x337af5fe, 0x88b94479, 0x06e8efd3, + 0x5fe75673, 0x5fbc6932, 0xe0491028, 0x415d3398, 0xddd65594, 0x634e6209, 0x53a36f17, 0x9868e49d, 0xd897ae9f, + 0xc8f217a9, 0xabb547fe, 0xdadd4ea5, 0x598fac57, 0x6bb6f2f3, 0x640e27a9, 0x35dc9ccf, 0xd86db337, 0x75dffe78, + 0x91caf838, 0x36b085d4, 0x6ed768ee, 0x450aa248, 0x75581860, 0x3e453f24, 0xa51bc67a, 0x20e0acca, 0x47e70eb8, + 0xaa9b7ccb, 0x7134c149, 0x23853285, 0x21839cad, 0x2f7c32e4, 0x5840143f, 0xed302fbd, 0x581b8c36, 0x4920f9db, + 0x73a5a4dc, 0x7967c2ef, 0x9f35edba, 0x4a843409, 0xb7c9b5b8, 0xe458745d, 0xb6ea0cb1, 0xd1a38150, 0x3bc87b2e, + 0xa77c2bc8, 0x64352466, 0x546fc08e, 0x54dc73b1, 0x6f71ba3f, 0x22cc8ff4, 0xf0a59832, 0xf1d07c60, 0x5ad8e28d, + 0xa802621a, 0x9d2f7453, 0xd06b4d99, 0x97f49b06, 0x965eb221, 0x38dbb785, 0x1192910a, 0xc3f9a85c, 0x77ab0370, + 0x2ab8602a, 0x914c68a6, 0xfbb322c0, 0xa523c113, 0xe60149de, 0xf84235d8, 0xe3dc0fd9, 0x4eacd9a1, 0x90f3bc7b, + 0x7ac21e84, 0x4c201aab, 0x5f30959c, 0x981a6b16, 0xe1480f1c, 0x287098e5, 0x4aad77fd, 0xa0836557, 0x6a7da09f, + 0x54d04441, 0xc54a5f21, 0x80c0c42f, 0xa7db2efc, 0xfd769e3b, 0xb826096c, 0xa17c98b4, 0xa85849b5, 0x9d25b728, + 0x6d020a0a, 0x58ee3a0e, 0xaba7af02, 0xe02af851, 0xba5ee6fc, 0x55c666fc, 0x1fc6ac9b, 0x3defdad5, 0xadd16744, + 0x39c1f2c8, 0x21f04dce, 0x773dcd2f, 0x912439ad, 0xe69b40eb, 0xd34099f1, 0xb352b6b9, 0x9d0612ea, 0xfcc9dcf3, + 0xdc522f49, 0x994e33b9, 0xcba796bd, 0x5d73dd6e, 0xf5a6064e, 0x4e4d287f, 0x96f7ea77, 0x27725253, 0xb1ea353e, + 0x2fabf02c, 0xbd08b9bc, 0x798936fb, 0x54f032a7, 0x4ec19e6c, 0xf4cbc730, 0xca5a9520, 0x9fe9f376, 0x8b6ce5d6, + 0x7e0fcd55, 0x12c6f935, 0x5cc43d1e, 0x543c33b7, 0x7041826a, 0xa5256d80, 0x2720f70f, 0xe121cb51, 0xcc96b596, + 0xd74bdfdc, 0x3f71dfca, 0xaf56b426, 0x67d94aae, 0xc8b276e4, 0x46092c01, 0xa510fad4, 0x9d30444c, 0x7ab2bf4a, + 0x31c9c5c4, 0x815f7c12, 0x2de950f6, 0x273bb46e, 0xb8ec5432, 0x1f44bb3e, 0xe93063ed, 0x6e07bcd9, 0xc238d590, + 0x268eb553, 0xcddf37d2, 0xb8c39eee, 0xdf4be870, 0xb269538c, 0xb7a74fcd, 0x5f4944c9, 0xd81d3d62, 0xba9c4864, + 0x529cfb97, 0xff81c72a, 0x8599f2c5, 0x1034f226, 0x52fd9219, 0x802d4da2, 0x0843005d, 0x11573e35, 0x64f9294d, + 0xee319983, 0x9e20484f, 0xf7de9a63, 0x84ee0e0e, 0x6172461b, 0xef7d14c4, 0x7eddb92a, 0x05d819c8, 0xeb12a55e, + 0x729b04f8, 0x066e33dd, 0x5c557078, 0xc1d538a7, 0xa1ce9e64, 0x3962c31b, 0xda9956eb, 0x10d7037a, 0xdf2dfb93, + 0x627ea0a0, 0x944807c8, 0x09940f7d, 0x01995c32, 0x38367e7a, 0xf43c006b, 0xfb7438df, 0x40496934, 0x1efb35ba, + 0x1f675f03, 0x521a3928, 0x1c0cdd57, 0x47d22b77, 0x2fba6015, 0x5a370ed9, 0x138072ec, 0xf2cb9e91, 0xe275f730, + 0x7e582c18, 0x91ee7970, 0x18f561f5, 0x2a13542b, 0xe2a370f4, 0xd4751e0c, 0xeae1983d, 0xea5cb34f, 0xee244eec, + 0xaa5857a0, 0xbff2af59, 0x25dc25ed, 0xd076596e, 0xbb3c08f9, 0x4e566d47, 0xed138054, 0x5b564390, 0x09f4e86d, + 0xdc6a57a9, 0xbffa78c7, 0x9169ef9e, 0x0dde876f, 0x05182130, 0x11030150, 0xe908c171, 0x3ba07429, 0x9ad45b32, + 0x0627b191, 0x3a0a312a, 0x2d47e370, 0x78bff691, 0xfe1e8868, 0x24131c91, 0xb21543b8, 0xf0206a56, 0x79607c9a, + 0xe1d7344a, 0x731aa786, 0xa162c393, 0x3843e614, 0xb4f31ad6, 0xb5be76fb, 0xbb541d80, 0xb2baf0ac, 0x85d61ebb, + 0x6ceaabfd, 0x2ff00ec4, 0xf470551a, 0x1a965dba, 0x2d662bdc, 0xea754df5, 0x68a149f9, 0x59b7a6e6, 0xeca15c4a, + 0xb910daa4, 0xbaebab50, 0xf5556c2a, 0xa42664f4, 0xf7cf1f99, 0xee3a3daa, 0x00c18764, 0x71577e62, 0x0e77b976, + 0x6dfb4b57, 0x08983c74, 0x7bbedb39, 0xf9ecda61, 0x6b2bed5f, 0xa0eb944c, 0xb767a93f, 0x6f9ebd3b, 0x890f01c3, + 0xf7839199, 0x011f2895, 0x4ea29c16, 0x4a6752c4, 0xae75a849, 0x6b0dfba5, 0xd48ceedf, 0x41960fcc, 0xfbea33f6, + 0x310c826d, 0xef809f2d, 0x1d58bf3a, 0xa055a871, 0x2d9b88a8, 0x82c0728a, 0x5f6a9cda, 0x770f30b9, 0x51c1bc34, + 0x32941aaa, 0xaca44d21, 0x374da8aa, 0xebb54de9, 0xbc20fe8e, 0xbee57f0d, 0xc5fb1b00, 0x196b381b, 0x5cc13bdd, + 0x24f72e41, 0x7b353e77, 0x92d8a114, 0x36e38467, 0x8c6a7f67, 0xdffc0590, 0xc166b3e4, 0x1550078c, 0x2bbf6e54, + 0x02d7231e, 0x250fe882, 0xa33cfdb1, 0xd915cc82, 0x776488e8, 0xd65aeb97, 0x433eef8f, 0x41f40d2b, 0x503e3d80, + 0x77cdafd6, 0x18cd82f5, 0x35235684, 0x2609979f, 0x805cd157, 0x4e896d31, 0xfa834f96, 0x8b04e80e, 0x9246a829, + 0x8b1602ac, 0xedd5d795, 0x65149527, 0xed994e6a, 0x33c404b0, 0xde74a4d3, 0x25743363, 0x02bc05b0, 0x211b47ab, + 0x6a00cf61, 0xcb5d6c3e, 0xd0f0609b, 0x4526a271, 0xf4a2694c, 0x1818a853, 0x852f2058, 0x27c54841, 0xb2020dda, + 0x3a1f8e4c, 0xf1cbd79d, 0xfd79b4e7, 0x9dd47f83, 0x7493cabc, 0x5f058d5b, 0xf6357c52, 0x9d22892e, 0x8c407707, + 0xaa2bc39b, 0x33004af8, 0x9a4a119e, 0xf61981fe, 0x464ef6f0, 0xd2969dbc, 0x36190e47, 0x60d329cd, 0xca63dca0, + 0xad650481, 0xbab43a89, 0xb254442c, 0x033fc21a, 0x8d2dd132, 0x1390eece, 0xa5fdec08, 0x95a5ab2a, 0xeb1be751, + 0xcd4b62a2, 0x1fee330b, 0xac6a54f9, 0x837f112d, 0x7a41e201, 0x11c38bfc, 0x55034a6a, 0x40f0bd45, 0xc2aeb8c1, + 0x3871c247, 0x7b5b4b93, 0xa38c7cd9, 0x131d7f04, 0xc455029c, 0x79b18fab, 0x94365cad, 0x049553fa, 0x6afe2453, + 0xe8152f1a, 0xf1053fc6, 0xcf5e8d05, 0x00ce5ce4, 0x7841b05c, 0x418dffa9, 0xb24449cd, 0x099986db, 0x570c0812, + 0xeefde2fa, 0xebdd324a, 0x6700861b, 0xf2c82130, 0xc6296f15, 0xaa042927, 0xb826b85d, 0x9a6c09e9, 0xc7f221de, + 0x2469feb8, 0xb56144e7, 0x23fbd941, 0x301c651e, 0x5d50a96a, 0x56814af9, 0x316da7c3, 0xc4f5fe08, 0x6fbcc112, + 0x1d9bac29, 0xcfdc433f, 0xd487a244, 0xad525f12, 0x31dab567, 0x6b7f926b, 0x88c96ae9, 0x12953031, 0x91362dc5, + 0x23d2bd03, 0x7e59f7de, 0x905eec28, 0xeed21530, 0x6a9f3b46, 0xa1b61a45, 0x1b43be57, 0x3b57a6e9, 0xbff5fcbf, + 0x6fde06fa, 0xf7143b3d, 0x0f30251f, 0x53c6a251, 0x2cd15977, 0xae221301, 0x23e67261, 0xc0327a05, 0x8be0f2a3, + 0xa384766b, 0x4f896c4d, 0x52950044, 0x45372d66, 0x60c12af7, 0x5e3cd079, 0x28ff7053, 0x2cfe0bf4, 0x744c6aa8, + 0xafd28cfd, 0x5c0e04ed, 0x61f6d4dc, 0x389f3150, 0x0ebad3ea, 0x1e6d38b9, 0x53d625bd, 0x9c94d037, 0x6ff1a93d, + 0x32590c08, 0xc64dd545, 0x75843858, 0x0296318a, 0x455021cf, 0x9f319627, 0xc660c6eb, 0xabe7abc0, 0x183cc494, + 0x2e308e36, 0x1d58e6fc, 0x1aca1276, 0x45474cd6, 0x10d1f285, 0x5b797143, 0x1a944534, 0x00e42780, 0x3ac3f2ed, + 0xa80fbee8, 0xa7f41048, 0x4a3d7c10, 0xd06b94e5, 0x1d9d3cf6, 0x8d79facf, 0xfb53dc4f, 0xbe564c0b, 0x479222b6, + 0x72b62012, 0x090ad2d5, 0xbe286733, 0xda1b0221, 0x3417c0eb, 0x1d680221, 0x6c4faeba, 0x8c0eed9b, 0x145e348a, + 0x76ccee7b, 0xc5e534f9, 0x993d8ffe, 0xd76aae11, 0x4787bd2f, 0x839fccc4, 0xa9c21924, 0x500cad11, 0x6074d821, + 0x531d7a3a, 0x1540be68, 0x61c614ee, 0xd7841d9a, 0x52756f78, 0xd201e542, 0x0ec4ceed, 0x4bba0aa8, 0xb70a5abd, + 0xbdf1b95b, 0x5d50c3ea, 0x94484c80, 0x56ee08e7, 0x3d3ab718, 0xd120fee2, 0xc2ff56f8, 0x4b5054ca, 0xb7e75c80, + 0x8d3de007, 0x274a06ed, 0x90ca1f60, 0xe365ed1b, 0xd7a2de16, 0xaa7a2781, 0xf3bbaed1, 0xf63c6a44, 0x4273c734, + 0x1147a4b8, 0x02be6fd5, 0x636decb1, 0xb57700d3, 0xa5c4e63a, 0xb3244bcd, 0x01ff2a02, 0x7e383f2f, 0xd73f24f7, + 0x94fc5839, 0xfd1dfe46, 0xfc98f229, 0x16a16455, 0x09c65ae7, 0xa744fe27, 0x5c6c5d4d, 0xc9cadf2c, 0x74284df0, + 0x2a9d5d6e, 0xadbe4451, 0x8de98d94, 0xdb5e7094, 0x3131c0af, 0xdcaf0f9e, 0x8f886004, 0xaa3ded18, 0x647b5072, + 0xc2496fa0, 0x22785f51, 0xe1c95bb1, 0x3fab84f0, 0xc524c1da, 0xc14e6443, 0x98811abd, 0x10633c91, 0x2744f1a9, + 0xde317504, 0x825d0086, 0xfdf23b7e, 0x80273975, 0x2137c50e, 0x6a2d0f87, 0x95014818, 0x9f59226a, 0x803d2695, + 0x9e840af1, 0xfb331ef8, 0x78b2a2bb, 0x64dd7672, 0x7ede3192, 0x90919268, 0x116fdcdc, 0x1dc99dac, 0x0e0624d5, + 0xcf6b2526, 0xc56d7529, 0x0cf5a5e4, 0x99bce1bb, 0xed26c3ed, 0x4cc86548, 0x181bbbe9, 0xb65f3924, 0x6df891c2, + 0xf0335900, 0xb7ab394f, 0xb9e5653d, 0x053dfed6, 0x21442178, 0xc6b86ae1, 0x41dcf782, 0x8acc6a89, 0xf1213d43, + 0x6a564d51, 0x6cd6adb2, 0x14b11dc9, 0xbf50fd05, 0x0164d160, 0x1cce608e, 0x1735c7df, 0xb3d6b29e, 0x8d2b2930, + 0x76afc7da, 0x4754e831, 0xcdb0aef4, 0x04990205, 0xc7afc64a, 0x06c4dbb4, 0x690e7c65, 0x6a4de68d, 0xfa9b26db, + 0x92d8e4c1, 0xa648f10a, 0x313af7f4, 0x31ff2d85, 0x096ac1b3, 0x60ed49b0, 0xa233fdcf, 0xc722f59d, 0xea4d5747, + 0xb10e93d1, 0x6469631e, 0x16d872c9, 0xc03e8b79, 0x4b8bd211, 0x8dc89ba7, 0xdae14eeb, 0x7ba21e9d, 0x71941cdf, + 0xc69cc42b, 0x12d59841, 0xfc9eb9b5, 0x327216bc, 0x76b311ef, 0x8e3e5c53, 0xdafa0b4a, 0xdadbfacf, 0x273ba447, + 0x515b2cd2, 0xee3c3e8e, 0xcb766109, 0x77d20a06, 0x5268b4bd, 0x896c5763, 0x373a086a, 0xf65e73ad, 0xfeea60af, + 0x2c3d340c, 0xab5eb21b, 0x1dab92f0, 0x4c61dab9, 0xebffdb7c, 0xe9b584f5, 0x3080252a, 0x72d54a78, 0x655688f2, + 0x48f8a61f, 0xba10d7fd, 0x91961e05, 0x9db722ea, 0xa4576b4e, 0x987c4a38, 0x69b62f9a, 0xb0d03d05, 0xf54a0412, + 0xd65a05df, 0xbc159e3e, 0xf664c440, 0xe487430e, 0xa74e221b, 0x9c6bd471, 0xf099b128, 0xc752b27b, 0xf972d775, + 0xe68a9673, 0x1706f69f, 0xcac48a76, 0xf90275f0, 0x5bfbc978, 0x21576ea9, 0x6836500e, 0xd02c6172, 0x20f84c1e, + 0x0bac149e, 0x5845734c, 0x988f9f78, 0xc6242708, 0x7221b055, 0xf8cc893b, 0x9a672687, 0xaa577694, 0x078b0b68, + 0x25df6225, 0xe61dd909, 0xf19083b6, 0x4d093992, 0x0cd6344c, 0x7e4eb234, 0x08946f55, 0xd6322889, 0x423cd163, + 0x0eef6933, 0x3c8364f2, 0x20d025e3, 0xa3db50f7, 0x5f0524ca, 0x25f7e45c, 0xc1ed4455, 0x4c82d7e5, 0x38863ad3, + 0x7c14086d, 0x6d478451, 0x796e7aa5, 0xa68ed34a, 0xf22fb6ee, 0xfd02b176, 0x0eea559a, 0x0082ab98, 0xba1460e9, + 0x2c7b687d, 0xf9577290, 0xe203534a, 0x13242a0c, 0x2b899cf1, 0xa0014376, 0xc5d56844, 0x75926a09, 0x7ff95868, + 0x59edb8c5, 0x7c417fb2, 0x0c8f5bbc, 0x2a3f4f8c, 0x0e7a9b81, 0x1a468684, 0x23b6e6f1, 0xaa01768f, 0x082f64f4, + 0x973459bb, 0x6d56a10f, 0xa6f87a4a, 0xe50a997c, 0xbefa79ca, 0x808779ae, 0xb76aab5b, 0x0645f7f7, 0x5f037dda, + 0xee858acd, 0x1b6271be, 0xd6cdf205, 0x95117484, 0x3021f9f8, 0xee7a8554, 0xda0c3603, 0x09c9974e, 0xcfc08e0b, + 0x687d9a11, 0x79252840, 0x4011f8ce, 0x5a0c6d4d, 0x1d28bf1b, 0xa65afb77, 0x3f8f0fd9, 0x7b1efb6b, 0x844c0091, + 0x632b6fa9, 0xe751464c, 0xcf5c5e6d, 0x71edbfc3, 0xaad8a940, 0xb5a6da24, 0x157f0ab9, 0x9721a9b9, 0xa3271d61, + 0xf7ce0e2e, 0xcdc6e36f, 0xc3e06696, 0x594d5374, 0xd8a689b0, 0x5cef848e, 0xe4b3f9d8, 0xaf47ef84, 0x4f03b1cb, + 0x76faf8e9, 0xebcae4e0, 0xa30b489e, 0xf675099c, 0x1c8c4fb2, 0x22b8e505, 0x3330acd8, 0x22bc38f9, 0x3ec67bc8, + 0x8a8a8b11, 0x7cb6cdf2, 0x5d93cce8, 0x0773b7c4, 0xcf5cc54d, 0x9543d507, 0x0e58a009, 0xa623cb07, 0xfe8d2271, + 0x8bb980f1, 0xc55fc5d5, 0x573bf2cc, 0x2ea28e2e, 0xe6ebe1a2, 0x3efae9b6, 0x388dbb7c, 0xb4638af0, 0x5d09e976, + 0x09d8c6bd, 0xa1707036, 0x117c26b3, 0xcd972a13, 0xa36de9ec, 0x35861e13, 0x67703db5, 0xce22a56f, 0x52424cb2, + 0xf5518da4, 0xbebb25dd, 0x0de0f6a7, 0xab282af4, 0xbeba9bfe, 0x5d7c297a, 0x8cb2404b, 0x736f95f9, 0x598a3231, + 0x314d82c8, 0x5e41369e, 0x79633fe8, 0xdfe56a0b, 0x35dcd0d9, 0x0a619747, 0xbdc84bf8, 0x0e90f269, 0xa301da44, + 0xa9397a11, 0xd271b01b, 0x23feb328, 0xde5cd2f4, 0x98beddbc, 0xf31dce6e, 0xd1033ee1, 0x14fbf47f, 0xa719d2d5, + 0x0e993819, 0xc0770a44, 0xb7dd9d7e, 0xcba60206, 0xf3dbae91, 0x62d3c6c6, 0xaa77e9b6, 0xab548bb5, 0xd6f76554, + 0xede1a36a, 0x5eb40e28, 0xe231ae8b, 0x69ac848d, 0x9b9457c7, 0x649c14b7, 0xc9c61bee, 0x89752fd0, 0x8ed5e6a7, + 0x81ddac28, 0xfcca9351, 0x97641eff, 0xae242179, 0x4de1ea87, 0x207486bc, 0x81a8ee2c, 0x94d1b933, 0x125d90ec, + 0x4992a701, 0x0186e141, 0x899bfc8c, 0xb9d3c6ea, 0x310fe9d2, 0x255310cc, 0x8f3f90b9, 0x14a0981a, 0x2b31895f, + 0x72f10f74, 0xca151d14, 0x99f38283, 0xfc3be8b1, 0x90cfba09, 0xb87e2c0d, 0xc1eb1bce, 0x0d5b57e1, 0xf94b24d3, + 0xb183178b, 0x874b2a2d, 0xc06b47a4, 0xd2fafd8e, 0xabc60b70, 0xe7b332d4, 0xe0af6d7d, 0xb37625d2, 0x91509d56, + 0x0120fe0a, 0x1a98f644, 0xcadd7122, 0x170c79c4, 0x6ef1bdb5, 0x4f72b02f, 0xb646cfd2, 0x71034837, 0x0efac47b, + 0x5fbaf5f1, 0xd328c258, 0x6cc65352, 0xd48507b7, 0xfb0ccd41, 0xcd76ebfd, 0x78765b05, 0x8e12eda8, 0xdf1c289c, + 0xd4533d4b, 0x44d667a4, 0xa013194a, 0x718db9ec, 0xec08e7a9, 0x3c0fc2e5, 0x4323a192, 0x1f4e43ba, 0xaa28ec1b, + 0x5f9dfbc8, 0x88fc6779, 0xe9a8a225, 0x22f87e8e, 0x05d51367, 0xbdaccaa1, 0x3527b923, 0xc5ddbe37, 0x22c7c5d7, + 0x9609b772, 0xd6a4f3d8, 0x2e1cd529, 0x68c49c7c, 0x19c70dd5, 0x37067859, 0xb5361b7d, 0xf2556c4a, 0x758f4f10, + 0xcfe1498a, 0x1fb7e821, 0x8a02b49e, 0xda48cd46, 0x4f6efc39, 0x2b49f6d7, 0x7e37bf81, 0xe7828041, 0xdbfa841a, + 0xa9d361c6, 0xec908956, 0x97efa27e, 0xf95e518f, 0x7dfbd3fa, 0xc05e7de4, 0x04eb4bf5, 0xbb90d91e, 0x00b04a53, + 0x839ea357, 0x3be73e1b, 0x43961a92, 0xa5ce6e9f, 0x149a05a6, 0x1a309fe0, 0xece9077e, 0xb8c4dd36, 0xd531821f, + 0xf25b9cd3, 0x7c068a34, 0x7177ece8, 0x65b8d68f, 0x19450f76, 0x9f86e9bb, 0xba2ee5a1, 0x2e2d4ab1, 0x68ce9081, + 0x3626da17, 0x893e3190, 0xb0f94756, 0x0fa11b5d, 0x34c53e45, 0x819d4e19, 0x57e6e618, 0xcfd4eec0, 0xd983f32e, + 0x4d9af6ec, 0x9330049c, 0x2f849dd6, 0xd1923124, 0xac1f541e, 0xa19ddfa6, 0xe59e618b, 0xc772b036, 0xb2c7f681, + 0x5b5bc81b, 0xe5822ee2, 0x1ab51964, 0x556672eb, 0xa0b7212e, 0xd21f7858, 0xb90fdb15, 0xc97ca251, 0xd9ed6ce8, + 0x8cadc0e9, 0x0fe937d8, 0x74b1c757, 0xa36967b2, 0x5390f84f, 0xaab7b926, 0x0f156280, 0x4a77202d, 0x84c41cbd, + 0x8814a1a3, 0xf42a45a6, 0xf55590c7, 0xdf9fff33, 0x03326137, 0x863a8da0, 0xdb350f65, 0x1d97ad8e, 0x52b3b965, + 0xcc3b3482, 0xbba60036, 0x367ed973, 0x987aef98, 0x60fcee46, 0xb8736673, 0x95260161, 0x0c7e6cd3, 0xef998e22, + 0xc9f3a08f, 0xb0360aac, 0xd5ce1945, 0x351cf9fa, 0xd855358f, 0xc58011c6, 0x3fd614e5, 0x3464d1e4, 0x4a57c2ca, + 0x16145200, 0x2e17d85a, 0x2e2733ee, 0x77d25185, 0xc5432a83, 0xe9895463, 0xc9efbdff, 0x49e50013, 0x85971c15, + 0x1c127dc7, 0x43a213e7, 0x2c4d2a07, 0x9c7bd1b3, 0x92f9ea96, 0xf345fa16, 0xc402962a, 0xe2aed5d6, 0x2e4bf395, + 0x035da6de, 0xe712360f, 0xdfb3a96a, 0x6841b68d, 0xfcffea4f, 0xd131fd25, 0xca4fabfe, 0xec09381d, 0x9249ac9d, + 0xa48b41ec, 0xd9559b64, 0x4bef31bb, 0xe98146f5, 0x668d87f4, 0x79e401b2, 0x542fa177, 0x7e2c1a26, 0xbeef1457, + 0xc9c4ff17, 0x6e762b21, 0xd2fd961a, 0x7d58ffb6, 0xa7d5a477, 0xda64e291, 0x813f9723, 0x9c862252, 0xba533447, + 0xa2d7160e, 0x3885d7aa, 0x7eaabee8, 0xc56367d0, 0x6197c261, 0xb3afc2a2, 0xd21dda53, 0x1a45cf95, 0xad655dfb, + 0x6e6db47d, 0x67225e6d, 0x40f31086, 0x5cc6a53e, 0x8de6028f, 0xc41f1b1b, 0xd8d4814a, 0xd0645393, 0x6de0a03f, + 0xa02bb75b, 0x30903604, 0xe54a9643, 0x5bf27a06, 0x090ce886, 0x3d851762, 0xd9aef626, 0xff326c9d, 0x7bf2b96e, + 0x0f83bf53, 0x6cbf4186, 0xb38edc2e, 0x317f746d, 0xfe9ace58, 0x7e52eacd, 0xc24529ed, 0x52c552f9, 0x61ee9c75, + 0x27a11b62, 0x45bd63d1, 0xf78195ea, 0x589795b6, 0x0ec417b2, 0x0c6a82d5, 0x89e5417f, 0xe2d6a9d2, 0x918f5672, + 0xd21dc468, 0xa30d4284, 0xdea7c420, 0xb014348d, 0x498ac072, 0x7a230caa, 0xabefcc9b, 0xeb31e6e4, 0x9b59c0a4, + 0x9fb99b9d, 0xaf4211db, 0x824389b1, 0x6b684d0c, 0x692d214e, 0x37b78a03, 0x6c25c0e6, 0x3bfc072f, 0x8c0d0687, + 0x5af39475, 0xeb818879, 0xdc726f5f, 0x3bd8c911, 0x552ba581, 0x452d7105, 0x387c358d, 0xb7f5962f, 0xb9c58dd3, + 0xf791dd4e, 0x603436a0, 0xbbeb8c3e, 0x41e8e93f, 0x198d972e, 0xa5424280, 0xf1b7371e, 0x5d355021, 0x65d58cf4, + 0x3489ab59, 0x90b7360e, 0x7948bed3, 0xb99b55c5, 0xd5fd72a7, 0xd42133e8, 0xed974411, 0xb35d3b86, 0xe1ea9fda, + 0x31198917, 0x6c515ada, 0x36214d08, 0xb1c16972, 0x1f44058b, 0x88226354, 0x438a3e95, 0x8dce6a65, 0x7f205ecd, + 0xaf08b81c, 0x78d67156, 0x83343579, 0x1dacc36f, 0xdc0e7924, 0x43b9e5e0, 0x7b742356, 0x661b4de9, 0x489bba84, + 0x6bb970f5, 0xdc45edf3, 0x0b877ddb, 0xe20ebd12, 0xda5d61bd, 0x59049e83, 0xcc23ffb5, 0x0d4c6101, 0xd6024509, + 0x218a5782, 0x964d0986, 0xf6f8b2c2, 0x802d964e, 0xc311932c, 0x8d248d11, 0xd55286a5, 0x1abdc8a8, 0x81421416, + 0xbee29019, 0xc3d7344d, 0x9c42a114, 0xb08dbb55, 0xfc629722, 0x30a49bb3, 0xe8f06958, 0xd50c6634, 0xf56a7790, + 0x707d3b2b, 0x7e122351, 0x572eaf00, 0x41409aff, 0x5380a44a, 0x37cbfb39, 0x3259de14, 0x683fd45b, 0xd2a98bfc, + 0x8d92947e, 0x2ec974c6, 0xf8415ffd, 0xa36a6af4, 0x7c7cb077, 0xa2b3f313, 0xde2c6d76, 0x3525cac0, 0xc2154241, + 0xc64af8f4, 0xd5a1ec76, 0xb12cf168, 0x4aa474a5, 0x66e6adc0, 0x961c7571, 0xc13d6bfc, 0x9f8f8931, 0xa534338b, + 0xd3c5c3dd, 0xfdb8f39a, 0x680f92e2, 0xec88241e, 0xbeec9bb1, 0xa790551b, 0x8924d1ac, 0x50c81d0d, 0xeb12bcd0, + 0x2440ffd1, 0xfdd11fe3, 0x594afbb6, 0x627cf2ce, 0xdef56df8, 0x77b046f1, 0xb438548c, 0xdbd5c55e, 0x6b99e508, + 0x4eeb7112, 0xb57d2937, 0x093f1abd, 0xd11bf825, 0xb2d48286, 0xdf268af4, 0x8992e32f, 0xd69ac52d, 0x080b8b83, + 0xf5670e9b, 0x56b5a24d, 0x182b5997, 0x0dca7d0d, 0xe1b0190f, 0x5f1f502a, 0xee38b535, 0xd3ea797a, 0x6815e21a, + 0xff7b1dae, 0x65f91298, 0x3ae5e499, 0x78a0b966, 0x7c9ca698, 0x956309ff, 0x3826e65b, 0xb7c35a56, 0x2d8ea8e8, + 0xcb821fef, 0x6c161fd9, 0x3dd1ba7a, 0xe65863f3, 0x4354cd5c, 0x4cb35ae2, 0x463a9d20, 0x23cb5fc0, 0xd270acbb, + 0x27bfbb45, 0x8d5bbdd4, 0x22197d28, 0x20cdd2e1, 0x17f4e302, 0x2548e947, 0x45dba9ef, 0xa7e93f87, 0x49e9504c, + 0xd9f51eef, 0xababca16, 0x6fbb6b3c, 0x9d8a620d, 0x5a35d0e1, 0x44837b30, 0x4aeec0d3, 0xc3bab222, 0xd2e92983, + 0xbf21f594, 0x648f5bd8, 0x4a7800db, 0x321fecd8, 0x9764ad0b, 0xac53277a, 0xda90fc1d, 0x31bd9317, 0xcccacf00, + 0x89617f82, 0xce12a594, 0x0df1d2ec, 0xa1802d82, 0x9edc7167, 0x048c344c, 0x0223481b, 0xef068c27, 0x10c0209f, + 0xbfd222f5, 0xba68ca7f, 0x6cacfc02, 0xef38d5ae, 0xab183b5c, 0xa1e50bc3, 0xd122f3c4, 0x38b1f285, 0xee34a1fc, + 0xffa697d5, 0x117df807, 0xada60451, 0x27a30d0e, 0x6c817fea, 0xf29b4b99, 0x2110560d, 0x5a9b561a, 0x8851df45, + 0x5ef56f94, 0xb87397bf, 0x0f5f6e89, 0x1adff3d9, 0x8a3da693, 0xd4fed11b, 0xd0d74d9d, 0x032eef38, 0x27e1d491, + 0xee7598b7, 0x7d06c2d9, 0xf7f84d82, 0xc4343df9, 0x5f877025, 0xbe329dae, 0xf7488fe6, 0xbe0aed4f, 0xd70efd1b, + 0x6e3d905b, 0xe8dac8d2, 0xa8235302, 0xf81a94aa, 0x5fe70cad, 0x6bfd2ba2, 0x626eb086, 0x65da6d96, 0xfb13158d, + 0x4517d2ba, 0x8086a0e5, 0x5f7220f6, 0x60ca0a40, 0x69433587, 0xcb948a32, 0xea0417ab, 0x9f371090, 0xe97d3476, + 0x8f441b1f, 0xc449221e, 0x30cd15a8, 0x1e0faae2, 0x01273c04, 0x01dcede4, 0x44dff8c1, 0x185f7fc8, 0x2c04475b, + 0xa1c6c3d2, 0x25699ce2, 0x07874266, 0x8ded172a, 0xed9e2c4c, 0x28540f9e, 0xa7ad784c, 0xe8ff66c7, 0x63922747, + 0x57c28eba, 0xe2aef5d7, 0x145337cd, 0x0f7d2a82, 0x4d7d49e3, 0x155956e2, 0x171b23b4, 0xab60e697, 0x705816ab, + 0x102c9344, 0x2d74de8f, 0x7e6f12ee, 0xd4a069ea, 0x8c4215d9, 0xb9c41f27, 0xfe7b4c8e, 0xa3f53f4a, 0xee5d8482, + 0x50c25f7f, 0x15760ba3, 0xc826d155, 0xfcaecae0, 0x7defcddc, 0x47e1e6dc, 0x482b40d4, 0x54b5e129, 0x2cff2ea8, + 0x7ed7e7e1, 0x4edf8245, 0x892161f9, 0x79eae598, 0xd8842b47, 0x78b2507c, 0x520267cc, 0xbf80e74d, 0x0a12d048, + 0x39e74e76, 0xa6423b86, 0x3abc2009, 0x9507b4d1, 0x870cfd05, 0x4dd993d9, 0x337fa308, 0xbe4b3bb0, 0xbc7cad2b, + 0x562fa2f3, 0x18328539, 0x8ce3291c, 0x362c236f, 0x6f41cafe, 0x91d12226, 0x5ca01ada, 0xb88b2f28, 0xda6828cc, + 0xb3a4f8a3, 0xc632b35e, 0xcb506596, 0x79432d62, 0xd84df17b, 0x6c410374, 0xe763e091, 0xef7be902, 0xd7a2e6bf, + 0x32ebc17a, 0x482e18f8, 0x76c9835c, 0x26da1080, 0xf6410478, 0xb10f210c, 0xd74a46a9, 0x0b75fd42, 0x5883dd76, + 0x5f8c6c14, 0x06dd947f, 0x8728b42d, 0xbb57442c, 0x82f9d29b, 0x995d009b, 0x65f09012, 0x312c5ccf, 0x5e03d740, + 0x75237e5c, 0x5a30ac27, 0x8cdf6b01, 0xa06bfee1, 0x951576cb, 0xcaa0812b, 0xe8ca6a05, 0x356ee980, 0x5ea7b1a4, + 0xfe7f68e1, 0xd5e17d29, 0x07e6b021, 0xdeba161f, 0xb65432b5, 0x61c19cda, 0x58dd3ef1, 0xf556439b, 0x2f0e208a, + 0x8d759485, 0xb74e7bc4, 0xe213afe5, 0x88d8620c, 0x99c2e7b5, 0xd51f33da, 0xbe09eb17, 0x06b939fc, 0x77785e2c, + 0xc02625e5, 0xa786b292, 0xcf97e87c, 0x2b885199, 0x38a5a231, 0x66dfe7e1, 0xf4d09d98, 0x625747fc, 0xb2d8a461, + 0x409e8b6b, 0x274d8d84, 0xfc14f31b, 0x86b32ed8, 0x5318da8c, 0xbb49e066, 0x9e18ef68, 0x1ce1ef2c, 0xf872e754, + 0xa8a0e991, 0x80333b16, 0xd789f225, 0x23132001, 0xb630d736, 0xc9b78b49, 0x23233d98, 0x86ddd404, 0xadd69ddf, + 0x2d155f73, 0xb4d29639, 0x6f479792, 0x24e04b6e, 0x651cc466, 0xd37bec23, 0xb70048e9, 0x901dbfc2, 0xfe1c7925, + 0x88058790, 0xc553c85e, 0xedd0ceac, 0x3a9cb08c, 0x7e956320, 0xaa753469, 0xbc5e6e60, 0x6d8fe162, 0xd8fb6e27, + 0x5c724e90, 0xa481d24f, 0xccd73b79, 0x5e8a7adf, 0x0178e04e, 0xd5e9857b, 0x20aea369, 0x75d3ac2a, 0x05f2be02, + 0x23189b56, 0xb8815746, 0xd4049e5e, 0xb5607ab0, 0x0d914800, 0x59dac230, 0x9409820d, 0x71655e35, 0x99177b9a, + 0x20451443, 0x7db8caf0, 0x6c66ebf0, 0x8b72484b, 0x343ff80c, 0xe8b3308b, 0x5763f9e3, 0x2ab7c4eb, 0xa0db2c83, + 0x378e300b, 0x5ba9ca40, 0x3bbb7851, 0x916a8223, 0x56463766, 0x91114420, 0xc6c8674a, 0x4882cccc, 0x1d914c6a, + 0xf5a5464e, 0x5b8af1a0, 0x8f58b319, 0x9de93c29, 0xd941f10c, 0xd6b0842f, 0x4ad322b5, 0xe6491958, 0xfefa4151, + 0x4d8ffb75, 0xb05196ff, 0xc4e00234, 0x1f21838e, 0x69549e9d, 0x0f334dd1, 0x78b96971, 0x0816eeda, 0x92ea0c08, + 0x41d3389d, 0xfaa934f4, 0xff515dde, 0x1f34ca6b, 0x77af3704, 0x3a5707a1, 0xc5a26db6, 0x80e8449f, 0x256393c0, + 0x0a7da6d8, 0x61eff00e, 0xa55b044a, 0x208d0f81, 0x69448751, 0xfd7cb042, 0x3ac82bcc, 0xd42f252d, 0x177a792c, + 0x150be4df, 0xb2cfc031, 0xbf247a06, 0x997975cf, 0x8db2c79e, 0x7a5cff5a, 0x15ace551, 0xe9cdb1b5, 0x0937d109, + 0x4dc0eb43, 0xab120938, 0x55b5d214, 0xcca8b4c0, 0x99ab0e51, 0xfbd6423d, 0xd4ef729b, 0xcb09dadb, 0x3a19aa67, + 0xb948af6a, 0xff064758, 0x0a2f4f9b, 0x435a1272, 0xcce37fdb, 0x1c1d1c73, 0xc5db2115, 0x2d3dd677, 0xb6354160, + 0x81dba5f2, 0x0a607d94, 0xfa659f8d, 0x86efe085, 0xe0a654fc, 0x4724c0e8, 0xe6464853, 0x59ce88f4, 0x5a002a06, + 0xa8857d13, 0x2074b008, 0xf5e08f3a, 0x609d059c, 0x8ed9d834, 0xdf4ae456, 0xe51eb4c3, 0x81408433, 0xcca2157e, + 0x964ec4ad, 0x34f62bfb, 0xb2ac8763, 0x763be27b, 0x39217608, 0xf9609a89, 0xe7efc1cd, 0xf6d7b5e1, 0x5f7a295d, + 0x70885621, 0x8fef74e0, 0x3cc3e941, 0x6e3e43c1, 0xfdef73ca, 0x5aeab6be, 0x027e4376, 0x4067fc71, 0x2a4069c3, + 0xd80e4744, 0xd240d9e8, 0x0a48521b, 0x4ed8c8a9, 0xc31efca5, 0x5f5a66e8, 0xe338bf0c, 0x58cbdc49, 0x65c50ea1, + 0x76e32b64, 0x485f2b0b, 0x95836f9f, 0x3f027a24, 0x48b877a2, 0x617632fe, 0xb02f0bf8, 0x3b8dc44d, 0x184b2d85, + 0x445cf73a, 0x870dc9ec, 0x30c24397, 0x5624c2e4, 0x2b932e8e, 0x3f6c744d, 0x7a47e6ee, 0x8fe97ad6, 0x8827553d, + 0x725be1fe, 0x3fed7731, 0xce6101e6, 0xdf0bb54b, 0xfa57098f, 0x27fa4278, 0x33c53144, 0xa4bd4d86, 0xe8538e30, + 0xbe16712c, 0xa9980b3d, 0x5c39c0e3, 0xfc950ef3, 0xd842bec5, 0xa55ad639, 0x136af852, 0xebaea8ea, 0x7eec81fd, + 0xbeff5245, 0xe4fb64b7, 0xe43d8354, 0x9639e3a5, 0x3d78ab43, 0xb929f900, 0x6c5c7288, 0xde64a1a4, 0xff5487f3, + 0x30be6668, 0x1e22c0cc, 0x21f9676b, 0x57916c63, 0x3f6c2d29, 0x046efbd1, 0xd0f1d5b4, 0xbfa8bd11, 0x28df949c, + 0x8acc5dc4, 0x96b80255, 0x7c00991c, 0x5c44c5e0, 0x8d962c84, 0xca6f8374, 0x1b1190dd, 0x83586747, 0x59602260, + 0x1ba0fe8e, 0x105f0613, 0x2baac676, 0xe4dacc54, 0xb91826e3, 0xff733967, 0x5c74c63c, 0x9aff5d91, 0x92f52a88, + 0xc61f0c79, 0xb45cf009, 0x044c26ef, 0xbbf9a9cb, 0x37bb6ea0, 0xffe9cf08, 0xc845a289, 0x61f04957, 0xf6d6e4a5, + 0x8c866571, 0xba3d3ffe, 0xa52226ab, 0x4451128b, 0x05888378, 0xaae18e0e, 0x52cdd79c, 0xfa1f974f, 0xcf93b2cd, + 0xcf841542, 0x47f8c566, 0x28091e1e, 0xe95fea15, 0xc0f39696, 0x9fb7b300, 0x9702af6b, 0x653f5857, 0x2c9a45e9, + 0xed4a711c, 0x53cda8d0, 0x00138cb5, 0x9b827cb5, 0x9aeb4266, 0x259d24a8, 0xceaadd33, 0xd3e1949a, 0x95921f75, + 0x7fc34d9b, 0xa56bd262, 0x7d87c38e, 0x90ece0f9, 0x64d5ab44, 0xb797e0a6, 0x57eebce5, 0xf74872b9, 0x3d6ca62b, + 0x1b6befd8, 0xae3901e3, 0xf0a40290, 0xcc4b842d, 0x49375969, 0x5f17c21e, 0x3096bded, 0xa0353acd, 0xa10fc7ef, + 0x7c595dba, 0x959a5c9d, 0xb9310369, 0x9d96c26d, 0xea707d64, 0x67aed083, 0x7fe073fa, 0xd91c912f, 0xce46bac2, + 0x428317fa, 0xbdaccb32, 0x4e3680a6, 0x936eca3a, 0xb5a79bb9, 0xa2ba82af, 0x11cde27d, 0xd7b674dc, 0xf246d333, + 0x963e1e0a, 0x0d33f6d4, 0x7850b554, 0x9cbed5d7, 0x88ebceda, 0xad547214, 0xed0d37a7, 0x318db4f4, 0x62869aef, + 0x4242e9d5, 0xef282adc, 0x07fc9b62, 0x105d67df, 0xefa713de, 0x188ade61, 0x46ad9fc1, 0xd1fcefba, 0xad929ec6, + 0xc4b54f03, 0x9d732b79, 0x367562f4, 0x70c5880f, 0x7d529a7c, 0x1dcdbc43, 0x7cc55300, 0x48bb883f, 0x1ca7cfe2, + 0x3b9a32f9, 0xead22b69, 0x3370d10f, 0x09890e47, 0x20146350, 0x81bc4c6b, 0x76975a7b, 0x72b79f3f, 0x17d7f19b, + 0x9a1d4c73, 0x57aaff9f, 0x736ea0c0, 0x31371109, 0x5e71dc89, 0xa4cafccf, 0xec451dd2, 0x6f18a1da, 0x98f6e00b, + 0xf3cbf816, 0x4504288e, 0xae83325b, 0x5b069460, 0xfde9e168, 0xb6b6f681, 0xac36692e, 0x91a3677f, 0x8fafc2bc, + 0xc06f8b69, 0x04c2bce9, 0xcab2b531, 0x869b4511, 0x0db4776a, 0x8f6d8814, 0x6b15f546, 0xd4523432, 0x8496ac1e, + 0x0f10c74c, 0x8dccb619, 0x71fae047, 0x50d95475, 0xcfd51599, 0x4d2fc0a6, 0x75fb76da, 0x15667084, 0x7a86cec5, + 0x6ca6ec9b, 0x6f2ffc2f, 0x2145ce60, 0xaf6b2559, 0xbb4bfabb, 0x6e4877ef, 0x32b2a196, 0x9b0d8a5f, 0x09749250, + 0x65b4dab2, 0x2d0a0f6f, 0x6e599146, 0x7845fd3e, 0x38a491f3, 0x2cc8c88d, 0xf86ab822, 0x8cf424bf, 0x9fcb01b0, + 0x71982069, 0x57a139c4, 0xa81a6739, 0xf97211b0, 0x0ea5a45e, 0xb625e8cd, 0x8988aae8, 0x92b04517, 0x38a23c70, + 0x7689f9b0, 0xcd558181, 0x54da69de, 0x646c729a, 0x9bbf3aa5, 0x392a2708, 0x3cf6c78a, 0x1895ebf0, 0xb4052574, + 0x179faa49, 0xce1948fb, 0xcd4eed0a, 0xa951c5a2, 0xaf58366e, 0xf8e44245, 0x6af91341, 0x086a14d4, 0xb27895ae, + 0x68b8e6f8, 0xe6449f4b, 0x5972f126, 0x8f15dba1, 0x077d32e6, 0x7f3b3b8e, 0x6521b928, 0x4c8e8514, 0x803b16f9, + 0xfd5f429f, 0x1df8efc9, 0x69260f8a, 0xc1ab4c13, 0xa638c801, 0xe73e547e, 0x8c69ea0e, 0x22da2a99, 0xfccac0bb, + 0x6479d13a, 0x5fd0793c, 0x2aae0197, 0x85052df3, 0x5f9fc3c4, 0xb115c0f8, 0xa5925102, 0x5fc5286b, 0xa8c1fd28, + 0x2a159fae, 0xc8cb8363, 0x6ce0861a, 0x2ac6ee8a, 0xf3d9d6cf, 0xb489cc03, 0xdf2195fe, 0x039fb959, 0x7917f3aa, + 0xf58229e1, 0xefd01297, 0xebc3e914, 0x2a1c93a7, 0x6b26283b, 0x8dd2020c, 0x6903a93f, 0xc9468f11, 0xb891291b, + 0x06bb3070, 0x83d7cfbd, 0x88b56cb6, 0x7d798032, 0xea2065ba, 0xcc177651, 0xc1ad83fa, 0xd4c28c15, 0x9b79a716, + 0x7c4665bd, 0xe4b4f97c, 0x7577361f, 0x5487955e, 0x8a58358d, 0x33c2ce54, 0x72ca6e2b, 0x1a6aef32, 0x1b0d9480, + 0x9a92aa64, 0xef3de55f, 0xfe813458, 0x77703591, 0xf6f085af, 0xb33f8d27, 0x58bcf0dd, 0x222f0f70, 0x6c7e889f, + 0xeb2658db, 0x3dfc5f99, 0xbdf79e35, 0x03ca3f38, 0xe9979860, 0xe5004d66, 0xb92ec371, 0x34689b66, 0x5d8e9f3d, + 0x3722e4e2, 0xeb37d518, 0x38a40e07, 0x1a1eaeb1, 0xda6de347, 0xb0e166e6, 0xbbcaba40, 0xac8ec74b, 0x453614ec, + 0x5f6a4421, 0x271266d0, 0xe9e8e984, 0xf7b1e455, 0x4ea86414, 0xe8106465, 0xaf205ff9, 0x1c956beb, 0x1bb38964, + 0xfce32a4d, 0x019521b6, 0x60e85d29, 0xb20d7139, 0x678eac49, 0xea4ba891, 0x41ba2b5f, 0x79d032f7, 0x97c9ff67, + 0x89a6af1e, 0xf6d8c522, 0xc0818207, 0x07165f41, 0xc89421f1, 0x2e39d388, 0x816756c5, 0x647b0943, 0xacd22cac, + 0x46293d68, 0x6db23907, 0xec311e56, 0xdf0149b8, 0xed0d9e40, 0xbba8f7ae, 0xa0cf96dc, 0x87f8e816, 0x4b8ba2f6, + 0x9e031bbb, 0xa012a393, 0xa0f7fd74, 0x68811499, 0x98212a57, 0x9ec705ed, 0x64e68bd4, 0xf850e677, 0x49cfde4b, + 0x54291461, 0x2e65fb91, 0xc308a579, 0x0cc16092, 0xee15dc1c, 0x47e010a6, 0x6cb57440, 0x68bdf48a, 0x8caf1f87, + 0x3664c7d2, 0x07ccdfac, 0xea5b5a4e, 0x4b250991, 0x93189bf7, 0x56572c2a, 0xb7a8bec8, 0x2d13e7af, 0x289717e4, + 0xe0e3f2e3, 0x91603dc7, 0xb117ca8a, 0xb9b2e6ba, 0x79ab3ed5, 0x51c09fe3, 0xf86decc8, 0xadca69b9, 0xbe82872f, + 0xd9fad42a, 0x89a18536, 0x65b7dace, 0x1ae34809, 0x0657ab58, 0x2773e184, 0x8949a706, 0xf6a85175, 0x313eb5b9, + 0x49275440, 0x39f7c43c, 0x14699884, 0xde4ec94b, 0x3a0ed21a, 0x27e6ee75, 0x4c53613e, 0x67906808, 0x7f7149a3, + 0x94091829, 0x95262190, 0x32bb97c1, 0x8982f3c3, 0xecc98f5f, 0xfca8a7fb, 0xfe737921, 0x2c343e9b, 0x22f71244, + 0x16ffadb6, 0x1cca8759, 0x86eee041, 0x088bf553, 0x1986de3d, 0x18a64924, 0xdb3bf17b, 0x1e4d57a6, 0x75631bf2, + 0x59bc4ebb, 0x818e814c, 0x1538149c, 0x1b4a0b55, 0xd5349e2c, 0x9f82fb2b, 0x7a728025, 0xc467d790, 0x9669b4c1, + 0x4c53ccbc, 0x0d078639, 0x22337d2b, 0x5a11e743, 0x3a3fa8d9, 0x10a4ce9d, 0x641f41d9, 0xad779394, 0x1477816e, + 0x5b91cde5, 0xdc83ea6c, 0xa10c56e8, 0x7bf32d2b, 0xeba3b195, 0xc7874fcc, 0x8ba0ce89, 0xb61c338f, 0x44810e96, + 0xfcf512f6, 0x02eb6ac6, 0xc0077faa, 0xa556d93a, 0x0695981c, 0x0801e78f, 0x815dcc3b, 0x14e35d73, 0x7cd136be, + 0xe4bfd515, 0x64f3bf43, 0x26ed6006, 0xb3484e1f, 0x7c245d29, 0xc6509265, 0x9383b76f, 0x012d968a, 0xe5b108fd, + 0xf8bde1aa, 0x1e38ae69, 0xcbee5c45, 0xc5596ea9, 0xbf7ff53e, 0xe567d354, 0x22a2d250, 0x5ef4f712, 0xbcdbc4e1, + 0x81b997e5, 0xd9a73b22, 0xab736069, 0xc20c2bba, 0x6efccf2f, 0x47234c65, 0xe6bb6410, 0x7e77207b, 0x32807060, + 0xfaa67aee, 0xd8ac176c, 0xcb56ab63, 0x91a467c8, 0xeea09e70, 0x571c6b4a, 0x4fa83bfa, 0xd7dafc7f, 0x4f04d856, + 0xde595cb3, 0x2695c50e, 0x211dcb00, 0x436e6c1a, 0xeb494a70, 0x5d7cd910, 0x8bc01ee0, 0xcc58c000, 0xe431a679, + 0xa3401b0d, 0x79dc14c6, 0xf67abd5c, 0x52fe050b, 0x78c90777, 0x015cd7e7, 0x6d891093, 0x89ff8ed6, 0xc83b64e0, + 0x51c7f972, 0xbb715ddb, 0x83bb3ed6, 0xa0bf1d27, 0x056538e0, 0x2f40e777, 0x561f3f07, 0xfd0b83ee, 0xa3c999f8, + 0xd878121c, 0x32147991, 0x5fd27e3d, 0xcfc9c2a5, 0xf20b94b3, 0xcd0af9d2, 0x42372258, 0xe0ecd28a, 0x542e31f9, + 0x0f19a3a7, 0xa29dc6d2, 0xff2e5c34, 0xb7f6070c, 0x1d9b258b, 0x36d00d32, 0xa1cfc2f2, 0xff081609, 0xd2cdb3c8, + 0x0ebb69fc, 0x432225e8, 0x16694f8d, 0x9ca2380b, 0x7c6b394a, 0x10498875, 0xe0def286, 0x873d838e, 0xf1c943b5, + 0x2fa42367, 0x4cec6d76, 0x9fda76b8, 0x2e2e0287, 0xac79e5f7, 0xd8536970, 0xa34c126b, 0xe29415f6, 0xf69b0b17, + 0x44f3341c, 0x88f65e9c, 0x48f7c3d6, 0x125f7564, 0x997ed4cc, 0xb5c92f39, 0xa825fabf, 0xb108d749, 0x9cd29d95, + 0xde2b2e2c, 0x0d343e74, 0xbd77b912, 0x3f319dec, 0x0cebbf59, 0x2b836cd3, 0x29ed47e6, 0x379f8a77, 0xf12e55a1, + 0xb88a9910, 0xb350b050, 0xa68e1eaa, 0xb936d7fb, 0xfde442de, 0x3ef1e452, 0x8a996872, 0x0643aa8e, 0x7f49d5d2, + 0xdac84d69, 0xde2e2ca8, 0xb960edd6, 0x89004ee1, 0x78cdea5d, 0x09b53547, 0x70e11bb9, 0x32e9fdf7, 0x17890b63, + 0x37045004, 0x01fe6e71, 0xf2e4686d, 0x5420c748, 0xdbf44963, 0x5eff37fc, 0x051e1a4e, 0xd68d3136, 0x64142a77, + 0x865130d8, 0x4cf33662, 0xf002d33a, 0xa87dcd05, 0x7d762dfe, 0xda617b5c, 0x7a825520, 0x1eb20486, 0xa268c049, + 0x7dd204cb, 0x17e4378c, 0x86aa87dd, 0xe68a30b3, 0x383d4336, 0x203677ba, 0x5edc667a, 0x90bcd908, 0x35fbc18c, + 0xc236860e, 0xff40bbb8, 0xb0a0dd49, 0x0f35163e, 0x060131f2, 0x0391a10a, 0x36202848, 0xc79db493, 0xc2951049, + 0xadac298b, 0x4388e0ca, 0xe914d29b, 0x723ba919, 0x3f31e0e9, 0x24f8fcfe, 0xbff24410, 0x4b4b725b, 0x0e242bd5, + 0x4b1d32b4, 0xe5d9fa98, 0x62f7ec95, 0x25340f0a, 0xfdfe9089, 0xd11d7968, 0x600e7377, 0x76148b91, 0x06780c11, + 0xd5baaf34, 0x6d468c5e, 0xfa4b262b, 0xb101f8e8, 0xdc84bb8e, 0xc98d6e49, 0xbd82c097, 0x0fbf7599, 0x8329fe73, + 0xff3954a2, 0x4d49c389, 0xb3493920, 0x9a60c33e, 0xbab5fa17, 0xbcb0d8bb, 0x33d90308, 0x971180c2, 0x9c9feaf1, + 0x0787f532, 0xe331c411, 0x41f362d7, 0x922df75c, 0x0397fc4d, 0x5e65e90c, 0xb7c311c3, 0xd1ce9ea4, 0x56488f8a, + 0x9650a4cc, 0x86dfd274, 0x447124cf, 0xe0b831c7, 0x0d0ea00d, 0x6a7d8413, 0x9ee08440, 0xa44eece1, 0x725f6a33, + 0x2e5e614c, 0x1756bc8b, 0x58bee20a, 0x526bf7bd, 0x17c94f64, 0x0ee621f0, 0xa976218f, 0xd7dbbfb9, 0xa4426124, + 0x0ee3b621, 0xea09d77c, 0x17cd7c67, 0x41433904, 0xd23571dd, 0xa8ba8839, 0xf87c7ac6, 0x5a69edd5, 0xcc483b0d, + 0x24cad04a, 0xffa77f3b, 0xad1da4a6, 0x4e590fe4, 0xc455de83, 0x2c846666, 0x94b51530, 0xc76e7f35, 0xe3fd3c37, + 0xa33b39df, 0xbc7d3afb, 0x8054072f, 0x53293480, 0xa6ef83c8, 0x318b9f51, 0x658b9fca, 0x6c7d7b17, 0x2dcc069e, + 0x18701e45, 0x790bd4fe, 0xe16688d5, 0x86a048a0, 0x886467e6, 0xd67d33b2, 0x86cb2de8, 0x6bfc4b65, 0xece90955, + 0x63a8e720, 0xeca3c286, 0x956aeded, 0xbf11107a, 0x281c4675, 0x69207220, 0xcbf7d194, 0xf753b476, 0x6ba3bd78, + 0x92917eda, 0x2046762a, 0xb27d8cce, 0xf11aff0e, 0x3e8be045, 0x7cf989e0, 0xfda125ea, 0x7a68cdf7, 0xb6c54ae8, + 0xae479be1, 0x50ab9777, 0xb32abf68, 0xd9a66bb9, 0x7b11906c, 0x34e8df78, 0x2fecac04, 0xe29e1edd, 0xa60b1659, + 0x3f719d7d, 0xa7798928, 0xba483fa8, 0xa2f915e0, 0xfe12c842, 0x25633ae5, 0x587f457b, 0xf0b95668, 0xcaf1153b, + 0xbc766a80, 0xc72953ca, 0x723f674c, 0xa125e78f, 0x0f37deaa, 0xf2e43ed9, 0x14aaf86a, 0x80edf05d, 0xbc3b351e, + 0x31993983, 0x8798ab62, 0xc7880106, 0x04f9a605, 0x2d282d48, 0x43b63cff, 0xf07f39d4, 0x2bfe0fa1, 0x2a933570, + 0x03d9a268, 0x9b37b614, 0xc787da95, 0x8362b649, 0x0f63a2fb, 0x4303ba82, 0x655664f8, 0x749ac295, 0xcb3837b0, + 0x4c62ef2e, 0x9e41596c, 0x9a217ff3, 0xd1997b12, 0x722d5bd7, 0xa871f823, 0x81ba921a, 0xb72bb64e, 0x7765eb8d, + 0x7e27986f, 0x24bb0832, 0xbab6b91c, 0xe195bc71, 0xf5aa2a42, 0xd71c11ec, 0x3b94bfe0, 0x1c8cb805, 0xafab98e3, + 0x4eb42b73, 0x499781ca, 0x7f335f08, 0x2575279d, 0x2ecd3781, 0xd7867ce4, 0x107070db, 0x6efe376c, 0xc666088e, + 0x8186f5d3, 0x253d8f12, 0xcea69f06, 0xc8c32500, 0xd4758a09, 0x508b6f47, 0xe8d3ba43, 0xcf1fbcbe, 0x4ee53507, + 0xb7403f0d, 0x02e03b3c, 0xe556e285, 0xa80c5afe, 0xa4726ddf, 0xb6cd91f4, 0xbafdbac0, 0x6d399fb5, 0x9d990abf, + 0xbb6df5ab, 0x22716c12, 0x04e9f1f2, 0x6c18c816, 0x02ff2c2b, 0xced645e4, 0x8def711c, 0x0c481d6d, 0x90123196, + 0xd8220ab1, 0x8ef82770, 0x3761af5c, 0x97b45281, 0xc8a7bebd, 0xd5e01b9a, 0x9dd4bdaf, 0xc64f1f52, 0x401e4cbb, + 0x4652113c, 0x1c8117c4, 0x3194adf8, 0xe7e323e9, 0x21c3857c, 0x97b57817, 0xf11f0308, 0x840fcd17, 0x6d8a6477, + 0x798afd9d, 0x750eeff2, 0xecfd776b, 0xf6821b09, 0x7387a359, 0x457b6cc5, 0xb4de1932, 0x7a6a1395, 0x62e0e0b8, + 0x41a127d0, 0x7e7bf133, 0x34cf227c, 0xc876345c, 0xa2a56bb7, 0x3a44d9cc, 0x1951259f, 0x76941f2c, 0x64318227, + 0x834e175e, 0xa61d1e18, 0xa537f346, 0x3e06d430, 0x5d51a247, 0x2658c0f7, 0xb5087634, 0x9e565fe0, 0x650d2c7c, + 0x48f2a04b, 0x8959aa79, 0x4775ac2f, 0x073a7ce2, 0x6e5aff64, 0xbd3fa880, 0x4d1b2fbb, 0xe9ea415f, 0x5a9fcdb2, + 0x59705818, 0x702ca783, 0xba8c1a1f, 0xfffd68b3, 0x3cdbe437, 0x24f4f767, 0x1500ba82, 0xe1fda9de, 0x5be0fb7a, + 0x7811d23e, 0xca871f0d, 0xf51d3741, 0xbecd3f93, 0xf3ae1dac, 0x2f0c9991, 0xdb960099, 0x91d86b02, 0xf0b0b053, + 0x4db19c82, 0x3c7599b4, 0xe87e1157, 0x4f8af2bc, 0x88ceb624, 0x029ae22f, 0x7b10f412, 0x87b4f5aa, 0x9c5b7e4d, + 0x807c2c99, 0x33330294, 0x48d83cfe, 0x952332fb, 0xb23e71f8, 0x2d4fc6b3, 0x2c5e463f, 0xbd264ce8, 0xfbbf17c8, + 0xdbfee850, 0xc55d949f, 0x9417ed39, 0xa92ed01c, 0xd5bd5937, 0x19b7a758, 0x4463efd0, 0xee11324e, 0x72dc78a3, + 0x5fb97f68, 0x77902c78, 0x720618f6, 0x7d5972a9, 0x700818ec, 0xe78d7205, 0xbd195a5c, 0xa153367f, 0xe0cba9f3, + 0xd9701ea7, 0x62d6fc60, 0x71e0fa49, 0xc6f2cd26, 0x6cd56471, 0xd5183a63, 0x74f7dbb5, 0x41935aa0, 0x7a6cc46c, + 0x0ca3ca98, 0x653baa88, 0x92b0b7b4, 0x0e5ff9a8, 0x029b628e, 0xc12819cf, 0xf5410a43, 0xcaf33f7d, 0x7d7f6bbc, + 0xc99f02c1, 0x3b3954fe, 0x77bbd568, 0xc13111c4, 0x01808830, 0xe6f5f063, 0x6c13de3b, 0x52c5322b, 0xb136619a, + 0x7163eb23, 0xc5eb08eb, 0x09cdb630, 0xf1e4f364, 0x465ede0f, 0x45196e5c, 0xdf10f0d1, 0x4e19c867, 0xe25b82e7, + 0x999ed759, 0x003cc6f4, 0x8224e9a6, 0x01bcd24f, 0xfa40996c, 0xadd72bdd, 0xf1fc5007, 0x89777187, 0x87b94727, + 0xebbef147, 0x4c1dcaa1, 0x7bec5f64, 0xc4ab4507, 0xc0513cb4, 0xf1eb6a8e, 0x0a6bb9c8, 0x44231228, 0x8ac4353d, + 0x8a3773bc, 0xd769323d, 0x8b9649a7, 0x44dd4b16, 0x9c2ee972, 0x743fc455, 0xfba4b797, 0x178fc642, 0x53dcd227, + 0xf2772a91, 0x167c0264, 0x9c71177d, 0x9e6cd4be, 0x3a4c26c8, 0xb83f78f3, 0x04c61f80, 0xc600bb86, 0xbeb95517, + 0xc42248f7, 0x30e5bc27, 0xd2661c49, 0xb22d79a0, 0x985a6749, 0xc024801b, 0x12f1c4ed, 0xe2b2da79, 0x753dd5ad, + 0x668243e6, 0xcefdf204, 0x546a764e, 0x17fd987e, 0x32b54a38, 0xb41d657c, 0x9c12da79, 0x49c8fcc7, 0xe8a5fbcf, + 0x181cfc22, 0x9ffa6d34, 0x6ee64f32, 0xbb67eecf, 0x8072c830, 0x6ef3ec26, 0xb3527b62, 0x646a1982, 0x8c8dc12e, + 0x5dca3e73, 0xd7cd86d4, 0xc795cac4, 0xbfca60e4, 0xd57dd5c7, 0xbaec88e2, 0xd2aba192, 0x76186d0e, 0x369f4aed, + 0xd36cdf31, 0x9f6fc12e, 0xb7e82eff, 0x4198fc3d, 0x25645afe, 0x911dad43, 0xef5b7149, 0xcf08879a, 0x7ad75939, + 0x50a72886, 0x40fe6856, 0xdd474414, 0x2009b442, 0x4ff20933, 0x8adabb5d, 0xdeff9b38, 0xaddac17c, 0x8ca15027, + 0x95f30b3c, 0x4b6a2c52, 0x6eb23a2d, 0xa43a9a83, 0x9766ca81, 0x0e4acc77, 0xdfb92890, 0xd5431e45, 0x89bcf021, + 0xae605490, 0x89378ac6, 0x2641452c, 0x4d125105, 0x9a01e5ec, 0x7519c5a4, 0x394987de, 0x5fa43918, 0x6224c736, + 0x61573329, 0xad008cc1, 0xca534d5f, 0x833e1bbf, 0xfee3098f, 0xe95df663, 0x825a7964, 0x3e07b403, 0x56279bec, + 0x0d38999b, 0x85bd58cb, 0x4516c02f, 0x77b972a7, 0x2766bc7f, 0xb532c24a, 0xd017d29b, 0x605d0524, 0xc42d39f2, + 0xbad4e1ae, 0x3ccf2a96, 0xf1d99708, 0x1a44adfb, 0x50befac8, 0x21ea275a, 0x45f019cf, 0x97cbdf71, 0xc9cafdb4, + 0xfe2dae26, 0xb7e0f20f, 0x4fd62804, 0xf9420e5e, 0xef95ce26, 0x7e2677c1, 0xb95dd44b, 0x41c76aa2, 0xe88b85f7, + 0x32bffa06, 0x1cc59e63, 0x4479cf32, 0xc7ca0b78, 0xd432efa7, 0x61b7a36d, 0x2ff48e58, 0x8f1d4a29, 0xaa5400c9, + 0x30bd355f, 0xccdbba0c, 0x690dc218, 0xfe9f00b7, 0x1ba6b43e, 0x0d02d29a, 0xde5e14c9, 0xd9d5f874, 0x95c3fd68, + 0x2e1324fe, 0xe924fc7a, 0xcc65ca7a, 0x120207e0, 0x54001b5a, 0x0dbf310f, 0x3a6d33ae, 0xf35c0af4, 0x6be2c6b8, + 0x603c0adf, 0x06d35650, 0xa9c269af, 0xba2001d4, 0x80b93bc0, 0x13df7496, 0x56f751ef, 0xd84666d1, 0x85fe2b34, + 0x2d50ea34, 0x0d32c814, 0x2f68e238, 0x3c8fb40c, 0x0fba4794, 0x2c84da7e, 0x47a88b65, 0x0e2edf8e, 0x4401b165, + 0x870d094a, 0x15a3f849, 0x8c8f48a5, 0x13cdad67, 0xb591eebc, 0x7af64068, 0xc64b8d5a, 0x9e351697, 0x8f49c6b9, + 0xc141ba9c, 0x3e11df1b, 0x5068c8b9, 0x877ed039, 0x06f4cffa, 0x0b317fa0, 0x366c7b23, 0x8cdcdd92, 0x6761e3fb, + 0x506512d3, 0x28f3fb14, 0x7476df74, 0xdcbce131, 0x6289fe6c, 0x1c11cb85, 0x4eee5e75, 0xaf39d0cd, 0x3d7846d0, + 0x66808c95, 0x7fb1bc81, 0x924613ca, 0xe47b8cdd, 0xdff1a0f2, 0x791ded22, 0x8d275dd2, 0xcefd448a, 0xce29949d, + 0xd6e666e6, 0x84e045e7, 0xfef0da96, 0xaa63ef09, 0x96e4a0a5, 0xc94f6c09, 0x94495110, 0xdbd65dfb, 0x180d96c1, + 0x68fde5c3, 0x2a0e2d0c, 0xaf3e8c65, 0x2ed3d0ad, 0xf0b3dc8d, 0x770fc3c2, 0x01ec58f3, 0xf8d86004, 0x46128efb, + 0x43791198, 0xf6869d59, 0x3c351ce4, 0xb2c4606a, 0x3fa5fa03, 0xdb3efef0, 0x9bda4a28, 0x7f68fbbc, 0x0382c823, + 0xf6cae51c, 0xd5fbd753, 0x7eb4ff13, 0x64f41504, 0x5020cfad, 0x27e94edf, 0x89d0c12c, 0x00947122, 0xc7a159db, + 0x6ae895fc, 0xc1afa03d, 0x418bc01e, 0x19cab911, 0xcd591e12, 0xe4edfa6e, 0x5f2a30ee, 0x7f434c59, 0x2bee3d34, + 0xfc680bde, 0x7472effd, 0x8b44453a, 0x7a582961, 0xbaaeaa76, 0x0de1f3e6, 0xe0643e29, 0x623e576f, 0x9c802e68, + 0x2c159e68, 0xe9137e51, 0x8d20fcc2, 0x26af0efe, 0x9d8ae888, 0x67051077, 0x3dc2a04d, 0x3573a0d3, 0x1b69613b, + 0xcfb27c3f, 0x36c56574, 0x2b670478, 0x8bafaff3, 0xab675dea, 0xf9c21958, 0x84f40c97, 0x00092c80, 0xa1a514ec, + 0x6de60337, 0xc9ff8aec, 0x9faa8849, 0x700af696, 0xc40a9d44, 0x76bd4aae, 0x975030cb, 0x6d1e7ca4, 0x018398c5, + 0xcdbb100a, 0x486483b9, 0x7796b44b, 0x79cdcbcf, 0x27b8f6a0, 0x793d030d, 0xdff37fce, 0x5e08adad, 0x7ef304c8, + 0xc469fff9, 0xac0648c3, 0x2c3840a0, 0xbcf6ff67, 0xfdead478, 0x5b740ea9, 0x53f565b1, 0x1f264067, 0xe5efb3bc, + 0x389a04ab, 0xb8ae7eab, 0x16efc4a9, 0xf2c993f3, 0xf8896a51, 0x9c8577a2, 0x21353fee, 0xd81f4a0a, 0xf93a74a7, + 0xca993f14, 0xc1100a6e, 0x905a2468, 0x3b957d33, 0x908c9737, 0xb7d9f6da, 0x8e74abd4, 0x9ec8c8ff, 0xbe42b662, + 0x0a460b1b, 0x7770b907, 0x6f4189b6, 0x20e8b659, 0x2b5257f8, 0x4b072181, 0x5b2ecdee, 0x486e7cac, 0x890a50b8, + 0xe6d1ace3, 0x7a844cdd, 0x974e63c2, 0xe018583c, 0x88082f5c, 0x9cad3e69, 0x234bf447, 0xa5f4ecc7, 0x5f365a29, + 0x8b5f6769, 0x6766fc34, 0xa6fa7b9f, 0x38f27525, 0x102ab66d, 0x7c56259b, 0x340c0889, 0xe7c0fcc8, 0x72dcbcbd, + 0x33451580, 0x5d97236c, 0x4be1b818, 0x7d2fe431, 0x18ae2244, 0x97c24dec, 0x3139e0f4, 0x6c76e288, 0x88665370, + 0xc95b1b47, 0x8c453130, 0x4e5044f5, 0x24099de6, 0x8237c3ec, 0x40448c5a, 0x8b1e817f, 0x3acb38f9, 0xb84ed1f0, + 0x554d5303, 0x34a56776, 0x147407e8, 0xe6aaa776, 0xae4f3d84, 0x74ab9ac4, 0x7c750cba, 0x224cc04d, 0x5b1f388f, + 0x9e40b066, 0xbf6628f8, 0xcb75ceba, 0x2dd2d04e, 0x22f0fd65, 0x6a96b119, 0x6038450a, 0x980a1ade, 0x5d46da87, + 0x81ab85bf, 0xaee7fd02, 0x79100762, 0xdf1fbc61, 0x6132ac30, 0x53ffdf1d, 0xd03c9a11, 0x57816849, 0xc8d163a9, + 0x1ae6bb69, 0xf37c9239, 0x20ed88dd, 0xe7ba0c4e, 0x0429be21, 0xac7a51b2, 0xa80f4568, 0x0d183454, 0xf5fee168, + 0x0c47c477, 0x04cd6250, 0xa4dbbfdf, 0x0f3890eb, 0x37c4f374, 0x519d0264, 0x43dfe547, 0xfb48162b, 0x1a981df1, + 0xca9ace53, 0xf35bdb81, 0x45a09f0e, 0x0618068a, 0x7f3d8f37, 0xb05eb224, 0xc3e4ce98, 0x6bf4a746, 0xe3fa35db, + 0xedc1b3bb, 0x6c216592, 0xf92ec821, 0x8d28ea39, 0x625d14f7, 0x71129105, 0x8f81e9f5, 0xa20550ca, 0x02c66388, + 0x802f61d3, 0x50117435, 0xd5ae8c5a, 0xab478e1f, 0x1e8611d9, 0xfac83677, 0x7ff1ad57, 0xeabdde27, 0x8baade23, + 0x8f0f51df, 0xd48517c1, 0xd1f32389, 0xf6b8383d, 0xb694adb3, 0x47fe072b, 0xbf0fbc40, 0xadfeaa4a, 0x0592ba9b, + 0xb8c53dc1, 0x88f4923b, 0xb379070c, 0x5898ba99, 0x0d6e4cc2, 0xfddf451b, 0x4fe5ac1d, 0xe95014ca, 0x36d1ec2f, + 0x2a5c6de4, 0x0b9e7cbd, 0x86fba736, 0xe1215211, 0xf1d7c2d2, 0x23e692c1, 0xc3b9b1a9, 0x35dc41a4, 0x87221e16, + 0xec0ad738, 0x91ed49cb, 0x41219d1c, 0xab114130, 0xd786f867, 0xa6e58e57, 0x0fdeaf1b, 0xcbb057fe, 0xc0be5905, + 0xa9d721e2, 0x3b14ad95, 0x44ab8e51, 0x84c1e441, 0x2aae942a, 0x027261d7, 0x31f79fc6, 0xcb7aa0a4, 0xc5bf881d, + 0xfecaaf46, 0x01059e02, 0x6ba52007, 0x7aab4a97, 0x4c255a68, 0x83ce96df, 0x4c461976, 0x3498e55f, 0xa1fb5fd0, + 0xb56160ac, 0xc22eb50a, 0xf57c39be, 0x5bbdd530, 0x4af6f43b, 0x2d629e8d, 0x52092118, 0x794bcdf0, 0xebecc8fb, + 0xc4f5b9f8, 0xbf80b32e, 0x97a1fcfe, 0x2dfc4bdb, 0x8eaa8760, 0xe0336310, 0xff676f27, 0x176b7ad1, 0x1ccaa490, + 0x844700f1, 0x65f66d5b, 0xaf80bcd5, 0xd877a8bf, 0x0c5bb52a, 0x12cea584, 0xccc319a3, 0xfd2b4f9d, 0x5901f244, + 0x893b6226, 0xee478a41, 0x76e6eaaa, 0x3b0835ab, 0xe97b31a6, 0xbde8ab63, 0x3c58ad4c, 0xe9ecd212, 0x7e9a8452, + 0xb3f36767, 0xd81f4439, 0x5e02a6c6, 0x367ee199, 0x0e14f738, 0xfc1c779c, 0x5b5fca57, 0x494ff678, 0x4c0acd7f, + 0x7c623723, 0xe8034c3a, 0xf9dc24ba, 0xad05348a, 0x4509bf4c, 0x515dd9d5, 0x12d4d5a3, 0x73889036, 0x39a38bb8, + 0x6f4bef52, 0x908ce0f1, 0xd55173e2, 0x620a9c92, 0xc9161d4e, 0x08926f6b, 0xa74d8c42, 0x9c5a2f44, 0xc7a70fa8, + 0xef83e9a7, 0xf42e2d58, 0xa5684db8, 0xb68d8200, 0x3b16ff75, 0x1c52477f, 0x55b27fc0, 0x7efc0047, 0xd95bb883, + 0xb0c839d1, 0x5add869c, 0xfa144709, 0x7ddc56e6, 0x3cff8a4a, 0x28944bc0, 0x686a029a, 0x43ff5a09, 0xedc45d94, + 0x0bd36245, 0x64286ed3, 0x0b737639, 0x43668ba7, 0xd93e1852, 0x02b0c332, 0x844c3d02, 0x2b1073af, 0x0ffaf7c3, + 0x9c97bcda, 0x5cebafce, 0xdca60794, 0x6173303d, 0xa442badf, 0xccf3fc54, 0x991cf7db, 0x4e67a9ad, 0x0c1f8e2d, + 0x56b30b34, 0xcc5123a9, 0xdf6622e0, 0x9937d35b, 0x3f6dd7bb, 0x8ce0864b, 0x69c17091, 0xa7df49d0, 0x33303256, + 0x9f0d0ba1, 0x4a513618, 0x24c93ff6, 0xa7484fa0, 0xad684b84, 0x42402c2e, 0x28fafa2a, 0x76ed2da1, 0x98d6fcc8, + 0xbfe8f553, 0xee86c46b, 0x33e8a20a, 0xf45c3eef, 0x6dc09e9a, 0x878e15b9, 0xb057f926, 0x14023ad0, 0x5599455f, + 0x7d353f97, 0xb5fa798e, 0x6f920135, 0x5c51a8d9, 0x43698840, 0x5150a3c2, 0x91c881d2, 0x93daf015, 0x2c2c7095, + 0x928a4e83, 0x262722c9, 0x37d4928c, 0x32865181, 0x32d143c0, 0xcd2de9a9, 0xc80fa486, 0xe103aafb, 0xc2461c6f, + 0x8ecb0cb9, 0x8ef1948d, 0xa31d4863, 0xada62a38, 0x9a7e9a89, 0xe81f0fd8, 0x73457401, 0x83fe2a28, 0x4edc6c8c, + 0xa3396305, 0xbc5c9fa9, 0x0b20f3d2, 0x4ceb3ed4, 0x4988890a, 0xb146cb25, 0xfb87d767, 0x2c8322aa, 0x5c9def78, + 0x034dd196, 0x2655950b, 0x89327702, 0x4c4950f1, 0x68e92ed0, 0x6be51a35, 0x091ee2ad, 0xb7b23487, 0xeb18a132, + 0xbe7883a5, 0x23083470, 0xff83d94f, 0xc9f14bd3, 0x8bf09fc3, 0xa26fd227, 0x8aaa7d6c, 0xe19a2531, 0xc8648271, + 0xb3f477b6, 0x43f76de8, 0x280f15ef, 0xd7b629ef, 0x5f4031b5, 0x9c0cbc28, 0x5e3b6dfd, 0xf1ad74f5, 0x773e6ae4, + 0xc0edc9f4, 0x41b0bff2, 0xcb2cb54d, 0x15f5a303, 0xf87066e6, 0x5f4e7d0c, 0xd84b07ea, 0xb1e44adb, 0xb83e9d12, + 0x7efd6375, 0x7817c4bd, 0x9f61c189, 0x4bc280fa, 0xb8a4dbb7, 0x61c53ad7, 0xb39b9551, 0x2503e7a0, 0x83bb91cb, + 0x3b34fcb4, 0x2fc4aeec, 0xbdf8a38d, 0xa5999c6b, 0x9115153f, 0x4b8c8375, 0x2e4355dd, 0x2d56fc6f, 0xa2c7bfb3, + 0xca3d3157, 0xd6523937, 0xa8628a5c, 0x5f61cb30, 0x41e32720, 0xaea8dcfa, 0x403256cd, 0x72c7f512, 0xf0187915, + 0xf21d48df, 0x7aa599e3, 0x561f626f, 0x277ff4a2, 0xf5d9c7fe, 0xef4af5b3, 0x9a925e3f, 0x2b3ab4d2, 0x80a2bcce, + 0x37313b00, 0xbc50adf3, 0x6f2008e8, 0xc7aaa25d, 0x947dcac5, 0x75170de8, 0x006a31af, 0xaa0dc7f0, 0xe2df55c7, + 0x7e800f1e, 0xc38bfbb7, 0x98294d86, 0xe04b9567, 0x9b62c307, 0x9622b115, 0x6aeabec5, 0x52417eb1, 0x4abe680f, + 0x781004fe, 0x145d5533, 0x5ead2287, 0x73e0446c, 0xcd941417, 0xdeb6244f, 0x0e61155d, 0x655bae38, 0x3e688e1c, + 0xb645a00b, 0xffe4dd23, 0x06541fba, 0x0086a0fd, 0x857e6169, 0x349d75f5, 0xdc85622f, 0xa5dc2f4d, 0x5a8a060d, + 0x2756ca49, 0xac574f42, 0x696978ee, 0x6087345f, 0x5c38aa3e, 0xf2a18a83, 0xb295c86a, 0xa932a4ac, 0x15e6fc3e, + 0x1563ca49, 0xa098d6e5, 0x2bb5acb1, 0xb5321de5, 0x53669d6d, 0x030adcd6, 0x6228e10f, 0xde2c77a4, 0xa4cf1280, + 0x59409e78, 0x66d41b04, 0x16323ae1, 0x4f64781f, 0x3c20e0ae, 0x1be84663, 0xef266b0e, 0x0654a9b0, 0x8985d39c, + 0x3173f9e9, 0x1a0c5c59, 0xb45b90f4, 0x56ed3482, 0xd5c3dc40, 0x0ec262fd, 0x6088719c, 0x8bf31168, 0xea7de4ad, + 0x4be2f36a, 0x0cebe2fa, 0xdefee2b1, 0x44adb2f2, 0x86a6cd51, 0x2e9123e1, 0x43b75db0, 0x99d38cfc, 0xb51be1c5, + 0x7a307e69, 0x327a6a78, 0x135dd203, 0xf84f6eea, 0x63cd3d79, 0x705683a9, 0xd4b43bcb, 0x9f8c24ca, 0x58954943, + 0xff5754e1, 0xeb2381e3, 0xc2853714, 0x2354eb74, 0xbd2ade0e, 0xed472c74, 0x5e11efd4, 0x72b4d765, 0xa3135f21, + 0x1937beb5, 0xf335a69c, 0x8595929d, 0x53a05229, 0xa115de42, 0x66efb982, 0x3aedb40e, 0xa2862494, 0xfd4344ab, + 0x2fc438c4, 0x9bf76f6e, 0xa97e59ec, 0x326bab72, 0x28f1d517, 0x236cc15a, 0x623b465e, 0x65b859ee, 0x92088a8d, + 0x25bb04e5, 0x27b4fefb, 0x8c24b464, 0x11eac599, 0x1c1a796a, 0xb957047d, 0xc78a2c33, 0xe1016357, 0xc5d0ee80, + 0x8b9c29ba, 0xbec5ec68, 0xb82f5b9a, 0xb83b396c, 0x79bf0f3c, 0x287036ab, 0xe65a09e8, 0x33540fa6, 0xf06989a7, + 0x8c66de4b, 0x803e82dd, 0xf3b9326c, 0x539e2fac, 0x6424044c, 0x1af4ccb3, 0xa2295e76, 0x91485659, 0x7f6f8696, + 0x5872a3e5, 0x7eaf81b1, 0x708b4980, 0xecb70482, 0x361f49f9, 0xb71ed318, 0x05aa1eac, 0x64cb2fca, 0xd1ee1b07, + 0xea3f99ce, 0xce2010a1, 0xa071155c, 0xcf97e009, 0xb95f6eec, 0xd66c2cfc, 0xa4dae105, 0x1c7f534c, 0x82c69378, + 0xc179d2f3, 0x0ebad05f, 0x32fb6884, 0x574bca13, 0xa1c5cb5b, 0x310a61c5, 0xef275619, 0xd130f649, 0x68620c57, + 0x586109d0, 0xa427f189, 0x8e51dea4, 0x60bec167, 0x53a69ec2, 0x0d2472b5, 0x00056c3c, 0x03cec5ff, 0xe2fb97ed, + 0x2439c502, 0x8a82511a, 0x2c1feab7, 0x1e103434, 0x50096f09, 0xb9b9af9a, 0xdb227096, 0x2ec86c7f, 0xcf3bff46, + 0xe02a47f6, 0xb69c0ff1, 0x6a62e3fd, 0xf3d9dcfc, 0x2f364e7d, 0xbd091e39, 0x5b0ee6c3, 0x78d760b1, 0x3d124c8f, + 0x9eb8baac, 0x70b26528, 0x342487ac, 0xd9f3bd54, 0x14159a0e, 0xa1988287, 0xe9222b9a, 0xb1337874, 0x66468448, + 0x77351058, 0x2fd893d7, 0xf2923c10, 0x7d98b939, 0xc9718872, 0x961c3769, 0x7db5021c, 0xeb47aa01, 0x63a4a725, + 0x4dcd1a30, 0xcbc9b619, 0xdaabe693, 0xa3b74ad4, 0x934d20e4, 0x7dfd315b, 0x4d446152, 0x4c7fbda9, 0x4ab562ab, + 0x7a5e26f7, 0xf69d8d28, 0x5d87259c, 0x5a589bf4, 0x7d404e8a, 0x4937e863, 0x0906e79c, 0x66c45646, 0x874a1949, + 0xfcf95ef5, 0xcfbc5256, 0xc535d923, 0xe8cf7c49, 0xfd364b67, 0x009dc958, 0xfbd1b5c6, 0xb4850b88, 0x381dc993, + 0x2d88d087, 0xc9b65635, 0xd6e33c72, 0x795911b7, 0x39e6ba37, 0x506b9b8d, 0x2b68e05d, 0x06ff0c65, 0x95d5242e, + 0xd60c6354, 0xe538b4a3, 0xdc2d2da8, 0x06259d13, 0xa5dcebd0, 0x59dfbe79, 0xcf2fc243, 0x85262df6, 0x274cb8f8, + 0x1a081a12, 0xb87fd5e4, 0x112076ec, 0x76a6a789, 0xe314528d, 0xee46a47d, 0xe3302f8d, 0x0cd70c2d, 0xde2430bf, + 0x892192f8, 0xdf16fca0, 0xdf5e287b, 0x2f61f9b3, 0x421852e7, 0x937316c3, 0x494089e5, 0xf13764c8, 0x17174ff9, + 0x82299a7d, 0xe1be7836, 0x5a45e596, 0x6d8fb65a, 0x2dacb259, 0x7e627e8e, 0x51e810bb, 0x505ab32e, 0xb74c9242, + 0x946e806c, 0x83d7b084, 0x577501b4, 0x48c2d570, 0xc0d0245e, 0xd497d7a0, 0xcc00972c, 0xf5ea41b8, 0xa7b8046b, + 0x04edde5c, 0xec0520fe, 0xed6e736b, 0x760a1ad1, 0xfd18d9cd, 0x5fbcd33b, 0x7a1aba1b, 0xc4f7967d, 0x1f80ad06, + 0x47e0de10, 0xe30d374a, 0x47798e64, 0x0ddd7628, 0x554a0095, 0xec16592b, 0xb4b6b694, 0x40d48a32, 0x8cae7375, + 0x66b3bf4b, 0xf3c6a2ae, 0x17bd961d, 0x197c44ae, 0xd291e9b0, 0x4ff34074, 0x67924877, 0x8a018fd9, 0x41cb02e8, + 0xf47ac036, 0xcb939be1, 0x7090c9f1, 0x4538c89b, 0x38adfd3d, 0xd4f966b4, 0x82000151, 0x166ee01b, 0x073344d8, + 0x972150a3, 0x9f44ff30, 0xe9438ca1, 0xff39c494, 0x433cba63, 0x5e5b9c23, 0xde53a022, 0x23031b52, 0xf4159689, + 0xbc9d28ff, 0xf0ca9da9, 0xaa9f932f, 0x41720f80, 0x69dd3de1, 0xf3249124, 0x5d2b581f, 0xa01bdd02, 0x54bae589, + 0xe96737a2, 0xfac3de97, 0x0b4e8267, 0x316cb131, 0x45624393, 0x633296dc, 0x184a4e6f, 0x90680cb8, 0xecada60e, + 0xbb50ce03, 0x24df8ae5, 0x874cab30, 0xd0c632d2, 0x5793afef, 0xc7b3b0e0, 0xa89787d3, 0x2959987f, 0x981a93c7, + 0x77f0f9ce, 0x96389336, 0x4b866bb4, 0xfaf7daeb, 0xe12ea583, 0x6d59b842, 0x9c17135e, 0x8d057cbb, 0x53253022, + 0xbf41d39f, 0x87406788, 0xd8339f6e, 0xc8e8f82c, 0xa0f79e52, 0x81a09a1e, 0x06325911, 0x4913ae1f, 0x457a9e72, + 0xed62c8fd, 0x1471e1c1, 0xcdd7cb32, 0x6a710641, 0x0c042c70, 0x28bdf92f, 0x05b6680a, 0x15f12dab, 0xbbf65634, + 0x3188180d, 0x0160becd, 0xbee8a539, 0x08b24d67, 0xed66bf8d, 0x185756cc, 0xf34a4fa5, 0x82977372, 0x8aa2a1fe, + 0xbcb6f39a, 0x598d936b, 0xaf9cc0d9, 0x83daa331, 0x3a0cd725, 0x2c459ab5, 0x238bdd6e, 0x69efed58, 0x696aa82c, + 0xcfc2e415, 0xce7037b9, 0x92624812, 0x12b1290f, 0xa93b1360, 0xb1e06301, 0x351f564f, 0xa0dc1ba4, 0x906e6c04, + 0xf4e188b5, 0x2b031dd7, 0x90743fb6, 0xda4672a9, 0x54e86ffa, 0x5d158316, 0xa5d943d6, 0x28a3e0d1, 0xe5edb3d6, + 0x2fb8c066, 0xf3e51758, 0x9953b524, 0xbfd0853b, 0xbd26f3e0, 0xaf5ab59a, 0x54a69595, 0x3211aba6, 0xe80e7057, + 0xd90e00d3, 0xc38203bb, 0xa8b8a9eb, 0x14ed78b9, 0xf277b54a, 0x43d92e44, 0x5a32d3b2, 0x71e38df5, 0x113b1c80, + 0xdef2cdb9, 0xf688cea1, 0xe9c2d219, 0x8a829174, 0xf35da9eb, 0x5d9b43d5, 0xf4cc57e0, 0xd66cf75b, 0x5b7172c3, + 0xec5fa185, 0x5fecf8bd, 0xb810c690, 0xc7372949, 0xedcaf8a6, 0x7124c343, 0x8a7a9058, 0x7c8f672f, 0x8bab664f, + 0xbe99d9a0, 0x1fc1785e, 0xa382f844, 0xf010333b, 0x8092d5af, 0x498c329a, 0xb9a7b68b, 0x8de07807, 0x335581e4, + 0x499d74fa, 0x0f1e7c0e, 0xd9932149, 0x21cb2caf, 0xd95f2a2f, 0x5edf9ae9, 0x8743bc70, 0x171337e2, 0x5a0c00d1, + 0x4ac21e5d, 0xb7041f83, 0x67556969, 0x8da69732, 0xd6cb0c42, 0x8ac14f6e, 0xf273179f, 0xc7a98165, 0xad887f4f, + 0x250d98e7, 0x472df18e, 0x99870c3e, 0x0e872c31, 0xa5eecbda, 0x870bd67c, 0x1d120b57, 0x873aa6fa, 0xb933b155, + 0xfd0954a8, 0x4c561919, 0x4237bff3, 0xad9622b1, 0xd5eb7b89, 0x96c2b156, 0x5cba4dce, 0x255c6254, 0x096012a1, + 0xa854772f, 0xcf8a221e, 0xc0c9aa41, 0x4dd38edc, 0xc922f3ef, 0x4591ac6f, 0x49e1cfa5, 0x29fdaa9e, 0xf6852f29, + 0x6d4174ae, 0xb9aec956, 0x3261123d, 0x05946876, 0x5b622196, 0x30235521, 0x3fa35436, 0x3564e5de, 0x3580af27, + 0x9b0e8d01, 0xcd90f92b, 0x5ccb59e7, 0xa48ef889, 0xbb6e3044, 0x6d528df5, 0xb9d2bbca, 0xbe7937c1, 0x6fcb90a7, + 0xe4b7d58b, 0xefb2e5b4, 0x453a7f84, 0xeb94b79e, 0x184b2645, 0x8b40ac04, 0x186f50ed, 0x04e614bf, 0x5e96a1cc, + 0xe5fa664c, 0xc55b7386, 0xcff6c5f6, 0x03e3cacf, 0x848fbb9b, 0xaea2a22a, 0xc021c845, 0x7330f272, 0x2f004ce4, + 0x52fe953e, 0x159eb2bf, 0x8d851783, 0x1d0585c2, 0x83c79986, 0x7c8cdd3e, 0xaf535ea7, 0xe6d05522, 0x0b43cc36, + 0x12a5765a, 0xf7831429, 0xad091980, 0x80536337, 0x9e8a0493, 0xb5ddca68, 0xff0e6862, 0xeaf4b4b4, 0x6f6497ce, + 0xc1f07a30, 0xb4a6d4fa, 0x06bc305f, 0x96d0c4b8, 0xc92ca7fe, 0x000aaf9a, 0x1b92fd96, 0x3c9c99be, 0x69c1d5ab, + 0x2059f5ac, 0xe380c0b4, 0x96004f45, 0x51ae2aec, 0x1646482e, 0xc2faeef4, 0xa14c3d71, 0x442753a9, 0x8dc313cd, + 0xb44c8af3, 0x5bed5bdd, 0xbad184b5, 0x6f50d3a7, 0xd35fcc4b, 0x08ba5fee, 0x5e56427e, 0x59b04d8b, 0xcb5b99ef, + 0x3ce53097, 0xf5b30994, 0x77cebd31, 0x09572548, 0x6a75d063, 0x54a78ab3, 0xcb91aa4c, 0x9d2248d3, 0x4a52f7ee, + 0x0fa436c9, 0x94abb569, 0x7a67934b, 0x7983713e, 0x2a8d5ab8, 0x561d4015, 0x5dd098bb, 0x0b632667, 0x3b0f94ff, + 0x35b1995c, 0xf5f3ff6b, 0x1c73ee93, 0x23f5ee3f, 0xf087f699, 0xe47acf98, 0x2c1601a8, 0x477ecb22, 0xeb020553, + 0x0712b1c6, 0x27e34753, 0xa084ebb0, 0x8a05b5c8, 0x0c6ef128, 0xa107de8f, 0x2bf3e374, 0x93d5c7a9, 0x29681056, + 0x1bd54712, 0x8b18e593, 0xddb5e6e0, 0x06687bb5, 0xf2960a18, 0x84e95049, 0x684f70ed, 0xa4f29df7, 0xa2d45990, + 0x86684169, 0xb19e068c, 0xcd0647c3, 0xdddf007d, 0xa440ae2c, 0x3476d71c, 0xd844199d, 0x9f8c2975, 0x331c1867, + 0xa3231f61, 0x5a6a7f88, 0x329390b1, 0x6d7ba92a, 0xe786a3c3, 0x782f9a07, 0x2b37f659, 0x5f45efc1, 0xdec8fe06, + 0xfbf323f5, 0x29e32170, 0xd25b2e19, 0xb4b53901, 0xf451455f, 0x4fbd9e39, 0x94e9fcc1, 0xdb9c5a67, 0x9e66e470, + 0x727ad38d, 0x9bb45f09, 0x050cc9b5, 0x4c55e70b, 0xb52cb3b1, 0x8170e3cb, 0xa9419ed7, 0x31d3561e, 0x66bc4bfe, + 0xa7660add, 0xbe7b4908, 0xf5900a8c, 0xe75a8759, 0x74fc46b3, 0x853eaf0a, 0x61c9ab98, 0xdb7b493c, 0x9b95e689, + 0x1b0b3805, 0xba3f2e95, 0x8ca3e78d, 0xa95943db, 0x94b13e6b, 0xb0a00b31, 0xdd5c717f, 0xc66d56c1, 0xd8b97cbc, + 0xd61f3b2d, 0x49c4a409, 0x1773c65a, 0x00156293, 0x5827cafc, 0xd970ded2, 0xf7376fc9, 0x031fe503, 0xe8933baf, + 0x11f5a539, 0xeda7835c, 0xe18348d7, 0x149daa68, 0x4ae3b48b, 0x0a287a7c, 0xd84c8909, 0x269b1e1b, 0x5fa1701d, + 0xd4f6343c, 0x21f2a749, 0x603d223d, 0x0f6e7570, 0xfc37a82c, 0xd7845088, 0xdc5783a4, 0xb3445d69, 0x19ecbb8c, + 0xa298bbb5, 0x8e0931b0, 0x0c609458, 0xc6d3ba14, 0x2ed29f82, 0x566ea5e7, 0xa4c48f92, 0x6c90af79, 0xec76e6ff, + 0x0ce09ba8, 0x096651fd, 0x93c3a398, 0x678689ff, 0x2eb18358, 0x871313bb, 0x451959bf, 0x45999c5f, 0x83446c18, + 0x1fff80df, 0xca231eb9, 0xf35a1545, 0x30823fdb, 0x18b34cb1, 0x227badd6, 0x466cb970, 0x76e95b83, 0xe0ac2cc8, + 0xbbae7c13, 0xa3c1e634, 0xa69c17a2, 0x1ea931eb, 0x86c4b3d2, 0x37cb4123, 0x363161b3, 0xd61b3501, 0x116cd287, + 0x757fd337, 0x6883edf8, 0xd057190c, 0x4e52b71b, 0xaf520260, 0xd55cf745, 0x7e6607f7, 0xe928620d, 0xb0bae5e9, + 0xb3f8192d, 0x6e6dcdeb, 0x099b90f5, 0x9c853946, 0x69e07229, 0x1f0f6c1d, 0xc0ce1ece, 0x639f28b2, 0xb007b016, + 0x0dd1d420, 0x1e678ff5, 0x63b90442, 0x442f7d32, 0x8250a2b3, 0xca148ea2, 0xabce359a, 0x8d1d5126, 0xa61ed97c, + 0x6b4f4848, 0xc5b26d32, 0x420090a8, 0x6bba4398, 0xaa69668b, 0x97b66976, 0x08ae692e, 0xb818caf0, 0xb200b626, + 0xa2c94e1f, 0xc29d3fa3, 0xb2c37449, 0xb68fa489, 0x1e5df719, 0xac4e39d9, 0xbd9db58b, 0xdeb9898f, 0x000595b3, + 0x526bf34c, 0x2e5a5940, 0xc64b707e, 0x24099ca0, 0x7540bd22, 0xe999f293, 0x6ec80246, 0xc1f31a59, 0xbc348f38, + 0x32163de3, 0xaae45020, 0x2a7d070a, 0xfb09fdd0, 0x3afe1d2e, 0xc86f0098, 0x6825be31, 0x8b4ecf85, 0xb647a461, + 0x1982d0dd, 0xfc66949c, 0xe69a18b6, 0xec2eec72, 0xf34e7b4f, 0x190a0bea, 0x0b227e06, 0x6c000849, 0xc66895e4, + 0x63e48ab4, 0xc75a7d2a, 0xbede3398, 0xf7bc3f65, 0xb6f4a485, 0x40976795, 0xe9667891, 0x151b8704, 0x754df147, + 0xcd114438, 0xeca64c46, 0x36254ca1, 0x381fc1a7, 0x679292a2, 0xa408e8db, 0x8207bc55, 0xcd8b4d23, 0xbf391ad2, + 0x1a02ac2e, 0xb7da2e39, 0xbd3c96f2, 0x8fd219af, 0x00192bcd, 0xc492e665, 0xd3f78dd0, 0x564d7138, 0xef1f9645, + 0xbe8384c8, 0xec6ae71f, 0x8cd63517, 0x875f5768, 0xbde568e5, 0xb2568a5e, 0x8987f51c, 0xa3e10107, 0xb630e24f, + 0x9c340402, 0xade19423, 0x76b09d49, 0xf857581a, 0x1f7db0ed, 0x59cd53a9, 0xe20abb76, 0xe690e5d2, 0x0de9a261, + 0x83084435, 0xcfd333f3, 0x5b063569, 0x5932851d, 0x6ef0c1c9, 0x346e7ef6, 0xc54a0e89, 0x78b04ec2, 0xf0206e92, + 0x2c06d854, 0xd67efcd7, 0x15110d17, 0x846f6c32, 0xcc35fffc, 0x5ae9c141, 0xde62f73f, 0xdee2965e, 0x46db9d44, + 0x02f22731, 0xf334dde7, 0x52f4ec35, 0xcc311de2, 0x47eeabc3, 0xb58c8cbc, 0x8971103b, 0x5921212d, 0xcab2f168, + 0x1613f23b, 0xef259f71, 0xd0fb900a, 0x191c4136, 0xc5e5ea10, 0x1c6fb504, 0xe4fc94ba, 0x040137ac, 0x9b8191ed, + 0x8f8cac1f, 0x159c1dde, 0x43f87514, 0x7afa95b6, 0xb116f390, 0x8b0d0882, 0xd5ca3f86, 0xc06c378b, 0xaa1fa6ca, + 0xe2fea342, 0xf6d4495a, 0xee6f59f1, 0x61d7a0bb, 0xe4d884f1, 0x21b019c5, 0x3b11e5e2, 0xbcb57d2e, 0x2468e27d, + 0x1cf01b64, 0x7fec3c82, 0xa0252cec, 0x6fb64941, 0x0fadb297, 0xdad967f7, 0x3e02801c, 0x250be2ce, 0x59847636, + 0x185b37fb, 0xe1ac7601, 0xa6a2dbcc, 0xb99a27ab, 0x795c1619, 0x6149772f, 0x5d9e73ae, 0xb8aa39af, 0x70c21ac7, + 0xbc457ab2, 0x8311bcf5, 0xe070d025, 0x28818bfe, 0x523167c8, 0xd20bc25d, 0xc23f26a5, 0xae8e556c, 0xc55b24d2, + 0xceb6c35d, 0xf3cae026, 0x9583f28d, 0xffaf9683, 0xbabb9f28, 0xd7f31eb4, 0x5c70ec95, 0x3e4a8a6d, 0xd4632cc9, + 0xa11485ba, 0xfb128331, 0x21d4caa8, 0xe8afca6b, 0x196191f4, 0xc67a8093, 0x5fb9de6f, 0x1e22b488, 0x2cee05cb, + 0xc26e145a, 0x145cb5ee, 0xd4dffb8e, 0xdf885867, 0x73966832, 0xb6445317, 0x9b220239, 0x0957a5ea, 0x3c58296f, + 0x5e8a0d57, 0xf184a69a, 0x96ab605f, 0xa6598631, 0x45c35c87, 0xfd05dab3, 0xa6043c5a, 0xe3cbc9b5, 0x9ca1dc27, + 0xc0413a84, 0xf0a6521d, 0x64e4f89f, 0x8ef88df3, 0xde8f7e40, 0xee936087, 0xbc524810, 0xc2138781, 0x17fcdade, + 0xdfc5e42f, 0xeee68d47, 0x9fceb6f9, 0x48f6dd29, 0x0fbc1599, 0x187f032f, 0x4b202763, 0x0defd9a8, 0x1f6ab73a, + 0xd883f064, 0x600a8515, 0xab0c189b, 0xecec9faf, 0xcd7ea250, 0x0ab04f6c, 0xb237aacd, 0x5e058284, 0x997cebd1, + 0x78046e99, 0x75d96eda, 0xcacb9101, 0xb94e35b6, 0xb8641a36, 0x47cb8b7e, 0x10b6e31b, 0x57057182, 0xa721a700, + 0x1535254a, 0xcdf1616b, 0x5b8f0a98, 0xa62a946e, 0xf7422429, 0x7c1e8794, 0xb1779166, 0x4a494e90, 0xb095d3f5, + 0x9868827f, 0xcdc9c196, 0x65694366, 0x1a6eaf3d, 0x58c13709, 0x35a78990, 0x73b198e9, 0x1694ceca, 0x85194cde, + 0xa9dd94d4, 0x71acc65c, 0xa990a5e1, 0x66ef2f6e, 0x82fd3c72, 0x081eb275, 0x521208e4, 0x04976207, 0x4489942f, + 0x7635fdb3, 0x7b7145ee, 0xdb9f07ef, 0xa8ad1425, 0x8fb6276a, 0xe71c6dba, 0xd4ff3d47, 0xafc1f07e, 0x1d6c2c70, + 0x1e2e3574, 0xcb2700ab, 0xb2122d54, 0xb73c0e6b, 0xeba0b51f, 0x0e602f02, 0x469810bc, 0x70625127, 0x01e662fc, + 0x402821f8, 0x63c55111, 0x2ddd8c0e, 0xbaa52992, 0xf35657bf, 0xe5f77773, 0x2b2debf7, 0x2a88b97f, 0x6fa740b2, + 0xbffb3ff2, 0xd743c925, 0x63314c48, 0xe311d2a4, 0x2777d66f, 0x7d7f5577, 0x4d074930, 0x7edee5b1, 0xe96f2441, + 0x5d7a43bc, 0xa537fd70, 0xa1460a93, 0x569bd4ac, 0xc0c3ac40, 0x43c93217, 0x86ac8474, 0x174b3970, 0x1f8046f1, + 0xba79f4ae, 0x370d9641, 0x765ee7fc, 0x8a29d2d9, 0x1ed300a8, 0x4c96ef12, 0xf367da61, 0xaa742a63, 0x25c2c85c, + 0x1e351fb3, 0x21ba6556, 0x70393a00, 0xbbb6d3da, 0x15931b2e, 0x197166ea, 0xb76babb7, 0xa18d0765, 0x697352c0, + 0x51db4195, 0x72b860c8, 0x97c24842, 0x7511a66c, 0xa604d0aa, 0x43396197, 0xbd0e294c, 0x05c59612, 0x5159adde, + 0xe99f5b23, 0x123c07c2, 0x1400b317, 0x537bc267, 0x5093d9a9, 0x5faf3c9a, 0xe9d55078, 0xad8493b6, 0x67d3396f, + 0x014f7e47, 0x274e2441, 0x86fc2017, 0x99ea5f44, 0xdcff23d1, 0x41c9f9f3, 0xf64c33a3, 0x7b6df0d6, 0x91fc341d, + 0xcdc88fbf, 0x7f312041, 0x66bc67e2, 0xb2c372e0, 0x22f230c0, 0x17033fe8, 0x559f2383, 0x00ed0875, 0x22fefc70, + 0x8bdbbe41, 0x3298282c, 0x2b297bd2, 0xfd7c2d92, 0x6d05cb00, 0xd15ea7af, 0x5e18cc5a, 0x8147c7ef, 0x1a610b7f, + 0xebfbb74c, 0x06339467, 0x13f3e49b, 0x319fc0cb, 0xfbc6dc43, 0xf0b2ad06, 0x0112c53c, 0xe5965db1, 0xcf62f5fe, + 0x241557bf, 0xaf292ba5, 0x970f6b0d, 0x5cf01938, 0xc077944f, 0x6414d9e8, 0xbcb787f4, 0x20a0126f, 0x7730b194, + 0xb1cb4cf4, 0xe91dd2d6, 0x61b8416f, 0xe69485e0, 0xf8f8fa13, 0x085a7bd0, 0x47516a94, 0xddafe4d0, 0x987d9cd1, + 0xbdacc511, 0x3f8b977d, 0x4c86223e, 0x739d0448, 0xe46b2ebc, 0xdaf83c91, 0xa6002c35, 0x97bdb88d, 0xd0200372, + 0xef4cf0e5, 0x731cac8e, 0x5df5e1a3, 0x06096ba0, 0xad7918ef, 0x6497e7e7, 0x3f84b97e, 0x8db969a7, 0x8e993bb5, + 0x3876f02e, 0x0d5353d0, 0xd5d9f3e0, 0x17458cd7, 0xe54d6a23, 0xa24db2f9, 0x5c29a03f, 0xa519fb83, 0x5158b70f, + 0xae978f12, 0xf96cc130, 0x971a5f7c, 0x62f6e86c, 0x320f92f5, 0xef445ce1, 0x44e8567d, 0x4aaf0999, 0x7d6d5ffb, + 0xf772d9ea, 0x9c2f2a4b, 0x1f4d0039, 0x75c8e03b, 0xa35ffde7, 0xc89e2675, 0x51db5189, 0xebb66e5d, 0x6116d777, + 0x31e543ef, 0xbbcf02df, 0x6c109172, 0x7449d2ab, 0xd9fa2baf, 0xf35c4a08, 0xbce1f2f6, 0x2b60be40, 0x4ef19342, + 0x70441229, 0x23f1da53, 0xd3f4891f, 0x4d80b9aa, 0x38f94897, 0x063fd7b8, 0xa7c7a80c, 0x4653475c, 0xc10545df, + 0x27731e28, 0x35b28bc4, 0xe9f4387b, 0x09b16775, 0x46fe01ac, 0x7611a0ed, 0xdf6ac3ed, 0x87b417d8, 0x32c5594c, + 0x39761eb5, 0x41b23c17, 0x2b7989e2, 0x2dbf9381, 0x0b1b48a2, 0x156471cf, 0x33f681e9, 0x3b1d93ec, 0x67469a93, + 0x6bca0a84, 0xc7877095, 0xca9310dd, 0x56f9ec4d, 0xa85e9d01, 0xad1e37a7, 0xcbc66b9f, 0x27e6c7ac, 0x9aa252c4, + 0x3f6fdfae, 0xd7b231d6, 0x89c8fb55, 0x26ff6a20, 0xa0fd4f1b, 0x9a383bb8, 0x26599a11, 0x7e9bf940, 0x07c6499f, + 0x5f32b319, 0x49d91e79, 0x2a3eb9e9, 0xd412082d, 0x0ae5283d, 0xb6e95402, 0x17c225f3, 0xc3e8872c, 0x16486acf, + 0xabda5145, 0x43c288b7, 0x9d9e7a07, 0xa26563e5, 0x5c1f5a1f, 0x5cc4d41e, 0x43640692, 0xf20f1095, 0xe3636c03, + 0x930057db, 0x6012e172, 0xd2e4caa2, 0xdc6b7aed, 0x166b29ef, 0xb19dc746, 0xd97dd3e6, 0x11f8bd0e, 0x4e07327e, + 0x9ceeab2f, 0x9401e6ae, 0x32c31dd6, 0xf0e3fd56, 0x7804ae1c, 0x5acc7056, 0xb0397497, 0xb22e4f7b, 0xb36afc2c, + 0x86b58a1f, 0xd9ee70f0, 0x0993ce74, 0x5beaa3db, 0x97183474, 0xb17fe289, 0x69825b18, 0xd4d08786, 0x0df1207c, + 0x0d663650, 0xd97af359, 0xf581c097, 0x7678d79c, 0x1a1b7555, 0x72a21a3c, 0x53f32282, 0x692cced9, 0x387a8d7c, + 0xf4823efe, 0x6aadaf3c, 0xb9d583a0, 0x10de479f, 0x11850abe, 0x3558048b, 0xcdf732b0, 0xf8e84184, 0x1715a1c6, + 0x38653f31, 0x73edb8d5, 0xfc87521c, 0xe132bc1c, 0x87e9bd7e, 0xcd8de435, 0x6fff1ec7, 0x6522c9a7, 0x08620870, + 0x404fae1e, 0x4e0e183f, 0xe415cd3f, 0x5506d9e8, 0x8595e007, 0xd4ecc1a3, 0xef3f0892, 0xd8e8a17a, 0x06cab6da, + 0xcb715309, 0x6b2b9c52, 0x8342d8ab, 0x0bdd8951, 0x939570e6, 0xc496569e, 0x55397b5a, 0xa488cbeb, 0x37c72715, + 0xbb0996d9, 0xe27701c5, 0x656c8e4b, 0xae3593db, 0xff884842, 0xd50398d7, 0x031ae030, 0x6b17c25e, 0x8ead7874, + 0xd53dff81, 0xd87e3221, 0xde055b23, 0xe0ae702a, 0xadd5c7be, 0x74f800b5, 0x0016ea72, 0xd6131b97, 0x842aafe3, + 0xb7f7d58b, 0x605fc244, 0x4d9fa823, 0xe16c7143, 0x77e47079, 0xe8606237, 0x54f14970, 0x88a1b269, 0xd420cc0d, + 0x58d88698, 0x12fbb61d, 0x5663ad27, 0xa5785f56, 0x293dcf79, 0xeadea0e4, 0xd7bc0a70, 0xb543c142, 0xc3d0822c, + 0x2719cabd, 0x0ce5701e, 0x73baac00, 0xe6263fa9, 0x0d2b8b55, 0x0b1250c2, 0x7611819d, 0x64a58799, 0xab79d77f, + 0x33112c24, 0x509dfff3, 0xa5be601b, 0xdeb34197, 0x67662501, 0x3920b3e1, 0x7d394dbc, 0x597d389a, 0x98414bfe, + 0x6a19bee6, 0x0f2a2cb0, 0x110ec935, 0x8adba3d9, 0xe3223ab9, 0x85e6811e, 0xde7061c4, 0xf3c7b461, 0x44b61ac6, + 0xd48026eb, 0xbd8a5add, 0xcd8972ff, 0x7c71d3ac, 0x0003794a, 0x8c704ba1, 0xe30e4288, 0x407d9ee3, 0xcd5d9632, + 0xbb36385d, 0xb377f8c7, 0x43f81640, 0x0d1040cf, 0x54bb9f29, 0x17026d3b, 0x128e5485, 0xb91be295, 0xabd128c8, + 0xbb41d6dc, 0xc9c4a838, 0x6e5f946c, 0x3c7d26a4, 0xcea75e5f, 0xba70308d, 0x7fe85ca6, 0x58c9e018, 0x7cb249b6, + 0x6b900203, 0xf2e59610, 0x4e560c06, 0xee6faaef, 0xa7c7eaea, 0xa9da79cd, 0x46b4cad2, 0x0ef7aaa7, 0xcdba477d, + 0x5b72484a, 0xc9d676e6, 0xa0449cc8, 0x587d1753, 0x4a4e7a37, 0xafea9aba, 0x6c3165d3, 0x1a14c7dc, 0x15a4f377, + 0x68db1fdf, 0x4e2a0532, 0x3c4373b7, 0x9a1036f8, 0x5cfa04e3, 0xbb9105b6, 0x407f236e, 0xf9854428, 0x6558a1aa, + 0x3317c436, 0x0183ac1d, 0xd398ab6d, 0x3e33a150, 0xd4b05639, 0x4cfbc25d, 0x02a74642, 0xe67a636c, 0xc424e947, + 0x9f06b775, 0x627737ff, 0x8b5c5e2b, 0xfd9794e9, 0xb56b7c59, 0xb9028ea1, 0x03c2124b, 0xe5596d42, 0x08861061, + 0x4aafa598, 0x9ad8e484, 0xc783a0ac, 0xe74bff8b, 0x47ac3976, 0x59b6a313, 0x7fc30cbd, 0x9fa8993a, 0xb016e8a3, + 0x324f6976, 0x2d86b9a0, 0x42e2238b, 0x37ee3634, 0x0a2adb23, 0x1fbbb1cc, 0x3acc2a7a, 0xe7821e4d, 0x3dcad0af, + 0xfbdf65ad, 0x7ca55e27, 0x7d8084a4, 0x2060696e, 0x88aec329, 0x466f9468, 0x19bb0a27, 0xe7f55d70, 0xfaf281e5, + 0xdb65b902, 0xec90434b, 0xeffb7d78, 0xf54b5322, 0x9fd00f88, 0xac717e58, 0x07ac36a3, 0xf756b944, 0xc0070977, + 0x0709690c, 0x0f5e5d76, 0x31b6e5ba, 0x3680e8d9, 0xd1e66d11, 0xca75e982, 0x3bd9978e, 0xac20ebf5, 0xc8ab653a, + 0xab3fe0f9, 0x4499e1fc, 0x89d00a3b, 0xa7b2d34a, 0xad1b377e, 0x10df0bcb, 0xbf87cc83, 0x620fa727, 0x468a8db2, + 0x637fa613, 0xef412560, 0x6ec2814e, 0x75d847c7, 0x25229029, 0x44c8bd04, 0x4a2dd6e4, 0x25cea18d, 0x61081999, + 0x41b4af58, 0xbd96c3cf, 0x524e71fb, 0xb7582647, 0x483334ad, 0xa6837094, 0x1cc3a2a8, 0xea4fc3b1, 0x1642bc87, + 0xe3317a2d, 0x37120193, 0x906d6ef5, 0x8560fcb1, 0xd53c6e0f, 0xfb686210, 0x29cfcdf5, 0x7c82bcb6, 0x45aab045, + 0xf1cc323c, 0x0117baeb, 0xaf461cf8, 0x2dd7d09c, 0xbbc85419, 0x8434f2ec, 0xca90f65f, 0xb338effe, 0xf82aaf19, + 0x25f18d68, 0x50ae57da, 0x03b5b5b9, 0x7fcca7e5, 0x216fa3f6, 0xd8ed41a9, 0x0657bff8, 0x7a8ffc2a, 0xb133329b, + 0x7b461930, 0x3b42b8bd, 0x77788572, 0xf5b9a8d5, 0x6f0a2d92, 0xe866097e, 0x5e5889c1, 0x2156513d, 0x84cb5130, + 0xb1ef1ac1, 0x4552a36a, 0x38733f5c, 0xa6f72e2b, 0xb5381576, 0xc5df30f6, 0xc87b39e4, 0x1f5c7f5d, 0x45407eba, + 0x35df0228, 0xe6dd1589, 0xe8be09c7, 0xf1ab9d2f, 0x83ab6baa, 0x20f34b40, 0x40aa843c, 0x3a72d429, 0xd8785039, + 0x2309b274, 0x9b460024, 0x657a7314, 0x7978e3b8, 0xa43e93c2, 0xe09096df, 0x7583a7c8, 0xfcd9ccf4, 0x182c5a21, + 0xc77d2b2d, 0x4ab3dc75, 0x93b8e9d4, 0x294e3080, 0x80bfee76, 0x58ab2ce3, 0x906b6e18, 0xf3507fd9, 0xe48588d1, + 0x4a22fc08, 0x1e69bc92, 0x694f35e0, 0xf89cb7aa, 0x0861f491, 0x3ecf623e, 0xc321c840, 0x63d5166c, 0x0509dc90, + 0x1c34a2c5, 0x60f98d0e, 0x7a07f821, 0x086d67fe, 0x436cf4cc, 0x92764935, 0x099a3f64, 0xc773f0dd, 0x4edadf0e, + 0x647824db, 0x3b901ceb, 0xcc858c7e, 0x51f6de35, 0x1e9b7924, 0x2f23f45c, 0xd9111f89, 0x5bbdf767, 0xb54bc547, + 0xd9619dc5, 0x0a141330, 0x6e3ec690, 0x12627d53, 0x6047450c, 0x3d786dc9, 0x7fc5bb16, 0x0eee8b55, 0xd4a5a07d, + 0xe2422509, 0x13b85c22, 0xeff18a0b, 0x82c5612a, 0xed5f68d3, 0x6fff90de, 0x31b7e2c7, 0x9823bac7, 0x0a6d4adf, + 0x177aae7e, 0x172d2771, 0xd3fefb6f, 0x55fae28a, 0xe58180f8, 0x72c62f11, 0x3847f06f, 0x9900fbab, 0x1368881e, + 0x1995bbeb, 0x99af9161, 0x33461a60, 0x029580d2, 0xad94c539, 0x22f4640b, 0x14c63b2f, 0xfd999c41, 0x9a8440df, + 0xeafff43b, 0x82d58e21, 0xd50991e4, 0x22ac2168, 0x3727b3e7, 0x1b236f11, 0x5676fc32, 0xdbeb9c91, 0x0b9c654b, + 0x02c2c99d, 0xa3bf19e0, 0x5aa3d1bc, 0x4e2cab86, 0x21f5badf, 0xcc034718, 0x70d4baa5, 0x698d181c, 0x78fe7289, + 0xb4d1f268, 0x8a3ce25f, 0x64e1cc4a, 0x941bbbf0, 0x24b8f609, 0xee173131, 0xa3f6c398, 0xbd21fa6c, 0x789238da, + 0x0bd49a43, 0xcce900fd, 0x16497283, 0x3d41fcf2, 0x056057f6, 0x2567953c, 0xffc923bd, 0x88c6515b, 0x8259f010, + 0x2ed1c4b0, 0xa442e7c7, 0x96e0ffc2, 0x75efc322, 0x089991df, 0xe97a74eb, 0x5e55c938, 0x540c9f75, 0x5831cef0, + 0xe7c41021, 0x2499f6c8, 0x19d11a58, 0xbf301d71, 0x66559928, 0x61df73b9, 0x8057cc50, 0xdb0ab8a8, 0x36d419e9, + 0x766b2726, 0xa513250e, 0x0b166974, 0x65535844, 0x34344d8d, 0xa8189449, 0x0ce41bf7, 0x74a58341, 0x1422a48c, + 0xc0be1872, 0xb7250639, 0x59c7fe89, 0x5c974489, 0x8966f70a, 0x2479d3fd, 0xdc51cf4c, 0x77ff1b05, 0x35041042, + 0x6649d1a1, 0xf5b789ee, 0xfa144367, 0xa6cba758, 0x087f9495, 0x92349f05, 0x9949131e, 0x9f34e128, 0xdaaf1563, + 0xf9d40651, 0x701315b7, 0xe3bdca86, 0x4ade04a4, 0x861e36de, 0x67460e37, 0xb1d33938, 0xf84068d5, 0xa7eba9bd, + 0xe24249d9, 0xb6d0a953, 0xf9322466, 0x59cff42f, 0x03b2238c, 0x76dce826, 0x218aa2ad, 0x3f3c8d6b, 0x52691098, + 0xee812dbf, 0x7cb7da0c, 0xcb3442ca, 0x4a670b3a, 0x4365ebde, 0xe5d0e2c8, 0x37990997, 0x18d80cc8, 0x6971b548, + 0x563b5e2f, 0xc11c3351, 0x53ecc854, 0x13b31689, 0xe1d28767, 0x3a8de93d, 0xd82b9efe, 0x044a8d5b, 0x8c341b57, + 0x5e22b3a0, 0x2421c3c5, 0x4d123c75, 0xf38fc5db, 0xab376726, 0xa1103b5f, 0xa6f3dcc9, 0x5370810b, 0x29cc0308, + 0x4d0a1dd3, 0x95ea3fd8, 0x742e00ea, 0x5786a68a, 0xd29e7e9c, 0xdc69beed, 0x37999460, 0x89c45c53, 0x2f7deab5, + 0xfc7745bb, 0xc718e32a, 0xaf09d45e, 0xcb5aea40, 0x1279fcbc, 0x8ce1585d, 0x20c4ac61, 0xb2f1cfa7, 0x78627bd9, + 0xe23ac578, 0x35c53db2, 0x434ecd14, 0xd9f98966, 0xedef8748, 0xe3767d3b, 0x820e806c, 0xa948b10d, 0x9b7451da, + 0x52dae128, 0x9269745e, 0x3dbdee0d, 0x92031abe, 0x31d0dd61, 0x716787e1, 0xafa6d3eb, 0x3eb0d709, 0xf53be2be, + 0x14cf60ea, 0x82cb7130, 0xcf6e3469, 0x071ce4ac, 0x4bb65fb5, 0x2e38f683, 0x57c87796, 0x23693822, 0xd56600de, + 0x0e65f62a, 0xf35b43e9, 0xa73a28c4, 0xc55c5368, 0xb5131ae8, 0xc7f67592, 0x9bb248b5, 0xe0ba7503, 0xbafdacc8, + 0xb917e95e, 0x680d1845, 0x4315c013, 0xc8c82e8c, 0x7c3c4919, 0xb578a81d, 0xa89c079a, 0x7452122c, 0x787e20d3, + 0xf9fde270, 0xe8f7ca93, 0xe4be8176, 0xd5c93a5f, 0xdf550d25, 0xb45567af, 0x5942de88, 0x9ba8a85b, 0x419fd6e8, + 0xc2d15b3f, 0x26c99601, 0xfb8a44ff, 0x55e44762, 0x40555423, 0xcff59aba, 0x5d3ad877, 0x74aefed6, 0xbe8e0048, + 0xdcc1e11a, 0x46df0343, 0x744cbf93, 0x916eeb6e, 0xe3c8dcf7, 0xab9fa9bf, 0xe03e6600, 0x9987188c, 0xbe5ee099, + 0x7d5fb45d, 0x7ba6e158, 0x45b0c4ce, 0x2c80f2c4, 0xccf0a056, 0x970bc6ec, 0xc610b098, 0x12b52513, 0xed71f3f6, + 0x15c6fbe3, 0x55fc04a6, 0x9298e5cc, 0x1118cdb0, 0xe58d2c21, 0x88141d7d, 0x228742d7, 0x02d91104, 0xe1c81927, + 0x9778bb03, 0x603707b6, 0x480a4bc8, 0x1d5c8653, 0x49c8fb1f, 0xe845b7b7, 0xfe214c19, 0xbfad7af7, 0xe8959464, + 0x8615318d, 0x6747d1e3, 0x1032c254, 0x096d65b0, 0x787a7a5f, 0xb4b656a7, 0x1c02596f, 0x8577050e, 0x46c471b8, + 0x3abc5f2f, 0x569ecd25, 0x8f2bbc9b, 0xe9ded2e1, 0x1ffa6d38, 0xe21af6ac, 0x08d7919f, 0x6550e930, 0xc37f659e, + 0xac70d612, 0x6705b573, 0xd06a7aac, 0x64f064df, 0xd746e3ef, 0x27d80194, 0xc4c77910, 0xbe911318, 0x1c2b6b49, + 0xc2a274ad, 0xaa209a62, 0x7c21a7e8, 0x2b182b97, 0xa22f547f, 0xa10ac5d2, 0x823137c2, 0x80945817, 0xbbf208f6, + 0x6257f8ee, 0xa020b3a0, 0x0adccd6a, 0xf8bd7a81, 0x3d32d335, 0x0078a5d7, 0xebfc52f2, 0x4fb42fc8, 0x7413bd90, + 0xbe822ede, 0x6888d024, 0x7ce5461f, 0x44326cf0, 0xc6c42b13, 0xae2c59c2, 0x72e9d10d, 0x0141c08d, 0xfdc50a50, + 0xda006449, 0x90c2c770, 0x0c2b1cd8, 0xf88a8dc9, 0x6940d382, 0x658251da, 0x0e081622, 0x4dac7acf, 0xc0e5a15c, + 0xf3d00cb7, 0x4e28d176, 0x672afdec, 0xff22c602, 0x60df8a4c, 0x7eed1552, 0x46276302, 0x886d4224, 0xdc572361, + 0xd7a685f5, 0x404b0edc, 0x339409aa, 0x85835f58, 0x13711427, 0x6f3765b2, 0x4dad4208, 0xd1be8293, 0x36a88e77, + 0xdd27fe58, 0x7395ad30, 0x3522a514, 0x04d53e74, 0x3f48bbac, 0x7a6c565e, 0x3c6cb9b7, 0x992053cc, 0x355377cb, + 0x19065158, 0x5df6036a, 0x8cc4cb33, 0x8e53afc3, 0x6fe1e4e2, 0x2c911277, 0xee1235fa, 0x15369078, 0x2d94a1eb, + 0xcdbdbe97, 0x4af767aa, 0x0d6ecf41, 0xfbadb1c9, 0xde9adb2b, 0x78067dcb, 0x39d8e66e, 0x375d73a9, 0xd2086a91, + 0x22b31138, 0xbc14c6cc, 0x918752b6, 0x9f3e7cfb, 0x5177c54e, 0x035ff808, 0x9228ff78, 0x87dd9505, 0x43558f57, + 0xc0ade123, 0x53c14172, 0xf48f6182, 0x198e0ec0, 0x023157da, 0xbecd91ce, 0x984761c9, 0xa8577ece, 0x182b7a77, + 0x6b410054, 0x57aa09dd, 0x9986761b, 0x28f426c6, 0x3dbac89f, 0x068bdd79, 0x3e59c776, 0xf37469f2, 0x9aa99386, + 0xb7ca3c75, 0x7227a691, 0xd12b4b32, 0x7197db37, 0x07eb0fd3, 0x3a5a9320, 0x5acd6517, 0xd3eb6958, 0x705a0067, + 0xab66a598, 0xa84a4d36, 0xca1ba2b5, 0xc62d750e, 0x62488168, 0x0815ecb9, 0x7c4b4673, 0xcad95a11, 0x7dc68851, + 0xbcbc419a, 0x79940229, 0x07449054, 0x5246bd84, 0x8e794cb7, 0x4c817e59, 0xb29bd12c, 0xcaf1b041, 0x436e8fde, + 0x4fe044b8, 0x2aa06096, 0xbc0f5e76, 0xe5eb1ea1, 0x1734c8aa, 0x27cb1a88, 0x4c3be71c, 0xbccb7f86, 0x137d8faa, + 0x341e9167, 0x0dbb6217, 0x2d47dec6, 0xc838327a, 0xdbf0b628, 0x882e75ba, 0x9d758a2d, 0x5a4294e7, 0xacfec2c5, + 0xa0b1057b, 0x1f9db051, 0xe9b2f9ce, 0x2b20ca74, 0x7ba25925, 0x4714510f, 0xb7813aa6, 0x5ebe19c0, 0x2b7b21ed, + 0xc8eead1f, 0x863aa956, 0x2797bdbc, 0x2e3e98e5, 0x15d9a832, 0x8ee7e008, 0x15341b1e, 0x93128e50, 0x58d416f9, + 0x1aed0992, 0x383654f4, 0x85adab74, 0xb0a923b1, 0x3093e7fd, 0x3da8f23b, 0x913582f9, 0x35a27506, 0xf9998de5, + 0x1d7752f9, 0xd57e56a6, 0x8153bac4, 0x67e913bf, 0x23cfdf2a, 0x9cc2a6ca, 0x5358ce18, 0x6dab45df, 0x058ac6cd, + 0xd9ab66e7, 0x4a8d596c, 0x2df948f1, 0x283592e1, 0x1b7ca59e, 0x8589541b, 0x6169ca2e, 0xb6760f13, 0xf429ba03, + 0x1c6b9084, 0x6b179137, 0xd5a351a2, 0x81a28faf, 0xa075609b, 0x75f88cba, 0xc9c50cf7, 0x5ecf89e4, 0x223e20b3, + 0x6f2a3284, 0x3d011ac3, 0xcf6af90c, 0x31cc3923, 0x8093d59e, 0x2ab3a96a, 0x0be8edbe, 0xa0c84c12, 0x587cd11e, + 0x0d9985a1, 0x1a5eac96, 0xc9d58211, 0x31de0fe3, 0x9a25ae80, 0xb8121483, 0xde53b699, 0xd9266bd7, 0x0186e272, + 0x97f126ad, 0xfadb85de, 0xd3c72cf0, 0x8302d47a, 0x927d242f, 0xd034c094, 0xa598021f, 0xd6964718, 0x10396a96, + 0xbcb93b20, 0x613b70e3, 0x9efd1350, 0xbf60d513, 0x7cda6a6f, 0x23406b79, 0x2cb77846, 0x47c8edd3, 0x40417428, + 0x05abaa20, 0x8816875a, 0xc741a82e, 0x6ba04a70, 0x76bbb93b, 0x5e2183c7, 0xb6a7b89f, 0xfaeb7558, 0x31e5b92c, + 0x0e61c36b, 0xe098b7ae, 0x4b6a3442, 0x39e5ebc4, 0xb1a0b95e, 0x6b75a5d4, 0x1731318c, 0xde79e206, 0x5c88fc32, + 0x800842f9, 0x6415bb24, 0xff7d1a5f, 0x0fd91d65, 0xd7321f07, 0x66bd221e, 0xa03eceba, 0x95012cb8, 0x53664ff0, + 0x137b9b1b, 0xeb843c38, 0x48e389d9, 0x80f363c2, 0x1013a70f, 0xb5f5d049, 0x600e288b, 0x57652d6d, 0xf8de5053, + 0x25b642bd, 0x69484e2d, 0xa4471b72, 0x3ada0e23, 0xd1b6909a, 0xb633001b, 0xb2fa1b51, 0xa6f017f8, 0xb43b2703, + 0xfe6cb33c, 0x855ba22d, 0xd40b359b, 0x402da0d3, 0x59b7de6a, 0x8fe33dc3, 0x8cdc07a6, 0x7005efeb, 0xa96803b9, + 0x661b12eb, 0x460da2d1, 0x127df002, 0x87bcbe2c, 0x06329e39, 0xfff86bbc, 0x82524e89, 0xda42baa0, 0x4f8c942d, + 0x6c7da28d, 0xaa57f6c0, 0x2487676a, 0xd771df0e, 0x7e8a372e, 0x37b96b37, 0xea445a65, 0x31831967, 0xb6a520c2, + 0xe092f65b, 0x5e89dac9, 0x0ff27aa8, 0x7b48c17c, 0xf2e5e6f1, 0x99ecd94e, 0xab93bce4, 0x9baee96e, 0xbd42b8a1, + 0xc4c561c1, 0x391ca733, 0xb4485481, 0x01c526a3, 0x565f35e8, 0x8334e3d3, 0x9c0b30fe, 0x23e71eca, 0x0ac9624b, + 0x95cd1f19, 0x6f815738, 0x7be139fb, 0x1b0217d3, 0x3d892cff, 0x730c907e, 0x83bfdf37, 0x2d9dc015, 0x6fa9d825, + 0x0af1bbfd, 0xd01d6c58, 0x06ce2978, 0x7e429803, 0x3c0e033f, 0x90a675da, 0x163e7c78, 0x279522b3, 0xa7e2a41d, + 0x8fb55b73, 0xc2f67dc2, 0x16e1d9f1, 0xa1ba9e86, 0x2c760d56, 0x884f44cb, 0xd7db4682, 0x097ed715, 0xb81dd250, + 0xd060b3bd, 0x338ed957, 0x77d5f951, 0x9920608f, 0x6aeace24, 0x9d136356, 0x263eeb20, 0x1de1c1ed, 0x519b1537, + 0xcb9f6b78, 0xd60ee261, 0x353cb28f, 0xba19cb72, 0x24777bb0, 0xa979961f, 0x9f579819, 0xa03985bc, 0x499fbc90, + 0x000e9984, 0x7498639f, 0x607e9fbd, 0x5fe991fc, 0xb8198c4a, 0x0da2f3fc, 0xc98771ad, 0x456ce24b, 0xe540d6bb, + 0xe49b8fd9, 0xa7dcc95c, 0xd80d1ee8, 0xecca9792, 0xf3850620, 0x4c14be0c, 0x41ea570d, 0x7c31fca0, 0x927b9f31, + 0x3d700830, 0x1779a810, 0xa2c644b6, 0xbb042a71, 0x7addcbfc, 0x0701bddc, 0x5b68c9cb, 0xfcce8545, 0xa324da23, + 0x6b274654, 0xd9d4695e, 0xad279268, 0x001bf207, 0x39fd4824, 0x2d7c2030, 0x711914e9, 0xc56c9379, 0x8aaa2b96, + 0xfc5e7923, 0x54af3053, 0x7d5bb853, 0x944f31f0, 0xb93671c9, 0x174ac15e, 0x5134afa6, 0x7a6bc970, 0x96c722ee, + 0x062c3a81, 0x57b119cf, 0x3a7a377c, 0x7379f759, 0x4c6cc7a7, 0x54b27b01, 0x49a13a12, 0x3950d9c0, 0xea3088ca, + 0x6b1be993, 0x8c43c653, 0x58186953, 0x61f378c1, 0x702d780d, 0x3f153a40, 0xc7db4914, 0x059b5229, 0x644cb3e6, + 0x209e9ac5, 0xd8fa9759, 0x6d34cdd2, 0x6a3b4a4d, 0x17abb529, 0x26bb1a63, 0x6cbfe419, 0xf3dab4fc, 0xd303f731, + 0x5093c486, 0x57137c8b, 0x101da220, 0x526eff10, 0x3a88a36b, 0x8a6b1719, 0x3cda579d, 0xea3acfc2, 0x3f9700e5, + 0x2546035b, 0x61381205, 0xbd3346fd, 0x857ef394, 0x57edc3d1, 0xf56404ca, 0x8c03e57e, 0x29262a44, 0x59e2afc5, + 0xcebb9d30, 0x89ab24f8, 0x90d22cc3, 0xcd04695b, 0x7bd4cb60, 0x3b4aec5f, 0x70133cdc, 0xf2026f36, 0x30f34426, + 0xf1e4112d, 0x696ad124, 0x5c7f0952, 0xaeb95288, 0xee8ba844, 0x7dfd44da, 0x628f7872, 0xdf316ab3, 0xb9842ccd, + 0x19a42e42, 0x887d7c99, 0xd2cc2030, 0xd380e4c2, 0x97e2ea96, 0x61607355, 0x21260217, 0xb5bfed11, 0x8b350266, + 0x4f114fa2, 0xc69ab624, 0x0bdc1310, 0x717492e2, 0x573720ff, 0x56802163, 0x25139510, 0x62617d8d, 0x79208d98, + 0xa1443dcb, 0xed44a87d, 0x3a3902cc, 0xbdbebfe7, 0xdbefc402, 0x46d72396, 0x93030374, 0x2252ba0c, 0x611d9091, + 0xed5defcb, 0x2f575ee5, 0xb0983870, 0x7d78beb9, 0x256be473, 0x3ce03679, 0xc34e6817, 0xd16974d2, 0x8cb1fc7b, + 0xc70a8af1, 0x3ae56d16, 0x94c2cd44, 0xbbbe017c, 0x09eb18e3, 0x0451c3d2, 0x1df73e35, 0x8dcdb4a6, 0x1bfb300c, + 0x1477643a, 0xdcbf224e, 0x09507d31, 0x56437892, 0x80e9cfe2, 0xfca76bdc, 0x0f86fa81, 0x830e8db2, 0xebcf9ebf, + 0x83c4566b, 0xe92ebf7f, 0x9fe9bfff, 0x6d755af3, 0x4d80765e, 0xdd218b18, 0xd1ef16a6, 0x89d4f686, 0x134036a6, + 0x16c2ae15, 0x8b4b550d, 0x30680cb9, 0xe2f8aa66, 0x5df7596c, 0x9e4f3b48, 0x96d5912f, 0x2b64691a, 0xdd2c44bd, + 0x24b100bc, 0xd03c01a7, 0x5579292b, 0xb5aec27b, 0x780a20b4, 0xa78132d2, 0x674f7c39, 0xc0458db3, 0xe5e083f5, + 0xfdb4732a, 0xc35c13fc, 0xf76cd21d, 0x73194f3a, 0xf51ce398, 0xfa1713d5, 0x4b05c87f, 0x2c81ac5b, 0xab4816fd, + 0xd4b7dde9, 0xf1d46a0c, 0x4543ccff, 0xa1b1629f, 0xfe326a2a, 0xbfc32acd, 0x2311ac18, 0xe2280c69, 0xa1a9c90a, + 0x6bba8bfe, 0xb4ffa62a, 0x1a71def4, 0xcbc4026b, 0x4800d4f6, 0x16f3ab56, 0x25c17cef, 0x9ceca009, 0x99a45b3b, + 0x1a7fcb2c, 0xc9e22b41, 0x346877f6, 0x58843e86, 0xdeb7beb0, 0x21e31141, 0x6d1e583b, 0x3f03c6aa, 0x378fbcdb, + 0xb780c60c, 0x335c9bf5, 0x669dbd36, 0x2e22ad09, 0x019feb65, 0xca8b8e9f, 0xc45a9678, 0xc8a4fd56, 0x3a156d12, + 0x76d45da9, 0x4cfcb027, 0x7092e65f, 0xb008a3db, 0x06851b5e, 0xf1201a13, 0xa5c7bee6, 0xc2be8164, 0x533f389e, + 0x4d2f64a3, 0x9cba90fe, 0xfa6e036b, 0x4c21d3c3, 0xefeedef3, 0xd2de59b2, 0xf215cbfd, 0x1bb9bb30, 0x5641b7be, + 0xa9d773bc, 0x5d2733f0, 0x19364ff2, 0x0ecc83d2, 0xe98dec74, 0x81822a36, 0x15afc1b6, 0x7e4e5b0c, 0x18881c96, + 0x6c2d3d51, 0x1d35de2f, 0xc1208a52, 0xde02b7f7, 0x41146c90, 0x0f881e85, 0x57bf62f2, 0x404e3954, 0x49907594, + 0xc35f2901, 0x98bd6e03, 0xe97cdfeb, 0x68e33737, 0x9e7f4e30, 0x4c1174c2, 0x41dd30b0, 0xb868b73a, 0xc3d2ff28, + 0x36906292, 0xfa1e0eed, 0x59ce8ce0, 0x038c36b9, 0xf411086b, 0x2c37cf9f, 0x55a49a30, 0x4959f8f2, 0x4cf0e95d, + 0x6fda88d0, 0xc2c8468b, 0x333eaa34, 0x6ae6b1a5, 0x5c9d284f, 0x83e33efb, 0x1425909c, 0x9aedbcfb, 0x660a42a7, + 0xc9f6c985, 0x1b9511a9, 0x790afb66, 0x69c33f57, 0xc27fe6ac, 0x17f256c4, 0x0293a63b, 0x329c2c9d, 0x123d3bfc, + 0xf1e0c5b5, 0xc2b11b22, 0xfaac94a0, 0x5b181501, 0x18f61828, 0x2af196f6, 0x172f6a0e, 0xb1e0ab3a, 0xb2a334bc, + 0x505b46bf, 0xe8ad6d60, 0x9d1970c0, 0xdd95208e, 0xa4185f1b, 0xab01f76d, 0xcb727549, 0x417be59b, 0x96c11b26, + 0x24fb0c89, 0x21469472, 0xcdb20ebd, 0x8d3ede40, 0x564f5841, 0xcbfbd708, 0xc997e9f9, 0x4bea50ca, 0x3d28dacd, + 0x5b912428, 0x0116e57d, 0xc991fcd7, 0x1342a040, 0x54ec098c, 0x6c785f6d, 0x6240220e, 0xca2bad93, 0x581188af, + 0xdc93417f, 0x1baa11fd, 0xb297161e, 0xf5d4b369, 0x7114c5f3, 0xb1e872a3, 0xd0924baa, 0x608d6257, 0xf9446a8f, + 0xb937a0fe, 0x698aef24, 0xee7739a0, 0x9ff4ca47, 0xc78a71b8, 0x66ffd18b, 0x72386096, 0x06fcb925, 0xd068f2f4, + 0xd3cb23dc, 0xe4d4cd11, 0xa61dfaad, 0xeb912801, 0x3431f22c, 0xc6c98110, 0x6309fa3a, 0x3373574d, 0xd2dfb63e, + 0xeafe102a, 0xc6c63d71, 0xd6e6cf64, 0x1b0b0a57, 0xbbad7e09, 0xb10071f8, 0xf4f600b8, 0xed44409e, 0xdc9277e1, + 0x332cf15f, 0x82fe00f8, 0xef2aba55, 0x2ba331fc, 0x45834141, 0xe837ee44, 0x31ac3fc9, 0x79aeb739, 0x7821fa1e, + 0xe1f391a1, 0xb7fe31df, 0x7498b82a, 0xa392379a, 0xb34f9960, 0x5c314c21, 0x7f2b58b7, 0x24598801, 0x0c8288dc, + 0x98b539c9, 0x927b8095, 0x8b871307, 0x16630951, 0x091a3639, 0x0bf32d2c, 0x3245ebd0, 0xe286f618, 0x89f2d7eb, + 0x4ba4e88e, 0x322ef169, 0xed78ec01, 0x37b832d3, 0x3b27bef3, 0x991f7b05, 0x9ff10252, 0x96d6001f, 0x98f30bf5, + 0x66ce34c2, 0xacdd90c9, 0x4cb24e5d, 0x46516553, 0x29ea96aa, 0x48227913, 0x26eed91e, 0x1ee8f56a, 0x942de65a, + 0xb92f5935, 0xe10bdd97, 0x760bf04f, 0x354f07f2, 0x94fb0c92, 0x71b41ea9, 0xc1eec4c2, 0x3d1523f8, 0x4717bd0c, + 0x869709ec, 0x38816bb7, 0x0c0aea64, 0xdd4d0dfa, 0xa34f707b, 0x987bce25, 0xbd6b7823, 0xea7a3c54, 0x98c7b487, + 0xe6bd9b76, 0xe8e5e3f2, 0x29a744ea, 0xdd3ca62e, 0x00141483, 0x70b9f638, 0xbfc7b7ff, 0xfa9ae891, 0xb615a586, + 0x3ac793da, 0xede73c82, 0xbbc4ddd7, 0x4fcce274, 0x83e3efa5, 0x5d0c7330, 0x559ea7ac, 0x463556b2, 0xc55f6ca4, + 0x7bbb6eab, 0x93362644, 0xed77f10c, 0x3b60aada, 0x9d17e39b, 0xd2da2926, 0x00a92c7f, 0xecd309de, 0xfa508ffa, + 0xbe354770, 0x6c3c0009, 0x909d950c, 0x9ccd99e3, 0xe8299184, 0x39df5ef9, 0x04fc76e3, 0xf393ea81, 0xc4b2730f, + 0x9f8d2b67, 0x4da03938, 0x6d83c733, 0xf0cc17a1, 0x9229496d, 0xb1da6a1c, 0x44c037e7, 0xc3de9ab3, 0x9543de46, + 0xbbf4e981, 0x252c0d41, 0x26339d8f, 0x270b4054, 0xe8dbc954, 0xc3840ad8, 0xc2ba370b, 0x5212b486, 0x96f3e96b, + 0x18f62d31, 0x8a425161, 0x7c7f10d2, 0x763ff0b2, 0x57866357, 0x3741854c, 0xf98a222a, 0xf6341076, 0x7622732c, + 0x437a371c, 0xf64958f0, 0x7993ca36, 0xb5e597b9, 0xcd6f794e, 0x6610b0ef, 0xa082398a, 0xbd0beee8, 0x35beee1e, + 0xdd7ef1ca, 0xf3da12a5, 0x13ac152b, 0xa949a1c0, 0x3902dcb6, 0xbd971be0, 0x28d6ad14, 0x896fc065, 0x788ef86a, + 0x76b42773, 0x57c327af, 0xf835a687, 0x425c0366, 0x1c294da6, 0x6417724a, 0xbbd74307, 0x50e55237, 0xf101f579, + 0x4d39f4a3, 0xbd281346, 0x98da3b11, 0x47abc9dd, 0x51b1d293, 0xb6daff31, 0x7cb222b6, 0xef9afc57, 0x01212ec7, + 0x1b73d8fd, 0x90c21309, 0x041305a6, 0x3f43eca7, 0x798cac12, 0xf8a48dac, 0x863fa55d, 0x39da53c6, 0x1629b220, + 0x7423eb9d, 0x7273138b, 0x4c3ab2fb, 0xe9e0d515, 0x79d3051b, 0x8fac62d4, 0x9814490a, 0x0e8cb06a, 0x7a6bc12b, + 0xd73917a4, 0x7bd18650, 0xab5dfefe, 0x63a4047c, 0x76b821af, 0x33f4bdca, 0xd70cd3c6, 0xaccc9cbe, 0x93b33c7c, + 0x4696f6df, 0x95487b04, 0xaa9929bd, 0xb1a6bb47, 0xb10e2f28, 0xf4495f19, 0xf3c84ead, 0x41e8fb27, 0xbf9507d9, + 0xd30acf43, 0x585cff8b, 0x6aebd473, 0xd7057089, 0xbe8d26a8, 0xea10397e, 0x03f94711, 0x47cd701a, 0xe7793ee5, + 0x7ceb7bf6, 0x17e5cc3d, 0x47c7a73e, 0xb5eeb157, 0x0c97b070, 0xaf5e3fbd, 0x1762b168, 0x19b54f1f, 0xe3c08cd5, + 0x5fa08573, 0xe3eaf9f2, 0xfdafbd77, 0x24ba4d76, 0x23aa0b23, 0x6903850e, 0x93b8e61c, 0x7ffaa70d, 0x9d672b5a, + 0x290c9791, 0xe096cd3b, 0x56169d04, 0x56dd99b7, 0x9adf61d1, 0x312f1845, 0x5fa63b27, 0x219a8c2a, 0xc032ac35, + 0xc56d2729, 0x95fb67a9, 0x3caa1a8d, 0x3029d4be, 0x94b61f79, 0xba8d2f0b, 0xdc1e23f0, 0x0e861a6a, 0x409c3ce7, + 0xaa70e0d8, 0x554fe2c6, 0x4057bab0, 0xb8183bce, 0xe5385828, 0x58e76055, 0x01471fe9, 0x50e6e605, 0xa8ab7990, + 0xbe014182, 0x1eda83ec, 0xd45e49b1, 0xc4f3cf6e, 0x584e455d, 0x7e2efb99, 0x517315b4, 0xd026539c, 0x247308da, + 0xf07ad6d2, 0x41bfb48f, 0x73a34727, 0xc70e979c, 0x9e06584d, 0x77e279e6, 0xb59d5cae, 0x9f8cbe97, 0x440bb664, + 0xc455dcd7, 0xe26816cd, 0x07e53f0f, 0x4b7112f4, 0xee2ebdd3, 0xdf8126e9, 0xe9642f0f, 0xb29524f9, 0xce773664, + 0xffc86a15, 0x9a241391, 0xd41c8aa6, 0xd2637e3a, 0x403e9fd2, 0xdb7d7cbd, 0xb341db58, 0xb94338ba, 0x4f0a14bf, + 0x35f50696, 0x6864d073, 0x66866b0f, 0x984a6783, 0xb7905067, 0xc418e26d, 0x3eb23f50, 0x47792fc5, 0x489f4155, + 0x06feb0ce, 0x36585794, 0x3efc5539, 0x35916c3a, 0xad91e70e, 0x856c1a76, 0xce3da876, 0x03001217, 0xa73dd1c3, + 0x0703cf1d, 0x9ff17064, 0x1b737ba0, 0x170c44bf, 0xd857215b, 0x9906c203, 0x47c5c432, 0x37070bee, 0xe1426b85, + 0x390037ba, 0x3fa14b9b, 0xb46cb18c, 0x039ddf7e, 0xbd615a20, 0x9157797b, 0x2439b8c5, 0x76a23c23, 0x0cc66757, + 0x3d63b1cd, 0xe9949652, 0xf6067f64, 0x87cfb898, 0x63ac4802, 0x464a128f, 0xa9929e86, 0x594dd189, 0x0bab66fd, + 0xe996b600, 0xfabea429, 0xeca45a7b, 0x46150949, 0x70f73290, 0xcd9ca01d, 0x302a1e0c, 0xa98d3935, 0x4cc2c011, + 0x8f8e35c4, 0xc077b8ec, 0x0ea7f9cd, 0x12b5d0b0, 0x9553b248, 0x4b3c613e, 0x5a52c903, 0x575042dd, 0x7bb3d340, + 0x03054044, 0x77439efa, 0xcf35939c, 0x4980421a, 0xd593473b, 0xd6741d26, 0xd85363bf, 0x7cf539da, 0x2aac1fbf, + 0x08027d29, 0x34f8e615, 0x2ffd9d12, 0x6f47c0df, 0xdff9ed3a, 0xdadd4b4c, 0x3c4ebed0, 0xfa279730, 0xfd5adc7a, + 0xffa961a7, 0xdc553d64, 0x5927694d, 0x7b0a26b8, 0x51eff638, 0xf73e2941, 0x3cf4e428, 0x500a8568, 0xd1b66f05, + 0xb6dc6aaa, 0x900096b3, 0x79689d51, 0xb09e2326, 0xcabebdb7, 0xd79150c0, 0x069941db, 0xec19a1b5, 0x82d26adb, + 0xef029a0a, 0x6876bf27, 0x95565b4f, 0x56c3a305, 0x63f43b91, 0xa34733c1, 0xa9573310, 0x5e8c9509, 0xa91d594c, + 0x151a82f3, 0xe887265a, 0x789599ba, 0x49a30ce8, 0xe2089cfd, 0x33f6d6d7, 0xed92806d, 0x9f321d2b, 0xd14a1052, + 0x9b7f6346, 0x12711911, 0x4ff881a6, 0x0795855b, 0x36af2adf, 0x10d6c865, 0x631a0efd, 0x75901724, 0x4b91118c, + 0x11a25930, 0xc6e0b7ff, 0x1c91f50c, 0x04306f8c, 0x9388d36b, 0xda33253a, 0xf1635427, 0xbf6ca342, 0xad66bfd9, + 0xf19cd930, 0x32de3416, 0x0aeb36f7, 0x02b0a011, 0x769de189, 0xa5780166, 0xf9ad8a81, 0x0d997ca6, 0x7b63969c, + 0x79c5e25e, 0x053aef74, 0x93549f88, 0xf8bf9ee3, 0x85058449, 0x3f3c5de3, 0x3c3ed4ff, 0x2b295a03, 0xa9fb60ed, + 0x972d3477, 0x988ce70b, 0x659a823d, 0x73abdd68, 0xd4f515a8, 0x3f62e503, 0x07c729d6, 0xfd94f241, 0xf8b909a2, + 0x5778f66d, 0xcf72ebe8, 0x51c54843, 0xa4fe1ebd, 0xc55ca767, 0x07448843, 0x98da6cd4, 0x60d45a80, 0x5f62f25a, + 0x2b4e0fbd, 0xde0e0c63, 0xce759f14, 0x6f7d9f48, 0x89b732ad, 0x4a6aafff, 0xbec42b18, 0x0ab7429f, 0xb3b31182, + 0xfc1cf5ef, 0x1e641c97, 0x9467c694, 0x50c38edc, 0x64102cfd, 0xc871d4b1, 0x0e9092e0, 0x694e188b, 0x4bde10e1, + 0x86d1f74b, 0x91c8419a, 0x0332d3a7, 0xf01e4fd6, 0x3e497918, 0xc423d06e, 0x1da4d294, 0xa0e5f681, 0xfb1483c1, + 0xf727610d, 0x03cfbde0, 0x7493e19f, 0x095c5a7a, 0x4d7211cf, 0x5eabc160, 0x0fc31bba, 0xda45ed86, 0x7651af6b, + 0x3fea972a, 0xb05e76d9, 0x4dfe23f3, 0x3cb5eae9, 0x20ef74bd, 0xb23c5a27, 0xc92fba7c, 0x906c6e37, 0x31323aba, + 0x5a0fc327, 0x4c759318, 0xec9d8d79, 0x8fa2b630, 0xfe25af5f, 0x8b29dd71, 0x1f8057d7, 0xc4c6a70d, 0x8ea02d6b, + 0xa8aa03dc, 0x68af24d4, 0x9074268d, 0x8db4ec0b, 0xddc0a6f3, 0x6a98ee16, 0x6bde9594, 0xa1fcc41c, 0xcc21535b, + 0xeb3c1e36, 0xa20c25b3, 0xfcb95777, 0xf8c1ff3a, 0x9714190a, 0xbeb8e78c, 0x65b927e3, 0xca724de6, 0xe5ef9b27, + 0x007cd970, 0xdd9c1f82, 0xed551662, 0xb0b76adc, 0x9bee25e8, 0xcb0b8695, 0x59ecd2e4, 0xa7af4106, 0x053a216b, + 0xdbe18467, 0x9de5375e, 0xd9dacb64, 0x62e62d8f, 0xf90c84ea, 0x5e795486, 0x0a3a2415, 0xa4b28a11, 0x6fc46b05, + 0xb5306ba0, 0x4be028ea, 0x5e6e1d1c, 0xabed9c68, 0xb450fb3e, 0x3dbb1fcc, 0xa2c36943, 0x2e19f34d, 0xfe1b07b7, + 0x91492229, 0x6137d1a7, 0xd50ce194, 0x9ca6e73c, 0xbd2cf32c, 0x4df145bd, 0x044fb917, 0x2acf9ac2, 0xc12baceb, + 0xe5f9b664, 0x05f98c8c, 0xe5a211dc, 0x6450f7ce, 0x6be67193, 0x34a97a84, 0x4b07eaa6, 0x5b509b27, 0xe5f84b41, + 0x7a071652, 0x88fc9988, 0x2df3b3fb, 0x5514a4e5, 0xdbff836a, 0xf61b7d4c, 0x68fa2475, 0x6016f5b4, 0x9284b000, + 0xdf016c33, 0x577c44c9, 0x54034288, 0xae95f9d8, 0x00c9880c, 0x0a85d2ba, 0x4ff87592, 0x916cbe56, 0x6b81de3d, + 0xcce0bb2b, 0x1fa17015, 0x890760ed, 0xfe62c02f, 0x65828ee3, 0x76cd6508, 0x6dbe1c2e, 0xb2d3fb30, 0x1ec5d0e0, + 0x70a5f573, 0xe32a39a0, 0x197f6c6a, 0x44f4744f, 0x95f6cf74, 0x34de031d, 0xf981cdb7, 0x58c56dde, 0xe03c851f, + 0x4f4e4cef, 0xb3b8ca16, 0xb890473c, 0x1a492c98, 0x77944c3f, 0x4d9135b7, 0x5e8c3c14, 0xde7c104b, 0x7f3a4810, + 0x7562b4f2, 0x3526d045, 0xe73491ce, 0xcc3865e1, 0xd32be389, 0x25029c67, 0xd73bfd2b, 0xe0ce82cc, 0x757f3655, + 0xda2bd0b6, 0xc1e96df4, 0x8b69c402, 0x2ab5e34c, 0xffd12790, 0xd44d6266, 0x499c4d1e, 0x48de1871, 0x01281270, + 0x310ee468, 0x13cc4132, 0x39ec6828, 0x01eaf164, 0xc7d78bb0, 0x08358bbc, 0x2988b9f0, 0x1db9a8d9, 0x00ad3418, + 0x688bc88b, 0x0c5a8f3f, 0xc68aa1be, 0x24def579, 0x61d03962, 0xbeb347b3, 0xdeabe44b, 0xef726865, 0xc1dfdadf, + 0xe10ad45d, 0x7b9fa2b4, 0xcc61db49, 0xd466b43f, 0x8755b3f8, 0xd8faa290, 0xece7a173, 0xd28adda6, 0x5d2b8201, + 0xcdd0650b, 0x984495af, 0x12333a67, 0x531623c2, 0xa3dd9a2f, 0x35bb24ac, 0x82c10efe, 0xa73ea073, 0x8b87bddc, + 0xde4639df, 0x030a76dd, 0x1f2dc16d, 0xf209c8e0, 0x3b132fb0, 0xb622adc5, 0xdd0e9ecd, 0xa8617d81, 0x33728d71, + 0xf11fe1c9, 0x70d85f06, 0xbb6a6e46, 0xf4b3f768, 0xe72ceb84, 0xb527bff1, 0x9729c36a, 0x4952a17a, 0x267bcbed, + 0xdec7404d, 0x078e29c7, 0xfda23594, 0x7d905f41, 0x74c2ba75, 0xc0037884, 0x43c00b92, 0xea4436ed, 0x211d7396, + 0x78574dea, 0xaae5ddc8, 0xdc5aa1e4, 0x119350d7, 0xbeb281ac, 0xc2e3fe26, 0xfdb043d0, 0x2404689d, 0x881192ab, + 0x68634159, 0x499a5749, 0x17e33902, 0xfbbfff7f, 0xbf0def40, 0x0fd0e2e2, 0xbd57be02, 0x6e0b7507, 0xe481c21a, + 0x1b0d8fd9, 0x536758a6, 0x7563c655, 0x12642285, 0xdad58c22, 0xee80f7b7, 0xcae87fa2, 0xe3d4b29e, 0x29fe48ba, + 0x4c45ff7a, 0xd975392c, 0x81480fa7, 0x52a943d6, 0x216ea8f1, 0xf6dac1e6, 0x9118e4b1, 0x8936df8a, 0x3753ad08, + 0x7b5931bc, 0xed67d809, 0xe82aca73, 0x267c26df, 0xde20a002, 0xc89605b8, 0xc4a9e27a, 0xbf81348d, 0x37d58b17, + 0xf12aa0cc, 0x21474f6e, 0x83531ab2, 0xc1c64e92, 0xa988c317, 0xd22b2dac, 0x77fb2470, 0xe8b92358, 0xc34c34eb, + 0x1fc60e1e, 0x415a21a6, 0x5a7579f7, 0xb19fcd71, 0x31ccc287, 0xc8ef8e35, 0x6bedfba7, 0xcf2df363, 0x58cbc273, + 0x7903b03e, 0x18414877, 0xdfa7676d, 0x9a182a33, 0x3933fbc3, 0xdfa2ec2a, 0x9942f293, 0x9c581845, 0x345b4477, + 0xff189c09, 0xae5745ce, 0x400c298d, 0x9e7fde26, 0xe06c80ae, 0x91d02da4, 0x79f0dfa4, 0xdb5ff81a, 0xb44bcea2, + 0x0a8707dd, 0x53278795, 0xb674354b, 0xffaa8590, 0x0ee7b61d, 0x5b0dbc47, 0x02c14077, 0x5daf6362, 0xc26d6d1b, + 0x986b99a3, 0x62c75a02, 0x13cf083c, 0xdaed4278, 0x95b34fa1, 0x69586f34, 0x1db593f6, 0xba10e400, 0x65228259, + 0xe529b4f6, 0xe4abc739, 0x19ce7caa, 0xaa83afc7, 0x60034f74, 0xeb0ca1be, 0xd903d188, 0xea181e01, 0x824e6b62, + 0xec1bb8ce, 0xe6b1603d, 0x1ae860e3, 0xa485f4f0, 0xb8fa23bd, 0xdddc58eb, 0x861531fd, 0x6d452d78, 0xc01e2af1, + 0x1fb47965, 0x72f8d344, 0x7d60c2f1, 0x6617b903, 0x287a0305, 0x6162240d, 0x797701d9, 0x4d424cfa, 0x13f98319, + 0x3c31f751, 0x83e41d28, 0xc83d3b04, 0x7535f911, 0x0890f197, 0x60427c5f, 0xfa4f9cb4, 0x91582daa, 0xa8996384, + 0xeddc4d36, 0x888968c0, 0xcb6f2589, 0x5b9c8903, 0x0960913d, 0x26002119, 0xb66b90c9, 0xb1e019b4, 0x9ec15ad9, + 0x69544d2d, 0x616e59b1, 0x774e699c, 0xdeff7cb6, 0x74d01180, 0x987a91c2, 0x3480e35e, 0x153529d0, 0xf7bcd0e3, + 0x9f4ac4b9, 0xed0a5790, 0xa3a040b6, 0x917904ab, 0x42c22558, 0x3b02e5ed, 0x9869dcf9, 0x91557a01, 0xd57fa3ce, + 0x69b7d5c4, 0x4209cbe4, 0xd4b3c994, 0xb89edaa0, 0x96f337ef, 0x32455f2d, 0x4e1ffd5f, 0xed69cae5, 0x5ae57aad, + 0x9a9c186a, 0x2a926043, 0xe5747dd6, 0x5a4128e2, 0xd33a11c2, 0x6d70ab33, 0x7e293746, 0x857baf81, 0x5186e98a, + 0xd5f38534, 0xdc7bfc4c, 0xa409b175, 0x47b837cc, 0x32864edd, 0x7d49c555, 0x8ccee762, 0x2a4f07f1, 0x65568ddb, + 0xc1f6c788, 0x78f972b8, 0x38a9df6c, 0xd7bacf5b, 0xb74b7f3b, 0x4fb1357b, 0x8c1d9f03, 0xe3b239a5, 0x063defa9, + 0x8cd3d2c7, 0x53e5e78e, 0x84c57acd, 0x4a1adf65, 0x85eabd73, 0xa6d3b31b, 0x2bc09cba, 0xc636d014, 0xb82e6f23, + 0x6b9deb72, 0x14f5ecd1, 0x908d35c7, 0x8af1833f, 0x73b452d9, 0x7c952840, 0x982501b3, 0x7c76f916, 0xdfc0b98b, + 0x2a6bae99, 0xdbc485d4, 0xdc2ccc84, 0x6f8f3781, 0x9ac1f5cf, 0xde640dff, 0xf0f7d4fd, 0xf69dd0ff, 0xfc5bb9bd, + 0xf7daa63c, 0x862c2be2, 0x47d98bff, 0x96af84af, 0x4c3e7c12, 0xb702e478, 0x303bd1ed, 0xf4dd7dae, 0xf487a725, + 0xd57edbd8, 0xcbc1c182, 0x60936d1a, 0x02b2eb5c, 0xaec20932, 0x38af9a5b, 0x65c7631a, 0x6ff54d3d, 0x894c21bb, + 0x9447efcd, 0x994fbef1, 0xe5afc2e7, 0xc6faa2d0, 0xd8a2bc07, 0xc3b88761, 0x8edcb124, 0x2aa051b6, 0xe0e06191, + 0x4537e7ad, 0x520c47d5, 0xeb4208c3, 0x04dbbc4e, 0x823ce444, 0x583004ba, 0xdfb33c91, 0x4814fe0f, 0x054841f8, + 0xfb976ec5, 0x01589a01, 0x324b9c8d, 0xf1764472, 0x4d9c00d9, 0x6bb5e03b, 0xc2f1173e, 0x10686da7, 0x7109fe90, + 0x44993d2c, 0xc0fe50b3, 0x16742a56, 0x16c6175f, 0x44b57428, 0xa4a46c7e, 0x46507869, 0x5261f3c9, 0x64d38dee, + 0x44566528, 0x64a7098b, 0xae2889f7, 0x423ccd84, 0x2aa9f71a, 0x8879bf37, 0x1707cdb1, 0x0f37b469, 0x9ebd6c73, + 0x2625f830, 0xba1ca9f6, 0xbd6ea801, 0x1d3b94c0, 0xb66d32fd, 0x988b7127, 0xa70760a4, 0x8cfa3297, 0x8bb13533, + 0x1210cc1a, 0x56041781, 0x350d44e8, 0x5fcedbc2, 0x6948627a, 0x94dcdd31, 0xf9f632a0, 0xcc82d90b, 0x09f680c6, + 0x08d083dd, 0x06a38e62, 0xf1937b92, 0x700eaf2e, 0xa7c57e13, 0x2a28d181, 0x33ddbe60, 0x11046c80, 0xdedc1e0d, + 0xd455d83f, 0x1eaaea68, 0xb3bbbbcd, 0x9761eb6b, 0x3ab7ba8b, 0x587b3392, 0x2389b72d, 0x3f46484d, 0x49dd8fca, + 0xd58a06a6, 0x9d2458ac, 0x2c339dd3, 0xa636131d, 0xae6e667e, 0x0d329f22, 0x3afe7bc0, 0x02cf082f, 0xe2544e02, + 0x3453b875, 0xe016f464, 0x51a1eabc, 0xffc48631, 0x418f9612, 0x5ea182ce, 0x952e54e6, 0x692f9fb5, 0xd57e2cc6, + 0x3329f9fc, 0x3751e7fb, 0x35f23d9b, 0x168d36e9, 0xcf16d1e9, 0xf06c207e, 0x1d5638c9, 0xa4d17de5, 0x51199e52, + 0xe76f8a6c, 0x2a8f5394, 0x853a6797, 0x44628f55, 0xd4e7b036, 0xa104053b, 0x6f3209ac, 0xd2b107b2, 0xde04d6cc, + 0x0a527683, 0xfb2e3e12, 0x61b0cdee, 0x77ddabde, 0x7da17bdf, 0x98c98400, 0x54b2d53c, 0xccf6175c, 0x9630930a, + 0x876f4cce, 0x846c565b, 0x0cc26bd3, 0xbb8108d2, 0x90cf8863, 0xb8840a2d, 0xee737b8e, 0x59cb515d, 0x2f9fa2b1, + 0x0a1cd99e, 0x1f6654b3, 0x9162770c, 0xfd46eda0, 0x532c4b41, 0x91608dba, 0xa7f94b7e, 0xcf2603b1, 0xd0f6aba0, + 0x212a1828, 0xab553d0e, 0xaaece470, 0xcd332d35, 0x6cfc06b6, 0xfa39b499, 0xb461d3f7, 0x1b6cd71f, 0x587ed92b, + 0x47745171, 0x4974a6ca, 0x94fda23a, 0xe750c8b5, 0x8707903a, 0xd21fe0e7, 0x8ceacfa7, 0x275e5782, 0x9828a0d0, + 0xf4ff2a91, 0x73a19d30, 0x6f5f1c18, 0x046639af, 0x291ae266, 0x37402742, 0xd3465928, 0x844ae4e5, 0x8647612e, + 0x22e2a052, 0x2fc727d6, 0xb1bb47b8, 0xf1cdc4ea, 0x312af877, 0xe6fbe6cb, 0xc8cba1e6, 0x6d1beb64, 0x902a18e7, + 0x998bc0e8, 0x3650b81c, 0x4576089b, 0x435d3008, 0xa4219e2f, 0xb9be0074, 0xf6e6f60d, 0x8c2ebfba, 0x2a873bd4, + 0xe696ed62, 0x0a385396, 0xd85f3297, 0xd92565ea, 0x3f7dc798, 0x68e37b8c, 0x7d3d036a, 0x93ccf0e3, 0x2d99140a, + 0x60b0c8a3, 0xff8468b9, 0xa1821aca, 0x1dd6db0f, 0x47612cb5, 0xd40370cd, 0x3eae5655, 0x451298d3, 0xf2c834c9, + 0xf8bb738e, 0xb595ef57, 0xe248239b, 0x90449ed3, 0xc2331ead, 0x8da2d828, 0xd0629b40, 0xb9629a44, 0x7e1e1f51, + 0xfdc3d949, 0x7ac82173, 0x4e26b6a4, 0xc24d61a4, 0x41aa8fb9, 0xc87f344b, 0xe030fd6e, 0x5dd58040, 0x852c3cb9, + 0x69559ee4, 0x46bb3726, 0xa4894cda, 0x9477b6c3, 0xef03b51c, 0x39e2bf52, 0xbd273c17, 0xdd68f406, 0xe6460a77, + 0x2ea18782, 0x03a0c8d2, 0xddff8836, 0x594173d2, 0xdf02b399, 0x4ecf6d97, 0x7c57227d, 0x2f4415ea, 0x3bb5bec2, + 0x23f04d66, 0xd3b14294, 0x2e34c451, 0x9971c9b0, 0x950e793b, 0xcb50fbaa, 0xf77adddb, 0xe7eef8df, 0xa0709d26, + 0x5fdf52da, 0x802f24e5, 0x7bd74419, 0x9e131819, 0xda8a6409, 0x53fb228f, 0xfeab0763, 0xb359014c, 0x2ee545ed, + 0xfa31310d, 0x3b87fe6f, 0xb8dc7813, 0x6b7859e5, 0xcc005af6, 0x19745f5c, 0xd381593a, 0x0d09a4c3, 0x37ffff8e, + 0x6dc17d8c, 0xb9c1d371, 0x6e66a5b0, 0xdd701586, 0x370439c2, 0xb131c9b1, 0x1e3dbd76, 0xa2cd8920, 0x40af3d3b, + 0x13f27d79, 0x8e604d65, 0x898dd753, 0xbab4efb6, 0x1b430f3f, 0xda2cf013, 0xdad869ac, 0x6d1b45bb, 0x0a261db3, + 0x89d221ae, 0xffb61ccc, 0xf8518d2e, 0xde15898b, 0xea24dae5, 0xfbfdf5e0, 0xfb8923c8, 0xccb0984c, 0xf3798bbe, + 0x8ed40254, 0x21edf061, 0x65f1bbb7, 0xa603f986, 0x45ab603a, 0x8bebd3dc, 0x97b2457d, 0x12dca365, 0x1f9f0b29, + 0xfd755ae9, 0x7c8fd0f2, 0x8f5d34df, 0x3ab962f3, 0x6965feea, 0xb00edf17, 0x6f5ce1d7, 0xa1cf6d80, 0x387f79d9, + 0x5f3ed63d, 0x46150e60, 0x3138a5f7, 0xce1acac2, 0x0c9329df, 0x3000a695, 0xb1ced29e, 0x3034205e, 0x1f6100f6, + 0x56fd94bf, 0xdcf99b08, 0x24d7bf67, 0xa664c0ca, 0x0af51907, 0xba13ab7f, 0x77f805f6, 0x73dbccd6, 0xb7b85991, + 0x5001fc48, 0xbeb783a4, 0x283e7e2b, 0x92d11774, 0x90e03e10, 0x8c09ca58, 0x6fd3a21e, 0x348892fc, 0xf042bdf2, + 0x63a8fe13, 0xf8a91207, 0x6f818e2e, 0x8bf65341, 0x8b2cbb44, 0x183f909d, 0x6b66f795, 0x7c94a9ce, 0x32b86a45, + 0x5e68d925, 0x169bd896, 0xd83dbbc0, 0x97fbf3bc, 0x52ddb505, 0xa3bfcb7a, 0xd5e3d6a7, 0x3824bf37, 0x5d7d8f93, + 0xd11e4b7e, 0x629ba92a, 0xdeeef067, 0x86a86e6f, 0x28cca596, 0x193989e3, 0xf63d73bf, 0xc10bda4f, 0x0face5aa, + 0x9057d975, 0x42de856f, 0xd2c1ca09, 0x2847ce5c, 0x39b47e61, 0xf8db26a4, 0x57c4ef38, 0xddf0f4ad, 0x3f5c2cec, + 0x2cc37d0f, 0x4c292764, 0x60fdab96, 0xaf3bd44c, 0x3532e8a0, 0x371c60ea, 0x4dca1632, 0x1d050ef2, 0x96e9446a, + 0x7f3f5a0a, 0x7e5ef0e8, 0xcaa902dd, 0xb834d634, 0x505f9098, 0xf9206af2, 0x75d77477, 0x689bfb66, 0x7f7cff15, + 0x65ec33f7, 0x86afdfeb, 0x886266b8, 0x681c6bc8, 0x6e9f2ebc, 0x825a9cb0, 0x39153a41, 0xd3f77ee8, 0x29ba9bbe, + 0x489f8815, 0xded951b5, 0xccf89150, 0xeca7ef73, 0x5d6f0dc5, 0x972af5fa, 0xad497288, 0x0c63cfc9, 0x2c85a659, + 0x505a1224, 0x3202e675, 0xa8c7236d, 0xe46833c4, 0x7093f0c4, 0x57b18ad4, 0x148897c9, 0x271bbadb, 0x6da15de6, + 0xc6d836c8, 0xb3a511b2, 0xef81af7e, 0x5449124f, 0xb89a1960, 0x597ed44a, 0x7cbdd184, 0x4ccf3604, 0x10a397d3, + 0xf6bf9bce, 0xcacaec98, 0x588475ba, 0xc3efcbad, 0x2e486ae1, 0xb853d99e, 0x3008a014, 0x3c044aa4, 0x7e3218be, + 0xa48e302d, 0x82c36c8b, 0x65ffd258, 0xad0814ac, 0xdd007708, 0x0dcc4dd2, 0x18b87d82, 0xf7149bfb, 0x7ba2e8e3, + 0x3ec1e5e3, 0x33d7eb5c, 0x1604207b, 0x51fd39bc, 0x8a401071, 0xbf451683, 0x3899b798, 0x02f9afc2, 0xc1303954, + 0xfe45031b, 0x885dd905, 0x6c47be9b, 0x3287561b, 0x57b254d1, 0x55bf77db, 0x8bdfb5b2, 0xcf16e1cf, 0x71f7262d, + 0x032473d5, 0x7e4bef5c, 0x8c16a0fa, 0x2dc2cfd7, 0xd3c3d218, 0xe4cd70a6, 0x7df30e47, 0xb489d2bd, 0x291a543b, + 0x3703feb7, 0x1591136a, 0x0e6ebb0c, 0x9a3ad1aa, 0xadfcf266, 0xdd7d5716, 0xbd2f2f35, 0x16b2ca68, 0x58466871, + 0x3b0f7d89, 0xd2913e4f, 0x31b6d056, 0x16223387, 0x53223c11, 0x7756519e, 0xb5bb9bed, 0xc909f7b0, 0xa6fbf928, + 0x3ccbaf70, 0x71cf4e28, 0x4c8effc6, 0x00b20b28, 0x631554d4, 0x5d9c14fd, 0xb6746894, 0x952acca2, 0x848290e4, + 0x7a2f80b9, 0xc83f2d20, 0xbd316542, 0x70b3cfa9, 0x9078446c, 0x64ba95a4, 0x49f7b865, 0x289aed69, 0x00084efe, + 0x655ef8a4, 0x3c56c3df, 0x693728f2, 0x30f1d25d, 0xcdb0770b, 0x07966b17, 0xeba6fb1a, 0xbfae7c19, 0x609acc63, + 0xbdd991cc, 0x34a2b280, 0x2e5233dd, 0x9398c506, 0x20a7794e, 0x8a8167a9, 0x766a8b37, 0x1c689089, 0x20c543ff, + 0xda2c54cc, 0xc87e2daa, 0x17d58646, 0x7b8bfd57, 0x41c130d5, 0xd695deba, 0x560c9a2f, 0x7c067081, 0x0ee60d45, + 0xf63a13d3, 0x6c0b0c57, 0x9782b1d1, 0xf7360509, 0xe4cc89b5, 0xd884bf93, 0x10a48f8e, 0x0a161c5f, 0xa64a8a2e, + 0xfd262ceb, 0x4d0776a0, 0x337cd0ef, 0x7d312514, 0xf194cc6a, 0xf7835bba, 0x79f22a0f, 0xedf85e9b, 0x452ae25c, + 0xf77d79b3, 0x5012cfa4, 0x73b9f437, 0x743ecf98, 0xc53775f2, 0x814bb57f, 0x57d955fc, 0xde04b7fb, 0x340711e1, + 0x6c995dbc, 0x2d88c187, 0xf082ed74, 0xcb92c8e7, 0x09e865c8, 0x5d3eea34, 0x78ab309a, 0x2c3b1a5f, 0x6643edc9, + 0x7694b162, 0x964b722c, 0x94336de7, 0xc9f45166, 0x42b6ea82, 0xe3037b36, 0x491e28ea, 0xe1ffafa9, 0x86247f09, + 0xca06b1ed, 0x09834dd3, 0x3e6a56fa, 0x0ee87c9a, 0x2503ab54, 0x73888840, 0x39896c4d, 0x3ba83ac2, 0x599ab59b, + 0x2cb8b814, 0xed049d0a, 0x0f6c7ba1, 0xdf44560b, 0x832bd5dd, 0xd5dcb4bd, 0x3cda1feb, 0xd0a9f12d, 0xf7e5cb90, + 0x9dfaa046, 0x7c69913e, 0x155bdf17, 0x4d496277, 0x5a2111f3, 0x830daf69, 0x209dec5f, 0xd36f804c, 0x549022f0, + 0xd2ceb54f, 0x8b671a7a, 0x59786181, 0x2d33eeaf, 0x906a3ec2, 0x8e6fce77, 0x93dfea7d, 0x3f9396db, 0x790e19e6, + 0xdf0ba712, 0x6c833bd7, 0x8085461c, 0x3e1f95d9, 0xc33b2eac, 0xa1e7621f, 0x64c828c3, 0x00121642, 0x0763c90a, + 0x61c10587, 0x7fbc138a, 0x9a858882, 0x906b5f83, 0xcd3d40d5, 0x0e92498e, 0x25c1622c, 0xe539ea51, 0x747d357f, + 0x5440dce6, 0xd8e04dfc, 0x2d03b801, 0xd364f450, 0x01b590ef, 0xd350c867, 0x5e50d978, 0x9864ad14, 0xc737d7b3, + 0x0ec3769b, 0x291e836f, 0x9f2e677a, 0xfa7fd941, 0x2abe19e4, 0x51cf0413, 0xf7e64a9d, 0xcade1038, 0x7aa46ab9, + 0x5e7ea657, 0x23eb3175, 0x2b56f816, 0x99e034b2, 0x1fc70356, 0x8994c490, 0x6633a069, 0x359be47f, 0x48423d8a, + 0x47d51c37, 0x181ee27a, 0xd7fae015, 0x4888ab2f, 0x61c990a6, 0x55ada3b7, 0xcf629e92, 0xee877822, 0x84ba01cc, + 0x9fbb099e, 0x97f6dd5d, 0x8f601869, 0x08f40f44, 0xd9981f3d, 0x6962b2d0, 0x6b962f98, 0x87e8d0a3, 0xf46d7dd0, + 0x001d5042, 0xd6e7fccb, 0x1c49321a, 0x47819490, 0x1e7bc9f8, 0x89a3eaef, 0xc746086e, 0x023fb4b7, 0x9056f1e0, + 0x39717880, 0xd0fc02e0, 0xf94ba0bf, 0x81303dae, 0xd2a3cf6e, 0x19cdac12, 0x879e02de, 0x51d1102b, 0x24c83b6f, + 0x7644613f, 0x3f782c8a, 0x07cbcab2, 0x10aae983, 0x7cb98fad, 0xf1eb2a12, 0x0b45e053, 0x4d216ed2, 0xb0bd30c8, + 0xcb392a04, 0x4b8104ca, 0x20db3550, 0x4f4a3b12, 0x6bfee79e, 0xc69784e0, 0xefa22b5b, 0xf87fedbb, 0xe4d7a45f, + 0x4f821647, 0x862f2e36, 0x3613d265, 0x0ed98351, 0x613fdc0d, 0x5f2132be, 0xb16e56bf, 0x004144b5, 0x7ee90d4f, + 0x833bbe2d, 0xb9aec0fd, 0xa3b62fb3, 0x440bfe6a, 0x6fcd90ea, 0x00efbccc, 0x0625c238, 0x3982db21, 0x0628cce6, + 0x65e9afa9, 0x2ceaa3c7, 0x508e0b1a, 0xda07594e, 0xd5c20d1b, 0x75b97be5, 0x8f6fa2d8, 0x1d2c2479, 0xb23e6918, + 0x043d4ddb, 0xbfed2ec5, 0x3ff038cc, 0x86d5ff8b, 0x7a483627, 0x82e64716, 0xaf11d374, 0x0bc3c2dc, 0xef76d61b, + 0x7cdb00ea, 0xcd1d3ff6, 0x069a2877, 0x7f964902, 0xf1db3495, 0xd29542aa, 0x99d6fbfe, 0xfa04bf90, 0xbbb9845f, + 0x3fd9ada4, 0x1cd76fa4, 0x532f5e3f, 0xeb5ea56f, 0x019c3949, 0x2ed40b6e, 0xfff601d8, 0xf65682d1, 0xaba49ce9, + 0xf0208a45, 0x52c84c1f, 0xbd78d1bc, 0x66f28975, 0xb9a8e4d4, 0x3b8fb2a3, 0x86a3df1f, 0xcea21b90, 0xc674dd39, + 0xb98b673a, 0xb4f16bc9, 0x7c4e0f06, 0x82e5410a, 0x8d5025f4, 0x3b2f3c86, 0xb78bf393, 0xc257519a, 0xdb474e52, + 0xb93e2ea8, 0x123af5a4, 0x94801eb6, 0xaf9eae90, 0x4470618f, 0x9f63c681, 0x75d7ee86, 0xa415f825, 0x6467b108, + 0xd547c357, 0xeb52b02e, 0xb53d1553, 0x1f61bb5f, 0x59631ea8, 0x79b68a12, 0x89d81316, 0x29263085, 0x83a32a84, + 0x9fda9104, 0x63fa641e, 0x31e6320a, 0x12f60406, 0x54fadbf2, 0xb48ad27d, 0x91a34f73, 0x227813b0, 0x99469062, + 0xc8bb02ff, 0x35234899, 0x618eabe9, 0xdfdd07be, 0x1b7092f1, 0x44931372, 0xb1eaf494, 0x3fcc3772, 0x711db168, + 0x018cd961, 0x7e71c111, 0x8d11ae86, 0x6b9b3784, 0xe01145f5, 0x4064422d, 0xc1595fee, 0x160933c9, 0x2d7946b1, + 0x0dc0afa9, 0x5e0d9019, 0x8c56a389, 0x97ab3c21, 0xae10fb01, 0x7dfdf8bc, 0x5fd1cf28, 0x623e8424, 0x1f0f4524, + 0x24ee4f2b, 0xac1fac82, 0xdcf2fb12, 0xa7f46d09, 0xf55e9473, 0x92686e2a, 0xf1e31834, 0x653b6c05, 0xa74d83e8, + 0x46111c09, 0x91fe97dd, 0x81916481, 0x19bfbcd8, 0xaece0683, 0xecd24d6c, 0x0a000608, 0x0fb2b836, 0x2bddeaa3, + 0x04b2d797, 0x420c816d, 0xdf1deabb, 0x2132ab53, 0x1fb1be50, 0xe98f793b, 0x3489dcbc, 0x0f8829b1, 0x59bb3b9d, + 0xf23cb106, 0x02a8ee46, 0x10566980, 0x43fc5ef2, 0x53f82e9d, 0x6091d261, 0x3604d77c, 0x9b8fcd43, 0x264895e2, + 0xb7270762, 0x9cfc6257, 0xaa36c9bf, 0xce4aea91, 0xd00132c5, 0xd1042c65, 0x9f43739c, 0x6f218976, 0x9ced3b49, + 0xb30b9920, 0x0bd6846b, 0xf6d6a9c3, 0x4aea8e05, 0xd8a8ea51, 0x7602c3d9, 0x246c2801, 0x157546ac, 0xea8e2b9f, + 0xa6505ac4, 0x9992a20a, 0x226b467f, 0xa8c40276, 0xa081698e, 0x6bb3b587, 0x7407a323, 0xcd637d1a, 0x464289bb, + 0x1772c27b, 0x9a9e7ce2, 0x9f3bb7ca, 0x47393e31, 0x15235f1c, 0xb7d1b47d, 0x1d0484c4, 0x1e6fcd1c, 0x84e20508, + 0x3e0d914d, 0x306a2d51, 0x36f83038, 0x45abfd3f, 0xa5129977, 0x3c80a330, 0xa3179aff, 0xea2f603b, 0x68d1bb8a, + 0x97084f99, 0x1d895720, 0x18f128c1, 0x7f714fbf, 0x78804925, 0x215166ac, 0x1a7b6cc7, 0x1a11ac7b, 0xe9869d43, + 0x758ba800, 0x825c7173, 0x628891ee, 0xc311fab7, 0x235535fa, 0x4ddce492, 0x17264bb9, 0xc3026783, 0x2ead30f5, + 0xb3d84ece, 0x45694859, 0xbf87d29c, 0x6ec18b40, 0x076fb909, 0xe8559203, 0x3bc6d02e, 0x507a54da, 0x830206eb, + 0xfafc9823, 0x15f397e9, 0xfa7814d7, 0x0f0c234c, 0x74e87fa9, 0x1b45fda7, 0xc7432d61, 0xc3e7e56b, 0x8a612cf2, + 0x1b7e8996, 0xe184c49f, 0x3037c631, 0xae6128f1, 0xd11d4f26, 0xbf0ccc57, 0x29154d2c, 0x17ea5282, 0x1eb96042, + 0x32dbc192, 0x367ff089, 0x3e4062a8, 0x5c229832, 0x9a3209de, 0x9df74879, 0xf2b645b5, 0x8222fbb8, 0x89e72368, + 0xbea4267a, 0x4b24b394, 0x94e0ff6c, 0x90fdea48, 0x8da628cd, 0x921a1129, 0xa691a11b, 0x43266e80, 0x7f0f75ad, + 0xd62ba917, 0xebdf2333, 0x2b069558, 0x4ac78286, 0xcd7a09ae, 0xf62fdecd, 0x2cee7964, 0x8d4f358e, 0xbf59ecf3, + 0x429baf00, 0x48dbcca4, 0x3d1f29a9, 0xddd6e316, 0x9c13f072, 0xf340efd5, 0x026d671b, 0xaceff9d4, 0xde1e8d71, + 0x008596d2, 0x3b1b24c6, 0x6ca347e2, 0xe436392b, 0xa3cc1200, 0x8af66ff8, 0x5673b9c8, 0x83d7b347, 0x43863797, + 0x856d8865, 0x52f3bf76, 0x8ef56884, 0xd3eb82dc, 0xe13fdf1a, 0x84f805b7, 0x72abc88b, 0xd4da8ceb, 0x635fcb6d, + 0xb3b7c831, 0xc21e0a26, 0xf1f28ed5, 0xad20fc04, 0x1af09496, 0x7c15abba, 0xd96b8d95, 0xa723f95c, 0xa1e29cc6, + 0x1555d746, 0xeb45522f, 0x67fcc902, 0x8fcb47ef, 0xda48505c, 0x75c19b68, 0xf037f3ef, 0x9f27148b, 0x022b41d7, + 0x9fc5f022, 0x3814db5f, 0x3721ab99, 0xaaec519b, 0x3cb4be4f, 0x7c8129b9, 0x15f8c847, 0x47e0a047, 0x1578fd09, + 0xe5c4996f, 0xa60da0ea, 0x7689489b, 0xb7ddb8bd, 0xd6a04ca1, 0xeb9eea2c, 0x87de447f, 0xd85e1ec0, 0x68ed4d77, + 0x4fd7c3d0, 0x16804519, 0x6d9a1b50, 0x54bbeecf, 0x80947a96, 0x39f8701b, 0x52639fcc, 0x3eb677f4, 0x8a979be1, + 0xf59bdfc2, 0x3e57925b, 0xc709ff74, 0x389a2e52, 0x8215a845, 0xd07d827e, 0x1dcb47e6, 0x44dbc6db, 0x91d14a76, + 0x5752b1a8, 0x59cce776, 0xd50ff5c5, 0x8c739224, 0x12b58960, 0x7907ba13, 0xff9d6370, 0x7f64ffb6, 0x2b17df4f, + 0x1a625a22, 0xd6487408, 0x41957b40, 0x61d14ea0, 0xfe3b18f3, 0x9494a268, 0xa9336805, 0x49bd093d, 0x565407d5, + 0x8288fd2f, 0x5e9db215, 0x7594a980, 0xf29c229a, 0xe5b89f23, 0x9ed21fd8, 0xeac9e844, 0xb0f5feb3, 0xf3321082, + 0x3c9cc813, 0x31554040, 0xd0fdb47f, 0xbc3f90ac, 0x63061f40, 0xce8e6f4a, 0x1a438be4, 0xcf8884d2, 0xc650f01a, + 0x277647e1, 0xc5439248, 0x2871e657, 0x6747a086, 0x81d1244c, 0xefed2c7c, 0x0799cab1, 0xf56fa71f, 0x7cc868bf, + 0x38723500, 0x45cef67d, 0x3649405d, 0xdffa9fca, 0x5ea29c54, 0x798d2dfa, 0x943849f9, 0x591d8f7c, 0xcbfce62f, + 0xc19decbb, 0x98f0a74c, 0x8e43992a, 0x21965e93, 0x0abbf6c6, 0xae7bc0c3, 0xe6aceb96, 0x9cf8af4f, 0x94ce8d6c, + 0x95764ee4, 0xfd329b77, 0x92ae2ffa, 0xf9ca1760, 0x2569c899, 0x3e48bda9, 0x2621fbaf, 0xe1123f1d, 0xdf60a3cc, + 0x5e2bc02d, 0xae4281d4, 0x386cedbb, 0x4ca65755, 0xfc26f91f, 0x88568f40, 0x331f2259, 0x5e90e086, 0x93b505ae, + 0x16c92d1c, 0x2bd83fd2, 0x67f9a4ef, 0xad9c85f2, 0x6b452cd7, 0x2c73097a, 0x19efed2b, 0xabf83fe5, 0x0db2903b, + 0xe0ea9efe, 0x64459836, 0xdc0e804a, 0x346d1e16, 0x8956e13e, 0x9e2d7844, 0x3d7f52bc, 0xb18ddb48, 0x5fa6ea5a, + 0x8fcb92d6, 0x73b24665, 0x6694150a, 0x801854e0, 0x245fe7ab, 0x038eda55, 0x07e3c1e3, 0x55d36341, 0xd381a1c9, + 0xa1653cab, 0x19854b2a, 0x12811ab7, 0x28481a14, 0x272c08b8, 0xf929db52, 0xa4354e9f, 0xd9be7fa2, 0xa11ca3cc, + 0xa00fe3a8, 0x46c2ad6d, 0xf17cb0a0, 0x4011ade8, 0xda95a177, 0x9bdbf54f, 0x5623411b, 0xca3cdfe3, 0xda1b3bdc, + 0xf48c0b18, 0x7d788ff1, 0xb7656505, 0x6545ad72, 0xa05550e3, 0xf410fa6e, 0x853e367d, 0xbc703d2d, 0x49e3ae02, + 0xc3fe2e7a, 0x44c64590, 0x0828251b, 0x86755ad9, 0xedf042d3, 0x98657c61, 0x74bec45e, 0x3ec0823b, 0x8cb69dd6, + 0x30210b3d, 0xe8c95457, 0x92957c81, 0x90c9933b, 0x7d7bedbe, 0x906ee0fd, 0x97e83772, 0xa6ef68d6, 0xa7ab1e3b, + 0x553518f8, 0x62fad740, 0x67149aae, 0x0a42c36d, 0x18bbdfdf, 0xa4baf3da, 0x1645f261, 0xe21fa7a9, 0xf7315c5f, + 0xa4654fe8, 0xd2b1aed7, 0xf81fe581, 0xb586e19d, 0x61857558, 0x0db0ab20, 0x326d8954, 0xf12caeeb, 0x3a92f4e1, + 0x3f7f0742, 0x47be0eb6, 0xb2cf5e8a, 0x8235ac98, 0x80cc9aa6, 0xbfcbbde3, 0x3353fbe8, 0x9189e281, 0x2d68edab, + 0x1b0f606d, 0x5fc6ef64, 0xa0ebd164, 0xb8ef1721, 0x83b0b926, 0xb8c06320, 0xff45c4fc, 0x2b2fbab0, 0xc6452c47, + 0x0312d4ed, 0xcf40ed7c, 0xf8509566, 0xb8727bd8, 0xd5e91940, 0x89123f21, 0x733515dd, 0x94d48d8c, 0x9f1e7edd, + 0xa388c85f, 0x84c9667f, 0xbeaa6757, 0x971d9104, 0x0290f443, 0xc182a145, 0xd80d0be5, 0x5093bc04, 0x8683322a, + 0x36c7619b, 0x4f951c68, 0x5f42a014, 0xa1e7a943, 0x27e52f9a, 0x63b85436, 0xa72715f4, 0xd9ee045b, 0x6f545da4, + 0x4353b26d, 0x33ee4c83, 0x894ab7fe, 0x087ed6ae, 0x7f66c8b0, 0xa8956e33, 0x7032f6c8, 0x41d31469, 0x8265b2a9, + 0x0ab6adf7, 0x487b56c0, 0xe29158bc, 0x073568a2, 0xfbb43ff1, 0xf9395927, 0x325dbdb9, 0x9b6b54fa, 0x064eb356, + 0x7e52e5d2, 0xde767acd, 0x0aedd594, 0x548ab6b6, 0x1cbf9565, 0xb798e145, 0xbb170670, 0x6766c14d, 0xc339dff8, + 0x2c680dc9, 0x41870bed, 0x373eb053, 0x5a003b57, 0x96e2865c, 0x61a15301, 0xd91a911e, 0x06949dff, 0x2ff818d4, + 0xa31d45a8, 0xfc9f5a33, 0xf7b567fd, 0xbd8e6033, 0x149999b5, 0x94341a46, 0x2dbd8022, 0x9519cfe4, 0x2488f5b4, + 0x763a5f60, 0x04d8080c, 0x88ad6b74, 0x817f611b, 0x52704b46, 0x4c555249, 0x64a1c4cc, 0x776a64bc, 0x43227bcf, + 0x1ed3d3e6, 0x7e48a05c, 0x12291992, 0xa9698ba3, 0x51c14ecf, 0xa8b3b5e8, 0xf810268b, 0x23ecff5a, 0xe143e8ea, + 0xe075cb1a, 0x9faeaedb, 0x83cf5d7e, 0xdd61d7f7, 0xfacc42b9, 0x79a15c96, 0xf3af4297, 0x5eabdd2c, 0x5db3bb00, + 0xdda5ba22, 0xd095de89, 0x05b3c26b, 0xdf172f2c, 0x13fcb311, 0x6b984612, 0x7f3b4caf, 0xdd0271ef, 0xd0fcacf7, + 0xbb689bd7, 0x8145b41f, 0xf761a3f8, 0x15c9540e, 0x95d6ad51, 0x48e89127, 0x118ad058, 0xf0eaf605, 0xb82a8183, + 0xdd7b2ad5, 0x46624678, 0x5dee669a, 0x9de7392c, 0x40e01d31, 0xc7734389, 0x3d4f2f73, 0x732fdadb, 0x3f0d3e33, + 0x24cbe961, 0x10350b38, 0xd27448a4, 0x59670dac, 0x498b1eda, 0xee121929, 0x48a658c6, 0x939cbe9a, 0x6b524b22, + 0xdbf8bcdc, 0xffba7cb8, 0x98c9a535, 0x67721661, 0x764aa15c, 0x826a0dae, 0xa50f71d6, 0x5dfe5f3f, 0xb807d16c, + 0x598b3f86, 0x1987755a, 0xd37fc539, 0x80d1c2bc, 0xc0a40594, 0xa2175a79, 0x79eeb5cb, 0x770b6e91, 0xff542ae8, + 0xc7e83c57, 0x02632100, 0xb3c70377, 0xee336140, 0x89105797, 0xd81785c6, 0xa7145523, 0xc00295bd, 0x1174a551, + 0xbcc36260, 0x9525366d, 0x0d29d8d0, 0xb8878333, 0x951bdf68, 0x0d13740a, 0x9b291a42, 0xfdc80627, 0xd847dbb7, + 0xb926875a, 0x7136b488, 0x536ffb4d, 0xce7be39d, 0x9beb06f7, 0x5e303eab, 0x0b0244d5, 0x1cbb969b, 0xc0652244, + 0x2ccd3df7, 0x17c4ee00, 0x07feafbc, 0xdd957f88, 0x7caa1cda, 0x7e6af46e, 0xfdc8f2fa, 0x25abc11b, 0x6025aaed, + 0x79eb6569, 0x02e7ac8a, 0x304ed5b0, 0x896ccc3a, 0x2f621ef5, 0xb22e57be, 0xafd79ddf, 0x011eeaf4, 0x311fd643, + 0xc703a762, 0x89e505a2, 0x16c115a2, 0x0891bdfd, 0xe26c6e95, 0xa7b3fb90, 0x5df8523a, 0xeb011829, 0x134d3a48, + 0x1a25506d, 0x0a03ba68, 0xa6027317, 0x1a346762, 0x6ccae43d, 0x9eb304e7, 0x0fac1849, 0xf7d703f4, 0x5bc4aef4, + 0xe98dd563, 0x2ba35970, 0x67b15f98, 0x60d72386, 0x4634655a, 0x8938f6f3, 0x0a5fa227, 0xeabbe333, 0x169914a8, + 0x53a30f35, 0x164ad5fb, 0x3e58a9fa, 0xc7365072, 0x69b2b25f, 0xe0a7ed0f, 0x5e9380c7, 0x4a65fff1, 0x974c1a3a, + 0x240f103d, 0xb7ac44a3, 0xc732598f, 0xc0b58db5, 0xb07ea775, 0xff83eafd, 0x7bc3900d, 0xea7d2792, 0xff4cc8c9, + 0xf6cf1971, 0x15b17a13, 0xc349cc11, 0x634c15b6, 0x80533794, 0xe70084dc, 0x05df5c55, 0x2642ed59, 0x5406be65, + 0xc7aeaae1, 0xc426955f, 0x316e23f8, 0xd06c8373, 0x36a6f2c9, 0x14181642, 0x73bcab85, 0x6ac876cb, 0xbb4b5f38, + 0x52a9040f, 0x4bd423ca, 0x4f073fcc, 0xc71b0178, 0xfca0a25b, 0x8ffcf911, 0xfec5f6c7, 0x52d5029d, 0xf9cdee80, + 0x7eef2085, 0x2f5f7dab, 0xcc3c632e, 0xea8f5f55, 0x7ccc3615, 0x5736bad7, 0xb1ee70c4, 0xd8e4c618, 0x9420df0b, + 0x7d41dfec, 0x5718576d, 0xcd75c279, 0xc50472e5, 0xb63b0a7e, 0x6f5d1242, 0xc3b089d9, 0xc86a9a2d, 0xa8ad2d15, + 0x5dc71018, 0xd16cc50f, 0xf986411c, 0x2829ec16, 0x81f17cf8, 0xcee5fd37, 0x0e13da88, 0x246998e3, 0x29dbf525, + 0xcf920504, 0x4fa92c51, 0x4c22c890, 0xb7c96c54, 0xf3db3899, 0x924627e1, 0x1a4d84f7, 0xfb86a121, 0xc2fbc639, + 0x329b71c2, 0xa62d6191, 0x245099dd, 0x5b68962c, 0x7d23d510, 0x00b44c67, 0xce3f77e2, 0x9ffb2201, 0xc78c71cd, + 0x6e072dee, 0xcdf582e1, 0x1aacd81b, 0x1fdb27a5, 0xc508751c, 0x64ae3778, 0x41179da3, 0x4516d672, 0x11597eab, + 0x33837c8a, 0x1f082c99, 0xa348a309, 0xbeda0b4a, 0x342b7baa, 0x443fb227, 0x73389c57, 0x86ef3779, 0xce037beb, + 0xebeaa4b0, 0x4830b06f, 0x5adc2ca7, 0xc0565c2f, 0xb31ddc25, 0x2b05f7c2, 0x124c5484, 0xd0d479df, 0x14d4c2a3, + 0x2ee855a1, 0x73ef664b, 0x4d28b75a, 0x9fcda8f0, 0xdb4c4ead, 0x123f2ff3, 0xa5d02a3f, 0xd7e89f7b, 0x0f0c5751, + 0x16d7ebd1, 0xaae13383, 0xebad6216, 0xc3139fa8, 0x74d37415, 0xedf97e9f, 0xd3316472, 0xcdd17d8c, 0xf5bb7ba2, + 0x89bf42e3, 0x83c9e014, 0x919fc821, 0x725cef59, 0xf4e03ec5, 0x7c7fea69, 0xf79d0533, 0x3be48132, 0xcce58c76, + 0x5dffa016, 0xc2320c1c, 0x7c662373, 0xacc4da05, 0x5134e06b, 0xf2a8175a, 0x8457d508, 0x96155acc, 0x89fd7829, + 0xc22b3f8a, 0x2e22b85a, 0x89efb2f8, 0xbba22261, 0x706600c7, 0xacb8a373, 0x01aa735c, 0x156baba0, 0x2e43cca3, + 0xb1e90286, 0x9a8b95ad, 0x1c166506, 0x04d4629d, 0xe646b4a1, 0x7cd2a2d0, 0x72e8b1de, 0x78a4a1d4, 0x045fefc5, + 0x55693f27, 0xe1535a8d, 0x2fa35478, 0x6acf67b5, 0x8bbb9664, 0x36902397, 0x7ebd5094, 0x014a9f22, 0x3e249290, + 0x80d0e39a, 0x0b7700b6, 0x3bcfd87e, 0x259ba995, 0x5f9c47db, 0xa3f3843a, 0x8eccb330, 0x0a969014, 0x1fdc4c80, + 0x1fd78674, 0x3959bd0f, 0xf2cdafd8, 0xb6317529, 0x57c148a3, 0x01b38bce, 0x63fa3599, 0x2b836672, 0xeeb8b979, + 0xf3c418c9, 0x200cb1f5, 0xa81dd589, 0x34275470, 0x1d7219ba, 0x43c2d71d, 0xbc1af342, 0xe4033de4, 0xe91d12d8, + 0x2e50b031, 0x521d7ff8, 0x899a5d7b, 0xe7b3e1e6, 0xd3895beb, 0x5b0e1aaf, 0xcae381f4, 0x5d7959a1, 0x10d0d8d3, + 0x1f562b57, 0xe0c27f7a, 0xe68d4fbb, 0xab0e71cb, 0xd40eca39, 0x8011ca7e, 0xd19ee0f7, 0x179012b6, 0xdc20754b, + 0xdd1912bb, 0x313bde0b, 0x9f5159bd, 0xfb2730b5, 0xabd32262, 0x12f59fa3, 0xc37a78bf, 0xcb3d2aa5, 0xf98ee8e7, + 0xcd9de5e7, 0xedd0ffde, 0x637cb85e, 0x7f8ef717, 0x4a65feb2, 0xfe2da1f1, 0xb2a7c929, 0xe5113c84, 0x0bc06737, + 0x2d774ac9, 0x7bac0ab8, 0x617f5aad, 0x03fd78ce, 0x6f266125, 0xd394915b, 0x6a4b7c43, 0x56b40dc4, 0xc5dde566, + 0xec226d0e, 0xfce627b3, 0x037207f4, 0x6899ea88, 0x3674a3bf, 0x60f9c76d, 0x4c40c8e5, 0xec4e7dd9, 0x5670f0a3, + 0xeffaaf7b, 0x6a060fdc, 0xfc47e40b, 0xb39ddfe9, 0x0dfb20ea, 0xa3bde803, 0x5169916a, 0x3cb4da42, 0x7d5b9fe8, + 0xef905f11, 0x4e23b57b, 0x24a33ab6, 0x36ae50e3, 0x6b20a777, 0x245233bd, 0x99618656, 0x2dd5ba37, 0x7044eb91, + 0x9cfb4b15, 0x60f3f5de, 0x10b3fab7, 0x184da9b9, 0x319662c9, 0x8fe09ac8, 0xd3e6a032, 0xca0b3da1, 0x537121ac, + 0x86700573, 0x6b485f04, 0xcde77b48, 0x4a9c6b59, 0xad0d9429, 0xe350fefe, 0xae0f55bf, 0xf812fb76, 0xead8f64b, + 0x1cd76508, 0x3c283d69, 0xb33584e2, 0xa0f030eb, 0x7c33b18e, 0x932b74f9, 0x404555b7, 0x0c1dbf08, 0x4b66fdd7, + 0x630fedb0, 0x94151871, 0x803314d5, 0x44a1063b, 0xe8ad3d06, 0x295497cb, 0x08842ed8, 0x3dcb4bf6, 0x69b1f9ea, + 0x1dd483f5, 0x4510a296, 0xafa632ee, 0x891a050c, 0xf98314a9, 0xb140348d, 0x7e9860db, 0xc4af6ad6, 0xc801399f, + 0xb9e1bc2c, 0x2f11143e, 0xc46a4fc9, 0xe0cc2f5b, 0x3cd9e51d, 0xdf7b8319, 0xa5258aae, 0x63e851cc, 0x6b5d2024, + 0x01b4ab28, 0xf118ec04, 0x409934de, 0x9a9725f9, 0xfddf711e, 0xfce44121, 0xafc09995, 0xeef28341, 0xcfe71839, + 0x4eb8b166, 0x9e60f457, 0x46aa4f48, 0x9c0751de, 0x475911d2, 0x710e8413, 0xebcc2d41, 0x653f4faa, 0xf94d8358, + 0x2645758a, 0x0b64d8e9, 0x340ab632, 0xa99a110c, 0x6d7b43a3, 0x18aa953a, 0xc0823410, 0x72e23e07, 0x75495249, + 0xeaf2ddab, 0xe4a89e91, 0xbd484d5c, 0xde6dd471, 0x1190d934, 0xc950e578, 0x6e3cec13, 0xf5db11a6, 0xa13b9aea, + 0x7624ab35, 0x2e3a2eca, 0xded7cab2, 0x3e9c560e, 0x2f39d836, 0xfc597fe0, 0xb4d01aec, 0xb22e3c28, 0x1ae327ec, + 0x413af243, 0x68cfda56, 0xc5dd171c, 0xf3bcd89e, 0x9683f79d, 0x4476b406, 0x75b9516d, 0xd6e1fd5d, 0xd9da32c7, + 0x3dd6c0c4, 0xe4142d47, 0x2bbf6e58, 0xb1f85ec3, 0x1df98f14, 0x65148f97, 0x196e9ef3, 0xfb9d9139, 0x8a8ca75b, + 0x74f18b02, 0x0f91b46a, 0x9b3625f3, 0x5ae4f093, 0x1a96289f, 0xa29bd2a1, 0xa7ad79fe, 0xb0074a97, 0x45a19aec, + 0xa963b1ba, 0xebe650f9, 0x1294e9a9, 0xdd675712, 0x052ad740, 0x4f14751b, 0x3b95f563, 0xc2b6d953, 0x9407f89a, + 0xb65b6f0f, 0x64367ba6, 0x72a8e4e8, 0x8dbc07f6, 0xa8944c22, 0x3802146c, 0xc854fdeb, 0xe58a8fd0, 0x9504c94e, + 0x33230c63, 0x044a1ca2, 0x2aa6a304, 0x2c493bf8, 0x4f566392, 0xc7f6c0c5, 0x3a611608, 0x132f4bb2, 0xd202f7a9, + 0x9455a684, 0xb0cab826, 0xca3c8915, 0x0e090ebd, 0x5cf21128, 0xb2ea0000, 0xad29483d, 0x8c205b86, 0xc10bb0ce, + 0xafb563e0, 0xadfdfcf7, 0x00a13069, 0x0081f691, 0x8e84c230, 0x39415adb, 0x2a524837, 0x271840d7, 0xd1a0d035, + 0x1e6334d5, 0x767410f5, 0xb1d50c7a, 0x1a9b91fe, 0x96ec66c9, 0x7f4afd63, 0x0fbcdd6e, 0x635fc40b, 0x25b1a87b, + 0xcb2bc0cd, 0xc172630f, 0xbae8440e, 0x29e9293f, 0x08f96a96, 0xb706db6d, 0x9b5dff16, 0x8deb51a9, 0x5a404f93, + 0xe2b17517, 0xa7ac24e6, 0x8612ad35, 0xaf58e4d4, 0xc44ed014, 0x81f8a271, 0x06996be7, 0x6ea38b84, 0x9b7f707b, + 0xa0854a05, 0x5d0ef0ed, 0x09e64747, 0x326c8ce7, 0xa020fdec, 0xe10cdf50, 0x0b776245, 0x68b0ebfa, 0x9cbdd122, + 0x798f0738, 0xfd28635a, 0x63235b44, 0x5ddb6149, 0x94312f6a, 0x08cec433, 0x2784aadd, 0x78349b4e, 0xf9b4fb60, + 0xcc2524d8, 0x49914894, 0x524e8d4f, 0x58829724, 0xfad2dee9, 0xca1e5dd6, 0x175300e4, 0xb4dfd4c1, 0x774175ad, + 0x7a5f9a70, 0x694efbac, 0x6856c661, 0xdca8b288, 0xb0d2bef1, 0x6f7ccb4c, 0x77ca4155, 0xb9a0dba6, 0xe379cb4d, + 0x054d08a2, 0xc039c975, 0xc96f1e05, 0x3105667b, 0xf754c68e, 0x7047d9b1, 0x4bc95222, 0x5fe94b32, 0x028ca97e, + 0x077b9706, 0xddf299d5, 0xc94ba3d5, 0x7d80321c, 0xf1c7e1c0, 0x7307e4b3, 0xb7d8da39, 0x4b661761, 0x9811b60b, + 0xc9f8652f, 0xed7affc4, 0x9d42d35a, 0x9b8abf22, 0x6c883279, 0x49d8db53, 0x38053dd8, 0x9c730dd9, 0xf42a57fa, + 0x9beb0ce0, 0xcc490411, 0x7a80c95e, 0xf91b8dab, 0x20b023a3, 0xa807ada9, 0x0240d541, 0x123ae9a5, 0x89e4d6fc, + 0x5cb616d1, 0x12dd6b72, 0x335cc2d2, 0x29edea2f, 0x8ac73ce3, 0x17467d2d, 0x26e8554f, 0x5c4bdf24, 0x7fa43581, + 0x723752f1, 0x9895a6fa, 0x4db300d1, 0xdd7fa02f, 0xa52eb6aa, 0x4669a112, 0x0c41d249, 0xd7761fa1, 0xb2efee7f, + 0xd1c2893a, 0x1fe24300, 0x26d2b453, 0x5ba39f6a, 0x07eaefc9, 0xefd0f2b1, 0x67c5013f, 0xf51ea625, 0xba3255fc, + 0x19f1da6b, 0x9f1c5cf4, 0x697059ef, 0xf6eca19f, 0x6dc9fa5c, 0x600b9197, 0xd154dcb3, 0x23041617, 0x8258bbfd, + 0xe24ff10b, 0x393b39f7, 0xa2226064, 0x5d4a97b1, 0x4bab76a3, 0x583c24cf, 0xc15c85f5, 0xa07cf771, 0xfdd52328, + 0xc9578f29, 0x88ff3e81, 0x71ccfc4b, 0x8231f7b4, 0xc2d4c226, 0xc677149d, 0x4b074c4c, 0x7617bb36, 0xc267ebb0, + 0xdb186713, 0x8a047329, 0x349fd525, 0x4a3b9daf, 0xfe788e7b, 0xb19be589, 0x00b5b591, 0x4ce60ae9, 0x55f44fe3, + 0x50b59730, 0x268e1b55, 0xa7ce2003, 0xa48560ab, 0x266e6881, 0xe2c25276, 0xaa90b378, 0xe920ea01, 0xa1950dec, + 0x1aad4e21, 0x7177a5e6, 0x048f665d, 0xe78a1bec, 0x3cd8fc35, 0x8cf59658, 0x930649d9, 0xf63c9499, 0xbf1ace10, + 0xcec1a4c0, 0xb463e04d, 0xfb25c6cb, 0x7c69fee6, 0xa3d19b81, 0x10c3e571, 0xb2f28ec2, 0x038fffc8, 0x70814427, + 0x461262ea, 0x94d9988b, 0x1c36c533, 0xe3488414, 0x4191bba0, 0xa8d43335, 0x2c950ee4, 0x7a442f82, 0x7a707ef3, + 0xb87efe92, 0xe41cdf5f, 0x489c7917, 0xff943963, 0x24d85ffc, 0xdb7b8193, 0x2d77b06b, 0xadeaa601, 0x5d8c70ed, + 0x11c5c57f, 0x087d6e7e, 0x7a0d7f2c, 0xe7ee1f22, 0xee61c1c8, 0xb6704c5f, 0x0a13f16e, 0x94310dc3, 0x269672c6, + 0xef50b53c, 0xe9816a71, 0x26a4270b, 0xab1aba31, 0x44b3fd4b, 0x3cf1971b, 0xc8e12baf, 0x8ac02f9d, 0xc0353ad1, + 0xd9a172c2, 0x4bd33634, 0xbbf87a27, 0x033d87da, 0x13a9c83d, 0x02c26230, 0xa58999f5, 0xf93e81c9, 0xc36c65b1, + 0x386b4e91, 0xbd136d57, 0xc72ab3b0, 0x66aa2d68, 0x7a2805fc, 0xd4f5a3ea, 0xd4472728, 0x769f519a, 0x8aaf34dd, + 0x04cc412f, 0x767a07d9, 0x3f8aaeb0, 0x4e6a98e0, 0x78f5fabe, 0x250ead22, 0x01f85e16, 0x29b4e856, 0xe1fa7d06, + 0xa22b013b, 0xff75263b, 0x11d91a48, 0x1472bd96, 0xa935741c, 0x1836ca84, 0xe1c34720, 0xb3e76b78, 0xa1bfe52c, + 0x30ce9af0, 0x14220d9e, 0x8e4cb6e7, 0x6c8ed755, 0xd5ce5efd, 0x47afbe04, 0xe5a9631c, 0x2de1a575, 0x84537dae, + 0x97c54dc9, 0x9fb87350, 0xcdbce44b, 0x155b09ff, 0x44ef97d8, 0x3bbaa1cb, 0x2c74113b, 0x1c631907, 0xc5fc41bb, + 0xcaa93c89, 0x3c07eed7, 0x2ff2804f, 0x0d41fdbb, 0x7612f855, 0xc5d02ac6, 0x87eb39fb, 0x92f37e01, 0x2f27e971, + 0x244f68ca, 0xfec9ab21, 0xef504068, 0xb69c2aab, 0x60b69d7e, 0xdf7d6312, 0xf970a4d2, 0x1dbc553b, 0x29765167, + 0x1f79bf9b, 0x5893648a, 0x88c29a66, 0x01e7e082, 0x9b67e839, 0xddbfb267, 0x8f80a214, 0x2c90d8fe, 0xd6f4a082, + 0x183935e1, 0xe7c070b4, 0xe082632b, 0xa2376011, 0x353aa102, 0x25517d83, 0x9a6a57d9, 0xa32d20e9, 0xb0599dc3, + 0x36db0dc5, 0xf387473a, 0x3aeeadbd, 0x1b426d1a, 0xea15edd8, 0x7da0511a, 0xfc656666, 0xeae0688e, 0x68ac57d7, + 0x5f1ab182, 0x2bafdb3e, 0x4d80c845, 0x0c92b6f8, 0x3d53d96a, 0x90c15034, 0xb83d6275, 0xa15bfaa1, 0x5813721f, + 0x443e7983, 0x545a3fa9, 0x2bef59ce, 0xa6c5ac93, 0xb90e1cb0, 0x06b217e9, 0xefd35dbc, 0x18ed17d4, 0x4adf3222, + 0x798509eb, 0x78ced4d4, 0xb9a57ae3, 0x146f92af, 0xc6cf6404, 0x97e53463, 0x5c758d87, 0x24469991, 0x2721e399, + 0x78573714, 0x8bf79231, 0x2e093039, 0x39b809aa, 0x324e68f4, 0x610bf13d, 0xaa8b87ab, 0xf5a42b63, 0x027dad81, + 0x059d2e8b, 0xa3e592e9, 0x9ffcb919, 0x1fae59ee, 0x5172b6d5, 0x015a2ca5, 0xd727b270, 0x47964d73, 0x38a3d6e0, + 0x0ccd1d35, 0xae44ad12, 0x090b9e43, 0xf1f37666, 0xbd39e32e, 0xd265273e, 0x547aa12e, 0x9b1fb67e, 0xae7b10c6, + 0xe964def0, 0xba218074, 0x3630960d, 0xf6a891e4, 0x0e030a55, 0x0ebd72bb, 0xd7bb1ea4, 0x4b7803b9, 0x98ea9e15, + 0x5cddd3d8, 0x956bc0cf, 0x4908e4ec, 0x0f338087, 0xb8264cd0, 0xb457479f, 0xcea61b58, 0x48e79423, 0x1b4aab8e, + 0xf1fbb879, 0xf338fd04, 0x20262379, 0xef31ffbc, 0x54f33409, 0x6d15f7ed, 0xbf990b6e, 0xfabaaa77, 0x186c1cf3, + 0x8c91c310, 0xb184c265, 0x74956eb8, 0xd0f5e05f, 0xb7088bc8, 0x00078891, 0x8969a79a, 0x27068259, 0x297f6181, + 0x70577e46, 0x9e34d951, 0x54b60165, 0xe24a64e3, 0xf8f37464, 0xb843d994, 0x071ff01d, 0x5d49e773, 0x53fbefab, + 0x3b58eeaf, 0x0df24287, 0x3f13c400, 0x72b5c381, 0x69521bbe, 0x8e8e031a, 0xb757b75b, 0xa4a40d30, 0xe4a673d5, + 0xc7fa833a, 0xda966abb, 0x71b221c1, 0x18411bf6, 0xedb7a53f, 0x96e2c568, 0xe8fee27e, 0x9938d874, 0x9bf1cf7c, + 0x556df0b2, 0x6fbfce00, 0x34564bac, 0x0348fc6c, 0xde545610, 0xc52f7502, 0xf63ba9d2, 0x5a4128a8, 0x7fa8eae7, + 0xcd99a8a7, 0xf30d39a5, 0x3c5f410e, 0xbce80a14, 0xb939236b, 0xe41fe00e, 0x26bd7e7f, 0xda5b8858, 0x44912c05, + 0x9ac4e5b2, 0x6dfe0649, 0x4045792a, 0xc4c99ce3, 0x5fe8b1db, 0x148366db, 0x6313caee, 0xbb62aa85, 0x7ea4c6cc, + 0xed51571b, 0x4469ffbc, 0xef01e316, 0x0420c5df, 0xe0c83fba, 0xedf88321, 0xf7f57064, 0xf5a6ea8b, 0x6032044c, + 0x069927d4, 0xb03b4efc, 0xdfa9daf3, 0xde5b0b5f, 0x98d7dd2c, 0x47ce09d4, 0x3c3e85ed, 0x39af128e, 0x527913bf, + 0x82a77b01, 0xcfde42a4, 0xaf151efd, 0xedbe6d02, 0xfd1af95d, 0x0ed3dc96, 0x2bd228d4, 0x48d89856, 0x4be61d17, + 0x4a1e61e6, 0xf9569767, 0x786c6695, 0xea535d99, 0x9b4e73cd, 0xe6b87295, 0xab08b3cb, 0xfd3c9b65, 0x1847f377, + 0xf5813e87, 0xb64d56ff, 0xc4e742ad, 0xf0efbd5c, 0x28fd6417, 0x6e543767, 0x71a43397, 0xb3987ad2, 0xd30d76d0, + 0x8ddc206f, 0x66893973, 0xc179deaf, 0xd71abbf8, 0x54f1d7f2, 0x879968d5, 0xde55a950, 0x80dffef4, 0xa13943ee, + 0x2ccd6c7a, 0x32c9cfbe, 0x790bd750, 0xa4f59fbd, 0x2db7aabf, 0xb803f83d, 0x2ce297e2, 0x48190124, 0xada47fdf, + 0x9344aa0b, 0x6cf59dd4, 0xb5dca967, 0xa5be7481, 0x4beb4f01, 0xccd4c6ba, 0x31a2697b, 0x07123cf0, 0x277c0f64, + 0x08687e61, 0x71a431c6, 0xb0765cc8, 0xcfb7cc8a, 0x235278b8, 0xecaab3fc, 0x3a6a96b2, 0xd5ee6f21, 0x4d9e8585, + 0x164dd6c9, 0xfc5e27cb, 0x828ee442, 0x0409d50b, 0xb877cb19, 0x374e39ea, 0x8ca8565f, 0x7cea3fd9, 0x178ba593, + 0x2d31d820, 0x4118b914, 0xc218dc21, 0xcef8d0be, 0xd05fd8bc, 0x45aaec72, 0x7be792fc, 0x11fac0dc, 0xb83aadf9, + 0x43293306, 0x5d93e966, 0x423ee537, 0xfe5d203e, 0xd96305af, 0x5330f299, 0xfc9c501f, 0x45de9115, 0x3dfd1e47, + 0xb74d6cff, 0xa95d71c6, 0x3e99b10a, 0x6fd1d94c, 0x0626e5b8, 0x8f6aae77, 0xc03494f3, 0x0ba6558b, 0xbb605d59, + 0x51f972d4, 0x5fa46215, 0x2b6a0a2c, 0xd132fdda, 0x1d2587b3, 0xd3dddbc7, 0xd163f05b, 0x597caf86, 0x1c6da68c, + 0xe4aa6126, 0x8cd2a5a1, 0x18384612, 0xa3dd8fef, 0x7f30557f, 0x235fc5b2, 0x705967e5, 0x493edede, 0xd550f9f5, + 0x00047350, 0x60eda8f7, 0x898c348c, 0xb2bf9cfb, 0x56d6654d, 0x1c0cfb6e, 0x6d1cee5c, 0xd6dea805, 0x3a1ae3a5, + 0x685b46d8, 0x36b88463, 0x7cdc7adc, 0x4b7c5d28, 0xf95b6d14, 0x7d7d5c49, 0x0884c5a2, 0xb133eeff, 0x317ac6ae, + 0xdb27a303, 0x70661a56, 0x9702380b, 0xe2397683, 0x62912a1c, 0xbe2cdb33, 0x4bab6ce5, 0x4e17e467, 0xea379ff3, + 0x8412c4db, 0x216a936a, 0x527286db, 0x32cd694b, 0x5b2d6451, 0x79c6276f, 0xc47dc592, 0x03646a5f, 0x4a5946b0, + 0xac12c0c5, 0xd0458bc0, 0xb341bd9d, 0x937efefa, 0x0846cea4, 0xf30c8c9f, 0x61c64d6a, 0x8d21a682, 0xbf9b8ec8, + 0xa61ae3e1, 0x1ba79c39, 0x767f7716, 0xce09e72f, 0x9ddb23e1, 0xc7185c88, 0xfa4c52a8, 0xc019e935, 0xe06e3571, + 0x9589254e, 0xf5daf63e, 0x9846c274, 0xef6d73fa, 0x852d3508, 0xf1085391, 0x9cd34c00, 0x3100789f, 0xfd3a07d3, + 0xf238cef5, 0x7d9d32f9, 0x199d306e, 0x73330bad, 0xac8d10ed, 0xf89eea4b, 0x8a89fb16, 0xf60ba8d6, 0x69a3112c, + 0x854b46e8, 0xbba9d5a2, 0xfdf4e7ec, 0x0dec40f6, 0x10b1cdfc, 0x2e2116eb, 0x06979fb7, 0x6eb121de, 0xbb5d6f70, + 0x14dac746, 0x924a87c6, 0x03113267, 0xe86a3989, 0xa91cf08f, 0xb92c9b15, 0xb46507a3, 0x14b41a77, 0xd6843685, + 0xc9e4a54c, 0xcd05a677, 0x0f527428, 0xf97ef9a8, 0x87055796, 0xc4cfc208, 0x790b1a41, 0x0c44da7a, 0xc57c264a, + 0xea25a923, 0x29dafffd, 0x71230ad7, 0x6b713d6f, 0xe2f8651f, 0x5482c23c, 0xa1aba175, 0x4aad66c7, 0x16db6575, + 0x21335125, 0xa9e5cec5, 0xad9435c3, 0x54b2d379, 0xd8e31642, 0xb9fd41f0, 0x387dcf1d, 0x175da749, 0x9611fc2a, + 0xbc5c0859, 0x4b0fe475, 0x90dfe29c, 0x62cb8daf, 0x74ebda01, 0x28d544ef, 0x0e24c82b, 0xf3f5e8b9, 0xcfe7edc1, + 0xfd4db37e, 0x04311091, 0xc9eea1ae, 0xecdfc043, 0x6cf3c473, 0xec17079b, 0x00dd38c5, 0xd32056b3, 0xca390b14, + 0x11caf1e9, 0x30d027bf, 0x46ee4bdf, 0xee3cbb7e, 0xd6fb83cb, 0x882667d7, 0x9fb75b6c, 0xf60736ac, 0x92ffb1f5, + 0x941ea54f, 0xbc3b5847, 0x5239d4b0, 0x193fd05d, 0xdc70d079, 0x9394b965, 0xb0f71470, 0xff24639f, 0xcf09fde8, + 0x2703817d, 0x1988fd73, 0xd3811142, 0x5f6ef91f, 0xadadaeb7, 0x0ce9e655, 0xf9ad22b9, 0x05d258c7, 0xf428c16f, + 0x68c3bba3, 0x68304c8e, 0x92c5febf, 0x5e9fa69b, 0x4732086f, 0x9ed2c3d6, 0xd5536471, 0xcb91d81b, 0xb8e40e48, + 0x6829068f, 0xeefc11f9, 0x578d90cc, 0xe9e16c64, 0xc2f30800, 0x85e27e56, 0x3476f551, 0x6a858aad, 0x25e2bd5d, + 0xb2b7df04, 0x33865c03, 0x182d0a2c, 0x5787a074, 0x56f395a5, 0xe04c53c5, 0x2be82e24, 0x7d315f73, 0x9aaf3a80, + 0xe2778fdd, 0xf6895fa8, 0x9d40fa61, 0x4ac62b99, 0x1c1e159d, 0x634887e5, 0x51d0b754, 0x0148a880, 0xd44e1087, + 0x7272e49b, 0xb136f745, 0xb38e698b, 0x553074bf, 0x889a4b78, 0xb9867280, 0xdb9f326d, 0x86aa6a46, 0xcee0431b, + 0xeec864ee, 0x53dc5543, 0x50b57623, 0xc549ff55, 0x61c9aa21, 0xe160e423, 0x22b9aaff, 0x6dda8a55, 0x54621c9f, + 0x0d2350c4, 0xb8b8302c, 0x334936f3, 0xadec82b6, 0x915909e9, 0x6191df35, 0xd4942f4a, 0x478d2245, 0xa541e3a1, + 0x672b54c3, 0x9f018e66, 0x2a683a04, 0x6a0d80a9, 0x5888feed, 0x62616bf1, 0x6d98fe1d, 0x4fcaad93, 0x0056ea79, + 0x748b270a, 0x454f0925, 0xe44c6fdc, 0x198ecbea, 0x8f715f81, 0x12c52006, 0x6e616abc, 0x8012cf70, 0xebbad99e, + 0x23439da6, 0x9e2b57d2, 0x7f5261d5, 0x50dcb0b8, 0x84ea069a, 0xacbb40dd, 0xcb5b3c7e, 0xfcf5ea8f, 0xa4874839, + 0x253665ea, 0xa7ff00d7, 0x993ab984, 0x3cd83cfc, 0x8a741bda, 0x9c1222f0, 0xc046bcf1, 0x3d5e16d6, 0xa28b8c52, + 0x8b33a6a7, 0x912455b8, 0x179f3705, 0x7cc659ed, 0x7c7c29da, 0x9741a1bb, 0x80f65b96, 0x4a2cdd9d, 0x579e86a9, + 0x840ce2e4, 0xfa5e7d01, 0x35475240, 0x3da54639, 0x9ea498d8, 0xb3884360, 0x790d8d63, 0xa4aa629e, 0x459c32eb, + 0xb755eb7f, 0x76895fcc, 0x1ada1d75, 0x0c281fb0, 0x66544aef, 0x69166910, 0x0a4cefd0, 0x8403b204, 0x2b80a86f, + 0xfae3e9a0, 0x46ae9817, 0xd5a91cc9, 0xb4f992bc, 0x468cc4b3, 0xa968ccdb, 0x2797c8bd, 0xa25aa978, 0x8bb185f7, + 0x6eb9730b, 0xb60bc93a, 0x3dc9ef31, 0x93e49e3d, 0x2d1a10b4, 0xc3a3f1e1, 0x27b1b376, 0x653ba138, 0xc4487757, + 0x1971cfcf, 0xefd13767, 0x2e9fdd81, 0x171485a6, 0x7ee05844, 0x210309cb, 0x42d72633, 0xbb0136b4, 0x1bb08815, + 0xd32ee52a, 0x55b72eef, 0x4685510d, 0x9eedcd41, 0xefe69359, 0xc86ea3ed, 0xa845d71e, 0x10bab1b3, 0x356818f3, + 0x524da4db, 0xce784afc, 0x9a458226, 0x7f4f9fc4, 0x7f3f0183, 0xcbab3805, 0x3a5d25da, 0x5b35a6de, 0xcca03c76, + 0x6bbda4e1, 0xdfccc551, 0xe9382f39, 0x77f2fbed, 0x0cdd4de6, 0xefb20d8f, 0x9b759f1a, 0x8e707219, 0x9c825558, + 0xbb813ac4, 0xdeae04aa, 0xae403f6e, 0x047144a3, 0x6de0e5b8, 0xcbd0d1d4, 0x3ad42111, 0x4dd33b25, 0x86ed77a0, + 0x0a592ef7, 0xc8b44f55, 0x61d182c9, 0x5b3bc0e3, 0x8e9627fe, 0x8487772b, 0xea7bf55a, 0xc7170c9a, 0x282dcd27, + 0x5a95cdc5, 0x5060f106, 0x74a0f688, 0x6543db20, 0x79f5b677, 0x32c63235, 0x62acfcfe, 0x4c65f58d, 0x0b3f10c4, + 0x25c631d0, 0x9ce4ab72, 0x07005b89, 0x405756e8, 0x16e9411b, 0x33fc8a3d, 0x0e19e5ed, 0xf58209f7, 0xa0683973, + 0x0dc0760a, 0x506d8089, 0x89a54ae9, 0x73313c1c, 0xe667c101, 0xffdd78d9, 0x13e3d8de, 0x80e85e87, 0xbbc16377, + 0x64b4e947, 0x46043dc6, 0xd6ba03a7, 0xc6e9ce0f, 0xad93db29, 0xcce5852e, 0x00335e26, 0x05abc57d, 0x84fe0a7a, + 0x23ebd346, 0x986f33cc, 0x7efbcfab, 0x57b52a96, 0x9073f503, 0xa13703ea, 0x826c0371, 0x1e5af877, 0x732a1fe0, + 0x3e9b113c, 0xababd3a2, 0x54280723, 0x60d5c381, 0xa8dc52c4, 0x4ee40621, 0xadce92e4, 0x1e4b152b, 0xfde29102, + 0x37aa48ff, 0xe18d14b9, 0xe91822aa, 0x8c4c6a90, 0x488049cb, 0x2d773f95, 0xb5228d4c, 0xadb8fb7c, 0x82fb3826, + 0x014d030d, 0x4baba8f7, 0x27134297, 0xb25f3adc, 0x7ef97a0f, 0x1db5aeba, 0x3f9a0815, 0xb0de6477, 0x36b6f886, + 0x7246c8bd, 0x19d37964, 0x4e389278, 0x9288ba1f, 0x5e50cfe2, 0x87955167, 0x53e42131, 0x3a1e0f5c, 0x50f179d3, + 0xa0d04db7, 0xb904d114, 0x621113e3, 0x975f9d32, 0x7828d621, 0x9ff17e6b, 0x8277c830, 0x3705e11b, 0xab796624, + 0xeff9daf8, 0x168294ae, 0xa6c34680, 0x07f7f9c9, 0xacf87f5f, 0x7a7a3e66, 0x6f7be7ae, 0xc2ed828a, 0x3016d642, + 0x2014c3f3, 0x344929be, 0x62b1af61, 0x4fa24e03, 0xb4124ce6, 0x639a9829, 0x3068d40a, 0xb0b6e092, 0x2a4306c5, + 0xd98ffad2, 0x058a771d, 0x31b549df, 0x478bcfe0, 0x737d6cfd, 0xf807b77e, 0xb64e8042, 0xe7174ba2, 0xce347660, + 0xf17dacca, 0xdc474a92, 0xbbc86642, 0xab10f5be, 0xe4007804, 0x7bdd659e, 0x962e60ff, 0x32e3605c, 0xd92e57c8, + 0x40c89aff, 0x1d3455ab, 0x64bff5c0, 0x5c8e591b, 0x8dd85927, 0xfa6553ef, 0xad52435b, 0x731ce398, 0x50357bd5, + 0x05218309, 0x47e06c2e, 0x91c93eab, 0xa8786347, 0x3ba0ffdc, 0xc8ff386f, 0xef56a5d1, 0x9db81bc0, 0x72574a31, + 0x5d3b7e2c, 0xb0778b53, 0xe2745e2b, 0x523bb181, 0x93e343f9, 0x2cadb938, 0x1ec2e849, 0x9ba90676, 0x3c2a4e8a, + 0x323783ff, 0x6840c356, 0x3bb316bc, 0xa977aa8e, 0x801d8dca, 0x43c33350, 0x7a36b565, 0xd26fc964, 0x4f7a5ead, + 0x9e611163, 0xa77adf3c, 0x27a9cbb8, 0x93aa349f, 0x15c112b7, 0x84b18c72, 0x17e06b22, 0x3369cdd3, 0xfa5b783d, + 0x813eeebb, 0x74057940, 0x6061c82e, 0xbedb61b0, 0x13ee521d, 0xe3e18f46, 0x624685e8, 0xa573217d, 0x5a145657, + 0x96129557, 0x5e82b3ef, 0x39457d7b, 0x5a620bad, 0xa6181130, 0xc82e6338, 0xa245fd7c, 0x47b50a1b, 0x636aaa88, + 0x58b473f7, 0xc417ebbe, 0x30ef8bf1, 0x44900e7a, 0xc7036e75, 0x92a90db2, 0xa1ad8ab0, 0xb0811407, 0xc37a21e2, + 0x3cf216f6, 0x24dac32b, 0x264da0ca, 0xc2b7db0f, 0x4eea9f20, 0xea9f5577, 0x6f506eb5, 0x78f6271e, 0x8c9f0626, + 0xdfe7b74f, 0xd4aa3c67, 0x6ee5c48c, 0xa59f7919, 0x43b62284, 0x5cf9bc84, 0x637a21fb, 0x7ece4d16, 0xb2111b34, + 0xadecd27d, 0x3a118b2f, 0x334f731a, 0xcd15ad1a, 0xceb32e95, 0x736431bc, 0x101f00d1, 0x99281993, 0x6db7847a, + 0x001918f4, 0x99db18ab, 0x55fb8584, 0x1d98167c, 0x49c7645c, 0xb118e260, 0xd562eb11, 0xe8bcd250, 0xf75e56f7, + 0x9dc94ec1, 0x93c32394, 0xc057d41b, 0x6ee6de5e, 0x071680b2, 0x41c21e5b, 0x9009f6f4, 0xa48fbe6e, 0x5e12eddf, + 0xfba01c61, 0x12c41121, 0xa11c9c86, 0x7e6ce5cf, 0x528b4f3c, 0xd4bf4c54, 0x8968a0df, 0x49bc637c, 0x176d0a53, + 0x90f82fbb, 0x26a654c6, 0xa004d3a1, 0x17908792, 0xc7d56976, 0x14df05e9, 0x9c3974af, 0x3df8b15a, 0x84401cd3, + 0x15c38bf3, 0xc1b100e1, 0x27eac0ba, 0x79727d23, 0x03a85748, 0xa9dd8be4, 0x253768d2, 0x7ea73633, 0x2115b732, + 0x06fcb210, 0xa7c67140, 0xd634004c, 0x3579a5b5, 0xff62a308, 0xf6f75e3e, 0x04aa27f4, 0x20a93d90, 0xc572f46a, + 0x0ce45d07, 0xd39bd305, 0xfd9431fd, 0xa796fe2d, 0x4d14bec5, 0x3b9913be, 0xd941a640, 0x0e60adc9, 0x7289d239, + 0x4ecafa17, 0xcb4e4685, 0x5404ee7d, 0x48934c33, 0xf12e0d30, 0x4f02ee0c, 0xcd549cc0, 0x376b113f, 0x92cfc00d, + 0x7443b688, 0x010d393e, 0x05cd5445, 0x4cf10eb4, 0xab784b1f, 0x92a773a5, 0xaa7fb427, 0x95238016, 0xaf073793, + 0x7f68b530, 0x3fabfd3c, 0x0b452d7a, 0x6a2d1da6, 0xe9d8a40b, 0x19417553, 0xf0e3ce7a, 0x15c02cf2, 0xfb25c1bf, + 0x09d0cb02, 0xdfcac66f, 0xea1d4b1a, 0x82df9873, 0xee93fe60, 0x9f029a9b, 0xa7ca8145, 0x1c1b7cce, 0x62200121, + 0xf299562c, 0x3f112e6a, 0x0bbecd5b, 0x503a7932, 0x5abcc742, 0x2ef4ad89, 0x4209c791, 0x4cc557ae, 0x7d9c887f, + 0x49d5be48, 0x5ca13837, 0xecd10bb5, 0x0c981dcf, 0xa775ebba, 0x24c54874, 0xe362e829, 0xcaafb84b, 0x721358fe, + 0xb11b72ff, 0xd480f960, 0x0ae2a785, 0x139de0f7, 0xa6ff8162, 0x42582540, 0xefea8084, 0xaeb83774, 0x130a8a6a, + 0x6ddc6405, 0x3e604c94, 0xd73f7111, 0xd309b5ae, 0x80918eb9, 0xc9f14a46, 0x07688f53, 0xae85d3b6, 0x0778ed83, + 0xbf5c1f3d, 0x97d5b559, 0xa71e3541, 0x3246b075, 0x48927996, 0xd9b86d6c, 0xa413c81d, 0xdbc47107, 0x6fd0709e, + 0xe2701f45, 0xc6aa9aaf, 0xb7e9056b, 0x2c36a1b5, 0xdb43b1da, 0xace3395c, 0xb12c7b85, 0xf2102945, 0x6750243b, + 0xf6ec565d, 0xabb7058a, 0xc2482ef0, 0x5f8ef9b0, 0x504d970b, 0x37418cd6, 0x394333e1, 0x3c235d07, 0x90bcb4fa, + 0xf8d62ce8, 0x6ca4401b, 0xf79b193c, 0x94b9720d, 0xff59766d, 0xbab11dba, 0xfad51067, 0xb4dfc4a8, 0x3971e161, + 0x944f0905, 0x4a1b10d2, 0xdde26e2b, 0x1e159399, 0xd7e6717b, 0xbb6c6b92, 0xfd6095fc, 0xff46d90d, 0xb9d6fee2, + 0x13abb0ca, 0xec0269d6, 0x136b6500, 0xf3750f41, 0x3944f66e, 0xf2c41534, 0x54f47c7e, 0xbc558126, 0xa093c0aa, + 0xba437e55, 0xa32b43d4, 0x1dbd0032, 0xef708859, 0x2bb65fc4, 0x6315623e, 0x196f3cc4, 0x5e4e07f1, 0x18e9380b, + 0x6118cf04, 0x81b8fee3, 0xcb1674b9, 0xb33849e6, 0x676f041a, 0xc1993807, 0x5acbbf02, 0xf9797ba2, 0xca6fce93, + 0x6091734c, 0x7ec3bcf7, 0xe24e77c1, 0x7f4c97d4, 0x9397878f, 0xcd616229, 0x68cf030b, 0x60565826, 0xe05671cb, + 0xe9caac2e, 0x7e1e0c5d, 0xc32f1de1, 0x01dd665e, 0x36160645, 0x785074af, 0x4b540a42, 0x1914bf9c, 0x88a7680e, + 0x4b90d3d2, 0xa3252dda, 0xe82ba8b5, 0xc4c5fd12, 0x20ade882, 0x75fe14d1, 0xa2891ec6, 0xc79d24fb, 0xbaa4383c, + 0xd2ec5133, 0x03d95f57, 0xc10a9e9e, 0x62c4d38b, 0x2f77bc6d, 0x4200aa86, 0xa3c48fed, 0xb16abe7d, 0xb6c05f94, + 0x95400204, 0x3018328c, 0x2eb159fa, 0xd8c1fdde, 0x639efd9a, 0xfeb7bc60, 0x16f33222, 0x7fbe769e, 0x3adaacfa, + 0x2dd03b8c, 0x48e98daf, 0xf844b0d2, 0xf30be6ba, 0xfba2d03f, 0x2009e6b9, 0x6872a5e9, 0x6592d677, 0x8c701033, + 0x518cf301, 0x5e9d3b0b, 0x06a5d9bd, 0xa78799c9, 0x965e784f, 0xc32b1d64, 0xbb1b50ad, 0x176c5632, 0x0e852e22, + 0x755e424f, 0x3ce63ad7, 0x830ee494, 0x2be2045e, 0x5208efb5, 0x9ba880c2, 0x95348566, 0x7dbf95a4, 0xd3df2ef9, + 0xae73d011, 0xd60f2a04, 0x9cef8bf7, 0x825af9f3, 0x8e1fe0d4, 0x97068494, 0x6a307a7b, 0x3c2e303c, 0xd86c9268, + 0x642f0f54, 0x1e66bbf3, 0xbd6d75d9, 0x5f2aa2b9, 0x0f8e9e2b, 0x75c565ee, 0x87b7c137, 0x55bd9da1, 0xcba285e2, + 0xc6d56e47, 0x2e12cef2, 0x15bbc8b3, 0xd31430d0, 0xd6d8f5ab, 0x841ad12c, 0x7ca10f0b, 0x3ebee6b8, 0xb97ea535, + 0xcfff2762, 0xbcc0e7d6, 0xe5121419, 0xb33d403c, 0x98803a7f, 0x469d5e1c, 0x57abcf2f, 0x76d4bd2d, 0xfc04bc85, + 0x5caf62be, 0x0d081862, 0xd6c6c65a, 0xd691f4c3, 0xc3bd1080, 0x85d97661, 0x611a9030, 0x6cb1c0f3, 0xa3b69f79, + 0x9eb1e91d, 0x1dc2fd28, 0xf00f91eb, 0x0c7b745f, 0x7f55ca76, 0xff14efa6, 0x7bd8081f, 0x9e50630c, 0xf8d3f2b5, + 0x95ab6aac, 0x07ffbac8, 0xe3ea3e12, 0xeb30d64f, 0x85eff3ad, 0x96ea2c73, 0x3204b6d2, 0xe876f34d, 0x87ab832f, + 0x07d53738, 0xea6a3cde, 0xc6bea7b4, 0x9ee7c3e4, 0x63c11d5f, 0xbc14fc50, 0x23a8dbc5, 0x0bdce961, 0x732dffeb, + 0x303d91ec, 0xfa2a2c3b, 0xeef8a5c2, 0xca460483, 0xfc481ff5, 0x1cf06081, 0x803e007a, 0xcdd870bf, 0x2b5c0249, + 0x7e46a4c2, 0x56cb499a, 0x511ebd73, 0x613f6792, 0x8dc79df2, 0xe7212180, 0x1068a55f, 0x016dd5a4, 0x91e237ea, + 0x9bddf026, 0x09bc9344, 0xcb870f03, 0x54bdda3b, 0x88bc0684, 0x4896e3b9, 0x80d91ca2, 0x8a6a7b44, 0x2e49bacc, + 0x893af543, 0x214b3eb9, 0x31d23890, 0xd706a86b, 0xb38fe8ec, 0xde75015b, 0x61c79681, 0x05bc628c, 0xc5a790b6, + 0xddaa8ad6, 0x777213d1, 0x86ddf4a9, 0x7a5d831c, 0x89fd5ecb, 0x38ca762c, 0x78158232, 0xff923e60, 0xeb4126ff, + 0x804a8005, 0x506c0eb5, 0x444dd314, 0xa0eb2c0c, 0x8292fd6a, 0xe8093be7, 0x83b38260, 0xca01a5db, 0x9340c6d4, + 0x649a7c56, 0xb46cd7db, 0x13a9174f, 0x466e0ef0, 0xea55a299, 0xaf616bd6, 0xddac7e2b, 0xc728ddc6, 0x39cdbde3, + 0xeafe437f, 0x56551127, 0xd6fda22e, 0x09d363a0, 0x0729da9b, 0x023d21e6, 0x8f8fa320, 0x1a841cc2, 0x96530f0d, + 0x9edb8ebf, 0x01dbe57a, 0xb922ea5c, 0x3fc23968, 0x7b1aaa61, 0x068cb8cd, 0xf5a2d679, 0x2f4238ec, 0xc1219c75, + 0x95ad0c93, 0x07304546, 0xe36331ea, 0x040ef95d, 0x77d9a7b1, 0xbbac9018, 0xbd9bfa44, 0xbde29ac9, 0xfb0f265a, + 0x066fa55f, 0xb0c8116e, 0xba6d5c9d, 0x940cc555, 0x5926ce33, 0x9a2f6116, 0x16b538b9, 0xd24fc2a5, 0x6e1c7124, + 0x91822c4f, 0xe827a3f9, 0xf10e51ec, 0x668d9d97, 0xcaf92953, 0xb2430591, 0x8b3c7a36, 0x49238f10, 0xc7926bee, + 0x936be0f7, 0x46ae60b8, 0x6b88bb05, 0x20d66f42, 0x92918882, 0xa5a33ed1, 0xa54604af, 0x61aeeb6b, 0x936fe9ea, + 0x454efa70, 0xb3466f38, 0x8e44278f, 0xad6f6f18, 0x833234c1, 0x2408cd2a, 0x1c1fa229, 0x6bb80421, 0x9b1a86ad, + 0x00c4c2e1, 0x8dcb65d7, 0x92e85678, 0xf82ae17d, 0x32b37912, 0xa452d405, 0xa800dfde, 0xbd14c448, 0x048a3c9e, + 0x53671c78, 0xb335ab8e, 0x3ac53c83, 0xacad666f, 0x1948d29d, 0xc85658ef, 0x0c6a9306, 0x51ac12d4, 0xdf1ff5a2, + 0xd82fc781, 0x0a1c19cc, 0x2beb9fe1, 0xfa30c593, 0xec70a4ec, 0x95a5c33b, 0x2f5fbfc6, 0xb03fd4e3, 0xddca67a8, + 0x7049bacc, 0x37e2a2b7, 0x8e99b028, 0xea00f491, 0x7c2004bc, 0x230fecd3, 0x4be56373, 0x8b78a662, 0x76978b7c, + 0xa48ec66c, 0x6430ccba, 0xbad86325, 0x841b1b5c, 0xf2e9bbae, 0x6830cf5c, 0x0bd5030d, 0x1e7972e4, 0x83d71ab5, + 0x9a2172b6, 0x4c68163a, 0xb7985500, 0xbe8a2c1d, 0x0a372f92, 0x6fe4c94c, 0x55e621ba, 0x7e86077c, 0xa4d7d236, + 0x180f8729, 0xe6072802, 0xbd0c2233, 0x40b19ecf, 0xc3766769, 0x834c59ce, 0xe34c216a, 0x0fee2d82, 0xf536f70e, + 0xbaf8b2ad, 0x3e7280fc, 0x869a2cd4, 0x770b9c9e, 0xa5a589dd, 0x657e3302, 0xe53057e2, 0x4a887910, 0x237afaba, + 0x60c25bb9, 0xfed3953a, 0x26dfa29e, 0xda1f9d35, 0x248ee591, 0x5797756e, 0x37ea559f, 0xa2409a5f, 0x8d1d70a4, + 0xc2f292f4, 0xa2348dee, 0xd66920b2, 0x6759b9a6, 0x1955795d, 0x6ae839d7, 0x91953120, 0x1c931557, 0xb33de81f, + 0x4669f106, 0xf9680def, 0x91429c2c, 0x4af1846f, 0x93aba167, 0x3e88d416, 0xf7799a70, 0xb1c7861d, 0x99386fa3, + 0x69ad6e08, 0xccac9627, 0x0358eac0, 0x4aeb33d2, 0x695c0514, 0x85e6ba1a, 0xe45409e4, 0xe995d02d, 0x73d125a8, + 0x3430c538, 0x6a34c89b, 0x39001a64, 0xde66d6c8, 0xe2a2670c, 0xae29918c, 0x40824d25, 0x2212210d, 0x003247ce, + 0xd595e6e7, 0x9d740f97, 0x3f466b20, 0x649244a7, 0x23245da9, 0xc82695e3, 0x946a03b5, 0x3b45fd31, 0x270f06db, + 0xb869abb2, 0xf711dd96, 0x5c019068, 0xccde463c, 0xf070ea01, 0x85b81dbf, 0x34df6e28, 0x1b0cc5aa, 0x5ad15e1e, + 0x2582f60e, 0xb39c3a7f, 0xd136e7a6, 0xe72bf665, 0x6e2f8d73, 0xecc1f1eb, 0x6375c437, 0x9f74af01, 0x360d8297, + 0x71a08bfb, 0x623a48be, 0xbbbb6ba7, 0x9cef2760, 0xf106be7a, 0xb7063d35, 0x4f78d100, 0x7ba1586c, 0xfdd10ea7, + 0xfef65604, 0x7224ade4, 0x29e6c940, 0x73570e4e, 0xd70e1f4c, 0x3a82ea97, 0x61f365b0, 0x1d0b97b4, 0x5abc3437, + 0x328d3ecf, 0x3f0c934a, 0x3e090fe9, 0x57cf4e12, 0xa6eaeeca, 0x23a36842, 0xcc58e443, 0x6d70a698, 0x56032367, + 0x38dda07e, 0x928407ab, 0xd1ed3eff, 0xe14642f3, 0x21ba0cbc, 0xebf6cb2b, 0xb89331dd, 0x1b042743, 0xdcc7e1f4, + 0x3d88d419, 0xd7b5af7e, 0x54282e85, 0x629fb57c, 0xc3748d6b, 0x6f64eb3b, 0x4da947da, 0xa0612798, 0xcbd0b50d, + 0xe88bb643, 0xf9903a70, 0x862160e3, 0x6ee908ac, 0x38786c2d, 0x920e4f2f, 0x0811571b, 0x51ce8fd1, 0x88b6da34, + 0x57e9442f, 0xc3a5f4a6, 0x80c4a442, 0x07fa8039, 0x7c75e266, 0x330a942f, 0x27003d0e, 0x655a7a25, 0x2e062093, + 0xb98be3d5, 0xc8f3054f, 0x2befe431, 0xeab94c93, 0x298f4923, 0x8e32460e, 0xc76b4d5a, 0x7ca77d35, 0x92db6bbc, + 0x6b8e6627, 0x8c19f546, 0xc3738310, 0x9fd9657a, 0xc859dc33, 0xcef58219, 0x72ea262b, 0xf5cc02bb, 0x6f4f91de, + 0x425610c0, 0x6cf389d5, 0xbbc300ab, 0x99499131, 0x36f6c577, 0x8f686b1e, 0x59219335, 0xb990686f, 0x56189909, + 0x519a311c, 0x4da10c16, 0x097440f8, 0x427e42bb, 0x1f870ca0, 0x589b5b09, 0x689378cd, 0x19dd1558, 0xe1e42fc8, + 0x94c2e845, 0x7b74a267, 0x8658e3a2, 0x22564f87, 0x26ce5598, 0x0a6c4f6c, 0x250818b0, 0xd6c9f7ae, 0x4a361653, + 0xe98fdbc7, 0x1f4e8e9e, 0x789a3594, 0x329abe16, 0xcdc0986d, 0x651a165c, 0x83961499, 0x7911d8a6, 0x5320793b, + 0x16431f7e, 0x6fc8e822, 0x67f5db56, 0xe56bab75, 0x08646ff9, 0x7deecb69, 0x6ebd872b, 0xa629d3cd, 0x07aab3b6, + 0x19c6e2c7, 0x97b6d5ef, 0xb513e4cb, 0x56b1e81e, 0x327d6380, 0x9a4f10ad, 0x5fddcc74, 0xd011c699, 0x31126f8d, + 0x026d386f, 0xec11029d, 0xc64f98a4, 0xfdc045be, 0xb7e86e55, 0xf89a3867, 0x6904bae2, 0xc6b792c3, 0x6adf733d, + 0xf712c183, 0xac133324, 0xd15def31, 0x10066fa1, 0x6c5d642b, 0x7f8a867e, 0xa9a7653c, 0x02296171, 0x24ab80da, + 0x3a7e56ac, 0x00619549, 0x8e5dd0a4, 0xe0439d58, 0x9c29e073, 0x272a707b, 0x5e02e17c, 0xebe2aa5f, 0xfc0ce650, + 0x243c8b48, 0xf4993af4, 0x83c0bf13, 0xb6fcf326, 0x56615cdc, 0x8bdf04ba, 0x3a016a4a, 0x1773dd3a, 0xe3165ced, + 0x76359caa, 0x9f06e765, 0xb0069e33, 0x5f7cc78d, 0xe77257af, 0x80a20c65, 0xc3ca5e7c, 0xa4845aa4, 0x2c1381bc, + 0x046c2db6, 0x3006a90f, 0xf9a73c1c, 0xaca96b13, 0xadc05fe6, 0x522180a8, 0x3620e795, 0x877570da, 0xd3a8b806, + 0x55e80f7d, 0xd8ed6a06, 0x6730e36d, 0x6473d1c3, 0x8470219b, 0x5c62a218, 0x9cf4257c, 0xf0529fdf, 0x68b5d7d4, + 0x9693641e, 0x43a608eb, 0x5bb552a3, 0x2306b876, 0x68676028, 0xbac2d5e9, 0xb6207e7c, 0xb6306f2b, 0xc36a8db5, + 0x300cfbb8, 0xd960acc1, 0x5bdca09b, 0x8b117dbb, 0xe97b2822, 0x9ece6766, 0xcb77574f, 0x8cb59092, 0x1258041e, + 0xdd2b42d7, 0xe7f679bc, 0x9bf493d7, 0xbb558f26, 0x89645fd7, 0xd4eb8bca, 0x59c2b894, 0x109de0fb, 0x74e489dc, + 0x85fd453a, 0xd7ab69e5, 0x416e0815, 0x3075e2ae, 0x11b6609f, 0xe7dedcc6, 0x14da6468, 0xa39f0544, 0xd475d0d7, + 0xc014d0d1, 0x8cef3c2d, 0x99ffad1c, 0xf3481e1f, 0x169e7b31, 0x6455fba8, 0xbd2562d5, 0x5055c3a6, 0xade08541, + 0x8bcd9de8, 0x2cc0736d, 0xd3f9c494, 0x4288a4eb, 0x41bb2f38, 0x763ccfd1, 0xf893bfd1, 0x8976e1b1, 0xca37107e, + 0x0f1938e3, 0xf3723960, 0xdf36bac6, 0x5e35f320, 0x9cdccdb4, 0x27185b20, 0x55ee7d8e, 0xb714ced9, 0xf54a1648, + 0x16d82052, 0x562a69c5, 0xe21a1f8a, 0x3dd4553b, 0x66a88ec9, 0xeb287702, 0xe0a6884a, 0xbd3acdd7, 0xae86c185, + 0x32dde97c, 0x228bd267, 0xcdec5272, 0x7163513f, 0x6354b1b6, 0x039bc22d, 0x5bec7015, 0x081a010e, 0x9396b495, + 0x6b6076ce, 0x54ebb803, 0xf39b7bfb, 0x502e9213, 0x6743e1d6, 0xcb909a0a, 0x01b22e4b, 0x03ae35b7, 0x52d0205c, + 0x524ebed7, 0x6e561d45, 0x4ae498c3, 0x523610df, 0x2ba80408, 0x4dfa748a, 0xef56dd47, 0xd9637143, 0xeadfef46, + 0x7b323b8c, 0x1e939de0, 0x727bf7bd, 0x29ac553d, 0x21faa0c7, 0x922eaa3e, 0x1414d291, 0xa892280e, 0x2ed04a76, + 0x5b9166ea, 0xe6ee4c36, 0x5161c447, 0xc2369560, 0xbf262c33, 0x8e70e78f, 0x8c0c920b, 0x8fc6103e, 0xe170f95c, + 0x99d847fb, 0x57cdf9ae, 0xe71ebbab, 0x0c202b00, 0x519254cb, 0x2b9fa068, 0x0f08e6e0, 0x1da1f827, 0x4aeaa28e, + 0xc9080ccd, 0x8fb3454f, 0x1a8641e0, 0x7023d105, 0x3ca6551b, 0xa7659297, 0x16c17b92, 0xd6a50a64, 0x87d5a3dc, + 0x2f1c4913, 0x692c252b, 0x526752c2, 0xedc0d9f9, 0xcc953cfd, 0x2a8ed3ca, 0xec315e9e, 0xccf3b42d, 0x82447a6f, + 0x4fb6d172, 0x8a61218b, 0xadc78f3b, 0x89a22180, 0x897bb444, 0x8f3efc45, 0xf28999fa, 0x8779cb22, 0x8343b2e8, + 0xe5163c41, 0xa881daf1, 0x84dd9c2a, 0x0d292ab9, 0xc0dc5844, 0x30fa04fe, 0x3f92e194, 0x97fb5beb, 0x3df42717, + 0x78cc0a3e, 0x704fdf35, 0x14fe28ec, 0xbc618358, 0xa506a116, 0x7d00e187, 0xeaf2c147, 0x2f7e9893, 0xe58ef7a4, + 0xfb62122e, 0x7683129e, 0x099b44bc, 0x7e7a9e7f, 0x7a565294, 0x473b61ec, 0x4ee019a3, 0xa0f9a103, 0x546b6406, + 0x03440a2d, 0x85915023, 0x1058f0c0, 0x9ccd15d6, 0x8f92bcde, 0x188198eb, 0xe92da621, 0xe8da354f, 0xfd5cdcb5, + 0xad59a48c, 0x3d2890ea, 0x7be09dd3, 0x0c761e98, 0x47da2a30, 0xb4d6eb6d, 0xbba6ca06, 0xc5e5a61b, 0x46891bcd, + 0xb7bb9fef, 0x3b37cc91, 0xe0b8851e, 0x955caea1, 0x1d31a55f, 0xf3d3b5d9, 0x931e4a6c, 0x86208b47, 0xe116ab35, + 0xf70cd5e5, 0x9004d895, 0xbb3fe7e9, 0x561ff051, 0x1ae90acf, 0x7e1c22d1, 0x77e9a3ae, 0x8d8b15a5, 0x0f55fd24, + 0xe818c806, 0x8e8b2276, 0xab7aca8f, 0x00a0550d, 0xe3cb60b7, 0xf54a528d, 0x7c37b0bf, 0xaff81c63, 0xd85d9e2d, + 0xfbf84da0, 0xf9a4e8d9, 0x6e33f432, 0x7ad23d55, 0xc58db0b6, 0x2ad037ed, 0xfb5ee36f, 0x42c6f12f, 0x16ecb577, + 0xf5672d1e, 0x2fa6a5b2, 0x8283cfa9, 0x2c751035, 0xbe0034fa, 0x3057590e, 0xdca1a523, 0x5bfc44e7, 0x6510bb55, + 0xaca94a85, 0x24f4f399, 0xa045cc22, 0x18986067, 0xd6e99972, 0xba140251, 0xe6d45114, 0x5120d2bc, 0xeb125984, + 0x63937ecb, 0xb7e5c5c5, 0x8767d159, 0xa7bc67ba, 0xd656a68e, 0xcbf72b91, 0x5f3e872a, 0xe363bf62, 0xa68465d5, + 0xc74a1410, 0xd8ff5d32, 0x7a0a7f36, 0xb039769c, 0xa160f51b, 0x3a41e464, 0xeb7fdddc, 0xab10bd15, 0x1ce35c27, + 0xa6958dc5, 0xe6ff7ad7, 0x6847c4fa, 0x8f4b3af3, 0x5c78d91d, 0x8d8c96bf, 0xc519f8ba, 0x13b2033e, 0x270adaa9, + 0x753e6c23, 0x2f4a66b1, 0x291d677f, 0xf6a2ff0a, 0x455913d3, 0x3aff0b58, 0x522b2e71, 0x6dbcdfe9, 0x578f5a18, + 0x766f2113, 0x2396f539, 0x8660dfc3, 0x4badfc53, 0xa09bca38, 0xacf99e75, 0x374f1c51, 0x4f551bd9, 0xb4cc9f2b, + 0x750184b9, 0x6c0d0c6d, 0x5c1450b8, 0xe8e98d5f, 0x75d72b1b, 0x4c99b136, 0x660240cb, 0x3e7bc2db, 0x9ae0542c, + 0xbb0e7920, 0xd5a6e7bd, 0xc1b5c30c, 0xa9035cbc, 0x0b26ab58, 0xa96cbf56, 0x467679d5, 0x32cb47d8, 0x3e401583, + 0x1282f340, 0x240e54c3, 0xcd291dce, 0xd8c9c526, 0x439850cf, 0x02241fd3, 0x8c1015e1, 0x8cd4429f, 0x82318977, + 0xc65df9a8, 0x5bfbd4df, 0xadc1ffad, 0xf89f9b3b, 0x1198ade8, 0x295b13f3, 0x35b1aa2b, 0x3381110f, 0xab0a9b43, + 0x7c420322, 0x302556ca, 0x49316421, 0x8cbe53d5, 0xc35c5965, 0x32237fee, 0xd76e45a3, 0x831d0b03, 0xa505e544, + 0xcdb91361, 0xbf2e39c6, 0xb1dafb20, 0xb38149eb, 0xb00f72ed, 0x1f981d65, 0x0de3f044, 0xd634e8b7, 0xdc40a460, + 0x7dfc5d96, 0xf98fa677, 0x5bac5f8f, 0xf92e132b, 0x208e6020, 0xa367d223, 0x3e3a4eb6, 0xf3366821, 0x975b1330, + 0x8cd1ecb4, 0x73ef415f, 0x4424fffa, 0x05f315f9, 0xbe37daff, 0x91a2b353, 0xcf4a7877, 0x4435f6d8, 0xbbcf6fb1, + 0xf3fd2028, 0x6f2607d6, 0x537d651b, 0x596b8edf, 0x02e0f0e8, 0xd4850ffe, 0x91c9a47d, 0xaeaf12e2, 0x10d31741, + 0x142fc007, 0xf8cb5fc7, 0xbaf55d2f, 0x0d68d56b, 0xd003cbc7, 0x270fde15, 0x1a751d43, 0x759c739d, 0x32699220, + 0x558ac03b, 0x4c0fc036, 0x5ede225d, 0xd9f88368, 0xf6508264, 0x84b238d6, 0x704b5d4f, 0x7fdac505, 0xd0941a36, + 0x37968af0, 0xbda5a671, 0x7ebd6100, 0x1cd618db, 0xaf380ecf, 0xbbe03007, 0x80a88669, 0x08978edf, 0xdf0041e9, + 0x17a11ca9, 0x861fb470, 0x15a7b374, 0x835fc153, 0xf87a1008, 0x4e89547c, 0x5333d38d, 0x78e90648, 0xae8df60c, + 0x01b28402, 0x0df9a4d3, 0xad2743d1, 0x905f456b, 0x08bb1234, 0x19202148, 0x792d7576, 0x5f1b602e, 0xc08fc85b, + 0xaf690081, 0x1235b641, 0x800eb546, 0xb5277ed0, 0xec3123c5, 0x4a95690c, 0x5c4dbaf5, 0xc51f4964, 0x85f1c397, + 0x344b8d1b, 0xb445e052, 0x77d5a1d2, 0x14f417cd, 0x9cb67f0e, 0x9fdbbcba, 0x0d32f21d, 0xb7812b6e, 0xb1970ff2, + 0xe6447270, 0x33f1a085, 0x25894eb8, 0x9e548d4f, 0x26d0ee9a, 0x9a80939e, 0x869cdfac, 0xa259c551, 0x1f318108, + 0x13e3a044, 0x217d30cf, 0x8f520951, 0x485449cb, 0xe50d5a97, 0x91a98c60, 0x40f08536, 0x4a14e4ac, 0x0a0ed862, + 0x750be3cf, 0xd9ff36de, 0x3cb87315, 0xc65b2536, 0xd43150cc, 0xe067cf3f, 0xedc581c8, 0x15ca2ae2, 0xe9dd300e, + 0x4af987a1, 0x43ac4c7c, 0x53873cc4, 0xc6d8b0da, 0xb0d0bf08, 0xa02b3a92, 0xad7fecf6, 0x021ad91f, 0xee579876, + 0x72f1c20b, 0x478e20b0, 0x3e8d32c3, 0x5654d921, 0xf13f8d11, 0x861291e6, 0x953010dd, 0x0e6f8fb1, 0x19cb9e1a, + 0x882fe199, 0x27e2ae01, 0xc07e4ab2, 0xf7e4b5f8, 0x36737245, 0xc1314d59, 0xda246ac8, 0xed5ab711, 0xdc0b3b69, + 0x63243a01, 0x00295846, 0x899c44a5, 0xf74ec0d4, 0xeb499068, 0xc2ce0a76, 0xde8156a6, 0x7e0eeaab, 0xd5058b9f, + 0xdf56d0ef, 0xe6225298, 0x5f958d55, 0x071157ba, 0x842e2c5f, 0x6e6b582f, 0x4cab0876, 0x8e345c09, 0x91f0d450, + 0x26e2f512, 0xf2ade63e, 0xf22b93fb, 0xc96a6961, 0xf575f7bd, 0xc0d22c3c, 0xb9c1a55d, 0xc7bf3239, 0xb14ae5a7, + 0xd5c097a6, 0x21f90e40, 0x9d934e3a, 0xd1641235, 0x1239d7cd, 0x90fff903, 0xf344a7b2, 0xc560cf21, 0xa7d6d56e, + 0x9f088307, 0xcf886d5a, 0x52b63c6a, 0x46c071bf, 0x7461fc99, 0xfa7f99e9, 0x9d6ba78b, 0xcd6cdf1e, 0xdcfde7e8, + 0xdcc7a022, 0x8e18cbfa, 0x355f5edf, 0x2bfdecea, 0x62f5074d, 0xb1e9167b, 0x9fd700e6, 0x84a6fecd, 0x6a209fdb, + 0x81424547, 0xab34b083, 0xaa324d20, 0x46b3900f, 0x31f67b68, 0x043eb142, 0xe83d3bad, 0x5436895d, 0x0555c4ee, + 0x52e51e18, 0x25fa1c6b, 0xc2313475, 0x8c5d0718, 0x91597fec, 0x4b653222, 0xd228fc9c, 0x0f036761, 0xbbac641d, + 0xaccfb7f7, 0xe819ccc3, 0x685423a9, 0xf1dce016, 0xb9c429ad, 0x10b5ef92, 0x031e5462, 0x4928eb0f, 0x939a30cb, + 0xfae1da2b, 0x6f08b2f2, 0xfb67e3af, 0x2ad15b59, 0x0785e9bb, 0x86bf2d0b, 0x55445c70, 0x128a89f9, 0xcaf0d959, + 0xc31404ea, 0xd6275f97, 0x248651b7, 0x7bc9ef82, 0x8c23fe83, 0xb6a811a3, 0x6793d646, 0xab855f7e, 0x6f817d19, + 0x560ca491, 0xdc96c8bb, 0xf3b62016, 0x7b3ca398, 0xa29793b6, 0x5cc9654a, 0x9d10953d, 0xc8edeae0, 0xdf881cee, + 0x8b715451, 0x421124fd, 0x2dcf1deb, 0x79d66be4, 0x8c62b145, 0x46ce442e, 0x3dfd2a3b, 0xb2461a18, 0xd3f3cbce, + 0xa866d61d, 0x9e2adf10, 0xcd207e6b, 0x9bed6445, 0xd0e212ad, 0x7ad24ac7, 0x6afb56c7, 0x3444cdd5, 0xa98b80df, + 0x17c1400c, 0xab881afa, 0x5c968030, 0x2965cdb5, 0xad034bd9, 0x49a76a00, 0x183fadeb, 0x4ed93511, 0x143c1b9c, + 0x29da7ec5, 0x3bdbbf54, 0xca19815b, 0xd086c29f, 0x8cdc3c78, 0x8168ff25, 0xc75e8d88, 0xba80ab30, 0x3427e14c, + 0xa191cfd0, 0x7ef83e32, 0x61de015b, 0x72dcd3ab, 0x2c535496, 0x93a70578, 0x9524e3dc, 0x5af7166c, 0x72099f8a, + 0xd6ff5984, 0x6bcc939e, 0xf3f3df87, 0x41028a66, 0x47986c89, 0xf9b083c5, 0xbd7b4b80, 0x0eda9936, 0x65de25ea, + 0xf6ba4d5d, 0x0ecb8832, 0xb038ffee, 0x55ad268c, 0x5cc4f363, 0xe82dfcb7, 0x3b32f3df, 0x8f0737c3, 0x6ebf4c87, + 0x9c0f8164, 0xb216639f, 0x1bed287a, 0x46a1627a, 0x7cf7093b, 0xba8dbc26, 0x3690f76e, 0x43eadf2c, 0x0bfb5818, + 0x42088c3d, 0x78be8221, 0x1bb05bc4, 0x07fde5b0, 0x8bd62d25, 0xba44594f, 0x1b75dd05, 0x230e9010, 0x6df40626, + 0x0957b7b9, 0x669b9c7b, 0x104548aa, 0xdd53da45, 0x8a0f8fd5, 0x9f3b475c, 0x142ec636, 0x2289b19a, 0xee9836d5, + 0x6e94969f, 0x50726097, 0x031a4619, 0x9dd5946f, 0xb37f91dd, 0x25ecde6e, 0xcdfbda56, 0x8a81a058, 0xcea9d8bb, + 0x787ef176, 0xa3b4f06e, 0x0fbefdf8, 0xb4deeba3, 0x271224b3, 0xd754532a, 0x6f161df1, 0x99eb6cff, 0x92d48794, + 0x6de058f5, 0x1dc9e408, 0x6ab57a38, 0x21ee3047, 0x9824f61b, 0xb8303174, 0x27344f8f, 0x23bad112, 0xa55a928a, + 0xcb2d74ac, 0xf29d59b7, 0x176b8a7c, 0x054ffdaf, 0x5204b85f, 0xdc460f2b, 0x5e9dadf1, 0xb89a300e, 0x7aa5c545, + 0xe56fff7d, 0xda8e9f82, 0x51cf0308, 0x42b46e39, 0x31ffc76f, 0x502100f6, 0xc669785c, 0x52c76c21, 0xde9b2d7f, + 0xf08008b2, 0x5ab6abaa, 0x0d44e23d, 0xccee9735, 0x005782ef, 0x96c1c4c0, 0xd47cfa97, 0xd9000c44, 0x6c9879b4, + 0x5f6de4f0, 0xcdbafe40, 0x638200c8, 0x0cabfb3e, 0x8b8dad58, 0x3bf90663, 0x704d83ae, 0xc8e60b8f, 0xfefb7571, + 0x47030067, 0xbe7e355e, 0x45ca0d7c, 0xc4e4b523, 0xcd58388c, 0xa93bc985, 0x53529d09, 0x0602bab5, 0x62171ae9, + 0xeee6ae9e, 0xfb3f3b33, 0xb4f8fd70, 0xecaec6f2, 0x846a69a0, 0x2004fe59, 0x447eb196, 0x29595d8b, 0x136e5de4, + 0x5b833bb5, 0xb032cbcd, 0x62c230a2, 0xbb221480, 0x9b05f8c6, 0xe34daf6b, 0x8cc7ee98, 0x4cea125b, 0xf5b2141f, + 0xb77815db, 0xdc6b811c, 0x5fa9c4a9, 0xf496314a, 0x3a95bfdc, 0x63131609, 0x906f87a4, 0xfecc992d, 0x54391481, + 0xebf65e2d, 0x247d5492, 0x4da8dc0c, 0x213b83a1, 0x52e65a1c, 0xdab8d2a3, 0xa77ded45, 0x66791551, 0xeb5b80de, + 0x994dc71c, 0x1fa4dd08, 0x6d6de746, 0x8492c6e0, 0xd0f22ffc, 0x9064074d, 0x9f0d17f2, 0xf225fdea, 0x0671ba60, + 0xd489414f, 0xdd771659, 0xefce38e6, 0xd120e183, 0xa1ffbbee, 0x4000d32c, 0x86a7f4ed, 0xb5c44508, 0x3b641157, + 0xb5b23e08, 0x75de6407, 0x86025d23, 0x054874b1, 0x7e280f8a, 0x2de0684d, 0x127afc5d, 0x2a51d218, 0x85255923, + 0xb9af24a9, 0x4a0a7afa, 0x13af4b25, 0x25b82653, 0x4ab3c00e, 0x74d30251, 0x0e68bb28, 0x9b221705, 0x69735cf1, + 0xd6266732, 0xc44f92ea, 0xf7107304, 0xa03bf3c3, 0x57fc5790, 0x13dbfcdb, 0x5496f479, 0x4ba85269, 0xc65fd8ed, + 0x850d8fb5, 0x42e921ee, 0xc8ffb391, 0x6de68b2f, 0x0483c68d, 0x3e7ef497, 0x39306337, 0xdb6f440c, 0x15d27c40, + 0x2ab6cdda, 0x487a498d, 0x1b821eab, 0x37a0ecb6, 0x3de5058a, 0x34f68802, 0xc2d51ebf, 0x100dc9fc, 0x946127fe, + 0xc6357ea7, 0x358bef8a, 0xf8a00632, 0x9a76c563, 0x3d8c1d76, 0xea6015c3, 0x59a3044f, 0xd08f8d66, 0x0a2da859, + 0xf7db374c, 0xb8728ce3, 0x6d4e0a41, 0x9b1977e2, 0xa39dedf8, 0x01a23730, 0xac69f015, 0x1f52dcc5, 0x6e7fa421, + 0x0622721f, 0x509efece, 0x0e7e91d4, 0x3edb7c1d, 0xd7a72780, 0xbc89ced8, 0x12334a6f, 0x4c5439d4, 0x773f41f6, + 0xa9d80351, 0x3a4cd324, 0x2cabb343, 0x48ee4f9b, 0x51d18cf4, 0x53dcc46c, 0xf98acb5f, 0x192752c5, 0x751103ad, + 0x96171f1d, 0x659f3ae4, 0xbfa89f61, 0xf078f520, 0x233607f7, 0xe971f66f, 0xbd1c31fe, 0x372c3b0a, 0x389af978, + 0xb975358e, 0x69dc20ea, 0x5c51d86c, 0xa3213611, 0x4e70d94b, 0x1785c077, 0xe4786c48, 0x56d978f8, 0x31aa465a, + 0x1bc5c89d, 0x951d0f27, 0x80d8ed17, 0x2e5893d2, 0x4ee37d70, 0xf1b61add, 0x2d2defe5, 0x7f7fbcd5, 0x230271a6, + 0x204bb0b1, 0x4ff4f36b, 0xc92ad96c, 0x28382d00, 0xe6d9578f, 0xbf46b99a, 0xcbd72255, 0xb6436987, 0x0190eaed, + 0x66157232, 0x95ce62e2, 0xfff92f56, 0x6f72c54c, 0xf61e3196, 0x972a4b7c, 0xc84fe040, 0x0b5a765d, 0x14042a63, + 0xe3adf872, 0x9fd94d99, 0x759926a6, 0x5283248f, 0xba48279d, 0x14ff7d7c, 0x2874b643, 0x78e75193, 0x32ccae87, + 0x38e5a1fc, 0xce8bcab7, 0xf85cc68f, 0x1ae5f3b2, 0xd94f8941, 0xf1df076d, 0xc0447f22, 0xd6fd46e5, 0x45a226b6, + 0x073c8fa7, 0xcc0a8d3f, 0x8828cab4, 0xb77fa6ed, 0x6d597b6d, 0x1c37e1c2, 0x4528586c, 0xb49bfc5a, 0xa179e920, + 0x34317663, 0x1c28795b, 0x809cedee, 0x287e2d9b, 0x9d8a4180, 0x5caba288, 0xf7bb6da4, 0x7ecd48dc, 0xfc03bd6f, + 0x97c1ada7, 0x05ae96a3, 0xcf2adfcd, 0x3a8d11f5, 0xdd6b69b2, 0xc0723704, 0xe0a060c5, 0xfba0bf58, 0xe57a7b1e, + 0x9500e75b, 0xb94146f9, 0x79b07dcb, 0x145d2523, 0x9e5fbdb7, 0x43132d92, 0xd439b324, 0xb52f471e, 0x80ce562f, + 0xddf15d94, 0x7b2e815a, 0x94e62f3d, 0x4ffdfd9d, 0xc5c363c8, 0x1e962112, 0x6caadf32, 0x8313d4b3, 0xc167dcea, + 0xe38ca881, 0x4d318daf, 0x8adff43f, 0x8b4a7d3f, 0x65772e23, 0xbb4fdebf, 0x8d1d0f46, 0x3d4e6d39, 0x984799e3, + 0xa3b43e49, 0xb1feec01, 0x445307cd, 0xc39835da, 0xeea7aa12, 0x8e0172a4, 0x5486ac33, 0x9fb8b6de, 0x283583e4, + 0x4c321411, 0x3c1edcfc, 0x0c0530c1, 0x0419a677, 0x5775b8d6, 0x09cdd79f, 0x1a9fff46, 0x384744e0, 0xe7dae38a, + 0x298374c0, 0x5c471e7c, 0x3d0c2064, 0x2a7aaa88, 0x498f9c31, 0x04269caf, 0xeb0dd23d, 0x946a6229, 0x3cc1edec, + 0xc29efb9a, 0x63f2a732, 0x6d805561, 0xe0b83b71, 0x2aad9da0, 0xd94e1a62, 0x5e1c8813, 0x58bb4fa6, 0x4cadc324, + 0x491f676e, 0x2ea7cb57, 0xb146b928, 0x70b26880, 0xb9945133, 0x3974e4b1, 0x7bc07c30, 0x60c83cbc, 0x25e38123, + 0xc14a4141, 0xc4b4557d, 0xf630b2cc, 0x3aff7a4d, 0xafb19698, 0x12ea7201, 0x1536d75e, 0xa196128d, 0x7d479056, + 0xc7e56a5e, 0x46eabd64, 0x84e57b38, 0x622e4a42, 0xcd74cd6b, 0x30703c63, 0x4ef1aca0, 0x314a85e4, 0x51ce0e87, + 0xbdd07a95, 0x8dd2c635, 0xd8c3feb3, 0x06f14726, 0xc8624bb9, 0x59b09efb, 0x0422e23c, 0xc081b9ff, 0xc1739b3b, + 0x0ef0e2e5, 0x36b4b5d8, 0x400cc816, 0x44a17f54, 0x02a8ef71, 0x5a960288, 0xe3ac15a1, 0xd4483df1, 0x7467d2fc, + 0xc6d34fa2, 0x0c3c4fa9, 0xfbffc338, 0x1ab79b46, 0x4e363ea6, 0x4c01e3ce, 0xa4659a18, 0x5b5b537d, 0x85040fd2, + 0xe182003a, 0x28d02877, 0x7e6439f3, 0x2d059bb1, 0x20ff08a4, 0x4635da09, 0x4678ec93, 0x7101aad7, 0x6b614ef8, + 0x3741dc09, 0x2d967cbd, 0x4e925d60, 0x2e8b8b04, 0x85dce306, 0xf97f44a0, 0x44259e55, 0xde231e89, 0x3619ec0a, + 0xb644aa4d, 0x65603e50, 0x7ac74af4, 0xe228f84f, 0x5d7a34f2, 0xb9a2b85f, 0x0e783a37, 0x020e2615, 0xc43e1c57, + 0x06581154, 0x73c22f17, 0xcbe0f35f, 0xac629160, 0x96dadc38, 0x698da3b8, 0x9c0048ee, 0xeb660fcf, 0xc9e6df96, + 0x475329c7, 0x9c65f0e5, 0x8a3d73e8, 0xf69a9b77, 0x8d14c7a3, 0x5bc8ef6c, 0x067bb777, 0xc52379f7, 0x372c792f, + 0x9af9fbe0, 0xe8dd4d0e, 0xa83a36b8, 0x834d3a9a, 0x6710f8fa, 0x8951c561, 0x5ddfef22, 0xbc1829a3, 0x21413777, + 0x7c1caaa5, 0xaca942a4, 0x34fdc188, 0x03976d5d, 0x0316e2c0, 0xe34e33af, 0xbb9aa938, 0x3a594427, 0x99c70e44, + 0xdf857df7, 0x079556ab, 0x5c53838d, 0x646ed9c5, 0xbbfb48ed, 0xe07ee61b, 0xbc778171, 0x078804b0, 0x79029c0b, + 0xb753bfeb, 0x75f6c4c6, 0x3f9b0d33, 0x1c63174d, 0xa5400a62, 0x26aa82c5, 0x5c5003ab, 0xfe2fac62, 0xa1ef31d3, + 0x803ef821, 0x8d9f5921, 0xf7384bbe, 0xf47b9199, 0x6d6b3be5, 0xb42c6dc2, 0x4552dfd7, 0xbbf7526d, 0xea771f8d, + 0x0d000961, 0xad88405a, 0xc6bcd865, 0x2cc3d508, 0xcb34a4fd, 0x63806976, 0x32528ae1, 0xbb27f864, 0x8a5a07df, + 0xe3cc0060, 0xe58d3a7a, 0x28be312e, 0xc443ed49, 0x4ab02a98, 0xd029ce4e, 0x0505a2ea, 0x0f6484e6, 0xd2b61f41, + 0x3298625e, 0x5da09b8a, 0xb0fb2033, 0x01f1632c, 0x58e8e47c, 0xeb9c7ec2, 0x4d0d7279, 0xf1ea0d32, 0xf8d880a2, + 0x615c5bf3, 0xa136c1ca, 0xca1e836b, 0xd60053f0, 0xfcda7554, 0x9b364e11, 0xb2e4a8e1, 0xac609a2d, 0xeac51286, + 0x41c9237a, 0x5ffb0cd8, 0xfac9c77f, 0x39910405, 0x4b4d86e1, 0x27b28ad9, 0x117f450d, 0xe71b4273, 0xb75c5687, + 0x57f4cebb, 0x412f1de3, 0xf7e06aed, 0x450ce7c8, 0x63bff46d, 0x675aec4c, 0xd131b97c, 0xf03e436d, 0xb71cdeaf, + 0x1e74fb8b, 0x7d189789, 0x0c9b9ee9, 0xac60388d, 0xa8594f5f, 0xf2ed08f9, 0x76682cbe, 0x2579e071, 0xbe453b61, + 0xa7d20794, 0xc7cb198b, 0x56dbb09a, 0x83a3a9e0, 0x4ec68d86, 0xc460c525, 0x05356296, 0x6f2f5c69, 0xe86cc6d0, + 0x905a98ec, 0xa03cb3e4, 0x9d2cc662, 0x9a6be35d, 0x3bad7e10, 0x93db95c2, 0xd9410c57, 0x6924e5c1, 0x5c35d2e6, + 0x23d34fd1, 0x563311ae, 0xc2488e90, 0x871a3f16, 0xdb7e96bb, 0xf9609a45, 0x6457137e, 0xf9c0f1fb, 0xc3864892, + 0xd71d4800, 0x94991b2c, 0xdc4c2641, 0xfd59d3f9, 0x1e818d77, 0xd84d2495, 0x498640d8, 0xff7ee3cf, 0xd33e2b23, + 0xf24d1fda, 0x7753bde9, 0x082df816, 0x4959692f, 0x19bdf45f, 0x5b5a2359, 0x6631d34e, 0x2923f3e6, 0x2fec71fd, + 0x0a8a70d1, 0x5702de27, 0x92313841, 0x449791ac, 0xb387742b, 0xe851d2b4, 0xb75dae46, 0xeb0d7bd8, 0xad3ecde0, + 0xe912e559, 0xb830ab43, 0x52b754bb, 0xee8dfe05, 0x938fbd1a, 0x061f4545, 0xb4c18df2, 0x4ecef72d, 0xa9610186, + 0x46b62635, 0x4ce26867, 0xf946ddfa, 0xb9ceaf28, 0x730e0324, 0x2933eca3, 0xe94a2023, 0xc9b0730b, 0xfc93ff44, + 0x4c3907c7, 0xb95b0fb9, 0xb6938f1d, 0x5a9a2ef1, 0xa249a9d7, 0x0472aeb8, 0x3e24c5f7, 0xb4599ec6, 0x9daec0f3, + 0xa3b70d62, 0x3ce87aa0, 0x74b4e317, 0x5fa848a3, 0xc2674248, 0x7fade30d, 0x105d2095, 0x22c4017a, 0x53bbcfd9, + 0xc1ec0bdd, 0x521ba2f9, 0x55965fa5, 0x18d47b85, 0x5eb83e5e, 0x6ae05f1c, 0x9387964f, 0x1f32dd0a, 0x46737e02, + 0x43a2a488, 0x83c377a6, 0x4f682c49, 0x350e34a4, 0x1bf25633, 0xbf8ac4d2, 0xa51fe75e, 0x930b6287, 0x21e75f13, + 0x92842b54, 0xcefb46d7, 0xd2f04fa0, 0x05c173e5, 0xe351cf79, 0x186cd123, 0x2c6328c8, 0xa254e6b5, 0xc15494ec, + 0x0c0f91e2, 0x8e233c9b, 0x7a8714db, 0x5ad92907, 0xbacb71e0, 0x16d62f2a, 0x9fe88b25, 0xf3f9cb39, 0x3b9646a5, + 0x040cb141, 0x7af757c6, 0xd6eb4881, 0x4602d1c4, 0xc4564a7b, 0xef369429, 0x1d2e942b, 0x67692f2d, 0x0478fae4, + 0x7ad00729, 0x130d1344, 0x290c1ac7, 0xc0994354, 0x927f73e3, 0x4ee6615b, 0xe47c953f, 0x11cd49c7, 0xa8d2b334, + 0x258a0a8c, 0x5427935c, 0x1ebe4283, 0x42e7a454, 0xcee6c96b, 0x407f1c47, 0xa4faae82, 0x237dbf6c, 0x45bc95b7, + 0x9e195bd6, 0x3396ae0a, 0x0e6d0413, 0xd045c0f2, 0x0788a353, 0x428c36d7, 0xc1855eab, 0x51ebadde, 0x4736eb20, + 0x6ac920ee, 0x12937ae5, 0x7bf6df81, 0x939a4597, 0xbd526b85, 0x33c7d5de, 0x8987d594, 0xb735539b, 0xcdaf56c6, + 0x71acfb73, 0xf6e0b739, 0x8205d010, 0x7e3c1399, 0x3966d99b, 0xb58f6528, 0x39a268e6, 0xfb261e0d, 0xac11bfbb, + 0x482442cb, 0x18a635b0, 0x7c51b88b, 0x3ae12d23, 0xfb76a8e8, 0x24acf814, 0xa7bc459d, 0x40a2530f, 0xef1d260e, + 0xd74aa101, 0x98ccbe05, 0x330cf9a8, 0x001edbfd, 0x1cdf590f, 0x848025bf, 0xca7f9d9d, 0x57089850, 0x694cd504, + 0x097d0849, 0x121232a2, 0x13e6688c, 0x15bccbe6, 0xc6ba4c43, 0x64ff7b61, 0x2f2f2592, 0x66a55d49, 0xa35d612e, + 0xd510f77f, 0x7b9b8f71, 0x60f03608, 0x64a02825, 0x2ac813a5, 0xfb7d3e77, 0x537c140f, 0x3dd85df2, 0x7a326116, + 0x50ce29c7, 0xa80e429c, 0xf99e6bc5, 0xc0898e2e, 0xfc0c899e, 0x4e62d93b, 0x453a3b4c, 0xd807f550, 0x89af5430, + 0x97d91ca8, 0xd444ae01, 0x275c02f2, 0xf662f7ba, 0x3d4df649, 0xf79d1899, 0x8d37b8b5, 0xd61e0796, 0x3c8070c1, + 0x9d8970c1, 0x49971256, 0x56e9338b, 0x28cafd9a, 0x50fab884, 0x572e42cf, 0xc91643b6, 0x98a2f605, 0xba2698d9, + 0x612907f9, 0x8a610764, 0x01802572, 0x186f379f, 0xcd10674a, 0xe39e3ea7, 0x13ac028e, 0x761fe3f5, 0x3e015824, + 0xb5030220, 0x0c11cf3a, 0x0241e794, 0x967ff0e8, 0x5700351d, 0x6ce254ba, 0xc622802f, 0x5a9b09a1, 0xd5111f04, + 0xc34c3e3f, 0x0ab84a73, 0x3ccf4a58, 0xdc60adc5, 0xd2d4bae0, 0x21ce685b, 0x742d1deb, 0xbf2a2865, 0x1cdac378, + 0x708ec7cf, 0x6af8f090, 0xa9705cfb, 0xb31c6fd7, 0xddebc0d5, 0x87d063fb, 0xa5fde28c, 0xce68dc60, 0x3a65cd82, + 0xdf2a90b0, 0xbc06117b, 0x3c56465f, 0x6f156db2, 0xe8763009, 0x92f559ae, 0x13f2bd1f, 0xe4be79cc, 0xe8d06287, + 0x1f028078, 0x800c61e3, 0xe190df17, 0x3477cf90, 0x83572426, 0x2860cb3a, 0xe242c28d, 0x2bd789e8, 0xc4ab3a74, + 0xf298cf09, 0xb54db387, 0xc2f13805, 0x269413ca, 0x6f3fe9b8, 0xaceabb11, 0x05da2a60, 0xa62c1c0e, 0x70008077, + 0x9c094316, 0xb53c3815, 0x56a34ef0, 0x378b8cf7, 0x437e9c47, 0x94a88c27, 0xd416547d, 0xc6c18a64, 0xbc59f605, + 0xf9582149, 0xf268c576, 0xdcb1e686, 0x1de7018e, 0x95907a98, 0x82d5f4ae, 0xeb90bd3f, 0xf475684f, 0x38bbc233, + 0x441c6cad, 0x8f48bb58, 0x2dfc1516, 0x1f91fa5e, 0x4947c85d, 0xce41728d, 0x8f45655a, 0x98539fa7, 0xe47728fd, + 0xa89696e3, 0x44bb5135, 0x3f7d5eb3, 0x99a63ca5, 0x86f8df6a, 0x0775715a, 0x7ebeb68e, 0x1c18c90f, 0x364e43b8, + 0xa0cfdb3f, 0xcfe669f4, 0x2b764ffe, 0x6b4de98f, 0x68d6cfcd, 0x44909bee, 0x396323f3, 0x3535b536, 0x72b325b8, + 0x7b3e7c7c, 0xf3750ce0, 0x3f67b977, 0x30419763, 0x44e0bdc0, 0xf9b82a6a, 0x8cabf7a9, 0x463a4316, 0x2ba8b313, + 0xdceaabfc, 0xe1ce19de, 0xcbf3c6c3, 0x0e37e747, 0x4a919312, 0x238a5cd1, 0xab3a32cd, 0x1db08b03, 0x0c533db8, + 0x56cab1dd, 0x2de8fb44, 0xf44cf82c, 0x41e5050e, 0xacac9b29, 0x988ca421, 0x81d08b6a, 0x0af79b02, 0xba8ab3b6, + 0x8744f674, 0x79c92880, 0x2e5280d9, 0x157502c8, 0x1de23f34, 0x83e180cf, 0x62973287, 0xd2c33f5a, 0x43a8e5d4, + 0x2f823bb6, 0x5244bd62, 0x11cfffbc, 0x599936d3, 0x7688b1f7, 0x38674954, 0x2814e2be, 0x89547242, 0x1cef7f26, + 0xecae952f, 0x7476f663, 0x68e8c156, 0x3ae3f342, 0x49b7905b, 0xf6839c4f, 0x515427ab, 0x2291dec8, 0xc3e489b4, + 0xcc39e994, 0xc1b5f349, 0x1896b164, 0xd013bd49, 0x29b1f49b, 0x32b482a4, 0x982e78e4, 0x3f4b479e, 0x65a6a648, + 0x30a5ed44, 0xb21e86d4, 0xd985d1f6, 0x0b3cebb3, 0x3b1f1737, 0x2eb68611, 0xa4d6b772, 0xc16b7515, 0xd805ee5d, + 0x5efd3e68, 0x08a13b50, 0x2d01eee9, 0x2e181161, 0x09e9b3b7, 0xd648ae21, 0x054ab5b7, 0xa27df43b, 0xc8debed6, + 0xcf764646, 0xd3cba23a, 0x59a9c4f8, 0xe8ab8667, 0xc2d5d1bc, 0xcf3c3350, 0x965b1a26, 0x7a5a5455, 0x3f70ffdc, + 0x2b45a588, 0x0a0abad6, 0x77e84ffe, 0x6a4c960f, 0xd4a17f18, 0xe2a7b0df, 0x882332e9, 0xff6c6b19, 0x3a34a783, + 0x03ca7f18, 0x4340c788, 0xc5f3023a, 0x24fffc91, 0xb1650329, 0x07f6c423, 0xbc359c66, 0x7ab5137f, 0x8bb53362, + 0x56c48dd5, 0x7e4432aa, 0x47e87994, 0xdd185796, 0x1a6108ab, 0x7e871c6b, 0xac0f75bd, 0x2ea1d023, 0x9ce2151c, + 0x6771249f, 0x0c8a0687, 0x512ab5a6, 0xbef9f740, 0x46ac465f, 0xb7fd3530, 0x5acf9f29, 0x6306c090, 0x7ec6da20, + 0xcc238dac, 0xfd716f6f, 0xa9cbeb9f, 0x28b9c04a, 0x792d7003, 0x8fb79652, 0x05dda002, 0x53e6bc49, 0x40740b60, + 0x9ece1b2c, 0xbf3e8886, 0xf2a12104, 0x87197804, 0x898f11f4, 0x1949ca78, 0x9ddafc69, 0xbdbcfec6, 0xd39c20a3, + 0x8021b54a, 0xbe4b5a3a, 0x398ed5f3, 0x3688efe8, 0x7f7f457c, 0xe3dca4e2, 0x18e7c0a0, 0xc5c2a6fb, 0x5b573565, + 0x327ccfed, 0xecafb582, 0xeb048fab, 0x52209438, 0x46fc57fd, 0x582368e4, 0xb1dc93eb, 0xd8239878, 0xe4f4935d, + 0x4b581d15, 0xf4cac300, 0x52c0eaff, 0x530d0236, 0x3e596f53, 0xa7061dc8, 0x55b60b4c, 0x1e1f5ec1, 0x6f02a2d1, + 0x2fe2aec7, 0x3e9cffee, 0x4264a140, 0x56855482, 0x0a4cfa4a, 0xcf9463dc, 0x85d2c897, 0x00d4dc84, 0xaf39a691, + 0x3c3d687b, 0x635ca162, 0xa33239fa, 0x13238fa3, 0x6626ff2d, 0x732a404b, 0x9bb9fbcf, 0x29efa0fe, 0xca70891a, + 0x9d63ba1a, 0x5ba9f277, 0x4513f72b, 0x4ff113ba, 0x6dde22a2, 0x2b526eb5, 0x80fba1f7, 0xb0e24c49, 0x39fc71c2, + 0xb0ff640d, 0x94328fdf, 0x959da2fd, 0xd7a9aff4, 0x798a254e, 0x017d00f4, 0x74f2df9c, 0x9850d1d4, 0xea4014bd, + 0xd6965b39, 0x1571b25d, 0x3c816c97, 0xd410aa3c, 0xe23677af, 0xf8421b66, 0xb02a2efb, 0x9789f49d, 0x5febc910, + 0xcb94842e, 0x04c093db, 0xd03afe89, 0x4e27bcba, 0x63814c9e, 0x8bdc1db8, 0x73feb726, 0x138848f9, 0xbafb4112, + 0xe5348e11, 0xf0d10980, 0xa6201484, 0xf3f1a98f, 0xa2625369, 0x62fde77e, 0x0e1abd53, 0xd2967f7b, 0x0701c9e7, + 0x1dffb4a5, 0x66012a39, 0xcdca274c, 0x4faf3c6c, 0x3da7fd86, 0x73a357c3, 0xa5df6177, 0x7eff42a9, 0x9f17ae74, + 0x1baea2b7, 0x8f947f0c, 0xc1918306, 0xdd05dd03, 0xe223ab0b, 0xd66da2cd, 0x0cba4aea, 0xdb007a95, 0xa02691f0, + 0xb7ddd5ee, 0x00ccc793, 0xcbc6b764, 0x87de7f2d, 0x6a45c9e5, 0x7cd2f742, 0x56076ac5, 0xb868c009, 0x45d02f11, + 0x40684fd5, 0xa3f1664c, 0x7142a92c, 0xfdd7ecc0, 0xcdffcfe4, 0x72ce951b, 0x5058c0ed, 0xb2c15808, 0x38d6f7e1, + 0x4418d9a2, 0xf75ba902, 0x0aaa4bfc, 0xe8ba31f8, 0xd5cb1d09, 0x46053df6, 0x3c70cb54, 0xc17c7d1e, 0x85cee8c2, + 0x942f87de, 0xe947f5ee, 0xb2e1e237, 0xfe94e72c, 0x930fd982, 0x465ee3c7, 0xc3ca10f3, 0x34fb8c7f, 0xf179c5ae, + 0xfa92fbff, 0xaa087ae4, 0xb58fb785, 0xe4bbba82, 0x7f6cae1a, 0x73112e0b, 0x85752e5c, 0x3eb87e67, 0x47ce5453, + 0x8ca2604b, 0xbe607462, 0xe8b0beed, 0xb6f80b4b, 0xa344e253, 0x1b80bfa0, 0x1f430191, 0x5332dad2, 0xa17c64a5, + 0xd17b9433, 0x708efe85, 0x47b498c2, 0x7b5e7af1, 0xc47e7349, 0x497998de, 0xc44f0bec, 0x32877f32, 0x7a281789, + 0x7bbd511f, 0x356a68b7, 0x875b2b69, 0xc09f46b8, 0x7de337d4, 0x45cf4b5e, 0xc0462fc6, 0x5cdbf9ec, 0xe9854e0e, + 0x812d6bde, 0x0afb3438, 0xafec0cd8, 0x606731f7, 0x74350a4b, 0x8ac9e2a2, 0x8d43f195, 0xff1b9e5f, 0x4632fbf9, + 0xc2e95d06, 0x909fdaba, 0x42a3caa5, 0x40537b60, 0xe9961d9b, 0x7c9e6b90, 0x5d4e93b6, 0xbffb8caf, 0x1f2e9e8e, + 0x5fa69acc, 0x9fa8f8eb, 0x2153a475, 0x874de097, 0x062340f9, 0xfafd23c2, 0x252b68e8, 0x4955bfdc, 0x793f73cc, + 0x2403930c, 0x98aa5831, 0x6efe0633, 0xc64702c0, 0xbb12aa50, 0x45758374, 0x9cb53f00, 0x82cb6a5e, 0xdeeb08c0, + 0x11e5cbdd, 0xdf80ed8f, 0x96e79a3a, 0xed1ae4f4, 0x9816ab64, 0x1d404222, 0x1b9123df, 0xd0874a91, 0x1cb38992, + 0x3c73463e, 0xcd73df18, 0x3d8983a7, 0x3628e3a1, 0xa9f43379, 0x33dfb059, 0xcde3ce26, 0x32f71da6, 0xfd890adf, + 0x3c21e4d5, 0x2f805400, 0xa2d5b019, 0xd7057ef4, 0x3f9a790a, 0xf59ec98d, 0x81befeb9, 0x66fc22fb, 0xa5458d0d, + 0x57940534, 0xaf49b779, 0xa51aa119, 0x1f9f97f2, 0x9473e555, 0x35b821ef, 0x1f339480, 0x4cad342a, 0x42c49fe7, + 0x60cf8a97, 0x1accbb77, 0xb5e38860, 0x9db3c1e1, 0x620e60c0, 0xf785dd6a, 0xff24d802, 0x3ade5afe, 0xd4b03609, + 0xb64426fc, 0x8496ae20, 0xb211b935, 0xf13a61d9, 0x6e788773, 0x377e9ca3, 0x638c86bb, 0xbcef07b9, 0x9116a467, + 0x0c6f3852, 0x205d4063, 0xae687c6c, 0x4ee7cb20, 0x65d50687, 0x7ed96565, 0x9724acfa, 0x48672117, 0x0ee5f42d, + 0x31700be0, 0xd3d6dd25, 0x6c67a0d9, 0x031ce4ec, 0x06431aa3, 0x174e6b3f, 0x6dd312cf, 0x7b256256, 0x6eca8f40, + 0x2c6f05a5, 0xffd310c6, 0xd1e4ac3e, 0xce1137dd, 0xc8f38837, 0x5f5e3719, 0xa948a5fd, 0xbb99c2c4, 0xa01e5907, + 0xfd0d97cc, 0xeb8a9e81, 0xf7928132, 0x163729e5, 0xab20f7ea, 0x42414586, 0x92c22eab, 0xb8d33ca3, 0x36f3145f, + 0x8e7f7a2c, 0x33920a3d, 0x0e899ad2, 0x8bf42d2f, 0x93e95f7b, 0x2b58cd24, 0xcd3867ee, 0x884313aa, 0xe27d640f, + 0x09da2c2f, 0x25e64256, 0x244d7ad2, 0xa78565b0, 0xa18e2cbd, 0x8b25192e, 0xd2c869d8, 0x4a3c42b4, 0x16b2c95e, + 0xfb3a69c7, 0xb62fd1aa, 0xc8adb845, 0xbfcb67db, 0xe6804545, 0xdc6e7f6d, 0x7a5702c5, 0x82a8994c, 0xd0f51c22, + 0x5b90625c, 0xc1949abb, 0x8e0f89a1, 0xb1fbc0c4, 0xf2c6f51c, 0x92f271ea, 0xa033df21, 0x81d2a96b, 0xeaa1787d, + 0xbd25f385, 0x0a0df7e5, 0xfb99a654, 0x85fc1542, 0x19abc07c, 0x8a6666d0, 0x94ac4a07, 0xda648476, 0xbfb6ee8f, + 0x908d62dd, 0x874874f6, 0x4a9587b4, 0xac211a45, 0xf26355b7, 0x72f0beef, 0xf5d81f5b, 0xedaf7c7d, 0x375421f3, + 0x4b2e565b, 0xe86fad65, 0xbaf4f3fb, 0x75c46a85, 0x965f0749, 0xacdc36c6, 0x29144ea2, 0xf54a2a78, 0x4e33a828, + 0x1781f180, 0x980f35cc, 0x9c94c87a, 0x3f75803c, 0x80641d4a, 0x39993451, 0x745df065, 0x6eae5c79, 0x3500908e, + 0xd115f8a3, 0xdb64ea62, 0x9aaf9902, 0x2eb2a018, 0x1a5a1eff, 0xd99c5155, 0x8b782d0d, 0xb7252fe7, 0xf6962778, + 0xa431d792, 0x5e96b1bf, 0x9f62ed6d, 0x8fe0accc, 0xf9fdb7ec, 0xa639874f, 0xd32061b1, 0xd7e2f1c4, 0x586b0b86, + 0xe0c2ea93, 0x9044d476, 0xc20142bf, 0x9b228c50, 0xd4e09d98, 0xd230b23c, 0x9f77b258, 0x27db85be, 0xa0c1aae8, + 0xc30cba17, 0x9be10a72, 0xa75f371c, 0x96b49185, 0x44910616, 0x3e401a9a, 0xc2e6ad12, 0x53445c21, 0x59187a77, + 0x7bb08d30, 0x97c2c937, 0xd39bd2a6, 0x25a98d74, 0x63cf3bff, 0x89510928, 0x96e7c3e9, 0xecd98666, 0xbf383c8e, + 0x72cd65fe, 0xd013841f, 0x4583747b, 0x2f7362fd, 0x55829bc4, 0x2d70035b, 0x8a69759f, 0x3e81f5c8, 0x3cefd6cd, + 0x68267385, 0x0ffd865c, 0x3c73b2a7, 0x95a28095, 0x02bedbca, 0x81a28d63, 0x10b13f5a, 0x9578692c, 0x8ab732d7, + 0x5c36a5f3, 0x901e1714, 0x4ccc4da0, 0x9a7a5929, 0x0902f6a7, 0x298b45d1, 0xf323420f, 0xa14b3166, 0x8c1a3c2c, + 0xc7f058c0, 0xcfb935f4, 0x4219bcb0, 0x1e0aadd4, 0x87faf2dc, 0x49841557, 0x95aa7c1f, 0x7499ba8d, 0x86448963, + 0xef926bfb, 0x316d4949, 0x038718a6, 0xbf9895d3, 0x12cb96be, 0x28ae8337, 0x969e19be, 0xf0e1b2b6, 0x7975f0cf, + 0x13e838cd, 0xc83950f5, 0x450cb9a8, 0x1f57625e, 0x05969ae0, 0x5bde4336, 0x6039a58e, 0x8a4be8e0, 0x5808b77c, + 0xad6456fa, 0xd3e59827, 0x09f86c1d, 0xd55f6eb1, 0x1e28fff1, 0xaaf9596e, 0x420910e8, 0x456a8889, 0xc655ca54, + 0x944134c6, 0x69bf72b0, 0xc7cde788, 0xa734a6e6, 0xeb7431dd, 0x84a616c1, 0xad32697f, 0x84c5c1e9, 0x1618feeb, + 0x6f63c0b9, 0xb5369d5b, 0xda2d1271, 0x55c0f965, 0xac3f404b, 0x0fec246b, 0x1d3deecd, 0x2512584e, 0xd0d5227d, + 0x192d6048, 0x8b42ec49, 0xd5774c2f, 0xa93ef1d6, 0xc89de1ea, 0xc363a20b, 0xe99d81f7, 0xff4d68ea, 0xd4fe0a9b, + 0xfdca09c7, 0x28e10669, 0x1b5e2a40, 0xc1804910, 0xf1b1e6a8, 0xd9720876, 0xc41ec80d, 0x7d59f8fa, 0xd4131d5b, + 0xf3e0fefc, 0x1c75dcc8, 0xa25a0eb3, 0xba2fbfda, 0xb9d6da19, 0x02ad3470, 0x80140958, 0x482a733a, 0x482fae6a, + 0xab9dd7d1, 0xfe91f1ea, 0xbe7fb88a, 0x23fa0da4, 0x4ca673ff, 0xbae051a2, 0x58f77953, 0x29e4abcc, 0xc0e570ca, + 0x02d1e958, 0xd2e9d2df, 0x1a671701, 0x634a5510, 0xe9da5a2a, 0x544bc37c, 0xa02b90c2, 0xac78553e, 0x7457929b, + 0x4a048661, 0xd84e549c, 0x0b4e1f2b, 0xf02b21d8, 0x80b316e0, 0xe2bd18f1, 0xa850a36a, 0x374d721e, 0x02f52b97, + 0x580e70db, 0x2a4fb7d7, 0xde48121e, 0x775c9dd9, 0x0f04691a, 0xd90bd228, 0x507309bb, 0x0ce65edd, 0x9b999936, + 0xb1d7a0d3, 0x8c8b0790, 0xce0fa244, 0x2999ff08, 0x45a22cc7, 0x5485e4d9, 0xd5b18e0e, 0xacdd0a7b, 0xa74cbee2, + 0x79f2ec52, 0x02bba00e, 0x1481b40f, 0x8c88a4a0, 0xef4100f6, 0x64502f9a, 0x38a660a2, 0xb1ef32ea, 0x5d6085c3, + 0x49f2d712, 0x95272c20, 0xf7433f97, 0xac2bc7dd, 0x21915a68, 0xe951f2ba, 0xa8de22b1, 0x16fed4c6, 0x671c9665, + 0x9517a89a, 0xfddd5e93, 0x02db2813, 0x8204a9d9, 0xa57235b1, 0xc3e4cdb8, 0xebd634cb, 0xc0c1c7e4, 0x3a646fca, + 0x814d1acc, 0x7860c584, 0xed6ef544, 0x620b2778, 0x4db2700f, 0xe2b88749, 0x615c362a, 0x7392c8e2, 0xdd147a28, + 0x0a201a44, 0x79235eba, 0x86361cf0, 0x5949a2cf, 0x6c077d37, 0xea7ea10c, 0x194efa39, 0x468dbdfc, 0x3efd4bcb, + 0xf6224b9e, 0x88fb2354, 0x9768576b, 0xc97bd533, 0xe340ce5a, 0xbed996d8, 0xd3f44170, 0xb4c77bce, 0x78472c79, + 0xe6fbe9c5, 0xafab886d, 0xd9ccfa6b, 0xd8bb447a, 0xc30a39b5, 0xb6005456, 0x8470a5b0, 0x861a99b2, 0x8bd16bc9, + 0x0c744f2c, 0xf93af127, 0x46b72e10, 0x1a002b20, 0x73e28eb6, 0xcfc7f0c6, 0x2576f4c9, 0xfa6b9228, 0x18d5ed40, + 0x80a5352a, 0x72569026, 0x6c8e6678, 0x9b439640, 0xc1724d8d, 0x7e43e1f4, 0x8edfed8d, 0xc60dfd93, 0x79fca3d5, + 0xe42bac1d, 0xc07410c2, 0xde8573ea, 0x84d6f0f7, 0xde973cc0, 0x66fa5f35, 0x4f05012a, 0xfb4b3d49, 0x0477e292, + 0x21e215bb, 0x921d64a5, 0x0acde91c, 0x4a9b51a3, 0x53ba3165, 0x31e52559, 0xb05061a0, 0xacc23c9b, 0x9371d39a, + 0x4ea1b7aa, 0x549ff531, 0x3471b9cb, 0xf4689999, 0x4b5079d9, 0x74cfc1c7, 0x266e8496, 0xa6c1d6b7, 0x8a58371e, + 0x6721aa16, 0xfdeb8c9d, 0x55196aca, 0x1e178f15, 0x1eea5b70, 0xb194c5dc, 0xfee2c7f2, 0x1f785ea1, 0xf628b113, + 0x1d52c722, 0x3b53c525, 0xc39824d4, 0x30865af8, 0x10439ab7, 0x179b8bc7, 0x3b2c753e, 0xa54f96d4, 0x50b4e5bd, + 0xab34c1eb, 0x831ed07e, 0x0cd2f69a, 0x27ccbbf2, 0x58302c74, 0xc206b2bf, 0xf6b9d140, 0x31f6b413, 0x2a4b6466, + 0x9cb0ddb6, 0x143e4dd6, 0x6efa5699, 0x25c1e16e, 0x6796f6e5, 0xb09c6162, 0x4d1b6d77, 0x0d92e5d8, 0xcb362ad4, + 0xd81c936c, 0x7e95bb59, 0x1c821cb4, 0xc842f5de, 0x28dadee0, 0x8c11ee7a, 0x2f01a9f7, 0xd8d117af, 0xe9de559d, + 0xa59cb704, 0x00296ca5, 0x846f62ec, 0xc8d7a1e0, 0x1af3bf0b, 0xbde46cb1, 0x1d45d31b, 0x56267ce7, 0x0fc210eb, + 0x130a9933, 0xafa6b9f9, 0x4adc7f9e, 0x60656bd3, 0xa4c0fb4f, 0x56d5e30b, 0x66315f2e, 0x7cd8e710, 0xb81a674a, + 0xbb33818e, 0xbe312d87, 0x9647eec3, 0x9c15687c, 0x2ce715bc, 0xf5ef04b7, 0x2a27d3e7, 0x4d16237f, 0x3b9d9769, + 0x6dc271ae, 0x06514faa, 0x9ea1923e, 0x39d2937d, 0xdf786c73, 0x5d8fa819, 0x72241386, 0x6dded558, 0xe47c3870, + 0x429cf57c, 0x495470fc, 0xd9c71a0e, 0xcfd89fe3, 0x5d41d853, 0x5c6adee3, 0x758e77fe, 0x459d8b6a, 0xce1eebd1, + 0x61ef0016, 0x88cb1541, 0x617e08ec, 0x907df9eb, 0xc11ad1c8, 0x78161e21, 0x78dea517, 0x6cb60c75, 0x7545fe67, + 0x145a9e7b, 0x2f010b79, 0x6407babc, 0x27aa3d06, 0xaf809cd7, 0x2874a7a9, 0x4c06161a, 0x25a36d7c, 0xb9d01ae9, + 0xeb86a5fc, 0x44f618ba, 0xa1ea27dc, 0x6035048e, 0x609d1e4b, 0x597c0c4e, 0xa7705e46, 0x0097eaf2, 0x2bb1a472, + 0xb9e09ed8, 0xc2f9e86c, 0x4bd28950, 0x5e521a9c, 0x711f79a8, 0xe0ef089e, 0x7ad5e37d, 0xef784c56, 0x39100dfa, + 0x4fce66de, 0xb9704793, 0x623efd05, 0xabf38810, 0x1602db71, 0x24fb2d53, 0x38e8148d, 0x906ae1d4, 0x04f345cb, + 0xcdd9e006, 0xfcea52a9, 0x08fa3cfe, 0x3d43e90e, 0xec27ccbc, 0x9276d01f, 0x5ff2311b, 0x69e64636, 0x66681434, + 0x754417c8, 0x9d03f500, 0xdf521079, 0xa4d9cefe, 0x52cbaaec, 0xbee7a909, 0x4421e71f, 0xe69f6bc1, 0x2f206410, + 0x59e1ba0c, 0x19f679e5, 0xbdff3710, 0xb192000f, 0xaaaeacda, 0x5d7dbf3e, 0xd0d6b6f7, 0x6cd2a6d7, 0xb8bb1d0d, + 0x20a775e3, 0x5196aa1a, 0x5bf1b9c5, 0x47289098, 0x445e801c, 0xc93d8f0a, 0x727a0742, 0xa430a481, 0x6b90c8be, + 0x53cb35c1, 0x3b216f19, 0xd00e920e, 0xdf2ab3dd, 0x2fe14c32, 0x71ad065a, 0x3e255e90, 0xf3242873, 0x77095e36, + 0xdddb9c3d, 0x406a9df8, 0x75fd7bb3, 0x745807c8, 0x406af4d5, 0x444e996b, 0x4bb594a1, 0xa025382e, 0xa0aa8608, + 0xdcc239cc, 0x11a33ab8, 0x7e470086, 0x98dcab61, 0x99c3a34e, 0xcf7be30c, 0xd38358eb, 0x858e7267, 0xa814aa10, + 0xd0026373, 0xeea8bc8f, 0xa116155f, 0x59bb36f1, 0x3cb990be, 0xf8786196, 0xf41e0ced, 0xebc1f965, 0xdab74faf, + 0xdc089451, 0xf0d2b312, 0xf979f182, 0xf4e1aad8, 0x319ef124, 0xfce82900, 0xfa85b56e, 0x2857aa45, 0x3b607bbb, + 0xedcf4e5c, 0x74b3d763, 0x67f7abc7, 0xc879d8d2, 0x1876964f, 0x5b2a96a0, 0x48cfb304, 0xc06a2760, 0x4b9cfe09, + 0x23d2d7e0, 0xf991a61d, 0x2d3d5252, 0xdf7c260f, 0x0913205b, 0x4b1bb692, 0x2288b407, 0x3042695e, 0xf04bac61, + 0x1c13b82d, 0xb908536e, 0xf8507da0, 0x95784649, 0xda81a42d, 0x7672ab83, 0x3dfc6c3e, 0xe7a39fd5, 0xb373ec0a, + 0x2221d298, 0xe4d53de9, 0xa9f5c406, 0x452df968, 0x539e1479, 0x8c5d9682, 0x192174d1, 0x0c3a827d, 0x7bd32a17, + 0xecb5effd, 0x06516364, 0xee79feee, 0x1ed4a2f8, 0x0c2f077e, 0xed58299a, 0xb99c6b2e, 0xaff2d711, 0x6845a14c, + 0x0287310a, 0xc04339bb, 0xae413042, 0xc3e61ba9, 0xeb221f4e, 0xc02d8611, 0x2c81b1d0, 0x09dd0244, 0xecd3d3dc, + 0xf64b2871, 0x8e019fca, 0x793d90d3, 0x44fb3cd5, 0xbad177e3, 0xa25a0dec, 0x66185c7d, 0x70eb0b45, 0xc69a564b, + 0xdce217b6, 0x17bf2586, 0x6922ef6a, 0xd4bd501e, 0x4051e6c5, 0x22004b1e, 0x286ff8a1, 0x58b3e25d, 0x91c08ce6, + 0x87a3af84, 0xec37e6dd, 0x749cdc7d, 0xbbe28a99, 0x27e708de, 0xffab88b0, 0x71b0992d, 0x9b39c8d1, 0x93b30db0, + 0x3979e415, 0x802b8d0e, 0xd054b6c0, 0x71a3800d, 0x6178ab6d, 0xd2950300, 0x8e8919bb, 0x8da08546, 0x21fd4887, + 0x74cce36e, 0x44a327da, 0x8b9564cf, 0x0939d37f, 0xdaf2d652, 0xecd75d50, 0x58b51ba5, 0x8aa2f3b3, 0xa8f920a5, + 0x61b29cf1, 0x4eb487e5, 0xdf250e30, 0x6ddc7992, 0x24e282f6, 0xdf03faa7, 0x264b7bd0, 0xb9ca2f8d, 0xb9f66e6e, + 0x726186fd, 0xb599278a, 0x3cca5d88, 0x860e69f4, 0x07dea244, 0xab4622e1, 0x318e9b33, 0xfee6f5d3, 0x4e1fd614, + 0xf2ab89b9, 0x58438c76, 0xd5d81c56, 0x38922625, 0x6d5c25c0, 0xf7813091, 0xae450e66, 0x6b0bb35a, 0xa21918c7, + 0x63ef0e55, 0x7b43aa74, 0x22acd30a, 0xb4d54b6c, 0x19f1cb28, 0xd41ebd4b, 0xf4dd7edb, 0x91aa90ce, 0x8ccc09ba, + 0xd5ff90cc, 0x743ed239, 0xa692b9c8, 0x6244587f, 0xde97b4e3, 0x913fd262, 0x47a7f0dc, 0x6a070a1a, 0xcf1573c4, + 0x47227bb9, 0x9959eae5, 0x754541ec, 0xa2de8140, 0x54a2ce99, 0xaa888ae4, 0xd5b19bb3, 0x82f15ad7, 0x093471ec, + 0xe47f5b7e, 0xfa3ccefe, 0x4aa459ce, 0x3d9df756, 0x572b6a40, 0x5c0cd825, 0x96776dc9, 0xc41593d9, 0x9b7bbb2f, + 0xf89349c8, 0xeb8e3b2e, 0xa3fd77ac, 0x183daffd, 0x7f5896b5, 0x170f08bf, 0x8ed9dc7b, 0xb447020c, 0x2aabcca9, + 0x5c7be665, 0x45ff2011, 0x63625c8f, 0xacecebcb, 0x168b2477, 0x1519b17e, 0x3e9c5d6e, 0x23272379, 0xa957b027, + 0xb41d3e22, 0xb1050246, 0x86d06691, 0xf38c86bd, 0xc33a5e8c, 0x23d50c15, 0x48167d3f, 0x3675ec6e, 0x80241f27, + 0x57e828bf, 0x75835c9b, 0xb19a0e3e, 0x93b1b7e7, 0x95685cfa, 0xb5712c4d, 0xd52555f5, 0x7a3f0352, 0x6cefd18e, + 0xa9ce42bc, 0x17bc83c0, 0x0621ad25, 0x9a48a3cb, 0x752cd15b, 0x18c7ac33, 0x80e91dad, 0x42951356, 0x0dfdb850, + 0xcd65a5db, 0xfa18edb8, 0x0a6b3b85, 0x6a0cfbb0, 0xf4d81760, 0x094e502d, 0xd11dbe68, 0x8c9de5fa, 0x33d21c20, + 0x05d4e2d6, 0x2c0ca5e6, 0x205c3459, 0xd9f739ce, 0x1409c653, 0x1434656f, 0x55361403, 0x7ffb6cae, 0xf628423a, + 0x5c9fa120, 0x118170bc, 0x10a19786, 0xfccbc1ce, 0x42d32a5e, 0x9916ea5b, 0xae1febbf, 0x1ea68d8a, 0xb7feb199, + 0xa53dca3d, 0xe10b5eba, 0xbc85f4bf, 0x0cc84213, 0x01676051, 0x0ce17406, 0x63ade585, 0x4920648e, 0x0a8c6ad0, + 0x7c75cb18, 0x68eb89e7, 0x995ef9c2, 0x158b490d, 0x2b9c31db, 0xf11525f3, 0x2ea6db22, 0xddbfa24e, 0x9a6db8a9, + 0xb19dec47, 0x3b5e1833, 0x272ce6af, 0x64d40d1b, 0x6773e632, 0xd9ef7cb2, 0x6d2cef4f, 0xbe85d2b6, 0x4528d868, + 0x2e8bec59, 0xf6983653, 0x11505620, 0xd5602cb0, 0x599ba9b5, 0x943a03c3, 0x2297183c, 0x09fef7ea, 0x9af5dd6e, + 0x73176f8d, 0x8829a90e, 0x861e0b18, 0x3bde3aa8, 0xeb1ed178, 0x40bc06a3, 0xb74aaf33, 0x55bb805f, 0x2bced174, + 0x18112c10, 0xd145250c, 0x27f5bf1b, 0x13bfca3c, 0xbe78a3d9, 0x7bb2264f, 0x246f7a13, 0x1a2961c8, 0xc748b5ee, + 0x8f291ab4, 0xa8c8ae4d, 0xfcfc737b, 0x5ab55190, 0xb22d50aa, 0x3df86db1, 0x0db2c933, 0xa602012e, 0x6ce02a25, + 0x51f7b731, 0x20bc3c4a, 0x7045f6db, 0x08dbdacc, 0xf7a07315, 0xdbd3b0ea, 0x1ed8c53c, 0x8dfba1ef, 0x58516f27, + 0x7da6ae7d, 0x2a8a6472, 0xdb06f0c8, 0x797dad1f, 0x3de3a083, 0x334bb954, 0xacb365ae, 0xa064d8aa, 0x7ad32652, + 0xc7f8dfc4, 0x6548b191, 0xd3ff4a05, 0x6b925e0d, 0x651653eb, 0x7896b2b9, 0xe80788b9, 0xc20fefc2, 0x7f2eb06b, + 0x5b2f8276, 0x7aaa8188, 0xf9c2b43d, 0xac5ab4a9, 0xcb00ea0e, 0x560d9bf0, 0xf283a9fe, 0x94558266, 0xd9078265, + 0x932021ad, 0x596df354, 0x487453f5, 0x37a16f18, 0x0b8bfed5, 0x71c58a22, 0x835b30d0, 0x22b4970c, 0x4ec72b18, + 0xf3ade298, 0xeaf83e55, 0x45d10038, 0xba27e653, 0x19b2df0e, 0x9f5d42de, 0x96862d85, 0x9e89ce5a, 0x15671264, + 0xb81b316d, 0x5c54db3f, 0x3800ef79, 0x417cb962, 0x58a29661, 0x135beaa8, 0xa176238d, 0xa33b5322, 0xc67e09d9, + 0x6532da30, 0xab4cfbf1, 0xf68484f3, 0xe9afa2fa, 0xf7858a19, 0xb86faf80, 0x6f10d264, 0x5a3b416f, 0x0ed0c390, + 0x01dd895b, 0x9b1be4e7, 0x4b8a5e50, 0x51a9e42a, 0x3d933610, 0xaa2f887c, 0x0465c7cc, 0x3bf5e4e1, 0xd6c2d96c, + 0x0c0fa93a, 0x1c06aab7, 0xf6cdc795, 0x335190c3, 0x760878f7, 0xbaaa4e4c, 0x3ea76931, 0x6a92ef17, 0x15014579, + 0x20473ba1, 0xbfbf3ddc, 0xf4a5bd9e, 0xf6941b9c, 0x49e1d611, 0xcc6876a8, 0x6142368c, 0x89efc57e, 0x4b491587, + 0x64b7d33f, 0xc650100c, 0x974d462a, 0x38a16f21, 0xcbb3fa5d, 0x41b3bfc0, 0x9084c59e, 0x4d85cb76, 0x43c5590e, + 0xd210465b, 0xee8ea61c, 0x8a9797f0, 0x9cae6095, 0x957d3d41, 0x7427bfd3, 0x0126b864, 0x992a4b16, 0x6b5ab5d2, + 0x0cd157de, 0xa0206143, 0x6b32b6ce, 0x7ad73902, 0x3137e541, 0xb8422d58, 0x7ebb4bc0, 0xbb23edd1, 0x07e68321, + 0x86ea19f3, 0xca39f2cd, 0x85d2d5e1, 0x307f99b7, 0x8a4df4d8, 0x10d1d684, 0x7d129a73, 0x17f3e99c, 0x13397566, + 0x4ee5e62b, 0xb3a46b9f, 0x0dcd0497, 0x1bc5c816, 0xe104cb33, 0x03c58642, 0x62a0b4b3, 0x8addf579, 0x062bdcdd, + 0xab152409, 0xc72c21e0, 0x7d7f0833, 0xc4ba2550, 0xbe4dccbd, 0xb4ed34c7, 0x8d9e4074, 0xe7440bd2, 0x8cba0795, + 0x77a128c5, 0xe9579721, 0x082f59ac, 0xe76e12a1, 0xea84c4f2, 0x0924046e, 0x1223e2cd, 0x203a9397, 0x0fdf07b4, + 0x3e859ee2, 0xb757952d, 0xca106535, 0x0d7c31f1, 0x83a35469, 0xde0b208b, 0x84f4ab2b, 0x46ba1537, 0xd8d6c417, + 0x04fbff92, 0xdc4b2ef7, 0x10cfeeb8, 0x801a48f8, 0xed097914, 0x16479c5a, 0xf4547770, 0x5ce3a568, 0x7425694f, + 0x3a221f32, 0xb479232f, 0xd5bc9102, 0x1beed2f0, 0xd377e5f1, 0x7b34c03e, 0x8e46e84a, 0x4a76c77e, 0xfd3a22d1, + 0xa89058c0, 0xcc82d48e, 0xd757df06, 0x685adabf, 0xca14c4d1, 0x75d8871c, 0xd3d68795, 0x4bb10b88, 0xab681918, + 0x3ff1183d, 0xcd44c2d9, 0x5ac6294d, 0x2679844a, 0x6420c7fa, 0x70c4026c, 0xa2c29ea1, 0xe0e7f5ee, 0x6206d483, + 0x97ff38d9, 0x1f0f8b38, 0x1088671a, 0x23d30e27, 0x5dc65efd, 0x07818c91, 0xeee843e2, 0x458ba89f, 0xc9680ddd, + 0x7f904b6e, 0xc74bfe27, 0x0d91ef24, 0xe5ce4621, 0x6f87130e, 0x4e1452ac, 0xc880236d, 0xfe6f6038, 0x5b8d7e7c, + 0xd480a335, 0x86fde88d, 0xebfb165f, 0x87fa46f7, 0xcc3e6fec, 0x79a15dd2, 0xd28bb125, 0xafc4dc61, 0x65d3d17e, + 0x43d414f0, 0xae0938ea, 0xd4beafff, 0xe40cc09f, 0x549cb166, 0x46fd1634, 0x1172f76e, 0x903e549e, 0xbd923970, + 0x7e126c4a, 0x161aec44, 0xa51128bd, 0x65ce78c8, 0xacef97fd, 0xd34c25f4, 0x1c2c1b1f, 0x5ac06ddc, 0x033928f6, + 0x86a23125, 0x7353a045, 0x014df84c, 0xbe8b2781, 0xfd440966, 0x41009ec2, 0x06e8eb15, 0x94ce49ec, 0x362367b3, + 0xcd637e5f, 0xdf28f8ba, 0x24eec01b, 0x66cfbfcf, 0x59b1c015, 0xa8518a73, 0x61eea412, 0xa62a75fc, 0xf8a98e47, + 0x14127cd0, 0xa7b4b00d, 0x9d035a5d, 0xa71ac2c6, 0x6fba87e0, 0x122d470e, 0x1f725fc6, 0x14815c86, 0x2279e028, + 0x45f14f0a, 0xe1e172d2, 0xbaf07c29, 0x55bbd838, 0xab6ca0bc, 0x20b74cf9, 0xf7125a79, 0x1a2a9c75, 0x17e584bc, + 0x7b5d1e09, 0x834af85b, 0x4f32e1c9, 0xe612f1c1, 0x247a859f, 0x393661cb, 0x402e9c58, 0x0f90d692, 0xa7bb6b04, + 0x41f6e88e, 0x24335cbe, 0x20964b29, 0x4f0fcd96, 0xd388af78, 0xc247aa20, 0x5fd83ab5, 0x1b103e54, 0xeeb9cb91, + 0xaf028643, 0xea078f3a, 0x4dc3e56c, 0x836eb7e8, 0x845f8f1b, 0x55c51669, 0x8a281e99, 0x4b5a868d, 0xc476940d, + 0x0790b43b, 0x0a26b1d4, 0xab28ced7, 0xd06b5a71, 0x924acc78, 0x88954796, 0x2290f876, 0x9bac321d, 0x112af9ff, + 0xaeb76016, 0xcd65062b, 0x4d0c1bc4, 0x95788649, 0x4cd5d34f, 0x996cbf8d, 0x67737f61, 0xdb3b4803, 0x6bdf5464, + 0x75c08c50, 0x16bd924c, 0x86da57a8, 0xdf8f5db6, 0xa3c7a28e, 0x8ab2d267, 0x87b5b7b2, 0xffffa3d8, 0x0140d1b2, + 0x08734135, 0xe9ea2610, 0x655b6aed, 0x44affe03, 0xebcd85d8, 0xf495bc51, 0x6232f9e8, 0x9ce674e9, 0x6d62bed4, + 0x6922b0d5, 0xee5289ee, 0xfcacdd98, 0x72d85cf5, 0xa7c31b58, 0x2ffd4a16, 0x7890dbb1, 0x51f1df81, 0xe9ec5a81, + 0x4b2e9df5, 0x9eede5d2, 0xb8e6abd6, 0x8f68b2fd, 0xa4463b1a, 0xf079189c, 0x8fac4b86, 0xadaced93, 0x015b9a83, + 0xfd890a3f, 0x8136c330, 0x67f80227, 0x35e532e6, 0xc08fc5be, 0x3207d3ac, 0x85417c9a, 0x267e7371, 0x67e98cd0, + 0x81479ae0, 0x9caae138, 0xdb059ec8, 0x17a582c2, 0x832c5e94, 0x02f9ae13, 0x10a0f3ff, 0xab772542, 0x0e18fd86, + 0x489660f2, 0x4339af45, 0x0d63c53e, 0x6a98246b, 0xe671a95e, 0x6039adfa, 0xbc1217b9, 0xcf569291, 0x73f530ee, + 0xcf6e8b26, 0x81074d20, 0x80f7dd13, 0xdeb3deba, 0xf1b2141a, 0xc55684c8, 0xc3fdf887, 0xf272c98e, 0x9959afd2, + 0x930f9fee, 0x3978f6cf, 0xdd43e6bd, 0x8c2fe62e, 0x897b824a, 0x178b15fa, 0x0aed7b86, 0x2dc1b691, 0xdf6bb0c6, + 0x4f786bbb, 0x35e8464d, 0x8ba6865e, 0x29a2e5e2, 0x42932a62, 0xb84e598d, 0xcf415e48, 0x51a288c2, 0xf02b7d66, + 0x4eb0d505, 0xc8192f7e, 0x935b2bc8, 0x4eb5c69a, 0xef412005, 0x71e581f8, 0xa11f3de0, 0x8c22bb83, 0x3bde3d7b, + 0x828d06a1, 0x8956f048, 0x5de51a20, 0x5aeabf4f, 0xc706331c, 0x475c7e64, 0x68167324, 0x30e34900, 0x088336cf, + 0xa3ffd361, 0x96f1e611, 0x89885410, 0x65fc27ca, 0x82ea23dd, 0x5fc08061, 0x7aadb9ad, 0x0df28f9c, 0x61218c7f, + 0x79465f89, 0x1503e181, 0x29538c52, 0xa3f5103b, 0x9542394a, 0x0299e5cb, 0xbfed79df, 0xf3926b01, 0x6e829879, + 0xc8ce8d23, 0x6436f8d7, 0xd5b22031, 0x793a3059, 0x74df073a, 0x48547246, 0x05b368a5, 0x0d693c62, 0x51edbeb0, + 0x5f106968, 0xdb01c977, 0xa700b612, 0xd3bf5cf5, 0x0932a203, 0xb5a5afa1, 0x9b4fd0b5, 0xee295c61, 0x6cfb0866, + 0xfbeac2de, 0x1ec51946, 0xe0a23c31, 0x671264ad, 0x3e008665, 0xc4e3e845, 0xc3f1e57c, 0x7b143f48, 0xebe66dca, + 0xd0f77d3b, 0xe1a2421a, 0x2504cb4b, 0xe53cbd7a, 0x5388a824, 0x9e08cfb6, 0x5cd8cc3e, 0x84cab207, 0xe9668e4f, + 0x6df75e5f, 0xd164886c, 0x42ae6566, 0x560e4236, 0x88400616, 0xeeaa56f5, 0x6a9c2ae6, 0x7ed2820d, 0x07dc7eef, + 0x53a8cca4, 0x5e511662, 0x82a636a5, 0x953508df, 0x6f648b54, 0x96afa7e6, 0xcc619166, 0x8dff8cd6, 0x029b372b, + 0x485504d1, 0x429a665f, 0xf5cc0f85, 0xec4d271a, 0xf999b85c, 0xd0feca34, 0xe14b9d64, 0xabd568b2, 0xc2e9cb89, + 0x158814eb, 0xd3213252, 0x5240f2d5, 0x15243ce7, 0x7e9aa9c6, 0x5e2947d4, 0x9b35605e, 0x0612ba83, 0x2bc0101a, + 0x09afda53, 0x247f0b30, 0x17e3f301, 0x3abbbd20, 0x798d6edf, 0x8cf9c834, 0x74ad3f18, 0x5859c356, 0xa1fd3118, + 0x9c7d74ec, 0xcbd45246, 0x6a8246a7, 0x380b7604, 0x42375402, 0xbd23ad4e, 0x908e40bf, 0x60e563a6, 0x6ea4cc39, + 0x0d66be92, 0x62cf9aa6, 0x5d85be77, 0x992407e6, 0x5dd70165, 0x3fda2bd9, 0x525f4ba7, 0x7fc9fac7, 0xeb5d0291, + 0xa8538ac6, 0xfdb63d2f, 0x0a088915, 0x82fc31a8, 0x907952fa, 0x3eb8410b, 0x9d2d8aae, 0x97435c46, 0xbbfe309a, + 0x475f05ba, 0x00341227, 0xa0094658, 0x6d1ca2a0, 0x53be657f, 0xf2c47854, 0x2fdc39e6, 0xbd10cd79, 0xd5583abf, + 0xcc12ddba, 0x826b6ee8, 0xcc11a8a1, 0xc6735043, 0x70f3699b, 0x76311dbe, 0xcbd6ae8e, 0x188dda47, 0x7217ac81, + 0xa455cc5c, 0x09ab4c04, 0xf691dc22, 0x5021e76d, 0xa0372aea, 0x5cd072a2, 0xc02245c7, 0x7bfb9ff4, 0xa1b10968, + 0x0ca3e5a6, 0xbb3d2359, 0x0abd6c95, 0x3765e418, 0x1139498b, 0x10229627, 0x1f14c29b, 0x327499c1, 0xd0c3854c, + 0x12d34578, 0xdeafd16b, 0xfb5cc6a7, 0x8cdc31c5, 0x479dd44e, 0x4cace836, 0x54537eef, 0xa78251ab, 0x1cda51fa, + 0x28a7745c, 0x9b393ffe, 0x00e7b465, 0x5b402b0f, 0x1516c47c, 0x5ea92fbd, 0x7c6be082, 0xf5f7cbe2, 0xe53c9847, + 0x57e9b659, 0x89e9e644, 0x3ee36c7a, 0xe6babd3e, 0xd9b372b7, 0x214c4648, 0x0df1f21a, 0xd163e2d2, 0x750c5ef9, + 0x631438a8, 0x2fc0f4bd, 0x7ebf5b77, 0x735ab150, 0x016de2fc, 0x29891191, 0xc597d17e, 0x62663fab, 0x30736cbb, + 0xf5200dd3, 0x2f7f749e, 0x56fdab58, 0x14ae80e5, 0xf29656cd, 0xc8311b29, 0x80dba3fc, 0x33e105a7, 0xf965399b, + 0xff903a06, 0xb6e58741, 0x70c02f7a, 0x2bcd1954, 0xb525643c, 0x2e3ac43a, 0x8b0f9f70, 0xef3878b1, 0x19bbd95c, + 0x61a3b73a, 0xa7a14802, 0x2bb5c688, 0x8a6b5284, 0x7743ae74, 0xcbf6630e, 0x65fc894a, 0x2990c681, 0xbacfbd97, + 0x70aaaaa1, 0xbebf02c1, 0x72ddfdae, 0x0be371f8, 0x9aa01ab8, 0x6eec039e, 0xf6b7817c, 0x02062edb, 0x33ed0e02, + 0xfcceb222, 0x7a5aaeae, 0x71c59db8, 0x65dbcf3f, 0x5f4a8db3, 0x762ddf69, 0x60dd0267, 0xccdff131, 0xbb3d7eb7, + 0xdeb41690, 0x13f027e0, 0x0945bee7, 0xf12a9046, 0xe850e439, 0x17ff48a3, 0x8fcdde0e, 0x0bacf0ce, 0x010c62ca, + 0x7200037a, 0xa82d0206, 0x66fc64cc, 0x39d84e80, 0x97725f10, 0x018f482e, 0x38a4b7b1, 0xdbedd300, 0x741a4d10, + 0xf1a083b8, 0xa0a766b3, 0xe5934776, 0x3d5bac5f, 0x9167169c, 0x9987dca0, 0x1c13e7e6, 0x6109a3c5, 0x9e48b66e, + 0xbd05e6c7, 0xae7f992f, 0xbe055723, 0x61a246e9, 0x0a1c96b0, 0xbf41c3e7, 0x452afc11, 0x67e7efad, 0x821f5145, + 0xf1933c64, 0x1ec03d17, 0x6df37952, 0xc39d3fa7, 0x1f027b29, 0x52d19e43, 0xc91aba18, 0x17526d10, 0xbaa3e1c1, + 0x7fa17443, 0x308eb9e5, 0x99050173, 0x555e4368, 0x2721bf5e, 0x73acb09b, 0x47543cd0, 0x2baf0622, 0xb4e89584, + 0xa2dbded2, 0xa209842a, 0x61cfdaad, 0x4c788700, 0x5721146c, 0xd97eaa16, 0xa3306d2e, 0xe4569a46, 0x1939848e, + 0xe52d01cb, 0x25c822d8, 0xcd03447e, 0x1cf612da, 0x4d83a547, 0xa51ed955, 0x2c892db3, 0x27b62383, 0xb37247c1, + 0xe0928d38, 0x716efa63, 0x8d4477b2, 0xd003b3aa, 0xc973eb90, 0x61fb1345, 0x488f8514, 0xa1c602cb, 0x06c9419d, + 0x887ef9cf, 0x8b57ef89, 0xbf21e735, 0xe149700b, 0x5be92b9d, 0x890f45b3, 0x929850df, 0x55f085b3, 0x3e72a472, + 0xed464e00, 0x4f3b97f4, 0x24811340, 0x78301094, 0x4952fbf4, 0x4f0dccda, 0xbdedd1e4, 0xa97f53be, 0x78871276, + 0x4f88fc8b, 0x41916802, 0x2ec3d0ba, 0xb93cc3d1, 0xab2ede0a, 0x50e27458, 0x494c76b5, 0x09fc1d2d, 0xf1c07061, + 0x50d33ec3, 0x1bbc132b, 0x0dc99ff4, 0xafd3b8bd, 0xdd5b2c91, 0xd5d11961, 0x08ab6225, 0x17b4ef4a, 0x56092dfa, + 0xfda17afe, 0x57337d14, 0xad531619, 0x4966c6b7, 0xc01fe3db, 0x713d89d8, 0xc87eee48, 0x07010a94, 0x98555808, + 0x92ff3126, 0x175ddcc7, 0xc1476ca4, 0xd01ba353, 0xfb516c94, 0x21704672, 0x4c0692d5, 0x94e2c206, 0x6220fedc, + 0x646ff213, 0x66576f94, 0xa93efd39, 0x3a0fe3de, 0x9b47bc0f, 0xa7da3e00, 0x65bdf50c, 0x7c1a932b, 0x2babdb61, + 0x1113272d, 0x4f6f9007, 0xcf6c8eae, 0x3d0ed56e, 0x16e90e88, 0x509c5d21, 0xf097d3e9, 0x01ec1a85, 0xf90b93f3, + 0x65748611, 0x806a9536, 0xd772bc4f, 0x6c98d14d, 0x5af1a683, 0x31aa9194, 0xc6bcb148, 0x032dcc00, 0xc641dfb1, + 0xb4f236b0, 0xdc1a9d4e, 0xbe185fa2, 0x4d15890d, 0xb4b77a49, 0x8eeaef5d, 0xe3fda329, 0xa5b9636a, 0x0ad2b95d, + 0x705dd20a, 0x1cc32bd1, 0xf7c40a4f, 0x94b1d376, 0x21ee7c4b, 0xd87c3369, 0xb6112b92, 0x939c87bc, 0xdae4cce9, + 0x336554dd, 0x9c67f332, 0x1fb9c5c5, 0xb8c0e069, 0xbb16809e, 0xabcfeffa, 0x8513e215, 0xef6c0001, 0x72f4a2d6, + 0xe0aef618, 0x5b0df215, 0x47ba9059, 0x893bdd22, 0x3ae3344e, 0x97a45c83, 0xbd959ef1, 0xe31bbc51, 0x5e40eee2, + 0x9ae7a8f6, 0xa893a091, 0xaa37fdab, 0x39b59285, 0xe3fe91aa, 0xbe90c435, 0x109eac7f, 0xbcde0ce1, 0xcd8ff7e2, + 0x83b381ed, 0x64c82bac, 0x6d4c79cb, 0x88812193, 0x15530bb6, 0xf8219e4e, 0xad962323, 0xb4d872ca, 0x57ba7c63, + 0x81783b22, 0x9f27e08e, 0xe8d8d7bb, 0x92845ea2, 0xa20df19d, 0xac2c5d65, 0x6b4855cd, 0xe9d7c561, 0x4a0befb9, + 0x8bc36cf5, 0xfe9486fb, 0xd8dd6fe4, 0x532ffd51, 0x2e608e95, 0x67ba20da, 0x99e05f14, 0x3f9e0ef4, 0xa4e62480, + 0x6a1d2004, 0x58375627, 0x12b9abbc, 0xaa539e23, 0x03194d8d, 0x3d2196d6, 0xc8b1381c, 0x1cdea34d, 0x932f439a, + 0x4db0d203, 0x575f37a9, 0xb681486c, 0x8110b078, 0x4ddc0658, 0xce26ad17, 0x5f27247a, 0x6f383844, 0xddc5bce5, + 0xafaf8120, 0xb61ed985, 0xc1655946, 0x5f69c2bf, 0x7627c26a, 0x9bcaa855, 0x92e81484, 0xd3aff4d4, 0xa10159a6, + 0x017f5588, 0x8176fd8a, 0x889ea6d2, 0x0ea3ef09, 0xd7fee4b6, 0x8a38a356, 0x7592d4a9, 0xb46bf5c0, 0xfc7dc9c5, + 0xc395e46f, 0x212ad04c, 0x10339d30, 0xb75145ba, 0x5b2682db, 0x668fa32b, 0x9437f50e, 0x27b3c0ca, 0x7ee87770, + 0x93276f21, 0x035a19d5, 0x41d2e0ca, 0xb5244103, 0x1a46cbed, 0x8d10f5a4, 0x3143f176, 0x94225fed, 0x56d645ce, + 0x39fa90f6, 0xc81f8b4b, 0xacd504f2, 0xcfb79a75, 0x2a544b04, 0x7107e2a3, 0x4addea45, 0x3ec55114, 0x73fd8b97, + 0x59ab2230, 0x98dafb38, 0xf09e7070, 0xf8fbd621, 0xfef040e3, 0xdbba91b0, 0x14d8a2b1, 0x121d4319, 0x3b571eb1, + 0x03b6a66a, 0x1009044c, 0xd5e96e46, 0x7b3803d8, 0x942811ce, 0xc2b7704c, 0x2f70403f, 0xc55d9483, 0xd5ae795e, + 0x00601111, 0x5148fc2f, 0x1a5f0c13, 0x208bd4d0, 0xae6784d4, 0x27a71bb0, 0x8f2cc772, 0x58f4ddf7, 0xd116e789, + 0x23140862, 0xdf0cc9dd, 0x24a01ca1, 0xdd94f54f, 0xc01591bb, 0xb3f4283b, 0xc81e2feb, 0x48280679, 0x7b91a2d1, + 0xa73a8fa2, 0x12f34bd4, 0xdd43e60b, 0x00761d4a, 0x0fa69647, 0xd3f20d6f, 0xf7ae22fe, 0x0e9592d6, 0x6d14da9d, + 0xaa1848ca, 0x70846d77, 0x68df1d8e, 0x9360fe34, 0xcd91af10, 0xfde00c76, 0xd5decea0, 0x26b54ad4, 0x6433edc1, + 0x97f8c38a, 0x4b52555b, 0xb8bc407b, 0xf1a173b8, 0x137b11ba, 0x3f7868fc, 0xe00990f4, 0xc697cfb8, 0x8bae0457, + 0xe00cbd80, 0x284a3250, 0x9a1b7a8f, 0x445b6ca9, 0x69bab65f, 0x6804218c, 0xcbbf86b2, 0xd6298f74, 0x4dad880e, + 0x45aea576, 0x4f42c743, 0x87b9f0ef, 0x6fe3d168, 0x6a231fe0, 0x7e4d6ba6, 0x5642db82, 0xe443f3e7, 0x01e80bf9, + 0x73e79ec0, 0x6bcc19ad, 0xd7329cf8, 0x87885834, 0xaea4aec5, 0xd34c4e60, 0xe1057ca1, 0xedbd12a0, 0x7080bb48, + 0x06b3879f, 0x4240aa49, 0x09e83beb, 0xf0bfadb2, 0x54c9dad5, 0xe705a4d4, 0xd97327a2, 0xb015052a, 0x9bf91b72, + 0x8738eec3, 0x94a01ce1, 0xf9c5dffc, 0x8cb12611, 0xfcbe029a, 0x387f1b9c, 0x5620c1b1, 0xe1d3882f, 0x5f4d2f2f, + 0xe127c950, 0x4d7a516b, 0x2d1e43da, 0x89eb0a82, 0xae7dd76e, 0x647c445e, 0x49d89894, 0xee9246fe, 0x4b997fb9, + 0x95bb6a1c, 0xf306ce0f, 0x5c6abe82, 0xcdd2b61e, 0x48ad4b38, 0x52490e02, 0x8b7886b8, 0x572c9f96, 0x1a8cddd8, + 0x3709425c, 0x9cab90ef, 0x92de3b48, 0xbad52978, 0x6bde83ac, 0x26d5d32c, 0xdcec1363, 0x64382344, 0xb47517cc, + 0x15d66aca, 0x21e1b22a, 0x73539dc8, 0xbabfd012, 0xca719b99, 0x1aacad35, 0x7e109521, 0x755c6d2b, 0x26d66ad9, + 0x66674a43, 0xe960d4ab, 0x85e03edf, 0xbb2667d3, 0xcd4e0758, 0x9338d42b, 0xbd8c75e6, 0x1e106a87, 0xe645f7a0, + 0x27dd707e, 0x6ffcf34f, 0xeb2d8515, 0xafcc9443, 0x331def57, 0x4b2a2f4a, 0x47ffc698, 0x9a78a47e, 0x56077e0a, + 0xcb7236dc, 0x8b8fc712, 0x1a093a94, 0x0b835ad2, 0x99017916, 0x79ffe0bf, 0x0555ace9, 0xbe43a170, 0x83ef2838, + 0x8a6a8bb4, 0x30e7cefe, 0xea1a7f47, 0xd51c9d42, 0x22ae65c9, 0x923fa415, 0x00b49d77, 0xdbf8c7a3, 0x9d739dd4, + 0x675bc7b6, 0xe3e5cc78, 0x551c9fda, 0xf2e12b50, 0x5b1afe9d, 0x80955b49, 0x2965b366, 0x023358c8, 0xa6305c7e, + 0x97d3b2d7, 0x8a1be91f, 0x3e07cd63, 0xa84d4c62, 0x62f6965f, 0x3ef5f484, 0x24109b54, 0x5d27334f, 0x736748ea, + 0xefc91b48, 0x8beff8f2, 0x78a63a90, 0xf50b291f, 0x996727d9, 0xd13c104e, 0x646c5e4d, 0x812e4aa3, 0xf77f31ec, + 0xb6ae0617, 0x7560b0ea, 0x9377de52, 0xed3e6020, 0x8d2922b6, 0x13bfccc1, 0xde3aba79, 0x185a3ebe, 0xebcfdeda, + 0x7e35bf89, 0x6cfc628d, 0x6312efb8, 0xd3aa2775, 0xc468317c, 0x9ab9f704, 0xa60d804c, 0x176bfc14, 0x2c12f661, + 0x9a52dfbe, 0xba106d5a, 0xae2f4b55, 0xe3fdbc42, 0x5a162b6d, 0x4e3fd443, 0x621df5f2, 0xf3913dc5, 0x57586fb5, + 0x47816954, 0xaaafefc6, 0x3c76cc2c, 0x470cde53, 0xca6d3627, 0x3942eece, 0xeef5399f, 0x8158bdb8, 0x5df5a4e3, + 0xd23ca24e, 0x41ddb19c, 0xe8f243d7, 0x26e9f27c, 0x0a0751e0, 0xd7541b16, 0xfe2b24c0, 0x9f48f9f9, 0x57fb7d49, + 0x4ac0c67e, 0x298ef4de, 0xdb32ea9f, 0x79edbd5b, 0xf9f90213, 0x0181b32c, 0xfdd90e58, 0xcf258ba0, 0x28b11417, + 0x45b4e3fd, 0x56b98098, 0xb77c3002, 0x797c5781, 0x15097443, 0x0c7b0f4e, 0x192e7ae2, 0x4bc86bce, 0xca15ea19, + 0x59f87466, 0xabe344ce, 0xee3dd193, 0x4f6cf200, 0xee09948f, 0xf2fb01dd, 0xf1542835, 0x38355a42, 0x0e1571ec, + 0xdadf0946, 0x745b0d71, 0xd9ba99b4, 0x46ed5b62, 0x9cf45dc7, 0x98daa019, 0x6ac4a878, 0xd6d9912b, 0x7ae7f3ee, + 0x706a7304, 0xd5ed0326, 0x5cacc404, 0xd24dcfbe, 0x6c6d134d, 0x36101f4f, 0x2e595047, 0x767bb073, 0x4a7f996e, + 0x151339b0, 0xc1946015, 0x23c59887, 0x2754cda1, 0xe5b0d707, 0x4f1b6efa, 0x3c1d602d, 0x1e6db5a1, 0x28c7eaef, + 0xcb054a87, 0x4664502b, 0xed3c7e5d, 0x7b2a346e, 0x26f8d38c, 0x131c280a, 0x423983dc, 0x985e98f8, 0x2b767239, + 0x1e3b7aa0, 0x698e0dbd, 0xb94fa5fb, 0x7cc54a86, 0xa45f3688, 0x5ca1f2e6, 0x594265f9, 0xe92dba42, 0xadd146ba, + 0x95351d89, 0x730bc14f, 0xf517652c, 0x56bdeec3, 0x24def6c9, 0x415f39ce, 0xe08f9be8, 0x345aeba3, 0x03453048, + 0xfc4076a7, 0x90c4d082, 0x84671077, 0x2f057077, 0xf6309926, 0x79ae07ac, 0xbab588b3, 0x67aa2b55, 0x60935d1c, + 0xc48679ab, 0x453d4332, 0x573ae9c8, 0xf6cdd009, 0x4e1768e5, 0xbefd35f9, 0x1458f7eb, 0x7f95b52a, 0xb6bd2542, + 0xffbbf9b2, 0x5b4489e1, 0x80c10682, 0xf19b83af, 0x1577a6a6, 0x62b6350f, 0x0888a327, 0x746f466d, 0x48c3f9b2, + 0x713a6236, 0x9cf0ede5, 0xfe042b5a, 0x36ac8100, 0x5b10d27b, 0xda7e5fc8, 0x50716177, 0x4d786a45, 0xda04fad7, + 0x60e1bb67, 0x1bcc7b4d, 0xa88a250e, 0x4bc59d26, 0x10465953, 0xf2de75e0, 0x09bab12b, 0xe46ba4bf, 0x7d1c1251, + 0x8837a644, 0x4ebbca2b, 0x4150644c, 0x056e99d5, 0x574581ec, 0x8378204b, 0x707f73e5, 0x90bbb683, 0x1ea7098a, + 0xa547d394, 0x2008fb15, 0x07171b22, 0xc3a869b0, 0x3ce7b8fc, 0x85b29d54, 0xd4b3251e, 0xce5cfbbc, 0x21159202, + 0x8778f4a2, 0xb9e3e344, 0xaf580f48, 0x07e4cc12, 0x0bebdc89, 0x51617e0f, 0x7ea5b421, 0xfd682046, 0x32d8195b, + 0x15c77785, 0x0d2f38ab, 0x2839041f, 0xa36e668e, 0xde3288f8, 0x19a91bf7, 0xba0d0bfc, 0x07956c57, 0xfcdf688a, + 0xc2e2cf42, 0x276fb749, 0x5557c7ee, 0xc334cef6, 0x233681fd, 0xa25f1070, 0x72c79b24, 0x4dc2dbe7, 0x4ee14cf8, + 0x36d47e84, 0xdb08d0e7, 0xd906d115, 0xbabfeb17, 0xa8c9a818, 0xf46ba61e, 0x58e75035, 0x6d6c3db0, 0x566da59b, + 0xa70bccac, 0x469c1ab6, 0x7cedbfbb, 0x81d32f9d, 0x25a0326d, 0x8c9ad74a, 0x6edf1b43, 0x591280f7, 0xaca49000, + 0x77e267c7, 0xbe13046b, 0xd71bce5d, 0x112efb1b, 0x27108546, 0x206f6721, 0xc3bd7f7d, 0xff0acfad, 0xd1f924d0, + 0x522c8f42, 0xfb1a86c5, 0xac283258, 0x0f599d81, 0xd957ef8b, 0x905b3555, 0x00f0e26b, 0xad305589, 0x4c6e0158, + 0x0a577f82, 0xd15ce729, 0x9f88158d, 0xfae91864, 0x560dcd7e, 0xe1b6ab18, 0x920f089a, 0x85ae1058, 0x152c74bd, + 0x02d2cbf6, 0xc7f81866, 0xd2b23edb, 0x612b8b2a, 0x1f8da01f, 0x88499357, 0x709e6bbd, 0xcac36b84, 0xe636d2ec, + 0x65e32ec7, 0x731e4286, 0x2d6474a3, 0x840dc51c, 0x7af67d39, 0xefff8ec7, 0xff72d1ff, 0xaa7130aa, 0x6c479116, + 0x9bb6ae01, 0x93d5a376, 0xc11eabed, 0xcd3d93f6, 0xaa7b22e6, 0xabb360c6, 0x6d77ba06, 0xf7815990, 0xb2a75bd6, + 0x477c5291, 0x72d2d187, 0x835bb6c7, 0xeb2ffa69, 0x94942217, 0x6b4f8b87, 0x9be4b37c, 0x5b1bbdf5, 0x83612149, + 0x09cf83e6, 0x8d4f5bf7, 0x3a561148, 0x32ee851d, 0x9b6b9a56, 0xc8f57b81, 0x9ab3c56c, 0x811d0cfa, 0x103ecfff, + 0x517c810c, 0x6159725f, 0x2366f7b6, 0xbb13df03, 0x1823c5bf, 0x90923ad9, 0x46d75f4e, 0x5f669dda, 0x74122b5b, + 0x194321a7, 0x7fc19d40, 0x305ea7a0, 0xc28451ad, 0x8fbee929, 0x90e65744, 0x6bb713a2, 0xcfc15232, 0x16f0edc5, + 0x51c8c353, 0x12d3c12c, 0x73b39680, 0xb007abd3, 0x191727fc, 0xb5267c74, 0xd3c57bab, 0x5d9bc440, 0x366be7cc, + 0x372b520c, 0x676b1569, 0x90c35643, 0xe7741fa0, 0x28f1aa22, 0x1f7f8491, 0x398d5e6e, 0x6e3713f5, 0x3ba69a24, + 0x65a2f878, 0xa5cd6498, 0x9a551dee, 0x50125a15, 0x864bdec2, 0xb9093618, 0x1b5ff202, 0xe1db4a4a, 0x62dc9e77, + 0x0a5e70c6, 0xc9551170, 0xe66dc94c, 0x7a6bb30c, 0x37400bbb, 0x0d948dd4, 0xcf723443, 0x6716b61d, 0x98cdadf9, + 0x389f587f, 0x19ab0801, 0x0c30ff9e, 0x83dab158, 0x82f357e1, 0xbfb49314, 0xcbb13899, 0x0807bc20, 0x1bd6166d, + 0xf8a0d162, 0x4f807d26, 0x81cd1ff8, 0xe39cc9dc, 0xa382f6e7, 0x02c1599d, 0xe1290982, 0x71172491, 0x6d1672ad, + 0xf474935b, 0x5259d927, 0x0ad6444e, 0x657bde53, 0x8877a7ec, 0x1e3ba895, 0xef5f5c3c, 0xcbdc83a0, 0x752f259c, + 0xe8be06e3, 0x5fb6ebeb, 0xf2c47292, 0x4f1ec815, 0xd9b12361, 0xa3a6fbb5, 0xa3ad9efd, 0xc65fe7ef, 0x6ca20b11, + 0xaeb89170, 0x15a5a449, 0xb216eaec, 0xbac14c44, 0x788e7cb4, 0xbe1205e9, 0xb41e02f9, 0x550d3208, 0x7357a0f3, + 0x0b3bd201, 0x0767fd32, 0x31139e31, 0x5fe7f17e, 0xef42cd21, 0x3c5368ea, 0x6fdca428, 0x4eda0ffd, 0x2d36f5db, + 0xa36b0529, 0x0011f7d1, 0xfcd64dce, 0x0e3bb453, 0xee181fb1, 0xf1bfe4e5, 0x65f93cd7, 0x8aa931ee, 0x08164212, + 0x5000d710, 0xdc841307, 0xddce9b7d, 0x4f2812c9, 0x3cdfd9d8, 0x44aa11fd, 0xf29b6870, 0xd0e85315, 0x73c0733e, + 0xc893a2c2, 0xf0330a16, 0x974af045, 0x91b7fc87, 0x002a05a4, 0x709dadce, 0x4a29da2f, 0x92d959ce, 0xf72ef1a4, + 0x549a5668, 0x331d2310, 0xe180cb81, 0x3a1c912b, 0x13fb40d0, 0x01b8f392, 0xef236eb8, 0x9b973128, 0x8de6c122, + 0x8ae5a02f, 0xce1afb92, 0x00852280, 0x9b545943, 0x1460447e, 0x1c7611e2, 0xcb1894b7, 0x019260da, 0x1ad2a197, + 0x9280c62e, 0x0e742f18, 0xef7ded66, 0x43fe131b, 0x1e98ee44, 0xc8f28dfc, 0x1136d276, 0x463122b5, 0x2b109aae, + 0x7ac9e817, 0xb3e716f9, 0xc2cf74b3, 0xdb845f0f, 0x8336ee02, 0x024ba526, 0x81cc78b0, 0x43b15e94, 0xd14cf28a, + 0x63ca453c, 0x82b8afd9, 0x42b89753, 0x67589bd7, 0xee7b49a5, 0x174aecb1, 0x989ada55, 0xe881951d, 0xa143ddd7, + 0xf4450bbf, 0x982735ea, 0x4d00a7cc, 0x4c46d2db, 0x37442cea, 0xd1e145d8, 0x80212b14, 0x25f197e3, 0x337b9eb3, + 0xf728d5a6, 0xf0cdb9a0, 0x690934f6, 0x24236947, 0x7c6527ef, 0xcee697b7, 0x2c9bd26e, 0x830c799e, 0x66e7883a, + 0xa22125aa, 0xcf9d3019, 0x29e4cc9a, 0xf2e7064d, 0x431eb213, 0xf8aa1fd5, 0xbf2b8d21, 0xe70c14ca, 0x3a132138, + 0x36ad856b, 0xe3a6cfd1, 0xe2265875, 0xfbb6ff1d, 0xd42c43ef, 0xa91f703e, 0xede3cc3c, 0xe398b306, 0xc7ae5ed2, + 0x2d49f027, 0xad939387, 0xc321236d, 0x781d664c, 0x9a72151e, 0xcb54b09a, 0x50ccb05c, 0x591d2e2a, 0xd27e8ce8, + 0x38bad818, 0x04be6be0, 0xc780d550, 0x6de6ab47, 0x000ad46d, 0xc9b7a827, 0x133e1f33, 0x0a002980, 0x74a99614, + 0x43e23662, 0x36814b68, 0xa34db32d, 0xeb4a87bf, 0x0600a607, 0x4351949d, 0x8fcf6b7a, 0x8f360052, 0x24baeece, + 0x1a6b67ff, 0xa835e579, 0xdc790078, 0xc63cbed7, 0xc76b5124, 0x68762ab9, 0x3219b509, 0xd2ec141f, 0x92e7ba8f, + 0x9ad5eb30, 0x6210fe8f, 0xa72797b5, 0x18d14a77, 0x053422af, 0xb8dc3c38, 0xaf58fab9, 0x14cccb94, 0xe1081b01, + 0xac24ffc7, 0x2558172e, 0xe86f0cde, 0x58ca7deb, 0x7d76e5be, 0x068d9149, 0x08a05426, 0x204b5177, 0x5ce19256, + 0x5dfa8a04, 0x0f3c3569, 0xbb20d212, 0x9c217975, 0x3a7acbf7, 0x46c044f5, 0xc3777353, 0x9150c3e3, 0x7e4d728f, + 0xa63f2f43, 0x3d802e2b, 0xcbca1be2, 0x38eae501, 0xdb67e939, 0xeec9d420, 0x9357a953, 0xe3f97c7d, 0xd157da3d, + 0x23509ea0, 0xe2163b38, 0xb23da80a, 0xff01c1df, 0x5cbc9361, 0x95927bc3, 0x80fcfc65, 0xdc23b0dc, 0xb43c5eea, + 0x3c3c0107, 0x7de8c4ae, 0xeef0db5a, 0x28b31ea0, 0xe4e2c3a5, 0xf8a826e8, 0x0cad6931, 0xcb4dbc7f, 0x8a3a8bb0, + 0xe5521314, 0x80dedf91, 0x6cd3976e, 0x8ab2eca1, 0x46b66775, 0x9744a8a7, 0x84c8da43, 0xf6b34751, 0x05aa3110, + 0x9b0b659a, 0x5236aa04, 0x6045840e, 0x4c3779f0, 0xc2b587c9, 0x105dad3a, 0xa3d88466, 0xed6e534b, 0xbb1be9a6, + 0x75dbf146, 0x8f3bf2f6, 0xb9288d48, 0x1a96d323, 0xd50d0560, 0x304f113c, 0xe263bc92, 0x2c63525c, 0x6ee2f24a, + 0x5d0a1d92, 0x9aad0543, 0x79b35529, 0x6548310a, 0xb2ed9d30, 0x6bd42f7b, 0x491710ba, 0xe9b7ee87, 0x6ee0a60c, + 0xbcac7a8c, 0xe127d759, 0x1942697f, 0x34b31df1, 0x7c2128b0, 0xe938146f, 0xc42bc7ab, 0xc470ac17, 0x3b15ffce, + 0xcae773b6, 0xf7d1829f, 0xa26fb8ee, 0x930aa011, 0xf28d89b4, 0x3f4660e9, 0x375bede0, 0x4353653b, 0x722e1caf, + 0x2534d020, 0xf872a858, 0x94dc8eef, 0xf0a20382, 0x91e4e310, 0xd3bb1110, 0x9f6187ab, 0x28f451f0, 0x65e369e6, + 0xeba81b2f, 0x599e99d4, 0xb3fcd41a, 0xb09c04a8, 0x79ff2730, 0x52c3bb6f, 0x927d43d1, 0x0e3b99ae, 0xb9269463, + 0x8b9f4fa3, 0x2a2dfd3d, 0x541177b4, 0x52f0f6e6, 0x658fec51, 0x18eca21b, 0x4e3e953d, 0x2e6b8b20, 0xb6ac2824, + 0xbddaa70f, 0x101a4390, 0x52a3b285, 0xbdad0bf7, 0x46721a09, 0x6b72b591, 0xa34f7e1b, 0xaaf66824, 0x63063ccd, + 0xd2a40d4a, 0x8fa5a7d4, 0x0d95aa01, 0x6ed6f7ae, 0x19d0e8c6, 0x627437cf, 0xa49923ff, 0x168b3f0e, 0xf6489c24, + 0x4b984ba5, 0x0c309ea6, 0x90c9b732, 0x55d83962, 0xc7c770fb, 0xd84ac898, 0x876366bd, 0xc04fef87, 0xafe6fb6d, + 0xfaff3977, 0x5a1cabd2, 0x69f58c72, 0xb34310a8, 0x7849d185, 0x3ca56539, 0xccac3c10, 0x55bbe3da, 0x2a0da53e, + 0xb742f123, 0x4df93ece, 0x4d0b897a, 0x06562a93, 0x9b172c01, 0x79287305, 0x2a00daaf, 0x2de4500c, 0x3ac468e1, + 0x1c6cdea1, 0x15d07f63, 0xd4a77cd0, 0x2735a60e, 0x92a5072f, 0xab40ffeb, 0x5a80f5a3, 0xa7f7911f, 0xa78878f2, + 0xcf20bb82, 0x2cda6089, 0xf5cad7b1, 0xec8d80bf, 0x8b222db4, 0x1df1e680, 0x46ec9b89, 0x3fbd0da1, 0x9c54762b, + 0xc45efd00, 0xdca84ecc, 0xb7479500, 0x717e2171, 0xdacc7171, 0x4a13e0b0, 0xf5331fff, 0x09797be4, 0xc8929f9d, + 0x5ec54b5b, 0xeecc89b4, 0xb4b67da3, 0xf4482cad, 0x47c4fdf7, 0x094ed7c0, 0xabf48235, 0x6d4bbba5, 0x09b5d30f, + 0xb24f88e1, 0x04400d7d, 0x14ac00ee, 0x74ca1943, 0xe2b542c3, 0x08f765c1, 0x55a58599, 0xa0a7f2d7, 0x6c711990, + 0x2fbf2cff, 0xc4a57d6d, 0x76c55c63, 0x529b0dfa, 0x8841f7a2, 0x51b74ab2, 0xece06ed8, 0xb463f904, 0x7516fe2f, + 0x3d40520d, 0x32d4a45c, 0x8baf5a84, 0xbc9818d4, 0xbc4cc524, 0x42205a25, 0x29b5f542, 0x3ad97555, 0x8aad4d89, + 0x0ed0978c, 0x4e6a7f3d, 0x87be8e69, 0x707905a9, 0x4f7e3cc0, 0x39cc166c, 0x00e4e16d, 0x0d9b42ff, 0x996e8208, + 0x7e7b86e1, 0xdc7338e9, 0x38b56350, 0x0d3cf65a, 0x05010a79, 0xa0c25ecd, 0xb29c14af, 0x8bf0a1ab, 0xbb1db938, + 0xc3909da6, 0x004be540, 0x46be49bc, 0xbc1d3827, 0x43c0e169, 0xd6bc66f5, 0x40963aa1, 0xbe12cdbf, 0xcdce3096, + 0x1e049f38, 0x8ef6e902, 0xe35e28d0, 0x37e1cc42, 0xfac563ca, 0xcad58b07, 0xaecc6a13, 0x4cb3dc45, 0x2377421a, + 0x5c8e608c, 0x1c73cdb9, 0xd120597c, 0x5fdaed38, 0x40e7040d, 0x2625a531, 0x937651d9, 0x1b01c64a, 0x80519d4e, + 0x85bd234a, 0x3d81b739, 0x9a623090, 0xb03a6aea, 0xa5aca061, 0x6b119203, 0x7a4a2ac5, 0xf15ccf88, 0x18ec9432, + 0xb40f97e2, 0x948eecca, 0xf7e3cfc6, 0x3144fae1, 0xe52069c9, 0x18324809, 0xc655fcb7, 0xbe9afde7, 0x8302787d, + 0x47e9a414, 0x34e0380a, 0x2f0bc601, 0x44b2c5f3, 0x846e25d1, 0xf31830bd, 0x35a50521, 0x8fec446d, 0x5f4e2b38, + 0xdc218b86, 0xdb884a7c, 0xbc18ad62, 0x6f1f004a, 0x9239d020, 0xbb89cfbf, 0xadca116f, 0x0f7195fb, 0x73546f6b, + 0xbf827c61, 0x63c0027c, 0x3a81e0d1, 0xe1ecb3ca, 0x9bf934ce, 0x4709c923, 0xf63b8101, 0x34cad0f3, 0x9d683bef, + 0xd93c84e1, 0xfd83dad5, 0x5d04928c, 0xce21ffd8, 0xb885ddf9, 0x2f222f3d, 0x4e013741, 0x7652dd2d, 0xe34cf4f6, + 0x33739eac, 0x841ed796, 0xe1d64e4d, 0x538409a1, 0x9ed73cce, 0xc81c9c94, 0xe72ca12b, 0xb79492fe, 0xc7fe081b, + 0xfad9bd66, 0x74e4bfa6, 0x543636e6, 0xfa23e9c4, 0xfe9c2928, 0x3d44a109, 0x14c3828c, 0x6aaa86a7, 0x237f52a1, + 0x5b7c67cf, 0x17739bc1, 0x6f7052aa, 0x5948c6e1, 0x409928bb, 0x8574bf4b, 0x28f769fc, 0x422a5604, 0x93b94149, + 0x539c0699, 0x76e3eb38, 0x09d8b018, 0x15d0759d, 0x0e15b86d, 0xd7a40a5e, 0x3d6f9a8e, 0xae906b14, 0xf3a5ea50, + 0xbad5e0d4, 0xf2748796, 0x76fb2e1e, 0x51a8d036, 0x258ac956, 0x0e069738, 0xf4ecc0a4, 0x1c952908, 0x089b8a7d, + 0xb8e63d58, 0xe9d30016, 0x5e53b1c0, 0x66f2fa55, 0x8377607c, 0x24ac1e10, 0xf3f1e3c2, 0x79f6a39f, 0x06b0aebf, + 0xd0b12011, 0x9144b362, 0xb70228b9, 0xb5f44ee7, 0xcddb2ac9, 0x81438a1e, 0xc86558f1, 0x977d6626, 0x6523ea99, + 0x5c5a6c69, 0x7df3edfe, 0x83f4d51d, 0x32ee0e1d, 0xc1c6942b, 0x87005b65, 0xce12eeb1, 0x93bfe68a, 0xb0c41665, + 0x96ad2c90, 0x69fe53c7, 0xb8c74bb4, 0xf542bde8, 0xe095c113, 0xde10bc43, 0x5d1f42cb, 0xb86b93d9, 0x1dc1b8d6, + 0xa782fd48, 0x76ae4585, 0x311782c1, 0xdb3a216e, 0xad14942c, 0x47b3f375, 0xc4f6a875, 0x63b76ebb, 0xb4fdea81, + 0xa8bc5636, 0x99c4d80d, 0xf92a9dda, 0x3223004d, 0x2f8221f9, 0x322a3303, 0x5b6b946d, 0xfbd36f2b, 0xc5ed42d7, + 0x5296b779, 0x6ca3da8d, 0x5661081f, 0x23573734, 0xba187ec5, 0x6777766b, 0xa2d7c3a5, 0xfbb1cef7, 0x4d00f3f4, + 0x85a7b7bf, 0x728a15f1, 0x70d44371, 0x9c8a6452, 0x0c19abf7, 0xd43337be, 0xfe92f72f, 0x3e1cdc53, 0x6f224de3, + 0xbf902140, 0x5f2c1d07, 0x66e657e3, 0x0b766760, 0xe584fd20, 0x7c2be7bb, 0xbdf12496, 0xaaa6d4c8, 0x9bab58ff, + 0x9d740956, 0xa4ed0689, 0x5153b479, 0x6183a805, 0x7da93c00, 0xd844dae0, 0xa86ec278, 0xb1960caf, 0x8110f633, + 0xe159220c, 0xc6225e09, 0xd16fcf28, 0x7f2cd3e3, 0x3f781195, 0x44b3b408, 0x8c37d4be, 0x30235451, 0xd4fd4abc, + 0x639da700, 0x643b9cf3, 0xd24b34a5, 0x56c12d77, 0xa95c8987, 0xe48366c8, 0x2af3383c, 0x2e8b9589, 0x6d6880e8, + 0x50f0b102, 0xe5fc4dca, 0xa3f48dec, 0x7b05e4d6, 0x7974381c, 0xa76753a7, 0x30f841fb, 0x62a621cf, 0x5e1881c8, + 0x1a29e9fc, 0xf2afdc19, 0xfc233809, 0x985d6b3d, 0x49c38271, 0xfa7cc2ce, 0x837fb1c5, 0x57ae017c, 0x702c86db, + 0x4d76ce9c, 0x19c28bab, 0xa58db9ea, 0x66949fcb, 0x5463e11a, 0x8d4e3c9a, 0x1b1fcb67, 0xff174799, 0x7541a641, + 0x7c1da398, 0x552d77c5, 0x813db583, 0xf0070830, 0x695e9452, 0x0333d1f8, 0x998d32e1, 0x4d541eac, 0xe554a185, + 0x5247efff, 0xccace693, 0x1cf42b2d, 0x039bfaba, 0xd5147710, 0x2cee93a4, 0x0516a148, 0x62102355, 0x11ccde30, + 0xfa758348, 0x3f2c5b36, 0x2c8bad98, 0xda91fc8d, 0xaa254d4f, 0xf7c30417, 0xf795f8cd, 0x332e02f3, 0xc52b48e8, + 0x0b860642, 0x9c148d3c, 0x316cf260, 0x7ba08737, 0xf9e3e96f, 0x0c05d2de, 0x0b32fafe, 0x0071d3ea, 0x896e8fc8, + 0x85542fdb, 0xc33ccb96, 0xebacf429, 0x48a2c087, 0x3f812454, 0x2ce6e033, 0xbd774d23, 0xb9583745, 0x5fc47166, + 0x71f8cd52, 0xe52c666d, 0x38b294e5, 0x79011dd0, 0xa6270b30, 0xf14a30d9, 0xbb7c1b2f, 0x3fc63624, 0xef82edb5, + 0xa9724435, 0x61f249e8, 0xb032360a, 0x849139fd, 0x27d27c09, 0x86085206, 0x8b69c39d, 0xeb42fb44, 0x44c3876e, + 0x61eb9e56, 0x18a309db, 0xf58723f4, 0x5cbb8594, 0x91e8ae19, 0x60a74959, 0x32e49be9, 0xef785e5e, 0x9e212fbd, + 0x6f7d68cd, 0x2efd9603, 0x0405f351, 0x421ac291, 0x18b31a3f, 0x6b074ea6, 0x59f32ed7, 0x94f291cb, 0x4f9edb00, + 0xb1370125, 0x7d50c990, 0xa358a478, 0xfa0ea4da, 0xa5fde599, 0xdf586fb9, 0x2b358a64, 0x29f38be8, 0x777d8eac, + 0x156a0865, 0x5ba09b22, 0x2f293f9d, 0x1531a7f1, 0x84e88cfa, 0x6273e1e2, 0xe2a0f426, 0x50dc0178, 0xba056f25, + 0x67424bbc, 0xf329b566, 0xa67977a2, 0x0d0557a6, 0x7a71bde8, 0x025c2064, 0x7b62ee2e, 0x8a562c7d, 0x4ef467b2, + 0x50053d3c, 0x01792092, 0x31fc1c1d, 0xeccfce91, 0x6ffc633b, 0x7db6251b, 0xec6f004d, 0xe111be29, 0xdac3ecc9, + 0xd8ae5fd0, 0x152de3ea, 0xb3a0b2a3, 0xb7b7ea0a, 0xa4df035d, 0x55e63223, 0xedc45f68, 0x9d64b089, 0x3727a072, + 0x587c4e85, 0x97984dbb, 0x066b36d5, 0x8a74a9b6, 0xa2b2e841, 0xe8fa457e, 0xb1698f86, 0x986cd6d1, 0xf91981a4, + 0x29699e99, 0x83b007aa, 0xf6b28d1d, 0xf4744ce4, 0x6c151999, 0x2ad4336e, 0xc07285cd, 0x561e6853, 0x15504870, + 0xf39afd8e, 0x05c7bba1, 0x02d74165, 0x59b90fc8, 0xda5ecd44, 0x67d98811, 0x2656ec18, 0x3d63a194, 0x7a423fa0, + 0x313d3087, 0x78840ba1, 0x8ec97884, 0x8f5f2bbd, 0x8c3573a9, 0x71798a1b, 0x83e3d122, 0x38559085, 0x1b8a0441, + 0xc8a0706d, 0xf4748a6e, 0xfd78e17c, 0xf9d9265a, 0x06d0e43d, 0x978d63a1, 0xce188391, 0xf8993ab5, 0x633dfc67, + 0xaac6979a, 0x0817e53d, 0x3e5cbbf4, 0x69fcec6e, 0x2dfc3325, 0x74d43679, 0x076c20bc, 0xe9cd6b8e, 0x3331ccb3, + 0xb77a631a, 0x6ceab91f, 0x17fab409, 0xf3e02b61, 0x2a0272ae, 0xf96afe44, 0x5879b631, 0x2c460ef6, 0xfb523099, + 0x2de388d9, 0xca1954a0, 0xc97ecd89, 0xb60be543, 0x29844121, 0x14ce8365, 0xc3607ce1, 0x38ca6fa8, 0x85154614, + 0x3d1c9463, 0x6ae66996, 0x0cccf2f9, 0xf84005f0, 0xfbccee1d, 0xee139942, 0x176405e9, 0x0e44a581, 0x4cefb68e, + 0x57bfcb06, 0xca56bd5f, 0x4930c148, 0xc9951417, 0x85847cf7, 0x1da64025, 0x6519536c, 0x77731df8, 0x8e2227db, + 0xa73f189e, 0xd29f2d94, 0xdf4e4ac4, 0x22213657, 0x966a7963, 0x489b0469, 0x240456d9, 0x6f9d0e27, 0xd9fbe2a8, + 0xc0b16e88, 0x752c37b9, 0x4c780691, 0xfbcf7437, 0x21ecc6fc, 0xcfc5ab19, 0xfe8a7f6e, 0x08e474fb, 0x0b20d410, + 0xa5096569, 0x845ac54d, 0x9c34bf30, 0x05ec6765, 0xa5d8baa5, 0x75e0e336, 0xbc15a181, 0xc10b97ff, 0xf84fe565, + 0xd19d0099, 0x3542fd2d, 0xe866341f, 0xc8279b01, 0x5ec29b50, 0x1354b9f5, 0x5ca13729, 0x7a117bcb, 0x67e4cd20, + 0x4e00fff1, 0x5da7b6c7, 0x7571ad74, 0x24a4a511, 0x669addb7, 0xb00a20ff, 0x2f0b1e92, 0x2d0c607d, 0x6868c682, + 0x8af553da, 0x9aa7ff14, 0x21436836, 0xbd8ae3d6, 0xe843edbd, 0x3ed1d89b, 0x3ea3c67d, 0x9a9729ea, 0x6c53fe29, + 0x767863ca, 0x957212f7, 0x15c7474b, 0xa105ab37, 0xce510209, 0x56f3c0a0, 0x8e0465e1, 0xc080fdbb, 0x203d1aa2, + 0xfdfa4b89, 0x24e19807, 0x3ed4788b, 0x0ec54e24, 0xdf70a58e, 0x87cf1d90, 0x83196320, 0x538ae0ef, 0x640b4bd4, + 0x18768891, 0x415e03ea, 0x1f7a8ead, 0x9e535320, 0x593a1a4e, 0x2d6732d7, 0xaa00ad81, 0xd91888c8, 0x3efdccff, + 0xc2d6e88a, 0x277791b0, 0x23fadc68, 0x44a96116, 0xc763733b, 0x4a71079f, 0x4cb3e452, 0xea61c346, 0x93c1453b, + 0xec01d232, 0xf306974c, 0xd5ad082d, 0x8b37d5d9, 0x9e98b7c9, 0x914125a3, 0x05c2426a, 0xee22fe1b, 0x0aac2084, + 0xa940946f, 0x839931ac, 0x52779e7c, 0xde79738e, 0x6a604597, 0x2fb5e594, 0x160c1ed4, 0x0879267a, 0x3afc7134, + 0x4551bc61, 0xdb026be1, 0x408780a3, 0x523ac015, 0xb625fda7, 0x8e8c6e14, 0x3b33b460, 0x13ccff77, 0xbd9ba557, + 0xae1f77cf, 0x1747ae29, 0x3a1ef3a9, 0xe60b6f18, 0x99628dc3, 0x9b837b26, 0xf956c594, 0x167d752b, 0xf782d749, + 0xcd8a484a, 0xb58cc236, 0x5f96be4e, 0x118ab37e, 0x905cefe4, 0xcd897c13, 0xfb75db1d, 0xb8216960, 0x9c27087f, + 0x8df8cf99, 0x09b32d64, 0x35f7835f, 0xf3044a5b, 0x3ecbb473, 0x2a7a86ca, 0xeea4e2e4, 0x9a8fc14f, 0xf8cc06f4, + 0xcaf202e6, 0x7468e0b2, 0x76e9092b, 0x85cecfd2, 0xaaf1bd29, 0x472bb2fd, 0x78587a82, 0x20a1e1d3, 0xc9959df8, + 0x3ef5ea27, 0xc9ad7b9f, 0xecaff54d, 0xae35e0e3, 0xff6b6317, 0x5413de0a, 0x322ed005, 0xf2bf7fde, 0x5f9b664c, + 0x29199564, 0xe24f7150, 0xf764c451, 0x5059f3ec, 0x559a199f, 0x063114d7, 0xa7fe8054, 0xd27377dc, 0xc3d1d28c, + 0x00cb8f0e, 0x0975f072, 0x3af6b6f7, 0x9267d2b2, 0xfc4d196b, 0x24dba44c, 0x15fb6b5d, 0xf3e209fa, 0xf9bd7191, + 0x6ab2ef9d, 0x1c5210e4, 0x2d255c90, 0x958e9ef0, 0xe3ea3e1b, 0x3aa4098b, 0x7163d812, 0x15a6bc7f, 0x66873291, + 0x7ce465ea, 0x6815a1b5, 0x250558e2, 0x8dba31f2, 0x313ea673, 0x86b3b89e, 0xb1dc077a, 0x3f9d3b90, 0x6c5ead63, + 0xedc6d2b9, 0x3d37c0b4, 0x26e85a84, 0x555c2608, 0xd7cf7a3a, 0xf85f4b3c, 0xeb5ae67d, 0x468c314f, 0xe2e172a8, + 0x97cd5532, 0xb9bf50f2, 0x84bb2eea, 0xb0498901, 0x7ecc8536, 0x55409ab3, 0x01f649b4, 0x6bd9d60f, 0x096b0f9e, + 0xaa1721bd, 0xfdb2cd5e, 0x5d1f11f6, 0x638360ed, 0x7dbaf8df, 0x48badff0, 0x5a75c20c, 0x98ffee21, 0xda53338c, + 0x9af072cf, 0xc002e147, 0x88d6c0e7, 0xf2f83d3c, 0x09246b2d, 0xbbed1cb0, 0xb4d06a2b, 0xc30ac657, 0x5737d212, + 0x481f9710, 0xcf7bc4b5, 0xa7869790, 0x341d6676, 0xfdd4d107, 0x7923aa10, 0x53b10fda, 0x2f9b7346, 0x16eb3f87, + 0x03b03e95, 0xf71cb3ef, 0x0f6f596f, 0xd81902e3, 0x4ac5e7aa, 0x631cb8bc, 0xe4e7d273, 0x334d139f, 0x470df346, + 0xe7fab909, 0xba80f1bc, 0x000a6f6c, 0x20673ebd, 0x5ed7f936, 0xa148e5ad, 0xa40014fd, 0x87d34e7a, 0x486a83f1, + 0xa14c5d90, 0x17e4a435, 0x867129b4, 0xc9899cb9, 0x879a8842, 0x7d940dd1, 0x168067ad, 0xfa4fb5ca, 0xaf6930af, + 0x2c0cc316, 0xd744654d, 0x56eccacf, 0xfc4bdf38, 0x7eb41068, 0x42feb3b5, 0x373ee024, 0x1080b4bd, 0x4e9404cd, + 0x36ab4e25, 0xb5607482, 0x3359935e, 0xa7faec93, 0x382189ff, 0xeded12d8, 0x049f7741, 0x63cd45c1, 0x2550f6f8, + 0xb79bb6e3, 0x48607869, 0x4cca0496, 0xc29eccac, 0x3f831965, 0x487276f0, 0x52d25b28, 0x6d96b04c, 0x4b1e7815, + 0xf4b90a3f, 0x07f91c99, 0x6255be3b, 0xb1f4edc2, 0x715b4246, 0x244f2ea9, 0x932a5663, 0x96080ef8, 0xb0e1091b, + 0xda7b0860, 0x286e8575, 0x790aecda, 0x5c5a1fc7, 0x3f8f808a, 0x7002f086, 0x9a7ac259, 0xd2b890da, 0x36432e74, + 0x151a94d4, 0x7fd66d09, 0x1f3e14ee, 0x04e17ca3, 0x635576d3, 0xef0769f9, 0xb136c7a3, 0xcb03bedd, 0xd9203a22, + 0x9b35790e, 0x6001d810, 0xa6a9c912, 0x3bc27664, 0x265fa55b, 0xb55cda59, 0x1b0604bd, 0x86f6931b, 0x7c61f4be, + 0x6722fc24, 0xf7cc83b1, 0x565ec657, 0x4cb70561, 0xb2dd3a5f, 0x95d0efe0, 0x522c10e8, 0x70fd157d, 0x6ae6b161, + 0xf8a1d010, 0xaa90df79, 0x11c301ec, 0x188c456d, 0xc44c5161, 0x977fce9c, 0xc8f8d72b, 0xd1a19f6b, 0xd91fa6ff, + 0x875096b1, 0xbfbf21f3, 0xe8040b3f, 0xf4dd0244, 0x6f8a5cb4, 0xff69cbc1, 0x2b9b70ed, 0x691e9e0c, 0x199b718a, + 0x4d85ed85, 0xd05bf207, 0xaa848c02, 0x2afc59ad, 0xc37b2b1a, 0x57c80cc2, 0xa459251c, 0x0a42ccc1, 0x5fc8289f, + 0xff5c41da, 0x7739de7d, 0xb4e1c3bb, 0xf4ae951e, 0x72161351, 0x74dbaff3, 0xe5aeafc4, 0x9ca5303c, 0x573dc8a9, + 0xd9222e37, 0x39908da4, 0xa562e6e5, 0x9f52689b, 0xce9fbd1c, 0x9d23a5e8, 0xc3287191, 0x4103ca4c, 0x14fb8890, + 0xc66f8f3b, 0x20b21a1c, 0x2a954ad9, 0xc67c5d5f, 0x0a02c223, 0xe28c3b9a, 0xa3c7756f, 0xa131d510, 0x7818b011, + 0x1295cb8e, 0x19b7e978, 0xa0d7c210, 0x366f0635, 0x4a7077f2, 0x5a79a060, 0x58842cb6, 0x03372c8f, 0x73187117, + 0x62e812b1, 0x67fe7363, 0x8fc91d78, 0x2cd8986b, 0xdb1858f4, 0x8d3e5070, 0x73d345bc, 0x3d1e0fae, 0x9e2428a3, + 0xb974f1e5, 0x00654ca2, 0xdb009615, 0x00b5d001, 0xa90de392, 0x684ddb61, 0x9feaf8c2, 0xb9dacf1a, 0x1a9c7daa, + 0xb6cd39ff, 0x8008c8d2, 0x05d9f668, 0x7e258cd4, 0x13cf6678, 0xee1046f4, 0x5b1b3e0d, 0x20c25a51, 0x7a19ad5e, + 0xa0ab58f7, 0x93147c6b, 0xeef3c23c, 0x0544332d, 0x30121071, 0xefe906ea, 0x318b29e0, 0xce40659d, 0x3a1f1b43, + 0xf2dd4437, 0x1dfcfa7e, 0x6455fba1, 0x95544172, 0xdd1653d9, 0xf88a3096, 0x0541d1d4, 0x0b4a8fbe, 0x7980768c, + 0x85c00398, 0x755c7420, 0x17dccc20, 0x94e649bb, 0x3e0ea56c, 0x6de86621, 0x3c106ac0, 0xa71f1edc, 0x4263e709, + 0x2d5347b3, 0x8a8d48e5, 0x228aebbe, 0xde394b6d, 0x4e53e34a, 0xb303a6ea, 0x875dad49, 0x8408d3fe, 0x71f287c0, + 0x1a9661d0, 0x62deeedc, 0xc1361fb4, 0x726c29cf, 0xf8638ad4, 0xfa3b4a0b, 0x45bbf0ea, 0xb6cf6975, 0xe2edb287, + 0xd8e659ee, 0xb197a525, 0xa3b722bc, 0xc65e1c1e, 0x5cb5a86c, 0x71ceb5b0, 0xdaac9e76, 0x31b68968, 0x10e6a76a, + 0xd600827c, 0xc1dc2836, 0xd72e9d71, 0x7eea1b98, 0x7d6bb43a, 0xaba2a476, 0x9b0e8590, 0x84571d94, 0x145fbb78, + 0x7ca9521a, 0x89d2a927, 0xc64d02dd, 0xbc80263b, 0x8166e736, 0x4786ce0e, 0xd241d3ab, 0x440e9eee, 0x2f10f0ae, + 0xba230fe6, 0xedc6f873, 0x006b6ec7, 0x5e6151c1, 0xd6377593, 0x21f92fcb, 0xfc5c1b6c, 0x303290fc, 0x45fca98c, + 0x4d7762d7, 0xc6901b2c, 0xe1d08566, 0x12e45a1a, 0x17559b2b, 0x4dc869dd, 0x3fae7063, 0x5f83ae8f, 0x03d50942, + 0x6dc1cf22, 0x90f2a8bf, 0xa0837d60, 0x4480e52f, 0xc2828def, 0xd33b3337, 0xa6c6ccbd, 0x7f74a70b, 0x466a1495, + 0x9bdf6aed, 0x8f14f84a, 0x5ec9f898, 0xf54d1e39, 0xdc402696, 0x9ca67539, 0xd34f18f4, 0x69d5812c, 0x16cf2940, + 0x000266e3, 0xaa5fece4, 0x2a1c19e0, 0x8f8ffddc, 0x092ebf6a, 0xbb216f8b, 0x3be379d3, 0x67ec2cb0, 0x3e624e42, + 0x2b891984, 0x4d42106f, 0xda6e38a1, 0xd7533a71, 0x10ea738d, 0x382e340a, 0xa0f51e76, 0x72ce9ca9, 0xad2616bf, + 0xa6241c58, 0xa5166754, 0x9a4fd52b, 0x80f833c2, 0xb5b27bad, 0x09bf9fbd, 0x4f8a0848, 0xc9cc88cd, 0x4131381d, + 0xe6bfc5a9, 0xe0233cc4, 0x7aca140b, 0xb61e896a, 0x3c2e9cc3, 0x42165ccc, 0x45d7772c, 0x3437daf0, 0x488b6dd9, + 0x4cd5f62d, 0x6c59b526, 0xef11f91e, 0x27810dd6, 0x5bb703d2, 0x3fba01ab, 0xfbd3c9ba, 0xf10df224, 0x1a0defe3, + 0xf4e58428, 0x4e6cffd4, 0xe27d887b, 0x9024ba68, 0x84a24d5e, 0xfc5a46f4, 0x73d0275e, 0x3898c949, 0x9bc579c9, + 0xf63b7d28, 0xb6c39ee7, 0x8539e915, 0x4901f7ac, 0x362bf850, 0x6a3ec147, 0xdc42b816, 0xc1b095da, 0x8687882f, + 0xff330c2e, 0x516bc6cf, 0xe021a5c5, 0xe1e52670, 0x7a3f5b7a, 0x7c58a7b8, 0x7f6615b4, 0x367a7d65, 0xa6cf12ba, + 0x8a52824b, 0x61c8b5b1, 0xdc55ddf9, 0x0bb4e8aa, 0x137bdc20, 0x38cf2336, 0x885fd8bc, 0x549962a1, 0x8fe3253d, + 0xfd764f85, 0xe47f6557, 0x8251fd27, 0x6eb02568, 0x139ca59a, 0xc25124d2, 0xaf35e695, 0xb2329dcf, 0x6b2a483f, + 0x113e395d, 0x68920a31, 0x07088cde, 0x9745ce49, 0x66ec7320, 0x59b64d10, 0xb139a64c, 0x62e4ad75, 0xabe2e33d, + 0xadebd10b, 0x5365095a, 0xf8d39b39, 0xa406429a, 0x11d4829c, 0x9b9551ed, 0x33d7798a, 0x35b8145b, 0xfcf8c97d, + 0xe57b204f, 0x5d7dad69, 0xbc5d5ff7, 0xa575877b, 0xa6423436, 0xeebccede, 0x4e0f29cc, 0x2fc7a874, 0x7bc98d65, + 0x28ffabe4, 0xf8ce13e3, 0x1a103d50, 0xc1b24f8f, 0xacb2fdb8, 0xf6345f64, 0x11587f8a, 0x993cc7f6, 0xfe4fd709, + 0x0bd10778, 0x28101ed6, 0xb9ac5de6, 0xe3463f2a, 0x414b394a, 0x80067c24, 0x7efe347d, 0xd9d393ee, 0x84fbb492, + 0x860fdf7b, 0x52f22a78, 0x5a3b6dca, 0x46fa2359, 0xe128ddf5, 0x84fb11c8, 0xdeaf9bfc, 0x162ac4a3, 0xeccb1e9a, + 0x222edc23, 0x7ace1a0e, 0x2ec23c6e, 0x8543aa00, 0x3b10e56d, 0x908128ee, 0x828727b4, 0xc58de809, 0xca6cfd26, + 0x9b5f9ad5, 0x7c6b4dde, 0xbd1cb6ec, 0x59f8c7a0, 0xe732a03d, 0x58972773, 0x72804f28, 0x0a6c753f, 0x12c561e3, + 0x5d5d8f4f, 0x868b28ba, 0x23ae9764, 0x8a3a9daf, 0xf5a03859, 0xaa9ae0c6, 0xb2e7f0de, 0x113cf81f, 0xe7312bd2, + 0x73fdffe4, 0xc175907f, 0xbd52d4a9, 0x4f2c78d9, 0xfa3a2eef, 0x1900b736, 0x26a26cf9, 0x66b8a87b, 0x214e5666, + 0x935185e7, 0x125d958d, 0xefce600c, 0xd6f695bc, 0x010e1e86, 0xa2e7ec38, 0x83ce1bcc, 0x4ea14294, 0x40110eb8, + 0x3426e033, 0x5968a91f, 0x3c5f144a, 0xd53bace5, 0xb2c09574, 0xf222baf7, 0x97a2ddc3, 0x762b44c3, 0x350d889f, + 0x929169b1, 0x0318c8be, 0x82ad810e, 0xda00969c, 0x4b36f418, 0x1ebc8401, 0x06e7b760, 0x786809c2, 0x895be648, + 0x502694ae, 0x9f002f84, 0xbd48a265, 0xe6d9ae08, 0x0bb7ce0e, 0x347edd11, 0x35d0995f, 0x81532dfb, 0x233dc6f0, + 0x29032aa8, 0xc5d6fe62, 0x495a4bf2, 0x6a0c879a, 0xf2976451, 0xf93ef218, 0x001796b1, 0x78262f47, 0x92d29adc, + 0x8d96e28b, 0xcee43de5, 0xfcfe06d0, 0xc19f23fa, 0x2dd6db02, 0xee5700af, 0x63276b81, 0xa0e07ec3, 0x76a2be5d, + 0x2c3222ed, 0x1b4e4b22, 0x85954384, 0x6e928ef9, 0x33a5edd9, 0xd16812b0, 0x95d4eee0, 0xbccff516, 0x2513d2f1, + 0x2f8ea1b7, 0xeea85915, 0xf12313f0, 0x80f4bbbf, 0x58767eaf, 0x94f8c232, 0x0008a5b4, 0x8ba5cedb, 0x03c25da2, + 0x1e6c719a, 0xfe9c9806, 0xbb36badf, 0x66adf84b, 0x549c7299, 0x04580aff, 0x8503cca5, 0x4c4cd04f, 0xa2fa9654, + 0xb0b02551, 0x3c513b66, 0xc2ff9fca, 0x21cb057b, 0x1ae0ade4, 0xef079801, 0x58f2b4e5, 0x40f15c61, 0x0109b9e1, + 0xdfcbda49, 0x78d6aad4, 0x34bc9135, 0xf5aa3dc0, 0x81c68081, 0x16425d87, 0x87182281, 0xe7d194fe, 0xf909f360, + 0xdf9bdcf0, 0x0fb247dd, 0xf4959f9a, 0xd14b85b3, 0x717692f9, 0xc1fc87bf, 0x61b013d0, 0xf2e545af, 0x4dae24cb, + 0xb4f3db7e, 0xfbfd8759, 0x68806144, 0x12d00eed, 0x1fbd26e0, 0xc68128c9, 0x34aed498, 0xb42802f8, 0x31e3d884, + 0xd8e98064, 0x03a16ef5, 0xcede4aa2, 0x19bc94d2, 0x0d684724, 0x07495860, 0x24c21404, 0x24a359d7, 0x6c4dc587, + 0x93176ee7, 0x96b2143f, 0xae402308, 0x36506c0a, 0x97ea8a35, 0x1d67317c, 0x04f3da38, 0x4b4701c9, 0xed61ce4c, + 0x9391a5b6, 0x05a19c4f, 0x840ac017, 0x5ceb1a89, 0xfdd0b332, 0x13655c51, 0xd653ea5c, 0xa57b9951, 0x91dcdc5c, + 0x26f34d70, 0xdae0d673, 0x27c38094, 0xcb553397, 0x752a685f, 0x7d5bbaf3, 0xf9a29362, 0x0552a20c, 0x4abcb49e, + 0x11b2ad1c, 0x70e06493, 0xdac3a47c, 0x56fa0b0b, 0xadc9eeee, 0x1afdd878, 0xbd3c4911, 0xa3b68dd3, 0x9737ab21, + 0x7dd94c24, 0xadb3b5bc, 0x6d02cb2f, 0x89e94f56, 0xf4ec952b, 0x31cee45d, 0x323f0b6f, 0xc2249fc1, 0xabd2f201, + 0xaf2dff85, 0xa64f4f17, 0x24915ac7, 0x541d3ec5, 0xed5f8c2a, 0xf0ef24c5, 0x12299a75, 0x09349af7, 0xc4463b16, + 0x805bcfb7, 0x94af2500, 0xbc8f1665, 0x6a6bb161, 0x19ae6b1f, 0x26dd7b2c, 0xb54cb8f8, 0xfdd26d00, 0xbe596ff0, + 0xfe30c855, 0x55452243, 0x840244b1, 0xfd1c7ffe, 0x57486418, 0x0e0aae9a, 0xddece953, 0x44553e4d, 0x95fdebee, + 0x1122d777, 0xbf6c0992, 0x7ebd6138, 0xbf84e347, 0xba13cc84, 0xd9e377c9, 0xe52feafc, 0x36663b7f, 0x6cd15c67, + 0x66a183fe, 0xcf62809e, 0xc81501ab, 0xc7be5d53, 0x62a3888c, 0xf4187dba, 0x4bd3ef8a, 0x2b57a4b1, 0xf5bdbe4e, + 0x72df2881, 0x65ace438, 0x5663f172, 0x3539a8ea, 0xa46bf984, 0x50e9149b, 0x34249d87, 0x9e2c4671, 0x0e39f920, + 0x200d97a2, 0x2640dade, 0xab166f3e, 0x51b79924, 0xd32cf8fc, 0xdd9586db, 0xf517cbaf, 0x574d0802, 0xad9aa4fc, + 0x42113545, 0x76ce6956, 0x34131fe1, 0xc8445af7, 0x8ea84c7a, 0xcff8973d, 0xa7c60c91, 0x52cdaa05, 0x8745cbb2, + 0x86dec980, 0xc9f3a7f8, 0xdbbf62e9, 0x3b94183d, 0xda93cb16, 0xe68107e6, 0x3eb2bf63, 0x64b96ec3, 0xcd2c6c9d, + 0x0ae8c7a3, 0x9cf0d23e, 0x21963d43, 0x6f93a4f4, 0xf7b05789, 0x0278f0ab, 0x14bf4a8c, 0xd3c2a3be, 0x85067a3b, + 0x3a538eed, 0x1794399d, 0x351d00c1, 0x4cf4eb37, 0xf1412351, 0xa361a9ff, 0x40b5fb3b, 0xe5520024, 0x4efcd29a, + 0x310d022f, 0x7358fe68, 0x07710b6d, 0xee728062, 0xd7610c7d, 0xd2ac21c4, 0xba3f3d5d, 0x2717aa2f, 0x27240e12, + 0x004d47a6, 0x9a7a6431, 0x49a061dc, 0x41ce6716, 0xb4f00da0, 0x4e193776, 0x79be2fc6, 0x40c2431a, 0x7290a180, + 0x905b3cef, 0xa1716a53, 0x813f972e, 0x659e52a6, 0x21606b05, 0x05db94d5, 0xf9389160, 0x725af45d, 0x5c95fa9e, + 0x81d7f6a4, 0x599ffeb5, 0x8dda6a08, 0x9dc2d9e0, 0x790e761c, 0x2722890f, 0x89ad47d0, 0xa2ea2519, 0x1738fede, + 0x3caeb508, 0x379ad9b1, 0x65c0ab40, 0x33ecc6e4, 0x7128953b, 0x3e2bf25d, 0x5bee12e7, 0xa7396197, 0x2f077530, + 0x54bac5fc, 0x28ab870d, 0x914bba47, 0xa3fae335, 0xa6703e3b, 0xfe708010, 0xe633c7a5, 0xf43ddd75, 0x0eb6d3cb, + 0xee789665, 0x45673f9e, 0x7d0fac27, 0xa6b915ed, 0x7698174d, 0x3c971d64, 0xd87a9b75, 0x4256874f, 0x6daaf805, + 0x6b403d3b, 0x8de26e11, 0xf2d7422a, 0x73ffbebb, 0xc195a1ea, 0x31e21e95, 0x0165cb27, 0xb9e1650e, 0xed75e09f, + 0x79ead099, 0x07525d78, 0xa091792c, 0xfb89564c, 0x3b9755f6, 0xabaa2018, 0x03a07970, 0xb1931750, 0x25d0412e, + 0x31fd6aea, 0x2fe25b26, 0x0124c10e, 0x4d5690a1, 0xb06fb3c6, 0xb953f092, 0xb8afe77e, 0x7eef37df, 0x5e75a400, + 0x0aa83b88, 0x3bef1f2f, 0x5dd5a547, 0x39b77729, 0x21e1172a, 0xf13ed351, 0xc45e8fa5, 0x7427fc22, 0x6495e723, + 0x2770ba55, 0x47aadbb2, 0x6a8066d8, 0xbf995b84, 0xb95d4a18, 0xab07c4e2, 0x85132ceb, 0x0cfc0da0, 0xfe2cdd0c, + 0xc350e15d, 0x8d54e839, 0xc1e9d591, 0x6f856501, 0x2f52121c, 0x0ac60eb0, 0x11dfe0a0, 0xe69a7045, 0xc73b1534, + 0x5f61ccd4, 0x28825d80, 0xb5b27d50, 0x97b0d343, 0x600edb9a, 0x9612f960, 0x125a7c45, 0x37e82bca, 0xdbf03420, + 0xe02c699e, 0xe3d0e7c8, 0x8fb050d6, 0xa6b293c8, 0x30bbae2f, 0xfafee395, 0xb345dadc, 0x9769ce5c, 0x2a27f8ba, + 0x4fcdfaac, 0xecd14e45, 0x812c95e3, 0xb93a91d5, 0x612db4ec, 0xecc3ad74, 0x845ce089, 0x46e18899, 0xeda61719, + 0x1c9f61ae, 0x6951b6a2, 0xddc57615, 0x8d2db581, 0x9ef8cb4b, 0x286f2ae2, 0x87e600c1, 0xc812bcf7, 0x64f9f74d, + 0x40c6a757, 0xb3b4e38d, 0xc55a0c0b, 0x0edb1ab8, 0x32f18985, 0xf63218bc, 0x23b1525c, 0xa724b9aa, 0xe40cab6e, + 0xf7ca4651, 0x310cff69, 0x2b5e61e1, 0x7699f465, 0x96a7b18e, 0x247e18db, 0xc94201d2, 0xe70ae07b, 0xb9adaba3, + 0xe872e81a, 0x3a507cfd, 0xc84708ca, 0xad8f7236, 0xf4b12e59, 0x673bd385, 0xa15b69f8, 0x53a3aaf4, 0x4e8f2b00, + 0xf8f083c9, 0xfb36643c, 0xc2884f7c, 0x73c9e001, 0x860af9c4, 0x216ebac2, 0x41b402b4, 0x2fd49947, 0x6382a359, + 0x1738318b, 0xa5a51360, 0xe1980d14, 0xbaa1946e, 0x34850215, 0x1567c659, 0x1e244683, 0x87bda00d, 0x31936421, + 0xe6ff89e0, 0xcb8eccae, 0x6a6540bd, 0x37b7f3ed, 0x932717df, 0xc90965c5, 0xe9bc19c3, 0xd2200a45, 0x846a1897, + 0x1c1f9e0a, 0x0a037d90, 0x1965af77, 0x97e15853, 0xd6843512, 0x3464d67d, 0x5925215e, 0x6f523fd0, 0x7a60005a, + 0x70e6242e, 0x02fa27c9, 0xb8f738e3, 0x9f9e529a, 0x4207e8a4, 0x463bc8d5, 0x82be6f3c, 0x154438df, 0xd3247733, + 0x3c38179f, 0xbab7520d, 0xcb8bee3c, 0x9afd2e11, 0x59819fda, 0xb600aa61, 0xfb0c2ed1, 0xf1f87abc, 0xd75fe07c, + 0x4fb92497, 0x9df76263, 0x7baa18ef, 0xdc029ae5, 0x36c546fe, 0x37c1ff4c, 0x68d05cbe, 0x32078f41, 0x6189b624, + 0x4fa38c44, 0x7495cdfe, 0xdf455685, 0xcc99659f, 0xe481cbac, 0x9e265d69, 0xf324a68a, 0x8c863ff7, 0x4342a900, + 0xd3f0b28a, 0xc2b32ac5, 0xb17231f4, 0xbf0b3bb1, 0xa6c971d7, 0x9e41ea03, 0xbc0cde33, 0x0b8309d2, 0x9517a700, + 0x156d3662, 0xe6900601, 0x2127625f, 0x4f0ca544, 0x4203da3c, 0x5fed7965, 0x7f6bc92f, 0x9212232e, 0xd18adcd8, + 0xbcb086c2, 0x50773f9d, 0x49632243, 0x483d0285, 0x96af728b, 0x1465b7f5, 0xdf97db25, 0x4b56dcb7, 0xd9b3a8e5, + 0xd5ff02c4, 0x80af00f0, 0x62655fdb, 0xa7768c28, 0x67a65eb8, 0x1e70ee36, 0x71b41096, 0x411a2abb, 0x6c781ee1, + 0x697023ea, 0x8ed404de, 0xf41e9019, 0x361de846, 0x73700793, 0xd07662dd, 0x93399a45, 0xda414909, 0x00bc315f, + 0xa3a51b4b, 0xdf9ce652, 0x4a22353c, 0x4fe6f4c7, 0x9fd5d209, 0x633f0ca1, 0xe4e4b8af, 0x4e3b0ebc, 0x8e0006ce, + 0x0da0e15a, 0x69daf921, 0xef23c389, 0x7ba3e24e, 0x2430ce41, 0x4f839143, 0x7ca529e2, 0xf90c1f4c, 0x2775d408, + 0xc325dbc9, 0xf0bd033f, 0x24635a58, 0xf4150519, 0xeb4ff0af, 0x9fa63a02, 0x33a2f3e6, 0xb22c0d9d, 0x09dc7b0a, + 0xdfea8e07, 0x81e89c2f, 0x070ea201, 0xf257f0c0, 0xf16b71e4, 0x56c7afab, 0x31a955ae, 0x296a9115, 0x3507eda6, + 0xa4a64fb2, 0x8c953aaa, 0x9ab0983c, 0x3398e8c3, 0x9a2737a7, 0xc61f5826, 0x2bc82c39, 0x2d241145, 0xe372ed0a, + 0xcd96e0e7, 0x87ee942b, 0x67584c83, 0x2a45b9d2, 0x3c6add94, 0xae808b77, 0x8fb2c6cc, 0xb257d33e, 0xe0076836, + 0x5b86b1df, 0x5466eb3c, 0x4420361e, 0xb582a4de, 0x404b1c41, 0x54c9fe6b, 0x176bc33b, 0xd5cc72b6, 0x7dbf3553, + 0xdc2be858, 0x68b8e2a8, 0x1d63f035, 0x9fa1561d, 0x65e285f7, 0x884c6518, 0x03314ee0, 0xd1e0163f, 0x40753743, + 0xb873eafb, 0x31c32393, 0x5d5cdfce, 0x5955b1d6, 0x3a0d5658, 0x2f0bc34f, 0x32873561, 0xb3720184, 0x0952eb95, + 0x129abea9, 0xe899e9e5, 0x03c7f5c7, 0xc394b527, 0xf957df9a, 0x7699ccc7, 0x599dd10b, 0x9fc85501, 0x1de5c38f, + 0x25c046d4, 0x1da36322, 0x07a8a779, 0x44d475cd, 0xbfb91847, 0xe736f71a, 0x7b348cb1, 0x40dc613c, 0x5ae42716, + 0x33135de4, 0x2e7a3249, 0x7a55d291, 0xccc27f39, 0xd4601f74, 0x0f0fe825, 0x59f20218, 0x85ddc2b8, 0xb700776e, + 0x2b9bc2b0, 0x334a5ac3, 0xf829dfed, 0x9fd81aaa, 0x122ee190, 0xac98cdfe, 0x5a819ef2, 0xa901187d, 0x0f0e7910, + 0xa475390a, 0xbe84e51e, 0xfd3fac60, 0xdb19cde2, 0x23fa91a8, 0x9acc3285, 0x4ae2bb68, 0x77068e52, 0x93d6707b, + 0x5482f83a, 0x926643d8, 0x50137040, 0xfde303b4, 0x0713ebec, 0xb9fd3d6c, 0x624247d2, 0x8f2000db, 0x58790af6, + 0xee4231f1, 0x068e2f6e, 0x57568319, 0x4205d310, 0xb70b8a74, 0x47fe8897, 0xdb92a66e, 0x0a603f43, 0x5b7e04db, + 0x4eb1d95e, 0xacad7353, 0xe2ca72a8, 0xb5561270, 0x0bc88917, 0x913f85a9, 0x30acd009, 0xdfd5228b, 0x2d975adf, + 0x6d761442, 0xa959ec75, 0xce87fe1f, 0x462e5168, 0xfa8e252f, 0x23caaf5d, 0x88d08ca8, 0xbda33179, 0x4b292f0d, + 0xc766e8cc, 0xdf1aca80, 0x91438c37, 0x5365bbf5, 0x4aa10464, 0xba0412a5, 0xf9c195ff, 0xe92c94f9, 0xcf93799c, + 0x74e93251, 0xa1ff1a81, 0xafa8c93f, 0x7b0befbc, 0xf78ea9e7, 0x84d54ce2, 0xa7ad12ef, 0xde62734f, 0xddf3c78d, + 0xa8236b1f, 0x15ac9a0b, 0x022e43da, 0x4296c561, 0xf8a65783, 0xf0f4ef92, 0x0e2c098b, 0x07c451d0, 0xec3801b5, + 0x2487cacc, 0xb7bcbd1f, 0xcbd302b6, 0x29f36c5b, 0x465372f5, 0x402da436, 0x222e71e8, 0x31074ae8, 0x0a1646ae, + 0xd826af93, 0x68cc3b68, 0x76b9ba9b, 0xafe8eccf, 0x06194058, 0xaf42cc2e, 0x64c8e577, 0xf388b429, 0x326ba7e8, + 0xa31c5cce, 0x6a1c426d, 0xfb8a0a06, 0x36140cbf, 0x73cbec6d, 0xef785302, 0xbc828bb1, 0x7005f8fa, 0x09d6d4da, + 0x3aca140a, 0xc40b6256, 0x655aab55, 0xc49355c8, 0xc972ee69, 0xaa8114e9, 0xef489c3f, 0x862dde7f, 0xc3e001df, + 0xf731d788, 0x0f6c2e1c, 0x1016d0a3, 0x6bb68800, 0xe2997e0a, 0xd70ad551, 0xc21fdfa5, 0x0faab822, 0x814906d3, + 0xdb1b4d10, 0xcb24cde7, 0x1cf2dc91, 0x1fa46d02, 0xa47b3528, 0xc1650099, 0xc2032b39, 0xcb671367, 0x5ef29661, + 0x32df9bf6, 0x2b8a3a98, 0x5395d489, 0x1860644f, 0x7e395900, 0x9fd3d41c, 0x0c45cd48, 0x7668a70a, 0x26f7518f, + 0x09c1d892, 0x90f35cbc, 0x7cc559f3, 0x2ca9f3a5, 0x3799f988, 0x0e6340b8, 0x0af9c366, 0x9ec51c7b, 0x507c2bfc, + 0x0e8e0601, 0xeca9c493, 0x457ed610, 0x6b39445e, 0x8a9209a0, 0xdd417b89, 0x311a816e, 0xdc6ed7ea, 0xb8a2f4a6, + 0x8dbd7190, 0xd6f7347f, 0x9c28d2f9, 0x351d682e, 0xb6827bad, 0xbe2c3bb9, 0xbf5ff5d8, 0x1a1c00e0, 0x4342e3f8, + 0xdd6ca254, 0x6ca2e4f0, 0x924d770a, 0xd84e36d4, 0x094c658b, 0xda90c4a0, 0x4bfcee8d, 0x718b23e8, 0xbbd2c9a1, + 0x7859b665, 0x697add42, 0xcea00180, 0xe3074a5d, 0xe5475087, 0x5fa78bce, 0xc945f897, 0x417d6997, 0x8e7af417, + 0x5f19b95f, 0x6aa6274b, 0x5ecc257f, 0xe7c34759, 0x16a30bbb, 0xfbb5c575, 0x26a10b1a, 0x6ec36580, 0x2d2f5958, + 0xa9ff45ae, 0xf684877b, 0x4d858b18, 0x6d828265, 0x74be56fb, 0x91b88d21, 0xee173868, 0xe42f7dec, 0xd21841cd, + 0x366cd1f2, 0xaf4bf275, 0xed25f60e, 0xc481cfe7, 0xdedbf7ef, 0x974e09a0, 0xb657cd1b, 0xbf605878, 0x604da2d7, + 0x6f9413cc, 0x980bd4e8, 0xa28db0e3, 0xed4794f6, 0x41aa6ad6, 0xdb478567, 0xa9956922, 0x32766180, 0xf5ca3f74, + 0xf74c3e23, 0x463fbe22, 0xd3122e73, 0xfa99f829, 0x5397b281, 0xfa3f9722, 0x9bb62007, 0x853028fa, 0x04e3310f, + 0xa6a58b54, 0x980e7a89, 0x39dbe144, 0x2698154a, 0x35ea7b48, 0xb6ae1dc0, 0x7015ae91, 0x140cc1b0, 0x0b46832e, + 0xf95384bb, 0x44fa12db, 0xdacdfb8e, 0xc68b7470, 0x44fa5216, 0x1cf0c9ee, 0x68ed1b58, 0x7417d801, 0xdecfda63, + 0xa1d9a24f, 0xef80b91c, 0x3b875217, 0xd8c491ce, 0x38254d5f, 0x205054a6, 0xd9f36130, 0x4dbe33b9, 0xbf6dfe16, + 0x2751101a, 0x7dc67d90, 0xafa34058, 0xf13f7111, 0xaad3d9d0, 0xbe8eb401, 0xde9b5f89, 0xce43ac90, 0xa9c797a7, + 0xf800dee2, 0x10a939ed, 0xabc462ec, 0x0bca3963, 0x44d2491f, 0xdfd3dfe2, 0xa2726bf0, 0x66163177, 0x7a0c13d4, + 0xaffb89bb, 0x572a36b3, 0xa10a3482, 0x45142eed, 0x1bbe73b7, 0x8dd15fcb, 0x88b99dcc, 0x98c6b4aa, 0x066fbb16, + 0xdda53bb3, 0x8bd21276, 0xbef6e6a8, 0x5ea9b256, 0x64ecb3d1, 0x6bf4b9ab, 0xa5ab4530, 0xb8d6f89e, 0xbbac536e, + 0x0859b20a, 0x56e5fe0c, 0x14bdbfff, 0x485499ef, 0xa4d223fb, 0x50e791aa, 0x040380fa, 0x09213c82, 0xc5928a91, + 0x5c9679cf, 0xd4110182, 0xff6f486d, 0x42e09d52, 0x77941729, 0x1f940841, 0x2ad42039, 0xf04bbef1, 0xf3cbdd89, + 0x7f6eb158, 0x5bcda246, 0x3ef7bbb3, 0x87cfee98, 0x4a8cafc2, 0x0b3ebeaa, 0xd6d598f4, 0x28cb241e, 0xa989c68d, + 0x1e18967b, 0x72d6333e, 0x06d1c867, 0x2ee86abf, 0xcedefa78, 0xdea90824, 0x5b5b3899, 0xef63a82c, 0xd809bc64, + 0xde58f068, 0x9c1b60f7, 0x215c4ad0, 0x8bbd5ead, 0xc4455a0c, 0x8a430748, 0xb62f7754, 0xbf544bbf, 0xd3032de8, + 0x8ec8079f, 0x034611b2, 0xdeeffe9b, 0xb221a7cc, 0x54fb0980, 0xd2453a51, 0xf874375f, 0x951b58d3, 0x4ae7f60f, + 0x3fce4e4a, 0xeebb2d82, 0x2dce3bbb, 0x975fb7c6, 0x11778294, 0x385d3513, 0x7f604673, 0xe6d25fc7, 0x2cc562b5, + 0x22a401bf, 0x7ca60449, 0x9313eb15, 0xe3e7ced5, 0xc43048f6, 0x5a37ee9a, 0xf0f464d5, 0x339c8298, 0x3d41f0a5, + 0x924e1233, 0x7d230e77, 0x75b92fad, 0xb379be44, 0xdceab32a, 0x064d566e, 0x47e226a0, 0xd2596dd0, 0x4e9b5bd8, + 0xceed6661, 0xa850171c, 0xfc1b2d6b, 0x06330387, 0x2a8ab2ca, 0x098ab8ff, 0x0f4fbf8a, 0x8d9d528e, 0x41f9d623, + 0x5be1a9ab, 0x6bbd4174, 0x7d9d049b, 0xf9ed326f, 0x3acd4bd8, 0x95c1a69b, 0x25009cc2, 0x64c4652e, 0x94ee05d4, + 0x4afcbc32, 0x83875634, 0x2aff8fe8, 0x022dda37, 0x381d114f, 0x978f8bd7, 0xa9611c36, 0x86944a65, 0x5a8708e7, + 0x58852807, 0xe118fa92, 0x28c5b824, 0x70fe2e8b, 0xb24f9476, 0x59fde72b, 0xd755920e, 0xb88616ef, 0xf5909012, + 0x5bf67c0b, 0xe16577e8, 0xf8109618, 0x81bbb798, 0x9bf1e861, 0xedd548d3, 0xc6066c63, 0x057dad7d, 0x9ad4ab46, + 0xde6e80e4, 0x45c27d3f, 0x833c2ed3, 0xbae0b63f, 0x22800af6, 0x93749f0d, 0xadd0e3c3, 0xe55fe67d, 0xcdf702f5, + 0x80f038c2, 0xec2eaef9, 0xccff8744, 0x17b5cab3, 0x513c5d47, 0xcee43528, 0x8e09f336, 0xa6801817, 0xe9d22d9b, + 0x0b69021b, 0xc785cf86, 0x5c8ffda7, 0x8bde804f, 0x60d6fc85, 0x8df77b70, 0x19030b83, 0x3a3bdcbc, 0x360f0aed, + 0x4f59033b, 0x2f9f9ab2, 0x3a032f80, 0x35dfde06, 0x9a719f5e, 0x6e6ccb97, 0x2b407136, 0x0445d761, 0x58561e41, + 0x76d13c27, 0xd88b0c12, 0x3ec4d23c, 0xd8d92998, 0xef06f7e2, 0x0ca0d8bd, 0x7c5dce51, 0xaec47c18, 0x226d816c, + 0x41001485, 0x37e3b29a, 0x4386ed75, 0xf7d8ed38, 0x934e2fe3, 0x2953ac02, 0x73717e11, 0xab19a822, 0xeab83cb2, + 0x0c75b65f, 0x48fc3e30, 0x21f12a45, 0x1d2ea428, 0xccaf019f, 0x384e3346, 0xa11207bc, 0xaa0f096c, 0x6d884afd, + 0x3f1553cb, 0x690b7f8d, 0xa3bd3c22, 0x4206358e, 0x6cd2eae9, 0x16e9e427, 0x65a1b4e2, 0xfa835e8e, 0xbf553a7d, + 0x88a8b53f, 0x05afdbf6, 0x3351caa8, 0x0074bf8d, 0x1223caf2, 0xf06e9aaa, 0x6dfca291, 0x2e0079bf, 0xd79a5498, + 0x37a2c7ab, 0x96fc22a7, 0x248be6f7, 0x80dbf7be, 0xdb3d255c, 0x6c0b5bf5, 0xedc4d1be, 0x4eb0340b, 0x46719b59, + 0xeba9de13, 0xd658a813, 0x36a25354, 0xacd0c756, 0x1dc6a7d7, 0x950e82da, 0xd6ca1959, 0x8f8f0618, 0x34b29cf4, + 0x94f8d19f, 0x5d3bfb38, 0x5f94537e, 0xd5b29f04, 0x0bdf1309, 0x4a4e7e55, 0x8b58db51, 0x95a17dd8, 0x4276a396, + 0x279c02ac, 0x4552313f, 0xf96969e7, 0xa036b052, 0x43545df8, 0x9a3b89b3, 0x9b673491, 0xbc29be01, 0x9c3eab28, + 0xb01264dc, 0x31c58fce, 0xad84d835, 0xfa3a72d7, 0x7948a0a7, 0x3c411a5c, 0xa85a1bfb, 0x5b543d14, 0x360ef716, + 0x5139dafc, 0x2e823eab, 0xf4aa489e, 0xe5c73fc0, 0x9cd5e967, 0x57a32dcd, 0xf3e34620, 0x1a8065db, 0xb1759e50, + 0x7afaa71c, 0x1f610b99, 0x4ae28d28, 0x6977ebd8, 0xbec97d2d, 0x4d74a548, 0xf4b3f3e2, 0x96f64fee, 0x26fb7560, + 0xe6d212ff, 0x1a40d971, 0x2e4f1414, 0x670024e1, 0x2b0309dc, 0x13449092, 0x7f2a7451, 0xdf7c4012, 0x1ebfda8a, + 0x10b72177, 0x8642e465, 0x27790f86, 0x4e5061d6, 0x4ef056ec, 0x9b7807ff, 0x2863b329, 0x28955724, 0x4609db3b, + 0x60ae2abe, 0x447d98eb, 0x30eb705f, 0x42d97c15, 0x772638a7, 0xff4bd30f, 0x77d47ca0, 0x1a33989a, 0xddade06d, + 0xf54c90df, 0xfa56b8b4, 0xfb27374c, 0x08ecb317, 0x80a92bd6, 0xa4caeade, 0x6788dc81, 0xe436ecce, 0xc2d08c14, + 0x84235bc0, 0x060ce3f3, 0x109f573e, 0x861f484b, 0x881c7e05, 0x083aa401, 0xbd59b573, 0x3a37c9f8, 0x77d2efe6, + 0x8125fee9, 0x8ced1d17, 0x70cfcbe5, 0x4c0dfe20, 0xc9e5ead5, 0xe83131d0, 0xdd2b8512, 0xd9174d1d, 0x4bb07f44, + 0xca30d8ee, 0x0cfc0f8f, 0x2151289d, 0xfcdf091c, 0x162abdd6, 0x558af934, 0xc23dffa8, 0x78fccb05, 0x500a448a, + 0x7c346926, 0xd0ee5df9, 0xe299389e, 0x586fdc65, 0x6ac9b555, 0xe36f8487, 0xff4a75eb, 0xcdaf476b, 0x24efa6ed, + 0x8c9e912b, 0x49e8dad5, 0x76e1dde3, 0x5cb0c256, 0x90c35e5d, 0xdf566728, 0xdb5905fc, 0x8dce5c84, 0x2f6fbf39, + 0xf9e7f0f2, 0x061d8792, 0x3b35e98b, 0xfbed9249, 0x023328b0, 0xd4919fea, 0xb2bbd743, 0x9b932da4, 0x37a41e7a, + 0x778da1ec, 0x048c99fb, 0x4ff2ceac, 0xc78db9da, 0xe00c388d, 0x63b9ff63, 0xc4555999, 0xc80fa854, 0x4afcb644, + 0xa6e2e309, 0xd1cf7199, 0x169f9f91, 0x8e7cd4e3, 0xca585ce4, 0xc30e4760, 0x1357c88f, 0x59a0ad2c, 0x436edff9, + 0x5f863aa9, 0x232e29bd, 0x8ee642e6, 0xdee514ad, 0x1683f4f2, 0xfcd143ba, 0x932391bc, 0xcea6da13, 0x227763bc, + 0xae7240d2, 0x6bf71216, 0x82b2a5c7, 0x3fc4fcf4, 0x531f0faf, 0xfbd98a70, 0x7eaa53e4, 0x55ef6a42, 0x444e1a5f, + 0x0a40eefa, 0x70db9ef5, 0x1ab57467, 0x33fc10a7, 0xf31bb7fa, 0xa0f9f180, 0x1311ecc5, 0x28f5abe3, 0xf0ba73b1, + 0x8252bf3b, 0x3efa0668, 0x46c207c5, 0x63b9a42c, 0x8794280f, 0x823add2a, 0x2b496d6f, 0x5583900a, 0x489fa820, + 0x31343d5e, 0x97c75945, 0x332eb976, 0x90c9c11d, 0x4bb5536d, 0x60a4ab6c, 0x1b0e9369, 0x8eafdeef, 0x1e6b2d35, + 0xc9ac5f8c, 0x5490dfb4, 0xcabaf0b7, 0x09a6c9a8, 0xe8a4817d, 0xbd95a034, 0x11b77cfc, 0xf58fa7da, 0x6a1c7295, + 0xb65ae610, 0xb4b18b9d, 0xb6b2cf06, 0xe4c526a6, 0x714ff8ed, 0x393a5ca5, 0x98b1e821, 0x493b6614, 0x8dbe9b08, + 0xe934119a, 0x127cd42d, 0x4bbeae95, 0x8c9c96c4, 0x097ccbc7, 0xace0afa1, 0x732f4037, 0x33613f9e, 0xc9b74a0c, + 0xf1591fc1, 0x3611f6f9, 0xf2d68446, 0xe5646c29, 0xf837f0b0, 0xb62f424a, 0x1bfa7ba8, 0xe6fe38a9, 0x2db44afa, + 0x2bc059db, 0xad69d10a, 0x7cc43cf4, 0xe60faf15, 0x5fb54683, 0x681a05bc, 0x52535539, 0xaa776be2, 0x99d6c074, + 0x61a2dee8, 0xbaeaf0de, 0x5c24418a, 0xbed16f07, 0x1f318265, 0x2092cbfc, 0xd21995e7, 0xf9cf94a6, 0x23c71cfe, + 0x66438f6c, 0x2f827044, 0xbfcc9fa6, 0x1a14f91b, 0xe19ed5f3, 0xff3a0c74, 0x0ddec70a, 0x1fb1c182, 0x1bd969fb, + 0xee6e7ca8, 0xcb8cc124, 0xa703b7ed, 0xaa4b81f5, 0x0d686ccc, 0xcd8b9a2a, 0x95982f05, 0x9ee810e4, 0xa197d2c3, + 0x7fbac1ed, 0xa6f13e0c, 0x14f755be, 0x4e50f00d, 0x0184b07f, 0x211a7cff, 0x11a25b75, 0x8dff47d7, 0x7f62e6d1, + 0x1bd81813, 0x14cbad9d, 0x631f8b20, 0x8f27668b, 0x285f40da, 0x0b82734c, 0x4a4553e9, 0x9a201e37, 0xdc0ddc15, + 0x807e24b7, 0xa15afc2f, 0x57287689, 0x043d155a, 0xf28a4823, 0xe143c76a, 0x680e6a60, 0x1510a548, 0x26c37ab0, + 0x555aa3e6, 0x399c9d23, 0x0ad5362c, 0xe36a0423, 0xe4b7d819, 0xa4995de6, 0x05aec66c, 0x5e9059fe, 0x23959de9, + 0xb12bbe3b, 0xa3801113, 0xfa02a50c, 0x5222bbec, 0x2cdd394b, 0xa7893d78, 0x5f2dd938, 0x697adb66, 0x301316f5, + 0xf1bf47e5, 0x6e09ce9f, 0x393ad495, 0x31d789c9, 0x4046ac20, 0xd182dc1b, 0xb4e4f328, 0x73a055d1, 0xa2d2a5e8, + 0xe59a8fe1, 0x272bb5cf, 0xaf04488d, 0x252f53a9, 0x9d918712, 0x4ec2fbe5, 0xefac834f, 0x9e772a4e, 0xcd9b9029, + 0x149bd2ef, 0x89bae615, 0xb16ed0eb, 0x0f80aa04, 0x10c879f7, 0x0a7133d5, 0x10a2e051, 0x07a1ce5d, 0x0cef4803, + 0x8f4c0515, 0x31020d4a, 0xc79605ce, 0xadc04155, 0x55483e4e, 0xbae562b6, 0x386f8537, 0xbba791ea, 0xc1bbab0a, + 0xfa24dccb, 0x760a11d0, 0x907c1349, 0x15a81098, 0x2b2d2a7f, 0xef4632e0, 0x14ccc5b3, 0x5ef9511f, 0x5bf9f73c, + 0x719076ab, 0x6538730d, 0xd2f4fe1d, 0x7288d58d, 0x2e56e88f, 0x5b0e78bb, 0x826ae505, 0x4a369dff, 0x4bdd8010, + 0xb6360692, 0xc1218f48, 0x1442147f, 0xb3fb22ea, 0xfa314369, 0x548a885f, 0xd5c9a226, 0x7e75da13, 0x14d8b186, + 0x0600f183, 0x1a34506f, 0xf0b97c5c, 0x170c1693, 0xaf4ff566, 0x836e19ac, 0x3868c45b, 0xd47afa17, 0x2221abc1, + 0x76d903d4, 0x32ca4cba, 0xb397ea8b, 0xca1f165d, 0x52d14fcd, 0x217b681f, 0xc1408f6d, 0x822ba989, 0x10092cc7, + 0x18e5601b, 0xd0df8e82, 0x4d2d7196, 0xcf67b9be, 0xfa5ec85a, 0x170ec24b, 0x90085a79, 0xd38729fc, 0xa8b717bb, + 0x13cc64ce, 0x82b62be6, 0x035acfea, 0x3605e661, 0x1e9656b7, 0xffa81336, 0x88f54167, 0x174e77a6, 0x3aae90c4, + 0xa25f1205, 0x8c604321, 0xead50492, 0x7c2ca727, 0x25f434f2, 0x735f1bec, 0x507664cb, 0x04163f3d, 0x3b178ae5, + 0xea5330d4, 0xaed8c53f, 0x5efa6f66, 0x14edaf61, 0x562e1914, 0xcddbdf28, 0x1478990d, 0xf1a88602, 0x926a1162, + 0x449383a4, 0x3ea5f10a, 0xa3edfa56, 0x77b40817, 0x899b348e, 0xc5603a86, 0xc62c533a, 0xb6466dcb, 0x8ed400d3, + 0xa3d7fdee, 0x32f4a735, 0x85599ad3, 0xc30018b3, 0xd4649221, 0xd61bf97b, 0xba9e23f9, 0xfd9fb8d5, 0x868ab280, + 0xf2c74f06, 0x6e9cf47d, 0x9d398695, 0xb3083eee, 0x94f39801, 0x219239e7, 0xe095af93, 0xdd425e4b, 0xed57d84d, + 0x38b86511, 0x2257ceed, 0xe1f66ecb, 0xd0fe7f3e, 0x4c0bdaed, 0x048ba690, 0x749bff08, 0x6c556756, 0x33a4d2f4, + 0xef14bbbe, 0xcbdff04a, 0x47667bca, 0x0b7dce66, 0x6f58af07, 0x61a53797, 0xf44e8456, 0xa941c215, 0xe4f62234, + 0x103b7701, 0xf90f2d55, 0x209d17a3, 0xe54dd599, 0x0e6ce16c, 0xd9d63ab0, 0x333a544e, 0xd94e720d, 0x8e04ed57, + 0xed8a801a, 0x6911d12b, 0xe2d411e0, 0xaa2eff46, 0xf4039bcd, 0x6f2eae0f, 0x4c781567, 0xbf49f25f, 0xb0beaf52, + 0x2f12cae5, 0xcb3d9a7c, 0xb64035c5, 0x2613f145, 0xa9839baf, 0xcb4a6d5a, 0x746c69d8, 0x6ce4706f, 0x76f7a6a9, + 0xe341fa47, 0xad893e8f, 0xb3ef1649, 0x82892a07, 0xa335cf7b, 0xfe282596, 0x57eab128, 0xae349a7a, 0xdbf74a7f, + 0xee4b789d, 0xe7a18fa1, 0xe761b722, 0x7a6e603d, 0x05d13700, 0x288b226c, 0xc613643e, 0xbfa60a0e, 0x711a0b1d, + 0x4a5ce0a8, 0x0fc86fd6, 0xf082a4ad, 0x968fe4b1, 0xa26cd523, 0x318ddd8b, 0x7a656274, 0x032a858c, 0x54fe3374, + 0x0f1fba8b, 0xa3f4136b, 0x4cba63f2, 0x1512b1b5, 0xfbd92f2f, 0xfb4680bb, 0x3735e497, 0x41e45d6f, 0xe8d8971b, + 0xf7ac48fd, 0xa8583940, 0x110c6ce8, 0x3ffb057c, 0xda90eb98, 0x6001ba3d, 0x8b2d6866, 0xc88bcb8b, 0x57b0ccc5, + 0x7503b6a1, 0xe0ea19f0, 0x7b78f6a5, 0xed00d166, 0x20d21811, 0xd76aae09, 0x941e852d, 0x417afbe5, 0xee9fb1f6, + 0x3675f977, 0x42184504, 0xe54acc43, 0x6df50f8f, 0x13bcf1d6, 0xa3e0c107, 0xe05c36ac, 0x4ec5dea9, 0xccd72edd, + 0xfa4b5d15, 0x28fc073b, 0x107ad3e3, 0x3f8add5d, 0xd95862d9, 0xa220713e, 0xa81a7b31, 0x4219c57d, 0x8fc09a97, + 0x1d10b9b3, 0x62c650db, 0x21df284a, 0xff6439fa, 0x95af2513, 0xdacd4fc6, 0x6753eeae, 0xc771f199, 0xb4e94cf3, + 0x2cd27d22, 0xc52e1263, 0xc77f0143, 0xc7e60791, 0x8a82898c, 0x4dc90ec5, 0x57b0f683, 0xf9110154, 0x2fb3b666, + 0xd72108db, 0xa0631544, 0x912e59ad, 0x15bfefc6, 0x4e924cdc, 0x83eca698, 0x012081a8, 0x3b38df20, 0x9339c4fd, + 0x411c0b87, 0xbf060ff8, 0xffbbfd24, 0xae88a871, 0x4576dad0, 0xc2e070df, 0x450bb228, 0x4b01b46c, 0x1978f9e4, + 0xef6e6c59, 0x5aace7a8, 0xac5c23fc, 0x8ca802c3, 0x3e420c08, 0x5c2954b8, 0xc1c3c504, 0xe375bcc9, 0xb83b5151, + 0x4dfd3f1a, 0x4cae4f70, 0xe7c8e75d, 0xac21bd87, 0xd57d5e72, 0x001d2062, 0xe97814c3, 0xf3e681b9, 0x13bd35d8, + 0x5fb15537, 0xd207ce15, 0xd38e354e, 0x2daed530, 0x713b5ad1, 0x6ae1c049, 0x627f819f, 0x8b551a52, 0xfd107290, + 0x690a551b, 0x11946e26, 0x681692af, 0x7f2a1220, 0x905a5b72, 0xef1cf8fe, 0x58b0dfe1, 0x2e3912d5, 0x82b0a177, + 0xbd681d7b, 0xd8236b25, 0x74b79b7f, 0x927f24c2, 0x3ab2f75a, 0x1b90eec0, 0x387cdd2b, 0x13ad03aa, 0xa709a9c9, + 0x937fc129, 0x439242ed, 0x5ac8997f, 0xd8d73d08, 0xdf29c0a5, 0xd4b25b6a, 0x6322219a, 0xa7c5e902, 0x1e1e5a4f, + 0xabd9f1b3, 0xf29e1031, 0xd7518c13, 0xcd372046, 0xd0777306, 0x3515dfc2, 0xcdcc9a24, 0x3828496c, 0x2995839b, + 0xb459d25e, 0x5adf6e5a, 0xeffea06f, 0xd092f8ae, 0xc47cd05a, 0x6c0bddce, 0xe6686c98, 0xdd4aed5b, 0xc8df9f88, + 0xa09c088b, 0x54f3805b, 0xb30126b2, 0xc39c6502, 0x2da24472, 0x1be19b27, 0xb00a2616, 0x5a6a9ace, 0xd003002f, + 0x88b71c6b, 0xe09147d6, 0x8ccfbaa7, 0x1d019664, 0x24e8126e, 0x4a69d5e3, 0x3681956f, 0x709654c3, 0x17c8fe87, + 0x03a251a0, 0x9873aa4c, 0xe0627cad, 0xe2460f20, 0x42d4c987, 0x17b23efe, 0x9ad3fa17, 0x709e64e8, 0xbef8e5ef, + 0xe5f09ab6, 0x2d63bc12, 0xd8b4cee5, 0xecbf073d, 0xe038c0de, 0xac490405, 0xd8b5003b, 0xd761b25f, 0xd46a0bda, + 0xf5f9c977, 0xb8134077, 0xd0df6e15, 0xf9e9b4c0, 0x028f0c9c, 0xec00b4a8, 0x1c762592, 0xaa55c4b6, 0x8e8bccf4, + 0xef19668a, 0x36ccbdef, 0x4cf9a8ed, 0x4179d3bd, 0xe5f74f40, 0x28a1e9a0, 0xcf2a93a9, 0x4320214f, 0xf80cc02d, + 0x9342158c, 0x2c54f538, 0xfe493163, 0x631a0eac, 0x04d03ded, 0x21ff6c9a, 0x89e53bfb, 0xbb2bed13, 0xba1e20e1, + 0x11d1ead2, 0x69a274fd, 0x4d89bc7d, 0x4dafaa7f, 0xe216e399, 0x7a5fa7c7, 0x98cce4ae, 0x4fefc306, 0x1322bd51, + 0x839ac49e, 0xf2f0e7f5, 0x9d29f8e6, 0x59e07c4a, 0x70eae979, 0xe486e851, 0xc5b5cc73, 0x0d0d479d, 0xf1be3804, + 0x331224d5, 0xc8b59e07, 0xa477d49a, 0x41106c65, 0xbba03284, 0x914c4377, 0xafad450e, 0xd96daeb8, 0xf19b0863, + 0x9feb6669, 0xff4a671d, 0xefe5fe74, 0x937ff5bf, 0xc5607f2a, 0xa82f3434, 0x1151883a, 0xb7a38a4e, 0xbee06339, + 0xc781f9fe, 0xdc1bf12c, 0xed16225b, 0xa24ed0ab, 0xb6d61e61, 0x8ffe636e, 0x387e3d0e, 0x6a8540a0, 0x383fc618, + 0x6ff4b03a, 0x89f4c620, 0xb886960e, 0xec85fd5a, 0x531e1923, 0x1083507d, 0x4d0d493e, 0x6d277128, 0xc2c3136c, + 0xbdf0aecd, 0xb9564c12, 0xd343900a, 0x688fe661, 0xd05b1e6f, 0x155ba267, 0xfb0466ed, 0x2026d2d7, 0x5e343ce1, + 0x7ed59994, 0x6ccb88f1, 0x663707b3, 0x036b11db, 0x4b0b0f47, 0xea06fbe6, 0xc1346622, 0x6a135347, 0x62ec331d, + 0x2e2fc544, 0xcf8d92f9, 0xf1fe3939, 0x49b62fa7, 0x9d9140b6, 0x5544cef9, 0xc35c6584, 0xf9fd8a10, 0xddeca3f7, + 0x5764c70b, 0x0306a48e, 0xe3cacc50, 0x445edfa5, 0x59a574e1, 0xd9b005a2, 0x91d5e91d, 0xcaea41e2, 0xcc4444d9, + 0x7a7303f7, 0x82307b51, 0xd6ad83cf, 0x62af50eb, 0x96af6449, 0xcc0df0d9, 0x2596b39d, 0x26cba6a2, 0x22e27301, + 0x450c2560, 0x487d5747, 0x0d5affde, 0xcd0eebfb, 0x97e69044, 0x502844b7, 0x946b40e0, 0x65e28825, 0x0b0fae40, + 0xe4615054, 0x66749ed5, 0xa580a749, 0xbc6ae613, 0x2069d26a, 0x8191cd29, 0xed964b83, 0x9029bb34, 0xee4f170d, + 0x5520faa8, 0x98ad318d, 0x723c6a05, 0xb8db5ae3, 0x46186d81, 0x1764f1b0, 0xb114c7f1, 0x11a436e6, 0x4991bdf1, + 0xaba5f2ca, 0x4c0aada6, 0x7c166009, 0x516d55b9, 0x27967628, 0xa63e9e1e, 0x91912ea1, 0x17b0ac68, 0x907f6ebd, + 0x5f3c6a54, 0x79df5a3a, 0x11054127, 0x903960e1, 0xfc94ef4b, 0xcf3e3404, 0xd5ddf20e, 0xdb5b2827, 0x4673c7c8, + 0x8550252f, 0x0b053525, 0xc553323a, 0xab62767d, 0x690db6d7, 0xfc53ff48, 0xbd10c599, 0xcdbab953, 0xa3e480e9, + 0x1266f7d1, 0x358cb5ee, 0x4e004756, 0x66222de1, 0xf2ac12d2, 0xc6be3807, 0xb5c412cd, 0x254bc8fa, 0xe66a7955, + 0xeecd2e0f, 0x061662c8, 0x4ce67162, 0x8b314a77, 0x096b30e2, 0xd3f8428b, 0x83292f12, 0xab8ad4fc, 0x2a6d46fb, + 0x5ca8aaeb, 0xfbb43273, 0x7b0abbcf, 0xc26007f4, 0x93983296, 0x492852a3, 0x167660ff, 0xa0b39b39, 0xa7551aa8, + 0x907704f8, 0xbe4a728b, 0x4dc92f44, 0x4b4dfc97, 0xd1ab4e7a, 0xe51960c1, 0xee09c84e, 0xf5e4233d, 0xf3946a62, + 0xb751518d, 0x6a9b77ec, 0xd09f31b1, 0x520ce104, 0x66b49a18, 0x148020c4, 0x49f764ec, 0x2c1f5e43, 0x063889dd, + 0xd7244f75, 0x7778df76, 0xe6ca3154, 0x96eb9962, 0xd2a9d5f8, 0xc612b604, 0xfbe176ad, 0x829d5ed5, 0x9705170e, + 0x9421fe6b, 0x963c265f, 0x3cebb0b3, 0x1493b29c, 0x23666dc5, 0x3dec8b2b, 0xc075d851, 0x393f76cb, 0x6e513608, + 0xc4fb785f, 0x46f9f2c6, 0x82f84631, 0xaa83309a, 0x01ffdecd, 0x8584dddc, 0xd0be2151, 0xb2f977a1, 0x0e68bb9b, + 0x72876fa2, 0xaefe475f, 0x352ae319, 0xd4c27516, 0x98188a6a, 0xfbce9a9b, 0xfa252a51, 0xf0ff4dd3, 0xd033207e, + 0x997dc54e, 0x8b698872, 0x3a1c62ae, 0xb48dcdfb, 0xc06921b4, 0x73abb7af, 0x4e98a651, 0xdd313f75, 0xa3a2d6ee, + 0x412903b7, 0xfd5e9e2e, 0xcb9dc92d, 0x59df272e, 0xc44ceb55, 0x6feec807, 0x5a97af29, 0xa11319f9, 0xfc2922a0, + 0x7d6d0662, 0x5ed8434c, 0x3903d708, 0xcd77a8ed, 0x4109dce5, 0xe8154f51, 0xc618745d, 0xccf34810, 0x73ddc671, + 0xc00c9277, 0x6ffa21b9, 0x2e87e96b, 0x5308f686, 0x33f55661, 0x7f490d85, 0x39e149f2, 0x5fe6069d, 0xddba494a, + 0x0dda5c47, 0x012cbba4, 0xb7b17293, 0x0194a52e, 0x07a05831, 0xd36917a4, 0x621ec732, 0xdb4a8d91, 0xd4bb1c18, + 0xb6e57e35, 0x0c82c2a5, 0x9ad4ea09, 0x647c0ae0, 0x2f6548d5, 0x66064edc, 0x4997184c, 0x0bf2982a, 0x1d83bff3, + 0x929da04b, 0xcca2d77d, 0xe8878d13, 0x37471db7, 0x70676225, 0x3ac2257e, 0x8ee8bc16, 0x55277e28, 0x8bdc9044, + 0xed064850, 0xe0557111, 0xd2c5aa97, 0x43ea7ade, 0xdb9463ba, 0x2a1a4369, 0x5bd23f9e, 0xda9d42e7, 0xd7daf882, + 0x1445c0a2, 0x43679c4d, 0xb6b78623, 0x13c87361, 0xfd3258af, 0xbd7f6d81, 0xb979db50, 0x4ca8138a, 0x66468052, + 0x2a0c8ed4, 0xa7dbcee4, 0xc3724d5c, 0x438fb2db, 0x60cc99e3, 0xea3991c6, 0x8ea6f2d4, 0x0fa93ec7, 0xaf121fa6, + 0x75232c2a, 0x458a7db0, 0x0c55ceeb, 0x8e4416fb, 0x7038b95e, 0xae6e9dca, 0x0eede105, 0x0753934b, 0xe4664a39, + 0x50b4f35e, 0x9ce40e55, 0xfdcfced6, 0xde2a4336, 0x3d0dd923, 0x869fa502, 0xe8594b1f, 0x29484c3b, 0x524c5f09, + 0xbcc5dc83, 0xbf7c5332, 0x93730581, 0xf0d0c2ef, 0x0fa90930, 0xa5d8386a, 0x21286fde, 0x9b81884d, 0xe5c559fa, + 0x570900f8, 0xf5795ea3, 0x221883df, 0x13f748c3, 0x7f89c8f1, 0x427835b7, 0xc398bb85, 0xfcfd6ec0, 0x85fb165a, + 0xe7fd4a55, 0x077e58df, 0x701ec253, 0xf4243c18, 0x11ea6f06, 0x87a07da5, 0xa966e144, 0x11d000d0, 0x1f65c02f, + 0xb9a39cde, 0xa0d17b65, 0xe1e20f99, 0xcb4af865, 0xeab882e1, 0x37e0e09a, 0x498c560c, 0xd91cb956, 0x3f7cf301, + 0x0b1f4162, 0xe0f10d67, 0xd71f4b9e, 0x2d4d83f8, 0x0707c143, 0x70fc0427, 0x3e9be491, 0x4626d75f, 0x32b05fc4, + 0x2b0f07dc, 0x28617d05, 0xa02fd805, 0xe6a8c2c2, 0xeb311923, 0x1c3ed3af, 0x9c72d604, 0xee310d7a, 0xc2b7d08a, + 0x3a011755, 0x22c96fe9, 0xfa79e817, 0x05848bff, 0x578d81bb, 0x340fd327, 0xb91a0d96, 0x653c2d55, 0x7d197415, + 0xd348c8bd, 0x3a04ba5f, 0x6def4970, 0x63997938, 0x36a5a495, 0x5900132a, 0xb6104712, 0xdee0d353, 0x56e89c25, + 0x093dde65, 0xf25a9e85, 0x9af5c7e3, 0x78fbab94, 0x386bcd7f, 0xf4dcd735, 0x38a2e0d3, 0x6173a817, 0xc021116e, + 0x198b5b11, 0x3fd05d4f, 0xb6329737, 0x8716f8c7, 0xa6abfe48, 0x5de1989c, 0xec1224a0, 0xf752f350, 0x25524480, + 0x9bfd3289, 0x82a8a26f, 0x55e98dc4, 0xb7c4b37c, 0x0ef48e9a, 0x5c3d22f6, 0x2d0e1df0, 0x1ec4f8ec, 0x76130f13, + 0x791df044, 0x89f632eb, 0x7273e005, 0xe9478e2d, 0x4a0e380a, 0xd90bbe64, 0xf088d2aa, 0xdca04b32, 0xe2864a21, + 0xfd06330f, 0x0781ed16, 0xc0fc5c24, 0x8269f72f, 0x6c2284ce, 0xc992d46f, 0xe9311641, 0xd0865e00, 0x9c0513ea, + 0xbe7ec6c3, 0xcdb237d3, 0x36d45606, 0x40f0049d, 0x8edfa0d9, 0xbc0c83b0, 0x34eeb6e5, 0xb0c0daf3, 0xf02f62e6, + 0x6483bd1e, 0xae6d2d39, 0x0edf168c, 0x25391b8c, 0xe39549f4, 0x77622057, 0xa549218b, 0x055ed8c6, 0x287b0f84, + 0x33686f58, 0x398fcc15, 0x11733136, 0x453f6df8, 0x91795897, 0xd0531507, 0x3f727605, 0x6f973acd, 0xa91d1e60, + 0x2ac9ee50, 0xf19b8c35, 0x292c51a1, 0x40118f25, 0x3464dbcc, 0x532d6d16, 0xb1785d39, 0x0f9a2dfb, 0x4cbd8a80, + 0x17e46ee0, 0x8ce56621, 0xd412ba3d, 0x97a90e50, 0x63c41cf1, 0x35a4352a, 0xb26b8af8, 0x911f069d, 0x6f7f7c94, + 0x3f30ab58, 0x5906449b, 0x04842937, 0xf2a3798a, 0x5b935a06, 0x6ee42bec, 0xe0fbf99a, 0xe9455b12, 0xba6695c6, + 0xf6e86d39, 0x3b672508, 0x8e68c597, 0xd66b45ad, 0xdb885311, 0x4b47b114, 0x60b18f92, 0x4f04503c, 0x90f3b105, + 0xbbfa7557, 0x06d4b717, 0x97473122, 0xf8d2c3e6, 0x828a9552, 0x4841ddb5, 0x7dc06c46, 0x31660abf, 0xe7ef66fe, + 0x6d66269c, 0x9f336c67, 0x4f47e94f, 0x5e95dc1b, 0x75261aa7, 0xbe4c8f5a, 0xdaa2dbeb, 0x6fa2b0a1, 0xbee38e25, + 0xd50eaf7b, 0x84806734, 0x35c64719, 0x581c1270, 0xfa0c40a6, 0x026e593e, 0x2c03ad57, 0xdf603615, 0xe3b029a3, + 0xadb6371d, 0xd28f22fe, 0x7d77e288, 0x18f170ef, 0xdcbfdd0d, 0xfb1f4c3e, 0xd28a3385, 0x8bcbffca, 0x00c16fc7, + 0xe8b3e1fc, 0x967716f4, 0xa9e1f954, 0xb2196d2a, 0x5be03b34, 0x863d9bca, 0x62136c2f, 0xde10839a, 0x066d9403, + 0xd50be6dc, 0xe00d9a42, 0x00f20c9a, 0xb17e10b0, 0xeae9a34a, 0x96fe2588, 0xa84899d5, 0x0398e666, 0xe933dcf8, + 0x9177942e, 0xd47fbc27, 0x8e0960f4, 0x9f09de9f, 0xb1d07985, 0x9a163a46, 0x5675a9b1, 0x070863cd, 0x6b61fae2, + 0xa6cacc4c, 0xe5ef4b13, 0x072fabfd, 0x3934fad8, 0x8ad1e630, 0x191f2c4e, 0x63c01c93, 0xe1a4e4ee, 0xa48e1028, + 0xd58ae364, 0x035ed28e, 0x85664aa4, 0x468effe9, 0xc377f5fb, 0x3d4fc469, 0x404b7db9, 0x6e16e28c, 0x87dc6936, + 0x62b642e3, 0xc38e917f, 0x742b100a, 0x1662f9bf, 0x9927e149, 0x5961667b, 0x15273007, 0x2fa2057c, 0xf04434fc, + 0x8a8553ec, 0xee3dc850, 0x4c808ad1, 0x50ff7bd3, 0x0537ab8c, 0x76a161fa, 0xf1e6fe0c, 0xc6acfad5, 0x5183e620, + 0x61b86531, 0xeeef4273, 0x3d7f45d3, 0xab462d8b, 0x6fa97983, 0x61d4bff9, 0x8ae2cadd, 0x3fabd882, 0xf727be28, + 0x4ca05a63, 0x5a89633a, 0xd1b95f6b, 0x8500be1a, 0x41959746, 0x8d305874, 0x775a9120, 0x3485549c, 0xa398ed43, + 0x404402fb, 0x1d1dc3a3, 0xe13c9cd7, 0xf44d19bb, 0x8fccd029, 0xbfdc5116, 0xd1fc84bc, 0xccd0b5f1, 0x327c0f41, + 0x15a4b26c, 0x994c509a, 0x1ffcc2cf, 0x3d3f863f, 0x4bdb6fb9, 0x0595dd0c, 0x785a2102, 0x5c2c3032, 0x0006ecae, + 0x5ab13026, 0x93877b91, 0xfb8c0d62, 0x2a98258a, 0xd19cc6e9, 0xdc00477f, 0x0011d0ba, 0x4d4b83e4, 0x8691a12b, + 0x7be9139f, 0x1ba1f2ee, 0x1cd7a751, 0x6e8f7a3d, 0x4c65986b, 0xdecf38f8, 0x34a53191, 0xda30ff45, 0xe0b1c635, + 0x595c2d07, 0x68932da2, 0xc544228b, 0x000e0685, 0x1562d1de, 0x7cb5572b, 0x5d011c05, 0xcce12d5b, 0x80eb2f24, + 0x4341592b, 0x6b25d162, 0x15885f62, 0xb649cb6b, 0x3558c234, 0x010b902e, 0x0b0a27cd, 0x3c1917a7, 0x6b4dc3e8, + 0xef0b3433, 0x4d1b06fe, 0x00c298e8, 0xd259640b, 0xea58891d, 0xaafcecc3, 0x5e9363c3, 0x50eec055, 0x9dbcdfda, + 0xfdc692de, 0x0ac68aa1, 0x57357245, 0x55e4e877, 0xdf38fa2e, 0x9922f0e2, 0xe5690a27, 0xa15fc2be, 0x19e79f4d, + 0xbe66f404, 0x08eb94a6, 0x33e23326, 0x5ffb9a61, 0x6654caf7, 0xa2cfee3c, 0x2e5bc30d, 0x49494e15, 0x94f3fba9, + 0xd4e530d5, 0x8e3bda79, 0x4d284071, 0x0f6960e3, 0x4aa01923, 0x4cfc76a2, 0xadc3b52e, 0xe4fe6b49, 0x0f164aff, + 0x39aa5a4b, 0xffa5d822, 0x557c63f3, 0x1d77ba54, 0xa1dbe4fc, 0xe1eaad6f, 0x2dbe11d6, 0x84d0bc17, 0x3e5a6e84, + 0x0c3ce7ad, 0x0e69008e, 0x89e7c892, 0xb559782d, 0x790d36e7, 0xeece1626, 0xa9c4fe8f, 0xacdee5b0, 0xa7a706c7, + 0xacb8ebab, 0x07dfa5c6, 0x4218a893, 0x36dfbd07, 0x2c181ca4, 0x935ef0e1, 0x73f486ac, 0xcccfd1b5, 0x48996f94, + 0x672cadd5, 0x2588c0d9, 0x89400d17, 0xd2020189, 0xfc65714f, 0x0991296a, 0xbe176c8d, 0xce706e4d, 0x67afab49, + 0xd3b12cad, 0xac835ec0, 0x6e33595e, 0xceb01d66, 0xdde7fe58, 0x793b8fb2, 0x9f807593, 0xf904c941, 0x2b08c61b, + 0xe5ba7ad0, 0xb5a1b5ef, 0xbf7dce3d, 0xea949b7b, 0xdfc31347, 0x986f1339, 0xd2df488c, 0xfbcadc8e, 0x162ee2ae, + 0xa15b13c7, 0x158fe394, 0xd7c66a8d, 0xa732f2a7, 0x5d883ac3, 0x2e94ff9f, 0xf507ab5a, 0xd7698b0a, 0x4adb5897, + 0xa52e708c, 0xe47b3600, 0x4c7664ab, 0xa64a6f39, 0x1444effa, 0xd5930b6f, 0x0795bcaf, 0xef593a2a, 0x9c22c229, + 0xf133205d, 0x41bf1524, 0xa8e79838, 0xadd25cad, 0xb0b97b30, 0x2bdc096c, 0x77afd496, 0x80050c2a, 0xfead2878, + 0x4df22cf6, 0xea291154, 0xb0ed8dac, 0x5ef21ab2, 0x95aa23eb, 0xb09d3bb7, 0xcd0c0cb1, 0xb44583fe, 0x25363d11, + 0xd9a3e543, 0xb2081e22, 0xf5c06cac, 0x43ca66c6, 0xae0874a6, 0xca5e068f, 0xd7b9281d, 0xa1036b56, 0x1a7a03e9, + 0x40af50e6, 0x54eb5222, 0xfca74d8e, 0x4f694414, 0xeb95ed0b, 0xff64354c, 0x5458e2f2, 0x4226a164, 0xc87dee64, + 0xd2992946, 0x45908324, 0xdf5721e9, 0xab008334, 0x4e17ba79, 0xd9db2dd0, 0xb8911ab4, 0xa8de2889, 0x5fac4628, + 0xf566d859, 0x22ac8cc0, 0x8f6ac358, 0x10f3dd72, 0xd0356986, 0x7758db6e, 0xa68e795f, 0x7f4e8afd, 0x37b75ba2, + 0x4312b60a, 0xaf4d37fd, 0x160eb142, 0x0cf80dc6, 0xa1ff3296, 0xcdbead46, 0xab12260c, 0x1b936beb, 0x3515f28d, + 0x289fd317, 0xbcae88b9, 0x52231948, 0xcb72003c, 0x21adc47f, 0x352a89cc, 0xe7e7179a, 0x42ffa3cf, 0x778ea4d1, + 0xcca97a5d, 0x2b62950f, 0x65222015, 0xa2342e76, 0x2a4df1e7, 0x1208c246, 0xe1fb2002, 0x19e30382, 0x2f34608d, + 0xdbebea7a, 0x841ddd63, 0xdb943373, 0x0ee7a0db, 0x67999b46, 0x53bb6e43, 0x92520bdf, 0x892d4dd9, 0x04708ba8, + 0xf3a08015, 0x5c33431a, 0x05d8abfc, 0xf4a2ec64, 0xd3858925, 0x96e09f66, 0x7e75c2ef, 0x456c353a, 0xea6da87b, + 0x666c004d, 0xcd88c3bc, 0x3b9eb6b6, 0xa96f01ba, 0x6f33b572, 0xc7f61994, 0xa17a219c, 0x5d0070ff, 0x37d02937, + 0x8555932e, 0xa659caaa, 0x1b4240e1, 0xcc18b7ec, 0xe919f097, 0xfd26f7ae, 0x6797049c, 0x815b0243, 0xb5052661, + 0xc0e78443, 0x305db9cf, 0x16aa04dc, 0x47bc1640, 0x7240c33d, 0x77fa8ba7, 0x0c46db31, 0x1a0272d8, 0x76177c35, + 0x57a34999, 0x2b5ac606, 0x3953bd13, 0xc0cb1a1b, 0x762d43d9, 0xc609cdcb, 0xd47ef2ae, 0xc7e77db0, 0x855e216b, + 0x4aac8d0f, 0x3f63eea9, 0x01530230, 0x90110cb7, 0x02519ab8, 0xdf7ae568, 0xadb427f8, 0xd86cb22a, 0x8d9d9573, + 0xb6f9c094, 0xef23c4fc, 0x9a119aa5, 0x9a8495ed, 0xbd3355e2, 0x4b89e820, 0x14c7e3e4, 0x79c4b839, 0x4f6d07b1, + 0x34f866d2, 0x21cebc98, 0x07ea27ae, 0xb45ef579, 0x57f6b36a, 0x6524bd77, 0xf968cea2, 0x7a4ad6b6, 0x26e964f4, + 0x2de4de17, 0xc8ed3f75, 0xb843c8e6, 0x5fe7903e, 0x411b9625, 0xc3374c1f, 0x0915c7ad, 0x96f7e130, 0x73c25ddd, + 0x8cfe3d2d, 0x8df4c90d, 0xeec49057, 0x054db53b, 0xd520c377, 0x0a9c5a6b, 0x18020344, 0x6fd47f1c, 0x76088114, + 0x2c6b7690, 0x18bff942, 0x0cb3ffce, 0x0a8e2d12, 0x9dcf3239, 0x5ddcccd9, 0x148383b9, 0xc09cdb27, 0x67cd0f73, + 0x6266f7e0, 0x02edda9b, 0x6546be59, 0x1ff17708, 0x517b6cbf, 0x372c7fbc, 0xb656a065, 0xd36ae16b, 0x84c4cfc5, + 0xba63e200, 0xa5d18699, 0x71439c78, 0x64a1fefc, 0x10927b67, 0xb2eada79, 0xd02bedbd, 0x3d706472, 0xaaa3ae44, + 0x2ac159cd, 0x622076ff, 0xc7394b3a, 0xc8b33244, 0x660bf529, 0xa729a80a, 0xbc10c091, 0xaadc9d4f, 0x2a3978f9, + 0x31602d0e, 0x139c40e6, 0x4543a0a5, 0x6d23bd99, 0x8d46ae4c, 0x5e1d9a86, 0xf0a346d4, 0xa355b780, 0xdc1cb1f5, + 0xbbae7af2, 0xd86e2561, 0x731f3913, 0xb06dc264, 0x9eaba121, 0x44613bd8, 0x707aa7ee, 0x10945d29, 0x043475f2, + 0x03d2f634, 0xf6a78b50, 0x3678cdf5, 0x741ba537, 0x49379ade, 0x39632e23, 0x61a2b92b, 0xb2188759, 0x1d1da2c5, + 0x7592441c, 0x85d99ef8, 0x1a8a9c63, 0x2d5cbcdf, 0x9d482008, 0x3d4fc1ed, 0x2933cd00, 0xa07c30f6, 0x5977033a, + 0xa309742d, 0x1e91b534, 0xe4b7c02d, 0x679aee76, 0x1c22f714, 0x80a47e5d, 0x8b4077f4, 0xbff20f18, 0x5de71fec, + 0xf443b638, 0x8fce79b2, 0x7d4e7fc8, 0x3f973c1d, 0x9b85508c, 0x18b9642d, 0x022b5620, 0x7f96c97d, 0x52acaf7a, + 0xcc83bc59, 0xe51fae7b, 0x5088fe29, 0x9f693330, 0xbcb7664c, 0x8b12ca5b, 0xda0d26bf, 0x3cfd2dfd, 0x3799d847, + 0xa7c6f997, 0x7126b565, 0xaf349f7e, 0x7e6710d2, 0x2877ff78, 0x8238e8e1, 0xc2762ed4, 0x83388e90, 0x57bab791, + 0x619e266f, 0x7b85ba1e, 0x6af78b61, 0xa3f612cb, 0x0407d507, 0x6a9c03df, 0x9ed68f08, 0xe9e5f494, 0xe535d7f3, + 0xd6c365c1, 0x7aa2319c, 0xe0f84e48, 0x638defde, 0xd27bb5ee, 0x9c6920bd, 0x9fcbb209, 0x0f4f51db, 0x0527eab9, + 0x99c76403, 0x01fe41c5, 0x143b46fa, 0x0601cb30, 0x97763264, 0x8ce5069f, 0xbe67841f, 0xf314b69d, 0xc8b01011, + 0xab818006, 0x93292943, 0x26acee89, 0x01b6ccd7, 0x8944fb81, 0x102f5efd, 0xcc51ac3a, 0x8981dec9, 0x5dd42e7c, + 0x943d87c4, 0x916a9bb2, 0x465e346b, 0xf65d31dd, 0xed6286ea, 0xeaf34c1d, 0x3228f9e4, 0x8f8b71c1, 0xea22628c, + 0x8c8775c9, 0x8dcee7c5, 0xff581b2a, 0xb48cf92e, 0x089e0409, 0x587a9871, 0xcb208b89, 0x7e35e28f, 0x178e4f2e, + 0x060d5780, 0xf5fd06a2, 0xcd7c2f7d, 0x7cf2643d, 0x9fc58aed, 0xafa47e04, 0x82be19bc, 0x885a8325, 0x4ece7f78, + 0x4b8c1ab4, 0x6d654cc3, 0x78b43d47, 0x30e46c43, 0x2fa495de, 0xb9c54716, 0x15224658, 0x0e1861b1, 0x41c58683, + 0x28bce598, 0x0d5124a9, 0xa897b5b6, 0x674c2a7c, 0x5c33db68, 0x9b78423e, 0x053091c9, 0xf248fe65, 0x0d7f9203, + 0xaae9f7e3, 0x216b843b, 0x5450ae53, 0x09fac3e0, 0xee610823, 0x9068d870, 0x0e8dd42e, 0x260a6854, 0xd8a1ea3d, + 0xb645869e, 0x875d3322, 0x8ec2bd72, 0xa4655a68, 0x9a7c6b03, 0xa9be5f2b, 0x9e49fe8a, 0xe50adcaf, 0x68db6837, + 0x7a5c998d, 0x9f513a38, 0xc07015a1, 0x78d5dd26, 0x3d096b3b, 0x19b6f425, 0x72e597f8, 0x2bd92f82, 0xcbad2aa3, + 0x0de3c50f, 0x1244a410, 0x49d1d070, 0xd4026035, 0x1d6a812b, 0x396ec04e, 0x6f26fca8, 0x6e686178, 0xe254cfae, + 0xede1a6cc, 0x91980aae, 0x2f665c2f, 0xad137ae0, 0xf0b54d3a, 0x0f1645d9, 0x3c544ee5, 0x18c8cebe, 0x8f9c678c, + 0x932628b0, 0xdf8adf6c, 0x3a2a7ad0, 0x5c6bb34b, 0x48d88380, 0x2247e788, 0x1dc773fe, 0x0e76125c, 0x0bdd06f2, + 0x93a15a16, 0xf8417c47, 0xb0fcda2b, 0x00d98b30, 0x1b2bdfd5, 0xf023d233, 0x639f4a89, 0xfbfffe33, 0x8e404644, + 0x0b30ff81, 0xd476558a, 0xe955be7a, 0x0a460674, 0xc0a4c175, 0x7fe34706, 0x51bb7e8c, 0x4649795c, 0xc3927f5b, + 0x1fa11730, 0xb8651423, 0x35db61a3, 0x5102d83b, 0x478d9029, 0x1e4a5d6b, 0xdd11bed0, 0x5143b24d, 0x906ff158, + 0x5470f017, 0xf5358ef2, 0x214f6ef6, 0x5de31da2, 0xcdd8d516, 0x49201dfe, 0x610dbfca, 0xf3a386a4, 0x0a5a009c, + 0x93ea677a, 0x9b21da7d, 0x1e13384a, 0x7f403e00, 0x953ef10d, 0x82b8e580, 0x317c887c, 0x08c89c46, 0x1e66f756, + 0xecf4ff10, 0x2d86c7c7, 0x083bd7b4, 0x299b56e5, 0x60c105e4, 0x041f9315, 0xd4583465, 0xfecc52f2, 0x24d97183, + 0x844a009b, 0x607272cb, 0x8f67b9be, 0x5b6c23ec, 0x979ea5ab, 0xa21019ba, 0xaa06fb34, 0xfb49201c, 0xb3f20d36, + 0xe433fa30, 0x81e1f631, 0x9144e1c0, 0xd807a7a5, 0x3fe4f4e6, 0xf4f9a13e, 0x1632c6d2, 0xa8a3c21c, 0x03e85105, + 0x6c49b16f, 0xfdd51b62, 0xab5c7756, 0x4432783d, 0xa666d703, 0xe4b29d5c, 0x58ac29fc, 0x1c2c3c60, 0x1fa16c3f, + 0xa9ca44ee, 0x8f1f7778, 0xe17eb991, 0x222a0a2e, 0x11e7d6be, 0xfc21bf50, 0xc536474e, 0x20dd4426, 0xc75b7e65, + 0x7b40df1c, 0xc35a30fb, 0x0fd4fac6, 0x07dc37d8, 0xe4c49f63, 0xebc2ea88, 0xd96015b6, 0xdc337f73, 0x3de3347a, + 0x9fa91d0b, 0xb4a56f7e, 0x5577c533, 0xf4cca073, 0x3c84360d, 0x7e2eb264, 0x3c35b312, 0xd04f8b6a, 0xfdb70caf, + 0xd3916e8a, 0xc8ef2803, 0x3f2a8dcb, 0xb701b7e6, 0x284273fa, 0x7e3ae3f8, 0xc358cc7e, 0x14b1992e, 0x8bfe7c44, + 0x29b30a4a, 0x1736fcd2, 0x9628de7a, 0x3549cbd5, 0x8bbc471d, 0x31f1a9a2, 0x1bdaed61, 0xe764f9cb, 0xed0ef6cf, + 0x39a86ab1, 0x875f7487, 0x4e37dffb, 0xe93af5fa, 0x241f741b, 0x6092fef8, 0x5f03b23d, 0xad3ee9e5, 0xdf4df07c, + 0xe4d05d8d, 0x30c05055, 0xc8d78b94, 0x16cdf95b, 0x44dfa0f2, 0xffd6570e, 0xa75cd62a, 0x14a77cbf, 0x87cbdde9, + 0x7b5614a2, 0x153a1b57, 0x3b204497, 0x399320c3, 0xddbec89e, 0x8dbc27a4, 0x14e32844, 0x4110af93, 0x2b8a5f49, + 0x72e11a52, 0x7685aa5a, 0x682bf48b, 0xed81d17f, 0x2c38ddb4, 0xa693415e, 0xb15ff4ab, 0x2f589c3f, 0x8427cdc3, + 0x68513d7a, 0x728d5e51, 0x3b2a3337, 0x001da644, 0x81a76abf, 0x2a5c7e23, 0x2b6b7c86, 0x0c20c953, 0xe4a6df16, + 0x95afa25f, 0xd5c77b13, 0xf6b2ddba, 0x0ecd14be, 0x89523c39, 0xb98acac7, 0x83adbaa7, 0xeb535b4a, 0x6c51ddbc, + 0xcdaa8760, 0x159abe83, 0xaf9157d2, 0x7c3ecb52, 0x2be7d730, 0x5799b9c8, 0x8ca9579b, 0xd9373c8e, 0x44c1c216, + 0xb925d7a0, 0xa1f93b25, 0xa3efc401, 0xbd517070, 0xa5a73572, 0xcee59507, 0x93e424f9, 0x474a1d7a, 0x03ce5300, + 0x13499134, 0xbaa52d96, 0xfbc7a63a, 0x12fc59bc, 0x5f4d0655, 0x94cc4649, 0xf71e8298, 0xfbac91fd, 0xa3885dd8, + 0xfb02c793, 0x7a4b7898, 0xc8a174c9, 0x50fda6bb, 0x49aa9452, 0xd07d554a, 0x2fd1e8f2, 0x6ea506ef, 0xa7a74b77, + 0x0bfc573a, 0x5ffa61e0, 0x0620f318, 0x549d6128, 0xb9e51607, 0x727b5266, 0xab243fe6, 0x270cd565, 0x9a5a8ab4, + 0x4b1b849b, 0x6bf221f3, 0xc49cc6e5, 0x7ef35578, 0x471bd82d, 0x47327ba8, 0x41b6b878, 0xb955ae1b, 0x577d483b, + 0x5b63c9c6, 0x4be71ca0, 0xd3a37e17, 0xae4b4a40, 0xe48bc4af, 0xedfbd6da, 0x71f5362d, 0xb68f61dd, 0x90017cb8, + 0xb28982a2, 0x884d29e9, 0x554509ad, 0x9b09615a, 0x32f6f803, 0xb4808769, 0xc74e516e, 0x69338e77, 0x81da56d6, + 0x2fdd5c19, 0xcf743b24, 0xb0bfcc6a, 0xe5f1736d, 0xe4f3cf0a, 0xb4625cf9, 0xda601354, 0x8ba3c246, 0x247c6755, + 0x966852be, 0xbdb18691, 0x3263e36b, 0x2fe11315, 0x6573d654, 0x26a5f038, 0x12da8da1, 0x9e68648c, 0xe0907db5, + 0xff1228e0, 0x356601d2, 0x520cb973, 0x6b6addb4, 0x1e0da9be, 0xe5908fed, 0x58a32ce1, 0x48a8cddb, 0x54709a7e, + 0xa6907f08, 0x089225c7, 0xf3757a37, 0x795c6216, 0xeb896295, 0xa8de0d0d, 0xedc15a96, 0x9f78bfc4, 0x413c0def, + 0xdcc687e8, 0x53fddf58, 0x667be66b, 0x59826439, 0x4e51d707, 0x4d9070c5, 0x6dcbc65e, 0x7cf5f1b1, 0x63f63cf6, + 0xc568ace2, 0xcef3d89f, 0xfae66b62, 0xcd12f14f, 0xd2725e1f, 0x7d74f5cd, 0xbaa7b738, 0xcb08bfd5, 0xdbfe15c3, + 0x0446b937, 0x0da1eba9, 0x29a4537d, 0x6a98df26, 0x234edcc0, 0xb7f4c960, 0x818ff628, 0x590c5971, 0x520313b3, + 0x45100677, 0x0148fdfe, 0xb8f90800, 0x2b2b6ba2, 0xc66864e6, 0x2aba3c63, 0x9a3c3779, 0x57066ab2, 0xbf49bb35, + 0x31003a96, 0xea4d4a34, 0xf6c728a7, 0x3ff61242, 0x663566db, 0xc77cfd66, 0x27f0eaa8, 0x3a3c325d, 0xf4995c9b, + 0xe0089e94, 0xdd38c3b9, 0x204415e0, 0x7ff561a9, 0x30cd7e74, 0x1219676b, 0x33aacc0e, 0xd7a9249f, 0x70e27c76, + 0xcd4b4195, 0xc6b4abf2, 0xa93a709f, 0x697aa673, 0x88105302, 0xb027ac3c, 0x3d85e86a, 0xd2d0d919, 0x55ee73d6, + 0xcd22a113, 0x4d1d2324, 0x8fbd4799, 0xdc4a70a5, 0x320d9a97, 0x7dfb2b87, 0x1cdad0a0, 0x49259627, 0x81bcbfd4, + 0xa4a4435a, 0x9dfa392a, 0x8e23f946, 0xb44c2c42, 0x4ace4894, 0xe7d77109, 0x9e0ec490, 0x890210e9, 0xb7260ec7, + 0x20b313cd, 0x7cec889a, 0x89bd5ed0, 0xb34509a3, 0xebe7b06b, 0x16326bc1, 0xa5985c6b, 0xe1f48a28, 0xc4c7e9b2, + 0xbc18d80a, 0xed80f706, 0x77894393, 0x050ffc95, 0x6e74bc02, 0xce9380f0, 0x1010bfc6, 0xbd5c5720, 0x8a559b2e, + 0x4f3272b4, 0x4867d5cc, 0xc1eae16f, 0xcc269800, 0xa17d7285, 0x06fca37d, 0x37cd9927, 0xbcd79ae9, 0x821b4339, + 0x9ebc1a34, 0x2b14603b, 0x962e612d, 0xab16c5b1, 0x375430e6, 0xd9ba129f, 0x4f9e8d46, 0x3ae0c17f, 0x0aaaf396, + 0x4d39591b, 0xf5f1ec5b, 0x30816f92, 0x3f0be447, 0x83825f54, 0x9617516e, 0x38d2eef0, 0x5db7798b, 0x884a5435, + 0x7914732b, 0x9a24bd91, 0x86c2844e, 0x17094f89, 0x21e2ca58, 0x988cbb36, 0x761f8302, 0xd16fb07a, 0x88244253, + 0x7844a213, 0xaf75afe2, 0xb9ad24aa, 0xcd6adac6, 0xe6ae69bd, 0xf592c52a, 0x8d532e74, 0x938707e7, 0x63709780, + 0x6fcd287f, 0x5ef0d3ec, 0x20c654a9, 0x33de7cb0, 0x838a2300, 0x04f21087, 0x786248e9, 0xbf55753a, 0xed434bb3, + 0x5cbad327, 0xf30747fe, 0x1b8d7818, 0xdf6bbae7, 0xe5c136e8, 0xf1a2009c, 0xc751c9c0, 0x0e0cb8da, 0x1bdfe226, + 0xb58937ec, 0x7e8a4415, 0x191f42fb, 0x0f103fbe, 0x53f54188, 0x9988284f, 0xd4105310, 0x6a18b299, 0x0b147084, + 0x5dcdbc06, 0x9bbf7d27, 0xbecaa9e3, 0x078e66e1, 0xc260274e, 0x8b659cb3, 0xccc867e5, 0x38439b74, 0x8263803b, + 0x24f7be9a, 0xdca7d25c, 0x6cc0ee5d, 0x08970167, 0x8f308b2f, 0x881c7043, 0x103ca45e, 0x68911465, 0x4ed1fb73, + 0xce1f1025, 0x10b413b7, 0x4bfaa7e7, 0x2b66c8fa, 0x21ba3bc7, 0xa0e194e3, 0x9390d233, 0xb859409c, 0x969714f3, + 0x95574920, 0x947115f3, 0xed9df9e4, 0x388849b8, 0x221f847e, 0x682b82cf, 0x44c81e62, 0x714b2ca3, 0xd214d376, + 0xf19b6f86, 0x9e63bbd3, 0xb5a659bd, 0xf57ce460, 0x63879222, 0x46622d21, 0x3f60327d, 0x7ecafb38, 0xdc5340ec, + 0xe36ded38, 0xb5c4543f, 0x1c698679, 0xafa33019, 0x539add43, 0xd58335a2, 0x2c05b736, 0xd7066414, 0x17f8bc96, + 0x305b82f6, 0x0f2885c2, 0x15aa3700, 0x5b466975, 0x6f1c7267, 0xeb23306d, 0x371b000e, 0x7b8ed2bd, 0x9721a75f, + 0xb3ccdab6, 0xe2df9d43, 0xc3ff63a3, 0xb26a92a4, 0x84eb810a, 0x3b8cc47c, 0x3c6e1808, 0xdf585328, 0xaca197a6, + 0xabd4d27e, 0xd7d42689, 0x1eb6bfa6, 0xf831348a, 0xf1d91435, 0x13eca895, 0x83ff54f9, 0x93c16c80, 0x7010cd95, + 0x8f2097e8, 0x3c2e8efa, 0x3714c0de, 0x096e51bf, 0x6adcb0d5, 0xa9248fa2, 0x2c1be903, 0xb29bb451, 0xd4b1ce48, + 0x23aaa587, 0xac30b763, 0x6b217fd6, 0xce0ca941, 0xdf7e2b4d, 0xbc17cc31, 0xd5db97b7, 0x16931435, 0x026556e5, + 0x83683251, 0x10ff6ffb, 0xd4e77ebd, 0x4bf32bfa, 0x447d18a0, 0xe0717b22, 0x9130e4ed, 0x5db36e2c, 0x09d62b55, + 0x7b610cbd, 0x3f8ff7e7, 0x4c6f0da6, 0xa80dca0e, 0x35506221, 0xc69c325b, 0xc867d3e1, 0x1c5697df, 0xc4807800, + 0x4a291210, 0xc77d2a8e, 0xac6a2b38, 0xfbb7c967, 0xc73e619e, 0x7a99a856, 0x7150a880, 0xa44aa84d, 0x9e8938bd, + 0x6819a094, 0x5b894fbe, 0x905f271f, 0xddf93177, 0x5191cf1c, 0x5563efc7, 0x0939e1e4, 0xb9c0aae4, 0x4eab1483, + 0x80d49a12, 0xfbf08662, 0x9b35f54c, 0xe228afe7, 0x3e978b8c, 0xf2d96599, 0xeffe5c16, 0xdd072e8f, 0x57901ea3, + 0x841c045e, 0x6baa8939, 0xe95183d8, 0x9520d01f, 0x460f9a51, 0x6b4d388f, 0x75375536, 0x674e4590, 0x31c0d699, + 0xd63cf0ac, 0x408eda70, 0xb8a7dbf5, 0xec8d023b, 0x3dd09955, 0x8356bfa1, 0x0f523406, 0x4c5517e1, 0x86ce8204, + 0x52cd40a7, 0xe8f7be25, 0xad5960cc, 0x69657c36, 0xdc2638a7, 0x76e1d4e9, 0xf16ad66a, 0x3f50443a, 0x40408702, + 0x6358e05c, 0xc69d1620, 0x6d5ba3a5, 0xe0cfb3fc, 0x6d334382, 0x774fa4b4, 0x5aaeee0d, 0x92624150, 0xebe1d9fd, + 0x12cda136, 0x8a79902b, 0xfb892da9, 0x40d7a9e7, 0x0f3760c6, 0x1504db73, 0xd6dfff17, 0x6074093c, 0xeeb30f5f, + 0x3b4e5f96, 0x4f359846, 0x5b5f77bd, 0x19d43e39, 0xbb363ab7, 0x4c10a35f, 0xd9a1e3b4, 0x6043b017, 0x11ebaf61, + 0xd28fdcb9, 0xc49cd030, 0x966a5571, 0x703b3224, 0x94d19a0e, 0x3bb09cc3, 0x12a1d9e6, 0xf9ce1571, 0x1bf40c5f, + 0xf9126fc2, 0x28d71011, 0x43a7bb9f, 0x0e00ea0a, 0xaf30e478, 0xce5c8f39, 0x026b2d94, 0x4cedc987, 0x9a0cb69a, + 0xacbbf086, 0xc2e80363, 0x5301b02c, 0xe2a72c70, 0xa57ea8d9, 0xd16a927a, 0x79da8d06, 0x940ded27, 0xa62a7cf1, + 0x865b4b3e, 0x23ca4bb8, 0x5619fe4c, 0x2d544ba9, 0xf30559b9, 0x8f450c9b, 0xc7bbed50, 0x18fa5cf4, 0x460dbcb3, + 0x031c9d9b, 0x4f36b1ca, 0x1bca6e8c, 0x956b4feb, 0xa43c28c3, 0xd640ac6d, 0x3f537239, 0xd109e829, 0xc3c0977c, + 0xf9176b55, 0x84a2d49e, 0xa27c92a8, 0x002e06d6, 0xa97af5b5, 0x0860a6a0, 0x6d1bc8fc, 0x85e2c3f9, 0x245322cf, + 0x8997e898, 0x1b4f3ea5, 0xe0e51c57, 0xe6106649, 0x58e30a30, 0x548f57af, 0x9eb408f1, 0xba150a82, 0x4ddc5326, + 0x0ad4a4ce, 0x14b22563, 0xa2b7dc79, 0x3d86c8d9, 0x32e2f7ef, 0x37fc1a9a, 0xcddf7612, 0xe8b01eea, 0x4ea3d66f, + 0x48c3b352, 0x1472b0e2, 0x9fa6cd59, 0x69b5f362, 0x6f62b44e, 0x1d297ccf, 0x95e86045, 0x0aff5437, 0xeb00cbb9, + 0xda14826b, 0x35276b43, 0x1a9f04a4, 0xb9f328f1, 0x4325f425, 0x36355d33, 0x602c24e0, 0xe4d96ae6, 0xc8722883, + 0x0ca6343d, 0xf9a81e67, 0x553f8941, 0xf0366e77, 0x0871f05b, 0x6d6d38a7, 0x0b37a12d, 0xd617816f, 0xb2f1bcff, + 0x231417f4, 0xf7bbdebf, 0x94855131, 0xa4cfe86e, 0xb677f299, 0xc43410cb, 0xc402dfda, 0x05f4624c, 0xdca41864, + 0xfa8dfb22, 0x556e4ee2, 0x1fa09c66, 0x036000c6, 0x5616dd10, 0x39dab5ae, 0x2ac4e3d0, 0x8792d892, 0x6887f520, + 0x5b68aa45, 0x4423d3a8, 0x04f80413, 0xa34f1c25, 0xed2f5d56, 0xfe24b289, 0x4283966c, 0x60dc5e36, 0x90c3587c, + 0x0f394edf, 0xcaa44c5c, 0x30a29546, 0x9a1dfd83, 0x89e6122c, 0xe9631d78, 0x9e92f891, 0x6a759172, 0x628a0e94, + 0x46b0e925, 0x8c25231b, 0xbd3cf517, 0xfe2c7356, 0xb608c1d4, 0x8e92dc68, 0xc21efe67, 0xcdc526b7, 0xc208cf30, + 0xe9615779, 0xb0ddcd33, 0x453b438f, 0xe75bf625, 0x14814a1f, 0xfb0a8fd6, 0x19829265, 0xf57e2d0f, 0x465c88a7, + 0x5170ea9e, 0xce09fa81, 0x519177f4, 0x76c30037, 0x8de79ee2, 0x47f4d79c, 0x4d5e85f4, 0xb392a71d, 0x3b6599f4, + 0x7a7f0e60, 0xc89d6832, 0x6bef73e0, 0x0757456e, 0xbdae1180, 0x47717e4c, 0x966a5e58, 0xf41c7527, 0xf128806b, + 0x97fd6e2b, 0x18bc5162, 0x3ac1901e, 0x5cfd32c4, 0x0b1687e9, 0x862196cc, 0x4058b606, 0x2ea6509a, 0x0e716708, + 0x559df437, 0x4d2d9f75, 0x0ecb4403, 0x48f9d7ea, 0x2fbcadae, 0x651570ac, 0x72b61bc8, 0x670c8390, 0x19bcbc74, + 0x7457e381, 0x440145e2, 0x19c6758a, 0x51e9bd6f, 0x964367f3, 0x81e08e81, 0xc9ab2e59, 0x54b0f977, 0x5ef4c598, + 0x6ff00dc1, 0x543d3a87, 0x3406d7cb, 0xe5e930ad, 0x5bbc60ec, 0x21b78849, 0xcc5b1f88, 0xcd30bd09, 0xc22ab78f, + 0x8ee82094, 0xe5e5e439, 0x9e2be9be, 0xc671c3b0, 0x0a4fd5f7, 0xdfa341b5, 0x148910b3, 0xe3fdcf1a, 0xa5b461c1, + 0xbcd3b2c4, 0x91a7c622, 0x7078cee8, 0x9fd4cf0c, 0x6f716987, 0xdc12b414, 0x53cac5d7, 0x7ba1e9eb, 0x9589b32a, + 0x30d7862d, 0x0f30d385, 0x7f20ef91, 0x0c35c306, 0x996be89c, 0x9a5134ae, 0x67d3c622, 0x9753dd03, 0x7318d8be, + 0x9fa5c433, 0x3a5cc0b4, 0xc4f2901b, 0x61cc7693, 0x13051498, 0x450c8830, 0x7faaa877, 0x35967921, 0xad3a4f1b, + 0x803e3bf0, 0xee4f9a35, 0xc4af8a93, 0x93c39cb2, 0xe5e9b45f, 0x98ca5487, 0x3bb38812, 0x8a1d97e5, 0x5659de3e, + 0x39b36bab, 0xba1593f2, 0xefccc805, 0xdd7a18e9, 0x5653f12d, 0x2454141c, 0x48cc7656, 0xdcc00076, 0xf6e7ddcd, + 0x7a25cbee, 0x4138b89c, 0x8f34e519, 0xe0d205b4, 0xd6c6dc99, 0x88707ab3, 0x0c85c7f6, 0x00238ca3, 0x6dee6566, + 0x4877e82a, 0x61527dc2, 0xc15083b0, 0x15396e09, 0x13053d43, 0x69b50332, 0xe3927020, 0x1e7b8ac7, 0x1d19add9, + 0x81c341e9, 0x06584221, 0xf4b21be5, 0xd67f71fc, 0x3a225f51, 0x05b7bd4e, 0x9d8c6f5e, 0x028720f1, 0x626a2fd4, + 0x1d87e568, 0x5c25624b, 0x41c2c84c, 0x8c1f69ed, 0xf36a2930, 0x1784e072, 0xa7004822, 0xb9e6f56b, 0x9fe63402, + 0x3a17c0fd, 0x1670957d, 0x1a432dde, 0x08b1653f, 0x92e7c984, 0xf28c4184, 0x81449a71, 0xef569237, 0xa1b46ff9, + 0xb117c55c, 0x2b60f342, 0x7bf89e00, 0x4552b836, 0x5d4db3bb, 0x01f3a96f, 0xe085875b, 0xf6bf782f, 0xbe399a41, + 0xca01955b, 0x21cc76e8, 0x926ab7dc, 0xb16e8c85, 0xa5afb196, 0xb6fbd59b, 0xe10807dd, 0x2ad341a8, 0xed976f36, + 0x845b2015, 0x9c780f47, 0x5acf935f, 0x65678aa4, 0x0f720af6, 0xfaf60787, 0x5e665ea4, 0xb77c5894, 0x3618569a, + 0x77b1fdbc, 0xedece7f9, 0xb8050c3f, 0xd46dd38a, 0x0e5c0696, 0xa33925f7, 0xd1412a54, 0xe737eebe, 0x0f008706, + 0xc91e9022, 0x3bed04ec, 0x9620da6d, 0xf2d081ff, 0x51bd9123, 0x80e4ff8d, 0x00132505, 0xba2bfc62, 0xd32071c8, + 0x03e1873a, 0xb40269d2, 0x419ed99a, 0x99bfd25b, 0xbfd7afd3, 0x01283a1a, 0xafd7b406, 0x1d13a1a8, 0x0f02723b, + 0xa8064376, 0x7bcd820f, 0x9c655947, 0xdf377ebb, 0xd6cf25bc, 0xcbc7d996, 0x954bace3, 0x4d3d145f, 0xf9456886, + 0x4cb28393, 0x972d702d, 0x4bd831e2, 0x1fb39f9f, 0xebfd7338, 0x27a07823, 0xc9b841a3, 0xd597deb7, 0xb13078e4, + 0x9d631a00, 0xc41d8943, 0xafb00b3c, 0xd157ddae, 0x6a30bb3d, 0x10cf90d2, 0x24b5cec1, 0x4732c7d9, 0x16a3b649, + 0x21db4411, 0xa9e4c75a, 0x0a04b7c7, 0xc491f07a, 0x6f3c4b9b, 0xeb0477bb, 0x95ac9146, 0x06fd09df, 0xe68c87b4, + 0x7b5fcbf1, 0xadfa132b, 0x12c4efcb, 0x706cd18b, 0x88114dfd, 0xbdcba067, 0x7cf6f979, 0xe23e611e, 0x9c11b1c3, + 0x984d2095, 0x5afef88d, 0xcc02e59c, 0xad6738c6, 0x5163e12f, 0xe83439e0, 0xe8b917df, 0xfa710fdd, 0x356c86d7, + 0x54b81b6d, 0xe89fbeb4, 0xda69d28b, 0x37d69b6b, 0xceb4096c, 0xb8ccbbf5, 0x286a2afb, 0x07811642, 0x98a1512e, + 0x56556886, 0xa28a6dd9, 0x6cd1f7a2, 0x9603b3b9, 0xeb29d54e, 0x6b1c926c, 0xaa50b648, 0x63fb67e4, 0xbeea9a07, + 0xbb5f081a, 0x924d5afe, 0x248dd777, 0xb1923b55, 0xa3bdf951, 0x5155d3d6, 0xb7cbaf01, 0x10ef8e52, 0x3703b979, + 0x7eaabdd0, 0xde4ebb32, 0xd3664930, 0xf728664f, 0x33df3f86, 0x460cd126, 0xac2ee83f, 0x0a4db8b2, 0xd6e062b1, + 0xc58b2495, 0xcdbdac4a, 0x502f8746, 0x9636c4aa, 0xc7334a7b, 0x25244540, 0xe1aa723f, 0xa1b9ef18, 0x33127dd9, + 0xdf038a50, 0xe82cdae1, 0x8e7ff659, 0x516e5383, 0xfc91660e, 0xc8055368, 0xd5c9726a, 0x8c7298c0, 0x561e3c3c, + 0x10148469, 0x1b554796, 0x2271c0f3, 0x7048ddcf, 0x76f89fa4, 0x66706eec, 0xc0ed97be, 0xab58e603, 0x4dad9097, + 0x604a8574, 0xcdc1c452, 0xc733d546, 0x397f4b68, 0xb568d86c, 0xf17c63f2, 0xde5a52df, 0x3586a281, 0x9acf4a45, + 0x5f3ca174, 0xc2dfc532, 0xff85f954, 0xf13594b3, 0x591e8b7f, 0x863ed6ad, 0xc5bb89c4, 0x81ba31b9, 0x35a95abc, + 0x2bdbe9a4, 0x9df83b12, 0x88d38aae, 0x286ec225, 0xaa615c87, 0xd109bc51, 0x6d363ca0, 0x44fa9fe0, 0xa8fcf89d, + 0xe8db80a9, 0x98ddd795, 0xc52648a1, 0x6500b265, 0xbda2798c, 0xe128c0f3, 0xf98c536a, 0x44376ebb, 0x2bf12512, + 0xafa09e2b, 0x7ce3c38e, 0x69175416, 0x4c9fe7b7, 0x56e38275, 0x6da53ef8, 0xa797d898, 0xdf30ddc5, 0x0d902f9d, + 0xc4b6601d, 0x83f92694, 0xccae0332, 0x0a9a7bf4, 0xe7092363, 0xcb005011, 0x37c9ec9b, 0x5a7b98fd, 0x4f83bcea, + 0x8c40fcb6, 0x3c5f82c0, 0xdc2a9a13, 0x06e633ae, 0x50c3b201, 0xcc985ead, 0x4aa6595d, 0xfa5355cc, 0x3ea257d0, + 0x2719ad35, 0x6f16fab8, 0x794ee07b, 0xf8aa035b, 0x769e43c4, 0x66669ac7, 0x458939e4, 0x422c4552, 0x677f16ae, + 0xf5f873c9, 0x32c7d431, 0x5ac37edb, 0x74028f59, 0xf923fc3f, 0xdb445f7a, 0x10462106, 0x486afd78, 0x2781a15a, + 0x6af2264a, 0xb795c53a, 0x74640bd6, 0x05b3fea3, 0x490ba6f7, 0x151c21bb, 0xa6ea713b, 0x7e5d7120, 0xfeb3e3fa, + 0xae7a6bd1, 0x505e24bc, 0x451cc6f7, 0x4e26c0d3, 0x5332b44c, 0x88fc4718, 0xf61e6c75, 0x7181bfeb, 0x1c5e3238, + 0x0a735877, 0x1f86aa4f, 0xa7939688, 0x5061ad47, 0x878a56d5, 0xa3e7dded, 0x1b0821ba, 0x044d20c2, 0xe1a98ad5, + 0xe658c56d, 0x33874821, 0x21c6b17b, 0xf8b8248f, 0xc41207b9, 0x8e8e148f, 0xf5c39943, 0x6cac96df, 0x69a3d7a0, + 0x3103b94f, 0xe9f93273, 0xd8be5e0c, 0x071faded, 0xc95304d8, 0x5caa006c, 0xf5e3e003, 0x33fa7518, 0x72f7ee54, + 0x740801dd, 0x1688237d, 0x78a372d1, 0x73e8d622, 0x109e95ae, 0x899eb6f8, 0x24efac56, 0x1a0a041e, 0x16dd2ecd, + 0x4c4f972e, 0x689cb40d, 0x901f8931, 0x1833f331, 0x37d78c6f, 0x0f487de2, 0x8aa086cd, 0xf2d4ab46, 0xb4417b30, + 0xf34aeb8b, 0xfd3ea8cf, 0x3da28c16, 0x7b96b665, 0xeba13daa, 0x46189fa5, 0xfb9c6032, 0xb5aa6e9d, 0xe34e0209, + 0xa01064f0, 0xaef58bcc, 0x7557617a, 0xd32850fa, 0xac76d41a, 0xd823a836, 0x59530dda, 0x0075b9e6, 0xa2bfeb03, + 0x17b1d674, 0x8066c4a3, 0xf29319de, 0x33ad84ca, 0x6fbc728d, 0xd208dfcc, 0xd0f5c3ac, 0x6753d49d, 0x077dd1c8, + 0xba1f2bf7, 0xa906a620, 0x934b81c8, 0x70430606, 0xe2bd48e1, 0x225cbfd5, 0x550cfc5f, 0x7fcbf8d1, 0x95e5e0cd, + 0xaf1b8e95, 0xb0295a80, 0x6190231b, 0x9897c9dd, 0xb7dc9af3, 0xb65baaaa, 0xfc31d5d9, 0xa2d4302e, 0xf02f50dd, + 0xe858f2c1, 0x5b0740e9, 0xb6b2fc31, 0xb49f0934, 0xcdd8faee, 0x4e7cd83d, 0x08d78830, 0x66a4892e, 0xbe72bcf1, + 0xa22933b2, 0x2bd1d778, 0x96a03864, 0xf8c9a933, 0xf915dfd1, 0x424b864f, 0x8e9f75e1, 0x960c07c8, 0x4f5464b9, + 0xacf56e09, 0x04ef3e09, 0xf79ce14a, 0x85c9710f, 0xe5a18784, 0x89abb4bc, 0x141f4aa1, 0x1bd27951, 0x056582fd, + 0xde9b9726, 0x13ac301f, 0x4eb7ba08, 0xcf0d7fe9, 0xce8ad2b3, 0x5716955d, 0xbde2fe18, 0x13a37c20, 0xf17dee11, + 0x9af3f57a, 0xb4b544a6, 0x4c70c5ee, 0x6e0f77e2, 0xd5fe0624, 0x751890bc, 0x1e6ce453, 0x187b8c33, 0xafba601c, + 0xab3a75f0, 0x5f46657e, 0x6b8a02ac, 0x7b0bc79a, 0xa99073d1, 0xc606195d, 0xd7ed5ab1, 0x9c8481c6, 0xb56bf0b5, + 0x2358549d, 0xf2f4c216, 0xd79afe32, 0xd00f9b16, 0x380b7e20, 0xabf98f40, 0x210abb5a, 0xdbaf87e8, 0xf3aea328, + 0x72905748, 0x21125830, 0x817adfef, 0xdbf68696, 0xcb0b2b42, 0x408a9a05, 0x2ecbf429, 0xc4a352d9, 0x4e8f6de0, + 0xa67556cc, 0x0c8768d0, 0x57f22a76, 0xc7c1b852, 0xca537b25, 0x60808bf4, 0x68c8a688, 0xbf8c5953, 0xe820fe69, + 0x54cfab1c, 0xe90d4ca8, 0xf3b49361, 0x3c241bd1, 0x200dd4fe, 0x31b64e19, 0x4b59ca2b, 0xf2a6a648, 0xcd23a1f3, + 0xe59c6671, 0xd688a99b, 0xf7168b0e, 0xf0d22d71, 0x8bc4ba30, 0xf2a5821a, 0x89be88f4, 0x29456403, 0x884ca3d7, + 0x0cb34b96, 0x7950cf9b, 0x8f0d8fa5, 0xe3f9e59e, 0x099668b9, 0x971335a4, 0x6663790b, 0x990926a0, 0x0078c3ef, + 0x3f18aaa1, 0x9f9d1ae1, 0xaf8f93be, 0x1b7c9b60, 0x9cb2cbb7, 0x8a5f1d35, 0x73301fb8, 0xc8ade601, 0xd513d570, + 0x09e9b75b, 0x0f1a126c, 0xa0a0c511, 0x632df6bf, 0xb77265c9, 0x0447f08e, 0xa055b890, 0xe96a957c, 0xbb1058ac, + 0x4a639aa7, 0xaee3aa0b, 0xefff2a5a, 0x8f2c5a10, 0x1759f5d5, 0x956c9317, 0xd2ad2633, 0x1212b165, 0x36a16a57, + 0xd075c54c, 0xd4e655f5, 0x2c5f7287, 0x674521d4, 0x0f7789ff, 0x313742fe, 0xf14db7fd, 0x3becbc6f, 0x7fcebd58, + 0x7ff0f440, 0x235436c3, 0x093a0317, 0x141a5ca7, 0x4798ca2c, 0x36b4f0ff, 0x5867d592, 0x4c98964b, 0xeffd4f13, + 0x3b80adf1, 0xf7f32060, 0x32e1fe85, 0x73af704e, 0x3d98156b, 0x67ffd75e, 0xfc4a3589, 0xa9167f30, 0xbef348a7, + 0x966061f0, 0xe57c6341, 0x190b5578, 0xab3e4aa8, 0xc4ba8b73, 0xd4318a41, 0x68284449, 0xeda20682, 0x7a9d5ab5, + 0x53f5902d, 0xfc2bf4f3, 0x4898addd, 0x27704ccf, 0xddd6640a, 0x83750544, 0x379a9440, 0xc2ab9410, 0xc3177e07, + 0x2829ab8b, 0x7e4eead4, 0xce9a0c35, 0x9783c9ad, 0x4b2f53f7, 0x3729d4ad, 0xe6b3c79d, 0x3b85266a, 0xecb33540, + 0xaeccf3da, 0x594a04f9, 0x68fa59a2, 0x1bf8818a, 0x49f6fa54, 0x36eaf38d, 0x57d06114, 0x81f02c87, 0xb2e9cd3f, + 0xacd16988, 0x02227c7e, 0x108bd4b9, 0xccf66b70, 0xd44d8e2d, 0x522626cb, 0x703e296d, 0x875c9fc9, 0x3855623c, + 0xc5245505, 0x838a456a, 0xff97d717, 0x63e461f4, 0x6530721c, 0xeb96d9e4, 0x8fc94e8b, 0x57acd54f, 0xf5155ccb, + 0x07622cf0, 0x42c43190, 0x6bacbe73, 0xf1b380ef, 0x2c374e12, 0x7c4b1197, 0x3416f849, 0x7c6248be, 0x4586313b, + 0xa0843a12, 0x879f2d1d, 0x93a76021, 0xf602fcbb, 0x2c16790a, 0x01e8445c, 0x9e438999, 0xe2e6de8e, 0x9ca112eb, + 0xecc25cfe, 0x5a2e1b61, 0x8a9e8a36, 0xfe78dc7d, 0xe65fc4b8, 0x060aa1a3, 0x0a543fba, 0xa894c177, 0xbc647c44, + 0xac44e17e, 0x4e990ca8, 0xe6fb53e1, 0xe2f47b1c, 0xaf1a4900, 0xa2796558, 0x19305aba, 0x9593106b, 0x0516d8eb, + 0xdf78dc03, 0x2890ac84, 0x715814d1, 0x114f1377, 0x3a699fec, 0xa3c4f1e6, 0x0fd4ae6f, 0x78d185f6, 0x40b660ec, + 0x55ce0555, 0x35396e95, 0xb69631a5, 0x0e1a358b, 0x7d6946be, 0x5166a7d7, 0xec4281fd, 0x3c60cec2, 0xa6b6a6ab, + 0xee919e8f, 0x775b9a52, 0x3d31dfee, 0xa876ef46, 0x513e22f5, 0x3c46498a, 0xd669b36e, 0xc0fc5428, 0xead79cbc, + 0xe31fc2f9, 0xa63870bd, 0x991d8eb3, 0xfec3d8e1, 0xd47fa455, 0x78a6ca61, 0x8f4bb0a9, 0x8cf8346f, 0xbb4682e1, + 0xb39ccb86, 0x613bcabf, 0x62301a42, 0x4fef6913, 0x45716da5, 0x8d2c1d2a, 0x908268e6, 0xe7ad884e, 0x5456782f, + 0x733822e5, 0xb4cf26a4, 0x20876b4c, 0xfea1df2b, 0x13960f5e, 0x58e9e015, 0x245e8e59, 0xdf253fe7, 0x4471829f, + 0xb78e6913, 0xe66edc3b, 0x5680eb4f, 0xc5afa04b, 0xfe2ac4f1, 0xcaca4c96, 0xb8026e5a, 0xa5196464, 0xb6871b39, + 0x51e318b0, 0x0ebfdabf, 0x393fba11, 0xc1497a40, 0x7bf1ac62, 0xaf8beca4, 0xbd5fb35f, 0x2eeb381d, 0xef7c9d67, + 0x6b5b9c90, 0xf73766b3, 0xea02d01b, 0x2036e41a, 0x1979ec5a, 0x40a73492, 0x20c1a744, 0x8c6b3184, 0xc29a2973, + 0x5777f339, 0xc8c0a1b7, 0x314c30c0, 0xd7f06bc5, 0xee1f4de5, 0x03b6ed17, 0x3ed3c90f, 0xfa8f6d27, 0x749d5c93, + 0x678c7b2d, 0x295f6eea, 0x3077d48b, 0x4411fa2d, 0x9382c66f, 0xd6f60fe0, 0xc27c8056, 0xed982bd6, 0xba30e2c0, + 0xcee45a46, 0xc09a197e, 0x994ecbda, 0x069243fb, 0xc75df086, 0x7b43b224, 0x11c3a148, 0x20ceabbb, 0xf5a9b97c, + 0x326e28da, 0x1e200164, 0x4829d5da, 0xc3f045c6, 0x678bec2b, 0x197159e0, 0x5a7b82a9, 0x433b874f, 0x06830475, + 0x46347b0f, 0x74ee1241, 0xd1246c2f, 0x469bda61, 0x6aad9b20, 0xcca9bb40, 0xd57163fb, 0x34f36eb3, 0x38b517d5, + 0xefd251c1, 0x85f56e9f, 0x82428d9d, 0xd987a632, 0x1ab5f614, 0x570cc268, 0xd679516f, 0xafb56273, 0xd574b0ea, + 0xe49d4351, 0xbfc1623f, 0x0f442dcc, 0xb6747d2c, 0x99dfc7b1, 0x92bae255, 0x53313b24, 0x579da8e9, 0xf1b4b007, + 0x7f6a942a, 0xe9294bd1, 0xc7836a07, 0x7f9b4012, 0x4bae2425, 0x5c607740, 0x3d3d28ad, 0x1a770129, 0x8a5bd68a, + 0x3d4b0e59, 0xc5a8ed0c, 0x59140230, 0x203dd5a7, 0x7eafc1f9, 0x855ed000, 0x2a8a8dad, 0x7e87e927, 0x9a09d69e, + 0x4ba3924b, 0xa0e34ff1, 0xba44e52b, 0x4896c83d, 0x756481a4, 0xe7125e73, 0xfa53ae7b, 0xc569d9ed, 0x659f8752, + 0xbd204354, 0xf6266414, 0xc83604b7, 0xc2e80392, 0x8c783fc7, 0xa41e3d2d, 0x634e63b6, 0xadc20e87, 0xb0130efa, + 0xcf5eb758, 0x184a706e, 0x19b75efd, 0x93cc3d74, 0x7795911f, 0x1bf67447, 0x8c186fb1, 0xf3a4bc97, 0x20cd8e1c, + 0x84795bd0, 0xa6a3c4fa, 0x7ae78a39, 0x731f6f96, 0x2410b8b2, 0xcf02d4b7, 0xb32baafd, 0x8eebf562, 0xa342831d, + 0x486fe0a8, 0xc6a723cb, 0xdbd4321b, 0xada3dbc3, 0x860de739, 0xc120c4e2, 0xa22fff6a, 0xe6812689, 0x4691d36c, + 0x2ff08010, 0x0f4b2fa7, 0xd99687e3, 0x76083ffa, 0xd5030414, 0x5581e3ea, 0xffaba84f, 0x3ad771b2, 0xd38df0f3, + 0x01ca1940, 0x84d627f8, 0xdfc24fcb, 0x8bde74a9, 0xf8693f85, 0x629a4522, 0x28d61c74, 0x3fdb3c70, 0x7ff9afe3, + 0x09d64693, 0xb9d806d6, 0x3800edae, 0x6f49866a, 0xfd47c5d1, 0xf0beb93a, 0x7ad02fb1, 0xa1e6fdce, 0x7fa55681, + 0x35fc0b03, 0x6a980ce8, 0xe5069464, 0x75637138, 0x6e6873f7, 0x133c429d, 0x4b3d0d9d, 0x3f6a8cc9, 0x2421639e, + 0xca7b95f2, 0x5bfd8b40, 0xf316ea12, 0x99614b70, 0x2ccdb532, 0x8fc0b5f7, 0x3453f2af, 0x3ee9ff42, 0x43f34cf4, + 0x160fce7b, 0xfd78b2ec, 0x57bf2d5a, 0x6c6276be, 0x542ad90f, 0xbd4326ae, 0xfd7a22e1, 0x8bf8c950, 0xd445507c, + 0xd122dde5, 0x3ab0efad, 0x297281dd, 0xb4b65a9e, 0x1a2b6de6, 0x49cf38da, 0x6b201aa9, 0x85640636, 0x70e25f1c, + 0x291bff9c, 0xf3dfcc4e, 0x88a582ec, 0xe8e14576, 0x55de5139, 0x48707979, 0x8296eab7, 0x39eee416, 0xc9240770, + 0x82a9732e, 0x243439e3, 0xa0215ce1, 0x8a6d2550, 0xa386f21f, 0x54993020, 0xce0adda5, 0xbbfa5d39, 0x32511160, + 0x6ec3f802, 0x9e46d8db, 0x9af6f42f, 0xb3e549f9, 0xb6cb4a70, 0x1124b2f2, 0xa8ea9165, 0xd1f76251, 0x626d9254, + 0xc63f6229, 0x81d1f5bd, 0x080d1035, 0xd6a6ddfe, 0x09ec1fdf, 0xc1c910a3, 0xdd34dd90, 0x75013e01, 0x046a56bb, + 0x5385f7f1, 0x188f8e19, 0x4a49160f, 0x8b4bc5c3, 0xd1b7f407, 0x476f7d74, 0x7ed70005, 0x65d7921b, 0x1f08bd3a, + 0xde3d2a7a, 0x3d2b77bd, 0x8dc9bffe, 0xe5a1f8fd, 0xf277e9ad, 0x2b6bb9e3, 0x891d0657, 0xa600a8da, 0x2800c7ad, + 0x5bbc8638, 0xf2b72d7a, 0x241d049f, 0x8f762f11, 0x6e92d4f9, 0x8b0d6ce8, 0x735729f1, 0x58d71f92, 0xf07017de, + 0xf9db3704, 0xc315db62, 0x7c2f5018, 0x2b6a1f9b, 0x11665e82, 0xf2a7fffd, 0x49b384bb, 0xf329210b, 0x8347f190, + 0x2dd28033, 0xb4b4dfec, 0x9719e3db, 0xd51b487b, 0x0d797397, 0x946a57d0, 0xf267061a, 0x1be3e21f, 0x568de30f, + 0x19331fa3, 0x096189b8, 0x90d91966, 0x2a527c0a, 0x5c65dc21, 0xf4f2376b, 0xb93bf2c1, 0x22d91c0a, 0x06cab242, + 0xefc7ffa5, 0x7cd3e75b, 0x47101ef2, 0x83abf60d, 0x5da4dab0, 0x419a3ad3, 0x6e8a83c8, 0xc9339252, 0xbb10800a, + 0x8af272a7, 0xa89194d7, 0x2b7ed0ec, 0x7733b57b, 0x2a889925, 0xbedbb70a, 0xf07f80e2, 0xdf23463f, 0xa3ccccce, + 0xd71a897e, 0x0b9ab486, 0x4bff4db6, 0x91507a34, 0x3ae27275, 0xff7e8490, 0xe054648f, 0x75f77339, 0x2f1da54d, + 0xa4f5a228, 0xfb3e2d2c, 0xceadb361, 0x0a8a6100, 0xc95cf489, 0x42f8f4dc, 0x577c4422, 0x8959bddb, 0x354909f6, + 0x348a8fb6, 0x70534f11, 0xfbd37c6f, 0x0a2e1c1d, 0xbae37ecf, 0x64fece1e, 0xf0b00d6c, 0xbe41c1ec, 0x391b3cf9, + 0xd506af93, 0x11290451, 0xc9e13445, 0xbb515be6, 0x744e9c9e, 0x60d8cf8e, 0xfad1b8a5, 0x1997429a, 0x3bf3e3d6, + 0xa8b0f310, 0x338ab8d0, 0x6d19e766, 0x20acc6d4, 0x74a900db, 0xe3e6fc11, 0x6e4d58e3, 0x3f7bb1cb, 0xdbbc1567, + 0x276ec07d, 0xc57d820f, 0xdf155f5f, 0xee8eebfd, 0xc7b109aa, 0x8ea0885e, 0xbc5773ce, 0x3cb27487, 0x215f6a85, + 0xe70254ea, 0x637b53fe, 0x1611ca1b, 0x93316a44, 0xbf77111b, 0xc8f954e8, 0xbb3e06c8, 0x553d6c81, 0x17bcc5cb, + 0xa6b0eb7b, 0x6cda47c6, 0x819fb2e7, 0x144346a1, 0xa09d6849, 0x76a8586d, 0x8cf477e7, 0x21d64776, 0x97015b41, + 0xeed5d9e6, 0xf59867bd, 0xc817cf29, 0x5b8c7014, 0xbb8508f5, 0x507deb8b, 0xa65c0770, 0x60f8abbe, 0x01ce7782, + 0xc55e455b, 0x90ad1a50, 0x7bfe3dc4, 0x697728dd, 0xd80931af, 0x2d270a51, 0x36f52839, 0xac219b5c, 0xec137575, + 0x0e38c965, 0x0432ef68, 0x8fd09ba7, 0x75b798b8, 0x3c870779, 0xa2afbf85, 0x7780a17c, 0x1dc35adb, 0x3e2489b3, + 0x591aad01, 0x891b5a82, 0x63eba35f, 0x3c19f901, 0x64ea4c8f, 0xfbbb0f2a, 0x7f4d527c, 0x8e5bb4ba, 0x3d15ffbd, + 0x6201c6b4, 0xd4ae1373, 0x0b67218e, 0x6c945b14, 0x9af8e37c, 0x3edbd78e, 0xac99e67a, 0x5fa30566, 0x47cdd759, + 0x500ff28a, 0x077a4dfa, 0xef23746a, 0x05e059be, 0xbcc5137a, 0x76f505ca, 0x4acc6bb0, 0xd9f25697, 0xe1572282, + 0xc145558c, 0x797f9eb9, 0x8256731e, 0x4a95aa8d, 0x903b8d61, 0x2e23f674, 0x9183d4bc, 0x8267dabb, 0x7d1a2c81, + 0x591cd4d8, 0xd8131f54, 0x47886d7a, 0x6f45d66e, 0x9c17990b, 0xf6407cea, 0x36711fd6, 0x46045dc6, 0xd9b3aa29, + 0x6b83317e, 0x68841a3e, 0x01274c35, 0xbe6f65e2, 0x590d61d1, 0xf726f144, 0x5ce27e4e, 0x379a087d, 0x20a3e7de, + 0xa0852a8f, 0xdfb3da53, 0x48a3440a, 0x57d56149, 0x562a3fb6, 0xa529ddf3, 0xf1f282ee, 0xc7f29a18, 0xfe5357ed, + 0xe9c4b57a, 0x9a89c042, 0xa24932d7, 0x8f879452, 0xdcc39245, 0x7a2f6a4d, 0x172a8fbc, 0x8a080edd, 0x9cab61ed, + 0x281680af, 0xcbf6b6f0, 0x82287ef5, 0xacdfaa39, 0x20004715, 0xee8dc9f1, 0xaee3274f, 0x8debaf6d, 0x4d37da0f, + 0x851c0763, 0xbaf40a82, 0xa5bab9db, 0x956ae1f1, 0xecd67210, 0x2365516f, 0xe394b89a, 0x64aa58b8, 0xc0334fbf, + 0x45f294ca, 0x1aaa9ef5, 0x66362c9c, 0xfc1f477b, 0xbc322930, 0x41588133, 0x72bfc11e, 0xddc0fbb6, 0xb34078d0, + 0x1739fc22, 0xd5d1dd77, 0x9c3fdbdc, 0x6366b4fa, 0xc4ef4416, 0x6981e017, 0x75a29250, 0xb23d501f, 0x6c2884a5, + 0xbb24bf48, 0x2225a4cf, 0xa58fb4bd, 0x5c5248b3, 0x9ff92574, 0xd15a128f, 0xf2d2b8f3, 0xf0f026ec, 0x1ae49be1, + 0x776706dc, 0x698bdb49, 0xaac41b07, 0xc078c543, 0xd74fef65, 0x6ebe7260, 0xeb9202b1, 0xd218d013, 0x64b2ece5, + 0xc2006b1a, 0x405168c1, 0xe902a3b3, 0x5dff82c7, 0x70cf3cd0, 0xd0877304, 0xcddef1bc, 0x73eb3863, 0xcc4228df, + 0xf66e8418, 0x31c7af56, 0x938882aa, 0xcbafe2ee, 0x4357acb8, 0x0ff322ef, 0x5d334ed9, 0x2f231984, 0x558ef287, + 0x422a34ba, 0xc759ccd3, 0xf3c6b894, 0x1edbb029, 0x71bc6cdd, 0x4eb1354e, 0x0c30032a, 0xfc761658, 0xb4e70d39, + 0xc31e5f5b, 0xff01703d, 0x1dec442d, 0xcf58572b, 0x2b8b8d10, 0xe9499806, 0x9c3f27f4, 0x3d38dc0b, 0x928f13ce, + 0x7db23a84, 0xc07adee0, 0x73df43ff, 0x95729d47, 0x0fe49482, 0x6520bb53, 0x78e351df, 0xee33b671, 0x5169934f, + 0x200ecebd, 0x51e50da5, 0x0e62b1a7, 0x6c8f546e, 0x88843a8e, 0x659f09f1, 0x471a1cb6, 0x099b58c8, 0x44c1c93a, + 0xba7c15ce, 0x2f9f6b69, 0x0362ed31, 0x0b3d8d09, 0xdcfc3c27, 0x93eaea67, 0x7dc35c6c, 0xdec47c4c, 0xcafda8ed, + 0x81ad4cc1, 0x70134dd5, 0xe0e88a25, 0xbe462910, 0xf2b5b1f7, 0x44ed536b, 0x59cc03f4, 0xcd87d79d, 0x421f7a30, + 0xb79a53fb, 0xaddb955f, 0x30641e89, 0x7ab73fbe, 0x8ae34fdd, 0x55042fc0, 0xd91bd970, 0x44805ee7, 0x5e50069c, + 0xd0d73a9a, 0x4d9afbf3, 0x41e12f26, 0x47cc9c1c, 0x5773a657, 0x8a99759a, 0x0ae056e3, 0x5fc4df4f, 0x6b09d67e, + 0xff826f95, 0x7ca24a49, 0x7eeb29eb, 0x2b5d3bb1, 0x50314a83, 0x6f0cf229, 0x46372695, 0xb834a623, 0xc0565677, + 0xc6d3676c, 0x66b1fcc2, 0xe50c3f94, 0xb0b34959, 0x9e96818e, 0x7bfc8dc5, 0xbffc49c4, 0x79d4523f, 0x38718585, + 0xd31ed0ea, 0xde8b24ab, 0x92b22320, 0x933fb369, 0x9d14ad76, 0x16ebea29, 0x5d50d2bc, 0x6ffaa8d0, 0xb573bc4a, + 0xdd5ba5cd, 0x365ae0b1, 0x5fbf5f97, 0x58b25a45, 0xd9f0e98e, 0x89d19846, 0x23636ca3, 0x89e9aee7, 0x31601e6d, + 0x85f5e50a, 0xa412057f, 0x5224b319, 0x01149354, 0xc3e055b2, 0x64312d45, 0xdec7818f, 0xb8589c2d, 0x5b7628fc, + 0xfa289ddf, 0x0f070f17, 0xaa5ff47c, 0x632c3489, 0xfa8909ed, 0x13abee5d, 0x4014ae5d, 0x895430d0, 0xeb9e55e5, + 0xf1fbb1ff, 0xb10383de, 0x99ab112c, 0x1124fded, 0xa3a62c47, 0x109906fe, 0x188f69e5, 0xb00460fe, 0x12da739b, + 0x7eebe695, 0x4687b8ad, 0x91fd3924, 0xfb525c57, 0xc13b5439, 0x15646b97, 0x5256c12f, 0xa66edc25, 0xfd48f890, + 0xeef77997, 0x89c402a5, 0x6bee50a8, 0x68511be7, 0x07e159d0, 0x9b3df230, 0xcd0b1c8a, 0xf847db17, 0x1c2365fc, + 0xa5c6eda9, 0xd5755c84, 0x8506ff92, 0x4bbf61ae, 0x91a100c0, 0x05bad911, 0x4e6f2eb6, 0x8e1f601c, 0xeee030aa, + 0x2ab7ed5d, 0xb4c7cfb6, 0x761ee504, 0x3910a592, 0xd8f8d937, 0x5910d992, 0xd0cd1a95, 0xd2649406, 0x796e47c0, + 0x9b7fbb71, 0xdb1840b8, 0xb3612b58, 0x62068cfe, 0xe9d0e32c, 0x08c22a11, 0x9ec02b3a, 0x5c3610f3, 0x5047c6bc, + 0x8b368f9f, 0xd2e99c71, 0xdfe02cb0, 0xecd757e9, 0x127a126c, 0x5f7b281d, 0xe0b75389, 0x9b2d27a6, 0x32137c95, + 0x60d055b2, 0x59fd8382, 0xc0f770f1, 0xc36d03e4, 0x0de001c8, 0x8e06e879, 0x0643c88e, 0x9a06e8dd, 0x47512667, + 0xad07554e, 0xbf0133e8, 0x4bd7b0b9, 0xfa512981, 0xd05c8a94, 0x6657397f, 0x012c9a73, 0x22fcaa30, 0xc186a6d6, + 0x8dcea2ce, 0x0905201c, 0x1f66f9ed, 0xbf079018, 0x2a0825a5, 0x3a19fce8, 0x86644d8c, 0x2a8e0daa, 0xe92d395a, + 0x36fbb62f, 0x4892d374, 0x99ce4107, 0xfb26617a, 0xe884b5e8, 0x9ae98d07, 0x12300f45, 0x22226de1, 0xa19ad06b, + 0x99f67a86, 0x920c75f0, 0x8e1fa5cd, 0x2d3761e9, 0x73b019cc, 0x8aa7c2aa, 0x97fc0c8e, 0xdd286d84, 0xeae9b005, + 0xb5ef9709, 0x6808ef21, 0xf8a01d01, 0x59cd6cd3, 0xd6bdb8f0, 0x218fe067, 0x4a4bf249, 0x3c07d200, 0xaa6891a0, + 0xc8f9b777, 0xf20d5276, 0xb3369630, 0x73024913, 0xcb6a9331, 0x4431cc76, 0x88a86447, 0x0b6fde33, 0xab6887bc, + 0x1da55dab, 0x0c9bf86f, 0x0fe4cc86, 0x7a793b78, 0x410f0684, 0x3cc1fef3, 0x5eec2d96, 0xbdd41d68, 0x28883844, + 0xabf5d067, 0x5bc5e311, 0x5e45b429, 0x610f927b, 0x36faf43e, 0xf8c4e1ec, 0x33e9229b, 0x12365fe4, 0x5ec98bf5, + 0xa34db000, 0xcd5969da, 0x02e73d49, 0x8756be53, 0x9905d219, 0x47ea57c8, 0x4a7d86c0, 0xb6f1e850, 0x3cefd7a5, + 0xb95a899c, 0xa42875cb, 0xea734432, 0x63847dbf, 0xe000474c, 0x3d956480, 0x6cefe572, 0xc78a09f5, 0x004e73ff, + 0x94fa111f, 0x7166674b, 0xa18cd5b0, 0xbef7cfca, 0xb440ec91, 0x8bb6c717, 0xc97228dd, 0x7ca55c91, 0x2f53bb20, + 0xde053eab, 0x0d383f31, 0xa534d345, 0x0e3acdc7, 0xe3b51134, 0x0d79ea2f, 0x3cee53e2, 0x46036c01, 0xcf9839e8, + 0x3bf4f248, 0xa8c62fa6, 0xcd2f087e, 0x3d159891, 0xc15ae0b6, 0x4564dddb, 0x7ae1fc17, 0x27944264, 0x129f88d8, + 0xe9ffa60e, 0x66ed7557, 0x7e0db77f, 0x530e4e99, 0xd9b3a093, 0x534ed0eb, 0x89d39583, 0xf1a41a86, 0xe7fb4523, + 0x6f047c6b, 0xc13b9fe9, 0xba56b490, 0xb64913e0, 0x56b7b78c, 0x7723304e, 0x491ac402, 0x813b3d2c, 0x7e2b7c74, + 0x052c9438, 0x8027ffb9, 0x1f348d02, 0x9a993c6f, 0xaf76425c, 0x2e2de85a, 0x18f0106d, 0x6344e442, 0x8eec2111, + 0x041697e2, 0x72c0c7cf, 0xcf882333, 0x68dc7382, 0xd25d2a42, 0x3f2b3c29, 0xb64b242b, 0x900c07e3, 0xc15c235c, + 0x3e3399e5, 0xef9af975, 0xa89d6e25, 0x9d62f3e3, 0x63b8c8ac, 0x74a89dc2, 0x44983cc7, 0x2445f995, 0x79c51c79, + 0x51f2c995, 0xf9a7c987, 0x1d695df2, 0x211226ef, 0x3bcacaff, 0x0949a2ac, 0xc557d428, 0x2174b5d7, 0x21b8196c, + 0x28affed6, 0xda95a01a, 0x697fc09c, 0x67b55384, 0x6279cd1c, 0xd0262653, 0x2bd7a1d4, 0xff69bc9d, 0xc2eb93e0, + 0xb6d32872, 0xc6dafaca, 0x89f674a5, 0x3ebfc03c, 0x0b74a407, 0x47587260, 0xe3a15bc8, 0xb0ceb022, 0x05e93a77, + 0x9b81f6bc, 0x9329549b, 0x6e731dad, 0xf3a29ef6, 0x04c215c8, 0xea3d8a1b, 0x5bff38da, 0x1d694c99, 0xbd38f015, + 0xca3b96e3, 0x8452e1f6, 0x61802791, 0xabe9c016, 0xdd0d107c, 0x06dff3d9, 0x627870ed, 0x94565805, 0xba5a29b2, + 0x433bae6e, 0x5b90c95e, 0x4f22569e, 0x01717fa8, 0x80c8291b, 0xd831bad9, 0x327c7772, 0x868cc52a, 0x409d6530, + 0x99881008, 0x387db540, 0xac8bc231, 0x27c959e1, 0xa556049d, 0x744fdb4a, 0x5a783980, 0x53e7967a, 0xce8281bc, + 0xe56a91cb, 0x7ffdd68a, 0x223a82be, 0x984bac87, 0x395f229c, 0x2e6cee06, 0xf5536bc6, 0x7ba8ba70, 0x0ac9ad64, + 0x04feb596, 0xe59811c0, 0xa259245d, 0x220bb5b2, 0xfbca0603, 0xb9b9dac9, 0x0f7f0b46, 0x308bb0e8, 0xcb4d43b6, + 0xbc107268, 0x57204c58, 0xa4f810ed, 0xe3fc505e, 0x6c040f11, 0x7f894cde, 0x16657c7a, 0xaa953c70, 0x8ae5b075, + 0xa9e7494f, 0xc40239ae, 0x4dcb7be2, 0xa73dfb3e, 0xa92dd354, 0xede7df4d, 0xd6f7d666, 0x1ebbe31c, 0x27e9c871, + 0x0aacea64, 0xd496428a, 0x3dea3100, 0x1e11a0b7, 0x65b9b85b, 0xd781a90b, 0x024d955c, 0x8b6fde4c, 0xbcd5bf7b, + 0x809bb3dd, 0x7bf5c317, 0xfffda270, 0x2ee4a59d, 0x1e4ffdfd, 0xcfcf589f, 0xf79c2f5f, 0x748e73a1, 0x5b7cd610, + 0x71b28734, 0xd5e981c8, 0xe72bb5d2, 0xf0f641e5, 0x427017ae, 0xd5c07c96, 0x1c619792, 0xa7e8d2e5, 0x49b30ee0, + 0xac2eea3e, 0xc5dce055, 0x5db57d45, 0x51c07c88, 0x029ed502, 0x8c1e207e, 0x96692eab, 0xfd96be23, 0x8f23a30a, + 0x301c1347, 0x4ad569d1, 0x413960e7, 0xcc994730, 0x328ef8ca, 0xb59b98b2, 0x822ad3d5, 0xc212bf02, 0x5c060d26, + 0xfd61fd2c, 0x1af7bdd9, 0x976929e2, 0xbc444cc7, 0x2cd83229, 0x866e8f60, 0x2fc33e01, 0x1a802589, 0xc4b184c9, + 0xcfc0c6e4, 0x56352514, 0xf4417f26, 0xb0a2a553, 0xc43c4f93, 0x70fba896, 0x4e6444a2, 0xd24e882d, 0xea5317c4, + 0xdfde3029, 0xda9dcbac, 0xe79851f0, 0xba6205e8, 0xf059885d, 0x7b312f8b, 0xd570f4d9, 0xa7e086b3, 0xb637eae6, + 0xb2f4db85, 0x2c4f7ac3, 0xdab8b9ca, 0xe05287b7, 0x42d095e2, 0x41f9a576, 0xdaf88c29, 0xc23760c2, 0x852b81d3, + 0x1af725db, 0x60686233, 0x69e36b2f, 0xd1a7f120, 0x04c856ad, 0x4566c769, 0x4f1b0eae, 0x9ad6585c, 0xd92d0211, + 0xfc09d18b, 0xfa061d22, 0x2464978a, 0x055ffcf3, 0xd5ec26a1, 0x607a5df6, 0xb87cc426, 0xa6e2db7c, 0xd5488781, + 0x0bcf384c, 0x92a1686a, 0x6be81234, 0xb755163e, 0x3dcc3724, 0xfd4614c6, 0x943bad16, 0xec35080b, 0x052600f8, + 0x1d1e37df, 0xa9c19a28, 0x850dd872, 0x23c1acde, 0x126610d4, 0xc7f8f2cd, 0x24536a09, 0xc224a0c5, 0x47d71bb1, + 0x8db63252, 0xbbe1a69b, 0x8ffbc397, 0x98e9be72, 0xb86795dd, 0x6ac02dec, 0x3b0a793a, 0xdb55d38a, 0x61c28f2f, + 0x6e774159, 0xcff25b37, 0x11800495, 0x9f447a42, 0x9f6a9bd3, 0xa7c69fe2, 0x6605066f, 0x6349b4fe, 0x2b66324e, + 0x23691ec2, 0x57c8e54c, 0x6b6e175e, 0x0dd76bd4, 0xd27d538c, 0x4b43b203, 0x57912af8, 0xa000bbe2, 0x7fc4d53f, + 0x25ec1f49, 0xa96b7754, 0x6e2689bc, 0x50656d25, 0x8cfba107, 0x364d3e71, 0xfe83bdb9, 0x695e93ea, 0x063c9902, + 0x695caf4a, 0x3f9d8dea, 0x2124b9d5, 0x0930c502, 0x9c10a5aa, 0xc12803b3, 0x1a4988f5, 0xc332ca86, 0x9cbc72f1, + 0x566d2c7e, 0xb1840f23, 0x992b51f6, 0x3b84659f, 0x395532a5, 0x6ce7aa6a, 0x9f9c0be8, 0x5d824e26, 0x63c21811, + 0xe14b59c1, 0x7240182c, 0x147c8c25, 0x9e99d5f4, 0xaf80029c, 0x01b19261, 0xc53749b7, 0x84d02439, 0xe8c6f840, + 0xe8929e99, 0xcdf0d64f, 0x43925f38, 0x567499d0, 0xc2d9530c, 0xe39942e7, 0x8e1232ac, 0x7d17ce39, 0x66f41e04, + 0xaa16e9f5, 0x83b4ec05, 0x6bc0cade, 0x67b5876a, 0xa74a9151, 0xdb62be43, 0x32ed306d, 0x71850756, 0x5ce3549e, + 0x9d06a409, 0xe4b52779, 0xbeb1f5e1, 0xde0a7341, 0x2b467a6b, 0x504f9ce5, 0xa76a173b, 0xaca6cdd3, 0xc372651c, + 0x4a3a3aff, 0x65f6144d, 0x4e53324b, 0x8b26cd5e, 0xc8327e9b, 0x10939825, 0x64098078, 0x035c7ab8, 0x8542ea7c, + 0x45189271, 0x9472cf01, 0x52151327, 0xf31bde8b, 0xcb2de1ef, 0x3c0e98b1, 0x4c2ecbf6, 0x5a503d9c, 0xd8666333, + 0x17027dfa, 0x474a153c, 0x0ca84beb, 0xe5eba6ca, 0xe3c48267, 0xc0a6e0e0, 0xd23af17c, 0x82d340c5, 0x4edba760, + 0x09f64918, 0xbe648b36, 0xdefc6b03, 0x7980e1c7, 0x7cfcef3f, 0xaeb4ef1b, 0xdb6634dd, 0xebc7feaf, 0xb7cc95eb, + 0x739f0a20, 0x031a5c6a, 0x20377b98, 0xd93d63c2, 0x59839bd3, 0xb389c1bd, 0xe8646d3e, 0xfbe52e15, 0x7e1000e0, + 0xc5e447c2, 0xf8d2e132, 0xb4e5e99b, 0xc247f970, 0x6f66c1f0, 0x906c53b6, 0x71bff7e0, 0x7d3fa905, 0x9186da88, + 0x49afa6e5, 0xd61ebb72, 0xa20734ab, 0x1be4e7b6, 0xc129ef56, 0xef3034df, 0x487b6ea8, 0xd328f496, 0xcc7822ac, + 0x74622148, 0x22474198, 0xd4379237, 0xbf39a68d, 0xcffc9f58, 0x8f51fa36, 0x22fb18bf, 0x464445bf, 0x95acaaa1, + 0x072ebdb7, 0xeb48d658, 0x39aafed9, 0xbbfaf371, 0x94047277, 0x74fa43fe, 0xe13a8918, 0x931ef15b, 0x172c68b8, + 0x03ced234, 0x2d6d7271, 0xa4a0bc1f, 0x48f03e4b, 0xf4cd3b51, 0x266d2adc, 0x82bfc2d7, 0x43daa264, 0x078622be, + 0x14a31922, 0x5ce6352e, 0xf943a6df, 0x298a6034, 0x65b5287e, 0x529b0eec, 0x71db9a3a, 0x0d6ec796, 0x9a58f215, + 0x848bf18e, 0xd5bcacd0, 0x0424377b, 0x60e7bea9, 0x420ec728, 0x98064288, 0x70a08ab0, 0xfba38e2e, 0x82943543, + 0xf215a98a, 0xb05e3e43, 0xbf9060da, 0xc6de35c2, 0xbc973274, 0x6ea5416c, 0x8ebb82bc, 0x3aa9e44f, 0xbe9a7df1, + 0xc3f7cbea, 0x3c866eec, 0x3301670e, 0x893d84eb, 0x6b863054, 0xee0ccc2d, 0x62ed41cf, 0xdb0d0aab, 0x3759dad4, + 0x1b239d0f, 0xfb1dbe26, 0x4230b984, 0x3f87f72e, 0xfa0674e1, 0xef9c7a85, 0x09f4f5e8, 0x5363d1f7, 0x6bb529fa, + 0x441e7e2a, 0xf555c00e, 0xf3b185b2, 0x03371475, 0x37d2a602, 0xbe965bf9, 0x422ee35c, 0x6799988e, 0x4689a0f7, + 0xefdf68b4, 0x19971eef, 0x962a1e2e, 0x8f89b0b4, 0xe31890e7, 0xf907ac8d, 0x2282df54, 0x7f6d83e7, 0x4305ef16, + 0x3a44f275, 0x4917095c, 0x12759102, 0x948b0ff2, 0x890f9b58, 0xe32c1731, 0x15a9af94, 0x8915d181, 0x33081a17, + 0x258d918b, 0xa0b56bb9, 0xc5a20c93, 0xde083f96, 0x8cf6d683, 0x8dd122ed, 0xf20feae3, 0x17edace4, 0xe41d2920, + 0x198168c7, 0x2e7cc14a, 0xdc5d29c7, 0x91905259, 0xb7328526, 0x3c3016b8, 0x54c5f610, 0x682277fa, 0xcb4d34ee, + 0xf74034a3, 0xb46bed23, 0xcd4ec110, 0xead86593, 0x6a16e288, 0x543d7a43, 0x57a4e104, 0x39a0c477, 0xe0805e57, + 0x711c1500, 0x5f6fac6a, 0xf59307bf, 0xa972333a, 0x28f91dd5, 0xf406cce2, 0x7ab4279d, 0x51bf96f4, 0x32f99ad9, + 0x749d777a, 0xc0d3fce6, 0xd3dc2259, 0x512b61d0, 0x6432c192, 0xad90dc90, 0xcc3c2cef, 0x624a93e6, 0x465afbb7, + 0x4856dcb8, 0x595a39ea, 0xd0c9b99b, 0xc01582ab, 0x621fe32b, 0x17bc08de, 0x4f315170, 0x544597cf, 0xf86f066a, + 0x3d428996, 0x205aa14b, 0x1143d746, 0x3ee5726a, 0x7364e617, 0xe7630f32, 0xec9b6f0b, 0x4b99231c, 0x721a6c23, + 0x1c727b60, 0xa0228e71, 0xe6e48043, 0x7a437285, 0x1df8e040, 0xfed6a030, 0x7a80207b, 0xfbb1ad65, 0xb093f085, + 0xb7d56b32, 0xd5980bfd, 0x49af478f, 0xda19e375, 0x2203f463, 0x4351e8a1, 0x5c493d59, 0x18028e86, 0xb72792f7, + 0xc7a890af, 0xcf6c7e7a, 0x87fa7200, 0x70fcb074, 0xda7ab526, 0x456b0674, 0x6d849a9e, 0x1f6552d4, 0x9d16eb5f, + 0xd9c013b0, 0x6540a2d6, 0x9dd24a7d, 0x3db64f7e, 0x88c6be65, 0xd8af4911, 0x5a284b4d, 0x89a69045, 0x8e25d318, + 0xab9baa2a, 0x6e772294, 0x44ed37cc, 0x6c0b3862, 0x3f21f075, 0x80d866c4, 0xb9080009, 0xd62a01ef, 0xf73ce11c, + 0xd5503276, 0x09bceb86, 0x76cad292, 0xf29b22f2, 0xb153a96e, 0xa6a24d1d, 0xda4b8225, 0xa60f31e9, 0xb1dfa09c, + 0x2e8c5fc0, 0x1ae6568a, 0xb33dda73, 0x5ea87c71, 0x2110be47, 0x17077712, 0xa45546b6, 0x67f3ffd0, 0xeee0cd81, + 0x6aad6b00, 0xf93b63ef, 0x0f79f9f0, 0xab808991, 0x3e6921dd, 0xbce9c010, 0x6c0d2225, 0xed629c06, 0x34461ecf, + 0x01e57c2f, 0x0630529a, 0x8dc4b77f, 0xd6e863b6, 0xf481dbb6, 0xf77670a7, 0xc4458afb, 0x03215723, 0x58fecb1b, + 0x7e4d54b4, 0x3d7cd094, 0x92325319, 0xa05596aa, 0xee9b5003, 0xc2bd30e9, 0x1aaa6362, 0xf4fad7b5, 0xb1409031, + 0x9df6cca2, 0xdbbeef9c, 0x61df0804, 0xadf3f17c, 0x47ce3a2c, 0xd94685c8, 0xf08dd0d4, 0x0f7c2a0c, 0x426b2d94, + 0x86b06e45, 0x38e18aef, 0xdc45fab0, 0x51badb7f, 0xc538e51d, 0x6eb166ff, 0x874e8568, 0xadc2e7e0, 0xd89e3fa0, + 0xdd5891cc, 0xe701a114, 0xcb74c8ed, 0x2e7788a8, 0x5236f886, 0x39edb6bd, 0xacc5dac5, 0x8d421c27, 0x8d5a1782, + 0x8084ff0a, 0xee60fc2a, 0xcd53b3f2, 0x9dce2adc, 0xa1e1ff7d, 0x8b21866d, 0x9ba84bd9, 0x22697629, 0x4c676aaf, + 0xb6f99dc7, 0xc98ca190, 0x7e18014d, 0x7f8b10f4, 0xb014198d, 0xdbc6e927, 0x959b7346, 0x94841245, 0x7d40ca55, + 0x190f38c1, 0x1f605fe0, 0xffb50440, 0x4d3db2b6, 0xf69ae175, 0xe5e854f6, 0x527d7436, 0x0a5e20bd, 0x84f137b9, + 0x355aa4f4, 0x8af17992, 0x55f5d591, 0xe2158e54, 0x816b6173, 0x403d1997, 0xb6097c96, 0x882ce972, 0xf78dc739, + 0x7cdb7fd3, 0x47347786, 0x5ae95783, 0x9c78e9b9, 0x0409b32c, 0x32b1cd3b, 0xcebc9081, 0xea21a036, 0x4a9ae607, + 0x99a0175c, 0x97fdaf1c, 0xcc46dd67, 0x560803e0, 0xcd223e23, 0xbb22e00d, 0xabb034ca, 0xfa84eac0, 0x51c6ae88, + 0xdafd708d, 0x7858684b, 0x8dbf5c2c, 0x2ccd716d, 0x83f3d441, 0x85e7f4ea, 0xca05b0fb, 0x043d8ecb, 0x1fa6058c, + 0x95fb4ebd, 0x011afc45, 0x6c680fbc, 0xd6dbb869, 0x081f0ced, 0x67b5b65c, 0x4ce35e72, 0x34ff4c08, 0xa7ddf8b2, + 0xe6d59f71, 0xeb655b08, 0xe071ad0a, 0xdd4b301e, 0xfb8f657e, 0x3e90bd78, 0x0be7723e, 0xcccd2f9c, 0x4d87e07d, + 0x97a3ba17, 0x847acffb, 0xc19078f8, 0x4eacbc8d, 0x4de317b1, 0xb50cc7ba, 0x88fa8972, 0x4ab22b47, 0x590c3aee, + 0x510c41b6, 0x53ef0ae6, 0x976200e6, 0x3da24763, 0x759eea0c, 0xf2e3e037, 0x03a5a4fb, 0xbf46d2dd, 0xf453269e, + 0x03db4380, 0xe4a0e96b, 0x9f089be9, 0x27b2a815, 0x3b3ca739, 0x69fcbf3f, 0x1e2d10a7, 0xee578102, 0xbba47e25, + 0x648bca1d, 0x681de828, 0x5a0e4d1c, 0x37acf394, 0x4d9d2a7f, 0x9a4deaf9, 0xfc914ec7, 0x6e8c302a, 0x3a504ef3, + 0xf8d4a0df, 0x5bd77e95, 0xf08a2498, 0x3992969a, 0x159e0e74, 0xd0d68e1d, 0x49a7df92, 0x8789ec85, 0x61c23123, + 0xd9f80227, 0x42a0cb74, 0x116db56f, 0x714ab7d3, 0x23460c1d, 0xdb893b2d, 0x9c0ec5aa, 0x3c7d3699, 0xb1b7a4e2, + 0xfdbed9d0, 0x721f20e9, 0xe82671aa, 0x74bb03b4, 0x48b1022e, 0xa8db6e0f, 0x428045c2, 0x34e9eee0, 0xdd2f8e6a, + 0x27381f87, 0x349cdca1, 0x0472ddd4, 0x7dd7a2af, 0x6752bbde, 0x95e14213, 0x35e625df, 0x2e42bef9, 0x21e4a9cb, + 0x257381ef, 0xbbf84651, 0x3f133e5a, 0xe1279084, 0xd63b9b54, 0xa0f68883, 0xd63b86d9, 0xafdb2ff7, 0x5d114823, + 0x86bc325f, 0x16a7617f, 0xa6a094ac, 0x109f0abd, 0xb35557aa, 0xc4974187, 0xc8eb102c, 0xdafcf62a, 0x0356657c, + 0xce6fcca1, 0x6a31738f, 0x4ba91240, 0x4d78454b, 0x6ef2b542, 0x5ff87d49, 0x6423cc80, 0xecb8dd8d, 0x2877c628, + 0xca1f0294, 0xe49c6225, 0x9bbbddab, 0x5dbf12df, 0x265c34d1, 0x7fc02e26, 0x39f2cf16, 0xc039d687, 0x70f5fb71, + 0xd3baaf09, 0xf97286e3, 0xba4936a7, 0x8407bba2, 0xe6d59dc9, 0x823e63dc, 0xc914e832, 0xd11d40e9, 0xa8ea5eb9, + 0x0ff261e7, 0x15eb1319, 0x33915176, 0x5b3f95ee, 0xc960585c, 0x9af71abd, 0x4209bb23, 0x9083a759, 0xbf420ecf, + 0x3967a345, 0x36394a8c, 0x65d34bd0, 0x78fcc807, 0x0595fb1d, 0x7025fdaf, 0x05ebd149, 0x91d71075, 0xda721a9c, + 0xa2fc39c9, 0xf20c25b5, 0x7d1c33d2, 0x0a64f1c6, 0x0d5096e3, 0x43104ced, 0xc86e999c, 0x3332fa16, 0x8453849b, + 0x57cfa35a, 0xa2ebe27c, 0x00d4257e, 0x7c4cf1f8, 0x73c9e89b, 0x0031d1ab, 0xf0a76bfe, 0x8e088332, 0x1b1acf0e, + 0x09de7240, 0x5fd56b29, 0x3deaa4da, 0xae360ef5, 0x690a855b, 0x7cc9e11c, 0x60bd61ae, 0xcf92a29b, 0xd7efbc94, + 0x03b17ebf, 0xfaf7c518, 0x71b6ea10, 0xe7a0de7e, 0x305e4d04, 0x1b90e589, 0x2f44033c, 0xcf51f4b2, 0x230dae56, + 0x8bfd1b6f, 0x5aac397a, 0x82b5b7df, 0x6bc1eb29, 0xf13a29b5, 0x4ddec8d3, 0x9bc1efcb, 0xb99c91c4, 0x6fa93bf4, + 0x958a9bb3, 0xec4caae6, 0x785e82c6, 0x561bcfff, 0x46b643b8, 0x68314462, 0x9cc9526b, 0x053a2016, 0x14efc499, + 0xa5265942, 0x6bc8da1b, 0x21a14191, 0x828c488d, 0x7f43610f, 0x014394c4, 0xaff8c308, 0x43752ba6, 0xe038ae4e, + 0x226f5910, 0xe4047ca5, 0xa2755b2d, 0x395d7c86, 0x13ba30c3, 0x661478de, 0xe3cb5362, 0xbcb4c365, 0xad664275, + 0x0e75f918, 0x35737482, 0xab1a7d86, 0xb1bc75b6, 0x1885261f, 0xb170669f, 0xf0af4ce5, 0x78763a20, 0x9cd50415, + 0x0282b0e7, 0x1d4251c6, 0xba314777, 0x91ec6368, 0x40656d5a, 0x1f9bc352, 0x728a066b, 0xd8759baa, 0x5d9fcfd3, + 0x74ab74a6, 0x6ca2516c, 0x9130117c, 0x7e184a90, 0x5d93da5f, 0x01a787c2, 0xf520a519, 0x276adb67, 0xe231e445, + 0x5f825dfc, 0x151a3f7d, 0xe5abe75a, 0x59a29919, 0x91216653, 0xe9ecd1e0, 0x3c257335, 0xfc3a6d40, 0xd85bc31d, + 0x32415ea2, 0x5a9e56af, 0x312d6177, 0x3f24001b, 0x1eb8b1a7, 0xe140b532, 0xd80e14a8, 0x7ce42d6e, 0x7b721614, + 0x654489d1, 0x7818243f, 0x96195bf3, 0xfda92246, 0x9a1b61cf, 0x3c7d52c9, 0x3490a2a2, 0x47777dcb, 0x7ec27c52, + 0x704286ba, 0x8064e9f9, 0x4f00e3fa, 0xa1e65057, 0x70664e2c, 0x742498ee, 0x7efd8584, 0x659b7410, 0x0754a583, + 0x848f5646, 0x673fe321, 0x72188220, 0x546dab96, 0xa6d4c079, 0x9317817c, 0xf9b280ab, 0x89db5391, 0x4a24387c, + 0xea250388, 0x3bbaec32, 0xe3bbefcc, 0xfddeb04e, 0x71ed1e62, 0x1085883c, 0x678c046d, 0x6220d919, 0xcfbe8903, + 0x7a78f7c4, 0x00d0bb5a, 0xc96a1b29, 0xcab84b62, 0x292de4ce, 0x7f7be7c1, 0xdc6c6135, 0xd69914e8, 0x21cf80ea, + 0x64505934, 0x5f88e85c, 0xa37bfc3b, 0x06e3e54a, 0x3ff5cac6, 0x419b100c, 0x1b504a5b, 0x0ec5db30, 0x06815b14, + 0xc06da404, 0xef52d174, 0xc4ad4609, 0x4bb4cceb, 0xf74305e7, 0x0a8f1aad, 0x03cc0b9c, 0x1523d12e, 0x4702408c, + 0x96558a0b, 0x6dfbb904, 0x42583006, 0x6121f202, 0xc9081639, 0x1d4905f8, 0x7406f0da, 0xfd7abc92, 0x4fce9c11, + 0xcadee92a, 0x215ee28e, 0x304787f5, 0x5475e6d0, 0x941b9f60, 0x3fa5b65b, 0xc653e51b, 0xd0d4c51b, 0x9d832998, + 0x64d9a1ca, 0xc5b71513, 0xbec78c7b, 0xd6aa94f8, 0x671a438e, 0xc8c4d5d5, 0x6e8ba6c9, 0xa0a1671a, 0xb7345e86, + 0x44e251ee, 0xc6f13931, 0x8880c8e0, 0xd35bf989, 0xae323a74, 0xfc53f07d, 0xd7820a2c, 0x7ec426b4, 0x7dafb303, + 0x4b4c6d8d, 0x561f9520, 0xe8c2e945, 0xe7c2537f, 0x1cd6566e, 0x32a516df, 0x4172108f, 0xac3025fd, 0x89baccd7, + 0x5f19bf12, 0x1e76df7e, 0x32842f96, 0xce4e11e2, 0xa2860419, 0xf11f0c7f, 0xcb81c931, 0xec649f03, 0xc948c6b6, + 0xc43ce9ef, 0x34adf94f, 0x3af98753, 0x07b7fc4a, 0x131d9d5f, 0x506d286b, 0x11507bf2, 0x574c45f9, 0xbadf2f15, + 0x432c64c0, 0x109b2b07, 0x2aef15fb, 0x7c6e6e03, 0xb1984fd0, 0xeb251e71, 0x1374a4fd, 0x5c2b55d3, 0x572576c3, + 0x58eef9cf, 0xb49d72d8, 0xf0e98819, 0x35fb2f68, 0xebab9326, 0x9e499e02, 0x30c34e47, 0xb926ab35, 0xa6770b9d, + 0x7b89dbb4, 0xc5105dc9, 0xbfc9d7a3, 0xb8414483, 0x18478f1b, 0x9b2a1f06, 0xc0cd7f69, 0x80237116, 0x449ce963, + 0x77ad1c3c, 0xb8189618, 0x2025533e, 0x7514b7a0, 0xd5f96aab, 0x3080a187, 0x5daf5bb2, 0x8a764215, 0xbe75edaa, + 0x7e0cec9e, 0xbd083e31, 0x5701b9d9, 0x96cbbd60, 0xa97ba14f, 0x3caa93b1, 0xecf33e89, 0x5bf33d73, 0xf5290ffc, + 0xf4982f1a, 0xdf9d7f90, 0x3f4d7434, 0x260be088, 0xd969c085, 0x04131819, 0xa7b85205, 0x7d5ec134, 0x3c9d735c, + 0xe410f9c6, 0x0b880392, 0xb6a4507e, 0xda1fce35, 0xba8b8d08, 0xbbd6b925, 0xc128fd1e, 0x04fa2db4, 0x0e3a6074, + 0x8a182a5d, 0x9f58a998, 0xcaa5a756, 0xa08d90b1, 0x77c68671, 0xa89279fd, 0x90a2b8d0, 0x5bd707ec, 0x18da8a55, + 0xb7652bd5, 0xc6b1d54d, 0xabbc7e6d, 0x89db08dd, 0x8e96c7a4, 0xa1c19aac, 0x37a158ad, 0x87a10a5c, 0x17b86b78, + 0xef2ad906, 0x0af37205, 0xccd89cd4, 0xef67ff69, 0xd2d3b887, 0xceed7e71, 0x417e54ed, 0x41122d3e, 0x864faca8, + 0x02f63431, 0xab2f2a2d, 0xe7e8755b, 0x00259e38, 0xd5386636, 0x9cc2af11, 0xbd20c984, 0xd259498f, 0x5dc361ed, + 0xa2de805c, 0x4403cdae, 0x0aac2e07, 0x55b917de, 0xee408f68, 0x1ced187e, 0x6711a43e, 0x4a8cbc0d, 0x095363a6, + 0x42061585, 0xb288735d, 0x8f964ca6, 0x4ee62b19, 0xf334bbb2, 0xa0b260b4, 0xf86d1913, 0xc4c4e48c, 0x820bdcc6, + 0x4652533e, 0xc314a39c, 0xdae1bcac, 0x08359e57, 0x75b8fec1, 0xb829caa5, 0x769eba82, 0xfc99cf44, 0xecf18d71, + 0x6cae9ae5, 0xbe177fb2, 0x2dcd2046, 0x2f46d309, 0x9eed166f, 0x80e6fd91, 0x70f1a343, 0x2c18a70b, 0x0141ab09, + 0xf400d2a1, 0x4f7ab75a, 0x553dc38a, 0x01fdb0aa, 0x2cb3cb38, 0xbc76bfdf, 0x56a15307, 0xb2d9931f, 0x65121151, + 0x4c88157d, 0xc4af8812, 0x72e642b8, 0xf62dce33, 0x7bc139da, 0xcb80e339, 0x9c07b446, 0xe4d3e3e1, 0x43bd2241, + 0x0c2c3d59, 0x3094c670, 0xfe55f98f, 0x0e7633b8, 0xb848e306, 0x5a681727, 0x820f32f6, 0x790ed418, 0x90542f1e, + 0x301ce5c0, 0xdfec317c, 0xc8cffc76, 0x4b702278, 0x5fafde23, 0x8e09ca50, 0xf8f74abe, 0xb4ab8f8a, 0x1787b0d3, + 0x307914bc, 0xbea4bde7, 0x0a7c5c95, 0xb1274fd4, 0x4244321d, 0x68284faa, 0xf8a4fcaa, 0x00777a55, 0x87f7a55e, + 0x020e8c1c, 0x9cd713be, 0x6c79d6b8, 0x6fd8bd76, 0xd0078d05, 0x6f1254d5, 0x416c068d, 0x12319c1f, 0xa7d2dc06, + 0xb38d655b, 0x3005caa4, 0x569ec82b, 0xb4fd9aba, 0xbec3212b, 0xe8d83fae, 0x291c6884, 0x737f25f7, 0x95f4c6c8, + 0xdf0eeb76, 0x2fc39662, 0xf65fc383, 0x4914aec0, 0x0182c3ea, 0x6248e4e4, 0xf1405ee8, 0x36fb6ef0, 0xa5d5fd7b, + 0x4230c1c5, 0x664d6bb7, 0x874d3b25, 0x672dbb4c, 0x573bc226, 0x69cdc5b6, 0xf8a67dc4, 0xb0d96a7d, 0xf9c742b0, + 0x59f55eda, 0x7b0f8fe2, 0x2d04b33f, 0x58c53c7a, 0xb1996b4b, 0x9e694778, 0x4fc6bfad, 0x00137284, 0xfdc68000, + 0x3cd466e3, 0x4c7551f5, 0x61e13c9d, 0xf67d5799, 0x24d49b76, 0x0eae02b5, 0x9e6ccb8f, 0x2c8d8796, 0xb229905c, + 0xbeaaace2, 0x1624718d, 0xade5b4b0, 0xbf05f0ae, 0xed5b6179, 0xffd78bed, 0x972e47a7, 0xc0ad8246, 0xc4877495, + 0xe39578d6, 0xe42c3cab, 0x81778d90, 0x3ad9fd51, 0x8d92dfdb, 0x4095bf2a, 0x16ca0582, 0xc5900164, 0x20191d7c, + 0xab5b3968, 0xf5d964e6, 0xb44f9d55, 0x5c08cb1a, 0xe3003d7f, 0x5bdeb219, 0x76e84576, 0x9678b671, 0xf5db12ea, + 0x3e872c25, 0xb612a410, 0xc624eaef, 0x1a8a982a, 0x3252b222, 0x9a2b3e1c, 0xdab82163, 0xd37f4b04, 0x537f8e70, + 0xc6f73908, 0x7626fa5c, 0x831c9298, 0x4378785b, 0xaaf97650, 0xd7b348ef, 0xaf993a25, 0xa3f438da, 0x8fafb713, + 0xfd9e6e55, 0x920a6d37, 0x5ac7cf73, 0xc9d416c3, 0xf107cafe, 0x5a980779, 0x9ad3f292, 0xc7e21fae, 0x6a99d9f0, + 0x16b3b500, 0xa1f079a6, 0x061d7455, 0xcfb8c906, 0x47d21939, 0xe914025d, 0xbd1f7db1, 0xc98e245c, 0x12b877a8, + 0xaaa09c1d, 0xd13cdbf7, 0x58159958, 0xbfa2dff4, 0xc0e488b4, 0x0ab134b2, 0xbd8d5aec, 0x06cb53ca, 0x76720b11, + 0x8bd0d06a, 0xf64b9ea4, 0x6430382f, 0x128c5a92, 0xd51d6660, 0x351ca992, 0xa7ea1fcb, 0xf91d06e7, 0x9b5c7604, + 0x4f54ef8d, 0x81646253, 0xde678c45, 0xec1b37fb, 0xf8c5e9fe, 0xc52b23b4, 0xd0c24c5f, 0x3c6aa0c6, 0xed84481e, + 0xcb34fc24, 0x8771fd35, 0x4ce04f80, 0xcc0693c2, 0x321de8a3, 0x11c06e0f, 0xcd13dddc, 0x26556e77, 0x00322dcd, + 0x66dbe106, 0x95ab58cd, 0xa255a5c9, 0x53bc5f1a, 0x42b63eb2, 0x85ccc9df, 0x479b2335, 0x405dd25a, 0xe3b388ad, + 0x60699400, 0xe945e2db, 0x3b622794, 0x8ab5077e, 0x2a0598ce, 0xfd93aba1, 0x0faf83e1, 0x5dc0cc7c, 0xc011bc37, + 0x2807cad4, 0x608cb60c, 0x2bd36a51, 0xc5e576c9, 0x34ff9f0d, 0xd9266de2, 0x0ee9b6de, 0xa8b35bb0, 0xaeeb3bc8, + 0x2c8edf3f, 0x39ba6648, 0x673f9a9b, 0x31f9e63c, 0xb287652b, 0x7aca8021, 0x4a65844d, 0x2399ab44, 0x877962c0, + 0xda1b5cff, 0x5f10709a, 0xf94542ea, 0x9ac9c996, 0xea30b8ef, 0x6d8b196c, 0x046813da, 0x83b8d547, 0x3fe9032d, + 0x7a1849d7, 0xc40e0d03, 0xac9d0c5b, 0x3f12f34e, 0xb1d1b66d, 0xc0b32e4c, 0x31248cf0, 0x8033149f, 0x378fabca, + 0x80e93a4d, 0x8a94e2a7, 0x0f4fc864, 0x7732229f, 0xaa736d5b, 0x3f47ee68, 0x21a015d6, 0x8d6dfd9e, 0x5550dec0, + 0x6c7780b8, 0xc4804340, 0x1b4f7fc1, 0x8cbf248b, 0x65ec0ad5, 0xf696e1b2, 0xf7389f9b, 0x935c5233, 0xebbc7704, + 0x9b429faa, 0xad8e9abe, 0x2ceec178, 0xccfdb257, 0xc9126945, 0x4dcfc00b, 0x8b26e06e, 0xb13b2e7a, 0x0f1947a3, + 0xf05b6898, 0x16b1216c, 0x7f134ada, 0x450cbed9, 0xe721b9f0, 0xec744317, 0xd1b17377, 0x5a62b94f, 0xcf9c3e92, + 0x3314b6d4, 0x32e0f91d, 0x4ce78bce, 0x74d3c13f, 0x44f17583, 0xfcb25265, 0xc48c0136, 0x0e1e148c, 0x16690520, + 0x161c1289, 0x21362bf1, 0xef7a2641, 0x7a4754bc, 0xba0d9109, 0x8d5f85ad, 0x57c08e6a, 0xa6cbd9c0, 0x52fe41b0, + 0xa1944e49, 0x66cc72ff, 0x095f9d1b, 0xe75ea6a0, 0x05017888, 0xfec28876, 0x9a051ff7, 0x8e8a8f96, 0xab1ef991, + 0x1a05a147, 0x17947799, 0x0221c487, 0x14e8c0fd, 0x2b96dc0e, 0xd5b7151e, 0xf33a7fb4, 0x95ac16db, 0x903ee66a, + 0x001869bd, 0x0abfc039, 0x34b26572, 0x9af9ae6d, 0x696cc1a3, 0x0b9c5d69, 0xcb25d8b4, 0x0cbb7bc5, 0x25df0991, + 0x06de0bf9, 0xfbaf571e, 0x7a906b23, 0x66312a1e, 0xd32e7a28, 0xaf2f116b, 0x78aba6b9, 0x8ff127bd, 0x9479afa1, + 0xda6fcd1e, 0xc31c7702, 0xedc61274, 0x8f4df163, 0xeb514c1c, 0x782c559c, 0x43ea75c0, 0x09e5f482, 0x2031f7bb, + 0xf38fadbd, 0xeb4455d3, 0xc78e1835, 0xa30b2b88, 0xfb1b43fc, 0xc23808ee, 0x91ff3230, 0x0121cc52, 0xf338c31a, + 0x66a43738, 0xa71a6c8a, 0xda68bd60, 0x746f09af, 0x08939eb7, 0xef1e0271, 0x4bcbf418, 0xadd005c4, 0x96ac1282, + 0xe13032d4, 0x669c44a4, 0xabbbe9f4, 0xa92f040a, 0xf5d66ee2, 0x4eeba426, 0x7f1c0a27, 0x2616a6c8, 0x35db7883, + 0x0f256f43, 0x7e1156d5, 0xd943b715, 0xccd23a4d, 0xb0678fef, 0x87be5022, 0x73d2d74f, 0x68367ae2, 0xe329f243, + 0xa8ac3ebf, 0x2b604cd8, 0x83245959, 0x9a3f8618, 0xf6f6793c, 0x67201350, 0x34557cfd, 0xb9c6732f, 0x88c931d4, + 0x129815dd, 0x1c7d9804, 0x89dab0de, 0x101e382e, 0x4d253d7f, 0xe21dcfce, 0x930ced78, 0x7f863406, 0x94580765, + 0x4090e829, 0xfb563ee9, 0x1bb546a0, 0x1cf58151, 0xef0a8c1a, 0x2d725bdb, 0xb1493f5a, 0xdc9238f9, 0xebb7be0c, + 0x67711241, 0xcf15a056, 0x13e4e5f7, 0x6af85a6f, 0xc587be48, 0x258bdf0c, 0x6de9948c, 0xc2bb63d0, 0xcc8ba5e3, + 0x50fd8cb8, 0xed8f88aa, 0x9b0b1cbf, 0x836bb7cd, 0x9b1cd340, 0x77f1bfe9, 0xb71ddcf6, 0x63a0bf70, 0x45f137d6, + 0x9595b15a, 0x6b7ad3bc, 0xe6d9e6f7, 0x559dce01, 0x879f68c8, 0xb004acbf, 0x1e4838b5, 0xd6bf5580, 0x28ba2e2f, + 0x0dd95e51, 0xac3c6740, 0xa3c53019, 0xf294e1a1, 0xf8a06857, 0x612f3eae, 0xeff55247, 0x54c783e5, 0x1d61d48a, + 0xc3a0ef2c, 0xa8507ffe, 0x5e99837a, 0xb62aae11, 0xc9bd37c5, 0x9d5dc190, 0x0a9b33a9, 0xca104881, 0xb81df183, + 0x4fb6fae1, 0x3eece06a, 0x743fbede, 0x7437f563, 0x58245d94, 0xd7c83eab, 0x1cdeed2f, 0x2b1fb4d4, 0xb94647ea, + 0x09c5396c, 0xf5777c50, 0x8cd6f46b, 0xc757385d, 0x876eb377, 0x50a40c5d, 0x3819ea7a, 0xd7b48b15, 0xb6e47977, + 0xa286ab59, 0x7effcca6, 0xd260a4d9, 0xf07c413d, 0x6082e4ee, 0x5ffa5cd7, 0x3b332657, 0x18b0bc12, 0xd378f922, + 0xcf48dbf6, 0xa0833341, 0x469cb65a, 0x465ee304, 0x81d630bf, 0xb914b95c, 0x52d2066a, 0x6958aa90, 0xc6de936f, + 0x557d3d9a, 0xb7c62d92, 0x912b8197, 0x2149e390, 0x8c6ad3a2, 0xc13be708, 0xee6747f6, 0x8c08b040, 0xef966d61, + 0x9d09328d, 0x0a4e3245, 0x659d7f22, 0x7023c706, 0x3bca65b1, 0xb70df260, 0x7f9797cf, 0x508dc7c0, 0x6dbdddf9, + 0xf13a0182, 0x92c8a8fc, 0xa006fd0f, 0x9e4686fe, 0x89d6e07c, 0x151ec199, 0xf76b231a, 0x9b5e29b3, 0xc5bb2b03, + 0xf9b0fdbc, 0x8e4d5e79, 0x29418372, 0x36a2fa44, 0x177962d4, 0x176273cb, 0x2824b3b0, 0xf5dc745b, 0x63820c8b, + 0xdc03fe4c, 0xbb9854b3, 0xf093efe0, 0xda6a8c71, 0xbb5138c0, 0xc4ee8037, 0x40481b38, 0xfe68d259, 0x2dfbcac9, + 0xf960598c, 0x7787fb33, 0x034ae8da, 0x40585937, 0xd6466d6e, 0x5146fb71, 0x06dc11c3, 0x855fd86e, 0xd3e3b44b, + 0xac10dd70, 0xac528b44, 0xfea1e7ec, 0x7d4410be, 0x00867c33, 0x576f1963, 0x5884cfc8, 0xb97f4246, 0xdbbe51ea, + 0x32bdd88e, 0xca6ff953, 0x4b5217fa, 0xdc970a1a, 0x428ce7b5, 0xa8b80546, 0xe2d11bb3, 0x563cc404, 0x64a4d7ad, + 0x75adfdf3, 0xaede7be4, 0x64e7a5b1, 0xb47c7889, 0xf29f8ea4, 0x80dc5678, 0x176099ec, 0x21b27641, 0xadcba258, + 0xf1cc396d, 0xb8f72934, 0x5efae44f, 0x1ce7b41c, 0xff4b7367, 0xaef060d6, 0x15bf7ee2, 0x5f61a5e3, 0xc2ff6a20, + 0x16b7f403, 0xe1043836, 0xab6aa617, 0xea5772e7, 0x8c1655ee, 0x4b77560d, 0xe1e7df63, 0xb200aeb6, 0x6cee7d46, + 0xca305b58, 0x18a20ba7, 0x83693bfd, 0xaddfc58b, 0xfd2b981b, 0x78103dca, 0x68b00b86, 0x0c5a3369, 0x4e480847, + 0xc7f81edf, 0xdc7a97dc, 0xd93f4215, 0x03fe912b, 0x714a9fbd, 0xdd8d008b, 0x26f09a60, 0x62228fcc, 0x687b4519, + 0x13ef0545, 0x3d7ce727, 0x3c94c18c, 0xb9dfffde, 0x8e8b1ffa, 0xd37354d8, 0xf17d7efc, 0x4e9b0360, 0x7060846b, + 0x2dcc5cd3, 0x80baebc2, 0x45a1f491, 0x647497ca, 0x7cf37e74, 0xc7056642, 0x0f0ad219, 0xc2a81324, 0x4c002419, + 0x17c1d980, 0x35108904, 0x2c383758, 0x9a9a846d, 0xeb833d6b, 0x7e061461, 0x2f2f0f8d, 0x554510d7, 0xe046edf7, + 0x4a723dfd, 0xba9ea399, 0xc2b22139, 0x37f58359, 0x46c11292, 0xde02566f, 0x1a3f22d4, 0x9ad75c6e, 0xd5d526b4, + 0x374c4e95, 0x1e67045a, 0x8ff4ff9c, 0x868f1a84, 0x99c3bd90, 0xc61a80b1, 0xb908ba9f, 0xec2675f4, 0xf5a80821, + 0x335baefc, 0xc963a804, 0xbc2f3723, 0xc8cc9ab7, 0x84858dc5, 0x44ddcf04, 0xdf799e55, 0x65cb9517, 0xade4a5fe, + 0xd71e82f2, 0xcdd245ec, 0x688e1f0f, 0xa8f78b6e, 0x4ab3c087, 0x976c926e, 0x2ba5fd19, 0xba3cdbd1, 0xa053a030, + 0x40e065d8, 0x01ad9e9d, 0xf6b7236f, 0x2c11f3d8, 0x0dd77f9d, 0xba767bff, 0x005563c3, 0x5df3afd6, 0x97b084ba, + 0x9838271d, 0xcadb538a, 0x1ce4198c, 0x278b78fb, 0xa0af6488, 0xa5ea1122, 0xf1fec19f, 0x296651ef, 0x50a42439, + 0x4a016cd7, 0xc7767edc, 0x77837dc3, 0x0e3170fc, 0xd54ee136, 0x870dd1d4, 0x6a6ca604, 0xd9dc1e03, 0x7de23e32, + 0xb20843db, 0x2c9910b7, 0xb9c4039b, 0xc4bb8d43, 0x0241c669, 0x69c2397f, 0xe52ae11d, 0x3c55ab47, 0xf44adfde, + 0x7e612847, 0xf76fd159, 0xb37c4e4f, 0xc390adf3, 0xb102af3a, 0xdeeda0d1, 0x3651ad5c, 0xe6c83c9b, 0x37c55fc8, + 0xbe2a0c33, 0x8aa44b81, 0xa5107ee4, 0x98b6ba56, 0x646ed242, 0xe3209469, 0x47f7f1fc, 0xbfca96f2, 0xe2516a83, + 0xca0512ec, 0xd8087e89, 0xc1912d87, 0x7018d14d, 0x6711d373, 0x9e8fb5bf, 0x3082a5fd, 0x7861b5ec, 0xca59fbeb, + 0x6d5ebf94, 0x231e2d8f, 0x5f8f80ff, 0x2e48eb2b, 0xdc571f84, 0xf4466d9a, 0x0e3283a1, 0xb4c8b6c4, 0x7c2f5bb0, + 0x36888d20, 0x87b6cf2a, 0xef17d2f5, 0xc08e4576, 0xd0608282, 0x5fc08125, 0x70534bf5, 0xa24f0ae4, 0x5af568c0, + 0x94f96f9d, 0xd251e55e, 0xc5cc412e, 0x5c6cc96e, 0xade6a5a7, 0xcc9604b8, 0xf45d983d, 0xb8e65214, 0x95b67036, + 0x3bdc8dd4, 0x2035f6c7, 0x3b2b854e, 0xb7d964c9, 0xbe734727, 0xe6be5d98, 0x9d594128, 0x31cbef1c, 0x2ca19785, + 0x76e73266, 0x119dabc2, 0x064d9ffa, 0x8df6bed4, 0x6b9a9e89, 0x809b8772, 0x0a486afd, 0xd549c4b7, 0x5335ba1f, + 0xe2114586, 0x0662be07, 0x5c9ddc6d, 0x7e0aa964, 0x6e455a46, 0x19f1f49a, 0xf0a444c6, 0x79370059, 0xf2d90f2f, + 0x66fe180c, 0xbadfcf50, 0x4399e4ed, 0xb3579106, 0x6d3a3710, 0xb97a4a21, 0xcefe58d5, 0x9fedc827, 0x0ac88b42, + 0xc2b1d3c0, 0x2686644e, 0x85c79393, 0x5cb21274, 0x436b7c1b, 0x4ec11eff, 0xb39a6e12, 0xef945f7f, 0x6928634d, + 0x6ad008e8, 0xf4e9c62e, 0x43365ce5, 0x28707430, 0xa7421fb2, 0xd8f9abac, 0xea31cacc, 0xb37858bb, 0x4ddb81a5, + 0x99a0aebf, 0x84e60ab6, 0xb0030f7b, 0xdc035eec, 0x4a42519a, 0xf95cfec2, 0xdbd51dbb, 0xfb002083, 0x63677d39, + 0x61dba037, 0xf2f716e4, 0x0f42ecc3, 0xf9249deb, 0x55a19487, 0xd9953706, 0xd9643519, 0x56216aac, 0x05420805, + 0x766d9014, 0x725991a7, 0xb418c296, 0x641e32e2, 0x5c19fc24, 0xe20b22b6, 0x2ccb6d5c, 0x6f7273c1, 0x80d37c02, + 0xfbd60145, 0x9abb1936, 0xdae71516, 0x1a006c9c, 0x743e303c, 0x3498a9ca, 0x18044640, 0x632616b1, 0x9d1b791e, + 0x0d7bc0cc, 0x9ad21e6f, 0x7137d1b4, 0x303cad86, 0x6033ff5f, 0xae9c6a3b, 0x798e77c2, 0x6e8f7ada, 0x91d67ffd, + 0x218aae25, 0x42acc224, 0x208021ee, 0x67412ae1, 0x6495e1ab, 0x47cde9cc, 0x5299bec1, 0x10f5a6d2, 0x2bbcabd4, + 0x7645f66e, 0xf985d84d, 0xace4701b, 0x13f89aca, 0x350537f0, 0x7e55a104, 0xe607ca04, 0xbac99f1d, 0x0bfdabd7, + 0x9eec13d5, 0xae193a9c, 0x83f7ef5e, 0x8c4e3244, 0x76f41b2f, 0x96036689, 0xf618f886, 0x491ae0cb, 0x63117610, + 0x24092a3d, 0xfd7b5a32, 0xc9ac21bc, 0xb0f7f85e, 0xe874db18, 0x9290e072, 0xe4ad3a7f, 0x24e211ef, 0xf893e32c, + 0xb5dc141d, 0x583b0ddc, 0xcc9cd893, 0x32409f9c, 0xc75da738, 0xb3ce726e, 0x1a6e5691, 0x71f59649, 0xeb094f75, + 0x40b1391d, 0x4bbeab2b, 0xab7b174a, 0x861718fb, 0x1869f4c1, 0xf2d60ea1, 0x49a71d28, 0x8e8256d1, 0x6bb483ec, + 0xef35e9e2, 0x4aa6dd19, 0xc1506347, 0xe2b041df, 0x635f7034, 0x3ddb0cb9, 0x7733190e, 0x057e8294, 0xb6f6a1d3, + 0x699b86d4, 0xf231ec4e, 0xd83cb0bf, 0x74f39f58, 0xd83937e1, 0x7be99133, 0x9e09d799, 0x30b48568, 0x2dca7161, + 0xfcac4cee, 0x0ca679ac, 0x4033fac8, 0x79c6585d, 0x713edc39, 0x1955a47d, 0x46552347, 0xfdcc9893, 0x9cd1b604, + 0xbb4e7073, 0x27e5de44, 0xe537aa5d, 0x12355c10, 0xfa919ad9, 0xfeac7efd, 0xc0729e74, 0x2b5228de, 0x7ad9c1af, + 0xf051d659, 0xad88d6a8, 0x21661aad, 0xf08661d7, 0x606d9020, 0xcf74f4eb, 0x6b8ecaff, 0xe0310dbb, 0x60f3ac8a, + 0x050c3c51, 0x100d3a54, 0x94a6a7c3, 0xcc196243, 0xb75176da, 0x7307847e, 0x55aec3ee, 0x1c9a94be, 0x83f2b81c, + 0x406c26b3, 0xd17b4137, 0x37691686, 0x3d5e06b1, 0xeb7ef346, 0x82dd0524, 0x7b9322cf, 0x4c48a470, 0x293b6900, + 0x3e6b830a, 0x03153078, 0x88b3d4f5, 0x70bf432c, 0xbfe897ef, 0x6a6c0910, 0xa9fca897, 0x706305dd, 0xefd89017, + 0x503e62f5, 0x54dc0063, 0x5fa92006, 0x811d356c, 0x6ee9232c, 0x784ba9a5, 0x4f0c7165, 0x0306e7a5, 0x8361b8b1, + 0x3ca0b3ae, 0xd9c3cdaa, 0x72a274cf, 0x1b4eb239, 0xec08ef90, 0x246cbc64, 0x6fe495d9, 0x10f24871, 0x3f38c80d, + 0xfddfaa83, 0x7ffd18af, 0x7b3a8f6f, 0x477725d3, 0xb269dc18, 0x0f1a8a60, 0xac76ec07, 0x5aad9bf8, 0xac7a6c5f, + 0x19e87ecd, 0xc49731e0, 0x6e9c5401, 0x96567c07, 0x62628947, 0x6431b029, 0x312d2dc0, 0x1948212a, 0x7b6027ea, + 0xbf00c236, 0x049a382a, 0x96fc1366, 0x731e4719, 0x6c6df6b7, 0x76af4442, 0x7b8b240d, 0xe26df8f0, 0xc91e6819, + 0x4f8e26a2, 0x0677312d, 0x2fd3200e, 0x697235f2, 0xaa716ab7, 0x33269507, 0xb4ee0b7f, 0xe29f877a, 0xcfea0128, + 0x2f3a50ce, 0x21194758, 0x41e62013, 0x5eaa53d0, 0xdead1ccd, 0xe51ada72, 0x9cc95193, 0x199fe089, 0xaac475b4, + 0x1d4a323b, 0x1d60ce82, 0xd52728b2, 0x54b49445, 0x8016ed15, 0x626d92e7, 0xc98e2853, 0x5f26e121, 0xd6528a2b, + 0x9f14ff0a, 0xbf4872c3, 0xc8cf33f9, 0xe1a77d1f, 0x9a2e7325, 0x0ee857a2, 0x0cb04a80, 0xc8523d28, 0x237ff31f, + 0x68e06684, 0x85caabee, 0x980517a4, 0x9e83eb1a, 0x07d1b0e5, 0x12b125a9, 0x9901bd22, 0xfe983b22, 0xe71c1968, + 0x265a4383, 0x98e04336, 0x3b8c517c, 0x0fcffbc8, 0x1ba37fdc, 0xa1c03f5e, 0x9bda0354, 0x05ed6197, 0x25310635, + 0xcf60afe7, 0x5347593f, 0x90b1d317, 0x2cdf2e9f, 0x6cd14d68, 0x140de615, 0xd9bc75c4, 0x8458dac2, 0x30f19a18, + 0x281545b8, 0x135988df, 0xc71c83cf, 0x6cdb976e, 0xe5b491a3, 0xd3538782, 0x535f7b80, 0x1a771580, 0xb0839225, + 0x37de7721, 0x48cbdfd3, 0xff96ecc8, 0xf3674c20, 0xfdea382a, 0xdd5017d3, 0x211a8aaf, 0xf814f92b, 0xef8ea39b, + 0x40e5225f, 0x6d2d5238, 0x16b95a06, 0x9cc57c67, 0xecee73e3, 0x596f01d2, 0xde37ebd6, 0x75306b9d, 0xc8934d2a, + 0xf6205b10, 0x80b69445, 0xe5193219, 0x9772819e, 0x986da88e, 0x522fe0c1, 0x3d64449f, 0x4b54c160, 0xf417c258, + 0xf5cc456b, 0x1f7ea730, 0x38164c35, 0xc67081ef, 0xd3680e52, 0xa7d85d18, 0x1cfa2f7c, 0xf66b739d, 0x1aa9feac, + 0xaf00df5c, 0x5541c1f6, 0x973e0357, 0x74b19f85, 0x51ec501c, 0x1f30c5f3, 0x458ef1cf, 0x68f26386, 0xe9a2ba63, + 0x7d4629ae, 0xae05de4d, 0x37f62c1c, 0x9be22ef9, 0x82dc762c, 0x6e3c7d2d, 0x6749aae7, 0xbba121dd, 0xbc720e51, + 0x9d1a90c5, 0x5ff91625, 0xc4ef67ea, 0x528a64ef, 0x21afbf53, 0x14ac9b5d, 0xcb9749bc, 0x7a745197, 0xa0eee766, + 0xd1fceac3, 0x389fcd30, 0xc3e1e6d4, 0x4bbcb080, 0xe3b89af5, 0xd55e7ab6, 0x673145e1, 0xdb69532b, 0xbf93d1f2, + 0xc7b8568c, 0xf007bdc8, 0x338d271e, 0x5c495f69, 0x160b9a79, 0x5c2b61ac, 0xbfdb890e, 0x95552f2c, 0xab4ecb8e, + 0xa60a8c12, 0x06e961c6, 0xb2475034, 0x62cad560, 0x801ab5e1, 0x45584cb7, 0x113af72e, 0x46fb2cc6, 0xf444c31f, + 0xc1ecd6fc, 0x204ebe7e, 0xc7bc1163, 0x23910445, 0xb79a5fb7, 0x4e499307, 0x1429fe46, 0x352adad6, 0x5aabab43, + 0x81ea316f, 0x23482492, 0x5d2c7b1f, 0x4e7ce4a5, 0x693309be, 0x12931ce6, 0x516b2c9f, 0x9da2ef30, 0x26835e68, + 0xfd0894f7, 0xa6b1c074, 0x94c52856, 0x9cc3464e, 0x67e0f2c5, 0xf1a41690, 0xf845db29, 0xa82b53aa, 0x8ea34b81, + 0x29e245b9, 0xf35bf317, 0x1073f95d, 0x51488849, 0x2468a5a7, 0x5892d50a, 0x33b0fe72, 0x5baea3d4, 0x1cf07f39, + 0x04c980dd, 0xa35b5ffc, 0x1717a3f0, 0x8a27a793, 0x1d540a24, 0x3ea7e2b8, 0x24e701f0, 0x7cc35630, 0xad7df873, + 0xbde2aa24, 0xe12b1baf, 0x254eee81, 0x60fb8c3e, 0x06099123, 0xafd662d3, 0x61cf5894, 0xaa283fda, 0x2ea2079d, + 0xad57b4e1, 0xb0bc6aad, 0xee68f4a8, 0xf277e2e0, 0x76c3e2ad, 0x3f11ed8c, 0xf81209ed, 0x42526bda, 0x57524d8e, + 0xea09febb, 0x88d66f03, 0x79597bb1, 0x4d9fc7ec, 0xdc00c40d, 0xefa3b5dd, 0x9d3879d0, 0x5acbc3bc, 0x4562e3c9, + 0xfe034da0, 0x2c499d37, 0x89309abb, 0xc2e2cd82, 0x5da9c0e1, 0x4c71b7df, 0x658600a8, 0xa4fbd5c5, 0xedde6041, + 0x1bd50b02, 0x75c04a6f, 0xc02e63d6, 0xc3419b67, 0x4fdf6c2b, 0x6fc6a68c, 0x1e5714a1, 0xc30b978d, 0x13c1ff7e, + 0x3b69bc68, 0x0dc0b859, 0xabbbc1a6, 0x2c3e481c, 0xbe5da3eb, 0xbc5971dc, 0xb0d931e6, 0x2901f616, 0x8f4e4b4a, + 0xb8f2beea, 0xc9f7d01f, 0xf9007cba, 0xb812401f, 0xca2936d8, 0x724bef9d, 0x4b201b7a, 0x5342b647, 0xcf563116, + 0xde74f7bd, 0x07096002, 0xfe58a5a6, 0xc5ebb5e5, 0x26161fcf, 0xc6df9592, 0x42b072d6, 0xf82cb4cf, 0x7393224e, + 0x8ce12dcb, 0x28ac78a0, 0xfa2ebf08, 0x1d2b1a55, 0xbb978a34, 0x76e1d5f1, 0x786d2ab4, 0xbdccdbc6, 0x2813db34, + 0xec38a334, 0x38850be8, 0xafee4a33, 0x74e6b4a2, 0xc9ffb99e, 0x42acae9e, 0x807fd379, 0xddd88979, 0x97c9bab5, + 0x3314f32e, 0xa35e2573, 0xcf951bfb, 0xfecc70de, 0x2c393ceb, 0xf19c05d8, 0x7741f468, 0xbdf1e8b4, 0x63effc80, + 0x66a8cd85, 0xac96c54d, 0x3e77b140, 0x49352c87, 0x822d4774, 0x8872f2be, 0x8ca96d1f, 0x5576bb2b, 0xd8c33ecd, + 0x7a6a3a7a, 0x75e1e086, 0xc23f999d, 0xaa2f8a31, 0x819d0869, 0xcad06158, 0xb2d69dc9, 0xef222ff4, 0xa2b7eece, + 0x0e8c7c28, 0x0f4f9ecc, 0xeb650f91, 0xb1cbc5cd, 0x293519e6, 0x99c12b27, 0xd4888849, 0x5f60be68, 0x9c3d92a6, + 0x87488917, 0xc93ee20a, 0xa0950f5a, 0x64d79963, 0xaa489605, 0x9e076f6d, 0x59e7455e, 0xb7d6f0e6, 0xe1fb9798, + 0x6ceda809, 0x50ba435b, 0x0104cd73, 0xaa92f5c9, 0xbff5d195, 0xb94421ab, 0x9d10cf0b, 0x0593e8c1, 0xa3722d98, + 0x8a6814d8, 0x17e3bf8d, 0x58b39ad2, 0xd07e753a, 0x6680e9d3, 0xa687940a, 0x719cbd3c, 0x6a62d6ad, 0x6ef2f735, + 0xd5cbf5d0, 0x02916463, 0x00a0e4b8, 0xd585b986, 0xd8fc08c5, 0xf7c77c60, 0xc4d31d22, 0xd89a0463, 0x4f49c4b5, + 0x6597e5b8, 0x50334aa3, 0xcead2ff0, 0xd284d88e, 0xd7b0b3e8, 0x343c46c7, 0xd5b62868, 0xb88eb8c2, 0x7a2147fd, + 0xd4fd92e5, 0xbd6881b3, 0xde1cc229, 0x41cf34a9, 0xe5e581a6, 0x78c96173, 0x88ccda07, 0x76bf143c, 0x390322e6, + 0x8e53c370, 0x3335db26, 0xadcf6a6f, 0xc0e94352, 0x0960a520, 0x743d94b9, 0xb4b8a743, 0x0fd1e096, 0x9ee32018, + 0xbc9c6141, 0xf68c9abe, 0xce380b78, 0x6f121044, 0xef423433, 0xa971a5ab, 0x3f73eda0, 0x8d981e3b, 0xc4b075aa, + 0xa1ad01ea, 0x1bbec477, 0xf75d75bb, 0x7c3d9ba6, 0x20e38641, 0x21539154, 0xe69ae3d0, 0x558ea6fc, 0x4d5e4b43, + 0x1d2e3c1d, 0x1609be29, 0x7237a216, 0xbb47c401, 0x84bec430, 0xaa48c833, 0xe5791c93, 0xa7e06c68, 0xae9a2083, + 0x293112b6, 0xd9765fff, 0x8ce80234, 0x31361857, 0xbc632fc8, 0x08ff7a42, 0x80f4b6be, 0xadd7172d, 0xe1d5e6d0, + 0xf95c76a4, 0x0fbb9a95, 0x1dd746ef, 0xf58af8f4, 0x4d5e8c4b, 0xd6ccef76, 0xe15e1e66, 0x454818ea, 0x01933bcb, + 0x55ecafb8, 0x80ae0d47, 0x30e4d4ec, 0xac72c4e1, 0x75b5825f, 0xe65119a4, 0x0fbf7c8a, 0xe1630f6d, 0x5ae3aba1, + 0xff085274, 0xc59ac17b, 0x654b2888, 0xd44e298b, 0xdf38ffe4, 0x54966503, 0xc99ba926, 0xd52a2e2e, 0xbbf70c9d, + 0x92e8a590, 0xd2c8902e, 0xf37dd77c, 0x9f816c2c, 0x3a669720, 0xa0f94811, 0x52c44ac7, 0xd4d48de2, 0x4d39309b, + 0xe0c57979, 0xefb3b97b, 0xbbe523c6, 0x232c3c3b, 0x9a3d14a0, 0x5a5d2940, 0x5e530b28, 0x7be570c9, 0x4242b38f, + 0xa097e8c3, 0x0c6a3b66, 0x621fff8d, 0x9908be78, 0x20c7c41b, 0x5b6678ef, 0x0b629cd0, 0xce5fa6e3, 0xf311f352, + 0xc2d2474f, 0x768b4bd3, 0xd10664a1, 0x3cb1a8b9, 0x3e078a90, 0x041582cb, 0x643eca0a, 0x7ff05283, 0xe6cae8ce, + 0x20101a4d, 0x5af055d8, 0x01d585bb, 0xe798b9c5, 0x9373ec5d, 0x9ebe5961, 0x98898694, 0x13c62017, 0x249e80cc, + 0xeedf605d, 0xb324f5dd, 0x66c79897, 0x4e66dbb9, 0x307ee954, 0x21c6b9d3, 0xcf8f71da, 0xc083bd89, 0x25fbca56, + 0x952a7e55, 0xeaeae774, 0xdfbbe538, 0x03eff7fd, 0xa50ba586, 0x4e3639fe, 0xfb2a6f73, 0x21a56842, 0x0fb45f55, + 0x23cd4317, 0x7e64f4d8, 0xa2c91504, 0x809df291, 0xc2290e24, 0xe075d2e0, 0x3cde84a6, 0x19945db4, 0xddffe5c4, + 0x84d46589, 0x56f2ba9a, 0x80eeb802, 0xc76da1cf, 0x89994cb9, 0x02aa3faa, 0xf76ec603, 0xd56f74a4, 0x9cbfb2c4, + 0xf4d7713b, 0xc336abff, 0x27da7a59, 0x126d7dca, 0xdef5981c, 0xd7c299b9, 0x3c508d3e, 0x4fa4e738, 0xd3b3820e, + 0x3d9a1c9e, 0xde499132, 0xbfba597c, 0x8b49ae03, 0x5b5110ee, 0x33eb0da8, 0x9c37d4f7, 0x52f56d37, 0x403aba4e, + 0x56ffe07d, 0x4ef8c714, 0x7f143dce, 0x3a2da040, 0xb8965390, 0x8cddf9c3, 0x3c8e92ab, 0x3e4c4261, 0x023ee767, + 0xebb8758e, 0xb7fbd382, 0x02dbcb95, 0x120e74d1, 0x23240ac0, 0xdb68a2b4, 0xfb92c473, 0x4d6b843e, 0xcff71007, + 0xf36de5dc, 0x99d1c016, 0xdda771f0, 0xc2298c0b, 0xd112c8da, 0x1ae794a7, 0xc35f1998, 0xe6b7d1fb, 0xa7d0bcfe, + 0x403a12f0, 0x6a4b74ec, 0xdc1d0e2c, 0xbd7c98e2, 0xd777162c, 0x54240fbd, 0x211ceb5c, 0x160d7afc, 0x10eca63c, + 0xb6134080, 0x516ae1ba, 0x963ce944, 0xb89d4c73, 0xf3739fe4, 0xd471f0db, 0xe8f4d82e, 0x981a392d, 0x24e49689, + 0x488816dc, 0x01edda6b, 0x585c9e52, 0x9fa8e68f, 0xded57e0f, 0x0f7e73d9, 0x7c1d4f6a, 0x461e99d3, 0xb83abe3f, + 0x47582112, 0xb3bf3cac, 0xddd57106, 0xba0bf85a, 0xb11ec7cf, 0xe420d0df, 0xc038acee, 0xb7560ed1, 0xb15a408c, + 0x141d8905, 0x304b63d8, 0xe76381b3, 0x28febf77, 0x5ff4eecc, 0xb03249cd, 0x79aef537, 0x8fa9cb09, 0xedb45164, + 0xdddd2614, 0x50f27c34, 0xf8e95f1c, 0xac2e1940, 0x171b5942, 0x3bbdcfff, 0xdcf1c8b7, 0xdcd422a3, 0xc587be8e, + 0xcda5c72c, 0xbcd1685e, 0x216fb40c, 0x1c8b32a3, 0x14197937, 0x8299447d, 0xfb75c99f, 0x6d26209b, 0xcf30cc0d, + 0x0a55c4c7, 0x3b99486e, 0x2326403c, 0x270383cf, 0xef3c2eec, 0x176793dd, 0xdced6006, 0x12a36780, 0x7de9e6f7, + 0x6d88d0a6, 0x2d4959e9, 0x9db85f5b, 0x0d9629f7, 0xed3623e1, 0xd6030d51, 0x7f624147, 0xeedf52c7, 0x8b8ba217, + 0xab7bf7c2, 0x873e107c, 0x75bd4dc0, 0xab105dcf, 0x3f0245be, 0x79c3ae4f, 0x11a06c20, 0x6fd42b03, 0x6e772a54, + 0xa344ec12, 0x53f622f2, 0x5ba56519, 0xd4db25b2, 0x8fa592b5, 0x64b9eb64, 0x6b961e21, 0x6c5bde6b, 0x4d73f80c, + 0xa135dd8b, 0x61c3e9a5, 0xba390fcf, 0xa269b0e2, 0x8d5a5ced, 0x29f5f387, 0x95c262dc, 0xcbd06721, 0x5f71abd0, + 0x2d1e5552, 0x5961c3d8, 0x632b415c, 0xb5e790da, 0x4ea47568, 0xc40c8252, 0x57e5a783, 0x556a3326, 0x82ddad34, + 0x6daf58dc, 0x99e079e6, 0x54d78fd5, 0x71457b75, 0x14cbfbfd, 0x8f44ff49, 0x169429eb, 0x3ade359f, 0x3ae82025, + 0xa310110b, 0xc20346a8, 0x78de39de, 0x102497e1, 0x93a24e57, 0xa6b49257, 0xd00f67f6, 0xf63d0d4b, 0x923574e7, + 0x9de980aa, 0x55d92405, 0x3006c2c7, 0xcdd39baa, 0xfe4dabf0, 0x12ec1797, 0x8e736598, 0x3a4e5ed4, 0x9f371dba, + 0x49100f25, 0x9abe65e2, 0x1466b8fb, 0x420ed163, 0x443ea28b, 0x51cf535f, 0x48beeb54, 0x8741b148, 0xfab3b029, + 0xbbe99167, 0x042bd8b7, 0x03864c21, 0xa9955533, 0x2cd2ae3a, 0xc318a591, 0x1580d1ce, 0xaa67c22f, 0x40ddeba1, + 0x8aed8b54, 0xeca036e1, 0xec450f7d, 0x000070c1, 0x4eb46aae, 0x4bc09f23, 0x24434c51, 0x02d36490, 0x7b684935, + 0x214b4056, 0xf54698cf, 0x8bb02a74, 0x4a15abca, 0xa53af007, 0x0c04c4f9, 0x81707f9b, 0xf390a9e3, 0xc76494e4, + 0xb9a02bd5, 0x53884d1d, 0xfaaa9cb0, 0x1181502a, 0x08472999, 0x9ddef3eb, 0x72f3a8ab, 0xa20d4aa5, 0x26b56c50, + 0x39001226, 0xc31d0f25, 0xf5b0790c, 0x0bc5f42f, 0x99461807, 0xdd519080, 0x8e2f7472, 0xfc25a926, 0x79cb29c4, + 0x3d4bb0cf, 0x571c6369, 0xa3053fa6, 0xaf08976b, 0x9f70039b, 0xd543b417, 0xf00a6ee2, 0x9e4cd167, 0x2f122f56, + 0x9ce6d0d3, 0x2ea7f4a6, 0xb75bcebd, 0xc6cf93cf, 0x7ed636bb, 0xb8301160, 0x232feb74, 0xae380a77, 0xcf715a20, + 0xc0e96b5b, 0x6c923974, 0x314ffe46, 0xc0e265c7, 0x4a52fc8d, 0x098057a8, 0x9ad07a33, 0x01689306, 0xfd84e07e, + 0xb3b51ecd, 0x71b69d23, 0xb617138b, 0x78335d15, 0xda978d7d, 0x2549999f, 0xb45667ae, 0xd2f5314d, 0x9713abbf, + 0x391a5d07, 0x89f4569a, 0x1562485a, 0xe60cddc8, 0x68f09599, 0x78c01ad9, 0xb3f57850, 0xfe2250b8, 0xd924ff8e, + 0xafe7e29b, 0x84432655, 0xc3c34631, 0xe7e9ee58, 0x3b9bfbf1, 0xc567d975, 0xec4c024a, 0x8ac05d06, 0xb90bc4aa, + 0xeee6ff89, 0x51e538b1, 0x6116a723, 0x020ab75d, 0xecfa51de, 0x95565352, 0xb9df4c5c, 0x3c0d087d, 0x71124f88, + 0x80344e13, 0x7a938242, 0xa7b388a9, 0x57bd1827, 0x20f4d37b, 0x7fc2bbcb, 0xa0f0ca59, 0x125cc5a9, 0xe3db48a1, + 0xa44e426d, 0x553b2b61, 0x1102156d, 0xf4249fae, 0xc26d5220, 0x73e11cbf, 0x2e46bd28, 0x5f2b761c, 0x51a05aee, + 0xb7cc95a7, 0x06c136d5, 0xa91770b0, 0xc2f53f1f, 0x1fdc6aaa, 0x646bb18c, 0xf925b168, 0x87c9124e, 0x1bd5e96e, + 0xa0555629, 0xdeff2060, 0x847e93cb, 0xf5dce455, 0x6ffb16d0, 0xa7ca21ce, 0xc84c2ba0, 0x8762d486, 0xef4b6509, + 0x406b5c33, 0x3c4a1ad9, 0x82713574, 0x73642d5c, 0x79205950, 0xc487fdcd, 0xc9351229, 0x844ad1ac, 0x2d48cc6c, + 0x40227924, 0x70e003f8, 0xf0d149af, 0xab8a15b7, 0x5dbb5279, 0xb0182e97, 0x8f5f647e, 0x0e9d35e0, 0x52f20927, + 0xa60f4748, 0x8f6521ec, 0x836dd047, 0x899df159, 0x87e6e34b, 0x1ced734c, 0xa2a64df4, 0xdc194b15, 0x68af4514, + 0xe984f8bb, 0xdf747684, 0x42721728, 0x783a8c05, 0x67cfc79a, 0xbb45400a, 0xbed4fa8f, 0x35c19683, 0xccb17745, + 0x8f4225db, 0x92d12e9b, 0xa620a9b5, 0x452896e3, 0xf6733eef, 0x4b98e977, 0xfcf260c9, 0x70fd841b, 0x9cb2c465, + 0xdc9abb48, 0xbca4ff3d, 0x7bb7d0a5, 0x315f9c32, 0xbf48091c, 0xd96d1eb9, 0xee0a5163, 0xfb4d869f, 0x472fc51b, + 0xbe0c1712, 0xe497847a, 0x42ce26c9, 0x41835804, 0x82a89775, 0x18ca5daa, 0x899da044, 0x15d48635, 0xc21e6aa5, + 0xe4a930fa, 0x8e4af88f, 0x28872c86, 0xc7826517, 0x1e048337, 0xec7128c4, 0x7f92dc7f, 0x6b499fed, 0xcb07df37, + 0x556dcea6, 0x90bb842b, 0xdb4acf38, 0x03e26049, 0x38bb9ed0, 0xcedc5afa, 0xf15204f7, 0xf9631b16, 0x1e9059af, + 0x9ed963cb, 0x4b76ac6c, 0x175b89b0, 0x7bc9a96b, 0x35c44627, 0x5ebb6135, 0x5079d871, 0x41f8cf98, 0x55c61a86, + 0xfe7766f4, 0xd9758f18, 0x5803b618, 0x33fe0836, 0x3d8c37c6, 0x4830f859, 0xb77a5526, 0x5da321ba, 0x18bf4ec4, + 0x0a490e8f, 0xbf58b54d, 0x5b9feced, 0x4d4191fe, 0xab7fefa0, 0x4955b0d5, 0x99367048, 0x6d747a4a, 0x83cd6adf, + 0x29b200f9, 0xa02be4c1, 0x7ac15ca4, 0xcf86291c, 0x4ff6d63f, 0x87022f87, 0x147b3ea0, 0x18474bc6, 0x2a40f61f, + 0xe6a9bf92, 0x427548ad, 0xa52414e8, 0xf9099e8f, 0xf0596388, 0xb417dc1e, 0x70fe3cc3, 0x680a283c, 0x158aa073, + 0x2f81580a, 0xb5b23d67, 0x9301e21b, 0x32178e94, 0xe5148878, 0xfa426f28, 0xa0287242, 0x2f4073f1, 0x553f48af, + 0x282b6c84, 0x1f787d83, 0xc535fdb2, 0xcbc9dcd0, 0x91a1e8a6, 0x2d404f70, 0xe2f6484d, 0x2eb3c955, 0x3f9bae36, + 0x2e528159, 0x5600f038, 0xea5680e3, 0x90744f94, 0x2def1581, 0x0fd411ac, 0x5434676e, 0xcfefceb6, 0x7a92f56d, + 0x14a5d1a8, 0x9e7d75bc, 0xbaeb61fd, 0xadef03fd, 0x6cdcb2ae, 0xc730fd91, 0xfd889634, 0xdc40b892, 0xd4a8492c, + 0xcc3e6526, 0xdee6f1a9, 0x0021db7b, 0x188fe5fd, 0x96dac78b, 0xff276c2b, 0xabd65f17, 0x6e33cf80, 0x5733f8a5, + 0xacdf8bbb, 0x7c96aea2, 0x324a2c7e, 0x5217346b, 0xcfe42921, 0x51d02713, 0xe07d805c, 0x5531b829, 0xf2613f7c, + 0x42691322, 0xf476e386, 0x928a558d, 0xf72f671c, 0x3c08cd6e, 0xa9f4e758, 0x76985db4, 0x1e5f10f6, 0x1c026e6e, + 0x47937020, 0x4fab094d, 0xd041ef20, 0x8e469770, 0xf43da07f, 0xf2e9dc4b, 0xb561167c, 0xe75179ee, 0x6b578e66, + 0xa612c0dd, 0x3e736aca, 0x6e4c1695, 0x6938a2af, 0x85902b96, 0xc49f2572, 0x316bc877, 0xc0ed9d99, 0x88dd81ec, + 0x8e73c859, 0x06c97244, 0x0e15fdc2, 0x1fd89cfb, 0x3f2aa919, 0xf9832823, 0x5a4f26f1, 0xb6081164, 0xc1af7f02, + 0xb80ad52c, 0x4c504250, 0x5dc7d2ab, 0x4c9a1701, 0x90fd91a1, 0x157d95ba, 0xfb0fb63c, 0xdb256a71, 0x94708c89, + 0x4ab34472, 0xaf9fe84b, 0xceaa92e2, 0x4539b705, 0xab9608b3, 0x7db22f0a, 0x622072b8, 0x769b2362, 0x95ea6907, + 0x672c17a3, 0x9a55bfa9, 0xede7abab, 0x7795d6f6, 0x551d84e3, 0xea4cc80e, 0xd4db00d9, 0x48da2feb, 0xdc9ce08e, + 0x50826d6f, 0x1cb89ade, 0xd4116a0c, 0x6d9982bd, 0x4e9eaff9, 0x06bef494, 0xa746ee8c, 0x47034409, 0xd19da75c, + 0xe7dec380, 0xad7fc827, 0xcd26c2fb, 0x6765254b, 0xa281df0e, 0xd0fd2ee1, 0xc552c3c3, 0x8e59c8fa, 0xa82fec09, + 0x045b8260, 0xe44e6315, 0xd4c5ac47, 0xdaba1a73, 0xad7927b2, 0x0a0f9565, 0xd75701eb, 0x9f341869, 0x36325ba2, + 0x27643f19, 0x799122b3, 0x0c0acd46, 0x3421ca16, 0x693ea835, 0x76f792cf, 0x55c7a4e2, 0x623c643b, 0xf0a69232, + 0xbb061660, 0xf9795ac1, 0xc33e081b, 0xfbb7b8a2, 0x1fe4283e, 0x2688b014, 0xd1a18a41, 0x473391fd, 0x574a76e7, + 0x35db8643, 0xfd277f76, 0xc9286fa0, 0xc5d02f8c, 0x23cd6569, 0xb93ce701, 0xbfb5850d, 0xba450707, 0x633cade9, + 0x2fc062bb, 0x6a314dd3, 0x3e45897a, 0xd905d5f1, 0xaad7f5f5, 0xd31370ff, 0x3ca6d177, 0x1c96746b, 0x7a8aa61e, + 0x2d2ba2c6, 0x28abda9d, 0x87071290, 0x72b075ad, 0x5a799a3b, 0xffd93b7f, 0x0fa447bf, 0xc5c73cce, 0x437d06dc, + 0x03c9465d, 0x6bfc40b8, 0x57c330ab, 0x5dac7956, 0xe7dbc6ad, 0x40b25d62, 0xf57baa7a, 0x112d8d2e, 0x1a890a63, + 0x06f1941d, 0xa542d6d3, 0x4f28ad1c, 0x4a67a585, 0x75ca55ea, 0x55978437, 0xf13a1c85, 0xa0452223, 0x90cc74bf, + 0x1f83d2af, 0x1f2fc5fd, 0xb313e283, 0xe5df7d2c, 0xad94fb1e, 0x00b72dd8, 0x589eab56, 0x9810a4b5, 0x45b4daa8, + 0xc0e9937a, 0x14b76854, 0xb605840c, 0x74ecae3c, 0xc448cfec, 0x0a9a8c34, 0x01fcb78e, 0x9e9b24a9, 0x816b3cf8, + 0x726b32c4, 0xbb186ca7, 0xe1c11b5f, 0xd7321e37, 0x5a5ea2dc, 0x60fba600, 0xc6700fe7, 0xbde667d2, 0xadb86ae7, + 0xeea1e080, 0x272d4847, 0xcc64af8a, 0xcc05a105, 0x6ad55bba, 0xc2f6d1de, 0x9d6b9e99, 0x05cb0f58, 0x290707c8, + 0xaef31611, 0x3ab8c15f, 0xdd96cbc2, 0xcff0569b, 0x182f7941, 0xc82b7055, 0xcf91bea6, 0x975bb166, 0x19d9ce1a, + 0xff2c309c, 0x2bb11ea3, 0x966cac47, 0x071e6901, 0x56aa8dd1, 0xd0164639, 0x989f3fc1, 0x3175cb0b, 0x206fe322, + 0xbb07d8b9, 0x3738a7cf, 0xe7b20143, 0xc2cf04ad, 0x31ed2fa0, 0x45688314, 0x00e9f7c5, 0xb999b81d, 0x905dd1ce, + 0xf3d7b96d, 0x8ba84cec, 0x52b065cd, 0x328f0910, 0x4bbcc87b, 0x492c1321, 0xb0ad3c07, 0x30aa6a9e, 0x33676393, + 0xac2b7115, 0xa59ed4c8, 0x91a5e2eb, 0x88599d53, 0xe59609c8, 0x7b7625d8, 0x5447c256, 0x94007d27, 0x28e3a70f, + 0x1d67824e, 0x8f8b5f1f, 0x75abc78f, 0x9eddcd15, 0x13f97f8a, 0xa0eee928, 0xba34e95d, 0xc9c7055a, 0xeb1ceb5d, + 0xd2fb696b, 0x8fa6f506, 0x2e051b76, 0x6158a191, 0xe4a64772, 0xd61b1746, 0x9a991d43, 0xf97d07e0, 0xb11cbab6, + 0xa7645a3c, 0xfe3c88a6, 0xc883b4ff, 0x77894e46, 0xb643ba25, 0x25b2d5a3, 0x6db82d7c, 0x725ecc7b, 0x42234c4e, + 0xd9dd762d, 0x657a9424, 0xc150a77c, 0x7c9e4625, 0x7c47c58c, 0xd3769545, 0x9bfdb772, 0x15a6c40a, 0x23bdec44, + 0x3de7d60a, 0x53faa735, 0xdccb78e8, 0x65f66ede, 0xb8224c58, 0x748b9293, 0xae504ca7, 0x3fd49a30, 0x213e16b4, + 0x70735f3e, 0x539d8a9d, 0x77c08a51, 0x164b9965, 0xaedd4b4b, 0xbf913b87, 0xb4663958, 0x40013ec2, 0x15cb0438, + 0xb8f0e43f, 0x8a3a0a9d, 0x04d17740, 0x406db4e7, 0x6ecba9ec, 0xea821c51, 0x4a8d48f1, 0xf125794c, 0xb75a8133, + 0xc24b654a, 0x2c2be658, 0xc716c606, 0xb09bba05, 0x050f9542, 0x4c15b40e, 0xafe9e8e0, 0xbd8bd3cb, 0x9e0351a2, + 0xb60c2e63, 0x92fd944c, 0x25f36a1e, 0x7d6ecde0, 0x130f9449, 0xefd16864, 0xfba66459, 0x118eb116, 0xd3185e5c, + 0x62ae2b5f, 0x0a41217a, 0x7051cb74, 0xa95d5825, 0xced1a416, 0x526281d8, 0x775a5270, 0x0e1f5a92, 0x890d75be, + 0x3f3683d9, 0xfe91a12c, 0x59140ac8, 0x0403c6b9, 0x0964d315, 0x5d1dcb10, 0x2d9139a9, 0xaf48380a, 0x873cc8a8, + 0xed76565c, 0x5e3eb7da, 0x18769802, 0xf7889b36, 0x121ae32e, 0xa67dd00d, 0x8ea3c28f, 0xbf1d2d85, 0xc7f715a4, + 0x2c46bde2, 0xf439d2da, 0xc99358db, 0x20914bb1, 0xac6692f2, 0x661cae9f, 0x0b1b07c5, 0xcdb4dcaa, 0xf959558d, + 0xdfd14862, 0xc0ca5a73, 0x469128f5, 0x33b64268, 0x46d4c74e, 0x3ab59aca, 0x71d23ac1, 0x2f385d43, 0x1dd735fd, + 0x44dc241a, 0x226cbca6, 0x4c2c4405, 0xe3f77f1f, 0xbaea3293, 0xb500a973, 0x3cd3cb9b, 0xcdcc704b, 0x8f3300a9, + 0x13b4e44c, 0x356447ff, 0x4182e96a, 0x70c249d8, 0x0a8cd659, 0x95e40313, 0x7449f696, 0x6afdf602, 0x0c17f889, + 0x3d487d3b, 0x551154db, 0x35815e51, 0x2e3c933d, 0x89415669, 0xc846538d, 0xae730c81, 0xeaa552bd, 0x9829d8a2, + 0xce4e758e, 0xcd0c32fb, 0x15606c5a, 0xa714a79a, 0x8d94c0fd, 0x7d6bef15, 0xdd83881f, 0xc6bd945b, 0xa578598e, + 0x10b1766a, 0xf3055b21, 0x5d617b79, 0x1547b876, 0xc37feca4, 0x28db1cbc, 0x83f7bc6e, 0x263b48ec, 0x4a448928, + 0x08e9220d, 0x6e2ca131, 0x421b0a4b, 0x52330b4a, 0x87fd8de2, 0x63a65ddc, 0x5858cc0e, 0xc4d3fbc2, 0x5372dda3, + 0x6a8ec384, 0x481c3711, 0xb280ce43, 0xb3b00daf, 0xd8c45b48, 0x9e109b97, 0xaa8f454c, 0xa40d6e84, 0xa6930b00, + 0x8dcdd906, 0x0662f2ac, 0x2d0ce609, 0x1d9a84bd, 0xc5c2ebe6, 0x9608bcd3, 0xf50d6888, 0xe82f3066, 0x2a42b6e3, + 0xfe84d238, 0xa1f42a44, 0xf33a4694, 0x8a115c1a, 0xeb008ac8, 0x6a7b6908, 0x6999e148, 0x4b7e0a1c, 0x12688eff, + 0x2dd7602d, 0x40c2d956, 0x32723544, 0x777b9da9, 0x742ad440, 0xa8d8e890, 0x919f2624, 0x2fd9f306, 0x2558f360, + 0x6fb8a8fa, 0x824f6105, 0xee6208b4, 0xbba88c66, 0x861690a0, 0xb85fd428, 0x6bb77a21, 0x7093db47, 0x694fa6d0, + 0xc92ed3af, 0xb0d872ef, 0x74f45af4, 0x7b6deddf, 0xa596509a, 0x392f0bbc, 0x2b98a970, 0x7e86d7d8, 0x43388cf0, + 0x905cce1a, 0x90662125, 0x5a679d66, 0x7b181181, 0x2c6141a6, 0x6f6e2d9f, 0x5b45ae2b, 0x01eb6a6b, 0xbc19add7, + 0xc388b952, 0x6428ae50, 0xbfdd4d57, 0xfded1cff, 0x236d9b68, 0xb7d506b8, 0x99c89439, 0xa96bd57f, 0xac3cb30e, + 0x769ce7cb, 0xa9ae78ed, 0xffa7744e, 0xf4c33144, 0x8e5e1b7a, 0x61962de7, 0x03a3cf55, 0xaff2558a, 0xa6f6f485, + 0xad33d19f, 0x2c7b02a7, 0x4ae05fbc, 0x04d32051, 0xd4779b9d, 0x7300c0fb, 0x3dfa68a4, 0x7c118f74, 0xf30c14b0, + 0x408ffed8, 0xe70f0202, 0xe2eeedf7, 0xe2f1d2f3, 0x198227b4, 0x39b7be76, 0xfea8f8b2, 0x79d4ddcb, 0x5044a0cb, + 0x981d9f59, 0x6bc0f227, 0x527f3628, 0xae8b1f81, 0xaa82832b, 0xbdb8a24c, 0x55981cda, 0x38948e10, 0x5809cd8d, + 0x5fc75453, 0x704d7ff4, 0x55694450, 0xa8bd38b1, 0xf18d3061, 0xcd529eb7, 0x93d0a501, 0x756559c5, 0x7f66bce1, + 0xf5034a3c, 0xe6fdcb64, 0x77ff116e, 0x770fa451, 0x8667c68c, 0x31719909, 0xe445c9ae, 0x80d758e0, 0x40bb1aec, + 0x748893df, 0x4d85c47f, 0xba15c473, 0x8b7db732, 0xeb7bdce3, 0x35da12d9, 0xc09ddafb, 0xe75dd5f4, 0x90b19727, + 0xc5b2a6bc, 0x631930ca, 0x8184f998, 0xc8d62a56, 0xa7c29815, 0xfdf7a02b, 0x1f88a099, 0xfc8224d7, 0xc40231c5, + 0x99d6420c, 0x7c631967, 0xb50ecf34, 0xbc4791d2, 0xa9b60020, 0x27ddef45, 0xd05974eb, 0x4483c62d, 0x20ae304d, + 0xc4ac3457, 0x61087a2b, 0xde3685b6, 0xfde1aaf3, 0x099d3c90, 0x81168820, 0x446925d0, 0x0d35e8bf, 0xc5232486, + 0xe153ecfe, 0x2fa03a24, 0x8a3e8da2, 0x9d9b3940, 0xe88dbb90, 0x791db5e9, 0x9f09f640, 0xfe015e37, 0x8a3ab22f, + 0x56e3d8da, 0xca9cc8d4, 0xf38dda4a, 0x2831ede6, 0xc45d3daf, 0xec86a284, 0xfce0a965, 0x3f739c76, 0x5d591cef, + 0xe01014c9, 0x4608e039, 0x4241a3ca, 0x154d02f4, 0x7d53fda0, 0x58287311, 0x4da0d3f0, 0x0a6d0094, 0x90720eef, + 0xfd07b50d, 0x02b90db1, 0xa15b240f, 0x7b89881d, 0x422de496, 0xb136022e, 0x57cf3d57, 0xed0e5a87, 0xe4d569e8, + 0xc77a50ec, 0xec4baa43, 0x60049991, 0x8c7a0719, 0x8927e681, 0xe953228b, 0xa0d85341, 0x721556dc, 0x19a9c6bc, + 0x84948a87, 0xad9c3c42, 0xe1785e45, 0xa846f911, 0xddd883e2, 0xdd7a45a9, 0x1c6b3203, 0xfc377b14, 0xd5c15ebf, + 0xccbc27ac, 0xb8336f17, 0x70fe2ea3, 0x4e3d6f47, 0x5918ae81, 0xcc6cf09f, 0x80ddcf25, 0xdf983e9f, 0x9d38f394, + 0x9d068ebc, 0x51aa0a68, 0xcfc522bb, 0x500017cc, 0x9eaeceb1, 0x18ecc5c1, 0xa8dab353, 0xfaf809e2, 0xb5174218, + 0x171e79d4, 0x17d31e71, 0x17ac945c, 0x2a10efb4, 0x614a9562, 0x045d72d2, 0x891f1240, 0x4514896e, 0x6dbeb91b, + 0x9e9637f6, 0x7031c5d2, 0x5c05afb8, 0xf0b24a76, 0xc2699666, 0x1b81d5ff, 0x157f0e74, 0xe10f94b0, 0x5493691d, + 0x038e8c7e, 0xd64f1f4a, 0x0064a7dd, 0x420c2c8d, 0x05ab0f3e, 0x0377cd1b, 0x209c2518, 0x586148d0, 0x57427343, + 0x50060b72, 0x329a1d60, 0x092bd766, 0xa71bbca6, 0x7d501381, 0x1893e4b1, 0x5b296927, 0x3087a79c, 0x6f9df3b8, + 0xafab67f6, 0x0d8acd1e, 0x31e9a90c, 0xbbf78481, 0xe06f222f, 0x7306fe48, 0xcc579d90, 0x364a9471, 0xc07a7a6f, + 0x85363237, 0xe7b26ea5, 0x8a92222e, 0x31e92e7d, 0x7772a6a1, 0xdf8440c1, 0x08187bef, 0x725e4a31, 0x807184da, + 0x37ae971b, 0xa65c7586, 0x384939fb, 0x69789d23, 0xf6de0a67, 0x8c0e8a9f, 0xe8986d03, 0x6320fb25, 0xfec54746, + 0x22d72f56, 0xc7416db6, 0xa16a97c7, 0xfb845267, 0x5538fb70, 0xa5138644, 0xcff5fcca, 0x92cfd7ed, 0x6089c739, + 0x63ee08c7, 0x0664cf13, 0x8337e488, 0x42ce4e41, 0x2c139b5a, 0x6077f1d1, 0x8ac2cc75, 0xeef71370, 0xfac80c66, + 0x533043f9, 0x38c09d9d, 0x4397f111, 0x3b546362, 0x0bd8be09, 0xccb469fd, 0x9dddf133, 0xfed976b1, 0x5ae1382a, + 0xb352ad00, 0x1dad2efc, 0x89cc51b7, 0x3e8de42f, 0x6629b65e, 0x06fc7463, 0x0b26b0ba, 0xb77d1857, 0x348e7df5, + 0xb205d791, 0xbd90c1ae, 0xe97b7db9, 0x2e6773f4, 0x138aebcf, 0xb815d0a1, 0x0a321aab, 0x493e466e, 0xa89139f0, + 0xa2da5042, 0xfd2f8d2c, 0x30b6966f, 0x94f7d11d, 0xc0ab087d, 0x9cd50f9b, 0x3fa9af03, 0xcf8f7414, 0x98fecd93, + 0xff513b05, 0xc394f59c, 0xd52a743e, 0x97f53ff8, 0xa9640126, 0x74177796, 0x9f8e979a, 0xb54edb57, 0xc2512f41, + 0xa403c8c6, 0x59b307b1, 0x3bb53d03, 0x580a9eb3, 0xeae60df8, 0xfedb4706, 0x2a7372d1, 0xed57f281, 0x9996b142, + 0x109ea474, 0x58b27a15, 0x2018bde3, 0xf0babcac, 0x0480e007, 0x1cbbdd3f, 0x33b789df, 0x3ca01b91, 0xe1dfb355, + 0x16596d5b, 0x8d0f02d3, 0x0684fd4b, 0x8b2fa8a0, 0x13ff40aa, 0xbc15606a, 0x196ee284, 0xda4edd54, 0x39b5b292, + 0x1c6dee89, 0xdeb82fcd, 0x908f9266, 0x5d1d159f, 0xcecf6a01, 0xb9daf442, 0x90be64b2, 0xd3ee0da3, 0x83a267c9, + 0xadc82dd7, 0x6966b731, 0x7128d69a, 0xdd294366, 0x5b24ffb8, 0x581de68e, 0x0bf5ae26, 0x350ec452, 0x0cd96140, + 0xd758ba39, 0x1304db07, 0xd7ef7859, 0x3029b87e, 0xdd494b73, 0x4dc67f93, 0xcd6573b6, 0x9c028f78, 0x703259b8, + 0x1bf469f9, 0xc2c4e7b0, 0x062807ef, 0xe50a065e, 0x78cce8b0, 0x7e2ba16f, 0xf8707ce6, 0xb55a06fc, 0x7376d882, + 0x02164ac6, 0x07c6a745, 0x87a15434, 0xa6b87f9f, 0x669345e0, 0x925fd24a, 0x47496d01, 0x988642b4, 0x3b747310, + 0xd66336f7, 0x70a05c16, 0xf6f4d66b, 0x28570749, 0x8bc9af8d, 0xd83c9f48, 0xbe9a3d55, 0x7273f185, 0xd934a0c3, + 0x6cc81c69, 0xf6ed4d23, 0xb58c86a1, 0xf1c2c0ba, 0x44134f78, 0x62d846f4, 0x363c1615, 0x7bf65434, 0x3c40accb, + 0x4b7c2f6c, 0x6c0ccc4c, 0x06ac88dd, 0x10680ca6, 0x0e4fbabf, 0x6e9c04f2, 0x0c7cc5bb, 0xfd8eb77c, 0xc2c04f79, + 0xa168464e, 0x74da28b8, 0x0041a178, 0x98b3f64a, 0x15f52ab5, 0x7b210988, 0xa0b85504, 0x206f6ac6, 0x15b795fd, + 0x68c3e66f, 0xcbd0d24b, 0x7506bfcd, 0x46d58159, 0x10434360, 0x2ba0cec8, 0x6f75adae, 0x8a28a1d5, 0xce5f0c92, + 0x370feb0c, 0x8455a1c2, 0x5adb8c90, 0xa7159a49, 0xf15467bf, 0x8802e5cf, 0x2fe02d5e, 0x7fea805c, 0xd693e937, + 0x085557e0, 0x0f29af02, 0xa87ec494, 0xc9c5477e, 0xc240fd39, 0xde06c3a9, 0x0b65c55a, 0x69702206, 0xd105de5f, + 0xb0555d77, 0x3af76b0a, 0x6a041a81, 0xca73a20a, 0x039e3119, 0xa0267e8c, 0x018c97bc, 0x1d3bc469, 0xfea7ab0a, + 0x1df999b9, 0xa1d370bd, 0xf078db42, 0x970c8846, 0xdc7e696b, 0x8aec5123, 0xae0d750e, 0x0fc56239, 0x43f101f3, + 0xc56aee82, 0x38667f97, 0xbbfacd60, 0x62e78af6, 0x7185abe1, 0xc0b49665, 0x595b56e8, 0xca14444a, 0xaf8dd35f, + 0xd821c65a, 0x704faf67, 0x16d19163, 0x184cc7c0, 0xf7fbaa5a, 0xf7a6bdd1, 0xf10a6743, 0xe4b85f9d, 0x68af1666, + 0x8d2f26f4, 0x4b20675d, 0x3878f583, 0xf81cad11, 0x236b8d89, 0x47c1fe22, 0x82eb98ab, 0xc88ebbbc, 0xf6244b41, + 0x3fe1c445, 0xc05f537d, 0x068fd797, 0x2ac0d4d5, 0x99581add, 0x3cd2e3c5, 0x05a45ef6, 0xd7eb198d, 0x4f4b10ec, + 0x28837069, 0x0aa9305b, 0x0ec67398, 0xa90609a0, 0x03377d3e, 0x6da70897, 0xfb38ed4b, 0x7a291510, 0x0094393a, + 0x6e660e0d, 0xe2982077, 0xd86095be, 0x77d319a4, 0xe89897e6, 0x19a1ca79, 0x35691396, 0x3da14cf4, 0x2333b07d, + 0xe334722e, 0xee5a7565, 0xca26571e, 0x52cf705b, 0xf5e57d32, 0xa87a03f8, 0x471644ef, 0x43dcc55e, 0x0530297c, + 0x8cda987e, 0x13205d08, 0x9946d751, 0xbee06fd3, 0xb1e3914b, 0x0b1b016e, 0xf44da49f, 0x89fd469d, 0xb25e0234, + 0x4c863e76, 0x596354fe, 0x820a37cf, 0xdb579932, 0x5fb55bfd, 0x34d3bfec, 0x548d8a89, 0x4f2fa31a, 0x7c6b87bd, + 0xe16ff3e7, 0xa156bc12, 0x912d7b25, 0x28bf284d, 0xf7380429, 0x773b18e6, 0xbf6cd4c5, 0x42e4a719, 0x3f102afd, + 0xf1df9df2, 0x26c0e05c, 0x5bf0936d, 0xc5ff7152, 0x8fe5faa4, 0x4a487ae8, 0xd87804c6, 0x59b9ec85, 0xd258e0a9, + 0xbddd6191, 0xebbb3485, 0xc856f03c, 0xeb53700f, 0xb630360c, 0xa4bca35f, 0x63b1635a, 0x87a3e2e0, 0x9a61438c, + 0x4bb1c584, 0xaa02eb5c, 0x3c87a50b, 0x0bc33ed0, 0x6fc4138e, 0xef3a71ee, 0x6ff6dc69, 0x3ea02619, 0x55972b38, + 0x96aeb90b, 0xf6f4a306, 0xde6719d9, 0xab0a09a2, 0x683e1708, 0x950441c3, 0xca080871, 0xdebb142b, 0xdb841a67, + 0xe4a5bae8, 0xddb23cee, 0xa4e12fa3, 0x103872e5, 0x4050f7d1, 0x07bd906c, 0x1f58934f, 0x9b750dca, 0xa2a8190e, + 0x60135f26, 0xbd680dbf, 0xb1c7410e, 0x4c47a9e7, 0xc81704d4, 0xa2a89e70, 0x2d44200a, 0xb0814ab7, 0xf34d8533, + 0x44522e35, 0x5a95b014, 0x67ebf2ea, 0x6fec37f7, 0x2b127f93, 0x8b88662f, 0xb4c1d30c, 0xc5f93c2a, 0x1b5a5555, + 0x59acf691, 0x68bd24bd, 0x2e5220ea, 0x7893d064, 0x5bc0f686, 0xc7f075dd, 0xf450a35d, 0xc697a868, 0xbb144cb2, + 0xe2bb055c, 0x487e4b1f, 0xd45d785e, 0x5e708523, 0xa23e33e6, 0x52ee3c40, 0x5a1ab47b, 0xf423f20d, 0xcdc9d8ff, + 0x9333d574, 0x850a1861, 0xecea0151, 0xda0ed5fd, 0xa92998c7, 0xc2e5b662, 0x91cfbc2b, 0xbbe41d10, 0x16be5cd1, + 0x3bddaeaf, 0xedcf6a38, 0xa07e498f, 0x9efbacf5, 0x10afb04f, 0x7236d2a6, 0x89735ba3, 0x32568aa2, 0x06aef048, + 0x7805e754, 0xa1c71abf, 0xf2aaed7d, 0xfac3e92f, 0xb4c94884, 0x5f14d33e, 0x89ebbd6e, 0x7220b59f, 0xaa0261a4, + 0x5dc24cbf, 0xb988b1c8, 0x595345b2, 0xc0a302ec, 0x7e28332b, 0x0e020d6b, 0xf3a3ec1d, 0x0362a93c, 0x875550ef, + 0xfe6d8447, 0xc17db43e, 0xfc25dfe2, 0xfff17068, 0x8cd6bfe5, 0x8a74d46f, 0xa918c9af, 0x4f167277, 0x5b22f325, + 0xcc93c0ed, 0xdee8a99c, 0x0c3c3a90, 0x3a425640, 0xe8cf72b6, 0xe082e302, 0x20258fc5, 0x5f646d3f, 0x867521e3, + 0x08d8df73, 0x9ab033b0, 0xbcdf490b, 0x6d89a1f6, 0xc8eb0741, 0x0a3ef30c, 0x951f4ea3, 0xb6ebcaaa, 0x146983bd, + 0x73411724, 0x6f49ae60, 0x4cdc611f, 0x8881134f, 0x0ef8e9eb, 0xa7499aa3, 0xefffdfd5, 0xa52ac6d7, 0x2aeba066, + 0xea17df0f, 0x022c190c, 0x643d088c, 0xc852ae80, 0xda039792, 0xa14d3aa0, 0x1cb1881f, 0xaa21975f, 0x9f1cfa6d, + 0xc2351ad9, 0x1a8b5071, 0xbd678efc, 0xa0928676, 0x61df6882, 0x6bc7c982, 0xf00384dc, 0x60d44e4d, 0xf9af111c, + 0xf8084221, 0x4afd8d31, 0xfa572c8d, 0x861fdc23, 0x81533bf9, 0xda817cc2, 0x19c4c9af, 0x73fab396, 0x60a87779, + 0x72b1d7d0, 0x9a7505fc, 0x7ffeb687, 0xd267a5a2, 0xc73d1f31, 0x9ddc0108, 0xb07a34c6, 0xf3ef1b00, 0x28ff5c6e, + 0x0cc89ba2, 0x650f22a1, 0x673f781f, 0xb9eac713, 0xae1d4625, 0xbcfc1e08, 0x241325f0, 0x0e9f53af, 0x9aa852a3, + 0x62a1b89b, 0x688cbc29, 0xdbde63ae, 0x22ddf53f, 0x740d4f71, 0xecdb6edf, 0x83180d4b, 0x3b23650c, 0x82ac9443, + 0x2b8fab43, 0x924a56ae, 0xcd34d435, 0xba097115, 0x7cc3c1ae, 0x1a755546, 0x00091cf5, 0xb584834a, 0x3af65105, + 0x637c5355, 0xdf5aa79f, 0xdae890aa, 0x6d4bf12c, 0xb48b1a4f, 0xcb558224, 0x0b671acc, 0x2736f187, 0x836430e4, + 0xf8fd91b8, 0xdd47d840, 0x0be537fb, 0xa9abf3cf, 0xb4f94c48, 0x1792ecbf, 0x0e85f9bd, 0x5d02aee4, 0xd91bc722, + 0x97414088, 0x7ed5de92, 0x88ee82bf, 0x8c53c0d4, 0xd01398d8, 0x6cf4d256, 0xa560c744, 0xf93dc214, 0x290266c7, + 0xd31aa640, 0x615244cc, 0x12cdce6c, 0x1ff0a0c0, 0x381e810b, 0x792c4ede, 0x000aa07f, 0xa8c7eeb3, 0x0fa14d8c, + 0x301407d4, 0x66273530, 0xd9c298ab, 0xa23effe8, 0x173c4274, 0x2d9a3f21, 0x9bae34c1, 0x25ec3c96, 0x330ce379, + 0x3a372785, 0x22c21ea5, 0x75c4d29f, 0xf8af6da1, 0x17da70c9, 0x959279fa, 0x16c5486a, 0xaac34d1e, 0x16f17cfc, + 0x56c6915a, 0x2e9a2895, 0xf8578765, 0xfed34725, 0xb4c5aab2, 0x3a71a4c5, 0x8bd86e6a, 0xfbab2d7a, 0xe826433c, + 0xba805de8, 0x08d519b6, 0x0dcc6c92, 0x4f609a10, 0x005c02fe, 0xa21dc87b, 0x9f9492cd, 0xb2b060a4, 0x64576153, + 0x81786e6e, 0xf458ac36, 0xba665bb8, 0xffb8b9c3, 0x16811848, 0xc9c0dc9a, 0xc4086b0d, 0x4d117b0b, 0xbf10bd3c, + 0xdf356ac2, 0x0cf427d2, 0xcee0fbb7, 0x8caa5e4a, 0xeaac7f83, 0x8142cce5, 0xc53ca760, 0xf1573c83, 0xa9c9ab6a, + 0x1ba160dc, 0x0dbe1e0e, 0x73c455eb, 0x62d829b0, 0x45cc3555, 0xc0922a9a, 0x81d2dab2, 0x9ddf9777, 0xc4901896, + 0x35d0c921, 0xeff02eae, 0x62efd47e, 0xf3880c6a, 0xde9f76b4, 0x99346334, 0x38f8387c, 0x16b9875c, 0x3c6dca23, + 0x5ed47ce9, 0x502618e1, 0x7147b39f, 0x6cd62912, 0xc12d8cf6, 0x40f43123, 0x83dada4f, 0xe31bdc3e, 0xd23a961a, + 0xac77d77b, 0xfc4b23b8, 0xdb2cfb6a, 0xf18b7888, 0x9a1620fb, 0x2f6a5183, 0xb3cd7c63, 0x06873261, 0xbef7f318, + 0x51ad8831, 0x567f36eb, 0x594973d8, 0xd5b93df1, 0xca189dd4, 0x317520e5, 0x17239fbf, 0x681abe1f, 0xa5aaf901, + 0x8aab9f0c, 0xbba5966f, 0x69bb3632, 0xc868f880, 0xb9383d94, 0xb16066a3, 0xc42970c6, 0x29da2efd, 0xd6f1957e, + 0x3b30ed4d, 0xc0402077, 0xcc2ed9d8, 0xa8f7813b, 0x792537bb, 0xb36ea4cf, 0x1354a9ae, 0xe8d74012, 0x3f6ed505, + 0xc08b18f8, 0x86f146cb, 0x8ca9d70c, 0xdb7bc85e, 0xfac5a473, 0x1eac4986, 0x21d9d3ab, 0xe317d28b, 0x0d0fe9a2, + 0xcbe6e48c, 0xdead3486, 0xa111d087, 0x49ab1726, 0xe87ba2b2, 0xda727f8a, 0xf371b54a, 0x1efcbef8, 0x8eeff6f9, + 0xd7ede393, 0x984dfefb, 0xc75a5048, 0x82187be1, 0xe37e3cd0, 0x596bbee0, 0x91961634, 0x78519a71, 0x85844cd6, + 0xac7e29fe, 0x906aa988, 0x8f5e156d, 0xe32756d2, 0x024c061c, 0x0384155a, 0x46744512, 0xc1c82446, 0x9de5ba43, + 0x678e29a2, 0x03d1a903, 0x534a7bf5, 0x738a9e83, 0xfe0cefee, 0x4d2a316e, 0x7786caca, 0xf06ef9f8, 0xc356da31, + 0xd5ec6aab, 0x98d4ab0f, 0x1e321982, 0x659f3b27, 0x396d29ac, 0xb2c49e29, 0x920df3c2, 0xdebb9e2f, 0xf2035c53, + 0x565d5ed2, 0x3d8302a5, 0x9a4ed604, 0xd5d0fafb, 0xab37e76d, 0xd03c72f2, 0xefab66bb, 0xebe47a42, 0x60b0688e, + 0xefa644e0, 0xa42595d9, 0xc63c3f30, 0xde141a98, 0xff51dd16, 0xe4fb88d1, 0x3f5469e1, 0x13da2adc, 0x84796e52, + 0x59ac3c91, 0x1b49704b, 0x49363371, 0x50a95233, 0x8a3d2a5e, 0xb2d88b97, 0x4e4e5b7a, 0x3c3229b9, 0xb320cacb, + 0x9bcf5586, 0x9656f51c, 0xc86af1b9, 0x2a56c391, 0x2ebca7c4, 0x63e4d2b5, 0xb8bb0833, 0xf0c492c8, 0x279c17c9, + 0xda73910d, 0xb377782e, 0x9697bade, 0x7922881e, 0x9669a991, 0x4c55eed2, 0x7805d71d, 0x20b75b71, 0x9743f6bc, + 0xc313181d, 0x1469633c, 0xc21549ce, 0xd5450944, 0x64c9148e, 0x5b7f2931, 0x0e8b9948, 0x7245a264, 0x00fa4a5c, + 0x04db1fc4, 0x204626c1, 0x38933608, 0x249e5388, 0x2a718b6f, 0xd9954cb4, 0x9b597e7d, 0x757c0a48, 0x93ca10e2, + 0x20f5def1, 0xde870966, 0x82fcda18, 0x88b4b1a6, 0x1c4170ae, 0x6c348980, 0xf7d1f8c2, 0xad07d146, 0x18793947, + 0x016df2ad, 0x488edebe, 0x982056a5, 0x0129ed2c, 0x43a222ee, 0x155341a5, 0x23b825fe, 0x1589bf8f, 0x6255d261, + 0x26790df4, 0x45bea96b, 0xa391908f, 0xd9b04f9c, 0x4d58d551, 0xf0ec178a, 0xb3405f7f, 0xf3e46528, 0xb337c04a, + 0x2afd266b, 0xca919f27, 0x6eb0754d, 0x99bd1638, 0xa56d8a94, 0x37c12b24, 0xcabacfbf, 0xef9aaba0, 0x459a852d, + 0x935ae9cd, 0x21d2d8f3, 0x5d02e642, 0x4230143d, 0x6467bed1, 0x54c9bf34, 0x58a418a7, 0xf5e1cb4a, 0x2c175ba1, + 0xe1ab6ba0, 0x3be356d5, 0xa2f5ac38, 0x044d386d, 0xb8a87b70, 0xb40a6e88, 0x38acbc32, 0x8718b31b, 0x832699ee, + 0xc81db85b, 0x71542378, 0xc49b0cb7, 0xb229ccb6, 0x3ba63d72, 0x6932aa10, 0x469d4f7b, 0x7ab4f4ef, 0x8d6edbad, + 0xdb298732, 0x6be845e3, 0x63c0e06a, 0x8a2ce944, 0x5b252eb0, 0x76945bd8, 0x8a95da99, 0x3f392ca7, 0x5af0fcf1, + 0xed0503e8, 0x96d5dfed, 0xe568efbf, 0xb1a531f6, 0x4cd7c490, 0xf61c4bdb, 0x6f1ac7f3, 0x17f90059, 0x54203115, + 0x382de9a1, 0x0fc53167, 0xad604ad1, 0x4526d973, 0x0aa32147, 0x3a15f0c5, 0x7ba23e71, 0x8d6f3eb6, 0xc2ce85ca, + 0xa1677cbc, 0xa2631f27, 0x585db471, 0xa889c849, 0x8c22ac57, 0x2c44d461, 0x9ec13bde, 0xf9b7b912, 0x18af5194, + 0xed86c8b8, 0xbbbf2db3, 0x9cee31bd, 0x5ad2693e, 0x3a786c28, 0x757512e2, 0x6aa3c3ea, 0x75bdf39c, 0x264a06c4, + 0xdc4637d5, 0xa39b3cdc, 0xf3062646, 0x03805cf3, 0xef820919, 0x2179504f, 0xc4d5daf4, 0xe6b567e7, 0xe158b16b, + 0x52210f8b, 0xdfb774e8, 0xf5d28e3a, 0xa2e32904, 0x778c5c2c, 0x4f4f5f8f, 0x4cd3cefc, 0x96db745f, 0x67a2e3f5, + 0xc74e06b3, 0xa9a6cb9e, 0x2c62cea5, 0x21619558, 0x0dab90f4, 0xd476abdb, 0x0c945299, 0xb4c845f4, 0xc75a7bca, + 0x2ce4ae28, 0x9d39bfa2, 0x3001397c, 0x6b28ba29, 0x37181cf5, 0xea7d8197, 0xa94901b2, 0xf8da9e2c, 0xdb123d59, + 0x3db3f385, 0x283c824d, 0x030136ce, 0xcc937438, 0xdebb37ca, 0x55f31ab4, 0x711a3139, 0x46776a72, 0x42495e91, + 0xe2f573e4, 0xbde3fbd6, 0x67ba640f, 0x3b92ec8e, 0x71dc1e0c, 0x16c12b45, 0x83f63a20, 0x84453768, 0x0f9b6fd8, + 0xa6e2cb43, 0xe62a130b, 0xf32b8ed4, 0x6751b7af, 0x2ea9555a, 0x0dfbe7b4, 0x5ae45fce, 0x59ba1fe1, 0x7b0b75f9, + 0x2db30e1c, 0x4d9d84b5, 0xbc808c69, 0xfe8a85a4, 0x9be7542a, 0x8abc6aea, 0x5207b90b, 0xe2fd7533, 0x11f56fc6, + 0x733ef81e, 0xf1121609, 0x894e95e8, 0x91602019, 0x60bee8ca, 0x2d8e442c, 0x38be324f, 0x5d1388ce, 0x1dc53b99, + 0xfc23e5fd, 0x5e1d5c7a, 0xf76595ff, 0xad7d2a33, 0x45891476, 0xde5fbf15, 0xf984fff9, 0x90e80f49, 0x208b9193, + 0x3041f5ef, 0x3a195399, 0xd718b008, 0x84ae2a4f, 0xb8ca032f, 0xe0837dd8, 0xbfce53d7, 0x2199c91c, 0xad8cad0e, + 0x037fe77a, 0x7c61a2c6, 0x8c97b7d9, 0xbb7dbafc, 0x2b9b9a10, 0x243e08ea, 0x581b002e, 0xaff9d51f, 0xaffc3e67, + 0xa50b2129, 0xdcace1fb, 0x7cf37f95, 0x1a87a0bd, 0xc7ecb6cc, 0xbb86800d, 0x2c2e287f, 0x320e40ac, 0x3fcd6efc, + 0x988b3559, 0xad8af910, 0x3758f327, 0x1a769df9, 0xd58fb60c, 0x354a2a87, 0x5d07de1c, 0x8c517b22, 0x62f9a4e1, + 0xa2468fd4, 0xae793051, 0x77d30d0b, 0xf3325b9a, 0xba377b59, 0xd892e90a, 0xb74a8aec, 0x6e2c6294, 0x22b5409b, + 0x8d11a8db, 0xef72b01d, 0xdd3980a3, 0x2c526e58, 0xcd7080bf, 0xbc7d3e21, 0x0ddad139, 0xa44bd2b3, 0x94faa151, + 0xf9e5dcb6, 0x26aa7ed3, 0x44c81af5, 0x80db14f3, 0xed4c6e43, 0x276e5831, 0x6011bd06, 0x90bb4301, 0xc197156c, + 0xa1e3eca8, 0xf6ed9bc3, 0x806cc200, 0xefc74179, 0xf6f8c01e, 0xdbbd343d, 0xdd15afeb, 0xc0dd02f7, 0x492e127d, + 0x77e6712b, 0x29c8adb9, 0xb95efd05, 0x16a64cb7, 0x46554732, 0x87898594, 0x8e119505, 0x951e13db, 0xae61b93a, + 0x74535203, 0xc34c3240, 0xe0d62593, 0xb0d7ce6c, 0xddb92662, 0xab364db4, 0x0ff7812a, 0xa3b2f9dd, 0xed2cb086, + 0x2cc995d5, 0xb6271c45, 0x61b4ecc2, 0xa0d693c0, 0xb5a843fb, 0x406bd781, 0x7db8add2, 0x55f3b4bb, 0xd7dec6a5, + 0xa306aba4, 0xad635d65, 0xc2f3dca2, 0x066055bd, 0x814998ac, 0xd611bdb5, 0xf9138c51, 0x1767b134, 0xd077f3e9, + 0xc0ad9ee1, 0x1d62d142, 0x1325a8e3, 0x70a52a1d, 0x52ac144d, 0xa4d1b117, 0x582e88fd, 0xc74da1d0, 0x1c1acb55, + 0x58e51ee6, 0x23f06302, 0x6f658ff5, 0x3c0918db, 0xee893f5c, 0x785573c1, 0x7d30f7f7, 0x69e9a2a7, 0x16970455, + 0x940f64a6, 0xe1c3f56c, 0x4593d775, 0x1a68352c, 0xa6275d24, 0x704469f9, 0xcf1cfa7b, 0xb24d3e4a, 0xecd5aedb, + 0x4f631fdc, 0xb232f4b4, 0xff68b9b3, 0xd9212696, 0x0f92c27f, 0xa1bb7fd8, 0x40436bf9, 0xb0c0e6b6, 0x340bd0c4, + 0x4b4700e2, 0x4f3942d6, 0x482f48f2, 0x49a1a076, 0x4b53dff2, 0x9768cfe1, 0xc7456705, 0xba27390b, 0xcc7550da, + 0xc16b9372, 0xb2679573, 0xd5d48cd3, 0x0f36c0bc, 0x9d28fd1e, 0x0809c41a, 0x989bbd84, 0x01517ed9, 0xd57b13bc, + 0x2a9b3e63, 0xad66da85, 0x4c72ac47, 0x3cb924d7, 0x6dd669eb, 0x5afabc5d, 0x60766226, 0xff5a67c2, 0xfd48689c, + 0xe9a3fda4, 0x4b30e6a7, 0x876656e0, 0x7e27fe8f, 0x51f5cc51, 0xa0b9fa1f, 0x384110b7, 0x4e963fec, 0x321c0f2b, + 0xe94d3887, 0x6d24421f, 0x60f49722, 0x1c3f363a, 0x0251e695, 0x437594af, 0x160dd09f, 0x1367db4a, 0x3d2d1cf6, + 0x3e4254aa, 0xef56bf8d, 0x4ec0e5ea, 0x19a577ac, 0x99bdf878, 0x0e545bd0, 0xb1490703, 0x5230dde7, 0x053d9ac5, + 0x7b0f8b87, 0xc3027f91, 0x026bc4a2, 0xed7ef5fb, 0xd3db58ca, 0x440da7ac, 0x43fa32cd, 0x43320688, 0x6a0fc1ec, + 0xe91c9e1d, 0x20c28f42, 0x9f677058, 0x57e7d397, 0x401ad428, 0x39c00f50, 0x8077497f, 0x98ba06b3, 0xb5329760, + 0xcf536768, 0x9e2683b7, 0x9a9b472b, 0xb7998661, 0x0a2c1914, 0x1113fae5, 0x319d48ec, 0x35627cec, 0x9d9523fa, + 0x5e2f4779, 0x0489382f, 0xe9fb5bfc, 0x28e7a519, 0x5cdb5b5a, 0x20d7bd66, 0x3abc6264, 0x1ba9faa3, 0xe689cba1, + 0x5b9e2a91, 0x139b3062, 0x08d99e14, 0xc1d34c8b, 0x81f595b8, 0x7f4a5270, 0x7e0494f4, 0x1503a010, 0x5ccdb7a8, + 0xe5353993, 0x9bf0cd31, 0xc5c519f3, 0xda874c0d, 0xf4eda0c1, 0xba3dc00c, 0x51b3c893, 0xed9928b5, 0x77068d1b, + 0xd0efddb9, 0x6fa4b503, 0xfbe6c367, 0x0420ef61, 0x526d4d79, 0xed699bab, 0x2cad8d16, 0xa241e075, 0xb0010028, + 0x717dd49e, 0xdf956832, 0x6d14a4e7, 0x835b51e2, 0x50ba6e42, 0x70c0f0c8, 0xa62d920e, 0x3c36af1e, 0xfdb14ad2, + 0x38f8c386, 0x15094581, 0x3b6d8437, 0x4a1958dd, 0x0f9605a2, 0x5edb2b44, 0x764e0db5, 0x65630949, 0xbc122cde, + 0x8080d675, 0xe4c71170, 0x6bb7f473, 0xd5aa3a73, 0x95f71fb0, 0x6c841cc8, 0x29635a21, 0xe8e64b0d, 0x7af722c2, + 0x6429ee7e, 0xc7dd07f1, 0xe3582b42, 0xc62fa9ff, 0xadc858ea, 0xd0d0c9da, 0x373952f3, 0xaa4de594, 0x0852804b, + 0xb2ff6227, 0x95d61eea, 0x11f14a3f, 0xcda7e594, 0x662c0578, 0x2917e286, 0xf2f55e52, 0x34de9a84, 0x3092eeef, + 0x1338f36d, 0x354c0163, 0x663052ed, 0x366adfdf, 0x2298f32b, 0x0cc0b25d, 0xd96c10f0, 0xf9bd11da, 0x31104400, + 0xf3c425f1, 0xa438645a, 0x07b46c9b, 0xb9e499c0, 0x678fa1f2, 0xc6e1dcb2, 0xc147ec64, 0x3b4507a9, 0x2fabba33, + 0xe22cbfeb, 0xb22eca1b, 0x30cd08a3, 0x65d4866e, 0xa8942552, 0xc0f185ce, 0x8b28ddfe, 0xee81dddf, 0xaf5ab688, + 0x983381bb, 0xcd46a4d3, 0x9d133f74, 0xdb1dd28a, 0xfc98c582, 0xe79e66e7, 0x214b9af5, 0xff8fa7cc, 0xd54a0030, + 0xd6073d45, 0xe9684eee, 0x527d84e5, 0xe85d3719, 0x7089485b, 0xd7bc8daa, 0x210b5438, 0x7ce13e86, 0x52ad20d6, + 0x6628bc03, 0x5f134c03, 0xe4da8678, 0x0d73489f, 0x0f3feefa, 0xcbb09821, 0x40608bbe, 0x6e18d894, 0xc1fc3bd4, + 0xbaa80856, 0x34cdb39f, 0x979164a0, 0xbdcc79f1, 0xe651b421, 0x302a9689, 0xe0926358, 0x0afb485b, 0x593c0ea5, + 0xa83c389b, 0x8a48a52c, 0xc76fded2, 0xbb18021e, 0x3f2ad426, 0xd68414c4, 0xfecdd2d1, 0x8fee8dfb, 0xc8da8e0d, + 0x9c9a1baf, 0x6aa33e52, 0xece3e810, 0x8758b2f7, 0x1ee6f252, 0x1008810c, 0x4925188f, 0x6d2469ef, 0xeb9980b8, + 0x08cfbba0, 0x36deb724, 0x25cc90dc, 0xd7019b03, 0x0a25b835, 0xac4724fb, 0x66b0e23e, 0xe8662402, 0x935dd815, + 0xa3a050d0, 0x90f352c3, 0x82c855fa, 0x59ca856a, 0x0439ca36, 0x266abf4a, 0x468b948d, 0x75c3059b, 0x3cf5775c, + 0x9750ac27, 0x781a45e8, 0xf87017f5, 0x59c39c06, 0x27ba2e18, 0xe1b316eb, 0x2539085c, 0xcab28eec, 0x0c755134, + 0xc79cc20a, 0x16619f0c, 0x9cc84647, 0x7872fc8a, 0x62100a3a, 0x945f5d84, 0x43841a60, 0x1b697e98, 0xce1922d3, + 0xc442e55e, 0x34ec8cad, 0x231b749e, 0x8eb14d3c, 0xc3d0e4ac, 0xfe3120d5, 0x75eea79e, 0x7e5ff260, 0x4db09c08, + 0x8b48d16c, 0x4d6679db, 0x08adc9ed, 0x36500f1f, 0xafcc3023, 0x191cdfc1, 0x273e1daa, 0x632a07a5, 0x7a670399, + 0xaf747008, 0x500629fe, 0x3bdd62a7, 0x7a904286, 0x457ccc5d, 0x3fc9672f, 0x431c26e7, 0x0a28a874, 0xa44776da, + 0x8981c38f, 0x2ceccece, 0x3189f2af, 0xc10d3a97, 0x1a2aaa26, 0x12454010, 0x18cd11cb, 0xd0558529, 0x26708d90, + 0x6207e90a, 0x6c201cce, 0x80fa9afa, 0x40e275e3, 0xd7a01715, 0xf0fb16a8, 0x967b0f6c, 0xedc3dcda, 0x3b612c9b, + 0x23fffca8, 0x8b095414, 0x3485333f, 0xf70b18f3, 0x84733ca6, 0x6c2f9802, 0xfadd215a, 0x51309f50, 0x87e470e8, + 0x96aeade9, 0x625be084, 0x42503eab, 0xef8b3bde, 0x13fe232c, 0x9e72d51b, 0x2fdbd3fb, 0x3fb51c4f, 0xa982f1f8, + 0xc582ded1, 0xab3067fc, 0x2f8f6b04, 0x43bb66be, 0x81781871, 0x267a380f, 0x9a7460fb, 0x4471a917, 0x3154f078, + 0x31f90b00, 0x41114f15, 0xf9d2bb8a, 0x1bd62fc4, 0x57a91a3a, 0xcef2dcfa, 0x56c8a7ee, 0x0257ff54, 0xc8e09f35, + 0x6f92d8b3, 0x6d62d39a, 0x81d15a13, 0x6b7cc502, 0xe71294ee, 0x92d3488f, 0xd2469348, 0xda6396a3, 0x01d8cdfd, + 0x72acfbf8, 0x9a50eaaa, 0x4edc2d17, 0x73e31316, 0xe711d716, 0x2348e621, 0x85efc70b, 0x01b680a1, 0x570354b0, + 0xc197df55, 0xce40939b, 0x64271bc3, 0x42fd9670, 0x05a7f7a2, 0x704761fe, 0xba3a9633, 0x8f95eb04, 0xe08f5955, + 0x73bd38e5, 0x3b7ed3b4, 0xdd2fbd32, 0x6c3d6e6f, 0x73075df5, 0x864f7540, 0xeaac20de, 0x810b602a, 0xe4ae7ba9, + 0x364de84f, 0xb7976a09, 0x8d3a3cd8, 0x2264d5f5, 0x9bfbbd4e, 0xe17ab443, 0xd1ffb02d, 0x5bc7d6fe, 0xb4c6ee99, + 0x4d9c8c6a, 0x2749142e, 0x4a8f66cc, 0xe4ccecaf, 0x712df902, 0x46af662f, 0x5d6a7672, 0x5e9dffe3, 0x1a309a13, + 0x39883626, 0xd24eb45e, 0x14b8c2d2, 0x789625ed, 0xfe722e82, 0x2cd24876, 0x66c636c1, 0xa0127830, 0xa72bfbb5, + 0xcb1ba7b3, 0x066b6f6d, 0x22fe2bf6, 0x8945db29, 0x01f082f4, 0x779c8907, 0xb196033d, 0xf293cc95, 0x04506e20, + 0x5fcdc84c, 0xa75fd7d3, 0x52d8922b, 0x70c976fd, 0x51d1475c, 0x59ddb425, 0x4e14b950, 0x98d50326, 0x62796a4a, + 0x7cf2336d, 0x1eb17db6, 0x77b18e56, 0x5187fe02, 0x61421c50, 0xeea6e257, 0x3dd82e61, 0x4d0afe71, 0xe7120f29, + 0x988b9703, 0x2c6d64af, 0x69ddfd9d, 0x639d53a2, 0x5239984f, 0xcf6e45b6, 0x83264f00, 0xa4471d31, 0x0dce319e, + 0x1a7bcc54, 0x8147c82a, 0x38a4395d, 0xd8ed35b6, 0xe9190296, 0xf5ef4049, 0x23dcfcc5, 0xf0841180, 0xd8448fee, + 0x9b8fa5de, 0xce2eb709, 0x691d5aab, 0x67d4f90c, 0x5dcc5137, 0x51f2954a, 0xef0d6185, 0x963a27ca, 0xae6d8d76, + 0x2add8c8c, 0xc41d3c49, 0x2c98c304, 0x50eb482c, 0x05e4eabe, 0xbff14c2e, 0x0a80a227, 0xfcf8a6e3, 0xebcb5779, + 0x117e5957, 0x2879c290, 0x2d38ce7e, 0x0c142f64, 0xd07255f7, 0x4c33d023, 0x73cb9627, 0x2b798820, 0x39fea7e1, + 0x60bb2654, 0x688c44f3, 0x63db05c0, 0x9de36569, 0xb4b6b9c0, 0x6ea917ad, 0x73e5c024, 0x890f2ef1, 0x10008695, + 0xfbcdd7b5, 0x195d90ca, 0x1e5bb855, 0xce42c844, 0xa13f5283, 0xd9fe5231, 0x937ca2d7, 0x7ad5042b, 0x3465cd8a, + 0x938df2c8, 0x2237197b, 0x4a83cc3a, 0x36480322, 0x8fd6d358, 0xd87d0d7d, 0x712b31fe, 0x6e3c167b, 0xb94b76c9, + 0xf8fd624e, 0xc54310df, 0xd0568e78, 0x197a311c, 0xf62f4556, 0xe58a2cf1, 0x11dac440, 0x0fabf9ca, 0x6e7954c6, + 0x0ff59768, 0x8891a4f2, 0x893f25e2, 0x2da66959, 0xbb26712b, 0x91b4e21e, 0xda9b41e9, 0x9f85302a, 0xa0a86dfd, + 0xbd05450f, 0x8c8a9bd8, 0xd6e0f86e, 0xe18c10b1, 0x544b1b9c, 0x44f35fe4, 0x9cecdfcf, 0x1a63e5ec, 0x228c73be, + 0x3826c33d, 0x4b53102b, 0xd5a19a2a, 0x5c20ec66, 0x17a2952b, 0x9175fc43, 0x1886a95a, 0x245aa6f5, 0xbd3369cd, + 0xde3ef906, 0xb064d49d, 0xffe68a4d, 0x552089cf, 0x09778050, 0xc937ae1c, 0xa4a3090e, 0xd2ce7a5b, 0x4b53b54d, + 0x97da109b, 0xa3edfe4f, 0x98cc5d11, 0x4c39e634, 0xd2858017, 0x6554da51, 0x9b9d4aa9, 0x1e731314, 0xe5671c8f, + 0x3fe522da, 0xb033a9ab, 0x08b21af2, 0x101407a3, 0x091225e1, 0x4410efdc, 0x79567bbb, 0x7764fa1f, 0x87470bc5, + 0x14beda68, 0x692103bf, 0xa60cb8de, 0x0c9cd698, 0xa5e183c4, 0x7b78dabc, 0x88a451b1, 0xb7cd4197, 0x7e6db655, + 0xc4bbe5ca, 0x10d82e1c, 0xc3916ea9, 0x764e78c8, 0xd4c44ee4, 0xd5d549e2, 0xabda96eb, 0x93db3b6c, 0x17e3563b, + 0xb68ddc9f, 0xaa4b8178, 0x24c10eb3, 0xa9ac4359, 0xad08c3ca, 0x70fd63a0, 0x101eca32, 0x2aef8300, 0xd88e258a, + 0x50c26aa5, 0x4e25148f, 0x9bd397f7, 0x26ef520c, 0x31070e85, 0x06bea29e, 0x27af02cc, 0xc95adf87, 0x9bf60c21, + 0xfcf1b343, 0x579d8761, 0xd3b540bd, 0x2bb2f3f2, 0x23db6f14, 0x8155c4aa, 0x1217d128, 0xec391f80, 0x4d41e593, + 0x7d82247a, 0x3eff2321, 0x17a551a8, 0x784b7bfb, 0xb22e5e41, 0x0f195e5a, 0xd37a740b, 0x280d6601, 0x2625c735, + 0x16508800, 0x82b8cb7a, 0xfcfaf87e, 0x2490cbfa, 0xdc552396, 0xb95e05e1, 0xcb0cdc97, 0x6f66fd9b, 0x5894faf7, + 0x1f52a6c8, 0x3c6999a8, 0x535d5dc8, 0xaeb1ff64, 0x8cf23bf3, 0xc32e907a, 0x18cf6b65, 0x5e19f9b1, 0x887ae96f, + 0xa7a80e24, 0x2af17130, 0x4227242e, 0xe33eaa38, 0xf759ba90, 0x2067e46e, 0x1eb40e6b, 0xb48d52d0, 0x3b27f396, + 0xba6ee0b8, 0x3c53390c, 0x7493136a, 0x360a25d6, 0xdc8acefe, 0x6f31e0f7, 0x4a42253f, 0xd7b42a2f, 0x30e9f1fc, + 0x07e3cd77, 0xe892fd9f, 0xa4fbf27d, 0xb20c1554, 0xcf649a62, 0x695a18ca, 0x2607e757, 0x50e62e19, 0x7c422b43, + 0x1b650593, 0x909b2154, 0x0ec98a65, 0x06ed3383, 0xd37143ae, 0xf9024701, 0x51837257, 0x6369926e, 0x1ef53e65, + 0x05e18929, 0xed0d82de, 0xd4737223, 0x91918640, 0xe04b0d4c, 0x9d2899db, 0xc9af0b60, 0x85b6262f, 0x54630a3d, + 0x54548abc, 0x2bfca3ec, 0x7bddf977, 0xda640ed9, 0x242b5cb3, 0x131891ec, 0xf60ccd1d, 0x08f8a9f1, 0x2a0b0e55, + 0x2121f5f5, 0xe1d45463, 0x84e67533, 0xc3aa0e66, 0x115cd6c5, 0xa9367435, 0x1a72580e, 0xc2321e7c, 0x6d760dc0, + 0xb1e58c89, 0xc1f7ac3b, 0x7e428b45, 0x5c66da21, 0x8790a5fc, 0x3d623d15, 0x8c64e332, 0x13923069, 0x21def422, + 0xff3ba0d8, 0xe8f13949, 0x1c51409e, 0xb77b867e, 0x292be1ce, 0xd0c7a665, 0xdc85cf34, 0x7bdcec31, 0x709c1cca, + 0xe06f28f3, 0x0f561ee6, 0x1ddc733b, 0xbcd90156, 0x7cf9e28a, 0xde53336e, 0xb0b5abf7, 0xf50eac9c, 0x30e757ce, + 0xecd4793d, 0xf294c895, 0xa1237f0e, 0x1f442aa0, 0x80ed8ff3, 0x17ecbcba, 0x7adb092a, 0x8e59ca67, 0x9219b4dc, + 0xb665d1df, 0x662e0c3f, 0xa1b79fa7, 0xdc739eb2, 0xe37dd181, 0x30552def, 0x7119f9e7, 0xcc81ae31, 0x94d7c241, + 0x919299d8, 0x873bea5a, 0x562da620, 0xa557b5a2, 0x9617c7db, 0xf790f0db, 0xe7d56779, 0xa9b65671, 0x822da105, + 0xfb8ad974, 0xd3ec67ac, 0x613eb8c5, 0xcbf6fa45, 0x9fd593d0, 0xe1b438e0, 0x02cdf4eb, 0x30d9ac72, 0x70f3a404, + 0x380a5208, 0x710fa5ea, 0xb8350dd4, 0x453bd578, 0x57faca58, 0x333303ed, 0x1a597e5a, 0xb0f247cc, 0xb48c454e, + 0x0d730557, 0x9ec72196, 0x2afb2256, 0xdae8e3b6, 0x7f44d880, 0x19a0c206, 0xe8c1c1ee, 0x60188aae, 0xb8c487b2, + 0x136a8057, 0x36c1660d, 0x8b7da0a3, 0x89e17a06, 0xf227ea80, 0x1ecfd868, 0x64431aac, 0x81cccc4e, 0xeb737b79, + 0x579c164a, 0x4d43cf38, 0xe428443f, 0x0ec39f16, 0x669ed6dd, 0xed374be4, 0x49ecbe12, 0x06441251, 0xb845f39b, + 0x7943dd1f, 0x75612699, 0x8739c698, 0x731d4dd0, 0x425fb322, 0x6ce00a72, 0xe7053e7e, 0x06ceb9e8, 0x09ac5be7, + 0x8ff4edc3, 0x90754cab, 0x2a3070df, 0xc3d4cda2, 0x8c30699e, 0x0c774aba, 0x3939fee8, 0x2e79f6c7, 0xc1387e7d, + 0x48d10970, 0x622f14ad, 0x5e3d9614, 0xd02f92b5, 0x1abf55bd, 0xaef44268, 0xc56d9056, 0x7a6d8bfd, 0x4a9d99e1, + 0x1ae97e7e, 0xc61d07e4, 0xd8683f40, 0x91d3e95b, 0xadb67ad2, 0x0f031cf8, 0xc2de34d0, 0xb04b86d6, 0x5f0ff399, + 0x8b23490a, 0x6eb0de6c, 0xcf489f58, 0x3e10bfde, 0xbd106857, 0x46d564ab, 0xa05f81aa, 0x9a5e088d, 0xebf51257, + 0x538472f2, 0x3e4ee9f1, 0xacca9dc6, 0xcd6a2ae3, 0x6a5a2b0a, 0xfca2ebea, 0xeef996c1, 0xbb2d3872, 0xd5a14bb5, + 0x28a9cc31, 0x69206101, 0x08508512, 0xe252a25c, 0xc7b85719, 0x128bbfca, 0x5b7539c0, 0x3a12900d, 0x4128fbfa, + 0xfe3cdb48, 0x3d528e5f, 0x0196d263, 0x2c8f32a9, 0xb1970763, 0x0d97d33a, 0x61ceeab5, 0x8920c4eb, 0xa43b808c, + 0xc6187e72, 0xaac90260, 0x2294b379, 0x1b08344d, 0xa5c72439, 0x19c3f0e9, 0xa06f0e99, 0xc7f4f73c, 0x5e0a090c, + 0x4a2b547e, 0x2eadf428, 0xfbb7d88d, 0xa3ad1aef, 0x534e84df, 0xb78e794e, 0xee4b4c9f, 0xc2cbbf72, 0x54b53aed, + 0x9b9f66cf, 0x1d3c0a0a, 0xa06beb02, 0xae5c9b44, 0x7e4f15ec, 0x52d6fde1, 0x05353219, 0x093b64de, 0x8d053db4, + 0x7fe79ca1, 0x1b784c8a, 0x8925385b, 0x82d3474b, 0xe38a426e, 0xb6e876ef, 0x5cb9dc78, 0xa211fa78, 0x8a1b09fc, + 0x6b465314, 0x9583a057, 0xe135f595, 0x2d0196ff, 0x931f95eb, 0xc2692f6a, 0xd50977cf, 0x5c10aad5, 0x86b2bac7, + 0xe140cff3, 0x9e0151a7, 0x43750d0c, 0x05302634, 0xc8e6423a, 0x0d513213, 0x0ae72d31, 0xc9e770ca, 0x13d6eb80, + 0x1dea0d93, 0x1b5075d6, 0x333bb73d, 0xbc49487f, 0x5bc991e8, 0x8f0517f3, 0x0bf8d6d6, 0xb908f7bd, 0xcb17987e, + 0x9ac34dad, 0xa7fe33f8, 0x29ff9196, 0x77b0bb3b, 0xaf4bcddc, 0xf2e334dd, 0xa479d57b, 0xdfd79539, 0x2968af62, + 0x50b95f1c, 0x8d552d50, 0x54cfd7ef, 0xb9d48c4d, 0x80ddbfee, 0x0b58b0f5, 0x93b0580f, 0x4b72e4be, 0x8588db8a, + 0x1bdde163, 0xc549adc6, 0xf610a3d4, 0xa1c89408, 0xbab6071e, 0x7faee935, 0x4c694d41, 0x02de5a6f, 0x7b64d2db, + 0x8394df69, 0x68f6170d, 0xdc6a101f, 0x0fa8dd1b, 0x3334f2df, 0x8d1d1d7d, 0x0f820976, 0x967d374b, 0x15171caf, + 0xf4968abd, 0x422e7136, 0x1f9cc61a, 0x8824c31b, 0x979f4e84, 0x662e8fd5, 0x7811b3fd, 0x6a761438, 0x180a6f73, + 0xdfad4317, 0x64c51707, 0x23b5ab03, 0x0520e101, 0x2cefe605, 0x32e6c943, 0x144def01, 0xfea4c7cb, 0x495771a4, + 0x345e96b5, 0x6c52c755, 0x0f310628, 0x4f939278, 0x1cbdec09, 0x24e5b48d, 0x30aef757, 0x07909479, 0xa32f7313, + 0x2016279d, 0x4961649f, 0x13e896da, 0xe31b4d9f, 0x65c75c57, 0xe5740044, 0x5dc07b26, 0xfffc25ca, 0x48ad708e, + 0xd61bc9f4, 0xaa21dc30, 0x895d6ddd, 0x2be660ed, 0x1c3b35f9, 0xf08b8826, 0x419a2a63, 0x2f519867, 0x1a869458, + 0x9ade75d2, 0xc825c369, 0xc321b06e, 0x39234d6a, 0x6910e515, 0xdb2bf91f, 0x0f29c983, 0x952d237e, 0x37a817a7, + 0x3dc8ad84, 0xeba35d94, 0xd4003713, 0x22c3e34f, 0x7c2aa3f1, 0xd4694beb, 0xeb72cde8, 0x50909666, 0xed999344, + 0xcd423684, 0xeafb64cc, 0x363d0e5d, 0xed4616c1, 0x249d4fdc, 0xd2902e16, 0x5ffe56e5, 0x03fb115b, 0xd03f5c18, + 0x9811edfe, 0x05dd9813, 0xd52ced98, 0xd7175cb0, 0xeacace22, 0x62bb8a56, 0xded124e5, 0x6557fb5f, 0x13a1131d, + 0x6a42d448, 0x7c8e341a, 0xa774abc8, 0x42c867f0, 0xb7cf7913, 0x400871f7, 0xe2e64d95, 0xaadec261, 0xab17a32a, + 0x2fdc0ae7, 0x999faaef, 0xbb257184, 0x53de6f3f, 0xf321a6e1, 0xc30e2f2e, 0xa1506645, 0xc83d5596, 0x80be8e93, + 0x9801a157, 0x0881d99a, 0x800a21b6, 0x930503fe, 0xee711b7c, 0x99b1f7a0, 0x7b7b433d, 0xfb8c38ae, 0xd3754b4d, + 0x12f554f3, 0xdd9e9ecf, 0x079d74a4, 0x5e03bb19, 0x4b724345, 0x122bcc54, 0xe1edf02f, 0x96dd1253, 0x43b27e0c, + 0xa4f898e7, 0x59a7d063, 0xad38be52, 0x389f7e3a, 0x44b3021b, 0x133ea819, 0x0103aab3, 0x46246644, 0x5cd60e3d, + 0xe9e86434, 0x2a3585a2, 0xb12b3ba5, 0xb4197c2c, 0xb3d62eec, 0x4613ab1d, 0x4c8715b6, 0x3ac383e2, 0xd3d7fa5e, + 0x293f212e, 0x714f8524, 0xd005ca27, 0x27176c01, 0x1d515b20, 0x4d1df263, 0xbe5130f5, 0xbcd9b944, 0x637598cb, + 0x06a1bc85, 0xea51b9c7, 0x3e7532aa, 0xde7608f3, 0x90da23e3, 0x215f5092, 0xc90cbaa7, 0x794fe0e2, 0x2ff847af, + 0xac6f4691, 0xfeee4986, 0xcbe3b9b2, 0x4f501060, 0x451b6ee2, 0x6b66b6a8, 0x20521107, 0x0b49da4e, 0x0ad5e737, + 0xd9573b40, 0x964bb6fb, 0x604ba9c4, 0x6e7926a3, 0xf08980fd, 0xe08c0f9c, 0xc465ec56, 0x0ee03686, 0xf9ca2eab, + 0x2ba55b08, 0x1645848a, 0x5093d4d9, 0x563c7ebe, 0xb29f7015, 0x99f5613b, 0x3eee69a0, 0xcdc71536, 0x317d5635, + 0x3d6794b7, 0xf7cb66c0, 0x1529b192, 0x2286eafa, 0xa639a862, 0xce5c70c0, 0x7a69258a, 0x9604b749, 0xa6876c9a, + 0x4f59a845, 0x9006cfb9, 0xd7f6144f, 0x838b1405, 0x07930f7b, 0x6b3fb870, 0xbfb2c47e, 0x996147f5, 0xe0de7d52, + 0x52e8592e, 0xb01e35d5, 0x66d2e1d8, 0xf7780a45, 0x39af858e, 0x0a1b1182, 0xe8568b26, 0xb241556a, 0x494e8379, + 0x5f98006f, 0xebdb9307, 0x38460f1a, 0x41b639b3, 0xc919e117, 0x5b2fa1cf, 0x1f99f1eb, 0xc49164d0, 0x92502bf7, + 0x19748889, 0x13080884, 0xe9033583, 0xba7f4ca8, 0x2ad254bc, 0xf047ce3f, 0xf8a6b199, 0x2a544bec, 0xc796a458, + 0xc3efd83b, 0x79af45e3, 0xba3562dd, 0x374b1541, 0x1a767052, 0x498ed38d, 0xc1361d6d, 0xae77c476, 0x8ba13129, + 0xbfa0e927, 0xc72d48c6, 0x4592a485, 0x1d2b6911, 0x1886374f, 0xa463af0d, 0xe4f1795a, 0x3d1fb74e, 0xe865ac90, + 0x68f8f1b0, 0xcb3733c2, 0x2b39097b, 0x924ee0d6, 0x3d4c065a, 0xc3e4c7ed, 0xef810487, 0xb77397ba, 0x109b4bef, + 0x82412885, 0x4a9e1d39, 0xe379b023, 0x40d4012d, 0xcbc7af8a, 0x3354331c, 0x4d6fa8df, 0x40bb2c2d, 0x9b33ea23, + 0xce998214, 0xbe893378, 0x24b19f9a, 0x8d7a90f4, 0xbfe2aa4f, 0x8849e89c, 0x7c8e0c2b, 0xf445034a, 0xb787b2d1, + 0x88403006, 0xe79f468a, 0x1fc49f6d, 0xa3644543, 0x8ce265ac, 0x44c3fcb7, 0x14b7b4d6, 0xbeb193cf, 0xce2e5421, + 0x3896ccd6, 0x214286f2, 0x8e6fdb71, 0xedc65aad, 0x87b86fbf, 0x32cc9563, 0xb8ed4ef1, 0x7adada9f, 0x73982e36, + 0x9b7faa1f, 0xcb702603, 0x17a04d4a, 0x44a533a9, 0xbab6fe4e, 0x5339757a, 0x9e0f4d34, 0x8864f866, 0x6b0f397f, + 0x7fe0513e, 0x8d991db8, 0xc9714533, 0xccdb69ed, 0x27624ae1, 0x20c61c48, 0xddd67e1d, 0xb6bf908f, 0x7eacf65e, + 0x143a4c6d, 0xe978335c, 0x6df9e839, 0xb7633932, 0x5519dc9d, 0x17230972, 0xb605b9f7, 0x18b92770, 0x8e6d77d1, + 0x9d0468f5, 0xc4892329, 0xa5de790b, 0xdb4ffc34, 0xd4f02685, 0x471391f5, 0x842e8ae9, 0x628c8aea, 0x25d1d706, + 0xbd1d383a, 0x6db781dc, 0xc2a327c4, 0xf0c4b356, 0x63cc1dc0, 0x7642a84a, 0x4fa98393, 0x29b2b0cb, 0x3412763d, + 0x4effa761, 0xf6bd0336, 0xe1f209a8, 0x5233ff5a, 0xa92a0bed, 0x6495df83, 0x439f053a, 0x73271e4f, 0xdbfe7446, + 0xbf9668fb, 0x3cfde1d3, 0x71a70524, 0x5df1488e, 0x0e43f07c, 0x67f9287b, 0xbf04bb2f, 0xc9ffea67, 0x9c2cc8eb, + 0x74281a6a, 0x9649343c, 0x09fde17b, 0x877be207, 0xb504860d, 0xe06cd06e, 0x48103f6d, 0xe2043f48, 0x268c3d69, + 0x1500ae4b, 0x45f83f22, 0x4ec84259, 0x1fa1e641, 0x198b933e, 0x8f068cba, 0x243e6867, 0x27dc326d, 0x88c18b23, + 0xc30325c3, 0xa7c58af9, 0xc1f46a39, 0x29a024d7, 0xe8f52afe, 0x549d1746, 0x022500da, 0x758fbdeb, 0xc4cc2764, + 0x9b1495e2, 0x4f5ff893, 0x7287dc86, 0xbfafd2d7, 0xdc32c7ef, 0x8594147b, 0x553b0b8b, 0xc4ed30f0, 0xfa9765df, + 0xc6258f7c, 0xeab62314, 0x6278747e, 0x27d163f2, 0x66342534, 0x6c47e4e6, 0x0670dbbe, 0x3927ddd7, 0xd48e96c8, + 0x55e37d46, 0x3f354919, 0xb648683c, 0x618aca08, 0x949e74a9, 0x29367a2a, 0x0750dfe7, 0xe0042b24, 0xc1a90bb9, + 0x93aaf072, 0x48211274, 0xf8759d97, 0x18df9460, 0x8e3e051b, 0x53e2806b, 0xcb683196, 0x63afb9de, 0xdad00713, + 0x6251adee, 0x759fb158, 0xa5b91309, 0xd78dd450, 0x80ab92c6, 0x6b436212, 0x8b3dbd07, 0xa95cfb63, 0x20041dad, + 0xa7d253f9, 0xf3790175, 0xafb3c9e4, 0xfa491462, 0x1fbfcf5d, 0xcbb61d8a, 0x9fb9544c, 0x08b4fa62, 0x3a11b572, + 0xeffed6b0, 0x588234a3, 0xa3b52055, 0x533e3a4d, 0xf7283b98, 0x53a2cc78, 0x5ad01e62, 0xacf3f914, 0x9ab50216, + 0xbab67db3, 0x9ad06fe0, 0xa4a16587, 0x967e9ce2, 0x111a28ef, 0x8e2173a3, 0x1e141013, 0xb6092d87, 0xf86a558e, + 0xbf2fa0b2, 0x21fcc3f2, 0xf5cd0103, 0xd60013c5, 0x8bdf9427, 0xdf6bc22c, 0x20912d53, 0x7b38eff6, 0x03546084, + 0xc7d6873e, 0x7f0923fa, 0x6fd86317, 0xb95b44b1, 0xe918e053, 0x86948224, 0x07a68222, 0x1cee1986, 0x67fb72b0, + 0xeae341fa, 0xe7f713ac, 0x2a5bfd6f, 0x10e49f43, 0xca458fd2, 0xa4fff7e5, 0x5b6628f4, 0xed840d2c, 0x35a7d052, + 0xc0d186f4, 0x613afbe9, 0x13134d96, 0x0186b3c3, 0x3692b1dd, 0x3bb52328, 0xb9d5ea64, 0x9f307225, 0xb20c791f, + 0x34ec21fe, 0x9c1b7d32, 0x4ca6c59b, 0x654e669b, 0xb6bed80f, 0x8acd77cd, 0xf518928f, 0x9ac8c69d, 0xbc978e88, + 0x87102a21, 0x635551c5, 0x1f1b0696, 0xc5044cb6, 0x0ef322d3, 0xafd1e9cf, 0x755f6078, 0x4c3ef8c0, 0x477b3f76, + 0x8a6df76f, 0xb728efb6, 0xf4990a7c, 0x560b97f9, 0x79edf7bb, 0xb5b5fba0, 0xb8ec7ac7, 0x3f75cf85, 0xa058c51e, + 0x80f9f043, 0x710b3b39, 0xc0e83049, 0x465dd7a5, 0x859cc855, 0x0e678210, 0x67dfe37f, 0x7ea629c2, 0xc3cf7108, + 0xf16990d5, 0x1f83d175, 0x518dcd03, 0x806671a8, 0xb57da12b, 0x22541f90, 0x24efcb07, 0xfce8c0de, 0xce89b916, + 0xa7f6972f, 0xe3ec9311, 0x68c09a90, 0x073cd42b, 0x5dde5882, 0x455b7a72, 0x69e281df, 0xaa4600da, 0x67fdb1d2, + 0xdc700b6e, 0xd80ff1cf, 0x2aeae381, 0xd1faddac, 0xe1605518, 0xc158c9d2, 0x54ca3c93, 0x2e277e6d, 0xfd654c3b, + 0xddad3df3, 0xc8eeac28, 0xc644b1c7, 0x13bf67d8, 0x0c9684c2, 0xc32f57b6, 0x05106777, 0x852b4ae0, 0xbb058415, + 0x13d7d092, 0x8801ea29, 0xaec50fd3, 0x6550f769, 0xe58a16c6, 0x8436acf5, 0x3fc93a13, 0x45f75959, 0x834afd6d, + 0xae54b33e, 0x66607902, 0x183af68e, 0xce34f24e, 0x4fe3da81, 0x5e68edeb, 0x32ac7925, 0x4baadfd3, 0xefaddf33, + 0x410443be, 0xb8a3d830, 0x4f193c4f, 0xa4022cd2, 0x6ed0d9a5, 0xe7e704a7, 0x393aed90, 0x7d6aa321, 0x2195269c, + 0x285773e8, 0xad468833, 0x517fe698, 0xe540293e, 0x8bf3aab1, 0x4aa1bb4b, 0x5503ed2a, 0x6aa38c8e, 0xc30a1f74, + 0x0dbde301, 0x68b065dc, 0x2d3a272b, 0x9bf80f8f, 0xc8cf6d17, 0xbdda1a10, 0xf8f0932d, 0xb38053a2, 0x29953a3b, + 0x15d64bbf, 0x5316a476, 0x944968d2, 0xd2f22048, 0x4ea19ead, 0xc24d7049, 0xa2289ea8, 0xdd53f7c4, 0x59ae7703, + 0x49be8787, 0x9e7dd83e, 0x84922997, 0x2ab9a89f, 0xdc942d37, 0x4652945c, 0xbfbe2377, 0x998c9b2f, 0x04f8d013, + 0x8df4dbef, 0x97c9a858, 0xe58f9113, 0xd76d0c81, 0x0c12af4b, 0x2fbc3cce, 0x7b03feb4, 0xc7bf0dac, 0xbd782cd1, + 0x99a64a32, 0x2d9416b6, 0xc77a7b88, 0xcb974aac, 0xaf1a193d, 0xd300a0cd, 0xc1aae5d0, 0xc643374f, 0x99492a30, + 0x44777769, 0x752ade7a, 0x490d9391, 0x59bbfa8c, 0x34e804f5, 0x283ef3ff, 0x9af0d126, 0x0fb3c5aa, 0x43f744ff, + 0xb84ac696, 0x904994b5, 0x0d46509f, 0x26c030a9, 0x658ab36a, 0xca4ed0be, 0x6af3d20c, 0x1c602be9, 0x6a19bd0a, + 0x343465cb, 0xcff4867a, 0xa53c20b8, 0x4c6e4cf1, 0x30e3eef2, 0xe599e683, 0x0e0c323b, 0xa09e7dbb, 0x9c205698, + 0xb370d5bb, 0x9e7451f4, 0x96c47f17, 0x815532ba, 0x860c4956, 0xebb675d3, 0x2955cb2b, 0xe3f860e3, 0xc0fdd850, + 0x5c3aa721, 0x049be23d, 0x16ecd44a, 0x93dbc415, 0x45b261f9, 0x877d115d, 0x8b73b983, 0xa18fc3e9, 0x94bf9cf7, + 0xad0cb7ee, 0xb2426324, 0x05ef7685, 0xee02daa1, 0x7c37b9e0, 0xef1a9560, 0x680dbcc6, 0x13e5570d, 0xb325a48c, + 0xd1e1df97, 0x4947a973, 0x354ef1b6, 0xf313ed27, 0xf16fa5ff, 0x44b9972d, 0xc34d3a2e, 0x0e021ed8, 0x74b5afbf, + 0xba1330ec, 0x8e183223, 0xb8dd911a, 0x4b113304, 0x4b6e196f, 0x6d4a39ed, 0xc37a42a0, 0xcc7dc5e3, 0x376c2194, + 0x7c53c0ea, 0xb9d01b9e, 0x261b287a, 0xd1196ce6, 0x7a562521, 0x1e9e2103, 0x8f890796, 0x5e6c4c5f, 0x8f3517d0, + 0x1f12bd5b, 0x54a7e501, 0x3aee8268, 0xe59313c3, 0xfd074447, 0x23767530, 0xee2f3c6a, 0x74567e88, 0x0b63e219, + 0xf8649d3f, 0xf71c6871, 0xf6603c48, 0x8ed9c058, 0x2f33bccf, 0x0ebef79c, 0x009a4160, 0xb169ddb3, 0xa83506dd, + 0x4afaa4d0, 0xa4b23fac, 0xc8afaf08, 0xe7af9db3, 0x7c0badda, 0x36bb0ed2, 0xd4c62357, 0x50c4dafb, 0x849425f5, + 0x03929937, 0x61b5d16a, 0x9a718c6f, 0xa5a8e2ef, 0x31fce7f7, 0xcad89c57, 0x9831da65, 0x9777fba4, 0x810c892c, + 0x9768a528, 0x50d98729, 0x855cbe94, 0x8f3d2d34, 0x107fa88a, 0x2517d899, 0xae659132, 0x1dd7e17d, 0x5d80bcce, + 0x66deb0af, 0x8f084590, 0x6bba14c6, 0xc08a1681, 0xb662d008, 0x1b1366e4, 0x14736c8a, 0x8c87ff0a, 0xfaab7770, + 0x15584ae5, 0x041ffc88, 0xcaac8a85, 0x057494aa, 0xec5d4835, 0x67febdfc, 0x24585914, 0xb44cd503, 0x63d36aca, + 0x7b10d4b8, 0xd81ad087, 0x4ff5ad7f, 0xf562f387, 0xfe226ea3, 0xbecd1c06, 0x0f4db7c3, 0x63197ce3, 0x3f5fa664, + 0x599664be, 0x4e69ae55, 0xcfeff4f7, 0xfe5cbf0c, 0x63cf01c8, 0xd1bc5a17, 0x63e5a38e, 0x20465560, 0xee29b302, + 0x32b2594c, 0xe702a4f0, 0xda12a7b8, 0xf1e2ae0e, 0xb8916ee9, 0xd2694897, 0xc285fa24, 0xdf568652, 0x431ed903, + 0x57e58c56, 0xcaaf2724, 0xdda77be9, 0x54b68b55, 0xcb5e7a99, 0xdfabcbf6, 0x5d9c8e80, 0xb10a777f, 0x6a484599, + 0x257df4fc, 0xf268f1a2, 0x5f975b91, 0x880e8484, 0xcb76a0df, 0x07fbe9f9, 0x66b80f31, 0x63eb8176, 0xd7e73271, + 0xed0e9730, 0x3d93f44b, 0xd4baf448, 0xe188f28f, 0x35025782, 0x795b0f0f, 0xbcc5017a, 0x58ab225f, 0x8fe9a35e, + 0x89d5b8b4, 0x2ad40480, 0x06dc9c37, 0x18a52013, 0xecefa385, 0x1e7a6b23, 0x0e850978, 0xde66ead2, 0x467cd4af, + 0x657e08e0, 0xeef7a50d, 0xf844e972, 0x84ee80bc, 0x3bb61dbc, 0xb04c72b9, 0xb38f2832, 0x37102ac4, 0x6b8d787e, + 0xaecad772, 0x8b7da88e, 0xcae5757f, 0xfcc1d57e, 0x2b36cc48, 0x96558819, 0xce4d623b, 0xc9067653, 0xecb85234, + 0xee151fa2, 0x375840e1, 0x2eacaa5c, 0x2c8a5243, 0x785eec0f, 0xad80f872, 0x119591c4, 0x560cbdd0, 0xcc0885a7, + 0x9858e48c, 0x65c08b64, 0x51dbead2, 0x143e42c9, 0xda7ebdb5, 0x835df7a3, 0xcec826a5, 0x6398e0fc, 0x2dfbe1d4, + 0x6321af1a, 0x41b6703e, 0xbc59a422, 0x0c5d4449, 0x55bfac11, 0x1c794abb, 0xcf7cd13c, 0x7c4d70f7, 0x5b2a6410, + 0x22f8897b, 0x70b86dd0, 0xa877034e, 0x492271a6, 0xae177038, 0x5d7fff3f, 0xd1a41422, 0xd2b4390c, 0xfeb1681b, + 0x7200f228, 0xbc197a3a, 0x0462b5c1, 0x5df17e06, 0xe6aef610, 0xa205f1a2, 0x94c0efa9, 0xc49ccc33, 0xbc0e23ec, + 0x7e1db5cd, 0x0c00d8d5, 0xa17d7716, 0x355f8347, 0x9cda945e, 0xf81d31e2, 0x3490356d, 0xdf8f0465, 0x7d6a68a0, + 0x19a1a548, 0x09dde077, 0x92f290a2, 0xaecfa293, 0xb2e52cc2, 0xab167652, 0xa04f0358, 0xd3483737, 0xedb1d9cd, + 0x5db921af, 0x0c26b64f, 0x7aa69eba, 0xd2062e74, 0x1c1364a3, 0x7898d729, 0xb1040232, 0xcffec806, 0x441d17a1, + 0x37e260ee, 0xb791f7cf, 0xe8680f46, 0x82d36273, 0x6fa462fb, 0xc6d29e5d, 0xa8a8dd33, 0x3e083b5c, 0x9ea842ea, + 0x0eaf1fc1, 0x52080015, 0x5289552c, 0x833aef28, 0xf1aa3d34, 0x75997729, 0x364cab59, 0x49531bce, 0xe8c9e1a6, + 0xfc1413b6, 0x0945a537, 0xeca4ce56, 0xbacf3650, 0xd5d3fe71, 0xb68ee580, 0xef2594a6, 0x675cac13, 0x6db26d6f, + 0x838ac380, 0x53c30b32, 0xeb498547, 0xfed1cd48, 0x70ac42ca, 0x07fe815b, 0x03bbc7af, 0x09bd256a, 0xa372c8f8, + 0x7d5b59ea, 0xc16fe720, 0xcd568626, 0x2fcef398, 0xcdebb2ef, 0x3bc71a53, 0x24e1accd, 0x21120698, 0x396df496, + 0x1c8d07ab, 0x3b161782, 0x0dc9c2fc, 0xa9429f7d, 0xf33b099a, 0x84a743e0, 0x2b7189b4, 0x44f2775f, 0x7fa0d8ce, + 0x8e7e0d70, 0x612c141e, 0xf5c6a29d, 0xd5161fa1, 0x8a13591e, 0x124ae588, 0x00681a40, 0x60e5bfa2, 0x1a495706, + 0x1faeda9e, 0x541425fa, 0xf93e2794, 0xa52841ec, 0xfacdffdb, 0x8815ce1c, 0xb12f9164, 0x4bfcd75b, 0x433a230d, + 0x695062ad, 0xed18504f, 0x784eec23, 0x2e73b541, 0xd273f932, 0x5cf8b224, 0xea315aa9, 0x7a6a9107, 0x1190de52, + 0x2adcc796, 0xd5a751b3, 0xbf20ede9, 0x1320fd47, 0xd42251f4, 0x4fa11daf, 0x27679abc, 0x5d4aa59d, 0x10518145, + 0xe110af06, 0x8bf909fb, 0x6f8a5832, 0xe24ef61b, 0x5762ebeb, 0x0c52032d, 0x35a32057, 0x51d955bd, 0xf45bf589, + 0x2bd4cfc6, 0xad06f85a, 0x9fb8bb3b, 0x8abe13a7, 0x1074de84, 0x53af7b8e, 0xae270671, 0x9f3f179c, 0xf65c426b, + 0x9cb58cf3, 0x93eaa3d2, 0xb0e3522e, 0x46256cf2, 0xf87e5b18, 0xfd358751, 0x4753d690, 0x186da980, 0x77b39e40, + 0x7a5f29fb, 0x1d474a73, 0x0db96219, 0x8613689e, 0x3fc5ff4c, 0xaa19c559, 0xf5889d33, 0x0dc9bee4, 0xd1c1b29a, + 0xcbdb41da, 0x1ced4983, 0x2286db8f, 0x69157920, 0xee8eef74, 0xf014cb06, 0x8532b9df, 0x671e267e, 0x58de8f6f, + 0x157bef1a, 0x42980829, 0x690c0667, 0xdf3dabdd, 0x7cb2eaf8, 0x10a8d8f3, 0xb2181c27, 0xa8dcbe8b, 0x8a52d826, + 0x765a62c3, 0x15420303, 0x76fb2b18, 0x3b34e983, 0xf43f40a6, 0x77119df6, 0xea33654f, 0xb9ab0e07, 0x1fb68901, + 0x5721215f, 0x2bf1e57e, 0xea093e38, 0xccfe629c, 0x4163d4a8, 0x8a9e29c7, 0x7c086a08, 0x2928812d, 0xe385fedc, + 0xc42299e9, 0xac4b7622, 0x19c63564, 0x08370d3f, 0x525e2037, 0xb14b2a6c, 0x8821d1f9, 0x9335ac18, 0xc29c4f96, + 0x3f6f22d5, 0x6ab9c5c0, 0x06c15f7d, 0xf1472545, 0xa03494c9, 0x0386469d, 0x393c11d7, 0x2c829098, 0x49b0edea, + 0x6d82e60b, 0x6735c236, 0xc9bf9791, 0x4a3db468, 0x033250e4, 0x14b9a1f6, 0x46f78085, 0xecd168b1, 0xcba95092, + 0xa7da882c, 0x17de012c, 0x1e125708, 0x053a2729, 0x32223732, 0xa77caea5, 0x28a4fb37, 0x36265c61, 0x58c2cbc0, + 0x7329fc16, 0x77bed276, 0x02aa9d43, 0x846245b6, 0xb39aac44, 0x1651c517, 0x17459f45, 0xdc146a52, 0xc4308e37, + 0x43ad6eca, 0xabbb9d2a, 0xe18d7f7e, 0x777b24fe, 0xcd9346a3, 0x4335b204, 0xf84c0885, 0x8b3d6b84, 0xb5dcd45c, + 0x27a62415, 0x4fdc8b6c, 0x63c271ff, 0xd3d9031d, 0xf10f57ef, 0x979b55b6, 0x11dedf2d, 0x543a259b, 0x3215d85b, + 0xade74808, 0xeb6cc51b, 0x6cbe0881, 0xbbbcf197, 0xf0383bf6, 0x1ee6c15c, 0x6571920e, 0x60847ee4, 0xe1b71b59, + 0x0994d6b9, 0xe7da0c75, 0x51cf6b57, 0x5ee22294, 0x0476d7d3, 0x74611015, 0x43eac692, 0x02572278, 0xb94d139f, + 0x055bed92, 0x21cdbe93, 0x7da73c45, 0x28ba73c9, 0x493c60b7, 0x7de7d133, 0x1c7b8391, 0x66aee1ec, 0xf7a48369, + 0xc5c01a22, 0x0ea1761d, 0x90bba361, 0x87110c17, 0x44aecadc, 0x7d0ef836, 0x6e5864b8, 0xa54f3a97, 0xc2771063, + 0xa249cd6c, 0x68e268a5, 0xc8aac20d, 0x3d3b80a6, 0x66420495, 0x61f42d24, 0xeab88ef0, 0x870303a8, 0x9d41bd99, + 0xaa9ad227, 0xcb3ba69c, 0x453f9a39, 0x780a9e7f, 0x825bc09e, 0x75dd5712, 0xc0366ada, 0x968679b9, 0x649bdebb, + 0xe8a5abc8, 0xe3e8ad19, 0x8cce91f1, 0x4c4404c9, 0x26eabcb4, 0x902d8587, 0x3ee677d7, 0x9daa1164, 0xd8f4af71, + 0xde430144, 0x67251a83, 0xb166cce9, 0xfcad5b42, 0x44eeb67c, 0x4ac480a0, 0x940da84b, 0x9a4520df, 0xd0c503c8, + 0x29d8f46d, 0xdc11ae16, 0x74858555, 0x50ef3102, 0xbebe97a3, 0xe1243561, 0x99becbb7, 0x883782d3, 0x50ff8eca, + 0x8a2f6569, 0x0c57915a, 0xbd0739db, 0x3c645829, 0x7a192c94, 0x3a777eb5, 0xbfa4e43c, 0x8368e63b, 0xae179909, + 0x430e99f8, 0x9eed7822, 0x2c08f28b, 0xb8f17882, 0xb405e97d, 0xec5372a3, 0x8edc6513, 0xfb0a0e25, 0x1c186e22, + 0x97c0ba32, 0x3031232d, 0xc8357519, 0xb81c5318, 0xa86f0366, 0x07c2e4ce, 0xeeb87bcc, 0xd7c0b28e, 0x715536d5, + 0xde1cef5b, 0x55167ed6, 0x6eede073, 0x7ea87d70, 0x4e217ed2, 0xd09853bf, 0xb078706b, 0x6472e4a4, 0x3b8fac2a, + 0x147e7d71, 0x9c542062, 0x81f67749, 0x836f30f7, 0x844acfcd, 0x5573d683, 0xab0819fa, 0x15632e69, 0x96cb38de, + 0x12b83eee, 0x21d50d62, 0x41b142ad, 0x5312fdc9, 0xc35cd2c2, 0x357704b9, 0xf57ffa9c, 0xff82f6fb, 0xad214bd0, + 0x89b0c5c6, 0xf2b83537, 0x77bf5a01, 0x65ac40aa, 0x0f4bf8c7, 0xb132d670, 0x5bdc8de4, 0x9e3afdd0, 0x734f5ea8, + 0x2f7d056d, 0x18145cee, 0xb9c0ad51, 0xeea2a8f9, 0xea757ad4, 0x6fa1bc38, 0xf1991b57, 0x8fe2d25e, 0xcb9bf880, + 0xb754b4bf, 0x000c4963, 0x100ced75, 0x6a2c2185, 0x28458f2a, 0x1340a38e, 0xb9b35e21, 0x4790dcde, 0xdfce806e, + 0xf98c9ed8, 0x83136647, 0xab25c1bd, 0x206b8ff3, 0x7bceb432, 0xd3753880, 0x182edd1e, 0xa6d625d4, 0x50f600a9, + 0x7db24952, 0xa1f178cc, 0x5abc49fa, 0x8033fe7e, 0xbfeb8d23, 0xd2dd5d2d, 0x13b841bb, 0xba760a99, 0x2b11c288, + 0x45621d1d, 0x44ea00d9, 0xc34ae254, 0xdfb79a29, 0xda4776b5, 0xea56b265, 0xb6add9b2, 0xd77269f5, 0x9272d5cf, + 0x50875925, 0x72eeb2c1, 0xb2b24d62, 0x16ff4e7c, 0x26e15cb1, 0x2add03d1, 0x9b35bddd, 0x55ea76fc, 0xaa65bca3, + 0x5438a259, 0x6c91a155, 0x22a80ccf, 0x5c29627a, 0xfcceb59c, 0xd10b46ba, 0x6160c379, 0x306e95b9, 0x058c9552, + 0x54c14205, 0x4219ac27, 0xb38a8d84, 0x835a9c00, 0x96c07806, 0xc53af24f, 0xa7e39ccb, 0xebe0f35e, 0x62a6b24c, + 0x3b42b06a, 0x13502825, 0x3a60a801, 0xee63e517, 0x534100e1, 0x63477aa4, 0x4459913d, 0x778ace5d, 0xb4703a96, + 0xc3ebce21, 0x6a933205, 0x4ec60ac9, 0xb0dda5ac, 0x93c6e51e, 0xd494a353, 0x9337fe65, 0x867ecc55, 0x80e77d80, + 0xaddf8d26, 0x709fb226, 0x6a40fc23, 0x81368744, 0x115765bd, 0x8895d667, 0x21b30f26, 0xa3ac8b71, 0x01cb5a30, + 0x4b0d8dbc, 0x3cc85724, 0x0387fa56, 0x7f41b7b8, 0x571601bf, 0x62d8b680, 0x8d3e20c0, 0x64cd6f94, 0x6f8d5c44, + 0x766ed43c, 0x0f3737b3, 0xe247b5cb, 0xd6ebd769, 0xf0ea2c3e, 0x3c768231, 0x02d0f0ad, 0x4805f75e, 0x44c46bc7, + 0x1f64bba7, 0xc3faa691, 0xdea137a4, 0xf56c0603, 0x5130e5b2, 0x892ee35b, 0x983aa37c, 0xf54b0b28, 0x60a00ae1, + 0x8b2ded79, 0x73e3b6e1, 0xd0cfef93, 0x73154fee, 0x76f542b6, 0x4c34c11b, 0x2c6fbe1a, 0x418f2a02, 0x1bb4ad92, + 0x61770f6a, 0xafed5c8c, 0x0c977119, 0x70afe630, 0x5878b386, 0x3d84b6c5, 0x666ff28c, 0x3c94861d, 0xcb184dac, + 0x4b2daac8, 0x15233102, 0x66717cf3, 0x35eaf1c2, 0x94dfb092, 0xbbb6e28c, 0x637a57ad, 0x209ef293, 0x99d1ef1e, + 0xea052fc9, 0x0f250050, 0x6d4195f3, 0x2c5c086d, 0x7492c972, 0x99f4485d, 0x00267c0c, 0x0b14958a, 0xd5dd2a3d, + 0xb21951ec, 0x09b11ba6, 0x21ab2641, 0xb408aec3, 0x63e84cfe, 0xc2a7d441, 0x2ce771e6, 0x24d45b59, 0x60ed638c, + 0x63d0e272, 0xf6545778, 0x2374b537, 0xded82eec, 0x56e8f664, 0x8631ecb4, 0xe15f23c4, 0x830ea30b, 0x90ef8146, + 0x39cb9e75, 0xf13a4dfa, 0x76aa7032, 0x08fc324c, 0xd3ed92ac, 0x19eb5eea, 0xbe64638c, 0x85dd20cc, 0x863eaca5, + 0xfe9489d1, 0xa029e4c7, 0xee5af9e2, 0x46572726, 0xfcce0c19, 0xd27b9147, 0xe178d60b, 0x13a5dd23, 0x2bd20dd8, + 0x3db57b33, 0x888386c8, 0xc2b87d86, 0xbd138662, 0x7b2e9269, 0x631e9772, 0x65e3d592, 0x08e1a05d, 0x7b13ce75, + 0x918f7d6d, 0x17680af0, 0xb40ed21f, 0xdfeed068, 0x3243db80, 0xf5499397, 0x5d352520, 0x93364a8d, 0xa00bacb1, + 0x50930ed4, 0x2e93e00e, 0xfb5a4439, 0x92b41309, 0x31e81f71, 0x34287ae6, 0xa78bd909, 0x7cce4cc6, 0x3b205ae9, + 0x92f25414, 0x21930b61, 0x3fcbe7ea, 0xe26ff315, 0xe344f80e, 0x2660c342, 0x6d0e7ed0, 0x4037d2c1, 0x7a932e23, + 0xce001f19, 0x8b9ba518, 0x75ce957c, 0xa47d22ae, 0x2a239fa0, 0x2c6e35cb, 0xea402623, 0xdc0b9fec, 0xa4c1f5ae, + 0x922d1781, 0x1c7cb6be, 0xd379a79d, 0x4e3df04f, 0xbf834738, 0xa4049892, 0x99630c78, 0x0ff3cf9f, 0xf41c0f22, + 0xa8f5b95d, 0xc94a7925, 0x70320027, 0x25b38b5c, 0x4a533957, 0x233b64c9, 0xfc93a05a, 0xe4070484, 0xf7d659ac, + 0x13f8685e, 0xeb26d5c4, 0xa7954424, 0x3e694067, 0x6be2915b, 0xd83b1976, 0x6b74f3ff, 0x8cb2d1a5, 0x57a14cd8, + 0x8e9c3f5e, 0xcf934e9a, 0xc57411e1, 0x1ae79e32, 0x8f35a34a, 0xb63dfd14, 0xec7f30fd, 0x381fb118, 0xfac21327, + 0x0983d00b, 0x958cac42, 0x2c1ccdaa, 0x1c4f6bea, 0x4ce23016, 0xd2a417e6, 0x44d2e96b, 0x4f5acf0a, 0xa72e4796, + 0xae4c690f, 0xd06ddad7, 0xb5549943, 0x782d620a, 0x680223fe, 0x5160d40a, 0xf8f0b149, 0x6b2a5f34, 0x719cf492, + 0xe5b9a8f6, 0xf4873862, 0x8ecc09d4, 0x89d32b08, 0x3f638f73, 0x198c309f, 0xfeacbb84, 0x9f368b00, 0x0eec3e54, + 0x572693fa, 0x65687dba, 0x9e2e38fe, 0xe939e70e, 0x07a0eb4b, 0xd57d36a4, 0x52eab842, 0xd842739d, 0xa1afbefd, + 0x3b17e652, 0x885196ac, 0x757fb5c8, 0x0661bef8, 0x2c914360, 0xce728d03, 0x27ae7f6f, 0xe785f039, 0x64693483, + 0x05513573, 0xf5f05805, 0xc8cf702e, 0x4ea4af5d, 0x2c1d9932, 0x390f9ab1, 0x6a6c2245, 0xfba1a19c, 0x67061806, + 0xaed142ea, 0xcebd9e2b, 0x149c41aa, 0xd4e22217, 0x76deb46b, 0x19bcf732, 0xdd20c1fa, 0xffdf4c71, 0x452b4e8a, + 0xbe77d404, 0x6cc5f178, 0x648d495f, 0xf08ceebf, 0x085347a8, 0x6172c8ff, 0x00c48cfd, 0xe725dd6e, 0x0d8937c7, + 0xbe846dfa, 0x5db78e69, 0x0e006c12, 0xc2cf6255, 0x322d1ab6, 0x6bdbc815, 0x2e3d0172, 0x131565b1, 0x937b13a2, + 0xacf27041, 0x08097564, 0xc351da23, 0xd2ab078f, 0x74af9abd, 0x9ee9daf8, 0x4c9e450d, 0x73fc612a, 0x882a91e9, + 0x8d38d8de, 0x6839e645, 0x1a703705, 0xff750a29, 0x5bc004be, 0x4173bca1, 0x2efa4852, 0xf89abb75, 0xb97658ab, + 0x4156712f, 0xa78c8ac4, 0xc62cd85a, 0x662a6bac, 0xb76590d5, 0x84293455, 0xa99d121e, 0x3380f48f, 0x8bdecef7, + 0x6c33bcf2, 0x71ec2dc3, 0xb2f0ec55, 0xb1416527, 0x82abb50a, 0xfea1c8be, 0x359f52b4, 0xdc0c04c5, 0xb6f496e4, + 0xba07d278, 0xcd31dfd0, 0x9b24764f, 0x00dd1c52, 0xa4620ead, 0xc0287314, 0x9dd31385, 0x2b9d9c36, 0x75652ff2, + 0x24fc0a73, 0x517d1262, 0x6c0c21a4, 0xcb47b6d3, 0x2fa79224, 0x74334aaf, 0xb7af22aa, 0x8fab1064, 0x960709c6, + 0x102798d7, 0x0b8ee976, 0xfa90180a, 0x60ff2314, 0x1f19a0a3, 0xeba70d5b, 0xa0a399fc, 0x57ea3101, 0x1892084f, + 0x43204b0e, 0xec8f6cf9, 0x83c2ef23, 0xcfb53913, 0x416a69f6, 0xf95dbd0f, 0x7901d6be, 0xbbf2a1ed, 0xc7483168, + 0x56ac9883, 0x104bd80f, 0xd6c0c9b5, 0xfc3ab28f, 0x6b78cd0f, 0x425c56e2, 0x50022298, 0x22abf87a, 0x856cb87e, + 0x8f54c7be, 0x65d084d4, 0x3590ff73, 0xbfbc9394, 0x7b565c7b, 0x3c6f686b, 0x75f484df, 0x05f2edab, 0x9bbf9ec5, + 0x5695efc4, 0x593ee9e0, 0x514ab99f, 0xff268d7a, 0x7d09dab7, 0xc8e6cddf, 0x37595457, 0xe6df0fb7, 0xcb2ff0d0, + 0xe8e6425b, 0xcc15de89, 0x80472d28, 0xa4380f3d, 0xd8565c23, 0x9bfca4cf, 0xaf1f96a3, 0x7a6b296a, 0x98162a09, + 0x9a3c371d, 0x023ea9f6, 0xcc10c983, 0x67bb14fc, 0xa6ab5d0d, 0x66966a7f, 0x0e5ee0c0, 0x07bc43ce, 0xd863b2e8, + 0x571a7d02, 0x0e41674a, 0x7356bddb, 0x467c5b0e, 0xc51e1a6a, 0x6cd86e1e, 0xbbe59ea0, 0x3a0a102b, 0xc884b4ae, + 0x3823a6e0, 0xb844555e, 0x3382e582, 0xaa685636, 0xced89091, 0xa20e6ccb, 0xcb9ef39c, 0xd56c0fc8, 0x44f1775c, + 0x5301a9e3, 0x655274dc, 0x85da2d08, 0xce896209, 0x1d076a66, 0xddbbfc0c, 0xccdd0cdc, 0xd70778ed, 0xa7ee7d69, + 0x59a7172b, 0xe6deec6f, 0x2dfa877a, 0xc9918c85, 0x08e1344e, 0x82125b15, 0xc9fb6cf8, 0x95bdf173, 0x64521d9e, + 0x6dfb7abe, 0xc3956fac, 0x660fe1f6, 0x4eee5a92, 0x89e6514b, 0xb0abf6c7, 0x490daaaa, 0x784a2678, 0x79099a9b, + 0xf3a085c1, 0x722ee6c8, 0x9486820b, 0x597e73dd, 0xed677bad, 0xf7ad061f, 0xcbeb84d4, 0x4792b8a6, 0xe3bbdf34, + 0xbb10c6b6, 0xaf7dd130, 0xee46e549, 0x1b9ce9af, 0xb021f8a0, 0xd0d2f125, 0xa9943512, 0x7ad3b948, 0xed0aa97e, + 0x755b4741, 0xa0390659, 0xe06f5c7c, 0x3f4b7999, 0xb3cf9a03, 0x0b3920d8, 0x37d0404a, 0x150b4cf2, 0xec3bdf7f, + 0x8228a507, 0x0726c541, 0xd58797e1, 0x100c4e4e, 0xf8b8d140, 0x666c256b, 0xf48c3516, 0x0f83f9d6, 0xf16d2444, + 0x2307515c, 0x7e2e0946, 0x15ce12ec, 0xcb52c444, 0x54c20095, 0xd8d68744, 0x1c0bd571, 0xa802018a, 0x78095b0d, + 0x75079ed3, 0xbaad98cc, 0x77fa9ecf, 0xa2745937, 0x86fb1d4b, 0x60fa4a1b, 0xf1b49e37, 0x10d17b94, 0x4e857aa5, + 0xd728f2d5, 0x9eff521d, 0x72f048a8, 0xd35ad1ab, 0x3f183c4a, 0x14167cb3, 0x28fe62f1, 0xb15bd450, 0xabef83e8, + 0x3ca6339f, 0x4fec629d, 0xf809bf6a, 0x30a24864, 0x63aa5ca4, 0x1cb3fb51, 0xedc8d58e, 0x6c214fcc, 0x1569d827, + 0xd250bbb8, 0xa3937546, 0x982cdb7a, 0x6549a633, 0x1c4de556, 0x58f13f2a, 0x779aa06f, 0x486346b3, 0xf75b60ac, + 0xac20dc94, 0xd2023982, 0x1c5d5baf, 0xba52c8dd, 0x09ff07c0, 0x0c26904c, 0xde60e959, 0x479241ed, 0x1b711c87, + 0x95299541, 0xef59d597, 0x9ef721d7, 0xa6c08b8a, 0x3fc23a44, 0xb2a10487, 0x9716ce77, 0x582e4372, 0xda655e49, + 0x3c6df441, 0xfce2e8cd, 0x727dcad2, 0x54829fe2, 0xfa08516e, 0x770b566f, 0x6ea4041c, 0xc28d622f, 0x1037d1e9, + 0x4a58a4e8, 0xd4b6112a, 0x940aef13, 0x40636e8f, 0xe39b2e12, 0xa00e2ece, 0x2d086f6a, 0xaea3c69e, 0x4b60fe85, + 0x7661922c, 0x75d65770, 0xb194bc7b, 0xf68b11c9, 0x4551d97d, 0xa101eb5d, 0x6168d29e, 0x42595cc3, 0x0742a506, + 0x1722c25d, 0x16381740, 0x81f531e0, 0x3933b338, 0x614f9ce6, 0x4d701a8e, 0xc69cc128, 0xad2b2867, 0xbe9e4878, + 0xca95912c, 0xd33d2a6c, 0xbea61dfd, 0x9c18de93, 0xb5e14f1d, 0x30bf26ad, 0x8a734e77, 0xab24a248, 0xfd2311c6, + 0xdb0ca948, 0x831904c2, 0xa24389c2, 0xa3f4106a, 0x040cf575, 0x9387ebd3, 0x3ad373c6, 0xdba66182, 0x64b4fa90, + 0x32b55bee, 0x93c52e59, 0xca6b9fa1, 0x23f9c726, 0x2d474f7b, 0x328af842, 0xbd328ef7, 0xa916dddc, 0xb30feeea, + 0xd69f8f3f, 0xdbee6367, 0x2075166a, 0xe0012e35, 0xb8a78ba6, 0xcfc1f07e, 0x1fa48472, 0x18bce449, 0xf20fbde4, + 0x812a9f75, 0xe928b2cb, 0xbbf80979, 0xfc2b194b, 0x8dd41299, 0xa8db1d88, 0xca76d617, 0x087baf5a, 0x41aa54ba, + 0x4977ea37, 0x5969ea0b, 0x816a6ca5, 0x0a93b28b, 0xcb0ebe69, 0x9e343b30, 0x8511c9cf, 0xda05056e, 0x211524fc, + 0x5f59490a, 0x6091dab7, 0xef6e3c89, 0x5dd98f6d, 0x0820e56f, 0x9cd5ac36, 0x12837217, 0xb913df19, 0xc19ad6d1, + 0x8761390d, 0xe767fa18, 0x2b85c845, 0x4350b1ca, 0x13ae605f, 0x23600d0a, 0x996f0c39, 0x6c804873, 0x3898be28, + 0x302aff46, 0x803d5d23, 0x847c7378, 0xfad791a4, 0xb0f68b5d, 0xa5aec671, 0x9e7118c2, 0xd87d05f3, 0x1be8bfc6, + 0x85041df0, 0xd6edfa19, 0x8d9149e7, 0xd1ba0968, 0x3ec89cc0, 0x7bd49421, 0xd24a9762, 0xaedfaacc, 0x82a3f64f, + 0x3e710f90, 0xda4cdb41, 0xe6ab5df3, 0x8404e124, 0xd93ff01b, 0x083ac3fc, 0x2a1ed1be, 0x1e7a0d0f, 0x1fd54b01, + 0x19163b1f, 0x53042113, 0x65b3b185, 0x9ae458ae, 0x8c1c8f2d, 0x2e243995, 0x88e65d29, 0x2629ce1b, 0x0d954ca5, + 0x04b2afe9, 0xbe31744f, 0xd94ddb92, 0x1cf11dfb, 0x930b41ff, 0x68068266, 0x7f440dca, 0xf44eff5c, 0xbf932934, + 0x8e635538, 0xdb3dab3b, 0x155ed8ef, 0x4a1e1d81, 0xd96f512b, 0xfbd0406a, 0x3c4c39d3, 0x7d8cbc57, 0xd5608ff8, + 0x622c1677, 0x7bb1360b, 0x68d18c63, 0x1467ae5f, 0xbcd6bb59, 0x7ecdda60, 0x6d9a3218, 0xdb15e99e, 0x78741c79, + 0x495128ff, 0x8f30f670, 0xc3c6a246, 0x4c0a00f8, 0xe966a3cf, 0xe0eae451, 0x31edb809, 0x5824a38f, 0x837bebda, + 0xb26b9ead, 0x77e94cb5, 0x466c23c2, 0x41403a76, 0xdfa10b4f, 0xe578f17b, 0x26d73bc3, 0x0278fb60, 0x279c2c89, + 0x7357599a, 0x03f65236, 0x17478d1c, 0x4adbacd3, 0x1db80e18, 0x9e47b1e5, 0xb1ad2012, 0x463be1b9, 0xff537a61, + 0x88fa936a, 0x5921ed55, 0xc61fb19e, 0xeb2de1b8, 0x4b53b76f, 0xd6e43d56, 0x92743630, 0xd220a476, 0xf742a520, + 0x9b825844, 0xf801f8aa, 0x1cd0d771, 0x4d477f75, 0x368def47, 0xd7d689fc, 0x3de97b10, 0x74f1b92a, 0x76168630, + 0x2c2d9bf4, 0x8b93311e, 0x390f48b3, 0x8c169a8b, 0x74f56239, 0x51efd3cd, 0x3ec6f092, 0xbe508b49, 0x96aae945, + 0x26854434, 0xbe5d0c95, 0x3cb701b3, 0x080bad6f, 0xb1a6a8ed, 0x6d4b0e6e, 0x80cdaff8, 0xba82f1da, 0x30109088, + 0x2c293e97, 0x70635ac1, 0x58cb5ad0, 0xd1ae5477, 0x2b33bc2e, 0x9fde3b0c, 0xbc3ab56e, 0xf331acae, 0x79fac7b5, + 0x9bc3eb13, 0xb68d9c13, 0x4addacd2, 0x8b0d4824, 0xf8700bd7, 0x163b8b7e, 0xa7a4cd10, 0xa0694574, 0x70f4a9a2, + 0x5a7ff1b0, 0x05ab5d77, 0x155ecb9a, 0xd06817ac, 0x76ec4419, 0xf0543735, 0x5e999b7e, 0xd1109367, 0xefb90cec, + 0x592d9dfd, 0x8a84521a, 0x79151d7d, 0x7f4c636c, 0x3bd9fe4d, 0x8ca04114, 0x40cf5052, 0xf7bf26cd, 0x1683bca9, + 0x69d6642d, 0xd0eb74e0, 0x04602c4c, 0x048b4b81, 0x9ced00ef, 0x887ca0c6, 0x7fcadc05, 0x2e36d76e, 0xdaf35bb5, + 0xb46bbf85, 0xfc36e3ce, 0xf3c3b550, 0xd687086e, 0x224d293d, 0xa929bee2, 0x0852cb70, 0xcd0c62ec, 0xf7cbb4b6, + 0xf51c523d, 0xc83756a2, 0xa54273bf, 0x431aaa33, 0x4b450332, 0xa26291ba, 0xb10bdc44, 0x1e1d90e9, 0xb42a1639, + 0x143940a2, 0xf3024892, 0xde936b1f, 0x191af35f, 0x02ac936c, 0xba27ee67, 0x439ed02b, 0xb05650ca, 0xb5eb067e, + 0xc08fa98b, 0x9045fb48, 0x54aef742, 0x7bac7c28, 0x7f72aa68, 0xdaffd328, 0x4f9b0f74, 0xa3b8393f, 0x7e010e4a, + 0x4951e2e0, 0xae68d4cf, 0xe7069978, 0x0887e04c, 0x0d92ccf9, 0x02b3e2d6, 0x231be296, 0x6a286fbb, 0xa4e033d8, + 0x8699dcc6, 0x99439959, 0x0b26b527, 0x749be9fb, 0x7bf4f717, 0x39a2f3f4, 0x0179ee74, 0x2160b358, 0x38633d55, + 0xd8264960, 0x79fcd0c2, 0xdf19dfb5, 0x56463e53, 0xdf1a253e, 0xe319cc62, 0x2c6bd408, 0xd86e136a, 0x10997ee5, + 0x13debfc9, 0x6406584d, 0x86d42d0c, 0x12b97143, 0x4c5276de, 0xe1209687, 0x77f13316, 0x48ad240e, 0xf9f7fa6d, + 0x48cdb64e, 0xe9be2a33, 0xdfb640b1, 0x13cd85b3, 0x41ecff90, 0x090610e4, 0xb5922b45, 0x23521c03, 0x448aea1a, + 0x335f9c84, 0x86421460, 0x6bd84725, 0x3b32cdbd, 0x441906a7, 0x93c1d965, 0xfeaba5da, 0x00c58f4e, 0x2ea32d7b, + 0xdc64b07b, 0x5f90ccef, 0xcd7a6805, 0x4c14cd89, 0x071f5757, 0xbc0f1c7d, 0x11dbfa48, 0x3c53e4dd, 0xf1f24e0b, + 0xf2dd4d42, 0x3d514200, 0x20e29373, 0x017dc3fd, 0x72aac2e4, 0x48f73156, 0x47b18470, 0xb919f909, 0xae570553, + 0x44a0564e, 0xdb5b0930, 0x420e596a, 0xe8e59e5a, 0x8d0a35c1, 0x293ddd85, 0x111bbee9, 0xeabf1f33, 0xafa1e14a, + 0x617bfce4, 0xdca2d0e7, 0x1e455e9a, 0xeca52bb9, 0x862ab2f2, 0xcf134269, 0x17546eb4, 0x4eff477f, 0xc03aafb0, + 0xdd2f7151, 0xd8997b9b, 0x35afee24, 0xa9b48b96, 0xcc54d85d, 0xa7a5c595, 0x8b7d53a2, 0xec0a65b6, 0x82018b99, + 0x4392b6a1, 0x1cdc824e, 0x54a0d93c, 0x523e0d06, 0x99157ee8, 0x2d2385c8, 0x39adca3a, 0xb0418c52, 0x650a740e, + 0x5ae54187, 0x33a99187, 0xdca4c400, 0x8f0fea69, 0xc71cafab, 0x72ff58e4, 0xe7683440, 0xea2fcf2b, 0xba0dc12e, + 0x8ee09b4b, 0xe557ba06, 0x0499ff38, 0xccc0fc68, 0x3adc0cc6, 0x5a2878bf, 0x632e491b, 0x8f974645, 0x9c808d14, + 0x847892f6, 0x8a6d73c4, 0x758dc06f, 0xfb675a27, 0xef3b4574, 0xce9f4fbb, 0xbc8ef3f9, 0xac90cdeb, 0xae7d112f, + 0x12d558c5, 0x7ab0bbd4, 0x77b64e30, 0xa2e8c233, 0x5d36ec7f, 0x0ef6109e, 0x256fbb71, 0x62c48e7b, 0x2f0478eb, + 0x05cfd715, 0xc2e69c99, 0x6e41d534, 0x7f73ea90, 0x127b5afc, 0x97ac1adc, 0xaa85a8f0, 0xd0262f22, 0xdbacc929, + 0x092c8b8b, 0xcbd26a25, 0xae13a3aa, 0x047421a1, 0x8668c77f, 0x9f42bf0a, 0x90bfe512, 0x14620b3d, 0xcecd1b5d, + 0x17c728d5, 0x85e132b0, 0x3102a3c3, 0x1159101b, 0x419d456a, 0x2b07f225, 0x2e995572, 0x90ad2883, 0x86ab2241, + 0x2461507c, 0xb1b41a10, 0x74cbea9e, 0x4310249e, 0xe0bc5f6b, 0x571ee001, 0x8fd118c6, 0xc97db10c, 0x6feb345b, + 0x7db5d8e8, 0x13fe944f, 0x338555c3, 0xd1c68e5c, 0x44fbcc0c, 0x39c26ebd, 0x23bc5909, 0x5b6b2a3b, 0xa31b492d, + 0x26643a61, 0xeac88e5e, 0x1c87072a, 0x96acd861, 0x9bfbd9d8, 0xf84f54de, 0x9bda8246, 0x316b1eba, 0xe1a8c8f3, + 0xf8e6b3af, 0x35ce4a21, 0x98cb3c57, 0x4b0788b9, 0xf426cb0e, 0x3a9e50e2, 0x0c690326, 0x2656816e, 0xf1816e70, + 0xcf36018f, 0x5f049676, 0x56a33907, 0x1360e883, 0x7eb4817b, 0x5254d2af, 0xb93484e3, 0x7bba5c6e, 0xdfefa8c7, + 0xc4d16df3, 0x44cb7e37, 0xc1961e91, 0x2c2b6357, 0x753afd01, 0xa4be9b54, 0xe12520e4, 0xfa61534b, 0xd709f216, + 0x901c26dd, 0x1a366401, 0xd93c282e, 0x1f2489b0, 0xc53dde0d, 0xa14ebe57, 0x4207d17e, 0x67571e16, 0xeee8f011, + 0x7fce975f, 0x71685ccb, 0xc8c83645, 0xb772c6e5, 0xcd6f1f53, 0x3edf05d7, 0x618ecd4f, 0xe5136990, 0x70d61732, + 0x3840d928, 0x0b5da379, 0xf426ca82, 0xe59530ae, 0x9948a465, 0xbb5c17df, 0x6ee41f28, 0xd9970e4c, 0x3d30c496, + 0x28ddc755, 0x20ed5e71, 0x1fb6ed7e, 0x04bd7f8a, 0x1d8c65aa, 0xc725ff83, 0xe4cd7ed9, 0xf9e3a655, 0x046fe9e5, + 0x00765168, 0x035d7753, 0x77594e02, 0x6f6d1d74, 0xc19240d8, 0x4ca0d30a, 0xc6b2af76, 0x1b676857, 0x0b1011ec, + 0xb6745e16, 0x291c851e, 0xea8b984e, 0x29e900de, 0x7605ad1f, 0x9115be07, 0x18c918e5, 0x3986c292, 0x210d9c53, + 0x7773a503, 0x02e37fb6, 0xbcd3cc49, 0xa4e4961b, 0xc4f7ba04, 0x880a16d7, 0xb5b6cbe2, 0x8364d607, 0xe07d2992, + 0xd2bd3ad3, 0x315e034f, 0xe51423cf, 0xf2276d77, 0x20344448, 0x5ba60ccc, 0x196c16e8, 0x8ff7c3ed, 0x9a115fe3, + 0x2b00a514, 0x87d7ea76, 0x7c3bf5a5, 0x59741852, 0x64e3d8a8, 0xe0e0887b, 0xa12804a4, 0xd3e64f0e, 0x242070af, + 0xf17931db, 0x841fd921, 0x0032edc9, 0x6966ceb2, 0x5668967a, 0x88a8e4e0, 0x9885e697, 0x2065e8cd, 0xdd836623, + 0xb95e98d5, 0xec808a96, 0x1a1adce5, 0x10d39fdf, 0x0706e50a, 0x741677db, 0x7e14def8, 0xebd2c80f, 0xd46e63d7, + 0x5025fd65, 0xf47012f5, 0x46d31514, 0x5ddf153c, 0x4c04a54f, 0xd2461368, 0x8f00279b, 0x5776c014, 0x5b5e451f, + 0x4532f0d3, 0x9df38fad, 0xa80c6ea1, 0x78ccb6c6, 0x213d8fba, 0x73a6a44a, 0xfeb4c241, 0x83718a04, 0x0969ea6a, + 0x8ddf0b53, 0x6d1646ae, 0x2441557b, 0x0526d9c8, 0x611c933d, 0x349e3718, 0x0c3a1467, 0x644177f6, 0x4de36ab1, + 0xbe0f2ab5, 0xea76f6bd, 0xe12822e8, 0x34587de8, 0xf9f7dcca, 0xe3e5b12a, 0xfb1abe73, 0x26476974, 0x4eb4b7da, + 0xc9959201, 0x8186e33a, 0x7e0805d0, 0x87143257, 0x4113b80a, 0xc36b4ba0, 0xaa0db600, 0x06d6da30, 0x4fae7237, + 0x561682fa, 0x9951f8ca, 0x04e731e8, 0x87e7fb03, 0xc9998e79, 0x19ebecd4, 0xf94309a3, 0x72515c76, 0x1eb97642, + 0x9a6d0009, 0x7b4d88a6, 0x09465016, 0x4dc1f9f7, 0xc266de54, 0xb5d812db, 0xb16a7c0b, 0x25f9fdda, 0x540d06f6, + 0x6b2673f4, 0xea8f4c1d, 0x69b51d52, 0x573258cc, 0x38cc9195, 0x104663bd, 0xcbc49b5d, 0xe1cf89b3, 0x64293af8, + 0xd2b0553a, 0xe4141988, 0x83bb2819, 0x1bbb92d8, 0xc798ab66, 0x3f91f5d5, 0xb4aebba3, 0x30e91dd1, 0xff86844a, + 0x40ab779c, 0x0e2c1a73, 0x488c7cd1, 0x765dbbef, 0xc8b965f4, 0xc64e0438, 0xe980a7bd, 0x4f11d97c, 0x003267a6, + 0x0f21aca4, 0x3658119f, 0x593d54a1, 0x8f84e9e7, 0xed32b3b9, 0x7c7ab363, 0xc7e8e629, 0x723c3c94, 0xb2a37864, + 0x0260eb5a, 0xa1b12d94, 0x07f6b43b, 0x79890a65, 0x7b9199f9, 0x1b286f76, 0xaf07fef7, 0xbf572eab, 0xc3dff870, + 0xc1ffd755, 0xf3cfc430, 0x04f1b908, 0x4ac1b6c9, 0x9d1b4083, 0x12221047, 0xf0189a85, 0xbf4099b9, 0xb666be04, + 0x2f49788b, 0xb84fcf4d, 0x9c5dd38d, 0x161374f7, 0x5a4540fe, 0xa0f14343, 0xf2e7acf2, 0xed254322, 0x03d49e31, + 0x6f7c2fa0, 0x98ca44a8, 0x7d3cded2, 0x0ef7e286, 0xc5c9c50c, 0xe14cf505, 0xf5732392, 0x9906a720, 0x96f19152, + 0x5b00610d, 0x61ea4c41, 0xba5fe4c8, 0x9cb301d5, 0x03e96c6d, 0xeb731be4, 0xd0fc4288, 0xbfa3ecfe, 0x57be9fe0, + 0x92df1dd0, 0x7bbba605, 0x49e876cc, 0xcd47f7cd, 0x6e961eb7, 0x279233a9, 0xda6391a4, 0x4f0b9014, 0xd91cba0a, + 0x47374efb, 0x6bf9f70d, 0x0fc98d96, 0xd4bfc18c, 0xd260988c, 0xa5909238, 0xbc2ab045, 0x3a66940c, 0x9bb88fb6, + 0xb6b83b83, 0x1ad3bfd3, 0x2f50b18b, 0x34e0bcbc, 0x82e4674b, 0xfe6bd68a, 0x220dcb8c, 0xe3e69f1a, 0x19015446, + 0xf9be2570, 0x2044edc6, 0xb2a84ae6, 0x784fa436, 0x53ebec58, 0xfc777497, 0x0021fa6a, 0xb20ceb12, 0xa5dda059, + 0x26b67462, 0x8428c177, 0xf895518a, 0xbf85c9e1, 0xae4c54ed, 0xac6fd944, 0x809a9342, 0x1f75637b, 0xc00e7986, + 0x208697ff, 0x0b92ba0b, 0x9236cd21, 0x849132e0, 0xd32a83a7, 0x84cdb8f2, 0xcc349107, 0x08a3db72, 0x063b788d, + 0x8bb81b52, 0x62a01576, 0x0f73b24f, 0xdfefa406, 0x165af3ff, 0x0ba3cd6b, 0x340b8f33, 0x1a9470f4, 0xc8738f35, + 0x1d900fad, 0x4a24678c, 0x0ae5e6dc, 0x5d655c04, 0xc9de74d6, 0x57000766, 0x084e05bb, 0x554c8753, 0xd6e1a736, + 0xf14562c7, 0x03ebe549, 0x1c3f71d6, 0x16880de0, 0xeebbe74a, 0xbd8da759, 0x6f54ff4c, 0xc5a3005f, 0x57dfcc59, + 0x54776766, 0xd9334141, 0x7ddf2af5, 0x52f6694a, 0x85971dc1, 0x60fcf820, 0xecce6764, 0xcc36f8c3, 0x9d9fbd7c, + 0xa5d582fc, 0x549f3915, 0x607cc28c, 0x8b98da4c, 0x52f41e0d, 0xcb121e2d, 0xa2b15d88, 0x8e4459a7, 0xca6323c4, + 0xbeb0e6f3, 0x1162347f, 0x503b224a, 0x38891a75, 0xe855b9a4, 0x21ca5714, 0x2d828e8e, 0x74ecc0a3, 0x5dcda61e, + 0x36d5c294, 0xce4bf8cf, 0x0bf67243, 0xce02424a, 0x7258c588, 0xe43d6146, 0x54aee549, 0x559e8369, 0xa188d5a9, + 0x625f3092, 0x40a4184c, 0x4924a10e, 0x0bc2dbc2, 0xe2389789, 0x9f8cd528, 0x6c4f2667, 0x05773244, 0x19fa0b0e, + 0x85d659d1, 0x2708dffe, 0xaf438494, 0x3543938e, 0x48c6daba, 0x3c58b996, 0x977c7ce0, 0x656438ee, 0x05452131, + 0x7b6e6118, 0x86a5f16c, 0x1a4e983c, 0x57119064, 0xaba58204, 0xcbae9f81, 0xb36f1fc6, 0x5221ec90, 0x5fbe5a27, + 0x54be037e, 0xbed68fd4, 0xe6927aa7, 0x41cf44a6, 0x0c7c6255, 0x9e8ed736, 0x50fae29c, 0x3ce2ff05, 0xd7264633, + 0x588c42fa, 0x773b2621, 0xce13acad, 0x04fd79cd, 0x821a6c94, 0xcab79c02, 0x5fe0c4f4, 0x4f5b91b5, 0x027ad6b3, + 0xf59f357a, 0xe79de129, 0x61b48228, 0xcf22fcc3, 0x5b003f46, 0x4d93bc51, 0xe9abf9bd, 0x5299ed1b, 0xe4bf4f20, + 0x6d78e47d, 0xdcd0fc7b, 0xed0db979, 0x86e9ad41, 0x55aa9dc0, 0xeeb37551, 0x66628108, 0xaaf7602f, 0x3572d535, + 0x81e49daf, 0x638b0f2f, 0xccce635f, 0x70b05a5b, 0xdd72eedc, 0x1e6f0f10, 0x5e8cdec8, 0xfac11815, 0x32038a58, + 0x982a8f0b, 0x083e5843, 0x88277c40, 0x2f38bd61, 0x55bdb856, 0x81b20c3d, 0x2bbbb07d, 0xe6fd8637, 0x8facf235, + 0xb64ee174, 0x1a661ebe, 0x090aeee4, 0x74aefdb5, 0xa41d8371, 0x14bd54e6, 0xfc144e25, 0x50834e85, 0x22485197, + 0x5d4fd32b, 0x5eccf4f6, 0x861bb07f, 0x680ceb3d, 0x035ededd, 0xd6469d35, 0xfbb2fa28, 0xbb70ea98, 0x191f2981, + 0x124956e0, 0xbf209606, 0xfd6468d6, 0x2deb2958, 0xa846bf40, 0xb056e546, 0xe0a06829, 0xbfba7d1e, 0x839c9b44, + 0xf14e5fd0, 0x64448473, 0xde6f3142, 0x6c142675, 0x3d660973, 0x74227d60, 0xc5f56a8d, 0x53ea7b3b, 0x8b84d505, + 0xbc3636a6, 0x5a10162e, 0xdc3c7ba9, 0x6dbc53a7, 0x22e3af52, 0xfec9eeb4, 0x14695a31, 0xe1f94d4d, 0x5e8b26d7, + 0xce5a48bf, 0x413aa770, 0xc0816da3, 0xa9e9d887, 0x4caf89a9, 0x6b29a615, 0xb413029c, 0x95943ffa, 0x23e6c3ae, + 0x1d07bdd4, 0x1b08ec87, 0x247af152, 0xee1df6b8, 0xa10ef827, 0xccbe9688, 0x3b87a10d, 0x6981f0ca, 0x15195ab8, + 0x7e187f8e, 0xc5679b82, 0x3f6011f4, 0x3477209e, 0x2c00fde6, 0x64499ea7, 0xaf110f91, 0x8dcbdad3, 0xd2319109, + 0x0de682e0, 0x8c4232ca, 0x9c960601, 0x9994276c, 0xa7ac4cba, 0x31e2c0d3, 0x83e5f192, 0x157c950b, 0x083472af, + 0x58ad1d52, 0x96d6bf54, 0x03a6198b, 0x644fccd6, 0x8dc80bca, 0xe18d836f, 0x1f1d1bb6, 0xbf78c84b, 0x9865ea5d, + 0x11495cd8, 0xae147f36, 0xe62cbe53, 0x88af880c, 0x9ef66c14, 0x6a029b94, 0x8492cf33, 0x28bed103, 0x98f6343c, + 0x3ef6d56e, 0x5f624d8e, 0x38fb1bb0, 0x5444a26f, 0x49822483, 0x68c92315, 0x093d6115, 0x6e7fac07, 0xfd2076ca, + 0x8c5966db, 0xe5efb061, 0xe521b7c2, 0x7c29c63b, 0xe7a91c58, 0x8add745b, 0x75cae5af, 0x80070e04, 0x6db51c7e, + 0x620c57f7, 0x03badb5b, 0x39962460, 0x72378dfb, 0xe81d028e, 0xbcef585f, 0x0c74f539, 0x50b10a6c, 0x6e8a307f, + 0x098e6cb0, 0x0927c8cb, 0xacc7e3a8, 0xd1362f8d, 0xe7053ec7, 0xfaf67137, 0xdc6b1738, 0xe5acd45e, 0xe28c719e, + 0xa9ce7f85, 0xc4aa2928, 0xb9191959, 0x28f61d3c, 0x9b3d03d0, 0xd8d32173, 0x7809e4a1, 0x137525bc, 0x4c0af4dd, + 0xe5ba2acc, 0x89c105fd, 0x7d2db4e4, 0xb01d90b8, 0x2b745375, 0xde920bc0, 0x3c9a5936, 0x035c7177, 0xb440df97, + 0x108baef2, 0xf10b3bd4, 0x63b6e105, 0x7f8e96d5, 0xdd33f895, 0x27d6a135, 0x1ef1423c, 0x2fbf17cf, 0xfc62158d, + 0x5d76bdca, 0x5be12c53, 0x9c520207, 0x13e97255, 0xe660d4f2, 0x039bf5ee, 0x4f91eb02, 0xfb2fecc3, 0x9c7b6763, + 0x4fcdca56, 0xce01b573, 0xa87a09bb, 0x625dfc00, 0x7776025c, 0x6ba3ed7c, 0xb16ef7f8, 0x02b8b092, 0xb6c04f9d, + 0x2ba1f973, 0x73dc1616, 0x8e0a6b7a, 0x6993e66a, 0xc75a852a, 0x3bad57d0, 0xfd4491bd, 0x55a8946b, 0x0fce318f, + 0xd47e82a0, 0x414a0bca, 0xdc06d9da, 0x71b0d20b, 0x33cf3e83, 0x40f8a467, 0xc106ff68, 0xf95e4c29, 0xc1cd39a5, + 0x4130a8f5, 0xadd17960, 0x5b976d0c, 0x98b540a4, 0x4d6e8042, 0x52979001, 0xceee78cc, 0x1a7fcb6b, 0xf60015f2, + 0x4579c26a, 0xcb153709, 0x2bdb35a1, 0xf276ad2e, 0x12454820, 0x199a5de4, 0xeefc2c37, 0x46454fbe, 0x3346b9e6, + 0x8da975ae, 0x4665b94f, 0x0ff38fec, 0xb41462ab, 0x68ed1bb9, 0x0313f51c, 0x83d56b11, 0xb4c449dc, 0xcc026ae9, + 0xb7ad28fb, 0xd330df8a, 0xcd41ae39, 0xec8ab450, 0xef100bca, 0xcea9ed5a, 0xce262488, 0x373c9e21, 0x4cb6ec36, + 0x8310e3bc, 0x12745b4f, 0x3c5aa756, 0x9bccf6f9, 0xea76e733, 0x1baa9c6b, 0xad43bf73, 0xbe837c1f, 0x7de13944, + 0xfc19295e, 0xefc3232b, 0x19f3cf7c, 0xa9122ca2, 0xa1fa776c, 0x023b4898, 0xb95f75e5, 0x6f55cc54, 0x1bb0e1f4, + 0x425d5ad5, 0x0bcb9f16, 0x3143a494, 0xe01ff6a4, 0x82c2f47e, 0x95c5482d, 0xaffbfe19, 0x59efb9f2, 0x0d1b1674, + 0x08bdd339, 0xd1de1068, 0x9a1156ed, 0xf8fb321e, 0xf17c6ae6, 0xfeee3241, 0xb7b06f59, 0xd8217ac3, 0x9cd6a77c, + 0xb63c30a3, 0x620c1856, 0xb7b55000, 0xdc4a75fa, 0x4a5bb15c, 0xc0647295, 0x9aa5d0f0, 0x8e304c43, 0xcb829a5f, + 0x1b8be4d0, 0xdd359d3f, 0x87ba065f, 0xa0f23e39, 0xb4bf28e6, 0xc7148f76, 0x568f6d43, 0x9a0df59a, 0x18919caf, + 0xac3296c3, 0x38b3fea4, 0x4640aa76, 0x3f76edc4, 0xafb86a92, 0x61f0edab, 0xd304cd32, 0xa7d35622, 0xe4703ca4, + 0xf6ff5c8d, 0x387e85f0, 0x586bbb2a, 0x7d11710d, 0xda46f993, 0xd9676030, 0xb4acf8fb, 0x734d48f0, 0xcafaf824, + 0xb70b0f8b, 0x9be79cfd, 0xcc627728, 0xc78c6d92, 0xf61679cb, 0x9eaa3950, 0x5ef09d8d, 0xe334c441, 0x500a85e2, + 0xde131f79, 0xcf64719a, 0x3935b0d6, 0xe939436d, 0x8d29c728, 0x0da9eb1b, 0x0451ce78, 0x42772a7d, 0xfd6de32a, + 0xc0273294, 0x7a4a1e48, 0xaa67b26d, 0xeeefa9bc, 0xc36b25f9, 0x6e343d1f, 0xfb2e0a79, 0x7c7e3454, 0xa5fd8a1d, + 0x612f46e9, 0x061dd8f7, 0xa3b5e967, 0xe85f9136, 0xd3223d28, 0xc9582d0f, 0xe8d1e974, 0x5fd3a8bc, 0x887f4419, + 0x8ec3c7c9, 0xac1b39af, 0x5c64bde6, 0xf4f1773d, 0xd7b11c8a, 0x793e4c9e, 0x00063fed, 0xc228b670, 0xc15fae13, + 0x9287092d, 0x32bd3bd8, 0xb6e5cfdc, 0x5b013ae1, 0xf5f95843, 0x928a744f, 0x37131bd8, 0xc195cc3b, 0xcd2ca178, + 0x77333d56, 0xc3f1a3c3, 0xcf4336d5, 0x10ec0979, 0xf3f8e636, 0x1f472d5c, 0xf6b3b6b4, 0x9040adb6, 0x513c674f, + 0x508637ba, 0x3433c9ca, 0x2396be5b, 0xc5ff606c, 0x356fd845, 0xd843bbbd, 0xd687e446, 0xbdbdfc24, 0xdab1faf0, + 0x7eba1369, 0xebee972f, 0x462f613e, 0x1bd1d27d, 0xb2924eb4, 0xcf87f5a3, 0xaa56ab72, 0xd6c0be25, 0x3f736218, + 0xdb194ff6, 0x68411c87, 0xe1499dab, 0x296da464, 0xf0371a1c, 0xa1a475bc, 0xbb866f11, 0xf62834cb, 0x917aedda, + 0x56976d6c, 0xc3bdb3c2, 0x1be3a771, 0x542b0949, 0xc3b6b688, 0x13a6d2e4, 0x273d9ee1, 0x2d551abc, 0xfe5ecf47, + 0xcdb8419b, 0xbaae19ff, 0x45ccd3ac, 0x8434263b, 0x91c83a73, 0x90fde69f, 0x6270df02, 0xee9010b6, 0xee615521, + 0xce302aa7, 0xcdbbe813, 0x6dfdde67, 0xf5498074, 0x0ccc7d5b, 0xf4815ae4, 0xc3b4f6c4, 0x65b2a940, 0x231bac55, + 0xb93a115f, 0x65c437d1, 0xeb1a5791, 0x3af25577, 0x1ccf154d, 0xae03974f, 0xd1664053, 0x756053f8, 0x1f1bee0e, + 0x04ecee3f, 0xc0cf5a47, 0x4a34bcf1, 0x2777d7de, 0x1197b571, 0xa5e6ec08, 0x7a709689, 0x7bfe5865, 0x5446292d, + 0xa64e59c5, 0x45a4963f, 0xb55eaa87, 0x8c5f87a0, 0xaae647c0, 0x996a2ad8, 0x1a47929a, 0xd7134a1f, 0x66077eb8, + 0x64e5b498, 0xd3d91a29, 0x5bb16c94, 0x89fedc2d, 0xdf825c2c, 0xefbde310, 0x1bd55839, 0xc14868e5, 0xbd54a4f3, + 0xc1d3f713, 0x65712e5b, 0x7e575d45, 0xe89af253, 0x37b35e11, 0x3ff8c05f, 0x24ebd98a, 0xa9d92842, 0xdfe921a5, + 0x7299dcb7, 0x78136baf, 0xbf37cbf5, 0x654e2996, 0x61a7bd2f, 0xbecc81db, 0xdc9e8bd9, 0xc269813c, 0x2b7f2fa5, + 0x36ced51d, 0xc7b30000, 0x518fbdf9, 0x7c04f6fc, 0x95d88115, 0x7f294b1d, 0xc189f805, 0x7fa239e3, 0x8b6ba28a, + 0x87d3c15e, 0x11c64434, 0xb4934568, 0x66af3899, 0x0b1d0467, 0xc464765a, 0xb68704b9, 0xb49db990, 0xb67606a0, + 0x50357a67, 0xa6d7ad21, 0x94d19dc9, 0x8a3c9515, 0xcf7be7ff, 0x3bab154c, 0x3696b971, 0xa780d9bc, 0xd95bbfdb, + 0xa91220c7, 0x34590598, 0x676d629a, 0x3e6dd591, 0xa529b3cd, 0x84ee5257, 0x13c8068b, 0x4ee871e0, 0x4651a246, + 0x0ed04156, 0x65a99a49, 0x20765bcb, 0xa19bb12d, 0x03eafb95, 0x3e7c6532, 0x8ffc7c70, 0x2314fdaf, 0x41a3b1f0, + 0x76b2d3d9, 0x0ebe30d2, 0xa57736db, 0x051c625b, 0xe1be7c38, 0x102e03f9, 0x9cdfe1e9, 0x2123ff6a, 0x8cada030, + 0xf44970bc, 0x1c37b5db, 0xc9835e05, 0xb7ba0b37, 0x58cd055a, 0xf9fdb50c, 0xf4099522, 0xf452985a, 0x7c2adddc, + 0x65f8a106, 0x68013028, 0x774f87e9, 0xf22b1935, 0xf881fcd2, 0x1166c2c8, 0x37cff7fc, 0x6b448620, 0x9ced30f4, + 0x55618e19, 0x50304672, 0xded1797b, 0x70dde0d2, 0xb63bd763, 0x39b60fa0, 0x1d8d9730, 0x6f7965ad, 0x3d9f0597, + 0x20dc5058, 0x491a22c5, 0xbe0fc08a, 0x778e67ec, 0x51fab6f2, 0x89723584, 0x2ef2ef68, 0x14eb48d6, 0x619e61b6, + 0xf763b873, 0x8de98bbf, 0x6407c06c, 0x3460198a, 0x9cf93cf6, 0xf4da1f27, 0x9cf9f534, 0xd5a62aa1, 0x5967187d, + 0xab6aaf3f, 0x4df419f4, 0x822db070, 0x0ce84024, 0x97b8b604, 0x005b5741, 0xa94c0f9e, 0x50d24da5, 0x7d2bd080, + 0xd34188db, 0x756568f6, 0xd2ee2111, 0xac6f18ff, 0xdc4efb1c, 0x60edc12d, 0x981a0684, 0x1f2781f3, 0x98271318, + 0x30f2f409, 0x7abda07e, 0x0c21d70c, 0x54d74b7e, 0x5ed1aecb, 0x68c9fcd6, 0xd730c736, 0xa9965ed9, 0x122529ff, + 0x5dd7c813, 0xf340f24b, 0x474c73f7, 0x8b67472c, 0x5e12771d, 0xbbf2c9e2, 0xe06c57a8, 0x1cbf64b2, 0x63731a1c, + 0x0da0bd13, 0x44af65ff, 0x7a5dbc5a, 0x406410d3, 0xba115b13, 0xa7e51c77, 0x5a34ef8e, 0xffc959c4, 0x34ba519c, + 0x10c6e5f1, 0x47bfff15, 0x69b555c9, 0x94322229, 0xba176334, 0x9e895c68, 0x66ac62e1, 0x290bfff6, 0xf8af11c3, + 0x3d8d315f, 0xbac28821, 0x3cdab156, 0xa2346475, 0xb976144c, 0x83f3b59f, 0x082dce9a, 0xaedd6de4, 0xc3e6e0c3, + 0x04a636e5, 0x63c5353c, 0x62ae063f, 0x3d1642c8, 0xb573c8ab, 0xe9421582, 0x53bc1632, 0xcbc2b2bb, 0xa3e36124, + 0x4ccd4688, 0xe1960c2a, 0x2130ae71, 0xc0033a60, 0xbcf3425f, 0x12902db9, 0x0605c547, 0xfcd65611, 0x3959499f, + 0x5dfa4c83, 0x721deb27, 0x0b0d244e, 0x933f6a83, 0x05dbbd3a, 0xb650e6f4, 0x28353782, 0x1245a2d9, 0xcd9c4031, + 0x6137e6ac, 0x6ad350ac, 0x38977ab4, 0xb473c000, 0xe1869097, 0x55ce6753, 0xa2cffee7, 0x5ada0aa8, 0x28b3d48f, + 0xb4092605, 0x03a23b9d, 0x2c1d3f17, 0x18cc38fc, 0x4446f909, 0x0555be51, 0xb1712b74, 0x931cb5d0, 0xb982b448, + 0x13c656a6, 0x32f03995, 0x605e2352, 0xd6b7dd30, 0x8b07ca9e, 0x59299c1d, 0xbfdd2836, 0xe02357d9, 0x6bebc850, + 0x2ae5e31f, 0x72ce0df9, 0x12e7efdc, 0xac9735bc, 0x8b5ac63e, 0x6263982e, 0x567e8be6, 0xf066f3bf, 0x755325e1, + 0x1f806dfa, 0x5d2df0b4, 0x06037ba8, 0x9b1c0fdc, 0x38fd9b0d, 0x2f3c5aa7, 0xc71c683a, 0x5af0b2a3, 0x2536f9b6, + 0xafbf0120, 0x17183e6a, 0xc08f2bf0, 0x26aaaedc, 0x3fd415ea, 0x0d4d3b9d, 0xdaf30e36, 0x0082fa27, 0x495b5b9f, + 0xa47ae3eb, 0x20ea9044, 0x3ab878b8, 0x6290c6fa, 0xd150e6c8, 0x84b360d5, 0x50c144f9, 0x2cfefc97, 0x881fe218, + 0xe0863e5e, 0x3bb915a5, 0x298bdf4b, 0xccfcee85, 0x5f8340b9, 0xc7dd73bf, 0x13953e9d, 0x0bb2531d, 0x8a10efcc, + 0x8f425938, 0xc52d1e7f, 0x8a5cf586, 0x36154225, 0x0ae6664a, 0x6a949717, 0xfcdad514, 0x022b912c, 0x6e5b5b0f, + 0xc0f2b4f1, 0x32304550, 0x32f31ff9, 0x2277e5c2, 0xa14d06b4, 0xe28a25fe, 0x556396ef, 0xee94b750, 0x16d5acf6, + 0xe9a7d1ca, 0x6b432f30, 0x133d6232, 0x4fdbd875, 0x497d6bbc, 0xf0983f94, 0x93add9ac, 0xf1cd9b4b, 0xb871b17f, + 0xfe67acbb, 0xcc6f6ee3, 0xfd831aed, 0x0715db4b, 0x737222b9, 0xfcf8d1fa, 0xf7b6fd16, 0x7370c761, 0xad0c6f37, + 0x65616f49, 0x42406827, 0x808f44aa, 0x64bce8c8, 0x91363826, 0x39cdfeeb, 0x9b51f093, 0x3a6a6953, 0x1c6c6b64, + 0xf1e9e5df, 0x419f132a, 0xd6ce42ac, 0x50b3d97c, 0xa8587a36, 0x97892f6c, 0xfb8fcd04, 0xfda49910, 0x7f07dcc4, + 0x666d6c00, 0xd271e296, 0x75457a9a, 0x40558f1a, 0x02ad5fe8, 0xab50b813, 0x2a38e0ec, 0x171ed8fa, 0xd6ed70ce, + 0x40a77229, 0xc4f37e8d, 0x82deeac7, 0x6b01614f, 0x4b2a2f5d, 0x6fca4bcd, 0x0fba865c, 0x788e1271, 0xc79100a1, + 0xa9ffd994, 0x643c4444, 0xfad81826, 0x385363e3, 0x6de3eae4, 0x2b81601b, 0x7c44d637, 0x9399c7a8, 0x991fee7d, + 0xff947a74, 0xa33b99ac, 0x11b97d98, 0xac05100f, 0x69fad0f9, 0xcf4deeb3, 0xa347e824, 0x130b950b, 0x3b55aaea, + 0xfe9a8ff5, 0xeb25e52a, 0xf3d5dfcf, 0x74df2803, 0xaba67f5a, 0xb507e04a, 0x83330e66, 0xc939270e, 0x70fe0fdd, + 0xa2deced8, 0x3cbf655d, 0x8edfa12b, 0x1be2f76d, 0xaeebb885, 0x9ced0a0e, 0x7d3f8660, 0x770c3e34, 0x8a141150, + 0xfd6765a2, 0x8f5a453e, 0xcdae3056, 0x3354c882, 0x19bf9d13, 0xbbc2a7e9, 0xebebcc73, 0x07130a9d, 0xc2e39c1d, + 0x9c17f666, 0x0be342aa, 0x4cca441f, 0x866635c2, 0x494b09c9, 0xdf4187cd, 0xd080986c, 0xd79987c1, 0x722558dc, + 0x77823958, 0xb28394dc, 0xefd79310, 0x82eb3190, 0xd037ac71, 0x3af89111, 0xfdc9b2a0, 0x9a758f0f, 0xad36189b, + 0xe53ef5d3, 0xf65a5597, 0x44d4132b, 0x7150ca52, 0x1dc65045, 0x5dc350b3, 0xea6c8f8a, 0xdb3cbc7e, 0xd33b5084, + 0x392f7b72, 0x755294c6, 0x59d3fb96, 0x6305f1fb, 0x09d1b5a4, 0xae5268ce, 0x408f62f6, 0x5fff530f, 0xce0894b2, + 0x77868eaa, 0x1fc58d18, 0x0fd5ff97, 0x91a7d19a, 0x9057d3d4, 0xcc67f50c, 0x1799ff22, 0x3eb76335, 0x9f388cfa, + 0xf7dd15ca, 0xea9c39c8, 0x755ef069, 0xa785f15c, 0xc1e8194d, 0x4d8957ad, 0x1d7a2a96, 0x5d8917b3, 0x1bc7a82d, + 0x504f7a75, 0x92b84c4d, 0x82371d85, 0x6ef28ae9, 0xfcc9c59a, 0xdfa1545f, 0xf3f6ec6a, 0x488722f9, 0xee2928b4, + 0x9d17fe6c, 0x41e23bf5, 0x41eb22cb, 0x06c69506, 0x55560e20, 0xab2bf67c, 0x788ad56b, 0xbdd445e0, 0x4f28fd15, + 0xde6b2c70, 0x5c4aa0d0, 0xab2e976f, 0xe42e6813, 0x6c0ea4e6, 0x5cbf4fdc, 0x70722c8e, 0x1a9e912e, 0xf1898021, + 0x644bf7fb, 0xe725e911, 0x2b9341ed, 0x0dd86ff7, 0x53db0b26, 0x09ad289d, 0x675bb59e, 0x8edb9269, 0x593d4251, + 0xc69349e4, 0x5bc015a1, 0x10bc0333, 0x041d0ccd, 0xc258250f, 0x55d66ef0, 0x57176f45, 0xeb63012c, 0x8d8a723a, + 0xec3f431d, 0xb927bfae, 0xfd4399f1, 0x26da2934, 0xb6881f4c, 0x2f1b8c61, 0xdb3a0c4a, 0x7b7bf8a7, 0x92498405, + 0x9ec7bfe9, 0x6a305479, 0xbec51d12, 0xe6c4366f, 0x6f020210, 0x49c3a448, 0x14371a82, 0x583113af, 0x2d5f4a60, + 0x0ebd74ae, 0xaaa04aea, 0xa471ada7, 0xa2280be3, 0x34461346, 0xf4aa249c, 0x1be92c9a, 0x91a981c3, 0xe4068c5c, + 0xb8884071, 0x98a57f15, 0x9147c16f, 0xde46f4c5, 0xc333a740, 0x34c7e7ea, 0x25ca66f8, 0x8bf56b06, 0xf4facdef, + 0xf523196b, 0x9840e88a, 0xd26bc756, 0xc2368c5b, 0xec656629, 0xd12c16cb, 0xb7eaeaa3, 0x88a17000, 0xdf541ce5, + 0xa247c540, 0xa6771fb9, 0x5df3e788, 0xfefb0557, 0x46d0e136, 0xfbe025ba, 0xf055f263, 0x535cc7ec, 0xd0f217fe, + 0xbc063a3a, 0xc5b5c830, 0xaaefa5a6, 0x6fd32c0f, 0x0219ca78, 0xb8a1b286, 0x7281c48e, 0x951a041b, 0x59109b89, + 0x130068a5, 0xfcffe7c3, 0x8d535b09, 0x15d9a9db, 0x22f02778, 0x57f38ea3, 0x950dfad2, 0x033063c2, 0xeaa588c6, + 0xc1062cdc, 0x9771efe9, 0x5aac5c9b, 0x602f1070, 0xc73e78ce, 0xc926ff02, 0x46a85aba, 0xd0ba704d, 0x530338f7, + 0x24179c54, 0xcd80ef7a, 0x74baa396, 0xb17b9c1e, 0x1fbaad2c, 0x85ba2cd3, 0x378a86a7, 0xf4bfdde4, 0x567192e0, + 0xa39e2a7b, 0xa9c5c69a, 0xf4ed2d38, 0xaf689384, 0x51ad92e4, 0x860418d0, 0xc0c0d4bf, 0xc0afe19b, 0xaa26fe5e, + 0x1326da58, 0x562ceb94, 0x207c8260, 0x78a4258e, 0x35da0cd3, 0xf9e94833, 0x9ec6f6f5, 0x390ea8e8, 0x0d04a474, + 0x12f3de34, 0x885c0243, 0x050c9e46, 0xdff0323b, 0x3617646f, 0xdbc3a288, 0x6905f3ca, 0x9bef1022, 0xc2b81c14, + 0x1005eaf1, 0xf3dec340, 0x060d694b, 0x936ae875, 0xff39f7f1, 0xe7146f6b, 0x8a7934d1, 0x526a1632, 0xe75a85ab, + 0x2a464a4c, 0x4cf13e7b, 0x676cb179, 0x44957589, 0xb18d3c44, 0x973f1f58, 0xa6a435cf, 0x384c63e3, 0x44465b29, + 0xaabe3964, 0x9e885e9d, 0xe21a6bd1, 0xd3851300, 0x1aa6eb2a, 0x022bcc24, 0x07ca3700, 0xe8ec51f1, 0x3c85209c, + 0x1cba9961, 0xf49d4383, 0x58d7a05e, 0x52570100, 0xa44273f0, 0x5526fcae, 0xa4c31750, 0x9bef83e2, 0x0013db31, + 0xb6d7f55f, 0x3fdf342b, 0x583b96ff, 0x86e48275, 0x30931925, 0x760e4c01, 0x6acdf83c, 0x90f0bdbd, 0x34973570, + 0x323708c5, 0x5bcc1c84, 0xb28a2abc, 0xe6d62863, 0x653b5f73, 0xda5ae0f2, 0xf52cae30, 0xbaa6a7eb, 0xc273c961, + 0xb463650f, 0x327e0655, 0xb25f6e90, 0x263640bc, 0x41d366ab, 0x6cf53427, 0xd3056bdd, 0x1d2bd095, 0xc9e7146c, + 0xc391f1cb, 0x515d5c46, 0x3f16ada0, 0x1836e812, 0x7f2aba61, 0xee7d9ac2, 0x8dec9594, 0xb54aba9d, 0x1fe6f7e1, + 0xc38f4576, 0x06c17a15, 0xd3557601, 0xafd82b2f, 0xac62c2ea, 0xb8c98b93, 0xf6319a82, 0x1995648d, 0xf89ef2ef, + 0xc300b8be, 0xa9b5978a, 0x14a1dded, 0x7d60071e, 0x9756ddd4, 0xa770cc79, 0xc87acc86, 0x8c4492e3, 0x7bf3f966, + 0x4fcac9d9, 0x5e1dde4d, 0xe1cf989a, 0xb61231ed, 0x565e7d1d, 0xf7a21cf4, 0xdf9bd0b3, 0x9420543a, 0x33a60ae7, + 0x57a567cd, 0x35a9ba3b, 0xf711d73b, 0x388d3c77, 0x28fbe9d7, 0xc49e0b44, 0x4eb321cf, 0x21933c7b, 0x30391aa6, + 0xbc572a5f, 0x1147c2aa, 0x11c28c33, 0x40f58686, 0x64d891e1, 0x654519a8, 0x41e81139, 0xc4ed78ab, 0x9ba90b76, + 0x5e58ee4f, 0x5f0fa446, 0x79130fe2, 0x94513c4b, 0xdcc2b213, 0x7821610f, 0xb4ede021, 0xab2d271b, 0x7192dce4, + 0x02bdb53a, 0xc5812ee6, 0xdeb4b3ef, 0xd50a31b3, 0x18c336dd, 0x93d6cfb8, 0xfb360d43, 0x4701f552, 0x0566f3ef, + 0xacc3e484, 0x60a6436d, 0xe830f3fd, 0x776862ac, 0x746674bb, 0x508d6792, 0x75f34f09, 0xecae26af, 0x19417d33, + 0x8092ef98, 0x3e474fac, 0xe55525bf, 0x9f7e5119, 0xbe992e68, 0x19e162b6, 0x4093773c, 0xf2e597a9, 0x3843c69c, + 0x2b26acf9, 0xf2fc098d, 0xfcb880b9, 0xc0e199d6, 0x48963014, 0x236fb67b, 0xd3b56983, 0x537c8fbe, 0xca98878a, + 0xbd698e5e, 0xe8c4d3fc, 0x5d2b1456, 0xeb544c53, 0xf4080995, 0xfa4b04e2, 0xb77e887e, 0x8d733695, 0x81e69aa8, + 0xd1afccfb, 0x251606e8, 0x71906a99, 0x60b3045a, 0x80bef68c, 0xa95da2f9, 0xd5503cbe, 0x9766c4ec, 0x82000976, + 0x2e5bdd5b, 0x92c96649, 0x7027d627, 0xcdb23297, 0xc6a5a3c7, 0x2aa13537, 0xbf04af21, 0xcb2bbd03, 0x03f13d17, + 0xaf74037c, 0xb595aa91, 0x779ad059, 0xa240ac7a, 0x0f27976f, 0xbd71bf07, 0x48d3017f, 0xd8560b6c, 0x13e2e329, + 0x5a2c697d, 0x5cb29638, 0x03ed0a94, 0x6167a622, 0xcb473333, 0x3919326a, 0x2c98623e, 0x3d244caf, 0x90d51bb6, + 0xeb11fed2, 0x875a7f5b, 0x74dde759, 0xd91d010e, 0xfd5955bd, 0x0ce1469a, 0xc808bbb6, 0x487d70e0, 0x5bbb7df7, + 0x200ebc8c, 0xbcde0e15, 0xfbd36925, 0x1cf08121, 0xa166fb88, 0xb0340add, 0xe90caf5f, 0x4f62f569, 0xa74deabc, + 0xfab19309, 0xe8f55a17, 0xc8acf3d6, 0x0820d55b, 0x11c2e01e, 0xbccf9aec, 0xe3ba07f1, 0x7e4c9663, 0x4e9b7a3e, + 0x9aa1dc50, 0x8cf79a8f, 0x73f99544, 0x34fc1bea, 0x48c97f7c, 0x43b4ed80, 0xca8ed092, 0x5f7c7ee2, 0xa231fb6a, + 0x5456022b, 0xd17985cc, 0xc1faf969, 0x8e25259e, 0x61cdae41, 0x8a546afd, 0x4c1df59a, 0x401781b1, 0xf42ab986, + 0x15668ab3, 0x14d69d99, 0x629eab5f, 0x4694be9b, 0x223a58de, 0xc72eb31a, 0x1c7785ab, 0x00e005e8, 0xc58fd8fe, + 0x385682e1, 0x4cdbfca9, 0x4d15c153, 0xa6643e9e, 0xdfb66ff1, 0x81ea7be9, 0x095adc28, 0x86bbbd91, 0x67159085, + 0x8bef051c, 0xa34a545e, 0x05322a0b, 0x4020a034, 0xb9f3fbde, 0xa8e6c546, 0x1b31e8ef, 0xd52c4985, 0x70cca50c, + 0xe7b67ac0, 0xb1794f9d, 0x7bcb8068, 0xc6b40e38, 0xfcf78710, 0x54d75dfd, 0xb1890930, 0xaa8670bd, 0x574a045f, + 0x63a7ea3a, 0x3d1518da, 0x45afde93, 0x2fb4c044, 0x1caf761f, 0x3cd3a7c0, 0xcb88dc19, 0x5e279a67, 0xba130bca, + 0x59084bd5, 0x7dedbc85, 0xdab1c6b3, 0x515bb239, 0xc2ad0ebf, 0x25d4f95f, 0xca11cf21, 0x69d00805, 0x703d4885, + 0x4ac4009c, 0xf397e834, 0xb63549c2, 0x626759bc, 0x3c1e4ea1, 0x35957b94, 0x102a60e5, 0x2e9aa040, 0x05a51a9c, + 0x50229d0d, 0x6409d3b8, 0x1d63866f, 0x52ead6c5, 0x293ee7e4, 0xb6c057ad, 0xac549bed, 0x86dc2599, 0xa287d3ca, + 0xb9ad8d51, 0xffa79d02, 0x6e581933, 0xfd3f0246, 0xc9397668, 0x6a04d8fe, 0xe98e45f6, 0xc1e131ff, 0xcbdb305a, + 0x21477e8e, 0x9bdb6321, 0x79087b02, 0x2078a68c, 0x2612e70e, 0xacdba456, 0xead37fe3, 0xb75e0d8a, 0x84f83a11, + 0xf0160485, 0xe22f0afa, 0xc13c010d, 0x88e5a4c2, 0xdca681f8, 0x41accd1c, 0xe9677aa0, 0x2207b753, 0x616e50d8, + 0xba4a59e0, 0x0609bd0f, 0x0e66caf4, 0x9cd5f178, 0x1b26f8a5, 0x8aea926b, 0x7b7f6792, 0x92bb6214, 0x0e1e7e5a, + 0x9c451bcc, 0xa7e2d743, 0x86f9f5cf, 0xbcb1e9b8, 0xfc882026, 0xe6516a5a, 0x6ea03613, 0xae0d4eb7, 0xdd15d198, + 0x7013f8f5, 0x360700ec, 0xd1498b10, 0xbd97cc78, 0x0cd4ede3, 0x51e5a4d1, 0xecadf8c5, 0x68388611, 0xd57e1235, + 0x24b03c4e, 0x11193a7f, 0x663b4a90, 0x70388d21, 0x1858aed5, 0x3b6be8e0, 0x6cb5bf16, 0x3a6f7173, 0xb67c63f5, + 0x7cf1ef49, 0x6b06d745, 0x7ca928a2, 0x40fd9192, 0xdcd3e1a9, 0x6e151d24, 0x6f3c3e5c, 0x03ef9902, 0x9c7727f7, + 0xd93fc249, 0xe8bdf6ad, 0x50f72d5f, 0x637dd8e8, 0xd846e5eb, 0xe8c2a869, 0x5e79fba6, 0xd608be92, 0x5adffeec, + 0x2f4951bc, 0xae075b13, 0x4566104f, 0x0974a7b8, 0xde1afed4, 0x3d7d93df, 0x372c2f20, 0xa72f8cf8, 0xaaeba036, + 0xca9b3d34, 0x18a70bb7, 0x1cb08d0a, 0x15b4ed4f, 0x84db5083, 0x53647566, 0x9945b992, 0xb54b5040, 0x8bf7bb86, + 0xa079b606, 0xb84533e3, 0x9724fb53, 0x4a817481, 0xbcffb793, 0x7a769610, 0x34239243, 0xe7a0d919, 0x15b05480, + 0xeb268268, 0xe5ceabb1, 0x682dcffb, 0x06c6f1a1, 0x2fd2929a, 0xd902625b, 0x13af4600, 0x2f62563a, 0x8abdfdbc, + 0x21fc6ab0, 0x7c7c3269, 0xce8bdba6, 0xc4a8c513, 0xcf08184d, 0xa26460ae, 0xcc02140a, 0xeaefcb72, 0xb66d1e45, + 0x9cc35c4d, 0xb2446a38, 0xdf793960, 0x067f6afb, 0x4f7cf469, 0xc1130daf, 0xc162a7ab, 0x64b73d71, 0x68a37dc3, + 0xcbe0a233, 0x3b1f2b82, 0xaaef1103, 0xf7cdf7d6, 0xe4f5a01f, 0xa7044df6, 0xb0c88497, 0x22461fc2, 0x0a775875, + 0xcaea9687, 0xa875cea4, 0xe4329585, 0x1352a1d3, 0x491ae95a, 0x9953e216, 0x33092c0a, 0xe361bb24, 0x52ffd3c1, + 0x9eba6a77, 0xc587a418, 0x244a2a6b, 0x7218220e, 0xe4678ef1, 0x99294db6, 0x06d05715, 0xf4670b8e, 0x72f3a6bd, + 0xe4c37152, 0x5a3738b7, 0xfe1b9c6d, 0xde98cfeb, 0x77fb97f8, 0x619d6667, 0x5291a054, 0xa77df291, 0xeddc62bc, + 0x90982a24, 0x81be6f4a, 0xf439a9b9, 0x69c2b4d3, 0x9eb5f081, 0x844a9ff1, 0x33fef7a4, 0xbb1c4354, 0x4d0b5138, + 0xe3a7405c, 0x61715c39, 0x06ef180d, 0xebb568f2, 0xeb1d3283, 0xf7582e4c, 0x5db9a4ec, 0x5d6f932f, 0x9f79ff18, + 0x51d31f4a, 0x12f08acf, 0x1b03e6cb, 0xff375081, 0x5fa5f4d0, 0x6d493748, 0x4b965c7d, 0xc30df0cd, 0xfbb1db04, + 0x4200bd90, 0x70d7ceac, 0xb2c7afde, 0x6b58e157, 0xe21d9932, 0xa3c197f9, 0x21e05adc, 0xc7d97e7b, 0xd8cdd5e9, + 0x30414717, 0x54ef015f, 0xb93506e0, 0xb760b2cc, 0x68197f85, 0x72dfa2bc, 0xe9effc7e, 0x984cb383, 0x8d2ba20d, + 0xc1eb5f50, 0x7a3cf61d, 0xd04cb1e6, 0xca737744, 0x0ac243ac, 0xc1ebc786, 0x43b80680, 0x74623583, 0x37a375a1, + 0x5907ab49, 0xde408a71, 0xd3e7f670, 0xf7196eaa, 0x4c10a103, 0xe785530e, 0xf0f74c15, 0xb2893e99, 0x79be08af, + 0xfe1775b0, 0x14adc9cd, 0x61ca0eca, 0x895627b2, 0xd505328c, 0x1b6c60ad, 0x082d7d58, 0xa030735a, 0x028f7e87, + 0xe3956d46, 0x0c8dc55e, 0x9843048b, 0x483dc4d5, 0xb4b4d027, 0x173aa51a, 0x19f4ef3f, 0xd6e85234, 0x67080679, + 0x2934f464, 0x6c89d71b, 0xe24cc651, 0xb48748d0, 0xaeeb0c96, 0x3eb68b44, 0x9df92255, 0xe3425306, 0x50df5bd7, + 0xdb110efd, 0xc08c9ff7, 0x79d18536, 0x0cb7c95a, 0x31221b19, 0x4770c64c, 0x5afc5f6f, 0x42ecd910, 0x69288058, + 0xc0845fde, 0x0ddba229, 0x306cbc14, 0xf3d4f323, 0x627aef6f, 0xffa70704, 0xb898ac63, 0x589a529d, 0xf5ef3c50, + 0x594f1c82, 0x9f3ee883, 0x98182d07, 0x4c6d07c5, 0x53a8807a, 0xa19bd2ef, 0xe354c84a, 0xa698ea88, 0xe6a70de4, + 0xdbb89e80, 0xb17e6d52, 0xee69fe74, 0x9295b04f, 0xc8c827ec, 0x30e75a44, 0x85a7c2ae, 0xcb79b2a1, 0x25b7163a, + 0x56960f66, 0x25a0db0c, 0xe0caaeca, 0x02380f6d, 0xc409b37f, 0x599a98dd, 0xaa374402, 0xfac6c3f3, 0xf9c58115, + 0xf206a950, 0xfab93c84, 0x20ec6160, 0xedcc5f11, 0xc968b832, 0x0cdc1cc9, 0xf3e6132b, 0x23752843, 0x4a6dccff, + 0x3df4e4b1, 0x07c143ad, 0x774e109c, 0xed5d880f, 0x3cd63d59, 0xdf7c2780, 0x177ae7cd, 0xe4db5938, 0x21ce4c0a, + 0xe77ca6ee, 0x36d1ce3f, 0xfd464877, 0xfb9ae2a0, 0x838e6b74, 0xbab2a1c7, 0x9e81f734, 0xb4a55b94, 0x99abecc0, + 0x57123e13, 0x9c8ca0e7, 0x5d5d3d3d, 0xac083818, 0x19468281, 0x65d5d767, 0xfa12788e, 0x003d1da0, 0x57c959bf, + 0xfee32f90, 0x000e831b, 0x7669ed13, 0x29b2d332, 0x87bee94f, 0xf301fcbf, 0x44a045fe, 0x9931c6a2, 0xa11cc36b, + 0x58830c3d, 0x702bfbee, 0xe5cc68ec, 0x6e9295af, 0xa0073e5a, 0x1bc28a0d, 0x45f8364a, 0xee8b2192, 0x01312fff, + 0xee1c980a, 0x1018f902, 0x5fc4cf55, 0xf07e950a, 0x71162d6a, 0x5b8cbf32, 0xcc1e0be5, 0x30036308, 0x534a09d3, + 0x75fca157, 0x2a5c59d7, 0x7942b6e8, 0xee176fd3, 0x5c0fbe59, 0x2ff264c4, 0x298b39b6, 0xc3108c57, 0x906d2343, + 0xb5e7e191, 0x15a6a42d, 0xf2c891bc, 0xa8ece146, 0x48dc013a, 0xeb6377eb, 0x0742620d, 0xce19f2e5, 0x10a9f80b, + 0xca79fc71, 0x5273d60f, 0x1fec670e, 0x781a7b8e, 0xc2a2b353, 0x45ff8600, 0xbe95417a, 0xecb366e8, 0x0c7a27f2, + 0x39ea39c4, 0x7404f7c0, 0xb9f000a8, 0x97de41e6, 0x191d97d7, 0x47b1c08a, 0x0525cf71, 0x5afbaa3a, 0x4f4164bd, + 0x483f974e, 0xb938dfcc, 0xf176bb94, 0x8664a56e, 0x1cb2da40, 0x3a7aa939, 0xb8313fa8, 0xd5986540, 0x6ce2f80e, + 0x8d091dc6, 0x3f503058, 0x65c35e82, 0xbc95316d, 0x76aeb464, 0x3089bb48, 0xbbcddecc, 0x6b8386a0, 0xf8a36a78, + 0xd46c9dbd, 0x9155db1c, 0x3cd59926, 0xc0d02017, 0xd63c2481, 0xb7b73298, 0xa1d8a674, 0xad86fe59, 0xca80e4e0, + 0x189c2496, 0x29a136aa, 0xd704c56a, 0x9eb9a03a, 0xfae4cd77, 0x760a155a, 0x4fb5dde4, 0x3435bf4d, 0x1a041409, + 0xc11037bb, 0x07499875, 0x5f5ba51b, 0x26e29702, 0x404109ae, 0x3b844785, 0x4c2fbbdd, 0x9caf321a, 0xe2340902, + 0x89a2a6eb, 0xcc40c4f5, 0xcd99c1c4, 0x6a7a81ac, 0xd4e05e5d, 0x1e7f5028, 0xae90706b, 0x8ff2a148, 0xb7dee0f5, + 0xf6800571, 0xe5dbcda2, 0xb0049e32, 0x2a25e0c3, 0x46695904, 0xd536e2a6, 0xb326e29b, 0x70e5db2e, 0x6f29cf60, + 0xb421ab53, 0x02686889, 0x2a98ac05, 0x04a49266, 0xac53e1cb, 0x91d834a1, 0x66d17e4d, 0x7ee603fe, 0x92b1098c, + 0x11c8bfb5, 0x9f6f31e8, 0xbd0fe909, 0x4a699dda, 0x13b83c1c, 0xc6607491, 0x088513e1, 0xd171dab8, 0x28094a49, + 0xb880d480, 0xcb508325, 0xfc5b786c, 0x366124bc, 0x93e6c19c, 0x6d839180, 0x88c60b67, 0xd19b0159, 0xf0aba9d8, + 0x7ed3b5bf, 0x3f7e3d4e, 0x129a94a2, 0x5afda4d0, 0xde3fd10f, 0xd7d7b6b1, 0x8b1f3c15, 0xfe43eb67, 0x7abb40ac, + 0x1005e615, 0xaf2be0ae, 0x6c542202, 0x5c29799b, 0xe453ff0b, 0xb5146491, 0x0fa21e2e, 0x15f2ac93, 0x8429c738, + 0xe340a92d, 0x017395d1, 0x38943fce, 0x8146cd86, 0xe544e79d, 0xb4c15058, 0x01b06a9f, 0xe233e276, 0xdbdb1cc5, + 0x91dcccb5, 0x76b44481, 0x4ad04d52, 0x228b87d7, 0x774619dc, 0x90100467, 0x633e1129, 0x00af2836, 0x80de31c7, + 0x8998b54a, 0xf094dd89, 0xf2a461bd, 0x7d06cd0c, 0x54d75e79, 0xa66710c7, 0x89973914, 0x15bc1089, 0x616d3f2b, + 0xb6dbe7df, 0xac3fb887, 0x33b956cc, 0x354ef54e, 0x2e8f7ec0, 0x427d3c65, 0xe1f7e747, 0x887ebb85, 0x1cbfc4d0, + 0x659ef979, 0x976ba9cb, 0xf65e082b, 0xaaed9538, 0xd4a40961, 0x3822bf75, 0xd5b1c051, 0x1d2aaa66, 0x1aa0b4a4, + 0x2d48fe56, 0xd3d197d0, 0x4ae0053b, 0x086e3a23, 0x7853167a, 0x5b576304, 0x981a4715, 0xcc5980fb, 0xedd59532, + 0xd446adff, 0x51e3e6a0, 0xe060a66b, 0xb771ce1d, 0xe27b6255, 0xf47d982a, 0x15954920, 0xffcf4f3f, 0x1919f047, + 0x08d02235, 0x3051f1f9, 0xc71014a9, 0x4264a988, 0xfe121124, 0x3a14e025, 0xb19399ba, 0x60114d27, 0x32d9739f, + 0xd02c73a0, 0x2ae69052, 0xb6e3bb3c, 0x37b61d20, 0x5f96c613, 0x4b4db70e, 0x9a1a9d85, 0x1d1ff113, 0x45bbabbc, + 0x30e2029f, 0x97df8b03, 0x0c62768e, 0x71b52a4e, 0xd7711c14, 0xafa2bb9e, 0xb6321992, 0x27ae2455, 0x070a6311, + 0xfd21714a, 0x56cdeeba, 0x10273bd4, 0xfc00b733, 0xe6490175, 0x8eb24436, 0xc8cc8db4, 0x533720a0, 0x6c9e496b, + 0xfa6ac56f, 0x61a8ec44, 0x13b1b789, 0xa202cf08, 0x014b9b25, 0x75b6e9e7, 0x3a7a51c3, 0x7b3a1878, 0xdd13a888, + 0x5afeea59, 0x67f4891e, 0x1fc5958e, 0x2b7c954f, 0x2013ad00, 0xabd71adb, 0x72e173d6, 0x6519a5ed, 0xa6ff03d7, + 0x35c49e18, 0x3b371123, 0xd124bf92, 0x89a9b4cf, 0xaa2e7381, 0x365d9309, 0xa46b3f73, 0x41b6d786, 0x518dc0ef, + 0xcb6a0fac, 0x92c1b4f1, 0x6fed0ef5, 0x324502a1, 0x9c8b7f6f, 0x3c0c1297, 0x87cf0bc6, 0xc769a353, 0x8aa50d94, + 0xe4a5c6d7, 0x4d3caa22, 0x19a9b993, 0x30a53fc5, 0xeac3502c, 0x7d6be931, 0x07ab09ac, 0x7f51aefc, 0x9b51ce7f, + 0x2274f655, 0x29942ee1, 0x70eb8c58, 0x193c4166, 0x5cf8800c, 0xbdb742a6, 0xe7d0edbb, 0xb632465c, 0x4c1351d6, + 0xdf52689c, 0x9c02022d, 0x0def8b82, 0xccd02d17, 0xf7a6d823, 0xb824c77f, 0xe9224d95, 0xd03f4eba, 0x86d54076, + 0xa57f3948, 0xfa59ffe0, 0x6d10a9db, 0x696fa48c, 0x6896909e, 0xbb40ce4b, 0xbdd9e615, 0x653b7c91, 0x50e138cc, + 0x06299d69, 0x2635b316, 0x57b0a8b9, 0x86d8ca2e, 0xdf15d476, 0x0adca9b7, 0xe182462f, 0xd5ea0194, 0x7d1b2900, + 0xae18cf0b, 0xc94ffd80, 0xb5451072, 0x3bd5af61, 0x41d6aa33, 0xaa35e369, 0xce7f1a62, 0x4fcd56b8, 0x47249420, + 0xb7fcd68c, 0xcb0f3a6b, 0xc55e7a9c, 0x86ef253d, 0x85e58c0f, 0x19e1a641, 0xf8856388, 0x595fa257, 0x56ec2946, + 0x790d08e9, 0x4cd1b4f8, 0x5fc3d2e2, 0xafd355e7, 0xf9580296, 0x3802bc07, 0x1b0d523c, 0x3e809712, 0xfe005069, + 0x9a98fc05, 0x0b40d9ff, 0xaf7a718c, 0x796b87bc, 0x728e076f, 0xbf9c995c, 0xdf6d225a, 0xe0941874, 0xfe736f68, + 0x1f9296dd, 0xed726c0e, 0x57e01d0e, 0xbb7acb3c, 0x2d1dd415, 0x9356e0e8, 0xf239357a, 0x5597ab92, 0x38c94c6a, + 0xb3711322, 0x5e8e2cfa, 0xdedaa1a7, 0x578f394c, 0xc89ad02a, 0x76648541, 0x912b4069, 0x5559381f, 0x8af084f0, + 0x52c3e17e, 0xd19d4088, 0x5578a1a9, 0xa8dca4a4, 0x71806b29, 0x2a8820ac, 0xd59ce42f, 0xdc865f0f, 0xe6862ec8, + 0x5cf732b2, 0x216b8cc2, 0xf73a785d, 0xd434a916, 0x44df8c8c, 0x269f86ed, 0x044ee37e, 0x40b0c553, 0x8c529a54, + 0xe2ec5308, 0xa67bd33c, 0x25f882b1, 0xc1502c3f, 0x975cd795, 0x546f6095, 0xee8ada4e, 0x284de14c, 0xc6ea2086, + 0xf5e76c88, 0x44fb99eb, 0x27809c2e, 0x9482617e, 0xaac1bdbf, 0x1c469059, 0x38e5ba20, 0x5d7db405, 0x66de6488, + 0x17b9dbf4, 0x2de35630, 0x43e6c916, 0x5d1f0567, 0xa233f820, 0x0b1a7f93, 0xc91f10dc, 0x58243bd8, 0x95098698, + 0xee32e798, 0x1cd73ada, 0x86d77f92, 0x2b6ea72a, 0x1ad4b4c2, 0xdd6683c6, 0x858d10d2, 0x8cc66b3d, 0x0f52c06b, + 0x95720588, 0x97c0a2e9, 0x83ee9582, 0x27e48e7e, 0xb1d34bab, 0x0dda0ae3, 0x2aa75c43, 0x9e3a5f56, 0x5d926b28, + 0x1144aecf, 0x0c0aa3af, 0x0f68b1ef, 0x93fde7c0, 0x122bf056, 0x3c4a93d8, 0xe71fd4cd, 0x442724e8, 0x76ff0fb2, + 0x1e45782a, 0xf6456871, 0xe0184a2b, 0x75d6112f, 0x59676359, 0xb7518caf, 0x35d9c873, 0x70a7e5a2, 0x0d1790d2, + 0x3357f657, 0xddace92a, 0x3551fa59, 0xbf9a2480, 0x908042d7, 0xe8dd40d7, 0x3b2b552a, 0x0bfba24d, 0x2b642d79, + 0x8a91c39d, 0xeeb1ef78, 0x6c69853b, 0xcfa2774f, 0xfc6f477e, 0xf180650c, 0x21336628, 0x3753059c, 0xeb5d7e5c, + 0x827cf1ba, 0x8008e018, 0xf2e9a7f4, 0x5ff9401d, 0xfb0f474d, 0xe05c5ef7, 0x3ca9f790, 0x7b4fa984, 0xa8ad64d9, + 0xb5d9a3c4, 0x1625492c, 0xd7556704, 0xd9394f61, 0x5d835961, 0x3182bd6b, 0x2b238f76, 0x9a835d4e, 0xa278aa8d, + 0xd0dd5513, 0x86c6f27c, 0xfbcbeb6b, 0xe40110a5, 0xdd04558b, 0x7cfe7ed3, 0x909924b6, 0x9207e8aa, 0x4b212bf8, + 0xabd0c373, 0x1c818040, 0x96ed3051, 0x5105df46, 0x2bd4b829, 0x0be26e75, 0x33e8c217, 0xe46cbf46, 0x0918d2d9, + 0x421c7f1c, 0x7f2fa3f1, 0x991f17f0, 0xa8fb2b68, 0x308384cd, 0xd3ef7532, 0xc0a73112, 0xc8618a85, 0xc7a26ac7, + 0x20b4d337, 0x77b43013, 0xcb00e128, 0x97bb2c4a, 0xc436a5e6, 0x10b417d6, 0x6d4fb58c, 0x987899ad, 0x3bf7a51f, + 0x6c911c42, 0xc2a4ab6d, 0xff723cda, 0x0b886e11, 0x4aa03ea7, 0xffd611c2, 0x8895cafc, 0x386aaafc, 0xec35ea39, + 0x6d312f6d, 0xe82aa666, 0xcebc9105, 0x27fc5079, 0x0514a597, 0x95403821, 0xb00e8255, 0x86d6a4ce, 0x72c0434b, + 0x7b8d89b2, 0x0981d0e0, 0x4be4604d, 0x093f1a37, 0x748c727d, 0x3caecd31, 0x76ee9fd6, 0x0d9300cb, 0xc17dc95b, + 0xfad07bc1, 0xc7c11cc5, 0xa7aabb4d, 0x79bea780, 0xecb072ce, 0x36f59c7c, 0xe14bb23f, 0x146b855a, 0xc042c5e9, + 0x88ad9354, 0xd23739ad, 0xd5e7c8d9, 0x42224063, 0x05e7e133, 0x749388e6, 0x3aad0b9e, 0x0557f4c2, 0xa27f3da3, + 0x9a504522, 0x2624a10d, 0x1d084f7e, 0xba94f5f1, 0xb203aaa1, 0x29d2a5f1, 0x96c81e4d, 0xa3fa2449, 0xfae5bfd7, + 0xd923273a, 0x9cb81182, 0x06bcd5e8, 0x653161a7, 0x3294ea91, 0xa2c175dc, 0xc49010fa, 0xc2eaa4d8, 0xe14a5a3f, + 0xc278a0c5, 0xf2bf53d8, 0xd6d5cfad, 0x4fc94b95, 0xad1ba720, 0x7a19c706, 0x3a53a8ed, 0x15a8b85c, 0xf4baa75e, + 0x8dd5ab3a, 0x7eee0ab6, 0x211cbf4a, 0x940ad9c5, 0x4864fc0d, 0x38f95a09, 0x6f7d7f1d, 0x015ccd92, 0xba8b6e57, + 0x894e018a, 0x8feaa091, 0x665b5af0, 0x97ea010c, 0x9425c7f5, 0x817fc23b, 0x9292a5c2, 0x6fb07616, 0xa1be3cd8, + 0x58c8cfe7, 0xad6037b0, 0x45ff04cf, 0x3b5dce09, 0xd833acbd, 0x9f0b030f, 0x7dcb5542, 0xeb9f1a78, 0xbd060054, + 0x667896f8, 0x399748de, 0x68af1930, 0x5dfaae52, 0x1b3830cd, 0x834c5bcd, 0xcfbcac90, 0x91a7c991, 0x1d8be117, + 0x80852f67, 0x71d73854, 0x0e837f71, 0x955059b9, 0x41a35903, 0x72c73c3c, 0x7ceb749e, 0x3c54ea91, 0x768fadb2, + 0x40b064a3, 0x949f38af, 0x9647930a, 0xe38cd3b2, 0x5c3683c1, 0x4071218b, 0x8dbeacc6, 0xa7a66142, 0xbadcc282, + 0xccf1aa91, 0xdb10d44e, 0xf509113b, 0x508433d1, 0x65e7eaaf, 0xb96bb806, 0x87982376, 0x5de88090, 0x679ba536, + 0xcb4330e6, 0x3c9db2c4, 0xb0516877, 0xfc2d823c, 0x3d4adfb9, 0x46d83e32, 0xc3f9efdf, 0x5a827df8, 0x38a80402, + 0xb3ed1631, 0x2340f2c6, 0x32af43f1, 0xd6fbb18b, 0x6830449f, 0x57b9d27f, 0x99bb0d21, 0x119ad4e8, 0x6e3c84ed, + 0x3d19f58e, 0x8b406d0e, 0x576324d8, 0x8f8b18a4, 0x24a15d94, 0xe87ce812, 0x2512b2a8, 0xbacd6567, 0x5a7085d3, + 0x0da1fa23, 0xd18afea3, 0x106ba71e, 0x32893bcd, 0x066352db, 0x571efeb6, 0xf5d9375f, 0x18d66a52, 0x6f9b51da, + 0x64282040, 0x4c3e09f8, 0x7c5598c5, 0xc33b200d, 0xf6afb749, 0x4256db02, 0xee5d7b88, 0xc7380753, 0xe684e24c, + 0xd38872f8, 0xa7d48993, 0x7c2869e6, 0x6c102f53, 0x398c64fa, 0x8b0841c2, 0x9435bc5a, 0x8320160d, 0x273be0d3, + 0x3ad000b4, 0x7e0400a3, 0x9e9a40c5, 0x89cc4ac5, 0x2f6d8932, 0xc5cf80d6, 0x90329c75, 0x8cc0afc7, 0x58a4a775, + 0x2544bfd0, 0xca8330ec, 0xf2e034a7, 0x44dc7cc9, 0xe30ff85f, 0x9be057b4, 0xca3fd76e, 0xbf0feb44, 0x23ec9bb1, + 0x6f1bb934, 0x650e32fd, 0xe5e4ec2d, 0xfe9069b6, 0x1eb19cc1, 0xfaaaaddf, 0xa4ac9bca, 0x49322725, 0xbf194450, + 0xb2312a6b, 0x5714e6f0, 0x50f2ded4, 0xb2a13f9f, 0x14496e45, 0xa16e39a2, 0xbf36786f, 0xbe7c87f9, 0x64d8c6d2, + 0x23901bcd, 0x2b9e72b8, 0xb70a5df5, 0xeaf988bb, 0x47e50915, 0xec3d1927, 0x89633968, 0x3e82b56d, 0x7b8fba03, + 0x52e194ff, 0x54964992, 0x9ccf0c47, 0x8e7c088d, 0x205b4c10, 0x3c4697f7, 0x5a26c25e, 0x0bb79394, 0x09fd9838, + 0x2652c484, 0x450839cd, 0x9977c6ca, 0x1291cd99, 0x54aa4aae, 0xc7147b4d, 0xdb370a9d, 0xd14911fd, 0xbdfdbab3, + 0x81aa625e, 0x3412a328, 0x4b4bb805, 0x28b02027, 0xde1de463, 0x8f4788ae, 0xb6eabb70, 0x769136d8, 0x4d5c284b, + 0x397cbf68, 0x9ce13f51, 0xacd08813, 0x0ac21a0f, 0x42f22f5b, 0x7580b096, 0x9b171135, 0x5ba3e175, 0x23db6dd4, + 0xe1730e5c, 0xc3d89e1d, 0x9a09077e, 0x1e78b717, 0x66ca0f91, 0xcb628b47, 0xc2cde455, 0xedb04161, 0x00208ecd, + 0xf2028597, 0xa4d04a6e, 0x5d6086ca, 0x31b9c70c, 0xe0f9615c, 0x2e3fadf7, 0x46fcaee5, 0x4e371991, 0x72ca8ac3, + 0xd0429131, 0x511e0356, 0xb2f9b390, 0x52ed0c03, 0x6320acdf, 0x28d4bcef, 0x76bcfa84, 0x3d912f02, 0x1e2dbd39, + 0xac480a2e, 0xf8722698, 0xf4ff7deb, 0xd9d55bbb, 0xc05975fe, 0x5ab2ac0e, 0x415a22fb, 0xedd62648, 0x4745462f, + 0xefd7da71, 0x8067f1e2, 0x2d8227fd, 0x158e4e4d, 0xf6833604, 0x56d1bc88, 0x2e9e92cb, 0x7517d8a8, 0xf4c0d80d, + 0x32ec4700, 0x2686c1fa, 0x89f35aad, 0x720831b7, 0xfcb87c0d, 0x5dabddce, 0xce60d627, 0xcfe2083d, 0xa0091033, + 0x87142d4a, 0x4d5fd554, 0xe36c032a, 0x62a6e731, 0xfe0d3581, 0x11d881d5, 0x59018efc, 0x8f80f0a2, 0xd10f9ee9, + 0xd0330c3d, 0xaf80c751, 0x211839b7, 0x961ba1a6, 0x491a0166, 0x7d250ecc, 0xec9daadf, 0x2a67e664, 0x4306ef95, + 0x605c2493, 0x98643eca, 0xcfd4d9bf, 0xb1e84668, 0xe1e5a46b, 0x1095714a, 0x0273c063, 0xf2ea6068, 0x74e12bae, + 0x0ef35812, 0xe35130a9, 0xeaecd2cc, 0xe76620d4, 0x337d4b26, 0xf70feb56, 0x25f14c3c, 0x01f41cdb, 0xb613989e, + 0x43ef6c0b, 0x8db40ed4, 0x40481aec, 0xf3f03339, 0xd12dfdaf, 0x422edc71, 0x27197a87, 0xd374bbc3, 0xcb09ea22, + 0x22b09f1b, 0xa3b26234, 0x1ef31de0, 0x77d98c9b, 0x47e8ecfe, 0x64613288, 0x5543f80e, 0x95554dc8, 0xaf0048d4, + 0xbe8e6221, 0x7bc3c82f, 0xcdc76417, 0x3af7915a, 0xb6f8ebbc, 0x261e38cc, 0x1f1a17e5, 0x3d3a7cc5, 0x63098d99, + 0xb2a2fbe1, 0xb4585b2e, 0x408d3ae6, 0xef17b40d, 0x2ae8dc35, 0xfb9df738, 0xd90a2970, 0x17015260, 0x6ad13a8d, + 0x8ce35c29, 0x96d89f00, 0xa7f7e790, 0x3ce65b40, 0x9fe846f2, 0x5d76d68e, 0xa40b5fdb, 0x3f9cd092, 0x9a90c15d, + 0x32e80826, 0x3cbeb2f7, 0x2c91f9f8, 0xe6a98355, 0x47b6c34b, 0x3565f4a6, 0x6894c75b, 0x3fc933b1, 0x54da72e4, + 0x46b75c35, 0x624c6b1c, 0xaa880812, 0xcdad96fb, 0xfa33dde7, 0x8f80af97, 0xb848d746, 0x3700ea51, 0x228d0cd9, + 0x62bc6c51, 0x8ae390d3, 0xd73623a1, 0xca683a65, 0x525e6e04, 0xbcc6dfdc, 0x7727efa8, 0xea720a1e, 0xa0fc8eae, + 0x3a21916e, 0xff77c7c4, 0xb6dc6ea8, 0x2681120a, 0x04b53a2f, 0xb99e2edd, 0xaff7d29b, 0x8cac760f, 0xe465b790, + 0x33e246ca, 0x49b61327, 0x71acef36, 0x3db2eb97, 0xf7402e67, 0x8287ba11, 0xe29127fc, 0x0aeed8ef, 0x506552fd, + 0x2b4efd11, 0xa4e4c507, 0xca28f6e3, 0x45c4d85f, 0xbb3305cc, 0x79c20e90, 0x29bacb08, 0xfb662bef, 0xe9238b48, + 0x055ffb36, 0xf40fd630, 0xe0e92968, 0x6692fc4d, 0x6ffc8825, 0x66ccf6f0, 0xcd013519, 0xb9e573c7, 0x616a1589, + 0xef1bedec, 0xf2476d19, 0x2799af23, 0x415eeaf6, 0xa7bd4806, 0x55891f04, 0x440682b8, 0x9ed9cbe9, 0x09688ad7, + 0xebb79080, 0x4fbdbdc5, 0x2cbeb0dd, 0x9248c0dd, 0x32bced03, 0x9a912d6d, 0xd33e95dd, 0x2881babc, 0x6ac5dd3e, + 0xd1f19d09, 0x274e0a3e, 0x95f73ddd, 0x54122404, 0x1f6160cb, 0x0b0b181a, 0xb72bfc3f, 0x608106c0, 0x6e5567d0, + 0x42675bba, 0xb635ac59, 0x41f753d6, 0xbced1f47, 0x43722ac7, 0xaa1ed624, 0x4b716ef5, 0x1f4b5305, 0xc4832446, + 0x3f9db084, 0x2ef21f3c, 0xd53da81d, 0x8444411a, 0xd020fe98, 0xbbb83248, 0x269c366e, 0xc2ae7c37, 0xe3f0bdd5, + 0xeba2f0a7, 0xb72bab91, 0x4db09bc6, 0x27335148, 0x4b129f69, 0xb19bfa8a, 0x02dea8ac, 0xd3746c46, 0x21c1c5d9, + 0xfae07c96, 0x1709169a, 0xea97de35, 0xd614254c, 0x5b292d81, 0xb92ad38e, 0xc599ed29, 0x5849aa2e, 0x726c4c51, + 0xef35567e, 0x51d2e51d, 0x6a19a966, 0x454f0a6a, 0x4d7b3c9d, 0xeb2c25e5, 0x81b42771, 0x6509fe09, 0xde086eb6, + 0x76d89579, 0x148a0e3d, 0xc888fb5e, 0x819a5818, 0xc942cae5, 0x204c42c0, 0xc9a0cb14, 0x6300eddb, 0xfe379e49, + 0x3d05cc2c, 0x42635f1f, 0x896dbb08, 0x19168c80, 0xf942df54, 0x8d720bfb, 0xc28babe0, 0xccd3dbab, 0x9029e115, + 0xc6742420, 0x3f36eec7, 0x6b98db8a, 0x361d67c7, 0xf7cf5108, 0x61b188ce, 0x9e5ff28b, 0x20842e2f, 0x9862cc4f, + 0x8013df5d, 0x036fb9aa, 0x4692aa0e, 0x6c607d28, 0x10c8b595, 0x32dc87eb, 0x41fabeaf, 0xe26c4279, 0x37f423ee, + 0x30565f3d, 0xe1df0f69, 0x9c490aad, 0x63791411, 0x693db1bd, 0x83931074, 0xe5684be4, 0x5f8cdf5a, 0x482b27b7, + 0xb24cdb1c, 0xdd83ddd8, 0x9cc9a84d, 0x1181c9bb, 0xb5dabfea, 0xdeb3ff9c, 0x264c5a16, 0x61bbf9b4, 0x8d81906f, + 0xf2020bdc, 0x4d901528, 0xa8ed408a, 0x4ceef0c1, 0xe36163ce, 0xe60199dc, 0x63b64fff, 0xa550e1fc, 0x2371b170, + 0x73651b03, 0xa041c6d7, 0x8152c37f, 0x149e9a4f, 0x3f03a65d, 0x5e662d89, 0x485b4b0c, 0xccba1e99, 0xd522dc40, + 0x548105a3, 0x5f1c6a17, 0x22f7449b, 0x110c9343, 0xba96e0c5, 0xa2eb6d46, 0xf57b2ff1, 0x04b24867, 0x8f2bd1c9, + 0x2ffddda9, 0xca442afc, 0xac4163a5, 0xe24b85a7, 0x90059cb7, 0x8f1057b6, 0xc7a4f74c, 0xb07bab2c, 0x6ff8d7d6, + 0x4b9de7ba, 0xb6bdc463, 0xa2cb3d89, 0x8f765b83, 0x52d3b913, 0x8b18084c, 0x3595e02c, 0xf82358ea, 0x7580b4c9, + 0x68b59998, 0x07c9cc1c, 0xbb25e1bf, 0xd5bee98d, 0x4986398e, 0xd33149df, 0xafb711f9, 0x728635b1, 0x768955a6, + 0xaee1bbb7, 0x25c88dbb, 0xff85a5c9, 0x6e281d04, 0x95b5bed1, 0x665fc1c4, 0x1d8c8746, 0xc47062a9, 0xa7259cd9, + 0xaaf302a5, 0x6ed96703, 0x59310d15, 0x0efd2c9a, 0x1e5cce53, 0x3152474e, 0xbea1981b, 0x42f872d1, 0x024c34f5, + 0x50874936, 0x348bfd29, 0x46d8285f, 0xc216049e, 0xd3206da6, 0xd6cbfc0c, 0x06de5d64, 0xce4df307, 0x036e8e6e, + 0xae706571, 0x72f6e28c, 0xf36dba42, 0x4dd25253, 0xacd352ff, 0xa3bfad39, 0x35fad40c, 0x6bee9e98, 0xa496c813, + 0x01e25eee, 0x8b05e466, 0xeab0e73f, 0x8b496c3a, 0xe759580f, 0x5cbfa189, 0x5249679b, 0xe950faa0, 0x79b0c94f, + 0x4120ef7d, 0x6f7ab435, 0xab6e4675, 0x9553e5b0, 0x91068610, 0xbd427bf8, 0x85b96274, 0xebb8b8ca, 0x37977793, + 0xb89a27db, 0x07ddd123, 0x891f8154, 0xbcc2f5a5, 0xed7d64e1, 0xf527ea78, 0xcaf47f24, 0x435f9408, 0x2d1dacd2, + 0xd86a1c3e, 0x634e96a1, 0x3a21519a, 0x86d79a6b, 0xa2baab7d, 0x8172ae9f, 0x243c99ae, 0xcd1bc5a5, 0x0853ee7f, + 0xf8316531, 0x15223153, 0xdd248ce3, 0xc268177c, 0xdc748522, 0x679fe807, 0x062eeb23, 0xb31f7058, 0x08c94908, + 0x69c4cb1d, 0xebbc3336, 0x704ad96f, 0x20b1d0f8, 0x20513eea, 0x180bc3a5, 0xe5b2b712, 0x9fc37379, 0xa8d68d26, + 0xad8c66db, 0x4196f10c, 0x8bc47215, 0x8aabccce, 0xa7c88fe2, 0xade36968, 0xc00d63d0, 0x7ca057d9, 0xb6c669d8, + 0xb8a6feb1, 0x2e01f7d9, 0xc50375b3, 0xcef0297e, 0xc939a975, 0x87f421ac, 0x38b40840, 0x7af5c745, 0xc2183826, + 0x19e3aadb, 0xfde34142, 0x17e0f771, 0xe65074d0, 0x4bb46c3f, 0xc8afeb7f, 0xf018029c, 0xe27b4883, 0xded44d72, + 0x124c3d8f, 0x8a3029d4, 0xdc30e29c, 0x5eb34bf9, 0x4f08f26e, 0x9669f4a4, 0x903616a6, 0xdd281aee, 0x216e7ea7, + 0x349767db, 0xd2772c21, 0x53a082e0, 0xcdad513f, 0xce339db8, 0x0e1e6000, 0xbb2b3fad, 0xd12e0764, 0x2f7582b1, + 0xeaf1d617, 0xe7ab05ec, 0x33776d7e, 0xd8ba014d, 0xb446a9ea, 0x01083d59, 0x0242b604, 0x5003ae6b, 0xfb1ebe5e, + 0xc23d9c6b, 0x165df4e7, 0x33527647, 0x9e01444e, 0x17a311bd, 0x71d39765, 0xb8c4998d, 0xc4351368, 0x4f7aa484, + 0x3f197732, 0x7de7bc42, 0x596aad52, 0xedc79fa5, 0xc6fe0df3, 0xe1ef1bf5, 0x8f339493, 0x7042139a, 0x1d603842, + 0x473b59b1, 0x6df9e940, 0x0d48df55, 0x452daf01, 0xa42e413f, 0x567aac4c, 0xd823b330, 0x73651422, 0xa310fb3e, + 0x9b1efcba, 0x5eab820f, 0x446fbf32, 0x79f8f2a9, 0x90525b33, 0xe32dadab, 0x83f2838a, 0x304a7cc5, 0x8024d23e, + 0xff38c158, 0x7f3267ca, 0x90bdaeeb, 0x7b207cf3, 0xa7244df7, 0xd916571b, 0x3da5597f, 0x10f32048, 0x98828f54, + 0x7fa9a7af, 0x18f9fbd8, 0x805cd8c6, 0xb45a176d, 0x276a6338, 0x7e6e0401, 0x05e62eb4, 0xe1835420, 0xadc5ba3b, + 0xa932766a, 0x67793744, 0xa18ef930, 0xe8210718, 0x7fbcfeaa, 0x0c0bcc3c, 0xecffb86e, 0xa1b58752, 0x9ba352a6, + 0x20dd9cdd, 0xb08e8539, 0x84c01bdc, 0x4ef5f368, 0x66ae7aa8, 0x50e63aca, 0x52d7b1ff, 0x43d07820, 0xd00fe62f, + 0x872e36dc, 0xa4a83976, 0xc1a17da5, 0xb421e7f8, 0xcd0d5941, 0xbf814ea9, 0x52957623, 0x2b474c3f, 0x0ede64dc, + 0x06c35ae8, 0x373fe325, 0x09bd1411, 0x47f01073, 0xb50d3ce3, 0x71e77988, 0xac5aadee, 0xcbc25df8, 0xdb2298fd, + 0xa5c81bce, 0xa26573cf, 0xaf300a65, 0x1052f440, 0x4c1c247f, 0x90c74397, 0xbdec16ce, 0x853af781, 0x1804ead3, + 0xc02ccea0, 0xf6533b66, 0x6c8ee715, 0xa527d466, 0xf1799e8a, 0x2b121951, 0x9b38abe2, 0x10d9f4f9, 0xe9abd81a, + 0xb8d4b1a6, 0x94a8e05f, 0xae21a1d0, 0x6f92b589, 0xfba26732, 0xf994366b, 0xb289da86, 0xe5810474, 0x6277acde, + 0xea8c430c, 0xd86fd05d, 0x7e6547dc, 0xd5eeb852, 0x6ddf6c2e, 0x52d2b3b0, 0x171f1e31, 0x352f3858, 0xf97d236f, + 0xae0ee4f8, 0x0175a3e7, 0x509ac81d, 0x9f9cacf2, 0xbb9effa5, 0x03644e28, 0x9233f2df, 0xd701fc88, 0xf766c8bf, + 0x79f99626, 0x4de2cab2, 0xebf36db5, 0x99cee99a, 0x75e36fdf, 0x5082528c, 0xb7542a74, 0x7f6d1062, 0x3ba2ea7e, + 0xb01c54a2, 0xe5bfc7f8, 0xdc437de3, 0xb20789d8, 0x50729ea5, 0x80e31708, 0x8374fbc9, 0x523a4b93, 0x5063e5ee, + 0x3f6cf0ea, 0xecc5f2e7, 0x71a76a7a, 0x40c6a30b, 0xeff3277f, 0x150b1a6c, 0xd86fc24c, 0xa7a52cb1, 0x89e23833, + 0xd072b255, 0x8a80b0cb, 0xf3026d4f, 0x790fd89f, 0xfc49dd45, 0x3158ee64, 0xffa297ec, 0x42fb0b8b, 0xa2837664, + 0x6190ea4f, 0xab34bae1, 0xc615df38, 0xdc4f3321, 0xb847f6c0, 0x8b0018d4, 0x1f323f5c, 0x5ad4ed8a, 0x867f2de6, + 0x6949f6c0, 0x010dd543, 0x856eebe2, 0xfa8f00b0, 0xc482f6b4, 0xf20581f8, 0x8fa9c8e0, 0x61d841a6, 0x0ee2ca39, + 0x80d5dea4, 0xb3638aa7, 0xc28eaa25, 0x5c64f0e6, 0x58aeceb3, 0xad59180f, 0x4c4edc69, 0xa8b86d2c, 0xdef54d32, + 0xc5c09d1b, 0x55fa8553, 0x8758ad96, 0xa5a6e380, 0x37a3722f, 0xf956d3a1, 0xf1824f20, 0xe6fdc45f, 0xf86efa27, + 0x5098ca21, 0x4417f136, 0x446c5a33, 0x20ee2c35, 0xf4797af7, 0x0cf72a33, 0x37310d47, 0xd9407f3e, 0xc95b88e2, + 0xab1cbb6e, 0xfda6eafa, 0x39aa4d0a, 0x4fe357ad, 0x43b698f3, 0xce2f6148, 0x48ce0eeb, 0x25e2280d, 0x84091e9f, + 0x032a8449, 0x6019af16, 0xae0709a0, 0xab3d7eb7, 0xe6dc8868, 0x6db38e7f, 0x8fce82ab, 0x67e5a35d, 0x0a5cdfe7, + 0x08eecd45, 0xcaf5f730, 0xf37cd5f7, 0x5b28ce78, 0x0f05543a, 0xf799d7b0, 0x979e8a4b, 0xeb751e3e, 0xbeaaaeda, + 0xb4a3ca52, 0x70ebe907, 0x30b94d3d, 0xab6df92e, 0x9d9b4b50, 0xbe3b275a, 0x45fd6a25, 0x45d58577, 0x1b82fc72, + 0xc8411828, 0xc1d1574a, 0x09ddf8be, 0xdc76975f, 0xda675d53, 0x65489d17, 0x254f7209, 0x3ca0d112, 0x7ba1394e, + 0xc23972c5, 0x742e7dfb, 0x9ea2db38, 0xd40ff444, 0x2312f10f, 0x8bb674a5, 0x1d3dacde, 0x1030d7fc, 0x61913e97, + 0x486507b8, 0xe2554036, 0xfed22665, 0xe2869fd5, 0x8424ecc0, 0x61e9f3e2, 0x1aa86eb5, 0xff434d26, 0x22819a2d, + 0x22106b24, 0xad7a885e, 0xbb74d8d2, 0x629a11d7, 0xc255cdda, 0x6b5e0b80, 0x0176aa23, 0xcf83087a, 0x584fa6b4, + 0x5f7419c0, 0x59fbc764, 0x65ba2c2c, 0x12d94820, 0xba4f58a4, 0xa6c63def, 0x282e7ade, 0x9bed356b, 0xa6f173d3, + 0xbf5f0158, 0x5d564359, 0xd3e4024a, 0xd10020b4, 0x0e1996c7, 0x7f02c9e2, 0x50494bb1, 0x3d6349f8, 0xec636a4d, + 0x58d058bf, 0xd111b7a3, 0xf34420bb, 0x2b57ff91, 0x4c7b8d60, 0xb8417781, 0x513b8dd3, 0x49eeca43, 0x83ac8d67, + 0x701385bd, 0x8f763c3a, 0x022fd102, 0xe8dfbfae, 0x1340de0a, 0xd89655c8, 0xa06cad2c, 0xf9730b12, 0x3bb5e855, + 0x52f71882, 0xedee63c2, 0x4ec77a9c, 0x30e73da0, 0x57626965, 0x419a3dab, 0x168b4e6e, 0x4e736913, 0x89833c53, + 0xdef0aadf, 0xa7de4526, 0x0cbc7079, 0x6338c1d9, 0x5d3816b3, 0x2ea35cd1, 0x750c5895, 0x1ea06874, 0xbd1dcd2a, + 0xdc05a0c7, 0x2fa0655c, 0x7ced26cc, 0x414d778d, 0x347bddf5, 0xeff050c7, 0xbf38a752, 0x220263cb, 0x0d4486b4, + 0xf506c06c, 0xe0a3faef, 0xddf73b31, 0xf24f2a84, 0x2aae2d52, 0x643145d6, 0x327c6a91, 0x361804a6, 0x1d208c86, + 0x47bdaeee, 0x6199a3a5, 0x74e4296e, 0xf670c971, 0x7a62f737, 0xdbe888a0, 0x34cf2f72, 0x89e0f0f1, 0x3a1d5787, + 0x59f8da42, 0x87b4361f, 0xca0cd5a1, 0x279a5208, 0x4db5258f, 0x160b69e1, 0xe54a445f, 0xea08a529, 0x992349cc, + 0xb5677f5a, 0xafaa37e0, 0x68de1c15, 0x87019112, 0x124ae1d4, 0x32b1ffc8, 0x2b1f9b83, 0xb933a92e, 0x4ca886af, + 0x78a9c023, 0x44761536, 0xcc453151, 0x9f57493d, 0xad857c83, 0x6fe2a19d, 0xaf981be8, 0x7ffb91b4, 0xbd46903b, + 0xc6b90d7d, 0x4f118aa4, 0xbadaeda6, 0xc9ecd14a, 0xcab108c1, 0x918ad03c, 0xadfd5d54, 0xb8f82475, 0xed8e5103, + 0x6beaaeee, 0x2e2daa89, 0xcae727b0, 0xcb6fb2b6, 0x63a2d247, 0x4e0a9238, 0xf5fe43d8, 0x7df9e31d, 0x42eee5cb, + 0x208a3425, 0x2de1c345, 0xa4d30b10, 0x29e510c2, 0x3d00227c, 0x6c9f48e7, 0x7d7556b6, 0xab838519, 0x4282f571, + 0x137d1ca4, 0x88b1d509, 0x856a089c, 0x8cc27807, 0x781f3ca7, 0xe7708bf4, 0x0f9548e5, 0xccd8d3b9, 0x43aa648e, + 0x55a2662c, 0xc1bc6eeb, 0x0b6b0b64, 0xdfbe77dd, 0x3dc87f02, 0xebb84133, 0x190fefe9, 0x218ffcbe, 0xefd91a88, + 0x71884b7a, 0xec5bfee2, 0x680d878e, 0x0822ac88, 0x3a78f140, 0x66428dda, 0x5b386053, 0xa0049d90, 0x9e792cab, + 0xbd2ff9e5, 0xce62c152, 0x51bd6a10, 0x0e8201ae, 0x3ef6d270, 0x4b628c82, 0x8db6f1fa, 0xb3e08a04, 0xd578c584, + 0x8d0c7c88, 0xee763f5f, 0xf112fed6, 0x70023e8e, 0xbc055a8b, 0xe39d65d9, 0x5d4f74f6, 0x54ca4e05, 0x1912502b, + 0x577ffe1a, 0x424f8603, 0xd5c28b4d, 0x9f53f517, 0x566a062c, 0xd637ccec, 0x5ffccbc2, 0x32c363dc, 0x256f87d7, + 0x03c65c78, 0x2e47c40f, 0xbddc80b5, 0xd2989a36, 0x467503d0, 0x328ddf9b, 0x07733e95, 0x57b22002, 0xd4ee77cd, + 0xada4a0f9, 0x9f8083dd, 0x63fb87e5, 0x5ae93fa0, 0x4ddcc2ef, 0x4e27264a, 0x2f885eef, 0x2dbe424d, 0x9ca84b82, + 0x4d175acf, 0x1d2dd51f, 0xea9e616f, 0x1f05f00f, 0x31ac773e, 0x09e9f0e9, 0x6437b1a1, 0xf1cafe79, 0xe8afcbcd, + 0x81ac11fd, 0xff265cb4, 0x747a9040, 0x0d3057df, 0xff675ff0, 0x90107ca4, 0xa3f82ecb, 0x0e875c07, 0xcdb2a09c, + 0x5729b68c, 0x9746f07b, 0x5945984e, 0xb4ace5b7, 0x30a39b7e, 0x9927810f, 0x7213c11c, 0xdebf8910, 0x2ac59272, + 0xf4a803a4, 0x55d1993d, 0x3411a373, 0xf89a8453, 0x21126e02, 0xc4baf51d, 0x445bf559, 0xa6b2eafd, 0x9febc936, + 0xbff7bab7, 0xeaae3f55, 0x60f8705e, 0xf8c734db, 0x4cd67c1e, 0x7ae1ad3c, 0xb0e0a7bd, 0xeedf5ac3, 0x334bfa9e, + 0x88615d44, 0xa4e2f710, 0x100e8607, 0x79d04136, 0xd3c92f12, 0x275b1d46, 0x8def09de, 0xbc4cdcdd, 0xfca9d2c3, + 0x7c37fcd9, 0x0b5ff327, 0xa00042f6, 0x842513c6, 0xb5a6325c, 0x6faebc20, 0x1793549b, 0x95cb26c4, 0xf78c2458, + 0x4c57c531, 0xf2333eac, 0x49fef84c, 0x08b73267, 0x5ca545ac, 0xe30ec3dd, 0xfcee373b, 0xf1ca30fd, 0x7b5b124f, + 0x0ce31faa, 0xd7f6653c, 0x197d9beb, 0xbb44fc9a, 0x03d76b46, 0x2774a9ef, 0xdf70259d, 0x9f23e6bb, 0x31367652, + 0xd76c6222, 0x34a4d622, 0x527e1980, 0x59fcd00e, 0xc802b7f0, 0x1918a251, 0x3e7fde45, 0xca05469f, 0x3dc152e9, + 0x0a0f1d07, 0x69b6a623, 0xd2a9488e, 0x27580af7, 0xe3532beb, 0x552fdebc, 0xaea1bf49, 0x2dc8a9d4, 0x5e4e5294, + 0x7fced637, 0x76b75734, 0x9219d0f2, 0x230f850a, 0x1a5ae9a3, 0x65d24cfc, 0xaa0bf447, 0xa85bd031, 0xb4df13b7, + 0x425c40c0, 0x6ade1c77, 0xa5a511d8, 0x08b6d130, 0x32d7e284, 0xaf599b52, 0xb1ea33a3, 0x91ba5ba2, 0x7ade4ec4, + 0xd54b3a2c, 0xfd20ba05, 0x0e557e7c, 0x3c767c5b, 0x87b861ad, 0x2c4fadae, 0xcbb0be26, 0x94a6d7b5, 0x99b05fda, + 0x13b38f95, 0x0fb5a441, 0x4246e1ca, 0xdbc0a75b, 0xd3233338, 0x1210c28e, 0x55384ae4, 0x9690d80a, 0x42a33870, + 0xf6a0aac6, 0x20bf93d0, 0x4afc9aee, 0xfd95f236, 0xe68d00db, 0x90c41692, 0xcbd74a56, 0x143574fa, 0xa8d2c327, + 0x804f21b1, 0x6cff0ede, 0x5e4d5878, 0x22c3bfd8, 0x78d8d64c, 0x7e6f8bcc, 0x1c19b1ce, 0x035711aa, 0xdf51a269, + 0xc72fb752, 0xd797b582, 0xfc19b17a, 0x019562a9, 0xf7a784e5, 0xfaddf288, 0xbf2129c4, 0x70a8915a, 0x497a1093, + 0x99f9458a, 0xbaeca4c1, 0x6a68d7e6, 0xf1c12234, 0x46e4e9c2, 0x46630cfa, 0xa161c6c1, 0xbbfeff4f, 0x4d9ef07b, + 0x06016712, 0xe64e3dc7, 0xc6124a47, 0x5bcf3336, 0xf9d64915, 0x1f0fe09f, 0xdbde3d62, 0x634e690a, 0xcbd462e4, + 0x28f79a0b, 0xd723f7d1, 0x16529e1e, 0x5d7dd925, 0x49373d29, 0x4f40a009, 0x7c335140, 0x3604be34, 0x17bff1dc, + 0x49a6568b, 0x403c99eb, 0xe148f6ff, 0x362ec0db, 0xd0db8587, 0x63883c35, 0x49fbb21a, 0x631b6d25, 0x5b76ad47, + 0x7af89cc2, 0x8afee6c9, 0xb3ecd63e, 0xbdabe34a, 0x417d33f0, 0xc2953c02, 0x9b6499ce, 0xd4b55874, 0x52691d3f, + 0xa649468f, 0x05afbf43, 0x46135e23, 0x1caf1831, 0xe8982908, 0xece5e393, 0xc3a85826, 0x5677f377, 0xc9adfe91, + 0x3ba9ac1f, 0x1586dcfa, 0xd3773ccf, 0x0dd5d16c, 0x5c4b2e98, 0x7465c95a, 0x3a24403f, 0x0ae42cc4, 0xcfb6d377, + 0xc0136c11, 0xb86375b9, 0xed8f3cef, 0xc507145b, 0xd967edf5, 0x64ea0fd3, 0xa02ec3df, 0x8d5806c0, 0x344575bb, + 0x165cb05c, 0xfa5a65d0, 0x76ebc667, 0x28536dd2, 0x4e02582d, 0x75205d81, 0x3b8b94d6, 0xb1e5cde6, 0x29053fc2, + 0x452253c7, 0x2a8c3b87, 0x3e752f7c, 0x3e8cc1af, 0xb0ab88fd, 0x49cf8c12, 0x015dcf04, 0xb7142e2b, 0x5dc97dc4, + 0xc3b0f586, 0x207399dc, 0xfe39d1c2, 0x3c88ab77, 0xa1aeb0cd, 0xe3013377, 0x69499e0d, 0xe00b5d03, 0x4d528ca0, + 0x8e2c5ac4, 0x29312597, 0x0f423460, 0x652af490, 0x6b765f21, 0x90cf804f, 0x74579a5b, 0x85b7807a, 0xd5d810be, + 0xe842fe33, 0xcca2cf25, 0x569ea383, 0x509587f3, 0xf5d6d87c, 0x0955d70a, 0xa7446174, 0x7119b485, 0xab058b38, + 0x3023fe6a, 0xbfc287c2, 0x6e843bdd, 0x711e0be0, 0xe0e71a8b, 0xee2d095a, 0x7fa65a7e, 0x88a02eec, 0x85f81aa2, + 0x7e1c7b07, 0xa42812bc, 0xa1dd8fba, 0x8938cc97, 0x8a2f8436, 0x5c1a0068, 0x86b42e85, 0x6716843b, 0x38233436, + 0x9288a9ab, 0x9e5eb7cc, 0x05299e5f, 0xf3390969, 0xbd57fb6b, 0xab0f9510, 0x6ddadf39, 0x247363a0, 0x74a22226, + 0x900aa988, 0x4a152d98, 0x3b557d3c, 0xcdd7eb2a, 0x941414e7, 0x30711f90, 0x7172ac13, 0xe10dfece, 0x9dbb1a72, + 0xc91a834a, 0xb19c2b9f, 0xa0d0c72a, 0x43e56020, 0x802b30c1, 0x36eae163, 0xcd53666f, 0xfa2a7d83, 0x956cd887, + 0xe4052d10, 0x2ebc7387, 0x5d2b0212, 0xc0b70b9f, 0xc968009a, 0x9d7311f6, 0x3c7a5091, 0x3c2e0f9c, 0x5b1ad6ce, + 0xd5e90b7f, 0x3b92d642, 0xc8e560ad, 0x270a07ce, 0x41c8bdbc, 0x5c6dc1dd, 0x4c51daf2, 0xf6ecd87a, 0x5430bb76, + 0x777ca023, 0x51592470, 0x7b681a66, 0xdc762103, 0x9e201553, 0x653b4cef, 0x3c5a2928, 0x4ec0c0a7, 0x5fe34755, + 0x4df0f9bb, 0x96c0c5d3, 0x52152ef9, 0x357745bc, 0x590d5160, 0x18908f46, 0xafa8c567, 0x1ff0f769, 0xb803cf6d, + 0x79e1592e, 0xe00e7d32, 0xfdcf696b, 0x7038d23a, 0xbbebb20d, 0x791780a7, 0x527ea25d, 0x00d6c12a, 0x73b1818d, + 0xcd8967e9, 0x0b0b0748, 0x8b1f2b9e, 0x0539d420, 0xfb24204d, 0x2e31dff6, 0x30764f6c, 0x9feea4e2, 0x335b44ec, + 0xd046109c, 0xb55d43dc, 0xa55a2fe8, 0x92d3d388, 0x1c59ba45, 0x671044e0, 0x15fb1012, 0x3cc726df, 0xdee53e0c, + 0xbeac677f, 0x810e9ed4, 0x6ddaebb1, 0x6bbda9cc, 0xa98e3de5, 0xcee2f728, 0x44f190f9, 0xf4f234ac, 0xdc596212, + 0x8afec2f8, 0x5aaa4164, 0x17ec0af3, 0xbc8f11da, 0xbbf5bd21, 0xcd2c9225, 0x0f53ffcd, 0xdb84fd35, 0x1e6548ea, + 0x241120fd, 0xa7b9da43, 0x75b5bc92, 0x646cd63f, 0x35a1fdd6, 0x33198ba7, 0xc7f0611b, 0x331b8f5f, 0x716eb844, + 0x3a5c552d, 0xdf8eeb60, 0xb3f81b8a, 0xec27b981, 0x1a3e7d8d, 0xa81f5969, 0xc2575ae8, 0xa4ca18e4, 0x854d1655, + 0xad365c40, 0xf58a938c, 0x4b4e9955, 0xc5c8e131, 0x8ba04604, 0xe07d804c, 0x2bf13605, 0x3269c340, 0x8bd1abf6, + 0xa48c3135, 0x383b593e, 0xacfdf499, 0x9a8bc363, 0x3f2a964d, 0xa4b2b050, 0x6e24b43a, 0x1e670818, 0x3b7b2680, + 0x177379b7, 0xdc9f528e, 0x407dbed7, 0x249b2246, 0xd8607643, 0xab443d21, 0xb6d33e1d, 0x1e33dc17, 0x142033fd, + 0x516eb5bf, 0x5a429a7a, 0x5522a765, 0xc39d8c18, 0xb15a0f3e, 0xf0a0de31, 0x0dd001f4, 0x1fef17ae, 0x6d2500d0, + 0x7e40ac4b, 0x24f3344d, 0x900cd6c8, 0x338c00b4, 0x72bac7bb, 0x6b87d236, 0x3b883e52, 0x706886ee, 0xed50c7de, + 0xe65f29f4, 0x7d9fbdef, 0xdd4f7e65, 0x34de26d0, 0x97441a16, 0x9159a795, 0x0fae15cb, 0x9140f11f, 0xabaecfcb, + 0x13838fa6, 0x55ef1fba, 0xf447ebed, 0x92b0a756, 0x5e6b4960, 0xe8b1c163, 0xd94ec911, 0x50ea733c, 0xeb9966f9, + 0x6baea638, 0x44045d54, 0x54e44fac, 0xec781e08, 0xe37bac57, 0x0f7c9815, 0xdd067ac0, 0xbc238ec7, 0x91d08a1d, + 0x51958a21, 0x534e831b, 0x787c0245, 0x26117fb2, 0x2373993b, 0x7032ad0e, 0x5b98b6aa, 0x2a435255, 0xe6c7ca25, + 0x77d1cd4f, 0x0eff4d79, 0x47bc6fbc, 0xc613fa99, 0x9e1fde08, 0x5bf322d1, 0xf2a74826, 0x8d186180, 0xe7844710, + 0x1fb72b3d, 0x84c74502, 0x6630c1f0, 0x7040e421, 0xee98904a, 0xe99eab38, 0x1c59c109, 0x413df024, 0xce560360, + 0x266c8160, 0x3f7f41ce, 0xfe63b55a, 0x151f0e1f, 0x1283ac89, 0x60c55fb3, 0xabc46267, 0x0c9b7499, 0x7c3d163c, + 0x1b9f529f, 0x19856782, 0x0114401c, 0x920d7be7, 0x4a3ff27d, 0xf0e95a45, 0xb9ade3e0, 0x1bd681a1, 0x0b0285ff, + 0xebf50796, 0x94a86b20, 0xcdc1c3c6, 0x110cbb5f, 0x8b7f555e, 0x22124b87, 0xd3f6f522, 0x52a4f702, 0x1a272c94, + 0x056618cc, 0x5252338a, 0x98f71085, 0x0f38df4e, 0x6db2a233, 0xf924e2b5, 0x570a124b, 0x365c7d20, 0xb5de007b, + 0xf5ec8942, 0xeabfdae3, 0xd25aed9e, 0x4c518176, 0x42fefdf4, 0x347d6ed8, 0x8ac76b46, 0x61c797f9, 0xa56cd513, + 0xd37486d5, 0x64ee9366, 0x6b2c604a, 0x6fb242e3, 0xff6a3122, 0x8a51ac4d, 0x903d7d1f, 0x9e417136, 0x0af903df, + 0x20a43b38, 0xd6520cbe, 0x5d6ae915, 0x3299b26c, 0x87648bb2, 0x6915c7fe, 0x03c976fa, 0xff2cbd4d, 0x4021db58, + 0xf0257366, 0xdc1f55e6, 0xfa9503c0, 0x62ca14c7, 0xf1582f97, 0x3db2ab0b, 0xaf2fb67e, 0x7a589963, 0xbe5857f7, + 0x35e8834c, 0xd5d04154, 0x69a482a2, 0xef90c92a, 0x8a6e6ded, 0x546b537a, 0x84a770ac, 0x30289a2a, 0x45a485b8, + 0x93a06ac2, 0x45a14bb2, 0xfaca9b96, 0x4189dbd1, 0xdada2cbc, 0x6a313728, 0xbc4c815f, 0xd933aa7c, 0x36e7709f, + 0xe0f3299f, 0x121f1997, 0xcfda8447, 0xa5bc8f2d, 0xee4b3d74, 0x3d341f6b, 0x8da5a3c7, 0xcc7408ae, 0x76be7dad, + 0x11fe7640, 0xf1143363, 0x0e0f2e38, 0xb1cd5750, 0x9d2cfdb9, 0xbfeaf8a5, 0xa4024893, 0x167836c9, 0x8fab6a9c, + 0xb3d459a3, 0xe1efee5a, 0x2e66d7e7, 0x5bc01122, 0x0337d111, 0xe1c6bc30, 0x915fd2ff, 0xb52afb66, 0x195a1179, + 0x4eee7668, 0xb704c032, 0xd2761a1c, 0x7bf0dc21, 0xb68bab03, 0xa2ef01fe, 0x49c6d0b3, 0xef040349, 0xb85d91d2, + 0x08c6dd4d, 0x57cc66dd, 0x481d408e, 0x2199dc0c, 0x112cb98c, 0x6af0c9cc, 0x75e8af34, 0xc3f9e7a8, 0x6d9eb402, + 0xf76b5631, 0xec59e34b, 0xfb94907c, 0xa12ced61, 0x647482a3, 0x46fe1bda, 0xdcd0336c, 0x2e2b40cd, 0x03606d9c, + 0xcd896b04, 0xdde5681c, 0x85be80b7, 0xb6b154ce, 0x1a1e9ff3, 0xdd9890f8, 0xf4338231, 0x2fef6516, 0x1b1e736c, + 0xc960509b, 0xe3bdf708, 0xde597abb, 0x4147c2bc, 0x8900e047, 0x7313b6c3, 0xb89485b4, 0xff7d6548, 0x75f3b467, + 0xa5eaeff1, 0x502706e2, 0x7e927728, 0x605f9917, 0x2fa6ec6a, 0x6db78fb5, 0xee96f89a, 0x084ecd2d, 0x0a6bdd07, + 0x5e4f10b3, 0x0c013464, 0xb7e88b93, 0x010d7fbe, 0xc71e4508, 0x9716888f, 0xd04a9414, 0x8313feff, 0x087875f9, + 0x6c6af5f4, 0x0d2d94b3, 0x3d111b61, 0xb992814e, 0x13c46407, 0xd18c29a7, 0x830f9cb7, 0x8ad8e005, 0x8ef74e68, + 0x3ef0a4f9, 0x344a430b, 0x9f4e6b41, 0x19de4c3d, 0xe1e69feb, 0xcaecb8c5, 0x94724f20, 0xb362dd00, 0x01295ba6, + 0xc6d78acd, 0xe51806cc, 0x44a8ba6f, 0x4bb54086, 0xc30aa6e4, 0xb85e57c5, 0x031b5617, 0x601f7498, 0x4a47d88c, + 0x096a2c86, 0xef91f323, 0xca4bbd1f, 0x7de77f70, 0xd2d4a807, 0x1c5f0b7a, 0x9499cb04, 0xe677baed, 0x8040f2c3, + 0x1c463417, 0xbfedca0c, 0x2d5e9393, 0xac4b22d4, 0x7521bc7f, 0x0834eff5, 0x37aca8d2, 0x3529bdaa, 0xb89a433f, + 0x09240e2d, 0x206b6e63, 0x211c2cb8, 0xbc56530c, 0xca0e80bb, 0xd23a89db, 0x338d4d43, 0x0e170246, 0xc814ffa6, + 0x56c7a364, 0x01a7a20e, 0x54215379, 0xfccd0e3a, 0x85eff44a, 0xe4ea3c50, 0x0382f643, 0xc0a03134, 0xb09301f0, + 0x046187ed, 0x4c04b4af, 0x5366f0c6, 0x04cd6a45, 0xc3bf9598, 0x659a01a8, 0x31ed5b8f, 0x82452244, 0x8782b46f, + 0xa1497101, 0xf6a939bc, 0xc65785e9, 0x7bd2a3e7, 0xa5f8b60e, 0x3c948a4f, 0x22b84959, 0xea068562, 0xd165c55a, + 0x9da710df, 0xc64764f8, 0x40ffcff9, 0x9bda9514, 0x1ea9b9a7, 0xdfd44152, 0x0e0fe17f, 0xca1fbe46, 0xe04b1b6e, + 0xbd8ed71c, 0x40c51465, 0xa91d0481, 0xadf56e7d, 0x30e19f47, 0xb11d70b8, 0x0e1d2a52, 0x7cfd39fc, 0x3252750b, + 0x13cd2834, 0x761e2a79, 0x92fec7dc, 0xcee7aa9f, 0x4b63a14a, 0x1f35ee89, 0x35e642a8, 0x4940a569, 0x439bec80, + 0x07a67fb6, 0x76b403e5, 0xd7468a3e, 0xa5b4eb9c, 0x86f7a0ac, 0xe0754b2d, 0x8bef2a0d, 0xa76c2df0, 0xfefae46c, + 0xe7689e0b, 0xde4832f2, 0x62ce44f7, 0x00e1e91b, 0x4c213b88, 0x1cac6999, 0xd3420f94, 0x549d5d96, 0xac010cab, + 0xd19b405c, 0x1e0a38d5, 0x805edd1a, 0x30592a2a, 0x56efa8b1, 0xd9da7c71, 0x2001029a, 0x4a15149d, 0x0608c608, + 0x0d80b919, 0x913fee6e, 0xeac942be, 0xc5e01e1a, 0xd2de70e4, 0x61b75dac, 0x0d5a171d, 0xffc277a4, 0x46477fef, + 0xff9a5d8a, 0x06be8411, 0x11217459, 0x99e1cfe4, 0x453bbeb5, 0x4fa2c078, 0xdb2fc991, 0xbde91bca, 0x51852e5a, + 0x2f88110f, 0xa29661af, 0xab95ff23, 0x43ed0b5a, 0xcc6a21ff, 0x568c09cf, 0x7a984c27, 0xf6857d0e, 0x3bbd2c73, + 0xf348b8ea, 0x3ae9dbff, 0x73135c16, 0xaf038886, 0xabac2ae4, 0xc6872b1b, 0x7448515e, 0x8c30fd43, 0x249e359b, + 0xc0b7cf15, 0x67434cbb, 0xcc24787d, 0xe8362746, 0x8fb113bf, 0x7c9576f9, 0x4f454cbe, 0x307153b6, 0x22df5205, + 0xad2f67ac, 0xeaee0baa, 0x54799be1, 0x7d9bb0f0, 0x682afe1b, 0x2dc60d66, 0x0ce36ef5, 0x3ddd9cd8, 0xa18fb5b8, + 0xba7e02a5, 0x69e3a371, 0x08d70c9f, 0x03a877b5, 0xbb2052fe, 0x4ec6c573, 0x39a743f5, 0x24393392, 0x09a133e9, + 0x18d4994e, 0x6d95b6ae, 0x7bfac543, 0xbba37511, 0xc6c68be8, 0xa7cc1f46, 0x60b17a88, 0xbf67466c, 0xedbe8277, + 0xbeae5afc, 0x3a3eac7f, 0x2689d962, 0xf8cb6fd4, 0x485a040b, 0xabfe6a7e, 0x756855fb, 0xdc21d7fe, 0xbd081152, + 0xd487185f, 0xb051a998, 0xebbb76c0, 0x8153dd94, 0x8706ae12, 0x918796ef, 0xfad4b404, 0x45471424, 0x5858659c, + 0x966ec938, 0x08b29193, 0x7f89f79b, 0x906def4b, 0xedbfc08f, 0x5bd9caee, 0x225c5b72, 0x5350ed89, 0xd803d69a, + 0xc30a7c09, 0x46ea6282, 0x738dfbfd, 0xaf07ff78, 0x9cbf0684, 0x02d1ff08, 0x8aa5ca46, 0x1e881c1f, 0xedf49303, + 0x50546435, 0x32011b68, 0x19952d0c, 0x0f2cdbcf, 0x745a26eb, 0xe86451ec, 0x249e42c2, 0x20bf9854, 0x08001467, + 0x1c25628b, 0x82a9facc, 0x826c1736, 0xd6c733db, 0x34229fc8, 0xe46367b9, 0xcfe1e63c, 0x1c993ee8, 0x735ce771, + 0x7b48cbe7, 0x385b945e, 0xe78e7868, 0xa0131e50, 0x962c722f, 0x9ae955d2, 0xd811c4b6, 0x20f5235c, 0x75c755c3, + 0x905f0585, 0xd9eb0cb1, 0xdc6a8a10, 0x3bca1a4d, 0x43b795a2, 0x7cd72a6e, 0x21707ff6, 0xeab3cdb3, 0x080bf793, + 0x135c918d, 0x0d0ba626, 0xd6c4bbd9, 0x4ac175c4, 0x9fc6cade, 0x1d9fcfff, 0x64ada5d6, 0x006dd0ab, 0x5c4162db, + 0x6463372b, 0x54e7863c, 0xd6fb22ff, 0x1c3c9634, 0x05d185e6, 0x3797b40e, 0x016737d7, 0x30285e4c, 0xedfe8ede, + 0xc4ab3d19, 0x8139ff55, 0x3a96a852, 0x261d4007, 0x057ca55b, 0x76fb94c6, 0x32b63213, 0xb27d5087, 0x9e9339d7, + 0xcf967fcb, 0xbec08902, 0x3430601d, 0x9f7cfd76, 0xfcbbc73c, 0xbdf33da2, 0x6684200e, 0x6a2fb4db, 0x8191bfc9, + 0x15cbf901, 0x0df3934e, 0x6c9f3e5a, 0x11d43309, 0xcb5004d9, 0x4c58fe5d, 0x7fe72de0, 0x947a71fd, 0x301ae2e6, + 0x3054328b, 0xa00d2fe5, 0xafe97619, 0x09d91427, 0x3af7da44, 0xa82b6013, 0xb92c7dc8, 0xb70c8834, 0x1fb4792a, + 0x2127c1d3, 0x7b5236ee, 0xb82db647, 0xa5ab1f31, 0x5824dd76, 0xd36471a2, 0xbb88e4e3, 0xada158ea, 0x787e33ae, + 0xa62b92a3, 0x4ead4b00, 0x9c7b12bd, 0x9c3fface, 0x6413c9a0, 0x1a1fdcc4, 0xcbe9159e, 0x0da320db, 0x7cc135bd, + 0x2d6a0421, 0x4d124b21, 0x8b3d7c82, 0x57600b57, 0xaab83df1, 0xf367fde7, 0x72922086, 0x304031ea, 0x80286ff4, + 0x2bd7ccd3, 0x9fe57af6, 0x56ba7275, 0xf4bcfd74, 0x34d3335d, 0x282dfe0f, 0x2cd7c732, 0x49a2d381, 0x6ef1b6c6, + 0x1bc91bd3, 0xb9fdec55, 0xa90db0ea, 0x44f45eee, 0x12e49ce4, 0x0f0dfbca, 0x347690f7, 0x85d03a18, 0xc59d33ea, + 0xe084aea8, 0x43f23af1, 0xd7f5434c, 0xf939eba4, 0xb831cab7, 0x5e6fe676, 0x12b2cd37, 0xa958985c, 0x6c50a974, + 0xd714bd2a, 0xf1f99bfd, 0xa736fa24, 0x67ccf2f8, 0x6f14237d, 0xa6b559ee, 0x05168bc9, 0x81cbf1b6, 0x5674203a, + 0xf49b737f, 0x6672522d, 0x173572aa, 0xab848069, 0xf43fc75e, 0x394d8a18, 0xe9724d4c, 0xeeb15b49, 0x9caa2d4d, + 0xb51486de, 0x6a064598, 0x80c183f5, 0x3aa21f88, 0x38a9d954, 0x78b589c1, 0x39baddc9, 0xcd7f0e96, 0x3d284167, + 0x7a2eaba6, 0x5a74dcc0, 0x618d339e, 0x7dad1fbd, 0xbbf1590c, 0xe9035c1b, 0x0d058634, 0xe85f3612, 0x43afcfd6, + 0x64430627, 0xacedd66e, 0xf924ce99, 0x3c36597e, 0xfef5f441, 0x15fad2f4, 0x97c6cd4d, 0x670c344d, 0xc704d3cb, + 0x8e4e94e6, 0xb568b30f, 0x461a9a38, 0x0714d13f, 0x011a85b1, 0x927413eb, 0x049f8f69, 0x5b2a06dc, 0x930bc50e, + 0x08431d5f, 0x980e6dd2, 0xd82f6b82, 0x076e499e, 0x54a1d06f, 0x9f9c0325, 0xd9124779, 0x7658400b, 0xc8abafa9, + 0xc7711046, 0xc1df70be, 0xaea1866b, 0xed131528, 0x345a5026, 0xdf27ad57, 0x0a0bf840, 0x6363b2f1, 0xf881a036, + 0xdaf7a19f, 0xa1d72fac, 0x4455e7c1, 0xcec0bf51, 0x4a92a69f, 0x3fe01443, 0xae43098d, 0x52c7376e, 0x8bf376cb, + 0x063a9f2e, 0x8a8ee4b1, 0xf7f97772, 0x4cb6bd6d, 0x665947a9, 0x34a74c25, 0x3f61f6a9, 0xecb439ee, 0x3c670c25, + 0x5c947a03, 0xedf543f7, 0x56d4c891, 0x8ac76ee5, 0xce0a3699, 0xe42f2041, 0x833e4362, 0xbc2ee1c6, 0x1473415f, + 0xb53e9c9a, 0xa789df86, 0x6a3e15c3, 0x868d751a, 0x35731ef2, 0x56378471, 0x903e5f12, 0x2de7fe9a, 0xb559f68f, + 0x0e35fe12, 0xf1c0f3bf, 0xe631f85e, 0x615c33ed, 0x3a4a7ceb, 0xc976fb59, 0x6f79abde, 0x07d40761, 0x0b5eee5d, + 0x7afea7e4, 0xed8dd845, 0x79fb940d, 0x334769f1, 0x09d27e03, 0xcf611b9c, 0x70ee8cdc, 0x39ef6f8e, 0x7d245bf5, + 0x9fb5554c, 0x5ae998c0, 0x022023be, 0x2e3d690d, 0xa6d6778d, 0xaaed0c9c, 0xf0389d4a, 0x8f049271, 0xb1493d23, + 0xc9c94142, 0xeb71de1b, 0x53e2528a, 0xf4bd831a, 0x4960138d, 0xaf82af50, 0x6dea89ac, 0xaf27b8bb, 0x8d32da97, + 0x7942f5c9, 0xd041e6a2, 0x9763755c, 0xb005051a, 0xfec5872b, 0xe15cab1a, 0x067d681e, 0x37c6f02f, 0xff06ec78, + 0xe5a6a957, 0x984ecd7a, 0x62d70f9f, 0x9c65c97e, 0x1049552f, 0x9e7441aa, 0xc9580b6e, 0x15e47404, 0x8b428278, + 0x33e1075f, 0x3b1cd324, 0xc8c7c6fd, 0x847d8805, 0x6c6025f7, 0x145c6b0d, 0xf49ff4f5, 0xe9c50f43, 0x75b73e30, + 0x7b5203b4, 0xd7c6df77, 0x4357c665, 0xff1078a4, 0x9593adb7, 0x3885a969, 0x2d74bf96, 0xcbe6a5ae, 0x4b544ce3, + 0xa09c6e71, 0xa34d9eb1, 0xa1a05a4a, 0xbd8830a6, 0x80484633, 0x40d552e9, 0x416d9e1b, 0xb50733a0, 0x8a6fb163, + 0xc6d066e7, 0x9d683cda, 0xf745b6f9, 0x823776d4, 0x61a3da19, 0x40232c3c, 0xcbc7553e, 0x55094daf, 0xf7d9b95e, + 0x3efc8aad, 0x45367338, 0x77da11de, 0xa9092de2, 0xfa9a6892, 0xcda09162, 0xd22b25c4, 0xcfa9eb75, 0xb1bdb818, + 0x385685fd, 0xb4080a06, 0x81c98410, 0xf7f24967, 0x5af56fe4, 0xea41ff59, 0xccbac71d, 0x6f589cb2, 0x872821b9, + 0x6a406972, 0x41f39196, 0x5f7ec377, 0x9bc8de46, 0x8d561be7, 0x6898ed64, 0xffeb234e, 0x0e3a35fd, 0x9813aea3, + 0x1a365b62, 0x95415f05, 0x561d3a75, 0xa26a7752, 0x1a4ebf2f, 0x8e850a41, 0x25987af0, 0x8f3fae91, 0x14263e26, + 0x0015daff, 0xc086360a, 0xf249fe18, 0x8e3633b4, 0x9c8d6b3b, 0x6e66ebef, 0x436dc937, 0xa7c6dc2f, 0x1fb7cf5b, + 0x00e4f240, 0x44e086de, 0xb6431175, 0xeb8eb1cf, 0x6cab6a7c, 0x08f88ea9, 0xc2bd4e40, 0x0f06f1c0, 0x956ea9b9, + 0x4bec2ae6, 0xbe3f8807, 0x6509b8a0, 0xf73486c1, 0xcc881820, 0x91bb0aba, 0x015fe6e8, 0x01e5293b, 0xd65d0d96, + 0xf3557321, 0xdab6241a, 0x33c695e8, 0x03d236b5, 0xbaa5e8c8, 0xe2f25374, 0x7144ee99, 0x6df1dc7b, 0x023f0e64, + 0x8b954c2b, 0x18152efd, 0x9de3c1d0, 0xe4b0e327, 0xeb905b44, 0x57ff8c1c, 0xfd7b3db5, 0x7bc79c68, 0x8906c53a, + 0x77509ce3, 0x684c9c93, 0x7b940c52, 0x717baf3b, 0xf7ee5b74, 0x74ff2808, 0x50949ece, 0xcdb12fa5, 0x9ee909da, + 0xf9f7c5d9, 0x82f8331a, 0x018234da, 0xb0776649, 0xabb80f7b, 0x5795e9f8, 0xe7f954c7, 0x6c22bc7e, 0xf16e8a12, + 0xf7ba7935, 0x63683430, 0xbf92c3b9, 0x95a11201, 0xa9bdfb1a, 0x294cf43f, 0xfcf05609, 0xef6776f9, 0xf20e7063, + 0x690f8edc, 0x1a67aedb, 0xfe355c71, 0x9aef7fc6, 0x8c447aae, 0x10d0aeda, 0x50781bf7, 0x7b84ec28, 0x60ef2fa3, + 0xa0c5e14d, 0x9f73ede8, 0x6ace77dd, 0xdee9c7a1, 0xc0e414d2, 0xdea9ccd2, 0x7554089e, 0x50cba24e, 0x97ba9ea7, + 0x6b354643, 0x6d5b5e67, 0x3063826a, 0xa9c29b16, 0x981e5c1e, 0xc1258d7a, 0xc8ec50c2, 0x750aba6d, 0x6be8a48e, + 0xfe4e061a, 0x830c2a31, 0x86d7ea85, 0x7bbca1c5, 0x63fa447b, 0xb2f81ec5, 0x51935694, 0x3a180c41, 0x17c890b7, + 0x58c55a40, 0x019dad7a, 0x88f49d8d, 0x0ba3c291, 0xd537ee62, 0xf99edf9e, 0xcfef515b, 0x969e37c2, 0x060d0c54, + 0x1a0537da, 0xf451904a, 0xdd06b3f4, 0xc6622247, 0x926941a0, 0xb1e721a5, 0x78b728ac, 0xc2fcf076, 0x8557e807, + 0xdcd1c96f, 0x2faa6c2a, 0x2942fc74, 0x03ecabc8, 0x3a350dcd, 0x90d3e059, 0x42933204, 0x82035320, 0x5678f2eb, + 0x3882cec0, 0x01abc911, 0xd9d94c48, 0x74b0df51, 0x534206d8, 0xdc5a7a92, 0xd2845f9b, 0x0f1c922c, 0xe2ea1f20, + 0x78f63026, 0xb8c71601, 0xc633b1f7, 0xff25c98c, 0xd3d337fc, 0x2b6cb732, 0x4c8050d7, 0xbf1b5a9b, 0x419c5c8c, + 0x8b9e62f3, 0x8eef623c, 0x898f6f3b, 0xe5e46be4, 0x23aacc48, 0x0384b95b, 0x8631c2a3, 0xba6ac768, 0x3c43345b, + 0x47c24d23, 0x9f07ab54, 0xa9cadfa4, 0xcbafce4b, 0x52de3c34, 0x92506c1c, 0x79d5b89c, 0x3dae5655, 0x99b3049e, + 0xca7b577f, 0x3fbb4864, 0x98d7599e, 0xafa0d14d, 0xa691c39f, 0xa7f708b9, 0x5bfeeddd, 0xf91e4f27, 0x200a336e, + 0x9a2831cb, 0x927a94a9, 0x4df54461, 0x47dc9733, 0xe6d19806, 0x1e85d269, 0x2cd421ad, 0x1559df84, 0xfa924dab, + 0x71455685, 0xe4ba670a, 0xebbb8b76, 0x63c8a836, 0x8109b83f, 0xd852568d, 0xf5c1d181, 0x9d609edf, 0xdc58b09a, + 0xa226227f, 0x65e79ee7, 0x6b7d7a5a, 0x51dd1928, 0xd2746d51, 0x754a0250, 0xc34e2ba5, 0x0f5dd2e2, 0x653c1245, + 0x1b913779, 0x389480c2, 0x67e29405, 0xa2f0074e, 0x7d547492, 0x68177693, 0x38f91ae2, 0x9c3fa5fc, 0x898db343, + 0x3fcc7bb3, 0x1c189829, 0x6944271d, 0x5d17d517, 0x45c088ad, 0xa35f8fdf, 0x97fa7246, 0xa940b0cc, 0xb2714f3e, + 0x5adebafe, 0x206621bc, 0xc0770874, 0xc3db2034, 0x56e9a130, 0xec945147, 0x12c519ae, 0x79d6f5b3, 0xe4f1e39c, + 0x6bc43d2e, 0xcec34259, 0xb1c1db47, 0xa43b01af, 0x3f30f571, 0x6209ec77, 0xd4bb7b09, 0xf7c32239, 0x143ef471, + 0x902bb8ec, 0x5dbf1e74, 0xf8127da9, 0xda68e845, 0x6f5bb81d, 0x3f38bc84, 0xeef933e4, 0xfff76808, 0x6aeb9c23, + 0x524d8ef3, 0xa23010cf, 0xbbe13e8f, 0x98635939, 0xe42cf4c6, 0x2fa4ef42, 0xb665f8f8, 0x9a2cd1ca, 0x2d575446, + 0x57c86e4d, 0x9d5e4726, 0xb779fc64, 0xc35e604c, 0xd9bed6fc, 0x54709d31, 0x5d762a6d, 0x079051a0, 0xc1932944, + 0x27223f96, 0x9f158b89, 0x54b11964, 0xca2a1d30, 0xe65e4d41, 0xee60cef0, 0x782864a4, 0x310cab8f, 0x24feeb34, + 0x6a4a17cd, 0x0fb48cc1, 0x9a75f3ae, 0x0f803d1c, 0xd893b3e8, 0xefa2be7f, 0xc55a1808, 0xba90b6f0, 0x969bebdf, + 0x8292e97f, 0x9842afec, 0x651c0b56, 0x66dd57fa, 0xe0a533cb, 0xac383efe, 0x467376f8, 0x803c2de6, 0x7133ed34, + 0x178282b1, 0x7a11bc02, 0xa3dcecbc, 0x4ceb111c, 0xc275f55a, 0x2bce6344, 0x691ca494, 0xa33b3f8a, 0x913a585a, + 0x26118c11, 0xcf47533d, 0x6a40ca30, 0x224ad9e6, 0x4e602a02, 0x8c11301c, 0xe7b4b956, 0xc5fb8988, 0xa51e35b8, + 0x3d5aa5e6, 0xb3b49172, 0xfdff8484, 0xe2c16231, 0x5893053a, 0x671059ba, 0x61c86594, 0xf9219b72, 0x76dd8dee, + 0x346fbadf, 0x05d9b694, 0xf0d902a3, 0x98941330, 0x5deb2ecf, 0x2877995d, 0xcb30d134, 0xfda347ea, 0xfd67edcd, + 0x79bfa4ef, 0xd0381ddd, 0xd9896716, 0xbdbc3b50, 0x92fa59de, 0xfef2642f, 0x24153524, 0x9619c9a7, 0x8b85845b, + 0x2de0ddfc, 0x5ac58667, 0xf12743a2, 0xa82e39c6, 0x72e910c6, 0xeee41560, 0x23e5a677, 0xd3bcd8b5, 0x1def81fa, + 0xe47e8d32, 0x1efe067d, 0x1d4f21ed, 0x298f8438, 0x46d81284, 0xffdc874c, 0xc4361167, 0xd09d6229, 0x0add70c2, + 0x72afec40, 0x4866af63, 0xff52dac5, 0x6dd9c3ed, 0xc5a8eb47, 0x2783d661, 0x990e4926, 0x1ab028ef, 0xf8971e59, + 0x046bbd32, 0xeb04a641, 0x64e07e05, 0x7effa7fa, 0xe9760da2, 0x95a0b445, 0x3d02a676, 0x1bb6501f, 0x01e03dd8, + 0xe6c58b7b, 0x818cf30d, 0xf6ae4623, 0xc29db23e, 0x3c17fd86, 0x8b146c96, 0x1596c2ed, 0x68ebafe9, 0x61122179, + 0x090caaa4, 0x894addff, 0x8b0b3da4, 0x0d8dc3e3, 0xa1c78408, 0x6c98e209, 0x9338df91, 0xe9838879, 0xf0d27708, + 0xcc526dea, 0x16a9e61b, 0x048969d4, 0x487f8f74, 0xbf5b63a8, 0xea762fcf, 0xdb88d9ba, 0x4b2d2262, 0x2db6c9de, + 0xc75788ae, 0x87ab6750, 0x3433a56b, 0x68ca32f6, 0xd75e76dd, 0x8db4b6b7, 0x770fd2f0, 0xd14e87f8, 0x7c02a0e5, + 0xa5c70b22, 0xdce0b181, 0xe3affdaa, 0xe851f870, 0x58ab75d7, 0xc2eebea3, 0xe2cd4b1f, 0x00a7d7e0, 0x50c08121, + 0x635d3bd2, 0x68ead679, 0xb43b8906, 0x0e5e3f7c, 0x86b6d862, 0x72493fc3, 0x3de78dcd, 0x9756679e, 0xf8256cf0, + 0x0dc38952, 0xe9321a8e, 0x25d638ed, 0x36692d87, 0x5b7bc85d, 0x4c0d02f0, 0x9537e750, 0x4b483a8b, 0xcf5d310c, + 0xdfa780d0, 0x92e05046, 0xff403dd5, 0x21ddf108, 0x07cd1029, 0x07014762, 0xd040eedb, 0x84acc261, 0xf90fb460, + 0x647ffa99, 0x3bf7e8e7, 0xe838b4dd, 0xe5e8204b, 0x9ed15d00, 0x022c19e5, 0x0a0c1aba, 0x2a7580ae, 0xe775512a, + 0x78eed195, 0x1cc44793, 0xd27a56a0, 0x425c1967, 0x2929db09, 0x0872d1bc, 0x82ee4c1f, 0x0da5053d, 0x3337e5d7, + 0xe5efbcb1, 0xa726626e, 0x73ad850e, 0x0703a83a, 0x7a4db7cb, 0xc8b74b51, 0xdb3b3286, 0xdccd9d56, 0x2b9edea0, + 0xab7f7706, 0x8d39ab3c, 0xa7940459, 0x7e4cf342, 0x8a3ef196, 0x5772c85b, 0xdf75a35c, 0x2fb63ec5, 0xfb8e50d1, + 0x0b1b9640, 0xe0cc35ff, 0x71dd07c1, 0x4b9b82ee, 0x2b9fa065, 0xf4dbd91d, 0x3e1e59f1, 0xf3e364ef, 0x29954778, + 0x1fdb53b3, 0x9989defb, 0x5372e8af, 0x6c5d18e6, 0xbf4bffb2, 0xf48c5222, 0xcacbacad, 0x0106eaa6, 0x69976e4c, + 0x05194719, 0x4fb3ed4e, 0x21faf033, 0x043fda5d, 0x06a9e1e5, 0x930a0359, 0x2653c862, 0x3f97f472, 0xc689a0a6, + 0x524c5203, 0x52ab75b6, 0x4b654fc2, 0xb942ba0a, 0x1cbb7f1f, 0xbd7d6ed5, 0xc477c5af, 0xd7ee24f6, 0x060db34d, + 0x1287ca40, 0xff07ba1f, 0xe16e2d29, 0xc9808219, 0x03bbced5, 0xaa9e29b3, 0x1667b08b, 0x0c545aeb, 0xb028ff22, + 0xccb01c73, 0x36e38e92, 0xe22d6b37, 0x29604d6a, 0x70fc21d2, 0x897ec1c2, 0xb820d282, 0x80824f72, 0x93917ca4, + 0xe9a46018, 0x5c18e8ea, 0x08cc9ef4, 0xf6af90bc, 0xc7f7c6d6, 0x6c18d7a9, 0x77854d06, 0x55b68c92, 0xd6b154b7, + 0xfd8a2429, 0x54a7e405, 0xdc093ae2, 0x92b544ab, 0xc99d9b48, 0x832d22b8, 0x1ae6cc30, 0x8a8f3c13, 0xeef4f9fc, + 0x11e6e4be, 0xb7779016, 0x683bebc8, 0x98ea12a8, 0x19f5c471, 0x2300aae6, 0xb5bb4006, 0x0e799837, 0x233373df, + 0x45172638, 0x00b81fce, 0xf48ce52e, 0xe07c5e64, 0xeb84fbec, 0x1a7e2658, 0xa7c5213f, 0xc2311380, 0x4feee962, + 0xb6ac72e4, 0x402f9272, 0x47a16140, 0xa1119774, 0xe29aab19, 0x9484e460, 0xabf2773c, 0x565cfd12, 0xaaba2590, + 0x5ca24016, 0xd4324c20, 0x2df6ff9c, 0x5333f9f0, 0xe8c55507, 0xa391cd43, 0xb0a440a8, 0xe759932c, 0xeb6e5f93, + 0x4b48b5eb, 0x5d09cc01, 0x28c5a7fc, 0x492d7842, 0xf5fd0986, 0x24a91e25, 0xadeefebf, 0x9afda0e4, 0x6dd4cffd, + 0xcf84b584, 0x6c51c770, 0x8c026f60, 0x142dde15, 0xcc56157a, 0xba42bf23, 0xdd9a8ea2, 0x2a369c74, 0x458ac0c1, + 0xf7130805, 0x5ad7b606, 0xeb2158a2, 0xb2617b27, 0x4bdc12e9, 0xc7c6d5f8, 0xb0b58fbe, 0xb9ebd076, 0x9d82092b, + 0x884a63b7, 0x46d66fcf, 0xaa8c213b, 0xcda32fb1, 0x462f5e9a, 0xeb94a772, 0x79d2aee7, 0xe10eb3a6, 0x91a27494, + 0x6600b0d9, 0x0371198a, 0xdd16a1b0, 0x93141d46, 0x7fb783e0, 0x1fb48536, 0xc729b1e1, 0x04d6549d, 0x5f5db2eb, + 0xc03c102e, 0xfc4e6f1c, 0xe347c4eb, 0x29b7bae8, 0x799767e2, 0xfc8cf89c, 0xd3cdd9e8, 0xbe0ba16d, 0x5c1a54ce, + 0xef664aea, 0x29949733, 0x29da05b4, 0x729b52fb, 0xf7b811e4, 0xbc2dc476, 0x8b5576a1, 0x9866ab5b, 0xe1150550, + 0x6d98ef2c, 0x9d8c0abe, 0x09ec1358, 0x1ee3e7f4, 0x4dea5390, 0x1919dded, 0xce0a7db7, 0xff03e0d8, 0xb9c9c562, + 0x04ae093c, 0x4a78f447, 0xa97751fb, 0xf5705ce6, 0x86b02193, 0x77915bec, 0x72ac7d7a, 0x89229be3, 0x28c99679, + 0xdb7687e3, 0x9505a6b3, 0xaaf7356f, 0x37817fb0, 0xc1e3212a, 0x66f72cb4, 0x97478cc0, 0x2ef206e1, 0x4247dfda, + 0xd990246e, 0xcf9210d9, 0xe95455f2, 0x8023210c, 0x8363b25f, 0x7a7c0153, 0x745ff21b, 0xcb2921b2, 0xf8e6e0d0, + 0x6e4930a4, 0x41ceba8a, 0x508e4c01, 0x399288c5, 0xed302b47, 0xef9add29, 0x82e34268, 0x06480aa8, 0x20abbae5, + 0x7e384eaa, 0xc3515be6, 0xb4cafdd8, 0x45eade72, 0x04a304b7, 0xc19c51c3, 0xec5c278b, 0x6b489f50, 0xe6d8e3e4, + 0x28a27023, 0x4bfe708f, 0x9ef1a1da, 0x17571115, 0x995297be, 0x86fa7b2a, 0x586ca90f, 0xa8a33d0a, 0x957a5bc0, + 0x1f6ec0ad, 0x9ccd4eba, 0xdd1be0ea, 0x4a2336ce, 0x9b6c09f0, 0xabb45f92, 0x297ccfbb, 0xa012a59f, 0x425b795a, + 0x9224e1b5, 0xad489900, 0xf0a20d54, 0x2548cdde, 0xb822b9a4, 0x0b34e96a, 0x182ddff0, 0xad844615, 0x044e9119, + 0x7e9abb10, 0xb18e3e4b, 0xa00f8990, 0x191c870b, 0xa6c8baf5, 0xc218f97d, 0x49cf601e, 0x0f7d78bd, 0xb0612ef5, + 0xdf126cd1, 0x3597ad4d, 0x3451a9a4, 0x2b9fcf91, 0x653d2961, 0xd78e2b2e, 0xb31dc404, 0xed424bf9, 0x8e1ef750, + 0xcfedd2e4, 0xcbd2e611, 0x0c96d9d2, 0xa73de534, 0x2d1fc2c9, 0x347ba572, 0xb4913c5c, 0x191c36ff, 0xab6a5be3, + 0x260f9062, 0xda00ec6f, 0x78d64adf, 0x66b27f77, 0x5e8fbca5, 0x3b4b81df, 0x59867825, 0x2bd1ec1c, 0x38aad2fb, + 0xcba072ed, 0x025b67b9, 0xe0cb372c, 0xaf4c86bb, 0xd69175c6, 0xa541099a, 0x76010075, 0x260a76c3, 0xe2a6af3f, + 0xeda0ab05, 0xe9791f15, 0x94f956c1, 0xbc427d3b, 0xbd01dfb5, 0xd0dbf86d, 0x88abc308, 0x6d8cff6e, 0x16442c08, + 0xf7e5320e, 0x67c23692, 0xa6064baf, 0xd247772b, 0xe19e5a08, 0x707b9d0f, 0x48c0cfb3, 0x37e50f03, 0x2111b00c, + 0xa88060c9, 0x0e8e3274, 0x2fbd0d81, 0x3ab1fb10, 0x6b2921ee, 0xe5ff3b96, 0x2640d1ff, 0x95e77787, 0x069c52a5, + 0x97319991, 0x939309ee, 0xa14da75d, 0x80619ec9, 0xf3fdef4c, 0x674184fd, 0x49e3dc9f, 0x5eb12bef, 0x67413a99, + 0xfa95733a, 0xd0ad35f1, 0x0e7a2353, 0x8b336830, 0x2758a2c6, 0x55fb6fef, 0xf3ba43a7, 0xac39ff7d, 0x699aba08, + 0xeead39e7, 0x23dfcf1c, 0x08dc8bf0, 0x7500ba55, 0x66e352ad, 0x0aa32c11, 0x95b8c6b4, 0x5cf7dd51, 0x6557a083, + 0x462823c4, 0x6ed5998c, 0xaf6c89a7, 0x29e75ed2, 0xfe4f4d07, 0x77711ac8, 0x36accfff, 0x8cb9ed5e, 0x53cd9a96, + 0x330071bb, 0xa50359d9, 0x05b3a4eb, 0x45c31567, 0x2dabb121, 0x1c83be53, 0xb036573f, 0x32a3bd75, 0x5eab04f4, + 0xcea68e76, 0x19e378a5, 0x1ad151fb, 0x30dc9f61, 0xade2cf61, 0x5424485a, 0x08cea810, 0x42ac42ea, 0x9e6c2d9f, + 0x271e50d9, 0x23964b41, 0x87d94cf1, 0xd7ba341a, 0x8bdf8de4, 0xb4701b28, 0x37585e5d, 0xe4c78a92, 0xa6b03565, + 0x92512a46, 0x164e99e1, 0x5820143b, 0x37cb87b4, 0xaedd5785, 0x3db05bd0, 0xb95cb512, 0x9010942c, 0x3ce0a51d, + 0xc5fc6df4, 0xafee7c6d, 0x3fec809d, 0x489b7115, 0x90ae6dd4, 0x79f57d85, 0x874e81f7, 0xf6c550e5, 0x119982b2, + 0x3e4f0684, 0xe8b17263, 0x683240fa, 0xd649b998, 0x28af32b8, 0x0ebaee75, 0x4f23ad6b, 0xa03d301c, 0x463047d7, + 0xf7b5df52, 0x2ee13b7e, 0x8ce82cb9, 0x5f416b45, 0xae1707e6, 0x8b827190, 0x624306b9, 0x817cb8d1, 0x517144df, + 0xa3da337e, 0x76412589, 0x67aff3ca, 0x88db828c, 0x0c5e7c2a, 0xf8f1d7fa, 0xae2cc147, 0x9c19330e, 0x7acc730c, + 0xf26522eb, 0xe4192621, 0xca824cae, 0x7d96864e, 0x57d6ee27, 0x4f3f7bab, 0xd39fbdcc, 0x96203126, 0x653aad72, + 0xc2ad5b1f, 0x5ecc200b, 0x033a2700, 0xd0f8b629, 0x8893633d, 0x35694112, 0x73c1fdda, 0x6669865b, 0x86a84dee, + 0x5183b399, 0x3a97c732, 0x9e86b20b, 0x25ed203f, 0x5baff609, 0x41af5a00, 0xfe14ec13, 0x409aba1a, 0x6201270e, + 0xc1541a46, 0xa096e318, 0x372244b0, 0x90cfd488, 0x0f21380d, 0xf586999c, 0x7208f2e0, 0x4a5f2caa, 0x255d5207, + 0x579e7fae, 0x9e9f370f, 0x3ae6d5d6, 0xcf01b1ce, 0x37547f02, 0x1dc29d6d, 0x8b08e189, 0x02282aac, 0x317f847a, + 0xaef17129, 0x8a455df7, 0xa8b84b84, 0x6f1d7d4b, 0x8aa110d5, 0xbcfb3c06, 0xfec75e12, 0x6520ea93, 0xc87cfc6d, + 0xc095ed09, 0x17160e8f, 0x1e9880f8, 0xeaa566e5, 0x3347edc7, 0x9031906f, 0x0c687c61, 0xec83d42a, 0x6d0bc44f, + 0xc90c3674, 0x1cee27ee, 0xae4e225b, 0x5b33f7e6, 0x893ac3c6, 0x3ae2a309, 0xbaca2b58, 0x3b0f931c, 0x60b7378b, + 0xd5261594, 0x38acd224, 0xb745beab, 0x022667dd, 0x9efbef5e, 0xfdcc454b, 0x1de09c82, 0xfe8fd0c0, 0x01dedb95, + 0xdae51067, 0x744a3701, 0x8762bd1f, 0x698d1da9, 0x8f7feb3a, 0xfac37d7c, 0xf9a1987d, 0x88f2bc36, 0xae837de4, + 0xa06f2056, 0x1e061ad9, 0x9db0b19f, 0xc9cdfe01, 0x5bb477e5, 0xddd7c48a, 0x3fd146ad, 0x4bfc0441, 0xc132ce48, + 0x58aa7ad2, 0xde6d0a87, 0xb6232e54, 0xcfea6fb3, 0x9093ac0e, 0x45554869, 0x985b7d6c, 0xbce8b220, 0x1751b919, + 0xac69559b, 0x9bc35e6a, 0x33828b3a, 0xed06b5b0, 0xdb2322cf, 0x15d25a6e, 0x84651e30, 0x095d28f4, 0x644591e3, + 0xe00eeb97, 0xa4033cd1, 0x1135d045, 0x35323c6a, 0x5b04dfbc, 0xa3918862, 0x93737aab, 0x305e2755, 0x5e1383ee, + 0xf61a7553, 0x7df21d0d, 0x3831e950, 0x267239a2, 0xfcc68b36, 0x5132f7da, 0x1d6cb5c4, 0x12e1717d, 0x58f8ef50, + 0x1c589b71, 0xa1e3679f, 0xa39e2ae9, 0x0e54901d, 0xeae123a0, 0xdcf5598b, 0xfa3f4e65, 0x365d60d7, 0x1ea9da9b, + 0x397bd430, 0x272997e6, 0x9279e813, 0xb7f47f15, 0x855cda17, 0x86c124b3, 0xdb3985be, 0x4740728a, 0x40f0e789, + 0xeb6f05ad, 0x7d68ed06, 0xad4125d1, 0x259a0e6f, 0xc8e5bc5c, 0xc037e4f5, 0x63ebc7c5, 0x3c1f1065, 0x8d5d3aba, + 0xfac46b18, 0x8ff9c038, 0x44d5c2da, 0x03c53bc1, 0x960783da, 0x18cf397d, 0xd3e1c7d8, 0x4c4ac355, 0xfe5239a5, + 0x1a91fa85, 0xe1678209, 0xd798774b, 0x1e5e3220, 0x9d73d44e, 0x82f6904a, 0x3f3e6cba, 0xbdde1f53, 0x4bc88b73, + 0x623dc6ee, 0x5577dece, 0xe8cb706a, 0xa537789e, 0xaf65fa9a, 0x786a2738, 0xfb422ff2, 0xfd41a97f, 0x6e8ed23a, + 0x1685fbfa, 0x0a5b604d, 0xa8ffde36, 0x373e25c4, 0xef5cfe20, 0x03e00cdb, 0x2d2cfd9c, 0x14a615af, 0xf06c3ffc, + 0xa4849beb, 0xdd75b433, 0x0718fda7, 0xec144cdd, 0x5177f26d, 0x43d4095e, 0xae484034, 0xcb0a8eb5, 0x71e75a24, + 0xdbe7f514, 0x14e1ee03, 0xaaa72b6c, 0x6c934b52, 0x75b13b44, 0x9e0f847b, 0x280ced78, 0x94106bcf, 0x7e99f91a, + 0x0f557c79, 0xab4e34b5, 0x7e648da8, 0xe3e54ad3, 0x735a5353, 0x6cdc7a11, 0xfbfe2642, 0x65c91a4b, 0x8d52078e, + 0xfae7de6c, 0x4c3aa447, 0x39a6ba9f, 0x7bc4cc78, 0x475a2368, 0xa45ab650, 0xdc5a2ac8, 0x4447d5f4, 0x65ce83b3, + 0x04bb8404, 0x858a9a94, 0x56889b74, 0x57c97ff2, 0x8f45d7b0, 0xda3cd4bb, 0x333a3019, 0x7d69c37a, 0x0ae5a076, + 0xdc6c66ad, 0x5f1f6075, 0x4599d47d, 0x591ac6f2, 0x77c2d975, 0xd71d9530, 0x6126a900, 0xa33ceae5, 0x0c04b3e6, + 0x4f83e793, 0x73e8edb1, 0x90183c7f, 0x27521fc2, 0x52d30fd0, 0x3127dc78, 0xd0558701, 0xb21bb131, 0x8e58a9e3, + 0xd912eae2, 0xc2799536, 0x17931a9b, 0xf62b07c8, 0x256e4a14, 0xd6d2b1b8, 0x8061be6a, 0x0e987522, 0xcafb193c, + 0xe28c59c6, 0x9cfe3eae, 0xcecd8603, 0xc667b011, 0xcbd2e50f, 0xfcded331, 0x269ed023, 0xaf8bd07c, 0x4f1f0ab4, + 0x400c45a7, 0xd1c90b5c, 0xdb045638, 0x3ec43730, 0x1c838aad, 0xaa4255c5, 0x4b51b050, 0x45b261b7, 0xb28c2d80, + 0xc0386076, 0x5e5577c7, 0x46e15059, 0x87f3b45d, 0xcbd6ba8f, 0x740d7c4a, 0xa805cfd5, 0xf7ad4c1d, 0x5eb4f493, + 0x4391fa86, 0x25b9ca59, 0xfb39b4ed, 0xbdd1cf8d, 0x3cfb1e57, 0x9c4a344f, 0xd7d647c9, 0x9ad7e9e6, 0x9d056256, + 0xdec58a55, 0x64bf0990, 0xc2fd8d97, 0x38f83a37, 0xec961cf6, 0xbd092ef7, 0x2fc91a46, 0xf0d04c8d, 0x4a17e934, + 0xf9a50bbb, 0x4bb94a62, 0xeb323048, 0x81e65efb, 0x23539c21, 0x6c05f781, 0xbabec616, 0x30f6f4ea, 0x10e7a96f, + 0xbec22447, 0x9c28850e, 0x4c848a84, 0x3f177aa3, 0x57c82db4, 0x248a462b, 0x1ca1315d, 0x61236fdb, 0xf3ac1e30, + 0x9810c426, 0x1a51bc06, 0xfbf0eecb, 0x55b0f0b1, 0x54fd920d, 0x9b0a548a, 0xb5827037, 0xe27bcb72, 0x59846781, + 0x3fe858bb, 0x1840ef6b, 0x3ab44033, 0xa0273c5a, 0x8075d15b, 0xf37d3852, 0x3e1e96bb, 0x9ccc81a2, 0x26d3be54, + 0x1136ff68, 0x8b90f896, 0xa93a3cb5, 0x2960267f, 0x4411a157, 0x1c2ba91c, 0xa50fe35b, 0xdc18fb1c, 0x442d4485, + 0x348b7929, 0x0c59a19a, 0x628c02dd, 0x90330e9c, 0xf188b2a3, 0xf6cc59cf, 0x25b4d2f7, 0x03cdfa63, 0xcfd0484c, + 0x082af00e, 0x97ac760a, 0xd6059fe1, 0xc283922a, 0xd9fc5b0b, 0xbf283198, 0x59c163c7, 0xf5be0a10, 0x8efd4711, + 0xffd178c6, 0x3595a7a0, 0xbab8f958, 0x9c59df81, 0xd9ffe9bf, 0x0c8f69a9, 0x6251b9b6, 0xf21dc327, 0xa8c2c59e, + 0x82420295, 0xb58760a9, 0x87196ee5, 0xc6744122, 0xc53d0a22, 0x0296663a, 0x9d9945cf, 0x6fa4d805, 0x9ce13b9a, + 0x1b233469, 0x94020db3, 0x7b1ac19c, 0xf19868e1, 0x2024767a, 0x42934658, 0x70a467cc, 0xd92a8ea4, 0x00c3155e, + 0xbbe3971e, 0x8c543236, 0xc8d6d2ee, 0x4ba37e81, 0xea5225a1, 0x0ea28b6b, 0x26239590, 0x67caecc4, 0x90318a61, + 0x7e3d19b0, 0x954b20fc, 0xca3fb960, 0x933f5e21, 0x6c78a99f, 0x7fc54bc0, 0xa4b3217d, 0xac6ee380, 0x08078dbc, + 0x8f0408b4, 0xee4c224a, 0xd84a088c, 0xc5091213, 0xd5c3aeaa, 0xe2080ebc, 0xfb852746, 0x247714bd, 0x9556881c, + 0x9f633816, 0x8c090629, 0x5b16160a, 0xd2fd49d4, 0xa4dc9f57, 0xe39e557f, 0xed681532, 0x89a3955f, 0x68ebd3fb, + 0x5667ee8e, 0x9fd27843, 0x3168a5cf, 0x23014cfa, 0x5aba5a9f, 0x24f3f2d1, 0xfb7360cb, 0x0a0bd0e3, 0xb729aede, + 0xf867aa45, 0x768f6171, 0xc11e3554, 0x302bc103, 0xadd23e22, 0xc6266f45, 0x3eb4f9dc, 0xc0ca3d93, 0x06d097e5, + 0xbf4dca67, 0x161f8d38, 0xc7fcce75, 0xae09ac66, 0x6158042f, 0xc97a1db3, 0x8978690c, 0x1bb546e1, 0x098d65f3, + 0x99c20d34, 0x3b25279a, 0xd7e99aa7, 0x704a1a18, 0xad3de7a5, 0x4e6a3ea1, 0x787bbc2d, 0x77cbaabb, 0x2445743d, + 0x620dd590, 0xd72595a4, 0x62843cd1, 0x66a048fc, 0x23410233, 0x67c82c73, 0x5335bc46, 0x4607f656, 0x7283c057, + 0x5add7652, 0xd85b8cf0, 0x027f8409, 0x9064e431, 0x69c00046, 0xdaff9698, 0x04ec143a, 0xea1b700f, 0x02945d7a, + 0x5f684012, 0x65ffee07, 0xb19e2126, 0xc7a2c3fb, 0x48048724, 0x37e9b17b, 0x0b217521, 0x3d4bab2a, 0x2be41d38, + 0xf0bb3a75, 0x9dd3e0a0, 0xcfbaa379, 0xaa95af15, 0x7a25dd94, 0x622f80ee, 0xb42b52b9, 0xcf99d2d3, 0x21f274f8, + 0xe53765e1, 0xd189258a, 0xe0c9692a, 0xc14fa3ec, 0xe2409df3, 0xbfbcfb9f, 0x5c0397a1, 0xf8688c8d, 0x5d9f8c64, + 0xec292316, 0xd33f844c, 0x3fda5e01, 0x8c1e2344, 0xc85414a5, 0xbbc4cee3, 0x3aa9c1c1, 0x64565b8f, 0x70382bad, + 0xd32503bf, 0xa2bc219e, 0x85e4050d, 0x01b792c1, 0xd62a5cd3, 0x3c18fe92, 0xab5b80cc, 0x753807b0, 0xafadf4ec, + 0x9d101c06, 0x49fea00d, 0x6fd0933f, 0xbbebe1a7, 0xa4c9e698, 0xff0ef32a, 0x142ee200, 0x870b721b, 0xa4400480, + 0x098c7df4, 0x3b3915db, 0x389ffaf7, 0xd5340132, 0xa53c765c, 0xfedbea88, 0x17234a63, 0xde3c1112, 0x189e5806, + 0x62abaf0c, 0xf70aad32, 0x330e57fb, 0x3889c13b, 0x9eb4aefa, 0x9ba28036, 0x0ff7a80f, 0xee150836, 0xfee6d862, + 0x7295431d, 0x90e6e6fb, 0x94573ab3, 0x9fe3a11b, 0xccfb96e8, 0xcc550846, 0x5e094e05, 0x34cdc8d7, 0x92b90bb5, + 0x329c61b2, 0xa898739f, 0x379a4ee5, 0x1fbcf0ac, 0x63026fcb, 0xdbe8b5e9, 0xd27e7c9f, 0x0926315f, 0x4a3e0063, + 0x0735ccd5, 0x40025d7b, 0x12c1d995, 0x0e2f72a9, 0x15933160, 0xb8ac588b, 0x021f9599, 0xf7ac1226, 0x325442c5, + 0x1e1d0be9, 0x50c1fbef, 0x7f6d605a, 0x343b8cc0, 0x67da1748, 0x44b234ff, 0x8e5a77e1, 0xe521bbb9, 0x61cc8ea2, + 0x54471662, 0xfe9ac88c, 0x753c6c14, 0x6ba3d5ed, 0x88b59522, 0x8c11c839, 0xc11b614f, 0x08c7cf32, 0x29e1e598, + 0x10294a6e, 0xbd7d2738, 0x6a73b484, 0xe63935b6, 0xa27e740c, 0x9140959f, 0xa263b99e, 0x8e748116, 0x379d7f2e, + 0x7402b3bf, 0x30d5d4f2, 0x3cae635f, 0xc8a31d7e, 0x088f8d18, 0x202adb61, 0x63e24a5a, 0xd83896b5, 0xd084ef7a, + 0x55030d3d, 0x2fc93c92, 0x677bb479, 0x1128aca2, 0x3fcaba1c, 0x3288c51f, 0xb999d883, 0xd052f105, 0x02836332, + 0x5e93f8c9, 0x7eee5fbc, 0x487f76cf, 0x41b1a95c, 0x4a866e4b, 0xb7a852e5, 0x4dfa817b, 0x99801335, 0x33fbebe0, + 0xcc0ee79e, 0xc749bebf, 0xd3a8e8f6, 0x14349fb0, 0x3066a77b, 0x736f1b6e, 0x189b0d72, 0xdd5efa9d, 0xc09bf6f2, + 0x952f7e61, 0x636f1009, 0x0396b09a, 0x8f0f4a82, 0x61abf725, 0x63897d11, 0xcf4f336b, 0x911a1e75, 0x83ca16e1, + 0x4325b574, 0xda6641cc, 0xb456a8e2, 0xbe79bf0d, 0xc501396c, 0x63295f8f, 0x9e83dc31, 0xf77ee5ee, 0x6b5c38e3, + 0x6281f82a, 0x6717b128, 0xcc662e7e, 0x61cbdcce, 0xeeb95b18, 0x7d3a9553, 0x12b29dce, 0x6dd7f5ae, 0x624445f0, + 0x315a958d, 0x26bf71e3, 0x72444b7a, 0xd0eba998, 0xb5759ac5, 0xae3c1461, 0xb1d23f2b, 0x74f1300f, 0x0dbcad96, + 0x46ed1445, 0xc83fc54b, 0x342faa53, 0xf2adb6bc, 0xad15f2f8, 0x01a91fc8, 0xedc6aa07, 0x2a9c08a2, 0xc2f945c3, + 0xe7da5414, 0x24628472, 0xfb3056ea, 0x2b6b8834, 0xbbf3e5fb, 0x328890b0, 0xd5da687e, 0x1edc0f9e, 0x22a75f16, + 0xa6599f62, 0xcfe11d45, 0x9460acf0, 0xca441b36, 0xa26b8505, 0xefe25820, 0x6ed5a02e, 0x4aa87e91, 0x931557cb, + 0xa5471103, 0xe841af0b, 0x694ca128, 0x195ed6c5, 0xa99c7b21, 0xdc370556, 0x8a7c8fa0, 0x87230b2d, 0x69ba54f8, + 0xbac9e66c, 0xd7577bb0, 0x8e4926fe, 0xe90db182, 0x04b9c183, 0x5aa145dc, 0x62c24dc4, 0xb0b5ed69, 0xe399948f, + 0xc0f4d80d, 0x6bc111b0, 0xf7e3a0d3, 0xd0a83a90, 0xfcd979eb, 0x3e0a6e9f, 0x70943119, 0x0b7117b9, 0x540c6cc4, + 0xfb374807, 0x5f73ff80, 0x8c4992f0, 0x7bc7f04a, 0x2bdbb3a7, 0x6dd862fb, 0xf52d7b02, 0x94ebff6e, 0x55517499, + 0xb9fe9623, 0x99d018db, 0xd74baa87, 0xf0b6842e, 0x18442022, 0x1c4701f4, 0x13c994ff, 0x395ad821, 0x377f2d75, + 0x9a69f7eb, 0xde60a686, 0x16741e24, 0x27517ee4, 0x5f8a5e63, 0xcd1cfadb, 0xf2189118, 0x036ea2f0, 0x307955fb, + 0xd158cf09, 0xb007596c, 0xacb9e24b, 0xfc3899d7, 0x79e4ca63, 0x94d058ae, 0x569c9ff6, 0xf311c0dd, 0xcd371f80, + 0xa617e71f, 0x75d87580, 0x66b258f1, 0x6d385ad8, 0xa17d1a44, 0x4b98ed8a, 0x51345c15, 0x4454b6d3, 0x592c950d, + 0xd77cf193, 0x258669b9, 0x8b5c4eef, 0xc8c4fddf, 0xccccaaf4, 0xccad5658, 0x433a7504, 0xe62d4f52, 0x9513192a, + 0x57b2da88, 0x3500d8da, 0x92cd4029, 0xa45390f0, 0x1815c47a, 0x32d11f15, 0x3dc28bb7, 0xf965c9bf, 0xc809e073, + 0xd6c56abb, 0xbc90c665, 0xc4c9101f, 0x2ece01b3, 0xb65b4832, 0x96247fa4, 0x1b297a5a, 0x8f30e28c, 0x53f63449, + 0x6bf7eaef, 0x51f58e68, 0xf2db59db, 0x32cecd4b, 0x423b9a82, 0xb45085b8, 0x4d4708eb, 0x6d6abe88, 0xef2b3020, + 0xf19f7322, 0x2f89857e, 0xc8411a04, 0x39962455, 0xfc4859fa, 0xc9173d62, 0xc74f32b0, 0xc75f7196, 0xfc73a246, + 0xf49ed685, 0x75153163, 0x5f822240, 0xf6bec6d3, 0x094c8ff0, 0xfe93341f, 0xc17d1f8a, 0x8e6782ca, 0x3f487af3, + 0xca7a84a7, 0x9f8e9810, 0x741f319d, 0x70c91f06, 0xa4904cab, 0x2a0d347f, 0x48e4ae9a, 0xa407594d, 0x8ff66327, + 0x57c604be, 0xe68fc29a, 0x68aaa828, 0xdbd2cf93, 0x0f82e53e, 0x2bf89b7d, 0xca761c1a, 0xdec7e668, 0x93649115, + 0x8caa307a, 0x0d6bc6ca, 0x26fd8576, 0x878f9183, 0xac9befd1, 0x45075d82, 0xe9788e78, 0xb4686e6d, 0x6ba070bb, + 0x14459589, 0xbd1c495d, 0xad43f8f9, 0x2d2071f5, 0x1c4750f6, 0x2dae6fd4, 0x18e5b4d0, 0x4491a06a, 0xa3c3f70e, + 0xe1d94c0f, 0x630c8fa5, 0xa097c779, 0xd571db8f, 0x8a280a9b, 0xc0b6f5a9, 0x657c97ca, 0xf1ae9efd, 0xeae16c8f, + 0xbe51e7c8, 0xed449176, 0xfc83d917, 0xd5b38930, 0x711d2f81, 0x1ec38ee8, 0x1eb0ac72, 0xfe5a3f7d, 0xf3cbf763, + 0x386b3aa3, 0x7f26a290, 0xe3cd87c8, 0x2af2c1b5, 0x3b9969f9, 0x793c1859, 0x520b6ea5, 0x80c8f683, 0x3331a85e, + 0x95748a52, 0x39e7280d, 0x2de76e73, 0x8884c3ad, 0x0a28b57c, 0x9368ca33, 0xa222cf4a, 0x2da9e8ff, 0xb8f0efc5, + 0x056fbfeb, 0x11f14c3b, 0x504943b9, 0x2375ed81, 0x94826cc8, 0xa954e67a, 0xd6475f15, 0x2e035444, 0x10ba6075, + 0x65938c26, 0x78b794fb, 0xc7447b20, 0x12554050, 0x6d9b7950, 0x92e80de3, 0xab96cf8e, 0x9a064f4e, 0x6ab91c89, + 0x102ee080, 0x562b0620, 0x34c3ba9d, 0x8e6d3373, 0xfd97755e, 0x6346c8a8, 0xa8138aee, 0xc32441f8, 0xb76932e5, + 0x154c90f3, 0x76cdf9e0, 0x7ab8ce3e, 0x325c6072, 0xecfb56f2, 0x90e63083, 0x82186945, 0x5a5cda6c, 0xe3c65f06, + 0x8e3ba7c8, 0x671a62e9, 0xec3e382b, 0x92cb705a, 0x4d789959, 0x68e78eff, 0x6bc093e5, 0x08c4846a, 0x2c2b5e03, + 0x9dacfa53, 0x0add20bb, 0x4d29a1aa, 0xbcbf3fd5, 0xb5e557b1, 0x57ef7c7f, 0xb7567ef9, 0x84ff5798, 0x183e918b, + 0xc6d7e497, 0x918765a2, 0xf617f4bf, 0x23cdb3a8, 0x5bd88eb7, 0x1e17ab2e, 0x73b330bd, 0x0167eadb, 0x8da6df9a, + 0x8ef4b1d3, 0x7cd6665f, 0x532268fe, 0xb9b56dd7, 0x720e0f07, 0x04c3ad91, 0x7cac02dc, 0xeaea3858, 0x5a9f7a96, + 0xe072ca9b, 0x0a2c9ff1, 0x0f9bd724, 0x6000c438, 0x9026b2a7, 0x48db8322, 0x74dae37a, 0xeaddab7e, 0x227bbd65, + 0x2e2e6ae6, 0x8f5e484f, 0xc21b2b66, 0x6a2a9ffd, 0x47cd4594, 0xf8e028f3, 0x0a55c96f, 0x95dbe989, 0xcebfacd2, + 0x599fdeb8, 0xde54b35f, 0xce796284, 0x1271c28e, 0xf2b733eb, 0xf2d8d191, 0xfe463583, 0x96990b39, 0x564283d3, + 0xbc4c5a58, 0x5cee1967, 0x4aaa826b, 0xc4366afb, 0x301b00f3, 0xe81993b4, 0xa8692f42, 0x3bf02042, 0xdadaa715, + 0x7dab77d2, 0xa8c38abe, 0x40035ce0, 0x18539f4f, 0xe88d7c9f, 0xfdac8d17, 0x2204e2c7, 0xfc05e7af, 0xf3696fd3, + 0xaa7deec2, 0x0b05f1fb, 0xdbf88eeb, 0xd087881d, 0x36778aa6, 0x1eb4cba2, 0x4a688afd, 0xe6b802fe, 0xcf5e9aa7, + 0x6e1029cb, 0x4e3408f3, 0x9405d31a, 0xd01a404a, 0xcb4cac9e, 0xe2fd0314, 0x5580416a, 0x50bb9f1b, 0x34af3bdf, + 0xf971fe76, 0xf56226a7, 0x11b5bb08, 0xfeee8a90, 0xbc427acc, 0xe64d4b12, 0xcb99e1ea, 0x93909794, 0xba123982, + 0x40ae734b, 0x5bbe23d9, 0x61d41ac2, 0xfbb3aa05, 0xa05456eb, 0xff8542e6, 0x5a307e00, 0xde6b7c86, 0x23d048a6, + 0x2b7712c2, 0xf32a028a, 0xd0988883, 0xc591fe74, 0xe20b1def, 0x1c8c5543, 0xdfe6d64c, 0x1d77d543, 0x768a4915, + 0xf6e56219, 0x19f1ac3f, 0x6e72b98e, 0xa9cbf590, 0x4a659796, 0x7608d51d, 0x8c11ccae, 0xb2cf92c9, 0x013e6275, + 0xa55446d3, 0x899f7dd9, 0xf49840c9, 0x692f33a5, 0x48f90bfb, 0x1700d192, 0xe9de2480, 0x6e1ec056, 0x750bcb7b, + 0xbc7cd627, 0x8c076a0d, 0x11d960b7, 0x107fd3b1, 0xbac557a9, 0x76ff77ed, 0x430b03b9, 0xbe48e251, 0x2e716769, + 0x4b1599c8, 0x1edf7f81, 0x11715e3b, 0xeecffd47, 0x4c072df2, 0x647d7752, 0xe0dae3f4, 0x58b09a6c, 0x3afcdad5, + 0x333110c6, 0x6c308c79, 0x887a80a2, 0x8bb5f8bc, 0xe6398176, 0xf0568384, 0x2da033f2, 0xdb23b972, 0xe86cb78b, + 0xd5bc364a, 0x94bce76f, 0x3d8dff1b, 0x1701086d, 0x2596f735, 0x909c8f51, 0xe98d031e, 0x26b3caa8, 0xfd294670, + 0xdf16347b, 0x843765e1, 0x00eaba9d, 0xc2a5b53d, 0x28384080, 0x2bd84b79, 0x314cba67, 0xd387f209, 0xa8329215, + 0x5a2eeefb, 0xb383d0e6, 0xcbbada1c, 0x0c84bdea, 0x1a266797, 0x5b0b77d8, 0xb12d6067, 0x442a7be9, 0x358252a3, + 0xc9d8df10, 0x18f5dd58, 0xfcb3e57c, 0x765e8c1e, 0x971a5e4c, 0xbc7143a6, 0x3323fee1, 0x8defd517, 0x0f67d3f6, + 0x4730f8e0, 0x8f3ae035, 0xc4d17c6d, 0x9479a23a, 0x520ffb99, 0x11d81a2e, 0x5d87d8ba, 0x9d1faa01, 0x17695f8d, + 0x7248c630, 0x51f94f61, 0x36396aee, 0x9e1f60bf, 0x9664924b, 0x5a36899e, 0xaa3219e2, 0xfafe13f5, 0x9a74d156, + 0xaf409779, 0x80ff2bff, 0xfc7a84f0, 0x0bfb9464, 0xacc7ab89, 0x05260b9a, 0xad77212a, 0x8f0fa649, 0x377ec7ff, + 0x07f52238, 0x7580ce81, 0x4f327419, 0xaa3ec023, 0xffe0d8d9, 0xc91033ea, 0x58fce1e6, 0x597c17b2, 0xfaa59930, + 0x00456477, 0x45af6f87, 0x373c9f23, 0x5ed5f8da, 0xba6d220c, 0x03ca30e9, 0x93690b47, 0x1ea70f3a, 0x2af1de8f, + 0xabfeb79a, 0xc168c65b, 0x594f333c, 0xf1f3230d, 0x26c0603e, 0x38046836, 0x40b4911a, 0x9b983a2a, 0x0380c011, + 0x3cdb0a11, 0xf59f56d7, 0xf715d490, 0x5f52b231, 0x52ce5b7f, 0x27e42e39, 0x331949d7, 0x6702f70c, 0x5a1351de, + 0x9a674ded, 0x16641a9e, 0xc0d75e72, 0x637d2081, 0x65cf45c6, 0x8a09ddd8, 0x4fe6f3ae, 0x0dbce90f, 0x06916a1a, + 0x80fd4f02, 0x4d63b7b4, 0xf4a18a23, 0x9198b7bf, 0x14771fdb, 0x4585c01c, 0xf162df58, 0xc82cb8bc, 0x7682b124, + 0xb3658517, 0xb70a591f, 0xbd538ddc, 0x7a001cc5, 0x66a68cae, 0xd0f7c9d2, 0x90d9a6aa, 0x46d1e944, 0x3a4cb9fa, + 0xc8d2c3b0, 0x9d2c57a5, 0x5e3ab324, 0x3de5170a, 0x6310ebb3, 0x7d83751c, 0x1fcbde5e, 0xe3ee4db8, 0xe48baba8, + 0x5900d4a8, 0xa70ed6cc, 0x2a584045, 0x434b8bae, 0x4081f003, 0xf2619f38, 0xc4a04245, 0xcd7f9808, 0xdc6808a5, + 0x071e3fe6, 0x25b32431, 0xf80c77e5, 0xd2e8c0c9, 0xfd1f1533, 0x65edab98, 0xee174847, 0x93c13804, 0x388a5162, + 0xbab01f13, 0x753080f1, 0xae87515a, 0xc3378d00, 0x6c47fcf9, 0x1f9bf68d, 0xfce3284c, 0x67426631, 0xb9c2c4ca, + 0x8f5a3ceb, 0x6e0a8276, 0xf9550d67, 0x8da4828a, 0xa6939735, 0x956d959d, 0xb5b0fbb8, 0x9e4be54f, 0x2c88c89d, + 0x0a65ffb3, 0x2f233283, 0xb3a84460, 0x0319d8d6, 0xcf1658ac, 0xd0fa0221, 0xc7ee183a, 0x001adfa3, 0x0e47fa3e, + 0x3db678d6, 0xde70385a, 0xd05851ff, 0x1f035297, 0xc2ba57f3, 0x1d59a68a, 0x30bc610e, 0xea2d4751, 0x9b88e703, + 0xc691cf42, 0x3b828e48, 0xb11037a4, 0x5c01b661, 0xbf6a1189, 0xf47d63fd, 0x991edece, 0xc001730d, 0xb39ec914, + 0x3cb81991, 0x753b2b20, 0x46211fff, 0x1960cd3f, 0xa582cfe9, 0x005fbe7d, 0xf139d720, 0x41bb2224, 0xcbc99544, + 0xeefdf192, 0x1fd88370, 0xda86e95c, 0xc57c7134, 0xfcf7a0f4, 0x57471dfa, 0xb0329da7, 0x46df1a08, 0x9f190628, + 0x5c5404d6, 0xe93800d1, 0x489366ba, 0x1b0119ee, 0xac3aa890, 0xf1cc2769, 0x1ab385b3, 0x79cf97fe, 0xf295fbc7, + 0xf73ef905, 0x738e3498, 0x64b3a4c5, 0x0e9079a8, 0x678f2a4f, 0x1c19304f, 0xddb8b47f, 0xab9078f8, 0xeff255c9, + 0xcab221f8, 0x475db474, 0x0c22515f, 0x04fac60f, 0x655ae99a, 0xb0c54f39, 0x19559a40, 0x123801ab, 0x2db10005, + 0x70740a5e, 0x23eb1656, 0x660cea65, 0xabf030c7, 0xfdfcf06e, 0xe1dbf1ff, 0x0c411127, 0xa0c38a1d, 0xda8b216e, + 0x155f0b6b, 0x3712fc8d, 0x7107dc26, 0x95343175, 0x357ba697, 0xb20728c6, 0x697d4a2f, 0x0d81cb36, 0x0af9085e, + 0x0fc4820f, 0x9800b170, 0x1cf62d18, 0x3eaa6bd5, 0x135e9e9e, 0x6a037397, 0xd3603d36, 0x82e592ba, 0xf873031b, + 0x47ab0900, 0x6cfcb82f, 0xd794a50b, 0xf60d2b8d, 0x6a0b8bc1, 0xfc25ef89, 0x56ec1805, 0x4d0c5283, 0x09ee59dc, + 0x0fff9976, 0xf0597375, 0x26edcbb3, 0x3c3a7f43, 0xcc435b11, 0x0fa4854a, 0x194a7650, 0x17ef8d92, 0x3ccd540d, + 0x65b7bd75, 0x8765cd06, 0x8e932cd8, 0xc857814a, 0x96b15fd4, 0x0b4322f1, 0xe5260a07, 0x2f82455c, 0x031b704f, + 0xaf84ba03, 0xe0af90ca, 0xcc3aa04a, 0xed00d223, 0x3a17da1e, 0x37ea3b72, 0x11effaed, 0x6ce92099, 0x676a1675, + 0xf15ec8a6, 0x66a7e073, 0x1e734101, 0xe5f56e53, 0xe3530441, 0x0ce32496, 0xbecd6fd4, 0xf0f1a675, 0x7bb66d85, + 0x67f18f11, 0x71d7faee, 0xc52621db, 0x63b484b5, 0x1c37f777, 0x0057f1af, 0x13899fb2, 0x848a6cb4, 0xc212cd14, + 0x6a6006e8, 0x70685088, 0x644813f8, 0x1def816e, 0x9f3a1e00, 0xfca537cd, 0x639ae709, 0x74263507, 0x2e413cbc, + 0x6ca4d727, 0x0a675e2f, 0xebae288e, 0xa57fd8de, 0xa66ad125, 0x47f69fe5, 0x893eaa65, 0xeca84a9f, 0x6eedf862, + 0xc83128d9, 0xf097bc9e, 0xd64f58eb, 0xe8600894, 0xe6704d78, 0xb7c7d777, 0x7dff817b, 0xe2ef1cd3, 0xe370f344, + 0xc182b30f, 0x89d92a47, 0x87065e95, 0x8a464f19, 0x99641eac, 0xa3020d63, 0xc5abad07, 0x14f1c174, 0xdb0a1244, + 0xaacdb4df, 0x807aaf6a, 0x9842d2b3, 0xbfe6919c, 0x1a8eeceb, 0x40af95ff, 0xe07b8034, 0x2c9b6293, 0xe528ae37, + 0xf7ebc937, 0x9344b41e, 0x7ce74f07, 0xfb02d090, 0x6ceb947b, 0xddaa2a5b, 0xf1541227, 0x7cd6456f, 0x39fca94b, + 0x3a204fe1, 0x58321d62, 0x891855c5, 0xa21aa6fd, 0x9e80c9fa, 0xe6fac70c, 0x48bc50ec, 0x50c341c2, 0x8d280f64, + 0x5e5af273, 0x3764d500, 0xbce5cd85, 0x058c268e, 0x60d60556, 0x1360e75a, 0xab220627, 0x2b3778ae, 0x420c320d, + 0x479df501, 0x664f4d3a, 0xbfcee56e, 0x44a4476f, 0xcb08c2d4, 0x82a9481b, 0x7b6b791c, 0xf748277a, 0x6a967a94, + 0xe594fb87, 0x9fc34e06, 0xc7dcf6cf, 0xc4cc845e, 0x29d49912, 0x715da411, 0xcb294b37, 0xd1782d3d, 0x54f31394, + 0x7462c2b5, 0xa775f367, 0x34b3cdcf, 0xcb1abe16, 0xf0c66c9b, 0xc2f1af38, 0x7c2ced68, 0x92613e14, 0xc62b3f5b, + 0x171433b6, 0xeb4c97c3, 0x2b268f08, 0xc4b522c1, 0xacc6d2f7, 0xf3d7f39b, 0x207f8112, 0xee08eba0, 0xfbc8978b, + 0x799e9812, 0x2057f4de, 0x506b30ce, 0x16c2cea2, 0xbbb9551d, 0xfbcacd18, 0x497f87fe, 0xa79a154b, 0x9e481052, + 0xe76de995, 0xd6fa949d, 0x7c7fbaf8, 0x280d244c, 0x10fe5fa0, 0x3fa34cc4, 0xd4078076, 0x30536170, 0xe3a4b6c4, + 0xb9f6aae7, 0xd20afced, 0x6ff19730, 0xea2ace7c, 0x6ce0ab82, 0x9bda9a88, 0xce8d83df, 0xcd4eedad, 0x164ae8ea, + 0x1bc4eaf2, 0x9b382840, 0xf49780d9, 0x0263461a, 0xc9dce1b0, 0xef92578c, 0x7436cc64, 0x04a0b73e, 0xea02f343, + 0x388367c3, 0x44c753f4, 0xda34a0f6, 0x70712101, 0x5d94b5f1, 0xfac7e7df, 0x301cc700, 0x336b022d, 0x8d1bcf97, + 0x8dcaa5bb, 0x0423b7e5, 0xf35e3049, 0x3dfc2aa5, 0xb000a261, 0x92249253, 0x5982eb4c, 0x371da55a, 0x5c0bc5ef, + 0xb025c0e3, 0x0442298a, 0x142ffa0c, 0x0521b27d, 0x05e5a0a1, 0x2f280d30, 0xe751b264, 0x9eb1b6ed, 0x20de2001, + 0xededde11, 0xa9bd721e, 0x3258d8e8, 0x15c4e7fa, 0xc66f07f1, 0x9e5722fa, 0x8ad2664d, 0x04e81f8c, 0x56404c3c, + 0xd935678f, 0x30c5c2a5, 0xa2f0cb53, 0x59942fd5, 0x8c6b7097, 0x63460f26, 0x52cc7b34, 0x30ad705f, 0x5a972f1d, + 0x6c7d0d2c, 0x8bf531a1, 0xd1ac38f7, 0x58d0b6ff, 0x48e4543b, 0xcbc4e385, 0x64044e19, 0xcf0aafc8, 0x58205bd7, + 0xb7574ed9, 0x78f4d0bf, 0xe71585a6, 0x2f5351cd, 0x8408abc5, 0x1ed33e0b, 0x57cd2350, 0xf73d0224, 0xe63893f6, + 0x9efd3e8f, 0x8a350a01, 0x9e4b2d1d, 0x043d4fa2, 0x0bb4bfea, 0xd978ab06, 0x6c689226, 0x1eccc38b, 0x2f0a6715, + 0x419ea461, 0xe8cf4ca2, 0x63e28257, 0x61628c81, 0xc8ab9b1b, 0xe5636a62, 0xc5fc866a, 0x38a59f76, 0x8bfd1cf7, + 0x54e6dfbc, 0x61132267, 0x77838f2f, 0x8c36aefa, 0x42b04f10, 0xf901f42c, 0x27cc3015, 0xf94802c5, 0xa379f348, + 0x550ad60e, 0x5c6191fd, 0xd08f2062, 0xf9eab1b8, 0xb34ba9d5, 0x818879f9, 0x467df52e, 0x1a22cb25, 0xc67b4583, + 0x668d59f1, 0x719208c3, 0x0549053d, 0x0e96399e, 0xd8e41d97, 0x084193df, 0xadd756ce, 0x75b35391, 0xe717e388, + 0x422e9bcf, 0xb857a5e4, 0xaf0cf8b3, 0x94e1322d, 0xb2fbdfe6, 0x1da6269c, 0x3ad63ea3, 0x410aec4c, 0x4041c1ab, + 0x97fa0e98, 0x11edd1c4, 0xeb9299a1, 0x9c3a915e, 0x62f88423, 0xcd71106d, 0x5d81656b, 0xbc94fff9, 0x7751b11d, + 0xc18167b8, 0x3a854188, 0xc8b4025e, 0xbfa76302, 0xde856cc8, 0x4ba5cf20, 0xcddb16c2, 0xcc28de41, 0xfb597ed0, + 0x1cbbd4d0, 0xbe765cc6, 0x6c9af75a, 0xc868afff, 0xa367eed0, 0xb15acbfd, 0xb2d4c7d3, 0x041167f3, 0x16c3238f, + 0x67dabbee, 0x7cabc552, 0x91eec147, 0x1e8cd463, 0x0feb78a4, 0x1349812f, 0x0a3e03ff, 0xe31c1b9d, 0x9167114e, + 0xc8d4d790, 0xf76599da, 0xc42bca55, 0x8a18b72e, 0x5cc13e0a, 0x952b9fd6, 0x78edbe27, 0x9812ef41, 0xaf4472f1, + 0x961346df, 0x56af57a0, 0x3bd7a394, 0x980fa871, 0xcffcfa7f, 0xf4a45766, 0xc28c2c07, 0x454cd315, 0x9d44caa7, + 0x1498290b, 0x8cb9b593, 0x1d63f5b7, 0xeab47011, 0xe433c8ca, 0x3bb0f9f8, 0x74d8565a, 0xc5dcfbed, 0x70d79814, + 0x859a9051, 0x1300ed50, 0x2b1fe07c, 0xdb5d7acf, 0xc4191f57, 0xfb65ca3e, 0x67aeb29e, 0x4fdc698b, 0x5c2bd70d, + 0x91acea68, 0x856a0708, 0x27347695, 0xd65014b2, 0x8b02d613, 0x627987a6, 0x6923dd19, 0xf6fb3a1d, 0x429b3962, + 0xd0828fd3, 0xf42ac10a, 0x2262459b, 0xc1a66b48, 0x2c158f1d, 0x46fcf1ce, 0xa571e597, 0xdfa0d66d, 0x765cb580, + 0xa2b28671, 0x07e19525, 0x1e06ee5c, 0xb9372f4f, 0x2882b111, 0x4d4fdc11, 0xcc5fae44, 0x8a9bfc9e, 0x22d459b4, + 0x5cf325ac, 0x2b1c4127, 0x6b71a547, 0xbb9747bc, 0xc2ce8dd5, 0xc8a2dfa3, 0xfe5408b6, 0x74b25d99, 0x157e4a78, + 0x91122c70, 0x8bebb810, 0x6a33640e, 0x344a57a6, 0x6f5ed3bb, 0xc91e2927, 0xb8082290, 0x3a7be3d3, 0x32696940, + 0x1aed439d, 0xc340f222, 0xc5e567b6, 0xa8720caa, 0x955258f5, 0xd6301a84, 0x29fe5f12, 0x3d4fb8a3, 0x0593cb58, + 0x03d23ec5, 0xa9c67c66, 0x3359a029, 0xf2d32cae, 0x93375d50, 0xf48c730b, 0x6d7a4177, 0xdae4acd7, 0x1a189da5, + 0x824bf6ea, 0xa2338689, 0xabe26b1f, 0x91ddd838, 0xf52811c4, 0x3ce4ceb4, 0x5ccbd81f, 0x8d0caa84, 0xce7e9812, + 0x851d5f8a, 0x6fa2ecf1, 0xd94bf09a, 0x90407cd0, 0x410bdc67, 0xecb774cc, 0x2ee756f9, 0x957e0002, 0x6fc0ff64, + 0x26e608b1, 0x0bacafb8, 0x51c88700, 0xfd2cdb04, 0x61513885, 0x90fd60c0, 0xf6e01dd3, 0x2a836721, 0xebd254ec, + 0xf4336316, 0x8aa6bf52, 0xf24fa159, 0xc2932884, 0xcae94720, 0x8521f7d2, 0xcb485b49, 0x4fef10f4, 0xafeb494c, + 0x9cdb5a7a, 0x72a6afa6, 0x64559bdc, 0xd8b40abe, 0x6ba1eaa3, 0x7687c31d, 0xd183a782, 0x05f702d9, 0xc1ca75c4, + 0xe1c99828, 0x0c7bbe17, 0x6cbb6a78, 0x155d206b, 0x08f53a13, 0x2eefb04d, 0xa587d5fb, 0x8b53e57b, 0x7c59c773, + 0x114ba2ae, 0x5104c0b8, 0x8055802b, 0x16fae0b4, 0x93351367, 0x62693da2, 0x9a2df05e, 0xbac9f93b, 0xcb12ebb5, + 0x835d8451, 0xeb9603e1, 0xc424a781, 0x029659e3, 0x3e509c1c, 0xc1ccbcb7, 0xea19cbec, 0x806324ed, 0xdc12aadc, + 0x517fcdb5, 0xacd5d5a7, 0x40fbdeb9, 0xb383f2e8, 0xc39dab25, 0x9dd17595, 0x1401bde8, 0x80c297fe, 0x5ac60158, + 0x185216a1, 0x851cc2eb, 0x9c0eabb2, 0x6e6ae6e2, 0xd5d34f97, 0x2b601afb, 0x48d3e0b8, 0x826fa3ee, 0xadfd6715, + 0x5730f4ae, 0x98811fa0, 0x69ab1e66, 0xda8dacb4, 0x26aa8ab0, 0x4b540428, 0x16c754de, 0x9c653aa1, 0x09d60462, + 0xa6e9f22b, 0xb6bdba09, 0x9ef1792c, 0x7c165943, 0x98980691, 0xcc83aff9, 0xf842d891, 0x245a2e6f, 0xff1150e1, + 0xc6c37ea0, 0xf24895d3, 0x7384574e, 0x5d2a1657, 0x38abcb8d, 0xcb7771d3, 0x4194da84, 0xf631633e, 0x3a06640b, + 0x48802585, 0x481dcbad, 0x95bbb161, 0x83868e36, 0x6b7205c3, 0x1f87ca6a, 0x5af60683, 0x7bececf1, 0x7c6a2d7c, + 0xdfcb2c97, 0x87b98e88, 0x5c9a1384, 0x7ed72c0b, 0xcaa1c12b, 0x6a172e59, 0x6a1de616, 0x1cdc00a0, 0x76b0c96b, + 0xc3876f17, 0x88582aa8, 0x7677f03b, 0x8af9b1f2, 0x4b80c2b9, 0xb56dce03, 0x46f0bd99, 0x87efc0d7, 0x3b0521b8, + 0x67039260, 0x19b91075, 0xc0c69b41, 0x60154bb9, 0xd38d40a4, 0xd02735b9, 0xd9507226, 0x0d4234e0, 0x0142009d, + 0x99b13cee, 0x8cb988e4, 0x3efc6d2a, 0x576f683c, 0xea479083, 0x11565028, 0x16658651, 0xd7a6ff7c, 0x7c4fc0aa, + 0x10407195, 0x758fe014, 0x31d1b484, 0xf73c2bd9, 0xfc387438, 0x9a3745bb, 0x3a5b5c30, 0x49d6beb7, 0x1b76da88, + 0x119e1cf4, 0x32760646, 0xa53aa07e, 0xae45c525, 0xc08ffa4a, 0xc2fe38a0, 0x9b953919, 0x8781c655, 0x195b9bd3, + 0x4562218d, 0xf4db5ad1, 0xc5881df3, 0x02d66c1c, 0xd091f55f, 0x34765f16, 0xe2962c87, 0x1f7081f2, 0xb7d25175, + 0xeab480d9, 0x7d8947d1, 0x71be1c8d, 0x4ee949c9, 0x8b89c41d, 0x429509d8, 0xdfa5ed74, 0x8517b55b, 0x46b3a26f, + 0xca7e0118, 0x27b6e18b, 0x31f473ff, 0xa491b4f7, 0x19d6cba7, 0x372a9e30, 0x787029fe, 0xc3e9a53e, 0x8f997780, + 0xf6496a32, 0xc679b9fe, 0xdc0cf572, 0xef7f6fe4, 0xeb44ca57, 0x483f6b33, 0x4cb060af, 0xf663b266, 0x89b9c43c, + 0x0a8f86eb, 0xc7eaffcd, 0x8effd67a, 0xbe858d68, 0x3687d466, 0x140c00ab, 0xf0c832ac, 0xe7e9ffb1, 0xafbe6329, + 0x824de323, 0x8b614f9e, 0xa1fe85e0, 0xdfc57ec9, 0xb3362826, 0x76320f55, 0xe2180cd6, 0xecb02098, 0xed9de176, + 0x4bdcfb14, 0xda8f3269, 0xc32c8580, 0xab2eb4cf, 0x3583d6f2, 0xb3e2320f, 0x04c3e91f, 0x5680b7a3, 0x11728093, + 0xdeafaba3, 0xfb3fd38a, 0xa8027450, 0x6d3c4cce, 0xbb5b7e5e, 0x9e166d5b, 0xe297bbb2, 0xd2eba8fe, 0x18bcb06e, + 0xf4d82fbc, 0x2724e72d, 0x08e8c539, 0x8db41824, 0x375acf7f, 0x5afd6135, 0x38fd7434, 0x988d0a66, 0x3d0f0adf, + 0x3e8c39b6, 0xd2b3ea39, 0xa6c54eb5, 0xfe1b1df7, 0x7ea288ab, 0xeb705977, 0xcedce738, 0xd25bbbbb, 0xf187ce89, + 0x4fbe0698, 0xcf9bab9a, 0xda4e9a20, 0x3f3b2072, 0x21245d1a, 0x9201565d, 0x25170922, 0xab61dfc4, 0xbf1f51dd, + 0xe1deb0ea, 0x76982d33, 0x3fc5d318, 0x176ec98f, 0xbdf819f6, 0xe88dfa06, 0x32eb90f1, 0x0326c15b, 0xd58e1787, + 0x7a47ce4e, 0x59eefb26, 0xc505a3cd, 0xf24395c7, 0x2688869d, 0x5a290fe6, 0x159efd72, 0x89c8fa82, 0x06016827, + 0xd9aea6f0, 0x75ad61db, 0xddcc7370, 0xe3f514ae, 0xd5ba8db6, 0x2a14cce9, 0x96fe8add, 0x309a954b, 0xdd6d1825, + 0x06906f9a, 0x83f5da71, 0xdff014ea, 0x50ae229d, 0xfa8ba6c6, 0x6ce5cccc, 0x4f994042, 0xa16e6bc2, 0x98068473, + 0xe6250f7d, 0xbe278e70, 0xa597730e, 0x166ce4e6, 0xb3131edc, 0x9a5911bf, 0x644b428e, 0xf1b90fc1, 0x41aa07d9, + 0x7b331442, 0x93070871, 0x0bec5a52, 0xf43927dd, 0xdea4a6c5, 0x89be16c8, 0x7c0f26d3, 0xcfd823a3, 0x0f681626, + 0x42383adc, 0x844106c9, 0x716be68a, 0xa0006e95, 0x7c110949, 0x793edc95, 0xb3dd172f, 0xf80f5b9c, 0x39880e4d, + 0xd312146c, 0x5a7146a7, 0x6860ba0c, 0xf2663be5, 0x3adfb3d7, 0xb1073ec3, 0x12328a78, 0xabbb1cff, 0x71b189ec, + 0xaba00c15, 0xc0e83cca, 0x444506ff, 0x6cedae51, 0xf49ec6b4, 0xd0ecc4a4, 0x4feaf161, 0x84edbc08, 0x33f2fd68, + 0x2ef19520, 0x8e84ecd3, 0x68625d43, 0xcc0b319b, 0x97cb72f2, 0x5f524fb7, 0x2e0bbee3, 0xf2fe57a1, 0x2a1c050e, + 0x6b950ec4, 0x234db84a, 0x27734c1b, 0xe87719fa, 0x7a43c05a, 0x5ab5ec0c, 0x2b08d58f, 0x759d6f06, 0x917f140e, + 0xf55ce503, 0x450f4813, 0x9d55d048, 0xae1e2001, 0xa4867a39, 0xc9f6dea4, 0xd195e039, 0x81dbcde7, 0x5de23ef7, + 0x3b914ff7, 0x9bd61b73, 0xe8c7e2d3, 0xbe9eb304, 0x6a37c23b, 0xcb37ce6a, 0xe80676f7, 0xe0edf600, 0xd365a891, + 0x6dc70318, 0x18fd6d45, 0xdd0d019a, 0x3fd7c82b, 0x0142bcc5, 0xdd2c1cdb, 0x79c45202, 0x53d949b7, 0xc588d8f8, + 0x5428d0e8, 0x745e305f, 0xabfcdf13, 0x845fa961, 0x8b7827ed, 0xfd7f937f, 0x24f78cd9, 0x05602382, 0x5da673db, + 0xe257bcdd, 0x7766c9b5, 0x3af3eb8c, 0x36f743a8, 0x56ceefc8, 0xc72cab5c, 0xa5f62f47, 0xe23db9aa, 0xe8a9216f, + 0xe529d891, 0xcffc8973, 0x67a66e12, 0x3d8d62bd, 0x3f08a994, 0x188cc638, 0x2c5662df, 0xb78a336c, 0x72e73d4b, + 0x97a97e7d, 0x9969720d, 0x6b8d5693, 0x0d3ee1e9, 0xdc410730, 0x15338312, 0x1ef63c12, 0xd348b824, 0xf50437e3, + 0x68ef6861, 0x02f049e0, 0x59d0ef12, 0x4e22a8f2, 0x854a1cbb, 0xdac4cfd1, 0x4006c12b, 0xe80c103a, 0x879782d5, + 0x1c604b54, 0x19b522e1, 0xd33ac6e6, 0x654032ae, 0x2d319807, 0x2d359e99, 0x1a1e9b0d, 0x25ad54e0, 0xaacafdc4, + 0xdc97b367, 0xe554531c, 0xeee6254a, 0x6c426a95, 0x8d558fa8, 0xb0ea2e86, 0x857b8709, 0x08b12018, 0xb789b91c, + 0x08d7fcbe, 0x93ba9313, 0xd9585b93, 0xdc4b706d, 0x80dc55cc, 0x2999b72b, 0xa5577449, 0xa2512bee, 0x5a2078eb, + 0x5e0070ed, 0x0887987d, 0x80565b73, 0x506536c3, 0x7e57b53d, 0x23dd5797, 0x4966ea22, 0x8a500582, 0x21c7240b, + 0xff7046c8, 0xcf438d1b, 0x86316ece, 0x912abcd9, 0x3fee3d8b, 0xe922e287, 0x90c5db3f, 0xcfe2b84d, 0xaf44fc0a, + 0x6ee5ff82, 0x829ea920, 0x26d9b901, 0x5a42ada5, 0xcd091e1a, 0xff3cda70, 0xac834940, 0x221cee79, 0x5ed79581, + 0xcee290fa, 0x85ecb896, 0x9faa3c26, 0x99bcca64, 0x8100e252, 0x63e6917d, 0x73a2351a, 0x869071a5, 0x380ac2d5, + 0x81cacf42, 0x3f3eefc4, 0x0545a759, 0xa7b82a7b, 0xf370d628, 0x958f4ce4, 0xf8354a51, 0xa9d437af, 0x7e958771, + 0x6954284c, 0x3822839d, 0xac0946a1, 0x1526bfbd, 0x568e45d3, 0xea6efd49, 0x5aa4c9f9, 0xfe810775, 0x447dadc8, + 0x133abb5a, 0xad66235a, 0xdd1674f2, 0x94603801, 0xfb0432e7, 0xa788be73, 0xf036664d, 0x1200045e, 0x872f4c5e, + 0x4930fd29, 0x7a5e2c2e, 0xad5951fd, 0x56f29fc1, 0x935b9c18, 0x73ea6e00, 0x07947aec, 0x4b6d2b36, 0x0a8598f6, + 0x9267eb7b, 0x18d4f568, 0x0a271c25, 0x85530151, 0x35b215c4, 0x21a879bb, 0x2ef3da8c, 0xe4b33ac6, 0x1b1af382, + 0x89eae3b2, 0x20030264, 0x2ee78769, 0x930c70e7, 0xa68ec9a8, 0xf12cd26e, 0xe087a0fa, 0x7b97ea92, 0x7670525d, + 0xffffdae9, 0x71123266, 0x175114f8, 0x8218cdf7, 0xb0443721, 0x09361cb5, 0x40d68f33, 0x9ed3fe15, 0xd9b269f1, + 0xa22e765d, 0xbc142e94, 0x828b350d, 0x13a3249f, 0xde233dc5, 0x5971ef93, 0xed12c46f, 0x25f1b98b, 0xd25ec8d4, + 0x0acda1c0, 0x5c791182, 0xb34d9aec, 0xd560057f, 0x099255f2, 0x2db3be06, 0xd82141a1, 0x5cdd2186, 0x14de12ca, + 0x52f5c5d2, 0x81b72014, 0x1859134b, 0x59b41114, 0x1a0b55f6, 0x196c9d0a, 0xea8ea4d2, 0x3f74338e, 0xa56f73ff, + 0xdec05e31, 0x96ff5f6c, 0x9fb364b2, 0x94d592f5, 0x0fe15a45, 0xdc0ecac7, 0x30645f00, 0x55c58be0, 0x5d31a237, + 0xa6e17f07, 0xf472cb2f, 0x7598ac2a, 0x972945b3, 0x0784912c, 0x005cc1fd, 0x84da0aa2, 0x690bb3ef, 0xd9cd36e5, + 0xe31b7b03, 0xbc578257, 0xd0367b1b, 0x77c6e1c5, 0x025e9b76, 0xfee2425d, 0xc7d0c124, 0x468023c9, 0xee365d0a, + 0x21cf8e8d, 0x931676bc, 0x7f43719d, 0x18819074, 0xb99f69ce, 0x4cead4a4, 0xfa2c8bef, 0x75a65a4c, 0x3de7a8ab, + 0xd05b29c7, 0xecc0c4da, 0x17017e3c, 0x96698f29, 0xaeb342c8, 0x232720d0, 0x4166bccf, 0x459ba595, 0x3c411a56, + 0x763131b1, 0xb18b3074, 0x79d3f7af, 0xc6f7b55a, 0xce468878, 0x65f693f4, 0xf350ec0d, 0x02f38177, 0x95b5fb40, + 0xc99e9117, 0xbfe303b8, 0x29ff9e5a, 0x254bd200, 0x7f1242e5, 0x9fb691d1, 0x42469e9e, 0x97a8a94a, 0x196a400a, + 0xb6d0acac, 0xca3d9651, 0xd9917078, 0x82fa0f84, 0xb3b9df74, 0x8de08ebc, 0x4f29975f, 0x5af0eda7, 0x63924ba6, + 0xcf27f67e, 0xc6cfd452, 0xfe748846, 0x894e78c0, 0x917e0ec5, 0xca5d36ef, 0x81d7ad78, 0x9fcbf722, 0x753d8c59, + 0x14462d44, 0xa9e7a104, 0x0039be99, 0xbe35e7c0, 0x2c4d30f6, 0x9a0c0cb2, 0x9fad99b2, 0x16c762c4, 0x006ae763, + 0x79d89550, 0x34ec2959, 0x8d24e242, 0x91b27a91, 0xc48d40e8, 0xbb8f90b3, 0x2010c1ca, 0xb0a228da, 0x529a8ad0, + 0x84a6f91d, 0xbc1fddee, 0xb246c60b, 0x4edf99a5, 0x7e0861ce, 0x2189b7b5, 0xdccefcbd, 0x0a9dc2d8, 0x646ceaf5, + 0x4ca766b2, 0xef50ddb6, 0xc0a8df26, 0x49f89e45, 0x32c09f7c, 0x53c3659a, 0xf680a65d, 0x2fab951d, 0x363e8088, + 0x86caffe1, 0x6b7a1604, 0xb8158c75, 0xfe7a1af7, 0x76624064, 0xdb33afec, 0x3e2c78f9, 0x7d034ece, 0xe1aa8b78, + 0x0df5b267, 0x20b4aef1, 0x2d2a9805, 0xeac71293, 0x86324078, 0x88e352a0, 0x4c62ff40, 0x1e4974fa, 0x06b44105, + 0xfd030fb8, 0x4f3e9db6, 0x978f8b13, 0x4d51c9d4, 0x26adce8d, 0x14a79c2b, 0x51523461, 0xbb7b4da0, 0x71da0ca9, + 0x44e2466e, 0x8f205d3d, 0x4e493356, 0x8e3422af, 0xd6ba4457, 0xcb44445d, 0x54d95ac1, 0xcc92d679, 0xd60c8272, + 0x7e0a99cc, 0x9c862e04, 0x18a5dbc1, 0x27be81b6, 0x659cb57c, 0xc6a9b724, 0x884858dd, 0x1b46aae1, 0xf33382de, + 0x179a0306, 0x1568d9f1, 0x23d9b8d5, 0xcf593aa3, 0x12a9af0d, 0xe1ce9c46, 0xb7db09f4, 0x2ea5d721, 0xd7c31e2f, + 0x0f0d7814, 0x8ade225a, 0x507b0690, 0xfb7d177d, 0xa3217075, 0x2cbb72c9, 0xdd52bca3, 0x5e6a8d93, 0x3c1f8532, + 0x9cf8e2ea, 0x03e6fb9c, 0xed8cece3, 0x996b7799, 0xcf0e5ef0, 0x7c579400, 0xa15edd73, 0x62a60bab, 0xf4aa6e2a, + 0x7a9c44b3, 0x1ef5ac60, 0xaba2334a, 0x6773e787, 0x586aa8a9, 0xcd9ef428, 0xb035f668, 0x2b0f23fa, 0x3680d4be, + 0x2f7021e7, 0x4438bca5, 0x3bc15ea5, 0x7fd74e32, 0x6a629a69, 0xe87f2511, 0x88bc9d11, 0x7bdf93da, 0x912dadd9, + 0x42edd850, 0xa112e12f, 0xf544c27a, 0xe64d244e, 0x5f9d5a57, 0xd685a03b, 0x750d8dbc, 0x7ce394ef, 0x30298664, + 0xd912ca22, 0x9af7d76f, 0x65e02f8b, 0x1dd27c1a, 0xb5d519dd, 0xc7b172ba, 0xcf1c090a, 0x6ad3b5bc, 0x53cf016f, + 0x8681185f, 0x338269a3, 0x6ec858a7, 0x47bddccc, 0x14e4d2f5, 0x1dc21af8, 0x39d707a6, 0x6fd5f3fa, 0x939807e5, + 0xc96803e5, 0x4f8fe1c2, 0xee698bee, 0x5381aec4, 0xd0f67ed8, 0x53728352, 0xbd8aae34, 0xfba4f12b, 0xdb8886dc, + 0x4c85feae, 0x5f3068a8, 0x851b3890, 0x8d4f5e28, 0x0134052a, 0x476af871, 0xe107744e, 0xf936e2cf, 0xcf34cbff, + 0xa3eeb478, 0x552c3230, 0x2cc7317c, 0x4b40b00e, 0xf0aec22c, 0x5e0197f1, 0x75134990, 0x70be63cd, 0xeff8ab81, + 0xb01113b1, 0x092c0b15, 0xaee2b8cc, 0x582ac50c, 0x0824c59b, 0x86b0baee, 0xdc893e1e, 0x345327cf, 0xcc2f1c5c, + 0xcfd1967d, 0x6d48f322, 0x07a70639, 0x5c732efd, 0x90cbe794, 0xfbf0befa, 0x8375d79a, 0xb08c6bc0, 0xac76a5f6, + 0x03d3c1c1, 0xc8c84ade, 0x7546a913, 0x40dc781f, 0x93fd1f40, 0x2ba1782f, 0x94221d95, 0xad27c138, 0x6ff1c284, + 0xb59823f4, 0xdfc3d318, 0x984deebd, 0x3795de20, 0xd0769eab, 0xb54dc663, 0xeae6b621, 0x39df12dc, 0x09cd9eb0, + 0x7393d1b1, 0x801604ee, 0xaf37bb16, 0x2b86a17a, 0xb0f42997, 0x77db6524, 0xbec96ce8, 0x4ae23729, 0xb42cc3d3, + 0x138f7e8c, 0x22c6ca98, 0x0a586b03, 0x3b4a4529, 0x81b335b8, 0xadb7459b, 0x2553857f, 0x905dc086, 0x1a90ab19, + 0x96aebde8, 0xd5178a9b, 0xbce063e6, 0x7033476c, 0xa5979c55, 0xac80e77c, 0x1f9ddda5, 0xf52e58c2, 0x6cafe992, + 0x5daa4e44, 0xd0418baa, 0x3000c9f8, 0xbff03b8e, 0x6a3a239e, 0xa1e34e6c, 0xac8175eb, 0xa7e38f17, 0x9bfd61d2, + 0x20a9f171, 0x8dee22f0, 0xf0764484, 0x4d699789, 0x7e714570, 0x2cec8567, 0x6419a897, 0x338a748e, 0x61425469, + 0xd6cb856f, 0x3f037265, 0x9c8cbb80, 0xd0e22cac, 0x7b17f555, 0xe2c66adf, 0x158f31ba, 0xa2b167e0, 0x95e903fc, + 0x63c5045e, 0x6631c312, 0x29c0e6a1, 0x02c1c4dd, 0x35b21b81, 0x9fd6711b, 0xca4b4e40, 0xe6592306, 0x114619c1, + 0x6b07da86, 0xa76b5025, 0x36421c1a, 0x8e3fccad, 0xdfb1d9a0, 0x46bce482, 0xed802fa2, 0xd5bbeb2d, 0x83011c74, + 0xe40b9cbf, 0x98d78dd5, 0x1373ce25, 0x35ff33a4, 0x499a16c3, 0xc7609dbd, 0x8bc631ca, 0x322b759a, 0xf793b56c, + 0x464d158b, 0x803d78de, 0x2093656a, 0xe3ab1633, 0xad0e2598, 0x7ec11cbd, 0xe11a1274, 0xd5df6e48, 0x7542d937, + 0x37fb07e6, 0x82fa2fab, 0x175960cd, 0xc28b3a52, 0xb28484f1, 0xf48cc684, 0x8a92368c, 0xe19d60bf, 0x9cf1a7b7, + 0x1a23f0c2, 0xe5534a3f, 0x29f5bc3d, 0x9e79b44d, 0x7c68fdde, 0x82b7033d, 0x3e0ba209, 0xe15d2513, 0xbc54d688, + 0xab0a8773, 0xbcb971a7, 0xfd9736d5, 0x665a9ba6, 0x651d4262, 0xe41df60e, 0x8b199866, 0xea564a8c, 0x892d4866, + 0xf671abf3, 0xf3e25a7c, 0xe10528e4, 0xa3f0ba57, 0x50d31109, 0x1d1e032b, 0x0e04e75c, 0x7506eeb3, 0x32f759f4, + 0xcc6a3d92, 0x74ea14eb, 0x0b290de2, 0xac1e402f, 0xb8a2ebc9, 0x92134e8a, 0x142856d8, 0x2259650f, 0x593c4855, + 0x68d6fa98, 0x8e03d190, 0xcb559ecc, 0x21042f97, 0x27d92972, 0x040be777, 0x3f083187, 0x350fc4eb, 0xaa8dd017, + 0x5c518523, 0xb09de1a4, 0xd137496e, 0x4dd60c81, 0x8e641e71, 0x48fd0c37, 0xa4dc9def, 0x76722804, 0x64196485, + 0xecc098b7, 0x4cbe6d87, 0xe97092c0, 0xee19c0e5, 0x1bd24ba1, 0xcd53149c, 0x6bedfd32, 0xcaea4f5f, 0xe0f2d53a, + 0x32222cce, 0x62f04f78, 0x281c4aea, 0x92f1d746, 0xddd30925, 0xbce5006b, 0x1964137d, 0x2f339eff, 0x073b06b9, + 0x3806fabd, 0x7cfdd1de, 0x8ea92392, 0xca2bf0c7, 0x6f19258a, 0xf3dfff39, 0x838e7d04, 0x21ee01b5, 0x4f79ad31, + 0xc81dec10, 0x8a021570, 0x032740a9, 0x671404de, 0x64b4f318, 0xe425749a, 0xb9f196ad, 0x752ca164, 0x55918347, + 0xfb3cbd07, 0x4a250a48, 0xf90af985, 0xdf827279, 0x1ff54a6d, 0x73a2e24d, 0x9d8a17a6, 0x22953d50, 0x9ec66708, + 0x21716936, 0x9ff27cd4, 0x66cabc9a, 0x7b15b7f9, 0xafa68161, 0x63ea3760, 0xef7e1f6d, 0x733d72dc, 0xebc902dc, + 0xaa8ecd95, 0xc633714b, 0x77cc13b6, 0x997bfd96, 0x289ab7ca, 0xeba7a264, 0xfd5c5651, 0xc3411a5b, 0x5d834ba4, + 0xd8bf1606, 0xdb24fb68, 0x1b3b9b6b, 0x80bb8791, 0x3f087e8e, 0x41c60f54, 0xe00c8f0a, 0x325554ec, 0xd1a0e434, + 0x4544b041, 0x9c42a29e, 0xb11832d1, 0x5af8ea30, 0xf9a79ab1, 0xb003d5a3, 0x942ca953, 0x582c8920, 0x2db624e1, + 0xe1424060, 0x412a9157, 0xc18d9a94, 0x68a427e4, 0x21cad876, 0xba1be04a, 0xd1ef84a9, 0x08988413, 0xe359ea1f, + 0x4cfe8dbe, 0x59863e1e, 0xf8327125, 0xd9f1753d, 0x77b4a25a, 0xf8b114c3, 0xf4259e25, 0x3d952dfe, 0xa0191376, + 0xe09dcb7f, 0xb761cbca, 0xfede9076, 0xb1404d99, 0xe1fc4db2, 0x00f50f6f, 0x7ae04d6c, 0xb339f845, 0x8ed71398, + 0x3a737281, 0xd04cef9f, 0x57a1615c, 0xef045732, 0x04503c6b, 0xddac7645, 0xa8f9f113, 0x61ef0675, 0xd21eb19a, + 0x0c4d93f9, 0xa485da9c, 0xf2ce65dd, 0xf2245f2d, 0x92090dc0, 0x72d599bb, 0x286d1e79, 0xad640608, 0xc7acf68d, + 0xeda7eb5d, 0x950e6744, 0x3922089f, 0x7b3037f8, 0x9e11b096, 0x7a46bb38, 0x1a15acac, 0x35902c06, 0xcc114eb1, + 0x81e319c8, 0x84c439d1, 0xafc550bf, 0xdc85cf14, 0x696e8ab8, 0x0a2ca729, 0x47c2502e, 0x8cf7732d, 0xb7589765, + 0x076ee187, 0xc4e26443, 0xe1c28f20, 0x8e01fc17, 0x97d32480, 0xcabb61d7, 0x82130285, 0x05aa1ce2, 0x6fd4ffdb, + 0x679b3fe6, 0x3454908f, 0x471e3edc, 0x36336495, 0x0a4739a7, 0x67cbf051, 0x6af0d047, 0x7da98fbb, 0x66174df0, + 0x8f75cbfa, 0xb42d0bca, 0xadceb870, 0x049a5a91, 0xa70439f1, 0xbe5b57ac, 0x856f0055, 0x07805fcc, 0xff4a7940, + 0xba3dd26e, 0xcbe3efbb, 0x90fd3ca6, 0xef180cad, 0xd49a2fe1, 0xeac70e33, 0x47640130, 0xc80fbcfd, 0x60d37b9a, + 0x66157a7f, 0x33b6be90, 0x9b7f1b83, 0x896fbe7d, 0x638886f4, 0x39b0322c, 0x37dcee0c, 0x54771a0c, 0xba7dd17e, + 0x19846706, 0xc08e1d00, 0xe17af913, 0x3221206b, 0x4eab89c7, 0xe589fd1f, 0x42b34450, 0x7fe711da, 0x7d235a38, + 0xbd725ee7, 0x8abcfd6f, 0xff5eb551, 0xdefdf921, 0x11c61d72, 0xc184d800, 0xe0f21ede, 0xbca2053c, 0xd7cce490, + 0x477fd3a2, 0xfef06802, 0xe205b0a1, 0x6796703a, 0x55a826c0, 0x91f7cd58, 0x28fe3da1, 0x68d27f1e, 0xa154309a, + 0xbd85d001, 0x4676e242, 0x2a4df060, 0x48767dfa, 0x7ba2eebf, 0xc3477ae5, 0xaf147174, 0x91fba18a, 0x2784b532, + 0x753a8929, 0xef7923b6, 0x840468d0, 0xee3c5ecc, 0xb98a6df0, 0x6b1977af, 0x59d7d858, 0x044e36dd, 0xc6441e11, + 0x5ab4eb9a, 0xd6954d71, 0xdbeb3110, 0x2ee22ed4, 0x3b09d65e, 0x226ceb8b, 0xf27a3424, 0x09bf27c5, 0xb1c9aac3, + 0x2db6a327, 0x3e15b3f9, 0xaab2e756, 0xd553ed67, 0xb694dba3, 0xee34f592, 0x23381868, 0xbb0d2b4f, 0x20a3cbf8, + 0x31daf122, 0xaf83621e, 0x3f6e3ade, 0x4475370b, 0xd12ddb85, 0x7bb94e5a, 0x970544bf, 0x471571f7, 0x8eecabd5, + 0x448e570b, 0x7e811c48, 0x76705125, 0xf4d7ef8e, 0xdbfa0a3c, 0x9871cfe6, 0xb9f13da2, 0xd06ce447, 0x9bc03f0d, + 0x34a34a38, 0x4b125fda, 0xbcc405cf, 0x3086bfd3, 0xf402de74, 0x693de838, 0x390fb739, 0x0304de02, 0xee05c928, + 0xb9b2b7c5, 0xe8692942, 0xfcff3148, 0xe8b6a95a, 0xba8439a4, 0x94e0ab9d, 0x2b67abe7, 0xf6b887ac, 0xd51d90fc, + 0x0cfe4129, 0x08bedd8f, 0x20aca1e2, 0x2d97f7dc, 0x768baf2c, 0xe070c4cf, 0x887b630a, 0x39226ce3, 0x223d3135, + 0x67087ecc, 0xde71591e, 0x9f449967, 0xe29397da, 0x4c86b95b, 0x9d0e9d46, 0xfd45a499, 0x8dff712c, 0x4b9efb11, + 0x8a7666bd, 0xb34bbc1a, 0xb8edc228, 0xd40a8ef0, 0x1c258871, 0x694cc695, 0x7f4ae6c1, 0x05798857, 0x0b2b387d, + 0xa3eb06f6, 0x26938660, 0xe6be3e7a, 0x9f04da64, 0x280c94cc, 0x88ba3c14, 0xf1eb649e, 0x1fb22abc, 0x3068af2e, + 0xd508d5f7, 0x456a7c1e, 0x755ccda5, 0xab47dfee, 0x37baae20, 0x522d9457, 0xd3bf8559, 0x557a5787, 0x54f484d2, + 0x834f0bf6, 0x90f10bec, 0xc89437f7, 0x40f24d50, 0x7da6c287, 0x85d4673e, 0xf5ef574a, 0x603ad149, 0x776d52f6, + 0xd5ff1c6f, 0x0b6ae110, 0x7f8e75bd, 0x29f34d63, 0x1a591451, 0xb158e06a, 0xb3cbde06, 0x5efa86f8, 0xb750b02e, + 0xa1d7d275, 0x928f8907, 0x7c1a228e, 0x59337335, 0xf7b7d508, 0x0ccea95f, 0xa3425d64, 0xdca257c0, 0xc43ca2f4, + 0xc65aaf40, 0xfee70d4f, 0x2e4112db, 0xbb52a3fd, 0x617d350f, 0x0235fb8d, 0x2738b3a4, 0x94e0034f, 0x57b28e1d, + 0x1eb54cc6, 0xec150a15, 0x4129a4ba, 0xa4e0a2df, 0x9c47a5ed, 0x8d963a28, 0x9b51b089, 0xcdd65aae, 0xc4bc26f6, + 0xeab4f15f, 0xc03f5105, 0xbbf8d7a1, 0xbbedb86b, 0x4ff3abf6, 0x4cf91f47, 0x81e3468b, 0x0203924a, 0x1280b5c1, + 0xfbeafea1, 0xa515e378, 0xa0af03eb, 0xc8ef5d11, 0x0bb01526, 0xae116bd4, 0xfec987bf, 0x455b2152, 0xa573f4cf, + 0xf7080fa4, 0x5186a1df, 0xb680ffe9, 0x18dac264, 0x3fc55505, 0xadc52c04, 0xab52b9a3, 0xb43d0280, 0xbbce7dc7, + 0x85a91ee6, 0x71ef84de, 0x4c0fd9fd, 0x3096c86f, 0x4804c9b7, 0x8c3e5aad, 0xdf5ba9cc, 0x6a8d1d59, 0x17525e19, + 0x85a919f9, 0xe8d2ae05, 0x4fd7bc70, 0x25fb552a, 0x17ed91e4, 0xb1fcf491, 0xd207fadf, 0x987b012a, 0x7570c3e8, + 0x4ab8eee5, 0x120b730d, 0x6ed38b5d, 0xb957464f, 0xd5d803dd, 0xf6b76176, 0x9d5f8513, 0x9a7ebda1, 0x5f4c70cf, + 0x25c56da4, 0x6dc8a442, 0x5eff37d7, 0x509f5861, 0x786958c1, 0x0dd17bda, 0x927069bb, 0xec2889c8, 0xb747b354, + 0x3504c4f1, 0x94258395, 0x05836f5e, 0x12068054, 0x42751853, 0x05859782, 0x784882ad, 0xc3988e94, 0x20c7eb21, + 0x6f5d9be5, 0x23840867, 0xfc160e47, 0xbb3bfe14, 0x2497e7ee, 0x42e5f8c2, 0xbdb0d262, 0x97d52dd1, 0x512c6081, + 0xf2beb1b9, 0xdab5a157, 0x9a86a417, 0x1f9a1932, 0xcf9da6e5, 0xf82d53a0, 0x2b0baa7e, 0x2327b4a2, 0xd71a161a, + 0xdf403475, 0x948bfb49, 0x24fc9862, 0x225123cf, 0xced76b57, 0x755bc1ec, 0xd0a2dc53, 0x64bfa749, 0xeca16661, + 0x61183c53, 0xcbbf1397, 0x49c5459a, 0x18e394b2, 0x1be4f48c, 0xf7d8ec91, 0xd81fc5c6, 0xcdb1c20b, 0xfe3c90b0, + 0x4b836637, 0x556781e5, 0x5af18ba0, 0xf0e454e4, 0x79278ba0, 0xe0c76baf, 0xb36c577e, 0xa23b9489, 0x11305ed4, + 0x1b2cf419, 0x250a4de5, 0xe5cf8de5, 0xc5aba253, 0xaba81623, 0xbf255563, 0x5956abd8, 0x54354af8, 0xae4ae23e, + 0x138d859c, 0xb6ab68ea, 0x28c55e2c, 0x5dc5e110, 0xb467d47c, 0xc3cc8685, 0xe1566c24, 0x322c8890, 0x677857fe, + 0xfe8eb38f, 0x0b61ea66, 0xddd1b4ca, 0x6f1cbf51, 0x44f08357, 0xcbe21396, 0x744fe8b9, 0x143b958b, 0xab05e6fe, + 0x3c54dcd1, 0xa5b694a5, 0x0030a4b7, 0x254a05bb, 0x4214883d, 0xd53902f1, 0xcc0e599a, 0x22298028, 0xa55470d9, + 0xbee9ff6c, 0xaf1e2a5e, 0x0f69d102, 0xfc02aa22, 0x19f1d3c7, 0xb6aa4ebe, 0xf1751cec, 0x8a0ae852, 0xd180a904, + 0xad8605a1, 0xb5f57878, 0x6b6db0ed, 0xaaf42553, 0x64f45bb7, 0x9ff787a7, 0x84e527c0, 0xb2839040, 0x4f044fec, + 0x14cbd950, 0x522ae19f, 0x0030916b, 0x517635ca, 0xc3a74420, 0xf13d6a0e, 0xeadd4b6e, 0x8e20585b, 0x0b36ab20, + 0x5f6b6be3, 0x6126831b, 0xdf84a59f, 0x4dd6380d, 0xb77899f2, 0xbb5e5703, 0xf2086ddc, 0x6532cc3a, 0xdb8aa73e, + 0x6570ee92, 0xf32f68c8, 0x019ddfdf, 0xa57896e4, 0xc10e0c77, 0xe3f15ffe, 0x900e26cc, 0x3cd78e47, 0x14354762, + 0x9d6a699a, 0x3ab5c295, 0x15bd0b3f, 0x751f7fab, 0x134faaa0, 0x70e112a9, 0xad293978, 0xdf35c6f2, 0x4ba653e2, + 0xc4fefeb4, 0x5b4e5baf, 0xefb1d2dd, 0xf79e0d2b, 0xbc488b42, 0xe7f21b7d, 0x5aa9157d, 0x6b86dec9, 0x835312f6, + 0x6adf72e9, 0xf613d479, 0xa2379126, 0xefe91cb2, 0x124d80d8, 0xf810e5b7, 0xa9780fd0, 0x15f06bb7, 0x50145248, + 0x502c59c2, 0xc8271ed4, 0x718152d3, 0xb138b95b, 0xfb031cf7, 0x5c4d4895, 0x7aa222ac, 0x566cacfc, 0x3283df05, + 0xe3b5f754, 0x91288231, 0xeb9b4a58, 0x3ab36dfe, 0xae69ec8f, 0xf9e33e4e, 0xbe85bb36, 0x870dca46, 0x7154ead6, + 0x6c3d6885, 0xde765276, 0x09309ecf, 0x5d1c9e35, 0x7cd844a9, 0xa1252152, 0x9967ff0d, 0xa792dde0, 0x2b5e20c1, + 0xebccd1cb, 0x3ceb2b15, 0x49538aae, 0xc1ae7073, 0x10ea8682, 0x6afbba45, 0xe0973996, 0xda059f47, 0xc5fdac19, + 0x7f0f74b3, 0x424d8f46, 0xfd844473, 0x2a8aebd0, 0x69dc3074, 0x86fe309d, 0x55c9310e, 0x0d7f978c, 0xc6dbee41, + 0x19c6edb1, 0x95c916c1, 0x77110905, 0x17deb9f5, 0x8bd33b28, 0xb483f91c, 0x1121b3cc, 0xf6233cb6, 0xef243748, + 0x9271a226, 0x01d89f4a, 0x2338f83f, 0x215fdd9c, 0xc62470c2, 0x6159032f, 0x7c523bea, 0x1d80e70b, 0x49d67bf1, + 0xbf6fd8c2, 0x6555f052, 0x224ac6ca, 0x1095a7fa, 0xf4161b64, 0xd3023679, 0x97f93cf6, 0xe8d0a971, 0x7355a50a, + 0xed4a763f, 0x977bffbc, 0xde073c28, 0x52826765, 0x97e44e42, 0xaed68ae8, 0x8ace251f, 0x71edc9de, 0x16cab2c1, + 0x96eddbcc, 0xfb734d47, 0x71480c74, 0x84b94b94, 0x6c236c04, 0x4d0c3de6, 0xb562e004, 0x3a986190, 0xadc294cd, + 0x3b006f5a, 0x2146b5c3, 0x196571c0, 0xdc6552e2, 0xfa52b97f, 0x11f974b4, 0x7b966641, 0x23f081fa, 0xae22a48c, + 0x056ebc03, 0x5dbb6742, 0x273b0378, 0x19f09b75, 0x35fc426a, 0x16c0e434, 0x97eb86cb, 0x323f6f61, 0x077820d4, + 0x2ae697d9, 0x2dca47ac, 0xe4b2af3d, 0xb53f500f, 0x7f8e17d1, 0xdcda13a7, 0xc531b97e, 0xdca522c0, 0x226ed058, + 0x90551792, 0x175e9a12, 0x53d3838c, 0x12f4451f, 0x738d2aea, 0xeb18a832, 0x5646355b, 0x8695d90d, 0x2a87de20, + 0x237b5c4d, 0x7d56d740, 0x8696dd8f, 0x0eee469e, 0x0477d2be, 0x76420bfe, 0xbfc3c534, 0x2d734253, 0x14749579, + 0x33a47713, 0xf58375b0, 0x9db44d59, 0x5dd5a550, 0x9594103c, 0x672172b6, 0x9721a601, 0xf22bce5d, 0xc6078ab6, + 0xc214a017, 0x7d2bcd16, 0x4461cdaa, 0xe9fcccc3, 0x9dd03af7, 0x00d0ab31, 0x4044ba0f, 0x079023d6, 0x3356d18f, + 0x07f4cc75, 0x8a15eaca, 0xd7e93425, 0x8f749cb9, 0x7f0da3b7, 0x927a943d, 0x23258aa0, 0xe65189c4, 0x1a97f8e7, + 0xbc772ba8, 0xec579f52, 0x31bca957, 0x0ff87e8a, 0xdba76ad6, 0x98d22cb6, 0xc20f56e0, 0xa647618b, 0xfcafe613, + 0x0b792c28, 0xd0d3d611, 0xb0206927, 0x91bee8e4, 0xe275c131, 0x5eb76a17, 0xb3aa5551, 0xd2709740, 0xbd98bfa9, + 0x82d101bb, 0x17ec637e, 0xa1f440a2, 0x4e8ba3f9, 0x22e2e36d, 0xca6a319d, 0xfbb6696c, 0x14137e4b, 0xfd07b93a, + 0x88187f43, 0xe25ec3c6, 0xeed94802, 0xd3cc9ee2, 0xbf24a2cb, 0x6a135c35, 0x0e03b434, 0x4ec89ccd, 0x6ea06429, + 0xd48a5822, 0x10189fcd, 0x4d8f8ce1, 0x1fb21f86, 0xdd542d32, 0x944bd3ec, 0x6df5785b, 0x588b4182, 0xf9fd1d64, + 0x94ff2b13, 0xd01c64b0, 0x02e8d32f, 0xfb51a649, 0x675b91f2, 0xe468ebcd, 0x0b78ef1b, 0x32bd69e0, 0x977084b2, + 0xedee1dc9, 0x54a06b39, 0xb4c0719d, 0x8b8f4989, 0x608d4eaa, 0x034e4683, 0xb2558cd0, 0x4feb8c0d, 0xc6a764c6, + 0x97c6225f, 0xb90e31e6, 0xcb6f3bcb, 0x29c445da, 0xf445a686, 0x83fdbecc, 0xd968f247, 0x868d2474, 0x9bd3cb08, + 0xa0f84f35, 0x91e211ad, 0x93a8c50a, 0x44a68fa8, 0x05aa1550, 0x1fe3a0b7, 0xe31f0d49, 0x6b7586d5, 0xb259cc82, + 0xf4c1cb1f, 0x942452d9, 0x4ea1beab, 0xa47b1a74, 0x7d1f64d5, 0x4afff063, 0x8533476d, 0x57313806, 0xf63d7c84, + 0xe3b34678, 0x8d5f885a, 0x4b28b571, 0xf975ed59, 0x895c16da, 0x30c3bc0c, 0x8ebbba49, 0x212ec712, 0x189c94ef, + 0xe2de388d, 0x12b13ee8, 0xed353d9e, 0xb62fedf6, 0x1c0c0536, 0x77d7ab11, 0x25b7c9ae, 0x69b40dc5, 0x5bf65ca2, + 0x8e4af743, 0xdee6c528, 0xd9c226e8, 0xddeb659c, 0xfbd87368, 0x0a0c0944, 0x2e1dcc24, 0xd1d71331, 0x6ca6d66d, + 0x9aa7ed35, 0x89f4b92e, 0xebe97071, 0x14f55b49, 0x4bad0750, 0xe692d6b0, 0xe51f95c9, 0xbd618500, 0x0230a9eb, + 0x3b6ee594, 0xba3212db, 0x96e1dc9e, 0xb6a8ed36, 0x0e939743, 0x52fad7e9, 0x3ce8c1b0, 0x31d9ba70, 0x6f0cde45, + 0x162f7ba0, 0x694fcbd7, 0x06d9a23b, 0xecffd9c6, 0xa0ac4b0a, 0x6004d03f, 0x8a6d36d8, 0xa616d57d, 0x9ea25802, + 0x65fe2b0e, 0x0f2c1340, 0xba689a69, 0x03c0caba, 0xc2c2867c, 0x74508495, 0x5d7e5ff7, 0x5f44a6ee, 0xe05a8d92, + 0x20641689, 0x7cefbb52, 0xb3abf4b1, 0x68258b5d, 0xfcab5325, 0x9d01fb49, 0x883ff097, 0xda553543, 0x3a09bd66, + 0x9ec26962, 0x12316d11, 0x9bafc881, 0x453c698c, 0x5b1d47c8, 0x707bf851, 0x7bd92353, 0x8179137d, 0xd6d03391, + 0xd490037d, 0x9265db64, 0x28e997af, 0xa742c9ab, 0xfbc8f9ee, 0x1976804e, 0xd7532d61, 0x0f81c023, 0x53457024, + 0x95ebafb7, 0xa5e16160, 0x7cfb5806, 0x73eaff15, 0x934d782b, 0x0ea9c60e, 0xa1e6b17c, 0x3231b481, 0xdb2f5923, + 0x23207cae, 0x8d5f5867, 0xa2165d07, 0xb312e6ca, 0xfa28b7d8, 0x0bdb5355, 0x73c38cf3, 0x95ed4789, 0x26e8d8af, + 0x38e0e6c3, 0xb7e8cb7e, 0x0cfeeefd, 0xbc8ea901, 0x0030d958, 0xd0d597d2, 0xfcad5b25, 0x5d950693, 0x131f4e81, + 0x421fb3dd, 0x723a94b2, 0x13d1549d, 0x5eff5c43, 0xc7199ac4, 0x06be9094, 0x1345abea, 0x6cecd91d, 0xfc78a14c, + 0x39b505d3, 0x55f77bfc, 0x2f4c8894, 0x00d9ca3b, 0x588a852b, 0x54232571, 0xfa1d3614, 0xce893159, 0xa7eb369c, + 0x1720d0b3, 0xc7493369, 0xe6d03427, 0x7ac9cd9d, 0x225b4f73, 0x4e5c46e3, 0x0326de68, 0x398bd1f6, 0xfd8ae901, + 0xcc027be3, 0xdbd37a6f, 0x1187778e, 0xb80e1e44, 0x3bac8341, 0x4045becd, 0x83678105, 0x361d5b98, 0xc041b4ab, + 0x0ff20c75, 0x6d85769e, 0xcfdf8eba, 0x66ede2b8, 0x7546fabc, 0x31a585d8, 0xd95d8b6c, 0xcd820ba4, 0x17e5f470, + 0x74ebec06, 0x24c2c8ac, 0x58a8324d, 0x88d28336, 0x1d2cb81e, 0xa3737889, 0x83cb6246, 0xb4870a7b, 0x40e7ce15, + 0xe6c2d647, 0x7ce1cda2, 0xf519577e, 0xeb98139a, 0xb188dbcf, 0x410a8fef, 0xb32c0ac0, 0x26934fb0, 0xfe6bb85b, + 0xe6e7e321, 0xfe3815cb, 0x39891e92, 0x9ea928a0, 0x808848c2, 0xaef16ded, 0xf3f5d35d, 0x3f4d699e, 0x61750dc2, + 0xfc61f29b, 0x16949d63, 0xad27b6ae, 0xe7f80937, 0x8d2ccdd7, 0xf0c5575e, 0x27ec8ca0, 0x76f87a58, 0xb4acd187, + 0xbc6eca0c, 0xcdd03f43, 0x1636010f, 0x7c569d41, 0xcf6720a5, 0x5a1e05d3, 0xc88dbbac, 0x537ceaf9, 0xd2d1567c, + 0x471cf798, 0xfc4ea62a, 0x40085c14, 0x8a2f153b, 0xd340d9a4, 0x5e62d588, 0x0b4cbbc4, 0x2af9446b, 0x74a4ec51, + 0x0b60cb45, 0x2880985a, 0x98b7ca90, 0x84884828, 0xd8b729c2, 0x160cf0e2, 0x8b9e0a33, 0xd528ff1c, 0xf3713f27, + 0x53789656, 0xfd8d1603, 0xf199d50d, 0xd76ef7f1, 0x1cd59be4, 0xc1f5f721, 0xc299c87e, 0x9f0378aa, 0x112cfe71, + 0xb0bdbdf6, 0x20e7ea47, 0x0a04f32a, 0xe613f10c, 0x277b4935, 0xb8752a42, 0x456313a4, 0xd7091a19, 0x15c24e40, + 0xb2218afa, 0x1c6fa453, 0x4333f97b, 0x8143703d, 0x4205ffdb, 0xf53435cb, 0x90f06e14, 0x125e7710, 0x3e8b817b, + 0x4efc46c7, 0x220aca2c, 0x29ad3364, 0x209d4a4a, 0xe5fb6179, 0xa2cff83c, 0xdf718e93, 0x8c81498d, 0xaa8486b3, + 0x308de16e, 0x844c793a, 0x7e1e2d40, 0xee069493, 0xa1cc8fcb, 0x21612b7b, 0x9294c821, 0xc640f204, 0x3531fdf6, + 0x2787b76d, 0x98432667, 0x27de809e, 0x71e85079, 0xa68d1b3f, 0xcd155b42, 0xfd2ce635, 0xf85224f4, 0xb3cee050, + 0x45447425, 0xa3bcc3f6, 0x7b391115, 0x6c83c7ef, 0xb372e7b8, 0x6b624482, 0xc9a8beec, 0xcd430082, 0xf1eb550d, + 0xee59781d, 0xd0588afd, 0xf799e61e, 0x54b9434e, 0xdc85c5a8, 0x18dfdd47, 0x128a80f3, 0xdccf26be, 0xeb845176, + 0x93b7d3b8, 0xc4ab1f61, 0x9aa83897, 0x581681f5, 0xf71d557c, 0xcbf9bb05, 0xa1d5817f, 0x1a32e7f3, 0x6af2c6e2, + 0xe69f42d7, 0x2bdef124, 0x17477b10, 0x8daf1655, 0xb66c34c9, 0xd7581a72, 0x136ce945, 0x20d22044, 0xf7b3ce34, + 0xd09db28c, 0xabf654e2, 0xc7bcb6bd, 0x3d3d6f97, 0x42200aaa, 0x6d1f91e3, 0xf184c3d4, 0x89833d4b, 0x28e6804d, + 0x1621d342, 0x2a4bad38, 0x11f41b4b, 0x8fe52cd3, 0x4fa4225b, 0x4ccea7e4, 0x3dd43888, 0x56f9f22e, 0xf3bf36ea, + 0x7838d875, 0xc2ab6978, 0x62b79fa5, 0x04409b8e, 0x8c416081, 0x07aeaecc, 0x2f239e11, 0x84545410, 0x5211d675, + 0x364eb6bc, 0xb789ea7c, 0x9fe64366, 0xf90b449e, 0x062481dc, 0xdf347d37, 0x7dd71cb3, 0xc451d00a, 0xc04dbadf, + 0x18c3df35, 0xdf32c4e8, 0x570372ee, 0xeb5bb1df, 0xbbae95e5, 0x77e7e52b, 0x059718fc, 0x71c41a94, 0x3fcd86e2, + 0x3972c4b6, 0x6de00867, 0xecd860d6, 0x5b4fa575, 0x64fe7e9b, 0xbc2421ee, 0x1b272e20, 0x81f55f73, 0xa4ec1311, + 0xc0c1ca2d, 0x9c11979a, 0x2dc5ab1a, 0x79905742, 0x13b3c373, 0xe4f47f7a, 0x594faf39, 0xa7d76a91, 0xc9c8091d, + 0xf2e79d66, 0xe0909c89, 0x8a05d398, 0x4a52b86f, 0x35fc9e62, 0xca009dfd, 0x2a5f31c0, 0xaa19da7c, 0x9da05481, + 0xf6a03189, 0x12f8c923, 0x36527327, 0x181d6027, 0x775fe5e4, 0x4bf77ef2, 0x2500da96, 0x6be8464f, 0xdac0173a, + 0xf771709c, 0x6e73f62b, 0x25583611, 0x5416bb9b, 0xb8092dfd, 0x72d102a2, 0x8bc34b1b, 0x51c8ca6f, 0x3078be98, + 0x85efe4bb, 0x4d023799, 0x696001e1, 0x45925265, 0xdf08155e, 0xd72f8eea, 0xb9d47b44, 0xcd095557, 0xb762d1d6, + 0x9c514142, 0xcad5396d, 0x744f3676, 0xe7dc649a, 0x6c43812a, 0x801df11e, 0x21421cfd, 0x464353ec, 0xf12a5ced, + 0x0e66b69a, 0x5b1e2274, 0xc52a3263, 0xc1b5f6e9, 0x449fb2b4, 0x832ba657, 0x6462b723, 0xf203e9b0, 0xfcf70f45, + 0x08ba5c5d, 0xcb96b4a0, 0x5985a570, 0x3744a5d8, 0x8f3e40dc, 0x8aee405d, 0xefab98e8, 0xaad27da9, 0xbb608302, + 0x770bdaf0, 0xe5a4c61d, 0x29e211bc, 0xf276b5b9, 0x0570c799, 0x321e508e, 0xdd1abc1a, 0xc8346064, 0x1b803a8c, + 0x9f44ab31, 0x58c83412, 0xcd859c18, 0xb82f1a9a, 0xb2e21376, 0x46a001ec, 0xccc78404, 0x75306cc2, 0x19abe50d, + 0xabcdd001, 0x933ae5ee, 0x29173e05, 0x7f27199a, 0x8b1456ac, 0xcf4fd945, 0xc769ab6f, 0x4125d2e1, 0x8ce679f3, + 0x24440b14, 0xeaa8742d, 0x743fb658, 0x095ac15b, 0x581d1bea, 0x92bd1033, 0x79a1da49, 0x424646c0, 0xe0347bc9, + 0x7dcf0021, 0xb421b43a, 0xc8be6615, 0x652f8cd9, 0x46cb3782, 0xf3bab7a4, 0xa2839090, 0x34c2785b, 0x705fa7a4, + 0xaa1d7083, 0xc732c292, 0x1fef7f0d, 0x474c09aa, 0x4a0355d2, 0xca029351, 0xceca09e4, 0xd8e3ab36, 0xe71efe2d, + 0x37666710, 0x4f32e5be, 0x65345af7, 0x47352116, 0x23535b8c, 0x57927b0b, 0x3e1a39b7, 0xbbcae9b6, 0x45b7e2b1, + 0xc8e2ee92, 0xb937c795, 0x83a0da63, 0x5f560ba0, 0x695dd28a, 0xcb6adf60, 0xfd5036ba, 0x154daa33, 0x15c39118, + 0xa77278bb, 0xe538e188, 0xe6b717b9, 0x11c3b802, 0xfa91bc78, 0x3bd5c85e, 0x089bef8a, 0x2263562a, 0xda4e7b59, + 0xe1698e2a, 0xed472ee2, 0x85268f92, 0x36ae9c0c, 0x2e31b796, 0x47d96081, 0x162c6c0d, 0xf9fe6fc6, 0xb2f21cba, + 0x083b64ac, 0x26991fae, 0x021480da, 0x0a9be338, 0x0cb597d1, 0xf82bdb93, 0x99674c09, 0xc2ef2ee3, 0xea6b9298, + 0x287626c3, 0xceaf5b22, 0xf33625a1, 0xb60b2bfb, 0xd85c6ca5, 0x6a19e7a7, 0x82a3f0ee, 0x089f85b9, 0x97df6de9, + 0x44bdbf1a, 0xa2a96965, 0x7078e4cf, 0x1b2ad738, 0xb4fff8d0, 0xbdff601d, 0x0dac0408, 0x9f9d3f76, 0x9f14276d, + 0x17cf39fa, 0x29228766, 0x52f50e91, 0x9fa7cb0d, 0xe8ae194b, 0xbbf7c1e8, 0x4f4a30ff, 0x8af60b3e, 0x7cd1292d, + 0x33f0c0ed, 0x5f55860f, 0x66dc282f, 0xe8377ef8, 0x5909fddb, 0xdc216942, 0x293b713f, 0xc7ee7977, 0xcac17ff5, + 0xd161ebf6, 0x287e4467, 0x665c78e6, 0xcf99a6e1, 0xd5cc878c, 0xfe8e30db, 0xfd8c31ac, 0x21e6ba64, 0xe59f64ef, + 0x4967b191, 0xb16b7f1c, 0xfa850359, 0xf8cad6e8, 0xec8d08e6, 0x59c82330, 0x86627afd, 0x28e9daab, 0x67d52436, + 0xe2ac95d8, 0xb9015a43, 0x15e80aa0, 0x29721ef6, 0x9677b030, 0x35940848, 0xd63e8c9d, 0x351a0313, 0x7f8fc681, + 0x34e57823, 0x52515564, 0xd834ebbe, 0x8dfa3ce5, 0x6f572947, 0x2f174c8c, 0xd7e919a5, 0xd0d970c8, 0x4fe42fa9, + 0x3214e3e4, 0xd8936f03, 0xd38db567, 0x7c29cb4f, 0xf6257d39, 0x5c065baf, 0xefe6255e, 0x88da2ce9, 0x2e16ec46, + 0xfcef6a1d, 0xe1b02b8a, 0x971e3d83, 0x340ae725, 0xdcd77616, 0x836a6d55, 0xba478746, 0x2abede00, 0xccb94c2e, + 0xd010d04e, 0x154f28db, 0x5461fba8, 0x09666baa, 0x697fae45, 0x1dcff8e9, 0x46b154a3, 0xc7c91ab9, 0xa467715c, + 0x0aa020a4, 0xd075bd9a, 0x7ad8a641, 0x11a9eaa8, 0x6f298a1c, 0xc7303180, 0x4638c946, 0x2e64814f, 0x07937bef, + 0x9b4324a5, 0x8ea76d5c, 0x686e667e, 0xbd83ce6b, 0x394931f1, 0x447a1bfe, 0xa4cc4f0b, 0x72762bd6, 0x4bc9b299, + 0xc21a7c63, 0x025a37b9, 0x7712637c, 0xae402638, 0xed12169c, 0x515e1324, 0xad388867, 0x13c01940, 0x97fea327, + 0x27a09be5, 0xd1a52c37, 0x656fa21f, 0x4ddd40c6, 0xa7c66fe6, 0x1ab2dfd3, 0xd19cb225, 0x1489b389, 0x8f9ae842, + 0xd3da037f, 0x43dfe8c3, 0x1beff226, 0x73a4b143, 0x724052c3, 0xea9b1b0c, 0x133567f0, 0x6dfc58b4, 0x4f78cdc2, + 0x63b217e6, 0x62e2ac32, 0x433ce2cf, 0xcfa7487f, 0x8facf052, 0x8ce4b2b1, 0x6225f7f7, 0x2ab1dabc, 0x1c80bec1, + 0x06eab75e, 0xa586df6e, 0x5bbca8c6, 0x7e10bf8f, 0xf49d5d5c, 0x7b7aa072, 0x66fd9972, 0x4722d3c9, 0x20628631, + 0x920d6e22, 0x337e7dca, 0xd65f451a, 0x6d6eee04, 0x5ad86d55, 0xbde011ce, 0x237b3f36, 0x1ce3c964, 0xe4332869, + 0x5724a4b7, 0x3705a9d6, 0xe7b47b21, 0x8193189a, 0xe9b47c7c, 0xe53d7a0c, 0x93bf2297, 0xb28934af, 0x0eaaac60, + 0x77dcc6ef, 0x11a20fe5, 0xc5eb96b4, 0x5c74927b, 0xe8f4bf26, 0xbb61eafd, 0xe7b74a40, 0x70e588c0, 0xdd3a5f89, + 0x5e69cc54, 0x0f960107, 0xfab1aef0, 0x3e58b1be, 0x87041330, 0xd9e580ef, 0x6f7b3f5f, 0x8d53c2aa, 0x9bfa66eb, + 0x1013d5df, 0x3c4bf1fc, 0xf9a53973, 0x08f1ce49, 0x7f28caa1, 0x56c89ae9, 0x9ec6fa3c, 0x2b28bfef, 0x0b331f11, + 0xd94e1c15, 0x8fe4fe9c, 0xa4879d84, 0x438d0cfc, 0xb6704b5f, 0xfb11ec4f, 0xbb1fa27d, 0xa12406b7, 0x56298c96, + 0x039b145a, 0x8b487338, 0x463c19db, 0x486fe798, 0xe17047d7, 0xc6cb4de7, 0xc17283a2, 0xe8ec6d09, 0x62b52ebd, + 0xfe922652, 0xed1e72f4, 0x56e9d697, 0x6cb2467a, 0xde8dd18f, 0x8d552a2b, 0x1adbe5f8, 0xf5a4684e, 0xb9b87bcb, + 0xe3b63b5a, 0x7dc9e5b3, 0x18c04264, 0xd05db611, 0xc1123931, 0x554c7bfc, 0xb3354e70, 0x15b2bdc0, 0xc13c90de, + 0xb3f9212c, 0x05065064, 0x6f7e4f6a, 0xb230a8ac, 0xafc06196, 0x626578fc, 0x8eaad2c9, 0x5e6012ab, 0x730bdac3, + 0xd7f3e9aa, 0xe2a846e6, 0x776481ed, 0x735e3ebd, 0x77db7192, 0x1b15cd0e, 0xc933cabf, 0xe1b6c906, 0x548c2da0, + 0x8f9363e9, 0x11e6504f, 0x6ef19803, 0x36d2071c, 0xce0966c3, 0x7e811f35, 0x3f87fb13, 0x97771c4b, 0xfc26f57f, + 0xbd0346f0, 0xe839a13d, 0xb5377036, 0x8e0ddee3, 0xa8b416a2, 0x62318f05, 0x08cae41d, 0xe5f2121f, 0x52939d59, + 0x03b33031, 0x8f8ae94a, 0x0184ff8b, 0xac95d623, 0xa181aeee, 0x1a453685, 0x00f0f333, 0x64c25b6a, 0x99259e86, + 0xf5e9fabc, 0x1b1e70d8, 0xd36ad6d7, 0x2063ff61, 0xb111138e, 0x13dbc2cf, 0xfeeb74ce, 0x33b41811, 0x894f12f3, + 0x7952a307, 0xf1abd6ce, 0x4a039bef, 0x8f4cc102, 0x91f47356, 0x7c753fef, 0x0cbe1c94, 0x00493d48, 0x497235b8, + 0x4d85f089, 0x0032a4be, 0x796b81fa, 0x3f235021, 0xab5b18fe, 0xd3cbe040, 0xf87a0217, 0xd3d3dc53, 0x21f9ddc7, + 0xca7ac635, 0xdbd25553, 0x8c958d7e, 0x15cedd71, 0xa9793024, 0x12509b48, 0x888cb7b2, 0x1cd9acae, 0x274e2982, + 0x333b496c, 0xdd64d085, 0x929fc5c7, 0x8f7ffc45, 0x5afddcda, 0x9ecb7fae, 0x09cbfc8a, 0xb6e32db9, 0xdb622118, + 0x444dd377, 0xb3b6a34b, 0xc8857faa, 0x6ced7f5f, 0xbade9c5b, 0x5ddbab3f, 0xeeb6dd39, 0xdd6629cf, 0xeb726db6, + 0x549a94f1, 0x63d3a647, 0xe61454b1, 0x21bbddb4, 0xde185688, 0xd848c30f, 0x61b2e6d5, 0x8fa92e76, 0x4a12dbc4, + 0x7f3f5c5b, 0xd35a7bb7, 0x80b83b62, 0x487f14df, 0xbd768ef6, 0x251b9eb6, 0x88566ac5, 0x951500b3, 0x4897da96, + 0x809c2d56, 0xc76b88b9, 0xef2d6ccc, 0x0170c749, 0xae9c7dea, 0xd1575d93, 0x02a099c5, 0x58e6b760, 0xd3219757, + 0x9cdb4ee1, 0xf0f0ec22, 0x280ee29d, 0xfcfdcba4, 0x91f237bc, 0x85349612, 0x1fd38aee, 0xe3792055, 0x204bce7e, + 0x2f50b539, 0xa2082d5d, 0x68128731, 0x84e1a93e, 0x78e48d85, 0xf9dd0570, 0x59f0681b, 0xa1284be1, 0x543cb643, + 0xa7462589, 0x19905dc2, 0xe20a0cac, 0xcfb815cd, 0x62010ea7, 0x603a5d9a, 0x4dfc7b67, 0xc6104ff2, 0x628835cf, + 0x1ae664b9, 0xbf2529f4, 0xf7b64a26, 0xfaae18ac, 0x6a07d075, 0xf6396e8e, 0xf3181ce8, 0x1f66f06e, 0xbc3d791e, + 0xe68b4cac, 0x6a328b68, 0xcbebfa49, 0xd7f8cf70, 0x094bca45, 0x346edc19, 0xf291b889, 0x2fbcc4d8, 0x4355da3c, + 0x050b9863, 0x430de159, 0x1783245e, 0xc9fb02d2, 0x37dd8ac3, 0xc9ff15e6, 0x04d8b7e2, 0x9a6e011b, 0xd535cee2, + 0x58b189dd, 0x555b6be9, 0xf4163d2b, 0x7f1fc2f1, 0x2d915c6a, 0x1c454c6d, 0x722f0dd6, 0x5084c3fe, 0x95cfe57a, + 0xf43ccc64, 0x4aea8c07, 0x0efe38ee, 0x395629a0, 0xeb481b9d, 0xcff69b54, 0xf55b121e, 0x842542cc, 0x5d947fcd, + 0x10d8fba1, 0xdfe72d91, 0x4ba9e691, 0x2829eafe, 0xe1c7a58b, 0x91d1c5d8, 0x334c1a76, 0xfd8a76b3, 0x098aaa29, + 0x7208b0a7, 0xd218c592, 0x4391c86d, 0x5492be67, 0xfac44e7b, 0x4a87c6ab, 0x9f57521e, 0x6079edfa, 0xc0eecba8, + 0x8ea4658b, 0x9826afe7, 0x16a739fd, 0x323364f5, 0xdbcf0f8b, 0xbab72a26, 0x72e88b4e, 0xcfcf322d, 0x77b781fa, + 0xf7914ec6, 0x13d21517, 0xa680ed44, 0x36b0f5eb, 0x4c9db0c8, 0xdbcc6d16, 0xf53ddcd1, 0x7208d83a, 0x13f086dd, + 0x2ee7684d, 0x73e98701, 0x8aa905c5, 0x82ea2156, 0xe3081ae4, 0xde619f03, 0xa371e0f5, 0x64bd7d0d, 0x18d5d09b, + 0xbbbc7c03, 0xe6a09c22, 0xf8ca08e6, 0x67c06127, 0x4d8b9f91, 0xa3907d27, 0x85fcde07, 0x7673f42f, 0x9c73bc59, + 0x0bf57423, 0xd36d6041, 0x1ba9a920, 0x5bf62d1f, 0xd1b43b6d, 0xc0f66b26, 0xbf91a7e1, 0x3d8cf29e, 0x662919ab, + 0xba5cfad7, 0x1b36a896, 0xfa65809d, 0x251a3cea, 0x8404698d, 0x0b369623, 0x8e1f646a, 0x724c6598, 0xb3fac1ac, + 0xbcded676, 0x0231d169, 0x6282bd49, 0x4a4d72c0, 0x5b83671b, 0xc0520cfa, 0x97e95cea, 0xd46c9aa1, 0x24f1022c, + 0x3bdd4e67, 0xd992e377, 0x42022263, 0x1745f402, 0x0630362a, 0xcbdbb2fc, 0x241c8bdd, 0x69a394fd, 0xfd00d732, + 0x12b58f8d, 0x15930aab, 0x3f84b134, 0x1bc70718, 0x36a6ee7d, 0x0cab7f94, 0x37a5016a, 0x0f8d4c24, 0x605bbf2b, + 0x07dced77, 0x63df0a1d, 0x5de1ab4c, 0xbde15af7, 0x45740088, 0x6a764623, 0xeb2d907a, 0xdba11b38, 0xcc2c9adc, + 0xac5406e4, 0x98e56b32, 0x6c1ba4c7, 0xd1aa0d23, 0x369f05b2, 0xc0b39e86, 0xe4e57dd7, 0x1d07cba8, 0xa7d2fe35, + 0x3402689f, 0x6e19bafa, 0x95a60808, 0x1d950f67, 0x0566e996, 0x10bff093, 0x79bd02c4, 0x5efdfec0, 0x5f720f43, + 0x32905ff8, 0x46b5e254, 0x331095d5, 0xec2a57b8, 0x8d01738b, 0x76a4456b, 0xfeee7136, 0x47bf7fcb, 0xb8ff6125, + 0x982ce0fb, 0x44bbacf5, 0x455c045c, 0xf3bfee37, 0xe640b4ac, 0x5876a207, 0xb094f750, 0x700280f7, 0xcd4e5aaa, + 0x192d32c1, 0x7b88271e, 0x1809ebaf, 0x6d2d1180, 0x29033f92, 0x94f9d2a2, 0x2c4fc7d7, 0x68a6a4d9, 0x0cbc4252, + 0xb630c039, 0x4792c6ce, 0xaec12f46, 0xe19e655e, 0x50b8f263, 0x12924b43, 0x1b1c3fbc, 0x56fd78d9, 0xce4f9c6f, + 0xc97d3a72, 0x57164293, 0x383349e6, 0x4da649c4, 0xa9b07b93, 0x002f0215, 0x8667924d, 0x9678fe5c, 0x5863f10f, + 0x3dac9893, 0x333f3965, 0x1b97f6d9, 0xfc1bd6e3, 0x2f6d4ed4, 0x5ed2146a, 0xc2869c7b, 0xdc8517ee, 0xd93174dc, + 0x7251189a, 0x61a47cf2, 0x1f13f6bf, 0xd60de9d9, 0x8057d6a8, 0x256ea754, 0x76f4c1f6, 0xc226d0f1, 0x348dcd66, + 0xc2c16483, 0x4bccf223, 0x65932c09, 0xf921c760, 0x9701f9c2, 0x6ed64405, 0xc1be4cd9, 0x0482fcaf, 0x67730fd5, + 0x888e7491, 0xed718690, 0x30910aae, 0x096f2b8d, 0x6bbc1aba, 0x306b570c, 0x571efe8f, 0x093d6c01, 0xaccb915b, + 0x99dc5a09, 0xb52f70b8, 0x7648f1c6, 0x2b04e824, 0x2ca77886, 0xbc686f14, 0x8dd47cf9, 0xc5b455a2, 0x6b54c4ff, + 0x435822b0, 0xb363f3f1, 0xaa7b2fe1, 0x183e0d79, 0xbd217836, 0x860a657a, 0xcfaaba5d, 0x4921caf7, 0xe04077cd, + 0x05e08eb0, 0xa1fcef95, 0x5234139c, 0xf7b84530, 0xbd952da6, 0xff58d551, 0x6206e740, 0x22ab63a9, 0x0779e9c3, + 0xfe004d07, 0xa3d3d042, 0x9b676242, 0xbaa2389e, 0xd970c818, 0x5f83ef64, 0x0de0a7d7, 0x0ef6c037, 0x9d4699ac, + 0x5a767b89, 0xaf183388, 0x57f6c505, 0xdf5a7e40, 0xcf9114be, 0x53865a32, 0x15c54f5c, 0x63e27f0c, 0x3de9d1e7, + 0x93eabb84, 0x5b39b8e7, 0x0dfb7aa9, 0xf9c76d31, 0x2a5cf2ef, 0xbe732937, 0xccc6096e, 0x0638b3e4, 0x8d566db0, + 0xd8e9772d, 0x6c382968, 0x4ecb0f98, 0x06523de9, 0xf5244029, 0xac495b9d, 0xa0f71785, 0xa14bbab2, 0x7c350e40, + 0xd1899b1d, 0x9bf2be21, 0x6bfcf76c, 0xe89ba755, 0x4b539ec2, 0x4782b7f8, 0x35bad3e0, 0x0d2afdde, 0xe6e0e887, + 0xd904a9bd, 0x587b79dd, 0x28068eec, 0xf2636924, 0x16b120e2, 0x7a4f8ed3, 0x98c66e8b, 0x760ce279, 0x9cab4acd, + 0x5c98476b, 0x2e6c8733, 0x77363f05, 0x77b4320b, 0xe709738a, 0x6f8e6555, 0x43977b55, 0x5fd66d5d, 0xbacbbacf, + 0x3a01488b, 0x1f7fa3db, 0x1f5c74c7, 0xa2280cb7, 0x6dc23df1, 0x76188040, 0xb7520e98, 0x27f609b1, 0x8464a1f2, + 0x390f131e, 0x00aba320, 0x6993b755, 0xf835e9f5, 0xafb233f4, 0xcb2df6d2, 0xdff73539, 0x4a043a50, 0xab604522, + 0xbd29217d, 0xaa1fd306, 0x25aa3034, 0x8fbe28f0, 0x7b98ce11, 0x2f24af1a, 0x14684ae4, 0x6b25d5ee, 0x34da8373, + 0xf06d6d3c, 0x777e6d18, 0x6ba5eced, 0xc0a4b5a6, 0x5ab0abcc, 0xaf440cf5, 0x896a2d85, 0xe3b11137, 0x77aabcdf, + 0x7bdbb646, 0xc9b9078a, 0xf31e1cc8, 0xdd7d4665, 0x527ff25c, 0x8793d647, 0xaca83a8d, 0x3685ca40, 0x93f8fc43, + 0x2913341d, 0xc7960568, 0x3233122d, 0x808b98d3, 0xd720b914, 0x69ae737f, 0xf87c6d2e, 0x80a2c7fd, 0x0608f2f0, + 0x3680e884, 0x29f6cd01, 0x56187725, 0x2085187b, 0x8913383e, 0x395c450b, 0xf3fc52a2, 0x2e7f27b8, 0x696c019b, + 0xa364bd1a, 0x10f05fd6, 0x728c9fd8, 0x5f06f31d, 0x5d007555, 0xe73ce03a, 0xc4d2a5ee, 0x34be22c8, 0xfad15aba, + 0x168dbf55, 0xa7955245, 0x06c58db6, 0x54e35ce4, 0x73d18f16, 0x04c1bc42, 0x7dc7dd93, 0xd3b72b0a, 0xe6da13c3, + 0x61d6629c, 0x9df21798, 0x23b22f09, 0xb25cf714, 0xb5a08a85, 0xceedb3d5, 0x90e1fe76, 0x8f3f977b, 0x4f700f1e, + 0x80b65b93, 0x9032a160, 0x706224ed, 0xd638c829, 0x8ab32fe4, 0x9b2780d5, 0xcd623098, 0x9755b4b4, 0x9b89c326, + 0x1c85ceb3, 0x32690907, 0x4e3f4733, 0x6f9b9419, 0x4452df1c, 0xfeb4a8cc, 0x50b3656c, 0x0ace5d73, 0x4dab0009, + 0x256dafc4, 0x11625c41, 0x62240a7c, 0xd43cf11a, 0x235e46e6, 0xcce2f4d6, 0x393b77cf, 0x75352a0a, 0xd1461009, + 0x1aee3a6c, 0x6a83821b, 0x486e05f2, 0xc0077ce1, 0x358b6eb1, 0x1371de27, 0xe9420465, 0x6f347ab4, 0xb689fe0b, + 0x8900ad40, 0xe69baec0, 0xf5fbce45, 0xb0122907, 0x4a82560d, 0x84466f4a, 0x4d54d218, 0x0be145ac, 0x131c6b08, + 0xd7e7dcd4, 0x97ffa9bc, 0x4f047a8c, 0x61c20927, 0xd3cde6c6, 0x2f5a4c16, 0xfd49d8fb, 0x31e6a7f6, 0xc62338a7, + 0x68f1678d, 0x27f0bc46, 0xffff55f7, 0x9f382989, 0xef167545, 0xd06393e6, 0xbc6044f2, 0xf2f0c6ce, 0x0ccdd603, + 0x734ae2ec, 0xc0cb2665, 0x043d24aa, 0x8d111b0d, 0x5b70c59c, 0x244c1bd0, 0x6fb1651b, 0xcf4a6e14, 0xdfe8c3ad, + 0x77d4003b, 0x1b08fe4c, 0xffe8c8d9, 0xe67c2e47, 0x4caaf841, 0xb19d3c19, 0x5079d2e7, 0x8ca67dde, 0xe3e4abc6, + 0x097eb1e8, 0x2d42c7f6, 0x3b880c66, 0xb0b6d2d0, 0xf69c1128, 0x7e6c20d6, 0x9d9ba33f, 0x83215307, 0x0a3128ad, + 0x4b4d3793, 0x3eda96eb, 0x4f7efc95, 0x57a11fee, 0x6995eccc, 0x162176a7, 0xd5a2e081, 0x25f43607, 0x0575208c, + 0x18316235, 0x829129c5, 0x30426a56, 0x54c377e7, 0xf992eca4, 0x9d82b911, 0x54cc5f04, 0xe57f8aa3, 0x15edafb3, + 0xa5f5e6c3, 0xd829b472, 0x9123bb6f, 0xa62401de, 0xb053f3e1, 0xd7939a11, 0x4570e3c8, 0xd391f5e8, 0x981a12c0, + 0xe745a6a4, 0x81a5b292, 0x81bc0fa2, 0xf9352ba7, 0x0e1c814c, 0x6a8feda7, 0x8135d245, 0x3a984091, 0xa0e3b97c, + 0xe8599d14, 0xc17f5d04, 0x2c6b12a4, 0x28f9a8ec, 0x956ace3a, 0x27c6589b, 0xe91ca2ff, 0xcee36546, 0xf15bda0f, + 0x9b049dee, 0xfc7cd73e, 0x3051ea52, 0x611eb7bc, 0xcba646f0, 0x3ee641dd, 0x42e7df65, 0xe67249fd, 0x0b62755d, + 0xec6db8f8, 0xc8ff8e54, 0x51fa22cd, 0xad65640a, 0x4da042c2, 0x27fe1b46, 0xe3b9b3a8, 0x8b6df453, 0xd76421e0, + 0x294c74dc, 0x686d33b2, 0xb886e4fa, 0xbdc7ecf2, 0x83794449, 0xf23df42d, 0x202162d1, 0x0d3b3f9c, 0x0fa19e61, + 0x5c944e6a, 0x26b39ffd, 0xbd40f07c, 0x8336c878, 0xf599c93e, 0x8049a9fc, 0xdb9cf234, 0xe3bceca3, 0xe89c769e, + 0xc05e6cb7, 0x5761469b, 0x0842d337, 0x8e5d9c69, 0x595e54d5, 0x714c2d52, 0xda4de357, 0x19d57c12, 0x22f7c405, + 0x8ff37ef9, 0xe59177bd, 0xf40e536c, 0x23b55ca1, 0x670feea4, 0x3b421cbf, 0x80d739cf, 0x1ee8e70f, 0x2c7f8446, + 0xebb55379, 0x5e23760e, 0x2d16d0f9, 0x910274af, 0x3d2fc1c8, 0xcc966ef0, 0x59a197ed, 0xad1065ba, 0xe990ed8e, + 0x55635305, 0x1391af25, 0x247c9058, 0xa4277895, 0xd09bff24, 0x74d9fd5b, 0xf71968b6, 0xaf7b67b6, 0xd0af1523, + 0x3e1c5fc9, 0x00074d21, 0x1451a29c, 0x8a97badf, 0x1bf52541, 0xfdb6dc9e, 0x663a168b, 0xe330a63c, 0x4729420b, + 0xb48957b7, 0xddf6ecc9, 0x4167cab3, 0x8443341c, 0x86aa4cf5, 0x0bbab5de, 0x3ce045c7, 0x6073da9b, 0xc6b96522, + 0x8857c91e, 0xa292b74a, 0xd83ff830, 0x169065e7, 0x82177a3b, 0x959c44f6, 0x265801e5, 0xa8dbf934, 0xb26ff68f, + 0x434975ad, 0xe304bfc5, 0x9f549db9, 0xd27467e5, 0x63816690, 0xeee0e9df, 0xe3764d51, 0x6844089a, 0x2ba9d850, + 0x90d8241f, 0x09bdb75b, 0xeb81562d, 0xbbd0488c, 0x00909f5e, 0x6520ce8a, 0x6db18f5a, 0x0d557742, 0x0044a56e, + 0xe10a79d6, 0xc69ecf9e, 0x0dcfa2a1, 0x7312db05, 0x9651604e, 0x21853664, 0x071959b3, 0xb8b0cb77, 0x406aa1bf, + 0x82d67db0, 0x9352b085, 0x5f36947f, 0xc5c4e62d, 0x1d92307c, 0x28c48035, 0xc0aebfaf, 0x2542b54d, 0xa79d97d7, + 0x54f13fdd, 0xb77054b4, 0xaa461fca, 0x9cd31ef9, 0x38be28a0, 0xd20dc1c2, 0x97be4d9a, 0xfea59699, 0x0c2c6655, + 0x931e9216, 0xec24eeba, 0x264ef044, 0xfa68f997, 0x917a8cc0, 0x47fe0320, 0x9c27e047, 0xa0e383d4, 0xa7a93e3d, + 0xd4b4d4e6, 0x8c78cb6e, 0xcf1172b2, 0x9e53324d, 0xde3fc35e, 0xbd6168a9, 0xa4ed6dd2, 0x40a005e5, 0xea97a1bb, + 0x5197e999, 0xf971e729, 0x6eb6e6c6, 0xf2186f26, 0x956be1c0, 0x198ae0c9, 0xf8837133, 0xc5345061, 0x71523372, + 0x2c740bb8, 0x6382559a, 0x956212c7, 0x09b22bf4, 0x88915936, 0x9e24e4b5, 0x9966e99e, 0x9b23f80e, 0x07ff318a, + 0xd8ef7cb9, 0x986eedaf, 0x10ef8dd3, 0x0cff9089, 0x1f257edb, 0x2c237e15, 0x6a7995fd, 0xc43d4d42, 0x138ad595, + 0x8ffdcb40, 0x55aa67a8, 0x467f1381, 0xe66e83e1, 0xc145d848, 0x34872eb9, 0x3b90edc5, 0x4fd6fcb3, 0x5d3e5045, + 0xbe079412, 0xc5479a0d, 0x79b05534, 0x747e76d8, 0x31e925df, 0xa87e3525, 0xc4414a25, 0x41ef729d, 0xd230ac7f, + 0xbc9ec796, 0xb4727881, 0xc82bf346, 0x78ed3d54, 0x9e32c423, 0x9e1a8127, 0xb9fc08cb, 0xd1348fae, 0x9989f1f6, + 0x5119fa9b, 0x271e6a6f, 0xb501d9f6, 0xbdae23db, 0x02737f5c, 0xc6972fcb, 0xea2252d4, 0x6f02751c, 0xb4a2e2af, + 0x96ec2c6b, 0x0dcb5ea2, 0x11a521d0, 0xa0bea2b1, 0xaa5fbc07, 0xb2b9a6d7, 0xe74ec9d6, 0x101a5a17, 0x0e00bd11, + 0xe18da710, 0x38e34672, 0x344427bd, 0x09b07dee, 0xd9ee80b3, 0x1710f3f4, 0x137cefac, 0x3caddfd0, 0x12fb7527, + 0x4d1e089b, 0xf257478b, 0x1de88770, 0x17626deb, 0x137dda4f, 0x491be67d, 0xac4018ac, 0x44e904fa, 0x71dd7582, + 0xedee4aae, 0x517c902f, 0x722cad2d, 0xaa77d80d, 0x94f732ac, 0x94a66b9e, 0xa815604f, 0xc1095b01, 0x3ccf402e, + 0x3c4ad225, 0x610c054d, 0x5da0f8f0, 0x718b0069, 0x19697713, 0x310bbf3d, 0x2b026413, 0x87ca982e, 0x3c51d3b3, + 0x1c28462f, 0xd9e076de, 0x0a8de2f8, 0x398b5fb2, 0x5e205feb, 0x7f97dc47, 0xf15aea65, 0xf777f2f2, 0xe1cf4860, + 0x50c4825f, 0x775bc143, 0x591b99d9, 0xfe3b3b04, 0xe2b53ee8, 0x84f9c3d0, 0x67879577, 0xd683455c, 0x6311006e, + 0x35874796, 0x260ea5c7, 0x279ee8de, 0x4c260a82, 0xf93c65b0, 0x00a93a7b, 0x9e39c181, 0x73207992, 0x49f84f5c, + 0x0c427642, 0x4a5e3bfa, 0x665e3fec, 0x4a2116f1, 0xb25f4f47, 0xc7187265, 0xbb9976fd, 0x4b5fc70d, 0xaa1ab35c, + 0xc935f9af, 0xeccd4c01, 0x62ab2f83, 0x5d4ab686, 0x429c5981, 0xdcc8ce86, 0x7da2c94b, 0x0bd1f284, 0xe3bd78e5, + 0x1de8f2b9, 0x2ce64b0f, 0x4940c79c, 0xbbcd761a, 0x282e241c, 0xe4b22c83, 0x60fce126, 0x36d207f9, 0x57f8f5b8, + 0xc908ced2, 0xf13f7684, 0x1c16daa9, 0x7881b0dc, 0xcffb4887, 0xeb23ffee, 0x04741745, 0x1a8b440e, 0x2a279e5f, + 0xe8b87ac2, 0x48514447, 0x1faa4cb6, 0x337e3bea, 0x00a0ca68, 0x84c88fc7, 0x58446190, 0x1e1a3f57, 0xce1bbacc, + 0xfea594f0, 0x947acd59, 0x6bafa9e9, 0x6965a3eb, 0x0fc46b0f, 0xe0a8aacf, 0x226a56e5, 0xb202ee77, 0x4f0caba7, + 0x5e9de277, 0x640f1ecf, 0xd758cc98, 0x0f81e2a7, 0xb38f4ac5, 0xd4bb4163, 0x74ed4c82, 0x129beb1d, 0x161cb722, + 0x8e6dced4, 0x2d8a7243, 0xc8e2801a, 0xce153026, 0x5a1d6568, 0x47e1fea1, 0x3bb72b5d, 0xd7040b68, 0xd17c139d, + 0xc1d56ac6, 0x3363dd8a, 0xdc5710b7, 0x7711511e, 0x9cbfe5cb, 0x1d42a34b, 0xc2fab8e5, 0x7c865f6f, 0x0213204b, + 0xfe308333, 0xfb997712, 0xb579ebcb, 0x49c2f396, 0x1bc98a4b, 0xc94935eb, 0x9b84ef17, 0x868bcf75, 0x24012c26, + 0x668f494c, 0x178b9f6a, 0x6140ace4, 0xcb569d9e, 0x082b6dfa, 0xa6b491db, 0x686060ea, 0xc7a149cd, 0xa1496e1c, + 0x7d0011c2, 0xdf3a1f77, 0x658df68d, 0xfec13283, 0x1cd3a05d, 0x6946f477, 0x0cd81f71, 0xdd3238a8, 0x35468f1b, + 0xd09e5e9a, 0x1cd493cc, 0x43c1573f, 0xe020d0e7, 0x6ea79977, 0x77f41bd3, 0xfc6ab36e, 0x1e5b967a, 0x29002d46, + 0x2997ad7c, 0xa36e36ff, 0x6112f679, 0x77b14bd1, 0x137c351b, 0x50985769, 0xfa014f42, 0x581afa04, 0x85e7efab, + 0xb9dad285, 0x864c3b89, 0x5c94964a, 0x578ad33b, 0xa310f863, 0x2b7634b2, 0x63da4928, 0xf5bc388c, 0xc2575509, + 0x221d2fb3, 0x148a2035, 0x9e4eb9d8, 0xc191f057, 0xb2a3325a, 0xbd3e5a38, 0x2427389a, 0x6fd8159b, 0x83ee446d, + 0xce92ea15, 0x7d73f141, 0x57d842e7, 0x85767cd6, 0x73942fe5, 0x966bb3f6, 0xd6713857, 0xa87d1855, 0xf6f8377c, + 0xb499e6a3, 0x669a2a74, 0xcff0f256, 0xb31987b0, 0x3ecc16b2, 0x9002b65e, 0xa30d7242, 0x7f6d8394, 0xc873be87, + 0x9ecf884d, 0x0f809a60, 0x2b06a94a, 0x581c4628, 0xa37088e2, 0xd64a063e, 0xfa366d59, 0x3dbfb501, 0x81b3934c, + 0xe11b4d16, 0x98981945, 0x851d93ce, 0x4e5f73b0, 0x8713cc4a, 0x990c3e88, 0x3f10dde9, 0x2c741b6e, 0x16ca9e62, + 0x8a9574c9, 0x5fddd704, 0x91e0f946, 0xe145b261, 0xd6c8e914, 0xd46a195e, 0x836f2b84, 0x888488f9, 0xa0171075, + 0x5b68e624, 0x69bf7207, 0x97f89c5f, 0xf68bf78b, 0x0e48fcd1, 0xeb49a381, 0xe04b4e48, 0x6c2b4749, 0xa84a84e1, + 0xe7359ec5, 0x651a830b, 0x9d95b25b, 0x65d139ac, 0xd452f94f, 0x28f3612c, 0x61c87396, 0xe429effe, 0x3ea8483a, + 0xac2bf450, 0x450615bd, 0xeb94bf71, 0xa759a259, 0x418fadc4, 0x59734a93, 0x7a47a6f9, 0xe1652560, 0x5afb7d14, + 0xcca9ac68, 0x3516a22b, 0x28d369f3, 0x5d6ea00c, 0xa7c9c0ad, 0x137b9fb3, 0x2c7137c7, 0x733a939e, 0x29a50a01, + 0x3fa44daa, 0x7160a761, 0xac698f11, 0x1653e030, 0x12d99a27, 0x07a9f12d, 0x45df07e3, 0x010fc0fe, 0xfbc7b3da, + 0x6d1e6dad, 0xf992a21f, 0x52f3d632, 0x909eed95, 0xb27215d1, 0x732961e8, 0xdcd541b0, 0x28c21d54, 0x0df2b4ac, + 0xac33143e, 0xa9ea0eaa, 0xcdfa2588, 0xc927571c, 0xca35f8ca, 0xc840a0fc, 0x55b4b757, 0x9434bd7a, 0x2e1ac1e8, + 0x0a9b1162, 0x8aca7625, 0x034f9307, 0x0491ef04, 0x785d0c72, 0x73b299f7, 0xd17861e0, 0x4323eaa2, 0xd7e0aca2, + 0xf989705f, 0xc4f09bb5, 0x99fd7f86, 0x271c30d1, 0x27e92bd2, 0x7286960a, 0x255036df, 0x941e2779, 0xdb8eae4e, + 0xf6adff46, 0x2b49ac54, 0x0a1cef40, 0x1f28d624, 0x8d6162c8, 0xf080d22e, 0xb6bb18f2, 0xa880e3dd, 0xa78846fe, + 0x4d2fa3ed, 0x05378029, 0xc49b8f5b, 0x2905cb26, 0xd3aeb39a, 0x1629690b, 0xdd1757eb, 0x2ff1f673, 0x9a688a6c, + 0x1d4d24c1, 0xc9742446, 0xabda29b1, 0xcdaec5b7, 0x295c0d7e, 0xd90ff9d0, 0x978d435d, 0xaf68329f, 0x38bed6ce, + 0xcff29244, 0xd79a356e, 0x5910c2a9, 0x77e55bd1, 0x505f5a79, 0xd26d9743, 0xe070d255, 0x4e577e72, 0x68f33845, + 0xc18b2566, 0xa83308d5, 0x022b9e46, 0x2b6f4a24, 0x6c7dfc72, 0xf76630f7, 0xb12f83b8, 0xfbc91237, 0xab95158e, + 0xf8aa7ac5, 0xd76a5eba, 0x891fbec4, 0xe1cde14e, 0xf5fd0124, 0x123ce625, 0xb2e43de0, 0x65626d23, 0x3333eaf7, + 0x1f29e299, 0xd6b24c0c, 0x6a6481f5, 0xeb4ad807, 0xd7a16f02, 0x9655eb0b, 0xc22d345c, 0x3bec5fa5, 0xd22848fb, + 0xb9117606, 0x99d8de15, 0xf58f6e56, 0x7533b564, 0x90ad90f7, 0xa114cff1, 0x7fd502b8, 0xac5a34e0, 0x76e2b46e, + 0x3e106b77, 0x01e92323, 0x556d779a, 0x18b1a5ad, 0x2d9d2887, 0x54e1bd94, 0x9994a582, 0x59cf2080, 0xe17b5ab2, + 0xcb1f04ed, 0xd42fe908, 0xcd00aec8, 0x820a5c05, 0x229bee59, 0xc8446595, 0xc9dd9716, 0xdbb9653d, 0xd55f6f4c, + 0x2183da6c, 0xf615fa3d, 0x88b43107, 0x85f645a8, 0x3436b234, 0x7e553a12, 0x2cef38fa, 0xa738eed6, 0x011e4dd9, + 0x915ccf5f, 0x20b174c9, 0x25215972, 0x30b7a4cd, 0x2129f05c, 0x29ea8163, 0x13f81c91, 0x9045309b, 0x2064548b, + 0xf91efa18, 0x579d0262, 0x24c3d838, 0x8b3be565, 0x553939e8, 0x31d0c06b, 0xd314be9d, 0xb6c246d2, 0x114f9e12, + 0x1d8c0eef, 0x57c98e18, 0x50116040, 0x0778bbf1, 0x30d91dd9, 0x948b14f4, 0x1cd63672, 0xd72dbc14, 0x72c165f4, + 0xadfd0381, 0xdfee0594, 0xfd8f9a78, 0x29cf2f71, 0xe25469be, 0xec88ecda, 0xaeda0c7c, 0xa4b9957f, 0x5dc1a43f, + 0x3a77b4e7, 0x62ad807f, 0x04a337ea, 0x9b506605, 0x0379c816, 0xdb7feb21, 0x9702e194, 0x50f3c880, 0x437398f9, + 0xdb172038, 0x19658647, 0x0cad25c4, 0xdac606c6, 0xb84181d5, 0xb0dd73f1, 0x19065c8a, 0x51f1f7f8, 0xbee06590, + 0xc89c841d, 0x0c5e131e, 0x35468f66, 0x99cb53ce, 0x406283a7, 0xb2452b5a, 0xc707ab70, 0x74fe1adf, 0xa0e5107d, + 0x9c00f3bc, 0x24396759, 0xa768b114, 0x5f43e28f, 0x81aa7895, 0x66a389d3, 0xb6fceb34, 0x04ce34fe, 0x3f3905e3, + 0x5b1cfb92, 0x60cb41c7, 0x737fb221, 0x2a083549, 0xbb8d21a2, 0x1cdf9641, 0x79f3099d, 0xb43db075, 0x7ea7dedf, + 0x715888e7, 0xd1e4685a, 0x7287bcf9, 0xccdd9a60, 0xbccecffa, 0xbafb6e86, 0xf14a9b3e, 0x61e07c8e, 0x82918d5e, + 0xeb7d33b8, 0xd556421c, 0x15973a1b, 0xb90c91db, 0xa28faa1e, 0xc75b5121, 0x22dd0094, 0xa1b18fde, 0xc31376fa, + 0x05ca884a, 0xa5ebb379, 0xf63ac40b, 0x8466e9df, 0x40fbe81e, 0xe48eee20, 0x439b3381, 0x49b7ba18, 0x4219a400, + 0x5b54e97f, 0x1f080608, 0x72f70697, 0xead22ab7, 0xc8882403, 0x4a225667, 0x6fed4907, 0x9cc37375, 0xcba56457, + 0x94f85aaf, 0x9530fa6a, 0x3c478d49, 0xbc802dbc, 0x128a1538, 0xfc7e6e7e, 0x56baafa0, 0xeee4137d, 0xe0eaba4b, + 0xf64fcc01, 0x42bcc451, 0x31d11845, 0x3eec0754, 0x14e34422, 0xcf9564f1, 0x14c28626, 0x4c0d2afc, 0x3b7ac641, + 0x2e20cbae, 0xf977574e, 0xad3d0f5c, 0xdaa9c35e, 0x2f2e7b3f, 0x887c91b9, 0xf719e901, 0xd9376c89, 0x08adaa13, + 0xac741cdf, 0x8649efca, 0x8ba0702a, 0xcd6aaa37, 0x2e79f9d9, 0x1b8fbe04, 0xf6749bcf, 0xc5cc75fd, 0xb26605dc, + 0x84c6a553, 0x0c7e811d, 0x4b8181fd, 0x2674568f, 0x94896210, 0x0d6e87a6, 0xe0480f9e, 0xaf0b04f0, 0xaacd4ccc, + 0x18cec985, 0x20969a9e, 0xb190cf4a, 0x7add1f18, 0xc036fbee, 0x4245caff, 0xc344905f, 0x1dfe6053, 0xbf0601c0, + 0xa44ace0a, 0xab6273c9, 0xf2a88c45, 0xd23b8264, 0x34c2ec26, 0xce570e10, 0x0e4630bd, 0xe3eb4789, 0xf665b661, + 0xe057977b, 0xaa193923, 0x3017954f, 0x7a711b1e, 0x20583480, 0x2532da05, 0xad78e090, 0x3667ca4c, 0x066b7657, + 0x2567444b, 0x194ec9e0, 0x2edb827f, 0xb1401823, 0xc26cd9ff, 0x6fd7f641, 0x39d2f320, 0x0f0fe22a, 0x742dfee5, + 0x1ad7277d, 0x6f766d1b, 0xcc88dedf, 0xfa95ff25, 0x67c42dd6, 0x66e510f5, 0x6ed71be4, 0xf265a559, 0x8997aab8, + 0x4a86abbe, 0x4f047175, 0x59b00f4a, 0x82ba7234, 0xd3a81753, 0xac92292b, 0xe3fd3b24, 0xf6b2c4a0, 0x4c596b11, + 0x3f742cd1, 0xbb15f74e, 0x56eea259, 0x8b79eb9c, 0xf1de113d, 0x1c3d3dbe, 0xca8ef39f, 0x61b6293a, 0x4e4b74c7, + 0x319bcb75, 0xf2e48f4b, 0xdb0c8439, 0x285a9edc, 0x97f4e07c, 0xea8c9801, 0xd84438c9, 0xc2def1ce, 0x99f34b3d, + 0xbb37d944, 0xd632c6d3, 0x28044d93, 0xe200c371, 0xaa8479c1, 0xa188b88a, 0x4b2dbfea, 0xb8e34345, 0x8db34bce, + 0x329595cb, 0x2905e1bf, 0x007235a3, 0x2a2acf97, 0x0a3171de, 0x3669135e, 0x987358ce, 0x8d692801, 0x8bd03049, + 0x82a3cecf, 0xbe44d6c5, 0xceb2802e, 0x165d24db, 0x51c801b8, 0x6b84e02c, 0x13261123, 0x46a3ab66, 0xdc50a6f7, + 0x7c4e95cb, 0xc7a14e17, 0xa03965bd, 0x7fb68aec, 0x2f268d3e, 0xcd6f095b, 0x4ced2018, 0x7b7c3c76, 0x36e8a0c4, + 0xa53067cd, 0x9469b12f, 0x86ffd9c7, 0x909e84cf, 0x591fb34d, 0xcbec6274, 0x014513ba, 0x3b5ab3a3, 0x1e0ff7a6, + 0xf99c8df9, 0x41ea2e46, 0xa8124a99, 0x9a61e6c9, 0xd0b0f054, 0xf711d3c5, 0x6214952f, 0xc7bef68a, 0x627ad183, + 0xb624fcaf, 0x63db7bec, 0xc5c62329, 0x718a79a4, 0x4786d2d5, 0xd198f724, 0x92577935, 0xd9905b94, 0xb9ba3a88, + 0xa9acd4ee, 0x51ce62c6, 0x2c8c5296, 0x108c38ac, 0x26a82778, 0x27100ed6, 0xc5e83fd7, 0x2a86e960, 0x411cb773, + 0x5593844a, 0x82586d69, 0x63b05c37, 0x0fd2b681, 0x4de2d032, 0xd40b3d86, 0x1ce8e784, 0x93ed3415, 0x04bb6556, + 0xdf10fdcd, 0x7fbc8586, 0x1d9a55e2, 0xe48c898c, 0x89a26ac2, 0xd598f771, 0x89e57236, 0x472d887c, 0x01757ad2, + 0xe98aea11, 0xea51243d, 0x26ccb359, 0xd7ad5777, 0x856017b1, 0xdbdd8f54, 0x5fd25865, 0xff70f445, 0x5e678fc1, + 0x9143078d, 0xd1001d25, 0x5fb99d91, 0xebdb4a7e, 0x299eed15, 0xf804a8e1, 0x0060b0ce, 0xc8826df4, 0x64fdc4bd, + 0xa20a85a9, 0xabe218a0, 0xbaeb1d06, 0x97454c3a, 0xe73584b3, 0x2ed4d6d0, 0x075bbe2f, 0x2b066332, 0x5057711d, + 0x3ea562de, 0x12f19209, 0xddebb68d, 0x9d86f1c3, 0xe67b0ad3, 0x483837a4, 0x8e24bbc2, 0x821478a1, 0x4504b886, + 0x8581b62a, 0x2602bcd1, 0x22767bf5, 0x3f38761c, 0xd36c62ef, 0x59a75948, 0x5c8770ab, 0xd8c91bae, 0xd58cd2a2, + 0x1f516691, 0xcf073d87, 0xda7b5736, 0x815e48e4, 0xae93d68d, 0x06dda188, 0x31e9a44b, 0x5d2b4be9, 0x59fb358b, + 0xb7651551, 0x25516ad9, 0x5c6db49e, 0x6f313106, 0x2ee99099, 0xb77931d6, 0xac758546, 0x04a8349e, 0xd42ff0ca, + 0x5ac6ca2d, 0x6009589f, 0x4822185c, 0xa06f4d80, 0x4bfec3f2, 0xacd318bb, 0x4e192596, 0x6714b64f, 0xf9825e58, + 0xfe638a1c, 0x5330cd6d, 0x7ffabff3, 0x70e1a4b2, 0x611c1d6a, 0xb89a15fe, 0x5694fa37, 0x4a2ada65, 0x696bb9d0, + 0x1cd3f89b, 0xaeb299d4, 0x7c9a6264, 0xe34b24e8, 0xef82fd0a, 0x37d159b0, 0xbb7e06e7, 0x0331a8b3, 0x154efd07, + 0x11f499e1, 0xb2c94bb2, 0xf2651a86, 0x12263988, 0x628934c1, 0x5f2f7a3a, 0x9a188b7e, 0x18eef4b4, 0xf772ac27, + 0xcb3642ea, 0x85647a9c, 0x92d99844, 0x6243dab1, 0xdb2cc472, 0x5af6e61d, 0x0879293a, 0x289022b7, 0x775dfbd5, + 0x2c88d058, 0x303864d9, 0x31cd279e, 0x99109b7a, 0xe9dbbc82, 0xd9f20e02, 0x35a3f5c8, 0x89bcec41, 0xf9b8e1b5, + 0x7ba2247b, 0x6c36b6c0, 0xff4684a9, 0x20e180d1, 0x1a26f5af, 0x3f029167, 0xc6286578, 0xea671668, 0x7dace0b1, + 0x9fbac223, 0x07bbed79, 0xa5265f64, 0xc9484628, 0xece44e21, 0xdf2b347c, 0x5d82bffc, 0xfd955ff3, 0x4e7ef717, + 0x9d3fe9f9, 0x7f32f83c, 0xf00c221c, 0xb4fd09d2, 0x67a02906, 0x777164a8, 0x32d47c14, 0x63a69faf, 0xd284948d, + 0x0afc1749, 0xf938e7f7, 0xde2679f1, 0x168f8dfd, 0x4783b9d4, 0xf2e3b92f, 0x35006c0d, 0xef93e013, 0x82259e83, + 0x82f4ca07, 0x4e3a1329, 0x2a443a9f, 0xd9353c37, 0xb2379bf8, 0x77bf23d4, 0x566e873d, 0x1bba9d69, 0x39764f4a, + 0xccb87f8b, 0x14e2c0b6, 0x7d0f1de4, 0x0ef8d912, 0xbb53ab97, 0x47669e07, 0xea29ce01, 0x43a79faf, 0xaed6704c, + 0x64868c06, 0xbd82b7ad, 0x629a3f4e, 0x5afa0b51, 0x4ab84053, 0x1a7194be, 0x1b0a8b74, 0xa9d72c5a, 0x75a2e829, + 0x0f9c49b7, 0x44321f10, 0xd37cfe07, 0xc5033924, 0x1f05eea4, 0x171aee5f, 0x549d29e3, 0x4169e2f0, 0x50042885, + 0xbc246839, 0x38873ef7, 0x70e71270, 0x2c89bee7, 0x0b0717c6, 0xe4fce65c, 0x4f759dd4, 0x646cef04, 0x3b91f684, + 0x3a3cb522, 0x52ee1abf, 0xbcdd918c, 0x9b47ceb4, 0xdedf4465, 0x0581d548, 0x04f6a22a, 0x7e3ac534, 0x1ace5460, + 0x292e9b3c, 0x888a7ecc, 0x111bd10f, 0x99a6c0d0, 0x37cdb16c, 0x8b7a4425, 0x4bb67439, 0xc6ff1f52, 0xcdbb6907, + 0xfb2c5f71, 0x3b950fa1, 0x0c2d4968, 0xd22eaf28, 0xa64eea0e, 0xe8f970f3, 0x7fd2e257, 0xb715cde4, 0x7dd46897, + 0xf8289696, 0xbf8a043e, 0x4afa1921, 0x79282c60, 0x23f8c563, 0xac172d8e, 0x400bd37f, 0x9aac6ca3, 0xadff1bf1, + 0xe38bacf5, 0x87996d7a, 0x54a2cec0, 0x2726dcf4, 0x17c7c9d3, 0xe67e7b39, 0x33663023, 0x538177a8, 0xdd0a4e50, + 0x1236c4fd, 0xd2e3dc27, 0xf03115e3, 0x7e2023b1, 0x2f7776f3, 0x43eace5c, 0x4cb71de9, 0x3a578723, 0x96330541, + 0xd66d57a2, 0x79f5e600, 0x1b0bb439, 0x1fed0086, 0x48b9e355, 0xeb8e91f7, 0xabde5122, 0xac4ef5f8, 0xc4594b5b, + 0xae8b0108, 0x9a83c393, 0xc13dce78, 0x86e71171, 0x1ae2b8b9, 0xd99d9607, 0x4632f1c9, 0x43f4892f, 0x96dc92bc, + 0x9c0da8f2, 0xeb8b79f9, 0x4207a730, 0x5b41afb7, 0x52fac629, 0xa78fa6bc, 0x0b43422a, 0xdd67e117, 0xcd3887eb, + 0x40f6f403, 0xbf52d1f6, 0xcd3fde6e, 0x6e201eb3, 0x62038e71, 0x2e4a0950, 0x34794045, 0x66261bf5, 0x91428efc, + 0x8d7d1036, 0x2b72f182, 0xa66c5063, 0xdea7bca6, 0xc8035e3e, 0x06faa4a1, 0x26722e5a, 0x082c86c4, 0x2a20a5d1, + 0xcece0551, 0x843be80b, 0x6a17fac9, 0x2caaaf1a, 0xdd865166, 0xb33d96c9, 0x536f1d97, 0x4763c816, 0x165d9809, + 0x3ad92896, 0x018e14be, 0xe31a780c, 0xe206ea16, 0xb1d37e70, 0x125e4b64, 0xd825cc67, 0x0b065f7d, 0x4e6b7e9d, + 0x4c6a5492, 0xca0726b6, 0x49c15c6a, 0x51402531, 0x803e3a93, 0x786e0349, 0x090fdaef, 0xe5491043, 0x75afc300, + 0x71a6bc29, 0x65efd0e0, 0xa15d5345, 0xfb744e2e, 0xc13dab30, 0x23a06cac, 0x359fe5fa, 0xa9e0d9e8, 0xbc01ce45, + 0xdf7e16a9, 0x5340688c, 0xdd4fe1b6, 0x4ca4ee01, 0xe2dec18a, 0x41caa48d, 0xdd0032ba, 0x71014307, 0xe07bdeb1, + 0x291c3ba6, 0x12620de2, 0x3d5a6519, 0x2343bc8c, 0x7a8c0e28, 0xf2b6e2ff, 0x479e66ee, 0x9a0025b8, 0x77fafe4f, + 0x01a4eba7, 0xc6faa1db, 0xbd4f4ffd, 0xd937e0f9, 0xfdf68d03, 0x1061f0ea, 0x6c8be0ba, 0xeed88a46, 0xa8b9b97a, + 0x2760b9bb, 0x322b6aa0, 0x48052305, 0x7580cc1d, 0xfd19f871, 0xc52bbc84, 0x127ee0d6, 0x2144e28a, 0x9f448e8f, + 0x9b5343ea, 0xa70a7097, 0x5d38cf2f, 0x2d03e9ae, 0x0bb96210, 0xdef9d77e, 0x2b49e626, 0x4fbd0cdc, 0x7eb0a5c9, + 0x6d03d59d, 0xc25d0147, 0x4697a2c0, 0x7cdece15, 0x782ee508, 0xb939f2c5, 0x9e981855, 0x6aca0cad, 0x336cce92, + 0xf030ed89, 0x8cafa7c1, 0xf858c121, 0x2caf1b16, 0xe2dbb97d, 0x6031008a, 0xbb42b6eb, 0x59847b8e, 0xb7debb32, + 0x2c12f199, 0x9a4c7332, 0xfe985aea, 0xc037cbf8, 0x1e33b2d5, 0xc594a03f, 0x641f9d99, 0x7db1568b, 0xa5c947b2, + 0x23b12c1b, 0xbe44d91e, 0xc04a8000, 0x1659ca3f, 0xd8b46e15, 0x068c9405, 0x209dc7ee, 0x4ed8962a, 0x4f8dd62f, + 0x2ede1fc4, 0x244f61de, 0x83daffb3, 0x2b28d968, 0x38dd7b55, 0xd0e6cd0c, 0x1172da17, 0x41f64cbe, 0x3f500d0a, + 0xeaeebf8b, 0x4f80bcf6, 0x29d9172b, 0x2af6b598, 0xe3a18caf, 0x3dfd77e6, 0xa0d941a0, 0xa3fd9f0e, 0xd6dfd70c, + 0x5c3f81b3, 0x3d644f24, 0x60082d32, 0x5d4c0676, 0x3afffe89, 0xc80b5547, 0x9d943943, 0x424430a2, 0xb3a4e5c4, + 0xf5bb2144, 0x1084d92d, 0x7ea3e332, 0x38898888, 0x20cbca4d, 0x18981394, 0x1a26b427, 0x3c5e8685, 0x24715561, + 0x1a295c97, 0x1728a499, 0x1b6bfa0e, 0x1bca92d4, 0xa8fa7663, 0x717bec98, 0xc4853dbd, 0xd66347bd, 0x6463e22c, + 0x7a4285c3, 0xc1e2a6d8, 0x2a0bd15b, 0xee10dd49, 0x778cb87f, 0xeb947afc, 0x1e4b04b1, 0xd266e525, 0x8f135d6b, + 0x19dca368, 0x35abe51d, 0x5d573ee3, 0xfa87b390, 0xece24f0d, 0x3f4dfd79, 0x3a142d98, 0x3ce76539, 0x7987ae45, + 0x1a617d01, 0xf9eb0345, 0x80cd6931, 0xcfc2e446, 0x6f7d679e, 0xd74de4fc, 0xb660598f, 0x02301c57, 0x3dce6e80, + 0x65ddbd03, 0x87cfb833, 0x09e5b257, 0x4c501c23, 0x2b28ac94, 0x285b2e98, 0xc6e0c877, 0x76050f1c, 0xe0072456, + 0x3425366c, 0xc63cc4d6, 0x4d17229f, 0x1f0a4b09, 0x9c7d5a73, 0xf4824cc1, 0x54081524, 0x568fa70a, 0x96635ff8, + 0x334a7f1e, 0xab1e2a6f, 0x8670c1a9, 0x1192fb9c, 0x0ef31f27, 0x48c7c3b5, 0xa5d44259, 0x011ecaed, 0x570ed039, + 0x683d1c5d, 0x7ba418f5, 0x81c26577, 0x6df4b105, 0x242fad3d, 0xcf156af5, 0xfb93105f, 0xa98747d6, 0x9d0f32a6, + 0xbe5f648e, 0x2c9ab4d0, 0x104aa52e, 0x5ccd3fd2, 0x2f59ffed, 0x5611296a, 0x1d66712d, 0x03bac541, 0xaa365585, + 0xc47c8c84, 0xdda5852e, 0x927ed385, 0xadaacd30, 0x4bd93d89, 0x44542438, 0x26f49cf0, 0x217837d6, 0x7921ff3e, + 0xa3015037, 0xeeda0115, 0x2d21c8d0, 0x1a111c99, 0xf9ff1a25, 0xd5d404fd, 0x36e4bd8e, 0x075907a3, 0x540a2cd9, + 0xdd1fce2b, 0x8a88a2bf, 0xf8c1bf16, 0x189c5844, 0xf2020a2e, 0x04b5c0e3, 0x3e574918, 0x3d1dda73, 0xe518d1a1, + 0xc043786e, 0x323a26b2, 0xcec1b5d3, 0x65d87d34, 0x1e7d2702, 0x905dd1bd, 0xa8395ee5, 0x249a5ee7, 0x4fd5e4a2, + 0x0d89e747, 0x56d0b3bf, 0x1e52255c, 0x374a0d96, 0x20715cc4, 0xb7100457, 0x32523fbf, 0x4b4ee063, 0xab73fb91, + 0x24760e62, 0x340091a8, 0x272a129c, 0x03493240, 0xc9d1c52b, 0x40cfb5f9, 0x41bcd22f, 0x23454170, 0x6565c3e2, + 0x177de95c, 0x930d9d2a, 0xca789491, 0x5427787a, 0x7c483e30, 0xb4b4bc0c, 0xe539b3a1, 0x6fc8e8ec, 0xf027efd5, + 0x55975b0e, 0x7ebb63e5, 0xa56acbc4, 0x18278a25, 0xa6f6a9e5, 0xbe14dfdc, 0xd2065f4e, 0x3de7c689, 0x2bc9ced2, + 0x2e5b5983, 0xafbdc2cc, 0xb03596bf, 0x40916d4d, 0xc83a5411, 0xa8c2da53, 0xe6f73f3f, 0xea89ced3, 0xf55dba4a, + 0x1ee6bbb8, 0x0a9892a7, 0xd56006f2, 0xec138a8d, 0xd01d7ed0, 0x1e4ea83d, 0x8be0c1d9, 0xcfa0b005, 0xf532b9f0, + 0x80563984, 0xb3a59038, 0xb23e08cd, 0xa5a470be, 0x4bba6dca, 0x1dd6348f, 0x1c49403b, 0xa1853f27, 0xb7b99d57, + 0x81160a99, 0xe9ea5ec5, 0x08e38190, 0x8ef5f4f6, 0xa8295bee, 0x3011a30f, 0xdd3e6935, 0xb58906e2, 0xd78aa7e2, + 0x4f823fec, 0xb2ad6be8, 0x3873af4e, 0xe489245f, 0x4c7c95d7, 0x64e3e4ce, 0x8f812234, 0xe34e2e8b, 0xb8e0690c, + 0xf93594c2, 0x7c247776, 0x4663978c, 0xdca98fa6, 0xf4fbad3a, 0x3bf1d597, 0x8859952f, 0xf9b7f6ed, 0xb2a31f3a, + 0xb4b93325, 0x379f5037, 0xb905c1bd, 0x19c30685, 0x24e4a7bc, 0x6bf23fa1, 0x95c1100b, 0x519048b7, 0xace71e73, + 0x3a79dabe, 0x2e28741e, 0x81c69dea, 0x21d4fb3c, 0xa0e6f814, 0x24b96f4d, 0xb987ddb7, 0xe7ee4975, 0xc6581e75, + 0x1b9f5be5, 0x45d5c546, 0xb8249841, 0x30c5b565, 0x1cc86c3a, 0x5337600b, 0x83784964, 0x513d5024, 0xbe69f80a, + 0x79790f15, 0x5223ac8b, 0x9f14b51a, 0x6d0a302e, 0x3a403446, 0x5db50618, 0x261660c7, 0xe6f00b11, 0x3977e572, + 0x06d23287, 0xe87aa100, 0x7653d8a2, 0x8ad07029, 0xdc0f04ae, 0x3edec3be, 0x56048113, 0x6f234b20, 0x5e87f1e3, + 0xc782d926, 0x0c265d6a, 0x72d032b6, 0xdd15a724, 0x1c1d52f3, 0xe367698e, 0x4294ef0e, 0x4143e789, 0xe82ee7f3, + 0x212fc9e6, 0x1ad603c5, 0x0f20a3d1, 0x61e50210, 0x0fdc8bcf, 0x5932a583, 0xf1b56bf8, 0x5bb67d8b, 0x8ba45140, + 0x6ee508d9, 0x7fd68f47, 0x23a808c0, 0x4a168099, 0x58e53eea, 0x703eaf95, 0x3ef2658f, 0xade384a4, 0x6138e01c, + 0x4a15a496, 0xd29305a0, 0x9f21018c, 0x93cfb677, 0x662c1ec0, 0x7cd8b90d, 0xfd9af42f, 0xb2248ee2, 0x0e9d53d3, + 0xb0367499, 0xdee4eb92, 0x60e27ac0, 0x815cd91a, 0x8ae80ac4, 0x5ef42cd6, 0x60b28a74, 0x86a6a326, 0x271f96ac, + 0x185b53fb, 0xbb329cdc, 0x75bbb1f3, 0x7a70adae, 0xfca41b74, 0x7a9f7778, 0x3fcd20dc, 0x6bcb966d, 0xae0b1f48, + 0x9c11bb2e, 0x45a6aa0d, 0xb6bb0544, 0x50ea381d, 0xadd09811, 0x34f6f98f, 0x050828cb, 0x15ea3717, 0x424faca8, + 0x0a07673b, 0x449b2062, 0xd7ee65cd, 0x41d2381c, 0x0343e106, 0xeb9f6633, 0xb38be08a, 0x2af63bf3, 0xded57c0f, + 0x24951246, 0xadf66c46, 0xdd2b97d3, 0x0b31f6e3, 0x3fe85ce2, 0x02a157bd, 0x7125b2a6, 0xa8ed921b, 0x8fe635b7, + 0x5675e045, 0xb2484af8, 0x309db473, 0x2d593fe3, 0xfd18c533, 0x5ccbabab, 0x816d939b, 0x3a8d7d2a, 0x18a1046f, + 0xa70f7f07, 0x8ebfd848, 0xdb04cb5d, 0x18679d68, 0xa7c46dc3, 0xaa43d48a, 0x76f0ea38, 0x9f00b75f, 0x4d93ab58, + 0x97a11726, 0x7279dac2, 0xdf4d15da, 0x46713ffc, 0x772e838e, 0x6a741427, 0xea4d6225, 0xbc28a5f2, 0x020c9ed6, + 0x3340a141, 0x1b49858f, 0x0c1a5bbb, 0xc79c5877, 0xe9c40b9f, 0x7c8087ec, 0x50fa6e2a, 0xd71d3ba2, 0x3612d60e, + 0xb32edccb, 0xde625545, 0x9dd1884f, 0x32cdc3b5, 0xec61ac1f, 0xfebd821c, 0x7a172cb5, 0x6e7f9bcb, 0xf45be6f5, + 0x5db0286c, 0x775a8031, 0xfe341cec, 0xcfe4063e, 0x38beb50a, 0x8419ce45, 0x17123771, 0x8400db40, 0xc3efbead, + 0x8f5b9513, 0x95344c32, 0xc6dccf4d, 0xa921693f, 0x7050fef3, 0xc49e00e2, 0xc9f5c993, 0xb5ced0e8, 0xac6ba2e6, + 0xf267773d, 0x63c05f7e, 0xe0ee9f17, 0x2245f10c, 0x829b5bdf, 0x8bc83629, 0x1d3e6a58, 0x1494f0f8, 0xdbea3303, + 0xa0a6cf33, 0x4160089a, 0x74a2d125, 0x52bb0fb0, 0x4c870caa, 0x251d0e27, 0x77785b1f, 0xf170652d, 0x24354645, + 0xb35d8108, 0xc6634f94, 0x7682e399, 0xe2d57a0a, 0x98839a66, 0xa12f68be, 0x88e9a2b7, 0xd9f0f4d5, 0x4bcb26f4, + 0x094c9319, 0x97a12c3d, 0x948b809a, 0x17831f90, 0x7296b7b4, 0xf5e22d34, 0x8108ee08, 0x58283fa2, 0x3f85f63c, + 0x78848d7c, 0x62926dac, 0xa4d6bf26, 0x41de0d3d, 0x8ed651f9, 0x89cf3df5, 0x492f7e33, 0x2065bf13, 0x3dd3439f, + 0x8366c69d, 0xc03505e7, 0x07afc857, 0xcd19bf4c, 0xe95ffcbd, 0x5139567a, 0x52bef3c6, 0x5f9dd084, 0xb5768d78, + 0xf1f4149d, 0x666fc892, 0x932c27d7, 0xec5ff1bc, 0x50d6bac3, 0xbe1aed17, 0xa34e01b8, 0x4aaef768, 0xf3448a73, + 0x55c860bf, 0x106f33c7, 0x48da17d2, 0xd9df6c2f, 0x70b625b6, 0xf9959a38, 0xb47b0ebc, 0x25200988, 0x29d0c4da, + 0x819c572a, 0x2b5100fc, 0xcb44efbd, 0x38693bf2, 0xd4701a28, 0xa6cb31f6, 0x5e048628, 0xfb20df8b, 0x451f55e6, + 0xb1fa0194, 0x5c5632ec, 0xe164d3c0, 0xa91ce4b3, 0x4268adfb, 0x5dd8d8db, 0xf4bdc713, 0x08b68c32, 0x858a64c6, + 0x0f3a6c8a, 0xd31d93ec, 0x33a2ffb5, 0xdd5a453c, 0xfd5ea415, 0x1c7ec15b, 0xa3146722, 0x7b74e9c7, 0x9f3ca02d, + 0x1014cee2, 0x3050bf74, 0x051aa679, 0xa05b36fa, 0x4fca0622, 0x6d4f3eb8, 0xc6fa90e4, 0x06a9e646, 0x1d2378cf, + 0x4d9117a4, 0x684e320e, 0x21be1a49, 0x7c268ab3, 0x7901e6bf, 0x6158ec15, 0x32a261bc, 0xdb41b0fe, 0xb68ff7db, + 0x51420568, 0x51269cab, 0x45553971, 0x3cfc4ab5, 0xe0968f5a, 0xfda23f36, 0x478abac8, 0x4fe0b545, 0x470471f5, + 0x24b1ec26, 0x41a00925, 0xd85e79fe, 0x108eb2c5, 0x964de8ff, 0xcffe493d, 0x417eeabe, 0x8c48badf, 0x2203ad1a, + 0xbc9d7ebc, 0x469a811c, 0xfda71c4c, 0xeb617574, 0x778fa89d, 0x6404ca45, 0xea7eb4e2, 0x75011f37, 0x259f9823, + 0xa95eb2b5, 0x200166d7, 0x929b967b, 0x3dbc6c8b, 0x887e3bbc, 0x0e91ac6b, 0xc927b046, 0xc3a82d99, 0x14a19cc6, + 0x648cc1c3, 0x545c6e37, 0x8c89cbed, 0xec54264c, 0x6cbedefa, 0x6431e9ad, 0x9af873f3, 0x1afa08bf, 0x516852a7, + 0xa7baf26b, 0xc4d35289, 0x3650dc4e, 0x6c83c079, 0x46f19780, 0x2716adcd, 0x268bc16d, 0xd765b804, 0xc4c7d8d3, + 0x6fbbed76, 0xaead230c, 0x2fcd30ff, 0x920d1001, 0xcb199b70, 0x8279380a, 0x8f1e5676, 0x691aee5d, 0x023367a8, + 0x40ce04cf, 0x80b28330, 0xecec8f0e, 0x6ddca04f, 0x1b026ee9, 0x8633dded, 0x503fb2e2, 0x7bc3dea4, 0xc981b9f9, + 0xa38bab35, 0x7bb8521d, 0x6077d00a, 0x1e70f876, 0x445ec589, 0x14eab75b, 0x150140a3, 0x9360a30f, 0xbf687993, + 0x7bfbddbd, 0x634eb082, 0x5ab9a810, 0x98e6eb0e, 0x2df7b610, 0xf434274a, 0x7e1daaac, 0x58fde125, 0x381f1a3b, + 0xddaf7c09, 0x7d1b2c52, 0x929c5f34, 0xc69398aa, 0xb53fb5a1, 0x918b135c, 0xaf8f7f25, 0xef3476ce, 0xafb1afaf, + 0xe5596068, 0x200697de, 0x33be5fc7, 0xa145571b, 0x2c6d26ed, 0x535de201, 0x9e813ece, 0x9128fffc, 0x77d1ad44, + 0x9befde34, 0xea4b41dd, 0xba7a4913, 0x21e95de8, 0x1e96f7ec, 0x9eec5aa6, 0xe07ae5c8, 0x658d87e2, 0x3d4660de, + 0x6265ab64, 0x9ff7f78f, 0x4820939a, 0x08fc266d, 0x462eec75, 0x08fc11f2, 0x7af25830, 0x6ac78ee5, 0xc041f5ae, + 0x69c84975, 0xc51efc7c, 0xc8281c6f, 0x26ade9c0, 0xa6242968, 0x5f10dc76, 0x1db88c5d, 0xff7d9f17, 0x65bbfbca, + 0xd2805666, 0x432e4d9b, 0x8381d503, 0xa76ddbef, 0xdb1964ee, 0x4c029133, 0xd695f2fe, 0xae161af9, 0xc50e05cc, + 0x75c8ed93, 0xe3437ad5, 0x08ae7237, 0xf9675c60, 0x8fe0e99f, 0xcadf4be7, 0x3ebf7612, 0x3550d3db, 0xc7c83ef8, + 0x7c1e1759, 0x00dbc66b, 0x5cbac9d2, 0x3597b922, 0x1e1e3355, 0x10d99744, 0x3f9ea0f7, 0x4ab57ad5, 0xa881ac18, + 0x10e0d659, 0x24ae9767, 0x1c38f619, 0x39aa2d20, 0xf4fd7219, 0x7155a3ff, 0xce8d6dee, 0x4f475409, 0x16f7efc6, + 0x0185c15f, 0x935ecca0, 0x4cf071ef, 0xf3af7b49, 0x70c86b7e, 0x41775d25, 0x5a37ca16, 0x008daef3, 0x5100a039, + 0x2fd53c38, 0x78eaf679, 0x8351fd1e, 0xd7bfe854, 0xac9207b9, 0x87b05ff2, 0xc6f31901, 0xa50f7afc, 0xffde3ca6, + 0xde079fe7, 0xaee223e5, 0x6e23524f, 0x84951bd9, 0x8c64c52c, 0x66774c4a, 0x4925b493, 0xe4b81421, 0x6b0e1383, + 0x3a81a959, 0x284861cc, 0xf4fa345a, 0x5d4d1245, 0xffc68fcb, 0x4e6facdc, 0x188ac395, 0x19b13157, 0xd876951e, + 0xdd995ca1, 0x76549427, 0x2b0b5610, 0x2c1ca852, 0x919a1742, 0x77df8800, 0x7286f2ea, 0x1f4c4b2e, 0xfc014ac7, + 0x2221d628, 0x4200b9d1, 0xa699d550, 0xdecc521e, 0x920481d9, 0xdade7765, 0x75864446, 0x3e6d147a, 0xfe124883, + 0x147d8f51, 0x8de7a9d5, 0x1efccd37, 0x30e0c188, 0x9fd328b7, 0x7e6f8ca4, 0x6ce9253e, 0xe3e20b27, 0x4737676c, + 0x9ea8c3bb, 0x66ac3dcc, 0xc12f6e8e, 0xdb83bd19, 0x77002024, 0x1383a74d, 0x833a1e0b, 0x9f747ade, 0x5d842867, + 0x8a651fe6, 0x660bf5b4, 0x6126caa4, 0xd288949c, 0x0a375ccc, 0xecefdc8c, 0xb86eafbf, 0x72a24aa5, 0x3e0cbdbc, + 0x203f0ff8, 0x6d34682f, 0xfb360c80, 0xad7de30e, 0xbd6469c7, 0xc99281c3, 0x83749f4e, 0x6dd204ed, 0x22df29fe, + 0x3a760d8f, 0xc1d29859, 0xc6f41bcf, 0x426e8dd5, 0x0a78dd67, 0x5697b4cc, 0x54464f5c, 0x4b794a08, 0x629cd208, + 0xba6e9f7e, 0xe45f8d89, 0xaa9990e8, 0x65362efe, 0xb4b0d1a4, 0x4e94c74b, 0xbe4d4b69, 0x80329293, 0x669848a7, + 0xd48f3bae, 0xa2e33679, 0xeeb4e514, 0x1370c897, 0xd5c02f6e, 0xefcb0f04, 0xec9bb166, 0x3f7387fd, 0x0cb5e0d0, + 0xa4e48913, 0x7d21a83c, 0x479b2298, 0xe21c68e1, 0xc4754c09, 0xc712fe03, 0xa06792bc, 0x91b0647c, 0x2917b0b1, + 0xba84f212, 0xfdd43daf, 0x05978ba0, 0x1ba0a877, 0x59295846, 0xf5eb7c20, 0x27f89e64, 0x9b704292, 0x7fe3bc7a, + 0xd64ec3bb, 0x591e3eb7, 0xba4bf60f, 0xa0b4812f, 0xeacdbe70, 0x35eced66, 0xb786faf5, 0x116de8e7, 0x5ffc5824, + 0xdb2b200a, 0xc73fc05c, 0xd6bcaaae, 0x0b4bbf04, 0x788a06ff, 0x63e7a530, 0x6cd36863, 0xd99977df, 0x4a99afd8, + 0x41f3190b, 0x083e4441, 0x4ba88689, 0xfa0ef62d, 0xd9bccb42, 0xfc0797f7, 0xb3dc581d, 0x4cb1892b, 0x2f7e1498, + 0xcd9215ff, 0x79ae278f, 0x59838b3d, 0x7b1737e0, 0x54244f7f, 0xb72a52bc, 0x2372985a, 0x12241d53, 0x6adc8539, + 0x9711abd0, 0xd8b24f36, 0x01980a3a, 0xd8b59f84, 0x75086d69, 0x62b3966c, 0xd01343a6, 0x6eca5c0d, 0x549577f5, + 0xbe111715, 0xd701d42a, 0x05a1bdb0, 0xf278ef4c, 0xae31e504, 0x6ed7bdee, 0xbf4c349f, 0xa74eb3ea, 0xb71274f9, + 0x91a56ca9, 0xbec35738, 0x9739f40b, 0xc005cbfa, 0x82cd5983, 0xee0cf47f, 0x4469cf1d, 0xd2aef6dd, 0xbcd7b016, + 0x986e82fe, 0xfd978861, 0x10c210d2, 0xfcbef2c6, 0x64f9f6ed, 0x15328bf5, 0xd9e50897, 0x457abbdf, 0xc85b4203, + 0x159cdf7d, 0x6fe38deb, 0xbba6e24c, 0x08771461, 0xbefdd29e, 0x5ca06667, 0xcefecb37, 0xc90661ad, 0x5e14f4dc, + 0x74f49c9f, 0xda7c7d89, 0xc54fb68b, 0x043b3db6, 0x4c577d46, 0x5785334c, 0x52fc2178, 0x9a0c4c9d, 0x22a6fb86, + 0x6762809a, 0x916c206c, 0x0be02f2c, 0x0dd94a9f, 0x66ecef06, 0x59a72d52, 0x4d3ddceb, 0x24c99b74, 0xec1bd3ed, + 0x280e6a89, 0x3fde1fe8, 0xc841196e, 0xdcb4ae66, 0x20e61c69, 0x226a87cf, 0x4ab88f39, 0xcdb51598, 0x1007a046, + 0x500958da, 0x46dd3be3, 0x7e9e433a, 0x973e279c, 0x35d9cf50, 0xeb26cffe, 0xc471c52c, 0x039ce931, 0xe0f97b52, + 0x4360a983, 0xf5ce202b, 0x21200db2, 0x32aade18, 0x53afc633, 0x2469d2f5, 0x89d24d88, 0x3bbb8c80, 0xa791e6b9, + 0xbec46474, 0x70f70413, 0x6ffd6368, 0x3c16cf1c, 0x41d2c391, 0x470bbd7a, 0x5f32bbcb, 0xd56672f5, 0x0199fcb1, + 0x21d9bf1a, 0xd03cf321, 0x1369cff2, 0x0ef098db, 0x00eedf16, 0x2e133a49, 0xd7b7de5f, 0xe2eb3b2c, 0xf4519b3a, + 0x0c62b78c, 0x9464783e, 0xdf71e28e, 0xd6bb3b8c, 0xb36cf127, 0xdf5ab111, 0xd0ef39ea, 0xa5721896, 0x3a8b8e81, + 0xa77fc3c0, 0x3eaa5f4e, 0xbf5566ce, 0x95b6d489, 0x24246e76, 0x3bc2d37a, 0xbcdf8d25, 0x3ebe7a59, 0x7f610c91, + 0x7736bcdd, 0x75bc2424, 0x85c70d05, 0xbeb7ba24, 0x4423de3b, 0x228f9f73, 0x7c01c1bf, 0x9f0d29a4, 0x61a80872, + 0x3ec5601f, 0x27ba04c4, 0xd7a5024e, 0x71452235, 0xfb211dc9, 0x61aa93d6, 0xbf25696f, 0x22b2f2a2, 0x969488a2, + 0x82dff5ba, 0xcfe623fd, 0x88329b88, 0x4cccb4ba, 0xb76482cc, 0xe5023477, 0xa46a3894, 0xbe7c5404, 0xd1fd3901, + 0xe6bbe2ce, 0x0c4f1b4f, 0xacc9b278, 0x3db561f4, 0x332dc3b6, 0xf38df13c, 0xeae891c4, 0x8f00c6d3, 0x778f1d35, + 0x99846b91, 0x5f3096ff, 0x4a87ec24, 0x7c7c7bfa, 0x47ee71c1, 0xb372259f, 0x572c7bbb, 0x9fac8e01, 0xbc3e5e7b, + 0x0a98ad4a, 0x8724098b, 0xb65b4238, 0x08816daf, 0x0ba64183, 0x50cc14e1, 0x42895df2, 0x8858e739, 0xcbe17ba9, + 0x1b74d24f, 0x4402d400, 0x5cc6ed20, 0x279a68ce, 0x7127622f, 0xb430e865, 0xe15ef496, 0x0ebe1de7, 0xd28793ef, + 0x1e95ce31, 0x753f0cb8, 0x9bdb6bfd, 0x5ecc4ba1, 0xf4421461, 0xadf6bdfd, 0xc01bd28e, 0x4419125c, 0x2d7d94e3, + 0x5073c54a, 0x96aeece3, 0x840a2b99, 0xb24aa255, 0x38345e2f, 0xf34125d6, 0xc761e37c, 0xb5ef96ce, 0x11d2d1fa, + 0xad59d51b, 0x360870ab, 0xbfcdf45d, 0x480e2047, 0x0dfda9b9, 0xdae944f9, 0x6f03ee85, 0x3b6f8dec, 0xed9fd4ce, + 0x2cfd70f7, 0xcb88d469, 0x5935984e, 0xa8d78801, 0x341df785, 0x020e6c47, 0x65f12cef, 0xdec04f23, 0x03e3fe4e, + 0xdd3008ff, 0xada46c49, 0x85e22f56, 0x278bb9f1, 0xfdcaa6b5, 0xaf47c5c9, 0x01381941, 0x3f60c1f6, 0x67f8da0e, + 0xa5939439, 0x4c0f815f, 0x2a17adbe, 0xed844395, 0xf2574d5b, 0x55e0b113, 0xdc8a1aef, 0x7ec73cd1, 0xb4d868e0, + 0x56f54288, 0x636cab2a, 0x5b33eb1b, 0x1a4f3fda, 0x613a2cb4, 0x5fac0fc4, 0x082f9f9a, 0xddea4a23, 0xc1484a94, + 0xa75a8bf9, 0x5575b1b5, 0x895bf61b, 0x7e3d5b23, 0x0c504c94, 0x8f7002be, 0xbb91b010, 0xe0c0e536, 0xdb74aee7, + 0xb1364dd8, 0x2d7610bc, 0xf0b00272, 0xa69f0300, 0x66e18979, 0x3268085a, 0x4efa9e50, 0xd084d664, 0x360f51fb, + 0x6b7a7c30, 0x2784ab4e, 0x3783c57e, 0xccf4e91d, 0x53b8639e, 0x194c94c8, 0xfe9f1f85, 0x2c3fd121, 0x5f61d770, + 0x5eae06a4, 0x58696c5a, 0xfc6871d1, 0x190701f4, 0x6ea70120, 0x1aabebf6, 0x634f5197, 0xee0233f9, 0xa86fec8c, + 0xf8b401e5, 0x3d41f088, 0xd040ff28, 0x35e174dd, 0x5e62e392, 0x7298867f, 0x4a0141f9, 0x16af8a83, 0xe79ade31, + 0x600f270d, 0xfba0bc80, 0x963ef16f, 0x1d356ea0, 0xfecd8e0f, 0xbe48905f, 0x4e444b91, 0xb00ddb84, 0x50dc11cc, + 0x66dbbdc1, 0x9b70316c, 0xaa65c3cd, 0xe4c95a37, 0x16807f45, 0x1c780fdb, 0xe48d9478, 0x551787d5, 0x5a9f9918, + 0x73d898a7, 0xdfadd8fd, 0x1929933e, 0x68ba46fe, 0x20216b46, 0x8ed90a4c, 0x468398db, 0x3d7c8352, 0x1791921e, + 0xbb5f1e08, 0x7e566151, 0x1c65b9ce, 0xd9a2f352, 0x81d68bd6, 0x80c980f5, 0xc9fd0a8f, 0x536fc6a3, 0x9e9d42bf, + 0x82fa063e, 0xcb52fabb, 0x07be95ad, 0x4677fb89, 0x3e6ce045, 0xa3b66e20, 0xc5061497, 0xffd971db, 0x5f535bc4, + 0x8c327bdf, 0xb1bc1ead, 0xea9cbf9d, 0xcdab1f9a, 0x76b2d7f2, 0xc3c2c476, 0xbffc7ea3, 0x0f2a9fdc, 0x33a14617, + 0x3fd9bb97, 0x07a1f3d9, 0xec3fabfb, 0xa9ff2d22, 0xf777121f, 0xa64456f4, 0xf7d1bd52, 0x411f3c98, 0x0f55fb48, + 0x053eacbb, 0x700c0ed5, 0x83b963ba, 0x97cd7698, 0x6f220158, 0xca43ce0d, 0x6b29fdf8, 0x60f1b4c6, 0xd547b235, + 0x0358ad8d, 0x7ebe869c, 0x5af8778e, 0xe2fbc986, 0xbd1c082f, 0xcd059775, 0x3cabcfda, 0xe2376984, 0x4747e9a9, + 0xd2373caf, 0xf6a5860b, 0xdfa4021d, 0x69ad5b16, 0x2284c521, 0x59d71496, 0x5f9c7000, 0x0c3b6c91, 0xbb9b4879, + 0x97582d54, 0xe0724668, 0xe2aeaa4c, 0x331f51b8, 0x6e2ca429, 0xc016e51e, 0x1c42d62f, 0x8b48d470, 0x271ae05f, + 0x5d90e07d, 0xf8785c52, 0x19a9c1e3, 0x02c97c1f, 0xb78faa43, 0xfbaeb138, 0x10586a10, 0x7dd1bd14, 0x91638d23, + 0xce1b1a7f, 0x30090d9c, 0xfff154b9, 0xdbd388e6, 0xa7ed52f9, 0x7bd0a9f0, 0x413dc608, 0x23475b4c, 0x3c79bb08, + 0x541906c3, 0xc25bfe53, 0x8cb22920, 0x396c9527, 0xc6e96e6d, 0xb1d78e9b, 0x978fb498, 0x36cd5f22, 0xac668ac5, + 0x54dafbfd, 0x593de62e, 0x2e42e635, 0xa881013f, 0xc094af28, 0x0efb8375, 0x11dab52e, 0x2540ed9b, 0xa68eded8, + 0x7abc5440, 0xde98a988, 0x9002bb36, 0xd84f6337, 0x75555601, 0x34586498, 0xd4dc0ef8, 0x7dd5914f, 0x8d99d5ed, + 0x4610e1a5, 0x270a8dec, 0x20dcbc37, 0x573da163, 0xc3de4fdd, 0xfed241c7, 0x5f702fdd, 0x69ef7655, 0x13a1d8ef, + 0xd3b95e3c, 0x1a5980fe, 0xb5319513, 0x9db66136, 0x5087d029, 0xfc5ee0b9, 0x3885f5f5, 0x434657f5, 0x3a93e272, + 0xd9352c83, 0x210a7dac, 0xc94a6161, 0xbecaaf13, 0xa203a2cb, 0xe4b7956e, 0x33a795ae, 0x3013f92d, 0x7017b2a2, + 0xe9648991, 0xf666727d, 0x87254196, 0x425e6c0d, 0xdd6921f2, 0xbaab70e6, 0x1950b964, 0x12cc95f3, 0x8588ea02, + 0x9c309889, 0x226d5346, 0x08c0422d, 0x4aaff038, 0x318e1ed1, 0xb1250842, 0xcd92c239, 0x30ac9516, 0xa41a7cd0, + 0x439c4890, 0xb3d64c18, 0xe7ef72cc, 0x5bf0e280, 0x0630f64d, 0x976e451d, 0xb76c815d, 0x54779a00, 0xa7dc36ee, + 0x3e6c2eb0, 0xda42f914, 0x39fcb8aa, 0xca8f5498, 0xd528556b, 0xa7861f2c, 0xb83334a1, 0x302e2414, 0x9daf4e66, + 0x1e11f170, 0x3a143b9b, 0x853f108c, 0x484f2ea5, 0xeef175ec, 0x31e06474, 0x75c4b65c, 0x454d4395, 0xe88aeb5c, + 0x90cceb6d, 0x9a8f046a, 0x3561242c, 0xb0495b23, 0x7e91a88e, 0xaae05d29, 0xf6438703, 0xd21ecd9a, 0x2cfbf6ac, + 0x233fc54e, 0x1ea2bd78, 0x50414629, 0x7b1a2dbc, 0x9a32e01c, 0xbaf19dab, 0xf99405c6, 0xb43a22cc, 0x54c14b94, + 0xaa3714a8, 0xc6d724ed, 0x3efcfc89, 0xac284f06, 0x01b333b9, 0x5c229bb2, 0xd9438eb6, 0xebbb298a, 0x83f5346f, + 0x2ca83009, 0xcd6d1575, 0x1d869607, 0xc5844af1, 0xfb1d13bc, 0x0a923b7d, 0x543d836d, 0xce7b47c3, 0x09325077, + 0xddc69fc5, 0xa84fac2e, 0xf1a34dad, 0x037b9aa5, 0x1abb9cb8, 0x9373b949, 0xb990b1c8, 0xa578cf79, 0xe4dcc060, + 0x66c03367, 0xd9be1315, 0x4d555340, 0x11929d56, 0xaef2901c, 0xc57fdc57, 0xb93b1dda, 0x803acd41, 0x0a9d1d5c, + 0xace3a189, 0xb301b223, 0x1bcdef5c, 0xb1e320cc, 0x23f223e8, 0xfd7492d0, 0x8d2de4f2, 0xc9c5a5d7, 0x649a3287, + 0xf215a122, 0xe08f3ffe, 0x65653b50, 0x941fd735, 0xb3d79d1f, 0x7070d2b9, 0x70ce8d7b, 0x67889ef8, 0x9bdc7d28, + 0xcaf4f4f6, 0x05fef23c, 0x48b7dc57, 0x8bd7fa12, 0xa52c4ef4, 0x89a79b8a, 0x3ba605e2, 0xc819c385, 0x9e9f9104, + 0x8d5bcbf2, 0xe4fdf73b, 0x0643276f, 0x790eacaa, 0x13a90024, 0x3f1f28f3, 0xd8bd6ef8, 0xd8f910d2, 0x00c6be15, + 0xe06016f5, 0xaa221402, 0xa029ff77, 0x7817ba1a, 0xf9ed2c16, 0xe0971174, 0x3e7e3b5c, 0x60cdf284, 0xef759e55, + 0x4020458b, 0x182d9540, 0x85a32cab, 0x7be4e579, 0x1ea122b0, 0xd350c4b4, 0x8d44340b, 0xed086e64, 0xd411bff3, + 0xc08503e4, 0x032a0396, 0xd221159c, 0x6f7d68ed, 0x895a623a, 0x0909a5bb, 0xbee06f06, 0xb690e2fc, 0xdbd5cebc, + 0x265deef0, 0x6f2bf00f, 0xacef4f16, 0x09f65401, 0x1aadd1d7, 0x53ae0c18, 0xde0b4424, 0x936b315e, 0x712cb052, + 0xef49abac, 0xa3f4b791, 0xadbf41e5, 0xfaa53a83, 0x15f0595d, 0xd9e2cbb5, 0x6db0d781, 0x08a045f5, 0x34d4343f, + 0xe01bb483, 0x4a069213, 0xf5fbc43e, 0x23769f5e, 0xb305d49f, 0x4afef682, 0x3e557f40, 0xc8f8b987, 0xbe8d4db9, + 0x39704de6, 0x08cacb6d, 0x97c3c23a, 0xfab89da9, 0xe5dffd65, 0x5d11ab26, 0x5985d8b0, 0x8b6f15cd, 0x3731a369, + 0x9e616045, 0xbb07df01, 0x7d63bf86, 0xe457c930, 0x8f322cf0, 0xad0245b8, 0x5ff2b4dd, 0xc61bbdfd, 0x6242de03, + 0xe5b42446, 0xe03362fa, 0x7847fb04, 0x5afb1e6d, 0x0a072803, 0x0d48fc22, 0xa63c500f, 0x6fb7c6c8, 0x539ac025, + 0x55bdd19f, 0xb9b74278, 0x2e29de06, 0x9e71e2c2, 0x3619ca29, 0x8590bc96, 0xa7de08fe, 0x2b6f54cb, 0x34504373, + 0xe5ac41d7, 0x764b6ea5, 0x0418a0dd, 0x886cfe9a, 0xad5e90c5, 0xa87ae68a, 0xfaea2295, 0x70bda1ae, 0x24b9d102, + 0xa05d8bfc, 0x67c23eca, 0x1f9aee2e, 0xb6360e7f, 0x2676e750, 0x62fc7ced, 0xed7e3ed7, 0x61b5e969, 0xa6643ef2, + 0x13f78cec, 0x55d5c9e3, 0x7d0e1837, 0xd73509ce, 0x9ef54531, 0x53c616e0, 0x8debd429, 0x2de3ea22, 0xc498e68e, + 0x7287080e, 0x9aeac5da, 0x6edd1a1e, 0x1d6ec11b, 0x6314a901, 0xaaa84229, 0xb134b896, 0xc9d9f8d9, 0x8ff53af4, + 0xc8bc481b, 0x13ec8911, 0x4236d4eb, 0x975e841d, 0x531f9933, 0xad8706a6, 0x219544fb, 0x1c8dee20, 0x933c2bab, + 0x181b672e, 0xf9720f21, 0xbbe02e5b, 0xf28d5c07, 0x75c60f36, 0x756f764b, 0xb3c19956, 0xa48053d2, 0x14c8d0a9, + 0x3f541528, 0xe08a771e, 0xaa208bd3, 0x48aafb11, 0xb5a34887, 0xed4968af, 0xaf4a2979, 0x6d12f3d2, 0x7bf15781, + 0x3d861eb2, 0xc8d093b5, 0xd4af20f4, 0x8f8bec35, 0x61b78976, 0x6bd7c5e8, 0x1ecf4478, 0x89f76893, 0xdd7fc4f6, + 0x9575c902, 0x353cbd32, 0x122f2f2c, 0x12799078, 0xe115b5b6, 0x300ba238, 0x9641654f, 0x269c8c41, 0x1ba8dfaf, + 0xb58b6115, 0xccf81b09, 0xc484018e, 0x53e7f876, 0x33cb516d, 0xa598cd85, 0x96ff6cef, 0x6a01be51, 0x7e6da28e, + 0xec588f84, 0x50a23131, 0x4705dbea, 0xe4130e37, 0x844f43c1, 0x94a5d756, 0xb28a947b, 0x46b9b710, 0x812b8c04, + 0x08665e95, 0x0bbe6687, 0x3f5db4a7, 0x0d9d6564, 0xb2cd24fe, 0x435c572e, 0x738a8784, 0x734885a8, 0x7ea18bd1, + 0x76536b62, 0xf0b48e79, 0x60e8a486, 0x3a97dac8, 0xc8115663, 0x549d5228, 0x93664af2, 0x4170d3a6, 0x51cc64a3, + 0x47e50f43, 0xfd089994, 0xa7bf3669, 0x27c86218, 0xa2247c34, 0xcb0d4c98, 0xb942ea24, 0x7dafaf03, 0x39c8b291, + 0xa4dae21e, 0xeaff9c6c, 0x9fbe9c1e, 0x5beed636, 0x458721c7, 0x7897d79a, 0x8997ede2, 0x23408af9, 0xa16a6a89, + 0xf0d8d1fc, 0x88e265c8, 0xac9199f1, 0x51a39e4b, 0xe4445e46, 0xec2efde1, 0xd7d72398, 0xed2268b9, 0xbf073032, + 0xb7a5df43, 0x2bfcd0cb, 0x9b0125be, 0x71f9f9c9, 0xcc8182f9, 0xc8df86f3, 0x602761aa, 0x90657a06, 0x6ebd28ae, + 0xafaf29c9, 0xe34694ba, 0x61b2e8c5, 0xce4e7924, 0x657e0afd, 0x763e45fc, 0xc919161d, 0x7901c017, 0x9c411a6e, + 0x4f992658, 0x8dbac46a, 0x6aeec55e, 0x890995f8, 0x6dbf896e, 0xef063d70, 0x6e43a93e, 0x463ccd4b, 0x930b8bf5, + 0xbd0c9edb, 0x1a4f00f2, 0xdad07157, 0x4a53d6f2, 0x4507bdeb, 0x1d66ae55, 0x65cd467d, 0x4457ea6c, 0x7b63a40d, + 0xcc988b9a, 0xc92f1255, 0xb3620de4, 0x20af699c, 0x2d57af04, 0xb8cebe99, 0xca3386c4, 0xcb7064af, 0x250f7d6d, + 0x89daab04, 0x1fd4df63, 0x03cc955a, 0xe7b65b0b, 0x9f308231, 0xfdee35d5, 0x67952ae1, 0xef57ba35, 0x26debae3, + 0x278a27c4, 0xaedad107, 0x029afec4, 0x06be2547, 0x03ccdd16, 0x4ae9edf4, 0x164dc66d, 0x72808858, 0x8266b490, + 0x6371d8da, 0xbbba9710, 0x3a2f8a5e, 0xb7226451, 0xec0e3241, 0x0c013c22, 0xb7635ba2, 0xdb206d85, 0x939de79f, + 0x7b6dd4c8, 0xda7ff402, 0x1a13e32d, 0x304084dc, 0x23b85ad0, 0x2c06c157, 0x1687aca6, 0x865b43ed, 0x7861b813, + 0xb846e388, 0x4ad13c16, 0xb35e3b7e, 0x932870f0, 0xcf4d8779, 0x9bbec694, 0x9544d55b, 0x32d4cfff, 0x151ead2b, + 0x81f3ddf6, 0x4b2f74df, 0xcced2f0a, 0x3ae10a3f, 0x24172442, 0x64b7d114, 0x3ec4d54e, 0xc5e4755f, 0x439b8713, + 0xeb061e09, 0x7a125e49, 0x5df86019, 0x8ff08119, 0x8ebed408, 0x14ff71aa, 0x5424b7b5, 0xa7b754a5, 0x7036b5bd, + 0x75762122, 0x7f42117e, 0x2615c731, 0x4312c4bb, 0xdecee840, 0xedb3e8c9, 0xc3002ec4, 0xac55da69, 0xbd0cf99e, + 0x3e6601cb, 0x47a1a5a2, 0x3576086c, 0x8c625563, 0x06f203b1, 0x314c44c5, 0x9376844d, 0xa30e3fc8, 0xb7607bb6, + 0x2770d2f0, 0x2ed305f8, 0x9c508944, 0x2d28428b, 0xf5791986, 0x0bea0854, 0xe87682a7, 0x8dcdd57b, 0x3c5f7f62, + 0xe2c34ed9, 0x88b943bd, 0x3c526f89, 0xe0a81f06, 0xee7ea8e1, 0x92cfbd53, 0x95106aa8, 0x8d90cd5b, 0x1ba728f1, + 0x9bc67c35, 0x2899f904, 0xa6c6e5e1, 0x226bc9c3, 0x65abe7b1, 0xdce035f6, 0xd2b61238, 0x02e6e2cf, 0x54c12fec, + 0xc161dbf5, 0x859f2828, 0x8c5b9e79, 0xa5df359d, 0xef3f1b55, 0xf8d268d0, 0x7d95c48a, 0xb830f34a, 0xccac243b, + 0x077e7db4, 0x7337f267, 0xffad979b, 0xcf02dbb1, 0x47df9fcd, 0x7463edc0, 0x1709b4a4, 0x133ae09e, 0x18814e26, + 0xda936a79, 0x1c8ebcf2, 0x62817a87, 0xcddbaab2, 0x9bda2a82, 0xbfb6cd6e, 0x9fa115e6, 0x962464f9, 0xeab20517, + 0x9afbcac0, 0x9a3a3d63, 0xfc4353c6, 0x146c20e4, 0x8c077d7d, 0xda9010c3, 0xd0c019d5, 0x90389132, 0xd302a79c, + 0x9cd86849, 0x7c1dcb97, 0xa3c7f285, 0xc08b956d, 0x071dae19, 0x98c219da, 0x8f390315, 0xb646c1fc, 0x868b6c62, + 0x55ac5af1, 0x7cf83310, 0xd20483db, 0x96d87f7b, 0x1fce67a7, 0x1c1a1047, 0xd88e0c66, 0xbd1c41a0, 0x52f19184, + 0xcc52d74c, 0xbaaad1b7, 0x3b6a80b9, 0x8d9e2df3, 0x430b51d0, 0xcc687781, 0xc5ca82e5, 0xa42c7fc6, 0xc2f54339, + 0x28290fc9, 0x8d336d6e, 0xb6d9870c, 0xe855c5e3, 0xb9833e86, 0xf2b92f79, 0xf6471c7a, 0x33d180c4, 0x0905c92e, + 0xb2717f66, 0x3ef96242, 0xe260069e, 0xc8dcaca2, 0x8d93c38a, 0x065984d1, 0x8d4b8cd2, 0x71796a14, 0xa0a27951, + 0xb75c9090, 0xdf711621, 0xe35f81fa, 0xd2b3e4fa, 0x3a0c98e3, 0x0137e6ee, 0x62b63d61, 0xc45ac451, 0x3e477607, + 0xf1aedf18, 0x71141b4b, 0x9a3423c2, 0x0d12214b, 0xf20b8ea7, 0x5c3acde1, 0x912d82b8, 0xcf25a406, 0xfed72e8f, + 0xdf34f620, 0x3bb37f5e, 0xc0d4c85f, 0x22da59d9, 0xed835c03, 0x2215e8ba, 0x4269e829, 0x734232b0, 0xd812550d, + 0xe5fdef06, 0x3adc21a2, 0x03061a83, 0xe0d6b05f, 0x6a50fa60, 0x44aebdca, 0x6a90c92e, 0xea62fbef, 0xa5a19b7e, + 0x53b661d2, 0x2b72b7d5, 0x33217196, 0x76836928, 0x7be63aa0, 0x0f32c773, 0xc868ba8c, 0x02f3820d, 0x8e597e57, + 0x3176f661, 0x9cf5da78, 0xacc37217, 0x1ee68b5c, 0xab67e331, 0xcaa6630b, 0xf0370aac, 0xe91fc5cb, 0x310772de, + 0x631a911c, 0xa8edcaf1, 0xbdfdca5b, 0xe1b183d0, 0x522cdb46, 0xba6f3bca, 0x43d88a3a, 0xae8c81ad, 0x9e747a46, + 0x8d7a6c19, 0x90b234be, 0x62d34c63, 0x46c5166a, 0x39e2f1f8, 0xef97420c, 0xa6ebb2dd, 0x9288a17c, 0xb72f690f, + 0x4e841141, 0xc1445f84, 0x4b9a5daf, 0x2fd649cc, 0x66cf10ec, 0x995d5f95, 0x8c432bca, 0xcb0f1e0f, 0x99f04a1b, + 0x5cf2a0d0, 0x6993d144, 0x661f1e8f, 0x00e76b6a, 0x5dc38c0f, 0x7a17eb6d, 0x1998abeb, 0xd390a265, 0x101fe557, + 0xc371a6f9, 0x1e709856, 0xffabf7fe, 0xa3a9973f, 0x9c2ff899, 0xd8fcbc58, 0x79f04a2c, 0x2d54529f, 0xd5bc8517, + 0x0aa0a55f, 0x81bc1318, 0xf4e78334, 0xdc842b6e, 0x481c2b2d, 0x3cbea61c, 0xc4f8a9e8, 0x7dcabc71, 0x2e0e55d9, + 0xe573c5b4, 0xe1497518, 0x0dc84dcc, 0xe4f638f5, 0x36daa4ec, 0x744f9ff2, 0x50399ac8, 0xe662c96b, 0x0d4277e6, + 0xb0aa3558, 0x946ac393, 0xe17956b9, 0xecae1d0c, 0x391bea36, 0xe4c13366, 0xe348641a, 0x8daca675, 0x8e332d8e, + 0xd4bd9f85, 0xeaa71224, 0x8a3900ff, 0x30c61fe0, 0x4895d297, 0x27affdca, 0xc20c585a, 0x4303af42, 0x927acc3b, + 0x67376595, 0xa084f3be, 0x012907c4, 0x6f9a6af7, 0xc6633020, 0x1e2bc30b, 0xa63a1196, 0x42fd5522, 0xae73ff91, + 0x8755dbef, 0x4d8ac1dd, 0xf597c119, 0x27dfc56a, 0x0fb9fd18, 0xbac68ef1, 0xd6afed34, 0xa1b3cd74, 0x6fb33ab0, + 0x5c72454b, 0x5b8405b7, 0xafbcd4ec, 0x3a2e13b5, 0xa62a1f85, 0x98364004, 0x42924ed2, 0x5d7408f3, 0x772904c1, + 0x6fbcd820, 0xc3e94414, 0x1bdef62e, 0x6b245e4d, 0xfd559621, 0x3bbbdfa5, 0xaa256463, 0x6647ad25, 0x32486223, + 0x2ca43110, 0x3c42f050, 0x47bbcf2c, 0xb57b58cf, 0xed935219, 0x938ce832, 0x6eceb9ed, 0xecab65fc, 0x97089e33, + 0xd969c2d0, 0x50a6e5c6, 0xb1a71397, 0x8dd5c98c, 0xd7e52947, 0xa11fb664, 0x99970615, 0xfd2bee29, 0xf7a61839, + 0x46499e62, 0xa4399d84, 0x0b381a1f, 0xba020db1, 0x3c785925, 0xfaf8c847, 0x541c0e12, 0x805d14e2, 0xe1850c30, + 0xe08f66bd, 0x8ce1bd61, 0x6cad310c, 0x682fcc5c, 0x085cc6f6, 0xaaae460b, 0x2c514000, 0x59d01f17, 0x2ac9a26c, + 0x5a55aa76, 0x4f4733ef, 0x47fef406, 0x41aee863, 0xe75f6460, 0xb5a56e9f, 0x8f4053cb, 0x9ad2c925, 0x98ac87b9, + 0xf0515544, 0x6a9dcc32, 0x7586c933, 0x78211f03, 0xd1a314f4, 0x502a63c1, 0xbec4c465, 0xba90179f, 0xada6268b, + 0x609c949c, 0x6c8a3427, 0xef0e1720, 0x41083b9b, 0x8f3da87a, 0x32154fd2, 0x0f1b1377, 0xce945662, 0x1a5406ef, + 0xcc26381f, 0x174371fe, 0x3d3dd5d6, 0x53ca96e9, 0xc5c50797, 0xd3b387f3, 0xe3d743dc, 0xce7ceb6d, 0x08c27668, + 0x04879d01, 0x460ae430, 0xb8cba93f, 0x3ec26cf3, 0x93c36450, 0x3e72f2c6, 0x71d57414, 0x21997e1b, 0xa08e2d17, + 0xcb4a439e, 0x3c705d2d, 0x3decb54a, 0x0374c52f, 0xbd2843d0, 0x2f176563, 0xce9069c2, 0x38399d82, 0x322adbd6, + 0x69d4b869, 0x29e62ca4, 0x7e7546f2, 0x55d9e41a, 0x9a19b073, 0x9395d32d, 0xaa711c2d, 0xfeee413e, 0xeaa8837f, + 0xa2a5f124, 0x76f65a42, 0x8f408ecf, 0x4ee995a0, 0xd50e0c2b, 0xb5d1912c, 0xa7546e5b, 0x68a35392, 0x590892ce, + 0xe7366e53, 0x8bbe0891, 0x98ef078d, 0x13d0d191, 0x65beb278, 0xf3670a91, 0x2c79024e, 0x136d4540, 0xf8245491, + 0xb948f4ba, 0x30f899e9, 0x5728c3e7, 0x7ef7d995, 0x30f77053, 0x0558febc, 0x242508fe, 0x99cf48fd, 0x66eaa7c7, + 0xedfa9de6, 0x7e0f5c18, 0x5d771121, 0xf5b82db7, 0xa0e429d7, 0x70cd4549, 0x0f3cbef2, 0x69bf8f0d, 0xf47dbf57, + 0x0ca3b928, 0xdc560291, 0xf93603c0, 0x93c6efc3, 0xa160327b, 0x500a3212, 0xca026269, 0x2baf86d7, 0x57373a10, + 0x43347c1a, 0xcc8f56ff, 0xf25f5b6b, 0x8593adae, 0x66dc339d, 0xc774fb14, 0xe5adced6, 0x287bda99, 0x0daaca38, + 0xe68cabe0, 0x379669af, 0x7d7e3878, 0x644a6fd8, 0x30d4c6d3, 0x0330d2a7, 0x60d6389c, 0xabaa502f, 0xa9a9a9e6, + 0x332d8753, 0x9d1eca94, 0xae9193f4, 0xde8cb580, 0x8908e402, 0xe51ffb64, 0x999c63b3, 0xfd617497, 0x05d4adb8, + 0xf9e9031f, 0x0f96d9b1, 0x1efedd55, 0x3539e07d, 0x02ca7918, 0x70bf53af, 0x55c1ea4a, 0xebbd6c23, 0xb0e7c56c, + 0x02407354, 0xd59fae07, 0x9a0e7707, 0x9faee3a4, 0xa9a04740, 0x398df47b, 0x458b95d6, 0xba7d39c7, 0x69b21e3d, + 0x7bd6b6a1, 0xba9ed5c1, 0x3de36cf2, 0x270da498, 0x362c08fc, 0x5e93cb4b, 0x1b874657, 0x54af067d, 0x80cf8b84, + 0x07b3f079, 0x8b78f266, 0x8060fb46, 0xd7138fc1, 0x3dcb1225, 0x74276fe1, 0x35c7ee86, 0x48a58acf, 0x9d4b83ce, + 0x95a15bfd, 0x0d70463d, 0x8daf6d69, 0xaccf4cb0, 0xac6524d4, 0xf01d5696, 0xfef5ad3b, 0x67b3f590, 0x527ca541, + 0xd7154d88, 0xb317fda7, 0x144e5da6, 0xeb9d8888, 0x0b87d22d, 0xa5a25056, 0x550f41e1, 0x13f14b96, 0xdadfd378, + 0xb461c309, 0xce54ef09, 0x628bdf09, 0x1a9fce69, 0x0e31aeb2, 0xa8e6ddd5, 0x9dffea7b, 0x67f2503d, 0xf0998fd3, + 0x53334557, 0x766875ad, 0xf6c524f3, 0x100418c6, 0x80c9fec8, 0xb89acab6, 0x6dd3b788, 0x63e733c5, 0x3873c22f, + 0xa9e3453a, 0x2593fb95, 0x35434968, 0x078da9a4, 0x777320c1, 0xa8f666d8, 0x89cdf324, 0xa0ff45e0, 0x5f2ff9cf, + 0x1669d4e0, 0xaac4d8f8, 0xf9c4427d, 0x925bb311, 0xd125e6db, 0x61077e1b, 0xce1a8041, 0xf42b2418, 0x19819557, + 0x67ca9f2e, 0xdc7efcee, 0x5fafee2b, 0x30e38299, 0x68b11bc4, 0xc87c629a, 0x7cfa493d, 0x2f92c9b8, 0x41874919, + 0x3c5daf5a, 0x321ae89e, 0x35ffd898, 0x5737a9d1, 0xb7e5a503, 0x584a71f3, 0x00f5efe4, 0x7a6856c5, 0x243a8b26, + 0x7e38efe7, 0x8f4cd2c8, 0x5d5c4dc0, 0x49eb0096, 0x717d2e06, 0x0f94759c, 0xc76b5fcb, 0x5e87c011, 0x65b39b41, + 0xbbe46cee, 0x10e6bd8e, 0x36cc3c7c, 0x0edf2409, 0xdfc45c97, 0x7f864545, 0x83531e05, 0x9dcda3d5, 0xfd139fb9, + 0xdba826de, 0xff22c1a3, 0x19037270, 0x3992d5d2, 0x88d0f8bf, 0xdb122b56, 0x0b3dfbfa, 0xc4f12a82, 0x6ab6213d, + 0xdcc4a566, 0x53211da4, 0x8d77d985, 0xd22fab5e, 0x0f795422, 0x3b23a060, 0xebb827f8, 0xb7741643, 0x69b44698, + 0x61ac5fa1, 0x63fc078f, 0xcda4ef6e, 0x6e36ec63, 0x5d978c8c, 0xc5b4aebf, 0xc978b1b0, 0x5b324351, 0x77c96f8e, + 0x890f275e, 0x3bfc5cd8, 0xf34b64df, 0x79e4e6df, 0xc515c0e6, 0xd3f87c5b, 0xadbd2a2c, 0xfca4f093, 0xba468fd8, + 0x793049f2, 0x0b2b3f36, 0x55e5064a, 0x5e6d414e, 0x571258e9, 0x2e8c19ba, 0xeccae93f, 0x70c7da5a, 0x323c636e, + 0xa392dc4c, 0xe1502de0, 0xa659424e, 0x075f3a8c, 0x079bfbab, 0xd139f9ee, 0xc9a3f3a4, 0x3ef73e49, 0x65f8882a, + 0x5c11b2e9, 0xd3c4a12c, 0x7182b037, 0xa9b045db, 0xf3d41e88, 0xfd646014, 0xce405494, 0x14a1c02c, 0x57f9706e, + 0xfe4cdd78, 0xdb1a56df, 0x8ba2dad3, 0xf87a02c3, 0xf1602e0d, 0xa6da06bf, 0x68b73af0, 0x07edfea1, 0x54ac362e, + 0x0b7fa743, 0x201bc12f, 0xa0ef68fe, 0xffd595fb, 0xc39a7b80, 0xe92dc372, 0xca2f3014, 0xce25d36a, 0x3bee1fad, + 0x433b899e, 0xbd03c34c, 0xaa20d8b8, 0xfa3cc39a, 0xaa186323, 0x045e2540, 0x8d51a03c, 0x89f1ebed, 0x926f12dc, + 0x6af80481, 0x2e5d4106, 0xda3cd6ac, 0x35aa0c22, 0xa2a9cd33, 0xbfb9f59d, 0xe5be7a26, 0xa89f9b56, 0xdb7d24c2, + 0x08e72259, 0xb8b587b4, 0x009952f1, 0x0c84cc70, 0x7543c48f, 0x005db3ac, 0x05bc0456, 0x5936869e, 0x6480184c, + 0x4294cffd, 0x6a13da09, 0xd0eac4a4, 0x472019c0, 0x1494d5c2, 0x6dfac15d, 0x77fb0907, 0x33ce55bf, 0x71bacd0d, + 0xcefd40ee, 0x5ae526fa, 0x7e41274c, 0x4bc718a7, 0x081247a9, 0xe6d4c22b, 0xa71410ec, 0x58b5060b, 0xc634d6ec, + 0x3415cdcf, 0x03d92ee6, 0xf8232ba0, 0xd7103111, 0x64521d81, 0xf211fe73, 0x59eddb7f, 0xba6c9a2b, 0x96745125, + 0x77f0e1e8, 0xea9511bd, 0x92cc0877, 0x81b9f02b, 0xc773ce5a, 0xde35c3ca, 0x312875c3, 0x4a644e84, 0x252a2ec9, + 0x8c68f47b, 0x01458907, 0xece5b212, 0x734c0e70, 0x58d790dd, 0xfee2af0c, 0xb83b5f7f, 0x5686bc3b, 0xa7cc4bc7, + 0xbb1d7b0a, 0x958443d6, 0x6640f243, 0x62199cff, 0x85675fba, 0xb7f57540, 0x71e34984, 0x0070d744, 0xc02eddd6, + 0x3801294e, 0x56f82390, 0xcf79ccce, 0xba804b2c, 0x67d04ffa, 0x4d0803ac, 0xc242923b, 0xd5b9ce87, 0x189f92ff, + 0xea7c501e, 0xe9424eac, 0x032aac5a, 0xf7e28b79, 0x2bcf9320, 0x41c117d3, 0xc9c5af5b, 0x611e333c, 0x58577ce9, + 0xed7ffd48, 0x65932ee0, 0xea38375b, 0xb62524cb, 0xa25b2a9e, 0xbcbcb236, 0x2829739f, 0xa726279b, 0x3a2a7cbb, + 0xf1f88c4a, 0x56a64009, 0x7ff05aad, 0xc5abfdbf, 0xf3077f31, 0x897a4f06, 0xe92cb0b6, 0x42e9c786, 0x87e24ce9, + 0xb5543f1d, 0xbd252e8e, 0xb73517e3, 0x27b5dda4, 0xd117e2c8, 0x97a5c47a, 0xf7067bb8, 0x5aa55e69, 0xa7a78e9b, + 0x79be586b, 0x44eb3feb, 0xf3d241d5, 0x1c8d504a, 0x01517b07, 0xfe7bb97d, 0xf52d07de, 0x05bda0c8, 0xbd598dd4, + 0xf03f8006, 0x8c190fc3, 0x008f5d78, 0x2ec70ff0, 0x19654336, 0x61be7850, 0xe2468138, 0xba64722f, 0x8d2b10c8, + 0xe350a236, 0x283bffc5, 0x4f1aed79, 0x5a1beab9, 0x30befbbd, 0x76f3e0a9, 0xd61534d7, 0xcbe36646, 0xb18133de, + 0x98f9c740, 0x430faf4a, 0xfbb70b73, 0x22e48a81, 0x43e6b117, 0x25c243ec, 0x9bbcc190, 0x301a5d67, 0x31d9b732, + 0x01085dd0, 0xca552431, 0xeb4ecf90, 0xef6d2902, 0x63a0950c, 0x6ffdda48, 0x7ae9ba90, 0xa2cd32dd, 0x145cd7cf, + 0xc3890c9a, 0x90bce844, 0xd94e2c3b, 0x533b0551, 0x9884ca03, 0x9e13bff7, 0xc6714b8b, 0x27ed409a, 0x79525871, + 0x42fbdac1, 0xafeaa2c7, 0xe18b6932, 0x4f7d1848, 0x43b37157, 0x5d8af7b2, 0x12540d78, 0x42580dbb, 0x241fd38a, + 0xa7eb52be, 0x0ea95b6d, 0x180a1d48, 0xf1f71cd6, 0xa39eae8e, 0x3da412be, 0x399453f7, 0x7da7769c, 0x4fc32641, + 0xd0b72ece, 0x2a979f87, 0x183878fa, 0x9346bd51, 0x73c836cb, 0xa2817a46, 0xcb380df6, 0x6b37c4c4, 0x2c1e645d, + 0xd800a51f, 0xbabad700, 0xd0c7ef72, 0xba62c9d9, 0xb4def6f9, 0x596bbb6d, 0xeb95046a, 0x330ddf2a, 0x44cff86e, + 0x2b8a527f, 0x34414075, 0xc5770753, 0x04bf64ac, 0x27295346, 0xa493d709, 0x17cc179a, 0x9d25b924, 0x9862b7f3, + 0x503449e3, 0xe9363f9a, 0x44ca2b63, 0xc7578ccf, 0x64a27ac5, 0x84bd8fc5, 0x7d44f1cf, 0xe15e48fd, 0xc5b36a9e, + 0x4875d366, 0xb1633ead, 0x8111fc14, 0x7aacd415, 0x74b9af32, 0x1d011f48, 0x829e131d, 0xcb782946, 0xb71876b6, + 0x0b3659ce, 0xc59140db, 0x5b746547, 0xe4b6b46d, 0x01951b9f, 0xde2c23e4, 0xf6cb80fa, 0x424e7298, 0x66fee481, + 0x20cd804e, 0x86f9b360, 0x14099e53, 0x5081dc5b, 0x70b0bd0d, 0x5c1401c7, 0x6dc8868a, 0xd14e87ec, 0x6127347e, + 0xfe3bc4d8, 0x6bef8539, 0x7c3194c3, 0x223c894f, 0x6714f56a, 0x96ec4886, 0xc5acd0c0, 0xb2c96584, 0x343d7fa6, + 0x6ba99556, 0xcbb48bf2, 0xfc2c3485, 0x80800778, 0xeba7b9d3, 0x3a30afde, 0x465fa90e, 0x6714944a, 0x76baacdf, + 0x02db6595, 0x2fe3547f, 0x3729e399, 0x74ad8d35, 0xe3a4a4e0, 0xf7bd8637, 0x94186302, 0xcef60cd1, 0xd8b7726e, + 0xfad26c8f, 0x3902e352, 0x8ea8871e, 0xc36025cb, 0xf184381e, 0x52dc7ce1, 0xa38666f1, 0x505d087e, 0x603df3ca, + 0x2bdb04e7, 0x8b893469, 0xbe782803, 0x932ebe4b, 0x36522dab, 0xc4aa2ec9, 0x52b8a65d, 0x4c30f589, 0xac7a822b, + 0x40f2088e, 0x1cb45840, 0xe5ca6ceb, 0xf48505eb, 0x945a3b66, 0x3f1d898a, 0xa04c1ed2, 0xc0273a53, 0x30412cb8, + 0x3d859e0f, 0xc226c7b0, 0x4311c779, 0xc33fc307, 0x6aaca797, 0x2df26dfc, 0xb4f11d81, 0xd350dab7, 0x6557c420, + 0x408cf507, 0x5a7a947b, 0x25c74896, 0x7c1df36e, 0x5984d0ee, 0xe536f4f4, 0x13eb0805, 0xa3a615e4, 0xdb411d92, + 0x8c4f5240, 0xb3fb0835, 0x81889744, 0x8b9d9def, 0xbf97acf7, 0xf493f3bd, 0xeb436ad7, 0x52e2d93f, 0x6d5dc7d2, + 0xc1d3136b, 0x3e239a15, 0x82b8c9f2, 0xee96fbd6, 0xc8a28b6a, 0x8ae80e6a, 0x481440ad, 0xa72e2ce6, 0x3c9b9a42, + 0xaa4e92a0, 0x7f5881d7, 0x59921f42, 0x88054d10, 0x2d22f63a, 0x6cf2fc6e, 0x3f289a63, 0x23e3c778, 0xa55309b9, + 0x7e1e80b7, 0xc14f8a9d, 0x6b93b377, 0x42102ef0, 0xe11ab68a, 0x4f5a44bc, 0xc0d303d2, 0x32c34126, 0x82e6f213, + 0x6ea3864a, 0x595c7a93, 0x9e6bed13, 0x87a7edc6, 0xa1a4c120, 0xcbf5e0f6, 0x14c6200d, 0x1bc1adec, 0xe3892e40, + 0x1e33ef6d, 0xe0b68e6f, 0x7d59c3a5, 0x42427f62, 0xa008c84e, 0x7e98291b, 0x4af91dc3, 0x73646ce8, 0x5eba2140, + 0xa9492bae, 0x8c977ffd, 0x45d2675f, 0x557bd37a, 0x2fcef0e9, 0xfb2a6782, 0x46ab030f, 0x609e9951, 0xc94ab1ec, + 0x303dc8d2, 0x02b26212, 0x68668e2c, 0xfadccb3d, 0xe697ec13, 0x587f1601, 0xdf797b6d, 0xf2f4b47e, 0xeb6f86f1, + 0xc8efaf00, 0xcb223019, 0xb2aa9844, 0xf715c5aa, 0x72370ce1, 0xbb739aa5, 0x590dcfd0, 0xd6ceb05f, 0xc35a02aa, + 0x60b742cc, 0xd47bb27d, 0x1dfac348, 0x68260cad, 0x38475e6f, 0xfd848892, 0x7d77d6d9, 0xe47d6217, 0x497765c3, + 0xdd9626ca, 0x98db9723, 0xe0a7bc61, 0x0a85edd3, 0xaf1cf078, 0xf583fdd1, 0x82a2332a, 0xc4cba90a, 0xcd39214c, + 0x725e7acb, 0xeb1f3e26, 0x8c4cf67d, 0x928b6b63, 0xd598001b, 0xc3f0a119, 0x58ad5da6, 0x75f463da, 0x588dfcee, + 0x295d78a2, 0xd7a2a6b5, 0x05f5a03c, 0xf79886a0, 0x76afdd47, 0x00a00138, 0xfe1774f5, 0xbc2fea14, 0x71480902, + 0x4f4fa2cb, 0x37983d13, 0x7f04fb43, 0x6f39745d, 0x23ee578b, 0x07dd1931, 0x64c5589d, 0xfeff2b8f, 0x09216836, + 0x420adb24, 0x0035d31e, 0x960df348, 0xf5f735ca, 0x4b12a919, 0xcd0040b7, 0xbdec818e, 0x2a271163, 0x5625fbb4, + 0xfedf55ca, 0x02110730, 0x58b8ea9b, 0x3bacbdc8, 0x1b16fb3a, 0x1857ce56, 0xf25f967f, 0x091accc4, 0xcd07de20, + 0x1a7ea4de, 0x609269bb, 0x7860286a, 0x6fb0e4e6, 0x7bbb4ebe, 0xdcd94aed, 0x88a9d6e4, 0x492127e8, 0x3117c592, + 0x8d0eba94, 0x46c6b2ae, 0x39510967, 0x9007f1e7, 0xb8a62f85, 0x01f438d6, 0x8090c0d2, 0x2bc62709, 0xbef651be, + 0x286a7d0f, 0xc09430b2, 0x8accaf11, 0xa9c37371, 0xb5949e5f, 0x0fcc3673, 0xc9380994, 0x0b4fbefb, 0x7d94b97f, + 0x7de2a330, 0xbf03ad13, 0xd74013a1, 0xc4f3b335, 0x1d52840d, 0x078f85fe, 0xa31e39ea, 0x5f3e907c, 0x60c8d9a7, + 0x1e277a26, 0x92602c70, 0x0b426392, 0x74d41e5d, 0x3627b418, 0x328d13b3, 0xb8432ed1, 0xe2d0806b, 0xeddaed1e, + 0x46a02c71, 0x29a321c5, 0x3cd7d6d3, 0x85eb09c9, 0x9a551c03, 0xc604c8a3, 0x6d7a8bb9, 0x83cf4754, 0x486339a8, + 0xb93b2323, 0xd98c5613, 0x9acbc531, 0xe66667bf, 0xbf54e54a, 0xdd75d492, 0x961e3775, 0xad9eafea, 0xd75dcd60, + 0xdd3f7db5, 0xf9a3b21b, 0xdec730b6, 0x0851f2d7, 0xd2e4fef7, 0x658504b5, 0xa6893bbf, 0x3bf3a5f5, 0xdf6e28fe, + 0xe16793b8, 0xe0bf5fa7, 0x57c8051c, 0xdc8c315f, 0x80d45439, 0x08a7a04f, 0x0122c8f4, 0xadde44af, 0x9aca2f84, + 0xa96af956, 0xf66aaa98, 0x87c82e86, 0xdc69b199, 0x5cee8cb5, 0xb2edb201, 0xff54fc91, 0xf3368031, 0xc0b39823, + 0x3c2675bd, 0xcf534c28, 0x44cdb9d6, 0xd892ea9b, 0x492724d7, 0x651ea225, 0xf9f72c77, 0x1daa5e90, 0x715408f7, + 0x2a69da36, 0x4a59619b, 0x01dcb4e0, 0x0601e096, 0x3488e54b, 0x75ee353d, 0x82b7ae78, 0xc47d12ee, 0x529d06f8, + 0x92d07f88, 0x7f471b6e, 0x3bbeab7a, 0x39807db2, 0x94824e9d, 0xc9e94219, 0x7a3168a8, 0xab4313bc, 0x9afb8e29, + 0x2e95885e, 0x5d9daf0b, 0x76e5018c, 0x19d96bd7, 0xf751a9af, 0x38f5a1f1, 0x85631108, 0x02b0ae01, 0x244a913a, + 0x4dc6c8d3, 0xaa8eef4f, 0xb44c077f, 0x824a1b79, 0xe35888ac, 0x7d86534d, 0xe52cf404, 0x6fdd7abe, 0xbee2d249, + 0x76299fe3, 0x35e3a244, 0x2383a89f, 0x46c4aff1, 0x09cad952, 0xe72dede0, 0x67e924d1, 0x223eb1be, 0x65d754d4, + 0xb0234f76, 0xe8a649d1, 0x55a8af30, 0xd2426b91, 0x8f97117d, 0x3d0173ef, 0xd84e4dc4, 0xb1b3dd05, 0x6fb4e710, + 0xad02ba62, 0x3ca1b057, 0x7018bbb3, 0xcf40c44d, 0xcbfb4410, 0x3ca5bbb5, 0xeee5651f, 0x0e161659, 0x0090cc4a, + 0xd351072f, 0xddad1cb8, 0xe8601d2e, 0xc05aa289, 0x5922ff92, 0xa6655b9b, 0x5fe4a1cd, 0x4aaeec06, 0x3131b354, + 0x41ae8051, 0x5e3eebda, 0x61bc03fc, 0xd42b009b, 0x6dde50c1, 0x678dd67b, 0x501627a0, 0x84921239, 0xd0d781d4, + 0x3ab98a50, 0xf29392a7, 0x5971cc93, 0xc6b5b8a4, 0xfb185003, 0x5b323513, 0x03196ec7, 0x45623f7d, 0x2b37ab87, + 0x2debf459, 0x2977860b, 0x46cbdb58, 0x5ce8cc8c, 0xaec790c8, 0x736f312e, 0x0a63aecf, 0x9e33da67, 0x3b9ff724, + 0x6f915be4, 0xcb734fce, 0xf1543239, 0xfd18d1b9, 0xf7162e81, 0xb3a90c76, 0xad917a9e, 0x1562501e, 0x5a9f9c5d, + 0x3104f1b7, 0x019cddbb, 0x8c287d17, 0xad617f99, 0xfa88b38e, 0x8b6c609d, 0x56c40754, 0xfa10401e, 0x85a69a6c, + 0x60392124, 0xc02ef463, 0x78c2416c, 0xa73f384c, 0x58dc6105, 0xf26a22d2, 0xb05b6619, 0x15cd1ff9, 0x03096d0e, + 0x3195c0ce, 0x89a0d56a, 0x4c4d269b, 0xdfc82745, 0x918b8495, 0xecc84bbe, 0x905d547c, 0xa2ed6362, 0xc2cee5ed, + 0x30216b6d, 0xd18e5124, 0xf4c6ab8b, 0xa9a327a5, 0xaca23b9e, 0x29fbd7ee, 0x175764da, 0x86efc26c, 0x825de26c, + 0x1c4fe78d, 0x283ce248, 0x4ac10c0c, 0x50bbf3fb, 0x029f6275, 0xe4fa99bf, 0x03e447f9, 0xb58fe8c4, 0xd3ff4b84, + 0x62ceb07a, 0x154821ec, 0x57acf840, 0x820ebc15, 0xdc3634b3, 0x5ded71c6, 0x50b7c917, 0xf45c8e44, 0xfa3d34f6, + 0xac3f72ec, 0x8cddaeba, 0x9fd76792, 0xe8f631cf, 0xec652ab1, 0x4f77b310, 0x8731f203, 0x9b1ca4d4, 0x66bc06b6, + 0xd7bf2a9f, 0xe85e9a7a, 0x3c4b23d9, 0x500c633c, 0xae4c3699, 0xcf603f66, 0x5516d253, 0xce9cb03d, 0x4e4e94ad, + 0x9a6c97c8, 0xf64195a2, 0x4654bfaa, 0xfafcb9b6, 0x19d8950e, 0x5b1e76db, 0xbd65ed3c, 0x9a7c9495, 0x6ae08520, + 0xc5e76655, 0xb8283a1b, 0xa99506f4, 0x9bad69ac, 0x88bd2344, 0xec8462d7, 0x2138c82b, 0xe481c196, 0xfd3f41cf, + 0xe94bae66, 0x5bcb5b13, 0x2898f120, 0x53bfc982, 0x08f986e4, 0xae207148, 0xc22bfc08, 0x8a5020ce, 0x9b58ea3e, + 0x6f72422e, 0xbbe61f89, 0x858581f6, 0xc7b1c6e9, 0x469fb2a8, 0xb4610534, 0x9d58f6fe, 0x26bf4649, 0xf315de28, + 0xcec0f753, 0xeab9d8cb, 0x080fef72, 0x3aeaa30b, 0x66d795c5, 0x4bfdeef1, 0xfc91af88, 0x39416dfd, 0x5bbf1404, + 0x42a017df, 0x68ed4aab, 0xe62ab313, 0x9e9225ef, 0x43f8c595, 0x23287a84, 0xa2eb5953, 0xb8127b33, 0xe77a570a, + 0xa44386f7, 0x29d11f1e, 0x9c790194, 0x3b591abd, 0xca34f643, 0x6d19bba4, 0x375d77f1, 0x0b251032, 0x1b9cad58, + 0x07f75a65, 0xe350bde0, 0x330d51db, 0x9ac02a7a, 0x93850dc4, 0x1c4e38c4, 0x4df16ab4, 0x4d0539b4, 0xbcd073a7, + 0xdedb7462, 0x9a1735f2, 0x3a270ddf, 0x6e84f448, 0xd43ff76b, 0x6c223839, 0xc0146552, 0xc26d2da5, 0x391cd6b5, + 0x366b271f, 0x5c7f49fa, 0x1535d991, 0x7b99ed3f, 0x1268bf4a, 0x8feb08f2, 0xb3147781, 0x73eef8ec, 0x9a3baa11, + 0x471b3d3e, 0x28e15300, 0x2cd29643, 0x7869b033, 0x8ee2e423, 0xeba17e0d, 0x1147e107, 0x10cd31dd, 0xf62b8269, + 0x770ed913, 0x37c9e6bd, 0x71d5a928, 0x534e3ef1, 0xac6f4f8e, 0x12e4986c, 0x0e980054, 0xd82a7b68, 0xa8b65319, + 0x0d789d69, 0x04ee8210, 0x5240cec3, 0x44cdf9eb, 0x3e9be0fc, 0x5b4a29f9, 0x63feb3f8, 0x9cfb2a6d, 0x8511a2af, + 0xa70f0dda, 0x3874ca42, 0x8c1e33ec, 0x5c198862, 0x5d3d2126, 0xca76ab0f, 0x4bcf0901, 0x34634fed, 0x5f2f50d0, + 0x0a62a4c8, 0xfa3f8f9a, 0x6838c4fa, 0x45bcf291, 0x33420971, 0x3b19032f, 0x5a78ab1b, 0x8a2a2d9c, 0xf6e42092, + 0xe932953d, 0x21440e30, 0xc80d9ac9, 0xf4e21c8b, 0x2e304404, 0xb0d8a528, 0x502ec2e0, 0xae02393c, 0x1a7f6fd3, + 0x284f7eae, 0x472e20b4, 0x566fd29b, 0x266e4ffb, 0x094113e4, 0xf89aa4fb, 0x4831b50b, 0xb10d2943, 0xdaaef780, + 0xbc6bddac, 0xb10a66e1, 0x1b4323d0, 0x4709e2e1, 0xb1c94599, 0x7602fe88, 0x6828bd9f, 0x9fe233f5, 0xe500a509, + 0xa3d5179b, 0x6781be15, 0x198b1ac4, 0xbb8d607b, 0x59c3b2c9, 0x640974e5, 0x1bec4641, 0x57bfbe8a, 0xb8ee6496, + 0xa70dc9fd, 0x2d2ef7fe, 0xc8f33ebb, 0x7354232d, 0xb499006a, 0x4753f8cf, 0xbf47144a, 0x15b0f955, 0x08c4d36b, + 0x8f24c18d, 0x86c613b7, 0xee941bc9, 0xe5a4e391, 0x4c14ca0e, 0x5760ddf4, 0xb79cf32b, 0xd3815126, 0xe07e1924, + 0xd7d8b2f7, 0xa607b6b8, 0x8644e7bc, 0xa2df704e, 0x12ef3958, 0xc6fdab8b, 0xeae25855, 0xa19cd609, 0x514b1c09, + 0x51f9fd39, 0xbc71de26, 0xc7be4c41, 0x99a05417, 0xbe634f4a, 0x615edc1b, 0x89f5df75, 0xd933cc15, 0xeda34c06, + 0xf83f96b8, 0x3a28e253, 0xd4d65669, 0x599587c6, 0xdb59fc44, 0xf610a652, 0x5ca01eba, 0x12c68171, 0x504165ce, + 0x1034ca59, 0x69a94ef8, 0xe810b073, 0x3d832886, 0x516e34aa, 0xd729fa0a, 0xe22f63aa, 0xae8bcb90, 0xf4965962, + 0x1750148f, 0x649c4ff7, 0x4417a2ae, 0x574d8c5d, 0xee6368e4, 0x251f2f44, 0x77e9bb1d, 0x4801f2b1, 0x077c927c, + 0x77bda395, 0xb08a6b4c, 0x6c52e0ca, 0x60e769d9, 0xf619855e, 0x7c7652a6, 0xc47a2d6e, 0xf04f973a, 0x9f572aad, + 0xedc49347, 0x8eeea5fa, 0xcfc7b7d5, 0x18d29c3d, 0xfdfdf3c9, 0xd209381c, 0xddfc4ee5, 0x1585dfe1, 0x2859f52c, + 0xd70869fd, 0xd6d6a175, 0xdfe4dec4, 0x0a21b1b5, 0xcfae9b8d, 0x921eb7ad, 0xc9020997, 0x73b44e46, 0xa3bce24a, + 0x3bbbb9b8, 0x4ea918e2, 0x16288893, 0xec331eaa, 0x3ddeea11, 0x6b22a45a, 0x178f2200, 0x543fbbbb, 0x90c223ba, + 0xc167a255, 0x968b52c7, 0x237b45f4, 0x39c9679a, 0x12d07be7, 0xcff443f2, 0x3de08c70, 0xf9eb46bf, 0xecd3696f, + 0xccdd0312, 0x510fd99c, 0x7b075ce5, 0xf2d5972c, 0x13b1a565, 0x647f4407, 0x3dda1c52, 0x0db195b0, 0x2b2f8eff, + 0xfa137377, 0x6caedd85, 0x8fe097e1, 0x10ac8564, 0x72981d2a, 0x08801390, 0x0e3f1ef3, 0x7108f544, 0x6633d426, + 0xc4bd651b, 0x7d06da4d, 0xbc1d9a63, 0x90a067d5, 0x9a7df559, 0x1d0a11b7, 0x1e5da7f3, 0x29fc2c9b, 0xaf70f7dc, + 0xe41b41fd, 0xab9624c3, 0x5d75b435, 0x002621ae, 0x7a9b9919, 0xa33b4861, 0x27d3f2cc, 0x9dd5a907, 0x065640c3, + 0x07086a7c, 0x6ad3c7e8, 0xda61d0fd, 0x997065cc, 0x7ef2b121, 0xeb787574, 0x4d335fd6, 0x32924acd, 0x7a9b34e4, + 0xb141aab8, 0x142c608c, 0x6da52db7, 0x38f48141, 0x3e8c6aa0, 0xb8096c4f, 0x7b861d61, 0xa60fd6b3, 0xc64e4612, + 0x0df0efb5, 0x82a2098c, 0xf58f70cf, 0x090f9316, 0x7adc0c57, 0x89c80d7a, 0x98379e82, 0x07627449, 0xba249bde, + 0xe4071277, 0x335b6e37, 0x10197c05, 0x9806fcf3, 0xd419c50c, 0xa924d154, 0x686a0968, 0x1d4b2dce, 0x5f21ba32, + 0x22a288ce, 0xd46494a9, 0xcacd96f7, 0xd4fb0ef8, 0xb52990ff, 0x4328b4a4, 0xd53e43d5, 0xe17e01ab, 0x22c5f729, + 0xee0e806e, 0xaea91ce4, 0xc9368cf1, 0x3298a441, 0xada607d5, 0x0ce64ea4, 0xb039ee8a, 0xc624916d, 0xce3cb963, + 0x6a21afd7, 0x8bf96410, 0x4618d43b, 0x7def1c9e, 0xcbec3e7e, 0x2fd1e025, 0x87d93d6b, 0x0ff5f5d8, 0x7c21d0d1, + 0xf5ec1657, 0xf4c2190b, 0x2eb3b608, 0x08745f07, 0x6ebf3462, 0xe421705c, 0xe86372f3, 0x49adf1da, 0x5aecc162, + 0x671d0028, 0x1ebbda45, 0xd6d010cc, 0xf5395b97, 0x21df6419, 0x2d4b3d3a, 0x6ad03908, 0x81931219, 0xff65858c, + 0x8e78697d, 0xa9ff5ca6, 0xf2e609c5, 0xccf21be7, 0x83966dfd, 0x8a3cc868, 0x39233e2a, 0xc8902098, 0x69c98dca, + 0xe3ef8e7c, 0xa163b614, 0x14d2a62a, 0xc2c5c281, 0x6cc9b9d8, 0x1062064c, 0x6040cfcc, 0xf92fc8f3, 0xb802811e, + 0xdf2af1db, 0xe8e6f840, 0x1f4ca9cf, 0x6ba56df1, 0xd0ca8462, 0xe37139a6, 0x2fa37f0e, 0x522fb55f, 0xf73269ef, + 0x0a3d8ca8, 0xf16a0a01, 0x1802107c, 0xb4439056, 0x4b0a451d, 0x89ea2c4c, 0xa129618b, 0xceebbdb8, 0x4538462f, + 0x0f0245f3, 0xba48bd00, 0xc35b8aec, 0x87486b26, 0x046413a7, 0x82f0e45f, 0x030c82f6, 0xc8863f3b, 0x5e477d1d, + 0x9c146856, 0x13e2206d, 0x13bf11d4, 0x2be3908f, 0x7a4a1945, 0x1ac7ca96, 0x0c83535e, 0x7390f976, 0x2f2daefb, + 0xf0d7a92d, 0x9fb3f3c2, 0xe1c6de32, 0x834e151b, 0x69ae51f8, 0x4ced1563, 0xec6fb8a2, 0xff68a14c, 0xdc0bf8fb, + 0x01e1bd7b, 0xbc687394, 0x40c2f545, 0xe8af3002, 0xd37a3c35, 0xe7ab8da4, 0xd2096256, 0x838d60da, 0x5e44811f, + 0xe67a6484, 0x272eba23, 0x34568289, 0xe665c623, 0x28e32ebb, 0x380e31e2, 0xec66fa5f, 0x9326ce9d, 0x5d566645, + 0xe60c3eb5, 0x521e1756, 0x5480e735, 0x07b7f520, 0x344470f7, 0xbad01966, 0x435288a1, 0x1b8e3bd3, 0x840bfffc, + 0x06e4073f, 0x5ab23cde, 0xdb0482be, 0xf53e30d1, 0x51d5640e, 0xb5572dcb, 0xad565df8, 0xe60e26c9, 0x03368102, + 0x239bd1df, 0x80cff272, 0x9640352c, 0xa13d9d05, 0xf2e59975, 0x6eb89c1a, 0x081fc914, 0x5fd76af5, 0xb420cc67, + 0xd3941e78, 0x1ad61f76, 0x8fc02d0e, 0xece7be6e, 0x7e13393c, 0xeea6da04, 0xa4a3d76e, 0x3648ad17, 0x8aef288e, + 0xa1ce51e4, 0x64a93a93, 0xfd2f5089, 0x599bac3a, 0x8d3a0170, 0xf8b3cd30, 0x89ab7843, 0x1d3e5db8, 0x06cbb16a, + 0xd28952d2, 0xca284893, 0x8fd1a1e1, 0xecc8aa4d, 0x465de563, 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, + 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, + 0x9e794663, 0xecda4063, 0x4f3c615e, 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, + 0x5bee2390, 0x5bb0ac2d, 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, + 0xcbc03381, 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, 0x5e365ae5, + 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, 0x1da22f3d, 0xbde1988d, + 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, 0xc654b0f4, 0xb3c61edb, 0x34380acf, + 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, + 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, + 0x6ca12b76, 0xca9e521a, 0x3de6ed99, 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, + 0xe3860943, 0xf1f3f4e7, 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, + 0x401dd9b2, 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, 0x9c7c7cab, + 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, 0x68fd2cdb, 0x5b325dc5, + 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, 0xdfeceee9, 0xeff255fc, 0xfc97bd59, + 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, + 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, + 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, + 0x19026be2, 0x106a090e, 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, + 0xfd1119a3, 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, 0x2e43d2db, + 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, 0x24996054, 0xe5fd7518, + 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, 0x19490a6e, 0xbfcc1617, 0x967882fc, + 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, + 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, + 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, + 0x071ae0e6, 0xc3c8d053, 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, + 0x3678e185, 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, 0xb67c5819, + 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, 0xc2222ef2, 0x5a046246, + 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, 0x54a3bc82, 0x5706694c, 0x4664f6db, + 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, + 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, + 0xce8f27be, 0x5a559021, 0x9b1740dd, 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, + 0xe9952168, 0xdc81cac7, 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, + 0xb58b5c72, 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, 0xd99e6ac7, + 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, 0x3635a87c, 0xcee78062, + 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, + 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, + 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, + 0x384ad656, 0x9d824935, 0xec915f03, 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, + 0x4064fbb5, 0x66ad961a, 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, + 0xdbe24543, 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, 0xcadaf946, + 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, 0x628675d3, 0x6b1d569f, + 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, + 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, + 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, + 0x8d3c9334, 0xe5c6c529, 0x20e898db, 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, + 0x0d748033, 0xecc5393a, 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, + 0xf35661c3, 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, 0x5d2efdf7, + 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, 0x69c800e0, 0x5d310e80, + 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, 0xe9811969, 0xc08a7628, 0xe5e44555, + 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, + 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, + 0x80082d96, 0xb5a06d54, 0x1612537d, 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, + 0xf2fac0cc, 0x737aeb61, 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, + 0xaa36609d, 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, 0x0c2f32bc, + 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, 0x6a6777dd, 0xa7029cb3, + 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, 0x59ebc41f, 0x7e55932d, 0xcf78bead, + 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, + 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, + 0xc99944ec, 0x5289e5ff, 0xd64dd767, 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, + 0x4cf9307b, 0x1b6533fa, 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, + 0xe854ce92, 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, 0x408694a5, + 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, 0x24ed6723, 0x0c24fa00, + 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, 0x7db55eaf, 0x0fa8aabb, 0x0e942194, + 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, + 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, + 0x0350d608, 0x54e77f30, 0x866c2575, 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, + 0x3bf7c1bd, 0x5762abb7, 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, + 0xa9a36bdc, 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, 0x5b171723, + 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, 0xe66188ab, 0x4d2b635b, + 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, + 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, + 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, + 0xa31e8408, 0xac80b477, 0x7e7ddefc, 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, + 0x22eb7378, 0x08773858, 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, + 0x65c5fac3, 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, 0x7b9de18a, + 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, 0x804275c8, 0x6ff502be, + 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, 0xf65056f7, 0x18393ab3, 0xbf8c8b96, + 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, + 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, + 0x9685fd96, 0xc354066f, 0x9cdbc452, 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, + 0x328dfdbe, 0x7d168a67, 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, + 0x5fd2e5d7, 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, 0x3fb91263, + 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, 0xca097d3e, 0xa90c478f, + 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, + 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, + 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, + 0x4b823e48, 0x581b2420, 0x4ff2d70c, 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, + 0x476626bc, 0xad5c9d4c, 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, + 0x766880ca, 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, 0x89eac33c, + 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, 0x4eb31945, 0xf2c5d93b, + 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, 0x793fdc45, 0x519a1c15, 0xe31ee96d, + 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, + 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, + 0xd036e501, 0x0cb814a8, 0x06b9ab5d, 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, + 0x9284b162, 0x2cd5b7ab, 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, + 0x6ba484fe, 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, 0xdd4c9f22, + 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, 0x7143f3bb, 0x540b1347, + 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, 0xb2874627, 0x7f0c9a4a, 0xf8106eae, + 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, + 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, + 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, + 0x15aa0461, 0x1bc775e8, 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, + 0x68377d59, 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, 0x90689424, + 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, 0x362b4809, 0xec92588b, + 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, 0x32a14d01, 0xf4f6fec4, 0xada9360c, + 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, + 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, + 0x86428407, 0x45d6c023, 0xc77ebdeb, 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, + 0xf8198b68, 0x881246e7, 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, + 0x9e82681e, 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, 0x2d42e033, + 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, 0x0d1c971e, 0xe7795114, + 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, 0xb31d23cd, 0x8102d36d, 0x51aeed2d, + 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, + 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, + 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, + 0xbd3d8fa0, 0xe798d010, 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, + 0xa956eb79, 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, 0x723065f1, + 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, 0xac794782, 0x002064e9, + 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, 0x344f1195, 0xa7181920, 0xd05fcfd2, + 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, + 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, + 0xb75639f1, 0xadc76771, 0xd3543fd5, 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, + 0x6c95fd6a, 0xc3bb4a03, 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, + 0x045c945f, 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, 0x5acd89f8, + 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, 0x353f926c, 0xe3471231, + 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, 0xd16e5090, 0x9eff66f3, 0xa35ee078, + 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, + 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, + 0xc4062fef, 0x2bd3b757, 0xcbd45594, 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, + 0x2857a67c, 0xce5b2c90, 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, + 0xcd439cd3, 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, 0xbb20e7d2, + 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, 0xee542f36, 0xb0807f6e, + 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, 0x5104928d, 0x047c150a, 0x328cc000, + 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, + 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, + 0xcd61b411, 0xfddd923d, 0x638d0e61, 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, + 0x6bef47aa, 0xf460b130, 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, + 0xdfe4f729, 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, 0x55d094ff, + 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, 0x3161690b, 0x3ffa1fcd, + 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, 0x8a41bcac, 0x38d2f20e, 0x9aac541c, + 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, + 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, + 0x54705c7e, 0xba150347, 0xa80514ec, 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, + 0x7ce59906, 0x577da8f1, 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, + 0xd28382ff, 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, 0xb7bc9a79, + 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, 0xcc0be43f, 0xa606a522, + 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, 0xea4a38b5, 0x76901b4b, 0xe2583ac7, + 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, + 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, + 0x0cfe6db5, 0x5accdc39, 0x3377eaed, 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, + 0xc8bd6a8f, 0x625a6215, 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, + 0xae81db75, 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, 0xfee25664, + 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, 0x8bb3653b, 0x026eedbb, + 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, 0xb5bcee42, 0x6db10b43, 0x9fec55e3, + 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, + 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, + 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, + 0x429e2dc7, 0xc309b30a, 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, + 0x7874b53c, 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, 0xb92b80c7, + 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, 0x3326a1a1, 0x78b01e6e, + 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, + 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, + 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, + 0xc687b587, 0x383f7c40, 0x54830d04, 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, + 0xbf32f0c7, 0x2a796a67, 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, + 0xfd0367d1, 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, 0xc0e35390, + 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, 0xa32b3c81, 0x1d02d66b, + 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, 0x456c5876, 0x4c7a1f7d, 0x8210e535, + 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, + 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, + 0x03826132, 0xf505a1c5, 0x5536b8f5, 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, + 0x743d2b0d, 0xa82aed8d, 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, + 0xafef4d80, 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, 0x6b311848, + 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, 0x129d80fd, 0x18982768, + 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, + 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, + 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, + 0xeaac07b5, 0x0a377949, 0xcea56fc5, 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, + 0x65e46fe0, 0x9a5df9f9, 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, + 0x8358ab8c, 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, 0xdc18fabe, + 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, 0xd48cbb77, 0xcffdb7b0, + 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, 0x8ac94023, 0x11efd6fa, 0x5a6574f0, + 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, + 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, + 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, + 0x743b1a4d, 0xcd7ff202, 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, + 0x18060bb0, 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, 0x4bdc887f, + 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, 0x58f5a07b, 0x3c0266e5, + 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, + 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, + 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, + 0xbbff8af7, 0xaab1617c, 0x596a01d9, 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, + 0xd980aa05, 0x9269bb19, 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, + 0x298eb742, 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, 0x27fd3816, + 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, 0x2ae780c3, 0x7374f385, + 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, + 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, + 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, + 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, + 0xc19f5cac, 0x0bed2aa4, 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, + 0x783cfc66, 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, 0x1628b35c, + 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, 0xb361da26, 0xc0e2aa6b, + 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, 0x10f2492f, 0x231be0f1, 0x2b6fc840, + 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, + 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, + 0x7f6ace2b, 0x21514ebb, 0xc46d4800, 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, + 0xaf2ba637, 0xc4063ea0, 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, + 0xf942657f, 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, 0xea694198, + 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, 0xb453ee10, 0xafe27498, + 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, 0xbb74e075, 0x4408ab02, 0x2eae958a, + 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, + 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, + 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, + 0xfc5ff382, 0xc25ae007, 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, + 0xca5e1ee1, 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, 0x27c57f08, + 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, 0x86952278, 0x2810740c, + 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, 0xabc1d828, 0x05b673a5, 0x93e0c5ce, + 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, + 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, + 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, + 0x9d268a7e, 0x0485322e, 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, + 0x4f7b98f0, 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, 0x9161c085, + 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, 0xd6243501, 0x50f99e78, + 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, 0xe7888474, 0x58967c61, 0x9c2344d8, + 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, + 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, + 0x4a543dd4, 0x72d27f50, 0x794b2c38, 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, + 0xde3dfa58, 0xeac4977f, 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, + 0x4e87a4a4, 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, 0x829272a4, + 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, 0x508ed11e, 0x34f13455, + 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, 0xd435af57, 0x3e86d270, 0x7f04d0f2, + 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, + 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, + 0xfc49bc3d, 0x55757973, 0x84149ef8, 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, + 0xa17f53c4, 0x882c2967, 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, + 0xb340d658, 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, 0x76c9e6a2, + 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, 0xcc17d17e, 0xc52d9ae0, + 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, 0xad9625b4, 0xdbb45f5b, 0xf707fbea, + 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, + 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, + 0x6107a718, 0x83643c4c, 0xf2f96503, 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, + 0x41397ea1, 0x5793b309, 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, + 0x30ed4df8, 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, 0x9e264e70, + 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, 0x3f767c6f, 0xd1c48bab, + 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, 0x50da0980, 0xac96ecf6, 0x008c4910, + 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, + 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, + 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, + 0x49a844d0, 0xbbf5495f, 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, + 0xc41a3c1d, 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, 0xdea90048, + 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, 0xb709b9fe, 0x4549aaea, + 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, + 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, + 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, + 0x17a388b9, 0x78038049, 0xc505ab47, 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, + 0x7e6727d2, 0x9cef5fce, 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, + 0x88bb5013, 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, 0x17261a8e, + 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, 0xf480ab6d, 0x39525194, + 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, 0xdfb74aec, 0x62aae2f0, 0x46b855b3, + 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, + 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, + 0xe260be49, 0x18b01f3b, 0x0a2fc30f, 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, + 0xfb85d9ea, 0x2ddace97, 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, + 0x8c823cb1, 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, 0xf22f9ccd, + 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, 0x769e9c28, 0x65f8905d, + 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, 0x631f0974, 0x3f48dae6, 0x025739cd, + 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, + 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, + 0x5113ea88, 0x72ef2942, 0xd4aa0766, 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, + 0x74798f9c, 0x35e96814, 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, + 0x5ddb2efb, 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, 0xf4ab5191, + 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, 0x88a6c986, 0xdb0e7bbb, + 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, 0x0baad5bf, 0xaed19942, 0x66e4b053, + 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, + 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, + 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, + 0x34268b83, 0xe4bb7d3a, 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, + 0xac836a26, 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, 0xec264fe5, + 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, 0x381f32a7, 0x20a5e8c0, + 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, 0x15470bc2, 0x9ef31ae9, 0xd9e26951, + 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, + 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, + 0x2bf519ed, 0xf57860ea, 0xd69ba992, 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, + 0xccfc8b54, 0x58a93087, 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, + 0x60d94733, 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, 0x8ae04ca7, + 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, 0xca2f0fa1, 0xaac2e3bb, + 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, + 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, + 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, + 0x07796220, 0x0f0f8722, 0xbd6092dd, 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, + 0x17862bac, 0x610b9ce2, 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, + 0xcf3f6b27, 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, 0xff007778, + 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, 0x15a2c929, 0x9263b116, + 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, 0x187b9976, 0xf5ea2689, 0x87e3b151, + 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, + 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, + 0xbaa41197, 0xe5dcc72c, 0xaf16a669, 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, + 0x257e15c8, 0x12fbc35b, 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, + 0x4f1906d3, 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, 0x6d7b3b88, + 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, 0xfc5fbfed, 0x18db2aa6, + 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, 0x4429b1aa, 0x838682ab, 0x5bdfd86b, + 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, + 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, + 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, + 0x5e68e36b, 0x838322dc, 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, + 0xed6bf807, 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, 0xfb7507a4, + 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, 0x532e6654, 0x0c528786, + 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, 0x230b4319, 0xdd780574, 0x58889d79, + 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, + 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, + 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, + 0x73e830ce, 0xb353b81d, 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, + 0xe7929941, 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, 0x45da675f, + 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, 0x52a33502, 0x7d4b918c, + 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, 0x4b0a5e47, 0xce55bc17, 0x09656fd6, + 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, + 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, + 0xfe627e5d, 0x791daf5e, 0x50943665, 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, + 0x3e6a0f21, 0x9dad2288, 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, + 0x72f16cfc, 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, 0x86de5619, + 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, 0x06add0d4, 0xd0c462c6, + 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, 0x494f49bb, 0xcd7f90a5, 0xb6709e40, + 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, + 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, + 0x9bafb81d, 0x62e53468, 0x86ec692b, 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, + 0x8d6632f1, 0x8ba05667, 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, + 0xcfad36f8, 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, 0x526af581, + 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, 0xdea23b22, 0x9f8c78c5, + 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, 0x8d801702, 0x98d2fe2d, 0x3ed6b821, + 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, + 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, + 0xb2ccc077, 0x6162fefd, 0xb3701463, 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, + 0xeabc4ede, 0x82191ff8, 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, + 0x3e457dab, 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, 0x5ecc278f, + 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, 0x0862a010, 0xb3c9a772, + 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, 0xed37dba7, 0x26112057, 0x68c688f2, + 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, + 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, + 0x67c335d0, 0x6981f384, 0x6ca54c87, 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, + 0xf5315cf0, 0x995fb40e, 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, + 0xa571dfbf, 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, 0x1ce39a6b, + 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, 0x33a6d8b3, 0xd9101e64, + 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, 0x13eb0f7c, 0x77b31835, 0x65c53459, + 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, + 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, + 0x0e5f8848, 0xd61ad101, 0xf44c42a4, 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, + 0xd37d5397, 0xeada6952, 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, + 0xfea92813, 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, 0xded23976, + 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, 0x881ccb9e, 0xa1bb6a8d, + 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, 0xe19a859f, 0xfb877d69, 0xc91faf5e, + 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, + 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, + 0xd5e24aec, 0x6731d1b3, 0x48ebc226, 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, + 0x18281991, 0x42588569, 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, + 0x915978fc, 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, 0x4a5faf73, + 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, 0x477d5c34, 0xe2ef3d70, + 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, 0x6db3425d, 0xce451d6f, 0x6f2a53e9, + 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, + 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, + 0x0365098d, 0x013e15ad, 0xc990d5f4, 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, + 0xed216f9a, 0xcb714de5, 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, + 0xf602de55, 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, 0x99029b50, + 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, 0xbd2995e9, 0xd906ec04, + 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, 0xb921c72a, 0x9fc5a234, 0x55d0fbec, + 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, + 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, + 0x84b6ab49, 0x5b3c6835, 0x0015afb6, 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, + 0x89cc97bc, 0x713d3b24, 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, + 0x86363b5f, 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, 0x7368089c, + 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, 0xe516c9a0, 0xeab5aa5d, + 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, 0x614782cd, 0xce169d44, 0x6433de5e, + 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, + 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, + 0xc0ac7573, 0xca381e11, 0xfc5916b6, 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, + 0x332f9714, 0xa3804fc5, 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, + 0x37552b9e, 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, 0xe9b11f94, + 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, 0xcfed5315, 0x27f4a06d, + 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, + 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, + 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, + 0x3c9c2d05, 0x6794edd6, 0xc22cc352, 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, + 0xc045f697, 0xfd090038, 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, + 0x36ae74e4, 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, 0xd85611c1, + 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, 0xb326cc47, 0xe0faa978, + 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, 0xb77eda67, 0xc49052e6, 0xc514a075, + 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, + 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, + 0xf28a6231, 0x9eaa4f64, 0xe9468748, 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, + 0xd8eae4af, 0x46876f0b, 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, + 0xd1daf994, 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, 0x5389bce5, + 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, 0x62a8e0a5, 0x200442ca, + 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, + 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, + 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, + 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, + 0x29bc2f91, 0xac5eaa62, 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, + 0x8bc6cf4f, 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, 0x6bbb33dd, + 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, 0xf708838e, 0x2caf050b, + 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, + 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, + 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, + 0x6746103e, 0xa0eff544, 0x0bba778a, 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, + 0xf1ee2d08, 0x1b100e82, 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, + 0x7ea8c2c3, 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, 0xd1d5c2c0, + 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, 0x5ce3fa8a, 0x2075b595, + 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, 0xdb4a2241, 0x806460ec, 0x183637f9, + 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, + 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, + 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, + 0x724a1e6a, 0x1f49fcfc, 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, + 0xf8481f7d, 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, 0xc548731c, + 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, 0x92d1c238, 0x59503c44, + 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, 0x82172a29, 0x5db3569b, 0x6a0ab6f7, + 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, + 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, + 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, + 0xc2110048, 0xef4c9825, 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, + 0x3d923162, 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, 0xaddd3c63, + 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, 0x20d00302, 0x0718e1f1, + 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, 0xb6747958, 0x6bcb60f5, 0xbce4158b, + 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, + 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, + 0x436ca416, 0x0091a7da, 0xe705853a, 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, + 0x99f5e336, 0x67e6d388, 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, + 0x20fa88af, 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, 0xdeb5cc9a, + 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, 0x112a8ec2, 0x385e89a8, + 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, 0x0c60638a, 0x0c83492d, 0x95d61b20, + 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, + 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, + 0x50f5b110, 0x0c23b119, 0xbc27c7e8, 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, + 0xd1b98d82, 0x632df3e2, 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, + 0xe98733e0, 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, 0x75257595, + 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, 0xf12a2f87, 0x900624fa, + 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, 0xf3be72c7, 0x01ca0052, 0xdf927440, + 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, + 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, + 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, + 0xc226cc77, 0x294e0e4e, 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, + 0xd0489c01, 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, 0x5d6bc3c2, + 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, 0x0c117533, 0x0b70ddeb, + 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, + 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, + 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, + 0x4cd711a6, 0xc46a6a58, 0x2d82b595, 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, + 0x9920ac09, 0x02db13ae, 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, + 0x108cdb88, 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, 0x2944706d, + 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, 0x8ee22fc9, 0x9970baae, + 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, 0x253d5795, 0xa8e3738b, 0x9770975d, + 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, + 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, + 0xacabe801, 0x47952193, 0xd3138e94, 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, + 0x68161660, 0x6365afcf, 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, + 0x96847976, 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, 0xedabeffe, + 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, 0x25d6ba47, 0xec63d289, + 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, 0x671596a0, 0xa08b6a5b, 0x0bca7779, + 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, + 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, + 0x9e283138, 0xb2631843, 0x8c9d46d6, 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, + 0xa4fa2f87, 0x472f5be5, 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, + 0x6fba83bf, 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, 0x7d4f1ea5, + 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, 0x9b0b0ade, 0x6373a3b0, + 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, 0x4c9ca5fd, 0x7f1f3313, 0x30013306, + 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, + 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, + 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, + 0xbed76d66, 0xf5b960da, 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, + 0xad500497, 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, 0xef6e61d8, + 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, 0x4ed7b964, 0xff1f6c98, + 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, + 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, + 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, + 0xbbdb8c62, 0xf6dd386b, 0xe3358787, 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, + 0xce5af4fb, 0x712564e1, 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, + 0x66f6d4a7, 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, 0x499c86a6, + 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, 0xc94b8391, 0x7bd8e512, + 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, 0x449df40e, 0x93f035f8, 0xafd2521a, + 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, + 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, + 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, + 0xf9621d42, 0x77ee21f3, 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, + 0x45317e93, 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, 0x080f5133, + 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, 0xf8ab5684, 0xbd3b8b9a, + 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, 0x428761dc, 0x97459150, 0x709e0a12, + 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, + 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, + 0xac7d020e, 0xa7bf5312, 0x4c6834b7, 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, + 0x03f9e743, 0x3004dfb0, 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, + 0x9ad90bde, 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, 0xa1fc99fe, + 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, 0xfd35ccf2, 0xd2473bb9, + 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, 0x32e8b9f2, 0x103ef0a9, 0x1888642e, + 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, + 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, + 0x8ec2282a, 0x146232d5, 0xf4241f66, 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, + 0x2d03e06e, 0x305c322c, 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, + 0x2c33b686, 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, 0xa9d0de99, + 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, 0xce93f4cd, 0x822382ec, + 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, + 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, + 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, + 0xc83c381c, 0x098d5293, 0xc0738c93, 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, + 0x359fc239, 0x806328f8, 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, + 0x7d0cf9c7, 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, 0x356f9c19, + 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, 0x96e32fe0, 0x142e5994, + 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, 0x702f1422, 0x4008e264, 0xbbf91d05, + 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, + 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, + 0xa6b29bb4, 0x67777742, 0x65b6542c, 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, + 0x86507fb1, 0x26f76111, 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, + 0x658bb0c8, 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, 0x685d4d9a, + 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, 0x30d5acc3, 0x18d236ab, + 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, + 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, + 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, + 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, + 0x37160e0f, 0x9f623018, 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, + 0x99b0115b, 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, 0xc7d5de52, + 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, 0xf080b017, 0x4da4d290, + 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, + 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, + 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, + 0x0d628e03, 0x4a93cdd8, 0x6f643479, 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, + 0x1983f603, 0xd4591b19, 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, + 0x3488b648, 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, 0xde17a435, + 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, 0xc4706c3f, 0xdf14d9ab, + 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, + 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, + 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, + 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, + 0xb8c941ca, 0xe26b9187, 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, + 0x0bbe4840, 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, 0x7fa40f5f, + 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, 0x611a0f89, 0x3a0e5f8a, + 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, 0x01079381, 0xc250fa30, 0xead64afb, + 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, + 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, + 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, + 0xe5b8b32e, 0x9c6261e3, 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, + 0x8f854e38, 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, 0xa8e1a4e5, + 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, 0xff46bbb2, 0xa38e83bd, + 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, 0x6a145a5c, 0x6a41add1, 0xd954c1f0, + 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, + 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, + 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, + 0x5eba32d0, 0x3cc4a69c, 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, + 0xc8013642, 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, 0xe9e313b3, + 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, 0xef679615, 0xc074d215, + 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, + 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, + 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, + 0x208a0b6f, 0x7245f138, 0x352dee4f, 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, + 0x46fc92f6, 0xfcfa9de2, 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, + 0xa44da7f3, 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, 0x35818ebe, + 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, 0x3a03b930, 0x868b0e63, + 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, 0x4d72927a, 0x1b62ae8f, 0xef765353, + 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, + 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, + 0x83b4c653, 0xfd8585e4, 0x23af00e8, 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, + 0x822679ff, 0x695356ac, 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, + 0x9a82734d, 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, 0xccf76bc6, + 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, 0x0e3e6c5f, 0x83452a89, + 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, 0xdadeeb74, 0x7425d656, 0xdcf615c1, + 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, + 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, + 0xc725ecc0, 0x35b295d1, 0x7534f83a, 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, + 0x98a03f22, 0xd70a9952, 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, + 0x7ccba435, 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, 0x771d7fac, + 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, 0x59029f2b, 0xb47ed32a, + 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, + 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, + 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, + 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, + 0xdf2b52bc, 0x0849a8d7, 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, + 0xcca50f90, 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, 0x38d03044, + 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, 0x7ec20957, 0x2e01a0db, + 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, 0x0b90f4dd, 0xa36b8065, 0x31933133, + 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, + 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, + 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, + 0x339b1a9d, 0xcd9c7feb, 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, + 0x85fd0e01, 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, 0x0470618d, + 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, 0x89209a5c, 0x5a60a94e, + 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, 0x22497a31, 0xf3512771, 0xb6adb43b, + 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, + 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, + 0xfc9d64e3, 0x1b454a6d, 0x8b220894, 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, + 0xc66316e8, 0x52366573, 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, + 0x2d196453, 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, 0x6fb6bf96, + 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, 0x3c9257fd, 0x8a3d0140, + 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, + 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, + 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, + 0x615723de, 0xf5fde9a0, 0x96bab4f4, 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, + 0x54f0e2e2, 0x5355cc42, 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, + 0xf6ff9372, 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, 0x0230da46, + 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, 0x26a6191d, 0x83da081c, + 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, + 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, + 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, + 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, + 0x8bf9c71e, 0x1a682b8a, 0x7bbd75b5, 0xb06c035c, 0x9bd1355b, 0x03f15e1b, 0xe1dc6a96, 0x724c12d5, 0x5eeb7abd, + 0x6f1a533d, 0xe4163b97, 0x53963f78, 0xf4bdc4cf, 0x30bc6aa8, 0x55020a94, 0x87424139, 0x7f4e0fc0, 0x0dced4cc, + 0xcc44f761, 0xdc915d5d, 0x5923afae, 0x5fca09df, 0x6da60086, 0x4176cac0, 0x2cd1c0be, 0xeaf4a65a, 0x9a2b0460, + 0xd9adceb3, 0x837911fc, 0x24a064e2, 0xf62aef80, 0x2c72361c, 0xabcea574, 0xc9e8494f, 0x58fdc7fe, 0x19835be7, + 0xe2f50795, 0x22577eee, 0xf37a909d, 0x01085e15, 0x433de341, 0x47e376d9, 0x0bba767a, 0xf77fa338, 0xdaabb9e6, + 0x321bb7de, 0xd9c18914, 0x63c61551, 0x608ac9b2, 0xdc175799, 0xa3b005c1, 0xb30ba812, 0xb8f13ae7, 0x4e6515ee, + 0x63b6e03c, 0x21dc18eb, 0x92116367, 0x912c40eb, 0x67431a9d, 0xa3ac94ae, 0x8778ab34, 0x97d032f9, 0xe363d369, + 0x83361fee, 0xfc13d3ed, 0xa8b81258, 0x3ad31da7, 0xf22b43bc, 0x5e4dc39b, 0xaf3c8d97, 0x4e4f0c56, 0x9ad45750, + 0xce42b7f5, 0xfee1c9dc, 0xda821b40, 0xe112aa6d, 0xc534e246, 0x49278e21, 0xb44895c1, 0xe3d1ab5b, 0x73a79242, + 0x6c9f7498, 0x635ece54, 0x11679e76, 0x2ecfb564, 0x32fac952, 0x9ef53d09, 0xe639b29c, 0x6bc8773e, 0x1bc739cc, + 0x89ba5c0c, 0x4bd2bc26, 0x422ddfd6, 0xfdb0a8e4, 0xcf2f81a5, 0x14841e89, 0xd4f78e53, 0x63013219, 0x359821da, + 0xb02ce75b, 0xac288e79, 0xd6225779, 0xe9c65694, 0x49a11a14, 0x1607727d, 0x5371ef25, 0x6e32e37e, 0x46463aa1, + 0x2f9f3be7, 0x008814a8, 0x4aaeb902, 0xeaf8f5a0, 0x36ff71ae, 0xeda38d7c, 0xc8154fa2, 0xbd72884c, 0xeb83e123, + 0x8c815ce0, 0xe3cec3c1, 0xb7cb6a68, 0x4b2967a5, 0x6f401978, 0xa790036a, 0xd7098ddf, 0xe29bc8fc, 0x990029a6, + 0x03cdb1fe, 0x0dd3e1d0, 0x154d7ad7, 0xf416dee7, 0x5563bc46, 0x724bd24d, 0xc9afafda, 0x15fbdda1, 0xdafbcb38, + 0xd5a26b25, 0x619bed77, 0xba04b927, 0xfd2d6b8a, 0x77894e2e, 0x3a2b2115, 0x4f97c16a, 0x624c5c48, 0x87b8ac99, + 0x52727b94, 0x1e24f7f7, 0x075e8797, 0xf6c0d443, 0x1bbfc65e, 0xaaef1178, 0xc6ee8328, 0x328b718e, 0x6f763df7, + 0xf0198c11, 0xd6cd4bf9, 0x3ee66642, 0x717949cd, 0xd07b2cb7, 0xa023dc26, 0x36fb0e07, 0x833771f3, 0x865405d9, + 0x440f6fbb, 0xaf079d0d, 0x2187a5d8, 0x1c48bf61, 0xd1a3e59f, 0x022d6bda, 0xd6bbf539, 0xf7e1e652, 0xd13cd569, + 0x1953bd8c, 0x2c00848e, 0x15a8bd5e, 0xf1633fe7, 0x56e8f0b5, 0x3b009bee, 0xd18e24a5, 0x06e6be5a, 0x20b080a8, + 0x2b7c3d6b, 0xc9e867d9, 0x013902a6, 0x722d7f90, 0xaa97b1b4, 0x6a72eaa5, 0xa35fb788, 0x02c7801c, 0xf528ad86, + 0xc08e0f90, 0x36013f85, 0xb6507cfb, 0xce50853b, 0xdc81a410, 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, + 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, + 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, + 0xca3c7387, 0x3ebc4e22, 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, + 0x0d609b5c, 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, 0xe964371d, + 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, 0x8549a545, 0x72cd25a6, + 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, 0xfa0f309d, 0x2450505b, 0x7e62d6b6, + 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, + 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, + 0x554de3f7, 0x00236229, 0xb65a8838, 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, + 0x1e0f4174, 0x0e4f84a9, 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, + 0xbecc7016, 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, 0x36f74f81, + 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, 0x49684acc, 0x27ceed4c, + 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, 0xc18462c5, 0x30407eb5, 0x8e18797a, + 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, + 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, + 0x39bc1a46, 0xf4865fdf, 0x22bd8658, 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, + 0xd9382232, 0x947cd63b, 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, + 0x65a5e218, 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, 0x9cff960e, + 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, 0x5da4cf70, 0x861ef098, + 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, 0x2d914387, 0x9ed7f94b, 0xf00b5441, + 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, + 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, + 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, + 0x78603c0a, 0x7c403889, 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, + 0xe1fecec4, 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, 0xee70ca50, + 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, 0x57098afb, 0x744d626d, + 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, 0x5936ff74, 0xc1477a35, 0x3665ecdc, + 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, + 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, + 0x7e1959e1, 0x91787e6c, 0xda51caa5, 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, + 0x8fc78d5d, 0x3ea2142c, 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, + 0xa69d279e, 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, 0xb001c899, + 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, 0x46ebff79, 0xccb7b9b6, + 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, 0xac829629, 0x9ffbf3a3, 0x718c8f7c, + 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, + 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, + 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, + 0xbba13c12, 0xdd02c804, 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, + 0x347c5339, 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, 0x4396ff24, + 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, 0xee7ad3a2, 0xcc436c78, + 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, + 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, + 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, + 0x68c77435, 0x356f1249, 0xec7fe5ec, 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, + 0x8bac2cae, 0x5104a87d, 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, + 0xd5a33292, 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, 0x129c6972, + 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, 0xa54b4c48, 0x667c537f, + 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, 0xe16ab1b9, 0x3d5dd389, 0x5947821b, + 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, + 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, + 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, + 0x8e2665b7, 0xee93572c, 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, + 0x07a80a9b, 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, 0x8a302c05, + 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, 0x9b86cabe, 0x48f7ca80, + 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, 0x79bda240, 0x909fd98e, 0xf49643bc, + 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, + 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, + 0x8821bf49, 0xde5b8005, 0x6e749b41, 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, + 0xc85a975d, 0x00904827, 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, + 0x3ac88c9e, 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, 0xadef941f, + 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, 0x15116dd8, 0xcf51bdc7, + 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, 0xe55e6fbb, 0x43524b5b, 0x12dbc403, + 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, + 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, + 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, + 0xb541d640, 0x84ceb075, 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, + 0xd2f96c90, 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, 0xc9f9d7ed, + 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, 0x3ba18f38, 0xb9d8d6f5, + 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, 0xf818f739, 0x08eaf9e5, 0xc9f08a15, + 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, + 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, + 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, + 0x730d6d4c, 0xb4f2cb42, 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, + 0xfffa9c44, 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, 0xb4ba3765, + 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, 0xf93f4075, 0x9d0ed557, + 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, 0xa5fd92c4, 0x48985b22, 0x9d228641, + 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, + 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, + 0x7e4bb890, 0x1c7739a1, 0xc91fad83, 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, + 0x1eb7fdad, 0xa71313bb, 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, + 0x75bea2bc, 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0x9c315fcc, 0x8b0762de, 0xf28b8010, 0x4bcdda72, 0x45ac9a18, 0x9083961d, 0xf6958e74, 0xa0fcd93e, 0x27592fb4, + 0x04a62c4f, 0x166d4f24, 0x51f0c2cd, 0xb0eb792d, 0x16f78963, 0xa8bb6ccd, 0xf337352d, 0x9f43e39f, 0x3d97dd79, + 0x6ead7f57, 0x52b3c51c, 0x3f796edd, 0x6aa1f5c0, 0xeb1a2a90, 0x3ac20033, 0x102f3f16, 0xf23ddf24, 0xc687bd96, + 0x8af2126c, 0x4d291b91, 0xa561894d, 0xbe645b50, 0xcbd4e08a, 0x69d2d86d, 0xa968161e, 0x5151bc96, 0x753c3dc2, + 0xef4d59c0, 0xd30c1862, 0x6ccbf7d2, 0xafb953d5, 0xdb56b7c4, 0x4665df3e, 0x2d3e6768, 0xf53d533b, 0x827a8867, + 0x657544bf, 0x0cb9eb01, 0x0b31a06d, 0x3fb9c37d, 0xd10ccba4, 0x04ac9226, 0x73947d16, 0xaf488ad5, 0x5fd80905, + 0x442651bc, 0xbb74c336, 0x0fb4191b, 0x83b43e90, 0xa503f9e8, 0x0a4b69b2, 0x1cdd641a, 0x4f9f87ea, 0x2782d210, + 0x9f5af7c3, 0x4c4596be, 0x6a2c6b98, 0xde3bce9b, 0xded33cd5, 0x98a997c8, 0x33d5dc67, 0x1cd9e6f1, 0x183daa74, + 0xb6bb9348, 0x7eacd48e, 0xc404584b, 0x7fb9c568, 0x1a22c0f9, 0xbaa07503, 0x9ab52d6d, 0x655b1ae9, 0xddc911e0, + 0xf40c5d15, 0xa0ce92f6, 0xd0ba6bde, 0x424811c6, 0x0af474a4, 0x87bddd1b, 0xa7d730be, 0x565d365e, 0xbe345362, + 0x5f09e609, 0xf19b5a91, 0x0105b2d2, 0x54bc661b, 0xcacb5c1c, 0x18cb8dc7, 0x4f313730, 0x74d26f5a, 0x629e3a50, + 0x9bfb6788, 0xe45c47bd, 0x75a9e66d, 0x5d2a6d46, 0xb2922a49, 0x3a4564c4, 0x6b3e0469, 0xc931f54b, 0xf37af5fc, + 0xae0a9227, 0xb495eaf6, 0x4dcae07c, 0x41899421, 0xc0b25903, 0x0d66040c, 0xe968c1be, 0xe0cf525c, 0x538b1867, + 0x58b4e4ad, 0x556532e1, 0x67069e3c, 0x2bc5f09b, 0xa7a6f446, 0x2b3ea3b8, 0x1625a485, 0xb9e3f4aa, 0xa5d1eb62, + 0xc40580bc, 0x3471d078, 0x4ed73918, 0x7bffd923, 0xe98f7931, 0xd24b8474, 0x3b60ed38, 0x5388f377, 0xb8e97998, + 0x13cd4c75, 0xb6998008, 0xfcf5f0b7, 0x262d1baf, 0x7772c989, 0xceef466d, 0xc88ecaa3, 0x1b61fb05, 0x1d10b579, + 0x57d2b7a7, 0x2127f2e2, 0x41213721, 0x2bfdfaa4, 0x6b8f20d6, 0x664d62a8, 0x8290a4ff, 0x5cb567c4, 0x8bbbf9a0, + 0x10800312, 0xa842463e, 0x0014f612, 0x9f8a4c0d, 0x08b15b33, 0xf3f6ddea, 0x1f5d3371, 0x1e15d7f3, 0x0b75ade1, + 0x400bb658, 0x2c51e379, 0xcb93de39, 0x91c2b362, 0x8be75e76, 0x2ca0f9c5, 0x32552d87, 0xd3b81d28, 0x8aa8c570, + 0xb27eab78, 0xaa1e51ac, 0x89502bb5, 0x2c588630, 0x95eae621, 0xf58ed713, 0x3d47e807, 0x175601c8, 0x41b46760, + 0xa112459c, 0x5549b1b9, 0x3a6791b0, 0x262d42fd, 0xf57fc215, 0xac17daad, 0x02d5c2c7, 0xc60e0e5b, 0x78928fee, + 0x96e4d6de, 0x4da13de6, 0x063b4d3c, 0xdc9182e7, 0xcb44f614, 0xee140310, 0x18b1ad42, 0xce4c46f2, 0xea7b7c10, + 0x0e32b86c, 0xde08244c, 0xa057c218, 0xd5420c94, 0x1cb9737c, 0x637aa739, 0xc3cc6ef6, 0xad0743ff, 0x8dea9f18, + 0x2f9294d8, 0xda03f866, 0x4e0ad156, 0x25bf86f7, 0xe9d33974, 0x07dab60a, 0xaa2f2e5a, 0x960f77b3, 0x6d39077f, + 0xc7c8a305, 0x1f362db8, 0x72c4e115, 0x81d9e5eb, 0x8d2dd534, 0x9773bd76, 0x6add1c6c, 0x831a3319, 0xa54c3c87, + 0x281786f2, 0x6b1e4b54, 0xe3ea1078, 0xb2b42daf, 0x228bd531, 0x269b2881, 0x53d4263b, 0x66f9a018, 0xf54306c2, + 0x6df72f95, 0x3b61772d, 0x3bb738fc, 0x3fbfd11e, 0x6d142675, 0xbe678e5f, 0x199033cb, 0xaaa59bf8, 0xf690a05b, + 0xf37a38f4, 0xcb1f42f8, 0x48fd71e8, 0x63744120, 0xd3b70a40, 0x230841c6, 0x26a2aa52, 0xeac69c20, 0x06897036, + 0xa51ba165, 0x89e2af8c, 0xe0844bc8, 0x45825e86, 0x097ee7ce, 0xc67d7b6c, 0x0add7597, 0xe9e57e68, 0xd5f41e91, + 0x186dae46, 0x61d420c6, 0xa6b8e835, 0xc5c03608, 0x20438f99, 0xb70bbc5a, 0x024dfabd, 0x50027d4c, 0x28e80eec, + 0x199bc40c, 0xf2aa0a80, 0xcf747795, 0x1be27e32, 0xdde4944c, 0x2a24835c, 0xc1a4c273, 0x2de341ea, 0x45e2f7d7, + 0x2212ee19, 0x07064028, 0x800f7391, 0xf7635268, 0xff37d87d, 0x77296d3d, 0xe1f57f41, 0x89ae2512, 0x2b0783e2, + 0x66cf66af, 0xf575fa25, 0x793f314e, 0x78b2aa5a, 0x88bfdb84, 0xfaa2cc1c, 0xd6b151e2, 0x35f3e5b4, 0x1b2fc6e8, + 0x70f3c9a7, 0xb4aca44a, 0xe0f19973, 0xbb272e6d, 0x13ca151f, 0x2412e5cd, 0x339f58fb, 0x029ee9d5, 0xb87c2f2e, + 0x672ab382, 0x7e1767e2, 0xa541937d, 0x14012db9, 0x86d4886f, 0xa6dec976, 0x74c8deb4, 0xb054503e, 0x38435210, + 0x35231ece, 0x41ad6f71, 0x58334381, 0x35880b60, 0x1844cccb, 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, + 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, + 0x50dd62e5, 0xf2dc2490, 0xb742d94c, 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, + 0x40278377, 0x4f1306d5, 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, + 0x3c727cc6, 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, 0xe3f264d4, + 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, 0xdf701ef3, 0xdbee77ed, + 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, 0x6bd1ccab, 0xdd2cbbd4, 0x6d4849d8, + 0xd98b154c, 0x0ab4f750, 0x47356874, 0xebf27a2a, 0x0d4fb4c3, 0x6a0a8af7, 0xf7ed0b0a, 0x37c2fb35, 0x71fca686, + 0xc13423d9, 0xc6ee8987, 0x5c82b6f2, 0xcc976d72, 0xdce65764, 0x484ef5d9, 0x90092ebd, 0x0cf8d8e8, 0x5d5ce0a2, + 0xcd6aa7de, 0xf9ce34a4, 0x8dd070c3, 0xb19a0b57, 0x337139a4, 0x3eb26084, 0x15dde756, 0x9f1bad7a, 0x345a8b88, + 0x5be24d48, 0x3535a045, 0x46701866, 0x56cf8a71, 0x90a1aa98, 0x60163285, 0xd6a03320, 0x16407c3f, 0x7b04325e, + 0x4f36731e, 0x9179afbe, 0xaee15ca5, 0x153b788e, 0xd682291b, 0x2473cd31, 0x0395c9bb, 0x360b4089, 0xb8f41c41, + 0xd61b957c, 0xb1d3601d, 0x285c0134, 0x2611a026, 0xe30cd2e9, 0x8d0b77c5, 0xef5fd3ac, 0xbacd2083, 0xcce26409, + 0xdfa29eca, 0x7e300ef1, 0x183b8cac, 0x9b02c4c2, 0x6c06ad46, 0x2ec94baf, 0x6725545c, 0xd5e9bf3b, 0x2efd4983, + 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, 0xc0c97ca0, 0xd6456515, 0x86a49990, + 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, + 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, + 0xab800038, 0x0e5f415b, 0x77d71868, 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, + 0x7999f376, 0x687e76cc, 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, + 0x5d416565, 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, 0x78b1dad5, + 0x1f27e9b9, 0x98b6e1ea, 0x81687e81, 0x886fb026, 0x5e10e71f, 0xcabc6180, 0x2909b195, 0xc01d1672, 0x0fa6344b, + 0x3239c578, 0x979c5f26, 0x5f02cf6d, 0x1cec8e40, 0x6ba2d9aa, 0x4f33d4e1, 0xd372c5d0, 0x7c4e2487, 0xe83452b8, + 0x503f00db, 0x20f1c459, 0x52ff0f41, 0x6b4d7ca2, 0x5094973a, 0xf6c5c4eb, 0x7e907c43, 0x3fa6e0b9, 0x663b8a61, + 0x23cf5760, 0xb204aa05, 0x7ad97512, 0x0230a11f, 0xa1a1b1e3, 0x02904261, 0x9a59b732, 0x81eea9f7, 0x2cf2e047, + 0xcac406ab, 0x6040d630, 0xaca48454, 0x0c87baca, 0xaf25f28b, 0xbacb8233, 0x988e8592, 0xab788159, 0x4a0c1bbf, + 0xf054ac4c, 0x5a2ef885, 0x3d489b41, 0x97a17e02, 0x0acfc836, 0x2d8f23fc, 0xe4c15510, 0x467ff8fa, 0x3532bd03, + 0x3992d5b2, 0x5bffe9fa, 0xc1b55be7, 0xb911132a, 0xbf0cf669, 0x8b2100c3, 0x498a3dfc, 0xf14db0e7, 0x8116f826, + 0xf2b491bf, 0xf91bc9c7, 0xab237142, 0xb80ddc3e, 0x5761abc3, 0x93aa4ced, 0x5d99ea4d, 0x8dc34690, 0x28f34916, + 0xf1528cfb, 0xf79a38cd, 0x5c71d094, 0x2878672e, 0x62e3d8ab, 0x2c4fc9f6, 0x7e22e107, 0x64f9509f, 0xbb52265b, + 0xc297147d, 0x8788dd32, 0x62ccc36e, 0xa8c3738d, 0x40feaab4, 0xe5e66e66, 0x876256f2, 0xf7bfbaad, 0x52ea5a26, + 0xab326551, 0x5999a1f7, 0xf5ac042b, 0xce8e4683, 0x6330dd47, 0xba9e63d8, 0x8338d24c, 0x194890a6, 0x7497f838, + 0x7749e986, 0x7774cb6a, 0x5cc0dbc4, 0xf6763737, 0x394efffa, 0xbd7c14a2, 0xc5264914, 0xcaf27fb8, 0x48a66129, + 0x01919ed6, 0x01093bce, 0x6e5f244f, 0x01c7f1d9, 0xe3bc7804, 0x5141def9, 0x9bcbe40e, 0x30ec2e4c, 0x251b2f34, + 0xd31af56e, 0x37fa3f6b, 0xb1e569ef, 0x7865efc8, 0xc038eef6, 0x5ab6dbea, 0x309d5530, 0x5b6f8abf, 0x58bcf70f, + 0xfc20c388, 0xd8e1eea2, 0xad21bfef, 0x5b1b9234, 0xbf44f6e7, 0xa8f11aaa, 0xc2f75f34, 0x2f5ddc74, 0x2236410b, + 0x8b13ca61, 0x89e973f4, 0xce916d12, 0xe4382a60, 0xa1419bf6, 0x1716c2dd, 0x363e3a65, 0xabb42af5, 0xf1e6aa4f, + 0x057db65e, 0xf56c1511, 0xa3bcccc8, 0xb7a257f2, 0x229ae0e6, 0xc9c2de2d, 0xbd5a0400, 0x1c40074f, 0x4b6dc5dd, + 0xaf0a4310, 0xacbf48bf, 0x2feb142b, 0x130a9037, 0x5c530c69, 0xb77f369e, 0xbd8160b0, 0xae8c4405, 0x6893368e, + 0xd4e51c6f, 0x3a7c54a3, 0x78c68b79, 0xf1ba8fce, 0xdd24712e, 0x11043f49, 0xb2b0b6e9, 0xae647902, 0x2f0371a3, + 0xb980fde0, 0x7e18d7c8, 0x2c88c7a1, 0x69c12990, 0x024df51f, 0xad269cf9, 0x20d07c08, 0x46dd7e5d, 0x8b9164d3, + 0x94db4bf8, 0x197cbfdd, 0xd6468cb3, 0x2eeb6901, 0x8c44979c, 0x1d81e0f7, 0x9f946bbc, 0xedfde6b7, 0x2486f2a7, + 0xd8c9af8e, 0x4c0a6f94, 0xd5944971, 0x00fab05f, 0x5426b324, 0x4afb07e3, 0xdfb43f92, 0xe40171d5, 0x4486b8a8, + 0xbc6870e7, 0xc95d18f4, 0x1ca8b3c6, 0xea1c1852, 0x5ca2e2a8, 0xe8da3dab, 0x17612271, 0x2ab72b95, 0x9c15d202, + 0x5c6d5389, 0x85da1da4, 0x429919c2, 0xbdbc5233, 0xb622137b, 0xd7acde34, 0x7cef7a78, 0xb7da1755, 0xef672b63, + 0xfee2f710, 0x03236b0b, 0xc92fc557, 0x8e574b88, 0x2805ba96, 0xc81c866b, 0xad184d45, 0xb836c91f, 0xbeab9200, + 0xc41b82eb, 0xee8ab2af, 0x81160ca3, 0x37fc7eec, 0x83437c12, 0xb86f9be4, 0x44f2d5af, 0x24be3b99, 0x21add5ca, + 0xd0d168c4, 0x32560890, 0x6f698ad0, 0xc5c3ca2c, 0x957eb6e0, 0xa3de6166, 0x09934285, 0xd88381e5, 0x176ff5b3, + 0x493f9565, 0x39f6d3a6, 0xf695c64f, 0x632e92f8, 0xef7404ce, 0xe1466f18, 0x34c0cf9f, 0x5d81884b, 0xa6605610, + 0x56f84ee2, 0xa881494f, 0xa133dee5, 0xe585bdc2, 0x3454b808, 0xb8eb525d, 0xf03de612, 0xd3625812, 0x5f9e2734, + 0x538214a7, 0x21f2740d, 0x39cafc80, 0x092f0669, 0xc244c4ff, 0x569c8561, 0x8ce00cec, 0xfad3174c, 0x17a98478, + 0x3fba51e2, 0x7839ccd3, 0xd3cc2942, 0x34459786, 0x9e605d5a, 0x481ee65e, 0x63c01029, 0x97c3b03b, 0x0556943c, + 0x9ca515fa, 0x45ee4c64, 0xfed15ef4, 0x65baabdb, 0x037c4d51, 0x892ea8a2, 0x2de6038c, 0xd8716227, 0x57424e4f, + 0xf1b5ca70, 0x287fcd83, 0x653d548d, 0x2baaa7ed, 0x6af133ba, 0x4bfb12eb, 0x0585c00b, 0x7926e62b, 0x67f71020, + 0x06941d09, 0x3269b9d6, 0x6becf31f, 0x18b598fe, 0x139643a5, 0x9a9160e1, 0xbe2df596, 0x782f8037, 0x9bcce7db, + 0xf3be74bc, 0x4f7f7177, 0xddcacedb, 0xd348bb00, 0x0ef68de3, 0x1ff7d95c, 0x6201a28d, 0x24f67327, 0xa1425633, + 0x48426e5d, 0x3ccfed4a, 0x92baf081, 0x868d6418, 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, + 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, + 0xa4f0c02c, 0x006bdbc5, 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, + 0xd9d19ac8, 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0x40bb52d5, 0x654712b1, 0xd8e940e2, 0x8ff4683c, + 0x2a998600, 0xd4aad8ba, 0xee241d02, 0x94346fe9, 0xc02eb848, 0xc2c91e1a, 0xea843f6c, 0x5bc57c6c, 0xddd8a617, + 0xebf9c3c0, 0x4980bc36, 0x6d334dcf, 0x97a4b3df, 0x2a94b788, 0x83811aca, 0xbbc37422, 0x6292df1d, 0x761131db, + 0xb2d8dbe4, 0x7ff0219d, 0x95d470ee, 0xda8c0e74, 0xcf981bc4, 0x95642758, 0x215c055b, 0x2aaea2f2, 0x28a91766, + 0xe750abab, 0x995e1edf, 0xe39955fc, 0x33af7feb, 0x238315d1, 0x2ffeef88, 0xe8b6f798, 0x35eeeabc, 0x8368340f, + 0x81dcaf0b, 0x9313abd6, 0xf0c7b961, 0x87cc331b, 0xcece3df4, 0xcb90e2fd, 0xfc2850ab, 0xc5e37ef3, 0xf727bba5, + 0x97c7f994, 0x283e5938, 0x513bd493, 0xb5d182fa, 0x4e8d6fb8, 0x83686263, 0x1cae22db, 0xcc923e99, 0x074cad57, + 0x8938a877, 0x12338d86, 0xd558d946, 0xb28895e3, 0x5a000780, 0xbe031e1c, 0xd33b3dc1, 0xdffdebe3, 0xd234f8ea, + 0x1523c8ba, 0x68a0608b, 0x8b615bd6, 0x2930eeda, 0x28cad819, 0x7c3e8c7e, 0x0aec3b74, 0xc92b4e33, 0x6278a8dd, + 0x1df2fd4f, 0x90a5a45b, 0x34354809, 0x597f9b39, 0x8d1c5736, 0x73d3f226, 0x8bc263d5, 0xe5cd9545, 0x800db58a, + 0xc23bc076, 0x1be19e52, 0xca477b42, 0x15007281, 0x0f687cc9, 0x6a31c769, 0x1d75c0f7, 0xe34730f6, 0x74540689, + 0x38f67674, 0xaa46a55a, 0x6cc6f2de, 0x6762be31, 0x74e55f6b, 0x8dea8bf6, 0xce92f7b7, 0x47b7ba55, 0x7dede31e, + 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, + 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, + 0x11e80584, 0x3a49181b, 0x01877253, 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, + 0x7b06c1bd, 0x241bb5d3, 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, + 0x6a39fefc, 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, 0xe97476ff, + 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, 0x6bc54667, 0x5da05bd4, + 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, 0xa18cde24, 0xa865edcd, 0x4a0863f2, + 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, + 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, + 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, + 0x9d3fcbd9, 0xa2157e5f, 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, + 0x8430e9fe, 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, 0xcff88a4f, + 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, 0x027ff968, 0x7c059f38, + 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, 0xd8861fcc, 0xa171057c, 0xc650cd2a, + 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, + 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, + 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, + 0xd2063aba, 0x38356c3f, 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, + 0x1c1010ce, 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, 0x52f9037c, + 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, 0x49c20c19, 0x5283a436, + 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, 0xc2223c9d, 0x99554000, 0xcd28bc49, + 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, + 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, + 0x553e3c53, 0x4ff910a9, 0xb16d9d48, 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, + 0x1ead51ac, 0xf531936c, 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, + 0xd81a58c7, 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, 0x5bf25e25, + 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, 0xc806079c, 0xc684f5d5, + 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, 0x4adb2b92, 0xf781402f, 0x870c8ab5, + 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, + 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, + 0x5d7847cb, 0x800a7cd4, 0x2174ea30, 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, + 0x2e1cd1e9, 0xc7308954, 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, + 0xb2b5f06d, 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, 0x8692254d, + 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, 0xdee4891d, 0x83247a45, + 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, 0x3e9a6812, 0xb7981ce1, 0xd48dac33, + 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, + 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, + 0x79d4b7c0, 0x4f0d800c, 0x6615417d, 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, + 0xb2213194, 0x520c5c4b, 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, + 0x4dbd49c2, 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, 0x7fd1b105, + 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, 0xc844714c, 0x83a50459, + 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, 0x795f7841, 0xa403bc22, 0x95959ab1, + 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, + 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, + 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1110_transceiver_0401.h b/src/modules/LR11x0/firmware/lr1110_transceiver_0401.h new file mode 100644 index 0000000000..43f7a832e0 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1110_transceiver_0401.h @@ -0,0 +1,7741 @@ +/*! + * \file lr1110_transceiver_0401.h + * + * \brief Firmware transceiver version 0x0401 for LR1110 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2023. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0401 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x06b5c13f, 0xc3680745, 0x5ea06cbf, 0x88c158ef, 0xb02175da, 0x63512c1f, 0xff2c307b, 0xb340a6b8, + 0xfef9d0b6, 0xd8765718, 0x1bc5171a, 0xf97b5ddd, 0x59f77bce, 0x2c34c3d2, 0xf51fa6a6, 0xe469dacd, + 0xd76c633b, 0x5533fdc9, 0x8b85a152, 0x8c23be86, 0x8b5809bc, 0x57b46180, 0x3b4bf923, 0x3e64f3dc, + 0x6683c266, 0xe9b76e17, 0x2bb8b9b3, 0x5ad71b3b, 0xa9b86059, 0x5808ab88, 0x157376a8, 0xce8c957f, + 0xa8ccd933, 0x9ad9acc6, 0xab04c008, 0xf362a997, 0xbcc3ab89, 0xdbac3b8c, 0x452e0c17, 0x79049e67, + 0x23f465fe, 0x2b08c9a1, 0xfbe36fe4, 0x725d61b1, 0xec4f91c5, 0x9283c5ea, 0xc651ce68, 0xc5206c67, + 0x75b461e9, 0xa43d4fd1, 0x93780b80, 0x7ccc6464, 0x525d4cb3, 0xccdcba01, 0x2c0bb5bc, 0x9b0ff163, + 0x59378f7e, 0xd484025d, 0x200ce752, 0xa7dd1042, 0xe9d5c39b, 0xa80b8edb, 0xdaea23f7, 0x345d5840, + 0xb04d044f, 0x156553cb, 0xcd21e28e, 0x996597f1, 0x8aae762f, 0xe4faa6eb, 0x9bb463ff, 0x4812a0e4, + 0xd0086607, 0x6869a837, 0xda4c3438, 0xa9feebbe, 0xcd24d332, 0x5022af14, 0x48d51513, 0xf1ff1950, + 0x7c51af7c, 0xcbde9fff, 0x5083945c, 0xcc27f58c, 0x258bc12f, 0x44de7575, 0x7ac98805, 0x8bf487fe, + 0xd5411a8d, 0x38968201, 0x3387b0d6, 0x77b11b63, 0x6d906a97, 0xc80cbb82, 0xf84b9cf5, 0x6dd65dd2, + 0x6dcb758e, 0x42fe0c3d, 0x3077bd96, 0x679cca55, 0xa32c9d36, 0x3b7cee5a, 0x6a9d0e49, 0x1063bed2, + 0x655f5a56, 0x844b7757, 0x054fe2cb, 0x25c4b871, 0x7706c5ca, 0x8147e446, 0xa0fe4852, 0x32e10dfe, + 0xbbc7b496, 0x9538fcea, 0xd5477b2e, 0x86189e1b, 0x691ed12d, 0xdfb6faa0, 0x406d5e52, 0x35873475, + 0xa9fca155, 0x465f6a88, 0xb454b812, 0x347076ee, 0x2c78130b, 0x762891b4, 0x95cad806, 0xd75db654, + 0x6c3ad5ba, 0xf9d44a44, 0x7bc1e539, 0x9f8ec729, 0x108144dd, 0xdd0208da, 0x97762b40, 0x290f20ea, + 0x5a677648, 0xf0839947, 0xf0365a09, 0x08dc830e, 0xaeae1bac, 0x5e6ace3a, 0x891d5516, 0x4c86819d, + 0x92d924a4, 0x87c403aa, 0xa8cbf5c3, 0xed6f31c5, 0x61777f9a, 0x62b96ce0, 0xf3849c0e, 0xc62e8a0f, + 0xe70b5db8, 0xb9b591c6, 0x24bdb049, 0x65dcde36, 0xd735b2a0, 0xd089bf27, 0x3ef8601f, 0x3874fb8a, + 0xb2552436, 0x3431fe80, 0x9eb62262, 0x34459e52, 0x65e9fe97, 0x79eb58b4, 0x967d8968, 0xcc2830b8, + 0x7fc4c680, 0xbfaedccf, 0x193d5fb9, 0xbe3d81bc, 0x61fcfe2b, 0x84986037, 0x2a9661ba, 0xacd3e408, + 0xff45eba7, 0x4ff12a17, 0xb7973179, 0x41f5812d, 0x9ae21e2e, 0x230256b1, 0x63982190, 0x6588ba9b, + 0xcc9aae59, 0x6ee156aa, 0x83bfdc26, 0xf62565ce, 0x14da3e57, 0x2ebb1bfe, 0x2b47b692, 0x294aca9b, + 0x711b5209, 0x435516b3, 0x5216659e, 0x16b4333a, 0x15f8a32f, 0x4d053c3e, 0x7bd6857f, 0x163315e0, + 0xb48cedb2, 0x343d3bca, 0xcc46a4e3, 0x9447ff69, 0x91275783, 0xcd0ae78d, 0x88fa1947, 0xe13592f3, + 0x4ec9203c, 0xc4830096, 0xd6d6ba6c, 0x3267261d, 0xfdfa830c, 0x1647e2cd, 0x888bc8f3, 0xedb311a1, + 0x0a35fbac, 0x82595171, 0x5fabd491, 0x15cf7e06, 0x7dee9015, 0xf07abdc3, 0x5c16c019, 0xd4e07062, + 0x8be5eacb, 0x7691e306, 0xbfc0e03e, 0x7365a0ac, 0x3da66adc, 0x5dfbb55d, 0xdb8b8ed0, 0xe5b394f3, + 0x33d106c8, 0x9ff9f9fc, 0xaaa9e9ad, 0xbca7fa5f, 0x74876892, 0x0aa6409e, 0x1802ca8e, 0x54ddda12, + 0x13463b19, 0x9cc518dc, 0x71ea33e3, 0xb24f3957, 0x915b3f8c, 0xdc6c32dd, 0x06b925d6, 0x93b6338f, + 0x8d689a98, 0xd12e555c, 0xd2ffdf32, 0xcc6c8535, 0x2bd8a5e6, 0x66fe9646, 0x35832130, 0x91018d90, + 0x6a6e13be, 0xd115fb75, 0x42931487, 0x31353863, 0x4faf739c, 0x1a54eee8, 0x0c7170d2, 0xc2a9d116, + 0x54bffc57, 0x68661a18, 0xe4e5056b, 0xf75ba48f, 0xc7fc7ab9, 0x0ff19b04, 0x9fc10a97, 0x8bd7e014, + 0xe09fd885, 0x401a89a8, 0xa184d2bd, 0x6f7b5d68, 0xf70c1677, 0x1d195673, 0x71b31884, 0xcfe1d375, + 0x792eb77f, 0x49b6017e, 0x6c93500b, 0x6c381c70, 0x12b2e5d8, 0xe9e5333b, 0x86296875, 0x75ceaca8, + 0xb571e249, 0x9df2fd32, 0xb2708818, 0x00a459cc, 0x78d7ae14, 0x798c6314, 0x99b13b8f, 0x1969dd48, + 0x796b547b, 0x35da8320, 0x5f015dde, 0x4c50dff2, 0x80d5249b, 0xbf120bba, 0x0d46b6b0, 0xaa5950f4, + 0x4037cc21, 0x75abd8fa, 0x91cdf874, 0xc390feb2, 0x5113501a, 0xa2a5ef14, 0xd1d56cc8, 0x64f5db84, + 0xb4ccc027, 0xc734a3ad, 0xcab876ec, 0xfc2c4fd4, 0x68ae1082, 0x096d399c, 0x07b6e7ff, 0x17bd1bc1, + 0x0037417c, 0x7a4da25c, 0xeb0385e3, 0xec41d005, 0x2372631b, 0x921d2dd8, 0x8ba9dab6, 0xa9066ee1, + 0x46a39e23, 0x00e833b1, 0x118e0bd9, 0x35f6210a, 0xbf47c2fc, 0x0ceba0c0, 0x5f227f2e, 0x44626341, + 0x04161a6d, 0x18b218d8, 0xac04ecfd, 0x22c85f2d, 0x30b3161c, 0xb01cb4c6, 0xa1ff2848, 0xbebad921, + 0x96e347d3, 0x1172126c, 0xe4540271, 0x3ac76564, 0xed89266e, 0x104ed2da, 0x4b394ad4, 0x27910ae7, + 0x917332d0, 0xcbf5b386, 0x928cde0e, 0xbb2bc39e, 0xb6d5e1b6, 0x30bd7471, 0xa59c0b85, 0x12949fc2, + 0x2bc009c3, 0xd96beb34, 0x39fede06, 0x2259e5f9, 0xa15a2fbe, 0x5bf26fbf, 0x9219c68d, 0xb4876c1b, + 0xf691f69e, 0xe03d9554, 0x5b0d9f45, 0x60116bcf, 0x29c61447, 0x25c73867, 0xb57bbb21, 0x621edad5, + 0x9e56680b, 0xaa011d89, 0x8f4848ee, 0xa625d422, 0xb6a5b9f7, 0x9bd29a0a, 0xad085f34, 0xcf0ecc4b, + 0x9beef36d, 0xf87d6f2c, 0x8a914b99, 0xd3e348df, 0x7f3ce798, 0xb7642525, 0x8ec9998a, 0x9500ed01, + 0x509850b2, 0xadccbd5f, 0x0e0e567c, 0x2be759dd, 0x41c8c37c, 0x5b640664, 0xb5943ea9, 0x47dcb346, + 0x785b7f93, 0xa1017d00, 0x78baf6d0, 0x8f0776bc, 0x26a8474c, 0x0d1caa6c, 0x43072f59, 0x1418c250, + 0x30d625ae, 0xc23b9062, 0xa583c81b, 0x9bcdaa9c, 0x0f120d33, 0x88f5ca11, 0xab8e2da1, 0x11c83d24, + 0x2c1b2947, 0x0eb8fd36, 0x5e1d3061, 0x5fde4ee2, 0x4376cd28, 0x47cba253, 0xa1533ff6, 0xd7d0f0d9, + 0x7cbd9e8f, 0xaa304e18, 0x0b81339d, 0x2a774cd5, 0xd7efa442, 0x6a6d73f1, 0xf8d33d83, 0xfc7414ab, + 0x99f22455, 0xdcda1324, 0xb2ad8391, 0xb4555867, 0xaae6fd5a, 0xfd40ecec, 0x0aaee9bf, 0x76c9ccc5, + 0x42a93351, 0xbe5ee3e7, 0x18692550, 0x64c4b472, 0xe982b4bb, 0x92fa4d91, 0xec068c6b, 0xb90d08ec, + 0xb7af2dd5, 0xa985f2ce, 0xff6e280b, 0x033853dd, 0xe0ee6a96, 0x7376e7c2, 0x2b8e2574, 0x52523fb0, + 0x9a7b2170, 0xb5cec470, 0x83e50646, 0x07292041, 0x585aa2da, 0x5f179615, 0x87d7e704, 0xbff8e291, + 0x92dca48b, 0xe5140908, 0x48e63c1d, 0xede7ede9, 0x98c3ac45, 0xefa1e2d2, 0xf642cb4c, 0xce6685aa, + 0xd105a062, 0x52605f35, 0xe6bf7741, 0x20303c97, 0xb802b1c2, 0xee170f39, 0x7a522314, 0xd4e8b116, + 0xda633527, 0xcdf3a048, 0x5239f279, 0xc4cddd04, 0x0c8af4e8, 0x54d3afae, 0xc26858e4, 0xf393c5ba, + 0x697b9b86, 0x358c4ef4, 0xe9d4ca60, 0x96ec01b5, 0x89132dd8, 0x834aae5d, 0xe22e9dcc, 0xc59a899f, + 0xccb4f806, 0x2b015f02, 0x06f20d42, 0x964bc11b, 0x07eb4ce5, 0x76e49c16, 0x230d0da0, 0x969181e5, + 0x0737f599, 0x92ba61bb, 0x09efa6e1, 0x00be5925, 0x95d7257b, 0xb3f4647b, 0x243f5800, 0x540f39a2, + 0x9b7373ee, 0xd0b88088, 0x5a870eb4, 0x908d3f5b, 0x8a7a3a88, 0x915cb42f, 0x8712d126, 0x3ab0d0b6, + 0xb9cb9e32, 0x1ea7196b, 0xc0301baa, 0xe8494d94, 0x0aff3e0e, 0x8d0203f2, 0xf45a371a, 0x66447517, + 0xef331d4f, 0x0262d6d7, 0x162c5d6c, 0x933e6df6, 0x9b0d283f, 0xbea97069, 0xb675b2ff, 0xbedc9d7a, + 0xb84fd519, 0x00fef70a, 0xc03f6177, 0xb05e6c63, 0x52e277c2, 0x7600bfec, 0x2efb692e, 0x51f54a53, + 0xbe2cc74a, 0xd496c097, 0x9e812b8b, 0x83fc9bd5, 0x3508a0be, 0x389d7961, 0x60a232fe, 0x7931bd80, + 0x0fcbb815, 0x93306548, 0xb7b636df, 0x78419d04, 0x3f822b7d, 0x25b7ee05, 0xa737ad99, 0xd2062843, + 0xed2761a8, 0xf539cd6f, 0x22e73a86, 0x3c8558a4, 0x2d1afeb9, 0xe8a315ac, 0x38d24550, 0x85c8749b, + 0x2ed7654b, 0x49a2634d, 0xa954c727, 0x64e6f09a, 0x9770b086, 0x9d2a0bd1, 0x7daf3c0a, 0x2c69b9a8, + 0x3bc80233, 0xcf429134, 0x780d25e1, 0x09710767, 0xc410ce74, 0xcc1dd33f, 0x791f340a, 0x86205fd5, + 0xe685c940, 0xdd6a216a, 0x4833a8a2, 0x4673bc54, 0x775b4ead, 0x42534299, 0x4e4d6690, 0xa2457724, + 0x018bdbe8, 0x994fba95, 0x90163a99, 0x59d4dadb, 0x8baf6592, 0xdbf11cb0, 0x719e6a94, 0x97d8efdc, + 0x79971155, 0x51607b1c, 0x5528654c, 0x22a93cb2, 0x2922b14c, 0xed86075d, 0x595f9a52, 0x0c38b488, + 0xb3f6b7f4, 0x8db83787, 0x4a5a6502, 0xf7dda9da, 0x75847441, 0xf042644c, 0x694712d2, 0x52ea458a, + 0xe1dafa7c, 0x6632765f, 0x8b10de7c, 0x0f56b39f, 0x39b58c6b, 0x11679fda, 0x2e347d78, 0x3ff2fa59, + 0x329afed9, 0x8c140639, 0xf14204ef, 0x869f4b56, 0xa5c6bfe7, 0x17880a1b, 0x6972388f, 0xdacbb771, + 0xaedbd7d0, 0x7a264ae4, 0xddacc938, 0x02095c3b, 0x45eef619, 0x449d8e29, 0xa29a1af1, 0xe610cdf8, + 0xcf29e702, 0x2f382c02, 0xf55f4727, 0xbcfc29b4, 0xa954e9f9, 0x109174b4, 0x87a7cff5, 0xe794ecbb, + 0xee2569b4, 0x54a8f298, 0x7b36dbc6, 0x03a53987, 0xa23bcd6b, 0x4c0948a0, 0xdf13831a, 0x139999e9, + 0xfc7cefe6, 0x5d5e1cc5, 0xf14cab60, 0x896e9bd4, 0xdfcfb643, 0x5b8bc71e, 0x9f4f37db, 0xc593e27c, + 0x32b088c2, 0x4460da12, 0x8911b23b, 0xa94383d0, 0x59295231, 0xdd3e83a6, 0x68c0fdc5, 0xaa2f3821, + 0xb6ad9a4d, 0x2ca0b24a, 0xb37f40d2, 0xe4c84db5, 0x7607aa39, 0x7b72f88a, 0xaa75e206, 0xd9528b73, + 0x4f25790a, 0xfefcc180, 0xe7f46a48, 0x06ea1cdc, 0xb495ed7e, 0xc2f3870f, 0x11a252fb, 0xb654f590, + 0xa0e47cf6, 0x1553668a, 0xa22a7e9b, 0xef68f1cb, 0xd4fc7192, 0xe6a393bd, 0x5d2dd23c, 0x179e23d4, + 0x2d2d29f6, 0x38bb8a4e, 0xcfd5193f, 0x9d5bede4, 0xf44d852a, 0x44b0d708, 0xdf97b74f, 0x32787377, + 0x4e8d1c8e, 0x9427971e, 0x9e284ba0, 0x22223937, 0xc57a6203, 0xe0687598, 0xfb80ff56, 0x929a31f8, + 0x2dd5b248, 0x196e700b, 0x680c1897, 0x7c4d73bc, 0xfe3cb8b9, 0x08242f40, 0x42ced390, 0xd58cf3eb, + 0xd892d10a, 0xc65d803d, 0x6832514b, 0x5f701245, 0x501d8521, 0xe7e3df9a, 0x86348610, 0xcea30117, + 0x76b82f0e, 0x3811fdc5, 0xacdf1b7e, 0x097ed4aa, 0xfa904229, 0xf5d3c279, 0x59854216, 0x3ef96eef, + 0x4087cf39, 0x29842fd6, 0xa7032f7d, 0x3a793857, 0x164851d9, 0x470d9ac1, 0xb1bf4941, 0xdd35254c, + 0xd29b67e7, 0xd6c455bd, 0xadb7a9a8, 0xd0852798, 0x6868c36d, 0x004ce2e9, 0x9212e8f5, 0x9462b10e, + 0xbfa615db, 0xff4b6d94, 0xa5ccc1d2, 0x3481b48a, 0x61c7163e, 0xd383e6c9, 0x6674bce0, 0xc81813f7, + 0x832772f6, 0x2d669ea4, 0xe82bb0ef, 0xc0732c6a, 0xec6a1e1d, 0x25cce096, 0x680a5dec, 0xf395120f, + 0x5b33d9cf, 0xbdfdef6e, 0x2ecd344e, 0x59fe1241, 0x4b2335a3, 0x0247ba1f, 0xcad8126a, 0x3fac1144, + 0x309298f1, 0xe6cea2e3, 0xe9a0a896, 0xa12006e8, 0x3f7c9252, 0x9c059682, 0x00dfdb0c, 0xc739e862, + 0x320c5599, 0x9b92ddf7, 0x7f527cab, 0x8811e7c7, 0x9b25d6f6, 0x58407513, 0xb6764b45, 0xb734fc0e, + 0xa29b8d14, 0x3354b168, 0x561adf5d, 0xb021d584, 0x18e0bce4, 0xc4ae2969, 0x99d59090, 0x8c1a556d, + 0xdc93a319, 0x71474e28, 0x5aaeb0bf, 0xba3d46eb, 0xa27aa07d, 0x1a3f4470, 0x790ebce6, 0x8a4ed465, + 0x21d79081, 0x293adf58, 0x3d24bc36, 0x265bf6a2, 0xa466857a, 0x2fe4fc3e, 0xc4c73da2, 0x21fb0e84, + 0x7e27d441, 0xf4a95c0c, 0x8cde3e2a, 0x0cc0f5c5, 0xb86e0f80, 0xc5962a5c, 0xa25db3c4, 0x4eaa3d56, + 0x384dfd3b, 0xb64f7b8e, 0x04b9582a, 0x92ffce66, 0x2f7dfde8, 0xc53f84a0, 0x5cd213fa, 0x3d368ca9, + 0xee00887f, 0x9f18dbe3, 0x4436a752, 0x9e5376b4, 0xfa79fc82, 0x96f43669, 0x7dd39379, 0xf98a7578, + 0x75e83b8e, 0x78f058d4, 0x14aeed4a, 0xd58c7fa8, 0x163fb3d6, 0x6f947dfb, 0xf9d5373c, 0xc54adcfe, + 0x4ef6a216, 0x5c4f7a25, 0xbeabd42d, 0xfaceea30, 0xea47ed62, 0x5a6ef27e, 0xdbb69659, 0xdc497a7d, + 0xf333478a, 0x2e483021, 0xbb9a85dd, 0x1aee4e66, 0x9eb5b003, 0x5d979c65, 0xb6a2d006, 0x07bb403d, + 0x8ed378e6, 0x3ac8781c, 0x1f0102f3, 0xe99d4d80, 0x9fc65944, 0x0d6ab57e, 0x0f565ab7, 0xe571c610, + 0xcfbf807e, 0x79fc72b8, 0xf174e605, 0xdc86bfc7, 0x76a4ddfe, 0x6ea97d95, 0x7b93f645, 0x0bc60dc2, + 0xf1a76954, 0x0b7204e3, 0x45835bcb, 0xe2bd1747, 0x809acf1f, 0x3f4a825f, 0xae8331ca, 0x94b52db9, + 0x6d78a134, 0xdc6cdcfb, 0x10a49c34, 0x0f75b60c, 0x2a805738, 0xe8351d28, 0x3070cf3a, 0x8168b7c9, + 0x983c3cc8, 0x8c85ef3e, 0x04fbaa5b, 0x5286dc11, 0x3f3c43d6, 0xeca75eca, 0xfbe1fa29, 0x37a7e736, + 0xfc8e338f, 0xeeea3d8c, 0x4339c88f, 0x53d0f953, 0xbc23a269, 0x16a3bc9e, 0x9602375f, 0x9d09b0a4, + 0xf18c31f5, 0xe3b31f19, 0xdd2daa32, 0xe6fcd0a2, 0xbf22dfcb, 0xccc1caa8, 0xb96e63a2, 0xb9fbd9bb, + 0x84e5da74, 0xd56e4482, 0x36e64e9b, 0x74d41488, 0xe190abab, 0x77a8e01f, 0x91602eaa, 0xea6e4b0c, + 0x3dd19cb1, 0xcfb5aac0, 0xef17457e, 0x815c7e12, 0x9925dd19, 0xf0e6749c, 0x98968c0d, 0x75b09bd9, + 0xdfb618e5, 0x9c07e197, 0xd3a65673, 0x83c58a23, 0x51dffeb1, 0x45565f78, 0xe22e52eb, 0xb83693f3, + 0xe9d11414, 0x20b7879e, 0x4e9bd7b4, 0x95a386ed, 0x86245292, 0x9c405eef, 0x50631213, 0x45db3b18, + 0x4b6be9a5, 0x75eac801, 0x13e3c04d, 0xcc3688ce, 0x8467d5e4, 0x2ed0920a, 0xdedc1c8a, 0xa258302b, + 0xf658eeed, 0x22297b7b, 0xf0c4201b, 0x60c91b48, 0x16f0abc1, 0x48a0cf54, 0xf0c1367c, 0x0e7fb68a, + 0xa2ce7c33, 0xa45a65f9, 0xd4000c58, 0x6041f202, 0x537a08df, 0xb5a432df, 0x2e02a057, 0xed8c4636, + 0xda743825, 0xd28111ad, 0x459c0d4c, 0x325d6067, 0x897bec6b, 0xdf418d82, 0xc5cb105e, 0x76814b36, + 0x033b940c, 0xdac1739c, 0x4b6492f3, 0x3c8276fd, 0x096ad96e, 0x2eeb9244, 0x6f230496, 0x72da866a, + 0xf33731e5, 0x96ffed1a, 0x242a4757, 0x211e7bca, 0x024a7734, 0x0df75580, 0x3b764a91, 0x03241181, + 0xddaea3c3, 0x0b6e6232, 0x7bea4de3, 0xbfa74500, 0xae4df350, 0xa23c858a, 0x86cc55f8, 0x64679a44, + 0xd41ed433, 0x9e262069, 0x1753616b, 0x309f47dd, 0xa4788926, 0x12624b68, 0xe53e1e1e, 0xea0b2ad7, + 0xf1f64952, 0x5e5ed611, 0x7ba22bd3, 0x1d0daca7, 0x5472aed4, 0xbd0b4f3c, 0x037e8427, 0xc9aea6ee, + 0x6940c1a5, 0xd23cf8b6, 0xc737f631, 0x8185128f, 0x5dcbe5ce, 0x1597916f, 0x67911223, 0xf7b6860d, + 0xb40cbcaf, 0x50509a28, 0xc35b2123, 0x746c663a, 0x106a933c, 0x3725d093, 0xee355149, 0x5e9aeb6b, + 0x165b632b, 0x3d1d78ca, 0xfe026a1a, 0x97ab2987, 0x2b5145f9, 0xc812bc85, 0x6ff72e80, 0xd14423a4, + 0xfd3ac610, 0xb4c536e9, 0x2f06017c, 0x728868ef, 0xb7df7cd2, 0xa5af761e, 0x6358a21c, 0xb1f43f86, + 0x726d9578, 0x3953e7b5, 0x8f79322e, 0x0db8fc7f, 0x1d7d3d99, 0x611edd1f, 0x47ac5509, 0xc537c467, + 0x79165586, 0x370bbca7, 0x77c17875, 0x3fe8d6b5, 0xf95f4185, 0x3fb5661f, 0xba0bd6a8, 0x47409ec6, + 0xc8284f0e, 0xa58ff93a, 0x13649b1c, 0x273cc8f5, 0x44dec673, 0x8ced1882, 0xe09448b1, 0x1e7f92e6, + 0x7760b16d, 0x17336231, 0x7d5abae6, 0xd061bdb9, 0xf2dd3397, 0xc74e38d8, 0xe7651fa0, 0x46201ac1, + 0x683219a6, 0x7b60ff1b, 0xcd6dd25c, 0x6a10b44a, 0xd593dca4, 0xe52d8ec4, 0xe8ee7493, 0x7ded7922, + 0xb49c13cd, 0x854672eb, 0xa7fa126f, 0x30786fd5, 0xe0c1c79c, 0x0a92d304, 0x00c1e3c3, 0xd1a729f1, + 0xaeeda5ce, 0x5ba57f83, 0xfb577627, 0xcfe6ee14, 0xe25dbe58, 0xbf909b79, 0x906f7326, 0x8b8f84c8, + 0xe67afcbd, 0xda452228, 0xb58d7e60, 0x02b7e02b, 0x13010b92, 0x120082ca, 0xa6eeae7b, 0xd860a2ed, + 0x09528d64, 0x2483164b, 0xb7406218, 0x5421874c, 0xbd597f31, 0x529d6bc5, 0x41d39359, 0x2127977e, + 0x0a799784, 0xc1e3a676, 0x5e70574d, 0x0eabca6d, 0x9feef667, 0x77585af1, 0x0263ff90, 0xb6ac00ad, + 0x3e0e6d4c, 0x746dfbfe, 0x521c36bc, 0x4c87bfb6, 0xbf667865, 0xad80c9ea, 0x4f701c01, 0x9f6af556, + 0x595673b9, 0x0273bd55, 0x64fae747, 0xe5a0a70c, 0xa3052a6c, 0x97a8af1a, 0xe9b10b9a, 0x6df86261, + 0x20a591e5, 0x0c9668eb, 0x5e26cb41, 0x856adfdb, 0xed9e0304, 0x8037ea48, 0xdb1461ca, 0xb4dccd7c, + 0x4ff76222, 0x6b553a82, 0xfe6d18d6, 0xb84613fb, 0x48909b41, 0xd9ba8827, 0x4beb2763, 0x24ad1c87, + 0x0f9d9935, 0x5b9d8b49, 0xbd635266, 0x0d996f45, 0xd709543a, 0x39f3bb3c, 0x0515a705, 0xe067f500, + 0xf19748ef, 0x2d6efff5, 0x230e4983, 0x0ca85d65, 0x0a1ff5d8, 0x531b7450, 0x00d744a6, 0x819594de, + 0xc7061453, 0x5603411a, 0x1de94fd1, 0x45481efc, 0x09df9c60, 0x42256b70, 0x9c0f7e8f, 0xcf2faca4, + 0xd7fc978a, 0xcbba6d5c, 0xed247140, 0x24f63534, 0x66fc0b30, 0xa0619caa, 0x27680b55, 0x3c9122ba, + 0x09983fcc, 0x4781d661, 0x35e84b41, 0x5ae48f1c, 0xf8911c25, 0xd21e1581, 0xe76a746a, 0x269f695d, + 0x20616aaf, 0x75f243f6, 0x670e8a78, 0xd6f79243, 0x93280a62, 0x8d85d8de, 0xc970f86f, 0x26e9498b, + 0xb67ca469, 0xb99a8638, 0x4f2d8d3b, 0xe97b7c4d, 0xa9d3a346, 0xb3892f33, 0x1b3ddd67, 0x6a942046, + 0x2a8ece05, 0x00c97d0b, 0x0d38c1f5, 0x351f1825, 0x4015a376, 0x520fd741, 0xe00fd3ea, 0x4c290a45, + 0xf33e7edd, 0x60b9286d, 0x97c7f3a1, 0x84c8dc76, 0xc7de1e9b, 0x6baf423d, 0x6c5aa753, 0xcadf83ee, + 0x2600f0d6, 0x1b568b18, 0xc03d5be7, 0xd1e43c28, 0x21510709, 0xbe0967e2, 0x593d66fa, 0x725fe872, + 0xcda4bcdf, 0x27eb957b, 0x3546ead7, 0x430596f5, 0x16a11f93, 0x4cdfde5e, 0x30377384, 0x85e323a9, + 0x467f6dab, 0x65ca40cb, 0x5d532301, 0x24851b6b, 0x26a41789, 0x5953e979, 0x6e966ebb, 0xafbac856, + 0x09944a14, 0xf91b68d1, 0xa9408e70, 0x6c1f9d48, 0x58952275, 0x35a4ea9c, 0x9b0fac88, 0xc3c2678b, + 0xc9d332b3, 0x45fc29c3, 0x1ced15ac, 0x9a5a764b, 0x5301f543, 0xeb1773e9, 0x9c8462b8, 0x07b068d5, + 0x48b3100c, 0x1c878284, 0xbd5ea8ae, 0xd27f75ca, 0x90b2c3b2, 0x32e82952, 0x849b28da, 0x2bb15063, + 0x0f35f719, 0x8ae1831f, 0x3e7b9fe6, 0x4c839cf7, 0x0b6c8221, 0xb1f517fa, 0x01799472, 0xc71acb6d, + 0x3db13c5d, 0xdebd3f98, 0x1a022459, 0x6830458b, 0x424f42d3, 0xb058c3c1, 0xd66b3c01, 0x44000ae1, + 0xda8052d5, 0x864d13bc, 0xe186b3f7, 0xcb440fc0, 0xfa4579c4, 0x8499a50f, 0xa4b567bc, 0x8b9def62, + 0x64f8f488, 0xc077ddff, 0x68eb3557, 0x19d838a2, 0x1619f265, 0xaca19595, 0x9178d8d2, 0x6d307e89, + 0x5b3df055, 0xf51d9fe3, 0x5f6cfc4a, 0x976fa4a8, 0xa4a72115, 0x44206a08, 0x16894c78, 0xcc7626db, + 0x6219d5ec, 0xf9b4a30c, 0xa6633e94, 0xa6633009, 0xc25d748b, 0x2ad2812d, 0xdec873bb, 0xcace4746, + 0x058a03a7, 0x47266f96, 0x78302ca0, 0xf37262d0, 0x9e64262d, 0xbcaf9256, 0xf92d60ea, 0x7ce26538, + 0x796264b7, 0x7f71f9d9, 0xe55753b1, 0xb09c5f10, 0xacf93fca, 0x7483f4dc, 0xd7565e53, 0x66e64544, + 0x86e44a3f, 0xa3bafb58, 0xb59d64be, 0x99e72a79, 0xa219a865, 0xbb2691de, 0xa1bd414e, 0x97cffdb9, + 0xed4721bd, 0xc3bb22ea, 0xa22b5ba8, 0xa4667bd8, 0xd60c51b8, 0xb2d10fae, 0x50db8a1a, 0x4e62e0aa, + 0xd4593eb9, 0xd6cba9db, 0xf439ec63, 0xa8c3ff59, 0x69b27fac, 0x5a0b2ff6, 0xce2cd6c0, 0xbe360818, + 0xf6f21b5d, 0x6a7f7c3e, 0xa07b25dd, 0x27014c35, 0xbea76d42, 0xd160770c, 0x162c228f, 0x8ba1ef04, + 0x5b4c269f, 0xe05f43ec, 0x233808c5, 0x5232a0e2, 0xeb74e01b, 0x93a4305a, 0xc4fb3f69, 0xe1ba2243, + 0x1036c094, 0x2379511b, 0x2fd7a3b2, 0x5c92829f, 0xb415e670, 0xb3f59b79, 0x53bfdb85, 0x9839e445, + 0xa49f7bfa, 0x13703213, 0x2ea6c615, 0x5029a399, 0xc8c88377, 0x17d440b5, 0x2621d2d0, 0xcf10b325, + 0xef516ac9, 0x550f6705, 0x8a5717f9, 0x4694338b, 0x4fe9256a, 0x92a59f4b, 0xbfd86049, 0xd6ac29f4, + 0x19d1f918, 0x8ff0d1d3, 0x6a28cff6, 0x680fe7e4, 0xed65b2cf, 0xac27161e, 0x231f42ac, 0x6ca148b9, + 0x80f952a4, 0x4eab65bc, 0x0bc8bec1, 0x9f5040e9, 0x6cef3ef4, 0x85bbf554, 0x398a2c55, 0x37ed512e, + 0x0e7d9bff, 0x5f3c8d0c, 0x79d471d6, 0x9bf0e59c, 0x3d7147bd, 0xe7ef766e, 0x4606e068, 0x31df8132, + 0x288989c7, 0x48dba60d, 0xc8f681c1, 0x1cefb34d, 0xf344c85e, 0x754487b7, 0xca61258a, 0xdce8c178, + 0x5af0a3fe, 0x35fee11f, 0x592c3667, 0x86363296, 0x555e03b4, 0xf7088aa4, 0x3d803364, 0xfab589d8, + 0x182507ae, 0x8f46ad66, 0x67bdb818, 0xb761b6cb, 0xa005cf9e, 0x8a3f2cf7, 0x1ada23e7, 0xd310147a, + 0x7b4d60ef, 0x8fa7ea51, 0xd0020da9, 0x6ae8bbd2, 0xc65c7833, 0x4354291c, 0x64542cc6, 0x6497be92, + 0xdd09158c, 0xb6928db2, 0x60b85314, 0x3bf38579, 0xc0cc6cc3, 0x98a2d7ac, 0x560f0790, 0x37d38e2c, + 0x5c7fe19c, 0x482bb2b8, 0xc2e22992, 0x917ffd86, 0x80b33d97, 0xb7503afb, 0x322b674b, 0x80c8de8f, + 0x485c56c3, 0x0bc16ca4, 0x5190a641, 0x1a04c32b, 0x1feeb0a9, 0x4c5dc6f0, 0x17cf2b5e, 0x6f05997a, + 0x204ebee5, 0xb3e55e1f, 0x2ac3a17c, 0xfcbe331d, 0xa7a57452, 0x8bf8194d, 0xc5fa6f97, 0x00800d20, + 0x7557b7ce, 0x1d4a45cb, 0x12739bd3, 0x3e957fa0, 0xa8dc0763, 0xd41098f3, 0x04c42a38, 0x80df6df0, + 0x63b5af60, 0x0585a179, 0x2bf994f7, 0x71b2d43e, 0xb2beadf4, 0xe9583468, 0x4fca1db1, 0x699346c9, + 0xc94fb857, 0x1b7ea533, 0x64cf1827, 0x999fd344, 0xb678d265, 0x4e866b48, 0xc27d514c, 0xa6dc54f5, + 0xd5239afe, 0x3755744f, 0x418d43c2, 0x85664f5e, 0x94acec15, 0xc3037176, 0x6e96fbb9, 0xf9f5ee81, + 0xee4ba778, 0x2999891a, 0x612d91ac, 0x77563cff, 0x4fdd2f96, 0xf27d10d0, 0x8c2e0278, 0x6653b28a, + 0x9f81d0f9, 0x6d13b99a, 0xfcc6eeb5, 0x65dba9a2, 0x905276c8, 0x4378c176, 0x2cd3f22e, 0x5891bdf7, + 0x23ccfb8d, 0x8b3cbce4, 0x1168ff97, 0xfaae3981, 0x2414230d, 0xd20ee081, 0x5ba22992, 0x54db0bec, + 0x4cebacc0, 0xfe345e74, 0x55d2e0ff, 0x653090c6, 0xe3671451, 0x6a6e5ed4, 0x82e8bdc2, 0x98c08ac4, + 0x1465fd75, 0x9fb2cf68, 0xed6fe002, 0xb89c2655, 0xb91abbd6, 0x34fe206e, 0xe2c07704, 0xedc312f3, + 0x5ed9f995, 0x670c2fda, 0x7fe9f3d8, 0x31bdbaa3, 0xca01bacc, 0x37841b15, 0xccf05896, 0x6e9100cf, + 0x48aad89a, 0xe1b48527, 0x9910d716, 0x0768107f, 0x1402e696, 0x6f9e55fb, 0x036de871, 0xa198b267, + 0xf5277baf, 0x0cb15e33, 0x2ad4580e, 0xe655cbb2, 0xaa4b9321, 0xd7e27aa3, 0xd0436bc0, 0x87410dbe, + 0x1ff8a186, 0xa1f9f8f1, 0xdfcde6fe, 0xfb23eaa1, 0x06f12d01, 0xb7ede702, 0xec4c639c, 0xcc95d443, + 0x4b0dd2ec, 0xc843474c, 0x4efdfb16, 0xbd4b1810, 0xc13f190f, 0x80a6528e, 0xe14f89fb, 0x95c657bd, + 0xe038666a, 0x3b4e5f52, 0x80b5629e, 0x41982ddd, 0x77c71e1b, 0xa2915326, 0xdc7d10d8, 0x82d28537, + 0x8fe9566e, 0x66d0b498, 0x34dc4ccc, 0x45d4ba9f, 0x7b475638, 0xc4c38b3d, 0x16f80149, 0x5866238c, + 0xbba366ac, 0xde80ae6d, 0x20ef8be8, 0x764a3e60, 0x8d5675f2, 0x3e8851ed, 0x1ecb2979, 0x1c5cac9a, + 0x942b5803, 0xe5ce2547, 0x7935d781, 0xd290f708, 0xb6c55d3f, 0xdb9ee79e, 0xaf6b1070, 0x38a82ffe, + 0xfff8da7a, 0x8f085325, 0xe337b245, 0x3f55d766, 0x6d498058, 0xd7dcec41, 0xb0efaf7f, 0x86611f5f, + 0xd5adad5a, 0x5625a905, 0x58d2581a, 0x2a0feea6, 0x9ef32cea, 0x13f72083, 0x36ffa24b, 0xc3cd9df3, + 0xaa93e651, 0xafcf4805, 0xfd96faa5, 0x652dac35, 0xd34c69cb, 0xb1d6eb5d, 0x3801398a, 0x961126ce, + 0xcdbc8688, 0x93975a02, 0x089a8da8, 0xbef4a407, 0xec937da0, 0x2c5cff4a, 0x0e911ebc, 0x5b4d86f5, + 0x0f272049, 0x8fdd6019, 0x0edd919f, 0xffb3440f, 0x4e814938, 0xf9064d17, 0x8fcf102c, 0xf27b85fa, + 0x6b675e9f, 0xdbe973d1, 0xd81855c0, 0xc1cac6ca, 0x6b6d8bab, 0xb0e44d8a, 0x2ffffd5b, 0xeac91ae9, + 0xeb72d3a4, 0x43fffee5, 0x8288c139, 0x5dd04d2d, 0x4e9e740a, 0xd2269ff0, 0x99fa6f81, 0x875d87ce, + 0x61eca49a, 0x8e02718a, 0x20b8cae0, 0xa9bbdf25, 0x72799221, 0x0395577e, 0xe3822fe3, 0xea98e6a7, + 0x18a83fa1, 0x459d0f6d, 0x481f94f9, 0x6f965d9f, 0x54dc2dfc, 0x0509c86f, 0x2ba5b747, 0x23c9ca0b, + 0xc654653d, 0xe725fc87, 0x8985b44f, 0xf086b645, 0x8429bce7, 0x72751145, 0x351c06b3, 0xc419b91d, + 0x47cb94d0, 0xb3c5d4bc, 0x10bb1994, 0x195cdc6e, 0x8969b766, 0xfddfc7e7, 0x1069b447, 0x1b3f83a9, + 0xa58bf9b3, 0x3a5b3e6d, 0x2c9fbce6, 0xccab0115, 0x6ad21f73, 0x651c1ccb, 0x3325861e, 0xcf7a81fa, + 0x5bf4c7cf, 0x54e4a4ae, 0xcfab7bf9, 0x42460ffb, 0x3a1bdeaf, 0x7625dcc2, 0xc86c6dc5, 0x6f1cb079, + 0x3f59715f, 0xcdd3b3ed, 0x2c3fe518, 0x91bac1e1, 0xa5c12881, 0xa12b92fb, 0xa71db7e6, 0x8d461494, + 0x9bd6fb03, 0xc8c652cf, 0x2cf1d145, 0x0b3987dc, 0xbf9eed21, 0x97d7b459, 0x61fc16af, 0xa99969f6, + 0xe369c372, 0x6d025bea, 0xbeb5910c, 0x1a2378c3, 0x92a55494, 0xba4ae0b5, 0x6eee01ca, 0x4acca646, + 0xcb511e71, 0xfb14ac5d, 0xa815dac5, 0xa01bbaa6, 0x62aa6bd5, 0x77cc1c69, 0x862b220e, 0x19d29f4e, + 0xe440ecb4, 0xa02fc539, 0x3052938a, 0x6d6635bf, 0xefb8f150, 0x95268780, 0x9c089396, 0x1a5c0ca1, + 0x2970da87, 0x40be32f1, 0x65f55253, 0x6c501a9b, 0x9b3c08e4, 0xed5c48e7, 0x92ac7f55, 0xb0f63707, + 0x701b9e9c, 0x063c63aa, 0x9a28250d, 0xf055d902, 0x4e655553, 0xb39fa965, 0xb2fd6f7d, 0x4d9635e5, + 0x71b0f70a, 0x3af6e6dd, 0x6c566a25, 0x1082f28a, 0x81f8bb04, 0x9ad64eb5, 0x9026acaa, 0x34015169, + 0xc888d661, 0xf11dd2d3, 0x8022ed70, 0x76cc26ff, 0x0272b6fa, 0x9f705b04, 0xd3ccad6b, 0xdc5b5162, + 0xa85074a7, 0x7a586672, 0xc57b11f4, 0x59f3f43a, 0x60ec4a2e, 0x285361e9, 0xe786bec7, 0xd4be1734, + 0xa33a403c, 0x729988a6, 0x3d87baed, 0x66b7b4e3, 0x097a0f4d, 0xd0c26b43, 0x88e710ba, 0x703327c9, + 0x43df05b0, 0xb5d155a0, 0x4b94fc22, 0xaa9fb4ca, 0x0be17163, 0xd69ebd64, 0x9e9401cb, 0x6c48e759, + 0x52cafaaa, 0x9c6092ed, 0xd5ee4e6e, 0xb830a912, 0x2d5541cc, 0x513c70ec, 0xabeb0d00, 0x3c278a59, + 0x00739744, 0x04cf8b3a, 0x930760a4, 0x0eb31f1d, 0x32510a12, 0xde6d1fdb, 0x716a93a7, 0x14a0944c, + 0x53b5896a, 0x3bfc0a96, 0x20184562, 0x812f31e4, 0x7dcd6b6b, 0x1d37b4d4, 0xbfc7d34b, 0x230349c1, + 0xdb8f4b27, 0x61c460c5, 0x35f42265, 0xc4a8ea7e, 0x181a51b9, 0xcaa0a096, 0x0d97a78f, 0x815c37cf, + 0xb56b34b7, 0xe801cb4b, 0xb1e6447f, 0x23edbf88, 0x53491e22, 0xeacd25c6, 0x6ab3d15b, 0x1c1156af, + 0x5f65355e, 0x5e9b885d, 0xba8187e5, 0x4c406ad9, 0x3fb4d1fe, 0x60af7d50, 0x1266ebb8, 0x173e68f2, + 0x4e1a0a6a, 0xe2897b83, 0x71255715, 0x4c275c4e, 0x4feb3007, 0x727c5bd4, 0xd08e6154, 0x44648641, + 0xbe05fb49, 0x512bdbfa, 0x28e536a5, 0x61e1acfc, 0x60790e9e, 0xeaea80e7, 0xdfd27424, 0xa228d952, + 0x689c1be2, 0xb5080aa4, 0x0a4a234b, 0xefa26a1c, 0x1c8d6c0d, 0x6c4381da, 0x07d3eb47, 0xdbd63c5b, + 0x66584387, 0x7ac32c6f, 0x42f1944d, 0x8ab2ad82, 0xf84d0613, 0x4d02f783, 0x7dd9568c, 0xfb55cc16, + 0xf9d04a9a, 0x013594f5, 0xd5839524, 0x9af65704, 0xb4ad4c01, 0x0be43400, 0xad73d78b, 0xa96904b8, + 0xbdef90bf, 0xe37758fc, 0xd71169d8, 0x15197974, 0xf3c779d5, 0xd8406faf, 0x58555744, 0x9fd08911, + 0x0a5d28cf, 0x689c53aa, 0xb93825bb, 0xebba37d3, 0xefe9ea87, 0x5380e468, 0x1259939c, 0x7b63d735, + 0x3dc53c64, 0xc471f794, 0xa748755f, 0x3312dca5, 0x6ef16fdf, 0xb030f4f9, 0x6bde8def, 0x948361db, + 0x5f96bb58, 0x4f0865ff, 0xcbd5b81d, 0xe23db296, 0x1e927951, 0xfcac62e4, 0xce5bb19b, 0x573ce702, + 0xd7f6db4e, 0xd44751cc, 0x2f66b897, 0xb8558b2b, 0xac796887, 0xb018d1e5, 0xe69e6a97, 0xba86e308, + 0x6cb76def, 0xbab33495, 0x6ba31111, 0x5084e977, 0x3d42f383, 0x10deca2e, 0x5532e890, 0x099f8a45, + 0x1a9f5796, 0x3c794f76, 0x9eb490d3, 0x451c2a3a, 0xd71b7201, 0xdc442950, 0x1e2c66a5, 0x889a6f04, + 0x394e866a, 0x853a991a, 0xd913530e, 0x0be9c690, 0xeee451ea, 0xb77b9921, 0x68cf33dc, 0xd5fdfcb8, + 0x284ae649, 0xece3e44d, 0x6b9b0eb1, 0x60129853, 0x2a323ef2, 0x09e56550, 0xf5f7dd43, 0x9c99dc60, + 0x5aec0ace, 0x7e801062, 0x4f7d80d5, 0x2853d419, 0xb7b485c7, 0xf9b4e845, 0x4d94b762, 0x68465145, + 0x78f30213, 0x1a150bf1, 0x9986b2fa, 0x6aa9f052, 0x4f4a8fda, 0x30d0c8be, 0xbd5d123d, 0x76508ab6, + 0x17ac2c4b, 0x0d740adc, 0x83e0db8f, 0x729acbfa, 0x39aa84c8, 0x968fe35e, 0x43ad6c89, 0xc9f47a72, + 0xab8fcdb7, 0xc38b2e1f, 0x20ff2e9c, 0x8a99c49f, 0xcfa92fc7, 0xcc764b7d, 0x9d1f0004, 0x5431821e, + 0x00b9febe, 0x0b9b2214, 0x27445442, 0x165602d9, 0x72f32140, 0xf5f27832, 0x7fd60c84, 0xc232184b, + 0x48e603e3, 0x700bc68a, 0xd9f5d085, 0xdc0ac7e7, 0xda455056, 0xb4cd2e93, 0x36d3112f, 0x78d01a3b, + 0xfd436fa0, 0xcc68cdb0, 0xb7609eef, 0x98cfab0f, 0xb0306dfc, 0xcf8f5b71, 0x2684769f, 0x51a16ea1, + 0x2c64b6fc, 0x80e1af92, 0x2dfa8c8e, 0x92eea3e9, 0xa64e73e1, 0x93f146e7, 0x6372354b, 0xf9922bb9, + 0xc8d480c7, 0xcffd1273, 0x58391a40, 0x306a68bd, 0xddd99948, 0xf63d64f4, 0x9ff9ec31, 0xcf860e9f, + 0x4416071f, 0x29cdc659, 0x67e7448f, 0x7fd6cff4, 0x24d3b1eb, 0x680807be, 0xecba8f0b, 0x1b5d1cbb, + 0x2471b6e6, 0xe717b2a9, 0xd496febb, 0x4eb59ea3, 0x5b0eaf43, 0x97fbbf4e, 0x30a6436a, 0x9b36a9bb, + 0x8759e2b1, 0xad1ca4b5, 0xaaf54ee1, 0x6c0b42dd, 0xc4406ea9, 0xfb0246e2, 0x6def3621, 0x6aacdba4, + 0x39c763bb, 0xc543fa9a, 0xe3c0dbc4, 0xcd6ea2bc, 0x68607955, 0xec2ff07f, 0xd17b28d6, 0x4fdb9b94, + 0x28644cbc, 0x264598b2, 0x0a5e35a7, 0x8e1c4576, 0xc56ea0a6, 0x831ea6ee, 0xff81ce8e, 0x9ed9a4e2, + 0x5334ddd5, 0xb7e9f055, 0x455d122a, 0xbd4bcf70, 0x36fee53e, 0x00bc5917, 0xbb1eaed1, 0x2c2fc5f6, + 0x847cd0ae, 0x2d106b07, 0x0137a8e4, 0x3a3a99f7, 0xc38e31d1, 0x1f138aa1, 0x091f03b3, 0x88362845, + 0x9c701385, 0x88bc0a38, 0x0aebe9bc, 0x77193d1f, 0x7b472f92, 0xb92b1258, 0xcf79d304, 0x2702939a, + 0x9b3aaf47, 0xe271b143, 0x6a30ffc7, 0x312d6eea, 0x6dd084d2, 0x8b3220b1, 0x40db7e6f, 0x364c8c4b, + 0x92773cc3, 0x4d54a37b, 0x1ccf9526, 0x0d70c1a6, 0xc8344ff2, 0x5ce76feb, 0xd1fdcb50, 0x65ff8ad2, + 0x34d52a10, 0xa2d35bbb, 0x52770e73, 0x3f0a5672, 0x6e00994d, 0x11eb134f, 0x7d74253c, 0x5a5a5dd5, + 0x9b6bc646, 0x6e7b3875, 0x469c7f7d, 0xb4ae8e9d, 0xfab23363, 0x2dd93b74, 0x78098d36, 0x25761b73, + 0x62316351, 0x0dbf5f54, 0xdf6f3555, 0x30b1adaa, 0xb4e8a000, 0x6b34c3d4, 0x5f44cc3b, 0x1897f0a9, + 0xe649982f, 0x76155f9f, 0x848d3d49, 0x8e0928d3, 0x44422553, 0x70328d80, 0xf188702e, 0x01dac6a5, + 0x2323045f, 0x70942992, 0x54312bbb, 0x5b511d44, 0xee60fce2, 0x68188763, 0xd1e8644d, 0x249e7038, + 0x16ac713e, 0xa049238c, 0x1a5b46dc, 0x0f0fc15e, 0x7ceee612, 0xc8f21c98, 0x0d47bb54, 0x27337fbe, + 0x655f9a5f, 0x34e43b2e, 0x9309fcbb, 0xce8383c6, 0xf99909de, 0x45b3232d, 0xba70e675, 0x00e31bab, + 0x023441be, 0x2e207b95, 0xa7f20a0c, 0x479c29e0, 0x6632eac3, 0x95b067a8, 0xa4f7c078, 0x400f036b, + 0xbd739876, 0xf7d660da, 0x82f5fb28, 0x35e1ba78, 0xb7546b94, 0x3fe592ad, 0x2558adfe, 0xbf117547, + 0x931085c0, 0x8ed08199, 0x174a2759, 0x11cdd4f5, 0x32c97bd3, 0xd2e4e449, 0xa985aa19, 0xf3691a54, + 0xabc2444a, 0x802e6a8b, 0x39981cef, 0x433f845f, 0xd0bac6d1, 0x32e8c14f, 0xcdb22b88, 0x118ec91a, + 0xa030e982, 0x900a37b8, 0x2e8ea0b9, 0x1934cf72, 0x078a5d4a, 0xaf8ef85c, 0x0322e070, 0x5953f979, + 0x6663ed50, 0x38a7098f, 0x687c8780, 0xebac5a4e, 0x9f3efc25, 0xc9ddae4c, 0x6d1bc25b, 0x10942555, + 0xeea5efd9, 0xd4a55e4e, 0x22510de8, 0xb3fcd6e1, 0xa61d0a48, 0x164df4c2, 0xeecadf87, 0x538f243a, + 0x11bb1f4c, 0x33059d84, 0x11509fac, 0xeafbae6b, 0x787928c6, 0xee112b2f, 0xf8b0e0bc, 0x4f9a21e2, + 0xe8a06e8f, 0x1578bab0, 0x4a9913ea, 0xa2eb76c7, 0xa842db58, 0x04a3fb4c, 0xfa00de54, 0xe0d35acd, + 0x60158d59, 0x769959f1, 0xa4b99754, 0x521aeab2, 0x6efd8b4d, 0x76f98d48, 0x471de979, 0x42e8d0bf, + 0xed3108a5, 0x7f3f60b5, 0xff9e5e23, 0xcc619a73, 0xb74ccb75, 0x387285b1, 0xcb2a1438, 0x063ae8d3, + 0x25572dec, 0x448d67f9, 0xad53fc86, 0x4fae671c, 0x3f4b374f, 0xcdce165a, 0x76cd72c5, 0xd54b6728, + 0x44bfd3b2, 0x1d8d628c, 0x12df4bae, 0x1b08897f, 0xa38fd9f7, 0xfa0b612c, 0x8e382afd, 0x5d0ca07d, + 0xdbce61f5, 0xc156a174, 0x549af3d5, 0x1fcf9a75, 0xc6878a22, 0xb5d362f0, 0xe10bbe9a, 0x9c3c6112, + 0x9f5d2c0e, 0xad4d1f94, 0xda02cf70, 0xd223ab88, 0x332218dd, 0x81d3b474, 0x0d51a5aa, 0x36e3ae2a, + 0x2715162a, 0x8c020afb, 0x0d419d68, 0xdb45bab7, 0xecd1ec3f, 0x230dee73, 0xa62cacea, 0xc4b3656c, + 0x01822200, 0x3f10575e, 0x5b60cfb9, 0xa80c55bb, 0x18951df2, 0x909bc049, 0x2688647c, 0x778bd9a8, + 0x57bb71b7, 0x12ae82ec, 0xd489424c, 0x8988e46d, 0x60438c7f, 0x739511d8, 0xfefb42ac, 0xa01fb730, + 0xffae3474, 0x185c2b02, 0x82b0c33a, 0x1892b253, 0xf64aa078, 0xc1f3d68c, 0xa6879e12, 0xd2ed5e1b, + 0xe8c621e0, 0xc52d2e29, 0xad638048, 0xf94b5b29, 0xec8b488d, 0x5ec13a84, 0x48f876f5, 0xe2711a82, + 0xac44204a, 0xcc9498c8, 0x480f643b, 0xd319e43d, 0x25001f7e, 0x4e833076, 0xda8862d2, 0xd9f71360, + 0x79fce5c4, 0x8fa58b18, 0xb313b0f1, 0xa5146352, 0xd3481e78, 0x652edbb3, 0x9bae9a4d, 0x2f32d2e5, + 0xcfdb0121, 0x4bec2170, 0x94d7a942, 0xa234ff2a, 0xee88ffca, 0x97cf1149, 0x0187e793, 0xd7bbec50, + 0x8f7e74f9, 0x7f728940, 0x2798a1b5, 0x5a8e5bbd, 0x973bc940, 0xaea75fa2, 0x2050a499, 0xb484815d, + 0x99e326c0, 0x22dce357, 0x65c8b24b, 0x33544593, 0x1a5d5e1e, 0xcbacb308, 0x5d9a8ce5, 0x70e9c4f1, + 0x68fa4d22, 0xe49036ef, 0xdf249012, 0x366b4168, 0xd48360e6, 0x277f3f78, 0xb8d81302, 0x8c78b342, + 0x0ccd0cee, 0x26caa607, 0x8771bd4a, 0x3f731a6d, 0xbab823de, 0x9bfe1a4f, 0xde63e2fa, 0xefb342f3, + 0x20353a21, 0x958f2fec, 0x4c239a18, 0x0a1506c9, 0xf35798f4, 0x46fbef77, 0x5bc19108, 0xfc2fe908, + 0x1e0448fe, 0x3efdca29, 0xadc6587d, 0x3a3d9b3a, 0x095bfe22, 0x9b85a486, 0x3c36c7e8, 0x8a1926a3, + 0x32020077, 0x0e25c1c8, 0xbecd5b96, 0xdd1a9ad0, 0x4ee26891, 0x3df16878, 0x9752534b, 0x0be7e99d, + 0xae7834f8, 0x92586b29, 0xc8b06d7c, 0x48d88d5b, 0x4b59ba9b, 0xd1694d8d, 0x6b8dd964, 0xd6b1e182, + 0x6570adbd, 0x57d54e17, 0x9c72167d, 0x3fe78ec6, 0x298c5999, 0xea4c9cae, 0x9518978c, 0x5151ef00, + 0x7b65589a, 0x2238f135, 0x9e333239, 0x5b371e88, 0x8de02a62, 0x4f335155, 0x1f4893df, 0xd5894ffa, + 0x2cad8ac5, 0x215ac94d, 0xbddabf7e, 0xa5499ba0, 0x2ec74cad, 0x6dcfd5b1, 0x61614717, 0x5941dc72, + 0xd637b488, 0x48a6b63f, 0x7d3137c9, 0xea0c314b, 0x4c61aeab, 0x60961db6, 0x4e064054, 0x94a2e544, + 0xeb1b5c05, 0xbc4d73dc, 0x6201f77d, 0x9bf78c32, 0x4c74164e, 0x8ede6744, 0xe6c14e45, 0xb4d17459, + 0x80bce943, 0xdb0da16b, 0xeffe2644, 0xd0bcae38, 0xf77269b9, 0x7e59c2d5, 0x842b99e1, 0x6e84f247, + 0x0275739b, 0x9bb38735, 0x14fc1831, 0xf35f5507, 0xfa6fdda8, 0x899b5cf8, 0xca836fc5, 0x16a7950f, + 0xef324741, 0x60c8f376, 0xed0c92f0, 0x06a04c14, 0xbee438da, 0xbbe5d73d, 0xe64af28c, 0x2c020bda, + 0x8a274f2f, 0x7c42d748, 0xd2c90afc, 0x09fa2ee4, 0xb1a08bc8, 0xad09f774, 0x3743b156, 0x410964e2, + 0x7dcd492f, 0x48eb78b8, 0x2fed5ccb, 0x54143754, 0xcf90aa1f, 0x83203189, 0x51527f84, 0xa10bd6eb, + 0xaaa37e35, 0x13db606b, 0x418aaf6d, 0x221e1208, 0xac8ac5f2, 0x460db814, 0xcb2c3f13, 0xcbf9ce39, + 0x765687d3, 0x6143658d, 0xff4c6389, 0x2c789aaf, 0x74228818, 0x19958fdc, 0x0d344ce0, 0xc392175b, + 0xd2c2a393, 0xa34825a4, 0x3ae934ed, 0x167cfad0, 0xe2b35d29, 0xa1db8178, 0x92fd11f2, 0x92cdd35f, + 0x57b7f6e8, 0xa1332275, 0x6bfe29b9, 0xed7dba68, 0x33e30b7c, 0x4e6ba553, 0x2f4f5ebf, 0xf1258b15, + 0xc2996836, 0x624c5d28, 0x39de2d9b, 0x95f42428, 0xd9b3f788, 0xe17a156b, 0x03c09289, 0x429b85ac, + 0xd82ee445, 0x76e090b9, 0x27bbeff0, 0x6ceebf25, 0xa85a63fd, 0xc7923dc5, 0x1d75c203, 0xe9fa03fb, + 0x68211f1e, 0x02fe9695, 0x536cc8f3, 0x8cdafea4, 0xb95b7b08, 0x14861fc9, 0xe24877a5, 0x3c2b4f21, + 0x85c3b39c, 0xdb542259, 0xf4b72a22, 0x5ee0232b, 0xd80e3778, 0x64d8e718, 0xe1235e40, 0x75a21c42, + 0x4da88f78, 0x95f0f9d1, 0x862955f3, 0x369704c3, 0x06ea22da, 0xf976ac1d, 0x4b382b70, 0xb90886b6, + 0xaf485d10, 0x3fbe2eb3, 0x10d10e2d, 0x25d3a318, 0xeff9d401, 0xae285fa2, 0x088c2f95, 0xf1741d8c, + 0x6030c9aa, 0xdd9c0d67, 0xed3da9f8, 0x5a30d98f, 0x498d1f60, 0xbe6d6770, 0x7284f084, 0x6b4fb912, + 0xfb2af5f9, 0xbee4efbe, 0x5c9bcde4, 0xbe7f55c9, 0x1d63c759, 0xcaca59a4, 0xa064d311, 0xe2651a8e, + 0xa8492b80, 0xc8dbffc2, 0xd78d129d, 0x38cf01ac, 0x66f784df, 0xd3322559, 0x6c8371bb, 0xce607e39, + 0x95f23961, 0xb3390456, 0x8b1329d1, 0x7e6219e0, 0x7b35b70d, 0x31d0726a, 0x6ca4065f, 0x637e5267, + 0xce1f74ff, 0xfbc4dad7, 0xa2804929, 0x58ff00ec, 0xcc616ce9, 0xa4822148, 0xe7d41cda, 0xebb1b329, + 0x2581c48b, 0x6288d0be, 0xaeaaf1a7, 0x3ef0428f, 0x03335988, 0xc107a9bf, 0x69848c11, 0x8001988d, + 0x89ba74dd, 0xe30d2f64, 0xa415dca1, 0x1ed26d4f, 0x85d726c3, 0xa8f73956, 0x14c3850e, 0x5b9c59cc, + 0xbede6aba, 0xf98d7c05, 0x62717c70, 0x878e6a03, 0x59aa6acb, 0xa9c95b9d, 0x3dd4344f, 0x8a24a765, + 0xb4f16577, 0x4f2f199f, 0x493f74ea, 0xa3276ca8, 0x895587c8, 0xeae2496f, 0x986043d0, 0x4710d4ff, + 0xf0766df7, 0x765e51c9, 0xe61089cd, 0x84ff162f, 0x3643a672, 0xbde05e0c, 0xfab8b018, 0xf592e472, + 0x73217c70, 0x56ceed2d, 0x3a01a6bd, 0x1647a975, 0xe164ceda, 0x679125ab, 0x68fe8f8d, 0x1cdf5003, + 0x702b7efb, 0x0cb32896, 0xfce46fb0, 0xae852f16, 0xcbc7f14f, 0xd1f50bb2, 0x536b301b, 0x9515337f, + 0xb48b1564, 0xe47e6141, 0xfde3844e, 0xdff14cb5, 0x79d15d1b, 0x9bfed72e, 0x3a37755a, 0x1970bbb7, + 0x03780fee, 0xa64f9c8b, 0x5ffc1f15, 0x40e47ca4, 0x54f4d33e, 0xd5dae7c4, 0x22cbe318, 0xab46ef75, + 0xd4946991, 0x85acb2f7, 0xc85614c5, 0x0727b983, 0xe31cd789, 0xd2a76982, 0xd5ca1a47, 0x544be829, + 0x95d6faec, 0x286f3c9b, 0x3b0c5093, 0x02b02e12, 0xc1cdf51d, 0xb52a9ea5, 0x94ee0452, 0xbfd999c1, + 0xdef756f9, 0xf65d696f, 0x3cd9e579, 0x664b6bde, 0x6b31d475, 0x10669ee4, 0xfcd14451, 0xc2cbfcf2, + 0x3cf70f4a, 0xbf13cfa0, 0x20a34bbd, 0x27951086, 0x849ce5a5, 0x2f9e3509, 0x00cc45cb, 0x96724ca3, + 0x51453236, 0x5638a67f, 0xfd6711b4, 0x03b07f7e, 0xa5d5b158, 0x7b5360dd, 0xb844a0ad, 0xb8a4e497, + 0xd958c946, 0xc00c77fd, 0x3c952163, 0x719e0e2d, 0x19a53c6d, 0xbfdc723c, 0xefc01ad7, 0x3e6c4e2c, + 0xee9580d7, 0x3aa08cb4, 0xb7cd2821, 0x9f33cc7a, 0xf2868e79, 0xe56a9cd1, 0x47387962, 0x233d644d, + 0xf1ed0aec, 0x803ffefe, 0x4a433a26, 0x8dcafff3, 0x29cd193d, 0x0e2d13ef, 0x1681ed8e, 0xd04c0aac, + 0xa77dbe3f, 0xc84defb8, 0x150a359b, 0x8c9f7015, 0xd343a033, 0x9a7aca7a, 0x85312bed, 0x8f7bf859, + 0xb4da63c2, 0x7a2b473c, 0x2440084c, 0x32cdad1b, 0x133a47d8, 0xfce8c4af, 0x343ad389, 0x205900fb, + 0x53e6d1ff, 0x0e20f27b, 0xfd307eba, 0xe4a2c670, 0x518a9bac, 0xedd56f05, 0xc5c63c32, 0x2acabe56, + 0x7242caa8, 0xa674204e, 0x0093e4ce, 0x51aecc1e, 0x14e40438, 0x2f0fd069, 0x5074e755, 0x28d3794f, + 0xff360f06, 0x4a129e70, 0x9ad1d97b, 0xa6ecffc6, 0xc3c9d3fe, 0xdef23e6f, 0xd3e11163, 0x3ddee1dd, + 0x7840854d, 0xd3bf4d3f, 0xc1432049, 0x043fb2fb, 0x7910f011, 0xf3095a4d, 0xb32e8767, 0x8a7eb109, + 0x7cb1df94, 0x5157c1a2, 0x52570309, 0x4d14fa74, 0x8871d63e, 0x81c5387c, 0xca38062c, 0x0eca13fb, + 0x841a0215, 0xff168548, 0xf1d78ba9, 0xb8bbddd5, 0xa2d91500, 0x081b6874, 0xa9500596, 0xa61de22c, + 0x7a80b063, 0x72c31398, 0xd2ec0c55, 0x0a20600c, 0x9e117f19, 0x1e001e23, 0x61f8be6c, 0x4def5e2b, + 0x19090b72, 0x6123a91b, 0x1323a6fb, 0x6f89f752, 0xb24011eb, 0xbd010710, 0x3f57c27e, 0xb86ceb16, + 0x9cd4b9fa, 0xf4e8e1f1, 0xcd392fcf, 0xe2578579, 0xd3dad04d, 0xbbd7612b, 0xa6fe6881, 0xe9adcece, + 0x1aaba536, 0xd6b3285d, 0xf430be3a, 0x787df6fb, 0xd08e660e, 0x8270edfb, 0xcd58b0c9, 0x2f8dac19, + 0x3d0618e6, 0x28342aaf, 0x77a83913, 0x58c0070c, 0xa0c1e585, 0x56d6dc7a, 0xcf4df122, 0x873d238e, + 0xb1905356, 0xb392210d, 0x51073e20, 0xd57da9bf, 0x5305538b, 0x36affe2c, 0xc915e3b4, 0x159be072, + 0x42e9eabf, 0x0ce2a966, 0x58945596, 0x249714e5, 0xf5922088, 0x9754bfa3, 0x71264393, 0xa1e45281, + 0x62bae9e1, 0x05a1af6a, 0xd8f957a4, 0x896d9712, 0x426d54b9, 0x30736c69, 0x824594a2, 0x3ee02830, + 0x3939db06, 0xa2b17026, 0xf82d8fcf, 0x282cd9a1, 0xfcb19fbd, 0xabc2a30c, 0x4f090a79, 0x903dbc3e, + 0x3b8c15f8, 0x482f4d90, 0x891d88d6, 0x2321db18, 0x268202cc, 0x1fdd7681, 0x12f209f4, 0xaf891f08, + 0x13f8f1de, 0xb64d24a2, 0xe0f04b26, 0x358c87a5, 0x29bd95fb, 0xd5d8a280, 0xfc45d9c2, 0xd81d79b9, + 0x731df861, 0x8fa3a008, 0xe6b40564, 0xc4352900, 0x755e8529, 0x135638bc, 0x5838fb8a, 0x60f13515, + 0x7227f71f, 0x019ea425, 0x2e859239, 0xa3b51532, 0x3a132b58, 0xd6dd8b04, 0x1eb39a7f, 0xdb2ee386, + 0x51a50b1f, 0x238ed758, 0x6a3ebf47, 0x07d1384f, 0x3df19716, 0x00f84f1e, 0xb9de991e, 0xbda91eb8, + 0xed7d48b2, 0x8e06d0cc, 0x0309e9c5, 0x46dc53da, 0x87984dab, 0x59b1ce22, 0x6ff7399b, 0x38d2e675, + 0xdd5dd834, 0xdd5f1a5f, 0x4720fb1e, 0xa79010fc, 0x7fa98653, 0x5f4deb5d, 0x956aa930, 0x4869cfb8, + 0x0a321d05, 0x53441b61, 0x8c1fd129, 0xad8e5586, 0x0699e1e4, 0x396c175e, 0x77dfcf17, 0xbf0b18fb, + 0xf68d8a2e, 0xba485d54, 0xab02ba21, 0x7bbdeb40, 0x1f8f551a, 0x3304bbed, 0x0649950b, 0xa8051c2a, + 0x75469be7, 0x822d4ad1, 0x8f48d5bd, 0x8ed4ce8c, 0x7f36e9e1, 0xf0fbba65, 0x28e63de3, 0x1fbe84d0, + 0xbf082242, 0xfacea92e, 0xaf9153e1, 0xdc6ab767, 0x9dec13fb, 0x44d21059, 0xd3956b4e, 0x06cddd2d, + 0x43e90700, 0xf5447239, 0xb568c16f, 0xa471037e, 0xfcce9080, 0x47189f0b, 0xd93a78aa, 0x92c01ea9, + 0x47f31550, 0x7ff498f5, 0x8069dc94, 0x73a876fb, 0x90e060c6, 0xd4902170, 0x028645c1, 0x78a0b158, + 0x02c42eb0, 0xb9b78456, 0x1f222ef7, 0x2c9a38ea, 0x897b53ce, 0x0f5fd599, 0xa2e765a8, 0xf40e1e33, + 0xcbafcb43, 0xfb3bd8ff, 0x7ae93e5d, 0xdc81a199, 0x1a97ef8e, 0xebc55cb6, 0xb036ccb9, 0xa4a01560, + 0xcef002d8, 0x0214202c, 0x31ce74de, 0x2c892e39, 0xe2b46e75, 0x4ee1c8b5, 0xff4130b1, 0x3244a670, + 0xfcddf9b8, 0x37ccd4eb, 0xd09ea0e1, 0xb15aa3b1, 0xea42b9ab, 0x94ff97b3, 0xf4c1f85e, 0xbae56f25, + 0xa98a297a, 0x54958e4b, 0x9aa035a0, 0x0e384366, 0x6bed5874, 0xfce78348, 0x8c21c9a4, 0xf23fb25e, + 0x4c395759, 0x3b140305, 0x4bd37ac9, 0x52fa962f, 0x27293568, 0x2ebab17c, 0x07e087e0, 0xeb7c08a2, + 0x4ce28989, 0xee76abf2, 0x39217f99, 0xbaabed6c, 0x9e4fbcac, 0x9912d45d, 0x8e756468, 0x60645f84, + 0x3de86e05, 0xa1869c9f, 0xe0ecad38, 0xd3cfd464, 0x286572a8, 0xedd65867, 0xa50c0a59, 0xf30e2af9, + 0x2c9ad6f2, 0xa45951e1, 0xe6281644, 0x5dc2f65c, 0x4844e89e, 0x3b42c83a, 0x574c05bb, 0xf6fa8ac0, + 0xab2d2f19, 0x0219dfbb, 0x0e237f20, 0x4f940956, 0x872ec1ac, 0xb2cfa35a, 0x360d0cd5, 0x10f14728, + 0x8e95bfa6, 0x0a883e11, 0x55eb2e79, 0x12079afa, 0x32255c42, 0x50d97d97, 0xcd6a5389, 0x0f7a1259, + 0x354a6c27, 0x6a07a2a6, 0x9fafd51e, 0x3e5e45d8, 0x9a7d1938, 0x4d89bd73, 0xd4c9f451, 0xb3521524, + 0x826b456a, 0x485583d5, 0x377c8bab, 0x86ca6990, 0x54cc568d, 0x85650291, 0xb8fce44d, 0x4d5982b3, + 0x552c072b, 0xc31fbf6e, 0x0d2cbafa, 0xe1ea3c9b, 0x3ad1a457, 0xcb969224, 0x9e86cc09, 0xdc56c000, + 0x29405919, 0x44194f55, 0x2c8df24a, 0x74709155, 0xaf792ac3, 0x44090315, 0xf3c42ade, 0x054c803d, + 0xb8507ce5, 0xbc68727b, 0x01b23c35, 0x6676cc38, 0xc891a9e8, 0x236b8f49, 0xe0137197, 0x87d35fa3, + 0x2a207ce4, 0x119d0099, 0x20376eb6, 0x13697e3d, 0x1f946e88, 0x56df8cb2, 0x4f55f403, 0x49c30c30, + 0xc383786c, 0xc2b72b8d, 0x4efd9ff5, 0xf741b128, 0x32ca7bfb, 0xe4e4302e, 0xf79492cc, 0xff7d2488, + 0x9a121d2f, 0xa4ffbb9c, 0xa7f4cd97, 0xb401e48c, 0x2888f994, 0x353fd297, 0xeee9f67b, 0xeec3720c, + 0xcee6166c, 0x5a5ddd2d, 0x07982d7d, 0xa235b24a, 0xed7e089a, 0x120e782a, 0x49c55e86, 0xa96a10a7, + 0x204e4ceb, 0x9bbdca9f, 0x19aefd27, 0x8fbd95c4, 0xb73be6ba, 0x1f54539a, 0x01e06ec0, 0xdc33b165, + 0x682ddbab, 0xeacbb0b1, 0xfbfcec03, 0x25f93bf2, 0xf371d5c7, 0xa8d8da70, 0x85be9fb3, 0x2a1269ab, + 0x25ad375e, 0x318ccb1d, 0xbef0c85c, 0xf6d4d79f, 0x9077ed48, 0x0f403d9a, 0xb55c305a, 0xb8540168, + 0x8b8cecd6, 0x8a169114, 0xe9e841d4, 0x67d7e6ff, 0x2b4d985d, 0xac6e8a5c, 0xd1d9b149, 0x86511800, + 0x0aecec3f, 0xaf5d97c1, 0x4fe37937, 0xd11bc958, 0x1bd01e32, 0x21b90582, 0x86957816, 0x4f4ec0bf, + 0x740fe561, 0xc474a333, 0x24445118, 0x26f3b896, 0xabc18637, 0x6c64318d, 0xc8585ccd, 0xd0fa8295, + 0x1dc6fe4d, 0x7c04fe0e, 0x5306cd87, 0xc8efed60, 0xc5dcf239, 0x39842076, 0xd4d99e75, 0xd03a5662, + 0x5ef86787, 0x6df94acb, 0x1d06e4f7, 0xa63e7a21, 0xad6af020, 0x4e6500ac, 0x633d3812, 0x82ec3d0a, + 0x8df761fb, 0x8d0ebdaa, 0x4d308a51, 0x2b1ffcd0, 0x05e64954, 0x12a0a2f7, 0x87aa4c62, 0x4eb74e8f, + 0xad2c3471, 0x35921b21, 0x92004c3b, 0x8f3a8a1c, 0x011533b8, 0x148a23e8, 0x4a36fe24, 0xeffeff2d, + 0x8709bb1e, 0xe4835584, 0xfe347484, 0x458bfccb, 0xb1d77a9b, 0x66a96df3, 0x785e9a33, 0x3ac48696, + 0xce68a625, 0xda8cde28, 0x85693113, 0xe14c5e7a, 0x59f817c8, 0x85e5f77f, 0xf89bcb1e, 0xc8741f18, + 0x70412487, 0x27fd16ed, 0x5b070633, 0x80b0eebf, 0x54d4248a, 0x4cb82c98, 0x0efcab09, 0xe635b7d4, + 0xb0acbccc, 0xbbdb8ba5, 0xb3c9345d, 0xa771017b, 0x3c65a481, 0x604be043, 0x2a7e3156, 0x12b2c8ec, + 0xfebd6854, 0x0340d10a, 0x9e321265, 0x6d3cbc66, 0x68c5b4c6, 0xa27f4675, 0xb488c417, 0xc7494d9b, + 0x970d4000, 0x66604461, 0x4582137e, 0x4b5c8881, 0x3cba7601, 0xee52043c, 0xa8cc7d5a, 0xca62b801, + 0x12929246, 0x6a81ae64, 0x1bf0cdfd, 0xbe557237, 0xa987c49b, 0x771d8c1f, 0x4a3f679a, 0x1dfddfc5, + 0x31fe719f, 0xb9b699f8, 0x715a3788, 0xcb6d8ffa, 0xfacdf6b2, 0xd843603e, 0xf105249f, 0x4297adf8, + 0x2ee89cc9, 0xb5d30bb1, 0xdf503a9c, 0x4bfb23aa, 0x9f053ae9, 0x4e78e2d7, 0xe4d33174, 0xb88fc6fc, + 0x157a8260, 0x4d7a081a, 0xac2f693c, 0xee5f9cf1, 0xeb670b00, 0x3831a958, 0xcda585b0, 0xd1f622f5, + 0x948c3594, 0xe80a0676, 0x5aa51918, 0x00085994, 0xf2c9698f, 0x445616c2, 0xfbf9c9ff, 0xe502c3c6, + 0x3adfa6b6, 0xec29a1ed, 0x5bc28a97, 0x31086415, 0x1f5b922e, 0xf40b5384, 0x7dd93e48, 0x74894242, + 0x0e5a26ac, 0x44fa41f8, 0x5c1eb214, 0xc5944a3f, 0xbd14766c, 0xc5c83843, 0x581efadd, 0x06a8a6c0, + 0x1f66a75d, 0x631df1bf, 0x5d148ba5, 0x431084ad, 0x73a3d36f, 0xf1a75704, 0xdc262aeb, 0x696a3151, + 0x6638caa4, 0x6152f03b, 0xaa45a5a5, 0x14cfa934, 0x04881790, 0xa1a5b8e4, 0x5e1f2a54, 0xc405a666, + 0xb6617d38, 0x1aa94600, 0xa33253c7, 0xb25d614c, 0x7ca27b38, 0xa9462d9c, 0xd5ef2a7b, 0xcbcb35b1, + 0x357cb2d5, 0x88102760, 0x77b77abb, 0x6e8cc6a4, 0xd20f76fd, 0x46d10103, 0x1c213c5e, 0x692c2ab5, + 0x6774472a, 0x2eccb066, 0xf10d3859, 0xda43915a, 0x37076bba, 0x0701d371, 0xcc8d0d42, 0x3c8220e7, + 0xa4b85957, 0x5c363c98, 0xc1f0106c, 0x0497ffe3, 0x62f41b7a, 0x6a53e435, 0x2a378dd5, 0x59aaecd1, + 0xe9482854, 0x38347470, 0xe9786316, 0xcd668aea, 0x91ce7caf, 0x8fe63850, 0x6c9eb42b, 0x4f76560e, + 0xe9376a98, 0x57bcc8c9, 0x67478a51, 0x112fa2a1, 0x472452e5, 0xaa54cc70, 0xc480a90d, 0xcd224bdc, + 0xc8de6fb0, 0xd6cac942, 0xab6f262f, 0x22989010, 0xa64b3e42, 0xe4e82db1, 0x6d2d7cd7, 0xcecad929, + 0x09d9bd13, 0xdec3462a, 0xb030311a, 0xfd840a62, 0x5aa3b611, 0x5f479b72, 0xbdb14393, 0x0d58f669, + 0x94ec103f, 0x9b7432d7, 0x05ffca37, 0x2635c1d8, 0x4c3691e3, 0x5e382f75, 0x3693062e, 0xbd72ad80, + 0x9e85d8c4, 0xea76bc96, 0x4a2d3924, 0x465a8dc6, 0x5f6ac7b3, 0x0ce46601, 0x7e7c6b54, 0x3703adde, + 0x848b820f, 0x0c90c90b, 0x4a1cd648, 0x82324b38, 0x7679d61e, 0x8286785c, 0x5c6e15d6, 0xc00a7600, + 0x6379c515, 0xd4101c33, 0xe6aa0310, 0xf3ee2201, 0x1a408be9, 0x99838057, 0x148719a4, 0x94a5f3d4, + 0xa242960c, 0xd3204445, 0x7c4dfd46, 0xd2ae9e69, 0x8475c6ec, 0xa74c7a11, 0x05e71516, 0xcd82225b, + 0x4029fec2, 0xb5ed07b1, 0xe1cdd322, 0x6256ed7c, 0x1f8bd5d5, 0x0e754581, 0x8ea5a93e, 0xcc07be57, + 0xfcd4e266, 0x6f2f8a96, 0x1072af3c, 0x9c5afa21, 0x12d5632a, 0xc0a49ef6, 0x2d9cb55a, 0xc0804d6f, + 0x2fb1fcad, 0x5f74845a, 0x3cee6378, 0x127530a0, 0xed20e47b, 0x762a0687, 0xba9bbddc, 0x36b1fd53, + 0xe2c10d07, 0x543112bd, 0x64137e21, 0x2dae3c80, 0xd0980acf, 0xf910b5f0, 0xd7603c8d, 0xffb1cf92, + 0xca6d05e1, 0xaaeff6f6, 0x48295a09, 0xa5ae773c, 0xc3aa5773, 0x2f709bd6, 0x400febc0, 0xda6b1234, + 0xaec169d7, 0xafddeef6, 0x06c5fe7e, 0xf0299462, 0x72b90952, 0xbd7a3ecd, 0x8633b6cd, 0x77135202, + 0x8ac7cda6, 0xc1df0ac7, 0xa817cb53, 0x6def8c8b, 0x69976f75, 0xc6ec5cca, 0xbf09712a, 0x2843c17a, + 0xa3bdf782, 0x454cf249, 0x706a65e7, 0x2a0bbb7b, 0xe87b1982, 0x2d1fea90, 0x03a5c29d, 0x3c9f2ab4, + 0x1278ff03, 0x4577d621, 0xc77ee029, 0x23f16fc3, 0xc7fed0dd, 0x4a83e593, 0xc48412d8, 0x402ee631, + 0x3c641e36, 0x0d456bdc, 0x33cd284d, 0x2a2b83f5, 0x5b6612c9, 0x12374cc8, 0x8a6d3a5b, 0xf502128a, + 0x807a8ffa, 0x4e1b9626, 0xc9d35c60, 0x3b50d742, 0x4abd1851, 0x3c027e49, 0xaef0d988, 0x2d44f1b4, + 0x11f85b92, 0xf2bddede, 0x0adc969a, 0x6c499cca, 0x23e9214c, 0xd7cc8958, 0x845c5b30, 0x38e8770f, + 0x0ee649c7, 0xa686a1b2, 0xbd055e11, 0xb220c18b, 0x702a8d64, 0x812119d2, 0xd8435e59, 0x9a10ed10, + 0xefe338af, 0xdfaaebbc, 0x53511c73, 0x6fa125e3, 0xc5139a9a, 0x3f920cfb, 0x777f7bc8, 0x6065a1c1, + 0x6c3bcdb9, 0x84e16659, 0x64665e4d, 0x4c87601a, 0x1ff89a4c, 0xc314e2d4, 0x038d5134, 0x1e8be4b1, + 0x84f490f2, 0xfc0ba6cd, 0x96a6cff5, 0x314c7303, 0x4f48e31f, 0xafbbda3b, 0x47a1cf3a, 0x7e1a2943, + 0x9e1328a6, 0x9ce1715c, 0x3a6d9fac, 0xdfb2a69a, 0x4e67106b, 0x719be034, 0x9fe6a958, 0x08a595b7, + 0xba181f81, 0xb5f1107d, 0xd09c59f0, 0xbe5a8e3b, 0x34afb627, 0x7ac02259, 0x58674fad, 0x08396ddc, + 0x73e3608a, 0x97d60f7c, 0xc24d0550, 0x08b58f9f, 0xb037a3b1, 0xaedd76c7, 0xfe5da4e5, 0x555b74d4, + 0xa08b9a90, 0xcc28acdb, 0x0eed1dfb, 0xff596b67, 0x4837dfbe, 0x44b906b0, 0x46092ed3, 0x554d1204, + 0xa4fe1610, 0xcc957bdd, 0x1a72ab7e, 0x71795bb3, 0x44d6877f, 0x93ff1311, 0x0802ed52, 0x0b25a352, + 0x98b4b5f2, 0xba89d99f, 0xb0766791, 0xe6591cc8, 0x5311b232, 0x0d1ebf16, 0x69d1cd70, 0x4e4e9caf, + 0x2fed3f3d, 0xaee2a85c, 0x5471fb29, 0x7a00b4e2, 0xf90ed3e4, 0x712141bc, 0xca6a4d38, 0xf2c10727, + 0x9a563a16, 0xe2cf7fdb, 0xff91185d, 0xf7041064, 0xc4b3861e, 0x12ea7c79, 0xbf9aa00f, 0x37588273, + 0x2dc53adb, 0xcdf2a743, 0xaa2bb20b, 0x2bedca6d, 0x1b8d4778, 0x9af5f80f, 0xb7dd9af6, 0xead96d58, + 0x2c6f00b0, 0x545d09d5, 0xa502285b, 0x1ca6b927, 0x0b0e8428, 0xfa758922, 0xc3b2c46a, 0x22f5b595, + 0x9148bc04, 0x98fff322, 0x49765ca5, 0xe242fae8, 0x25e52bfa, 0xad4999ff, 0xdb45a6c8, 0x3bfea4ec, + 0xc9f4a531, 0x264862d8, 0xaa5cf56a, 0x6f991dd1, 0xae0a5339, 0x366916fb, 0x38237ef0, 0x1615992e, + 0x8d40b05e, 0x1ac8bb20, 0x8dc201f1, 0x5c8c6393, 0x337db9df, 0xdcfd1d6d, 0x151b96f1, 0x69c480ab, + 0x57c244e3, 0x4ddb52ef, 0x89213f37, 0x25af7156, 0xdbe1ac39, 0x9810aae3, 0x9d2b2e5b, 0xe39f132c, + 0xdcb20623, 0x32ffffa2, 0xf4235c36, 0x02ad2f0f, 0x9c6f3e94, 0xe64a18f0, 0x3a2ae570, 0x2d62cd2a, + 0xc452604c, 0x8ce0b318, 0xe9c9a2da, 0xaaceabb7, 0xd8d7baa2, 0x20376fa2, 0x0b426ae2, 0x8ec0e00a, + 0x9594966a, 0xd1006b85, 0xe36a73de, 0x4f8fc38f, 0xcc14b444, 0x26485f9b, 0x61b01fdb, 0xa25c653c, + 0x0c998b8e, 0x148e007b, 0xaa244b5a, 0x422d4b62, 0xa0833a95, 0x6c9687b7, 0xebb902be, 0x70b5a1bb, + 0x823e04a1, 0x9eef5ba7, 0xae80621d, 0x51124a10, 0xb940c274, 0xfae9fd10, 0x738fa445, 0x780a3ab9, + 0x4e349a67, 0x44de7189, 0x7e1f495e, 0xd4684dc0, 0xcf01c803, 0xf385d05c, 0x5628b70d, 0xbf2e25ae, + 0x40ec3fba, 0xf9c9bec9, 0x74ad5511, 0x5219212e, 0x44d5ca27, 0x76ebf350, 0x02542508, 0x69f2693e, + 0x95e427d4, 0x0fcb525e, 0x17976e47, 0xb01564af, 0xcf59e071, 0xb62743f2, 0x761a3ca2, 0x71d23f41, + 0x34370749, 0x3213054d, 0x3a8408bc, 0x98cf2e26, 0x879dc2e3, 0x1c1f89bb, 0xb7fd5d1a, 0xc2e097ac, + 0xee5b9c87, 0xbcd9dca6, 0x9aec17b3, 0x9f6237eb, 0x65312052, 0x1e50f0fd, 0xd29b0a92, 0xa370b6ca, + 0x9463a169, 0x5d12075d, 0x2ec898aa, 0xc803c46b, 0xe96eda2e, 0xdca65695, 0x9ac90477, 0xe3db7212, + 0xae197466, 0x83cc3fdc, 0x18df199b, 0x8ca32940, 0xc915dde7, 0xeb65eaee, 0xfec2e714, 0xff7e4816, + 0xd7c24ab6, 0x37431ccf, 0xc5b65324, 0xd1a7073f, 0x61d87007, 0x7b0ebb05, 0xde159a8d, 0x708346e9, + 0xba70127e, 0x01b7ba9e, 0x7368352e, 0x664a0399, 0xddb52c02, 0x87f0ab9b, 0x8a16681b, 0xa918673e, + 0xd7d04cf3, 0x5d891067, 0xc30e8b4f, 0xc090c4eb, 0x1435997a, 0x846952cf, 0xbd3e734e, 0xb8ba2662, + 0xcd89d8fb, 0xf95e9b2c, 0x5fcad23a, 0x75382075, 0xd96bc565, 0xc1fd26c9, 0x954c3e23, 0x01caec5d, + 0x8a4a8e0c, 0x4b3cbaab, 0x7588d84b, 0x0a194e2a, 0x01a96ed7, 0x01fc676b, 0x11dd29f1, 0x0038e37b, + 0x96161871, 0xd03153ea, 0x0c8c3a8b, 0xd91c303f, 0xcf45ca97, 0xef6827c9, 0x2758775d, 0xd139451f, + 0xaab4638f, 0xa636b882, 0xbd101af5, 0x2828f53a, 0xa9465fb7, 0xa8a6e61b, 0xe4a2ddb8, 0xf0486eff, + 0x370334c2, 0xde45a4cb, 0x2ade04f3, 0x142a71e6, 0x9b82eda6, 0xa4a53570, 0x00ae17b0, 0x2e2d806b, + 0x6260c55f, 0xad8eaad4, 0x4cfb482c, 0x6d091ab5, 0x47453f83, 0x981c28a5, 0x1608b142, 0x5b2cae04, + 0x75a745cc, 0xa085211a, 0x8c858496, 0x82fc851d, 0x1a80a801, 0x36269095, 0x96ab8110, 0x85abef15, + 0xf4215690, 0xbcbfd553, 0x8b3f9330, 0x5bbcf556, 0xbbe1ebc7, 0x8e587834, 0xddb5981c, 0xb826b803, + 0x3d42e7f7, 0xcd8279be, 0x13791e04, 0xdc1825c0, 0xb34d00ac, 0xf3b15eb3, 0xf35f3cdb, 0x517dce3c, + 0xa4dfa7ce, 0x3a4273fc, 0x2fad6713, 0x1ecdec94, 0xe9ab3040, 0xca67a8e1, 0x0edafcf0, 0x9ec910df, + 0x74fcaf5f, 0x9b2e7d6a, 0x0181810f, 0xb19ed0ba, 0xf2d94858, 0x5e9e5daf, 0xd406b452, 0x8eeaeef7, + 0x8bc4bb4f, 0x274a5959, 0xf3c526fa, 0x1d02fad3, 0x0f0245fb, 0x6278d625, 0xc27fc22d, 0xf55f241d, + 0xad337ed5, 0x1ded1ae7, 0x9206f23a, 0xa6459fc8, 0x9666fb2c, 0xd16b1fa2, 0x7dd7b90e, 0x8fc6b604, + 0xa9040196, 0xcb9c518c, 0x609c9a80, 0xda5458a8, 0x14e8f21e, 0x85fa125a, 0x62c94c66, 0x6e8ccb73, + 0x7517ed1b, 0x29479b7a, 0xa480644d, 0xb82bc923, 0x94dad5b0, 0x591accc6, 0xf6cc0eb6, 0xf1b9747d, + 0xa4a96e16, 0x4118f2fd, 0xc5f2b5f5, 0x00176f4a, 0x05285081, 0xce505ecd, 0x16e06473, 0xe192d036, + 0xb51bb0b1, 0x7d185313, 0x5c0cd276, 0x2c5e4be9, 0x3f6aaeb5, 0xd40ac871, 0x13dd92ec, 0x62fca1c4, + 0x60ff3ff1, 0xf73d68a1, 0x887e9e56, 0xae68dd80, 0x6b1dec8d, 0x4dc88ecc, 0x5de8de52, 0x717004c3, + 0x4a212949, 0x4cebc23d, 0x670fbdc6, 0x416aa4bb, 0x1e388dbb, 0x0ecd3a63, 0x5af5a1c9, 0x15d3c8d5, + 0xb012f1a8, 0x86fd39e4, 0xd1972801, 0xbe91aa4f, 0x323067b3, 0xb120c8b4, 0xb6d60f42, 0x2035834f, + 0x92b8aa56, 0xe0a4a72f, 0x42b4f296, 0x8372f7b3, 0x2dd9e6f3, 0x8ad281c1, 0x7ceea4fc, 0x9089eff8, + 0x1c166645, 0x2cb625bf, 0x6e42144b, 0xbc5eb1bf, 0x8baba2b8, 0xb0276177, 0xb31bc91d, 0x140cb06e, + 0x968e822b, 0xeba73c50, 0x57866443, 0xcaeabc42, 0xae87fa13, 0xf14d7682, 0xebf164c4, 0xec5f2148, + 0x19363de7, 0x5a085fcb, 0x3a2d721c, 0x579286d6, 0xac1a34d2, 0x23f0073f, 0x51dcf76b, 0x6205184f, + 0x6a5a2dfa, 0x3a4bae89, 0xa116a376, 0x3c3f204b, 0xe716b775, 0x8ac8a967, 0xdaa67e51, 0x7330aab3, + 0xa58cc003, 0xdb33971c, 0x2386cbcb, 0x885dccf1, 0xde1d75f4, 0x26b1f405, 0x7dac7fbe, 0xb51870a1, + 0x57857904, 0x30f6ad15, 0x626e2d55, 0xd9d63d6b, 0x76c15e90, 0x1a0e9bf8, 0x5cb167dc, 0xd964336e, + 0xe0dfcaaf, 0xf529f106, 0x1573cc40, 0xf6660b94, 0x5615ef0a, 0xf33d5521, 0x627881d6, 0x708d9c42, + 0x5f756cbc, 0x0a6f9824, 0x9a9daff3, 0x77f31215, 0x491e6da5, 0x5028e7b6, 0x8fc407b0, 0x1630b036, + 0x1ebee7aa, 0x4b93556e, 0xaeb792f4, 0x571b1cfd, 0x66799a0a, 0xb8b72dce, 0xe0a3a66a, 0x90d5bdce, + 0x681a9571, 0x5120945b, 0x1368a204, 0x52844806, 0x489c139d, 0x7742f07a, 0x94d52624, 0xea67ace5, + 0x8a2a5b13, 0x434d2f87, 0x8377e334, 0x77387bcd, 0x1e288f2a, 0xe988a463, 0x5db98414, 0x2e8b4536, + 0xde81924e, 0xf9e1f9c1, 0x653a4827, 0x4a61d4cc, 0x0f7fc44a, 0x86bf60b5, 0xf12be351, 0x5529d571, + 0x3c2f18f5, 0x14a9c3b6, 0xe0f7c7f0, 0x765bd5e4, 0x689fa222, 0xc690975a, 0x7acd7c65, 0xfc0262ff, + 0x29ac9870, 0xebdeb43c, 0x25aee549, 0x43044021, 0x93b180a0, 0xbd159345, 0x426bb6a6, 0xf6272672, + 0xb63680a8, 0x7762fe1a, 0x29388033, 0xe05cc7bd, 0x97bd0bbf, 0xc08bfb40, 0x0dc18e14, 0xa745ef26, + 0x401ff2af, 0x4738c9a6, 0x6f7a29db, 0x97cebb66, 0x42f9cb8c, 0xb1899d4a, 0x4c83edac, 0xf4c8994c, + 0xb563fac8, 0x70e19231, 0x7cb53e55, 0xdefa756c, 0xd7786869, 0x96ef63bb, 0x98805768, 0xbdd835e6, + 0x381b47a3, 0x938faeea, 0xc5e60be3, 0x715ff530, 0xd3716a80, 0x69352300, 0x4c0ceebe, 0x90d0ab47, + 0x03229ac7, 0x200a09f3, 0x1ada8b57, 0x2c7477df, 0x718f33f8, 0x121cf4b4, 0xea8ecec1, 0x582dd441, + 0x2aad5e88, 0x1e18d795, 0x18684ad8, 0x950f55f5, 0x113212e2, 0xfb45a2c8, 0x8cd954b7, 0x824077fc, + 0xf45b4fa4, 0x8c9a86b9, 0x1e18d504, 0xfc6c8ec9, 0x594a58eb, 0xc0aa10e1, 0x9bc635b0, 0x3679eb64, + 0xbb49077f, 0x2a18014a, 0x30f42534, 0xe416b470, 0xdaad8180, 0x9883f2ce, 0x1c0b9215, 0x4d71addd, + 0x3ce808e9, 0x60edb496, 0xcd0a80b4, 0x8cd3bce8, 0x169ab903, 0x653a5f47, 0x5aed5a12, 0xb6ce0fda, + 0xde8937b7, 0x72356cf6, 0x1084fe4c, 0x6af65e72, 0x4d81bd3f, 0x2f426156, 0x97618108, 0xb7187b03, + 0x1d0fb0ed, 0x4636f5d5, 0xf2ffed01, 0xbbb25d13, 0x6ebe5a56, 0x5551b134, 0xdca9c015, 0xff18ca95, + 0xb9d595a1, 0xa74a4f56, 0xc2b81cef, 0x4431c339, 0xddfc0fb3, 0x674ff6a4, 0xb15e71e4, 0x9c303633, + 0xa8288043, 0xc768f048, 0xbc41d9be, 0xa2155182, 0xc7f7e74f, 0x469d4956, 0x26002f27, 0xb238b63f, + 0x3581439f, 0x925c3e25, 0x85c46f27, 0x3bcab133, 0xeb2f8aa8, 0x1134e8e5, 0x7f18cfb1, 0x44e82e46, + 0xe3ca2954, 0x1ef39027, 0x50077600, 0xe30553e6, 0x94e6113e, 0xe8e6c5e0, 0x49397d72, 0xe9ea77fa, + 0x50840f6c, 0x25c936da, 0x8e9f4209, 0xdddd3836, 0x061fbdfe, 0x94f86415, 0x8bb85f06, 0x913893ee, + 0xc389c356, 0x4943f2e1, 0xffce64ec, 0x5c162f2b, 0x80d19e41, 0xbc40cc6f, 0x5cc8f15e, 0x12ec508e, + 0x8c8d572f, 0xe164009b, 0x3d759365, 0xcffbe569, 0xbaeb4a72, 0x891e6f30, 0xeb008c24, 0xa29af88d, + 0xc67e87c6, 0x4d6b6ba6, 0xde88113a, 0xbe32434e, 0x768a5c30, 0xef88f22d, 0x20c27e46, 0xda6344c6, + 0x6ecfadde, 0x560f9487, 0xb704f2ea, 0xca16f943, 0x1f316269, 0xf6e27efd, 0xd797b8b4, 0xce9aa65c, + 0x0016dec9, 0xce6d5f23, 0x0c1061af, 0x3264778e, 0x00e8638e, 0x83408907, 0x5c4133dd, 0x27d1d103, + 0x0fa29416, 0x5f60ea63, 0x6abbb96e, 0x8a61aa1c, 0x0a03eeac, 0xdf938364, 0xf7d7efaa, 0x23f1a314, + 0x06264919, 0x039a6ffc, 0x5d18ab53, 0xa9f7fcab, 0x25720105, 0xbc0658bb, 0xaaf8f0ec, 0xa61dcd79, + 0x36d843c4, 0xb3e23ecc, 0x9be126f4, 0xf33fac69, 0x26fb4a21, 0xe5d31a6a, 0x4c346dbe, 0x34c58fff, + 0x45ef7e95, 0x92661702, 0x49175d24, 0x4cbf33e6, 0xaf07faa2, 0x8b66c019, 0x9d2dc428, 0x29c9e1a0, + 0xa485092b, 0x2228e493, 0x57b6093f, 0xab1383d4, 0x148a0a98, 0x149a94ea, 0xa553e86c, 0x5dc24048, + 0x641a58f9, 0x598e102c, 0xdbefafe8, 0xcb5a280d, 0x5479532e, 0x7cc735e5, 0x0ffc3287, 0xe372d72e, + 0x189817ea, 0x5e52552e, 0x167c1cea, 0x6e8c27a4, 0x53892e50, 0x659e59c5, 0x11701b64, 0xb72b5995, + 0x5a44c802, 0x192636f6, 0x216ceb13, 0xb844ffa6, 0x09fb9859, 0xe3e066ec, 0x14b0d2f1, 0xdf56d03f, + 0xac61d978, 0x4e740f4c, 0xb9a586cd, 0xc5db2329, 0xb26c7712, 0xff8a1ce5, 0x7b04f758, 0x20032d81, + 0xece7c08e, 0xeadcfa01, 0xef7b3589, 0x58c596da, 0x8db4701e, 0x360c172f, 0x698d34a3, 0xd659d3f4, + 0xbc027d64, 0x951318cc, 0x2cd81593, 0xb497fc0c, 0x4f4a1d82, 0x2380d708, 0x7b32126d, 0x30004dbc, + 0x9e851215, 0x5c26549b, 0x1e1eeb07, 0xd4fef732, 0x07da47c3, 0xcbd43f74, 0xa00d8119, 0x4de45932, + 0x5ba3def8, 0x4ebad220, 0x81664779, 0x11f6511c, 0x4e4f77f7, 0x2b5655e4, 0x2fd1a0fd, 0x69330835, + 0xea098705, 0x12965514, 0xe925baa5, 0x90ac9dfa, 0xc443c45f, 0xbf67b34e, 0x5fa12488, 0xc8c4fd5e, + 0x027564cb, 0xbfdb2d44, 0xfa45a529, 0x1b19b7b8, 0xbb020f2d, 0x2b87f83a, 0x20f81521, 0xec84047c, + 0x739f599a, 0xd7a716f4, 0x704b3780, 0xdf0f18fa, 0x174412ec, 0xcb8e40d0, 0x63ed0ab7, 0xf50e5468, + 0x60ddaebc, 0x5459a472, 0xa1f6fc08, 0xdac2ef78, 0x022cb6be, 0x1452465b, 0x6b1f67fb, 0xf3c8587a, + 0xf6f12f76, 0x7d9c2544, 0x7211ba9e, 0x0c7c2a89, 0x17a16fd0, 0xf8379dd1, 0xb722844a, 0xf62f582d, + 0xd48a510e, 0xe65346c1, 0x771561dd, 0x4571a724, 0x50548a7d, 0x2ff66660, 0xdfe8cb5b, 0x07db1936, + 0xc3533822, 0x3f033e4f, 0x4f08c09a, 0xffb9e417, 0xcb3e7c24, 0x0086b5d6, 0xc014c9b7, 0xf1bf6af5, + 0x6e404dd3, 0x2f507cc9, 0x72b3caeb, 0x86c9b165, 0x2efe7419, 0xfb349d33, 0x7c49b96d, 0xdd42c910, + 0xa2d2cbc8, 0xb894d979, 0x5f97288a, 0xc0d2547a, 0xab8ce868, 0x08c763a5, 0xf0235783, 0x425722fd, + 0x6f72099e, 0x0d44d511, 0x7f389097, 0xbe74ce63, 0x3db3eb8d, 0xe505928e, 0x09e46ebf, 0x35b4a9ba, + 0x2084625f, 0x1eaa10af, 0x44801c6e, 0x06a3cbc1, 0xdce34363, 0xbe468cd7, 0x2a40437c, 0x4ca1650b, + 0x7cda9495, 0xe8766b05, 0xb019c00e, 0xc48602d6, 0x4681b97d, 0x277f5cfd, 0x64eac752, 0xaf4c1962, + 0xc0f8fdde, 0xe323bd2b, 0x087ed83d, 0xf30b7617, 0x5f3e03ab, 0x520a18e0, 0xaf6038c5, 0xb9b30538, + 0x973b8d6e, 0x0b321e65, 0xbb87f556, 0x535d5dd6, 0x1d7e5c26, 0xa5ad8620, 0xd41bd392, 0x704e655d, + 0x354d959f, 0x4a030128, 0x5780e411, 0xbc7d0642, 0x844c9116, 0xd7357602, 0x14a30357, 0x18868cc2, + 0x51a50485, 0xd1999f26, 0x84405448, 0x8b313c5c, 0xc7931c65, 0x4f6bfac4, 0x0d5afbd5, 0x7280d045, + 0x8a2ce932, 0x813a8799, 0x7489caa7, 0x513558a8, 0xfec493d9, 0xaaaffab7, 0x6e67e7ca, 0x9ba3b77b, + 0x35f5c26c, 0x445db964, 0xacfa133c, 0x8c54f555, 0x3bc2f374, 0x96a8cbe4, 0x41ebd9fc, 0x4cf7165a, + 0x9b2712d0, 0x32066f57, 0xf8982389, 0xcbbff44a, 0x198f03de, 0xd53d7f67, 0xafb53977, 0xcd82ddec, + 0xa2571fa6, 0xda630e9a, 0x7b508f3d, 0x3f43bd7a, 0x26086981, 0xf814d2cc, 0xadb1aa4e, 0x9ad5a6b7, + 0x8c0eab32, 0x43a85fb0, 0x713dafbb, 0x3366f95b, 0x2b63ad1a, 0x779da30a, 0x09701fb5, 0xaebed123, + 0x8aed5c10, 0x888c0520, 0xd2887fe5, 0x54938d38, 0x8ec3c556, 0xf39d2df4, 0x32679611, 0xef1552b5, + 0xa7d9ef4e, 0x610bab44, 0x96733936, 0x4d60abc2, 0xca7a1e3f, 0xe0b43457, 0x474f0603, 0x04a87a6c, + 0xe0654f0f, 0xfc8c203e, 0x1762e53a, 0x7376f1e8, 0xeb98a2b0, 0xa8f4805c, 0x50774ffa, 0x46939bf5, + 0x015e98f5, 0x6fc4007d, 0x39b3060b, 0x420b2348, 0x1af99e18, 0xbef48cbc, 0xcac87ee2, 0x8204453e, + 0x54be4fc5, 0x88de11fb, 0xe36ee16b, 0x33f0dc28, 0xb651da65, 0xde8db4d5, 0x295551b0, 0x0940bcbe, + 0xbb09d09e, 0x93a21938, 0x5bf6ec24, 0xfb27f5d9, 0x4f6862dc, 0xca9bd111, 0xf6b4f055, 0xbf8bcfa4, + 0xf5bda4ac, 0xdbb2ede3, 0xb6920ba9, 0xeaa95cca, 0x3ffdab9c, 0xd82d95c8, 0x065dfff0, 0xc60c611b, + 0x8ab15067, 0xcb2eac25, 0x12a675c3, 0xfe1360ce, 0xf5037fb9, 0x03ddb1de, 0x193caf0a, 0x6c6cbaa8, + 0x8475e9a2, 0x7ca66248, 0x8b372606, 0xbe8f6528, 0x64cdfe1e, 0x7b69911a, 0x193dcbab, 0xdeb7d726, + 0x8b92cc44, 0xa51e2db7, 0x48190e60, 0x6a39b384, 0x1c37145f, 0xdda2a482, 0x4ea9dd4d, 0x64b0878e, + 0x1c9a4271, 0x563ffd07, 0x0cab2472, 0xc202798e, 0xb938e8af, 0x39f8ebe6, 0x9346c651, 0x1002779a, + 0xd7bee3af, 0x988dc238, 0xa0c7a9f2, 0x452ea83c, 0x92dffc75, 0x6ca4fa24, 0x91924c61, 0x6b9a4089, + 0x2fc8e1e2, 0xfa12aa1e, 0xa1f89bf3, 0xd097b411, 0xb1451a6d, 0x32a22939, 0x215479e1, 0x4720cc3c, + 0x9f835170, 0x41d40579, 0x7c700414, 0x6bf41a8d, 0x25917c1f, 0x5f7416d7, 0x5959f0f7, 0x918ff837, + 0x49a3610d, 0x0f393131, 0x77f03717, 0x0306bf28, 0xe0f521be, 0x7dab075a, 0xfac32456, 0x8a334c9b, + 0xaaa051a3, 0x3670fd4b, 0x75a6e005, 0xb33ba820, 0x5a546aa7, 0xb1c18b77, 0x52e75f91, 0xe06c7d52, + 0x4afe3929, 0xce3a7cf9, 0xc7f8663f, 0x54fc3165, 0x75276215, 0x62f78a15, 0xd04edfd1, 0x4084109d, + 0x9f4c5297, 0x36b9eee0, 0xf5495e70, 0xafd070b7, 0xbec25e22, 0xe07d7787, 0x32748f45, 0x13bcc8ea, + 0x27c7ee53, 0x28e14fae, 0x4081c3ad, 0xee496f6d, 0x850be104, 0x8c856417, 0x85c40d91, 0xc3afdea3, + 0x94794d99, 0x0932f07b, 0x49286d64, 0x22062b87, 0xa3618e2c, 0x2ce970d1, 0xd9829bbe, 0x9f18f901, + 0x906abc39, 0x684e8ef8, 0xd0aca6fb, 0xadc5d4ba, 0x3a456b01, 0x70037709, 0xc48e065f, 0x2b083cdf, + 0x069ff31b, 0x03c766fa, 0x885d91e1, 0xe7e06719, 0xfd0d3fe8, 0x6e3c2f4f, 0xef2b253f, 0x156bf6fc, + 0x5e407081, 0xf82f876e, 0xeaae6b01, 0x959c5e44, 0xce61f7f9, 0x8c9ce582, 0x22e05226, 0x3f8d77ef, + 0x67e1ad69, 0x8eb739c2, 0x6e697fd8, 0x596e0817, 0xcf2f65ec, 0x2e9eb2fe, 0xa9e00422, 0x072dd8d5, + 0x40a1a4cb, 0x9e9a9f5c, 0x0ddbc208, 0xa160e3f1, 0xaa8819d8, 0x68a2c701, 0xd4decc3c, 0xfb12c062, + 0x928eb404, 0x40e5a708, 0x3820e8b9, 0xbea3f8a1, 0x605fc28a, 0xb88f4e0b, 0x8470216d, 0x695a9774, + 0x52f67c31, 0x17513260, 0x9c9b7906, 0x9d3b972c, 0x87580f5b, 0x1e23acdb, 0xea3b9c74, 0x9a0b0d76, + 0x094d12f8, 0x7d56f34b, 0xbd403aa1, 0x7d4ef057, 0xf27b9031, 0xb6b781e5, 0x4554320c, 0x90f2603b, + 0x5f45ec27, 0x02994ec3, 0x481694d4, 0xf4732075, 0xd7e4b00e, 0x7c89f631, 0x310ab90b, 0x959e8bd0, + 0x6f97b6ea, 0x7dac9ce9, 0xc09e6069, 0xb735b2a8, 0x800efb11, 0x9c3de476, 0x48e490c9, 0x8766019a, + 0x9b6e996c, 0x50aa0cbc, 0x53dd2455, 0xb12752c7, 0xda0c136f, 0x12c9b4e8, 0xe55e811d, 0x4c7ce843, + 0x3a37ca89, 0x79ff1c88, 0xd535b185, 0x122b2377, 0x67e490c2, 0x1fc5d63a, 0x16978ab5, 0x64d39740, + 0x7f7ff252, 0x7f5bc9fc, 0xb0d29086, 0xe2659f8c, 0x731858b0, 0x51677940, 0xc9470e8f, 0xd896c7b9, + 0xfc128b16, 0xbf645dee, 0x1b2d4e13, 0xe226846a, 0xf664949e, 0xc81aa6fa, 0x76a103c2, 0x7afa8026, + 0xc7c9f699, 0x1969420d, 0xa4bcfebb, 0xa744aba2, 0xfd7a3b76, 0x9e34de42, 0xc75cdd4c, 0x56a52988, + 0xee2752b6, 0x84594590, 0x921c0b3f, 0x3240603a, 0xc8ee75eb, 0x101875c4, 0xa516e7aa, 0xb494f546, + 0x4251ffb7, 0xed427f4a, 0x312322eb, 0xd5bd3f99, 0x138be844, 0x7627c2ea, 0x36ba6ec6, 0x5775325f, + 0x6b1547bd, 0xe5d67474, 0x6a3728b6, 0x977e6e6f, 0x43e11890, 0xb606edc4, 0x97c14eec, 0x7cda9f04, + 0xd5918121, 0x52a55605, 0x282938aa, 0x2dddbf00, 0x5756a89c, 0xe1be4cb9, 0x6d1d86dc, 0xaae8b804, + 0x1815dfa1, 0x7291dc86, 0xcb407aad, 0xac7c24c6, 0x427a00c1, 0xa3f43ed4, 0xdb5056fc, 0x811eecb5, + 0xcb4b95df, 0x24b4cea3, 0x644dce9e, 0x4304b93f, 0x2a2012a9, 0x7b60f7fe, 0xe69e77fb, 0x41afe627, + 0x5b418dd2, 0xc6e121b1, 0xbe1c15ae, 0x6ec52480, 0x2b147ef0, 0xd9b25c28, 0x7b016907, 0x09571cae, + 0x67196640, 0xb906ec9d, 0xfeaad943, 0x9c9e88d8, 0x933933aa, 0xfc458b79, 0xd333ddc3, 0x0f61304f, + 0x46ba9cff, 0x78f1d8e7, 0x4a492409, 0xc5b6a9c4, 0x9431cac9, 0xa1287226, 0x0dbc0e28, 0xa7d17b8f, + 0x4c7b5129, 0x712b6dfb, 0x1257690b, 0x3ae97c0f, 0x7eef4d2a, 0xa2c0630c, 0xe642b886, 0x72e367a1, + 0xd8907e84, 0x254b6d9a, 0x8679e96b, 0xd6e2896d, 0x22a227e1, 0xdc065126, 0x1780c626, 0xa91c46a0, + 0x9e13399c, 0x71b7e367, 0x351a881c, 0x1be155a8, 0xaa551826, 0x70ffeac3, 0xeb9efa6f, 0xcba3e16c, + 0xc9126105, 0x291efa27, 0x9b30949e, 0xe00fe873, 0xd09f4986, 0x6338a802, 0x631b625c, 0x47846e71, + 0xbabb2de4, 0xe604e686, 0xeada47b9, 0x4c7be120, 0x3e034b24, 0xcf3a4b59, 0xbedfd220, 0xbc29ea33, + 0xa40b3c92, 0x52360f89, 0xff629033, 0x50ee1c2f, 0x04634d55, 0x88c059aa, 0x047703c8, 0x631f6029, + 0x10b07b40, 0x315a6377, 0x4ca7d446, 0xcf410548, 0x9483f9fb, 0x7ce5d7f9, 0xbe0df065, 0x0856a24a, + 0x3353d2fb, 0xcd16b967, 0x1ccb1821, 0xa465ecfc, 0xc4e1f62f, 0x07e3ce09, 0x48b7ff22, 0xeda92e1d, + 0xd7e9825d, 0xe8acae5b, 0xb4b4cc01, 0x0f04189a, 0xfa8eec7b, 0xd71a52ad, 0xba70ce12, 0xf6fdfa0f, + 0x3add0af1, 0xd874615c, 0x73587db0, 0x54be0cce, 0x06c5eba0, 0x088e1a71, 0x8237756a, 0x5bc9f0c7, + 0x62d355d0, 0x1996f4bc, 0x79035fe5, 0x2cc16c63, 0xec88f015, 0x486ecab7, 0x161629f3, 0x251ed715, + 0x0c80269f, 0x12800321, 0x865a9e47, 0x44c50800, 0xb38917b3, 0xfb2578c5, 0x047c7500, 0x1e271803, + 0x4e5a1575, 0x655562d1, 0xfeaf23ef, 0x8de716c3, 0x361ad907, 0x055dbe9d, 0xeab588e1, 0xeae739b5, + 0xe919f4e8, 0x3c3e20e5, 0x6c8d634e, 0x444b3839, 0x6d1c6831, 0xcf058a06, 0x83377ad4, 0x1e069deb, + 0x19c7f72c, 0x72c33555, 0xad494f26, 0xbc0f7311, 0x594fe43c, 0xb1f25b02, 0x958c4431, 0xd6ac0bdb, + 0xb58419b5, 0x23674dda, 0x8dd1b02b, 0x9d1750c1, 0xe07faa79, 0x24c7bd19, 0x5a09fc3e, 0x8cab8991, + 0xc7d01561, 0x3f9b448c, 0x61448dad, 0xa7a32f47, 0x4088a591, 0x2a0a1ad9, 0x15625cf3, 0xa2a3d809, + 0x4601266b, 0x0c450dee, 0xd8d3fcea, 0x2a9b498d, 0xa76d1bc5, 0x1cf45c4f, 0xa80a47e8, 0x3c2ee7b4, + 0x8ecce774, 0xb045a12d, 0x625374b5, 0x6a2e6984, 0x2b26be81, 0xf348af76, 0xf711ef96, 0xce5b6cf4, + 0x6ce75aee, 0x3e8a5851, 0xd75c7194, 0xb74a8ef9, 0x62493456, 0x3f89bf53, 0x2805a92d, 0xbfa68d17, + 0x7fd8c7a7, 0xcea436b7, 0xc2fcfc4c, 0xf605c63b, 0x7665205f, 0x08c0b150, 0x6fd8e557, 0xe8c8fa21, + 0xe8441a13, 0xf072fd1f, 0xe0293951, 0xa4addded, 0xcfdef195, 0xe3700a4b, 0xe795f6ef, 0x2582df7a, + 0xf0847627, 0x13eaf39d, 0xf10c0686, 0xb2359dcb, 0x7e321054, 0x29bb32af, 0x4a340e35, 0xe2dfa02f, + 0x1ffffcb0, 0x6ad71721, 0x08771948, 0x8319f2f3, 0x8e05224b, 0x47d53f70, 0x39defa85, 0x0093880c, + 0xec7fee03, 0x58fc8919, 0x50139377, 0x201002b6, 0x59834b29, 0x4b62453a, 0x2430e64c, 0x7465d975, + 0x3cf488df, 0x5d874e35, 0xfb1cfe4f, 0x0ca68c98, 0x0c22c7b3, 0x25629d60, 0x0334d321, 0xf56ff4ca, + 0xe3c94c1d, 0x3ccb53f3, 0x18a55970, 0xe209b823, 0x3b37a117, 0xb9dad3f6, 0x2c14efb2, 0xaa446863, + 0x23918eb6, 0x1a356b9d, 0xdfd43d6d, 0x765e8ce6, 0xe2c986bf, 0x10c7ad4f, 0x98993868, 0x138ddeda, + 0xb93658cd, 0x082cf58c, 0xba767333, 0x88520019, 0x960f2df9, 0x484f85f2, 0x2f075f2d, 0x2d7c3e6e, + 0xa4e944b0, 0x4f7a178f, 0xf1ce4061, 0xf7ded186, 0x573857f4, 0xeb1a5b3b, 0x551bcb7f, 0xd6da994d, + 0xae819361, 0x411651a4, 0x54a5f374, 0xd99f50d4, 0xd2c7a522, 0x1ef86e69, 0x5563304b, 0x9720e923, + 0x11826892, 0x7aa24fb3, 0x2fcbc142, 0x9ced017a, 0xebb242e6, 0x2073f934, 0x6ded4d6a, 0x6e18917c, + 0x4df58893, 0x7602b8d3, 0xf514fe26, 0x127f0e5e, 0xa1b9af10, 0x018a90aa, 0xe5c013b7, 0xf3da6bbe, + 0xafc03061, 0x4ef7c2f7, 0x49fde888, 0xda6d007e, 0xca39b9d4, 0x09da0a4e, 0x518ae010, 0x3472cdf7, + 0x52749af9, 0x5dbf865b, 0x4cacd5ce, 0xd386fbbb, 0xb583ac34, 0x8454071b, 0xe19fb440, 0x5a545e6f, + 0x6a8a5147, 0x065054b3, 0x24036443, 0x8f0d2d68, 0x6c3e5cfb, 0xfa9c2c35, 0xf1a26e20, 0xe2ab8210, + 0x6bd3000e, 0x369d98a0, 0xa539861a, 0x288dbcc2, 0x430da05a, 0x78a731d1, 0x1cebd40a, 0x5967ce52, + 0x4332d4ab, 0xe31122da, 0x56fc2fb9, 0xe0354d02, 0xa843b5be, 0xae6c7e1a, 0xb4fb5f24, 0xd09d0a0b, + 0xb6de3af3, 0xe3772d2f, 0x18ee6462, 0x10ffe810, 0x33773c2a, 0x4d305f64, 0xdb6715bd, 0x64a4ce70, + 0x04c41e71, 0x675d6dd3, 0xb76bffc9, 0xb88c12cf, 0x33f67233, 0x0a0b8199, 0xd3012e5d, 0x52450868, + 0xc9059521, 0x0291ec02, 0xf83624da, 0x43eee206, 0x8fc3cacc, 0x0079d7fa, 0x4d7e2867, 0x0caed84d, + 0x5751cc90, 0xbf3941cd, 0xa0bc10ef, 0x36a9a6ac, 0x83cb2076, 0x5510d8df, 0x27a57cf9, 0xaa6cde15, + 0x706441c4, 0xa7864022, 0x13c765c4, 0x5ceb0264, 0x20526caf, 0x9d8068b1, 0x9089187f, 0x60a08ab2, + 0xded7d79c, 0xc6913645, 0x70a492b1, 0x74910273, 0x9cd60b41, 0xa80ed3eb, 0x985ffee8, 0x91271af9, + 0x00ff91f8, 0xfa746ad8, 0xe36f981b, 0x05a538d9, 0x0d00dbac, 0x829f2f0a, 0x8bdba1ba, 0x7cd1a269, + 0x5da7ce59, 0xaceff8a4, 0x4de9f95e, 0xd0464925, 0xe35dd13a, 0xef995e6d, 0x5b065f73, 0x533e4c60, + 0xfac78043, 0x0d2dd9af, 0xf5491b68, 0x1a4c0dac, 0x9f7dcb4b, 0x374f3e87, 0x17425e84, 0x93b15e20, + 0x7e5c9570, 0x4344f135, 0xb52c9bde, 0xb83390b1, 0x9345303e, 0xf0ebe7ba, 0xdb597589, 0xad5b7cb6, + 0xba8c1410, 0x88c57b0e, 0x72cd68e1, 0xd372f456, 0x4c9f6021, 0xfcc71797, 0x1895cdd7, 0x63515bff, + 0x14ebf2e5, 0xfe7ac4f7, 0x9e96c055, 0x27cdccd4, 0x9fe36dc8, 0xe94d07cb, 0x2fbe1d5c, 0xc784cbb7, + 0x138a25ad, 0xca35429d, 0x1f5dcd05, 0x6608733d, 0x5368f7bd, 0x612e4560, 0x3a12ff2f, 0x584f92f8, + 0x2fdb5adf, 0x00e9defd, 0x72465ac3, 0x9425880e, 0xb4d54ad5, 0x7e8b82ac, 0xf8edcd3f, 0x3ef7e4f5, + 0xdb4f9eaf, 0xb81034cf, 0x2028badf, 0x8bddaeb3, 0xf63acfd2, 0x77329ac7, 0x8348bd8b, 0x682670fa, + 0x784bb5b3, 0x3e4a27a3, 0x6c7cf166, 0x639555d3, 0xab0da6ad, 0x2239b548, 0x8aa141fc, 0x56470270, + 0xcbc4bdee, 0x6b061de8, 0xccba8ef3, 0x0719e12a, 0x8821a57b, 0x32f1befc, 0xd89dde8f, 0xec7a8327, + 0x084e931b, 0x17acb48f, 0x2dc47eb3, 0x9a9ee63d, 0xb6efbb91, 0xeba8d351, 0x281ac944, 0x2d016d9b, + 0x18887964, 0xbc80590e, 0xe742ee3a, 0x83ad5f1c, 0xb0f0b9d2, 0xe2d6dd27, 0x23d5bc3a, 0x5ca449bf, + 0x4671b401, 0xd887697b, 0xd0ef24ac, 0xe5addd93, 0xb407c38a, 0x5f572bf7, 0x530cadb3, 0xb8ebcabb, + 0x9213f688, 0xaaba0baf, 0x1de7a9b9, 0x5be0684b, 0x58659be3, 0xc5cb5cab, 0x5ed96073, 0xeab3f5b9, + 0xb5c39702, 0xddf18874, 0x943ab490, 0x92003132, 0x30c50478, 0x8ea057e8, 0x09ccf42d, 0x471fd96b, + 0x01234744, 0xb9126f39, 0xff5927e5, 0x91c10ad1, 0x38a8466b, 0x424e43b6, 0x658334f2, 0x07a4a9fd, + 0xa7e5d88b, 0xd38d3481, 0x5384cc11, 0xbb90d7fa, 0x3efa4ce6, 0x3bed725c, 0xceb2c428, 0x369ff05b, + 0x6b10698d, 0x430d8b54, 0xdff6fe8f, 0x2e510894, 0x39ba6a80, 0xa74903e1, 0x8bf9d372, 0xe8814cef, + 0xf588595e, 0x91daa7fe, 0x8da2843a, 0x2fd949d3, 0xde564a83, 0x6d157599, 0x0227dfb4, 0x7f6bc829, + 0xed1c4f43, 0xdf0e018e, 0x0229e48e, 0xdfcd2cca, 0x23858c71, 0x7c92c526, 0xa66cd19f, 0x9cf2d02e, + 0x7729afab, 0xbfda5171, 0xf4d7264d, 0xeba47c6c, 0xd9e1a405, 0x278accb0, 0x06d1225d, 0xba000d0d, + 0x63f4dca8, 0xaffc8ddb, 0x1fbd23c9, 0x1e83fe2d, 0xeaa67da0, 0x1396da57, 0x86bb4318, 0xb3367335, + 0xe290ae97, 0x0c1967bb, 0x26d7321d, 0xf0ed5453, 0x38f51896, 0x368a4950, 0x2769fcf6, 0x61d79b11, + 0x39fde6d5, 0xf39ee57a, 0xb4309b70, 0x550fe839, 0xc6afecb7, 0x1088053c, 0xfbfdd48a, 0x61643a8f, + 0x5743a3c4, 0x760be25c, 0xa016a567, 0x038d7533, 0x1423dab5, 0x83f19fbe, 0x4a12f3a6, 0xcf2553a1, + 0xd3aa061a, 0xd9b09c2d, 0xe4590be2, 0x15880b06, 0x14e0d165, 0x847484db, 0x784fd7fe, 0x9f523f1f, + 0x630134c1, 0x1c77ea45, 0xbaff0ad1, 0x1f96d13d, 0xbafbfdfc, 0xa9c40cf4, 0x6f7e9d0f, 0xfb4decc8, + 0xda0383a0, 0xf4c7c24e, 0x44fc0528, 0xac79c330, 0x472bcdf3, 0xedb7575e, 0xaa706166, 0x12a41637, + 0xdf833999, 0x6eaf2567, 0x7b4a065f, 0xb403d9a7, 0xd64a048e, 0xce53a1d6, 0x9dfed61e, 0xfb06faa3, + 0xa4a5470c, 0xbe6f59e6, 0x1389e5ad, 0xb3f2e858, 0x2f37f9ee, 0x4ba2d613, 0xf3e2055e, 0xf2666dd0, + 0xcebecb1a, 0x6cce2e86, 0xf6ed0466, 0x5aaef1d9, 0xeb84ff63, 0x3c6c86b1, 0x746c1348, 0x325fc556, + 0x02268299, 0xd32d15aa, 0x0a68e027, 0x94448fbd, 0xb0c91588, 0xe16f540d, 0x5b9837f9, 0x34cdc924, + 0xd4ecc0d1, 0x40e55a57, 0x49eb3a98, 0xf068fefd, 0x31c36477, 0xd9ee218a, 0x74480c93, 0xf02fa101, + 0xfdd27609, 0x69309f1b, 0xc8c77c7f, 0xe8b737b8, 0xf58faa2a, 0x22c617eb, 0x1016598f, 0xf36cb0c2, + 0xbdfc2429, 0xf248339c, 0xbbf99880, 0x4fd82344, 0x9dbcb451, 0xa8455012, 0x731c89ef, 0xf3b6c13e, + 0xd596b219, 0x2cd9da08, 0x75e21b6d, 0x58a50d6b, 0x41adb441, 0xa66ecbb5, 0x4d127146, 0xc88aa9c4, + 0xd7f9427c, 0x47967a7e, 0xd4fb16ae, 0xaf0e4d69, 0x5b92fd4a, 0x8239a42b, 0x3cbb7f84, 0xed78be40, + 0x515364ba, 0x3bc7f71d, 0x77b70d46, 0x6bed141a, 0xc994de37, 0x28bcc0c6, 0x774b9c89, 0x6c054f2b, + 0x07b2ae1c, 0xac318b09, 0x8b6a2eeb, 0xd334a185, 0xebde28b1, 0x37fd14e6, 0xe130def3, 0x6b6ddc3a, + 0x67f25ac9, 0x7cb7463e, 0xb9d13ef7, 0x923a0df3, 0x6e41961c, 0x10489fe6, 0xe1948556, 0x9f542cf5, + 0x71b9b622, 0xee615238, 0x48e0d93f, 0xad38fe45, 0x78aaa794, 0x9a315733, 0x5ba213ba, 0x0010f64d, + 0x9a368795, 0xf11ec4f7, 0xaba1bf76, 0x219cc58b, 0x67e03a4a, 0x67355772, 0x30b720d5, 0xf2b91eee, + 0xc5e116d7, 0xf3290c35, 0xf0cfd592, 0x9b95a23d, 0x3fac6d93, 0x274fb75b, 0x543bf30c, 0x4a8097bc, + 0x22f22f08, 0xf76c5265, 0xc76f4bdc, 0x782d9492, 0xa67083fe, 0xe56d4249, 0x443baa56, 0xefbe82f1, + 0x95acf47c, 0xfd3eec61, 0xadb22bea, 0x4447872c, 0x6551750c, 0x21261a72, 0x6bc5d16e, 0x844e7ac6, + 0x3ebbb50a, 0xb63f74d9, 0x827d0e6c, 0x034b9fc8, 0xe1e2e583, 0x76b720bf, 0xa25f0f50, 0x8b1045ae, + 0xa1ae3b13, 0xe988ec8b, 0xb8c940c4, 0x90b8be01, 0x4a502934, 0x66bc2b08, 0x1ef9ec26, 0xcf6e04ad, + 0x735b0b6e, 0x1aa31e1c, 0x66585c50, 0x21836bcf, 0xedb15a2d, 0x7de39435, 0xcfe2502b, 0x3ef74c4e, + 0x451bdb77, 0x379b2e9f, 0xac9beadd, 0x8ecc01af, 0xcea4fd21, 0xfae38330, 0xb7b20c8a, 0x98572551, + 0xeb686ea2, 0x18b62d45, 0x0ca55c18, 0x3afae783, 0x22fcc00b, 0xa3354a23, 0xb682b8fa, 0x2a946044, + 0xb9e84265, 0x676518f4, 0xf856beb2, 0x9d915a00, 0xda63cc0e, 0x0b6c838b, 0x2ba651d5, 0x6d900e16, + 0xee98d276, 0x9d59e4fa, 0xfab8bf5d, 0xe7bc2a7f, 0xb4afc6a5, 0xb38c7998, 0xe4e0f355, 0x467f621a, + 0x3a794dc1, 0x884c0ac2, 0x659f4193, 0x9b2f49d9, 0x91340bdc, 0xee59d30c, 0x4692cba5, 0xf6e72124, + 0xc16a9971, 0x6e08ef36, 0x1f475997, 0xc69fce9e, 0xd2fe8bf7, 0xcf8703f7, 0x546b1297, 0x02bc27ba, + 0x72e44b1d, 0xcaf73483, 0x7975fe7f, 0xba148275, 0xd7c2377a, 0x7fd1473f, 0x4cc0725f, 0x39bd98ad, + 0xb7a336b5, 0xeef958d2, 0x54bb77ce, 0x3e6ad35f, 0x4191172c, 0x9d147b32, 0x20b4d35c, 0xadedbf03, + 0x0361004d, 0x10920d96, 0x0b912f36, 0x74a85afb, 0x281d35f3, 0x534524cb, 0x067f666d, 0x9b2e4793, + 0x34fca227, 0xfb3fd00f, 0xe2c7e21c, 0x8f43fb91, 0xd1765c1c, 0xd8004c0e, 0xc5b52b18, 0x8add4982, + 0x3cf43ad6, 0x873712d6, 0x4f1439aa, 0x840a1635, 0x2ab7a7aa, 0x50867aa0, 0xda737751, 0xb6bfbafe, + 0x508c6d13, 0x0efcf745, 0x9262ec2a, 0x53c622c5, 0x05380812, 0x4f3ec1ec, 0xddeb0ad8, 0x9b9011aa, + 0xacb91009, 0x2bc3eff3, 0xf0795168, 0x79e02e64, 0x9a52d30e, 0x25eb1bb8, 0xf2a5eb3f, 0x747cc302, + 0x2549605c, 0x7eb1d03e, 0xe01545b6, 0xc6a3a531, 0x0e3d0552, 0xb25ad55a, 0x457bc761, 0x9a2a9f46, + 0x41c8b662, 0xe013b49d, 0xfeafb31f, 0x3807bd18, 0x443cf300, 0xe8aecf78, 0x7cbba9e5, 0x1199fe00, + 0x6745522e, 0x6c0f47b9, 0x0bc6093e, 0x7ca30fb7, 0x0ba1c58b, 0xf1f9b26f, 0x43ae0465, 0x78ef03fc, + 0x0a5cfb50, 0xae438ea9, 0x38a95e1f, 0xe64c6f8d, 0x2f96cf97, 0x04253f64, 0x9f3695dd, 0xf02670e2, + 0xc63fdb87, 0xe50b5def, 0xa4b3bdef, 0x7c3624e4, 0x2ae8b9ca, 0x9587daed, 0x0913ec51, 0xe3598908, + 0x99bbc4ab, 0x7193bc41, 0x9d347b81, 0x460782ae, 0x843befb7, 0x7f868d44, 0xb0755851, 0x4dc88ed9, + 0x4183cda7, 0x3540cd4b, 0x381d7750, 0xafa5b901, 0x7ee7e5bb, 0x874eaada, 0xdea67e2a, 0xf53984b4, + 0xfed368b2, 0xdddefb31, 0x0c16e05b, 0x0844132f, 0x5d9613d6, 0x8938ac35, 0xd54d853a, 0x024881bb, + 0x7c1e75f1, 0x84893baf, 0x96569220, 0xccaff040, 0x0e367aa2, 0xa6892b1f, 0x0fc7b01f, 0x514e0620, + 0x581648f6, 0x6f39e4c9, 0x04f0b7f0, 0xcd552c01, 0xbd513cd4, 0x86deff5c, 0xc97b6de8, 0x6eb9ea6a, + 0x86737c43, 0x351a88ee, 0x521c72f2, 0xd66dbd30, 0xe8a0ace0, 0xbb413769, 0xcf837158, 0x9a5bba2f, + 0x890c1406, 0x27d02be1, 0xbb62a769, 0x7cdb7a96, 0xb3c2ac41, 0x3a4f8380, 0xc74a226f, 0x793d1bf0, + 0x0a96082b, 0xaa2fd901, 0x182caff6, 0xae074ca7, 0xa7fd858d, 0xf02c640f, 0x33275ab4, 0xfc352ea0, + 0xb51e2f18, 0x60557f22, 0x949cf520, 0xf1543f14, 0xa7680e68, 0x8c644a0f, 0x726cf05c, 0xbe3443ab, + 0x32b21799, 0x19a78648, 0x3d3c1a8c, 0x6cdfdfa3, 0xea86b706, 0xd38ba6f3, 0x2960a9ae, 0x0788e962, + 0xf534a14b, 0xe3510cdd, 0xfa7d8243, 0x1e6810a2, 0xf9bb5b86, 0xdd239fe5, 0xa672d442, 0xf296c79a, + 0xd587e216, 0x7bf32720, 0x6a11f616, 0x5012f10b, 0x9214fd85, 0x4f3f9cb2, 0xa369b047, 0xfa8d050f, + 0x3506858f, 0x29379430, 0x09243770, 0x73376421, 0xa0d5db05, 0x643972f9, 0x82a602ae, 0x83e54301, + 0xcdeaad64, 0xbcac6cbb, 0x2c469a11, 0x0c8e07f4, 0xdd76e63a, 0x3bc7a655, 0xe9c3c706, 0x8cf9db77, + 0xab1dfd1c, 0x11a5bbdb, 0x25d2800a, 0xca0187a3, 0x5067624a, 0xe9c3112c, 0xc741dbf8, 0x9fe5931b, + 0x88dc30bc, 0xc788715a, 0xd6ff4ef7, 0x961df3ff, 0x25b86536, 0x67cac65d, 0xbb0218c1, 0xaa84689b, + 0x1a857ca1, 0xe3e8ef2c, 0xbd6fa85a, 0x5becefd9, 0xa17723fb, 0x49b26092, 0x0ee0a5ab, 0xa6233f98, + 0x1df07725, 0x28451def, 0x41179bac, 0x6070d73a, 0x0c48f07f, 0xe7c5c0c4, 0x2e2c64ca, 0x62b76a46, + 0x9f0c351f, 0xfb60c5d5, 0x2ec27586, 0x10ab8728, 0xd60917f5, 0xebd72952, 0xbbea9b18, 0x46bce345, + 0x07163323, 0xb57738e6, 0x77bf373d, 0x286040a8, 0x8fb7b451, 0x56baddf3, 0x86330fec, 0xd3f5359b, + 0xad00c3bc, 0x2871e66c, 0x71bb365d, 0xc7e68acf, 0x26467265, 0x7af44a50, 0x951e06f1, 0x0b9e3415, + 0x063481f8, 0x28f42a80, 0x4fa1335f, 0x3a9c3be4, 0x7d5c5fb2, 0x4d4c6e0f, 0x79980ec1, 0xd7e4109f, + 0x2cd5e8ba, 0xcc1d446b, 0x32f4467b, 0x27ccc64e, 0x8eea4e32, 0xc4030cab, 0x1da0c4f8, 0x3f4a9c1d, + 0x4c79d94c, 0x812bfa71, 0x20a9ad2c, 0xcc807d0c, 0x3810c9c0, 0x78113bed, 0xe03144e9, 0xa7095a52, + 0xc65b3d84, 0xf33cf6c8, 0x50d2bf80, 0x9957a997, 0x7b25db10, 0x4c8d8244, 0xb9932e64, 0x260317ed, + 0x43aa353e, 0x1c6f2a60, 0x1eb7f5fa, 0x10e0eaaa, 0x535952eb, 0xa245d7f3, 0x7b170368, 0xff325478, + 0x69b1041d, 0xe2777017, 0x65bfb06e, 0x0a7e41a7, 0x30dfb2e5, 0xe543fb23, 0x93b9ea8d, 0xae4e635a, + 0x4870e109, 0xca1e914d, 0x7514b684, 0x79d1cd7f, 0x6d8a8fde, 0xef871a53, 0xb75684ea, 0xc1016422, + 0x79f0ff91, 0x0befd8c8, 0x74f87d61, 0x7072013c, 0xe334986d, 0xbf311cf6, 0x13144976, 0x9d46d80e, + 0x89f5847e, 0x601fbec7, 0x3164c1b8, 0x3f696594, 0x1ec3e4a6, 0x566a3eb5, 0xd6a5337a, 0x8d58b503, + 0x2a652ad1, 0xdc9c3db2, 0xb4952f58, 0xe6836ac3, 0x856d94a9, 0x02a05498, 0xfe1e51fe, 0x26870848, + 0xcb2a715b, 0xa01bf901, 0xfe48fe0d, 0x456fabdd, 0xd2ca5523, 0x53533145, 0x435d9030, 0xe7775de6, + 0x93c7b5a2, 0x01d70295, 0xbce0eb4c, 0x395c5244, 0x032fa565, 0x26581b29, 0x4473864d, 0x47616c63, + 0x73ddce45, 0x80718cf0, 0x95448896, 0x7267cacc, 0x94c3084f, 0x55b83e38, 0x64aa0feb, 0xe66cd369, + 0x426d6555, 0x7aab55ed, 0x10e874fe, 0x7f4959bc, 0xd24bf2d4, 0x65d8bd45, 0x4f0d02d9, 0xb04f7a8a, + 0x84eb94c2, 0xec137533, 0x28b1d514, 0x82312965, 0xcee3681d, 0xdd0c992c, 0xb9feb6df, 0x6eaf6815, + 0xd78a7784, 0xd3df2321, 0x2b88a7bb, 0x71f989a8, 0xc739b73b, 0xd3d9eda5, 0xae80cb38, 0x1ddf912d, + 0x2c2f694b, 0x44695399, 0x046c553c, 0x99147c62, 0xadd80f6c, 0x81a22a6d, 0x65e749be, 0xa9b75ac6, + 0x553eca5f, 0xd9e234c6, 0x4bd2dcf5, 0x54c26dcb, 0x37948031, 0xe4ba5229, 0x23e938fe, 0x8c7806d3, + 0xca6e3b54, 0x49002c26, 0xeffc1e21, 0xe70c62e8, 0x30188a7d, 0xd6be787e, 0x84cded2e, 0x33cb7eea, + 0x5e107391, 0xc94b1da4, 0xfbd5e486, 0x8a93b4d5, 0x94c2094f, 0x0d986590, 0xe9e66d0e, 0x86e3142c, + 0xa56d1115, 0xb1275092, 0x9c88a431, 0x85c9c370, 0x6295c10d, 0x5b724399, 0xaf895642, 0x24e7e2ec, + 0x88e788ae, 0xb3186a93, 0x75a88a20, 0xb2e3ac40, 0x07f0fb6b, 0x4bbc674c, 0x20c5b2c6, 0x0c7f7e80, + 0xf686e267, 0x6022b569, 0x6a8ed195, 0xc2ab0307, 0xb8359f5a, 0x99422b7d, 0xf56483e2, 0x40344147, + 0xdeab7ef7, 0x1b35545a, 0xa03740fa, 0xa1a7299b, 0x95af0c85, 0xf64a8061, 0xceb61466, 0xb7ae727b, + 0x6c057256, 0xb4b7f248, 0x17c47c75, 0xc69c7d9e, 0x1a056240, 0x252ecd2b, 0x79fd45ae, 0xd7bd264c, + 0x3683ea86, 0x58b38336, 0xaeb05d7f, 0x68639f5d, 0x836597d4, 0x422e28bc, 0xd11b5501, 0x6d60e64b, + 0xf6a274f1, 0x22e82344, 0xa84bb789, 0x97989dde, 0xf8d8b627, 0x70792be4, 0x38f70e56, 0x5f9717c7, + 0xe1236d1c, 0x66fceacd, 0x80789af9, 0x1940a9d1, 0x1f696373, 0x26e6756b, 0xc052196e, 0x8898989a, + 0x6322ce02, 0x6ef60d86, 0xd76eb195, 0xa3ff5562, 0xa1d99686, 0xdc03d27d, 0x34d35559, 0xbc5b5bc9, + 0xe6d960b5, 0xcfb6b43d, 0xe3b8c0e5, 0x062dd371, 0x50a792d6, 0x3f868d1e, 0xcffac460, 0xe7ac96ec, + 0x97797fea, 0xe146ecf2, 0x0b37eb28, 0x37a1dc85, 0xd0b12b93, 0x3e8c8316, 0x5ee420a6, 0x3cfd0914, + 0x5909f0c3, 0xb4c55f49, 0xae195320, 0x64b4f8ff, 0xca66c3d9, 0xb347632e, 0x31b87961, 0xa4e15c4c, + 0x25084b3d, 0xd5fac421, 0x10cf5932, 0xf132196b, 0xe6f4f34a, 0xcb8f4dfb, 0x7aeb2eb6, 0x08219ed5, + 0x02201885, 0xa9377b32, 0x88866621, 0x8b8becf4, 0x897fd968, 0xefd84621, 0x443a5851, 0x887b0d4c, + 0x5c34d8fd, 0x2bb49478, 0x59a7ef61, 0xc79e2e22, 0x74a53dfa, 0xfe35bd84, 0x28436217, 0x0bb885ab, + 0x29c7cc6b, 0x6f5e0690, 0x4e4a8543, 0x7261ddb2, 0xc82acb36, 0x5034f881, 0xf979582b, 0xb5833582, + 0xef21a6a7, 0x498e0b70, 0xfb95ee83, 0xd8d8ce55, 0x2fddccd6, 0xe7137dfb, 0xd661a450, 0xcd521aa0, + 0x68465924, 0x4065cb52, 0xd3d1fa8b, 0x60c444ed, 0xab4ca8d1, 0x72bb3ea8, 0xea63c96c, 0xb3d5eebf, + 0xbdfe5370, 0x4468b757, 0x8c356b55, 0x887b99fe, 0xae855823, 0x22f06897, 0xfe70f5bd, 0x1b4f3876, + 0xa949d945, 0xe0ae2f8b, 0xaac9e5e9, 0xbe7981c6, 0xc38fc9a0, 0x536b1ec0, 0xdbb1bbf2, 0x49199b3c, + 0xdbdfbc7d, 0xe3acb52e, 0xfe83d387, 0xa7fd57c9, 0x9d6d7f20, 0x8b3e285b, 0xc0ed5ffa, 0x148b7dbf, + 0x198b8645, 0x6f840b58, 0x8e995c6c, 0x3dba5985, 0x42b5c53d, 0xfa13fc04, 0x34d062d0, 0x75c4b619, + 0x3f14af1c, 0x8df54fb7, 0x24be652f, 0x1312ef00, 0x17292446, 0x5a154b23, 0x0b1d7f50, 0x9762d8fc, + 0x3e9b3ddf, 0x7f5a7d01, 0xe9d70e4a, 0xfa94ae12, 0x1e3fe298, 0x3804c1a5, 0xe8d35660, 0x2facc7ff, + 0x448b3938, 0x031ec806, 0x68511665, 0x093345e2, 0x10a21cad, 0x3e04d0a6, 0xb6708d2e, 0x32b0f6ae, + 0xfeedc656, 0xd8c9c156, 0x0c2014c0, 0xbff00bf6, 0xa10b79b5, 0x63dbe48c, 0x10a6af1a, 0x0e605dc6, + 0xb45f6620, 0xb672c976, 0xc03bef8e, 0x23717395, 0x6e83d6cb, 0xeceaf8a5, 0x211c9a14, 0x05eb0e8f, + 0xed8acddf, 0x828ed1f4, 0xa640a68b, 0x8531cf52, 0x85cf3bae, 0x60266fcd, 0x6e5ef34e, 0x8011c04f, + 0x62258c84, 0xeecc735c, 0x7c15a62d, 0x4fa324a0, 0x76d3249c, 0xf3bf4dd3, 0x460c0592, 0x87463599, + 0x9000adb2, 0x8bc5cf41, 0xff3dcb04, 0x5662e329, 0xdd66646e, 0xcdafc640, 0x9c97598f, 0xd7e2f5bf, + 0x8a8361f9, 0x0625cd4d, 0x1d97e3c5, 0xc174c3f2, 0xf78d58b3, 0x51a9c128, 0xc6f631ee, 0x9d8710e6, + 0xa78e8162, 0x1e8ad65a, 0x8c88eeb9, 0x320b7d14, 0xdedf8faf, 0xc827aa5f, 0xd3cec234, 0xe03e789f, + 0x39cdbdda, 0x115ebc78, 0xca073bd4, 0x8f1103df, 0x763a5fcf, 0x0fd6ae6e, 0x04fc287d, 0x7c03dbeb, + 0x70c40829, 0xc0c164bc, 0x5869d535, 0x4d751f99, 0x3e266e9a, 0x6017e3fd, 0xb9011393, 0x03f6d5e0, + 0x50358750, 0x81e89270, 0xe8abf171, 0xdce2561e, 0xcf81006b, 0x5c389152, 0x784ee5d9, 0xc145df70, + 0xd34866e6, 0xc0774779, 0xb23accaa, 0x5644dab7, 0x750410f4, 0x40203062, 0x5be5a795, 0xb4cd0ba5, + 0xf56ee9b7, 0xbb3a6f52, 0x1e0a390a, 0x6357302d, 0xed7f2ea6, 0x9a458e71, 0x02c6ade5, 0xa8b46876, + 0xe5d65697, 0x1387deaf, 0x4d11e1b5, 0x5360b5b1, 0x9acfa5a5, 0x32e65af2, 0xb07f67cc, 0xd0afedc9, + 0x8bac8f72, 0x4b8bc700, 0x9b82df9d, 0x38f06c97, 0x8537e681, 0x4536e8a2, 0x9c06cde8, 0x4b6f3661, + 0x12798204, 0x8d808d0f, 0x02afd715, 0xb5380b22, 0xc5f7daf5, 0x5fd6b5c3, 0x72bfd392, 0x07922cec, + 0x18b0fb0b, 0x4637970b, 0x05ffbc54, 0x00597282, 0x00709917, 0x1161f0cc, 0x88db6ee5, 0xcd858a1f, + 0x59402d38, 0x13e3adea, 0x62bb9ade, 0x9379d4a9, 0x31dff14a, 0x28df12e2, 0x44aedfc8, 0xb8f6fa29, + 0x7eb88247, 0x8da5ecce, 0xf1002a12, 0x23b8aeb7, 0x68acbdd8, 0x0ea6cdca, 0xcbde3418, 0x838ca656, + 0x7f87bece, 0x791f98cb, 0x32792247, 0x0847c845, 0x57a5ade1, 0xcb7f05aa, 0x06d1690b, 0x737653de, + 0xb95d2dbb, 0xccb8fb37, 0x62ea3544, 0x0a563f23, 0x24cc0a9f, 0x1b00ac88, 0xa6233404, 0x5f9bc8d1, + 0x011fedf3, 0xaec7b166, 0x25651648, 0x8d81be0f, 0xe2d7e8ce, 0xb28a5382, 0xfc181410, 0x2e235be5, + 0x2c5a2473, 0xe8d55c44, 0x0f3d4a1d, 0xcfa606f6, 0x11662339, 0x43f9dbeb, 0x0392a888, 0x55fb685f, + 0x03b071c5, 0xe0c6b43c, 0xf5978c97, 0xb55ea65a, 0x7601914d, 0x8c8db6c8, 0x1f8e572f, 0x014b8135, + 0xa9e00eea, 0xcb8879dc, 0xc37bd82a, 0x085080a5, 0xa0377ad9, 0xabed38db, 0x5c949d33, 0x4c3816f0, + 0x484a1e0e, 0xcf819a01, 0xd53efc47, 0x53adafcc, 0x0730b388, 0xe4dd43ca, 0xe1b74d88, 0xd5cc9ee7, + 0x1f5974a9, 0x0966b581, 0x55110b83, 0x5e0319dd, 0x31fe7441, 0x27345e56, 0x35e9741d, 0xf7369b3a, + 0x4d118586, 0xf1ee6650, 0xd7b462e3, 0xb5580a4c, 0x9568d4ae, 0xee653c8c, 0x4c1057de, 0x2c8bbccc, + 0xa0aa8f1e, 0x46ea4009, 0x80dfc946, 0xa59e9c92, 0x6c373781, 0xc64b0da2, 0xd7961dc9, 0x80d9c222, + 0x50b3d555, 0x2ec64457, 0x5facac77, 0x6a4a2f84, 0xf9951d3c, 0x8ed499be, 0xb5780c94, 0xace5bcc4, + 0x6c89b812, 0xff0f2e7a, 0x73415f40, 0x8e2ef921, 0x592f3680, 0x849d31b7, 0xbc6a099f, 0x45b4fb78, + 0x8f2b1455, 0x852d9152, 0x2e74c419, 0x9eb41705, 0xbe0c29d7, 0x5312da11, 0x48d4c168, 0xdd344601, + 0x54ba8936, 0x4e51aaa9, 0xedf5e171, 0x800e09b3, 0xa7fd3f6d, 0xdb1b1dd6, 0x1e5921b0, 0x9edd1bb4, + 0x7c538667, 0x29c56003, 0x6a49864e, 0x5239c6ab, 0xcb586854, 0xe667e165, 0x043b1ae2, 0xad44593a, + 0xa8079980, 0xf92d792d, 0x6b7e25b5, 0x0d01dfca, 0xef1c26d4, 0xd1a06902, 0x94156b26, 0x17f44e96, + 0xb64601eb, 0x99242036, 0xee616a3b, 0xe4be8534, 0xc7764325, 0xf59a6711, 0xf73cc08d, 0xda13bf0f, + 0x6c42fafa, 0xe555cdb5, 0x231672fd, 0xc3421df4, 0x73a4b054, 0x4c0f26d8, 0xef07e8b1, 0xfd5dde15, + 0x3aa5f8a8, 0xf96e2380, 0xe550b60a, 0xe68ce72e, 0x39c678ec, 0x81f883fe, 0xd72cc90b, 0x8922afd0, + 0x3763e710, 0x2ad23f9e, 0x0cf5e282, 0xfea32613, 0x02906330, 0x6f6a0fa4, 0xa7d6e99e, 0x3e89d698, + 0x53126a70, 0xf3cef895, 0x47003d19, 0x72df36a0, 0xe2decc63, 0xb0c31922, 0x5d3a4308, 0xbc89f143, + 0x835be0e6, 0x6682277d, 0xd38b36ed, 0xbde0896f, 0x91959846, 0x590f4395, 0xb06ddf51, 0x434cb8fb, + 0xde568f5d, 0xa60aa50e, 0x97f110c4, 0x8aa964fd, 0x291cf63f, 0x410d31dc, 0xce0820e0, 0x36eb5651, + 0x170b5fa8, 0x3782c3ec, 0xb48b013f, 0x7cc206b1, 0xe3a927f5, 0xc0a6e8d9, 0x703a5717, 0x859843cd, + 0x876bd1bc, 0xbd7859b5, 0x7225c905, 0x06c1644b, 0x8bd3cab0, 0xc82a0071, 0x0b47b7d7, 0x58eb7607, + 0xf8284194, 0xd41c0f75, 0x19f67e27, 0xf9aad4dc, 0x5217e71d, 0xbbb110e9, 0x473d0f82, 0x89c61b8b, + 0xf08e3629, 0x82198e0b, 0x4297e16c, 0x0174106e, 0x258de9fa, 0x792a63eb, 0xdc220539, 0x9336854d, + 0x2eecfed0, 0x8c2957f7, 0x19a8aa29, 0x6277a349, 0x2647e0fe, 0x2f8152f0, 0x31e4883b, 0x5db95659, + 0xa7b28634, 0xe36d2f66, 0x384a8c15, 0x714f4316, 0x670f1005, 0x29139de3, 0x9019d1fb, 0x613dc1d7, + 0x62504f35, 0x3ad3fa12, 0xc0bc910b, 0x24e7fddc, 0xa0891137, 0x677c3b3d, 0xcbdfb03f, 0x94014e2a, + 0xa7eea654, 0x40380632, 0xbd84d9b8, 0x8020b400, 0xff541b0d, 0x32d28b0f, 0xb19fefc8, 0xc2840d21, + 0x9f852cc9, 0x649a0979, 0xa4386c2c, 0x3ef343bc, 0x5ee939a0, 0xf999f76d, 0x65f87b12, 0xac26a6a9, + 0x4af3ba00, 0x2ed105e7, 0xed95070b, 0x0170bca1, 0x93b8876e, 0x31f355dd, 0xe42a224d, 0xaced6ffe, + 0x60feb905, 0xbc79a51c, 0xae1dc3f1, 0x34281091, 0x92bdca00, 0xa809a7ee, 0x09e6a91e, 0x217d15cf, + 0xc135f08d, 0x34a31383, 0x43e05f8d, 0xf10c19e9, 0xd56b6f81, 0x230ff567, 0xe6fff7c8, 0x8e912ea3, + 0xbdd65b8c, 0x73f51391, 0xb3c97197, 0x4d5b32fc, 0xef7d9a82, 0xa752e0ec, 0xae38b58d, 0x1561c990, + 0x25d0fa4b, 0x9c21e712, 0x9494ea9e, 0xd0d88ce4, 0xda81c38f, 0x2d262b64, 0x4a39f9ec, 0x59234df9, + 0x25d4b9af, 0xb039055e, 0x1b38d705, 0x3dc69ab0, 0x6d5948ba, 0x730f4f7f, 0xe1af03da, 0x834f3ba4, + 0xff6b0da3, 0xd14a5240, 0xf0a3f4a5, 0x8db6df98, 0xaa884090, 0x41be43ea, 0x098b8505, 0x08f92d30, + 0x6909493a, 0xafef2fc0, 0xae1e6c45, 0x5d93bca9, 0x43650613, 0xbe67ad60, 0xf10f8659, 0x49b3b71c, + 0x0b79081b, 0x922f27c3, 0xb5002036, 0x057ec592, 0xf882a209, 0x4ac16616, 0x6c12f86a, 0xce686e3a, + 0x4495d21f, 0x075467d4, 0xc27dfee7, 0xbd106848, 0x1f82c34a, 0xed414335, 0x634adee9, 0x7e8c9a2c, + 0xfb223485, 0x78e5942b, 0x4040fba5, 0x7fbc89c5, 0x2bb81fb4, 0x5a2be1c9, 0xf5661aa9, 0x09a15c86, + 0x94aeb294, 0xb0fd27d2, 0x7d9009e6, 0xf38472ae, 0xef6384f2, 0xa5bc8c0c, 0x9ca2fe65, 0xf46e6aed, + 0x9d117085, 0x631e51da, 0x19e3af3f, 0xb574d255, 0xbe87e4d4, 0xfa771189, 0x03341678, 0xaf730213, + 0x93033ed0, 0x8bf4911d, 0x71f47cb8, 0x5c5c8a65, 0x4c4add27, 0xfd583f52, 0x0ae76de8, 0xeba09577, + 0xd18263da, 0xbb0e6bdc, 0xb021713e, 0xe37ba433, 0x586d70c6, 0xc7eea3bb, 0xad803a86, 0xa9accefc, + 0x6d4d4d79, 0x83d92a5d, 0x2833cfea, 0xe69b2e3d, 0x5cbc55c0, 0x1d6f3de4, 0x1606d71a, 0x661f160e, + 0x963a3aef, 0xe7926605, 0xc7fd9930, 0x7dfc0f7c, 0xe9aa3da1, 0x82dcee5e, 0xc3bdeca9, 0xecdc1322, + 0x49e4e95f, 0x94e5c813, 0x7c7c927c, 0xd9337e63, 0xb0e12dec, 0xf0f30425, 0x5f8b5e5a, 0x0e916edc, + 0x81d3864c, 0x93e07c23, 0xcaf67898, 0xf45f0e6a, 0xfb90e1e8, 0x1323252d, 0x8423fb00, 0x9f211995, + 0x60f0df5c, 0xdbb1aa7d, 0xb9c0ce05, 0x8d0842e1, 0x92566996, 0x791c6924, 0xa118fdcd, 0x31f1f176, + 0x2712da1c, 0x0cd9fb8f, 0x614aceda, 0x39824d52, 0x86ca1391, 0xd11a61e9, 0xee269a11, 0xd850719a, + 0xe7e35a2b, 0x3ca89ee4, 0x60e6bf4e, 0x9993972b, 0xcea88292, 0x5e3cc939, 0xae53dec1, 0x36695a4e, + 0xac090e34, 0x18ee19a5, 0x64a02ed6, 0xb9338fcd, 0xf418f410, 0x3257392c, 0xb4138035, 0x3b770dde, + 0x8efe596a, 0x9e93b667, 0x7add3b13, 0x3ad4aacd, 0xa6ba2238, 0xea123810, 0x1f05dd4a, 0xbba67389, + 0xb6ae4c11, 0x72d577a6, 0xa68d7efc, 0x7feaf2a2, 0x6f3317a7, 0x83c8355a, 0xdfcfb0d5, 0xc5ce1ba6, + 0x689378e5, 0x07aa8a14, 0x035cfcbd, 0x0e856649, 0x86bca391, 0x73c7ee00, 0xaa3ad28e, 0xcb7133f2, + 0x6613d47f, 0xbc75d406, 0x471dec31, 0x93c47d8f, 0x8cc26dbf, 0x466fe961, 0x3d721e02, 0xe576fb7a, + 0x2ba2d73e, 0x6a600b8d, 0x507daf38, 0x1d90fb55, 0xf7d83a90, 0x13245ec9, 0x836492cd, 0x2e37244f, + 0x0ac0de15, 0x4ec93763, 0x6caa7be8, 0xa3ba67bf, 0x4d14c405, 0x6bc0a94d, 0x716d1c75, 0xe5161618, + 0xefda22f4, 0x6f71762d, 0x32be5765, 0x0ad7fd6c, 0xaafe2de6, 0x3c0d0e94, 0x6a50b592, 0x78533019, + 0x2e9a99cf, 0xa427af5a, 0x2bdd9f8c, 0x3818a853, 0x453ba2d5, 0xdc7f6604, 0x8566b7e2, 0xe21f55f1, + 0x35fd5fbc, 0xc487a36d, 0x7ffaca07, 0xef31a67e, 0xdf5796d1, 0xc836d20e, 0xf8dfce47, 0x6f127c62, + 0xa1998f15, 0x004893ed, 0x8836b395, 0x0442b068, 0x8c25ca45, 0x752bb28b, 0xaee582a4, 0x8444ab82, + 0xfd7a513b, 0xd976d77d, 0x8f5f6e27, 0xad62fca6, 0xc7a920e8, 0x330b674b, 0xaafa023a, 0xbe5a7747, + 0xfd654b4a, 0x9448e245, 0xcf824484, 0x0312d518, 0x01703186, 0xb5e40699, 0x525c16f2, 0x53470af1, + 0xa1c48b02, 0xb2054061, 0x8cb69fcf, 0x69da3194, 0x17c6dfa6, 0xd5194ece, 0x3b322b9b, 0x2631257f, + 0xfb83a17a, 0xfd0b656b, 0x4d602324, 0xf0ca5982, 0x55d24d9b, 0x18a3f699, 0x017dd877, 0x69018744, + 0x0588af75, 0xd6ee45e2, 0x88599b0e, 0x1ef54f1a, 0x6ef26640, 0x06804ddd, 0xe4b305b7, 0xf8a0bcd3, + 0x941f34ec, 0xe59b1aa7, 0x34fb0b0a, 0xaec3d45a, 0x4a2d70e7, 0x7effff4d, 0x836bf370, 0xa6c3867a, + 0x6e97ca51, 0x660f7653, 0x36e1f1d3, 0x70082c80, 0xf1038f20, 0xf0249e22, 0xb40cc721, 0x16cc22fa, + 0x372a8059, 0xe8f168e0, 0x855deb45, 0xdb957b26, 0xe782dee9, 0x8f85c05b, 0xa843da73, 0x02530930, + 0xe7497815, 0x37cedaed, 0xbe68b1a4, 0xae23324e, 0xaacecea3, 0x3afa3420, 0xd5917495, 0x7f62a294, + 0x79d872b0, 0x71907e41, 0xf290cb17, 0x7c79ca13, 0x67d1c609, 0x2a55794f, 0x3fd2d399, 0x51c356de, + 0x42d0624d, 0x26202916, 0x8c2a5acd, 0x7913d49c, 0xe92d3a85, 0xbe2ecfc5, 0x7aa06b4f, 0x2a575b13, + 0x2da4bc78, 0xd22fde6c, 0xc7a3bbe5, 0xc673adb9, 0xe95fa12e, 0x49117360, 0x0b4e0f4f, 0x60f3efab, + 0xf2d6e343, 0xaecda3f0, 0x578939bd, 0x30d33a0a, 0xf79dcb6e, 0x9c826ca0, 0xcf8978da, 0xdbcdf2bd, + 0xb69b4137, 0x5e61459e, 0x7a3c58ec, 0xc9d5fda1, 0xe8208c69, 0xb66e25b8, 0xe62d1689, 0x5d59ab36, + 0x11702ac2, 0xab57b82d, 0xeb6e838a, 0xc762f89b, 0xe1ed5c67, 0x115786c2, 0x978bc8cc, 0x160acedd, + 0xde837899, 0x426381aa, 0xda804fcf, 0x6687b387, 0x48337df0, 0xf0086146, 0x63ff005f, 0xfc72d8c2, + 0xc6905c76, 0xf4cfb718, 0xe243c85d, 0x108440c5, 0x4bef30cc, 0xdefe2cc3, 0x7bd292d9, 0x6babcbda, + 0xa277d826, 0xc4bc5da1, 0x11101ed1, 0xe2063396, 0x6b0be804, 0x9d087218, 0x9b921d6e, 0xeeae2ba1, + 0x8abecad7, 0x3fc5e4de, 0x307c5557, 0xd42ba2da, 0xf4b1a2bd, 0x9492fd7f, 0xa036c10b, 0xdc931c19, + 0xcde6bc4e, 0x2ff7743a, 0xfb306928, 0x8e620ae4, 0xc2ef3bc5, 0x3321b77d, 0x2cc0575f, 0xc75a5695, + 0x82e02e8c, 0xbe427883, 0x8af2f521, 0xffed96b9, 0x2d1595a0, 0xf22ceb59, 0x92ba2fc9, 0x13485e01, + 0xf53c8384, 0xeaf477ea, 0xff7459d4, 0xdb3e9336, 0x9cce28b0, 0x363ab867, 0xd504f950, 0x0030b626, + 0x5305411f, 0x10fe2042, 0x500ddae3, 0xd0c90a8b, 0x34168362, 0x72172553, 0x59ab64d9, 0x51c806a7, + 0x9ff7e244, 0xad0f6e1f, 0xa78acea6, 0x0f863382, 0x2c6964bc, 0x071ad85c, 0x70c37891, 0x6c6846fd, + 0xb84b6082, 0x79944b6b, 0xfe2e5c3c, 0xc05c8ad5, 0x2d863557, 0xdd70e120, 0x19147a86, 0xc6483cfb, + 0x120969d7, 0x69477ae3, 0xc2eb44f0, 0xb3ff79fa, 0x4ed91aa1, 0x808a5754, 0x9949ff45, 0xaa3a1317, + 0xd6a1f92b, 0xafce471a, 0x96076d7a, 0x314d1714, 0xe97cdafc, 0xa921a482, 0x1694396c, 0xf94a1113, + 0x228a4018, 0x3d3594df, 0x8bdb18d2, 0x92e3b6e6, 0xd2fce7b9, 0xbd34ad02, 0x62ddc60a, 0x2dbe0a6b, + 0x8ae5cbd8, 0x8db7bec1, 0x83bd23f7, 0xa8bf1f73, 0x84def1ee, 0x8806f917, 0xbe3351f8, 0x6fcf9a03, + 0x9af931c2, 0x2fc56693, 0xaf7365df, 0x7f157fca, 0x1b6ca2da, 0x7e69fe9e, 0xf0c3a34d, 0x382d6885, + 0x3102ece4, 0xad009b04, 0xd5a0d9af, 0x5006729c, 0x8fb41ecc, 0xfa93b611, 0x101fa15d, 0x3b536698, + 0xe63687ea, 0x632ce90d, 0xfb8769ba, 0xee3dec2c, 0x07e852fc, 0x11bcb2fe, 0x8f053aec, 0xd0ed38dd, + 0x550c5a33, 0xd426155d, 0xe56ecfb5, 0xdb8757ae, 0x1835bc71, 0xbd2ba651, 0xe1796146, 0xe5d37814, + 0x34d16c82, 0x4fbfa6d1, 0x7211a8ad, 0xf1d0a5b4, 0x634af373, 0x726da63f, 0x7a1496e3, 0x7f9c81e1, + 0x8960741e, 0x04ddcc27, 0x3300e724, 0x73303511, 0x98f86764, 0xde967f44, 0x72ebbf56, 0x9bd71666, + 0x67f46439, 0xb83e5357, 0x97d72f03, 0x2eea3a0c, 0xc6edf992, 0xe9cea1c1, 0x4560fcb0, 0x6b80cf52, + 0x0498413a, 0xbf9578cd, 0x2eb19449, 0x24bdd927, 0x4d59a344, 0x83dcfbdb, 0x90d97e16, 0xeeb5efc4, + 0xf48c028c, 0x8ed7742c, 0x5fafd724, 0x3f05d748, 0x341d1e71, 0x2c32b448, 0x5a509160, 0x64b79f7a, + 0xd50b7fef, 0x6ade38d7, 0x152ffdac, 0x2d01e930, 0x870ae271, 0x4ede4608, 0xf3097d1f, 0xeaa2c479, + 0x29e41fd7, 0xb0e32b98, 0xa155b5ed, 0x252330f9, 0x133b2d2f, 0xf56978e3, 0xfca5197b, 0x48f98223, + 0xd3f24dd3, 0x2ec3bd8b, 0xfdc30040, 0xa54e24c4, 0x76890eff, 0x019a8b6f, 0x883f24bc, 0x39776113, + 0xb1f03877, 0x45b67f45, 0xbcb51c74, 0x50dc8b81, 0xc2ebb5e2, 0x6af55969, 0xc1e15c8b, 0x8723dc98, + 0x2f19204b, 0xa545dc4e, 0x7fb4500a, 0xa108e898, 0x6934e51b, 0x9d874681, 0xf98cad9b, 0x93b1717b, + 0x8a148a74, 0x683d4774, 0x262ecd57, 0xba179a6e, 0xece2446f, 0xa13e950d, 0x5256248b, 0x5999c9fc, + 0xfcacf8f1, 0xb6e23eec, 0xcbd68782, 0x07ce081d, 0xf727c701, 0x3f37e526, 0x240725b2, 0x8c7bc3b3, + 0x40a16027, 0xd531de02, 0xa2c4d3fc, 0x60514d2b, 0xa4a4795e, 0x227576c2, 0xc2d70489, 0xb93caa27, + 0x4bba9bf3, 0xbf3a81fd, 0x722b42af, 0x813610c7, 0x9b82bdd6, 0xdcce30c6, 0x09e6c16d, 0xe1234031, + 0xa5520799, 0xfc024d56, 0xd226f344, 0xdc23c095, 0x55577bb2, 0x4b3e6d6c, 0x6b14a1a7, 0x7c48fdde, + 0xff7b4b42, 0xd691ac47, 0xf4fe3756, 0xe0c1578c, 0xa7fec7f0, 0xb29cbea4, 0x916cb88a, 0xddb57791, + 0xe364fa77, 0x9c19ef89, 0xcbfeedfc, 0x6ea8a24b, 0xac2824e9, 0x976d75ac, 0x3fe711e4, 0xb31172d3, + 0x01606422, 0xcb39007d, 0xc2dc4cd2, 0x30fe18ec, 0x8ae02197, 0x725a75b5, 0xa817aa87, 0xa39ad8dd, + 0x6d54189e, 0x27ffe6b0, 0x8df16601, 0xc1620e02, 0x74b4a085, 0x302ba080, 0x0af75eea, 0x56c97567, + 0xf3885976, 0xb58b1eb3, 0x3674b1ef, 0xb544e40d, 0x13cf254f, 0x518da6fc, 0xafc92e16, 0x71697e59, + 0x719be28e, 0x740e4a95, 0xa88a3891, 0x424603f6, 0x54339630, 0x0951fd01, 0x5b4137aa, 0xf72a1271, + 0x38597117, 0x76387582, 0x1d6dd347, 0xccd17a36, 0x781b476e, 0xb923fb86, 0xafd70bc7, 0x42102573, + 0x1935553c, 0x75ca5b0c, 0x65a0ed6d, 0x41a5327c, 0xbac6237a, 0x799272a3, 0x0cc2dc52, 0x5cc58268, + 0x856b3477, 0x86eae898, 0x71554ceb, 0xf5b7a9a0, 0x140dcd71, 0xcae56531, 0x41247804, 0x89d16356, + 0x1a882fb1, 0x2e93e19e, 0xf0cb2a5c, 0x73fbe1ab, 0xa983a52d, 0xd6b7d54c, 0x3d49403d, 0x330f4f2a, + 0x9e4bcfa4, 0xa8463365, 0xaeea71e7, 0xd8b4e7a0, 0x33ff057f, 0xbe974849, 0x4fa489cf, 0x12d6f927, + 0xb80ee410, 0xb55ef4aa, 0xcfeff96e, 0x7ac254f6, 0x5ce8746f, 0x9e769aed, 0xc4dbf669, 0x0121b701, + 0x1bacd53e, 0xf1ea4b4d, 0xd4753ec5, 0x437058f4, 0xcbc9a9f9, 0xab17c782, 0x86769ddf, 0x3e64312c, + 0xa0194181, 0xaa9f8b1c, 0xbd3bb962, 0xf121b6b4, 0x094a1b06, 0xbbaa613a, 0x0018adf4, 0x4fcaf534, + 0x194f24cb, 0x8430618b, 0x2a8ce040, 0xd16fc454, 0xbc62d4e0, 0xf9177710, 0x91b424b7, 0x58d83e4b, + 0xf71c97ee, 0xabcca69a, 0x05df64f0, 0x13067ba2, 0x621821ef, 0xbfcebde1, 0x8ff1965d, 0x9e76bd62, + 0xbc0fdac5, 0x13ef6a50, 0xfe2a9c50, 0x57b47b00, 0x8ef55cc8, 0xdc59ab8c, 0x31765c67, 0x3d6b0e9e, + 0xca0443bf, 0xef941318, 0x8492be12, 0xd8b0a4f6, 0x716c4a7b, 0xca34d4cb, 0x243005dd, 0x59da802e, + 0x4aaf285a, 0x80eda488, 0x1b7af95c, 0x717dc877, 0xe951d0d4, 0xa7edef57, 0xba74d7eb, 0x823763c7, + 0x539c55f9, 0x162dcc8c, 0xb029a205, 0x4b8556b6, 0xe5c37b27, 0x7b9b2a07, 0xb691d554, 0x31dfc03a, + 0xbb90e58d, 0x36319727, 0x8b79d056, 0xf19666d7, 0x8e2ab56c, 0x9dfc8a1d, 0x954a7576, 0x2954f657, + 0x26ba17de, 0xa07d57d9, 0x4f465e4e, 0xdee4f680, 0x0d589c4e, 0x50369f2e, 0x73b074ac, 0xc8195858, + 0xbbd7bdd7, 0x85449e65, 0x4a4558bc, 0x4171f947, 0xe90370f7, 0xd8e5be58, 0xfdb39afb, 0x3a256fd8, + 0x6328d88a, 0x5f6b3c29, 0x40dde9bb, 0x8915a69e, 0xfbea4a10, 0xae8803a1, 0x42be2907, 0x1357b3de, + 0x5cf65e55, 0x00df8609, 0xaff3996b, 0xee16539f, 0xf5397338, 0xde55b0e6, 0xd01cbca9, 0x658fc397, + 0x97bcd33d, 0xef35c984, 0xeb2ff695, 0x39c9e1ea, 0x42248048, 0xa3bf1c7b, 0xef4cd181, 0xcffe129b, + 0x24fd111c, 0x538d9d10, 0x730c2220, 0x80908d05, 0xe451c48c, 0x4c37b598, 0xa074c5ba, 0xadd910c1, + 0xfaa2e9b9, 0xfa50a775, 0xff0ce95b, 0xb2f91edf, 0xd20ca357, 0xfe9ff38c, 0xa18e77a9, 0x9db447ff, + 0x33dc5e7c, 0xbdc77119, 0x951f87ab, 0xe0e13407, 0x2c9e9469, 0x509de2ce, 0xae704798, 0x83a818d3, + 0xf8682316, 0x078f525c, 0x0f0889fe, 0x49616e99, 0xa7b64f58, 0x5de3fef6, 0x147e4e7f, 0x0e982813, + 0xe4d878d5, 0xbc0b4397, 0x7de040df, 0x405fb8bd, 0x6a74115b, 0x305bf034, 0x4cf3bd0c, 0x443a08b9, + 0xf010dfba, 0xa16c1240, 0x21ee2861, 0x96085e7b, 0xca2df430, 0xc0b7d8e0, 0xfb1b8ba9, 0xfc548dc0, + 0x69e6a69c, 0x2cf02bc7, 0x7e800a06, 0x96728d32, 0xc02116a4, 0xb07e6370, 0xb0f35454, 0xc6412ed0, + 0x4d85b7f6, 0x1beab65b, 0x3dbecf88, 0x92c8b438, 0x23556beb, 0xb267d15b, 0x07c33a15, 0x113e1d06, + 0x44aef291, 0xd0f1163e, 0x87330173, 0xe45713da, 0x19411191, 0x6ad2af32, 0xd66a7eff, 0x280806f6, + 0x0863c4cd, 0xe71a4831, 0x966bd33f, 0x45fe8082, 0x5fa134b3, 0x42fff11a, 0x84001f85, 0xbe86ada9, + 0x597d9f58, 0x8bc0fdf0, 0x756b029d, 0x3caec56c, 0xa505c999, 0xf44fb413, 0xf10d7c2f, 0xc43a32a7, + 0xc703de01, 0x9e1247b7, 0xaa713e0d, 0x4536d6c7, 0x405fbebf, 0xf2370387, 0xda02dc99, 0x401847fd, + 0x208e71dd, 0x7100b8e1, 0x25e5135f, 0xfe488dfb, 0xfc5cb95f, 0xd72ef5ca, 0x5b1c4e2f, 0x92aff5b5, + 0x2fe43482, 0x59b4e2e8, 0xbd65dc6d, 0x950611f7, 0x1198f4e5, 0x8f87625b, 0xa0340a4e, 0x6eb193cb, + 0x11ff8270, 0x22699098, 0x39f6743f, 0xa9c399e4, 0xfd599140, 0xd64786a4, 0x13778fba, 0x04736bfc, + 0x717ee585, 0x42ffdf14, 0x880cf4c0, 0xd9b19efb, 0x4e070c77, 0xb7242bc7, 0xee7fd1e9, 0xdd84f048, + 0x6619d643, 0x0066f114, 0xf36c9b46, 0x2b0651d6, 0xd5e6354a, 0xbb072de6, 0x62c9748c, 0xd7f9354e, + 0xf98d5971, 0x4c6e223f, 0x6a0bd7f2, 0xe40d3bb1, 0xc63d9441, 0x8432219d, 0x55d02e6f, 0x3f0a55e3, + 0x3af6d64c, 0x849adbf9, 0x2097c2d5, 0xc187c778, 0xc33a4ea8, 0xa2d555e5, 0x5e173161, 0xb0f7a191, + 0xaf04ec53, 0x76789772, 0xf536cfdf, 0x2b771aa2, 0xf12f1015, 0xaca5de65, 0xde5fd954, 0x3ece12bd, + 0x37494551, 0x76b54a52, 0x869e615f, 0xed6af64d, 0x480eac33, 0xb7c6dcb2, 0x0ee99493, 0x11e88fc3, + 0x9295754e, 0xddb2b022, 0xa595e4b9, 0xb33dfbe3, 0x17bc6435, 0xcf2c9240, 0x3fb97378, 0xc07239c0, + 0xa7be783d, 0xfb021ef7, 0xbe3dfd8c, 0x37403d93, 0x2ed93b1f, 0x74421749, 0xcb2ddb84, 0xc5efe3b6, + 0x97b85788, 0x5641504a, 0xb1c92e3e, 0x31b2f9f6, 0x2e372476, 0x19743537, 0x7fe8ceae, 0x50d1f94a, + 0xbf61c896, 0x5fe8dd12, 0x3cf77a92, 0xe8b8a305, 0xee204152, 0xf7a7e2f8, 0x85f041fc, 0x28780db0, + 0xc977f3ca, 0x8a4e7609, 0xfaa5e614, 0xe3c89f07, 0xe5ec8567, 0x12f7dfa5, 0x01ca5b5e, 0x8e3d9385, + 0x5db2dbf1, 0x495c737a, 0xab4d7638, 0xb8f3e856, 0xfc0340f2, 0xe05d0e7f, 0x9620294d, 0xa9736273, + 0xf232bd4f, 0x40d89d27, 0x2f0d3cfa, 0xa0ec84ad, 0x01751045, 0xdeab4b65, 0x6980c100, 0xf0b7db0f, + 0xcc1a9d9e, 0xe816a32c, 0xfdf0a285, 0x2f651cc9, 0x364ffcc2, 0xbd38c0f3, 0xc9b7167e, 0x632ef8a4, + 0xbba8f8c3, 0x04ec15f8, 0x8646de6f, 0x036ef85a, 0x7bdc9147, 0x0bf546f3, 0x13ed7253, 0xe81db2a9, + 0xbd206923, 0x0711b7d2, 0x703e6a1e, 0xbe1df372, 0x378c4ff4, 0x849a224f, 0x0d660476, 0x7b479e30, + 0xef6608ce, 0x656217ae, 0x3b5ea4dc, 0xad79521d, 0xe154033e, 0x02d3dd22, 0x5cecf5c1, 0x3c0684cc, + 0xb4525f26, 0x56566f09, 0x1856d530, 0x8b4db349, 0xbdcbe722, 0x8e27e5c7, 0x2874609e, 0xc2a75ec7, + 0x362b51d7, 0x6680d585, 0x6a47d4cc, 0xebca66d0, 0x37ad761a, 0x0a85fac4, 0xcb1dd454, 0x4b9690d1, + 0x11ed5dc0, 0x8375497b, 0xdbf24db0, 0x6f9d2ba7, 0x2cbdb80a, 0xf6c917ef, 0x0ff94f3f, 0xbde979b5, + 0x7ea714f7, 0xcd6fec09, 0xc24bc5dd, 0x3f27db3e, 0xa76bec59, 0x179411a0, 0x8f26a693, 0x9fd15d37, + 0xcbe5a6c4, 0xfa52152e, 0x5546972e, 0xd9bacbbb, 0x9f86b6d8, 0xf0b9ed20, 0xa7e01a95, 0xa7f2c23c, + 0xa2e1d366, 0x7b96d1df, 0x46dc9d15, 0x794e40d4, 0x1b3a7723, 0xfcc503ff, 0x2b1466f1, 0x328a7f41, + 0x17f3d54e, 0xa63cff68, 0x829d60a1, 0xb0cc6746, 0xe5d4bdb6, 0x1f5ffc4f, 0xabbfae28, 0xee1270a8, + 0xa4e951f3, 0xc3264578, 0xc4d8365f, 0xa7ab9363, 0xc66f4fc0, 0x762d909b, 0x263d4b89, 0x3d1c7365, + 0x5bca47d8, 0x24e86967, 0x04ec1502, 0x3186a2e2, 0x6e39e91b, 0xcf57de91, 0x61aa7dbf, 0x9365e90b, + 0x7701f16d, 0x27cdc298, 0x9265bbd4, 0x8c4f1f24, 0x839523cf, 0xe4439d6e, 0xb9cc3945, 0xcbb693f7, + 0x9472f518, 0xff46af72, 0xea75936d, 0x3c99b545, 0x45f39a94, 0x5e2a34c3, 0xcb1cc5de, 0x6a934e32, + 0xd37babb0, 0x225116dd, 0x686ec751, 0x6e287054, 0x61ede5ad, 0x897f5765, 0xb069a69b, 0x4525897f, + 0x51e13b29, 0x7d315247, 0xcbd82593, 0xe53f41c2, 0xd724043f, 0xb1bb5194, 0xb53b0ab9, 0xcce8b483, + 0xb2f11810, 0xd2ccf876, 0xc967c109, 0x61ddbaa1, 0x1a8959eb, 0x60f51b84, 0x331f1c57, 0x8daf0580, + 0x481dccdc, 0xf4648615, 0x8c8749dc, 0x95867d8a, 0xddb0cf9e, 0x65b28d86, 0xf5f41d12, 0x1acb3812, + 0x0b18048c, 0xaf953eb3, 0x050d9227, 0xc9415b8e, 0x41c513dd, 0x54f3e494, 0xef46009a, 0xee30fbd5, + 0x9f5c871f, 0xfb44b3ad, 0x5274a85e, 0x3a50a102, 0x53525391, 0x5de228a6, 0xe2f7d662, 0x83d346f7, + 0x034226d1, 0xe099feee, 0x90469d01, 0x2eb39176, 0xeff4444a, 0x1ad87b52, 0x76918bd0, 0xaf815e16, + 0x2e3f070e, 0x0d954016, 0xc591b1da, 0xeb0af715, 0xc7179408, 0x846a95ee, 0x2930ccbc, 0x551ac7b9, + 0x8486f80a, 0xa0c5922c, 0x79631b82, 0xee44f99b, 0x60db5973, 0x4ba8f897, 0x6c2b4df5, 0x417e0d24, + 0xa7aaf502, 0x45298d48, 0xfc8d6fe0, 0x648233dd, 0x5b36a861, 0x450d0623, 0xa565b743, 0x1141aa1e, + 0x7acecdbe, 0x6c69c4bc, 0x603aea64, 0x27cb630f, 0x997563c3, 0x5ce91178, 0x732f547d, 0x0883fbb5, + 0x97bf3a38, 0xad49e986, 0xed866456, 0xc3964b28, 0x2d8775aa, 0x5ddb24c2, 0xc25afce4, 0xb9f7e92c, + 0x4d9900b3, 0xb824249e, 0x57d0989f, 0x1562a635, 0x89d4e5fe, 0xbc060754, 0xd2884320, 0x198a652d, + 0x1d086878, 0x73f09104, 0x45fea68d, 0x188e774b, 0x089fbaf6, 0x421d1c77, 0xa34277df, 0x5f6ee48e, + 0x65ceac97, 0x7359224f, 0x8290de41, 0x502917c7, 0x09da13e2, 0x585a0221, 0xe359736c, 0xc07d9b25, + 0x0d3ad7fd, 0xd19db80b, 0xf16d10df, 0x22e334e3, 0x37332c5c, 0x19b47730, 0xd5f76842, 0x2f6a83d9, + 0xe624f0e2, 0xbd8e450a, 0x8fb5fe3c, 0xfe25183f, 0xcbcb754f, 0x6f85deb6, 0xa729fa7c, 0x5227e282, + 0x9426fbed, 0x628f7e05, 0x95aa8813, 0xf086137a, 0x3258a374, 0x6c02514d, 0x0aa1867a, 0x9ceba43a, + 0x2296b8d6, 0x53e32cb6, 0x5d5ef267, 0xbb7c5b09, 0x015a896c, 0x6885c309, 0x8d58e0f5, 0xcc067bc2, + 0xde9c4491, 0xbe847e53, 0x48952163, 0xf24cf1f0, 0xc002c4e9, 0x047ebc87, 0xaf748ca4, 0x4975fd34, + 0xc4840210, 0x35f269cd, 0x62cb4240, 0xe1dc4426, 0x2485dfe4, 0xb78e5b14, 0x37291775, 0x99c3ad86, + 0x24f6ed25, 0x12e97505, 0x3faac728, 0xd977deee, 0xd840a74a, 0x05fe08da, 0x6d346b1a, 0x5a602001, + 0x4a49884a, 0xa054e2be, 0xb26f1f72, 0xa6c2bbae, 0xfb9ed6d2, 0x9bc21fad, 0xe4fe0090, 0xf405e16f, + 0x02da6b81, 0x461bc57f, 0xa38a9805, 0xda01705d, 0x406eb083, 0xfa0b7da4, 0x42055f75, 0xe9abc291, + 0x5ed0df7c, 0xbdae3675, 0xfb045282, 0xc2fe7602, 0x9bb79499, 0xc28d14f2, 0xcfd6c14c, 0x901bc8fb, + 0x850b4593, 0x7cfe518b, 0x8c1cdde2, 0x2c47668c, 0xd1905870, 0x95b9e3b7, 0x93749e57, 0x247e1212, + 0x27892275, 0xaba51320, 0xc1a21326, 0xa5ce972b, 0x3eb1346d, 0xc4b83f70, 0xa03d3b58, 0xc785ec76, + 0x07a96578, 0xbbf5155a, 0x2e993f9f, 0x129cf0d9, 0x1cf33222, 0x22c16978, 0x7a6e408a, 0xf6f9f43a, + 0x5d59ef02, 0xbe4157fb, 0x87492025, 0x2ced31af, 0xa9806a37, 0x7d876125, 0x91161f53, 0x06c42414, + 0x2cbdc6df, 0x89da1990, 0x680f1128, 0x1b028477, 0xb2f093c6, 0xffa74f89, 0x95279eb7, 0x1cf61a2c, + 0x4f1ca553, 0xe5a94cd1, 0x116cee15, 0x29ae42a3, 0x0b89aa44, 0x59bdab98, 0xc28c1ea4, 0x713e6c6f, + 0xc9b073ac, 0xf91e292f, 0x457e6ff1, 0x7221e2ba, 0x77826e12, 0x8e652709, 0x196e88bc, 0x4dcbe3bd, + 0xbda777aa, 0x037879c1, 0x275571d7, 0xfb5c01f0, 0x450c76a7, 0x427c7645, 0x382fa37d, 0x4f8adf5d, + 0x35170264, 0x5fa8449a, 0x400ef1fb, 0x42891559, 0x1627e97e, 0x7adf0e98, 0x6bba9a0c, 0x3f9e28d8, + 0x9da1321b, 0x8572ccc7, 0x785bf029, 0x05ca6bb2, 0xa245e2e9, 0xd5da646a, 0xf85b77ca, 0x930338b7, + 0x307fc2d1, 0xbfd7e1bf, 0xa4ba204f, 0xd2d19d2c, 0xb5c1bbef, 0xc6968028, 0xd1e935f2, 0x6b134586, + 0xf81a50d9, 0x62413fcb, 0xa37ff527, 0x4e749853, 0x1a37e107, 0xc1864bbb, 0x6bd491a6, 0x44d791c1, + 0x5f956a6c, 0x0c9b87ba, 0x43c9400f, 0x7ece8d16, 0x7e093e91, 0x7d248083, 0x57dc37c0, 0xbc90044e, + 0x20c3cbc0, 0xca64a38f, 0xaa2d16cc, 0xc1ad73e4, 0x4f3c7f9c, 0x14c61ee6, 0x26d40833, 0x17335292, + 0x08a04315, 0x5791e702, 0x26a138b3, 0x2a492676, 0x66f348cc, 0x7aef91c0, 0x639cb42a, 0xbac05af9, + 0x5b76bafa, 0x2a9a8d9f, 0xd64af1e4, 0x853b2eb5, 0x3b4311c6, 0xb3232a1e, 0xef443620, 0xf317f77a, + 0x4f68da22, 0x3a59e7a3, 0xb95d9925, 0x6ecbd6a7, 0x1d76faba, 0xeac88212, 0xccf8eea2, 0xa7077f10, + 0x5b39dc1f, 0x6c3822c7, 0xece785a3, 0x4b2d6a59, 0x9765f606, 0xaa1d7cae, 0xc84340d4, 0xd9ecf1ac, + 0xc7aa3e87, 0xc042127a, 0xbc085d73, 0x03560401, 0x7237de04, 0xf0f75507, 0xb3da82b4, 0x89fc4539, + 0x248ca9d2, 0xe158dafe, 0x022c4453, 0x3ccb1300, 0xb3194784, 0x72928b88, 0xe47d93db, 0x0819c2b7, + 0x520cbf47, 0x9ee51a32, 0xcc7656ec, 0xb79d4720, 0x95a2d96f, 0x076c6712, 0x2a41f93d, 0xacc48926, + 0xa2e7d731, 0x66a70daa, 0xabf0dc4d, 0x5251287b, 0xdb734a33, 0xc0fdd399, 0x5d5258b8, 0x5be5cafa, + 0xe6e36cd3, 0x032c9ecd, 0x3bfc26b5, 0x5e572f67, 0x80647054, 0x8ca9a394, 0xdcaee56e, 0xa920eae9, + 0xca6ac552, 0x3110f098, 0x59b1dd4d, 0x586d15bb, 0x749cc1fc, 0x13004cdf, 0xf8eef2c5, 0x0ea51930, + 0xaf2317cc, 0x68b17cdd, 0x0dbba483, 0x4f9def54, 0xf908fdbf, 0x51c5b2e8, 0xdfc19090, 0xd0d34f69, + 0xd44a43db, 0xd1d0ac87, 0x0b5ee3f6, 0x27368fa6, 0xf081194b, 0xa70a21bc, 0x120e47b0, 0x0953813b, + 0x628d91c6, 0x7e628f42, 0x84c22e9d, 0x15f8ed83, 0x73b888b6, 0xe17c6550, 0xc568ceb0, 0x244cb4c5, + 0xe882e2d4, 0x658a940e, 0x59c55097, 0x606c20ed, 0x567d6f90, 0x20ab6f2b, 0x1fabb466, 0x9e4fb937, + 0x89fbe04c, 0x88a08ca0, 0xa38795b3, 0x2b520926, 0xcdefafff, 0x8a31d320, 0xb43c6178, 0x7ac21d9b, + 0x6bfd3a4a, 0xbe81607b, 0xc03466cd, 0x992330cb, 0x19cacac2, 0x10744b18, 0x03981d7e, 0x33d61e4c, + 0x39b2b746, 0x023627ed, 0x18829547, 0x0cf7c7fb, 0xc9ecdb95, 0xc4360f97, 0x4dad870a, 0xb41b9342, + 0xd783badc, 0x0ae9af45, 0xcc49b4d6, 0x29080d1a, 0x3a487a31, 0xe6ec5271, 0x123ea39d, 0xf8a84a00, + 0x8b826fd1, 0x9df3fe74, 0xe0d889ba, 0x48fd5257, 0xfc8a3dce, 0xc4133600, 0xf341c93e, 0xef8d82d8, + 0x9235beb3, 0x23317f6a, 0x86d0ee48, 0x7f97bfef, 0x59c4c42c, 0xe89bebcd, 0xabdc27a7, 0xb77d9fba, + 0x0ec13a9e, 0x7b050882, 0x8ad0f652, 0x2cbed378, 0x335888ca, 0xc9556358, 0x413db547, 0xa9cfd17f, + 0x2d02d552, 0xd6624b54, 0xea7b9f68, 0xd6fc1a2c, 0xbd4b2d21, 0xefb0dd3c, 0x78916a28, 0x290e5b91, + 0xad12bcb8, 0xf5956684, 0x18c030c0, 0x8c9f5471, 0xff1067eb, 0x998d61a6, 0x9ecd98dc, 0x1c09a82d, + 0x4f91b509, 0xf883565e, 0x4756601e, 0xbc632331, 0x8f37ab08, 0xf22eb732, 0x871d022a, 0x0843cf67, + 0x401794bf, 0x18049f53, 0x2f7652be, 0x301c3acd, 0xe99020ed, 0x164d55de, 0x23261d96, 0x65fb4cc2, + 0x935f873e, 0xd9fe7bdc, 0x7e801fad, 0xb8755845, 0x1fcfa1bb, 0xb6d85673, 0x4f57d02b, 0x4e2c8ce2, + 0xa21e2ec2, 0xe729d8c3, 0xceafaf48, 0x6d10c719, 0x5ed1f4da, 0x491bfec4, 0xed67e60f, 0x45b364fa, + 0xa33e1836, 0xcb5213a9, 0xac85af58, 0x3358e02e, 0x0cfea9f2, 0x7ef6db83, 0x60e32805, 0x1995c9af, + 0xf2c06c53, 0x96fcbd97, 0xc772f2e2, 0x61dd130c, 0x8389561c, 0x804978be, 0xe8cb54b5, 0xd9555a79, + 0x99d8b875, 0x449f5c83, 0x18ee103d, 0xf7b733c5, 0x23acb138, 0xd64b6cc3, 0x9c679b88, 0xf271e701, + 0x964a07c2, 0x2cc7e2fa, 0xeeed0aaa, 0x1e33295f, 0x18bf1862, 0xeb15452e, 0xbac34130, 0x10bddaa8, + 0xb1c2e465, 0x8e277662, 0x035da605, 0x35e021e0, 0x131cdf32, 0x7a7c1138, 0xe2e977f8, 0x6c4c4064, + 0x49a516a0, 0xf4f6beb7, 0x01b2cc78, 0x0e0ca203, 0x762880dc, 0x0ecbfcaf, 0xdd89dd52, 0x40bfc864, + 0x28d88e96, 0x9404bbcc, 0x4efdd112, 0xe0be857b, 0xe2a30991, 0x748bbdd2, 0x210bada7, 0xdafea84e, + 0xf7284d51, 0xa8471349, 0x09c89d2b, 0x6fbd7ef8, 0xb0178f6c, 0x00d6744c, 0xb50adbb4, 0x38eb094f, + 0xb74998de, 0xb3e3ec9a, 0x454f5f08, 0x32cbe6a0, 0xaa30e397, 0x3083ce0f, 0xa4b04359, 0xd383cefe, + 0x73ded464, 0x205e8a96, 0xf0ceb2bf, 0x6e4d2124, 0x1d82df8a, 0xafd59ba2, 0x5b379aca, 0xa05384fe, + 0x44918171, 0x6a89630c, 0x957f2855, 0xd28ef752, 0xeea372fe, 0x3ed102de, 0xdd1b0c6a, 0x672b4c7c, + 0x6f3a6e0e, 0x179cd8dc, 0x539fe9df, 0xb8a3557b, 0x982eb403, 0x1653936b, 0xe805457a, 0x7e7224b5, + 0x69fd6552, 0x928d4478, 0xfedb5597, 0x36722d3b, 0x9c5d8d6e, 0x695b98fa, 0xe9bb5120, 0x3321979e, + 0x15c8c5b1, 0x6f6276df, 0x5cf88550, 0x6ed1a06a, 0x98647c33, 0xa487d6b9, 0x1c5221fe, 0x20ab75ed, + 0x60b49088, 0x41655f0a, 0x98d07e1d, 0xa62386c7, 0x7d378c66, 0xe2e249a5, 0x83027164, 0x0df304d8, + 0xc45fc853, 0xdd6c0dfd, 0x222a872f, 0x61a296f1, 0x985b30ab, 0x028e1ae6, 0xe9059682, 0xcc2e1c0f, + 0x2e566d85, 0xf2aa5b58, 0x499e6614, 0x81b8c40e, 0xd05885fa, 0xc13606c6, 0xc6b8a095, 0xafacbab6, + 0x079e74c7, 0xa805d334, 0x1f852ab7, 0x09d92444, 0xb4ab3ff9, 0x0e02e8f7, 0xd5d13172, 0x1b26adfb, + 0x72fe8ce9, 0x4913352f, 0x5d414507, 0xdba69b85, 0xf89805b1, 0x77a80f1a, 0x6361795b, 0xd39ad649, + 0xe7d4a28f, 0xe7c76636, 0xbca53a8e, 0x3d9bb6e7, 0xdb623859, 0x80b19416, 0xc152d7cb, 0xb04e7cd0, + 0x26dd60ab, 0x5fab62c9, 0xb6fc6d48, 0xd0f8640c, 0x39a8f5ae, 0x420bffd6, 0xe7d95b1b, 0x90c90169, + 0x1a37d023, 0x5efaf8cd, 0xbbe538c6, 0x46db3132, 0x591a9552, 0x2fa66064, 0xa8d30e4f, 0xd48d24e9, + 0x95925bc1, 0xac4c5b38, 0xc2afcf1f, 0x3ab57020, 0x89010abc, 0x40a8ccbb, 0x1d053500, 0x443f0fc6, + 0x0f1c11d4, 0xcd4e63b6, 0xb25e01ac, 0x1bcfdbef, 0xf937f17a, 0x22de65d3, 0x403c559d, 0xf52c767a, + 0x9a5262b9, 0xa667bd59, 0xf02a2ff9, 0x88273950, 0x9406038e, 0xe5c0647d, 0x05eefc66, 0x6fa31827, + 0x2916afc6, 0xe273abc8, 0x57645f45, 0xaef3b010, 0x54c5dcd6, 0xfb7f3d08, 0x53c60878, 0x631af9bb, + 0xe48665c8, 0xb5a2b47e, 0x16e8febd, 0x08dd527d, 0x1c1f57fd, 0xab910d99, 0xc89555c2, 0x3c0e8a96, + 0xd6714f2c, 0xa393a62e, 0x13a73cb9, 0x240a0ce5, 0xf140a6dd, 0xbc102d13, 0x98241f7b, 0xec7c029d, + 0x37189445, 0xa144101b, 0x9b1faf55, 0xeea59b25, 0x5aa4a810, 0x2cb76d6e, 0x7f176300, 0x515bcba5, + 0x905690c2, 0x945d0476, 0x1a5466b2, 0xb33fec27, 0xaf3efd59, 0x67ba15e2, 0x765950e1, 0x747d467e, + 0xd97c2e2c, 0x8d2499b6, 0xfe16f2f8, 0xe6548d22, 0xb399ea90, 0xe7e3668f, 0xddf0440b, 0xa00da01d, + 0x2f5bd627, 0x3df10a87, 0x6bcaa847, 0x76b38283, 0x513eb9b3, 0xc6dd3bd4, 0xabcb03e7, 0xe29d0716, + 0xe5cee09f, 0x248c4409, 0x917dacd1, 0x4cf7dc97, 0xf8e2e05a, 0x7379ed27, 0xa1ae1653, 0xaafca76b, + 0x97b80ce1, 0x1bddcf4f, 0x33a4c8d3, 0xf65173de, 0xc55fbf4c, 0xbcd6ced9, 0xa11d450f, 0xef5dc053, + 0xcfeb24f9, 0x00574afa, 0x4375a192, 0x148dd2d2, 0x609cb470, 0xe4a1a4f1, 0x5cc73662, 0x291fd928, + 0x749c5d18, 0xa3e74224, 0xc08d3cd2, 0x254f8657, 0x9f7784e6, 0xd31721e9, 0x57654d5d, 0x5edd812c, + 0x1b321713, 0xc38f7137, 0x648b71c3, 0xdf8bbaf1, 0xf7bd73ce, 0x81eaacc4, 0xe5591cc8, 0xd61a8d26, + 0x7dee3afc, 0x19a53d33, 0x9e5735de, 0xefcf30cc, 0x462a139d, 0x2adafda3, 0xbb4b2a2b, 0xc7ed43fb, + 0x17eab73c, 0xea6c2ddf, 0x76fe97d7, 0x34a718f5, 0xcd063b93, 0x65ae57da, 0xb71811a6, 0x03652ead, + 0x78131e83, 0xee3bb615, 0x9909b5c3, 0xf3e3ee21, 0xc45e5217, 0x46ed5315, 0xe805ed25, 0x3db151cd, + 0x5a679386, 0xe3bebc19, 0x1831a7cd, 0x727ddb4d, 0xfd0bcaee, 0x66d465f1, 0xb573ab82, 0x249fe47e, + 0x1601b7e6, 0x6acc4592, 0x47d47e6e, 0xa2d368a0, 0xeff62b3c, 0x524e7b01, 0x5f814ebf, 0xb6ca677d, + 0x4bf99720, 0x8bcfe4e5, 0xfcf969ca, 0xcc97f9a7, 0xc50cf7f4, 0x2aba6994, 0x7710694e, 0xe66bf0e0, + 0x0c901ae1, 0xd62e0d31, 0xc552718d, 0x5f3d11ce, 0x5e128233, 0xfdc1f247, 0xbf3b6146, 0x622fec6b, + 0x948e635e, 0x9e214a04, 0x73d028ac, 0xffa5f747, 0xb93da954, 0x8f6bcf2a, 0x24ecf78e, 0x699733df, + 0xbfed1fed, 0x5a410c00, 0x21c46ee1, 0x018b6180, 0x5c961349, 0xde3788a8, 0x456943e6, 0xad97d1c7, + 0xf7fa03d6, 0x17f94f30, 0xe31f4ed3, 0x6f9444e9, 0x19ec793f, 0xd9542e04, 0xfe978c44, 0xdc19defc, + 0x382b4548, 0x6ba7ac16, 0x96ebe019, 0x14652562, 0xc8b3cbe7, 0x78c8301b, 0x3e16ec46, 0x9c7dbd9a, + 0xa7a10ffd, 0x322e4b6b, 0xbe57033b, 0x798cc365, 0x41a76155, 0xe6cfe660, 0xdf777090, 0x7f0a4018, + 0xd7898a9e, 0x60984db2, 0x48b45704, 0xd44a5b9b, 0x907fcb6f, 0x7a8b720e, 0x6485df7b, 0xc5138124, + 0x971e65d8, 0x99bf803e, 0x0fb477ef, 0xa534eb7e, 0x941f40ef, 0xb6ff3afd, 0xca6e1773, 0x51ba8e83, + 0x1db71d65, 0xa3edbe1e, 0x6ccd8c8c, 0xb8ec4067, 0xb7e96b38, 0xd4c3ff1c, 0x64650a0f, 0x5ee81d95, + 0xf45230ac, 0xa1ef92fa, 0x707c53f8, 0x53c1d87b, 0xaae16c30, 0x7e4b275c, 0x6182c157, 0x7b872fdd, + 0x07ef11b6, 0x006d6ec2, 0xdcd292a6, 0xc7afd422, 0x3f8f6f34, 0x201c011d, 0x4a920ca7, 0x95213054, + 0xfb6874fe, 0xd512b785, 0x6c6acd22, 0xec96e42e, 0x9b326381, 0xe1c2fcf7, 0xcd262059, 0xe5570d2d, + 0x60afdd11, 0xb85ad26c, 0xe463aabc, 0x08d28cee, 0xbbe221c7, 0xf4b77211, 0x56b38740, 0x18486328, + 0xf808acb1, 0x4bd6f9f3, 0x18be4966, 0xf4c2375b, 0xe0a233c5, 0x0667ff33, 0x7bf27aa0, 0x13b8a8a8, + 0x17d68b4c, 0xd0d349f2, 0xba4bb245, 0x08d95ae7, 0x0dfc950d, 0x0c419db1, 0x71a7a5ec, 0xd7420285, + 0x1c19ba21, 0x54f93907, 0x35c93a9a, 0xd7a8d11d, 0x64c69478, 0x46f958cf, 0xd402ffd6, 0x429b57a0, + 0x1db69072, 0x893f1efc, 0x17eb6c1a, 0x957eedbf, 0x2ba8f4cc, 0x13fd7944, 0x7d9acb61, 0x59771752, + 0x49a6e805, 0x97c5b015, 0xf139f685, 0x300cdc8f, 0x56b99819, 0x0013a81f, 0xd8792401, 0x189fbe96, + 0x47ecb9e6, 0xb82fe818, 0x0f7597d1, 0xc8ec54ea, 0x851f0d6e, 0xf1afd7f6, 0x255a91f0, 0xa824544d, + 0x3670b07b, 0x90d84464, 0x38378669, 0xd842f5ad, 0x935dffae, 0x0835e06f, 0xd7c91d59, 0x5d8a7960, + 0x59488c72, 0xb5e88e34, 0x20079c19, 0x146d7265, 0xd76221d8, 0xb96ba466, 0xd752ba6a, 0xc3c094b1, + 0x002b37fb, 0x7c0a6d1a, 0x309c4f52, 0xfca1cec4, 0x55afcd43, 0xe632ef98, 0x3d8adcc8, 0xf82f4527, + 0x6d486ddf, 0x3b16d908, 0x5ee70fec, 0xd1ae8c18, 0xeb0e2c5a, 0xcb29cdfd, 0x5cb82936, 0x34a46ed2, + 0x6eaec876, 0x97d869cc, 0x55f231ad, 0xabc1015e, 0x7c39801c, 0xb7504b6c, 0x54143143, 0x42124fad, + 0x52a08bfc, 0xdf82453f, 0xe02b1eff, 0x9c35eb75, 0xfcae40f9, 0xd52dba33, 0x2d34c2fc, 0xa9eebbc0, + 0x214e9c41, 0x9bca2cb2, 0x4798fe6d, 0x84ad0cb4, 0x1f364b8d, 0x55ad8b1c, 0x16112cd3, 0xfae06dff, + 0x18782043, 0x9cf70099, 0x1f40676e, 0x2de68e11, 0x0729cd34, 0x3fb1dc48, 0x4d1326bb, 0xfb86447e, + 0x5812c3cd, 0xf982b563, 0xfc21ed28, 0x099b5239, 0xf0116534, 0xb1de1558, 0x7775ea96, 0x2f9f6166, + 0x4ef30401, 0xacf0c552, 0x203f5e94, 0x9a412a14, 0x352c5522, 0xcda9171b, 0x65dec37e, 0xa13ea6f1, + 0xe0a6238f, 0x3c35bf56, 0xf98dfb2f, 0x4fb9693b, 0xdfad957e, 0x73543dae, 0x26b71f69, 0xa47c9aeb, + 0x355cb830, 0x5e61262b, 0xb887432b, 0x38a4285d, 0x840630e0, 0x77fdf31e, 0x7fe7cea2, 0xf70918f4, + 0xfaa048d5, 0xe7c626b6, 0xb71d8130, 0xc831832c, 0x8683f8b1, 0x7cd2cec9, 0xecd861fe, 0xced85fa3, + 0x2915abb2, 0x3fc1b5f1, 0xd77866c4, 0xddcba677, 0xa3068594, 0xbfea45f7, 0x359ace91, 0xcdff2bdf, + 0x6f2a4107, 0x84d55df5, 0xb114f606, 0xe5a43062, 0x7ebcec75, 0xef5fe496, 0x5b37ac76, 0xca6c0032, + 0x9cf68556, 0x76d0f7d0, 0x03de82fc, 0xe971d46e, 0x1119681b, 0x2e04575a, 0x0c17cecd, 0x64d0df46, + 0xe5c13129, 0xc339ca3b, 0xcac1be40, 0x1233848a, 0x38f53051, 0x06a96fde, 0x42dfbc99, 0x6d604703, + 0x2091fafa, 0x7c8260d1, 0x32120630, 0x8a9a0d71, 0xb8f3b805, 0xed0018fc, 0xd9fbf729, 0x6b0410ca, + 0x724f22ed, 0x065193fb, 0x1152c288, 0x8be76efd, 0x28d8531a, 0x22c49290, 0x558b0077, 0x78508498, + 0xbb076f8a, 0x21218c44, 0x4970bae6, 0xa84bf94f, 0xe32098e1, 0xe3a1571e, 0xfcf05817, 0x45fa6e41, + 0x9ce9f79e, 0x0e477b3a, 0x0b967745, 0x75ad2c66, 0xcbefe58e, 0x71e552eb, 0x01e23248, 0xe113ad39, + 0x89840b4e, 0x3238253c, 0x75a9d352, 0x61b247c8, 0x1b434e7d, 0x9d0dc965, 0x95057fdf, 0x45378674, + 0x241d475d, 0x4464b7bd, 0xd59fb714, 0x65db24ad, 0xa6fa5741, 0x540f089f, 0xdd8d9eec, 0x79651d5b, + 0x9af57a93, 0x88fa0cbc, 0xaa0a7770, 0xa54176d7, 0xba7e1733, 0xa189ce5f, 0xc1b8786c, 0x41cfde6a, + 0xc8c4baf6, 0xd20f3e39, 0xdef8ecd1, 0x4c4af73c, 0x5f79092e, 0xde4540cc, 0x222bc245, 0xd13fa053, + 0x6dfd01c6, 0x24a0e4dc, 0xf9e4df0b, 0x5bba50c6, 0x4bcc8f6d, 0x6256e9ab, 0x64429329, 0xdb8866cd, + 0x5ff08cf9, 0x322efa64, 0x7b8a4b15, 0xa7a3057a, 0xe943dd07, 0xa19aeee7, 0xf8a8451e, 0xc6c57f60, + 0xbae88a6e, 0x231b7fd7, 0x08bce18d, 0x47ca7205, 0xfb98981b, 0x0622f980, 0x695ffb78, 0x31299b9f, + 0x5da13473, 0xf1b35359, 0x44ac11fb, 0xfec0a560, 0x9b39340f, 0x64112a7d, 0x4eac5175, 0x03f733ee, + 0xbc837289, 0xe628d34e, 0xe0ca4d22, 0x38517019, 0x26cbd68c, 0x95826104, 0x3cf48426, 0x90b93001, + 0x2d542469, 0xa78c1277, 0x791b351b, 0x57bba0b5, 0x790da22c, 0xa52766f9, 0x668b2757, 0xed33f9ae, + 0x0cc8e583, 0x1a535358, 0xa576faac, 0x21b2c057, 0x1e1ccddb, 0x4dbf34e1, 0x7fb2ab87, 0x6efc0edc, + 0x73de84c7, 0x369c20d3, 0x6c2729e4, 0x4e1c2dea, 0xf5a3e3f8, 0xf113863a, 0x96d74554, 0x61a1b40f, + 0x7a2de8d9, 0x0cea3760, 0x0239be6b, 0x5408fef1, 0x0d416fec, 0x813ecfef, 0x3ef7a7c1, 0x295059fa, + 0x7e58387e, 0x38920b5b, 0x2d08ff45, 0xc647ac37, 0x6326b9ef, 0x7d7a589d, 0x6f1143e4, 0x45205da6, + 0xaf3c2b29, 0xcdcf836a, 0x60469dbe, 0x9423fe12, 0xd8234c80, 0x6d604b61, 0x74104d94, 0xfc286e01, + 0x13a19823, 0x8a159956, 0xa15c29fa, 0xc14153a6, 0x2b2b0955, 0x318226a2, 0x1a3bf29c, 0x9122a9da, + 0x0af7c0d9, 0xa5c2d091, 0xf78aa645, 0x6efb34f4, 0xbc1b04c4, 0xb1b4558f, 0x0e58e581, 0xeebac8a2, + 0x9f7a76fc, 0x454e3b43, 0x0f9d4faf, 0x8b197bf7, 0xd52eaeb7, 0x354d0a99, 0x61a4ca85, 0xdfb22edb, + 0x7d6b0eb9, 0x64eb6e1a, 0x1a9dd575, 0xe9448c68, 0xe5d52a1f, 0x71bd215c, 0xa676839e, 0xfee6b023, + 0x847346e8, 0x0dcc128c, 0xb3453e4c, 0x63cbe4f5, 0xc94e58c5, 0x107ddb35, 0x6478106f, 0x40eb1f32, + 0xdeb2ac07, 0x83f516d1, 0x63bc26da, 0x92bb08d1, 0xef0dc666, 0x86024744, 0x0a543dc3, 0x58b91cf8, + 0x14c52b25, 0xd044b9ca, 0x8e431574, 0xf49dbbab, 0x68896699, 0xdd2d80e0, 0xefe7bb8d, 0xe5168d83, + 0x8917b18c, 0x87be2fdd, 0x1070bd19, 0x2787247a, 0x81de5d20, 0x6683417f, 0x5c0d7f6d, 0x4189253b, + 0xeca21d58, 0x952f073b, 0x8c9a43c0, 0x18d219dd, 0x99310448, 0xdc15dc5a, 0xafc1d7c6, 0x3ff3aaa4, + 0x5b26ce9a, 0xd965d129, 0x4915bfcf, 0xdb9474b2, 0x02a98100, 0x8ef34b77, 0x81e3d58a, 0xb53dd24e, + 0xbdd1da03, 0x48a71471, 0x6879afac, 0x1c3cf7da, 0x1a1ccaeb, 0x00851aab, 0x6597b565, 0x07e530c9, + 0xd7760c95, 0x70514aab, 0xea583601, 0xe0df8674, 0xfbd4aa98, 0x1bece003, 0xf6f4bd34, 0x3872926c, + 0x2b75e259, 0x4167b0b1, 0x2bd93dd0, 0x8ca57ab7, 0xc5907619, 0xee9eaf0c, 0x709f08ce, 0x7b51f96a, + 0x78f2e387, 0xdf88f193, 0x8784acde, 0xa3559e86, 0xa72b0e24, 0x48638c0d, 0x083e711b, 0xfb66c379, + 0xcb419293, 0xbbfb2f55, 0x3d9932e6, 0x564682b7, 0x94dbcf97, 0x0a8c47c0, 0x77b0dcd3, 0x4ad5ea0f, + 0x3f785b52, 0x28313c95, 0xdc3acaa5, 0x47ee0e8d, 0xfc65906e, 0xbf87afbb, 0x53d6a5fc, 0xf14b8d0a, + 0x1ebf67a3, 0x96cfb491, 0x4987f084, 0x8f471175, 0x744602e0, 0x61495ce8, 0x1e330089, 0x8f273c8d, + 0xd37e7d54, 0x3be2d33c, 0xe5c190f7, 0xe48cbc6e, 0x271ae025, 0xdadde4bd, 0xe763deaa, 0xb37af056, + 0x933687ce, 0xef798635, 0x6e9cd483, 0x8c3a180c, 0x56d75b1f, 0x36e0d2ce, 0x21551f84, 0x58fe87fa, + 0x868df3aa, 0x70374c0e, 0x543ca18d, 0x7f03729e, 0x685331e6, 0x8e01bb65, 0x32a27052, 0xcce0bdbf, + 0x0fe23453, 0x6076ed32, 0xefa319c8, 0x96878e9f, 0xf8a0fc23, 0xb840fd3f, 0x381deaf0, 0x8bbd318d, + 0xe891d2cb, 0xb6e17eec, 0xcd4e6f83, 0xadf41cac, 0x19efe4e6, 0xc7b923c2, 0x677d145f, 0x95d8a1d8, + 0x5877270f, 0x7f637bb8, 0xf9417ba4, 0x919ffa92, 0x7433d991, 0xf0712641, 0x3730d019, 0xd77b8033, + 0xf161138f, 0xeb1ef5cc, 0xa45976c7, 0x7ceca167, 0xa4a5932f, 0xf73a1f37, 0x883c2d48, 0x1b91d8a7, + 0x389b2023, 0x16a574e4, 0xc9446e23, 0x3346c4f2, 0xbbb41b8a, 0x8e34c7c9, 0x0088a7e2, 0x82e3c89e, + 0xf2175c99, 0xbf4b4882, 0x67b11bae, 0x993c86c3, 0xb5f89e4b, 0x086a74d3, 0x93de39cf, 0x1e4bf741, + 0x89f554e9, 0x26708da1, 0x0faa6b90, 0xe60e6376, 0x0094d4ab, 0x6d967a2b, 0x363f85d5, 0x1db872d1, + 0xe5984a62, 0x59a773d9, 0x5f4cdddd, 0xab368e9b, 0xa3e40391, 0xb6f1d0e7, 0x786e6d26, 0x667f18e5, + 0x74608770, 0xff435039, 0xd163ac88, 0xe7c824c2, 0x8befbf09, 0x84d796c2, 0x25212408, 0xb81cc925, + 0x4d6326dd, 0xcbb91f91, 0x0255d05a, 0x31d423a8, 0x8f83c853, 0xe5d04493, 0x523b5776, 0x7e474d44, + 0x83d3bc64, 0x01f7f043, 0x88f7a271, 0x2955f59b, 0xdafa4be0, 0x435b0da6, 0x2838757b, 0x05f12f05, + 0x30405d32, 0x8453303f, 0x4c9ce132, 0x009d6358, 0xa61ada3a, 0x287def50, 0x6ef3e232, 0xabe5f59a, + 0x816d1cff, 0x29c9fd10, 0x6617e35c, 0x8d79a560, 0x91c2295a, 0x5dd7fbe9, 0xfc2b5f47, 0x072e2c7c, + 0x4568503d, 0x8b95056d, 0x94468e0d, 0x170e68dc, 0xeefd4c86, 0xd7504f0d, 0xffb7bc2c, 0xb1232471, + 0xd13c45b7, 0xb34bfcb7, 0x7ad7acf7, 0x6e655976, 0x1966cad9, 0xebf63251, 0xe7a949e5, 0x26386e7a, + 0x53ae647b, 0x97f88ede, 0x175e51d1, 0x9ddf340a, 0x4a3f75aa, 0x2fbfda6b, 0x53c1e688, 0x8efbb7f4, + 0x29fdb904, 0x68cfd6c5, 0xceb03b82, 0x7a21c99e, 0x875d5fc6, 0xfac80b79, 0x2bd93c00, 0xcbe3be33, + 0x6c2faf32, 0x215b4f3f, 0xda353dc9, 0x71a9e3e7, 0xf16a4194, 0x6bc71cb5, 0xbaa2aaad, 0xa39e6cae, + 0x657d10f8, 0xbb4cb3d8, 0x995f46dd, 0xb4fe652b, 0x4a502869, 0x8532c999, 0x4c585ce7, 0x2be608f8, + 0x8d988404, 0x067b54e1, 0x088a66df, 0x1b13c8a7, 0x30b31c5c, 0x942ed116, 0xf83e669a, 0xd0d068c2, + 0xd9fc4b40, 0xe2aad014, 0x893476f9, 0x04fbb2c0, 0x6fef67fb, 0x23937d41, 0x7e93d939, 0xad519259, + 0xbd979662, 0x51ad83ac, 0xb8199243, 0x61fb64ac, 0xc8516d7e, 0x41a63cae, 0x8f937d96, 0x23b2d873, + 0xa10a58d0, 0xc5fdc101, 0xb1f5003e, 0x5953a8f0, 0xf747dbb2, 0x1c946d08, 0x68f0c758, 0x312402fa, + 0x44c6eefa, 0x693cda92, 0xcf58ac82, 0x8b6fd3c4, 0x5fd50640, 0xd26c88f3, 0xaea9f038, 0x0f3112c4, + 0xbba0966d, 0xa5b287e1, 0xcd3c13ee, 0x54ba1036, 0x55e9b15d, 0x218f2bdf, 0x801a6a41, 0xa91b0adf, + 0xa7753942, 0x90b7218a, 0x4e40d46e, 0x2fe4f6d2, 0x276c0276, 0x351ca985, 0x30c0c4ed, 0x784a2106, + 0x0b85d975, 0x8519a0ff, 0x2f803e44, 0x1b06fa9b, 0x30ef0872, 0xe5762df6, 0xcced6086, 0x817a36ea, + 0xf6049465, 0xc0a1e0cc, 0x8f21fd79, 0xa4192809, 0x754c2fd6, 0x19fd0b75, 0x0c22a4dd, 0x431a9391, + 0xc84d4f7a, 0xec750826, 0xb2a65937, 0xe802765f, 0x32c20ae6, 0x672ce5fe, 0xe678533f, 0xd847b734, + 0xd31e0563, 0xd26e4ef8, 0xbacc868c, 0x21c4b422, 0xfb380ced, 0xab2d1118, 0x3ab6eae9, 0x0f795878, + 0x397145cf, 0x5f27b615, 0x368094b9, 0xaac355ac, 0x366b1f77, 0xd302901a, 0x85af400f, 0xa2b47c93, + 0xcd3d47d1, 0x3d9e7b2f, 0xf49afd6e, 0xe9542cb0, 0x67b93b76, 0x52fc1c41, 0x440c6b7f, 0xf6a1a7db, + 0x9d81c63d, 0x2e9d1ef9, 0x5b4b7542, 0x8251b141, 0xfe744271, 0xf78e19ae, 0xbc8dbc84, 0x72d8d960, + 0x50f87b63, 0xdc8d0c07, 0xf8903a99, 0xe21a72d5, 0x494d25ed, 0xf65e7b21, 0x1c598051, 0x0dce158e, + 0xa8f41648, 0x6d8230de, 0x20e7d799, 0x4d43624c, 0xadecdb4c, 0x33121404, 0x11f3bb9c, 0x19fb97d0, + 0x87afcc55, 0xf589ceb7, 0xcb37b883, 0xf2b52ca6, 0x8be2d820, 0xf63132ec, 0x5fd1aaa1, 0xce28db16, + 0x0f25f38d, 0x28c12141, 0x07c6d015, 0xe469987c, 0x47a094a9, 0x0feea305, 0xfce9a9ee, 0xffb48100, + 0xfeb1636f, 0xe3125f28, 0xb4b4fab1, 0xafc0840d, 0x639a4a2a, 0xf861c53b, 0xaf9adb34, 0x05fcce4d, + 0x92b80ee4, 0x50e44986, 0x8c68c1c2, 0xb728c1a3, 0xfc42c910, 0xe8d722b2, 0xaaa96bd5, 0xff9d23b0, + 0xdeb91eb0, 0x6e567ee2, 0x405b9fc0, 0xf28f95fb, 0xedb053d8, 0x583dfe48, 0xb1d1eec6, 0x4ccea63e, + 0xb1f8c4cf, 0x083d3a6d, 0xa6196852, 0x824526b3, 0x74081996, 0xf3388097, 0x19f7998e, 0xe37d61ed, + 0xc852d7aa, 0xbccb5de6, 0x330f27c7, 0xd03cc468, 0x5cb56ca0, 0xa78ceab7, 0x6c04a79f, 0x37be07fb, + 0x9475a89a, 0xff4c2153, 0x7097e3b7, 0x48bfcc4e, 0xb685fb3e, 0x08997acb, 0x923ed7c7, 0x074207f5, + 0x27d60593, 0xe99583fb, 0xb7cc3454, 0x7b577d20, 0x99471169, 0xcd964b37, 0xe09d3c42, 0x9419f8b5, + 0x3f173eb1, 0x83886c8c, 0x52d6df5d, 0x32563b42, 0x49447699, 0x8c99a1da, 0x16da709b, 0xe2a87112, + 0xf2a8d2c2, 0x7e0798ef, 0xa40925d8, 0xe1c7d99f, 0xa62adb08, 0x22a17995, 0x921aa5a1, 0x52c10b19, + 0x793b0ec5, 0xf66a51f7, 0x0d8df5ce, 0x1359e9d5, 0xe0f5dcbf, 0xdf5d9058, 0x33917b4a, 0x956033e9, + 0x05fdbd2b, 0xda52484c, 0x4a431b94, 0xf700658c, 0xc10d65dd, 0x962750b1, 0x9a26fc7d, 0xfe3c57a2, + 0x93737b82, 0x6dc10994, 0xc82f7bb6, 0xc8ef5239, 0xbc767e18, 0x12514bd9, 0x3a107055, 0x8716178a, + 0xcab3a871, 0x996991e8, 0xcdc5ce34, 0x5274eafd, 0xf553b8ff, 0x6bae590d, 0x25890d79, 0x0e784cf5, + 0xd445a44d, 0x386b9ca8, 0x79bda2b6, 0x02027460, 0x8c7d32f6, 0x5692adb0, 0xf7ecf2bf, 0xfa394aa1, + 0x5bdde1bf, 0x8c1f47ee, 0x455b5617, 0xfdf63483, 0x7ced4d08, 0x68169b8f, 0x617ce03e, 0x7b92754d, + 0x00ad7c0a, 0x779bb198, 0x0f6561ca, 0x2441dcfc, 0x61ff09df, 0xf7144be7, 0x64c41f31, 0x438ec592, + 0x83b23408, 0xd8817341, 0xf338340e, 0xd7500efc, 0xf8fc2fe1, 0x2e4d8a53, 0x7e441b45, 0xaefadad7, + 0x357125ac, 0x3eb8c343, 0x6def3300, 0x92b7865b, 0x4346a7f0, 0x56ebaf35, 0x573389e3, 0xed915e04, + 0xc5a6bb5d, 0xf38719c0, 0xe46ed733, 0x371c2b29, 0xcc6fbf34, 0xa4fb0b4e, 0x807161f4, 0xdb3b3190, + 0xd1f7e07a, 0xbf466adf, 0x20d48d4b, 0x7f046c32, 0xe74f8968, 0xc9edc206, 0x717be4f8, 0x8c624620, + 0x099f5d5c, 0xab6e8dea, 0x9b125bc3, 0x5fb4787b, 0x94af61af, 0x9deb4482, 0x326516c9, 0x45fbaf1f, + 0x903a3e0b, 0xa3035f15, 0xcbeb6508, 0x998fbced, 0x2ec7af6f, 0x0316ee3c, 0xaaa06655, 0x97366213, + 0x791ec8b9, 0x177116e8, 0x11b40092, 0x906ab781, 0xb3daaadf, 0x2fb04711, 0x647fe914, 0xb5e6299b, + 0xd254b0f7, 0xcbbbf286, 0x7f654f78, 0xff45aeb4, 0xf4f10020, 0xcf10f508, 0x8041dc69, 0x3ec12e36, + 0x103cda9b, 0x09474a5b, 0x4c67c0c3, 0xab04cebc, 0x0a391a0f, 0x682b99b9, 0xb6dddcb6, 0x8b8d9709, + 0x0d1e925c, 0xc6007540, 0xe1ac4c9b, 0x821fea8c, 0xfca65c71, 0xbe1b17b9, 0x3f6213ea, 0x9b4a1a39, + 0x11152d39, 0x0d3a556f, 0x7ddca185, 0x875948ce, 0x86dd5b81, 0x95246646, 0xd191ddbe, 0x1bc45546, + 0xe3ee5ceb, 0xc36c1949, 0x7e10e287, 0xc8c7f8e6, 0xb718c7d6, 0x8d615a3c, 0x98b0dbc8, 0xde917837, + 0x168a1ccc, 0x8930d468, 0x35702d62, 0x3fb35fcf, 0x57e97bea, 0x2d70d8da, 0xcc56a70a, 0x548b76d7, + 0x1b15d141, 0xd9edd2df, 0xa85e6e7e, 0x9ac65d0c, 0x6cf37234, 0x6a115357, 0x8c600b62, 0xeff63135, + 0x1166f2e9, 0x692b9214, 0x1bd6a5d6, 0xcde3e7b5, 0x4b42c3d7, 0xf1d7b093, 0xc6408ca6, 0xa91cb5d8, + 0xb234a5de, 0x4fa00c6e, 0xecbd14c2, 0x9a07a852, 0xd99addff, 0xc45b55a4, 0x4a74a793, 0xd7b7ff3f, + 0xba9dae33, 0xc2abc75d, 0x21f46d42, 0xd709c417, 0xbcbf1b0e, 0x343ec3c0, 0x15c80268, 0x1b49eaf7, + 0x757962a8, 0x10d42aed, 0x98d5f3f4, 0x25c42b2c, 0xb804c52c, 0xfba8fc65, 0xbb8f730b, 0xe149d9f2, + 0x5a6aca2e, 0x23c61395, 0x321e22d3, 0xd19d208a, 0xf54937fe, 0x779c37fa, 0xff25ae88, 0x3fbb5c78, + 0xf59b7158, 0x124eb43f, 0x26848f40, 0xce872587, 0xe92c1dce, 0x2daa9f0b, 0x8ada755e, 0x1efda97b, + 0x310d5b91, 0x008fccbf, 0xd18b93f1, 0x978adb28, 0x7a40f13c, 0xa5d10a2b, 0x816d23a9, 0x27a20eda, + 0xb8b612bd, 0x4a2e899f, 0xb4fbfb0f, 0x8a4855a5, 0xb043b240, 0x85182f78, 0x84c4aa83, 0xcbadd306, + 0x52df32e6, 0xa6c57461, 0x5afc71d3, 0xe92a741b, 0x5836442a, 0x632c7f1a, 0x499e527c, 0x1580d854, + 0xad744750, 0x7d1565b1, 0xa1be27ce, 0x78cab7dd, 0x9ea832ba, 0xc4a1ea3a, 0xfc390973, 0xd90a677f, + 0x13a985f1, 0x6565add7, 0x0a77ceb7, 0x57091bb1, 0x7da5c767, 0x7cd85d09, 0x37d79e02, 0x703b47ee, + 0x1bc82c55, 0xb8c72fda, 0x8c104ae1, 0x5441de10, 0x048326fe, 0x4a4b0efb, 0xc4bfff9d, 0xab62774e, + 0x95117d41, 0xc5a2b600, 0x598a51bd, 0x584b8755, 0xf10baf40, 0xb2ee6bdf, 0x867ecd93, 0xb5dd03e1, + 0xfa65e26d, 0x677ea72b, 0x1ed7e1cd, 0x72f3762c, 0x890ff4c6, 0xae643e6e, 0x2f22f48c, 0xaf287bba, + 0x99ae3f04, 0x24007f34, 0x16acbf66, 0xf7ef0b6c, 0x7fb7725c, 0x9fb29a2d, 0x114075ca, 0x6ff9cc1e, + 0x57bbb77a, 0xa254093e, 0x6dcde432, 0x1d8b183a, 0xbb70b49e, 0x1e7b918a, 0xd298619d, 0x49e1da06, + 0x171d36ca, 0xdbae48b6, 0xffb9dca4, 0xa9b3da64, 0x09933cf3, 0x53c96fbf, 0x121878de, 0x793cc720, + 0x8f3e4819, 0xdd4683b5, 0x946219c3, 0x5bdae393, 0xa16bad61, 0xc81a4223, 0xaf32f4f9, 0x7c721785, + 0xaaa45b2c, 0xe784172f, 0x96722c60, 0xe4c090be, 0x191e13ff, 0x7eb98ec1, 0x50c02d1f, 0x6f1d0694, + 0x7a9f535a, 0x22fbb740, 0xa151fcaa, 0x104fcc62, 0x6a1acbfb, 0x378ebfe0, 0x6a953697, 0x828c3f77, + 0x7b05c2c2, 0x3bed493b, 0x851ac7d0, 0xd2c1bd84, 0x8e14ed25, 0x716d6b40, 0x4481622e, 0x52641013, + 0x1ab73be8, 0xa73a9e04, 0x34b383d9, 0x3513af08, 0x7dbd6564, 0xaf7c1a6d, 0xa7419d2d, 0x3f639965, + 0xd9de4feb, 0x6df8dd63, 0xd56a15aa, 0x5ff66942, 0xf19e9477, 0x88e3b8b2, 0xebdfd0eb, 0xcf980d9f, + 0x94603ce4, 0xd36d8d33, 0xe9850c02, 0xc10ec42a, 0xe756054a, 0x1f81ec2b, 0x33331754, 0x64fca9f4, + 0x3106929e, 0xd5cc851c, 0xaddca67b, 0xa73a6a46, 0x09df726b, 0x3b742ca9, 0xed882bff, 0xaa71c0f4, + 0x749b6e53, 0xb0a72bc8, 0x2b619117, 0x9591c6ae, 0xc565a2eb, 0xb5f96230, 0xe6e02f89, 0x9ff0f4c1, + 0xaed69e2b, 0x667b3b96, 0x4bfab329, 0x2e873dd7, 0x94d2d5ca, 0x80bbf917, 0x95f59e2a, 0xc7cead7c, + 0x6a6729bd, 0x5e3ca9bf, 0xfcae3027, 0xc86742f1, 0x014af351, 0xe706aacf, 0xe17abe00, 0xd690a405, + 0xe0226e9f, 0x39e0e919, 0xc4aa2136, 0x83466da1, 0xbf7f9f3e, 0x54243b5f, 0x660a9391, 0xf8dae1e7, + 0x52e99103, 0x0786ad49, 0x6156bae5, 0xb1dc208a, 0xd56314e4, 0x5dcdf393, 0x4a45a361, 0xa682eaa3, + 0xdd041506, 0xc7074049, 0x0fdaee89, 0x2f58aa98, 0x3d2b766a, 0xfcb285ad, 0xe68f136a, 0xc4dea8c6, + 0x3db581e2, 0x35bd49fa, 0x99931a65, 0xb260a21e, 0x9e8ed35b, 0x492492ed, 0x1096e345, 0xb64ba4da, + 0x15909b48, 0x4c618196, 0xae9755da, 0xcc29a20c, 0x1f59fe35, 0xa0701e0e, 0x29af754f, 0xa582fad8, + 0x82110fd6, 0x63d2c773, 0xf3681955, 0xc7cd16e3, 0x0937b01a, 0xad55a99e, 0x8b7b0498, 0xe686f96c, + 0x63c046da, 0x6546394a, 0xffd504a2, 0xe14bc099, 0x1eb47e19, 0x453d5d31, 0x4ff5a67c, 0x7fc9ddb4, + 0xb477ea40, 0x8ddb5254, 0x643df5ba, 0xe92d4bab, 0xb7eb494d, 0x4f6d484c, 0x38679eef, 0x1de5dd12, + 0x73996f4a, 0x64900557, 0x70083068, 0xba35e74e, 0x4ff59185, 0x792e7343, 0xf2f6571f, 0xb7dd604a, + 0x8760012c, 0xd9571858, 0x95c6163d, 0xf9a2323f, 0x6c36c71d, 0x2e820825, 0x663b2934, 0x63f0ddcd, + 0x25f1c84e, 0x4d8e838e, 0x5ccf67f3, 0x79c9e8af, 0xb4046995, 0xd48731be, 0x7aec60f2, 0x1b3fb45a, + 0x83eaa671, 0xcbc8204f, 0xac2e4e92, 0x23e6ea7e, 0x5acf7d10, 0xec66af8f, 0x7090648c, 0x35878d3a, + 0xc96db157, 0x3dfec12e, 0xf9bc8fcb, 0x696a2819, 0x37830a7c, 0x1998994a, 0x6436887d, 0x07325c79, + 0xa9c9f9d5, 0xd8f5c6ce, 0x6ea85a06, 0x275f0eba, 0x6b1257e9, 0xb1f46424, 0xbc01b768, 0xa22496d4, + 0x49d81b29, 0x760b4682, 0x719193f8, 0xf8f5b1f7, 0xd6bad00f, 0xc796ab81, 0x3c9d9120, 0x95134186, + 0x2c9def99, 0xdb857446, 0xa12cbe50, 0xbb9b41cc, 0xe8798b5a, 0xd746dcb9, 0x6a89ae22, 0x0e4f83c9, + 0x77da1e14, 0xa10a7f28, 0x74766728, 0x6496ce29, 0x053c745f, 0x00480724, 0xe346a135, 0x2b4db4ec, + 0x9f7b3644, 0x5b391768, 0xf0721b56, 0xe41d2c37, 0x1570651e, 0x543ed5ca, 0x0dcbac9e, 0x6005d8a6, + 0x6e5df7db, 0xeac0d04b, 0x7bcc64ca, 0x5ce70793, 0xd900854c, 0xd6e5a8d4, 0x4c6b2739, 0x935e43fe, + 0x22669acd, 0x51875b9c, 0x358af077, 0x7e645ef0, 0xa4b4eb98, 0x0ea2b22b, 0x0f040142, 0xabb6d1b2, + 0x2b8a55d4, 0x1dfd5e20, 0x41c0ef25, 0xa3ff9541, 0xb5fb2f78, 0x4fc79d2e, 0x1852f5d5, 0x368bd5a2, + 0x7bc3b2bc, 0x235a2d3a, 0x3a7806dc, 0xc1bcbfbc, 0x6e42be59, 0x07659cb5, 0x779e276d, 0x31e62f08, + 0x4aff2e75, 0xf3e38ef2, 0xdefbbfa0, 0x0e26503a, 0x5f1a41ec, 0x28788898, 0x7e2b5962, 0x353f9073, + 0x3d26e86d, 0x316afc6f, 0x1c2dd595, 0x4e6b963c, 0x2be76535, 0x0ecc1331, 0x6dda2873, 0x663a87d6, + 0xa8415368, 0x598063cf, 0xe20b0af2, 0x3df315a4, 0x1792e944, 0x286af484, 0x0bc0fef6, 0x6d20cbf2, + 0xc1a96266, 0x4aee2234, 0x8630ae5c, 0xe724a113, 0xb3809be1, 0xfb109adf, 0x759778e0, 0xa724d8f8, + 0xeae700e2, 0x4c46c835, 0x411c2f66, 0xb3ec0dfb, 0x6cd6cb84, 0x1652bdd5, 0x666e9fc0, 0x372a9561, + 0x47c2e795, 0xc171ed5d, 0x172ff03a, 0x62c0097f, 0x30e1580d, 0xe119cfb0, 0x6283f56c, 0x05b67dc0, + 0x1c3b7aca, 0xea1d8f45, 0x8ebcf459, 0x81d23c9e, 0x5e73af88, 0x448207a8, 0x25fd98b4, 0x402aea0b, + 0xdbf4161b, 0x9ec9e3c0, 0x717e9b82, 0x190d6cc1, 0x199863a7, 0x8dedf290, 0x4af02043, 0x76c8658b, + 0x1c009bc2, 0x827b81e2, 0xdcb952e7, 0xd4dc7828, 0x57036121, 0x18db65aa, 0x390839ba, 0x1375b2fe, + 0xa9a8ba7c, 0xc48526d1, 0x79ebeabf, 0xcb090a3d, 0x8490145a, 0x77ecd115, 0xcf66fce2, 0xef2bbd10, + 0xbee4854e, 0xd3d5175b, 0x6a9a59b0, 0x77379a7c, 0x306bc61a, 0x72cecbf5, 0x63bf0996, 0x15780ec7, + 0x7cb9436f, 0x9e55e757, 0x3a90f4a4, 0xfcb2ddeb, 0x42cf84c4, 0x4acaed0e, 0x82558dd8, 0x61410d34, + 0x52328ffe, 0x3ed22b6b, 0x52b392e9, 0x83306af8, 0x8c30857c, 0xa47cac93, 0x41effaf1, 0xbc443d86, + 0x50c33cd3, 0xe8a73d4d, 0xc6f436ca, 0x120457ca, 0xca9f3024, 0xed6ba804, 0xf2058134, 0x3c71783e, + 0x4716aa49, 0xe58ed283, 0x797aac26, 0xf4a7c6df, 0xb9244223, 0xde682b7c, 0xce4a26dc, 0xb23f96df, + 0x2b24beb7, 0x811bd6c6, 0xdc456d9b, 0x647f4e7e, 0xda48d262, 0x834f6c3c, 0xadd2d0f9, 0xe102a6dc, + 0x33244ee2, 0xe8482af3, 0x33e4fc1a, 0x19b85f12, 0x86924e58, 0x2e7438e1, 0x5b31d0b0, 0xa29124c5, + 0x6b336f94, 0x693f4b23, 0x20bcc9bc, 0x7c3d5034, 0xded0b2e5, 0x74fba127, 0x13dba6b7, 0x80b2ae14, + 0x1ccac358, 0x06a12b15, 0x464860a3, 0x538b5b02, 0xf93749ab, 0x7c339b8a, 0xc7b7de6c, 0x30e74f95, + 0x004ad35a, 0x180b7e24, 0x42c8bad9, 0xd42cd15d, 0x3c06a34a, 0x665e3c0a, 0x2defe860, 0xb3e7060b, + 0x475b3996, 0x3f0f0a06, 0xa25580f5, 0x8d69e47f, 0x4e9815f7, 0xf29f0fdb, 0x33fb2843, 0xcdc98ea6, + 0xd5c91716, 0x6e2357b1, 0x279ec846, 0x9b8fc349, 0xf0d7ad35, 0xa58effa7, 0xc4ef2171, 0x864a6dae, + 0xdba44c2b, 0xe266927a, 0xf9d4230a, 0x487d94ef, 0xf7974dab, 0xb5e555d7, 0x4a9004b6, 0x04ae1d5d, + 0x9b4057b1, 0x342ab07d, 0x2ba2abf6, 0x4f95e6ff, 0x5687462a, 0x4d171e36, 0xcbd29493, 0xf7c569cd, + 0x35caad91, 0x5032ad84, 0xd8349d96, 0x547ec80c, 0xd4370540, 0x09633757, 0xc929291f, 0x73a2a51e, + 0x793a2b1c, 0x55784e79, 0xb0e7d05b, 0x098eb526, 0xcea78570, 0x21f89ed4, 0x9a046695, 0x8df0ec98, + 0x3f08c84e, 0x4ad3343b, 0x447576b6, 0xfa4b31a6, 0x3e46c7ab, 0xab860cfd, 0x980e82fc, 0xe2d0897b, + 0x71f29308, 0xc53ddb8a, 0x8118c901, 0xc9dba889, 0x9ad6ba79, 0x61a6c433, 0xb9dcfeef, 0x1a26f41a, + 0x27106c5b, 0x4989d397, 0x52379db4, 0x3448aea9, 0x255ecebc, 0x71cceab4, 0x8185382c, 0x0cda58c7, + 0x5911a420, 0xf2b156ce, 0x74eed78d, 0xd564c922, 0xe2d27797, 0xd5e0e44e, 0xce627df5, 0x4e31d867, + 0xddbd86b8, 0x430d7843, 0xa806c2b4, 0x6dbb9df1, 0x695808fd, 0x00c1ed4a, 0x13e4b587, 0x6681a742, + 0xe667f887, 0x424e6d1a, 0x8d7522eb, 0x052f7a91, 0xcad328c4, 0x539c766e, 0x4304aa14, 0xf16a917a, + 0x9b8d9e2f, 0x88ee5b6f, 0x8797a227, 0x7e67a313, 0x393f2836, 0x4286b775, 0xaa14f362, 0xfd200527, + 0xd7d24804, 0x28b59403, 0x1a1ab1d8, 0x043f0750, 0x9266b0c8, 0x37b4b2ac, 0xc1b70897, 0x454ef885, + 0xb2997a82, 0xb5324e5b, 0x6a80905f, 0x99257e81, 0x40644fcf, 0x3e41125a, 0x2bdd52d8, 0xff956331, + 0x00019224, 0xbd6c0297, 0xe88da0c5, 0x0b70c928, 0xfc7b3667, 0x970db786, 0x5aa7eb1e, 0x652d5c46, + 0xdb79d154, 0x148f3447, 0x7f14ff20, 0x846143da, 0x833449b6, 0xc36a16f4, 0x8d200bf6, 0xf229277a, + 0x946f012b, 0xc4f6ab11, 0x987bcba0, 0xf19bc7cc, 0xe5aead5f, 0x395c52b1, 0x8dceea5e, 0xd07cd7ce, + 0xbae6a7c8, 0x83fc867b, 0x25eedea7, 0xa7c91cc4, 0x09e5710a, 0xf68b5d54, 0xfed4a35d, 0x3c5dc132, + 0xbd75b025, 0xccb4ade7, 0x9899a770, 0x99a4b75b, 0xebdf1c88, 0x6e77f46c, 0xc4f180db, 0x980333cc, + 0x3f332370, 0x60b8616e, 0xb9d69085, 0x3b62a7fa, 0xf90a67c6, 0x74154486, 0x49fcaae8, 0x1ff105ee, + 0x280bc201, 0xb16767b8, 0x9e2536e1, 0xecb9112e, 0xe156aa0f, 0x0b041290, 0x8332b25a, 0x42a9aa9d, + 0x4e45f334, 0x9c7a2ff9, 0x6456437e, 0x4d613314, 0xe2db2865, 0xebceea6c, 0xb641c050, 0xfe211ffe, + 0x369b963e, 0x5ce7009a, 0xcfbe8f60, 0x53cb4a5d, 0xc5cb48cb, 0xff7387c5, 0x8e86bc04, 0x75e3705e, + 0xda736ad5, 0xb5d01b54, 0xd564796f, 0x94dc5535, 0xb26248e4, 0x5a11a56c, 0x50a3efc1, 0xd9ead591, + 0x62b2e4a8, 0xc4c442b3, 0xe1c055f5, 0x2252fffa, 0x636d0768, 0x8fa8b085, 0x8f33bf02, 0xc1c7997d, + 0x62f1c2bb, 0xf41774f2, 0xcaae9971, 0x18fdab6c, 0xebbde7be, 0x0d9fd1df, 0xc67cc870, 0xfe5f324b, + 0x5f609262, 0xfa30e155, 0x6577342b, 0xb78b86cf, 0x823f3714, 0x0f4301ed, 0xce6564ab, 0xa3a3f93b, + 0xebfb31fc, 0x32c18e2f, 0xd5eb0b76, 0x0a063304, 0x15e8c6a6, 0x3fae2e94, 0x0fcec716, 0xdf9144e6, + 0x12a4ca2f, 0xafe6ff03, 0xc115fb3b, 0x51e8dac6, 0x46ae8c69, 0xfdb14965, 0x33074e45, 0xdb9fcb35, + 0x07ce9f52, 0xbea70bc7, 0x58aaf0b0, 0xc91afe24, 0xd26019a7, 0x1acfd669, 0xb5e89b22, 0x7f8a4175, + 0x479269fd, 0x00eda155, 0xa2d5274b, 0xdb5cd8f4, 0x19254259, 0x4c3c33ed, 0xc0de79af, 0x8c1095de, + 0xd339534b, 0x1d2f1201, 0x916448e4, 0x3d5b6695, 0xf088a459, 0xd5be1617, 0x5d547a16, 0xf05b2bcb, + 0x0ac130ef, 0x3ba87d67, 0x2d97efc6, 0x3d24b171, 0xac6c269f, 0x1245df85, 0x913c1541, 0x8d7e390a, + 0x8c610f6f, 0xc27e7746, 0xb85ebe7a, 0xbf831dbf, 0x412d51c3, 0xde4fa0ee, 0xf6bcc845, 0x0edfdd68, + 0xbff41279, 0xb5dbf334, 0x186e1fe6, 0x13cafe1e, 0xcbb70f64, 0x2f58b7f9, 0x7c9ed6bd, 0x7b025426, + 0x13a0eedc, 0x8deba5b1, 0x0ffaeaa5, 0x4cdf442e, 0xd8005a3f, 0xc6d42fbc, 0xefb00d3d, 0xe88371ee, + 0x60392577, 0xd62a469c, 0xee03e3f4, 0x846f8ff1, 0x5bca830a, 0xc2cb9d80, 0x322261ab, 0x60d87c8c, + 0x340a7779, 0x45185145, 0x7cd2f532, 0xe716413f, 0xa50ab3c8, 0xa36b3838, 0xe69616c6, 0xec2f55ea, + 0xd6c15b7c, 0x1d2ba307, 0x3d18f66e, 0x27d1983e, 0x8bceaf61, 0xfb728bc6, 0xe1b94689, 0x6fdece13, + 0x3c96d399, 0x0f8821c6, 0x5ae84e76, 0x2ab7298b, 0xa852aa92, 0xb3a66b42, 0x422f54d6, 0x31a05923, + 0x8e21c731, 0xf71fd01a, 0xb33d8125, 0xdc954df9, 0x613cbb53, 0xf8f5c447, 0x7a0cc6c7, 0xdf3f073b, + 0xfd090225, 0xab988dab, 0xf8603e08, 0x0ca5b033, 0x4a99f606, 0x74861f1a, 0xbe445d0b, 0x12716405, + 0xc0026c50, 0xf342a306, 0x6a479bf4, 0xc50f4a0c, 0x3b81150f, 0x53e34803, 0x9d5529b6, 0x8f050582, + 0x0c965afa, 0x659806e8, 0x728b1067, 0xb6b8f2b5, 0x96aa5e20, 0x41554458, 0x0a32f505, 0xc8b08250, + 0x34f81925, 0x50693182, 0xe97fe559, 0x851de635, 0xe3047f8a, 0xe940c362, 0xff58a22b, 0x66ba4347, + 0x6520de07, 0xa452cafc, 0xeec466b1, 0x6ebf1952, 0x9793d74d, 0x10d3df75, 0x388af7ae, 0x066c4b9c, + 0x3562f643, 0xba21d203, 0xc1c680d3, 0x6769408e, 0xcedda5da, 0x5ac7cf04, 0x6c3621b0, 0xd85cc0d7, + 0xe6fa5b57, 0x606b3bbf, 0xeeb426d2, 0xe9de4f29, 0x3cec35eb, 0xbfacab90, 0xa673db5a, 0x90dc1e8e, + 0x9d08a3cd, 0xecc37379, 0xb067071d, 0x57a75eea, 0x64744be3, 0x7d9edad7, 0x03cd9e47, 0x2e47e95a, + 0x160b3a28, 0x826a3936, 0x1a9e5a85, 0x306684aa, 0x2d5b9c34, 0xd3df88e6, 0x6e6282a9, 0x23b66c34, + 0xc8c01e23, 0x3a9345fa, 0xc5d9c5f0, 0xbfdef8d0, 0x4496f83f, 0x98478462, 0xbf614ffb, 0xfb444bbf, + 0xa8f21cde, 0xee7c5979, 0x94e1b409, 0x29403a57, 0xf0784c14, 0x223ef8a3, 0x8d997969, 0x8a5785db, + 0x066bf54a, 0x6e59bee7, 0x146433e1, 0x188a467b, 0x0e6ff06e, 0x9fc9b9ba, 0x4f667b85, 0x0b76b380, + 0x675c346c, 0x31bbefe7, 0x839df792, 0x860a77a0, 0xe44c2d2b, 0x865972c4, 0x42e982cc, 0x5c013c6b, + 0xf5e196e5, 0x9c748d34, 0xf62cf6a9, 0x9ba3a102, 0x3ce4d097, 0x6ce0a21f, 0x2f4775a0, 0xa90e384d, + 0x1f098f4f, 0xc4b35d4d, 0x8bace3f6, 0xeb6ebf73, 0xe7e2415f, 0x21805058, 0x60970624, 0x45dc858f, + 0xe4a9677f, 0xe003fe96, 0x210730c2, 0xe56e3a59, 0x404da47b, 0xa7839ed5, 0xb3e45db4, 0x5d31da03, + 0x5ffca665, 0x54c280f5, 0x809c8940, 0x9ce23e6f, 0x8cef0fc0, 0xc301fc3b, 0x965d2ee3, 0xcda9ef11, + 0xdb255484, 0xbe6efebf, 0xf474d387, 0x043e8dfb, 0xac8f233c, 0x77d19726, 0xba2e13f3, 0xd98e5086, + 0xa651d885, 0x79ca8170, 0x1b65b708, 0x2b2286c7, 0x521f1bdb, 0xc7fbbdc6, 0xc038efc3, 0x7e98639a, + 0xfed51d2c, 0x955f2e9b, 0xebf21921, 0xdb02963d, 0xe4f24603, 0x8e2a2752, 0xeb2c4e5c, 0x782b7e90, + 0x83b8c506, 0x632b9f0e, 0xb17416f5, 0x20498f68, 0x9d6fa49d, 0x9723a5e8, 0x56eac6bf, 0xa0bb5ea5, + 0xac6b10d3, 0x50226a6c, 0xe82d8fe0, 0x6b5bca0d, 0x728bdbc7, 0x45e68ce0, 0x0513261a, 0x5f888448, + 0x52ba7c3c, 0x0b04620c, 0x9bd04f40, 0x6486c47e, 0xbee5cc42, 0xbd237c00, 0xa61276c0, 0xce386992, + 0x7ce7a0cd, 0xf39cacf2, 0x06d25a28, 0xa98f5be4, 0xadec3b0e, 0xcb2b1aa1, 0x05af66e8, 0xe60b5809, + 0xf001386b, 0x3ee48ab8, 0x128ac927, 0xe8a4a265, 0x363610b3, 0xf2003b19, 0xb9425f3d, 0xd6a10270, + 0x3fe66ca2, 0xcf6fbb86, 0xa48510e3, 0x9f656cb2, 0xc2b983c9, 0x88343029, 0xded38252, 0xa40060c5, + 0xdb612a4c, 0x19204826, 0x2da5cd51, 0x61984ee6, 0xb77155e0, 0xc5cc0ab9, 0xd6f37724, 0x7a2d7f6c, + 0xe9784ebe, 0x29fcff39, 0x390bf09c, 0x3097d7e3, 0x9bb0c2ec, 0xbc769021, 0xc7951688, 0xd7de875d, + 0x79ee6719, 0x2ac737a6, 0xdd2c0403, 0x5677f725, 0xdf442b51, 0x42f2b6ca, 0x8d383693, 0xc1ca5763, + 0x28b5486e, 0xc257677a, 0x66778cc0, 0xf505a799, 0xc7fb303c, 0x60ce6fa2, 0xf483553a, 0x48492105, + 0xf3687f43, 0x72e0823e, 0x93512643, 0xf20427db, 0xdbfb6f2b, 0x28d08e46, 0x6419b06f, 0xd9020517, + 0x1d0887a9, 0x8a184320, 0x59f6bb36, 0x3ead79cb, 0x227e6acc, 0x4232d020, 0x083bca82, 0xf465fd80, + 0x0c4e79e2, 0x60962299, 0x402840e8, 0x82b1b98a, 0xc9755d4d, 0x8171be3f, 0x699ae160, 0x341e9dfb, + 0xe10aa442, 0xd8e24c85, 0x5f27162e, 0x96b22f22, 0x569a11a0, 0x12f34285, 0xb4d5b4dd, 0xac9fa9dd, + 0xdd98a9c9, 0xfce80f43, 0xf5d2426c, 0xcf2f8186, 0x52a45306, 0xa2c982e2, 0x1eca92cd, 0x4d9f3ef1, + 0x4d90bf15, 0x32ef3d19, 0x175fcb01, 0x11c6097b, 0xec74afe1, 0xa6ce6ec9, 0x7b91b8fe, 0x7c86f3bb, + 0x1fbe035e, 0x68c06493, 0x845c854d, 0xeeb14a41, 0xda2404c1, 0x6311642c, 0x075a6078, 0x675354a9, + 0x77bdc4be, 0xd840afd4, 0xff403205, 0x7f8db55a, 0xaf9f31c0, 0xcc1d04ca, 0x53bfbae4, 0x9e503644, + 0x2935b802, 0x7d263abe, 0xd400b0d8, 0x2057e37b, 0xaa7c84d7, 0x8fbda654, 0x7a8ce8a2, 0xc86e0677, + 0x4ffe3184, 0xbd4c0271, 0x1191601b, 0x6993b62f, 0x51ef2bbb, 0x81ebd19c, 0x1795ace2, 0x56ec761f, + 0xab0166f6, 0x31bac669, 0x78cb858f, 0x6f107d38, 0x3134cb3b, 0x066f1cd0, 0x1b566ef2, 0x72d62a35, + 0xd6d1cdd5, 0x1423502e, 0x99e85641, 0xe8989ae3, 0xb5233659, 0x23639884, 0x74aad77f, 0xe887712c, + 0xb5957754, 0x40b6fe33, 0x488025e1, 0x5274845e, 0x8df90388, 0x3f13eb77, 0x02177207, 0xdf5fca8e, + 0xcfef7d20, 0xb5bac766, 0x75cba067, 0xbf1a3933, 0x534f3eec, 0x372b8a57, 0x78de5c60, 0x76ebf31b, + 0x1de83ef6, 0x8349a798, 0xff814568, 0x4cb9ec55, 0x2244f0e6, 0x83b49aa0, 0xd390bfbc, 0xc61a9b19, + 0xd52b4673, 0x8953c295, 0x961a5728, 0xbe43839b, 0x615bf023, 0xf9304254, 0x0a803ab4, 0x892a9ef6, + 0xd33286a8, 0x0deba879, 0x9d6608f7, 0x2bcda36d, 0x578dcd42, 0x16d79e9f, 0xc685d386, 0x45abc525, + 0x98b33031, 0x39d8d326, 0xab712671, 0xc6bbebfd, 0xba39e408, 0x4127bb02, 0x89a0bdd9, 0x1cb7e3aa, + 0x84b368a3, 0xc53146ef, 0x4ef3cbba, 0x0037e6e3, 0x6de5fcd2, 0x0fe08743, 0x7c93a2f3, 0x2048114d, + 0x4eafef40, 0xb34d7307, 0x38e9686c, 0xbbec4ac4, 0x37ef3ef3, 0xc36404e1, 0x1ed7c2c1, 0xa04c029d, + 0x4ff06761, 0x7a03ede0, 0x514ac6f1, 0x8439d76a, 0xb9f445f3, 0xd300a654, 0xa447cee2, 0xc472bacb, + 0x71ece979, 0x837d9c89, 0x690e5025, 0x83744182, 0xf377e384, 0xb4b4b598, 0x09d78357, 0x7188ceed, + 0x3ee31393, 0xedc33163, 0x2fe056d5, 0x527807d9, 0xbff162ab, 0xf790cc53, 0x8aa0c610, 0x19efda9d, + 0xbd2ea247, 0x67ca5ff2, 0x781d3d62, 0xac229970, 0x0aac0497, 0x370673a4, 0x891aa3ce, 0x98954c8f, + 0xc186d162, 0x1f448baf, 0x1ee826fb, 0x6839c74e, 0x205fc2c1, 0xf361da2b, 0x6e9b2c99, 0x477b1438, + 0xf3c1d44e, 0xd9e414c1, 0x5816ed68, 0xbf9396b9, 0xd34c8ab0, 0x4e369a66, 0x7b3fd83b, 0x901c8c25, + 0x20d32ebd, 0x21154718, 0x84f63461, 0x3fdfcf4e, 0x19102098, 0x89e7d085, 0xca335f15, 0x8b244b08, + 0xf4467182, 0x71b649a7, 0x71330bfa, 0x0204669f, 0x9ee4c424, 0xa15ef884, 0x7c731831, 0x1a76d36a, + 0x236d032b, 0x417f5418, 0xd3f35639, 0xf024fd0f, 0xa02e5eb5, 0xe6702247, 0x4c7f2b77, 0x6a2092f6, + 0x71cdb156, 0x65811f69, 0xbeb347da, 0x9480b572, 0x75e21612, 0xdc4c1f09, 0x1166d7e4, 0xcaf4c255, + 0x7c453336, 0x2fc234c9, 0xbd807595, 0x417377e2, 0xbc927e17, 0x6fdf0863, 0xcec932b3, 0x451f6ae1, + 0x4d405ce7, 0x1e75854d, 0x17cab2b9, 0x68a32fb1, 0xe747fe9b, 0x00eaeae2, 0x0fe64eb0, 0x4075a695, + 0xf4e7e7f4, 0xc52d3042, 0x34b49e37, 0x50897630, 0x1382d6c2, 0x2d96a576, 0xc2e612e1, 0x74b79852, + 0x6c8b3693, 0x744f70f4, 0x5b1b6dda, 0x3501122e, 0x5e574c5a, 0x72afb1c6, 0x98f98b62, 0x58632314, + 0xf67418a7, 0x73a867f6, 0x81ffb88d, 0xe2552c9a, 0x98c7d491, 0xb4e2c200, 0x1ec1a626, 0xddaafcd6, + 0x570d64f4, 0xd9eca021, 0xe6e010eb, 0x1f7f3ddf, 0xc8a17fe1, 0x73c9eeed, 0x001c8e2d, 0x566592ba, + 0x4c8a83c9, 0x3540c625, 0xdc9ccfa3, 0xc0b094f8, 0xddba59c7, 0xcb2ec69d, 0x0c7e9ba1, 0x27c71e4e, + 0x0657b955, 0xfa9b8c56, 0xc1996871, 0xef185a35, 0x5e1efdc1, 0x40c39d14, 0x5db23799, 0xbb936482, + 0x0fc8b18b, 0x9b3aa5e8, 0x35d00887, 0x0a9bda7d, 0x273546f2, 0x28e56770, 0x64b52e28, 0xc5e1d14e, + 0x74c22c4d, 0xc724dd2e, 0x9c06111c, 0xafdf9713, 0x435c5052, 0xa74fe5cf, 0x036a0a66, 0x810003cf, + 0xfb8355b6, 0x94ab4a1c, 0x36e0820f, 0x03e7ddf1, 0xca0da89d, 0xa3b2bd8a, 0xce8fdfec, 0xaccb6caf, + 0xfbe17103, 0x8efc398f, 0xcc3289e8, 0xc8492db9, 0xb1b5033a, 0xb0723bac, 0x61b7e8d8, 0x92a394c8, + 0xe2abb177, 0x2cdef5cf, 0xf0220c73, 0x69562ce1, 0x4661f851, 0x5e2695bd, 0x213c2ab8, 0x0d0037f0, + 0x119da268, 0xbfd015cb, 0x988b3b1c, 0xacdcab19, 0x5c5de043, 0x6b83852e, 0xe5551f79, 0x1a136716, + 0x71f3be10, 0x97e8ef4c, 0x57389490, 0xec68e31a, 0x9dc609e3, 0xb51d76f8, 0x6716dd6e, 0xb14c38bb, + 0xad73376b, 0x62918585, 0xd9fa7074, 0x0dc46d25, 0xd570b7a6, 0x59031406, 0x27d3004d, 0xc49aa5ac, + 0x61912860, 0xc63caf00, 0xa576e45f, 0x5fcb82dd, 0x41238f6a, 0x6331bc2e, 0xda2bfd2a, 0x6d34aee9, + 0xd03d2170, 0x07b25753, 0x7f60c6dc, 0xc71a476d, 0x117d956e, 0x920e8845, 0x171e9778, 0x1c15f032, + 0x30c90b4a, 0x3ab4ce94, 0x6137ade4, 0x2c0c6c0c, 0x9f84d337, 0x45b309fe, 0x0dc0558c, 0x05d24c3b, + 0xa691044c, 0xab42ecb0, 0xf0645647, 0x50f98fbb, 0xb7689b52, 0x73c678cd, 0x3fad109e, 0xe6213c53, + 0x06c9f8b5, 0x6ef172ec, 0x6ed38c79, 0xef109cc5, 0xafc8b2b0, 0x91cb91a9, 0x3081dcbb, 0x7f9dd83a, + 0xc3165fcf, 0xd392e42b, 0x8cb2aae4, 0x4cad2d73, 0x24214986, 0xa997af75, 0x094e2a69, 0x5a5927a7, + 0xbb312346, 0xa329880b, 0x700edc5e, 0xebbe1062, 0x1ce76c65, 0xd199d603, 0x68c8bd51, 0xdb3a977d, + 0x29f009e7, 0x43b158ee, 0xd3226b85, 0x27a944b6, 0xa2fa54f6, 0xe3ff6de3, 0x26c4a217, 0x7f60726b, + 0x35cfcd1f, 0x36b37539, 0xda6b62a1, 0x05fd6e8a, 0x19f8394e, 0x7ef10b09, 0x9df47478, 0xe690f7f0, + 0x0f06551b, 0xd6d72893, 0xd1ac9e75, 0x0e79e5c2, 0xa21cfa49, 0xc9ba8154, 0x748b82e1, 0x1a97a02c, + 0xb13e0b26, 0x43b0d578, 0x1d3e73cc, 0x50107ccc, 0x6ca871f1, 0xbe7bcb9d, 0xf26ccf89, 0x4a610cd3, + 0x2d191897, 0x7699ab41, 0xa8859f46, 0x9a95531a, 0x4ec4ce35, 0xee29505b, 0x2cd9b21b, 0xf4b453b9, + 0x1a67a98e, 0x74f32841, 0x5d21c385, 0xe5afe2ca, 0xbf41da01, 0x92a843b8, 0x4ed8fdca, 0xc9339c26, + 0xb1d2dc38, 0xa239a11b, 0x53873290, 0x863b9d34, 0x21e76783, 0xfe505404, 0x43d2e32e, 0x64e47b2f, + 0xeab6bb9d, 0x6a2b4f30, 0x4f7c6772, 0xb8c8e23c, 0x1c9b48e8, 0x040ded47, 0xcb94a82b, 0x8761086e, + 0x443bb77a, 0xb5bd7f9c, 0x2a0bfc87, 0x882881e6, 0x52ce6664, 0x66745a6d, 0x9dbb96c7, 0xccf3cd74, + 0x9408a4fc, 0xdfa23251, 0x9955c435, 0xc27d75e5, 0x00b72ed7, 0x3528862c, 0x234f0ce2, 0xc1b8c552, + 0xf97d4322, 0x8e4fc40d, 0x5d010cac, 0xc68ec35b, 0x5052b246, 0xde94f2ba, 0x461fa1f4, 0xea3a3275, + 0x9993662c, 0xd00e431c, 0xe1889a5c, 0x4a59f15b, 0x8155e767, 0x48f9f8ec, 0xc1125fc8, 0x29153259, + 0xe7131370, 0x15c48089, 0x060fb3ad, 0xa4d0ebc1, 0x4da4ccef, 0x26ba5346, 0x4f3722a5, 0x7cb7d396, + 0x6d8c96b7, 0x45f4c401, 0xffd585f4, 0x1ff3fed7, 0x9c658421, 0xcde0cf76, 0x64b4bf42, 0x25a7f1fa, + 0xc0bfe226, 0x405a9f12, 0xdc047e12, 0x9297ea80, 0x362678f5, 0xb18f96e7, 0x48515c21, 0x99e1f741, + 0xc9136f9a, 0x481dcfee, 0xe0b2fe40, 0xb5bfccf5, 0xef295c39, 0x70497f60, 0xb5c1a8f5, 0x404a43c0, + 0x152a295b, 0x504b2536, 0x23d903d4, 0xb33e6a96, 0x80e1a42f, 0xaa811cc9, 0xc5ade9fe, 0x9af93620, + 0x16c73ab4, 0xa759923b, 0xd126530a, 0x8b4c5ca1, 0x0c8984fe, 0x2015119f, 0x03b1bc28, 0x75631ec5, + 0x0d7ce2ba, 0x96eedd8e, 0xac15abe2, 0xceaf48e1, 0xa3e8992d, 0x3ccf46a4, 0x28fa08f1, 0x18375f64, + 0x34e06cf1, 0x056af317, 0x2b05ba81, 0x0da0da95, 0xb2a69525, 0xabbbf2f6, 0x157930ae, 0x77a5927d, + 0x5b6d59a2, 0x1743a0a9, 0x458ed828, 0xbc6e3680, 0x0357436c, 0x87066d45, 0x0beafab3, 0x7814bc51, + 0x316f1121, 0x13e4e750, 0xb21be49e, 0x5b4c551d, 0x4ab1b5c3, 0x0eeab3fe, 0x1a6e7b68, 0xe01e1e58, + 0x06fa9fa9, 0x1c08297e, 0x2f86343e, 0xef622ebd, 0xd747663a, 0x08c44608, 0xc2c3f697, 0x3d0edd4f, + 0x36b06208, 0x513aff01, 0x6ba2f143, 0x39121fb1, 0xfc633bdd, 0x52f13f0d, 0xd237c91e, 0x9ba66f22, + 0x771b9ce5, 0x0ba4184e, 0x8e1337d3, 0x9fa704c5, 0xf1c44b9a, 0x1d72799e, 0xd7121c47, 0x4b4125bb, + 0x6da619ad, 0xa78eeb49, 0x2917234a, 0xe6eb9c54, 0x0838bb61, 0xa311af66, 0xe3a50353, 0xb2bf629b, + 0x9fdd39ca, 0x398332d3, 0x01988a12, 0xc2e9cd55, 0xd270a4f3, 0x2f5dd0eb, 0x57cc745c, 0x14b348f8, + 0x677cf075, 0xe09f49b6, 0x95f03774, 0xf6dbc30d, 0x09a0f90b, 0x8a27de08, 0x98655ea1, 0x3b9a6cfd, + 0x3efa91cf, 0x50755b2c, 0xd2bacfb5, 0x57c44b66, 0xd1e381f1, 0x7f3c6afc, 0x13f0baa5, 0x75ded132, + 0x09651959, 0xca5a148c, 0x7899c14f, 0x08585656, 0x8a01ef00, 0x8b28a2c7, 0x3cfd451d, 0xdb3dcb35, + 0xc2a3ec53, 0xb85bda4b, 0xee703d7c, 0x23cf464b, 0x3796e7d8, 0xefd4511b, 0xb8060d81, 0x167e12cf, + 0x3390bd6c, 0xfd048d4a, 0x9d9ac7f3, 0x13d14b0c, 0xc994e8ef, 0x5fe9097e, 0x613bda71, 0x1adcbf64, + 0x04b1f79e, 0x3d8f31b1, 0x99303007, 0x6c39a69f, 0x918e48c2, 0xfbb2480e, 0xdf77ca77, 0x45081163, + 0x6acde0ef, 0x6e1fec11, 0xd770374a, 0x67dedfe1, 0xcd578828, 0x62df7cb3, 0x12f22d39, 0x18710543, + 0x8f6ff1fa, 0x79f36056, 0x6c0897c3, 0x9f2fd1d4, 0x28a86c1e, 0x253fe993, 0xd94f8aef, 0x8de3971b, + 0x96b4b5da, 0xb9bfa74e, 0x363782f1, 0x3db40944, 0xc1c8e57b, 0x4da1afc6, 0xfb299f71, 0xecdd2763, + 0x57ed976f, 0x7fecdebd, 0x1ff752c1, 0x2463b894, 0xf9c7b78b, 0xf1307692, 0xbf41c0c8, 0xd78657a0, + 0x54bb0626, 0x3f3673f6, 0xb1971cb2, 0x5d77b79e, 0x6832af48, 0x9c8ac293, 0x686268ed, 0x80714550, + 0xaea39673, 0xce0e0173, 0xdde958d1, 0xba594911, 0xb75c1a3a, 0xd52ab5f6, 0xa4444c50, 0xffb1bcaa, + 0x05e6db46, 0x788be20f, 0x37c42459, 0xa3a96bc3, 0x4220cf97, 0x2064ec15, 0x2eb1c7e5, 0x80981c07, + 0x5dec7864, 0x39a60470, 0x703280b1, 0xa5570c6b, 0xc3253f29, 0x9961992e, 0xc0a6d423, 0x2443a4e9, + 0x9922fbe1, 0x7cdfbea8, 0xf824a1e3, 0x2eda4f22, 0x8d361402, 0xeb9bea12, 0x450cfbff, 0xcf49a147, + 0x457cd015, 0x98ad5a4b, 0x9c511221, 0x6a19385a, 0xd7167fdd, 0xf3cc96e0, 0x09c75ce5, 0x531d9bb4, + 0xbce50a32, 0xd3279a07, 0xab7176c2, 0x73019175, 0xee7830b0, 0x163bada1, 0x03df3625, 0x0c25b546, + 0xd59bf988, 0xa73f2bfd, 0x1f707a98, 0xa9c0fff1, 0x4d32684a, 0xef75af3d, 0x970b2969, 0x6aaee281, + 0xecc0f719, 0xde6be418, 0xd5893261, 0x233ce1c0, 0x76f38863, 0xe9fd8aa1, 0x135419e5, 0x7a55058a, + 0xb90bf8b1, 0xc10676c0, 0xd28121de, 0x235d10b8, 0xfa4fe6b3, 0xac52f035, 0x446e0c88, 0xd991c2a5, + 0x73fead45, 0xb1966388, 0x4c196914, 0x5add223d, 0x06f858d9, 0x09134e5c, 0x009eb9c2, 0x9864d412, + 0x6c7e6d71, 0xde4d5977, 0x9394af22, 0x84c90aed, 0xf345ffb6, 0x2a6b6ad2, 0x925cc895, 0x157fc526, + 0xc3711b64, 0xccddf78f, 0x280ba04b, 0x662a11fb, 0x8302fa84, 0x83c08a2d, 0x6ffa487e, 0xecb1cf42, + 0x2765528a, 0xfe3d6a20, 0xde2ea601, 0x698a7e1e, 0x2faabb98, 0x489ff549, 0xe8c2d3b0, 0xae16d928, + 0xb036c6e1, 0xf7b4b275, 0x9140060d, 0xdada8883, 0xe37c0bcc, 0x91c45664, 0x1feb7848, 0x01c4493c, + 0xa8970e26, 0x93be3c6e, 0x4a51ea9b, 0x4cba9a63, 0xc5551935, 0x59feed71, 0xd7317b13, 0x35008306, + 0x21bf3a84, 0x7903ae99, 0x867f1358, 0x57bbd00d, 0x9ea298b4, 0xe1a1d1a4, 0x1e69691b, 0x0b24d426, + 0x0c3fc643, 0xd4f348a5, 0x3c33d945, 0xc375d158, 0x80ea0e89, 0xe3d1a1ff, 0x1c98fa7f, 0x686235b1, + 0x91c603ed, 0xe143fbd7, 0x000a5405, 0xc7df2edc, 0x1586d235, 0xb21e0aa3, 0x45c54d33, 0xa25ac29a, + 0xb5612a25, 0xd7050891, 0xc3ed348f, 0xcb54fc32, 0x1d37d68e, 0x36298e4b, 0x86417fcb, 0xee679602, + 0x1133c3a2, 0x9016ae02, 0xe802cf9d, 0x8335d782, 0xd89ebeb2, 0xc7802c2f, 0x27472ad7, 0x7ff561d0, + 0xdfd87990, 0xe06a892d, 0x44464957, 0xb732ef15, 0x86018c87, 0xc3389f14, 0xc402bfa0, 0x03225dfe, + 0x455635e4, 0x5848fef5, 0xedb16e34, 0xb1d2c30a, 0xa4cf484a, 0xbdd36c3f, 0x5c4a2fc1, 0x8802ae50, + 0x2aa4eead, 0xeef7f91d, 0xd3ef00ad, 0x89e3dedc, 0x11783dd2, 0x4592ed48, 0x24200d93, 0x6db5c6e7, + 0xcb36a05c, 0xf7cf163f, 0x4704cf21, 0x2bba29ae, 0x8cdf9b15, 0xe901ecde, 0x6d192a63, 0x3034e6ca, + 0xef792ac5, 0x36d4b865, 0x01ee6c92, 0x4d450f63, 0x7375e4be, 0x178d62af, 0xb56bd1f7, 0x926bf0cc, + 0x1ea8490f, 0x7c614dab, 0xb917b77e, 0xe0c08380, 0xaa960e10, 0x7784fa9a, 0x5fcb7181, 0x8b8518c5, + 0x03f16db7, 0x79c98321, 0x103bf431, 0x0c0476b5, 0x4bf811c3, 0x183d98ef, 0xd6b693de, 0x2e0d8090, + 0xa865eb5d, 0xd8a84140, 0x637d97fd, 0xcab66281, 0x3713944b, 0xe38e244d, 0x9cac561c, 0xbc40558f, + 0x27852253, 0x7eea7b1e, 0xbce593c9, 0x687c73d9, 0x0f970d6c, 0x0a553d11, 0x0d6b512c, 0x1585eef6, + 0x218b7a36, 0x25e3108c, 0xc333a834, 0x6ac05b02, 0x11e686ad, 0x2a75fd54, 0x9af72489, 0xdd86c014, + 0x5443a95c, 0x6773c83d, 0xaed6cb6c, 0x453ef47a, 0x52fa4f37, 0xbda1d264, 0x42134b71, 0x0b45549f, + 0xf23eb402, 0xb863749d, 0x9581454c, 0x12f94382, 0xa2874f08, 0xcaf8ca30, 0xaf152ecd, 0xf2117dc1, + 0x632aef83, 0x8c19ed81, 0x3bfb3d0d, 0xc8f935bf, 0x50573842, 0xac862556, 0x27533ca3, 0x8aa9abb2, + 0xbb5c8de5, 0x5549aba9, 0x851d1b76, 0x4d0584a7, 0x7a15e770, 0x4705d6cd, 0xc3b2cde2, 0x96e48ccd, + 0x1198b9f0, 0x95e343c4, 0x02f585ce, 0x4da4ac53, 0xb27637bc, 0xefe2ba23, 0x6a33a0ac, 0xe7e61dba, + 0x330b5f3c, 0xed668da2, 0x3e681fe9, 0x685ace25, 0xc20ca99d, 0xb954000a, 0xf36e9942, 0xdbaca15d, + 0xe980a7ba, 0x04ce584b, 0x29b0c92d, 0x217b5497, 0x145ce110, 0xd3abf8d8, 0xfe9b7d2d, 0xa9fc27c7, + 0x2ff70d59, 0x2dee86dd, 0x81f9e17b, 0xa981fefa, 0x5c64d27b, 0x153da759, 0x05ae3c25, 0xb0c9db3b, + 0x1e12abc5, 0x1d8de83d, 0xa5ab4a3a, 0x5d6a1564, 0xa3490583, 0x57db173c, 0x0ab492a2, 0x84f8015d, + 0x098c3c05, 0xcb467ede, 0xf18a766f, 0x2bc6c45e, 0xf06ef1b5, 0x0a5e785d, 0xe6aaaece, 0x466535d4, + 0xdda34fe9, 0x6a62e054, 0xf7a3eb6c, 0x135d318a, 0x3fd11e64, 0xcb062b8f, 0x1840f613, 0xf6447532, + 0xbfe06c4e, 0xd34db8e3, 0x24b89444, 0x4e7057f6, 0x0dd0c80f, 0x2a1e229f, 0x27d9f347, 0x8ea958d4, + 0x6afcf944, 0xfb3a3312, 0x4b943507, 0xfae34552, 0x11c292e6, 0x210cb505, 0x0b039267, 0x424bf3ca, + 0x27ae54f4, 0xc34dd7a8, 0xd0d2007f, 0xd169dc86, 0x283fcfd7, 0x301ae690, 0xe92ae866, 0x5c1cfa32, + 0x3a644fcd, 0x03b6e192, 0x86de36c4, 0xfaf931ad, 0x6dd38f83, 0x95497090, 0xc6e9f5b9, 0x9c714ce2, + 0x3fa4b375, 0x21014ea8, 0xcca61381, 0xb7798b1d, 0x477fb034, 0xeffd9a8f, 0xac1e6c97, 0x860b50ba, + 0xfb1bf7b8, 0x120f3c02, 0xcdfdd34e, 0xb4f7bb3a, 0x3ea68ee3, 0x9c2c8741, 0xb964ae1d, 0xce5d2dbe, + 0x17f5d0fa, 0xde3b98d6, 0x9e44a8ac, 0x3e34756e, 0x66a5ebf1, 0xe00ad40b, 0x6d5b8cc7, 0x775aa366, + 0x6c4e5fc5, 0x48a8c65b, 0x07214ef8, 0x17d45cf9, 0x1dd8740a, 0xb5da8080, 0x488f8e81, 0xd3b0c5fa, + 0xef26c10a, 0xd8520675, 0xeb9ef8fe, 0x25d38fae, 0xdba43824, 0xfa657645, 0xd0623098, 0xa7d3a1be, + 0x1f226288, 0xf3c4f2c1, 0x6b6caf92, 0x2e7d8d88, 0xbcda9eef, 0xbf5091cc, 0x92f0bb8c, 0x83941bfb, + 0x288f449f, 0x987273b9, 0xd2208571, 0xc1faad5a, 0xb2c31f81, 0xc0bfbb1b, 0xaa0737f0, 0xf79386f5, + 0x5bc2fc36, 0x70e804f0, 0x9caa57e2, 0xd142f19e, 0xac414ba2, 0xfeec9dce, 0x8f266e33, 0xaae1f7c9, + 0x94f6492c, 0x6b40e414, 0x8db5d69f, 0xa53ec23c, 0xb09a5a1a, 0xac40604e, 0x7809163d, 0x70b32268, + 0x5796db20, 0xdf0bef00, 0x8069221a, 0x71c2480f, 0x0b0f7a45, 0x2121e93f, 0x6d015aec, 0xba350b42, + 0x0aeb5655, 0x489bc518, 0x0f2161be, 0xde4fdf3b, 0x2a32cd64, 0xa58ec3df, 0xb8530239, 0xaa3db955, + 0xc78610c5, 0x3bab7a1b, 0x2a60623c, 0x6978b337, 0xfc8cb6e4, 0xc0175d7f, 0x46309a36, 0x2bcf00ab, + 0x773be5e9, 0x27986469, 0xfa0c21fc, 0x25f0624d, 0x08b67571, 0x641e4cb2, 0xc8dbb489, 0xd43539cc, + 0x9bd906e0, 0x8e21e7a7, 0x6eddb79a, 0x96d65975, 0xa9908f2e, 0x890e7657, 0xb36febc9, 0x539a97f6, + 0x8711521a, 0x88a163bc, 0xc3651bbc, 0xd7479654, 0x95924e57, 0x583643be, 0x5a92f642, 0xbdab9024, + 0x39dc76a0, 0x632ba97d, 0xa39b8a52, 0x03c5d48f, 0xebab3eeb, 0x4fd10907, 0x67bd5282, 0xf78e7237, + 0x377b200a, 0x7b48584a, 0x5e833069, 0xd403cd4c, 0x7e6b3b2b, 0x230ba05d, 0x041858f1, 0x2ead157a, + 0x12353f9a, 0x94dc2e36, 0xc47411c9, 0xd43066af, 0xcdeb74e1, 0x2d15ad4b, 0xf741366f, 0x6eb8ee8e, + 0xfd6c43fd, 0xf78e4a0a, 0x62b76010, 0x02583bc0, 0xa4aaacab, 0x4974d444, 0x1fb06c5e, 0x361da644, + 0x6dea3bfe, 0x5c2b159f, 0x9f66dc72, 0xd2e1803b, 0xcac34ec9, 0x09d96860, 0x56ab2791, 0xafc921b9, + 0x8955b0d1, 0x32a3d1fa, 0x238527f3, 0x72bcad2f, 0x2c4d5ad1, 0x0ab96743, 0x0a046531, 0xa71dd426, + 0x468e3878, 0x64b5858a, 0x509e6a59, 0xa2caa552, 0xe470bfd8, 0x9937308e, 0x748925b0, 0x97f2fbd9, + 0xe3b76b81, 0xb2b219ec, 0x89d67425, 0x8ff56254, 0x5a608bbc, 0x07a8265a, 0xfc0eb7ee, 0x83c6025b, + 0x0788e9f5, 0x3c948974, 0x91c1264f, 0x431d47d1, 0xcc4a01a1, 0x98aab242, 0x68a2a7f3, 0xc612389c, + 0x02c9b88c, 0x40270205, 0x409bde0c, 0x5f0b8e8b, 0x66234b77, 0x79ae0a9e, 0xcfcfd8a7, 0xe91e5760, + 0x1811b82b, 0x78419bf7, 0x27a07080, 0x822ff48f, 0x6eea7d06, 0x63597964, 0x2d0f73a1, 0x943c84c5, + 0xcfb0bdd6, 0xf15aea8d, 0x2c8f623c, 0xa08b36d6, 0xee99ec38, 0x9d9283ac, 0x1a563b2d, 0xf0b78108, + 0x2321e947, 0xbd5d3eef, 0x72fff920, 0x821a0dda, 0xb969e49e, 0x1fb0e9d5, 0x5e1950f1, 0x4abc8dd0, + 0x42df629a, 0xd5398683, 0x10314894, 0x75e557cf, 0x88253634, 0x2cdbe8dc, 0x93e3db95, 0x20cd2d73, + 0x156b095e, 0x46960ac5, 0xde614a8d, 0x4dc27964, 0x836983b2, 0x7f768abe, 0xb6b0896a, 0x84777e84, + 0xcf54ba4d, 0x4e76be02, 0x23f26d11, 0xf8b82afb, 0x214fb0cd, 0xd4e0b903, 0x89d5cf1e, 0x0c8b5abe, + 0xa00a2165, 0xc0bb450a, 0x1c79ce50, 0x91ba96c1, 0x2f08210a, 0x4e3c524d, 0x4c250aea, 0x1d820d6a, + 0xd69b968f, 0x11b7eb14, 0x81fadf41, 0x699dd350, 0x9d89c94f, 0xf664c3f6, 0xc3c2301f, 0x482ae106, + 0xc97a82af, 0xa39cfa23, 0x5888510f, 0x29b2f04b, 0xb70edbde, 0x756f8a70, 0x3556b66f, 0x3e026c3c, + 0x854c2822, 0x8d19da93, 0x82773e23, 0x1ddeedea, 0x7464edf1, 0x8303fe32, 0x34753c69, 0x045949cd, + 0x20be5cf2, 0xe899c924, 0x993928f7, 0x3f1c30ca, 0xaac78014, 0xe3ea16e3, 0xeb7d2446, 0xcfa2d535, + 0x0e072ecf, 0xf0d52554, 0x275dd2bb, 0x40846341, 0x5023143d, 0x95193139, 0xae615f42, 0x53ab2f7f, + 0xb7be6d91, 0x0d15be57, 0xba76e53b, 0x0bc128ec, 0x982d882e, 0xb65d01b8, 0x3712e464, 0xe0ba938e, + 0x5827787b, 0x6554d1fa, 0x04f881bb, 0xe53309a0, 0x8f8f8fe5, 0x080c5f25, 0x36eb488f, 0xfa57896f, + 0xed596048, 0xa992a2f0, 0xc0d1af6d, 0xb42bd82f, 0xcde9c286, 0x1c41ee30, 0x1e6e90b8, 0x4e5abf35, + 0xe06a2526, 0xc5570e6f, 0x4b1a95b2, 0xa9373474, 0xb1fdd324, 0x74493a27, 0x77b0d408, 0x5ea370ba, + 0x2aee5cf8, 0x436f0d98, 0xfc5be067, 0x40514073, 0xca250a75, 0x4de2f759, 0x29558a43, 0x0ae1fa6b, + 0x946b504d, 0xef1f7645, 0x5555366e, 0x271f356f, 0x9f0641ac, 0xad44b1d2, 0xc29424ec, 0x4b1b48e5, + 0x234f4981, 0xac8cd350, 0xae94c6a9, 0xadd8e564, 0x2401b45a, 0xe24d0b0f, 0xcd146831, 0xc1e1020c, + 0x6c1276c5, 0xc71a41fc, 0xbcf02ccb, 0xc0513a5c, 0xeb59796c, 0x0148eefa, 0x60a1cd2f, 0x5fea747b, + 0xc46d6c2d, 0x967254c1, 0x4883a44b, 0xa2cae592, 0xb55949dd, 0xc66a4d26, 0x3b7650f4, 0xac996e80, + 0xdc6114c2, 0x39785167, 0xffe23b7e, 0x00d9aac2, 0x55c05f07, 0xf555fcfc, 0x44ce5768, 0x464da094, + 0xbfcefa25, 0xeddc2617, 0x8d1e362d, 0xf553d575, 0x819bca27, 0xed68efd6, 0x8f83d6d4, 0x8caa89be, + 0x8f21215f, 0xac058113, 0x191cf0fa, 0x3a341f36, 0xb38fb484, 0x0cf7d0da, 0xec9fef4e, 0xa6bbe165, + 0x4a2cf059, 0xee4c60e7, 0x855a4284, 0x1ec8f567, 0xa12efbfe, 0x829c59e3, 0x503f50d1, 0x0ed470f6, + 0x2226bc28, 0xb4a1c392, 0xd62f205b, 0x77d53314, 0x650b62fb, 0xe19168f0, 0x3e2aafa7, 0x92e46f38, + 0x825aa298, 0xd265f9dc, 0x39016375, 0xe658ec26, 0x63634791, 0x79e9564b, 0x9cf0cb42, 0xf79247a3, + 0x2e0e0f79, 0xfd461618, 0x976e9712, 0x829679be, 0x520e504b, 0xa1e6e732, 0xa4658069, 0x30098307, + 0x2a247300, 0x1a383497, 0xdb4bb44d, 0x3189982b, 0x59ad68d7, 0x4877c8c8, 0x0f5653c4, 0xdecdb67a, + 0x44febca3, 0x6629b744, 0xc1ae39b1, 0x4f053cf7, 0x2df07e5d, 0xfb6fd565, 0x96e9aad2, 0x8b963b91, + 0x1b928cec, 0xca58b885, 0x653fe96a, 0x4034fca8, 0xbbf121c4, 0x6622cb4d, 0x442a51e8, 0x7d9712ee, + 0x3728f8ea, 0x28eef300, 0xdc2fedcf, 0x3e1018bb, 0x9463adbc, 0x187e2aa0, 0xf268e907, 0x5a1a2638, + 0x680e45df, 0xde742bb7, 0x7685ead5, 0x35bdcaf8, 0xf51f4989, 0x1306c089, 0xa001cb50, 0x8afb837c, + 0xc32d8fea, 0x602caa73, 0xbf816bd9, 0x8ae964aa, 0x6b8c8324, 0xddee5646, 0xc325c26a, 0x59486e96, + 0x3010839c, 0x33619ded, 0x77613d96, 0x04461e16, 0xac07b0b9, 0x25f37d57, 0x25e01a20, 0x51e0fdc2, + 0x9f680324, 0x90b78a50, 0xb16ef873, 0xf6273c06, 0x83bc81a7, 0x5d289f93, 0xf069de19, 0x55e04f1d, + 0x25ab5f31, 0x50b852f6, 0x136597b1, 0xe6cc1476, 0xbb1335a0, 0xf727ff7a, 0xb482ae35, 0xa646706f, + 0xb89eff85, 0x73a89c82, 0x3c51c05c, 0x41e91a86, 0xf5a5655d, 0x0cd2ddca, 0x6f70548a, 0x45ff257e, + 0xfc3123e5, 0xd05784ca, 0x4a9c521b, 0xd85468c2, 0x150d47cf, 0x27c535bc, 0xa1c2de24, 0x4414db6c, + 0x8ec5d1fe, 0x9d21680a, 0xb4cd138d, 0xcd4e2591, 0x5d95103e, 0x1791f25c, 0xf0fdac02, 0x10d219ba, + 0xd92d732a, 0xdb909aaa, 0xab2cc4e2, 0x42e42cda, 0x16dffcd7, 0x8c284ca9, 0xe585effe, 0x74741caf, + 0x229ccbf7, 0x0041e68c, 0xb4b4544e, 0x07a85517, 0xed6496c7, 0x57f037c3, 0xa8a80696, 0x8e85138a, + 0x4f1426ad, 0x88019c19, 0xcc2fe2bc, 0x5c93d98f, 0x800ed305, 0x3ff32109, 0xa1363509, 0x32c883b3, + 0xeefc566b, 0x4feba202, 0x189db32b, 0x305463fa, 0xac88d4c3, 0xce5373d0, 0x9d7e2ace, 0x7c391193, + 0x54ebbcf8, 0x0ec03677, 0xd677cdd9, 0x1e666d70, 0x52b6e473, 0x8b657702, 0x5e6eb3d0, 0xfe3bb314, + 0xe340a4df, 0x32399379, 0xc161a647, 0x779c46ca, 0x00dfdfef, 0xf3ecf7e3, 0x63c68be1, 0x88a2b32a, + 0x9e21d531, 0xdc7f89a6, 0xcc4cd6bb, 0x2076e962, 0xd4cf8e57, 0xcfa1d0cf, 0x62a0586a, 0xb7de1280, + 0x068c2ae4, 0xf09f6f67, 0x7378df8a, 0x88fd0df4, 0x81de4993, 0x8f0d3548, 0xa7d62d88, 0xd966cc83, + 0xd54ed257, 0x70f7f073, 0x304dcb95, 0x5b6d6682, 0x7d9eb3ba, 0x81913b07, 0xb2f22caf, 0x22a8f14e, + 0x160e2238, 0x4f15a2e6, 0x748cd890, 0x8794b5c0, 0xabf814f4, 0x4a720611, 0x669498b2, 0xa5fda564, + 0x58814d2d, 0x5479b197, 0xfa34e319, 0x8ac8a834, 0x7efa60fa, 0x2fda7b0e, 0xffbca221, 0x6286ce62, + 0xb404772b, 0x52332ea9, 0x0fb0d2ef, 0xbcc05f49, 0x66924b0a, 0x4ab3581c, 0xf1ef4f87, 0x1637b765, + 0x07df30f2, 0xe03097ea, 0x5e7659ee, 0xcb530bf0, 0xaec4a51a, 0x95d530b0, 0x70a93637, 0xba747727, + 0xb3f69e35, 0x410eccd1, 0xc132cff3, 0x91d79e42, 0x37779744, 0x407fc3f5, 0xc2f53c1d, 0xf6f6cd1e, + 0x9029afde, 0x396219f8, 0xcf302e09, 0x4a8a8a58, 0x1c5d4bf7, 0x9f9cd7a5, 0x5ab505ea, 0x517a6683, + 0xf5908784, 0x920afce7, 0x2e10be52, 0xafd480ff, 0x93f86f01, 0xc795a4b0, 0xc6f7ca8d, 0x8883e24d, + 0x74d9b862, 0xcd5f778e, 0xcac0d00b, 0xd2340bb1, 0xc0b0820b, 0x2cd75639, 0x35ce54d9, 0x054ae5ac, + 0x142d35bf, 0x63f8228f, 0xf2062db2, 0x2042f057, 0x06a0ed8a, 0x23dc7c24, 0xfac6d0b9, 0xe44104d9, + 0x41d2586e, 0x4f37e7f7, 0xd8ed0b31, 0x397f86e7, 0x5514fc94, 0x9d7d0edf, 0x3e4d9b5a, 0xb9bde7d4, + 0xb346b2ec, 0x50c3bdb1, 0xa56bcfe6, 0xdbd01b77, 0xe36d5328, 0x09dcf486, 0x13bb621b, 0xab387d54, + 0x717b23a8, 0x3fd71b49, 0xe04965b0, 0xd63979d1, 0x6267acc5, 0xd44e68d5, 0xe41b7a42, 0xaa9de617, + 0x611603e7, 0x2edf01b9, 0xf329cb3f, 0x85bf5661, 0x5d1ca246, 0xa1f69997, 0x0e3f297d, 0xfc3f9ae1, + 0xf1e20c17, 0x49bc381a, 0x14a4544f, 0x1f8e4451, 0x9e6acdc2, 0xbcf59a4c, 0x42409f66, 0x1ca6319d, + 0x382727d4, 0x85f615c7, 0x823700b5, 0xabb6e078, 0x08b775b5, 0x9cc19258, 0x8fd53d9a, 0x58b74299, + 0x090558be, 0x5df89441, 0xd53de454, 0x33f534b8, 0x4cebd823, 0x8c5e3558, 0xf3c9e5e3, 0x3ca3f588, + 0xaa0dacb7, 0xfaa8897d, 0x2551ae4f, 0x78c0f9a9, 0x92542c57, 0x238f5af0, 0xd72c92cf, 0x61375742, + 0x9feeee4e, 0x85ba12b0, 0x6e0ab71b, 0xa51ff83d, 0x55b53fa1, 0x2b4636c9, 0x5d6940d3, 0xbf4f1cfd, + 0xedad81a8, 0x1bbcc527, 0x64b80dc6, 0x80f4192d, 0xee681a95, 0x04d4848c, 0x69a7b4e4, 0x8455fb46, + 0xc9759431, 0x5a98cbb2, 0x8f61483c, 0x6fe10e16, 0x01f3fb43, 0x43c1fb9a, 0xecfe0bd0, 0xd215652c, + 0xc1d86031, 0xcf8173e5, 0xb53c6f36, 0x6c4c3833, 0xf63e38b2, 0x2467caac, 0x75ee127c, 0x92f0f422, + 0xcc890639, 0xd1cb5123, 0x4e50d088, 0xdf2ced56, 0xd9b44f62, 0x939f5abf, 0x490cfd01, 0x4761000d, + 0xa28376fd, 0x4e0f1627, 0x17c35756, 0x543cd0be, 0x97ed7a5e, 0x9c532cea, 0x762600ff, 0x2b16c886, + 0x6cdd673c, 0x2678e1d1, 0xc7951f15, 0x922eb068, 0x6f7dbb4c, 0x84236931, 0x275a7b56, 0xb5554a26, + 0x6c3770d8, 0xceb727cb, 0x99e5db02, 0x567e0992, 0xe7e1e29d, 0x7647f6d0, 0x4e38bff9, 0x41fd1e72, + 0xa881b5dd, 0x084e1d83, 0x03cbf924, 0x1c5700d4, 0x7896f14a, 0xc37f499d, 0xd4c91042, 0xbbb3135f, + 0xd71808a8, 0x950998a1, 0x1b767ab6, 0xebf93384, 0x947c3357, 0x245b685e, 0x375bc63f, 0xba01e62d, + 0xb78e4377, 0x2cda2fd8, 0xbbc2d03c, 0x5d79c4a9, 0x89d58187, 0xd637e261, 0x3b0eb242, 0x0ab81415, + 0x183c350f, 0x88b07966, 0x6d0b8f4d, 0xc5e5f9f5, 0x4e290d08, 0x9626e981, 0xe6ee6717, 0x2b669106, + 0x0d8fbd30, 0xd7609963, 0xe9aa1d6f, 0x0d0a90fc, 0xa3a068f7, 0x5f90a640, 0x1eb6390b, 0xa694e4e1, + 0x54dd386e, 0x5448398a, 0x39ba64e0, 0x4a6e362a, 0xe4f9aae1, 0x5c2f2b9d, 0x6d0d3044, 0xc19d74d6, + 0x769a8450, 0x29dd076e, 0x93a40b1e, 0x8c5c7c3e, 0x77841f8d, 0x552375ec, 0x825f0d71, 0x70c73c93, + 0x9d257b9d, 0xbf094445, 0xc4d5652c, 0x3f3a20a6, 0x48154145, 0x0c3fce4c, 0x072aaf6e, 0x96a06a0a, + 0xaaf0bda8, 0xbf896311, 0xbca382fc, 0xa9d2694a, 0xff620a2a, 0xea45773b, 0xd57c7b7f, 0x0d311133, + 0xd1e8723a, 0x87e6a4f0, 0x52f49494, 0xc3c95bbc, 0x210a38e1, 0x1a9da838, 0x76b05cda, 0xe2d03a23, + 0x757ebb32, 0x32fa5882, 0xfb379aa4, 0x8bf20fe4, 0xe91ddf7d, 0xd8287c99, 0x22b7be83, 0x569dc9d0, + 0xf85e0b4b, 0xdb2a58f1, 0x3b5b5618, 0xadccfab7, 0x59742308, 0x8e88aa22, 0x39ae7442, 0x44b7f886, + 0x6619dcd3, 0xa70c5b52, 0x5edec244, 0x87eb07ef, 0x11b9579b, 0x8ee405e0, 0xe34dcced, 0xb6161797, + 0xea8b6132, 0x89adc674, 0xcd843aa3, 0x6ae264e2, 0x6c7c8bbb, 0xbbaafc33, 0xa8951810, 0xdbbc5df3, + 0x25d95154, 0x1fa626a1, 0xecbb92d7, 0x775b7bef, 0xba277c10, 0xa556363a, 0xf43b9dd8, 0xcd2806e2, + 0xa62c78bd, 0xff82cf4d, 0x6d522f29, 0x09a57ca5, 0xda76963d, 0xc843d749, 0x46fdd365, 0xc1cd50f8, + 0x3484e298, 0x360d24fb, 0xfdfd2e54, 0x72860e40, 0xe588bada, 0x4c52a8b8, 0xef2207c5, 0xe338d51d, + 0xfd9b983d, 0xaf108402, 0xc006c5b3, 0x5f5fb3fe, 0x128140e9, 0x6c6dfff7, 0x381ddc5b, 0xe5b41b43, + 0x84fd40f2, 0x10765b29, 0xbc31f066, 0x57f449c9, 0x1e452020, 0x6f1c69a0, 0xeba4171b, 0x26312218, + 0xc9bb356d, 0x4d05ec02, 0xef5f037c, 0xe3704ae5, 0x8250ee28, 0xa14701e8, 0x99393f5b, 0xfd56041f, + 0xba15477c, 0x195d9804, 0x56ee7cb7, 0x8fb503c3, 0xb95b11ae, 0xaab9abd9, 0x4672e5d6, 0xa5fecdb3, + 0x8b2711df, 0x8c1db68c, 0xb33e1d8a, 0x356e4457, 0xd16bafc1, 0xc6bfd3d7, 0x55016ac9, 0x2c7be238, + 0xadb51d47, 0xec6053d0, 0x42c09021, 0xd92381cc, 0xef7b5ebc, 0xd01a7c42, 0x4ec48707, 0xdafa0fd6, + 0x15171231, 0xc377b77b, 0xc7025bd1, 0x89926a1e, 0x6d8509f7, 0xa6cf1401, 0x9a0c6d52, 0x767d3071, + 0xf08479ab, 0x2fe0ca83, 0x6959615b, 0x8926d13d, 0x34c6056e, 0x16cda6fb, 0x3f1a532f, 0xcbd508a2, + 0x131cbfd7, 0xc869794e, 0x4abc04c6, 0x7067caaa, 0xaffaafbd, 0xda5f28ea, 0xe5fe0a6a, 0xb460e540, + 0x9d882928, 0x9e671593, 0xe0eca9be, 0x385676c4, 0x71235359, 0x69baaf2b, 0x8afe76ac, 0x75c103f7, + 0x6e4dab5a, 0xda6ab868, 0x4db6a1a1, 0x905b7b84, 0xfb3d8ca8, 0xa75b42b7, 0x4ac75ee5, 0x3798e6b0, + 0x22417237, 0x00f565f9, 0x79b13b37, 0x3006bc23, 0x9eb2f852, 0x4f7b2b5b, 0xecb1b9ce, 0xddb36faa, + 0xe86dd302, 0x272d852b, 0xf8844571, 0xef9ac417, 0x083cec3b, 0x32c07645, 0x73222bc1, 0xc2da399f, + 0xb9205e68, 0x32713c45, 0x303820f3, 0x93c6c10e, 0xac980bb6, 0x8294c5b0, 0xa4bd857a, 0xfee32200, + 0xa0106f0f, 0x474b86d9, 0xe2bc96eb, 0xeb0cc516, 0x10e334e8, 0x0232c900, 0x5a516d1e, 0x1f170586, + 0x68dc5f11, 0x6e67f65b, 0x063b5df4, 0x20187b00, 0x4f860420, 0x6087f73d, 0x1b7c5723, 0x27a76c10, + 0xc53f3c6f, 0x42458ecf, 0xe6fc752d, 0x13592c68, 0x3fa5a9dc, 0x59c20c18, 0x443b0f80, 0x1e759232, + 0x3016095d, 0xb4f4d08a, 0x81f2226a, 0xa0f183e8, 0xa1ab80e0, 0x66977bd6, 0xc8509132, 0x622f6531, + 0x6dce3ae4, 0x5e9888c5, 0x30e01006, 0x8c6a7d0d, 0xec70e00f, 0xfdc55253, 0x1a0e0dc1, 0xcd101a08, + 0x0148a4f2, 0x61cac2ab, 0x1cc37b61, 0x7ba64f2c, 0x402fb992, 0x107ad458, 0x3f5ba0db, 0x9ff02bc7, + 0xb12fddef, 0x9dca984c, 0x05fbaad0, 0xa638f052, 0x5d77e9fe, 0xd607ba77, 0x6a47fb1a, 0xea244f14, + 0x4404f824, 0xe26f4c3b, 0x66a8f29e, 0xebf48f19, 0x2584422b, 0xd6c38251, 0xc1ee7972, 0x90b89de2, + 0x8d607333, 0x3c12a963, 0x5e52dc4c, 0xb01cd461, 0x6aa03de6, 0x347f6388, 0x0ef05892, 0x09e61138, + 0xb2c0c10c, 0x1fff0ebe, 0xc4256d57, 0x79008111, 0xda07cb8b, 0x4c7ec3dc, 0x2a8f6f9d, 0x9192be82, + 0xb716fb07, 0xa4aecd08, 0x0ab0edea, 0x1117ae04, 0x036221ca, 0xf8b3e027, 0x1ef2a8d1, 0x7498a8ae, + 0xeee40083, 0xb8fba2a7, 0x1520d6df, 0xab876f12, 0x8bb7b49e, 0x977c821a, 0x4b32a60a, 0xd8a184fb, + 0x6be8c22e, 0xf45e284f, 0x37707ae9, 0x1b6d6188, 0x2048ca26, 0xfeb5ef1c, 0x9b4241a2, 0x59e63b4e, + 0xa211c21e, 0xd8dcfa79, 0x4d1b597e, 0xb6ca4cc7, 0x9af2e790, 0x653a3a55, 0x0f5d1929, 0xa194a493, + 0x449a0ffc, 0xd9f68079, 0x90da43c0, 0x84a304e8, 0xc5b19e09, 0x7903eb98, 0xa7e7319b, 0xfb215030, + 0x86d2413d, 0xcc53104e, 0x8083e472, 0xf42f71b2, 0x66002cc8, 0xef81c87a, 0xa3438d38, 0x5cc1e241, + 0xc3f36288, 0x32eceb57, 0x643b070a, 0xb7e00cfe, 0x781d7f3a, 0x4f6da572, 0xfd6ecbb9, 0xc0cbb221, + 0x506dd99e, 0xd0ef5c7a, 0x6c9a9f50, 0x15f37e4f, 0xb58fdddf, 0xaacc7794, 0x183dfca9, 0xa5b73a9e, + 0xf4e70fa9, 0x836c495b, 0x78a3257d, 0xb7f43e6c, 0x8a023265, 0x970f7a0c, 0x9976d0a6, 0x20345f3e, + 0xba889509, 0xcaf43d39, 0x03ab561e, 0x2f88001c, 0xd1eaba3b, 0xf7a6c17b, 0x9789d141, 0x0c40f9a3, + 0xe77e5269, 0x47e863ca, 0xab01cae4, 0x6ba8c5e1, 0x4d90a4ac, 0xc2fb9a3d, 0x71e96e66, 0x7d6bca41, + 0xccf21bba, 0x71a4afd0, 0xacda99d4, 0xf5739c63, 0xd8c9682b, 0x7525f7d1, 0x2f220bc6, 0xeb7c9403, + 0xb42281aa, 0x9d39b944, 0x65112ac5, 0x63616388, 0x6de9e9c2, 0xe7bf58e9, 0x138503a0, 0xc4aaa5c5, + 0x236ac864, 0xc121e146, 0x63c3a143, 0x31f13877, 0xcb616c99, 0x099e2077, 0x74e41bbb, 0x1caeb321, + 0x07f3768d, 0xff440c9e, 0xf0155bea, 0x390caa7a, 0x8be58455, 0x841e8a5f, 0x02a979ef, 0xd780dce4, + 0x746bf14c, 0x70226255, 0x98a8a1a5, 0x16a7d2e8, 0x3dd844b2, 0x18c4e3ce, 0x4d28a50b, 0x5608f51f, + 0xbcb0f321, 0xd127cc34, 0x04c348dd, 0xe1f31f18, 0x0493ba4a, 0x875e58bc, 0x874a7a87, 0x7b806a63, + 0x3af385bf, 0x7a76f79e, 0xc57a8723, 0x6d74bdf3, 0x88c881ea, 0x347a61fb, 0x3f47a031, 0xf4773642, + 0x4f8457de, 0x6256a25e, 0x92957e12, 0xc3602529, 0xcc5676db, 0xd58ed9ac, 0x7051f5ba, 0x5a48b9ba, + 0x0b62bc15, 0x3fd9ccfd, 0x8f3501f5, 0xccd2c4b8, 0xd9a829b5, 0x91854e18, 0x0de1003b, 0x89c6dbe7, + 0xc08f96a3, 0xf30c016e, 0xd565ed5f, 0xbe4ff514, 0x804c8e69, 0x3d1a7be1, 0x949659ba, 0xcf9081a6, + 0xaee291ae, 0x1ee075de, 0x530d2f83, 0x37018544, 0x8c6be8f8, 0x50a0a914, 0x10afbe1f, 0xf2595ffc, + 0x9ae66d12, 0xd1f93dae, 0x34edc49b, 0x17333f73, 0x6d419855, 0x6f03533b, 0x17c6f6b7, 0x48fce270, + 0xd057bf79, 0xe7c8c398, 0x4fd11115, 0x133218e0, 0xca1efd52, 0xcf65015c, 0x89b614b8, 0xceb4ae77, + 0x59cd4c4b, 0xd7079594, 0x6013c84e, 0x5117e3ee, 0x476baf22, 0xf927e0fb, 0x9c6b5157, 0x97415271, + 0xced709b5, 0xcc417d56, 0x3a9b6191, 0x5c0f1838, 0x4838a1bf, 0xd0287d48, 0xa786cf15, 0x84944a13, + 0x18f0486e, 0xbccad452, 0xedc7e171, 0x817c3afc, 0xa6fa2968, 0xfed34a3c, 0x48dc2e79, 0xc75d904e, + 0x601a7497, 0x654d4c4f, 0x843eae78, 0xf46d53bd, 0x27e1497e, 0x4b159b8d, 0xdd942038, 0x72a3a221, + 0x23772071, 0xb27747e0, 0x18f4bf5f, 0x2cc281a9, 0xaad31104, 0xa40785af, 0x152db700, 0x38114aca, + 0x2c529e77, 0x07a34d71, 0xd5c203d2, 0x55eba09c, 0xf851b446, 0x92562f2d, 0x033dafb0, 0x8cfad79d, + 0x87851420, 0xe7e2bb74, 0x3372617a, 0xd1fe3b6e, 0x7b894172, 0xb3d35292, 0xcb33bf2a, 0xe901a06c, + 0x72926420, 0x16f2b575, 0xc05e86f7, 0x8b27f1ec, 0x806887de, 0xe0e24b06, 0x2cf2dd2b, 0x1f1666b4, + 0xb001cfe8, 0x5c35e96d, 0xbf7cd5ae, 0xf8a592e9, 0x5061f61d, 0x7a765fc4, 0x96c12f30, 0xa8fb3477, + 0xb6511148, 0x5f7c343d, 0xf5a4889d, 0xe52e2b56, 0x35a07a28, 0x08dfa5b3, 0x496e8daf, 0x142263f9, + 0x840f1de7, 0xb16e1fde, 0x9c57ce66, 0xaee4876d, 0xa6f6190c, 0x0754ae5c, 0x89b32a48, 0x90a279e8, + 0x5d75bdf7, 0x3b4fc6b7, 0x327f9b6f, 0x9501042f, 0x28e1c98e, 0x69e3df9f, 0xf7985b67, 0x06fc25d6, + 0xc1324eef, 0x2eb36214, 0x9a341fe8, 0xe7b7e6aa, 0x2042d79a, 0x46eae33b, 0xae9f00ba, 0x731f5e9b, + 0x810a54c6, 0x51cb9c42, 0x41d866ef, 0xd50e1320, 0x9ddd0414, 0xbe133552, 0x5cdbc224, 0x697f0d5c, + 0xb66ca636, 0xd0475959, 0x7120895c, 0x8f8b8f96, 0x69667ada, 0x08827e35, 0x49f9eeff, 0x84d079dc, + 0x7162c317, 0x5cacd269, 0xa448a05c, 0x34251846, 0x8038369f, 0x8118a10d, 0xbce7aab2, 0xc921bb99, + 0x47e3d929, 0xc80adb2a, 0x10c441b9, 0xc5882681, 0xad97569c, 0xb1ccc1ef, 0x7ccfb0e2, 0x87d6254c, + 0x5feb3d09, 0x012026a8, 0x18d6b96a, 0x1c0010ad, 0x9e015f59, 0xb54b030d, 0x027d4590, 0x291ab972, + 0xa8b6d29d, 0x44e31e1c, 0x5e610b8a, 0x16f6fc80, 0xbe2fd3df, 0x26f2e3e6, 0xaea824c7, 0xb3b559d6, + 0xc8291181, 0x1721f5af, 0x59dc3f23, 0x0f0bcb75, 0x2e7264be, 0x2d819181, 0x3fea833c, 0x130dc7d2, + 0x1d705b65, 0xdad80f49, 0x0d4df027, 0xdc41612e, 0x45ef3396, 0xae7f719b, 0xf602b57e, 0x00fa7b23, + 0x153c294d, 0x7fa459bb, 0x87f5b5a0, 0x1fe841ea, 0x5c77575b, 0xebf95ed8, 0x6656e433, 0x2416afd1, + 0xd6ed0e7e, 0xef8ec9a8, 0x5ae046b3, 0x19ed3593, 0x859f0426, 0x8a451d87, 0x6969b427, 0xbd5a2240, + 0xd2ebe917, 0x6209eec2, 0x627d77ac, 0xcb19c144, 0x4d4b4db8, 0xde31884b, 0xe41e2183, 0x7806c5ff, + 0x54aa4528, 0xc1a3528a, 0x8aae4758, 0xbe81b98e, 0x0560b2a2, 0x9ba24000, 0x792a25da, 0xe46e8854, + 0x4737e69e, 0x570adb23, 0x05101ceb, 0xe29df530, 0x64b138f8, 0x09297df8, 0x692ddc30, 0x691a7967, + 0xa1d8503f, 0x57c59090, 0xf9c05a7e, 0xd7e50e73, 0xa472d4d8, 0x302b5b31, 0xcef29cc8, 0xe6322734, + 0x875c038e, 0xb981543a, 0x1e4f67d3, 0xd9794c66, 0x4dbddbe0, 0x2579fa55, 0x429dccdf, 0x24b04217, + 0x69daa9fd, 0xe4b6bc33, 0xd780e6ee, 0xad3ee7e8, 0x8f7c624e, 0xe68f41d7, 0x0c480748, 0x556760cd, + 0x1ce2665f, 0xc3f4d32c, 0x1fdd10c4, 0xefc91120, 0x329d29fb, 0xfc730d2f, 0xc8dccf6c, 0x31b15adb, + 0x1d220a7b, 0x15815389, 0xcec5a9c2, 0x01337c3f, 0xbfd54044, 0x65379017, 0x569f463e, 0x4a208b64, + 0x27acb728, 0xed9ecf7e, 0x67249371, 0x800d34bc, 0x2206025c, 0x7e482ff5, 0xa3f735f0, 0x917c1274, + 0xaca3bf4c, 0x18dec92f, 0x87fb9ead, 0xf894db95, 0x5bcd2980, 0xcd5bf2af, 0x162f2075, 0x3df2a7b7, + 0x99348469, 0x33b9e19e, 0xe00cdd03, 0x4cb0deac, 0x0de18670, 0x4e52b705, 0xe6e609d7, 0x1059b7c6, + 0x051758d5, 0x56d9f007, 0xe23ccbb9, 0x6a7bcada, 0x57e7c6fc, 0x464684d0, 0x81071f21, 0x429f1e3e, + 0x4c129914, 0x9891e6be, 0x40432ff0, 0x6da98cb9, 0xf494a02d, 0x0f4b60a6, 0xcfbc9098, 0x053a9d1b, + 0x96285868, 0xccf660b2, 0x896a6458, 0xcbb304cb, 0xc87462cb, 0x15287de9, 0x4f621880, 0x7a909ce4, + 0x2f57eb91, 0x08568180, 0x67a795c3, 0x5014f691, 0x8d8b51fe, 0x91edc018, 0xd8d68216, 0x3004c2db, + 0x95e377bb, 0xa9713a54, 0x1de80c3d, 0xd7569f0f, 0xc5316be4, 0x4f7404c5, 0x4e7641ca, 0x77059b5f, + 0x271486fb, 0x49e9ceab, 0x27e1b1c2, 0xfe448b05, 0x966c88cc, 0xfeab3ca8, 0x80a2c02e, 0x3729ddf5, + 0xf55f045f, 0x0409d6fa, 0x67688101, 0x510a517b, 0x34d951b8, 0xbb660286, 0x4240c942, 0x2145c206, + 0xe4cfae76, 0x636f1767, 0x02e5a599, 0x09b73c62, 0x4a3e3a6a, 0x0a775859, 0xccaea830, 0x80ac5c72, + 0xbfceed81, 0x8a8793e3, 0x60a3ba97, 0x6870c2dd, 0x39a8bb26, 0x4428cea1, 0x67b82b3a, 0xe9e70fc4, + 0xce2bd396, 0xd919632a, 0x6b4e7c15, 0xf9f4b2f6, 0xcaf18da1, 0x5a0aba48, 0x758b8283, 0x8d8630eb, + 0x70c848f1, 0x36135336, 0x24c82d74, 0x66e6be94, 0xcdffc41a, 0xb988aa2a, 0x5feca680, 0xfc961d41, + 0x3cf92637, 0x98eb922f, 0x2642c8e1, 0x1ab34281, 0xceeb201c, 0x4d78c940, 0x46e680b0, 0xa9d25934, + 0x2fcf815d, 0x64a55659, 0x1e267969, 0x0a3aed3b, 0xe24a7b3e, 0x2b636395, 0xc05d978e, 0x87109f26, + 0x0f80ad0a, 0xb0276d84, 0xff459773, 0x1b4eeafd, 0x6eeaf585, 0x23cf7b45, 0x91488ed8, 0x170062c4, + 0x0270be4d, 0xb93bbda6, 0x115e68a2, 0x2ac81198, 0x51607919, 0x766e87a7, 0xb9d43461, 0x4d533cc0, + 0x6b6d23c3, 0xa7962afe, 0x293f8d88, 0x6a9111ef, 0xe845a384, 0x5372fa3b, 0x3385f633, 0x1f914d6b, + 0x58389105, 0xfccb6405, 0x3f37e766, 0x7306666b, 0x98c6d99e, 0x5cc9a7e2, 0x28a1562d, 0x427c1cdf, + 0x7fafb135, 0x7b95f8b2, 0x5fe3b064, 0x1a138805, 0x3c417e69, 0x04b2ea0d, 0xb33e5504, 0x17dcbb69, + 0xceec86ff, 0xb1f1f363, 0x4a83280a, 0x277640d1, 0x756a2b31, 0xf18a3607, 0xc2347154, 0xfcdda141, + 0xe2147ddf, 0xf50fbcdf, 0x4b5f5ec6, 0x96ee18c0, 0xd40eb283, 0x85622f6b, 0xb8d73fe5, 0x6cb2405d, + 0x29c8e4b1, 0x51abb66b, 0x1a07fc9f, 0xaa24017d, 0x7fa5b221, 0xf632db5e, 0xee2ef868, 0x67a15d80, + 0x8fde7384, 0x5d632043, 0x9d5efa0a, 0xae0acc26, 0x79063b27, 0x3009fea3, 0xa2b4cbe2, 0xde25b2e2, + 0xe6e9c597, 0x7d1c4122, 0xce5be9fd, 0x28bf3962, 0x8fe0a41e, 0xa6b53a5e, 0x7653608e, 0xfa4c5904, + 0x3c151b83, 0xde41c9d2, 0x8486d366, 0x9940142a, 0x81b225a2, 0x20612a14, 0xbe5660a1, 0x439ece7a, + 0x6f54e01c, 0x53a7d67c, 0x484da644, 0x06997d4a, 0x582c531f, 0xebaa77e3, 0xb559732f, 0xf2af66fe, + 0x28f40477, 0x3198c678, 0x5ad19726, 0x599ea8a0, 0x9be9b272, 0x3c0f8723, 0x0d13cc2b, 0x802b8358, + 0x829d2a87, 0xc09092e3, 0x0a248e01, 0x77dd51da, 0x8c1d6dee, 0x7ebae9a0, 0xa9e25e64, 0xb2e93be6, + 0x793dcf9d, 0x651e9ccf, 0x12ed7d4a, 0x7b0802d1, 0xcabb5ea3, 0xf73d50b0, 0x0f76e87d, 0xcb574e57, + 0x9a165d71, 0xed6f95e1, 0xd0d2e0af, 0x6070aea8, 0x4c631b99, 0x2a39c31c, 0xe875228c, 0x69c02000, + 0x29ab1636, 0x81971f01, 0xbddccb31, 0x9b3a6db7, 0xf88b3428, 0xbb422fed, 0x122a8abf, 0x449d37c5, + 0x7d6bf63d, 0x3e41e6bf, 0x9b5c9b32, 0xc99a86a4, 0x9db8300a, 0x39d1a9fc, 0x0125f6be, 0x503dbeda, + 0xa48a9b5e, 0xec1f05d8, 0x522ae418, 0x7d923834, 0xb1f787e7, 0xf2ba70e9, 0x4e40efa8, 0xb482da2c, + 0xcce74cce, 0xa46c5be0, 0x7e195bd9, 0x1ea68ed6, 0x3b39b9e0, 0x5fd34544, 0xf9e137b4, 0xb30afb94, + 0xb896b031, 0x52bc117a, 0x47f9e99b, 0xdcabb19e, 0x42928222, 0x4c72874f, 0xbcc4c089, 0x2dff3fcd, + 0xdad72d00, 0xe53a2735, 0x7cce47ab, 0x742bd856, 0x62df90cf, 0x2e56015c, 0x778dff81, 0xb5cf49d2, + 0x9ce8a531, 0x9ccb8410, 0x6aa1e379, 0xf891bb85, 0x6b6feee3, 0xe9064bc9, 0x04438ec0, 0xfd8d3314, + 0x5667acad, 0x6d2730e2, 0x4b817d66, 0x4e00a33c, 0xd143390e, 0x72d74e4d, 0xd7ea9923, 0xbeae2b50, + 0xf0fd5612, 0x65efed26, 0xffbfda72, 0xa061da44, 0x88d2d218, 0xb53dff1d, 0x3c4cfc09, 0x296c69ae, + 0x78b5337c, 0x3c57a8b2, 0xa81af43a, 0x6078a2d9, 0x1c960175, 0x445f46eb, 0x46bf9cea, 0xd15879c9, + 0xa9570f73, 0xd521b839, 0x83671039, 0xf5ec065e, 0x87f4328a, 0x5edfdaed, 0x8d286713, 0x45a0eec5, + 0x40d617f8, 0x4d45d9be, 0x5bf70807, 0x5aaa3149, 0xdcbf0469, 0x2ecdb8bb, 0x05aff9ce, 0x5b249feb, + 0xaa929224, 0x7ddd9cb6, 0xdf3f1a15, 0x306c1e29, 0xed46dc02, 0xc727209f, 0xb09a98bc, 0x4fc4d1a9, + 0xa5fa8899, 0xafc960de, 0x31c0b4b2, 0x7c76991b, 0x2b50167b, 0x1c2b1ce4, 0xd742c0ae, 0x82234ddb, + 0xf56064ed, 0xb83c256c, 0x443130a6, 0x5b4bd440, 0xba063af0, 0xa1e51537, 0xf6eb8dd3, 0x27dcc45e, + 0xdbbc1915, 0x4f65cce6, 0x615e27f7, 0x20072665, 0x8bde0f29, 0x5a029137, 0x046b3b05, 0x8eec0d73, + 0x66c5d476, 0x54471b37, 0xc3892278, 0x9f978d89, 0xddb3af84, 0x97677c4d, 0x6852de05, 0xc6a4f3dd, + 0x2cc6dd2f, 0x9ca7aa2f, 0xce622c56, 0x2677f3aa, 0x41710bba, 0x188583e6, 0xa064b9c9, 0x5d92958c, + 0xcd0356ec, 0x01c9eb45, 0x8982fabc, 0xf5ddaa81, 0x7304c8e3, 0xd6d97d04, 0xfe4a9eee, 0xe90859c9, + 0x7a53a0a2, 0x8d0d1af9, 0x6420eeb6, 0x33d09025, 0xa5160a7a, 0x3fa1bacd, 0xa6c60bdc, 0x788e3617, + 0xff9a71e5, 0x74c256e6, 0x4d0ba977, 0x3550beb3, 0x42655499, 0x4cca13d4, 0x919560a5, 0x775e1315, + 0xcf502892, 0x16826cc8, 0xbc20955e, 0x74c64d9e, 0x1424ecaf, 0x5117591a, 0xe6c22cab, 0x77f43461, + 0x75a20cc9, 0xff92fae6, 0x6bf1de23, 0x9d7a3ee0, 0xd5b07b19, 0xb5fb3358, 0xcd033897, 0xa6907848, + 0x53386a82, 0x2840c8e9, 0x8194e104, 0x493e2cee, 0xb7c2328a, 0x29dbbefd, 0xd93422c7, 0x330c27b1, + 0x4a46b83b, 0x30ada510, 0xb446de36, 0xa76dae78, 0xf72213c7, 0xa527a216, 0x2a907689, 0x9f242585, + 0xc09a045b, 0x858adc1e, 0x29cbb6f2, 0xcdc1108c, 0xed15fc9c, 0xe22d95d5, 0xb7204802, 0xacd6a9d1, + 0xa042bb43, 0x897272fc, 0x0810a8a3, 0x2bdbb844, 0x54d7db4b, 0x3125889d, 0xe4be3acc, 0xe876074d, + 0x3459973c, 0x29fb3a6f, 0xf53c24c4, 0xb426f8fe, 0xd1d79343, 0x52f2a621, 0x361c2343, 0x509396cc, + 0xff411d78, 0x65713bf7, 0xb091d063, 0x48911a9b, 0x38c8be86, 0xc8ab5b33, 0x8eedb38b, 0x5f78024f, + 0x9814a875, 0x79eccf37, 0xb0e20287, 0x013bd1f1, 0x268ae476, 0x30ee09d4, 0x74eedf28, 0xc3f66fa4, + 0x66af5200, 0xcee06d7e, 0x8f983483, 0x09246faf, 0x1e1c04a2, 0xd1090266, 0x0f2548bb, 0x763cfd2c, + 0x0aaa309b, 0xed47caf3, 0x813436dd, 0x315234d4, 0xa5776bf4, 0xcdf6be8a, 0xed468733, 0xd15f3bf3, + 0xefed579f, 0xda9d26da, 0xdac72de6, 0x09615793, 0xd0137cf2, 0xd45c66ec, 0x71269fc6, 0xb6667832, + 0xbc7a2c31, 0xc126de94, 0x1e8afd43, 0x1ab4fed9, 0xa9803c6f, 0x2647660b, 0xf58d3777, 0xfc953923, + 0xdcbbfd1b, 0xa0734596, 0x7795980c, 0x6ade576d, 0x7ccf6b59, 0xec608fa9, 0x51e86608, 0x2c559c39, + 0x34f72b4b, 0x41464c3b, 0xf81844f7, 0x3565110b, 0x68514342, 0x4fd227db, 0xca0f3e46, 0x1d5f812a, + 0xfd009c2d, 0x04da572d, 0x89c9e52e, 0x3ab04371, 0x5d1c6c02, 0xd2a16576, 0x73672f80, 0xe32c7311, + 0xc0739764, 0xb3f5c9cc, 0x00ccf68f, 0x97efa49c, 0x7ee97f0b, 0xa67c2a9f, 0x212c1a40, 0xe85285e1, + 0xc4c86548, 0xbe4c8024, 0x7a6146cd, 0xcd320a74, 0x8af88f10, 0x5b0ae470, 0x140233d2, 0x206fc79c, + 0x917818eb, 0x2f833403, 0x260b8b9e, 0x2819a580, 0xb06394a4, 0x35202cb8, 0x692bac67, 0x144fcfcd, + 0x38e06f0e, 0x96c9ac8e, 0xe6f0a52b, 0x21435cc6, 0x667e39e0, 0xcd5b9512, 0xbc6dd4b2, 0x7cb99517, + 0x054f9570, 0x962dcc96, 0xf5d23830, 0x447b59a5, 0x3a11d4b2, 0x6b087aed, 0xf89cda2a, 0x426d4feb, + 0xe853adfc, 0xaea01b6d, 0x46e507ab, 0xae4be22a, 0x4a527103, 0x0a999ca4, 0x29e8d752, 0x3bada4c8, + 0xf6b29dc3, 0xb46b2300, 0x63463a9a, 0xa5392cc4, 0x5739f643, 0x59b1bc43, 0x1ea44ba9, 0x546feb6c, + 0x75c2a5a0, 0xa6b1e51d, 0x9b29e173, 0xedfba27c, 0xe7f60384, 0x66a43880, 0x3d70654a, 0x38910b4b, + 0xa73bb185, 0x00e75e67, 0x88fdf2a9, 0xb2ca2ebb, 0x1852e671, 0x2f744b92, 0x1268724b, 0xa6be1272, + 0x2556c045, 0x449102c9, 0x3be8cfd7, 0x76bd179a, 0xcdf12db5, 0xd6358484, 0x58f0decb, 0xe5693a04, + 0xf6ae863b, 0x3563d47b, 0x7027bf05, 0x1d4fedf7, 0xd2b9e462, 0x5a283349, 0x4136d108, 0xc3f45b29, + 0x4ebd6567, 0x15b8a0ab, 0x9909e265, 0xa53f3093, 0x6e8f1bd7, 0x5798e83a, 0xc5762355, 0x613dee3a, + 0xb4dbf85b, 0x305ef739, 0xb3a63d6b, 0xf653a10f, 0xfd8a3a8b, 0xb5d9fe06, 0xef7a5d1e, 0xfee857ce, + 0xeab1a7a6, 0xbb76d921, 0xf74af6b0, 0x3b731c40, 0x80e5b930, 0xe7026c8b, 0x734d1758, 0x472c33a3, + 0xbe487327, 0x712a000c, 0x9fb47706, 0xe7c2e4cb, 0x4b137ca5, 0x9367d3d4, 0x75705a2d, 0xbfde46a3, + 0x36e58d52, 0x5dc9c151, 0x572cd44c, 0x77a3955d, 0x6598a5ec, 0x85799186, 0x84985512, 0x850c4d32, + 0x14e5e82c, 0xb7310b7a, 0x0b0c2202, 0x24922359, 0x01c4e64a, 0x0df154fb, 0x926bb410, 0xe8e80461, + 0xfb51aa03, 0x81bce384, 0x0ccd2997, 0x66fa1ccb, 0xe0624490, 0x250d04a1, 0xa4e37772, 0x7fed1653, + 0xef396c13, 0xd7438491, 0xc5c87fae, 0x0e28ecda, 0xef52dc7c, 0xed4fa687, 0xc08bd881, 0x96822f92, + 0x2f9b35e3, 0x187c5ab8, 0xebf0820b, 0xbac62d1a, 0xeb8f1e59, 0x0f144a2e, 0x5163261b, 0x8bed1c62, + 0xdf32e470, 0x7799ed48, 0xa5304c5d, 0x53e33bee, 0x2f384616, 0xd51167df, 0xfc1a70b1, 0x1d2910cd, + 0xbb7be89f, 0xa00d81ac, 0x47309c7c, 0xedc3c652, 0x51ddee33, 0xdfa38450, 0x1aaccf65, 0xde67d733, + 0xc5b582a8, 0xe6048edf, 0xa289f6f1, 0x026e35fd, 0x1569a09b, 0x7c1da715, 0x5f25cd84, 0xb5fec8cf, + 0xfb698620, 0xc68553e2, 0x1f15f997, 0x3897fd9c, 0xe729c48c, 0x84f79542, 0xb247b868, 0x0f86fe9b, + 0x603aa242, 0x69b3b444, 0x80f80d77, 0x6176b274, 0x17580f33, 0x9951ac3d, 0x1b1c8aec, 0xc8a549d1, + 0x0dc03c52, 0x9ab0bc2a, 0x6b098ee1, 0x5c17b85b, 0x618b6968, 0x70f4717b, 0x22e76a26, 0x05958264, + 0x8352df3b, 0x38d3192c, 0x7db4c9a4, 0x6dc07f59, 0x94a893f4, 0xbf2cad4a, 0x4bde3aa9, 0xcd42d864, + 0xaccbcf69, 0x856887b5, 0x3728f3b8, 0x3f030323, 0xdacf48e0, 0x04a2c343, 0x30162540, 0xe729cdef, + 0x52279d8f, 0x0fdf0cd2, 0x492666a7, 0x83e74e5c, 0xad069b28, 0xbeeef8da, 0xefa866dc, 0xf3af7cc0, + 0x645d8678, 0xb17e641b, 0xe4aaab6d, 0x8ac3a687, 0x37295348, 0xfcac6c3a, 0x52f06ca4, 0x333bc27c, + 0xa93ea1ac, 0x54bd1d0b, 0xa0b0bce0, 0xbeb5ec93, 0xa51a2bb1, 0x42925cbc, 0x932a9bcd, 0x030c9712, + 0xd311d7a6, 0x912a770d, 0x93b4c64a, 0x1b367693, 0x80dc2f8e, 0x3448bf39, 0xd6885f16, 0x38926476, + 0x508b1f17, 0x422bd087, 0x28f17864, 0x709f6373, 0xac852f5f, 0x7a115f6c, 0x804a07e9, 0x34b93028, + 0x993124b9, 0x5769285f, 0x8ce45325, 0x6919e0d6, 0x8d1524a8, 0xe072b369, 0x046232e7, 0x944c0c10, + 0xc52b77b0, 0x5b91bad4, 0xa96e6949, 0xf65c4a1f, 0xf0fcea3f, 0x0dd9bcf2, 0x5ba30b00, 0x6e1bd32a, + 0xcf3cc728, 0x8f060cb0, 0xd0e40d90, 0x9a389b53, 0xe273d94b, 0xa41626cc, 0x32322c63, 0xfd974f6b, + 0x3ec3e422, 0x527702d4, 0xbbf6b999, 0x74f5928f, 0x2ea3dda3, 0xffca68b0, 0x190a580b, 0x01a5a66f, + 0x9dc7c5cd, 0x7fb0894e, 0xee7c4b0d, 0x305a9b58, 0xe6bbae0a, 0x65289496, 0x9628c600, 0xaaccc8a5, + 0xf442cd3c, 0x078556f5, 0x686a03cb, 0x8da5a78e, 0x4389aeae, 0x0b7c342c, 0xe62cc582, 0xcd11379e, + 0xbbcdfca4, 0xfb48fb5c, 0x0d981691, 0x6ce5ad37, 0x6174288d, 0x9d24cecd, 0x24047947, 0x03b81982, + 0x29e317bb, 0xc22ef3c2, 0x94260d9e, 0x83da31f0, 0x61bb9125, 0x98021b99, 0x7a47111d, 0xcd077638, + 0x8f7bb509, 0x4b89f342, 0x41f59f7e, 0x28304c43, 0xb8088d9a, 0xe4a1043a, 0x762f6a6d, 0x397d2f0f, + 0x3b3456ea, 0x6f4a67ab, 0xe0f28eff, 0x4a286748, 0xb04000ae, 0x8068b005, 0x0fde5940, 0xf4944efd, + 0x0bc5399a, 0x29cb9a36, 0xd4a4f410, 0x0496e86b, 0xfc5b4ce9, 0x2adb70b0, 0x18affe58, 0xda58afe1, + 0xbf124c5d, 0x26346b69, 0xc1534306, 0x1b5fbf5e, 0xaf0c009f, 0x24543652, 0x869e186f, 0x3b3208e3, + 0x0eec1793, 0xaa1a3f0e, 0xd99b9143, 0xd5db7e03, 0xdeb51193, 0x9201ed16, 0x481410ae, 0xf2e7f19c, + 0x22006eba, 0x043983e9, 0x54813b3f, 0x01f8cefb, 0xe652ddfa, 0x1420c97d, 0x51232476, 0x314b3147, + 0x9059bbe5, 0xf231161e, 0xeb5eb452, 0xb8c0b7c7, 0x33932c91, 0x6188b592, 0x8687361e, 0x5d1ba2cd, + 0xe1c32296, 0xc32bc5de, 0xacc08509, 0x61c30385, 0x0853f630, 0x22da3140, 0x641c3451, 0x066064fd, + 0xe64bf4b3, 0x017be954, 0xba34846c, 0x886efb2b, 0xbfa0cdee, 0x969e5d6b, 0xb56c9aa9, 0x702798a1, + 0x3751f5a0, 0xa46c6559, 0x197e4de3, 0xea8acd8b, 0x41bc5e1a, 0x7c38a7fb, 0x34fd7e9c, 0x290c205c, + 0x7805bca6, 0xfa82c252, 0x920e3582, 0xba085431, 0xbd743217, 0x2deb8afb, 0xfa8f9d8d, 0x4a9a4bcf, + 0x9ae8edd1, 0x7979520d, 0x0996b402, 0xe5e4c3f9, 0x3be74874, 0xcc79bc4b, 0x21d6ab2f, 0x0c2c145e, + 0x294eddbe, 0x6e6a17ac, 0x8a8e0bed, 0x36d95f07, 0xf3da4397, 0xd2d84cde, 0x6db5c444, 0x6f283773, + 0x55018a83, 0x2d992a43, 0x5f9eadbb, 0x15c73ffe, 0xd42c179b, 0x2769ed81, 0xe7a641c7, 0x0ed8fd3f, + 0xf56c597c, 0xce58f917, 0x54d5bdd5, 0x3b8ac826, 0x9d9d9557, 0xefb09e90, 0x0a4ba5cf, 0x3bbf4727, + 0x65609f42, 0xcd0ef615, 0x98c59b7b, 0x70ffc85e, 0x82588534, 0x9ab95b56, 0x63a8e01a, 0x210ed17c, + 0xf9022e4f, 0x8d9ac630, 0x1b5cf1b8, 0xbec05a72, 0x87fa1ecb, 0x5e5af265, 0xbf64f363, 0x784bcee3, + 0xfd05f4b0, 0xe45240d6, 0x7034f8a2, 0x64594db0, 0xf6ab42ae, 0x2a704741, 0xebf115fa, 0x48a939d9, + 0x9f3b482a, 0x6192fbda, 0xecf8d3f8, 0x24485cad, 0x0ba60461, 0x4d8bc0cb, 0xf55ab5f4, 0x471cc0a9, + 0x793bba5a, 0x98a9e0d7, 0xa5e7d569, 0x2712d3dc, 0x2a6193a3, 0x49ffdbaa, 0x5d7171e1, 0xbf48dcc2, + 0x04e0daeb, 0x76daaed2, 0x8f93c3bc, 0xe996a0c1, 0x1abdeaa8, 0xa257a5d7, 0x4185fd91, 0xf85bed02, + 0x8d88081b, 0xda905ebb, 0x206d1b44, 0xd50d16c6, 0x8926f27f, 0xacfc5202, 0x191a8564, 0x3a9669f7, + 0x18503bfa, 0x6d9c9281, 0x9a560fd1, 0x4176f010, 0x4e7a4a21, 0x03ce3e43, 0xb993b18a, 0x96ab5a6d, + 0x1d0ea0f0, 0x23f661fa, 0x366ac72c, 0x7e0a3d55, 0x31156224, 0x3a2320d9, 0x6cdae4d4, 0xddfce3bf, + 0xc6f0dc30, 0x1a084902, 0xecce2238, 0x70a16a8d, 0xeb3111e2, 0x3ded12e0, 0xe3818a88, 0x91d00fda, + 0x3b857d79, 0xbaf582d8, 0xffa46aa2, 0x0b22386a, 0x956c3d24, 0x0d8d5d2d, 0x94456d48, 0xb159f547, + 0x72ffbb82, 0xa6518559, 0x5cca61a3, 0xb52c93ca, 0x57420647, 0x9eb00b43, 0x332480d7, 0xb579ecbb, + 0xc46905ec, 0x555365d8, 0x104296a6, 0x38bf8dec, 0xa276402f, 0xb8ff399a, 0x7419409f, 0x9b3aca04, + 0xb3f8e637, 0x6fb12861, 0xf9bf342b, 0x5f487074, 0xadaa2b66, 0x369ad29e, 0x11612548, 0xa6bcb325, + 0x829254e7, 0x2c3effe7, 0x228e479b, 0x6cc4fd57, 0x81ad3f6b, 0xc367fa02, 0x567b072c, 0x076493fd, + 0x3eef8d53, 0x5699fab3, 0x87a6c4b8, 0xbd37c491, 0xdfee4cf4, 0x970eaf96, 0x910c5d31, 0xf09cad03, + 0x0baa6eaf, 0xdd8bccd9, 0x7c1dd440, 0x85e4c203, 0x90afab3e, 0xc1a31d41, 0x5793eaa8, 0x3421942b, + 0xd7467891, 0x25f41a5a, 0xec266a28, 0xf79744bd, 0x7a5af04a, 0xa39ad417, 0xe7e1bebc, 0xc73e0742, + 0xffbbb423, 0x3162febe, 0x648a5b88, 0x95abb406, 0x78634401, 0xb00d9e70, 0xffb92e92, 0x54d3c1db, + 0x4f2efdca, 0x89fccda5, 0x533ebe5c, 0x26feffd0, 0x96539d44, 0xd172da23, 0x8fb490c6, 0xc4b2283d, + 0x355bd689, 0xcac4a1af, 0x457a3b69, 0xfa6ca68c, 0xd538332f, 0x3e195a16, 0xce688468, 0xfc01f0f1, + 0x3bdea3c3, 0x51164a74, 0x258d0558, 0x737b55cd, 0x78dcdcf2, 0xdbf364a4, 0x1d89af08, 0x97246fe2, + 0x86b07278, 0x8c29e100, 0x15d4211c, 0x4f3b4939, 0xf3739675, 0xf95f5063, 0x5512001f, 0xc9d596b2, + 0xf0af4792, 0x0c1ebbac, 0xddb2609c, 0xe014629c, 0xcc6a7d51, 0x9f30287d, 0x325710bf, 0xcec8df6a, + 0x6e27fac8, 0xd2995b97, 0x4d744387, 0x14681fc8, 0x5e5ff3bc, 0xb975a504, 0x4d43de81, 0xa0979a1b, + 0xd418df78, 0x29165ba0, 0x5230afea, 0x88a57aaa, 0xe747d768, 0x51349d19, 0xc0237221, 0x145941ec, + 0x3d4201ed, 0x47c8a072, 0xc4b933c9, 0xdd04ea89, 0x93e950f6, 0xfb86aba7, 0xf7a7acc6, 0xf53279e9, + 0x4984d497, 0x1cd5efe5, 0x35b03e53, 0x335480c4, 0xbc82c5de, 0x799b198e, 0x3d15be7b, 0xb2b328db, + 0xd553dfec, 0xcf1b2385, 0xaf069f38, 0x4a550adf, 0xb51c867f, 0x4c2831ca, 0x1fdf94b7, 0x335ca351, + 0xb63f7605, 0xc8cc2540, 0x6a035cfb, 0x05f6945e, 0x9e634f90, 0x9bce236a, 0x041fa0d8, 0x6e00c541, + 0xae24ab1f, 0x2528257b, 0xf39950b5, 0x6fa53c11, 0xcc7c90db, 0x25da502b, 0x8e577b54, 0x009686e7, + 0x15d0b8f6, 0xb52e807d, 0xcc6e6a58, 0x0c8feb57, 0x8b640562, 0xd95522a4, 0x3928c7d1, 0xb58f383f, + 0xe291958b, 0x9ad648c9, 0x89e6c29b, 0x3b5027d6, 0x7c5a8260, 0xfa5aec97, 0x94ccf8de, 0x8b7d5d13, + 0xd906fb3e, 0x3019eb37, 0xdeb2e114, 0xcafc56dd, 0x9f77fb77, 0x027698be, 0x5cc6f7e6, 0xb50df7b0, + 0x2b748259, 0x1eacdda7, 0xdf4cf4b0, 0x55f5eb17, 0x8ea262e8, 0xfe7a4bd2, 0x3105e1e7, 0xd228515f, + 0xb2709b08, 0x6d3549d2, 0x1e257eff, 0xa60b9df1, 0x3f7562e2, 0xeab0502c, 0xf4fcff76, 0xd74f8438, + 0xb3ab6278, 0x32607465, 0x35cf2c45, 0xa15a0dd6, 0x1734f530, 0x0120efa2, 0xd17485c1, 0x2579ac0f, + 0x1e16d65f, 0xe0836a3e, 0x50027aa2, 0x975f4588, 0x704a321e, 0x5c19b480, 0xf2d94501, 0x5d7c66cf, + 0x1ca8c4bd, 0x4e7aa51b, 0x938d12da, 0x03357757, 0xd6386250, 0x11e34438, 0xa888c3ef, 0xe0ee8de4, + 0xaa66a5fd, 0x0fea4d8a, 0x70794644, 0x5622fc3c, 0x7e1b2009, 0x3ae8c71c, 0xe54f37d8, 0x1359c449, + 0x708d365c, 0xb363ccfd, 0xb5e62b80, 0x2c495f5b, 0x48b66f60, 0xc8a1fed9, 0xe45f8d5d, 0x5ebc92c7, + 0xae5e6ec3, 0xa175a978, 0x58ba7984, 0xbdf2b315, 0x5f50aa4c, 0x3cd339c6, 0x9b6a9168, 0xf4d10c03, + 0x12c07290, 0x25a7b2c8, 0x37614d0a, 0xdafdceff, 0xdfb584c9, 0x026c26c9, 0x4701a420, 0xea029f2a, + 0x5ce443f7, 0xc5b2a922, 0xdb7ebcbb, 0x9137d5e8, 0x54f6e21a, 0x0d710113, 0x47bb2a48, 0x4d976ca9, + 0xeb3354ad, 0x47fe7637, 0x9ae4a9b8, 0x392dc794, 0xd9a6e753, 0xe3606255, 0x1b136746, 0x5fdc2cd3, + 0xc1efc0b7, 0x5fe56f0e, 0xff29f76c, 0x0f2fb6f2, 0x794fcb6a, 0xb0da3de7, 0xeec31339, 0x24ae11f9, + 0x52d7936f, 0xac67a81c, 0x25fc6874, 0xb37c1dae, 0xa1278753, 0x96a4ebb9, 0x086f0dc2, 0x5e20c3b9, + 0x598d49f0, 0xa47523df, 0x62c7014f, 0x8849b0c0, 0x91962cab, 0x4321b4dc, 0xed7bdbf8, 0x013c71e6, + 0xe2d1c4e5, 0xc8cf4e43, 0xa0ef7325, 0xdfa4afbd, 0x17215905, 0x3ae8280f, 0xf1eaba71, 0x438f0241, + 0xd671dac6, 0x41330196, 0x08fc3e6e, 0x2695e2a9, 0x48bb8417, 0xb381332d, 0x60bad860, 0xaaa9f00c, + 0x029287ad, 0x460fc912, 0x5d1d0a39, 0x09a84bae, 0xb4d31f5a, 0xc431e5fe, 0xe90c18a0, 0xd60d7939, + 0x4e0ee641, 0xaabf0388, 0x5508f59b, 0xd3f4f1c8, 0x830bd67f, 0x945b41c0, 0xc8947e2e, 0xfd73f4bb, + 0x60720dc3, 0x1e898e30, 0x622fce2f, 0xda65440b, 0xa80ec4f5, 0x77e90377, 0x3c9cc978, 0xfe0936ac, + 0x9fbd5df9, 0xda3bb5b9, 0xb9070bca, 0xfa389be7, 0x19af2f96, 0xee8601ed, 0xc8d09f4a, 0x51a873c0, + 0x6c1492df, 0x7c442271, 0x12b89b9d, 0xf83d7e7d, 0x0b876ad4, 0x130c941e, 0x0d077611, 0xb1760038, + 0xcded1e1a, 0xc5441278, 0x47e8b25d, 0xb27fb425, 0x0185438b, 0xa51254ba, 0x6c0150b0, 0xa949618a, + 0xba13d4e0, 0x304dfc07, 0xee1c7d05, 0x315bf542, 0x79885fca, 0xf1e80dec, 0xd413f13c, 0x67798eb1, + 0x5347dbde, 0x2ba68429, 0x912fdbff, 0xe9bae903, 0xa0749c39, 0xc0af1771, 0x471c1daa, 0x370ffee0, + 0x4beeca45, 0xc8f9d96d, 0x962a6b84, 0x4f4c2f94, 0xe24c92bc, 0x7389a023, 0xe24d002c, 0x1975e5a4, + 0xf5bc1205, 0x3bac7720, 0x26153de0, 0xac4ad18b, 0x1cf54ab0, 0x6a06c2ae, 0x961b38cb, 0x7eb6f1e8, + 0x0b84fd1a, 0x8395a2dd, 0x1ceafb89, 0x507bb006, 0xdf72ae3f, 0x8c7741b1, 0x8bb75a0c, 0xcb153de6, + 0x43ff153f, 0x18bd717f, 0x276fa3b4, 0x2bb1b3d6, 0xaada16b4, 0xa1b5293c, 0x2d10e946, 0xf441eb0e, + 0xa438f420, 0x6ac1c5cf, 0x4a39f587, 0x1be0c1f3, 0xc4656638, 0xed5d158f, 0x2044eee9, 0x1f5f9852, + 0x51348c84, 0x05bfdb29, 0x217ab792, 0x37d30844, 0xf0ef4b1d, 0xf45fb990, 0x13698ad0, 0x441c7144, + 0x54831896, 0xac17d198, 0xcf5b8f0f, 0x985cef1c, 0x725aac28, 0xf550d76c, 0xfa6fed13, 0xb2672812, + 0x57f25712, 0x86e07efd, 0xce5bf825, 0x704bf366, 0xeca52eb6, 0xa9adbf04, 0x64b242df, 0x2f6fe443, + 0x48aadd7b, 0x270bb056, 0x8add4538, 0x27011e71, 0x9787d8d9, 0xf2572c52, 0x845aba70, 0xd0a4b969, + 0x5ff64b64, 0x608ab884, 0x7332ed6f, 0x9b05c337, 0x2b1731f4, 0x6eb0c7d8, 0x5d769df6, 0xa8b95deb, + 0xc614a2c0, 0x997ad7e8, 0x8e15dc47, 0x185093cb, 0xae3fe32e, 0xedd6fe96, 0xfcc1558f, 0x652b6fdf, + 0x473de7c0, 0xbd55ae9b, 0x02c9bf75, 0x19f949d4, 0x4067e3d1, 0x45b5254a, 0x5ad18c9d, 0xf29299fa, + 0x6d7dfc73, 0x693abfb3, 0x93d82973, 0x71e46aef, 0x783e5493, 0x80a786e3, 0xab8b269d, 0x181daba9, + 0x02f95886, 0x83fd0c14, 0x1438e76c, 0xdc64aa8b, 0x27e1f824, 0x49c6d0c6, 0xdb8cfd3d, 0xc82a1b56, + 0x16aab492, 0x964cc242, 0x2150b905, 0x56b18d66, 0x1244beb3, 0x6a70e060, 0xa17f3af6, 0xee2c1b33, + 0x97ff0ddb, 0x3c967081, 0xbc22d950, 0x7cafa7ac, 0xb30ba77a, 0xbbe59cad, 0x1f06968d, 0x542e1b86, + 0x3c642649, 0x54feabfb, 0x6be34321, 0xe747bb35, 0x9a5b12c2, 0xe2a34de8, 0x0ad55546, 0xb538c5d3, + 0xe0b82b6e, 0x7e09d4a5, 0x9138c83f, 0xb5b4df02, 0xf1b76ac5, 0x919e9f27, 0x343c5e1e, 0x75f2c4d4, + 0x4d6f504d, 0xc5951cd0, 0xe88246b4, 0x1c6dba67, 0xb917a3b5, 0x90ef415e, 0x0997a96c, 0x67a833b9, + 0x1de1ab4e, 0x3c146e63, 0x9b4af8d6, 0xf1d3f473, 0x8bbd05d5, 0x3f0b5bec, 0xc816d23c, 0x8cc45e32, + 0x1d4a36ad, 0x7c5dcb4d, 0x4bee980f, 0x0f2b6c66, 0x6c68df1c, 0x42602cbe, 0x1eb96027, 0x13bb379b, + 0xa12d1b86, 0xa4c5f34f, 0x4367c680, 0x4f79380d, 0xa1640446, 0x0a4c1b30, 0x0b845e77, 0x1fb08018, + 0x9d7574c5, 0xad7cba5c, 0xbb731e72, 0xe097ad81, 0xb1ae800b, 0xc3c1d1cc, 0x0223dc6f, 0x9cd196d0, + 0x3ea2cfff, 0x05ba2139, 0xb4e815a2, 0x54de6e37, 0xe96e7870, 0x5877feed, 0xe1cd80f3, 0xdfec53c7, + 0x06439931, 0xea9d266b, 0xd152d29e, 0x7370fd89, 0x87ea6fed, 0xbf862646, 0x8ab7f02a, 0x8c0e02e0, + 0x82c2eaa8, 0x5a0f337c, 0xc220d180, 0xf8c03866, 0x6bdb46b3, 0xb1f2b5b9, 0xfb22fac6, 0x3e8e7c6b, + 0x6f1b13f4, 0xf8262060, 0x19160e91, 0x89445d60, 0x69e50d59, 0x652c6721, 0x0530eb92, 0xf5aa96eb, + 0x78732020, 0xcc1062df, 0x833881c6, 0x32a482db, 0x9f94c3cb, 0xbe5098ea, 0x24626b43, 0x66059141, + 0x73c3f604, 0xda9785d8, 0xbc3f83ac, 0xd116c26c, 0x126b8b98, 0x1b9e0dd0, 0xf90dab88, 0xf0b6ff42, + 0x47ebac11, 0x951684c8, 0x659a684c, 0xfa066944, 0xfb332db0, 0x29137698, 0xe35fefc8, 0xad2cef17, + 0xd75878ba, 0x371ad906, 0x34769156, 0xb03944b9, 0x9cd50836, 0x372c75dd, 0x5de82da3, 0x84523c5d, + 0x6211835b, 0x3d68a323, 0x4d0151a0, 0x52b6e28c, 0xd7950a20, 0xd32aca5e, 0xa734dc55, 0xe58145a8, + 0xb59fe54a, 0x50b61331, 0x1e796870, 0xfa3b0942, 0xda24dfd7, 0x96250d28, 0x53e2b360, 0x80c88491, + 0xd2d85031, 0x84aaef38, 0x0a7b645f, 0xfbe9a0a9, 0xd660459b, 0xec6a71cc, 0x4db112ba, 0x027a287e, + 0x6ec47fdd, 0x30cd9a06, 0x48629c63, 0x45a6fb09, 0x93d5a509, 0xc57512bd, 0x6a13d9f3, 0xf4eb12de, + 0x61479a50, 0xdaf8305d, 0xfc0e5314, 0xacb8f535, 0x32925fa4, 0x3e6a3c7a, 0xc3110a7f, 0xfe06124b, + 0x6720c9bd, 0xbb4910a7, 0x2512c0ce, 0xf8f47ec7, 0x2c307a9b, 0x89caf27d, 0x8c3ad1cd, 0xb6bb03bd, + 0x3d459b2f, 0xdb3f4692, 0x4d3e41cb, 0x9ed59ce2, 0xee155510, 0x7b1558d1, 0x7d25ecb0, 0x76ce214a, + 0x58bd3f88, 0x3fbf4f73, 0x5965fb56, 0xbacab3ee, 0xc20c5d71, 0xdc946cc6, 0xaad9e813, 0x775b5255, + 0x97ce2ac6, 0xcb8aee5c, 0x5b3c9b08, 0xecb0989d, 0x8bf81c4f, 0xd1f5c651, 0x0d450d53, 0x9c1e1a4a, + 0xfb7fd589, 0x5f743cd6, 0x621b98ad, 0xdf6638a6, 0xf6b7dffe, 0xb6475acd, 0x5fe0329d, 0x2afcf579, + 0x7a477cfe, 0xd2ef6aaf, 0xcfd8e064, 0x002ca5c5, 0xa0b5bbfb, 0xd4f07002, 0x72498052, 0x1a40bc56, + 0x3387b9f1, 0x26383c3e, 0xf34d9e62, 0xc2a91e54, 0x1b55d906, 0x29554884, 0xe54a449b, 0x62a6ce51, + 0xb8e21720, 0x2d8b21ea, 0xa04cc5e2, 0xe642b979, 0xed187907, 0x269f0848, 0x18dbbdba, 0x6101a586, + 0x09838e7c, 0x881bec4a, 0x0ca1d2f3, 0x782590e9, 0x137fe348, 0xff56b7d0, 0xe7da162b, 0x9c606c77, + 0xdde0ce26, 0xd84add06, 0xaf2ea96b, 0x586a5f0b, 0x8606b10c, 0x62c30e61, 0xedd9afea, 0x1d774c07, + 0xf751ba74, 0xf7b6588b, 0xc6b802a6, 0xce5a3f2b, 0xb63fabe3, 0x23279b1e, 0xc38cbf31, 0xc39ac15c, + 0x71cb9dfd, 0x5d35a072, 0xd73b64a8, 0x08326e83, 0xfdd1a309, 0xa234f0a7, 0x3224e602, 0x552f7560, + 0x1e8e8091, 0xbe3c8465, 0xe5d8a0a1, 0x6f622882, 0x7638171b, 0x62d7fc91, 0x63bf2a07, 0xcbc69b04, + 0xc5a77c38, 0xe47d4848, 0x368fcfa0, 0x06bf1f60, 0x7f29ee2d, 0xff63b2d3, 0xe9791081, 0xb4d3c986, + 0xc097575f, 0xafd26cbc, 0xd0970069, 0x26aacba4, 0xa4c9dcea, 0xc2b3b3b4, 0x7be13548, 0xcb05b1e9, + 0x247abd8a, 0xc7e4c8ac, 0x9c1a8398, 0xea6d4161, 0xc3182ea2, 0x8cc3f47f, 0xa81ca10a, 0x92a8fbb9, + 0xa7fbe0ee, 0x01150202, 0xc545b448, 0xb446556d, 0xb0ffc3b7, 0xee986e22, 0x7de0d1bf, 0x4a28073c, + 0x4adba40c, 0x50db6c73, 0x4562ac0b, 0x8b1a662a, 0xdc83a5e7, 0x549e02c5, 0x809aed51, 0x70021fdc, + 0xc6ee1511, 0xf02f1332, 0x6156c9d3, 0x8a47474f, 0x5bd37a61, 0x61609e0b, 0xaff68feb, 0xa27bdd55, + 0x4c2ba085, 0x11feac08, 0x893b2c7c, 0xd9ed916d, 0x0403be81, 0xc5c58c76, 0x90888381, 0xea97f0e7, + 0x0ce145d0, 0x348d3665, 0x2647f303, 0xf6ae028b, 0xb4f99212, 0xa6e16c5f, 0xca07b324, 0xcb2f74c0, + 0xca163c66, 0x4d8f1446, 0x29a838e7, 0xb5bce18a, 0x50986580, 0x9d9bb760, 0xa2fe808d, 0xb17ed9f9, + 0xb25436d7, 0x9743b9e4, 0x6e500bc5, 0xd9cf8963, 0x9d7c8a4d, 0xd844a2eb, 0xc42753b0, 0x70776eac, + 0x25e168da, 0xf5d65891, 0x4f2c12cb, 0x125e8824, 0x1622f7b6, 0x7990a3a4, 0x9f780c04, 0x269ef53d, + 0xc9afaa74, 0xeb14897a, 0xd5ba7ba6, 0x9ce721fc, 0x7861df46, 0xeda98725, 0x4c8989fe, 0xc3472496, + 0x90c34715, 0x3f6f5fe7, 0x075818f6, 0x5f325e31, 0x92a34daa, 0x5caf5f00, 0x78f013d4, 0xe73b0838, + 0xac8bd350, 0x8db2d311, 0x8f1f7af0, 0xa0e5011b, 0x57b5a5a9, 0xfe0b8349, 0x30d08bda, 0xb66ac8d9, + 0x8cffc053, 0x8892f9d2, 0x25cd6bdd, 0xc9018411, 0x93a9381c, 0x1f943b60, 0x6208dd3c, 0x9108b1d0, + 0x6cd69322, 0xf9390baa, 0x048263bb, 0x5cb44efc, 0xa684adbc, 0x30e504e8, 0xbbc7c33f, 0x5e64b56d, + 0xbef5d6f4, 0xea2982a7, 0x21431efb, 0x26fd04aa, 0x8d5abf90, 0x8069c5b1, 0xaf694e7f, 0x8d98da7e, + 0x9d9bf2d5, 0xcff3cca4, 0xf9a188e2, 0x3f3a43e6, 0x12ff64ff, 0x52022632, 0x2fa6616b, 0x8862611f, + 0xf4d4de4a, 0x4e277bfe, 0x89057aaa, 0x31903ba1, 0x0da2eef8, 0x32618b63, 0x22cb036e, 0x6f797ec4, + 0xd45e8c92, 0x9aafe7ac, 0xef07179e, 0x4d4e5072, 0x32c7d894, 0xa42a52b1, 0xb0e8ea41, 0x0fc453f7, + 0xca1bddeb, 0xea5b52b6, 0x28abd61f, 0x16fa605a, 0xa51ad33d, 0xb5061e11, 0x29ac8dac, 0x8519ecf4, + 0x2f830aeb, 0xbc563852, 0x4b39f51e, 0xd7fdb880, 0x2cfa11c6, 0xcda68b7d, 0x6187674e, 0x020f446c, + 0x564fc894, 0x6f93eb64, 0x98f1193a, 0x256724d2, 0xaf3b3831, 0x97126bd4, 0x97e3390f, 0x150b0a16, + 0x3542444f, 0xfe586819, 0xb1b681c1, 0xad5436e1, 0xbad93bdd, 0x714bef91, 0xc296a390, 0xe60f9bf5, + 0xba7b397c, 0x79c95aa3, 0x4fd00bda, 0xa0021b02, 0x36727226, 0x93dc1d13, 0xefbcaf4f, 0xba945993, + 0x9398f2a7, 0x9616aa05, 0x77539eb3, 0x7d1f08cd, 0x28f8eb79, 0x04aca31c, 0x298364a9, 0x3c86888f, + 0x25fc149e, 0x86ab52e9, 0x794e3c8e, 0xc95a5513, 0xfa6d8024, 0x315860af, 0x2fd32670, 0xb25f6f83, + 0x7e6a3c1c, 0xf8050708, 0x333ee736, 0x76ff7a40, 0xef2ec79d, 0xeb3ea6c6, 0xaf5fc3aa, 0x6616633f, + 0x7d16e0e0, 0xfef809a0, 0x9ad3e031, 0x7e098370, 0x4b0007f6, 0x0bfdc332, 0x33be3d01, 0x72a1dcc4, + 0x91be688c, 0x9a55d92c, 0x24304aa6, 0x72b70038, 0xc35f9e1f, 0x47f8fcb3, 0x52f6510d, 0xd4ba5ef4, + 0x42a4e270, 0xcc2cb72f, 0x780bce9f, 0x7454603c, 0x2830b980, 0x285634a3, 0x0b905499, 0x3e699e0d, + 0xc1d705a5, 0xe368b488, 0xfb35be5b, 0xaf865b28, 0x45349528, 0x13ed1c85, 0xaca1d3fb, 0x5a0c7f2e, + 0xe026254a, 0x86740119, 0xb7096166, 0x269f683e, 0xa5646d0a, 0x371f53dd, 0xadbe6cb1, 0xa28d54c2, + 0xd1356b3e, 0xf0ff490b, 0x79e30191, 0xdb53a1ea, 0xa130d2c6, 0xe59f7668, 0xaa581125, 0xbbbe5785, + 0x75affb16, 0xebd56414, 0x67b8da24, 0xd175bd40, 0x6097f031, 0x339fd639, 0x32c34b01, 0x682afa7b, + 0xfc63c964, 0x9f4fc0eb, 0xa47f1226, 0x19c5849c, 0x25fa8bb6, 0xbaffcc72, 0xacca2f8f, 0x5fe995cb, + 0xa2c92aee, 0xa03c6483, 0x4a940c76, 0x86197f8e, 0x58b58823, 0x50b2fdc1, 0x5e5378cb, 0x5b7b1df0, + 0xe7af5e4c, 0xc8d20988, 0x505af2fc, 0xb55c3402, 0x19976efc, 0x6a1eae51, 0x20fdf83e, 0x9248c174, + 0x7a3a603e, 0x14670561, 0xdf05e04c, 0x5e49ccdd, 0xb3607402, 0x8935594a, 0x79fd66bb, 0x3b6873a3, + 0x009edc7a, 0x2296519f, 0x0e0ce583, 0x01173ab3, 0x6ab71fa0, 0xcbaba7de, 0x957b930f, 0x057b6e6b, + 0x067b3fef, 0x53465377, 0x477554d8, 0xb57e6791, 0x420199b8, 0xa2acfc16, 0x805dc224, 0xe8bf59ed, + 0x3c7af962, 0x64eaabed, 0x3b627d1e, 0x9f777207, 0x884417b7, 0x864b025c, 0x9ef9cea5, 0x6aa96244, + 0x23e3e93a, 0x205d33b6, 0xdee73a88, 0x1c2c395c, 0x55503ecb, 0x0eff5265, 0x61a2dd44, 0x07716f57, + 0xeabb95ab, 0x4ecee8cb, 0x5ec8f22d, 0xfcdae1bc, 0xee239ad4, 0x3e1cdb43, 0x67a5cb51, 0x7d8a8da9, + 0x17ea9ef8, 0x681d8c0a, 0x01208f2d, 0xd6dfafc3, 0x259d7e1c, 0x50e7ff72, 0x7a187af6, 0x3b426b14, + 0x9d5b4585, 0xa818f5c5, 0xef1c0481, 0x7b940dc4, 0xea10f3d9, 0x868f31dd, 0x5e207a87, 0xf03fc3e5, + 0x655c6685, 0x1e2262e7, 0xa4de82d6, 0xae302907, 0xca68a9a4, 0xaf2b4530, 0x1548b3c5, 0x9fabd30e, + 0x36abd276, 0x56f0f3c9, 0xc7c1f3ad, 0x0dfc5a32, 0x4199e005, 0x501109e5, 0xea797ebf, 0x0dc97938, + 0xe083e692, 0x7af071d5, 0x78e67d35, 0x654ba7cf, 0xf00316dd, 0xbea3d6ef, 0xe4727d85, 0xf0334f6f, + 0xf15f10e8, 0x3861da6b, 0xcf7b0e54, 0xe21d5d69, 0x47819d7f, 0x4e9e4db7, 0x9d170d48, 0x5e8a870a, + 0x80f53640, 0xf23f5864, 0x60f5bba5, 0x1e1547c0, 0xa6231574, 0x06d4f16f, 0x6ca6685d, 0x68ba8ef7, + 0xb9ee4586, 0xad8cbd9d, 0xfb39053a, 0x98c09688, 0x5a8827c2, 0xf4f3154b, 0x69d137ef, 0x08558c75, + 0xd05c4846, 0x3f6eca56, 0xcd880d24, 0xcc9e6cdb, 0x2a46bd29, 0x1eeb4e6b, 0xe3700ce3, 0x600064c8, + 0xdd15d274, 0xf4d8bb4d, 0x6cc5d66e, 0x21e19519, 0xd7175371, 0x4a671a33, 0x89c66cc9, 0xdbe53e7c, + 0x37803bf5, 0x11fb5ad1, 0x1d16a110, 0xd24457f5, 0x5640e58b, 0x15da203a, 0x2ff313c9, 0xd5dfe909, + 0x0d365a17, 0x9fc9b7a7, 0x8ef28a14, 0x10d3ee33, 0x57974d61, 0x89f4face, 0x1c1ec7c4, 0xaaba66e7, + 0x3b6b2817, 0x033b0307, 0x21583c82, 0x5d2db67c, 0x6f9f2c13, 0x6099a976, 0x13eae68b, 0x3ac2a43f, + 0x50b43561, 0xd9765d00, 0x6c1a8f46, 0xec61d7dc, 0x550ed092, 0x610fc181, 0xe104c733, 0xba0c95b4, + 0x5c713e61, 0x066032b7, 0x87b8552f, 0xd59a8bae, 0x6290dbc3, 0xce4920cf, 0x0fb01972, 0x739b7848, + 0x91058f8e, 0xa7f608a1, 0xea83050e, 0x0afc9afd, 0xed858c06, 0xa40875a8, 0x6d49f556, 0x691f8e4b, + 0xa6774d47, 0xeef807ff, 0x95de28e2, 0xa88f60c3, 0x3300103b, 0x2f783ddf, 0xae9b32a7, 0x447bd43c, + 0x3b4e2138, 0x6e9c7285, 0xae2e1469, 0x5676f07f, 0x9245ef66, 0x478335ae, 0x613d982c, 0x06021742, + 0xadcf822b, 0xaab39f42, 0xd73f682e, 0xa43f4170, 0x5c9eec82, 0x035e888a, 0x9e8b3d05, 0x10d64025, + 0xe5b61bd4, 0x338f0d57, 0x2741c272, 0xa49b90a8, 0x90a66a56, 0x2ffbf43c, 0x541fb0cd, 0x9a520508, + 0xe6c54cec, 0x1cd96554, 0x06cdf76b, 0xe6edb4dc, 0x38ac4d76, 0x94c3d4cf, 0x1d64d306, 0x9209b286, + 0x3edcdd4c, 0x050ab120, 0xe5848d2d, 0x01c2f66b, 0x79c0268b, 0x1efeb794, 0x6e8df816, 0xf7e9f5dc, + 0x71dc84fd, 0xed059cf2, 0xe4eadcfa, 0x99af8681, 0xd2ceba09, 0x0bf4523c, 0x753c7040, 0x625974c8, + 0x67212ddf, 0x6805b439, 0x2a6bc705, 0x18c5a852, 0x668ef6bb, 0x8a2d210e, 0xa5d265db, 0xaaf6fe4e, + 0x213bc173, 0x4dc22c51, 0x151c9cd1, 0x8e3124fd, 0x6eccdd3d, 0x8c9564e2, 0x32cc4483, 0x8dda596f, + 0xa7e95238, 0x70d552ab, 0xa52f2510, 0x3ddb4f31, 0x00b69938, 0x185c82e6, 0xe34478a0, 0x65ad5b89, + 0x470bbaeb, 0x82f3defa, 0x12109a08, 0xb6672b4a, 0x27f0eec8, 0x508e43a0, 0xfeef36a6, 0x37461e10, + 0x36657ec4, 0x55f9e4fe, 0x609e165c, 0x9bd5a2b6, 0x7f6e02f9, 0x0984a141, 0x59a5e623, 0x7b885fe7, + 0x5c3a35f7, 0x293de7e8, 0xfa56a88d, 0x633b0f60, 0x312bb48a, 0x0c9688fe, 0x1c38806a, 0xd186cd55, + 0xa8b54f67, 0x7d80cad8, 0xc22a6d45, 0x1e407cd6, 0x734d162e, 0x1a7bf423, 0x47513802, 0x90a3eb78, + 0xa08dadd2, 0x991f271a, 0xfd02b143, 0xf3570bb2, 0x87815d43, 0x453a2ec9, 0x5e547dce, 0xbdc3e8f6, + 0x448c7b98, 0xc107ed6f, 0xe551cfca, 0x51881d6f, 0xbc91ec91, 0x2411d8af, 0xfef4cf97, 0x9aa6b97a, + 0x34bdb819, 0x1407bf84, 0x18f5adc2, 0x13d18bbb, 0x82694eb5, 0x1c40c045, 0x8ba728f8, 0xeda8a11a, + 0x34ffaf9a, 0x2dde9e69, 0x1bfb5696, 0x332391b8, 0x24ee6340, 0x16d5e399, 0x715ad954, 0x4a49d5d3, + 0x0ee16f1c, 0x1bb4ea57, 0x1652217b, 0xe7a0d2fc, 0x98d456b6, 0x4c65ecc2, 0x0dd288ab, 0x490b89f9, + 0x278a2c8d, 0x761e6cd7, 0xa7a59da1, 0xbd46aed6, 0x54ae91d8, 0x40a13930, 0x0afe72a1, 0x71d23b13, + 0xed0bb07f, 0x029fb8d6, 0x920c4a68, 0xa4afa8da, 0xc8618bfa, 0x70e0b81b, 0xa3700998, 0x68ac0f06, + 0x33880a5d, 0x19f3c539, 0x35391046, 0x73149c2e, 0x94d7eccc, 0x834a4320, 0x7e099531, 0xeb6cb866, + 0xbd56ca76, 0x80497eff, 0xb0b37b0a, 0x899baf18, 0x03806f08, 0x0fcad484, 0x3ad5de1e, 0x45e0fb52, + 0x0098004f, 0x5debc465, 0x49b6b238, 0xe1fb910c, 0xbe7e4635, 0xa101c0cb, 0x22bd1fe7, 0x68b75a8b, + 0x068e2884, 0xdf2156d0, 0xc371b691, 0x0e840b7b, 0x20a82f48, 0x5468fafc, 0x629af4dd, 0x680ef12b, + 0xe32a813c, 0xf389a759, 0xd9b2223c, 0x8caef8bd, 0x54456886, 0x0f741da9, 0x7dbc3cc5, 0x55548b33, + 0x22b64647, 0xcf975a4f, 0x49845bba, 0xabe0ea99, 0xad2f1ad3, 0x58e45a4b, 0x0eba62a4, 0x9de476e4, + 0xa1e15e05, 0xf7a2cfef, 0x6b447c25, 0x13888ad2, 0xc4eeeab7, 0x200a7ae1, 0x5a32a048, 0xbc3da05b, + 0x996f89eb, 0x2317b2ff, 0x67ba3ad2, 0xcc22ecf4, 0xedcb9d09, 0xf21fccdd, 0x1ca39ff4, 0x71578195, + 0xc0c5c4ee, 0x9b7fc267, 0x26310295, 0xdc517fed, 0xdffab67f, 0xff72a6f0, 0x557ad56a, 0x8e5ca4eb, + 0xe900b350, 0x241255f8, 0xf3b1f416, 0xb2b66a2c, 0xe70c8cb8, 0x2c4f5e67, 0xa62a4caa, 0xa0742da8, + 0xb15f0f7d, 0xa8e7f58c, 0xedfb31a7, 0x25256576, 0x2678f6a8, 0x9ed0a0e0, 0xcf7c2796, 0x1a6b5412, + 0x4a1933b8, 0x5e6cb647, 0xdbbc63af, 0x30c254a2, 0x295005e7, 0xc0864a18, 0xa52d041f, 0x0fbabd75, + 0x184ee5bb, 0x68db9436, 0xd562c099, 0x6cc4909f, 0xd7cceb5d, 0x8a477e96, 0x94795e30, 0x76222c3a, + 0xfd0cfbca, 0x8e8ce478, 0xf75f504d, 0x3b8ec122, 0x226e0e96, 0x2ea44932, 0x9391f9ec, 0xb53c6e57, + 0xd499a9da, 0x00757885, 0xd639ce71, 0x4ad49bd7, 0xfd0d97e1, 0x5a883278, 0x762836d9, 0xd815f968, + 0x5d24609a, 0x9763a77b, 0xfd92a28e, 0xfc8c5feb, 0xb0a95ce3, 0x577ad1be, 0x3424aeac, 0x8debc9ab, + 0x918ab7f7, 0x6a67af76, 0x829b21dd, 0x97e2e3f7, 0xd3755e3d, 0xc811f494, 0x3e146381, 0xf865a14f, + 0xd182703a, 0x33e44a2a, 0x68c453e1, 0xc4b67c1a, 0x619c3c90, 0xa6211f1e, 0x726b86d7, 0xb0877368, + 0x57395dc5, 0x708dcf4f, 0x9930ff46, 0x5e39ab09, 0xdc2f661c, 0xfd8ccfee, 0x74f2b477, 0x9f0a0d5d, + 0xeb03215f, 0xf428c26d, 0x62109881, 0x42d573e4, 0x8424bfe0, 0x864d9696, 0x543336df, 0x7067608e, + 0x86ee8940, 0x5a8934eb, 0x79ebc01e, 0x8edbac67, 0xfcbae656, 0x9c868211, 0x441353cc, 0x8723321a, + 0x91328678, 0x3a6416c6, 0x75e561fd, 0xc75f7490, 0x57eff9b5, 0x9ec5eb3c, 0xd475931c, 0x39cfd3fe, + 0x72428bc0, 0x4323ae4b, 0xf1270708, 0xb2b63f73, 0xac6a1fdd, 0x4cf018bc, 0x0b29bed2, 0xfb9f4b7e, + 0x636de4db, 0x3c89fb63, 0xa2ec10d4, 0x31ea4a8a, 0xc9c2311f, 0xf876b89f, 0xfce64221, 0x1dbaaf65, + 0x38855476, 0x1b4a2438, 0xf810b198, 0x13ff7d84, 0xe26c9ce9, 0x47f35b3e, 0x61f77e40, 0x3955ad4c, + 0x0d56f4ef, 0xe30f90bd, 0xb540ad5f, 0x9e527155, 0x27705f6b, 0x35e8c229, 0x1b6cfac8, 0xa0a415b3, + 0xafdee462, 0x9f6f559b, 0xdb60f7d0, 0xb8701df1, 0x233d7f3d, 0x3519502f, 0x90bf001e, 0x3afab7b5, + 0x633bbe87, 0x7328227d, 0xce726ed1, 0xb1b633a9, 0x897981b8, 0xb1ee22b2, 0xdacdeefa, 0x4d40aa2c, + 0x3c90c57e, 0xcee71414, 0xbe1ea6ad, 0x63d5b3aa, 0x3bffdef8, 0xb43b690d, 0x95b2410c, 0x9d02a075, + 0x9c7ffbe6, 0xd3ad32de, 0x7fb1de5a, 0xb16aa650, 0xe1366fc1, 0x346d7f40, 0x13e522e8, 0x9cbb2308, + 0x773c01f6, 0x94e89dc6, 0xb95edf80, 0xfbfa3a29, 0x4306a3ad, 0x660c6d50, 0xd7bb10b9, 0x3a02a96c, + 0x44d34a88, 0x1866f40d, 0xaf94bac5, 0xaa4d518c, 0xa7826495, 0xfb01a90e, 0x05a949f4, 0xc32c6e57, + 0x39466972, 0xd48c6161, 0x84762ffb, 0x9214fc65, 0x751c0aa2, 0xc691713d, 0x2819c2b6, 0xe0662e33, + 0xe96c7bd4, 0x754c8c98, 0x32b54963, 0x0c5aaaec, 0xb1cae4d1, 0x4d0a8f50, 0x33222760, 0x6d9bee16, + 0xbfaac300, 0x7df45cae, 0xb6251818, 0x925a6ea5, 0xcf0dc578, 0x81e6541a, 0x0c5ac074, 0x751ac5f4, + 0xbd795cd4, 0x1431636e, 0x25cc1f04, 0x6d6e5bc4, 0xb294a748, 0x9c12eb26, 0x30c80567, 0x7254dd68, + 0x9ed09ad2, 0x23499c3d, 0x585e1034, 0x69161969, 0x442f2524, 0xada801e0, 0x540b8864, 0xbbacc56e, + 0x6a20e2ab, 0x87c86aee, 0x6bd2e917, 0x24456fe1, 0x07a2a99c, 0xff73203e, 0x633bbaca, 0xc725c7d1, + 0xfbf887f8, 0x1cbf982a, 0x2a0dfa19, 0xfdc05fe8, 0xecf0b455, 0xae43644e, 0x088f1657, 0x3514398b, + 0xdc4c610b, 0x40734dca, 0xc3aa62dd, 0x273c3c96, 0x3a110202, 0x0b48c179, 0xc2b7bde9, 0x3352ef03, + 0x9cfa0fa2, 0x5d5de248, 0xd2b2c688, 0xd87219c3, 0x9fbfe4d4, 0x3aae3c9c, 0x84e1057f, 0x5b69f99c, + 0xc5f2cd9d, 0x882d99a0, 0x0d49e015, 0x58ba6fec, 0xbd184061, 0x82d52604, 0x269202bd, 0x7f0cd6fe, + 0x013dba28, 0xd55a1d81, 0xe4dda477, 0xe670b1fd, 0xb46e1fba, 0xafebd1ad, 0xfaa18680, 0xd8919354, + 0x5434ef0c, 0xf84d3c1e, 0xbc81b9e3, 0x7f45b778, 0x206f46de, 0xf1e5fcac, 0x8550afce, 0xcbc409c5, + 0xb9f7f41f, 0x1d78b7cf, 0x2eb56cef, 0xaddd2053, 0x618a94bf, 0x9da6f4a9, 0x0fadf3e9, 0x9ac084fb, + 0xbbfa163e, 0x30ec5a1d, 0x676120f4, 0xbe2696c7, 0x263cd728, 0x111624fa, 0x6392a0ec, 0x49a1ff31, + 0x4a6779c0, 0x2bba9aa3, 0xf27d2fce, 0x4f12b5bf, 0x32816767, 0xa116ebe1, 0x5b284fa1, 0xe1d72fc3, + 0x681c870b, 0xe37b82e6, 0x94b96e06, 0xcf747b89, 0x967ab3fe, 0xa279479f, 0x04d5bc44, 0x71b66a21, + 0xf3607822, 0xef122de6, 0xa3110de1, 0x5cff536e, 0x27f0a71c, 0x3c4e1fa5, 0x98b65cef, 0x44b359fa, + 0x186e8b40, 0xe82ef577, 0x1abc29a7, 0x372c5eff, 0xbac58eb1, 0x164284e8, 0x7d619932, 0xe6b2883c, + 0x3c983948, 0x8e7d8efb, 0x5a71a9da, 0x632ae064, 0x84a5e156, 0x1dea8937, 0x6774c212, 0x8ebc55ea, + 0xf1f469d5, 0xdad61323, 0xad03d563, 0xdca4dfb2, 0x6e627e38, 0xcec03735, 0x4a373e52, 0x4ebd610e, + 0x4aa2cbdd, 0xebbe1536, 0x5ada6774, 0x962496f4, 0x68204a70, 0xdd9ff381, 0xa75b1999, 0xca736daa, + 0x8642e020, 0x02821b2b, 0x8d4e059e, 0x9795293f, 0x743a3407, 0xb1d9172e, 0xa5cc86bb, 0x8488a60d, + 0xd82aeeaf, 0x06e65a3a, 0xdf4ea9db, 0x0f90a7d4, 0x88eedc52, 0x671ff930, 0x88ede8ae, 0x8a4c9b57, + 0x97638c70, 0xe02e7d4e, 0x7bc0dfb3, 0x92926ae6, 0x4191b005, 0x27b7b0b9, 0x3e963741, 0x47f1426e, + 0x4e8cca3e, 0xe4f9a560, 0x0ca45574, 0x80845df3, 0xa2152359, 0xf79ed0b7, 0xa50071f5, 0x5f912e1a, + 0x00485cb1, 0x77e33cd5, 0x6610ee6f, 0xbf3e9c95, 0xec1da6c6, 0x29b4caa4, 0xf72e3caa, 0xe9ec6eda, + 0xeb38c8ce, 0xde1bc82e, 0x52044a7d, 0xeadfbaf0, 0x67a28e12, 0x95c5898f, 0x4063102f, 0xa18eef91, + 0xaba8811f, 0xdecd9922, 0xe9feaeb1, 0xb0876392, 0x8eaec949, 0xd3cf9e47, 0x16f4b25c, 0xed8452bd, + 0xbe4a7e90, 0x789cdc96, 0x23091f5e, 0x5b799530, 0xe1d973e8, 0x9537a8da, 0x1017a833, 0xc14f094b, + 0x9f52956e, 0xe6ca36d8, 0x8c0be2a7, 0x6980919c, 0xadd06b0c, 0x18c0d671, 0xa95ea02b, 0xd6627da6, + 0xe92d7df6, 0x914004e3, 0xf33ca8ad, 0x9850f089, 0x44364b88, 0x231dc2f2, 0x9d56151b, 0x717303d3, + 0x495eb071, 0x17809b83, 0x5448055f, 0xf007c4b7, 0x7f453b80, 0x47308a59, 0xf6847b09, 0x5480841c, + 0x8d7b4cec, 0x0b3d277c, 0xdd98bc06, 0x4f30069e, 0x906ee712, 0xa5924cea, 0xbffd6ca4, 0x6ba7f7ba, + 0x0a5cfe1f, 0x0082764f, 0x60002c82, 0xadb1161d, 0x1a6917f9, 0xf797c602, 0x724f06b5, 0x49d619f8, + 0xb372a44a, 0x05fd3392, 0xa0c534e1, 0xee41befe, 0xb9125511, 0xde7e0b87, 0x530c5351, 0x8b65d225, + 0xd6f0584e, 0xbd188e15, 0x335cf622, 0x08ae159e, 0x96e01c6b, 0x6a1c5b9c, 0x859ed288, 0x0d61eb03, + 0x9b77b230, 0xccdc5144, 0x3fbbbbb4, 0x9b7933af, 0x20fb5c57, 0x9cd1b8bb, 0x95b8936f, 0xf3fbaf45, + 0xfd8e97b1, 0xa100005b, 0x40534ba8, 0x2b0ebdd3, 0xe1e152e7, 0xa42500c5, 0xd8c843c1, 0x770e39d9, + 0x997ffe7e, 0x5c5d7f81, 0x7af44434, 0xfbb8840c, 0xddc7fb07, 0x4f2ed813, 0xb0945518, 0x127f088c, + 0x4a77a352, 0x32fa3ef1, 0x6e2731ed, 0x927a8fb3, 0xcb73e9f0, 0x2112bf56, 0xdee8bab5, 0xea9c2a54, + 0x7383f2c3, 0xe0e23e73, 0x4e31bfda, 0xc8c2e297, 0xcd463944, 0x12151a38, 0x2f8c3c39, 0xa3787003, + 0x38ad1d1c, 0xff2ff25a, 0x22d7bd48, 0x312a0393, 0xf05b7acb, 0xa8d24fbb, 0xd9c762c1, 0x91579edc, + 0x8306499b, 0x862d709c, 0xaa07f456, 0xf34fbcc5, 0x2d300b12, 0x1e31b640, 0xdb9d98dc, 0xa2996f53, + 0x0bd54b5b, 0xef39b31c, 0xdef7114f, 0x99567ed6, 0x7455aaa5, 0x0156885b, 0xa43dcecf, 0x8116999b, + 0x8797267d, 0x68fc4363, 0x1a667458, 0x37851a26, 0x038eb314, 0x4e12351a, 0xfad04831, 0x65556c8a, + 0xa276eb7d, 0x221a47e3, 0xbf99df80, 0x452c9b84, 0x50d24cfd, 0x5c55e2e4, 0xed790e83, 0x0a8a29f4, + 0xe74c118b, 0xa568068c, 0xfa794b1c, 0xf8428938, 0x494f4038, 0xe29a876a, 0x14cbae58, 0x30f997a8, + 0x749c8622, 0xb850d24e, 0x0d77c443, 0xda614cfe, 0x42ae4bb2, 0xcc97c4b6, 0x09f50da7, 0xb5f0d138, + 0x133c2260, 0x79275106, 0x8d7333f6, 0x85a57111, 0xfd9df06b, 0xbeecdf7a, 0xb99d9d7a, 0x29d66c34, + 0xf2076bca, 0x7bd5bd3b, 0xe9e74c26, 0xad76cd37, 0x523db01c, 0x62f1c17f, 0xdd947244, 0x058701a0, + 0x4c232bf4, 0x666f3d13, 0xc0dea168, 0x8ceb69fd, 0xd988be4f, 0x60388c06, 0x160e0e5d, 0xd393469b, + 0xb869b64d, 0x3af1cc6f, 0xa7c8355b, 0x3421d281, 0x525d852f, 0x136a89b6, 0x64c4c060, 0x7e7fdf7a, + 0x30cbad27, 0xd8bb1ce6, 0x58a63e77, 0xae106afe, 0x32c599ae, 0x4a1a13fb, 0x8ad23389, 0xd50139e0, + 0x5ea899df, 0xf991b604, 0x4b1258ce, 0xa7d8e54a, 0x2a80e1d7, 0xd497d40f, 0xa948af04, 0x7a540bb1, + 0x1585ebd8, 0x4b03a13d, 0xee90e1e3, 0x45110600, 0x84799c83, 0xc65c041f, 0x42e4f417, 0x8711f081, + 0x9dac682f, 0xb1e7fba7, 0x93611644, 0x0f2bd734, 0xc9c8ae39, 0x41e8e420, 0xbd7b6a2e, 0x8d96183d, + 0x2b5df7fc, 0x661740a1, 0xbfd122c4, 0x80dd2e7c, 0x7af6a329, 0x49683301, 0x4d52941a, 0xda838e2b, + 0x15b3be74, 0xc938f8e7, 0xff8545f0, 0x87376392, 0x1bff863c, 0x6bfd765b, 0xfd50b766, 0x3e51fa26, + 0x98612ead, 0x1951d510, 0x8fb5f047, 0x718d04dd, 0x89322783, 0xd56a1721, 0x21ee02fe, 0x6474228f, + 0x6857ca71, 0xbbeb0c02, 0x61f786c4, 0x624f9ec4, 0x155f7b71, 0xd55ee994, 0x4eae634e, 0xa2424091, + 0x524b51d7, 0x263a6a97, 0xde112894, 0x66f967b5, 0xdadff699, 0xa946599a, 0xe5b39200, 0xe8186c5a, + 0xb7afd766, 0x9e6061e8, 0x5e3e9919, 0xc2e9b107, 0x9af9f4a9, 0x0c4c2c63, 0x543ebf6f, 0x356a9974, + 0x9bd0bb5d, 0x2b4e659e, 0x10ddce1a, 0xdc22e0cd, 0x94457077, 0x88f46728, 0xd8eb519c, 0xb334d8ed, + 0x2f0cd35f, 0xfb419d4c, 0x7d3ee4f0, 0x9adc13fa, 0xea5b4ce8, 0x5efd7747, 0x199073db, 0x0bda737a, + 0x020a219b, 0x8f4139d9, 0x045ecbbc, 0x4d02328b, 0xdd6b6fce, 0x7f92a0a4, 0xbe008d42, 0x5b20b09a, + 0x5b207134, 0x43fec235, 0x98232385, 0x9e76cbaa, 0xb8e3af49, 0x4d75f57b, 0x26aa557f, 0x1893e035, + 0xc69410ce, 0x89a065e8, 0x65ccfaea, 0x836de641, 0x4ebf1467, 0xf5fe0946, 0x8e09c8d9, 0xb40a97ad, + 0x09cb4bd5, 0x333ec30b, 0x880df904, 0xb103f967, 0x39280bc8, 0x15bb06bd, 0xb85a44ee, 0x1a7d85d2, + 0xa61dc525, 0x6990c04d, 0xe55bfbb7, 0x130a0069, 0x3f130857, 0xdd48e953, 0x9b7f7d2f, 0x4c2bf7e8, + 0x6173982a, 0x987834c7, 0xd8bd1895, 0xc4d38091, 0x092c9d6c, 0x683e437b, 0x3e44c806, 0x14efd499, + 0x02a7eda9, 0xf873ac52, 0x4fba9783, 0xe9c747c9, 0xdf5f018a, 0xbd61cc70, 0x2823d3fd, 0xe49b6723, + 0x4d5d20a2, 0x79127e71, 0xbd1a4641, 0x78b9296c, 0x42c81069, 0xe434c4cb, 0xc65f2aef, 0x0b04a9ae, + 0x45a4a055, 0x67fa6aaf, 0x35421349, 0xc9d2b054, 0xaf0b6baf, 0x68b683a1, 0xaf4f7bc1, 0xf051553d, + 0x45ed4540, 0xa6f01cad, 0x9249ea63, 0x1ef9ec29, 0xe9979a95, 0xb0f92d6d, 0xbcaa8877, 0x109ca78f, + 0x06629770, 0xc892115e, 0x028342ea, 0x821b6552, 0x134317fe, 0x85d37187, 0x49b4b91c, 0xfcffab17, + 0xc4cf8010, 0x0098cba4, 0x475835f2, 0x7010318d, 0x011a98e5, 0xa9bbec9e, 0x21a19068, 0x12bee8e7, + 0x3112be58, 0x10f3d06d, 0x2bbe23a6, 0xfa2b3e6b, 0x5c674161, 0x11fca1b2, 0xf75c5753, 0xe5e1452a, + 0xa808254b, 0x90045031, 0xc873bb21, 0x88f04fb1, 0xb6fff5d2, 0x6755c471, 0x45051115, 0xde6d5cff, + 0x876d9081, 0xbe7c8db3, 0x905bc9d6, 0x202674d0, 0xb460f490, 0xbf979b96, 0xa35ad5d4, 0x80497d25, + 0xb2301552, 0x71ce6e79, 0xdf29308a, 0x7fe3862f, 0xf0586a3e, 0x925997b7, 0xf8a97b9b, 0xd460bc43, + 0x6d32d0e2, 0x76a18d1d, 0x468b5a99, 0xd0dfdb31, 0xfe7ec43a, 0x06011ab8, 0x9c491381, 0x86eca4a3, + 0x7eec5d03, 0x5c45aa05, 0x78cdac84, 0xf9487fa8, 0xd96038a7, 0x29f445b9, 0xafa32457, 0xebb8f54a, + 0x3eb7fd25, 0xce0308c1, 0x13bac26b, 0x7ae77f38, 0x164eaf3a, 0xb8440654, 0x9e586e6b, 0x5eb871ce, + 0x7455c8d1, 0xb0da55d9, 0xff2dd15e, 0x15366d47, 0xe0c77af2, 0x1f8d7402, 0xd4680661, 0x696dd7a4, + 0x45de810e, 0xc917cf92, 0xe22cd6dc, 0xa21e89fe, 0x7e465cf1, 0x779c5ce2, 0xe5efbf11, 0x3d5fe9d4, + 0x26c4bc22, 0xed893ac4, 0xc9be0e2b, 0xc65859ea, 0x1b7d31e2, 0x7ad2756c, 0x084a7cf1, 0xb9cf5255, + 0x108d4cea, 0x8634e5f1, 0x8aad39f1, 0xe8926f85, 0x68eb1a3d, 0x9cabcbc1, 0x6c9b93d6, 0xd24c7ac2, + 0xa30f14f0, 0xf5b1c8ed, 0xb3a2b275, 0xaa5aca53, 0x3082dfd7, 0xd86a5f76, 0x97f872cf, 0x59e918dc, + 0x6d6f9e37, 0xb8e64b71, 0x6246f317, 0x57fb27d1, 0xfb0ad5f0, 0xa3606b84, 0x847a0558, 0xb7df9110, + 0x42bd777f, 0x2d7cdc21, 0x76074581, 0x18f8f5e4, 0x3ec147e5, 0x139a4e99, 0xc56ea3ad, 0xcfbc3f08, + 0xa44c494d, 0x84c799ce, 0x45dd4631, 0xc8d1f945, 0xecddf94d, 0xa6892c4f, 0x621132ac, 0x0a928bda, + 0xd7b1ce7b, 0x3c44cec8, 0x2225b80b, 0xe25d55e9, 0x38fe15b9, 0x6a5bddba, 0x2c904f5d, 0x7840ed50, + 0xac5fdcda, 0xbd49667a, 0xf356b5cc, 0x125f83c5, 0x6b5efb0c, 0xbe630a35, 0x39098ad2, 0x62e812c7, + 0x0f8383aa, 0x41f539ad, 0x8a28bf8d, 0x11a6c810, 0x61eb1675, 0x6f640e33, 0xe72b122f, 0x7ca5080f, + 0x38bdfe15, 0x489a7e70, 0x405c14e7, 0x4d21644a, 0xa8ca3a7f, 0x307fb5df, 0x9f238e58, 0x6a82b64f, + 0x2e4b6c9d, 0x249243b5, 0x7470312e, 0x1b6e6838, 0x4eeca02b, 0x33a97660, 0x6015d2f6, 0x5132ee99, + 0xc955ac44, 0x526fabba, 0xd74973d4, 0xf7a30607, 0x26754075, 0xdefbc7fb, 0xe66cad58, 0x54555b13, + 0xe1804906, 0x0de44133, 0x6eebc61d, 0x05c24d23, 0x45ba8e99, 0xab12d486, 0x3d7c44eb, 0x63d7c352, + 0x1e9cde05, 0x8b4d996c, 0xd9a47c63, 0x53588114, 0xebe6c77b, 0x3ae3468a, 0xb0d7ff76, 0x6ff0931e, + 0x51edf444, 0x21d1899a, 0x3377bd7d, 0xa09bddb5, 0x3331ade7, 0x11deba1d, 0x55332dfc, 0xec2f7de7, + 0xb8b4fb24, 0x957b883e, 0xf3237c44, 0xbd961c6a, 0xa1ebd578, 0x9162768a, 0xf06bed7b, 0x8452c3aa, + 0x19064889, 0x1d27ec23, 0xb73f2213, 0xc289886e, 0x4fd818c3, 0x055095e9, 0x6d3c74d4, 0x9267686e, + 0x714ad5e2, 0xf56cc39a, 0xb8fa364f, 0x782926ec, 0x39b34ebd, 0x9d161517, 0xc734d812, 0xef890d85, + 0x182a746c, 0x7a4658c2, 0xc84944ac, 0xe650b446, 0xccdedae5, 0xe6e5b488, 0x5082c9e5, 0x3da5d780, + 0x7a776ea6, 0x8df209ad, 0x3de64909, 0x07f15410, 0xa8aed575, 0xf7ae6791, 0xa40e2fc2, 0x1904f478, + 0xfed35bdb, 0x5b9ab8a8, 0x9b9935da, 0xf57b659a, 0xfde51d3e, 0x3fe9440f, 0x5175844d, 0x425690d3, + 0x987becd4, 0x90f55b92, 0x888187ce, 0x26ba6d89, 0xda7d4a0f, 0xdea258a6, 0x854483d9, 0xb86a035a, + 0x93369358, 0x99b562f5, 0xb4f21df0, 0xfda3f940, 0xceec788e, 0xff33cdce, 0x750df73d, 0x66282614, + 0xbd0cac8d, 0x0c6644d7, 0xa283895d, 0x34d1dab7, 0xc44b3e7f, 0xedc33076, 0x1c884407, 0x2be04d69, + 0xd79dc9df, 0x12c14122, 0xc6e14a7d, 0x1a125a83, 0x63cdcea2, 0x9181f707, 0xd61faa63, 0x7d1a5d20, + 0x0037e621, 0xd129f9dd, 0xcbb150ef, 0xbef5dcf9, 0x815fd02a, 0x5796cd6c, 0xb86c82fd, 0x7ebb9e0f, + 0x82c5cc4e, 0xae141911, 0x032dd5d9, 0x55128cde, 0x2e879e05, 0x46c94759, 0xbd0ae6c5, 0x5739be9f, + 0x242d3183, 0xa8f80c87, 0x680e060b, 0x76343cb6, 0x07dbaa2a, 0x73803969, 0xf7b6732f, 0x6ff9ca6b, + 0xdb13c665, 0x5bd5f8f9, 0x3e77e877, 0x8e5f3038, 0xf34ff543, 0xaf6f7c5d, 0xfceb2d9e, 0x5cb23e8b, + 0xcaa76ad7, 0x19bf92bd, 0x820193ec, 0xaef0e794, 0xd670653e, 0x797cdfd8, 0x77ae76a0, 0x36daf0a2, + 0xd65aa93f, 0x4f7f9ae6, 0xb6646ee7, 0x5c632523, 0xa92a4df7, 0x4eab9f86, 0x2e526d52, 0x4058573a, + 0x7111dc13, 0xa7d34046, 0xf4552bb2, 0x5f7f43ce, 0x9bb75ee6, 0x53684e04, 0x4f6774e3, 0x9e5f324d, + 0xcfec7ee4, 0x32ad1b20, 0xeda96c59, 0xacba3c16, 0x578c6bc0, 0x4acb3427, 0xfa5c4504, 0x6e4027f2, + 0x04806994, 0xfcad5b39, 0x51864c75, 0xe1f0726d, 0xa2440218, 0x3044bee9, 0xe82b8a94, 0xceeb6d15, + 0xa0d4c97d, 0xa573c660, 0x0de0ff82, 0x9f524717, 0x00f3612d, 0x9a6945df, 0x23fd78b6, 0x7491ecc6, + 0x2d4cd0e2, 0xa9358bd4, 0x4df062e9, 0x0a8a5002, 0x62e9dfe1, 0xca5ee060, 0x7bd45fba, 0x29f648de, + 0xd676c3db, 0x46425963, 0xafb0a1e2, 0x10c227d3, 0x406cfa67, 0x7cd71a6c, 0x0a541435, 0x3368aca1, + 0x126114d0, 0x09b4469c, 0x27111648, 0x3ec873e9, 0x5002baa6, 0x950b5e82, 0x910a534f, 0xf209fb3c, + 0x963523a9, 0x91c2b624, 0x78eb06ec, 0x2380d303, 0xc25d9779, 0xb9b8e820, 0x0faeffe9, 0x3e77c0c3, + 0xaafe82c4, 0xf81aa550, 0xe6034627, 0x0012ea78, 0xb28ea468, 0x34184016, 0x690c2eb1, 0x9f15ec36, + 0x1487352b, 0xed1230fd, 0x622ded1f, 0x2df0aeeb, 0x9d3433bb, 0x3a0ed4d5, 0xf02e90c2, 0xf9f5085b, + 0xe593a286, 0x957f363d, 0x34125431, 0x6a76bfbe, 0x4824e960, 0xcedbc9f4, 0xcbe04138, 0x834486f4, + 0xfce9524f, 0xc89c25ec, 0x7fd447a7, 0x06fd7ee7, 0xa7cdf94a, 0x373beeca, 0x3e181664, 0x88f6f7c8, + 0x73a66984, 0xc86ab3a9, 0xb50b9c36, 0x3f39a742, 0xf1fc530f, 0xb50059d9, 0xcf01462c, 0x137d8d0d, + 0x61357c05, 0x45d31117, 0xdfc3b25f, 0x352a66b9, 0xf2feb8f5, 0x5b542d83, 0xe4082cb6, 0x3d24a577, + 0x4ef24b0b, 0x88226413, 0x5b04ea63, 0x1633a692, 0xac85c4c3, 0xc0987070, 0xab367ffb, 0x3133d89f, + 0x63119e49, 0x61038048, 0x9f7b6fb0, 0xb27a6230, 0xb862e78d, 0x9373584c, 0xdce381ea, 0x4776b130, + 0xae0e9a35, 0xf1218972, 0x7893e0f8, 0xd9b27d66, 0x4a846d44, 0xaa097218, 0xb961f323, 0x5a75e3a2, + 0xa2385168, 0xc1aa4f39, 0xc1b0a2b3, 0x3986ca0b, 0xc2871c23, 0x7a2d8552, 0xef91bdc9, 0x9c33ee17, + 0x60418aeb, 0x62587bdd, 0x44bd971b, 0xba71fad0, 0x0b14be15, 0x8f507de2, 0x81079443, 0xab9962e5, + 0x0b708c73, 0x98b90816, 0x51420be0, 0xf9b89b07, 0xbb327b80, 0x7127d3b1, 0xee93540b, 0x7237c69a, + 0x85207bc1, 0xe1fd58db, 0xb1d3ae1a, 0xce1a36af, 0xe8c527ab, 0x15b709dd, 0x8fcf8c28, 0x3cc77644, + 0x61b9c636, 0x010b17af, 0x365ff8dd, 0x64d6e98c, 0xe0eda0df, 0x6fc26f88, 0xf8dac1ad, 0xc1e74f14, + 0x4cea0510, 0xed70c1ab, 0x3a4bb95d, 0x994e3ce5, 0x4c0cfc49, 0x532e221f, 0xa8b412b0, 0x6958b599, + 0xe64f4ea2, 0xd169a1b3, 0xc8e4eaa6, 0x9afa6cef, 0x28d2db03, 0x1e741808, 0xe11daf2e, 0x3caa176f, + 0x4eea11ae, 0x6609fb56, 0xe585006a, 0x0c13c881, 0x5c465d96, 0x5788b7fd, 0x67fcb871, 0x70920110, + 0x76b17b67, 0x2854d1db, 0x64be5527, 0x3c5a3cbc, 0x840cdf07, 0x81e5063e, 0x9e5a16f3, 0x6a4c501c, + 0xe9c318b4, 0x09b5563a, 0x58f490ec, 0xe19b5427, 0x6ae8845b, 0xd28b008c, 0xab530a72, 0xb09cf800, + 0x5d16b7c8, 0x52854f1f, 0x1808b920, 0xdc8f6820, 0x53c050fe, 0x48fe1f2e, 0x864d47e7, 0xc0fd5bf9, + 0xa9f1ec11, 0xa04b0528, 0x19265ffd, 0x48e0dbad, 0xcc16455f, 0x3c6bcf30, 0xe33db7b2, 0x157ee6a8, + 0xec8f99eb, 0x96a6eae2, 0x4f9a1a13, 0xde97e82c, 0xd8ba5e8b, 0xc7d80bec, 0xbbba27e1, 0x53eddc88, + 0xd731c02b, 0x6c3e801a, 0x35d37950, 0x368a40af, 0xb9b689fa, 0x3d28fe74, 0x72354f15, 0x9a5e586c, + 0x47d40b39, 0xdd1b7cd7, 0xb6f8c602, 0xa21f4374, 0xd2da98fb, 0x18c69e1e, 0x7d79e2eb, 0x5cfc00f1, + 0x6d869f28, 0x9485700a, 0x2f2352f0, 0x6af2aead, 0x92236b86, 0x90210ca1, 0xcd874dd0, 0x4f4e5106, + 0x352bee65, 0x39291fa4, 0x5a4aed4f, 0xd511178d, 0xa90f6921, 0x49eab217, 0x95951f5c, 0x809eacb4, + 0x3cc11a36, 0xdbe7faf9, 0x5facd68e, 0x3c6d7c68, 0x965daf7a, 0xdd1e399a, 0xf5745477, 0x2c77f8ab, + 0xac06f22a, 0xbe656d6b, 0xb7701795, 0xacd91585, 0x6438c244, 0xf9cef518, 0xbaf237ea, 0xcdc46b01, + 0xab349bd4, 0xca03dafa, 0x6d8272ed, 0x038deba5, 0x9e245fd8, 0x3569e15a, 0x572c0fcb, 0xec18da7c, + 0x83223d27, 0xc756e751, 0xa44499a9, 0x80bf3bf9, 0x680a4dcb, 0x91d797e0, 0x74e06036, 0x1d3124d2, + 0xfb69f8df, 0x275233b1, 0x7a0bf807, 0xfd8ba3ee, 0xe1c9fd0e, 0x051f910a, 0xa1c6e8e8, 0x1069bd48, + 0x15cb9aaf, 0x4b8f3393, 0xa880166a, 0x2cb093c5, 0xc06eb4f2, 0x48dfd750, 0x3b5f9c74, 0xa71bf5d4, + 0x04061f24, 0x1f8463b2, 0x6a04c4c3, 0x276ffe50, 0xd5b3f3f7, 0xdbc7e337, 0x91181951, 0x39e2d1b9, + 0x57d47261, 0x7ef12b17, 0x378b21b2, 0x1f468806, 0x0690fd6b, 0x3fa8c325, 0xa325dcf6, 0xddebe04e, + 0xf29eec8c, 0xb7261e36, 0x46e0281b, 0x528d06fc, 0x5293c2a6, 0x1a443036, 0xdcd7a1f6, 0x28e03f4f, + 0x9524cd8a, 0xd2104700, 0x7fbda361, 0x4bab60e9, 0xca709509, 0xb98eb1b4, 0xf26e001d, 0xff7cc717, + 0xa61a2f25, 0x40914f48, 0xd8d5582e, 0x7e3ebe76, 0xefebd2ca, 0x2b769a6d, 0x884cb75f, 0xf48ff3df, + 0x27f7042e, 0x606b4473, 0x0377d133, 0xfed70b52, 0x5a07c188, 0x225f12ce, 0x64ca2755, 0xc01ddc43, + 0xb677dd47, 0xc3af0791, 0x46ded4a4, 0xd8f6f794, 0x429bf506, 0xbc2ac925, 0x96977ed0, 0xba65478a, + 0x0e77a3b6, 0xcecf5a1a, 0x992d09e4, 0x3a1e88d5, 0xc4afd3b2, 0x7bbd8285, 0x078ce107, 0xba434bd1, + 0x67283d40, 0xd2c978e5, 0xd41e060e, 0xdc6a3ff4, 0x924a206c, 0xbe3d753e, 0x0eb9dcb5, 0x76c267fc, + 0xe4d59e81, 0x218daeda, 0xb81fa002, 0x348c1d9a, 0xcb60b9ed, 0xe252ea8a, 0xe843df83, 0xef0ddad8, + 0x660d5da5, 0x4e6b9203, 0x61654f77, 0xc2f60afb, 0xfbc23f31, 0xd0086488, 0xab56758d, 0xca38aae2, + 0x47cf1751, 0xe88945c7, 0x297021f6, 0xe760c4c1, 0x06555f3d, 0x15e93009, 0xfe8e5f84, 0x3630cf19, + 0x21222110, 0x4f56d4bd, 0x07cf1d7d, 0x8143d9a8, 0x0a9b056b, 0x552ab8c9, 0x214dd35e, 0xab7ade10, + 0xb107f9e0, 0x7924a743, 0xb9b7f8a3, 0x49d93d70, 0x1c51f393, 0x53935c99, 0x2b37cac1, 0x41e7ca27, + 0x500bdcf9, 0x142da7db, 0xc25c6b90, 0xb122cc15, 0xcfcf4119, 0xd1f17e61, 0xdbc86951, 0xa4128e95, + 0x68dc747f, 0x3bb2787c, 0xb289191f, 0xda978505, 0x8da49d81, 0xf44e8a1b, 0xb74964ab, 0x7d42324b, + 0x07eca455, 0x540d04cf, 0x86769772, 0x2844e0fc, 0xbe7c0c79, 0x0c617607, 0xa3cbf34d, 0x8dec48fe, + 0xfdd0c880, 0x59b17890, 0x6da6b0b1, 0x5e8fd3af, 0x07b28cef, 0x4260d9fb, 0x545de67f, 0xcc22ef80, + 0x4bcb2b73, 0x30974c91, 0x48b326c2, 0x4b9b8e9b, 0x4f15f58d, 0x544b1078, 0xb8daa653, 0x0fb84063, + 0xa1e41bb8, 0x8d999d01, 0x7c4b8c9a, 0x3fe7eb05, 0x35d601e2, 0x7971570a, 0x70428ae2, 0x3e19eca1, + 0xb39949d7, 0x45b4d480, 0x8deccfc8, 0xbd6a244c, 0x70f99c2e, 0xdc3584c7, 0xc6521b0e, 0x3931225a, + 0x22d1fab6, 0x20539ed6, 0x7d2f2631, 0x39d783cf, 0x7eed131c, 0x50d3ccee, 0x71223a82, 0xec4e2b34, + 0x59afd29e, 0xacbcfd18, 0x943386c4, 0x2d300adf, 0xf0c435e7, 0x281ecb7b, 0x8a13b4cd, 0x72ce4ecb, + 0x4f44c35f, 0x8fa06bc8, 0x8263129e, 0xd909959b, 0x66638066, 0xba798395, 0xc357b81c, 0x1e482f07, + 0x9e2628db, 0x4149d059, 0x66769e5d, 0x609c4289, 0xf2bfa6e5, 0x663deb9b, 0xc699aaf9, 0xc625ebb9, + 0x624e8f81, 0x4e95f0ec, 0xb7fb4808, 0xe1af70b2, 0x1e35a3f7, 0x0b0a4332, 0xfbada0ff, 0xdb162202, + 0x93d48a56, 0x454df552, 0x94eebdc7, 0xe763522d, 0x25aedc0e, 0xf9d0debc, 0xc24188cd, 0x8e414da5, + 0xc28a3f65, 0x2e522a0a, 0x373d728c, 0x79fb0a5d, 0x62fe3ac1, 0x8cce163f, 0xd5ca237f, 0x8248ffef, + 0x54588537, 0x8d8174c9, 0xe5f1369c, 0x485c7576, 0x178fe208, 0x67bd5a68, 0x5e722c73, 0x444329b8, + 0x2199f717, 0x89e8d376, 0xfb96d5aa, 0xc6c50356, 0x6f68994a, 0x860462ff, 0xf9d65e51, 0x1d57af52, + 0xbc8cfa36, 0xf6dccfdd, 0x2d245ec9, 0xcaf4cd30, 0xbe18f1ed, 0xffe0a876, 0x527e921f, 0x4e06694c, + 0x730ff845, 0xfe496503, 0x8c3fcf5a, 0x583d9e1e, 0x1efd0479, 0xf5a5dced, 0x63b6e98b, 0x5b1ca33b, + 0x360ee6cd, 0x9740252f, 0x42be244a, 0x70529f99, 0xb3fa2c12, 0xc3725399, 0x2a7e31cc, 0x1e3c63bf, + 0x4ac4d3e8, 0x40377f76, 0x7f4624a7, 0x53ebb138, 0x6bac404c, 0x8c8128c1, 0x8f2b247f, 0x7dd94f41, + 0x1204469f, 0xbeb1ed87, 0xbf122450, 0xe032b822, 0xf58459ae, 0xad825c46, 0x8b7fbb42, 0x9f327924, + 0x90477b65, 0xf4e8d1df, 0xb2a40e14, 0xfe56a996, 0x258a5496, 0x25c63c60, 0x1826162f, 0x4295e071, + 0x14552388, 0x12337633, 0x139ff63d, 0xccdd5960, 0x6d840d15, 0x5878ac4d, 0x8294960d, 0x6814488a, + 0x613ed428, 0x13e5fb7d, 0x30302178, 0xeafcc6b2, 0x2c18ee8c, 0xd72dffca, 0xc41b2e30, 0x492ecb24, + 0xf57087e4, 0xe4d08d93, 0xc365f387, 0x71597fc4, 0x525f4a58, 0x686ce3b3, 0x19211ba1, 0xee350a0f, + 0x7d15a90f, 0xa7b4dae6, 0x461e68ad, 0xaca67e67, 0xe33a11ab, 0x100af7b4, 0xbb0093c4, 0xe7eb5e7a, + 0xbd0687bd, 0x97493abc, 0x28b51c98, 0x496d28af, 0xf1f126ba, 0x8eaf851c, 0x3d39e4e5, 0x90d6557c, + 0x5d4e688d, 0x1d43196c, 0xb72dc427, 0xb3ca423f, 0xaf2ca8b4, 0xbb899c83, 0x36498a7c, 0xdb892a9d, + 0x3dc47508, 0x199c034b, 0x346b98e3, 0x21624332, 0xc38821cc, 0x92c908d4, 0x9e690793, 0xcdb7dcfa, + 0xc852030b, 0xf1ebb2d2, 0xa7853665, 0x65c97de9, 0x9ddc3cf5, 0x999cf8c3, 0x996c5533, 0x657d3406, + 0x8d70f33e, 0x99ffa7da, 0xbbd69c22, 0xd44c47f6, 0xb308f210, 0x8f3e9bf0, 0x50c7a8cb, 0xe7fce5eb, + 0x25bbab29, 0x8b42aaa7, 0x9acc4857, 0xa39aa2f9, 0x792328f8, 0xe4bedd5c, 0xabf73140, 0x0d9ffb66, + 0xddf92d05, 0xdf9a4f1d, 0xf0b797eb, 0xf5367a97, 0xba18d064, 0xa154f072, 0xc3942802, 0x05b90b1a, + 0x987b5a1a, 0xe1c7ced2, 0x78b88aa8, 0x1b158deb, 0xc186b784, 0x00a536a0, 0x713e492f, 0x51399796, + 0x015d2f15, 0xc9488b9f, 0x35f3cf94, 0x3040a9e7, 0xdf61aa86, 0xcdb370bf, 0x5877fcbe, 0x521ec49d, + 0x38b88e4a, 0xf197d859, 0xab2e87a5, 0x36deab38, 0xc183e950, 0xd1faeb16, 0xc86e353b, 0x5923d314, + 0xfccb277c, 0x8cab953e, 0xc733be4b, 0x6f0b622a, 0x4779e76f, 0x1f7d14fc, 0x2d858fcc, 0x01d4523d, + 0x2ec2f543, 0xec948382, 0x0e43545d, 0xacd4247c, 0xb7c5039f, 0x34d428ae, 0xea8dab6c, 0xd0fec8ae, + 0xa6884868, 0x2127e8d4, 0x83316365, 0xf017f8c6, 0x9740d808, 0x3f1ac47f, 0x30af45c7, 0xff35b225, + 0x4ed10fca, 0x5b9a0039, 0xf6b6713f, 0x022bf7f3, 0x1cb8efe9, 0xd907c7f2, 0xb2f88adb, 0xdbdf6b14, + 0x45621782, 0x04482fe8, 0x784691c9, 0xc6c237c6, 0x6af6a606, 0xc3bb6350, 0x0ac36333, 0xdea137ff, + 0x02cef1d3, 0xa8cde20c, 0x24d58700, 0x32a7c36d, 0x69de39f9, 0xa802f76a, 0x9ebb3e54, 0xdd95c540, + 0xd06344e1, 0xe9019e67, 0x516b31a7, 0xceaaa8f5, 0xf43e0148, 0xffdb7084, 0x83777ed4, 0x320fbf94, + 0xc62135b8, 0x64887d4a, 0x2037b18b, 0x79cc6764, 0x6ff3e511, 0x46d5cd22, 0xe39e7281, 0x079b74ed, + 0xe8a05b8b, 0xab7b782c, 0x2ad10867, 0xbbb25373, 0x9aea8272, 0xf7412e18, 0x865873ea, 0xa8cccea7, + 0x6cc7d41e, 0x3d292afb, 0xf02d9a89, 0x7b7ab353, 0x80c5eb7c, 0x4b77547d, 0xece7b1cd, 0xe326e664, + 0x2cfc714d, 0xf7fccecc, 0xbdfdc3c9, 0x827bed5d, 0xa5c71720, 0x419a44a1, 0xa11dbefa, 0x15c27de4, + 0xf386d4d7, 0xb42b526e, 0x167ce79d, 0x1b2ed281, 0xc72425fb, 0xd25f77f1, 0x366e26a0, 0x98352a1a, + 0x6d352460, 0xaadf1f7e, 0xcda0692f, 0xfab2e8e7, 0x02083115, 0xce032434, 0x8d3b614e, 0x600735bf, + 0x558a61a8, 0x2af4aeaa, 0x4dc78171, 0x147c6f42, 0xfb8ccc06, 0x69f41ad3, 0xad74e609, 0xe6f13754, + 0x1e4fcb55, 0x98983efd, 0xf3f10476, 0x6978ddb5, 0xbb28c16e, 0x3d6f5c8e, 0x0bd5d24d, 0x73eea7f6, + 0xdfa1b60a, 0x12db54d7, 0x1f2af651, 0x6b2f43b4, 0x8db6e923, 0xa76ee861, 0x8f830fab, 0x4c9dc7c3, + 0xfaaada95, 0xdd5507a2, 0xea2dc813, 0x147cc3a2, 0x861974a9, 0x8dab0d44, 0x8214cd88, 0x5cf83ff7, + 0x0a3d7f37, 0x60f9a3aa, 0x5731eb49, 0x22a371cc, 0xa565de44, 0x022e88d7, 0x86369497, 0x115c7eda, + 0x975807a6, 0x917b08cf, 0x99775799, 0x288bfd69, 0xc94ec722, 0x03f03903, 0x6fcf82cc, 0xaf96fa2a, + 0xdaea2062, 0xccf0b430, 0x2d038b14, 0xe925cb22, 0x90c11bc4, 0xb039f1dc, 0xa7ac221c, 0x5aeda323, + 0xe383376c, 0xb7ef11dc, 0x9aa23aa4, 0x11d66a5c, 0xf255b9fa, 0x438a3b0c, 0x0a48ab98, 0xc465cc60, + 0x6b946969, 0x531aba0e, 0x43a2bfc0, 0x79006cf1, 0xdf387153, 0x6e82e56b, 0x74da9479, 0xf070f7fc, + 0x625b2cf1, 0x1441391f, 0xc3c7f3d5, 0x475f5a81, 0x197a43e3, 0x1019256b, 0xb58d13c5, 0xfcfbf80d, + 0x217dd7db, 0x98165a68, 0x2a3ab24d, 0x0259710b, 0xf714a6c2, 0x1b9b149a, 0xf73f87f3, 0xc584f80a, + 0xd16dc5b4, 0x5ac53caf, 0x735b1e60, 0x90b6db76, 0x470e7fe1, 0x8fc4a2b4, 0xb7b479a6, 0x7a1a8a3e, + 0x0e7eaba2, 0x25397e78, 0x6c072732, 0x4cfe9c48, 0xfa4016c1, 0xf24db278, 0x37b0f0cc, 0xa8cd5a33, + 0x2c17c900, 0x59fcef85, 0x5cc03dd3, 0x84822b74, 0x263dc428, 0x573175f3, 0x08b11300, 0x2056dc21, + 0x8d850e6f, 0x394ab4a8, 0xd250e2b4, 0x1e7aa8a2, 0x7800e492, 0xc3f3dd9d, 0x60b9d116, 0x98d4e061, + 0xe17e4a2d, 0x1c44786a, 0xc5749a7d, 0xac5cc3de, 0x08cacd98, 0xa0d34407, 0x8618600f, 0xb5d2cb6b, + 0xa95fb0c3, 0xf310e303, 0x1783f199, 0xc5096dd9, 0xd9b43e2b, 0xb26097fc, 0xebc66e11, 0x1e62580d, + 0x2b8ff740, 0xa700bea9, 0xd04a54df, 0x0c6f5a26, 0x7595cbad, 0x05bfc150, 0x504c177b, 0xe1cd306d, + 0xfbb31b8f, 0x24e54d36, 0x20fe8f06, 0x45b5112a, 0x04ba1bee, 0x0d69000b, 0x23ad57f5, 0xe97e4a53, + 0x9be4456b, 0x6681cc43, 0x691806d3, 0x43ed3f38, 0x5c3e21d2, 0x4c6d0f46, 0x48bda0b2, 0x8fc7ee09, + 0xbb2e05f9, 0x1c962473, 0x759850cf, 0x00883d52, 0xaa6ed46d, 0x1b32cdac, 0xcbe3ae7a, 0x729196db, + 0x1b96ed2a, 0x75d2fe57, 0xdbf5ebe6, 0x5b01ab48, 0xafd80e44, 0xd5fd2b5b, 0x48cb9563, 0x7ba33ad4, + 0xe4093f84, 0x597860e4, 0xea0463c5, 0xfbdc68c0, 0xbdca3fdf, 0x74f65d4c, 0xd122f78d, 0x57562049, + 0x430447fc, 0x0769aa47, 0xa2887592, 0xa5b17386, 0xc7a5a00d, 0x8a42d5a3, 0xea679066, 0x485e516e, + 0x9506c190, 0x7766fdfb, 0x4f9a2af2, 0x3c2263c7, 0xff51ba63, 0x38b59c61, 0x5687b2f5, 0x03c46407, + 0xacb190bb, 0x3b684c75, 0xcac840d7, 0x00acb499, 0xc52e4d8c, 0x73009750, 0xebe13e2c, 0xdb27e74f, + 0xaf9da2c7, 0x170992b4, 0x94535f76, 0x6663ba57, 0x7554b9fd, 0xffb80124, 0x874ccaba, 0x53349a46, + 0xe27f17d5, 0xe6c89c61, 0xcd0394f6, 0xb6d8db31, 0x9175a944, 0xee18305a, 0xb44f3cac, 0x9fff9a07, + 0x858cdbf1, 0x933b2f3d, 0x44c51a26, 0x9031d536, 0x45d4cd19, 0x9ef760d7, 0x4984fb3a, 0x9ffe69ba, + 0xafaa86b9, 0xb82b516d, 0x6b19485e, 0x29bc5f27, 0xba59b71a, 0x463a2004, 0x29e018e1, 0x4e0f14ee, + 0x57c78af8, 0x756d53b9, 0xfd2057bc, 0xa71cdd91, 0x74bb54b6, 0x833ac425, 0xfeed1011, 0xffb774b7, + 0xcd6fb94d, 0x490f7938, 0x870d4b6f, 0xce3bc164, 0x54dd235e, 0x1a4383fd, 0xd28290ed, 0x22dc6944, + 0x25687a66, 0x340a388d, 0x7ba54504, 0x755cdbb4, 0x8645f7a0, 0xd341315a, 0xd77d8615, 0xc44b7c0f, + 0xee0e56e3, 0x89105790, 0xc0c7692d, 0x72c83799, 0x6c70da4b, 0xbb37f8e1, 0x2d0492cb, 0xdb50d1dc, + 0x4c08e68d, 0x79ab6758, 0x4a206083, 0xaa54bc32, 0x50405b0d, 0x2bbcb8ca, 0x419b1874, 0x77a1c940, + 0x532e5aa9, 0x31ab50c8, 0x6dd7c4f9, 0x922ffd59, 0xc43d9c9a, 0xac829930, 0x93eb2415, 0x6da150c8, + 0x2807ebe7, 0xbb0eb4c4, 0xeaf3f351, 0xd8627009, 0x885f31e4, 0x235809bd, 0x1ea6d462, 0xfdac4a75, + 0xd43735d9, 0x1d652522, 0x06a677bf, 0xa4622890, 0xc5a8b96a, 0xf81d2b62, 0xc1fd72a2, 0x5d21c4e0, + 0x8d90c749, 0x401d1267, 0xfe5731ed, 0xd6586fb4, 0x26ae9eb8, 0xc07aaac3, 0x3430af72, 0xcf91df6b, + 0xad9a5122, 0x6a9c12e2, 0x78a70382, 0xe9abfaf5, 0x584113bd, 0xcc0f0d9a, 0x9c11a6bd, 0x7e3022fc, + 0xc71b85ed, 0xdab7ff97, 0x19bdd073, 0x4861332c, 0x14d4ae35, 0xdca0d1c6, 0xdf5ac5c8, 0xb5de00ed, + 0xbdeab4cc, 0xb0d9d967, 0x6afd2b29, 0x82e46e11, 0x9f8676d6, 0xe94e1580, 0x62a091a1, 0x3209b85d, + 0x18d455a3, 0x85d1a853, 0x8ff3db69, 0x39d041f2, 0x77c176cb, 0x113b6ccd, 0x167a9567, 0x5ee05f42, + 0x4754ec35, 0x05c22f07, 0x6b889d0c, 0xf1d03bdb, 0xb66ef227, 0xed163074, 0x0dd15052, 0x3fe33f16, + 0x57ac07e5, 0x411554c1, 0xa8e147f5, 0xba933d7a, 0x6f1263e0, 0xf5fb7cb0, 0xd64f65a4, 0x17322cb8, + 0x154119aa, 0xfd864cc0, 0x291412d2, 0x6473cbe4, 0x11883799, 0x0987c302, 0xf6e50bc2, 0x46f2553c, + 0xa37260df, 0x0fc1147c, 0x4cf43fdf, 0x0c8437db, 0x194407ae, 0x680b6dd1, 0xf8b4b54c, 0x9c0df18c, + 0x112dda34, 0xfc61a827, 0xc0c0ce1d, 0x478f27d7, 0x9680f964, 0xeecb918a, 0x0a4936bd, 0x5274eaf9, + 0x954ad1cd, 0xa6e87ce0, 0xe5a7dec4, 0x4f94ca4a, 0x15d44cda, 0xa8125ab1, 0x6d982b8e, 0xc3838b26, + 0x4b56b04f, 0xcc9f727a, 0x0c8900b2, 0x268c3f93, 0xc67fd3c0, 0x6f95a4a1, 0x0112ff76, 0xaceb2456, + 0xa88df8cb, 0x8215d2ec, 0x8ae31fdc, 0x08b1cf1c, 0x5c849f7e, 0x7374e017, 0x436d2174, 0x61df48f3, + 0x03be016d, 0x17d73f61, 0xfed31727, 0xd9d63c33, 0xe696bd60, 0x25167826, 0xba402ef1, 0x2dcf081f, + 0xb18056fa, 0x17dd725a, 0x2f0d4d61, 0x3cee0999, 0x27ee992e, 0x2a830c97, 0x5f74b572, 0xbccbcd3a, + 0xaa22a16f, 0x2972ba2d, 0x3d5e2cca, 0x5975d4bc, 0x70c74b07, 0x5064dcb5, 0x4aa6257c, 0x7648affc, + 0xe4117fe3, 0xde251887, 0xd0b3266b, 0xccbb05e4, 0x9e954bf2, 0xa34e83cb, 0xd3035413, 0xe3ee8c90, + 0x58776969, 0xa34df221, 0xc7d977f2, 0xd0985b79, 0xbfe01425, 0x35226c23, 0xff09008f, 0xb6d01d96, + 0x4fbd5fc3, 0xebeff20b, 0xd2849aad, 0x8505752a, 0x69d278d4, 0x93baef39, 0xf67cb5cc, 0x8d0cee04, + 0xe4899a9e, 0x0101adf6, 0x5deb9d23, 0x0dcdd451, 0x32c0a51b, 0x98cf3988, 0x08c93e80, 0x0c56dfd2, + 0xf0883af7, 0x4b4785c4, 0xe89446a4, 0x984dd44c, 0x3499277b, 0xfe829451, 0x9c229541, 0x7fd35032, + 0xafd5ac87, 0xea6ae767, 0xbac773b6, 0xfd7129c7, 0x72d1a397, 0x80469e00, 0x044f2754, 0xfa9d484d, + 0x95642fbd, 0xfea258d6, 0x151d48b7, 0x57d6d5bb, 0x6433e677, 0xd2ed9e5d, 0x50ab4b8d, 0xd3602e12, + 0x949dd2d8, 0x21a67373, 0xc0b2eaaf, 0xcf8f08c5, 0x79f9d5db, 0xce7ae0ff, 0x6073ae3a, 0xba494944, + 0x0218c16e, 0x2421bf3f, 0x025fa60c, 0x3788a353, 0xef58e15f, 0x05fb8783, 0xd9f470b2, 0x6b99b9e1, + 0x6c2bee1b, 0xaf4a67e2, 0x05cf2f6e, 0x20254b2f, 0x4e293ec8, 0x6cee686f, 0x6b2b8604, 0x25ca605e, + 0x184e3247, 0xd27d288f, 0xa7520ef9, 0x76afe282, 0x4ebd4981, 0x7806a2ac, 0x7b002125, 0xd471658f, + 0x25757546, 0x523cb0f8, 0xdebe0ec7, 0x6b14e762, 0x04e2a17c, 0xd8d89b82, 0x2dc88492, 0x1073d278, + 0x7c735c96, 0xb0fd0d4e, 0xa6862b06, 0xb2b48dec, 0x7062dd75, 0x4ca3f480, 0x9696dc6b, 0xbf0ca9f3, + 0xcb1dbdc6, 0x0b41368f, 0x6b3c0e8f, 0xfd7ba575, 0x876c16eb, 0x4d2d69c8, 0x3945f0eb, 0xc39b1cac, + 0x1778d849, 0xa05d07ad, 0x2430077e, 0x1c32200e, 0xf8790db1, 0xe79da740, 0xdc7c29b0, 0xd25e55ee, + 0x77a339ea, 0xeba5af53, 0xaec56c1d, 0xb41bfe32, 0x89885cc0, 0xd7f69fe5, 0x0bf49085, 0x4b67d2ff, + 0x2c56e7d9, 0x28675afa, 0x1df53563, 0xe1af895d, 0x5d01f4ea, 0x967c2941, 0xc17de0cb, 0xb881761f, + 0x27daa241, 0xb0d4b5f8, 0x8c0a17ec, 0xa66edc18, 0xef95aebb, 0x25445e17, 0xf9623076, 0x1b78d711, + 0x63b6c008, 0xa9f05d45, 0x85aa1ff4, 0x0e28dcb2, 0xcb181308, 0x4425bb06, 0x7467b7b5, 0x8c5271a2, + 0x2db06506, 0x2e5e8864, 0x0661d7e4, 0x084aa220, 0xd6e95c39, 0x73f025fe, 0x219c8e51, 0xafe0061c, + 0x798493d5, 0xccfc430c, 0xf437d81d, 0x65f6a329, 0xf30d318f, 0x601bdd31, 0xf999447e, 0x0b33746d, + 0x08aabc18, 0xc7a34285, 0x67c99be8, 0x987eabdb, 0xdfb8cb5e, 0x130f1be2, 0x7ed04a48, 0x34defe48, + 0x711735c8, 0x7640d0ac, 0x112f8eab, 0x2853a19f, 0x2ccf1c12, 0x98bd1973, 0x5d0d9624, 0x5d8e586b, + 0xe153ea57, 0x005492bd, 0x00554b56, 0x6265c2ed, 0xd3e65718, 0x88886668, 0x961be040, 0xfb3e331b, + 0x1f94ecb1, 0x0750e877, 0x4faccfae, 0x04fee618, 0xc4e3962e, 0x2b480b2e, 0x9481e551, 0x446ec5bf, + 0x91c31ed5, 0x20bd12c9, 0x886dc4ee, 0x2deaf4e0, 0x2d5aa9ee, 0x8439261d, 0xdc714fcf, 0xae6333d8, + 0xc8617f16, 0xeaecafda, 0x7d2243dd, 0x581d4035, 0xd97451e4, 0xc341e899, 0xcd2d36bd, 0x3375744e, + 0x362781a9, 0x19954018, 0xddd34bac, 0xac8e2166, 0xf04c2e01, 0xd5ff5b15, 0xa16ad1ed, 0xfebb481d, + 0xec56fe27, 0x316074ac, 0xcb03175c, 0xb83223fe, 0x4ce033d6, 0x747eae0c, 0x3f7671d1, 0xe46e9dbb, + 0xad57442c, 0xe05d2f6f, 0xb66e173f, 0xa0dcaf1f, 0x4c5bd9c5, 0x7c59ee99, 0x20dfaa1f, 0x71095e77, + 0xe5ce30fd, 0x9a66c092, 0x89b1b7af, 0x6e9c8acf, 0x817a766e, 0xeee7813b, 0x319d035d, 0x085e99d9, + 0x1f033829, 0x5f3cfa32, 0xaf9b491b, 0x40c51f11, 0x957be7c4, 0x302d8b46, 0x04602e1b, 0x3bcec23b, + 0x0c8a968e, 0x19c3f8ba, 0x3203e946, 0x9abb174e, 0x6c2d0d93, 0xcce3dca1, 0x0bb31bfe, 0x3bf321ce, + 0xba0c7e79, 0x925105d8, 0xf358720f, 0xd4e45669, 0xf551a486, 0x6db34de2, 0x0bf46624, 0x3b97900e, + 0xc7bd14d1, 0xe4fa1e72, 0x969361e9, 0x5967f3ec, 0x7bd68a35, 0xf8085020, 0xf16fe966, 0x5d5dbad9, + 0xe2e9cf7d, 0x3fd07475, 0xcf0948cc, 0x61abcf84, 0xb0a23525, 0xf60e73e0, 0x8c892d29, 0xb98a6bef, + 0xbe469992, 0xda7699c8, 0xe30b87d4, 0x2a2acf54, 0x310b6e50, 0xb6c6e7fc, 0x11030da9, 0xe7238d55, + 0xb24330af, 0x23fdc124, 0x7a0f9f06, 0x6980293f, 0x260ba4fe, 0xa1cfca5d, 0x8d3db451, 0xafdbe1f6, + 0x7a982a03, 0x2eb3ec30, 0xc9e6d10e, 0x3f20eac9, 0xff9e9232, 0x7ee7b350, 0x29ae3f2d, 0x1e7f34b2, + 0x671a9465, 0x54be31d0, 0x8f9add98, 0x8826de9d, 0x16c9876a, 0x30a580cb, 0x41740652, 0x5896ac0f, + 0xde36ed70, 0x2d89d363, 0x5f596804, 0x3486995f, 0x463b04e3, 0x1a3feecc, 0x45fce066, 0xdd11a558, + 0x54f2bdc2, 0xc1f94113, 0xe22a9f16, 0xd267575b, 0x94be53e2, 0x620deefb, 0xac983fa8, 0x83b766e6, + 0xfc70aa01, 0x3ef62bdd, 0x1a2913e0, 0xd1f8b5ef, 0x33a24af6, 0xbf082543, 0xd6bd6592, 0xc7399c31, + 0x6550729a, 0xe08c8212, 0x41d5ac78, 0xf9ccdbab, 0x17c45a38, 0xe58bbc61, 0xb7175d49, 0x11734cc4, + 0xb0bcd312, 0x2f932a8e, 0x74c582c6, 0x38af472a, 0xd23a47f9, 0xddf28304, 0x75331a64, 0x82667a4e, + 0x723e118e, 0x35ce972f, 0x54a49c4f, 0x5a2ad75d, 0x284d17cb, 0xa071d3ba, 0xe8383e40, 0x7e03eb5c, + 0x6e9f0f8f, 0xd7f7ffab, 0xc97e0399, 0x123b6827, 0x6c49886c, 0xb79ba4c5, 0xd8cea6ce, 0xa9238e29, + 0x50bdf458, 0x0fb0e42b, 0x71478fe3, 0x39ba822e, 0x9856a317, 0x352eb893, 0x0ff2e584, 0x6fb63ff0, + 0xb291ec2a, 0xae33cf4b, 0x5d7e2586, 0x0c1ccb02, 0xa064f04d, 0x865e1c49, 0x0f47527b, 0x9bc134dc, + 0x30dda423, 0xb6189ba9, 0xe14c33bc, 0xb5774b0f, 0x62f7b44b, 0x271ce403, 0x65655eb3, 0x5b09a5d5, + 0x7137a489, 0x63cccaf2, 0x51492b74, 0x55967a63, 0x18eee060, 0x96af1201, 0xcff94e7e, 0xb5f381cd, + 0x854c1fd2, 0x0ba9f2d2, 0xe3ff7307, 0xeb23d844, 0x4fe010e5, 0x3c77f1dd, 0x3215c4c9, 0x863f299d, + 0xee2c702b, 0xea0d97e7, 0x79df1e66, 0x3767bb7c, 0xf8e13669, 0x6ef161f3, 0x5def04f9, 0xcc009e2b, + 0x7c2af898, 0xbec20c97, 0x3eba6865, 0x1bc932c5, 0xfdb0e176, 0x5aff160b, 0xddad6e16, 0xbe55988b, + 0x5503c090, 0xb43d5790, 0x92a16de8, 0x46f7c6e5, 0x4a297c14, 0xf55a0015, 0x026b511b, 0x79547eb1, + 0x488c8e96, 0x09263990, 0xe7073429, 0x87dc9978, 0x5919defc, 0x8551192c, 0xb57bdfea, 0xa238448c, + 0xbb57ceb7, 0xe20e74ef, 0x4eb6f78d, 0x0ed4d428, 0x7188cff2, 0xdd869eaa, 0x81758eb7, 0xca7d6004, + 0xb5bd3bb5, 0xbf6bf076, 0x1e785c27, 0x3159f3dc, 0xe2f983af, 0xed40184f, 0xdbf6ec9c, 0x4038055f, + 0xcb2f5536, 0x9f8ad90a, 0x90adfb03, 0x4d22560e, 0x122e4792, 0xa362e088, 0x66d158a7, 0xe55ef187, + 0xf11f2510, 0x5d8b7173, 0xf4684b59, 0xfa1da661, 0xdbf467f9, 0x5a956c61, 0xd4e38138, 0xcad508bd, + 0x802d0b7c, 0x08119a36, 0xcc62124e, 0xef08936f, 0x91c0c76d, 0x37fcbf90, 0x1f1bb340, 0x003fa202, + 0x27a711e5, 0x3e14108c, 0x058f01b4, 0x4646d620, 0xc8b9a6ed, 0xaac56456, 0x9ba4ad07, 0x486306d3, + 0xb8aa7ba8, 0x7cb82636, 0xc52ed5e6, 0xdac32e04, 0x81989901, 0x927dc648, 0xc25a9441, 0xc701d04b, + 0xfde457ca, 0x45d69718, 0x90eb95d4, 0xd6967719, 0x428c03a7, 0xa4cb478c, 0xb45e84b3, 0xb0c3214f, + 0x1495fdcb, 0x3c6e8e92, 0xca88b68e, 0xe4a6bb45, 0xadd359bf, 0x0ef489c9, 0xf17964da, 0x5541bc9f, + 0x71e187e4, 0x264da4cf, 0xc14893e6, 0x441139fe, 0xeacde4f5, 0x04cc4d54, 0xe29691b1, 0x43b6adf6, + 0x94cc8273, 0x54462976, 0xc089f69b, 0x4bcf583a, 0x8c7dec9c, 0xac2b1761, 0xcc14367c, 0xa63abace, + 0x307eca04, 0x195c27b5, 0x72508294, 0x3430bbc1, 0x23f50151, 0x87ed9af3, 0x5bad72aa, 0x555fffb4, + 0xf40f95ac, 0xaa1dc24f, 0x21496879, 0x2a290c96, 0x33e522e1, 0x1b35c2d1, 0x50fa73db, 0xc6261850, + 0x2e362f8d, 0xfefba865, 0x80ab14f4, 0x892680a0, 0xc0b7c790, 0x3fbebce7, 0xb29380d5, 0x0d216e80, + 0xd19a06e3, 0xb7795928, 0x62ae868c, 0x17b9adf2, 0xf40b51cc, 0xd69c7e45, 0xbdaf329d, 0x272312e8, + 0x6cf822e2, 0x1d900ced, 0xca66219e, 0x8f34e2cd, 0x2937b64c, 0x985ab51e, 0x1516954b, 0x9940954a, + 0x47500f46, 0xf8be0359, 0xaf70ce41, 0xc5d291c1, 0xa118d9f4, 0xfa3feb54, 0x81b2fc54, 0x29f8af6a, + 0x28df6efb, 0x372cbc8d, 0x1413bdce, 0xf958492b, 0xcd7680f9, 0x1e11a87b, 0x71ac508c, 0xf004de97, + 0x9c1029d4, 0x9fc69f52, 0xd3c51815, 0xc2456e5c, 0xaecc8267, 0xa5a21099, 0x2a6f474e, 0x7542497c, + 0xea16f71b, 0xb522bf2a, 0x03f6e2a2, 0xb6fa128b, 0xc5530995, 0x2af3cae7, 0x2687d330, 0x69af7481, + 0x4d0917bd, 0xc734de64, 0x4af32077, 0x295d251c, 0x23d35f11, 0x6660870b, 0x00a18326, 0xcddf98a5, + 0xd34f8fc1, 0x06a1d515, 0xf6924f6a, 0xc554efc6, 0x1de89e63, 0x3c956029, 0x10ba1a71, 0xcbaf57da, + 0x989712b6, 0xd42c2f3e, 0xd61d53dc, 0x768e3569, 0x23ff6561, 0x103deb45, 0x0971bb8f, 0x1b0ff35f, + 0x304eb7d4, 0x57a17455, 0xbb70a5b4, 0x1b9a983c, 0xde1e7ef3, 0x61150b0e, 0x2580a0bf, 0xe1a67a78, + 0x906f31c7, 0xc9466a56, 0x854fe22e, 0x5a29f71a, 0xefe2821f, 0x3c2ae6f8, 0x563e61a0, 0x961d4c92, + 0x9cb0efb5, 0x8c0d28d2, 0x1d6d6414, 0x7e001b8b, 0xa47fc406, 0xa0cb2fec, 0x91bd0487, 0x09c670c8, + 0xd8d32dfe, 0x9541e0a0, 0x63557a9a, 0x2e54c0aa, 0x7e4dda78, 0xc62af25f, 0xa2ccd77d, 0x05c9f9af, + 0xf483b577, 0xb61f5951, 0xc5365e8e, 0x3a150452, 0x73c1b6d6, 0x6ac3b05b, 0x1cd83d80, 0xbaae54fb, + 0xc789e9d1, 0x14b30984, 0xfab2e173, 0x51a80e3f, 0xffc19519, 0x576acdc3, 0x870cce5e, 0xb00b83e3, + 0x28834a03, 0x87712d52, 0x093fd8d0, 0xe8f5cc34, 0x4434f8ca, 0x7ddaf455, 0x54cf13fa, 0x0723b0ca, + 0x7641ac0c, 0xd43ba806, 0xb04de7f9, 0x69c4be6a, 0xf5d31348, 0x1f8f731f, 0x83423d75, 0xd7e053c5, + 0xa02e3d4b, 0xac690d8a, 0x987eeb0e, 0x3979a961, 0xd573cc09, 0x97c3514e, 0x297cee98, 0x019bc58d, + 0xc7cd2a4f, 0xca12a885, 0x078c2d15, 0x32d12fe8, 0xe3f82322, 0xa98a2c38, 0xa85055e2, 0xd47117c0, + 0xc68958b3, 0xc6145a2d, 0xb0a87f04, 0xff17b569, 0x7da98a14, 0xdff7195e, 0xca3d505a, 0xd1be7682, + 0x05932c29, 0x739a94cf, 0xacfa2688, 0x7d8c6572, 0x771eab7c, 0x758dbe56, 0xb7e8002a, 0xf2561f83, + 0xb4b82902, 0xba8e9ece, 0xf733164c, 0xe97e7ca6, 0x73490f82, 0xc20a7a10, 0xa78a4be7, 0x1a980ea8, + 0x50327911, 0x909cbe1f, 0x6ad0d1be, 0x3c1fa61b, 0x4c99b26e, 0xb3c413a7, 0x382b489d, 0x4c5108ae, + 0x14701a66, 0xa6593d72, 0xd0495fc5, 0x05dbd659, 0xb392d15b, 0x6dc1591f, 0x951d01c4, 0x244b83be, + 0x8f535f14, 0xbea97138, 0xcdf9386c, 0xdde26a5f, 0x5233dfea, 0xcd103070, 0xdd83efab, 0x39f6506a, + 0xbfa35b80, 0xfc6fbeab, 0xd9b35896, 0xe08407fc, 0xbc9bd9b6, 0x97ffbc60, 0xfbb5efd6, 0x2bba9ff9, + 0x5bfa1a5e, 0x9fb8f5d3, 0x551aaa6a, 0x78e21f41, 0xf0c54b08, 0x4d9ba0ea, 0x2738109d, 0x59f4a84f, + 0xa4edad3a, 0x2c25128d, 0xcea5f5ce, 0xa5a06153, 0xc9cea7bd, 0x08519f92, 0xc721cbd6, 0x5d401a08, + 0xb7db52ce, 0x4e26d81c, 0xf872acac, 0x188bef26, 0x4f36ccc0, 0xc916a47a, 0x7f59e4ac, 0xeb6c8932, + 0x32438377, 0x666e7367, 0x5aea1e92, 0xe6dcab38, 0x708fd98e, 0x1a59f59c, 0x33c2085d, 0x3722f570, + 0xe7634677, 0x82fc94a2, 0x5a7a8e2a, 0xc5792ffd, 0x79fa8699, 0xabf31416, 0xdbeec12c, 0xec871851, + 0xb59e7826, 0x346d4d4f, 0xb6c42c00, 0x8f0d7a70, 0x0faf936e, 0x903ae9a1, 0x8e77684d, 0x009e6bce, + 0x0da4072c, 0x7660936d, 0xe08f7487, 0xb295f665, 0xd4b2641c, 0xedb50e21, 0x96b8e55e, 0x827edcad, + 0x45abf5e4, 0xa3df9a80, 0xecd91f42, 0x63c4da44, 0x02ca7eb3, 0x43bcf744, 0x08b18e5d, 0x231adf41, + 0xe0697471, 0x89632244, 0xb4b30526, 0xaba866f3, 0x8b0ad56f, 0x961f8f04, 0x94e6438a, 0x62da5353, + 0xb9d46ac4, 0xfc18bd64, 0x888c246e, 0xa157ec0b, 0x082b19ef, 0x2c7398fb, 0xb506a21f, 0x3dc26fdd, + 0x3a96e387, 0xd06881c4, 0xc36bc418, 0x1cfe3ab6, 0x3fe10c97, 0x8b0fe059, 0x170d8304, 0x280c0369, + 0x0d7243a9, 0xb2d95e9b, 0x8029e1a1, 0x42d536eb, 0x991a12bb, 0xac83d401, 0xacd5aa3d, 0xfb45e3b4, + 0x889e5f11, 0xf5ba8b62, 0x0341b769, 0xb77bb2c3, 0x3df4f0d7, 0x11ae40d7, 0xf20a86a7, 0x9fd71945, + 0xebb37e7d, 0x1bef14d5, 0x8ae6adba, 0x2d0e4653, 0x8a7662b7, 0x06bfa4f3, 0x2aab8031, 0xd402c019, + 0xb343636c, 0x21029e3a, 0x52ad053b, 0x42d15a5b, 0x57efb66a, 0x9b2c41d5, 0x868a2aba, 0x4cb24a2f, + 0xeb85ea9a, 0x5cbb3325, 0x170c4af1, 0xe70dd188, 0x88d042f6, 0xfc0ad0aa, 0x27f9cf1d, 0x63a63b23, + 0x70c181ec, 0xcb1e8cd2, 0x3af6c7a4, 0xcb745c31, 0x1bbe8729, 0x500b40b3, 0x9ba0d65c, 0x2e3fd2f8, + 0xff692f5a, 0xf01081a9, 0xd607599a, 0xb2f75011, 0xe9c29dab, 0xebc5ff87, 0x69d9d8ce, 0xb133de91, + 0xca7e3d2a, 0x3edb82b1, 0x85ff4e7a, 0x56159f46, 0xd8d36c19, 0x1b07ce27, 0x0acc2bb5, 0xcb098648, + 0x95e7d952, 0x18f61666, 0x9a649c50, 0xf4589609, 0x610923ec, 0xdfb480c7, 0xb52382cb, 0xa91efcee, + 0xf2aeedac, 0x9b186c1f, 0x0b2a736e, 0x10b9739c, 0xdfbe95fc, 0x7af0465a, 0x4654a24b, 0x4db629f4, + 0x44defd82, 0x3ca1ecec, 0x88db17cf, 0x431f6f45, 0xf05a57f6, 0x2d0b0053, 0xc1db8462, 0x07273b19, + 0xcf5b2540, 0x2ea41d05, 0xfb45b41f, 0x66e30d0a, 0xf58d55ed, 0xe40eef10, 0x2180b80f, 0xe87af2dc, + 0xed07f5d5, 0xf19096fe, 0x09006822, 0xa5188385, 0x2aa747f6, 0x8ee77336, 0x2cf13bb7, 0xbe97504d, + 0x08a80fba, 0x4846058b, 0x0739bdbf, 0x3a2a2667, 0x6b7b2a63, 0xa6a0f2f5, 0x6a637a70, 0xab36ed3d, + 0x6c4b8d0f, 0x958505d5, 0x0ba18df2, 0x2afafd6d, 0x0007669b, 0x4220e47c, 0x80462f36, 0xabb68e6b, + 0xfdea65e2, 0xdb740109, 0x2ada595b, 0x22a1ef3e, 0x3c08ff7c, 0x89e6bd6d, 0x41eb8fff, 0x290c3bfe, + 0xe0202e8d, 0x796e5474, 0x1b70e201, 0x113eef18, 0xaf75ba23, 0xe72a7591, 0x04657b71, 0x9d5e922f, + 0x62e92e6c, 0x8d0eab22, 0x777e7195, 0xfd5fad03, 0x2ef8ed1f, 0x423fd39e, 0xad75664c, 0x731b2ef5, + 0x993130b0, 0x1dd518d3, 0xe83e1e50, 0x52e2d03c, 0x5e363f28, 0x86204e0b, 0xb0e8626d, 0xc8ae391b, + 0x99469043, 0x394d08b0, 0x78107a1c, 0x4d48a726, 0xb52c8afc, 0x6777b278, 0x9d375531, 0xde862660, + 0x51fbe65f, 0xbcbbe161, 0x9ba10669, 0xe767efc4, 0xca9074bd, 0x225bd94b, 0xf8707a61, 0x47e17d6c, + 0x9649ebf1, 0x681e0451, 0x5e59134d, 0x83930f7a, 0x8b14b9c8, 0x454e990f, 0x8a04fecd, 0x33b83b98, + 0x783ba767, 0x606a05eb, 0x4bc06417, 0x84d68a3c, 0xd3141b41, 0x7a1de407, 0x6e6993c6, 0xf5856bd6, + 0x6330f690, 0x2ad14592, 0x3f149629, 0xbdc535c8, 0x6a347fff, 0x88c022a0, 0x2ce8dec0, 0x6d8414c8, + 0x63541697, 0x12e20e63, 0xd3b4a189, 0x9629adf6, 0x75335cc3, 0x7d080199, 0x97b92fed, 0xae1b769d, + 0xb23df657, 0x205ea9c1, 0xefb64969, 0x804377e4, 0x15ac968f, 0x3bd7cf73, 0xbbafd836, 0x16e9359c, + 0xd687a3f6, 0xabc57c90, 0xf9a64e42, 0x7c8b6212, 0xcd5440c7, 0x2f555d95, 0x1fb28ab1, 0x36d8c897, + 0x5ecdf62a, 0x40c71ab7, 0x066337bd, 0xcc9b0475, 0xa7b31de3, 0x366dd526, 0x49e66825, 0x042461a4, + 0xc259495d, 0x1d448f23, 0x9cb102ea, 0x2d13770e, 0xcf71ee1a, 0x86440213, 0x13096c7f, 0x21eff750, + 0x705af198, 0x503bcede, 0x9d9e26cc, 0x00da0293, 0x0f1d1092, 0xb1607ace, 0xa16faf4a, 0x8f85ecbc, + 0x806ff8c1, 0x7f3fc8f3, 0xb1ae22a1, 0x0b89f007, 0x9a1ead64, 0x2b352056, 0x2da844f7, 0xccf01ca3, + 0x2ff9d2ce, 0x32f42361, 0xf140c99e, 0x2b852d92, 0xb7c189eb, 0xbd1a36f8, 0x32df6833, 0xdc819840, + 0xc4ed7052, 0x5d388284, 0xd989038d, 0xef47535f, 0xf16b1c24, 0xbcd9d0d9, 0xaf03ab40, 0x058eb5bd, + 0xedb7e4d5, 0x67dae8ed, 0xb0b8fbe9, 0x0ab84af7, 0x9ab0b449, 0x33569732, 0x355ef0c3, 0x348dbdc6, + 0x077bdec1, 0x88e1cb26, 0x4d7d2dee, 0x599683cc, 0x10349f2a, 0x6dafbaac, 0xc5f62aab, 0x43657873, + 0xe149477a, 0xe555d3dc, 0xe6f2c852, 0x5034025c, 0x2f4a1754, 0xf10afdfe, 0x8bd2c021, 0x4813dd64, + 0xc20334c5, 0x104c5ba7, 0xdb5ed003, 0xac5bd0e0, 0x4c414386, 0xacf124a9, 0x4f79fda0, 0x92c50bb7, + 0x938b5e77, 0xe231d5d9, 0x01ae2322, 0x50a3fcf7, 0x7446d1de, 0xa90247fe, 0x58bf6c5f, 0xab2f3b0d, + 0xaf97560d, 0x9c6a99c5, 0x648e05ca, 0xd7000f9f, 0xdf07ad4b, 0xf509de86, 0x982ce721, 0xa1939613, + 0xdaeddb1e, 0x63e98e24, 0x04271a4f, 0xd935c54c, 0x10555a55, 0xc1d708d7, 0x50f33877, 0xd7da822b, + 0x4f706be6, 0xeb50ae8e, 0xccf3968d, 0xe63675ca, 0x9af9e72e, 0x1084dfa2, 0x8ce8fcb4, 0xf0c333f8, + 0x25f42641, 0x8dabffdf, 0x35be12d1, 0x74116bd8, 0xab71fcb8, 0x08c351f6, 0xe78af203, 0x147c8993, + 0x64a3e6a2, 0x266aa74b, 0x2fec47fc, 0xe574890f, 0xc9f7f26f, 0x6eedec50, 0x4da3be66, 0x4b681d8b, + 0xd6300aa6, 0x1b737323, 0x2a728e50, 0x520ccc74, 0x484501ec, 0x83e964d3, 0x523a8bce, 0xd7ad706f, + 0x9e08f85b, 0xea6abba2, 0x6fae27bb, 0xbfb467b8, 0x25130519, 0x0ad5df74, 0xebc51e54, 0x6eadc7fe, + 0x62332d10, 0xa01e865b, 0xea3eec34, 0x162e1fc7, 0x8dbbb6e6, 0xb7290beb, 0x0d67b53b, 0xf8c9c103, + 0xcf266472, 0xa2c7e575, 0x38fa4abf, 0x57868620, 0x418234c3, 0xa7b3726a, 0xba73f6b2, 0x7c7905bf, + 0xfa9c8a27, 0x01ff7c85, 0x4ea4ee5b, 0x2a5b34a3, 0x244d7ead, 0x3097aeb6, 0xfe565695, 0xfd76428b, + 0x240847c9, 0x83bf6993, 0x63a284eb, 0x4e9a270e, 0x4ca7d879, 0xe55b12eb, 0x26a66a07, 0xe3a0e55e, + 0xab119603, 0xa3affcfb, 0xf73304de, 0x8caab8fb, 0xc3f0b69f, 0x95057bc8, 0xe2f0b3eb, 0x2b124d85, + 0x11b03eac, 0xd346c0c0, 0x6f989785, 0xdc1db1fd, 0x9d3b0b5b, 0x4bf93473, 0xb76e0b56, 0xb214104d, + 0x62bafc96, 0xc0b2ac7a, 0xafc404ec, 0xf90a69a2, 0xcf440b3b, 0xea0260b9, 0xbe3d8cac, 0x68dce242, + 0x7c769565, 0x2f27862a, 0x8d857579, 0x7db88f23, 0xf371c712, 0x3456949b, 0x0668d99b, 0x320cfcf6, + 0x29b3afe9, 0xce87e726, 0x374724b5, 0x547ce476, 0x83d74069, 0x840e9745, 0xe1b13f54, 0x075ab2f1, + 0x7d56db37, 0x41cb5e43, 0x5aefee03, 0x49208c81, 0x7619b44e, 0x6713825b, 0x6879b8df, 0x6887ded6, + 0x82b38a55, 0xae2c37a7, 0xceee3fc8, 0x303d897e, 0x58dd157b, 0x220e49e7, 0x6dc23017, 0xd49c3172, + 0x0dc17456, 0xf18ce899, 0x7c238f04, 0x84ee8f9c, 0x999d6d37, 0xb472001a, 0x0571ca50, 0x39d77bc5, + 0xed09c192, 0xd6851ee3, 0xf4a87337, 0x84ace5da, 0x599e4996, 0xeccd79c6, 0x592d07e2, 0xae152e66, + 0x1ccae540, 0x20ed91b0, 0xa37e21d3, 0x451c53c9, 0xf917c6f7, 0x43669024, 0xe281cc87, 0x74f7467e, + 0xf784f8d6, 0x6e60998f, 0xe5ef12de, 0x01224a22, 0x1f84dcca, 0xc19d9c8a, 0xeded6721, 0x3208b321, + 0x6e52ea95, 0x17235739, 0xc9fa6a1c, 0xfd8bb08b, 0x3c186ffa, 0x6f24115b, 0xc6ae146d, 0xea2fd2f1, + 0x9ef92a87, 0xf040c03e, 0xbf19c8a7, 0x0a8f647e, 0xf8c2df88, 0x61b6af5f, 0xb5bc3d5b, 0x20f32fc1, + 0x9221dbc6, 0xcda3b9b7, 0x536f0c0b, 0xe3c96e34, 0xd59c0091, 0xd42d0e9e, 0xb4a090ee, 0x1d52e612, + 0x1fb75ca4, 0xc4c3575e, 0x24f02958, 0xfcdf7374, 0xfcd74cac, 0x03a292ed, 0xffdf7a8d, 0xef9c9409, + 0x7c62779e, 0xc2987f1f, 0x238756ea, 0x4fd9669f, 0x4ddfc23c, 0xc44eb578, 0xdac7075b, 0x33f4c160, + 0xa6d76571, 0xe42a6c33, 0x0f3fc9fb, 0xe052078b, 0x1860f2f2, 0xf0f7de72, 0x329a5ca0, 0x2682496f, + 0xd283c795, 0xa2e30c42, 0xa6de35aa, 0x716d7adf, 0xaee62e7d, 0x048d55b6, 0xd922e358, 0x138d170c, + 0x23ba3a3b, 0x0f911023, 0xa836b275, 0x8bc52c54, 0xc30a505c, 0x60c24b5b, 0x210519b2, 0xed9a1bd2, + 0xa0ef53d7, 0x4e1de394, 0x920e0f3a, 0xa1c1344b, 0x0c3eea0b, 0x3659fbf2, 0x0eb21352, 0xbbc816bd, + 0x102f7f9b, 0x7eb61d77, 0xd8a2c1db, 0x1221a720, 0xfb868d1d, 0x9933ab62, 0xd6ae524d, 0x52218719, + 0x44a724a7, 0x24389752, 0xcc6acc76, 0xd6c4ad72, 0x632826a3, 0x62df1a8c, 0x80559e3f, 0xb45b3c92, + 0x150486ce, 0xbd39954e, 0xc03fce52, 0x2b4afbc9, 0x3f152cbe, 0x57d514ce, 0xff1524d1, 0x50be5432, + 0xa83548d8, 0x2dd61d22, 0x688e23bc, 0x84743c12, 0x4f394816, 0x3cdad44f, 0xbfda542d, 0x652f630c, + 0x06c7ce22, 0x30b6cb2a, 0x9936790d, 0x533ae799, 0xfc774030, 0x7abf21c8, 0x1fe22201, 0xcef5e5c9, + 0x25ec854e, 0x9db33e56, 0xf89e7267, 0x26fe6963, 0xef19713f, 0x00588f3b, 0xa27394c2, 0xefcd3090, + 0xb8e6f506, 0x8214405d, 0x6cd3d395, 0xe600b29d, 0xa06b87d1, 0xb63befe4, 0x65a63e09, 0x9459cc6b, + 0x3e7be9c1, 0x7c5f3fd3, 0xb45c85d4, 0x1b7cd1b0, 0xab298ad4, 0x5d20c3d9, 0x3caea471, 0x64e52657, + 0xa592df3f, 0xb55606a9, 0x48a3b865, 0xc03c70a8, 0xb10d1037, 0xb636f066, 0x4809ab80, 0xb1532a0c, + 0xca24f7e5, 0xee654606, 0x40e85f16, 0x263a977a, 0xd20e8d65, 0x165e0058, 0x24270047, 0xdd87f8a9, + 0x1a84d94b, 0xd47a32dd, 0x092ab295, 0xbf178e28, 0x07d02d42, 0x0135a9bd, 0x178582c9, 0x0a120808, + 0x5acd88fa, 0x7b7d5ba6, 0x45e329a4, 0xdb0c41df, 0xd331af34, 0x3b6b5bb5, 0xbd0532af, 0xdd0665c5, + 0x069afa18, 0x1d8f6389, 0xeaae1b63, 0xf9d26a1c, 0x4bef725d, 0x432fa522, 0xf5c7ed65, 0x3e0b1a1b, + 0xbf5c2b01, 0x3e6304bf, 0x196e9630, 0xed630f05, 0x12310358, 0xebc6dc72, 0x221ebe31, 0x48e76f3c, + 0xcdddee61, 0x5fbf6c98, 0xb41a9274, 0x05c3437f, 0xc23f38f0, 0xb2407355, 0x96bd3f18, 0x1dc8858c, + 0x0bdb89f4, 0x374fae55, 0x0ca3ca5a, 0xa0459f48, 0x401fcfdb, 0x0a7ab7d8, 0x4c4f8080, 0x29956a4e, + 0x1fc559a6, 0x09bf84d5, 0xc4430e52, 0x08aa8f55, 0xb1ba879e, 0x05152b2b, 0xaeaa27ee, 0x448a28f1, + 0x860de705, 0x34f4af25, 0x9dde5085, 0x0b9c9ba3, 0x9aa90909, 0x7efaf908, 0x1c2b766e, 0x05966a61, + 0x35949f06, 0x2e0aed54, 0xce88bf74, 0x0d964a43, 0x8095370c, 0x789c9718, 0xb12587d2, 0x67252a59, + 0xc97f4610, 0xa7f03167, 0xb1c48923, 0xfc8ce646, 0x14b9b788, 0x045dca13, 0xb20ca181, 0x78f89886, + 0x1f3017b9, 0x8d5411eb, 0xdc06a47d, 0xd7059600, 0xd0252aef, 0xb53723f4, 0x9ce5d3bf, 0xf803c859, + 0xb80db44e, 0x033fe839, 0x972483f2, 0x63d1d872, 0x5aea345a, 0x2cba0d80, 0xf4d1debb, 0xb705add8, + 0x254db6dd, 0x49ae8607, 0x7737edaf, 0xdb93e1e0, 0xd11b7a09, 0xfb97743f, 0x15aa1a76, 0xd60040cb, + 0xada43913, 0xde185945, 0x8ff670ec, 0x1e3da19d, 0xd49030f3, 0xa86684c0, 0x0ffcd364, 0x4c3c438d, + 0x75bedd7a, 0x12c27fcd, 0xc32ceee0, 0x30543692, 0x874c10fa, 0xa440ce84, 0xca5e3d2e, 0xd0ad096c, + 0x413099c1, 0x8f43b19a, 0x6b47ca48, 0x8c4959eb, 0x37a5d891, 0x2be8f813, 0xa45e3cde, 0x40f962ac, + 0xdae279eb, 0xb9ed78e8, 0x0b1ce062, 0x8b002953, 0x9c463218, 0xc843e575, 0x561054cf, 0x7aee0db8, + 0xadc7dd3d, 0x19adeac0, 0x8b689f04, 0x9c2ef646, 0x1835612b, 0x81c29ad1, 0x6c5daaf4, 0xc8a820c4, + 0xc5832616, 0xd7f046d1, 0xbd20c43a, 0xc77ddce2, 0xef6ab551, 0xadb5e73a, 0x4954b166, 0x15825843, + 0x87409ec1, 0xc8c87671, 0xe4c78ff6, 0x2e311853, 0xd0280465, 0x81dca15f, 0x2ab855b7, 0xc96c2b66, + 0xfa80e124, 0xfb1c2f42, 0x9a5a9cec, 0x7eae94cb, 0x7cfdc531, 0x74136153, 0xc955dba3, 0x8b39e5fd, + 0xa16fb3f8, 0xc88641f2, 0x1068942f, 0x9bde4535, 0x001e35f5, 0x84bbcf9d, 0xce1cc929, 0x00261af8, + 0x02ec5796, 0x23fad8f8, 0x0aa3fef8, 0x03511f1d, 0x3a8460e9, 0xc0cf0015, 0x0788b17b, 0x5823206b, + 0x83111916, 0x9353bb95, 0x0ea70cd5, 0xdb1c2119, 0x2896ae98, 0x39a4ff51, 0x5cbf43a3, 0x38d6155d, + 0x3c089e83, 0x703b272d, 0x518401cb, 0xfdd1d495, 0xfebb2986, 0xa528ca45, 0x2f9f8292, 0x3b55ab39, + 0xe575a82e, 0x58a4a767, 0xecd5b226, 0xee20c93b, 0x21a94c90, 0xb31df24c, 0x882a7e84, 0x435a6f74, + 0xd3fdcf44, 0x36ab8583, 0xf8f27b0b, 0x7acff1f1, 0x297ce913, 0x62516435, 0x39eddd74, 0x8d4d7f28, + 0x95373fa2, 0x2cc2c088, 0x4cdac1ba, 0x0b4d5f7f, 0x05acfa17, 0x501908ae, 0x9cbddb5c, 0x10a4e2fc, + 0x31833203, 0xca3b3766, 0xcf8475ee, 0x0d7f3c40, 0x2726305b, 0xf39ecb8f, 0x88f0709c, 0xd5fded54, + 0x69ce9c4a, 0x9576f7c9, 0x1a6c0c8f, 0xe99355bb, 0xe8fc3e8d, 0x3bd2c095, 0xbd26d65c, 0x30e14d96, + 0xcc255db7, 0x710e9d4a, 0xbba18ff5, 0x70eeaa6e, 0x886e7d38, 0x9831002e, 0xa98c8e97, 0x1f9264b4, + 0x86b3df7b, 0x2ba6e190, 0xe65c15ce, 0x957b3506, 0xefcac18f, 0xcaddcf8a, 0x72bbf392, 0xf7174b59, + 0xcf5d0718, 0xd198cdd5, 0x6529004b, 0x8c34145b, 0xbe58a21a, 0xfe848ffa, 0x6e0b891e, 0x214852fe, + 0xd1ddec47, 0x3765c634, 0xf12d97c2, 0xd95ad576, 0x6c115269, 0xe6b3d4be, 0x62d34e3e, 0x181e9339, + 0xe31a4d0b, 0x70c123ad, 0x95fcc157, 0xeb27ed03, 0xf2691d14, 0xd8008a63, 0x19783a32, 0x28fb2255, + 0xb2ec9941, 0xf1c04a0f, 0x2e217541, 0x675cc7d8, 0x2057b2d0, 0xb442055b, 0x9b974c01, 0x4416e1e3, + 0xc983fd80, 0xc0b182cf, 0xfd209ed8, 0xaaaad2b8, 0xf6f6cc87, 0xbe897209, 0x3fca9855, 0xba315353, + 0x1b832d78, 0x8ef58a8a, 0x2a4cd664, 0x2f0b184a, 0x1c137f14, 0x6ab6bd4e, 0x8498eb28, 0x4db98680, + 0x63875072, 0xa84b38ba, 0xf3beeb19, 0x26e2b0c6, 0xad2e3e7c, 0x43fae3fc, 0xcff18bb1, 0xe89d0265, + 0x33fcdc96, 0x3bd12e8e, 0xf4b24769, 0xc40f5d42, 0xe1fad2a0, 0x41e97344, 0xb13d951a, 0xa6f661eb, + 0x6ddf4163, 0xe2e67c88, 0xf966f6c1, 0x70aac00a, 0xb0632df6, 0x8a899cc4, 0x3cfda54d, 0x08c1c7e0, + 0xd25a86d0, 0xf2ddd6d1, 0x64ff1cf4, 0xfe268cbd, 0xbf5cd03c, 0xee0c6a07, 0x1e6c92ec, 0x130f736b, + 0xcd73400d, 0xcc85ab64, 0x5ca8b84a, 0xebec5d04, 0xa16483d1, 0x9a626f1e, 0x04371941, 0xb215c2d2, + 0x74348d80, 0xc25210d3, 0x5bed8221, 0x80b01eee, 0xe2e8a49b, 0x1a5825fe, 0xcd0bb5df, 0x1b44a68a, + 0xdee5193a, 0xa47ea76c, 0xbaf837e2, 0x6947b542, 0x42f75e7b, 0x4e4df997, 0xf3cfc5b5, 0x0af2e608, + 0xfcadfeac, 0xe079edf6, 0xf0dc44c3, 0x67517331, 0x85db7619, 0xa0727339, 0xccae0a7e, 0xd413cc6b, + 0xd8ab380d, 0x6cdb6228, 0x0d2bcf86, 0xe284a214, 0x51ad5b2e, 0x243638ba, 0x65f9c0dc, 0x57d11aa9, + 0x6049baf1, 0xea7a5902, 0xb4582b8c, 0xfa5544d1, 0xb88e9949, 0xbe685fb7, 0x08fb0537, 0xb2f0057a, + 0x59ac99e9, 0xabb2dc6c, 0x265eb6d4, 0xdb0f22e0, 0x5151245a, 0x302c7204, 0xf78b54d3, 0x27e5f017, + 0x1a5012f9, 0xa5d43b49, 0xd97b15b4, 0x7b3c6744, 0xc6d67b9d, 0x44eae8f6, 0x45f911b2, 0x7b610ded, + 0x26274551, 0x7acb4043, 0xab5123c6, 0xc39cb6b4, 0xede7e127, 0xe49dc796, 0x7a354fda, 0xe021b539, + 0x7e446a4a, 0x0a345fb0, 0xb266d3c8, 0x35d1ff25, 0x0d8f8dc9, 0xc7fa3f51, 0x0d099c8c, 0x6f84e7bd, + 0x1f464447, 0xfb9876c8, 0x91791592, 0x72e97062, 0x3be2c456, 0xed431fe4, 0x1db3c297, 0xf342e340, + 0x41c2e98a, 0xee6cf8fa, 0x5f7d9c72, 0x0840d7de, 0x7c9452fc, 0x60d17209, 0xb979cc43, 0x1894f2c9, + 0x873e137a, 0xd363c49f, 0x15cc4b77, 0xbf29094d, 0xd2f416b7, 0x5578f78f, 0x7d656f0f, 0x72c6d5b3, + 0x6c61757e, 0xadf51397, 0xce761209, 0xcd7033aa, 0xf273716a, 0x3f45d9af, 0xe7bd498f, 0x1ea49362, + 0x154a5575, 0x06fd9f5b, 0xcd48c0da, 0xb78c2d14, 0xae420636, 0x7269b39d, 0x7a97ecad, 0xb5ad2287, + 0x50cde432, 0xe30d1f16, 0x1806644d, 0x77285925, 0x3e7bf7be, 0xb74db597, 0x873573f9, 0x5b12262d, + 0x6849799c, 0x8bf91290, 0x4a55777c, 0x69a2ec6a, 0xb92f5ca4, 0xe9a0392e, 0xbe7ea537, 0x365068ba, + 0x6f145548, 0x56a8603c, 0xa930e797, 0x5a164b54, 0xa87309e9, 0x028bfeb2, 0x85b3276d, 0x62e3622a, + 0xfd413de4, 0x5d162b19, 0xdc97bdeb, 0x8cb8e41f, 0x0a8e2387, 0x1225afba, 0x8273162f, 0x64e65c17, + 0x95a22ed7, 0x31b59dd1, 0x75e41fe7, 0x2d245df5, 0x767fe7f4, 0x81ceb525, 0x03ccd9da, 0xd1d67110, + 0x3df1c94f, 0xaece9e63, 0xf583840d, 0xb3599900, 0x93d121e2, 0xc00f256b, 0xa5b528a0, 0x363b31b5, + 0x3d632920, 0xf3cfd137, 0xe35721a5, 0x67b970cb, 0x38d8f332, 0xc28b80bf, 0x77d3f1b1, 0xce1f09ac, + 0x5e50e56b, 0x08c78a71, 0x7956a671, 0x653b11f9, 0xb58ab33c, 0xc1489834, 0x36eaa16f, 0xd1e672ee, + 0xadc3c7f6, 0x47260511, 0xa72adefe, 0xff40497a, 0x88493f0e, 0xccc7706b, 0x72533487, 0x34d8420e, + 0xf28f6d69, 0xd0a2a706, 0x11d1f020, 0x5f1d40d2, 0x992640dc, 0xbe219e6e, 0x8590e9e5, 0x5ed0701f, + 0x0f569bd6, 0x84989829, 0x53a87fbb, 0xff23f205, 0x5ad0006a, 0x0f45aaf0, 0x74c423b2, 0xdbaafb58, + 0x37ba16b3, 0x6194d8ad, 0xd94e07e4, 0x421455bb, 0x2f41d462, 0xd85d05a4, 0x14f5957f, 0xa6475415, + 0x43952a46, 0xe08c9a75, 0xbb72baec, 0x41bc5e7e, 0x41cfefa0, 0xda3b9423, 0x6f18b605, 0xe16dfbc0, + 0xac368160, 0xfa2d76f7, 0xb79573ac, 0xc4c622a7, 0xebf34e0a, 0x2f6884a3, 0xc4f2339a, 0x07506a00, + 0x5fa283cd, 0x1cc92e70, 0x60df23fc, 0xdc582893, 0xaac975ce, 0xe638e808, 0x73e056b3, 0xa923ea0a, + 0xccf88906, 0x9464a555, 0xd2a5a58a, 0x538cda04, 0x81758611, 0xa090728f, 0x58b3d1de, 0x58b5aa04, + 0xb261f9df, 0x268c4677, 0xd2fc8559, 0x6579a5b0, 0x6d834e30, 0x92c1ea86, 0x27922b8f, 0xe3e2423c, + 0x87254392, 0x583f2ba8, 0x849e3e7a, 0x2c3e5344, 0x3040a26a, 0xdf129413, 0x3bcbe07c, 0xb5c01f62, + 0xfb41dac8, 0x283468e5, 0x4553020c, 0xe5374c7e, 0xed6b22fb, 0x6ed2186c, 0x0274c2b8, 0x66c9fe2c, + 0x311bc737, 0xc3044484, 0x11c73ada, 0x55e64ca2, 0x0babc4f6, 0xadf8eed7, 0xed78400e, 0x6de78ccf, + 0x1336118c, 0x5f6350e7, 0xc5b8f4d6, 0xa319c2c6, 0x09ebabb3, 0x25d5c8d1, 0x25d46042, 0x9a288191, + 0xa2c09e3b, 0xb59f7ed1, 0x21e8916a, 0xeca807a4, 0xe266b93d, 0x0bed81ed, 0x77e0bb95, 0x83e03d59, + 0x3f2892a5, 0x2a61f854, 0xaa48be09, 0xb81ee947, 0x4ac9bbf8, 0xfeeaa7d0, 0xe4299431, 0xc053192b, + 0xdb53e9ab, 0x7556eddd, 0xb33a4975, 0x7ef47fa8, 0x097bf826, 0x400c830d, 0xb3adbc30, 0x1237058f, + 0xee550593, 0x3c04f431, 0x1cbccc10, 0x070b983d, 0x0633d187, 0xaa88ca97, 0xce02bcba, 0x28025b2d, + 0x95786ba1, 0xb30f2524, 0x8850c5bb, 0xaac1825b, 0x013e60d0, 0x6f67fb43, 0xaa536453, 0xd5cdcafd, + 0xbb600b9c, 0xe6d75897, 0xad034dfb, 0xc062eda1, 0xa9c61928, 0x7b243536, 0xa5d2a9ab, 0xf48a586e, + 0xac849cfb, 0xfbd0f590, 0xecc7a004, 0x3da6031a, 0x7d9d11f5, 0x7ac28fbf, 0x58a401bf, 0x5c63a625, + 0x42546f31, 0x21700ae5, 0x8470adf2, 0x3986fefb, 0xb93c74b6, 0x1350481a, 0xffedc8f3, 0xb1c84c09, + 0x35ab7614, 0x82a6ccd1, 0xc932c023, 0x2b4e215d, 0x2bdf2d0e, 0xf9bb0550, 0xcd3db017, 0x78074573, + 0xe2e3600d, 0x5f2f9116, 0x6c10c6c5, 0x39cd7f85, 0x1b840535, 0x55355d84, 0xca341741, 0xc8304632, + 0xfcfa3cc3, 0x662d617b, 0xf4d37465, 0x21f75411, 0xc6e8de90, 0x346023f1, 0xd2212dcc, 0xd4bb8d42, + 0xa7b289bb, 0x45e9a671, 0xd43e197e, 0xdabc82ac, 0x56ddf5e7, 0xd5773fde, 0xe67cbfbc, 0x65ab9f7e, + 0x40bf5fa0, 0x8654b577, 0xcef55a69, 0x78623c65, 0x72aaeb89, 0x47132a16, 0x88bc1d69, 0x7dd0a126, + 0x523217b3, 0xf5a4c50a, 0xed87fa42, 0xe92f0c14, 0x536af479, 0xc54886e0, 0xaf539b28, 0x3297f50e, + 0xbbe50084, 0x3a0797f7, 0xc5cf0d18, 0xe2af8cfc, 0x6bccdecb, 0xb2c62a94, 0x01bfe25c, 0xb1caa80b, + 0x0db75142, 0xfbb82ead, 0x351cb20c, 0xceca653d, 0xdd3c33da, 0x750f8dfc, 0xcae8f933, 0xc70d125d, + 0x8dad63b2, 0xe642e335, 0x3746371d, 0xeff96549, 0xc57efa37, 0x77457d06, 0xbb4059b8, 0x2631ff09, + 0xb4ed57bc, 0x80673d38, 0x58328b9a, 0x3207a804, 0xb191a931, 0x24655d93, 0x660d7b5d, 0x4d92f11b, + 0x831f05c1, 0xbf006ae6, 0x77e2050e, 0xcd2cd3f3, 0x22a31724, 0xa6052a5f, 0xef75a2d0, 0xfdaa1de7, + 0x7461ce4c, 0x1602ab8e, 0x072b0193, 0xa9b4f64a, 0xb1ec55fe, 0xf38642c1, 0x14ff2d1a, 0xa9f6ca83, + 0x727bd174, 0x7be1c525, 0x1b13f7d8, 0x77485267, 0x484df6d6, 0x478308d9, 0x59ba5830, 0x5034a81b, + 0xa9f6229b, 0xb08c6bdf, 0x24649cd3, 0x9888e964, 0x3fc397e1, 0x1d343172, 0x3732249d, 0x8fbf29b9, + 0xe55bfeda, 0x10f02e2b, 0x3fa90896, 0xf7d62c43, 0xcf678fa1, 0x9b10e391, 0xb5f78c90, 0x7f27ad21, + 0x79cffeb1, 0xd1747ef0, 0xdc53e23d, 0xe7c29acc, 0xebe2d2c3, 0x892d5349, 0x71fb8f4c, 0x4902aa24, + 0xaef447b5, 0x10cc35ef, 0x8c190b57, 0x279ea094, 0xdff60d8c, 0xce3e92de, 0x916bbd53, 0xa43a9ac2, + 0x35d906e7, 0xc898674d, 0xf5987abd, 0xcc4f593e, 0x86902cfa, 0x050b3d9f, 0xc7363328, 0x54c8ed25, + 0xdbfb3ec1, 0x3ed2ce34, 0xd341fc3d, 0x510a3c1b, 0xff3ca4d9, 0x4d43d776, 0x7f88d193, 0x26a6529d, + 0x500e3356, 0x64839795, 0xfc39a15e, 0xb9fbde96, 0x5843ea52, 0xcb415272, 0xa4291e14, 0x54efaab3, + 0x6952b339, 0xcf42dcb9, 0x3fa51b65, 0x3c763afe, 0x7c03994e, 0xc19e83cb, 0x5b91bc35, 0x77705de3, + 0x88db319f, 0x80719968, 0x2e9fd16a, 0x62aa566e, 0xe524bb1c, 0x9e553f0e, 0xe4a85efe, 0xd1fc7dd6, + 0x0a4f97d5, 0x7ed77c92, 0x29706070, 0x753c8c6f, 0x3ef36939, 0x0a077c79, 0xcd355822, 0x6222bbd5, + 0x1ff5c915, 0xca9e0674, 0xa76d67e6, 0xd0f43a03, 0xa355159e, 0x001c1e97, 0xe8369441, 0x7fd84d90, + 0x246d1d53, 0xbc574369, 0xdd9c305d, 0x9eddf7ec, 0xabab4b49, 0x8df8efd5, 0xa75b6f25, 0x43e88d3d, + 0x824e1611, 0xb7341005, 0x34e6571d, 0x0fbab1c9, 0xef4adc1a, 0xc736d90c, 0xc85034dd, 0x3c66f278, + 0x801eb00c, 0x8ec0d32a, 0xed271fd5, 0x5d282e0e, 0xefbc519c, 0xed72b614, 0x79c4b508, 0xfac4e1b0, + 0x7a2fc6ef, 0xf221a32e, 0xe5c4680b, 0x4ba10383, 0x00ac4adc, 0x3d5826f8, 0x87a06be8, 0xfbeee0a1, + 0x25bccb86, 0xf19c4de8, 0xa97784a6, 0xa16db7ea, 0x9f54d95c, 0xb467e0bb, 0x522c1797, 0x23ed1d3f, + 0xb40fc5a6, 0xba75122c, 0x37cb6a90, 0xc3c4f585, 0x133e6dd3, 0x9a0aa7ad, 0x80086949, 0xc561f70f, + 0x35bc3fa0, 0xff3df648, 0x94e54fc4, 0x03eed8b7, 0x6b5d47f7, 0x0173a1d4, 0x680496b8, 0xe510ef12, + 0xd2b2b2e2, 0x70bd2478, 0x38c7f9ed, 0xa2917cee, 0x5daff067, 0x8033529c, 0x3d92f9d1, 0x303d33bf, + 0x3a8c3940, 0xce7c259c, 0x4a5e1883, 0x327c541f, 0xfeb22ee8, 0x26ec7c3d, 0x0ccb3de7, 0xfc57732c, + 0x2044fb80, 0xfaa66280, 0x846d9ef2, 0x7256d69c, 0xb998dc67, 0xc5a542a3, 0x888a5b6d, 0xe41d7a04, + 0xc1cd4939, 0x149f0719, 0xbd3f039e, 0x30d65fa4, 0x252b3082, 0x10557fe3, 0x0fd15e65, 0x2b7952be, + 0xcf9e84f7, 0x37e41a92, 0x87dd3eae, 0x690bcfdd, 0xc17452aa, 0xca971a3d, 0x81bb591e, 0x1148e586, + 0x752220ed, 0x3b52dc68, 0x2eb5486c, 0x15e61fb7, 0xb7602635, 0x0a46787a, 0x77174f36, 0xb4b0f48f, + 0x170f8481, 0xe00bc1b0, 0x117725f6, 0xebbfc711, 0x9186bbe7, 0x3e13c8fc, 0x444abe6b, 0xfc11a206, + 0x8399c4ea, 0x0dd76c51, 0x92d6b31d, 0xfc03b587, 0x2477a7f5, 0xc5d71c81, 0xa60cec01, 0xe4c015fd, + 0x1130ea7e, 0xc76a060c, 0xfe43cfbb, 0x5a41261e, 0xf9ba7939, 0x1d3d28eb, 0x6738bc5e, 0x7cec91a1, + 0x960eb3e0, 0xde589817, 0x93b5b7f6, 0x2673eb1d, 0x15253ba2, 0x2b498436, 0x60181f0b, 0xf1222f60, + 0xc819c75d, 0x88330000, 0x7fc266c0, 0xf221e9fa, 0x6e465db8, 0x59e973f9, 0x0036f333, 0x7b317eda, + 0x8fc3db45, 0x7d9ab1b8, 0x1567d66e, 0x5fb76b36, 0x8fff52f1, 0x9f04a49e, 0xc10a5bef, 0xffe4253c, + 0x4e1c3d68, 0x56207454, 0xd9864a46, 0x4cd70dac, 0x7327e4d9, 0x687609a9, 0x46f38794, 0x6d722f23, + 0x5eb60533, 0x9be469f9, 0x73c8a898, 0x85cd5322, 0xbd7eec09, 0x3130c702, 0x060f939c, 0xc3982343, + 0x87d3f64d, 0xfcd30970, 0x4dcb68c7, 0xf8d80b69, 0x4f739e21, 0xe7998670, 0x3b4aa9ee, 0xbf67cc72, + 0x3460d674, 0x31a12e32, 0xf9b00a89, 0xcaa75224, 0x8ad60f21, 0x201e6fa9, 0x2772c5c2, 0xa29b6bcb, + 0xf6e73915, 0xbc5dacc9, 0xc811c527, 0x23967865, 0xe5c4a050, 0xd63e8676, 0xde0b5d01, 0x3c489a62, + 0x39a759bc, 0xabe99692, 0xf5e6af7b, 0xd55f8a0b, 0xbf3a90f5, 0xcce124ad, 0xcefadb07, 0x791b6d52, + 0x71738041, 0xac43aebf, 0x8e865f92, 0xed46a88b, 0x90cf5445, 0xa6ef55d9, 0x58cf88af, 0x2cbaf2de, + 0xbf405daf, 0xbadee4dc, 0xd4111db0, 0xf95cd43c, 0xd14f09a3, 0x0127526f, 0x393e14e2, 0x85034be7, + 0x6bca3397, 0xdaa6bb33, 0x2b85195b, 0xc09e2017, 0x37a1a785, 0xc2c40f53, 0x20cf082a, 0xf51b0761, + 0x84e44af0, 0x5581db4a, 0x4cb0d8b6, 0x8e8530a1, 0x067aeb1a, 0x3646c75c, 0x4637af25, 0xcdf58369, + 0xb26ceb3a, 0x53238d8a, 0xaa204779, 0x84c9ba87, 0x380c29bc, 0x760d752c, 0xb24ae3e7, 0x7f7727a3, + 0x677e6e1c, 0x2b3e8dda, 0x97ff34fb, 0xd448b401, 0xc8bc56ad, 0x9485ca82, 0x3ebd9825, 0xa4ef5719, + 0x2eb8cb17, 0x3be7a92a, 0x741ca25d, 0x57cb76e6, 0x487d09c8, 0x906907a5, 0xfa5d8afd, 0x30c6b228, + 0x526b587b, 0xa5fcf61b, 0x33a9d053, 0xc3c07be2, 0xb2d2ff2c, 0x4ed12386, 0xcd199ab1, 0x60ff54fd, + 0xeec3c14f, 0x3ed887d3, 0x5620797e, 0x6ef53aea, 0x93fc83f7, 0x23e8afb5, 0xbf9b4bdc, 0x01f9904f, + 0xd353ccb8, 0xa2a581b7, 0x2f28d846, 0xb0e902cd, 0xc0a6425c, 0x2dcf79ad, 0x9fd9b497, 0x0197bf8a, + 0xc2e3e203, 0xa578850a, 0x8bb355d7, 0x766b40e0, 0xcb6dcaae, 0x402aaa4a, 0x47aa554b, 0x52f6275e, + 0x6fbbef11, 0x34bbb4cc, 0x1995a13e, 0x344ba609, 0xb188a323, 0x539dfba5, 0xf97a44a1, 0xdd03f343, + 0xefe0e0cd, 0x7f377d7c, 0x919e2449, 0xbeb91325, 0x6873e866, 0xc709192a, 0xc8ec52a7, 0x15b341f4, + 0xdf33dc14, 0xfb54dd01, 0xbfd66ac0, 0x6ebbb89c, 0x52fedd56, 0x01586391, 0x17b52a25, 0xce92f6bb, + 0x1fb93b89, 0x5fa808b7, 0x2b69dd7d, 0x032c4988, 0xf555ce7c, 0x261a9734, 0xe08c0b82, 0x11de9a06, + 0x4a15c89b, 0x3ee07320, 0xcb1fb1f7, 0x22482026, 0xe3527b21, 0x6f802a89, 0xf742c6cf, 0x18f081fa, + 0x878af21f, 0xc16a718a, 0xf5312cd8, 0x54aa75aa, 0xa77ce744, 0x0b8f7a87, 0x24f2450e, 0xae890def, + 0xd07638b3, 0xedd4e545, 0x515dd4ff, 0x59238620, 0x7f20cbcc, 0x4134a109, 0x6fb66962, 0x2dd49185, + 0x4f4cca72, 0xbc1a3f36, 0xfe60a5fa, 0xd6f7d5fb, 0x5ffcd6d8, 0x126a214e, 0xfb18a384, 0xfe8fbb27, + 0xb0861b77, 0x7c9e10f2, 0xb2ac5f74, 0xaf7a67e1, 0xd7a60651, 0x2d334ecf, 0xb8902fc9, 0x2ba4f80f, + 0x617036e0, 0x8bf435d0, 0x76ba84d4, 0xe9522df9, 0x504e5bb0, 0xa4847c25, 0xcb81b122, 0x6133cb8b, + 0x11938887, 0xec3c2c15, 0xc96eefd4, 0x35b39185, 0x6a643c91, 0x8d2b1354, 0xae1fde22, 0xcb7571b0, + 0x15af5200, 0x49a3ddcf, 0x2826c469, 0xcd3ee5ea, 0xeba698e4, 0x14c158a9, 0xf4e77698, 0x72af25eb, + 0xf14d953c, 0x566cf098, 0x87151f57, 0x9d2bea0d, 0x8430ca22, 0xb08589bb, 0x385aa9e2, 0xbf84f846, + 0xab06e47d, 0x476a2617, 0xef619fed, 0x459fccd4, 0x39933afc, 0xf7bc61b1, 0x01add611, 0x8ec77f3a, + 0xc37a4c34, 0x0a11e1c9, 0xa6612ae9, 0xfabfcd1c, 0xbf983915, 0x6f37afc9, 0x916792c9, 0x9633afb9, + 0x4a9521e8, 0xf38db0ed, 0xc1471f2d, 0x3bb42f42, 0x78b299e0, 0xee91c850, 0x9fbce752, 0xf1de9e4b, + 0x087d4eaa, 0x3c108043, 0x5448d410, 0x5b2c397f, 0x314f7458, 0x661d3567, 0x0c385a6a, 0x965bebe2, + 0x1398a5fa, 0xc97a44be, 0x2a29c1a7, 0x1b68f6a6, 0xacc69a4b, 0x682e2c3d, 0x7e9d79d6, 0xd2e5349c, + 0x14695865, 0xdef83e81, 0x45d5716b, 0xd9ae5992, 0xef54e671, 0xd691f858, 0x4afb7c05, 0xcc236b52, + 0x42436fdd, 0x7bf258e0, 0x2d19cc83, 0x5fe80b07, 0x39d8f2b6, 0xd394cbff, 0x6aa10510, 0xbf02ffe4, + 0xdb534125, 0x04bff12c, 0xa34fa133, 0x8f32edff, 0xa620c0a2, 0x641f52e5, 0xdb4497fd, 0xe8156630, + 0x79042b2c, 0xc2eb13a6, 0x6025c078, 0x99ddb7b6, 0x98aa4f5d, 0x635633e5, 0xd53fcc95, 0xa8de231e, + 0xdef9c6aa, 0xdbe7cb27, 0x6f54a9b6, 0x0c8fbf47, 0xb47e8081, 0xc2379343, 0x196cbf4c, 0x4e09daf4, + 0x9ce0edd3, 0x70d08728, 0x1c90bc01, 0xe86e5292, 0xd1eb3229, 0x5cb2eeed, 0xa3ca072f, 0x311333b5, + 0xc7f129f9, 0x71e29359, 0x0b8df529, 0x848e4ae6, 0xfbba3417, 0x012c200d, 0x4859f5bd, 0x7daa0b38, + 0xba8286de, 0x443d54bb, 0xf83ceaef, 0x8c0ef6cd, 0xd122f37a, 0x647830c5, 0xe2b3bf64, 0xafe8e245, + 0x043abae0, 0x80b0295b, 0xaadd4481, 0xf20b21e9, 0x2d9f3bd7, 0x2a7619e5, 0xb6c95d0e, 0x8e591e48, + 0x2b858ebe, 0x8f8f552d, 0x11c633d7, 0x1bd25ce7, 0x4683c4cb, 0x7c89d91b, 0x4dc647ab, 0xc97a0fae, + 0x15e6a778, 0xab153741, 0xf2dd0b1d, 0xc08584cd, 0xdb760137, 0x96cb0666, 0x9e8aaa4b, 0x654298b7, + 0x22cb5109, 0x80aaa2c8, 0xa7726240, 0xca9facd8, 0x268a806f, 0x254b8816, 0x9a8270f3, 0xf2675963, + 0x958e21c4, 0x39b76d8a, 0x22c4259b, 0x0f638883, 0x15bd3732, 0x26fbd267, 0xdabc8a97, 0x4de8f353, + 0xde61f333, 0xdc58d6ed, 0x99564780, 0x674472e3, 0xc134b083, 0xec481d8d, 0xf1bb0721, 0xe2f39925, + 0x7f3a4ba1, 0x53477fc0, 0x8d8a707a, 0x766fd45f, 0x8fca0c66, 0xef55f70b, 0xff7e7b1b, 0x8c948ec9, + 0x0ed677ae, 0x1cbba5a2, 0x4f177bf1, 0x741b236f, 0x281d1df8, 0x2d17517c, 0x9251a5ba, 0xb33dfb66, + 0x25558940, 0x95dfcd28, 0x01ee51ca, 0x5a63c15a, 0x7aa87180, 0xd2a293fe, 0x5a99a820, 0x2d33a300, + 0x9f5b1906, 0xba267482, 0x05a5c9c1, 0x91d426f3, 0xc9d2b454, 0xef5ad8aa, 0xc16387aa, 0xb58a727c, + 0xd9c5b394, 0x0967e8c8, 0x66ae2166, 0x52177010, 0x70e04613, 0x291ed265, 0xd0d15923, 0x68677885, + 0x88d1423a, 0xa6305ced, 0x4e5be4a1, 0x5acc0ecd, 0x27a7e4d1, 0x546eb98c, 0x9ebbaf95, 0x86e69c55, + 0x0f0153c7, 0x8911bba4, 0xea4b6db4, 0x062ac7d3, 0xad70eb7b, 0x53b05db5, 0x9932095a, 0x602b7926, + 0x4b7f9b1c, 0x0bb339b4, 0xf16d2b2f, 0xbdd02602, 0xcb13d72e, 0x33a30c86, 0xc14625ea, 0x0bbfad52, + 0x25424c7a, 0xd7a5e535, 0x3293364e, 0x9678ce98, 0x09b59b04, 0x3553f017, 0x0e32292c, 0xfee01fc1, + 0xb7366ecd, 0xb3a2b581, 0x9eff60ef, 0xf6b2047f, 0xcd097fad, 0x420f19de, 0x7f876229, 0xcfc65e23, + 0x544dcc45, 0x63cbd3da, 0x2da958f2, 0x570c0949, 0xc6add6ac, 0xc043d3e6, 0x90dbfb4b, 0x2eb19801, + 0xae2df8ef, 0x68c84d9f, 0x27c18a06, 0x26f1065e, 0x42fcae28, 0x47e10a51, 0x7de82566, 0x857012d3, + 0x65bb14de, 0x0264b312, 0x64a7012e, 0x39d25f2c, 0x626531f9, 0x4dd75559, 0xfe04e759, 0x5a342a13, + 0xd974496a, 0x835b7190, 0xaf1a0d67, 0x8e75d543, 0x0c2c1c2f, 0x82292b1c, 0xad83a5e0, 0xd6dc50d3, + 0x0dac20ee, 0xa09327bc, 0x989bc3e2, 0xc0c0646e, 0x2b31e2b9, 0x844dc3ed, 0x1fc4dd1f, 0xd1558a27, + 0x38161524, 0xea380751, 0x46785d69, 0x1f79dba4, 0x0b880cfe, 0xdde99b68, 0xe161a826, 0x26e93e28, + 0xe91ba44a, 0xd7ccd17c, 0xd1103f72, 0x158ec2a3, 0x90a5fbd2, 0x0e371cb2, 0x5ba4c3b0, 0x54ffe47c, + 0xad0b8895, 0xed2bb505, 0xff212da3, 0x5dbfef17, 0xb2fbce06, 0x056f2e30, 0x91a7d899, 0xba6f133f, + 0xa538c8bc, 0xac145a43, 0x01ae20ee, 0xf486b731, 0xf5439275, 0x1e2ac76a, 0x62edb6ad, 0x0c3216a9, + 0x31fddec4, 0x5322cb90, 0x62ee4008, 0x1bc85261, 0x4def7c54, 0xf9066ed0, 0xa14225c7, 0x3e6a3315, + 0x8d8c043c, 0x0d4f44ea, 0xdce1763a, 0x0440f924, 0xe636de58, 0xf9441fd8, 0x314b699b, 0xea8cd720, + 0x84341ab1, 0xa8e2dbcf, 0xefd25c2a, 0x583d9e39, 0x47f92a9c, 0x287085af, 0x7b1301a0, 0xc3063f58, + 0x6d27ae4d, 0x7bcca4c3, 0x50ec5f59, 0x25a377b3, 0x487a6396, 0xe9722f80, 0x3476e532, 0xbf0410ed, + 0xcce9ecca, 0x243cdeba, 0x591eb67f, 0x145e6816, 0x5b9ab38b, 0xe87c2255, 0x2a1c3baf, 0xa76af31a, + 0x0c1ed7aa, 0xcdab2dbf, 0x1a97e924, 0xc54ed41d, 0x02940c50, 0x6bf69de9, 0x887d699e, 0x40900481, + 0x0b967abf, 0x344b2953, 0x6105c17f, 0xcde4db3a, 0x31688c50, 0xa6464fab, 0xe142102c, 0xfdbf46f8, + 0xb69dbec1, 0x8d12ef0e, 0xf00d7358, 0x4a755df5, 0xe8408334, 0x8b4ffc26, 0xba3be208, 0x51388537, + 0x5942af27, 0x9753833e, 0x148e746d, 0xc025b3b3, 0x73752b33, 0x0f07ff8d, 0xed981302, 0x0f87275c, + 0x29490838, 0x07a90f48, 0xd23b894d, 0xa4835fea, 0x3ced4772, 0x39b7ad56, 0x5d3cd379, 0x6cf5770a, + 0x27322e5c, 0xc7d6cfdc, 0x1483173d, 0x51784190, 0x22aa8a29, 0x88794cf1, 0x9a3ea800, 0x2c2d354b, + 0xc191cc15, 0x9e85f3fd, 0xb0a129dc, 0x3a49e5dc, 0xc0f502cd, 0x7290b30e, 0xb76b4f90, 0x5d2f8661, + 0x0d469aff, 0x9af94905, 0x31cb0a15, 0x53aa1bc0, 0xba8ae3f2, 0x6c712fbd, 0xf7f56ee2, 0xefcb064c, + 0x5a279018, 0xab6ddeca, 0xcb94dd7f, 0x91d92802, 0x71c3d804, 0x681829a8, 0xae98d312, 0x541256a6, + 0xf4f4fb9e, 0x07d56bf1, 0x5bee815c, 0xefa6240b, 0xa372e768, 0x7bf2ae20, 0xec1dd814, 0x07792d6e, + 0x56d93880, 0xa992e0c3, 0x51abfb77, 0x1608e935, 0x91071aeb, 0x6b0e19f1, 0x74d9f9bc, 0x4b0c56bb, + 0xc297e657, 0x848697a5, 0x25a637a8, 0xee8f3582, 0x055b31e3, 0x0ae4da37, 0x3c56d1f1, 0xd28477e2, + 0xc86774cd, 0x91b9d2e4, 0x90ffac87, 0x87595fff, 0xac516100, 0x3d24bdae, 0xd407e733, 0xc7171a6e, + 0x46f9fb0e, 0x1d054e7d, 0x1e3f949a, 0x1621948f, 0x83fd09a4, 0xe546b706, 0x6533144d, 0x18bb7bed, + 0x716e5fef, 0x6459a7e6, 0xb479cd9c, 0x8bffe8dc, 0x9bcc3152, 0xce4e1bb7, 0xbad7e10a, 0x03b5e1bf, + 0xf5c738eb, 0x9881ff4b, 0x5e0522e8, 0x1131ee80, 0xf3430cb6, 0x3cce98b8, 0x338fa769, 0x9091f629, + 0xa23b678d, 0x7771667c, 0x2c7f116d, 0x3c70a948, 0x0fe5c586, 0x1583a762, 0x86b37050, 0x06a87741, + 0x8f5fa979, 0x23946fcd, 0x6594d354, 0x0e051938, 0x6639d169, 0x9b3ce123, 0x6c8b6467, 0x47ea2438, + 0x523c4694, 0xd99ab6e0, 0x85889f0b, 0x7b59188f, 0xce9e0376, 0x1d4ef953, 0x47ab8d84, 0xdb430cac, + 0x1251db9e, 0xbe50d7af, 0x8e504675, 0x7b6d419f, 0xa8d653c8, 0xa433f4b1, 0xce2e462f, 0x0360fc9c, + 0x858d354b, 0x216efb60, 0xe78e7f5c, 0xcb4dfcb6, 0x0c15bac6, 0x96d5a3b9, 0x564c0179, 0x401d04a9, + 0x5dacc10a, 0x0ab89cb0, 0x172a281c, 0x4ba8f579, 0xd818651a, 0x854848e4, 0xdbf52f8a, 0xa4053238, + 0x8bc520b9, 0xcf321ca8, 0x6f3c171b, 0xab7db319, 0x48dc2bbc, 0x27f88c45, 0x21e2dfcd, 0xc571d503, + 0x5add06e6, 0xe8aafaa5, 0x188e8d9b, 0x3bead852, 0xcf48a81f, 0x6d9558bd, 0x4f01b05c, 0x6b232e7b, + 0xba49478f, 0xf2674166, 0x6858a5f9, 0x02fd1b82, 0xbda94e86, 0x8fcdb35c, 0xedd1ec90, 0xc82b727b, + 0x6c229d2e, 0xb7e19238, 0xe6506012, 0xf2fbaa41, 0x580afd30, 0x75d6d717, 0x28403157, 0xb7b07c41, + 0xe471cb14, 0xbfbd4668, 0xe80b0a67, 0xdd60fc8e, 0xe72623c4, 0x63ce47af, 0x137f4d70, 0x08afe81d, + 0xfab80bda, 0x596a2f46, 0x8aec74de, 0x63b87c03, 0x22802a97, 0x9bf4fc1f, 0x045aa55c, 0xb7bb03ad, + 0xe7ef7a0a, 0xc193b2d6, 0xba593b43, 0x9e124054, 0xa06e6182, 0xeddf8600, 0x09429dbc, 0x58ec94e6, + 0x2003cda8, 0x03da3418, 0x2c9dec49, 0x4e050467, 0x4118661f, 0xd0d38d32, 0xa4bd4c63, 0x3251f606, + 0x163fe733, 0x1e95f412, 0xfe3c367a, 0x027ef917, 0x17b7394d, 0x24336112, 0xf23fcade, 0xf33b4965, + 0x84bd6ae6, 0xffdc2bef, 0x2d4a2ccf, 0x32fa86f6, 0xd9b4b9bb, 0x2477bd05, 0x04933f95, 0x873bc43a, + 0xa6bf58e4, 0xcf8e0df9, 0xb0e0f5f2, 0x45aafc73, 0x60c87c76, 0xc71da6b0, 0x38019c99, 0xd06df12a, + 0xaf8f69b0, 0x85aa4467, 0x0a39f760, 0x8a58ab03, 0x7aca5fad, 0xd6203327, 0xd4f15c91, 0xa20d1497, + 0xedcbd6ac, 0x38f330f8, 0x7abd40ba, 0x3f84cce7, 0x444d2c05, 0x396a67e5, 0x30ead522, 0xa35635f4, + 0x3967c293, 0x6d0a8f4b, 0x4230f05b, 0x3d3c91ab, 0x4b416382, 0xaf2c494f, 0x9792182d, 0xaf08addb, + 0x8fbf081b, 0x0cb8d924, 0x0be12df7, 0xca89bcfc, 0x6e984e19, 0x0270a9c5, 0x1cddac56, 0x5106700a, + 0x3bc82de2, 0x5fa32409, 0x10579325, 0x6a14b9f7, 0xbc6c30b5, 0x864685a1, 0xa1f93fb5, 0xed666838, + 0x70e75619, 0x258af6c0, 0xbeb2c70e, 0x16b154a5, 0x53af6921, 0xabbf8ae0, 0xd47c35dd, 0x8c07ab7f, + 0xa529f446, 0x2eea7b2f, 0x0847b93b, 0x733941b6, 0x655e02a4, 0x47e4aedb, 0xf034aa45, 0x5cbeb65e, + 0xf918b36f, 0xa07fd2db, 0x31354922, 0x1a871b83, 0xfd3fd073, 0xcbff4e9a, 0x0248ca60, 0x9eb6f1d0, + 0xf11c03d9, 0xb2390722, 0x690ca67f, 0xd225634e, 0xc2916d75, 0x975c1853, 0x1aa2e435, 0x91a5a37b, + 0x049ee9af, 0x03952107, 0x1cb9dec3, 0xa7b7c2bc, 0x652e123e, 0x518efaa0, 0x9a63411d, 0x26706e4a, + 0xc2b2327d, 0x81b3c71e, 0xc94a64ee, 0xc8d0f7c0, 0xc930fac9, 0xed4e7bdf, 0x17d8b81b, 0x9ea2015e, + 0x276ed18d, 0xc8961f8e, 0xa25248a3, 0xf7fd3b03, 0x6616be5e, 0xea963e8f, 0xfbe66e6d, 0x28b97c0f, + 0xed6a4a31, 0xc3e9fc24, 0x4198dc6f, 0x72c3b585, 0x1959a100, 0xc7818aed, 0xfcc689bb, 0x889124d1, + 0xe0b85acc, 0xa2af8a09, 0xe10749fe, 0x004ee4a4, 0x05c39098, 0x88b978ff, 0xb63cbb60, 0x34b40465, + 0xc835b37a, 0x22f9f945, 0xfcd2e762, 0x449af8e4, 0x9a46015a, 0x87fa87e3, 0xd144d341, 0xd66b356a, + 0x50e00f39, 0xd3a5dac6, 0x0e04d0a1, 0x8d9c8924, 0x85513c49, 0xdc4e5aa8, 0x8322cb83, 0x9de7c2e6, + 0x2f8b0aa2, 0xa68b25f1, 0x0f6225a2, 0x900d26d3, 0x035727f5, 0x51caead9, 0x422a89fb, 0x8a5cd7af, + 0x6b54477c, 0xe3ddd4ff, 0x62d0df43, 0xc6859af7, 0x63f24ed3, 0x6756da8f, 0x149f843c, 0xfe593e6a, + 0x28658148, 0x9c5af6e4, 0x6a3d9517, 0xf86f07b3, 0xa87927e1, 0xee0a8452, 0x15752d85, 0x09fbe958, + 0xd7eb9a88, 0x3883cff5, 0x15192cec, 0x1288eb40, 0x314c0038, 0x69d8ed28, 0x3c09470f, 0x7e0373a3, + 0x78f4b7c7, 0x9e342534, 0xbeb6f440, 0xe5b6bfd4, 0x0cd307f4, 0x5373ff05, 0x7d009289, 0x2166c330, + 0x5e5ee0c8, 0xb8965ae1, 0x18f45bae, 0x6771c2a6, 0x163ddd4e, 0x1dc98bc0, 0x507040b8, 0x91acbe93, + 0xcdefb08d, 0xceaf4cc4, 0x048be8ff, 0xe49d8b55, 0xbef4017b, 0x3dafe0df, 0xcf9e3e57, 0x73adef12, + 0x6c5a2441, 0xa80bb316, 0x3ca9981e, 0xbdbd9090, 0xc4f01e11, 0x5d3b5d7d, 0x0d781b44, 0x9473080d, + 0x1d5d1cd1, 0x0ab59d70, 0xf3039c8e, 0xf589d6bc, 0x7285b85a, 0xbcfbf54f, 0x35861169, 0x7f205649, + 0xb8577c11, 0x46fc31b0, 0x8c0caef3, 0xe444b29f, 0x2d90e281, 0x6f8d0843, 0x102476cc, 0xbcbaea79, + 0x256fbc33, 0x446555c6, 0x09d8b55c, 0xf36ff22a, 0xa495f9bd, 0x7677152f, 0xc379d36c, 0x3a3aca9b, + 0x8410235e, 0x62d7f57a, 0x757df850, 0x5e50ea15, 0x322d42c8, 0x88fbbea5, 0xbd096b9b, 0x789ca5ff, + 0x7068e5a4, 0x68bde2e3, 0x5a23ac0d, 0xc2bb7ce9, 0x9e40d78d, 0xa4660fa8, 0xcfe9bf00, 0xb2a36a7a, + 0xc5da6ed0, 0x86f20718, 0x1e17c933, 0x4c65b1fc, 0xbd680163, 0xa1c81b17, 0x8f8f7668, 0x492de05d, + 0x836bb273, 0x590b174d, 0x259156d2, 0x8b6b52f4, 0xb9d489f4, 0xd91e7a43, 0x03bb5172, 0x19b96d36, + 0x3e59dfdd, 0x4681d830, 0xbb69e1da, 0xcfe559f3, 0xe3159923, 0x889af0e6, 0xa39bd3bc, 0xf0fe717e, + 0x49e07278, 0x1389153f, 0x7701cf00, 0x50ffe40d, 0x2139e599, 0x2aa1a7b2, 0x896eedc8, 0x3571afb1, + 0xb9637dd6, 0xebb17b6a, 0x0621eec8, 0xd7283b63, 0x62cd696c, 0x3b954ab8, 0x81311907, 0xdf02fc91, + 0x4f97b47d, 0x3c2e94f9, 0xcc1e217f, 0x8f0a56f1, 0xa3bc1b9c, 0x9a556961, 0xc184cfe0, 0x95fb8256, + 0xb980d121, 0x4c316e94, 0x0f9dd76a, 0x22937be8, 0xc6d59882, 0x4cd9c4a9, 0xd89c8709, 0xca85c636, + 0xfc9480ec, 0x3003b87f, 0x76713130, 0x51e707d6, 0xc1c91fca, 0x4a002fcd, 0x22f5e198, 0xbbb942c6, + 0x785f7725, 0x07de2988, 0x351bbf31, 0x1bdd5a91, 0x399df2c2, 0xe1425733, 0xfe05062d, 0x134c866e, + 0x54cf4126, 0x57e51869, 0x2192f33d, 0x9c2655f7, 0x61ee32c4, 0xf49318ca, 0x2f9d7fcf, 0x4cca696f, + 0x746a4c9e, 0x27a355f4, 0xecbf2487, 0x80834b74, 0x9eadfc85, 0x6805e838, 0x472679b3, 0x669a25ab, + 0x5c3f6440, 0x6fdf3c94, 0xfc25cc7a, 0x94a49139, 0xdb920b95, 0x9906a8aa, 0x9c82fa88, 0xc240135d, + 0x7812e3a5, 0xd9ca82a8, 0xf4da5f68, 0x1b4ef310, 0x3d3ef034, 0x1b1a1ba9, 0xe486f1fc, 0xc858d7d8, + 0xc655b9df, 0xb9357441, 0x0de0b67a, 0x934b0c16, 0x73f3b180, 0xd55f1391, 0xca637cbf, 0xca5359a8, + 0x226dbe19, 0xaf9f3881, 0xe827206d, 0xa0a3e7bb, 0x5b6d9298, 0x2fc46f77, 0x4e714611, 0xfa60c8c4, + 0x3119b307, 0xc74bcb3a, 0x3190621a, 0xdc6fed9d, 0xd75fb7d0, 0x22a5eaa4, 0xb4e81f24, 0x78da80cf, + 0x974ca194, 0xa90a8688, 0x8a4ca7e4, 0x08d0caa1, 0xd472b427, 0xa100de46, 0x80777cf6, 0x5cc784bf, + 0xc18f3e48, 0x9bfc87c9, 0x9f8243e3, 0x5bb2823a, 0xb7507978, 0x75fbf5fb, 0x8e5748de, 0xdcc74a64, + 0x54ad4d7f, 0x39252898, 0x1e2f1b42, 0x4b33cb54, 0xa2373c02, 0xe1c18b78, 0x55f7b01c, 0x7a03f1ce, + 0x081f1f2e, 0xf658005f, 0xb0d8c2dd, 0xc6ca9942, 0x5d6ba443, 0x573251b3, 0x52c71a84, 0x69c0c54b, + 0x05d7e2a5, 0x57a59cb4, 0x6100a2e6, 0x1bea17b5, 0x78e1b405, 0x5606d321, 0x098aea4f, 0x449e0159, + 0x7279a803, 0x535ecf35, 0xa938a91e, 0x183ce6e8, 0x732238b4, 0xb94b9d61, 0xf5b4c4a6, 0x016313c2, + 0x3ecb457d, 0xe18c2c3e, 0xb83583a1, 0x468e33ac, 0x99106489, 0xd7434965, 0x8d655b14, 0xbb7da9b4, + 0x849f509e, 0x387d03f9, 0xa9f730c7, 0x4378ae04, 0x1e625c23, 0xedf7f8e8, 0x3d546417, 0x18306662, + 0x2ec715fa, 0xd371514c, 0x0a7c838e, 0x5ec279ac, 0xa764e4c1, 0x1649bd39, 0xc2a017d4, 0x1885a6bb, + 0x27d3d554, 0xb0c05cf5, 0xe7270b98, 0x9794c31a, 0x41f3ed12, 0x54d0853d, 0x45cf5d2c, 0x2afa7a1f, + 0x0799eb29, 0x7595851f, 0x92a7478d, 0x0a658477, 0xa9603fdc, 0x06d75ad2, 0x67bbd3b0, 0xff1e7a0e, + 0x853096bf, 0xd7d5d89f, 0x8736719c, 0x9e758ef8, 0xcafbef3f, 0x040b8562, 0x45db8456, 0x713817d0, + 0xd59893a8, 0xb3f3e71c, 0x48510e89, 0x9597872e, 0x0f4af0c2, 0x45931746, 0x95de0ee0, 0x8fd130a7, + 0xf25fe882, 0x3be67f3b, 0x595171c5, 0xdd4f9f17, 0xee8e5955, 0xbcf2a1dc, 0x2884f857, 0x01a7de37, + 0xbc2da997, 0x45300669, 0xba4573d2, 0x2a03bd7e, 0x42db1cdf, 0x525098a3, 0x04261d84, 0x995e55cd, + 0x352fd7f0, 0xdaeec6d4, 0x44ed2a47, 0x96364cc3, 0x449474b0, 0xf494fde4, 0xd1fffa2f, 0xb7f402a6, + 0x901806db, 0x2d8a44e0, 0xabd3a243, 0x536bb3d3, 0x3ae6946e, 0x242dae46, 0x55ade26d, 0xd583e47d, + 0x2091906d, 0xaf76d6f0, 0xf2acca30, 0xda6c3ac2, 0x4b392f89, 0xdabe6ebe, 0xbaf015a3, 0xea908d41, + 0x80553d7d, 0x2ed37b1c, 0x95f9f589, 0x8d515c5b, 0xfa1b02b9, 0x7c6ae969, 0x3b96c2c5, 0x3df7aec6, + 0xb72167e4, 0xaefa00fa, 0x7bdbf8e5, 0xa4caca21, 0x054a7827, 0x1c829a3b, 0x68281b5d, 0xd4aefa77, + 0xb2e52182, 0xd61f6638, 0xa5d14a11, 0x3f2f4e6f, 0x9d7d1291, 0xe288fc3e, 0x60aba6df, 0xee03317b, + 0xfaf6a934, 0x7c31085a, 0x6b392b56, 0x91634e14, 0x52ab6ce4, 0xfb78161f, 0x62d6b1c6, 0x9fdf0375, + 0x30401ab2, 0x6e7df851, 0xa8039602, 0xcfdb2292, 0xc4154e6d, 0x4ac4c9e8, 0x40cd2e66, 0xac84b93d, + 0x35b6340c, 0xa74dda3e, 0x89b99334, 0x7d237820, 0xa59e81fa, 0x79480f3b, 0xe7906240, 0xee1d99e1, + 0x3af94aac, 0xe537625d, 0xfcdefc53, 0xea15996a, 0x30cf8415, 0x414f6417, 0x4f2d2d04, 0x9ecf5d6f, + 0x3b3ebfa4, 0xb607cfda, 0xd41445f7, 0x3ae110c9, 0x95bd3c08, 0x6c1c3f1b, 0x046c92a6, 0x419301cf, + 0xd27aa579, 0x6350cfbb, 0x70238a2e, 0xb38b2050, 0xb0d96df9, 0xe69413fa, 0x8089d388, 0x4d9b1df8, + 0x3e818e99, 0x87065894, 0xb29c5da2, 0xb0a23d28, 0xf912038d, 0xe1ef350a, 0x6f116215, 0x59789321, + 0x42e951c6, 0xd54fb7b6, 0x432a70ed, 0xa91fe494, 0x7886cf6b, 0xfc2f8b2a, 0x81186d27, 0xa117d223, + 0xed7b9a43, 0x44a1d8c1, 0xb9a3352d, 0x21ab6908, 0x64562642, 0x4e2fb35c, 0xc4f6d1b4, 0x60749423, + 0x49d72d53, 0xb72e0b70, 0x8c98958b, 0x111ebfd6, 0x0ec911ed, 0x486a200b, 0xee98fa2e, 0x09df0eeb, + 0x1d1dbd4f, 0x030a07dc, 0x0563b0a3, 0xf641d8f6, 0xc80b8132, 0x7de4af21, 0x29714b0b, 0x09b87ae5, + 0x8a36899d, 0x6a2252ea, 0xfe2de584, 0x59a7b1cd, 0x3875be7f, 0x86a562e7, 0x53dd7b53, 0x9a1e5aba, + 0xb589f9cc, 0x1157dc2e, 0x0dbfbdfa, 0xd3b5f6bd, 0xa36d7892, 0x9bf8aec6, 0xafe17f0c, 0xee02f9b2, + 0xbfd42923, 0xb7442331, 0x0eb2a48b, 0xdc170308, 0xe89ee0e1, 0x09de72d7, 0x02d7d055, 0x12e25fdc, + 0xe1153f42, 0x6c190aa5, 0x79883c8b, 0xe314d0e3, 0x71b66952, 0x3c8f4be5, 0x7218d8f2, 0xe5e2e0c2, + 0xf0350014, 0xc607dc8f, 0x94b8dd1f, 0x1d2d2aec, 0xf7b71a76, 0x27b928f9, 0x64269fbb, 0x2dce3f27, + 0xe56a4dc5, 0xc629b0b1, 0xf18d41b0, 0xbba9d1f9, 0x410a2bdd, 0xdef81cca, 0xc028a190, 0x5453f0ef, + 0x5efa11e3, 0x261e0757, 0x8b435c06, 0x0635d481, 0xae0dfaca, 0xfe06ae14, 0xe2bd43a4, 0xc76e762b, + 0xa7d80419, 0xe17d2871, 0x0022c8b8, 0xaa1d8ad4, 0xdde09fa0, 0x76f8dd85, 0xff2087ff, 0xe0ac0017, + 0xe1b71e73, 0xa6cd2b78, 0x23b914e7, 0x2a36acb7, 0xc37b022f, 0x6ecba416, 0x3bb6b29a, 0x6da879ec, + 0xdd4cd4de, 0x5f36f9b0, 0x329be86d, 0x47f05bb5, 0xabb94423, 0x85ea5d91, 0x157f72c0, 0x553668b4, + 0xed16b2f9, 0x67a8bf69, 0x995033f4, 0x9cf1e4ce, 0xd1116cba, 0x6a1bb7e2, 0x6a6cf0d7, 0xb886d055, + 0x84a00a22, 0x10f5de2f, 0x7f86dfe2, 0xffe4c6a7, 0x5ee423a1, 0xc87342f4, 0x3bb7b4a1, 0x4f55ce14, + 0x8cb44e51, 0xb8ae871f, 0x3b186775, 0x278d19dc, 0xaf6e2db6, 0xe6c454e0, 0x988583c8, 0x4f50e571, + 0x3ca879ca, 0xe76ad2a2, 0xe7f31c3c, 0xf075e364, 0x5bc0f65a, 0xa2d380b5, 0x91895a69, 0x678f49c4, + 0xb0bd88b8, 0xd05c405e, 0xd5338209, 0x21cb6587, 0xf1cc04bd, 0xbb305dfe, 0x80a6287e, 0xa2976680, + 0xbb962878, 0x88a5f9f9, 0x1c0a6247, 0x67d15ce3, 0x8bd58194, 0x1318cd48, 0xffac033c, 0x892f063a, + 0x89088155, 0x0d4db375, 0x36c1e139, 0x010efb9a, 0x50f769aa, 0xfd3fee0d, 0xab2a67e7, 0x430f7af8, + 0x80194040, 0x7c4ea240, 0xa7b2922a, 0x932a0329, 0xeb288b1a, 0x8ce1983e, 0xd03f4d43, 0x4c06ffd5, + 0x878d3cf1, 0xa79c6549, 0x107201f0, 0x9f841a29, 0xa39f4265, 0xd47c4735, 0x93b0d171, 0x78f322b9, + 0x0b4d2f58, 0x3587567f, 0x03a2ff43, 0x7e382c46, 0x3fc1c6b6, 0x04b42eb8, 0x833efc3a, 0x42bb53c5, + 0xd72945cc, 0xe05bedd3, 0xa3fd8430, 0x2f7465d3, 0x294c12f7, 0x0a72cbc2, 0xa71d7bf0, 0x90090ce1, + 0x8e6c45d4, 0x571b4b84, 0x5827977a, 0xabf5de01, 0x5f615038, 0x48090cf2, 0x1b72b40e, 0x440e935a, + 0x303bc1c7, 0x2ef7833f, 0x390dbf82, 0x8859175e, 0x9de99b0e, 0x4cfa5b18, 0x12062a3a, 0xe43d0834, + 0x88457f5e, 0xef5e610e, 0xd9e36a91, 0x4b70aa07, 0x857e8815, 0x62cc3566, 0x1f18ff81, 0x6d676bcd, + 0xc3fba718, 0x7d5eaaaa, 0xb46e694d, 0x797cc0cc, 0xd5055bb9, 0x32ba2427, 0xc41d46ab, 0x39663315, + 0x515f45ab, 0x5889839d, 0x2012f306, 0xb375b2d2, 0x1cee5ca3, 0x8148bced, 0x51e24635, 0xf6544d69, + 0x9b8fb6fd, 0xdad54034, 0xc44bd41f, 0x457b67ff, 0xb23e73cc, 0x8abea051, 0x095d4e8b, 0x1b4b059b, + 0xcd54743d, 0x70394596, 0xbff21ba3, 0xf581adb2, 0x91568def, 0x108224ed, 0x56d44d36, 0xdf0d95fb, + 0xbdcd2986, 0x1faefc75, 0xf2d86f74, 0x9bfb1351, 0xd474e280, 0x30c6ad08, 0xae161e34, 0xc6ed49d6, + 0x5c0f7e8c, 0xefd61a76, 0xd9195f92, 0xb1bf3832, 0xe8075a61, 0x9ce78195, 0xf4bf63e6, 0x8b7c27a6, + 0xbfb2e533, 0xade660a8, 0x37b8b8ce, 0x562b279c, 0x4e1c969f, 0xc9fd628a, 0x54fb425f, 0x72a41f90, + 0x9c4fc10d, 0xf5ce21f0, 0xc547cb56, 0xf65251ea, 0x97b121b7, 0x388783fb, 0x5ce2ac74, 0x10d23ab4, + 0xb289d2d3, 0x41ea4c9d, 0xa4a9979d, 0x70cc65dc, 0x4d6c1903, 0x196bc5c8, 0xcf1e03bb, 0x36b5eb6e, + 0xe5eb638e, 0x423e85a1, 0xc161b173, 0x1ff4cc63, 0x206addda, 0xaed0cf0b, 0x8338f8a1, 0x2cec0ea4, + 0x11e42546, 0xe64ab40c, 0xf9ca1222, 0x18e0fe59, 0xb0b72310, 0xaf49a111, 0xbe328827, 0xb699984a, + 0x5420230d, 0xca4ae97f, 0xdf906045, 0x4168a1d1, 0xcbb8f4c9, 0x5a704c8f, 0xe36fa467, 0x9910f463, + 0x2f034ea6, 0x6677cde3, 0x67659bc3, 0x766f9956, 0xf60281cf, 0x14c456a0, 0x9ef8b369, 0xfef42c6d, + 0x804a1dc6, 0xb80c5556, 0x9d797b8e, 0x607fb662, 0xf3863ff9, 0x69b104c0, 0xad713475, 0x620b0e30, + 0x09f4a633, 0x456c20f7, 0x73a7e261, 0xa82fb42f, 0x3a492504, 0xa267c572, 0x93ef3f9e, 0x65f3c123, + 0xcf52011e, 0x1670ab7c, 0x79887dac, 0x055200d2, 0x3f0df79d, 0xf4de0e73, 0xae3af2bd, 0xe6da9c9e, + 0x655d2b0d, 0xc3c18ab5, 0xa08cdb75, 0xbdafc8bd, 0x6f1fc3a8, 0x3f1197e9, 0x8bb727b2, 0x5ac1b899, + 0x8391126a, 0x75848748, 0xd64d4549, 0x8448fdb2, 0x7f131a31, 0x4f1130fb, 0xc3d59256, 0x71f09c91, + 0x378d3d74, 0xf7ce5e63, 0xa299563c, 0xca5d457d, 0xd2e4f2d2, 0x75811e9e, 0x487522ce, 0xfc034d39, + 0xb77fd251, 0xf3c4b2e4, 0x387853b2, 0xb2f20274, 0x736d2edf, 0xb5bb4bb0, 0x90c943ee, 0xf6faa195, + 0x0d1b557b, 0xf280bf83, 0x0a8b3944, 0x1983dbee, 0xeed16395, 0x1208f580, 0xb43217df, 0x43a06f63, + 0xa03fc3e2, 0xd17accc7, 0x99cc6aaf, 0x9b555d42, 0xd5321ecc, 0x17521be2, 0x9b43d789, 0x1b9c4090, + 0x0e0944f6, 0x1f18dead, 0x2578a36e, 0x900f3952, 0xd909c5e5, 0x0ed3bfa1, 0x859f5ea4, 0x949e9a89, + 0x9bc16e9a, 0x3bd40351, 0x66df7d90, 0x28fa8ec2, 0x8528ffc4, 0x01b8420a, 0xa6d0b995, 0xdef23933, + 0xb973fbfc, 0x5c377757, 0xbd0b06c0, 0xe128d01d, 0x87b458f5, 0xc9322187, 0xbcc72569, 0xb2e80438, + 0x6f7bc52f, 0x3161b273, 0xe254430b, 0x485002c3, 0x8344058c, 0x36f2e03c, 0xc3843f6c, 0x3e71a6cf, + 0x7956dd2b, 0x74707079, 0x401668b8, 0x0fd8448f, 0x47d1ac14, 0xa8056fc1, 0x5d8ea17d, 0xe67f0ca3, + 0x31a5b4c6, 0x0eece689, 0x27e9f151, 0x760d9f3b, 0x4c5366b8, 0xcfe23dcb, 0xc65ed9f3, 0x90d2d20a, + 0x34b35328, 0x1d92f942, 0x91c10cde, 0xc0bf702e, 0xc071dc9b, 0x12f40e60, 0x5a1d7de3, 0x94718776, + 0x83cc3373, 0xeea2f2c9, 0xe5f41fab, 0x1b9e7550, 0x1f8ffc62, 0xca96f53c, 0x273ea8c9, 0x16daafb7, + 0x8fc4e0ac, 0x1bb8507f, 0x39cc5792, 0x0faac9e9, 0x639905c1, 0x2db0b64a, 0x82d66f35, 0xa554e6ea, + 0x3e898e04, 0xaae58a01, 0xae5fbd1d, 0x3973c77d, 0xa2cfa20c, 0x2d3f3f78, 0xb8803ad8, 0xb5ae8b81, + 0xc625569c, 0x64ed4fce, 0xa3ecc6f4, 0x9a48569a, 0xbfe3cf99, 0x3330fd57, 0x34c53ae1, 0xfa04ac35, + 0x3fe0ccd3, 0xc8caa060, 0x11f3eac6, 0xd8917a79, 0xdbc1c04d, 0xcbea6328, 0x9d68abfe, 0xed6bfbae, + 0x2babdaeb, 0x30337061, 0x232193f2, 0xccaaf620, 0xf1231165, 0x9acd8fd9, 0xaac21262, 0xb3ab6ce2, + 0xd09be636, 0x75499672, 0x8672a259, 0x6d324a88, 0xd69bdc1e, 0x56c43129, 0x2787b82e, 0x50f3ece7, + 0x27c03cf2, 0xcd6525c5, 0x8a83d958, 0x12ed1f7e, 0x16f49a47, 0xbb22deda, 0xea86d248, 0x044857d9, + 0x890b37bc, 0x381ce126, 0x21e13d45, 0x710a8967, 0xb65b4d3b, 0xe813caee, 0x31cbc091, 0x15c8096a, + 0x7d7a05d9, 0x07c4513b, 0x8aa96344, 0x2f0add12, 0xfe8e9ad6, 0xdf82f03a, 0xf38d5450, 0x2751cf99, + 0xa8eed6ce, 0x8095e201, 0x9e13923f, 0xdd6aca14, 0x0e4ca616, 0x6511bcdc, 0x2dff1dff, 0xe9aa58c5, + 0x6a1cde68, 0x0b93941d, 0x816a6f88, 0x019b4fb1, 0xa1a8a475, 0xda49f6bb, 0xe798ef9e, 0xe0cacb7e, + 0xc0ac738f, 0x8684e510, 0xd9a28388, 0xc6565bbc, 0x7ef4307e, 0x215a5309, 0x0ef0466d, 0x3d9a9b71, + 0x73dcae25, 0x5bee9774, 0x6f0d0d85, 0xfd6a0ce6, 0xc25526cc, 0xc21daa7e, 0x18163b3e, 0x44294090, + 0x15b27bd8, 0x66aa4282, 0x03960f36, 0xc1738ad8, 0xc31d44f9, 0x492642c7, 0xcff1eb76, 0x468e6944, + 0x3df5ff0f, 0x6760fca4, 0x496f25fa, 0xa544beb9, 0x739fecc6, 0xbf181689, 0xbee15390, 0xa6b6f238, + 0x46eb5abd, 0x39666d21, 0x8ad09df8, 0x5011b181, 0x68b7bed3, 0x98436e4c, 0xe6ba353f, 0x375eadb6, + 0x9f14a4cd, 0x34fb256b, 0xf0312a2c, 0x84aa1b36, 0x9537ec26, 0xc52de354, 0x12160dd9, 0x5f4e50de, + 0xd9048bfe, 0x52fc066e, 0x7d26ed40, 0xb82ab709, 0xbc0ff86d, 0xa2cb2a3f, 0xf2376ab0, 0x3e1b6d7e, + 0x30c233f4, 0x0d3a32d4, 0xf0003888, 0x164526f6, 0x1a1fbdc5, 0x56dbb01b, 0x6e8c2a5f, 0x62749d0b, + 0x5ea4878f, 0xbb67c4c4, 0xf18f1f4e, 0x025e9369, 0x22f41ac3, 0x3f20384a, 0xc351a8b7, 0x866ee5fc, + 0x66f878be, 0xb9abfac8, 0x9d0f306e, 0x470eb291, 0x65222367, 0x97a3fd08, 0x0ce012c8, 0x64079efb, + 0x3d0383b4, 0xdb21f176, 0x3571cc31, 0xe6b0f767, 0xbb0fe631, 0x7c7277ba, 0xc543e003, 0x9f1db2d9, + 0xaf57bd5d, 0xfaee84ad, 0xd12ee794, 0x161e8a30, 0xe4e2c43b, 0xe6ca7cd6, 0x95d8b2e4, 0xcf5d72ca, + 0x0564ca65, 0x2608d025, 0x7a46d5d0, 0xcd3d1be9, 0xd32bea21, 0x74eb954f, 0xebe0fcbc, 0x40e8d79c, + 0x67689184, 0x1ffbb2b5, 0x9a0ef70e, 0xaf5068c5, 0x904e6f4f, 0xdfb7e4c7, 0x5a2c53ad, 0x14faec23, + 0x30886924, 0x6bf2e3c8, 0x0950b17a, 0x4ed22d35, 0x506baf3a, 0x041c4ee1, 0xa449ee86, 0xd054ce44, + 0x731b3c33, 0x0bd566df, 0x29e0e9d3, 0xabd619ce, 0x47cad76a, 0x861bdcc6, 0x6abef9de, 0x41bfc6ad, + 0xe8c54ae3, 0x1030b685, 0x692390ac, 0x8d2f48a6, 0x48c22b46, 0xa5d24014, 0x5f83d59a, 0xa586be83, + 0xc4656da4, 0x69063582, 0x92526e4b, 0x89865555, 0x181eb4c7, 0xe6853138, 0x504aa5b0, 0x241c8ede, + 0x47fda24e, 0x309df589, 0xe45675e2, 0x91f55e70, 0x2a764a3c, 0x93d9f3a8, 0x916e4680, 0x537e78af, + 0x99df8157, 0x6bc55d1e, 0x95a8f819, 0x11288c38, 0x7f777bb5, 0xfc64210a, 0x11a31a06, 0x5c647f22, + 0x361bc570, 0x26d96295, 0x230c944c, 0x6e2aef65, 0x0244f9de, 0xb466b61d, 0x6841261b, 0xb8f59bc4, + 0x4ce8ae4f, 0xcaffda12, 0x582db9ac, 0x32fdc718, 0x15c177ff, 0xbd8b5886, 0x5942faa0, 0x0b6b2bd5, + 0x6fcb2cf7, 0x7bd37344, 0x6374a554, 0xef241a99, 0x8d243b94, 0x93111306, 0x17e98433, 0xfb945861, + 0xbf31c379, 0xb04857ae, 0x92a7fbe1, 0x46d2a49e, 0xdb24f0d8, 0xb684640c, 0x7e5f94ae, 0xe7993b6f, + 0x40902ddb, 0x2e1ad956, 0x013bbf9c, 0xed81ab36, 0x699bf902, 0x96e15c6e, 0xe45b130d, 0x28ed550c, + 0xa4a78925, 0x3cf0997e, 0x1bcdd8dd, 0x75f04756, 0x0545d2bf, 0x086792a0, 0xa883f647, 0x6515c77d, + 0xa9faf95f, 0x378f4e01, 0x52a76178, 0xa8ace196, 0x16cc01bd, 0x627e7f68, 0x68105fb8, 0x5fa1df49, + 0xcf40ca69, 0xf66f8ef5, 0x0459fa5e, 0xc632cf33, 0x0a2f4e27, 0x08019ae2, 0x0fb21128, 0xec2ef4dc, + 0xcb28f88b, 0x74cce58a, 0xc6eb3d2a, 0x757872e1, 0xe577c215, 0x39e9c103, 0x02c91b5f, 0xafc76dbc, + 0x49795150, 0xa18a30f1, 0xa13a97a7, 0x8464e83f, 0x61fd0b48, 0x1154b078, 0xa1ac45f6, 0xfc39226c, + 0x1ddde069, 0xd66f1d14, 0xaf746727, 0x325b1801, 0xcbdf4db3, 0x25a56019, 0x27e875a1, 0xcc82d4bc, + 0xa633be6a, 0x7fee23c7, 0x90448921, 0x8e76be30, 0x1a90e938, 0x0a8d79f0, 0x8c3b85fd, 0xd4492e24, + 0xc5259e33, 0x57fd280d, 0x1cb4ae90, 0xc990a293, 0x82d88ff9, 0x2d24b1e0, 0x7297299b, 0x64f5e839, + 0xe1613311, 0xd96af5e3, 0xae081e01, 0xfe70913a, 0x9e2e9d44, 0x9ffbc657, 0xdf050b78, 0x3e635d1a, + 0x93e32069, 0x43acd5b2, 0x6d66eb6b, 0xaa0cee4e, 0xad3bc3df, 0xacb0892e, 0x721f16bc, 0x01acdcc2, + 0x374a0ea8, 0x048d002b, 0xfc8dd131, 0xa29d4ebd, 0xc0c7b6cc, 0xf5c38340, 0x2895397e, 0x6d40f3dd, + 0x62dafbe6, 0xd26cdab6, 0xd376ed0b, 0x08748f13, 0x752a9ef1, 0xd7dee728, 0x72d58444, 0x4403324b, + 0x7159baa4, 0xf362e466, 0x6e1d41cd, 0xeb174c46, 0x27fec6dc, 0xe82075e6, 0xb4fe8c1e, 0x41b7a6ef, + 0x6530035e, 0x8a98a647, 0x9c3ddb6a, 0x0b0317a2, 0x0a75b86d, 0x819c51e2, 0xb19edb07, 0x2dbd6b8e, + 0x2d1ca7c3, 0x16e335f5, 0x3066a09a, 0x7f81ab30, 0xdffb17f2, 0x313913da, 0xaf9d8acf, 0xc7f54b0c, + 0x2b502e3e, 0x8b715342, 0xf16e040c, 0xae36182c, 0xbd070a0a, 0x50744366, 0x2da1bbf1, 0x629b361f, + 0x2db3fa35, 0xa8f6375e, 0x1b483ef7, 0xa7f60253, 0xf7de3a55, 0xf3293b08, 0x1805c614, 0x87457700, + 0x27420042, 0xa9ca5860, 0xfaaa3362, 0x1311251c, 0xba4ac979, 0xabe929bd, 0xdd84d36a, 0xa42c4586, + 0x092c43f6, 0x813562cd, 0x608628ae, 0xd8ba00dc, 0xc4d98691, 0x365c404a, 0x06334c75, 0xeb838333, + 0x20b1478a, 0x2f83cb96, 0xc93b5ea2, 0x9682b4d8, 0xc9d275f2, 0x84105a0b, 0xd455c9fa, 0x2f0c31ba, + 0xa01b4003, 0xc9c67bfe, 0x88ed2e9a, 0x53b7356e, 0xf857282e, 0x242dce19, 0x68f8537b, 0x367d38ee, + 0xfe508791, 0xb4e3e6b3, 0xfa939275, 0x16b02e86, 0xb519b25f, 0x34d23679, 0x1504a503, 0xab85f9bc, + 0x46db9d2b, 0x9ecd0d70, 0x22dbc6e1, 0x7554552b, 0x780b2065, 0xa89b6928, 0xa7df6bee, 0xa8c84dce, + 0x4c69ec09, 0xeb8f534e, 0x5870b752, 0x469ca0c5, 0x0577adfb, 0x0af6ed2e, 0xf14f891e, 0x64777a93, + 0x7f175b58, 0x3f8ea948, 0xea4c0210, 0xd3c26a5f, 0x570782e6, 0xb449e3bd, 0x88866490, 0x53cc975a, + 0xb9b874d3, 0xd3b120f2, 0x04c14279, 0xbe11213c, 0x1c77c84e, 0x4c4d613e, 0xd899cea6, 0xe33ec278, + 0x1e1af33a, 0x7fc2b2c6, 0x3ebe26d8, 0x5385384f, 0x18675d47, 0x4f40470f, 0xedec0d29, 0x829321c3, + 0x25ad56a7, 0xa27e1a4e, 0x416953ed, 0x09ec87c2, 0x6ad2e61c, 0xc706164a, 0x25cc9e64, 0xab4b0583, + 0xc7fb0af2, 0x1b1319b8, 0xa13b4297, 0xf943718e, 0x71ae7461, 0x850eafb0, 0x27c1a687, 0x8ff065fa, + 0xb720e91d, 0x26e3cd62, 0x71d8a102, 0xd35cf73a, 0xda453ea6, 0x339d22f9, 0x3b8c73d1, 0xe6eef97f, + 0x77ea0976, 0x984748ee, 0x4a41a1b4, 0x18edff64, 0x7bfef4c9, 0xcee9301e, 0xdf464b6e, 0x32fa92e0, + 0xd7a19d5e, 0x9f1e6e92, 0x28ca0ffb, 0x0f358a81, 0x987b3054, 0xe88e7358, 0x3e69a213, 0x2c535628, + 0xc6a873bc, 0xa59d6b96, 0x6d49a750, 0x0df5079e, 0xd9bf3209, 0x98734fd8, 0x8a523d17, 0x7d2688a7, + 0x3b9ec3cf, 0xefaa515a, 0x3929c22a, 0xa991f9d1, 0xead52f88, 0xaa420c05, 0x7a303319, 0xd90f2179, + 0xe424dbc2, 0x396a499c, 0xf3f74a9b, 0x4d2c6901, 0xd0d33bcc, 0x8131c77d, 0x64161f40, 0xc733ce92, + 0xa854aab8, 0x012d06cc, 0x2a6d70cb, 0xda97673e, 0x33cda528, 0xdda339e3, 0x2038eef2, 0x9b5b5e51, + 0x6d198370, 0x1a4b9579, 0xabcc01d0, 0xb34643cf, 0x2ae4b116, 0x83e4aa15, 0x5c8f8b9b, 0x2af5c415, + 0xc6b377a6, 0xb56878ea, 0x042dd8cb, 0xb685b760, 0x01794265, 0x802a349c, 0x93026fae, 0x60723202, + 0xeb9580c4, 0x3d5e699c, 0xb96eb21c, 0x038ec12e, 0xa1d47275, 0xb9293beb, 0xe71f6cb6, 0x95cadf61, + 0x810993f8, 0x851f148b, 0x20a486ea, 0x71faccbd, 0x6f1d6978, 0x532d5a13, 0xc83d1f09, 0xddec5bf4, + 0xf760b77c, 0x60f01d09, 0xfb2d8df1, 0x47243ac8, 0x6acf010e, 0x6bc14a31, 0x29619716, 0x2383b63f, + 0x94b47a8e, 0x51b203b9, 0xddbb2bd1, 0x88e760f7, 0x7d221054, 0x1915b0a5, 0x30410213, 0x9e1086de, + 0x26a45ccd, 0x7c6dbb07, 0x2c0cf565, 0x4006fd09, 0x297d4ec8, 0xe7662979, 0xc42ed8ac, 0x2c71b76c, + 0x6fcbb75d, 0x48d59a49, 0x8b5986ed, 0x125d6534, 0xb2b0a28e, 0x50e79ad3, 0xcdbdcc98, 0xca24b25b, + 0x6dcf6199, 0x6bc9cc5d, 0xe548b58e, 0xe15cba61, 0x54036347, 0x56c48819, 0x0e4a4076, 0xdfb8063c, + 0x3b48083a, 0x05cfd32d, 0xabd647e6, 0x5143cb66, 0x175c2efd, 0xdd2de230, 0x08e156eb, 0x01018a44, + 0xdd197271, 0x0a3eebb0, 0xeaca422b, 0x78ced6e7, 0xc80dc0d7, 0x3abb2c59, 0xa2c3ad71, 0xdf8854d4, + 0xb5e86dcf, 0x0b4ebe0a, 0x1189806e, 0x7b8bf9c4, 0x4752159b, 0x476fba53, 0x3f308030, 0x87a8dd5f, + 0x089b7dfe, 0x429ab6d7, 0x4e3b299c, 0x3ffe7e9a, 0xea617d1e, 0xdc4bdcd1, 0x3f80df29, 0x5201d0b2, + 0x36d242bd, 0x0f814bc0, 0x13e8fb59, 0x2ea0a06f, 0xd91f9ec9, 0x829349ac, 0x38033ce7, 0xb6ab2790, + 0x0be388b2, 0x82bcf027, 0x6f38bbd4, 0x39a23d91, 0xc194bbe5, 0x59002ef6, 0xbf5c7b05, 0x8325f4c4, + 0x9dbd652b, 0xb6a5fc11, 0x53468acb, 0x59928981, 0x82c424b2, 0xae1a2725, 0x6d8be3c5, 0xcca14a49, + 0x93e491f1, 0xcb4792b9, 0x5b18119e, 0x64f3a348, 0x1819355e, 0x4c3e15a3, 0x2db268fa, 0x72beb455, + 0x5a7be0ab, 0xa236000b, 0xc38ee975, 0x20bfbba4, 0xc1065c58, 0xa0eafcf2, 0xae94de1e, 0x89f7cb2c, + 0xafc25e0a, 0xc300ec2b, 0x2045743f, 0x2076298c, 0xe26346fc, 0x259d7266, 0xf796fd3e, 0xe1b567c8, + 0x6a1b9fdc, 0xca5292cd, 0x3e27b5b6, 0x44eab769, 0x7e9e7199, 0x69924b3c, 0x4989b008, 0x19f11795, + 0x1ef72526, 0x01882420, 0xcee7d0d3, 0x28e105f8, 0xfad2606a, 0xe6930fb2, 0x90546122, 0x7ba344ba, + 0x48f2aa49, 0x5f7ee6bc, 0x72f32dad, 0x7ff6587b, 0xf04f9ecd, 0x1e2f0153, 0x9e56e632, 0x076b9e6a, + 0x5e8bfd55, 0xe8fb671b, 0xebd0c4f2, 0xb7598e2b, 0x4387572c, 0xe82a2b07, 0x562b8a67, 0x566b3c4c, + 0xe0517e50, 0xde2f269a, 0x2e499501, 0x442171a7, 0x947574e3, 0x6091092e, 0xb52c9441, 0xe6eb0a68, + 0x14a998b6, 0xb4ff92a0, 0xee37babf, 0x0a16d629, 0xbe569801, 0xf29a4ae9, 0xf32f5c3b, 0x7f5c5da9, + 0x2c735b5e, 0x8d590fb7, 0xd31eece5, 0x919cbd5e, 0x068a0703, 0x20430703, 0x05306e2d, 0x24e936fb, + 0x2572ffe9, 0x4576fd50, 0xb3ae96dd, 0xbe602d9d, 0x0b169a87, 0x12f95f15, 0x68884228, 0x3d1b88b2, + 0x172720f9, 0x2bd8e8a3, 0x7a5dc721, 0x7f3b6af8, 0x741a9139, 0xa0b47a22, 0x05885f57, 0xa6613afe, + 0x1b959e2d, 0xfb355906, 0x48e3131f, 0xb265a3e5, 0x81d36e88, 0x4df071b9, 0x2c564fc8, 0xe305ea21, + 0x0806457c, 0xaf963a44, 0x99b1cdad, 0xc58b3e54, 0x71e31a7d, 0x1f46fc21, 0xb6b6b46e, 0x6b81a648, + 0xfdc87abc, 0xfe7d9f96, 0x29c96e2f, 0x89b33980, 0xa8a71c5f, 0xa4b9cf4e, 0x46b590fd, 0x636ea5fd, + 0x5a2c0491, 0x08d8dca1, 0xe758a549, 0x758d5c46, 0x6e9a0711, 0xf28b1a45, 0xafa6065b, 0x4a095c5a, + 0xf9b0d1f1, 0x377691e5, 0xee23c63d, 0xa5386b65, 0xbc7a0fc9, 0x857e0eda, 0x49a83302, 0x358c1583, + 0x967de778, 0x9d470019, 0xa85459d2, 0x606ecd6f, 0xd9ab1ee6, 0xb9bec523, 0x8b5bacb4, 0xa667c992, + 0x92744eb4, 0x63b7b6fb, 0xa02354d0, 0xeaa86638, 0x94b7f47e, 0xa909425f, 0x2b934212, 0x3deaceb2, + 0xcd74cf79, 0x81115d82, 0x922a05e0, 0xc7abaa4b, 0xa0f85ebb, 0xa5555a2e, 0x47c7cd7f, 0x9629b4b4, + 0x34eae6d4, 0xd44d2c92, 0x266ab5eb, 0x9cfe4bc9, 0x26a58985, 0x3166b84f, 0x44a38522, 0xb363563b, + 0x6c47dc9f, 0x3b896806, 0xeb1c4558, 0x16615933, 0xc4793420, 0x3f8b87c5, 0xb286fe72, 0xaf2b0093, + 0x41e878a9, 0xf2cc8734, 0x9819a15c, 0x78cd2457, 0x454f92ba, 0xce03bcc0, 0xceffff64, 0x1d33e03b, + 0x15b56274, 0xa5ea41f0, 0x9945d9d5, 0x282143d0, 0x19ce6a10, 0xdc25e6bc, 0xc771fe77, 0xf7ae9ada, + 0x5f9c2fdc, 0xd740f144, 0x4281954d, 0x31bfc055, 0x66daf65b, 0xbf8000b0, 0x361b6b3e, 0xfa43165b, + 0x3273ff0f, 0xa1bca04d, 0x6fdfa47d, 0x3d73502f, 0xa74274ff, 0x59aea38a, 0x6a73a65c, 0xd452910f, + 0x86459b81, 0x76ff3f23, 0xb91eac86, 0xd86f6a9c, 0xc6f0b123, 0x41d6f851, 0xa7e69a6e, 0xb6475035, + 0xd150b5da, 0x7cbea57c, 0x91dcb72a, 0xa69c5b40, 0xe7b66875, 0x2ecfb9cc, 0xe4b34de7, 0x67a50d69, + 0x1b131e9e, 0xfa3a5710, 0xcb5da057, 0xeb0df2ca, 0xd69d594a, 0xc5bab7d9, 0x9d2d7a0a, 0x1d01de60, + 0xfb06bb51, 0xf72e3ffc, 0x54b7a5f5, 0x6fe07842, 0x67868a05, 0xdffda705, 0xfa869f6b, 0x3657fa08, + 0xad98ad3b, 0x9a16cdf8, 0x90b677f1, 0xc70777f1, 0x9ae7ec0a, 0x49c4b6ae, 0xaaa3a7da, 0xc0e3e605, + 0x2b581fc7, 0xe953cc2a, 0x91a4ac3e, 0xcfd4c2cc, 0x930a2014, 0xea1e7914, 0x21cb29ad, 0x8e0c95fd, + 0xdd432bba, 0x0c6099c7, 0xa4f5ca0f, 0x05862867, 0xa857b281, 0xabe79204, 0x755c64d1, 0xe4202d28, + 0xa03a67c9, 0x5a056e28, 0x6dd6289a, 0x503617be, 0xd885eab5, 0xf3f280e3, 0x5db0c3ca, 0xbb6e4208, + 0x6767e411, 0x2362f67e, 0xa2ee7c96, 0x10bc6223, 0xd259a334, 0x79d15fe3, 0xad3ccc74, 0xb48c3c34, + 0xbc9235c4, 0x88d72526, 0x2312536a, 0x5589cd23, 0x4b1ef15f, 0x2a5028f7, 0x1e7affd6, 0x8dc58103, + 0x8dde405b, 0x7ae8f8fe, 0x3139976d, 0xbba78d64, 0xdedfbe8e, 0x9fe26631, 0xa3b35814, 0x907c55f8, + 0xaed325a7, 0xe14e00df, 0xcd9ebfad, 0x825c4ec4, 0xa7bcaed4, 0xfa5f2020, 0x13f5b911, 0x4ab65e9e, + 0xaae16e18, 0x517e5f9f, 0xcd42c56e, 0xb7240ab3, 0x7c28e44a, 0xd1edbc14, 0xc9f7df50, 0xd8f79262, + 0x597cd25b, 0xfab89292, 0x56fe9f2f, 0xb53acbc5, 0xdba41c89, 0x819a8547, 0x0fa296de, 0x3f906095, + 0x766acfb7, 0x908c3e54, 0x5cc523d0, 0x9f807bdb, 0xe1bd89c3, 0x3443647e, 0xb6d3a3f9, 0x84a1b592, + 0x37b5722b, 0x495f43e5, 0xc78f813f, 0x7e3621c1, 0xd86c6882, 0xcb7beaa3, 0xf164d56d, 0x096f6032, + 0xfa1384f2, 0x1d12cf0a, 0xd0ee4bb8, 0x47b3c950, 0xe88e26aa, 0x46500751, 0xd423c3f7, 0x165e2b65, + 0x19ca0f3c, 0xf933fcd3, 0x011bd2bd, 0x50ca9faf, 0xb94776aa, 0x7897f0d1, 0x17e1f814, 0x7787bbf1, + 0x6348d399, 0x18c44f06, 0x7e1f1253, 0x11b3fb40, 0x00c493ef, 0x1a16c72e, 0x5935261f, 0x593a88ea, + 0xc83f8dca, 0x2f79d40e, 0x9e211f05, 0x2e778181, 0xf50a87b2, 0xa853b0c4, 0xce2c5ade, 0x619660ed, + 0x02976aff, 0x7a1d3974, 0x3118857c, 0xf90090c7, 0xe29db50f, 0xe0faa9a7, 0x36a27769, 0xfb5eedec, + 0x717ad9dc, 0x34f43398, 0xbae12633, 0x71849258, 0xe32134e7, 0x1bc3105e, 0x3346c690, 0xfa1d81e3, + 0x3f0bff53, 0xebca0df0, 0x228f3400, 0x8cdbed24, 0x2f30f464, 0x1e8e56a0, 0x3b583734, 0x93c1bf8e, + 0x329f942d, 0x03256156, 0x898f2ed2, 0xee981f8a, 0x7687f731, 0x90f6af8a, 0xee171f3d, 0x1f70e378, + 0x9db90183, 0x2ffde3b6, 0x33e224f7, 0xd2c79b8e, 0xca1a1b7a, 0x8ca7951e, 0x33b715dc, 0x16b947bc, + 0x654ccc5e, 0xca9ea8e2, 0x81f73da6, 0x81817ff3, 0x6584d67f, 0x92e11c87, 0xf9ee4f7b, 0x3c6de651, + 0x822aa1b5, 0x331c250b, 0x805a650d, 0xe1a21920, 0x3a2fa21e, 0xed6e2a58, 0x5066944c, 0x12cc9293, + 0x8ad4833c, 0xcccf52fc, 0x222fca77, 0x70bad2ec, 0x2cd2b55f, 0x6e66f981, 0xfe9c3af9, 0x362953a2, + 0x37777e93, 0x7dabab44, 0xdeedde9b, 0x89eaf1c2, 0x618aa7c7, 0x07527258, 0x62282931, 0xc6a374ed, + 0x8aa67520, 0x5c1d9d19, 0x552b2f47, 0x682ae4d6, 0x85d9f8f5, 0xccf3dac1, 0x074cdbc4, 0x9f3f2676, + 0xebf21fab, 0x0591cf67, 0xfba919cb, 0x4b975dae, 0xd17063d5, 0x2011a833, 0x596b4da1, 0x70aa9223, + 0x9bdcbcfa, 0xc3429620, 0xf1ad646d, 0x2abbc833, 0xfe9131a0, 0x7313c732, 0x6655835c, 0x4d92a674, + 0x23b68e3a, 0x1e4ae762, 0x4b3d156b, 0x785f5f26, 0xba23f2ea, 0x21b7f51e, 0xb07ff105, 0xc455edb3, + 0x5af36869, 0x4b0eb40d, 0x89b6ce2e, 0xe2ebc692, 0x1af081b6, 0x71a47d7a, 0xa584b336, 0x2fbffd24, + 0xc1b5d3b5, 0x06e66b8c, 0x4be3bb21, 0x4476fb45, 0x10244638, 0xceefce89, 0x22bd197b, 0xad2e346f, + 0x441f7a5a, 0xff13cce9, 0x31cc263f, 0xefeeb72a, 0xefc021ce, 0xf3b091ae, 0x6bd582a6, 0x3d129296, + 0x27a111d3, 0x19a816be, 0xefb5d073, 0x10d0713d, 0x130917d3, 0x21ede1b6, 0x2483552f, 0xa430ed33, + 0x736e230e, 0x4860bdd7, 0x3d2d13e0, 0xc78d22ac, 0xf5ee192d, 0x763197cd, 0x75b60f1d, 0xd172c225, + 0x374ca56a, 0x4429f368, 0x2f3a2c03, 0x37ac0198, 0x0ad3a169, 0xd406c64e, 0x0c47acec, 0xd0ad6ac7, + 0x1e2b6b85, 0x69401cf8, 0x968b21fe, 0xdf3bdf4d, 0x09878ea6, 0xa4b9ee23, 0xe6d44cc5, 0x72d7532d, + 0x24b7c9b6, 0x9b79e76b, 0x0c8e7327, 0xe6022562, 0xdb315dcd, 0x4a426cb4, 0xd468ec6f, 0x67b20096, + 0x94ac3732, 0xbc8c8101, 0xa3df1b9c, 0xe2536cd3, 0x950752bb, 0xc52a224b, 0xa07d2199, 0xfd631db7, + 0xccb731d0, 0x3bef4dad, 0x2ae72daf, 0xad15b0f4, 0x61d24018, 0x65937f47, 0x61c27429, 0x659bdbd5, + 0x1a184126, 0x8c3f2a4d, 0xeee82a77, 0xcb4d79ea, 0xa585ec2c, 0x7be4f309, 0x48f84bee, 0x8f2eb866, + 0x6a7ba3f8, 0x8681f660, 0x1be2cf7d, 0x3ff1d20e, 0xf635fce3, 0x05d804ef, 0xd12cf373, 0x07d2f3d8, + 0xfd816280, 0x927f9f66, 0x7f255b2c, 0x4d1c635e, 0xc113bb8a, 0xb3437c8b, 0x8d9cc6ac, 0x6df3b052, + 0x1712996f, 0x160b6b06, 0xbdc0bd61, 0x6780b314, 0xd1d9e306, 0x0674b370, 0xd8567937, 0x6c82c1a4, + 0x48a064f9, 0xf7c96d94, 0x466fab2c, 0x36f87741, 0x1b47eb5b, 0x6dd2f6c4, 0x7cee31c4, 0xec92bd93, + 0x5aada10c, 0xfa23c10f, 0xa1a552cd, 0xe0957d2d, 0x7f252ebf, 0xd78cc072, 0xf9ff05fd, 0xf4a4a4f9, + 0xbf74a7b6, 0x700c80a6, 0xeb74768e, 0x5e9f93e0, 0x83578770, 0x243327fe, 0x680f6356, 0x780fc515, + 0xaab789ac, 0xaf4ccd9b, 0x689b88a4, 0xef6fce03, 0x75933189, 0xf24236d9, 0xdc8e99df, 0x2d6efbd8, + 0x6578008c, 0xa2504073, 0x76963166, 0x6f5ca3fd, 0x8743c02b, 0x16468721, 0x4c8a86b5, 0xff42c086, + 0xbae75bcf, 0x4f9b9fa6, 0x0e982db8, 0x70cff6be, 0x7bd13e59, 0x928619d3, 0x639c4012, 0xfa944bc1, + 0xd2c84ab6, 0x71ace618, 0x86caf276, 0xb4514408, 0x4a700382, 0xd5056f1b, 0xb4431f61, 0x92fb1129, + 0x91b8854f, 0x2dbfac6c, 0x2426723c, 0x32016673, 0x982a157c, 0x56a5de9d, 0x45408033, 0x4d5b264a, + 0x6ea3119b, 0x451d6dbe, 0xd70fdf0b, 0xd57afda6, 0x6f22bc3c, 0xc16e7e83, 0x099803b4, 0xc71b7b3d, + 0x4fcaa9ed, 0x73c932ac, 0xb8e636a3, 0x1c65c205, 0xc420d12f, 0xafae7026, 0xbedd5b47, 0x92353f4d, + 0xca555e7c, 0xd5ef4eb4, 0x317aa84f, 0x6934065e, 0x8cec293a, 0x055b4be6, 0xe7aceae1, 0x42fc5994, + 0x2ecf5dc4, 0x0aa6ecd9, 0x5eb765d0, 0x9eb13888, 0xb90fd8e2, 0x793b5f6d, 0x3a611c78, 0x0c71f477, + 0x986febbd, 0xd3826214, 0xd87cca82, 0x5336e84c, 0x0b3994dc, 0x77ebf524, 0x093fb887, 0xb336f9a0, + 0x07d69447, 0xf485f5ce, 0x04f342ca, 0xc38fc6a8, 0xd462b149, 0xf30bf85c, 0xb71ff9ea, 0x2809eda9, + 0xd01eb5c9, 0x9fa73851, 0x02f7dcbe, 0xb22f7674, 0xb1fce2d9, 0xeb13444c, 0xd6c70ac7, 0x22de7e1f, + 0x0fdcb3ff, 0xe40a18c9, 0xe01a58d6, 0x758b5d53, 0xcbfbddae, 0x4a60820d, 0xf79fc1e6, 0x451901e1, + 0x715d2a40, 0x5b68bab4, 0x56b5e2a1, 0x58945b70, 0x58e03dcd, 0xf892734b, 0xa124b209, 0x4b33c9da, + 0x60d2cf97, 0xa65063dc, 0x8f41cf29, 0x3bd21b5c, 0x3be9983d, 0x2b29ec35, 0x94fc41e5, 0x291e2b4a, + 0xd657111e, 0xd7a85fa3, 0xf1248c71, 0x679eca51, 0xccc9497c, 0x95304c1a, 0x802725f0, 0xfde2e1ee, + 0x176d2055, 0x787c8131, 0x6b7d3c7a, 0x55d4503c, 0xdeb839e1, 0xe067eac8, 0x321987ea, 0x8f6a600b, + 0x261ff80a, 0xee5ec10b, 0xa04e6a28, 0xa22d806c, 0x1dee9f73, 0xeb20bffe, 0x2b0ebe4f, 0xebc0be21, + 0x20523756, 0x69267fdb, 0xd5468c51, 0x7a1ea2c6, 0xef8128c7, 0x4acc453c, 0xc712d7b3, 0x9d7ae89f, + 0xbcd3b7d9, 0x62ef70ea, 0xf5e0cf02, 0xed4be9af, 0xe7890be4, 0x51a4aca8, 0x5501da0b, 0x5074776e, + 0xab659b20, 0x1263fd80, 0xb5158726, 0xd65b003f, 0xaf7dc77f, 0x22dcfd94, 0x3d1ebc00, 0xa5505214, + 0x19eabb5f, 0x341ae766, 0xdbbf32fb, 0x7db59984, 0x46e15396, 0xf897773a, 0x15ab49fc, 0x5bb45bce, + 0xacfa070e, 0x6ce3dce3, 0x8e011bc2, 0xe355564e, 0x85b7a4fa, 0x20ee3ef9, 0x5a375b24, 0x2b80a635, + 0xeb449bd7, 0x1ad0c4d0, 0x53f21c60, 0xfa49a92d, 0x29e55acb, 0xc898ddcd, 0x54eea787, 0xdee38fbe, + 0xabceedb1, 0x734621c5, 0x85bbb2e9, 0xe08ef671, 0xff06505f, 0x4f1aae56, 0xc520c5bf, 0xfdabcfe6, + 0xfcfae7e1, 0x94644ea5, 0xda17af8a, 0xf2e39c03, 0x91da846b, 0x6933a825, 0x55cf9bd1, 0xcd698e3a, + 0x6a3da818, 0x2fcf6e50, 0x2233dbee, 0x1ad941b2, 0xdf8bf2c1, 0xa5cef9c6, 0x52c144ea, 0xb9b20c07, + 0xcb73607e, 0xa00d6182, 0x9ed3a569, 0x60bac318, 0x773618d2, 0x21cc9e6b, 0xc269c9f6, 0x4d3a7546, + 0xffdf9b80, 0x5ab4db4b, 0xe5c1d189, 0xfe6649f9, 0x8e973a92, 0x18de3f97, 0x0c83d550, 0xb9e1f37f, + 0xb22faa9d, 0x741e8af8, 0xca3d9aa2, 0x1c176977, 0x700d878a, 0x892c0e9f, 0xa63b3fc1, 0x5c028dc1, + 0x59a4f5b1, 0xfcca60e8, 0x209768a1, 0x191931ca, 0xe27d7768, 0x3b413d19, 0x61396079, 0xb2aca0b3, + 0x11d02501, 0x786227a7, 0x645a0037, 0x166c5f20, 0x0e958fe9, 0xdcc5b4d1, 0x1a58d3a1, 0xe94e5f50, + 0x287b8b13, 0xdbf173e0, 0xf3491f34, 0x3f3f093b, 0xafa614f6, 0xf3507bf0, 0x526e28d8, 0x4e580ff0, + 0x24b5a7fb, 0x8117669f, 0xa4545271, 0x32a59fc5, 0x7f57fe4c, 0xdbb6499f, 0x047fda68, 0x1e84000f, + 0x6d8ac03b, 0x68c19258, 0xd1e64fde, 0x857a14a3, 0x3b8c7853, 0x5cb1c20b, 0x3d1422b7, 0xc61a2921, + 0x64ec5824, 0x915e2e38, 0x002c7325, 0xf360da16, 0x8a1f5838, 0x6f79e556, 0xe7ed9d38, 0xce378e9c, + 0xfeacdec3, 0x8d29cfb4, 0xa90c014c, 0x3e224294, 0x5452b66d, 0x6f800d22, 0x97796de8, 0x4ed92e06, + 0x033b3b14, 0xc55bb379, 0x85a0bbde, 0xebea36c2, 0x694907c9, 0xea0ff7dc, 0x0bb7f30e, 0x64c65899, + 0x32fe4539, 0x6788f13f, 0xca6e2af5, 0xbba35a7c, 0x44cc0385, 0xebb1c78c, 0x89ecd243, 0x3187c6ac, + 0x255d9003, 0xcf954bd2, 0xa0aec9cc, 0x12b12546, 0x982d6f20, 0xd218c396, 0xd0d30214, 0x15889a92, + 0x9828dd43, 0xb180d5b8, 0x4d8bc93f, 0x80a4d246, 0xc224de92, 0x2d9a7aed, 0x3f33af1f, 0x001032fb, + 0x74b0c4d5, 0x58e4449a, 0xdc6567db, 0x9a7c0509, 0x8814a2f5, 0x750682c0, 0x65017670, 0x38cc9488, + 0x0ce81c49, 0x93487108, 0xaff5a754, 0x4706fc32, 0x57721bd8, 0x14cf25be, 0x28c24f5c, 0x27c42c55, + 0xa9682726, 0xbe9a9b4d, 0x1cb3727e, 0xd4e04ae9, 0xf0474c90, 0xc4597d52, 0xc0a83482, 0x5aea45fb, + 0xb7678bb9, 0x41470880, 0x74fb9e3e, 0x01e34be6, 0xbac4452f, 0xe8bb5207, 0x5c14ff37, 0x5bfd5527, + 0x8081b99d, 0xf70f2cba, 0x72d54edc, 0x334b3d4d, 0x23b29c12, 0x5d9156b0, 0x36ec0b25, 0xfa91092a, + 0x0626170a, 0x2ff2e63d, 0xcf7eed99, 0x72d73870, 0xb0f3b360, 0x53cb0c19, 0x52d3b731, 0xb10609a1, + 0x72cd27fe, 0x64234203, 0xdffb39bd, 0x6adff969, 0x40c7418d, 0x0380cbca, 0x1df3356e, 0x7b503483, + 0x2224f1bb, 0xeef5f086, 0x7f79ecc9, 0xf3ab862f, 0x1924fe91, 0x6ff194f8, 0x660c5edd, 0xaa7cd150, + 0x48a4f02d, 0x81796c16, 0xd89a028d, 0xe48e3827, 0x6915b915, 0xe31793f3, 0x73b377a2, 0x7f2e52d7, + 0x1c4420cd, 0xe584cf90, 0x4d1448b0, 0xe7f4d406, 0xd4e4c72d, 0xada67e83, 0x0f3db2bc, 0x4872c17d, + 0x2a0a8563, 0xdf7d7a80, 0x42dc3455, 0x7e762f99, 0x5b09de78, 0xe305e01a, 0xe7576eff, 0xf2ce5e37, + 0x73489f52, 0x77ebef15, 0x384552fb, 0xabcef07d, 0xde5250f5, 0xf77066ec, 0x279b6934, 0xa36d6585, + 0xbb19288d, 0x07efcb9b, 0xd3a88456, 0x15c220f0, 0xa0723afb, 0xf41c7e75, 0x7c59d144, 0x8dc55a0a, + 0x483a7c33, 0xf4189d46, 0x49497a3f, 0x397d1abc, 0x52eee4b6, 0x5eb2e773, 0xf771ae7f, 0x92faae03, + 0x2e66193a, 0xee7b466f, 0x31f076d4, 0x6548636c, 0xddaeee1f, 0xe23b07d0, 0x36403748, 0x09ac4e10, + 0x25aef4a9, 0xb4930401, 0x0b83bf24, 0x5ca2c606, 0xb791d523, 0x4e3eb779, 0xbb379f07, 0x8714947e, + 0xdc8a683d, 0xfc8e6ec6, 0x32644841, 0xa5ec08db, 0x42ba1b8d, 0xe0145083, 0xfa0cd506, 0x10497c4e, + 0xfc985c4e, 0xeb688737, 0xc1c4a9ee, 0x9d29ded2, 0xe1721ac1, 0x8f57c902, 0x43057e4b, 0xd9e60da6, + 0x87a50b9c, 0x528a56f3, 0xf59a4bf6, 0x23e49572, 0x8a232a41, 0xd32dfb66, 0x970fb6ae, 0x19d217cd, + 0x4ef108a9, 0xbb69c014, 0x5641aa6f, 0x8678df7e, 0xec77be75, 0x58e948b5, 0x9a56aa40, 0x3023e88c, + 0x9e449b12, 0x7d4dc5ae, 0x25a6f210, 0x633726e0, 0xc08f0756, 0x1db402db, 0xd7f2d97c, 0x29193f6e, + 0x6ed3d0e0, 0x8518cebf, 0x2f8a796e, 0x6f0af762, 0xd3a5a362, 0x55d81eef, 0xc7dfec88, 0x14f0affd, + 0xe5fe6542, 0x642bc381, 0xe6d795d2, 0xb63115fe, 0xc4a11f72, 0x10e7dd14, 0x45fc7db5, 0xa9d41cff, + 0x43e8d82f, 0x00936317, 0x0bd7f765, 0x37461ba9, 0x5ea6c2ba, 0xc8acf510, 0x882e273e, 0xc5dd6a7c, + 0x95447628, 0xa9fa8794, 0xe5f83994, 0x4ba7dd64, 0xf5239837, 0x9b6a033b, 0x84f5291f, 0xce942632, + 0xb9c4022c, 0xd9b81d99, 0xe0e78859, 0xff20da6e, 0x81b6f42a, 0x7d20638f, 0xe291746f, 0x17383cca, + 0xd8efe0ed, 0xbc69b0b8, 0xecd2d80c, 0x65f723e3, 0x709142cd, 0x81c468b2, 0x81d41ee4, 0x11d666ba, + 0xa33792d4, 0xcc0a9fdd, 0x83498c91, 0x72c7b55b, 0xfbff9022, 0x8184a309, 0x2dd590a3, 0x3abf167f, + 0x4ef746bd, 0xcb8571cf, 0x54022191, 0x371ba271, 0x8530fb38, 0xa14a4df1, 0xf8050630, 0xe207ebe8, + 0x88085fc5, 0xc15a3500, 0x35c019a2, 0x95866f07, 0x42c8b7f6, 0xc38ab47f, 0x1e6bf20d, 0x346c7f65, + 0x3b6c5990, 0x7f21f0f3, 0x59bb4bc7, 0x26912bcf, 0xf5dcf9ce, 0x32ba3c4e, 0xfaeee32d, 0x525e9f72, + 0xe93b236b, 0x8ead1adf, 0x740de107, 0xeb877f98, 0xb21ee99d, 0x706ec5a6, 0x600b0d87, 0x5fa23d92, + 0xd7684697, 0x7d20d986, 0xd94ed800, 0xbc2eb8c6, 0xc1c63def, 0xe6b82387, 0xe2892162, 0xbf2d5b09, + 0xcb0b3e07, 0x3d75cdf3, 0x808b26c5, 0x81b1696b, 0xdf93e40e, 0x46b7e281, 0x39f237ab, 0x4821e91d, + 0xbbb83e12, 0x70cc9bac, 0x356626cb, 0x80ae0593, 0x86cdf409, 0xad54d6e9, 0x3e718c9f, 0x2cad3672, + 0xf7c85d55, 0xd7a0facd, 0xef909f9d, 0x9058eda9, 0xe337f374, 0xc210291b, 0x77819332, 0x1704d273, + 0xa3ee6275, 0x62728926, 0xf18dc8fb, 0x5bf29f44, 0xa48739fa, 0x26d8a42c, 0x7203ef33, 0xbc2d4f49, + 0x1115409e, 0x4c37723b, 0x3c09c0ff, 0x9568433e, 0x7da0c741, 0x1ae2d4f0, 0x96829fcd, 0xc015f330, + 0x197bcb89, 0xe558b7cd, 0x0a8d9cbb, 0x0341a50b, 0xef4f44bb, 0xe45c5b51, 0x28166e5f, 0x7dbe4b43, + 0xc185b111, 0x98cfe523, 0x2a09f798, 0x0ee05b08, 0x0104a821, 0xc3aa9f93, 0x1c4b7c65, 0x4c480714, + 0x4514a0e0, 0xbd578e7a, 0xf84a9996, 0x3b79c70d, 0xbb14a01c, 0x244d5a2c, 0x9a6acfd6, 0x06b61dc7, + 0x426c2d82, 0x12c03cbe, 0xad283ad6, 0x798359a9, 0x32183e43, 0xf60ace29, 0xe09b3d25, 0x9f61fc30, + 0x0b501f48, 0x5e25e349, 0xfce34278, 0xc34000c1, 0x61423c92, 0xb5061e63, 0xebe82b96, 0x5443084f, + 0xe6e172b8, 0x0c018aeb, 0x4e1bb4a5, 0x7feba506, 0x45017896, 0x13548d63, 0x5265731a, 0x52d7b1dd, + 0xf441dbb2, 0xe8ffa24f, 0x789eae6e, 0x473372be, 0xaf13f786, 0xf8c68612, 0x8f5c67ad, 0x8412c5b9, + 0x55f085f2, 0xe442f123, 0xc848f7b3, 0xfd1444f2, 0x3d67ea5a, 0xc308fc4d, 0x840abe34, 0x981e179b, + 0xe5fd5541, 0xe9204965, 0x049aef20, 0xb603c6a7, 0xdd4caa30, 0xbbb9dc67, 0x0b9aceda, 0x5d8c543a, + 0x678b2992, 0x221de570, 0x07515850, 0x69cd89de, 0xca7c8821, 0x13ec2312, 0x22fd4644, 0x89b0ce41, + 0x70f781a4, 0x43bbee6a, 0xc93f928c, 0x245ff39b, 0xe566fa4f, 0x6d4e359e, 0xe70c4cb9, 0x884786af, + 0x299cf3f4, 0x5aa233a7, 0x6bb6f39b, 0xf6df2419, 0xa791f80a, 0x1ce74ef9, 0x8ac82d34, 0xc8377c92, + 0x29d9abb4, 0xf7dab3c5, 0x7c8b7a6d, 0x56722fb2, 0x7d4e996a, 0x499dbda8, 0x88529a3c, 0x88653dec, + 0xffa49166, 0xed4810a2, 0x3c895a95, 0x12b7ddfd, 0x7c0995b7, 0xfd035d75, 0x7f8b277c, 0xed7bdfd0, + 0x9011e17c, 0x02333253, 0xbfdc2a0f, 0x85eedce1, 0xc656253e, 0xcdc26f06, 0x934385d7, 0x9d189a26, + 0xf2b01c59, 0x12804d02, 0x1dee3ddc, 0x53193bdc, 0xbf1e0285, 0x8c19303d, 0xd1d19b9e, 0xea9cfbc6, + 0xa52b9748, 0x980dba61, 0xe3b14395, 0x1595caf2, 0x3019717e, 0x2912ea0d, 0xb83e4126, 0xcf0b7a2d, + 0x6423bb62, 0x202e1237, 0xe2d4f36b, 0xba481a59, 0x7f2f083c, 0xe62de948, 0x2bad6b90, 0x3ea59bab, + 0x02c8cf6c, 0x658c26a2, 0xbf825b70, 0xca9cdc76, 0x670323e9, 0xd6b2ecf0, 0x50a10c34, 0x81a38a62, + 0x68cf6942, 0xb993d32e, 0x065725de, 0x32cd84cb, 0x36e3776d, 0x6765d41b, 0x302831d2, 0x31315cb3, + 0x89e8ad6e, 0x6d5cd629, 0x897a4a9d, 0xe64e8196, 0xcf9891e0, 0x3008d75f, 0x85ccaa20, 0x617979f4, + 0xa12cc8ea, 0xa1d92693, 0x54f3e01d, 0x78a21ee2, 0xa12e3e8a, 0x3168f9a6, 0xbd9b07c0, 0xce98041a, + 0xd9869c49, 0x35bf661f, 0x62f4e974, 0x997f3a98, 0x6bb8de65, 0x21ec6264, 0xc0faf18b, 0x4a428e2d, + 0x583c8091, 0x566a7ed5, 0x31055da5, 0xdb8bdf80, 0x2e563801, 0x2ed21ac5, 0x17b2b2e2, 0x8a612503, + 0x80e82c79, 0xa9019884, 0x864ca9d9, 0x255634fa, 0xae5da14d, 0xd5a817c6, 0xe426330b, 0x83b13e57, + 0xa402c1f4, 0xe6af1247, 0x31cd7c1a, 0x0a97d595, 0x761e842e, 0xd9db4e05, 0x9e597433, 0x4cb61369, + 0x732bf03e, 0x1e78ef03, 0xf214ed53, 0x11819d81, 0xb0c2858d, 0x8afeef58, 0x02c9ea7d, 0x020d96c9, + 0x78780243, 0xe1d4293b, 0xb599cbc9, 0x09a2033a, 0xdef2b734, 0xc57eea11, 0x479ab227, 0x35e4729a, + 0xc51413fb, 0xbc7a05f3, 0xe8ae46fd, 0xab5a4447, 0x26a0a09d, 0x1efb1895, 0xfed6281c, 0xb74ab25d, + 0x439c3d86, 0xd10be2fa, 0x68d62e5a, 0xf0a5a07d, 0x8f39228a, 0xc7aaaf85, 0xd28d0428, 0xcdf91c66, + 0x62c71a4b, 0x768879a4, 0x763b0eaf, 0x603bfe87, 0xb5360375, 0x46c4d1bc, 0x63695b76, 0x66c0e4bc, + 0xf05ee888, 0x0de597e7, 0x2b1b612b, 0xe5b57321, 0x9ffcc8d3, 0x4fde2616, 0x82fd3e29, 0xab0f2265, + 0xf5ba539d, 0x9b2e460b, 0xc8325586, 0xe5168cfa, 0xd840b83d, 0xca17afc8, 0x770fa989, 0x1fbf7985, + 0x6b21f605, 0xfce496b2, 0xc91402e3, 0x400ce901, 0x0bbb0003, 0xcabf1ccf, 0x714e6467, 0xa242ebbf, + 0x302dca21, 0x637abc93, 0x5c08618e, 0xbb0e7f61, 0x0ba60ef4, 0x5ae265f3, 0xe68395f7, 0x9e22acdd, + 0xdb23a0fe, 0x324fcb93, 0x01d3370c, 0x6eb1e4df, 0x86dec2a6, 0xc7528511, 0x8fc98066, 0xb64fe6cd, + 0xbb6e9d60, 0x4f3ff123, 0xf3e46569, 0xbd81afdc, 0xf993860d, 0x39b341b9, 0x28ded9d2, 0xf17b11c9, + 0x81d47407, 0xc0f849ee, 0x51ff768c, 0xcdbb2c05, 0xfcf4f373, 0xa289a545, 0xb21769c9, 0x17e52aaf, + 0x0be43334, 0x14aabecc, 0xfdf4d629, 0xb1827a4d, 0xbf677e7f, 0x674ecfcd, 0xf7e023be, 0x4ee7c9f5, + 0x8c79b10b, 0x7724ab5a, 0xb8ef46e1, 0xafce1d6a, 0x10d79829, 0x19180b72, 0xf017e83d, 0xc249a932, + 0x49242c39, 0x44eba76c, 0x74388d1a, 0x57046253, 0xec26400c, 0x0f9b52c9, 0xb35525e2, 0xf9d8a954, + 0x06bccc74, 0x7857e9f1, 0x72a3b56f, 0x115b7907, 0xda3cfe9c, 0xb27910ab, 0x4fda1f17, 0x4ea96376, + 0xec0ad1c2, 0xb6c2defe, 0xf782d037, 0x354e6325, 0x9c5e0ebc, 0xc8b4068b, 0xb7f283de, 0x59ea81f7, + 0x74bb863f, 0xdcc46db9, 0xfca17517, 0x44006ad9, 0xa8c23931, 0xeb39bd1a, 0x0d969e5a, 0xa3a39661, + 0x8243d2f9, 0x17aea6d3, 0x0c94f1d3, 0x6fd4f2a6, 0x4219c7cc, 0xcdf85718, 0x90c9f05c, 0x4c1d6ebe, + 0x79465288, 0xd50574d1, 0x45fb8b9a, 0xddce7664, 0xcd10d879, 0xed3d74a3, 0x0846bc16, 0x0c51e838, + 0xeb2ee8e6, 0x516be1f4, 0x9be56845, 0x4ba95c7a, 0x1c580480, 0xa8572fd8, 0xa380b262, 0xd8a210c3, + 0xd6eecbb6, 0xd015b6e5, 0x9d34d64d, 0xd07782ca, 0x15873318, 0xc576602a, 0x2f3f430d, 0xbb1d6478, + 0x2b31f116, 0xc3a4c91c, 0x1ddf0c3d, 0x9c30997a, 0xaaba20e3, 0xa8cebbc3, 0xe28e8bd7, 0x89adf650, + 0xc3c3a4bc, 0x5256d0f6, 0xcd3f4c87, 0xbbe2931a, 0x450433e8, 0x3d9be8d5, 0x1306cbc9, 0x5861704d, + 0x4e4a2315, 0xcebbd997, 0xe2c5d246, 0xa5ea001f, 0xb35a2323, 0x7f85f024, 0xaae03704, 0x4c2eb9dc, + 0xe8737170, 0x65866cbe, 0xe7667775, 0xe716714a, 0xf26ed911, 0x81861943, 0x1ca88762, 0xb7221a1c, + 0x9bf71417, 0xbd6867b6, 0x86c488c7, 0xa691be87, 0x49617f06, 0xa2754496, 0x54ba5b94, 0xad652e8c, + 0xdc362e05, 0x169fb6d8, 0x3333e9f0, 0xa9de9707, 0x9d3a6381, 0x6296a496, 0x92afc50e, 0xba6c5651, + 0xc559ed2d, 0xed7b5882, 0x132a574c, 0x282105a3, 0x41ec5bbf, 0x945cd05a, 0xd8e3d8af, 0xeb61aacf, + 0x47025c12, 0xeec4f831, 0xd03470a1, 0xd4787802, 0x07f657fa, 0xba1c54b9, 0x257f1205, 0x73a8763c, + 0x991f1b02, 0x8de0f3a1, 0xd009e5c5, 0xe7be0759, 0xd650c347, 0x057b7d6c, 0x9bf518b1, 0xc9b6de20, + 0x9a0cf59e, 0xf2d90087, 0x5ab0c6c7, 0xd0167777, 0x90fb1636, 0xc53d04fe, 0xa839edf1, 0xc941e8e1, + 0x12777678, 0x84f36475, 0x9d09f39d, 0x16ca8e3c, 0xffa435f3, 0x34711498, 0x33096298, 0xf98ec3ff, + 0xfdecb1a6, 0x8f221fa8, 0xea7d070d, 0x74fdf765, 0xe303f757, 0x5187b0a9, 0xed6bb0c3, 0x6142ea3e, + 0xc4d10e32, 0x03bc6131, 0xf7e9c839, 0x3c78f8f6, 0xd52e9f4c, 0x0bfa25a1, 0x7c6f8c63, 0xa8705a7e, + 0x12f5b5b6, 0xc26c4fec, 0x84539184, 0x2ea09723, 0x31f63080, 0xcc0dcb38, 0xba678830, 0xac9ba46a, + 0xcf073d97, 0xe7cef3e4, 0xc0a26e96, 0x9cfe3fb8, 0xc787ea80, 0xa02d2998, 0xacc5fc53, 0x970206cc, + 0xa2957e20, 0x3f463914, 0x927f7f63, 0x8f093fde, 0xdf14e671, 0xa4f8dade, 0x02c86335, 0x0474ec50, + 0x2933190b, 0x7a3b1ad7, 0x321ff949, 0xc0296a28, 0x11ca1280, 0xf3697fbc, 0xe29b8882, 0x6ec7a591, + 0x4a2890a6, 0x2bbdbc89, 0x9e0814dc, 0xb58ae18c, 0x5d776f33, 0x5b21481d, 0xaf433710, 0x7361e0a2, + 0x3908f3ac, 0x18a45823, 0xd79491b0, 0x1790828f, 0x48d7aad5, 0x90d0b47a, 0xbc5607bc, 0xcd454798, + 0xa8f041f6, 0x55560792, 0x49313fbe, 0x518a8b7f, 0xcae43e6a, 0x8f4aa719, 0xbf2192ca, 0xd1ace7d0, + 0xbbb74a92, 0xd374fdaf, 0x4c245c49, 0x9c5f4a77, 0xbaaa2ba4, 0xfcc90e08, 0xd058b80c, 0x0a7edb50, + 0xd85367a9, 0x7f47f998, 0x2ac42362, 0xef561617, 0x7c50a029, 0x051ef621, 0x16f69e41, 0x386f1acb, + 0xd29c33e7, 0x636ae2f8, 0x824a6141, 0x16acd3c6, 0x17a78b8b, 0xf8f90660, 0x5db97047, 0x4f501ab3, + 0x73c43bf4, 0x52f001af, 0x323e36f5, 0x0a3c0d05, 0x62d418e4, 0x3e78d1b0, 0x91396a5d, 0x34dd8499, + 0x562e5819, 0x6435b0f7, 0x13c1ab64, 0x2f0ef97b, 0xb9d8dfb7, 0xf9a3833c, 0x92790e33, 0xc1075847, + 0x89be6b42, 0x4c22bc04, 0xaccef2e9, 0x580cfc74, 0x6628785e, 0x7ec3cce2, 0x8ccf81c9, 0xfc4fe7d4, + 0x6bc2807f, 0x2c894945, 0xa89b45ec, 0xa3892358, 0xb6996e22, 0x8a992c3a, 0xe636e5c8, 0x7ec203fe, + 0xd5b405b0, 0xe33e27cf, 0xb55d21d5, 0x5f962c94, 0x63e50c69, 0x523bf36a, 0xba6d51b2, 0x404b1b84, + 0x4c79c508, 0xabca4fc3, 0x7b9a1933, 0x147967f8, 0xad6efec7, 0x8de29362, 0x9fac6406, 0x3dc6121b, + 0x3ac9644a, 0x4c14c0eb, 0x47752aa1, 0x2a2265bc, 0xd432e75f, 0xfedf155d, 0x409a730f, 0xd80e02ff, + 0x75cad9d1, 0xa627facb, 0xad69feff, 0x7abe2053, 0x53e3ae0e, 0x97358868, 0x6ddf2bb4, 0x7dd3a66e, + 0x15d9769c, 0xee39811a, 0x8f2e343c, 0x0c540421, 0x33f1dd58, 0x8eddcdab, 0x70152f38, 0xdfdbe9bd, + 0xa4316352, 0xa8e8dcb6, 0x4104dd50, 0x3f09baff, 0xfb218f32, 0x418ab609, 0xf550e915, 0x5072f271, + 0xac287e1f, 0x839ecc7b, 0x3f568f36, 0x49760b12, 0x2fe281a5, 0x04196850, 0x3a9d2bdd, 0xd6e11ce9, + 0x9165d9ac, 0xb433a250, 0x3cb5e6d5, 0x8cc06e6f, 0x73231e25, 0x9612ee28, 0x4e8e467e, 0x0ee0a276, + 0x2677bc3b, 0x84587d8c, 0x38337cdf, 0xbb0a5f20, 0x7f96d614, 0x20e36f71, 0x6ff52214, 0xb5a59311, + 0xba539629, 0x5652e080, 0xd2cba3bc, 0x32b2cc20, 0x213995af, 0x75424984, 0xc1107a24, 0x9938e5ed, + 0xafc21b22, 0xc751f712, 0xc7145664, 0x59ef00e9, 0x57dd726e, 0xcd354ca3, 0x76a21aa7, 0x6b00c13e, + 0xa9600acb, 0x6e9547ed, 0xba303361, 0x5234a724, 0x1bce8f56, 0xd01d7662, 0xc3ec4725, 0x56e75bf6, + 0xa96b5bf8, 0x9edd670c, 0x1bdc5229, 0x57023fa9, 0x45f6fc13, 0x0c5a3150, 0xcdb02334, 0x172458a9, + 0xba77da62, 0x1d46f65c, 0xddfaf5e0, 0x8b539f12, 0x68e6d877, 0x4eb0acf8, 0x44d5e139, 0x1d5c3cdf, + 0x14ef414d, 0xe18c0b26, 0x51c71ac7, 0x869d7b1e, 0x40d05317, 0xe4c032f6, 0x8f226ad5, 0xa75fbfe5, + 0x04a8d4d5, 0x0752e873, 0x87a2d332, 0x70b84d05, 0x1a3b38d7, 0x3ebf8b61, 0xd57c0d61, 0x2a15176c, + 0xab5ced2d, 0xd709bc8c, 0xf241d64b, 0x2adad365, 0x68251994, 0xec85cf15, 0xcccda1f3, 0xef928262, + 0x4c05cc05, 0x822f5b15, 0x945a3af0, 0x95ad5089, 0x3b85b080, 0x1f655981, 0x8e2af420, 0x10fecdc3, + 0xcac32b32, 0xaf3ef414, 0x82da015f, 0x0aebf7d8, 0x54bbcd4c, 0x76517574, 0x602ab358, 0xade3af95, + 0x0dac674b, 0xbd3e317c, 0x154187f2, 0x0e3282cf, 0x2bf3d7e1, 0x2974bb6c, 0xb511e3a9, 0x3aa59e6e, + 0xd688cbea, 0x531c67e7, 0xf3cafef3, 0x931f9ca4, 0x217e3c2d, 0xb72bfcd7, 0x86e16cb5, 0x2e6b314d, + 0x8a8e4bfb, 0xba3610c1, 0x11c7bb71, 0xdc1f604d, 0xf4554a67, 0x89199ca3, 0x1d1465dc, 0x1b931225, + 0xb395cf7b, 0xac33f16a, 0xc3c9e75c, 0x9eefaaa1, 0xc10d3f44, 0xc8e562b0, 0xded761fe, 0xb1d94a33, + 0x30d1175a, 0x2769e347, 0x63485318, 0x5fdda108, 0x5f2bc364, 0x549b7730, 0x72bb0cae, 0x8c62bb2e, + 0x8a4bd7ae, 0x790b3664, 0x6df2b01f, 0xb2265343, 0x3d84b231, 0x690cbc06, 0x52e1f0c1, 0x63fbf2e9, + 0xb1c9b9db, 0x7bfb5c11, 0xfda46539, 0xeba7f20a, 0x12abf0c6, 0x6b9d38e6, 0x5296a10a, 0x2ba6cee2, + 0x2a932594, 0x0bb49924, 0x1808cc73, 0x1beb34a8, 0x96e5426d, 0xb73f94d8, 0x833984b2, 0xa3ef6b23, + 0xa7da78c6, 0x00396fe8, 0xcbcc65f4, 0x1957d95b, 0xf3dad9ea, 0xd74dca5d, 0x3a3bffd9, 0xfc96947a, + 0xb5b872d5, 0xe716863a, 0x8a698558, 0xd2c6d2b5, 0xd6986924, 0x0ce91e84, 0xfadde712, 0x56f522ba, + 0xf17066b8, 0xdab2511b, 0xb7b505fe, 0x4b83021b, 0x5eb2f4eb, 0xb9b8acd3, 0xaa1c91b6, 0xdcc6b2b6, + 0x35e06767, 0xa50923b1, 0x6ee3a370, 0x98069ca0, 0x9a94f292, 0x773ac6a1, 0xbf3a2aec, 0x1da60683, + 0x87bba9e8, 0x8bbb3d10, 0xcc9101d3, 0x49a273e1, 0xbd934cf3, 0xd5863dc1, 0x2d9e1412, 0x0881edc4, + 0xdde4e38d, 0xb7c244f5, 0x2ea37823, 0x38246751, 0x4ac3f459, 0x3bc2da78, 0x73c984f7, 0xefb4f27c, + 0xebe2b8d4, 0xe7b70bd9, 0xeca2800e, 0x50837f21, 0x05989a69, 0x8d0555fa, 0xc9a5163b, 0x201eca69, + 0x7e7cf721, 0xbcb9085a, 0x01849aa9, 0x7af8e9e7, 0x27db55a6, 0x2ecb5efc, 0xc9e329da, 0x33ef832b, + 0xac003efd, 0x2f8c16d6, 0x0f228e75, 0xa35a2602, 0x1a47a752, 0x9bd4b6b5, 0x18ccf462, 0xe1ceeb2e, + 0xf962ddf0, 0x2195dee7, 0xb8c5df95, 0xc7a71906, 0x1ab75fb4, 0xe6727c96, 0xe9f5d8f8, 0x53555221, + 0x47b4637a, 0xd834023e, 0x206642f1, 0x595a1806, 0x39da3c97, 0xbacdc31e, 0xa3bc2015, 0x2ab2cf91, + 0xf2383589, 0x7892766a, 0x82fc5478, 0x80deb905, 0x95978603, 0x6996a5f0, 0x9a6f5c28, 0x928f38ef, + 0x615d5ddc, 0xaedba7fe, 0x2b1438ce, 0xe89c5d62, 0x732e1afa, 0x0d5b317a, 0x652da6ac, 0x2b00457f, + 0xc9950cb6, 0x0e1b0dd3, 0xe2cab322, 0x2a16e525, 0x1630b58b, 0x9bf5e4d3, 0x613b8c70, 0x8f72399f, + 0xa4370400, 0xc6f3f0d3, 0x13ea0cba, 0x28b8fad5, 0xcaf90f9e, 0xfd04be14, 0xab5c95b3, 0x5fba5918, + 0x74c7b2f7, 0xf92fd3d1, 0x0ce4c27b, 0x1a68c00d, 0x5796818e, 0x75de9820, 0xef4ba240, 0x2d22c7b4, + 0x1dcee3a2, 0x0e6e5e9f, 0xfaccb185, 0x1209e5b2, 0x0d134795, 0x78fe018a, 0x81558d3e, 0x4fed4cc8, + 0xe6f564db, 0x93063822, 0x9bcedf01, 0x5b5497f7, 0x27981fc0, 0xf90fa19e, 0x389cfb18, 0x17b661e2, + 0x98e5831f, 0x9ad39ca4, 0x5194b1cd, 0xb07e6e7c, 0x6981c36d, 0x7e21f01b, 0xc45ce9e9, 0xdd8306ff, + 0xf1bd7351, 0x628aa59e, 0xe80d1dc3, 0x2ef2a9ab, 0x8962b2da, 0xe1611f18, 0xad2fbefb, 0x93b5f800, + 0xf5936cec, 0x708708c3, 0x9dd98155, 0x924b7de5, 0x3d8225a0, 0x61e8d2ad, 0x3241dc15, 0xd9fd2369, + 0x06f10d41, 0xc20b4b71, 0xe7fd4709, 0xab45e8cc, 0x2873df94, 0x0e09de93, 0xa4a759ce, 0xe63d1357, + 0xa0bf9e53, 0xd15a1169, 0x3734830c, 0xb7c95fca, 0x8f0ce2e9, 0xf7bb4968, 0xf6d9138f, 0x4ab0aa3f, + 0xb97b3b05, 0x464a6bdd, 0x90405500, 0x802f7231, 0xd1e37527, 0x8da7b774, 0x74e487f3, 0xbaaf3620, + 0xa88e5e89, 0x2a30b1c1, 0x51bb2590, 0x09b2b35b, 0xca563580, 0x8c1a4f26, 0x02ec25d8, 0xdaa8093b, + 0x5011ecb6, 0x57d04268, 0x58c44de9, 0x69f506b4, 0x3ac2593f, 0x2d0789d8, 0xee0d0960, 0x91188b21, + 0x3ae84ad2, 0x26fc5350, 0x6dcc9f2e, 0x64e03994, 0xfa2a9c42, 0x6cd497f5, 0xdc0b42f1, 0xf2a307d8, + 0xbd176418, 0x157a2d55, 0x0c75a699, 0x9a3e1cb3, 0x0aed8ffe, 0xbf552551, 0x2a9a9e4a, 0x1947aeb5, + 0xf38b2b48, 0xff80c54a, 0xf75b0e2b, 0xd6536431, 0x0a2906be, 0x1fd393a4, 0xc36a81ab, 0x6e21505b, + 0x0a2a9330, 0xa5bc5ea3, 0x98d31fa3, 0xb20fceca, 0x2e53bf9e, 0xeda98ea7, 0x89047da5, 0xf3dcfa4e, + 0x236bdcce, 0x15303cdc, 0x76d9585b, 0x611791ca, 0xbebec7a6, 0x8c297b05, 0x31ceb8a6, 0x18c4b4d7, + 0x3edd12bd, 0x215d2f3e, 0xae9fa1a4, 0x9893bdff, 0xebc65a76, 0x5e6a5650, 0xadfea2f4, 0xe932145a, + 0xcc116e88, 0x71c7960d, 0x3694f001, 0x6d101578, 0x27972cdb, 0xc911f80a, 0xe4d85ade, 0x09dc34f1, + 0xc66605c1, 0x0da462e2, 0x3b880414, 0x6c4da649, 0x83067241, 0x009c2944, 0x5542068e, 0x4c4fa184, + 0xac169d21, 0xed0cdc13, 0x77151212, 0x5db8d0c1, 0x81cd935a, 0x93a58264, 0xc774cb3c, 0xf440ba14, + 0x8478d4f2, 0x3bba0539, 0xe989459f, 0x36a3af36, 0x0d4a01e2, 0x1faaab24, 0xb1634dfa, 0xf5508e2f, + 0x8e97078c, 0xe686d89a, 0x9d9cd936, 0x4c374ccd, 0x9686fd07, 0x9c16ab66, 0xd6a20454, 0xe5614de1, + 0x35a57662, 0x769f60e0, 0xb9a4407d, 0x01c405e7, 0xdb83ea65, 0x3be19700, 0x3866f88d, 0xed37fbcd, + 0x9c6c81b7, 0x15dca2f2, 0xa0ccf6cf, 0x01562860, 0x98a4d51b, 0xb6959255, 0x108d6933, 0xf0425f4c, + 0xd9cfbed2, 0xfb4b6167, 0x5c02e42b, 0x12a77ead, 0x2887b7a5, 0xbf401ae1, 0xe9e6520e, 0x722dbf39, + 0x2422669e, 0x08580571, 0x07237e00, 0x43918abb, 0xbde553b3, 0xfd08706f, 0x3986274b, 0x62809a59, + 0x7a5cf681, 0xaca5c6a2, 0xa402135d, 0xe04f95b9, 0x64b587d4, 0xcaeda26d, 0xc5cef6ab, 0x92f6b6fa, + 0xc9f58cbd, 0x32264303, 0x79c491ea, 0x11be00dc, 0x467398d2, 0xf7e209c6, 0xe139cadb, 0x48edcefb, + 0x54e33b49, 0xd9f16db9, 0xa6f4e048, 0x6bf5da75, 0x7def8a50, 0x7f397667, 0x376db3c2, 0x4a81ed43, + 0x4ea876b9, 0x4668c77f, 0x603fcc2d, 0xff261f78, 0xc412ec48, 0xcab02c0f, 0xee2428ec, 0x6a1bc932, + 0xb183725d, 0x5187f5ab, 0x63cee902, 0xe6c9c4b4, 0x5be6a9d2, 0x0349f097, 0x55087093, 0xedaf45a6, + 0x42e49695, 0x862da52c, 0xbe3680af, 0xacac5b07, 0x61440d7e, 0xe4c2445b, 0xdc2d69dc, 0xe069752a, + 0xbfaf73e2, 0x4c92c341, 0x58b9f32c, 0x82742a76, 0x7c6c0106, 0x2712e2d7, 0xb25c77b2, 0xc89c6a83, + 0x1a2cb65b, 0xf40b7cdc, 0x32f72f44, 0x9e4a7ae0, 0xd6cc7f1d, 0x878fd935, 0xb920c8d9, 0xf4d15bbd, + 0x0a78884e, 0x6a57dacc, 0x450a16cc, 0xa299f40e, 0x3c795833, 0x745d7fe9, 0x2e4e5e7c, 0xd4ce9c23, + 0x51c239aa, 0x6e56b063, 0xa08360f3, 0xdd14abd7, 0x2e383384, 0xd3bc598b, 0x37579995, 0x1b865765, + 0xb9fe89ac, 0x6b1dda06, 0xa489fe15, 0xa2d82218, 0x4bf2edfa, 0xc55c2fdf, 0x83a383f3, 0x6e40c9a5, + 0x57b3d1bb, 0x05c29077, 0xa159cadd, 0x2d498af7, 0x62eacdbf, 0xcf1336a0, 0x7c4b22d4, 0xcb615213, + 0x08976651, 0xd9a08c2c, 0xa6c6f076, 0xc60ddd30, 0x87321863, 0x9fa1c2c2, 0xe4747007, 0xf547f010, + 0xb364d357, 0x4517f5b9, 0x5f2ebacd, 0x523cffe3, 0x934c7313, 0xbed35ca0, 0x5850184b, 0xc4f3a2e0, + 0x0114cca2, 0xa9112378, 0xb6d296d5, 0xf31653fa, 0xc7fcb9e1, 0xb92318ce, 0x59031d3a, 0xc2a1614b, + 0x1e3d2dfb, 0xdcb86205, 0xba99390f, 0xb45413f3, 0x21f2de84, 0x9f545cf7, 0x543cdbae, 0xbf294a6a, + 0x606e3806, 0xeff6bcce, 0x1969171e, 0x001aefa7, 0x3c0251c3, 0x607488b9, 0x8ad73291, 0x69d9987d, + 0x084b9fe5, 0x028e2412, 0xa53e803b, 0x799223fc, 0x59044081, 0x4aa86ebc, 0xcd4eb302, 0xa24e41f3, + 0xfc736f9d, 0x0a698ae6, 0x3d6199fd, 0x667eb70e, 0xa8fbad18, 0xce5f8091, 0x7c01c581, 0xa4b1442c, + 0x5efa561a, 0x3cf66eb3, 0x6442e27d, 0x4a4bd627, 0xd8ed2666, 0x8b396efe, 0x3398ab1c, 0x5fe3debb, + 0x7d0b4a81, 0xc9c0e88a, 0x2eb100ca, 0xcb18db9a, 0x1f613178, 0x3aad6ae2, 0xa84a8668, 0x76bb557c, + 0xe52f9aca, 0xf5d981c8, 0xef7b300d, 0xddd16cf4, 0x4c6e576d, 0x84017d24, 0xd6382b9e, 0xfae3c0ce, + 0x369080b4, 0x981e05cc, 0x3e4bd1a5, 0xff749d37, 0x3b5faad3, 0xbf08e0fb, 0x43c44c09, 0x5ec1e29a, + 0xafafb6a7, 0x7223a3e6, 0x42a4e155, 0x644c6145, 0x248ead99, 0x4fef3048, 0xa2f2c8ad, 0x9a38e3b1, + 0xd2ebd7d0, 0xc6e47db5, 0x6c79ab75, 0x8ea6c256, 0x9eff45f3, 0x1dd42fc4, 0x99c39cbc, 0xe368a438, + 0xcf6b7015, 0xf4f87708, 0x7e5f31de, 0x732bfcf3, 0xb826b30d, 0x439e972d, 0x461963e0, 0x91540eec, + 0x67b87b2d, 0x08503c69, 0xe33d6921, 0x3e497c25, 0x191f91fa, 0x36bf2ba2, 0x9e6bf1ab, 0x0fcc559e, + 0x145d22c0, 0xbe6d56c8, 0xdcbaefdf, 0xfa32ed95, 0xe2cbd95c, 0x8c781059, 0x5e579383, 0x6cfa8b6e, + 0xbb039494, 0x95401476, 0xe16e7869, 0x4cadc342, 0xaeb80215, 0x0dacd7f5, 0x3fff3174, 0xafcc4173, + 0xfdc69180, 0x50df8764, 0x5b8e3789, 0x1d2abf22, 0xc3ed14eb, 0xb76f3b35, 0x670d3b30, 0x40bbc4e9, + 0xbd270835, 0x9699210d, 0x436423e1, 0xe317ad13, 0x01ae3823, 0x327efa04, 0x6faa70b7, 0x3696bee7, + 0xbf36da59, 0x8fefd665, 0x68fa02e0, 0x556127f0, 0x3d4d782a, 0x27ea7bc3, 0xcaa233f5, 0x0d84e2da, + 0xc88a2616, 0x8d3dfeb0, 0xb2e5c860, 0x5e7f899d, 0x150e7df4, 0x2af7b384, 0x04d1a8b9, 0xfd5b0de9, + 0x5271c2ed, 0xe9a305ce, 0x727e94a0, 0xbcae86f8, 0x0a275b4f, 0xf267b57d, 0x6e09fe16, 0x47cb6a54, + 0x33296dcb, 0xc43684b7, 0x50b4ab80, 0xeea05834, 0x70790dd8, 0xb2fdfbdd, 0xdb942912, 0xb789f17e, + 0xb969cde9, 0xe975c2e3, 0x2e83b1e5, 0xb5aba12c, 0x2a3bd318, 0x839ed05c, 0x781d55b2, 0x53e9b5a6, + 0x4894a348, 0x05dae1a1, 0xaaa532d9, 0x5cb982e3, 0x62600d62, 0x5ef6ccd0, 0x133b36f3, 0x820e8ca1, + 0xc3244d5b, 0x83971e16, 0x8cb94c9d, 0x7edd736b, 0x719b8d9b, 0x39a854e8, 0x2d3c2cae, 0x0d46514c, + 0x92a94d5b, 0xada2cbf5, 0x4d1788e0, 0x98ca865a, 0x6bbe8d0e, 0xc54072ae, 0x7c1de262, 0x0c95d805, + 0x7448f07a, 0xb9113e92, 0x721f7f1e, 0xfd22a55f, 0x94805e1c, 0x00d82fca, 0x4748d37d, 0xf2b783c0, + 0x76636212, 0xd883c404, 0x33361f83, 0x138ccb10, 0xf1d7d9a4, 0x05ff408f, 0xeca5aefd, 0x5bce40ca, + 0xb7348792, 0x2d1321a4, 0x274bfcd8, 0x5c3a7795, 0x0c637b07, 0xe79ff39b, 0x08d67b0a, 0x51ffb137, + 0xd8dcaa49, 0x65b1c8ed, 0xeaeb2511, 0x3ffe9f3f, 0xcaea75cd, 0x7fcd2e77, 0x57f3a343, 0xa608ac40, + 0x2aaed9be, 0x6192c63e, 0x347f86fa, 0x994419c2, 0x22d05697, 0xdce89d62, 0x1e243566, 0xd9000519, + 0xb49e55fe, 0x075b3828, 0x3bf562fa, 0x0e8313a7, 0x0daa566a, 0xfd15816d, 0x1c0d67b2, 0xffca509a, + 0xf4712de0, 0xfd19c905, 0xbeb89aaf, 0x33f1c167, 0x67ca8647, 0xc2871166, 0x1f3ae129, 0x1b3005a2, + 0x64abf807, 0x4118a188, 0xc58813d4, 0x0d4d1fca, 0x395d953e, 0xdf326a17, 0x435c85a7, 0x4b583da6, + 0x5dd05fc2, 0x81426843, 0xe3bb9fac, 0x942fd632, 0x4ed58a1d, 0xa0730fa2, 0x12234076, 0x480ff335, + 0x41dc2036, 0xfff5f79d, 0xebf2b048, 0x031fb505, 0x20bd2616, 0xbb528902, 0xfaa13080, 0x1a76c5f7, + 0xfe367aca, 0xdebe6b9b, 0x083bbce3, 0xdb9c2da8, 0xd7cae1fc, 0xdf15c4b1, 0x66e3367b, 0xe88b0f3e, + 0xbe3cfc57, 0x52bb31fd, 0x6356fcb4, 0xb8ea7581, 0x353f016c, 0xac1a4ece, 0xf2ea41d8, 0xa1c05a3d, + 0x5e4139cd, 0x6e406377, 0xa2415366, 0x75e4bbb8, 0x8cb6de06, 0xa9ca79a4, 0xbe5ff037, 0xb9898b25, + 0x51ae2c2b, 0xcaf7d77b, 0xe23536de, 0x49262d35, 0x841a0d89, 0x9c41d391, 0xcf1c7a6b, 0x0c577f7a, + 0x16c91aa2, 0x5933f800, 0x787b4d5c, 0x10f58893, 0x301c7867, 0x57e77644, 0xbb7bf2b4, 0xea14775f, + 0x44d037b2, 0x8315308c, 0x3d0286d7, 0x46151c5c, 0xcb4b776c, 0x6c08143a, 0xd1384b55, 0x15c3336c, + 0xcafab560, 0x999166c2, 0x2b77b50a, 0x285d96a1, 0x34f4ab5f, 0xb91494a0, 0x68b5c9b3, 0x040402cb, + 0x421691ae, 0xdc2f4726, 0xa4004574, 0x2b4ce519, 0xea3a726c, 0xe8eebf14, 0x911d0f02, 0x85c79e29, + 0xbd4abb39, 0x73433b0a, 0x7f98d297, 0xad1bf8f7, 0xa7061e53, 0x769063b7, 0xfe300057, 0x6bfa701b, + 0x8ed0ad57, 0x9c2f9fce, 0x208ba8dd, 0x741df74f, 0x9c6efdcb, 0x9587bc42, 0xdd802ea4, 0xc469063a, + 0x0a149b34, 0x0bc81712, 0xe74a4624, 0x34f63a10, 0xe82cf069, 0xdeed8074, 0x770a6d8e, 0xc52ab9bb, + 0x52da9ccd, 0x24218eb8, 0xfc4edd9a, 0x138e760a, 0x4768b36c, 0xda587ee5, 0x010c454c, 0xe2ff7819, + 0xc1bd0e5c, 0x67a7b6da, 0xd16a8245, 0x74c8329e, 0xec717131, 0x64d162d7, 0x79a72dcb, 0x331d0b3e, + 0xec8d4068, 0xdd0da7f6, 0xc863a225, 0xba5d0894, 0xc0061d61, 0x8ba44940, 0x289689d5, 0xbb641f46, + 0x613368b7, 0x3795e15b, 0x85ee4e2a, 0xebb69884, 0x7d0f1c2b, 0x9e2bf62a, 0xbe126167, 0xd3c03618, + 0x799cf8fa, 0xe4d88c7e, 0x25ef8c41, 0x1b3c62e0, 0xfcc6e9e5, 0x8aefc8ea, 0xf6723bcf, 0x3af13d28, + 0x6ebe3cbd, 0x419d1a50, 0xd7271c54, 0x3cd984b6, 0x4a08947a, 0x3a688fcc, 0xd33b9365, 0x8f9139dc, + 0x19c44ed6, 0xec4a30e8, 0x659fea47, 0x85deac17, 0x5dcae26d, 0x9b2a58f8, 0x254beb65, 0x2bd5be5b, + 0xb447a91c, 0xafd5a246, 0xcd954dd4, 0xf5d4edce, 0x218a2385, 0x2a32187c, 0x7cf1118c, 0x8858a3fa, + 0xf5264451, 0x586afd37, 0x3d799f8d, 0x92cb2d09, 0x4b9a1310, 0x42e5adee, 0xb9ffcb3b, 0xad279096, + 0xa6e3e67d, 0x49da0103, 0x6d4f2f5a, 0xa71ef941, 0x9c39a866, 0xe4e20ed5, 0xe5e81b46, 0x6a6ba828, + 0x5a0c9d09, 0xdc077770, 0x956bbcc3, 0x0a1d6592, 0x478bf7db, 0x6b3e87f4, 0xd21a03a7, 0xbfd4110c, + 0xbba6142c, 0xc5c146f5, 0xff925ef1, 0x5281ed58, 0xef98981f, 0xa228552b, 0x483c57d5, 0xe1a2b2c3, + 0x45b93f6d, 0x3616c90d, 0xee385d94, 0x4326fdbf, 0x87afab38, 0xd85fbd00, 0x422274b1, 0x1de7ed34, + 0x8c379f3d, 0xd18bfcbd, 0x24e9fc35, 0x414e6f62, 0x48b39e20, 0x1c52598d, 0x2c49f3b9, 0xabd804d1, + 0x5846af7d, 0xc956878a, 0x59566269, 0x92542116, 0x10aac9dc, 0x29665a7d, 0x29e082a7, 0xcb4c98b5, + 0x46b18b96, 0x27782ef5, 0xd632bb68, 0x311aa669, 0xe24eeab8, 0x146bc028, 0xfbd3f537, 0xb4aefd9d, + 0x9fcecce8, 0x54178dcc, 0x3589ba00, 0x2f4e917b, 0xd14bb7f2, 0xc074b09f, 0x4f00c456, 0x2bbeba0d, + 0xb026f79c, 0x75718aad, 0xba79d6f0, 0x98a670e9, 0x883f1b06, 0xe64439d3, 0xf22aecaf, 0xee54b69c, + 0x3c1a8375, 0x66050ffe, 0x8fd9d00d, 0x05f24f7f, 0xe4e0a941, 0x63e6dc5e, 0xc0bd4521, 0x0a200246, + 0xdb635430, 0x73fc0570, 0xe426fe73, 0x86993569, 0xd90ac57e, 0xbf20bd8d, 0xf09fbd46, 0xa6dc8132, + 0xfbab0917, 0x80121cab, 0x57c90c46, 0xf23901db, 0x47b494a0, 0x4713c124, 0xdca9c1ed, 0x71a87a3b, + 0xc2b372b9, 0xa77036c6, 0xe79a6417, 0xfa5d09fb, 0x9385d1d6, 0x146b34c9, 0x923b3786, 0x68601143, + 0xd6a11ef4, 0xe2192673, 0x6750376f, 0x1b1fe381, 0xf82fc536, 0x2baa65a3, 0xc62dfd8c, 0x7005d5e1, + 0x9e38b7d8, 0xd5742efe, 0x9fd89a56, 0x69d62d5f, 0xe85ba7c0, 0x47626390, 0x1f124af4, 0xc1d85a05, + 0xff39cc0e, 0x9a20a7ce, 0x86e9b70e, 0xc9556117, 0xdc3d578c, 0x0952c345, 0xe5d08317, 0x4ab9f852, + 0x4f372532, 0xbffc5897, 0xc7717ab1, 0x6af0fe65, 0x29d821cc, 0x42ab7f87, 0x60c8cd9a, 0x269f4aea, + 0xceef0465, 0xa0b13fa6, 0xd0ed72b5, 0x27571065, 0xdc988419, 0x877462ba, 0xeef0371f, 0xdbab5e45, + 0x1fc27350, 0xe4d5b7be, 0x8a934e32, 0x3fe58833, 0x4f9faabc, 0xba57e0ab, 0x5f120bc1, 0x8e42b34d, + 0xdae0a31b, 0x4ee6a8ec, 0x9d18a918, 0x4cf80c78, 0x14695b87, 0x19062f2d, 0x278a4e0b, 0x1b72a947, + 0x3139f5ec, 0x4ecb9adb, 0x63e0bfc8, 0x00a2255c, 0x188c98f5, 0x46b54c67, 0x0d747c82, 0xaa99232d, + 0x4a640aef, 0xdf7e1fd5, 0xa5dc965f, 0x599c75e1, 0xd01792a5, 0x602bbf90, 0x4b2c03d0, 0x708ecbea, + 0x6e83ae67, 0x98f9535c, 0x46eceecf, 0x85fbd54e, 0x2862ad60, 0x98b282df, 0x58879f95, 0x183469d4, + 0x76039fa3, 0x7fbf9bbc, 0x67843628, 0xf6b02741, 0x9b98300a, 0x89c42a7e, 0x9730b604, 0xcf2313d2, + 0x5fc79b03, 0x590decd2, 0xf83f900f, 0xb91bfa9d, 0x354b05ae, 0x81579435, 0x0d57720b, 0xad1a6ae4, + 0x13a5040a, 0x9d60a03b, 0x543d8a88, 0xe2b9d5f6, 0x121b9e58, 0x900c9de8, 0x04f4ed27, 0xc4bebd37, + 0x6109ee4f, 0xae7555c0, 0x94a0f872, 0x1234b7d9, 0x1b437c7d, 0x6791ccd1, 0x33d6caa4, 0x62084ad6, + 0x91f5c4ef, 0xd3509a39, 0xaaddf815, 0x9699ff42, 0xd85d74fd, 0xe25cbe7b, 0xdc4fc729, 0xc0e3174a, + 0x718844cf, 0xbd4a036c, 0x72ad1969, 0x13cb6271, 0xbd857956, 0xd667c774, 0x7346a76e, 0x0a473c22, + 0xd2f79482, 0x686ed365, 0xa1a13ca9, 0x94a0d00f, 0x687713a8, 0x1501c655, 0xd85abad6, 0x73821d07, + 0xad1cfa0a, 0x501f73b9, 0x5135fa03, 0x02fb007a, 0xf15aab46, 0x6262a477, 0xe89c3476, 0x478851e7, + 0x293c83d6, 0xc275c319, 0x63d7df09, 0x2d19be0a, 0xd54b7920, 0xbe01fcee, 0xccef3478, 0xe5f95f30, + 0x478cdd14, 0x9ba714d3, 0x83bb1e37, 0x00916e2c, 0xcf360959, 0xcf7e1247, 0xcaf99f40, 0x8cc7eacf, + 0xd9c269e0, 0x690865fd, 0x83a96157, 0x9635c995, 0x2fa46af1, 0xc05f9788, 0x0b95e1a4, 0x88f44afe, + 0x9911b0f4, 0x4eecfe18, 0x7b6ebfba, 0x8268948a, 0xe80203a4, 0xb158ba53, 0x13a9650f, 0x22fee9b9, + 0xc78855a9, 0xe06977e5, 0x496ad944, 0xfffe1873, 0x998c2966, 0xd6bafe6e, 0x0cc22bf2, 0x291cd128, + 0xbb2ad915, 0x2b9a9cea, 0x5276b703, 0x00db44c1, 0x14a0bcda, 0xf945aeb5, 0x257b5714, 0x7783ee62, + 0xfa8935e8, 0x613aeb23, 0xb8372918, 0x1a4fa2ec, 0xc55f4e2c, 0x835ba6cc, 0x075fc05d, 0x16e247ee, + 0xbd0e9e09, 0x2dc69029, 0xb72ce2a9, 0xf185bc77, 0xe2daa68c, 0x84fdbe5c, 0x0f7e4785, 0x3513152f, + 0xdfb6d5b7, 0x59ff348f, 0x425a87c4, 0x1bfd6827, 0x0143851e, 0x4aa51b91, 0x99b43aa0, 0x8edd271a, + 0x650bf3af, 0x72b3ee3c, 0x8dcaa210, 0x50e2a0ec, 0x9b4a230a, 0x1d945fd9, 0x2f1d1460, 0xd6581bf0, + 0x300a7505, 0x756a02e9, 0xfd69ef91, 0xe534fac7, 0x270c4dd6, 0x0da3dfb3, 0x076819bf, 0x53657122, + 0xef9db3a6, 0x11868a9b, 0x5756b287, 0x3d05ad2f, 0x6c340b2e, 0xd2b56375, 0x811929d1, 0x4ae7906c, + 0xeafe6a72, 0x1150fa53, 0x6cdeede0, 0x4d71c129, 0x465c0cb1, 0x12816534, 0x8cfcce40, 0xe0e89c83, + 0x2752cf9f, 0x78d86314, 0x3d940ddc, 0x704ad2bd, 0xf6cadc28, 0xa1ba86e5, 0xbf5d15e2, 0x1389d3ae, + 0x23d1bb62, 0x74730dbe, 0xbfd70005, 0xb4813cd3, 0xb1565dd6, 0x4a4ba56a, 0xf464cbd8, 0xef277382, + 0xe760d828, 0x9c732cf6, 0xda59caf7, 0xb2e30631, 0xf365fcba, 0x83cd07e0, 0xc6ec594e, 0x3cd7a9fb, + 0x3a2bd69a, 0x7e1994da, 0xa16c7d35, 0x4adaf109, 0x57646d25, 0x5be1b42f, 0x2fcb52d1, 0xae6b61b4, + 0x78eeb85a, 0x04a73c65, 0x10b7df23, 0x46c7e089, 0x54c0fef2, 0xcaa0ade1, 0xec50f05c, 0xa3dba6de, + 0x4bc704d1, 0x30c430e6, 0x09275750, 0x57784f5c, 0xbceb1457, 0xa3eb0998, 0xce326bc8, 0x41dd936c, + 0x02162dd2, 0xea787742, 0xac3edc53, 0x2eefb930, 0x7c31188d, 0x3fdce68c, 0x4d24fae3, 0xff8fbe96, + 0x61defc03, 0xdb41ec5e, 0x6fa3e4cb, 0x43dbe580, 0x77ef1978, 0x9907dd2d, 0x83845469, 0x31b1473b, + 0x33ecbcb6, 0x5ea77446, 0xf5305be2, 0x9782879d, 0xfeb423c0, 0x92b3e50f, 0xc209e872, 0x8d353d3e, + 0xff0114ae, 0x4d1df632, 0xa3372ed9, 0xb4ebd3f5, 0x0836ec05, 0x9dde6888, 0xaa9f1d03, 0x4015af30, + 0x2d4cc90a, 0x6b41c4a4, 0x0152a9c4, 0x6f22c8d7, 0x58124276, 0xc9979858, 0x01cb54e0, 0xbcc62064, + 0x417893d4, 0x1dc67352, 0x0883757a, 0x9f998e3f, 0x0c3f589a, 0xe7305b68, 0x1751d6f8, 0x0f0fd6a0, + 0xdd6ed2a8, 0x083482af, 0x68e24e54, 0x4d47d5cf, 0xa5a512e5, 0xdaf8f880, 0x4511a5fe, 0x4d1fa7cd, + 0x9116f174, 0x9d0e1cae, 0xdcb26127, 0x2ed8faf6, 0x00c15382, 0x22e1d49b, 0xe1021b47, 0x4f4fd54a, + 0xe20703b5, 0x6e3f1b12, 0x56602a68, 0xd7941dcd, 0xf48b6ab0, 0x3e475b60, 0xd96e6daa, 0x901fbd32, + 0xdecbf237, 0xdade43b5, 0x150cb03a, 0x94e2c28f, 0x8d789110, 0x98f30969, 0x1a5b5505, 0xcdad3378, + 0x621595eb, 0x0b63db00, 0x94bfe310, 0xf52eaa5d, 0xef58f566, 0x962c755d, 0x76475323, 0x4e0b380b, + 0x4e96aab3, 0xa86f4a89, 0xb492ca00, 0x52a1f837, 0x399a9871, 0x28740568, 0x6ddcca03, 0xbf9488f4, + 0x799b2a12, 0x9e37e99d, 0x6091beb7, 0x65a4be04, 0x55dcbbab, 0x1ace2616, 0x87e971a0, 0xf4cb2933, + 0x28e21b37, 0x1adf0d9b, 0xa47d54a6, 0x7f58b71e, 0x77e0a424, 0x08f1ae38, 0x9253ad7f, 0x7b660fcb, + 0xb4aaf21d, 0xeb952ef7, 0x6ba78101, 0x225a8f62, 0x6e2a1143, 0xe68945e8, 0x9a63dd84, 0x89f3c910, + 0x589520ce, 0x5616677f, 0xd78f39df, 0x0d0f659f, 0xd3cc78c7, 0xa1885685, 0xa9a76ec0, 0x525407e1, + 0xd9cccbfa, 0x8b13dfa9, 0xf7f8471a, 0x2586eef0, 0xf448e546, 0x6acaa303, 0x4d5965eb, 0xac79be8f, + 0x26255a46, 0x045154b2, 0xe74bbd29, 0x1a3c4ae7, 0xee5e1d3c, 0x3916373e, 0x5254dccd, 0x43021459, + 0xd94a9627, 0xebbeb8f0, 0x0eb3cea7, 0xcc8ba866, 0x6114a9a4, 0xb0c96fba, 0x052b4a42, 0xbc230b2e, + 0xa226d25c, 0x00398cb3, 0xadb5a2ef, 0x7986514a, 0x4c6e52c4, 0x73bb6c5c, 0x724c7fc7, 0xf98d2b5c, + 0xca925e5d, 0xb6a4bce5, 0xda5e3e1b, 0xa087ec6c, 0x1b79df72, 0x8f8b4ed4, 0x688cbba9, 0xb894cd73, + 0xe6fbd3a4, 0x5fd3dffc, 0x2e50a81b, 0x4cabc5eb, 0x9ba61761, 0x0b5cb7e0, 0x2facfb8c, 0x46ce9cc0, + 0xd9e9bac2, 0x0b637c4e, 0x7563287e, 0xcfb1fe19, 0x28a6a506, 0x904a899d, 0x8e3e1543, 0xd04e5f5c, + 0xcb6ac832, 0x6b3ca9c6, 0xacd178bb, 0xee35283b, 0xa3c3153d, 0xf4fb4bff, 0x9d9b65f9, 0xee57e101, + 0xb5cc12dd, 0x10103e0d, 0xfe83a50f, 0x9733a746, 0x27cb4778, 0xfab5afc6, 0x6c173e1a, 0x627c2b1a, + 0xec770ec7, 0x4f364cda, 0xcd0811c2, 0x472f5081, 0xea06049d, 0x537fa455, 0xa8416d65, 0x9e99319f, + 0xb2f93d7b, 0x730626bd, 0xde9cc0e9, 0x1c90809f, 0x22e4aebe, 0x546eefb5, 0x37a792e0, 0xbfd05303, + 0x934ee622, 0x4f5fdd9a, 0x27a85ec4, 0xc071aa69, 0x5ead75a3, 0xa711b45a, 0x0711ca88, 0xbc7100df, + 0x09adb3d1, 0x70eb0619, 0x40caf5d5, 0xb7abe200, 0x4e2ec5eb, 0xb903a992, 0x6578a36a, 0xf4ca67c4, + 0xb0cae954, 0x524059bd, 0x0e427436, 0x19e3223d, 0x2c0b995c, 0x9344eb73, 0xa94ffd9c, 0xc631e371, + 0x7ade6d1d, 0x23d5e838, 0xc9ec2cdc, 0xc62d4703, 0x693ed1c3, 0x081c6cec, 0x6ff55717, 0x17a64659, + 0x9cdd9027, 0x2ed14aa9, 0xfb08251d, 0x76a01cfe, 0xb434d331, 0x19c6396c, 0xdaa13326, 0x71f04ac4, + 0x94436e17, 0x45326d22, 0x4a58f8e4, 0xb3f98f58, 0xc506dfe3, 0x305c0d85, 0x7db51855, 0x1c837eda, + 0x8958d7f3, 0xb46f8266, 0xf9b21cf2, 0x64aaf0ab, 0xd526c2c3, 0x6809668a, 0xa2c6927b, 0x02e0d519, + 0x50f5f06f, 0x03da69e2, 0xa2ca9a3b, 0x83e1cce9, 0xbf9ca4f3, 0x300d7535, 0x73e48cf3, 0x1af29991, + 0x19a716df, 0x32f40bac, 0xf04d65dc, 0xb4e4f4fc, 0x22e2f331, 0x47a773a5, 0x02f6dfdd, 0xada631ce, + 0x5afa50ca, 0xd45fa69f, 0x2e8caa70, 0x284efc4f, 0x956a5db8, 0xfc54b16b, 0xccf255a7, 0x250deb56, + 0xa12b2e07, 0xf6d79243, 0x4da7b56f, 0xff99abd6, 0xeb61c54b, 0x9d914b68, 0xc2730c35, 0x503fe8db, + 0xd2041798, 0x16eece3f, 0xdcf78117, 0x8653c1b0, 0x7b044f3e, 0x0b0d8c32, 0xd2805d18, 0xfc5fdc6e, + 0xc7bf0fce, 0xc0748b7a, 0xf2645a65, 0xb2f85c5c, 0x50b9b520, 0xdb19ad9c, 0x601f1621, 0x943934e9, + 0xe635d767, 0x46d535f3, 0x660c87fc, 0xfda80226, 0x545252bc, 0x8a91decd, 0x9cf1b613, 0x8f888a66, + 0x146ed832, 0x23c7ee98, 0xe64d74d7, 0x01223e78, 0xdc808cc1, 0x25620a37, 0x090da4ec, 0xc60e8aac, + 0xbb4b8941, 0xca729148, 0xc0afee37, 0xc6f7389e, 0xf75f3cf7, 0xce7b67e4, 0xc13c5f3a, 0x330fd448, + 0xa8127907, 0xcec18e0b, 0x7d528441, 0xfb0934c4, 0xf4db81ee, 0x24d8470d, 0xc498078b, 0x0aefa480, + 0x7d3e37fc, 0x524624e4, 0x1dd45be2, 0xecb3be85, 0xef5604d5, 0xb80f916b, 0x8001b198, 0x1c19faa3, + 0x8fff1dbd, 0x8cead8ed, 0xa46561d3, 0x491e1130, 0xcd36cc89, 0x83818d62, 0x34e21606, 0x33a9d5d5, + 0x56f96abf, 0x7729ed55, 0xa3355d1d, 0x1163ce25, 0x863032de, 0x393e3c1e, 0x4bf853f8, 0x9e7328e3, + 0xea1b96fe, 0xc0333fb5, 0x7f609a15, 0x7a9d09d9, 0x80e2f537, 0xf6892316, 0x6ddbe95c, 0x2658ffd6, + 0x0bcc0ff8, 0xbd7d1e4d, 0x7f6b5fdc, 0x3d8b00da, 0xb219d6df, 0x60da5664, 0x358ebc93, 0x7602a7c2, + 0xdd6d944d, 0x30a8fd20, 0x451eaa03, 0x52320eb7, 0xb272824a, 0xbc317f0b, 0xdcc17b69, 0x36e7d639, + 0x288f09b7, 0x560786a1, 0x78ca9f7f, 0xcb0bd673, 0xe37d8849, 0x7ba5a5cf, 0x762c5487, 0x4e836437, + 0x69f94c37, 0x14f47cbc, 0x33de1125, 0x8f58d6f1, 0x31ae68a0, 0x723404fe, 0x298b372f, 0x6a4b4f3f, + 0xfb2b2766, 0x901f7a4e, 0x0e1310c6, 0xa26daa30, 0xf5b2f54a, 0x37c9f77a, 0x4e4303c9, 0xcbb16d98, + 0x5ae1bf2f, 0xad691a61, 0x0747b83d, 0x321730b8, 0xa1edbac8, 0x93d9cd88, 0x8a177973, 0x57a1b9df, + 0x09a63202, 0x0da9ae8b, 0x602131d3, 0x898a486d, 0xe25a6109, 0x96a3a23a, 0xb6e869b0, 0x6dee06be, + 0x66adfedf, 0x3a609573, 0x2fa28a34, 0xd42f1f15, 0xdbe121a9, 0xb924ad45, 0x85b6cf96, 0x2ace64f6, + 0xbda91815, 0xa7fc06ca, 0x35defcd1, 0xccf5c29c, 0x25db282f, 0xf1db3ce9, 0x5954e34e, 0x8be95fa3, + 0x1a134f45, 0xdc338373, 0x78fffac8, 0x6b3ff35d, 0x84d01300, 0x301544d6, 0x873e5831, 0x077f546b, + 0xe22f6748, 0x0cecd533, 0x5ea7e021, 0xa87f8b66, 0xfcdec6e5, 0xaa783ef0, 0x408ab27f, 0xb12571ff, + 0x299deecd, 0xdc396d33, 0x8ae4fb8b, 0x60cdc0e8, 0xbed56d5f, 0x24081241, 0x91f26dfb, 0xeb0f4224, + 0x9f24a59e, 0x45821054, 0x4ad61817, 0xa1a7f59f, 0x769c0625, 0x3a177d92, 0x35fbf7cc, 0x7cf67429, + 0xdd4b7739, 0x202d4ca6, 0x84795712, 0x156c3eb4, 0x1c3ff579, 0xf1d09725, 0xe39157cf, 0x0d1a359d, + 0x20ac790d, 0xfc28875f, 0x4acd6e2a, 0x7c021535, 0x3fc8b198, 0xecf6a023, 0x06a642a6, 0x8a7988b8, + 0xc14c3d3a, 0x6ed37b63, 0x7c7b12e2, 0xb2fa29de, 0xd6533973, 0xfa399126, 0xb648a467, 0x9748ec18, + 0x9de28596, 0x29ea7167, 0xc4108f7f, 0xd5a1d85f, 0x0b7b8d6b, 0x2a217e26, 0xe290a5fe, 0xff490833, + 0xe773e732, 0xedbda442, 0xf884db1f, 0x1f57c68e, 0x4195af11, 0x5c9b4e4d, 0xa5313503, 0x9c041c24, + 0x3667ef64, 0x44323154, 0x243355eb, 0xdad1a2ed, 0x491e0480, 0x82a657b8, 0xa7fb6308, 0x3b4effd7, + 0xea42b39d, 0x70f1e692, 0x1565b161, 0xfa46c228, 0x9d03f504, 0x0550c1a6, 0xa09435a8, 0xbdb5b2ae, + 0xc7c02600, 0x956db728, 0xf5fb3808, 0x040cc0a7, 0x3e02505a, 0xa4d0a811, 0xa644c783, 0x237dcc36, + 0x746abefc, 0x8b0773af, 0xe84a9ae8, 0x3cd6e362, 0xbde8cbe5, 0x36691358, 0x4b293d9a, 0xdf41d6e9, + 0xee00cf32, 0xb63bbaab, 0xb1b51c61, 0x3b134bc0, 0xbc7c4615, 0xeda579e6, 0x7b940580, 0x21017d9a, + 0xaacad790, 0x5d604f50, 0xec16667d, 0xfc93537c, 0xd2c1c02a, 0xa54b2215, 0xb7d6ac89, 0x3cb07ee5, + 0x385e56c5, 0x479f7381, 0xcaf15202, 0x2a090df5, 0x0e791efd, 0x6527358e, 0xfb16e86a, 0xe80c984f, + 0xdfe125f3, 0xcb4d3828, 0x9166d920, 0x79cfacd6, 0xb5f98bb3, 0xbfb1b78f, 0xdf879765, 0x67cd18c4, + 0x95a78bb1, 0x20c502cf, 0xd77f5501, 0x18771cbd, 0x543cb787, 0x608edcd8, 0xc50936d7, 0x485168ae, + 0xbbcc0700, 0x83cbc2a5, 0xc0b3cbb3, 0xa165d1fb, 0x3bcdd2eb, 0x489e6f93, 0x8d62b6a4, 0x088cfeab, + 0x75d1dded, 0x049b3c73, 0x40cef574, 0x4e536a96, 0xa676125f, 0x294c3bdb, 0x43e1df7b, 0x892eacbd, + 0xc63255e6, 0xabe2143f, 0x8d0582bf, 0x018c88be, 0xe320d627, 0x1735d08e, 0x1bdab303, 0xcd4c6867, + 0x2fc03741, 0x3a9bcc13, 0x52581a43, 0xce8cadfb, 0x1eb67d8c, 0x84c4ad30, 0x88109639, 0x8d3c6b5e, + 0x71e23652, 0x38939fcf, 0xe5945ed8, 0x9d920424, 0x7d70737e, 0xddc9ce95, 0x2cd1e6a1, 0xdcc683de, + 0x2ac3b78b, 0x17de52c4, 0xc0e31650, 0x23947483, 0x834869ee, 0x45ed317b, 0x62f960e3, 0x6f2fe6c3, + 0xaed56f1d, 0xd06c42c9, 0x4421c65d, 0xe8e81137, 0x72dbfa0e, 0xefca7576, 0xce5244d2, 0x79e6981c, + 0xf14b4bf5, 0x6cef9f22, 0x966c1777, 0x63bfa884, 0xb2bda8cd, 0x2277a8d2, 0x95b9227a, 0xc8674154, + 0x2228ab4c, 0x604fb082, 0x15aa219f, 0x14a1f3e0, 0x01f324b8, 0x07e4be9d, 0xe0244f9c, 0x654d1869, + 0xb51dd677, 0xb033542b, 0xb3248661, 0xd89ae55e, 0xd8c5060a, 0x446bec66, 0xdd12ad94, 0x855b38c1, + 0x5dd997c9, 0xfa40141d, 0x1720df79, 0x74542b1b, 0x7bdb564a, 0x58108c83, 0x56816513, 0x8b9d0457, + 0x18d153ba, 0xdaf1e801, 0x14749bef, 0xf09ee33f, 0x9dc02036, 0x5d99d843, 0xe15f9178, 0x5724e9ca, + 0x7fd7b1d0, 0x213755ea, 0x3e557215, 0x03cd1fd5, 0x14cb4866, 0x74ddbf7a, 0x985983fd, 0xf6d955f4, + 0xd5b89428, 0xf0edbec5, 0x32129b04, 0xed17f7dc, 0x3b5f257f, 0xbb321237, 0x3ac38683, 0x0601d14b, + 0x2470fc4e, 0xdad3dd1b, 0x5062023f, 0x5e6b1e7e, 0xc7d9115d, 0xe2b731a1, 0x8114316c, 0x80ad2f70, + 0x451edcd2, 0xd0f1308d, 0x1831ebf1, 0xe648d637, 0x98b8c250, 0x638979c5, 0x7d83e414, 0xf003f327, + 0x9af66511, 0x4c32719e, 0xa9e9fd3d, 0x9ff3e985, 0xa78fd6a9, 0xbb54205e, 0x4b8d4d04, 0x0b27d36e, + 0x9773272f, 0xab2748b7, 0x482d9bcf, 0xe2cd1c64, 0xfcf11654, 0xe83281fb, 0xd23932d4, 0x074373b0, + 0x01e92e1f, 0xa90e2ab3, 0x7c9169d6, 0xfccb604e, 0x4f0a2e78, 0x1d77c21b, 0xb2d06531, 0x005ce63e, + 0x83a72a30, 0x03ade9dd, 0x0090c7e7, 0xfd6f5c48, 0x36485a8b, 0xb1043c96, 0x459d5c1d, 0x318bc4c5, + 0x856457a4, 0x0d704901, 0x6b8e5809, 0x526aff00, 0xffb2b81b, 0x25ea93bd, 0xdf42a687, 0x98ccb3b2, + 0x8f5f7c00, 0x2403ad97, 0xa29a1258, 0xd411ebd9, 0x69c003db, 0x6d33f26e, 0xd99fa911, 0xa84b0ee0, + 0x2b6f0f0e, 0x7708ab01, 0x495b7de4, 0x4b94f12c, 0xfa5d5cf3, 0x04533ac2, 0x394c6a67, 0x8eabac92, + 0x7686c0fa, 0xe7d35ecf, 0x0592d64b, 0x35941f11, 0x3121a7b9, 0x102b0856, 0x217e7cf9, 0x5a430af2, + 0xe029d4cb, 0x2396b361, 0x54f2b5e0, 0xcbf22750, 0x6ccec485, 0x0dbab75d, 0x48f6dcfd, 0x8e1da0fa, + 0xafd9628d, 0xbbc289b0, 0x0374fc24, 0x53014035, 0x8291e291, 0x6bd9af9b, 0x178b63c3, 0x767c70e9, + 0xc1ce36fe, 0xb454f5f9, 0xb721661d, 0x922e1195, 0x5270d4b6, 0x63ba9354, 0x8c6037a2, 0x2f6fbd21, + 0x9d391a40, 0xfc7d8994, 0xd18eb771, 0xb49c8cf9, 0xd26b2289, 0x3759cfd8, 0x64dd64cc, 0x678229ee, + 0x9bff2b8b, 0xc4a08cb1, 0x4e103026, 0x6051e782, 0xfb78ef46, 0x4fdf1bc8, 0x724c9eb2, 0x2bb72ab2, + 0x6522fe6a, 0xa6b89644, 0x4f254bbd, 0xd9c6b7a6, 0xed35aa5b, 0x5f3907a4, 0x848171fa, 0x0cc4f776, + 0xdf0f22db, 0xc9a9e787, 0x334e7641, 0xe9053efb, 0xfd81afec, 0x4db9ff7b, 0xf55832b8, 0xffdf8684, + 0x6c781140, 0x0b16d754, 0x885b1bb8, 0xdf6ba865, 0x712b3163, 0x090d30fe, 0xe5a3bec1, 0x12266994, + 0x17341d45, 0xd7774715, 0x9138888a, 0x477907a6, 0xb60007a7, 0xde660597, 0xa1291eaf, 0x4d200cb2, + 0x0bed0d63, 0x05900243, 0x32dd3b96, 0xa2a7cd20, 0xb80c4fa8, 0x74c6968a, 0x10d22311, 0x26096934, + 0x1b9ada50, 0xe663be21, 0xb5fa8367, 0xc717138f, 0xf10305b8, 0xda9a8cbb, 0x2544b2d3, 0x38bfbe57, + 0xae9e94aa, 0x493d0f24, 0xec7af761, 0xfd6d5a00, 0x03781666, 0x1acb1e67, 0x9cce68e9, 0x60f04ea1, + 0x2960291e, 0x7bd62dbb, 0x64fe8c6d, 0xb259ce53, 0x12e370c4, 0x4c5c576e, 0x183ecef4, 0x510bf02e, + 0xd73cdce9, 0xefcc05c5, 0xf55d47a3, 0xfcd6e4ac, 0x00d97b7b, 0x8e7acc73, 0x51762fc7, 0x4ef369a6, + 0x4df394d1, 0xa247307a, 0xaaa0400e, 0x80dc86af, 0x10b9d4f4, 0xde8e25ed, 0xbada7496, 0x42947932, + 0x26e1b71d, 0x7925be2f, 0x203e8710, 0x48f52d97, 0x58f4675d, 0x9fcc6179, 0xf72af0d3, 0x6145ba48, + 0xc133f37e, 0x96f8e922, 0xcf9a4e53, 0xf109c102, 0x910bb600, 0x17f0f283, 0xfa888505, 0x7429c876, + 0x85d34c88, 0x0da8c0b6, 0x7c467561, 0x9114cf29, 0x748f031a, 0x2c54b185, 0x13ae82d9, 0xdf0dfb23, + 0xbe9d73c0, 0xe47652da, 0x9cd356ca, 0x4cc8bf92, 0xea58e9f2, 0xc1f1f42d, 0xff6d04aa, 0xa934bb9e, + 0x90589c47, 0xc8f0210a, 0x890c240d, 0xa0749956, 0xe2c13e19, 0x7c61f6e2, 0xcc86d5d6, 0xd51a9f93, + 0x8e67566c, 0x5717a95f, 0xd739f6ef, 0x5f185d3e, 0x64c8b0bb, 0x749f1f37, 0xcfff1b73, 0x945ef90b, + 0x5dcf7b56, 0x4b4ba4ed, 0x7c0ca154, 0xc731a0cd, 0x7a34e33f, 0x5f925b76, 0x5eca90f2, 0x1da1b162, + 0xdee9368c, 0x3e9141f2, 0x6ff2e516, 0xf1680b75, 0x36290a0e, 0x593f0de4, 0x10959f64, 0x5ca02a36, + 0x3b380531, 0x9afd88b6, 0x2e7cd13f, 0x2b8065fe, 0x8f6fda0a, 0x21a1ec4d, 0x8000c076, 0xe7d20af2, + 0xfd62f330, 0x0f61ac75, 0x23d485e2, 0x6d77a9e5, 0x891456b1, 0xc112e00b, 0xeb848769, 0xe38a26da, + 0x1819069e, 0x76d8db2f, 0x1dc0ccd5, 0x19ac4803, 0xf14f527c, 0xe9a61aa4, 0xd7684727, 0x951d6801, + 0x75933437, 0xb566b205, 0xbab02aa2, 0x7fe135d7, 0x1540f5ef, 0x20d6b46d, 0x6b3af54b, 0x1f273f21, + 0x3e47da6e, 0x4c8ae180, 0xab696437, 0x77ee4e3b, 0x80e9bc34, 0x06860df6, 0x767560c1, 0x644bf164, + 0x5bc4d2c6, 0x4e7ee086, 0x7dba69c0, 0xf3df0bcd, 0xe505983a, 0x1285875c, 0x87ca2d81, 0x50b7412b, + 0x87f86823, 0x014bc0ee, 0xeb053677, 0x950558c7, 0x8c616e19, 0xb3f30367, 0x7b30339b, 0xa306fe0f, + 0xae2d3f50, 0xdb0731c6, 0x257ee968, 0x38d15d58, 0x38c7b67a, 0xeb687f01, 0x37ae7b62, 0x34ca9ef3, + 0xdffe0028, 0x3384b561, 0x5edec89e, 0x249e1211, 0x03fd29e4, 0x8e1255ab, 0xaf6dcd8b, 0x51ac5170, + 0x75e7b6e2, 0x98303a07, 0x580ae54d, 0x514831f6, 0x1bdc76cb, 0xe8a08e25, 0x31cb233c, 0xb2bbfacb, + 0xbfdde7d9, 0x5bc894ab, 0xcaabffe2, 0xfc432970, 0xacdf8656, 0x2711831d, 0xa2911c9d, 0xf63d47a3, + 0xd0175f4c, 0x2e1c116c, 0x1d5e01d5, 0x43541cef, 0x5e8cf472, 0xc4e780c8, 0xd0d69af9, 0x7d7fa183, + 0x628a4668, 0xda76cda3, 0x5a78f2e4, 0xdb5a9351, 0x8648d5b6, 0x11104b8b, 0x885d603d, 0xf99b9f4f, + 0xe5c978b7, 0x6d95d714, 0xd47a9ef8, 0x52e07b1c, 0x211bf620, 0x2a769b70, 0xe91c2283, 0x98451501, + 0xe9285344, 0xd22f3a1b, 0xfba100c1, 0x46540fec, 0xce3cefdd, 0xd60cc88d, 0x6f24316d, 0x3c8adf88, + 0x3b4d4738, 0xb44be756, 0x1c75f964, 0x13555561, 0x504301fe, 0xd212ca59, 0x181b030e, 0x41084b59, + 0x0d858851, 0xc659f5bf, 0xd452bb79, 0x98f0611e, 0xd5f680dd, 0x4f1528ec, 0x27aa9658, 0xd49fc5a9, + 0xf2f37b3d, 0xff75e92e, 0xa2b28f3c, 0x3839503a, 0x3dc3f33d, 0xd14cd4c1, 0x9f42951a, 0xbea623ee, + 0x10b3d2a1, 0x652ea62a, 0xb2f50ae5, 0x118f9e24, 0x0edc367c, 0x784850dd, 0x97b43f20, 0x99b9778a, + 0x62965361, 0x606fcc6b, 0x034ccee0, 0xdef14c34, 0x02f8afb1, 0x49161105, 0x73482268, 0x3d547fef, + 0x1473667e, 0xe7536662, 0xface2b1d, 0x6ae0993b, 0x0b90f464, 0x9d53cbc1, 0xc3f0f79e, 0x254d2bfd, + 0x373b2b1e, 0xacd2977b, 0xe3147922, 0xe86f8898, 0xa1096f56, 0x7cce3663, 0x1ad27ee5, 0xd41ab1a6, + 0x88372723, 0x7c7ad5f9, 0x9a500086, 0x08b01aed, 0x7e7c8ad3, 0x2e9c169f, 0x16e652e5, 0x737a1701, + 0x83c55ba8, 0x95cf02aa, 0x30f7592a, 0x7d282618, 0xdfe11185, 0x81a022da, 0x9a335a27, 0x03a19f6e, + 0x79671615, 0xbd5e9884, 0xe2bf4ff6, 0x58a76e1c, 0xdf4eb504, 0xb256526e, 0xfb586a4c, 0xa1267cfc, + 0x35991e14, 0x897bcd87, 0x097a9bd7, 0x6ad526de, 0x0c43c39f, 0x0e86c670, 0xa3a7427f, 0x7197425f, + 0x7f40e7eb, 0xc10ae9f1, 0x408c57c0, 0x27d81850, 0xfe617a29, 0x39596c41, 0x08066cf0, 0xf765c83c, + 0xf8113645, 0xc813d2c7, 0x55a1ec41, 0x438b6bb6, 0xb3435c83, 0xa327c9d6, 0x358a9051, 0x21ab3ea7, + 0xab7d70f4, 0x314ec1e7, 0x125c5e5a, 0x55ea2406, 0x5d90ef04, 0x4f0f076b, 0xe707c06e, 0xd38efd6c, + 0x79f635be, 0x6ec05242, 0x87f6df35, 0x65fc1d60, 0xbe08fadd, 0x1df09d57, 0x9d4f48c8, 0x237ce2c9, + 0xc37041db, 0x5f22df39, 0x650171d3, 0xff885823, 0xc064fa21, 0x7c0cd925, 0xa171b7ec, 0xf0ac4d0e, + 0x929c5abb, 0x683db424, 0xbb123238, 0x9489b8d2, 0x1029cbca, 0x9b6e7219, 0xab057efb, 0x058c7ea0, + 0xd07b0d28, 0xce7bc9d9, 0x757f15a5, 0x7d2127c2, 0x5f640a4a, 0x6ae1327a, 0xc8c12d0f, 0xba586f61, + 0x7cac1f7a, 0x6798a5b8, 0x1dd5f213, 0x7b0cafcf, 0x0b483b45, 0x48af274d, 0x70d78d43, 0x43a41388, + 0xbbdb0493, 0xb8862a01, 0x9b0c971f, 0x484bb1d0, 0x37d38a5b, 0x6cdf0c5e, 0x0ef25b80, 0x786546e9, + 0xe52d0c39, 0xe1739020, 0xe2701c35, 0xa76b1bb7, 0x4be60048, 0x2e9faebb, 0x9a205819, 0x0a579ae7, + 0x40e68ebf, 0x5154fc4c, 0x3a222f48, 0x30706e61, 0xe68274f3, 0xc2e1d06d, 0x8625989a, 0xf575bade, + 0x333c7e0f, 0x722305a5, 0x61904542, 0x9be85a26, 0x5de14f6f, 0x917e4ed8, 0x9cd93598, 0x1cb17712, + 0x4cd2882e, 0xfcc85a0e, 0xe75d8dd0, 0x136cadf5, 0x0a9adfdf, 0xe80d9788, 0x1928322b, 0x1f38b761, + 0xa6cb4608, 0xfb8c6200, 0xa01ff3fa, 0xc4fee5f3, 0x88a174aa, 0xcfdeb609, 0x9c372e42, 0x862e09a7, + 0xeb05ad22, 0x2c2338f0, 0xa609bfb5, 0xc73ad458, 0xa2984e28, 0xfc97120b, 0xb9d4ebd1, 0x8155f008, + 0x17bea475, 0xb9a1fcda, 0x357a790a, 0xc013ea15, 0xb1c8a5bb, 0xc8486de8, 0xc9fa0f7f, 0x88064465, + 0x30a6476e, 0xcd1b64d3, 0xb69ac8f6, 0x651a7056, 0x5ae0e21f, 0x9a98e960, 0xe28a790c, 0x7bf5d3e9, + 0x8f4c16a1, 0x18df792b, 0xdcd72204, 0xd6ce13ff, 0x226077c5, 0x890eb2c5, 0x03c8338c, 0x9879e218, + 0x47983f73, 0x2bca2a75, 0x1206273d, 0xc0a5793c, 0x99f72c0a, 0xbbe31a28, 0xf037755b, 0xf6ae9618, + 0xdc4116bc, 0x21d824ab, 0x7732cc7d, 0xc7d09c44, 0x084a318e, 0x4515030a, 0xd2ca7140, 0x5b0347c3, + 0x4c42fe7a, 0xcffc01eb, 0x07ea3754, 0xc1fb7c5f, 0x55157da0, 0xf621005f, 0xdb1f1d92, 0x7358b7f7, + 0x5e22345e, 0xf1eedca6, 0x4c54896f, 0x39f7888b, 0x010c3f64, 0x17841edc, 0x337ca549, 0xc89decc2, + 0xc52e36e6, 0x037c2a31, 0x78992a68, 0x0b266f08, 0x3e6d2a93, 0xebba90e9, 0xe86967db, 0xcc9415f2, + 0xce3ec899, 0xd04b99cc, 0xc0d95ae6, 0x0d7a1cc2, 0x249d4d77, 0x7bb0abcd, 0xe7bec521, 0x9e9586a7, + 0x58408036, 0xa36cda2a, 0xd83e7ade, 0x38d08c70, 0x3bb1bfc9, 0xf7879234, 0xe64302b6, 0x7f9017ff, + 0xe33c0c6f, 0xf58cc947, 0xd77d2a87, 0x9fbfe452, 0x00740e8c, 0xb76d7d44, 0x15c275d4, 0x1d22dbc3, + 0xb6eceea7, 0xfe625b9b, 0x9dee2157, 0xfd693079, 0x3e1c5ccb, 0x182dbdcb, 0xd620785f, 0x7e20db89, + 0xb29cd593, 0xcd84b00d, 0x4503599b, 0xfdd0e7af, 0xe2412209, 0x0284229f, 0xb48652fa, 0x5fbc513d, + 0xd8ba9e9b, 0xc348a79b, 0x3d68d482, 0x5d223af0, 0xbd567796, 0xb558097e, 0xc76a41b1, 0x9e92918d, + 0x95d89e3e, 0x317ab483, 0xceff6aad, 0xcdb8d73c, 0xefd52679, 0x6aa9dbf5, 0x55ab2a10, 0x48c13cf4, + 0xe8e788ba, 0x149afead, 0xda872bcd, 0xec147efe, 0x8c585bb7, 0xa97395bc, 0x0993b6eb, 0x54962d86, + 0xd9f94ea2, 0xc7c5a7ea, 0xb6b9a6e3, 0xcf0e2224, 0x8e93cd39, 0xb7fe3c86, 0xa2741961, 0x7e1eb59e, + 0x5ac7362e, 0x60c96724, 0x065b20f6, 0x498a941c, 0x791f6383, 0x58fc0d28, 0xca764b4e, 0x5c49a6a3, + 0x24eabb47, 0x68c3f458, 0xafcd0846, 0xbe9604ed, 0x87102ae3, 0x809a8115, 0xfad05573, 0x81962bdd, + 0x846a3ae1, 0xa421c1c0, 0x306204bc, 0xf16d438c, 0xd057120e, 0xf307936b, 0xc29597d1, 0xc89353c2, + 0xa6f77a10, 0x0cd9a57d, 0x0035f78d, 0x16b041c9, 0xfe5bb7e2, 0xad132f75, 0xf10893f2, 0x2ad1a678, + 0xcdc1ada7, 0xd631aa74, 0xf501c2ca, 0xd14246f6, 0xc86801eb, 0xa76b344a, 0x2508b07f, 0x48992758, + 0x70337aee, 0x7d3de800, 0x8086c40a, 0xeea0ff8d, 0x1d890f59, 0xecf3a44b, 0x03ec8e70, 0xc649c661, + 0x171e0f49, 0x5df55d12, 0xddffd82b, 0xbef24fff, 0xec045bc3, 0xaf0eed7a, 0xe755bbf1, 0x8b265509, + 0xe1bf46fb, 0x052cd858, 0x5d747495, 0x6255eb04, 0x4c8ddae0, 0x186a727f, 0x30721ef7, 0xc02d9920, + 0x1911da25, 0x2e9c8574, 0xff4bd50a, 0x190bac0c, 0x174f7983, 0x70f50fae, 0x24c9bac1, 0x913973a8, + 0x223c274a, 0xa24c390a, 0xcec3329b, 0x3f96f983, 0xa5cc8a99, 0x9b203e03, 0x7fe87f2f, 0xc508481e, + 0x386b2cd5, 0xda564785, 0x01954e22, 0xb7f03254, 0xab2c80d9, 0x8f3398e4, 0x449ad7c6, 0x7f3da27e, + 0x84b37d34, 0x8d01475c, 0x45d230b7, 0xf44ba49a, 0xc7623328, 0x53d5a6fe, 0x4d148da8, 0x485f4c00, + 0x0dc1d64e, 0xa58ae42c, 0xcd5cc2d2, 0x2278a465, 0x3bbfa58f, 0x226d7be2, 0xd66f1a3e, 0x5f90ceef, + 0xd81d2bdf, 0x6b6a6368, 0x06a117b1, 0x148fa2bf, 0x28b06f3f, 0x23be8082, 0xbeb64f75, 0x9961a12b, + 0x413a4e19, 0xb2c0a3d1, 0x381a415e, 0x879b939b, 0x2158e156, 0x5c7dbf1b, 0x5b8de1c3, 0x4e77e7f1, + 0x674c246b, 0x5caa2169, 0xcae1041d, 0x4fc66b83, 0x3df88a42, 0x440f084e, 0x107ec145, 0xca56b0d7, + 0xfc33c8f9, 0x702c416f, 0x5c4a82fa, 0xb7a8424b, 0xaaad1f46, 0xa588f580, 0xc29ebdad, 0x9e5cc745, + 0x02ebe5d9, 0xaf1bc985, 0x47f548f8, 0x85705523, 0xcf686d4c, 0x5c1aeef9, 0x99d14d27, 0x3556126b, + 0xb32dc039, 0x77fd6e3f, 0xfdaf7adc, 0x1beba2cf, 0xf6615310, 0xad0e74bb, 0xd7eee149, 0x521f5e06, + 0x3265710b, 0x2906cd99, 0xc284769d, 0x20c83d28, 0x85b54e1f, 0xbdba2f6f, 0x0f42debc, 0xf7a03458, + 0x3928e61d, 0x3b52a9da, 0x3d874d15, 0x721a6768, 0x7ab5c096, 0xa7694898, 0xc52b9786, 0x40aaf0fc, + 0xb744aac4, 0x6a8d877d, 0xbd564317, 0x764821b1, 0x717aeb1f, 0xdced43c0, 0xa621b76b, 0xb0cbf020, + 0xf9993057, 0xacd92df4, 0x0a077bfc, 0x153c014c, 0xf45a9157, 0xbb47f161, 0x90724fae, 0x9a7e4b6c, + 0x040496bb, 0xe54281a4, 0x2c8af695, 0xcd958e6d, 0x24c3c0e4, 0x57ef3111, 0x43819be1, 0xfdac7a0f, + 0xd4de3450, 0xa6307d22, 0x4ec58e06, 0xa10fe4d7, 0x1ccd9965, 0x75ff15de, 0xddc145b8, 0xc6f62a16, + 0xd8de8fc4, 0x6e4ce254, 0x5c594287, 0xabeddffa, 0x2de8f73d, 0xa5f6d623, 0x5a7ff105, 0x2524a822, + 0x03c5313a, 0x1f98612c, 0x25f8d9bf, 0xfbf93be6, 0xc904ad65, 0xd2dfc0f6, 0x9a8b00f6, 0x06b34946, + 0xc6c239b5, 0x8591ca53, 0xcd63e974, 0x52ac6418, 0x65b5f2d2, 0xd21a5e46, 0x131ef050, 0xbe2ac963, + 0x6a771662, 0x43bc41d0, 0xc651ed14, 0x08c738b7, 0x395e1ebd, 0x19e66135, 0xc2918dc9, 0xe8dd3d09, + 0xe55e2662, 0xd5e02444, 0xcd8ef006, 0x1ea475e4, 0x45ab6353, 0xa811de37, 0x05251ed5, 0x6f3c3360, + 0xedf8ab0c, 0xf39cd987, 0xb6199e56, 0xdf12a57b, 0x41316b9d, 0x2222126c, 0x2e12328d, 0xeca6081d, + 0x5fc79e0d, 0x9c6881c1, 0xdca5b866, 0xeb2d1f54, 0xe19c0904, 0xc5d46e2e, 0xe76ca0f1, 0xf1d20945, + 0xcce523ad, 0x490050b9, 0x9b207b7d, 0x68293ab2, 0xf7dbac98, 0xd5a578ea, 0xe87ea621, 0x6ac5d670, + 0x9de8adf2, 0x4e78b006, 0x4d697000, 0x0dd51574, 0xbf591187, 0x30fef83e, 0x4f6b92bd, 0xcfa5bbb1, + 0x092abccc, 0x567f0136, 0xbe5018b4, 0x330dae8c, 0xb48a9790, 0x3d5ce64f, 0x436dd659, 0x61ab7b9e, + 0xc05a036e, 0xe1846493, 0x0f01cfbb, 0x788535b2, 0xe58b23a7, 0xc95e6f4f, 0xbd9fa31b, 0x584f30c7, + 0xedea6fe2, 0xa40c9889, 0x9be6b312, 0x459e1054, 0x3b147d86, 0x9b6a4d83, 0xaf9423fb, 0x045f1e1f, + 0xaa5171ff, 0xb0397605, 0x05f7036f, 0x868f1404, 0x7accac6d, 0x4169db03, 0x535ab9d5, 0xfcb203d5, + 0x3e5b8968, 0xad604068, 0xee3d23a1, 0xebcbba45, 0x38c024d1, 0x39c22ae0, 0xff93f902, 0xfde8c498, + 0xc0cc0ab0, 0x924614fb, 0x10436040, 0xb37d2558, 0xcb6c8371, 0x622a7388, 0xc849c7d3, 0xc20afc13, + 0x62f58fe8, 0xc0b35052, 0x5ad94839, 0xce30f90a, 0x7960149a, 0xc3216d00, 0xd4e319f9, 0xd13455cb, + 0x08a8627e, 0xf7df01de, 0xf8adf96e, 0x11cd26f8, 0x66b7040d, 0x7815aa61, 0x88e74dcd, 0x90617ec9, + 0xb11e7e7d, 0x4125639f, 0xdd1851b9, 0x786dc7d9, 0x8ce904b3, 0x2dfa7bf4, 0x3a09b3b4, 0xd4811885, + 0x31b70f8b, 0x2bddf65e, 0x1da71dce, 0x4fb18966, 0x9544a2d7, 0x939dabac, 0x00294a59, 0xb1078b54, + 0x2d2c6bdd, 0x01cb90b8, 0xff909d12, 0x3dc9c113, 0x8afc20f2, 0x0c72eae1, 0x4e3c6d15, 0xe43b6746, + 0x30f799ce, 0xf540b2e7, 0x50d7b659, 0x658a7124, 0x4c985c37, 0x2e3c06fa, 0x4c77c3c5, 0x7f708878, + 0xf2d2fb44, 0xe1552a4b, 0xf1fd39a5, 0xceca73f6, 0x3c8a3543, 0x5bbcbcb4, 0xe232071e, 0xd8351410, + 0xa01b5832, 0x36cf6cbe, 0x4f0aa996, 0xe2f376bc, 0x0987952d, 0x157335b1, 0xb04e8167, 0xb6807274, + 0x1f04dfc3, 0xc8a0dbfb, 0x7b455e8d, 0x52755bee, 0x1d0af92c, 0xd576daba, 0x473fb4ab, 0xa87a79dc, + 0x796b8134, 0x020ccf8b, 0xca8a18b4, 0xf74b2477, 0x3dc01dbc, 0x329a450d, 0x36341ad7, 0xf3708e13, + 0xe0e35c8f, 0xa2a2ad41, 0x8b537524, 0x13602642, 0xd3ad7c02, 0xfec8524c, 0x479ab46f, 0x13385520, + 0x9c545222, 0x3ee193f2, 0x8080e24a, 0x010bce48, 0x66ac2af4, 0xac712ed6, 0x5ab1cfe3, 0x529abf3b, + 0x874d2f5d, 0xef93c263, 0x5f5f3124, 0x94824a8f, 0x897e3af1, 0xcf1273a9, 0xce6b32fc, 0x3651a567, + 0x800c6216, 0xdcd4f4ef, 0xdde94209, 0x0d2effc2, 0xcdf8ff46, 0xe8faaf5e, 0x78f1e735, 0x7a7d677d, + 0x566606ed, 0x937cf845, 0x597c6714, 0x2142ed21, 0x9741c701, 0x92583bca, 0x33cf3b40, 0x7190a699, + 0x4ec026cf, 0x56b0973c, 0x02c234ed, 0xc5118a77, 0x865ddab4, 0xb1ceaf47, 0x8188c890, 0x087947da, + 0xb2e5b695, 0x8d0493ca, 0x5ad6ab8a, 0x6de65399, 0xb1227656, 0x83474719, 0x6e062756, 0x325303f2, + 0x98c863b3, 0x50493966, 0xcbae7b42, 0x652993d3, 0x4f249bf2, 0x099ae45e, 0x7b203747, 0x07eaded3, + 0xd87f70a8, 0x5538548a, 0x61b7329b, 0xf4e3cc64, 0xb10ab0eb, 0xce3a273e, 0x4cb2c01f, 0x269e97b5, + 0x4569b85b, 0x8537023a, 0xa9d6f40e, 0xbd3e0dea, 0x968598e8, 0xcb666345, 0x7fe55d1d, 0x244a9df8, + 0xcc1616e7, 0x50975b49, 0x60307e1e, 0xd5d41448, 0x71610cbe, 0x692aaaab, 0x4560c8e8, 0x7e75584f, + 0xe122c8e6, 0xd698b0a5, 0xa35713ae, 0xffb5a429, 0xd5724b00, 0xa42d6b12, 0x7ccc892d, 0xcab1ce80, + 0x4ff5604a, 0x1ef18b32, 0x34aba06d, 0x07fc3bff, 0xea65ec50, 0x2617fea7, 0x15f577bd, 0xe1ddbb5e, + 0x9e313d9c, 0x1321be19, 0x48bda5c3, 0x9f8bb6ff, 0xf92f5cb1, 0xadd3f377, 0x7232cbdf, 0x37f423bd, + 0x45d4b62d, 0x628d83af, 0x90701a39, 0xab9f7551, 0xb212d78b, 0x4ac39657, 0x8ac8e5c3, 0xb9261864, + 0x188dd482, 0xacdf3fae, 0x370c68af, 0x35b2dc1f, 0x6aea1a50, 0x03096a92, 0xd04e99c3, 0xa6a4e9ec, + 0x0e0e96e2, 0xf4d63d6f, 0x378e32ca, 0x15d70b5a, 0xf66bf8fc, 0xc873ec86, 0xbe82bc71, 0x9558a604, + 0xfe155f7f, 0x387bb719, 0xe3a6606e, 0x49c46ef6, 0xdbe9b2d3, 0x0a964af2, 0x29f393fb, 0x4c3b97d2, + 0x8e1660c0, 0x293e1cc5, 0x0717fcc3, 0x7566d11c, 0x366d1b45, 0x7954b146, 0x2f0d3e7f, 0xc85bb317, + 0xc0f2c57c, 0xd5afde98, 0x9c50d8e1, 0x98025cc9, 0x05ff0802, 0x15b2fa2e, 0x39278a02, 0x244e7746, + 0xe68eeb59, 0xcda768ee, 0xd45c5012, 0xfa1edee8, 0x697bb932, 0x33997e15, 0x45b0a70e, 0xf9c966e7, + 0xd7290329, 0xfa4084b1, 0xc10a848c, 0x843969bf, 0x3de34b29, 0x074f57af, 0xd05f94fb, 0x52fa86d0, + 0x3b4dc65a, 0x3d8f1672, 0xc4fe420e, 0x7d5d2d55, 0x1881ca86, 0x6378d293, 0x67ea6222, 0x21efa3cb, + 0x8f1aa560, 0xccce0135, 0x0e4c7309, 0x95a504ed, 0x7cda4338, 0x55e93844, 0xf9840caf, 0xa59a0ec5, + 0xcd16f4a0, 0xddc5958a, 0xdb311cfa, 0xac0a3a61, 0x6ee1461a, 0xcdb8bac9, 0x26dc4455, 0xf58bde21, + 0xf233350e, 0xcbcbfa85, 0xc79e3397, 0x5c6d3914, 0xf5de7bf9, 0x928c21f7, 0x0e5d103f, 0x38ff5f7b, + 0xc9ea3701, 0x7efb28f1, 0xf51717d6, 0x1dccfcc9, 0x27caf7d8, 0xcca2baf4, 0xa6b76e30, 0xeb193d70, + 0xdbd4632a, 0xd9235052, 0xd79dc54d, 0xd5fecb1b, 0xbd87d6b5, 0x0b050162, 0xb9bdeaaf, 0xd5796d78, + 0x0aef7666, 0xac551def, 0x074b3303, 0x35d6e69f, 0xa0932d3e, 0x01e0bc6c, 0x7306e216, 0x3327f03f, + 0x26ddbd83, 0xf4b666a5, 0x8793d435, 0xb35a13da, 0xfbba86b3, 0x33edb591, 0x8d3e3f56, 0x472b086f, + 0x963bcb64, 0xcc3536d5, 0x0da4c704, 0xe25622c9, 0xd8e71760, 0x083acad8, 0x75da4485, 0x0847dedd, + 0xac7c11ce, 0x0e5b387a, 0x1a203e98, 0xc5d08f23, 0x97882b48, 0x137c97ca, 0x108a22e9, 0x40d981b3, + 0x93621940, 0x6f743859, 0x242387de, 0x9b547ff0, 0xa452b365, 0x2b008002, 0x3db72a50, 0x27f4195c, + 0x0e56db77, 0xfdc23be2, 0x0ecf5dc4, 0xd63f91a1, 0x3f58f645, 0x87672522, 0x00f1c640, 0xd7478916, + 0x5f221b06, 0x6e0e8db5, 0xf36234da, 0x480f193e, 0x6daab5b5, 0x4cb04bce, 0xb14266ef, 0x1c408e9c, + 0xc50f088c, 0x240dab38, 0x4d077f7b, 0x4682def2, 0x1373a4b1, 0x205ca694, 0x77ee1280, 0xf9cf5a9b, + 0xae6e83b4, 0xaa4594e3, 0x9085e458, 0x94a121ee, 0xdaa9f85f, 0x12e09bdd, 0x6295fcb5, 0x02431247, + 0x17ad91d9, 0xf32ef350, 0x704f916e, 0x560e1a91, 0xa572958f, 0x61932fd7, 0x129c4e3e, 0xad72b25d, + 0x8084abf5, 0x652e3627, 0x794001ab, 0x28dbbafb, 0x7f9d6c7a, 0x30887ab4, 0x8aae8289, 0x7e8d695d, + 0x80a10aaa, 0xb8dc8a83, 0x14796335, 0xb422bf8c, 0x3a9a711f, 0xf04d9124, 0xe24e3af6, 0x0d1a8a5b, + 0x49b11f3d, 0x45908621, 0x9d355eeb, 0x9ebe60a7, 0x247895ce, 0x7025d238, 0x3dafe8e2, 0x7060375c, + 0x94a7832a, 0x39c2fc51, 0xb0f5f5e8, 0x8074e704, 0xa79a177d, 0x42988c95, 0xc7aa82ec, 0x04c8645d, + 0xcb483606, 0x40307171, 0x88824fe9, 0xd91fb8c6, 0xe8611e9d, 0x1b32c1e6, 0x08fe2b48, 0x132042c9, + 0x99ae8e7c, 0x31a432a0, 0xecc674e3, 0x4b8fa475, 0x2c61ca5c, 0xef6237df, 0x083c5dbd, 0xa04baf3d, + 0x2fc23051, 0xbaf0c514, 0x767a642b, 0x50a49074, 0xf762d420, 0x9b55d745, 0x9716611e, 0x2e0c2b8e, + 0xb3bc9b38, 0xcd78f475, 0x71df8513, 0x02b176ec, 0xac43d6ae, 0x7474a7d8, 0x3bf14c75, 0xf1c33221, + 0x6f8fd33c, 0x3c374d3a, 0x933dc919, 0xf06a83d3, 0xfe39fac3, 0x059fd9dd, 0x8d066b79, 0xbb331f7e, + 0xa0a05152, 0xf0b01d86, 0xe6941324, 0xa964b34a, 0x22891b92, 0x06861fef, 0xa29cfa28, 0x1ea4070a, + 0x800f758f, 0xb04b476e, 0x23603a6e, 0xa270db58, 0x56b004da, 0xf9b02372, 0x533c7f45, 0x9f2cc9a8, + 0x3b13ef25, 0xd677a05a, 0x2780677b, 0x2ffea339, 0xb01cd0e2, 0x51d81328, 0x034bb424, 0x3eac6321, + 0x4a4b8593, 0xe6605d75, 0x6d3a7b9b, 0x26e35439, 0x66692c44, 0xaf076644, 0xc4078483, 0x76772659, + 0xf4956f59, 0xcd9a9784, 0x6fe0559f, 0xc3ac3f3a, 0x8976bc02, 0x4456a5d9, 0x8789232b, 0x41f864b7, + 0x5be12e37, 0x1ff41bc8, 0xc4f31aed, 0x8ad1d136, 0x20629088, 0xc3d4db43, 0xbf018097, 0xd916bb05, + 0x89fdce37, 0x13117c72, 0xd09dd381, 0x3c82416d, 0x386aac4e, 0x59506e8f, 0x5fe6b097, 0x10fb1fd9, + 0x99c91474, 0x342cb0fe, 0xabefc0c4, 0x88dd0847, 0x49b5bf2d, 0x1c7eb70f, 0xe93f10c2, 0xc23dfd3f, + 0xda3eb330, 0x2b54e6fd, 0xf8383a3a, 0xfdd434f4, 0xe0bf80c2, 0x35203dea, 0xd7a5c30c, 0x9dbeaf93, + 0x0cb1839f, 0xd3fceb20, 0x5328970b, 0x1c36bad5, 0x52095e5c, 0x851a2c2b, 0xc7365f3d, 0x568ca9d8, + 0xf36daa20, 0xe37e5370, 0x3278ba91, 0xcd3c105b, 0x556a5617, 0xa68bd54f, 0x7fc48ca4, 0x7fe25c7f, + 0x0d2774d9, 0x34f690db, 0xa156479d, 0x0b05c894, 0x039d42bf, 0x5e9bc73d, 0x2f17e082, 0x65f9346e, + 0x3b40d9fe, 0x72691656, 0xfdc43ba3, 0x7bbaa754, 0xe579171e, 0xa36a6ac2, 0x53f81c91, 0xbac7eb5a, + 0xadcf60ae, 0x75ddd0bd, 0x1b7c153d, 0xec3311e3, 0xb4c4d149, 0x92e11a03, 0xa6a81274, 0x738ab4a2, + 0xc4f79aed, 0x4c4394d6, 0xacca3baf, 0x8a42ecc0, 0x184b1374, 0xa3753863, 0xa0852757, 0x3038a0a7, + 0xb98fa975, 0xfed4e830, 0x6109b9e6, 0x33360f60, 0xe7f30562, 0xb7fead74, 0xe99c70ce, 0x86e2723e, + 0x072aea74, 0xf530bc9a, 0x51303c0f, 0xe2ca3c92, 0xd2316dc7, 0xf21e46aa, 0xb261ee37, 0xd9dfe996, + 0x1cfbc92a, 0x5a906317, 0x8c512ed6, 0xf03d90c5, 0x344c4071, 0xfa77a70e, 0xb6851eaf, 0x01a6f0a4, + 0xfb090058, 0xead94f90, 0x8e9cbd26, 0xc6b656cb, 0xa843209b, 0xcd68ed74, 0xc19f9492, 0x7badba54, + 0x5c1161c1, 0x93519f96, 0xe95a9bde, 0x27e55180, 0x028cbd63, 0x7aefb698, 0x733b49b7, 0x2c1a7d67, + 0x99d91c86, 0x395ff7fe, 0x3bda26d5, 0xbe389709, 0xae3c339a, 0x23d38cc8, 0xe1dc1634, 0x8727aa8e, + 0x03690185, 0xfcbe8d51, 0x92b9a2a2, 0x01aba058, 0x01bbea0f, 0x8d67e07f, 0x41734179, 0x7e184762, + 0xa44ad972, 0xd61bfe04, 0x486c6ed2, 0x6b78395f, 0x98ff0662, 0xb91f6adc, 0x8ddbca73, 0x4e3e9a87, + 0xff7a0efc, 0x1f24e66b, 0x45a63d56, 0xc2c48dc5, 0xba6ff5b4, 0x6fd13536, 0x22d92b52, 0x61432f55, + 0x17daa219, 0xfb002a07, 0x7991711b, 0xecc5d268, 0xc7cf4ff6, 0xb927c0f0, 0xa97f69b7, 0xc2bdf3dd, + 0x163f2746, 0x11a25f64, 0xf0d12f33, 0xab91e95e, 0x547c0e0f, 0xb50beff5, 0x85c3db2b, 0x8282352f, + 0x1f802583, 0xfbaa7946, 0x60386c69, 0x74831846, 0xced833e8, 0x5f3f2acd, 0xe7ea84f3, 0xd1e1a2db, + 0x75c57a31, 0xe35b56ac, 0xd01702e6, 0xa451e55e, 0x8009f0bd, 0x4a7e9f18, 0x0a6b58fb, 0xee5c17fd, + 0x5613bff2, 0xa6f56d95, 0xc377a5c2, 0x6a1faf07, 0xd32d63ae, 0x5cc4df4d, 0x43f0b97b, 0x7263b673, + 0x917c1f36, 0xf750c1af, 0x7c5bd39f, 0xe0f8e3d9, 0x00056fcb, 0x79e35dea, 0xdacc5dee, 0xa16abfa1, + 0x15c9119e, 0x376fed8e, 0xb0b1cf23, 0x86dd05a9, 0x49823ecd, 0x238a7cb2, 0x76b10c91, 0xfa721ffd, + 0xd3291364, 0x3742690e, 0xc92efe2d, 0x3071c280, 0x66d97216, 0x9b150f87, 0x99b35a31, 0x7d1cf527, + 0xe69bfe7b, 0x98fc60c9, 0x2b100789, 0x6458466f, 0xb76aee65, 0x9aee7101, 0xc9a8e9de, 0xb0681bd1, + 0xd4cc2dd6, 0x75c9ded4, 0xa6d25145, 0xaf89c03c, 0x3083d6fd, 0xb807850a, 0x14b95c85, 0x2f86f62a, + 0x4b3190b4, 0xd3ce24f7, 0x06449ac8, 0xcc0434c3, 0x73226be1, 0xa66756db, 0xc412d1e3, 0x7cc1bb3f, + 0x0ca5c4a8, 0x8565d32e, 0x31c44894, 0xeff8814b, 0x518e1688, 0xbff3ad06, 0x9d6cb9cf, 0x537d14c5, + 0xd4e7ead1, 0xab16977f, 0xe53cb170, 0xfc2c1724, 0x0f55fb62, 0x5a7cdb9e, 0x87ab7065, 0xbab799a9, + 0x69d8e18c, 0x91bf70ae, 0xc9453379, 0x19726c54, 0x89869c81, 0x25e2821c, 0xca1237cb, 0xfdc6e216, + 0x368c95eb, 0x5027b9ca, 0x526ea5f5, 0x07bb3e56, 0xc051ac86, 0x59b0f869, 0x13d3bad3, 0x86785f79, + 0xb1d7477c, 0xfedc8f05, 0xb6e25bd8, 0x950b67b9, 0xf085c2d0, 0x408efe36, 0x8b35ce7c, 0x669d9563, + 0x037b1bd0, 0x123bdc00, 0xcfca75b6, 0x8f65585d, 0x047ae3bd, 0x988ca05a, 0xbd3660b6, 0x4aa39f59, + 0xda0a73b8, 0x2017c857, 0xca10991b, 0x39cfc0e9, 0xffb765a3, 0x1af29fea, 0x281858c0, 0x6ecd5e34, + 0x5a21cb6b, 0x8f47ea68, 0x95fa2d55, 0xf24fbde0, 0x522b129b, 0xd8f899c0, 0x28ca785a, 0x9886100a, + 0x852c3b11, 0xa6bf2be8, 0x3e708de9, 0xe2d7974a, 0x2b4f649b, 0x36e6ae41, 0xa0bfc0e5, 0xa33e356c, + 0x0d052d26, 0x965537f0, 0xc7f20619, 0xe2ff881c, 0x554f651b, 0x29634007, 0x057750f2, 0x2e16477e, + 0x04c24e30, 0xed24969d, 0xe64474e6, 0x1921c1a6, 0xaf4eddf0, 0x715ea1b9, 0x3bf2efc5, 0xfb8786d4, + 0x4f5a764c, 0x63250ea0, 0x3596bb86, 0x928586b2, 0x33c788a9, 0x9641eea0, 0xe57ea4ba, 0xcbf4acfc, + 0x494e023d, 0x103d6ef8, 0x3dae91dc, 0x8882a4ba, 0xc13de8d4, 0x9beb8e94, 0x119ca03b, 0x4c35a41f, + 0xe9778975, 0x8d0a5d1b, 0xcb086901, 0x6a5840df, 0xab6c12f1, 0xd94d118c, 0x0b29a53e, 0x9a9822fb, + 0xae2e24af, 0x5afe28ce, 0x7a1b78a0, 0xa89410dc, 0x81529d5d, 0x93460ba4, 0x8d2212af, 0x843e3465, + 0x1ba85055, 0x6d371473, 0xc9c2d98a, 0x20ef4517, 0x38ec4573, 0x4ab576b4, 0x0119b2e5, 0x40bf464b, + 0x90b4bb85, 0xbf0b7ad3, 0xfab5d18e, 0x01e919e8, 0xf1cd237d, 0xc53edef1, 0xc270a45c, 0xb5fe2e3c, + 0xe34cbf6f, 0x38c25225, 0x617713e2, 0x986dfece, 0x2af3fbf7, 0x86380514, 0x0cd9f57a, 0x85276406, + 0x9e371a3b, 0x67ec5b35, 0x3d735792, 0xc4aed828, 0xcd6dcc36, 0x4002d2ed, 0xce20c625, 0x30ac6cf8, + 0x9b23cc44, 0x2f54f0ff, 0x37974940, 0x42f60875, 0x63bcec01, 0x79f2f5fe, 0xd61b96fe, 0x18e4b270, + 0x22458efe, 0x759d3164, 0x5cf8fe4a, 0xa239f8ed, 0x007419b2, 0x1cf53523, 0xc1546eee, 0x799ad3a7, + 0x4946c5d7, 0x258e5200, 0x9a0cfb09, 0xc4436fe8, 0xf5b07642, 0x5782a43f, 0x72fb3f40, 0xa0ad1e22, + 0x80f60127, 0x8a8d6aa6, 0x2c4f79a0, 0x9a00922d, 0x427dc437, 0x86dfe895, 0x639416c7, 0x344d5485, + 0x87cbfab6, 0x88b5f65d, 0x02a546ea, 0x9dadc640, 0x89a30f2a, 0xcf703620, 0xab4ed9ba, 0xbe522079, + 0x919541be, 0x99162266, 0xcb9e877d, 0x99d61b39, 0x686e444b, 0xcdd15f07, 0x7017e006, 0x07f8ddec, + 0x072f4748, 0x38ec4a23, 0x2b414faf, 0x16952f84, 0x04b66419, 0xebade28e, 0xbd450e8a, 0x45ea6c70, + 0x7ecd2346, 0x6a1e0988, 0x29d54a5d, 0x2254de17, 0x8cdf476e, 0x4e8e5b63, 0xe924bd5e, 0x444fa12c, + 0xeb06a1cc, 0xaf02ee33, 0x033b0a12, 0x8a2a0c65, 0x1e57f028, 0xd0ad062c, 0x52e1738f, 0x255e8fa4, + 0x4a600945, 0x4d5ce936, 0x4752476b, 0x3ed5bd83, 0x17cc2822, 0xcc117b00, 0x75da0b42, 0xc52ff037, + 0x21e3b079, 0x0e1c9037, 0xfd841002, 0x7a8ab44f, 0x1c1862b2, 0xd6e62da9, 0x0c8c7fc3, 0x57f5010a, + 0x5e3dc193, 0x94d6c2d8, 0x51264683, 0x766798af, 0xcb6179bd, 0x74843a8e, 0x769e934f, 0x9efc0d5d, + 0x06667c8a, 0x6fdd5357, 0x8eadaa78, 0xc1ba681e, 0x64b072bf, 0x9b932f22, 0x141f8364, 0x8f569778, + 0x844703a6, 0x23e0adc7, 0x37085ce8, 0xc421065c, 0x34c1539f, 0xbef83566, 0x6e77cbfd, 0x1b9b90de, + 0xae966a15, 0x403753ca, 0x25dc2204, 0xb341c055, 0xd7802fe9, 0x01d3c87f, 0x81df3274, 0x8c711322, + 0x5dd2c1fa, 0xb865f6ce, 0x0ef19236, 0x242e8c95, 0xfc7bcf02, 0x54759f33, 0x3363b884, 0xb6b27d69, + 0xa5f94e0b, 0x5ff93322, 0xf6249908, 0xa0176546, 0x00eb4044, 0x1a5880e5, 0xdc0f6e5c, 0xbbaa506a, + 0x1a940233, 0x016584fc, 0xee3120c9, 0x2320bda5, 0xc18955f1, 0x18149b8a, 0xe924d02f, 0xcc68384a, + 0x371be340, 0xbd6ee303, 0x31a3e07b, 0x0d6a9f46, 0x229d6f8f, 0x9952427a, 0x657420d5, 0xe72df3eb, + 0x3ec7d29f, 0x5d313e04, 0x2fdfb7f2, 0x3da04053, 0xa158a9eb, 0x15a45bcb, 0xf31066e0, 0x36999371, + 0x0495b8c0, 0x97cce67b, 0x20598b82, 0x44ec26c4, 0x6dd9d144, 0xa208f292, 0x3ae425fb, 0x2c9929c1, + 0x5265f883, 0x723d48c2, 0xb1f9dd42, 0x03092134, 0x690d0209, 0xafd00683, 0x51e1cb2a, 0x35a0e305, + 0xaf386de1, 0xb2ae02cf, 0xdb3cdf95, 0xb6b81c87, 0x02d3a430, 0xd838504a, 0xd5be5769, 0xa98b3bdd, + 0x8c042f0c, 0x124b8fdd, 0x05664d9f, 0x7244c682, 0x48e0fde2, 0xdef041b3, 0x42e93e1c, 0xb9aa984a, + 0x1c4ab237, 0xe3579a47, 0xcfa91b99, 0xcb8c634d, 0x54fbdb34, 0x5327152b, 0xbae67b6f, 0x7c41828a, + 0xa3f1bd80, 0x479a1ce7, 0xde4af7cd, 0x9a48a0a6, 0xddb25e23, 0x624514b9, 0xefbeac5e, 0x5fad0695, + 0xb5a5e666, 0x3e00550e, 0xf9673b13, 0x1adb4ed0, 0xfd7330ab, 0x038f8662, 0xe7268e3e, 0x04b98b9d, + 0x6ca4899d, 0xb7afc824, 0x52ae359d, 0x9457888c, 0x4ef37fda, 0xda70f1e5, 0x55368813, 0x7eaf5845, + 0x98c15911, 0x4bf97fc2, 0x4bcc446b, 0x4064c638, 0x1a92356e, 0x7557ee83, 0x80acf1a4, 0xed8dc2bd, + 0xebe87454, 0xf78677b6, 0x1b112885, 0x1ef61efa, 0x244bc9f4, 0x5ead2531, 0x1b939e25, 0x379124cf, + 0x3ece2ae4, 0x58587e66, 0x5d57ec76, 0x3607dfce, 0x7bcd13fc, 0xed8ea196, 0xc401acde, 0x10b576fb, + 0xac941d59, 0x723a4f47, 0xd8823ff1, 0xc341e3a8, 0x11fc4740, 0xe95e320f, 0x016f219e, 0x97143c21, + 0xcb4bb410, 0xa60709f2, 0x70839e6e, 0x498ce8bb, 0xa9f8168f, 0x959988c8, 0x632abf7e, 0xfd17a446, + 0x3f55da96, 0xd3e51111, 0x1894f683, 0x009c5905, 0x2b3b6f66, 0xc2d69df0, 0xe6d01af9, 0x40cbe3bc, + 0xe1052c91, 0x8ff35791, 0x91fba08e, 0xd4ffeb01, 0xf7d66397, 0xe1da7c17, 0x302b8815, 0x6fbfc354, + 0x5217c7a9, 0x77e6af9e, 0x4ea7b94e, 0x8bcfc9c2, 0xeba6d4be, 0xdce8c572, 0xa3ca4201, 0x27e0ae0e, + 0xb4f286be, 0x05cb327d, 0xe3ddcf4b, 0x1c0f6cc4, 0x21c524d0, 0x684785d6, 0x3e0e4f25, 0x62f479b8, + 0xa639b1fe, 0x26e47d7c, 0x59242590, 0x280fc914, 0x68eb40fb, 0x3f6b1688, 0x1d4e8769, 0x35ba74cb, + 0x85033d05, 0xc6dae47c, 0x6a114189, 0xac8edf68, 0x36452030, 0x40932a89, 0x70018ae9, 0x99d786be, + 0xc7adb41b, 0x342e35d3, 0x05c55e04, 0x1754401e, 0xac2cb5f3, 0xb9e2636a, 0xfcaa2941, 0xf5acf381, + 0xb34edd9b, 0xf035dea3, 0xd0f0a291, 0x3d654a54, 0x457b4e8d, 0xf4ae1805, 0x146f0d66, 0xa11ffd43, + 0x8719d786, 0xa6ac7c70, 0xda5bc36b, 0xbd879dc2, 0xd4ab43bf, 0xceb04077, 0x29a582d7, 0x56075911, + 0x56fc679e, 0xd4fb6902, 0x28b2e7a3, 0xf730b293, 0x9d1d8a1c, 0x6f714aac, 0x68db18cd, 0xd87fe975, + 0xf608b3fa, 0xa3cfbdb5, 0xef0000d4, 0xe189162e, 0x8778f425, 0x879174ad, 0x1bb6d0af, 0x7d54c830, + 0x39717e4c, 0x2dcf805b, 0x39b0bd42, 0x20872e25, 0x94e52045, 0xde0d15d1, 0xfd65e167, 0x27e55913, + 0x7b8603ed, 0x94950627, 0xe801f534, 0xe9d0eba7, 0xc20372dd, 0xa7bb3e38, 0x2dc76d62, 0x5b61de38, + 0x682c9d75, 0x208a937d, 0xf6f4ae85, 0x5ec3f639, 0x087d4f52, 0x0c497e9e, 0x6f555c31, 0x7ded7cea, + 0x0bf87334, 0x466044d0, 0xe10ee127, 0x1c147803, 0x716efb86, 0x0014ea91, 0x04a937cf, 0x3b830f35, + 0x57ae703a, 0x067b841f, 0x8fa573e1, 0x93aeb6ff, 0x06b50788, 0xbe8e91c8, 0xb0c98f90, 0xc688f47d, + 0xa7c59159, 0xe2538454, 0x1fd7ba93, 0x95999437, 0x832da484, 0x1adbef40, 0x1c8bdda6, 0x71a5e4f6, + 0xb04e3b35, 0x7fcfd7f5, 0xb62588c0, 0x14a23dbe, 0xcc363de9, 0xa72e6892, 0x3b99e7b9, 0xf893869f, + 0xa20da3eb, 0xe8a54551, 0x5a9277c5, 0x854b2c39, 0x5c363da1, 0x49c540c6, 0x45f65dcb, 0x9641fd83, + 0xcebc7f3f, 0x6ab7f159, 0x6d5d04f1, 0xb01a0ca3, 0xc8ad4452, 0xb1b97e85, 0xc911d33f, 0xe5c090cb, + 0x618e47f9, 0x8773e177, 0x0c04b1dc, 0x907f34ef, 0x2aacc5b2, 0xf4861ac2, 0x0ac478d1, 0x3a63e2db, + 0xf28d72eb, 0x8e9eb197, 0x4f8cda45, 0x848b5075, 0x0657f151, 0xc4492396, 0xd5a58150, 0x45d2332e, + 0x68dc7674, 0x5dced27e, 0x25d8258d, 0xf13fdcb7, 0x748ed3c2, 0x97131580, 0xc0ac273c, 0x1a5677fb, + 0xc82a67d0, 0x4d00f927, 0x261e7adc, 0x5242e635, 0x7a812885, 0x8489befb, 0x47402e9e, 0x6408364f, + 0x2c7a0bc2, 0xd45c6561, 0xd3cc6c00, 0xfc1e29c4, 0x96eb8ffd, 0xa482e6d1, 0xa3df996f, 0xbde54b08, + 0xa950f396, 0x4f63b584, 0x6325c7ec, 0x8be2aebb, 0x73b86486, 0x0ec0f8de, 0x730fb2a2, 0x0be02eda, + 0xbe31c454, 0x1a143162, 0x1d08b4d7, 0x95ea8b50, 0x04a5b94b, 0x55e484ec, 0x8ad4de6a, 0xbef4e866, + 0x8b028790, 0x623cf4e5, 0x7b548576, 0xfe32d74c, 0x0ee72145, 0xb18fefbf, 0x13fb4b17, 0x55e25046, + 0xe5d47be4, 0x45881b84, 0x1b3d2eb9, 0x693c699d, 0x43e342dd, 0x1b7336c2, 0x0345f7a6, 0x76731f43, + 0x666d7251, 0x16cb829a, 0xfdcf84ee, 0xe5f8eec5, 0xa72d8e9e, 0xa379c654, 0x054fa677, 0x206a1a35, + 0x882e425a, 0x91c79c2d, 0xa1f522d4, 0x611851c5, 0xb59edbed, 0xabdc23a5, 0x83ffcf7f, 0xc61b09c5, + 0x6a2ed7fd, 0x50675135, 0x23a9cd8b, 0xcf05a38c, 0x2ed904a4, 0x68c14f8a, 0xb899c472, 0xbcdc1f6f, + 0x823348f6, 0xe6d3996c, 0x65c45d9e, 0xbb0923fe, 0xa37d3964, 0x2c54cd4f, 0xd5a8d5ff, 0xff708550, + 0x9d6964ee, 0xc2cc15d9, 0xa451f071, 0x76fbd717, 0xd764080c, 0xecbbee0a, 0xd660d53a, 0xeee9bfea, + 0xff4a25be, 0x6be917c9, 0xd22afcaa, 0x1f59e2ec, 0x07a92fb1, 0x26f2f4dd, 0xa1c63110, 0xccb3ec71, + 0xd5bf440f, 0x48e0e740, 0x08055bb7, 0x31b61d5d, 0x6a179073, 0xec14c714, 0x0154e0b8, 0x7ec000bf, + 0xc146bb9a, 0x215b4140, 0x11373c73, 0xa709a298, 0x1a2e83bc, 0x52284aae, 0xd297b21e, 0xa4e6bd78, + 0x033f8b60, 0x6342424e, 0xa10ebd25, 0xa5f1d08f, 0xed1f944c, 0x2bb46ad7, 0x3f92694e, 0x178993cc, + 0xd21c227b, 0x8895aa2b, 0x222674cf, 0xadf9cf93, 0x1e80bd9f, 0x4556818c, 0x002ec4ec, 0x1563d9be, + 0x34a24a3c, 0xdfcce375, 0x72a5a904, 0x47d75169, 0x36a57377, 0x87b9ca88, 0x90731a6d, 0x10b66d0a, + 0x94092687, 0x4cce3453, 0xacbccc19, 0x211a22b3, 0xe4f3cb7b, 0x017f2834, 0xe6a167ab, 0xe3ba24a8, + 0x164d7fb2, 0x8a4b16f3, 0xa10e1fe2, 0xbbb87d51, 0x581cb7c7, 0xc7f994b9, 0xdc468995, 0x3ef90532, + 0xd523a463, 0xe0a523cb, 0x093fba5c, 0x312c4e16, 0x1bc1df18, 0xc9142f2a, 0x8e31c8fe, 0x62052ab1, + 0xc8d66a26, 0xf5f6c68a, 0x52e35a32, 0x90c1bc61, 0xeb73b054, 0xd4322ab2, 0x6520e66c, 0x29d751ee, + 0xc78aab86, 0xae40c8bc, 0x64dfa17d, 0x204efa79, 0xb234298a, 0xba7dd4cc, 0xc3c0bef5, 0x866f2a03, + 0x2310b66e, 0x8c176d2b, 0x392d05cb, 0xe5025db1, 0xd248a567, 0x4ec5c395, 0xbb21c4bb, 0x651216be, + 0xb699273b, 0x0b4d89c3, 0x04ff2c92, 0x464824b3, 0x86ebfab6, 0xbf4c3f4c, 0x888be8d3, 0xe81ab0fa, + 0x0717c55e, 0x4a91b640, 0x1dbe563e, 0x8d5ce23d, 0x0923796e, 0x675c5641, 0x7cdb7a2c, 0x7129a46b, + 0xba3ee06d, 0x8e4c9892, 0x7c01453b, 0xfc1e3331, 0xd52a5ee9, 0x37033b9c, 0xca64f08c, 0xd138e5bf, + 0xf5eedbf1, 0xf2450ad0, 0xcf202ceb, 0xb53f531d, 0x0e72dfbe, 0x2f8ef075, 0x184d5930, 0xc7ec968c, + 0x1ac821b8, 0xe4738114, 0x614900d0, 0x106b4a38, 0xdd9b7449, 0x761b989f, 0xa4567aa8, 0x9978e962, + 0x6ae25304, 0x1c374478, 0x08db9c09, 0x7652f2ff, 0xdfa419f9, 0x613001b3, 0x5b71b167, 0xc2b5e7b3, + 0x0e53211b, 0xf3268ab0, 0xe8f354cb, 0xb73af12b, 0x600f6532, 0x93e27e7a, 0xce17eb67, 0x520d8012, + 0xdc9ad005, 0xc2388557, 0xc874877d, 0x5a83f77f, 0xcdef51f4, 0x048b1254, 0x088995c7, 0x69505be7, + 0x1e37da70, 0xe03f6b8f, 0x4a0e3eaf, 0x8496ccee, 0x2eb2630e, 0x9e00cc2b, 0x381bdc71, 0x3fb1054f, + 0x444c6dc9, 0xb54593de, 0x5be6ba50, 0x2b4aabdf, 0x4d1561bc, 0x2a68ad17, 0x7a1b61a2, 0xe4f81260, + 0x0eadbe50, 0x81ed8b15, 0x843ee860, 0x8dc4ea2f, 0xa570aa89, 0x09cb4507, 0x2119ada7, 0xc400bdc0, + 0xe9cc93b8, 0x367fd87c, 0x28997073, 0xb47457c7, 0x7d116dbc, 0xac88e2ae, 0xaa4a663c, 0x03fb0355, + 0x0c78e864, 0x5746b1b6, 0xc5372520, 0x6755d141, 0x6f5c8f0a, 0x2c71354a, 0x01a98cda, 0xdafdda0e, + 0xecfb81f9, 0x8d38bf6c, 0x5e7506a5, 0x59d05f9f, 0xd6632ec6, 0x83ad1683, 0x5660113b, 0x593274e2, + 0x39c155d3, 0xc8dff3d5, 0x06cf54eb, 0x6ad1854d, 0xf704fd44, 0x418c8bae, 0x6e21adfc, 0xbfd90350, + 0x836e0ec7, 0x4ddfa35f, 0x83729666, 0x839978f2, 0xf34be632, 0x690936c9, 0x753bbce0, 0x1055a8cd, + 0x0e974cce, 0x002b98e2, 0xfafe73f2, 0x408a5f31, 0x400f814d, 0xa8dfe79d, 0xbddbf2e2, 0x25b2b5ba, + 0xa264aa86, 0x234705d4, 0x5e1d93e2, 0xb890fdac, 0x5c0fb964, 0x7fce9b12, 0x6552f6aa, 0x2e80defd, + 0xe58f4339, 0x7a98773f, 0x36937282, 0x3e524dab, 0x2093015b, 0xa7033f2e, 0x4707de44, 0x3e69a13f, + 0xeff2c33f, 0xe6e3d9e3, 0x29e2ffb4, 0xa03752ec, 0x374d23c0, 0xaeea6196, 0x800dfdaf, 0x3d82bdf9, + 0x0711c642, 0x584def0b, 0xd84a2bbc, 0x206cd340, 0xa076ea3c, 0xb4038195, 0x830557dd, 0x5a6cb70c, + 0xcfb74bae, 0x83a785ae, 0x260928b9, 0x46af652d, 0xb6af3233, 0x11ed59ae, 0xe99618b4, 0xc8a1efdc, + 0xea07ce68, 0xe534725b, 0x64e19c9f, 0x3c0ff648, 0xa0a55ff4, 0xfefb94bf, 0x64dcc21d, 0xb823c206, + 0xa5dffbd8, 0xeaceddad, 0xa7cea631, 0x5fce1cfe, 0x8aee165b, 0xd0920182, 0xd12986ab, 0xdcbc1385, + 0x7457698a, 0x57510f82, 0x9997be1c, 0x3664b8ef, 0xa8f2f312, 0xc04587e5, 0x150665d7, 0xc34dc552, + 0x1a096a0a, 0xaf42a15a, 0x7500486f, 0xa69b26e6, 0x727bf3cc, 0x5e82a5c9, 0xed0fed8b, 0x8fda4d99, + 0x1320ba6f, 0x71294350, 0xcd493471, 0x787f4faa, 0xd6b1698e, 0x8347e76c, 0xbf8c8c16, 0xe0beeb0b, + 0x2f4fc353, 0x73f5c1d4, 0xb9d1c187, 0x88e0b161, 0xbf95e4c9, 0x6158e368, 0x00486e77, 0xc14d24ba, + 0x0a41652b, 0x74ba7d79, 0x3b9d2fc8, 0xc2f6d412, 0x8b9c20b7, 0x77f55529, 0x64c0c0fb, 0x72811ab1, + 0x451b8de6, 0x8b601dd1, 0x8e5e58e2, 0x721bb348, 0x7a61b26b, 0x4326f2f1, 0x5487fa73, 0xcfa11a4c, + 0xc6a36fab, 0xfdaa9541, 0x8c9232ec, 0x837e4b62, 0xee444f9e, 0xc3fbd1a9, 0x6c87e9f4, 0x2b69b86c, + 0xb1fdc7c2, 0x836b4c32, 0x75a70e8b, 0x1efe14d6, 0x9900fb25, 0x1475e478, 0x3d8341d4, 0xf58ade19, + 0xd4a29cfc, 0x50c99961, 0x2164a7bc, 0xeb260f3d, 0x5aa077dc, 0xceb05ab5, 0xaea737f4, 0xb56dfa74, + 0xcfbf589e, 0x4c1919b2, 0x0edef528, 0x2a5fda39, 0x1c55a36e, 0x77be106d, 0x0ba14a72, 0xa65e1ccd, + 0xecbb1ecb, 0x624ca00a, 0x856bb3c3, 0xfce0d723, 0xc78d9deb, 0xf4af46f5, 0xd11427f3, 0xcf9336db, + 0x21e1f646, 0x3f8eaeba, 0xd63c0620, 0x075ee74d, 0xd106d57d, 0x0bbae057, 0x6626164a, 0xe7aa03d2, + 0x5f7f87db, 0xac4b096f, 0x43b2c5be, 0x7f2f3402, 0xf78225d4, 0x2420a959, 0x7ce675ba, 0xd577a530, + 0xb75baa2f, 0x917f5fb9, 0xb286e3d7, 0x31fb9f00, 0x11745340, 0x4afcc219, 0xda831643, 0x595e64f4, + 0x8b56712e, 0xbdf9c800, 0x7c047119, 0x6ac8a7a1, 0x6293e599, 0x1a5dfe66, 0x5c1c0dc6, 0xb6e8018b, + 0x7baa757b, 0x0e9506cf, 0xbf89e667, 0x6a826068, 0x4dba389d, 0xcb51332a, 0x2f5b6bd8, 0x126f8a72, + 0x9e463f6a, 0xb6720952, 0xbc9e733d, 0xc9f93d64, 0x2c5fe445, 0x79a1bddb, 0x7e1cbd74, 0xdc6c3d88, + 0x5043adfb, 0xac8fc6ec, 0x42154409, 0x001f256e, 0x8d49ed53, 0xadc64f43, 0x5273e307, 0xfa7fa880, + 0x173057f3, 0x9dfb20c1, 0x99d07740, 0x25f10c59, 0x62250efb, 0x59778cee, 0x93d7e462, 0xa2aca8e9, + 0xd0fdeced, 0x5d86fa3f, 0xa1db2bc1, 0x0464d63d, 0x1d3a9777, 0xa546ac1f, 0x22092f9e, 0x1cb1ac7e, + 0x59fa0f64, 0x36bd559d, 0x6f4216a7, 0x876f1473, 0x155d9fc5, 0x3fe0ec98, 0x54ebd184, 0x2e3ac1b8, + 0x7963ed13, 0x0b588615, 0xc6439370, 0xaba86e4c, 0xe2021b7d, 0xba1a3706, 0x4db0db88, 0xebe725b9, + 0xb9018329, 0x48656a99, 0x13ea4ebb, 0x901bc179, 0x8cdd1008, 0xe562b875, 0x7df68d68, 0x6f5aad96, + 0xfe2f49e6, 0x9a223b80, 0x26eb27bc, 0x61e0203a, 0x11dfb412, 0x1e313167, 0x82420535, 0x103dec79, + 0x2d3ed8c4, 0x9eb1e236, 0x924676b8, 0x83e42e05, 0x2ec51b54, 0xe93a4e60, 0xcc226c36, 0x0b63777b, + 0x8af16453, 0x649bd333, 0x0744f0e2, 0x06710ae3, 0x8d2dd7a3, 0xb7b26566, 0x59ca6011, 0xf1772582, + 0xae8f5b19, 0x04828b4d, 0x7cc1ac81, 0x9a19f30a, 0x9ccb6bd2, 0xc69101c7, 0x2636e8dc, 0xae059cc4, + 0xd8513767, 0x8c55acc7, 0xe7218f2e, 0xc60a6619, 0xb136da48, 0xf2d4e9ba, 0x8b31d974, 0xe2ac937c, + 0x935f3c13, 0xc3b7f486, 0xf68c4082, 0xdcdc0a9c, 0xbf9a46dc, 0xd9c2af02, 0x981ef7f2, 0xc9bde246, + 0x80b341a8, 0x8f3a544a, 0x7e7c9c4e, 0x47760741, 0x0cc4875d, 0x85fc2c8a, 0x8663298c, 0x0cb1a141, + 0x6bbf5332, 0xd7b6524c, 0xfe5117b6, 0x91f65212, 0xc18d686c, 0xac64d47c, 0xa6d9ea1d, 0x1d8c7769, + 0x26bcd85c, 0x761959fb, 0xb1fef2f3, 0x43befc2a, 0x298bd885, 0xdfa3ea72, 0x7caa96e8, 0xf5256449, + 0xe05f42c4, 0x8a511cb3, 0xb6adc82c, 0xf95793b9, 0xf3d758a3, 0x07c23ca4, 0xa248f960, 0xcfd73a70, + 0xf39e0691, 0xf71b71ee, 0xf30678e6, 0xac108c18, 0xe645fefc, 0x67f823d1, 0x99193982, 0xc82e0748, + 0xa11940be, 0xbee62c1d, 0x55103f84, 0x281935ee, 0x1ec5e5d5, 0x1e323c2b, 0xf538aaa1, 0xb6a33da1, + 0x48d3c678, 0x439f2f3a, 0xaee13867, 0x0991109a, 0xce396060, 0xf49b1a51, 0xcb1f6eb2, 0xb2da93a6, + 0xa1d1ccb9, 0xa933e714, 0x6633131b, 0xd5220883, 0x48ce7118, 0x62787af3, 0xf53a9504, 0x4c38d4b3, + 0xf27ffec4, 0x979fd102, 0x63cd5c32, 0xb31a206d, 0xb8d00242, 0x9c6b852b, 0x884a4b73, 0x7392bcfa, + 0xdcbf6bc5, 0x00784702, 0x30f97710, 0x2646f0ea, 0xd455554e, 0x2cdeab9c, 0x6aed26cd, 0xd5853c53, + 0xdae1a633, 0xcf15227b, 0xca009fe9, 0x8ecdd26f, 0x461975f6, 0x0db2c557, 0x44ac0213, 0x0d0d63a6, + 0xa64da839, 0x5a289b60, 0x07ce959e, 0xdd655a08, 0x7b7aefe8, 0x5a5a21cc, 0xff1ddfc9, 0xb44885f9, + 0x3f017d40, 0xfeb3181b, 0x3300df23, 0xbcc75bac, 0xb1053d02, 0x904106c3, 0x7da8511f, 0x6890caf2, + 0xdaecdc7c, 0xc9d65f5e, 0x5008b57e, 0x60546576, 0x81bd5e9f, 0x821ab7fe, 0xc7b3fdc7, 0x42745627, + 0x9afb47ad, 0xec4f0dcb, 0x54898593, 0x9d3a4f65, 0xca0c8db1, 0x263136ba, 0x7ac9397a, 0xa1065a08, + 0x0ffb1489, 0x0c53dce8, 0xde4aaf37, 0x0a6f902f, 0x91134d61, 0x38ae641d, 0x22b7b021, 0xb067e9b0, + 0x7de9c9f0, 0x7ed0ce99, 0xe06fdeb8, 0xbb1a4e51, 0xa6b5ec04, 0xd06d5b3e, 0x9a89b129, 0x7e148b01, + 0x61c61819, 0x93f6b265, 0x6c6995bc, 0xd1d147b1, 0xf1687eab, 0x134445d6, 0xdaf07150, 0x19abb685, + 0x5462d7d6, 0x30400285, 0x49fc2201, 0xbcb1b1f8, 0xe801098b, 0x0f6fcf70, 0x37db3ec0, 0x25422f75, + 0xaabb23d0, 0xb5c08a43, 0x40107e07, 0x5aa9bdb9, 0xd470e576, 0x3043337a, 0xb75b81dc, 0x20f12a9d, + 0x27783a16, 0x23a2395f, 0x87949f3c, 0x1247fc95, 0xe55958be, 0xbd1b4de1, 0x785b8088, 0xd4a213bb, + 0x8bb80909, 0x7a25f87a, 0xb3432f5e, 0xf964be1d, 0xaeb8567e, 0xc1746267, 0x2523af32, 0xae1b89f4, + 0xe966672e, 0x9f187eb5, 0x53c15e98, 0xc4744a13, 0x1a930922, 0x18270765, 0x06806b3c, 0x30f0bb86, + 0x5ef191f5, 0x47feff12, 0x8ceb6cf8, 0x1180842c, 0xe2591e09, 0xce22a41d, 0x32f293d3, 0x7532c04b, + 0xcdb426ce, 0x401c0927, 0x720d3610, 0x9284e34a, 0xece30592, 0x94b337bf, 0x83207ec6, 0x2d3f573e, + 0x96caf4ef, 0x6168615f, 0x35ba2a52, 0x1b316117, 0x81af960a, 0xb7e62304, 0x8f7781a2, 0x32a398b3, + 0xb8decb23, 0x0e6b5413, 0x3eeee73d, 0xbfcc44e2, 0xef7a6d6e, 0x558c8286, 0xe8615f23, 0x1575af52, + 0xd0ff1ec4, 0xd2863a19, 0x46e3f380, 0x4ba3aff5, 0xa3f15d4a, 0x77f5cf52, 0x62405a90, 0x5ab3ed64, + 0x179d14f0, 0xc662b05f, 0x628929aa, 0x94490c61, 0x9a7f6846, 0x87596805, 0x4509ffbe, 0xbafc9f68, + 0x8ba75e06, 0x985743da, 0xa7d4ef22, 0xa4df2b39, 0x483df063, 0x4876e67d, 0x68e1eda1, 0xc8519171, + 0x9222be0e, 0xc2e089a7, 0xfb418b19, 0xe8eb418a, 0xed484c28, 0x4abfbdc1, 0xf0b49d45, 0xbfe64d7f, + 0xb0f01d41, 0x2a56349d, 0x2897f86e, 0xecd0b571, 0xe8f41203, 0xcb1b2425, 0x395916d1, 0x1c1f4b0c, + 0x185c5766, 0xecb6fe35, 0x526afd6e, 0x1eed683d, 0xb7c5f187, 0x22c5c08e, 0x50df360b, 0x3db6e76c, + 0x1c9c89fd, 0xbd299985, 0xb74a6e64, 0x5f32108b, 0x14b9b93d, 0x51789eb6, 0x9f5814ea, 0x27db5103, + 0xbaafeeb8, 0xc76bdc6b, 0x03fb004e, 0xf218bbd6, 0x706b7096, 0xe1275dd0, 0x21d67724, 0xd7b438a8, + 0x26f7c87e, 0x87ed4324, 0x6d6e7f61, 0x04049c49, 0x1fd40945, 0xf8fcb265, 0xef16dae0, 0x1c535db6, + 0x39dcf599, 0x46f42b2d, 0x24cdf774, 0xd9f9b349, 0x5774d4ed, 0x38b7d4c8, 0x5010c9da, 0x2b456e7f, + 0x6cc5ca51, 0x12b647ba, 0x38aa4db8, 0x7d99132a, 0xfb14b906, 0x77f34668, 0xa21ffa7c, 0xb6e0cb3d, + 0x9339bb34, 0x8f6048f9, 0x2b79f564, 0x100c03d2, 0x6ae6f788, 0x29dc0cde, 0xbec65b7b, 0x40ceceaa, + 0xe6f1c8d4, 0xa7144238, 0x5ebcbcbd, 0x323751b4, 0x9e6bd942, 0xa0fa3ea8, 0x5512a3d6, 0x6c1953a9, + 0x4f93cd58, 0x4ecb0192, 0x098dadcb, 0xf1634aa1, 0x152e1827, 0x9e638c50, 0xe8f92cf4, 0x2daf8e47, + 0x4971ed93, 0x467e24e0, 0x195e1d93, 0xd97ba74a, 0xc75afb38, 0xc64f1a84, 0xd12cdd15, 0xe2541641, + 0x97f01bb5, 0xe29e8af4, 0xe01f2545, 0x16fcec75, 0xa8f91d07, 0x5edc644b, 0xcf596d6c, 0x955484ed, + 0x7cede8d6, 0x134989bb, 0xe1696d00, 0xe3813eb2, 0x7d593a80, 0xdd26af07, 0xbc8ff9d8, 0x0c3ea183, + 0x573ff10d, 0xd0b03047, 0x744bffc8, 0x4f55c077, 0xc785efa1, 0xec5dcd7e, 0xd5d89d6f, 0xc07318de, + 0xd7946851, 0x827c188d, 0x7eb604ce, 0x0c35d326, 0xd4d03583, 0xf61e4f8f, 0xaf06d790, 0x3a6b69bd, + 0xc5365790, 0x9733cfd4, 0xf04c5c0c, 0xc913ef23, 0x7cd4a76d, 0x8aec1be6, 0x315fea8f, 0x37899071, + 0xb1cc3e0e, 0x47a725bd, 0x0bf48b31, 0x24f7e664, 0x699d349c, 0x06545a5f, 0xe82b75a7, 0xdbc1eeea, + 0x297bbdf7, 0x0dc23ab8, 0x2df4a5c2, 0xcbf2cb06, 0x625ef308, 0xdad4883f, 0x54f1d85d, 0xd63744f9, + 0x9d77064a, 0xe33a72c5, 0xcbda263f, 0xdf024033, 0x3a0c31cd, 0xed47542b, 0xa2782054, 0xc96bf02f, + 0x25773eec, 0x138f184c, 0xf6e3dd69, 0x0aa9b1dd, 0xd162871a, 0x3d5a3797, 0x38a2f1fc, 0x4008d1e3, + 0x46bd7b05, 0x6b48f5c2, 0xdea9dc04, 0x0d901674, 0xc77277ca, 0x13c1d05a, 0xafb43234, 0xf936d685, + 0x36a5b14e, 0x75d068d6, 0x34fbdea7, 0x214252b6, 0x7e046c4e, 0x4a1da65f, 0x1ee66066, 0x18ef2c64, + 0xc36021d2, 0x876d44f5, 0x44b47800, 0xbe603dbb, 0x350e5329, 0xc48b2b94, 0x26e8ed4a, 0x1c5d71d4, + 0xa0b0608e, 0x2251edad, 0x2554631f, 0x736c38a6, 0xea1de918, 0x98d5baeb, 0x0b39859e, 0x0e25461e, + 0xfb60e24a, 0xbc6cf1b1, 0xc0ce27a9, 0x78d9eb0c, 0x1cd8035a, 0xaf4be23a, 0x707515b7, 0xb029e1ef, + 0x06008685, 0x64432c2d, 0x92bc7609, 0xda3fc710, 0x5644f826, 0x8891688b, 0x2074e126, 0xac05b815, + 0x4f829c38, 0x1c739d5a, 0xd308abb5, 0xfd0a8c9d, 0xec9d21b2, 0x591c234c, 0x68145ec0, 0x2711af55, + 0xbe96fa6f, 0xf9a13535, 0x9ce1bb44, 0xe756be0a, 0x74cfab4f, 0xd2973340, 0xee2c7755, 0xe99b05bf, + 0xfd96e7dc, 0xf847501c, 0x28fe3bf3, 0x0589b8f9, 0xf01c4b11, 0x96174739, 0xb15c8a77, 0x32d60c82, + 0xff98363f, 0x7b1352fa, 0xf912f3fa, 0x2ff7602c, 0x1947233d, 0x0addc60c, 0x944eb3c9, 0x763c020b, + 0x384660e4, 0x742490aa, 0x4e184ecf, 0xc01d8de4, 0x45dd453b, 0x8211cd80, 0x4048092c, 0xbde2ce91, + 0xad415270, 0xa6dc23c4, 0xe7ac0263, 0xe5d34b95, 0xe50779ff, 0x117758e6, 0xc7222667, 0xd4744851, + 0x3982ec02, 0x3d5787b9, 0xa3916007, 0xc244b9c7, 0x743e02c9, 0x169d89ce, 0xc6e18752, 0xde033a1a, + 0x5da1eb64, 0xf3abfeca, 0x734802f0, 0x80a1d8e9, 0x1f3b2536, 0x7f444a5c, 0x6b430b72, 0xfbf61779, + 0x3b808942, 0x37b019a9, 0xaefb11e7, 0x79d00905, 0xdc9a45ba, 0x23ca3ec5, 0x7725fb55, 0xfbd43df1, + 0xeda04567, 0x032b929a, 0x5afb386f, 0x3bdc8063, 0x9ee5f35a, 0xf913e6e6, 0x42da163c, 0x6971a628, + 0xcef9c0ca, 0x8e08cdb8, 0x1893b429, 0x5f3fd5ef, 0xceede440, 0x444696e4, 0x4d7ba771, 0x1a54a97a, + 0xd617e357, 0xe5ecf68d, 0x974c5b9b, 0xd61f3b33, 0x8f570048, 0xdefc53da, 0xf2633efa, 0x32c1509f, + 0xa384c1be, 0x7d99c841, 0x9724ad7c, 0x8e2aa6de, 0x4f1dbac1, 0x77ad4069, 0x4c45e445, 0x186daea6, + 0x3bcf0f09, 0x66f561cb, 0x0aa5f952, 0xf6d325a8, 0xd5ba5422, 0x2bb8513e, 0x543d00de, 0x996460b9, + 0xf25f32cf, 0x34a70454, 0x56065605, 0x3ccd95ae, 0xe06df779, 0x9f81540e, 0x4c3e0665, 0x96b70f7f, + 0xfe3e9b52, 0x4271692e, 0xa92bbc1a, 0xae89b515, 0xb6eabd87, 0xb083e806, 0x811998de, 0xc79a56e4, + 0x58eb302b, 0xddc9b6b0, 0xd4234c93, 0xd2c1b15f, 0x8e0e62b6, 0xf6ba64dd, 0xa795ef71, 0x61fcfa8a, + 0xe07b8f19, 0x9f293d19, 0xd1599fea, 0xc6ace76c, 0x510a2ba2, 0xc5496fa8, 0x7f4ba4aa, 0x17888e9d, + 0x60c0545c, 0x6d8ccf33, 0xc580082f, 0x1642246c, 0xc4a58107, 0x899e9300, 0x9749b3a2, 0x83724fe8, + 0x4e0329b6, 0xce7e2be1, 0x64a74e93, 0x60574ac9, 0xf584b8b1, 0x4f0324f0, 0x75f59af0, 0x42f49639, + 0x6af1c20b, 0x49e706c3, 0x3678c968, 0x6380b369, 0xa3df3568, 0xb80ebc71, 0x492eabf6, 0xa9219bee, + 0xd6bf2500, 0x269c7ff2, 0x82897b3e, 0x7f958432, 0x53771fcd, 0xdfd551f5, 0x8a9f75ce, 0xcb0ed50c, + 0x630e744a, 0x58a4ec79, 0x0d42d757, 0xf0fc6317, 0x0d0a9680, 0x418831e3, 0x57ec241e, 0x4d409c77, + 0x9e4b7334, 0x55f67bb8, 0x14ba7345, 0x915c9fc9, 0x0f62c118, 0xb5744c82, 0x85fc186c, 0xbbf80948, + 0x272508e0, 0x003dc461, 0x8b80dcba, 0xced2dafa, 0x95d0dad2, 0xa1e5e0c3, 0xe89b0ea0, 0xa4ee919b, + 0x9238842c, 0x625dfc5c, 0x46c14a1f, 0xecea7d0b, 0xb7fb5860, 0xe90bff70, 0xd0922e68, 0x6ca74717, + 0x1c4da67e, 0xf29b3b55, 0xcea7274b, 0xa6426722, 0x6136b6e5, 0x45ba6f7d, 0x6df6b83e, 0xc526f546, + 0x04b15a50, 0x72f9e8c0, 0x3d573482, 0xe3d95ff1, 0xbad91205, 0x7c23ae70, 0xdbd3a244, 0x21fa97c3, + 0xa81488a6, 0xb336ea92, 0x44e6a7a0, 0x652bffd2, 0x7ace0c64, 0x8ec91641, 0x6002fb1e, 0x3822caf2, + 0xcfd4e85a, 0xe0e98592, 0xf63c3dc8, 0xc1a901ae, 0x8182cdfe, 0x79c5cb3b, 0x19141b3a, 0x738539f3, + 0x021216e1, 0x3ce38534, 0x127953e4, 0x3b91a780, 0x8c7633a5, 0x7ca42334, 0x3063dac5, 0x0dcb548d, + 0xee22b703, 0x60860781, 0x505f9b78, 0xa62b2834, 0x9baa63df, 0x464411f1, 0xbf431172, 0x0ed3d715, + 0xb575845e, 0x6800c14b, 0xa3388f11, 0x227a12ff, 0xf177fd02, 0xc5051b93, 0x7afd5bb1, 0x3e6d1bc9, + 0x63ae22b2, 0x1ed70de4, 0x89bd808f, 0xc3f1c7b3, 0x144f4e38, 0x5cb7c759, 0x17fb0bbe, 0xbe6fdb31, + 0x5f3deb24, 0xd3deffb0, 0x266f33e0, 0x091d590b, 0x7f31305a, 0xb3879d19, 0xd6de9c37, 0x2e1b6f6d, + 0x2679d6f6, 0x6b37ebc4, 0x879777a9, 0x0133b896, 0x2b95c8e9, 0x2e6f2e80, 0xed56cac8, 0x53720e6b, + 0x8b91866d, 0xf4acfeae, 0x19957ea8, 0xe1d7fbc8, 0x141704a5, 0x8d8f2a05, 0x28467bb7, 0x2575915b, + 0x077b3df7, 0xb17e5ac3, 0x44a2ce99, 0xb65246af, 0x492adebf, 0x8f7710e6, 0x9f2b046a, 0xdcf687db, + 0xa0d189d1, 0x7d1a98d5, 0x7330928f, 0x995ab042, 0x81e85173, 0x27dfc92b, 0x6e74b36e, 0xe6bb0e75, + 0x698804f8, 0xaa9fb96c, 0x56a5b345, 0xa85ae9c8, 0x072f6113, 0xde1eec07, 0xb9c71aae, 0xf090b4ab, + 0x17be1127, 0x6641dd3d, 0xa01decfa, 0x54522e70, 0x21d9e45b, 0xd392a11c, 0xc6d85f6d, 0x569808b7, + 0x04fa8a31, 0xcde91444, 0xa943ce21, 0x57923bbe, 0xb8c1946b, 0xe3c79aba, 0x29aa705f, 0x1bff230b, + 0x9892b0bb, 0x11779cca, 0xb3d780dd, 0x5c5a74d5, 0x682927c1, 0xe8177e96, 0x860ebc4f, 0x71acde40, + 0x05ef466e, 0x5cfd106e, 0x27db997f, 0x96ac6f00, 0x5023de72, 0x47d1b3cb, 0x7b0b99c5, 0xa67ba0b2, + 0x8ee9fe67, 0x8812cd27, 0xd9afe755, 0x6484d40d, 0xd8a619ba, 0x800d5b28, 0x685d84ef, 0xc61026ad, + 0xc1aebaef, 0x36da557c, 0x1f5b9ca8, 0x9185ec1a, 0xa072e6be, 0x0131a8e6, 0x4b63c51d, 0x318690a8, + 0x04a8e35a, 0x08ded501, 0xc83344b2, 0x0d7e706c, 0xace6adf2, 0x073f34e5, 0x0555fd53, 0x5f7b0950, + 0x53f49d94, 0x478438c4, 0xd049b3f1, 0x9b4d52f5, 0xc67ec9cc, 0x709b33f0, 0xb092c99a, 0x140d093a, + 0x49f9eedf, 0x3476fcb8, 0x4848a351, 0x7e95b919, 0xe89db2b7, 0x88b8eb2d, 0x4dec4160, 0xa6fa1bc0, + 0xba70224c, 0x7761a0ab, 0x77661b6a, 0x6cbc9935, 0x88579e8b, 0xe351fabb, 0x920daf68, 0xa7037f1e, + 0xa208656a, 0x0e1614e0, 0x18cdb952, 0x963d972b, 0xd45c9953, 0x3002c67d, 0x89e0eb94, 0x877a953a, + 0xf228c137, 0xb4327b77, 0x3ccc8413, 0xfb9963ed, 0x4d2e17c0, 0x8e7fd630, 0x082f7ef6, 0x0859f250, + 0xbcd3b415, 0x21d26b72, 0x05dd2c51, 0xcbf0ff34, 0x5bc5111e, 0x8779e60f, 0x9bb339ca, 0x94057fc1, + 0xc9245e46, 0xe574c1c0, 0x9d40ffdd, 0x016edbff, 0xcf6e4462, 0xeff8db62, 0x94fb9bae, 0x42c347a8, + 0x67bdce6e, 0x4f96258e, 0x2594da99, 0x4763f341, 0x8cb24e42, 0x3e5dfbd2, 0x2935c4d5, 0x2cc59d2c, + 0x2926d7e5, 0x9e85bc37, 0x488774a7, 0x25c2a43b, 0x2da707a9, 0xeb5fecde, 0xacb1d736, 0x6964c09c, + 0x22e75ee5, 0x28692177, 0xb70ba5a7, 0xbaf2ffff, 0x9f421370, 0x4af771dd, 0xda39016f, 0xf957a1a1, + 0x20386db7, 0xcbc51e4c, 0xd70375eb, 0x28d824f3, 0xf7f66bed, 0xd823be0d, 0x7627e302, 0x48eeecbd, + 0x51ed9f95, 0x00f243ce, 0x9da02e4e, 0xe12bd0ab, 0x1f258c15, 0x526bf7a8, 0x96e8b0f7, 0x72026049, + 0xcf7a0265, 0x1b3b313c, 0x572cacab, 0x58fce41a, 0x6f8ef89d, 0xdf800c91, 0x6696db6d, 0x97189cf2, + 0xb124670b, 0xf58b3fa7, 0x61cd7132, 0xd4024e88, 0x0bb6bae4, 0x88d090ce, 0xc6f39987, 0x3dfd3e72, + 0x7a143350, 0x6be9b59a, 0x998ecbd9, 0xe06cedfc, 0xb315d3dd, 0x2229a2ea, 0x1ee5e198, 0xd5a6794a, + 0x39729dbb, 0x1be83173, 0x46e070ca, 0xb8e9d1c0, 0x301a7d32, 0x4afd44c9, 0x26e7e406, 0xd02c16c8, + 0x3bdaba1f, 0x1a3e6b0e, 0xf048428a, 0xd803223b, 0x4c483dbb, 0x963a7a81, 0x6c24c478, 0x654214f4, + 0x8e97c40c, 0x7af6d1e9, 0xbc83ad22, 0x8f1dec94, 0x3ffb3171, 0x49668375, 0x5caa37cf, 0x72b0467b, + 0xf5477595, 0x7078426a, 0x7978c4bf, 0xc32355cf, 0xf702e464, 0xf3562e16, 0xde45f488, 0xe40d0d7c, + 0x0428c4a6, 0xa0d056cc, 0x352e853a, 0x2080342f, 0x2e46b2d1, 0x42e23569, 0x6d1ad61e, 0x6a7d4dfb, + 0xa5c6078a, 0xb2d14c07, 0xd8c87e8c, 0x503daacb, 0x4e116d7b, 0x34d67e89, 0x98d01805, 0xd7e91ee9, + 0xa90878d4, 0x3677fe3e, 0x36c0727e, 0x547960ea, 0x2064f763, 0xb2f76db1, 0xe249103b, 0x6b90bd4b, + 0x75db87d9, 0xc1a55e72, 0x6bceb5f4, 0x03b273bf, 0x3d3219c3, 0x59801f3c, 0x6227d324, 0x793b359d, + 0xef853358, 0xa9ffeb74, 0xfcd843da, 0xb5053acc, 0xae50c945, 0x8bf660f2, 0x486e1d9e, 0x5ab1f348, + 0x92d69c17, 0x5c26fb98, 0x83f3a39e, 0x1d75f579, 0x5aebd173, 0x4e7340b6, 0xe893c2d5, 0x7ae09ff1, + 0x0fededbc, 0x88a7d3e1, 0x4b02f9d8, 0x0ce42777, 0x6aa9595b, 0x1b164fd9, 0x0247f6bb, 0x09a8297b, + 0xacaf5999, 0xa4b77fcb, 0x18e71706, 0x9a3a0c2c, 0x954e1594, 0xe62d4133, 0x55e226db, 0x0cccc5f1, + 0x2c1013c4, 0x4fc7e617, 0x87da6b98, 0x393e33c9, 0xa9f8ee5f, 0x5800f6b6, 0x8ebdddea, 0xe0183c80, + 0xef6d8bf3, 0x0e10a9b8, 0xa77b5821, 0x9a5f1a71, 0xd2da33c6, 0x9d1fd3df, 0x60bd9923, 0xec3d9c11, + 0x675df03c, 0x0f00f79b, 0xf6bb0645, 0x3f1f94ea, 0x9a43adb2, 0x5db22b56, 0x10093265, 0x4fc1bcda, + 0xe5cb3c44, 0xe44f461b, 0xe22d0087, 0x60e38a01, 0x98e48d0d, 0x0f197598, 0x887b43da, 0xfd41b0fa, + 0x26f71077, 0x46e8d9c1, 0x727e7b07, 0x165996f3, 0xb98dfcdd, 0xd7d5cfaa, 0xc367df64, 0x81a76659, + 0xfa2a3bbf, 0xdc6e928f, 0x570faf17, 0xb4796002, 0x922267f1, 0xc82bce5a, 0x8a1e717a, 0x0e96197d, + 0xa3128c7c, 0x0f2b2c81, 0x4c94e72a, 0x862fec13, 0xe89bf379, 0x7d70c0da, 0xe587eefa, 0x1a347a16, + 0x78eadf71, 0x8f905597, 0x6b60dfc6, 0xd497c3cf, 0x375dce58, 0x6db16795, 0x5947f566, 0xca487faf, + 0x9fa5be25, 0x52071fd2, 0xe3ac7f55, 0x11e50a9f, 0x9fdb94e0, 0x15a1046e, 0xfb24995f, 0xf24d47af, + 0x41be20ba, 0x36e73655, 0xee755b9e, 0xd4db4d78, 0x26f5c443, 0x99f44eb6, 0xc4b33f8d, 0x6431bef7, + 0xeed8c9c5, 0xa75f8408, 0x63aa3711, 0xf72c0ccb, 0x5c868732, 0x782b1b10, 0x066d52ff, 0x06797a09, + 0x0f69d792, 0x896e010c, 0xd163117a, 0x13e4b415, 0x40991e7f, 0x97772d57, 0xde1f6762, 0x7cfcf7b4, + 0xd5bf032c, 0x690154c0, 0x90ea7460, 0x9abca78b, 0xef159a9e, 0x782cf8a0, 0xdd7891c2, 0x02dee439, + 0xa0db9b2d, 0x760e8271, 0x0d1293bc, 0x2d1b4143, 0x03957c34, 0x01914549, 0xbd1b4c6d, 0x6465879c, + 0x514d694c, 0x0d037113, 0xefd979f2, 0x3695ec73, 0x533cc86e, 0x1dac1c29, 0x023cdac5, 0xfcfce832, + 0x3facbf2f, 0x20177b86, 0xb1c3bc4f, 0x101a8165, 0xcf5c430c, 0x5854dfcf, 0xa59fd968, 0x72553975, + 0x8dc8e2a7, 0x7e08ac81, 0xc8c47526, 0xc2260e4b, 0x1bf55355, 0x4a1e8a6f, 0xe0460dfd, 0xda2bf87e, + 0x17979f3a, 0x48dac572, 0x100ad866, 0xd8fb41c3, 0x4ed9f6c9, 0x1ec7f7f4, 0x675a5889, 0xb61debdf, + 0x8800d144, 0x60fd669d, 0x8daff557, 0xdb5b614f, 0x276f6665, 0x58453534, 0x5cb407f5, 0x5c251151, + 0x9d5ddc1a, 0x0b33528a, 0x3aebff78, 0x424b8c54, 0xb7b5ca6d, 0x366ee32a, 0xbcc0effd, 0xa87f6836, + 0xff7a9695, 0xaa2ae1a8, 0x01e82e97, 0x8c64479f, 0x650544b1, 0x0bac49f2, 0xf7ebd31d, 0xf5a1ad9e, + 0x41890151, 0x22116222, 0xc8b3c0fc, 0xe99133b5, 0x1ca19944, 0x6390e6e6, 0xc41b1484, 0x2db3e67b, + 0xe336803e, 0x9653fbf2, 0xe4c431b1, 0x4c3b0bba, 0x8f8bb833, 0x293e745f, 0xb5c08fdc, 0x568482b5, + 0xa78d2e7f, 0xf595d965, 0x40b71588, 0xd9f3bee8, 0x6f421e51, 0x1de16633, 0x317f4909, 0x205becdd, + 0x5adf3862, 0xd923d31e, 0xb593cfb1, 0x3c650006, 0xf5ec5c7d, 0x8d736e39, 0xc662a2d0, 0x9c1c5020, + 0x1a0af22e, 0x4f6b29cc, 0xad986ff0, 0x73cea049, 0xcf2ee0f7, 0x0609033a, 0x1601cbb1, 0xf09e4216, + 0xd6574a2c, 0xc1d211f8, 0x38e18e46, 0xfea08671, 0xb3e93d54, 0x001271ec, 0x2b502306, 0xbd544ba4, + 0xd1ee8f37, 0x548c2e1e, 0x6930e750, 0x14470a89, 0x71da3fd9, 0x9e7fdd30, 0x66d2a716, 0x41ebf9f0, + 0xd588b0b0, 0x384d85f5, 0x23180b15, 0x2ca30600, 0x869c2656, 0x9b3e0587, 0x9b77c40c, 0x2239857d, + 0x0b2aeec8, 0x8a96594c, 0x4aedce6e, 0x60210bbc, 0x254a5675, 0x7c67e7fb, 0x5ecc69d6, 0x0f98fc10, + 0xc983f81d, 0x92a31f50, 0x5cdadf7a, 0x3c1a870a, 0xb08a6fbc, 0xa2061d17, 0xa1b93d9a, 0x96595a84, + 0x55b5f829, 0xa681afdf, 0x9e298285, 0x33dcb8ba, 0x12c41eca, 0x39c1bfc3, 0x470052b7, 0x1d0de5d1, + 0xeff60563, 0xcc29b31e, 0x05464cce, 0x217864d4, 0x4ab3b7d5, 0x02eaa28f, 0xc8b53dde, 0xea7a283c, + 0xeec4c834, 0x14d944b3, 0x0a19e109, 0x2cdcb27f, 0xa4c9590a, 0x853edd56, 0xa64cadcb, 0x02ccbf92, + 0xcb71a0b5, 0x6846a050, 0x1f0c14f6, 0x716e549d, 0x1acaa72d, 0x6d230174, 0x2cacfbc4, 0xf5983d66, + 0xba053df4, 0xf1b31d5f, 0xc2633ca5, 0xb1872407, 0xcb3b4512, 0x84fbc311, 0x13831401, 0x167fa160, + 0xdbb9dd1a, 0x43e32002, 0xeeee2a81, 0x2a756304, 0x6ce9653a, 0x9f8a7a44, 0xab5b0b0a, 0xfcb7e496, + 0x82cf1598, 0xcc0bfe13, 0xfb7878b3, 0x62021297, 0xbd9d1dd3, 0x03e179eb, 0x802bd5d1, 0x75a8837c, + 0xdca7d192, 0xb50c0dee, 0xec8c44d1, 0x0183fef5, 0xa3983381, 0xcbfb7568, 0xaaaabd74, 0xc16ac0ec, + 0x587c530a, 0x81e08960, 0x6d01be99, 0x6624a05f, 0xb7773dbe, 0x5ec99847, 0xebc5db2c, 0x90037cab, + 0x3fbf40a6, 0x46b5cf1d, 0x080666fe, 0xba00710b, 0xc39e18ed, 0x1fc53b8b, 0xe0d2de6b, 0xc529a805, + 0xe8802e16, 0x89010bf5, 0x5d1f3ef2, 0x5b552d17, 0xcdc72d2b, 0xf6b125d6, 0x52e00953, 0x1095cd06, + 0x9b7f1f51, 0xb374643b, 0xc7a1f3e5, 0x9c517ef8, 0x194d4566, 0x6e90cf8e, 0xf2d28a22, 0x8b10e8c8, + 0x8941b466, 0xe234f569, 0x98d3e544, 0xcd5de117, 0x40dd75a2, 0x61c8df46, 0xa9b1a49d, 0x560a783a, + 0x9f481290, 0xe5b7ce1c, 0x1b111a69, 0xd7220f8a, 0x980b350b, 0x47a5e82f, 0xe4835326, 0xf3376034, + 0x4ddef385, 0x3520a581, 0x4ce74936, 0x2c00a969, 0xced88d56, 0x0cc5b59f, 0x0984bce2, 0xaea1c22c, + 0x9a39d3b6, 0xc87a49d4, 0xc0d73885, 0x99e2da0b, 0x401ea68b, 0x4812db37, 0x8340c412, 0x8f7afa00, + 0x8ba89490, 0x326db715, 0x3559cefb, 0x7e397718, 0xf669af89, 0xf7ffd061, 0x4f84452f, 0xae931e1e, + 0x6fb5cb57, 0x25872369, 0xfa4f35c6, 0xe53bd110, 0xb4930653, 0x8fd67e5b, 0xcd0a96e3, 0x7935f576, + 0x8ef8c583, 0x749e8589, 0x9d139476, 0xc3a8746d, 0x91b05ede, 0x9ceacd29, 0x714474d9, 0x67566a08, + 0xd8695661, 0x8e1feefd, 0x9cd63617, 0x2df074a3, 0x035958d6, 0xc6eefc8e, 0xd9f50aab, 0x86bb7526, + 0x8f6f54a5, 0x3df66099, 0x3f32deb3, 0xd585eecf, 0xf851dde0, 0x05b70487, 0xd7a35d22, 0xaf5c12bd, + 0xb11d0a92, 0x92d76ef6, 0x95d30b12, 0x34cf1329, 0x1f3eda2c, 0x567ebaa4, 0xbe9a892c, 0x4d9e6cbc, + 0x344cfd61, 0x3e1923e0, 0x8bf9086c, 0x8e7ce0db, 0x1c73ca91, 0xf4fbbdfc, 0xabbe5ffb, 0x1fae0cf6, + 0xdb4278a7, 0xe39fa084, 0xb180fd60, 0xaf966d53, 0x0cee86a7, 0xb539a37a, 0xe7afc113, 0x9f8c5708, + 0xa43105a2, 0xdd17cde3, 0x35f06c3b, 0xd1147093, 0x87c4fcb7, 0xd81744ee, 0x50b2297d, 0x88257206, + 0xee1c99d8, 0x3741bdf3, 0xf155543b, 0x0bb000a3, 0x50b4ea92, 0x4cb7edef, 0xa3d83a39, 0x8358c6b5, + 0x5fca686e, 0xa70230d4, 0xb602b1d8, 0x8ff6da86, 0xd0d0115c, 0x5846c2d3, 0x2ca586c6, 0x907a06df, + 0xe20465eb, 0xcc3987fe, 0xca84830d, 0x545d1fcb, 0xb0e1ed99, 0x9910610a, 0x898c48ad, 0x052a25e8, + 0x4a77cd3a, 0xd3588aed, 0x2578386b, 0x81767f9f, 0x6b4f76fd, 0x12104096, 0xf094bbc2, 0x42aa6d23, + 0x98b3ea58, 0x50971be5, 0x047a39a5, 0xf686f5df, 0xd405c297, 0x3664d28e, 0xd9666dae, 0xef74a775, + 0x982142af, 0xc8b60e79, 0x34843b1f, 0xf1e9fe2a, 0x7c0cb9c3, 0xaecba345, 0x4f1b6386, 0xf42bf487, + 0xf78bd769, 0xcb7e4692, 0x7f003f01, 0xf67ab150, 0x0c5bd77a, 0xd42476aa, 0xf587949a, 0x37c1777b, + 0x1076b659, 0x514339e8, 0x8e233a4b, 0x706f6568, 0x532eb226, 0xa2976ced, 0xd6d2483e, 0x668fc455, + 0xc2f01221, 0xcf0b81a9, 0x74cfa869, 0x06618980, 0x566c7a4b, 0xc2c7a378, 0x9d6f66e2, 0x0692faa6, + 0x4df2defb, 0x7a562496, 0xa6578c55, 0x31b49d7a, 0x1bd8d299, 0x27aada61, 0xfb6e81e5, 0x97860f64, + 0xafd27d90, 0x2be4d61b, 0xa3c9d19e, 0xbf6476cb, 0x699a7365, 0x64913b83, 0x40ccd954, 0x52bf7d16, + 0x49205d69, 0xfec1d213, 0x6607e206, 0xb0071a78, 0xd803af25, 0x169912e1, 0x88682fd2, 0xccd6114e, + 0x5068e8e4, 0x5cea4ed2, 0xf19cba39, 0x71f5ddbc, 0x23be9f62, 0xbd8e21f4, 0xa7c17a6b, 0xbe364b1d, + 0xc8db4f3b, 0xf56dab5d, 0x7bd3b847, 0xb0fd4464, 0x2238fef7, 0xb983b05b, 0xd2349a87, 0x0b402d78, + 0xcf889175, 0xb69a3e7a, 0xf15e637b, 0xd0c3e164, 0x3fd21f52, 0xa636366d, 0xc83267e4, 0x123ba470, + 0x3e43494e, 0xf60c8713, 0x16069c0e, 0x2733dcb6, 0x2ecb481e, 0x700ed068, 0x53285baf, 0x0db005d2, + 0x98087b01, 0x1ba21a36, 0xab5701d9, 0x3a8c28b1, 0xf9d8ae7a, 0x115b8a6c, 0x0cd79b60, 0x560fe9e0, + 0x08fff64e, 0x82ef8ea4, 0x196047a3, 0x37d1f5d4, 0x3326094c, 0x18c80083, 0x899fa6bd, 0x0e46632e, + 0x28845260, 0x4cd400bb, 0xc795c33b, 0x3dd86570, 0xb562b120, 0x91528f17, 0xa5175768, 0xd7e05221, + 0xb41008f8, 0xf3202ad7, 0xd2bd13d4, 0xd8f26c70, 0x8c3e9b25, 0x9c5d3b49, 0xf78e2b31, 0x0812269d, + 0x0ea3575c, 0xb125de7e, 0xc48a8bb3, 0x5c48cf47, 0xdc6db203, 0xe29d64de, 0x3f87673f, 0x7ca70a73, + 0x42127e67, 0x4a8b3d65, 0x3a30073f, 0x7f3b3a88, 0x1b700283, 0xa942452f, 0xf5f60e7c, 0x0bce1d63, + 0x5a2e238b, 0xc098e1ea, 0x189f03cf, 0xd606a3b1, 0xd70b1999, 0x81edae92, 0xa188ed7b, 0x11a5cbaf, + 0xfe3afe8f, 0xae03fd94, 0x1680441b, 0xaa44a0a1, 0xc105c8c0, 0x36d15753, 0x5788c5ed, 0x87d7d890, + 0x3a308ee0, 0x2b6791d9, 0x211e65d7, 0x76b2b6a3, 0xff1be584, 0xf8e04309, 0xfe2228ec, 0x32df0ca4, + 0x7c21271b, 0xa5efeeb9, 0x3cd29c48, 0xf6972643, 0x5fecce2e, 0x96fcb757, 0x6f52b7e6, 0xa7c4fc20, + 0x9224929b, 0x1128dfdb, 0x5a4944c2, 0x7b20c7c6, 0xd58a0850, 0x2ac6b9a6, 0x868eb393, 0xefea5eeb, + 0x3c7d1f25, 0x375100a9, 0x5c151e78, 0x3ec2cad2, 0x52ab020a, 0xa84e3855, 0x0cca0ef0, 0xf2079f11, + 0x098d547c, 0x9c5be7d9, 0x306edf44, 0x1c473c9c, 0xefce6324, 0xf0f5e321, 0xfeadbdb1, 0x9deec8a9, + 0x3d2aa7c8, 0x4f3c4e13, 0x5a922ac4, 0x3b129a4b, 0xe29c293c, 0xa7eb7254, 0x252e1c01, 0xc70187e9, + 0x17612d6d, 0xefbd3ac5, 0x7879ce94, 0x69fe35eb, 0x3da3f493, 0x0b7c248a, 0xe1040b48, 0xd8d4389d, + 0x8720f398, 0x29c2fbe4, 0xec1b8835, 0x5b221d34, 0xdb35ba90, 0x53b34b64, 0x9e2a8718, 0xc5521b51, + 0xfead9af8, 0xdb985c7a, 0x46d78ba0, 0xd0c55318, 0x992737e3, 0x8e921493, 0xd5c08d8b, 0xf8ebf609, + 0xc7e0d01b, 0x5c9db5b1, 0x6d37b7de, 0x52714f3a, 0x099a3c9f, 0x7b71beb0, 0x107ea8cd, 0xe4d4128b, + 0x08eb30c8, 0x4843d4c5, 0xacd50951, 0xe723f568, 0x5ac20760, 0x826d9aea, 0x6d935283, 0xebb4de32, + 0x0f4b4154, 0x4a809c56, 0xc2096343, 0x702096f2, 0x4d234cb9, 0x268e69bc, 0xa9637f82, 0xc1a19108, + 0x2657fede, 0x35ee85b2, 0x7c1d7e60, 0xb8e7176e, 0xcb865cdc, 0xf618f4ae, 0xc8a5a66d, 0x760fc5b5, + 0xcc7bff45, 0x126c1feb, 0x81693e15, 0x5af7de98, 0x62d1deec, 0x14784fcb, 0xd46f18b7, 0xba6e58df, + 0xed24e92e, 0x6a517bc7, 0x056671a2, 0x87a45fdc, 0xe09a12db, 0xa514ee2a, 0x8c5a3da1, 0x846a2711, + 0x2c24b092, 0x2614b4e2, 0x2b56bead, 0x4b284a7c, 0x45a85290, 0x381ea42a, 0x422a79f2, 0x35e2f2fc, + 0xde57a61a, 0x838dfffe, 0xd90213c7, 0x819947ae, 0xfaab9e01, 0x696d001b, 0x0796f95b, 0xa258b02a, + 0xb693a6b8, 0x74687fe5, 0xf417f0ad, 0xff4a86e5, 0xa1d9cdff, 0x3102fad6, 0xf219866d, 0xbd599a66, + 0x48da3a8e, 0x27e2191d, 0x20ef1037, 0xe477d9f8, 0x7b87f977, 0x08962215, 0x5ca2b275, 0x426710e7, + 0x84b3af74, 0xcc9e9e2c, 0x7001710f, 0x86a390e9, 0xa2566505, 0x0ada08a3, 0x3e95c375, 0x7135a5e7, + 0x7547c111, 0xd4faba85, 0xcd074492, 0xe468733e, 0x5de45c2d, 0x5c6fa672, 0xca442daa, 0xd70326ff, + 0x7659fbf9, 0x7e0cd404, 0x87235bd4, 0x85225547, 0xece13c1d, 0x64aa52a5, 0x35e8b826, 0xf919b8c8, + 0x44604aa5, 0x424efb3f, 0xa7bab903, 0x951eac3a, 0x37f39643, 0xd0f37503, 0x8db9b5f6, 0xd2075060, + 0x63482fb4, 0xa7f87be2, 0x8a3829c8, 0x85dfb6bf, 0xaffe6f35, 0xa50b52ea, 0x811ae7ac, 0x4e31bb54, + 0x243c1a8f, 0x15f5a58d, 0xe83a789f, 0x74ba579a, 0x411a7feb, 0xabf66aff, 0xce2fc596, 0xc96885cb, + 0xa48b70b6, 0x2d0a1051, 0xee683724, 0xddcfc099, 0xac3de644, 0xb760e5aa, 0x42e075f3, 0x2eeb48de, + 0xb77eee9f, 0x99be7fdd, 0xe852dede, 0x8369cfaa, 0x7bd37397, 0xce450709, 0x159235e4, 0x7de40d45, + 0x1c2dba94, 0x38956534, 0x4dd580e9, 0x5a7a3614, 0x832ee7e9, 0x73172a74, 0xc46c2fc4, 0x6dd1983a, + 0xd5814e41, 0x522785d4, 0xea94e931, 0x4f4ac6d5, 0x48978832, 0xc22b6088, 0xa2abb562, 0xc9e69434, + 0x2a5f1b14, 0x43a76d26, 0x277a601b, 0x8fb12bb0, 0x881bef14, 0xeff8e0c1, 0x2180ad5e, 0x4c659acb, + 0x5981e744, 0x7ec4e63e, 0x4a94613d, 0xb565d7a0, 0x8b20ef31, 0x141623f6, 0xd0f5321f, 0xd8536199, + 0xd6430453, 0x0c8c103a, 0x81fa0cb6, 0x1652562a, 0x3bc2a9f9, 0x8b9f503e, 0x2025f917, 0xa8dc6398, + 0x573d30f0, 0xe96bb430, 0xc379f6a5, 0x8f682727, 0x48ad01d1, 0x74de96f9, 0xc1a530af, 0xc889996f, + 0x4fcb937d, 0x2b0b731e, 0x771ee3bb, 0x74212f6a, 0x8190f057, 0x7371327e, 0xef2c2ecc, 0xffd6817c, + 0x1be8e2e0, 0x20bc6978, 0xe8780e0c, 0x1f91094a, 0x3621ca1e, 0x570ce1ec, 0xe8f3dcd6, 0x373f36af, + 0x2b8822d2, 0x11a6c184, 0x8a24079c, 0xa3f565f4, 0xa4e5bc16, 0xa599c2f5, 0x20d07a87, 0x6d45101e, + 0xc7d27be8, 0xd90b4b32, 0x6a24dced, 0x9bee143d, 0x5149cfe4, 0x0e004df8, 0x9b7f8832, 0x3228b4de, + 0x3d3ed815, 0xcf61d4f8, 0x9663285d, 0x0fc34df7, 0xb0a97fc9, 0x52ed50d1, 0xbaf9e29b, 0xc6315f35, + 0xcbfc8ec1, 0x30bbb775, 0x8864a94a, 0xd8f425e7, 0xd37b31dc, 0xaf9039e8, 0x047f48b6, 0xfa365f07, + 0x36b65298, 0xa3dd8699, 0x866a6308, 0x0156ddeb, 0xfa1ca1ab, 0xf9f09fc8, 0xe5b2c347, 0x28642967, + 0x492b1cb1, 0x47a6a343, 0x6baa79b1, 0x8be5a0ef, 0xd90550e9, 0xcb51b751, 0x807f9ba8, 0x48cb0c12, + 0x52fcdfdf, 0xeef08df1, 0xe8925047, 0x23b459f0, 0xecf7de5e, 0x4f6f70c5, 0x339e8666, 0x9a8f5f00, + 0x1fb0cfc3, 0x9b8b566f, 0xc207fb4a, 0x86308a92, 0x85e8e741, 0xe744e8ae, 0xf8a68948, 0xbcb22849, + 0x12ecc660, 0x8d08cd25, 0xdf2d255d, 0xeda4fb44, 0xd3dcb818, 0xfcb722bb, 0x29e08618, 0xc2275b99, + 0x0a0ed6f1, 0xc6d54bf5, 0x79fc53e6, 0x8ccb829b, 0x6fb2cf39, 0x91e49b55, 0x9c262f10, 0x763d7a9b, + 0xba74cd67, 0x9d262846, 0x2d69eb5b, 0x8f5dfda0, 0x7c7afdaa, 0x52553599, 0xc19130ff, 0x0ee7d7b4, + 0x2bdfea5d, 0x9ee4608e, 0xb383ea5a, 0x56e73328, 0x9dbae308, 0x64b78503, 0xfac59e4e, 0x3c25d8c9, + 0x222a7ad0, 0x3ae41d45, 0x2ddaf5e2, 0x866ad8bb, 0x29e05e47, 0xe5c9112d, 0x9f61c2d2, 0x93067109, + 0x1a151172, 0x07fee247, 0x625f67fa, 0x41ff74ed, 0x0e8f549d, 0x1b6541ce, 0xd15e36bd, 0x8961f940, + 0x22e92e5f, 0x2193528d, 0x7c340ab6, 0x00eba25d, 0xb44e0e37, 0xb05a0f60, 0xc4f3264a, 0x2eb97250, + 0x1ded0401, 0xc741469c, 0x3e1d9c17, 0x1f8fbd87, 0xa607b7dd, 0xcfe4e3fb, 0x614033d3, 0xff586d39, + 0xbd0a2a5f, 0xef965137, 0x46bdf6ac, 0x445b03de, 0x8e61d775, 0x6ccef914, 0xbf6b30f9, 0xfa21116f, + 0x8a262bd3, 0x6ff71cb1, 0x4cadeb49, 0xabfeed3f, 0xde24bf7e, 0x587e9224, 0x1be69cf8, 0x19b9708d, + 0x6bde8dd2, 0x80643b0b, 0xb2757724, 0x8e60190e, 0x519eb6c8, 0x163bac82, 0x0a6799d3, 0x54bf95e2, + 0x5789f478, 0xf8e41830, 0x89a99c9f, 0x36ee6c86, 0x230cf62b, 0xc7cf6033, 0x63b71d40, 0x3bdcaf6b, + 0x4462e8e1, 0x3a13037d, 0xf286240c, 0x0dad1c21, 0x225c2e37, 0xa14fa84d, 0xd4efe77c, 0x592686d3, + 0x5b0b599d, 0x638478e4, 0x7610ff0e, 0xd26c62d3, 0x09ee3d91, 0xb951dbc5, 0xbf3b44b1, 0xe9ab2045, + 0xc599a0f3, 0x3ccfa91d, 0x64c1c7e4, 0x946548d2, 0xde8f70d0, 0xe1da09f0, 0xa2968d6d, 0x2a6a1d59, + 0x99efbc64, 0x19698912, 0xe02666ba, 0xe62913a3, 0xaf33aecf, 0xc3308bb7, 0x67f4c64d, 0x1c0e0ff3, + 0x3eab7384, 0xba07d1aa, 0xe12f49ca, 0xb9ddf501, 0x75ec65ed, 0x57c1af50, 0xbeb3b6c7, 0x65e555b5, + 0x2c7160fb, 0x66036901, 0x3ee38329, 0x5f22d843, 0xa7201dac, 0xb2579bf3, 0xbc47c86a, 0x1c9fa68a, + 0xab0ee545, 0x2161fd35, 0x058a43dd, 0xbad09ed5, 0xb98ca8c9, 0x2f9efe1f, 0xa32a7967, 0x2e0fa6bc, + 0x96e02335, 0x5a05b304, 0x8325ffe1, 0xa45448f7, 0xb18c3a89, 0x3fb6667b, 0x87ec29c3, 0x1cf7bd2d, + 0x4efa6cdb, 0x37a597d7, 0x0a31c1d3, 0x9e9a5a18, 0x0108f6ea, 0xc0c04d1a, 0xe474e4aa, 0xc11077a9, + 0xa4130b80, 0x1737e389, 0xfd6e6173, 0xccda2629, 0x3c0902a7, 0xf15fdffe, 0x59559ecc, 0x9777f2e2, + 0x7a9d341b, 0xb3323779, 0xded98298, 0xfc93dff8, 0x8a262772, 0xdad6b6bf, 0xad6f9890, 0xd52ff60e, + 0x66de198e, 0x0ed9e241, 0x7b5c9c4f, 0xceeb2d00, 0xb209ff7e, 0x73ce2a01, 0xa3c41db2, 0xf2416b1b, + 0xfdff57d6, 0x575105a1, 0xbc1bd549, 0x4cae7617, 0xbbc925cb, 0x6467734d, 0xbbcbade1, 0x82783d84, + 0x435535e5, 0x8237160d, 0x08786ef5, 0x5f5c6966, 0x96719d18, 0x2d427922, 0x9ccaa885, 0x92d18155, + 0x05c53c03, 0x695ab5bc, 0xf9688801, 0xcdf51e1c, 0x90ae9a52, 0x8dfe33b6, 0xba4ab5da, 0xf36fdf55, + 0xadd0a9ba, 0x2d3e5cb2, 0x6cf48116, 0x7e1236e3, 0x427eca9f, 0x91bed403, 0x7c0ab78f, 0x48300c8b, + 0x7bc4e8f1, 0xb55090a4, 0xe66f5e59, 0x1fb5dfee, 0x4dc3d149, 0xa639f2b3, 0x096ed945, 0x3f0a3029, + 0x9a1538fc, 0x7f909fbc, 0x8c91acba, 0x43291287, 0xa07d6225, 0x99ff6416, 0x750d73bd, 0x1e23e2e6, + 0xc90c8782, 0xa6bf9c1a, 0x647a108b, 0x97d229b0, 0xe255ce3b, 0xe929011a, 0x0cc8c8de, 0xc673a9d2, + 0xedc08065, 0x39ab34bb, 0x16a72a97, 0xd2394d51, 0x36c47208, 0x5fe9dd6f, 0xdc6152af, 0xaf2f5649, + 0x9e813183, 0x956423cb, 0x2dd9e1c6, 0x70ed0701, 0xa5f421d8, 0x2fd524a4, 0xc8ae4c73, 0x2d7b6a14, + 0xef4b78cd, 0xd07d9f2e, 0x61e3b258, 0x10839288, 0xef98003e, 0x0c5ec37d, 0x45672177, 0x5c75f363, + 0x160d38f8, 0x19906fe9, 0x5f97e7f0, 0xc88fb793, 0x4c49f73f, 0xfd89c424, 0x6ef48245, 0x2f28ea12, + 0x03db1517, 0xfd6d2792, 0x69ed3990, 0x51e49087, 0x6545490e, 0xaa06ac81, 0x289363e5, 0xf6f36db6, + 0xa4cde2c9, 0xcc1e88df, 0x7f6fccde, 0x0872d317, 0xf9033cbb, 0x3771005b, 0x80918390, 0xec5becd8, + 0x5b6664c2, 0x6def9ec8, 0xc7825586, 0xb196359b, 0x422ce567, 0x7eb3a39d, 0xe9e74656, 0x5c5abf0e, + 0xf0572321, 0xaee83782, 0xbff8f1f5, 0x2b5d10b4, 0xa449c5f2, 0x1220ad8a, 0x67b14d1c, 0x6206fa55, + 0xd9a30739, 0x223eaf8d, 0x53ae6018, 0xdc1258e8, 0x323f4694, 0xde2eca97, 0x9d99d154, 0x5948a4b5, + 0x22773046, 0x73a7b608, 0x717ace40, 0x6f289514, 0xb0c54430, 0xc6226333, 0xbf2b4ab9, 0x30f036c7, + 0xa9596c7d, 0xe4a64798, 0xaf6c6365, 0xbb161525, 0x705ac2e6, 0x0358f183, 0x16a1ec20, 0x209e7a53, + 0x43054944, 0xef325e6d, 0xd3d8fb57, 0x80cebf3b, 0x92d8e291, 0x6f87bb6f, 0x9246ddde, 0xd72e35b6, + 0x66000b9f, 0x39cf576b, 0x826d1a75, 0xc3c75d22, 0x504e5354, 0x4da60822, 0x9e88b046, 0x3ddb1bbb, + 0x65e72746, 0x20104c59, 0x0034ffe9, 0xa0617ad4, 0x47623f61, 0xe25ff2f3, 0x2e35d016, 0x114760b7, + 0x935990f9, 0x8fbb9e72, 0x06b57d3c, 0xec8a895a, 0x831c038b, 0xd6561e99, 0xa9408bae, 0x17f9c309, + 0xaeb8587f, 0x1d718a8f, 0xe7d5a6da, 0xa02c60f3, 0x293908bb, 0x00bf488c, 0x881d0705, 0xd5f84ed8, + 0xc1e15151, 0xf5073b60, 0xaf9878c5, 0x543505b0, 0x6a63173f, 0xe3784ffd, 0x5184cc1e, 0x20798c6b, + 0xdaeb56e4, 0x7ac50607, 0xf7dccbef, 0x44a98e9a, 0xae48ff63, 0x00af922b, 0xe0dc7813, 0xf05e33fc, + 0xc8a03806, 0xfc8134c2, 0xdd291cfe, 0xae7f25c9, 0xe2cc32d8, 0x4b4c8eaf, 0x484e4da1, 0x9067e59c, + 0xc80af1d7, 0x3756df41, 0x2f8e1c89, 0x9d84f25e, 0x103ebe57, 0xe2b21ab9, 0xd0079052, 0xbe21a9fa, + 0xc8cdefb1, 0x0fd47a41, 0x25ed0062, 0x64ceaa68, 0xb161ce3e, 0xee68daff, 0x8eae38b0, 0xb7b186d9, + 0xccf55357, 0x15779584, 0xe6d89558, 0x4fe54b1c, 0x09c9a93d, 0x72201f00, 0x8973fe24, 0xd965c341, + 0x166a7074, 0x437fe332, 0xb2297178, 0x93445f09, 0x798c4bdb, 0xc0d1d193, 0x360c9730, 0xbba8d338, + 0x366a2dcd, 0x50a62465, 0xa05d8848, 0x510e942d, 0xaa304455, 0x7e6cd61e, 0x9028e55a, 0x506e109c, + 0x9a3db0b8, 0x07324b2d, 0xf60639da, 0x50d4bb8c, 0xb2724354, 0xe7e9c208, 0x5c1e3594, 0x05e1ad6e, + 0x8539f0cb, 0x16e1b208, 0x4ebf7aa5, 0x970cb971, 0x15fc9b62, 0x9138e722, 0xe4807f85, 0x4f5ad34e, + 0xec94c31e, 0x11bb08c6, 0xe6ecbe75, 0x7107f406, 0x5cb97ad8, 0x7fbd9421, 0xb65bf8e6, 0xb49319de, + 0xdee8d93a, 0x852793eb, 0x5438ab3e, 0xe663ddd4, 0xb6239961, 0x5647bc6d, 0x99306e5f, 0x3ecce949, + 0xa7b8228c, 0x999e5633, 0xd07738c0, 0xc7f20bad, 0x1c1bb045, 0x43c46016, 0x1dcea77d, 0xe111d15c, + 0x12de63bd, 0xfe788bbe, 0x1a5616fc, 0x61f63b6e, 0x1ad025d9, 0xe50966ef, 0x8fbbbf29, 0x226e72e6, + 0xf651ec20, 0x81ec3c20, 0xffe50f5d, 0x242316e0, 0xeeecfc74, 0xcc22c44b, 0x96defcda, 0xc68a6c40, + 0x9d5e9b33, 0xe1ae5790, 0x60015aec, 0x1c79b391, 0xa13d731d, 0x78545fd8, 0xb3113871, 0x20a6c648, + 0x0eddae6b, 0x65294430, 0x98b347b9, 0xf5c7bc64, 0x9f569561, 0xf40172c0, 0xf4d0f224, 0x3c21f6fc, + 0x26153cac, 0xcdad0c6f, 0xe6ea3a54, 0x6ffec81e, 0x6c53908a, 0x3ab8aa69, 0x591655ea, 0x9b4e69cd, + 0xd5913a39, 0xd4027bfd, 0xce66c6aa, 0xffc53041, 0x66ec66a5, 0x42f00428, 0xc134ec85, 0x3f5823f3, + 0x19be85c3, 0x85e6ceb9, 0xf6257def, 0xf229446d, 0x296476ac, 0x2f1d68b8, 0x89ddb0b4, 0xe4c9ed36, + 0xc0a85ece, 0x619514a5, 0x95c712dc, 0xf6cb411c, 0x0ea68d54, 0xc78e5d7c, 0x5cbd9590, 0xde91186b, + 0x70b6d269, 0x6944f7e3, 0xac7ae64b, 0xc8da189f, 0x200821ec, 0x692686f9, 0x47f3ee96, 0x4ed8541a, + 0x9d57b2ce, 0xf467186a, 0x1cbebea8, 0x8738670b, 0x420c6e9d, 0xa5e8181b, 0xdd6f546b, 0x0835c82c, + 0x57351fa5, 0x80dcae70, 0xe4cd3aa3, 0xd8926f36, 0x39fceb5f, 0x293b858c, 0x9f0c7b5a, 0x029bae75, + 0x4b722176, 0xcbb17bf1, 0x2e98f3aa, 0xc8100cb7, 0xdb9cf4ef, 0xea9631b3, 0x9fedb400, 0x5d6814e5, + 0x04003571, 0x456ccb14, 0xdbc48bb0, 0x6c1ad1fe, 0xf4fddc2d, 0x11ff591c, 0x4476a633, 0x7cfd87b0, + 0x3aca82c8, 0xddf6cddd, 0x8d2097d7, 0x19f5a3a4, 0x9b5e6f43, 0x1f4a4f01, 0xdf66d0c0, 0x96f61db9, + 0xaeae4d9c, 0x8e74f058, 0x18627f73, 0x3cf1457b, 0x5947fea8, 0x497b5563, 0xfb0497f2, 0xefa9d27b, + 0x76a1d0c1, 0x8f3c6795, 0x698217b1, 0x1f0fc060, 0xd20975ec, 0x9ffc3b44, 0xeb5a8d25, 0xb2a21d4f, + 0x208191a2, 0x74eba213, 0x4bd7456e, 0xfd0e2fba, 0x576cfb24, 0xed62323e, 0x284beed6, 0xe26787bc, + 0x4f96ec9a, 0x4c7ac957, 0x20be24ac, 0x425108ee, 0x89125dd1, 0x16b87126, 0x12a02930, 0x080efd58, + 0x76b1fc07, 0x3b234e83, 0x962fad2a, 0xe7de3fc1, 0x8e26a83c, 0xa3ba46ba, 0xa8ad2a72, 0xd99534e2, + 0x2e5a83b1, 0x1169148a, 0xe33182e2, 0x24cd10f9, 0xfda04017, 0x703d3f3b, 0x147bc95b, 0x90d7639a, + 0x4e304115, 0x2d6d01bc, 0x8d721347, 0xfe1ac6bb, 0x61863dc4, 0x5ed96af9, 0xe5042e1a, 0xb5599533, + 0xc93cf249, 0x15b5e818, 0x6f22c9c2, 0xb19e80f7, 0x94a6d76b, 0x94a00d49, 0xdee76157, 0x35ca3a20, + 0xb676316f, 0xf9dfcac1, 0x336dcc5c, 0xa5e0fe4f, 0x21081032, 0x878abe7e, 0xdd2654cb, 0x485da86e, + 0xd069b953, 0x4be82baa, 0x68f1a1d3, 0xd1082f7d, 0xa421563b, 0x942cb1f7, 0xe43c64ce, 0x2016463b, + 0x9eafc2e7, 0x5e702e3b, 0x3fa8d449, 0xefd8fa14, 0x28eed44e, 0x9549d7cf, 0x73186836, 0x1373ab38, + 0x20a89d27, 0x261baf4b, 0x0a0856c3, 0x59fd782d, 0xab7822f7, 0x0c5a3150, 0x4269ad6f, 0xa196921e, + 0x874d5c60, 0xae6ab538, 0x83ed9308, 0xf769d072, 0xb224ad67, 0xae7ccdd6, 0x82e75853, 0xae6b04a2, + 0x4e87bfe5, 0x33eb0184, 0xede48b22, 0x70846e3e, 0x90aec9c8, 0x3cd2646c, 0xeb152f9e, 0x5a02b008, + 0x66981455, 0xbfe4b0d5, 0x839faee1, 0x7f7e0938, 0x52f3ff3b, 0x38b81c90, 0x1b5b085a, 0x6bcf22a2, + 0xcf74dd6a, 0x9e1cc82f, 0x7e254679, 0xb1d463c8, 0xfbd5090a, 0x507073c6, 0x8878b12e, 0x57646b22, + 0xc00893e5, 0xdfc8e21e, 0xde25117e, 0x58dac97c, 0xc71a5b55, 0x11079629, 0x2cd68c05, 0x64eb0eac, + 0x9d54f54e, 0xfa8fbaf3, 0xadfce91a, 0x277f59ba, 0x8e2f3ed9, 0xea93f60f, 0x28f07de2, 0x85797e3b, + 0xeac79845, 0x708a0389, 0xa24b442f, 0xfc1adc1b, 0xa33bd864, 0xbe845806, 0xea8fd793, 0x103ca35f, + 0xa7476ae5, 0x3616acf5, 0xc5b446ea, 0xbe446c3a, 0x658e4624, 0xd3fc30dc, 0x0b41cb4f, 0xaed33804, + 0xd2f7edc8, 0xfc24d597, 0xf8817390, 0xc6833606, 0x6412f2a8, 0x52550654, 0xc6f9127a, 0x9186b470, + 0x39e98773, 0x612637e7, 0x9f21c6fa, 0x1fe43f1d, 0xb9f5a836, 0xf7a7908d, 0x6f5a9dfa, 0xfafdeb00, + 0xc217e6a5, 0xd15afb6e, 0xa9504b65, 0x2732c335, 0xc9256362, 0x91edeeae, 0xe1b6e250, 0x25391e40, + 0x818d28a3, 0x03c5ecd8, 0xb0baf924, 0xc227aa23, 0x322d98f9, 0x6865dcb7, 0x40fee0f7, 0x36e8540c, + 0xa558ecd1, 0xb56905f1, 0xb2cf13f0, 0x28a1f5bd, 0xc9fe8906, 0xdc3cdecb, 0xdc0fd491, 0x5a73431a, + 0xc846f320, 0x43d39cc8, 0x15b5a9f3, 0x8ba3c9f1, 0xe9081d6a, 0xa035083d, 0x19b539be, 0x4cb51ed9, + 0x6bf40fae, 0x1a4cd074, 0xa5092115, 0x958ee59f, 0x414c097b, 0x3ea1be6e, 0x97297430, 0x77a0edbf, + 0x9c757bdd, 0x7e5a60b6, 0xdefe7b1f, 0xc0366ae2, 0x1900f2e5, 0x15854bf5, 0x844adf93, 0x5972112d, + 0x392c84d3, 0x6e1065da, 0x63e7ddeb, 0x027f67d1, 0x580e9c93, 0xe3312222, 0x3019e908, 0xbb1294e2, + 0x96180303, 0xa1068fdf, 0x20899a6d, 0x9fc55571, 0x66efab07, 0xd597e64e, 0x17f03aef, 0xa25bebfe, + 0xb35819b3, 0x001d7ec9, 0x82fa6598, 0x36843f09, 0xa7a66c01, 0xe3631a94, 0x5d3806df, 0xc9cc78be, + 0x3004e50c, 0x8a447904, 0x767c95c7, 0x07ba1ec3, 0x77e3ddf0, 0x243c6ca9, 0x6cf0eb3d, 0xa50acefe, + 0xed4fe138, 0x733de1f5, 0x885cd8f8, 0x05756b6b, 0xd537c1b5, 0xbf91f891, 0xed927494, 0x650b2725, + 0x7bafeedd, 0x7927f36f, 0x20a8a04c, 0x385dde6c, 0xa95fcf50, 0x2db880cd, 0x924c97a3, 0x48472a28, + 0x0f9fe003, 0xc7927641, 0xa95710f6, 0x891b5b48, 0xeec55ee1, 0xfe269e4b, 0xf7a0239d, 0x2c12da87, + 0x8ef8f8f6, 0x9869b8e7, 0xc837a359, 0x9693c6fc, 0x42028ab3, 0x6d586e31, 0xec9b33b6, 0xe62a53e2, + 0xdc13fa50, 0x6cb33fa0, 0x2d5876ee, 0xf5d106ac, 0xbfc58cf0, 0x6b8fde7c, 0x78cd2b0c, 0xabe501bd, + 0xc03dfa47, 0x5566a505, 0x2f5fd6c0, 0x0a719a44, 0x535cb2d9, 0x48234a8a, 0xc72018b8, 0xc707e673, + 0x983e6b8d, 0x855a5a72, 0x2732251c, 0xea0b4c9f, 0xeed29dc6, 0xa52ec4ed, 0xee3e27f7, 0xfdc0ce0a, + 0x05a19415, 0xdc242bd6, 0x80e8fc5d, 0x4875e853, 0xd47338fe, 0x3659d9c3, 0x7d1446ce, 0x6eec9c4a, + 0x9c90658f, 0xae0b145c, 0x9023be83, 0x8a63b05a, 0xd4bc6f70, 0x5515f90e, 0xa9ed6f8a, 0x87aa5ffb, + 0xf8c94096, 0x35bec132, 0x7c183904, 0x13d46e3f, 0x4cba6586, 0x2c6d4f37, 0x364132d6, 0x1aa7929a, + 0xf1a611e6, 0xee67ed91, 0xf70164f9, 0x93dbd013, 0x8c9aebe0, 0xc4dd7577, 0x33bc0d40, 0xad13b642, + 0x2673e73f, 0xfc369062, 0xe7d5f89e, 0x46734990, 0xd1a7f9b2, 0x73727fbe, 0x107b3fef, 0x9416412a, + 0x2228005b, 0x4932882e, 0x2b72fe0c, 0x5c7c8008, 0x454ce246, 0xa15b38ec, 0x2d81cc4c, 0xe2d5f86c, + 0x8f14a7ba, 0xab9c89db, 0x4f6a2f56, 0x8a992e62, 0xe147a6d5, 0x005c4191, 0xcefa400f, 0xc907159f, + 0xc3eed958, 0x7ff5a282, 0x38330eb8, 0xf15dfdb3, 0x995ba85c, 0xeacf57cb, 0x39d8e195, 0xd713e468, + 0xec3d393f, 0xb5253689, 0xa05723b7, 0x3841dc32, 0x6be8390f, 0x54be6e3b, 0xccd757e3, 0x5c30627b, + 0x1977edb3, 0xe35369ff, 0x04f5324c, 0x2c0e9487, 0xce7d6c14, 0xcccb2af1, 0xe0f52e43, 0x20e418ef, + 0x595bdd10, 0xa6549fe3, 0x280ff725, 0x9f9c22ad, 0x93d617d6, 0x7e930840, 0x343f3aa8, 0x2c6c518e, + 0x35b097f7, 0xa3cc3e35, 0x9455d329, 0x0e8bc294, 0x14c0aab3, 0x16cd5ed0, 0x20c930b6, 0x961bbebe, + 0x8b9b3cba, 0x133905e3, 0xb4883b8e, 0x57e6a23d, 0xf9da2824, 0xaae8aa63, 0x1eb4f32d, 0xefbf7887, + 0x2cbd672b, 0xe2569ea4, 0x4f4a3a02, 0x5f7051ab, 0xa08bfa68, 0xd8edf78e, 0x8bca04ec, 0x35f5f53c, + 0x0d9d22ab, 0xdc58421a, 0xb8b0ef82, 0xb45f601d, 0x4edb975e, 0xc2c586a0, 0x9876f752, 0x6c918260, + 0x612b36f9, 0x7e2fe173, 0x4e927f7d, 0x2d3c7301, 0x37079bf8, 0x079c6560, 0x6aeeaea1, 0x75f902db, + 0x64f1dba3, 0x019c5918, 0xa6e13c9a, 0x0c93864b, 0x248ae6fe, 0xd8b54e77, 0x50bcc599, 0xcaec95f6, + 0x0e65884e, 0x434cd677, 0x07d79984, 0x75bb83ce, 0x6fdb9494, 0x9624f27d, 0x1c2a1528, 0x24656cdb, + 0x2c96f6f4, 0x08138295, 0x1c8194c1, 0x7915d6e4, 0x48f057ec, 0x1bbe2bbb, 0x00843aab, 0x9d3e71b9, + 0x82b73134, 0x30197ff7, 0xeccfeed8, 0x0651764b, 0xaeabeac1, 0x2d398dee, 0x85058659, 0xb606ae5a, + 0x9a47822a, 0x98baa511, 0xeb67ab0c, 0x7be37589, 0xe4cef2d9, 0x1398e54d, 0xbdde7db6, 0xa6ea3bc0, + 0xa21884df, 0x79798023, 0x2608c55b, 0x28f8cedb, 0x706b2b2c, 0x6d49b91e, 0x5c5f9955, 0x279545b9, + 0xc9c6014d, 0xd94d9062, 0xd31f7424, 0xfd662a8d, 0xc1d9e9e6, 0xe72c252b, 0x478601f4, 0x50dbe441, + 0x6a3e9e4c, 0xae70f95c, 0xfef86ea8, 0xb28403d7, 0x1a1e7027, 0xbcfe2468, 0x238db2a6, 0x1a8836c4, + 0x06e51004, 0x319ed593, 0x803d063e, 0x0b8c4088, 0xeb5e35f4, 0x13dfcc52, 0xc984f338, 0xdfbc5692, + 0x87b38625, 0x2093d82b, 0xdf83e55a, 0x84039f7f, 0x0cc6d525, 0x44964adb, 0xeaab190c, 0x52435624, + 0x77183964, 0xb4fd017e, 0x94e3cccc, 0x910b5272, 0x65d4a2f6, 0xa83b1e63, 0x9a4f20f4, 0xc907f197, + 0x4532e6a8, 0x2dbbdc14, 0xe392e897, 0xe80deda8, 0x3153b5be, 0xc6c9d5da, 0x3c332f8d, 0x9b4aa131, + 0x7211cdcc, 0xe583070e, 0xf3db2a90, 0x5ba5959d, 0x447c1542, 0x467c5b8e, 0xa94e56d0, 0x7a80b7eb, + 0x7b34c1ad, 0x933727f9, 0x35e14ac3, 0xe507dda7, 0x0e377dd8, 0xa3e0c83c, 0xc466c656, 0x732ded48, + 0x49418c57, 0x7f57b3f2, 0xa3d51410, 0xd8e1ad37, 0x08675619, 0xf788d776, 0xe8faf6ed, 0x54a98183, + 0x4823a3a2, 0xa2e72641, 0x6283f250, 0x7e2d6f0e, 0x3432c35a, 0xf8719de9, 0x153dea33, 0x5073d3bf, + 0x0ae40890, 0xfae13159, 0xd4b45e48, 0xb53198be, 0xbfcc8557, 0xfa95df59, 0x81aefd5e, 0xee1ea54f, + 0xd5c499ae, 0x4b704362, 0x11fe378c, 0xbdc6df09, 0x0a6d1efb, 0x81a6d2f9, 0x74b62ffa, 0x1413a583, + 0x70853733, 0x452bb1f4, 0x9e42d4c3, 0xe8298d69, 0xee40240f, 0xe9d0c13c, 0x798df7de, 0xfe19e808, + 0xa8213f95, 0xc9c54768, 0xe6ef1030, 0x0c530934, 0x207a7370, 0xfc37e777, 0x8e68f18c, 0x3ab7241d, + 0x6638f571, 0x5e0b63f1, 0x43d84eb4, 0xd5f63f4f, 0x4322b8f7, 0xd2c648e8, 0xe062a3a4, 0x4eb8125c, + 0x02d4c911, 0xc36397c2, 0x27d103e0, 0x0f16f07a, 0xdfc74bc4, 0x4e37fc82, 0x7246fbcd, 0x4b4a7993, + 0x358ab862, 0x45f3b042, 0xfead91cc, 0x43d25623, 0x51cf47ea, 0x84aa738e, 0xefc9447e, 0x1ec2dcf0, + 0x6c13f2ae, 0xedc6762f, 0x00daf05a, 0x143bd559, 0x3b0a7be8, 0x9844a842, 0x48d1f7b2, 0x7b958a68, + 0xab44bcd6, 0xcf39773e, 0x70c70a75, 0xe5f47aff, 0x3b8f55fa, 0x2337fe6f, 0xa182d54a, 0xd5ab6eed, + 0x21223ca3, 0xb102b319, 0xdae2e97f, 0x909a8539, 0xfc909504, 0xa814f734, 0xb4861c5a, 0x36968496, + 0x06197037, 0x4d8c7f54, 0x7fd73afc, 0x9aa23163, 0x6fb9c6ec, 0x583fbbd6, 0x5c62854d, 0x543c2973, + 0xb392f1f8, 0x532856e4, 0xd477e9a6, 0xebba9443, 0x4bf4c721, 0xb3a419a7, 0x40583a28, 0x8ba9c28d, + 0xb5a8bea0, 0x587e6916, 0x035e7a4e, 0xb71cfd24, 0x5e744f38, 0xc1e770b8, 0xa09b3acf, 0xcff5343b, + 0xc358c97f, 0x237fb4d0, 0xc1a33e6b, 0x469c04da, 0xf93cb499, 0x0e03aa5e, 0x930c245f, 0x185bd39f, + 0x4aac87d5, 0x90caeb5b, 0x7c1c5c38, 0x6c4f418d, 0xf6197eef, 0x796cd739, 0x2b3e8c14, 0x11fafb33, + 0xc108a2ec, 0x07d36798, 0x176adfea, 0xf5d442b1, 0xbd55f511, 0x93fd07ba, 0xd11e4e43, 0x9eee5f42, + 0x3f7f1cc0, 0x1b4a95eb, 0x4593137d, 0xd76a4100, 0x0f6a1baf, 0x7c158fc9, 0x269c9db9, 0xf43652a3, + 0xa3dd8ffe, 0xf70cbd80, 0x19352cd4, 0x9d7ad16c, 0x9978f185, 0x2ceea69b, 0x4785b280, 0xf0001280, + 0x40d5d43c, 0xd2a1f08a, 0xd9c495a3, 0xb62641ff, 0x94078ea3, 0xefae4a7f, 0x56949e60, 0x244964eb, + 0x79ce61fd, 0x8fcd7b5c, 0xc01412ec, 0x3dc20148, 0xaf655f65, 0x4df2088d, 0xa72e79b1, 0x13acc096, + 0x91958c80, 0xe9a5aae0, 0xcf0445bf, 0xb7cdf04f, 0x63790ca2, 0xbd0f83eb, 0x9173ab12, 0x76984832, + 0x5b056008, 0x48539440, 0x9d950499, 0x40346f87, 0xca7da4d9, 0x51c93e68, 0xc9fc97d5, 0x72c3464f, + 0x04072e5a, 0x1bae1834, 0xc35b8132, 0xa5b7e730, 0x43403b29, 0x9a65b5e4, 0x02041026, 0x226efc80, + 0x69ab4e7b, 0x91e4d10e, 0xff6eb0f1, 0xc63cd886, 0x00aaedac, 0xdc4af4bb, 0x0a9d550e, 0x0315f3a7, + 0xe2fbe1bc, 0x2cf47e22, 0x69e23989, 0x491e57bb, 0x0116e339, 0x5a628d5d, 0x070f4e43, 0x89383f0e, + 0x26eb4692, 0x381a9185, 0x3f0ea4d2, 0xda84d3d4, 0x38adeaec, 0xc0180eee, 0x28083585, 0xaf62928b, + 0x1ffe955f, 0x83a3a927, 0x33d9b769, 0x21badeb8, 0x90800292, 0x126fb8af, 0x2501e55c, 0xbb95b783, + 0xa56f62ca, 0x95a7e149, 0xbf90fe6e, 0x0830b81a, 0x26c9da06, 0x79fb2571, 0xf8c893b6, 0x692543c5, + 0x3be9be11, 0xde160d4a, 0x1b0a62fa, 0xfc130997, 0x82f3c0be, 0x05151998, 0x43f8a9fa, 0x4edfc022, + 0x19539c15, 0xadb5927d, 0x787a3f76, 0x28136f3c, 0xbd6ce0e0, 0xb4ed5235, 0xabff519f, 0x53358e47, + 0x760aaf27, 0x423972e9, 0x7cfa1986, 0x2c7b0641, 0xa3cd5f5f, 0xacad93eb, 0x1ec15f39, 0xff29621b, + 0x3a41a27c, 0x37981840, 0x35f4cafc, 0x0844a439, 0x426d795c, 0x50c2ea67, 0xbc76d0a0, 0x70bb6baf, + 0x46edd290, 0xf41b0eed, 0x2371937e, 0x5824498c, 0xc94c8abc, 0x159e6821, 0x0a2e02f0, 0x4fb1d9ec, + 0xd9f66358, 0xb7e5fb7c, 0x49466a5f, 0xe9eeb8fc, 0x2162945f, 0xec2b75ce, 0xfcc3350b, 0x272f8092, + 0x96f663f1, 0x567c8a1f, 0x832cb58b, 0xea47bc58, 0x6ed788c1, 0x971229b7, 0x8c4b03c6, 0x5ccbc580, + 0x97ffceaf, 0xc9c4158e, 0x30e26591, 0xfe6d091b, 0x0731b367, 0x2d9a4d2e, 0xd029d2f8, 0x6b69d81a, + 0xfa64452d, 0x3b73f9ad, 0x3435551a, 0xa3aeb874, 0x3036f912, 0xd207a7db, 0x25531a20, 0x96af3a8a, + 0xd27a8f5f, 0x48fd875c, 0x9782e7b7, 0x00fd8682, 0x026df744, 0xae595b97, 0xace90e84, 0xff77a819, + 0xa4b8dd1a, 0x4875946e, 0x19156811, 0xd80eeebb, 0xbb45a9cf, 0xa2a97f7f, 0x01f805b6, 0xd1ad7a19, + 0xae87300f, 0xbbecfe3e, 0xc912a0ae, 0x42e165f7, 0x6f794a19, 0xba0fd1f3, 0xb260048e, 0x21eefce8, + 0x72eb3167, 0x729807c1, 0x07d5cf3e, 0x95f8bc97, 0xbea7561f, 0xd1ad39b7, 0x16c7410d, 0x057522f4, + 0xc5e0d502, 0xa26e1891, 0xa1b90b2b, 0x16f21dec, 0x992e22e9, 0x88e7a7e8, 0x0a578a84, 0x6dbd5d1e, + 0x8b25fe21, 0x4cbc07bd, 0x9132315f, 0xb7604311, 0xde85ec7b, 0xb02063c0, 0x7c609a89, 0x4bb5229e, + 0xf0dc86ae, 0x1539959c, 0x92be31d3, 0x47f52876, 0xc4002821, 0x7ae4c625, 0x3a190be0, 0x8dd1452b, + 0xe7aef518, 0x057b8f91, 0xe56121a6, 0x3e04b6d2, 0x93f1ee8a, 0xb149b141, 0x63da35a8, 0xea8473e8, + 0xf6800a3f, 0x33f7203b, 0x1c739991, 0xfca62f62, 0x8ad7ffc7, 0x763e2cad, 0xf5fb2348, 0xd0abfd06, + 0x799f30fc, 0xf0ab92e0, 0x843aa73f, 0x3079e585, 0x3cdf677a, 0x96a5a6a2, 0xb0e76a6a, 0xd34358bb, + 0x75785021, 0x0ebad0e7, 0x81de0dd3, 0x4e8a4703, 0xe4d8d79e, 0x19c4af23, 0xdc6f061b, 0x3b19b89e, + 0xed14d47b, 0x62cbcb34, 0xa36427d2, 0x3632b001, 0xb35457a0, 0x9b3a94e0, 0xbba63680, 0x48c1074b, + 0x7d444ef7, 0x9ca3c3d7, 0x53ebb714, 0xae600fa4, 0x81d8f252, 0xec944222, 0x89b8292b, 0xb45ec8c5, + 0xab440048, 0x8f41b214, 0x84c4d402, 0xb51aee09, 0x792f3068, 0x16d304d1, 0x3b194b58, 0xe3ce1c60, + 0x8d7bca9e, 0x3c955248, 0xbc560586, 0xaf734a44, 0x7ceb631d, 0x6ded6a5f, 0x0d9591e1, 0x22b2da5c, + 0x6d1e6820, 0x0fac3535, 0xcf4997d3, 0xb52f0c38, 0x61df2725, 0xc1e5c9e8, 0x2947c151, 0x7e144407, + 0xb4205d77, 0x658e3c75, 0x438d5553, 0x19d4a4b8, 0xf989b49a, 0x12ad331a, 0x6a6bdc54, 0xe841c3b7, + 0x67b1d8f0, 0x0ac78e4b, 0x812eef21, 0x6eff8753, 0xb5967907, 0xfeaf7975, 0x0918bb75, 0x5664223a, + 0xeac89c6c, 0x0ed50708, 0x3da97066, 0x2b7825e7, 0x47fa6145, 0xf43f74ed, 0x06861433, 0xf6606a14, + 0xeff50116, 0x85f79979, 0x93facd1a, 0x669a1b91, 0x1e09d95a, 0xf2f73b15, 0xdae1a499, 0x8e101bc4, + 0x29193a5b, 0x9f08bc72, 0x48c86691, 0x6b54779a, 0x8cbca578, 0x4ed379f1, 0xd8fb0e97, 0x5504f3e9, + 0x33b6de2b, 0x22e7a80f, 0xd497f3e3, 0x34691bd2, 0xe43841b6, 0x5a2552ad, 0xc443aca1, 0x140fdff9, + 0x698d4c4b, 0x395c0c00, 0x40b5c6f6, 0x069f72b1, 0x7f175e16, 0xc7b15098, 0x80216c81, 0x4e4aad02, + 0xf112e4d6, 0xd94a0c49, 0x6931e42b, 0x47a028b5, 0xe5e5a8a9, 0x9b93a896, 0x3bcf5645, 0xec5ebef9, + 0x3ac29355, 0xaadfa232, 0x87a2682f, 0x08eb7842, 0x39149720, 0x0f774291, 0x8598ce63, 0xf50fc937, + 0xd7c43af6, 0xee40aa0c, 0xc3eee60c, 0xa1c49ed1, 0x6ab79d5c, 0x67ac7a3f, 0xa3dfa85b, 0x1112054f, + 0x09d5f69f, 0x9c92d357, 0xc1c269ba, 0xdc60dfa9, 0x64f4e40b, 0x9b3441de, 0x1a8b4635, 0x72e673af, + 0x3b0dab03, 0x363232e8, 0x73f16479, 0x3c5f0682, 0x962126ce, 0x3385bbcf, 0x979cf279, 0xe1c89f13, + 0x38f467d8, 0xeff52454, 0x68b374f5, 0x37ddb872, 0x6bb07711, 0x4535d2c5, 0xa95b322b, 0x7c6f1cdb, + 0x09da309a, 0xb61f3713, 0xe2ce0db7, 0xfb1f2936, 0xe5954906, 0x3e9bea6f, 0x1d346780, 0xbfba1e68, + 0x96eb8c8b, 0x84f99238, 0x9cc6322d, 0x08d891bf, 0xe6485db6, 0xaa5c1ac2, 0xe05ea014, 0x4614bb70, + 0x54e8b6fd, 0x7178019d, 0xca8a85c2, 0xcdc72000, 0xc1bef54c, 0x40993b17, 0x473fc2f1, 0x030b089a, + 0x98a09f7d, 0xd9d3c50e, 0x54e12a48, 0xea4e1bea, 0x25da30dd, 0x406a13d8, 0xcfc0e41a, 0x98ef3aa5, + 0x6b80e2c9, 0xe649deda, 0x280d8db2, 0x54f3de98, 0x73ba2312, 0x73f20221, 0xcfa419c1, 0x191a563d, + 0x7ba8196b, 0xa8a5e96f, 0x907ea792, 0xc5477612, 0xe2541a3a, 0x44d9c230, 0x2529b48e, 0x0adb90c9, + 0x206ac010, 0x19e30ca2, 0xa994c0a2, 0xbac640a2, 0x7b3eedca, 0x52398507, 0x6e87f125, 0xa3a3ffa6, + 0x018a0cd8, 0xdcd4bce7, 0x6d801985, 0x76bfeda7, 0xb9ccb263, 0x7a2d9afb, 0x2c75e3be, 0x3bb2d3c0, + 0xa37d1eee, 0x86174562, 0x67599d21, 0x6a1584f3, 0x60d5fdf8, 0x60a37f46, 0xa3fd678f, 0xe10e1682, + 0x9a9b7099, 0x67539e8b, 0x4e31d778, 0x8d7de5b4, 0x72d0b06b, 0xb5178fcd, 0x28b6828e, 0xf32935a0, + 0xc3661124, 0xa7ef61e4, 0xe750f863, 0x37ac7be2, 0x915eb534, 0x6e303b91, 0xc9d5158b, 0x0d3842e9, + 0x3e4023a3, 0x83975c9c, 0x711210fc, 0x24810e1a, 0xb1a9295c, 0x8c2a4303, 0x6e47ca96, 0x5ac5b588, + 0x8cc49ed6, 0x606b0ad4, 0xb97b5964, 0xd050ef5d, 0xef049e35, 0xa8a218b8, 0x850a0805, 0x932e0dc6, + 0xeec16a5f, 0x98fa88bd, 0x6d8837ea, 0x8179ee90, 0x78c5c3b1, 0xfebe115f, 0x9fe42750, 0xf8f097fd, + 0x592f89e3, 0xe27989de, 0x972d6a1b, 0xcb847bd5, 0x07e16763, 0x885e87e1, 0xb62c92cc, 0xcd32542d, + 0x1c9714a7, 0x27ec5dfd, 0x870a0608, 0x94a893f0, 0x8f7d7ed3, 0x946061b4, 0x6e3e37a5, 0x59e6f716, + 0x78372f7a, 0xfea8f8c3, 0x9e0c9d84, 0xf59118bd, 0x9bb4e638, 0xbca049f4, 0x10776d77, 0xf515297a, + 0x2a782937, 0x442c982e, 0xa7c5c382, 0xd00e29b6, 0x4b8a4fc0, 0x98677106, 0x8349643b, 0x471fe30c, + 0x056dac57, 0x04dd8056, 0x27dd3703, 0xec0765d1, 0x9d2b2c4e, 0x7eacbb93, 0x4924eac9, 0x7f743345, + 0x4fdbb949, 0xc381e16f, 0xe7804fff, 0x8adde99e, 0xd7c6937e, 0x17bc7e09, 0xb9837c31, 0xc8a94067, + 0xb26d4a93, 0x4ec11340, 0x3755bdca, 0x9bbb5244, 0xb03a60c0, 0x341e9f70, 0x99556c02, 0xb3cc43dd, + 0xa4d26fa4, 0x61f3a2c2, 0xdcc3a179, 0x5d734b35, 0x109818f0, 0x7d140a4b, 0xe1c5fd6e, 0x373ed82c, + 0x3f85330f, 0xea67c5a1, 0xeea34ac6, 0xfc6b362c, 0xa45b5373, 0xa906005e, 0xe2d37d6b, 0x39e8a3a1, + 0x30cb8797, 0x0a4a76de, 0x754a8ee4, 0xbff1a53c, 0xcf74dca9, 0xaa26f3b2, 0x1c7e6d37, 0x001dd42b, + 0xe7d2f3b6, 0x115f223f, 0xbc41f479, 0x249efb39, 0xe771ab17, 0x99e0796b, 0x6a8de4d9, 0x5e603031, + 0x1325c802, 0x9853e71d, 0x7ea08a92, 0xb101349d, 0x385b8766, 0xc7a56ff3, 0x0f91a873, 0xf7017882, + 0xf3e9c4b7, 0x1b6a6bff, 0x003d36d5, 0xd77c5ead, 0x0e176563, 0x58106277, 0x001905bc, 0x6c4ce805, + 0xece82662, 0xdb31c074, 0xf80e1e50, 0x551f990a, 0x49cda93b, 0x788654c7, 0x73d29dab, 0x9eddc61f, + 0x0a3bbe74, 0x70103268, 0x3cf7304f, 0xee0a5b2f, 0x94b0312c, 0x413a6306, 0xc3d19923, 0x25ca1990, + 0x8858a564, 0x633277b0, 0x7d465626, 0x62c78b54, 0x1cf73dd6, 0x91b2e097, 0x530ef2b8, 0xd672cd93, + 0xfee338f4, 0xe595554f, 0x75600703, 0xb8cc69f1, 0xe1398643, 0x58904b08, 0xed84d1d2, 0x755fba6a, + 0xad8050df, 0x8a26a2d9, 0xb8bfa30f, 0xf1e1e0f8, 0xd41261d7, 0x1821a9da, 0x4647cd58, 0x419087ae, + 0x8147e2b1, 0x602c640f, 0x3a6c8d9c, 0xb47f8f54, 0x47e116d2, 0x4066fc20, 0xca9f695f, 0x36b82b3f, + 0xca4c8ed4, 0x2510987e, 0x2216c28a, 0xe6765af8, 0x97f6c7b2, 0x786b8072, 0x5f6dfdd7, 0x5ae24cb5, + 0x3a1d2b2f, 0x32af5b08, 0x67959630, 0x6831f5f7, 0xbce9bb2f, 0xf7d144e1, 0x06065ae0, 0x17eb640f, + 0x20f1a28a, 0xf779cec5, 0x1fccc694, 0x4c2b1c23, 0x45bd6feb, 0x2e32ff0d, 0xa12f6e83, 0x07848b39, + 0xb9b5812c, 0xcca085cb, 0x8ce88d3e, 0xe3a9d031, 0x6b4aff81, 0xa8685e31, 0xe87027d6, 0x537e752d, + 0x9c546e83, 0xb5b0218a, 0x68dc3cec, 0x02b0ee48, 0x1d764202, 0x86d38ccb, 0xc2f3f732, 0xf691bc0f, + 0x5f4486e3, 0xa6b9a9d5, 0xfef9dc4d, 0x46a97363, 0x9122c48e, 0x1a9f4e55, 0xee8d92da, 0x97796235, + 0x2ab84b97, 0xc0d819f0, 0xb0354666, 0xc3acbed4, 0x22aafdbf, 0xfb7734d8, 0x73335001, 0xbd723736, + 0x77968d48, 0xe5afd201, 0x146d2bcf, 0xaf59f89d, 0xc2802eac, 0xd0296c33, 0xc8d9b3eb, 0xb0ef14ed, + 0x9bbca3ed, 0x34c0a133, 0x6dac53c6, 0xc8b67d2d, 0x4281ae93, 0xcb4d3f29, 0x2a557dfc, 0xad94d314, + 0x7df83bd3, 0x7809691f, 0xd9d7505e, 0x3f4b6a4d, 0xace31d4c, 0x7715d4c6, 0x84ceb128, 0x746e76b4, + 0xc429bb37, 0x0d719f02, 0x813e0b1f, 0x65ed46aa, 0x2d8a8100, 0x587b55d0, 0x855606ef, 0x5f0e100a, + 0x063a8c8a, 0x519d12f5, 0xc6e02044, 0xf75e81d2, 0x56962374, 0x926b986a, 0x76481207, 0x3e71af32, + 0x0a04a086, 0x06d1ae04, 0x3adffdbd, 0xdb9b347c, 0xb1414544, 0x6c3b6e45, 0x4ec54cfb, 0xb75ec9b0, + 0x95e03241, 0x70a2547a, 0x762f5e66, 0x1d66f69d, 0x0a83d71d, 0xcb47aa6e, 0xab51b423, 0xd54398fc, + 0x64d0d985, 0x04774a88, 0x48d1bc0b, 0xa0996a41, 0x8569a49c, 0xba1ee2dc, 0x728ce6b9, 0x3ed90f04, + 0xd8551fa6, 0xd18a9780, 0x0e729cb4, 0x881a361c, 0xf9c6bbd2, 0x48ad3f81, 0xe2a98a0d, 0x4f894079, + 0x164cfb80, 0x605e894a, 0x19a585ed, 0xf801f7fa, 0x6b11a445, 0x9a00ab54, 0x726dc154, 0xded86870, + 0xcbdc1e69, 0x2e2f3842, 0x92422754, 0xd4cdc334, 0x49de4d76, 0xbef911b3, 0xb8737528, 0xedc239f3, + 0x7d3ecedd, 0x47c2f5b4, 0x66ae6048, 0x1d9d7c52, 0xca7d43be, 0x4ce4e3b8, 0x12b5d434, 0x795c1a61, + 0xc4c88b75, 0x58b6cc87, 0x8d43b082, 0x78d7eeb7, 0x1a0f092c, 0x036b4aea, 0xb6147fa4, 0x7cd4cd31, + 0xe8a0dd89, 0x933cd390, 0xa8a3687c, 0x8af87da7, 0x114eb2b4, 0x8bc5a041, 0x9969fa85, 0x3480d01f, + 0xfb7c22f9, 0xdde5d30e, 0x46adc046, 0x961c16a9, 0xe79c25b8, 0x9d6811f6, 0x56a68ee1, 0x3aedfa3c, + 0x179d023c, 0xb1bd047b, 0x3c657093, 0xcdb352a4, 0x3538dd48, 0xe1102c12, 0xe8f93a30, 0xf2aecd29, + 0xf072ad64, 0xbde835b0, 0xe0aeae1e, 0x2320e825, 0x5ab47295, 0x4fe0ddd4, 0x7caea627, 0x37b71c84, + 0xbcaaa244, 0xc2d858ed, 0x53a62f02, 0xf31bc945, 0xf7830d8a, 0x49fae5b4, 0xaba1eb6f, 0xe8b4b724, + 0x81701ed5, 0xa6202169, 0x42eca1ca, 0x01c1aebe, 0xbf72475c, 0xa97ffcca, 0xe1fe61c0, 0x1039ce1f, + 0xb10bfaf9, 0x2d19f935, 0x4341109c, 0xb1c74a53, 0x8e23f9b9, 0x76ac16e6, 0x21d96797, 0x8430bbfe, + 0xf21f17e2, 0xf24970cb, 0xb77c9339, 0x3ff39b21, 0xaf7be7b7, 0x441459d8, 0x0005ade7, 0x34d7f475, + 0x4070b6ed, 0x290e12fd, 0x4a2cf584, 0x7e03040d, 0xf51d6d0a, 0x1d399c71, 0x389318a7, 0x6cf8408a, + 0x16e3a0dc, 0xd7e4a68a, 0xb1d3c8be, 0x11710332, 0xcc9e6157, 0x735ed3de, 0x4d4877c3, 0x3be5c9a1, + 0x5125a45d, 0xc758be4e, 0xb629e56c, 0x940a6e50, 0x0a1a39a3, 0x9ee7024a, 0x3a7c46fe, 0xf02b3706, + 0x01d2f9c7, 0xfdc99968, 0x6057a23e, 0x2b62c3d8, 0x9bb17170, 0xf81fbf93, 0x6df5bbbf, 0x7612429d, + 0xc2db3eb4, 0xa4f28b9d, 0x79ce31f4, 0x3c939ad7, 0x338b6baf, 0x6de3de5a, 0xb1da14c7, 0xe2a32030, + 0x8c775261, 0xc752cb70, 0xf46edcbe, 0xd20a8015, 0xaacda150, 0xaa0b6281, 0xc9b9be76, 0x354754ba, + 0x7f638387, 0xe0c6eedb, 0x712057cf, 0xa48e4a16, 0xbc932362, 0xc1a0f59d, 0x89109f05, 0x17068675, + 0x1bacc87e, 0xd91ac8c8, 0xa3b5709a, 0xed1ac3e8, 0x714278a5, 0xa9451cdd, 0xe0e93c6a, 0x8aec7e3a, + 0x247ae735, 0x215f25e0, 0x4cfa0065, 0x4d58c124, 0xd8b90a68, 0x50a580ac, 0xe6e320d8, 0x3178608c, + 0xdeb93c4f, 0x5a9e6114, 0xad74c571, 0x03cd6bb0, 0x8e65c3a5, 0x775d4172, 0x85957409, 0x63453926, + 0x70ae0eab, 0x011a6dc3, 0x3a33c774, 0xdc596528, 0x2960c368, 0x2ebc2b7b, 0x7174b0aa, 0x53d600a4, + 0x19a2f7ed, 0x399a3105, 0x83f0d5ba, 0x29563df8, 0x27644c78, 0x3f9b1899, 0x18cf9b80, 0x24655cfe, + 0x2c25e2d7, 0x94452ab3, 0xa2026c85, 0xcee0793a, 0x387f0d00, 0xa13d3aa3, 0x05c06c8b, 0x22686809, + 0x598646a7, 0xe8c8bbf2, 0xe19776b4, 0xc4613705, 0xa4627e28, 0x9893e642, 0x33430be7, 0x400b12f6, + 0x20f4f00d, 0x7edd6a8c, 0x6be1e461, 0xd803faec, 0x453843e6, 0x20982528, 0xb73a70a4, 0xc34d5832, + 0xe1b0a2b6, 0x145c3347, 0x877b99c7, 0x3ea82aa3, 0xa5f41285, 0xfd832406, 0xd8a03d2b, 0x5c3ffd66, + 0xd609d763, 0x03222a2a, 0x62144374, 0xb4da0da7, 0xdf5ea9b7, 0xdc147de6, 0x628efb38, 0xf246230d, + 0x5c9cd157, 0xa4c5ee05, 0x0794fa36, 0x8cf16669, 0x6883ce1d, 0xfbe14211, 0x54051e8b, 0x5320a9c0, + 0x3d312173, 0xba186e67, 0x6263a3d7, 0xeaefbe08, 0xe11aefaa, 0x694e8299, 0x53dcf454, 0x2317a17c, + 0x4fbee2f9, 0x47dcca46, 0xa699e3c0, 0x453f5f3e, 0x73b56b60, 0x3d0471aa, 0xe59b3d17, 0x5c923305, + 0xc70e0ea1, 0x2873ce8c, 0x2ce9bdd8, 0x9ee2e874, 0x2aa9d490, 0xe2c4a683, 0xa3b17005, 0x26e01402, + 0x6ec8b654, 0xd90d93d9, 0xf654002e, 0x64df074d, 0xde39be75, 0x7d1fe712, 0x81ffeffe, 0xbe721ede, + 0x60370393, 0xd0c03819, 0x1c543020, 0xefa425f7, 0x0bb49a09, 0xc7bb0f06, 0xe5a06f99, 0x8abba7de, + 0x961f9e38, 0xd2fd8d0d, 0x40aa8903, 0x215ad715, 0x9cdd8b5a, 0x6c103b8e, 0x984a5520, 0x0f29a6a0, + 0xb0c218ff, 0x75675dd1, 0xc71c0d16, 0x3688560d, 0x0af3e2bd, 0x8fcda9ba, 0x773436f2, 0x480be085, + 0xba51064d, 0xeba400ec, 0xe1638384, 0xc9c14f6d, 0xba179e7b, 0xa7494ea3, 0x363da874, 0x16e2e01e, + 0x9b6e6676, 0x34b079c4, 0x878278a5, 0xa231d211, 0xa713fac2, 0x2e3aeb61, 0xf4682281, 0x2070d92c, + 0xbde11d53, 0xabd6c4d4, 0x2c4f08e4, 0x42aa5866, 0xa235146c, 0x25fa17cb, 0xe48950b0, 0xb6fad4cb, + 0x58e442d0, 0x1d30e90b, 0xffc89f50, 0x72564a29, 0x2b8ea227, 0xd7fd81d7, 0x3b1cf852, 0xc2a98b22, + 0x8f8d4858, 0x949afd7c, 0x2a99477b, 0x181f32c3, 0x5b4d64e1, 0x7734fa08, 0xe1f4d761, 0xc9c3f541, + 0x0ab47a13, 0xa03e0b24, 0xc542760d, 0x6c4565ec, 0xe6504c3c, 0xa7dcd32f, 0x3baedd07, 0x5d3aa698, + 0x257b71c2, 0xa10dbe70, 0x4daedf4d, 0x1aa68ff9, 0x2569aa1d, 0xe44adbbb, 0xf1b7c5da, 0x34421341, + 0x668f25e0, 0xa85cf9f3, 0xa146846b, 0x0f3a0078, 0xdfb9ba4a, 0x147b0049, 0xee8755ae, 0xea08f6e7, + 0x540d16f0, 0x1d14e9b8, 0x1c30eff9, 0x296d90e4, 0xd9f53a1b, 0xcb13b3e4, 0x648c8601, 0x50bf8d1a, + 0x4ef658f5, 0x2595fed6, 0xdebee038, 0xf819a33d, 0xd3fb6a1a, 0xaecc368a, 0xee5b0487, 0x30e162e1, + 0x3c49c259, 0xeebb5f62, 0x17130f3a, 0xc513a4d3, 0x02bc5489, 0xc3a2fcdb, 0x0edc8128, 0xb70ff56f, + 0x26ff105c, 0x1aa3e974, 0xb35bcfcd, 0x1c60b39a, 0xd98c9287, 0x8dfa56ec, 0xcb59dae5, 0x0cafe07b, + 0xed651a32, 0x9fd1dad3, 0x3d0c1170, 0x1d2036e4, 0xd1930606, 0x0f049d94, 0x9f90793c, 0x52209bdd, + 0x5a513621, 0x2f8afb77, 0xe1dc0798, 0x3ab29012, 0x7810b307, 0xad027ba9, 0xe8c8830f, 0x124a25a2, + 0xfca23957, 0xa6782096, 0x4cc3d8bc, 0x22c84a66, 0x8c19de7e, 0xd896ce57, 0x74777c0b, 0x903ea413, + 0x4e171dc1, 0xd696aef6, 0x0bc4fa1b, 0xd5c61a8d, 0xc7c37989, 0x05a95b19, 0x80c3eb34, 0xf3a48a64, + 0x25e158fd, 0x6ca664ee, 0xee9fc758, 0x4fd6de23, 0x47fa4815, 0xc54ae62d, 0x769701c0, 0xc1bbd154, + 0x6bb3b381, 0x466eee22, 0xd8f7161a, 0xdd7df300, 0xff296422, 0xb7f076a5, 0x00e3a810, 0xe03f1532, + 0xfb528493, 0xb44acdea, 0x375aaeac, 0xd462df9e, 0xb34ce7ec, 0xb875e166, 0xd36b44f9, 0x815419a5, + 0xee28d5b1, 0xfd0e65d9, 0xb634e134, 0x4898a403, 0x032e2ac2, 0x27fc1f97, 0xd24ee493, 0x931b69e4, + 0xf88b9b98, 0x0711fb9c, 0xedb551f0, 0xd7666a73, 0x0160bedd, 0xfdcdad14, 0x3e068024, 0x125d806d, + 0x635a1357, 0x08a9ad1e, 0x15005f06, 0xcfc44864, 0xc118c7cf, 0x60a9173b, 0xd8479522, 0x814e3880, + 0x34ded47d, 0xb8a32051, 0x9658ccdb, 0xb3614df6, 0xf4f383cb, 0xb4660d98, 0x0184f2d5, 0x05b7fd8a, + 0xf6d74ff8, 0x0822caf6, 0x07d16863, 0x5785bbb1, 0x3171c586, 0xa7116846, 0x3b38784e, 0xafbf8569, + 0x1a3128e7, 0xf83f75d7, 0x7d3bc744, 0xbc317087, 0xa1688c50, 0xcfbc2fcc, 0xd23b880b, 0xcbb233be, + 0x4b86da6f, 0x179fac22, 0xc6b6759e, 0x6a213d9b, 0x00ae0989, 0xd42f3c0b, 0xa59a927a, 0x38642f43, + 0xf57edf59, 0x18537d93, 0x91c101a1, 0x2025c203, 0xa01821b4, 0x2fbb2195, 0xc77829c5, 0xc452acca, + 0x6e9f3284, 0xca6109d9, 0xc005beb6, 0x3c85db12, 0x169fc70e, 0x449ca9ed, 0x14c3ea16, 0x49799bcb, + 0x282d5ba9, 0xff20d3a6, 0xda126c44, 0xd60bb2ad, 0x0f06b7c7, 0x61d542f8, 0x34efe1b5, 0x6993c67c, + 0x6091ceb9, 0xa621878c, 0xa68639c7, 0x95bb19cd, 0xf7062116, 0x5b9e5e3a, 0x8fb39eea, 0xd758d900, + 0xce68d288, 0x261b206b, 0xe8ea2fdf, 0xf2325860, 0x53c04b9b, 0xd7f13243, 0x636021c7, 0xac45221a, + 0x53de4b4a, 0xf8c850dc, 0x6abb56c1, 0x1b8618a6, 0xb7a39ad8, 0xb304564e, 0xc52bc20d, 0x16fdc900, + 0xbf695b31, 0xf11917cc, 0x9c59cc72, 0x34afe46e, 0xca7481d7, 0x60e4ac40, 0xa167ddd4, 0x0b67a9a7, + 0x6920693d, 0x4e1e19ca, 0x45faa722, 0x85e8ce06, 0xf08b735c, 0x32c89486, 0xe7fe1d2e, 0xbc2792da, + 0xb5425048, 0xc43febf4, 0xe0ee6b75, 0x0a482c4b, 0x7bb0bcdd, 0xa377daf7, 0xd6e28c60, 0x098a612e, + 0x466a2e42, 0x52aa8f48, 0xef9d0188, 0x206f365a, 0x0c964aaa, 0x774a8f5c, 0x144ab8b8, 0xf0f05a87, + 0x05244879, 0x339dbc91, 0x8f61c339, 0x68c14515, 0xbb7a15fc, 0xb376ceda, 0xf83030f7, 0xc4278000, + 0x1cd1f25e, 0x890b0cad, 0x79ecb55b, 0xcbcbcf06, 0x4a91f2e7, 0xc5056db4, 0x598ba790, 0xe68debe5, + 0xbbe0700e, 0x58928b92, 0x2442adce, 0x9162ee1d, 0xb5632831, 0x531e475e, 0x35d07eba, 0x467735fe, + 0x62d13dba, 0xcdedbec4, 0x0ec2848a, 0x7f211e1c, 0xf2db5b67, 0x505c3c91, 0x5e51e9ae, 0x59556508, + 0xa1750914, 0x92dfd11a, 0x3d8e9344, 0xf6f8b245, 0x5f15ac22, 0x1caf58eb, 0x2aabb790, 0x52898c38, + 0x66d4dd45, 0x9118384e, 0x7c7b461b, 0x97700df4, 0x65b76820, 0x46293da6, 0xb3fbda3a, 0x5a8b73c2, + 0xaa091b43, 0x3c9a1074, 0x2874850d, 0x976b8d9a, 0xd31ade4b, 0x93680970, 0x1a5cb2f0, 0x5914340b, + 0x2f002a01, 0xdcffcaea, 0x2a66bb9c, 0x387add99, 0xfc26e69f, 0x7ab8351e, 0x2e86d3f1, 0x2b2bda15, + 0xfa78af6a, 0x2f1cabca, 0x6a32d4dc, 0x97342bfd, 0x5db8be6a, 0xde7c14ee, 0xbe9309c0, 0xb1c8f39f, + 0x8b01cd78, 0x9f1d5cce, 0xd6582e71, 0x9b9b238f, 0x53c28e1a, 0x78153094, 0x4fb8d63f, 0x1342b554, + 0x667bc822, 0xe8c65683, 0x473b1a2f, 0x4ad066c8, 0xe2712da2, 0x96188899, 0xb9fe72f5, 0x67819d94, + 0x67500d49, 0x6bd027ad, 0x33c4628b, 0x2ed69ba2, 0x6a089b9b, 0xb6f0ca4b, 0x40beb72e, 0x74790d35, + 0x4cf8e58e, 0x4cc0ddd9, 0x74f26578, 0x5719fa77, 0xb7e89352, 0xd1f798d1, 0x802d6586, 0x28d61db4, + 0x9cbe5c0d, 0xeb1ccc75, 0xa8a2b698, 0x50524be3, 0x58c9834b, 0x79cd752a, 0xf66e1599, 0x252330b1, + 0xa4a5ef01, 0x6f926235, 0x365e3de4, 0xf4f0487d, 0x83407716, 0x1eb0e9d6, 0x5820cab5, 0x20873910, + 0xdb3af321, 0xf2e5a11a, 0x9f1d29b6, 0x96143768, 0x9893913c, 0xe1956010, 0x5f15dcee, 0xe9b15d8d, + 0xdb0202c7, 0x2a9baa70, 0x98249b10, 0x9201b05a, 0x6ba958f3, 0x5ee62bdb, 0xb81ff50c, 0xc1cce4f9, + 0xbbdf9ca4, 0xcdc388ff, 0x6c9d17a3, 0x5593498a, 0x6ed8bd36, 0x4a17e0d5, 0xe6a63ac3, 0xab69b8b5, + 0xc897c522, 0x07613784, 0xf53aa4fd, 0x845faa61, 0x820bfb58, 0x20a99204, 0x2fc6a0de, 0xaaf80dd7, + 0xd7670bda, 0x1af9dc81, 0x6f8feb0e, 0xef457bfc, 0x52cf5390, 0x71875b42, 0x67b8b6a8, 0x7feba64a, + 0x3f2a8dfa, 0xff2f8992, 0x3a83e91e, 0xf16fe448, 0x3ce028d4, 0xa016b026, 0xef79bdcd, 0x3e435407, + 0xaa9ab6e6, 0x8a6ec5b6, 0x5e4794b5, 0x5d345f3e, 0x2e54e78f, 0xff2513c7, 0xff8cab90, 0xa8037319, + 0x12039148, 0x6b2f57a5, 0x794255fd, 0x46110397, 0x8168ccb4, 0x32494960, 0xed161246, 0x0530df92, + 0x1c9896c8, 0x62d5abc1, 0xc9e13200, 0x943f6fc3, 0x9d259b6d, 0xdb8b6746, 0xfef70a35, 0x63c5b1e1, + 0xa2a8ddcf, 0x220719a2, 0x50712771, 0x415aafb0, 0x64d8a4fa, 0xf1176bd2, 0x3de1e45d, 0x6483287b, + 0xb6ec74b4, 0x3150657a, 0x27a39372, 0x814962b4, 0xb57138ea, 0xfbbade37, 0x7ea31bd5, 0x338b9c4e, + 0x4ac7ed2b, 0x7bdc456a, 0xeb892350, 0xd1da14e5, 0x7efb67b1, 0x23278980, 0x1d610f95, 0xa6b11e5f, + 0x308c5c19, 0x419e31ab, 0x7b5d66a8, 0x3580f210, 0xc4918ed9, 0x1842bac2, 0x72eedb6d, 0x6dc39922, + 0x421cb986, 0xc3955e14, 0x1e528f5b, 0x2599433d, 0xf5b1224f, 0xee5acf27, 0x53db9325, 0x6b7585ec, + 0x7147388f, 0x139280e8, 0x1b526bc7, 0x6310c659, 0x0869f17a, 0xff554e9c, 0x8cccebf3, 0x1d2dff27, + 0xc099a1c9, 0x40172a6e, 0xe8cf901f, 0x0b03388a, 0x31c06747, 0x85b3a740, 0x1f99b6cb, 0xe84b581a, + 0xc4cbdd88, 0x36210a7e, 0x2e85a362, 0xa8fa46cb, 0x6f2172d9, 0x9d52fb08, 0x0c574103, 0x7b529fbc, + 0xd504b637, 0xe6a8ee22, 0x613342c0, 0xaa2fee32, 0x8330a97e, 0x9d0b52b7, 0x4c6149ba, 0x1f0ecd2c, + 0x2de96f80, 0xc417ee3c, 0x4bb4d735, 0x1783ecb8, 0xfa337ed5, 0xfbc30852, 0x4df8a418, 0x5f5c76b2, + 0x6179ace7, 0x48fa0fb5, 0xf68abfa1, 0x79490f27, 0x2a45c394, 0x4f060bca, 0x44894f5b, 0xbe850437, + 0x791c3332, 0x598f14c1, 0x44ce7f43, 0x410da83a, 0x2b53001b, 0x3e665fe5, 0x3b2afbe4, 0xc75654d4, + 0x12f4d85e, 0xec0ad9fb, 0xba088e1b, 0x3ee2b6cc, 0x48f1edfc, 0xd9fb66f2, 0x778b45ac, 0x9dd503e4, + 0x26c3eafc, 0x4a2691d1, 0x49496cfa, 0x8aa8bbeb, 0x1ec9aff8, 0xa4d64ffc, 0xde34d357, 0x15095fed, + 0xa54cd8c4, 0xa18ac227, 0xd76ea476, 0xc3935a67, 0x3c5940e9, 0xd1d190b4, 0x9887fbc9, 0xeb60b422, + 0x8eb34569, 0x36a98c8c, 0xd7dee346, 0x1cd955d8, 0x8090eca7, 0x5aa63450, 0xfabecb94, 0xb5368552, + 0xed1bdf1d, 0xae9c773b, 0x5510e7ae, 0x2580bec1, 0xf412a562, 0x166b8a14, 0x4f9a520a, 0x742e3683, + 0x6d3a491e, 0x7e746114, 0x5894970d, 0x5feff306, 0x9b9649c1, 0xddf4e5fd, 0x71303983, 0x424be7d7, + 0x7545f224, 0xbf3c7816, 0xc4273d8a, 0xb73cab40, 0x4ad16928, 0xeafaf654, 0x1ecdd519, 0x5ec7f545, + 0x8c992684, 0x4dcd195f, 0x5cafaf9c, 0xceb955fe, 0xe8cb3ca1, 0xfa0b8d35, 0x406eba9e, 0x7891415f, + 0xc6b2bb6e, 0x2e493231, 0x4b019fcf, 0x3e26db8c, 0x23d00ecf, 0x8e4482f8, 0x21ff61b0, 0x590d8134, + 0xdfa00155, 0x4cf0809d, 0x7dcd1234, 0x14e089c8, 0x6feebcdf, 0xa07dee4f, 0x7e9fc33b, 0xc45a8430, + 0xc452ec96, 0x1f9b46d3, 0x06fb9fd4, 0x825d7219, 0x0729750a, 0xd02cba31, 0x259db2e3, 0x358db26a, + 0x46359aaf, 0xbd7e1314, 0x41156007, 0xf86a1fcf, 0x5b8d8fc5, 0xf92881ca, 0x2ef55341, 0xee263ceb, + 0xc617c13d, 0x63262833, 0x02125376, 0x70371da6, 0xb287767c, 0x8cd1b845, 0x0161d2e2, 0x2f784751, + 0x36ffe9f3, 0x8258111e, 0xc33146e4, 0x59f84200, 0x23047066, 0x7ba9dc61, 0x791f07cb, 0xd592cb9c, + 0x751afd51, 0xea30d2d0, 0x4f4e7857, 0x9fd15439, 0x4a3d604b, 0x0603221f, 0x734d02be, 0x5c2e84ab, + 0xe3947241, 0x593c9769, 0x84364ab5, 0x6a7092e9, 0xe0a69591, 0x05d50348, 0xe5b634d2, 0xe8d6ce85, + 0x1f6d6d90, 0xf0399fbf, 0xe76ca0bc, 0x80719ebb, 0x8643aab2, 0xa673dca1, 0xe7156f34, 0x4fe0978a, + 0x80978b40, 0x6570b845, 0xf41c1874, 0xf6425214, 0x666d91b7, 0x9e653dcd, 0x3da9618f, 0x311b92d5, + 0x06b9a83a, 0x3666be52, 0x97660e56, 0xabfa7938, 0xf8625fae, 0x02de5c37, 0x47c0fcff, 0x39b9bdb8, + 0xec83d63f, 0x7ee3369a, 0x650b750c, 0xe5849477, 0x1037e3f7, 0x3ba2c616, 0xd3f621d5, 0xb58f8741, + 0x9562226d, 0xc86f860a, 0x14b30921, 0xfbcc0cb4, 0xe3775417, 0xe2e9f23d, 0x5810046b, 0xa10c505b, + 0x08628670, 0x740ef99d, 0x96f4ee19, 0x18e7f43a, 0xada67e58, 0x191faa9c, 0x717e1d0a, 0xb4f28735, + 0xfd401e6e, 0xbe268b6e, 0x1bf13df9, 0x7ae0bf27, 0xd5c6c325, 0x565fc4af, 0x7bec6d25, 0x0cc839e8, + 0x9a8b60fa, 0x896a63b9, 0xfbd903a6, 0xa2535de2, 0xf3f475a4, 0x0810d048, 0x39cead4b, 0xbba2b139, + 0x3400da57, 0xfc61e1f7, 0x9ee90404, 0x12417d39, 0x0512237e, 0x87fca9a0, 0xbfb4dd85, 0x5891b7d4, + 0xf4647807, 0xb8e55ac3, 0xa02f2cd7, 0xa21c3aae, 0x0a5733a2, 0x6994d585, 0xdbd75f96, 0x40e40016, + 0xd537f80e, 0x7ddbf235, 0x355a6cbc, 0xc930f45a, 0xb77e9a66, 0x5677c7cf, 0x73582237, 0x726ad89d, + 0x16903626, 0x21e0a322, 0x9db319a3, 0x485b1d67, 0xcf39002a, 0xc4f7d188, 0xfc8d55de, 0x434cb6dd, + 0x715087b1, 0xda6a7222, 0x81296816, 0x7c92bba3, 0x5df53974, 0xf0fe8889, 0x81b6f57a, 0xf995eece, + 0xe1510932, 0xbef15604, 0x19c338ac, 0xc35b48b7, 0x7cc4d0ad, 0x69b57ba1, 0xea48e96d, 0xcd0b9aed, + 0xb5abcdcd, 0xdcd1b627, 0x8028c520, 0xd3783da7, 0xbe431dcb, 0x7bd1129c, 0x242a3dbd, 0x86e6381d, + 0xcad0387f, 0x3f8bea2f, 0x79a48ae8, 0x98696a6b, 0xbd6bcff2, 0x76c2a073, 0x7d14b190, 0xc64ec310, + 0xf5e39170, 0x547fa942, 0xcd96baa4, 0x27a6d76b, 0xc187e378, 0x547b99e7, 0xce239936, 0x6e32bf5a, + 0xb6de4842, 0xb87a0c32, 0xd1d5dbae, 0x11ff3106, 0xf73b8c27, 0x40865de6, 0xe21ce69f, 0xcf6e3cb8, + 0xae8cf5b2, 0x90742781, 0x9f3fc5ba, 0x14eb5e6c, 0x976de8de, 0x09036877, 0x639472a2, 0xb150ae99, + 0x3305d17d, 0xb05d7e4f, 0x96a7d647, 0x938dda17, 0x808e953e, 0x25550898, 0xd342bc8a, 0x1d85e635, + 0x2a40ecbd, 0xd67da911, 0x94de4402, 0xf64bbd61, 0x6a5419ce, 0x1b4ab855, 0x1ef6669a, 0x72864f22, + 0x77fe3a75, 0x4d67e7a1, 0x5d1f200f, 0x4503b0ab, 0xfb4875ae, 0x6aab84fa, 0xe4e89444, 0x78eba507, + 0x60950006, 0xd3c149ed, 0xe3e0a7f4, 0x8b357e99, 0x279ad443, 0xb9a4ab22, 0x0e533e80, 0xa6b7780c, + 0xd8a0b7bf, 0x35e83857, 0x6e7798ea, 0x2cc9abf7, 0x488dd2bc, 0x4b6c86e1, 0x7f90737a, 0x69f9edbe, + 0xd32c03fa, 0x92aeb574, 0x7df2e60e, 0xc9e5691a, 0xe1a96154, 0x8d45242b, 0x0fa38315, 0xf701c6b3, + 0xa295a441, 0x32574550, 0x2666814b, 0x42823cf7, 0xce5a6588, 0x47b21140, 0xa8db9672, 0xbe152020, + 0x8139e7f4, 0x87f966bf, 0x96c78e67, 0x4e4894e9, 0x2429fae8, 0xf81bc713, 0x748016da, 0xb2c9b041, + 0x0bfdb6a9, 0x2493ab4d, 0xca84b264, 0xf3542cce, 0x32326235, 0x40ecf69b, 0x4b0f08f0, 0x7b430466, + 0x8f7cc36b, 0xa2bb954b, 0x2dd0e9fb, 0x1a0d79ab, 0x8b6ae60e, 0x0def2e00, 0x13234fb9, 0x9e0f23d1, + 0x71c05851, 0x08305726, 0x804a2f4d, 0x76a6d181, 0x9a32e05a, 0x8307b99e, 0x06d5ef3a, 0xbbcd4d27, + 0x650d9e8a, 0x6e98fa8a, 0x9f78309e, 0xf40e1027, 0x13728bf9, 0xdfd900bd, 0x8e484769, 0xc99fad67, + 0xd945120f, 0xce43b833, 0x476623be, 0xb5e0f8ed, 0x9a14212f, 0x21f09d2b, 0xab5fe826, 0xbcc85f34, + 0xa75b38c5, 0x72b10c57, 0xbca25839, 0xc5b6be2c, 0x30fb5e3c, 0xec1b6930, 0xd7d7c0f4, 0x35f32eeb, + 0x61a02747, 0xa344ef8d, 0x2350d26c, 0xcbadb6f5, 0xd19ccfb9, 0xbbe10fb8, 0xdc3a3456, 0x240109bc, + 0x8f8dd30b, 0xcb269920, 0x9d75ae68, 0x4d64cd90, 0xc54c4a9b, 0x553cd1f5, 0x9699c30a, 0x91973435, + 0xb81cd7a1, 0x063105e5, 0x95723100, 0x29861e8d, 0xde3eff8e, 0x5f2a4e26, 0xbfd48b2b, 0xa3ad92de, + 0x0576b52a, 0x53724c10, 0x2c24143a, 0x620dc28f, 0xba36bcf8, 0xaafc8868, 0xa804c4fe, 0x4cd7cf43, + 0x97e3ee08, 0x4a38ef67, 0xb10cfaaa, 0xf481c8cf, 0x001bdf20, 0xdee9790b, 0xfa513841, 0x91b17888, + 0x659ee11e, 0xf166a328, 0x88b1d04a, 0xb9ad9661, 0xa6a75b6a, 0xe1746d39, 0x886a46e9, 0x822287f3, + 0x1493fef7, 0x9933c68e, 0x2a1c3363, 0xc2a34708, 0x683362ce, 0x89dfb225, 0x48f6fc1e, 0xdda59710, + 0xd6547156, 0x6cb9ca76, 0xcd293e5e, 0x77a53a01, 0x0f766473, 0xe4440398, 0x87e99331, 0xa8f1434a, + 0xf814f189, 0x82b33e64, 0x1441414c, 0x2cb0e41f, 0xf40bca5d, 0x87eebff1, 0x07b9771e, 0x658ace3b, + 0x5c9f573d, 0x2fe44ef1, 0x852c7236, 0x69cc0d5f, 0x3c0de2a2, 0xde054669, 0xf7b69118, 0x4571c1bc, + 0x62b12f9d, 0xc4e1083a, 0x45ca536c, 0x4441c808, 0x3b04d6c2, 0x1d0eef7a, 0xad5a1e46, 0x9b1f2523, + 0x47869ca1, 0x822e5fe0, 0x00fa4e2c, 0x49944665, 0xd11f8e11, 0x31693854, 0x9893c4da, 0x43f8ece3, + 0x17097e74, 0x79dc0bc4, 0xc4d47663, 0x1e1e28e6, 0xb27aafc7, 0x492b15db, 0x055f6abc, 0x313db1c9, + 0x1e591138, 0x7733232c, 0xde411311, 0xbd0ea27f, 0x6739b2b3, 0x954faa35, 0x244fbe0b, 0xcda589ad, + 0x4ae1ceff, 0x23921abb, 0xe05f1274, 0x83a52dd3, 0x1027426c, 0x86ddc239, 0x1703a875, 0x1669ca3d, + 0xc14ea6e0, 0x20da4886, 0x52f7e676, 0xc6a919bc, 0x428a6b5b, 0x15cf2d68, 0xb00dc72f, 0x80111dd4, + 0xee7903e0, 0x76c15243, 0xe81ce124, 0x175da605, 0xce29e732, 0x8e2e8182, 0xea33034d, 0xbed53290, + 0x6ed489a9, 0xfbe3e9d7, 0xfc9f76a2, 0x741433b2, 0x77672988, 0x2dcb3199, 0x64b139be, 0x42c84d34, + 0x00f69166, 0x5b527106, 0x31c1348d, 0xb99946de, 0x5543b39a, 0x079b240f, 0xf0738f7f, 0x7d46172b, + 0xf73d183d, 0x107bc393, 0x06100cf4, 0xb449bc03, 0xfc572a1d, 0xbdb5c6e7, 0xb7e4b756, 0x90e5e3e9, + 0xafba7bdf, 0x66857fae, 0xae942c59, 0xcf2476c5, 0xf547c6fc, 0x79a498be, 0x312e1c73, 0x3ecd39ad, + 0x45fb7094, 0x42a54a7d, 0xf1ab30f8, 0x72bb2164, 0xa05660bf, 0x27162fe0, 0xaef4d41f, 0x63b754f8, + 0xb2217b82, 0x6e88c424, 0x8a76725d, 0x8abc978d, 0xb7c60745, 0x3b930a4f, 0x9c6a50ab, 0x4f95f9a4, + 0xa50672f8, 0xee6c426c, 0xed498d84, 0xc9cb32b2, 0xfbbb9b14, 0x7051eb1f, 0xb968c301, 0x6f0f54c4, + 0x7b463ec6, 0x66501fc4, 0x2b4a63ba, 0xd7713224, 0x686bed90, 0x752315ea, 0xd35ab9f5, 0xcde5743a, + 0x956884c5, 0xd7e081be, 0xdaa0b0ee, 0x92e59978, 0xb0cbbf02, 0x0b0cc50c, 0x70def1ea, 0x556e2266, + 0x7a39c335, 0x14174ccb, 0x2d831e69, 0x8222761b, 0x9df26bc0, 0x54a81940, 0x035fe02a, 0x66b586b5, + 0x01c8d0dd, 0xf2c8ae2a, 0x9ff7bbea, 0x6a49070d, 0x184b2231, 0xa5223b68, 0xaf9e3a0e, 0x58a079ac, + 0x27c481c1, 0x32c35474, 0xf392e8da, 0xc84b76d4, 0xbae033ee, 0x7775def5, 0x49fa0c72, 0x160d584d, + 0x00b66d0f, 0xd30ac472, 0x755cdfe3, 0xfb6fcfbe, 0x658139ad, 0x0b2424db, 0x54c27d26, 0x38a16832, + 0x1ba945ff, 0x42b57f24, 0xd11039e1, 0x63a4b5ae, 0x104264f0, 0x1905368d, 0x6bb450e0, 0xbf4bcace, + 0xc793da22, 0xdabda544, 0x1c3c871b, 0x6cd5f948, 0x9881a7ea, 0x71fd896e, 0xcded1193, 0x34cdd2bb, + 0x8e215500, 0x956da096, 0x03c2bbd0, 0x1318e2df, 0xd22afac2, 0xe7974ddf, 0x5ec2c6c8, 0x6b4a4298, + 0xc61eb907, 0x1cea1bd6, 0xd50732ac, 0x93588928, 0x9a619cdf, 0x689a8e73, 0x5416e16e, 0x5308be75, + 0xc4b57919, 0xb8ffa2e3, 0xe7e9d414, 0x14f87a30, 0xe1b83cd6, 0x7220af25, 0x3b42ec5a, 0x3efe70bf, + 0xa9e79394, 0x1ffc203e, 0x71b1a1dc, 0x6f1a6899, 0x7e9658c7, 0xe599f8c9, 0x93973444, 0x5dddfa8e, + 0xe742f507, 0xc12a684d, 0x42a90e47, 0x6b1e77a3, 0xc56a326a, 0xe328e70d, 0x433fa9c1, 0x1602bdc2, + 0x7bc88b66, 0xdd829b88, 0x5412e410, 0xe9b9b9ac, 0x54b2e63c, 0x6c0f51b9, 0x61ff860f, 0x6f629332, + 0x83db065c, 0x6f51efda, 0x91e64681, 0x77f31d00, 0xb4e8c279, 0x785679a6, 0xf6ddfecc, 0x6f62940c, + 0x6a6499e4, 0xbb6a4c3f, 0xbf72dbe8, 0x4ad8991f, 0xa220c958, 0x5002d3b6, 0xf12fa1b9, 0xb844affe, + 0xa45a247a, 0xdcd402eb, 0x54f54b5b, 0x952d2f39, 0x65f7e06e, 0xcb05fe56, 0x9d6a60b4, 0x44dd31f3, + 0x7c6da6e7, 0x5ec2e6c2, 0x198c327f, 0x11992687, 0x7744a728, 0xaa944d74, 0xa4b90511, 0xc563fb36, + 0x82d2c3cf, 0xef96974d, 0xd7759067, 0x523d9c31, 0x2cbf6cb7, 0x24741cd4, 0x05f126dc, 0xd6731f4d, + 0x8b41799f, 0x55ac6f4f, 0x3f163e8d, 0x88f11c73, 0x3ce61faa, 0x5695a503, 0xe08387e4, 0x4b7a21c3, + 0xc5776da6, 0x6d124138, 0x3f12b6d6, 0x7f725adb, 0xc2224211, 0x63655be3, 0x3c1bffad, 0x9502eb0e, + 0x0f3ed787, 0x1d87f550, 0xa680c476, 0x2b1c2dd3, 0xc842f7ac, 0xc14ea1ac, 0x7da7ff1f, 0xb47f9828, + 0x2e95df23, 0xe037e951, 0x5ad81773, 0x1d73917e, 0xf7ed2678, 0x49149725, 0xaf5c6b1f, 0xf288b333, + 0xb3fb895c, 0x08bf4a53, 0xea83f27a, 0x05a63526, 0x7034ac1b, 0xb54bc19a, 0xfe82b9a5, 0xa3fdd723, + 0x698a7cca, 0x9a4fc443, 0x75c3e2dc, 0x4dbabb8f, 0x34f86603, 0xcb752a52, 0x0a94dca1, 0xea5283ce, + 0xb5a8b44e, 0x5367e19f, 0x9c14229e, 0x98770015, 0xa5765af1, 0x27f4c4de, 0xff0a5fe5, 0x481ed5e7, + 0xc6b30900, 0xa17e960f, 0x02408ea9, 0xaa3cd01e, 0x43179f5d, 0x78aadd90, 0x8d11265f, 0x8c3811e5, + 0x72afaa05, 0xcb0233a9, 0x74e9d9ea, 0xa09bcb2a, 0x402b385d, 0x318f92cb, 0xc9273e82, 0x90e878af, + 0x67427add, 0x79ef88eb, 0x858d1747, 0xf8b96bf4, 0x99a0db5a, 0xd6ff49e3, 0x6c28d54c, 0x8ee63f69, + 0xa6fc2a04, 0x5febedbb, 0xb8da6812, 0x5ba84def, 0xdcbe4f95, 0x29d8c097, 0xf3fd7b24, 0x50bd5741, + 0xc22718f5, 0xf31458ad, 0xd980c889, 0xa97f068f, 0xcfd52ab7, 0xa39fc0c3, 0xd3ee457a, 0x4ffe2be5, + 0x467dc336, 0xe1974e66, 0x23b3a741, 0x67c0da8e, 0x2e7b08a7, 0x502cecfc, 0x1203243a, 0x2b34b81c, + 0xbeba97cb, 0x3e19aa05, 0x444449a8, 0x2af98f86, 0xa61e9445, 0x4d614967, 0xcaa52bca, 0x2452429d, + 0xaf3a504a, 0x5d04d485, 0x7f34a038, 0x2429264f, 0x06b3e739, 0x555ef5e2, 0x32fdac71, 0x9d78abf9, + 0xfa0a9ab9, 0x618c94b0, 0xb7068e66, 0xdad977cd, 0xce75dfe6, 0x48cccdd6, 0x0072f6f2, 0x61ea10ec, + 0x275f6f86, 0xeca07896, 0x026f2ed8, 0x5110099a, 0xcb8e3556, 0xb946e388, 0xe5aa7ce1, 0x78211a30, + 0x88a7b17b, 0x7b81c2b7, 0x89f94b4b, 0x035c3dad, 0xb40ad9be, 0x24905d1f, 0xdb4815af, 0x083e9e44, + 0xe47ff5b7, 0x4a1b57bc, 0x6592eec0, 0xaf127f25, 0x14da5c31, 0x10927d79, 0x23930bb0, 0x31da4c06, + 0x3b9ceedd, 0x9ddc9340, 0x37390fe3, 0x9f250486, 0x647d7eec, 0x84bce6f0, 0x5435132e, 0x61d1ae08, + 0x2fdd7f98, 0xa89fab13, 0x4b1c4f72, 0x7f8894d7, 0x0896753a, 0x50c4a731, 0x17afe212, 0xbfc75e0c, + 0x1d1ae03b, 0x343db2e3, 0xbf349725, 0x278a3c7d, 0xf3b7afaf, 0x483e93b3, 0x41843ded, 0xa86f2b27, + 0x2b8d6049, 0x2019b569, 0x1ea11795, 0x187d68b1, 0xab526bbe, 0xad104fa6, 0x47e435e4, 0x86726ef0, + 0x496474d4, 0x277d70c5, 0x23423ae5, 0x5eb43f63, 0xf103eb6d, 0xad686f14, 0x76e31cb0, 0xc29a475d, + 0x3a7a7596, 0x8889a515, 0xe151659a, 0xcb942683, 0x116325db, 0x04abf3d2, 0x36a8501d, 0x80c27afb, + 0xd835f669, 0x46162ad2, 0xe16064e8, 0xaf87f9c7, 0x5a75dcac, 0x3e8a5958, 0x5f061023, 0x77a6720d, + 0x31d6de01, 0x5bf0ba52, 0x09783ce3, 0x8db179b6, 0x6130d313, 0x8cfcc756, 0x72848cfe, 0xfa5a0ff2, + 0x89f370d2, 0x0dc09724, 0x0128693c, 0x54a4d249, 0xe2ef48a3, 0xd6340f22, 0xedf11964, 0xdae4a0db, + 0xaefc717b, 0x1e226646, 0xa436125d, 0xa4b7ed78, 0x98303ef0, 0x81748150, 0x489c38a0, 0xb3430387, + 0x360d47b0, 0xcb20ec0e, 0x9b6b5ce7, 0x90ab4050, 0x9703effb, 0x6f2356e6, 0x264ccb29, 0x90de78aa, + 0xc68a268e, 0x625163e9, 0x400e4513, 0x985e7153, 0xd6508110, 0xe2d4c5fe, 0x5025c206, 0x590939f3, + 0x45258a0d, 0xabfae3cc, 0x15981a84, 0xde4fa857, 0x00a6a228, 0x13d639e6, 0x89beec74, 0x23babd80, + 0x9a67541b, 0x2997e410, 0x38944539, 0x89e31b28, 0xbf5789c1, 0xe319c4b8, 0x3afa218f, 0x442f8d5e, + 0xce09e7bd, 0x1b5a7614, 0xab2d9d9d, 0x402f3d99, 0x351854ef, 0x8b3155f0, 0x0ae8ea9d, 0x61db5aff, + 0x527dded8, 0xdd709059, 0xe01cb6f1, 0x868ae3a5, 0x45a6065d, 0xd81c584b, 0x8aae2675, 0x9aaac1d0, + 0xc125744b, 0xef7e23fc, 0xc4fbbc0f, 0xaf0fe317, 0x160c9d86, 0xbc61a64e, 0x1389a817, 0xea1734d0, + 0x802511c5, 0x3f26d109, 0x2e035bb7, 0x7d4def12, 0xf3176d31, 0x3d046dd9, 0xc4e397dc, 0x0b9e3ef5, + 0x44f5d671, 0xb9bcee74, 0xd0811f06, 0x7034c206, 0x4bb68b3e, 0xaf27eb8b, 0xcad4c839, 0x3861c960, + 0x8d7247f0, 0x4b3b9698, 0x41acb8d4, 0x14ba5ec0, 0xe6bdae00, 0x72eedf22, 0x5822ba19, 0xfd9bae60, + 0x741a6b43, 0xd38305da, 0x27039bdd, 0xec06f96c, 0xbe39317d, 0x4944e87e, 0xccaeeb75, 0xdeb40b54, + 0x662e4a31, 0xef29d187, 0x34335961, 0x5ac7e322, 0x3d77bde7, 0xeadd5bd1, 0xd682db2c, 0x4a23aa3d, + 0x15eb6517, 0x5461c8cf, 0x8c98fd83, 0xcb6184e5, 0xdb290467, 0xadf930e1, 0x83a811dc, 0x2578a97c, + 0xe567a321, 0x46b27702, 0x6aed6c58, 0xd6b95346, 0x0c1589d2, 0xb1e1ff5f, 0x3b5fbb22, 0xe3aceac9, + 0x9bc46531, 0x8924425d, 0x9b7b3be9, 0x02d4955c, 0xd9837d0f, 0xdc4eb92b, 0xbe9f5513, 0xe3c1db11, + 0x2a50a591, 0xea6e4c9e, 0xcd020366, 0xc4ff9ba2, 0xec8260e6, 0x18477de7, 0xf9d50d39, 0x94ebc3ae, + 0x47369764, 0x1f0dfef4, 0x7e67a253, 0x6e8fe941, 0x0671a802, 0xcdf443f6, 0xc29d96d5, 0xcea754ca, + 0x89d33e52, 0x6e32abb8, 0x3ccc7a2a, 0xff7c7422, 0x2771d046, 0x1f931ba9, 0x6e967f31, 0x0ffb73db, + 0xae417432, 0xd1cccb21, 0x743c9952, 0x37777893, 0xe15f2786, 0x53c61e78, 0x31d88933, 0x462b862f, + 0x9a4d6542, 0x45e31a53, 0x7e646190, 0x43411bd4, 0xd79bff55, 0x4f2f4fe8, 0x503a7136, 0x5beccd9d, + 0x48d5f9a6, 0xed11e221, 0x414338e7, 0x37364c87, 0x2362a516, 0xd45f3888, 0x43789413, 0xeeeacfeb, + 0xb05b7a7e, 0x8ca044f3, 0x91d34e34, 0x80249897, 0x94e19f61, 0x6aa3e01b, 0x6509b122, 0x05c9d0da, + 0xa8444895, 0x2cd7d3f2, 0xaf488589, 0x64fec29f, 0x2d58dba7, 0x2dc578b4, 0x842a0a08, 0x6fd7c8e6, + 0x2aaa343e, 0xeb829d8d, 0x71ea449b, 0x07e23381, 0x73656f37, 0xaf95f133, 0xb0cede97, 0x85ca2337, + 0x5d73e028, 0x149dc39a, 0x0a26033c, 0xc0486a4c, 0x10c74acf, 0xed09ed34, 0x6fef9594, 0xe35f791d, + 0x7fe4d2dc, 0x536a9327, 0x10760c07, 0xcf40ef94, 0xb10d4bb6, 0xdf064182, 0xc528206f, 0x79f79195, + 0x085c9dec, 0xd3bd53e9, 0xbff53066, 0x5681e348, 0xdd01fc2e, 0x875b55e6, 0x7f42cc96, 0x1218ddaf, + 0xe249bb82, 0xfac37adb, 0x4bebf34e, 0x1529f9e1, 0xd5e2a4b0, 0x911162cc, 0x49c5a3fe, 0x92ab3742, + 0xfb79c7ab, 0x939a918f, 0x1dd9dc83, 0x47c94395, 0x7e967b14, 0xc44a8c5d, 0xc682c13b, 0xee3fab90, + 0xaf3821c8, 0xc276ed2e, 0x71a1ed38, 0x7cb6510c, 0xed918d84, 0xcc843c95, 0x7b2b9c4a, 0x56681af4, + 0xc86cfb69, 0xff1e3c8d, 0xbd294e60, 0x0bf065f3, 0x2f43f8fa, 0x20ca8c35, 0x2f1d928d, 0x40bfbb75, + 0x2238c0f5, 0x3ed2450b, 0xb833fa92, 0x93c2867c, 0x9cc0a52b, 0xd1f637c6, 0xfe19a887, 0xef816846, + 0xd440ec02, 0xeb11c99f, 0x1d674e45, 0x4570a85d, 0x765ca5e3, 0x16a3644e, 0xfabbc92a, 0x0839d7b7, + 0xb991ae7c, 0x4e428c24, 0x11a72050, 0x4383c6fd, 0x06d38c86, 0x79633fe2, 0xfbb28a31, 0x915f7734, + 0x8248fa36, 0xf5c05cd6, 0xe75b3af2, 0x5cd9559c, 0xc04252d8, 0xcfaee9b6, 0x0df16fe7, 0x8d8c775c, + 0xb5cae83e, 0xea8356f0, 0xfcc310fd, 0xb6d325a1, 0x2cfe625d, 0xe20cf356, 0xb8037c19, 0x563ae4fc, + 0xf649a2d9, 0x275faccb, 0xd2792881, 0x022377bb, 0x246076aa, 0xe2e79150, 0x3571ba33, 0xb21c649c, + 0x5481c4df, 0x2af7d3cf, 0x502da76b, 0xdc29f49f, 0x9b586965, 0x9fca00b6, 0xf0d52772, 0xaf5dd782, + 0xae580821, 0xcfbf5863, 0xe1fd3255, 0x09f2cbb9, 0xa1a078f1, 0xb6595382, 0xd4566635, 0xe5730505, + 0xd4591c64, 0x21168716, 0xd1f96b6d, 0x927cb46d, 0xea2a4515, 0xf4843286, 0x5c94145f, 0x6356cdc8, + 0x276594cb, 0x85414bca, 0x2c62bb01, 0x6300686e, 0x0fcf6b71, 0xb60ff5f6, 0x570c2aed, 0x188a6c12, + 0x22f935aa, 0xb10ef831, 0xcd4a76b1, 0x282a63e7, 0x8f192325, 0x38d94ea6, 0xa7407758, 0x6c1d776a, + 0x26f01864, 0xdc770e7f, 0xcb39ff85, 0xac36e019, 0x54b9dfa5, 0xbded7618, 0x6b04cc00, 0xea4dc899, + 0x966b6e91, 0xd6e8c550, 0x1781bbb2, 0x4fef4355, 0xe0a712bd, 0xe47dfcbd, 0xc1197622, 0xf1b5f873, + 0x17725f50, 0x665176a6, 0xa5b8ac2c, 0xa93d8b07, 0x02018c82, 0x5d599564, 0x28b62ddf, 0x6812f4ac, + 0xd1f490ff, 0x0b559350, 0x9e18c19e, 0x430a5168, 0x46c097d9, 0xbd1b9f54, 0x0651b470, 0x68e7aff4, + 0x80496505, 0xdddd8a25, 0x796db458, 0x0b18c73b, 0x7afa29b9, 0x46e2becc, 0x1917e629, 0xf2e55527, + 0x42742804, 0x427f427f, 0xeb456ec1, 0xe910a82b, 0x594d039b, 0xd83ba75f, 0xb0adcb1a, 0x7b5cd000, + 0xd472434c, 0x6c7299a2, 0xaed863ed, 0x2ca232a0, 0xfc7fd3f8, 0x75346760, 0xf5a4273f, 0x0ac52f5e, + 0x2d83ac2b, 0xbd6190ac, 0x6c828740, 0xa8115831, 0x3e462173, 0x53b45186, 0x30488c73, 0x2de39ea1, + 0x11599f4a, 0x87440326, 0x46260053, 0xa3faa9f7, 0x6e77a6f2, 0x52fd7178, 0xf2c11b33, 0xe7dece3e, + 0x215e1dd5, 0x2c1c14f8, 0xca9ade45, 0xf79bf883, 0x10b38279, 0xab065d6e, 0x815a0427, 0xb68dba16, + 0x9fbef0ee, 0x47b2563f, 0x1ae72247, 0xae976b29, 0x81cfce90, 0x473e1efb, 0x20604538, 0x6e236efe, + 0x7cd01146, 0x1d17b9d9, 0x2b161f7a, 0x0560b12c, 0x7dbf3af2, 0x90b6215d, 0x74cf3e3d, 0x94c2b772, + 0x57721034, 0x747f8786, 0x3d4365ca, 0x26715ccd, 0x2ae873d6, 0x8755f893, 0xc6cabc81, 0x5a4121f0, + 0x7b3defc0, 0x7d8b0dfc, 0x6525ec4b, 0x29398901, 0xc7183dd9, 0x9639a3b5, 0xec8a82ae, 0x3efe02b3, + 0x830fdf02, 0x876eeaca, 0x6e606b21, 0xa841543e, 0xb0ff50dd, 0x6746ae8f, 0x758116a2, 0xcfb047ed, + 0xbf9f9935, 0x3da06b29, 0x15ce529f, 0xed31f825, 0xe214c8fd, 0x4a96d967, 0xfda0c17a, 0x219540f2, + 0xdaf13e90, 0x23aac8ef, 0x5e76b219, 0x301650df, 0xfed1d0a4, 0x6a967030, 0x43a61ec5, 0xa7271cb0, + 0x1a66ea53, 0x176f6da2, 0x0bc099c8, 0x6063960a, 0x198fadc8, 0x87865ab2, 0xb6e0aa3c, 0x8b308eb4, + 0x5a2fe66b, 0xaa86c3dc, 0x346798e2, 0xf336d806, 0x6abbd3fe, 0x9eecf2b0, 0x02101917, 0x0fb6a059, + 0xe18ec671, 0x41b90e39, 0x8093818c, 0xe2e07ee5, 0x76d8813b, 0x6b89b1bd, 0x8938af9e, 0xcb21d6b3, + 0xc5a70a9a, 0x8d9adcea, 0xc71eb772, 0x59b87c39, 0x8060ce7d, 0xb91df218, 0x7bbe1310, 0x64a47c09, + 0x13b88a69, 0xb56c79dd, 0x4382a64f, 0x29351070, 0xb1faa552, 0x0a129f13, 0x8e9714c7, 0xa8f6fa13, + 0xb39f1d83, 0xfb0bcf47, 0xbe7765bc, 0xccc901b5, 0xc79f32fa, 0x612d2a5a, 0xfa22fc74, 0xc1a5dc06, + 0x9706e5d9, 0xee1537cf, 0x526d9b01, 0x413abb09, 0x14176755, 0x5f046a21, 0xa3a825f6, 0xb85b6379, + 0x2609ee22, 0xcbfc53a6, 0x2741c065, 0x67513ef4, 0x4d1b3b4b, 0x6302bcd8, 0xdda71ac3, 0x7ec6c5d4, + 0x9e970eb6, 0xd4b58292, 0x9ff3ec8e, 0xb009d3f6, 0x0dc97c6d, 0xb84d73a4, 0x56fdd863, 0x49b4982c, + 0xd8865b3f, 0x56cef5ed, 0x65be81f5, 0x8d4b43d9, 0x7ee03cf9, 0xd667caf8, 0xddeef2fb, 0xfcf78b04, + 0xe682e870, 0xe85469ae, 0xa07de440, 0x02363e69, 0x7a2b995e, 0x11f02856, 0x48e3b33f, 0x954e0098, + 0x7510e005, 0x75c6ab0d, 0x207a369b, 0x2b8c7a41, 0x93359c58, 0xb2199c9d, 0xa2f83c69, 0xb42a07be, + 0x499c5634, 0xca588203, 0xb601ffa5, 0x93cb217b, 0x087e64b9, 0x57ae8b1e, 0x0721aacc, 0x453ab170, + 0x6fc8705d, 0x05fdafe5, 0x64beba53, 0x67183aed, 0x99446c4a, 0x279a449e, 0x77ce597f, 0xee41d3cd, + 0xd6ce3eb1, 0x6e130bd5, 0x5dbbc0f5, 0x090cb13a, 0x981774e9, 0x6c08a459, 0x04cda1b4, 0x32377e7e, + 0x13732552, 0x80046990, 0x36ac81e3, 0x7662a471, 0xf74839f0, 0x72adcb00, 0x7cf70dbc, 0x8c8c0608, + 0x2b7717b1, 0x7cf9936f, 0x45dfce9a, 0x8b63872e, 0x296762cd, 0xfd27c9c8, 0x83e4f0e1, 0xef1ea71a, + 0x7c1d0c43, 0x50204943, 0x62fd4783, 0x34416a6b, 0x7254d044, 0x766a2566, 0x6e87431a, 0x516c9ef4, + 0x08e043b0, 0xdb547eaf, 0xe126f0df, 0x0e4db770, 0x70d7a287, 0x128e18e7, 0x990a9ca5, 0x5f34e3ba, + 0x2e11e93c, 0x1c77e4bb, 0x35f4b396, 0xe7c4adeb, 0x2faf8c4f, 0x6f582a4b, 0xdca6d137, 0x8800222e, + 0xefa0b67d, 0x343bcd92, 0x5a991cb9, 0x7d8e4665, 0x838b8064, 0xa2d4c6d6, 0x72397612, 0x1623b524, + 0x61af9708, 0x8b15b042, 0x015b0522, 0x995d62ee, 0x9c2437b3, 0xf3b6e33f, 0x4ff32da8, 0xb89009af, + 0x942511e2, 0x1920108c, 0x2ba607c9, 0x9ba65fef, 0xc8e19e75, 0xf4562308, 0xb5603a96, 0x9abd7487, + 0x09d52b55, 0xf8fd0efb, 0xa65e6713, 0xee09ec2b, 0x18efd4d8, 0xdfe0c15d, 0xc4de499b, 0x0fc71334, + 0x89e16b8b, 0x7fd66190, 0x032872c5, 0x14ccca0b, 0x2b419744, 0x62b2a69d, 0xf41d4291, 0xd3f346c5, + 0xc09530f0, 0xb6228b71, 0x8c81c930, 0x8cbde724, 0x5b4a1f3f, 0xc6aa6881, 0x30583f18, 0xea2d16e8, + 0x951dad01, 0xfbe01e63, 0xef272e5c, 0x347a2c9f, 0xd4146325, 0xab98c3a9, 0x36b8ff21, 0x63c109e8, + 0x24a9821c, 0x4103792c, 0x00342bf6, 0x512350d0, 0x20971d62, 0x03c6a35a, 0x53ebdde6, 0x442c599a, + 0xaf75a55e, 0xc5ecede8, 0x30dfd535, 0xd3ee3577, 0x8132c42b, 0x64f56588, 0xfb4708ea, 0x5d3481db, + 0x4197a9d2, 0xe16f6205, 0x8232bfc5, 0xb7a9ce67, 0x556fe71d, 0x90a0a00f, 0x3ebc35df, 0xa4462f3b, + 0x183faba4, 0x71582618, 0xe58c2e3d, 0xf23a2d8a, 0x45c14c33, 0x87cc86fb, 0x7c615b03, 0x9b22c551, + 0x6c9e3e7d, 0x758a235e, 0x83d3d5b4, 0xde67f61f, 0x7d994a01, 0x6a580039, 0x36ff71f9, 0x2c35fe91, + 0x819f7d21, 0x05531f82, 0x702c4e4e, 0x869fe44e, 0xc94e3a11, 0xb618a63e, 0x52a396bc, 0x12ace010, + 0x6f82c07d, 0xa8997fa0, 0x1952e3c7, 0x6318bb5b, 0xfbc55101, 0x17d4722d, 0x1ff411b7, 0xe74c6418, + 0xa6090211, 0xa49769b6, 0x95aaca85, 0x894adf12, 0x3edfd616, 0x5a71f362, 0x819d1e42, 0x2e093aa1, + 0x7720cbbb, 0xedfb0091, 0x201d956f, 0x3fbfbb04, 0xef5f2243, 0xdb00e2aa, 0x3279675f, 0x1545d8ba, + 0xcfa363cf, 0x52bc4d51, 0xa9b4562a, 0x3f9865b4, 0x7ea01bf6, 0x6fa41f76, 0xbab5b6ef, 0x6e6c233f, + 0x238bf6ce, 0x9c10896b, 0x9279859f, 0xb9a188f1, 0x42a40f21, 0x59e8c2b5, 0x0385d7be, 0xb0c45675, + 0xcb64e0da, 0xecf50ffe, 0xe2ae0606, 0x4083b4e4, 0x4f9393c1, 0x115ae551, 0x34017839, 0xa8b5d500, + 0xc908bddf, 0xdb71724a, 0x594b3be4, 0x6ca43918, 0xbe094fe1, 0xa72208ed, 0xc71a532b, 0xfaa14665, + 0xa9c2eee8, 0x5952aebf, 0x4c75d0ed, 0x4c46559f, 0xcbb372de, 0xed16da0b, 0x348fa7ee, 0xdd8edb1b, + 0xc9cc82a2, 0x8df8b39a, 0x1a0978ba, 0xb88fe5cb, 0xedfe6124, 0xc19cc5e9, 0x053554d3, 0xea789296, + 0x45dca407, 0x8a9b9952, 0x4b509c6d, 0x56e9f693, 0x51e851c5, 0x0afd4a12, 0xe95dafe0, 0x1ea963ba, + 0x5d3cb61a, 0xa6da91a0, 0xb8dc899d, 0xdd910e6a, 0x8c47f45b, 0x3fc8b969, 0xa7158b3c, 0x41055743, + 0xedaa4eb0, 0xe7f3efec, 0xc0dbf206, 0xb1247198, 0x6bdfcb8b, 0xa724f599, 0x971664ae, 0x9ff88fce, + 0xca55e5c1, 0x8f1dffab, 0x2f9932f6, 0x8a20d1b2, 0x6a6e492e, 0x5d773a1d, 0x52e7f10a, 0x99b08587, + 0x0d6ba7f5, 0x4d15cd7c, 0xd71990aa, 0xfd6b327c, 0x748bb322, 0x838bc247, 0x6163a0d9, 0xeb4705fd, + 0x454e5602, 0x198ff6e8, 0xa19b3a89, 0x5c1edb28, 0x7c3b909c, 0xf306670e, 0x1b2601d6, 0xcffba51c, + 0x799b4185, 0x06858c53, 0xd0c3510b, 0x818a5c0f, 0x8e96f8d3, 0x65e4b01b, 0x4a407d61, 0x3a52535d, + 0x05df5153, 0x7be708aa, 0xbab14621, 0x479e6538, 0xc09850e1, 0xd2939c9e, 0xe78a084c, 0x12e265ca, + 0x17342183, 0x51bdafc6, 0x6b3ef528, 0xc9b69e1b, 0x402590b7, 0xc5ab9f3e, 0x524855a1, 0x1f97b754, + 0x7520cb3a, 0x59ed92bf, 0x445c014c, 0xefd99a7a, 0xc317c85b, 0x7e3b7476, 0xdb36fba1, 0x107d8525, + 0xf8b7d4d9, 0x305ce129, 0x57d368cd, 0xbf23588d, 0x71dd18e8, 0xda7d194a, 0x811868c1, 0x4fade4aa, + 0x557f2658, 0x020f047d, 0x6fd0ea6b, 0xccbd9330, 0x2d7ce541, 0x719511ee, 0x38559722, 0x17dbbace, + 0xc5b74b47, 0x335722c8, 0x4e065614, 0x4a31e9da, 0x302676ec, 0xd2646693, 0x78d1c38c, 0xca700de0, + 0x44af9a2d, 0xb51a4ef7, 0x7410f7e6, 0x4a366264, 0x54b9f63e, 0xf782f5da, 0x55e46fe7, 0xc385e116, + 0x2895f307, 0x13fbfd2b, 0x1537db27, 0x8dd70bee, 0xab0678c3, 0x5ee06579, 0x096949ea, 0xb754e8bf, + 0xe7ae633e, 0x8c10a44b, 0x73611960, 0xbc8b53f4, 0x6fcd95de, 0x0a392459, 0xb87f1f4a, 0xb7a839c6, + 0x1a920df2, 0x2f20a71a, 0x2fbea333, 0x4225fcce, 0x0091d627, 0x79013aad, 0x72af7804, 0x38374e51, + 0x95c7f0cb, 0x34a4d7fb, 0xa60456f7, 0x09591d1a, 0x2d510dce, 0x01c73f1f, 0xd1663fbb, 0x2ab6a95e, + 0xca77d761, 0xe8fe76c9, 0xb8b87f25, 0xa12b913e, 0xa794dab8, 0xd67702d1, 0x226561eb, 0xe1cd6632, + 0xf8085cf7, 0x306f9331, 0x2114140c, 0x6df62e77, 0x2200997d, 0xe53d03a3, 0x74fb473a, 0x754822f6, + 0x6bd9c112, 0xe3d10d13, 0xc245bb7a, 0x94f2a3e6, 0x6bb85872, 0x56581a49, 0x0f0e66e2, 0x83cffc8b, + 0x372a827e, 0x0cec4724, 0xb3cceb22, 0xe648f2ee, 0x14f82ea6, 0x2c74fe2d, 0xea39b324, 0x0da46d2f, + 0x3168dc82, 0xf86e92a4, 0xf99d13d9, 0x887b4a5c, 0x7770cbac, 0xc3ef32ac, 0x0c200b7a, 0x4d1122c4, + 0x51a4a243, 0xafef743f, 0xf427307f, 0x1bb12712, 0x89324f00, 0xfba2cdc9, 0xb56aa87f, 0xc77b5495, + 0xe7bf24e2, 0xfac3d1e4, 0xb1590fe2, 0xa77e51e8, 0x78769359, 0x01d879f2, 0xc914d233, 0x750bac62, + 0x425bfffc, 0x44c909ca, 0x83812d8f, 0xe8df40b4, 0x8c977ff7, 0x93ab836d, 0xb2d1c5f3, 0x0d9112e1, + 0x7d7ef559, 0x78175652, 0x256d6f66, 0xc6a2f517, 0x69fb1d6f, 0x5bdb4d51, 0x314d2b45, 0xbc7225fb, + 0x2c3f437d, 0x49762ad6, 0xfced19da, 0xbef4a878, 0xbe5f473e, 0x8048664b, 0x7be0d04d, 0x243139a3, + 0xdbf4c792, 0xe0ccc955, 0x65bcfe9b, 0x593eba5e, 0xf4e430f6, 0x75b09191, 0x42bb5865, 0xee99494c, + 0x9afc1ca9, 0xf23a5a65, 0xa19ea99b, 0x11b104eb, 0x52622f45, 0x1fcb224b, 0x158b149c, 0x867c727d, + 0x4628d1ab, 0x72909203, 0x7ca71e26, 0x52d22e4c, 0xc3bca5f5, 0xe957eac5, 0xbb6e5945, 0x8db6f302, + 0x0bd5b201, 0x6402b788, 0x7e410095, 0x6aeab951, 0x07f45ab3, 0xe1d4fcea, 0x2f26733e, 0xc70f0e50, + 0xc9343664, 0xf10dda9b, 0x2058d88d, 0xcd3f431d, 0x3efe3523, 0x17e77aa0, 0x70ab1b1c, 0x3eefdfd2, + 0x1b512597, 0xb5ecfe0b, 0xd4133a9a, 0x7f57d198, 0xefe2d183, 0x4b9b2840, 0xdf378aea, 0x0382230e, + 0xcd89f5e8, 0xd9dafe6f, 0xbaaf02ce, 0xac4402de, 0xe2bd7638, 0x6de42092, 0xf59a6cd2, 0x55d5f4fa, + 0x6caa360b, 0x1467523b, 0xd6f39146, 0xfbc2d24a, 0x0f515223, 0xaa1bb9ef, 0x4cf9a834, 0xd4136caf, + 0x9cb95dde, 0x7780397d, 0xa3c893bc, 0x4421347d, 0x8e583179, 0xb885a86f, 0x3cc08714, 0xc4d25a1e, + 0x950283ea, 0x0d1b194c, 0xf7f04896, 0xe72fab1b, 0xc5bd4dca, 0xf998640b, 0x8dd3b96b, 0xa2f202ba, + 0xe05e8f5b, 0xd954ff47, 0x016f4f5e, 0x0c8b9cf8, 0xa26a8ab6, 0x3a9bf33f, 0xc09ca1b2, 0xaf3609f4, + 0x69cead7d, 0xaf7d24d4, 0xb2e76890, 0x1615b537, 0x6beb4a3c, 0x5a49e05b, 0x2730d21a, 0x92f34233, + 0x7f7a127a, 0xfc270553, 0x3f1e031a, 0xcc216966, 0x9b5d18f3, 0xa0ab3d6e, 0xd71f0de7, 0x4b4eb58f, + 0x0395f832, 0xb3a49ca9, 0x9f53e243, 0x07a22973, 0x841993d5, 0xed116629, 0x27a4165f, 0x10ef94c7, + 0xcacf941d, 0x0a06e2e0, 0x63f9237f, 0xed9a6a0a, 0xa48767e9, 0x719882a6, 0xd7e37c0b, 0xc7a5e8be, + 0xd26bfb19, 0xce29f77a, 0x206b0461, 0x8067b97b, 0x7431278b, 0xe32d40da, 0xc2b3d570, 0x8189dee9, + 0xdc5a5a13, 0xdfc10e7c, 0x75e3ac53, 0xd2e85dd8, 0x68a1b646, 0x91c444f6, 0xf1436e40, 0xdc661819, + 0xd4c3f432, 0xb36dafcc, 0xd3fb82fc, 0xd64db33d, 0x8bce92f6, 0x21f98deb, 0xe2e5886b, 0x21604d29, + 0x882f87f9, 0xc989e3ef, 0xc19fdc02, 0x7fd20d65, 0x1b02d7d2, 0x0b818c0d, 0x7bf083ee, 0x28ca675e, + 0xbc21f8ad, 0x25817d42, 0xb1f49e86, 0x6f4f9d46, 0x36b4b249, 0x371e59a7, 0x95731c1c, 0xd9a5c8a0, + 0x949e0ce1, 0x60c5804a, 0x9e64c1b4, 0xc1667dc3, 0xd8336e40, 0x9ad3b8a9, 0xae9071a0, 0x45b00739, + 0x1c61b90a, 0x82d0ddca, 0xf890cb4d, 0xd454c2db, 0xb1c86684, 0xcfca2ee3, 0xeeb428ae, 0x0ea9df5f, + 0x070107c1, 0x149da998, 0x829f59e7, 0x9e0fcaae, 0x2ec7fb1c, 0x821b5ab4, 0x78d86e69, 0x2f555fa6, + 0xd1e35ac4, 0x55df2075, 0xa3f2b61d, 0x083c5f05, 0xda0ba6cb, 0x4868f0f2, 0x344fa863, 0x3991ffc5, + 0xca9c9426, 0x1ae65962, 0x3c9041c5, 0x4fd156ed, 0x827819cf, 0x17ba9a13, 0x4217aac0, 0x2a76a250, + 0x29c398bc, 0xc408186f, 0x2c202d6c, 0x68d9a8d5, 0xe0e09148, 0x6e5c0a64, 0x413cc7b2, 0x84b1f4ee, + 0xde7b23d6, 0x4f9a91dd, 0xf6cffb82, 0x850b03cb, 0x698a5291, 0x7629d7fe, 0xac3521e0, 0xea342c2f, + 0x66a24c4a, 0xd683c720, 0xdef19da5, 0xe8daa47a, 0x5e422e1c, 0xb80c7fe2, 0x4ae87ac7, 0x1323252c, + 0xf60b4fca, 0x44038b2a, 0xa2214bdb, 0x2261e396, 0xdee0e5cf, 0x4ff8f752, 0xf42233cc, 0xc1377e3f, + 0xaae78bb4, 0x005ee95e, 0x187d262d, 0x8210897b, 0x4b97da50, 0x73aaba18, 0x726fb103, 0x2ada4171, + 0x500df784, 0x9a993e07, 0x444363f4, 0x41a7529b, 0x1c1b89ce, 0x3461ecb9, 0xa804d79b, 0x37026eef, + 0x74c82e93, 0xc2b0adba, 0xf5288dc0, 0x94c38ea6, 0x6dcba304, 0xa81ff844, 0xb28a1056, 0x8b0c1f2a, + 0xfca4a0d7, 0xb7a90ace, 0xcbd0a100, 0x21549612, 0x4be4018b, 0x71edde03, 0x6350d478, 0xad9fbd87, + 0xa687b76d, 0x7bc7c62b, 0x2c498528, 0xca160e6d, 0xd447c4b8, 0x20784aef, 0x38a5f5a3, 0x47b0432b, + 0xeda7717c, 0x8a73cdc9, 0xcb1d2470, 0xce3ad6bc, 0x03e93fc5, 0xa98cdf99, 0x1e851c69, 0xdf14cf05, + 0x9c22264e, 0x9091c75c, 0x9a6a8fc2, 0x08af15b9, 0x22f350bf, 0xce29a995, 0x2c86859d, 0xf54fa5f1, + 0x1c98d41a, 0xa076d9c4, 0x73cebd6b, 0x67b04dff, 0x1031226e, 0x58e13130, 0xbfeb1127, 0x14ea5241, + 0xae216070, 0xa087a1ba, 0x8698fc66, 0x5f8adf6a, 0xab731519, 0xb30e43bb, 0x93d85e85, 0x7d018a2f, + 0xac42ec29, 0x37286cec, 0x5a5e3638, 0x1b90d71a, 0x6763f2de, 0x682765e9, 0x76d4e385, 0x175ffc72, + 0x9905ca1b, 0x57ca64f6, 0xb07f2471, 0x30e2d582, 0xe4cab6e6, 0x3d5bd51a, 0xe0746d73, 0xf6da7be9, + 0xd067d18b, 0x624c026a, 0x80eef3ec, 0xba102f87, 0x8d875b31, 0x8d477c3a, 0x5b45e941, 0xfd0bdfd7, + 0x8deb1a70, 0x84aae7fb, 0xf97fecbd, 0xeb8c76b2, 0x90492602, 0xa8a205af, 0x4406340c, 0x2d480351, + 0xa98d2e43, 0x1fe0c5c6, 0x135b7e06, 0xab1ae93b, 0xa077c5d1, 0x40591677, 0xa3f380ca, 0x4137b57c, + 0x3d9babeb, 0x58e6f93d, 0x15ef37f8, 0x96bbb7ca, 0x2476556c, 0x835f3c03, 0x7f0e42a7, 0x8476a3dd, + 0xd68a25d3, 0xe105e826, 0xda0f9086, 0xc12c5a58, 0xc58d5c10, 0x54a4aea0, 0xda9fdb8b, 0xb9c98616, + 0x3692be94, 0x1b752504, 0x3870bc3b, 0x74c09f4b, 0xa4fa0992, 0x638520a4, 0xf6f05b18, 0xa749fa44, + 0x753a923b, 0xf16ca8d1, 0x574d797a, 0x203948c9, 0x7f5b5600, 0x157be63c, 0x96563073, 0x15dc8287, + 0x9f432c25, 0xc73e8994, 0xb0c0b2c0, 0x5ca70546, 0xc016b057, 0xe3edf228, 0x1d92f329, 0x9df3aa1a, + 0x3b58b1a6, 0xb6fa75c3, 0x28e93f1d, 0x274a3258, 0x999c2198, 0x368f2a96, 0xfc6eb956, 0x13bfab54, + 0xa3f527cc, 0x63d96bc7, 0xb862e55d, 0x9ea24938, 0xd34360f0, 0xbf4d126b, 0x25e1e32f, 0xdb1c5e97, + 0x740633b5, 0x211b5737, 0x4ea47bd4, 0xb9ec6132, 0xdb4f415f, 0x3d34157f, 0xbe0217dc, 0xadefabbb, + 0x1749e74a, 0x273212bb, 0xb12c7007, 0x2888a3da, 0xa805f9d3, 0x14c3b478, 0x62131ae2, 0x38c659d2, + 0xc98fefd3, 0x825c8e62, 0xc68e6e7a, 0x56ceeea6, 0xa196f511, 0xc2ed068b, 0xfd7d9060, 0xd23e4538, + 0x49248b33, 0xc2e3d7d2, 0x8db3b228, 0xad468f4a, 0xe08c541f, 0xf8835a81, 0x1580f65c, 0x1093f1a6, + 0x50b7994d, 0x7e36365a, 0x993b0868, 0xec846831, 0x969e0fdb, 0x0983e40d, 0x4dbcafaf, 0x8ddc7567, + 0x331d452f, 0x3011a786, 0xb3999043, 0x400b4586, 0x9ea097db, 0xe9a2d094, 0x95824c96, 0x480549e5, + 0xd5ef28ca, 0xe224902a, 0xbf7758ab, 0x493dd078, 0x18134016, 0x569a315f, 0x2e557831, 0xfaa31ad8, + 0x235fd269, 0xe307b740, 0xf8df7f82, 0x53a14bc4, 0xcc61163c, 0xf44e221a, 0x029e0795, 0x181a976a, + 0x5c0721ff, 0x280a344d, 0x181888c3, 0x2cf596b1, 0x3cf8c0a6, 0xfda350bc, 0x13af1609, 0x1590937d, + 0x1a3a4f96, 0xa91753ee, 0xc8ab00a8, 0x364a13b9, 0x3c1732e0, 0xc85a6bd0, 0xaf996f32, 0x18f7573b, + 0xf2d4f311, 0xe3de7039, 0x66609991, 0x6807ebf7, 0x7cc9d4b9, 0xd0008597, 0x64103e98, 0x819ca59e, + 0xd3aff08a, 0xd59cedb1, 0x6f025238, 0xffde9862, 0x66b6ab62, 0x9ef47ae6, 0x7649b332, 0x2a0f2f21, + 0x2443aef0, 0xd0c51282, 0x54c7ac79, 0x473a0d94, 0x3b0e3197, 0x38e729ee, 0x8a65f2a8, 0x25d610dc, + 0x76df09f2, 0x9937d381, 0x1a6dfa4c, 0x45989466, 0x1b163aa6, 0x890c8b8c, 0x9bc993e7, 0xd9810d2b, + 0xcebdd6e7, 0x3b033ecd, 0x0b5d7cad, 0xd28c1659, 0x7c95552e, 0xd0e4bc70, 0x7baa710f, 0xd130ee62, + 0x576b41bc, 0x0f402ee1, 0x266160b7, 0xb51658fa, 0x7b4e66a7, 0xb28c3118, 0x58528748, 0x0fd9ed1a, + 0x624fa0dd, 0xc6c65942, 0xad2369d4, 0x4c10f367, 0x728e992e, 0xdddf28d1, 0xc5220506, 0xa6175906, + 0x9e9e3016, 0x266e9bad, 0x26d67a28, 0x4a939612, 0xbc3861bb, 0xcb8a0fbb, 0x1690680b, 0x8055fc48, + 0xf7fad36f, 0x4020a644, 0x501ed0ab, 0x89e4e9b4, 0x9e451ba3, 0xe72eceef, 0x8a52c664, 0x2b0ea075, + 0x48b9afd1, 0x0240d4cc, 0x7bc854fd, 0xc4238f81, 0x05421c23, 0x5ca94b0b, 0xf49431e9, 0x6bb817e2, + 0xbb77688c, 0x938e86e0, 0x58b534f1, 0x67dcae91, 0x7d05daf0, 0xc24ee014, 0x9b723544, 0x8b629b2e, + 0xff8c830d, 0x69b4f6b9, 0x3e56e2c5, 0x3a18df45, 0x23d25d36, 0x92498ba6, 0xff931caa, 0x82c1c185, + 0x443e5d0b, 0x0de4c1ba, 0xae00d244, 0xd4dc30c8, 0x86305a1d, 0x232e5797, 0x2f708ae3, 0x5c87b60c, + 0x2735b8cd, 0xc158c60d, 0x6d920ab0, 0x9eddb435, 0xa07b6c66, 0xcb6cbc0d, 0xd2db1f47, 0x272ff214, + 0xf1481e70, 0xf11640f1, 0x728f615a, 0x4b71f2f4, 0x2b9505ff, 0xaf8a79c3, 0xfa125304, 0x48a678fc, + 0x8b9035c6, 0xed3e7def, 0xcd1f22e5, 0xb42ef045, 0x799132fe, 0x75c577fb, 0xf4257a01, 0x57a7668d, + 0x8e450f79, 0x1866b03c, 0x52ae0a04, 0x742475bd, 0xd8e3a654, 0xa5915574, 0x1a73604a, 0x9eb6ac03, + 0xbdbdf900, 0x2bf477d8, 0x37d72156, 0x78c8ce80, 0x56e9a3ff, 0x00eb4a7a, 0xa9054c7c, 0xc4872091, + 0xe0775c1e, 0xca34583d, 0xb1e1f75a, 0x4736d040, 0x7265cb93, 0x4252ea80, 0x2fac120f, 0xca4fc91f, + 0xd3edc9ac, 0xd0807f32, 0xa86c3612, 0x55995322, 0xb7c9d462, 0xd70bca46, 0xa9fee420, 0xa598982b, + 0x1466d61e, 0x3c9fe9a0, 0xa691c37f, 0x70ba705f, 0x6c083523, 0xf6e2d0b2, 0xf2b357a9, 0xa2e6ec19, + 0x4843fd1f, 0xe0f9d9cc, 0xa1ca41b1, 0x8279582a, 0x8baa8fea, 0xe5643be1, 0x8440b504, 0xfaf9a67a, + 0xb9fcd902, 0x228cb352, 0x13e81b68, 0x8065a042, 0x70972f6b, 0x7e745017, 0x8cc64b20, 0x418cdf80, + 0xd8a8232e, 0xe6140097, 0x74211332, 0x8b026de2, 0xbf0906f4, 0xe5372501, 0x40f544dc, 0x2bb8c601, + 0xfbebc986, 0x47c6ba23, 0xbad6a9d5, 0xca55f61b, 0x7deba4d8, 0x89078ed3, 0x9dd46b8f, 0xc6b98ac2, + 0xd46d7036, 0x0108c518, 0xf2edb272, 0x31fb1c3d, 0x542706d0, 0xec485876, 0x48c0891a, 0x61eab38e, + 0xa93319b0, 0x7911d015, 0x69b8f315, 0xa0dcac69, 0x8ead4871, 0x370a7366, 0x21fbd813, 0x66964dc5, + 0x2f23f8a7, 0xa8fa4abd, 0x09ce7803, 0x7ac2dd40, 0x3378a644, 0xb564db97, 0xca97afad, 0x8182f180, + 0x7efbb75e, 0x6af12e76, 0x328034d9, 0xc64d4d68, 0x1df6a38d, 0xa1c99ee8, 0xe1c6dc68, 0x79b6fc2f, + 0xf887f798, 0x45cae318, 0x416ca7f4, 0xc23e9e4e, 0xc47ee902, 0x01976369, 0x85675d77, 0x0ef762cc, + 0xeff2ed0b, 0x7dd54a0a, 0xda96c102, 0x8a7a0a84, 0xe71f2d38, 0xdf0ec442, 0xf4d0f1c7, 0xc0ee2920, + 0x6a0a0766, 0x5558a5a8, 0x731c8148, 0x2b0740ec, 0x6d6949bd, 0xfab78704, 0x6e56d08e, 0x75383de9, + 0xc869d4c1, 0x74201e19, 0xd4bad7c4, 0x51d62ee1, 0x3f1f3435, 0xe4fd7a0b, 0xb6d646f2, 0x4cd0ad09, + 0x919ffb98, 0x5adcd93b, 0x99215116, 0xc36eba1c, 0x3b99ee0a, 0x859df0af, 0x7b3d221f, 0x1ea39c41, + 0xe5f320c9, 0x79354847, 0x9c67bbe9, 0xd97cf65e, 0x16c8e605, 0xa379faf8, 0x800540a1, 0xd0663c7f, + 0x3e44c4a3, 0x25d0efa7, 0x0d707465, 0xb9258e6e, 0x0af6a4fb, 0xd460be76, 0xd0738a3e, 0x494fc494, + 0x826a13d1, 0xd2249180, 0x74e53cf6, 0x819b01ee, 0x78a483ab, 0x5f5ea81d, 0x13529fe5, 0xa298c3a7, + 0x87c3e1e4, 0x509d568f, 0x4d4e365b, 0xbb536e19, 0xe2f08518, 0x38d823cc, 0xe16e847f, 0x5de0a18d, + 0xe6cdc8da, 0x790d856d, 0x5781e014, 0x4cdf959a, 0x062de0a8, 0xa08460d2, 0x7c0f3f4b, 0x0d52f31f, + 0x966e5757, 0x79d8006e, 0x03133ae9, 0x3afcb21d, 0xac9e4383, 0xd6159a83, 0xe33fc61b, 0x921c6d2d, + 0x88b6feed, 0x8383c50b, 0x58faedb5, 0x5cc9fd33, 0xb72576b6, 0x9df7dd9f, 0x04cdc73a, 0x17582d19, + 0xa03f6cf0, 0xe9997b67, 0xe29a7b5d, 0x685cb3ac, 0x7a8b0253, 0xbed57baa, 0x61d9656f, 0xc387ab1d, + 0x93ef2fa3, 0xd44b7785, 0xbfe79df5, 0x3e6103e7, 0x44b0ea03, 0x25cdf7a1, 0xe4bd3a50, 0x0d80afaa, + 0xda3ec7ae, 0x37a4a3f6, 0x7a82b3b7, 0xf373798c, 0x5fb0adb5, 0x87f10029, 0x0188b1d2, 0x5532ba5e, + 0x82b203e8, 0xf0f9c444, 0xde9753b6, 0x343c6db8, 0xedad8a12, 0x446b35a2, 0x6c230eea, 0x5b5cf388, + 0xe1337641, 0x52c0baca, 0x4b921c61, 0xc349bd37, 0xe49fc94f, 0xaaa82c24, 0xe1380477, 0x839908b1, + 0xfb6cc4d4, 0x53635507, 0xbc4491fe, 0x9dfabe34, 0xa53337a6, 0x7450e762, 0x5e78e1f9, 0x6bb10313, + 0x573ce424, 0xe9de88df, 0xc9204ff7, 0x1351878e, 0xbe629583, 0xf4d1936d, 0xce737aa1, 0xf9dfc789, + 0x8d545472, 0xc477aadb, 0xb5781732, 0x965123e1, 0x71c1e284, 0x296eb35b, 0x6a55fd02, 0x0bdb9629, + 0x3ee11fdb, 0xced5723b, 0x20191f27, 0xcf46a7cb, 0x0360dce9, 0x2fb33109, 0x93533020, 0xa11b3e2f, + 0xd34f8657, 0x87d47bd0, 0xd538d2ee, 0xe01fc93b, 0x35a36637, 0x24c170b2, 0x86477e16, 0xc0b0e058, + 0x0f6d26b8, 0xa27f7794, 0x8a531f6d, 0xdc387cba, 0x61d33b86, 0x5490d983, 0x9ea8d752, 0x841b4d89, + 0xec2f820a, 0xa9e0f884, 0xbd06b8fb, 0x9e6c564c, 0x5f725316, 0x78f6abb4, 0x44fa6da1, 0x9264db23, + 0x191bb6ef, 0x892491f4, 0x756a4197, 0xec8f515b, 0x4e7ccaee, 0xb3188bd9, 0xb5306bf1, 0x179f3b21, + 0x527b76c7, 0x95f6ff97, 0x14d91486, 0x4bc9ed85, 0x384a0c95, 0x96c8412c, 0x3a59c466, 0x0402684e, + 0x859ec61b, 0x806af973, 0xb008d7ed, 0x91632b65, 0xfb0f8441, 0xe1651257, 0x73928183, 0x6d123701, + 0xba72abf3, 0x10839927, 0x655230f9, 0x75d103de, 0x13731a43, 0x589a2c6c, 0xe4460942, 0x1d4859b4, + 0x6f68f5e7, 0x56a84e1d, 0x5e790aa1, 0x29e16516, 0x3ffdb8a8, 0xa58111b7, 0xf7900197, 0x31da4100, + 0xbd784645, 0x60fa6604, 0x5efb8bb0, 0x27721302, 0xd49f4046, 0xcc4aadee, 0xff493ea9, 0x7b28bd74, + 0x07396146, 0x0c44f0c7, 0x667d5c04, 0x87002bb4, 0xecaa647a, 0xbd01200d, 0xcf1262be, 0x324f282d, + 0xd688d66c, 0xc764be03, 0x6bfc9256, 0xfd07dbcd, 0xfde42d5e, 0xaa8e9438, 0x57267165, 0xa55b7d67, + 0xf7280c77, 0x6d65e7ca, 0x8ff7985f, 0x82d17685, 0x91b2db7d, 0x80600bde, 0x859fb82d, 0x619eda57, + 0xd490fda5, 0xc9136f40, 0x1cbc72bb, 0xeaf207d4, 0x554291eb, 0x6c303081, 0x1473295c, 0x4736233d, + 0xe379385b, 0x4241b5bc, 0xd99aa584, 0x30a87877, 0xc177be5e, 0xc971188d, 0xac538ca4, 0x684152e2, + 0xc7a69f69, 0x7d3a508f, 0xe1ab1b11, 0xc6c1f7c8, 0x2e947a15, 0x587d7260, 0xd0b2a832, 0x0e8833d3, + 0x623f4d7d, 0x6eaf2b51, 0x691dea8c, 0x1ab0d542, 0x826c3a85, 0x5e19693a, 0xeaa3cf4f, 0x1580fcc6, + 0x4fbdc7f3, 0x5666f3b1, 0xe8b44fd0, 0x43226855, 0xad8fad6c, 0xf15d38cb, 0xfb14e9d2, 0xc3b8cf1b, + 0x06c85aee, 0x93387b0e, 0x35af65c6, 0x3705b36d, 0xda321d4d, 0xcb3bbecb, 0x03bc40a4, 0x54280c42, + 0xec4107f0, 0x7f521f27, 0x2cc639b2, 0xcb4cc803, 0x60577b2e, 0x8dccdcee, 0xf9b99bf4, 0xd558843f, + 0xd0683ef2, 0xf69667e7, 0xd7426361, 0x0b6df44f, 0x5a826e84, 0xbafd57e5, 0x98c992b2, 0x1f382526, + 0xf96bf011, 0xce5a5995, 0x5b2723ed, 0x69ab1dee, 0x91b212af, 0x73fa8f50, 0xf9838a6d, 0x37c8a6a3, + 0x447bbd2e, 0x95ce8311, 0xadf635b8, 0x90ca6c85, 0xa30989af, 0xf11d0c6d, 0x20ee3e53, 0x744beb7b, + 0xbd188921, 0x703108af, 0x4e33cb44, 0x42b6272c, 0x0f1bf63c, 0x8d241f78, 0xea5e7a16, 0xc260c964, + 0x3b6e5316, 0xf49978e8, 0x229f11ba, 0x4ed8b522, 0x7ee98552, 0xd05ad908, 0xf1e9b775, 0xb500d830, + 0x9ad39c62, 0x935d7ed6, 0xe7537fa7, 0xdddec52f, 0x62658ad4, 0xff272bb3, 0x86a5798f, 0x503e1bf6, + 0x03ecea02, 0x56549c4e, 0x067f20e5, 0xccdfa243, 0xc7742319, 0x058b159f, 0x581c93e5, 0xcf89368a, + 0x014e27b8, 0x6d2d658b, 0x88d2a9ad, 0x18b9ca4a, 0x974891c5, 0x5033ec2e, 0x52369539, 0x814ef69b, + 0xaee921fa, 0xf6fd08fd, 0x1de07c61, 0x12982be7, 0xbe281d34, 0xbd5632fd, 0x8458e89b, 0x6c75ee75, + 0x03774908, 0xff3e4bcd, 0x5452b061, 0xadc749b2, 0x5ef66206, 0xf7447083, 0xcc3d0e1c, 0xa6e26f81, + 0xaf8fe05a, 0x6f869b82, 0x05f2afc6, 0xbffa3006, 0xe64ac82d, 0x5fd30fdf, 0x212831ad, 0x24ebc228, + 0x90e87006, 0xeb5f9107, 0xbf2ed240, 0xd976a6d9, 0x6ea4decd, 0x3a6ec122, 0x6ccf1cc6, 0x46c23014, + 0xe9bf0114, 0xacad8dc5, 0x335eb2b9, 0x137040ab, 0x4361b2db, 0x621a6968, 0x76fbdde3, 0x159315ca, + 0x4788b797, 0xd05d05c0, 0xa752a811, 0x2ebc9b51, 0xf6d62913, 0x82589d67, 0xf38df8f0, 0x483f3370, + 0x25f3bee4, 0x9b67e677, 0x25e23cec, 0xb431a5b7, 0x7542eb5b, 0xa2f0f4a8, 0xb32bc54c, 0xb5fca3a3, + 0x559c9086, 0x5ceb5e28, 0xe5a77eae, 0xa6a42654, 0x5fef2761, 0x85a347d0, 0xe309850b, 0xe9db13db, + 0x90441668, 0xb9c775ba, 0xfe1ce2e6, 0x72a1ef62, 0x20a1d2b5, 0x6e4afd6c, 0x91533c99, 0x43ef63bf, + 0x31c7361c, 0xba1642ac, 0xe04a9386, 0xddb661d3, 0xa91c17e4, 0xf409f685, 0xa98085ed, 0x95f4a47f, + 0x5f95d1a0, 0x15f18688, 0xf8a48715, 0xbdc48a6c, 0xe0024bfa, 0xe63b725f, 0x1f1e6ced, 0x5e027a20, + 0xb79341d8, 0xdea66301, 0x84be0c80, 0x4a05d147, 0xfbd9691d, 0x357bdc31, 0xc99131b1, 0x04be6195, + 0xb49d5dc7, 0x5166126f, 0xfaeeac45, 0xc012a6a0, 0x24c2f1c5, 0x05e22dcd, 0x29b6d850, 0x98667e8a, + 0x8b4ebcaa, 0x3644ba8b, 0x55aaa880, 0xaf9a48c9, 0xf8c3d9c5, 0xdacbc7cc, 0x73154184, 0x322634f5, + 0xb5e85afd, 0xc097edaf, 0x3e47b556, 0xf7e9df1c, 0x28416307, 0xd9de83c7, 0x2617b143, 0x8f92c8d8, + 0x8b9df482, 0x9033833d, 0xf9a0d329, 0x77b0fb50, 0x702213cd, 0xfc19395b, 0x9dab01f3, 0x9cb6d7e3, + 0xf0a05816, 0xb265b41d, 0x14e97668, 0x9784b79c, 0x7fb9a316, 0x898cd32e, 0x46e94d2e, 0xc41aa311, + 0x26f1c6f8, 0xfa503fd3, 0xf3de3250, 0x536840e6, 0xfc9a5d11, 0x34aaf519, 0xbd81327a, 0x5884b22d, + 0xf9d8d277, 0xde063f33, 0xfa424086, 0x23f0dbcd, 0x194b1b21, 0x177f5b29, 0x874e4e82, 0xfc00ee92, + 0xd12452d3, 0xd8b67780, 0xebfc4a30, 0x73eb2542, 0x574719f2, 0x8413dca4, 0xdd031521, 0xdb3f5f9c, + 0x4e7b5581, 0x30a1096d, 0x8e094869, 0x1231dd13, 0xec1d7a0f, 0xf34d32ed, 0x6c77c13a, 0xb8378923, + 0xdcc9caf4, 0xf51d0287, 0xa5eb07fd, 0xd756c3d3, 0xa3a1bb1b, 0xfc7690f8, 0x2774fa84, 0xaddde6ff, + 0x2037d966, 0xcd2010ae, 0x4e7d529a, 0x4010c055, 0xa72f1a3f, 0xa9c2d509, 0x264a1cc9, 0x95a89069, + 0x528e1bb0, 0x00995e8e, 0xff7e515c, 0x6c5ffa93, 0x4e6729c9, 0xcbc332f6, 0x1eed69ab, 0x1f8b3ecd, + 0x7f172a8b, 0xe1098da2, 0xfc1ca1b6, 0xc49c23ce, 0xf604be8d, 0x0210f4a0, 0xc1b003ca, 0xce9d646f, + 0x5755fd7f, 0xfbb89d59, 0xa92ecf9b, 0x5fb5be92, 0x3e8c930f, 0xac8a10a5, 0x76e34b17, 0xd26b6b6d, + 0xf919466a, 0xda339627, 0xfbd63061, 0xb854f9a1, 0x9a35e8e1, 0xa0514ff4, 0x8d40baed, 0x5340b1a7, + 0x33357b31, 0x33d8976f, 0x1cd50a97, 0x588d2f1f, 0x4f3bf23c, 0x94ed63c9, 0x578fcc35, 0x04ce91b8, + 0xaa5c23d8, 0x76e2e4fc, 0xad8e11fe, 0x7cb3db4d, 0xeb832572, 0x098c86a4, 0xa0a5f919, 0x6ecbd3a5, + 0x36e8ccc8, 0x0c249619, 0x3edd03e0, 0x1b15c5b4, 0x899ddcc4, 0x3e127da8, 0x49858ca0, 0xb251dbbc, + 0xf84edccc, 0x460b8229, 0x6c89131a, 0x815b881b, 0x03cac728, 0x108b6f04, 0x72af2ded, 0x509365b4, + 0x6622e7b6, 0xd2fb58d9, 0xe346c51b, 0xaf5f501e, 0x7f226d63, 0xa7d0bdf7, 0xfa217005, 0x6684f9d8, + 0x65d4d61f, 0x1fd37a92, 0x2497d2ac, 0xdc194586, 0x3c075181, 0x97a89257, 0xe79b84ae, 0x2770c743, + 0xa1e76c9c, 0x6bd151c2, 0x258bedbb, 0x3b7b1081, 0xca54bd5b, 0x53918c9c, 0x26514374, 0x6f65f571, + 0xcb50aa5e, 0xad369c34, 0x08c9bdc2, 0x53cac0bf, 0xb0999a4e, 0xe8074be2, 0xc618579e, 0x442821b4, + 0x4c7af3ba, 0xd579e8ea, 0x5e3c8432, 0xb37ef959, 0x91cffbb5, 0x23e55499, 0x9f105a3e, 0xf4101496, + 0xb9e92ad1, 0xc1b9e809, 0x7749c7ec, 0xc4fe2599, 0x5eeb2195, 0xa3ef563a, 0xe93d4407, 0x065cc413, + 0x72d79d2d, 0x03f305d7, 0x0e7910e0, 0xc3b9fb93, 0x961e5804, 0x17d03924, 0xc117a946, 0x6e71a6b5, + 0x1ff7ed66, 0x756589d7, 0x7d188712, 0x0e34e728, 0x03f333d8, 0x75f2754d, 0x6e351905, 0x6c2d3385, + 0x2f3609e2, 0xf7e6cd87, 0x4fd5d0a6, 0x164a2ff4, 0xf3462f6a, 0x3a2e4451, 0xfc81311a, 0x03daa835, + 0x5c8c7a68, 0x04c972a2, 0xe218eb35, 0xa1ddc29a, 0xbb82d3d3, 0xb31fb697, 0xc775a04f, 0xf1ff5797, + 0x5e3e850b, 0xf3630a87, 0xe0a8234a, 0x56d89359, 0xb95cb14c, 0xd2ce787e, 0x30dee497, 0x5e537ea6, + 0x4f2a1622, 0xf3964fec, 0xa1a29775, 0x7e32b2af, 0x42933546, 0x669f41d2, 0x1ea0b736, 0x611d9ede, + 0xc4a7ef59, 0xc8a0fda2, 0x4a18ab0a, 0x5637a546, 0xb0dd2c03, 0x65990f61, 0xe893b813, 0x9a145388, + 0x135ffc3c, 0x4a679639, 0xa75e9fc9, 0xfaa98fb6, 0x304e9d86, 0xd3966bbc, 0x2037521f, 0x18deef6b, + 0x5822abb6, 0x9541be40, 0x438ca18a, 0x5b4df083, 0x73067521, 0xcd0c6d0f, 0x7ac1e072, 0xce42cb6b, + 0xdc6fc5ca, 0xc57679f4, 0x862b5af1, 0x20e4797b, 0x60ec8660, 0xd8c01a42, 0x2b2a0333, 0x758d61f6, + 0x544d73fb, 0x1b63d4f9, 0x61fdfc49, 0x269317c3, 0x0a15af16, 0x64ab3af4, 0xad1e7495, 0x2947b42c, + 0x3059989b, 0x6a7e699a, 0x4ae8aa15, 0x7263dbe3, 0x77ab18e8, 0x153d3405, 0x4bc74d88, 0xd193a3b8, + 0xcb460451, 0x49d4bf89, 0xe5681691, 0xc7a2eefa, 0xea77bef5, 0x909fd7a2, 0x1f154a1b, 0x3a240d0e, + 0x6c674c18, 0xaa08c88c, 0x40fe87e7, 0x791b6982, 0x1f03b7fa, 0xbbaf6513, 0x819dcfb2, 0xbfca121d, + 0x5b38cdd6, 0x95de2929, 0xc71832bf, 0x55f326b7, 0x515d6c91, 0xf9505343, 0x6c64c79f, 0x4942e09d, + 0x5ee00e6f, 0xc1dae37f, 0x8043ccca, 0xeaaf7995, 0x8d86013d, 0x6649808f, 0xa1e8814f, 0x70050e7f, + 0x39a8069b, 0x9ede80a2, 0x0064fc37, 0x3b0929d5, 0x51115ed4, 0x6ad78e20, 0x3758fba3, 0x79ec70de, + 0x401aacff, 0xdac23bc4, 0xa9f1dfb6, 0xfa2a6a14, 0xbe5dd39f, 0x7239671b, 0xc2397354, 0xe8481c8e, + 0x38565ff1, 0x672911f6, 0x7c7b37f9, 0x31fa935f, 0x75ed4fc6, 0x4d2c0f6d, 0xc9dec100, 0xcf1f8954, + 0x8597251b, 0x23c65acc, 0x6039512d, 0xc72abf5d, 0x45b4c761, 0x2cba27e2, 0xea272d5d, 0x34b53246, + 0xa975ec05, 0x28949740, 0x1289fbe6, 0x0b90c378, 0xb76eb492, 0xabb6f230, 0xacb91c99, 0x0200545e, + 0xfa146698, 0xe86af939, 0x040dfbcc, 0x1ec3a1c5, 0xa879af21, 0x2814825f, 0xc0693cec, 0x5c6b6cf2, + 0xe9659170, 0x7bad931b, 0xf3e7e13f, 0xe85b37c2, 0x85b3819b, 0x0b2dd047, 0x6b647eb5, 0x00411d63, + 0xfcb6ae63, 0x66fa72b9, 0x29e131b8, 0x621d8d82, 0xd78017cd, 0x9f42235c, 0x181869dc, 0xc3ede55a, + 0xbc15ccbb, 0x5634fa25, 0x7e8b89c2, 0xfa72068a, 0xbaf39fb3, 0xfa0cc141, 0x096a83d9, 0x966677eb, + 0xdbed08a3, 0x4012ea17, 0xcd5aa428, 0x69fcd9be, 0x0f0d3880, 0xbd9e8dc2, 0xf08e3946, 0xee566938, + 0x824e7b21, 0x11e55ede, 0xecf2f70c, 0xdaba1056, 0x38cd3ac8, 0x15eac9c3, 0x42faea18, 0x0449592f, + 0x31d1d86b, 0x7b9ca3f5, 0xa1a8a26d, 0x4257746d, 0x3ae1715a, 0x81e473c6, 0x3091a40c, 0x463dac0a, + 0x72ad4b95, 0xb7fc2252, 0x809a41bd, 0x7076ded0, 0xda1b3357, 0x5b26c259, 0x2daee913, 0xe3c9f2b7, + 0x7e9fc22e, 0x0cabd570, 0xbaf01625, 0x7b0dc52d, 0x003d1853, 0xefdcb586, 0x865b1962, 0x3c1c1687, + 0x1f5035cc, 0xa9c9e6db, 0x5c7e8cee, 0xfa65f058, 0xa61cd516, 0x99d44854, 0x3b48b8a1, 0xc266905a, + 0xf3df8c57, 0x653f1212, 0xfc144b0e, 0x7581a8a0, 0x65c4e318, 0x23ca53f7, 0xdb32a478, 0x23173c63, + 0x7b80c6da, 0xf351c2bd, 0xcaaf986d, 0xfcf67350, 0xc6d99918, 0x6e4e4649, 0xc512f2ae, 0xe493c6bb, + 0x0e367b4c, 0x9cf2c957, 0xbee93dd9, 0xdc782754, 0xfa5af4d2, 0x39633763, 0x61a2d2d6, 0x8b687ecc, + 0x68e8d908, 0x4ca4d696, 0x1e6cf461, 0x9a3ff8c3, 0x5ca06829, 0x8f215533, 0x57ccf41c, 0xe4669c3b, + 0xbfd0adac, 0x1457de71, 0x0bd6c4d9, 0xcab6710c, 0xdbe69b8b, 0x63f3aa13, 0x5eedbe6d, 0xe8e2fe1d, + 0x29fc354f, 0x75a7ad7b, 0x6ef611ed, 0xf4f63832, 0xd68bb704, 0x2ce51f06, 0x41613ed0, 0x122558e2, + 0xf0850086, 0x081de161, 0x140cfed3, 0x93cc9188, 0x38f85109, 0xb8615cf9, 0x119aa089, 0x26369733, + 0x2651ad78, 0x5dc69d7d, 0x41e80d60, 0x98f3b279, 0xc0b52e49, 0xb8d51fff, 0xfd915af3, 0x21a1a7b2, + 0x95181b6c, 0x5aee445d, 0xa0bd7f37, 0x0217b178, 0x1bd750f4, 0x8bdd5201, 0xdbb18463, 0x6b88568e, + 0xbf16e624, 0x5e5f3868, 0xa7987cf5, 0x44f8d307, 0x5f2e0579, 0xae2ed8c4, 0xa3efdae6, 0xfabcfbbf, + 0xc1e087bc, 0xbae97248, 0xf4ce7eba, 0x53b5ebd8, 0x084e32dc, 0x08028f11, 0x78d43a24, 0xbb33dc47, + 0xc43e44b5, 0xd7bf31af, 0xeb01fc54, 0x9fd783af, 0xec452718, 0x370626ba, 0x6667ad61, 0x006727b8, + 0xc735ff1a, 0xb8f20621, 0x4cad4e3f, 0xb8a4cda6, 0xc69a4e4d, 0x931089da, 0x70426fb0, 0xb40cb1f0, + 0x4f94dbc5, 0x53d08e32, 0x809edc77, 0xa2878940, 0x7fd8e15c, 0xd5277ba1, 0x678e25ba, 0x0c75199b, + 0x04e2d1da, 0x14f27e3f, 0xdb1d1b66, 0x9c543b72, 0x202a6c25, 0x9e683222, 0x495082e4, 0xf6f81b47, + 0x0ed10b29, 0x0ade4e6c, 0xf62160be, 0x3788ead7, 0x54eeabed, 0x67ff159f, 0xf5dbce38, 0x88ed15ce, + 0x145fef57, 0x5c92b468, 0x48d867a9, 0x8ea88379, 0x776896b1, 0xb7e07d59, 0x495d7874, 0x24bbd212, + 0xde0c2fa4, 0xb295db4b, 0x93589af7, 0xfb4bd665, 0x039e1583, 0x05d50738, 0x5af8cb75, 0xd9ec1add, + 0x3439f210, 0x8fff7c01, 0x7a03b49c, 0x55b1630d, 0xfa884eea, 0x02460418, 0xdcd9cf83, 0x70045030, + 0x340e1e82, 0x36b5ba6d, 0xfdbc1a43, 0x82caa234, 0x1fac7ce8, 0xca9caafc, 0xe36edbd6, 0xfff5db28, + 0xca1a5ce8, 0x6fd1ce11, 0x67a8c912, 0x5bb296d6, 0xd3a02fb9, 0xb9cd79e7, 0x1c92020a, 0x3c95e383, + 0xdf12fb5a, 0x5d6a4504, 0xef55b1d8, 0x94620d61, 0x009fc16e, 0x19c28dff, 0xf117c026, 0x06a14139, + 0xae0b336b, 0xab490221, 0x69569126, 0xfe49d325, 0x1c9fedc7, 0xdb7c29ad, 0x71f4abb6, 0x0c6fca61, + 0x7f115dc7, 0x6953b9f9, 0x5d64d7ca, 0xc98b2b37, 0x88b11c12, 0x3799d4f9, 0xa452645e, 0x51847da0, + 0x11bbf4b9, 0x92b9f076, 0xae1ecd89, 0x03dd3bdb, 0x5d9adf10, 0x049d0ca5, 0x7e7154d2, 0x7dee6114, + 0x7d2a476f, 0xa2f8bc49, 0xd1584edd, 0x3591efa9, 0xa446d8b5, 0x589b0513, 0x865ba0f4, 0x1a7034c2, + 0x5ff29d16, 0x8580d825, 0x463d7125, 0xc7270367, 0xee96fd7e, 0x6943d29a, 0xe0360cda, 0x0059db1b, + 0x32e7de61, 0x91a39891, 0x1d21a9d3, 0x2c4b7590, 0x6b6a82e0, 0x5fbb6a57, 0x5dbbff95, 0x42fba05b, + 0x2739c5ea, 0x5241c956, 0x7e5848cc, 0xecc1a86f, 0x1882042d, 0x192e7f9b, 0x924e3a82, 0xcfd74a82, + 0x50df5a4d, 0x8fa3366b, 0xb3268c21, 0x9b4b1cb7, 0xec9b12a6, 0x644cdb41, 0x718f5a5e, 0x646368ba, + 0x4e8219a5, 0xed0edfab, 0x92dbf0d8, 0xeaa58068, 0xccf99f53, 0x82b84835, 0x596f95b7, 0x1d833301, + 0x86e5d7a4, 0xe5510b23, 0xd262d229, 0x7691b78e, 0x961f9772, 0x764e6568, 0x0ac7bfab, 0x84dd4190, + 0x467113e7, 0x09c76286, 0xe639e379, 0xa8f05324, 0x62d2e6d5, 0x61aad0fc, 0xa7713afd, 0xd2522710, + 0x7ed9f91e, 0xe2c78cc8, 0x53add041, 0x480030fd, 0x8f9e5212, 0x9173146e, 0x8c41cb45, 0xe6259d24, + 0x8d12c9ac, 0x08e9344b, 0xc4600408, 0x1773945a, 0xedbd3560, 0xeed68bac, 0x41339aa6, 0x4c8c8094, + 0x64e28725, 0x5d22c689, 0xd59ef5d7, 0x7e3c1f56, 0x094e8910, 0x7c8f2bb3, 0x771c9033, 0x49c9392d, + 0x68f57c9c, 0x3f66c34a, 0x20243c8c, 0xbe627161, 0x9a5372ad, 0x50956a58, 0xab40e412, 0x38e63d18, + 0x691f3d30, 0x03c61c1b, 0x3b4303a6, 0x80294a99, 0xbc23e1bb, 0x61fa6304, 0x3e6b0c08, 0x7c618056, + 0x209bf7b8, 0xbd0b6278, 0x90dcfa0b, 0x4055abd9, 0x83dfd4d5, 0x3178581a, 0x9197626e, 0xe36da77f, + 0x76b56f9d, 0x577fcbda, 0x8e504a59, 0x8178d213, 0x6643b87c, 0x53062530, 0xb30ebff2, 0x145e9222, + 0x5fda3c94, 0x1c329f75, 0xb55c6415, 0x6657b573, 0x80202ab4, 0x49e3294e, 0x0da1e305, 0xde9f8292, + 0x3ef5b2a7, 0xdb8b3d39, 0xdad29da6, 0xb794c601, 0xc24f5473, 0xa41bf5f7, 0xb1f5e6f5, 0xeb1f95ea, + 0xa0f9cd8f, 0x1e27388f, 0x40528dcf, 0xd400b2b1, 0x5e379216, 0x4f935181, 0xc2a83042, 0x63aba0fd, + 0x22b8b083, 0x2ae3be98, 0xd5ea0aec, 0xf1ae7e83, 0x5bdd9a8b, 0xa1ca23f4, 0xc5055a2c, 0x2000fea1, + 0x18d7c0cf, 0x644a6bdf, 0x8fcc6a23, 0xfd17a8ab, 0xc36d6b18, 0xee201d33, 0xf8d3773f, 0x0f5334b6, + 0x79bc974d, 0x7576cbd6, 0x07d9c151, 0x48467269, 0x2832f6b0, 0x2309fc73, 0x5fec3e1a, 0xd96c7554, + 0x4ea1b0f5, 0x5adebe62, 0xdbea10db, 0xbae8d32e, 0xd135eabc, 0xd48e6d91, 0xfd14ba55, 0x36941582, + 0xc30a025a, 0xd8106313, 0x52a624e3, 0xca861133, 0x970a72b3, 0x127753bf, 0x051a9e62, 0xa75bb0cc, + 0xb233543a, 0x27fb2147, 0xe6847de6, 0xfa1310a3, 0xd84d6adb, 0x62b9edbe, 0x35fa69fc, 0x90925ab7, + 0xeca87b64, 0xc22217bb, 0xbf4ec5ac, 0xdd68806f, 0x39f024fc, 0x7fbe9d64, 0xec0a2744, 0x6cd49a5a, + 0x9628757e, 0xec506ec1, 0xdf8ac710, 0x89ad22b7, 0x4cdcd7bf, 0xedf92054, 0xc8acef1b, 0xfa0c0ef1, + 0x6083884e, 0x9ced6a6a, 0x229ba048, 0x3d12b048, 0xc31e886b, 0x975d0a53, 0xd6cfd890, 0xa4c91fa1, + 0xc56632be, 0x87df6984, 0xd4f775bd, 0x50eed223, 0x8b1d719b, 0x4acae771, 0xc7826e0a, 0xa1ada5b8, + 0x94e11897, 0xd2579697, 0xb0c953f0, 0xbe6b6387, 0x9eba2bf5, 0x2d42215c, 0x6f099410, 0x6460ad12, + 0xb329bd02, 0x02d7b64d, 0x546e8e8e, 0x8b19c660, 0x205103ff, 0xda905a92, 0x5f117952, 0x42265e74, + 0x9931f0af, 0x6d4382e9, 0xf5635a32, 0xff72685a, 0x8d6c14f7, 0x849b94ae, 0x91424801, 0x69ba31b1, + 0x9eba6197, 0xdf6380c2, 0x96f3877d, 0x3f657f4e, 0x4d696ba1, 0x9d3df13e, 0x18f5d927, 0x96c04f4f, + 0x46cc2b98, 0xca39c9aa, 0xdc52b712, 0x485673e5, 0x41a5dbf5, 0xc771530e, 0x4717c5b6, 0x02209716, + 0xc5a8a5f8, 0xeb467034, 0x3143bb06, 0x0c19a3b9, 0xfaa61490, 0x900e8432, 0xac720e54, 0x38707eb4, + 0x04004779, 0x44fab2ba, 0x65dab07c, 0x4681d25f, 0xa2b1fe65, 0xca02da62, 0x39d73d1b, 0xb1b66cf5, + 0xcee2163e, 0x98434c28, 0x0e1af2b5, 0xfb37e042, 0x695e5240, 0xa2725d30, 0x51dda644, 0x884afe6a, + 0x1ad47fb3, 0xd45e7d10, 0xbb4451cd, 0xdd5632aa, 0xd40ea7d4, 0xfbcecf17, 0x332a9787, 0x9ba708bb, + 0x326a4812, 0x9c6bf38e, 0x9dcc10d6, 0x10579814, 0xb6cb5bda, 0xec321f25, 0xc2903e05, 0x61dc56fa, + 0xb15651f2, 0xddf6564f, 0x0f034673, 0x99ec6ab2, 0x9a1dba29, 0x5033c5b7, 0xb4386608, 0xb4cb117e, + 0x5a78cea8, 0x246a50b5, 0x24507544, 0xfe4e9c15, 0x697b4a34, 0x65591fee, 0x3460b1d7, 0xac2c87c5, + 0x45d488cd, 0x8f7f4127, 0xae956f9d, 0x5b8b6c3d, 0xfe3baacf, 0x6164f608, 0x7f44b904, 0x2d6d8177, + 0xf23af9aa, 0x48b11402, 0x74f92bc0, 0x02e3c020, 0x76b8fe3a, 0x9e1ccd9d, 0xd3dce903, 0x23dad9f0, + 0x69a1f525, 0xa43b7a94, 0x7b4bbd60, 0x9b918406, 0x1ad26140, 0xbefe4886, 0x6853c628, 0x74daf012, + 0xb7753833, 0x38f99764, 0xbc4059b9, 0x709290a9, 0x9563772f, 0x1e3c0ea9, 0x1acb3cc9, 0xaa959f86, + 0x42b95068, 0xa238e063, 0xd0d70e35, 0x99a806ac, 0xcb15691b, 0x67abebed, 0x602a0664, 0xdc675994, + 0xc7474577, 0x17f781df, 0x3001b38a, 0xe3915862, 0xafd98324, 0x11191735, 0x445f848e, 0x9d9302d2, + 0x91e8abfb, 0x00524b4c, 0xa2b448bf, 0xae7c1572, 0x9a662ed5, 0x9d36c057, 0x8a17814f, 0x6b88aa6e, + 0x0dd9ecdd, 0xd1922861, 0x5b7ef0ae, 0x9bf6b882, 0x81f568b3, 0x91873f3a, 0x2f7f4bec, 0x72736566, + 0xd3741789, 0x10d3f215, 0x54f9a726, 0xc36d7540, 0xcd26c4bd, 0xb86a7d40, 0x2a318ba6, 0x7ad06549, + 0x689fe2e9, 0xb3de840e, 0x3dbd8c9b, 0x99485cd1, 0xec9b4ad5, 0x18827093, 0xfa8f6370, 0xd5c2d299, + 0x8deafcd5, 0xc191f268, 0x0d022e11, 0xe471d243, 0x7711f118, 0xe3943c19, 0x657676a1, 0xf924f3da, + 0x93cbda59, 0xeea63a33, 0x255b8f63, 0x21ae0005, 0xa4d94730, 0x4b2555e7, 0x0b1cd3ad, 0xad43121c, + 0xe054653d, 0x21b02f40, 0x1abff795, 0x15ef8311, 0x2a351ec6, 0x4e066b32, 0x9c618a87, 0x27049d23, + 0x40324afc, 0x7b01cb9e, 0x4038c0a1, 0x7ff3c3b7, 0x03a01775, 0x3b6a497e, 0x986dd3fb, 0x7932f8c5, + 0x9ed40118, 0x7755151a, 0x24fc9418, 0x28f79049, 0xa11eac5a, 0xda1e968a, 0x4c364154, 0x478ffe77, + 0x4f5e7074, 0x3b02e149, 0xb2434e9d, 0x2076db2c, 0x8a39babc, 0x8c315cc7, 0x30654acc, 0x2f45c404, + 0x69bfbfe1, 0x25c30882, 0xba41c338, 0x728a96a9, 0x6d47d340, 0xa9de5a4f, 0xcf069b4b, 0x23ebbfa0, + 0xc267e7af, 0x57bca9c3, 0x6dd3dade, 0x1d3c5ceb, 0x5d83a016, 0xe69945d6, 0xd2dd9293, 0xb013d715, + 0x5a18a592, 0xd6c606af, 0xb1b2711c, 0xcc6e3149, 0xf34f1ae6, 0x79fa7fab, 0x28c5ecec, 0x86f15e44, + 0x8f7b02d0, 0x2e03c101, 0xa03e9ddd, 0xfdf4b398, 0x42f567d5, 0x4e8c1150, 0x1bd38858, 0x983b2787, + 0x45df05d6, 0x596b0441, 0x2ba6fd80, 0x6c0f7287, 0x08dfeb1a, 0x2f4a9250, 0x0492cd18, 0xee2dfb66, + 0xb5393a92, 0xc1d4852f, 0xc1ec5708, 0xa414bba2, 0x960bca6d, 0xfedca16a, 0x0f679a80, 0xbc4d040a, + 0x99e77474, 0x6ee8bf3b, 0x99201d74, 0x12462da6, 0xb8257df1, 0x5259f859, 0x50f6e282, 0x75ca983a, + 0x2d73ec19, 0x129a556a, 0xfbab8ef6, 0x1e031f4a, 0xdf10d9ca, 0xbc013f50, 0x751bf56e, 0x45835018, + 0xf8789255, 0xbec1a045, 0x822d9b58, 0xc6c5456d, 0x9aae4c9e, 0x96a728b5, 0xda151325, 0x6153cc9e, + 0xa49ba883, 0xb29de3f4, 0x5fa16970, 0x2e12ecf3, 0x81ea5ca9, 0x4ec4da63, 0xf7adb4eb, 0x95e18e45, + 0x1614e8a5, 0x905792b4, 0x3364b8e2, 0x6cbbc30c, 0x7ebad609, 0x278863d0, 0xd99a4b2b, 0x5717d5d6, + 0xfa3fd315, 0xaec3712e, 0xa50adf6a, 0x519532b3, 0xb05d6ea3, 0x307c1232, 0xa4637086, 0x9c5ed789, + 0xcaa47e42, 0x151e188b, 0x21cf163b, 0x8bf6f0df, 0x34c9d391, 0xe9d5513e, 0xa6b34108, 0xf5b3669c, + 0x131777a5, 0x8990a2d7, 0x9165a00b, 0xda7ead4a, 0xa4d33275, 0xb66c545e, 0x566180fb, 0x0067fabb, + 0x7a589c09, 0x006c196f, 0x73309f64, 0x21b6a58d, 0x9acd0dda, 0x758d7431, 0xffe5d6da, 0xe49714af, + 0x60264580, 0x771cf88b, 0x5b91e147, 0x8d7e3ba3, 0x7653bc8f, 0x01d2679a, 0x932fae82, 0x7ae01959, + 0xe8fbaedf, 0xae67eaea, 0x7084cebc, 0x3b9b8da5, 0x86404362, 0x75c6dfa5, 0xbe906df3, 0x5646405e, + 0x9fa87c3d, 0x34b725b9, 0xc04b6e49, 0x997c3c41, 0xc0a5192d, 0xd696f441, 0xb902d2be, 0x11a1eb5c, + 0x16b699ba, 0x16236f06, 0xd68297f9, 0xaf8e6ab3, 0x9552ecc6, 0x1d4e92a0, 0xb7e6ecd3, 0x09c7481c, + 0x69d34c8b, 0x4b299a02, 0xf6db1a70, 0xfbbf2985, 0x43b3f606, 0x409906cc, 0x70bc8527, 0xff20a438, + 0xc2c4982a, 0x9a14793f, 0x164c522f, 0xd2ca6cbd, 0x229b40a7, 0x68c166dc, 0xd5e1b46d, 0x9ee0641a, + 0x571abf18, 0xd5cdb391, 0xd749608c, 0x6c3eec6f, 0x2ccb1aa6, 0xca87fd11, 0x2443fbe3, 0xd2815516, + 0xe717bf1c, 0xcca34020, 0x09a8d4a5, 0x91bf62f5, 0x6a242e37, 0xe996f430, 0x6171ebe2, 0xc57769b2, + 0x47389de3, 0x5185d7c0, 0xb398635e, 0x65ce28e8, 0xc08eb9a6, 0xf0750bf5, 0x6103378f, 0x1c432194, + 0xf9132b9a, 0x47a21036, 0x68f3e9ac, 0xe35f9d8b, 0x73ff05cf, 0x9f5dccaa, 0x3e31ab07, 0x73089e78, + 0x9b25d6be, 0x47ee25f7, 0x4a41153b, 0x33b856f5, 0x1b415094, 0x74bba826, 0xb31a82a0, 0x1a38f795, + 0x030f2077, 0x5e753dc5, 0xfce8ad54, 0x6213bfb0, 0x44f59419, 0xa92d9f76, 0x6fe8f814, 0x7428468b, + 0xb22d1be3, 0x0459834a, 0xc21a0890, 0x2a7332d2, 0x70abc7c9, 0xd20308d8, 0x5ab0b5b3, 0x4eb875b1, + 0x9622045f, 0xd9c42deb, 0x89462ab5, 0x5bc88848, 0x1cfbb4a7, 0xf91df4dd, 0x5e9c511b, 0xbe33a419, + 0xa566082d, 0xc711165f, 0x752b9181, 0x8725bf36, 0x9455a896, 0x757102f8, 0x59516a6f, 0x3f2b802f, + 0xb314288c, 0x4766ddaa, 0x6471d2db, 0xbe8c1eda, 0x7b87dddb, 0xb83f7026, 0x09377a93, 0x82de2893, + 0xdbd42289, 0x0dfeec74, 0x79b3bab5, 0x93a47d8f, 0xeaa184e9, 0xce90cf92, 0x3017df6d, 0xed77e860, + 0x29e354fd, 0x7f5fb8c6, 0x14605ff3, 0x0b8b9d9c, 0x04c023cf, 0x69aa84f2, 0x05bfa878, 0x9978abf4, + 0x0f9ab761, 0x66b6f6d3, 0x4014af28, 0x31c16df6, 0x5d600608, 0x59189106, 0xf2d94d5f, 0xfc98e442, + 0x6e2fb926, 0xbf90db91, 0xd97387f0, 0xc132f58d, 0x4d873992, 0x687236d5, 0x8837a3f2, 0x50782fe6, + 0x071daf80, 0x85aeb14b, 0xd285124e, 0x7fe7eb54, 0x86d360cc, 0x99f22ff3, 0x41f82209, 0x9c217595, + 0xc2c38072, 0xeac1aee4, 0x22cc2bbf, 0x6e0a7680, 0xb880a6e7, 0xea0dc11f, 0x5802384a, 0xff622048, + 0xf32debb2, 0x32075f6d, 0xcb88d2c7, 0x988f2f56, 0x84e43b62, 0xe424a03b, 0x195dd018, 0xadf63d0f, + 0x0f9c8085, 0x8725a191, 0xcab760b2, 0x35f0b374, 0x099bedd1, 0xee6b3d15, 0xd7601119, 0x163a0fd8, + 0xd8399f94, 0xd2f1ebe6, 0xe9afb54f, 0x2233f8f0, 0xe0a05b86, 0x5116685f, 0x58a20b30, 0xa4f80f79, + 0x15207b9a, 0x8806b0e3, 0x75a46a31, 0x474f549d, 0x17a40a73, 0xe6703306, 0xabc1e4e2, 0x496e0241, + 0x29f4f8d0, 0x2142f600, 0xaa858cfe, 0x0785d300, 0x7af47c84, 0xb4a1d037, 0xcccb220e, 0x7a135f84, + 0xa7850899, 0xe2cca292, 0x313520f3, 0xcb57fb85, 0x2bf35792, 0x366573e5, 0x403d9026, 0x1e0e2d19, + 0xe43c437f, 0xd3ab275b, 0x3a59db6e, 0xaea09493, 0xc221ee65, 0xb278879a, 0xe96163e7, 0xba4c4f77, + 0xc2ef83e8, 0x41958fd1, 0xb502aecd, 0x9a459d8e, 0xe1e9ed79, 0x7741cadc, 0xe984f0dd, 0xae7a2900, + 0x5840aea0, 0x900d0f24, 0x4f53960f, 0x12227093, 0x0971f6b0, 0xe2237495, 0xc287f0a0, 0x2c1a5a72, + 0x3119ab80, 0x1767fe9c, 0x779dc84e, 0xd2335037, 0x93d7ae29, 0xa2965e1d, 0x22f8cb0d, 0x0e9da685, + 0x4fa90f2c, 0xe9d8a087, 0x6178cb53, 0xa1a0cbfb, 0x89d9ab99, 0x591c9983, 0x10063778, 0x92034a2b, + 0x0517f3f6, 0x1592671c, 0xdedf6afa, 0x8dc47898, 0x89014fbd, 0xe5c0b113, 0x3e4da4cf, 0x6818ddc4, + 0xe92a8e88, 0x6f92f658, 0x2ad1d873, 0x25252fb7, 0x072e255f, 0x4624ff73, 0x5b99b273, 0xff55597e, + 0x1851fc1e, 0x8c726734, 0x2d7bbcda, 0x8231bee8, 0x6d001d37, 0x08b641e2, 0x0df88231, 0x04bf65c0, + 0xd48c5eac, 0x07af4ed0, 0xb4463e31, 0x6d18757e, 0xf122b897, 0xd679315e, 0x928d0d98, 0x9cb85396, + 0x7d73fc0f, 0xe507a537, 0x16a60ff5, 0xa9fd2b4f, 0x63201787, 0x122b4588, 0xf89f7212, 0x58e52599, + 0xb8cf65c3, 0xb90b338b, 0xdd6bc831, 0x18b79534, 0x27957862, 0xd528c1f1, 0xe71d2543, 0x921d760f, + 0xbcb0fcb9, 0x3c7e99d1, 0xf041e1e5, 0x4adf0d24, 0x6adbd0bb, 0xce233555, 0x631277c6, 0xfdc06b92, + 0x24330f72, 0xa81a94d3, 0xeee5b8ec, 0x5dad223b, 0xca4fa9d0, 0xe2175fa6, 0xe9080d82, 0xbf0c9da5, + 0xd14e6e48, 0xe1ca1366, 0xb33bbea0, 0x59943ea4, 0x532df150, 0x7b9b3eb3, 0xe698c154, 0x89029440, + 0x24679a7d, 0x4917d77a, 0x140f57db, 0x82efd770, 0x3e46381c, 0xc97a65e0, 0xa4a88c37, 0x7d78de91, + 0xcf43d906, 0x9bbf7823, 0xe2792a11, 0xa89de3ab, 0xa9b907c9, 0x6fbc82ba, 0x90465214, 0x576dffac, + 0x36decb5d, 0x61679893, 0xf34dbbe0, 0xb0544fd4, 0xe0d72b18, 0x261df842, 0x6c335a29, 0xb3173f00, + 0x29cd0389, 0x5b602b1c, 0x10fb394c, 0x47974fcc, 0xbc1709c3, 0xb6e7d2aa, 0x2104f2af, 0xaee617cd, + 0x5f84f856, 0x03c2d393, 0xcf31c79a, 0xef990533, 0x4b5c3edb, 0x8809609e, 0x383d4278, 0x3fe768d8, + 0x72a219d9, 0x725c1ed4, 0xb4774a4c, 0xba5c2213, 0x9fd73581, 0x393dcd36, 0xf74ba23c, 0x6d938c94, + 0x72c71a6f, 0x8f65c1d1, 0xbe01956c, 0xd35c635a, 0xa41c3e05, 0x5e204cb4, 0x85d2501f, 0xac2447d7, + 0xfb34a7d2, 0x667cfa60, 0xd050fdc2, 0x092362b5, 0xfc6e48b9, 0xdede0c26, 0x943bb6d1, 0x4fadcc21, + 0x168556ec, 0xf4f34b00, 0x4473a31f, 0x03057529, 0xa7f02eda, 0x14533320, 0x515ba937, 0x23d4a00e, + 0xb0696ccb, 0x442bf5c4, 0x42bc19af, 0xb3b429fa, 0xad8427c0, 0xcff5641a, 0x9d2cef49, 0x897f61df, + 0xcb66be54, 0xbfbde85b, 0x46380916, 0x8dd87b10, 0x5b710170, 0xf32cc697, 0x726c2ae9, 0xc46cf8c5, + 0xf8374023, 0xd4d45294, 0xbaec6180, 0xc3925546, 0x40befddd, 0xb0e91f64, 0xa5d7c34b, 0x42396903, + 0xe514ddd3, 0x73ec54f5, 0xd923e84a, 0xfa9f4ab7, 0xc482977e, 0xa071695c, 0x9030993e, 0x88420753, + 0xd10638b5, 0x4c3dd380, 0xec704490, 0x2a9b308d, 0x71a787e9, 0xb44ae504, 0xd4a5f176, 0xdd2fc3bd, + 0xa736d9e2, 0xab5a605e, 0xc70b2b89, 0xdf885499, 0x74881447, 0x6110895d, 0xcd355c9e, 0x3b1f7b1c, + 0x7507d92d, 0x6ed24105, 0x80017bf0, 0xc04ec6c7, 0x183ba10c, 0x9e281ab2, 0xd0956f25, 0x46ed618c, + 0x8911c19c, 0x4c229e49, 0x3f3fdbc3, 0xa3d3c788, 0xc28b0e04, 0x469e3291, 0xf03b9121, 0xf8131720, + 0x5e33217a, 0x4a46fb1b, 0x3a4234ef, 0x25e50a89, 0xa7b86c8d, 0x7d81d399, 0x48a5a1e8, 0x5f732bed, + 0xe85bf45c, 0x5e6e40ee, 0x73e33dc3, 0x78945fdf, 0xc74371c7, 0x4740c4bc, 0x26e6a560, 0xcb95dab3, + 0x06eda605, 0x83d5e1fe, 0x7175c819, 0xc8752d8b, 0x3bb8d3c2, 0x1bcd2c50, 0xb746b601, 0xc985ab96, + 0x25679fb2, 0xb20d8ab0, 0x5cb45b76, 0xcaa3ad65, 0xaf89fb3d, 0xdb374621, 0xe3f13bfb, 0x1f9db9c2, + 0x307a41cc, 0xea600ef4, 0x77f34616, 0x07e0a5e5, 0x6ca22c62, 0xf3cdf989, 0x36c13365, 0x6e3017d7, + 0x8cc682e6, 0xbad7f2e8, 0x87ae8e92, 0x3bcfe9d2, 0x3b3a3b3a, 0xd76b1f84, 0xc8762bf6, 0x2e658948, + 0x1ab7d6bc, 0x7d401420, 0xe75cd6ca, 0x62d423ce, 0x6da96d04, 0xad9ae963, 0x5836cee2, 0xb36e402b, + 0x2fc2b59b, 0x4c6193cf, 0x0ea59c5a, 0xd49bc10e, 0xd0c48834, 0x1657192b, 0x53e62c67, 0xf6efe6aa, + 0x6b4c6c7d, 0x8c25be01, 0x6bd7179f, 0xb05f7e32, 0x5c01b1ca, 0x162dbf46, 0x18387812, 0x738ac810, + 0xae7c213a, 0x52b16c64, 0xacc4e0b5, 0x291b3bd9, 0x2128ada4, 0xd816265a, 0xb6beb3f7, 0x009de751, + 0xf13eeca6, 0xb1750918, 0x521e9566, 0x24bd97b4, 0x43cc9a30, 0xa7609392, 0x56f1a7e6, 0xa96c8301, + 0x26a15129, 0xe0dd5e19, 0xa67dca69, 0x544485fa, 0xbdaa8654, 0xcd138880, 0x50bcdeab, 0x029969ea, + 0x709e606e, 0xbec023ed, 0xd63cf900, 0xbb03bf51, 0x11822111, 0xfb4b197d, 0x09984b07, 0xd78bb802, + 0x43b8a395, 0xf9544b46, 0x017750c2, 0x3b7b642e, 0xe6629754, 0x78af571b, 0x85be1d1f, 0x31dd2356, + 0xc382f84a, 0x302f027c, 0x312e1d6c, 0x105d0d73, 0x48ac35ee, 0x779fd56f, 0xce9997e9, 0x75cedd48, + 0x72b7db2e, 0xcfbe3bfb, 0x4dcff65a, 0x8e3a6e41, 0x47e0441e, 0x3789e2fd, 0xf6f0e714, 0xeb253513, + 0x5f56276f, 0x5cd5c313, 0x34e030a6, 0x1ad515bf, 0x8caabec2, 0xbd404931, 0xa6a686e8, 0x13afeb90, + 0x7e4d421c, 0x14ebc64e, 0x8cd97243, 0x17cca25a, 0xdb7bcf35, 0xde1d7212, 0xf5a65b00, 0x608b4630, + 0xf5196196, 0x80a8d9cd, 0x54dc0d8a, 0x77df994c, 0x9d5e865a, 0xb7eeeb6c, 0x3a4e97d6, 0xa2522bb5, + 0x14c7ca0c, 0x072e2d3b, 0xca76692d, 0x0974d616, 0x1bf032c6, 0xd14f05fb, 0x33deaacd, 0x93a61f79, + 0xd126b28d, 0x19562925, 0xedb3a4c1, 0xfa3d2904, 0x085ece07, 0xa3e9d689, 0x31312478, 0x2f546988, + 0xafd935e2, 0x88cd4bc0, 0x85c1c464, 0x72ae0caa, 0xd20d396d, 0x564b14f1, 0x8f372b5c, 0x24365e23, + 0x16c05e24, 0x200ce62f, 0x2e17474d, 0xd386e31b, 0x65f26e36, 0x134effcc, 0x619ef3df, 0xe0d80e5a, + 0xfcdfbdbc, 0x26ee146c, 0x23382ae2, 0x49377f08, 0x6b734328, 0x0b085cb0, 0xf3d4ed06, 0x2f764727, + 0x15c27aae, 0x83342aa2, 0x4f4157ed, 0x14a88d01, 0x6c186255, 0x474b4647, 0x2cea78ab, 0xc87b1f9b, + 0xf60e9582, 0xb569afa0, 0x0168a2e8, 0x1b3dbeaf, 0x6e31cc38, 0x1318748b, 0xcc11b524, 0x81fb8fe3, + 0x149ac803, 0xa00693c3, 0x65fba983, 0x1db9a1d8, 0x9e5f3719, 0x511f45f8, 0x7ba2a28f, 0xd7a9f6f5, + 0xec2cacc3, 0x857ed42b, 0xf679858b, 0xa66c69c2, 0x8d6692cd, 0xd7322550, 0x60912f96, 0x6832f7bd, + 0x51496ac9, 0x73af9fba, 0x5f7a5ef7, 0xb8ccc5bc, 0x9ad69d33, 0xace8c2ba, 0x447acc00, 0x0f14a6c9, + 0xa4f560e5, 0xe4d00e17, 0x04848897, 0x16f113e5, 0xc3563fe7, 0xce7c3f27, 0xba433856, 0x349e72d0, + 0xb947035a, 0xbcbf2431, 0x2482f526, 0x216b4022, 0x1e21238b, 0x1cee9d20, 0x1f1e1224, 0x401994bd, + 0x9fdbac1d, 0x76e55649, 0x703d1cab, 0x29d37b01, 0x1257a7d5, 0xf3c5221d, 0xbaa342e6, 0xb1afcecf, + 0xaaf74602, 0x3cdd4aeb, 0xf3c0d610, 0x13be9b18, 0x8b22834d, 0x4e47b521, 0x12b1efbf, 0x2c002e36, + 0x2968569f, 0x76583886, 0x27c02f04, 0x736047a5, 0xb3883303, 0xbbd7bb4a, 0xb226838a, 0xa4cbaa3e, + 0xe09e87d5, 0x26d9daa7, 0x22458850, 0x2dfdede4, 0xa8296d69, 0xcf4f4023, 0xbd50bd4d, 0x683d6471, + 0xbe5bc247, 0x68079ff0, 0x2e9b6a50, 0x2d8e5640, 0x1f858ed3, 0xab099c4a, 0xb1e3133b, 0x899614d0, + 0x50ab3064, 0xc8ea1fdb, 0xda4fb55b, 0xfb126968, 0x03d1e34d, 0x038c1e6d, 0xa9861e92, 0x23693c09, + 0x234f6f25, 0x3d10b024, 0x581fc5c4, 0x8314ff0d, 0xec322896, 0x1a0e9571, 0x834170cf, 0x42a19179, + 0xf3605f9f, 0x4ad23a90, 0xfeb36baa, 0x2f3648a9, 0x2e3b7035, 0x1a361464, 0xc56fbba0, 0x7385fa75, + 0x68127932, 0xefbdac80, 0x2ff5d443, 0xab258168, 0x4bc49f12, 0x504d55a5, 0x55510df9, 0x1b0fcc4d, + 0xe02592b2, 0x1ddebbc4, 0xa7a552bb, 0xbda2f5cd, 0x454b94c8, 0x33d6a709, 0xdf2ab987, 0x5ca27de4, + 0xb522cf79, 0xfc1bd501, 0xcfd1dd01, 0x5967cb52, 0x1280b13d, 0x9b39df40, 0x726c07eb, 0xc5928bd2, + 0xeb06cf24, 0x3450ec7a, 0x6579c422, 0x956aa9cc, 0x0239cfd7, 0x3e01b555, 0x629e5643, 0x79979335, + 0x70145419, 0x2bf9f5c4, 0x2737353a, 0x564035e6, 0x552dc0c0, 0x2f11fb88, 0x8eb273ad, 0x22cabef7, + 0xc00792aa, 0xd037c61a, 0x09e62bd5, 0x326b135b, 0x4fd80e8a, 0xf34c6638, 0x78e53273, 0xaf3af2db, + 0x12231159, 0xa9e73dec, 0x3b30fc75, 0x19c6951e, 0xc6d7707c, 0xaec3755d, 0xb0ace221, 0x72db332c, + 0xf8dfb9d7, 0xc749619a, 0x7858864a, 0xaf7185f1, 0x6cac1e1b, 0xee06d6e4, 0xea569a53, 0x91df5597, + 0x3c6b7854, 0x3986a423, 0x39037930, 0x32a62967, 0x6fc4ddee, 0xccc7416a, 0x479e3970, 0x2e7e5492, + 0x87a69ccc, 0xe2ab5f65, 0xda523f60, 0xbe8c265f, 0xdb32b1e1, 0x08ded3c0, 0xed8168b5, 0x63ea2623, + 0x6a3ed86e, 0x5a4fb6bd, 0xf77edeb0, 0xd94a0cdf, 0x4c777acc, 0xb6d1c2f4, 0x2ccacbf4, 0x50b42f31, + 0xa5c61ec2, 0xa8681fe6, 0x36af70af, 0x2a1cbca3, 0x1973220d, 0x2b69df9e, 0x806dc896, 0xc1f1a39b, + 0x607a400f, 0xb536dca3, 0x0908f664, 0xcc1a2381, 0x3020dc8e, 0x5120953c, 0xdfca9852, 0x9f9f8c36, + 0xdf47b1f6, 0xeb4d7906, 0x75aff2a8, 0xbd032dae, 0xaafc91b5, 0x9230f522, 0x33bef458, 0x50f99667, + 0xf463c914, 0x90306f82, 0xe4f49212, 0xadca544a, 0xb0d8187b, 0x6bb770d2, 0xaa5b885c, 0xe77b1d43, + 0x8b6ef847, 0x28d58fda, 0x442ea554, 0xc575551b, 0xcc35aa23, 0x61270752, 0x580a5752, 0x7abc2930, + 0x7fb524fa, 0xf9d3eb43, 0xfe591eaa, 0x4e08d693, 0xab9fc152, 0xf13547f3, 0x469fa6b7, 0xc282c747, + 0x2aaf92de, 0x5b488aed, 0x92639131, 0xd7f30ff7, 0x6d500f4e, 0x017ce668, 0xe17d2672, 0x8d1a1aa2, + 0x409110e1, 0xb5a18269, 0x69a634f5, 0x720a6025, 0x014232ac, 0xdac0676f, 0xf562d1c0, 0x00693e44, + 0x14cf18ff, 0x1d0df07b, 0xd909a145, 0x593fce31, 0x5e0e0e3c, 0x499f82dc, 0xafcfcc00, 0xb7ddcfba, + 0x2dba0fa0, 0xbce9e296, 0xe63dd9b8, 0x472881fe, 0x9436e83a, 0xaf61ccb5, 0x95c9019d, 0x049c646f, + 0x916af39f, 0x6d1aa785, 0x3dbcca46, 0xf863a3f5, 0x7a52a3bc, 0xe054ef9a, 0x703fac9a, 0x98343338, + 0xa7d197f4, 0x7551aab0, 0xe35858db, 0x2d743f67, 0x71a06234, 0xf5d33e5b, 0x8c201adf, 0x7176c96d, + 0xfdb39b36, 0x5e9cc0fc, 0xdc09110e, 0x3cb564ca, 0xa3dcb206, 0x62b3ef9d, 0x2e49d71d, 0xe995cd34, + 0x6452c3a4, 0xe26fdfaa, 0x07152d62, 0xc74a8943, 0xa709658c, 0xa4c34a2a, 0x5e57106f, 0x93876d2b, + 0x89ad0be6, 0x3f1c0a6e, 0xbf6fa598, 0x4eeb0c36, 0x216dc043, 0x6c156956, 0x6b978b0b, 0x39da9454, + 0x7b445365, 0x4f057fa0, 0x9ccbee4b, 0xe65349c3, 0xf7a13583, 0x146d64c0, 0x12bf289c, 0x8783a606, + 0x10fb2e98, 0xde2ddd5a, 0x25b597dd, 0x82659744, 0x2eb4ccb7, 0x7f6b8824, 0x577df411, 0xf9a46ea2, + 0xa975ae4c, 0x355c5511, 0x4571762c, 0x0aba476c, 0x6fef5985, 0xe9202090, 0xf83a7500, 0xf3a72bb1, + 0x6d0137a4, 0x2402b367, 0x18c7594b, 0xbf8713cc, 0xbb3944b9, 0xa7e36e7a, 0x5500251b, 0x00e9ccd8, + 0x334afcda, 0x843aa437, 0xf2642b82, 0xeb76fee0, 0x6bf84317, 0xa614d3a3, 0xa7c07137, 0x8dbd375b, + 0x7e6d2af1, 0x383c1b12, 0x0002e0d4, 0x6722d016, 0xc8bbc658, 0x1f842217, 0x68313134, 0xe8f053a8, + 0xfe8f6d29, 0x648747f0, 0x26173823, 0xdd7b9220, 0xe457da62, 0x9bbe3d3a, 0xe8263118, 0x23a6df95, + 0xaac54100, 0xca5bd800, 0x94237604, 0x964ee3a2, 0x39a40e50, 0x137a96c7, 0x0b932fa4, 0x471db045, + 0x629538c8, 0x5bdd7c34, 0x848e91a6, 0x9d236d6a, 0x9e50fac5, 0xb5fdc206, 0xdbfbb491, 0x2fdd9816, + 0xf8c97ded, 0x8b0782e2, 0xb31bec71, 0xfaa16bb2, 0xc32ba0e5, 0xeb8784f1, 0x2345522c, 0xd2cb99b2, + 0x20f23617, 0x395fad70, 0x8dbd598a, 0x2613b781, 0xb932d062, 0xe0308cbc, 0x6615410c, 0x8491bcdf, + 0x9927d129, 0x1a122844, 0xf61ed6a4, 0xbb3e6f71, 0xa23720b3, 0xc4249c66, 0xa9b5100e, 0x0404fe3c, + 0x5024009d, 0x29a87c7e, 0xe9719f09, 0x8e389342, 0xfa58f825, 0x2b54e48a, 0x8b0d643d, 0x13cb9383, + 0xfea0b28a, 0x6c10c99d, 0x231aa724, 0x3440645f, 0x25d4f822, 0x8cc18cc9, 0xda75d285, 0x9d70125c, + 0x556fdb9b, 0xba087656, 0x56863946, 0x2392490c, 0xd669f00d, 0x454e7846, 0xa9903acf, 0x52cde828, + 0x7abd88b2, 0x71e80a67, 0xb6f0bd82, 0x54196ee3, 0x35e47195, 0x813e7316, 0x28547dc1, 0xb370b225, + 0x9d5ed712, 0x83bcb2ba, 0x03b9b2b8, 0x2333d994, 0x49c66657, 0xe9e04832, 0xeb1339a4, 0xffbfce7b, + 0x288a94d0, 0xd07df2d1, 0x06f4fbda, 0x484f383c, 0xab11e140, 0x4006571f, 0x00d44631, 0xb4ae9850, + 0x3a1f0cd1, 0x3e15a8cf, 0x8ae2ae0e, 0xfa070b5e, 0xbefc30a5, 0x5a7d3b95, 0x1c62b4e6, 0xb7db01e3, + 0x37211b03, 0xa284aa55, 0xb16e40ea, 0xb662303b, 0xe2d0b069, 0xabed81e7, 0x16664936, 0xfe62770c, + 0x7e63aef2, 0xb86a03bd, 0xb63f35b6, 0x4b50357f, 0x991ae087, 0xee3b3686, 0x68023041, 0x41d1206c, + 0x1b699369, 0x6b307606, 0x4db4fd75, 0xb9bfa221, 0xa56d110e, 0xf7f8575b, 0xd5da53bb, 0x29d02a93, + 0xa1f5e40c, 0x15913194, 0x15519e2c, 0x167b2035, 0xd98b7dae, 0x5374a26a, 0xf68bc4da, 0x927a6e63, + 0xa21fedbb, 0x5360be10, 0xf248eaf5, 0x23a8c284, 0x5f40428a, 0x32b44304, 0x8648d736, 0x04f3f06e, + 0xe9aafdd0, 0x52e993e7, 0x88be1876, 0x15df1e30, 0xc95ee80c, 0xd782540b, 0x0d0d1446, 0xbe391c3a, + 0xf77b91d9, 0x71950fc0, 0xed908a6a, 0xeb8709a1, 0x3f49841f, 0xa8b2ede4, 0xd83ee039, 0xb3a07e54, + 0x02ac001d, 0xdf391e5b, 0x42a2e02d, 0x6be95859, 0x92e1166e, 0xb8aedd1b, 0xc9a271ea, 0xf0f536d8, + 0xf42f3821, 0x2837cda0, 0x66de0c2f, 0xc6d2ba4a, 0xc9db7a4b, 0x43891fcd, 0xce45f0bc, 0x2dfb6bc8, + 0x1b2e01b4, 0xc3175079, 0xfab65a1b, 0xcb0a8c91, 0x22934cf0, 0x77ac3940, 0xd83ea4ba, 0xf0c96491, + 0x653e5be3, 0xb40690cc, 0x7421f5fb, 0x44e2c120, 0xaade6914, 0x8ddc3cff, 0xe0b6d70c, 0x49cb9e11, + 0x56950508, 0xa9155ec2, 0xf704c786, 0xe1a25c58, 0xeb25a359, 0x02102c98, 0x6537b071, 0xf0d55a8f, + 0x1786e136, 0x905a026a, 0x15b24013, 0xbbc7ca83, 0x49c35dd1, 0xf3c1a54c, 0xc8209045, 0x5a8c786c, + 0x6288d58f, 0xc453dfe2, 0x203eeef0, 0xd360843b, 0x9d63d0b0, 0x52ddb0d0, 0xe049e045, 0x3805668d, + 0x3fb7f135, 0x0a39baa3, 0xe7d224d9, 0x05e7bbf4, 0xaffff564, 0x678df0dc, 0xba608122, 0x58335092, + 0xaba59d78, 0x62487ebe, 0x82ccab76, 0xf0596377, 0xd617c3e4, 0x82e3daa5, 0xe8170117, 0xd0d8c95c, + 0xf39e500d, 0x037d51da, 0x78062eae, 0x85afd856, 0xa95ca7bc, 0xa8102850, 0x133d8887, 0x17867cdc, + 0xdb70cc48, 0x68d0e2ca, 0x71fff77b, 0x068a85a8, 0x5460fee0, 0xed79edfa, 0x29870dc7, 0x318ae04a, + 0x763d4f91, 0xd6ea7293, 0x86c10f06, 0xf7124112, 0x5f89800f, 0x5259e7ca, 0x503afe37, 0xc48c097c, + 0x59f0683e, 0xf89ffe77, 0xdb8d82bc, 0x2657d4ea, 0x53346e03, 0xe1d0d87c, 0xee9ab288, 0xc57eae0d, + 0x9324d3e3, 0x70ffd532, 0x9db50ae8, 0x2802d925, 0x132b5ab9, 0x6b7309c9, 0x01eaf34c, 0x4e725977, + 0x64aaf11e, 0x95c4321b, 0x79547631, 0xe5274ae9, 0x43aededc, 0xa4eed91b, 0x4f6f2034, 0x8e766d89, + 0x230d113b, 0x0cdfb97f, 0x9fe90b34, 0xd23e004a, 0xb6af24ee, 0x22554dac, 0x606fee2f, 0x0fa517c3, + 0x6104706c, 0xb651b4e6, 0xedd31461, 0x7834d99d, 0x7d690093, 0xc3cddbe9, 0xda630eaf, 0x505e6a51, + 0xb34ec55c, 0xf727c1a8, 0x7a27185e, 0xc0d3d54f, 0x3a9d599f, 0x057c8475, 0xe941388f, 0x50949436, + 0xa3efd2dd, 0xeedcbf84, 0x87a55a3f, 0x06a8edad, 0xc812b673, 0x5510b140, 0x89f3c1f5, 0x437cb719, + 0xa333690e, 0xf75826b3, 0x64a126cd, 0x7a8d637c, 0x4980e962, 0x88be3b33, 0x87970f3f, 0x2522c37f, + 0x70523fba, 0x94b1c9ca, 0xd0f74f96, 0xc10d8ac4, 0x9b5dd1a7, 0x946e0296, 0x9803965b, 0x987141c5, + 0xd5848a22, 0xe2e3dee9, 0x92f0ec3a, 0x0bf66e69, 0xfc160f51, 0x235a8175, 0xf62e6b85, 0x82aced24, + 0x3368c991, 0xec85f0b9, 0xc737b2b1, 0x90d7b9a6, 0xdad256e6, 0x94f394f3, 0xd237ca12, 0x7da2d895, + 0x7cb9d2f2, 0x54a3c780, 0x99282cb7, 0x58eb1343, 0x4cd3025d, 0x015cfece, 0x9977b96b, 0x08fce3bb, + 0x34e17cb1, 0x3060eaf1, 0x4f6b9262, 0x3fd70395, 0x5fc8a58c, 0xa94c8fc1, 0xc7b42e9c, 0x40e0b3ae, + 0x7d03f360, 0xb4d7358c, 0x8b9bd4de, 0x9a033f44, 0x2402e023, 0xea8d9046, 0xd907414e, 0xda6bb397, + 0xca94ebe1, 0xfd4e7c22, 0xc65afc71, 0xeca7942f, 0x52b27612, 0xd894aff1, 0x1ba48a63, 0x061fa97d, + 0x92b97955, 0x1bb27050, 0xbf1d17b3, 0x340f5619, 0x251bd5f1, 0x2a89f3dc, 0xfb7e8bfd, 0x026cc79a, + 0x0a3c2b23, 0xd738837f, 0xfb43356c, 0xf86f6267, 0x1627c809, 0x5f669156, 0x5cc069ae, 0x29b52cf0, + 0xbfef586d, 0x4d50acf6, 0x813a1f69, 0x63a4ad57, 0xc32f6f74, 0x3bbd227e, 0x6c84dcc7, 0x15c84b0b, + 0x9ce9a8cf, 0x0c667f15, 0x86809b9a, 0xb0c937d3, 0xed102ae4, 0xd154fe9a, 0x2a36ab79, 0xf2317c0a, + 0x38699157, 0x95249c65, 0xa5fe4b87, 0x07b0e74a, 0xc0d80eab, 0x0c188371, 0x775e11d5, 0xc1400516, + 0xf9be82ef, 0x6b2131ae, 0xc04f6503, 0xe51235a6, 0xc595067b, 0xdaedfda8, 0xa3511562, 0xb063f07b, + 0xb98476f3, 0x8d52c865, 0x6456f0d9, 0x8b22e098, 0xeb5b41e7, 0x8c6b68c6, 0x690bc57b, 0xe7d82ef6, + 0x3f57886f, 0x6275ea8e, 0xa9991ba6, 0x5be23922, 0x3ca8cfad, 0xcfdb1dfe, 0x82226dfe, 0xe1490c12, + 0xa381bc2b, 0x516a19aa, 0xa433b17b, 0x931d28a6, 0xbfbb35fc, 0x4002a8b8, 0xe18538ef, 0x68c5781c, + 0x6ae5fac5, 0x96d11090, 0xdb60ade1, 0x21c383a0, 0x2283e2f4, 0x38c5e184, 0x322f795d, 0x5c3985a6, + 0x5b437a5f, 0x109f14b1, 0x4c68583b, 0xea4c5c63, 0x61b1832f, 0x3ad6ee1f, 0xef1d89de, 0x67bd84ad, + 0xcbcc5533, 0x4936e3d6, 0xf705ab9f, 0x46852bc7, 0x194198a9, 0xfaf36344, 0x22e08172, 0x79be82c6, + 0xf16b6bf8, 0x8b13c4fd, 0xfc1f65f4, 0x90acd58a, 0x5a4c51bc, 0x3d4c3b1e, 0xcffbc825, 0xdb0ec551, + 0x8d8d27b5, 0x84d60372, 0x6f1b2df5, 0xcd4ec262, 0x2a90b06f, 0x13ebdad6, 0xc8aabf03, 0x44ed3b29, + 0x79feaa14, 0xa8668531, 0x621262d9, 0x54e383ff, 0xb2a08c97, 0x7acb58d3, 0xa44472e7, 0x0191a94f, + 0xe641f53f, 0x6bead57c, 0xd06b9e8d, 0xdce6fff8, 0xbc3fac52, 0x060e1ffb, 0xbe55c3a7, 0x1b8251f8, + 0xe9b835b1, 0x4b331186, 0x5f3712ba, 0x2a48dc81, 0x1d84c86a, 0x9209494e, 0x568ab14a, 0xf3aaa3c5, + 0x6d6341fa, 0xa42f8833, 0x3a052345, 0x03bbe9bc, 0xc06d4c88, 0x46c87f26, 0x3bbdc63d, 0x340e8035, + 0x4cdc9d57, 0x6605e691, 0x66f9cccc, 0xa7ec575e, 0xe25a843c, 0x0caaeb38, 0xf4e14739, 0xb1ada077, + 0x11d82808, 0x7e4f785c, 0xffa89fa0, 0x9a92290a, 0xa16e2733, 0x325a90f2, 0xa7e1290d, 0xf24eed09, + 0x909e6696, 0x8959c208, 0x0ade3e9f, 0xd7fc604a, 0x4c2e4f25, 0x3915b50c, 0x8cbf044c, 0x06109604, + 0xcf83778d, 0x43d9934b, 0x3deb9e52, 0xadc2a421, 0x62e16358, 0x9532d5a6, 0x44d08583, 0x49f8cfe5, + 0x3630642a, 0x76e817d7, 0x892176e3, 0xc2600792, 0xbb9d9c5b, 0x298bba31, 0x8edc7768, 0x2114f422, + 0xdf029778, 0xc3e18a51, 0x0e591ea0, 0xe599c6a8, 0x76465cb0, 0x6b30e1c7, 0x9c3b329b, 0x286c8ac3, + 0x05b8e751, 0x470c666b, 0xe62ffb63, 0x427c32f2, 0xd32f76f9, 0x165cc7a7, 0xe8d70d45, 0x0c8be519, + 0x3c6b3766, 0xf21ccf28, 0x7e250e49, 0x5bc3fbef, 0xd8ebbbd1, 0x7b656bea, 0x8ac8eba8, 0x1636b40b, + 0x651e841a, 0x22ce1c01, 0xaf9a8c1e, 0x98b9946d, 0x9f2c45a7, 0x97bcdea8, 0x9369bbae, 0x21f85e29, + 0x6b55fada, 0xe0fdd602, 0x0afb3c47, 0x1ebdcb50, 0x09526830, 0x46bd4d5c, 0x642e4352, 0xa2d8462e, + 0xb5a4d558, 0x7a572432, 0x69f304f6, 0x3d67786b, 0x913513db, 0x537de2bf, 0x8a627871, 0x988ca230, + 0x8ab22758, 0xd68dd8fe, 0x1b570b1d, 0x31a64643, 0x6c6a152d, 0xff65454b, 0x5a26f1ed, 0x3e2a96f8, + 0xe6930ca6, 0x16b60386, 0x7f4b2db8, 0xfc5be527, 0xfcee99dc, 0x5cdc5c1a, 0x8941b3cd, 0x65409c51, + 0x28b70f58, 0x8e35f524, 0x60b86427, 0x40eb7de7, 0x16d1c06a, 0xf46914ed, 0x9f6df0d3, 0x43c7d33c, + 0x850e8aa5, 0x78b366d0, 0x84c4f24f, 0x4f26f509, 0x69bbab1b, 0xd341a641, 0x101a902d, 0x7eca3616, + 0xb76e9ec3, 0xdc5eebeb, 0x5598d86f, 0x0f9db401, 0x3b86ad8c, 0xd96431a8, 0x1d4f54fa, 0x000df38c, + 0x17c012c3, 0x40c490d9, 0x855dc8c5, 0xab70bd34, 0x97ddf782, 0x9f849330, 0xf5f1bc2a, 0x3a01ba53, + 0x7f115a6b, 0x4236e1bb, 0x40219135, 0x742f620b, 0xb8cf2961, 0x3fcbec51, 0x678f49ef, 0x7af8fd83, + 0x2710f304, 0x4f014570, 0xf22d5841, 0xfc144b80, 0x8313f7b8, 0x13d916ff, 0x6b7ea0b9, 0x922fc1b2, + 0x336cdbfa, 0x7c9af221, 0xb6350d8a, 0x88687fdc, 0x8747aa25, 0xabb49823, 0x0a560b1c, 0xdc8cd482, + 0x6aeeb5d4, 0x1eb773f8, 0x780a270e, 0xdf0256dc, 0xc1741918, 0xc0af3351, 0x62ed552a, 0xd003f5e3, + 0x965e3360, 0x4b508984, 0x8ffb36ff, 0xfd549032, 0xa9d7ffca, 0x37b1828c, 0xe4093bf1, 0xebf6f181, + 0x67c4e3af, 0x205f6056, 0x6cb49c75, 0x9d3ef345, 0x8f782397, 0x9c82ea7c, 0x95b0f6b5, 0x8055d1b6, + 0x33c80654, 0xcfff2028, 0xca9ab96b, 0xe3c3a5a0, 0x146929f1, 0x12b20959, 0x35dd5f5a, 0x39c591f1, + 0xf5b51ffb, 0xf0b8f240, 0x4370ec7d, 0x144818f0, 0x6747a271, 0x37b2336b, 0x254c4d8c, 0x9d051e8c, + 0xa0ba159e, 0xc027c307, 0x7c503a65, 0xd983042b, 0xfb469184, 0x3b7ff59b, 0x060e3b6b, 0x09821bd3, + 0xaf1df2ee, 0x2480d493, 0xf3368da3, 0x0a16a543, 0x5433dc0f, 0x940bb949, 0xc9e65aca, 0x11e849a5, + 0x662d1da8, 0x67edf31c, 0xe6f1b4ce, 0xb1622394, 0x5420f995, 0xd9fb05b6, 0x3797b0e1, 0x0103109c, + 0x71734096, 0x0bd38fce, 0x1422e1f5, 0x900639e1, 0x1119629d, 0xa16b9d15, 0x0f5f236b, 0x4d272014, + 0x1a284c23, 0x5a65cf3a, 0xa2c58f2e, 0xfc07b6cb, 0x5d4c9b64, 0x6edbe4d6, 0xc5b1b7bb, 0xdb1238b2, + 0x3ce96d38, 0xbab3b4cc, 0x427a9be5, 0x298f98bc, 0x5874aa0b, 0xd29f44b0, 0x3e5dab4a, 0xf2bb5128, + 0xfc9f5820, 0x04f099e3, 0xed9fb990, 0x2b738ab6, 0xc4bc0e06, 0x340a276d, 0xe63244b5, 0xb2592c94, + 0x32bd6df0, 0x6fc0b059, 0xf9e67666, 0xb53a87b6, 0x0d36f460, 0xa0eb0626, 0xbae517f7, 0x31158708, + 0x6896ab05, 0x7c59acdd, 0xffc2b32d, 0x85e73a68, 0x3e4e7129, 0xbe1b1d82, 0x80380e1c, 0x9855f0e3, + 0x79fc8d51, 0x487af3d9, 0xc726b4be, 0x55b7a73d, 0x2cab9b22, 0x8d26fcac, 0x6fe31071, 0x1afb9eaa, + 0x8ff6ce0c, 0xf9222764, 0xbde8a3ae, 0x4bea1f2a, 0x112b3b10, 0x29224674, 0x84d30e6b, 0x4214040d, + 0x3d9ef307, 0x23b0e164, 0x2977fe96, 0x0ccf3880, 0x9bc7462b, 0xa403efa9, 0x40dd8f16, 0x16429d78, + 0x2595410d, 0x7a774dc1, 0x51d1a55b, 0xed55e6ae, 0x7f0eb500, 0x9c8289c7, 0x3075d02d, 0x0974838e, + 0xcd08a302, 0x4cf7f308, 0xb63f5650, 0xe46e7450, 0x87593ab4, 0x0cd2aae1, 0x2456cd61, 0x06abfb70, + 0x4ad0d093, 0xc16db71e, 0xd93b34f0, 0xb2d9f579, 0x69033c22, 0xa096ebe1, 0x99fc304c, 0xc2636db8, + 0xbfa445ae, 0xe5232c89, 0xdf52e1d9, 0x42a8deec, 0x8458d5b8, 0x3138274d, 0x7ab99b0e, 0xf1e0f3da, + 0xb610e2ce, 0x770f6bff, 0x12590f10, 0xf3a3c77c, 0x09e1e9f6, 0x5a9457c4, 0xaed0755b, 0x73f5af75, + 0x4f6f0ab2, 0xe1dad402, 0x8b4b0fe8, 0x30d709a8, 0x57245018, 0xe593d926, 0x581972cc, 0x643f9428, + 0x42c03bea, 0x0fa7c9bc, 0x32195766, 0x49b87b5c, 0x4bdf6117, 0x848c3676, 0xb513bb02, 0x9e5a908d, + 0xd08b4228, 0xb1a2a441, 0xbf724f77, 0xb3c7404c, 0x954822c8, 0xb21de7f9, 0xfb41c05f, 0x83285394, + 0xe05329ff, 0xa35b6ebd, 0xad6d2eef, 0x0b355dfe, 0xc2a5049b, 0x23fb0a69, 0x51061a12, 0x29b77d62, + 0x47e11f1d, 0xb1c2139c, 0x268cb793, 0x249b569c, 0xa3b0bba4, 0x19182eb1, 0x956b075e, 0x716449c4, + 0xde00d02e, 0xa7db8a36, 0x4c0894e1, 0xe81494d6, 0xf1fc2e74, 0x6018e1c6, 0x1aef6e1f, 0xc1671a82, + 0x89a28ccc, 0x5622756f, 0x5394de74, 0xd850aed5, 0x76066700, 0x764f3aa2, 0x07721665, 0x6bcb8d36, + 0xfb18edbb, 0x15ad3dda, 0xb0103ac3, 0x1ed02b06, 0x03c0b586, 0xeecfdb0a, 0xf64c0d3b, 0xa8d1e446, + 0x29ab23b8, 0xf9f7dc2f, 0x4177265b, 0x5319238c, 0xa54b52a3, 0x27a733ba, 0x377493d1, 0x386859c1, + 0xa93a510c, 0x287711d5, 0x175b93c1, 0x537be931, 0xfb4fb669, 0x97ddf570, 0xaa3532b4, 0x986eefe2, + 0x70d95a91, 0x38926824, 0xa36538cc, 0x41165168, 0x8b4e3a18, 0x63db9034, 0x3bffb65a, 0x9ddb943a, + 0xf80726ef, 0xdaf2e350, 0x3185533d, 0xbb336c2b, 0xd9c83162, 0x2140d8c9, 0xca8d76ec, 0x8878874b, + 0x905bb740, 0x432b9747, 0x5486ddb7, 0xf8877690, 0xc196c9fc, 0xd00619f7, 0x15574487, 0x12c07f1d, + 0xc99ca564, 0x06b86ebe, 0x54b23845, 0x4c07de6d, 0x87187665, 0xf90e9150, 0x212ac879, 0x2b741f77, + 0x712fa6e5, 0x90ceb97b, 0xb2ad52c4, 0x8938ea4c, 0xe549ed1f, 0x77043793, 0x6fcadf25, 0x23a86f3a, + 0x8e01191c, 0x1637229f, 0x8bbb2f0b, 0x3fded3d2, 0xfa61af28, 0xa7b67284, 0x479e4790, 0x4228588f, + 0x0e68f490, 0xdff9bad7, 0xff399184, 0x8f2e3a82, 0x1384c0e0, 0x80e35fd7, 0x7534bc56, 0x3cf2b25c, + 0x14a0323d, 0xa420d7e3, 0x6ffaefaf, 0x24b38dc1, 0xfbd0b8e0, 0xa15b68ef, 0xd8ccec4e, 0x9d1eb709, + 0x7a657cea, 0x2625d253, 0x829abb4e, 0xc752000d, 0xf2202fef, 0xe85afcf0, 0x648f669d, 0xa5e935d1, + 0x82bb41ca, 0x547e04f9, 0xf54800ce, 0x9c5c92af, 0xcec6bb28, 0x39e59c85, 0xe2ab4c42, 0xcb7f055a, + 0x4d42b6f9, 0x42a2cb1a, 0xab1d99f3, 0xeffd7e48, 0xd90dd9a0, 0x425ac985, 0x17f4f22a, 0x34dd5ac4, + 0x4a0a4252, 0xcfe7fe89, 0xcbdd1a25, 0xbd4325a2, 0xc1018a93, 0x968657c5, 0xfbda4a92, 0x1eeb528b, + 0x4ab3bc6f, 0x081739bd, 0x6ec7d4d5, 0x42c49c48, 0x73a41e9c, 0x9ec62818, 0xad51c3db, 0x2f69a7da, + 0xef5527a0, 0x383e5e94, 0x86d6f974, 0xf50cac04, 0x78d920b8, 0x6d6bdefd, 0x8a6abc1f, 0xc80278ae, + 0xb09b9021, 0x53bcecd1, 0xe74b6b10, 0xb01dc7ef, 0x5cba24d2, 0x55546a20, 0x400f6845, 0xe15ff43b, + 0x257119b6, 0xdf3a2136, 0x22d928d1, 0x1c6f2452, 0x0a7a3f0b, 0x2c6211a3, 0xe1855d9d, 0xda1d6db2, + 0xa373cb5c, 0xfa30ee51, 0xcb392085, 0x9a0ce48f, 0xadc69939, 0xe8c9fe10, 0x01a6fc6c, 0x4f79c0a4, + 0x969f6695, 0x76d7b46a, 0xede98192, 0x6cd6a259, 0xaf396b2f, 0xa64f51a1, 0x81c22f54, 0x3e91ba39, + 0xafff640e, 0x8408c1ed, 0xc6277674, 0xa964f4db, 0x0ed5d329, 0x67cc5822, 0x87143256, 0x7f46aef0, + 0xb2883db1, 0x1cc94791, 0x273cb5b9, 0xc24995cb, 0xbb36ddbb, 0xd41d6af3, 0x6a419500, 0x23bd21c3, + 0x35448325, 0x3f94824a, 0xe09ae1e4, 0x93c068c8, 0x779ec70c, 0xff374aaa, 0xa3adc937, 0xf1988dda, + 0x46e6c11d, 0x1ea066f0, 0xb04799dc, 0x3a7f91eb, 0xf3dd9ed8, 0xa4075df9, 0x117dbedd, 0x88c70718, + 0x186b2483, 0xa9c4465f, 0x8065ae44, 0xf806fcfb, 0x6436f0dd, 0x33b703bd, 0x59f3f82d, 0x68189c43, + 0x2d9d708c, 0x14e55ee2, 0xa7f6003c, 0x5e376004, 0x0e1b367d, 0x233f68b7, 0x8efc1e06, 0xba7722a7, + 0x10c5549a, 0xc45f125f, 0x88f493e4, 0xfe68247f, 0x4679efc8, 0x3233f136, 0xeba374b7, 0x0f104474, + 0xd3a31e7e, 0xaed974f0, 0xdbf4f8b4, 0x015c4963, 0x451ddbf6, 0x559ba329, 0x7f4d20fd, 0x67011d80, + 0xd526916a, 0xc1e11a74, 0xd75d9dca, 0x586dcc20, 0x9deb358b, 0xb4c6fe96, 0x0512dae5, 0xce14e4ad, + 0x6834991b, 0xee16ea52, 0xad405f8f, 0xa0703738, 0x4dd55f2b, 0xdf5afc2c, 0xee087d2a, 0x08c38c03, + 0x9b33f81d, 0x3d2d90f1, 0x8b2d11bb, 0x980fc0ac, 0xda714775, 0x7ae75d32, 0xfbe84a47, 0x4dfcbf39, + 0x94441da5, 0x4c305f9c, 0xc366feb1, 0x92d4423e, 0x65f0bc27, 0xc1dce48f, 0x71e39601, 0x9ece40da, + 0x254295f9, 0x28302d26, 0xe4b28699, 0xbe9c0742, 0x4db3ed13, 0x926abdb6, 0x7c46ca09, 0xe8a46e3b, + 0xcb9e129b, 0x8a95ae88, 0x636df97d, 0x2cae19d9, 0x51478918, 0x0da8b874, 0x17de63e0, 0xe0b62da5, + 0xbc63bc55, 0xfc99e3aa, 0x283d5760, 0xfcd8ff5a, 0x3d4030bc, 0x1faa940a, 0xf2fafd10, 0x40f532f6, + 0x5fe07839, 0x2f9824bc, 0x19171cd7, 0x746be31d, 0x49d79b15, 0x4eb9d264, 0x2db5509d, 0x839b7c47, + 0xc3da1c3e, 0x7bcc4728, 0xd2a98868, 0x489b9682, 0xa7bd5a41, 0x90dae2af, 0xe7f122a9, 0x0343ed61, + 0x791cd2d2, 0x531faafa, 0x4c09d020, 0x62c782e1, 0x83f2f271, 0xccee3052, 0x0622a8b4, 0x3369a38b, + 0x1fca672b, 0x3a589cf7, 0xa95f49f6, 0xaab4a3f3, 0x4e9ef94b, 0x0703ff5c, 0x2f86b386, 0x68ef1efe, + 0xd37335fd, 0xfeb439b2, 0x5ffc2965, 0x97001955, 0x78119143, 0x50530e1e, 0x8b827b6f, 0xea7efe09, + 0x250d50a4, 0xd2c6a90c, 0x0c436961, 0xa8b6bdf8, 0x8ed23422, 0xc5400a06, 0x875dfec7, 0x6c5c620a, + 0x7ab7cd30, 0xf9c2f06b, 0xd9a04d68, 0xa9607036, 0x7aa05d2f, 0xe6128fe9, 0x289a4fea, 0x1157bf95, + 0x87c4d3b3, 0x23e0452b, 0x0296d274, 0x39f908e9, 0x179b7fc3, 0xf5a9549f, 0xb04cd11e, 0xa581fa8f, + 0x5b822d89, 0x694f5705, 0xe0de0701, 0x42f76e51, 0x7ebf603b, 0xd2640dda, 0x660310b6, 0x73cd8a48, + 0x8bae859b, 0x8e7af9ee, 0xa8519447, 0x4cd0084c, 0x2afcfbcb, 0xdbcfc810, 0x699e4300, 0xbba0dc34, + 0x283f1935, 0xbb259ff4, 0xb1574e52, 0xe2fde136, 0xb72684a6, 0xb47e5824, 0xd8fa8b5e, 0xd0cbedd8, + 0x12f159c5, 0x9ac0a7c4, 0xd428dc54, 0xca7228ca, 0x088fdcbd, 0x195d1939, 0x87bbed95, 0xa612c417, + 0x7420e5ac, 0x31bf4951, 0x0c7afb62, 0x8907987f, 0x38cbd03b, 0xc08e74ea, 0x1d350860, 0x65ccc894, + 0xc433ebd2, 0xad5a417d, 0x6b0b4434, 0x9c01a836, 0x6dea557d, 0x9665543c, 0x9500db40, 0x895540c7, + 0x4fa98794, 0x0abe1da0, 0xb0a023aa, 0x67e0c92d, 0xfea503eb, 0x3c4595b5, 0xd602d6ca, 0x977b42e3, + 0x9bb10b82, 0xc423a2fc, 0x0ba52d93, 0x32ec2930, 0x362f7f2a, 0x3e83655b, 0x7e7982b4, 0x4e780e63, + 0x8b2913e6, 0x55146f0f, 0xca384100, 0xd124eb85, 0xd33c0bd1, 0x524e41aa, 0x845c75e2, 0xa22d780d, + 0xd1008ce1, 0x93c3096d, 0x7f634184, 0x48e59d30, 0xad20d9af, 0x77bd866e, 0x026c472f, 0x47b904bf, + 0xca6e3f59, 0x84026132, 0x285191fe, 0x8c8ad5e3, 0xa3c5fe50, 0xd24b023c, 0x603324f2, 0x349e04fa, + 0x77b7e2d7, 0xa3533d41, 0x4b3f0ed7, 0xad615b08, 0xf10060f9, 0x7addba0f, 0xb0be103e, 0x67939caf, + 0x3f3a70de, 0x627ff7f6, 0xdb5abc66, 0x3f8fa869, 0x7c0d0cdd, 0x9a56f46e, 0x6919f8f0, 0x8e3b137c, + 0x894a96bf, 0x67948e48, 0xefbb5967, 0x4276df0f, 0x8ae3e69c, 0xf861126f, 0x5ac32fea, 0x43f09ad9, + 0x621b2560, 0x95438f74, 0x1424b1db, 0x58e5ef00, 0x8ea43ac1, 0x59b23603, 0xdd9b20c1, 0x9c069172, + 0x31eb1f30, 0x58a73e0c, 0x52d63477, 0x3d2e4d73, 0x39011817, 0x37a97475, 0x0e00e251, 0x116e0c07, + 0x856697b3, 0xaa366d1c, 0xbb14149e, 0x2a87d3f9, 0xf3ef0932, 0x93c1597c, 0xa726e455, 0xe220109f, + 0x8266837a, 0x8d7963c9, 0xf7195e1c, 0xfcc83445, 0x6e62f1cb, 0xc0c9fe08, 0xe1be5788, 0x857633d4, + 0x822996c7, 0xb706f18d, 0x5307f268, 0xf30f1f61, 0xcb83b4f9, 0x5b406519, 0x0ad98d93, 0x5765e4b9, + 0x0bf775bc, 0x98004295, 0x3dbb7db4, 0xd8733784, 0x052c5fb2, 0xe77c3e6f, 0xfe633de4, 0x4cab31c2, + 0x58f0b2da, 0x5e5624b0, 0x04c2558a, 0xc8f54a12, 0x1107404b, 0xe9e30963, 0x4324628d, 0xa8d1ceb0, + 0x23b24e5b, 0xa654edc3, 0x813d9915, 0x353c47e4, 0xc691300f, 0xe871b28b, 0x80797baa, 0x6d76208b, + 0xd725c511, 0xbb53336b, 0x24d12554, 0x1388deb7, 0xce2101fc, 0x42f825a8, 0x92e7f5ba, 0x1cf47f4f, + 0x9ee362c9, 0x91236c5b, 0x3f9d7235, 0x51b51511, 0x02a7b324, 0x670f1090, 0x2545d229, 0x012e8450, + 0xaa6ec3f8, 0x22ea7818, 0x960faa8a, 0x32918ca2, 0x8d5c65d0, 0x5a2bfb7f, 0x0f45aa8e, 0x5da5fa19, + 0x0e09b180, 0x48facc97, 0xd429d47c, 0xa43165cd, 0x66adb614, 0xc6de86d7, 0xdfe5380c, 0xf3c4ffab, + 0x63e41cac, 0xd929bf38, 0xc57dad26, 0x6c3477f6, 0xb86a37d5, 0xc48492d4, 0xb75d28f9, 0xbc428b28, + 0x0b6d3ffc, 0x0bcf7086, 0x29d910e3, 0x7f68b0f7, 0x03ddca17, 0xc6bc4137, 0xe7e06d83, 0x4cef4258, + 0xd85c6a34, 0x20c8fe93, 0x56cd02ec, 0x858bec28, 0x4eecb855, 0x0d98e185, 0x4a11d80a, 0x4beafa9b, + 0xce97fa70, 0xb845d16a, 0xec903e89, 0x7a2923ea, 0xf9e553f3, 0x3a00ef8c, 0xc610f31d, 0xf4d7a277, + 0x74437ba0, 0xec8812c7, 0x3a2b8bd1, 0xff122faf, 0x0f3e1603, 0x388205a8, 0x80b65975, 0x4eaa25d4, + 0xf12d7d2c, 0x99e65553, 0xeb546365, 0x1ef89df9, 0x11426afc, 0xee94621f, 0x88d46a9f, 0xbe134b05, + 0xe01d7e5b, 0x7a872210, 0x25ad136f, 0xc011db9a, 0x54b0af77, 0x5d718bd7, 0x0d011de4, 0x78f4f34c, + 0xfe1d8000, 0x62bafb5b, 0x7753fa7e, 0x7c93b660, 0x0e1628fb, 0xe9161caf, 0x2aaea56a, 0x50f6da92, + 0x2c1f8d2b, 0xce7cf709, 0x10a9024e, 0x1b8c9259, 0x8a7ab4fe, 0x8d269f34, 0xc3f82e1b, 0xe66ba51f, + 0x215885fe, 0x581f9d38, 0xe6995a9f, 0xcdff7dcf, 0xb9321f51, 0xa4056b33, 0xd5dced23, 0x9e919814, + 0x7a2c7f51, 0xbdc5356e, 0xd6267ae1, 0xb44637c7, 0x92826c08, 0xe5c4d3eb, 0x61b9dd8f, 0x4a391466, + 0xc21d1a73, 0x60c834c2, 0x06bd6ef5, 0x3c1d3c61, 0xf921107c, 0x37b8fee4, 0x11c6ef37, 0xd8449a21, + 0xa43eb2a6, 0x75188694, 0xa75d7897, 0x97f6df8f, 0x25b9bf24, 0xc85f8a76, 0xd293dec6, 0xd363b2d9, + 0xc6039d55, 0x9515eb75, 0xd9edc60d, 0xbefdbf8f, 0xfa365c5d, 0xcc8db9db, 0xa70f4a78, 0xaab7f2a6, + 0xe7c83661, 0x05b72dc6, 0x2e6850d4, 0x370386d2, 0x38796cc0, 0x10ab8ca7, 0xda09f561, 0x4164c6ae, + 0x6649147b, 0x962babb5, 0x9e152eb4, 0xbeab77fa, 0xd6beaa88, 0x4f684f9f, 0xdc5c6956, 0xbe6e8dd5, + 0xc11ed83f, 0x600105de, 0x6b773972, 0xc0fc4bb4, 0x7cda305d, 0x07dd0473, 0x4890a46b, 0xc62b70a8, + 0xc7d5c80e, 0x9987b93b, 0xadb70659, 0xf566c4d2, 0xc9d10acb, 0x0a3b6f79, 0x8a94b528, 0xaa722533, + 0x490d1d6c, 0x4d0143ba, 0xb16f1f8e, 0x2c81bb2f, 0xebccab39, 0xbc08a5b5, 0x058cfbd8, 0x8c496837, + 0x0662f529, 0x3818501a, 0x1cf2cbe1, 0xa759c432, 0x5efbce22, 0x83c750f1, 0xf60f14f4, 0x452bf1f5, + 0x30e202ce, 0x61991ac4, 0x2b0e47ce, 0x0131b7a9, 0x3eba9c1e, 0xad4d619c, 0xde56c6f1, 0x555bf5aa, + 0x6769eb63, 0x0bf74db5, 0xd4f52fe0, 0x64604edc, 0x1914bce6, 0xf578d82a, 0x32023da9, 0x9e2b3a81, + 0xce0a8fef, 0x05c64435, 0xfa903c6d, 0xe40bc435, 0xae15de7b, 0x7e6ded5c, 0xa04fec3b, 0xe8c9da77, + 0xb2dcbd9f, 0x3ed1a026, 0x7991c958, 0xaf49f4ca, 0xdba52c95, 0xcbe06d79, 0xd381cc60, 0xeec9a2d5, + 0x033c5d19, 0x252561a6, 0x3aa93362, 0x4d8b349c, 0x0d56782d, 0x6ec21ac7, 0x2d44147c, 0x5993e1e7, + 0x15c94c49, 0xe415e14d, 0x1f08bcaf, 0x62db1a63, 0x038275dd, 0x797c142a, 0xe5eb6356, 0xb68ad848, + 0x4e00b3be, 0x70e495df, 0x9219799c, 0xde738eba, 0xa2f3987d, 0xb2acad6e, 0xe7211de0, 0x32b5a053, + 0xacd4ec80, 0x61606006, 0xe6ed72fd, 0xdb895d31, 0xcfccd698, 0xff5bd762, 0x424f5925, 0xe77d24e2, + 0xf252e10e, 0xcd190e4e, 0x00c72a34, 0xda5e5c0b, 0x3533990f, 0x651e4210, 0x5766163f, 0x02d87b45, + 0xd36f743f, 0xb9f6f75a, 0x544a0c1f, 0x6e47e612, 0x8e8f14da, 0x2bb61378, 0x4d5d4594, 0xb094b025, + 0x511616b0, 0x256fbf61, 0x171bc853, 0xd27c4219, 0xecf16ef0, 0xb0835691, 0x10fc636d, 0xa703f28d, + 0x1292386c, 0x5d5a2e3a, 0x57130f6d, 0x7b785360, 0x689f12b8, 0x9f4edf66, 0x4c55c091, 0xf9b7620e, + 0x89c239bb, 0xdea92940, 0xb79f1080, 0xa5e24190, 0x8eba67be, 0xffea6a3d, 0xd99ac4dc, 0xe0436968, + 0xcbd452f1, 0xd9f70be9, 0xd3d4782a, 0xaad53c45, 0xc7465c98, 0x605782cf, 0x50f4323b, 0xf962e8b6, + 0x276159b6, 0x0dae42bf, 0x6e95da32, 0x41c8144d, 0x0f2c053c, 0xccfb8fff, 0x48a9f45d, 0x02f85733, + 0x50802fc5, 0x08cf540e, 0x7461ec23, 0x4fb247ee, 0x2ea3aecd, 0x95e67731, 0x8934537a, 0xd91a08dd, + 0xb9f69111, 0xbea89070, 0xe1a7fc44, 0xe095509a, 0xec0e6654, 0xfde6c612, 0x44a91725, 0xbb0c4e72, + 0xbc1d02a8, 0xca7ec5a6, 0x4769a0e1, 0x7586cc56, 0xf236ba71, 0x4a374da2, 0xc8d3459e, 0xad090424, + 0x9c5b459d, 0xc2734db4, 0xaea21319, 0x06fcd892, 0xdac1c461, 0x9a9fa54c, 0xb34bc36c, 0x4af4e6eb, + 0xea0cb3ff, 0x538b026b, 0x233afa8c, 0xd90c6987, 0x66cf32c3, 0x05acb0b6, 0xe3ee80b8, 0x51de0ba2, + 0x4f718284, 0xb9c80c7d, 0x24660156, 0x54dd2b9b, 0x2c73f3d9, 0x0952ed27, 0xdaa27c0b, 0x7dee7f19, + 0x4743dbff, 0xccc2176f, 0x57db9996, 0x9b8063a6, 0x8e43ace1, 0xec748811, 0x5084a42b, 0x8ac4c38d, + 0x47d37121, 0x23aa4c02, 0x455ef40b, 0x6d3d5d38, 0xa3701e88, 0x4723e40e, 0x233fb57c, 0x7e31cfb1, + 0xe6efd29d, 0xa2f53ad2, 0x07e6c59c, 0xf85d87dd, 0xe9aea1f0, 0x301d0f5c, 0xf4fe8579, 0x903fcc42, + 0xd0969cc0, 0x0c845a4b, 0x8513f1fd, 0x517fc136, 0xa7f3acbc, 0xb23c2b27, 0x39bf49b3, 0xcdec91b3, + 0xb90ece49, 0x27e19267, 0xdd82c5d7, 0x4b1212bb, 0xf87b81c4, 0xea38acf6, 0x751ef88d, 0x90567099, + 0x932beb4b, 0x2a9a5d8b, 0xc9818ddc, 0xd886699c, 0xbad3ca1e, 0x892c104e, 0x2cbdaa13, 0x3a304c28, + 0xbbaa23ca, 0xd9523b21, 0x336f50ec, 0x7c8a6227, 0xbffe9758, 0x9185d5b6, 0x8b01f7da, 0xf2178944, + 0xbef28552, 0xb42cf6cf, 0x5dceab76, 0x95fd6e87, 0x20847886, 0x9a738cca, 0xdc18d857, 0xd381c2ab, + 0x4b9c1b7b, 0x041e26b8, 0x7dc7cd17, 0x3032f123, 0x3a30bd41, 0xbee77c75, 0x5c63c642, 0xb433ef7c, + 0x95e9eaa6, 0xfae4470c, 0x65f5dd86, 0xe02251d1, 0x67865a53, 0x5caef463, 0x744a615b, 0x7d3c7f35, + 0xa2a9ada5, 0xdbb696c8, 0xca8058ea, 0x93ef57df, 0x6f2ba149, 0x888bf97d, 0xdd03776c, 0xad781271, + 0xe6be8ed2, 0x44de51c1, 0x7acb18ce, 0xc9e282e3, 0xddd9a27a, 0xe6d377f5, 0xfd80a68e, 0x33c9c668, + 0xa8b3dae5, 0xd24965b2, 0xe6504333, 0x63ec48df, 0x8281eea7, 0xaf42cca9, 0xafd36fd9, 0xfeb64c7c, + 0xc1a1cab9, 0xa50932b9, 0xdf7f0dea, 0x5eb346be, 0xb80df5c4, 0xa66879fe, 0xdf61df21, 0x5fac24c1, + 0x653aa5a9, 0x6ff1a9fd, 0x4d114ac4, 0x61439665, 0x25ffc409, 0x25289179, 0x1e2a041b, 0x05c079f3, + 0xaeab098d, 0x310320a1, 0x5616814c, 0x1fd492cb, 0xf713d013, 0x586b910d, 0xeabb6cc3, 0xf39f6f88, + 0xd18777b6, 0x7a466ce9, 0x063bfe36, 0x2632adc9, 0xa15676c0, 0x3baab977, 0x8a2eb784, 0x9a43a925, + 0x9d80e31c, 0xf2e0389a, 0xc3808fd3, 0x134fe749, 0xd1835a01, 0x55b32109, 0x02af4222, 0x84130aad, + 0x906578b6, 0x3a82937a, 0x07e972a6, 0xb587fa51, 0xbb1e0560, 0x324485f0, 0x2b15037f, 0xb458c11f, + 0x378a8137, 0xca2760a4, 0x4e9c2250, 0x8e44da39, 0x772d7ea2, 0xab53567a, 0xe6da11b3, 0xb1ec3e86, + 0x182ac674, 0x7b6c1eb3, 0xe4f9f707, 0x152b75ea, 0x050aa423, 0xceadd42b, 0x87aab2df, 0x815e443e, + 0x9d074975, 0x9665f520, 0x538d2a96, 0xc063a00a, 0x2b1f2c2b, 0xf6488e39, 0xbeb0c2fa, 0x894c7eb8, + 0x2689078a, 0x95c31203, 0x32363046, 0xd081902c, 0xf183cf31, 0x77daf16b, 0x84645e15, 0xba6f16fc, + 0xe33037e8, 0xe878cd04, 0x7063a472, 0xd28de577, 0x02a6352d, 0x82d5bf66, 0xee69dd19, 0x1fb50238, + 0x4474f8b7, 0xfc1e282b, 0xa9067294, 0xc8926c20, 0xfd09eae5, 0xdd37c1ab, 0x5fb56f88, 0xfc1fbbf0, + 0x6bf6672f, 0xa86774b4, 0x65e24416, 0xb7b674cd, 0x321e33d6, 0xf1fce1e2, 0x0a518b04, 0x82cb1d92, + 0x050f7ef8, 0x17b5bd4f, 0x27c771e0, 0x3db033b1, 0x981f4a50, 0xe35a1c70, 0x22da5663, 0x9f0f79b5, + 0x6feeae05, 0xb2fc15a6, 0x2c8f279e, 0x47137a66, 0xd24393d5, 0x7b89a7bb, 0x00911933, 0xd4661e4e, + 0x66f6eda6, 0x711dd667, 0x1d8d817a, 0x32ab4a73, 0x1c145bb2, 0x45ff2bf8, 0xfb8f4e37, 0x6e6d316e, + 0xf579c80c, 0xd77c4502, 0x9354426c, 0xd2ccdcaa, 0x6eb784e4, 0x5b8a8705, 0x0bdd8e2f, 0x1918c642, + 0x5aef5050, 0x9a7e3b99, 0x6c942883, 0xeadd5744, 0xb9f1fc61, 0x27be894a, 0x5cce6ae8, 0xde8ddb79, + 0xf03c0b4c, 0x528e725a, 0x23d5b0be, 0xb4bef076, 0xaa1a8eab, 0xf8d44bee, 0x0916fe90, 0xb45f8ab7, + 0x06dc8c67, 0x08ae7bf6, 0x9d66b5d2, 0x223a6927, 0xf1f8f8a2, 0xee9bf41d, 0x6f3e2e6e, 0x8acbbdf5, + 0x9936fe41, 0x9db03277, 0x7de1922b, 0xb9af80df, 0x38b746d9, 0xa7dd8402, 0x8e9a2eb6, 0x413862d9, + 0xef3803a6, 0xca16caac, 0x7e414215, 0xe25aaa99, 0xd3f332c3, 0xc5b98025, 0xde5d4cd8, 0xc1aadb57, + 0x4e0dc415, 0x5269bc28, 0xff91c849, 0xed113574, 0xa70dcee2, 0xec877e25, 0xb1e77bc6, 0xcfe2149d, + 0x70b78474, 0x7f68d0fd, 0xcfdad35e, 0x056cf2bd, 0x7b666c92, 0x12d448b5, 0xac1746de, 0xe67fd7df, + 0x7c67e651, 0x2006b4a6, 0x3686290c, 0xf0b4a5c5, 0xe99d6410, 0x2733aeb7, 0x88c4d327, 0xd84827af, + 0x899c7ca0, 0x4108a149, 0x0f8b1bf6, 0x86fdf991, 0x7ba08a19, 0xc2043812, 0x0897dfac, 0x2e6309e5, + 0xfad50e3e, 0x8f017642, 0xc8772072, 0xbb2b57d7, 0x0ff357a8, 0x37a05765, 0x8a8ee00f, 0x4132455f, + 0x22d29217, 0xb3d1e2ad, 0x07e7f92c, 0xca33f8d0, 0xd5c16c0f, 0x8de3e472, 0x30659aa6, 0xb10b72c8, + 0x5999ecc4, 0xa36ba01c, 0x3672bcf0, 0x8da3916f, 0x918b00d0, 0x5f2bfff5, 0x0890488d, 0x9859d205, + 0x0c90cd68, 0x3d99fbc5, 0xe6e5834e, 0xc8ccabf4, 0x5b9cc283, 0x3679a8db, 0x80865f6b, 0xc963c4e1, + 0xccb34082, 0x2a61d80e, 0x09431b96, 0x3a7ca1b8, 0x5a9f57ea, 0x53c7802c, 0x6db8ddda, 0xb5ce83c5, + 0x7a871d8d, 0x83597817, 0xb4b58564, 0xce9712c3, 0x19f0be7e, 0x95230898, 0xd038eccc, 0x16eb62c6, + 0xd337a28d, 0x413bd43a, 0xc37ce991, 0xe6160498, 0x222b6543, 0xd727ee1c, 0xc5ea5f14, 0xee7c9434, + 0x5221a4c7, 0x6f0ea76f, 0xea302252, 0x9b01ee5e, 0xe69b16b8, 0x5e5dcffb, 0x38bed9ba, 0x1f09fb6e, + 0xb226653e, 0x3521670d, 0xc8d90b57, 0x18ee5e7c, 0x941e017c, 0x6416e286, 0x30ed4a68, 0x3175c1d7, + 0x9b895e3a, 0x9666f38c, 0xc7d80d6b, 0x1f600ad2, 0x6393732e, 0x5271c153, 0x5cf38db2, 0x04972946, + 0x5fc4b745, 0xe45cc304, 0x5b3b3abd, 0x5b46b11f, 0xfdb4c617, 0x5e4a5c80, 0xe1a0a5f8, 0xef046838, + 0xbd8cc2b7, 0x999a2593, 0x0ac11172, 0xc6598cce, 0x93fd815b, 0x6363de73, 0xd583dc03, 0xb5bc9260, + 0xb1831200, 0xd78bf515, 0x36939ed9, 0x813200d8, 0x7dbd5e3c, 0x93038a01, 0xf372efbd, 0x955d3861, + 0x5a8ce432, 0x48db5fcc, 0x871ad464, 0x81a11bac, 0xdbc5cbe9, 0x9cbab44a, 0x49bf1477, 0x83cd266c, + 0x268ab6c3, 0x0b301ac4, 0x5342d82c, 0xb127bbfa, 0x00bfa9b2, 0x9e5643f4, 0xb322af84, 0x18d6c44f, + 0x071a5f0b, 0x8abd4bfb, 0x8b90660e, 0x3c47ef45, 0xbd880ed8, 0xc391cb8c, 0x0c5a2a50, 0x820c69bb, + 0x09510274, 0x404f6e69, 0x87d77255, 0x4a879ea2, 0x59276359, 0x23f1fd5e, 0x301ac36f, 0x7c076196, + 0x389d4555, 0xb165e4f1, 0xb7d20abd, 0xaf84cfe6, 0x11c86dbc, 0x355b75b1, 0x8c277329, 0x287d55ea, + 0x452dd813, 0x437e2651, 0x3fff2f02, 0x7a603e79, 0x4a435e56, 0xe6e370fb, 0x34418c16, 0x81cb141b, + 0xc20d86e7, 0x42ca2345, 0x716e8bb4, 0x0145bcd0, 0xe536bc34, 0x96255077, 0xf9e7e54b, 0x58776b9c, + 0x7951bda8, 0x39a650be, 0xa9856bc5, 0x27e51f42, 0xf03b98fa, 0x9b046cf3, 0xe8119266, 0xc603e81e, + 0x0f66b0f6, 0x41ac03fa, 0x771298a6, 0x1394095c, 0xb89f91a0, 0xcf2c0b05, 0x6618cbf0, 0xf2b69d73, + 0xeb3672d2, 0xa0752db6, 0x05cb7d7a, 0x601f86d8, 0x9cdd0a42, 0x8ce36880, 0xf84862bc, 0xb68de148, + 0xbcfb3dc9, 0x43194969, 0x736c3736, 0x0d453a18, 0x6ddc4d71, 0xb96e94ad, 0x049e2e76, 0x38724d35, + 0x51315ac0, 0x797dda3d, 0x44bc220b, 0x8d0149a3, 0xce2aa736, 0x56ec6a39, 0x4231080a, 0x4fc5f8c0, + 0x8c3ebfab, 0xf8df668b, 0xd774722e, 0x0b83f787, 0x2907ad09, 0xe2e63b61, 0xeeb38b76, 0x980e0e2c, + 0x49b5148d, 0x01203689, 0xa99ebd5a, 0x425d3dbc, 0xb1b55279, 0xf0c1a3df, 0xa8fbb5b6, 0x8b8f164a, + 0xfef71591, 0x0dd4979a, 0x77c063a3, 0x642649cd, 0x3c08bc29, 0x395ba0c0, 0x93f1642f, 0xd50fd8a5, + 0x5778a7e4, 0x6895a265, 0x164a3f3b, 0x75ecde0e, 0x902fbc3b, 0xed3ce9a1, 0x9389b057, 0x2ecaf74d, + 0xbd7376cb, 0x6b4d8dac, 0xae4dfaa4, 0x439d86f9, 0xc6d421a5, 0xb182927f, 0x5a32245c, 0xf3837d07, + 0xa2eb6cb4, 0x782166cb, 0xa24cecc6, 0x04a3aabc, 0x3764b1f7, 0xe4b0a216, 0xcd61663b, 0xf761b4c3, + 0xffb996be, 0x195a9652, 0xed5980cc, 0xe53dcace, 0x994367e0, 0x9a3c123f, 0xf7c71a2d, 0xb8ee940c, + 0xa8ac17ee, 0xffdd39bf, 0x64f8695e, 0x31c544d9, 0xf787cfe5, 0xe32e5717, 0xd8caa530, 0x3eb9ed85, + 0xc3bb1cf4, 0x5bd904d0, 0x902fb978, 0x1cf030ab, 0x8671afc1, 0xa7a2a4b9, 0x11d4e3b3, 0x38df4ef0, + 0x62301836, 0x64ff6d14, 0x7b5b90e5, 0xd4c5301b, 0xdea851fa, 0x3d244741, 0xec60165f, 0xb5220f09, + 0x5d9bb148, 0x3d96711d, 0x0403c4f7, 0x4d6b9f62, 0xdc45e106, 0x66bc6c8d, 0xe9215e82, 0x5f5e0d0b, + 0xef2d63cb, 0x5fd359ba, 0x270eb591, 0x8c48b51a, 0x4eb9750a, 0x26fd4e40, 0x6f374997, 0x240635be, + 0x6daa4276, 0x54ea6a64, 0xcbb06129, 0xaf0058d1, 0xcbf472ff, 0x6c394016, 0x530500ac, 0xe03cf56c, + 0x890d095e, 0x9e04eeec, 0x73041d25, 0x75202b00, 0xcdde20e8, 0x4795f1bf, 0x67808421, 0xf1b63ef4, + 0x4933de88, 0x8e273b43, 0xc72d9cf6, 0x4d330f0e, 0x8ffe2aa8, 0x46dcdf85, 0x2fca41d7, 0xa1178f0f, + 0x2c308ba2, 0xa3c16447, 0xe5272fbb, 0xbad3b3b1, 0x2f8eb7f8, 0x3f3450be, 0x65689bf3, 0x366cd176, + 0x94453e4c, 0xc7430b23, 0x578508bb, 0x9c6185b5, 0x73d30186, 0x97027b86, 0x3a663e3a, 0xa9187df0, + 0x5b836fc6, 0x5eba863e, 0x6fcf0eb1, 0x3a4db642, 0x30fbd8d5, 0xe189f400, 0x7094f0e8, 0x6b377432, + 0x558f0d38, 0x18762120, 0x60efcc4d, 0x7f0462ba, 0xebab284b, 0x3368aa79, 0xa2ed9854, 0x1593f800, + 0x1b294d63, 0x12f1d1e0, 0xc1d35f23, 0x8871bac0, 0xf07c151a, 0x040e0c14, 0xd4d2fe5d, 0x3cf77e2c, + 0xab139c63, 0x1b851779, 0x371c8b4c, 0xcef25352, 0x21b502c8, 0xc55cd956, 0x7dcd8846, 0x69c73272, + 0xbe423951, 0xc0682508, 0xcff9ec00, 0x56e77a85, 0xf40d7802, 0xf759339c, 0x01664d5c, 0x51e81fd2, + 0x68115685, 0xb88cc39b, 0x355ce168, 0x8aeef4b1, 0x5471cf2c, 0x2d3b973c, 0x075c3da1, 0x170140dc, + 0x4dc51362, 0x0d74720f, 0x561695ef, 0x224f2be1, 0x49be8b72, 0x09e69a5a, 0x72db41d4, 0x637d2762, + 0x58fb4118, 0x81e1b6a0, 0x8d2c61fd, 0xbeefd7aa, 0x002c0ff7, 0x574a60cf, 0x589598cc, 0x41204b9d, + 0xe55d0413, 0xa52fc239, 0x00aee3fa, 0xa67b2713, 0xa25d678b, 0xf0862361, 0x5d705c8b, 0x70a489b4, + 0xe61e1858, 0xd0f362a6, 0xde1640f6, 0x270b08fc, 0xae238a6c, 0x93c3601e, 0xc678c765, 0x23e080bb, + 0xcb118649, 0x775578fb, 0xa3907105, 0x4afabf89, 0x1ccc1a9d, 0xbe0b18ec, 0x3250fefe, 0x31471fd4, + 0x2419bd52, 0x77a4196b, 0xc306dbd7, 0x62910c4e, 0x4cd55a0d, 0x53788577, 0xad97e350, 0xc91a6aa1, + 0x281d6cb2, 0xf793f607, 0xf08954e3, 0x9653e2d1, 0x67c01740, 0xc2fb63ee, 0x5b2753bb, 0x9a690b64, + 0xa26610c4, 0x1a6304e7, 0xfcad6082, 0xb46552ac, 0xb4e65a20, 0xa0555f42, 0x44678453, 0x2ab490c8, + 0xd1d9d11e, 0x8242a0ae, 0x65776788, 0x6b1e38c6, 0x7ca93a87, 0xaa932936, 0x15d71ab4, 0x94e6594b, + 0x0586d679, 0xa626583d, 0x0413719c, 0x95b08ded, 0x764f0161, 0x17a7666b, 0x6e81c116, 0xa1f58c5f, + 0x13402928, 0xe094beb0, 0xe71a7881, 0x383d1f89, 0x04908aec, 0x12d75ee7, 0x9ff474d9, 0xdbcd3cea, + 0x12c4a876, 0x82e94b82, 0xedbd2931, 0x94a859ec, 0x93bbe801, 0x3ba2291d, 0xcfc47557, 0xf7190af0, + 0x11914eae, 0x28d36778, 0xfd6c43e4, 0x0e50c22e, 0x89e98904, 0x20228548, 0x097ad1fb, 0xb350b4b9, + 0xe1e49d59, 0xc550c544, 0x25f04a25, 0x51398401, 0xc551334b, 0x4cb9a207, 0x4d5b7f0c, 0xbdd676fd, + 0xc23d3f21, 0xa220ccc6, 0x2223615c, 0xcf9093dc, 0x06fca3c3, 0xfd510ba6, 0x78d17a60, 0x5e0b2b2e, + 0xcef6f422, 0xf105dd94, 0x3742423c, 0x1bf34594, 0xebb096b4, 0x01079059, 0xe7df3bec, 0x2e2d702c, + 0xacea15a9, 0x4101e693, 0x1da0d8c7, 0xed1f0991, 0x6fbc69f4, 0xb872bbe0, 0x3c088da7, 0xf57e6805, + 0x483d5e2d, 0xecceee9b, 0x99738e57, 0xda4e6a21, 0x01b833e7, 0xeb1064be, 0x9c2a7559, 0x81e3c1b7, + 0xe20e863b, 0x413f79be, 0xe45db918, 0x22d3ad09, 0xf6cf7b0b, 0x14892b1e, 0xaaf19349, 0x5761880c, + 0x62cb4cb4, 0x83d6a3a5, 0x724c20d4, 0x4544d25b, 0xf249f3d5, 0x1f6c903b, 0x720434a3, 0x04c0a89a, + 0x279aab1f, 0x3bc8254c, 0xc968a82e, 0x24084606, 0x337058ae, 0x5e385db2, 0x60f7a9cb, 0x2b1cc767, + 0xcb2caec7, 0x1d69d8eb, 0x58ce5e6c, 0xdd68525e, 0x9e26a2c2, 0x9c6929b2, 0x3cfa8343, 0x4257be8f, + 0xc1879b39, 0xc8496015, 0xb5fec86c, 0xbb9e17c1, 0xe9ce5cc2, 0x0228c38d, 0x0bb3b3f9, 0xcad30b6d, + 0xef9bf007, 0xb86ed339, 0x3ba1d723, 0x61be152e, 0xb8fe2881, 0xe4627ed9, 0x8621fea9, 0xeabe8442, + 0x782228d8, 0xbf5a8f53, 0x8d8ea35b, 0xcaf1b8ae, 0xc86ad406, 0x0c2aa120, 0xaf7e5d65, 0x9368693a, + 0xa6e12b6d, 0x999b3af4, 0xed7e77a1, 0x4a04cbad, 0x4260cce5, 0x5d655345, 0xdf838bc3, 0x2c3de7b5, + 0x9f878ae2, 0x75961d9b, 0x23595a50, 0x8f060c48, 0x62fa9440, 0x52b4bb6f, 0x0f835a2a, 0x9952bb22, + 0x99c5fc98, 0x760452b2, 0x88f26efa, 0xb0291033, 0xa739c81c, 0xa3f5a3dc, 0x0820cd04, 0x6dd00a02, + 0xfc783589, 0x79227161, 0x4af0e097, 0x50ab410e, 0xdf630152, 0xb13806e3, 0xebddaf56, 0x8263914f, + 0xdc4ee3dd, 0x71ecafe7, 0xfcb167ed, 0x245e379c, 0x38282703, 0x18d052fe, 0x757ff813, 0xbd430953, + 0x8102880e, 0x0165c40b, 0xd4b2457c, 0x93f0643a, 0xa9175f7b, 0x70fd1d69, 0x6be52c8c, 0xa2e07745, + 0x9b06a014, 0xb0ab741c, 0xa34b0018, 0xea23c005, 0x1ca55ed6, 0xb68852a6, 0xe2eabfbb, 0x49f528a9, + 0x9f20f27e, 0xf3dda86f, 0xe202d24c, 0xf43078b0, 0x228eb1db, 0x17c6a113, 0xa3f5ff51, 0xcb75156c, + 0x9466b626, 0x9f45060e, 0x85dde35f, 0x646b4bb4, 0x45545b1f, 0xf2b0b06b, 0x900459f0, 0xa7ed6440, + 0x6db97b2e, 0xf7ec211d, 0xbee9b0f2, 0x8c791e95, 0x944f93ff, 0xb3002440, 0x62408f7b, 0x47bfe3f7, + 0x394c80d8, 0x39ae0c12, 0xff15df23, 0x5f2986f8, 0x9c4a1523, 0x037d7457, 0x44fb40d4, 0xeb2e29e5, + 0xa7ea1a87, 0xf96b3a60, 0x8fec25ed, 0xf61a8a9d, 0xb47c0a23, 0xba6e5ef6, 0x426c960e, 0xdf993edf, + 0x18141976, 0xe652e8d8, 0xcba40aad, 0x2b5a8b78, 0xb8fbdd9b, 0x0848fa95, 0x0c93e619, 0xbaeb983b, + 0x67913dff, 0xf91184f6, 0x5d0d1d44, 0x61156e11, 0xfc35e6d3, 0x408a0d7f, 0xd422c704, 0x86269fb2, + 0x27a7bcd8, 0xf04b531a, 0x488c5542, 0xed7115dd, 0xcd91927b, 0x56bc199b, 0xff3380b6, 0x9f072a29, + 0x2461b956, 0x49e49609, 0x801029e4, 0xd97883d3, 0xa1e32d6d, 0x3d70339a, 0xfebd3e6b, 0x92933b86, + 0xacfc903d, 0x01a04208, 0x31e97e93, 0x6c950eee, 0x2bf0a8a2, 0x8fe9a86a, 0xf5561663, 0x5faa2343, + 0x4a6f69fe, 0x28d4b615, 0x58629567, 0x1412985b, 0x3c57f340, 0xc2b8c45a, 0x71140236, 0x7541cff7, + 0x71b12b3b, 0x6cb26562, 0x7a36d9cd, 0x8f83387a, 0xfba5f819, 0x62c19fa1, 0xa49f5207, 0x7044b2f0, + 0x35b48cf4, 0x9eb503ca, 0x1a59c6b4, 0xdfde62c9, 0x10845d91, 0xfe7e1a58, 0x6ffc2a19, 0xfc4044ed, + 0x175ab1b9, 0x32b45a1a, 0xd3cef4f7, 0x48d9edfc, 0xf302beae, 0x7af55f1d, 0x0df3d50b, 0xc22419fe, + 0xc19d5cc4, 0xfb2ea7a7, 0x0dde367f, 0xe997cc61, 0xe0712f23, 0x4c268d92, 0x99db699e, 0x2f40aeee, + 0x2751890b, 0x398c10f2, 0x0e2fcc4b, 0xb02900bb, 0x1a4fa183, 0x344b6b28, 0x1270ef27, 0x05f19f99, + 0x984c26f2, 0x277b95f7, 0x66721b88, 0x653b8de8, 0x38e8cda6, 0xaac429d8, 0xc31d0826, 0x1dc4801e, + 0x99e48bc5, 0xe4eee8e9, 0xacdf9782, 0x297feff0, 0x38add647, 0x29717a96, 0xb2def416, 0x042e528b, + 0x40232bff, 0x469162b1, 0x9e6cceb2, 0x12ae1df8, 0x6ba6c4e2, 0xcefcc651, 0xaeb95378, 0x715748a2, + 0x952bf90f, 0x660629bb, 0x1519155a, 0x41a9ffb7, 0x39f99cc6, 0xfe52e1c4, 0xe1b1cd7f, 0x882c15c8, + 0x8efb4d3a, 0x414f65fb, 0x4f7ef2d2, 0x8f00f465, 0x46b94f46, 0x2a2a16d6, 0xcb5a3450, 0x4783da61, + 0x01c20315, 0xa3a3026c, 0xd9253b7c, 0x23cc09cb, 0xf9b8bb45, 0x444e3f0b, 0x4bd5a3d4, 0xcd43e6b4, + 0x9d048e2f, 0x29d05890, 0x732f6fe7, 0xf9d8a3aa, 0x97b915f6, 0xcc00a315, 0x68b63f89, 0xd952c252, + 0x07ad5741, 0xa5f943b0, 0xd9779a2f, 0xb0da7fab, 0x7fe92252, 0xbf3ccb55, 0xf3c990af, 0x96c8b47c, + 0x107372da, 0x709957f6, 0xc27303c5, 0xeaa5e5dc, 0x8e53ee4c, 0x0acb63c3, 0x8a269990, 0x2ba7ac8c, + 0x5d759fa4, 0xc99d4578, 0x1cceadef, 0xaade8b59, 0xd3dcfecd, 0xb11cd1ae, 0x4a1643ec, 0xb954e40f, + 0x2d1eca42, 0x0c386480, 0x39e37231, 0x86f04fe0, 0x84b40165, 0xcecd9aea, 0x4acc3ce9, 0x9b90c155, + 0x5e1249a8, 0x6fd3b1f3, 0x914b859a, 0x213ab7d0, 0xfc75f31b, 0xd133bacf, 0xbee52f50, 0xee2cd23f, + 0xb9bb4948, 0x14a48516, 0x32677656, 0xb1e84637, 0x35d1313a, 0xf922307d, 0xc9376be5, 0x0332d944, + 0x6b85e831, 0x0d6f5f70, 0xb8376473, 0x30871295, 0x39cfcb3a, 0xff81bc76, 0x54cef5ab, 0x0403cf43, + 0x298224cf, 0x96667b25, 0x0773475e, 0xb028c808, 0x38bcb114, 0xcd405e26, 0xca92b06d, 0x7d36eeee, + 0xae53314e, 0x4e5dc317, 0xe3683547, 0x63feb6c5, 0x4c22f475, 0xdcf829e7, 0xd8c3c39f, 0x3b3a458f, + 0x944d1834, 0x727da69b, 0xe7ad3a48, 0x469a6e58, 0xf4a6cc29, 0xeb678409, 0x24e167e1, 0x47ad26f3, + 0x593aaa55, 0x11c78e8e, 0x74dfc7e6, 0x9b34405f, 0x8b1d9bf8, 0x4d63608a, 0x5b50be66, 0x90472e35, + 0xf79fe821, 0xee36d8b0, 0x600460a2, 0x63d8e6de, 0x7fcbdf96, 0x10959ade, 0x2d497c3c, 0x538027d3, + 0x522f50a7, 0xabd1eac5, 0x8e3749b8, 0xa490bb1f, 0x48753aff, 0x175eacb9, 0xff7e6ee5, 0xeaf606fc, + 0xbe8f993b, 0x0a26e3ae, 0x8e115ace, 0x0261fea4, 0x6e6fb4dd, 0x7865fc72, 0x00d6d3b2, 0xf6060c0d, + 0x5f34ab29, 0xe35abec6, 0x8315f4f8, 0x54986865, 0x7af3085c, 0x3d85a103, 0x885b9537, 0x572565dd, + 0xc5c626b4, 0x90d4974f, 0x426aa53d, 0x03178dbc, 0x64c16d80, 0xbf6eff7d, 0xe7a2e455, 0xfb14ae9b, + 0xe1f3438a, 0xde98b8d5, 0x4f2ad488, 0x8b9ee91c, 0x238952eb, 0x70790595, 0xd058a903, 0xc972b228, + 0x7fe847de, 0x9784d274, 0xc70fa754, 0xf1f0a6c6, 0x5fa59f26, 0x02bb3d9e, 0xac665ea9, 0x2ac1917b, + 0xcdc502a0, 0x0252e3c7, 0x0cba8f76, 0xc72f34e1, 0x1d963362, 0x58fe636f, 0xab48d516, 0x27fbc77e, + 0x28b6cf49, 0x016104d1, 0xc465bb06, 0xe349955c, 0x9bc3d0f0, 0x64a8ec9e, 0xf6c59c90, 0x8f9943b4, + 0x11303038, 0x4deeb3b1, 0x3413d8a8, 0x15471e87, 0x854b7059, 0x4b9cf9f7, 0x79dca52e, 0xb7f5558b, + 0x8ce2d67a, 0xca5a2d67, 0xadb35008, 0x12d6bbf4, 0x0e732a64, 0xf07259fa, 0x05ac018a, 0x44717ef5, + 0x622e2dde, 0x8558d081, 0x70ca1a3f, 0xf9f1add8, 0xddff40e4, 0x5380e69f, 0x44cf1019, 0x85539a82, + 0x4bf892dd, 0x40f53b1f, 0x61587ba8, 0x1eeb2ccd, 0xd81c73e1, 0x44f9031f, 0x645ef2a0, 0xa7b14b43, + 0x1c7d88ec, 0x98d5ad97, 0x97f249dc, 0x055baa32, 0xf8e416db, 0x63fc0df9, 0x3971094a, 0x6340d467, + 0x2dc6ad3a, 0x8a9b92fa, 0xb30dee69, 0x41627863, 0x12d62ca8, 0x15aef546, 0xc3237159, 0x17a73913, + 0xd3ef9145, 0x2baa65db, 0xdd9a0e2d, 0x320c3ea2, 0xbd74f9c4, 0x845c5fce, 0x3f8cefd4, 0x2390ff41, + 0xbc35c608, 0x4ba51de2, 0xf3216e35, 0xfc912e05, 0x258136f7, 0x5385b412, 0xd0eea9fe, 0x776ee445, + 0x994b331d, 0xdbba7311, 0x3d2b4026, 0x1cb5101a, 0xe8ae3476, 0x6d883238, 0xc5a1f4b8, 0xc02369ac, + 0x12d67198, 0x35a5ff7d, 0xd53a8aee, 0x637ccaca, 0xb0fa9003, 0x9dca1eaf, 0x0d4e145f, 0x324034a2, + 0x1ce5104c, 0x557550f1, 0x11ac7096, 0x9afdeeb4, 0x5437f685, 0x77fec6a0, 0x5b3090b3, 0x34618e38, + 0x17e2be4c, 0x43fecc33, 0x2c510fbe, 0x455a060b, 0xbffb74e1, 0x41cf70a1, 0xd5de3d97, 0x1fb1c2ef, + 0x55ce0a95, 0xa4b31f19, 0xd1a14c21, 0xd9206c7c, 0x6bda699d, 0xd5f70900, 0x1a9c913b, 0x9eb3f0a3, + 0x01a08d36, 0xb9ca53f8, 0x01228d46, 0x1f8d1d39, 0x139d60c3, 0xe366a30c, 0x4f506cee, 0x7b660cee, + 0x21a30fa0, 0x33951490, 0xdecb2e01, 0x8cc15ad5, 0xba6fde82, 0x7de6a711, 0x758e073d, 0x84cacc23, + 0x2dd9db52, 0x5880a2f7, 0xf1a313cb, 0x63589ce1, 0x025e56cd, 0x576d82f8, 0xdb5862a5, 0x00693d49, + 0xbc825982, 0xef243aa8, 0x7b7ba862, 0x0f102069, 0xe2c389d9, 0x316efd81, 0x92ced376, 0x543fbeb1, + 0xc29bb503, 0x610f4855, 0x0af6a274, 0x01d1426e, 0xc9099307, 0x5f4dc1f4, 0x6c4006a6, 0xf338660c, + 0x337375b4, 0x3ac50374, 0xed129252, 0x6d857a64, 0xa19bfafe, 0x92b82034, 0x89cb1b38, 0x41724806, + 0xd3e51c57, 0xbf30c6b9, 0xe1358870, 0x6de32546, 0xe3ad9149, 0x11904f76, 0x6e49bb94, 0x6079ef9c, + 0xbbdebc2e, 0x608cf68e, 0x935a83b1, 0x8f401b3f, 0x0c49a036, 0x5f1f4e08, 0x3731152b, 0x2dca4b7e, + 0x1f2d0270, 0x4b30e41e, 0x53a8e32e, 0x1b88b153, 0x2b1e8548, 0xc7b086e8, 0xcaca1672, 0x00567f55, + 0x695c950c, 0x640fa18c, 0x5bc06434, 0x4eb2ff54, 0x5ab7fe42, 0x51b73010, 0xcd543b6b, 0xf9b11df1, + 0x111c387c, 0x832bed2f, 0xab1ce70b, 0xf2ff21cd, 0x49972c72, 0x926e053c, 0xca9bc7e1, 0x275fb396, + 0x58e719e3, 0x5628ecb4, 0x0dc62dc7, 0xc0f05505, 0xa5dd24a3, 0x318aed1f, 0xd82a1893, 0x67cbea11, + 0xc0320c5a, 0x8e4dc997, 0x3de9eb3d, 0x95b46174, 0x9002faa5, 0x6873a889, 0xb56f41cc, 0xbb65d54b, + 0x18f9bccf, 0x366761dc, 0x0fe07c55, 0xa48eccbb, 0x231de215, 0x1fe30c78, 0x0b784f2c, 0xebd1a9ad, + 0x9d0f3103, 0x56d816cb, 0x0cd8d241, 0xa1477c91, 0xcb8700ad, 0x7402f4a0, 0x06b0ba7c, 0x9e58da56, + 0xc5103fc5, 0x4912f92c, 0x5044f59c, 0x0336af5e, 0x78d1494a, 0x6b850466, 0xe3361010, 0x952322a2, + 0x8bc62e31, 0x12aeab39, 0x52d00239, 0x3e365883, 0x75faa78d, 0xb88917ed, 0x27b0fc3a, 0xea3caa25, + 0xb7f14265, 0x83ece144, 0x59ce01af, 0xde6e6d24, 0x17920182, 0xe1884cc4, 0x4d7bb80e, 0x3ace0d38, + 0x16e492ea, 0x12fcd1e0, 0x63794a7b, 0x5e05f7f6, 0x73b34078, 0xd80bc0cb, 0xd5ce6338, 0x2781c9fd, + 0x7f1ceec0, 0x0c3905fa, 0x1eaef68f, 0xf788b79d, 0xb3fc5f98, 0x7a874719, 0xfb2a26c0, 0x39a106a2, + 0xda6e934c, 0xe4e2ff40, 0x0e869744, 0x980ffb02, 0xc40ae01f, 0x89d01c6f, 0x932fbf8f, 0xd3af60f4, + 0x737b139e, 0xd749bfdc, 0x4606550f, 0x8be38a31, 0xcdd022ff, 0x9a8230c4, 0xb93ac7d5, 0x38563eb8, + 0xbdd3bed2, 0x5e17ccc6, 0x210797ea, 0x9cc26dc0, 0xb8fd97df, 0x22027aa7, 0x0276213b, 0x2c1f4d8b, + 0x413c8143, 0xc9444d10, 0xe1d13ad4, 0x06ad36ab, 0xfc318d5a, 0xa88658f0, 0xb4a8be84, 0x5d8095ef, + 0xf2754686, 0x88a0d3b9, 0x402e7252, 0xdef78427, 0x3dbdf513, 0xa43ce94f, 0x1e564733, 0xd944c7fe, + 0xe86da619, 0xa1860a19, 0x28627247, 0x4e94c738, 0x9171cf00, 0x5367a919, 0x17bbdba8, 0xaf7a3094, + 0xd635edd5, 0xe51dd068, 0xb0c1316c, 0x179f0a97, 0x67a25a4a, 0xe31b6765, 0x363759d5, 0xf71f0733, + 0x4b3ab6ca, 0xe52c679f, 0x60d55339, 0x76a22dbc, 0x02a96565, 0x9d4035cb, 0x01960af3, 0x510a3e9a, + 0x0233816a, 0x6d8dd769, 0x5a3bc1c5, 0x09e6eadc, 0xc1a245ae, 0xbc29318a, 0x56361c64, 0x72d12590, + 0x0072e2cd, 0x54fc9e10, 0xe50a49d4, 0x00ef872b, 0x2a3b8a4e, 0x99b6b5be, 0x4d9b9a7b, 0x16efc1b2, + 0x73b7617e, 0xed8316f1, 0x35422203, 0xc622830b, 0xb31850fb, 0x7bbcce66, 0x5277d0aa, 0x3c480c27, + 0x52437faf, 0x843db4c3, 0x9da25154, 0x01b4cac5, 0x1d2368a3, 0x6ea5e773, 0x80852af4, 0x9cfc5a46, + 0xedb18739, 0x2aa2a31e, 0x129def85, 0x2787ccf8, 0x882887be, 0xce8f7b29, 0x1575937d, 0xee616ecb, + 0x2480302f, 0xb8d217c2, 0x37ed68b0, 0xb048917f, 0x3fa3b86a, 0x20ce2797, 0xb310596d, 0xba410a54, + 0xc7b9bd33, 0xf09abc2f, 0x2150e698, 0xb7948cbe, 0xd4186e1c, 0xdd9f85e8, 0x243dbd8c, 0x70213f9f, + 0x3fe87640, 0xf96c0307, 0x2f70612c, 0x833c659a, 0xc53f7351, 0xeaf3ed9d, 0x55cc8575, 0x508e6f77, + 0xea2ee3ac, 0xdbc2164f, 0xf64c3daf, 0x8ee590fd, 0xe2a4ccba, 0xb0c2b35f, 0xd75a8938, 0x97bacdd2, + 0xfdcc6a55, 0xb03e8fee, 0x33be3d25, 0x1e4040a1, 0x0eccbd37, 0x03f36fd7, 0x2e03b350, 0x2aa0dd3c, + 0x4ecb8e46, 0xff468918, 0x8154c8aa, 0x9d53aaec, 0x17c052da, 0x3e2419c7, 0x8eaf4e4f, 0x2aa3f174, + 0xe48f6244, 0x72e2f2e7, 0xfc5da82a, 0x32d8906b, 0xd7e41b39, 0xcdaeb1de, 0x0d94ca56, 0xcfefb6af, + 0x4044627f, 0xdcc5a33a, 0x03ed851d, 0x255b95a2, 0x0dd9a20d, 0x5d5bcf78, 0x31cb57fa, 0x0421f2f7, + 0xd67990b6, 0x8e805e40, 0x09c322f8, 0x9125c13a, 0xe236db14, 0xbe022c12, 0xaadfbf58, 0x09488214, + 0xbe11a3ba, 0x116f1726, 0x790bec7d, 0xf46d950e, 0xc9a5e943, 0xe5540ee0, 0xe6fce795, 0x4db1c568, + 0xa1bc5625, 0x8c03c021, 0x16076455, 0x3a96d81b, 0x452231e1, 0xe24543f6, 0x336b1ee0, 0x9f24f5a2, + 0xa556b0f0, 0xeb0447fb, 0x3ae8314c, 0x6aecb651, 0xb7c524fb, 0x7f237094, 0x6e946244, 0x4ee327b3, + 0xed467238, 0xa4149419, 0xb1be8704, 0x4f57cad5, 0x3e71839f, 0xa03d7bc6, 0x4c8f2033, 0x89c059a8, + 0x18d052f9, 0xd089e43d, 0x3aa9bcb0, 0x91853abb, 0x893a0c40, 0x4e34595a, 0xde7f1831, 0x8ebf6a14, + 0x8063062f, 0x17475086, 0x179889fd, 0x4b23e180, 0x04c350ea, 0x924a0cd9, 0xa24eebb7, 0x72cca8aa, + 0x750dd167, 0xc353d640, 0x3ed6f964, 0x801921d6, 0x646d6164, 0xac53bc9e, 0x6a20cd38, 0xfbd3516c, + 0x28215946, 0x7c20a319, 0x43c38a0a, 0xfedf585e, 0xa4106f6f, 0xabbc55f6, 0x1872388a, 0xcdda3a3b, + 0x30075a22, 0x4906a6b7, 0x3c55f7da, 0xb68669d0, 0x3640e75f, 0x8e28ae4f, 0xcc141971, 0x698ea598, + 0x55280d62, 0xf4d83b33, 0x79cd36c4, 0x662d56ec, 0x601f0c1c, 0x16194ebb, 0x4eacedf4, 0x88bf2f9c, + 0xb5aca66f, 0x02214958, 0x99c04afe, 0x417e436b, 0xd6ed650e, 0x019d9c0a, 0x92be7621, 0xdc5af6fb, + 0x879ecfde, 0xbc416625, 0xd6f2fdc6, 0x4092f0fe, 0xcd3f9aa5, 0xc2b39525, 0xa1f83bed, 0x41c6cd9d, + 0x3744868b, 0x50ab339c, 0xf3dafa3e, 0x80b2ff0a, 0xbcfe7929, 0x17c369f2, 0x4cb4b76f, 0x9a52c066, + 0x7cfa404e, 0x0c97d982, 0x394b7023, 0x6de868a5, 0x5073d7c0, 0xfa7eacb8, 0x208c6039, 0xf395ac76, + 0x5eb76df1, 0x24ac30a8, 0x0b9867f3, 0xf2ad4a48, 0xff7468a3, 0xd0c771bc, 0x9ace3f89, 0x35237cca, + 0xe26b63d5, 0x9b297869, 0x83655dea, 0xceb75b42, 0x70ce56b9, 0xe80f2a03, 0x8058c4de, 0xeb38a50c, + 0xf9588bef, 0x44824c24, 0x511aace1, 0x72cd8d7c, 0x37dc3495, 0xcf9630b1, 0x7c16a635, 0x5fa9a28b, + 0x3d856c8f, 0x26c8ce5d, 0x8656fcf2, 0xff993216, 0x955f99a0, 0x48baab01, 0x8ae83ac1, 0x69085118, + 0xdb795aa2, 0x5d857f84, 0xcee560c0, 0xe938f0bb, 0x5b937e1c, 0xfc1130a4, 0x7a4d7d37, 0xabc2e629, + 0x0d6f63c8, 0x83cc9437, 0xc5a26c66, 0x8bf6197c, 0x568e7a18, 0x1e5ea2e6, 0x49268a7d, 0xc0a1a876, + 0x7d8f1a1d, 0xb2118a90, 0x53dd8519, 0x1ccccc5c, 0x7db62a4f, 0x4325381c, 0x26d0d4cd, 0xb83a9af9, + 0x8e0e9684, 0x5b3d348f, 0x6a11cb5b, 0x50abaf0d, 0x9e0e0483, 0x85d96eff, 0x78489404, 0x5dd8aee8, + 0xaf19244c, 0x6c99e9dc, 0x718f6e96, 0xa28751b4, 0x726c3d64, 0x8a1eb0e9, 0x285d2d10, 0xb7505e59, + 0x39cde873, 0x3ea74e2c, 0xc736dffa, 0x89c87967, 0x638510bf, 0x137df4d7, 0x0eabe370, 0x9e072be8, + 0x4c748df4, 0x1d2e4423, 0x5c3c712e, 0x7c9d0d0e, 0xf7a47294, 0x9fa593ef, 0x98d6e29f, 0x82e994cd, + 0xf3c7c0e8, 0xdd921368, 0x16e0bd0f, 0x3318670b, 0x40176664, 0xffbf999d, 0x2479cddf, 0xc1e848f7, + 0xe1993ff1, 0xc4541741, 0x05d8cf4d, 0xafda085f, 0xc0c0e1f0, 0xe518a260, 0x04eb6584, 0x0c8541ae, + 0x3876297b, 0x4ef3e42f, 0xc2f3c8ae, 0xe70a1c14, 0x32bedb09, 0x7ee5d866, 0x32616d9a, 0x9b7c7d4c, + 0x7f8297b1, 0xf3c4b388, 0x182e1d2f, 0x21d63dc8, 0x29183e28, 0x09d88338, 0x7a09f145, 0xd4c078bd, + 0x73805c98, 0x2a7d9cc1, 0xeaf3fd6e, 0x2e2b1e17, 0x2c6702d3, 0x788038d0, 0xe71b89a9, 0x8bf9ca00, + 0x1b623473, 0xe9d8995f, 0xdb034c3f, 0x9df2938b, 0x6ff463ce, 0xa2be6b4c, 0xdfe2f0f8, 0x6b2301e2, + 0x4e99ff8c, 0x77a314b1, 0x9b8e2d40, 0x2d2cd4ad, 0x4f21b15e, 0x6d7f8f31, 0x195f8d0f, 0xb98695d6, + 0x694c9000, 0xad651993, 0xd515d108, 0x6f0c5d01, 0xc13b1278, 0xb4a5dc4c, 0x28c47c55, 0xb152a92d, + 0xb45f151d, 0x2ce9b996, 0xa3c87760, 0x6ea8701f, 0xa680bdab, 0x41de4098, 0x68c01670, 0xe98e7e34, + 0xce891961, 0x36310a5d, 0x7ae6578a, 0x7c445ca0, 0x771bd3b3, 0x889435f6, 0x3584c052, 0x2023e055, + 0x61abae19, 0x12611eb6, 0xc439cb5c, 0x9d570b96, 0x26cf2301, 0x4eff96e2, 0xb9e34f1f, 0xcf842a09, + 0xcb44d4e5, 0x6a9afe8c, 0x1452cac1, 0x4653a5f4, 0xdcd62569, 0x6c2b8b68, 0xf2d99162, 0xd8251cc7, + 0x0caa3a49, 0xcde3ada0, 0x724ee552, 0x7f91b40a, 0xfda18239, 0xad96df99, 0x30c4d7eb, 0x5d7232bc, + 0xc4741d1a, 0xe7590274, 0xbb1b6852, 0x8f5bd34b, 0x3240b5dd, 0xbc0a3fac, 0x0f778959, 0xbf4a6f57, + 0xfa3395bf, 0xb24b71c5, 0x6cf00373, 0xd2f3a417, 0xce41e0e3, 0xa937bfa2, 0x6d98f9be, 0x2a24a9d5, + 0x7d06f382, 0x781ceaa5, 0x3d051b72, 0xd5022663, 0xd742e945, 0x10b26dda, 0x6bcfe51d, 0xca766f13, + 0x865ec322, 0x6a41895f, 0x5d0344ff, 0x7546c438, 0x8f9aa380, 0xc209d41c, 0x43123988, 0x9b6772a8, + 0x27554132, 0xb5d0ea52, 0x27f6f2d7, 0x1087a853, 0x75579514, 0x0e5f5c3a, 0x0b726ebc, 0xc8f5cdde, + 0xc5f25393, 0xa8625106, 0xf4b8d897, 0xe8853c4c, 0xa363bdeb, 0x301d969b, 0x4cb693d0, 0x99b58df1, + 0x5da7ad31, 0x839270eb, 0x797d6716, 0xd16935c2, 0x4b1fc27d, 0x07fc0c94, 0xdc63a8c7, 0x2c5cf332, + 0xfcf67eec, 0xbab483bf, 0xbf691bc6, 0xe0ad8d40, 0x370ac98d, 0x6489a451, 0x7b427b07, 0x3ccc983a, + 0x6cdcb138, 0x8f506832, 0x21ca2571, 0x265814b1, 0x69b24fd5, 0xeca9080a, 0x912f76e6, 0x5e6d54cb, + 0x88bc8e3d, 0x6e00bdb7, 0x828ed9d4, 0x06e27a42, 0x32173eb6, 0xc6972bc6, 0xbb981626, 0x3f2234a4, + 0x0c77b020, 0x01bb1dd1, 0xdfc0bb81, 0x3e0da993, 0x9c6db75a, 0x720bb9b7, 0x122466e4, 0x5e01832d, + 0x868690fd, 0xb159f995, 0x0981b169, 0x1eef7334, 0x948ab91b, 0xe792e630, 0x58d50ad2, 0x4798fdb0, + 0xbf4c2765, 0x1892c76f, 0x16e7cbc2, 0xa6eb9db6, 0xe89bb280, 0xe232995c, 0x12c9dd81, 0x79dec74b, + 0x61b216fa, 0xb6dae797, 0xbe16c477, 0xe49d20c2, 0x80209dc6, 0x6bba27c7, 0x1effdc6e, 0x3bdf451b, + 0x24580617, 0x23677865, 0x0c5f5b2b, 0x1f8bfc50, 0x3948eaa1, 0xb376151a, 0xe98a335e, 0xab7bd9fa, + 0x48006282, 0x6096cfb5, 0xe0ae59c6, 0x4fdb3237, 0xc23cfc0b, 0x7c6409c6, 0xa5e85669, 0xe933b403, + 0x31bdf250, 0xfe0b0a28, 0xa9384fe0, 0x508ee9a7, 0x7f8d7796, 0x1bfd76a9, 0x10b08b07, 0x3aec358f, + 0xe2382f80, 0xccfc6efd, 0xb93b88b8, 0x5936af44, 0x5f86e1f1, 0x5f2c74c3, 0xbfaf69d2, 0xe95b93a2, + 0xda61c7a1, 0x23de7a12, 0xfc88655f, 0x677700d5, 0x2d7db3dd, 0x143cddd5, 0x07198e07, 0xe99aa197, + 0x536894f4, 0x471c4ed9, 0x8aa94ea9, 0x928d3d85, 0x42ef171b, 0x8c7301dd, 0x70e2cfb8, 0x1104ad33, + 0xbd306763, 0x594aa331, 0xb814b814, 0xe96f7924, 0x45367eb9, 0x0951adc1, 0xb2e771d3, 0x845a05ba, + 0x69e1bb46, 0x09b1d628, 0x5161aa46, 0x4161567b, 0xd91ce6c8, 0xae91c38d, 0x80236ab7, 0x9248c27f, + 0xed08206d, 0x05435755, 0xb0d68b8f, 0xabd2af1c, 0x61173081, 0xa1347634, 0x23232d17, 0x6f155d8b, + 0x3fe5068d, 0x61ed9bac, 0x36c6e5b9, 0x82c6e289, 0x0e803e86, 0x0393305a, 0x5dd8ea2a, 0xb9786391, + 0xeefd5bd6, 0xcdcd9da4, 0x4f65de70, 0xf064ba08, 0x71933bc0, 0x2081efcc, 0x43a77039, 0x7d817821, + 0x3a4034e2, 0x8fe9f087, 0x18ec3ad6, 0xcd65f02c, 0x2e17b10b, 0x6b2c04ce, 0x21f8f317, 0x265cfeb3, + 0x0f90ddad, 0x7b0a534e, 0x7bdb6226, 0x32f229ef, 0x34a51704, 0xac9f3b6e, 0x2f24b3a3, 0xa202d700, + 0x4a9f8d14, 0xd7a5af4d, 0x3175ac80, 0xa789585f, 0xd8c5943d, 0xf8d5c9fc, 0x08293c93, 0x66f38f86, + 0x98640a11, 0xdd2e4f8d, 0xdc495da1, 0x6dd221c7, 0x3ac97546, 0xa4b6f8de, 0x972c2b7c, 0x6b6ce937, + 0x106c4ac0, 0x9489de50, 0x7a249730, 0x56617d1e, 0x8bc9e418, 0x4045bec7, 0x4c52d354, 0x53858fa0, + 0xf7854fa2, 0xead45ee8, 0xc6b63a53, 0x603277b2, 0xb493aeb6, 0x9d1f5889, 0x46c7ba3c, 0x1cc0d0e0, + 0x2e0c9dd5, 0x067ebcbe, 0xd91b860b, 0x240ed85c, 0xdd0368ae, 0x4d8e9198, 0xb1a0bd17, 0xc9c1b8ff, + 0x587d614b, 0x86e6e92f, 0x77126a7a, 0x0f212f77, 0xab0e9e48, 0x424fca68, 0x386bc7ab, 0xd37ac31d, + 0xfddaa495, 0xc1e5219b, 0x82198ab7, 0x57ab0196, 0x07a99de1, 0x82b341a6, 0x89e94494, 0x7ad01c15, + 0x9e4a53ac, 0xed0aa9f0, 0xdad0a469, 0x53a1715f, 0x64c5e4a4, 0x3a19e0f4, 0xb52d7626, 0x8a9e194b, + 0xb2042244, 0x9992b8cf, 0xcbb6b3c5, 0xf89fb5b9, 0xccc6b4e5, 0x8eb030eb, 0xbf90087e, 0x91b18286, + 0x04bf0f81, 0xa6ac1f41, 0x2a6d5ddf, 0x7cc010a2, 0x8a6e62ff, 0x3f973dd4, 0xeef54ee3, 0x2e6be9d2, + 0x71573909, 0x9a2297ce, 0x0fb2bf95, 0x5176e46f, 0x25187a1c, 0xaafa190a, 0x95515b4e, 0x127aa546, + 0xf431ee7c, 0x9e928f3e, 0x73a26061, 0x63f1bc8c, 0x636f1c9d, 0x2e15904a, 0x789ced5a, 0xee19329f, + 0xf1453f0f, 0xf00973fd, 0xfd9dbf89, 0x24dc4141, 0xf40357b3, 0xe246b626, 0x6bb09190, 0xec80ebeb, + 0x7e67fd40, 0xa85f0923, 0xc85352b9, 0xe094e9be, 0x3f3e6e87, 0x84f1a225, 0xc3c8993d, 0xf5a3e51b, + 0x9828b0af, 0xf7207021, 0x240f21b0, 0xafd44eef, 0xc2b37912, 0xa3c54c28, 0x20c5049a, 0xdae0701c, + 0x5d835584, 0x18bd44e7, 0x15afa091, 0xe8519bfd, 0xb177c291, 0x664b1fb5, 0x95327e05, 0x41854071, + 0x0083fd01, 0xd0ca77ba, 0xa35d902e, 0x8b87e855, 0x36bbbfc0, 0x6de60822, 0xe11849a8, 0xa3fbd2ef, + 0xe3771ab4, 0xdbd6ed55, 0xdfc51589, 0x122c3684, 0x74394740, 0xdf395b14, 0x8e216903, 0xbbff2ed9, + 0x459a652c, 0x7b05454d, 0x486c3bc5, 0xe578975e, 0x6ab38fd5, 0x24a8adc7, 0x3bb53774, 0xd3cbac03, + 0x8ff423da, 0xbce8d545, 0xa1e5a498, 0xc9e13041, 0x16029734, 0x3329dcca, 0xb6ed81e6, 0x14d740eb, + 0x49b91939, 0xbf0e7a55, 0xbb115d3f, 0x272cb836, 0xfef8debc, 0x05e0f7cc, 0xfbe386a5, 0x0682cf44, + 0xdc255ef9, 0x8b07c7ff, 0xc50c0819, 0x78d894c2, 0x0efd8316, 0x0f193c11, 0x8de9055d, 0x5e1226cd, + 0x73646e08, 0x8742b13e, 0xef1d9c5e, 0x5d3b8655, 0x50194cf9, 0xdab87243, 0x2211f9b5, 0x6244078f, + 0xa4d25942, 0xbce3d966, 0x3181e253, 0xc1828022, 0xc6dcea52, 0x8d080218, 0xe32cbf3f, 0xd28d234d, + 0xadbfd693, 0x902dd1fa, 0xad940551, 0x851abacd, 0x29e48527, 0x08133ea5, 0xb25c5066, 0xdcf6bf93, + 0x936469b8, 0x0aa2c8f4, 0x0b195c08, 0x9f0d082c, 0xb83bbbbd, 0x1c0b6b15, 0x3c08834e, 0x95c078a8, + 0xb245cebc, 0xcd9cb95a, 0xb2843e7a, 0x03db03cd, 0x6f6d9fa9, 0x917d8fc8, 0x02f8cf1a, 0xe9a8859e, + 0xf31f8adb, 0x59850ca2, 0x25300b27, 0x2494028f, 0x97396a7f, 0x4b3acd0b, 0xcdc1a1bd, 0xe9160615, + 0x33f5df48, 0x2d56e0df, 0xafd353a4, 0x063a7626, 0xffe29685, 0x683e311c, 0x6b4eb999, 0xb78d3c01, + 0xa984e7af, 0x4fa03d84, 0x96fd976c, 0x0adbeba6, 0x2e5f41f6, 0x88e079b6, 0x2e4e9e7d, 0x86431255, + 0x78802716, 0x33653ba8, 0xd4d8deba, 0x36893e63, 0x97dc4faf, 0x8a3cc43a, 0x0f0c8a92, 0x51efc730, + 0x3915def9, 0x1879fb6e, 0xb7525834, 0x18d75354, 0x0246cc56, 0x502cda75, 0xee6472e8, 0x67e256ef, + 0x0030b438, 0x5f07aa4d, 0x90735f57, 0x7d2642b6, 0xe0979424, 0xb5255a41, 0x133aabcf, 0x0ce99e54, + 0x8f5beb87, 0x189f8d89, 0xe856c08b, 0x499f9afc, 0xedabbe93, 0x5346e44d, 0xfc12deb3, 0x151c0219, + 0x95303d04, 0xed16efb3, 0x8a080db2, 0x3d1701b4, 0xbad0619a, 0x7a46e71b, 0x3ab2282e, 0x418b6be3, + 0xf2285ec9, 0x86ad08f7, 0x7404e659, 0xf685de35, 0x268610ce, 0x80a41d54, 0xcc3bb6d7, 0x1e888775, + 0x93e64dc6, 0xb63e35d3, 0x2d2d157b, 0xe823077c, 0x1166ccac, 0x3fb63338, 0xc275573d, 0x5bb37d79, + 0x8673a9bc, 0xf41d32b3, 0x153fa6f7, 0x3b0dcf13, 0x43b3965c, 0xfaf6fd1d, 0x350cc3e5, 0x46429b13, + 0xb36732d0, 0x73478da6, 0x525f4b67, 0x5774511f, 0xce9089cd, 0xb00a629c, 0x00beddb7, 0x63332048, + 0xc3feb717, 0x797ff876, 0x48947b8e, 0x3d77d169, 0x7cce0598, 0x7892f836, 0xe35bcc9f, 0xcb281471, + 0x2969e370, 0x66e96958, 0x633a9b3d, 0x4015faf0, 0xf1adcdcf, 0x24b2e00b, 0xce408ae0, 0xbccd9007, + 0xd7ad09a7, 0x0e3c996e, 0xa8d9c11f, 0xaf249c11, 0x3cca4af0, 0xb4233331, 0x62af0351, 0x63a1a84a, + 0x4e5f6412, 0xc117cd07, 0x985c0a24, 0x72bddbd0, 0x95e4fc07, 0x7e0e74d7, 0xb21a2f4e, 0x1d41adb3, + 0xa62d33dc, 0x5acddc48, 0x06d511ef, 0xa9193811, 0xf7f93cae, 0x264edb1b, 0xb6ba0e43, 0x9ef58360, + 0x169d5fa6, 0x57af6eb4, 0xa716aca8, 0x79d2739f, 0x6e5f04b9, 0x6d390c5a, 0xaf8368da, 0x695f71ce, + 0x00dfd5ba, 0x6cf83b8e, 0xa417095c, 0x554b4f99, 0x6ace9dab, 0x8f62151d, 0xb5b875ad, 0xbeda04cc, + 0x9b91ff0f, 0xd7611c9a, 0x7d4be83a, 0x02b1a92c, 0xfa106e6d, 0x06376d6f, 0x3d057dd5, 0x34f66430, + 0xbb270b85, 0xa041bda1, 0xe163a316, 0x2308715b, 0x80c9d6fd, 0x59174b0d, 0x28b00ff0, 0x41414450, + 0x293d01c4, 0x1b88eb16, 0x990669bd, 0xe23546ad, 0x52508ef9, 0xb386a49d, 0x35945a83, 0x571fedb7, + 0x756345a6, 0x6fa3e397, 0xab80398a, 0x59039f47, 0x2f5736da, 0x028ef4a3, 0xaf3eadb9, 0xb47c5a37, + 0x33ede9a5, 0xcf9690e7, 0xb56d9b28, 0x0df245ff, 0x074419e1, 0x2dd90dbd, 0x868ca4c2, 0x58900fa4, + 0x530db812, 0x38236b31, 0xbd28ea4e, 0xea7fa33f, 0x9ace1028, 0xdcc5ff9c, 0x4f9920a8, 0x597f9d8e, + 0xcaa98699, 0x9254e88e, 0x26ba59fd, 0x9afa33a0, 0xa8aabcdc, 0x01e28c83, 0x9ec7fe94, 0x81c5afdb, + 0xce047e56, 0x3ecd0c95, 0x1379f242, 0x45d83596, 0x7169e510, 0xa8ae3528, 0x4da87e80, 0xd5d04b51, + 0x01347b48, 0x9b467464, 0xaa4b45e9, 0x4da1cf4b, 0xd9957fec, 0x6c268623, 0x61512c8c, 0x93fafa7b, + 0xf65c0625, 0x83b3a00e, 0x45d86839, 0x61f584f9, 0xe12d47c2, 0x649deea2, 0x431567c3, 0x8c5bbbfb, + 0x70a3216b, 0x818400f0, 0x4d650ac4, 0xc7268575, 0xbc2852c8, 0x978ad97f, 0xefa2c39f, 0xf962bc4f, + 0x068cce3b, 0xb1214156, 0xddc69a22, 0x65e2602d, 0xd9e2f02b, 0xf887adc5, 0xb4b95ce0, 0x3a02cfa9, + 0xf0e536cb, 0x718e78ff, 0x4a960be1, 0x0f97f23d, 0x85aaa640, 0x5036fcbf, 0x6070bb12, 0x03f39f3a, + 0x0c43700b, 0x502ac641, 0xe5d1b74c, 0x11fde74e, 0x5ae65746, 0x0d513396, 0xf215494f, 0x89e8671b, + 0xe7170a22, 0x3d876537, 0x5b27ccdd, 0x1e9ee6e3, 0x5a50dc40, 0x61078e89, 0x8971b47e, 0x328aef23, + 0x9a3cfe5c, 0xbc1666a3, 0x7c9fe91c, 0xa224250e, 0x22ab5199, 0xb9f492dd, 0x481e5ed8, 0x00ac401f, + 0x17ad1c50, 0x72a309c8, 0x0c3d8114, 0x7e2059ef, 0x58ded48e, 0x78f1263e, 0x6c5f7c91, 0xdc727392, + 0xe0c2ab8e, 0x30acc16b, 0x07148720, 0x81da398c, 0x2b8f2fc4, 0x44b42489, 0x3b3b3851, 0x7ca40af4, + 0x242bb3bc, 0xfdfb4b8b, 0x82c03a8e, 0xc9b40534, 0x30c47eb1, 0xd58fe185, 0x5c2371cc, 0x7a504fb8, + 0xbbd9078e, 0x69ff2d04, 0x09b67bbf, 0x2fc6f98d, 0xbd563710, 0x0b2066b9, 0xedaa079e, 0x5c624f48, + 0x7144cfee, 0x84c43888, 0xa2cbcbb4, 0xed630dec, 0x64d9fc60, 0xe3e4391d, 0xc94576ca, 0x97b1b8a1, + 0x2556f45a, 0xcff6e758, 0x8465c62f, 0x92b92f2f, 0xaa0b3820, 0xd66ce346, 0xbd1e6d46, 0x22f07cfa, + 0xd9e4391c, 0xab01b257, 0xfd7e8fa0, 0xc143960f, 0x880297b9, 0x24aa4f52, 0x63d34a73, 0x0f5979b7, + 0xdf7f95b8, 0x3dbee349, 0xbe126650, 0xd138ee0e, 0xaec1d733, 0x1563bb65, 0xc3cf06a2, 0x5f70c27b, + 0xeba6aa29, 0x1b77315f, 0xab4eb0ba, 0x24398f14, 0x11f732ee, 0xe64a3cdc, 0x147427aa, 0x179be49c, + 0x4cc3a54c, 0xac0ef09d, 0x1e6aa07c, 0x25788d19, 0xa381332e, 0xc38cc5a9, 0x83860ae3, 0x0dd3c09d, + 0x7f84f67a, 0xf5ff4c81, 0xa25fdbd9, 0xda23a465, 0x9a11f17f, 0x4734ced9, 0xbce5518c, 0x0b023618, + 0xac2e8fc0, 0x453051e0, 0x6d735148, 0x08e73678, 0x341af0c4, 0x3f71a15d, 0xbede3ff5, 0x9855e144, + 0xebde0949, 0x529a946b, 0xe77999b9, 0x1390e24c, 0x7ab5253b, 0x12eda7b8, 0xdbb6ec11, 0x6e62c5aa, + 0xa0ae0e4a, 0xb2bd1da0, 0x7f32e667, 0xe408f6a0, 0xa88bc76b, 0x2494efbf, 0xb6b6b120, 0xcba6d2c2, + 0xe1e715d1, 0x38b81588, 0xc9b0c661, 0x806887d6, 0x40a73050, 0x7fcf90f9, 0xc385f093, 0x5183ee82, + 0x6154ce1c, 0x0d4f51b4, 0xb7c84abc, 0xf84f3629, 0xabcc76f7, 0x6a2b923d, 0x59df3c63, 0xb61fd25b, + 0xf83c49d2, 0xb9b3d4d1, 0xda3a6ff9, 0xff5298cf, 0xa1be0818, 0xac1f0622, 0x4ac0ad7e, 0xb2e90044, + 0xe640a30e, 0xfca50f5e, 0xecaf5338, 0x1d46d987, 0x5d0e1886, 0xe7df17be, 0xc84bb2ff, 0xcc0cbdf0, + 0x4d018fad, 0xd001d7d0, 0xee1ad347, 0x735f37fd, 0x4095263d, 0xe7d40604, 0x74400c28, 0xbbc3a79d, + 0xf5bece23, 0x7647d81f, 0xfa2863e7, 0xb716f640, 0xff4dba2a, 0xbc3f1e60, 0x400a20c2, 0xddd8cea1, + 0xf9b43f54, 0x46e606e6, 0x4032e6f3, 0x52a6999b, 0x415a6e63, 0x8dbe896f, 0xc1543970, 0xedc55f2a, + 0xb8899cc4, 0x55a3b1e2, 0xf20ec2e5, 0xdb99fd98, 0xc9c5f4e9, 0xfe092ac8, 0xf0d44957, 0x44d71dd6, + 0x37422a22, 0x6338d64c, 0x5f3b9c97, 0x66e132c3, 0x1d90b28b, 0x6f284b44, 0xa3cdaaea, 0x8e3d486c, + 0x152a09dd, 0x11054f62, 0xa67797d8, 0x326c6097, 0x1846bf3b, 0xb50d1a81, 0x28c96df8, 0x5663934a, + 0xbac6ad85, 0x4b59ddc5, 0xfaf3800b, 0x83f5b350, 0xde97e791, 0xf0e5ec14, 0x2a787f20, 0xc2b11db0, + 0xec8efb5c, 0x2bd81d82, 0x41819abc, 0x3a9a480e, 0x9cb57628, 0xeef2e038, 0xb8099471, 0xaf9c8c7d, + 0x4d257a52, 0x3c16a833, 0xe72e2b8f, 0x99889941, 0x51afb244, 0x432c698a, 0x84ce37c8, 0x64d617bf, + 0xd69910c1, 0xf516fcfc, 0xd77c8d4d, 0xb332e49f, 0x2aca0595, 0x81307abc, 0x4dca602f, 0x0f134a60, + 0x67236320, 0x0ad20536, 0x710713ce, 0x246d564e, 0x9b42e612, 0x24baba80, 0x76c3db96, 0x4ff2c36b, + 0x83698028, 0x5fdfc750, 0x271d9e43, 0xb4be2af1, 0xd70c0ee8, 0x12dc7723, 0xdbfcbb35, 0x9649d8eb, + 0x0edb3e8f, 0xc89622e1, 0x5b4ecb8b, 0x8d9d353f, 0x867316fc, 0x11cd8e50, 0x9d5b28c5, 0x28cffc28, + 0xbc928db3, 0x5a87bec4, 0x2372067e, 0xbf236dc6, 0xad05386f, 0x997fffba, 0x1d00313b, 0x427b267f, + 0x14d17bcb, 0x5265aef7, 0x48e446aa, 0x91be3f91, 0xa789a7db, 0x479291d3, 0x4b3096b0, 0xc40958db, + 0x6fe9996c, 0x60b5cecb, 0x32990e75, 0xec567db8, 0x5f4ac186, 0x5efce220, 0xcde0dda4, 0xe8337c62, + 0x542bd567, 0xc725f80a, 0xf1fb43a2, 0x5db2db6b, 0x23844c3c, 0x973d54c4, 0xeb8455c9, 0x57e9c70e, + 0x5f1a598f, 0x4cec432d, 0x7e693d4e, 0x4ae593a4, 0x2fa3becd, 0xb119e8ab, 0x55e7dea8, 0x1c3712b3, + 0x719256c4, 0xb6010608, 0x3b2b8168, 0x59b573ef, 0x8dc41ae7, 0x6789b6a5, 0x661a0cc2, 0xfdbe4b01, + 0x1014daf5, 0x54e7d597, 0xf81bcb90, 0x0924e85d, 0x61e3d24b, 0x99b1126b, 0x0bd27c03, 0x1f0b970a, + 0x23eb5610, 0x0d64f0e1, 0x2ec62cf5, 0x1b1d6642, 0xcaa4c31f, 0xf4e76874, 0xb5864b86, 0x4048444f, + 0xa06e9375, 0x5e412ba4, 0x026044c0, 0x5f3b2749, 0x379bcff4, 0x1c978600, 0x16b3793a, 0x51996903, + 0xd65ab494, 0x44b9f587, 0x92e4f107, 0xdc7b4153, 0x99606419, 0x33dd807b, 0x1abfb4c0, 0x354ce182, + 0xdbf31eba, 0x7e5b81e7, 0x4aef092e, 0xa21db75e, 0x7f2c1b6a, 0xb9f81205, 0xfcac0e11, 0xf5fe1412, + 0x033bda05, 0x97179260, 0xc075927c, 0x0bfff608, 0xbce15d7b, 0xd6b4196c, 0xe7a45656, 0x476dbbcf, + 0x7b325d83, 0x415b93a9, 0x7871abd6, 0x73c94d56, 0xe3a763f4, 0x1d9c4363, 0xd38b290e, 0x465f07ce, + 0x2ab42964, 0x1cbdf123, 0xb4de6a3a, 0xaa4fa078, 0x5842ac99, 0x22fa6274, 0x95466d8d, 0xf404735f, + 0xd09acf1e, 0xc2828008, 0x6aec5329, 0xf54e2e26, 0x6d0dc78c, 0x02634916, 0x26e2b23f, 0xde3f6fe8, + 0x31633ac1, 0xcf5ea33e, 0xae95e79e, 0xed9f90c4, 0x2fd24cbc, 0xe1443e65, 0x02123008, 0x7b73b7d6, + 0xb1dce353, 0x1b042c3e, 0xca093751, 0x792d9952, 0xd93e78b2, 0xeaef01fa, 0xe6bd7596, 0xe99ac480, + 0xcf484d75, 0xcb837c59, 0x3f85829d, 0x3f479083, 0xe781a315, 0x42616581, 0x274848c1, 0x3b2fa9e6, + 0xc2653cd3, 0x5c98a322, 0xdac77818, 0x3cef7b05, 0xb8e91ff2, 0xa54f7ba5, 0xfcd72e7f, 0xfc79dfe8, + 0x8a2277fa, 0x40a5ea25, 0x86a369b2, 0xc588ee8b, 0x3b676252, 0xe32d9d22, 0x4dd72c5a, 0x11edb232, + 0xfbb21f04, 0x10869d0d, 0xf7dd6a64, 0x4dbae428, 0x79fddae0, 0x40987e5f, 0x1d4f252a, 0x852e0199, + 0x4280c18f, 0x2e45ac13, 0x3605b7ac, 0x122b5144, 0x5979ff9c, 0x3f625537, 0xe48bb1df, 0xbbb09b67, + 0xf20ecc4a, 0x5f228f6b, 0x340b3078, 0x7b5de965, 0x3c8c9103, 0xccf4bdc8, 0xb9ad16f1, 0x56cb64e0, + 0x5c20dc7f, 0x2041e77a, 0x35e432fb, 0xea6e45e3, 0x1fbb644c, 0x38be0ce1, 0xa3ff31c2, 0x320e39cb, + 0xf190cac8, 0xb24c288f, 0x4ade6aad, 0xfcb8f5e8, 0x4d8a516b, 0x315f39a8, 0xe7183a61, 0x974ca594, + 0x790e9150, 0x42d50b94, 0x92dd5ae8, 0x22ed01d7, 0xd748ed78, 0x577acae1, 0x0399c142, 0xdae2abbf, + 0x3dd6391f, 0xdc023666, 0x53f93797, 0xd66e340a, 0x08012179, 0x8ad94c99, 0x2e8a1496, 0xe00c10e6, + 0xcbf13d70, 0x0f882973, 0x7b23cd27, 0xe1e50545, 0x7db33fba, 0xc0f480c9, 0x75579608, 0xd8073f1e, + 0xb9739238, 0x4a2af0d5, 0x87c64dc6, 0xed968ad8, 0x4d26ca1e, 0xd5066b72, 0x2839186a, 0xd132f400, + 0x1614e1a8, 0x245cde66, 0x1e34b0ba, 0x6c22019b, 0x5d378b95, 0x3f6c0778, 0x06ec00e2, 0xf517bb44, + 0xcd8affdd, 0x4add1d18, 0x4b11bd5d, 0x68539181, 0xd973d31d, 0xb13b8d29, 0x1ef2645f, 0x0a1ae38d, + 0xf9078fc4, 0x1a7a22cf, 0x78800d3f, 0xeee71ac2, 0xe8649810, 0x65a8c6d9, 0x870a721d, 0xc878aa3d, + 0x65afbfd4, 0xd2f2c5ff, 0x332f6d86, 0x7a248d5b, 0xacfc7b5c, 0x1bf5426c, 0x206b392e, 0x68e2c824, + 0xce631981, 0xca18e339, 0x1e6a9091, 0x5be85b0e, 0x08bb4767, 0x4f938563, 0x2e9d0329, 0x43f13678, + 0xda97c0b6, 0x23bfc2fa, 0xe9386c0c, 0x5d1b770c, 0xc247ed65, 0xfbfc244a, 0x3443b046, 0xe7100eaa, + 0x819b8386, 0x327532d1, 0xdf1fd724, 0x38deb9b3, 0xdf9a8682, 0x192047ee, 0x044e8dc8, 0x845455b5, + 0xbe3e1227, 0x6141d56f, 0xb5aadb03, 0x1b5c570a, 0x1e382acc, 0xe2f93774, 0x02c1598c, 0xfbe6cf02, + 0x84d56b57, 0xd73388fa, 0x2172fe6f, 0x9c1331cc, 0xd280d4fd, 0x5caa77b2, 0xb7236abe, 0xcaaaf21e, + 0x022e33ae, 0xae19bcfc, 0xaa59fc8c, 0x7bea5af4, 0xf2a21113, 0x7783885f, 0x313571f0, 0xa97149a2, + 0xfdfee9bb, 0x89bd32aa, 0xb75ed877, 0xed3aa96d, 0x754e8dd4, 0xa52560a0, 0x81190d6b, 0xce20740c, + 0x684e3228, 0xdeb677eb, 0xbba1070a, 0x45a25ad8, 0x38668914, 0x06e35a6d, 0xdef5546e, 0x794cd630, + 0x748b9423, 0x7c8c6cf3, 0x9c151e9f, 0x1ae826ee, 0x7b8e6cc6, 0xae801fd2, 0x9412619b, 0xf82ca514, + 0x6af46446, 0x99fba95d, 0x8f54a0da, 0xba49faf6, 0x8452a7f6, 0x255f181c, 0x949fe223, 0xf5b6710d, + 0x3aa44bff, 0x97e30392, 0x840e3953, 0xf8631d72, 0x8f0817eb, 0xf3e0f89c, 0x5b257796, 0xc0fefd87, + 0xf2aa8cf9, 0xc6bd9cc7, 0x633014b3, 0xf2f4a781, 0xb7d8b739, 0xe41e3473, 0xf96fc5ed, 0x2010a3c2, + 0xafa78c54, 0xf3091d2b, 0x003745b3, 0x52b323d6, 0x07adb422, 0x17b75019, 0xd5310a75, 0x30776517, + 0x4cf1f6df, 0x524bcba3, 0xbe9cbbc5, 0x8f0c4bee, 0x6d578b52, 0x199addbd, 0x18349e6e, 0xc82ee5df, + 0x1c7b9023, 0x7cf0c727, 0x011e4b22, 0x64209f90, 0x097b09be, 0x8113d1f9, 0x9c85970f, 0xb627453c, + 0xa9a841d9, 0xffae3976, 0x9c14b3f8, 0x65e2138d, 0x39bcd222, 0x3ec4d2dd, 0xb7143f1a, 0xed0ee4cb, + 0xcb275d30, 0xf17482c0, 0x290b3aaa, 0x09ea8acc, 0xc601a81b, 0xec7194bd, 0x594d743b, 0x01c4e173, + 0xf1308808, 0x10d7fda3, 0xa3297592, 0xcd516010, 0x41d7e65c, 0xe581c19b, 0x3837faf6, 0x77670dff, + 0x042419f3, 0xe957dca7, 0x43456f14, 0xedab99f0, 0x5f8692c7, 0x4b9130e2, 0x9b1e0339, 0x60f740ef, + 0x4b2a4896, 0xc167ae21, 0x5071248e, 0x75be35ca, 0xb182a8b6, 0x787cbf5c, 0x381003fb, 0xb07a885a, + 0x06d75ebe, 0x05f88164, 0xa8eae8d8, 0x47ca7aac, 0x4e8c48af, 0x59528b51, 0xa7fed2c3, 0xcb571f31, + 0xf71cfdf7, 0x9b1ba442, 0x5762242f, 0xc0852039, 0x7a957007, 0x0687efaa, 0x08066ae5, 0x04f94c9e, + 0x04cb8426, 0x726a6992, 0xcfed762c, 0x4e4a571b, 0xfea0a2d9, 0x1e9d210c, 0xd8d6da69, 0xd1f1f9ab, + 0x726e2d1d, 0x47bab7e1, 0xf89f1b51, 0xb4b4ff0e, 0xbda26f56, 0x93b3c655, 0x567ad3c9, 0xe3f0f2e2, + 0x88342774, 0xa2295440, 0x3c268886, 0xf295b776, 0x61754400, 0xd083771f, 0xfcc017ac, 0x3a9787b5, + 0x0656e493, 0x0e05dd3a, 0xfcb1d2f2, 0xf2585f99, 0xf50789a8, 0x241b6844, 0x1c40ce29, 0x782461f2, + 0x8e9d48d1, 0x11d47430, 0x49a1f2e7, 0xfdd6ccda, 0x40ecfc32, 0xddc1f7c0, 0xfb7aa4a6, 0xe1e3cdf1, + 0xbd45fadb, 0x27c7b311, 0x52646656, 0x7ead81e4, 0x68cb84e9, 0x8deba87b, 0x6d7260b7, 0x1859a6a5, + 0xc11f0dfc, 0x64fc7bac, 0x120b756f, 0x0e4f3e92, 0x7d56a966, 0xcfb2e02e, 0x42765523, 0xba94d29d, + 0x091723d3, 0xa02cd8d6, 0x42965d88, 0xeae8304b, 0x622989ad, 0x2a2ddcc2, 0x7a16757b, 0x22ec9c39, + 0x80768df5, 0xd449254f, 0xd230e8a5, 0x09f68078, 0xf855b430, 0x09fc873d, 0x7e3837ce, 0x37b68a5f, + 0xa467a557, 0x4f6cbae4, 0x4643de61, 0x361b3dec, 0x9ff3b2a4, 0xeedc36e7, 0xc9353b76, 0x16f78065, + 0xbf81399d, 0x6b7fe464, 0xea4248f1, 0x58eabe95, 0x2f4eacc8, 0x9548a824, 0xdd565ae0, 0x878061be, + 0x66876580, 0x082607a2, 0x655315ce, 0xa0dbc018, 0xa0968794, 0x9b578b8a, 0x95d4fd62, 0xfc3f840d, + 0x5bc233df, 0x34cf9b76, 0x684e42bf, 0xd485b032, 0x8a08425d, 0x8cfc9fa1, 0x2eea6d7f, 0x7fb37865, + 0x3dc38ee4, 0x6cfcf8df, 0x05362a1c, 0x76513c07, 0xe171bed3, 0x6da2df82, 0x8c6338aa, 0x69edae59, + 0x39cc51d8, 0x1a7d9c9a, 0xf0fea558, 0x8882662a, 0xaf1716ce, 0xb9ef7ff9, 0x244b39e0, 0x4f1bcfea, + 0xdcb17a4b, 0x9415baa9, 0x4a3a7aff, 0xafdb520b, 0x6b20f9bc, 0xb83c4c20, 0xaec15451, 0x030bdb9c, + 0xceadbc36, 0x3bd5827a, 0xec745785, 0xf0c59e01, 0xea7ea1d0, 0xe08b92b1, 0x614cd77c, 0x38d5eb3c, + 0x28b10807, 0xf10a741a, 0xf8676500, 0x70a208fb, 0xf7a8e842, 0xac6f5356, 0x22d0b853, 0xa92519a6, + 0xdb0fa1bc, 0xbb5ba40d, 0x1a2024cc, 0xb56742bf, 0x74ab6f16, 0x54a48c22, 0x54d8ca33, 0x6b9c2941, + 0xf3790e57, 0x3f0b1c62, 0xccef4926, 0xd421793f, 0xd750840f, 0x2d3068b4, 0xe7e81f0c, 0xc6a4a28a, + 0x5f33769e, 0x3f48f5d3, 0x8e50ca07, 0xb36fea31, 0x14ee5579, 0x5327ee39, 0xd936975e, 0x099bceea, + 0x3a035f4a, 0xefcdab1a, 0x8f325bea, 0x6174a388, 0xe63fb019, 0x091b40d6, 0x1ac430eb, 0x44ff659e, + 0x1bcf4841, 0x1810f391, 0x3a878efc, 0xdedd18dc, 0x91bd10aa, 0x9338f287, 0xda57ed38, 0x1c4679fc, + 0x0958724b, 0x0c33bec5, 0x7b1b4588, 0x618a83ad, 0xd9135205, 0x965e3856, 0x6e8066b3, 0x7c830fcb, + 0xb781b636, 0x9da01be2, 0xf549f775, 0x2fa61400, 0x9e3f6707, 0x0b54d479, 0x29407e0d, 0x40321a25, + 0xb62b7656, 0x5f367dc4, 0x2cac0629, 0xfbebda1a, 0x677ba76e, 0x78132f2b, 0x962f33c1, 0xef04cbf2, + 0xefa2fa19, 0x7b497bc8, 0x4443c8f4, 0x8b69197b, 0x1b265be7, 0xd7a7a91c, 0xeaeda60d, 0xfbf7226b, + 0x1b7ddaf9, 0xaa81f27b, 0x3c41014b, 0x2995292c, 0x612ad808, 0x9d228955, 0x8e15cc0d, 0x1e7f6006, + 0x05bc77f3, 0x319773e6, 0x67a65d62, 0xb98c80bf, 0x56fc9626, 0xfc232a53, 0xaa6cb957, 0x0f868762, + 0xdc347d56, 0xcb43c23e, 0x2750d914, 0xd5dce242, 0xf548a2f9, 0xbefe7aa8, 0xdc7e70af, 0xa38d5bec, + 0x7c2bc832, 0x965addd0, 0x06df0e1f, 0x97056844, 0x61a8c21e, 0xce1e2fff, 0x276e9c18, 0xc834e3fa, + 0x414c763b, 0x747e348e, 0xe7373bc8, 0x21f0c50f, 0x00730adf, 0x201a0cd9, 0xb7493307, 0x44d62e6d, + 0xef4e8649, 0x73c49670, 0xeebd9317, 0xdbcf9070, 0x286e0898, 0x595e3f69, 0x60192290, 0x943bddd3, + 0x61eee01e, 0x07a5464d, 0x2fcc19e5, 0x7d2363ab, 0xc693df73, 0x3b19d567, 0x18a86c98, 0x7c10a17b, + 0xcd738914, 0x0a2f03c4, 0x560fe58c, 0x03e8faef, 0xa17614cf, 0x639d5abd, 0x04ba11d6, 0x5c44c9c9, + 0x217d9a7b, 0xaa75e679, 0x745d2c59, 0x6dc07391, 0xb6ba6128, 0xe2c826ad, 0x81f00e48, 0xfac729e7, + 0x1d5c34ea, 0x56cbcdd7, 0x5eafa123, 0x1fb1eb65, 0x59b7f851, 0xbad3a248, 0x8c3aa39a, 0x0eb27a64, + 0xdabd1389, 0x04ab5753, 0x0ca23202, 0x003fe5a7, 0x270a27d2, 0x3fbde185, 0x6e300483, 0x8b8b958f, + 0xf679de72, 0xfa50b82c, 0x65d90bcd, 0x859f2e6e, 0xdb52ce76, 0x19a0af27, 0xb719c19f, 0x70b57249, + 0x96709cba, 0x122fa1f0, 0x44f959e6, 0xb9908e86, 0x66fb4b1c, 0x762ade3a, 0x03285ad0, 0xa46f1d21, + 0x2884b78b, 0xa3cebaa5, 0x52b1cd49, 0x7e41d68b, 0x6bcd4f03, 0x613720e0, 0xd56b3c14, 0x958ac50e, + 0x28632df1, 0xfe658ac0, 0xd142e3a0, 0x308c8d95, 0xcb7bf79c, 0xa8400b57, 0xdf3532ec, 0xc70bfb47, + 0x58151919, 0xae35dea2, 0x8d112692, 0x94d586c5, 0xe42795bf, 0x72552a33, 0x09eb9103, 0x4f4adf3b, + 0xfb3f94e8, 0x0d1f20a1, 0xd2366757, 0x1b22f1c4, 0x277f1a5c, 0xc6495fb7, 0x5e73c229, 0x2c34c6eb, + 0xf07a6b58, 0x314065ca, 0xf48dd058, 0x06a6ef3a, 0xa20f71d8, 0x717345bc, 0xae4d78de, 0x93683e99, + 0x90ae3be3, 0xb6d16783, 0x384e7c58, 0x9e027d56, 0xf949c5b6, 0x0b1ab3db, 0x6694bdb3, 0x08d8dee8, + 0x6d912380, 0xcf34fa9b, 0x4a473f83, 0x186e7738, 0x8cf9899b, 0x47a503c3, 0xad855643, 0x385468bb, + 0xf9f09ccd, 0x3a7992d5, 0x19e156d1, 0xba2dd524, 0x5fc8de5c, 0x504aaa4e, 0x241245c2, 0x529d2153, + 0x5fe03ddb, 0x0ac142a6, 0x79e70011, 0x0ae75e99, 0x89bf9f16, 0x5a02248e, 0x14f7333e, 0x59ab4c41, + 0x8bf1d93b, 0x1a9a1563, 0x6ae05821, 0x5e4312cb, 0x0abb6d6d, 0x202924a3, 0x9997af71, 0xf6fd788c, + 0xc52fc655, 0xfa5d50ea, 0x96572dbe, 0x6507f12d, 0x2d9f55c6, 0x33045f87, 0xa6096cac, 0x60efa251, + 0x6ba36c4f, 0x844db93f, 0xbd25af57, 0xdec85824, 0x4d2f1b1a, 0xe9c68bb0, 0x9d0dc02f, 0x6b0a17d5, + 0x57d4c540, 0x6a6820b7, 0x7d748900, 0x8c12247c, 0x6701187f, 0x486a8c08, 0xef0bc6b6, 0x20b618ba, + 0x060a1b90, 0x37a3b4ed, 0x769639d6, 0xabbd2cf9, 0xc8427f95, 0xa8971d5a, 0xd9e6aeda, 0xc63cdc95, + 0x6024168f, 0xd6e7a8ae, 0x9bda09c6, 0xa5910f21, 0xc82578cd, 0x40959076, 0x3d81426e, 0x664b1ecc, + 0xf68ee78d, 0x01b67156, 0xd0589e32, 0xe41b45b4, 0x015ed26d, 0x73aa7c72, 0xf2391c35, 0x798a3d73, + 0xad2478cc, 0xfeab544c, 0x9c9ce1e6, 0x85ca6929, 0x93a15000, 0x17059dc6, 0x82129553, 0x2b9b7b19, + 0x7983fdb1, 0xe32621da, 0x91fcd410, 0x3b1387d8, 0x0a68ab72, 0xbc8b0bd9, 0x5be5b686, 0xb928cb42, + 0x65ef8dd1, 0x02f8a743, 0xfa0878a0, 0xa47f78fe, 0x0829d7d3, 0x1c106464, 0x122c64a8, 0x4893ae19, + 0xeae6cb40, 0x65252e79, 0x1593f510, 0xbd1784f9, 0xe3e586b9, 0xd586a99e, 0x242b352e, 0xb2fcf4cc, + 0x29a409d8, 0xfb30e85f, 0x3335be03, 0x05154b68, 0xe3f974df, 0xc0fb5faa, 0xa4e47b7c, 0xe8a5d75e, + 0xfe8ce905, 0xe8a19888, 0xe75c3442, 0x4660b5f8, 0xc3b117ff, 0x45bbe786, 0x2e6bbdce, 0x6251ff1e, + 0x8432ac23, 0x77a8050d, 0x12346b53, 0x19d2725e, 0xb1c9df56, 0x0155b7ef, 0x026ab1e3, 0xc5e09f85, + 0x4ed856bd, 0xee1d0e2e, 0xbd3a3fd2, 0x1749a51d, 0xcd3d0f89, 0x26f7ccaf, 0xf31f7cda, 0xc1a1234e, + 0x36a21b42, 0x1dfc591e, 0xd7be7f7c, 0x1d65d85d, 0x9b6ff76c, 0xaa2c89bb, 0xf8ef37fc, 0x4d29a385, + 0x1a8b791e, 0xf3f5bd74, 0x32edfe93, 0xe44dbec9, 0xbdd97770, 0xe1eb53a5, 0xe5bcf6c3, 0x46520ce2, + 0x2bd157e2, 0x57be0a16, 0x62c4e427, 0xc4a835b4, 0xfc4d4c0c, 0x3418f6c0, 0xc3c0f1ee, 0x62f15798, + 0x19cb0162, 0xd27905d6, 0x709f905a, 0x14188bda, 0x2d66f57a, 0xa9fdbbb1, 0xfc6e0717, 0xd68b1aaa, + 0x504b722c, 0x724fbf32, 0xb1d11ab9, 0x01b7d9fe, 0x12a3239a, 0x4592252b, 0xc0e0fc97, 0x92cec37c, + 0x1c8f0382, 0xebc0aa15, 0x762e709a, 0xd8553026, 0x55240b21, 0x34cdc530, 0x61682f2c, 0xdeaa8513, + 0x5c9116a2, 0xd921aeb2, 0xe4e033f7, 0x0507172b, 0xeb0f45bd, 0x48215bc4, 0x14f1b69c, 0x129f2987, + 0xe5e1fdb0, 0x217b572f, 0xadf1b754, 0xa7d7f172, 0xb6b61870, 0x9d499ea1, 0x76a8c397, 0xd996eb75, + 0x03b5c5e9, 0xd6908c48, 0x19667910, 0xb522349e, 0xc107424f, 0xfced3d8c, 0x0553a873, 0x16b6d4d1, + 0x782259b4, 0xd948338c, 0x7c37c591, 0x5bf780d1, 0x1a9cfea1, 0x425adb87, 0x96efe12d, 0xa1bf7727, + 0x4f751bdf, 0x03f8b0ac, 0x8ee4411c, 0xae3a2e88, 0x61906394, 0x945d03e4, 0x09bdfa19, 0x457d64c0, + 0x954799bd, 0x099c9e40, 0xe17b5e66, 0x7f4cb576, 0x2817c508, 0x69a818c9, 0x147e0af6, 0xa36cf410, + 0xbba126f1, 0x213394f3, 0x244d986e, 0xbf16b253, 0xa3341058, 0xd9c6dd51, 0x62b69dd4, 0x664f3179, + 0x106365da, 0x7db66843, 0xd203211b, 0x6f317d5a, 0x09beb8ab, 0x2317c10f, 0xa4f5307f, 0xa8d64f93, + 0x52792c78, 0x9db21693, 0x579e0b92, 0x64d60810, 0x75246342, 0xd2437dd2, 0xd248e202, 0x7d7de47c, + 0x7e5bb0b1, 0x88fbc785, 0xd045b22e, 0x7ab9e753, 0x3702a46b, 0xfcc6ef6b, 0x857fb2f6, 0xa94715c9, + 0x288151b4, 0xd0cce7f0, 0xb1c23725, 0x06644398, 0xf6d8faf8, 0xec100299, 0xd712915f, 0x0a984ff4, + 0x7e2ef921, 0x77df8f6a, 0xd1355846, 0xc28499d4, 0x1963e97a, 0x30383982, 0xdc001e73, 0x308e5838, + 0x2eda2ffc, 0x0784f682, 0xf5311630, 0xf83ecae7, 0xd9841283, 0xa21ba190, 0x522be43d, 0xdf1f7115, + 0x5a05e88f, 0x21a89e56, 0xf863e91d, 0x3ee4952e, 0x0816b0bb, 0x663a7900, 0xa8ba0067, 0x37e34f79, + 0x6feff6f7, 0x0a1058c7, 0x65d32f98, 0x98a1543d, 0xe783eba3, 0xec4a4a73, 0x3a4592ed, 0xa65d3470, + 0xef695580, 0x69c12813, 0xadfdb2b4, 0x7588d0b6, 0x27f34f85, 0xcd6c6eb0, 0x7734992a, 0x1de7a3f5, + 0xad5e5294, 0xf255a4db, 0x0f51d6fd, 0xaca70dfb, 0x06bd8ec2, 0xf5822175, 0x8b16f30e, 0xb009e586, + 0x9147edb9, 0xd7f8a6ea, 0xbdfcd164, 0x782ca797, 0x285fa2b1, 0xdaa231ef, 0xa5cf9fa6, 0x5469cb0f, + 0xbd3b2638, 0xf7c7309b, 0x7b357376, 0x664534d2, 0xdd912929, 0x5517d241, 0x1fcef00f, 0x3eafab0b, + 0x0bf1e05b, 0xd31a8c31, 0xe5bf9275, 0x35f2b925, 0xbba9779c, 0x0589eb46, 0x4457f945, 0xb36fae46, + 0x056f7bc4, 0xe39ad8c0, 0x5667a1c4, 0xa980b2bc, 0x4b170c42, 0xe7051b9c, 0x1077d3fc, 0x7db9e079, + 0x9bd09127, 0xb50aa8f8, 0x9a2f7124, 0xe72c9d62, 0x61766045, 0xaedd583d, 0x37168aaa, 0xc67df3be, + 0x5ce96f27, 0x256877d6, 0x2a254659, 0xe3c328d8, 0xd81f9120, 0xab0dfa2a, 0x4e4e87e1, 0xc32d6dbf, + 0x0b1c9c16, 0x3bd96013, 0xac4e194e, 0x9222a272, 0x47a1c4f9, 0x4da7e421, 0x9656a7fd, 0xfd58727c, + 0x662912c9, 0x27f871ef, 0xcb5dc510, 0x123a4375, 0x9645d0c7, 0x6f83ad7f, 0x412d97a8, 0x989b6d18, + 0x3701b23e, 0x5df50219, 0x94ff2cdb, 0x2ee81721, 0x2431a0c7, 0xa20ea1f1, 0xc7710ec6, 0x1325411d, + 0x67140001, 0x6136da2f, 0xcbe9fda9, 0x05363570, 0x8b1a97b6, 0x18652eb4, 0x1702b23b, 0x3bec7437, + 0xc6cc0fdf, 0x47d1900a, 0xbb329fe5, 0xad3e48a9, 0x97488a19, 0x3760259b, 0x108d28be, 0x926302be, + 0x65f6cdfc, 0x57836fe3, 0x413b3352, 0xde7bdf3c, 0xe2b88b85, 0x2e0e81bf, 0xdc71e839, 0x27f36bc7, + 0xbb8c0d13, 0xc71bfdfa, 0x28576c5e, 0x3b7d0421, 0xbe720c40, 0x3a8ae80e, 0xa9449399, 0xc2bede14, + 0xf9ab563b, 0xcb12d15f, 0xd74647b1, 0x7ad191d0, 0x33cbac57, 0x31e1d00e, 0x5cfe1d73, 0x8af2bed6, + 0xd8e6f2e2, 0x546e1fc1, 0xcf39c456, 0x14eb302c, 0xda1e9d33, 0x3be8d948, 0xf8f13a3b, 0x9f2ce865, + 0x404d08d9, 0xd4a8bb5e, 0xd4bbe49b, 0x677b1205, 0x7e4e1c30, 0x7ffc9ae8, 0x63d12cd2, 0x01c12b0a, + 0x084f8fe4, 0xf89d77cc, 0x00beec32, 0xe5817a77, 0x2b3f06ab, 0xec570143, 0x0a4034b3, 0x88d0e9f2, + 0xbaa75c74, 0xb23b2e30, 0xf460b4ad, 0xb6b89072, 0xf2958007, 0xb26f0bd7, 0xb2aa1f79, 0x4c463ee4, + 0x8bc7d54e, 0xe7cd18e3, 0xceec8656, 0xc7f90256, 0x94afd5de, 0x3619acc2, 0x033efd9d, 0xb4fc7ad9, + 0x0f39af72, 0x313fafb1, 0x8f934029, 0x17af91b5, 0x6474f783, 0xafd8db1a, 0x352fcc52, 0xfa28bbaa, + 0x4945c446, 0xc0a254a4, 0x0c2c8c9a, 0x53c156b1, 0xf5c34d5d, 0xabbb18ee, 0x6d480b10, 0x9a37aae3, + 0x27ed751c, 0xeefd03f9, 0xa96902ac, 0x709ca7a4, 0xfcba4e31, 0xfa6a75bb, 0xf1e50d0e, 0x5212a13f, + 0x7700343c, 0x28a433c3, 0x721551b7, 0x595faeb6, 0xf21d94f8, 0x1cf822f8, 0xe48fb923, 0x2487842d, + 0x5b431424, 0xe04c0ea8, 0xeb8e2b95, 0xfd1c3c2d, 0xcc126126, 0xf3d8d3b5, 0xb06a52b2, 0x952daaac, + 0x834c4ede, 0x06daa003, 0x9ce70d50, 0x65478ae8, 0xbeb2e1ab, 0x53f33aa5, 0x42abc9fe, 0x79ea0c6c, + 0x3f1fc17f, 0x9ed14fcf, 0x00d31dac, 0x61cce611, 0x5670a185, 0xbeea65b8, 0x2c91a879, 0x0339c002, + 0x02e0635f, 0xbd9a314a, 0x110a7d35, 0x6f70db04, 0x158f9cf8, 0xf2224aff, 0x5b4b4005, 0x7e8ace2f, + 0xd9f58170, 0x96c6aafc, 0xe7343889, 0xa630ab47, 0xd549dd05, 0x929249aa, 0xfc49284e, 0xa2eaac16, + 0x28d7f7c5, 0xb1e467a5, 0xefc4eaef, 0x69072fe0, 0xac9cc560, 0x0434d3d1, 0x22cbbe42, 0x5611747c, + 0x4b6072f4, 0x15e28be3, 0x002d6e2b, 0xf450dfc3, 0xc01285a4, 0x1227a376, 0xed11aa11, 0xecfbb3b1, + 0x39779e77, 0xcd405966, 0x1049b512, 0x960719aa, 0x07550424, 0x7fa8b412, 0x72ca89e7, 0x7f7a168f, + 0xdce7aa69, 0xfeb9ff89, 0x6cd41789, 0x9a647531, 0x16141667, 0x7256685f, 0x9e0f4dcc, 0xeffd0b40, + 0x27b96685, 0x186bbe12, 0x44041257, 0x9a8af319, 0xb6937270, 0x67565b6a, 0xf0f6b8f4, 0x93246672, + 0x51a8434a, 0x1ee7aa39, 0xb6e1a03e, 0x45647dfd, 0x4338fb32, 0x0224acb1, 0xd48f75e3, 0x6c73fbd1, + 0xb602c18a, 0x2beb8ab9, 0xa29a4630, 0xc6fff2d1, 0xde5b694a, 0x9af1042a, 0xcb551d7e, 0x9e57e73d, + 0x92e6cbd1, 0xf3bb1206, 0x68e772ef, 0xce74c1b7, 0x5b91b521, 0xaca09b58, 0x85c8e3d7, 0x5bd42d31, + 0x11b548b8, 0x2beb047e, 0xace5154b, 0x94ed9b43, 0x01de0b69, 0x60d0ed38, 0x4276243b, 0xaeeef789, + 0x3a4ae0df, 0x28abb21f, 0xb4b8852e, 0xad9d8399, 0x09a99c86, 0x15fc25fa, 0x72b7e930, 0xde0e9fc9, + 0x456f8de5, 0x3d6747f3, 0xa5c1dc6a, 0xe8fa648b, 0x05a8cdd7, 0xe7609dcd, 0x6e4f08fe, 0xc35416ff, + 0xbe564551, 0xe737a5bd, 0xfd3ea611, 0x10b43979, 0x9277af31, 0x95e22141, 0x3e1d130b, 0xcc09ba69, + 0x80e01cfd, 0xe716d823, 0x210698c0, 0xf130583d, 0xa9eb3440, 0x575f0fe3, 0xdf30b590, 0x66fefdae, + 0xe3915dd7, 0xecddba13, 0x1b0894e9, 0x8f02b9a8, 0x26ac6679, 0xb1023cb0, 0xa18211e4, 0xcd19f7c7, + 0xc367c589, 0x817bd780, 0x85a1a9f4, 0x22fab79a, 0x71baa0a2, 0xa2b0e7d0, 0xe3a75e35, 0xbed7dc1c, + 0xd9251607, 0x3f2e74ff, 0x2d083658, 0x7cc7bbef, 0xa9e9a6d2, 0x503b0bad, 0xb21a1290, 0xa4e3eecd, + 0x92642bd2, 0xce2161da, 0xb010a8fa, 0x8a123723, 0x0fb7676b, 0x07b55315, 0xc41d5674, 0x8fa1e8f5, + 0x79625e3c, 0x299ab31b, 0xcf5fea59, 0x76048b10, 0xd9b57344, 0x9acd7c07, 0x75085269, 0xc5420d84, + 0x967e26a9, 0x76586948, 0xacfa9db9, 0x8c99cb21, 0x774b5503, 0xca5ea613, 0xf9e51400, 0x84d9e052, + 0xa7e4590b, 0x031019c3, 0xcfe6d01e, 0x7cc64b67, 0xff89439d, 0x9c273987, 0xd24b3a41, 0x22ce88d1, + 0xd1941d6f, 0x14e016cc, 0xda0f17d0, 0x3c85608b, 0xcd9436b1, 0xe597bd5f, 0x3a4d9779, 0x1ad78334, + 0xb4094d57, 0xca258081, 0x6c23631b, 0xf71fa764, 0xb8bb2084, 0xd2b87698, 0x3ad18e92, 0x36b822b2, + 0x36ec9b21, 0x613f6b1c, 0x2d1c09bc, 0x3742d2b3, 0x35c7866b, 0xa048aa99, 0x2fe669f5, 0x40985750, + 0xf469beb8, 0xd191ba40, 0x98227c99, 0x3e82f9d9, 0x01c3c8e0, 0x7acb9b75, 0x5d2a5b37, 0xa5239c19, + 0x47646769, 0x23b698a9, 0x72c02f52, 0x329afd16, 0x127c628f, 0xbb81d22a, 0xdb887fc4, 0xa7857e0a, + 0x4a0804c9, 0xdf1501a0, 0xb7ba7b74, 0xa78f901c, 0x0c062776, 0xa0bfb454, 0xbe5a2f8c, 0x88a042de, + 0xb624bb4c, 0x359ca39a, 0xb68d3842, 0x3c99132f, 0x044d0f47, 0xddce89bb, 0x058f9ba6, 0x7db5be07, + 0x6eea3256, 0x7eb02a12, 0x9aa21425, 0x44c558cd, 0x910c3f4f, 0xcdf555bf, 0x3db7e1c5, 0x78834b24, + 0xfd4945e3, 0x05c4df9e, 0xf07bece6, 0x4e0419d0, 0xcfc9a9e5, 0xae37feae, 0x92b3bba1, 0x3f539fcb, + 0xc06126cf, 0xbf05aa08, 0x46488d54, 0x48f6d4f1, 0x307b887b, 0xe97a8663, 0x9111aedc, 0x67a3cf72, + 0x9f35d4c2, 0x1961ce3d, 0xefa53463, 0xfdb2f1ec, 0x394909c3, 0x287c337b, 0xfd21155b, 0xd00aa09b, + 0x0307c0a1, 0x2cbf7f7a, 0x84bdc347, 0x3789e08a, 0xa281d40e, 0xc8a65fcd, 0xf475e4ca, 0x722648ee, + 0x6a80cc73, 0xd4ca9a89, 0x5e9aa476, 0x5e3fc5f3, 0xdaefaa4a, 0x173b15b9, 0x68ed777d, 0x72911fc0, + 0x63991be6, 0x36b27a7d, 0x625a6066, 0xf37372c1, 0x0b650738, 0x4ab7a16d, 0xd9c7be46, 0x966ca10a, + 0x15c2259f, 0x147aacc5, 0xf82a93c2, 0x031077da, 0xa2d4db4e, 0xc9f2c9e8, 0x5b13b2d0, 0x5681a461, + 0x4a45defe, 0x958f1fc3, 0xee44b4d2, 0x57b8d9a5, 0x5d742eaa, 0xb5fcf6c9, 0x475db17b, 0xda8397f8, + 0x81c948fd, 0xc58de3fd, 0x7ed9e762, 0xb4d0eb69, 0x495758ff, 0x29898948, 0xbd8ab1be, 0x2090740b, + 0xca885e65, 0x12ed8b92, 0x2ffb15f7, 0x4fffea45, 0x39aeb2d7, 0x3e833ffd, 0x50807a6b, 0xca63734e, + 0x34825cb4, 0xbac29078, 0xef914868, 0xee5f9846, 0x773a76fd, 0xa636c3c5, 0x0597d3f6, 0x4346cd00, + 0x62e4b92b, 0x770eee3c, 0x3bbda2e7, 0xec7055dc, 0x8785513a, 0x65c12588, 0xd04db1ae, 0x53cc9f3d, + 0xb7d9b64e, 0x50294a2d, 0xb582444c, 0x3112003d, 0x0347de32, 0x02344e49, 0x59910bdb, 0xa45d34c6, + 0xe5ea8f8a, 0x1f6c474a, 0xecc5b368, 0xb6a8cdf3, 0x9c46d662, 0x8faa991b, 0x8ccee01b, 0x5c390840, + 0xdb864de6, 0x723ad222, 0x678632b7, 0x89271bbd, 0x344bbee5, 0x57949ace, 0xe0b88cc0, 0xd9c2fda1, + 0x6337b0e6, 0xf6d7216d, 0x89f3f79f, 0xa691c680, 0xdcc25ee6, 0x4a5c90e0, 0x83beb5d0, 0x78cf55d7, + 0x83720629, 0xd77e37de, 0x768016c6, 0xc09d9f22, 0x37c00d58, 0x155f7d09, 0x3ea4b4b9, 0x4a7336e7, + 0x0a39c9cc, 0x874c79b9, 0x34601fc2, 0xc268aadf, 0x76818480, 0x9023657c, 0xf1895ca5, 0x99f5271e, + 0xa1a3ebae, 0xb9a40259, 0xa53ce366, 0xe98df2a3, 0x545b10c5, 0x884efc77, 0x49eaf0f0, 0xc9da3909, + 0xb00a0550, 0x98b74f75, 0x319c6978, 0x9115b60a, 0x8a9b1860, 0x0c55b909, 0xdfc21811, 0xc7839f26, + 0xa582a0d1, 0x230acbbf, 0x880a81f3, 0x8026f6d4, 0xe947680e, 0xe03ca35a, 0x5e85c5ce, 0x3f79fe84, + 0x9e469076, 0xa189eace, 0x8f34f43c, 0xd073ede4, 0x5a8129d7, 0x6635605a, 0xeecf5d7e, 0xc3cdf4f4, + 0x5382d6c6, 0x955f4384, 0x909d1226, 0x2889b818, 0x689999e6, 0xb4f74ed3, 0xc5f73f65, 0xb741a34c, + 0xccfee88b, 0x21cb4c3d, 0xf78d6cef, 0xdb54af48, 0x2131abe5, 0x24587274, 0x3d7852e1, 0xf4834909, + 0x0248b65a, 0x6db1e4b1, 0x7b2aecbd, 0x6b8631a6, 0x439bf31a, 0x2efc28e8, 0xc66ba2a6, 0x21e119c5, + 0x06ebe2f5, 0xfb1b61fb, 0x79d6c137, 0x0f6c7fe0, 0x0438502d, 0x7c2903ae, 0xd97e0ac5, 0x9c4a8b14, + 0xc8f462a7, 0x6e501cfe, 0x9abb00f8, 0xd7c83493, 0xf4b6c87d, 0x10741462, 0xc0156eea, 0x2cf75312, + 0xb81d02a4, 0xa6269b68, 0xe856d07a, 0xcfdf3677, 0x2210d658, 0xa21c1077, 0x723f3ecd, 0x110c5296, + 0x4fcf8e26, 0x7e6caa44, 0x4c9e5c8b, 0x1b117f63, 0xfd537940, 0xff1b85c3, 0xd7004a95, 0x457fdcd5, + 0x1239f574, 0xa34a0ba8, 0xf8c84ffd, 0x8bae07eb, 0x2b3ad25e, 0xa523888b, 0xdb9ca16f, 0xa44faafd, + 0x9acc464a, 0xee90f26b, 0x187772ec, 0x6dd07e88, 0x877a82fc, 0xd27e39f7, 0xbf581a4f, 0xe6fd1a07, + 0x603234d8, 0xb43d84c1, 0x9523d6ad, 0x783cfcc2, 0xb9234947, 0x93fd9ea8, 0x4493daf2, 0xa8425afb, + 0x49c32cbe, 0xa970affa, 0xc008fdbe, 0x52d70bc2, 0x03f5487e, 0x30e73b58, 0x5849c716, 0xccfb1626, + 0x45215577, 0xbbf797b7, 0xc637d8fa, 0x887cfcea, 0xe26f556a, 0x2c1a692d, 0xcc21c1fc, 0x3acfa351, + 0xffd3ede4, 0xf83c40cf, 0xb259a346, 0x2321676b, 0x979da827, 0xb851f5c4, 0xa69f1558, 0x92e6c3c3, + 0x8197f9df, 0x95c195d2, 0xc2bc35fe, 0x17fe3002, 0x1d61eca9, 0x0aefb23d, 0xb96f47aa, 0x0f80b54c, + 0xef1956b0, 0xf30b7895, 0xdb431d14, 0xdbe9793e, 0x987f7c57, 0x3338d1d8, 0x4f591c38, 0x138f44e0, + 0xf15578a8, 0x82a0e566, 0xb68561d3, 0x40eae92c, 0x6be5f25a, 0x772b011d, 0x5b4810cc, 0xd6cab3de, + 0x1fd820d5, 0x77bc3ffd, 0x43985400, 0x4ba0c111, 0x74ae69c8, 0x9cb430e7, 0x8178f77d, 0xf0fcbe35, + 0x853e8ca1, 0xe2fa913c, 0xdf3d077b, 0xb9529b08, 0x613f4b9d, 0x548f17db, 0xe2be16ab, 0xa866cbd6, + 0x308388a6, 0xfe0a268f, 0x98eddde4, 0x14300ab2, 0x6c3b63fc, 0x5bd5e122, 0x4a6c960a, 0x0ee0a594, + 0xaa2888a9, 0x4ec47b38, 0xfdde4bff, 0xaecd1728, 0xc14bb2e5, 0x0ff56310, 0x43a32cd3, 0x8d682b5e, + 0xbae2eb0e, 0x95fc8a6e, 0xa514b686, 0xbaee04ed, 0x972609c7, 0x0475da36, 0x88ee845e, 0xc828925a, + 0xd997225e, 0x91b5554a, 0x2d37ab16, 0x26feba74, 0x74085720, 0x051db2d1, 0x2715b752, 0x6ead9b30, + 0x6108e6c3, 0x5106a1ad, 0x72b6e96b, 0x1bec7581, 0x324576b4, 0x13ff1908, 0xd83fe8c0, 0xd7f09ad3, + 0x80bbbc8d, 0xabfd7849, 0x63a43a13, 0x0d7a762e, 0xcc3d3999, 0xb3915681, 0x99fbb48f, 0x7f5dd695, + 0x98d24bb6, 0x44163e79, 0x5d9c331f, 0x0ada1b6b, 0x3cbd9ccc, 0xfb447eec, 0xeb9a0212, 0x9c74845d, + 0x420369d4, 0x82bfef0d, 0x946c64c3, 0x7451df5e, 0xba9b47bf, 0xf8024e26, 0xa0e5c4d3, 0xb0ee0083, + 0x36336abc, 0x973903a8, 0x8af8cc1c, 0x20c68d21, 0x00fe787a, 0xd57bdbe4, 0x630d5989, 0xae10b302, + 0x7ed799f9, 0xd320a4fd, 0x69ca28ee, 0xdba924e8, 0x3e6be82f, 0x0d3fa4c5, 0xff1a599a, 0x4fa7ada1, + 0x474ca31b, 0xdd16d1bc, 0xfcfabc8c, 0xb069c88a, 0xf586d619, 0x1dd464e1, 0x2cc0aee1, 0xecd389a8, + 0x25640200, 0x63179043, 0xd0e93dfc, 0xf1da013b, 0x526a29fe, 0x54e085c7, 0x2a7b2811, 0x47cf7e4b, + 0x8eb05bec, 0xee2b221b, 0xbbb608ce, 0x58a12a27, 0xf76d8a9b, 0xace565de, 0x04176181, 0x93a4aa57, + 0xfadf1641, 0xcffbbab4, 0x57cd10d6, 0x6705f096, 0x64632bdd, 0xc51fba37, 0x9c84683a, 0x6fd58739, + 0x86eef770, 0x54529675, 0xf5042a23, 0x01f04bea, 0x5aeee457, 0x134b8aaf, 0x3557c338, 0x67a482a6, + 0xf2fd2072, 0x0388736c, 0x29134224, 0xbf1cc09a, 0x40487df0, 0xaff89fc4, 0xa19478fe, 0xce87f6dc, + 0xa843afef, 0x44f0eed0, 0x261e9c95, 0xde60a592, 0xa437ebfd, 0x9f0a801e, 0x5624ce09, 0x9888c8ab, + 0x0b64e60f, 0x055197c0, 0x54fb3be5, 0x0daa35fb, 0xab24b373, 0x87204df8, 0xd9dd16e5, 0xc7446336, + 0x7b201890, 0x1cbf0037, 0x7d7d78b3, 0x7ef34c92, 0x0d2356c8, 0x1354c42d, 0x00fd61a2, 0xb256dc92, + 0x97a9b5cf, 0x6bb38e97, 0x4ceb08a9, 0x695da29d, 0x5e2f9303, 0x5f0d3395, 0x3ee13c66, 0x85e3bb2c, + 0xf91cfef7, 0x0f978367, 0xca5d2bb0, 0xf2d46e32, 0x547c7bff, 0x362c7a3b, 0x18aabe05, 0x6b1ecbe6, + 0x0f66b41c, 0x6c0e1f27, 0x83fb0839, 0x32d8e894, 0xe71aa7de, 0x618cfd3f, 0x4011dbb1, 0x7cf8a470, + 0x6f8be506, 0x3f30bc76, 0x172b221d, 0x3708dba5, 0x8d8dfb33, 0x9b03daf6, 0xcb15dafc, 0xbdae7f1a, + 0x526ac474, 0x8f4ca0d5, 0x74ec5a2e, 0xb4d487d6, 0xe85d9b44, 0x549442ad, 0xdbf38aa9, 0x0788d9e9, + 0x47438a74, 0x2eea704e, 0x38617893, 0x77331e99, 0xfcc2db8b, 0xfd067c83, 0x3662799f, 0xe4e95ea2, + 0xd75baae8, 0xaddbd1f1, 0xe408f9c2, 0xe26d66d0, 0x37ebb4fb, 0xc13041cb, 0x4d58f4cc, 0xf728794d, + 0xc07a4fe8, 0xd5454c64, 0x8b80a6c8, 0xd8965f7d, 0xa71208c5, 0xa4785314, 0x892931e6, 0x445f1787, + 0xaf2a31a4, 0xb4494760, 0xb9e90784, 0xad2f7e31, 0x881402b6, 0xbf057317, 0xdb209daa, 0xb3ad6013, + 0xe5ace234, 0x1d5f2cbe, 0x155cd1ec, 0x39ef6039, 0xe745510d, 0x792e6512, 0x507d0ca7, 0xd03e9912, + 0x1acc1dba, 0xde7cbb04, 0x6385c788, 0xf5d5ab2a, 0x789449c7, 0xa64722ec, 0x08a7acd2, 0xb009a976, + 0x22d46476, 0xc3c430a9, 0xddb594dd, 0x99e147b9, 0x163c2503, 0x36480254, 0x1dfa687c, 0x09470c27, + 0x8178f05f, 0x81480a95, 0x79df7989, 0x3fbafc16, 0xe8b79c94, 0x86c5fbb3, 0x548cc28b, 0x00d89c2a, + 0xc24f179a, 0x460f085d, 0x276fa159, 0xfec9a1c5, 0x7f162e31, 0x3a5c98f9, 0xabb54289, 0x1f78996d, + 0x7a71a0cd, 0xb36b23b8, 0x867c5050, 0xbe96f0ee, 0xacfb0444, 0xff18c393, 0xaad5ea24, 0xc5f14138, + 0xeacb45f3, 0xc30cabec, 0x53438ae5, 0x9298256d, 0x7b2d6e93, 0x9f65cbc5, 0xef55e357, 0xdc281f69, + 0x5e93f0c5, 0xd15ac418, 0x90fde915, 0xd136a75b, 0x0ba954da, 0x3e400516, 0xe86a1bb3, 0xbe8ddffe, + 0x94b88577, 0x0709f204, 0x29ae190a, 0x4d273397, 0x9cc560b9, 0xc7b3b651, 0x0f492096, 0xd5b29378, + 0x57084da3, 0x1b948a99, 0x72a40145, 0x77871c52, 0xe4595934, 0x81ea6788, 0x0e934d0d, 0xa80faed7, + 0xd07c57bc, 0x46eef915, 0x7291f677, 0x64ffa5f5, 0x2e954df8, 0x2c4a353d, 0x32601cf5, 0xe9833ccc, + 0xf9dceae2, 0x5e192b7d, 0xf0aa2558, 0x0204fc3a, 0x561d0150, 0xfdc72ccd, 0x02b9f1e6, 0x79db25c3, + 0x5f0b169c, 0x25bd25ce, 0x5756a80b, 0x2f2e300c, 0x1b44ea6b, 0x1312739f, 0x516b4270, 0x45b85a9d, + 0x61b8693e, 0xfb326500, 0x865aa3d0, 0xd3d65b55, 0x29e89d82, 0x7382944c, 0xb3e22dbf, 0xfed565e6, + 0x8abfe2d5, 0x2d9578d4, 0x26acd995, 0x3c9a2165, 0x14b8919f, 0xa21e00e4, 0x30b158de, 0x9e1997a4, + 0xad880db0, 0x27546b6e, 0x309fa023, 0x1a92b485, 0xe92f88a5, 0x8f2fe62f, 0xa655f215, 0x686c75d4, + 0x1de09a2d, 0x9ed817e8, 0x0f771025, 0xd460358a, 0x10a63f59, 0x3469b388, 0x9e6a739b, 0x28b70808, + 0x61b5c009, 0x31379225, 0xfd007077, 0xcd3b3987, 0xc878eab4, 0x25695926, 0xf9f02c77, 0x9e94e047, + 0x2797e520, 0xad485786, 0xa5d2e6ed, 0x2cbc5e40, 0x1abc9ccc, 0x15df8fb9, 0x54cd0502, 0x2116f803, + 0xa586c46b, 0x25dddda7, 0x91a81ca3, 0xf0829cec, 0x89508f36, 0x8107703f, 0xdacb55f9, 0xa0ff9bc1, + 0x05d3b708, 0xb0d96606, 0x48b26332, 0x2ee5ec79, 0x509905d9, 0x79b7d104, 0x6f377f40, 0xd98f5a37, + 0xae8874a4, 0x8ff62541, 0xdd5dd264, 0x511cdd31, 0xa30932cd, 0x65bc00b7, 0x7d24d2f4, 0xb9a209c4, + 0x8d1996c3, 0x01b97e4b, 0x17135203, 0x9dd95e74, 0xf711607a, 0xc498f776, 0x3e5ff7b4, 0x300dec22, + 0x4cbe364f, 0x3e59f2d2, 0xc737a51f, 0x94406aa4, 0xebdfca76, 0x2434c250, 0xc9fd0d99, 0x6ab5964f, + 0x29a5944c, 0xebdf09d5, 0x89318cf5, 0x44c7bcb6, 0xbf0c57a9, 0x80439356, 0xcda496a6, 0x3a447f2d, + 0xa472650d, 0xd761ec19, 0xd0d8dc22, 0xa0a4281a, 0x65917c87, 0x8b48a106, 0x78ff6351, 0x96f74f1e, + 0x2d10946a, 0xdf7fcbd0, 0x400eb82a, 0x2cd322d3, 0x85cbd041, 0xa36555d4, 0xc74fff60, 0x4be0b36e, + 0xf417cbea, 0x7feab4e0, 0x749ab172, 0x91850905, 0xae23de74, 0xea6d19cb, 0xe84c3aa5, 0xd97004cb, + 0xb32b4cdf, 0x5a1c52d4, 0x7c2face5, 0x9a4f38d4, 0x8e8accfd, 0x1361664f, 0xe990ed87, 0xf1a7aa41, + 0x4ac25eb4, 0x7dd97bb6, 0xf73546f5, 0x70548007, 0xfe629a82, 0xc5fdec86, 0x2f62fbd5, 0x55a14593, + 0x31d7e1cf, 0x74d34b8e, 0xc1a1224d, 0xcedace8a, 0x6dbe6a71, 0x69368479, 0x1e37efff, 0xd0068f3d, + 0x7a06a723, 0x6d6ef049, 0x61bb3de0, 0xb54dad34, 0xfc264838, 0xe2488c33, 0x48191239, 0xcd61fdd9, + 0xa1683679, 0xd848e2fe, 0x912ce661, 0x6048fd25, 0x223f0caa, 0xda383214, 0xa0934f94, 0xd7ee3213, + 0x1485b95f, 0x855bc806, 0x5d0f7500, 0x47ec3346, 0x9a4f7af6, 0x7a7afb51, 0x3357757d, 0x47437d52, + 0x5fb42e10, 0x096f225b, 0x13758d10, 0x7759b388, 0xc4ef4642, 0x3d0578e5, 0xcba99dec, 0xf7a32cb2, + 0x04540bb4, 0x9bc44a0a, 0xfbbbb4dd, 0x93dc341b, 0xeeecd878, 0xa69baab6, 0x48027c87, 0xf00846c0, + 0x857f5ba1, 0x615afb4e, 0xb4345061, 0xedbec1fa, 0x31190f07, 0x322ca977, 0x482c4c60, 0xaa9e7148, + 0xe2739f3b, 0xc8e8a74f, 0xa2f12289, 0x86644e3a, 0xc21b9c96, 0x0d6c32f7, 0xd4b21224, 0x8edfe846, + 0x69d1314d, 0xeea80fdd, 0xaf29bc21, 0xac09a9df, 0x5ab18807, 0x3c55458e, 0x03059cd4, 0x3d636d20, + 0x4fb60533, 0x1a603cc2, 0x456ba930, 0x2881c667, 0xa385fae1, 0x958748e1, 0xa8735265, 0xc49aa4fa, + 0x811dfbc8, 0xe16634ef, 0xff89ad0b, 0x9762f47f, 0xb8d21b0e, 0xff0728b1, 0x02ca9304, 0xb668f158, + 0x72ff61f3, 0x8b69fe7e, 0xe501fc64, 0x1e1fac80, 0xf1fd6a28, 0x118d16c6, 0x9a4d09da, 0xaf27d456, + 0xd3bc7dff, 0x7ca959a7, 0x8f69a832, 0x57064858, 0x2c20571b, 0x12cf6d22, 0xf4552b8f, 0x66bbea68, + 0x7f19b00e, 0x6664759f, 0x8051725d, 0xeb124217, 0x9b211807, 0x771388e0, 0x1208034b, 0xaaf93881, + 0x5336b3a7, 0xddbce6c3, 0x3b1d8269, 0xf5180df8, 0x8d8f2579, 0x3de7cf01, 0x8e899390, 0x3763695b, + 0x5e617db9, 0x55b5e09b, 0x7219d278, 0x38a0cb65, 0x8a3c9119, 0x162be0f7, 0x1be9a594, 0x33249dcd, + 0x1e5b08a7, 0x0c6273da, 0x363d814a, 0x93556c8a, 0x64d1988d, 0x3eae2563, 0xf29e2a1f, 0x739994db, + 0x385bd6a5, 0x469f0320, 0x61793fc0, 0xe222d05f, 0xc72c6d4e, 0x06429dc6, 0xe9f7e046, 0x053d38cd, + 0x4519f73d, 0xd3e43b4a, 0x04399381, 0x0892c2d9, 0x2e6ebecd, 0x0630adef, 0xb22fddee, 0xfdd8cdd7, + 0xc3c7e24a, 0x893919ab, 0x22673aee, 0x71b92126, 0x2b489ade, 0x19a59e0f, 0x1fbff054, 0x66166ddb, + 0x1df15679, 0xe74454e0, 0x4f974898, 0xb53e4300, 0x659094ed, 0xe25f28a4, 0x35a0c49b, 0xbe2c8e86, + 0x11e7c1fe, 0x5e9c72e8, 0xa8955b57, 0x669ef648, 0x5cd159a4, 0x4f9dac0d, 0xd2dd0235, 0x43e06647, + 0xae7db9dc, 0xcc7cfae5, 0x3139d319, 0x1ce01d88, 0x9ea9c329, 0x5873517e, 0xf8ff818d, 0x1eb88957, + 0x414413d4, 0x6a0253ea, 0x38da9ac5, 0x8ec9c942, 0xe0bf541e, 0x8c92f415, 0x890d1599, 0x749d7fc9, + 0xc3cebf27, 0x4eb20b6f, 0x78a47f44, 0x17328c96, 0x5ebd77af, 0x333ddf32, 0x8a93f705, 0x3e1f7f30, + 0xb93841ab, 0x11d49684, 0x2acd90bd, 0xc21692a0, 0xbf2a1dde, 0x69c2f08c, 0xab95680d, 0xce274227, + 0xb787d9e1, 0xf96e82f3, 0xd7279217, 0x6115f53a, 0x7c1acd20, 0x721b8c98, 0x5b6b93d3, 0x75f100d3, + 0xd7e52390, 0x27b75f14, 0x31ebee00, 0x121c789e, 0x141a9174, 0xa88a00f2, 0x60e810a2, 0xd96d27ad, + 0x6a33ea2f, 0x676d7935, 0x4ea04abf, 0x9e27e61a, 0xb79c9824, 0x23e41c33, 0xaa0975d7, 0x3d6245f9, + 0x4af93453, 0xd6d5d776, 0xffe07162, 0xfcc27786, 0xa03db87b, 0xc35fdc25, 0xf482a2e6, 0x7b1b9913, + 0xe8c6654d, 0x84e81700, 0x0ff45e10, 0xc12c3436, 0xc071a911, 0xd683746a, 0xea7c7e78, 0xda0db41b, + 0xf4811528, 0xf7cf5077, 0xcc2de923, 0xea75f33d, 0x716889e4, 0xfc424893, 0x1806b8b9, 0x807bb9ff, + 0xf336db07, 0x1842cf10, 0x4a706191, 0x1bc2aeda, 0x78394c0a, 0x8eca19dd, 0x48143652, 0x13d8b472, + 0x2281e60c, 0x57cd8ede, 0x3805d807, 0x55aa56b2, 0xbea1bf33, 0x91dc0274, 0x1eb20b30, 0x3036217b, + 0xc748bc8c, 0xa5a49ca0, 0x4b96862b, 0x4af4e27c, 0x8dc3b352, 0x2cfd31a2, 0x5783ed58, 0xa042d94d, + 0x744cfc31, 0x7767f1ff, 0xbf45f177, 0x9c9fa68b, 0x869a1ee2, 0x63c81a96, 0x82cd4f8f, 0x495de181, + 0x87badf04, 0xa5e8984d, 0x6585b708, 0xfb8311d5, 0xeab4d5cb, 0xf0e1ed10, 0x08caba51, 0x02697953, + 0x5740c6a0, 0xe954d0d1, 0xa25f8d7c, 0x747322e0, 0xdf807975, 0xb94a7ac2, 0x15a6b1af, 0xe7564175, + 0xb868e64c, 0xa9a1df46, 0xc08819e8, 0xaef65526, 0x7975d92a, 0x9b6de12d, 0x8598f592, 0xf5c6fc13, + 0x7a780c33, 0xd6f2c280, 0x3f5a3765, 0x5d3ebff2, 0xdcb1eeac, 0x0ad03c8d, 0xeaac2d35, 0xc04e1158, + 0x7e0195f5, 0xec0d3118, 0x8647e9ec, 0x44389cd8, 0x2a00f7e7, 0xea691486, 0xa6228cc8, 0xb1ace063, + 0xa950fdd0, 0xe2444e14, 0xc7be3a4b, 0x7a7546c1, 0x0c73a6ba, 0x8e272078, 0x669adf51, 0xf82e18ec, + 0x76d78460, 0x61046b2e, 0xcc41a16a, 0xf70657a7, 0x0f4f30d8, 0x76e44128, 0x6d968031, 0xde21b310, + 0xa18f38a2, 0x2b814777, 0xd4be6be3, 0x389010af, 0xb152d4ff, 0x510ca9b9, 0x2c036f83, 0x858078b1, + 0xdb2a3547, 0x3e9f0738, 0x62919dd9, 0x32251313, 0xb08b8274, 0xe3772de2, 0x546748ff, 0xc9d532b3, + 0x93707431, 0xde155677, 0x512621b2, 0xaaa04463, 0xafede8d3, 0xc3557937, 0x3a34a3d0, 0xaf3f85b4, + 0xc8ddb3bb, 0x228e3c9a, 0xae814663, 0x5df088c9, 0x9c4b1a76, 0x61462f65, 0x09f32662, 0xaf5bfbaf, + 0xa7874dfc, 0xc89c3c6c, 0x20ff2130, 0x76a8ca89, 0x5cd48bcb, 0xc4b93761, 0xa71eadaf, 0xdc87db1c, + 0x4276ea47, 0x9f613968, 0x18caac85, 0x1c7399e7, 0x9594e892, 0x296710b7, 0x7412ad95, 0xf6d7c45d, + 0x5891bc72, 0xcbed3943, 0xb98e1f62, 0x49c83a67, 0x06366577, 0x173f7342, 0xdf462e09, 0x6ea35ab3, + 0xcabf3f1d, 0xb2688934, 0x7092cf51, 0xa502ad81, 0xcb41d229, 0x81178b05, 0x402037d5, 0xd5dbf092, + 0x95a9fcce, 0xaa1c78ee, 0xb3ab1365, 0xc76b7371, 0x5af7a8b2, 0xe224038d, 0x53233a9c, 0x09e17c09, + 0xc8d5afab, 0x4bb4d263, 0xf1b230bf, 0x7b149291, 0xde2936e3, 0x090ad6dc, 0x4456aa37, 0x85f3c497, + 0x607dc82d, 0xbec13538, 0x7658bdda, 0x8da5b944, 0xda3e9e0e, 0x80c02e5c, 0x9ffcd79f, 0x1651bf41, + 0xec256ca5, 0xd7930102, 0x00117928, 0x5d6862dd, 0xd1db7470, 0x5af255e1, 0x16c01ba2, 0x9e598299, + 0xfe7b57ca, 0xd975f6a2, 0x051719ed, 0xfd3bcfed, 0xf4539b4e, 0xa484c7c6, 0xc8c2f931, 0x7dbc30c8, + 0xf5f43215, 0x0fb008b4, 0x24a53591, 0x96790fea, 0x238cac6a, 0x1bea888d, 0x436030f8, 0xc6285f9a, + 0x92f5f581, 0xfd973c7d, 0xa3615bbe, 0xca01ccc6, 0x9c42f9ce, 0x14a500af, 0xe1d1b780, 0xfddff500, + 0x269433f3, 0xb98d1014, 0x83c48b76, 0x9f66f973, 0x87a0174e, 0x7fc0db3b, 0x4d02b147, 0x6d549b34, + 0x2ac27330, 0x16a46b24, 0x8830ebfc, 0xf4021f62, 0x86da996f, 0x982164b2, 0xef9bf615, 0x3ca64402, + 0x7fe87987, 0x2b4223d3, 0x2dd60caa, 0xbede366e, 0x22579d98, 0x7cb059ae, 0x9e87fba8, 0xaab5d4fa, + 0xef2316e2, 0x4bec2eef, 0x773667dc, 0xced709b3, 0x2034f56d, 0xe6d89eaa, 0xb7b5d903, 0x53f1bfa0, + 0x12add6fe, 0x0a34da15, 0xcbb1a83c, 0xcb4bbac4, 0xf85cc2ee, 0x7d6f2c6a, 0x048bcc6e, 0x7b53d9aa, + 0xa6d16182, 0x11caf86b, 0xd9b42108, 0x83c61e9a, 0x09f3132e, 0x1a80d3c0, 0xab216121, 0xa5b4d6bb, + 0xccfc55a7, 0xf38ccc56, 0x3a4eb091, 0x88ee7310, 0x60281c3f, 0x391740b8, 0x5f455270, 0x5dc89ea6, + 0x9d83e9e3, 0x4656389e, 0x84f08b13, 0x0470d10a, 0x02596c24, 0xa6ed5800, 0xf35a3b59, 0x8a91d3b4, + 0xc6b0cbbb, 0xe30a8eee, 0x7d565da8, 0x3499d4f4, 0x114ab22a, 0x743da4b6, 0xc213e84c, 0x46ac6914, + 0x2d5a1e03, 0x104b4aff, 0x4652c957, 0xe2993020, 0x8599e266, 0xb37e48bb, 0x366547e2, 0xc42a47a2, + 0x919003d3, 0x78b28762, 0x5f84c1ba, 0x26ca13f5, 0xed3fc91c, 0x7e160c25, 0xb49cd772, 0xd9ea2ae8, + 0x836359c2, 0x66c3121b, 0x89f323a6, 0x8263e32f, 0x798d8af4, 0x269d0120, 0x9ba73b52, 0x2b881cad, + 0x7e293a0b, 0x2b3735bd, 0x06724904, 0x83716418, 0x95804a8e, 0xe44d5cf1, 0xc6422988, 0x76d9157a, + 0x99950a26, 0x66fd738c, 0x445c26af, 0x3a93cae8, 0x752231e6, 0x8d26a84f, 0xff177232, 0x9bdee18b, + 0x3f1d812e, 0x77fa2658, 0x73f7969c, 0x459c7a0e, 0x4555a0a9, 0xe953ca3f, 0x3708f55f, 0x30262c97, + 0xd6273913, 0xc87c159f, 0xd9cf5036, 0x3ca0ed07, 0x76134806, 0x160091f3, 0xa03bb4d9, 0x59f5ee78, + 0x7cac37f9, 0xa569907c, 0x2efc3b38, 0xc24663ce, 0xc6d93022, 0x0418f2a5, 0xb4bce1c0, 0x7d41e820, + 0xcbcbec70, 0x1235025b, 0x43d01085, 0xdc0c40d8, 0xcb65106f, 0x3c25038a, 0xdcc8d211, 0x00e9d4f4, + 0xbbf97b4b, 0x67efea9f, 0x8c55f438, 0x160b4010, 0xd927ad0a, 0xea51acbd, 0x7312b822, 0x5faf30c1, + 0x82dd2481, 0xdef57c58, 0x2ede5694, 0x70dd79f4, 0x6fda8e76, 0xcfb72679, 0x935444db, 0x7a5b00cf, + 0xbbfad198, 0xae22d6f8, 0x6541d9b6, 0xad5cbb06, 0x19a17c37, 0xb9b76111, 0x2dc99fbd, 0x9cdd86e8, + 0x428bbd78, 0xef6a706a, 0x75b02fd3, 0x952066ad, 0x7d709b89, 0x9d8ab7c0, 0x1fac7985, 0xbffbe44d, + 0xbb1750ac, 0x9467c23c, 0x8a53465d, 0xb774e4c3, 0x3c616cb3, 0x387735df, 0xde4102c2, 0x38e7a8c9, + 0xe80d66f1, 0xd19e8362, 0xe309c2d3, 0xc7856386, 0xf9b1a9ce, 0x415ee723, 0xef60274b, 0xdf29d3cd, + 0xa8b73c03, 0xabee3ac2, 0xda043855, 0x4c6b7632, 0xecd9d583, 0x036b2719, 0xc794d652, 0x5b5d61f2, + 0xaff6b9b9, 0x8a3dabea, 0xd25b9e17, 0xac73234e, 0x163b3e5e, 0x7b1d47cd, 0x8b0e2ae2, 0x05aab507, + 0x950fc368, 0x1ca9e0db, 0x771e2476, 0x144415f3, 0xb808b1c3, 0xfa31d300, 0x46cfa3b2, 0x47af915f, + 0xb9040317, 0x044a4ec0, 0x91c65347, 0x6eef0f3e, 0x10816977, 0x8e79a9ca, 0xc4c347c2, 0x7c309ee3, + 0xf7739c05, 0xc53be574, 0xa335878b, 0xd04b3860, 0xa413d42b, 0x5b0af0ef, 0xf3065a88, 0x9d43dadd, + 0x990690af, 0xbc822cde, 0x0e88e336, 0x9d555cb9, 0x167aff56, 0x880cdee7, 0xf02aac2d, 0x0a7c7d68, + 0x4f750dad, 0x01528a6d, 0xee31c154, 0xbd0f48f2, 0x52e43471, 0x1e57ad06, 0xc890e486, 0x9a3bb682, + 0x66037355, 0x2f381995, 0xbdfddc94, 0x4e903acb, 0x147d03dc, 0x69067939, 0x1773abe0, 0xe78840cd, + 0x740dd93b, 0x77e4ad17, 0xfbf84b54, 0x687e34c3, 0x86cafa65, 0x83229804, 0x7bdf84e3, 0xf2f3e8a1, + 0x7447b436, 0xd95634ed, 0x107b17d9, 0x37bebda9, 0xc58b056c, 0x8fa178f3, 0xf3759c70, 0x5022ae76, + 0x2d751cb0, 0xdab5b38c, 0x58a56023, 0x9ccd8837, 0xa73cd204, 0x80388774, 0x609b8fd0, 0x638f4fc5, + 0xbd500106, 0x3891edfc, 0x0c10aaa8, 0x7d5b1cf0, 0x78e63f82, 0x669931c2, 0xf3858544, 0x0a4de850, + 0xbf67be9f, 0x6572502e, 0xf1e1c94f, 0xab9e8757, 0x5d2730f6, 0x762d474a, 0x4b74f936, 0x8c15e5a1, + 0x217859aa, 0xbb31086b, 0x6faf38e1, 0xf24ab071, 0x7ab45206, 0xcc030eff, 0x1332026c, 0x1949fbe6, + 0x87935917, 0xdd373996, 0xcd1288b0, 0x1778258b, 0x183db15b, 0x5605a716, 0x10617a3c, 0xb2cf95df, + 0x0617865b, 0xdb18af8d, 0x8133ac3f, 0xc6a0716b, 0xe2b65e7e, 0xb69f7ea2, 0x6f636010, 0xe8b2e594, + 0x02e1c127, 0x1483c8bb, 0xbac22f73, 0x714e8a2f, 0x880421f5, 0x469b44a0, 0xe23dce96, 0xaf52d4d4, + 0xb321262d, 0xcbd3f016, 0x47411e00, 0xd26b49b0, 0xf1b56bab, 0x2a2e154d, 0x61a19121, 0x305e4fca, + 0xe10ec16b, 0xc9013b91, 0x405b6f8f, 0xf4e51474, 0x2c21f19e, 0x7828f8fc, 0x5b2f3f1f, 0x77efda66, + 0x79115307, 0xb1f7bf33, 0x2fee661c, 0xf8305e64, 0x010b4592, 0xf6f7cc19, 0x6d5f884d, 0x186cbe13, + 0x275a5416, 0x5904ad4c, 0x05c0fb49, 0x8628c434, 0xc92fc30c, 0x09a7ea9b, 0xafcf3e51, 0x712b5313, + 0xf7399aa4, 0xf2cf7451, 0x8c21f081, 0x19533aee, 0xece06417, 0xda6aa502, 0xef37a38e, 0x98073305, + 0x5e69d753, 0x790d9ccc, 0x41cbfe75, 0x3a4bbf4d, 0xc6de5de3, 0x39edce44, 0xee017dc7, 0x3c272466, + 0xd41354e6, 0x43f16e73, 0x64f72dfd, 0xc3d5df5a, 0xcd950923, 0x05f4e78a, 0x90e00000, 0x9c43d00a, + 0x1a8a2165, 0x51628f7f, 0x7b179016, 0xafcb2e9d, 0xb77a1c69, 0x43bc5825, 0xa95b4f56, 0xdeaf7fda, + 0xa91c4ce4, 0x8623768d, 0x583dacb7, 0xc041b423, 0x5c2e6d48, 0xf0ccd960, 0x08c3875a, 0x35f32894, + 0x7cff50c4, 0xb5220da7, 0x0a6d62af, 0x13d4daa1, 0x66585b5b, 0xa9ba1db7, 0xfd663981, 0xccd7aeed, + 0x63b6f9be, 0x29ecf7db, 0xfbfacf5d, 0x49b9c4fd, 0xae6aaaf0, 0x43c7978b, 0xc6f5ee46, 0x33f0b755, + 0x584d2c7a, 0x2e38ee22, 0x53eb935b, 0x52eec784, 0xc9fd1835, 0x699a2848, 0xaddd25b7, 0x684293dc, + 0x508bf7e1, 0x5151e1e7, 0xafd2e09b, 0xcf9c53cd, 0x34b87693, 0x0647d2ba, 0xea366d9d, 0x65203914, + 0x30e12d9a, 0x6391f5ff, 0xa087f88d, 0x1320c28f, 0xdb82b706, 0xaa8be658, 0xd4a4966d, 0xf97b5c3b, + 0xa14f6953, 0x6003810b, 0xae01251a, 0x65a09522, 0x65c4314d, 0xfaacf3fa, 0xc76140e2, 0x27db09e0, + 0xe6783fbb, 0xa93aa320, 0xdc1e3ae8, 0x1d1aedd4, 0xb235ac96, 0xd079b40d, 0x761cf511, 0xc6cec9d0, + 0xc320eaf4, 0x8d0f575f, 0x10f599eb, 0x52174816, 0xc0ff7ff4, 0xfddab625, 0xbf386811, 0x4e8aa501, + 0x46eb2de6, 0x7f7e6a83, 0x89bee8e5, 0xc94464d5, 0x88c7174b, 0x902d97fe, 0x7f3622a8, 0x04a0444d, + 0x878ed8e1, 0xac50be3e, 0xe18ee38d, 0xb70585be, 0xff7144df, 0xa2253387, 0xcc835ced, 0x7b5e74aa, + 0x950c94df, 0xccedc875, 0xd474c2fb, 0xd79a121b, 0x7822a779, 0xcce52abb, 0xeb1d5af0, 0x4bbf6756, + 0x3cc6c282, 0x9a5f7d3a, 0x6c338bc0, 0x91b0c4fc, 0x630afb1c, 0x1287991b, 0xba4c1800, 0xd5bb0cdc, + 0x1dd0b3d8, 0x2b5d9110, 0x0376a369, 0x91650334, 0x8ea8dc7c, 0xb3a0408a, 0xe811f272, 0xcf0a4add, + 0x39d5cc77, 0xff269a30, 0x69e179c0, 0x6c244a6d, 0xa10eda3c, 0xa4932684, 0xa569ec68, 0x96c4c647, + 0x783ec05e, 0xfb89ed2f, 0xbe358b5d, 0x4ab32161, 0xf8aae8a2, 0xe090cee1, 0xde481dcf, 0xbd34713e, + 0xa6ec20ff, 0x7db11d9d, 0x8ea714f4, 0xf7dea2ac, 0x879ca168, 0x9a988714, 0x212e0e86, 0x29b61b2b, + 0x6f5d1fe3, 0x8668ac7f, 0xce55fcd6, 0x5b6b478f, 0xe2eb9963, 0x5b530e31, 0x07ae5f7c, 0xb4bfc2c4, + 0x44921b7a, 0x992a84e8, 0x07af068f, 0x1cbe76dd, 0x7dd3cc05, 0xb6e797fe, 0x84f3eb01, 0xd49aa247, + 0xf6fdca8a, 0x1cc49ed2, 0x78232daa, 0x67d847b3, 0xacfc80e6, 0xb605e2e4, 0x33a66caa, 0x7ad6fb91, + 0x11d698c5, 0xa58b0df3, 0xa09ca8be, 0xd6d161af, 0xaf34c3bc, 0x4744d88b, 0x7d7f54df, 0xfd63bc10, + 0xa5a6a525, 0x2102de13, 0x5f47ae4a, 0xb7378c1e, 0x52eb9f6a, 0x3a14b212, 0x352a0203, 0xd603f7fd, + 0xbc86c5d0, 0xeb88d198, 0xcaa10da1, 0x7431744d, 0x7ae4e867, 0x55c6a313, 0x79c47d0a, 0x1816a2cb, + 0x44b739d8, 0x0ba2ba3d, 0x83b6bee4, 0x5c1d7217, 0xb64c9a1b, 0xdf186f12, 0x6f48b7a2, 0x8376c839, + 0xe2cb399f, 0xf7dbd483, 0x5508a693, 0xfd3f0267, 0x7b77398c, 0x62efe87e, 0xeec84362, 0x76d317c4, + 0xccea10ea, 0x1587f1c6, 0x332a7d00, 0x7d304255, 0xdd012e61, 0x5ae678fb, 0x9ef51205, 0xeba26379, + 0x366a3cf7, 0x9f53193a, 0x4402e953, 0xcc955bda, 0xd03fbb55, 0xbf525ed4, 0x4103afbc, 0xcf8dfa65, + 0x0bb75629, 0x2efa7a8e, 0x4ffda1ec, 0xb437cbc2, 0x546e1787, 0x68a6fda4, 0xa6a2a96c, 0xd09a2657, + 0x3f9cbd53, 0xb6db4246, 0xb8e050ad, 0x16a9b24b, 0xe2c84610, 0x4006fea9, 0xc79f063c, 0x86136c1d, + 0x174936fc, 0x0ee8b755, 0x02b73971, 0xec700c73, 0xb786b708, 0x301e901d, 0x08ded692, 0x2274b771, + 0xa2b3d058, 0xdcc76d75, 0xb427eb47, 0x9f8aa994, 0x2556b729, 0x33597a05, 0x1f2af4ec, 0x37015250, + 0x95813d52, 0x62c4c2d8, 0x0acedbcf, 0x6b10abee, 0x00c6db87, 0x8ddbcc3e, 0xe5ef6749, 0x4b453b59, + 0xcc9eaa31, 0xee3e9585, 0x8898051b, 0x4f98115b, 0x9ea71ac6, 0x1b6804d1, 0xbfca7749, 0xcfc1c735, + 0x508ecc8f, 0x3a71e92a, 0x10d5827e, 0x378f7f17, 0x557d3c31, 0x71bf36a9, 0xb7ec53b4, 0xb4585daa, + 0xd4d3913c, 0x4cd90788, 0x129fdd58, 0xc7bcea6d, 0x7f551c11, 0x79b6236c, 0x3d95a838, 0x389301d0, + 0x9f99c0b6, 0x6008b329, 0x868494e7, 0xb54d6457, 0x4eaef466, 0xa08ca759, 0x6ec1b973, 0x1746ad93, + 0x4320c31d, 0x3077520b, 0xba0da187, 0x1930f5e8, 0x67e13baf, 0x9ad46991, 0x24b520cf, 0xffc4785c, + 0xf6bdfd4a, 0x7eb0035c, 0xb61ff817, 0xa3a7b073, 0xcbd1e222, 0x1e8866c6, 0xa26e04c2, 0x45c4fa71, + 0x9c9d25ba, 0xbbf3b753, 0xfcd87569, 0x896070b9, 0x91ecc0bc, 0x32f6a067, 0x30ba12e8, 0x53846581, + 0x5083fd96, 0x68cc9674, 0x0b8ae5de, 0xfbe99612, 0x4ac84b3b, 0x4754a286, 0x24da39f0, 0x24b028a9, + 0x522f514e, 0x6a9c583e, 0xda68138a, 0x11089914, 0x5958c5b9, 0xa705dc6e, 0x46c3e327, 0xedbf9984, + 0x012d7bed, 0x8d7aaf6b, 0x5b3d3105, 0xc3b5998e, 0xb1dcaeff, 0xe7633923, 0x871d7ea2, 0xcba1bc95, + 0x0efdf07d, 0xd9a818aa, 0xd7c3433e, 0xbd713301, 0x33caa9ec, 0x65a3969c, 0xf5a98e98, 0x8f737b89, + 0x7cda4cfd, 0x68fb00c9, 0x3440013c, 0xbf824315, 0xdf576097, 0xece8fb5f, 0x27535f7e, 0x9e4dc24f, + 0x2069bb16, 0x692121c8, 0x409b3a75, 0x79c821a3, 0x12d24387, 0xebcfdef5, 0x0a0a4291, 0x3d3fcd9c, + 0x610cccd9, 0x259b73e6, 0x5b85af33, 0x59c74834, 0x20e1c19b, 0x027ae0de, 0x2b4d5087, 0x87973c66, + 0xfcfea0d0, 0x4f8b5fac, 0x4c8e59fe, 0x722110bc, 0x6d6752f9, 0x92d86061, 0x873d15be, 0x395f235c, + 0x6368fd1c, 0xb922f28e, 0x82abf8cd, 0x0de9ce4b, 0x0d4509e5, 0x164d8d46, 0x38d6d6ca, 0x6e5ba384, + 0x201e7438, 0xff41b92e, 0x2f5ecd48, 0x058a461e, 0xe7866781, 0x9ff70b36, 0x28ce8830, 0x888ff52e, + 0x74cd19b7, 0xf75ca2d1, 0x09bb42ab, 0xbcb886ca, 0x01bec75e, 0xc5b95339, 0xe3596d8e, 0x0e4da856, + 0xc0698079, 0x16d551fd, 0x4521006b, 0x3a018221, 0xfa657b60, 0x063f3ec7, 0x03fd55bb, 0x760513cb, + 0x86adbd93, 0xec72b11e, 0x5976a5e7, 0x4b1932a3, 0x146d149b, 0xa9409452, 0xd04ea245, 0xd6f950e8, + 0xc7e7fc9a, 0x9d48e9f5, 0xed497d76, 0x4de47b68, 0x3c30a276, 0x7c08f20f, 0x1488884c, 0xd53b9c23, + 0xf5304474, 0xa61160f6, 0x8d378b3f, 0xcf661e31, 0x1d1a612f, 0xa8da99d4, 0x85ed0776, 0x82d06861, + 0x5c4e0fa9, 0xd8666e6b, 0x05b7dd63, 0x3c9128fa, 0xfd615e5d, 0x49afb878, 0xc61594f6, 0x39b0a0f1, + 0xf95c4fba, 0x5fcda8a6, 0x6c4cc7b1, 0x2920d292, 0x4728017a, 0x9c25f352, 0x06f9604e, 0x22657f14, + 0xaa7a1031, 0xe5e4f8ad, 0x8af160cc, 0x373dad9b, 0xf5de6767, 0x183d12cc, 0x9270927d, 0x5798338c, + 0x1e528374, 0xf915af63, 0x5656a524, 0x62436351, 0xdff51f1e, 0x487823c9, 0x186d77b5, 0x841a5d42, + 0x5461fae9, 0x20ce30ce, 0x0c59c638, 0xc14bb131, 0x986854b1, 0xd6bcf808, 0x2c811eb9, 0x3cf32e37, + 0x0d091e9f, 0x26c4043f, 0x2afcbf19, 0xd61a7c4a, 0xa94a02a9, 0xe0a65e9e, 0x3ca9c12f, 0x117c8547, + 0x9dce22fc, 0x54b310ae, 0x878c89b1, 0x3938e998, 0x579f77b1, 0xb5d1af29, 0x35cf1b33, 0xeb6a42e7, + 0xb317ea93, 0x780f0e39, 0x44e9d244, 0x8fad59e0, 0x2dd16aa9, 0x3d3e8ae5, 0x1d316870, 0xb2ceeff5, + 0xdf888314, 0xdded2c3e, 0x40680334, 0xc1fa75c9, 0x55870bde, 0x220bbefc, 0xe7f6c5a7, 0xd3334bd1, + 0x56b20675, 0x81b3dd7b, 0x9b088bbf, 0x83349fc2, 0x983a77a2, 0x20eb94f0, 0x537fbaf9, 0x2bb1060c, + 0xcb739649, 0x0279df6e, 0x6337746b, 0xfe977d94, 0x42d42219, 0x89d73bf1, 0x3b792456, 0x1b41f9fe, + 0x36c13423, 0x968cedf1, 0x298d8735, 0xd064a2d7, 0x29390e70, 0x33326d3a, 0x2be6fbd4, 0x079e73f0, + 0x60640e40, 0x9cd989b9, 0x6537cae7, 0x94ce220f, 0x9d821a3a, 0x6d44127d, 0x06d05a54, 0xe5a470d7, + 0xc78c5524, 0x56e8288c, 0xc85f76c6, 0x6ffa502f, 0xd381385d, 0x344d25f4, 0x9d959c23, 0xc6387c54, + 0x9900520b, 0x9dd8b840, 0xca514176, 0x3a2899c1, 0x109f3f41, 0xb9483f95, 0x8969e256, 0x94e031dd, + 0x45c24e81, 0xf0fc452b, 0x169f0b7e, 0x4c7a83ca, 0x2590023e, 0x3f370609, 0xbe520296, 0xf696212f, + 0x9a569d6e, 0x11f66b4c, 0x2e2d2e7b, 0x541515b9, 0x4105ad7b, 0xb089f908, 0xd5a19439, 0x66223618, + 0x5f2b99cd, 0x077c68b9, 0x152d6ee3, 0xe98ee9e3, 0xc441f4aa, 0x19af8d62, 0x6ac89f11, 0x3816ef1a, + 0x2a6159ed, 0xc5f9537f, 0xe55d95e5, 0x80f1c700, 0x32bd69bf, 0x13cc8e2d, 0x5140092e, 0x9fc6abf9, + 0x96bd1586, 0xf53e740a, 0x48250f87, 0xea01c65b, 0x186b356a, 0x9085f2e2, 0x57be483e, 0x103fe98f, + 0x42c9ab73, 0x55fffe35, 0xc273a73a, 0x98ad7b7f, 0x92ac2a2e, 0xd2fb432b, 0xb95d6455, 0x264b77a7, + 0x71279852, 0xad85efa7, 0xc1fb0ed2, 0xdfc7e7fd, 0x1ec5f7aa, 0x3480d09f, 0xd30a7f41, 0x0c7a4c2b, + 0x87e21974, 0x4d2f1e74, 0x12bb937e, 0x17432063, 0xdfb9b389, 0x207c0f70, 0x1e616538, 0x3ff11926, + 0xa258d673, 0xc2b6e488, 0x8bebe62c, 0xc8a7d7bd, 0x187cf817, 0x75abd423, 0x93ed2884, 0x82e29fcc, + 0x63cf9944, 0x0ef3c7fa, 0x52670e94, 0x1e34e479, 0x094a9fac, 0x1f533bd5, 0xc6a10056, 0x0b2e7165, + 0x03e2dacf, 0xdbe2b82f, 0x9410b73a, 0x03ec676b, 0xa15b4e8f, 0xf785c1e8, 0x4a896879, 0x3650b8b3, + 0x824ff923, 0x02eb3b3e, 0x244f59d9, 0x6cc26825, 0xc512b6d5, 0xf3bf4b03, 0xc72dd7bd, 0xe0b9c401, + 0xbf181e4a, 0x63cca6b4, 0x9d806fd2, 0x55a55b69, 0xed0c6cda, 0x517c6ca2, 0x089d0b83, 0x3bd248e0, + 0x8bec5a3c, 0x4cf15370, 0x86245832, 0xe553651e, 0x668b8a3c, 0x0e5be1cc, 0xa1c3e52c, 0x88262aff, + 0xed586f29, 0x8bff05d4, 0x26b644f1, 0x85bfff9f, 0x612a085a, 0x6ab1cc77, 0x737ca91c, 0xd00f3c72, + 0xf76469c6, 0xb931d801, 0x2b2620c4, 0x30b05f78, 0x4e7c2457, 0x6dd96e69, 0x6c3fa6db, 0x7d28ea5b, + 0x07b21190, 0x69a63163, 0xf377c204, 0xafc516b6, 0xa915ed5b, 0x66e2a55d, 0xd6ebc296, 0x31cab60c, + 0x0c229249, 0x3e9cc08f, 0x9e984192, 0x79546cdb, 0x3f1dc1c9, 0xf5774c95, 0x8885da98, 0x11d990b3, + 0x1438aed6, 0xbb6fef92, 0x017f837e, 0x3fcab84b, 0x89c15699, 0xe728f432, 0x7b5c1ac3, 0x3f94aec0, + 0x9c86d581, 0x7544d412, 0x12231520, 0xd59e5e70, 0x984b18ab, 0x9031410d, 0xe04898a9, 0x4ac32422, + 0x7fa49e9a, 0x6d3dee6e, 0xbb502373, 0xe2652bc0, 0x4ac68735, 0x38455dad, 0xf10cc085, 0xc0d3c398, + 0x359380cf, 0x2ac3782e, 0x8df5257e, 0xe50d607c, 0xa9a6d056, 0x42336e58, 0x238d1011, 0x604394cb, + 0x3b34054d, 0x8d6d032a, 0x307f8b08, 0x698026df, 0x4ead831b, 0x9148b3ab, 0x25ad10a8, 0x69f3dd28, + 0x9347820c, 0xc01e526e, 0x38f62783, 0x891b8c05, 0xf65547f0, 0xbc640574, 0xb9621c45, 0x63713b42, + 0xe69204c1, 0xad659ccb, 0xe119cf7e, 0x911d35de, 0xb9da24b4, 0xe0af7d1a, 0xdc577f62, 0xa5c10b5f, + 0x648ecb45, 0xaf555409, 0xe0e33296, 0x8bf5212e, 0xea216c0b, 0x2078f9a6, 0x55eaf2b2, 0x3f9fe5a6, + 0x4dcb1bc8, 0xd09982d7, 0xd5118b71, 0xec60b4b7, 0xa5013217, 0xf3fe78cd, 0x5d023ccf, 0xe3198185, + 0xa886e600, 0x60c16dd3, 0x664e7bb9, 0xf5bc9aae, 0x06d7f2bc, 0xb15b33b2, 0xc951284e, 0xcf02244c, + 0xe215fb7c, 0xce1e51ac, 0x21cd1ad3, 0x168948e9, 0x7e3766ee, 0x23e30e86, 0x8959c157, 0x34102556, + 0x761cae61, 0xf905d630, 0xfc66e78b, 0x2304230c, 0xc9ba3496, 0xac88d16d, 0x072c5143, 0x2ad3e7da, + 0xd42b2408, 0x53a4718e, 0x34f80041, 0x55e37f17, 0xa310679c, 0xc37937bb, 0xff90b4e1, 0xe79cf14b, + 0x95f8cf2b, 0xfb7e354c, 0xf30d3174, 0xab3cdb73, 0xa7a57d5c, 0x70492d2b, 0xcb70a13c, 0xa918202d, + 0xbb218536, 0x775d6292, 0x1dee80f4, 0x2930b8a2, 0x2840b871, 0xa820fe3b, 0x057c1168, 0x140fc988, + 0x8a96e541, 0xe052d883, 0x20eb10fd, 0xbbb889be, 0x90843cfd, 0x1bcf3d10, 0x152d8808, 0x4f3dd3a0, + 0xcbabe270, 0x6a042fff, 0xdb80b1f2, 0xe275006b, 0x17b5c7c6, 0xdc3d5963, 0x389bcfbc, 0xc2e28cb2, + 0x51a94ad5, 0xcd95dff8, 0x30b908b7, 0xb6c242f3, 0x32ee5c81, 0x39c2861e, 0x85e00efd, 0xb0e9ed05, + 0x88537a7b, 0x54d43eda, 0x04f486a9, 0xf1a543f3, 0x8bd8c428, 0xfa91ead0, 0xf15d41f2, 0xf8d58e49, + 0x372de111, 0xb0575c91, 0x232056b6, 0x3c6bdc40, 0x4ee4ff1b, 0x1427c7ce, 0x0628f215, 0xbef518fd, + 0x39337250, 0x30570264, 0x59dccf4b, 0xa6c4131d, 0xd546f52f, 0x96b91d9a, 0x492bdc2f, 0x79a6596d, + 0x1376c975, 0x9c497f8c, 0x31a2904b, 0xf01428ed, 0xf98f3ed4, 0x0112ebe6, 0x4234c143, 0xcf2655c2, + 0x8f1f116a, 0xdb9747d9, 0x2f983df8, 0x98206c6b, 0x26832c6c, 0xfc4bbef2, 0xf40388dd, 0xd0c3bb31, + 0xad87098f, 0x7ee1243b, 0x58c72a67, 0x6de0dc7b, 0x957f9da0, 0x66273e02, 0xb2ee828b, 0xa0eac5ea, + 0xd3cd7cf9, 0x7e33ff81, 0xd2b65043, 0xddc0d39e, 0x0712349d, 0xc3203454, 0xe7581609, 0x52481a68, + 0x50a04c51, 0x97235d35, 0x9078a6ef, 0x937ed689, 0x8a66fdf2, 0xa837ecf7, 0xfb0f858b, 0xb99573e9, + 0x7fabf90a, 0xa71b3720, 0x62a15d15, 0x213f29b0, 0xeff9f662, 0xc9eafe38, 0x77538e89, 0xeeee3511, + 0x414ed012, 0x21a5f756, 0x765fa277, 0xab9c6fde, 0xf42542db, 0x03540705, 0x7d25b68d, 0x33a0ca38, + 0xbf674f1b, 0xe24c96d6, 0x25b76854, 0xc3a4b293, 0xf8fc3c8b, 0x0abb87ce, 0x3086fff9, 0xc4972923, + 0x39330d80, 0x979d34ba, 0x0c7c7421, 0x10c3277b, 0x56d6c360, 0x2050e8f1, 0xb6d8ca81, 0x94daf68c, + 0x8723e291, 0xd472e8cb, 0xbdeef73b, 0x80cc0477, 0x927eb936, 0x8e8d29e3, 0x0959f3df, 0x692bf260, + 0xab4da3fa, 0x11969599, 0x84180361, 0x54c22515, 0x12a5a53a, 0x459528d4, 0x37926b8c, 0x00d1293e, + 0xbca258dc, 0xa288e857, 0x2365de5e, 0xb69aae1e, 0xfd0fd1d9, 0xf213f4bb, 0x40f9ebe1, 0x1bef2db3, + 0xc3db462a, 0xdf5c1be7, 0x16b20237, 0x3b746f64, 0x50e47455, 0x2b5211db, 0x1393aef4, 0x1f89c211, + 0x6bdd3b86, 0xa0f95dcd, 0xa9d8c1c1, 0xacd60615, 0x66479fd3, 0x735b4b2f, 0x4dc797cf, 0xe2f8129f, + 0xec3bc3e6, 0x05fdb367, 0x2eeb082c, 0x5eba0e74, 0x078ff6ff, 0x4af0c83d, 0x6ae6704d, 0xaa7f795d, + 0x79f1971b, 0xf2aa10f4, 0xbca30c00, 0xd109a918, 0x609d2d67, 0xbbd48535, 0xbb175ef4, 0x563ca94a, + 0x9119fac7, 0x5f7f793e, 0x7f9aaea2, 0x2efa0b28, 0x29393b64, 0xf6d20c5d, 0x270216aa, 0x08ab809f, + 0xcc9e6292, 0x0c5592c1, 0xd9bcf1aa, 0x9398f501, 0xa92788fc, 0xd28ec3e7, 0x8e00e89c, 0x778ed6ee, + 0x51da860a, 0x2487a038, 0x0bbb0078, 0x9c7265aa, 0xb270e23c, 0x042648d1, 0xf2482e40, 0x7dfd7cf0, + 0x88fc821f, 0x7703791e, 0xdaa8824a, 0xd94998ac, 0x74bf357e, 0xd4f57d8f, 0xdda6d7b6, 0x3d016b0b, + 0xdced18b5, 0x9b099ed8, 0x0f750076, 0x01af5072, 0xfd73da31, 0xacae390c, 0xf7a319cd, 0x16f2c382, + 0x3f11b45d, 0x876752aa, 0xf27ff5e0, 0x3fb37d3d, 0x4b0dca2e, 0x1d4f615d, 0x248110bb, 0x7195387f, + 0x3912da51, 0xf8b836ce, 0xbc0d5be2, 0x7fb90405, 0xc82956b4, 0x293ccbb2, 0x09f5f4a6, 0xd026d5ad, + 0xaec6782f, 0x99de0353, 0x597a56a7, 0xc77f1206, 0x53296531, 0x8bb354a4, 0x38402bcc, 0x2d9a37c0, + 0xa78847a8, 0x44886aaf, 0x08f23d20, 0x9aa11abf, 0x471bdf64, 0xa627b36d, 0xcd63ce66, 0x75a026a1, + 0x4341b32c, 0x3aebc5bf, 0xe2aeed85, 0x778763ad, 0x209e33ef, 0x1ebc4f44, 0xb9005949, 0x61f9e9e0, + 0xff033e3a, 0x773d3ba3, 0xc2478e63, 0xdbaa4ddc, 0x193ce6ac, 0xb48425da, 0xd8940cf3, 0x23896cd1, + 0x05f390a4, 0xb4a726b8, 0xb22849ff, 0x9de35db3, 0xca76678e, 0x7a7c7294, 0xa49ffa4d, 0xdd34c1c7, + 0xb84bde2a, 0x99ac695e, 0xc79522ad, 0xb9f2cd41, 0x1ac72c85, 0x3b729e2e, 0x8103ff01, 0x1c5cbf5d, + 0xa306f660, 0x94699a7f, 0x239e6b2f, 0xadd478fc, 0xa9ef1f60, 0xc309cee5, 0x26c12472, 0xbb7fad4f, + 0xf2b1b45f, 0xc14fe050, 0xa0bff509, 0xae8a4a86, 0xf124c3b7, 0xd88dc9ee, 0x1ecf1a27, 0xbc3b52ad, + 0xf7324dd6, 0x61e1580b, 0x220c8395, 0x2d51e4e8, 0x0e5879cf, 0x17eb362e, 0x17e739f6, 0xba2dd635, + 0x47fb1414, 0x34ef447d, 0xb698e9b5, 0x7671a66d, 0xdacc67de, 0x002b39ad, 0x99013248, 0x72feef44, + 0x8286235d, 0x3ebaec2c, 0xe3844a39, 0xf53a8693, 0x93e0407e, 0x32b2de52, 0x05bb8665, 0x6f123f96, + 0x1400b9d8, 0xdd49e438, 0x75116911, 0x664a79eb, 0x2ed039de, 0x369a9408, 0x45a695f7, 0x328f8809, + 0xf44c2cf6, 0xc3335998, 0x37b78843, 0xa9304779, 0x86cc0b69, 0x60498219, 0xb376a2ec, 0xa9b32e1d, + 0x4b6de6ef, 0x3eb20b65, 0x61f02edf, 0x340a437a, 0x374f9bcf, 0x335870bd, 0xc248ac64, 0x014fa044, + 0xf7ba498c, 0x648a164d, 0xf675445a, 0xd0097a02, 0x77948ad7, 0x90c1c774, 0x752a7529, 0x26a1920d, + 0x38b535e5, 0xc32000c1, 0x7401f057, 0xfa1c7194, 0x496c5b8a, 0x08a4945a, 0xb3403b85, 0xa0fcb060, + 0x6ee10ea8, 0xc6227110, 0x2ca94940, 0x07b32ffc, 0xa51c911c, 0x84c7dfcb, 0x7e7f93a3, 0xaaebe711, + 0x2bdb05bf, 0xa50e4bfc, 0x52700bd4, 0xcee75dcf, 0x5be3680e, 0x9426f8ab, 0x13457be3, 0xc4a80f13, + 0x5012d5ce, 0x270d282a, 0x761aa599, 0x9b9abe55, 0xe94eda6c, 0xe28bfeab, 0xcfdbeeb6, 0x23f69774, + 0x70d26e05, 0x4ad901ff, 0xa46dd7e1, 0x47524dc0, 0x6e947b28, 0x21cc2ab0, 0x958f6404, 0x5584dc4e, + 0x66a967c2, 0x2bd0628e, 0xc988b058, 0x685f6922, 0x33762437, 0xe9d88cc4, 0x6e81efc5, 0x8df1387b, + 0x4084239c, 0x5951d0f6, 0xc6f455f8, 0x858ad69f, 0xcfcb7912, 0xcdd9c2b6, 0x66a824b8, 0x2cd88acc, + 0x499cb764, 0xd6efb2b9, 0x9d695ece, 0x04bc5804, 0x0d785443, 0xdf503288, 0x52bb0f43, 0xca7d46c6, + 0xdab5cf2c, 0x12a11154, 0x18f94bb0, 0x6bcfa843, 0x1dda5213, 0x1da1429c, 0x5d1208b4, 0x654c6e5c, + 0x26d896fb, 0x6785cb89, 0x3d4c892a, 0x22bb30c9, 0x5438a86a, 0x45b539e4, 0x4a327cfa, 0x4b6fd591, + 0xdf5f8cfe, 0xc61feb4a, 0xefb0a7e6, 0x2565b98b, 0xec7a3115, 0xe08e9295, 0x38b164d8, 0x6fefaa79, + 0xe02adf04, 0x0a969a37, 0x477d70fe, 0x1a73480f, 0x076dfcf5, 0x564293cc, 0x271f9036, 0x708e1b8b, + 0xbba39ed0, 0xf32f4bd4, 0x7f7f5793, 0x0488ebb9, 0xba8242b3, 0xc96162ae, 0xb6a1b104, 0x188d3b89, + 0x95d2b9e6, 0x7f92f153, 0x16cd38e0, 0x2c127ce8, 0x593da76d, 0xbdaa9803, 0xdf26176a, 0xb943252a, + 0x2e39e852, 0x250c3938, 0xc9d4dc77, 0xd2e7835a, 0xb6af4fc3, 0x5d01406c, 0x2aca0456, 0x51f5e4f7, + 0x3e030c92, 0x60c402ba, 0x74eb37f6, 0x84bc592e, 0x50944eb2, 0xbdcafd02, 0x4e4a8d41, 0x628542f5, + 0x1fca1724, 0x02b44288, 0x0d72dc49, 0x2623919e, 0x261df516, 0xfa48d1a6, 0xe625e6e1, 0x8d25f494, + 0xa133021d, 0x8d1af368, 0xb8cac751, 0xce391ce9, 0x570a9303, 0x0ba62c68, 0x286e9b26, 0x4d6974da, + 0xea60a6a4, 0x4bba77bd, 0x8943fc9b, 0xe3db5278, 0x970a584c, 0x0d1b6b18, 0x0d6dcefd, 0xfb07bd3c, + 0x9a99f259, 0x0f16ca22, 0x8f51fea9, 0xe09a6849, 0x98c837e2, 0x6c7b5635, 0x1508f000, 0x60b79efa, + 0x114605ef, 0x64ce1b83, 0x4e5fffef, 0xe9be0c52, 0xc98ee4ab, 0x712a024e, 0xfc24460c, 0xc36ea5b5, + 0x0eefa9bd, 0x8928eefa, 0xf899c26d, 0x11a53872, 0x37f61edc, 0x000cbb4f, 0x693ca6d2, 0xd1ea9901, + 0x30d6587b, 0x7814ff57, 0x0d980117, 0x1a887f18, 0x0d8fc0fb, 0x9af06f85, 0x4e9206cd, 0x81899df8, + 0xe6f89ab5, 0x610203a6, 0xbb20296a, 0xcada0e1f, 0xd9a8e70f, 0x0566301a, 0xc253c998, 0x4238a37d, + 0x722d89ed, 0xc1aba9d9, 0xc2aa00d3, 0xdb01284f, 0xd207992d, 0x1f052575, 0x46095af6, 0x428c2a22, + 0x781e2ea7, 0xd1ec0d54, 0x2b6b27e0, 0x10053ba1, 0x1ca1db80, 0x04876128, 0x330ce6ae, 0xd9334c03, + 0x91c83178, 0x6c46114f, 0x8375f76b, 0x47227753, 0xdcf36e36, 0x04131c25, 0xcef3bfab, 0xe419463c, + 0x95dde4b0, 0xb3770fd5, 0xca449006, 0xd634f608, 0xca7ec47b, 0x79b1708b, 0x1b786be7, 0xd78d3b08, + 0xa245ef76, 0xf2ce36e2, 0x3b031185, 0x3833eb5b, 0x52c691da, 0x11748ec7, 0xff688e50, 0xe77b9484, + 0xb4d8d7e8, 0x74dc6670, 0xa01c4ab5, 0x51e49757, 0xf860c1b6, 0xbb57263c, 0x61985dea, 0x6b3f4012, + 0x795fa59e, 0xa089c3a0, 0x5f8b9f48, 0x903fc545, 0xdfd80507, 0x029b2d3c, 0x3f017a3e, 0x74af6f5f, + 0x01d1cfe2, 0x405c2848, 0xb5962b37, 0xb5cc53a5, 0x4935e24c, 0x407600eb, 0xc8f22e83, 0x5015479d, + 0x432894f7, 0x434b9cfd, 0xbbd4b8af, 0x6ee59c15, 0x02ef1cc5, 0xb04ab50d, 0x4b743f45, 0x6fc60f5d, + 0x27333ee0, 0x514aac4a, 0x15611337, 0x72896fb4, 0x1d440191, 0xa0a30d4a, 0x1b6c5b9f, 0x1870c707, + 0xb22605fb, 0x81c8a724, 0xbbb0c17a, 0x43209a1f, 0xcf328287, 0x76e9290e, 0xe6f33ea6, 0xa8a38814, + 0xe35081d5, 0x9c1d96f6, 0x59023eb2, 0x218829f8, 0x1c13fe87, 0x8e53f3c2, 0x49d8275c, 0x98678aa8, + 0x22ff89ee, 0x28b8f55e, 0xf72caea4, 0xdad80898, 0x378ba8b8, 0x8cd7ea78, 0xbebe0a11, 0xb498f8c0, + 0xa1a45c59, 0xdc31b7b4, 0x2c06e982, 0xbf601962, 0xb1c3d66c, 0xa3339ca2, 0x857e154e, 0x7d5e4178, + 0x32e988f4, 0x2f74b206, 0x7353cd16, 0xba0e395d, 0x02e72dee, 0x3632def7, 0x68c0560d, 0xca8cf7ea, + 0x22a4900d, 0x54ed7925, 0x4e26f6c9, 0x3fb95a0e, 0x310550e5, 0xebdd7a3b, 0xade7b2be, 0x96649bd0, + 0x49d9a50a, 0x67463fc6, 0xc30fa0c7, 0xc6692692, 0x415299ff, 0x26bfdf7d, 0x4330af18, 0x38183090, + 0x90d7d289, 0xe2d30770, 0x5acaddcb, 0xc19622ba, 0x76efca45, 0x1974c4b1, 0xc0ca30ed, 0x5e0a8112, + 0xb07c5fcb, 0x6661e039, 0xa52d0519, 0x6f6a58c4, 0xa8e076a2, 0x9d8a0ef4, 0xebcec6e8, 0x67a532a2, + 0x51ef9c58, 0xb391fb4a, 0xfd26df2c, 0x093c9467, 0x7b3713e5, 0x08fad0aa, 0xa59995cd, 0xd83baed5, + 0xcc28377b, 0x210debd4, 0xf7203ec5, 0x3c4214c8, 0x5abade8c, 0x93d67647, 0xf3191e2e, 0x8903a1c0, + 0x6c4ff77e, 0x0eb82328, 0xcfc31457, 0x4b2a336f, 0xbf6abca8, 0xd9d33819, 0x269e1dc7, 0xeb6b7f41, + 0x394fd1ca, 0x39f33de9, 0x302a9a79, 0xf14407e0, 0x06fd79f9, 0x89913d5e, 0x057ad074, 0xf97c3737, + 0x75b6382a, 0x2fb65249, 0x40796332, 0xc352a782, 0xfaa8340d, 0x900b293a, 0x4d4603b2, 0xaf25516f, + 0xdbcf481e, 0x3345d1e7, 0x1701ed09, 0xaf53ca27, 0xbcf7ffd7, 0x5f3bd11f, 0xf2d21f5f, 0x59a250c8, + 0x8647d802, 0x90ff7237, 0x0f87ab11, 0x0453d08b, 0x3be8323b, 0xd1a6d7c9, 0x432abbd8, 0x666d4a6e, + 0x157bd87d, 0x1d2be833, 0xc59436ae, 0x02f8821c, 0xedf3775d, 0xf1959152, 0x6f1ddfeb, 0xd6e17120, + 0x68a8643f, 0x44875635, 0x02e509ee, 0xb6dacf88, 0x7ecdace4, 0xec4b27be, 0x67f8e410, 0x898d64d3, + 0xd9af75c1, 0x0ff49793, 0xc68dd54a, 0xaa61c356, 0xcd379146, 0x65a805de, 0x8b52e6d7, 0xf5073fa5, + 0x044e2a0c, 0x4957f975, 0x4cb97bcc, 0xf227ef6f, 0x489880a7, 0x0d4acded, 0x0eab35d1, 0x19ebc5f7, + 0x37d0a11d, 0x35ce415b, 0x61fbd2c4, 0x310b7051, 0x534b26f7, 0x75146257, 0x94d991e2, 0x429a4d43, + 0xe8c3593c, 0xb6041f33, 0x63a6d102, 0x0d200bd5, 0x2c249a1c, 0xe9d965f3, 0x7da3d098, 0x0120e548, + 0x66960a8d, 0x0f442b60, 0xfbda5577, 0x3753b56d, 0x6a5d57e6, 0x6c6e595a, 0xc87674fb, 0x83c87203, + 0x8cc009a6, 0x14ce4b33, 0x62116915, 0x0aa58ce3, 0x5a3113ec, 0x9ebb89c7, 0x9f084cbe, 0xf159ebd3, + 0xfdd5e9eb, 0x355574db, 0xff77ab3b, 0x2f7d565a, 0xe10ce3ac, 0x7bf3b2b7, 0xf84a9ca1, 0x8805027d, + 0xe0618553, 0xcd21385b, 0x1273a10d, 0x76e398b8, 0x803a2ac4, 0xc86e4322, 0x26b9a793, 0xc3adc70d, + 0x2b2a5d65, 0x94deaed9, 0xc424228f, 0x125587c2, 0x41e1c252, 0x59d16fcf, 0x41a83f5d, 0x010641a9, + 0xf9925bdf, 0x09cd4421, 0x5d501b7e, 0xbc35a05c, 0x4820665f, 0x1887ae0f, 0xfb927ffa, 0x167e7edd, + 0xe55b9f5b, 0xcf05a29e, 0xd731b96d, 0x42c0dd1a, 0xdf4525e1, 0x704de65d, 0x5d8eff75, 0x7d8afbe8, + 0x6a98e8b9, 0xbd395b13, 0xe4c74cc8, 0x69f7a0a0, 0x987d86cd, 0x8929ab8f, 0x713c2491, 0x5dec19c4, + 0x7c9f5e71, 0x3c0d8fe8, 0x660cda1c, 0x00f71d0e, 0x0c72212e, 0x032f7e24, 0x6cd89906, 0x94296935, + 0x7aaac3d0, 0x82268e52, 0xcee3ed7f, 0xb8799cab, 0x0027c7b6, 0x770f77da, 0x6f5f9328, 0x7a9118fe, + 0x6ef9dd9e, 0xe54ce21b, 0x5602b9e3, 0xe096c658, 0x77c593d4, 0xc19f4620, 0x2dadff65, 0x7e93ed2a, + 0xed387702, 0x0f79e8c1, 0x10a9393e, 0x0613f204, 0x35e37d55, 0xc8aa789b, 0x1e2886f0, 0x882807eb, + 0x379a0f10, 0x7ac4c41e, 0x12ce0958, 0xf1ab76d2, 0x0292e87e, 0x9f7b2728, 0xa02c7de4, 0xf9c463a8, + 0x2c014bee, 0x8e9b4aff, 0x1fd6aa16, 0x5206806e, 0xa8098a23, 0xaa7b657f, 0xb9454f4f, 0xc01bc38d, + 0x30de42a2, 0xd7c3aa5f, 0xa2dd1875, 0x724e0dde, 0x6a95ebec, 0xde93126a, 0xf9075011, 0x96fc39fc, + 0x98ab18cb, 0xc19f0a6c, 0x7bf26703, 0xfd3d89d8, 0x6e3fea6e, 0x713e2c62, 0xff3bea0b, 0xb15284fb, + 0x3dbb09e3, 0x5577e167, 0xd48dbcde, 0x7b6ae2c9, 0x5d6c7dc7, 0xb936869d, 0xcc002e26, 0x58417773, + 0xaf044bb0, 0x9b02a274, 0x65e56616, 0xeb062786, 0x4f4fbcb8, 0xb5d20a23, 0x1f718013, 0x6648bb6a, + 0xe66e2d21, 0x94e3f84e, 0x97c3c268, 0x4937f304, 0xa4bb8b76, 0x94509719, 0x4e56cd29, 0x1fa923d0, + 0xa911f3ec, 0x1681b99a, 0xc36ba61f, 0x80698134, 0x66f3b0d3, 0x7522b130, 0xcdb88faa, 0x61847ebc, + 0x521f4b8d, 0xbf3c5207, 0x28b494e6, 0x601b62c7, 0x49b63aca, 0xb0b26f05, 0xc287fbd6, 0x2c582403, + 0xfda13455, 0x162de45d, 0x6fc1df09, 0x023e3a46, 0xbfb31aa9, 0xd810e40a, 0x032550ae, 0x6e214574, + 0x62673ed1, 0xec7101e8, 0xf07a2b6e, 0x516079ab, 0x14cbaccf, 0x2974ad9f, 0x25f75f4f, 0x82683b4e, + 0x5e225413, 0x3b988543, 0x0b19bd7d, 0x2c282e04, 0xb828378d, 0x6dc230e3, 0x002ac00b, 0x71d6e91c, + 0x591c5c1f, 0x33048fca, 0xedc5d4ab, 0xa8e218d0, 0x74ef3796, 0xaeac6e5a, 0x3a7615c9, 0x540376c1, + 0xde2bd8e6, 0x8ad981a7, 0x2b4c78e9, 0x01dff178, 0x82596519, 0x57469fdb, 0x29bb0d3c, 0xd3383d02, + 0x53ceeaaa, 0xd85f2614, 0x8db0322b, 0x01493e8c, 0x63cc8424, 0x6fda0059, 0x570aa059, 0xb7e0963d, + 0xa85b7296, 0x9735355b, 0x25a5add6, 0xb718f35d, 0xb092ba14, 0xd8e77065, 0x0ba5f893, 0x1d6f0045, + 0xfad8fa87, 0xe45f1bfa, 0xec0416f2, 0x05f6e13c, 0xb4091368, 0xabec30ea, 0x379bee1c, 0x41fac9de, + 0x0f925c25, 0x4b5d940c, 0x9f6163a7, 0x854419ea, 0xa899d2e0, 0x102d25a6, 0xef00873f, 0xe6ca5c95, + 0x691bbbed, 0xe22f3738, 0x9d38a1d9, 0x4d4e02b1, 0xc99bd549, 0xdcabbc70, 0xd2a32e42, 0x31528de9, + 0x6229d65c, 0xab533268, 0x57ac7733, 0x4299eb5a, 0x5bae37c6, 0xe93e193a, 0xebaaaa06, 0x23f44ba9, + 0xa87da210, 0x32e4812c, 0xdbc33664, 0xd7ef5a8b, 0x4d66f458, 0x58cd07f9, 0xbce31e41, 0x7cc59fa0, + 0x10a02bb6, 0x2b83098a, 0x1a389b0e, 0x5afa6882, 0x61e8bb48, 0xd0b68a5e, 0xd8fff156, 0xe201b8b7, + 0x19f6e5c4, 0xac5b66c5, 0xb59b4e5d, 0xee0ad03b, 0x6af313f9, 0xa948a698, 0xe50acb45, 0xaaa4683e, + 0xc8bce236, 0x945de280, 0x5214c093, 0x3f8d6ca9, 0x1de24395, 0x08ddb01f, 0x19b4c617, 0x7cf3ff3c, + 0x94c83254, 0xd0ed3500, 0xf8da34a3, 0x0c17b3eb, 0xa065d319, 0x61ab1d74, 0x574ffc18, 0x9ee8412f, + 0x5e533218, 0x126fbca7, 0x33651235, 0x7742bf20, 0x5bb46b45, 0xc8b8f8d2, 0xcd31f06b, 0x9fb847e5, + 0xfa7321bb, 0x2fc460d0, 0x0668cfa8, 0x6ba07a12, 0xc30f987a, 0xcf78ce50, 0x708a45b2, 0x22ef3276, + 0x2bafa361, 0x2b5e9f6f, 0x7c12b133, 0x2955433d, 0x7ae68ba4, 0x812e6387, 0xc0fe06d0, 0x15c3133b, + 0xa9212c74, 0xe0a8fea1, 0x23127863, 0x5e3c3151, 0xfc2121ce, 0xd568f548, 0xa0232b6f, 0x03a8ca1e, + 0x0a75177a, 0x108be51e, 0xa7488f61, 0x6cca2261, 0xaa369c1a, 0x726fd030, 0xd5301993, 0xe6594776, + 0x8e0ba951, 0x1c87fe38, 0x5a910e04, 0x51dea6ab, 0xa308dced, 0x5b64c921, 0x757538c6, 0xfc3f5db8, + 0xe8cfc3da, 0x42570298, 0x1799fd90, 0x11912483, 0xe5a14cc0, 0x750ee157, 0xca6830c7, 0x255eacd5, + 0xf5ad70ca, 0xd783fb4c, 0xb5295a2f, 0x7a3d58f6, 0x2b643b7c, 0x99817a2a, 0x7219bba3, 0xe46d48f5, + 0xa529e5dd, 0x5fa988ef, 0x24ed9430, 0xd3eabdc0, 0xabb95004, 0x837b0aa6, 0xb9a2f529, 0xcccc015a, + 0xa5a706a4, 0x90aa5c13, 0x8865593f, 0x56236cda, 0x24828eb4, 0xa947bdb6, 0xcb9617b7, 0x1b3a5492, + 0x2091d4c3, 0xf22256e9, 0x0a469e50, 0x3ba2c3f2, 0x6e24246a, 0x85bfb13a, 0x4869fe2b, 0xad1c99a0, + 0x1a1d5fe9, 0x100f6b08, 0x72f02625, 0x9c190f70, 0xc739f913, 0x3a57850e, 0x8d9ca402, 0x261e387f, + 0x22217d14, 0xf22fbf29, 0xb0af6ddd, 0x67fb22c9, 0x2c8346d7, 0xa0b2de41, 0xde3acfcd, 0x1df82392, + 0xcdd817a3, 0xd2168437, 0xcae08dbb, 0x839d2771, 0x9dfb797a, 0x9b18081c, 0x31b07f41, 0xa09abd53, + 0x8b0955e4, 0x624cdb70, 0x718bfe53, 0xe87a908f, 0xd9ee77ae, 0x67c8880f, 0x36061f37, 0xd789afce, + 0x9cbbc7f5, 0x4504e0dd, 0x49713c07, 0x1e6eae2f, 0xd416931f, 0x98b7fea3, 0x68a3a15e, 0xfc1b6128, + 0x315d206c, 0xb0fcaab6, 0x3d318209, 0xbc6eac22, 0x1eaabd4c, 0xee4f2d21, 0x8c727a44, 0xd71156bc, + 0xa8b2ae2c, 0xcdb0581f, 0x10aa42a6, 0xc6a47ac4, 0x3494be46, 0x11c56983, 0x36390191, 0x48b419f0, + 0xed5df1ba, 0xef2d250a, 0x676bf978, 0xfd59a2cd, 0xf5e7b0cd, 0xd6d09d3e, 0x8313f427, 0x7b77b81b, + 0x622edbcb, 0x05023d8c, 0x220cc86e, 0xfac462c8, 0xe2d965c1, 0xeb0034c8, 0x68f67bb3, 0x24664a63, + 0xe265a6d8, 0xe13bc0c7, 0x3f7505dd, 0xabb6edda, 0x7529641d, 0x0087803b, 0xdddbc261, 0x07d83c52, + 0xa52f5208, 0x0e98aa68, 0xf0b380ce, 0x54954b84, 0x70497e81, 0x389f3c18, 0x5a4f440e, 0x5cd11a49, + 0xecf1d0f6, 0x9759983d, 0x3fab1e04, 0xb031ec2a, 0x723124a6, 0x946e6ced, 0xdc7a6cdf, 0x9a8dfc8a, + 0xc9a45d61, 0x909a7c3a, 0x737cecbc, 0x8b196353, 0x2422720e, 0x5bfc3678, 0xa6bbffa6, 0xbea8e60a, + 0x2933111b, 0x80fae375, 0x007938d9, 0x249e153d, 0x65e241e2, 0x963b469b, 0x96384076, 0xc9914aeb, + 0x7258ec92, 0x8ccf12d9, 0x0aa63def, 0x53c44d3c, 0x9fae0cdd, 0x973b6b8d, 0x97054a6a, 0x6d0777d4, + 0xcf60594d, 0x5f41668e, 0x47da7496, 0x220661a8, 0x12db7b7b, 0xe684100b, 0xe51779c3, 0x68bd1f1c, + 0xe9a3d761, 0x54d4af26, 0xcf6b9f56, 0x7365b6e9, 0x3398ca1e, 0x19021b80, 0xb524e1fa, 0xc3b3f737, + 0x083a3737, 0xd9bd5eda, 0xaf21ef4b, 0x299ae773, 0xfdd67140, 0x85a163d2, 0x315a7944, 0x85347d8c, + 0x51e76832, 0xc6d298fe, 0x704845c7, 0x533b9747, 0x8b71a68d, 0xc9273c4b, 0x08103bb5, 0xcee8d11e, + 0x326466be, 0xbe0d40d4, 0x1293278e, 0xb235bdfb, 0xa248d7c5, 0x6552b3e7, 0xa253ca2c, 0xcf052ae2, + 0xd5b5a8e8, 0x02beeefe, 0xa9aab25b, 0xad9f1bf1, 0x3164c1bc, 0x1e078fac, 0x171d01a7, 0x8d104991, + 0x7d8cfcbd, 0x4656b5a9, 0xd395837a, 0xfd8cfda3, 0x431597c0, 0xc65683b9, 0xcfe21a71, 0x6efae97f, + 0xe8bd71a7, 0x68d6ede0, 0xd161a2bf, 0xf532204c, 0xe97824bd, 0x710f55ea, 0xd98b5bbe, 0x8bb39264, + 0x25ccd46a, 0x2edb041f, 0xe7dcb951, 0x17aef528, 0x2b7372c6, 0x894a859e, 0x8be2de3c, 0xb2bb15e2, + 0x5115cd8b, 0x94ffed36, 0x2b48bfd9, 0x94650047, 0x0bcc85de, 0xe9463032, 0x535b2330, 0x90c452d8, + 0x29204fe4, 0x05f53820, 0xc748188a, 0x1229c3ea, 0x5648a140, 0xcf331866, 0x9b2833d3, 0x3ae9d4dc, + 0x42187158, 0x75529476, 0x04f4814e, 0x3c967b89, 0xd30f9abb, 0xb70fe18c, 0x2cd2b7e3, 0xe1dd4533, + 0x8135b4df, 0x51977a34, 0x03eb3d9f, 0x924223e0, 0x5e331a88, 0x4b539da0, 0x7c8e5fcc, 0xb79a5671, + 0x2d973523, 0xa159517a, 0x8753c068, 0x11aceffa, 0xc86f0572, 0x7554afe4, 0x6bed0723, 0x91a35285, + 0x3edb028e, 0x740f44d1, 0xe9b0ed3a, 0x878583c6, 0x74ba3186, 0x398929fa, 0xbd66b543, 0x8f52139b, + 0x8626f131, 0x7ddfaf34, 0x95e788f3, 0x6db23029, 0xc1bfd729, 0x2f2db2c2, 0x7ff0f194, 0x65f9b44f, + 0x90efa0fb, 0x7078b461, 0xb78a5363, 0x3a6e43a9, 0x633cbf10, 0x425c03f2, 0x2eeeb7a6, 0xac35334d, + 0xd826f019, 0x3ab35065, 0xcce0f830, 0xc0bdc6d6, 0x5ee34d72, 0x03801397, 0xfbbdd213, 0x52ff2ed3, + 0xee11e66a, 0x0dac9374, 0xcdaaf57f, 0x53c16687, 0xe2b91caf, 0x261448c9, 0x06cd2954, 0x2528d33c, + 0x7b9e636a, 0x1910d1f2, 0xc05e51fd, 0x1a1ad127, 0x29a70578, 0x0d96d7e4, 0x5012ba5d, 0x64172e61, + 0x3ada951b, 0x29f038e4, 0xce886a96, 0xd9328c12, 0x88f7a119, 0xab3392e2, 0xe7497f9d, 0x1003c2f7, + 0x296b2de9, 0x9c3428a0, 0x94295b18, 0xdb27f0a2, 0xf631a8cf, 0x1cfd6455, 0x3072bf29, 0x51e9f22c, + 0x6394420e, 0x327dd94e, 0xc6a45d41, 0x1129e544, 0x740dc54c, 0x8cae2d25, 0x0df6e81f, 0xa5b22309, + 0xb60a6562, 0x5eca60a1, 0x36cfafac, 0x54872507, 0x3630e975, 0xbfb5b152, 0x3d027f5b, 0x43c62e00, + 0xfdd8189f, 0xf6d03603, 0xacc0af55, 0x0aef0fef, 0xbec23f0e, 0x5af8b719, 0xd8e706d9, 0x9756bf8b, + 0xb7b997fd, 0x3eff0a6b, 0x8d05d9d3, 0x80cf88ad, 0x91641c5d, 0xc6645d55, 0x190e6e86, 0xdef3b5c1, + 0x044d85d9, 0xfbe72782, 0x96a1758a, 0x2ed58695, 0x48972e39, 0x325ab664, 0xb9d216d7, 0x756efc18, + 0x6dddc998, 0xc7c2067b, 0x2be91d64, 0xbb50e651, 0x06c2bc0e, 0x8e46824c, 0xb6220908, 0x2c9b9e77, + 0xa8406661, 0x650b9438, 0xb26a3e5b, 0x3de184e8, 0xde90908f, 0xcc8e1a9a, 0xafa4917b, 0x6b9faaa5, + 0x57cbc6fa, 0x13cd1e40, 0xead3fb8d, 0x02424dec, 0x602e1618, 0xcbc0d21b, 0xc8b99e2e, 0x65f86a08, + 0x16dfa537, 0x983228ca, 0xea6995ab, 0x3621e753, 0x0a5b0c86, 0x961c8fd9, 0xa982ee78, 0xcfcc6b4a, + 0x68bece6d, 0xe222610f, 0xa3abd3dd, 0xbf5f3ee4, 0x4a850b3d, 0x8ab5efb6, 0xe55ccb38, 0x29d0bb4f, + 0xe719662e, 0x3aa624a6, 0x4a756b81, 0x769abf49, 0x58483a2b, 0xbec3c703, 0x00aef412, 0xdb43dd47, + 0xc28ac9ea, 0x37114a3c, 0xfd3988db, 0x9f1994e4, 0x9cd535dc, 0xa04f009c, 0xbeb54c98, 0xd4dd6709, + 0x26bb57e2, 0x83a8b720, 0x20096e5a, 0xeeae7e17, 0x039f1306, 0xb272ffca, 0x5b2f5c93, 0x784e05d3, + 0x4bfbd495, 0xe3f18fb0, 0x3704a504, 0xa7799beb, 0x24cd146d, 0xbabe8e63, 0xcab021a6, 0x977f187c, + 0x55707ea8, 0x2f561736, 0x1d506d17, 0xdec01905, 0xf4a7f606, 0x9667c1d2, 0x1cb63bf1, 0x983cde6b, + 0x8e1f90a1, 0x73402586, 0xe101f2da, 0x4ef9475b, 0xbb917865, 0xd5504523, 0x6a111c1b, 0x5b331116, + 0x36eb6940, 0x9cdb5adc, 0x840ed049, 0x7ddb0ecd, 0xd32b0a8d, 0x6980191c, 0xbee83b76, 0xe4a72915, + 0x9037606b, 0xcea74f90, 0x89ea8e7c, 0xa070c65b, 0x7f582354, 0x458f3cc7, 0x595e1872, 0x45844c40, + 0x9c45da8e, 0xb858f3c6, 0x960ee1d7, 0x5f26974b, 0x755ed61c, 0xef062044, 0xc0c2f9ca, 0x1f5fcef9, + 0xc61b27f0, 0x21c521ff, 0x7e99ce17, 0x50cb0ce8, 0x73d1bf09, 0x198ea8b5, 0x88a4aeb8, 0x6df5dfca, + 0xe9ebdcff, 0x6388b2c5, 0x0a8d3b46, 0xf0aea0df, 0x9b7c8c5f, 0x1502b53a, 0x446598d6, 0x1def5e1c, + 0x2b618c26, 0x707ad14f, 0x998d58a4, 0x14b7d19f, 0xf9ba506e, 0xe365981f, 0xbff6330a, 0xa47f09ff, + 0x974ad767, 0x76a709cd, 0x2fde40e8, 0x99ed582e, 0xbf565441, 0xb7dd1f72, 0x0234cecb, 0xda70eb3e, + 0xba4b2163, 0xd3ad8160, 0x0198991d, 0x61f3b95c, 0xb347b584, 0x2cdf1ffb, 0x648e43fb, 0xa3076bd1, + 0xb290b001, 0xdf33470f, 0x31b95e0d, 0xb42fcee9, 0x878ae385, 0x2879bfad, 0xe494f0b5, 0xb802cbf6, + 0xd650b03e, 0xfc50c30d, 0xe21d970d, 0xa7cace2d, 0x25d95556, 0x74cca68c, 0xa1465d94, 0x61f9cdbe, + 0xe2715564, 0x461b5d19, 0x0cd59eb5, 0xb92e3bfc, 0x4795b93c, 0x8be98d6c, 0x067ca7c9, 0xffd6c669, + 0x5146c00c, 0x3dbbd26d, 0x649c36d2, 0x9ae38faa, 0x40b09e09, 0x75351a10, 0x887105db, 0x3bfffa6c, + 0x738508bb, 0xe2300c6a, 0x1f2db4f5, 0xfac81f83, 0x6deced22, 0x89f19131, 0x4918d096, 0xd5a4ebe1, + 0x87068c8f, 0x7c3eff0e, 0xda6626d3, 0x49ea87a2, 0xeb77dec7, 0x6d09d6c9, 0xfe35a17c, 0xfbbd869b, + 0xb8592b57, 0x4ef50d3d, 0x099b73a2, 0x332bec74, 0x56d572e0, 0x991504e3, 0x531f5a06, 0x14783a27, + 0xcaa83b59, 0x5857473c, 0xf20e5498, 0x566a2737, 0x088a8fd1, 0x74303dc3, 0xf0e451b6, 0x110d3ba4, + 0x4f6db17b, 0x59252eb3, 0x1ca66ef1, 0x1317c48b, 0x4d61c7b3, 0x8b5a58b5, 0xccccc651, 0x53f9265e, + 0x9c6ac290, 0x66dac3c1, 0x67336902, 0xc981f796, 0x64d53c5b, 0x03d18403, 0x94ab217c, 0x8c2e2fd8, + 0xe20de560, 0xfc4904f4, 0xba4dc38f, 0x3cc50cc5, 0x3388cf50, 0x9c6726c7, 0xbc69f70f, 0x1c9d957d, + 0x9dfe6071, 0x17cfb96d, 0x9bf1bf4e, 0xae42cb7a, 0xb0ab556b, 0x1eaaa280, 0x8f7f5100, 0xc4215204, + 0x4db047ff, 0x87e49f95, 0x0d8d752f, 0xf6252ecb, 0x80889ed9, 0x73b4b9fc, 0x490a623a, 0x98d9a694, + 0xff804c10, 0xda9b1acf, 0x0c812683, 0x7d5dd4de, 0x200305e0, 0x7831ff2a, 0xd2a5ef7e, 0xcf39cf58, + 0xa0ccc9f9, 0xc269867d, 0xfffd22ce, 0x5f7ba2ff, 0x11627cd7, 0x2e50a908, 0xd82593eb, 0xe450dd27, + 0xa6003bea, 0x69515b89, 0x3ca0b587, 0xb1a96054, 0x3950c361, 0x68106a1f, 0xf792e6c3, 0xb272326f, + 0x0cdd5cc2, 0x40da0c18, 0x68ecb1a0, 0x5f9a25d7, 0x85b922b3, 0x732b03e4, 0x94313caa, 0xd0811065, + 0xf238e899, 0xa9aee289, 0x14efccaf, 0xe5802766, 0xdef8bb31, 0xc1863df4, 0xd47880b0, 0x1d2476f1, + 0xcc610b79, 0xb9498882, 0x2ab722f1, 0x034aeb48, 0x234551a6, 0xdf76f297, 0x352f12a8, 0x46f4afde, + 0x07b6bac8, 0x5da3de4d, 0x4af81c8a, 0xb3b392f5, 0x264fcfaf, 0xfb84e127, 0x36cd84ff, 0xe5ef4e79, + 0x831f1a03, 0xa5058409, 0x0a001ef0, 0x4f4d0dc8, 0x1ce7d542, 0xc25deb2c, 0x576b1a0e, 0x4a1fceab, + 0x61e1d2e3, 0xa998123b, 0x8dc8a60f, 0x30313c14, 0x94fb9361, 0xeba97c6b, 0x986e7dbe, 0x5c0a7042, + 0x1cb51ece, 0xdce3c6ad, 0xfc433961, 0xe8620d2c, 0x8d110549, 0x574b57a9, 0xc73f0938, 0x9ac7a0a7, + 0xd552cb0d, 0x0dc2ab6b, 0x8e85ed3b, 0xbabe7a22, 0x069e8d39, 0xfefa1698, 0xf3baa86f, 0x3f18250a, + 0x5320f091, 0x4a8db9ae, 0xc43e8a2d, 0x358b8d00, 0x6320fa44, 0x9b8cc80e, 0x229f1c87, 0x1e5cf31b, + 0x1c93a07b, 0x0187afd5, 0x5389e6ec, 0xc0c53e3e, 0x051df673, 0xb174589e, 0x84d88158, 0x864bf7a0, + 0x9f4e1306, 0xc3065dab, 0x806addb1, 0x849ad09e, 0x56f7698b, 0x16e68c46, 0xfe755b8a, 0x559bf62b, + 0xdb4a739c, 0xa0437399, 0xb17285f6, 0xc61713d3, 0xd05f39ed, 0x4a6ea58a, 0x2c6ff7fa, 0xc14b12ae, + 0x600f299c, 0x0964e60c, 0xcb8b14cc, 0x8d571c46, 0x72d94710, 0x30c821f5, 0x4fba5739, 0xdcbc75b9, + 0x5b47705c, 0x6cf202e8, 0x205fc72d, 0xaf31fecb, 0x22f408e6, 0x05de4ea9, 0x58505153, 0xbdeab7e7, + 0x3e6d6d4f, 0xfc2fa261, 0xf638e506, 0x24490af7, 0x353f0e8b, 0xdefc1175, 0x5466c3b9, 0xfcb26ad8, + 0x76e25321, 0x98334459, 0x060cd23b, 0x94742d63, 0x8d78c1af, 0xe7892f38, 0x4f4d3e4d, 0xc0825796, + 0x5792c4c7, 0xc75e6627, 0x6f2286cc, 0x3ac1bc17, 0x22d5677d, 0xa07b1e63, 0xad388e2c, 0x384fbaf6, + 0x65fcfd0a, 0xe758c673, 0x14484c7e, 0xbe346a6a, 0xea0065dc, 0x5cca7af5, 0x9c686f27, 0x372c5212, + 0x76e2b16e, 0x5457b824, 0xc6aa4e47, 0xd4002248, 0x594edac2, 0x76842c3a, 0x3ee0adde, 0x53a7ebd1, + 0x4eccaba9, 0x7dd471bf, 0x27374ebc, 0xdc610f8f, 0x28e33825, 0xabd0a433, 0x857bee35, 0xdcb5e932, + 0x90c32e00, 0x11c688a3, 0xb97592bb, 0x588acd71, 0x531e1ab1, 0xe18ae8b9, 0x146c3de8, 0xe6305e55, + 0x53d01297, 0xf04ce341, 0xf149b064, 0xaddc932e, 0xcadf4534, 0x9bdb82cd, 0x1443c29c, 0x49651032, + 0x2ca0c74f, 0x48e73c60, 0x3c0bb909, 0xa345995f, 0x2473d13f, 0x0b6b7d9e, 0x83acb5d2, 0x13ac0598, + 0x5ae3fc88, 0xfba3dbbe, 0x94161536, 0x9e35021a, 0x80aad44d, 0x4ed2dd4a, 0xa5b14893, 0xa45fdfde, + 0xbf8e6022, 0xb33964c6, 0x6b2a0c86, 0x43434e99, 0x79cddb9f, 0xc47a7fee, 0x4fcf89c1, 0xc6d39fbe, + 0xa31a8964, 0x8113ffa0, 0x91113ea6, 0x88d42bfc, 0x83b68bfc, 0xd8fff329, 0xf2a681df, 0x0691f391, + 0x84f36ba7, 0x9113d8d9, 0xbb96f71c, 0x91b7faed, 0xa352d936, 0x321081ea, 0x1893d72a, 0x7a3ec8a4, + 0xf15879be, 0x1f1814b4, 0x7c77669c, 0x996bf8fe, 0x099c6994, 0xaf7e2f71, 0xe1d9e4b0, 0x3af3ad01, + 0xa1074743, 0xf53acbb7, 0x03638c11, 0x74aaf3dd, 0x91c0f5c6, 0x0c95a400, 0x8dd9dd40, 0x0034aefc, + 0x915ce99d, 0x865b990d, 0x11dd4e6d, 0x57e34d4a, 0x78aeac76, 0xa33e8539, 0x58c9a26b, 0xfb3d05aa, + 0xd2f96425, 0x0f3d1cd1, 0x2d574033, 0xa4a61909, 0x71616047, 0xa1e888be, 0xc28b9076, 0x38ce4e75, + 0x0ea2d71d, 0xbc5cbdd0, 0xa275257c, 0x14749235, 0xdca275ef, 0xf46de239, 0x74a1b977, 0x9497b0eb, + 0x6b4cfbb3, 0x7fbbb3ed, 0x63214b6c, 0x1b221eaa, 0x5a393f1c, 0x4314a3c4, 0x1b50e054, 0xc2d04f55, + 0x5689d6df, 0x8bb1f3ca, 0xff9a9f30, 0x74fe11b2, 0x96f8eb2a, 0x04a79531, 0x50347866, 0xb1150ee7, + 0xa4a16033, 0x234d68b1, 0x0d8c109a, 0xba259e1f, 0xcb90a37d, 0x8aa878f3, 0xc141b6c5, 0x64c803b7, + 0xef8ae983, 0x176247fa, 0x4b4d5122, 0x550aaae3, 0x97cba3a7, 0x8e7a42f6, 0x24a1bdbc, 0x2b71a753, + 0x0d13671b, 0xaefb7dd2, 0x176d77b4, 0x4fa98b4e, 0x122c9d41, 0xc9a2345e, 0x9410f289, 0x4cc19ecd, + 0xf2b31ab3, 0x8ce0e081, 0x6f2d7f40, 0xb89c682f, 0x8e241e7f, 0x65fa81e2, 0x804f12fc, 0x0592aa08, + 0xd29b1fc8, 0x8e9df9f1, 0xcacb2120, 0x354ae6a0, 0xa76e9578, 0x8d84a92f, 0x5ea4b79b, 0x06225324, + 0x7dca2c56, 0x1577a4dc, 0xca9ee5bc, 0xf6f33fbb, 0x755ff143, 0x3317fd8d, 0x7cbf2ad2, 0xad9aa101, + 0xcb435044, 0xde9739df, 0x26e247c2, 0x6a519c84, 0x2a8be448, 0x64ceb96f, 0x9e768cde, 0x1451c171, + 0x949f1968, 0x8398fc6d, 0xa2e57bf9, 0x792d7d6d, 0x776bef99, 0x73d364ed, 0x9150f83b, 0x107e75bc, + 0xaa12774f, 0x8872f764, 0xb6cb259c, 0x55934403, 0x131a9b75, 0x7a48851b, 0x2d336364, 0xb592f1be, + 0x0973a98f, 0x2f6b94eb, 0x86584587, 0x610a6964, 0x849f42e6, 0x7a13c729, 0x09209bcd, 0x1e2f8415, + 0xfba967a9, 0xb4271aaf, 0x9e8a7be0, 0xc8e58b11, 0xb9be530e, 0xbbd373f2, 0x1804f2a4, 0x6b155e0f, + 0x2d7e4314, 0xb74c80cb, 0x8575d5f1, 0xe0c2f0b4, 0xc076aa37, 0xb56c564f, 0xc65ffc3d, 0xd076a2e5, + 0x4c83324f, 0x340d425b, 0x11e0b087, 0xbb9afe6c, 0xa9be4511, 0x0c0b1581, 0x27eac6b2, 0xe504ba55, + 0xc03717f7, 0x452b498a, 0x8eb03ce6, 0x74aa4d45, 0xe9b0b434, 0x140a11d7, 0xe933f641, 0x17356f71, + 0xb189ecf0, 0x393784a0, 0x8e62e5aa, 0x07451c19, 0x34807ca4, 0xfa727f93, 0x9e218659, 0xa24a6c76, + 0x5a692b58, 0x82517edf, 0x2432446d, 0xddb38b5e, 0x0404be4d, 0x74b1ac44, 0x9011f71c, 0xcbf4a787, + 0x4be54212, 0x477a6656, 0xce6529d4, 0x070d1375, 0x29ef6a0d, 0xe4b1c996, 0x67bdbb67, 0x83ce542d, + 0xb2902179, 0x4b3fb94d, 0x0f4823b6, 0xb58c7593, 0x1c64fe96, 0x3dde6d8c, 0x79669c7c, 0x4be7c359, + 0xaaf02a5f, 0xa5702014, 0xc1d2bfc3, 0xcc075627, 0x3a7d3943, 0x2109de36, 0xe0ebc005, 0x07d26678, + 0x184fd3c2, 0x365b842c, 0x77945a01, 0xdc3efb93, 0x31bcc5e2, 0x8d77a1c9, 0x4a8a6325, 0x0f6470c4, + 0x4104f97c, 0x307f77a7, 0xf4efb9a4, 0x065798d9, 0x513dea9c, 0xdeee1ec2, 0x6efd3bda, 0x4d7dffe4, + 0xfd3dc3c7, 0xba7c5b31, 0x912bb54a, 0x51475c9a, 0xe3666079, 0xf5541a74, 0xb7c5457d, 0x93e0839d, + 0x692e76da, 0x14d2312f, 0xc324da61, 0xc629ae78, 0xc9ff3007, 0x16d50f7d, 0x142d7f88, 0xf138a04f, + 0xaedf11e4, 0x0533e74a, 0x8e738909, 0x32bbb3e0, 0xc1eb20cb, 0xb54cd030, 0x6ae58e80, 0x3cd1731d, + 0x2ba7016c, 0x5ca1c743, 0x80cd42de, 0x4ed66717, 0x5a80e324, 0x32beee5b, 0xbb4bd00b, 0xe1d315f2, + 0x8e85a52d, 0x45f187c4, 0x4ded6b4c, 0x4b16fb3b, 0x57adf3cf, 0xb298dc8c, 0xa610991d, 0x447788b3, + 0xfdce43d3, 0x8ce6e63a, 0xed16e993, 0xf4b834fe, 0x1576e11b, 0x7c46fbd0, 0x59a18fef, 0xa19b96cb, + 0x1684b817, 0x7cde6405, 0x219b78d9, 0x20698b32, 0x96314aa4, 0xdc4cc86d, 0x7b9ea7ba, 0x1aac40c1, + 0xa9a48319, 0x834fa3a2, 0x76c1cdc3, 0x6c815cf8, 0x6b55d662, 0xd14e214d, 0x64224103, 0x399b9510, + 0x65a11c34, 0x2326ba9c, 0x56deab46, 0x9770b636, 0xf867d1ed, 0x7363b561, 0xfa11bbd6, 0xd406ea94, + 0x57e4a175, 0x237490b2, 0xbfb51615, 0xfa118a55, 0x421fff8d, 0x0799dfca, 0x39c78f11, 0x9ecf516d, + 0xe10b907a, 0xc060eac2, 0xfa65140f, 0x0f1e5f0f, 0xfc8ac8f1, 0x9b13f8fc, 0x6b4d9910, 0xa1fc1bb3, + 0xf4435141, 0x49ab34d8, 0x38a54465, 0x48483069, 0xb325bd9a, 0xebc89fa6, 0x66f3c645, 0xc5828675, + 0xec62f030, 0x654ff426, 0x39fe473f, 0xe2ce372b, 0x3e882242, 0x75941b52, 0xc7a65452, 0x7413bfe1, + 0x7b4742d6, 0xe96790d3, 0x74f0e143, 0x32e20c27, 0xd697af2d, 0x32dfbaf7, 0x7447b2eb, 0x4791df8e, + 0x7e52a620, 0xc568e57c, 0x15f6e8c0, 0x3c69c9c3, 0xeaff138b, 0x34ca7709, 0x411adba1, 0xfe19e69f, + 0x92cc49cc, 0xc43f77b9, 0x380085c7, 0x0c6384fe, 0xb95f54df, 0x69796410, 0x920264f4, 0xb2b89eb7, + 0xbd2597d7, 0xbe021ee0, 0xbac53cd0, 0xf273c4b5, 0x0526eb3e, 0x7b426d4c, 0xec23266a, 0x0f343d8d, + 0x56de06da, 0x1c72e51a, 0x845cc24a, 0x0beff191, 0x6adb01d0, 0x89c19706, 0xfca2bf7c, 0xa30aed7c, + 0xc32c2244, 0x050099e0, 0x263f20d1, 0xbce3d652, 0xffe9d4da, 0xead20bc7, 0x393b686b, 0xdbeabe31, + 0xb090133c, 0xd72e8434, 0x5bda618c, 0xab2caa01, 0xc071d523, 0xa2f55ad2, 0xb180e79a, 0xf32f9c17, + 0x5afea82d, 0xf06600bb, 0x8a61f0ef, 0x05b31241, 0xb49d941a, 0xdb2bf538, 0x4bb62e75, 0xbc192551, + 0x641545f2, 0xfded33b8, 0x5b1f98a0, 0xbeca0a3a, 0xdafe726b, 0x6c8acdd6, 0x203d0110, 0x90c4f9d9, + 0xba6e423f, 0x8826d283, 0x5f1719af, 0xf7350d63, 0x24654389, 0xb9967b52, 0x83d70e7d, 0x75543d02, + 0x3db17c5b, 0xd47efd76, 0xa55a0e45, 0x4182cf53, 0x1cbd4fc6, 0xa7653a58, 0x6c21d71e, 0x603e7d7c, + 0x6e2c8b68, 0xfe5ba165, 0x88d5ebb0, 0xdca587d5, 0x8971bca5, 0x8d81ddc9, 0xb9c41839, 0x2f5d9b0a, + 0xaec5e51f, 0x7b90eb5c, 0x3376480f, 0x32eca23a, 0x296199b0, 0xea7e1300, 0xd10d3894, 0xe171bbcf, + 0xa7ef047c, 0x82e49d09, 0x430702a7, 0x5e4d2a64, 0x7b8712de, 0xef3348b2, 0xc16693cb, 0x18f3d244, + 0xa7a1996f, 0xab37416c, 0xffa76b95, 0xcb1c8590, 0xab0b61e7, 0x2af8aa2b, 0xb266bfa7, 0x313316e3, + 0x49722492, 0xb9dd113b, 0x975c6bf7, 0xe2b841c9, 0xbff44a85, 0xcb6651c0, 0x8f927ba0, 0x28c3d49e, + 0xd1326534, 0x3e0a1add, 0x1ad1f6b5, 0xce5d6c1f, 0x9373e699, 0xe8204ca0, 0x5bfd4a66, 0x31200d19, + 0x43a3d634, 0xa507c063, 0x9a3f6951, 0x0f9ef973, 0xdb7a2020, 0xe39fdea6, 0x665bad02, 0xb04f9536, + 0xfcdae8c1, 0x70e5e88f, 0x2bf0a68f, 0xdc56e29b, 0xc97dff92, 0xc8bdb2ad, 0x2c891b70, 0x146d3b2c, + 0x5766ade5, 0x9060e14f, 0x5778662d, 0x58a156f9, 0x91301db4, 0x39ad76bb, 0x02343ca4, 0x4e4f0bcf, + 0xa5f867ff, 0xdb9a5ba6, 0x2ffb677a, 0xcf91f613, 0x008b2e76, 0xeb911be6, 0xd056d42e, 0x4940e732, + 0x3954ff03, 0x95235d10, 0x16902936, 0x4c5c6a08, 0x99c88346, 0x8b3a288e, 0x6d2bb8f3, 0x31bf7c6d, + 0x60509dd3, 0xe1f6aabf, 0xb0b31a27, 0xaede4514, 0x95a61b77, 0xc1e4065f, 0x27d893da, 0x44405f45, + 0xea321fcb, 0x13c8eee9, 0x85dfe2f8, 0x6a150fd5, 0x9b4ef01d, 0x6a763d35, 0x3943df1d, 0x5397454a, + 0xc9b5a13a, 0x552357d4, 0x78112c43, 0xf3207c67, 0x9de34d9f, 0x683d2fc2, 0xb1b7c72a, 0xdd937626, + 0xfe9255e7, 0x21132c2e, 0x954d5a4a, 0x16e5e6d8, 0xa81443d9, 0x78992cd0, 0x5b25c7da, 0x864daad7, + 0xfaaa88ae, 0xf7b009c1, 0xdcedc09c, 0x1066bffe, 0x95f544f1, 0x6ecdcb67, 0xbbf08fda, 0x1ade10fa, + 0x62af6cb3, 0xabdb68e7, 0xb3b0e0ab, 0xf47014ef, 0xfd6ace58, 0x7ae57acf, 0xecee956e, 0x183d1067, + 0xdfd1d1c6, 0x9450178e, 0x03c43ee6, 0x3e0621be, 0x94acc4ac, 0x10c8d0f1, 0x44b61d02, 0xced60a27, + 0xabfecabf, 0xec8ff36e, 0xa82f8b39, 0x3e25e103, 0x1b534951, 0x748abf1c, 0x2b6a0b24, 0xeea4ed38, + 0x9913ca83, 0x5781b717, 0x205c89a6, 0x2c265892, 0x9fe26157, 0xcee9a895, 0xef703e71, 0xf6a58c5f, + 0x37f37aaa, 0x3bf970a7, 0x3a5d6fe9, 0x6f99179c, 0xc32851eb, 0xf78b05e2, 0xd02c14c5, 0xb58f27ca, + 0xee1f4418, 0xda2d5cc4, 0x0939e4e0, 0xa287bcdc, 0xf9443471, 0x5f3108f8, 0xe2e0b55c, 0xbfe35147, + 0x41fece62, 0x2c3550ea, 0xe7917398, 0x64cc368e, 0xba2646b9, 0x8c7a0318, 0xad989e9f, 0x65482f7c, + 0xd600c55c, 0x8c8b4b96, 0xfcae28e5, 0x7f91590b, 0xd80818a5, 0xe7dde9c3, 0x32bda512, 0x0724f344, + 0xbcb6b4d2, 0x07ec1b3e, 0xe9127652, 0x87906330, 0x90ca0901, 0x9e794663, 0xecda4063, 0x4f3c615e, + 0x8c3d1553, 0x9536e091, 0x27f6b3f0, 0xad0cfa5a, 0xa6ee2cff, 0x3dc86de8, 0x5bee2390, 0x5bb0ac2d, + 0xd4d7389b, 0x62cfd45b, 0x0f480e36, 0x65887c8b, 0x61d1bc58, 0x8a568dbd, 0x03ebb4e3, 0xcbc03381, + 0x71750ff3, 0x8b232b86, 0xad7d6105, 0x250170ba, 0x905e8dda, 0x7dd5cf15, 0xe21f34a7, 0xfc7332bb, + 0x98aa7898, 0x7b105575, 0xd42c5ba5, 0x0659a6a9, 0x1dd2d4a0, 0x327d0e0b, 0xee472cb0, 0xddd15781, + 0x5e365ae5, 0x6d692079, 0x7996669c, 0xfadd39ff, 0x4f60d4f3, 0xcf8ba304, 0x843552a2, 0x56835804, + 0x1da22f3d, 0xbde1988d, 0xdde9acb2, 0x984ee523, 0x95c333d1, 0x0d8aad64, 0xb60e8857, 0x1203591e, + 0xc654b0f4, 0xb3c61edb, 0x34380acf, 0x1c7f42cc, 0x5b73a780, 0x3086017e, 0xa0f0cb25, 0xc4c7ab26, + 0x34961122, 0x41b7b3e3, 0x111e8141, 0xa2006aef, 0xe09f29ac, 0x7d0d6d90, 0xd928b95b, 0x9b36ef99, + 0xce837820, 0x990ea4dc, 0x04b4a83e, 0xed7a88a8, 0x159c901b, 0x6ca12b76, 0xca9e521a, 0x3de6ed99, + 0x7bdccb3b, 0x1bb77977, 0x804974be, 0xadf7537b, 0x3d0b297b, 0x4ce960f0, 0xe3860943, 0xf1f3f4e7, + 0x58ffad60, 0x92b0be9b, 0x35f5c369, 0xb4c1ec3d, 0xff1c0315, 0xf6c40009, 0x0b2cf6bd, 0x401dd9b2, + 0x267eff83, 0xdf9fc68a, 0xc091e597, 0x87b3cad8, 0x35a40acb, 0x9c3e8a73, 0x5d1db62d, 0x2dbefaa4, + 0xe643956f, 0x5a6f0a4e, 0x28e4a0e6, 0x96439f50, 0xadd45c15, 0x7214b9d6, 0x2260db9f, 0x9f76062a, + 0x9c7c7cab, 0x0392f69c, 0xdfaf7b6f, 0x7ef834ec, 0x0a23e59a, 0xa3cc1875, 0xe8ba40dd, 0xfbceeb6b, + 0x68fd2cdb, 0x5b325dc5, 0x5c5df314, 0x6d48191d, 0x2a04c3af, 0x31322dad, 0xbbcaa431, 0x5aeb4af7, + 0xdfeceee9, 0xeff255fc, 0xfc97bd59, 0x8575215c, 0x3f77c9d7, 0xcbf3eb42, 0xe59efdbb, 0x3e0ede30, + 0x08123223, 0x346bc373, 0xc740a4ec, 0xe186cf46, 0xfc7554bf, 0x341d0996, 0xf22fd6c3, 0x5ea34ad0, + 0xca8d7068, 0x844e2ab6, 0xf737925a, 0xedd0de59, 0xd6cf3824, 0xa43f9aef, 0xcc9bf9ca, 0x21cf67fc, + 0xfc618fad, 0x3aba6a92, 0x5ed838a3, 0xd3c92112, 0x01b2d1a3, 0x2895eb06, 0x19026be2, 0x106a090e, + 0xcf1ebd90, 0xe80485d3, 0x89a067fa, 0x2b578f0f, 0xde28c5ad, 0x0772b060, 0xc328f323, 0xfd1119a3, + 0x5dbcde7b, 0xf985b367, 0xe854333c, 0x98fd9454, 0x759e019f, 0xaa4c36e0, 0x60522c2e, 0x21f6ac01, + 0x84d0e4eb, 0x64201905, 0x55d04812, 0x8179aadf, 0x052741f5, 0xfee75a6e, 0x788b005f, 0x1705dde7, + 0x2e43d2db, 0x9423f4a8, 0x9529ea71, 0xad9ff77b, 0x93eaa219, 0xc8098c3e, 0x849ef43f, 0x74a408cf, + 0x24996054, 0xe5fd7518, 0x10ff50ee, 0x99502cb8, 0x42f08ebe, 0xaefbb9fd, 0xd5502bf1, 0x17011e5c, + 0x19490a6e, 0xbfcc1617, 0x967882fc, 0x7dabc6ac, 0x4d43af6d, 0x7d35eb74, 0x57fc672e, 0xc42f4215, + 0x5dec239d, 0x0b8c66a8, 0xe1c9084f, 0x7638acf8, 0xd8339218, 0x4e3832ff, 0x7f0b5517, 0xd8463abd, + 0xbcdee1ae, 0x58044907, 0xb1191896, 0x9253f687, 0x8ae80a55, 0x1f0a4d00, 0x89fb5583, 0xfc2d0242, + 0xe9f95f7e, 0xdcd27423, 0x77524c1e, 0xfb80aa91, 0x1cc95380, 0xcb1fa465, 0x071ae0e6, 0xc3c8d053, + 0x420a82f3, 0x5b5ac21a, 0xf77d1d1c, 0xb6dd3a1d, 0x59466a1d, 0x6cc8ba1a, 0xaa8593e0, 0x3678e185, + 0x459da03a, 0xc8108d53, 0x4d8bf6e8, 0xadbb18b5, 0xe4b5b90c, 0x5d07d1ad, 0x0abddd9a, 0xbb0cff69, + 0xb3d4cf08, 0xd3612384, 0x0c3afd9e, 0x0d0e4d39, 0xb78587d6, 0x8a4e1ca2, 0x84d21649, 0x573345ac, + 0xb67c5819, 0x928a1863, 0xaadf3d46, 0xc7d9ba22, 0xea4d7fdf, 0x1624307b, 0x00986db1, 0xeed8dbb8, + 0xc2222ef2, 0x5a046246, 0xc7b3eabd, 0xff5647c5, 0x7a47aea7, 0x14910d58, 0x04190102, 0x6bcf7e76, + 0x54a3bc82, 0x5706694c, 0x4664f6db, 0x3f1e3487, 0x611488b8, 0xf7aaa276, 0x356cd750, 0x1d7e249f, + 0xb29671f3, 0x34a50204, 0xba821762, 0x755bbc64, 0x904cdafa, 0x48dd953f, 0x7b032c92, 0x0e0bf1f6, + 0x7144be72, 0xb2281608, 0xf9782f11, 0xe4f28e99, 0x877621d1, 0xce8f27be, 0x5a559021, 0x9b1740dd, + 0xcaaa8c5c, 0x914ce8c4, 0xa200f85e, 0x819f2012, 0x474f36fa, 0x3c8fcd36, 0xe9952168, 0xdc81cac7, + 0x57204da7, 0x08bdf73d, 0x5a4a4a77, 0x007fe3dd, 0x0dea2923, 0x1dc37f2f, 0x44ab21ff, 0xb58b5c72, + 0x12f88874, 0xfa407115, 0x002820a5, 0x2df85b8d, 0x45e2fcd9, 0x9c0120d1, 0xc539c34e, 0x9c393022, + 0x27340845, 0x6ebfc65d, 0x0cb3a6e5, 0x6f732a87, 0x1cf1fcf9, 0x52b26db3, 0x8c5c8424, 0xd3e58ec3, + 0xd99e6ac7, 0x0b028a17, 0x33c8f957, 0x782c4957, 0x4fdadc92, 0x571b9295, 0xb88e25fd, 0xe9a63a98, + 0x3635a87c, 0xcee78062, 0xf6e1b0e1, 0xff4b0dc4, 0x5a7417f1, 0x429e3665, 0x1a3ac88a, 0x2abd32d8, + 0xf5d7d878, 0xad4b8ebc, 0xe2eb1ab2, 0x65c683fa, 0x0b5196f7, 0xb171b294, 0x6e2fb5ba, 0xd75ee248, + 0x44c82fe0, 0x69ceb2f5, 0x31fd6a13, 0x44e59d31, 0xfb29627b, 0x4dfde733, 0x7dc2b374, 0x0f89afc8, + 0x6a728754, 0x156fce7a, 0xbbbbbcf2, 0x03d0125a, 0x0a618c3e, 0x384ad656, 0x9d824935, 0xec915f03, + 0xe0676c8e, 0xdfb9bb87, 0x367679a4, 0x133d14dc, 0x37aa4df6, 0xd489651c, 0x4064fbb5, 0x66ad961a, + 0xab021723, 0xf90f66c1, 0xe582aa74, 0x367a62cf, 0x3f2bfb64, 0x2cc3e242, 0x3510fb59, 0xdbe24543, + 0x523963ca, 0x5324f293, 0x5cdb591f, 0x9978f38b, 0xfb0dae7b, 0x9dac987d, 0x27ad85b3, 0xa1fb6748, + 0xf36ee237, 0x29cca571, 0x808b522a, 0xec5d9c96, 0x6b2d15fe, 0xa26e0569, 0xb2a657a3, 0x6718f734, + 0xcadaf946, 0xfd67647c, 0x97eedd17, 0x05dfbd2b, 0x95632786, 0x25109814, 0x2cdb98d3, 0xa158d1e2, + 0x628675d3, 0x6b1d569f, 0xd2aa3c98, 0x828aebc4, 0x3c986c27, 0x571c5def, 0x033474e1, 0xf6e0990b, + 0xd1fe22fd, 0xe5b1fe40, 0xab4ab524, 0x531475e8, 0xead9bd0e, 0x912ad957, 0x1d6285e9, 0x2e9155b4, + 0x61a39429, 0x8144cd67, 0xd2f6c54b, 0x0bd39f54, 0x2ed3c047, 0x6669406d, 0xfa690caa, 0x31c4deab, + 0xa9d37d2b, 0x913b118a, 0x9880ce88, 0x83cedc27, 0x968d229c, 0x8d3c9334, 0xe5c6c529, 0x20e898db, + 0x011fb68d, 0x5dfcf22f, 0x9e3f42ea, 0x8c39f8ad, 0xaa01c4c1, 0xe9534452, 0x0d748033, 0xecc5393a, + 0x25b6e154, 0x6f6bcbc9, 0xfaf77ff0, 0x54609fb2, 0x7f4bfd0f, 0xcea7e8b5, 0x98f8be3b, 0xf35661c3, + 0x0a7a3c67, 0x5ea608aa, 0xe2724654, 0xc2875b5f, 0x61823832, 0x7de97631, 0xb1590811, 0x3c3df57b, + 0xb9ecfabd, 0xc130e7fc, 0xd37513d7, 0xe9782a3d, 0x9cb4154a, 0x393dfbfa, 0xc06f4881, 0x61ac70c8, + 0x5d2efdf7, 0x0f4e0041, 0x40ebb724, 0xb20cdbc0, 0xb3644a69, 0x75708f27, 0xdf522d37, 0x83b4adda, + 0x69c800e0, 0x5d310e80, 0x9b0b9538, 0x3a5eb98c, 0x77caf795, 0x6de37057, 0xb355d01b, 0x014e1dad, + 0xe9811969, 0xc08a7628, 0xe5e44555, 0xb3fc343d, 0x88a8612b, 0x340cc79f, 0x1b6b575d, 0x79fa7ef0, + 0x491353f8, 0x7350e6f9, 0xdee5a45a, 0xe43bdae9, 0xd70c56ae, 0xed403e86, 0x6c5a5354, 0x9e1651fa, + 0x2f236125, 0x0390f807, 0x0d2a075b, 0x514a3483, 0x9936c16d, 0x80082d96, 0xb5a06d54, 0x1612537d, + 0x962125e1, 0x45eb1ca2, 0xdb15fb61, 0xad005ccc, 0x1548d2a0, 0x25800e08, 0xf2fac0cc, 0x737aeb61, + 0xd892448c, 0x07c28d17, 0xf318aa6f, 0xc58e3a39, 0xf4dd4dbe, 0x9411e49e, 0x210fcbf2, 0xaa36609d, + 0xb4d95c02, 0x6a8f19d5, 0xe370d49c, 0xa3c84de1, 0x735de824, 0x32fffa12, 0x4f3a3121, 0xbc13ab9b, + 0x1a9218aa, 0xae8daec3, 0x955e5062, 0x79bee83b, 0x1094c531, 0x3d773876, 0x303c850d, 0x76bf9c52, + 0x0c2f32bc, 0xc88dbf23, 0x5c804946, 0x520d89a0, 0x36d430af, 0xf60e1cce, 0xb3150eba, 0x0643f587, + 0x6a6777dd, 0xa7029cb3, 0x99941fe3, 0x87c07ba1, 0x46e5cf71, 0x65bacf09, 0x559bdfe6, 0x8bdd8ad3, + 0x59ebc41f, 0x7e55932d, 0xcf78bead, 0x0cd4e489, 0xb90ad2b7, 0x58eac751, 0x1b56d7a2, 0xc2487093, + 0xc0aa7a64, 0xa905e9d8, 0xa7c43a2e, 0x25ea0b58, 0x85a3f54f, 0x10c6d4b3, 0x2b0b1e1c, 0x95ac942f, + 0x6fec080a, 0xc51790a2, 0x8461bba0, 0x31efaaf4, 0x1d371322, 0xc99944ec, 0x5289e5ff, 0xd64dd767, + 0xb6938070, 0x0794ef6e, 0x46b0a40c, 0x8a563291, 0xbe0f799a, 0xb2d7ff2e, 0x4cf9307b, 0x1b6533fa, + 0x62db2987, 0xe2116167, 0x2d809c35, 0x6bc74ba2, 0x6da8bfd8, 0xf30e9390, 0x28415cf6, 0xe854ce92, + 0x02465a49, 0x4fa98d16, 0x4ab1d89a, 0x50870f57, 0x57c283be, 0x5e1e0fc2, 0x247602a9, 0xe4786f47, + 0x7969635e, 0x3672c88b, 0xacf55cb5, 0xe3133e77, 0xe92b50a1, 0x0b380d50, 0xe36d4b33, 0x49e7cc83, + 0x408694a5, 0x0825b231, 0xee6a1e95, 0x4f4432b9, 0x878cf78d, 0x7309e88d, 0x7794bfc0, 0x55beb95b, + 0x24ed6723, 0x0c24fa00, 0xaf487dce, 0x89d43c1b, 0x27b69a90, 0xe3495260, 0x6e360f86, 0x98fee59a, + 0x7db55eaf, 0x0fa8aabb, 0x0e942194, 0xa047bf88, 0xa3460058, 0x6dccd3d4, 0x3add5264, 0xa74e5d1f, + 0x0a4be925, 0xeb497cfd, 0x257c3ec5, 0xe721cf98, 0x0604b27f, 0xa14973e9, 0x3de5257e, 0x0c7e9080, + 0xd63050bf, 0x09286198, 0xb48d32f1, 0xa97c74e7, 0x9c79ff0a, 0x0350d608, 0x54e77f30, 0x866c2575, + 0x0e2b4912, 0xc01c478e, 0xc05e5859, 0x3dd37eef, 0x0eebdab0, 0x5d19cf3f, 0x3bf7c1bd, 0x5762abb7, + 0x5c74f6c3, 0x769d60d4, 0xad2e158a, 0x15e3c181, 0x72e29acc, 0xfe82e2fb, 0x55ca03ea, 0xa9a36bdc, + 0xeda78987, 0x0b5a2b00, 0x848a6ea0, 0x6cd57698, 0x60dfd963, 0x16815f1a, 0xe421dcb9, 0x821e15f6, + 0x16965efa, 0x388eea84, 0x86f8a6d7, 0x008703f0, 0x3a0b64d4, 0x3a79ee37, 0xf82ab4f5, 0xff872ded, + 0x5b171723, 0x7f5da1fe, 0xfe29717d, 0xf2be0340, 0x82368aee, 0xb96c073c, 0x18e22af2, 0xf3a16603, + 0xe66188ab, 0x4d2b635b, 0xc0541ac2, 0x98fbe020, 0xe6fc9ca9, 0x71c4a0eb, 0xdb890815, 0x6bb37762, + 0x4b0b34aa, 0xdc175fc2, 0x55136b6a, 0xb7a2fc52, 0xec32d768, 0x3856fb22, 0x6ae787ee, 0xd291b7ae, + 0xa4261b5a, 0x96dda5d1, 0x31c6e7db, 0x3d18abc7, 0x7ffb2b20, 0xba1bc2e9, 0x4d654cc6, 0xdf503664, + 0x1706b911, 0x688e901f, 0x3693469f, 0xb3b7d82c, 0xb32952bf, 0xa31e8408, 0xac80b477, 0x7e7ddefc, + 0x9256f1d4, 0xd2e2236e, 0x1c4c2ba6, 0x3d0b8377, 0x1b31de69, 0xf2430e45, 0x22eb7378, 0x08773858, + 0x735cf2d0, 0x2435e1f7, 0x0098062d, 0xe259fb20, 0x98bb7dc7, 0x4fe8666f, 0x4325c6e2, 0x65c5fac3, + 0x54c12c8b, 0xa717c9fc, 0xbbee623d, 0x3f6982c1, 0xf539e965, 0x3bfc4321, 0x65557815, 0xcf4ea217, + 0xf4a5c703, 0x7bb51dc2, 0x1a3ccedc, 0x10f1fed3, 0x9564b6b0, 0x86d54614, 0x4e832bb9, 0x9e08a2ef, + 0x7b9de18a, 0xe3f94f98, 0xdeb2a16d, 0x865053e9, 0xc77e57a2, 0x08b2d22f, 0x6b14339c, 0x8a03536c, + 0x804275c8, 0x6ff502be, 0xfd9a90ba, 0xd6ddb0bc, 0x52973d1b, 0xe0013b33, 0xf9bff65b, 0x5485e22c, + 0xf65056f7, 0x18393ab3, 0xbf8c8b96, 0xad0a9fb8, 0x903c1b86, 0x8a112f64, 0x2b92f97f, 0xe9ddf040, + 0xb6789340, 0x2de6f4ef, 0x3ad7178b, 0x3e7dc30b, 0x35bdf632, 0x7301086b, 0x692ebcf5, 0x30d7dc52, + 0x64dfd466, 0x7105f6ef, 0x48397638, 0x45ff134b, 0x948a44d7, 0x9685fd96, 0xc354066f, 0x9cdbc452, + 0xc3f9623f, 0x26a22395, 0x74d6d6ca, 0x55f4c68f, 0x3458b963, 0x0f00da6e, 0x328dfdbe, 0x7d168a67, + 0x2621e1be, 0xac2b2fc8, 0x465f34a1, 0xbf3c8330, 0x647c462f, 0x8126d698, 0xa9a706fa, 0x5fd2e5d7, + 0x18e53ac9, 0x3a7ec000, 0x6941b0f2, 0x88b9ab30, 0x083d89bc, 0xa651ba4b, 0x1576e953, 0xb8a419af, + 0xf58ddd4e, 0x645f51ff, 0xa148ea0b, 0x98e77fbe, 0xab02a875, 0xdd39e005, 0x85552e1c, 0xcf833d62, + 0x3fb91263, 0x598d45e5, 0xf9a86b5c, 0xb64f0d5b, 0x7538186f, 0xd2522fc2, 0x181c3f14, 0x33358f47, + 0xca097d3e, 0xa90c478f, 0xd0aed5aa, 0x371adbac, 0x40ce1367, 0x426b236c, 0x89fe452a, 0xa8a88f38, + 0x7f1f44d3, 0xfcb6a688, 0xadbe573a, 0x05bfe39c, 0xdb0e18d4, 0x3eb0b20b, 0x3fdb061b, 0x2845d7c0, + 0xb359905f, 0x790681e1, 0x3e33a6ce, 0x1c9d84be, 0x2174b7dc, 0xcf87ebd6, 0x2df6918b, 0x9bbe6815, + 0x29df3655, 0xe2c1565e, 0x62b203f3, 0x510f5c84, 0x61679298, 0x4b823e48, 0x581b2420, 0x4ff2d70c, + 0xddf40ce5, 0x1611807f, 0x6c7d6f66, 0x0ab328eb, 0x22f4016c, 0xca6f0f1c, 0x476626bc, 0xad5c9d4c, + 0x2eb80f72, 0xd42b5ff1, 0xf0f19ea6, 0x9fe66acc, 0x7ec78441, 0xf465f4d4, 0x79a9c60b, 0x766880ca, + 0x7e122048, 0xfc9c311c, 0x9d1bd74c, 0x84aa1a87, 0x2b870d0b, 0x57fc595f, 0x601343be, 0x3158051c, + 0x2ca2d76f, 0x9f72b900, 0x6481d2b2, 0x7d695f7e, 0x1c00580d, 0xc9ad4b93, 0x76852afc, 0x6c10130f, + 0x89eac33c, 0x7d686990, 0x80060802, 0x70dea993, 0xe1fd36c8, 0xe1cb6b9f, 0xf786df9e, 0xb3475cae, + 0x4eb31945, 0xf2c5d93b, 0xb1d54492, 0x126542ab, 0x56508594, 0x6efb515f, 0x3252839a, 0x8a040f25, + 0x793fdc45, 0x519a1c15, 0xe31ee96d, 0xd3302ce5, 0x11db7990, 0x68461430, 0xa876f7db, 0x4256248f, + 0x7cd8fd92, 0x4c16b9ad, 0x749c5375, 0x851c73ee, 0xfa134f37, 0xe2967469, 0xda5dd915, 0x7760f86d, + 0x610b2421, 0x5adc488e, 0xb77550b9, 0x59b95ef8, 0xf38868df, 0xd036e501, 0x0cb814a8, 0x06b9ab5d, + 0x49fec781, 0xfa40384b, 0x533be651, 0xb0e4a064, 0xc1c1afa8, 0xbdc16574, 0x9284b162, 0x2cd5b7ab, + 0x52882ba1, 0xc779300c, 0x25450000, 0xa805b3ec, 0x0e89159e, 0x2b24bcde, 0x634827a6, 0x6ba484fe, + 0xe418533e, 0xcc64d282, 0xf185de71, 0x83fe042c, 0x9df00287, 0x2ab8233a, 0x9243767c, 0x1c6432db, + 0xf0393696, 0xa4f31d42, 0x9d599e1c, 0x6e4d31c8, 0x85830cd1, 0x5f2446d9, 0xac739059, 0x5868d669, + 0xdd4c9f22, 0xf0163343, 0xd2411112, 0x925bfe3a, 0xf8366b70, 0x0f50e2fe, 0x6455e113, 0xfcd9f124, + 0x7143f3bb, 0x540b1347, 0x5b007982, 0xd6d1360e, 0x64a10f13, 0xa8e2ebe5, 0x7374aead, 0xc8eb7e59, + 0xb2874627, 0x7f0c9a4a, 0xf8106eae, 0x79d91558, 0xcc35a3ad, 0xd0af03b1, 0xf2393d2b, 0xc1dd105a, + 0xdd73755e, 0xfec0b662, 0xe8bb98e1, 0x19a1f334, 0x5ab6406f, 0xbb1f4076, 0xc364bf19, 0xb1afa470, + 0xb27fbb42, 0x9da2b23a, 0xc993c8e9, 0x0a5c8ada, 0x2822b6db, 0x3539b2d2, 0x11bd2dc7, 0xaae15f47, + 0x54be4706, 0x5fbac156, 0x307381d3, 0xc4991868, 0x581d8460, 0xf4d54a36, 0x15aa0461, 0x1bc775e8, + 0xb3f0c76c, 0x7ada6492, 0xd3b3f14e, 0x5eeb7f3c, 0x9d571222, 0x8d286b11, 0x9af26617, 0x68377d59, + 0x99282b08, 0xb66fe8e5, 0x3b5b7d35, 0x98473fce, 0x619570f9, 0x62b28fae, 0xd5814430, 0x7df31c74, + 0x2b3dd219, 0x710ce639, 0x676e0df4, 0x295d8f18, 0x17d8c6ad, 0x4acdf51b, 0xfb55e78f, 0xa13d7268, + 0x90689424, 0x01b3b7bc, 0x18294267, 0xe2a2c733, 0x68ef19af, 0xe3c51209, 0x7c9db2e6, 0x31f5cc69, + 0x362b4809, 0xec92588b, 0xdcd60935, 0x43760e68, 0x58f0ca7a, 0x51d4db10, 0x02bff479, 0xb78f0f19, + 0x32a14d01, 0xf4f6fec4, 0xada9360c, 0x7aacb7aa, 0x978b18a2, 0x3f2bae8d, 0xb7394ff0, 0x0ff7c705, + 0x2fdab3ad, 0x74b9fe7b, 0xb862f514, 0x59f03bcd, 0x30f6542c, 0x11a9df5f, 0x51a11235, 0x58d3d8cd, + 0xd8b389bd, 0x6a389331, 0x4b20a4a3, 0xbb746c76, 0x30c3f0e7, 0x86428407, 0x45d6c023, 0xc77ebdeb, + 0xeabefca3, 0x60250546, 0xe8476f57, 0xe9fd3f0b, 0xbd21df0b, 0xa9a5c6e5, 0xf8198b68, 0x881246e7, + 0x00052c27, 0x64d3e8a5, 0xf2680866, 0x35bfb7de, 0x9d0f8ac7, 0xbcf2ebe5, 0xb144005e, 0x9e82681e, + 0x2053b274, 0x66da2f7c, 0xd0393e7a, 0x53f83cfe, 0xe90804fe, 0xf5fd44f5, 0xf127c10a, 0xc70afa8e, + 0xaf15c55e, 0x7c6dfbda, 0x80e0a920, 0x7b169698, 0xf8066cda, 0x1cf2a510, 0xef70f7ef, 0x000bc34e, + 0x2d42e033, 0x17cf50f4, 0x6ab4c571, 0x5134bffe, 0xc47320b9, 0x3a32271d, 0xf183f54c, 0xc5e1e43c, + 0x0d1c971e, 0xe7795114, 0x6ca29ccb, 0x9c446bd7, 0x3779f259, 0x5db53656, 0x6d105a7f, 0x31479f68, + 0xb31d23cd, 0x8102d36d, 0x51aeed2d, 0x482bd4b7, 0x093ed959, 0xd6e0bb40, 0x3f9177cd, 0x1453f24f, + 0x6fabfe89, 0x613efc72, 0x0910c552, 0xbe379d14, 0x78af4f98, 0x49d711ac, 0xc0fb4b1d, 0x20db2cad, + 0x9a1b5401, 0x650f5035, 0x2ecd6e62, 0x5e107f7d, 0x91434da6, 0x63dd552c, 0x7e5a1cbf, 0xb202afe5, + 0xeff1d62e, 0x684463d1, 0x8974e066, 0x27fd6fa0, 0x79febebc, 0x72be4703, 0xbd3d8fa0, 0xe798d010, + 0xac6bd206, 0xa1d27bdf, 0x265ee01c, 0x70759e0c, 0x2728d64f, 0xe6d41d13, 0x1d09c684, 0xa956eb79, + 0x38d9b259, 0xfdcc0187, 0x38341c48, 0x1d8a58b0, 0xa19cf231, 0x8da941d0, 0x103e013c, 0x015c3f4c, + 0x60e5b7e9, 0xfcc13a66, 0xcaaf7feb, 0x945951cb, 0x9013a1d2, 0x3493cc53, 0xc2e7a8ed, 0x3f1b09ec, + 0x723065f1, 0x0b12f08d, 0x9351d18b, 0x4bde8627, 0xfd5a4815, 0x178df664, 0xcc70d5a2, 0x94ffae9b, + 0xac794782, 0x002064e9, 0x89b09c07, 0xa2675e5c, 0xd688b577, 0x616d96a5, 0x4c8f372e, 0x29380589, + 0x344f1195, 0xa7181920, 0xd05fcfd2, 0xf8b0493b, 0xb5f7ed4a, 0x773d9e10, 0x638984e0, 0x24905e48, + 0x5fd2fcf9, 0x1c0e9f82, 0xcc5e7ff2, 0x24357ecd, 0x6f7eda17, 0xf0741171, 0xe06135ce, 0x6ede60e1, + 0xa1838ee9, 0x89da30a8, 0xdd929c2d, 0xf378f6e3, 0x82ab127f, 0xb75639f1, 0xadc76771, 0xd3543fd5, + 0x6ab2bba6, 0xbd96c2f9, 0xdb40a45c, 0x49f78423, 0xa95428ed, 0x13103128, 0x6c95fd6a, 0xc3bb4a03, + 0x77de024e, 0x0003585f, 0x6bddcbc5, 0x0e343cc7, 0xdbd11140, 0x48577260, 0x2dea7823, 0x045c945f, + 0x63d857b7, 0x636bdb57, 0x6b74eb6d, 0xf6da7b8a, 0x8d48f7cb, 0xffa3af77, 0x7a4d08d7, 0xa04f7b02, + 0x5e47752e, 0x15333def, 0x48b3b596, 0x316005b0, 0xf84ee6a5, 0xcc87dadb, 0x5467ba61, 0x669f0371, + 0x5acd89f8, 0x7c834ed6, 0x033433b3, 0x54cfe3af, 0x4d1d6022, 0xa800b2fa, 0xa4e68446, 0xec7c30f2, + 0x353f926c, 0xe3471231, 0xc902c21b, 0x90ac5d86, 0x00c86671, 0x4dc5aaf2, 0xe12d4914, 0xcc875d2b, + 0xd16e5090, 0x9eff66f3, 0xa35ee078, 0x909d7e8c, 0xc27a8732, 0xdd4d5a89, 0x20275663, 0x4aaa383d, + 0xe1521f40, 0x0e5d2cd9, 0xfd0d4aa0, 0x2f0f1b28, 0xaa93f083, 0xd4eb3c42, 0xf3cf4fa3, 0x16832a78, + 0xbd8bd1a5, 0x05448d81, 0xef09e3bf, 0xf4c7fd7e, 0x3c928cbc, 0xc4062fef, 0x2bd3b757, 0xcbd45594, + 0x051b3874, 0x50f2b65e, 0x9792bd7d, 0x3595cfeb, 0x49c03e8e, 0x81a17660, 0x2857a67c, 0xce5b2c90, + 0x2ce68d4f, 0x89bb9cae, 0x69720f64, 0x2cab6070, 0x80536888, 0xb6146a8e, 0x3635f35c, 0xcd439cd3, + 0x230f66a0, 0x48d4d5c3, 0x7c5ef87a, 0xe8a0ebf2, 0xc15f4664, 0x11a35d81, 0x232ca0df, 0xe2e05a1d, + 0x3a8a9038, 0x7c5e6b7f, 0x0d39f620, 0x9482ef2d, 0xfd6fe563, 0xdfb2bc3f, 0x2c478622, 0x1b28a03c, + 0xbb20e7d2, 0x46ee9e7b, 0x948d1151, 0x728cf9b3, 0x8dd1154d, 0xe79b2567, 0x17e1f8ce, 0xd8d2abc1, + 0xee542f36, 0xb0807f6e, 0x0337db13, 0x74984ee3, 0x3f08606d, 0x98787c46, 0x6b61bb87, 0x60ab9f85, + 0x5104928d, 0x047c150a, 0x328cc000, 0x1bc6762c, 0x160b5bab, 0x0769cdde, 0xab50811b, 0xb897102d, + 0xe09cf35a, 0xd3263341, 0x21169dba, 0xa8c11149, 0x99955698, 0x028d088d, 0xe405d1e3, 0xd0af6c53, + 0xbbd999db, 0xb65ce434, 0xb199b068, 0x59e27c8e, 0x6b25c316, 0xcd61b411, 0xfddd923d, 0x638d0e61, + 0xad23b6f2, 0x99d4d084, 0x39824560, 0x804409e4, 0x9e0887ff, 0xc03fab0d, 0x6bef47aa, 0xf460b130, + 0xa994b780, 0x4c4aa95e, 0x48b20731, 0x4218da48, 0x84dd2074, 0xa8aefa72, 0xea32042d, 0xdfe4f729, + 0x0062fc69, 0x13d954a2, 0xa9d0f94d, 0x46910943, 0xc1c484c5, 0xc7d40547, 0xb879176b, 0xd2add9e7, + 0xa61efc7f, 0xd901b0f7, 0x67b39591, 0x3e1875cb, 0xca0bc4b5, 0x45a79cbc, 0xc449a4a4, 0x09d77d15, + 0x55d094ff, 0xe6b5d475, 0x3add8a6b, 0x705c27c8, 0x475105f1, 0x6e4170a0, 0x3dd8741a, 0xe7c779bc, + 0x3161690b, 0x3ffa1fcd, 0x0fdb989a, 0x1f12c043, 0x316b1f4a, 0x268f2785, 0xd07bbf59, 0x22a51b9d, + 0x8a41bcac, 0x38d2f20e, 0x9aac541c, 0x8257d618, 0x4b3e480e, 0x52b8d305, 0xcf449535, 0x322fcb60, + 0x26fb9491, 0x881419f6, 0xc1485b11, 0x658200a8, 0xd3d47380, 0xd5d185a8, 0xa000bf6e, 0x857896f8, + 0xb5d73ca2, 0x72e68282, 0x020b4293, 0x9d142ada, 0x5704bd98, 0x54705c7e, 0xba150347, 0xa80514ec, + 0x7b833e2e, 0x0b47974d, 0x88cf75c8, 0x9a0be95f, 0xad3935ed, 0x5a7c2883, 0x7ce59906, 0x577da8f1, + 0x82406f84, 0x0ad224b5, 0x2f66fdb5, 0x45ddb2e1, 0xf2d0365c, 0x00269fd8, 0xf304f2e1, 0xd28382ff, + 0xee492fe9, 0x28d8d9c5, 0x0f3178fe, 0xeaece807, 0x81683d0b, 0x08eae84a, 0xf3df4c7b, 0xe9272fb4, + 0xd08ed3e3, 0x572e8f33, 0xdbf08a4f, 0xebb4956f, 0x261a2075, 0x5ce9bc72, 0x462a0bfd, 0xd7e2b842, + 0xb7bc9a79, 0xd5e7ff1a, 0xd7039c42, 0xf0afd3f4, 0xb677a73a, 0xfb0ee505, 0xe5814201, 0xe1925b67, + 0xcc0be43f, 0xa606a522, 0xb4a600f7, 0x4c4e33a5, 0x260bde4f, 0xc287f5a1, 0xc3319284, 0x28118725, + 0xea4a38b5, 0x76901b4b, 0xe2583ac7, 0xcc2fba9c, 0x3ef9bfe8, 0x71a79c11, 0x44cd186a, 0x8856278b, + 0x0f28fba6, 0xf3ba4cfd, 0x13675090, 0x7ed139f1, 0xac2d4414, 0xbae9e310, 0x6dc5d195, 0xe204f016, + 0xeafdcb81, 0xda3b6b04, 0x140d785e, 0x54ae9d08, 0x05e164b5, 0x0cfe6db5, 0x5accdc39, 0x3377eaed, + 0x63e1a7f6, 0x9a423716, 0x50900058, 0x223f532e, 0xff244941, 0x16ca7166, 0xc8bd6a8f, 0x625a6215, + 0x1d201a00, 0xe040bef3, 0x49d9842e, 0xcb58cb8d, 0x31c75ac0, 0xda976412, 0x1747734d, 0xae81db75, + 0x520dfae3, 0xb173f21d, 0xcacde04b, 0x6fc83de7, 0x9e7f5424, 0xcda94d52, 0xb1c57eab, 0x25a3a3b5, + 0x9454cffc, 0x2d6ee638, 0x6099b1b6, 0x709dcafa, 0xbc4fe650, 0x155ce3fb, 0x3bafd720, 0xf03e9043, + 0xfee25664, 0xd077958b, 0x06965abb, 0x19a12d17, 0x75f35aee, 0x1a44d7a7, 0xfdd7157c, 0x64b87b76, + 0x8bb3653b, 0x026eedbb, 0xb15256fa, 0x393e7046, 0x22397304, 0x9236421f, 0xb9de28bf, 0xecb4e961, + 0xb5bcee42, 0x6db10b43, 0x9fec55e3, 0x8a69c7b8, 0xf6feb5a7, 0x5227019e, 0x750c4c87, 0x6e3cf4cf, + 0x2073fc7e, 0x75a6bee5, 0x0a2f7151, 0x3ec31465, 0xd0fc46e4, 0xd5630fce, 0xca64c8d7, 0x0b3c93d8, + 0x0b7b2019, 0x81d4b074, 0xd89f69cf, 0x83d817fc, 0xf92e6b80, 0x8aaf6b99, 0x6c6daa93, 0xabbe2f52, + 0x0175f0c9, 0x8bea6775, 0xcaeb9432, 0x5bea64fe, 0x9700db05, 0x7b1242b4, 0x429e2dc7, 0xc309b30a, + 0x28a40d38, 0x24efcde2, 0x9719b9de, 0x50eefdcd, 0xc3358091, 0x9b839b2f, 0xe732dd1c, 0x7874b53c, + 0xa4d4a766, 0xf09eecd8, 0x1b8856fc, 0x80572ccd, 0x91fa6347, 0x153d987f, 0xf5c09fa9, 0x685706ab, + 0x5b4fcc22, 0x4c284e60, 0x9710e37c, 0xd42e0381, 0x3557052b, 0xd2cf7e2d, 0x978e4a58, 0xc08eb043, + 0xb92b80c7, 0x8a1c95ae, 0xc2fd5203, 0x38099ae0, 0x62dbf24b, 0x6cc853f4, 0xb21c5a78, 0x04760277, + 0x3326a1a1, 0x78b01e6e, 0x90c44f8d, 0x8d4ba828, 0xd72fe5a2, 0xc20fcd82, 0xa233aad9, 0x29c130d6, + 0xc2d5af30, 0x0d20d5c8, 0x4acc67a9, 0x21c3c85b, 0x3a8b8a01, 0xe128b8a0, 0x2eb1fc39, 0xce453c6e, + 0xfef84bdf, 0xcc716130, 0x8735b30a, 0x74850ec4, 0x3f7c5f3a, 0x8b74cd8c, 0x7c0c4e29, 0x07f7d7f8, + 0x8305a53e, 0x9bc266fe, 0xb8108ea1, 0x284023eb, 0x311d1da1, 0xc687b587, 0x383f7c40, 0x54830d04, + 0x4707a520, 0x1459b071, 0xd6036f39, 0xf5261533, 0xf956efcd, 0x031a57b4, 0xbf32f0c7, 0x2a796a67, + 0x20e2a891, 0x5750c57d, 0xbbf4d5b3, 0x25498150, 0x129c0216, 0x0d0e3f12, 0xc384e605, 0xfd0367d1, + 0x36036aed, 0x5ade82f5, 0x77fca6dc, 0x683031dd, 0xe11345e0, 0x53243ce3, 0xa9cd040b, 0x086cbbe9, + 0xb5d1d5b5, 0x4149cb46, 0x7bb2aef0, 0x4b26d5dc, 0xfa59125f, 0x7211ce84, 0x775f03c0, 0x2c7c4230, + 0xc0e35390, 0x3e27886c, 0xb54b099a, 0x41464137, 0x7235edff, 0x5cfb6e38, 0xb719a5b3, 0x20b55951, + 0xa32b3c81, 0x1d02d66b, 0xe8340192, 0x9c3bc17f, 0x1684c122, 0xaf031916, 0x8ac2bae5, 0x9ed9be94, + 0x456c5876, 0x4c7a1f7d, 0x8210e535, 0x801bc93f, 0xd3c7257f, 0x9b97650d, 0xd03e75e9, 0x01019d14, + 0xda736e42, 0x5e41ccc9, 0xcb26e331, 0x6a8f65b2, 0x8ebffd7e, 0x283f8097, 0xa41dfcea, 0xb4479a03, + 0x426aaba9, 0x0953e3e0, 0x677f01d6, 0x769774fc, 0x25527d64, 0x03826132, 0xf505a1c5, 0x5536b8f5, + 0xfd6d35fc, 0x7021210f, 0x4d909c11, 0xd7fd2b02, 0xcafa1402, 0xd42c12fc, 0x743d2b0d, 0xa82aed8d, + 0xb0c85c17, 0x2b7b0ea6, 0x03dd3683, 0xe06fcdc8, 0xe0442226, 0x5e999cbf, 0x91234cfa, 0xafef4d80, + 0xb9785e45, 0xe91cd5b2, 0xc81580fa, 0x2d7d7835, 0x3c4d8e98, 0xfb116cf7, 0x86d03742, 0xc5fa950c, + 0x5621f877, 0xbb560e06, 0xa0297544, 0x2ab18f48, 0xc80a7381, 0x299b2394, 0x41e1a878, 0xf019009c, + 0x6b311848, 0x319fea3f, 0x6a279853, 0x6fcc88f6, 0xec13d5b1, 0xe05e274a, 0xdd3a0863, 0x9da7439c, + 0x129d80fd, 0x18982768, 0x74f70405, 0x5cf7d1d1, 0x9a5e490f, 0x0cca97ce, 0x69458438, 0xa659c9e0, + 0xddaf3049, 0x6e6a53c8, 0xb79ad96e, 0x7317a8a6, 0xa9ce9549, 0x7edf1c7e, 0xd99e067d, 0x215a0acd, + 0xc1aee649, 0x97d31e8f, 0x57d91b20, 0x762a0727, 0x02530ccb, 0x867b5f50, 0x63f580dc, 0x669f7f69, + 0xee0a5567, 0x3991afba, 0x4195b0b0, 0xebd88723, 0x5880ed5c, 0xeaac07b5, 0x0a377949, 0xcea56fc5, + 0x78345abc, 0xec1d5622, 0xf1683b88, 0x40f70da8, 0xedac4fb9, 0x76416d6c, 0x65e46fe0, 0x9a5df9f9, + 0xa77ecf30, 0xa4de9fbf, 0x9053a80c, 0x16891ca7, 0xa78a3191, 0x7771fc47, 0x213eee79, 0x8358ab8c, + 0x18c7e786, 0x588cc727, 0xf27bd84b, 0xcfad80b2, 0xdfbb0e0f, 0x4df82d85, 0xdd68efb5, 0xa80cfcac, + 0x8e5f6b80, 0x2019afa0, 0x074d2eea, 0xef0c8c6b, 0x57396954, 0x06bd2d29, 0x5abd4931, 0xc0d52d4d, + 0xdc18fabe, 0x5af31d39, 0x0decaeab, 0xf8d113af, 0xd5e0de10, 0x44e4aa74, 0x062cc41c, 0x3e8f967c, + 0xd48cbb77, 0xcffdb7b0, 0xaa80c915, 0x04343e7d, 0x9554264a, 0x7a08a457, 0x2191cd64, 0xb2c896ea, + 0x8ac94023, 0x11efd6fa, 0x5a6574f0, 0x3f719ee2, 0x141c3acc, 0x38e77b68, 0xe84df758, 0xb63ad9e1, + 0xc63fad6b, 0x123b8d1b, 0xabf3e157, 0xbff009ce, 0x5112b892, 0x460e2d53, 0xa203d577, 0x20000508, + 0xf83dd332, 0xcb9daf4f, 0xf1f720c3, 0x90c55b0a, 0x0298bec3, 0x2b0a25c2, 0x088b5ff4, 0xc12b8132, + 0xaf648910, 0xc077261b, 0x8ace0a65, 0x1d955069, 0xbd9932a2, 0x562c3c00, 0x743b1a4d, 0xcd7ff202, + 0xeef0b311, 0x33ea2ee7, 0x80510f80, 0x240b1bac, 0xcaac5b9d, 0x8da3935b, 0x344af930, 0x18060bb0, + 0xc4283f29, 0xe55ab489, 0xf63a833b, 0xd8fb98f8, 0x304c6b32, 0x6274de1d, 0x8aaa2aef, 0xd224df76, + 0x611dcdca, 0x7219e2a1, 0x9c47d397, 0xa67fce27, 0x19a3041b, 0x970f28f4, 0x1f7a913d, 0xb76cda63, + 0x4bdc887f, 0x5aed3db4, 0x80c2109f, 0x6fedc25a, 0x56c67983, 0xd8a2df40, 0x632e4c58, 0x6c2255b8, + 0x58f5a07b, 0x3c0266e5, 0xe60f5e55, 0x54fdc947, 0x4f7d267d, 0xe8c5b7db, 0xbca0df19, 0x6e230767, + 0x594fa486, 0xaa7a1cdf, 0x3faa1b24, 0xdf04be5a, 0xa891ea41, 0x2e525239, 0xa53acad2, 0x2fa7f6ba, + 0xb713d316, 0xdec06e82, 0x98e3eded, 0x74d057df, 0x59e29abe, 0xe156696e, 0x08756ed6, 0x947c1ead, + 0xaefdfbd3, 0x52c4a6e8, 0xc809989e, 0xe07e481c, 0x534c0f35, 0xbbff8af7, 0xaab1617c, 0x596a01d9, + 0x666a008e, 0xa6d488e4, 0x198da4fe, 0x8762d8b9, 0x9e476feb, 0xcd8fed3e, 0xd980aa05, 0x9269bb19, + 0xbdf3be44, 0xe2fe28c4, 0xd7c70ad9, 0x8897a38b, 0x5b3dd2ea, 0x19cd92a9, 0xf2517e1c, 0x298eb742, + 0xd24ab4fc, 0x4666e1e7, 0xbcfdcb2c, 0x5cb2f913, 0x8816533c, 0x109bed95, 0xdad41c77, 0xe96b141f, + 0xb55f8bb1, 0x325e5d78, 0xa4475871, 0xf6308b21, 0x1896c0b2, 0x57eaf0b0, 0x291cde6b, 0x9977f69e, + 0x27fd3816, 0xfbd6f071, 0x9c30f8ab, 0xa6874c2b, 0x8c6ce71f, 0xab9aac0c, 0x6872aa59, 0x8fe96cb1, + 0x2ae780c3, 0x7374f385, 0x247b1761, 0xa33e6ebe, 0xbe0e2ccc, 0x809617ef, 0xf1c09484, 0xee10d4b1, + 0x3bb6eece, 0x1f8c994c, 0x8f4f4a6d, 0xdc4d6c2e, 0x16b5ab0b, 0xc8101d01, 0x5fa74bb8, 0x3fbc852f, + 0x2b9ab308, 0x8da67e1e, 0x136d5adb, 0x1fee6d5f, 0x06ca8042, 0x748b26fc, 0xb4ba6795, 0x92e293fc, + 0x4a72bae5, 0xc77f2aa2, 0x1a0cf67f, 0xe3af76d0, 0x6db54a0f, 0x27e7aa1d, 0xcdfca6a8, 0xe9bed71c, + 0x4d82b38b, 0xe57e1822, 0x4e00c5c4, 0x2733d84e, 0xaeea8a26, 0xfaab4518, 0xc19f5cac, 0x0bed2aa4, + 0x57c96f61, 0x2231b708, 0xda1ed852, 0xc11cbedb, 0xebe9e8a6, 0xf527a1dc, 0x118d59d5, 0x783cfc66, + 0xfe33765f, 0x3fafc2b1, 0x27d4882d, 0x7ae70bef, 0x66ae687f, 0x8f0eadfa, 0xe243de4c, 0x50d8ef45, + 0x374cbc30, 0x0243c870, 0xc9a38573, 0x93583993, 0x5866d66a, 0x7e9300ec, 0x6bc149e1, 0xdf6ca967, + 0x1628b35c, 0xff5bbb6d, 0x40e1c782, 0x9d0d408c, 0x30f63d99, 0x4e42c4a5, 0x03b7d2e5, 0x01af8ff7, + 0xb361da26, 0xc0e2aa6b, 0xbb0ff907, 0x09cce034, 0x15cfeac0, 0x3cdd47c8, 0xfa1c890b, 0x9657dee7, + 0x10f2492f, 0x231be0f1, 0x2b6fc840, 0xe2d4c4b5, 0xf6b028d4, 0xe8cac705, 0xd4849fe4, 0xd4cc137d, + 0xe744e87b, 0xdb807fb7, 0xd249a8da, 0xe3f2851a, 0x73f84ba4, 0xde6a1537, 0xd7bca5a0, 0xdd83e623, + 0xe92402b2, 0x26708f18, 0x2c08f3d4, 0x711e0c35, 0xe6913678, 0x7f6ace2b, 0x21514ebb, 0xc46d4800, + 0x7bac4cc0, 0xa666c711, 0xa46cd8b6, 0x258840e5, 0xa024f792, 0x4c7ada10, 0xaf2ba637, 0xc4063ea0, + 0xae703816, 0x46cb9555, 0xa3bc1664, 0x2fba7738, 0xbc9265ff, 0x446598b4, 0x9ac42684, 0xf942657f, + 0x5e9f1b4d, 0xac3b6358, 0x9f2e08c8, 0xa9e27648, 0xa172189a, 0x2f5beeea, 0x78a5d53f, 0x55cfe63e, + 0x49d377b1, 0x70b7043a, 0x296100dd, 0xa23c291d, 0x978ceff4, 0x056fd93e, 0x7f3f9d2c, 0x60181fd4, + 0xea694198, 0x5047e201, 0xa8ba0451, 0x53bc5b17, 0x03f7dfc9, 0xbd1416c4, 0x399b1672, 0x06175688, + 0xb453ee10, 0xafe27498, 0xc255c2ad, 0xf20450b2, 0x46a6c55b, 0x4faf404f, 0x8a41069a, 0x94df9940, + 0xbb74e075, 0x4408ab02, 0x2eae958a, 0x2185bc30, 0xc9bd31f7, 0x9f9a504d, 0x0b0af000, 0xa6886529, + 0x7156830c, 0x15ec0138, 0xdc314d4b, 0xddb7724f, 0x4cbd8450, 0x80031ed1, 0xf94c75d1, 0x3ffc5e6a, + 0x8ae6bd16, 0x76b3f4a5, 0x405f1157, 0xcc29856b, 0xbff96795, 0x6e9e520e, 0x5a400b16, 0x8a6baf6d, + 0x862521cc, 0x560947f5, 0x487e77c0, 0xb00d269d, 0xb16457e2, 0x50849628, 0xfc5ff382, 0xc25ae007, + 0x7679538c, 0x7a1906c1, 0xa5cc4eda, 0xff58bd45, 0xf739bbad, 0x1156c512, 0x5a332d5e, 0xca5e1ee1, + 0x6615bbb5, 0x09b078d9, 0x4f2d5e95, 0x636355b0, 0x51e26de0, 0x877b9f10, 0xccc1f593, 0x73b69b1f, + 0xda27470d, 0xb5f73244, 0xe9df5ded, 0x50c7adc9, 0xfec11eae, 0x9c2e0afa, 0x01360598, 0x1d746283, + 0x27c57f08, 0x764dd486, 0x45939cc1, 0x908fd571, 0x8555893f, 0x4f0c6516, 0x59d02f16, 0xc3221cab, + 0x86952278, 0x2810740c, 0xaff4e24d, 0xf0466b27, 0xc61b58ff, 0x51302151, 0x3b37db2a, 0xbf02ec46, + 0xabc1d828, 0x05b673a5, 0x93e0c5ce, 0xd03769cb, 0xcb45cf86, 0x50e1d41c, 0x95faae29, 0x7a4ef1b5, + 0x92b00b1f, 0xc0eba62f, 0xad1f42a3, 0x4ac69a27, 0x5f0c284f, 0x13782dc4, 0x58015627, 0x5e5d89ca, + 0x155f0bfe, 0x9412ac54, 0xfae35fa2, 0x7264d093, 0x072bfa0a, 0xfb1b7cb2, 0x0d8a3d57, 0x4bc5a0c7, + 0xb7c7e0a3, 0x4750b882, 0x7da82edd, 0x12e382a2, 0xdbf1b0d8, 0xd9fc24be, 0x9d268a7e, 0x0485322e, + 0xd7d5283c, 0x4fb84772, 0xb7cefb4e, 0x2c24f646, 0x3acaecdc, 0x6ecf163b, 0xd8b0f8eb, 0x4f7b98f0, + 0xdbccccbc, 0x15baf1b1, 0x331db227, 0x85625873, 0x08a32949, 0xc8a8e4fc, 0xc4a80c39, 0xb3a222b9, + 0x62662526, 0xd602afdb, 0x53c26c8a, 0xdafdc1ac, 0x96fbf361, 0x1faccad5, 0x35794989, 0x1d0c32b7, + 0x9161c085, 0x8505da04, 0x99c9fcb1, 0xa4d33a6c, 0x74d37184, 0x2ee7abdb, 0x0da5a43b, 0x5dbbb1c9, + 0xd6243501, 0x50f99e78, 0xbf38fc89, 0x87480829, 0x0d427d38, 0x13205817, 0x29f89153, 0x0d6912f4, + 0xe7888474, 0x58967c61, 0x9c2344d8, 0xd9b342f6, 0x7b3e366f, 0xb5a5e275, 0xf230dc82, 0xa76485f4, + 0x8f7d14af, 0x233caa9a, 0xcb28c333, 0x50f98666, 0x1984bc20, 0x46e2a620, 0xd5263808, 0x2e3db588, + 0x47bfa4e0, 0xb32f2513, 0x0aa7f021, 0x6c9ff00f, 0x0fea3600, 0x4a543dd4, 0x72d27f50, 0x794b2c38, + 0x9ba7e5c2, 0xc849fc1f, 0xe952c9aa, 0xc42d1a2d, 0x88e44e47, 0xba21f4c5, 0xde3dfa58, 0xeac4977f, + 0x3be76723, 0x01b3900b, 0x25be356c, 0xdd950aa7, 0x851efc40, 0x6fb2735f, 0xbd7c202e, 0x4e87a4a4, + 0x8661f1ff, 0x5b2fc885, 0x778e9da0, 0x29f0e085, 0xab396ade, 0x4917d26a, 0xec6a0a3f, 0x7dedac59, + 0x3fbd180b, 0x22f5d3a5, 0x37858ee3, 0xce79c4bc, 0xe9e551f2, 0xac4748d3, 0x5b3b5879, 0xb1c3932c, + 0x829272a4, 0x503bb2b2, 0x9684d42b, 0x6485bfe3, 0x4fc76b0b, 0x76994c6d, 0x6ccfffdc, 0x1ba4492f, + 0x508ed11e, 0x34f13455, 0x2a4d05e2, 0x655bdda1, 0x8ffb4260, 0xffd1a823, 0x9077ab37, 0xe019379a, + 0xd435af57, 0x3e86d270, 0x7f04d0f2, 0xce0369aa, 0x7c164c18, 0xe66ebb54, 0x95348b92, 0x6f3298df, + 0x4115d689, 0xc8a989f5, 0xbd48714a, 0x9b30818c, 0x6bad3326, 0x044372e6, 0xefcadcf6, 0xec85d7f7, + 0x37a627ff, 0x1cd43dee, 0xdcec6ebf, 0x952883a1, 0x78c45e86, 0xfc49bc3d, 0x55757973, 0x84149ef8, + 0xbc16d2ec, 0x3e2d4793, 0x8ddf9746, 0x88b56996, 0x8eb8dd7b, 0x42cd9723, 0xa17f53c4, 0x882c2967, + 0xe1d5d3d0, 0x010203f0, 0x3ad2ffca, 0x08d1f8d8, 0xb6514804, 0x6043e67d, 0xdaea0922, 0xb340d658, + 0xd8a24b76, 0x22231462, 0x055f75a8, 0x52ab5a40, 0x40d17820, 0xac3acdb4, 0x11e7fb07, 0x3beff0a7, + 0xa71ce863, 0x73e68102, 0x885a009e, 0xcd0f693b, 0xaf1cde98, 0x16efd7c8, 0xb7c4ec53, 0xbce66ead, + 0x76c9e6a2, 0xf20e2458, 0x9710ef28, 0x8b6b415f, 0x43bd3fc8, 0x8f7e54f4, 0x888b7aa7, 0xa985f359, + 0xcc17d17e, 0xc52d9ae0, 0x8180082f, 0x36a77648, 0x420e1c35, 0x40753602, 0x9f8130ae, 0xc7c66a16, + 0xad9625b4, 0xdbb45f5b, 0xf707fbea, 0xe2e6c19e, 0xaef57e48, 0x7f5936f9, 0xb4713907, 0x419c4483, + 0xdf4f9a33, 0x1d7cc630, 0x25ce202e, 0xddf24c56, 0xe7a78b6e, 0x9c483327, 0x4fdea710, 0xc083db43, + 0xb926bbd2, 0xc2fdf22e, 0x3c0efb96, 0xacd0cf96, 0xaf46e2a6, 0x6107a718, 0x83643c4c, 0xf2f96503, + 0xb44e939e, 0x7bd2ff75, 0xca7c61e9, 0x62cf2041, 0x84ea497d, 0x9ad06edb, 0x41397ea1, 0x5793b309, + 0xe90d2a12, 0xecac4f77, 0x57a43182, 0x4367211c, 0x4ddebea8, 0xc0fa4336, 0xbd8648c8, 0x30ed4df8, + 0x71b9bce9, 0xd30e5bb7, 0x9ed2bc51, 0x0d28391f, 0x69059f1b, 0xc2316ded, 0x25c041bc, 0xe829e82c, + 0xeacd8b3a, 0x4a56cf25, 0xd952eec8, 0x12328288, 0x0a2caf34, 0xdc77a9c0, 0x896343cc, 0x1102463d, + 0x9e264e70, 0xc99bc749, 0x298a8d6f, 0x1c1fca23, 0x7900e898, 0x95ec5005, 0xabfcf1f2, 0x7befc2c5, + 0x3f767c6f, 0xd1c48bab, 0x96d44504, 0x6af41cc1, 0xe747aa52, 0x19cd5dc4, 0xcc5eef4f, 0x4d8e0211, + 0x50da0980, 0xac96ecf6, 0x008c4910, 0x53271dd1, 0x2af356ac, 0xf2474681, 0x47e6ad5a, 0x4197a899, + 0x4d707a35, 0xa899e63b, 0x92ab9c12, 0x9b7042ce, 0x29dd6582, 0xebb44855, 0x840552f4, 0x83e01e82, + 0x33584216, 0x89b3872a, 0x023bf2b6, 0x353d3ccc, 0x03228e4a, 0xc0a9498a, 0x6ee6ea6b, 0xe4be0aa0, + 0x1f64dba8, 0x7104bede, 0xd63fb4a9, 0x6a2949b7, 0xf7317a5e, 0x8caa5d79, 0x49a844d0, 0xbbf5495f, + 0xb5327384, 0x7900764d, 0xdd1f7d2c, 0xbd24c8f6, 0xaaf61d6b, 0x82d537ba, 0x905a7603, 0xc41a3c1d, + 0x264da2c7, 0x96fa52e6, 0x64b457aa, 0x0b153c49, 0xf94cc0f0, 0x8a4d3a50, 0x464ca1a6, 0x6f334cf6, + 0x4ed75269, 0x90416304, 0x4b2d199d, 0xe27321c8, 0x96f62834, 0x206e763b, 0x6a5d737a, 0xb36b2ff0, + 0xdea90048, 0x0d58e812, 0x1fd2e8d2, 0x102e4bb2, 0x15d20b5f, 0x9606845b, 0xa116a1de, 0x9ad1bd43, + 0xb709b9fe, 0x4549aaea, 0x82961455, 0x4e97169e, 0xffb83ef3, 0xadae615b, 0x84d9ac85, 0x0da4a925, + 0x5b9f0e07, 0x77355c4a, 0x1dd931f2, 0xfd91301d, 0x7faadcf5, 0xa40b85df, 0x528c05af, 0x86ee977d, + 0x23488d1e, 0xe008f3c1, 0xdc8a8157, 0xc1a5a8b6, 0xfe6d58cb, 0x40435974, 0x2ed2f375, 0x9ffd78cf, + 0x682ddc91, 0x51f8be64, 0x2a4b3549, 0xfe733368, 0xb9f583fb, 0x17a388b9, 0x78038049, 0xc505ab47, + 0xcb927843, 0x508a48d9, 0x01aaaac0, 0x0eca9742, 0x0ad69c35, 0x9542b3d1, 0x7e6727d2, 0x9cef5fce, + 0x8f3029f5, 0x0da699d8, 0x0d9c28e6, 0x9fd48334, 0x829c40e5, 0x13cc254d, 0x094ca454, 0x88bb5013, + 0xcd841ebf, 0x8568a570, 0x42079c48, 0x0de0d666, 0xc3dbbd5e, 0xf3c85b77, 0x8471bfd0, 0x6060ec3b, + 0x70cda06d, 0x3cb3baad, 0x1ba8159f, 0x72848736, 0x9b4fe0b9, 0xa63e5ad7, 0x725188a7, 0xaa4d6361, + 0x17261a8e, 0x6a896049, 0x627d75a3, 0xc7606694, 0xed01a4b3, 0x898e408a, 0x3d48637e, 0x1ad9064e, + 0xf480ab6d, 0x39525194, 0x09332273, 0xfa9da51a, 0x08a1abc7, 0xec0fb7ff, 0x6634c2c0, 0xe65896c8, + 0xdfb74aec, 0x62aae2f0, 0x46b855b3, 0x9931b4ba, 0x4bf8ee31, 0x3e411d40, 0x0560ef7b, 0x5e45a39b, + 0x017e193b, 0x1df65f11, 0x30175cef, 0x127d65d2, 0x6a1799af, 0xdd4b4d76, 0x4bcb67eb, 0x97d243ac, + 0x42d2ee35, 0x29b9509b, 0xdc0ef377, 0xcc0f7700, 0x55e969d9, 0xe260be49, 0x18b01f3b, 0x0a2fc30f, + 0x87ddafc7, 0xf1dc5da4, 0x426f9cfc, 0xf5848a50, 0xab26749b, 0xe82ec0a8, 0xfb85d9ea, 0x2ddace97, + 0xcf06109a, 0x2843152c, 0x657e38c0, 0xd5265b0a, 0xf41d227a, 0xe3863b99, 0xc8cd0a3a, 0x8c823cb1, + 0x257d0391, 0x381b4e9a, 0x08cb145a, 0x31809279, 0x419603bc, 0xe806094a, 0x9afab418, 0xada93d07, + 0x98ee488a, 0x1ebc5b31, 0x9c1ff36b, 0xad1a7017, 0xbb6318ba, 0x119271db, 0x72317270, 0x42b3073b, + 0xf22f9ccd, 0x91060525, 0x65b002bd, 0xee54e05c, 0xec6d83df, 0xeeee7844, 0x2cc4bea4, 0x043439c0, + 0x769e9c28, 0x65f8905d, 0x8ecf8fc9, 0x2943f103, 0x5c4bc682, 0x820e7f9e, 0x182fc181, 0x380791d5, + 0x631f0974, 0x3f48dae6, 0x025739cd, 0x82cf58ca, 0xe1713436, 0x335444d7, 0xf549a629, 0x85534177, + 0xd76a9b89, 0x1d8a922c, 0x94934aaa, 0xb2566cd8, 0x27a0ed6f, 0xd62a5c24, 0x4ec25938, 0x00b23f3a, + 0x231c3039, 0xee6b76b0, 0x76674774, 0x272ca533, 0xd2d8b623, 0x5113ea88, 0x72ef2942, 0xd4aa0766, + 0xa4121419, 0x43d4cc5b, 0xf96d8a9e, 0xf5967133, 0x7b21edbb, 0x06c7b2b5, 0x74798f9c, 0x35e96814, + 0xcfa48b77, 0xb9fe78b1, 0x00ddcdf1, 0xb0e33bae, 0xa103d721, 0x65c12cfa, 0x1533784d, 0x5ddb2efb, + 0xc8e21ec2, 0x8566249e, 0x5ce64dd9, 0xe66b835a, 0xffc734f9, 0x37de2f58, 0xfb5fd023, 0xb1cff50a, + 0x8a6046e1, 0x7c9f5ceb, 0x8353fd30, 0xcd9fe994, 0x3d05b398, 0xf24bbd63, 0x4d7983e5, 0x6df13218, + 0xf4ab5191, 0xc2ac611d, 0xbc805c54, 0x50384b7d, 0x450bb619, 0xb1a97d6c, 0xad25adc0, 0x32598690, + 0x88a6c986, 0xdb0e7bbb, 0x3289aa17, 0x01d8855d, 0x216a754f, 0x1f724eae, 0xfa1d603d, 0xf450c73f, + 0x0baad5bf, 0xaed19942, 0x66e4b053, 0x8676dca8, 0x175e3cdb, 0x257db62a, 0x6e9feb60, 0x07566246, + 0x17007af8, 0xa566c524, 0xca47041a, 0xc9a6fee4, 0x2113ffef, 0x6d2528fb, 0x3aac7627, 0x30ae42eb, + 0x9869a5ff, 0x7c50a86e, 0x1ea1e3bd, 0x5c7adbda, 0x1b5701f1, 0x0c3ec855, 0x96e3ada2, 0x30d9fe16, + 0x9e180ea4, 0xb7d4a5a4, 0x85910990, 0xbb78bfa1, 0x7ba029d5, 0x66ebf4d1, 0x34268b83, 0xe4bb7d3a, + 0xf158bc14, 0xff06ca54, 0xfc0ed1c4, 0x60c3f500, 0x261d419c, 0xe8b577fe, 0xf48ee9e9, 0xac836a26, + 0x5358b61a, 0x1daec88e, 0x38c8626f, 0x6b882eaf, 0x650330b9, 0x7c80eabd, 0x61861454, 0x9e7b7f20, + 0x80c450ab, 0x7135cfb6, 0xface325c, 0x56eff7dc, 0x53cdb2b6, 0x36dbdc99, 0x7452b7e4, 0x3d11bfc0, + 0xec264fe5, 0xa207dbaa, 0xd5d46e6e, 0xf8018aa8, 0x2b9177a6, 0xefe6b9e1, 0x9225659c, 0x3adc597d, + 0x381f32a7, 0x20a5e8c0, 0x8e175709, 0x850dd86b, 0x9f0473bf, 0x4910fcea, 0xd427f014, 0xf1cb0305, + 0x15470bc2, 0x9ef31ae9, 0xd9e26951, 0x06167ac3, 0x041bafaa, 0x3a769b2d, 0x9dde9357, 0xf8517a95, + 0x938836d1, 0x34e5d393, 0x39fe8cd0, 0x3c3c7946, 0xfab35e30, 0x0f69ec7b, 0x045040df, 0x000305dd, + 0x9b51e473, 0xadd93c42, 0xb8b171a4, 0x81d92e80, 0x21dfd564, 0x2bf519ed, 0xf57860ea, 0xd69ba992, + 0x779d2e1b, 0xbfd5587b, 0xfc9a9ae9, 0x7e0edfa1, 0x33714c6d, 0xd5bc8b0e, 0xccfc8b54, 0x58a93087, + 0x1fb60895, 0x7b60605e, 0xdd0141b7, 0x6a251712, 0x0a98a13e, 0x7bfae4aa, 0x5999f6f8, 0x60d94733, + 0x1ad18a32, 0xfd40a3ad, 0x5a281170, 0x5fc28e03, 0xa83d7f89, 0x065a7966, 0x85a759d1, 0xf360e809, + 0xb5cc59b0, 0x9e160e05, 0xc52efcad, 0xf578ee59, 0x4af7bcf1, 0x07e752e9, 0x10fd16bf, 0xbf12e279, + 0x8ae04ca7, 0xd33392d5, 0x288ed4fe, 0x9a00c670, 0x3442d38e, 0xc6a646eb, 0x03f10d44, 0xe9f7225e, + 0xca2f0fa1, 0xaac2e3bb, 0x3693ff2c, 0xa5fd5974, 0x10aca931, 0xc79d2fc5, 0x1905ec05, 0x3c0036af, + 0xdb27a2a5, 0xc52a6a98, 0xe5c39241, 0x325db3ef, 0xfda6d410, 0x95f371af, 0xbbfdf27f, 0x2b969463, + 0x00af9e8b, 0xfd0a06b6, 0x3b31138e, 0xd2f95b87, 0xaef407e6, 0xf7868f7a, 0xe2e14e9f, 0x7e47aa64, + 0x7b5b0c18, 0x68064222, 0xb328e3da, 0x1ea963a5, 0x6a5eea69, 0x07796220, 0x0f0f8722, 0xbd6092dd, + 0xf0592f24, 0xb4fe1244, 0xe8ced2c0, 0x5c403977, 0xb4f35d9c, 0xa43dfd70, 0x17862bac, 0x610b9ce2, + 0xc23d5d6f, 0x63e577d9, 0xf2c93a3a, 0x97d9e1fd, 0xea202a67, 0x83a413f5, 0x192c7946, 0xcf3f6b27, + 0x1a2a1b5b, 0x69200bcf, 0x2a15f583, 0xe85c8f31, 0xa7ada8bd, 0xb38ffdbb, 0x4c34dfd2, 0x94d23baa, + 0xbb181ce0, 0x32a26282, 0xfcc7549e, 0x3c7eb423, 0x8e401587, 0x842bc8e9, 0xfac296d4, 0x109b4bd9, + 0xff007778, 0xbbadb765, 0x3f019170, 0xe481e6d0, 0x6fe05289, 0x3ff23f25, 0xd9388c79, 0x5e4f7f1d, + 0x15a2c929, 0x9263b116, 0x93cc63c9, 0xdcf6aa50, 0x0eefb65e, 0x9282866a, 0x62e33ae6, 0x4d899719, + 0x187b9976, 0xf5ea2689, 0x87e3b151, 0x5fcdfdc0, 0xc0df4539, 0x9da3e612, 0x76c37aff, 0xc2f069e9, + 0xb8aec95c, 0xcb9d0a10, 0xd48ef6e8, 0xd5edf990, 0xae53cc89, 0xbb24e2f4, 0xb5eb3dee, 0x5b395688, + 0xf116f57f, 0x4a8f7128, 0x3411060e, 0x92c514ab, 0xe863937a, 0xbaa41197, 0xe5dcc72c, 0xaf16a669, + 0x664039da, 0x3fc1734d, 0x4c72099b, 0xfc14ae40, 0xe9b31fd8, 0xce00343e, 0x257e15c8, 0x12fbc35b, + 0x833e7679, 0x27ca0696, 0x2bf7bc36, 0x530a6eb4, 0xd3fcd805, 0x454b1b6a, 0xe4c47cdd, 0x4f1906d3, + 0xd94d2f52, 0x5187a7f2, 0xf8592c40, 0x4b6c96d3, 0x7bd3ae52, 0x023e2427, 0x31c4282e, 0xd8215da0, + 0x1f43189c, 0x9e0aebb1, 0x363b6924, 0xbc50d287, 0xf9496a6e, 0x23b54310, 0xc32a677b, 0xa843fa43, + 0x6d7b3b88, 0xca4ae62d, 0x96b3fb52, 0x4727ad3f, 0xa1ba25f7, 0x6ce483c6, 0xe46d9127, 0xfb54eff3, + 0xfc5fbfed, 0x18db2aa6, 0x82914797, 0x1705333b, 0x7c374aea, 0x358367d4, 0xaa6212d4, 0x66ac9f4d, + 0x4429b1aa, 0x838682ab, 0x5bdfd86b, 0x1e82010d, 0xbc02c620, 0x7174d1ca, 0x5bb5714a, 0xb1a06898, + 0x3481ea5a, 0xe6a3da25, 0xda747472, 0x70b33853, 0xbcb36fa7, 0xb328445b, 0x18007475, 0x468e0836, + 0x144b837d, 0xfd420f44, 0x23cf8bf7, 0x112c60ce, 0x90f65308, 0x7361dbf0, 0xd8493b1e, 0x4dfe98e9, + 0x879d857c, 0x1c1b4958, 0x0fda938f, 0xd8fc7208, 0x763b5a31, 0x4cc05a2e, 0x5e68e36b, 0x838322dc, + 0x01fa6412, 0x2edca5b9, 0x33cac6df, 0xc4900965, 0x61e54212, 0x9b899ea0, 0x0adbe90e, 0xed6bf807, + 0x871a2102, 0x99f83316, 0xfaa0132d, 0x33d7f86f, 0x6bdf45df, 0xaa4f88c6, 0x84b2b95d, 0x89221af7, + 0xfde369e7, 0xadafaa15, 0x86c4f91b, 0xc21cee40, 0xe54929fe, 0xdc03e09a, 0x5b6edd32, 0x406e133b, + 0xfb7507a4, 0x6449e3a1, 0x66263430, 0xbce0953b, 0x4b68eaaf, 0x4946a06a, 0xb40599a7, 0x4472dbc7, + 0x532e6654, 0x0c528786, 0x2af9030a, 0xade14def, 0xf0e7432a, 0xd23120a5, 0xe174b6f5, 0xc9f1fcdb, + 0x230b4319, 0xdd780574, 0x58889d79, 0x888b4746, 0xe266aec8, 0x1b30570f, 0xec9b4e22, 0x380e1fd9, + 0x748f2bc2, 0xb50d9f1c, 0x22c3c3f3, 0x0698d82c, 0x15593d39, 0x6b503b3e, 0x9561ef62, 0x1ca680ad, + 0x44f1187c, 0x7d336a7f, 0xdba1b444, 0xd66f8a0d, 0x7df2a3be, 0x0dcb441b, 0x5bb5e4bf, 0x381b707f, + 0x818cadc7, 0x812e2773, 0xcbdaa154, 0x2bc1b9e7, 0x9f483af4, 0xeefc8478, 0x73e830ce, 0xb353b81d, + 0x5d4cd927, 0x4e2fcaa6, 0x441673b9, 0x5ca461b9, 0xc1a3b77b, 0xbfd0216c, 0x06f67edb, 0xe7929941, + 0x49354022, 0x54308318, 0x11dfcb9c, 0x9a840dd5, 0x1cea82ad, 0x4d3aead2, 0x4149bb2e, 0x24cadfe9, + 0x36333d7d, 0xb546ed5f, 0xf963fcba, 0x19ab91a9, 0xa2cafa34, 0x498ca20a, 0xcd9ca5cc, 0x8430b35b, + 0x45da675f, 0xd7fd46ba, 0x3818a7e3, 0x277c9116, 0xdb5813b5, 0x9f013844, 0x678c88e0, 0x2f19938f, + 0x52a33502, 0x7d4b918c, 0x345aadad, 0x0f4d0020, 0x111c02f2, 0xa696fc3e, 0x8bfef5ca, 0xcaa6e446, + 0x4b0a5e47, 0xce55bc17, 0x09656fd6, 0x9be84e6d, 0x1ac46e31, 0x456acca2, 0x53e98c55, 0xfedfd4fb, + 0x36b56901, 0x74d876ca, 0x44c167c5, 0xa6610e87, 0x14314c33, 0x646dc908, 0x40a72887, 0x8ada7673, + 0x83486b67, 0x7e718d49, 0x9ff5958e, 0x672a212d, 0xe2d6f1f3, 0xfe627e5d, 0x791daf5e, 0x50943665, + 0xf33f68cb, 0x10d90654, 0x040a07c5, 0x698a5f7f, 0x834e5221, 0xfbb625b1, 0x3e6a0f21, 0x9dad2288, + 0x3afe1dc3, 0x99f64d76, 0x6f1ec1df, 0xb0892ea1, 0x8932f631, 0x0f22400f, 0x44006261, 0x72f16cfc, + 0xc89ad73f, 0xe60b27fd, 0xebdb2c52, 0xc5a2f965, 0x49880d53, 0xe0a377c7, 0x6d4b80c1, 0xe4d1b6b1, + 0x28dfd6df, 0xda09bb42, 0x09468622, 0x9ee17fc9, 0xd6c9844e, 0xd921b960, 0xa9450866, 0x5eaec349, + 0x86de5619, 0x221917c1, 0x29cd6536, 0x08c1e273, 0x3e7b474d, 0xb3504a33, 0x1c926f0a, 0xe1f1106e, + 0x06add0d4, 0xd0c462c6, 0x25933747, 0xb131fa1c, 0xab9f2895, 0x175713ad, 0x48910c97, 0x90b455c3, + 0x494f49bb, 0xcd7f90a5, 0xb6709e40, 0x3a456351, 0x16335aeb, 0x043069b8, 0xe2bc8b6f, 0x08484654, + 0x35efc1c8, 0x7fb2d13a, 0x543a223a, 0xe52108d6, 0x3f252972, 0x42f5810a, 0x13c8b807, 0xa20bf6c0, + 0xa5ae718d, 0x0bd09563, 0x66ac29ea, 0xb022acf9, 0x87dcb2d5, 0x9bafb81d, 0x62e53468, 0x86ec692b, + 0x6f991bfc, 0x47158a15, 0x4bce9b45, 0x9bb8cf13, 0xe5529f03, 0xb9a287bb, 0x8d6632f1, 0x8ba05667, + 0xb81c2be9, 0x9d263673, 0x926195ce, 0x250d2c83, 0xc292a076, 0x695c4902, 0x5550ec24, 0xcfad36f8, + 0x9ee5e794, 0xa799f02d, 0xebf94220, 0x2282630d, 0xc5eaa672, 0x3ba5216f, 0xa823a2f0, 0x41eca645, + 0x2ab990c7, 0x63a4c199, 0x2a903d84, 0x277dfbfe, 0xadd8e3b8, 0xd9ba55f8, 0x186e095b, 0x5e4075b3, + 0x526af581, 0x87dcb079, 0xc0d7eb3d, 0x38315d3e, 0xf20278bd, 0x50c43023, 0x892d80a7, 0x5a009668, + 0xdea23b22, 0x9f8c78c5, 0x7481420e, 0x043b1bd5, 0x8eef556b, 0x1d7ea637, 0xfb31497b, 0x5d2b8163, + 0x8d801702, 0x98d2fe2d, 0x3ed6b821, 0xb4d9fc24, 0xc219cccb, 0xcd691896, 0x2ce68b7a, 0xff16d663, + 0x8dd0fc68, 0xf5f02adc, 0x3af3459d, 0xaa9bf9e9, 0x8d436e6a, 0x11ce6040, 0x725e6507, 0xf043a268, + 0x31ce4e7d, 0x2222e485, 0x8749b526, 0x6934e270, 0x462cb504, 0xb2ccc077, 0x6162fefd, 0xb3701463, + 0xa2ba5d80, 0xc3cb7c32, 0xc7e6f695, 0x79fa72f9, 0x11aec8dc, 0x231320ce, 0xeabc4ede, 0x82191ff8, + 0xafb8910c, 0x02da5f40, 0xd9d12334, 0x068ffbdc, 0xc3a0826c, 0x972a93c1, 0xc6ea0559, 0x3e457dab, + 0x9b5b9b65, 0x37b878cb, 0x67b76884, 0x24478b3f, 0x4067efa2, 0xaf8dcc1e, 0xfeff3319, 0xeadd9464, + 0x043a8784, 0x750aff92, 0xc349cfbc, 0x289ff1e0, 0x13e9cb37, 0x85c7625f, 0x1cd44f50, 0xec04c135, + 0x5ecc278f, 0x2b74651f, 0x3453e62c, 0xedbc41e9, 0xe20b9267, 0x32e1c10b, 0xc7e81189, 0x1a5bcb57, + 0x0862a010, 0xb3c9a772, 0xe95fe6af, 0xd9b1de34, 0x1fe8ba90, 0xb1e075de, 0x37822b05, 0x4c535295, + 0xed37dba7, 0x26112057, 0x68c688f2, 0x41b19555, 0x354c296e, 0xeba9cc8b, 0x9467d5e6, 0xe6f57ae3, + 0xd83de721, 0x8eb96774, 0x4a2283d2, 0x828c2992, 0x980ddb34, 0x50ebce4c, 0x647a0ab6, 0x0ed8dcf0, + 0xc5b46a8b, 0x1a8ff7f2, 0xedcd633f, 0x60f035c6, 0xd1efc163, 0x67c335d0, 0x6981f384, 0x6ca54c87, + 0xa073b4a6, 0x59d159ac, 0x7aead5c9, 0xbf09d971, 0xb25d18b9, 0x321eb98a, 0xf5315cf0, 0x995fb40e, + 0x0cc73d86, 0x33ba70df, 0xa1c926d4, 0x854f6c47, 0x059670af, 0x4a31b851, 0x86e2a930, 0xa571dfbf, + 0x3a3fe4b7, 0x267de697, 0xb31d69c6, 0x086ee6e5, 0x10a2d4ff, 0x6cc7ed19, 0xb156f99f, 0x925d2337, + 0xe23cc3fc, 0x712f8c73, 0x6edcbe75, 0x32a84f9e, 0x3e99cfd5, 0xe714aaf8, 0xbc2cef3a, 0x29c40a00, + 0x1ce39a6b, 0xbf7d9647, 0x75871913, 0x188709dc, 0x48ea3e9d, 0x36bb2748, 0xb36c6141, 0x3af7f514, + 0x33a6d8b3, 0xd9101e64, 0xdfd8eca8, 0xd5f5153d, 0x874f27ed, 0x56aaaac5, 0x731e46bf, 0xa44437b1, + 0x13eb0f7c, 0x77b31835, 0x65c53459, 0x6ee4421d, 0xd7e9c92c, 0xf5e288f2, 0x3e3a2146, 0x4f09dbcf, + 0xde9cc772, 0x51ea38d1, 0xda51a661, 0x65ead2e8, 0x23d7cf11, 0xea5a5b4a, 0xa002bef1, 0xc2deee19, + 0xeb90cf90, 0x1bdd3c5c, 0xf0797b5c, 0x4d56c8aa, 0xebf1443a, 0x0e5f8848, 0xd61ad101, 0xf44c42a4, + 0x15414f09, 0xd77098e7, 0x5ee1914d, 0xbd9532b1, 0x42168fee, 0x28e6e936, 0xd37d5397, 0xeada6952, + 0x21d17c84, 0xe40c49dd, 0x108eca26, 0xed56296a, 0x07f45509, 0xe5005df4, 0x8c5c2dff, 0xfea92813, + 0xda2b4bf1, 0xc08ba2e1, 0x1c3a5981, 0x7f7abc76, 0x3bb01dfe, 0x3e82aaa1, 0x8ecb21c0, 0x201b7eb5, + 0x482196b7, 0x182d7a24, 0x1722f6ec, 0xe502cbba, 0xad9b8b28, 0x228e2b59, 0x0f72fdb9, 0x123152f4, + 0xded23976, 0x2e489f82, 0x6d3ee0df, 0xa3d63125, 0x565c4afb, 0x68791a17, 0x2c28fe12, 0xb69d42e8, + 0x881ccb9e, 0xa1bb6a8d, 0xa040c8ce, 0x41854573, 0x2a5d6e2e, 0x820a67dc, 0x6dcf0caf, 0xb8bfb2c8, + 0xe19a859f, 0xfb877d69, 0xc91faf5e, 0xae766ef9, 0x8ca3b4d2, 0xcf11d179, 0xf26ccb02, 0x857e2d03, + 0x48f8a69e, 0xb4dbf074, 0xe92d4640, 0x2f423900, 0xdd79ffb3, 0x5750d90a, 0x58045a5f, 0x9b2c378f, + 0x32864934, 0x95e4353a, 0x8b398bfc, 0x70b55cfc, 0x97012c7e, 0xd5e24aec, 0x6731d1b3, 0x48ebc226, + 0x89672437, 0x2d28ee81, 0x7b149603, 0xdc32e155, 0x977f8753, 0x0ce8e2cb, 0x18281991, 0x42588569, + 0x39d1418e, 0xd6da5eda, 0x642b4a5c, 0xf8ec48fb, 0x7f664711, 0x6a535412, 0x25c20971, 0x915978fc, + 0xb7341495, 0x3f9f40a8, 0x871795ab, 0x23d301d9, 0xe7b80307, 0x0609bf8b, 0x7c87e829, 0xf959b7d9, + 0x5d2420d9, 0x2ab2f53a, 0x9dca605d, 0x5120c0fc, 0xceecf120, 0x2d611e16, 0xdf4ff30c, 0xb6cc52fb, + 0x4a5faf73, 0x1f0d6fc1, 0x46cc9793, 0x617a9aae, 0xfda4c737, 0x288969c6, 0x0a9f4b80, 0x5e319a89, + 0x477d5c34, 0xe2ef3d70, 0x966339d1, 0xce684564, 0x83af2d51, 0x9f4f2628, 0x5a88ee8c, 0xf4b0bfa5, + 0x6db3425d, 0xce451d6f, 0x6f2a53e9, 0xe9e41174, 0xfc571a6c, 0x1670ecf0, 0x4b376b4d, 0x7616a6c1, + 0x8853617c, 0xec0277b2, 0xc5736a45, 0x4c22072e, 0x1e936d65, 0xacc7c5eb, 0x14a7d65c, 0x42d132eb, + 0x9e2f1c77, 0x6413dae3, 0x017950b3, 0x1e54e24c, 0x65721063, 0x0365098d, 0x013e15ad, 0xc990d5f4, + 0x10dff7c0, 0xffc2ab62, 0xc147c483, 0x6ff9edba, 0xd9abf52a, 0xa1d7537b, 0xed216f9a, 0xcb714de5, + 0xd29ca05e, 0xa0a2ec8f, 0x1a4a2012, 0xa9ba4144, 0x1f79715b, 0x6adc31ff, 0x4d0d291f, 0xf602de55, + 0xb69fb6a9, 0xeb575c85, 0x7445a9e9, 0x385b1051, 0xc15bc459, 0x1bc003d4, 0x844f0dc1, 0xbecc44de, + 0x2c25c236, 0xa52f0a08, 0xc80aeee2, 0xaa209bf1, 0xde382e84, 0x43b0fe9b, 0xb83c1d09, 0x2a724431, + 0x99029b50, 0x28f20221, 0x7751d0ac, 0x03dc05ca, 0xdf3723ae, 0x3e6637f1, 0x4dfd2fea, 0x39d98822, + 0xbd2995e9, 0xd906ec04, 0x168f81f0, 0x39b22269, 0x143abd79, 0x8cd7c8a6, 0x831b3d21, 0xcf594cca, + 0xb921c72a, 0x9fc5a234, 0x55d0fbec, 0x7589a27c, 0x8bd7dac4, 0x67b9a400, 0x612d2eab, 0xa70771d4, + 0xd4c756a6, 0x43ee70e4, 0x10003659, 0xb3cc1090, 0x7bc2685a, 0x16c2c8b5, 0x90351619, 0x06aa683a, + 0xda34591c, 0xe2daa397, 0xdd98960a, 0x0885497c, 0x7a2bf17c, 0x84b6ab49, 0x5b3c6835, 0x0015afb6, + 0x3489b433, 0xcec96034, 0x0623a3a1, 0xe2cca1dc, 0x4b783cfc, 0x0601ceca, 0x89cc97bc, 0x713d3b24, + 0xb2d7e2e4, 0xcf222af1, 0x4dfce26b, 0xec6f1b6c, 0x0ff86b84, 0xf13e1b76, 0x341590fe, 0x86363b5f, + 0x374e92b4, 0xc0178983, 0x1aa64414, 0x578a98ce, 0xf2b52f50, 0x4de87319, 0x67200ef2, 0xe52c4101, + 0x21d8a5e1, 0xa22063cc, 0x1d0e7882, 0x6d1ebaec, 0x068971e9, 0xfe6ca3d9, 0x1163a3b3, 0xff115bd4, + 0x7368089c, 0x7286480b, 0xbb1f5fee, 0x3af095aa, 0x09f22cea, 0x4f9e1bd2, 0xfafbe980, 0xcc6e7b23, + 0xe516c9a0, 0xeab5aa5d, 0xf99a0da8, 0xad5d5bb8, 0xe9632a22, 0x13a090db, 0xfce40b99, 0xa013961b, + 0x614782cd, 0xce169d44, 0x6433de5e, 0xd1edc4f5, 0xae59131d, 0x37e4dcf9, 0x5e1da0bb, 0x67a48046, + 0x089840f6, 0x4c181c61, 0x2518fe12, 0xeb3cbf13, 0x37c8aac9, 0x558f93f1, 0x95f11417, 0x3033a3e8, + 0x3024f142, 0x6f86eee9, 0x099cdb88, 0xdd6706a1, 0x4f1b105e, 0xc0ac7573, 0xca381e11, 0xfc5916b6, + 0xb6040daf, 0xee0c2e92, 0x983cc9ff, 0xbe618b41, 0x4399b558, 0xa40b3211, 0x332f9714, 0xa3804fc5, + 0x52feadba, 0xd52ca3cd, 0xcbc279ba, 0xd44f56d6, 0x4a0ab377, 0x027e218f, 0x1e534958, 0x37552b9e, + 0x9761e038, 0xa23e86a6, 0x116a9b41, 0x2d0b1f6d, 0xf16d572c, 0xf897617f, 0xb56d3dd8, 0xe6e2f78f, + 0x9db48f44, 0x411d8628, 0x2deaa2d7, 0x01b02bc5, 0x3937c6a4, 0xc737e243, 0x3cd3dded, 0xae4691ad, + 0xe9b11f94, 0x282cbcd3, 0xd22cd298, 0x2ee306fd, 0xc38041aa, 0x9b2f4362, 0xe525bc66, 0x293c892d, + 0xcfed5315, 0x27f4a06d, 0xea70b3d8, 0xda6d733b, 0x3d8456a9, 0x978e905a, 0xbcd50896, 0xe213b4a8, + 0x9a882442, 0xab4e1d7d, 0xf28f7f9e, 0x98cf670a, 0x5698df8d, 0x67450862, 0x63e316e6, 0xf786511c, + 0xd2898b98, 0x9f18ac05, 0x5e438a95, 0xfa64de5a, 0x45ae6732, 0x2d8ad29f, 0x30c22b30, 0x15334b14, + 0x11e40e82, 0xc2bca40d, 0x4a92cc5e, 0x1adbe429, 0xe6c611e2, 0x3c9c2d05, 0x6794edd6, 0xc22cc352, + 0x60ff580f, 0x4fe05108, 0xad52940a, 0x5f3846f7, 0x3d01ac6e, 0xf38f23ef, 0xc045f697, 0xfd090038, + 0x0e7dcda4, 0x0d731cb8, 0xa4b773d4, 0x5be0c93f, 0xcc6553f2, 0x0832409c, 0xd2af9e9e, 0x36ae74e4, + 0x1529d05e, 0x549dd914, 0xde77cc81, 0x19b0e2f5, 0x0901f651, 0x709e3d23, 0x78bc29c7, 0x4807e79e, + 0x265c6785, 0x0c1a690d, 0xfc691820, 0x15395067, 0xce84577e, 0x76703629, 0xdd775d2d, 0x0e30c2b9, + 0xd85611c1, 0x4dcf3d54, 0x8d60151f, 0xb6f88148, 0x7ab50050, 0x254728df, 0xd6e8965e, 0xe9c765c6, + 0xb326cc47, 0xe0faa978, 0x9cbb1de5, 0xf551ae5f, 0xd9ba5798, 0xc6390dac, 0x1cefcf7b, 0x2794ddf2, + 0xb77eda67, 0xc49052e6, 0xc514a075, 0x48368808, 0xe70d1603, 0xa9e1c1f0, 0x6b3951fc, 0xc6bbd4e6, + 0xe4557239, 0xf7b0e06b, 0xac77dcae, 0x275f014f, 0x2cb79526, 0xe5c1d388, 0x15601771, 0xc6029172, + 0x15f82b87, 0x8a992da8, 0x3c4f8cd8, 0x25c4b7dc, 0x1eb3ae90, 0xf28a6231, 0x9eaa4f64, 0xe9468748, + 0x1a69224f, 0x938bb596, 0x6c059416, 0x4dfb7956, 0x87b23c10, 0x07a04de9, 0xd8eae4af, 0x46876f0b, + 0x68514f53, 0x310eac97, 0xd60f7bb9, 0xad7cd76d, 0xa6c2b817, 0x0dc8be0d, 0x262cfc11, 0xd1daf994, + 0x8f2d60e5, 0xf5b7101b, 0xb0b164c0, 0x210a09be, 0x6feb0966, 0x4abbe46a, 0x6acaa72c, 0xbbd93713, + 0xb96e1520, 0x15f4c9ed, 0x45d1266b, 0xc5b71d17, 0x801dba87, 0x98d7b025, 0x45b993ca, 0xe69d4732, + 0x5389bce5, 0xf0484918, 0x7e227ef1, 0x534565f7, 0x0909ecd4, 0xfd3d98db, 0x2a97819e, 0xc1281216, + 0x62a8e0a5, 0x200442ca, 0x1af1c025, 0xbb8bf576, 0xd6712785, 0x427d52e4, 0x108f84e0, 0x0e8cd3c4, + 0xabb4ad93, 0x7ad9f9e8, 0xdd9423ba, 0xb05cc0e0, 0xa8f1cb79, 0xcb4c5765, 0xa37a506d, 0x4bf9a5ca, + 0x07a073e8, 0xa1d2622e, 0xfdabc0e6, 0x951e3c27, 0x63d148e2, 0x939ad0f0, 0x29525a46, 0x311adadb, + 0xcc76eed0, 0x96ad3585, 0x2c08eb33, 0xb3d31251, 0x6db63d2c, 0x1588ecd0, 0x18c5f341, 0xfc2acbe4, + 0x4e639f0b, 0x912dbb3b, 0x4baa88f9, 0x70e8b98f, 0x425ce53e, 0xea08bce2, 0x29bc2f91, 0xac5eaa62, + 0xfb4b56b4, 0x18575639, 0x7d43ceed, 0x96dab1a1, 0xe1646778, 0x9d68b63a, 0xb58638a4, 0x8bc6cf4f, + 0x30f0365c, 0xe42ec54d, 0x6c07f688, 0x8897bc95, 0x96223af0, 0xd50a59ef, 0x960ef2b7, 0x634cdee4, + 0xc846f19a, 0xb48cb95b, 0x44fe4aa5, 0x8f778228, 0x423fbd15, 0x5b40740d, 0xab51acfb, 0xb484398b, + 0x6bbb33dd, 0xdb813471, 0xb4046784, 0xbf215e96, 0xf15716db, 0xb6445c93, 0x80df65ef, 0x8bb5d226, + 0xf708838e, 0x2caf050b, 0xf8065c89, 0x1278f29e, 0xaa5362a0, 0xf72e9080, 0xfbd2452d, 0xf229bb5d, + 0xbf557de9, 0xd7c2529a, 0xfd4cda3c, 0xe79c8672, 0x8b274a14, 0x3c0479c7, 0x9254685a, 0xaaeedd05, + 0xa14482c6, 0x1d65d3dd, 0x143694ad, 0xe1dfb46f, 0x6612a41f, 0xde3390f3, 0x437d630f, 0xf2701fd8, + 0x51b9cfe9, 0x0a455432, 0xc295db23, 0x2bb62a5b, 0xb204d0e8, 0x6746103e, 0xa0eff544, 0x0bba778a, + 0x86f1078e, 0xcb59c4a9, 0x27934279, 0xb46e3ca7, 0xb9b49d7e, 0x38d0a791, 0xf1ee2d08, 0x1b100e82, + 0x4ba518b3, 0x75ed5f41, 0x58f725cf, 0x0e618281, 0xa5574a16, 0x46f0d5be, 0x9d8c7768, 0x7ea8c2c3, + 0x923d9271, 0x5eaf34d3, 0x79c7d183, 0x14a8fd0c, 0x0d5b51bf, 0x5ebd7950, 0x14ea6a26, 0x836db01b, + 0xd7536e36, 0x2e87e1f8, 0xb70806df, 0xdd0fb988, 0x956656eb, 0x71824b50, 0x945074d9, 0x23322de1, + 0xd1d5c2c0, 0x0f788f73, 0x9a1fac27, 0x168da944, 0xeece3bef, 0x6a2262e0, 0x0440ccb0, 0x479e6c92, + 0x5ce3fa8a, 0x2075b595, 0x652c3e86, 0xa5812635, 0xc96d9bf5, 0xa5136312, 0x983aa9a4, 0xb41ddc82, + 0xdb4a2241, 0x806460ec, 0x183637f9, 0xfb281422, 0x78691843, 0xb4a5778a, 0xfeb158ee, 0x9218ca7a, + 0xcb9baccd, 0x4740f793, 0xae756dd4, 0xd0e93bd1, 0x5f394ac7, 0x7196fe01, 0x6803c5bb, 0xb56898e6, + 0x38fb496a, 0xfd8aa499, 0xd3489c47, 0x58e42785, 0x2d9e5200, 0xfcf470a7, 0x4d36dd6d, 0x8d10a972, + 0xf531beeb, 0xd5a9751d, 0xbf706d38, 0x12af2d21, 0x3804a901, 0xee4b2926, 0x724a1e6a, 0x1f49fcfc, + 0xb0dc2751, 0x535504bb, 0x571ea1f0, 0x9a367ff0, 0x608c7c3f, 0xf8a002e6, 0x6eac9618, 0xf8481f7d, + 0x58e023b6, 0x17397392, 0x0e1c3a37, 0x3a8e33d7, 0x6bf9a536, 0x9800d55f, 0x1f8a238e, 0x4a497edb, + 0x4075c90e, 0x47e918aa, 0xcb184527, 0x307019fd, 0x8f25f29d, 0xd839eaa1, 0xe1894005, 0x43980af8, + 0xc548731c, 0xb19aa6c3, 0x64041f13, 0x45d2b126, 0x19710770, 0xbc4bc2ef, 0xec8107d1, 0xf897d70c, + 0x92d1c238, 0x59503c44, 0xa5a4d885, 0x4cce0663, 0x9144eb1c, 0xdf9190ba, 0xf5278dfb, 0x5bfe1c63, + 0x82172a29, 0x5db3569b, 0x6a0ab6f7, 0x85882bb9, 0xa5501135, 0xb46f125f, 0xd404ea8f, 0x22ca5a64, + 0xbf5b7905, 0x1fe2e366, 0x2308bd61, 0x97d85545, 0x188034ac, 0x059b1af2, 0x23bb66b6, 0xbfbf80fd, + 0x3e248157, 0x81dd2ce0, 0x8dbd59b3, 0xabdbfe7d, 0x5aab6b45, 0x4f35d9ff, 0xbcdb779e, 0xd0c08a07, + 0xfcd45320, 0x798e0a65, 0xdf20eb07, 0x34f8694e, 0x1c770666, 0x656f5851, 0xc2110048, 0xef4c9825, + 0xa66a7b86, 0xa9b737f2, 0x5d9e546a, 0xe23ab35b, 0x9de51a14, 0x146c5f47, 0x0237ed3e, 0x3d923162, + 0x421f596b, 0x882edd66, 0xf74a2293, 0x7b6e5b19, 0xad4d5830, 0x6cead3a8, 0x61adbb39, 0x49c719e5, + 0xdd650415, 0xca931f31, 0xc74ecbe9, 0x266386a7, 0x0d42f1a4, 0x13e3d3a0, 0xe0a35fd5, 0xac3cdb15, + 0xaddd3c63, 0x9d0f479b, 0xcfa8ad38, 0x9efaf5ed, 0x6ce6a128, 0x4e7651d7, 0x64c35ab4, 0xb7afe7e6, + 0x20d00302, 0x0718e1f1, 0x9f2c8340, 0xfd1daef8, 0xa74fac13, 0x66e13a4e, 0x4e98435a, 0x10df673a, + 0xb6747958, 0x6bcb60f5, 0xbce4158b, 0x6259bed2, 0xa6002f2c, 0x40dff3b0, 0x1fae6336, 0xf92e0164, + 0x2d680e92, 0xf9799a6a, 0x1a67cf71, 0x7c761c44, 0x166cfe2e, 0x286d4b0f, 0x48d9a451, 0x248cbb97, + 0xfaedb501, 0x06cfcbf3, 0xa46d054b, 0x11efbcb7, 0x2a7a9b08, 0x436ca416, 0x0091a7da, 0xe705853a, + 0x124b6d44, 0x7237703b, 0x57652c28, 0x2f12db11, 0xde851d5d, 0x6a2c4895, 0x99f5e336, 0x67e6d388, + 0x1ad75a86, 0xa85bc994, 0x21efee66, 0x92b14a16, 0xdea5cbad, 0x9538956b, 0xdeff2973, 0x20fa88af, + 0xb24cf246, 0x54dcaac7, 0x35f9434f, 0x341701e9, 0xe34451dc, 0xf3f7ce3e, 0xa9274ddf, 0xdcffa15b, + 0x1b7fcd81, 0x8b7788b2, 0xeed33956, 0xec54aae4, 0x5ec185e6, 0xe4d9db6b, 0x6ab131f2, 0x278febb0, + 0xdeb5cc9a, 0xe5e16b56, 0x34dedee3, 0x0d18ecd5, 0xe39a969a, 0x11792fc6, 0xdf55d94b, 0x54afe658, + 0x112a8ec2, 0x385e89a8, 0x75d09b3f, 0x3dfde633, 0x7ac9c8bb, 0xe31acfd0, 0x1ab0661b, 0xae2bce96, + 0x0c60638a, 0x0c83492d, 0x95d61b20, 0x507dc3dd, 0x24eb3fdf, 0x74dbdf7a, 0x41c556d7, 0x58a46242, + 0x004d0ad7, 0x0aad4ab7, 0x82dce589, 0x8550c98b, 0x31b2a19f, 0x712cd22a, 0xb9f104dd, 0x10bd45c3, + 0xc9981e3e, 0xc0233ce5, 0x8a49a2ef, 0xee838f6b, 0x57dfc629, 0x50f5b110, 0x0c23b119, 0xbc27c7e8, + 0x37add957, 0xf5219fa0, 0x7f574918, 0x81d51d31, 0xd084e8c8, 0xf3979f4f, 0xd1b98d82, 0x632df3e2, + 0xfa56e889, 0x14466593, 0xbe5b3c45, 0x2e6a2e27, 0x01a6f752, 0x6e5a4db7, 0x961c96a0, 0xe98733e0, + 0x32930ef9, 0x8bd935cb, 0x319d7323, 0x099f3234, 0x8044141c, 0x74cff4e6, 0xbf07f58b, 0x3507c13d, + 0x03e71459, 0xe3a622da, 0x3ea22532, 0x1c6c91ff, 0x7dda5782, 0xff547f35, 0x462c2d50, 0xa1bee963, + 0x75257595, 0xf7c526e9, 0x8b18c3f6, 0x3c228bac, 0xb121f930, 0x9d1a0840, 0xacd2676c, 0x4d827630, + 0xf12a2f87, 0x900624fa, 0x60b463c3, 0x669e525b, 0xd7fefa7f, 0x96e4ce98, 0xe4a58e4e, 0xd4facc88, + 0xf3be72c7, 0x01ca0052, 0xdf927440, 0x65b3e648, 0xfe80e75a, 0x17fdce18, 0x610ec9fa, 0x7ecfd059, + 0x066f4a68, 0xa55688e1, 0x4f2df852, 0xfd63cd72, 0x55ac0ccf, 0xf300a4a5, 0x46bf3c5e, 0x08744922, + 0x8766e5b4, 0x54de2a50, 0x9e2b0622, 0x22c7180d, 0xdad6b9e2, 0x6ac0a2b4, 0xacd63d88, 0x1b95c283, + 0x023cd23d, 0xad931003, 0x5ce67a2f, 0xc3e5a1dd, 0xe283d568, 0xed5dde21, 0xc226cc77, 0x294e0e4e, + 0xb1750995, 0xa38789ce, 0x125c482d, 0x53ae99f8, 0x026916e1, 0xac0ca1e8, 0x7dbd5b51, 0xd0489c01, + 0xf275cdee, 0x61f03bea, 0x751d5196, 0x38bc0ba8, 0x992925ad, 0x8e9c3e6a, 0x84d8de17, 0x89816c5a, + 0xd049db69, 0xe3bd73ab, 0xb0db4a15, 0x513d36c1, 0x825554d8, 0xfbe0cf2e, 0xf181c983, 0xf06e2fe9, + 0x5d6bc3c2, 0xdd4943bf, 0xdeac8839, 0xe1b21b60, 0xf5de2ecd, 0x1d263007, 0x8aaa2383, 0x879fbf6f, + 0x0c117533, 0x0b70ddeb, 0x2fb74b12, 0xf9cd9f82, 0xa0dfb688, 0xf124b4e3, 0x3167eb53, 0xa018e47e, + 0x0f9ef6bd, 0x4a7a4ef5, 0xf3889c58, 0x3b2f6145, 0xe5997b81, 0x4489b2a1, 0x29d89905, 0xcdf9384a, + 0xdc38cc9c, 0x6f2cdb89, 0xa16a270b, 0xd0e256f3, 0x39135fcb, 0x90c8508e, 0xf3d29eeb, 0x31854624, + 0x8fffd4fb, 0xc55cbd39, 0xe47c7c7b, 0xee1a4675, 0xf2390d38, 0x4cd711a6, 0xc46a6a58, 0x2d82b595, + 0x5a6aa783, 0x55b6eb3b, 0x059c5471, 0xdc545daf, 0xaf4d801d, 0x69036fe5, 0x9920ac09, 0x02db13ae, + 0x1994470e, 0x8c368bad, 0x306407a7, 0xedcdee0e, 0xb35705e1, 0xfe7968ab, 0x057d744d, 0x108cdb88, + 0x9bc9fc39, 0xdcf2a150, 0x5920a130, 0xd7309797, 0xe7432f51, 0xab3ca2ca, 0x675527dd, 0x43ec0351, + 0x1b2cc70b, 0x393b5885, 0x49c355db, 0x8a8f0662, 0x6032cc37, 0xf382c1b4, 0xf8781fbb, 0x5d9b4f01, + 0x2944706d, 0x17662038, 0xcbc11d90, 0x03fa3ca6, 0x959fa620, 0xacba35c8, 0xa0592429, 0x6e2f8da6, + 0x8ee22fc9, 0x9970baae, 0x67e265d8, 0xdcd48050, 0x263d3753, 0x938899f1, 0x02733b96, 0xdd38455e, + 0x253d5795, 0xa8e3738b, 0x9770975d, 0x8f9899b0, 0xc2baf18c, 0x93df2492, 0xbbade281, 0x52e900b7, + 0x86d9909f, 0x233c4e67, 0x67b29b8e, 0x4a263bfc, 0x217b9e71, 0xe87ba100, 0xb2081099, 0x580c3602, + 0x3c7426a1, 0x24385f7d, 0x138062fe, 0xce01781f, 0x469c954a, 0xacabe801, 0x47952193, 0xd3138e94, + 0x3e6b18b7, 0x0084e991, 0xb39ab0d1, 0x3c4e8698, 0x9db0f02a, 0x05ca4a6c, 0x68161660, 0x6365afcf, + 0xfe7c2c9b, 0x2e0ca2f6, 0x0de81591, 0x59530f41, 0x3755299e, 0x8951bdbf, 0x90ce9043, 0x96847976, + 0x75263c8d, 0xc6feca9b, 0x2a1299d4, 0xc151b5dc, 0x4fef4e0c, 0x8b9371bd, 0x260abd19, 0x96804723, + 0x0104776d, 0x0d089f9b, 0x646f75be, 0xbba86b30, 0xb3575a2d, 0x68358d00, 0x21c9b287, 0xa65e6a28, + 0xedabeffe, 0x9ccdec13, 0xe9a805ab, 0xc0c35376, 0x3c841106, 0xfb4dc78b, 0x9cc21d3f, 0xea3ec0d8, + 0x25d6ba47, 0xec63d289, 0x3803e7c4, 0x04feb5a0, 0x98ee239f, 0xb6e6d137, 0x75eccc6b, 0x3f327184, + 0x671596a0, 0xa08b6a5b, 0x0bca7779, 0xb687cc6b, 0x6d028606, 0x8969cdc1, 0x9b5ccec4, 0x093bf3b5, + 0x2ee44040, 0x42b7e533, 0xbdb2f9ab, 0xad4916cf, 0x8ec953aa, 0x4c869ce2, 0xc40abb60, 0xaac46459, + 0x96110b50, 0x50eb5bb6, 0x8f71e7c5, 0x00becc1e, 0x08da58de, 0x9e283138, 0xb2631843, 0x8c9d46d6, + 0x5a8f4929, 0x953f3773, 0xc44c858f, 0xa2b0a933, 0xa60e6a65, 0x594689f7, 0xa4fa2f87, 0x472f5be5, + 0x3791c1f8, 0x15767f1b, 0x7bd3528e, 0x77e0c746, 0x08f97807, 0xd0658dd3, 0xbd160588, 0x6fba83bf, + 0x0d4a30b4, 0x288f435d, 0xcaf84c6c, 0x3ca69254, 0xb4d22840, 0x3af925a3, 0x82eab3ff, 0xd2343fae, + 0x288f025c, 0x5cb97759, 0xc8c85692, 0xb1a71f96, 0x3b4c6cb2, 0x1de25ce3, 0xab7bc371, 0x802889d1, + 0x7d4f1ea5, 0x8431f79f, 0xa933f2d1, 0x58d325a4, 0x15a17320, 0x024552c8, 0x5378e29b, 0x8c33cc6c, + 0x9b0b0ade, 0x6373a3b0, 0xa16c60de, 0xd40ffff5, 0x334f1a19, 0x7d195566, 0xb5f86898, 0x4d64e1d7, + 0x4c9ca5fd, 0x7f1f3313, 0x30013306, 0xea8d1551, 0xbc14dbd5, 0x2186e991, 0x1eb5a04e, 0x5689b9b1, + 0x0e5bcdbf, 0x40ee3943, 0xb7e06c50, 0x5e197a89, 0x6549d8b0, 0x99fa0ede, 0xa04353f8, 0x99fbebfb, + 0x6bfcc2bf, 0x089d8fd6, 0x274cfb26, 0xbccfb003, 0x0659b886, 0x55f8d60f, 0x5fb7dd2f, 0xc0702858, + 0xfa327edc, 0xf1c81c74, 0x83ac2e76, 0x38cb41ab, 0xc588c676, 0x5429f255, 0xbed76d66, 0xf5b960da, + 0xf438566c, 0xec4bf3c1, 0x8d9c8650, 0x9c301d54, 0x7d988a89, 0xcbfd03b7, 0x5162edc3, 0xad500497, + 0x4e7a1157, 0xbbdd371b, 0x17ad0e1c, 0x249f4579, 0xc2bb3437, 0x8d0f0fe9, 0x92283041, 0x6beeb579, + 0xd63f0be5, 0xab6860e5, 0xe2accf1c, 0x399acb91, 0x7971524e, 0xd29f527f, 0xa46fe70d, 0x1592542b, + 0xef6e61d8, 0x14e89c06, 0xbc2f4b3f, 0x8f62d408, 0xa37ed210, 0x990fad08, 0x7bbbdc0b, 0xa33121bc, + 0x4ed7b964, 0xff1f6c98, 0x0c18e69a, 0x717d8944, 0x243406b3, 0xb193790c, 0x88b9c2d7, 0x0cd28f68, + 0x7139ba2f, 0x1b1dccad, 0x72ce2fa3, 0x38d85aec, 0xd62520ba, 0x94bb4b98, 0x04995c60, 0xd2fc689d, + 0x7e08cc0a, 0xf67b2bee, 0xf9e9c64e, 0xc82fa175, 0xb2e5a59c, 0x1d02dc38, 0x53198d25, 0x89898067, + 0x418a2fef, 0xc749282d, 0x46db7d5c, 0xf2b3225b, 0x0b304f47, 0xbbdb8c62, 0xf6dd386b, 0xe3358787, + 0xa60c7c5e, 0xcc385582, 0xfea550a4, 0x77ebb688, 0xc866ac78, 0x8b3af4c0, 0xce5af4fb, 0x712564e1, + 0xaf51a941, 0xec9c804b, 0x4552c051, 0xefcf817f, 0x68b28a30, 0x435a0953, 0x426a1bc9, 0x66f6d4a7, + 0x3e2a6c9c, 0xe0f894c7, 0xb80797cd, 0x7c26f4d8, 0x4c11143d, 0x23cf3dac, 0x08dac7b1, 0x33084521, + 0x5b186874, 0xb7c6063e, 0x1619fecc, 0x171e9c40, 0xf67976da, 0xd7f61474, 0x6fb47b9e, 0xa4f458b1, + 0x499c86a6, 0x2606ebaf, 0x310c0fb9, 0x762e81a3, 0xbc021357, 0xa8626735, 0x516dea22, 0x83df392a, + 0xc94b8391, 0x7bd8e512, 0x1f518a9b, 0x34bec75e, 0x28a9fca2, 0xb6bb3140, 0x269527ef, 0x7611b5a8, + 0x449df40e, 0x93f035f8, 0xafd2521a, 0x5ee63b58, 0x5e46dafc, 0x9cf4ebe3, 0xda251e5c, 0x7cf00d14, + 0x86e98698, 0x21a0102c, 0xbd0e65a3, 0x036f9e12, 0x1160ebad, 0xfcfffb1d, 0xc57870c9, 0x83b7f3b3, + 0xa95e13f5, 0xab66ec2f, 0xe7b9ffd7, 0x73d83727, 0xd27edb9b, 0x2d45cd2d, 0xf38f13da, 0x6e55cb65, + 0x8a2bc57d, 0xd99e6a3b, 0x33d73f03, 0x5e260bcf, 0x341014e4, 0x18408784, 0xf9621d42, 0x77ee21f3, + 0x7ab1a367, 0x2106e2a5, 0xed2f174e, 0x12af80b0, 0x71f79fe3, 0x848525e1, 0x56a214ad, 0x45317e93, + 0x0ee6c982, 0x17b9321a, 0x0b82cc99, 0xbc9c1874, 0xe2fa59fc, 0xf8d51a00, 0x2324f29d, 0x1ec9c05e, + 0x4999c91d, 0x2f605595, 0xebfd3edd, 0xd0bc14de, 0xdf02f2c2, 0x58b69b5f, 0x2e810888, 0x0b369cae, + 0x080f5133, 0x8a9b5dca, 0xf8e5b728, 0xba755ca2, 0xfd30d47c, 0x6240207c, 0xb2305418, 0xe159fa21, + 0xf8ab5684, 0xbd3b8b9a, 0x2495ce7e, 0xbe842f1a, 0xf25816d5, 0x4b50b624, 0xddfb7508, 0x873ceff5, + 0x428761dc, 0x97459150, 0x709e0a12, 0x3932ed14, 0x8d65ac39, 0x9104ce3e, 0x19bcaaaf, 0xe4c40de3, + 0x0631bf9b, 0xbe293e3b, 0x3be12b51, 0x69203de4, 0xac958667, 0x060c8fba, 0x56e70a6d, 0x1b35b75b, + 0x409540b2, 0x12ee27f1, 0x5ecdb6f9, 0x7874bd29, 0x6676a89c, 0xac7d020e, 0xa7bf5312, 0x4c6834b7, + 0x1c643739, 0xa9661633, 0x79f55e93, 0xb67f1c85, 0x04f3e211, 0x8c85efd2, 0x03f9e743, 0x3004dfb0, + 0xce6cdcd7, 0xa80663ad, 0x62409b79, 0x2e7ab078, 0x754057a9, 0x61db725b, 0xfb7b8122, 0x9ad90bde, + 0xf7806d7e, 0xe0b14b1f, 0x79cae866, 0x5b89d581, 0xcddb3f14, 0x186fe8c0, 0x53991454, 0xf3ab1f5e, + 0x7192f548, 0x4148b4c9, 0xbcff8a9a, 0x062d1502, 0x224bdb3a, 0xb921903a, 0xc4de3842, 0xd2fdfb2c, + 0xa1fc99fe, 0x1e858716, 0x1f433ad1, 0xed71fafd, 0xb5b18215, 0xdf83e68f, 0xbd52b4c4, 0xf7da8c4c, + 0xfd35ccf2, 0xd2473bb9, 0xf999cf74, 0xc912402a, 0xb025c7f4, 0x5b08ffda, 0xbe62d1aa, 0xf6d8a9b5, + 0x32e8b9f2, 0x103ef0a9, 0x1888642e, 0xfaede01f, 0x48eccb49, 0x07a87244, 0x9f2e0301, 0xebe37ead, + 0x2adde9f0, 0xfa099ae9, 0xfc972f10, 0x3187f4d8, 0xe0de82c1, 0xaee9dcd8, 0xfd342170, 0xf3d36a92, + 0xc8497e1c, 0xad45f850, 0x49fca786, 0x6f658235, 0x140e3402, 0x8ec2282a, 0x146232d5, 0xf4241f66, + 0x44ab881f, 0x817e476e, 0x539c7855, 0xa1749c87, 0xefe6eeab, 0x4c6044ef, 0x2d03e06e, 0x305c322c, + 0xd277728f, 0xcdaa2229, 0xe4c15451, 0x2fda9847, 0x84b8a8b0, 0x9c3c1d9e, 0xe8fd7509, 0x2c33b686, + 0x6cdcd4e1, 0xb5a3fb7c, 0x5c5994e3, 0xfb055241, 0x1c65f66c, 0x9d8423e7, 0x435fb78e, 0xf69853f1, + 0x132961c6, 0xbe0e857a, 0x67c2b6df, 0xfeef2aa7, 0xfdb6a205, 0x24760749, 0x1a35752b, 0xc5435823, + 0xa9d0de99, 0x92c76088, 0x015b1ab5, 0xef160906, 0x3372b7b3, 0x54dcad9d, 0x25dce3fd, 0x0b0c3597, + 0xce93f4cd, 0x822382ec, 0x9227d82e, 0x35a33745, 0x2bbfbeca, 0x698727d5, 0xcdf67a6f, 0xe13d1b95, + 0x21ba5d29, 0x7f5f2e55, 0xa80c4f49, 0x411d115a, 0xb2a0d3c3, 0x0366e8db, 0xade19cdd, 0x588ee9a6, + 0x22d8cf07, 0x1d102774, 0xe3a1c2c1, 0x88f530cf, 0x3ce11c61, 0x82fa3fa1, 0x8c186e14, 0xaa0959d2, + 0x25fb2b8a, 0xee287e2a, 0x771beb25, 0xfda6fcc5, 0xfb167dcf, 0xc83c381c, 0x098d5293, 0xc0738c93, + 0x43375662, 0xb0f9df24, 0x12d32283, 0x10f2cf5e, 0xda962c98, 0x7180ca56, 0x359fc239, 0x806328f8, + 0xa6ad255d, 0x57ab6bed, 0xbb996b22, 0xc2dc0d9c, 0x78d9d49d, 0xa1667744, 0x6449c577, 0x7d0cf9c7, + 0xe02dc6c8, 0x0015ede3, 0x6367ce4d, 0x1f789dd4, 0xa63a59f3, 0xb477d671, 0x73731153, 0x278cb21a, + 0x2b59cfb3, 0x63ca03fa, 0x43cb8e94, 0x70aca8b6, 0x2cba450e, 0x0fd8486e, 0x5998a04a, 0xfd9f0a59, + 0x356f9c19, 0xeb27218c, 0x96f581c8, 0x3619be1b, 0xdd329fa8, 0x69cf721b, 0x1e84e2f5, 0x97f91884, + 0x96e32fe0, 0x142e5994, 0x0751fa41, 0xb99b82d0, 0xae9ceeeb, 0x96539bbe, 0x4bb2cc1b, 0x0095c97e, + 0x702f1422, 0x4008e264, 0xbbf91d05, 0x8dc92be1, 0x23a2e6a0, 0xd175171b, 0x7f16c06b, 0x10e7e7ce, + 0x080c071c, 0xceece868, 0xca900c8b, 0x2ad8111a, 0xf2dbb232, 0xb140b578, 0xaa2318b5, 0x15a5df28, + 0x7c2eaf9f, 0x81d4ac4f, 0x34001bb1, 0xc3811a64, 0xb79b3578, 0xa6b29bb4, 0x67777742, 0x65b6542c, + 0x99194ac9, 0x970a28e4, 0xcc1b779d, 0x3b6f75ea, 0x059d70bf, 0xd76b223e, 0x86507fb1, 0x26f76111, + 0x39b68807, 0x3aa7351f, 0xd427625f, 0xf4cfe720, 0x04eea40d, 0xd16c3529, 0x774ede30, 0x658bb0c8, + 0x91ef6e6f, 0x24ed14b7, 0xec5249cd, 0x27731320, 0xc9969735, 0xf7758e67, 0xb1503b40, 0x8774ec8b, + 0xdf26fd39, 0x7b634b0d, 0xa3415fb3, 0x45fa131b, 0x697763ca, 0x03375efb, 0xd7494fd8, 0xbdf5895f, + 0x685d4d9a, 0xdc977a9f, 0xf154c87c, 0x7e0da97a, 0xb7ec3d1d, 0xa3f803fa, 0x2e16c706, 0x0c332689, + 0x30d5acc3, 0x18d236ab, 0x16152ecb, 0xedd6f43f, 0x216ac1c6, 0x34834f39, 0x6337fb71, 0xbfb1a170, + 0x36cc4768, 0x17ab59e8, 0x8a3ba69c, 0x62f890c5, 0x475669c7, 0x8168174b, 0x2da226c3, 0x4f82355f, + 0x504e9cff, 0x078fc9b2, 0x9d48c1fe, 0x91278377, 0x531f086e, 0x3e351140, 0x414d7028, 0x7f4f62cc, + 0xb9d110e2, 0xb13da15c, 0x784cc8a1, 0x4fc2b21a, 0x03543d80, 0xf54d201d, 0xce5070d3, 0xd3e7c1c0, + 0x153129f2, 0xa4c9c59b, 0x275deeb3, 0x0620f009, 0xc2aa3873, 0x9e4cec60, 0x37160e0f, 0x9f623018, + 0xf2df1021, 0xf7310a8f, 0x05de36b3, 0x8ac1d8ce, 0xe615a205, 0x75d1b656, 0xc07ad662, 0x99b0115b, + 0xfd71e7f9, 0x33f9b105, 0x204c573d, 0x4655b2cf, 0x6a75b1e6, 0x3fdd6eac, 0x8232efd2, 0xd44aaca4, + 0x80f9ae35, 0xf435341d, 0x2410dfed, 0xd362be00, 0x18a97e36, 0x2e4c6a3c, 0xe563c8f5, 0x11c06843, + 0xc7d5de52, 0xae5a75c2, 0x3f2eae48, 0x56f35ce2, 0x84f02bc7, 0x6424810b, 0xbf0f18e0, 0x6e5c4fd8, + 0xf080b017, 0x4da4d290, 0x838fd3cd, 0xf6475bb1, 0x2bf62bdd, 0x6c0f69ec, 0x9cded21d, 0x4526eb60, + 0xdde0fd57, 0xf7e09cf5, 0x1adf2cc8, 0x5b73c3fb, 0x4f3a27c5, 0x8639c72b, 0xa3c9348d, 0xbbf1d904, + 0x4bf78c46, 0x027450d8, 0x2f20776d, 0x6a741b1a, 0xf671e821, 0x5801c3ad, 0x1c8c57fd, 0x19607a1b, + 0xef14d108, 0x3f613d69, 0x13ef157d, 0xa559647e, 0x1c4de367, 0x0d628e03, 0x4a93cdd8, 0x6f643479, + 0x5d753206, 0x9d05d91c, 0xe1a37fff, 0xa2568f83, 0x4fc1d111, 0x702f465f, 0x1983f603, 0xd4591b19, + 0x04ad5236, 0xe82bd799, 0xe8fec672, 0x900d5370, 0x629f450d, 0xbac8b6de, 0xdb0e091b, 0x3488b648, + 0x7dcf85cf, 0x5cca862f, 0x51e5bb74, 0x62874711, 0x2163b615, 0xb2da3a4f, 0x071a6016, 0x8fe7a8c5, + 0x45715829, 0x98825d0d, 0x21be28fa, 0x22dc01cd, 0x2e7351f0, 0xcab99edf, 0xc2f65391, 0x5f56ed76, + 0xde17a435, 0xbe66bf46, 0x4ec19e4c, 0xe8db3e86, 0x1146f369, 0xd683408c, 0xfd476b03, 0xfba0d5d2, + 0xc4706c3f, 0xdf14d9ab, 0x68523f08, 0xad24093a, 0xadfe0bc9, 0x1d0f5731, 0xdda248ee, 0x0bb8b688, + 0xcbdbfeff, 0xb65ae88c, 0x87bce34a, 0xbc63c3d1, 0xb7cdee46, 0xee255e49, 0x1a513429, 0xd830e28f, + 0x3ac4c182, 0x206a4f65, 0x2e591006, 0xb50aea90, 0x295dea2a, 0x633e1ced, 0xb4db6bb4, 0xc0ee27ca, + 0x0d925fba, 0xf506a5c1, 0x61990079, 0xb4cee538, 0xea98e71b, 0x3c2fdc83, 0xc7d48dc0, 0x65fb9abc, + 0xa3e2cecc, 0x014f78af, 0xf9772c78, 0x1e318419, 0x3699888b, 0x1b06cde2, 0xb8c941ca, 0xe26b9187, + 0xf42eaec9, 0xc18fa842, 0xd6498714, 0x075b54bb, 0xa25fdd91, 0x2fdc1537, 0xf4af556d, 0x0bbe4840, + 0x8b00813d, 0x2b7f4ebc, 0xc6c9e047, 0xf2137f7e, 0xa90bde60, 0xf3716daa, 0xb4747f27, 0x1d83a868, + 0x1ace9d72, 0x17b9def2, 0x8a48dd70, 0x4d700688, 0x8b7f870b, 0x503966d4, 0xc5951649, 0x08038511, + 0x7fa40f5f, 0x7d90f27f, 0xa1503f88, 0x266f4c64, 0x4fa9ad45, 0xae3808a2, 0x01763c5c, 0x1cfb3593, + 0x611a0f89, 0x3a0e5f8a, 0xade5987d, 0x30262607, 0x0958e5f9, 0x45e69d52, 0xfd1c2246, 0x9a8679f6, + 0x01079381, 0xc250fa30, 0xead64afb, 0xc56e6e4e, 0xc2b86ec7, 0x3b37ce84, 0xd63e7cfa, 0xa0f1f2bd, + 0x15806065, 0x17a7dbac, 0xb995759f, 0x1d0f34af, 0x31811ae0, 0x5145e2b2, 0xc45ac9c1, 0xb078bfb7, + 0x8f7389cf, 0x0fa1127d, 0x4c14085b, 0x218e2045, 0x397ded62, 0x03f28c4e, 0x7f2b6730, 0xaa51b4e5, + 0x63528d45, 0x185be5c4, 0x238fa0a6, 0x032909e7, 0xd9cf60d3, 0x8159f5aa, 0xe5b8b32e, 0x9c6261e3, + 0x109f1aa7, 0xcf481f75, 0xf4a015bc, 0xf269a1bf, 0x35ffe0a0, 0x16df5d17, 0xbc91c898, 0x8f854e38, + 0xaa72a795, 0xecbfbae5, 0xa723baf8, 0x0243a601, 0xb01471a8, 0x4937503f, 0xe9c3c8d7, 0x95ed65fe, + 0x11658c30, 0x7b46958c, 0xab894114, 0x8b3086f7, 0x8aa134bb, 0x30f21f57, 0x6a3c36d7, 0x5829727d, + 0xa8e1a4e5, 0xc2d4761e, 0x81f0c29c, 0x31604668, 0x479ff257, 0x598789be, 0x404bae31, 0x97f29086, + 0xff46bbb2, 0xa38e83bd, 0xf4fbbaf7, 0x83fd301b, 0xb1807392, 0xcfe9c301, 0xbd5cd38c, 0x0d60748b, + 0x6a145a5c, 0x6a41add1, 0xd954c1f0, 0xf5e3d7f4, 0x970ce71e, 0xa50ce842, 0xa48af7a0, 0x7d7435a7, + 0x7fa1e589, 0x219282f9, 0x759b9ac9, 0xfe233e71, 0x8f830c35, 0x5da98b75, 0x2cb90538, 0x17fdc532, + 0x6735bffb, 0x8da946a2, 0x562a171a, 0x1d80843a, 0x5e64c1e2, 0x060c40f1, 0xcc2ddf57, 0xd1b78c5d, + 0x2d2fb51d, 0x61d0772f, 0x0cb4d319, 0xcc4f5e68, 0x8471672b, 0x6d0ac553, 0x5eba32d0, 0x3cc4a69c, + 0x235d9665, 0x65064890, 0x4413794b, 0x5522ea3c, 0x2b3eb492, 0xf817613f, 0x1886e229, 0xc8013642, + 0x6902b326, 0xe4af63a8, 0x98970d24, 0x2ca4ac8c, 0x09172aa2, 0xa170150a, 0x6a991437, 0x1117c5a3, + 0x12934006, 0x727fe578, 0x1ee3e521, 0xb3c6dc1c, 0x7291d7cd, 0x68e7981e, 0xd78dc247, 0x6f2927f6, + 0xe9e313b3, 0x8372b851, 0x5521fc1b, 0x673f90f3, 0x25fdc22e, 0x562482b3, 0x2b905ebc, 0xda3fe507, + 0xef679615, 0xc074d215, 0x7f509875, 0xf5c54f02, 0x97dc05db, 0x379e15cf, 0xcfc8874f, 0x3b9b19b2, + 0x4d2d46f5, 0x8b4ea7e0, 0x96b23c67, 0x25786091, 0xc1c26761, 0x4c1e7fe9, 0xa6993b64, 0x61fff413, + 0x8bad48bf, 0x31ea077c, 0x92d1bfb1, 0xa8f680fd, 0x0be8f11f, 0xf6dbda3a, 0xa1afa99e, 0xd8ecf072, + 0xe7736c62, 0xce0b9266, 0x80ac7980, 0xb18aee41, 0x7b1e8fa9, 0x208a0b6f, 0x7245f138, 0x352dee4f, + 0x22758250, 0x52dd239e, 0xe8a075f6, 0x6139695e, 0xa694f88a, 0xd77a6002, 0x46fc92f6, 0xfcfa9de2, + 0x9cd6edbb, 0x52ec8b5a, 0x61469bbc, 0x3fef1a4e, 0xc2e6a7b6, 0x56da63be, 0x3331946e, 0xa44da7f3, + 0xec08a6ab, 0x0c3addf7, 0xd41ae18a, 0x2b8a8cb3, 0xf24532d1, 0x40e86b14, 0x5f3ab20b, 0x2d47cbd7, + 0x0f92f620, 0x7086a0d5, 0x42e4f2bd, 0x1fa5a5c1, 0x224efac4, 0xa389490f, 0x34de0997, 0x1388767f, + 0x35818ebe, 0xdc536f7f, 0xf6bf2e43, 0x5d0fc532, 0xcae39b16, 0x7624c578, 0x88375803, 0x3632cabc, + 0x3a03b930, 0x868b0e63, 0x53ca2a11, 0x2e7034e0, 0x024dba96, 0xae94b6bf, 0x1b03d498, 0x38bcd168, + 0x4d72927a, 0x1b62ae8f, 0xef765353, 0xbe970655, 0xeec37535, 0xe15af283, 0x6f60ce35, 0xe0368352, + 0x7f1a683b, 0xa2fce942, 0x8db414dd, 0x074fe9c9, 0x30dc0089, 0x3b080b0f, 0x355abc21, 0xc9ca93ee, + 0x661c984a, 0x5a5ba9f9, 0x5b383df2, 0x45680794, 0xbce8269d, 0x83b4c653, 0xfd8585e4, 0x23af00e8, + 0x930092c1, 0xccfa77bf, 0x181f17f6, 0x76720187, 0x23753636, 0xb1daabf7, 0x822679ff, 0x695356ac, + 0x9ec8f335, 0xc6ae001c, 0xdf9b5938, 0x841d5d99, 0x55388cc4, 0x798be0d3, 0xeb64ab62, 0x9a82734d, + 0x93c7e83e, 0x1787d3a1, 0x2fb71669, 0x4b6fca8b, 0x6c51e070, 0x234c5bff, 0x2dd17628, 0x176d1131, + 0x8c84446d, 0xe112b333, 0x38513490, 0x9adc0c20, 0x58e173c3, 0x38abc762, 0x17260cd2, 0xe8272ce2, + 0xccf76bc6, 0xa37e0c3f, 0xf73dc6ad, 0xced1d71f, 0x0043ef4c, 0xdca0d6fb, 0x5d1133d8, 0x838ff5e9, + 0x0e3e6c5f, 0x83452a89, 0x8d83c5d6, 0xe79cedb2, 0xbaa0d06e, 0x65c84a4c, 0xbc910c03, 0xbca9961c, + 0xdadeeb74, 0x7425d656, 0xdcf615c1, 0x80dca487, 0x8ef06651, 0xdaa64bde, 0x961dbf34, 0xd2a3cd38, + 0xd4a60333, 0xbc9d7fb1, 0x9d0cf70e, 0x50254842, 0x91a466eb, 0x96c931a0, 0xdb2d62fb, 0xee00f84d, + 0x73a2e016, 0xcb2ee15d, 0x8f1a013f, 0x81e7097e, 0x3957c1bb, 0xc725ecc0, 0x35b295d1, 0x7534f83a, + 0xe285dec9, 0x3880605d, 0xb37cc3bf, 0x4e75c284, 0xced72133, 0xac511196, 0x98a03f22, 0xd70a9952, + 0x798ba161, 0xdd47c31e, 0x7314490e, 0x5b861fde, 0x153c90da, 0x962e1d65, 0x6b409883, 0x7ccba435, + 0xc76b9139, 0x069ecec9, 0x6e0b32a7, 0x2145e385, 0x42e3ea92, 0xac10a0c2, 0x56d71f7a, 0x9a4ee46e, + 0xc541a909, 0x228454a5, 0x96d811ca, 0x7d02806a, 0x9037ede2, 0x13fbc300, 0xaa3607e6, 0xf2806515, + 0x771d7fac, 0xff795f9d, 0x135c1a8c, 0x9fba9ca3, 0x8b96eedb, 0x01094dba, 0x7d8d3045, 0x58aae114, + 0x59029f2b, 0xb47ed32a, 0x72c467e1, 0x891925d2, 0xe0e07ecd, 0x4a4ce80e, 0x8e8f3a9a, 0x42739150, + 0x8b1f740e, 0x9af5f49e, 0xfe0125a7, 0xd6ad02a8, 0xb237ee54, 0x0fea326f, 0xce3a7d4c, 0x6d666d03, + 0x51caa4e1, 0x5f687f70, 0x5be0b244, 0x3d96deba, 0xf8c4c8f9, 0x9db46aaa, 0xb34a16eb, 0x8a1319ae, + 0xb2765303, 0xb47a5fd8, 0xa13f1665, 0xab344d61, 0x4569ea40, 0x20dfd66c, 0x9b9019a5, 0xb1da8b08, + 0x215fa4d6, 0x090315da, 0x2f8d94aa, 0xd5bcc08a, 0xa89d6d86, 0xb66845e0, 0xdf2b52bc, 0x0849a8d7, + 0x88b9cd37, 0xcbc0fb45, 0x34a3f65b, 0x5316a2e4, 0x22aa3b5d, 0x2fde444c, 0x1cd232cd, 0xcca50f90, + 0x4cf0d74c, 0x28be8b5e, 0xa8ff0723, 0xd2367119, 0x40219b3e, 0xa276afe1, 0xe0c61c6c, 0xbd6d046f, + 0xa2a8a49e, 0x7be0bd8d, 0xc6d40d4e, 0x21db1d29, 0x73ec7705, 0x3e4789b2, 0xc0c2e948, 0x735a39f5, + 0x38d03044, 0x3f2e1259, 0x035fee6b, 0xf2f10150, 0xf0f758cf, 0x03260cbd, 0x1ad79247, 0x3f9fd6cb, + 0x7ec20957, 0x2e01a0db, 0x4f79703c, 0x63acf8de, 0xf171999a, 0x50400db7, 0xa02c8440, 0xedf55c16, + 0x0b90f4dd, 0xa36b8065, 0x31933133, 0x0c57f952, 0x082551bb, 0x58f3b242, 0x2f5fc996, 0x70f35f1a, + 0x2a06b4c1, 0xf7f8505a, 0xc7fb0203, 0xbc725ecf, 0x4ba71a77, 0xe063acbf, 0xc3a7b858, 0xe985a43a, + 0x53b13417, 0xd7824b4e, 0xbb55cbb7, 0x22b2ced9, 0x4efb2e97, 0xff6bf69f, 0x5a933bd3, 0xbe9ab658, + 0xeb435305, 0x9e081ec4, 0x3f191b5f, 0xf236b991, 0x39e0b6d1, 0xcea23303, 0x339b1a9d, 0xcd9c7feb, + 0x065cd763, 0x9415b45e, 0x5fb5165b, 0x2d814fb1, 0x95f4c511, 0x3fca117f, 0xa4f4c645, 0x85fd0e01, + 0x20e1659b, 0x79a94d22, 0xa1aadc95, 0x48f7436a, 0x36ee0cf6, 0x502b9cd0, 0x8622abe8, 0x045cae73, + 0x1bd7c223, 0x4e42fd0a, 0x9d78eabb, 0x4421e570, 0x5da0db49, 0x38b92120, 0xda4cca51, 0xc6000ae4, + 0x0470618d, 0xe23d2d01, 0x84f9754a, 0xe1dd4a3a, 0x4a273a49, 0x0e755ffc, 0xbd302409, 0xa0237b60, + 0x89209a5c, 0x5a60a94e, 0x3d88de37, 0x5a1e4d0a, 0xd68d4ac6, 0x40921014, 0xaf31feba, 0x9e86f324, + 0x22497a31, 0xf3512771, 0xb6adb43b, 0xcd37ad93, 0xf734859e, 0x296ce9de, 0x4722e7ba, 0x9c3db24c, + 0x76eebfc1, 0xac6bc56a, 0x6f7fb9d7, 0x3e4d8e10, 0xe412a1c8, 0xc2616208, 0xfd9675e8, 0x6029653c, + 0x97e66594, 0xdc308993, 0x31cd4da4, 0x17c0adfb, 0x98815255, 0xfc9d64e3, 0x1b454a6d, 0x8b220894, + 0xae76dd80, 0x0860135b, 0x099f52d4, 0x378cd0cd, 0x789d4637, 0xe36ff327, 0xc66316e8, 0x52366573, + 0x8eaf42a5, 0x73c67742, 0xa00f27e8, 0xe1357153, 0xcb7b3bc6, 0xc4a0d597, 0x33749332, 0x2d196453, + 0x751c43f8, 0x1e5f1fb4, 0x1d45987f, 0xbccfaaf4, 0x4f641572, 0xe563e4e3, 0x5ddaadd1, 0x8142fe32, + 0x66fd2b58, 0x8e1843a8, 0xe6944ba1, 0xccacf546, 0x56f52b6f, 0xdd429861, 0x7bf07800, 0x17eedcc6, + 0x6fb6bf96, 0x95dc4502, 0x7870fb6e, 0x0debaecb, 0x4ed2c6f7, 0x3615df61, 0x0f8a4568, 0x2dfc4caa, + 0x3c9257fd, 0x8a3d0140, 0x7968782b, 0x600651d3, 0xfb26ef04, 0x530afbc0, 0x6529b18a, 0x839be3a6, + 0xad837d81, 0x6cf6da56, 0x8dbf8ed2, 0xf47fff6f, 0x3c9dd86b, 0x7efb59cf, 0xc82ca5c6, 0x0a3bfc3a, + 0x7d7be4be, 0x7632d0fa, 0x88de34aa, 0x6a32ca86, 0xefd241ff, 0xa040b642, 0x9ab5215b, 0xf8994a0e, + 0xeac70a2a, 0x1b4ce7cf, 0x4c0da09b, 0x11b3de21, 0xd4ee8d38, 0x615723de, 0xf5fde9a0, 0x96bab4f4, + 0x06befd30, 0x5b3b625f, 0x85f4c13c, 0x5cedebf9, 0xa60b8fc1, 0x2ce21042, 0x54f0e2e2, 0x5355cc42, + 0xe3f3cc57, 0x540ec2e5, 0x31a41d8e, 0x712cdfbe, 0xbf449d40, 0x0bbf28ff, 0xc38c52b7, 0xf6ff9372, + 0x0789d093, 0x5c9fd8d0, 0x24441af5, 0x13f20259, 0xa9759918, 0x19d03fd7, 0x94557da8, 0xb58e0852, + 0xd0923bdf, 0xc9c52e34, 0x1a95edaa, 0xd1574742, 0x58c45a91, 0x99175f1d, 0xbec8c77d, 0x5150eb48, + 0x0230da46, 0x4556301a, 0x4944aebf, 0xd23a1ae5, 0x285d21c5, 0x437f015d, 0xc844b626, 0x5763f67f, + 0x26a6191d, 0x83da081c, 0x5ab77621, 0xc7851bb0, 0x9f902840, 0xc1d1fd57, 0xb700d3b5, 0xd2f546bf, + 0x2ae2c5d2, 0xab33dc53, 0x40421ae1, 0xcb6ed83b, 0x9590b501, 0xc4a4cc62, 0x0f06ea54, 0x5ce408aa, + 0xce24b342, 0xa7fcd1be, 0xf11940ea, 0xc0aab778, 0xdf87e2f7, 0x89bf9e71, 0x81f6484e, 0x9afd980e, + 0x4c03c363, 0x6657f2bd, 0xf90213f5, 0xc8555aac, 0x543c62a5, 0x6b92700d, 0x6e13a8db, 0xf2cbed1b, + 0x40503aac, 0x78e758cc, 0xb76c5530, 0xc369ce3a, 0x97508821, 0x22122758, 0x8bf9c71e, 0x1a682b8a, + 0x846b7680, 0x7373f41f, 0x06d6199d, 0xa63afaf9, 0x64457061, 0x70994fa8, 0x840edaa5, 0xc179ca40, + 0xadf6218e, 0x41a88797, 0xe61b2b36, 0x0bfaf963, 0x32cf6aa3, 0x4712e170, 0x68b2866d, 0x070ad3df, + 0x60f0535f, 0xaebd22bc, 0x6ce630ca, 0x8824c0e8, 0x8f369b87, 0x91abfa90, 0x38f1450e, 0x49752bdf, + 0xbea61999, 0xc95729fc, 0xa7635e7a, 0xc6545a36, 0x3de596a8, 0x302c6797, 0xda718da6, 0xa5041a5b, + 0xe6438045, 0x5424448e, 0x812171b0, 0x8a5baa62, 0xb34d102f, 0xe0bc66f8, 0x0e3c1c67, 0xb474181f, + 0x2499ffca, 0x60db193b, 0x9d073270, 0x4622bc1f, 0x2b3d0b3d, 0x302c8411, 0x3061c4f7, 0x46db189e, + 0x0e2afd75, 0xe926913e, 0xc48fda36, 0x18137058, 0xb8cf9354, 0x3a629a42, 0xf66fe332, 0xde0e330f, + 0xcba0a934, 0x7976605c, 0xbf9bb583, 0xe971f323, 0x00c6b20a, 0xf01e1933, 0xcc458ee7, 0x6efadc19, + 0x464bda11, 0x5b72d8de, 0x736ef4af, 0x4d241388, 0xe615691e, 0x2b235e1d, 0x0897adae, 0x4c7e93bf, + 0xe0e187cf, 0x1b25f39a, 0x3cc7188e, 0x813c6360, 0x90f61e9f, 0x217ccf5d, 0x59478001, 0xce464088, + 0x1c87c626, 0xb587301a, 0x82697f23, 0xf2c92668, 0xc4177d0d, 0x70b79288, 0xf9b6c6f5, 0x7d353848, + 0x2d0136e4, 0x9cf2e755, 0x6f76a083, 0x8f438efa, 0x7c2ce00f, 0xc8226346, 0x0aa13fdb, 0xdf852323, + 0xc05e12fb, 0x6c135c14, 0xb7df96ca, 0x636a0f4c, 0x8b04692e, 0xd77cbd23, 0x538986da, 0x7f6640c7, + 0x0d2231ce, 0x4e618f6b, 0xe2ebef15, 0x6c1e6597, 0xd606be68, 0xc60d3b88, 0x8a304876, 0xbd499f0e, + 0x2b1f84ee, 0xa3f1b1f1, 0x228cef55, 0xef610b0f, 0x5f40c25f, 0x160de7cd, 0x8e1e19cf, 0xa84a4271, + 0xf47eee1a, 0x0e30a0a1, 0x83fc9d36, 0xe3c51001, 0x888754ab, 0x9b0a406f, 0x85e0687b, 0x37d624d7, + 0xe8d868b3, 0x4222794c, 0x38cda78c, 0xf54e2ca8, 0x10fea50e, 0x6b9fb654, 0x25448603, 0x683977de, + 0x24e6e21d, 0x436f21f7, 0x2cbdccf8, 0x92c41b4a, 0xdf72b9b8, 0x09a23143, 0xf23705c9, 0xf3d56538, + 0x2a335255, 0xc6a05d83, 0x0a7daf97, 0x2033cd57, 0x37f7bb4b, 0x364bd04c, 0x54f833f5, 0xdebd09e7, + 0xd65a561b, 0xdd154f3d, 0x1919cc9d, 0x19487a7d, 0x6dbfd595, 0xd1aca2c5, 0x198146b5, 0xd9fec5d3, + 0x32b12b06, 0x3e543577, 0xa347277e, 0x3fabe27f, 0xa2a579f0, 0xae1b7d91, 0x6ffa538a, 0x3552d61e, + 0xc8cf5262, 0xfee9b568, 0xc04e17f9, 0xfbd33d23, 0x33b6ee92, 0x001d0046, 0x333f09ff, 0xa653fc03, + 0x6ef1e9c4, 0x4c26b3db, 0x708f9290, 0x1fba142f, 0x8618fd6f, 0xedcfb42e, 0x85b502c5, 0x9acf38c8, + 0xdb96178e, 0x6a3a6b66, 0x7a774c3a, 0x8716faa0, 0x75f645ed, 0x9be42108, 0xb8b9409a, 0xe33823b3, + 0x6f9c7395, 0x9061399a, 0x4d069a88, 0xb6cb4ee7, 0xaa0c16f1, 0xc186f6ca, 0x27a49448, 0x03ff9a82, + 0x487eb046, 0xf68644dc, 0x41c11e31, 0x004fe1d3, 0xc870a0ba, 0xeaff3d1f, 0xa56c84f6, 0xbf9faffd, + 0xd9ace2c0, 0xe0c703f7, 0x341a6acc, 0x0cbf2408, 0xf14f311b, 0xf193f588, 0xca3c7387, 0x3ebc4e22, + 0x56bebf42, 0x0e4635ac, 0xb7fd6bcb, 0x055a2a82, 0xf4854352, 0x47d220ec, 0x421ca930, 0x0d609b5c, + 0x9ec67f0a, 0x0fcb48de, 0x7c4804bf, 0xc5507f0f, 0xe752b62c, 0xbcce8482, 0x83da6958, 0x4e6b4114, + 0xad51c34c, 0x986a787f, 0x247e359f, 0x03a8afef, 0xad5ae388, 0xf8c45e72, 0x69b64f29, 0x551d0ed4, + 0xe964371d, 0x80e6afdd, 0x1d0b15c1, 0xd90f83ee, 0x706c7250, 0x032a7eb6, 0xb1f45def, 0xe9539be4, + 0x8549a545, 0x72cd25a6, 0x0b84bda3, 0xdaac8e21, 0xa7b7ad91, 0x46dd85c2, 0x5d5fadce, 0x4d10e91f, + 0xfa0f309d, 0x2450505b, 0x7e62d6b6, 0x1fc124b9, 0x2f83c695, 0xa2fcc4de, 0x4779f502, 0x7cbb0e0c, + 0x066fdf93, 0x04887009, 0xa497a6f7, 0xe25f05fc, 0xd65ab11e, 0xa25e22c5, 0x19045c1e, 0x3aa4021d, + 0x854e10cc, 0x07fa114d, 0xd983fce1, 0xc106b74c, 0x7a097634, 0x554de3f7, 0x00236229, 0xb65a8838, + 0xdd1fab0d, 0x9884995f, 0x447be782, 0x984e587b, 0x15b0caa8, 0x4fc22e5b, 0x1e0f4174, 0x0e4f84a9, + 0x4df83f84, 0x23469d92, 0x0b00d8c1, 0xea4ad785, 0xd9fe7129, 0xd8417b76, 0xb2437447, 0xbecc7016, + 0x0fa8fb6f, 0x1304fb53, 0x16bb207c, 0xf899f4d0, 0x040738b7, 0x6ebb74c4, 0xd9e007c9, 0x4ddae7a5, + 0x7c8c3483, 0x2f4db6ed, 0xe6d51eb1, 0x4c37d670, 0xf7f8fbf2, 0x310632f0, 0x3ee0f27a, 0xd0973c93, + 0x36f74f81, 0xebcc86ed, 0x7ab235a3, 0xf70a2c83, 0xe7ae2d3f, 0xde8fe3e9, 0xedbfdb59, 0x8f551374, + 0x49684acc, 0x27ceed4c, 0x585e4343, 0x000bb259, 0xbb362f6c, 0x0f9bdf2d, 0x77c632ea, 0xeebad78e, + 0xc18462c5, 0x30407eb5, 0x8e18797a, 0xc0b350ef, 0xfa3ead07, 0xcde427cf, 0xa3d7e0a3, 0xbdf0bf54, + 0xf107867e, 0x04f072fe, 0x399bdcc7, 0x840479c6, 0x34d8b969, 0x55106a2b, 0x8f33844b, 0x331e26bb, + 0x250050b9, 0x02fc81ce, 0x261ccf08, 0x2d74312b, 0x820c37b7, 0x39bc1a46, 0xf4865fdf, 0x22bd8658, + 0xff6ed246, 0x0890403e, 0x18be1499, 0xc6110aca, 0xe5af3a20, 0xec854f28, 0xd9382232, 0x947cd63b, + 0x2a15a8bb, 0xc49848ed, 0xf41d1ce5, 0xf53f5f2e, 0x4433b301, 0xc25b51c6, 0xcb5bc0ac, 0x65a5e218, + 0xf2f69279, 0x10cd8339, 0xf280e4df, 0x1bf7dbd4, 0xff73634c, 0xd07335f3, 0x465717bd, 0x23cfabb7, + 0x8826fad1, 0x3a95391b, 0x2b951ec9, 0x55c342f8, 0xf91e2089, 0x64547cad, 0x68d79216, 0xff6c7fe9, + 0x9cff960e, 0x1b3be666, 0xf3427850, 0x1af5972d, 0x8ce424be, 0x04a8ab27, 0xe1811274, 0x6401979a, + 0x5da4cf70, 0x861ef098, 0x168ebceb, 0xc8a728a6, 0xb896012c, 0x2143f232, 0x744927b4, 0x35201777, + 0x2d914387, 0x9ed7f94b, 0xf00b5441, 0x6904d92a, 0x482ffc7c, 0xf355da5b, 0x79d3cd0d, 0x0abde0bb, + 0xadf96fea, 0x7fcf5e87, 0x78828f01, 0xcac2d991, 0x347b8666, 0x82e63203, 0xa12927e0, 0x103a6991, + 0xbe39050e, 0xb33730c3, 0x9b9fe147, 0x69cb667f, 0xbe2c1142, 0xa65e23b2, 0x81d318b0, 0xdd0e9d89, + 0xb36f2c16, 0x06613a50, 0xad6a1eb7, 0xdf57feb7, 0xe95497da, 0xaea78d92, 0x78603c0a, 0x7c403889, + 0x6de90e91, 0xeb33d532, 0x4356f85e, 0xd4047a63, 0x28280051, 0x3a65b54c, 0xd3b82ae8, 0xe1fecec4, + 0xddfe0b8e, 0x4bff00f7, 0xf1fd4390, 0xbc07bb50, 0xf4fd8907, 0xed6d885e, 0x7e10ea21, 0x0b69c743, + 0x49857aee, 0xd55b943f, 0x6f06e7a8, 0xf2731c17, 0x86e4e839, 0xd67593be, 0x88211cc2, 0x7acef217, + 0xee70ca50, 0xd7f5d099, 0x9d710c19, 0x30c2bd60, 0x9136bc7c, 0xa68590b0, 0x903f4d00, 0xbfb477b3, + 0x57098afb, 0x744d626d, 0x04604e67, 0xfb1a3ca5, 0x4a4bdd39, 0xdfe3a5bb, 0x4eb043f5, 0x5c666653, + 0x5936ff74, 0xc1477a35, 0x3665ecdc, 0x26d8d8e7, 0x39dd4541, 0x72b63f98, 0x3961f77c, 0xfab6dec1, + 0xddf9fb37, 0x5a5270c0, 0xfcfb5e76, 0x1f416742, 0xfa567fb0, 0x467e9d0f, 0x874cb74a, 0x7c801db1, + 0xe95ac6cc, 0x57ef6630, 0x53b065eb, 0x96dcfd36, 0x9b194300, 0x7e1959e1, 0x91787e6c, 0xda51caa5, + 0xbaab1bf3, 0x0379e6f0, 0x9fdb3489, 0xde21a2e1, 0x9f5634fa, 0x93c246c4, 0x8fc78d5d, 0x3ea2142c, + 0xcaf76e76, 0x9da2521d, 0x2acc21ae, 0x2fd7bda5, 0xdec355d2, 0xf3746588, 0x76fb50a7, 0xa69d279e, + 0x179b864a, 0x7917f112, 0xf189f406, 0xf593fb1b, 0xe5da89be, 0x8917329b, 0x6878a8e5, 0x51bcbc52, + 0x343851f2, 0x648715fa, 0xdd3ceff0, 0x4f36b0e6, 0x769de5cd, 0xda66a672, 0x5cf2353c, 0x169edec5, + 0xb001c899, 0x2f212386, 0x5ff374d9, 0x902f9b63, 0x62938b54, 0xee128e48, 0xecd92b21, 0x31bba85c, + 0x46ebff79, 0xccb7b9b6, 0x72e02941, 0x4e807226, 0x8a0aefae, 0xf6b9c4d6, 0xd8f6949a, 0xf3c7d482, + 0xac829629, 0x9ffbf3a3, 0x718c8f7c, 0x53310af6, 0xe55f4c13, 0x95c8a29e, 0xe190fa7e, 0x64589aa5, + 0x1fe6317e, 0x4996238c, 0x73a59fc9, 0x0c11de06, 0x6ed34adc, 0x34614996, 0xf653263c, 0x272880e6, + 0xc8778076, 0xffb5570a, 0x88592be7, 0xb1697bed, 0xf7c4f8b4, 0xe9cf811c, 0x8e27d295, 0x42f3d0f2, + 0xadb004ba, 0x6529cc58, 0x48d75e2b, 0x3331acc5, 0x2f1c5aab, 0xdff15511, 0xbba13c12, 0xdd02c804, + 0x290304b0, 0x9a0ae9fe, 0xbac450e5, 0x819f0f80, 0xfa25ed41, 0x1365cbad, 0x748c5827, 0x347c5339, + 0x4ac23644, 0x82f6dd2d, 0x4a51dfec, 0x87b1c1d3, 0xfe079bc6, 0x5dd37d45, 0x0291efc5, 0x15da5da6, + 0x91c0cc1f, 0xe71ebb92, 0x559f1204, 0x40c5b180, 0xdb316bf2, 0xe5794310, 0x43b9ed16, 0x1bf9548c, + 0x4396ff24, 0xe6ef3b56, 0x04d193b3, 0xa66d0133, 0x738da1b0, 0xc505045e, 0x3aafd451, 0xd6dce0ea, + 0xee7ad3a2, 0xcc436c78, 0x238fc4ca, 0x7ea3ec91, 0x1cdb7b2d, 0x4a6aeb3b, 0xf95102c1, 0x428b7f39, + 0x74ca8a7f, 0x038b305c, 0xbb5b2f87, 0x328a6450, 0x195951e8, 0x8000d874, 0xa6ddbd7c, 0xd1cb90a4, + 0xb7cbabbb, 0xacf7af2d, 0x42bf44db, 0xc6431081, 0xdaf2aafb, 0xe0f7a0d2, 0xff94b1dc, 0x03fcfada, + 0xe908c60e, 0x9621c465, 0x30b81c91, 0x0b4ffbfc, 0x1834560d, 0x68c77435, 0x356f1249, 0xec7fe5ec, + 0xe59eceb8, 0xbe6cc301, 0xd9ff300d, 0x7b6494c3, 0x5df01be3, 0x3222a416, 0x8bac2cae, 0x5104a87d, + 0x24fd77dd, 0x5f85970e, 0xa44bc827, 0x160c793c, 0xeeef04e5, 0x92c5547e, 0x50c1cfb9, 0xd5a33292, + 0x4fb423af, 0x2de9ada4, 0xb516aefc, 0x9dbdd4c2, 0xf8745696, 0x43c6be27, 0x60b412fc, 0x35c9eb60, + 0xa2b3dd44, 0xb0c51e32, 0x20b5b608, 0x17cf4fc1, 0x0832da5f, 0x1f1ae752, 0xeee0b9f6, 0x7a88a657, + 0x129c6972, 0x4329e802, 0x2733b47f, 0x83c0e41f, 0xc10a7414, 0xe585fb2a, 0x76862bf4, 0x17ee4fd8, + 0xa54b4c48, 0x667c537f, 0xb776d649, 0x95b89628, 0x89fef7e4, 0x5f9d84bf, 0xf39148e7, 0xfac4d2b2, + 0xe16ab1b9, 0x3d5dd389, 0x5947821b, 0x5048129c, 0xcd6d342d, 0x92a2668c, 0x2f56f2e7, 0x12a60853, + 0x47a1c5a6, 0xd1a25115, 0x5d10f99d, 0x96fdaae1, 0x749da2cb, 0x2452766f, 0x6256655a, 0x71ad26b3, + 0x97c6b155, 0xd633a587, 0x992a9cfb, 0xd4bcf56e, 0x7c8757f2, 0x9d6ec64b, 0xb1bc042c, 0x2a53dc13, + 0x96483ce8, 0x15e73168, 0x63e3e7d7, 0x14004b37, 0x7bcbf0cb, 0xc60aac99, 0x8e2665b7, 0xee93572c, + 0xff17fafc, 0x9eacc207, 0x866eba92, 0x75a89fd3, 0x6b7ae30c, 0xa2566504, 0xdef5c75c, 0x07a80a9b, + 0x55257aef, 0xf98e2aa3, 0x7e0952b0, 0x9ae8cec2, 0xcb8ca77c, 0xcc8d3fcd, 0xd1065d2d, 0x9b10063c, + 0xff39a382, 0xee275cd9, 0x8f1293e6, 0x6280b8ad, 0x1593e1ef, 0xc218e302, 0xcc38f531, 0x770df929, + 0x8a302c05, 0x0aeab21e, 0x20e283b7, 0xf76f1fdc, 0x409b6087, 0xe3da47e5, 0xceb21d28, 0x60826770, + 0x9b86cabe, 0x48f7ca80, 0x5043aa5a, 0x360611a2, 0x59f934d5, 0xc3c4a486, 0xc9967a2d, 0x6a5308d4, + 0x79bda240, 0x909fd98e, 0xf49643bc, 0xf2bb63b9, 0x0da6b533, 0xf5369ae6, 0xaa1de445, 0x4d7bdfa2, + 0xca3f7db9, 0xe52220ec, 0x60821252, 0x43a0c0e7, 0x4b70e068, 0x0593546e, 0x10f7e764, 0xbdb5e00d, + 0xde38267c, 0x1dc15fa9, 0x63921d22, 0x496a3fd0, 0xf6716b1d, 0x8821bf49, 0xde5b8005, 0x6e749b41, + 0xc5c98501, 0x78cc06ac, 0x48f132e9, 0xae27d783, 0x6d1bea84, 0x3f318baf, 0xc85a975d, 0x00904827, + 0xe895c692, 0xb3055f23, 0x5e1c263c, 0xe4735664, 0xdce219fd, 0xdecf1bc6, 0x7f9c9425, 0x3ac88c9e, + 0xde861fbf, 0xa56d3c1e, 0xf1efb535, 0x38d40fe7, 0x6b492069, 0xdaa2a764, 0x3c426d03, 0x8f670e35, + 0x6a52cc82, 0xb184acae, 0x445ffc8a, 0x7e73a705, 0x23d43dcd, 0xe0c0bc13, 0x303643ec, 0x744d1ff7, + 0xadef941f, 0x4ea5b0ad, 0xada1d03e, 0x421e5a81, 0x066d7998, 0x34c4f1e4, 0x88ada64c, 0x9ad41d3a, + 0x15116dd8, 0xcf51bdc7, 0x8e03d1bb, 0x0ce64046, 0xa341fe03, 0x4af1924f, 0xa9110822, 0x1ba6ca6f, + 0xe55e6fbb, 0x43524b5b, 0x12dbc403, 0x79bbb0eb, 0x5eed39ce, 0x50f740fd, 0xa103213e, 0x7261e167, + 0xb4c44ba0, 0xda5f33f1, 0xf33a2b14, 0xa8fcf531, 0x0d956e14, 0xbc99a47e, 0xcba85743, 0x81f243bf, + 0x918bb561, 0xa5f40cd3, 0xf51e78dd, 0x9857413c, 0xfa8a8e3d, 0xa430fe6b, 0x4ab7ab4c, 0xcc4d0354, + 0xada2c0b6, 0xfe0b1433, 0xe00aa575, 0x25d036c0, 0xef2526a5, 0x725d1d16, 0xb541d640, 0x84ceb075, + 0x490051aa, 0xfc515fc8, 0x98522f44, 0x080fd435, 0x3a2d6b1d, 0x1619901c, 0x5d2df5fa, 0xd2f96c90, + 0x1305c4c2, 0xea61aded, 0x736096a0, 0xd25c468c, 0xc50e8447, 0xb59e09ff, 0x18390d0a, 0x637dcd09, + 0xe2cfd51a, 0xb6ab0396, 0x7344c619, 0xdd9c5b16, 0x099a1799, 0x559b09aa, 0x55029850, 0xf31cf56f, + 0xc9f9d7ed, 0x89d96862, 0x894f758b, 0x740e82b1, 0x20c5d0f9, 0x3dd1ad3a, 0x8f7a54fd, 0x0f25d659, + 0x3ba18f38, 0xb9d8d6f5, 0x1f4bfd93, 0x7df22166, 0xc49db4ae, 0x7452d902, 0xcb1a71dc, 0x03a403bc, + 0xf818f739, 0x08eaf9e5, 0xc9f08a15, 0x4ead9e3e, 0x6f736b7e, 0x7dbf9520, 0x8962d03c, 0x2cedc9ac, + 0xce6f3c82, 0x1480e3bb, 0x4ea4c9e1, 0x1f9d50e6, 0xb96d1c23, 0x8fd76968, 0x99f5f244, 0x11a08fc2, + 0xcf0da457, 0x305334b0, 0x516fed23, 0x9f28f27a, 0x37dba9ea, 0x3cd1aa59, 0xf8853cc8, 0xb1a4ec6e, + 0x3a7ed6d7, 0x4be545fd, 0x13b80497, 0xabbea8d2, 0xe9dfbf1a, 0xbf501d46, 0x730d6d4c, 0xb4f2cb42, + 0x17027428, 0xbaebc85a, 0x986e8e66, 0xf6098d80, 0xba9ec5c4, 0xc718d06c, 0x3093c90a, 0xfffa9c44, + 0x09b11373, 0xf347ad79, 0x8683ccb1, 0x64cef48b, 0xdecc4dac, 0x0276b3c4, 0x824f608c, 0xf567444b, + 0x0f55a1c2, 0xed1c8e18, 0xe06c0bcd, 0xa7a26125, 0x3778fb02, 0x5baf14e5, 0xdce2efdf, 0xf4ab4941, + 0xb4ba3765, 0x142b92c6, 0x550c3dde, 0xdc256bae, 0xb96346ff, 0x198df6b8, 0x34adc5ec, 0xb648d4cf, + 0xf93f4075, 0x9d0ed557, 0xbeb31815, 0x64b93c40, 0xb09b22b4, 0x9259a40b, 0x5a304513, 0x211d492d, + 0xa5fd92c4, 0x48985b22, 0x9d228641, 0x7624345f, 0x4f81841c, 0x4f393058, 0x0788e338, 0x6d624b36, + 0xe8d750c2, 0x291dd2f3, 0x951cfc35, 0x14561981, 0x5f02ba95, 0x342f2c1e, 0x4e20ace3, 0x8cc15859, + 0x0038322e, 0xf4e0ea1e, 0x889a310c, 0x89aca86c, 0x264ebb7a, 0x7e4bb890, 0x1c7739a1, 0xc91fad83, + 0x03ac9278, 0x987777b4, 0xe87bc9cb, 0xf8a8bce8, 0x81b38bd1, 0xaca7e15a, 0x1eb7fdad, 0xa71313bb, + 0x0cdb873b, 0xf6dd1ccd, 0x3c1b3fb9, 0x03b42a73, 0xfe007178, 0xa13e5582, 0x1bcf5c84, 0x75bea2bc, + 0x550a67eb, 0x5c22158b, 0xc0720dea, 0x4e6cc47a, 0xea689927, 0x4409e02e, 0xdcce6bb1, 0x4163d578, + 0xa29ea18c, 0x5962b5b6, 0xa7dc1b39, 0x1fb41756, 0xa1ba8d88, 0xb9d3456f, 0x0737d890, 0x6cf1976e, + 0x0ad358d3, 0x1fe7d188, 0xa441a038, 0xd749017b, 0xfb8f02d0, 0x6582acad, 0xb7a41863, 0x76c73619, + 0xb4e720f1, 0x6db88f9d, 0x7a0dd6dc, 0x6c659b2c, 0x65c8ccb7, 0x390b9bb0, 0x1d16bd9d, 0xa0c7b5be, + 0x559aa7ea, 0x7c22252d, 0xf670d51a, 0x55eab67a, 0xe8301cb4, 0x9e01ff34, 0x69357b97, 0x407f0c18, + 0x215e3cd7, 0xcc4ad03d, 0x4c8859a5, 0x87271e2d, 0x1d31111a, 0x5e105f73, 0x1e111a39, 0xce285547, + 0x12bbd85d, 0xff7af994, 0x0dec5c5b, 0xc75bea71, 0x1f550e57, 0x18cedf5f, 0x6e4dc533, 0xe3405920, + 0x2634e2d5, 0x178d50d1, 0x50861764, 0xed601056, 0x0313b34e, 0x3ea9ae73, 0x900c4745, 0x3c9a471b, + 0x436d4931, 0x8fe0d3af, 0xc783384f, 0xd768a847, 0x10be9c4a, 0xe5b49eec, 0xb15303be, 0xe882cfab, + 0x47a8bb08, 0xd83a497c, 0x7cd13bf8, 0xa750ecd1, 0xacc52d39, 0x712b6244, 0xfc75941d, 0x89a0a32b, + 0x02ee41ef, 0x69dc12e1, 0x032000ef, 0xcb6a7fa7, 0x033e1f87, 0xebc7e83c, 0x9359be0c, 0xa0a780ff, + 0xa534559a, 0x8a1445a7, 0xd06e8147, 0x52291f0a, 0xd2142cb2, 0xffff199b, 0x82ef9b5e, 0x05e9f04f, + 0x6dc4a7d1, 0x9a8ec694, 0x0ab7718c, 0xda0f13c6, 0xe7a28e0e, 0xf2dae7d3, 0x041876d9, 0x8a6ddacb, + 0xc6defd9a, 0xd95416c6, 0x55eceee3, 0x0e17e835, 0x13bc4258, 0x11b337e6, 0x600dae23, 0xf729e09a, + 0xd8b0d297, 0x004e3f16, 0x35c2edf7, 0xd9946f10, 0x5f00b82e, 0xc7dd2d48, 0xae27e620, 0x8ee54603, + 0x22ce7a20, 0x0a21a935, 0x9f0a9718, 0x5bf39159, 0xa6cd5d77, 0x68580b52, 0xc9e957a9, 0x185abbf2, + 0x8cb52fc9, 0xc6c67ef0, 0xf440c794, 0x3c18e37c, 0x5a0e322b, 0x7462bee0, 0xadabea14, 0x76e0db62, + 0xfa583fed, 0x24e7beb1, 0x750713c4, 0x2ebdd13a, 0xa071d3ba, 0xade71259, 0x24f59b1b, 0x73db6275, + 0x803c5824, 0xd40f1a11, 0x14195101, 0xd91250b6, 0x9cebaa26, 0xef2d84c7, 0x2f8c787b, 0xfc056d61, + 0xb9995c33, 0xa2d6e5b7, 0x9ed53d78, 0xbffeca75, 0xce4cfe48, 0x0b208dd9, 0x83d793c4, 0x36327c0c, + 0x43a85a4b, 0x468c0a4a, 0x54c03701, 0xcd9e8e62, 0xab0bfd6c, 0xbcb325f2, 0x3510fcf8, 0x210f28b2, + 0xa2116127, 0xb80efb13, 0x699eede0, 0xb7958600, 0x25029171, 0x585fa245, 0x1907208c, 0x835a17c3, + 0x6d9ec062, 0x1296d081, 0xccc4f8c1, 0x4ad93f20, 0x8527ee5c, 0xe747fadf, 0x10fafc55, 0x1d137495, + 0xc7e93b3c, 0x69a73970, 0x3f77b3b0, 0x683ce97f, 0xd0bd2787, 0x6953fc7c, 0x92dbf2b1, 0x5545acaa, + 0xf60930e9, 0xea7c7cc8, 0x05a98bb6, 0xa0c6f9dd, 0xad110d80, 0xe564a36b, 0xbd3826e3, 0x9aec2109, + 0xdc9182e7, 0xcb44f614, 0xee140310, 0x18b1ad42, 0xce4c46f2, 0xea7b7c10, 0x0e32b86c, 0xde08244c, + 0xa057c218, 0xd5420c94, 0x1cb9737c, 0x637aa739, 0xc3cc6ef6, 0xad0743ff, 0x8dea9f18, 0x2f9294d8, + 0xda03f866, 0x4e0ad156, 0x25bf86f7, 0xe9d33974, 0x07dab60a, 0xaa2f2e5a, 0x960f77b3, 0x6d39077f, + 0xc7c8a305, 0x1f362db8, 0x72c4e115, 0x81d9e5eb, 0x8d2dd534, 0x9773bd76, 0x6add1c6c, 0x831a3319, + 0xa54c3c87, 0x281786f2, 0x6b1e4b54, 0xe3ea1078, 0xb2b42daf, 0x228bd531, 0x269b2881, 0x53d4263b, + 0x66f9a018, 0xf54306c2, 0x6df72f95, 0x3b61772d, 0x3bb738fc, 0x3fbfd11e, 0x6d142675, 0xbe678e5f, + 0x199033cb, 0xaaa59bf8, 0xf690a05b, 0xf37a38f4, 0xcb1f42f8, 0x48fd71e8, 0x63744120, 0xd3b70a40, + 0x230841c6, 0x26a2aa52, 0xeac69c20, 0x06897036, 0xa51ba165, 0x89e2af8c, 0xe0844bc8, 0x45825e86, + 0x097ee7ce, 0xc67d7b6c, 0x0add7597, 0xe9e57e68, 0xd5f41e91, 0x186dae46, 0x61d420c6, 0xa6b8e835, + 0xc5c03608, 0x20438f99, 0xb70bbc5a, 0x024dfabd, 0x50027d4c, 0x28e80eec, 0x199bc40c, 0xf2aa0a80, + 0xcf747795, 0x1be27e32, 0xdde4944c, 0x2a24835c, 0xc1a4c273, 0x2de341ea, 0x45e2f7d7, 0x2212ee19, + 0x07064028, 0x800f7391, 0xf7635268, 0xff37d87d, 0x77296d3d, 0xe1f57f41, 0x89ae2512, 0x2b0783e2, + 0x66cf66af, 0xf575fa25, 0x793f314e, 0x78b2aa5a, 0x88bfdb84, 0xfaa2cc1c, 0xd6b151e2, 0x35f3e5b4, + 0x1b2fc6e8, 0x70f3c9a7, 0xb4aca44a, 0xe0f19973, 0xbb272e6d, 0x13ca151f, 0x2412e5cd, 0x339f58fb, + 0x029ee9d5, 0xb87c2f2e, 0x672ab382, 0x7e1767e2, 0xa541937d, 0x14012db9, 0x86d4886f, 0xa6dec976, + 0x74c8deb4, 0xb054503e, 0x38435210, 0x35231ece, 0x41ad6f71, 0x58334381, 0x35880b60, 0x1844cccb, + 0x2658ade4, 0x4ce82ec9, 0x0d4943dc, 0xa0a1a675, 0x4445f6d2, 0x97571d99, 0x0aa2ce04, 0xff4c7fe8, + 0xca9770a0, 0x94ab9434, 0x28ebef59, 0xa2028d42, 0xf29f7f28, 0x50dd62e5, 0xf2dc2490, 0xb742d94c, + 0x3a0b24aa, 0x3cc4e04d, 0x8db97c30, 0x45d14fc4, 0xe37c771b, 0x956aa797, 0x40278377, 0x4f1306d5, + 0xe114f56c, 0x051d23ee, 0xf1a6e96c, 0x715ea34a, 0x6640c200, 0x6bb4ea0f, 0x306f2b3f, 0x3c727cc6, + 0x5b1b81b9, 0x18a12214, 0x1a21b363, 0xa38d6122, 0xa196f0eb, 0x33e27125, 0x57b501fa, 0x16e059fb, + 0xe033975e, 0x008acc42, 0x435500d8, 0x03f871da, 0x242fa9f1, 0x022eb929, 0x48d19828, 0xc53f0f5b, + 0xe3f264d4, 0xefd8a419, 0x2d3440eb, 0x827e000e, 0x645c7b32, 0xe4f17655, 0xdb4840f4, 0x21570916, + 0xdf701ef3, 0xdbee77ed, 0x5ac0387d, 0xcc3ddab7, 0x5b29c621, 0xce6307af, 0x9051e128, 0x70be546e, + 0xe5295887, 0xa597af88, 0xf06f522d, 0x4f73aa21, 0xac506f1a, 0x31d839d4, 0x5586ca84, 0x10b8fe75, + 0x666dee9a, 0x273ee261, 0xf6a83b7e, 0x3ca0830a, 0xaf4bfadd, 0xe38629d6, 0xcd2f039e, 0x33664d59, + 0xad72b7a8, 0xf4efd92f, 0x36ec9dd5, 0x08e5a3bb, 0x24018681, 0x8ff9a2c9, 0x72f65ff1, 0x65cf903e, + 0xd19dad4b, 0xe31e6db8, 0x00657010, 0x09d1160b, 0x4e4cb197, 0xee282e42, 0x938465fc, 0xd38d4ee2, + 0x87d59510, 0x2221fd33, 0x58065679, 0x5acd0c40, 0xfd9b4688, 0x3173d8dc, 0xb398736d, 0x79ca0743, + 0x8b2e271b, 0x621798ec, 0x35cfe441, 0xe7db2048, 0xa2f55c4e, 0xac4501e8, 0xf2fd8347, 0x7f54bde5, + 0x6c4fe298, 0xb3f259c3, 0x5e90fc5c, 0x8ba8e261, 0x11b90a1b, 0x7f9129b2, 0xa2a4f2f3, 0xe75454ce, + 0xdebe2e6a, 0xd72dc867, 0x14af4800, 0xb7865bbe, 0x6c3ebfc8, 0xb0a78ebc, 0x8dd501ef, 0x93c56b74, + 0xd5e9bf3b, 0x2efd4983, 0x247f1d91, 0x90826b5d, 0x33f311f1, 0xbb97f01c, 0xb46dced6, 0x39edc2db, + 0xc0c97ca0, 0xd6456515, 0x86a49990, 0x6a4cbb9d, 0xbb429705, 0xe7140710, 0x9bcf88f7, 0xf7bb64ee, + 0x5555f4e3, 0x47951177, 0x1ef7b3eb, 0xe7165c1f, 0xfdd331f4, 0x453991f7, 0x5a5cc9bc, 0xd74ae2e4, + 0xdc4095ab, 0x2ba942fb, 0x908d5430, 0x55f01c70, 0x1caf16bb, 0xab800038, 0x0e5f415b, 0x77d71868, + 0x95c250d2, 0xc2ddb198, 0xb5c78778, 0x6a737fba, 0x55275156, 0x677b5b97, 0x7999f376, 0x687e76cc, + 0xf50cf81e, 0x83470a28, 0x01572e93, 0x86549582, 0x5c50c10e, 0xff2bebe6, 0xa7f4fe1a, 0x5d416565, + 0xce30fc05, 0x3607c9a4, 0xbcd45049, 0x6e672cbd, 0xf7b12a88, 0x842e7329, 0x705fc02c, 0x51bb7caf, + 0xd5e3391e, 0x0489a142, 0x06b74471, 0x941b6752, 0xb29818ae, 0x194db3cd, 0x9d06e674, 0x6821ae5f, + 0x9ecc96a1, 0x51f09f15, 0xf985920c, 0xf3817dfa, 0xd2cf0437, 0x119d7ac5, 0xf0834d03, 0xde945c1e, + 0x14d648b9, 0x19baafe8, 0x2ca23a85, 0x42412305, 0xacd69c76, 0x670e1b36, 0xf5616f31, 0x44886a9a, + 0x1f27e32e, 0xad34d87e, 0x71b0f2bf, 0xd2dc75f1, 0xd5af4a2f, 0x92436054, 0xffef9bb3, 0xb75f5b28, + 0x64d6b715, 0xa628acc9, 0x7ad27150, 0xa2381067, 0x8154b6cf, 0xe2ae194b, 0xc566bf18, 0x20d1272e, + 0x58360f0d, 0x05d07f14, 0x1bdb9d43, 0xc4acece3, 0xfaa4708e, 0x158ba099, 0x182f8ce0, 0xe90c823c, + 0x8ec8fa1d, 0x8e86856e, 0xb150f6fc, 0xe3920973, 0x35a1829a, 0x8fed56cd, 0xa9879418, 0x90ff3f31, + 0x9be06dec, 0xb087db48, 0xb453fbf6, 0x47aa0387, 0x8383dd07, 0xae9f61dc, 0xaad4cbea, 0x49cb9f52, + 0x4e7dabb9, 0x7bd7ef87, 0x6372c4bf, 0xe9ab0372, 0x00b1aa3f, 0x90675548, 0xdc99bf16, 0x9897fd3f, + 0x80ccd0a2, 0x55d51bc2, 0x0e01b883, 0xa7944198, 0x67477e42, 0xf5d0e780, 0x863871de, 0xd64984de, + 0xe996b870, 0xcd6e5f97, 0x37d7a316, 0xf49dafc7, 0xd668200c, 0xab31c0f9, 0x3e61ed75, 0xfc1e657d, + 0xd9802522, 0xaede74e1, 0x7bb23eac, 0x6280a41e, 0x6f000104, 0xba6cac30, 0xf2f2bf7b, 0x1add8c9a, + 0x6adab877, 0x75a8d23d, 0x9dcde5c4, 0xd04dc64a, 0x19fbe9a8, 0x4d62a2d8, 0x9c6f8b56, 0x3260802b, + 0x6eb505bf, 0x79efc8d6, 0xd161eb4f, 0x712dd324, 0x599faac5, 0x86a9112c, 0x649c8c31, 0x59757607, + 0xe0c070ac, 0xab084a1b, 0x0bfb8030, 0x4c4cd53c, 0xb8e30fd0, 0x104346b8, 0x64d910fe, 0x336026b1, + 0xe74ec66a, 0x06d82b82, 0xb57d5a26, 0x0713abe4, 0xbc12d49e, 0x07b1da65, 0x05aeae25, 0x9b8449ce, + 0x5ee2a1c6, 0x336157a5, 0xfb6fd4da, 0x8430f65b, 0x3b05ddee, 0x258a6377, 0xea73bf02, 0xd9d6f3e0, + 0x19b5b921, 0xc88cb15a, 0xa0338949, 0xd81225ea, 0xc57c4dc1, 0x636b0ee1, 0x0995caf2, 0x6a83ff2d, + 0x4ead6dcd, 0x5b419ab7, 0x6f04acc0, 0x43d77630, 0x70dc8988, 0x2a560217, 0x9227f8a6, 0x52e02360, + 0x07238009, 0x1672c399, 0x2decc657, 0xe4997759, 0x6d01ca1d, 0x6187eb96, 0x5b825589, 0xd6f98f42, + 0x2be45818, 0x389cf170, 0x59c24aaa, 0x006d7879, 0x081e4302, 0x0129d925, 0x00334557, 0xe8436fd1, + 0x1564693f, 0xaa28322d, 0xaf3db597, 0x74993709, 0xa132615c, 0xbdaf0813, 0xf0e62a93, 0x1df1a306, + 0x95922ce0, 0x13a682fc, 0x6e65f323, 0x15aadf5c, 0xc942037e, 0x079a83fc, 0x2a79eb76, 0x1f52bdc1, + 0xbd2c0dd1, 0x537fb772, 0xd32e243c, 0x7c203820, 0x0d4e6df1, 0x4ef2c008, 0x0d6798ef, 0xc1b6cc8d, + 0x3bedd009, 0x906b51c3, 0xa58ac600, 0xe2a2bf5c, 0x3cd97251, 0x7abf52f9, 0xa69de0f8, 0x7b17cd47, + 0x505fdf61, 0xd9d7f886, 0x5c258876, 0x7ec0f636, 0x69127c6a, 0x3b428f7a, 0x47344f75, 0xc6c024b5, + 0x4878e4be, 0x35ed55a5, 0x8b3a06ac, 0x8ec8ae51, 0xee4506eb, 0x7396299f, 0xb1e4db1d, 0x0aa0ad10, + 0x7737a742, 0xde11e841, 0x4219fb14, 0x6d2764a6, 0xff52bf20, 0xe76dfc8a, 0x350d15ce, 0x93b61f44, + 0x9f2ba88b, 0xd0bcc67a, 0x56c00de3, 0x57938d79, 0xce24c0c4, 0x80fe4b1f, 0x42c29685, 0x71e55cfe, + 0x0066cb5f, 0xe9854eaf, 0xdc03cce3, 0x0c929a6d, 0xe0337187, 0x08d437bf, 0x83d38c46, 0xf613d854, + 0x45514d95, 0x573854ef, 0x17ad2bf6, 0x05f2a957, 0xf570ec82, 0x684049ca, 0x779da059, 0xd63add8a, + 0xa209caea, 0xb64b8961, 0x212d508d, 0xb0e375b1, 0xc189a813, 0xf8f680a6, 0x2dab4427, 0x7dd6385a, + 0x81c6b08f, 0x67456c39, 0x6c156b05, 0x06a87155, 0x3b76f073, 0x06681b50, 0x8bc303ff, 0x94fe306e, + 0x08382179, 0xb067545e, 0xbf6d361f, 0xa127627d, 0x3c4f9be4, 0xda624c28, 0x1016a202, 0xa886c936, + 0x36cb4129, 0x1bee562e, 0xfa098578, 0xac8790b4, 0x47229bda, 0x8d13d480, 0x17c261ff, 0xa43e7db7, + 0x1da621a6, 0x5bf43096, 0x437bd8c5, 0x9528ef7d, 0x3559151f, 0xc7657fd4, 0x17914a23, 0x0356e2d0, + 0xd42bcc42, 0x055614b6, 0x3b51e177, 0x1fafef45, 0x68ba88e2, 0xab64d64f, 0xcdd0a77a, 0xf0b89778, + 0x3e3ca33c, 0x364abd7e, 0xde2bba6c, 0xb9976bff, 0x7aa3564f, 0x8a0e576f, 0xbc6943f2, 0xde9612dc, + 0x5a80fda0, 0x459b9980, 0x755c7b90, 0xdeec0d45, 0x9acaf099, 0x3e5d06c8, 0xd5cbc122, 0xe3985f1f, + 0xfae90a04, 0xcf3ee9ee, 0xf2ba3fea, 0xd009edea, 0x30c9dabb, 0x0faff4a0, 0xf5ccac5f, 0x603dffcd, + 0x2cb8368e, 0x51a633ef, 0x44aceaaf, 0x3f3d74ee, 0x825f92e4, 0xf20e686f, 0x68cf7610, 0x6d12e091, + 0xc5454948, 0x8767bc45, 0xc53167e6, 0x56dd43ae, 0xd4ae028f, 0x2fed5a70, 0xc8fa50ea, 0xe82b98ef, + 0x95aff35f, 0x1fb53fda, 0x792e0658, 0x909bc6b2, 0x70bdf1d0, 0xcf5c7d4f, 0xa4f0c02c, 0x006bdbc5, + 0x47ef6df2, 0xf98a5188, 0xca47b7da, 0xaa2b8d1a, 0xa5d235dd, 0x59d6be2f, 0x7e683b7f, 0xd9d19ac8, + 0x42ef934c, 0xf5985618, 0x73220a3f, 0x543064ee, 0xe0f94ce4, 0x4fb92f43, 0x6c40eddc, 0x7c3b5057, + 0xf8083b6e, 0x5836ba70, 0xfa90c9d2, 0x121c719e, 0x0f8dae69, 0xabcd028d, 0xcba204fc, 0x3fa96e31, + 0xe48f09d9, 0xa688150e, 0xbc757992, 0xc0d60078, 0x8e831719, 0x2a508602, 0x7a7272d2, 0xf7c4e6c8, + 0xff42d54e, 0x30622240, 0x50101c0f, 0x6f7835e4, 0x3d7873ef, 0x18bf795b, 0x25efd186, 0x4258c488, + 0x9c4912d1, 0xda55a663, 0x84b75644, 0xd89f37e0, 0x5bc3e2e1, 0xd653dd89, 0x26282e0d, 0xd8b1f406, + 0xcddc19ee, 0x52d6867f, 0x292e0e0b, 0xc420469a, 0xcb8fa179, 0x84eb998f, 0xbd863f18, 0xf608e74e, + 0xff21af21, 0xe1760504, 0x2d384c1f, 0x21cf0a20, 0x2b4742f0, 0xf043f403, 0x8338336f, 0x01e6ce6c, + 0x8588051d, 0xa07f2585, 0xba45c444, 0xd3488e21, 0xb73feb2c, 0x46be51e8, 0xf2ab16fd, 0x49344a05, + 0x6f62a5ff, 0x0d89771e, 0x07696b23, 0x49490a3c, 0x326577ed, 0xe277c8e9, 0xb2f60a54, 0xd3ee2cf9, + 0xcec387ac, 0xe271d616, 0x10aafe19, 0xb0e0b127, 0x7e36c049, 0x01e21d61, 0x9647c80b, 0x3ecffe58, + 0x20f938cd, 0x90cecc01, 0xec3c42fa, 0x04cf848f, 0x9bd54ae7, 0xf49a8381, 0x69eae452, 0x60458c0f, + 0x936d602c, 0xbfab1eb6, 0x1ce28a0b, 0x81d0a12e, 0x816c4f08, 0x3a8cb167, 0xa3bdf2df, 0x69607eca, + 0x7644b807, 0x6ee2b84c, 0x9b804f19, 0x3ebd7399, 0xe102e513, 0xcc3b9d59, 0x49516dda, 0x60bb04df, + 0xce92f7b7, 0x47b7ba55, 0x7dede31e, 0x3d0d802c, 0x1c5f0e41, 0xee1004bc, 0xbd478ca3, 0x5a4655ae, + 0x9577174b, 0x9f803144, 0x0912486b, 0x7ac880b9, 0x0cff1152, 0x1e7519b2, 0x5904c459, 0x0a98690b, + 0x71357ad4, 0x5546e0eb, 0xe854b9b3, 0x733cd8c5, 0xab9fc7d4, 0x11e80584, 0x3a49181b, 0x01877253, + 0xffd959e5, 0x9fa5e659, 0x7375a6cb, 0xb1e933da, 0x4c98a1ca, 0x40f45cde, 0x7b06c1bd, 0x241bb5d3, + 0xfdd2bda5, 0x96201bab, 0x59f74075, 0x5f2f3a13, 0x376f0ab7, 0x4d62bf5c, 0xfb678b95, 0x6a39fefc, + 0x84971885, 0x4a4f6982, 0xd482fe7a, 0x899471cb, 0xdb80fe1f, 0x1b2b3707, 0x400bbd22, 0x75175b6d, + 0x2ba0cee6, 0x3b4a399e, 0x93fb147e, 0x48a25aac, 0xe45e8b8e, 0x132885e3, 0xc1fa2e54, 0x5689f7d8, + 0xe97476ff, 0xa15a5a25, 0x2b8e1241, 0xad9bb8f4, 0xa0439b29, 0x9c1a9391, 0xd70011fc, 0xf91cdc62, + 0x6bc54667, 0x5da05bd4, 0x069dc6a0, 0x4491aae0, 0xaefe617f, 0x7328e2c5, 0xd727a4c9, 0x70482009, + 0xa18cde24, 0xa865edcd, 0x4a0863f2, 0xe065e10b, 0xe25118b7, 0x1a834da7, 0xd0bf8387, 0xcadec6fd, + 0xce225bf4, 0x98a74e8b, 0x4e16eedb, 0x817d2bc5, 0x51d786aa, 0xa52705b9, 0xb6027a8a, 0xfa7a21a8, + 0x16edf654, 0xe1309c32, 0x5fa043e7, 0xca8fd090, 0xba97d044, 0xae8ad6c7, 0x54f352dc, 0x1e8e615a, + 0x94b72b12, 0xdd3ca446, 0x47b2bb4b, 0x9f5c78e9, 0x38216de2, 0x43199650, 0x9d3fcbd9, 0xa2157e5f, + 0x3b86a9f2, 0x3a810a1f, 0xe08041ce, 0xb162087a, 0xe50205ad, 0x17c04d1a, 0xdcf5ee35, 0x8430e9fe, + 0x7e4961fd, 0x061a2e7e, 0x2ae757a5, 0xfad2fe0d, 0x33ffb4d3, 0xd8d89305, 0x08179d58, 0xa2ec655f, + 0x29e62c0d, 0x60de20f4, 0x3dc354d0, 0x8dd9601d, 0x53100b04, 0x1bf6fa95, 0x36113750, 0x6fdb0fd6, + 0xcff88a4f, 0x506eb018, 0x88611eae, 0xfad273db, 0x3247eb0a, 0x3eb3ac0d, 0xf6ea9bfd, 0x7201881b, + 0x027ff968, 0x7c059f38, 0xa9dbcb72, 0xfebc762c, 0xf17edc1c, 0x6c639b03, 0x4b3a904b, 0xcec599db, + 0xd8861fcc, 0xa171057c, 0xc650cd2a, 0x4099e824, 0x21a0d898, 0xa2020af1, 0x867da021, 0xe9ed104a, + 0x9da01970, 0x96771f21, 0x4004b800, 0xce59e1c5, 0x246f4e16, 0x5821156b, 0xf809cb5b, 0x13bb2f07, + 0xb6eec787, 0xe691a9b4, 0x0171a226, 0xe53ebb14, 0x8d32cd7a, 0x9b3b87e5, 0x6bda5b7f, 0x1be7b68a, + 0x6370f716, 0xd78173ba, 0x69b668f8, 0x23d33e8d, 0x81f16ac8, 0x79a620f7, 0xd2063aba, 0x38356c3f, + 0x15263822, 0xe623e5c5, 0x29372e35, 0x8aa4187e, 0x1b229eb6, 0x07733835, 0xbe52efcd, 0x1c1010ce, + 0x8c271ca0, 0x3260222f, 0xb6953016, 0x14858f6b, 0x01915ed0, 0x5d8d5947, 0x8162abac, 0xb63059ad, + 0x11113e16, 0xe4b8c3d2, 0xfa7b5a84, 0xa97a917b, 0xded14a08, 0x73e4f7ea, 0x52c23942, 0xc1131528, + 0x52f9037c, 0x2408bc6b, 0x0a6e8f54, 0x4e45c3be, 0xc509d1f8, 0x3977f960, 0x572c094f, 0x15bf7b65, + 0x49c20c19, 0x5283a436, 0xad6b9dc3, 0xcb4a4dd7, 0xd46bc902, 0xbc89b1f8, 0x2fde7eb7, 0xa38fe2c6, + 0xc2223c9d, 0x99554000, 0xcd28bc49, 0xfee4d359, 0x8bd5b59d, 0x8fe70889, 0xc273661f, 0xf07041cb, + 0x9f46fac1, 0x7512965d, 0xe03a55d7, 0x8c5ab0b3, 0x818125b8, 0xac2a961a, 0xcfc811ff, 0x3c118d92, + 0xe3c74350, 0x9311373f, 0xe24bea31, 0x9611b861, 0x96ed3b7f, 0x553e3c53, 0x4ff910a9, 0xb16d9d48, + 0xa2a4d890, 0x4b0fb07e, 0x3ffed269, 0xc0196993, 0x6dc00cc8, 0x1f337f10, 0x1ead51ac, 0xf531936c, + 0xfe8b67d6, 0xc23bffc4, 0x1b1d2a5f, 0x15c5676c, 0x5ea5495f, 0x113a60a7, 0x9d8c8110, 0xd81a58c7, + 0xd9fe0be6, 0x657c0011, 0x090cb701, 0x239514df, 0x78030c93, 0x07261fe3, 0x3e9b67ea, 0xe01e9655, + 0xed3c8f43, 0x76d2c352, 0x90a6f1ef, 0x4fd45a87, 0x244f18f0, 0xa15f075f, 0xaaad6cd7, 0xcd1b00cd, + 0x5bf25e25, 0x1f34d3b1, 0x5993e61b, 0x4a53d6ca, 0x5ebd1c1b, 0x6233e0bb, 0x4ee16745, 0x8e41f156, + 0xc806079c, 0xc684f5d5, 0x3fa41a3b, 0x84e9f1e2, 0x78be70cf, 0x4a5e1bcf, 0x7eedc097, 0x2d95831b, + 0x4adb2b92, 0xf781402f, 0x870c8ab5, 0x303b26bd, 0x1e2bb1c8, 0x17568bdc, 0xff29e92e, 0xa4b66185, + 0x217dbe7c, 0x3b0875a9, 0xe7bce2f3, 0xb38f1a9c, 0xa4f486f7, 0x3401b40f, 0x16aed595, 0x1f80cab5, + 0x3deea1c3, 0xcddc7a23, 0x500146fe, 0xf1a69596, 0x4f96b073, 0x5d7847cb, 0x800a7cd4, 0x2174ea30, + 0xb42e3a0c, 0x7d5cc23c, 0x5679b3ea, 0xf8dfb3ec, 0x4d7cc147, 0x86998ada, 0x2e1cd1e9, 0xc7308954, + 0x995cbf19, 0x118bfefb, 0xaae48f34, 0x65866e78, 0xc96d0da6, 0xb98fe29f, 0x1517f45c, 0xb2b5f06d, + 0xddcb94e8, 0x5a73af89, 0xebf84e9d, 0xcb18d56b, 0x5835f802, 0xc5804a36, 0x5b8f80bb, 0x8b8c77ff, + 0x7ff3cfc7, 0x46a41b95, 0x113ebecb, 0xe9277d6f, 0xeb4c0dd0, 0xeb93b28b, 0xecdf7bb0, 0x572714fe, + 0x8692254d, 0x399019a4, 0xdf4f1d85, 0xf15a7cd0, 0xb6b480de, 0xdded7180, 0xaeb68c77, 0xdeb20f1f, + 0xdee4891d, 0x83247a45, 0xcb9031af, 0x133da390, 0x02f6689c, 0x7b5f28aa, 0xfcd15258, 0xaf0c4d39, + 0x3e9a6812, 0xb7981ce1, 0xd48dac33, 0xda717420, 0x3b9bf63f, 0x9cdf4cab, 0xaae00a11, 0x46442181, + 0x22351272, 0x89529662, 0x4dbbb6d9, 0xe84f8776, 0x192bcf1f, 0xf3e08524, 0x79dc51cb, 0x33b09121, + 0x87c7de82, 0xa7e16239, 0x58c7639b, 0x5cd40530, 0x789c888e, 0x79d4b7c0, 0x4f0d800c, 0x6615417d, + 0x5dc33470, 0x561f41d3, 0x092f8fba, 0x9b18d23f, 0x882a73da, 0x9a37d746, 0xb2213194, 0x520c5c4b, + 0xb59ee8ef, 0xef8df5dd, 0x127fa5ef, 0x94d75725, 0x578f467e, 0x3d65c7d0, 0xde201099, 0x4dbd49c2, + 0x98bb5071, 0xc19c75e4, 0x88293a50, 0x4a3d18d1, 0xfd7ddb8a, 0x70c91dda, 0x828ce7f5, 0x58ef7f38, + 0x4cffb467, 0x2d92df11, 0x8768fcb3, 0xa7de3819, 0x0fd3f8b3, 0xe3a57387, 0x62d5c5f6, 0xbc1c2253, + 0x7fd1b105, 0x7ecb0531, 0x6ed42c0f, 0xae4a2745, 0x9ae219f8, 0x23dc8a4d, 0x322d35c2, 0x12c971a2, + 0xc844714c, 0x83a50459, 0x8298ccce, 0x3f505f01, 0xa263cf68, 0xbe2a50df, 0x692384dd, 0x65b0a828, + 0x795f7841, 0xa403bc22, 0x95959ab1, 0xf63a64c0, 0x1a340c73, 0x26828186, 0x88a72df9, 0xf60592a9, + 0xd7f5d99f, 0x0e0b3374, 0xc8dc60db, 0x8152e5a5, 0xcc28f405, 0xb7523104, 0xba8259b2, 0x01f30de6, + 0xe5a4203a, 0x83d017c9, 0x5a6a3663, 0x395093b3, 0x5a735fd1, 0xafbf4387, 0xeec043e1, 0x5afc4f02, +}; + +/*! +* \brief Size in words of the firmware image +*/ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +#endif /* LR11XX_FW_H */ diff --git a/src/modules/LR11x0/firmware/lr1120_transceiver_0101.h b/src/modules/LR11x0/firmware/lr1120_transceiver_0101.h new file mode 100644 index 0000000000..99248596c1 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1120_transceiver_0101.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1120_transceiver_0101.h + * + * \brief Firmware transceiver version 0x0101 for LR1120 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0101 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1120_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[LR11XX_FIRMWARE_IMAGE_SIZE] = { + 0x81fc7251, 0x6c52fa08, 0xcbcdba2f, 0x5905a7c3, 0x44f4f8cd, 0xf5ed2e71, 0x543a9874, 0xf18536b7, 0x40cdd20e, + 0x6952d64c, 0x03437892, 0x9a0f8ac8, 0x1d808dcc, 0xa7df2138, 0x0b17677e, 0x607bdc0e, 0x75486ea2, 0xa878d419, + 0x12ea2ff0, 0xfea7a06d, 0x573c2b6e, 0xcd49eb67, 0x1769bad8, 0x52c4cdec, 0x027772a2, 0xfc6d15b2, 0x434ca6e5, + 0x5f270daf, 0xf753af14, 0x3e05d989, 0x841ca722, 0xabd0fb66, 0xa7d0bf62, 0x077a4977, 0x6cc2d121, 0x91b635cc, + 0x29247e3b, 0x8bef6bcc, 0x1f73c0bd, 0xbb56b919, 0xd0fcaaa5, 0x63ee9e47, 0x90d9cf81, 0xcd8b3cfc, 0x62d96753, + 0x26f42177, 0x2721345e, 0x7bc83d14, 0x1ffe2a3d, 0xd505a939, 0x60612d04, 0x7119e180, 0x5af54d45, 0x6a5f4e7a, + 0x6c80ba02, 0xd25b95b6, 0x519c864b, 0x8d1fb0c3, 0xb552cc92, 0xaaafff4e, 0x79ca25dd, 0x25fb9b9b, 0xe84868f4, + 0xe5ec88e2, 0xf611c440, 0x1b43ad08, 0x1572a47d, 0x19ed044e, 0x5f435b03, 0x5ada0e8e, 0x0597757c, 0x44114ca6, + 0xa359b7f7, 0xc03d00b3, 0xcc2dd686, 0x81fb7674, 0xe0f62641, 0x3a35266d, 0xbaa43864, 0xeff66845, 0x6402d26e, + 0x31ddf294, 0xadfc6672, 0x52e5d5f2, 0x25834b8d, 0xf3563cfd, 0xb72627a4, 0x8895cab4, 0xd80596e8, 0x05f983ca, + 0xe2ba3c22, 0xc6e804fa, 0xc6af4b61, 0xe9e22141, 0xbce1cf2b, 0xfa1cdcfe, 0xaac70feb, 0x8b54f924, 0x540cf396, + 0xb8b9c2f9, 0xe06922c0, 0xd9b65732, 0x1d1b1054, 0x326a1a95, 0x10f7860d, 0x6bb21b78, 0x7ac07f57, 0x062e2444, + 0x05afd3c4, 0x2084227e, 0x7371ea15, 0x4a4e21c2, 0x51e82303, 0xa16ddcdc, 0xd3950481, 0x899f7b5d, 0xc498d4d6, + 0xeac2c361, 0xa59fcd6b, 0xa57cea54, 0xa6b7c221, 0x2b4252b7, 0x5870f4c3, 0x5541bcb9, 0x2ffff325, 0x1c25e9eb, + 0xb9eae900, 0x747bf7c8, 0xa9e5652f, 0x993f43fe, 0xc7a562b3, 0xece5fe60, 0xd224cc43, 0x7eb57be7, 0x9d8434eb, + 0x3336a65d, 0xce618bcf, 0x6a8b84b3, 0x453fff65, 0xc7c61f6f, 0x3db9c60b, 0xa62f1a98, 0xd0e40e27, 0x0b46198f, + 0x5fec6a1d, 0xbbe43af2, 0x426ac5a7, 0x7bb8becf, 0xa725c208, 0x55678e31, 0x6d824085, 0x261bf41a, 0xc930e0f5, + 0x099b1998, 0xf305294a, 0x9cbc7d0e, 0x913903fc, 0xf15fcd7c, 0xb7a56c27, 0x601385f3, 0xde24fc9a, 0xb37d9879, + 0x5d82b297, 0x46c18d78, 0xe6b7273a, 0xa6768b89, 0x9d2f39f2, 0x51c7677c, 0x9c20bddb, 0x440902c0, 0xd5fba982, + 0x68322459, 0xb55eb027, 0x17940bdf, 0x9c69f958, 0x78b71057, 0x0a933bfe, 0x1874a39f, 0x95800ae2, 0x251d8a94, + 0x35023669, 0xad4c4c77, 0x6718a37b, 0xb05fe2d9, 0xa4281250, 0x9778b4c6, 0x70af9d3c, 0x3f62bbf3, 0xa8a0671a, + 0xd49fc781, 0x10132acf, 0xfc620a77, 0xeb644723, 0x4aedee12, 0xa127aa1e, 0xc8c2f137, 0x28dc14a5, 0x9db0e6d2, + 0x3afff107, 0x042937f8, 0x527f23f0, 0x929aeecc, 0x4b3ccafc, 0xc131e0b0, 0x1ae5f9ad, 0xb37265d7, 0x021bf23c, + 0xf462c743, 0x2facd307, 0x6c3a8566, 0x7f9b8d5a, 0xba6a900b, 0xaea8e684, 0xf27ecda1, 0x839a1222, 0xc211b81d, + 0x22980c9f, 0xb552c369, 0x2e46b04d, 0xcaec6d31, 0x2d18016a, 0x9acc4b21, 0xd9d142af, 0x32473f94, 0x1ed30b57, + 0xce7b21a8, 0x77814743, 0x998a7181, 0xab42046d, 0x4dcdba91, 0xd3d4e4ce, 0xd3cd7f19, 0xaae8b6dc, 0x1a8c33ee, + 0x64f17f22, 0xf1bd2d26, 0xf9af1b1c, 0x57cc0080, 0xd0ea20d7, 0x98b29cce, 0x7f9841e2, 0xb0ed068c, 0x2638823b, + 0x16c3d731, 0xf260985d, 0x22f9b435, 0xa1e90356, 0x7e0ac4a0, 0x0fc51ce8, 0x666f44ff, 0x4dadda50, 0x8cd76502, + 0xde47b8bf, 0x5ff70fac, 0x09c9017e, 0x4eb9cdce, 0x259aea0c, 0x4e4be421, 0xcc17c564, 0xa34cdda3, 0x202bd05c, + 0x9c7f65c2, 0x90d59000, 0xc8d85b1a, 0x2bdb69ee, 0xf15a47ee, 0xf58306c7, 0x640511f1, 0x1163e136, 0xf7c01240, + 0xdfbc056c, 0x894839c1, 0x63d8cb71, 0x21296d9c, 0x70664d8d, 0x4b1ae683, 0xd83a6f1b, 0xa6054fc3, 0xc895762b, + 0x90d8be85, 0x0f39f559, 0x7c20e185, 0x4efc18cc, 0x9845d73b, 0x1c512b77, 0x8ab1f3d9, 0xded2bd5b, 0xc0ec1cc5, + 0x8b99ebe5, 0xd8e2f469, 0xf6dd5710, 0x7d528b74, 0x56a91db6, 0xfda5cccc, 0xc31ca693, 0x9e1eb41f, 0x86ace142, + 0xade31d81, 0x2345fe96, 0x096f3ee3, 0x0bbbe2c6, 0xfe348cd2, 0x0a10f3cb, 0xe16af816, 0xa67a2362, 0x55305fcb, + 0x1d67f8d5, 0x63643a9e, 0x67ef2541, 0x38f0dd2b, 0x7a749546, 0x5bf2a8a7, 0x855cea2d, 0xa2800074, 0x1506188a, + 0x7c0cf101, 0x003fa1ce, 0xb4f16007, 0x45dec47c, 0xc6374da3, 0x18f43d96, 0xb785606f, 0xa0cbfed7, 0x838ae501, + 0xdc753f86, 0xf1a762af, 0xfdf09b5c, 0x4a1e69be, 0xea211376, 0x44a1305b, 0x9bf8d517, 0xafe04a8a, 0x0470025a, + 0x676d2733, 0xf71702b4, 0x202d079f, 0x3df281c3, 0x096acfe2, 0xde317ec2, 0x5420eced, 0xcb556163, 0x202842c4, + 0xe1b5aae7, 0x3d1eb5c8, 0xb4dc4f24, 0x647d11c8, 0x6675a9ab, 0x0adf134b, 0x509ea2dc, 0xc568b0bc, 0x1d784914, + 0xa6991abc, 0x60d0f6f7, 0x87351d51, 0x8d9600ce, 0x5dfd7301, 0xac08bb32, 0x57e0fc51, 0xd3948f6c, 0xc9b79658, + 0xed8c0cec, 0xc85499b8, 0x721ae1f7, 0xdeb8fe6b, 0x77bf8afb, 0x2db003b6, 0x0868e6f7, 0x8ae0b374, 0xcfbb85e9, + 0x7924ae69, 0xc5ea6e9e, 0x1aae3103, 0x88388483, 0x0432bf4f, 0x33ddc081, 0x5eb52433, 0xe2b0a6c3, 0x9df2318d, + 0xca023f95, 0xac8ad305, 0x3e66bf32, 0x52010005, 0x29a97259, 0xcd25c197, 0x93e8b5b7, 0x1ee22d25, 0x05e15b08, + 0x3a224875, 0x39c33dcb, 0xa416acc9, 0xf1ff03b2, 0xf7c39a36, 0x344d25b8, 0xbac0ef42, 0x76de37d1, 0x1e6755a7, + 0x1caa5a70, 0x6853c6d6, 0x03901388, 0x242386e1, 0xa6cea4f2, 0x7addaf5e, 0x87f2ddc4, 0xdac2b79f, 0x19ce17a9, + 0xc6b03777, 0x59df40c7, 0xbabe1e07, 0x7c42b47a, 0xf7eb8b9f, 0x51a25bb9, 0x92c52150, 0x91b8d168, 0xd451d7dd, + 0x36a95937, 0xb5254e3a, 0x513589b8, 0xcd2ff1a4, 0xa97af12b, 0xe98331d2, 0xe224d244, 0x273654ae, 0xc40d0d0f, + 0x448cf57c, 0xb6228d5d, 0xe71e61f2, 0xf66ea951, 0x7cb73a1c, 0xf85e9b95, 0x672f0bac, 0x73b71222, 0x218247da, + 0x5b9d2736, 0x76f4b7b5, 0x5ed069f5, 0xbf2f285b, 0x17f97d96, 0xd7422153, 0x58f78cfe, 0xc44978bd, 0xfb2dbcac, + 0xc55554c8, 0x33db2de0, 0x27138275, 0x30ed81f1, 0x365bd2f0, 0x014d661c, 0xd871e11b, 0x72bb4f2a, 0x050e3d58, + 0x6344c276, 0x01bb83eb, 0x313a7331, 0xac7ebd0f, 0xfd82e0ae, 0xf537a0b9, 0x4372d84b, 0xe7c792e7, 0xf52d1bd0, + 0xd7b3a8b9, 0xf2a458e1, 0x93e16627, 0x1fa0741a, 0x0723a805, 0xe8fe0219, 0xc4a2d136, 0xc30c9249, 0x74606dc3, + 0xdd8084aa, 0xbdbb5428, 0xa7157d7f, 0xcf6a6d5c, 0x4ca2885e, 0xba367576, 0x8d266262, 0x2d6eddc7, 0xda6ebd6c, + 0x23f561de, 0xab7116bc, 0x7b4852ea, 0x22efa84f, 0x76aec382, 0xec99b02d, 0xdc9227b7, 0x334f9118, 0x0bdfa4b4, + 0xd33b2fc8, 0xb3e6eea2, 0x06b513f0, 0x6c0aff4d, 0x438eb5ca, 0xa7ca6829, 0xb5c0e9f8, 0x77d1b70d, 0x52d44986, + 0xf7b1b4e8, 0x470f6be4, 0xb233bf17, 0x6cedd356, 0x21e9a8c8, 0x90f2f7e9, 0x55136998, 0x57508489, 0x292c2ecc, + 0x702993e8, 0xfe2d8ea3, 0x76335aec, 0xf6138437, 0x9c1062db, 0x79559f01, 0x568a17d3, 0xc77b806f, 0xdeb0326c, + 0xedb67939, 0xb527c477, 0x2f392f8f, 0x507b0a17, 0x0b3adbb1, 0x3891a25d, 0x8573b028, 0xc6229427, 0xb266fcca, + 0xaa58ebb8, 0x0044c981, 0x9db57156, 0xe41d8bea, 0x678f9d81, 0x922ebc4a, 0xc8b984a7, 0x66a58fb1, 0x47a6305d, + 0xf9a00593, 0x313f9988, 0x0fb4a481, 0xd2b05e6e, 0xee21f927, 0x9d08fc52, 0xa592b5d6, 0xc2bc670e, 0x0a6cdbc9, + 0x94587152, 0x8dcda718, 0x40925986, 0xb66e0d2a, 0xdbf3cfa2, 0x56430f39, 0x4636bb3f, 0x936530cf, 0xdfe0b9f1, + 0xb993796b, 0x87257eb0, 0xa60963c4, 0xd1e74578, 0xd9df2cad, 0x43c97804, 0x167251c5, 0x5387fc5b, 0x17b0c10f, + 0xaaeb7490, 0x77bddd09, 0x9f33b9e3, 0x4bac5237, 0xbf236266, 0x74683669, 0x43f11f0f, 0x6ade53e0, 0x192369ad, + 0x59f77002, 0xfac44180, 0x2953e44d, 0x1fdb114e, 0xf669889b, 0x2b61acc9, 0xe4352267, 0xdfb7b4e4, 0x761b8ee1, + 0x0acc7b2e, 0x3b92007d, 0xb228ba02, 0xe4c4d50d, 0x647b4812, 0x47821f20, 0x27b3d6da, 0xae98df94, 0xfee4df50, + 0xfe499b01, 0xb3e773e9, 0x358e60dc, 0x421a877d, 0xf26d1736, 0x29c76b5d, 0x0de3e4f9, 0xcff1ae74, 0xec735e1d, + 0x77b5ea15, 0x9c56eb26, 0x652c9bf3, 0x54f38e8c, 0xeea8654e, 0x0ac0fbbe, 0x016a2078, 0x04d1498d, 0x2ddef79e, + 0x9a3c3f3e, 0xbedc5b3a, 0xb1d8e12c, 0x565cd3e1, 0xa7572f0d, 0xc3b6827f, 0xe54d56b6, 0x2d0fd02c, 0x94f1707f, + 0x8d778787, 0x773a0350, 0x62f1c2f7, 0x38fccc2d, 0x153f0aba, 0xe9ccfdae, 0x77978286, 0x2e9c2382, 0x5ab40377, + 0x9f0340d9, 0xcb5c31d9, 0x8af6afa3, 0xbf61fb2c, 0x5b207e5f, 0xb9aef3e1, 0x19888db8, 0xd484eb05, 0x9b93b0b5, + 0xa1c56680, 0x36dcd925, 0x49927465, 0x2829ca2a, 0x758366b0, 0xd03fbb63, 0x1d6b1283, 0x24b65a95, 0x196d07ad, + 0xdd29cabd, 0x1aafbb2b, 0x8da9f4ae, 0x50cb58d4, 0xb5076573, 0xe9e4afdb, 0x38e565fe, 0x9aa4d6a1, 0x0d79199d, + 0x7a122361, 0xcea2ac31, 0xa28722e8, 0x9a66ddde, 0x7c105026, 0x905d0d87, 0x375c81dc, 0x0793854c, 0xc47a14b4, + 0xdbca2756, 0xb86da3b9, 0x695a14dd, 0xabab15fd, 0xa3955050, 0xae7d8ff4, 0xb5edd9f4, 0x9cca1c50, 0x84a8f5c8, + 0x1553511d, 0xf0aadf07, 0x92f7081a, 0xcd550682, 0x042d9acc, 0xc8a6d807, 0x6629a7fa, 0xa80169c2, 0x1a94c68a, + 0x7d9a3885, 0x6c3f80fe, 0xb1fdffb4, 0x20ea5bad, 0xa6ed1857, 0x5cca96f0, 0x0cf235df, 0x5355eb1d, 0x778c2809, + 0xf678abae, 0x02a841fc, 0x99f74867, 0x835bf54d, 0xc38b9dc9, 0x1b0936b9, 0x0b15cdbd, 0xb2d79182, 0xb8a52cd7, + 0x1bb8406f, 0x621c1f0e, 0x33e0eba7, 0x2afa47ab, 0xa5116915, 0x7b98f6f7, 0x5e6355fd, 0xd692018d, 0xfda2b7b7, + 0xdd8b1a9d, 0xe5bfc9ba, 0xef1f5adc, 0xe06ad7bb, 0xaf620d0b, 0x947198b9, 0x8cd5edc7, 0xca7391a7, 0xdfcee062, + 0xf849934d, 0xd8acb4ba, 0xcbb13d3e, 0x60777893, 0x59481560, 0x4c3e3d2a, 0xc37185c2, 0x62d406a7, 0x5ac51db0, + 0x48c0d015, 0x34c369d6, 0xce939010, 0x53745749, 0xf6448e0d, 0x54ac4974, 0x9671f8f1, 0x6d0aeec8, 0xe2bdaa99, + 0x800777c0, 0x06056028, 0x90b7f459, 0x9fc8daa5, 0x63de230c, 0x4922abca, 0xd49f0606, 0x4a31f9a3, 0xf7b43224, + 0x5bfa1717, 0x0c06a0fe, 0xd72b95c3, 0x5ef6c224, 0x9ee4bd11, 0x369b02e8, 0xfe2668fe, 0x3c03dbcd, 0xd73abf6d, + 0x443463eb, 0x7dd7a249, 0x7ef30a16, 0xd067f186, 0x6e687799, 0x1ff311e2, 0x9aaf257f, 0x024ddd28, 0x066f5fc6, + 0x54b5b3e1, 0xffec6a78, 0x3877758c, 0x037c9315, 0x7fe61cf5, 0x05b9a1a2, 0x17147b19, 0x03adf5f9, 0xcba1cf52, + 0x64f5d1d7, 0xde9059ef, 0x6b03a677, 0x10179c2b, 0x3c2aad34, 0x1f17db04, 0xc0fc820c, 0x426d9530, 0x2afc4500, + 0x4626337a, 0xd979ce23, 0xef48927e, 0xf3db2f86, 0xc025c9c2, 0xc7e280e0, 0x7ed91650, 0x0caf69af, 0x87326780, + 0x7c516316, 0x3f2d12f8, 0xf41a88d9, 0x2c097836, 0x8a031626, 0xca539478, 0x49287a80, 0x23ac4019, 0xf5bc30ab, + 0xf178ef00, 0x2047b5d0, 0xacc55587, 0xb15100c7, 0x4b2d83bf, 0x32aa65ea, 0xd6d8b524, 0x0ad4a4dc, 0xa0f153c1, + 0x29a87ab7, 0xe14f6be1, 0x62d398d9, 0xd182c464, 0xfb8295b5, 0xe2b0e739, 0xadf43c97, 0x39b165d7, 0x287913e9, + 0xe375cda3, 0x5d01d073, 0x63da4cfc, 0xd8d26d4d, 0xf2e6ceed, 0x1d45bfe2, 0x6967beba, 0x902e5b0b, 0x375e0fe8, + 0xf7cbf5e8, 0x690bad52, 0x2b0d570c, 0x4830d9fd, 0x501344b6, 0xc6ab2f86, 0x67b12ea7, 0x1b85bf19, 0xeb8470a6, + 0x5ffd0d9c, 0x54bc625c, 0xf312086d, 0x13630775, 0x969b114b, 0x04b45c1f, 0xdb746b87, 0xa9fe4947, 0xa3bce045, + 0xa848992c, 0x69f751c2, 0xc8c01189, 0x5f7757a8, 0x87154694, 0x6a1ddea8, 0x210cb254, 0x6fb1f6df, 0x34d3cbaf, + 0xb11cfba3, 0xa625bb3c, 0x70638620, 0x32b33452, 0x9905ecfb, 0xbf2b0fcf, 0x4b27377a, 0xd118234d, 0xc838d9d2, + 0xf976e8b9, 0x2d6d0719, 0x753f2730, 0xbf6408b6, 0xff47e4b0, 0x05a566ac, 0xa596e72b, 0x3d600116, 0xc4d54ac2, + 0xd6b9df4d, 0xee6d548e, 0x391beca0, 0x06668b1d, 0x1acfbd9a, 0x4b4059f4, 0x857b9ab2, 0x82635233, 0x08509d20, + 0x0c638a64, 0xad1c5390, 0x49aee3d3, 0xca26c2d5, 0xe3d68146, 0x99d72f1b, 0x7bc2a35b, 0xf2c4e4d7, 0x98c4602c, + 0x72673044, 0x99264051, 0x076d6ea0, 0x39a0d3a8, 0xbefe0afb, 0xed62b1bf, 0x8262d41f, 0x2e6dae0c, 0xff8ff299, + 0x34ed9186, 0x808cbfdd, 0x5af6a5aa, 0x96a2eecb, 0x4b9cec4c, 0x5a6b4474, 0x2294e4be, 0x0a1859dd, 0xa6d2b695, + 0xf28c10f9, 0x76014db2, 0x9b47296a, 0xa644ffe0, 0x05336d82, 0x97622677, 0xc9c3db6c, 0x6685385b, 0x25dcd80b, + 0x2b79cbe3, 0x9f43518d, 0xe69378c5, 0x95d4ab20, 0x49067ecb, 0x2797ce90, 0x993a22a6, 0xf3befe22, 0x46ee6998, + 0x8bd22901, 0xb51bc3c4, 0x9643fe7f, 0x43f211aa, 0xb12e15ea, 0x06c7179e, 0x06cc1949, 0x1eabfced, 0x50d121a8, + 0xfa49f700, 0x95875f6a, 0x8c43d622, 0x29a3f55a, 0xf668119d, 0x74557ec7, 0x9f5f68cf, 0x72485a25, 0x3d2639fe, + 0x258cb56f, 0x58af5c4f, 0xf364cefb, 0xd03d6488, 0x80aeed37, 0x50feaff9, 0x81591a47, 0x11d50098, 0x7a96599b, + 0x991da261, 0x276bff00, 0xdbfe9367, 0xc4c2121b, 0x4388223a, 0x5d8d0350, 0xd0de5baa, 0x19994a2b, 0x9e705a1b, + 0x76158efa, 0x2de8c4f4, 0xdf4331c2, 0x78fe8f9b, 0xd7d6e0ce, 0xf70ebf41, 0x49260a3b, 0x23481deb, 0x07a3d05a, + 0xd5b8fbcf, 0xc41924d5, 0xb3adfa8a, 0xe56d0d29, 0x3a3095a7, 0x472b3039, 0x6f925e85, 0xaf41ca59, 0x60bd82cc, + 0xff4b23bf, 0x22425143, 0xd14407c6, 0xb28d3283, 0xc3ed586e, 0xea299374, 0x6cedfd5b, 0x6f6d7e21, 0xa8db6876, + 0xd6b84fdc, 0x880cb8c8, 0x5dd2a6b0, 0x3c74e603, 0x474ebf14, 0x7a8cba3b, 0x2623bbdb, 0xae2bf6e4, 0x8d154ff0, + 0x216b80ac, 0xada3914c, 0x70c1862a, 0x110bda4e, 0x98e9df8c, 0x03811d0e, 0x8667bc24, 0x8b970e4e, 0xae538ef3, + 0x1f24e517, 0x97046efd, 0xa1d301eb, 0x42f95cf9, 0xc96c3241, 0x111ab577, 0x4c85fdab, 0x5278bc4e, 0x78103cce, + 0x973de5f4, 0x7af903ca, 0x19355249, 0xa3242091, 0xc81a9126, 0xf74d6419, 0xfda32318, 0x98c46e16, 0xeca66bb1, + 0xe8bca86c, 0x4599a8ae, 0xb556d207, 0x77ae327f, 0x74343cfe, 0x983f6c65, 0x4579fcc5, 0x7b8fec97, 0x06912054, + 0xbc811df8, 0x90944274, 0xf698ba28, 0x50c6b20d, 0xaab41364, 0xd7dbf3e6, 0x1a05cef1, 0x549e0df5, 0xd4b6adbe, + 0x7ed4c36a, 0xfc0d5560, 0x2b1e015d, 0xf4a300c8, 0xde142dc8, 0x04d49c4a, 0x45c87b9d, 0xdb4e5cdc, 0xe1926222, + 0xb8a063bf, 0x256a8af0, 0xe142f134, 0x39d3d4e3, 0x08abdc8c, 0xd77f6ade, 0x1f783319, 0xddfb43a4, 0xa2a0613a, + 0x11328c5f, 0xee0e711f, 0x7b61f14a, 0xe38a90f9, 0x205ad734, 0x0f2e0794, 0x47c7e0f5, 0xbba3aaf3, 0x53c5d316, + 0x2241a6f1, 0xa9e4d498, 0x8600d93f, 0x4783a2fb, 0xd55600db, 0x398db0ff, 0x19219101, 0xd649dd08, 0xb59da38e, + 0x41bb34f2, 0xd11a1289, 0x21c220f9, 0x29e6c9c0, 0x8b6fd350, 0x5f593fe3, 0xb2c131be, 0x5ae17a52, 0x9d122709, + 0x6216e5fc, 0x8f8782d7, 0x403964c8, 0xffd04f4d, 0x12761a3a, 0xb81a6976, 0x3d44fb6d, 0x33162de9, 0xbe53fdf0, + 0xc6e1df1b, 0x875af6e9, 0xc60d8028, 0x49ab41c4, 0xb4fa13ab, 0xd5a4fa6d, 0xb0d000e7, 0xe84cb92c, 0x8f70ad2a, + 0x4c871b40, 0xd867ea9c, 0x2502e9c8, 0xdf936b2e, 0x133abaf4, 0xa0c834d6, 0xe748fa4f, 0x7a22916b, 0x561f7971, + 0xd930a25d, 0xbdf72d1d, 0xc76b243b, 0xbdb2e339, 0x49b84ec6, 0xcaa51f1e, 0x4d92c94e, 0xe5ceb6ff, 0xefe8237d, + 0x628330d7, 0xff50c681, 0x48020d5e, 0xdbf8b9df, 0x7c9a0c93, 0x07c218b5, 0xb04e0dad, 0xe623ab0f, 0x3e64f02c, + 0xa59f598a, 0x09f8657b, 0x41173625, 0xcc593d10, 0x49d97d57, 0x35f55c0f, 0x24a72482, 0x789184f1, 0x1b1b0ffe, + 0x7d5238bf, 0x24f2f2e5, 0xbcf77fa2, 0x718961dd, 0xe18f45c8, 0x9065e949, 0xc998a5d9, 0x73048a2e, 0x7ae6b06e, + 0xe51e15e0, 0x8ee1eef4, 0x4bb2f19c, 0x7eed75d6, 0xff152e90, 0xa734af0d, 0x2c4df279, 0x712cf840, 0xd15bed24, + 0x22a106c5, 0xae6508b7, 0x30704245, 0x9f06e73f, 0x67333c1e, 0x6ee07bde, 0x18684260, 0xbe70456a, 0xd03a0695, + 0xdef77110, 0x8096aeae, 0x885c16c3, 0xeefef126, 0x7333357d, 0x7fcae80b, 0xb98fb128, 0xab7c9324, 0xb235c30b, + 0xa18ccd83, 0xec636faa, 0x9e84664b, 0xae9c718d, 0x2dcea525, 0x3e3993b8, 0xd2a2f8a1, 0x2ed751ba, 0xdeb2b0e6, + 0x3822c28d, 0x48da9cb0, 0xdfa2aded, 0xfc879bc2, 0x84cb3295, 0x46c3ccf1, 0x110634ac, 0x5f3dc46f, 0xfa9acaed, + 0x29a2c8cf, 0x03a65568, 0xbdfc6720, 0xbd9870a9, 0x98c9ae15, 0x4698b09e, 0x45ff18f7, 0xf6197177, 0x311bccdc, + 0x6b937d8d, 0x9aebae81, 0x2231e105, 0x9b49b1e3, 0x465b5365, 0xeef0312e, 0x7911718d, 0xa9d9d86a, 0x436f9e66, + 0x2fb4f785, 0x39f69c1b, 0x6b8fce09, 0xe6cbdb02, 0xd652c59c, 0x7f7de20b, 0x056d020a, 0xf13d9dae, 0x624e9ecc, + 0xac77cdee, 0x439cf983, 0x93580298, 0x92556375, 0xf67b79e4, 0x08812b16, 0x237858a8, 0xe3aa2c72, 0x629e53dd, + 0x4735074a, 0xb3b308dd, 0x89a4b427, 0xba942329, 0x69be970c, 0x4aa974e9, 0x89507aea, 0x299b7bac, 0x41bbfc73, + 0xb5f39464, 0x6e49f5ce, 0x01b30f19, 0xbc6f295c, 0x888de911, 0xf96e9862, 0x49a63d95, 0x3d455803, 0x33ce8ec0, + 0x6129d743, 0x51def589, 0xd0e7ec8f, 0xc925adce, 0xe187d5c5, 0xe7233c37, 0x13c37de0, 0xb21f159c, 0xa0c8d9e1, + 0x32844aea, 0x7b5d8345, 0x17b46123, 0xf8eefcd0, 0x3de8993f, 0x110f923c, 0xb86833e2, 0x64097311, 0x9504a543, + 0x6039b8a2, 0xb04d88ec, 0xc56d33fa, 0x2fce359e, 0x60cf220b, 0x059de80e, 0xc7983afd, 0x5aed66a6, 0x270c27d1, + 0xd5a1b783, 0x783d5b33, 0x2f7a7cf5, 0xad04ad0c, 0xadf745e5, 0x007003f6, 0x30ed42d0, 0x533ed822, 0x2442f5bc, + 0x91007e7c, 0x8ce5eb60, 0x3e9b77b8, 0x649a07cc, 0x05c4e22e, 0x3a2bf192, 0x3dbd1a6d, 0x1c047175, 0x9160512d, + 0xdadaefc4, 0x16972f88, 0xd827a229, 0xd3a34179, 0xff698922, 0xf73b2640, 0xe9f5005e, 0x1851d0b6, 0x9f94787c, + 0xca5298d4, 0xf4cd8cb7, 0x940453b7, 0xa3ebc5e4, 0x34da3b06, 0x8464c209, 0xcff81b8d, 0xa3d3fe56, 0x3c34e397, + 0xb3d8b310, 0x6bfe67f3, 0x00b44479, 0x12920ccb, 0x2bd85d0c, 0x5d9e92e4, 0x858cf763, 0xc23b1717, 0xab9aaeed, + 0x2e538ed3, 0x02c28174, 0x5a0ea334, 0x74d51121, 0xbb1a82c9, 0x4ee96f86, 0x142942dd, 0x7e68fe24, 0xc1f3bbad, + 0x26a6e4a4, 0x21f3fb09, 0xe299ecfd, 0x6980b4bc, 0xa3e91612, 0x3d0097c1, 0xc3424df1, 0x86e7653a, 0x63e1050c, + 0x5e9d61d1, 0xa6c28a3c, 0xe92b7192, 0x09f30252, 0x4723bcff, 0xbacf47ce, 0x0fef1075, 0x08c84d0f, 0x55f231ca, + 0x8a42ee1b, 0xcf5c9a5a, 0xa38d4d18, 0xcda9d672, 0x566dc57c, 0xcd0d2044, 0x5cadba07, 0xd36dece0, 0x0abf40f9, + 0x4993baaa, 0x66958333, 0x61ce946a, 0x57d98961, 0x99a6759c, 0x830fe7e8, 0x8706923a, 0xd9fe6791, 0xed8d2db9, + 0x8130897d, 0xd2af8d9d, 0x9660e9dd, 0x0f24d791, 0x8a36853f, 0x20752514, 0x5c8b893c, 0xf8d64f0d, 0xa71e2ff7, + 0xcf6b0200, 0x7cf62c7c, 0x462bb468, 0x6b07bc9e, 0x9ed86161, 0xcb7792ca, 0xd6f6bd39, 0x0cf5c208, 0x4cb5869b, + 0x62e13dd5, 0xaa0a14ff, 0xfafe19d5, 0x57844267, 0x969f0e0f, 0xaca82143, 0x3705303b, 0x86c9729a, 0x29ff2eeb, + 0xc9dd8585, 0xc65a5c35, 0xe14e11f2, 0xd3625d7e, 0x6778bd81, 0x942c8fb4, 0x55d6c0b5, 0xfea3b83b, 0x43594bf0, + 0xaeb2a600, 0x53a341f4, 0x125aacf8, 0x9e65d088, 0x6f2c883f, 0x1f0fa5f2, 0x2fb151b2, 0x9ae22069, 0x8e3f506f, + 0x15501040, 0x1de8deb8, 0x591d693d, 0xa074a940, 0x18ae9d9e, 0x4ef614a4, 0x22865fe9, 0x36ed416a, 0x7922e1fb, + 0xf31807bf, 0xf727e216, 0xc9ea4057, 0x211009cb, 0x8aa1babe, 0x435d919e, 0x9201a21e, 0x03918241, 0xb589fc56, + 0xba033638, 0x65edd51f, 0xd8d790f1, 0xb2224eca, 0x8963b4d2, 0x04764b1a, 0x9728106c, 0xa117764e, 0x055d9dec, + 0x47627138, 0xb7af13d8, 0x40d3b71a, 0x906aed9e, 0xf835ca4f, 0x8ddf7812, 0x9a968c6f, 0xbc526e55, 0xc61384ec, + 0x4cde949d, 0x6e87663f, 0xca0d94f1, 0xf480a728, 0x46fc2431, 0x72f7509c, 0x9e777d59, 0x0b79b152, 0x36234d05, + 0x50a2ffc7, 0xa9ad8670, 0xbb2bde8f, 0xb1b4cb36, 0x2011b76d, 0x6e3c261a, 0x8c5be6d1, 0x30d10e48, 0xf3bff1c8, + 0x6763e89c, 0x5519f030, 0x21375a91, 0x820349e0, 0xe8014aac, 0xd0777123, 0x9a13c9c3, 0x442a216c, 0x5f1b04d2, + 0xd1aed795, 0x68339390, 0x977dcdf6, 0xc68e8397, 0x7ad3e8dc, 0x9094d754, 0xfc2a33aa, 0xdce09e75, 0x63eece2b, + 0xb9d844e2, 0xc71eedcb, 0x24c66daa, 0x18cf9c54, 0x0b647ed0, 0x1cc35070, 0x883da0ed, 0x6eebf739, 0x1ad98cd6, + 0xf67e425c, 0xf909730f, 0x1c36c693, 0xf1d41b0a, 0x8f857123, 0x50c5d67d, 0xb3bfea9d, 0xf16d034c, 0x0e021e3b, + 0xc03af2e4, 0xab6f0dc0, 0x759ed099, 0xc6bbd774, 0x3714c1cf, 0xee01c8af, 0x1cbbf0e6, 0x03d10239, 0x1338aaf9, + 0x6ea84add, 0xf87145e5, 0x4d5e0063, 0x5b2808c8, 0xc73b1965, 0x6b86ee5d, 0x33a7d7cb, 0x317e5076, 0xe048fb34, + 0x501229a0, 0x87975d2a, 0xbafa1294, 0x630dc7eb, 0x20f65a2e, 0xfee5ea7c, 0x56c44528, 0x78a3bf88, 0xab5c437a, + 0xfcdb5100, 0x97832a05, 0xb2a6cfe0, 0x47103a49, 0x0eece938, 0xc4253dd8, 0x2e692afe, 0xdc34de85, 0xd9b1e35a, + 0x65342c84, 0x9138518b, 0x6f7553a3, 0x379ab40f, 0x2947346e, 0x06fa1e47, 0x37ab1a1d, 0x7b62497d, 0x6b9286e0, + 0x97bcf746, 0x6ef082e9, 0x3e1766dc, 0x1409fa58, 0x8ce79768, 0x8db4cdbe, 0xaa52d4ad, 0xdb8dd905, 0x9f63d2f3, + 0x43bcd5d0, 0x17e9510d, 0xc7fb7745, 0x8b981832, 0x17f47a51, 0x4dc6151b, 0x9b1f99aa, 0x44a36417, 0x34913b73, + 0xbc3d44fd, 0x3a371589, 0x08f01084, 0x61f819f6, 0xcf0fa72d, 0x36ab869e, 0xe3527c6c, 0xbf89f0a8, 0xa5707c86, + 0xc92e1937, 0xd33f4922, 0xe8331892, 0x8c1a7c13, 0x9b409bb8, 0xe40451da, 0xa00cb08a, 0x78b0f69c, 0xa5919ce6, + 0xdbb59429, 0xae3655ac, 0xbf1818bc, 0x3d7830aa, 0x4ec2fe2f, 0x05fecf34, 0x2e99eaba, 0xa5f144ce, 0xbfd63bea, + 0xcec68fc7, 0x853055de, 0x59db3e1d, 0x5ab3c00f, 0x95b9ef74, 0x5962fead, 0xe7b4ca98, 0x5ee69a00, 0x030e4dc1, + 0x4747faf0, 0x43a98254, 0x4812a7f2, 0xd47ea5de, 0xe6073e83, 0x2b8c6a6e, 0xa2c92019, 0x0f5c0769, 0x51f7bcea, + 0x434eea13, 0xd780acc9, 0xbe91a8e6, 0x71176e61, 0x70c312bb, 0x21d699c9, 0x2b2686b3, 0x3204f2a7, 0x390c0bcd, + 0x7cc633a8, 0xb9ff0685, 0x0868e332, 0x7925b84a, 0x49b67284, 0x37ec16ca, 0x08a29fe9, 0xe7109a50, 0xcabe5e50, + 0x911b6ea6, 0xb34a4f9d, 0x9f1510a7, 0x46314ac4, 0x269a3d15, 0xd923e576, 0x9f3909ba, 0xaaaa4ed4, 0x7bc8a8c4, + 0xb0b1717a, 0x81b19c73, 0xb56c4f7b, 0x9d349eaf, 0x8725dbde, 0x859a3e68, 0xf324824f, 0xec3137ee, 0x0c7fd587, + 0xd33cb69c, 0x2e57a264, 0x28436538, 0x0922d506, 0xbe29d89e, 0x171b1fc3, 0xecd4afe8, 0x124f388d, 0x22e5c551, + 0xbb43a1d1, 0xddde7c68, 0xfbd5527d, 0x51c1be26, 0xe7ca19f5, 0xfe68daad, 0xf86cee68, 0x18f08cf1, 0x6a881e8a, + 0x006b2b90, 0x88078b31, 0x808c5106, 0x7194b603, 0xcb694082, 0x9281d56a, 0x5eb3c08b, 0x2717844a, 0x48154703, + 0x383b043c, 0xcf2d7d28, 0x15f2dbcc, 0xc5e846b7, 0x9dc3767b, 0xa3251774, 0xafcb929f, 0xf6f75ce5, 0x4fe1aaaa, + 0xc10b47bd, 0x1a34090e, 0x7387f80c, 0x49410ef8, 0xdcfcac7e, 0x16d2027b, 0xdaad2af2, 0xd2491d9e, 0x68313d8c, + 0x1392a02c, 0xe1bec43e, 0xdd2eddd8, 0xca18b891, 0x42c1f35e, 0xd99d61b4, 0x186ec620, 0xaf22e256, 0x7e12d1ea, + 0xd2c54f5e, 0x2bcceb80, 0x0b438288, 0x0b0dbd88, 0xab4f52d4, 0xf97d7a94, 0x26696d43, 0x78373e5f, 0xba2601dd, + 0x5c1c5fcf, 0x0afeff57, 0x692be494, 0xb757456e, 0x83b68816, 0x9e01f57e, 0xd22be365, 0x76e0c04e, 0xc531e0a0, + 0x245b2c60, 0xd86677c0, 0x8bab88b8, 0x416df0aa, 0x79158136, 0xd5c1c3d5, 0x8854bbe0, 0x41c67169, 0xfc131c8a, + 0x850d580c, 0x2dc8f545, 0xf6c73471, 0xb75654d3, 0x7e06c611, 0xd2a65ede, 0x9c198e3b, 0x07c97e0b, 0xfbe4ae0e, + 0x608e2b56, 0x589b8921, 0x9ac45078, 0xea31c54d, 0x0a8afa33, 0x388da47f, 0xf11c06fa, 0x358cfe92, 0xf88fde5d, + 0xb6f22853, 0xb6e17a0d, 0x0a56f343, 0xf6da9c32, 0xd8a205b9, 0x77e9de68, 0x2fd44edc, 0x1e811265, 0xc0c9b326, + 0x64882ca3, 0x4c6d4caf, 0x8ea8f028, 0x488f3f09, 0xdacca5ac, 0x50187e84, 0xa024124c, 0xab5fef97, 0xbf77f407, + 0x7453c9e8, 0xa1e40b40, 0x419bca6c, 0xff62edc0, 0xaeff306e, 0x56da30c2, 0x0995d3c9, 0xdb24db99, 0x383d95c3, + 0xefbbffc7, 0xc7924178, 0x8dad1baa, 0x2e9eac03, 0xab6b17c7, 0x87a742b8, 0x640646f9, 0x2da315f0, 0x861de6ac, + 0x450387c0, 0x6539bafd, 0x3426a9d8, 0x870f8c64, 0x3325cbdd, 0xc704d3e3, 0xd709c9d3, 0xab8b3bd7, 0x7ec78757, + 0xfc424214, 0x98f23d4a, 0x84e998d7, 0x83a3cce2, 0x58f52a8d, 0x46b6bd13, 0xac0f97e1, 0x376d93a6, 0x8ad9de69, + 0xace704f4, 0xc3a79f42, 0xb99f44ab, 0x17d38447, 0x80f5eb3c, 0x82a1f951, 0x3299939e, 0x965b0112, 0x4fa0ace8, + 0x9bae36ad, 0x58a26ea7, 0xd256f712, 0xfd0dda9d, 0x5ec2b38c, 0x8a6aa523, 0x7a8c1125, 0x80c93fb8, 0x9c83fca2, + 0x6f745fab, 0x3cf99405, 0xacbdbd30, 0xa8fb7aed, 0xab805ab8, 0x37847f3f, 0x670146a3, 0xfd4b0f09, 0x2b6a655d, + 0x0aeb7b5b, 0x889c0f28, 0x42344fe7, 0xe8ced261, 0xe8f7cdf1, 0xca67104f, 0x84a39f06, 0x43fd2da1, 0x04c12c0b, + 0x6d0bbadd, 0xc22da43b, 0x71847abb, 0xfbf53a93, 0x84f6605a, 0x4ab41249, 0x662a1f6c, 0x7b931ee1, 0xa4e8edc4, + 0xd0199db3, 0xea618f64, 0x8203794e, 0x032c58dc, 0x837ebd1b, 0xce716f33, 0x73ff28de, 0x55671fb2, 0xd42e88a9, + 0xc6fbfa69, 0xc6838f40, 0xd6c99241, 0xfa4c97dc, 0xb16f1a82, 0xdddb1381, 0x14351a83, 0xd5ddc6c4, 0x03c3d5d0, + 0x25f62740, 0xe27f38c8, 0x62b7d3f3, 0xf159c3bd, 0xd49c1ef8, 0xc4d6e4b0, 0x830bcc2b, 0xfa449599, 0xc72f5b3f, + 0x5d1a8786, 0x0e11a47e, 0x6718f946, 0x2e0e7cbb, 0xc64930c0, 0x2e61418a, 0xe82ad10a, 0x8bce6cdf, 0x22807ddf, + 0xf21e019c, 0xad75c4d3, 0x9150cc1f, 0xd9b44488, 0x96a4bf51, 0x3db1ad32, 0xe0da2aa8, 0xaf1b4979, 0xd7875431, + 0x9795e493, 0x121e1acb, 0x71d0d612, 0x51d18815, 0x5e9ae668, 0xe22c8762, 0xbd8bbb0b, 0x2ced1bb9, 0x5338ddce, + 0x5d100ecc, 0xdecbba55, 0x0aee2c19, 0x17d5247b, 0x077b9fb4, 0xe59809c4, 0x18cc0f85, 0x671796bb, 0x17bbac05, + 0x72793625, 0x20e5bf0f, 0x8da3fd22, 0x063e17b1, 0xecb4308e, 0x42df1f16, 0x98417292, 0xe54e2faf, 0x9f24d8ef, + 0xcd20a24e, 0xab88253f, 0x368c62df, 0x16474d54, 0xd2922353, 0x6071cc5c, 0x282711bd, 0xfa69dac3, 0x3be55929, + 0x82579262, 0x90ee2c49, 0x987a54be, 0x195ca6d0, 0x07cb9ca3, 0xf60b91c1, 0xedc2b8fe, 0xb08747f2, 0xb871c166, + 0x64de10fc, 0x8067e129, 0x5d583774, 0x2763e3e1, 0x08e63251, 0xbbb95fd6, 0x0eab78e5, 0x7f6c8d10, 0xa9261902, + 0xe1cc5ab5, 0xaea35383, 0x5311470f, 0x025bb277, 0x030af42e, 0xbcd57bb6, 0xb9d81543, 0xee9ba547, 0xa35d820c, + 0x6a455a46, 0x07ab6e70, 0x97a56892, 0xe5df9e28, 0x2f1e8754, 0xc9134d1e, 0x3d95abfe, 0x01b1e7fb, 0x6fc4b1ec, + 0x41fa30ef, 0xf20739e6, 0x9a66e261, 0xf1dc0188, 0xc2c34b9f, 0xbea5f504, 0xd98effb1, 0xc6b94f4e, 0xca183542, + 0x0e9d0ce9, 0x2261d8d5, 0x99463b41, 0x6d69dbc1, 0x33d6a6f9, 0x1c37300a, 0xded1accb, 0x88f48482, 0x638b195f, + 0xc5213a94, 0xf5b90c2a, 0x574452d6, 0x86c46876, 0x99aae917, 0x5f7fb8a2, 0x44e32cc6, 0x1ed13931, 0xfce6822f, + 0x27a01992, 0xc7e9285c, 0xb3f9e8d2, 0x3c45dead, 0xc66e0278, 0xe865e243, 0xfbb722de, 0x06f7b609, 0x23b870af, + 0x74dea4df, 0xa731d216, 0x8aec9c6b, 0x66b6bfc0, 0x6881c492, 0x216a857c, 0x99836c9f, 0x2e221a33, 0xa96a3bd9, + 0x331f01ac, 0x67e5b880, 0x8ef7b03d, 0x76eaea6e, 0xb30514a0, 0x892a0151, 0x7370b018, 0x721576a6, 0x063d2b42, + 0x2d549b11, 0xe03356dd, 0xc3ea5de9, 0x5a42ddb3, 0x4993e05e, 0x17b72e49, 0x1aca6763, 0xc082c2a4, 0x7c8853b2, + 0xc79561f4, 0xc0015211, 0x1a190cf3, 0x2a0399d2, 0x251be6da, 0x37dfaac1, 0x443a86f9, 0xa7c0c029, 0xd5537ce6, + 0x8cee0e6f, 0x52cc6dc7, 0xdbd29d86, 0x000ededd, 0x2db2aae4, 0x3b4c2497, 0xb8308afc, 0x16b1c690, 0x534ecd17, + 0x1e7f8561, 0xbbfd055d, 0x4734efe2, 0xeafa9d6b, 0xf2f7ec75, 0xb64520f1, 0x2429dd0d, 0x49c214fe, 0x2303210b, + 0x5098ba27, 0x057874b4, 0x82bebb62, 0x3b28ae43, 0x0a2df6ec, 0xaa01b6ce, 0x554287be, 0xa0b5f378, 0x21230a90, + 0x67fc58a3, 0xb0df8d19, 0xff087d5e, 0xc8bb467b, 0x4961c7dd, 0x7198a5af, 0xa7d27bc8, 0xfcb145b3, 0x19446353, + 0x29d80b66, 0xb48531f3, 0x68650958, 0xa3152d68, 0x84642214, 0xc42d2d46, 0x3a3bdf89, 0xaca19618, 0x862583d8, + 0x4ea14ee2, 0x1e4b7ba0, 0xf8d3e8e4, 0xa1f7ee33, 0x07752f8a, 0x97e23052, 0x3f9e0dfc, 0xd572677e, 0x308b4c9a, + 0xd6ff638e, 0x84024e35, 0x982ee869, 0xa8ac9647, 0xf2704dc7, 0xfae8d200, 0x708be1d0, 0x7a65103a, 0x2acb9722, + 0x77ccbd44, 0xbe8f3348, 0xbd42c37f, 0xf7d631c4, 0xcb75ae02, 0x25f0f5f2, 0xd4753962, 0xe658613d, 0x8689b1ce, + 0xf659e3af, 0xd74ebd06, 0xf561d791, 0xd4eeccf3, 0x702d2060, 0x7484e142, 0xe0df15ca, 0xeef9d645, 0xe71ab655, + 0xc5cbff55, 0x179c2007, 0xbdc585cc, 0x19d16e9c, 0xda6be0e6, 0xd1d1be63, 0xdbd0f4c1, 0xae693833, 0xd6d2eda3, + 0x6b2f1e46, 0xd2026ca9, 0x1b8e0a4a, 0x620aac3d, 0xa16b6a48, 0x800aa46d, 0x881a7230, 0x965b55ae, 0x56691035, + 0x41df553a, 0x65dd3846, 0xcb1120f0, 0x0e8a5c6a, 0x410b0893, 0x1749bde9, 0xd8042763, 0x5945a382, 0x3df46701, + 0x806d27bf, 0xbf73bc99, 0x0edf9585, 0xecafd0c2, 0x563dadeb, 0xa2b7d75e, 0xe6547b1d, 0x6e1b5071, 0x1035cd9b, + 0xfb66de17, 0x7acc72e5, 0xabfc7868, 0x8af568e3, 0xd61d7371, 0x33386d97, 0x6a96820a, 0x6f382fe0, 0x25ba4527, + 0x736b1777, 0xb92f3ae0, 0xfed4597d, 0xe1fef2fd, 0xba9b1a08, 0x545e49eb, 0x5a703bbe, 0x6bb4e2da, 0x0454e61f, + 0xc75e27d3, 0x033994fe, 0x8d83d9d5, 0x9cb216a1, 0x1c598e1d, 0x33532717, 0xefff56ef, 0xa81425f8, 0x0fc12414, + 0x4fd1b028, 0x5aa5bf87, 0xf2d34596, 0xb55750db, 0x63dbd335, 0xc04af3d8, 0x3468bfc0, 0x1b39f877, 0x8c8a959f, + 0x263a154b, 0x647bd134, 0x2e40c0e8, 0xcfa0e1dc, 0x06cc9b69, 0xf49cfc83, 0x42ddd76b, 0x2bb83bec, 0x977866c1, + 0xc08fec95, 0x8e294559, 0x537cfa62, 0xf0002aba, 0x30785f8b, 0xcf6fc0ef, 0xbd18e38b, 0x23b85011, 0xefdb7ac5, + 0xa0f168af, 0x9c791519, 0x1e49a4d5, 0x4e60a826, 0x69bed5b3, 0xa9d6ead0, 0x2e643a28, 0x0be3afcd, 0x4e0c7968, + 0x0ac8303f, 0x10b7faf3, 0xd217821a, 0x3e7155e7, 0x57a8c999, 0xf9da0983, 0xd0ca732a, 0xf374bea5, 0xbb66c2bb, + 0x7467b956, 0x722afabf, 0x5d1ad393, 0x50df9239, 0xeb46fb88, 0xd2cdefb7, 0xe3ec3aba, 0xc5fc3921, 0x1cb0ca01, + 0xfb8d5190, 0x3566abf4, 0x8fea9618, 0x0050e9fe, 0x110ccd87, 0x984deb58, 0xdc2c0e16, 0x3791b431, 0x2c837e07, + 0x5e31f895, 0x2219bf27, 0xc7ccee6a, 0x7d26ef6c, 0x6f628d2f, 0xe2783e78, 0xa657f2c7, 0x99694f0b, 0x9a148663, + 0xa8510853, 0xcd99579a, 0x887464f7, 0x55822e07, 0x85c06437, 0x0eda1943, 0xb6118945, 0x44648cf8, 0x47c772f6, + 0xcabb7874, 0xec0c2a75, 0x78a1eaf6, 0x53a7f1a6, 0xc1e7b0ed, 0x6693d623, 0x6fbfd073, 0xf543dfe6, 0x37e8547a, + 0x75161666, 0x4f99a738, 0x63702e64, 0xecb01ab5, 0x4bb8fc4a, 0x81256cfd, 0xf6c9cd64, 0xa69f0860, 0x5379c682, + 0xf943f776, 0x09ce16a6, 0x5875b360, 0xd30ba3a4, 0x533acaf2, 0xfd2fd657, 0x47a22075, 0x811d191a, 0x301c8b9d, + 0x0346e27b, 0x6d189f7b, 0x714c0d25, 0x6de6838f, 0x1b84fc4c, 0x6132300a, 0xfca3140f, 0x0e57b5a0, 0x5688e2b9, + 0x8fd6d4b1, 0x08e44cd6, 0x30d198fe, 0xda88e5aa, 0x33aa74a1, 0xb604c4df, 0x885b5fe9, 0xcd1183b8, 0x24dd5e75, + 0x315d17d7, 0xb46f99ee, 0xf2b5d28b, 0xbead6eb8, 0xa6464be5, 0x9d41a821, 0xab41536f, 0xa9e907fc, 0x07f15025, + 0x87cfd2dd, 0xf7081a26, 0x75ca74b4, 0x8954de3f, 0x0f2b2c43, 0x9e287098, 0x950f1644, 0x95066801, 0xa47cc52f, + 0xb92bc41a, 0x921538c9, 0x9fe6d42b, 0x01854edd, 0x5651f0ff, 0x4def05dd, 0xaa611360, 0x104a826e, 0x72f472f5, + 0x19adcc22, 0xaf7c2aeb, 0xed3d9eca, 0x4d7e8aef, 0x921095e7, 0x81a8f608, 0x2a649b72, 0xcd87baa7, 0x2618daef, + 0xac9227a2, 0x684e73f2, 0x37c376f7, 0x01eed937, 0x5b6764c6, 0xab1d61da, 0x84544181, 0x2e36bdcb, 0xc845b676, + 0x90232af9, 0x24572e8f, 0x8e53af38, 0x0e55f207, 0x3bf857ff, 0x856aa55b, 0x80c8c659, 0xe84bc67a, 0x5cc0ec33, + 0x7a73d108, 0x40fe9df2, 0xb95de279, 0x2daa86fd, 0x11c23bee, 0xb354be97, 0xe12952cd, 0xafaa8cbc, 0xe23983c2, + 0x2bac5a84, 0x7f0408a3, 0xec3af87e, 0x1d9f27ad, 0xba6711c3, 0x9ab5f7e7, 0xd3a03a66, 0xf58cf863, 0xad21adf2, + 0xf66ccb50, 0x3e624f69, 0xd11d0e67, 0xc6ae5345, 0x4ba90965, 0xd23ff666, 0x4d6d8ffa, 0x6b99d26a, 0x57e63ac1, + 0xea025cce, 0xb8ac455c, 0x30a66d00, 0x0b52e23d, 0xba5bda4e, 0xd3456b2c, 0x89657ff5, 0xc1b667cb, 0xbbfb5196, + 0x5f0bee15, 0xdb9bdb69, 0x68d07f54, 0xd6a591b4, 0x52d7cc2c, 0x38dd6789, 0x346c1c02, 0x9550b3b9, 0x541056a2, + 0x0a179f83, 0x344dee20, 0x4d721add, 0xcbf7d89c, 0x7b3e6d49, 0xc593095c, 0x27d28108, 0x006e0e39, 0x7f16879b, + 0x544194a9, 0x3dcdf336, 0xf342540b, 0xf2e18092, 0xcd5c6a3d, 0xc082b280, 0x0cd77c22, 0x91c71ee7, 0x06b6bed3, + 0x7eedd978, 0xdac3ced4, 0x9112f5a0, 0xd498196a, 0x8c487096, 0x0773a71d, 0xbe129061, 0x2dddd07f, 0x543491c6, + 0x2185bf29, 0x107f7a48, 0xd0b25954, 0xdc26ff41, 0x21c313d3, 0x7ffa0f88, 0x1ea545bb, 0x64dfdec6, 0x4773f908, + 0x165e5862, 0xfb5dc133, 0xd8f8d23f, 0x3711208f, 0xad97679e, 0x8f42bdd2, 0x80353dce, 0xac7ebbc5, 0x03363d8c, + 0x99d28b58, 0x74377bcc, 0x2ec4805c, 0x9a3530c1, 0xadd14510, 0xf4a56815, 0xc624a25b, 0xebb27660, 0x107d260b, + 0x327c8563, 0x91fb4a5e, 0x1dd802b9, 0x9dd477e6, 0x424294ad, 0x03e7a15c, 0x3f34c4b7, 0x85e8b061, 0x425615e6, + 0x479671ac, 0x1f7b17eb, 0xb6516ab6, 0x5ca43b5d, 0xe7801a1c, 0x07ce24dc, 0x0f5f3259, 0x25218bda, 0x48e45f7f, + 0x4337673b, 0x11d84740, 0x2bfa0883, 0x793a691b, 0xd2baae95, 0x0819b3a1, 0x9f2af31f, 0xc1a9822f, 0xac6e66db, + 0xade0f01f, 0x5ca772b4, 0x6000573c, 0xf4c0a4e6, 0x45edb30e, 0x5509e289, 0x69e935bb, 0x586ef358, 0x1b92ca61, + 0x4de13b3a, 0x79f4f1c0, 0x5643413d, 0xa5c413c8, 0x233512e6, 0x0de2ee22, 0x4c574be2, 0xb2e9effc, 0x4693f653, + 0x0897ba6d, 0x94c753de, 0x3efc960a, 0x4da165ad, 0x1d881265, 0x2b26b1db, 0x18d2f054, 0xbc7c7416, 0x47bb9da3, + 0xa6cfa4a4, 0x91ce8027, 0x15f013bf, 0xe87e1cb6, 0xa7760244, 0xd1cc5877, 0x28a429c3, 0x5ceaff0a, 0x52d9f107, + 0xc144219f, 0x76558c7f, 0x5e2c1d04, 0x3384a6f1, 0x039fa62f, 0x08795bf1, 0x73d1852f, 0x69e9e356, 0xaab3a4ff, + 0x9ed1719a, 0x290032ea, 0xdc8a2b75, 0xf3471d6b, 0x4f07bc0c, 0x89278cae, 0x3c80b747, 0xba877978, 0xf0da836f, + 0xa3e6b450, 0xbfb955f2, 0xa4488154, 0x6ab4b160, 0x17571de8, 0x36a9af01, 0x3d525b72, 0x4da2fe4b, 0x88a5eb4b, + 0x51839e2e, 0xb152a3a3, 0xc1a124fa, 0xba0e6ce6, 0xbd6383bc, 0xdaf689bd, 0x80c2f951, 0x49bc2b9b, 0x65c07832, + 0x97aa5ac4, 0x0c221334, 0x0e66a0f9, 0x4f6dbb37, 0x9c3c2e54, 0xc3c563e4, 0x364185ce, 0x4e9e0655, 0x828e2fb9, + 0xb953b424, 0x1cb9d975, 0xd46214f2, 0x8c8a104f, 0x89ef2bca, 0x21a6987e, 0x4b69a4e2, 0xe665cf08, 0x988fe4bb, + 0x35c5b9a2, 0x66153a82, 0x141e4718, 0x5d38b9e4, 0x52769e48, 0x8794dbe1, 0x3092d121, 0x173bcf04, 0xf19bc0a8, + 0xbf0477ae, 0xcca5b633, 0xfad2580d, 0x9d3ec513, 0xc8de23c5, 0x1a06e894, 0xc55c9b4e, 0x8b8a8df6, 0x90585cb2, + 0xad21dc41, 0x2434e72d, 0xae6c249b, 0x3cd970fd, 0x03b5f048, 0x18dc1596, 0x74f89290, 0x3bfb459b, 0x52a44931, + 0x560f8e60, 0x4fc1b677, 0x44afebba, 0x044ae609, 0x5b9a59a4, 0x76252edb, 0x0ead6c90, 0x6da556ad, 0x452852c0, + 0x3882580e, 0xecd49306, 0x3eff0fb9, 0x80ab30da, 0xad12de57, 0xb7fb1135, 0x2ca9e7ac, 0x922eb009, 0x9a7933e7, + 0x822a45f0, 0xcb29538e, 0xe1769513, 0x90303e99, 0x0398b9c8, 0x3427d5e4, 0xe35d68eb, 0x10e99c55, 0x0aaa4375, + 0x4c9b0bc0, 0xa58d1d8d, 0x6dc6d684, 0xf7b372bd, 0x7d1616f0, 0xeecd1ee1, 0xab34ac12, 0x298625e7, 0x699407f5, + 0xa7cb1d75, 0xc8590ff2, 0x79ddc936, 0x8aa7205c, 0xb935f801, 0xae917651, 0x4b2b9f57, 0x76568c6d, 0x7ac1ac68, + 0xc7e5e472, 0x8ec67268, 0xabdaaecd, 0xc78c1718, 0x1b4f71df, 0x857fbb6d, 0xdf6ab282, 0x5828c321, 0x5e15fe88, + 0x1bba04fb, 0xdf76b1ab, 0xfc6e5e4e, 0xa8cb086e, 0xada2672b, 0x04d7e4df, 0x191140ad, 0x2f0276c9, 0xb0b9cc59, + 0xf9133a99, 0xc9079cce, 0x4a7f1264, 0x6d2e314a, 0xee272307, 0x8bc2c327, 0x44e5c129, 0xf1d54d21, 0xbc8cab33, + 0x741f653c, 0xd493dde9, 0x26864bcc, 0x0fb8feea, 0x05585e2c, 0xd1204280, 0xe2094f20, 0x9f10f965, 0xa9b74ecb, + 0x1310ca2d, 0xa2f46733, 0xad71dbc0, 0x7a01cbd2, 0x23f897e8, 0x350dcacd, 0xd9409fbe, 0xba2cac02, 0x0f2fb628, + 0x97854fd1, 0xabbb1c8b, 0x60908b6d, 0xe35c0c9a, 0xc0289b93, 0xa5000492, 0x2035ff19, 0x9ee8c74f, 0x4ed8e1bc, + 0x4df3a399, 0x8a96dba0, 0x41e79330, 0x8471a6e6, 0xf8a3e073, 0x4d6fbc4e, 0xb6fbad51, 0xbc1f37c9, 0x2a506aef, + 0x5909813b, 0x2dd25f47, 0x3683a371, 0x2bdba3d4, 0xaa625cf4, 0x0fbbc156, 0xdcd880b1, 0x5417bcf5, 0xf167c0da, + 0xf4434940, 0x7905fb2c, 0x148fabc2, 0x789d4002, 0xf0767b50, 0x7497ad3f, 0xfc249687, 0xcd90ab40, 0x955e7865, + 0x404899a5, 0x61d12a03, 0x90a27d50, 0x7c7b37a7, 0x7f697a03, 0x99635596, 0x116fbb6f, 0x19b23bf7, 0xd5fe5fdd, + 0x9396f9fc, 0xb40ece15, 0x95264f5e, 0x2bc78d6e, 0x2e79f1c3, 0x00eaf728, 0x12bfcc34, 0x89f0043f, 0xf72f10e7, + 0x0a6dca97, 0xbb353bd6, 0x718d98c5, 0x72d3d1da, 0x7b45b018, 0x96de983b, 0x82382112, 0x92712969, 0xa414392e, + 0xca0b0217, 0x3409119d, 0x2f982cd8, 0x0e5784c7, 0x654a5a15, 0x2450d2e2, 0xa9fac0b9, 0x55d09158, 0xb7f7dcfd, + 0xbea79e67, 0x22a72ae9, 0xbba07b31, 0x21932c83, 0x7f2350e0, 0x803248a5, 0xd203e394, 0xc6d558fa, 0x5bed534c, + 0xdc1bd078, 0x0addbbf0, 0x6eb5ef1d, 0x33e7ab02, 0xaba7625b, 0xf4dd6f6d, 0xcfbf81b4, 0x17557fb7, 0x52fbf770, + 0x4d47aa46, 0x1116b43c, 0x5bc21f95, 0x199d3508, 0xcfd15e49, 0xabfa0968, 0x9203e34c, 0x27f5ce59, 0xa035d861, + 0xabbce763, 0x2b4ed5df, 0x1ba6a730, 0x4669d8d3, 0xff4d930a, 0x428482c9, 0x2aeffc15, 0x866b4eb8, 0xecb3bc7a, + 0x3814fa90, 0x6798c45d, 0xd40e4505, 0x50579493, 0x75a912fc, 0x01b41172, 0x9b541584, 0x7332fa4c, 0x26a54e6d, + 0xca0795cc, 0xc8f73d26, 0xfaa3673e, 0x9947bbf4, 0xa42b03e6, 0x624d506f, 0xfe88b42f, 0x03a6f6d9, 0xafd70047, + 0xe00e0514, 0x66232f47, 0x60be26e0, 0x1814ea2f, 0x75b2c430, 0xa2c05583, 0x5a45fdb1, 0x8b49e328, 0xc1908abc, + 0xdae6eef1, 0xa5f1a5a6, 0xbd117422, 0x38f6d931, 0xdab0122d, 0xd0784253, 0xea555dc9, 0x9be1c0a5, 0x70e1297a, + 0x851d35d8, 0xae972a48, 0xd3744583, 0x8ba8cb23, 0x231eadf6, 0x4c0bff65, 0x25fa7c5e, 0xf01a46ae, 0x82384c0c, + 0xfc580451, 0xe34534d8, 0xcbf2662c, 0x564c5c00, 0xf53b565d, 0x9185707b, 0x100ae12a, 0x4e218b3b, 0x3df1f13d, + 0x6f69e136, 0x01f498f3, 0x2208f004, 0x76200a1e, 0x189ca385, 0x3b13d374, 0x9a405e77, 0x05cb32b3, 0x450e90bf, + 0xb6c49013, 0x8a5dfb67, 0xf2041681, 0xa741c3f3, 0xdc4373f0, 0x568398e0, 0x76651437, 0xa3b2d7ea, 0x82765b27, + 0xab865904, 0x0c5cdc9e, 0xa98a0c8e, 0x62b3eb16, 0xe9928913, 0xb931732b, 0x4db69828, 0x0563e15f, 0x22a17028, + 0x8676e632, 0x5251b1c1, 0x678c2e5a, 0x87767080, 0xa6660441, 0x1b67a890, 0x73916ee1, 0x7a7b3da0, 0x7e6a9196, + 0x0c2c10c8, 0x7dcadff9, 0x6a14f936, 0xcfdbdc7a, 0x793e5bf6, 0x35d53aff, 0xf9a12bd3, 0x7054940e, 0x9bd1da5a, + 0x62e08f19, 0x4982af77, 0x3d21913f, 0x7240e3b0, 0x886310fc, 0xd01de2c4, 0x13addad6, 0xaaa7e02d, 0xadbb7f28, + 0x87f216a1, 0x9613f807, 0x18f2d9dd, 0xca9836f1, 0xf42d7b56, 0x5118da38, 0x4445a08e, 0x9df79eda, 0xf8ef1667, + 0x7b511204, 0xe58d3ce7, 0xb8a7a7ca, 0x51754dbd, 0x0f2cf0ec, 0x39fe1004, 0x76634531, 0x88401563, 0x9f636d3c, + 0xff873469, 0xf42e9183, 0x951bf7d5, 0x4e007bee, 0x4c51be4a, 0xfdafbe1e, 0x0d88c1e4, 0x84e64ab7, 0xe5caa2f6, + 0xc8d13126, 0xb296e4ab, 0x8840f867, 0x745203ae, 0x05ed8221, 0x94dcde97, 0x54b61e45, 0x599a3082, 0x28b4372d, + 0x0efdd433, 0xf22bb1d9, 0x93da934e, 0x1410fce9, 0xfbc1fd10, 0x0c790161, 0x5f1cefc9, 0x37eb4e59, 0x99d6d026, + 0x6eeadd9f, 0x4d1c5f96, 0x71bcc7be, 0x0d41d428, 0x96fa3258, 0xf698cd12, 0x2125533a, 0x80b738d2, 0xc679e70f, + 0x7624c0e3, 0xd987e43c, 0x5073d6b4, 0xee9a7a46, 0x49bb64c6, 0x7231bae1, 0x2bf9962c, 0x8dc786f8, 0xab7c9143, + 0x1b2820e5, 0xaad273a9, 0xe006b435, 0x6d454ccd, 0xaa61571d, 0xec6cab2e, 0x4e9f45c7, 0x9eb02e1f, 0xd9004d9e, + 0xd1c34864, 0xb2024eca, 0x21f700a9, 0xf9d2e30b, 0xd6360e38, 0xd1e5c4a7, 0x4b6eaf20, 0xd081bf54, 0x3656db54, + 0xf7503d27, 0x0c903de8, 0xb749ee6a, 0x08a547ab, 0xbcc32f28, 0x2eefa9b4, 0xc5c9cb99, 0xb32da4cd, 0xc7be1642, + 0x95837840, 0x767ebbe4, 0x21165b5d, 0xbef64801, 0xcdaa21e4, 0x9c9dec71, 0x05c9d930, 0x65a2d939, 0xb1ed90d4, + 0xb97feef3, 0x271b5559, 0x55b5c40e, 0x0d11b48e, 0xa72f2815, 0x9b6d017c, 0xf280c32f, 0xba0d9898, 0xe9d8022f, + 0x43f4e73a, 0xedca55c4, 0xc69cf774, 0x0624f2a5, 0xcba7a63a, 0x3404d214, 0x7d0187c2, 0x1870cf67, 0x9aa679dd, + 0x6d956e2c, 0xb7e36bc7, 0x144eab9d, 0x202ea243, 0x42f6717b, 0x2948c80c, 0x9d5278b5, 0x7177de09, 0xf24ccc88, + 0x512c3128, 0xd56bc25b, 0x9d5b139f, 0x96412dfa, 0x7c3a548b, 0x0be59964, 0x8e5d2f5f, 0xe78f5ed3, 0xedcf39e7, + 0x0c1f956d, 0x6a62fee3, 0x953ffee3, 0xaf422528, 0x9c4fa2f7, 0xf8bbe08b, 0xf006e0e5, 0x04e77351, 0xfeebdff1, + 0xe9470d41, 0x6f8861d9, 0x460c3092, 0xe1441f1f, 0xbe08e24f, 0x55806f6c, 0xb0de30c9, 0xa1ffbfc0, 0xd0c03b45, + 0x530bb6ba, 0xe80ccdc8, 0xd2aa43a9, 0x399ccf1a, 0xd52f03dd, 0x12c312ac, 0xe1895b45, 0xacc5b563, 0x35cb309a, + 0x136a35ea, 0x6114d831, 0x23c68bad, 0x3fd9d146, 0x817fc632, 0xb4695ddf, 0xb759d55a, 0xd4ebc668, 0x39289299, + 0xa824ba30, 0xf25c44bc, 0x94a85432, 0x0fa385f5, 0xbd55b6f7, 0x00464a78, 0x2d242656, 0x2154b7ee, 0x37d07b20, + 0xee7ed9fe, 0x47bd5dc9, 0xee82078e, 0x1edfd17b, 0x91c12bbd, 0x2dc6c8d1, 0x60736b89, 0xe7f356b6, 0x4c14d59e, + 0x2de896c8, 0x442df9ed, 0x50de368d, 0x76893cbe, 0x030b90cf, 0x24520b00, 0xc9cca643, 0xee964b87, 0x8f43dfc2, + 0xb4ed12f0, 0x4f2be0cf, 0x3beff6f1, 0x94d85c16, 0x8e6c4655, 0x2d7afcaf, 0x4d22c689, 0x1942a0e5, 0xc0e4050c, + 0x59c44938, 0x0b907fd4, 0x11d3ac61, 0xd0f6ccde, 0x82ba754f, 0xd54d0dff, 0x5801d89d, 0xe89ccdea, 0x29eb7598, + 0x8f87756a, 0x3ddf3d87, 0xbaa56719, 0x171eb256, 0x9473aeec, 0xb383aade, 0x73094579, 0xc3eabe00, 0x28db23a0, + 0xb6c76fc2, 0x52223a8a, 0xc00fc684, 0xea756f5f, 0x76b9f72f, 0x76fdc0d7, 0xa678f687, 0x42b994db, 0xdfe5c12b, + 0xdca9179c, 0xa5eb9c72, 0xfcfb107a, 0xdc63b12b, 0x6c84cee0, 0x561a6c91, 0x3bc0e348, 0x26782bac, 0x5b1fe780, + 0xd1118d70, 0xa4b1ef43, 0x469daff4, 0x4aaf1a27, 0xdb1df30e, 0x03a54fa9, 0x053cd842, 0xd07d85a3, 0xbaef32d4, + 0xe47c1401, 0x60635628, 0x05f0bc94, 0xad6dc45d, 0xb17d9b70, 0x22ab45dd, 0x53368cc7, 0x50435671, 0xc9b5a1fd, + 0x26c55cda, 0x67dc59c3, 0x5b11cd30, 0x2d0ff1b0, 0x03d63476, 0x1a9a3b5b, 0x1e150489, 0x665eda48, 0xf3d5bdd6, + 0x75e10f65, 0xb860d3b2, 0x8002ab76, 0xccd49769, 0x34a6ceeb, 0x7836f802, 0xad7806ce, 0x74b1ee62, 0x4f5c824c, + 0x8c8f42f6, 0x14b991c7, 0x0846232b, 0xe99228d0, 0x386e4ea7, 0x4f5cfe1f, 0x87bf4cae, 0x285a10d3, 0xadf7ac24, + 0xc0c15048, 0xdf82f737, 0x29b1488c, 0x75db7d11, 0x2bb1fc4f, 0xbaf0629c, 0x2edda835, 0x2f93afe4, 0x5dd12a62, + 0xecc31d1a, 0x40470c0d, 0x433a2afd, 0x2f924de2, 0x596c56af, 0xe95dd3c0, 0xefdf2f00, 0xafd0ebde, 0xf0d1d584, + 0x6def112a, 0x389c00ea, 0xd6ba3ec8, 0x279b2636, 0xb0094dec, 0xbda389d1, 0xb31698c2, 0x37d9c2c5, 0x22c64bb4, + 0x9b2de045, 0x0d2b2b89, 0xefcaecb4, 0xbe35f9eb, 0xc1640d22, 0x7b84f6e7, 0xf3fe0246, 0xb80e6c00, 0xbd470ac0, + 0x324a5be9, 0x4235545e, 0xa36ec23d, 0xa5e6ec81, 0xf572792c, 0xad3f1af0, 0x99c5e2d8, 0x1a12a6b9, 0x793e7755, + 0x29679634, 0x66a497c9, 0xb792559b, 0xf42befaa, 0xf6afc39e, 0x22235268, 0xcd81c0aa, 0x92391976, 0x31b995a7, + 0x3fa52e1a, 0x081adaa9, 0xc8844916, 0xcccf37ae, 0x279aa9d9, 0xc4f1deff, 0x73864b01, 0xae195345, 0x0d7e266d, + 0xafb8e145, 0x33c9c7af, 0x72a5c40d, 0xfe1cd8a0, 0x617e5212, 0xbec69d43, 0xa953cca9, 0x6ada6fbf, 0xaf299899, + 0x2d2a74ba, 0x2e7e5080, 0xf598b6b0, 0x32e607dd, 0xa3290feb, 0x926da68e, 0xf0cbde1b, 0xfd92cc00, 0x90e985c9, + 0x273af6a2, 0x5fd4354b, 0xdc5a2ad7, 0x2be2b49d, 0x44620291, 0xd5280e03, 0xb5b2570c, 0x4e3a571f, 0xf634813d, + 0x589df758, 0x67345804, 0x506edfd8, 0x8ffb4dee, 0x9c30c4ab, 0x79909bc1, 0xbfcf4547, 0xc072cb3a, 0x21cd75fb, + 0xe9857458, 0x7834078d, 0x6ff07fca, 0x4d7d9d14, 0x32cfd362, 0xafed1e78, 0x53bf4134, 0x22b77f58, 0x82acc997, + 0x41b27a5e, 0x898f850e, 0xf9a9d6d6, 0x08ad9544, 0x51eda395, 0x3ee14417, 0x367dc71a, 0x60f05c54, 0x32d88f6c, + 0xcb29237e, 0xfdb94027, 0x8e1e472c, 0xd68f9a51, 0x7e83bf4c, 0x9b6accf7, 0xae092a1c, 0x39894b92, 0x509915ab, + 0xade615e7, 0x58863363, 0x9b7cb9b0, 0xf89d89ca, 0x41495882, 0xa15e5d87, 0xef729382, 0x4ea9a368, 0xbfa37976, + 0x8933f0a3, 0xb94e51c3, 0x4a87f2f2, 0x2185e853, 0xb40a4097, 0x8daf98c8, 0x2f653ffb, 0x48807535, 0xb322f977, + 0x42ba61f2, 0x52436754, 0x4e866f52, 0xbd875cf0, 0xd440f634, 0x7d36cf8b, 0x4fe3f812, 0x29aaa307, 0x4643411a, + 0x71780d4a, 0xfdace4f3, 0xf2502f04, 0x5e78c1f6, 0x60ef0c5b, 0x98c32fe6, 0xb4b62d0b, 0x990c288b, 0xe92ae9fa, + 0x4f8013d4, 0x6072698d, 0x2f8cfce0, 0xce7eac6d, 0x35ed4578, 0x2918e948, 0xc85b8065, 0xb25c9a12, 0xf2b5b4ff, + 0x3f186023, 0xed781413, 0x8041b682, 0x8bb83ec1, 0xeaac1937, 0x49f55d35, 0x8427c28a, 0xbb1bd172, 0x179723a1, + 0x6829dfb8, 0x025de1c1, 0x22c87844, 0xd5b3dd0d, 0xd172e876, 0x7f280498, 0x83585670, 0x0b351009, 0xcefb7b8b, + 0x56d9acd3, 0xaaece676, 0x0b317dd4, 0xbf4fb893, 0xecb786cc, 0x9abd448f, 0xabe72594, 0x7d33cabe, 0x6014a925, + 0x088b272b, 0x26b14e8a, 0xb0d06eef, 0xb6b3804c, 0x0d8eb93e, 0x00a67c59, 0xc2a79f42, 0xdc6fff09, 0x4ebf5079, + 0x58705e33, 0x7362f38b, 0xe71e201b, 0xe7ee7fd3, 0x428a4fc9, 0xc0b3e8ef, 0x07f9bf68, 0xd858f9bc, 0xcd15d4fd, + 0x47da63b3, 0xf8954a53, 0xc297aea1, 0x8305fff6, 0x9a912e59, 0x71642b38, 0xd56b5e66, 0xdc31359f, 0x69351395, + 0xb016b753, 0x3efbb839, 0x8c050141, 0x2d88457d, 0x9d97669e, 0xc5d5afc2, 0x3fbe2b03, 0xc31b3083, 0xddfc33f1, + 0x43dbcbc6, 0xee739970, 0x76f9fccf, 0xc2480844, 0x21b6661e, 0x92050547, 0xad3e05cb, 0x1308465e, 0xad50474a, + 0xc0fc5482, 0x2a7c1f81, 0xc729272e, 0x30832247, 0xa39f7e47, 0xd7acdd35, 0x8b138d91, 0x036d0d9b, 0x5dc9e683, + 0x40eb9e28, 0x253b63a3, 0xe7d735bd, 0x0a43f5e3, 0xb49cf03e, 0xfe7ed572, 0xbc6cf67b, 0x0dc3f49a, 0xf5cc6118, + 0x2f04e1bb, 0x08c8c2dc, 0xad46b802, 0xcc7e3e2d, 0xb3676ee3, 0x7809e882, 0xe1542c0f, 0xc314dd03, 0x99be59e1, + 0x5aeab207, 0x061eab1e, 0x29c2741f, 0x29db99a7, 0x080b9f90, 0x20136706, 0xf875813e, 0x94b3b890, 0xfeddee4c, + 0xcaef7074, 0x58f6a38a, 0x25faa811, 0x9473d8a9, 0x90669897, 0xcc8dc74f, 0xe3ee93cb, 0x7bff2850, 0x2fa55aff, + 0x07df6819, 0xe930551d, 0xe221c6ba, 0x86308266, 0xdcab006d, 0x09ce13d0, 0x4681a49e, 0x76702760, 0x263f6719, + 0xfa99dbce, 0x1dfb47fd, 0x40937748, 0x8402c8df, 0x92fd6e4b, 0xb5d3598b, 0xbb790cf1, 0x28df6e3b, 0xfd811f6d, + 0xa703ad47, 0x1e33b6f6, 0xca3ab4bd, 0x2159a1c5, 0x72e14340, 0x59c24ecb, 0xf77aaa97, 0x40770757, 0x10812b01, + 0xb97c669e, 0xf8b6d958, 0x20074c1d, 0x9577068b, 0xe341ae5b, 0x9aa97d50, 0x5807b8b1, 0x9de0bf0d, 0x6218adcb, + 0x2849b0ff, 0xa26b8ccf, 0xc3685949, 0x758e861e, 0x7ae8c7cf, 0x7e752b86, 0x6e0dc3b7, 0x1f9a0999, 0x706397ec, + 0x21716fb5, 0xe67eda20, 0xd95667d6, 0xf609d150, 0x90d379d6, 0x10dc038f, 0xaa4164cf, 0xd3fb5dde, 0xff7bbb8b, + 0xc233b191, 0x4393b947, 0xe382d250, 0x9d031316, 0x13f81ef7, 0x7f4d9205, 0xc736be42, 0x54a03c5c, 0x418916b7, + 0xe286a654, 0xe165662c, 0xea06003d, 0x6fc24e76, 0xf5ae0326, 0x42d0b769, 0x9ded0755, 0xc1ee71eb, 0x7e235119, + 0x4dee1df1, 0x42370c26, 0x98b9c2f9, 0x62352511, 0x3c5e529a, 0xeced6729, 0xd98dbcdb, 0xb6b85a20, 0xc5a10847, + 0x4e00b010, 0x27e12374, 0x268a13fe, 0x1d2ef8ff, 0x8e71594c, 0x06ceab07, 0x72acb6b0, 0x4e53fcf6, 0xf4c2e2de, + 0xfc6f93ef, 0xfe950f4a, 0xdaedf6fe, 0xc8e674bd, 0x3a42e3b4, 0xaa868af0, 0x8ce684d3, 0x480de71b, 0x011bd8af, + 0xb0325cc5, 0x7c08446a, 0x260745fe, 0x561d991d, 0x2b40183f, 0x1b1c8071, 0x8ed62039, 0x48011dec, 0x1da23b02, + 0x5074615a, 0x95861c31, 0xa250a958, 0xbc4bd88e, 0xf5f786b2, 0x0d04cddc, 0xdaeb3d2e, 0x331b767b, 0x6675abb4, + 0x7f46968b, 0x9d2576e8, 0xf7b42eba, 0xed50ce52, 0x4b56615a, 0x12931a41, 0x4947ed27, 0xe7da1fb0, 0x99bb4166, + 0x62db5a64, 0x15995bf6, 0x632cb8fa, 0x787e333a, 0xdc0100fc, 0x5dffab4a, 0x480c3e2c, 0x3dd19397, 0x045352dc, + 0x73c4b04d, 0x0404e155, 0x39f6944e, 0xe9026c89, 0x7a101fe0, 0x03e09c37, 0x038d4214, 0xe4f565d5, 0x57e2cf6c, + 0xea1dd07e, 0x7fc90cae, 0xab684617, 0x0ea1cafb, 0x53edbb52, 0x2dc18e4a, 0xf23e4be9, 0x668c4e57, 0x3351c631, + 0x194ab772, 0x5462a368, 0x87825ccd, 0xd76db739, 0xdc90e628, 0x1aa90abe, 0x9e94fdfa, 0x90c90f41, 0x01f6e25b, + 0x657098cd, 0x7a5fe45c, 0xfc0c6672, 0x00c50562, 0x2b15f0f0, 0xedfd984c, 0x5a942ea9, 0xa0d9c823, 0x9684735f, + 0x5d9874ee, 0x3489bb12, 0xe2699b6c, 0xfd08479e, 0x822e0d87, 0x4841e8ea, 0xeb58b055, 0x2213ec96, 0xee465c5c, + 0xbe46c376, 0xc1febad5, 0x08979a1e, 0x17c2dadf, 0x893eb749, 0x863913c5, 0xce37d49e, 0x3efabd80, 0xe0a23dca, + 0x18f48dad, 0xff6e3a43, 0x750fc0a3, 0x0c08095a, 0xa99d47d2, 0x155c54e9, 0xb8bdddd8, 0xd8097576, 0xa815ef53, + 0xaa7aef32, 0x1e09fa70, 0x4fb1134d, 0x9322891a, 0x81e8cd13, 0x36c02287, 0x937439b1, 0x88993d3a, 0x6ceb07c2, + 0xeb6b8128, 0x44b68c42, 0x6378f6b1, 0x0647ae13, 0x9138ab95, 0x6491e8f7, 0x4300a722, 0x40c00540, 0xf866f04a, + 0x2923475e, 0xceea2870, 0x15a719ef, 0x768bde39, 0xec4a3292, 0xb90e0f5a, 0x70394a19, 0xd4450c94, 0x32081a6a, + 0x9cf558aa, 0x5c46c819, 0x8b3874a5, 0x63b5b924, 0x513e5554, 0x009c42a7, 0x7864b25b, 0x4571abd1, 0x6f86fb96, + 0xdcdba0e0, 0x7a534547, 0xaf9c3452, 0x0c9ce00c, 0xf827fd97, 0x3737580f, 0xe538498e, 0x03d7f5b2, 0x3e52a2d6, + 0xa3d527b4, 0x6543e4ad, 0x7c437acc, 0xd0c35f2a, 0x7ac1b87e, 0x18562a3b, 0x93633f63, 0xd770665d, 0x241a7739, + 0x73e68199, 0x21da56f3, 0xf08b4e64, 0xb9af4231, 0xd3174de7, 0x62cd3066, 0xf4acf9b2, 0x4da6a20d, 0x036d1873, + 0xcb429f5a, 0x594d1ebe, 0xb85b03f8, 0x9ebeafdd, 0x85c38e17, 0x643240d8, 0xd0235e66, 0xce00ea36, 0xbb77c19b, + 0x70c37bea, 0xa64d2f53, 0x7a6559a6, 0xf1357103, 0xe4e4ed77, 0x5c72f362, 0x986c390a, 0x4151d8b3, 0xf27e868a, + 0xe3327063, 0x075ad252, 0xb8a6be85, 0x2feebdd2, 0x063d7efb, 0x3f8b0dbb, 0x4d34f271, 0xb924ea84, 0x00c9a8c4, + 0xb3dd2f89, 0x6ff09007, 0xfc615c06, 0x7bf8d2e3, 0xaa93dd60, 0xbfe6dca9, 0xd841dfd9, 0x0c7faa33, 0x8da30eff, + 0x3d7c4424, 0x374bbdd4, 0x19687136, 0x916bb16a, 0x04483488, 0x452c9d03, 0x85b1eba9, 0x53e8525e, 0x181466fb, + 0x1eeeac4a, 0x248ae2fe, 0x8c799c07, 0x9cfbc833, 0xb77cad3f, 0xbda89180, 0x6738d329, 0xd52c74b0, 0x6a65f2ad, + 0x57fe2ae6, 0x11677ceb, 0x181a597b, 0xdebfe1b1, 0xa630f748, 0x1d281bd2, 0xdda2ee57, 0x7e57200d, 0xffa29c22, + 0x18246156, 0x36c63dcb, 0x08a9e996, 0xdae62120, 0x7ef2baeb, 0x199da5ca, 0xe3aaee15, 0xb7907b76, 0xd4587b08, + 0x0fa631e8, 0x842c81e0, 0xc5a503c2, 0xcc78c92a, 0x4299c401, 0x24155ef1, 0x0d191a28, 0xe35a43ae, 0xc90cb44e, + 0x223ac495, 0x608b8517, 0xa1856ff3, 0x82a19ed0, 0xda446489, 0xa2222e8a, 0x11decab3, 0x19ea50e6, 0xe4a95679, + 0xaa2ddb51, 0x3a74e834, 0x1de3ced3, 0x97337331, 0xd1ebcdff, 0x6c358509, 0x05295975, 0xeff39443, 0xf23f6f2a, + 0x8d8fe2c4, 0xeaab0ba3, 0x2447ebc9, 0x5df50ae3, 0x17932b99, 0x51e85ec2, 0x1bfae724, 0xc8045378, 0xe4a735d1, + 0xade26140, 0x6d41c861, 0x8ec90cbf, 0x85de2ef4, 0xef68365f, 0xf9ef37a1, 0xdf953a89, 0x1e191ed3, 0xea2c832b, + 0xe00b0446, 0x39279774, 0x91d45616, 0xbb672cc8, 0xb8133b69, 0x0b6734b2, 0xb61c6452, 0x5a9f9c7a, 0xfb3e0663, + 0x7399d31e, 0x69e3b0f7, 0xf64ae4f1, 0x3785e565, 0x804183c0, 0x1f95bf00, 0x20de3f32, 0x48edb6bc, 0x70d13a6b, + 0xeb878b38, 0xce3991c1, 0x53423066, 0x7b7e39b6, 0xb709d636, 0x78b9dae5, 0x84118a39, 0x22adbbab, 0x45ddc600, + 0x624c28fa, 0x85d4bf37, 0xfdb89d40, 0xa007836f, 0xde331c96, 0x2b8bc0cb, 0x11c4c0d5, 0x70ea8f0f, 0xa2ca0460, + 0xcd08f491, 0x98d5f4e3, 0x2a6053bb, 0x673c8872, 0x9174ed25, 0xb755ef51, 0x4768e11d, 0x348e21e4, 0xc3174236, + 0xe594d121, 0x0ca1eb36, 0x95dc2861, 0x0a10182f, 0x66b870b7, 0xb1e1aac3, 0x9fe02463, 0xb3fb0fd3, 0xd7068614, + 0x8def4948, 0x1c5d41f0, 0xeb0a9007, 0xb37a8ff6, 0x0882791f, 0xbb113d1f, 0xb52c3a36, 0x5e9a07de, 0xd278b8b4, + 0xfe2e9b71, 0x2b36d314, 0x5a21e9bc, 0x441bd0e3, 0xacdd67c4, 0x3812b586, 0xfe39f255, 0x56ab0fbe, 0xad0c01e3, + 0x465fa865, 0xb5f3d7ff, 0xea2e6f57, 0x81dbb7c5, 0xb570ce6e, 0x83bf9af1, 0xecde24d5, 0xc68fe9be, 0xa46ec4b5, + 0x389e83e5, 0x45741d83, 0xcec09c71, 0x2764de58, 0x31ee5611, 0x4f71c699, 0x9880504e, 0xcb02ad6a, 0x85f43a0a, + 0x7b6b9329, 0x158ac3ec, 0x42916996, 0x1b6e5cae, 0xecd00109, 0x76c00002, 0x1509a78e, 0x0626e776, 0xac40c048, + 0x1740e6ad, 0xcffba3ad, 0x3566cc02, 0x0f6757a0, 0x242a9e41, 0x5442a288, 0x6d6a63e8, 0xb280df60, 0x62d3ea18, + 0xdae82b01, 0x69df2b6b, 0x5b1e447f, 0x16793bd2, 0xc0218834, 0x37082f13, 0x3450f5d3, 0x150bc1da, 0x740b8bc4, + 0xe46df6f0, 0x32feb0fe, 0x0902fd7a, 0x28228d85, 0x4b0d55e7, 0x6c7ae0f3, 0x3615a6a9, 0xba4a72a4, 0xb3cc603b, + 0x36c998cb, 0xa5f8c150, 0x1721dbd2, 0xc0c58122, 0x557ec307, 0xe36361e2, 0x5eb7a58d, 0x0447e55c, 0x8fb0896e, + 0xc8308f17, 0x412a1e67, 0xc636abaa, 0x53c4a86e, 0x7e5d2922, 0x9cd4aaa1, 0x9dcacc29, 0xa7fbeb4b, 0xb61ea976, + 0xe04be40a, 0xc400cb2c, 0x74b31e09, 0xb0b5e293, 0xd00577cf, 0x79d865bc, 0x52d47ed4, 0xa0429881, 0x909f0e3f, + 0x41bed55e, 0xe09fb4af, 0xcb935f6d, 0x1f7303d7, 0x9bdee2e7, 0xd4c852d2, 0xad256419, 0x93eef487, 0xae6eb56f, + 0x73a2ad63, 0xfc03d9cf, 0x0d0b5200, 0x561ff80a, 0x210ae6e5, 0x5d38fbe8, 0x24cc225d, 0xc383fce9, 0x0f10faf8, + 0x5382d690, 0xd12fd571, 0xd44fc73f, 0x9e84eb5e, 0x91139968, 0x891574c5, 0x4ce87751, 0xbf6095e5, 0x5a23ff34, + 0x335ab8a0, 0x6b8b5f31, 0xabba41f4, 0x933a7d8c, 0xa41da69c, 0xb323d08a, 0x3ab57512, 0xc4376fa8, 0x229d91d2, + 0x4dccc65d, 0xc490010f, 0x92321cb7, 0x28a0a422, 0xe4187494, 0x30530b2c, 0x4520e00f, 0x88f17dba, 0xb9c5a50b, + 0xb88c9854, 0xc1b396d5, 0xddd51cb7, 0x4268fd41, 0x5fc9aaf8, 0xffa78425, 0xd27f6b8c, 0xb5a8cca2, 0xa54db80e, + 0x3c1ab066, 0xf845e47e, 0xfd18e92b, 0x009aff53, 0x6468229d, 0xa234face, 0xc65f7d7b, 0x3e89b4e7, 0x40a6d2de, + 0x4277faeb, 0xfe506dc2, 0x19ff11d8, 0xfcea5ab7, 0x217b4020, 0x98335a9d, 0x76e5e273, 0x4663872d, 0x47e83fe3, + 0x06f20549, 0xdcef2f8d, 0x7ff4c4e3, 0xf9a69056, 0x8a8b7201, 0xa1ff9cea, 0x329e6079, 0x22d905bf, 0xfe3ccaf5, + 0x651d1de4, 0xf74374bb, 0x443e4ea3, 0x0f5ef8f8, 0x4a35fc0b, 0x6bfe40a0, 0x59647483, 0x35586de3, 0x08e7ee9b, + 0xdd4db86e, 0xcc5d5514, 0xf3cafde5, 0x13096ac8, 0x29761b22, 0xded3e1a5, 0x0d05313e, 0x07c071fd, 0x80b429c1, + 0x7f02c30c, 0x48b41824, 0xa79767d2, 0x1702bf76, 0x4d99bd6d, 0x71e5c6cb, 0x5620ca46, 0xc6338a44, 0xee0885ad, + 0x6156b63b, 0x4d33827d, 0x725320de, 0xf4b36d00, 0x38d86717, 0x302faf1b, 0x8e68402f, 0x7568d03f, 0x31047463, + 0xdbf4714f, 0xa6811ad8, 0x1368519a, 0x5525d70e, 0xb07e70d3, 0x34b371b9, 0x1c4a9a20, 0xa9d06b1e, 0x20ae7637, + 0x42098bb4, 0x264003c7, 0xb98be12a, 0x958645db, 0x44752ace, 0x654dceee, 0xc93739a6, 0x68264295, 0xfad23dbe, + 0x71704ed1, 0x53aec0fe, 0x67180bbf, 0xcaa5e2a4, 0x3be48d6e, 0xf08bf702, 0x1a9d9c16, 0xd09d7e7b, 0x147489ae, + 0xf1d14088, 0x7f12200f, 0x8007b014, 0x58522dcf, 0x6423f3cc, 0x8eaf53cd, 0x81b0c4bf, 0xb6cb245f, 0xaf2be0ca, + 0xedda37dc, 0x5b375cbb, 0x081fb03b, 0xede6ba31, 0xa1a8db48, 0xf4101fd0, 0x3b7eea9d, 0x4793fc4f, 0xe364c098, + 0xcc3c8ac9, 0xd19048a5, 0xf1f7914c, 0x5eb0cb29, 0xceeccb79, 0x6ab389f2, 0x6c5a8ea7, 0x4fd96d47, 0xa29f70a0, + 0x9a6a7820, 0x8cdd1c53, 0x1ce8833b, 0x49c13a57, 0x5aa974ed, 0xe6f9c5cc, 0xacf6bcfb, 0x9f75a3f6, 0x9ccf84de, + 0xe11bb14d, 0xbb85c0b0, 0x6a1c22b0, 0x255d5628, 0x11efb3ed, 0xf569b8e0, 0xfb0b0487, 0xe621348e, 0x1e2478b3, + 0x765f83ff, 0xabc2ae79, 0x4ce4d384, 0x3b3d5ad2, 0x61531cd4, 0x066028f0, 0xd2f6349a, 0xc73045a5, 0xa1955759, + 0xe7665cbc, 0xcf1741b3, 0xb730c690, 0xcb2c9651, 0x17a9b768, 0xe0eb35fe, 0x0bf6a2b0, 0xea0e1452, 0x986139e4, + 0xcac0c9c3, 0xabfdad11, 0xed04fe0c, 0x46d032b2, 0xd39254ce, 0x3592c0fe, 0x7189620e, 0x17710bcf, 0x216a7ffc, + 0x60e3426e, 0x01ec3882, 0x08b8bda4, 0x2ba7bded, 0x93e9ee6b, 0xff341344, 0x029b76ec, 0x6efcd542, 0xba38e3eb, + 0xff1440aa, 0xf7ab2ebf, 0xdc76dd87, 0x05bea970, 0x1ec655d1, 0x997fb970, 0xf21de78a, 0x61925326, 0x4d3c0ef7, + 0x974ae266, 0x060ed02a, 0x76aface8, 0x7f17462c, 0x3dd322dd, 0xa4f69643, 0x257f30cf, 0xbc24d591, 0xc385c967, + 0xf095ba22, 0x9fec556b, 0x102bd5ab, 0x84c92d8e, 0x3266de15, 0x798cafea, 0xdb9d7f36, 0xd0ad380c, 0x45af247e, + 0x4144bf6d, 0x7849bb6e, 0xae36ae6a, 0xd52eaac7, 0xab77993c, 0xeda4d832, 0x12688e21, 0x8738bd2e, 0xe1102e62, + 0xce080602, 0xfb86ff4d, 0x96f08c9b, 0x31f63cbd, 0xcd8ccf3d, 0x0946c1e6, 0x96986dfe, 0xe8f9db81, 0x79a47e51, + 0xdaf9eddf, 0x913ff7c8, 0xd0275256, 0xa1752d88, 0x78cddc02, 0x59505f61, 0xbf72aa13, 0x979903b2, 0xde973cda, + 0x235a8865, 0x4269b0ac, 0x8ec24162, 0xde8d6056, 0xbf4fe494, 0x7938af0b, 0xa9048c26, 0x0fb8550d, 0xcb091d38, + 0xe6a70be9, 0x43de682b, 0x73b699a2, 0x45d0f198, 0xa93d70b5, 0x18189536, 0x1e90eded, 0x8a95d6d3, 0xdc228ede, + 0xa27534d5, 0xd61357a2, 0x7ebeaef0, 0x63a72975, 0x1291af68, 0x72417e02, 0x13ecdbb8, 0x352f7c2b, 0x5592ebc0, + 0xf090102b, 0x73883ab3, 0x963b9c52, 0x8db00571, 0x20542e63, 0xbb649e0b, 0xcf36f8cd, 0xe049dfd0, 0x834721ad, + 0x27989445, 0x7eb5ec54, 0x0c0fcf84, 0x4270e97a, 0x64baa73a, 0xe06855d4, 0x7cb81fde, 0x45df6230, 0x03aa6163, + 0x255f3948, 0x76258237, 0x1c8661d6, 0x445fc9b7, 0x5eda8a25, 0xbecbe560, 0x2013aef3, 0x93d5a588, 0x714a4f0d, + 0x559a808f, 0xf41f9ae4, 0xf8706488, 0x76e0eecb, 0x23923079, 0xd616c83b, 0x5ae6cfab, 0xb5ce8380, 0xadcdc539, + 0x231a6630, 0xd1c83de0, 0x0a22b89e, 0x4a36dfa2, 0xcab417b8, 0x1b4ee309, 0x7834f6cb, 0x8d98c985, 0xdd9ee232, + 0xa85d4a75, 0xf5819a7e, 0x68f5c4a8, 0x3d4c9cb6, 0xdf4727c7, 0x63831be3, 0x4a28da1f, 0x32e506d0, 0x544ed650, + 0x638d16f2, 0x0e7bf481, 0xcd4bc57a, 0x32465967, 0xfdaa517c, 0x698a7cff, 0xb6b04139, 0x42e624ca, 0xf27477f7, + 0xcc155ffd, 0x5b6c9380, 0xb359d93f, 0xc777f4cc, 0xb497b5a9, 0x645b5aae, 0x7fb0d58f, 0x967e8cd8, 0xd533113e, + 0x26b3c563, 0x63439c2e, 0x7030b825, 0x653a1c73, 0xf80d50df, 0x25d7f098, 0x151446db, 0x85be9622, 0x9fe272f8, + 0x7095f0fb, 0x18ab2b7e, 0xa9f6b69f, 0xe7c6078b, 0x68301c1f, 0x2819c202, 0xdb140dd2, 0x919dc45d, 0xdd12f9ee, + 0x9c534182, 0xea24947b, 0xe217921e, 0xf58e9d99, 0x1465cb1a, 0x7ba51a3d, 0xd18b7a0b, 0x85093e63, 0x817879ae, + 0x6e8dbcc9, 0x69380ad7, 0xbefcb109, 0xb4c378b6, 0x8d58b22b, 0x75070f08, 0x70112868, 0x1507ff5e, 0x499cd3b9, + 0x8d4400bd, 0x28a81d3b, 0x64cc007b, 0x5f6b548b, 0x6b076b7a, 0x822cc308, 0x50ca16b1, 0x1152e167, 0x79f1395e, + 0x1f06d403, 0xb2bcd91f, 0x113c2d3a, 0xc4b27529, 0x6dbe80e0, 0x91d26342, 0x42d5af3e, 0xd36d810d, 0x1f2d968a, + 0x51463854, 0xe637fb9d, 0x3e5a1b46, 0x22412538, 0x298e5a51, 0xa7cfca96, 0x2814bdc6, 0xbd954aea, 0x691ff63d, + 0x57f79861, 0xbcd0f794, 0x018276ee, 0x8a9ce51d, 0x3a45cf8a, 0xd7e8a765, 0xb175c09b, 0xfdd6c94d, 0xabd02e4f, + 0x46a054b6, 0xe24e1897, 0xb0a3a854, 0xf0e727f2, 0x32dfa545, 0x1485e099, 0xc7f6757f, 0x95548740, 0x96586159, + 0x6b77de00, 0xbdd35139, 0xae21ff0a, 0x3d88caad, 0x084db8a3, 0x3036d6f9, 0xcd66fbc5, 0xa6c58a86, 0x8332fcd4, + 0x7adb380e, 0x8b7b5fed, 0x228cc65b, 0x8081ed78, 0xd6d2eede, 0xfed8c192, 0x66ca2c34, 0x5d5f6f7c, 0xa94cb27a, + 0xddb810e6, 0x0410b71a, 0xcb6e6762, 0x8b0a505a, 0xbb780103, 0xdd6662d1, 0x77cc5de4, 0x72ef96ca, 0x25ea4d0e, + 0xd6399a79, 0x35098103, 0xff503c03, 0xb5f45d9e, 0x33e3e19e, 0x44522e6f, 0xbb095a1d, 0x2a481db4, 0x5c011c85, + 0x96aea8cc, 0x446d2d96, 0x37d42131, 0x63c460e8, 0x2123f6fe, 0xfead976d, 0x324f5609, 0xb2d9e125, 0x86217a09, + 0xfcf710c4, 0x6039ed41, 0x91619780, 0x91579b59, 0x1f940d06, 0xc1f87ecd, 0xebf48404, 0xde8ddfff, 0x0d95ca84, + 0x278065d2, 0x25b66b6d, 0x8c798cdd, 0xbffb73f8, 0xddefa800, 0x0827a82f, 0x630327cf, 0x97aa3e69, 0xe78c5a17, + 0x6f5743ef, 0x359ce62c, 0xff6bb1ed, 0xd38887f8, 0x8367c605, 0xd1121ace, 0x5f530e2e, 0x346a7f9f, 0x1488aef9, + 0x962d8459, 0xd8f5c054, 0xd094e180, 0xa2bfab27, 0x28c8748a, 0x6c1c6b42, 0x13292086, 0xbe7ca7a9, 0x58beb053, + 0x57ca9fea, 0x08e16ebc, 0xc41fa648, 0xb7c9e0c5, 0xbe416572, 0xccbb2e69, 0xcaedeb8e, 0x1f5388b7, 0x128d3c32, + 0xc3df33e2, 0x00a8f280, 0xf173bb66, 0x75337f53, 0x9588b19f, 0xf1cf3f5d, 0xc2e35526, 0x73113c92, 0x43f5470a, + 0x025d137a, 0xc80e17ae, 0xd289a856, 0x600e0bbf, 0x2cabf290, 0x6e76dd3a, 0x97b098d8, 0xbfd0f8ad, 0x411bb9ef, + 0xa20e98ee, 0x573e62d4, 0x7d162730, 0xfef9ab08, 0x41a550d9, 0x0115d3ae, 0x9c11a0eb, 0x3d349e7e, 0xeea9e2a8, + 0x71ff21d2, 0xbca06fe5, 0xbc71baab, 0xf4ac0b08, 0xc722ba29, 0x47076aae, 0xf5b3ad9e, 0xd7894410, 0x058843ac, + 0x84c7db58, 0xdbb903f0, 0x80096861, 0xec7fa213, 0x7aabd9d3, 0xe5166888, 0xd2e547e5, 0xd347846e, 0x29691f54, + 0x6dc437ef, 0x70cb9adf, 0x8f4a91c2, 0xa04098d9, 0x4cce7581, 0x91945b09, 0xc483b1d2, 0x3f863e17, 0xf6359910, + 0xbdd4f138, 0x2abee666, 0x6ee83ef7, 0x77ae344a, 0x87eeea88, 0xd46f58d6, 0x3661aff5, 0xbbd418bd, 0xbbf6e463, + 0x05be0803, 0x119fa6c3, 0xd900bf9b, 0x043659cb, 0x01ad6548, 0xb8dceb6a, 0x8281012c, 0xa333eecb, 0xb7a9a3bd, + 0xe42f948e, 0x8e637b25, 0x1bec923f, 0x59d2ad38, 0x1c187bbf, 0x27496aa2, 0xd0f36ed1, 0x7acf1ee9, 0x99b2582b, + 0x6450dab1, 0x0a84bb3d, 0x2530c6db, 0x874c54b8, 0x35a06c71, 0x06dc6ae2, 0x7449ee53, 0xa1e6cdfd, 0x07fea2af, + 0xd2ac0a06, 0x3b68d3be, 0x9a5a4ff1, 0xc4c31832, 0x0994788e, 0xa1c62ca4, 0xebd42e25, 0x4d3714ec, 0x998c0925, + 0x168db644, 0x264da858, 0xada472f3, 0xb7d156af, 0xc049f2cd, 0x4ecadfa6, 0xfb1334a0, 0x39c49ca4, 0xe57cf85e, + 0x3da2b8d7, 0xb34a405e, 0x44b1e187, 0x60c94aac, 0x9579e8fa, 0x648cd962, 0x99d6e2d6, 0x9bd6d317, 0x4376b5b5, + 0xd5d2c9c1, 0xec0826c6, 0xfc81ef20, 0x51212fcb, 0x969907c6, 0x8363cdfe, 0x110cd074, 0x3583db02, 0xea9df483, + 0xe24033e7, 0xb24a47c9, 0x545332a7, 0x1e764bde, 0x8796eb7d, 0x81f52fca, 0xb8555e92, 0x98db9370, 0xb119341e, + 0x5617a84c, 0x72b388ea, 0x56aba37f, 0xc326aa36, 0x636277f8, 0x84bce05d, 0x2ffd1002, 0x98f572c2, 0xac96192e, + 0xe9a9bf0a, 0xf4c34a67, 0x8d5a5d11, 0xa4fd7e94, 0x53a1745b, 0x6fc31c50, 0x5d54657e, 0xde268db8, 0x2f58b015, + 0xf20d5acb, 0xd7e7d8e0, 0xb0d2c61c, 0x58322dd4, 0xfb0353bd, 0xd607565e, 0x4a75390c, 0x395f7c8a, 0xceb5e0a0, + 0x116ee352, 0x1107c2ea, 0x5f5c7ebc, 0x875768a0, 0x015318e4, 0x59b619e2, 0xfd499af2, 0xf0a43df2, 0xb4b91dac, + 0x21e4acd9, 0xbf678210, 0x00d9afb8, 0x595636f3, 0xa16dbe75, 0xa311102d, 0x2179ac63, 0xe825455d, 0xccde849d, + 0x58cc7914, 0x53b8f95b, 0x3eb61eb0, 0x9f153f11, 0xfe575172, 0x3b27eab0, 0xcfa9827b, 0xa28a4ab2, 0x930eeb58, + 0x0f0d3aac, 0x6cfeeba3, 0x38f4f873, 0x791063cb, 0xad98ef80, 0xfed0123c, 0xab46d105, 0x24d6b12d, 0x93a4d508, + 0x217d09f2, 0x35b4bdc9, 0x8d469791, 0x8e3c44ca, 0x02c25377, 0x29de22ad, 0xcb66d1cc, 0x767eabd4, 0x2689a1a4, + 0x45d8f2af, 0xf4a49116, 0xe27a067b, 0x5209f247, 0x8fcda651, 0xfefbfe39, 0xea8a9163, 0xcc777297, 0x83697c05, + 0xac8fd1d7, 0x18cc5079, 0xb9bed8b9, 0x26f00850, 0x35669593, 0xbdabf52c, 0x4dee055e, 0xf009c725, 0x639fdec3, + 0x53a75309, 0x9945f4da, 0x6017cfc6, 0xddb1bb5b, 0xad4af6c5, 0xc07cdd83, 0x1f3d046f, 0x55ba5813, 0x6001b80e, + 0x778d60b1, 0xd2d6f099, 0x57ee294e, 0xcdeaef84, 0x44a9b94e, 0x3cdaf670, 0x8cd14e4c, 0x77516cb3, 0x2075736f, + 0x89790719, 0x7b4e4700, 0x2001ba96, 0x3ce3226a, 0x248afdad, 0x48c9989f, 0x1af730b5, 0xd7574b8d, 0x827b6162, + 0xbfa90263, 0xaf63a3e7, 0xedb3c9b5, 0x4bd11e52, 0x5549bea2, 0x5cbd6c98, 0x2ea9d196, 0x8b3169c4, 0x24e4a0cc, + 0x322e971d, 0x388c1039, 0x3e043e73, 0xf198ab13, 0x6c657216, 0x7d06835a, 0x7782171d, 0x6264bd0b, 0x0b376dcd, + 0x7f1f45b3, 0x8224d045, 0x5f4868e5, 0x44800cb5, 0x5f48a75a, 0xb37d378b, 0x170eb9d5, 0x95eb5440, 0x4a297c6f, + 0x9af085df, 0x28d0da97, 0x98049b81, 0xc90b88da, 0x5aaacdf6, 0x8c9516fd, 0xe8863fd5, 0x10ff322a, 0x26464268, + 0x114280f3, 0x562338e2, 0x8a41052e, 0xf481f47f, 0x8ba1d0a7, 0x53e3409c, 0x501523b1, 0xf70aea44, 0x06bbbca0, + 0xffe41c63, 0x7fdaee29, 0x4894db6a, 0x5f3c57e1, 0xcd609c15, 0x24ce6dce, 0x41f55aaf, 0x9dac5202, 0x8556d879, + 0xcf27ee35, 0x2f7f22b0, 0xb50d41c2, 0x49a89596, 0x42c655e8, 0x4e13ca23, 0x28f40787, 0xc7a54e3d, 0xaa22720b, + 0x743b9bf5, 0x2420439a, 0xf87ea869, 0x2d65d6dd, 0x4ec5f4a9, 0x3a2ae182, 0x519a0716, 0xa236b6bd, 0x0a79fe84, + 0xca55fff2, 0x3df9c4b3, 0x1a69ae38, 0x06fb2bde, 0x8ee38538, 0xc77f1021, 0x76d4d5d1, 0x35d4142a, 0x7acc27b6, + 0xaf087be4, 0x1b4d120d, 0x4ac9fd34, 0x1d827bb0, 0x9fa33161, 0x81f4b5b3, 0x6ce66860, 0x7c3b318a, 0x45c33921, + 0x4ebca2de, 0x6c28c7b8, 0xf55c09a7, 0x44102abd, 0x44976941, 0xa88c4553, 0x2764f78e, 0xbb8d438d, 0x4bc4c845, + 0xf9ee0d90, 0x6ca22e40, 0x4050fc16, 0x4fb9632a, 0xf3a0652b, 0xf260c136, 0x77c1e8eb, 0x4632a90a, 0x5934f441, + 0x1a2eed5a, 0x72670e02, 0x9b46aa2b, 0x1b206a72, 0x3e470e9b, 0xbc4972d4, 0xe4323059, 0x1387147e, 0x59d7a713, + 0x81bd8c5b, 0x167cd5a5, 0x346e274f, 0xe12a92a8, 0x79248230, 0x49094707, 0x599f4d29, 0x99bc9366, 0xfc650495, + 0xf9292ff8, 0x7e545f0b, 0x3a3d6974, 0xd4eb92b8, 0x442deb06, 0x33a55059, 0x0764651f, 0x71eb654f, 0x51900695, + 0x236f1e34, 0xc58e3d63, 0xecc9ba1e, 0x8e86a799, 0xd9eccde8, 0x853baab3, 0x5c4d6d69, 0x2faea363, 0xb56bd5ab, + 0xee3fb92f, 0x716b974e, 0x23af53aa, 0x2bc518fc, 0x2926de36, 0x2c2a47d6, 0x73b80c96, 0x576a9fc4, 0x5b8cb8e0, + 0x481f6eaf, 0x4910d292, 0x72545dfc, 0x761d1028, 0xcbc6f68d, 0xaed2effe, 0x9df80117, 0x0ba2bf5b, 0x6de6d874, + 0x26a62075, 0x28ac9ad7, 0x42f562c9, 0xdfe65405, 0x25d400b2, 0xfcdbda41, 0x4e683307, 0x5f7e9db2, 0x691f276a, + 0x9c4e1548, 0x5c1d3a0e, 0x30efc497, 0xdc7017e3, 0xaedececd, 0x9beb63ce, 0xf26d7715, 0xbd431627, 0xf39e0056, + 0x040c2053, 0xc57e7d6c, 0xea3c7546, 0x0741943f, 0xb2f1786f, 0x738180a7, 0xbb10d813, 0x2efe86c0, 0x49175550, + 0x53f30b3b, 0x91b55f63, 0x4c7017dd, 0x9e5a864b, 0x5a938a6a, 0xc5b9e44e, 0x332a3e2b, 0xeb4bae8d, 0x18b1c899, + 0x608b2444, 0xe2e501e5, 0xc9590a51, 0xf4b4bce3, 0x3869b952, 0x14ec7143, 0x23cb1666, 0x88f67d87, 0xf9516d74, + 0x1f7ec923, 0xa8f4a1d2, 0x1808cc6a, 0x03048128, 0x96d91146, 0x3b30652e, 0x9281fb13, 0x400bff16, 0x89882826, + 0xbc04ef7c, 0x1fe5382d, 0xf8c2a89d, 0x4aff39ca, 0x3d794e5d, 0xd380e7a7, 0x4b42da35, 0x64cd44e5, 0xa7d339c1, + 0x23ac4aa1, 0x056b0c09, 0xaa9df5b5, 0x859fa451, 0xd7461dc9, 0x9fe56df0, 0xa8df5908, 0x71dd6ff6, 0xfd333c8c, + 0xb67e711f, 0x37c25080, 0xc39d9dd9, 0x5e463fe5, 0xaf3bb6e0, 0xd0298fa1, 0x0980baa9, 0xc9b489b8, 0x044d256f, + 0x20a2ee70, 0xec4426ae, 0x332f995a, 0xef8c9014, 0xdc6cc9d3, 0x30603ee9, 0x27000484, 0x7316c69a, 0x28acef25, + 0xc42359aa, 0x55a394a9, 0x2ca3fa8a, 0x12e67be5, 0x51544424, 0x71bdfb5f, 0xd268e868, 0xcec67fec, 0xf82927a5, + 0xc3f57aa1, 0x5e4efef6, 0x92da8b85, 0xd0c68a00, 0xed256b67, 0x6ff323e9, 0x93bed288, 0x80b8c34d, 0x6e1585f2, + 0x1cb0aaaa, 0xff0065b4, 0xb3a0e860, 0xcf75cb92, 0x5d56b54a, 0xbdd07086, 0x13b42607, 0x278c5480, 0xd2ea01a6, + 0x1bdd09bb, 0x4cc606af, 0x37a74ce3, 0x7ca5adb2, 0x610f4911, 0xdcf7cfcf, 0x4f860915, 0x7a9b1b0d, 0xe5aee630, + 0xf0800957, 0x60fe7d9a, 0xe0048a43, 0x35c37fa5, 0xdfb2e9c4, 0x274b98c2, 0xb8f40dd6, 0x5108b52b, 0xef4ee8e9, + 0x73f9aab5, 0xbb8eb13c, 0xaaebfc05, 0xf50ccc92, 0x958a33b1, 0x4ff7428d, 0x9f9315ff, 0x1f04609e, 0xfe0abe24, + 0x3885fd4a, 0x9136bbfa, 0xd4a4cca6, 0x3bb166a7, 0x30871338, 0x4855b51d, 0x671c8449, 0xdb54bfe3, 0x517d9f85, + 0x9983e001, 0x80cd26f5, 0x838d3157, 0xb1d928c9, 0x98a2af1c, 0x44ede21c, 0x9d3d1ecc, 0x19c99f31, 0x897ff3fd, + 0xaaa91b15, 0x6bd0d8cc, 0xdb00db34, 0x7bd8af3c, 0x5b8f6b4f, 0x57dbfa66, 0x0b80c105, 0xa0869889, 0x045af5f2, + 0x8e23f745, 0xbfa0466e, 0x8b047347, 0x2e9ec332, 0xe37870a7, 0x8d19aa91, 0x370bb919, 0xa056374f, 0x3327bb68, + 0x6e6bb0c5, 0x83149da1, 0x2fd7cf2b, 0x4e364f5a, 0x7eb73b9e, 0x6b361819, 0x859a6dc4, 0xd4a8fa80, 0x6675b427, + 0x254694d6, 0xb2b61fcb, 0x5f56a0b4, 0x45364081, 0xfb9c984e, 0x14ddf33f, 0xc1d0edda, 0x37e0a557, 0x09a354cc, + 0xdee08e84, 0x29358742, 0x6945e749, 0x65d8d0b0, 0x7a05dbb6, 0x54636add, 0x81b8ad2b, 0x17e8f789, 0xf334d02d, + 0x63eb93de, 0x857f685a, 0xe5d0c0f8, 0xb1bf4132, 0x3a36ef1e, 0x3d955659, 0xc33af3b2, 0xff5463e6, 0x0463fa80, + 0x74158727, 0x9fd7abf0, 0x25ac13c9, 0x348693e7, 0x6560b60a, 0x1b441268, 0x195d34d5, 0x7434b924, 0xf531db77, + 0xfc93a32c, 0xde210add, 0x449dfac5, 0x9ab1d334, 0x632bd7dd, 0x17d9d83b, 0x1965b397, 0x103db2a5, 0x0234f3ea, + 0x51c03156, 0xe750b1a4, 0x9a62ed4b, 0x278362d1, 0x2ff22864, 0xde12a3e0, 0x0b0501ae, 0x832892db, 0x90833bb2, + 0x097fbdca, 0xdc2e925b, 0x2293892e, 0xae6174c2, 0x613416bc, 0x1a1c35f8, 0x1321f539, 0x11558a87, 0xf2d54ccd, + 0x5caa7530, 0x28d1f6da, 0x6da51a43, 0xdcf171de, 0xbfce1c0e, 0x8056e6dd, 0x21c5aa40, 0xef2ec035, 0xb01bdc84, + 0x31d61231, 0x6bbb171d, 0xb266c180, 0x1b645782, 0x20089952, 0x40c98d1e, 0xe0c07045, 0x6a6cebd6, 0xabf0b92f, + 0x441cdbfd, 0xef70d180, 0x012c353d, 0x52ff8087, 0xf7444330, 0x6b522d8d, 0xf9fc02a2, 0xa8262327, 0xa265a02d, + 0xdf9359cd, 0x199996f7, 0x249f39aa, 0x81527848, 0xb79a53b6, 0x48fdaf15, 0x4862eaea, 0x3f987588, 0x54c3dbe9, + 0xbd25a1dc, 0xe01daa2d, 0xebbc28e4, 0x4de6365c, 0x39f012b8, 0xd58c5b0d, 0xff3085fc, 0xe04906f5, 0x346de5c8, + 0x64b61723, 0x2997ca19, 0xca13e131, 0xfd283cdd, 0x430fa2f3, 0x6977047d, 0x67ca7b0c, 0x51db2cb1, 0xee18826e, + 0xff5c58b7, 0x4f773d17, 0x4b7d8922, 0x1164b93d, 0x6197e25b, 0xb83fe50f, 0xf128cc5e, 0x60a32eda, 0xbd9d2158, + 0x7871fbb5, 0x78a09cce, 0x2ff77b9f, 0xf83fc6fa, 0xe595937e, 0x330e54d5, 0x799136c8, 0xa8802870, 0xd5ab3582, + 0xa5de9817, 0x1144d2d0, 0x4fa91768, 0xa3d4df98, 0x0c0f80a8, 0x21f8b246, 0x315cdfeb, 0x288261a6, 0x21b92e46, + 0x18980c79, 0xc30c0155, 0x0ed49992, 0x1ef48ffa, 0xb31d90ea, 0x4f85f14c, 0xcb90fad9, 0xdf8f7f0d, 0xe0921c39, + 0x8adebde9, 0x51aa7476, 0x9e171b95, 0x8102dfd3, 0x7d61a9b6, 0x48aeb7a1, 0xacbbecf4, 0x643efc27, 0x929b9f47, + 0xbe32d3a9, 0xbeb7fa42, 0x249de6e8, 0xf1f9c2d8, 0xcda70592, 0x59b3139e, 0x79d81a47, 0x969ac9e4, 0xc52cab04, + 0x19cf32c4, 0xf6afc18b, 0x351c18a5, 0x0eb087f9, 0x76ffaf72, 0x85512899, 0x4b109747, 0xaf08c5f1, 0xb0418f50, + 0xfa42b9cb, 0xb86c0728, 0x4728c5a3, 0xe1f00648, 0x072061b3, 0x99185d3c, 0x385428f6, 0x7ff84fd9, 0x298a8064, + 0x188e525f, 0x31dcce61, 0x80b4ddbe, 0x55a66d5a, 0x09ea1661, 0xeab08692, 0x2174fd5b, 0xc3293242, 0xfc50003c, + 0x3532969b, 0x8f7c349e, 0x4ceefbc0, 0x26a627fa, 0xf52cd71b, 0x1916a152, 0xb51db5a7, 0xdbdfbbec, 0x411935b9, + 0xc4a58dff, 0xf0382851, 0x6dc73a56, 0x056f4e29, 0x034f3e9e, 0x8d685ad3, 0x3ed68f15, 0xdf810589, 0xe6e3ce91, + 0x8a0136bb, 0x0afea0a2, 0xae3f6fde, 0x88265fd8, 0xb1263515, 0xd9550477, 0x6591caa9, 0xce6653dc, 0xc1e09f03, + 0xc821cb65, 0xbc42f8d7, 0x9f63d250, 0x7a89c712, 0x405658db, 0xe165832a, 0x3a90d765, 0x947fe6b2, 0xed5b5f80, + 0x003ab9e5, 0x08bf80bd, 0xbaabe3c0, 0x7036ec91, 0x0b1bb14f, 0xa7bf3ff2, 0x654ac39d, 0xb425c107, 0x10d65781, + 0x9ed80270, 0x01557c30, 0x65901320, 0x0935fc1b, 0xdcf5f1f4, 0x3f8a9698, 0xb6a37a6c, 0x2529e98a, 0xea61bd97, + 0x929744e4, 0xe2b25418, 0x8c79d393, 0x1a097e36, 0x1b3a1ace, 0x0c9b1153, 0x4502644d, 0x47f85850, 0xe9d60945, + 0xc695a67d, 0x1f28ee05, 0xc3557ae9, 0x84f20ca6, 0x6be6b0ba, 0xc40dcb0e, 0xcb7325fe, 0x13843e26, 0xbd886fc3, + 0x330f2f51, 0xaacbfe85, 0x586c1b0a, 0x7defb2d4, 0x5fe0be67, 0x92a9e6be, 0x06419479, 0x51d70071, 0xe7a7b91c, + 0xa002cd32, 0x1b7e0986, 0x265c850a, 0x75a7902b, 0x5660a78e, 0xcd8cc7f3, 0xd4e0d0a4, 0x72d3e6a9, 0xa6f13433, + 0x6076da8c, 0x4c3a8eb2, 0xef0a84a8, 0x9e7db29a, 0x2b9d499f, 0x5bac238c, 0x28b74da5, 0x803c1f4b, 0xeefd7039, + 0xb8074cd4, 0x6c95aeef, 0x81a91d9b, 0x4f6688ef, 0xdbb7a212, 0x477caf59, 0xc629b7cd, 0x266dcc4a, 0xb5bb9811, + 0x2c082233, 0xb2f45912, 0xcdedff6b, 0x89811c00, 0x0cb3d42e, 0xaca9e031, 0x4e3d43a7, 0x12e81173, 0x7a745603, + 0x828c5ab2, 0xa68183e0, 0x66d37264, 0x6b028b7e, 0xd5596748, 0x55cbaf2f, 0x85afb624, 0xf2f79964, 0x2a3f848d, + 0x3a785e58, 0xe981a588, 0x43611b8e, 0x30ca313d, 0x4c21b46e, 0xd51ff051, 0x68cb8520, 0x704b95ee, 0x540eba8d, + 0xf27ee20f, 0x4f5f5b19, 0xe0584315, 0xef5f1b67, 0x5e3d1bed, 0x26e25870, 0xb8d22078, 0xe512a799, 0xb141cbb8, + 0xec13c2c6, 0xf4feb5e7, 0x67d86514, 0xfe0ca7a9, 0x966d9e2c, 0x64ef5319, 0x1d4b2696, 0x15a5e8af, 0x9b7f8b54, + 0x6a9351f3, 0x7be8a64c, 0x04f74abd, 0x79fddda0, 0xabfcd04c, 0x97bbcb7d, 0x24f9b0d9, 0x8c3ebb19, 0x1b5d8e7e, + 0xf7843b1e, 0xa38a1bb2, 0xca540f69, 0x43a5fb18, 0x896d71d1, 0x35f649c7, 0x6c1f0240, 0xfd9eca68, 0x7da94c47, + 0x7431dc12, 0x1e0fada3, 0xcb74f81c, 0xa4aea253, 0x2a99d15f, 0x514df740, 0xc1c89c95, 0x55f3b5b3, 0x1ecbeb3d, + 0xc71c08b5, 0x054270f6, 0x4e9b11b0, 0x899b14d5, 0x51b6e9f2, 0x674b219c, 0xb81a6d8d, 0xdccf2df3, 0x3de04c73, + 0x0867677b, 0x849da388, 0x05a31afa, 0xdea48e63, 0x7d2c7d98, 0xd77c2438, 0x9281c13e, 0x6084882f, 0xe2686d07, + 0xc0376e60, 0xb14fdaa6, 0x93b65132, 0xfbb3ccd4, 0x138f5027, 0x7643c552, 0xc27010dd, 0x02a60df5, 0x61bde801, + 0x838bc968, 0x02e052a7, 0x90742ba4, 0x92be6899, 0x0b1e3588, 0x6e832ed5, 0x139ab300, 0xc6e8ba13, 0xf5110d20, + 0x0bfb3b20, 0x5ba832c3, 0x2a0cb6f1, 0xae83cb16, 0x54d579d5, 0xf2123d49, 0xc5ad6961, 0x496138fd, 0x3e24f254, + 0x569d285d, 0x668dab41, 0xfb1cc4d0, 0x6a53d754, 0xbf8d1db7, 0xb44440ce, 0x6478e904, 0xec8e24a2, 0x92db00b0, + 0x8682d211, 0xfb101713, 0xe5fae299, 0x93a5b5fb, 0x178d265d, 0x64819ea7, 0x7d331fb0, 0x3451256b, 0xfb8a95e6, + 0xc702447f, 0xa3360a8e, 0xb50fabad, 0x18c1db8f, 0xc589e0e2, 0x79e920ef, 0x4687d289, 0x483bc547, 0x009f0ad6, + 0xe184cb44, 0xc8992507, 0x0e7fcd19, 0x925ee6e4, 0x65d37dfa, 0x9051a014, 0x262e5b6d, 0xae1f8760, 0x691443e3, + 0xbdbdcb9d, 0x7bc77d81, 0x9e7dd35c, 0x48eb9339, 0x67e87ecc, 0x64a23c14, 0x5db1c823, 0xd845a78a, 0x8172dea9, + 0xf476ecdd, 0x9db6dddd, 0x28c8c41c, 0x9be6c981, 0x5a776eba, 0x2c8a5609, 0x26e2f3fb, 0xd8e9f664, 0xe5fe0152, + 0x69060e8e, 0x55b6d7da, 0x19dbb9bd, 0xdcea3f7c, 0x061f29c4, 0x68e1a5b7, 0x25e7eeeb, 0xf51588a0, 0x003558ee, + 0xd675f853, 0xf9653aa5, 0x33a6d227, 0xb81266f7, 0x056307d0, 0x3d1e0e6d, 0xf52d93d2, 0x3509613e, 0xb7ac635a, + 0xc6a801d7, 0x8ca6c5d3, 0xfec1e91d, 0x01d8e43a, 0x95ff9baa, 0xe1a348d8, 0x56ffef46, 0x9d8820c1, 0xb2dbb6e1, + 0x8ab4f238, 0xab0efa3a, 0x4031bf74, 0x5d17cccb, 0x4f895442, 0x95cd314a, 0x59189098, 0x8dd3cf0a, 0x86785ce2, + 0x97d9d214, 0xf0c6ca46, 0xf30e0878, 0x9cf7b289, 0x44a409ae, 0x925eb8da, 0xe0a24f4c, 0xfd4e3778, 0xd0ec4c3c, + 0x93511591, 0x882299cc, 0x517fadda, 0x09a86f75, 0x42981af5, 0x5c4a1819, 0x2141a636, 0xabb721f1, 0x05b850f1, + 0xc67a583b, 0x22582340, 0x224d5ae3, 0x35aa8420, 0x9ffa21e1, 0xc3e47ee8, 0x84d96e23, 0x96708cba, 0x82010e89, + 0x0b1d5f52, 0xb2df6e23, 0x758620ab, 0x3abc28da, 0xdc97b53c, 0x52858004, 0x85c10a98, 0xd5ae20a2, 0xa7f58f62, + 0xe42e1fdb, 0xef5a3ec1, 0x038d93f2, 0xacaaf2b9, 0x14e1fae5, 0x52188a70, 0x33c98d0c, 0xd722fb59, 0x0c224818, + 0x21e8c05b, 0xd6a351db, 0xf815183b, 0x35669fa9, 0xdf7463b7, 0x9cd3879f, 0xf6407411, 0x0d3b6705, 0x868787d2, + 0x7081d1fc, 0x78f5700f, 0x34c27c73, 0x6adb5a7d, 0xd529c727, 0x043f4be9, 0xbadbb899, 0xa04785c0, 0x9b25830b, + 0xa65d112d, 0xaae418e1, 0xa767bf76, 0x9f648537, 0xe50beb74, 0xc066fb7a, 0x3bffe6e5, 0x6df4489e, 0xfaabc4e8, + 0xa189eb39, 0x5dc353cc, 0x76defd5e, 0x4fd81ebe, 0xce80b1bc, 0x542f207a, 0xf5d8c288, 0x1334bbc9, 0x3cc4fe3e, + 0xa14a24dc, 0x1f75bdbb, 0x3984dd21, 0xe19196f4, 0x4d7f45a2, 0x3cc00045, 0x9dfeb771, 0xcad33db1, 0x6f2d903e, + 0xeed2db14, 0x26510bda, 0xb59343b2, 0xc01639c0, 0xca90ed76, 0x20808766, 0xc1044301, 0xc8ffce78, 0x3dcfbbdc, + 0x6e1d3722, 0xd6a60ed8, 0x7225452a, 0xabca4784, 0x814dfc95, 0x8c8d6da6, 0x3a10f15a, 0xdce4ceea, 0xd5aa69b1, + 0x8c6f9536, 0xf42f0736, 0x8ba27c4c, 0x41b15b24, 0x39febee6, 0x347b2b11, 0x41d1cfac, 0x71ff6245, 0x8698d164, + 0xe7110372, 0x59f00329, 0xd3f771f2, 0x7793af25, 0x46eba4ea, 0x15f409f9, 0x3e070eec, 0x99550580, 0x1385bed9, + 0x825c22a5, 0xb075fd97, 0x81b67124, 0x23a14bd6, 0xca335f43, 0x20b3cae0, 0x4e2e847b, 0xc2829ca9, 0x588fd8a9, + 0x8f6adeab, 0x0038c745, 0x0fa8eb11, 0xae5b3f44, 0x7a66178c, 0x66c4084a, 0xc08cc25e, 0x9586a8e3, 0xec14b184, + 0xf2987919, 0x953c07ce, 0x344ad779, 0x7274ac6a, 0xe76bbcd4, 0x1d0df8ea, 0xfbd0bdc7, 0xa26b67c0, 0x612f1ac3, + 0xc523e6b6, 0x0202ecac, 0x069a5c29, 0x362feabc, 0x506b3933, 0xa1c671d0, 0x5a21411d, 0xcf637e99, 0x35fc8410, + 0x7f44558d, 0xd648d629, 0x7aa8bfff, 0x84627e18, 0x82faaf1b, 0x9529fc02, 0x9ade5e71, 0x638d1b88, 0xe75eace1, + 0xb332e963, 0x66852db8, 0x7cd58816, 0xa085d8ef, 0x90f712a7, 0x6797802f, 0x900aa69a, 0x393f823f, 0xe1e92866, + 0xa139a632, 0xd210e6b0, 0xa3c5aad6, 0x700ce9a3, 0x28fc38e1, 0x0818484e, 0x1e608144, 0x14b5331b, 0xf491e9a0, + 0x4a2afb07, 0x9f1edb45, 0xd9fc566e, 0xb6c23193, 0x92474db6, 0x78183a01, 0x2fcfa8c4, 0xd695cba4, 0xce6fc0be, + 0x83582a46, 0xa30e5412, 0x55aaec78, 0xc15aee29, 0xaa9bd0b5, 0x661633d2, 0x4903b72d, 0x58607291, 0x47cddf2f, + 0x6f82d3cc, 0x6188830f, 0xee3ebac8, 0x928cd0e6, 0xc0db6484, 0xc787904e, 0x435fbc3d, 0x791c347c, 0x89247d1e, + 0xae4ae4bf, 0x3e4199b7, 0xbd7f1a5b, 0x13401250, 0xb5452211, 0x73de875c, 0xd966caf5, 0x838218eb, 0x2d61df5c, + 0x7176209c, 0x35568fb1, 0xdb003c4b, 0x9679c3d2, 0x7f384a8a, 0x1fdafe3d, 0x8d1b0c32, 0xfc7e1bdb, 0x7c72cec3, + 0xb4b3f867, 0x0ee6aa1c, 0x377f64e4, 0x3605e735, 0x9cf9fe85, 0x9bfbf101, 0xc076bd93, 0x88378689, 0x09bacd70, + 0x2f0807ec, 0x08d3be7a, 0x97dae843, 0x9943d5f2, 0x066a2253, 0x80aa55b3, 0x58cfa38e, 0x7bc51d91, 0x40c5ff0a, + 0x44677294, 0x129c1b93, 0x725adaaf, 0x2fb58695, 0x9888595e, 0xa33b42ea, 0x66089f24, 0xe08997cc, 0x71b8cfad, + 0x97ea04b4, 0xbf754e52, 0x07708d85, 0x5631e0f5, 0xe1858f4e, 0x88c12933, 0x8e84b974, 0x6be8891d, 0xfe4e721a, + 0x6ae5fb11, 0x2ebcd882, 0x08230108, 0xa6ad022e, 0xedf0283c, 0x9cdd1266, 0x6258fce7, 0x50122035, 0x7aff09f5, + 0x934e16c6, 0x263eb063, 0xabf62789, 0x0a39b189, 0xa55fd23c, 0x2a06ad84, 0x3bb415a2, 0x26f22056, 0x3197a433, + 0x7d2a0b2b, 0xa89b9c24, 0x70bae127, 0x920291a7, 0xb5498353, 0xaf1bb2d5, 0xdef60680, 0x08362d0e, 0xf04eb095, + 0xd91924ab, 0xd1291911, 0x07934ccf, 0xa3e71f3b, 0xf6574481, 0x0338ca4f, 0x6e7200e5, 0x6198cfbf, 0xaf45578b, + 0x903cb080, 0x72ea61eb, 0x79ac24ca, 0xcd77c02d, 0x05c95126, 0x985512c5, 0xc2a90d77, 0xe4654a6d, 0x50adf3f8, + 0xadcced0f, 0x82645ce1, 0xb5700463, 0x32832930, 0x01cae3f0, 0x85481828, 0x65b2bb82, 0xeb92d6ce, 0xf99994bf, + 0xe18c1ca3, 0x59d31346, 0x7c8dba26, 0xd5339eed, 0x0726979a, 0x3b01c839, 0x4b013053, 0x54f050e6, 0x0ca67a57, + 0xdc4a7b4b, 0xbac740b4, 0xc5bacacb, 0xcd4140af, 0xc267fc62, 0x0924f44b, 0xd9106d2e, 0x05218989, 0xda6d3d8c, + 0x4db7d6c1, 0xd9fbb54c, 0xabb89e9c, 0x6144b8a2, 0x656fe184, 0x59a07d0d, 0xb0c73461, 0x93cd2447, 0xd1698fdb, + 0xa06d99a5, 0x5640c149, 0xb6769c45, 0x964ab9e6, 0x70d04f63, 0xd8e3f99f, 0xfa3354a3, 0xe2a308ee, 0xb5710356, + 0x487bad3c, 0x63ec9fac, 0xf0805824, 0x49cb4003, 0xa39fbf8a, 0xd3ef8477, 0x460c43d2, 0x09301f9f, 0x25954942, + 0x54e7ba79, 0xa6f4e537, 0xfc1ad919, 0xd022a7c3, 0x90ce1481, 0x8406c3f5, 0x0becd01f, 0xaf5dc9d2, 0x02e3e2c7, + 0xd4e611e7, 0xd5d58a3d, 0x76f0a1a3, 0xe3c46286, 0x3ee89241, 0xa9af5c99, 0x1d3f47aa, 0x273b67ee, 0x7ae858ad, + 0x55bae041, 0x7bce2ae0, 0x1567da53, 0xbabe641e, 0xf4a8dcd0, 0x3628be61, 0x4f115d49, 0xe60f1c90, 0x5fcb6682, + 0xba9fb127, 0xd7bbc2bf, 0x6cda0cb2, 0xdeb50bb1, 0xeb52acb4, 0x00c06e9a, 0xdaaf56e2, 0x9bb709db, 0x2fc3afb3, + 0x3b14f466, 0xe9b5e7b3, 0x7ec4880b, 0xd78daf3d, 0x439e9c7e, 0xafbc8e83, 0x5b028a8c, 0x69f53988, 0xbb9560f4, + 0x2cbb41b5, 0xb505f9ce, 0x5d1652fa, 0xb93f4373, 0x0b8d2108, 0xdaa1807f, 0x9f09e7ac, 0xa88df583, 0xd9726349, + 0x6fb01107, 0x8452150e, 0x1dde003c, 0x3efbfcda, 0x626f8597, 0x2be3044d, 0x576b8b13, 0xd1c47687, 0x18d0e430, + 0x56bb3729, 0x6c06f390, 0xe233551e, 0x37cd5a25, 0x3584bb08, 0xb9152639, 0x52255f60, 0xac4f3ee0, 0x17782181, + 0xdbe246d1, 0xd41e4771, 0x72f4a8c1, 0x679ff291, 0x9c9e918d, 0x8123e292, 0x9101c8d8, 0xc7bb8d0d, 0x77edcc77, + 0x42e9c9c6, 0x6df8d107, 0xdf2b61d6, 0xfdb30291, 0x807b79f1, 0x99c75ad4, 0x55409c8a, 0x9ffc7039, 0x13c808be, + 0xc44ee4c5, 0x299b89d4, 0xddd8948a, 0xdb4ce11e, 0xdb18a40f, 0xe91dfdec, 0x8420f546, 0xde47717f, 0xdf39bd0a, + 0x28de1414, 0x7a177243, 0x993bf5a6, 0xf366695d, 0xc9fe6081, 0xbab2d293, 0x0d7cfdc2, 0xc5b33197, 0xb028cfb1, + 0x148c0cfe, 0xf0a11761, 0x69620255, 0x00af9389, 0x5a27afb5, 0x104ae8e9, 0xcf6d92ff, 0x5454977e, 0xfd4fe771, + 0x7ae26748, 0xaa431a83, 0x9b04d200, 0x0a12e231, 0x8439c6eb, 0x80f5fb96, 0x7db87740, 0x6dde3345, 0x390b1f6f, + 0xf30d30f0, 0xb6342ee3, 0x65c353fe, 0xc08ab437, 0xaea5ce2a, 0x9d2d9781, 0x4775c40e, 0x19b68c75, 0x34a43d2e, + 0x4a7ab5b6, 0x6e598ac9, 0xa18d9daa, 0xb3117dff, 0x4724082a, 0x6e22fcb5, 0xf463c15d, 0x87f055dd, 0x5b58bcaf, + 0x2b897408, 0xd45722e0, 0x748311d1, 0x216dcd3b, 0xeaed4f3a, 0x5cd793a6, 0xa855f163, 0xacacc32d, 0x40b491aa, + 0x21f595dd, 0x010cf79e, 0xa4e841a1, 0xe23602fd, 0x68667f23, 0x023d02c6, 0xbfcdd57c, 0xa4ccbefe, 0xb137e44a, + 0x5e8e7093, 0xf3e8755a, 0xcc234541, 0x3d450bb9, 0x3cb65fee, 0x23acd029, 0x5ea58a32, 0x11a60576, 0x6a2a39f0, + 0xeeef530c, 0x1b38ab60, 0xd0072823, 0xac708cf1, 0x32710d64, 0x91938e77, 0xd2b09a43, 0xac936f23, 0x0abf4aaa, + 0x2f6b5ec4, 0x7d21ce39, 0xbfc3d76a, 0x6acddb09, 0xc459580e, 0x281833f7, 0x6c205582, 0x2a061dc6, 0x9ef5981c, + 0xfbd65bee, 0x11c47f12, 0x95f8778b, 0x9af6398f, 0x86ee2d3b, 0xf756aacd, 0xb9043653, 0xfe622ad8, 0x0b94f506, + 0xfe636b13, 0x138ad4fe, 0xf1b30574, 0x9242b09e, 0x179a3a2f, 0x0975a7ec, 0x758b9388, 0x25a5a5a1, 0xa3c5f52e, + 0xae078533, 0x5adf9c93, 0x37e65348, 0x8d7f63ca, 0xaab02c05, 0xb9358da6, 0x3f24de2a, 0xa17b4239, 0x374194f1, + 0x8e647aaf, 0x9c5472e3, 0xf99c032d, 0x797cd83c, 0xee187aa1, 0xc59a2959, 0x092246c8, 0x6432a980, 0xe6a5fd0b, + 0x28062094, 0xc27217a9, 0xbb11bd0c, 0xf6c337fd, 0x5d2f4c93, 0xba02a9bd, 0xe2f0d720, 0x34803bcf, 0xbe54fa12, + 0x41786b39, 0x6f3557af, 0x62bde135, 0xe609f9fb, 0x6b84d0ce, 0x2dafd0b3, 0x8800bb40, 0x61335f6f, 0xb21cc0ef, + 0xfdeed370, 0xe37542cd, 0x41a8d148, 0xabc0da9b, 0x7f5ccc39, 0xb0231a09, 0x4bc220d9, 0x70d30a11, 0x2d10cf15, + 0xaf03f245, 0x7a2725fe, 0x6d1211ee, 0x7e3d5f73, 0x4f88125c, 0x7fa2d38a, 0x3861768c, 0x0c278f86, 0xfc9c4768, + 0x49b447cb, 0x25137ab4, 0x1c265547, 0xbb33f657, 0xa58aedd4, 0xb12a709d, 0x8d606b4a, 0xb7a0ce7e, 0x76aebd45, + 0xb4130550, 0xadf6082d, 0x8494cb3e, 0xdace7c6f, 0xcb43f8d1, 0x3b3ad368, 0xd9c4589f, 0xfaea603e, 0x1523f67f, + 0x897bccc1, 0x745be311, 0x132bfd72, 0xcedd421b, 0x00f74eee, 0x9580b721, 0xc3c59675, 0xfbabf523, 0x5efbe257, + 0x8e18f6ca, 0x4c21a400, 0x2113b1cd, 0x8d85a03b, 0x9144b587, 0xee2cb352, 0xcb7d8add, 0x72ef5a2c, 0x07763f67, + 0xa7f7dbf3, 0x4b1294f2, 0x923814e5, 0x02c46281, 0x4c8cad37, 0x2c3a928d, 0x7227a069, 0x68e2fc11, 0xacd6bf26, + 0x7080250e, 0x1bbc1f0c, 0x5aa568bb, 0x2a74e9d6, 0x9bdcbfa8, 0x19eadc26, 0x5a9bbbdd, 0x733cc5e4, 0xb7e4f3c8, + 0xb749e856, 0xf2fc67cd, 0x7e31d008, 0x6b79577a, 0xbac11467, 0x5f339eb6, 0xd62ef82e, 0x0d7a239f, 0x7113b453, + 0x404dd84e, 0x0d3d6614, 0xc6cd8f6b, 0xd9e9ab21, 0x58462bf9, 0x58f937f2, 0x355a9422, 0x16228dc8, 0xc525379f, + 0xd78bd463, 0xe80ec9a8, 0x7b12a8d4, 0xc64689be, 0x27d32f35, 0x759ffdd0, 0x1893319f, 0x4694e3ed, 0x7b6fb3f2, + 0xfbd1d1ce, 0x7e05ef64, 0x2568bcaa, 0x439e33d0, 0xb33f61c0, 0x36334539, 0xfe4a813b, 0x76f95d8d, 0x4419ba1c, + 0xb8a9eb43, 0x9aa24626, 0x1cb1720c, 0x0f7394aa, 0x3fd2767c, 0x56fc769b, 0x2a6d28ed, 0x5d485d9c, 0x484b95a2, + 0xc73b48ce, 0xeccb2e46, 0x33f4cac5, 0xdf545a7c, 0x2948c2b9, 0x3e4de05e, 0x69407a4d, 0xdd0c8843, 0xfbb2042a, + 0xc489436d, 0x4a9e5e48, 0x8b3fc921, 0x32a102b2, 0x18946be3, 0xe5e6d07e, 0x2a7b7b65, 0x8a7e4801, 0x12ade166, + 0x4ad76023, 0x9c711f8a, 0x6a416b0b, 0x66972782, 0x16f47e71, 0x23b3f01c, 0xe8bf0dd7, 0xb153a159, 0x61f0d67e, + 0xab674bac, 0x43034871, 0x2bad9951, 0xebd637fb, 0xf796dcc8, 0xc178f8f0, 0xf90733cb, 0x4ccc9f0e, 0x0b640490, + 0x7d1e17bf, 0x6a3f721d, 0xb9d403cf, 0x776cd897, 0xaa4a6db6, 0x1cd37ba4, 0x1abd714a, 0xcc6a2091, 0x868c41a5, + 0x2062cfed, 0x50943cc9, 0x21dc5389, 0xcc699bf1, 0xf438303c, 0xd3183a89, 0x13a422df, 0xaca38d5c, 0xddf4c9b5, + 0xd487bf9d, 0x14862841, 0xc8cc24a0, 0x4acc6fff, 0x946d68ad, 0xe123d57f, 0x864214ef, 0x139fbb46, 0xc98f2d05, + 0x78481759, 0xd684294d, 0x43742db7, 0xce41ae23, 0xc0a75052, 0x843de9f8, 0xadf3a2d6, 0xfd00a291, 0xa92a42b6, + 0x5bb867c0, 0x75cb895d, 0xb8f11f5c, 0x16b91562, 0xc4cada05, 0xdf38a16b, 0x509ff252, 0x7151ec26, 0xf8b93c9f, + 0x7f5a8b32, 0xdd2e764b, 0x58c8535d, 0x7b486d11, 0xc093af5d, 0xd934aeb0, 0x1bccea83, 0x449e7720, 0x6822cae1, + 0x43949e76, 0xddae4f2e, 0xdf64ebf9, 0x2c6ee05b, 0x1374305d, 0xd5102041, 0x50163a04, 0xb2b9ded5, 0x5aedede7, + 0x6feca467, 0x1dc08675, 0xafea39f3, 0x561da048, 0x48cf0777, 0x72fbd346, 0x37a39fb3, 0x3240d80d, 0x2b9c98a6, + 0x33e43536, 0x3d76867e, 0x585a08e6, 0x44f7ed69, 0x80eb0761, 0x41cf8b47, 0xfefb7df4, 0x2016ee00, 0x9d8b215a, + 0xa5c52905, 0x51368455, 0x0c249783, 0x90346912, 0x8605bd07, 0x9df74276, 0x2d758e6d, 0x67cef62d, 0xc602c7c6, + 0xe0ef0a13, 0x5513825b, 0x470830c3, 0xccc05c80, 0xf1a10aa1, 0xa35d2002, 0x486459c3, 0xa702067f, 0x5ef0c2cf, + 0x316dd0f6, 0x0cf5299f, 0xd18aee57, 0x4d67847e, 0x72c926bd, 0xd99978da, 0xf014eec6, 0x451170ad, 0x61e6079b, + 0x30baedb4, 0xa32a15a6, 0x27a8f71d, 0xd800e58b, 0xc74ebeb9, 0x9c70efb9, 0x9ebecb04, 0x031d2018, 0xcb3d6ade, + 0x436d29e1, 0xdf481c9c, 0xcd0c1d9a, 0xa0d606a3, 0xac8173fd, 0xd8040cc7, 0x6ce8918a, 0x58a99212, 0x433d941d, + 0x7ba1d4af, 0xebc3e306, 0x1efe833c, 0x0d42a398, 0x44680c1d, 0x85d6ed6c, 0xd65c4e8b, 0xde5d2273, 0x67299e68, + 0xa59ef024, 0x7f2f12db, 0x52b78c1f, 0xb57df5b5, 0xfbac3734, 0x51103d9b, 0xd60dbae3, 0xad1dfacd, 0x8c6195b4, + 0xd917cbf0, 0x4025a1a5, 0x9239f686, 0x6a58fb84, 0x47463a48, 0x60cfe3dc, 0xae5069e9, 0x8c227ada, 0xa6dd2127, + 0xa27b7ed9, 0x6e16fe7d, 0xaa761480, 0x469cf4c2, 0x37b8d7d7, 0x5c515dff, 0x0a0046b5, 0xbfca1d07, 0x86ea5846, + 0xf098428a, 0x7da35c26, 0x7d61ae21, 0x4fd08481, 0x4061ae67, 0x46d816c7, 0x1edd84fb, 0xf55d4345, 0xa2a55771, + 0x64ecc4d1, 0x241b05a8, 0x76a6c052, 0x19c3c7cb, 0x9834b0d5, 0x94aa0b92, 0x201e1e28, 0x4de652d0, 0x57f61ee9, + 0x7d0a2215, 0x3904ef8c, 0xe0b701e7, 0xee77b3b6, 0x501e3569, 0xf3612990, 0x68063c51, 0x96105d71, 0xf3218570, + 0xba3d5077, 0x55bbb770, 0x8039e37a, 0x6f472673, 0x822dff5c, 0x721d517e, 0xd95399bf, 0x3cd24632, 0x691ce304, + 0x7cdc9b55, 0xb2795c76, 0xf344c7cd, 0x073da853, 0x1c1a087e, 0x43f1f40d, 0x362255f2, 0x5d486737, 0x3a80ed72, + 0x38b4f360, 0xabdcb364, 0x93863008, 0xfe05e61d, 0xb58903a5, 0x7b2deb98, 0xc1928bf5, 0x7fc52e7f, 0xe2e5b759, + 0x983bb9c2, 0xa3c116b3, 0x16205aa9, 0xae0445c1, 0xbe8bf6c2, 0xfd097280, 0x98a56518, 0x2309f731, 0xc07f6c99, + 0xae87315a, 0xc315e895, 0x6522f923, 0x00fd9941, 0x7cf5d0aa, 0xff6b4d53, 0x37a3bbdd, 0xd4cc84cd, 0xf74f83d5, + 0xef1f4347, 0x4cde932b, 0x6a94c33c, 0x96475085, 0x4525ebdf, 0x63563509, 0xfa40dc63, 0x2f4164c5, 0xed10746f, + 0xe6a92431, 0x42f769df, 0xb806bd17, 0x1e6a0928, 0x7087b8d1, 0x1cb1fdd1, 0xc7d7fb14, 0x3c9ef710, 0xcfad0204, + 0xd3090ac6, 0x86444152, 0x1080a779, 0x0d6eecfc, 0xa035246e, 0x5ab89f41, 0x8c2933f3, 0xa50b537c, 0xc80a2b7b, + 0x2f15cefb, 0x71958974, 0x8633280e, 0x98cea68b, 0xedbf3d8d, 0x13ad6f29, 0x34ccd22a, 0x9be43e98, 0xd3c74021, + 0xf2c69d53, 0x3a48aee4, 0x7f43e097, 0x3399e42c, 0xb1163456, 0xf177d8ff, 0x2ae35e7c, 0x01b821f2, 0xc8295ba3, + 0xff889d47, 0x7c2c0898, 0x217edaea, 0x7d5ed4f8, 0x84d1c80c, 0x0589bbbb, 0xfaadbbf0, 0x26f438b0, 0x6e0613d0, + 0xb2ab0e52, 0x5441074c, 0xe8479f4d, 0xa7e68350, 0xa2b21e57, 0x4a870fed, 0xe4e5e620, 0x0124f5c0, 0x4d12660d, + 0x5acc2712, 0x2e95eb23, 0x50373669, 0x8cb26316, 0x4ca0474d, 0xb390673e, 0xfc6714d3, 0x711bb7aa, 0xdf4af223, + 0x224b2ba4, 0xd6ba16d8, 0x53c35235, 0xdaa792fd, 0xbfd9a308, 0x13a788c9, 0x316d45c6, 0x820cd731, 0xc86d5208, + 0x85e24caa, 0x73bd801b, 0xad4e9416, 0x8de60493, 0xc4621368, 0xdc09142f, 0x48010d0a, 0xcc83e468, 0xa8f34dfd, + 0x2045871b, 0x1209ffa9, 0xe5986af4, 0x4539699a, 0x76a8b39d, 0x851b9410, 0x97c5b35d, 0x6ccf453b, 0x50e34836, + 0xbc1fa189, 0xd81c19df, 0xb6069bec, 0x096feb8a, 0x1fbf89ce, 0xb639ae53, 0x3d79f7c1, 0x3d08d8f7, 0xecc5455c, + 0x182a2a7c, 0x9b30cf8e, 0x7fc6d63c, 0xce667503, 0x26c18216, 0xac6471ee, 0x5a0da975, 0xdcfd5dae, 0x81492159, + 0x302ec787, 0xf0cfa05f, 0xd8dee507, 0x474ba735, 0xa23620bb, 0x7ef21f46, 0xbbbb3166, 0x5dd609dc, 0x4aa63b72, + 0xfa60942a, 0xb7d5e78b, 0xb80ed86c, 0xe7537548, 0x2efd3e69, 0xcf6f46b5, 0xb0b903fd, 0x1e8c1ce4, 0x45828611, + 0x58426b8a, 0xb3726ebe, 0x4bc0fccf, 0x5ec6a4c3, 0x9ed22ddb, 0x3d69158a, 0x040ac69d, 0xc2e3567b, 0xf60cd118, + 0x48dbb447, 0xfd3cfb15, 0x05d2dced, 0x9576a710, 0x080cdae5, 0x8e6fd51d, 0xa737a36d, 0x7a1d9e1d, 0x3e03b98d, + 0x59008959, 0x293a2fcb, 0x228882d3, 0xcf303223, 0x5ad1a5db, 0xe9302c96, 0x68d2b17d, 0x05a27749, 0x9dff0019, + 0xaa42b16b, 0x49bab022, 0x726d44ae, 0xc1d0920f, 0x4eb754da, 0x0fb63ed0, 0x4fda4b21, 0x95ccdc9e, 0x9d94a981, + 0x38b93059, 0x9847911c, 0x06ee86c3, 0xc9ae2ae8, 0xe20bb7f5, 0x1f33bb7a, 0x0ec571e7, 0x197373f2, 0x1cf0c6c6, + 0xd1ca5724, 0x2dce7d3a, 0xad856144, 0xd12f48b7, 0xfe1bcd8d, 0xe644a0ec, 0x21b61870, 0xf355e40b, 0xfdb98361, + 0x546f0d23, 0x7a06f9ef, 0xb2d058d7, 0x19f194b9, 0x8f6e1093, 0xd003f53d, 0xe42d7cdb, 0x71c00cf5, 0xeafc81ec, + 0x458f7065, 0xbeafd784, 0xac8a1295, 0x0f73e46a, 0x71e01454, 0xd2b5fb1c, 0x04fc5450, 0x4828ae25, 0x40f74c72, + 0x1ce20b6a, 0x6a5d01c4, 0xbc35728e, 0x375fe6b5, 0x6321c27e, 0x7f780f28, 0xfa2e9156, 0x72f40134, 0x888b798d, + 0x156a1fc7, 0xfec1c22d, 0x20a73ee3, 0x60ea733f, 0x3f51fabe, 0x48eafeab, 0xda57a28b, 0x424acef4, 0x4f0f732a, + 0xfee2cd51, 0x9348a195, 0x16c0e83e, 0xf22d858a, 0x3283cb8f, 0xe66edf7b, 0x41ff2605, 0x7eb22c77, 0xacaccfde, + 0xd7e6343b, 0xfe06e067, 0x479fa1a0, 0xcbabc097, 0xecd1e6a0, 0x23bc9a21, 0x77eaf630, 0xbf8ecceb, 0x10468fd9, + 0x1c518c74, 0xd61c1e92, 0xb4676453, 0x1a216a00, 0x0e2e9473, 0xb9d0cb4c, 0x77762ebe, 0x5b0d75ea, 0x63291a8f, + 0xa734dbee, 0x575bac15, 0x822b3406, 0xff1464a4, 0x7d32cf6b, 0x2e74d6fd, 0xc441d809, 0x3ceb9bf9, 0x95e16875, + 0x80f112ff, 0x92a6c045, 0x717cb263, 0x0f91d85e, 0x857ad60e, 0x529ad33b, 0xcf552cfa, 0x3c9ac703, 0x0e0c0f00, + 0xb40b177e, 0x612d825d, 0xa57f131e, 0x08257f2d, 0x39a0a6af, 0xe4c21295, 0x3a62c26b, 0xaae657d2, 0x663d369b, + 0x61b94ad1, 0x57bb271a, 0xef27283a, 0x955ae2ea, 0x9ae4491a, 0xd7b24551, 0xbdc35f1d, 0xf44f719c, 0x911f5b05, + 0xdb24bc72, 0xb2339827, 0xd68733c4, 0x2a344b10, 0xd2372eab, 0xf19615cb, 0x04583732, 0x9d941306, 0x7a7ff088, + 0x52c02e2c, 0xa9702177, 0x33600919, 0xa4c5ed27, 0xf98e47de, 0x879ff728, 0x853b7c15, 0x09b54a54, 0x25c7fe4b, + 0xb30159c0, 0x6ef1f2ee, 0x52f705f1, 0x4e150137, 0xc133ce9c, 0xe3ba0522, 0x7bdce29e, 0xabee209c, 0x91319d42, + 0x93cb8552, 0xa82ed7d5, 0xe10ed857, 0x16a31505, 0x6f46f189, 0x679b8bfe, 0xf0f1c316, 0x41e5e964, 0x0104b443, + 0xce181cd0, 0xe9ddc5b1, 0xa11df2f0, 0xc79a1100, 0xf8040a44, 0x2489b528, 0xaaaff1d8, 0x7fff1593, 0x6fca71c0, + 0xc3f281a2, 0x9167f1dd, 0x8e7ee7ff, 0x7da07820, 0x17714c4e, 0x8c6e205d, 0x8efd38c1, 0x249d7609, 0xdd070791, + 0x2187bcd5, 0xfdeaa0a5, 0x734b7f1e, 0xf91f1f7a, 0x8ca01e1a, 0x53b6deb9, 0x4f940bee, 0x449009ba, 0x6eda2234, + 0x809ff6ed, 0xb192a82a, 0x10262768, 0x1f903e49, 0xcfd3f491, 0xa08b2a36, 0x37e1856e, 0x485e3a90, 0x54f4b964, + 0xcdd3ec81, 0x5083dbf5, 0xdb6c1186, 0x087faece, 0xe9dc247d, 0x0e8e706a, 0x6201b9fe, 0x7ddb0efc, 0x67edd1d9, + 0x42d983ba, 0xa9585f1e, 0x4f5e4514, 0x72a2b5b7, 0x923004f3, 0x2acb04a9, 0x45b88f62, 0xbd21ef8b, 0x82c509a3, + 0xa2dcc546, 0xcf1c1772, 0x5c59f440, 0x16791e49, 0xa3824027, 0xa7f002e1, 0x168a1590, 0x1fa55da7, 0x73ce4f9a, + 0x303bab8c, 0x661c8a0b, 0xea1c1608, 0x2cfdf365, 0x8c2c0d09, 0xc9065184, 0xa4ec37c7, 0x926c8586, 0x272c6d4b, + 0x1e581312, 0x6db8fa83, 0xa49cda13, 0xaa3aefb5, 0x2e8e2d45, 0xb8f95dd2, 0x4d17079a, 0x588e7ced, 0xa45b7adf, + 0x8e6109c5, 0x4d1aa2e7, 0xe564597b, 0x9a8a0db5, 0x4d5dc1a6, 0x76c1cd0d, 0x717fb0dc, 0x17e1bf9e, 0xcaa8ae58, + 0xf01af211, 0xafc3b92a, 0x67ef99f9, 0x7ad979dd, 0xc81cdfcd, 0xb687c1bd, 0x0e50b146, 0x7c03ff12, 0xc116ab31, + 0xb31bd461, 0x8086de6f, 0x10178dd2, 0xba069aec, 0x96e7247f, 0xafeff495, 0x3a90b70b, 0xe99d8f88, 0xd374486a, + 0x6a1e71b1, 0x46fa1ffc, 0x0515c0fa, 0x85177daf, 0xd414ffcd, 0xe744979e, 0xe8295b61, 0x5838cb3c, 0x016da4d0, + 0xb77192fe, 0xad4683df, 0x0d92cb35, 0xe32a1ae7, 0xee20f17e, 0x77057358, 0x42738a0a, 0x098413c6, 0xc3215ee8, + 0x2f91e1bb, 0xf3e17228, 0x6eb03aba, 0x0c4bf67f, 0x019bdc27, 0xa385a4bd, 0xfc5c922b, 0xb0ec93d9, 0x875f7ecf, + 0x7a0f549d, 0xdac0aa39, 0xe1cdd2ac, 0x77a15fa2, 0xf0c87355, 0xb36e0512, 0x7920fd65, 0xe3107b1c, 0x19a3b588, + 0x7fd4b397, 0xf62552f1, 0x2af1e392, 0xa88bde02, 0x158fa2a5, 0x7c62262a, 0x267d2623, 0xc5a47324, 0x1fdbfdb2, + 0xe5e77593, 0x251daecb, 0x9db9c452, 0xcdae1b5c, 0xe5e07892, 0xe1e35432, 0xa64d22a5, 0x033c2298, 0xbfa90fab, + 0x29ee4be4, 0xa5b32120, 0xe5794e72, 0xd0360e09, 0x4074956e, 0x28704046, 0x34bf67d9, 0x71cb274e, 0x1a673290, + 0x695c4368, 0xdd91bced, 0x336086f8, 0x8dd523e8, 0x43cdbecb, 0x1995b4d0, 0x09df1c40, 0x4b7bdadc, 0xcd1f66b3, + 0xdc050590, 0x5a4134b5, 0xe67de420, 0xf7ac50be, 0x31600435, 0x162b7721, 0x88b3cd13, 0x94941ce6, 0x728b5587, + 0x104aa594, 0x61cf4e02, 0xe6158171, 0xdfa1645d, 0x8ae50cfd, 0x0d24b9d0, 0x0571cdf6, 0x97837042, 0x2f395ffb, + 0x79522d5b, 0x3cd25440, 0x56ff9bce, 0xa6fb9f1d, 0x60238feb, 0xa70ca429, 0x5c043869, 0xde5e2293, 0x92e8743b, + 0x3cb95755, 0x921fa6a0, 0x2ddc3a97, 0x5efe18da, 0x2cabcfc7, 0x5eed1833, 0xfee4233a, 0xc0696e85, 0x2649900b, + 0xf812019d, 0x5a088a85, 0x900de0e6, 0xe0362a25, 0xa44e04ac, 0xe431df10, 0xad5ec4aa, 0x6ca4a8f0, 0x4edebea2, + 0xca2ee07c, 0x60a9e625, 0xdb4029e7, 0x8f8b1a68, 0xc59a6194, 0x6310dd8d, 0x06788293, 0xde50be8d, 0x5f11c6c2, + 0xc98c9492, 0xb9eb2790, 0x936ae9c5, 0x7c9bdec2, 0xf606ba83, 0xf052801a, 0x3093222f, 0x4da52bce, 0x897fd16e, + 0x26d0b694, 0x56f785d5, 0xdd09bc80, 0x92a943e2, 0xa4f9dce8, 0x914bcadb, 0xa09f9872, 0x2d96e9bf, 0xfb8b37ab, + 0x65ef8127, 0xe833ec09, 0xf8ef1781, 0x0efa788a, 0x9add4e0e, 0x321a383a, 0xcf468814, 0x8ea1a090, 0x575cb94f, + 0x522eb9dc, 0x5775fc04, 0x80fd11dc, 0x8451a12f, 0x10a7755f, 0xdc1ff1e5, 0xc93fd306, 0x8a844dd1, 0x5eb8e17b, + 0xeb9d0087, 0xc4432d60, 0xc103d1b3, 0xaba1d335, 0xceeabe25, 0x8d7eda3d, 0xcc4f8cc0, 0xae54fbc5, 0x5531624b, + 0xd87eaeab, 0x622ae56d, 0xda557fa1, 0xd86114da, 0xe0962370, 0xe031b8dd, 0xf1b53d83, 0x50b71567, 0xcba24437, + 0x997fb7dc, 0xbe71fd1d, 0xd6f39f51, 0xda9bc309, 0x58b4927b, 0xd8031deb, 0x882c2201, 0x490b4334, 0x3c0265af, + 0x651b8303, 0x86346f28, 0x6d791a1c, 0x42892d0e, 0xde738b9f, 0x99d87f4f, 0xdfd2ca35, 0xbf871b30, 0xd4a30ea0, + 0x2e1f2ead, 0x10363652, 0x5e6ba60b, 0xf8061f3f, 0x00ed5e11, 0x438307d7, 0x84a7462e, 0xb48a6dc7, 0x796c34de, + 0x9ce17c3f, 0x4f72991c, 0x12d155ce, 0x9c627ebd, 0x35e36a42, 0x992a7f9f, 0xe8019b88, 0xb76e760d, 0x9013a699, + 0x319accd9, 0x224c4c49, 0xb5a5c625, 0x9c776944, 0x6015cb08, 0xa04a2d07, 0x087b5e1a, 0xa5077c67, 0x5b29288a, + 0xbd43d624, 0xbc520024, 0xb7499937, 0x52a7d61e, 0x66d32749, 0xf4498049, 0x09364e63, 0x0efbd115, 0x7e536942, + 0x0db1a9d1, 0x529970cc, 0xcfbbaff0, 0x5bf7cde3, 0x81e4333b, 0x73c504f6, 0x9f6c787a, 0xf7341e69, 0xfbb89fa1, + 0x9bc472d6, 0x2f244b3b, 0x152e9b8b, 0x657d9d7e, 0xd96adc68, 0x6cae9cff, 0xae5fecdc, 0x6a603b6e, 0x4076fba6, + 0x52110b9c, 0x137ca82c, 0xe11a0e01, 0x5c0d721a, 0x786a6913, 0x5b641215, 0x675ab599, 0x4ef3bc1d, 0x2aa73263, + 0x86757a79, 0x6bdd1002, 0x544998ff, 0x52c3d5b3, 0x10ae0474, 0x11f71c74, 0xa15e9cbd, 0x44326592, 0x8c6e8594, + 0x03352093, 0x79d2a615, 0x50131293, 0xd5fc7e07, 0x74c2c347, 0x39aae8c4, 0x5b480f4f, 0x17a6800e, 0xd82ea0e2, + 0x4a582395, 0x5984829c, 0x7a091d6a, 0x8e65d945, 0xe5469917, 0x0b43323b, 0x0510f5d0, 0x65bc5666, 0x9e790510, + 0xa4f17464, 0x923833b1, 0x4746578c, 0x16843c81, 0x91569471, 0xb7c6ab61, 0xe6d474e7, 0x9836a752, 0x28f24872, + 0x1f7daa3b, 0x064859ab, 0x6c5e3d5a, 0xc8e140b1, 0x117e75a5, 0x52a32047, 0x81bfa77a, 0x2bda4dec, 0xda1172a9, + 0x8e49099e, 0x8033c3ab, 0xb087dbb0, 0xe8f21228, 0xdc996029, 0xcc902ec9, 0x183b118c, 0x1b9497ff, 0x2b0e5a2b, + 0x15fc70cd, 0x4f1e3645, 0xd2c9820c, 0xb419650e, 0x27bd59a3, 0x07c66f94, 0x38eff79d, 0x61f3f6a4, 0xf8d1ee43, + 0x3c05a36b, 0xd0f4b82c, 0xa0e581a7, 0xf183ddf8, 0x63bd4d28, 0xb89588b7, 0x9f488905, 0xeceef135, 0xec396cec, + 0x25aacc3c, 0xe9618cb9, 0x808c6c73, 0xa8f7a73d, 0x0fc43150, 0x558b0118, 0x66edb73f, 0x34d557d1, 0xdd55c804, + 0xe4029329, 0x9520af12, 0x26caf5b6, 0x03b5556c, 0x62383246, 0x6828057c, 0xb38f6d3f, 0xc50856d2, 0x500f0800, + 0xdeda9d72, 0x50661683, 0x277d7c46, 0x6b597e6e, 0xba118278, 0xf793e364, 0x063f5741, 0xdd86174c, 0xd5cc9d21, + 0x44b6a22f, 0x5b8aec80, 0x73def042, 0xb61ee5a6, 0xfbcfd29e, 0xda763309, 0x546c4ba1, 0x3de9fecc, 0x393452f1, + 0xb3fa6638, 0x89e9a857, 0x9b77bea8, 0x9f3f6daa, 0xca443038, 0xc885d451, 0x00ed7abb, 0xea3eb649, 0x70dd809d, + 0x3f4b1401, 0xfc5edb49, 0xa19e9766, 0xfa77ce09, 0x9342fa97, 0x6770adaf, 0x4e4414cb, 0xdcb3726a, 0x0f242f6e, + 0x00647125, 0x5f37316b, 0xd70e7262, 0x3fdb7b87, 0x285764ba, 0x35486849, 0x0e540d09, 0x86de80e2, 0x4c490ec3, + 0xba3af3bd, 0x61123afd, 0x517c7744, 0x7c46244b, 0x98c4a8e9, 0x10bbdc33, 0x62c223ed, 0x71b234b3, 0xbc91a39b, + 0x1ef866fc, 0x7bf5a025, 0x1fb1283a, 0x11bcf2ff, 0x0a9d763f, 0xb6b705c5, 0x477ca792, 0x179771c0, 0xfadee80e, + 0xa30c6f5a, 0x7e220f23, 0xdc7f0b50, 0x4a47cc70, 0xb1c1d65c, 0xe0947648, 0xf0200f5a, 0xfcc95462, 0x42a9fb0e, + 0x78f71737, 0x5cc1a573, 0xa31317ce, 0xf82401fc, 0xe9d1e9d1, 0x7319275a, 0x10f76798, 0xb01e5934, 0x2ef65e6b, + 0x7b2e27c3, 0x335dd246, 0x76461c10, 0xb3bb645e, 0x4037da7d, 0x8622b444, 0x86dad765, 0x75a15f22, 0xb0b1236d, + 0x135fa3d8, 0xc907cee2, 0x8dfa3a99, 0x0c38529f, 0x6721ae50, 0x69145c48, 0x1346156a, 0x2e4469d9, 0xf5fa4382, + 0xe0342532, 0x8ceb4328, 0x90f82f1d, 0x5053fccf, 0xf6f2bdad, 0xacfb5836, 0x52bd62b8, 0x9c4c1da5, 0x0f79b004, + 0x3bc87998, 0x6b4b0517, 0x71356847, 0x9e0444bf, 0xf3784c14, 0xdf1780a1, 0xd0c1489a, 0x469ff2b6, 0xc148e455, + 0xaf6d0b67, 0x5f1d3f37, 0xf94c1d42, 0xaef97da7, 0x5e033767, 0x971f7e1a, 0x35e90cb4, 0x28939129, 0xae85d521, + 0xac04c668, 0x0f9acce2, 0xca5a0f78, 0x29202d80, 0xb123f450, 0x644ac10a, 0x04c54ac4, 0x82eb4172, 0x2c31b228, + 0xdf57853a, 0xe0abd99d, 0xbdae3b2f, 0x5908968e, 0xcb9b4a34, 0x79998e1c, 0x7cd70138, 0xd797f35f, 0x167a5e87, + 0x1ab26498, 0xae84c26d, 0x37ba422c, 0x2132a6e5, 0xe123b19f, 0x7479e625, 0xc8d13961, 0xa19a7c65, 0x5ba087d4, + 0x6e26eb79, 0x21220412, 0xffe1f615, 0x84c4c1e9, 0xc67f80c8, 0x22d1aab8, 0x9de6aecc, 0x182e3d9b, 0xb649923b, + 0x09fc0c35, 0x4ed2d8c1, 0x1cd5b848, 0xaf1fc2fc, 0x198cfb39, 0x3608197d, 0x33dadb96, 0x7ff84d9f, 0xe6174436, + 0x739c538b, 0x6bc341f4, 0x25fa0237, 0xb037b620, 0x5e06266d, 0xc8ca3d91, 0x8a272569, 0xa5519b17, 0x7e183ef6, + 0xe0d28f1e, 0xb9cd68d2, 0xf58057f0, 0x9f9deeab, 0x0535f6b4, 0xb26e8ba6, 0x7d586fcc, 0xe10b72a0, 0xb2de489b, + 0x8c48ca4f, 0xd2a49dde, 0x6048dd6a, 0xfb9ebd71, 0x646ea7d2, 0x9a81cbd2, 0x72991708, 0xc664f2de, 0x9970e546, + 0x086c787a, 0xbe870ab4, 0xee698f3f, 0xd17534df, 0xa4f69446, 0x4c215104, 0xa88c00a2, 0x49b4896b, 0xb1c790a4, + 0x46527716, 0xaf6a57c7, 0x47415d6f, 0xb492c0c8, 0x9f18b979, 0xa72643dd, 0xba7f0d30, 0x0b1dc8f8, 0xcf4fb8e7, + 0x1430b45a, 0xfc8dbd02, 0xf6bc2127, 0x1431e73e, 0x28721695, 0xfeaf16a5, 0xfbbf19a5, 0xddb0a40b, 0xbcea5169, + 0xf1961cd6, 0xd828c77e, 0xf820042e, 0x0cdc1a8f, 0x61127040, 0xb3f99178, 0xf1479104, 0xdb1fc5b1, 0x01e5560d, + 0xfeecc29d, 0x7c29ccdd, 0x9339b36c, 0x2cc30167, 0x4c3fb78d, 0xf2bc30f6, 0x54d3196e, 0x151f1c77, 0x9fcb43e3, + 0xb8ab96f7, 0xcb8e7131, 0x1e8a3f04, 0x9197c74b, 0xf25beff5, 0x683a6349, 0xc2594ca1, 0x0574ebd7, 0x84e2686a, + 0x69bbf912, 0x8f399424, 0x431c42e0, 0x1a2c4799, 0xb9374531, 0x1505f7be, 0xb58aafc8, 0x802edc77, 0x11423fcd, + 0xc512fecf, 0x5dadd74b, 0xd12ec4ae, 0x5420c452, 0x82429401, 0x5e1974c3, 0x4e5b8421, 0xfba02651, 0x97f50c30, + 0x2237a24d, 0x19839f01, 0xec20ccf4, 0xf4995c52, 0x6e9a7eab, 0x65411eba, 0x8b6ee126, 0x6039862d, 0xaee25ba2, + 0x11498aff, 0x4d8e1d2f, 0x9cb377cf, 0x605c4474, 0xbd19d535, 0x9a8f1fbf, 0xb8d73ee2, 0x24346d73, 0x2208a010, + 0x6f4bf472, 0x24fa186b, 0xce999cea, 0xc749da3b, 0x44bd7813, 0xd01ac8c4, 0xefd06653, 0xb815d1b8, 0x46c14b3f, + 0xb56e4d31, 0x9ebea37e, 0xf8c21042, 0xb9947e21, 0xaeba747a, 0x607b4d2b, 0x3cdbc3e3, 0x0f460c27, 0xff36c0fa, + 0x0ceaaeb7, 0x79fe45df, 0x362661aa, 0xc12228c6, 0xf24cdc5b, 0x268c04ee, 0x3443fca2, 0xd1f78e97, 0x927de8de, + 0x5d420abc, 0x05d4663e, 0xdc0386a8, 0x962844a5, 0x60b70af2, 0x31dfc8f7, 0x9d91167b, 0x01935230, 0x1c95e9bd, + 0x60462920, 0x97c32c06, 0x9154aaeb, 0x9060de6f, 0xafec0816, 0xd504d6b3, 0x080c6872, 0xfdc3929b, 0xbb665638, + 0xec2ff622, 0x24b0ec8f, 0x1c3d812d, 0x6d26e5fb, 0xcd6515bd, 0x8b83bec1, 0xce6c028c, 0x17556fd0, 0x341eb8d1, + 0x0e03303b, 0xb0d43431, 0x6e61db9c, 0x47a95481, 0xf2d137b9, 0x59e12c29, 0x73143c56, 0x0cb7b641, 0xec87de98, + 0xf5b34fb9, 0xd3d88aca, 0x396dd5ab, 0x73e2cc31, 0xb932718a, 0x1f3b0e8b, 0xef1ae11f, 0x611b5880, 0x56d4382e, + 0x6a8d261c, 0x4685bd6b, 0x43369153, 0x29f60cb6, 0x42f21e34, 0xe1794310, 0x28273aff, 0xf4c23038, 0x7313a59f, + 0x3bb695f6, 0x4a62df13, 0xe19ee8c6, 0x9f1704b5, 0x7cd507a1, 0x44f89bde, 0x43f1b753, 0xae5dbdec, 0x15f26e52, + 0xf17f9835, 0xe59b85db, 0x511251da, 0x4405da78, 0xe2ffc1e5, 0xf3f4c23c, 0xebcaa6c3, 0x5e24f25a, 0x4102a23c, + 0xa57345ad, 0xefae1c63, 0xc88935b4, 0xf7e45f1b, 0x90dc3063, 0x499b7b57, 0x64aa071e, 0x0f4e3c20, 0x803c29f5, + 0x76fbfd86, 0x315ca414, 0x1d0c5696, 0x631d2246, 0xb9ae3e48, 0xd1dad8c3, 0x15d77ba6, 0xecbf7deb, 0x127f3f2e, + 0xb27d30f4, 0x5f2c1483, 0x1a3bb89e, 0xb574bac1, 0x438fd00f, 0x18ad413e, 0x3a674345, 0x00a84d9a, 0xa3648b16, + 0xad68c8c0, 0x5a5d6a11, 0x173d17eb, 0x463843fc, 0xb49163e7, 0x14bb28c2, 0xce6152bb, 0x8cacc019, 0x73dad486, + 0x97315239, 0xb46685cf, 0x9bfb309e, 0xbf201832, 0xccba9cbd, 0x2d64a969, 0x509c64df, 0xcc3e9a4a, 0xdb7b993a, + 0x1466e7fd, 0xa2e8c8bc, 0x57473313, 0xb21b9410, 0x6479e4cf, 0xc7770b3e, 0x25a97c23, 0xe1c74ac9, 0xaea66d39, + 0xf27c0328, 0xbe19a815, 0x97de8faf, 0xf3a72c50, 0x45d65af6, 0x06af8ef9, 0x4f61ea38, 0x0fc3a314, 0xccef3e8f, + 0xcb6c5c83, 0xf7407021, 0x60af5393, 0xf7762153, 0xef4f24e6, 0x7866677f, 0x66de684a, 0x34a6e93f, 0x94fda720, + 0x5b8c4d63, 0xae82e96b, 0x6528c5e0, 0xd58445df, 0x383c7442, 0xbb1dc72c, 0x44a2e3dc, 0xa0116134, 0x52a4dddf, + 0xd7a36d10, 0x7dc10106, 0x863bb492, 0x62b5c9e9, 0x8ceabdc6, 0x25aae9c5, 0x276ed240, 0x38452b1a, 0x010af6c9, + 0x8e87d209, 0x85ff6dd9, 0x7b7b2bb2, 0xd5d23de3, 0x1155b112, 0x00a8680f, 0x0dd0feaf, 0x772af57c, 0xdce727c0, + 0x3b6e80c8, 0x7ca31393, 0xa9922621, 0xfdf0935b, 0xfbcd43d4, 0xac34ddbb, 0xa6658ed0, 0x8d29002c, 0x22b36b74, + 0xf4e51c73, 0x969a86cd, 0xfdfc3e5b, 0xe52dca7d, 0x50885aea, 0x79a254f0, 0xc331aadc, 0x252d5945, 0x96dab1e1, + 0x8bdc5e66, 0x4c3a3161, 0x568743b0, 0xa406c3fd, 0xfc82655c, 0xd5ca3c15, 0xd8e6f1df, 0xa6a0a274, 0x3d49044f, + 0xaff5cc8d, 0xcd683236, 0x5364ffb6, 0x0b5b2ed3, 0x4fbc0dac, 0x812edef9, 0xb0c17361, 0x5c7aeb09, 0xe0971e85, + 0x6134fbaa, 0x253cbe50, 0x5bbfa66e, 0xa77666dc, 0x2b687ad3, 0x7dfa8581, 0x46e03ec0, 0x5b78463b, 0x7f26018b, + 0xfff5cafe, 0x6234c759, 0x9e3a4cf0, 0x58dbb9e3, 0xd83f841f, 0xf0739ac8, 0x9d914091, 0x82e396b5, 0xf351daba, + 0x9a3f2631, 0x1b62b1db, 0xed688134, 0xefa65eff, 0xe8d6a996, 0xccbc7f1e, 0x1a7e0662, 0xf52a12ae, 0xc2d99a7e, + 0x5f2a644a, 0x879ff980, 0x60c24e01, 0x6cd86343, 0xa3e11543, 0x277c0312, 0xd39a343f, 0x22bb79ca, 0xc5f53bea, + 0x81aa3c47, 0x2299f1da, 0x19fc54dd, 0x834a6ae6, 0xffe9793e, 0x6a35e9c1, 0xdd0a5a07, 0x4d75cf2e, 0xfc23c016, + 0x4c0d569b, 0xb2c5c5b8, 0xbbaa1a93, 0x17dcab4e, 0x25fb7f51, 0x21da8a44, 0x96a9e9f4, 0x41c5bbbf, 0x84dd5e25, + 0x7eaacc87, 0x98c0bb56, 0x647b69f9, 0x5536ee36, 0xa178d806, 0xaff90a46, 0x675a81a7, 0xa3441447, 0x1fe7a0f3, + 0x83061454, 0x2e12c50a, 0x8ba1b720, 0xf24ed967, 0xc7737396, 0x06dd2b51, 0xa1554b4c, 0xd22fb261, 0x7f2b0e38, + 0x1e609a81, 0x40d9e183, 0x06c479fc, 0xe58a4095, 0xbb51af79, 0x7635a29b, 0x431a600e, 0xee945c57, 0x57240319, + 0x818e94e8, 0x82d14d96, 0xd264ecdd, 0x2866b27f, 0x484bdbe8, 0xcca0492b, 0x683c3a97, 0xf0e8bf43, 0x43c0cb86, + 0x94c4844a, 0xb8fbbce2, 0xae16fdec, 0xc31d6a18, 0x147c5e60, 0xf1f540a3, 0x009a21b4, 0x35b561db, 0xc7e7da5e, + 0x68050b3c, 0x5c5c781a, 0x7526d547, 0xfaadf6e3, 0xd875ea67, 0x32ef36b2, 0x3415a833, 0xd8bfb917, 0x77de0a86, + 0x1ef09b5d, 0xfc30d5bf, 0x35f3c8ec, 0xd58310fe, 0x68dab9be, 0xea99a0b2, 0x9e069dbf, 0x43d422ed, 0x33f24235, + 0xc0e5d205, 0x8cac2d9a, 0x1175dc8e, 0x969aac2d, 0x174e83f3, 0xbb2fd4c9, 0x63d53266, 0x7e577be3, 0x1abb6627, + 0x6cc41905, 0x72bfcf7c, 0x1f5283a2, 0x9ad4dc9a, 0x84f526e7, 0xea56a2cd, 0x43a00d95, 0x9bf64a67, 0xe1747701, + 0x1487cc84, 0x5b5580c6, 0x39718709, 0x8121d326, 0x2fefeffd, 0x54413ac8, 0xb63d822c, 0x098680df, 0x0edcda89, + 0x10d05b10, 0x7a6f7a8a, 0x07c3ab53, 0x3841cf5b, 0xaaefa2eb, 0x966f47c6, 0x841ba0e0, 0xe032eb79, 0xaa1fdd64, + 0x0340a78b, 0x4339c6e6, 0x4d653639, 0xa663f46d, 0xce46d537, 0xaa1579e1, 0x92b0311c, 0xb698692f, 0x5ec687ce, + 0x1576b442, 0xf5692820, 0x1dfebdb9, 0x60d3376c, 0xbae371da, 0x66903670, 0xf4ed13ae, 0xe073b53b, 0xbe1c6fbf, + 0xa1369d3f, 0xab01fc09, 0x9a1977c2, 0xf2f58f9e, 0x953f884c, 0x9e4ae454, 0xe6ab16c8, 0x0ae0fa20, 0xae309b89, + 0xa50df54b, 0xddc72cfd, 0xafcebcaa, 0x71069391, 0x7e251d88, 0x2fd137d5, 0xe2801de3, 0x30099619, 0x5a4d4342, + 0x8cf94a5c, 0x5682ef3d, 0x16109344, 0xc1782593, 0x86d0c6d5, 0xa57e0e59, 0x0a10ebcd, 0xe42356ed, 0x5aac3191, + 0xe783cf5c, 0xb074d71b, 0xb6ab5a13, 0x736bb64d, 0xf223d3cf, 0xa2789705, 0x02fc7037, 0x9f9d7566, 0x1b632ee7, + 0x528dc8b9, 0x5e5c5b04, 0x18c4bb71, 0x0cb8afd6, 0xb1dde22a, 0x4a086733, 0x4fd46905, 0xe480c3e5, 0xd7a74318, + 0x4ee8545c, 0xd2ee8e69, 0x79ac0634, 0xe1e527f2, 0x75973a76, 0x8789036d, 0x424d785d, 0xd2c8550a, 0x0716053c, + 0x3ffb96ab, 0x4a940e34, 0x3e711f64, 0xe70f3488, 0xf8e2eb02, 0x7c347815, 0x86e0741a, 0xd1aa75d3, 0xb340623d, + 0xfea1eb75, 0x7527ec3d, 0x29d67540, 0xf8ab5193, 0x40d327b3, 0x937d7b67, 0x51273107, 0x80079fb7, 0x773363e8, + 0x11ec4d41, 0x30194255, 0xba16b819, 0x515502ab, 0x592f32bb, 0x787487fc, 0x0382fd27, 0xd15b642e, 0x58e8bc3a, + 0x1312e1de, 0x2167e45b, 0xbe62780b, 0xa785af99, 0x27f121ad, 0x9e9dc0a6, 0x9257c466, 0x408cff2e, 0xa3ed2d23, + 0xfda0a5a7, 0xef116a36, 0x2384e3d5, 0x7242d4cf, 0x32786917, 0xb8492d5e, 0xb246a00a, 0xc63cf2ed, 0xd61f6c88, + 0x2eb394d3, 0x3760dc86, 0x1478f744, 0x43ef345d, 0x7a8c71b7, 0xd52775d6, 0x47292691, 0x3727ede0, 0xc0a4de1d, + 0x855af482, 0xcb30e9af, 0xb6a3b2dd, 0x57d03745, 0xac4b36b2, 0x06536164, 0x8f508990, 0x7e845067, 0xf8897dfd, + 0xc6e77bc1, 0x2dde1eba, 0xe32cbdee, 0x085b556c, 0x89cfe7d5, 0xb64821c6, 0xecf6f390, 0x08cd6682, 0xadfb1b78, + 0x8225af35, 0x5151e101, 0x954f6679, 0xf6895698, 0x2f12c8c3, 0x836f00c8, 0x89e02b42, 0xd0156f99, 0x14f87e20, + 0xf68d9dd7, 0xc42b3022, 0x4cfc2efc, 0xdc97b093, 0xb4fb1a77, 0xa2736ef5, 0x15796530, 0xba1161d1, 0xaf69bf75, + 0x7bf6255d, 0x22bc136f, 0x77078012, 0x5b7cd482, 0x016c047a, 0xdd217716, 0xa2e4c121, 0xdd6225a8, 0x9470cc4d, + 0x6edcf117, 0xaea93449, 0xad4721c1, 0xcca2f713, 0x449e4a59, 0x5f3e265b, 0xc6262fda, 0x729eeb8a, 0x0c9bfe03, + 0xd80a844e, 0x6f8c1cb9, 0xa9b050c0, 0x522912ce, 0x3246449a, 0xe317824d, 0xfaccec39, 0x344c976c, 0x760c9a2a, + 0xbf2cff57, 0x5a69a3d0, 0xad9dd09a, 0xaadc7a8d, 0xfbefc818, 0xd90c4ddb, 0x73637106, 0x5dff166a, 0x7fc0347d, + 0x115e9f7b, 0xa38691c5, 0xa52addf5, 0xce8ca9d7, 0xd95ea778, 0xb0ba4734, 0x03902a0f, 0x3f1e2477, 0x950588eb, + 0x0fbbf1e2, 0x8cbc0233, 0x2c775418, 0x0e46cd0f, 0x5d8babf9, 0x997e80e6, 0x89119e92, 0xeef84476, 0x20ec93e0, + 0xd2b52a74, 0xbb6b0e3a, 0x0c8848c1, 0x91ed12df, 0xf5c5335e, 0x963eb5da, 0x0809bdd0, 0x8f0a2bdd, 0x363850f7, + 0x4cf1fb71, 0x0c968ddc, 0x8592dd77, 0xf3a52cc6, 0x646931b9, 0xe3f61fa4, 0x7775cebc, 0x0f13f50f, 0xa267aad6, + 0xadf8c89f, 0xf9d9b9ce, 0x44850547, 0xab214844, 0xc2f03ab8, 0x8cd2931e, 0x220e96fc, 0x6a2dc9e4, 0xd0974786, + 0x1496bd86, 0xdc5b58ad, 0x017dea2b, 0x4000bb93, 0xcfac1d01, 0x22d40ef8, 0x5b6c165f, 0xa9ce4e4b, 0x2aae25aa, + 0x0b71aa9d, 0xedb846c0, 0x38fa646e, 0xbd9743ae, 0x08e37f17, 0x21a0f63f, 0x6577ce62, 0xf996d131, 0x2af242f5, + 0xd3b062f6, 0x2d138a1a, 0x034ec88a, 0x809f6258, 0xa99d8bc0, 0x54c64df7, 0x385411f5, 0xad6fea86, 0x95e96d39, + 0x562ba915, 0xf01fab61, 0xbd3b630c, 0x494e100b, 0x2bcad278, 0x2ef10999, 0xf5300149, 0xbca8474d, 0x0a0422c0, + 0x73c2412d, 0x9e3eee1a, 0x20a8376b, 0xa6384a6d, 0xf3941d9b, 0x4c9fa48f, 0x22a8a14c, 0xad6bd389, 0x5b6c04fa, + 0x46289ac3, 0x4083a922, 0xa68cd399, 0x84f215bb, 0x96b578e8, 0x11021ca3, 0x31f8d3e3, 0xa0872613, 0x4a940be1, + 0x52004db0, 0x13c2e038, 0x6ea8eca5, 0x14994a32, 0x83bdca49, 0x002e45c6, 0xdb21bda9, 0x363b3895, 0xa5e1a3ad, + 0x75ac8b47, 0x57fd3334, 0xdf2db7fa, 0x510f996a, 0xdca6667a, 0x9b49e333, 0xa77f5847, 0xcd4f11b3, 0xf6af70fe, + 0x3af4acef, 0x5d41781f, 0x5c42080e, 0xe7ec6659, 0x9f0cabd5, 0x60fbbc64, 0xb9378e2e, 0x3e9b1bd2, 0xfc6e5a64, + 0x75a8ff74, 0xa494827a, 0xb22a8301, 0x7300949c, 0x49e412e2, 0x0c227197, 0x01f998a8, 0x40530aaa, 0xd90f2626, + 0x6f116d20, 0x13eb2619, 0x433f23d9, 0x76b1c500, 0xaee14839, 0x9933df71, 0x556521ec, 0x318a9393, 0x4293c079, + 0x922b3c6b, 0xdee28ca6, 0x4798a496, 0x158f9ac2, 0x1b77ad88, 0x71dfb224, 0x152e14a7, 0xaaa00c54, 0xa6da2dd4, + 0xab5e77dc, 0x560e5a7a, 0x1343708c, 0xc99ceaf7, 0xfdab16f5, 0x50e784ad, 0x09535d95, 0x742b5eac, 0x6f957481, + 0x5ecae8f5, 0x952c3aee, 0xbc5bb627, 0xc565a809, 0xe8324e57, 0x86a4fed0, 0x561e5edc, 0xe157a526, 0x73dbc609, + 0xa6e2227b, 0x9377efcf, 0xa9cc1df0, 0xbac01feb, 0x6128b57b, 0x64ef3be2, 0x54d91e74, 0x0494b597, 0xb5866d01, + 0xd0567320, 0xf536fb52, 0xa77c63d8, 0x8fc404bb, 0x52165d70, 0x7599a90c, 0x975381b0, 0xcf6b4a9d, 0xf4931c9f, + 0xf9c1d784, 0x598eb096, 0xb2a3fd15, 0x26631df5, 0x5fe347c1, 0x1f5e28fc, 0x23d1ed49, 0x9b0c038c, 0xed080fc7, + 0x4e5c6e9e, 0xbeeddf7f, 0x4b5755b8, 0x4fd9445f, 0xab2d1b7e, 0xd85229bb, 0x5affd56b, 0xecdb6d04, 0xf7f2b020, + 0x17f9e929, 0x8bc305f9, 0x7a4b3133, 0x6ec25d1c, 0x46e4092a, 0xa0448b52, 0x47443185, 0x757cdd29, 0x6403689d, + 0x4ad6aff5, 0x90633f8d, 0xa0ff7642, 0xc365cf1f, 0xf4d98b7f, 0x4fee0483, 0x32df70c0, 0xfa4d8444, 0x6093ab90, + 0x8d4e9d30, 0x28064862, 0x51ca115b, 0x86cc07e0, 0x12b5d8fd, 0x567a1764, 0xe074ad81, 0xbe7311bd, 0xc4dd8654, + 0x8a48d07c, 0x87ce1849, 0xb188be75, 0x1b212992, 0x8018696a, 0x1b6ddfce, 0x4634cacb, 0x8e1da1f8, 0xbd2eb1cd, + 0xb4c8865d, 0xa82921ea, 0x2f3593c7, 0x276403a5, 0x6ca4e39a, 0x07ef442e, 0xe3921e20, 0x52dd6878, 0xd4bc2d37, + 0x5cf26cbd, 0x65deca30, 0x301c5c25, 0x6ec88554, 0x7d1bce5e, 0xbe3e6319, 0xf4f0de8a, 0x57e77105, 0xfe5f8b1f, + 0x919953c5, 0xc916d529, 0xe9fff87a, 0xdd130fff, 0x5402ed8f, 0xa3a00a44, 0xdd4f1386, 0xcc99256f, 0x13a74c71, + 0xf1357a1c, 0x9e75eaf7, 0x298c732a, 0x52975a10, 0x94eb78e0, 0x4c9bc3ec, 0x20d921b6, 0x23231334, 0xd26daead, + 0x55368cc9, 0x3b32b060, 0x346e3e80, 0x7f9ac88a, 0xca93aa91, 0x64f7f648, 0xc116fb5c, 0x032e8816, 0xc9c320e4, + 0x4f6db762, 0x1d874481, 0x795cc575, 0x04ac3690, 0x72e8ba48, 0x8df40318, 0x22903a60, 0x6899c4e6, 0xb499314c, + 0xa834d0c2, 0xff2a72e1, 0xdbd830dc, 0x9aba67a5, 0xa679e9c9, 0xddec760a, 0xd0a23e2e, 0x7815dbf7, 0xc4ca1f39, + 0xba823fb3, 0x857a7fde, 0x04669c3d, 0x88d33168, 0xcfa8a283, 0x27b01b11, 0xfeb68bbf, 0x381b462c, 0x2271bc66, + 0x41803dbc, 0x6def22f0, 0x52929520, 0x435d2465, 0x3cf4c02d, 0xb8f280b8, 0x021210a4, 0xdb78c574, 0x312dea47, + 0xb70a4936, 0x6060d859, 0xa39a1935, 0x096c961e, 0x11b0996f, 0xecc1f259, 0x95c960ad, 0x526d0004, 0xd6132b67, + 0x3d737389, 0x58afc8f6, 0xc63fe8da, 0x45fe762d, 0x82d0047b, 0xb4bb5242, 0x146de95f, 0x80161f82, 0xe3487cfe, + 0xc3e44923, 0xff077377, 0x9bc3d792, 0x8edd6cb1, 0x81d84193, 0xc57b8819, 0xccc25e1a, 0x907ab3f1, 0x6c7ede52, + 0x2f724665, 0xd1b5aba1, 0xc2857ff7, 0x2d028ab6, 0xbcaa8b72, 0xf102d4d3, 0xb8b0d1f3, 0x2fa84444, 0x14633b34, + 0xb075fd26, 0x67c6d73e, 0xc0f01be5, 0x13a74b61, 0xe3a73f70, 0x1b5115a1, 0xf5c11e4f, 0x46280d0d, 0x480643f8, + 0x0a1d5b8b, 0xab85007e, 0x1443665d, 0x0d70f7f2, 0x16e63048, 0xf6ecb495, 0x8e321c89, 0xb4750c03, 0xb07f5e51, + 0xd719f0d1, 0x37fccf2a, 0xf88728da, 0xdc4722b9, 0x460c4612, 0xdc62b09c, 0x1c9f8999, 0x02ec0699, 0xa4f7dc1c, + 0x375f0719, 0x61b4aa65, 0x95b8c38c, 0x1761ef23, 0xc0133699, 0x8ff48a2b, 0xaf63bc28, 0x96b23294, 0xe66ffec0, + 0xc976fbad, 0x9b322af1, 0xdf4921ab, 0xb7dc21ef, 0xce5ca821, 0xf51bc345, 0x5beec317, 0x523682d3, 0x1520dbde, + 0x9da5d1f5, 0x6ee81b0b, 0x4e0e8a7e, 0x52e3fd2a, 0xb5dcda7e, 0x3fde8f4a, 0x3f3447ac, 0x9f262286, 0x78465ab6, + 0xcc69b38c, 0x5abb8422, 0x56beb03d, 0x7fb0f2c4, 0xda7de5bf, 0x5a6f2642, 0xf3d8ff0d, 0xb43cbcb1, 0x725f5416, + 0x53a63756, 0xe8bb4465, 0xbe76a823, 0x08ab581b, 0x47f2cfcd, 0xc38588b1, 0x589d8681, 0xfbf39ce8, 0xdbf315d6, + 0xb9495c39, 0x9289bad1, 0xf2858e07, 0xa0844704, 0x77652596, 0x064f306f, 0x001399e9, 0x7fe346a2, 0x476c20fa, + 0xc56c062d, 0x1cd6edd3, 0xe3e3a0ce, 0xa995254d, 0xd7bf9e2e, 0x0727e937, 0x9c340a74, 0x226a4351, 0x4168627d, + 0x7009b5cd, 0xb5dabf4d, 0xe78789ba, 0xb1b666c3, 0x569e6a5c, 0x59adc65a, 0x26d128ee, 0x0bb8a354, 0x0acef439, + 0x440129f8, 0xfdb8d243, 0x14008bb4, 0x09edd9df, 0x07da619f, 0xafbef01f, 0x2f4999c9, 0x25645087, 0x6d16efb8, + 0x879a3312, 0x37d50bcc, 0xda26b85b, 0x81f9f5aa, 0xe73ae9bb, 0xd3552c21, 0xbbe20909, 0xcc6e1aa2, 0x1e873435, + 0x39ce32f5, 0x64b0bad0, 0x21df083e, 0xb4c18e8d, 0xb8e74803, 0xe9ab03e9, 0x32816460, 0x829b94c2, 0x79865ce2, + 0x84cdc795, 0xe8247c15, 0xcc51c97d, 0x962456d6, 0x73306fdd, 0x77b3f897, 0x9709d526, 0xf1c40f6f, 0x4a65e02b, + 0xf1bf06e0, 0x71d65d68, 0x884a5ac9, 0x5abaa6c8, 0x3f4a99f2, 0xf6c93cca, 0xb13a7132, 0x21061bb5, 0xe01c97ab, + 0xa8af5a23, 0xc790a465, 0x544f7899, 0x9b388794, 0xa087e608, 0x618f5068, 0xf1d52a01, 0x5c0fabbd, 0xdab3077b, + 0x9d5130ff, 0x518cdd38, 0xc13626d5, 0x8c81415e, 0xf1776512, 0xd0b803d1, 0x194d9694, 0x233bea74, 0x2ff384b3, + 0x42ead152, 0x14740662, 0x819488b7, 0x0beace8a, 0x27060beb, 0xe5814ec9, 0x8641f0b9, 0x40970cbb, 0xf584dcf3, + 0x93c4a803, 0xa7d01874, 0xbea30248, 0x75ffcfb3, 0x45e250a5, 0xd6bd3268, 0xd8ede7b3, 0xc355faeb, 0x6f9b72ec, + 0xb1febb20, 0xdf5d14e7, 0xc3aa6068, 0xc03277c7, 0x32bf123a, 0x9ce01da0, 0x07da6cba, 0x894332bf, 0x7b29bbb4, + 0xc71fa924, 0x1d6c5b91, 0x2cdec4be, 0x13fa896c, 0x701e3313, 0x0f42da72, 0x91e9a02a, 0xea0d97a5, 0xaf57a239, + 0xc5515f5b, 0xbceec30b, 0x6143d332, 0xd61af224, 0x23a2208b, 0x37d6b1bb, 0xb04ce9f8, 0x03ad0580, 0x0aadc7a7, + 0xc7a93250, 0xb7f7ce16, 0xd11b9218, 0x42c112d4, 0x986a223b, 0x469f785d, 0xaf4f1c39, 0xfae9b7fa, 0xc5cb4bcc, + 0x8cba7120, 0x9ea08c90, 0xfcc58ac6, 0xf123fc5d, 0xd543a953, 0x3f55d723, 0x365eb448, 0x26e93475, 0xe5734dc4, + 0x5acb7f35, 0x7a023642, 0x86dde3e2, 0x0ab849b9, 0x813ed4ae, 0x9acea124, 0x29260eec, 0x54c18da0, 0x86f74141, + 0x83e40e67, 0x31afba39, 0xc9f72e79, 0x9b9bcb7e, 0xd75a936a, 0x8e8f2a3e, 0x55951070, 0xce1f7d00, 0x79c216fc, + 0x4821524f, 0x2a1a86a1, 0xcb289b5b, 0x8fde92ff, 0xfeb81510, 0xcf1d2ff7, 0xb54e7bf9, 0x91f74a40, 0xd41c3637, + 0x240f2909, 0xc1ef720e, 0x18ebc5b4, 0x9d33200b, 0x318f0065, 0x723ccb3f, 0x73b51370, 0x9f960548, 0x371d2542, + 0x1773358c, 0x49f9aec6, 0xfa3cf95d, 0xaaafb4c9, 0x58d33e30, 0x6382a596, 0x2bf5302a, 0x748b37cb, 0xa1ecbae3, + 0x18a0b0fb, 0x92f96e1d, 0x2393bbaf, 0x4596316e, 0xbf015466, 0xba002f0c, 0xd5b97a15, 0xa4754df7, 0xdbd2d891, + 0xc0f24f8c, 0x0c775d8d, 0x990aaa39, 0x1c34a1aa, 0x80514c6b, 0xee8c992b, 0x8a7b135d, 0x10d7c8e9, 0xccf49829, + 0x93b220ba, 0x03a733da, 0xe5241842, 0xb5ad5764, 0x485bbaad, 0x6c05fa71, 0xecbde066, 0x96eec653, 0x9ad1b00b, + 0x4be3cb45, 0x511b8184, 0x3f8bc4f9, 0x7448264b, 0x5e266452, 0xcbf18067, 0xcab5b1c7, 0x0f9e3653, 0x5aa32e49, + 0xb3f73d04, 0x798e9d24, 0x6d315307, 0x27632025, 0x3289df93, 0x37873596, 0xc5465e80, 0xb5b0a77e, 0xb70cace9, + 0x9ed65d57, 0x7591f0b4, 0x6dd19b50, 0x420b728c, 0x47a85f2f, 0x86f5f57f, 0xea2def91, 0x5abb33ac, 0x669ffe33, + 0xbff04c8e, 0x769f3e96, 0xc8cb0f76, 0x5f936791, 0x3f42d91e, 0x1068658c, 0x0a44934b, 0x0216a825, 0x73012277, + 0x4d31c68b, 0xa6b2c8a5, 0xc0b12a9e, 0x7ed1bacb, 0x0f9f1db4, 0xcdc9c937, 0x40051d14, 0xd6caad41, 0xceac5e99, + 0xe8e5785f, 0x14d7be59, 0x8525ce78, 0x84de1865, 0x28e1d826, 0xcebe37bf, 0xc1e9c0b6, 0xb87809ff, 0x2c996c2c, + 0xee00cecb, 0x2a894a93, 0xb1c7fff6, 0x48477994, 0x28306eff, 0xac095254, 0x0f83deee, 0x4b2522ad, 0xed4f92c9, + 0x68c7e727, 0x4240b956, 0x2038f7c1, 0xbcdc7b0b, 0xe46e3fba, 0x2c04a360, 0x97cf3805, 0xc3d349c4, 0xe9d6e0cb, + 0x40b2c1af, 0x3e6e48af, 0x2f6d55df, 0xf28a6f9c, 0x528d8cd0, 0x84602d80, 0xb4537a5c, 0x1a2fe628, 0xaf6de12a, + 0xbb43d85b, 0xd760334b, 0x02eba9b2, 0xac973462, 0x52c5e381, 0x79015878, 0x8daca64c, 0xeab79c6b, 0x6552e075, + 0x4f0c2263, 0x91e095fc, 0x53ce6b27, 0x5e45951c, 0xf1b7992b, 0xcaf9088c, 0x8ceae481, 0x1b6189a8, 0xf24f235c, + 0xac568af4, 0x1cd81ff5, 0x4c9e6399, 0x580297f3, 0x02107241, 0x2c5bbe8d, 0x28e3a026, 0x4df96ae2, 0xff751ef7, + 0x450f0791, 0x1e6aa29f, 0x4950ad44, 0x75f0ebe2, 0xe6ae4a43, 0x688932bb, 0xc61ac0d1, 0xc3da3c24, 0xb4771a26, + 0x1e96990f, 0x60c81acb, 0x163488ff, 0x94523cb7, 0x534b5ecc, 0xee9fe47a, 0x322c4429, 0x0cb59a87, 0xe077dd1a, + 0xeb37cf8f, 0xa5264eda, 0x3d515461, 0xfb1409cf, 0x61142205, 0x79ea081e, 0x26978a86, 0x33f1908d, 0xc5519070, + 0xd4a10163, 0x0faa24a1, 0x64decf5e, 0xec067ccf, 0xddd7c67b, 0x45824591, 0x41c23e65, 0xc866ba80, 0x11781418, + 0xb3c7cc7d, 0x61b82dc2, 0x0bd365c5, 0x62565773, 0xb6e40d1f, 0x896eddc9, 0x34bb2dd1, 0x1be5aa1d, 0xec4cef2b, + 0xba90d586, 0xd009a8f4, 0x6a10f120, 0x09014132, 0xa4712ef4, 0x53af472e, 0x894f30c5, 0x9224e6f9, 0xcbf09588, + 0x01ac1b70, 0x297d4c36, 0x9dc75d9a, 0xb5968f57, 0x4f45a543, 0x19ffcd3f, 0x266a36f3, 0xcd9f500b, 0xfb81ef9c, + 0xdf2fc464, 0xdd4f0862, 0x2e80c846, 0x3a2e5994, 0xf679b44a, 0x97ec05ba, 0xb12c6456, 0xc4fefa0e, 0x506f958f, + 0xaa481e6e, 0x2506a5b3, 0x84734f77, 0xaa3bb1aa, 0x2355b433, 0xc23f4b4a, 0xb138889d, 0x4231403d, 0xde7769f8, + 0xeeae53c8, 0xbeb4163f, 0x4347cbc8, 0x22d11399, 0x2b560932, 0x2188be64, 0xf46569f0, 0xd303cb29, 0xd17d0be5, + 0xe52c7e43, 0x46bbf48c, 0xe0020965, 0xab46eb10, 0x64f1c024, 0x79a8a23f, 0x1afcfc36, 0x193cfffe, 0xa4bacead, + 0xc8619504, 0xa16b57cb, 0x46e6709d, 0x5a053291, 0x34311ca3, 0xacaeba63, 0x70268e30, 0x3012f723, 0x436bf7b7, + 0xdad8415c, 0x9522d3c8, 0x9f749856, 0xcc37b1ea, 0xbb7f91b8, 0xe55b8ead, 0x2fda3b83, 0x1fc31453, 0x153414a8, + 0xdcfb4db9, 0x349ab563, 0x3f6c98e4, 0x09cd04b3, 0x631fb649, 0x7140dfa0, 0x020a73e9, 0xd3ac992e, 0x75dbf1ab, + 0x82d1707d, 0x7957adda, 0x0036cdca, 0x7522dab0, 0x689916e9, 0xc9813c10, 0x80cc0ef9, 0xb2d3acf1, 0x2c2f13af, + 0x959ea93f, 0x18510db4, 0x832a1449, 0x9b07a061, 0x7331d2ac, 0x57755f60, 0xddfb7809, 0x9635387f, 0x265c6663, + 0xc747bcc9, 0xc10e33b0, 0x8d7ce476, 0xff1a8b6e, 0x8a33f296, 0x1f5c8199, 0x51b649c3, 0x3f20f9f8, 0xd311a86d, + 0x115bb76a, 0x514e2159, 0xc2c93019, 0xf37431a5, 0x95e1043f, 0xc1e5f3cf, 0xe7c7953b, 0x4abf8c64, 0xbefbe7d5, + 0x21f6fb29, 0x47944da0, 0x51d3a100, 0x1900c626, 0xc204becb, 0xbf2eb5a1, 0x6e728152, 0x23a975f6, 0x8eb9c5db, + 0x2bd0c038, 0x939d1e40, 0x74dc4ef1, 0x8ea4bccf, 0xb7194e35, 0xc2d97173, 0x8171fad6, 0x0998d13b, 0x5a2884ca, + 0x655b916e, 0x7fb3ec35, 0xe6b4ccd0, 0xbac9570d, 0x1823923d, 0x9f8c7433, 0x3accc097, 0x8b3a0111, 0x203769a8, + 0x4cd610ed, 0x2919f8ff, 0x97837acc, 0x89ba61c2, 0x72dc2aaf, 0x3fbfa44e, 0x6e3dd4c9, 0x822034da, 0x2930225a, + 0x0b562055, 0x52810f01, 0x1dfc1409, 0xa8958c98, 0x6094b603, 0xa4201541, 0xf3d54f23, 0xf2b9dbaa, 0x3c45b8e9, + 0xbd17cb2b, 0x1484b4cc, 0x201a4a4a, 0xe98ce6b0, 0x98d23d2b, 0x428c1113, 0xb020979c, 0x09f5831a, 0xe75a7920, + 0x47cd705f, 0x4febe958, 0x96c37ce7, 0x56d6c8bc, 0xe04f7852, 0x0e734d5d, 0x5c57863b, 0x538006b1, 0x8151aa93, + 0x4f015222, 0x591d60a8, 0x6ae7cc6e, 0x97415589, 0xa946f5ca, 0x66eca071, 0x8d3e2e86, 0xb1161e35, 0x57d57a5b, + 0xe59fdde0, 0xe4ea9565, 0x95a26d66, 0x13be8b6d, 0x56bc45bf, 0x8e7f8963, 0x54bf6727, 0x9916ada4, 0x62f2e025, + 0x265c7a67, 0xb5f81a27, 0x30537161, 0xe80cf7fa, 0xcb8ca950, 0x2b6e67fb, 0x2c786651, 0x07855942, 0x47bbf4d9, + 0x6f4a4c21, 0x36c6defd, 0xfe1e6766, 0x47813d1f, 0x670ab2d0, 0x0ed9a950, 0xdc11c7ff, 0xab91d4a1, 0x497bbf48, + 0x67fd4c95, 0xfb2a34e4, 0xc0b3225d, 0x485fa7e8, 0x5317a6c4, 0xb35e4460, 0x3f1f1414, 0x770acd95, 0xbd58116b, + 0x72b5f2ec, 0x048ce45a, 0x9bba9c04, 0x05d1ec41, 0x589a7ba9, 0x2c832f15, 0x8aefaf4f, 0x3e51fdec, 0x92690b20, + 0x6e6b8e44, 0x17cbe9fe, 0x93209776, 0xb882d196, 0x8fde8fe6, 0x9a65e314, 0xe35b143d, 0x1e103a1e, 0xe7b57a8d, + 0x7a05033f, 0x1982e1a4, 0x4cc730a4, 0x9e2ea015, 0x246feb16, 0x09caed77, 0xb6537dd7, 0x9f4dbfae, 0x26a289d3, + 0x92e91ae8, 0x91a58ef7, 0x2fc54ae7, 0x977c3e36, 0x3743928e, 0xa6ebfe39, 0xc2b651e6, 0xa6eb3614, 0xdd7144d2, + 0xb54b5ab0, 0xa922c530, 0xa3c85df4, 0x97d2d392, 0x5a111995, 0x8ceee61e, 0x6b1e912e, 0xa367c948, 0xde5f190e, + 0xaa626070, 0xcf49c393, 0x2bc3d7e4, 0x1d294753, 0xf5dc55ea, 0xb625b565, 0x5333179f, 0xc6d16749, 0x5753a9c3, + 0xa7711c74, 0x603cee15, 0xefe42b50, 0xc68fdc7f, 0xf9ff02af, 0x4f56f26e, 0x2b76b291, 0x0f096582, 0x80c72771, + 0x700de745, 0x9458f382, 0xf9bd14d7, 0x7672c89d, 0x47c7347b, 0x51985bbc, 0x8606281a, 0x0b9dd30b, 0xbbf31826, + 0x248d64a2, 0xaee947f2, 0x011daa8f, 0x7a40a4b3, 0x2f02eda3, 0xb88ef377, 0xba6ea199, 0xe11f16d9, 0xc3339560, + 0xc7176b1d, 0xc0b56723, 0xb7266faa, 0x16be8188, 0xacd3d6f8, 0x4b28b17a, 0xc18b3f05, 0xa1f58fad, 0x12016b98, + 0x01d2eead, 0xe5eb0b10, 0xb2fceb71, 0x96d2eb45, 0x2d71a3ff, 0x4db88a78, 0xfd0fb97e, 0xb8a7bb54, 0x3810ead6, + 0x71dd24bb, 0x8548eb6a, 0x6e89767d, 0x3a8ac318, 0x1f2ec060, 0xb4135f95, 0xd56eecb5, 0xbac40b41, 0xd2ee1534, + 0xcf83b06b, 0x209690d9, 0xd4a17133, 0xe12d5e24, 0xa63cbd25, 0x381fc6c9, 0x00b3c49a, 0xd1845c99, 0x75ac167c, + 0x74054a20, 0x7b53ccf0, 0xfdd061a4, 0xe459260f, 0x1e138036, 0x5710ae3e, 0x81528fb4, 0x52ec4bea, 0xfbc777bd, + 0x3cc69003, 0x77c4fa68, 0x7d192a9f, 0x02ca3c77, 0xb82ac6d5, 0x199adcc4, 0xc96964a4, 0x0e8e4e71, 0xe4191a80, + 0x873706fd, 0xfdfe0fd5, 0x3deb5867, 0x50d0e4e0, 0xa1427ba0, 0xeba1972c, 0xa9a5d314, 0x34231c85, 0x25888672, + 0x8363ece6, 0xc3bafb2f, 0xd0581c71, 0xed71d328, 0xb30e864a, 0x37c12c2b, 0xebe4148c, 0x1f97d93e, 0xde0945b0, + 0xe8dd853d, 0xeb921e5e, 0x47c6282c, 0xfcaf5663, 0x5b4cb385, 0x4e50eb5a, 0xcb117b3f, 0x094b6112, 0xc10e34af, + 0x16fcd1b6, 0xafef97b1, 0x19c0a1fd, 0x28aba640, 0x5e0a820d, 0x91eb670b, 0x2771c825, 0xa4d6669a, 0xb1c0e325, + 0xb40e5850, 0x613744a9, 0x1c71c5f1, 0xdbc4d1f7, 0x5db0c0a4, 0xbf5435b8, 0x97a17837, 0xa8522fbb, 0x7f715490, + 0x91858eba, 0xd79294f1, 0x865a7fde, 0x1d768b0f, 0xfa12549a, 0xaf0c52ab, 0xeb33e8a2, 0x0ccc9e17, 0xd04f4c4b, + 0x4d55265f, 0x2b0f34ee, 0x55d3654a, 0xd65c58fa, 0x941f30e5, 0x7008de39, 0x875ae693, 0x9a852ba7, 0x5ee91a9a, + 0xad395b7c, 0x909ba951, 0xbb81bea4, 0x9bc2bf0c, 0x242955fc, 0x5a827054, 0x2da5620b, 0xa2ae123d, 0xf3ec4bf0, + 0x87291ff9, 0x9cfc6493, 0xc7819e03, 0x26405163, 0x5a16a8a3, 0x9b9fc25d, 0xcf603c86, 0x59a6f796, 0xe13b6130, + 0x5661deb9, 0xbce2350d, 0x98931c58, 0x355f965b, 0x0f62eb29, 0x24f0514f, 0xdd006baa, 0xa65b806a, 0x1601f6ba, + 0x3ef3fa15, 0xe76c5d01, 0xae47aba8, 0x44a3aed7, 0x1f3814f5, 0x7ee20ea1, 0xed467343, 0x6179c8bc, 0x41ac13ff, + 0xc70efecf, 0xc3b70d5a, 0x137a53eb, 0xbfd0bb14, 0xf956363e, 0xf6ccfc35, 0x113ad1d6, 0x08ab91b4, 0xbb263c53, + 0xd4e4bf28, 0xb85c6ad1, 0xaca2afba, 0xa39666ca, 0xa1220b1d, 0x70ca7b2c, 0x324b8dd1, 0xf527ceda, 0xea9737ab, + 0x6b37c4ce, 0xbd694ae2, 0xc6b4bd23, 0xd5c86bdb, 0xd5c4e13c, 0x94299e3f, 0x0e7dee07, 0x37eb0a26, 0xb017b301, + 0x9241b061, 0xce907e8c, 0x5b60ca1d, 0xa74da81c, 0xc9bb4ebd, 0x8c94b0bd, 0x7f44b7eb, 0xeda8bd12, 0xf4457238, + 0xb5737d97, 0x2466a887, 0x48b6e9a2, 0x56cf6c64, 0xe2cac011, 0x53d81d96, 0xab95e544, 0xeb99178b, 0x65e862ee, + 0x46abec85, 0xdc032943, 0x987fbbaf, 0x64769c2f, 0xefc171f7, 0x4f18bf86, 0x915b8896, 0x997760c7, 0x8b94712b, + 0x3abde64f, 0xd52d0f9b, 0xde89fefa, 0x2bd40cd9, 0xca685a5f, 0xb7519ba7, 0x10e649f1, 0x884b6eba, 0x3763fbc0, + 0x76afac7d, 0x54384fab, 0xa26cd001, 0x9c40deda, 0x15c0470c, 0x586a2834, 0xcfb74b87, 0x9e0a0949, 0x8a1979b8, + 0x82cb75c7, 0xc58b8306, 0x4c3268fe, 0xe36d34ec, 0x659d0692, 0xf4d09087, 0x8a2033f6, 0x796bb90f, 0x14f62644, + 0x8d041f3e, 0xc9f5d9f8, 0x117badf1, 0xba366c32, 0xecde6c29, 0xddfbe982, 0xd9a8c0fe, 0x31fa22d7, 0x2bcbdfd0, + 0x548f1b39, 0x2646e15f, 0xeb232cd9, 0x807fccb6, 0xae381b1e, 0x86006cfb, 0xc4d46eef, 0xe4884e80, 0x0a2d05c3, + 0xa714a981, 0x2d62edf3, 0xa7ab5ae3, 0x811713d7, 0x90e29d34, 0x97b4a12f, 0xc77c505f, 0x84c16213, 0x3d70d687, + 0x09b9c8a4, 0x95605052, 0xee81d7f1, 0x14c61c88, 0x90c1d12f, 0x31f1c7a2, 0x84aefeda, 0xabae4ab4, 0xcd22cac2, + 0xc0add8b1, 0x44ff7e7d, 0x5028f809, 0x3d14a52a, 0xf2ca3734, 0xabdc1de8, 0x908b6a11, 0x36afee01, 0xd2aa99c0, + 0xf50001df, 0x342372a2, 0xc91abe98, 0xedcdc424, 0x8c7575e7, 0xbea1f363, 0xd9ab590b, 0x6ed4be8e, 0x0cf3f033, + 0x46832538, 0x75872a3c, 0xb8a941f1, 0x23511d26, 0x3fa362cf, 0x1ddd6031, 0xacb84d7b, 0x546b8c4b, 0x524baae8, + 0xf996699c, 0xcb30cbf0, 0x2d9e8459, 0x09e9688d, 0x2f697e7f, 0xdf9c4af8, 0x7e622d77, 0x234e1bd0, 0xccab7d2a, + 0xa1e65f1b, 0x6c66e853, 0xf3151d19, 0x119721a9, 0xd355d430, 0x36b9f942, 0xab8db356, 0x9e95bb23, 0x1a9d6148, + 0xfcba2f35, 0x22166079, 0xdea1d5c0, 0x72f4904e, 0x57b99ce8, 0x7a6debd8, 0x099aff1b, 0x5985fc94, 0x057b1955, + 0x957c2a87, 0xf267ca2a, 0x7e31d887, 0x3ced2c14, 0x46acd10e, 0xc8032d4f, 0x9047cb8c, 0xa79101c5, 0x88e69ee6, + 0x7f80a93d, 0xc86c8124, 0x4b372162, 0x481854fa, 0xde203408, 0x92535b6a, 0x6c1c716f, 0xc895c7fd, 0x7f2e2a26, + 0x21813f27, 0x8783c07f, 0x0bfb27e1, 0x2abcf407, 0xb827a900, 0x2f0fb765, 0xc84948a6, 0x47337ff8, 0x558884a4, + 0x1624deb2, 0x5ec6926e, 0x536433bb, 0x1a697b8c, 0x4e93557c, 0xc1ea0c43, 0xb74c2eb7, 0xfac7d258, 0x709421f8, + 0x13fedf0f, 0xeaaeee0b, 0x028a3098, 0x5434cd54, 0xf4ba0006, 0x57ed6d73, 0xf5777ad1, 0xbed6fcb6, 0x04b28d8c, + 0xaf70a107, 0xb63376a0, 0xdb20fcd0, 0xf0199f4e, 0xcc7095e7, 0x7bf61ec4, 0xfa3992cd, 0xaac60f3a, 0x484333c3, + 0xe030c708, 0x179507c4, 0x5f0f5608, 0xdc1acd1c, 0xad38d4d2, 0x3a14b421, 0xbf3d4e33, 0x9fde3e38, 0x34dcaf93, + 0x5363e14a, 0xe8b7a156, 0x1725adbd, 0xcf0e00af, 0xc11b70b6, 0xc622c5f4, 0x412e51e0, 0xf1c73843, 0x346d8067, + 0x62b87032, 0x3c96d485, 0x5d65f437, 0x750b9058, 0xc7c85297, 0xa08bbcf5, 0x361f620e, 0xd0dfffd4, 0xafde9cc3, + 0x86c5e8af, 0x080a6da1, 0x86eb4503, 0xfdf4739d, 0x5e3b03b3, 0xc9b850a4, 0x834d2673, 0x5856db7d, 0x14e1b57d, + 0xa0084678, 0xa0da13b2, 0xdbabfaa1, 0x962bd4d9, 0x239263bd, 0x40dc4053, 0x45ba9ebc, 0x1887f4b7, 0xd6482a9c, + 0xbe30850d, 0x5b45d4cb, 0x74e57620, 0x602a678c, 0xa1d8a889, 0x2cd3a427, 0xbb4d8ad0, 0xd4c6b5e3, 0xa778a99e, + 0xce3fc30d, 0xc71aecd2, 0xc0f46050, 0x02e0d3ab, 0x0b9e5a89, 0x3ff961ae, 0x22a2306f, 0xe752628d, 0xbc8113e3, + 0x872509f2, 0x3e87d17c, 0x602cfb67, 0xd631efa4, 0x11fd555e, 0x655e3347, 0xbace179c, 0x7e109177, 0xb1d4866f, + 0x0d2eff64, 0x2458337b, 0x56f6b92b, 0xfc683fa2, 0x2b23fb20, 0x608d86a0, 0x253456b7, 0xce15aaab, 0xcd014a01, + 0x0f053acd, 0x56f97a85, 0x1263d97d, 0x83ace82a, 0x6fee107f, 0xefa70dad, 0x57a28afb, 0xcbc50f6d, 0xdec66ff5, + 0x6d196139, 0xc1ca33be, 0xb557d591, 0x9c37d1a6, 0x151c5b6c, 0xd13103bc, 0x148c1396, 0xf2bdf401, 0x88995465, + 0xccc1d565, 0xca9540d1, 0x98b97f35, 0x1529f282, 0x31afe124, 0x7139dd14, 0xc589bc3b, 0xa093032b, 0xf2059d43, + 0xf36bd739, 0x2d43dec0, 0xba9ac643, 0x3d82f4b9, 0x12737bcf, 0xc77261e9, 0x6e4e10ff, 0x37350c2d, 0x92b04461, + 0x31c7452a, 0xa9643f6d, 0xa8f1494d, 0xd7bf4a09, 0xd0dd0ad9, 0x2661d3ef, 0x6a52008a, 0xaf6962e7, 0x48a27c20, + 0xe6471ff7, 0x7564027f, 0x83e38f46, 0x122864f5, 0xedeed74b, 0x7dc139b4, 0x9ba0e05d, 0x410a18ba, 0x54053c14, + 0xcacec798, 0x581b75a6, 0x8a743e5d, 0x887ad2b9, 0xedd4dddc, 0xd299a132, 0xedfcd35c, 0x4a0c7d68, 0x1dc38c94, + 0xd91ab73f, 0xbd1d6439, 0x3c25fad1, 0x77ba192f, 0xaae43996, 0x884bb429, 0x68fb66fa, 0xaceb25e7, 0x41ea05a2, + 0xa0171f09, 0xae89e6d3, 0x7cc21f24, 0x8960e599, 0x0f797a03, 0x809d5299, 0x3782fb75, 0xd682aeea, 0x726e1fc5, + 0x33218faa, 0x38064d29, 0xdc34aa1c, 0xae5b559f, 0x6bde51b3, 0x17393a82, 0x829bee2e, 0x1efdcca5, 0xc3effeea, + 0x9b729da0, 0xd08ba525, 0x01d9eb67, 0x1926356e, 0x4fa9cb75, 0x8a4d9729, 0x6ec365a1, 0xe84f1922, 0x1f84305f, + 0x37e31ab5, 0xe4f2ecdf, 0x30245227, 0x01869870, 0xc66efd9e, 0xd73624ce, 0xe48fbf20, 0x9f27a0fa, 0xd551ea99, + 0xf9d7cd0e, 0x1e57e591, 0xcd2ae4be, 0xe9f2f92b, 0x7da47912, 0x7428036a, 0x33f64ca6, 0x63d28fca, 0xb8e16952, + 0xaf6943d0, 0xb9580c97, 0xeaceefb6, 0xbe01e149, 0xbea5a829, 0x0a81ce18, 0x3609bca9, 0xd50386ec, 0x6a3dca8d, + 0xf6ae8248, 0x254f2551, 0x6e285ae2, 0x7ee10254, 0x79237d00, 0x0c8f567a, 0x1b6b95d3, 0x776cdbfb, 0x55d02b82, + 0xf9dbd539, 0x0787f758, 0x0fc87f46, 0x09259517, 0xe6ca6a3b, 0x7b24142b, 0x4c248812, 0x4da40654, 0xe127111e, + 0x3199ffc2, 0x2b9bdfca, 0x4b488ce8, 0xa8fd21c8, 0x520010cd, 0x61bdd016, 0xdd042403, 0x6aa0bade, 0x006b330c, + 0xc8df102c, 0xf766f015, 0xa7312701, 0x28a3d811, 0x63688fea, 0x20befc36, 0x1b0d2a1d, 0x6a6d6580, 0xb1973bd5, + 0xb6d9292f, 0xb99cb4d1, 0xbb56fc2d, 0xdc015d1f, 0x4d319aff, 0x54983197, 0x4e2b919e, 0xe95a40c2, 0x4a8d42c2, + 0x7481799d, 0x983d3231, 0x1c1c9023, 0x0c7f4793, 0xacff119e, 0xa5d5e179, 0x12c00c22, 0x95b5016d, 0xc069d0d2, + 0x02c8e46b, 0xb841523d, 0xe137c219, 0xcbb141f1, 0xff7e8d47, 0xe7f3ef3d, 0xcd7c220a, 0x5544c5f0, 0x62f310fa, + 0x7711f61d, 0xddf708f3, 0x786decdf, 0xa03227b5, 0xcd054244, 0x01f8f41f, 0xb9b7eca0, 0xfa5e79ce, 0x99d4c079, + 0x81c99323, 0xd3bce9cc, 0x64365a10, 0xce1de983, 0xdbaf0e6f, 0x6d43cca9, 0x05059431, 0x0d191a5c, 0xa1f86b9a, + 0xf656ad81, 0x540c6936, 0x752a12c5, 0x315bed71, 0x5fc67b8d, 0xda69f88d, 0x73afe6f7, 0xebd4bafb, 0xca169e8e, + 0xe1eae57e, 0xf442537c, 0x94547efb, 0x76a83221, 0xb6b65109, 0x6c18dd41, 0x802aeb4f, 0x7ff15d42, 0x29d9803b, + 0x91daabda, 0x03de4164, 0xc1236b5f, 0x469888b9, 0x84624fc8, 0xdb53f8bc, 0xaa4d0b17, 0x37150f4d, 0x9a2987b2, + 0x70587664, 0x9d53bd7b, 0x099d5eca, 0x1d86702f, 0x0439b6bd, 0x9252d941, 0x2875a3df, 0x48c56304, 0xacf267a7, + 0x4caf5f0e, 0x6cc47eda, 0x252a5792, 0x0125b5d7, 0x1ba5c5d1, 0xbaaafbc8, 0x9b735800, 0x78474756, 0x3ffc7be6, + 0x922bf35e, 0x88b9af66, 0x66c81565, 0xe4e37e9d, 0xaa35c017, 0x73d27ca1, 0xe5190809, 0x262728a7, 0x9e4c07dc, + 0xfea57715, 0x374e93d8, 0x0ca6a4ba, 0x40828a7f, 0xf8dc1e24, 0x850c55dc, 0x8c0b538c, 0xc867216e, 0x734f5fd5, + 0x3228fd53, 0x02c7880c, 0x73ea30df, 0xd6b92212, 0x83019892, 0x8f22539a, 0xdfcbf75d, 0x05e5c576, 0x142ce923, + 0xe5fbc069, 0x26363424, 0x0f87d9a7, 0xcdfc499a, 0xb95ac487, 0xe2a58f9e, 0x1b8b1b75, 0xef467d25, 0xdb8e7c00, + 0x7cf9ec8a, 0x788c9835, 0x19b5b386, 0xe06f674d, 0x8cc40371, 0x407848c1, 0x85e226f4, 0x5316c95a, 0x5bca1600, + 0xc34a8390, 0xe36a6f96, 0x1229ca84, 0xf673f54e, 0xa415c179, 0xa48a7aed, 0xa8e78e02, 0x84a48f77, 0x7389fda2, + 0x53c16f43, 0xf412f13a, 0xc25b5a34, 0x5890c6c3, 0xf2d796ec, 0x9c933d5b, 0x72c0fdab, 0x689739e5, 0x110a58e8, + 0xc9726976, 0x04f6d862, 0xf11a21e7, 0xf5a622c4, 0x29dc45af, 0x24e324df, 0x2397ee6b, 0x737d387a, 0xbb6deff6, + 0xc0cefb7f, 0x5e69a4c7, 0xdf0c9d97, 0x8f693561, 0xe9f8c73c, 0xcbcac9b0, 0x16e4d30f, 0x3a9d3fb1, 0x7e67e937, + 0x21015b8a, 0x51a8b075, 0xdb5efab3, 0xa5ad5b74, 0x6f9f53aa, 0x93050e91, 0x75364536, 0x6f786d07, 0xb50c6f61, + 0xd3c60dfb, 0x0a7885f2, 0xac306a0a, 0xa7a51b38, 0x5ca93070, 0x1162d556, 0x1c5c5200, 0x166f076e, 0x0fd92d42, + 0x7fb4be06, 0x56bafa9b, 0xe0bed388, 0xbd2ad650, 0x0b7c434b, 0xd1a15fc8, 0x8d8b833a, 0xd2ef439c, 0xb9f0b085, + 0xdb57e248, 0xf00b873e, 0xc16c3dfb, 0x3511bf32, 0xa1719a9b, 0x4255a189, 0x0ef1a712, 0xe8230520, 0xbf2eadb5, + 0xd742ad9a, 0x00ead606, 0x2dce1af8, 0x991bcd08, 0xb044682b, 0x9d307d9d, 0xa3aed745, 0x0bc1e23b, 0x44e483f8, + 0x77c2ebe3, 0x02db77c7, 0xcabff656, 0xf33ca97c, 0x2357a703, 0x88339d9b, 0xe6284511, 0x2c28b203, 0x03878062, + 0x264b2b1e, 0x384ae6c5, 0x9ae6f522, 0x41167150, 0xca9af78f, 0x28cf7aa6, 0x8cb36937, 0x5a14734c, 0x7497bfb8, + 0x66ee7053, 0xd1fbdff5, 0x0d6116fe, 0x24ca019f, 0x3e053e42, 0x8c57f14e, 0x7193814b, 0xf9f9882d, 0x83fec1a1, + 0x11584749, 0x492e1836, 0xa8d357ee, 0x4c9aa57f, 0x8b43bf21, 0x349e3c59, 0xdef65c50, 0x88af8f9f, 0x6e80ccd7, + 0x0614805d, 0x227665d1, 0x86744d85, 0x256aa903, 0x79e51504, 0x4549e442, 0xb40aa41c, 0x431944ed, 0xa63fe36b, + 0xf7ada092, 0xbb8fec07, 0xfcf4111a, 0x7c1f3cb7, 0xf848065e, 0x48b3a64f, 0x19b179ad, 0xe8a68c38, 0x7e19a0d9, + 0x9756a5a2, 0x96850824, 0xae452ed0, 0xcb277c69, 0x418939b3, 0xcffd5697, 0x6cde2ab5, 0x50b9bbb0, 0xd69c8b4b, + 0x3323fd8e, 0x2a6385d0, 0xf9051bfb, 0x7535cbd9, 0xfdaff757, 0x71ea12a8, 0x77f02246, 0x6d5e5f90, 0x20189d30, + 0x8e36b92b, 0x760d6498, 0x4a9438ad, 0x9341b1ea, 0x59b8acf9, 0xd57582f9, 0x1abd9190, 0x5361f3ba, 0x3bf3a6c3, + 0xf4d7207e, 0x40d8a98c, 0x99ec27e3, 0x2a429130, 0x2d58345f, 0xc21f6224, 0xe383a0d0, 0x7ad37ebd, 0x14670b01, + 0x884ef24f, 0xb471271b, 0xb7e8e043, 0xde014774, 0x5e778fe1, 0x8ae1f2c1, 0x1ac4c80a, 0xc5107a33, 0x4a31abe0, + 0x6d2d3c5e, 0x7febad16, 0xfb7c559e, 0x8c8340ef, 0x13b83e86, 0x411dc114, 0x72b6c7c1, 0x2ed068e7, 0xa464d4ec, + 0x29c60eed, 0x0f867a65, 0xa06c741b, 0xd4b61336, 0x0c24a08b, 0x7aa6cb93, 0x631778a9, 0x0deefbfe, 0x66b59df4, + 0xedcefb37, 0x2dbb6d96, 0x19813ee4, 0xbd805dd9, 0x8adb0092, 0x9e1243d7, 0x3466762e, 0x268602ca, 0x84ccb4b1, + 0xeeb55643, 0x92d47e5e, 0x8f93aba9, 0xb094e832, 0x8f9be074, 0xbc036b79, 0x69603c64, 0xa07a25e8, 0x964e0786, + 0x25658e62, 0x78fbbd41, 0x27be9c64, 0x1bace98f, 0xdd591045, 0x77c26f1d, 0x3cb0ebc9, 0xd36b10f6, 0x39131128, + 0x3dc3e372, 0x43c7ffad, 0x70817c45, 0x4539847a, 0xe5d2d4f5, 0x700ba544, 0x5b879ba9, 0x3941b52a, 0x0c6bbff3, + 0xd094e0bb, 0x55451020, 0xa638fdf4, 0x51ff1a9c, 0x1abb3644, 0x1a5a1f49, 0x8bf7433b, 0xc2e702b7, 0x3a9c4120, + 0xca80986c, 0x145ef31f, 0x37eddbe0, 0x2b283167, 0x7ca6e6dd, 0x45086d7a, 0x39419e48, 0x4d4da6d1, 0xe2159d76, + 0xb9057d45, 0xfaefb2a9, 0x958803f6, 0xef6aa475, 0x281cf400, 0xfce7c7ae, 0x9675dbb2, 0xfc05c5cc, 0xd6750097, + 0xc87d229b, 0x43dfc1f3, 0xbd4baf52, 0xf53bd337, 0xcaaddf29, 0xed09cd6a, 0xe379f46d, 0x9a2fe3af, 0x9d044a56, + 0xdd08b289, 0xd1a39060, 0x52208b9d, 0x7c386e79, 0xe131537c, 0x96bfe50b, 0x2dd5954f, 0xb5bced1b, 0x373a2a33, + 0xa74f2495, 0xec7b1ee3, 0x2a268b61, 0x283b2376, 0x1761db65, 0x7ae3f391, 0x881c03f5, 0xb0d7a8c0, 0x818bd339, + 0x4ce98a6d, 0x66cb1f0b, 0xf1390020, 0x31ed55eb, 0x78b4c2fb, 0x7cea27c1, 0x23eaa787, 0x67efb890, 0x95bc995c, + 0x2a149566, 0xd07c79f8, 0xa8323e7d, 0x8404cbd8, 0x2a1700b7, 0x15a8c7fc, 0x205463cf, 0x61ea2e95, 0x67099656, + 0x34a96a46, 0xcfc1befe, 0xc6af0bae, 0xa50ee511, 0xb411548d, 0xe61b75ec, 0x2d885ac6, 0x601da710, 0x4adca383, + 0x2332a7c7, 0x7d1bed1a, 0x488f005f, 0xe79ae37c, 0xc0112813, 0x374f9707, 0xe4480164, 0x3cf490e6, 0x3205a111, + 0xb0327451, 0x8420b09b, 0xab618502, 0xefeeb34b, 0x55bbc6ee, 0xe42e43c5, 0x49385af8, 0x956faad0, 0x7b910e05, + 0xea0134b2, 0x92cae71d, 0x164b073d, 0xe32af24c, 0x311b05f5, 0xc025c695, 0xa894cb2e, 0x92024526, 0x3f26d922, + 0x3d37dc81, 0xc043ee7e, 0xe5f078e5, 0x003466d6, 0x6beaac93, 0x8eea66ef, 0xe3752a16, 0x387307c9, 0x586c1b6a, + 0x8abd4f71, 0x51e844a2, 0x3f67e17e, 0x46d53ebd, 0xfe2e805d, 0xd795b93e, 0x8501ca7a, 0x5dbe02ec, 0x78f4bccc, + 0x911856d3, 0x0299ff09, 0x49cd439e, 0xf8f9e332, 0x2ee5ca88, 0xa001fffc, 0x023714fb, 0xb23953c2, 0xd1033178, + 0x1e8ec0e7, 0x68f047ee, 0x9c2454fa, 0x36e77100, 0x52451938, 0xbd131db6, 0xc69c7657, 0x49ba842f, 0xcbdecdcf, + 0xe19ebf68, 0xff85cfa3, 0x6abf7940, 0x660dc840, 0x333d6e3e, 0x34a6bfe0, 0xa91eec1f, 0x119b6e4c, 0x49694943, + 0xa3300832, 0xc778d8e3, 0xa007672a, 0xe047bb7a, 0x4331eb49, 0x1a6b8e94, 0xc58ee942, 0xc000b7ff, 0x1e7de84b, + 0x129b045e, 0x5cbf9f35, 0xdf742a90, 0x6d05fef8, 0xf138dd27, 0x36ee7c95, 0x139d6be6, 0x6c98e2e1, 0xefd4c0f9, + 0x7beef877, 0x4424064d, 0x2629f743, 0xd307dd05, 0x01b2ebb5, 0xecee6a08, 0xa1b95f48, 0x7796a864, 0x6d7c1c4a, + 0x744184c8, 0x3c482171, 0xc466d503, 0x3ae74c54, 0xb56bfcab, 0xb502cf34, 0x3b8d6c43, 0xd8e61b17, 0x8e682135, + 0xf359e0cd, 0x643169e4, 0x47540056, 0xd45a3b20, 0x326c540e, 0xca873f8b, 0xe6fbf445, 0x62c62865, 0x7b87b7d8, + 0x231cab37, 0x96d2d758, 0x64f78fc6, 0xa09af42b, 0x701ba53b, 0x03e6c89d, 0xee3bfe88, 0x0363256f, 0x5898e0f0, + 0xf80cf631, 0x06123ce7, 0xc39c6e09, 0x361a0e9d, 0xf00e36a9, 0x27744f47, 0xfed78609, 0x2d488340, 0x321b9874, + 0x2fa3c65a, 0xd161fddb, 0x2e40b91b, 0xc5f7316e, 0x1e58289c, 0xac4c9f47, 0x95afc589, 0xcffee5da, 0xa00f181e, + 0x8a49a05d, 0x6a49c913, 0x43f08ed1, 0xf69ab22e, 0xa01951ac, 0x54820314, 0x58af42c8, 0x5555303b, 0x1800b6de, + 0xf891f596, 0x6f507422, 0x6a9ba44b, 0x15d6e793, 0xf442678c, 0xa561cc84, 0x505052b6, 0x84c67176, 0x3d047b25, + 0x92d82c35, 0x7717b77c, 0xd981a747, 0x22078532, 0x2dd12831, 0x705722b5, 0xbb6dc1c3, 0x74758b50, 0xc6cfd49b, + 0x8d7bb9cc, 0x79afae56, 0x0ed47b03, 0x48aa5071, 0x84f09e7b, 0xd059e561, 0xbf0cc41a, 0xa9268eca, 0x9aa6c896, + 0xaade88be, 0x9101d652, 0x69e53ba5, 0x6cd78a8c, 0x4602bfce, 0xfcef4342, 0x430e9516, 0x50d34573, 0x0b7860d7, + 0xea327cf3, 0x4dc5bfbc, 0xf4341f55, 0x5d0b8274, 0xc3522280, 0xd3705cfc, 0x34317cfb, 0x74f9959e, 0x716c49f6, + 0xce445939, 0xa4617575, 0x4809ea09, 0xbc47b181, 0x6dc15dfb, 0x487ad5e4, 0x659bf0ad, 0xf1ecab04, 0x18a8b8e7, + 0xa8c15786, 0x5dd1f56a, 0xbb7d1e54, 0x43e5b4c5, 0xf533d065, 0x6083d25b, 0x829c8643, 0x65b2e742, 0x229bbf44, + 0x139707c3, 0x4c111fd3, 0xa1731b71, 0xb5bc114b, 0x4f5eed1b, 0xcae2c9be, 0x82544862, 0x7668f93c, 0x7a4e6f1f, + 0xbbee4d94, 0xa3dced5b, 0x5347dae4, 0xd9f112f6, 0xa6793307, 0x2e9c998a, 0x6c57c465, 0x789918d5, 0xbf003b64, + 0x531f4e59, 0xacec47a7, 0xf6a5ae90, 0xaf4a8c55, 0x39c0efed, 0x1e137aa0, 0x9d1484b6, 0x33b50569, 0x8dc6f777, + 0x0d463c28, 0xc8f91459, 0xa39581c8, 0x111b387e, 0x19ed8e27, 0x881a20ef, 0xc5f748e8, 0xee2dbf5c, 0x886a24dc, + 0x6adb67c1, 0xfd8c6ccd, 0xd2e65510, 0x5ec3986e, 0xc33a2afd, 0x910ec54c, 0x1ed21f18, 0x034b657d, 0xdebc411d, + 0x751cd0f1, 0x9d180937, 0xe502da10, 0xff476182, 0x7cbe8564, 0xa0e143f3, 0x4c7ffa3b, 0x39912a93, 0xfd66e953, + 0x6599594b, 0x004ee397, 0x65788e40, 0x444b76bc, 0x5fa30942, 0xb3cd8017, 0xcb8e632f, 0x0a966375, 0x7a757843, + 0xf22e5bad, 0xc1e5511f, 0xbd00b9b6, 0xb5cb831d, 0x0f23159a, 0xd88c78cb, 0x82755f48, 0x1f4bd3ba, 0xf5507d8c, + 0x4eedd37f, 0x782e1ed6, 0xe5f0141b, 0x61821871, 0xd63d5789, 0x43dc24a8, 0x30aa59bf, 0xc68f1c84, 0x81ed8166, + 0xded7ca5d, 0x758ed2a4, 0xf7dfae3e, 0xe06551cf, 0x8484f5e5, 0x8158f8a2, 0xce2bc87d, 0xedf1eed3, 0x25d60836, + 0x8d38ca21, 0x94054002, 0x3e254e2c, 0x05097123, 0xdbfe10e3, 0xa85ce3a5, 0x48a81408, 0xb5fffab0, 0xfe3a1626, + 0x0ba1dc2b, 0x67540ff2, 0x11253896, 0x24622cef, 0x74c21f16, 0x8289f4cb, 0x98cc6be5, 0xd1edbe3d, 0x7f2d71b4, + 0x1d3cc925, 0x38233c6c, 0x88633353, 0x1a072e6a, 0x7e553d82, 0x228f91ea, 0xd71abd41, 0x2caad364, 0xa3735edb, + 0xc221a9cb, 0x787dd6fb, 0xb1a1a882, 0x6b50a4ae, 0xe8f89c81, 0x89748961, 0x896de395, 0x5a269c53, 0x7b7f51d3, + 0x33a9757a, 0x2ce56200, 0xb48c2ffb, 0xe2282cdc, 0x973f4466, 0x3d10e499, 0x66b34a94, 0x1bf990c3, 0x900b02de, + 0xd3c563cc, 0xce8f3c41, 0x3851e01e, 0x90349b03, 0x599abf0b, 0x9aa25a6a, 0x62b8c479, 0xce841c2a, 0x910f5b3e, + 0x6a219314, 0xd3b88813, 0x995ebcea, 0x86a48e1d, 0xa886ac5a, 0xc0288ca8, 0xe705c98c, 0xaa922dfa, 0x8c22f316, + 0x23572639, 0x05217b97, 0xb75d4d84, 0x1c2c3890, 0x00146d4d, 0x6a2f01be, 0xe0dcaa4e, 0xbb50c601, 0xb7b4d108, + 0x944f00a2, 0xff756803, 0x483dcde9, 0xe87e21f4, 0x4c26757c, 0xafbc49f7, 0x08f7624e, 0x9f6a3fa4, 0xbc7ae679, + 0x86699c89, 0x22f62a4c, 0x28316fb7, 0xbb73fb9b, 0x8bf9620c, 0x8d1a133f, 0x57efa431, 0x502f4c8c, 0x230f9ee4, + 0x45337a88, 0xea0668fc, 0x58ea1974, 0x3e6d979a, 0x41d1a259, 0x4d505b55, 0x7b1e7f3e, 0x2209b87a, 0x3eb0d891, + 0x5661a572, 0x396a9f29, 0x4805a1f0, 0x14d113b9, 0x5a40cca7, 0x6318b272, 0x1b130d91, 0x592aec2e, 0x8825c18a, + 0xa1ab3348, 0x95ae55b5, 0x664f22c0, 0x0d68c1bc, 0xf4082953, 0x5bc749df, 0xb1d2c7fc, 0xb145f19f, 0x7554c80e, + 0xa0b39cf5, 0xce246a8f, 0xb18d0cfb, 0x03a71e0a, 0x5a81a311, 0x85fbc711, 0x8fff5ca6, 0x83be0ebb, 0x9c7b1ca0, + 0xe26420a3, 0x112c0a17, 0xb4c08bdd, 0x627cf29d, 0x941bc5c3, 0x0667cca8, 0x9fed33e9, 0xb346bba9, 0x68723369, + 0xef5839e9, 0xe313f5b8, 0xc93b0d06, 0x70e2947f, 0x08153730, 0xe482fe47, 0x6368cb7d, 0x0a681dce, 0x77f63fd1, + 0x8d7270c3, 0xfc9457ae, 0x70e7bc0d, 0xb6e4a2a0, 0x2c4b34b2, 0x9138c6d5, 0xbad6b74b, 0x5966d516, 0xe1b6edce, + 0x8d763712, 0xfe5403f7, 0x9f09ff24, 0xebcef977, 0x837ba515, 0x47704d24, 0x3f4f1d95, 0xc617fa7f, 0x5e5acca5, + 0x2ec6d2e4, 0xdc4e63ed, 0x96b6e8f2, 0x60661080, 0x6eb38e1d, 0x9c8dc3fe, 0x6721ce93, 0x03a9c2af, 0xed5a5bca, + 0x5af7d889, 0x4f25d0d7, 0xfb0235f3, 0x2f93fc27, 0x49355ba1, 0xe5193f55, 0x19adb865, 0x7d348566, 0x1966645d, + 0x9eb934f0, 0xfe5d8e5f, 0x8e3c8f0d, 0x2b134563, 0x7e55e647, 0x35a47094, 0xa1370d0b, 0x1ae9a43f, 0x19cde90e, + 0x3e14c0e3, 0xd49b97c6, 0xdf30c5f5, 0xae0abf99, 0xaccc3bc5, 0x4ab2f943, 0x39f6a930, 0x7d48d952, 0x93c6a837, + 0x0e5d337c, 0xb7f75747, 0x5cf89396, 0xc687c0e3, 0x1eae37ed, 0xb35bfbac, 0x0469bdf1, 0x4014dd10, 0x526b24c7, + 0xc8f39970, 0xe0d0e86a, 0x1bd63ca0, 0x83378fec, 0xcd203201, 0xd33f9684, 0x5abc9f24, 0xb147304d, 0xc8bcc35a, + 0x62f7149f, 0xb22a53d9, 0xd7f3904d, 0x0c63357c, 0x6d6179cc, 0x845790fa, 0xca1ce734, 0x61770d55, 0xf8f573ee, + 0xb176fd64, 0x5e7ba2af, 0x0185c753, 0xba507798, 0x54d0fdc7, 0xfa8fb382, 0x8064d5a9, 0xabf3e9b7, 0xf72964f8, + 0xc3084e30, 0x12ce737c, 0x8c59362f, 0x8cff8c30, 0xb49c124a, 0x691b4340, 0x3770e7da, 0xfe16e0b2, 0x1cce716c, + 0x820a870d, 0xf21dd76d, 0x0c89d1c0, 0x02e251c0, 0xa64c0bc6, 0x2fa69fc8, 0x65160514, 0xe8a2ce04, 0x0ccd61dd, + 0xd59ece25, 0x59438cc0, 0xe87c89da, 0xfdd57b09, 0x1509ae10, 0x213c5cb3, 0x2d90ab89, 0xb7f2aad2, 0x103bf5c0, + 0x01430b65, 0xaa500a77, 0x638f5a61, 0x93836ddd, 0x435ec6ea, 0x7b0e701d, 0x73a21bdd, 0x2f7d01f1, 0x12d346db, + 0x0cbe8f18, 0x994dad44, 0x66f7015b, 0xbe5f355d, 0x2bde7457, 0x270543fc, 0xb0a60032, 0x6c3e154f, 0x8a7d1e22, + 0xc8924fe2, 0x87f0677e, 0x35c1cc1d, 0x4753ebf2, 0x9aa25006, 0x8aba1420, 0x0408ca15, 0xf4a4e3ec, 0xe5d397a5, + 0xb3db1445, 0xbc09be66, 0xfb7f5379, 0xeb9b6de8, 0x1b3b7fdb, 0x91a5e67c, 0xb8b8d83c, 0xacd84d00, 0x82fd02b3, + 0x7fce471c, 0x939c2327, 0x12056d42, 0xce4f10e4, 0x8d46c7be, 0x57c2ec35, 0xf891e401, 0x7300ff72, 0x26675551, + 0xac01c365, 0x916f9440, 0xb0cab7ba, 0xdb83975a, 0xbd6f14d8, 0xd19b58c9, 0x5eb0079b, 0x1c7b06bd, 0xcc9aa020, + 0xee72ff30, 0x909fa54f, 0x0d983391, 0x4aa009fa, 0xfa08b798, 0xd4162a66, 0xa32fc06c, 0x4d842bdc, 0xb7116620, + 0x8f85306f, 0xb1d73c66, 0x753b0f83, 0x6fd8539f, 0x82762215, 0x0459df17, 0xb8ec5365, 0x482db936, 0xcf0d0115, + 0x67e4e303, 0x18f57a16, 0x354888e8, 0xd8e6f5ce, 0x6b4753cd, 0x5e02ccfc, 0x843516f2, 0x14551351, 0x1acdfa70, + 0x58deaedf, 0x1e864169, 0x528ea284, 0x751d049a, 0xf8010590, 0x500f18e5, 0x3ed7777f, 0x247e54d7, 0xb22e1879, + 0xecce1f9a, 0x6e080398, 0x885165be, 0x5a6fffa1, 0xa2395b74, 0xc998dd01, 0x688238bb, 0xd896dc17, 0xd90a0c0d, + 0x914fbf60, 0x46048487, 0x3a20226a, 0x7f4ac2f5, 0xb3a55294, 0x72b51172, 0x2833c1cd, 0x74c2d791, 0x98b7aa00, + 0xb92fa773, 0xf887f0cf, 0x4117b5c4, 0xe99c831d, 0x8803863f, 0xdcb3e822, 0x1bd957d3, 0xf574827d, 0x9bf3177d, + 0x0853c0a1, 0xb8eb02f3, 0x9d4fae4a, 0xace26e9c, 0x5055efa2, 0xed16cde9, 0xd25e1a1c, 0xf34e8826, 0x1e122940, + 0x358d5207, 0xde6dfd25, 0x4ee6390d, 0x57e5cfe9, 0x5a53a1a3, 0x681ab07d, 0x3092aec2, 0x58e9e173, 0x443c66e1, + 0xc53f3e87, 0x7b900273, 0xd029c624, 0xf4ada0c6, 0xa951fb23, 0x1fa97370, 0x3403ea2a, 0xc8dd2046, 0x855e79fc, + 0x21b520ff, 0xb5adfc2c, 0x7b998074, 0xac32cfe1, 0xd63e3c5c, 0xc5421620, 0x9ad2060c, 0xbd6338f3, 0x46774b70, + 0x33e7cd7a, 0x07f3f35e, 0x47ba140f, 0x2b070476, 0x4b0f79b8, 0x21d0d7ac, 0x7860086e, 0x035fffb4, 0xed6f3b5c, + 0x1bcbcc2c, 0x0e100765, 0xce000f35, 0x3b88d249, 0x9e04a157, 0xdaf8543a, 0x4bb9e1ac, 0x0b1fd909, 0x9840ded1, + 0x53c692f1, 0xfa33a9d2, 0xa82dd1a7, 0x5a32323c, 0x80ea420e, 0x691faba6, 0xc0059a95, 0x69f6a7b5, 0xe1604dc9, + 0xf5e79b2b, 0xe96b292b, 0xf1b40a81, 0x3d86df1e, 0xab5a3788, 0x31b0518a, 0x79015f54, 0xc90574b5, 0x03020953, + 0xd66eccc2, 0x0a626560, 0x89f689f7, 0x5fff5191, 0xf934538e, 0x96b68a5e, 0xadafa4fc, 0xad1947eb, 0xa5494327, + 0x833b471b, 0x35645543, 0x914d236f, 0xbc737e03, 0x55d1d699, 0x5d9a3e17, 0x04ae1f9b, 0xf540048f, 0xac3def49, + 0x95f10c4f, 0x62a7b61e, 0x20ea8218, 0x8f0852a3, 0xb2983e1e, 0x67c6d772, 0x3b66db55, 0xbf209830, 0x3c6c3b94, + 0x00796d76, 0x84b55497, 0xa7c6513a, 0xcfeac148, 0x3bb38ab4, 0xaf1e91b9, 0xa4b25bfd, 0x5fbb176a, 0xac28b0b6, + 0xc0b3cc8b, 0xc019c5ab, 0x7e3ac3b6, 0x1821ad55, 0x56f623e0, 0x3a157cf5, 0x0c4e90de, 0x2fffbdce, 0x6fdc20e9, + 0x497866b7, 0x2b2d28e6, 0xacfd794c, 0x93cceb61, 0x026fd637, 0x64fab121, 0x6cd24612, 0x5f109085, 0x3eaf2622, + 0x7e003c41, 0x59b05385, 0xe82a5b9f, 0x5307a522, 0x04d460ec, 0x047991dc, 0xca409fd0, 0xd54c4644, 0x2aab5503, + 0x7e1c4fa7, 0xbfae0610, 0x4f76d1d0, 0xf1c85c8a, 0x5dc6797d, 0x7d7ccfcc, 0x08e40aa5, 0xcfeede7f, 0x6459cf27, + 0x38ca16c8, 0xfb3c6cfb, 0xca763ad8, 0xb8586b1f, 0x70346f9d, 0x332e20a2, 0x76d17be0, 0xb864826c, 0x7cf22217, + 0x745ef173, 0x1cb7316f, 0x44015f88, 0x52f5781c, 0xfab794db, 0xcb7380c3, 0x702a9e77, 0xccfded22, 0x0d4906b1, + 0x6ab5892e, 0x3be95a95, 0x89228b11, 0xc0f7665e, 0xbf396c3e, 0xbb622a55, 0x0eeac1b8, 0x2a8ba4bd, 0xf80eb99f, + 0xea5c5337, 0x9a6b6255, 0x3cee148c, 0xae6bccd2, 0xa3deada3, 0x5a53a7b2, 0x4495ecea, 0x23620d51, 0x8db779c1, + 0x3cde857f, 0xb5822098, 0xd1472fd7, 0xd9186dc7, 0x9adbb6a9, 0x61fa9f1c, 0x9a3023ea, 0x69d70ca7, 0x4cac0bf4, + 0xdcfd25c5, 0xc0979eb8, 0x22782eeb, 0x3e7053b8, 0x93734597, 0x4ba9339e, 0x08baa780, 0xce6c75b4, 0xeb08a33f, + 0x342fff33, 0x58e7bc05, 0x207690ae, 0xaf7a0f3d, 0x842231b0, 0x25002f08, 0xd08545f7, 0x02a8a377, 0x02ab33aa, + 0x1962e977, 0x4f89ee07, 0xb20005f0, 0x886b5db5, 0x56d86942, 0xecb9e4d1, 0x6c30090b, 0xd9b2ef0f, 0xff6a9b67, + 0x9e9b5e39, 0xca291d44, 0x1d83f853, 0x8f194668, 0xea07ccfe, 0xe87ce3ef, 0x419e141d, 0x2c161b15, 0x007b449b, + 0xd6010622, 0x0a811847, 0x489d4c3d, 0xbafea0fa, 0x470c6346, 0xbc85a1f0, 0xe1569e51, 0xd304e3c4, 0x4fe5db66, + 0x2aeec9f4, 0xa19808b9, 0x5339701a, 0xe0e00791, 0xf982dee2, 0x033308da, 0x0270c444, 0x2ef9c629, 0xef67c580, + 0x2d5988bd, 0x21e1a120, 0x498d4600, 0x64a355aa, 0x4b8076dc, 0xecc326f8, 0x0fcd6856, 0x42ce37d3, 0xe0b60ef7, + 0x89dac43b, 0xb1fdbec8, 0x948ac5c2, 0xf7e7beaf, 0x43609aa2, 0x63c57ae7, 0x8004c87f, 0x175cb1e2, 0xa3e6a8c8, + 0x52d57f6c, 0x602f10b9, 0xf3fd3589, 0x848ed37c, 0x0ca07c4a, 0x2f192e77, 0x52fa89dc, 0x9d593239, 0x1788bc59, + 0x1df6ada2, 0xf80aed14, 0xc0f7bf12, 0xcc043004, 0x0d754631, 0xbb7e273d, 0x4b18e3a6, 0x59a89752, 0xa544b4e0, + 0xa91b27cb, 0x489b4035, 0x640707d0, 0x7d67b157, 0x02f93dfb, 0x0a0ccb2e, 0x27fa5179, 0x76c342c3, 0x4d4eb6d4, + 0xc3860309, 0xa5629119, 0x640a5207, 0x5c9c5cba, 0xddb43bc1, 0xdf2be4e5, 0x5ce90951, 0x721a095e, 0xe9cb0f73, + 0x62c92cd3, 0x0661e6cd, 0xd941765f, 0x4814a715, 0x2eb2390a, 0x99f81747, 0xf1ec69e3, 0x087e1b37, 0x06d08bc6, + 0x705c811a, 0x90c68640, 0x25de22ae, 0xd7cf8aa9, 0xe3d69c3b, 0x8d91a0ee, 0x43574d68, 0x6aea621f, 0xd56d3da1, + 0x42726b24, 0xb45eef0a, 0xa1665072, 0xd073ef07, 0xd2935c0e, 0x9af78e04, 0x84b53ebe, 0x37372f8f, 0xb75281ac, + 0x207bddfe, 0xfdcdef0f, 0xe8028da6, 0x76303f5d, 0x0e48a055, 0x72b8c136, 0x506eaa06, 0xb2e14fd5, 0xd8a3f624, + 0x8dcc38cb, 0xe02f7326, 0x57f97fec, 0xc7a2b1c0, 0x0a50c312, 0xb9b5e97a, 0x75a754ba, 0x3f46b0b8, 0x7fc6689f, + 0x9e006ce0, 0xca3246a1, 0x85c042a0, 0x6e34aa75, 0x89a176da, 0xf4b9b295, 0x44aaffd9, 0x7acc1a40, 0x69071750, + 0xb0ec27f2, 0x7b0e9b42, 0xdad37325, 0xec20d18c, 0x0f75abe7, 0xee044fee, 0xc036b182, 0x530fbee1, 0x68a92821, + 0xdcf51a03, 0x5feb1c75, 0x2c50514a, 0x0a81f51a, 0xdea652c1, 0x075b1b68, 0x648d53cd, 0x9f338dfd, 0xa2011f3a, + 0x670ed015, 0xff631e9d, 0x47ee3f18, 0x833542c0, 0xcf1f7f42, 0xf7c7d5be, 0x70dd3dba, 0x6e671f5a, 0x0361b4e8, + 0x789b80cd, 0x1d00196e, 0x334c20ce, 0xfb66f442, 0xb6077ff2, 0xc2a72f8f, 0x9ea271c7, 0x7a17c779, 0xcd90113b, + 0xf18fcd34, 0x7684d019, 0x55250dc8, 0xccdc1b08, 0x5e891830, 0xa9efce7d, 0x2c8c8e17, 0xa040efbb, 0xf8b81c5e, + 0x0d9618da, 0x84f315e9, 0x204cfc54, 0x1dc5c471, 0xc77dbdc4, 0x180a8c87, 0x89219397, 0x775aa5cb, 0x407d1bb0, + 0xd08e5bec, 0x4924578e, 0x3d88b6b2, 0x583c6bec, 0xc0a461a4, 0xcc7d2014, 0x00712449, 0x2334f7bf, 0x461bb1a8, + 0xe6e4dc70, 0xbb674e82, 0xc21caf7f, 0x88ba9254, 0xf8709e5f, 0xcca538c7, 0xe5b647be, 0x7bc26a98, 0x481cc1d7, + 0x5cdebd8d, 0xef876fa8, 0x3e04f759, 0x0ebc870f, 0x29b3acc9, 0xaafe9135, 0x10f12c1c, 0xf16d2a5a, 0x24c35ca0, + 0xce0adf15, 0x7d4293b2, 0x220ae1bd, 0x5cc0d34c, 0xda23614f, 0x36ba2465, 0x2f5dac11, 0xf42e3e86, 0x2f59edce, + 0x7fc79314, 0x1e8cde50, 0x8fda0975, 0x3478607f, 0xbff45cde, 0x40a78181, 0x157a6f80, 0x63663f6b, 0x2bb56f11, + 0x87b08478, 0x423eb06c, 0x3ca26d15, 0xb07102d6, 0x5bcfd643, 0x8196d0f9, 0xba358427, 0xe4f8801c, 0x1b476253, + 0xfcd3c08d, 0x059d145a, 0xa37ac133, 0xb9c3c69e, 0xe666ea0a, 0x9ac7ec9d, 0x42e17f14, 0x5c7fb9d3, 0x87d4b03a, + 0x876c31ae, 0x223746fd, 0xfcf7db1e, 0x4d621ebd, 0xd15e65d9, 0x5df97446, 0x19de74fb, 0x9c707862, 0x9ef1f9d8, + 0x3e4d6373, 0x579c6894, 0xe13cc6b0, 0xb860d820, 0x408dd89d, 0x297c6aeb, 0x018007ca, 0x99e3e37a, 0x9855c325, + 0x7b1e1468, 0x335d7a37, 0x90af85b8, 0x588a6e8b, 0x29d70379, 0x22663e79, 0x7759508e, 0xcae9ba31, 0x592929eb, + 0x38fa0ad9, 0x6cfbd3ae, 0x6d78abfe, 0xd69a6f42, 0x28706f79, 0xf5ba5a56, 0xb9711946, 0x5752d6d7, 0x1a5a2a13, + 0xe1126220, 0xf2ca806d, 0xcbcf2037, 0xea6687d1, 0x1c790167, 0x1f2693ef, 0x49a302ca, 0x39f59027, 0x22c1babb, + 0xaa0d25c2, 0x3f5588cd, 0xdeacac95, 0x54afd192, 0x3049c026, 0x14cc7b0b, 0xdfe42222, 0x49c6ad97, 0x07d76e54, + 0x41c2c020, 0xa42c216f, 0xe8b74f8b, 0x76467c2c, 0x5586a1ec, 0xeb23f9dd, 0xc6139d5a, 0x55dad65d, 0xabcc79a9, + 0xc5fae296, 0x673dc594, 0xdf77c57c, 0xfda0a53e, 0x669803fb, 0xb0071015, 0x46b68c77, 0xf0f027ad, 0x90abce91, + 0x15d5b842, 0x3bb7ca0a, 0x65cbd071, 0x1b459324, 0x74a4be12, 0xdbacf02c, 0xf94ca952, 0x61176851, 0x506033e0, + 0x0edbec9d, 0xc4176356, 0x0984f55c, 0x319ae3b1, 0xdcc6c508, 0x9c7c5559, 0xc2d0e833, 0x6de8d2b3, 0xb3e22266, + 0x320a5aed, 0xc4e4c878, 0xd2ac623e, 0x5d686856, 0xcaa2c3bc, 0x4bf057ae, 0x5f8e6e37, 0xe429d43a, 0x91e32b3a, + 0x79b0a7bd, 0x043b701f, 0xaed7fe36, 0x35cd9873, 0xf0332f99, 0x619a76a2, 0x1874a6b1, 0x97126880, 0x1e1b6ea3, + 0x31ad5d50, 0xdf3e13d3, 0xff11540d, 0x0fb3a964, 0x26faadaa, 0x736124b6, 0x73c3fef0, 0xcf85396c, 0x46305af7, + 0x7bc3712e, 0xdb73d556, 0x70bb193d, 0x1dc77807, 0x258f39f4, 0x7da7d3da, 0xb022c32e, 0x0c866284, 0x34d06bc8, + 0x5e6d19c4, 0x16cf0f98, 0x7e7b9205, 0xcb6f960d, 0x560b2f66, 0xcb14a2ec, 0x58b01d4b, 0x992c087e, 0x2ed41340, + 0xbac9c221, 0xe08f8930, 0xf5b950fb, 0x82a8721e, 0xfc74aab6, 0xa0bd76fe, 0x56c8492a, 0x0c534d04, 0xca03742c, + 0x92d9f27d, 0x20ffb83c, 0x96964790, 0x598376e6, 0xd7e87de4, 0xb4fd665d, 0x345f31eb, 0x48300772, 0x5f43a862, + 0x2a0111ae, 0x6020a086, 0xb1107fa9, 0xc27a9e03, 0x243efacb, 0xf3f92bfe, 0x1d33d70e, 0x182d0383, 0x1ed392ac, + 0x7527318f, 0xda45192a, 0x35fe6f62, 0x3d3ae88e, 0x107c9cea, 0x7f474886, 0xae083be7, 0xb85cd276, 0xd0d2e7b6, + 0xdf1f34d4, 0x59e7375f, 0x0c274788, 0x262227fa, 0xcd445fd0, 0x3e9cb133, 0xcf3227ac, 0xf9889cf8, 0xe04238c5, + 0xefef1221, 0xc230212a, 0x35f61fe7, 0xf667a296, 0xceadfa15, 0xc7808eed, 0xf71eeda8, 0x3ad5f1ac, 0xa775b61f, + 0x43c216d0, 0x83f038b7, 0x21e87371, 0x79f7ff0c, 0x89cc605a, 0xd2516645, 0xda3ce809, 0x9e5f2f58, 0x1862d204, + 0x039faf76, 0x9ec8cc90, 0x49010b82, 0x589b8bc9, 0xe2a15a1a, 0x065d3c04, 0x3b4488e3, 0xa2d780d0, 0xfc601adb, + 0x9bbf3355, 0xbda7d467, 0x32b6a01c, 0xe0f22cbf, 0x1ed4d637, 0xb72a0041, 0x944ce209, 0x8069f0b9, 0xe8982350, + 0xce9f1ee3, 0x76a468a3, 0x41f08333, 0xf975d924, 0x14a5cc1b, 0x7ae9f01a, 0x92d8aa50, 0x2f6fa50c, 0x950dc216, + 0xd77be02d, 0x59b441aa, 0x7be1fa47, 0xac5c0bbf, 0x055e5de9, 0x601e0a5c, 0xf6876930, 0x0d3efc28, 0xd4ebef56, + 0xc95ab414, 0x3905c5ee, 0x55422511, 0x8fbab9a8, 0xb0445d5b, 0xd4ea1df0, 0x6a04401b, 0xf934b7a7, 0x01814821, + 0x69fb1229, 0x137c598a, 0x1bdffbba, 0xebc63c45, 0xa9f58566, 0x158d9727, 0xfed12f78, 0x984dc75c, 0xe149044e, + 0x652ac7a9, 0x52980624, 0x5aa6a7bf, 0xd3758c87, 0x7dbbc2ba, 0xafd2bf82, 0x5b19d6d1, 0xe21a0fb0, 0x69959edc, + 0xce273af3, 0x3478143d, 0x8e605101, 0xa8dd171f, 0xf0161386, 0x4505ff48, 0xa3c64474, 0x2fe3041b, 0xcb655c89, + 0x3021e6e3, 0x9221f77f, 0xce620101, 0x656750c7, 0xd2882e18, 0x808436fb, 0xed647ad0, 0xb5f812ab, 0x2dcb12fb, + 0xfc8d152f, 0xdb9d2a63, 0xbaaa2826, 0x88453ded, 0x37de8439, 0xcfc8b2df, 0xd631119d, 0xa44ecb4d, 0x693ea737, + 0xa09b1685, 0x27129589, 0x3b4a286e, 0xbc257273, 0xb0d70f9d, 0x7c237fb0, 0x12fda864, 0x0f6d340a, 0x640761f0, + 0x8cece839, 0x9f3cb439, 0xdd5ccf2e, 0x9b3eb852, 0xbc37b754, 0x37279b9b, 0xce515e42, 0x0f364907, 0x9307df58, + 0x08074c85, 0x40311061, 0x38f6b27d, 0x79864ce5, 0xbfa2f7f6, 0x3b34b448, 0x5213e556, 0x94a35b73, 0x38eaf84c, + 0x574ab1d2, 0xeae60998, 0x814cb83a, 0x5e9d7e42, 0x0a1bfe90, 0xc22af936, 0x7df24744, 0x63685aa0, 0x77d11671, + 0x885bd5fc, 0x0faf968d, 0xfc8aac1b, 0xb95e06d1, 0x5af73b7c, 0x441fa5eb, 0x556f2ba8, 0xd96c753a, 0x942b22d6, + 0x34213f44, 0xd90c5759, 0xa1994dbd, 0x7a3d3219, 0x50da32c1, 0xad825b4a, 0xaa2e84f5, 0x7604919e, 0x9024ab81, + 0x4a1e7407, 0xec7baa81, 0x3b54258e, 0x59e3ff1c, 0xa2f60780, 0x6af74d2f, 0xed5ef45d, 0x5ff14b1f, 0xafaca1de, + 0x7e2056a9, 0xfe176aa0, 0xc864726b, 0x471fd564, 0xf73b6f54, 0x2e1251f4, 0xdbd173c7, 0xe877cbdd, 0x2fb2d20a, + 0xeb33930d, 0xf175d3bf, 0x660886b7, 0x8edb0b67, 0xa490c4dc, 0xd5e050c3, 0x5777c8a5, 0xdbed5d0d, 0x9784a618, + 0xdad27f52, 0xdb5a2e3e, 0xb32358d9, 0x215e2632, 0x5c5aef32, 0xf6b34d59, 0x6c297b3a, 0x2583596f, 0x044c8a2c, + 0x80914ed5, 0xaadb1838, 0xcaa081b4, 0xda1bf436, 0xeff0ee96, 0x54302d80, 0xdb4c7d45, 0x261210d5, 0x92a1620a, + 0xf22902ed, 0x605dc195, 0xf1ddeae0, 0x499281bc, 0xfb14159e, 0x1f5bb539, 0x946595a7, 0x5df9ac3a, 0xb2bb1da3, + 0xe5e4d1da, 0x3e1bc5af, 0x91379279, 0xcad9c526, 0x324c38af, 0x08a3f3d6, 0xa2f26de3, 0xec3c9869, 0x5530d330, + 0x9a5ca956, 0x5f7aa695, 0x860e613c, 0xffbcaf4e, 0x6f52d6c8, 0x13f6bd4b, 0x17530745, 0x83bdcacb, 0xcd1bd0df, + 0xae7a3a0d, 0xeb859ca0, 0xbcaebe91, 0x50f8324e, 0xbf0a7421, 0x5604603b, 0x523f5cd0, 0x58007227, 0x2c75ea86, + 0xd27825af, 0x7e01128e, 0x19b42dfa, 0xff3584c6, 0x6a81cf4c, 0x61169f2a, 0xcf859f1b, 0xa927ecf2, 0xb65e0fa8, + 0x8cf7b460, 0xc3126292, 0x3573bd72, 0x363de510, 0xe2aefc38, 0x246312b8, 0x85779de9, 0x360ae9ae, 0x62356a0d, + 0xfb0d7699, 0xd44c549f, 0x1e218102, 0xe3a6c9dc, 0x3d990349, 0xdaca851e, 0x21de4f35, 0x3841e9db, 0x9d40621e, + 0x752ec619, 0xabd062dd, 0x11f2f499, 0xf24cb9c6, 0x27752311, 0x32ae7b2d, 0x9b9ce4c0, 0xd3fdf176, 0xa4246c8c, + 0xaaf91cc1, 0xda628b44, 0xd64a2695, 0xfd2cdb02, 0xacde1eeb, 0x7f123f59, 0x321e2329, 0xcf3b4cdf, 0xaa8a0931, + 0x1d4ba935, 0xcb85a9af, 0x3b1b425e, 0xfcf55598, 0x12139d93, 0xa9a5784d, 0xb71f4dc8, 0x51a59b2e, 0xde3806f2, + 0xba01838c, 0x7bf2c785, 0xa49ab478, 0x0e832147, 0x2466e1e7, 0x8d12cdcb, 0x7131483a, 0xe86510fc, 0xed59e35e, + 0xbe88c612, 0x532f32d6, 0x1575427c, 0x5a9e3433, 0x760c33cc, 0x16611614, 0x8bbafe76, 0xecd5d639, 0xf58651c0, + 0xc3f33bde, 0x0fcfae5b, 0x9bddc01f, 0x10f0da1e, 0x2914ecdd, 0xb8948f29, 0x51964075, 0x47659ac5, 0x09d6787b, + 0x2a48bf20, 0xe30da105, 0xf85b4edc, 0x3309ef28, 0xc089876a, 0x1c86113c, 0x0c4cb7fd, 0x77f25bd0, 0x127930e8, + 0xd716dac8, 0x9bacde6c, 0xfed65671, 0xb2b3c7df, 0x2fbf96ec, 0x45ec9469, 0xf84ca8cc, 0xfbe23467, 0xe79b765e, + 0x81e25e44, 0xe83932ef, 0xcfea2c24, 0xa331be5e, 0x2e139395, 0x2409eed9, 0x0475b1e7, 0xc0861aa0, 0x3505502b, + 0x6d23d20d, 0xa8653833, 0xcf6d8587, 0x42623673, 0xac8a970b, 0x6dbb2fe2, 0xd60ad59c, 0xe9267e5d, 0xd5574f95, + 0xa7d4fc8f, 0x76f2d62d, 0xb8171aec, 0xd3e023be, 0x8e6883b0, 0xe57c0cc7, 0xb1e85bb9, 0xf321134d, 0x9b2d4fe8, + 0x17d7b82d, 0x76fd9f79, 0xbd8db7fd, 0x035240cd, 0xab188df7, 0xf57d5439, 0x153c8035, 0x5e3f7ad8, 0x88a2ec82, + 0xa69d6194, 0x24bc21b6, 0xf14bd5da, 0x2c0976f5, 0xd724f1e0, 0x33124b2e, 0x303cce39, 0xc8ab3aa0, 0x5b25c92c, + 0x0462f6cd, 0x9d4d8acd, 0x9858d47c, 0xf82f1532, 0x6642df4a, 0x67da3299, 0x487db0a1, 0x8be6cd08, 0x0cb04d3a, + 0x70007b69, 0xa3f17f34, 0x89752904, 0x2c062f34, 0xfcd773df, 0x0cf1c993, 0x7c299a8b, 0x50c03d80, 0xf293d138, + 0x979e075c, 0x4cd5b344, 0x75fb4e33, 0xbc14cfa5, 0xfefe118e, 0x44849d8f, 0x703846c6, 0xac5e7f29, 0x6ded8dbb, + 0xda187e0d, 0xb745f890, 0x4d793a47, 0x3b41bdf3, 0xa92ebe0d, 0x95ea3394, 0xc715d3c3, 0xdcc1a3dd, 0xb3afc3bc, + 0xd3c94c3a, 0x8d30ce49, 0xa2dd41b8, 0x6023cba2, 0xdc73ea99, 0xe7ca6373, 0xac0f8836, 0x266ca08f, 0x879798d1, + 0xeb964907, 0x2aa9cd9e, 0xefb203df, 0x5e30f5a5, 0x846e33cb, 0xc1cc3519, 0xbc49f297, 0xb72b7193, 0xfcd7cd3a, + 0xeaf88a5f, 0x59fea936, 0x93b66790, 0xee5cd842, 0xf23847b3, 0x439e65db, 0x7c519349, 0x4df56baa, 0x9ffb9f08, + 0xca6d45a9, 0x9165a12b, 0x77df38a9, 0x311e980e, 0x196c60c8, 0xed094866, 0x27afb1ed, 0xf9048855, 0x8d049768, + 0x1dac534d, 0xf5f0f6cc, 0xf2637eac, 0x7a2793bd, 0x20e3ef34, 0x76c8a919, 0x07670779, 0x20fca3ed, 0x9cd5783d, + 0x75367b83, 0x0028a3ac, 0x882e4639, 0x60fb128c, 0xc2a66209, 0xede7d92a, 0x7cd26498, 0xf17f397b, 0x915e468e, + 0xf5de7e9c, 0x5aff6a08, 0x1c176cb9, 0x392640a0, 0x06836e18, 0xfa053fda, 0x4d1323e1, 0x7aa08b4b, 0x5422b721, + 0xd4fbe0e6, 0xbe7b132c, 0xcc5ec1d8, 0x568026b1, 0x433c460a, 0x26d7e02e, 0xe85c63c6, 0xe4893895, 0xb043f431, + 0xe1821f69, 0xabc19fab, 0x918d7b00, 0xe0d2e111, 0x5f522952, 0xc86c64ae, 0x53499abc, 0xaad2372f, 0x007017a9, + 0x32ac3376, 0x7962a0c3, 0x1716fcfc, 0xad28ab21, 0x39ef81f0, 0xb43bacc8, 0x9b44ff72, 0x1ec02dab, 0x30e87978, + 0x29674d65, 0x975ae240, 0xa75fd903, 0xa147ec86, 0x2e33b868, 0x9e0571ce, 0x48184e49, 0x2f6f4f9d, 0x655479ea, + 0x9e10fcdd, 0x05072ef4, 0x31c15d8d, 0x97f56e51, 0xcb56daa0, 0x8904c0ec, 0x5d25c223, 0x13977e7c, 0x620a004e, + 0x7ce503c0, 0xd7552308, 0xa7de4570, 0x363cc34c, 0xcb19a730, 0x9c2ae256, 0x5d3df159, 0x321c849a, 0xb7456b4c, + 0xb0ad52e8, 0xf55fcce2, 0x69cd9346, 0x3cc5cee0, 0x4ce3cd05, 0xfc877580, 0x2e29039e, 0x81dd5804, 0xaa6120dc, + 0xe8ce9b8d, 0x9ba612d4, 0x119d70f9, 0x3f8919b7, 0x7fa7f1d3, 0xd6d09854, 0xc6c2c565, 0xf913e38d, 0x832cad18, + 0x022fe648, 0x72b081e1, 0xca9af630, 0x427af390, 0xf0912c0d, 0xa10c6ddf, 0xd6a50f84, 0x96a64817, 0xd4b1e021, + 0xa7a84f31, 0x10be2a0c, 0x28beadd3, 0xb2446eb6, 0xefac6f84, 0x5a69f9e1, 0xc84e74a8, 0x23b1a7e5, 0xa7043460, + 0xebedc617, 0x031daf74, 0x755a5960, 0x89283d7f, 0x4686e986, 0x991daeea, 0xf73af11d, 0x87ff7950, 0xde8bd3d6, + 0xb3012747, 0x7ab47bda, 0x6de6df52, 0xd4c11187, 0x847733c0, 0x11980af7, 0x84d9aec2, 0x8bb3793f, 0x67aae935, + 0x4e955e99, 0x65ca076e, 0xadb6fbcb, 0xad0daaf7, 0xd7a39cfa, 0x1b0fbceb, 0xa75bad54, 0xb3f35e5f, 0xcdb6ba3d, + 0xee524887, 0xa362efc7, 0x287372d0, 0x2a505853, 0xd057e3c1, 0xcf8eb6e0, 0xd222dcb2, 0x6c9e14d3, 0x88b1a103, + 0x63f4b98c, 0x898a1531, 0x0e43bb3a, 0x6bfbca2d, 0x5adfe777, 0x5aa916b7, 0x483e03bd, 0x4479d6c2, 0xd2c91ba8, + 0x770d4eda, 0x7a9ee154, 0xf665bfe2, 0x28fc8314, 0xe77b7e78, 0x9303658e, 0xaeee99bb, 0x6e12bee8, 0xebbfad69, + 0x0504bd5d, 0xd919a6e3, 0xd1501884, 0x1b2bee65, 0xfd969556, 0xf213c087, 0x7bdc6f46, 0x7d302030, 0xa862263d, + 0x45428155, 0xfc4a5cd4, 0x70fc0546, 0x7f175cf4, 0xeaaca4f9, 0x2e11c49c, 0xf7aa456e, 0x943f0334, 0x0f9048e2, + 0xc42aabeb, 0xb1a631a9, 0x572de75a, 0xc88c715d, 0x43112d07, 0xf69a2efd, 0x139577f0, 0xee88fc08, 0x065bd1ba, + 0x7a6f322d, 0x415b0f9e, 0xbde43956, 0xf85b5f40, 0x8afd0451, 0x54ae9688, 0x1f11a5f7, 0xdeb193bd, 0xa3984f50, + 0x6b29351d, 0x72a4e552, 0x0fabfe83, 0x0ad1f091, 0xb1490268, 0xf6432c18, 0x4754af47, 0x85fd28e3, 0xcf1ebe59, + 0xb61da9f7, 0x1ab6759b, 0x0cb20770, 0x909c9bba, 0x3d62096f, 0xeeae1095, 0xa15ab690, 0x1608ce7f, 0x2eb3f65b, + 0xe4a9f83d, 0xa0cbfc1e, 0xb6e35c21, 0xb0a4f47b, 0x4ab385ed, 0x42017af6, 0xd80b2ae5, 0x44673cf4, 0x7366d0dc, + 0xcc5ca235, 0x69ae60b9, 0xb3058273, 0x542d72b9, 0x571d110c, 0x5cbf7f75, 0xc4250bba, 0xad3765fc, 0xf70915ae, + 0x17ff9ef7, 0x0ca54114, 0xe2c3737c, 0xed8103a4, 0x2ffd18b4, 0x55c17f2c, 0x46f58a75, 0x1587f8ff, 0x1f6bf69c, + 0x013d6e89, 0x67e4fb7a, 0x00bbfd40, 0x0ea21f78, 0x9ff6cf8d, 0x3593f71c, 0xa0f508a6, 0xcbeeb566, 0x937a724c, + 0xfc2db5cb, 0x85cc3633, 0xcd53ca2a, 0x73ba3b0c, 0xda3970d6, 0x50ae90b2, 0x82b4c43a, 0x9b138e32, 0x82f3388e, + 0x16e21e51, 0x0c168ed1, 0xa9cf03f1, 0x50f5c549, 0x9e3ac7ed, 0x09f4ac79, 0x5de697f1, 0x1085ef5d, 0x3f06cefb, + 0xd6b432af, 0x7850f612, 0xc62cbd10, 0xc9087bbb, 0x483183db, 0x17065a4e, 0x9143a204, 0x8c9a6d74, 0x05256485, + 0xdd6238e6, 0x9fba4118, 0xd92f5c15, 0xb13f5c7c, 0x83608c6c, 0xd6cc07df, 0x84c5105a, 0x3e08e16a, 0x80e07df4, + 0xb85ceb9a, 0x471ffaaf, 0x8543dacf, 0x8961b8f9, 0xd03ecdf5, 0xf9cde8f1, 0xcc8ac614, 0xf08eb5fc, 0xf2843929, + 0x6694ec5b, 0xdce0711b, 0x3ff0f425, 0x1341c216, 0x8c058ee6, 0xa4445a08, 0xdb0a4e95, 0x5d5be132, 0x914d11ed, + 0xdd270480, 0x166e4c5a, 0xd5886ba9, 0x2d8bffff, 0xe74a6e02, 0x1c0201d5, 0x756e2108, 0xc299001c, 0x15553ddd, + 0x81f0f38c, 0xfc644e05, 0xc4c15bdc, 0x1e13e99d, 0xb123cc50, 0x6b9483f1, 0x70c1d08f, 0xb2e0a9e4, 0x6232ce08, + 0x9ebca705, 0x68d9766f, 0x9ae76f90, 0x4aa5ce29, 0x76bfeb7d, 0x8bf11a68, 0xc7a929b2, 0x5af0e2b7, 0xeb91c7d1, + 0xbaa060e0, 0xda107136, 0xd0975fb6, 0x159a3871, 0x27d39603, 0xa690b65c, 0x7dd2a91b, 0xc40da901, 0x553d6fe4, + 0xcdd9a035, 0xc541ef40, 0x41bef7ef, 0x015d1daf, 0x0f4dd752, 0x62a9902f, 0x6d0b2fff, 0x0075f800, 0x8e9c4a94, + 0xb90f5bee, 0x4ad4120c, 0x1c4ae3d6, 0xe209b8a6, 0x620f5648, 0xf967aef3, 0xf31297a2, 0x9233de80, 0xb755073f, + 0xd9ed7410, 0xeb4a6cff, 0xbb89fed3, 0x0d831dd9, 0xe865156e, 0x33dfe16a, 0x48b71ec6, 0x3725f63c, 0x64b3db56, + 0x524aecfc, 0x067bd63d, 0x45ca8a38, 0x0cc56ac6, 0x70a98a53, 0xc3692544, 0x4bb65df7, 0x45758902, 0x2203e360, + 0xdfcc3cd4, 0x4bd2e673, 0xaa08e960, 0x0f26fa6f, 0x6fb555c8, 0xb2cf824d, 0xbdfbbfa4, 0xcf2339a8, 0xe13bdca1, + 0x586643af, 0x48daaf9b, 0x58321472, 0x687d4894, 0x144c7cc8, 0x5e43d3cf, 0x12cfd336, 0xe4474901, 0x3a89c3f3, + 0x4a7bef19, 0x7695c2b3, 0xb008e7a7, 0x5e381689, 0x291e4d86, 0xbac1ac10, 0x687f3bbc, 0x4f73ba2c, 0x260ddbe4, + 0xed2c5549, 0x899558db, 0xe65df4d3, 0xc8d20383, 0x1bbc98cd, 0x0f35941b, 0x40aa8bcf, 0x73606688, 0xe489ef77, + 0xe696859a, 0x0a190d8e, 0x8107131a, 0x670b0a29, 0x90cd079a, 0xc0f620d9, 0x2c9f4e7c, 0x5134e7fd, 0x5ab2f9ed, + 0x3f64e4ca, 0x20eed2e6, 0x15f40eff, 0xd5d0ad93, 0xf9c4f076, 0x3585db36, 0x9ade8fd4, 0x9f039887, 0x20cf3e8b, + 0x83b6d041, 0x0dd47c2f, 0x5db94f2d, 0xcac1b257, 0xbef774c4, 0x6326cb57, 0xafd0689a, 0x125dc762, 0xfe799c65, + 0x3da42c81, 0x963c0d14, 0xdabcddb2, 0x988446a8, 0x5f04789d, 0x7dc414ed, 0x104b1835, 0x0dc28cc1, 0x67feb8ce, + 0xcccc95f8, 0x34f8cf19, 0x3a3a04fe, 0x0b4365d3, 0x551407a6, 0xc126bf6a, 0xa296042a, 0xfe01b371, 0xe99dd1a5, + 0x638a9da2, 0x7ed013ba, 0x08ed6e32, 0xda14c13d, 0xc6e3481b, 0x9560a2ef, 0x89b023ff, 0x6741dad8, 0xbfab3400, + 0xfc8d772e, 0xd25dad55, 0xf3968def, 0x1f727b2a, 0x30db3752, 0x6d59486e, 0x1784d0f8, 0x32bb6a4b, 0x880082ba, + 0xdf5d47bf, 0x4deb44f8, 0x9a84fdd9, 0xdeb44621, 0xa4d8f980, 0xa9d57be9, 0x3dc2002b, 0x4f99a441, 0xd28ed10c, + 0x8e932302, 0xd214491c, 0x37620b46, 0xbc98a730, 0x7aeb1dbe, 0x2887604c, 0xf1db118d, 0x9410b6e8, 0x8ccc6366, + 0x5c9b4622, 0x6ffea290, 0x1f66d1e7, 0x2dc64da8, 0x7910bc88, 0xaa469370, 0xdaeb9582, 0x9e8edaaa, 0xccaa5d39, + 0x79b898ef, 0xe8031450, 0xf3468343, 0x3b9db4d9, 0x923f2394, 0xf771af89, 0xcbde2cb1, 0x358571e8, 0x5e3862ee, + 0x354d3d1f, 0x422a6ab1, 0xdef74574, 0x35480d68, 0xe072a815, 0x2d6fa8bd, 0x6ebfd80e, 0x8d7b7b13, 0x5cdf0f88, + 0xe2dfc3c4, 0x8411a55b, 0x181722b9, 0xde4edf71, 0xa5b85bff, 0xf499a684, 0x3c504065, 0xb86ed751, 0x81a4691d, + 0x06965b19, 0x2da10dfb, 0xfedc55b3, 0xc875ede8, 0x5b2d35ba, 0xa94471e8, 0x6d68d65f, 0xf350c59a, 0x9277508a, + 0xc96aaae8, 0x85902934, 0xdd3bb501, 0x9062ccbd, 0xf73fc0b0, 0xa14c9f51, 0x240cb5cd, 0xc0401895, 0x603c2eb7, + 0x14aaa789, 0x0a0eec97, 0xb68d3dce, 0x6360f282, 0x5cdd51e3, 0x3d7a324f, 0x92b15c56, 0x66dd6354, 0x13f8b1a2, + 0xe2d40d1c, 0x34446bd3, 0x3a889ce4, 0xcd3b6d02, 0x4a00f74d, 0x7a23278d, 0x09a6c902, 0xd5be6897, 0x7aa3f847, + 0x13321c38, 0xa76f96d1, 0xf40619c6, 0xe7a08661, 0x2126d2e7, 0xe997af38, 0xbe224c87, 0xc8a77f71, 0x69eb8479, + 0x495370a2, 0x62df2820, 0x1919549c, 0x4dc0262c, 0x2f5f88a7, 0x2afe2171, 0x832fba1a, 0xb83b2cfa, 0xffc9b8c0, + 0x731f5e08, 0x09b66b47, 0x3185370b, 0xee69ff21, 0x3ad5569a, 0xb2123d9e, 0x25a401f6, 0x8176ff2e, 0xe65c764e, + 0xa8955a3f, 0xf57acb1d, 0x03ad7252, 0x174e111b, 0x5d50ac38, 0x5f6d1238, 0x1f8e6cb3, 0x58846072, 0x71cfbe94, + 0x79910bf4, 0x4183bd21, 0xf01e2881, 0x7ef245d8, 0x08652d57, 0xc8e96f09, 0xe2a6a643, 0xa0b25044, 0xfcb51923, + 0xe56d087e, 0xb4f14f02, 0x8369feaa, 0xa6f2ec69, 0x7d348a1d, 0x24bce7e8, 0xde60fa8c, 0x3b6a0d2f, 0x35925d74, + 0x7c8f48ac, 0x76cb8974, 0x7bd08366, 0x5032eaee, 0x8dc6de32, 0xe46df6d6, 0x8d511c24, 0x9c5188d2, 0x3620364d, + 0x63455d4d, 0x424fa740, 0xc4fd2d4d, 0xc86e3d47, 0x3f338f1d, 0x8dea0807, 0x84f33289, 0xa08127dc, 0x2901a3ef, + 0xea1da0d3, 0x89988481, 0xd4113b30, 0xbfe6e19d, 0xd4256e22, 0x666fed6e, 0xe0fc8055, 0xa1d41315, 0xed985349, + 0xd2cbc84c, 0x96449c50, 0xd1a6b056, 0x1f92d059, 0xd2b6604e, 0x0881a6c1, 0x93533fe0, 0x527a2192, 0xfe8472e3, + 0x1c4247ef, 0x6e906739, 0xd2e89c9b, 0x5ed52e11, 0x42becef0, 0x2e324faf, 0xc5636ec4, 0x89170cf8, 0x899da25f, + 0x1e766e3f, 0xab57a52d, 0x6a21a6e4, 0x502105ab, 0xd4b83d49, 0x0ba96668, 0xed2dd50c, 0x8d6d1e48, 0xb8ec5858, + 0x98badf8b, 0x732fc8b9, 0x767ebdd4, 0x067b678a, 0x277d3c0c, 0xc4100433, 0x84ef9f15, 0x34ab61ec, 0x7dab099b, + 0xd40854e9, 0xa1539fe1, 0x4ec33d63, 0x98f3a6b7, 0x16f88a60, 0x91970f77, 0x041ee657, 0xd437bc54, 0x55a07812, + 0x1c187abf, 0x53e7bf68, 0x88d2b0a4, 0x3a1ece6f, 0x1be0459a, 0x703303f8, 0xcae5e4cd, 0x3c71d9cc, 0x12b98a9d, + 0xe58f05b3, 0x3593e29b, 0xb95c4d6b, 0x43b4e856, 0x321bb11b, 0x76f20e03, 0x23c1836e, 0x0306b4a7, 0xb162cc53, + 0x29d0ae23, 0x332fda99, 0x9ac01273, 0x98105496, 0x00d1ee7d, 0xd4024bd5, 0x63ff7c90, 0xa71e0799, 0x085cfda5, + 0xa92a25da, 0x7ea99dbb, 0xe9e1de10, 0x84394828, 0x0fded4fa, 0x721eb480, 0xda302cba, 0x40cf6498, 0x25ec4f11, + 0xa98d0bb3, 0xbed64e69, 0x3d69d532, 0x60fb28d6, 0xae047ddb, 0x9f631c8a, 0xe1ed547e, 0xbb7b2e4a, 0xa2c5b8c1, + 0xeca12c60, 0x7a724d1c, 0xf5a01221, 0x34cbbc06, 0xc60235f3, 0xb31a4e2c, 0x43ca2e74, 0x03534a61, 0x1c9c1748, + 0xf527faed, 0x83943d94, 0x0f1609b7, 0x496eff3b, 0x8f3638a0, 0xc89d95a7, 0x0e89bbb8, 0xcc23ef87, 0xcccebdc2, + 0xb38cc06b, 0x7de3d97f, 0x1fcb7a3d, 0x7079269a, 0x4bdb4617, 0x340df96a, 0x77eb466a, 0xc3287bc4, 0x2c9ad4d2, + 0xec14f8a8, 0x7b238059, 0xf9c70c60, 0x95bd7817, 0x08055840, 0xbcede233, 0xfd3a361d, 0x68e99c4d, 0xe2ab6c83, + 0x38a84773, 0x30306972, 0x8aa2b612, 0x8e069cc0, 0x991c7230, 0x911b7a7e, 0xfdadb917, 0x5e9f4a6a, 0xc7711eba, + 0xbb9d8f94, 0x2ffdb9a0, 0xb59729ed, 0x55bb1d35, 0xf94786ab, 0xee65b73a, 0x9c667611, 0x42e2828e, 0x739435e4, + 0x5878db40, 0xb6feb907, 0x51fb08d0, 0x278857c1, 0x35d94311, 0xd7d7cdc1, 0xc8ea8505, 0x40ae102c, 0xf0511c24, + 0x9421715a, 0x96b7d514, 0x7ef248c3, 0xac27c169, 0x47d2780b, 0xdd426af8, 0x0d97e427, 0xe41de097, 0x81aec73c, + 0xbe66cae7, 0xa86db10d, 0x50c5278c, 0x8d0c61b2, 0xca419636, 0xd8faae14, 0x392d51b3, 0xae5a5c74, 0xed362d92, + 0xe78870ec, 0x41ff4098, 0x2868fbce, 0xfc559000, 0xff3e7ca4, 0x522901fa, 0xe3d299ef, 0x9f968c6a, 0x34ecf27a, + 0xa0b7f06f, 0x08cdd08c, 0xd41dc035, 0x821f487b, 0xde4e4298, 0xe75bc7ec, 0x94d038ac, 0x4bac68e0, 0x4d54a68c, + 0x0e4a584d, 0x301cea2c, 0x068957d0, 0x7a6dbac0, 0x0adc3ae9, 0xd5eb1a70, 0x3455253e, 0x95b765ef, 0xfed56d7e, + 0x1a4c0597, 0x87c9cdb0, 0x99c929a8, 0x3224467a, 0xc4d56b23, 0xe4ac7d1c, 0x9a24146d, 0x851c7ab1, 0x737b18be, + 0xbbb29f11, 0x31717da7, 0xfa7f4f63, 0xcc75ea58, 0x75ec8068, 0x9f731dc2, 0x340a9992, 0x01b98aa8, 0x26c06a6c, + 0xa8033f5d, 0xb2f0af6c, 0x88f380c7, 0x13b548cc, 0x2ad7637c, 0xd5fe5b57, 0x8e9d417b, 0xc467cbd6, 0xa586e119, + 0x24235bbb, 0xfad47344, 0x25196989, 0x05d3ba95, 0x1a1162c9, 0xad8c48d8, 0xcd4e2c2c, 0x03aa0102, 0x46557845, + 0xb18d23b9, 0xde795c56, 0x1a141d73, 0x0d93b7f2, 0x2f7c57d1, 0x117e939d, 0xfef676a5, 0x96dc824d, 0x82e7aa26, + 0xfc2fcf61, 0x26dfa54c, 0xadd425a5, 0x46655da7, 0x8485a18d, 0xe916e5e9, 0xc530047c, 0xc38da924, 0xced33b8e, + 0x34e3014c, 0x4782c310, 0x29b88b55, 0xfab47092, 0x4d3613e8, 0x1643cbf4, 0xc0b26c51, 0x0d67be24, 0x6c3cf90b, + 0xab9edc36, 0x5b3f56e0, 0x1f25463a, 0x908492b6, 0x6452df31, 0xcf20f0ae, 0xcb962fac, 0xdddff46c, 0xb1c3651f, + 0x8dbba73e, 0xa299d87f, 0x64843fce, 0x70746bbf, 0x87215c66, 0xa5a416cf, 0x8252aae8, 0xef4b1602, 0xd4b1595b, + 0xee0de83d, 0xaefb42a2, 0xd69b6316, 0xd86b6de5, 0xdb0fa31d, 0x12b67fac, 0x58dba93d, 0x0380fa5d, 0xdff52dd2, + 0xbda0db6c, 0x674a86d3, 0x99d1e481, 0xc83f56a2, 0x9466921a, 0x987c7ee7, 0x2e55c171, 0x06af5743, 0x370dfe3f, + 0x5176feb7, 0x175a1e9d, 0x71e4db57, 0xcc605f61, 0x0f1252ba, 0x8b397a68, 0x6d54cc6b, 0xcf2b49c7, 0xca39efaf, + 0x215305b0, 0xe56d4e27, 0x3ed99a10, 0x1c81e683, 0x2966314d, 0x48bbe8f4, 0xa043884d, 0x3eadd973, 0x390388e7, + 0xc4bb43ca, 0x95e7f6f1, 0x74dd9738, 0x2be74fc9, 0x478f9d4c, 0xd1ba3dcc, 0x6ec72eab, 0xf0bc85d4, 0x93547444, + 0x1af89959, 0xa3f07ec5, 0xefb1ee5d, 0x4b84f776, 0x8da84ddf, 0xc7a8e371, 0x37e02a8d, 0xcafcf3e3, 0xb1def212, + 0x30736ed2, 0x19098fd0, 0x18e108d3, 0xa5a40ded, 0xbc2bd9dc, 0x79f3d71e, 0x3383ceea, 0x76e8e383, 0x374a0624, + 0xf81fa6ab, 0x77219ae0, 0x008e5dfc, 0x214c73d2, 0xcc1ddd20, 0x2a5fc5be, 0xa9db8a19, 0xdefdeca9, 0x0e72a5a6, + 0x00da676c, 0x45570fbc, 0x9cb07655, 0xd355b81e, 0xcd0fe751, 0x10ad3e3f, 0x73b66e59, 0x9504bb2c, 0xfe35807f, + 0xdc374441, 0x69b9657c, 0xfae3f7d9, 0x7554e137, 0xcf30fadf, 0x6034f440, 0xd3f05567, 0x1a60236a, 0x44179955, + 0xc2f66a01, 0xc3dd3ced, 0x6563d2e6, 0x3e39fc4d, 0xaefe30bb, 0xabde7d75, 0x8d772dcb, 0xbc611d2b, 0x84a43be5, + 0xaec403fc, 0x7911c6d3, 0x4bf44940, 0x5c7045ad, 0x1a9924a9, 0x7483c7d0, 0x432f2e23, 0x1febb24a, 0x429d7ef2, + 0xfcc9ad33, 0x601ca0ad, 0xa5e66ff0, 0x7189a747, 0x804c4c13, 0xe71e953e, 0x953cfaf2, 0x1af86b9d, 0x11633c5d, + 0xaa14bea1, 0x7ea1d47a, 0xb49f4cad, 0x9f4c3f8b, 0x3c3d33df, 0x8cbe7dd4, 0xf7623194, 0x73acd72c, 0xf1705d45, + 0xaa0cea5f, 0x92a158c3, 0xeeaf07aa, 0xff989619, 0x50c8ab58, 0x256587f1, 0xc6040d40, 0x335c408d, 0xa78c2fa2, + 0xbf0c7f80, 0xeca04a7c, 0x4de0c6b2, 0x27c1af40, 0xd3aed585, 0x689111aa, 0x72b6d6d3, 0x929c93cf, 0xe8efc538, + 0x2ff7c568, 0x1a944d7b, 0x81e21598, 0xeef98caf, 0xc6ff22c2, 0x360feefb, 0xedb05599, 0xd14ddb6d, 0x7d1e7e36, + 0xa8159551, 0xa78f6000, 0xa32b1867, 0xe19a14c8, 0x9e80be0b, 0xc672b5de, 0x83a050a5, 0xbdfaf3d3, 0xa5c58db7, + 0xf0c4612a, 0x80c3ab88, 0x453798eb, 0x113db7bd, 0x802f6e2c, 0x97c123de, 0x253aebab, 0x25a63df6, 0x3a5a82db, + 0xece27040, 0xdeeeaec5, 0x7132ddeb, 0x8e5ae95c, 0x73a04d51, 0x9bbfcd86, 0x12f19e5b, 0x06ae1487, 0x377666f5, + 0x78a73402, 0x5047f5ce, 0xc76eede9, 0xe0331027, 0x0cda4fde, 0x158721e7, 0x3e00ee4c, 0x72353d98, 0x4d163e82, + 0x81f7c12e, 0xf5dfa6ab, 0x2c54df9f, 0xf864a560, 0x8a0376e9, 0xb903cf4c, 0x703d492d, 0x1b83f0b9, 0x327bde97, + 0xaa508449, 0x848295e5, 0x48450b8a, 0x63f7ebcd, 0x95755cc7, 0x8971df40, 0x42b96edf, 0x132b1f2d, 0x007c876e, + 0xd8cf332e, 0x1ea6ce8a, 0x57b5adc8, 0x4fa96067, 0x120374ae, 0x60c5b32a, 0xadd413a7, 0x0f7e6aef, 0xe361f46b, + 0x4e6f0ece, 0x722c276a, 0xf4ac390b, 0x7647f0ad, 0x0e2d52c5, 0xfde81653, 0x0b876dd6, 0x68da346d, 0x91f620fc, + 0xeaf8244f, 0xde173a9d, 0x4a7e4966, 0xcc47a3d3, 0x22621de2, 0xce51fba6, 0xef272d45, 0xe606c467, 0xa6824321, + 0x8d659f0c, 0x08c353e6, 0x5e0988ca, 0x7561676d, 0x5bcc284d, 0xc5130a1f, 0x74f1000c, 0x70809cca, 0x1afa996a, + 0xc5e7438c, 0xb47549c0, 0x05cb1ef8, 0xcfa5923c, 0x1239b442, 0xa3d0a732, 0xfa0cedde, 0x97015471, 0x4a738eb0, + 0x4f2409cc, 0xfce6dab0, 0xb62aa8f1, 0xf64633ca, 0x91fa0fba, 0x6bfd0838, 0xe3d62dd6, 0xec67752b, 0x47d8bcae, + 0x581fbdda, 0xbad6a138, 0x25aaf6ea, 0x702b1777, 0x9ebf9601, 0x7bed00a6, 0xd6f201a5, 0x561b4e3e, 0x4ded51be, + 0x730ccd34, 0x016805c6, 0x38ce1de7, 0xe2be56c1, 0x87a6f6a2, 0x025fc689, 0xd317390c, 0xe0eef339, 0xd3b47352, + 0x2220c5ec, 0xadd71a38, 0x26f1fe68, 0x8a6aebe5, 0xc634c537, 0x79144597, 0x3cc35c48, 0x9b18e922, 0x45950044, + 0x40014cb4, 0xd3d3d686, 0x18b43123, 0x99a706e7, 0x5c5098ef, 0x741e9fb9, 0x691dbfee, 0x871e1098, 0x3b21ef41, + 0xe32bd8cc, 0x0fa0a9e6, 0x8dce9e98, 0x4aa66b65, 0xb12dfb3b, 0x337c57bb, 0x375933fb, 0xa62e067f, 0x43a53736, + 0x23aa1132, 0xfbc3ed15, 0xda28744d, 0x6843bfcb, 0x58b7d390, 0x27c59288, 0x6a5e9d1e, 0x83c25a4a, 0x6c6c1395, + 0x1645a42e, 0x8f061a2e, 0x2b1c5443, 0x7ab6e8a0, 0xfe8c83e8, 0xcaa1aab1, 0xbc71adf5, 0xd92a4a10, 0x71edd9bd, + 0xf84dd23a, 0xec28e740, 0xb2974090, 0x5d3d1a13, 0xbe75f404, 0x6a66e3ea, 0x65704592, 0x84fa1a5d, 0xd2d3cd13, + 0x78af1bc8, 0x07e39b66, 0x76761fd4, 0xfca0d7f6, 0x4516350c, 0x43f19a61, 0x883b3397, 0x14273619, 0x0f12e9c8, + 0x612dd999, 0x5847d139, 0x50ce8723, 0x16374770, 0x1531c79f, 0x64743bc6, 0x9fd8c0a7, 0xb1c7c8ad, 0x9e15e57d, + 0x27efdcf0, 0xae722071, 0x0f33ba24, 0x4fe627aa, 0xee204721, 0xea681951, 0xe1771806, 0x6d05c98c, 0x0a4f588c, + 0x693024c3, 0x3ac52677, 0xf3f65a88, 0x66e859a6, 0x43624693, 0xc2a59616, 0xd13f1c94, 0xf4e0739e, 0x80f109c7, + 0x5ba80726, 0x4c45df55, 0xb7abc698, 0x4187ae0f, 0xdcad92c1, 0xbaee0af7, 0x5fba3be7, 0x6c5d26cd, 0xd7965b4f, + 0x64901fa9, 0x99852bd5, 0xc2968823, 0x14422c97, 0x58f243c0, 0x6bf77fe7, 0x86eb6ede, 0xdd0b4179, 0x59d1b820, + 0xe9a7ce93, 0x205bc096, 0x8e965140, 0x568ba158, 0x785d51c6, 0x20ae57fa, 0xe5ce4c00, 0x1573471a, 0x0fe76109, + 0xcf38b78e, 0x27cee8b9, 0x8d3ae611, 0x281a3e9a, 0xa7b9bb16, 0xdfc4edd6, 0x527b4dc4, 0x59e5c1f3, 0x645906d3, + 0x02fb03a3, 0x71ddca75, 0xbd37db1c, 0x502a29dd, 0xd241e989, 0x90294b85, 0xbd49fe05, 0x65bc0505, 0x1f6da3fe, + 0x495c6c4d, 0x8429ce75, 0xf956ddec, 0xf136a299, 0x31a214c5, 0x144c284b, 0xa26a9124, 0x05976734, 0xb647079e, + 0xa2688315, 0x8b432609, 0x9a181f03, 0x3db26797, 0xa68fae54, 0xc4a595bc, 0x8e7e201a, 0xab1b4462, 0xcb8bfd2c, + 0x73c31896, 0xda5641b9, 0x0297d2f0, 0x746a28a5, 0x08f9d704, 0xaf37c11c, 0xaac1c9bd, 0x43b71bf2, 0x8d22b81a, + 0x621f296e, 0x55e4c5f4, 0xb7391723, 0xb56132d0, 0x9fac9b0e, 0xd169922f, 0xe972bcf3, 0xfed95c9a, 0xdcbeaa3e, + 0x23240b8b, 0x46f586bf, 0xe49f10dc, 0xbe95553b, 0x9e94bcfb, 0xf0bda0c9, 0x09c4dd99, 0xadadfce5, 0xa5e95f10, + 0x818348b4, 0xf8da1f8a, 0xbb0a3963, 0xe1825ed1, 0x02bdcac3, 0x8ffe867e, 0xd7cbfa6e, 0x72d00544, 0xc71defd2, + 0x0a84492f, 0xc6ec68a4, 0xbd8d24ba, 0xc85364d5, 0x1795eda2, 0xcb267935, 0x910cdff1, 0x280ea378, 0x4f46e695, + 0xb221fcbc, 0x888bebc0, 0x0456d107, 0x7a9cfd2a, 0x6eddb6d8, 0xdda5bd85, 0x6eb48171, 0x6c4592aa, 0x3a43342b, + 0x7fe049ae, 0x547defab, 0x06ba10e9, 0x3f712671, 0x0fd543f9, 0x23f49d76, 0xf2fdedd5, 0x1ec231c9, 0x67f1f493, + 0x0a610008, 0x0568f0bc, 0xaa2a4cd0, 0xafe0efbf, 0xd0770024, 0x3a2945b7, 0x602ff3fe, 0xe25a1f5b, 0x51464dfa, + 0xe3f84a0b, 0x797c35e5, 0x3eeea10b, 0x44802aa1, 0xe2749801, 0xf9cede3b, 0xed7b5cca, 0x25f1787a, 0x773c2c3f, + 0xf5e31393, 0xee7646d1, 0x12962779, 0xf28684a7, 0x784cde7b, 0x3189a728, 0xa486eee1, 0x0061a34a, 0x33f53007, + 0x3dc9e60e, 0xa310234c, 0x9599b8bc, 0x4e4c2e45, 0x28db39bc, 0xbca0d00d, 0x86f892c2, 0xa10b6b2c, 0x5f62ba0f, + 0x5e69777e, 0x6833cb22, 0x2187b7b0, 0x6dd38b3a, 0x3a3ed167, 0x426a6cf8, 0x0cf79df0, 0x113e222c, 0xe3e88434, + 0x619bb45d, 0xed144e0b, 0x0e32deb5, 0xe0e2538d, 0x3aa37528, 0x371b59eb, 0x4cdd7c77, 0x33cb53ac, 0x81f182e9, + 0xedb37e2a, 0x7a32ce02, 0xa2bfcdaa, 0x9fb738d8, 0xfe059be6, 0x918fb715, 0x5c9b1fe4, 0xe0a2720b, 0x41c3270d, + 0xef744c4f, 0x16ad86bb, 0xcaf44592, 0xecd210c9, 0x3c5cb897, 0xefa69512, 0xdb68c790, 0x142a60ac, 0xdb39deb9, + 0x65f25e68, 0x6286b9e4, 0x99560f85, 0x510e3a52, 0x5fd366c0, 0x779f977a, 0xb695de50, 0x976a366c, 0x56287b4f, + 0xe6105a28, 0x1e995a90, 0x8cb73e52, 0x0099cb91, 0x3e7af2a2, 0xca73f9d7, 0xc4ba128b, 0xa07171a0, 0x74bfe63d, + 0xb9e21449, 0x7d5a2807, 0x0b57056d, 0xd184dbff, 0x0be51f52, 0xd7ec4c17, 0xd3f96a94, 0xebab3a2b, 0x46fd8d00, + 0x8c15c0d9, 0x6e08a35f, 0x8c47e5f9, 0x89446ae2, 0x4a2de247, 0xe69251a9, 0xfa3afdc7, 0x362618dc, 0x0a0637b3, + 0x9c3db702, 0xa5117e31, 0x47dc8926, 0xdd1fd2de, 0x701fe028, 0x783b5cae, 0x72610b14, 0x4da79e1d, 0x768633b7, + 0xae8bc3f4, 0x4f41b37d, 0x3299f766, 0x03519382, 0x6b5ef19f, 0xb9575318, 0x514dc9b0, 0xee634328, 0x7812aace, + 0x103f7730, 0x06e899b7, 0xc5bbab03, 0x49a6bd4c, 0x9ab19aa6, 0xb0555ea3, 0x4a3d1b80, 0x8fc6c1af, 0xde782ebc, + 0x8022195b, 0xcfd62c53, 0x1dae44ec, 0x12d6a268, 0x82c88192, 0xa9de000e, 0x1adcbb44, 0x34d808a2, 0x2acf1b15, + 0x02144b6e, 0xb57e3637, 0xb44d1227, 0xd46acce5, 0x161a6221, 0xf504a765, 0x8d84e73c, 0xe21bde05, 0xd38e34f3, + 0x3cf0cfe1, 0xfb40ca4c, 0x0106b10f, 0x5ebc3d77, 0xf3306f99, 0x6c35a0c9, 0xd2e056bc, 0x4895f29c, 0xb3d90cfc, + 0xcb5b34e8, 0x6d5d34bc, 0x36693e7d, 0x22ca3994, 0xfe3e353b, 0xa8dba8d4, 0x665c0b3a, 0x6c271b48, 0x7b63d507, + 0x3c13be30, 0x200ee9be, 0x8f979dba, 0xc99bf9a4, 0x85475a8d, 0xd4e6d4be, 0xd70fd4d3, 0xdf38ba53, 0x8dfc9e54, + 0xd46dc807, 0x1d5057cc, 0xef8773e1, 0xe9487440, 0x28b338e7, 0xcb912de3, 0x5c07dcf9, 0xd2c8c25e, 0x586ce012, + 0xd00ce7e6, 0xb5d29d9d, 0x36dcf67c, 0xf50cbbbe, 0x11e01f9e, 0x53a1206b, 0xb656c745, 0x13ac7d20, 0x60be6766, + 0xf5db4426, 0xfa2d8c42, 0x53677777, 0x7211b7ec, 0x055225e5, 0x025aa7ac, 0x21200534, 0x646af5e7, 0x09246335, + 0xe88250f8, 0x96938ad8, 0xd936ed76, 0xbc853a91, 0xd4466bdc, 0x1e30e0cd, 0x252119cb, 0x981a42be, 0x804ba9e9, + 0x05126dbb, 0x50b11d3d, 0xd711f0e9, 0xa2f09c12, 0x342a70b3, 0x1b498614, 0xf46c265e, 0x76a9c475, 0x182a659a, + 0xe1224f09, 0xfcb6e8cf, 0x73bc69ce, 0x77fec748, 0x046ff90d, 0xc353ffdc, 0x13ec74c1, 0x7a828845, 0x4624de95, + 0x4cd80351, 0x2abe56f5, 0x81467e36, 0x13d7ff40, 0xcd1c0138, 0xb387674b, 0x6c4e3419, 0xfaf4dd02, 0x97a2bd30, + 0x811125eb, 0x06130512, 0x46172c81, 0xb25b37d3, 0xed037273, 0x210a1813, 0x45e49d46, 0xb15aba2d, 0x162c2bd6, + 0xea1c377b, 0xbfe11d7d, 0xd8a65cbd, 0x3d7b1b8b, 0xfd6fc563, 0x57ccfc37, 0x4dc1d55b, 0x8c032ec2, 0x819c6c35, + 0xade53d17, 0xe500fc93, 0x4d8302da, 0xe0fa9789, 0x67e1328e, 0xec9fccbc, 0x9c51a220, 0x736fb773, 0xfd02007b, + 0x5347473f, 0xc43c31f0, 0x4708b4bc, 0x5110c313, 0x0f82be8a, 0x27227fa4, 0x8d9b45e1, 0xbbbbfbd1, 0x610ea2e5, + 0xf2d36033, 0x1f5c2a1c, 0xe920ba64, 0xb973271b, 0xf4e83ff5, 0x786e183a, 0x4f447db2, 0xcd2b15ce, 0x3e7c1db4, + 0xdbad04da, 0x26d8e4ba, 0x6003e171, 0xbb3542a2, 0x722733c9, 0x6f8ba820, 0xe8312c01, 0x9555ed0d, 0x41a745a8, + 0x3a3a9e74, 0x490289b3, 0xbc95c995, 0xb72da96a, 0x285b6928, 0x4c053d09, 0x96d89f7d, 0x7d2d2301, 0xf759f412, + 0x36fb607b, 0xee93688c, 0x25a2e1c8, 0x04e4c815, 0xcb174662, 0x966c9dc1, 0x2a0e9447, 0x5de09e5e, 0x9c9d2e1d, + 0x134dd849, 0xf8840f63, 0x37cbf3b6, 0xc9b74367, 0xe1415d3e, 0xe47f7dbd, 0x30a4a20d, 0x27fb731e, 0xdbcfcf94, + 0x6b8c8432, 0x51cd718c, 0x07de0c35, 0x0af73ebe, 0xdb98ae17, 0x42ef9ec0, 0xf80e597e, 0x8f04fbd4, 0x2a8ae845, + 0x98d07447, 0x670b6f3a, 0xfbe09d86, 0x4ef41c0d, 0xafd1c8a9, 0xf4e4d18d, 0x31a8d7ce, 0xae4ef194, 0xd8db048d, + 0x74a37aac, 0x3af77977, 0x570608cd, 0xb8ab982a, 0x2bb4bf88, 0x31bdfade, 0xe8cd228c, 0x8c5e0309, 0x396380a5, + 0x9329207f, 0x941659f5, 0x5f105243, 0x97507b2b, 0xc9731314, 0x7b84ee75, 0x8a9aa421, 0x4457fba1, 0x2b10665e, + 0x622ea5ee, 0x200b888d, 0xeb2117f8, 0x0304a0db, 0xb7994d28, 0x1ee4f3be, 0x7c9127e2, 0xe481875b, 0x6da90a3d, + 0x107d3388, 0xec076872, 0x1b564a3e, 0xfc1da8ce, 0x3a711824, 0x3f68d575, 0xeda675fa, 0xa13d6006, 0xb7322486, + 0xf27168f7, 0x7bba066d, 0x6fbd702a, 0x0c909ecb, 0xc9b1702c, 0x00180854, 0x9d7d0e19, 0xd552aa66, 0xd03e897a, + 0x8349340b, 0xc4b11d6e, 0x1c4d757a, 0x99805069, 0x2cb70f1c, 0xc7c5ee94, 0x1c92d42b, 0xcdf1523c, 0xa1f55658, + 0x73c00c2e, 0xa0b0b3bc, 0x9673fac3, 0xe9a3eb28, 0x96b16959, 0x5c93b526, 0x282b1b16, 0x86b67956, 0xd2cabcad, + 0xae3d9cb3, 0x5b669279, 0x72c84f36, 0xfd524406, 0x5cbb48a9, 0x52091aa6, 0x4bf83706, 0x03e65a5e, 0x3df3b63b, + 0xa211bebc, 0xc4bbdae6, 0x32a8803a, 0x16658752, 0xf4883fec, 0xcf0713ed, 0x681a9694, 0x2afa8445, 0xc990dd0c, + 0x98133858, 0x9a3c5912, 0x3d084927, 0xafd38be8, 0x38a32806, 0xe3881245, 0x52da7a57, 0xfa93f8a6, 0x0a2f6193, + 0x19a5cc5a, 0xd358422b, 0x230b81ed, 0xe973766f, 0xc62883cc, 0x48a87468, 0xe1a6b2f7, 0xede04fa5, 0x4f7003b6, + 0xd186e0f7, 0xb33b00f8, 0x81aee5cb, 0x8dcfc885, 0x86c41d9e, 0x90029a7d, 0xff86b163, 0xfdb5e3b6, 0xef285a0c, + 0x75d02b07, 0xe8d5ec39, 0x0865f1d8, 0x5727ce29, 0x0b5ecaee, 0x39da43fb, 0x51a71fe1, 0xdc8f3628, 0xa9f1f290, + 0x797d604f, 0x43fc0663, 0xbaeddacf, 0xa68408bd, 0xf5629ce0, 0x7c8e7280, 0x299f750a, 0x26905a1c, 0xcfb0e416, + 0xa18677c4, 0x5e3f900e, 0xa4448b63, 0xe6080509, 0x9a9414cc, 0x09064783, 0x6293044c, 0x7d6d3b83, 0x5f07b40e, + 0x71fda5a2, 0x059d069f, 0x1c31d666, 0xa50cefa6, 0x763c1081, 0x2c3fadab, 0xa7935057, 0x9b6ad47f, 0x52bd4161, + 0x62dd1373, 0x7dabfea9, 0x07fd263b, 0xdf5ee0d9, 0xf7b8bd70, 0x9636f4eb, 0xcc80be5a, 0xfabe9c20, 0xd749b76e, + 0xf8491b19, 0xbea13e2c, 0x4c1717c8, 0x6569c738, 0xfcd5c7b2, 0x7d63bd73, 0xfcc9453b, 0xcd12f9da, 0xe1ee7393, + 0xa05f217f, 0x28d0f6f4, 0x430261b6, 0xd4f9ac43, 0x42c0f031, 0x06749044, 0x6778a37c, 0xf2106126, 0x38f7de4f, + 0xd9201f4c, 0x65c05681, 0x23a9b633, 0x3066decb, 0x5f3252b0, 0x2c3e1a0c, 0x9c968acd, 0x8c37d756, 0xb6f77563, + 0x9c6bf112, 0x7cf6824c, 0x2020419a, 0x15d5bd87, 0x009a1736, 0x78151682, 0x0a7575ce, 0x1f8d8e21, 0x852a31c5, + 0xdbc914e4, 0x3897ea59, 0xe91457ec, 0xafe2c45c, 0x1618af1e, 0xe24d71f2, 0xc10c2ef3, 0x0f743f05, 0xbf4dffc2, + 0x6d994542, 0x5a85931d, 0x5dd02525, 0x59fc29c4, 0x65a5b214, 0x0a1fc856, 0x760c2987, 0xa5877dde, 0x263f4083, + 0x6be50a97, 0xc48671ac, 0x857fa533, 0xbe45f533, 0xfdc45254, 0x186a4529, 0x9a097576, 0x57e788e1, 0x258068e8, + 0x3b9fa636, 0x9a3187fa, 0xbe5bfd38, 0xbed6de94, 0x0f79d4d8, 0x34aa0124, 0x2029f30c, 0xed06a679, 0x08412390, + 0x682fa921, 0x36164740, 0xeeaed0d4, 0x6393a8f4, 0x42ae1602, 0xca5ac072, 0x8e8488a0, 0xf6d482b6, 0x2746666e, + 0xfc033188, 0x17000b0b, 0x3d819ab1, 0x1b3ca840, 0x9cb30e3b, 0x80c65e79, 0x6d72b0f1, 0x65bcfd1b, 0x97a115b3, + 0x3ab3eb4f, 0xd2107a29, 0x0044776a, 0x2034095a, 0x76654e60, 0xa644f3d9, 0xb06172ac, 0xa58f1fda, 0x9bfb8fc3, + 0x8ae2d160, 0x549645ae, 0x0f121397, 0x7c84c55f, 0x2a8722b8, 0x0cc0ed82, 0x58eb5863, 0x3ee3fa43, 0x5931b132, + 0x24b04dc4, 0x9059b4a4, 0xd4f400fe, 0x19de2a7e, 0xa2be096e, 0x07ca157d, 0x9b6a7b07, 0x8df468c4, 0x3856477a, + 0x4f218904, 0x5a05f96c, 0x7387b06e, 0xd359a968, 0x44abe205, 0xc485904b, 0xbb7481e7, 0xff97e18d, 0xfcd145a6, + 0x46e78029, 0x0cd7b46f, 0x3438d23a, 0x141f0189, 0x2a4128cf, 0xd5c20fe9, 0xd6780d6d, 0xde9d9d2d, 0x9d5358d6, + 0x43af87c0, 0x348007d8, 0x8ebec75f, 0x5e88a5db, 0x29177c05, 0xfc553152, 0x8908eb9a, 0x31c7ae50, 0x5b78f386, + 0x28e6831e, 0x4a9911d7, 0x29507bbf, 0xfb1e28ff, 0x0d91f659, 0x46912c3b, 0xbc163a0b, 0xcf2f8b32, 0x3155f854, + 0x21b95d1e, 0x2ce7a4f7, 0x10bdaff6, 0xba24f50e, 0xee3b57f4, 0x50dd3ad5, 0x471c3239, 0xa9c5a777, 0xc87b5de0, + 0x07af57b0, 0x6430865c, 0xdfdf35c9, 0x63410a2c, 0x809657bb, 0x3ab6a385, 0xea10f59c, 0x6d710b3c, 0x8b501443, + 0x9baec604, 0x5a923d98, 0xabb102fe, 0x942a7101, 0xe8bcab98, 0xdf7db6d4, 0x8bf3c8c2, 0x380003ee, 0xc36a152d, + 0x838cd119, 0x717541b7, 0xb715ec81, 0x5e83ae37, 0x2119c2f7, 0x35e82223, 0xe23783b8, 0x381c019e, 0xe3da9aa0, + 0x588de7c7, 0xc92b31de, 0xc484d5f3, 0x122bd4d6, 0x8c94f667, 0x9b3e9977, 0x2c5b062d, 0xc692bb09, 0xc90e8804, + 0xcd5fbb08, 0x38c8ea97, 0xf814374e, 0xd98acf89, 0x880fb867, 0x9dc8b6d5, 0xd38eb129, 0xb1396c28, 0x0b9e1070, + 0xb3e0c2c9, 0x7623eb74, 0x83643b27, 0x54889951, 0x447763c6, 0xe53780a9, 0x9f7b1c7d, 0x33d4d0d4, 0xfe89cad9, + 0xfeae3ad8, 0xbe73abf7, 0x72faec5e, 0x04d056a9, 0xbad37e99, 0x21d06c74, 0x7be2a235, 0xfe1091cb, 0x76bfac8a, + 0x9bbf231e, 0x889e5c2e, 0xe670e7be, 0x9552cf50, 0x3fbb629e, 0xb4321b11, 0x379af955, 0xc1018254, 0x3ed98b08, + 0x1e7842ef, 0xe2b00450, 0x7c280b82, 0x74f208cf, 0xf6f8dcce, 0x1e26e2a0, 0xd7bae0b9, 0x80969c72, 0x80a90f8c, + 0x4ecc80c3, 0xe59cb860, 0x0f3bde07, 0xe0f5175c, 0xefeda3f1, 0xdd6925f8, 0xeee53bc0, 0x00db471f, 0x4c2a825c, + 0x8ab36595, 0x7bf705b5, 0xd53d026a, 0xa2c98e76, 0x0e0092c0, 0x30cf9393, 0x6989d29f, 0xd51690e5, 0x6cbaac4b, + 0xc4f3bbaa, 0xb17df78c, 0xced1030e, 0xcd69836f, 0x0e70ed1d, 0xbdb36986, 0xab2618c9, 0x6e3d4c1f, 0xd554b7bd, + 0x25c554c9, 0x3d0178e5, 0xe413a304, 0x224987a3, 0xb5cef474, 0x25de8f03, 0x58cbf870, 0x11c7e936, 0xf978b2f9, + 0x673e9cc0, 0x605996ef, 0xcce6e245, 0xe337bb29, 0x8d8c63bc, 0x4594db95, 0xc82c270b, 0xe83924ff, 0xe1997531, + 0xd90d5096, 0x700e75fc, 0x3e37b216, 0x4ada2407, 0x543c6f4b, 0x77a5d06c, 0x265769c0, 0x4f1e55ec, 0xf2b916e4, + 0x407ffcf3, 0xb3eb761e, 0x6bbdf9f4, 0x2f61421d, 0x1afc7e57, 0x97a59c2c, 0x6f8e7150, 0x9bb9b9fc, 0x142a100d, + 0xa2c0dbfe, 0xa3c8dbca, 0xe72361a8, 0x59daf697, 0x72a73f46, 0x84b0af4c, 0x3cd53b22, 0x3e7f2307, 0xc2e0d57c, + 0xdd2395bc, 0x08abe82c, 0x04a634a8, 0x63f62aa6, 0x59de7adc, 0xe8f1c1c8, 0xf3ba1850, 0x254c8319, 0x8dc6a9b7, + 0x7c47bd4d, 0x418b6066, 0xe3defc6d, 0x8501c233, 0x33e8c954, 0xaf7d3a79, 0x9c9d23c4, 0xcbc1e4a4, 0x85db7f98, + 0x6da59db0, 0xe075eb8c, 0x0169d9a0, 0x58cddeb3, 0x1495e05c, 0x6db15757, 0xf6b438c7, 0xb3cc3188, 0x20a4ea60, + 0x0e21efd0, 0x4a32f08f, 0x1c8fccb4, 0xc5c00bd5, 0x6983bd4d, 0xdc44b2bf, 0x97f6419d, 0xebfff1c1, 0xb7cc4621, + 0xc9439201, 0xc390a6c9, 0x12708e66, 0x6ae17ba5, 0x11bba762, 0xd1631c95, 0xd6d588d7, 0x77c8361d, 0x01ff164b, + 0xed37b9fb, 0x0b4ca314, 0x097b1477, 0x7f0fa5a6, 0xbf05ff36, 0x18a3daa5, 0x908b9ba0, 0x2b900173, 0x1fcf0f47, + 0x0c85613a, 0x6db945e9, 0x479f9665, 0xd3202346, 0x47cbd247, 0x8c9ff17c, 0x596fd923, 0x2a5d2f64, 0x2ecc4e62, + 0x668f55c6, 0x611a51b2, 0x234dc03e, 0x8329fecb, 0x0efad21e, 0x2e28dadd, 0x1d8f67c4, 0xf952b59c, 0xf8cdc105, + 0xb3362be3, 0x20017c5f, 0xaf57cee6, 0xeb0145cc, 0xd7de30a1, 0xe548d3e6, 0xe7ff48bb, 0xf2a1ac1a, 0x5fb68a39, + 0x4cf77d9d, 0xc1922be5, 0x8787cbcc, 0xd274ee1a, 0xe0185d2c, 0x43945d54, 0xbb18dc27, 0x89b94e29, 0xfbf765bb, + 0x191b4351, 0xe9246422, 0x01190496, 0x9f03c390, 0x010ec18c, 0x25888ee4, 0x2d2d5f9e, 0xc0b0b103, 0xd0d62441, + 0x2d9d3ab5, 0x11849ea0, 0x25824930, 0x23920e7b, 0xac21fac3, 0x245462fa, 0x9b18aa1c, 0xb5cb3fdf, 0x1f83e33c, + 0x3dc0bb1c, 0x0e253071, 0x9f7a6f9b, 0x3e9a5ffa, 0x1fe33bc3, 0x13763730, 0x9534e092, 0xf7cc3d7c, 0xc7006530, + 0x28c86d7b, 0x4cca1092, 0xed5380f4, 0x3fdb7413, 0x2058219e, 0x617ac5f9, 0xe6c3a871, 0xbb3c685f, 0x7542d1fe, + 0xcef644e4, 0x4103aef2, 0x962525d9, 0x3e302116, 0x88409820, 0xdb1ead7e, 0xc4673bd4, 0x0aea0973, 0x04235a09, + 0xc80b8550, 0xb374d799, 0xea00756e, 0x24acfaaf, 0xf921daec, 0x09cd235c, 0x7534fe2b, 0x5d069e6d, 0xce7df5da, + 0x5c270fe6, 0x11fc84ff, 0xe3933f9b, 0xc775b1b4, 0x44d63ffa, 0x210e7392, 0x0db34d93, 0x9cdd30ab, 0xd7fefec9, + 0xb81e3680, 0xd36df525, 0x6c9aea28, 0x95c3faf2, 0xbdbdc5b7, 0xc2f80fe3, 0xe14ed0b4, 0x80a733e7, 0x91dca311, + 0x6e1e1c63, 0x849720a0, 0x4cefdc08, 0x2bf56837, 0xdae1e22e, 0xc57ff72d, 0x60da6c29, 0xd12d7bc8, 0x0ff03b13, + 0x878cd572, 0x30350043, 0x971e57c6, 0x2719ef29, 0x8619a64d, 0x246810f3, 0x789da094, 0x4615e332, 0x10c508d5, + 0x51131a3f, 0x717acd85, 0x4e3dd9fb, 0xb4178e57, 0xe7ef75af, 0xf2135f3c, 0x40e45e5e, 0xb3900491, 0xcc907024, + 0x3c213943, 0x5e23b700, 0xb9d7fa07, 0xbec6e664, 0x55038f14, 0x082654e2, 0x9b43fab9, 0x1ebd5a98, 0x91394d06, + 0x77ae98ca, 0xb8eea5aa, 0x47b92e44, 0x627b64d3, 0x090c83a7, 0x564314c6, 0x800db99f, 0x9884d042, 0x8588c88e, + 0x3f3b6bbd, 0x80e60c4b, 0x8a535847, 0x173c7fcb, 0x7dce0b41, 0x5ad57e9c, 0x474e49ee, 0xa664c42c, 0xa95caf17, + 0x9d3e6f06, 0x4b8ff637, 0x54d35e24, 0x20ecacb6, 0x4a996d46, 0x3d60651d, 0x62f77bb5, 0xc0445451, 0x709ae08c, + 0xdfc1f333, 0x883bd512, 0x5e46cb41, 0x0d15d9fa, 0x57fe2231, 0x50070a55, 0xd1544213, 0x632353d6, 0x117d9d8f, + 0xd79946ea, 0x4c8bff2a, 0x539bea92, 0x94870071, 0x021e07fc, 0x7556267a, 0x417e46ff, 0x6f8e3ff3, 0x7ca4a407, + 0xb7468ac0, 0x5ddd1898, 0x3d9a66a7, 0x2fd5d6d2, 0x2c99c966, 0x0459234a, 0x493f6737, 0x06dd2751, 0x06ab378c, + 0x61983697, 0x65430666, 0x98526833, 0xc21d718f, 0x8bf36e84, 0xea7b9381, 0xded4e27e, 0x808be9c2, 0x5da60b91, + 0x7aed0db9, 0xa89fd961, 0xce65a3d7, 0xbdefe0d2, 0x89d3968f, 0xf0480309, 0x1ff8b556, 0xf0ae50a6, 0x61077aa5, + 0x9d942d23, 0xab018a05, 0xa76b3b73, 0xde03ed97, 0x42934e20, 0x8c7126ae, 0x2b323e1c, 0xd35eae6e, 0xa74fe24f, + 0x68a99a8c, 0x296d00cb, 0x7d7a712e, 0xb50902d4, 0x5cd7c96f, 0x58e47346, 0x5619a7aa, 0xbdf4af42, 0xce7313f9, + 0x66c370f8, 0x31bf0851, 0xb7726e1d, 0x4ef9e0d5, 0x13b522fd, 0x3205a3bc, 0x30d02c88, 0x7fde4336, 0xc246ecd9, + 0xaa77ab57, 0x241439fe, 0x19488608, 0xcaaeadaa, 0xe2d7cc09, 0x28502389, 0x5e89b818, 0x263a0023, 0x2691ffbd, + 0xa1ef529a, 0x3e9f84c3, 0x4b40781f, 0x0f166ee0, 0x6ffea278, 0x44222f42, 0xe5011009, 0xd0e2d645, 0x91e7066e, + 0xab43a42f, 0x1b45d879, 0x8116f6cd, 0x06367ad4, 0x91a3d3e3, 0xa2e15b80, 0xb1cbe505, 0x46f3b18f, 0x7fe8dc6a, + 0x1647ee81, 0x0330198f, 0xe1b43f21, 0x6cbc2be7, 0xd7818800, 0x479bbb35, 0xb5b51730, 0x2873f9b0, 0x3b10a30a, + 0x3c15abdc, 0xcdb0aace, 0x4583da78, 0x20834781, 0x9d25e439, 0xb03ca7d7, 0x61a327bb, 0x2e12ec7f, 0x652f57ae, + 0xb0aebdd4, 0xb0e50813, 0x767a942c, 0xf2a571b3, 0x7057a832, 0x866ffbd7, 0x52c80066, 0xa6136619, 0xff618026, + 0xc56e5a15, 0xfbb036d5, 0xd8fa0e73, 0xe72fda9f, 0xdbe76bff, 0x0aa9c86c, 0xd3cde398, 0x9ebd9211, 0x2dc9cee1, + 0x8b0f37f5, 0xd4e33872, 0x7646cae6, 0x62e939d0, 0x213b5d13, 0x5947cfdf, 0xb92dde59, 0x85479f48, 0xff2372b6, + 0xf1af4e54, 0x2095c9a7, 0x9e117bba, 0x83ad762e, 0x21bcfea1, 0x6760ed48, 0xa767ce5b, 0x923e6282, 0x0895281c, + 0x7afd4c14, 0x4c6a3da5, 0x13af64aa, 0x7c50b633, 0x1ff24c62, 0x4d263b23, 0xbaa17b92, 0x239da0cd, 0x91061b24, + 0x2ef8c7cf, 0x32004deb, 0x71c82cc0, 0x2f7975ba, 0xd7c3172b, 0xa4cf13a9, 0xd08246cd, 0xb0a97d67, 0x5bbca9d9, + 0x730a1774, 0x2748db46, 0xf11e5846, 0x08ef7b0a, 0x85552322, 0xa788bba6, 0x9a85fdd1, 0xccb57cfa, 0xd4cf7821, + 0x26ec326b, 0xee5fa075, 0x39f57d30, 0x8d9321e1, 0x80b756d0, 0xb790c0d6, 0x2e6a3fe2, 0xa763d0cf, 0x92ca840a, + 0xdfac9e97, 0xb27e2e13, 0x02bf835e, 0x8318164f, 0x8e385755, 0x9d5afcc1, 0x1041140a, 0x3f00e1e8, 0x903f5f19, + 0xd50c21d3, 0x5741584c, 0xb632e1fd, 0xae6693cb, 0xc8141430, 0x1bf1118d, 0x619e0c0b, 0x7719f1e2, 0xa73e8232, + 0x019f5191, 0x2866bb4b, 0xa0b211b9, 0x28f7ca92, 0x54619080, 0x4254d097, 0x80165a03, 0xabf1f817, 0xe702704e, + 0x125ff684, 0x4dc2f6b5, 0xddf579aa, 0x41cfd2c0, 0x1cedc039, 0x28367914, 0xc0c0ea8d, 0x235c6a84, 0xc58dded4, + 0x6ce8348e, 0xe377aa9f, 0x21e962ea, 0x97dddbb5, 0x51b6c712, 0x88d232b6, 0x522269c1, 0x5694a202, 0x09ea4a37, + 0x49590be4, 0x1b59673c, 0xe9ca62eb, 0xe7c4b0ac, 0x6388f699, 0x1da5c814, 0x1f39c053, 0x7840e4b4, 0x73a37ab6, + 0x6e21b84e, 0xf3d54d8c, 0x5c4e27e5, 0x3c88421e, 0xaa98d4bc, 0x3be3aa94, 0xb80bae06, 0x4d5d4377, 0x64f91136, + 0xf100f02f, 0x4a525807, 0x9d1c104f, 0x8f14b988, 0xbc9a57be, 0x8c7d2344, 0xeba63fe6, 0xe3683eb3, 0xc640ade1, + 0x85da8477, 0x53f13a68, 0xa3352988, 0x75d43c76, 0xc1f873ff, 0xb52ee91f, 0x9bc25e37, 0xc76b3c16, 0xa5eba265, + 0x1b61d4c3, 0x58327f7c, 0xd3b4bf67, 0xaca4ec45, 0x8128f77b, 0xa02e7d48, 0xd09a4b45, 0xafd8835d, 0x5dcf7488, + 0x9673f150, 0x5e1d6f72, 0x640e900d, 0xbba8eda7, 0xff7c02f2, 0x2a47adc8, 0x2b8403ab, 0x5ea19040, 0x829c2676, + 0x56657a98, 0x0f0f913b, 0x2062c756, 0xcd69858d, 0x03e6e19b, 0x091fb768, 0x06e6f8e5, 0xab0ec31d, 0x1058aa84, + 0x57da05a8, 0xeb004cd2, 0xcb29b402, 0x0d9afb74, 0x6d014bce, 0x10df31d9, 0x7762857c, 0xf6aa8596, 0xb8cbb507, + 0xe1375302, 0xa3c6059b, 0x72bec0b3, 0xb6ed4944, 0x0b8ff48b, 0xf84492a7, 0xb26f3604, 0xf51f7e04, 0x33effd69, + 0xb0fbfa18, 0xecb3bd85, 0xcd0206ee, 0xa6e7f9ca, 0x55451a99, 0x780c7956, 0x94278776, 0x4d43517d, 0x07c83acc, + 0xd8085f3b, 0xae0c8723, 0xe42a27be, 0xb3015b3f, 0x29567edb, 0x3f15191f, 0xd9983536, 0x8f25c738, 0xc52f4c7b, + 0x4ef40be4, 0xb5d4ee24, 0x4ac859f3, 0xddde523b, 0x1467d34c, 0x516b2c12, 0xc42b9cfb, 0x3d31042e, 0x805b2f41, + 0x163d2c7c, 0x03204fef, 0x948203d1, 0x322131fd, 0x69d7c450, 0xe17cfb64, 0x86bbc588, 0x0959db34, 0x1250c70e, + 0x4344631a, 0xa1b10053, 0x68b87511, 0xac1c0bd4, 0x7d3fc58c, 0x10b831ee, 0xe9147d69, 0xcde289ae, 0xc6045d93, + 0x58714707, 0xfb719f1f, 0xf6015e6f, 0x212f71a8, 0x743dcad0, 0x22809cae, 0xfe367606, 0x16d5f67a, 0xf8980534, + 0x74f38701, 0x4f9d999b, 0x54c08e24, 0xf39e0029, 0x4fd5e260, 0xeaf8aeeb, 0xd28c0da8, 0x1bf59089, 0x87e5a17b, + 0xc7853aa5, 0x0c930510, 0x50fadc79, 0x17996796, 0x742c8090, 0xbf550141, 0x87215d85, 0x0a2f186e, 0xf0d14ff3, + 0xbe5b9ce6, 0x9161ea3c, 0xc1e0af7e, 0x1c6d627c, 0xce629aec, 0x2ff5bafa, 0x47ea7305, 0x66a66517, 0x401132ba, + 0x8f017dab, 0x49b06044, 0x4575b6ca, 0x23214f5f, 0xec3ba6b6, 0xc55a007f, 0x05c9e8c2, 0x2aa093de, 0x19b3f7ff, + 0xe2696922, 0xe22098b6, 0x17483889, 0x29f76349, 0x63463129, 0xa01e59a3, 0xf21e2509, 0xc094ac6f, 0x6cc77864, + 0x8fcbe739, 0x34937456, 0x5588d7c6, 0x21f74e5f, 0x89734ed7, 0x336cbf1a, 0x9365f73a, 0xc5a1939a, 0x0356c573, + 0x09b25b5c, 0x4052da3c, 0xd18b7e5e, 0xe5cfce74, 0x194ddcce, 0x1f3a770f, 0xee1ee823, 0xad69ba69, 0x7cc4d51b, + 0xfc9d8c38, 0x2503823e, 0x0aaeeea4, 0xf18bba26, 0x34044106, 0x2c07677f, 0x21683aab, 0x27845c36, 0x24e4763b, + 0xa49aef1f, 0x82127338, 0x35d1982e, 0x83d9f997, 0x27c0477b, 0xb765adff, 0x3f547324, 0x0a25142f, 0x3b77e404, + 0x96d395a9, 0x1b26d758, 0x8800d115, 0x6cc9857a, 0x0770e7e5, 0x2d2cb4a8, 0xe8969094, 0x5a5d9482, 0x76bf1215, + 0x09c9a445, 0x709c3044, 0xeb41ee14, 0xb1c5b2ff, 0x2b975e00, 0x11acc430, 0xfd04bfe3, 0x0e16ec73, 0xe96a9fec, + 0xad4f7971, 0x731e610d, 0xd2d350ee, 0xa4a4e182, 0x8eb49157, 0xa4af19f7, 0xc52aa4e7, 0x212ee443, 0xc4ce0dc7, + 0xcd0a2e4a, 0x4b9d56e2, 0x9111ba91, 0x69fe913d, 0x952f58fc, 0xd1b720fd, 0x20a06e68, 0x340bfbe8, 0x5d402732, + 0xff1b13d6, 0x991ded4f, 0x81ebc0fc, 0x57d1f0ee, 0xd4c06b1f, 0x9ac0587e, 0x923ed1ad, 0x4b58e7e8, 0xbd1cd2d0, + 0x88ad2e61, 0x679eb197, 0xd5069224, 0x5a1c50a0, 0xad9b6295, 0x491e5700, 0x9b27bd68, 0x6ea9ee0e, 0x8503f2f8, + 0xc0d75abe, 0x95760416, 0x4abb3881, 0x1d3ead07, 0x8fef0dc4, 0x3ba1ae40, 0xbd9f73f7, 0xf02096ec, 0x6c848d8a, + 0xa7fb1af5, 0xf0275aa5, 0x309d3cb1, 0x2462acd5, 0x43fb4ee5, 0xeddb7a6c, 0xbb41035d, 0xb9fb63ec, 0x96459a9a, + 0xd1ae9cb6, 0x6b419125, 0x0a17b8c6, 0xa5fd635b, 0x3005886f, 0x1bdbcac5, 0x4f5e0965, 0xa0100bbd, 0x4ebf3dd7, + 0xa00a8774, 0x8f831167, 0x1f47a921, 0x504b4b39, 0x617ca868, 0x41a52534, 0x0b8c98d9, 0xb601e3fa, 0xa6f84533, + 0x1216d737, 0xb0df7bb5, 0xe434a756, 0xf7535ee6, 0x1db1f68f, 0xcf079164, 0x1d916d54, 0x41b14825, 0x0306671a, + 0x9b4d2761, 0xb23a2e8b, 0x6387f2d2, 0x1035104c, 0x27182c71, 0x24320883, 0xa4ec1f06, 0x0a5e7f05, 0x860f83a0, + 0x274bfcb4, 0xb626661f, 0x7cf33acb, 0x0596de2c, 0xadbadc35, 0xb3cec8f0, 0xa4daec5f, 0x9157e512, 0x5670b822, + 0x5b310f66, 0x622b333b, 0x3106e8f1, 0x3b584f13, 0x165be2eb, 0x6dc6de81, 0x4c8c4f7e, 0x55b210bc, 0xda2cf937, + 0x365c2e5d, 0x60023228, 0x89247629, 0xd2e1fbb5, 0x84c09487, 0xe4958eab, 0xeff67885, 0xc7148658, 0x8e8fb964, + 0x1aa5926d, 0x6f119cd9, 0xc2d94775, 0xdd698037, 0x8d0214f3, 0x3a3a25f5, 0x8a5dfbe9, 0x8c83b786, 0xded310b8, + 0xc3998890, 0xbf479203, 0x79152b0f, 0x481b0f40, 0xc60ebf3f, 0x3bf4393a, 0xf4878019, 0xc0695aa7, 0x11dbdbb6, + 0xb9db4f13, 0x26407897, 0x21a9eb1b, 0xa32b9773, 0xcd9b3361, 0xd8bcc4a8, 0x7340c08e, 0xe76a7ddd, 0x72c7790f, + 0x460aa9f9, 0x27706d93, 0x4a703b79, 0x1349c584, 0x5bdcc669, 0xe52dd401, 0x7e2cf2d7, 0x2f98e166, 0xc1820cb2, + 0x47addb0f, 0xd8550380, 0x1fc0564d, 0xd2b2d06f, 0xc67069ce, 0xe32ad33e, 0xd4a0e2bf, 0x2e446b62, 0x195d16f9, + 0xc904c302, 0x4d7c7b1c, 0xc1cb6fd8, 0x62e4b1f3, 0x4961ae94, 0x05c261d7, 0xc2886ee7, 0xcf0e2a13, 0x42f67a39, + 0x0ee7cd47, 0xa52c7606, 0x22d1503e, 0x8aa8cb2f, 0x8b9addd3, 0xdd563243, 0x091c010d, 0xb15b83fb, 0xd4bed8cf, + 0x4a3abc03, 0x5d449f2e, 0x29d9f0ab, 0x0d254f69, 0x8f825b4d, 0xd3bb9f24, 0x5a931ff1, 0xf4c76d4d, 0x54faf5c0, + 0xc1167797, 0x60b82ec5, 0xa6a758b1, 0x247191c5, 0x44287ce9, 0x55974165, 0x900ff2c2, 0xc5a3f9db, 0xf00c8753, + 0x4fd466f2, 0x237be0db, 0xc89502b2, 0xc486e124, 0x129d10c8, 0x8dd9186f, 0x28958a12, 0xe8466c34, 0x646c0270, + 0xd99a2154, 0x9fe82ceb, 0xb1aed7bc, 0xbd1ae918, 0xcef3ce55, 0x2544d030, 0x93c7c86f, 0x426c747b, 0xe58500ce, + 0x19aecda4, 0xfef5aea8, 0xb827f86b, 0x2c736ade, 0x099b4990, 0xcf76cf38, 0xf02d8ccd, 0x78ce11c7, 0xbd57a519, + 0x78557e56, 0x647315ae, 0xdebafd28, 0x0f6cafca, 0x35e73332, 0xc4a01650, 0x9650b9d6, 0xbb237889, 0x579a6a91, + 0xf64a6c6e, 0x672aca62, 0x51ff751f, 0xde86982d, 0xdf47b2cb, 0xd208da19, 0x772008d3, 0x519c3afe, 0x33a289a5, + 0x5f18e5f2, 0x554caa22, 0x9ed67599, 0x1c1041ee, 0xa71714cb, 0x87160d3d, 0xc24352f2, 0x17fc9e2e, 0x592e315d, + 0xbf547a8b, 0x3411de55, 0x63694ce1, 0x1b10448d, 0x2fed86b5, 0x961c3a2f, 0x0055970a, 0xfeb97c3e, 0xc74ff222, + 0x51da666f, 0xde0c6df8, 0x9227af14, 0xcb21e370, 0xda9f6f67, 0x7319025f, 0x622e8aa6, 0x0dd2ed47, 0x7208fbf1, + 0x56874ea0, 0x8f4ad175, 0xa3f880df, 0xb5bbae2c, 0x87632d67, 0xa1c2d6d1, 0x9ba2c39f, 0x1bed32f9, 0x300f392a, + 0x42dbd3ea, 0x27cd2787, 0x2ef9e7e7, 0x05ee3416, 0x5aa4ff83, 0xa8dcb9ff, 0xe9d91051, 0x281c8c2a, 0xa26a8129, + 0xdac24d52, 0x14f5b88e, 0x545520bb, 0xba097ff3, 0x28916150, 0x4297da80, 0x248683e2, 0x5dd281ad, 0xd2bf938a, + 0xd0d70fb0, 0x373bcb56, 0xcd8d32ad, 0x29c78e26, 0xfaa7fc10, 0x3fe11f57, 0x8e97124b, 0x20d61277, 0x5a782059, + 0x434e92ad, 0x0cd7a30f, 0xa387b1f1, 0x049c9d06, 0xd76f761e, 0x64018b88, 0x9482aa9f, 0x321d414f, 0xfbf2a30a, + 0x3954f6e0, 0xfdb167da, 0x90239727, 0x62f94dad, 0x6092d477, 0x95f4f121, 0x555f7aa5, 0x81f1a52c, 0xaedeb696, + 0xf4b17313, 0x251fa5aa, 0x15c5266b, 0xe48d98ac, 0x8e560958, 0xae244e06, 0x7a3aaee7, 0x2fd6b23f, 0x560e757f, + 0xbc115d8f, 0x29b03bbf, 0x05d2a7ca, 0x2a292426, 0x5627e5d8, 0xbaa9c384, 0xcf8651c7, 0x6615433b, 0xb89a1403, + 0xc64aea97, 0xa6660c11, 0x28cffaaa, 0xc9aa76aa, 0x777ed2ea, 0x7032c5ec, 0x14bdd55a, 0xacc947cf, 0xb80ddf5c, + 0x54dedb3b, 0x9ab7b7dd, 0x0c2ed18b, 0x9302b71d, 0x7d48c5ee, 0xd33311cf, 0x6b0496ba, 0xe803e152, 0xc452c4f7, + 0x7f846559, 0x8be6fdcd, 0xb8135b20, 0x7768f091, 0x4a4bb605, 0xe19a3ee5, 0x2c7dbab8, 0xdc4571eb, 0x1e714e8d, + 0xa677e117, 0x1280d507, 0x367cee25, 0x69cbd635, 0x60e4c180, 0xf8347b6e, 0x3243101e, 0x1a285365, 0x61f2203c, + 0x19c836dc, 0xc51e7aac, 0x9cff573d, 0x22de0ea7, 0xecf76a3c, 0xe0daca80, 0x9c54f80b, 0x7fac8059, 0x6810ddb4, + 0x0c480f18, 0x6960ea50, 0x1b83d110, 0xdde64774, 0xdce7c2cb, 0x0f8c0235, 0xce3bb7d5, 0x07d10962, 0x7736b84b, + 0xec2884f2, 0x865d82e7, 0xff31047b, 0x93d25793, 0xaa7be0c9, 0x35178700, 0xfe37a192, 0xd8349a19, 0xd03b090a, + 0x35b84e9f, 0x905d1ee2, 0x7bfb902b, 0x6a955d81, 0x867d6658, 0xb7ff0f34, 0x9ac577f2, 0x999254b0, 0x85046d02, + 0xc8e5c455, 0xc0cb3392, 0xd263ec4f, 0xbf9a7bba, 0x800da058, 0x91b39f0b, 0x43d4da75, 0x4f6b76dd, 0x8454aa7d, + 0x708a0900, 0xeb59e036, 0x344de949, 0x8033e29f, 0x60cb56f2, 0xc0fb8cc3, 0x5738d845, 0x088dab4e, 0xe1a6a392, + 0xc11e2227, 0x70f0c063, 0xefeb39ea, 0xe62d9a7c, 0xe627f431, 0xb3a4bcda, 0x96bfc4b9, 0x428c7c00, 0xf70680b7, + 0x73c1e427, 0x16658491, 0xa7b7c415, 0xc3891fc7, 0xa8496882, 0x007a1c3a, 0x980a459c, 0xa3feb81a, 0xfd73b67a, + 0x72b36feb, 0xbca67063, 0x2a226b7a, 0x62ab37ed, 0xd0bc4e47, 0x53b9db82, 0x1513b0bc, 0xd4a859a7, 0x56f296a8, + 0xd8af9f9c, 0x86046c32, 0x5b4c79e8, 0x897551e6, 0xb2887ce7, 0xcd6c1335, 0x021ac4e3, 0xa3a8d670, 0x2e1fcc4b, + 0x43b23b0b, 0x9b88c5e2, 0x03e4105c, 0xb09fd4b2, 0x3bc9aa35, 0xd6a91bbc, 0xc04ad85f, 0xf034cd81, 0x84388440, + 0xa48e7b10, 0xac6a8719, 0x69b5be78, 0x860e5ae7, 0xd37757de, 0x2e726510, 0xcba0f259, 0xf5170723, 0xa89f79f7, + 0xe34ae329, 0x2a5f68e8, 0x1ea0989d, 0x97593c5f, 0x98e56cda, 0x5807be6f, 0xb331542f, 0x8c659043, 0xcfa9b75d, + 0x50b693aa, 0xd84ce4b4, 0x01309d2e, 0xc12fc723, 0xfdc33fd1, 0x8a2c947d, 0xfb703405, 0xace93659, 0xfb44c165, + 0x139f00ea, 0x1bcab016, 0xa0c55409, 0x90356b80, 0xb1e6f69f, 0xaa76bf90, 0x0273386c, 0x3e507b0f, 0x0a834671, + 0x364f5fd0, 0x4f1e04c2, 0xaba77bdf, 0x785fddee, 0x8e205810, 0x975eb6d8, 0x1a99d1f9, 0x1d34a6fe, 0x7780a430, + 0x246cc21c, 0x400477b1, 0x4717659d, 0x87c559fc, 0x67d5994e, 0xd5d9a61f, 0x71846a24, 0x3abd72bd, 0xa67257e9, + 0x216a9bc9, 0xe4eadeef, 0x41d41851, 0x81f9952a, 0x4bd19a55, 0x0b9bafc2, 0x5b2e9b48, 0x3bac3c21, 0x92fc038a, + 0x0adf5233, 0xd7ccb19d, 0xd994cc8f, 0x297f74be, 0xbdd4f9ab, 0x15f78998, 0x5bbd67bb, 0x2e501c15, 0x162ec4d3, + 0x1c8a37fb, 0x3d26b45e, 0x84cfadcb, 0xfed40586, 0x353fabb1, 0x486b89d7, 0xda54a881, 0x4c697dfa, 0x65cbe035, + 0x80606b7c, 0x3918360e, 0xff8bceaa, 0x2a4340c6, 0x7743b2d0, 0x3c872c83, 0x23688ed0, 0x9171c639, 0x3377af7f, + 0x09067ae0, 0x85574285, 0x5c03bc12, 0x82de4536, 0x9a17c683, 0xd34c1c8d, 0xaeaa8a9a, 0x00c5ed28, 0xf3781c2b, + 0x4fe21d1f, 0x0d5016fd, 0x80765e77, 0x428172db, 0x817c2d49, 0x46c21cd9, 0x59bf31df, 0x557794ce, 0x09468778, + 0x44668625, 0xad1a1ded, 0x7c772ffa, 0x3c24e170, 0x45955fbd, 0x686cc3b1, 0xd08b0519, 0x1f274983, 0x68d64aee, + 0xd1cda071, 0xccc3878e, 0x073435c9, 0xa7d929a4, 0xdf1bf292, 0xaa37442f, 0xbc0a5040, 0xfb3e0cea, 0xb7bb0fb8, + 0xc6ff628f, 0xd409b807, 0xb882d39c, 0xcc002692, 0xadb78e35, 0x8a8bd915, 0x042b5d50, 0x75bcda0d, 0xc2c5a039, + 0xb39683f7, 0x32b119bb, 0x715f4c95, 0x41d6b16a, 0xe92454b0, 0xf7c4cf6e, 0x5843721b, 0x7895bf81, 0x6988e4b3, + 0x460d64c2, 0xcacc3860, 0xdd34869a, 0x2d4f2c6b, 0xa6206b11, 0x631d199a, 0x62a41864, 0x9845af31, 0x6af8726d, + 0x5ec2e678, 0xd37b4676, 0x4a7acb2f, 0xb0994a65, 0xa310f487, 0x8dd41c11, 0x4decce7f, 0x5860d50c, 0x57b94a3a, + 0xa768c5dd, 0x8d683632, 0x71674c21, 0xe6bbee8b, 0x9e29951e, 0xe555cd44, 0x8bfcee21, 0x6ee0ccc5, 0xfbb2257a, + 0xaece4615, 0x3f76caee, 0x5278fba7, 0xef24aaac, 0x1ebfa959, 0x57845c23, 0xf370dfaf, 0x9f58e6ff, 0xf564c887, + 0xb37e7cad, 0x776cc45a, 0x751b22af, 0x6a6f3f8a, 0x189c0fc4, 0x20ac5e28, 0x21fb342e, 0xac1f98d9, 0xc4a5633c, + 0x1a21b4c8, 0xda0f45ef, 0x02440bdb, 0x5233c01a, 0xfd7aeee1, 0x367591d4, 0xab90774e, 0xcd9b2d1e, 0xd556c0bb, + 0x5639153d, 0xdac45bff, 0x909157c8, 0xd2d93069, 0xe45e25f9, 0xf22de68c, 0xc71cacd8, 0xb8f5af39, 0x95691f48, + 0x5847cf25, 0xa4ca3c7f, 0xd38cb0cc, 0x3a503ca5, 0x8f854fd0, 0xee19c836, 0xc6cf74c0, 0x75490280, 0x28632f52, + 0xbee578d9, 0xd799801e, 0xa4624b2f, 0x8b3aa803, 0x52ede283, 0xcd725038, 0x98bcce20, 0xaf14d5d5, 0xb5e1a003, + 0xe300923c, 0x0ff6c544, 0x5f728091, 0x0f691d48, 0x9aff7631, 0x86f0e0d7, 0x1b0132fd, 0xc15ada5a, 0x3a5fc2a9, + 0xebbd6987, 0x493f386d, 0x2dba1cc3, 0x3bec198a, 0xef730f11, 0xecb92baf, 0xab65467a, 0xdc661adb, 0x9ad16546, + 0x186100dc, 0xf4118436, 0x3488d6b6, 0x5feb9a7c, 0x34796a01, 0x6fb55732, 0xc462b5b9, 0xf4e52ae3, 0xaf413ff0, + 0xa41969dc, 0x7ea448e6, 0x0183feed, 0xb71fb4c9, 0xa026c27d, 0x0acb28ee, 0x9b4e896d, 0xc82150c8, 0x098fcc1e, + 0xe17e0d78, 0xa039c05f, 0xc3f79b4b, 0x5118f67d, 0xdfddcaa9, 0x59db4be0, 0x0078ba3e, 0x553f701b, 0x0bb503a8, + 0xc7eba25b, 0xf407ff8d, 0x99ec2228, 0xbed6da96, 0xe51550a3, 0x61b0f390, 0xa9f95e6d, 0x1eed164e, 0x1c68d61b, + 0x39883f81, 0x76449e5a, 0xc3a585fe, 0xc6ee48b9, 0xfd88f2ea, 0x1c5de877, 0x3feb19d5, 0xface7535, 0x8b6f1d3c, + 0x98724045, 0x66e96218, 0xde3d611f, 0x12b6465b, 0x8b512886, 0xf15aac68, 0xc41ab80a, 0x4e276adc, 0x36675e15, + 0x8e6a4473, 0x3d3a69c4, 0xbe90733d, 0xe69cbb7d, 0x207a2a61, 0xa2210762, 0x64300314, 0xb511787f, 0x207b41e2, + 0xb084859a, 0x9844cc67, 0x23f4b3e4, 0x6c655765, 0x64a0d3e9, 0xf4aa5a4e, 0x40c9cda1, 0x4ff44310, 0xcb038777, + 0x67c85564, 0x8005d350, 0xf288bfda, 0x399734f0, 0x88b14ee6, 0xd0d11fe4, 0xfd4efb23, 0xca1a8281, 0x2a14a213, + 0xa9167d06, 0x671077f8, 0xb53bddfb, 0x3473ccab, 0x978123f0, 0xf98c5bc5, 0x7242a78a, 0xfb7ff0b8, 0x7911cd3a, + 0x1e886002, 0xe9730ae3, 0x7417f266, 0x5d8de6bf, 0x2553a541, 0x14136983, 0xdfbc7169, 0x96ed9ffc, 0x757b945c, + 0x8360bf6b, 0xcbd1961d, 0xf7d0a516, 0xa88a652b, 0x3e1a30e9, 0xc184863b, 0x8c407572, 0x428086a3, 0x4813cb62, + 0x49cd8958, 0xf55c3109, 0x9a0fdfcb, 0xc720e807, 0x48e4251c, 0x79d99a1c, 0x77008b93, 0xfef29f23, 0x7d88faeb, + 0xac1e4734, 0x0d12f8aa, 0x3d0985b9, 0x8af395ed, 0x4ed4e7ab, 0x823cdfc3, 0x18eea2ac, 0xe2bce434, 0x96056abd, + 0x65b3a196, 0x6d9e21f8, 0x32187d4e, 0x5778061e, 0xd8574462, 0xc23f485c, 0x3a0aa41d, 0x5ac66759, 0xe34002de, + 0x1768745e, 0xa71aac20, 0xbddd9cb2, 0xb2a2bc67, 0x25b6bcee, 0x4bd011cc, 0xe474e166, 0x33ae3aab, 0xa02240bc, + 0xf1fe899f, 0xf0eeaed8, 0x535f9114, 0x9da3a1e5, 0xa643985b, 0xec5fcc06, 0xfc8472d6, 0xd3043e74, 0x0451f7ba, + 0x0cad8ab2, 0x968b7985, 0xc86418b8, 0x93a4ba89, 0x1f6957e1, 0x67712e10, 0xb393ffba, 0xab778f97, 0x0f278600, + 0x92ddd9c0, 0x642812c9, 0x8a403eb1, 0x0139d3b0, 0x0c976726, 0x9edccad5, 0x5f44a1b7, 0xbfb4d142, 0xb9ee30fb, + 0x00d5b94d, 0xcae3ff9a, 0x311fe1fc, 0x0d201f98, 0x59a4a4a1, 0x2ad8690c, 0xd2bf91ef, 0x65c8d528, 0xa3777914, + 0x41c6d0f6, 0x7ccf113d, 0xf53d6a67, 0xaeff796b, 0x190d7ec1, 0x78560694, 0x336fb050, 0x2ec8e712, 0xc03293f0, + 0x6e8bab35, 0x23fec0c4, 0xd419e0fb, 0x77b78b96, 0x68f7efaa, 0x384efde3, 0x303fa8f0, 0xe2f20063, 0x1443b856, + 0xb0fb00be, 0xf6ffad73, 0xb958c7a0, 0x09ccb0a3, 0x98e3e472, 0x94c43dff, 0x1a34fccd, 0x0874b1ad, 0x14306667, + 0xc22e87f2, 0xe56d22b2, 0x274053ef, 0xcdb5684e, 0x1c888f71, 0x1b0ddf27, 0xeccddf2e, 0x0f36675a, 0x5f6c7c83, + 0x2dbedda0, 0x23526d52, 0x487cc564, 0x7388afe5, 0xb7260b93, 0x34800bc8, 0x2a6c817d, 0xbd2f0548, 0xab4c1407, + 0x25d4a68a, 0xffad6fdf, 0xc4d0ac94, 0x04b26e01, 0x14dcd2de, 0xbc2c9ae2, 0xc5979b40, 0x544302c1, 0x6a7527eb, + 0xb482f06d, 0x1f3e66c7, 0xddf7a380, 0x27d5cdfe, 0x0e1f34eb, 0x7c51cb56, 0x2700ed0e, 0x7622bd73, 0x0c24d4de, + 0xeb028ae5, 0x8e4a53b5, 0x9d4dea87, 0x08dc2e9e, 0x9572c80b, 0xd8d40735, 0x3cf0c5b2, 0xac52b161, 0x3c0b9287, + 0x0048e671, 0x018dd154, 0x21279bb3, 0xdf645e64, 0x0691f4b6, 0x9e7265a8, 0x7a69a16d, 0xbeb33262, 0x7cedaa64, + 0x3f776aca, 0xd46a07fa, 0x22645f6b, 0x464472b8, 0x78271844, 0xcb82fccd, 0x1debb3d6, 0x4c53a962, 0x8f6d0b55, + 0xbbde6335, 0x3651ba92, 0xbb0a46e7, 0x31998989, 0x34c3a756, 0x598c68d8, 0x40542d97, 0xf4e1884b, 0xcf287f02, + 0xc2b39836, 0xac409d53, 0x99839ae7, 0x862097d2, 0x1b020472, 0x2f171715, 0xdefa73c1, 0x484daf11, 0x9ba9be24, + 0x9caf2047, 0xd5a42472, 0xcd597581, 0x8bf2db53, 0xb3999c07, 0x2a487c0d, 0x40c400f9, 0xb42fb7d1, 0xc40f3acd, + 0x09a14312, 0x1b39b6ee, 0xe40d5d6b, 0x6a9b0912, 0x1c958b09, 0x196da376, 0xeb98fd4d, 0xfcb88bc9, 0xd19ee257, + 0x2ee6ef16, 0x435a5e3d, 0x26f0b408, 0x9d644173, 0xfcbb3353, 0x222b714c, 0x2c332595, 0x83692303, 0xbb95589f, + 0x1b0adc84, 0xe41ec2ce, 0x72f59bde, 0x42cc94c3, 0xd7a50208, 0x45842943, 0xabc880a3, 0x5c416ee0, 0x0c2d31c5, + 0x60cd550e, 0x5e1fe8ad, 0x94dcf429, 0xe82e191b, 0x4a1cafa5, 0xfc6e9a90, 0xa6018517, 0xd1aee7a3, 0x047e8540, + 0xf2d338a0, 0x7de86a31, 0x6be45076, 0xb02e148c, 0xd9d39526, 0xd494349d, 0xd6fc83b5, 0x5ad4592b, 0x47fb777e, + 0x5c877e9a, 0xe8e7065f, 0xfcd98207, 0xadec0271, 0x1afd8742, 0x65c1b251, 0xe9a7d431, 0x3ec0f41d, 0xbeeebbbc, + 0xf087e60d, 0x018cc68c, 0xc67f9189, 0x8d2f5625, 0xbe52404b, 0x26c1545d, 0x075c1fde, 0x44da8389, 0x0fa2a13d, + 0x01737b35, 0x737c0b59, 0xe6a1393d, 0x5725ac1f, 0x955ea9b6, 0x51c2dceb, 0x0ab3dc30, 0xfa012048, 0x6e3c43a5, + 0x486174e6, 0x13dd06d9, 0x80828a64, 0x238244e7, 0x02ef6d9b, 0xaaef4cb1, 0x256e9110, 0x214f7dad, 0x4f3d84d2, + 0xdf49ea71, 0xdca28780, 0xe237b773, 0xafa35691, 0x61e31092, 0xda90337d, 0x95f98edf, 0xa563098e, 0x6ac8bc64, + 0x0eda6e7b, 0xd18caae3, 0xe3770ef3, 0x538b4947, 0xab19e6ce, 0xffcf65d8, 0xe69cc534, 0x2ec2a0ac, 0xe6c1f0a7, + 0x0bf79696, 0xb469e4ca, 0x094e5c90, 0xfbe8f06b, 0x37688bf8, 0x112203a0, 0x46a8c83a, 0x6441febf, 0x996cc771, + 0xb8dcc455, 0xe41f05db, 0x7505b462, 0x84865d7c, 0x82a1f3d1, 0x169b6bd3, 0x22ba3439, 0x1b133534, 0x34d49a18, + 0xdb36d07f, 0x9f43e203, 0xc99b4618, 0xd5ecf192, 0x8626e70f, 0xba7fa47a, 0x25ca1eb0, 0xbfa7f244, 0x5ba8f717, + 0xb9a04d3c, 0x63736321, 0x9007a464, 0x6ba040c3, 0xce95f397, 0x9822e3f4, 0xb0d69765, 0xdf05b4ef, 0x1ebeec4d, + 0x0c2e783b, 0x67e328bf, 0xd67a10a8, 0xecd961fe, 0x013c8fae, 0x1e2ad138, 0xf5529f8a, 0xb4ebaaa7, 0x8ab3fe99, + 0x79cc8e59, 0x9364627c, 0x24d15406, 0x1c1b5095, 0xc1fe6d36, 0x6a60924b, 0x8b40c854, 0xbf3e27f3, 0x93d7e1c3, + 0x654d3135, 0xa712b6e2, 0xcac809f0, 0x4d849990, 0xce673b99, 0xc3d435c1, 0x68f9f33d, 0xbaf9fe66, 0x270fe921, + 0xcbaa9be2, 0xb61bf6e8, 0xa6d45103, 0xcc017424, 0x52d1aa68, 0x23c4a7f8, 0xf3def4a7, 0x67d2e325, 0x0c52afb2, + 0xa343ad5b, 0x546ac2bc, 0xc680c99d, 0x26251316, 0xc14c9a87, 0x84adb9c9, 0xc4f24d3e, 0x577e675e, 0x6c49fcd3, + 0xa7a5b1f8, 0x2924a83c, 0x6567f3f9, 0xafb94c9b, 0x1fb8b069, 0x299ff669, 0xadc6f87c, 0x68569d5a, 0xb5ba347f, + 0x683de653, 0x74330b6a, 0x3f2a6e47, 0x6c3ba76d, 0xb32563d0, 0x5cad7e3d, 0xeeb1633b, 0x20665071, 0xec7ce486, + 0x776b6c98, 0x247cdb37, 0x04a23b83, 0x1151f601, 0x4c254322, 0xcd2d2d25, 0xd069d203, 0xd6888bad, 0xe25baa1a, + 0x2782a112, 0x9504dca1, 0x56f027d4, 0x2a49a400, 0x57ba8559, 0x0ed7d502, 0xc9da7a8b, 0x829813b9, 0xe1b971bf, + 0x0ad09d95, 0x7d9b58b3, 0x8f6170d5, 0x43f18eca, 0x2bf62e08, 0xdba6fb49, 0x28c06070, 0x526b9a6c, 0x4a24ed39, + 0xe5d89c4c, 0x2c530aba, 0x88d94502, 0x593b82eb, 0xa9a81b89, 0x3b1d2710, 0x49ff0ab9, 0xb5b53499, 0xa88e096c, + 0x64b32d7e, 0x3f87e9cc, 0x149e75be, 0x063aa924, 0xe740c3f0, 0xbbfce22a, 0x278b5def, 0x8966d688, 0x8bde4308, + 0x4b2c3483, 0xee73bd44, 0x62097d6c, 0xf9e8659b, 0x42f3af90, 0x3315a65a, 0xddaa6700, 0x4424f75e, 0xad3c9dcf, + 0x7023d05b, 0x0b29737c, 0x78325ce3, 0x692dcf5a, 0xc89f22d0, 0x62b818d5, 0x819e987f, 0xaff15a34, 0x0ba8ec1d, + 0x2ce07dc5, 0x734811a8, 0x2b611360, 0x1d341b78, 0x64511663, 0x22a7d1be, 0x651d7981, 0x8eee48c4, 0x5d98668c, + 0x48f1b455, 0x12bb7fed, 0xa44abb0b, 0x975cf2f4, 0xe407cd33, 0x8fff514c, 0x8103dd49, 0x479d9861, 0xcf087ae1, + 0xe6749bb0, 0x397767bd, 0x408e6dbf, 0x14b3cb69, 0x3f07f979, 0x293566ea, 0x32f0ff70, 0x23b4dc35, 0x1c58fd13, + 0xc9525b5f, 0x4800c3a6, 0xe732e06d, 0xfa07d221, 0x7a6a340a, 0x30fb6389, 0xad20b7b5, 0xaa2d0db7, 0xba51139f, + 0x0699ebd4, 0x7979ed2d, 0x1722b53d, 0x3a594a86, 0x4296b249, 0x8b1d9e5d, 0x8845a51a, 0xc5958972, 0xfc4b34a4, + 0x0a801dde, 0x1e8473dd, 0x6f07ed46, 0x1d52b12a, 0x49af3d2e, 0x05cf7d14, 0x8aff2ad6, 0xcf53cf6b, 0xdbfc0a35, + 0x2c325be2, 0x9784b6f9, 0xe6e74e19, 0x252222f5, 0x990fc8ed, 0x710343f5, 0x7b6bc6e9, 0xa5eba3d3, 0xa6c203e2, + 0xb43e51b7, 0x68ef2650, 0x4ece348b, 0x664e4da7, 0xab1fe904, 0xc22a6f24, 0x990654ac, 0x92d886a6, 0x050bd290, + 0x36219059, 0xb7a126a5, 0xfd9a66fe, 0x65087c90, 0x45cfcc3d, 0xaaf57e0b, 0x0b17d664, 0x3bd57c8a, 0x7a2118bc, + 0xa7ca3e38, 0x5b93f0cc, 0x8fe1603f, 0xcf21664a, 0x97fc61b8, 0x052ad7b3, 0x53c8074d, 0x4ab0ca86, 0x8b80ded2, + 0xcdc2072f, 0x96e23625, 0x768b4807, 0xb45d5cd7, 0x27c3bdea, 0xb2bce87a, 0x55daca59, 0x3467f50f, 0x63ed269a, + 0x29140928, 0xb4864ed5, 0xcb5279c8, 0xe85e6486, 0xb0d36a05, 0xdf443b6a, 0x6bdce147, 0x7d1a9a2a, 0x2d816034, + 0xec05deaf, 0xcb11b61f, 0x14fb80ee, 0xe279df33, 0x4fe4ccf5, 0xd0d810d5, 0xe36faf3b, 0xac9c73e4, 0x9610c214, + 0xe4f26509, 0xb9de03f7, 0xcc861f22, 0x3c915991, 0x184b7244, 0xddd5714a, 0x30297b7d, 0xbf161611, 0xbe1ab4fb, + 0xd331bf29, 0xe4db46cc, 0xb267302b, 0x78f0c4f3, 0xf46548e3, 0xfb7033d2, 0x45d33d2f, 0x2a2a9df5, 0x124b8fdc, + 0x5c77aeca, 0x52a505cd, 0xa77fe437, 0x24bfdbad, 0xaa59395e, 0xfcf80d6e, 0x117d8472, 0xc8702119, 0x1143ac7c, + 0xa8186b8d, 0x3b40944f, 0xd2339b9c, 0x7630a427, 0xa2c3cdc3, 0xb81e8b9d, 0xd0d515b5, 0xc2a473d3, 0x87f6c80b, + 0x8bf66487, 0x89e4eb77, 0xdd9d5383, 0x8cd83ca4, 0x8c414f86, 0xa0e30c3e, 0x4660b078, 0x2cf11818, 0xe9c5936e, + 0x69d20f99, 0xd05f2e96, 0x17cbf3a8, 0xdd432840, 0x2b56f42a, 0xc9624598, 0xdf716212, 0x439511f8, 0x90851e6d, + 0xa23315c1, 0xc11ff561, 0x538f591b, 0x1b6f10e0, 0x82182b20, 0x80c1fa48, 0x2416d948, 0x06c75d01, 0xeab0080e, + 0xc49b603a, 0x604796cf, 0xbdfa60ca, 0x3b40084a, 0x1e6dfd3b, 0xf6cf411c, 0xb626d2c5, 0x6f466753, 0xa47ada5a, + 0xe213ac93, 0x861b70a7, 0xda9a68ce, 0x3dea7d97, 0x9879231e, 0xb422eb3a, 0x04babea5, 0x35932aab, 0xeec301e8, + 0x7b229420, 0x1b44b665, 0x53211abb, 0xc84479e9, 0xc4bb3709, 0x4d81d416, 0x826a1fd2, 0x55c1d5d3, 0x247e7a99, + 0xfcd6c115, 0xc451d3fb, 0x4977743a, 0x4352ed81, 0x695c704a, 0x4ebaadf5, 0x1967e368, 0x064c961a, 0x86141a3f, + 0x754456cc, 0xf02cc09d, 0x56ead805, 0x060cdcb4, 0x1bc18e63, 0x9e17dedd, 0x0fa78036, 0x0a2f4859, 0x90b334b1, + 0x607ef4a0, 0x695e8e0e, 0xb0f95eac, 0x5f421a7e, 0x0f7c3ba9, 0x5606e035, 0xb60fb69b, 0xe5fa0c70, 0x2563f858, + 0xed79c0cb, 0x2c3e6a92, 0x0a6aaec7, 0x4a44606d, 0x3a81623a, 0xa6b54620, 0xee9d4236, 0xad639d5b, 0x0a1b4a0c, + 0x6e933bf0, 0x51bddcc5, 0x2afdc87d, 0xd368f550, 0x98a5ac4b, 0x1a350ecf, 0x746896eb, 0x3f94a72e, 0x8d747ff6, + 0xddfcd08c, 0xe2bd5374, 0x656bca35, 0x6aedb4c2, 0xda37c7c5, 0x6e45f905, 0x953c2ce1, 0x96919f33, 0x3bd5c05a, + 0x69a41230, 0x5acc16eb, 0xcfd71e75, 0x1e4ddbc1, 0x66c22991, 0xf872e2f6, 0x25002273, 0x56b752cb, 0xec00f2c9, + 0x9254b0fd, 0x7e2a7ffc, 0x67b378a2, 0x04640db2, 0xc5fc9898, 0xd34b6295, 0x086f5b31, 0xa12908ba, 0x0bc2d855, + 0x87d942c2, 0x1759f8d8, 0x96a982bd, 0xaa18fc14, 0x970c8bf4, 0xeb75dc8b, 0x54f2e1c5, 0xed55f873, 0x0654116b, + 0x65c88dbe, 0x4316affc, 0xb365ce73, 0x5bef2ee6, 0x0c0eff5c, 0x0b38c3a4, 0xe618b175, 0xa9cb6ea9, 0xb034bed2, + 0xfa475c85, 0x77b07ccd, 0x874dbdac, 0x5a54e10a, 0x4b931829, 0xf891893d, 0xd4ea61fd, 0xeaf74041, 0x8cbcc1e2, + 0xeb46c6ff, 0x644b4c2d, 0x419ca434, 0x22f76e7d, 0x16aad01a, 0xff8b76ab, 0x5356403e, 0xb61d26d8, 0xd8438cad, + 0xbbb5ae10, 0xfadab144, 0x16692e28, 0x17b914f6, 0xf94914b7, 0xe14b6b0d, 0x62f9dfeb, 0x22749ed7, 0x835b462a, + 0xec61a901, 0xb781629f, 0xc229cfcf, 0x92d58742, 0x392edfeb, 0xd37f72d6, 0xa468e0d6, 0x7a471cf6, 0x560baafd, + 0x700aa072, 0x5add3821, 0x34487c6b, 0x9f8c147d, 0x284d641f, 0x3cd1894c, 0x48bbf145, 0x1293990b, 0x39cd935d, + 0x5bdbae80, 0x33f0931e, 0xf350ae61, 0xac5d2b2d, 0xfe9992a8, 0x86145354, 0x85a7765f, 0x0593a348, 0x01bee31c, + 0x9414f837, 0x830d729e, 0x6f323c16, 0x021e37e7, 0xec5637b5, 0xad284568, 0x7e1fda26, 0x65027c2c, 0x332249d1, + 0xaf054475, 0x9b47ebcd, 0xe3740982, 0xcbe74b29, 0xa9a8b35a, 0x9477d4ca, 0x4dc35e3a, 0xd3e9dcbf, 0xb94c3f3b, + 0x3f218957, 0xee777833, 0x440fd91d, 0xf3f2a828, 0x036d59c6, 0xe4a27a63, 0x14fdf9b6, 0xd9a5505c, 0xd9ddc583, + 0xb06966e8, 0x5c02ed18, 0x313de968, 0xf46ff6c7, 0x88fe38f5, 0x3aa65ff9, 0xfa77f1bd, 0x1a0a1c6a, 0x88669e38, + 0x5cfc3d0e, 0x5235bedf, 0x90b75317, 0xe72d25d5, 0x58e11122, 0x7feed987, 0x87340e80, 0xdad17165, 0x9b8787f6, + 0x3be6d744, 0x09d329bc, 0xad7efd97, 0xd134bcf1, 0xd286a7dc, 0x116c0a2d, 0x7bbd48be, 0xd4176873, 0xff725ef9, + 0x399d22cd, 0x92fbb4a5, 0xd9f40bbe, 0xdd4666ee, 0x79bbbe79, 0xccb6b35d, 0x0bde35d6, 0x39b59c4e, 0x5eae87de, + 0x5a1414fd, 0xfee65539, 0xc9cfb460, 0xb8a6df95, 0x3adfae3c, 0xf96d3c75, 0x7c2af48f, 0x245087a8, 0xc0822194, + 0x03b6ba07, 0xf2e1628d, 0xd7717cde, 0xa3bd95b4, 0x8e40fb0b, 0xeb364c9c, 0xe0631760, 0xcba5a4c7, 0xd2c5fe48, + 0x7dd33397, 0x4c04ed0f, 0x15ef6318, 0x2079eac7, 0x2899df8c, 0xccf074e2, 0x889ae78a, 0x8edda3bb, 0x84ec326e, + 0xd0828d2c, 0xf7f5e762, 0xb2856cc2, 0xf3c094d6, 0x308ce766, 0xec57318f, 0x21b05f52, 0x1f939415, 0x2df4fab5, + 0xf4a6b737, 0x84f2c073, 0x712698fd, 0x711ac982, 0x4bca0464, 0xb799a6de, 0x68950250, 0xbb3b2a30, 0x5b025f3a, + 0xa1a39a29, 0x07d77649, 0xd2171881, 0xc7f3e983, 0x3f2457fd, 0x683c3ceb, 0x6fa18331, 0x6318f86e, 0x5f50be54, + 0xe291b6ce, 0xed5be4d8, 0x010dc789, 0x95d0a1ae, 0x715a3f77, 0x0b46340b, 0x732bea71, 0x890bf8c1, 0x940c3606, + 0x42f04183, 0x51a7a7c9, 0x3f2faa50, 0x9d7215e2, 0x2b7fac5c, 0xa7b0019f, 0xb8c4223a, 0xe5409546, 0x205a8c91, + 0x8c24763e, 0x76f3a9ec, 0x2b08de94, 0xe42225aa, 0x43a78276, 0x5c29fd60, 0xe91bbed0, 0x235bd1cf, 0xa0a1afbf, + 0x90b9f1b8, 0x1ace544e, 0x84f83719, 0x53fa7134, 0x6db96b5f, 0xcaeb77f7, 0xf27e23c1, 0xff0089d0, 0x0be598f3, + 0xd569e60e, 0x43ac5c59, 0xd9aeb0a5, 0x37804b30, 0x3b3e4eff, 0xd02d8270, 0xc14bfa72, 0x9b4db8b1, 0x2beee7a7, + 0xd4bb5dcb, 0x52ea05b1, 0xe9712f6a, 0x542d47c3, 0x1332f903, 0xd22780f8, 0xc6df2065, 0x61451768, 0x24d2bbfd, + 0xd294bec2, 0x264fc1ae, 0x9a169803, 0x9e5aeee0, 0x9d29cdda, 0x242a116e, 0x9186824c, 0xd3131ab8, 0xc3a2f41d, + 0x83755229, 0x3a0d1bde, 0xf0dd74be, 0x8002ac8b, 0xd5bb7f8a, 0xbf60fd46, 0xd22fbd13, 0xa7a25d37, 0x6a1bbcbb, + 0xe8a9ce50, 0xf260ba1f, 0x29841f25, 0xba3f2e73, 0x809da8af, 0x0b8a5af2, 0xef8c403f, 0xab4496e1, 0xc120d461, + 0x9039f643, 0xccc34ad9, 0x6fd0612a, 0x997863a1, 0x60043b35, 0x2d9f4ba1, 0xf15c105b, 0x9f697b8b, 0x295fccae, + 0x4f4bbc15, 0x44fea093, 0x06c9b102, 0xf84e01b1, 0x7162f31a, 0xce01ff0f, 0xee634ff6, 0xe9ebd062, 0x7af73437, + 0x65f329f9, 0x79c34a11, 0x98883e13, 0x767737e6, 0x04f5b682, 0xdfbb3050, 0x503d8e34, 0xcd584d3d, 0xc827bfac, + 0x4d222fc4, 0x0d0c67e5, 0x68ef9a0a, 0xf89becd1, 0x8468ee71, 0x9e262dd1, 0x85db09cd, 0x9a5e9651, 0xc6cbd7c5, + 0xad8e8703, 0xebb66113, 0xf8735944, 0x29f3bbd1, 0xe0d03e77, 0x7c6f0f4d, 0x82909dca, 0x8253cd66, 0x0d974acf, + 0x136b1349, 0x0a1034f6, 0x1a64c276, 0x69a1bba5, 0xd5c845f1, 0x54a5f509, 0xaf298cb5, 0x71e52204, 0x3776af9c, + 0xed4e87a0, 0xf0c6cac9, 0x3a25c3db, 0xc1d9b932, 0xd7bd5b4e, 0xf18a924a, 0x72294839, 0x633e807f, 0x9be1dc6a, + 0x2527a45d, 0xb0fe3f6a, 0xad854102, 0x76275b2b, 0x2acd5cb8, 0xba919562, 0x863b0e61, 0x303a8108, 0xdd79e96a, + 0x9d440a57, 0x0066752d, 0x998f7126, 0x72316e15, 0x06cd45b4, 0xd3f4c26d, 0x15370192, 0xe571b0d6, 0x3302b921, + 0x8ca438db, 0x6f94fc66, 0xfa864304, 0x84c69002, 0x0543db36, 0x014dee41, 0x72690a7c, 0x34f3c2c6, 0x845d0a03, + 0x556b5de5, 0x8672a2bd, 0xc05c1878, 0x90d977d8, 0x03e8936a, 0x6a5e23c5, 0x32c831b0, 0xfaadb04e, 0x962a60f5, + 0x54605024, 0x245cdca2, 0xca7ccc2e, 0xf3d6bd9d, 0xeca6fc54, 0xfe700a3d, 0x52821178, 0xa68df9ad, 0xa5085a1b, + 0x7f600f78, 0x68264d6a, 0x9d4ea439, 0xa580edf9, 0x01137398, 0xc18c6d66, 0xd3cd830b, 0xa254d17f, 0x681f14ec, + 0xbe91742d, 0x726e0b07, 0x1d03087d, 0xa0e3221c, 0x2deb187f, 0x1cba7558, 0xc9ed2d89, 0x375dc27b, 0x079220b6, + 0xd8bfda9e, 0x7eb6cf85, 0x5a220646, 0x097912c3, 0x6ef21d14, 0xac3dc1f6, 0x1b087cb5, 0x9137610b, 0x291ab356, + 0x38060c03, 0xaab8f216, 0x9aed0e4c, 0x51f42590, 0x815cb44f, 0xbb589bd9, 0x4f4cae6b, 0x7b131af0, 0x90457cfe, + 0xdc4c7fa2, 0xb74a9f12, 0x49b1d7d5, 0x1ee74a75, 0x527ea469, 0x7208276f, 0x4977dc78, 0xa133b90c, 0x931a8f35, + 0x792437fe, 0xcd175b8b, 0x2044da78, 0x46877814, 0x6375476b, 0xcd3861b4, 0xf80813d2, 0x469edf5c, 0x89ef00b2, + 0x5478bc74, 0x9f9fe7e3, 0x6e3d4d59, 0x4667a704, 0x8a2991d8, 0xe02f45b4, 0x00684a1a, 0x4b9d3341, 0x15f06a21, + 0x241eea64, 0x0af34913, 0x56ee8461, 0x1ad6e178, 0xb85cb9b6, 0x0de58a6a, 0xd6446043, 0xcb02a053, 0x5ad30a99, + 0xd1a53e63, 0x2b505668, 0x4f76efad, 0x1d6faed3, 0xc077c364, 0x9aad794e, 0xc8f8d689, 0x55cbc896, 0xbd787176, + 0xd706256c, 0xf60ac7e3, 0xa6779a3d, 0x4d5908f8, 0x038e6576, 0x636849b7, 0x4985d12d, 0xdb01182c, 0x76859f88, + 0xa720e7c9, 0x5b237b98, 0xe468d646, 0x3c18b369, 0xfcf9722f, 0x5a10d371, 0x09eb9e2b, 0x5d2416fb, 0x77c6463a, + 0x8fe1c2ad, 0x1c72df01, 0x825381f4, 0x6749f312, 0x3f96be5e, 0xe68037b0, 0xdb5e3c26, 0x33baf854, 0x3eabe007, + 0x9fadef58, 0x5fb1a4ad, 0xf978655e, 0xcc88615b, 0x668bb3d7, 0x2eb2dc96, 0x830fcfb7, 0x0264e152, 0x5b88ab0c, + 0x4cccf870, 0x5872c2e9, 0x9289266b, 0x4cfaff9f, 0x775eab16, 0x5d9a8d90, 0xed77e0b7, 0x7b58986e, 0x12b1cf83, + 0x4fbf9be5, 0xe081ffc4, 0x366b7106, 0x2656659d, 0xce920983, 0x924a63e7, 0x8cd09f7d, 0x75a16e11, 0xdc189c15, + 0xa6008f3b, 0xa51286d5, 0x4dbc50f3, 0x13052f6a, 0x3e6a6450, 0x6345566f, 0x72cc7e66, 0x990691b1, 0x8e7779bd, + 0x7e6c9115, 0x1702906d, 0x296061c7, 0x3bed4b04, 0xc9db7ca6, 0x06d35a15, 0x219db403, 0xc8a4f6ff, 0x28601a83, + 0x8e77eea2, 0xdb5cd887, 0x3bf9f412, 0x5af3954f, 0x22c2d591, 0x4ed61277, 0xa304297d, 0xae23a736, 0xfdf578fe, + 0x0193e7dc, 0x239f5ef8, 0x012dde0b, 0x8b321c11, 0xc96eed7e, 0x13042c62, 0x564a9f9e, 0x96feb6e2, 0xcdc24496, + 0x62a2fa41, 0x8f6179fa, 0x0e3af818, 0xa3846b48, 0xcdcbdb7c, 0x9e81440c, 0xd95dfd55, 0xaddbd580, 0x6b531cbb, + 0xdbf99cc2, 0x0d952bd0, 0x9cab8a09, 0x90ba199b, 0x92a77ee9, 0xca14126f, 0x55169320, 0xeb813ff4, 0xc50a2921, + 0x4baba74d, 0x51a8db55, 0x531c90e4, 0x7d8f0a76, 0x5c6a96e1, 0x76fe3cea, 0x3711ede0, 0x393d761a, 0x2a313bf3, + 0xcd8a9ca4, 0x0e97e3ac, 0xc9627eb5, 0x62fdcd21, 0xbe7d2f1a, 0x43646084, 0x0261bc5c, 0x74787872, 0x337611cc, + 0x17bfa243, 0x641f2d19, 0xef15e610, 0xff178117, 0x126a6911, 0xfa4415db, 0x1ed211a2, 0xab5ed947, 0x4caf1d86, + 0xd7407bf0, 0xab8c2093, 0x6ef1e9aa, 0x366d27c6, 0x2e5d09bb, 0xe19bd717, 0xa6158cfd, 0x44e51f91, 0xf85d1b7c, + 0xc04dffdc, 0x60e2a179, 0x7f9a60a8, 0xb2363cbe, 0x3f4b5437, 0x2deb611d, 0xf3aea830, 0x82fca924, 0x7f8446ff, + 0x638dc1ff, 0x85fd4476, 0xe11bb201, 0x7771bcfa, 0x2e5b202b, 0x9f2b8204, 0x485905ca, 0xdca151cc, 0x712df153, + 0x6c96c505, 0x0c09e85a, 0xce250487, 0x4b3d8ada, 0x8fe2260f, 0xe9025073, 0xaaae4c64, 0xfd714f25, 0xc869d9c0, + 0xde17ed40, 0xccb2ac59, 0x935fc35a, 0xc19113dc, 0xc227f144, 0xfe9e1107, 0x3fa89042, 0x2f22bcbc, 0x5e903248, + 0x8fd0953b, 0x31ddfb87, 0x25a9f720, 0x2cd269da, 0xd786ca2c, 0x9d230093, 0x207c6127, 0x498a19e7, 0xf718de43, + 0xd4be3288, 0x61184286, 0x025f41b0, 0x59ca2d23, 0x95ff9e6f, 0xa5d0c169, 0xea914902, 0x8dfc32a1, 0xf4b46c98, + 0xe4502b03, 0xd9fd41ab, 0x370dd32b, 0x9476f2b7, 0x5fcf20c8, 0xd62147cb, 0xb52c4495, 0x17d3bd82, 0xab844a61, + 0xae6fd270, 0x65406ab3, 0xb487a002, 0xb87a19d6, 0xa0a2d3c9, 0xf54b547c, 0xde1afd1f, 0x8d9062c1, 0xcdddd02f, + 0x211749d1, 0xa7e8e1b0, 0xff8577f8, 0xe617c51d, 0xcfa96514, 0x4f24f3f9, 0xb8346ad1, 0x44933909, 0x775584b9, + 0x339d724a, 0x451e80e2, 0xd2c9c0d8, 0x15bdc73a, 0x542f6293, 0x6b5685b9, 0xbd710096, 0x4a6fe36a, 0x49cfdb4e, + 0xcc6ed9a7, 0xaf88572a, 0x7f610741, 0x09cbb06f, 0x1b1bfeac, 0x2a6fdd58, 0x23a4fb60, 0xba0c351c, 0x70d25744, + 0xe340f569, 0xdacdff53, 0xe5b336f5, 0x1e1feb59, 0xaf5ab351, 0xb2098365, 0xbc1aa5d0, 0x701af075, 0xddedfb3d, + 0x5a8c9757, 0xc0a84b9b, 0x71507336, 0x379a2257, 0x790a6d8b, 0xb9b84fe0, 0x93e84022, 0x5ac6a972, 0x83adc112, + 0x42b73ea8, 0x80c240df, 0x19536fb2, 0x052ba248, 0x16703eaf, 0x37c19d6c, 0x1711d69d, 0x63f7341e, 0x6581e5a4, + 0xa8d4fc5a, 0x9909e67f, 0x75fcc87a, 0x534f6250, 0x89885ed5, 0x1bc5b9fd, 0x2fb6280e, 0x3793e413, 0xa270070c, + 0x9ef9aa49, 0x10c69889, 0xe06de221, 0x94dd7ddd, 0xcf845bbe, 0x114f7d08, 0x0c7c1eea, 0x67687adb, 0xc0f97c82, + 0xaecc00e0, 0x8bd08539, 0xa5f3346a, 0xa8ce409b, 0xd86e2038, 0x7d680181, 0x6edbd0dc, 0x0f44cb81, 0x0921335c, + 0x52f8d27a, 0x8382c998, 0x46bc3efd, 0x647fc4da, 0xb7e96e24, 0x3c70dfbb, 0xc7cd1995, 0x2e61649c, 0x196038fc, + 0x72688535, 0x0a72dacb, 0xce1445ec, 0xcfc867df, 0x097a9513, 0x000f8040, 0x031ba84b, 0x90da7e4b, 0x08ace9f0, + 0x84b34ebb, 0x3e15fd9a, 0xee35a760, 0xb0606365, 0xda7861e4, 0x84ca6452, 0x9f8d793a, 0xe71b31ed, 0x21ee5310, + 0xcb3b8c8f, 0x04b904d7, 0xba749850, 0x76673aef, 0x6380c816, 0xb3545d9e, 0x79d2203f, 0xc006a35b, 0xe4b3a9f9, + 0x47c4aa5e, 0xa26b448e, 0xf4d49ae7, 0x2a7f64fa, 0xf9caedac, 0x9e9d8f33, 0xebd20803, 0x6110ff94, 0x3ed0b633, + 0x5a08a92b, 0xac797039, 0x8edc2aa6, 0x9e405a61, 0x7b90bdb9, 0x9b03428b, 0xf415a40b, 0x4d8d8205, 0xe908839a, + 0x742bed48, 0x9f2d5bae, 0x5151e335, 0x87577c11, 0x62534484, 0xaec8775f, 0xc00e8e51, 0xa4531842, 0x76efa288, + 0xce12fb4c, 0x4cf0f8c3, 0xbe04ec3f, 0xc287ec48, 0xc5a5466b, 0x89afbe03, 0xb17beb29, 0xa556d9b2, 0x8c046159, + 0x9edebb5b, 0xee5b87ee, 0x585fed10, 0x03d9bf21, 0xd3b9366c, 0xe462aa14, 0xfa1f1197, 0x481ca1dd, 0x6b4a4687, + 0x50ae7c6c, 0x1dc252b1, 0xad48a566, 0x79ace129, 0x636db267, 0xf18a160a, 0xb4ddf7eb, 0x25a2f337, 0xc399b90a, + 0x7cab16a1, 0xe6dfaf94, 0x87507a51, 0xeb61e35e, 0xfeb80bd0, 0x31374ad2, 0x1f6e172b, 0xd1e6a9ee, 0xd4f1e5e5, + 0x01b504fc, 0x2717b77e, 0x898253ec, 0x2727d285, 0xa817d806, 0x0817d340, 0x009cd90d, 0xba2cbbc8, 0x5aa38724, + 0xfe259467, 0x995fafde, 0x372ecbaa, 0x21e2251e, 0x30d5f856, 0x94cb5cd6, 0x5ed001aa, 0xd77b1c68, 0xc30eb2af, + 0x2a5d3446, 0x54acaea8, 0x2e4530a8, 0x2ff80683, 0xa53f02bd, 0x0ab389a3, 0x0218557e, 0x940b6929, 0xafb71b15, + 0x8e166bd4, 0xb0781ddb, 0x3706114f, 0xaefe8209, 0x1e0398c4, 0xdc5871e1, 0x0c0fb390, 0x7715de9f, 0x98e4bfc7, + 0x4f88543d, 0x27f12410, 0x67641483, 0x32d6d9d2, 0x906d2e98, 0x5f5a2326, 0xee7c751c, 0x9bd550a9, 0xeb5e7bcf, + 0xca09e438, 0xfc2e6270, 0xbe9fa726, 0x45432b7e, 0xcf1be1aa, 0x21deca90, 0x67e0524a, 0x77d8d753, 0xee2d9a80, + 0x635225a1, 0xfa4e795f, 0xbb00a765, 0x429768c1, 0xe2b762a0, 0xa378cdda, 0x713494ca, 0xaa51421c, 0xcde35c6e, + 0x87e4be2f, 0xe26bb9a7, 0xfd88a0e3, 0x96acf098, 0xc46ebc70, 0x4052c252, 0x360dabbc, 0x9271b9ab, 0x8ad4b715, + 0x3d7b7500, 0xebeaafdc, 0x8c94dc16, 0xc98b1b24, 0x0c9006e6, 0x073fab10, 0xa2add5c8, 0x252e1fcb, 0x3f0b2f6a, + 0x5ce69e25, 0xe10d6db0, 0xb51d8508, 0x5b2dd4c3, 0x95da8cf7, 0x319f2f3a, 0x005128c4, 0x45295def, 0x67e6a7a8, + 0x75005f8a, 0xf6751bc9, 0x8f8f8d25, 0x22de9a30, 0x4c0eb0a1, 0x0c9cd020, 0x8e77dcb9, 0xae5159b7, 0x91c7385d, + 0xa8ca17a3, 0x30da7dc6, 0xfca0f080, 0x5d3ade61, 0xd3c5741a, 0x386a4209, 0xef7abf4b, 0x5d31f730, 0xc0398dcc, + 0xbcae918c, 0x9734da1a, 0x2eb59518, 0x71ddcecf, 0xaeb6f4b9, 0x1508de6a, 0x0b988a57, 0xc3e0edcf, 0xb88e6c38, + 0x229e8193, 0x0ecc2aa0, 0x940c823e, 0x86577717, 0x1780908d, 0xc000c147, 0x17f059a7, 0xdd031a2d, 0xcaf899b5, + 0xdc438100, 0x05bc9887, 0x47b29374, 0x3560ee7b, 0x8f571fb9, 0x3327ebb8, 0x7c56b2e2, 0xfb04694c, 0x6d0fc0af, + 0xc6931b4a, 0x2769929b, 0xb017f1fc, 0x38f1dcd4, 0x324d0983, 0xf797554a, 0xec3a77a0, 0x4f4bdd16, 0x5dc037d6, + 0x41728809, 0xaf290a21, 0xa23de8b7, 0x653bdc07, 0x17e6a1f6, 0xb8fe836a, 0x30788219, 0x6bcc871b, 0xaeeb938c, + 0xc7a96713, 0xe4c38f67, 0xa1d9113e, 0xdf0aab10, 0x01425ee5, 0x23f67eca, 0xaf594f9d, 0x7c950cdd, 0x70f2235d, + 0x639a3ad9, 0x786ff72f, 0xe384105b, 0xe1b08e44, 0x25f15934, 0xc116ed2f, 0x77d83703, 0x437ed78e, 0xc1af8bff, + 0xf1225f1a, 0x2a041912, 0x2251513e, 0xbf6d1952, 0x08b6eacb, 0xf28f2364, 0xfb854990, 0xe2e33138, 0x47045029, + 0x54ea3462, 0x9cfebfdc, 0x8956a78d, 0xf30fe6d9, 0x4679289c, 0x4d5f8008, 0xe96dd466, 0xf786bb99, 0x13235c91, + 0xd87a5a7e, 0x6e73f147, 0xa2af34f6, 0x5fb30ad9, 0x2fa9945d, 0x08de9a11, 0xc8e2f600, 0x1bb225b3, 0x2d5a1763, + 0x2808930c, 0x01364bfa, 0x2f225a16, 0xa191e8f7, 0x57456b40, 0x34fcc927, 0x277217e6, 0x0f972541, 0x1997fa31, + 0xb9993347, 0xa80d1296, 0x2a3ad406, 0x423bb3e5, 0xab970b93, 0x0b6ea103, 0x4059c8d3, 0x942053a7, 0xd9ccd5bb, + 0xdfc347b7, 0x84491703, 0xae4c2c7e, 0x2dcd541b, 0x7a28311a, 0x061065bd, 0x22175c04, 0x2de6037a, 0x217f4951, + 0x5a6274af, 0x4b812cb3, 0xa63c5296, 0x67c221b8, 0x6c835d99, 0xd79b8f2f, 0x1190317a, 0xaa59784b, 0x5907a345, + 0xedb28ed4, 0x02a10467, 0x21073a4b, 0x15a229f8, 0xe212cc95, 0x2ab720df, 0x409c29ba, 0xf6b1bd12, 0x3798bf3e, + 0x646cc024, 0x5352ceb0, 0xc3e1d9de, 0x987f3d96, 0xdc116f25, 0x1173f830, 0x3863006b, 0x4709b055, 0x81f6305c, + 0xba8c8e91, 0x8c55c876, 0xe3f475d0, 0x5e33da9a, 0xf20dbfac, 0x8994a107, 0x22805802, 0x412758b0, 0xfb84e039, + 0xacaf12c7, 0x421a2798, 0xb72862a6, 0x7921f0f7, 0x72e94be5, 0xe446c4fa, 0x01ab6019, 0x6399f429, 0xec3084a1, + 0xe744ab9c, 0x7dcd4413, 0x4f004c49, 0x469565eb, 0x17e23cd2, 0xfb0aa0ab, 0xd3e43889, 0xc3986d37, 0xa37d909e, + 0x9048487a, 0x2fbeb3db, 0xe2824ff3, 0x64135a66, 0xd28d2e01, 0x4c344056, 0xc304505e, 0x8e751dd4, 0x079be19f, + 0xd2a81d46, 0x5e62868b, 0xf9a2b160, 0x821eed19, 0x87782fea, 0x3355341b, 0xfd2ad6eb, 0x428ddb5e, 0x1e273d30, + 0x0db76fc9, 0x875d12da, 0xe7c25449, 0x2d9c74d4, 0x084d7ed9, 0xf349e21a, 0x293cf19c, 0xd050e72a, 0x7ab06200, + 0x2ed0be75, 0x5362149b, 0x13f5e24c, 0x17b7e35d, 0x284968bc, 0x70c8f6c6, 0xf05905b8, 0x79414000, 0x7ece6396, + 0x47376ef6, 0x49f08bc3, 0x1ef545e4, 0x7b6efce9, 0x87e94f7d, 0xb61e63d6, 0xfb14cef0, 0xd1e63ddb, 0xddb4550c, + 0xaaa5f3c6, 0x8afe8221, 0x02a200e3, 0xf31afeca, 0x06874dc5, 0x8c7139c1, 0x72ddc412, 0x6a33bbca, 0xa9891476, + 0xf7ffaf0f, 0xa89f9550, 0x8438f4a7, 0xf986b227, 0x004c9b3b, 0x0d53d818, 0x3bb592ca, 0x50a783cf, 0x1c5ee802, + 0xbe5ec883, 0x88c7adf4, 0xc01212ab, 0xe078563f, 0x6f7675b2, 0x2df9a7a7, 0x7b84efa7, 0xb9ff2afc, 0x43c0c1d3, + 0x1b04bac9, 0x8ede65b0, 0xa293b899, 0x9277ccdc, 0x9a03e7ab, 0xc077cd53, 0xf88b29fb, 0x447cc8f7, 0xc00de9ce, + 0xcbfd0360, 0xa95ac0b7, 0xcb2c4218, 0xe1b2d997, 0x3fc9cd0a, 0x96524666, 0x5b69a273, 0x22bd96d4, 0x084a1bc5, + 0x7a17ca11, 0xbba310b9, 0xb13d96f3, 0xf098f7fd, 0xfb9f3e7f, 0xd8eb3b89, 0x15b8c7a2, 0x5baab715, 0xe91a39e5, + 0x2480bcc3, 0x5ffa8afd, 0x14e7d195, 0xb19b5609, 0x37761565, 0xe50c7864, 0x93d20508, 0xfbcba735, 0x2a0af052, + 0x96713bb6, 0xf648110a, 0x67881df6, 0xa4f9f187, 0x13f859ab, 0x44ad2182, 0xa19bbda2, 0x8ca5fd52, 0xa7f43dae, + 0x881c4aeb, 0xe1dc9b1b, 0xf14e3f9c, 0x08d8c962, 0xdbc4b129, 0x8289b9db, 0x4f6092ca, 0x9019a79d, 0x68652f32, + 0x797f7ea6, 0xc8051bbc, 0xe3ad4404, 0x4daf7fc3, 0x4b893b8b, 0x566cd1b3, 0x6b631e37, 0x868cd13d, 0x3d0d23c5, + 0x96d38a49, 0x58a02e39, 0x431f47d5, 0x8ad1b3c5, 0x116a486e, 0xdb9e5159, 0x7291e622, 0x017652cf, 0x16b54f61, + 0xaa891a97, 0x27b2ed0a, 0xedc132a3, 0x95362390, 0x399257ec, 0x2c72ba8a, 0xf291e045, 0x50beba1d, 0xd8a18a2b, + 0xffa4837c, 0x20f12c91, 0x2a79bb55, 0xf6c49b09, 0x60c58437, 0xd161ffe3, 0x09a731c0, 0x79a553d3, 0x41c09b6c, + 0x54e91bf2, 0xb7151d06, 0x71e4e7fd, 0xe44cf492, 0x69af12ac, 0xe7961ffe, 0xa82023b8, 0xa38efbc8, 0xf0441e12, + 0x8d345497, 0xc0bb2b0c, 0x5b5df449, 0xbc14b9dd, 0x7bd1480b, 0xe21a09ba, 0xeb9926d7, 0x58a12707, 0xa6d981dd, + 0x818ac676, 0x42add75d, 0x59b35b92, 0x52407c23, 0x9bf3bf38, 0x95049ebc, 0xdbcfa2b1, 0x3edfec29, 0xae989657, + 0xc414911e, 0x95e11ca4, 0xd6dc8a12, 0xc494dc90, 0x32c44f57, 0x5d13f9a5, 0xa36586ad, 0xb7e9ea92, 0xc2eab4b1, + 0x0ab88f78, 0x632772cb, 0x5790a10f, 0xcb443edf, 0xbefd73d8, 0xdbc42b84, 0xb4057e1a, 0xe5e65f74, 0x714b4e95, + 0xb8cb3225, 0xe92859cc, 0xff381ec9, 0x6accc0dc, 0xf3dc6f10, 0xc7ce40ec, 0x95a494e1, 0x8aeda24b, 0x819e67a8, + 0x3c051218, 0xb1be092a, 0xf20ac7df, 0xa6b9a057, 0xfc87e4e1, 0xa84c8b57, 0x533cadf2, 0x9ebb2eba, 0x163c383a, + 0x236391a9, 0xdd87ecb1, 0xfdd729a3, 0x1ee0bf4d, 0x795fdf6d, 0xb252bbec, 0x92fedde1, 0xa6fd1f39, 0x49ae869f, + 0xa468be2a, 0x6b70138d, 0x680628b3, 0x90e251fb, 0x6dc119ef, 0xb5eaceac, 0x8bdba532, 0xdd06e86a, 0x60543794, + 0xa5d8d956, 0x6b107e4f, 0x558614d6, 0xaec6eee5, 0x3e756306, 0xebc457ca, 0x2e8b5314, 0x8322c69e, 0xfdef844a, + 0x7f9530ee, 0x34ec4bad, 0x487bcc4f, 0x0d4ce3f2, 0x38ed178e, 0xe70c4457, 0xfcf80210, 0xd39edde9, 0x3c0f75fd, + 0x2a6e9246, 0x86be2504, 0x885046c0, 0xc4dc0215, 0xc32fb2de, 0x77893989, 0xe6f2dfed, 0x305d3923, 0x7239a7a8, + 0xac963c9d, 0xf513bc4a, 0xe50534aa, 0x3c5ebf29, 0x05f968b0, 0xa3526c21, 0x0d501e50, 0xa0d577f4, 0x233ac555, + 0x661036cc, 0x4fa2dcdc, 0xb5794270, 0x8da8c15b, 0x51e4f8ee, 0x27d96b8e, 0xd0a4ebc7, 0x970523b5, 0xfdc42203, + 0xf593c750, 0x89b9e596, 0x3b0aaa8a, 0x5be152a9, 0xc04d37ad, 0x320736d2, 0x7bcc0b12, 0xc202e019, 0xbb54065a, + 0xc8f55247, 0x3b9aca2a, 0xcd8af569, 0xab74cfc3, 0x59ea5089, 0xfe9d9870, 0xdfc225fa, 0x93766215, 0x74098325, + 0xf53477fb, 0x29c37697, 0xc23fd75f, 0x5643b27c, 0xbc8b7c41, 0xca7c5c2f, 0x08f470a5, 0xcb8e0ffc, 0xbf857378, + 0x5920b86e, 0x15e7cbc2, 0xb8afeeda, 0xeb4a33d6, 0xf13b6198, 0xa9250224, 0x188c9ee3, 0x98f0e45b, 0x5eed9945, + 0x45d4e1e7, 0x64bfa172, 0x5b51c674, 0x9f53d063, 0xdba4dbe0, 0x087a7a65, 0xfefb1d19, 0x1aff87da, 0xae7f2231, + 0x3b43f95e, 0xd09a6a78, 0x2c33070a, 0x9657112b, 0xc1b0a26c, 0xb3c2892c, 0x08c02d60, 0xdb2e7107, 0xc22e0631, + 0xb0b70b28, 0x1959e047, 0x16d0d379, 0x242e765a, 0x79f5f3fb, 0xfc6d3cd5, 0x05f21d0d, 0x3ad68701, 0x2154ffa9, + 0x4d58fb01, 0xf2f5cd0e, 0x875e25d8, 0x7514bc21, 0xef8c07d1, 0x4c526daf, 0x716c28a9, 0x98c52fd5, 0x6229b750, + 0xa2589e47, 0xc01eb3fa, 0xf5961a0e, 0xe40a2ad1, 0x799fecac, 0x7a93a5b7, 0xac7edd22, 0x55112606, 0xcae49205, + 0x9cd4163c, 0x78d9a0e3, 0xa195e0bf, 0xef9b1921, 0x0df3e55f, 0x856bfb83, 0x6beb6e53, 0x0b8bcd07, 0x3b27c857, + 0x92e853e1, 0xbfc889c2, 0x83119c32, 0xb8c2b470, 0xe82c1537, 0x7b93175f, 0xadd9e7a5, 0x17b282ec, 0xd02222b9, + 0x30b4e749, 0x728c3ff5, 0x2530953e, 0x2746d6e4, 0x33a8fe31, 0xd999698d, 0x33b9b9c5, 0x4c23813c, 0x0d9d0cb6, + 0xbf1e0e94, 0xf1b2548d, 0xc7c14f77, 0xb57449ee, 0x7f28d4fd, 0x3d7b43c3, 0x9fcae341, 0x46242b75, 0x2e91b2a4, + 0xf3f76a42, 0xe7b65600, 0x914701de, 0x9e29cc41, 0xaaaac541, 0x73e42511, 0xfd7248e7, 0xaf8fc553, 0x547c0058, + 0x7ec1d4e3, 0x84afa5a4, 0x27f8e46e, 0xcde983e9, 0xee0a4fbf, 0x035b7f76, 0xcfbdcb04, 0xb40d47ba, 0x79ed07b0, + 0x5965c580, 0xaf08e747, 0xf27d3081, 0x73ef5b83, 0x7b706c68, 0x4c80abf6, 0xe1458ffa, 0x9662c965, 0x60ab33d2, + 0xc86f10fb, 0x002b771d, 0xb609a8ec, 0x8784b5c9, 0xfb4429a1, 0x899cf77c, 0xfaceb15e, 0xbd51b176, 0xec460a8b, + 0xc0afe15d, 0x1efb6ed1, 0xe250fc55, 0x28fb0969, 0xa8cb44ba, 0xdb0becb2, 0x769e4e59, 0x99ed7c3a, 0xae5cfc83, + 0x2d8334ad, 0x29f033f8, 0xf35fae9f, 0xae06c350, 0xa795b124, 0xb830ac41, 0xffea19fd, 0x262bb739, 0x88af4d10, + 0xe8a7b7bc, 0x860a9ade, 0xa7750dc6, 0xc5e5047f, 0x23d210b9, 0x5456e835, 0x8333734f, 0x5d9bd129, 0x767e0f70, + 0x2c71cc3a, 0x050966f1, 0xa574e77a, 0x1ea3b2f4, 0x25a3c237, 0xab86c8bb, 0x1d32e4b3, 0x887ec1f0, 0xc138eb96, + 0xfc78e77f, 0xa089f8c5, 0xecc8ec52, 0x4226a97a, 0xa5497605, 0x88751ae7, 0x084a6591, 0x6cf2d11c, 0xf906c8a8, + 0x0ab6bcdb, 0xd4fcee91, 0x4394eda1, 0x53591393, 0xfea17f6b, 0xea2017d2, 0x0b1d00fd, 0x8babf8fe, 0x8d29836f, + 0xcee1de08, 0x250b390c, 0xfcd85693, 0xcc164ede, 0x37706988, 0x54965e89, 0x47ce0ac7, 0x24030a0e, 0x2f3aad6a, + 0xfd7c1048, 0x4351ec81, 0x0c47bd61, 0x1ad8f210, 0xea5c2d1c, 0x241bdedf, 0x7c904ab1, 0xee40e2f3, 0x18ed42d2, + 0x04abf21b, 0xecff3857, 0x6c84b1e5, 0xe9054860, 0x928bdcff, 0x1f0e6f95, 0x814048e3, 0xb4026a9d, 0xdd459f5c, + 0xdcb2d241, 0x5aac60a3, 0x4e5d2abc, 0x9082e2ad, 0xd78a9cba, 0x9fb04d2e, 0xe3664780, 0xa9e784c4, 0x39ff93b3, + 0x6e29b1b0, 0x2b75b99a, 0x01163804, 0x6520e778, 0x7d3a0b44, 0x319e8335, 0xcb21d41c, 0xbdb47274, 0x18150ac3, + 0xec19f19c, 0xd0495a0a, 0xb7bf852b, 0xcd9e5b42, 0x46f326cc, 0xc51365d7, 0x27be3dd3, 0x30d5fd03, 0xab0158d0, + 0x9e40f080, 0xda1bf8a7, 0x03a304d5, 0x3f85c55d, 0x270d49d0, 0x41a6c53a, 0x786b548d, 0xb98f5d43, 0xc032499a, + 0x0cca1036, 0x57aedf07, 0x5def41d6, 0xd488450d, 0x3b3aa86d, 0xd2c465df, 0xeb274574, 0xd3024b9d, 0xb264aa37, + 0x451837d5, 0xd3391106, 0x7d620f06, 0x1546b767, 0x7a932b3b, 0xff14292b, 0xd75e62ec, 0x9cd293ba, 0xfab8391b, + 0xe14a7415, 0x2010262a, 0xa028728b, 0x89803dc3, 0x863a2627, 0x8960cfc4, 0x27709a4b, 0x9ecbd570, 0xee3de712, + 0x3eade9d7, 0x52cdbd30, 0x688af7d5, 0xc01c71d3, 0x5aa613b2, 0x9e76b2f7, 0x093f5ac2, 0x8646396f, 0xab01e729, + 0x280f6082, 0xd3ecd000, 0x6db4e937, 0x5c7c8bbb, 0xf0e54335, 0x5b800f85, 0x506c4f13, 0x70d455aa, 0x4c21fc66, + 0x92e3af13, 0xd874e295, 0x532b37fd, 0x64a07c7e, 0x1fc0ab26, 0x10b34c88, 0xd7018757, 0xf0b13242, 0x3f2adc29, + 0x3c678b19, 0x6ce5f136, 0x92c7d7e7, 0xcbad5920, 0x31d09c7a, 0x107a4940, 0xa914ed6b, 0x6c3e1a5e, 0xf0cd3700, + 0xaa2b8b7f, 0x329ffa7f, 0x126f5aa7, 0x6eab849a, 0xe6717154, 0x3dfda062, 0x5feebf66, 0x1b295198, 0xc382b5bf, + 0x899bc5a1, 0xb8aee1fa, 0x8ae50720, 0x015836ac, 0x7cdc6994, 0x3e2bcb04, 0xa4938ae1, 0x1a7a0f9f, 0xb7d99a79, + 0x40cb9156, 0x364161cf, 0xbba7418d, 0x4972d88c, 0x551c67a6, 0x49c3c22f, 0x98d6f700, 0xa3027d01, 0xeb8d0d6d, + 0xdfda953e, 0x8275b9dd, 0x1c590e65, 0xe991a1aa, 0x6091aada, 0xcda3f712, 0x2f4d3e53, 0x776aeb81, 0x2b0aea6a, + 0xdd030ee8, 0xe09ccd94, 0x0dc70109, 0xba305439, 0xba7029d1, 0x896d2b4e, 0x1991a869, 0x6ee7424f, 0xcc821bdb, + 0x79b66091, 0xf5ec33ab, 0x9a02c996, 0x07675385, 0xa164e87e, 0x8e19e005, 0x402c48bc, 0x8d88bab7, 0x16a1fcbe, + 0xeaac2055, 0xa9b3eca6, 0x1929c730, 0x3b2b7824, 0x0fa3eba6, 0xf7cb090e, 0x1906a8e4, 0x84d59549, 0x68424ea3, + 0xa11b6a8f, 0xb6c3ae4d, 0x817367c8, 0xfe7e9116, 0x9043306f, 0x32ac28b2, 0x2c6f8832, 0xc269c72e, 0x14c8a0f7, + 0xd5ad8675, 0xfcfa134f, 0x7f138c95, 0x04612d33, 0x961fd11e, 0xc487b003, 0x05d836e1, 0x79b06f77, 0x71efd00f, + 0x61a66cdd, 0x7ef59c29, 0xb63f3a45, 0xd31f8f76, 0x9d605944, 0x3aebe13d, 0xb6508de5, 0xe9f5024a, 0x1fcfb6e8, + 0xa8ecea21, 0xc3d06e4e, 0x0c6f5a7d, 0x2c921885, 0x05fca8d9, 0x2c4884ed, 0xaf91583d, 0xabf89a33, 0x62760f00, + 0xad561b61, 0xddf902f4, 0x0b222bad, 0xf2bcde38, 0x92ffab55, 0x61bbd4e9, 0x0ed3b20f, 0xd54aad76, 0x07838699, + 0x81de5ccd, 0x990dffd5, 0xad16b168, 0x7a813fe3, 0x620f79fc, 0x8dc1fa3f, 0xb8863b38, 0xa4a98992, 0xd76fc9cf, + 0x378d84a6, 0x2a336d87, 0xa6e6f42f, 0x9026e644, 0x320a86d5, 0x5fba43e5, 0x09d0a7f0, 0x9a1faf27, 0x3fd580cf, + 0x7280476f, 0x700373b1, 0xe2bfc55f, 0x0cccc4be, 0xd8504e35, 0xe32fb9c2, 0x5e1e3e88, 0x414b9da7, 0x745750d5, + 0x8635bf83, 0xf3ffd722, 0x51b17080, 0x9ad7ba0d, 0xf2ff2382, 0x9d0224a3, 0x285b12be, 0x8a83b2b5, 0x6c058d58, + 0x57a83ebf, 0x81c88038, 0xb527ac1f, 0xf6260312, 0xc68214d1, 0xfa94c6c4, 0x52c94242, 0xe53b4ce0, 0x07defb59, + 0xfbb11f48, 0xf527a3a6, 0x8a7d851d, 0x15ff0e2f, 0xbd8f334e, 0xa906fe2a, 0x08ca0a4c, 0x5174d629, 0xf73f7572, + 0x99135e34, 0x647513c9, 0x198195d1, 0x7d52bb6b, 0xd0e64855, 0xd54eb98c, 0xa693a501, 0x2b3bf177, 0x2a1ea256, + 0xe0d52224, 0xb9de1d4d, 0x55f20f23, 0xd2ecc4f2, 0x2037d254, 0x53266cd4, 0xc198e67f, 0xaa8115ac, 0x1d6a1d4a, + 0xfe2c7138, 0x86eeed32, 0xddde6f8c, 0xfbd04f43, 0xe4228b49, 0xd4f53f14, 0x3a286ed5, 0x314c956b, 0x69ca0b60, + 0x7a381b5c, 0x536228e7, 0xd370904e, 0x728e3f34, 0x830e3cc3, 0x634f4f4b, 0xce73d8f2, 0x367b706f, 0xdd106acb, + 0x66f1f728, 0xe6cc655e, 0x06763640, 0x44cf2455, 0x8e40046e, 0xa5212f00, 0x59b0d691, 0xb4ea32ba, 0x205b366c, + 0x5fa1c576, 0x4f0eb5c4, 0x6071c604, 0xdd356822, 0x93dafef7, 0x32d9c4dc, 0xaa8052ab, 0xa6321cfd, 0xb19f0048, + 0x2952ecc7, 0x60e7d095, 0xc52fa4c9, 0x7ea742b2, 0x011d8425, 0xf5ce10a4, 0xc21b21c4, 0x8b3ac6e0, 0x517013d1, + 0x161767a6, 0x7f4319c8, 0xb7bb5921, 0x22ec3a54, 0x5030626e, 0xc9a98dd0, 0xea82d566, 0xe84adb0c, 0x5403fa28, + 0x90b32b0c, 0xfc3d1677, 0xc12c5677, 0x145f24fd, 0x3101ed2f, 0xf0227bc9, 0xcbccdf83, 0xefd99325, 0x0835b3e5, + 0x8f6309cc, 0xe5abe511, 0x731db81b, 0x722a3aa5, 0x0a88c2e6, 0x34667e26, 0xb67cd7ce, 0xe8263d97, 0xf603c672, + 0x8c4ecaf1, 0x7fbea219, 0x595458af, 0x5505f358, 0xdd827922, 0xaf84f714, 0xb1d8d2a5, 0xf37c3687, 0x6b66d362, + 0x81375d96, 0x62e9faf0, 0x4914294d, 0x5f3baea3, 0x9a2100ec, 0xeb8af665, 0x79a89f9c, 0xbab53b63, 0x72ba68ff, + 0x8dcbdf7a, 0x7f0a9e66, 0xe0d41041, 0x893b738a, 0x4b429d9a, 0xa2cc0da5, 0x50f4844f, 0x31175c14, 0xdeb63990, + 0x99122dd4, 0xb3e39361, 0x0608f572, 0xed5535ac, 0x8939d7c8, 0xcb0f5719, 0x1f41e329, 0xb54ddf7c, 0x7ff399de, + 0xda5719f8, 0x64d5363b, 0xdbc79195, 0x9634188e, 0xb6f39148, 0xf8399017, 0x24ec1df5, 0xd37dd0d2, 0x63e9f35f, + 0xe92a2652, 0x19dcbcb9, 0x78414a4e, 0x0a336bda, 0x737008d6, 0xee741c69, 0x2bd88755, 0x054b656d, 0x929a175e, + 0x24594c42, 0xdd5e6d09, 0xc714b622, 0xccfc8e10, 0xd7613313, 0xc8d91cb1, 0x8557cbd2, 0x54fa14e0, 0x68611e7e, + 0x8f66b289, 0x3a2b30d0, 0xa8e5929f, 0x80360a2d, 0x46bc8da0, 0xa2f8344e, 0x14334a5a, 0xc081c3f9, 0x4974fd85, + 0x306dab02, 0xe03f8ed8, 0xbad2c2a2, 0x22ace9f4, 0xd2599e64, 0xf0f11aa6, 0xbed3dbbd, 0xbb43e346, 0x92ad4b3f, + 0xb61656d0, 0x0e8700ed, 0x7279139f, 0xa995105e, 0x4cb05cc0, 0x2e0defa2, 0x658ab784, 0xe9e5f265, 0xdbd69fcb, + 0xba61b0d3, 0xe1a657fc, 0x92d38918, 0x9d62f614, 0xb4a8cb3b, 0x96b5a284, 0x07003d26, 0x8abcc8d9, 0xbdf79bf0, + 0xd3ef7923, 0x1fa839d2, 0x2a850130, 0x7124b535, 0x1cd6e8dd, 0x4d8d42a5, 0x4a03ac29, 0x47b4aff4, 0x4e1e83fb, + 0xd83de51e, 0x20006519, 0xc300a3c0, 0x9568bdcd, 0x3088b825, 0x6166ca4b, 0x83da85b5, 0x36886b60, 0xc703974c, + 0x8ec6bd33, 0xc61da082, 0xce5be05a, 0x1941e791, 0x1cb01170, 0xe7fd2742, 0x126f57a6, 0xb4f10c46, 0x68df6ec9, + 0x45d715ff, 0xa964c217, 0xfc59c052, 0xb75bb3ba, 0xe6f699fb, 0x8b12a8b2, 0xff047a58, 0x23d1fb55, 0xf49ebb8c, + 0x4cc6d251, 0xf2c5537b, 0x9f18a1f5, 0x1aeb0ccd, 0x737dbc25, 0xd3988fdb, 0xb28f4449, 0xd337e625, 0xf9b09f6a, + 0x5f74be12, 0x04b9c084, 0xd1e65545, 0xe910d0ab, 0x21e05e7e, 0x555410d9, 0xd435897b, 0x662135e3, 0x7ee8df25, + 0xaec12aae, 0x7bda2c35, 0x6990e198, 0xcaa9805d, 0xcd08d4ee, 0x34a8ad00, 0x90c24c43, 0x44e13894, 0xa2c3db9f, + 0x909e5b19, 0xf8317a8a, 0xf15e5695, 0x637107a5, 0xb213cd48, 0xa00eb9aa, 0xe55d7352, 0x3a10e9a2, 0x9b9e4128, + 0x3e8c1e44, 0x5fb701bc, 0x8942bacf, 0x77157cfc, 0x52f637c8, 0xae6a4233, 0xbdb0f7d4, 0x2a3260cf, 0xf1b4f67a, + 0xfd8b5692, 0xb4a86a99, 0x89cfee0a, 0x3352e6ff, 0x4ea66eea, 0x56e4a3b5, 0xf9107142, 0x7ab81ccb, 0x785b8fe8, + 0x2e51786c, 0x697d2f87, 0xdd62d164, 0x2c7df643, 0x3482e015, 0x9ff5fe53, 0x200a23b9, 0x4aba60fb, 0x3306197c, + 0x2d3f2d79, 0x80ae5a0a, 0x9077ca3d, 0xb758e4b8, 0x00bc2ad3, 0x2808a44d, 0xa553d2a8, 0x7c051d8e, 0x979c6278, + 0xfabdd49a, 0x5a85766a, 0xfe806b01, 0xe0996c3b, 0x26ba82a5, 0x6200b272, 0xc89362df, 0x3ba4a70a, 0xeab50acb, + 0x36e8a68c, 0xd28799bf, 0x5321effb, 0x4762b814, 0x111f9aaa, 0xbf7119c7, 0x01f13f5a, 0xa312d514, 0x7aa77e99, + 0x135379c4, 0xf7daaeab, 0xda251e6b, 0xd40e1b9b, 0xee055eb9, 0xaad3525d, 0x3d7275bb, 0xf222fc66, 0xec434fa8, + 0x20e28c69, 0x8aa5d50a, 0x0f067d03, 0xd3e4201f, 0x410c8197, 0x4fada27f, 0xacfb00cf, 0x57fa73dc, 0xbca46590, + 0x8ad39f10, 0x78a0d6ac, 0xec05267e, 0x71a722cc, 0x7c0c20f7, 0x073b93ff, 0x1d5edcbf, 0x546e8d7a, 0x2d2783d0, + 0x1ac0af25, 0x716c5736, 0xa3b874cd, 0x9e5af894, 0xe8865374, 0x3bfe190d, 0x1b87f42c, 0xbe8c14e3, 0xea83dfb8, + 0xf0a3e0aa, 0x163f2aff, 0xd0997f32, 0x0a8adfd6, 0xae8b5038, 0x30eb6b33, 0x8cb281a6, 0xda7eb0e4, 0x1bed9aa6, + 0x68b96e2a, 0x2b52a10c, 0xee3e0aff, 0x84fe5050, 0xf8e3bd7b, 0xb5c0bec2, 0xaca2ba9f, 0xc9ae620f, 0xdb06596b, + 0x73dac686, 0xf9211f7e, 0xafe99f95, 0xba7b4b6e, 0x51f03347, 0xf4b78ddd, 0x055af667, 0x4c1102cc, 0xc80da48b, + 0x3a2772da, 0x9f5f02ab, 0xc4512777, 0xf14a04c7, 0x6cd25823, 0xf0fc519a, 0xfea785c7, 0x272d7000, 0xc0b26f11, + 0xe943ed24, 0x523a6f11, 0x6360f9f9, 0x924e7703, 0xdd629f68, 0xdf80f08a, 0x0f9369ec, 0x95284c2c, 0xd8875143, + 0xdef0abb5, 0xb9b09ba5, 0x038d601a, 0xaf604e94, 0x93c590b8, 0x924fda98, 0xbe125636, 0x019b2267, 0xb4180f03, + 0xcec3cb3c, 0x3eef55e5, 0x6961fba4, 0x36ee22eb, 0xb47de7f7, 0x10014a24, 0xe08ccb01, 0x41a48ba1, 0xb34f0221, + 0x45d00bde, 0xd87089fd, 0x5d73f7f3, 0x95ad3d1e, 0x6f3cef4d, 0x66a53d08, 0x2d6dec50, 0xa3e4eb80, 0x7fb0036f, + 0x21fb9a4c, 0xae4c9929, 0x00199225, 0x1951e214, 0x53c10790, 0x971b4786, 0x53f88b64, 0xea070326, 0x7a7b92de, + 0x80f80a34, 0x3547e776, 0xfacd4a5b, 0xd81f1470, 0x2312b7c7, 0x0a84a492, 0xc574c7b2, 0x5fa482c0, 0x388bd7b7, + 0x64876be3, 0x21ae25c3, 0x96ea751a, 0x8124b891, 0x0841c4c3, 0xdc1cdf83, 0x550a8f04, 0x3e45f646, 0x1ebf048d, + 0xe1bd461a, 0x559323c0, 0xb5e9d41b, 0xee7a15b8, 0x3e5fa5ec, 0xded4c4a7, 0xbe8c9d73, 0x4eab34de, 0x85e29832, + 0xd70df632, 0xfbae6eee, 0xa0c50571, 0xbd15d9d3, 0x4b674ffd, 0x6bf6f411, 0x40d0e1c9, 0xafd6bf34, 0xd6814e87, + 0x84532ce3, 0x84ab1d19, 0xf6648cd9, 0xd557f8b3, 0x8df2aa4c, 0x3a68570c, 0x925dab9c, 0x6780b6fb, 0x840e0f75, + 0x73787a77, 0x0da48928, 0x213262f1, 0xe7128b02, 0x71485d1e, 0x3f6f84b1, 0x1354747c, 0x541390df, 0x9b166cfd, + 0xf96ebc42, 0x7e281c78, 0x3f70c81d, 0x8c84ed63, 0x75bbaab7, 0x93a2d2b7, 0x951d3e46, 0x1f9c5890, 0x6bdb29db, + 0xb432a597, 0x06f6e9f9, 0xe9f7018b, 0x94350a1c, 0x137ecca4, 0xb0945468, 0x46ee2091, 0x3b5247b9, 0x88e58e06, + 0xec8e719c, 0xc912082d, 0x5b07caff, 0x69b02f10, 0x48383aff, 0xbfbae45a, 0x64dc4ef6, 0x50775bae, 0x90a4523f, + 0xe7c253bb, 0x27799246, 0x07cf4b24, 0x04180c1f, 0xd997d6ac, 0x12218339, 0x37cb3131, 0x88f37858, 0x7b53c0bb, + 0xdabed17c, 0xec5e1bd7, 0x055b3338, 0xce9635c7, 0xf45aa4c4, 0x18deb93a, 0x152d5416, 0xe84a152a, 0x5129eaba, + 0xcd2ec847, 0xf68d51be, 0xd1bf4069, 0x3dba820c, 0x62436f43, 0xecd9b99f, 0x1c8c7a92, 0xe2bdd114, 0xfaf38a80, + 0xdef7b7ea, 0x9a8398d0, 0x4971e0ce, 0x045c20a7, 0xddf759dc, 0x005c213e, 0x6a18fe90, 0x999f4a33, 0x3be4e5ab, + 0x1cf4945f, 0x2038c444, 0x630f6b29, 0xa5806bc1, 0x6b3dbd7b, 0x479e9286, 0x82da6136, 0x6ab95ad5, 0xc6f9db72, + 0x0c00ad61, 0xb2775076, 0xa610ebe2, 0x87f70596, 0xdd67302b, 0xacc1cfe9, 0x3162036c, 0x095caff5, 0xdc7116cc, + 0xaae587c0, 0xaeefdc4a, 0xdb88155a, 0xf3d5af59, 0xc489635a, 0xdc8a457c, 0xfac84424, 0x3ebf396b, 0xa88a1ded, + 0x846e6e73, 0x4f67d5ff, 0x6cfc1a98, 0xf8339e01, 0x35704899, 0x931320bf, 0xc3ce8a52, 0x48cad6e3, 0x9c947634, + 0x1df49614, 0xfab641b7, 0x037b1e33, 0x33750e34, 0x0be72989, 0x615a7789, 0x5e269a63, 0x54d3a9ad, 0x49515beb, + 0x17976d41, 0x9c28b5c2, 0x8058edb7, 0x88536c30, 0x76add520, 0xca415f59, 0x7877a4a6, 0x61833736, 0x982818e5, + 0xa2b34e6c, 0xf224acb2, 0xccaeda44, 0x5f09f137, 0xcfa62abb, 0x2e7a82a4, 0x7609f3b2, 0x4193cb57, 0xbcf0549c, + 0x543988ac, 0xf0be469e, 0x3ce194b4, 0x676217d6, 0xfb66f2f4, 0xa8d75dd1, 0xcdc4e223, 0x92bf2a9f, 0x543d61ba, + 0x10e47ce5, 0x755203ce, 0x07fefd5e, 0x7bc28210, 0x9f1e0ceb, 0xde27a4eb, 0xf0b83b91, 0x94d2d5a1, 0x3c8ace8e, + 0xc4f8e903, 0x6e724c45, 0xe6eb8126, 0xd91c3bc4, 0x89e01a8e, 0xd455c207, 0x9b663ce0, 0x5a8fbcfc, 0x9b475412, + 0x3f30ad0d, 0xb522cd29, 0x20b74add, 0xe5ba5937, 0x8373a7d1, 0xe5442c42, 0x9a349aa0, 0x366bdead, 0x91a8e737, + 0x6d7b3204, 0x8e655d58, 0x10813c37, 0x05607cd8, 0x7c3978d8, 0x8d47a3ec, 0x3ea88715, 0xf5daafd4, 0xffb26fb1, + 0x90fd45ba, 0xd6992549, 0x0817b3a2, 0x66f00ef1, 0x931c63bd, 0x533af123, 0xd1d4b20d, 0x9774574c, 0x2e21088d, + 0xe9d48a8a, 0x59eda837, 0xe79d6fc7, 0xc6a4483d, 0xc3a08b8e, 0x67e2cb45, 0x911645c2, 0x9c702a0d, 0xe0a4641e, + 0xb27411fd, 0x24338ac6, 0xd879a2eb, 0xb11072d9, 0xb578aef2, 0x9f5ee805, 0x99aacb8f, 0xdbc61e03, 0x07b83fe7, + 0xe1cef14e, 0x42f00354, 0x4920d488, 0x12d34500, 0x2d1b42b1, 0x7e0d50c1, 0x5b9b8e96, 0xea9ffb78, 0x1255458c, + 0xff6a65d0, 0x6207d1ca, 0x5d29bc21, 0xebad8e7a, 0xd0153795, 0xfed34f42, 0x03e9fce4, 0xb7db8220, 0x63a53354, + 0xa3b60907, 0xa46b3219, 0x49fd7a1d, 0xd1e0ca72, 0xee1d65d1, 0xeca5e6ab, 0x39ea3ab5, 0x04b14cbc, 0x0af55856, + 0xd74d4d51, 0x293a76c3, 0x559a3f36, 0x377fc055, 0x8765362b, 0x80cffae6, 0x08f8c0b0, 0x27890203, 0x86659612, + 0xc09c6b2c, 0xe204a843, 0xd9ff29c4, 0xab4fdac8, 0xd6526bc5, 0xb6d56f53, 0xc031f738, 0x5edfc856, 0xc53abf77, + 0xee7c3271, 0xaf5e63f3, 0x4214af83, 0xc40a5a47, 0xcfec276c, 0x6c9b9df6, 0x8cae69fb, 0x0db98654, 0xc5788b96, + 0x39c3e247, 0x3166f13b, 0x7ffb8e4f, 0xc91e862a, 0xfc5c9c89, 0xdda0323a, 0x0a3a5949, 0x6aa48144, 0xf3285137, + 0x146b99db, 0x4b9d4a0a, 0xb640ef65, 0x0648b700, 0x64abbed0, 0xa463ff4e, 0x51f83796, 0xb59d3151, 0xbfbc0877, + 0xc8b11b54, 0x09c1e437, 0x74ca3416, 0xc0bbe6e0, 0xd0ee0d9e, 0x56d7b86a, 0x97c3cfc8, 0xa42d0b0c, 0xfef99a06, + 0xaf0866fa, 0x38426b07, 0x0f1b45f6, 0xe7c9ee07, 0x7cfb3fa4, 0x6c380c99, 0x92c1144d, 0xa9454176, 0x5ec3bc77, + 0x6ca3ce3b, 0x6817458c, 0x30c23255, 0x74c88d38, 0x2726e93b, 0x06d536e1, 0xf76e8212, 0x80858549, 0xc4625fdf, + 0xa9977e54, 0xa0f5b72a, 0xa8de1357, 0xff6a9f7b, 0x943007a7, 0xaa20bbdf, 0x942bee5f, 0xd6ea730a, 0x9454457e, + 0xf50e1508, 0x235f4cb5, 0x56618875, 0xa55e9b1a, 0x607f07b6, 0x83ed3201, 0x9c6ee256, 0xc3ad242a, 0xefa6ee73, + 0x19c54d67, 0xbf907add, 0x90e1b16b, 0xc2042b23, 0x68bd2f2c, 0xe58be6d9, 0x946eb94f, 0xda09b32f, 0x7ccca307, + 0xccda7e09, 0x00e4af1e, 0x8f78408f, 0xa9ade7d2, 0xd6d7f3a9, 0x9713d168, 0x9467d2e3, 0x2c62906e, 0xe1da5fbc, + 0x51ee2d8d, 0xeec86e41, 0x341532d1, 0x97eb9b90, 0x27398972, 0x48587e5f, 0x01345cbd, 0xf73fbfee, 0xe212b57f, + 0x04952fb7, 0x1a771621, 0x906a964a, 0x00f9ebff, 0x22924323, 0xc9520666, 0x2ae9a4c4, 0x3b688b3e, 0x827c59ad, + 0xb7173808, 0x686ca029, 0x7c73a848, 0xcc1f3cc8, 0xfdad2a41, 0xe2fa477c, 0x5221b6c4, 0x001d2fb7, 0x98d3bc66, + 0x664162bc, 0x1b7428e9, 0x3d812425, 0x4fcb1b09, 0x28e06d97, 0xa922ae18, 0xb88fa71b, 0x291af9f7, 0xc42373bb, + 0x868e77be, 0x314190d7, 0x02f4b7fe, 0x416a247b, 0xeaa139f5, 0x21e6e41f, 0x936d0b4f, 0xb56e80fb, 0x39fee2f8, + 0x3bb0a5fd, 0xd0bef53a, 0x53b96801, 0x254c1402, 0xbd1ab1a5, 0x2f1082c4, 0x70faf185, 0x6d3c4cd1, 0x2a85f34e, + 0x9e2b37ee, 0xb8c396a0, 0x3747c33b, 0x2142ad25, 0x2d48f380, 0x2d329b6f, 0x78f23794, 0x57bc148a, 0x37cd631b, + 0x92b3ebe8, 0x48b1d94c, 0xd4a8e356, 0xa439f33a, 0xa3e04e66, 0xedd0fad2, 0xcec05b1d, 0x1a8ab96e, 0xb2fc7920, + 0x7ecbb472, 0x2d457393, 0x56752db5, 0x1cf880ba, 0x6bdd135a, 0x84a67896, 0x3e411a6a, 0xf5c309ff, 0xc9c8fdc2, + 0xca84c22a, 0xd31a1b27, 0xca1016f0, 0x03085741, 0xccb661e5, 0x6030114e, 0xe6609c52, 0xda21e3df, 0xae901a13, + 0xf8259702, 0x3b1b15f2, 0xba8e81f5, 0x3aeeb808, 0x822fc426, 0x72b7a479, 0x208e6479, 0x3f942b66, 0x652519ba, + 0x11651dff, 0xe18a6cfc, 0xbba8ab1f, 0x6badc5bf, 0x82ac8e9b, 0x365c4c9b, 0xadce6fae, 0x0934ce8a, 0x21b3002d, + 0x42efb117, 0xe9fece10, 0x0504564b, 0x65e5470c, 0x5d4cb669, 0x39fa6677, 0x336d820c, 0xe77af5bc, 0xbedfbad4, + 0x62e0e404, 0x3b407c82, 0xb85fda9b, 0x2dd64bfd, 0x47692f5d, 0x1b349b02, 0x04826f52, 0xe64813ea, 0xc7092179, + 0xb6fab2b2, 0x22c8ad2e, 0xde57050c, 0x097fc263, 0x0322d07d, 0x62d74d5d, 0xa8be5881, 0xed1eec2d, 0xfbfca9c8, + 0x0f7eccde, 0x306841a9, 0x8e96fb58, 0xa199a275, 0x810240d0, 0xa5b669b7, 0x8661063f, 0xeaef9f91, 0xd5d48131, + 0xe138b8cb, 0xbbc80817, 0x5dad437f, 0xc5045d6e, 0x2f3bbda4, 0xab7924c8, 0x06a29681, 0x1ebb37c6, 0x2aca0bed, + 0xf4e2458e, 0x6a494925, 0x9400c3d6, 0x60bfa322, 0x44214adf, 0x036b1df2, 0x0e0f7f0d, 0x7079f0dd, 0x71f3933f, + 0x7f8f194f, 0x23ca02b1, 0xcc5325d6, 0x55e3633d, 0x5dc5117a, 0x47fe179e, 0x90baee2c, 0xb285b34f, 0x36203f79, + 0x47bb5908, 0x2b461341, 0x98ab73cf, 0x0578cf47, 0x95ae8d39, 0x852968c3, 0xb1563b32, 0x80adfacc, 0x483cb583, + 0x4ccc27e4, 0xe065b6f6, 0x5c1ea2e8, 0xb93f6e38, 0x02caddc5, 0x531dda97, 0xd3577c02, 0x3663e677, 0xcad611e3, + 0xad6bbb2c, 0x574b6196, 0x235f2026, 0x5c0dd50c, 0x0af0e6de, 0x87d7afa3, 0x2b922697, 0x3fe94bba, 0xbb0d8701, + 0x88a772e8, 0x2679e3d5, 0x3cf64971, 0xdd2ff141, 0x0433b8cd, 0xa924b941, 0x5e3b1df9, 0x6828ac05, 0x10aa0349, + 0x155aedce, 0x1a1bd9a2, 0x3b5df225, 0x069c4642, 0x8bb1d7e7, 0xf4af3fcd, 0x0cdcf3fc, 0xa5a3f197, 0x27d5123e, + 0xec0fffa0, 0x42351d65, 0x2fcbafbc, 0xd23cc120, 0xa3b5d7e8, 0x9d427624, 0xdb23d795, 0xf8885a3f, 0xd661b1dc, + 0x9d635823, 0xcbbee7eb, 0x41426c88, 0x375775a6, 0xed52d7eb, 0x6bdcb904, 0x00de11cd, 0x1ecf4cfa, 0xbc398ecd, + 0x4174176c, 0x9af8fb5f, 0x32ea8841, 0x71063643, 0xf69921ad, 0x754493c5, 0xe92cca36, 0xb60ee215, 0xda67b45f, + 0x357facb5, 0x9cc026e7, 0xe5e67a21, 0x63179965, 0xcc088673, 0x3cda4573, 0x9eaf8250, 0xbafd1ad7, 0x36af0202, + 0xc4f5d08e, 0xa22bbc1d, 0x5a254992, 0xf62baa97, 0xe65d4495, 0xefc8b70f, 0x613a1619, 0x3a598a80, 0x954be055, + 0xd77f9bf3, 0x73d080d7, 0x3573bf36, 0x2cc8f6c9, 0x62310b9a, 0x1ceb2985, 0xf45fd106, 0x5603f35f, 0xbbf7aa89, + 0x4027d9b2, 0x3fa0e01d, 0x7b89e217, 0x949634e8, 0x00dd54e1, 0x0ba5431c, 0xd5425140, 0x4d5e83a7, 0x08a47bd3, + 0x6e08e4b8, 0xe19bb900, 0x90a96343, 0x376f1473, 0x3287bddd, 0x1c21a017, 0x23bc2182, 0x6ce40dc7, 0x7330e14b, + 0x699ad5f1, 0x34974cf4, 0xb708eb6f, 0x997583a7, 0x83094e66, 0x96ffe57a, 0xa4af88eb, 0x71c70a8c, 0x7211b76f, + 0x5c631efa, 0x7fdfb0a5, 0xe499dd16, 0x73866f9a, 0x80a660c8, 0xb905a76b, 0x99d90c54, 0x4ce423a7, 0x497ed1f4, + 0xe51d8ad6, 0x3cd3c9f6, 0x5bbbc869, 0x1c40b017, 0x8ba860ca, 0x3a402f12, 0x4f669284, 0xcf67890f, 0x2708f4d9, + 0x99c82ef3, 0x349a824c, 0x6b72611d, 0x3cda1cd7, 0x31ceaa6f, 0x6550c5ed, 0x8ec02699, 0x4086dd63, 0xbb079cf3, + 0x37fad793, 0x79495216, 0x154082ec, 0xc930922b, 0xea432068, 0x4fd09f9a, 0xd44328de, 0x8bdd5874, 0x3fc63046, + 0x6ab992db, 0x9165c000, 0x7f2f69fe, 0xe299ab06, 0x4707af7a, 0xe131b24d, 0x10cb5433, 0xc5ad339a, 0x80a7e5f0, + 0x47ff8aff, 0x8b653d86, 0x13640ea4, 0x6ca53a88, 0x7ea09566, 0x67544806, 0xef95739b, 0x42e1a66a, 0x0d076a4f, + 0xedcd8e10, 0x3dc98cc5, 0x069c572e, 0x1f9b0132, 0x17a007f2, 0xc5c41379, 0xde018357, 0xb779e05b, 0x06be7042, + 0x08b80b59, 0x2c36ae5d, 0x3f541eaa, 0xb06f8dfe, 0xa87aae20, 0x691c426f, 0x6bd066ed, 0x48ec0f06, 0xf1999558, + 0x16732d82, 0xf288d3cd, 0x56ace3a0, 0x103fc507, 0x9ecb5de9, 0x04781c59, 0xf8c522d9, 0xfb648c85, 0x3fd70772, + 0x377cde4c, 0x8400f247, 0xe4314ca5, 0x72cefe14, 0xbe595ed3, 0xcf8a9847, 0x7c886285, 0xb3c774dd, 0xc8ec722b, + 0xbcb6fcb6, 0x5d387d49, 0xdbf199fa, 0xc23615ba, 0x25149d5d, 0xec11f2fe, 0x668c5991, 0xcd9e34e4, 0x90949459, + 0xd88492f2, 0x1a805d87, 0x8552961a, 0xba50606f, 0xdfe909cd, 0xf0ded70d, 0x36f58c88, 0xdfcda956, 0x68a3dd5d, + 0xb5d2286e, 0x3c7ce6ff, 0x67ed87e0, 0x136e3000, 0xd0891c81, 0x4bb3f38b, 0x29ebf0b9, 0x74b67f79, 0x856984e7, + 0x919d5642, 0xb745612c, 0x0240f558, 0xb21d9be8, 0x144c4d69, 0x3cc22300, 0x1d11f9c7, 0x39f7d67d, 0x755c41a2, + 0xe396d881, 0x00833559, 0x07aca05b, 0x65e906cb, 0x8aac85af, 0xacd61694, 0x92eb0e9f, 0xc9e46a94, 0x8b1fe831, + 0x19dfa032, 0x0ef2cc48, 0x5e312aea, 0x5684cda3, 0x7eb9a45f, 0x4f387819, 0x2b8a1774, 0xf18b1020, 0x656ef617, + 0x583394f8, 0x60b12d19, 0x8f7da0a1, 0xe221b8ff, 0xd5ab6e3d, 0x0858a26b, 0x285ffafb, 0xbf4488e1, 0xfe928140, + 0x64b2b156, 0x23d728ec, 0x9cc00a0f, 0xd3f23749, 0x66e30ca4, 0x573a28a6, 0xebea8ebb, 0xf927f31e, 0xb632dca6, + 0xc58c2d13, 0xb973646e, 0xe1f5064c, 0xc12c6ce4, 0x15ff5735, 0xd6aa8e2d, 0x68e11dfa, 0x4a5e438b, 0xd11f45f9, + 0x9fb31687, 0x49a246ae, 0xadccbccb, 0x83e25441, 0xf7a3c755, 0x17c01ef3, 0x9b01d846, 0x7d523aa9, 0x8fa8a7dd, + 0x8bc20fd2, 0xabb57cbf, 0xb740f526, 0xbc87e7d9, 0x64ac1062, 0x41ddd73d, 0xc253632e, 0x07b4e306, 0xecf81fcb, + 0xe058eb69, 0x23d2771a, 0x7b749602, 0xf487ffc4, 0x79878ccc, 0xd912349e, 0xb7267226, 0xce6c2f01, 0x850c70e2, + 0x237f2d0f, 0xcaed1f1f, 0x04facd68, 0xf62b8151, 0x24882a83, 0xe81faac7, 0xabe8a6d0, 0x381b5c2f, 0x69bbb71e, + 0xeba7d75d, 0x2dee79d0, 0x78487c13, 0x3225fdd3, 0xd1eecc99, 0x1f55d8f5, 0x8ce63f38, 0x028de09a, 0xd2f00d50, + 0xc0fa00af, 0xdfa0bfc4, 0xc8269258, 0x73a78899, 0xc5323003, 0xe12a7cc3, 0x44e0a2cd, 0xcc89db0c, 0xdd865c9a, + 0xafbd903f, 0x137a5cde, 0x9ae49249, 0xd4fe737a, 0xa7dc3efc, 0x24d517e6, 0x013e924e, 0xd2210376, 0xb9503a26, + 0xd1c0d0cd, 0xe61bbcc4, 0x37e5059b, 0x9efa073e, 0xc4ced090, 0xe038daef, 0x1b1974d7, 0xea1b9532, 0xf822428e, + 0x41f67007, 0xe6ab4dba, 0x52ab314e, 0xd9fdd43a, 0x1432276d, 0xb4323562, 0xb56c214e, 0x2b1f3133, 0x55a94ac6, + 0xdd867acb, 0x2cc4a2a7, 0xea3d6a9e, 0x52d44e56, 0xbeef3f76, 0x5208b2d4, 0xe6d5ed0f, 0x0c82df29, 0x73edb033, + 0x996d7af7, 0x6050d9f2, 0xb7491122, 0x690e9044, 0x5cb50f49, 0xeeaeb21d, 0x92206e36, 0xb7a842a2, 0x4a718c9c, + 0xf7c2f2b8, 0x9475d0ac, 0x81cc24c8, 0xe8854538, 0x5f187fba, 0xc62672dc, 0x9835d66f, 0x1d0ac8f8, 0xc7458c9b, + 0x62d65828, 0xf336c3b3, 0x8d4fff4a, 0xc5c27a9d, 0x9ae76a6c, 0x29af6637, 0x82569021, 0x3057fdd5, 0x8bce2fed, + 0x56f4a475, 0x1c97d3c0, 0x6d56d2a0, 0xa2883e7d, 0xd26764e2, 0xeb2d3522, 0xb2a1baea, 0xb6ee7127, 0x4e615d51, + 0x12ebb12a, 0xfe18101e, 0xb583f6cc, 0x6a7a7e2f, 0xe4f80ce4, 0x66506670, 0xbe5e18da, 0x738b7d0c, 0xc06d4555, + 0xc15f87fc, 0x8ba3c3e3, 0xb3de722d, 0xbcea375f, 0xa17d12cc, 0x478a816f, 0x27d622a2, 0x5cf03901, 0xa3b513ea, + 0x0d1ab911, 0x33cb0cac, 0x8e62f5a4, 0x2c758310, 0x869943de, 0x7615b63c, 0xb6a23f7f, 0x58508c11, 0x058a00dd, + 0xb72fbf04, 0x80ecd42f, 0x198ea400, 0x4e78396b, 0xc7f54994, 0xe039da37, 0xaa0c6f82, 0x9b0b9d58, 0xb8387ef6, + 0x9e5efdf8, 0xa2715510, 0xd8ea47c4, 0x26727657, 0x497247fc, 0x4ce27497, 0x833e27a2, 0x98a2e3c3, 0x45773ca7, + 0xd58a0ae7, 0x99994686, 0xf87bec9e, 0xbef5735c, 0x6a439739, 0x0db926a2, 0x31d5af76, 0x120d7220, 0x50d242e3, + 0x5ee8f823, 0x25f7b8a6, 0xd883bc71, 0x047c9208, 0x4216e034, 0x9a89b0d7, 0x6bba5d9a, 0xe9feabd5, 0xb735c9e6, + 0xa91a6047, 0x0cbd71c5, 0x19df545d, 0xb52793e9, 0x7e56f0f9, 0xd9d5cd3f, 0x86aa8509, 0xaf5659b1, 0x3de03c8f, + 0x0ce0279f, 0xdca6c99c, 0x35740bcf, 0xf8a758e8, 0x05436f31, 0x8a8a4cb3, 0x3b9ff471, 0xb8cfa454, 0x234474b5, + 0x71411a6b, 0x29a8ebd7, 0xc2808f83, 0x3fc6fec3, 0xad9e4226, 0x9c6e4795, 0x31e7e68e, 0x66866875, 0xeda1ecb2, + 0xbf9482c4, 0x73643e44, 0xa78a6689, 0x83dfcdca, 0x965b28ae, 0xd45888b9, 0xdb0ef378, 0x1bce211e, 0xdfcfb074, + 0x318a8b64, 0x498aa10c, 0x99c354b6, 0x9777f1ba, 0xe08817fd, 0x589513ba, 0x0c4b5d34, 0xc5a37668, 0x4a306a7a, + 0x2042d2b1, 0x435b1007, 0xd7dc81a4, 0xc03c10a1, 0x9ce15deb, 0xa52809ca, 0x7018e2fb, 0x08f19d2c, 0x6e23f9ad, + 0x40ea95b4, 0x2bde2641, 0x0a93777a, 0x035f2cca, 0x646d8a27, 0x029cc314, 0x88fb3116, 0xe079e047, 0xec6766a2, + 0x85bcfc74, 0x92994a14, 0x03c7dd63, 0xcf804562, 0x394ece1e, 0x789e0ff4, 0x547a514b, 0x22df9e96, 0xf6976bac, + 0x5963fd70, 0x266d48df, 0xa02e6e11, 0x7f530547, 0x456db249, 0x4edc49d8, 0x31d807ea, 0x90a6e509, 0x20e0c128, + 0x304dbf7e, 0x635272dc, 0xf6d85580, 0xb9b2709a, 0x6dc9119d, 0xc1d5f70e, 0x33292b8d, 0x0a0b07ca, 0x879ed67f, + 0x4f98e15d, 0x3206e670, 0x11afd786, 0x2676f13f, 0x033a873e, 0x40e9f333, 0xbb06a504, 0xf660cdc4, 0x49b4cc0d, + 0x53045c06, 0x44abc4a0, 0xf3677a3d, 0x81bfd216, 0xc8682be2, 0xe4dcdfcd, 0x81e8ad79, 0xaebe9fdc, 0xdc03cd8c, + 0x7f336a7e, 0x258599d1, 0x42351766, 0xe2531645, 0xe350650f, 0x980fee7a, 0x86b47251, 0xa135fc36, 0x8d9a9760, + 0x7e7eb938, 0x44aeaa10, 0x1fa84853, 0xcc45b0f7, 0xecb008b3, 0x004c8f0e, 0x544a3ed1, 0x9b099b3b, 0xf4e59db5, + 0xd5ea0341, 0xfbafbfb0, 0xc8f08662, 0x6757ca78, 0x91853672, 0xe1a4e778, 0x91ee497b, 0xe57fb0a3, 0x43fa481f, + 0x6d8b3021, 0x3a9f2ecb, 0x9dba22fd, 0xb7c0a4f9, 0x295a1864, 0xe5e4cfaa, 0x8aa68264, 0x34e2af37, 0xa7325577, + 0x80d78126, 0xdf5a9ad2, 0x2b14a562, 0xcb7cee4e, 0x5400ed8d, 0xa2399be1, 0x379c3850, 0xcd664481, 0x1a9548ee, + 0x39486b31, 0x87907c2e, 0x46807f50, 0x52f25a1b, 0xee228fee, 0x9bc29748, 0x92ae7d6a, 0x4daa376f, 0x241a9e18, + 0x5aaaf887, 0xad182a98, 0xa9006414, 0x2e2ba334, 0x1672a796, 0x32059b81, 0xfa79024d, 0xc0f0d00a, 0xbce8fb6b, + 0xe0226358, 0x307b035c, 0x96ca58dc, 0x6d17adcb, 0x4ba0a07e, 0x67beb5ec, 0x97245eeb, 0x43511f42, 0xebbd3664, + 0xfbfb64cf, 0x8c5ef3b1, 0x0a82dbec, 0xc8942cec, 0x42ad7f31, 0x6018bebc, 0x504d2bce, 0xeded02b7, 0xe546ba66, + 0x0ad571cf, 0x076d6b7a, 0xdbb6a5fe, 0x32094ada, 0x3dc37df2, 0xa560374f, 0xbe08559b, 0xb81218ed, 0x1d343989, + 0xb22f0638, 0x97aba04f, 0x912c8fed, 0x2b8d812e, 0x9b01b18d, 0xd9514d17, 0xb9411ce5, 0xd9138d11, 0x8cfbadbc, + 0x2da25371, 0xabe3f67f, 0xdef2096b, 0x9856e5a7, 0x35bb85ec, 0xca630c38, 0x24bb7514, 0xfa425800, 0xd24ab72b, + 0xf710b111, 0xac2ba29b, 0x409dc05f, 0x946c11f8, 0xbdff7cc5, 0x77268bab, 0xb4690f79, 0x0894ed3a, 0x2e8c0f40, + 0x1e94ca27, 0xddbade50, 0xd3be1f37, 0x839d7d40, 0x01eb997f, 0xe92e9812, 0xe970fc10, 0xd06335b4, 0xd112fd23, + 0x3fbd6ff0, 0xaadd85f6, 0xb83955c5, 0xafae1a83, 0x48b4414d, 0x09da437c, 0x4084e5b6, 0x23077117, 0xc24d4ac6, + 0x9a183974, 0xa5b775c8, 0xf502836f, 0x9ed9ea8c, 0x252780bb, 0x73496e28, 0xa4633656, 0x2b736c92, 0xf16100e7, + 0x6341adcc, 0x49965454, 0x64360776, 0xc9fc6fc4, 0x7c9faa08, 0x4d737536, 0x89b9b800, 0xb1ecfa8d, 0x9eee4aef, + 0xc86f1b33, 0x0232147c, 0x3806dcbf, 0x54ce7568, 0x2e257688, 0x3a4a92e7, 0x95f0e339, 0xb40bb409, 0x16adbdc7, + 0x41451624, 0x7a1ed6be, 0x05ea666e, 0xd228005d, 0x3fc6255f, 0x921e3414, 0x8db03c66, 0xc7a10db6, 0x0f83c7ed, + 0xc9e4a815, 0x27f061b3, 0x44d86f65, 0xfd828f3b, 0x7dd87578, 0x1dbf9c12, 0xdabbcab6, 0x51a11680, 0xd4b182ad, + 0x6cfe283a, 0xcb17658b, 0xe6e2ec62, 0xda59b4f8, 0xdf5415b2, 0x8027bdc3, 0xb7fb1d34, 0x73fe165b, 0xde152e08, + 0x8debed88, 0x5f89749b, 0x1cb7fa9f, 0x118008ce, 0x5078a391, 0xf9d2813a, 0x82878e9b, 0xb9dc7b8d, 0x380ccef8, + 0xc2be99d6, 0xe43eaa82, 0xcbcb9a6a, 0xf280577e, 0xae3cb71a, 0x83c7e824, 0x8c243bd4, 0x08957019, 0x1a8a4abf, + 0xafca79f0, 0xce1f2c8b, 0x3b836046, 0xe45f291c, 0xad7928fa, 0xa04724ac, 0xbeb63b2e, 0x6b071e43, 0x7ea0a25c, + 0xaf0ffe8c, 0x4bb2273b, 0xaef06029, 0x34a69256, 0xf37b9ff0, 0xee195d63, 0x5d71ce0b, 0x5fcb119b, 0x970671a4, + 0x3243152b, 0x2877b25d, 0xa6f8d864, 0x29f50347, 0x2181d4e1, 0xcb5ee2e2, 0x46d92436, 0x87e43d4a, 0x0363c8c2, + 0x90f0eb5c, 0x341a7095, 0xc5247635, 0x574b66c1, 0x7d0d525a, 0xe9532495, 0x552264b2, 0xa230b4a0, 0x31445959, + 0xffafb0ef, 0x0f643bcf, 0x1630c39c, 0xcfd93e18, 0x55b62054, 0x8b14b232, 0x3c482c70, 0x2f8b8c6a, 0xafcd0483, + 0x7f1f2ba0, 0x8c8783be, 0x30e16840, 0x9c2d1135, 0xcb243683, 0x8976a62f, 0x3d88927e, 0x0e3a7f80, 0x01843c7d, + 0xe945f613, 0x65bf1897, 0xb737b8a2, 0x5e033483, 0x919f0fd1, 0x48542453, 0x7b630525, 0x21f671f9, 0x73938f0d, + 0xee091e05, 0xfc91b965, 0x52963f6e, 0x23712697, 0x14f9b8ff, 0x3a347f59, 0x3856f71b, 0x891cddc9, 0xe2f1273b, + 0xe92bdc33, 0xfd911e88, 0xc1982dcd, 0xea21367e, 0xbe3a56e9, 0x9b07576f, 0xfa53bdda, 0x976e2620, 0x883bd1a1, + 0x7373ac96, 0xcf0535b5, 0x8f043ca2, 0x0647e3de, 0x0f5d0f5a, 0x96f21e70, 0x612d7f2c, 0xb1729411, 0xbeb997d9, + 0x4ad690a9, 0xdc670669, 0x8fa3e0fb, 0xfd770ceb, 0xdd586978, 0xa3f84a45, 0xb6dd8201, 0xb4a36b77, 0xe78e82f7, + 0x7df7a372, 0x59136876, 0x620dc376, 0x2792aae5, 0x142c713f, 0x7961deba, 0x0e1d00e4, 0x4284b27c, 0xaa956e93, + 0x26903056, 0x15d43eb8, 0xa95c8b17, 0x356fe4a9, 0x6d9bf098, 0x26569531, 0x4a836972, 0x2db9c615, 0x774ceb28, + 0xbf803fc3, 0xb1b816ba, 0x7f654b0b, 0xc915531e, 0x72bf2cf7, 0x043bb777, 0x904e82ba, 0xe3aabbeb, 0xa652ceb9, + 0x653fd99b, 0x37df1e27, 0x8ca82acd, 0x1cbe047d, 0xd900d84e, 0x602b7536, 0x4dcc75c0, 0x80c87b3e, 0x3b287ece, + 0xedb3bcff, 0x58caf234, 0xe93f09b0, 0x604e23f0, 0x52ab75ea, 0x649ea4bd, 0xba72f800, 0x88f4f8f0, 0xfc5ccb8c, + 0xfe1891ff, 0x70c04b1e, 0xd47da871, 0x9f1eff1c, 0x100ef011, 0x1076c879, 0x78b131dd, 0x5c94c166, 0x8cdbb0ea, + 0x01e3bee7, 0xf813abba, 0x91e28ba3, 0xb62e2939, 0x1a3e2a1e, 0xba95e530, 0x125b547b, 0x7bdf7fb3, 0x985e065e, + 0xf29f0e35, 0xe7317831, 0x3c343bab, 0x73ba8573, 0xb74a7187, 0x30a44ab2, 0x72947d27, 0x65dda81e, 0x79374df6, + 0x27ca3727, 0xf67e95fc, 0xd35c2dd5, 0x1564c8e1, 0x72bf3109, 0x8190b15d, 0xc67ed666, 0x9832ef4f, 0x43c206c7, + 0x40375c41, 0x3340c866, 0x84f096e7, 0xd3899d4f, 0x0ed9bffc, 0x5ac83556, 0x1b04fad0, 0x68ed385d, 0xf4d5f6da, + 0x60780b74, 0xb2a1ca1b, 0xbf1c830a, 0x749b1cea, 0x22246675, 0xf5bf3658, 0x9762fb21, 0x4dddd221, 0xdee61911, + 0x8eb32490, 0x2d2dcdf7, 0xfea560ea, 0xa27c0ce2, 0x1c6e1eb9, 0x0404c38d, 0xd94cd28b, 0x4179923c, 0x54c249d9, + 0x635cf007, 0x94977339, 0x7211eb66, 0xdb1add22, 0x38ad3ac2, 0x922c58dd, 0x41dcd669, 0xb568b35c, 0x1d7aa016, + 0x9d62ae92, 0xbe1591ea, 0xb96f3923, 0xae1f899f, 0x47c80736, 0x03fa5795, 0x0dd0c0b4, 0x5975fcb4, 0xde953a74, + 0x98f0457c, 0xd176337d, 0xb66ba12a, 0x16b32299, 0xaf0312ac, 0xcd3da5cd, 0x09c1a20f, 0x2c47643a, 0x50de7ac3, + 0x44749654, 0xce2b0e8f, 0x759a5f3a, 0x5f6be749, 0x835dbbcc, 0x0d9f2cf0, 0x52fe796e, 0x4e6b0072, 0x307decee, + 0x21a504b0, 0xc8e88f12, 0x8710d4f7, 0x1c70d711, 0xa5fc1ea7, 0xe386a90f, 0x1aeb39f4, 0x1958bbc8, 0xc0879bf4, + 0x90178a03, 0xf9b33768, 0x6034e404, 0x6d0aaa21, 0x70c0cae2, 0xb0a32a4d, 0xfd36c4a4, 0xa5b473a3, 0xba599fa6, + 0xfcd900f7, 0x8d9542a9, 0x853ac500, 0xf59d3a8c, 0xc7be3ffa, 0xdcdb5104, 0xc3e4cb2b, 0xf48848db, 0x08ead0b3, + 0xa347e826, 0xa622238a, 0x7a1b04fb, 0x1c8440bd, 0x8d70d441, 0x751b2ac9, 0x44cdd30e, 0xd9a04957, 0x156f56b9, + 0x94d5456c, 0xb0badddb, 0x7399bf83, 0xb7385dd8, 0x381cf431, 0x927c7f35, 0x29baa1c9, 0x68685c21, 0x50179e6f, + 0xba627ad8, 0xb2be40a6, 0x3ea16bee, 0xa9a63a85, 0xca2e8886, 0xefd9a0ab, 0x857898e5, 0xe29c03cd, 0x79dd8aa4, + 0xd2f08173, 0x88b22871, 0xb692fb99, 0x6ede836f, 0x5a1f6d59, 0xf050f042, 0x1fea46cf, 0x64fb0ca0, 0x274262d2, + 0xad027e16, 0xda44851b, 0xc4cf3c76, 0x9c293e72, 0x3b27900d, 0xd38f8262, 0xf36280be, 0xf4a5ac7f, 0xadfc36b9, + 0x3f379ec6, 0xf401d35c, 0x4a9104d9, 0xb55f1a7d, 0x3a47c3cf, 0x74319acd, 0xb05b9cb6, 0x548c805a, 0x96c418b7, + 0x07b8dbaf, 0x3f0edab7, 0x5da46859, 0x0722ff95, 0xe1ee6c0f, 0x1a16da35, 0xe23dfb3a, 0xde0bdec2, 0x2cf61ae8, + 0xf8df576e, 0x667f378b, 0xacdc146e, 0xddfc6cb0, 0xfd26d92b, 0x46b3b1ab, 0x6a970422, 0x0d9cbe39, 0xc5207eda, + 0x77f85205, 0x0cbb647a, 0xbe021ee2, 0x40c56b90, 0x0d0d510a, 0x61f2df53, 0xe69f5d33, 0x43004e8e, 0x96f077a7, + 0x55f26242, 0x87b8b2d3, 0x22afe184, 0x8df9ae19, 0xa3eda0b0, 0xb1c98b7c, 0xbdc7e9d5, 0xbdd42769, 0xfee83f0f, + 0x1e7e11e4, 0xb987ec3a, 0x664ecd53, 0x6835d87a, 0xed72352f, 0x200279f4, 0xc0b6a78b, 0x353a25a5, 0xaecd2ca8, + 0x174cd7f1, 0x8b8ae7c2, 0xe0b7d4e3, 0x36006136, 0x00756785, 0xa057d8ec, 0x277a4ac5, 0x277e1c60, 0x03aac533, + 0xb10def94, 0x4df888ae, 0x4f27a8d1, 0x55a43187, 0x0e60d8c6, 0xbd5f8d4a, 0x38e9ce79, 0x91701d7a, 0x33583516, + 0xbad84008, 0xc290880e, 0x4ff1f1b7, 0x108b38e6, 0xdebdcc7b, 0x18f43d77, 0x14a9d847, 0x61359ed5, 0x8cc34b9c, + 0x71613373, 0xd5c4d375, 0xa7dde2f9, 0x27f4516d, 0x1c62c264, 0x8b20c1af, 0x8cb4996c, 0xf3eb5d9f, 0x53305f52, + 0xabe1b99d, 0x76ea6afd, 0x68eb6b68, 0xe890d549, 0x70e72622, 0x6c6c4b6c, 0xbdf7e28b, 0x4ec39ba1, 0x7fde31d5, + 0x8f0d3dd5, 0x65a6e063, 0x01186f96, 0x40780fe7, 0x2206144c, 0xcc39e593, 0x0e2ae474, 0xa731bbc1, 0x91134b47, + 0x0020045f, 0xf9bf005a, 0x8ae697ed, 0x5c6f831c, 0x8843aaf9, 0xc883cb29, 0x42addc9a, 0xa4870c6e, 0x50422df1, + 0x9970742e, 0xd4b3d945, 0x3883fe7b, 0xc470398f, 0xc4ed5d9c, 0xb35f8d71, 0x9d22af84, 0x8992f856, 0x29d77954, + 0xaf2a1371, 0xade563c3, 0x5f4a22a9, 0x69677f6f, 0xb7137200, 0xa759891c, 0x8329c86e, 0x5983d9e7, 0x5ccceacb, + 0x231f552a, 0xcc75e8c4, 0xa1a9f3a4, 0x7c40d84a, 0x13ead405, 0x4a8e67ec, 0x7ab224d0, 0x170de5e5, 0xf501af08, + 0x6396c2d1, 0x4f24ff32, 0x89e42136, 0x60e82769, 0xa87fec67, 0x8281306a, 0x3e180307, 0x450c130f, 0x7890ca17, + 0xe5f6a910, 0x0f579f3b, 0x8c565efe, 0x8a891c1f, 0x2ef1108b, 0x69fe4054, 0xc4583d9e, 0x01655b21, 0x3633b269, + 0x1e846f65, 0x093bcff0, 0xec77bf65, 0xc09254c9, 0xe3e9387a, 0x91080317, 0x2a76a772, 0x40d7ca9a, 0xdfa3cb77, + 0x56097a4a, 0x74983ff7, 0x1f1c007e, 0x989e9b89, 0xa51c0f8a, 0xedc2a5fa, 0x8cc22d91, 0x1d68c67b, 0x60136378, + 0x10343fa2, 0xeb021b58, 0x7371e2ae, 0x47f0b635, 0xf2d7e17e, 0xd108a46e, 0x7d3212d0, 0x5da40933, 0x6c3ab382, + 0x2f058ec7, 0x37e53405, 0x0a49dd35, 0x4a4523f4, 0x067f4a5a, 0x6344014b, 0x768e5bf1, 0x2c442e62, 0xd9e2b847, + 0xebed4653, 0xbd96a4e2, 0x7f3a0892, 0x5ab3cd2e, 0x17715ac7, 0x80c13adc, 0xc42c5a18, 0x52583a08, 0x48681f1e, + 0x722dbf50, 0xd7814579, 0xca7390c8, 0x70b4242d, 0x0b46512c, 0xa388470d, 0xd7fbb1f0, 0x3243b926, 0x54fdcb66, + 0x0673d0d9, 0xca3833cc, 0x78cdd1b6, 0x9023a138, 0x3720af6e, 0x0e917506, 0x72e619a7, 0x713ed529, 0x32d3332d, + 0xb81a93fe, 0xb35e4a98, 0xfa355a21, 0xd5e00865, 0x26b7f73c, 0x4817255c, 0x03ead53a, 0xaba22f09, 0xf0c66a1a, + 0x92debdec, 0x0000dd0d, 0x9d7d36dc, 0x423e338b, 0x847704a3, 0xabcf7f5c, 0xb09c149b, 0xf1c90a1c, 0xf8db4582, + 0x1cd239ec, 0xc1672431, 0x17531d83, 0x1fdba326, 0x2301450c, 0x07633382, 0x79f2d690, 0x4f283a2a, 0x82c033d5, + 0xa4726ca8, 0xdc50c295, 0xaab74d9d, 0x7c67d828, 0xf226777a, 0x645b4026, 0x6ad60570, 0xdc1ee79c, 0x13c7fe72, + 0xd79e5721, 0x02aaf0ac, 0xb94ee585, 0x1fb17492, 0xcfa40f61, 0xf84815ab, 0x41ab2025, 0x50eff2f9, 0x1fe2c915, + 0xd6392b47, 0x977c3d54, 0x1ac03b69, 0xf50a4697, 0x924aaaa3, 0xc8191961, 0x0ac2fcf2, 0xa78ba625, 0xe4d467da, + 0x7607bad3, 0x86e8ca1f, 0xaadd2b2a, 0xc9f9b438, 0x1342a6ab, 0xa8b4fb1a, 0xb7c5b472, 0x5c44434e, 0x642aac34, + 0x27d4d2af, 0x62ef253e, 0x3242d986, 0xc5528938, 0x05881e0b, 0x3af44cc1, 0x4585a9ca, 0xfad0ed92, 0xee2dbd0f, + 0x7a5f8ca4, 0x44d4042d, 0x41df9227, 0x6f091c3f, 0x39376b4d, 0xe43cdf97, 0x30ccbe72, 0x6c656594, 0x0fa04c5d, + 0x186d1e5b, 0xcfe773c6, 0x98d9ae72, 0x74e76fcd, 0x095fcc6f, 0x980749bf, 0x2a65207e, 0x2e3442b4, 0xce3579b1, + 0x552c6996, 0xa3e9df7f, 0x9e862c44, 0xf0b32621, 0x07f69690, 0x948a0c89, 0x74f7c9c7, 0x68ded67a, 0x2eb8608b, + 0x1c69bd22, 0xfdd406f6, 0xfc068203, 0x12491475, 0xea922a2e, 0xaad77c80, 0x1ff22c17, 0x21ee66b5, 0x9ba5fbc9, + 0x4d96877a, 0xc6c98690, 0xb8fa15b7, 0x6e72134e, 0xfe1e4366, 0x2f2679ad, 0xc9dcc27e, 0x5d80ba33, 0x59cf74e9, + 0xf1f9ad6f, 0x4db40588, 0x26121dd8, 0xcd0d1d29, 0x0d909e5f, 0xbae66121, 0x0df62169, 0x7c247ffa, 0x2dd92f7d, + 0x0a0e1596, 0xc15beda3, 0xa44842fd, 0xa3d3c738, 0x00fbe844, 0xe06d4183, 0x3d5f0aa0, 0x57e77f71, 0xff06de0a, + 0xed713d75, 0x3dd6c1ad, 0xf6474f0b, 0xee7fa1b1, 0x7e39310b, 0xe4d98849, 0x3dc126dc, 0xeaca093a, 0x84b5915f, + 0x141a6491, 0x0a5d887b, 0xfc9f4597, 0x87b6953c, 0x59791a75, 0x2a7700df, 0x894b9e3a, 0x1fb6abc7, 0x334aedce, + 0x25804e3d, 0x0bbf984e, 0xd750fe44, 0xe51a24f1, 0x1204b696, 0x7d75f624, 0x296def07, 0x0988ec1a, 0xafe83089, + 0x02ceda09, 0x638fafe3, 0x9ba4745c, 0x7843d06c, 0xc05e0e78, 0x902f087d, 0x0a8227b0, 0xdab6992e, 0x598e3d2b, + 0x9a3a00f3, 0x96f6061d, 0x2b5b2b2d, 0x1c231598, 0xe7ec11d9, 0x92a5fc0a, 0x26e60c2b, 0x7895d1a8, 0x9774b848, + 0xba6bbdfc, 0x4093cb62, 0x89dd9976, 0x25794bcf, 0x7bf176c4, 0x5f9978b2, 0x644f674b, 0x4eee3a1a, 0x096818c4, + 0xba2fa995, 0xeda077ad, 0x6bfae90a, 0x3279dfbc, 0x897095b1, 0xab2846bf, 0x991f3870, 0xfaeaea23, 0x755175bd, + 0x21ce9465, 0x9a16dad2, 0x48d0a501, 0x43775dd9, 0xca44786f, 0x6085408f, 0xa6cf001f, 0x131c173e, 0x3d7ce0d5, + 0xccbfa17e, 0xfa9489de, 0xa26c7e54, 0x9a2bf5db, 0xaf28ce56, 0x0bea2b61, 0x4c1e80fc, 0xebf54da9, 0x6851f1f5, + 0xf764ff7e, 0xada931a6, 0x3a5f8550, 0xb976dc48, 0x99778ce0, 0x79df3f8e, 0xc211f5a5, 0x977880ff, 0x6afa146f, + 0x78f1aa69, 0xeaa73c64, 0x24f4093d, 0x27fac49b, 0xba1b4653, 0x98e873d1, 0xbe2c2921, 0xec676da1, 0x49b167db, + 0x3537e452, 0xeb7f2f46, 0xd612dead, 0xac25f82e, 0xd499410d, 0x89aa468d, 0x62b63685, 0xc8708976, 0x49c08f10, + 0xdc2da053, 0x8161aba7, 0xec9429d1, 0x506467bd, 0x79b188aa, 0x4c81bd70, 0xce1e8b27, 0x68fe567d, 0xa9985d21, + 0x831d25d4, 0xa058f35c, 0xe0253054, 0x2f557a7a, 0xd31fa59b, 0xe19ccebb, 0x20a456b9, 0x0bffa5fa, 0x0a7fedcd, + 0xe00f2833, 0x53091421, 0x09bb9a6c, 0xd36c0583, 0x00056887, 0xc76b8116, 0x07fbdbb9, 0x3b72d64a, 0x8ebbbb40, + 0x9f1ca8de, 0x8235cd9d, 0x4aeb3717, 0x9d6666c0, 0xa35e6d10, 0x22a39bfe, 0xbff8e6ef, 0xeb7d695d, 0x6d4fe1cd, + 0xb016e208, 0x498c2c48, 0x1cd3f8f5, 0x0f30a9df, 0xeb3c7ba5, 0x10ffdd4e, 0x5e94b025, 0xa0cd4f44, 0x5fe8ef60, + 0xe8ca30b1, 0x0d2485e8, 0xc03a40be, 0x84169d56, 0x917e104d, 0xa3d76bc3, 0xdfe7cd01, 0x82a3454c, 0xf6bdb3e2, + 0xe2633070, 0x2aebec2b, 0x8e7992c7, 0x3496f849, 0x2c3c1a87, 0xe9acc2b4, 0xe6face50, 0xd89e828f, 0x999315a6, + 0x027d7b51, 0xb68ff7c1, 0xc321ded5, 0x713fc444, 0x75a31a3f, 0xa4cdb258, 0x4a28d162, 0x7f6b482f, 0x954d4bba, + 0xb902261a, 0xc67002c7, 0x47a980b9, 0x501f8242, 0xc8bd317d, 0xb6e84e40, 0xb2a8c3c5, 0xb8a4d13d, 0x3e119b71, + 0x40c5d1b0, 0xae0bc044, 0x442851c4, 0x6ed2202e, 0x68af76ca, 0xf6ed73d2, 0x5e44ddc7, 0x54a69931, 0x54dfdd50, + 0x7a67ee9a, 0x05caf2e2, 0xf1577f6b, 0x268e981b, 0x0bdffac8, 0x4602733b, 0x43bfc397, 0xf9d98180, 0x5025d0f9, + 0x25702d06, 0xe86082e5, 0xe1c69082, 0x4dce5487, 0xc855070a, 0x0c67a19c, 0xc35f6577, 0x71b8c03d, 0x9de52afd, + 0x6a7f1431, 0x07d10968, 0x71fc9d97, 0x60173894, 0x7f0294bf, 0x0a118f98, 0x26584e2d, 0xa9e0c53b, 0x4d2eb424, + 0xd6aa6a88, 0x0e5a5af6, 0x72c513f7, 0xc624ebc1, 0x909e2b5c, 0xb440e726, 0x93da3f43, 0x176235f1, 0x710e25af, + 0xae4c8b2f, 0xf748d7a8, 0x926bdb08, 0x795f11fc, 0x676afd72, 0x6696182b, 0x2e9065bf, 0x6d0436f3, 0x177e4800, + 0x063b3dfd, 0xe8b7ca5d, 0x661d3b38, 0x3c06ccc7, 0xc260cd7b, 0xdd558ab9, 0x285ac3cc, 0x3292c6dd, 0x8f9ffcd7, + 0x5bb8f72c, 0x94646695, 0xf21b0617, 0x7d521e37, 0xb4acd955, 0x6bde457e, 0x7d753026, 0xdccc0977, 0x6c59ef36, + 0x215008fa, 0x8a0e45a2, 0x625e5777, 0x52b025f4, 0x63fa914d, 0x1c0058ff, 0xaa42a700, 0x86f88b84, 0x38429fae, + 0x6c588664, 0x5a67cb38, 0x5606310d, 0x37acb01a, 0x4d163d3c, 0xb26848f6, 0x7247e8fe, 0xe718fd0e, 0x7c02a79a, + 0xe988892f, 0x3a495444, 0x161af3bf, 0xf1283078, 0xd4c62e17, 0x1ff28a43, 0xeacfaa4f, 0xd3106f83, 0x8c501203, + 0x9e3202a9, 0x9eb4eff7, 0xb3e6e5af, 0x41418f63, 0x16b517cc, 0x2a10f26e, 0xa9e32c52, 0x636b58f8, 0x18d848ed, + 0xfcc75bf1, 0x27af5bfe, 0x18adbac4, 0xf973ca8a, 0x5d976724, 0x4cba1c45, 0x218ac953, 0x4a84d89b, 0x75afc126, + 0xa093c901, 0x00027abc, 0xfc3c05de, 0xc9d7406c, 0xf9a635b6, 0x2acd87cc, 0x2d96ef7e, 0xd31155ec, 0x61a41291, + 0x3a13c33d, 0x0192452c, 0x4103611c, 0x8b0f6586, 0x7b2588cf, 0xead26fab, 0x215f61ce, 0xd9c32957, 0x75b77994, + 0x58397b2a, 0x31e70139, 0xddfc870b, 0x83d49690, 0xbbb3cf34, 0x10abb3da, 0xbfb920a0, 0xeb23a6ff, 0x70673f9c, + 0x07766595, 0x7592b226, 0xd5433b86, 0x23bfeb92, 0xdacb0938, 0xa01ab7c0, 0xc8780b93, 0x0b8b56d7, 0xe7158237, + 0x32f37b86, 0xa8b3f2ab, 0xfdc0d5b1, 0xbe4580d3, 0x310f5fbe, 0xe2c5ed6d, 0x85681441, 0x460a8c69, 0xb948b936, + 0xcb73483d, 0xf1027f90, 0xa05bdf89, 0xf97b3e1b, 0xa1a7cf28, 0xab6e841f, 0x31a3cb0e, 0x2c5bda03, 0x4fc826d4, + 0x2f490f34, 0x2dba7a65, 0xe6ec109e, 0xc7a063ce, 0x6565bb0f, 0x56f283be, 0xc385a290, 0x8dba4405, 0xfc200ee9, + 0x5da7b5e3, 0x10ff8e93, 0x2871d704, 0x8b1852a4, 0x9c9d96a1, 0x75772acb, 0x1e0fe09f, 0x55d2ea36, 0x3ca2be89, + 0x92b472af, 0x9d5f2082, 0xb01f0e8a, 0xc4da7f76, 0xd5fd509b, 0x7aea2a25, 0x4c76dac0, 0x3f8fb7ca, 0x9667a455, + 0xe0c7fbc2, 0x138f2a52, 0xcd8e550b, 0xbabd0f11, 0xa796edf2, 0x20b685f6, 0x90ce2b01, 0x15730850, 0x6be56caf, + 0x43abde21, 0x8b31603b, 0xeeb991cb, 0xc015096d, 0x9be56199, 0xb1cb4119, 0x0f078628, 0xe7d633a6, 0xd6a8cfe3, + 0xaede79e7, 0xd33e767c, 0x47036129, 0x5090a75a, 0x084bce79, 0x54629f4f, 0xcda4024a, 0x30859ceb, 0x1b1c659f, + 0x02a26cc5, 0x7b604893, 0x9b9082dc, 0xe8139291, 0xdfa15061, 0x2d2cfbac, 0xea70a4ef, 0xfcfb7989, 0xa2a6a4d6, + 0x24403621, 0x9f5d0e20, 0xc5517bdf, 0x82c19e19, 0xbbbdd020, 0xa42f008e, 0x554c77f3, 0xc8fa8cbf, 0x20779684, + 0x977e2dd9, 0x2e12e337, 0xc65fef09, 0x2ee17402, 0x20a3cb5a, 0x67aa83a4, 0x70e95c17, 0xd0472a38, 0x6103347f, + 0x6286c02e, 0x0fbc4dab, 0x3429b6bc, 0xe96549da, 0x14475929, 0xc304df39, 0x97d20d3f, 0xa2deb106, 0x87d36dea, + 0x0dc013ad, 0x142b0326, 0x7ace20f7, 0x5111d2a9, 0x8a6828dc, 0xa1ebb130, 0xc14872db, 0x35e24e6c, 0xac225089, + 0x017597ee, 0x2e787301, 0xca195b06, 0xd906db03, 0x0d04638e, 0xd765f795, 0xeac25aac, 0x5133a433, 0x8da54ba9, + 0x41e93083, 0x9a31da96, 0x502d81a0, 0x5326bab8, 0x36d0b656, 0x37974b94, 0x7e407b2e, 0x7fc1c2d6, 0x8a7fdbdd, + 0x1d3b60da, 0xab47cbd0, 0x9744dc7e, 0x3172ccf7, 0x3fe7ea4d, 0x584ebfa3, 0x2d8c6889, 0xf1c21595, 0x98c0aefa, + 0x74b4335e, 0x55a91075, 0xda562769, 0xc9cd4710, 0x4767cadd, 0x46b955d9, 0xc337ecab, 0x991a1003, 0x67f7877a, + 0x609406b8, 0x8788eac7, 0x5f5ad12b, 0x46f3cc38, 0x3ef17d57, 0x314be3eb, 0x2e38726a, 0x137859b6, 0x6ee51943, + 0x6f4888d8, 0x6838a9a6, 0x99e9ff01, 0xab04fbf2, 0x238ef97a, 0x2170e2df, 0x89a893c6, 0x97b26c28, 0x2bb0101d, + 0x77a34b40, 0x99960214, 0x1e0fdca2, 0x17c6fc44, 0x8c6a6dc4, 0xa38ad444, 0x5f991708, 0x046044ad, 0xf9b895e5, + 0x441c2720, 0xa8b8f1e6, 0x02ca2647, 0x1c2fcd20, 0x7d57c7fe, 0x9ed60215, 0x47c979e1, 0x44fbd738, 0x3d2b75ad, + 0x694d5d45, 0x7c973bd7, 0x8acc99b0, 0x4e159f9c, 0x9d4f56dc, 0xe694aa07, 0xffe1e13f, 0x24489b49, 0x4db39f13, + 0x1edefa57, 0xe02798df, 0x20d95b07, 0x9df12bac, 0xbd5cc07e, 0xc990e3b0, 0x762003af, 0xb9e19e43, 0xdf9d908f, + 0x91a7d7d6, 0x63da2896, 0x26dac5f5, 0x3cd51df4, 0x4f6cf1d4, 0xf723c791, 0x5972b668, 0x96ef9c6c, 0x80d8d5a2, + 0xd945a929, 0xaf8b6b6f, 0xb924cc6b, 0xb7b46759, 0x327e4fd1, 0xfffb70ec, 0xa49dba83, 0xb6625e17, 0x91f5dc55, + 0xd01a1e23, 0x0d21954d, 0x275600c2, 0x2d64e49d, 0x8216fc34, 0x550a54e1, 0xfd006824, 0x9cebd3f8, 0x82275cf1, + 0x9abdd017, 0x42a293c4, 0xbb39ac89, 0x8ce1e7c7, 0xcb12d807, 0xf51c2ba8, 0x2dd16d66, 0xc689e2f0, 0x6a3fbac1, + 0x1673a5ea, 0x847d9d20, 0x174be1b3, 0x669e4a41, 0xcc69294b, 0x7563358a, 0x4b426af9, 0x25e363dc, 0x2cd2297f, + 0xf85a4234, 0x1fb807ce, 0x2467b89b, 0x73ec3973, 0xbffc220e, 0xebb2d55b, 0x3c0f6014, 0x3c2689b2, 0xc9a7e6cb, + 0x3a793fd9, 0x52fecbe8, 0xd3f99825, 0x7127f276, 0xb349d511, 0xcde88615, 0x47e3b130, 0x8b2e72fd, 0xc4d40987, + 0x53e80e02, 0x32ac2644, 0x302886fe, 0x27cffb7e, 0x41a33511, 0xef50ae5d, 0x598f79d4, 0xb2b386be, 0x6b045bea, + 0xe5c8a7c2, 0x7c1e938c, 0x073f1ca8, 0x10905342, 0xdf34ecd8, 0x1df065aa, 0x1f0a82f0, 0x9dc676ba, 0x8d1c3d25, + 0x3ce8b68a, 0xcf322e1d, 0xd7627dd5, 0x029b5bd2, 0x1c0b0cb4, 0xc5d10ffc, 0x752d548f, 0xa3a5d2fd, 0x897aa418, + 0x16ab6b56, 0x3dc2869f, 0x995f604c, 0x3f95726e, 0xf887e1e8, 0xd97a6181, 0x23d3bc40, 0xf91fa4e1, 0xe2d25c97, + 0xd9790c32, 0x22c97523, 0xa2289664, 0xe48d5e72, 0xd6b34e82, 0x8bdc9a50, 0xbed9ea16, 0x98465d59, 0x2891a362, + 0x862ee046, 0xa6529cca, 0xac925ffe, 0x5754ecc2, 0xaab71cf5, 0xea388fc9, 0x33308621, 0x275d5699, 0x4b7f7283, + 0x6fd5607b, 0x277880ef, 0xfb28cf7d, 0xa836bd69, 0x6d01dbb8, 0xd9292bc0, 0x720d4473, 0xe68dad25, 0x29c76980, + 0xc22052c7, 0x82d69be4, 0x6c1f4e47, 0xa49dad26, 0x3f888c90, 0x0476eade, 0x07d2a89f, 0xf1e14849, 0x43421f43, + 0x96300cde, 0x801d7006, 0x6766e082, 0xa05dbe65, 0xed3e69dd, 0x13c1add4, 0x501fafcb, 0x533d657d, 0x0648c5c3, + 0x34edbc90, 0xa93364fd, 0x5875ed02, 0x917f4549, 0xa84ffb05, 0x1b7b6959, 0x84c105bc, 0x064e862a, 0xab22ad10, + 0x213cbeaa, 0x6ccdf675, 0x80326b7f, 0xe326c4b8, 0x10e513ac, 0x1fbee720, 0x6e9e675b, 0x1291d4c3, 0x7b76cc89, + 0xeb5d5317, 0x06b5e360, 0x8a3df8f8, 0xffc42d38, 0x98574553, 0x33c5528f, 0xd89972d4, 0xf0f1367b, 0x74945a22, + 0x24ac70b5, 0x9a40d5f5, 0x85a7094f, 0x9def58e6, 0x5b991379, 0x43bac724, 0xc7c6fcfd, 0x9f5e4211, 0xf4b7c0c7, + 0x397208d7, 0x58137240, 0x02393ec3, 0xd2fd6436, 0xcbe15fd0, 0x8d6b2bbc, 0xf620ab34, 0x7258522f, 0x39668de9, + 0xef9f2805, 0x4066a331, 0x5177128d, 0x1495bcd9, 0x79c68396, 0xb4bcc786, 0x10fea488, 0xbced3459, 0x3f1219da, + 0x7b160dc0, 0xda1488b7, 0x26978b10, 0x4e549978, 0x8ec7581e, 0x891c92e8, 0xd6eec49c, 0x57517278, 0x734d963c, + 0x2aa9b38f, 0x5e708749, 0xf39c070b, 0xa229be5a, 0x319dc6f0, 0xf4d413b7, 0xa83e6670, 0x7b19ec8b, 0x3d3a6091, + 0xed91eeca, 0x002ac1e6, 0xb2f94e62, 0x9d08e91c, 0x0c043f69, 0xc9ff2e4b, 0x6f4d40f2, 0xc15eb7c2, 0x3a29bda5, + 0xfb5675ef, 0x6781bc42, 0x6c757ca8, 0xd88bee52, 0xb823f1cf, 0x45c87cf4, 0x19f05d56, 0xe9030b20, 0x13bc8e56, + 0xfd8d507f, 0xa9193bd6, 0x17ff150b, 0x305a8457, 0x40179c25, 0x09f95380, 0x8fd84ef6, 0x564823c3, 0xb8ee7d1e, + 0x15012d8c, 0x1f46ed1a, 0xc6a41a8e, 0xed61d371, 0xa78e0235, 0xaeaee545, 0x33b75ad1, 0xc250a721, 0xafcc98bf, + 0xa8adfd3a, 0x11143783, 0x042eb95d, 0x3dcfcef1, 0x247f74d8, 0xdfd3db2a, 0x2e56df1a, 0x0b955ee8, 0x9cb374c8, + 0xf26f7902, 0xe2abe062, 0x32237376, 0xc95bf140, 0xa1b59b86, 0x008a79ed, 0x7d8861de, 0x5bfafba4, 0x421779f8, + 0x0f722421, 0x8313ea1e, 0x51d03d9f, 0x0601c6bd, 0x7e863d4f, 0x7da971ee, 0x503e65cf, 0x7624d43f, 0x07465ed8, + 0x8d38ca93, 0x52a22f21, 0xecbb9324, 0xa9a724cf, 0xbd462111, 0x69118e9e, 0x5c4ecf1c, 0x0737cb05, 0x654eeb21, + 0xd7587234, 0xc426e949, 0xe9e45e8c, 0x5e3e70d8, 0x80761cc9, 0x196c8498, 0x6b3bad15, 0xa8c33077, 0x4bcd06ce, + 0x6249eba0, 0xfd587a4b, 0x3263594b, 0x408e7535, 0xd4e73f62, 0x6031bd0b, 0xde7828c9, 0xac7adaf6, 0x56e3a51f, + 0x6e65a7e2, 0x41deddcd, 0xc32d09c3, 0x6554c184, 0xdb483090, 0xe9ad245f, 0xb9d4c4b3, 0x126c1f2c, 0x2b62a97d, + 0x71978628, 0x9a53da4e, 0xdba47f12, 0xdd4d6a21, 0x3592f03b, 0xb7d676d0, 0xd9a17e37, 0xb60f1b33, 0x0889ba87, + 0x767f3fc2, 0xb3024188, 0x83cbe788, 0xd531eacc, 0xb1da23f5, 0x1498f2f1, 0x20f0df08, 0x87b048f4, 0x57a4f0db, + 0xdd14a342, 0x350a1e73, 0xcc1ecf9f, 0xacd1172c, 0x840927c3, 0xd49e3ed7, 0x3ec70999, 0x68785f93, 0xed13ef24, + 0x12619b28, 0xe761a731, 0x2c7b4f57, 0x3168a46e, 0x749d327b, 0xc7270d3e, 0xccffdf16, 0x1583c866, 0x9e49340a, + 0x423190e5, 0x64371fa2, 0x49bff0bd, 0xe93daf6a, 0x90aa0e25, 0xb0cbd9f6, 0x89123eae, 0x8eb77b8e, 0xa7927972, + 0xa7d2678e, 0xf6625f92, 0xd9a1c443, 0x49705192, 0xecc6526a, 0x4ef08e02, 0xd0d3f880, 0xcd0ee29c, 0x7d910567, + 0x365ee4ac, 0xf138f8a5, 0x7514bb56, 0x442bd2aa, 0xc5a5d5e5, 0xb471cb88, 0x6c43bc0e, 0x285e69ec, 0xb9ba0178, + 0x9c6df90b, 0x3c0772bb, 0x712cec25, 0x8bc2c862, 0xf3451289, 0xaf116027, 0x91c0833b, 0xc8245fa3, 0xd4534625, + 0x91b79191, 0x84011041, 0x7efcef23, 0x360e98f7, 0x0bbfd521, 0x0d9a84c0, 0x9b4be39f, 0x45007e88, 0x278f6f27, + 0xd9196f47, 0x51e8d51d, 0x34f96be4, 0x17184443, 0xf557000f, 0x93c13fe3, 0xa30a5e9d, 0x77899419, 0x6c21632b, + 0xee831197, 0x9417b1bd, 0x23cc1ec1, 0x5c7ea17e, 0x05181e56, 0x6ec30e06, 0x774c2add, 0x2ee4d106, 0xca0ca1fc, + 0x3b595c91, 0xc8e8e2a0, 0x69a2d098, 0x1ab614b4, 0x6d7db91f, 0x94d85629, 0x15dbd029, 0x66967f47, 0x77760294, + 0xb4b036c3, 0xf1713b86, 0xa55404dc, 0x0399eaf3, 0xe5e8f746, 0xf3c27c86, 0xcdd4e986, 0x3254c676, 0x2dcb3684, + 0x125bf851, 0x7c9bb4fb, 0x779d4655, 0x5ccc3eab, 0xaae4131e, 0xa8a1a7cd, 0x3f706a7d, 0x2ea5f2ae, 0xf3406bc1, + 0xbd8de2ff, 0x7502ec96, 0x55430f6e, 0x5d1d816e, 0x7d56f755, 0x86390ad4, 0x7285845e, 0xb9f8d824, 0x44c0c3b3, + 0xcd94f33b, 0x57f4b715, 0xf2f72003, 0xf119689c, 0x59cc6ca1, 0x2d4abddb, 0xa24054d4, 0x09076695, 0x024fec93, + 0xa56ca88d, 0x9a1d301d, 0x10bc5f1b, 0xced7ab4c, 0xb28a3d7c, 0x351339a8, 0xbd4db254, 0x62b2bb07, 0xa846820b, + 0x04863e1c, 0xf012fc0e, 0x8952a9e3, 0x57b93210, 0x91f44a9d, 0x7d815aaf, 0xb1b9e66c, 0xa7b116e4, 0x903286f9, + 0x6537180f, 0xf5c88578, 0x46f0e04d, 0x71049169, 0xa5fae17a, 0xd3c63291, 0xfda64811, 0xf43a18fd, 0x33b42eac, + 0x8551b4a2, 0x5a92b65b, 0x671fad4e, 0xe8f5fdff, 0xd4430dd9, 0x21706216, 0xbf468de0, 0xec435e65, 0xdf53f845, + 0x42069b86, 0xe7646cc3, 0x4846193b, 0x1d9a5f77, 0x7a930f1e, 0xc14445d2, 0x58963cf7, 0xb8103fcb, 0x3d011685, + 0x7fdccf76, 0xdec8ecb6, 0x1e8c3c29, 0x4bf468fb, 0xe503a753, 0xe5db33d8, 0xab9244af, 0xd4e29959, 0xcc346686, + 0x7ad0879e, 0xcd0cf74d, 0x61a4820a, 0x2e6897a1, 0xd3722862, 0x0240c6b8, 0xf0dcb738, 0x8ad7ddc1, 0x6fab9026, + 0x88372152, 0xe3e6e28a, 0x84d588ad, 0xc002dad4, 0x3451be6b, 0xf3fb0238, 0xe83c5d0b, 0xb116e7fd, 0xfd548a71, + 0xc57c5000, 0x0712757b, 0x30b326cf, 0xc1936566, 0xad416038, 0x86576195, 0x1dde5f50, 0xe0e3b802, 0x0eccb75a, + 0x823905ee, 0x69fcc877, 0x0415b55d, 0xdbdc1e97, 0x35df9736, 0x73249644, 0x3d6acc47, 0x1917b8b9, 0x6fd9d634, + 0x26ca1779, 0x44c6b4fa, 0x9216a772, 0x0cb7118d, 0x125bc0a4, 0x4d76f48b, 0xb0127f27, 0x0e6da20a, 0x52aba926, + 0x581c4d68, 0xe04bcec9, 0x5c736cc0, 0x081b974b, 0xb6a8f205, 0x1f22f3fd, 0xca9d8a64, 0x55cec542, 0x2dd702a8, + 0x26dcdbb5, 0xc8910a40, 0x3f13a847, 0xad72613e, 0x34ed1a80, 0x9e9f8c04, 0x72df3aac, 0x8f2dcd37, 0xccdb9fde, + 0xfb4efa05, 0x5dc91c22, 0xe71f9738, 0xf7811b5b, 0x26c4fd45, 0x12de90f8, 0x7be16e9c, 0xbdfa8425, 0xa7a7b4df, + 0xcfde6721, 0x13feb55d, 0xda678a49, 0x608240e7, 0x5d61c842, 0x6dffc329, 0xe4f31c26, 0x0b24d854, 0x5ad75e1d, + 0x40ce0c89, 0x0c73a00f, 0x2d301d26, 0xfb5e3dcb, 0x6046e169, 0x965e10c7, 0x61f434fe, 0x8aa202c5, 0x50c73472, + 0xcbe83396, 0x794d1e83, 0x0825fd89, 0x19d5840f, 0xc44ac981, 0x38e32fa0, 0xcde910bb, 0x2cbe8e44, 0x0adfc6e1, + 0x30be4ac3, 0x992551ee, 0x88ef6cd0, 0x89a08013, 0xc94e4b8b, 0x34e6bf86, 0xe2a3bdca, 0x807369db, 0x32fcd2ae, + 0x2a1e8615, 0x685a2267, 0x0e34dc87, 0x652a374d, 0xc533543c, 0xb788e8cb, 0x8124b395, 0x67f2b447, 0x648d4484, + 0x371bcd05, 0x6a20fe72, 0x4931ad86, 0xcb98938d, 0xdb5de067, 0x353f424c, 0x273b6d7c, 0x8143ba85, 0xccf49578, + 0xe13d685c, 0x743a8d03, 0x067dd803, 0x8b4fbc07, 0x5649a0fc, 0xf90e536b, 0xa355a1ab, 0x91b61a0c, 0xe3c95ac5, + 0xdaa35bbe, 0x2463cffb, 0xb6ab005f, 0x7ef8d1f8, 0x2fdc2e6c, 0x28d1641e, 0x71609c10, 0x28f7cb86, 0xa5640d60, + 0xe2548617, 0x0ee559c4, 0x46497c36, 0xc8d6ed00, 0xe04e4095, 0xcf08e8a0, 0x239b697a, 0xc827db47, 0x588b60f0, + 0x6e108411, 0xe85bd873, 0xdefb55bd, 0x34b3907d, 0x32a31079, 0x71f7615c, 0x9e30dc66, 0xe5be2c04, 0xea81cba7, + 0x9f316398, 0xb3247be3, 0xb7e25cf1, 0x6f8b6372, 0xf591fb10, 0x9fc729dd, 0xedcf803b, 0x62086ef3, 0x1803798a, + 0xceef5c83, 0xa6633fa1, 0x2daa693d, 0x75858d07, 0x9c77c25d, 0x92163cb9, 0x64a98fb8, 0xfccb68e5, 0xde2ea94f, + 0xb976ffe8, 0xa8d60683, 0xa802864c, 0x9e90e4aa, 0x6b264ff1, 0x9d795a9e, 0xf7380b90, 0x3ec218a9, 0x1820a5a4, + 0xff4d70f7, 0x8eaf5e3c, 0x301cdb56, 0x315b830d, 0xe6fcda83, 0x2a2791c5, 0x1f01af1d, 0x81fa33da, 0xbba966c8, + 0x9822fd88, 0x3f976f0b, 0x1f7e5fea, 0xf740f8de, 0x86643de6, 0x81dc08fa, 0x14a782ac, 0x24f8f9b3, 0x514f4ad4, + 0xd1840b04, 0xb6f4da04, 0x9de16a45, 0xb97fc3f7, 0x56aef3d6, 0xf5792943, 0x42a17590, 0x73023ca0, 0x1698be00, + 0xd5d5cb26, 0xb9a85e97, 0xad0b2192, 0xf4fb8af4, 0xfcb17004, 0x4a951521, 0x0374d93f, 0x3ce6708a, 0xc45da953, + 0x184323ee, 0x7ed5e772, 0x62dc894d, 0x22102f6e, 0xf58baef8, 0x1014f7ab, 0x669a014d, 0x39df9cda, 0x746dbe8b, + 0x5d37bfe4, 0x4b9914a0, 0xf28b5903, 0xa4827536, 0xe5d30b67, 0xc515b974, 0xf8f9ce5e, 0xaa9b690e, 0xbf89e278, + 0x1ff9d7bf, 0xb6230e7c, 0xc1cf212a, 0x1d23208f, 0x45692f3b, 0x0ee4ee0d, 0xb9ed8db6, 0x78b7d528, 0x82150082, + 0x05cb9945, 0x9cc27ad3, 0xbc38931a, 0x50202e3a, 0xae40a2d1, 0x2b412a78, 0x34520c52, 0xcec7e3d5, 0x36a0b768, + 0xb6ce876b, 0x79ae981f, 0x4b00fa15, 0xf9ade47d, 0x5e5691f1, 0xa90f6459, 0x1d239e93, 0x2cad7019, 0x50801a82, + 0xdfdda553, 0x887b3f8a, 0xdaf5072b, 0xaf73453d, 0x51819988, 0x8ea01474, 0x5f50c34a, 0x81b21211, 0xc7c9e05f, + 0x8d64b00d, 0x8db219e0, 0xda54bc87, 0xc0be712e, 0x079837d4, 0x3de9193b, 0xea0d033b, 0x3b5d1773, 0xac5ec2d4, + 0x2a8e7282, 0x08566b38, 0x427d8052, 0x3e477158, 0x673dc359, 0xfb65dcf5, 0xccf34b9a, 0xf892b80f, 0xbb69746e, + 0xe93ff22e, 0xda125c47, 0x75e205eb, 0x5151566f, 0xc1814d45, 0xa1321427, 0x1c884c8d, 0x334c7fe2, 0x51cedd12, + 0xfcf8e36b, 0x611c03a1, 0x9fefe622, 0x5a2b6fb2, 0x3a2c9370, 0x0b885b13, 0x9e747ceb, 0x294cd689, 0x06da6034, + 0xaf501fef, 0xc0cfcb40, 0x6d2c8eff, 0x8b17aee0, 0xe92ef9b9, 0xf3c556d5, 0x60bec5dd, 0xce1f6bff, 0xbd2c3cc6, + 0x5ff9155c, 0x463ba0f5, 0x98883125, 0xed1438e7, 0x77280bdd, 0x48d6426a, 0xa85f99f1, 0x97015c95, 0x73a2ff86, + 0x88f40bd7, 0x691bd1f9, 0x20bfb969, 0x3c7d8581, 0x077ed593, 0x1c0abe4a, 0x997910a8, 0x25257833, 0x0ce6bddb, + 0xbe7832e5, 0xc3502903, 0x97cfb7c2, 0xde4e18e5, 0x43230c31, 0xc10e03b6, 0xf452ead0, 0x0b66bc35, 0x3b0166f2, + 0xd4970329, 0x223f5dcb, 0x3b364a86, 0xbee2e6dd, 0xf5a4a774, 0x08614b7c, 0x5b06f82a, 0x207e7298, 0x5c9ef838, + 0x2ccf8cbd, 0xa5bee34f, 0xac160192, 0x7e3553c4, 0xbafdbdfe, 0x9777731f, 0x0a16b9b0, 0x26830221, 0xf60f1a72, + 0x817f5779, 0x07ed09f3, 0x30e4613c, 0x8e8823df, 0x11e27b48, 0x7f8d4cb5, 0xdd02cd14, 0x8dfed44d, 0x5770e0a6, + 0xac102456, 0xc57de03f, 0xddb0a2a3, 0xbbaedcbf, 0x74a05927, 0x0588550f, 0x0522b447, 0xf25604de, 0x1ea401cc, + 0x3f87f220, 0xb1880029, 0xf3d2b452, 0x6b919173, 0x211a36dc, 0xbe0a477e, 0x6421823b, 0xc3de7d9b, 0xabafe647, + 0xdb580d02, 0xfbdfa15e, 0xbfe6c659, 0x05682bd0, 0x64f82cc3, 0x66d8db77, 0xdc606a2d, 0xf6bbe844, 0xa87a47c3, + 0x3ec1462a, 0xee2124e0, 0x2b0fc668, 0x0adcedb6, 0x71dd9ec3, 0x7060da06, 0xe775bf8f, 0x69b79e95, 0xe2061369, + 0xd5834c40, 0x435ec7a3, 0x985e7d1b, 0x596de22c, 0x675a5132, 0x6d258414, 0x43623535, 0x93fe3bcd, 0x9afc4441, + 0xfc65ec15, 0x6944d389, 0x87732959, 0xcc5c221f, 0x6ef46cf8, 0x75a3ea7f, 0x3f3e15d4, 0x204ce033, 0xb6c530d0, + 0x1e6e1c5e, 0x2a26002e, 0x800d1d31, 0x41e0f53f, 0xdf69caac, 0xaa9697ba, 0xf08e71fa, 0xfafee15c, 0xec728b81, + 0x14217903, 0x07d56fdf, 0x972b25b0, 0x57083559, 0xc8161d10, 0xf9b7e53b, 0x5f2158aa, 0x4e7cdee9, 0x3daae032, + 0x8dfd8841, 0xe89fa108, 0xba79afdc, 0xb33c2f91, 0x306f07df, 0x0346ad55, 0xd1220d08, 0x3e0e098e, 0x3315c8de, + 0x6a6429e6, 0xa905d7bb, 0x46001de4, 0x0db78f9f, 0x5526beae, 0x673b838b, 0x5e1d1efd, 0x754cb92c, 0x18eb2ccc, + 0x36bd8dc7, 0x29ad7210, 0x4d1b073a, 0xc12294fd, 0x6ce04c17, 0x3e973274, 0xfa3ec1d3, 0xf3f27407, 0xd63a2eaf, + 0x2c4563cf, 0x52ae2123, 0xa2aeec51, 0xa367b643, 0xa2e821f8, 0x3a8a74a9, 0x02086afb, 0xa6307fb3, 0x5a89a81f, + 0x237ddc35, 0x448281d8, 0xb7bea642, 0x95585210, 0x6b1fb745, 0x653e8d6c, 0xb84267ce, 0x20e60176, 0xda4db888, + 0xe1b02911, 0x93d94d09, 0x573df6dd, 0x85ecafef, 0xfc2194b1, 0x70820462, 0x11038eb6, 0x32071391, 0x57536500, + 0xf16e6dee, 0x219beedf, 0x7d19d78d, 0x60388cd5, 0x16055295, 0x223b5977, 0x826ddcb4, 0x7599a7d0, 0x7290943b, + 0x1f9176d0, 0xf2b1643d, 0x361cc1aa, 0xb4876405, 0xea176482, 0xbfd67e31, 0x909d5204, 0x394ff7a5, 0x46dd408f, + 0x9353fb2f, 0x46945c83, 0xa858f708, 0x2d579261, 0xa876be02, 0x0706a14d, 0x64c40dfc, 0x854f2613, 0x6fa690ad, + 0xb074a7fd, 0x7ae03b87, 0x7501149e, 0x2507098c, 0xfba56ba9, 0x93b1ef35, 0xad6db5ab, 0xf099538c, 0xb2a0a1c7, + 0x4fef6156, 0xb53a5287, 0x7d7db228, 0xb227c492, 0xe3986b0a, 0x58fcd152, 0x95eafce7, 0x9c6e1378, 0x657c579e, + 0x2867e894, 0xb0fe333d, 0x698e29b6, 0x2a6f08c9, 0x2c081447, 0xb3b92f83, 0x5b374a0e, 0x655b706f, 0x85204bb4, + 0x167c7416, 0x274cfee6, 0x2170ac71, 0x8ef3cf2c, 0x06754be7, 0x5121587c, 0x6efada29, 0x40e56aa5, 0x69ff14ff, + 0xeafa0293, 0x1557ea16, 0x7ace9119, 0x75b57afb, 0x422801e3, 0xb82e73ba, 0x4738e806, 0x88646ffc, 0x6cf68dd4, + 0x1ea7db63, 0x121746a4, 0x07d39250, 0xe338ecdb, 0x93ebca51, 0x94d6bd63, 0x724619db, 0xce93f542, 0x59f291df, + 0x7005a68b, 0xec1ff893, 0x9274bc29, 0xe998ca85, 0x512f6342, 0x20c1fed9, 0x9c2b3dea, 0x54f96ffa, 0x3de7b80d, + 0x59a2e0fc, 0xbcf5c22e, 0xfe0f2361, 0xe1678f99, 0xf509030a, 0x302c5cdc, 0x3d3320b9, 0x0aa97ed6, 0x181b8ffe, + 0x8dd0bc46, 0x8a19e2ff, 0xbd87c95e, 0x6d6c64da, 0x46984488, 0x8ebd1116, 0x588efaed, 0xfee2fa11, 0xc1f49212, + 0xe92f8dab, 0x76177337, 0x2909b9b9, 0xdc5c71cd, 0x8125a8b2, 0x8df778c8, 0x82094994, 0x4c0cbef8, 0x02a52ef8, + 0x2ca04d70, 0x06f5ce18, 0x170ef273, 0x275a9963, 0x171d1e84, 0x7d8bc82c, 0x0ecb086c, 0xa6d46701, 0x3b109e2e, + 0xba3a01eb, 0xc92814df, 0x0ab934b2, 0xe1278220, 0xe38d79cf, 0x57e15036, 0x2324177c, 0xccf0b14a, 0xfb74ce84, + 0x2d692ff1, 0x1c192ed2, 0x684c967d, 0x55ae6a3f, 0xd1845f83, 0xd4bfa565, 0x0fe8eaaa, 0x66df4637, 0x5974daa9, + 0xccb6f1f7, 0x02a2dba7, 0xa13886d2, 0x0918e7fd, 0xabb61a66, 0x8ca96f20, 0x67b4e942, 0xa8511d3e, 0x7e24167f, + 0x3220e767, 0xcb144212, 0x3a8327fb, 0xebb63bc3, 0xc5c2928e, 0x9be826b4, 0x35b290af, 0x7f1f3a43, 0xffbe7925, + 0x8d95d5c0, 0x30c5afc3, 0x8e4af6d2, 0xdde4a836, 0x6c537f4e, 0x0cb54d55, 0xc95963d0, 0x1865a5f9, 0xacfdd74f, + 0xceacad4c, 0xb3b4833c, 0x51cff451, 0x805fcc19, 0x22386054, 0x7cba3551, 0xbfcaeda9, 0x95a2862b, 0x0aa02497, + 0xe8ff3eca, 0xa4fedea1, 0x621d65c3, 0xef9a55a0, 0x93dd1e9f, 0xe2079985, 0xee4ebeb4, 0x1ef6fee1, 0x7329ecb1, + 0xa0151656, 0x947be739, 0x502d7561, 0xc5c1cbda, 0x9a5ec3b9, 0xe76a6b85, 0x00ad58cb, 0xf547485e, 0xc9484959, + 0xd4e23917, 0xc1fe736c, 0x4087d002, 0xae75bd66, 0xea3aa5d9, 0x1c7dc9ab, 0xd60d981a, 0xa40572b6, 0x4941e4ee, + 0x3a4bac74, 0x87c27bd5, 0x87ca90e0, 0xddfb28ac, 0x8fef2073, 0xdd64fc08, 0xc1dcadb0, 0x7f5ae6e6, 0x3e1d55da, + 0x9fefc815, 0xc9c789c3, 0x5eb14008, 0x75eb79d6, 0x4c586907, 0xe50ed87e, 0x6436e99a, 0x924a92e8, 0xd763b5a1, + 0x7f1f4194, 0x873b77f1, 0xbd077f58, 0xe48dc9ad, 0x2a54fc61, 0xfb83fb95, 0xb7723dcf, 0x805f9a03, 0xb1c860c5, + 0xcd19daee, 0x07225e7e, 0xc7bafa04, 0x436d1a46, 0x35897e0e, 0xf563d1ad, 0xc36c6f17, 0xe5a37ebe, 0x9b44d88d, + 0x3f59bdd5, 0xf066f7a6, 0xf9c73ce6, 0xe4433365, 0xd80b3a4b, 0xb8b91612, 0x8919bf3c, 0xd987c64e, 0x1bfb29de, + 0x1ac82539, 0x06def4c7, 0x01416778, 0xccacb7c5, 0x6a7a9b42, 0xc606243b, 0x3808e5e6, 0x4b4e010f, 0xd5495763, + 0x8f1fe02e, 0xd90b1348, 0xa1feee7c, 0x8cab3168, 0xb2856721, 0x8f5ccaae, 0x1353f1cf, 0xc59c5eae, 0xd1f4663b, + 0x6d2f6764, 0xbd7aca90, 0x4c6da3e4, 0x1416a7f3, 0x7986393e, 0x39d3ac2a, 0x7dc0b31f, 0xa5f0e036, 0x915dae47, + 0x2e8c3699, 0x2ef60db9, 0xab8bbf3d, 0x8e2eb7a7, 0xa99852e0, 0xcf92c3d5, 0x8a9414ce, 0x976236d4, 0x9081aefa, + 0xf5db12e4, 0xca2f8fc9, 0x75e41fd8, 0xe0f8f2d6, 0xe181e4c5, 0x69129d0e, 0x2ba86268, 0x75da0886, 0x586607f9, + 0x037294c8, 0xca62cb59, 0x74db30cf, 0x774d6f27, 0x9368c017, 0x716bc9fd, 0xaccbeb31, 0x4f5e646c, 0xbe5b6976, + 0x5531f0d6, 0x5e89c5f5, 0x1a90fe9d, 0x363bbf6b, 0xdae9fabd, 0xc46707ed, 0x0665ea11, 0x75036b3f, 0x8052b7ac, + 0x121c9964, 0x234fe8c0, 0x6f3be0ce, 0x751420a0, 0xadb89832, 0x72dd489d, 0x7ceb2ddc, 0xc2902a81, 0xbf72f461, + 0x5b904321, 0x09b55111, 0x5318aa8e, 0x6d0cae08, 0xaa0662de, 0x37963e5e, 0xee43840e, 0x49c75ec7, 0x74a539aa, + 0xde90827e, 0xda00d20f, 0x00fb81fe, 0xe5b684b8, 0xe25df245, 0x3e239ccb, 0xa132f7bc, 0x75efe729, 0x6c1ea49b, + 0xb8ceb0ce, 0xc2190058, 0x592734e3, 0x90787aad, 0x218fbaf2, 0xd49406dd, 0x6a1a2de3, 0x9cb9ea68, 0x20ec84ee, + 0xb4cf8f76, 0x0009dba9, 0xdd07fcd3, 0x6bba8b11, 0x3d12b117, 0x265ca25a, 0xc04ab5e7, 0xc58a9b1e, 0x9d5309a0, + 0x2579f3fd, 0x0f8dc62f, 0xb5cdab4a, 0x372cef96, 0x0c04551f, 0xdd8cee3e, 0x92d2916d, 0x84c3b06f, 0x7caf6bc6, + 0xed5d4de3, 0xa10bf7b6, 0x08f7fb0a, 0x093b6359, 0xc527400b, 0x99cb1063, 0xf773e1f7, 0xc3825ee7, 0x9880e20d, + 0x153fe3b8, 0x04558be2, 0x23a0de41, 0x556b7ccb, 0x6bddd2a3, 0x39b34dd2, 0xa681d2c5, 0xcb188f8d, 0xc7036756, + 0x2b17ee1c, 0xd33920a4, 0x2b830245, 0x048448a8, 0xaad2f532, 0x3e97a577, 0xd4275151, 0x60a99a64, 0xaa747973, + 0x0173c07e, 0x9e57c50c, 0x71cf7bde, 0x619880eb, 0xf861aa96, 0xbc43e54b, 0x114ef2e9, 0xa775c346, 0xdbb428a3, + 0xdbd88606, 0xf41d945d, 0x078d7c39, 0x199fa9d9, 0x7008e63b, 0x182d0a60, 0xa77729c4, 0x8d56ea04, 0x09e51ee1, + 0x180139e5, 0x97f7696b, 0x3bc329cb, 0x8ba245f6, 0xb3e2da36, 0x20cc7c38, 0xa2493b09, 0x4c35fd7e, 0xfa7f90f2, + 0x0a54b674, 0x3134b643, 0x0d5434ec, 0xfcedcaa6, 0xf16681fd, 0xf7ce832c, 0x2ff48a82, 0xe5db1a5b, 0x569cc068, + 0x473aab77, 0x4a53d9f4, 0x70f20f0f, 0x02bc4293, 0x1c214be3, 0xa2d513c9, 0x8c71bb75, 0x635124b9, 0x1703ad89, + 0xab8538ed, 0x7179ce20, 0x524e69fe, 0x848e29fb, 0xe2fed139, 0x400c012d, 0x017702c2, 0x628064df, 0x2f6c328c, + 0xba4d10d9, 0x35adb791, 0xbea8f908, 0xf8745f09, 0x844cd422, 0x74a5a4d2, 0xe61f73d3, 0x9fcf054a, 0xc8ab4d7d, + 0x7b6dbe22, 0xea09e165, 0x5810687f, 0xc5fa4de2, 0x4837e09d, 0x64331076, 0x98b2157b, 0x602501a5, 0x010bfd9b, + 0x8148d3d7, 0xd4c33f59, 0xeaf95953, 0x96cb2c64, 0x0cedd8eb, 0x3304bc54, 0x042d385e, 0x204a4167, 0xf448aba2, + 0x54e30b2f, 0xd948f3bd, 0x06210b85, 0x45c4625c, 0x578a9b0d, 0x00a34f9b, 0xafcc74cc, 0x9ebd9528, 0x7f2ff9a9, + 0xcdb3e4d9, 0xe50f290f, 0xb75d97d7, 0xc48f84af, 0xd795b8b6, 0xfd9c4488, 0x168e02d2, 0x2806d4a8, 0xdff0cba0, + 0x55cd7a11, 0x3d88f47b, 0xe0762d84, 0x91c3ba45, 0x84c17c3c, 0xc8f4d457, 0x3ecfb0a5, 0x271f6f33, 0x5b6e141e, + 0xcea1dad8, 0xa091b7ff, 0x19fec777, 0x4c930ca8, 0x0ef63bae, 0x51d81b8d, 0xf4a0a92c, 0x0693d82d, 0x51e624bd, + 0x8245d768, 0x23ad7184, 0xa9e9a501, 0xa105a42d, 0x7f47700e, 0xe46edd37, 0x2a2116c8, 0x845db348, 0xec6bd8ac, + 0xf511978e, 0x19175a41, 0xbc6adb66, 0xc69b7841, 0x67ea1113, 0xee9ad50e, 0x3fb81bdf, 0x5668e71f, 0xce77b754, + 0x729d7708, 0x8625b608, 0xb8cac79e, 0xa57a9ac5, 0xbe591986, 0x85d7798c, 0xa71e0a74, 0xafdb3385, 0x8f7dfb53, + 0x4c51ac73, 0x01d6d1dd, 0x199e09ee, 0x03dc3d43, 0x14462138, 0x8c59a394, 0x5030ea86, 0xe7e5ea55, 0x98fa1bc7, + 0x45f5b9ad, 0x615c90a0, 0x804a3508, 0xd0e41c49, 0xe11c7529, 0x5a103cd0, 0x2391c340, 0x872357c0, 0x79c2fc91, + 0xb55f718f, 0xe58f9c7f, 0x9308b2e0, 0x3bb6f44e, 0x2c9dc1b3, 0x067e3fb9, 0x8e75649d, 0x2c5b8c96, 0x6a918f4d, + 0x893ce898, 0xea031849, 0x1a09fc3b, 0xd3df2fb2, 0x1e7755c5, 0x02430d59, 0xd3464371, 0xba52c29a, 0x29c2d50a, + 0x25c4094b, 0x9be4e0f1, 0xba9fb149, 0x920d4919, 0x8a1b42ac, 0xdc3befb4, 0xde18d30f, 0x3bd61953, 0x65c1db3d, + 0xf48475c0, 0xbc10c4b2, 0x5e03dd5c, 0xa86a3544, 0x77e99c8c, 0xe7704c8b, 0x82d8c9ec, 0x36b476de, 0xacd836db, + 0x1f4da2a7, 0x734560ca, 0x8e3f02e8, 0xc318b1c9, 0xb18a5b84, 0x0cf83e0c, 0xf4fd1fa9, 0xae2f7d6f, 0x36b84891, + 0x264316dc, 0x50dff802, 0x74417e01, 0xe8d1a659, 0x50cef327, 0x2f584749, 0xf7c77128, 0x9ff7a033, 0xa9edbb3a, + 0xdfb747fb, 0x3e261a91, 0x3176c12e, 0xcaa30d26, 0x4826ccb4, 0x61e0b1f3, 0xe9ee2965, 0xa3a76778, 0x222d762f, + 0xa9e7a128, 0xf94f1824, 0x093b78b4, 0xbc762ded, 0x3382b6b7, 0xff146182, 0xd2f03bb0, 0x9270753a, 0x43ef9e6f, + 0xdb5272d7, 0x72e6b8c5, 0x6bb80fe1, 0x01d0a3bf, 0x5ad6d8c2, 0xf14e5607, 0xd8353002, 0x437d26e6, 0x2271eb76, + 0x142d6b0c, 0x4123df52, 0xf1b95cfb, 0x66ca735b, 0x903c7f52, 0x5b13fac6, 0xb27eb138, 0xf22a506a, 0x88984f65, + 0xd02992d7, 0x671deab5, 0x335a58e1, 0x21394912, 0x0107971e, 0x3bbb8268, 0x471ba396, 0x153255b1, 0x5b80f465, + 0xe6cdf0a1, 0x4c7594f8, 0xe72164dc, 0xae7590b5, 0xe639e2b3, 0x50908d75, 0xd5a6660a, 0x50e51e27, 0xb06f6ca7, + 0x80c4d9e4, 0xdc76c68f, 0xbfca889f, 0x2f1b3aa9, 0x55ba06c9, 0x659a0e55, 0x070a22fd, 0x4f43f02c, 0xe4eb384e, + 0x42ce0926, 0x1a6989fc, 0x54ddb0e4, 0x7aae485b, 0xa20eaa21, 0x9cb04957, 0xbb11b32d, 0x68ca6947, 0x6a374937, + 0x8480165d, 0xabe3e8df, 0x06d0ae47, 0x6190a9cc, 0x4d15bd06, 0xa8d814b0, 0xe23e8f28, 0x7c592ec6, 0x781b276e, + 0x480c1076, 0x2d851bf2, 0x7b3178ae, 0x8a44613a, 0x561e915e, 0x18f14221, 0x07df91b1, 0x0b9bdb19, 0x2f88512e, + 0x61a772ec, 0x3ef2c1ca, 0xcab02181, 0x6dcf6a5e, 0xab929857, 0x1fcb1636, 0xd86c57c3, 0x2a50bd5e, 0xd8830364, + 0x2c61ad47, 0x8ba614bf, 0x6430ae2e, 0xe8916726, 0xf8193f3e, 0x070d326e, 0x232cb965, 0x6e431ba7, 0xfefe1813, + 0x3e1c450b, 0xdf0f1c2b, 0xf165cae9, 0x6e3c1f8b, 0x82f85b20, 0x2e7071db, 0x9db4e729, 0x41c63120, 0x75300c0f, + 0x24beef9a, 0xf4df8664, 0xf2e7b2a0, 0xf2c05bec, 0xf451097c, 0x6b9cc73c, 0x508270d7, 0x7cc92e31, 0x0dafeb3f, + 0x592c9d26, 0xccad438b, 0x1d0f0fa7, 0x0a59abdc, 0x34ad6973, 0x1fef216e, 0xdb2ea632, 0xb359f1fe, 0x48587230, + 0x12963ecf, 0x427fdc17, 0x7d99c9f4, 0x3a40c831, 0xd5271d73, 0xa6c5f63e, 0x2ee5c7e4, 0x53712d3f, 0x531b634e, + 0x1c62ec23, 0x88d6a9d2, 0xebb93d32, 0x098f4712, 0xabea268e, 0x3812f131, 0x67674631, 0xf7c2ae16, 0xadaafbc5, + 0x0ece1c0c, 0x14d759a0, 0xd1370029, 0x31f49d61, 0x6d01d415, 0x3986a989, 0x61e8dafc, 0x8c7d6062, 0xd1ff91e8, + 0x9e23857f, 0x7afad917, 0x098b989e, 0x89169032, 0x6a469ff9, 0x4e736440, 0x8fffebd6, 0x482551c3, 0xe5c5560c, + 0x8acb26ef, 0xe0768c74, 0x4392fc7e, 0xc649f277, 0x3fe66ea6, 0x4f738fb3, 0xd1daa7ad, 0x76d65a0d, 0x87cc141a, + 0x8cf5b55e, 0x638bf5aa, 0xeab55c04, 0x9ca73398, 0x35938260, 0x346554b3, 0x4cea910e, 0x543df59d, 0x790dbbfc, + 0xa9be177e, 0xf9ef03ec, 0xc54fa3c7, 0x4be565a7, 0x13ca46c9, 0xccc6f54b, 0xb9f3f56c, 0xb2d9129b, 0x7837ce1c, + 0x50cdda8f, 0xd7abcc9b, 0xc916f178, 0x3db67a4a, 0xa75c9d98, 0x199d064d, 0x1f8d36d6, 0xe4c663e5, 0x8e91ce27, + 0xc665fdde, 0x129a0ff5, 0x22a0c77f, 0x596e83b5, 0x91885b78, 0x35d8c799, 0xd174bc17, 0x48a35059, 0xfbf175d7, + 0x4e13d1a3, 0x3ab25093, 0x2e067506, 0xbd3f7a20, 0x9d715b8e, 0x409f4ed6, 0x8ede4359, 0x83d0b80e, 0x7878ed3c, + 0x65f66ecc, 0x32180375, 0x6b669381, 0x69018494, 0x1a0d6099, 0xe86b0cb8, 0xfaa23c90, 0x5a706865, 0x13064af8, + 0x70d74142, 0x495ed076, 0x828fec7d, 0xe60138fa, 0xfa7279b5, 0xd4e64634, 0xaff5c572, 0xa7b97ea9, 0x516d718c, + 0x2c9e0edb, 0x5b1aef63, 0xe28aa9a7, 0xd9192338, 0xbbdce245, 0x9a048186, 0x1478a4b7, 0x0d7cf47c, 0x3271485a, + 0xc261b03a, 0x41484ce2, 0x822955c6, 0xe1d3eada, 0x68e6f91e, 0xbbee32cc, 0xd85148f0, 0xfc822609, 0x5c3dbc63, + 0x207d8e90, 0xff149542, 0xfd569b22, 0x43a9f7ef, 0x760c840a, 0x970ceb1f, 0x67289cae, 0x3ab487f7, 0x6617a4b4, + 0x51f42732, 0x64439df9, 0x580ab086, 0xe1b400a0, 0xb794a3d4, 0xccd22d27, 0x8b8311b8, 0xed25c3aa, 0xdefcf42b, + 0xb1806345, 0x3ce3fbf9, 0x88d08bf2, 0xa4400c37, 0xcb40fa8b, 0x7a36ed5e, 0x4f16b9e8, 0x55343dbd, 0xc596a1ca, + 0x0404d48d, 0x28d7740f, 0x0e9645cb, 0x06a58b94, 0x34ac269d, 0xb1f892e5, 0x37ccd273, 0x63c69e33, 0xc579a0b0, + 0xb7053623, 0x998b9f95, 0x0570e8b7, 0x456afe20, 0x74151a3f, 0x9f4fc70c, 0x064a464f, 0x5aaed55f, 0xbb9f3380, + 0x92666dea, 0x73deda36, 0x09078e98, 0x0202fe80, 0xae61faeb, 0x10b991c2, 0x35bb27d6, 0xf23c8d83, 0x76d8e984, + 0x360aba28, 0x50d65e85, 0xbac0aa8e, 0x8f0c8d83, 0xcdd5a278, 0xb609fd48, 0x50e1cbfb, 0xca2da4d4, 0xc5e4b7a2, + 0xa3a53ffe, 0x8bb970f5, 0x198c5abd, 0x233bc1ac, 0xd6e0d35b, 0x12105e9e, 0xf25dcce9, 0x31080139, 0x6d1b841e, + 0x16b159df, 0xfaea32fa, 0x396bb58d, 0xcfabe2ab, 0xb8a28f1e, 0x184094b1, 0xf50e210d, 0x38288955, 0x087c07ae, + 0x2d267f32, 0x2f1779a6, 0xd86558d0, 0xdc031a5b, 0x6cb6ffe4, 0xf664b4a3, 0xae77a0f6, 0x91a0f433, 0x42d8d174, + 0x3153a23c, 0x62ff02a2, 0x8747b1c4, 0xa73b756b, 0xeade467d, 0x5dae3021, 0x1d1e22a2, 0xcdda7ba1, 0xc021cc4d, + 0x34f9f619, 0xc8989663, 0x4359aabe, 0x8dc24f3d, 0x1eef02c1, 0xc46862ca, 0x5cac36ca, 0x40328280, 0xb74dd355, + 0x99269846, 0x475f4b13, 0x2b8d7188, 0x70cf98a4, 0x7ee8bfba, 0xaddf742f, 0xf11b7bfb, 0x0fc449cd, 0xc4ff222a, + 0x6dfefbdd, 0x9963c903, 0x7330aadf, 0xedc293d4, 0xae3f9605, 0x5a2396ef, 0x02138645, 0x58ddec9a, 0x127d47c0, + 0x3e6cbd4a, 0x68cc0965, 0x2ec485ba, 0x26f5c276, 0x365a0087, 0x62075095, 0x3128b8f4, 0xa9fff307, 0x2f45b1b8, + 0x6154ad72, 0xc3fd24e9, 0x7e8bb75e, 0x72111e21, 0xd0510ecb, 0xba2877a8, 0x959c7619, 0x3f6b54b2, 0xe140b0a3, + 0x085664fd, 0xbfd9deb0, 0x0229487f, 0x6f864c12, 0x5dd99dcb, 0xd8a15b33, 0xd877e6c0, 0x3143e4d4, 0xad76f668, + 0x8befbd16, 0x5f6f07ce, 0xa4da8da0, 0xddfa65fa, 0x33484186, 0x8473198b, 0xdd56b7c0, 0xa8ad1e94, 0xb6bd9ef6, + 0x0d54bc86, 0xbcbf8758, 0x7b691490, 0x53423526, 0x4a2e877c, 0x5649adf3, 0x93667b21, 0xa0abb82f, 0xf351d102, + 0x7352d03f, 0xce9c8b46, 0x9e384068, 0xa1d84bc4, 0x6bbd367f, 0xd65a201d, 0x7fb0fd5a, 0x273600f0, 0xe76cf403, + 0xc3431446, 0x3c9210d7, 0x42d77735, 0x572325cc, 0xd6b3748a, 0x9e49567c, 0x14415627, 0xd6f1b9ac, 0x2461e3a5, + 0xd20ce0e4, 0x63681ba0, 0x5c7ee139, 0xb7fe9929, 0x3b15bbc0, 0x5bfcff1b, 0xf493480f, 0x523f8ef0, 0x19c73a6f, + 0x52cad2e0, 0x36ff753e, 0xb8df6972, 0xbb827e75, 0x7dcda4fb, 0xb1ab0a70, 0x80da24da, 0x3fc7ff72, 0xb79dae9f, + 0x49ea8e48, 0xbea4032d, 0xf99aa8eb, 0x9bf18fbb, 0xc8846dd8, 0x6aab5a7e, 0xd3949569, 0x1b379776, 0x285e8bc3, + 0xa02302a4, 0x8231994e, 0x02bcc3f2, 0x14295a9d, 0x5d3745ae, 0x9686326a, 0xbe41ce04, 0x619ef3d1, 0x0db11563, + 0xcb7d815d, 0xfc25a6b8, 0x403c5958, 0x79779085, 0xc03585e9, 0x02b9c62c, 0x2ac520b7, 0x5d458277, 0x1cc76318, + 0x02fdfac2, 0x663f5466, 0xe39df46c, 0x70362970, 0x429af7ad, 0xf38e968f, 0xc2d47d1a, 0x862ccc1b, 0xe7fb3522, + 0x1625d97b, 0xfd9015f4, 0x2d59225a, 0x4df6884e, 0x323f8f14, 0xc57560b1, 0x746862f3, 0x1930b0cf, 0x0f55d58a, + 0x6a716fee, 0xead41553, 0x34b5537a, 0x1000b52c, 0xc6e49f9e, 0xbb3d212f, 0x9e3b3d0f, 0xaa58c1c5, 0x1f911b0c, + 0x8e0898c8, 0x1b985c13, 0xe220a2bb, 0x463c444f, 0x3cbb2c6d, 0x5ead1df9, 0xabf0bd19, 0xe51aef71, 0x716320eb, + 0x843bdad4, 0x197fe494, 0x5c320488, 0x6a4a2e23, 0x085f8b76, 0xa46a2c37, 0xf08c3818, 0x6be672e0, 0x1121a355, + 0xee67ed45, 0xa82a58b1, 0x6ef1ea7e, 0xa45aa468, 0xf8b0dc78, 0x3a07f7d9, 0x014951e9, 0x9863b2b5, 0x3fb02cec, + 0xb223c37f, 0x63e9fa7e, 0x2c1206c5, 0x19c4ea1e, 0xe288c597, 0x79075f7b, 0x079de3b0, 0x9002f94c, 0x8b91531e, + 0xceed27c7, 0xf07be3f8, 0x6e4a4c06, 0x145ce37b, 0x50d125b5, 0xd261efa5, 0xb406b985, 0xd7c11a74, 0x6d430ee2, + 0xf50f35b2, 0x9000b1ab, 0x5a43469d, 0xdec7f5da, 0x03c74275, 0x5207d893, 0xbd8cce43, 0xa6d0a409, 0xbac97b21, + 0x87531dec, 0xdd96fae4, 0x585b5a3e, 0x712b21dd, 0xaf2aeaf4, 0x7af579cd, 0xca0f1d3a, 0x3ead36fe, 0x7807d2b8, + 0x3bf03765, 0xaa41dd9d, 0x274be309, 0xed40968e, 0xbdd8ddb2, 0x3d5d3fd1, 0xa7ebb031, 0xa525fe66, 0x42ca0c8f, + 0xbdcdd85e, 0xe90eafe6, 0x1ad503f6, 0x8560961e, 0x6f8524fd, 0x42dc9cdd, 0xbbd4cd64, 0x9faf5adf, 0xfa761695, + 0x27e2b7ec, 0xc09c11d2, 0x7e1adff2, 0xb285eb9a, 0x1241d653, 0xb906506a, 0x22e8669c, 0xcee78e37, 0xdb9894b1, + 0xa4e2873b, 0xb665aa28, 0x8425879c, 0x4d3af3e2, 0x12ef87be, 0x24db3917, 0x443d91a0, 0x1595a5d9, 0x6d6f7c8f, + 0x1c5c7a1e, 0xffbbebb9, 0xcf5324c7, 0x0de06fb3, 0xc42d35b6, 0xd3d15f6e, 0x0f48be40, 0x5ddd0d17, 0x03cbbd06, + 0x77e02296, 0xa104cc1c, 0x88f72843, 0xe0a43325, 0x5c9ea29a, 0xd992f01b, 0x3d7a68fe, 0xee6335d2, 0xff669820, + 0x0ec1f7ef, 0xe1653614, 0x97e59245, 0x3f699098, 0x3ea36ae3, 0x174cbee0, 0x0a3f4456, 0x42e3a24c, 0xdb6890cf, + 0x38df5a48, 0xf36ae76e, 0x626bd6bf, 0xa7edcd22, 0x492bea8c, 0x82032e02, 0x6d4e9662, 0xcd912a01, 0x3d2abcb7, + 0x17f20ab4, 0xaa6c3839, 0x18698bdb, 0x6be652bc, 0x0c95d693, 0xa8540f2c, 0x6d99bb63, 0x35d0315d, 0x6c6b1e4d, + 0x947580a6, 0xf7f02632, 0x4d974208, 0x7ae0b8a1, 0x94187864, 0xec13b63b, 0x4892453b, 0x14961faf, 0xd3c9747b, + 0xc2787d55, 0x3818999f, 0x8b0cfeb0, 0xda654e86, 0xd2cece5c, 0x2166c450, 0x9b69d37c, 0x5c78a0ce, 0x0596460c, + 0x95a962b9, 0x05c1e36f, 0xff28ce41, 0x75196cc7, 0x85271c29, 0x04b2f86d, 0x75ea1b8d, 0xd3dec09e, 0x90e527ab, + 0x7de1e150, 0x51afc983, 0x9df93473, 0x2755f05c, 0xe4e67b57, 0x5f92ce43, 0x35989183, 0xfe86329f, 0x26e82201, + 0x6c23099c, 0x5d997dce, 0xa745cdbe, 0x336251a5, 0xe3fb50b3, 0x78bc5fec, 0x197a96f7, 0xaa99b03f, 0xd739f9d2, + 0x798050f4, 0x04cf2017, 0xb3031854, 0xdd982af6, 0x72ca6134, 0x34afe489, 0x97372e1b, 0x94f27389, 0x1b1c932f, + 0x792e22af, 0x34861ed6, 0xea01d2aa, 0x28cadfca, 0xcb7318e2, 0x784363c9, 0x03616a4e, 0x99fca7f1, 0xdef0d714, + 0x21eb13a0, 0xaa200a08, 0x0cf84991, 0x3c33ff98, 0xe7420a10, 0x1db21f15, 0xe3409213, 0x4567d84b, 0x954d7f79, + 0x3baa45e0, 0xff39e978, 0x546bef87, 0x47222c1e, 0xb6b18691, 0x4a3d9d3c, 0xae99c388, 0xa1fa2247, 0xef001f16, + 0x0073324b, 0xf5a4b848, 0x83b11454, 0x8c66407c, 0x859bf591, 0x9be428af, 0x48d50e64, 0xeb5c321f, 0xd9880d21, + 0x5006c139, 0x2364e9af, 0xbeb82966, 0x60ce2348, 0xe5174001, 0xdcf18d2e, 0xc3de7642, 0x4d7eae1b, 0xa4e1ed6f, + 0x714eb484, 0x6453df80, 0xfa4694b7, 0xdb6db9af, 0x4ba83721, 0x2f2e0433, 0x01c637c7, 0x5e95dc70, 0x7e28eab3, + 0xc779ee5e, 0x525d19db, 0xcee0a599, 0xe3cac0d0, 0xc30e002f, 0xbbb6df7e, 0x3b022601, 0xd0393b91, 0xb0dc5ad5, + 0x70c9e47a, 0x6f8af46a, 0x370e75ee, 0x31cd15c2, 0x2d23eee4, 0x253f9a66, 0x7657a099, 0x9db3058d, 0x03964718, + 0x51acfe20, 0x751da3ac, 0xd17ba274, 0xa1af833b, 0x91dee72d, 0x72294d7b, 0x091096a9, 0x2da379a3, 0xbb0f9f55, + 0x9fe6fcd2, 0xe36417ac, 0x9a9231a4, 0xf9f0b060, 0x26974d71, 0x1e386a9b, 0x8351cd28, 0xb13e397e, 0xb1e614fe, + 0xe17f0bf4, 0x7f952233, 0x9c79d7d5, 0x8603fbd8, 0xba625b06, 0x9f7ef568, 0x4f6e6a15, 0x874e8f4d, 0xf2d17ccd, + 0xe4c8309d, 0xff5d4671, 0xfe093ba6, 0x47da03ea, 0x419fa1c1, 0xdf63151d, 0x7409b789, 0x2c3467dc, 0xa54a1909, + 0x59558b32, 0xfd5545c3, 0xae5c519b, 0x75adb12c, 0x0f4f3ae0, 0x2d5224ca, 0x99c8278b, 0xeb249c4e, 0x883ea6b0, + 0x89da0324, 0xc3359c27, 0x089ee7a4, 0x5f10302e, 0xaa9e77ec, 0xd7afb510, 0x1cf644cd, 0x38cc3ffe, 0xc9cf2bb5, + 0x4c0730d2, 0x3346ca73, 0x19789923, 0x16300db0, 0x9fd79b25, 0x13a10746, 0x08266082, 0x79f37bc9, 0x5143e861, + 0xb41e8cca, 0x3a227efd, 0xf41ff15b, 0x7c8733db, 0x18400ee3, 0x190f8ca8, 0x77baba41, 0xc54ba192, 0xfbff4b8d, + 0x986bfa9d, 0x70440ef4, 0xdb3cfd26, 0x18d3bb07, 0x883e40a7, 0x363204e3, 0x2585d3ac, 0x8726d6ee, 0xb1428b70, + 0x2a76b269, 0xb5ad4231, 0xbcfbaf92, 0x4acdc170, 0x61988dfb, 0xa4567273, 0xe8156b8e, 0xa0a43bc8, 0x7e7e2044, + 0x8943d52d, 0x5d81e9f8, 0x3bdbf23f, 0xaa7f7f8e, 0x83684cd5, 0x9ec00ed1, 0xd40836a7, 0x25e284ad, 0x1b8e3a4c, + 0x972db13e, 0x03edbf79, 0x20bed16a, 0xe4acd426, 0x51debc26, 0xa2a724e2, 0x8b3fe069, 0xd9566b77, 0xf0f5cb1c, + 0x61d31d3f, 0x2f98c737, 0x414b4af1, 0x497ecc02, 0x33f161b5, 0x363e717b, 0xa33c4b4b, 0x0766b269, 0x2906ae2c, + 0x16e9633f, 0xe2872b3f, 0xad403008, 0xbd93b33f, 0xfc7ad0f6, 0x4a890c96, 0x6b77c2bd, 0x6c548ebe, 0x2a1a07fe, + 0x31d3042a, 0x83e9dc8b, 0x8a39007f, 0x2f75c758, 0x5a1b1e43, 0xa5af0383, 0x46c880b4, 0x173d8fbf, 0x28ed5f64, + 0x8c8702ba, 0x41b82251, 0xb79a0ad2, 0x92a406fa, 0xa57917ac, 0x9cd6f007, 0x75480eb6, 0x3f1f0bde, 0x9848ec21, + 0xc3cecbd9, 0x296437c7, 0x535165ff, 0x0b718069, 0x29c0c233, 0x57bb42ad, 0x6f20fbf0, 0x79a990d5, 0xe180c3b1, + 0x7abf3081, 0xf6e18f82, 0x898dcb89, 0x0b5d2582, 0xcb2f1dea, 0x021bec9a, 0xd722dcd0, 0xe9f58681, 0xef43aec1, + 0x464d5315, 0x966da4f9, 0xb9553213, 0xc76bdb4c, 0xae6b05d1, 0xc35cb468, 0x71dda059, 0x1a42cfb6, 0x357aea5b, + 0x094e29a5, 0x858e3033, 0x847a6ae2, 0xa11bb259, 0xf7ebb5f7, 0xa06305a2, 0xd71e4263, 0x957990d7, 0xd7743836, + 0x3a821501, 0xc629dc67, 0x9438aec2, 0xa9b19a08, 0xf47b9e4c, 0x378794cf, 0x91ca3b01, 0x6b1a9cac, 0xc87a8d5b, + 0x569fcdab, 0xf82bd0b6, 0xa0284a71, 0x161aba2b, 0xabb57c97, 0xabc0d8ac, 0xf19462c6, 0x374b91f7, 0xa7acf640, + 0xa2846159, 0xa91078d5, 0x8ca623f6, 0xf7bd1505, 0xfc0cd167, 0xaa295bed, 0x46ed0025, 0x83cfc293, 0x92385483, + 0x965f4c36, 0x9c80a248, 0x6ed21926, 0xc206cd60, 0x5448c26f, 0x3c23f278, 0x2fd2c34e, 0xc95de002, 0xe5e9b80b, + 0xf5c7eceb, 0xed3ac789, 0x0c4534c4, 0x2adfb28a, 0x07056592, 0x69fe719f, 0x5af0cd84, 0x059ef321, 0x545b12a3, + 0xb97815a8, 0x4b1ab174, 0x689c8c75, 0x85510ad2, 0xdddc9ce7, 0xdf4222bf, 0xe3be1e9d, 0xae5dd197, 0x5fcdfc76, + 0xd7d9a201, 0x78c31c44, 0x8d969913, 0xa359e54a, 0x9e445438, 0x7d702b29, 0x03a920e3, 0x7b606322, 0x76fdfe09, + 0x6412b221, 0x7cbabb44, 0x2494068e, 0x34b23a3d, 0x586a1a8e, 0x26a165f9, 0x384e88a7, 0xc3e6c8ba, 0x3fbc644c, + 0xc024051e, 0xf4e45cf1, 0x170cf97f, 0x68aa87ae, 0x8201e95d, 0x51b4f7bc, 0x6a4436a9, 0x892af28f, 0xe79d9ecb, + 0x6822fb7c, 0x58f7d087, 0x356c02de, 0xa574bf31, 0x61e37cb4, 0xbe9ef947, 0x91d0346e, 0xecff3e78, 0x1d3f9cfe, + 0x834c45a2, 0xeaf29046, 0x294c7bb5, 0xde717fa3, 0xd89b056f, 0x32cc33f5, 0x0f1f49a6, 0x1ed408bc, 0x33615004, + 0x459e45f9, 0xec43ead2, 0xc1698f8c, 0x15dfb8b7, 0x4cc7eafc, 0x05867a97, 0x74793862, 0xbf3d814d, 0x23fda2f5, + 0x9862df7f, 0x3362f85d, 0x55b6d5c2, 0xdd6c993b, 0x884b9a08, 0x421fdb3a, 0x98f6cbe5, 0x8194a006, 0xbc9eb9ff, + 0x061dc117, 0xb3cdeea1, 0x1d9b9fe1, 0x775d1e0a, 0x9d53fdee, 0xf1c6633b, 0x84934543, 0x10dfd5ad, 0xd5c46a24, + 0x3c02da08, 0x331b1d46, 0x5166997a, 0x65cfb03a, 0xcd17e9d8, 0x60fc1788, 0x8b69b08c, 0xb52fac14, 0x88ee16bd, + 0x58943d7c, 0xd52297c2, 0x61de5a3c, 0x195ced83, 0x7bb68d8d, 0xe3ae71be, 0x786ffc68, 0x0bac6897, 0x1022dedc, + 0xeaf1c0e8, 0xc0e61584, 0x19d6419b, 0xe4f98d0e, 0x640fa1a4, 0x2d53ec0b, 0xffc7fe25, 0x4c962988, 0x0bdf46d5, + 0x60120882, 0xda393730, 0xa1d99f0b, 0x00d1342f, 0xa88fb93d, 0xe45874a8, 0x6c6e05b0, 0x07abd5aa, 0xe2d7fd3a, + 0x563860a2, 0xc48a844d, 0x060be40b, 0x9c95b025, 0xfb37ea29, 0x9c9707e2, 0x8be49eb3, 0x91777a95, 0x2d822e56, + 0x7661a101, 0x7f7fd9eb, 0xbf7759d3, 0x9b5c7982, 0x3b6c7492, 0x5723c959, 0xa69fd830, 0xb9edcfa4, 0x3550e327, + 0x9427f0ac, 0x3e45bcea, 0x68907b2b, 0x7cd53364, 0xa31effac, 0xaf4ea9c4, 0x371e1b5c, 0x9602efab, 0x0af08cb2, + 0x8cb10211, 0x391085d7, 0xea60e637, 0x1ced4032, 0x9a347a6a, 0xd258746a, 0x6e649ca0, 0xbbb3bf04, 0x14d9ec57, + 0x6abfa159, 0xa9310416, 0x3a8b8c08, 0x30eee7c3, 0xb137185d, 0xc4252c43, 0xe5b2b56f, 0x3a5dafab, 0x3be8f4f2, + 0x8ee40db2, 0xaa3025e7, 0x84c95201, 0x4a5f63d6, 0x769a82ac, 0x4230a972, 0xb0aed94a, 0xbb9bfcf4, 0x58bb46c9, + 0x9e80cc9e, 0x5d55a760, 0x2c7f135c, 0x68765c50, 0xf707a14f, 0xc583805b, 0x8a7a9e59, 0x48f89d60, 0xb64221ff, + 0xf0e1c723, 0xf4409d8b, 0x8d7c8e58, 0x0e7c1112, 0xbecace9e, 0x568994d2, 0xf6c230e0, 0x3e287b06, 0xba3d6b8e, + 0x46bf475f, 0x34a88458, 0x48cf899d, 0x55af6297, 0xc4bb880c, 0xdae40acc, 0xd64c5fba, 0x366dfb9e, 0x495a1eb4, + 0x283937d0, 0x98033ad1, 0x5da6b71c, 0xb949e92e, 0xa7971eb7, 0xfc90eb82, 0x2440eb5e, 0x0f389c36, 0x331024f6, + 0x67539238, 0x2457bd1f, 0x0368eb59, 0xb914266e, 0x1b809f1a, 0xe1784b6c, 0x86a3ecef, 0xa65255de, 0xc28261f1, + 0x1e8e2c6a, 0x630d832a, 0x1050320b, 0xf82cef72, 0x16d64c16, 0xb92bedde, 0xa323885e, 0x3e6cdf8a, 0x0cc63d4c, + 0x36b4f3ea, 0x5198e4c4, 0xcf209e49, 0xb9aa4690, 0xcb93db0d, 0x13573857, 0x84df1298, 0xfe40f075, 0x4aa36bc6, + 0x6fa83ab2, 0xa4d63175, 0xb1da7d51, 0xe0d0bf83, 0xfadb62ae, 0x99606687, 0x0adb785d, 0x09bb9ad3, 0xc62316e5, + 0x4a714562, 0x906d5971, 0x93bfe520, 0xe9114636, 0xe7c0948a, 0x2ed0cf93, 0xe2128214, 0xad46d449, 0x5c10a8d9, + 0x34ce933e, 0x8ef4b5a8, 0xcbde69ab, 0xe723a976, 0xf72cce18, 0x8965a822, 0x5d188dd7, 0x43c185e6, 0xf72609ee, + 0x21b0e9ca, 0x02726468, 0xdf6acb93, 0x4e5f3f76, 0x3a8b43df, 0x7da18a59, 0x17b2851e, 0xdfe02a57, 0xe70e58b6, + 0x7806fc3a, 0x2cf6735b, 0x3c66236a, 0x8d3de952, 0x3675249c, 0x6fb31fec, 0x729293b0, 0xf5329198, 0x0e7869f1, + 0xbd6f6960, 0xe739b347, 0x18d07e8d, 0x3395d101, 0x45bbb343, 0x00e153e9, 0x83b07ac9, 0x48880f73, 0x210f5dcd, + 0x0a37a6d7, 0xcde2662b, 0x31a064f4, 0x3ee58aca, 0x7001073c, 0x2e213d46, 0x3ad5a0f0, 0x8437e424, 0xef66a1e2, + 0x77df7b45, 0x1f7e1048, 0x503df9b5, 0xd4156a6e, 0x7a2dbb7c, 0x1c9e4ba4, 0x567fc1ec, 0x301b5308, 0xb6bc1ff0, + 0x11ede7c8, 0x9689cf29, 0xca78b667, 0x1ca3f830, 0xb212f760, 0x6e01d157, 0xb044331b, 0xd180f856, 0xaa618056, + 0x12cfcdfa, 0x7bde9e54, 0x5100b961, 0x20617e2b, 0x282ca469, 0x04dc2103, 0x6c5cec5b, 0xc6795b49, 0xe5a04614, + 0xefc5058d, 0xad24c988, 0x099f0abe, 0xf04be7c5, 0x303088e2, 0x31e2c49f, 0x9de14bcd, 0xea916360, 0xb2a7736c, + 0x8ec4ce54, 0x9cc6ac41, 0x0b0248bb, 0x71930ff3, 0x82605010, 0x13251592, 0x808a9725, 0xdc82c2e5, 0xc936d980, + 0xbd977593, 0x3d4c8991, 0xaec24635, 0x4b714f53, 0x3d603d06, 0x429916db, 0x981657aa, 0x2d5e1761, 0x25328fc6, + 0x5d911e61, 0x9d1eebb5, 0x091c3939, 0x538a6d04, 0x4a835b81, 0x566a0f01, 0x9dfb0f71, 0x9cd670e6, 0x44998291, + 0xc2ce39e4, 0x638cd486, 0x6785852f, 0xf574d5f3, 0x9e8321fc, 0x0ecc35e6, 0x86cca23e, 0xd2a7f99f, 0x31568729, + 0x3e5bf006, 0x91a5f445, 0x1dbed013, 0x5bd3905b, 0xbc0436f9, 0x473b340d, 0x15cd7bd1, 0x4d04b135, 0x825986d7, + 0x54ac2c53, 0xc950326b, 0xb809d369, 0x8a4e8985, 0x896caac8, 0x79720523, 0x56637c67, 0xd22ec18d, 0xd0aeeab6, + 0xca95c149, 0x6f02af75, 0x36fa86ab, 0x59538d00, 0xe395b7cf, 0x9e880ed4, 0xb6a59ff5, 0xb7d2c974, 0x7e12e8ea, + 0xf12bda86, 0x641cf8d5, 0x421cbe6c, 0x771688c0, 0x727a52bb, 0x3dbd9a1d, 0xf58ca089, 0x09370b43, 0x63f9e1c0, + 0x70d6fc4c, 0xb1cdf613, 0x7656b65d, 0xb4507939, 0x59119f8a, 0xf4b7b007, 0x2417e273, 0x6f792727, 0x2c126570, + 0x4c97fd40, 0xa5163ae4, 0x3018a87f, 0x7d2df16d, 0x3d764d39, 0xbb408b1b, 0x09c4ae54, 0xf29d3940, 0xd19e0744, + 0x943e54e1, 0x91eca778, 0x6d8b69f6, 0xda70927c, 0xd8ba9c98, 0x40530209, 0x6bbce337, 0x700177b3, 0x23298e0b, + 0x55b15195, 0x714f5daa, 0x073e38c1, 0x5d6e422c, 0x105db050, 0x121389f8, 0xd872e63c, 0x3b4f7bf9, 0xb3deaebd, + 0x5786a1c4, 0x7b9d97f5, 0x6b4af860, 0x020ee40c, 0xb53694e5, 0xdb0cb949, 0xd644061b, 0x8601d34c, 0x775bab72, + 0x1c58375d, 0x5cd0d833, 0x0ce3c44a, 0x6de401fa, 0x74ad804e, 0xddae4be2, 0x4fe41e86, 0xe88cecca, 0xd81b5250, + 0x18fb40ee, 0xcf3969de, 0x9aa4d7de, 0x96f2805f, 0xaed3593c, 0x88ca6377, 0xb4aedc3a, 0x796927a6, 0x50565dd0, + 0xcfa2ffca, 0x1aef2ed4, 0x706ee231, 0xe335b453, 0xc5227534, 0x39707b03, 0x7fac5ddc, 0x2eb3c8da, 0x71cc8f6d, + 0x263e498a, 0x09cca39f, 0x83ddd8d6, 0xf1a173b9, 0x157c7337, 0xbe88474e, 0x423415c6, 0x3e6b12ae, 0x5a40bd85, + 0x815b46a7, 0x0992c4f6, 0x3d681433, 0xfea14077, 0x8901dcdb, 0x40b2e130, 0xe9db7583, 0xa4775bca, 0x2e88a017, + 0xb203eb1b, 0x4d22694e, 0x3106a750, 0x3b438d96, 0x4063ffca, 0x801f7237, 0xc7604a2e, 0x23cbd3af, 0xce76bbad, + 0xec44bf65, 0xe8d48bc9, 0x6502c7cc, 0xde0fdb27, 0x2e3fc4e9, 0x68bc0311, 0x44f57cc2, 0x33f41101, 0xef03dda1, + 0xc09717ab, 0xfe5b6465, 0x7f995c48, 0x08853b7c, 0xe4d57084, 0x9b27ea55, 0xa0ca6c76, 0x07da056e, 0x1211603a, + 0x1e3e6dce, 0x0443e332, 0x49432fe7, 0xe678392d, 0xcfba9075, 0x68e711c5, 0x0693e5ca, 0x3decc730, 0x64923a02, + 0x402b1d3b, 0xb960d6ea, 0xa16dfb78, 0x3d86d7e3, 0xa19b54aa, 0xd64ce5ac, 0xb77d9344, 0xa4aa81f0, 0x1d11e31a, + 0xe9f0f917, 0xfe8d4dc8, 0x89142689, 0xc622afef, 0xbb7f6033, 0x19401161, 0x9a78d72c, 0x671b3cb4, 0x5d8da408, + 0x9d8a0090, 0x44e89370, 0x37020b80, 0x9e546187, 0x1d1016ff, 0x6e2fbf3b, 0xf42cc4a6, 0xaa752fa9, 0xe98a8fd8, + 0xcb534760, 0x57254257, 0xa4e6846e, 0xc17769d4, 0x8f6bf314, 0x8cce8555, 0xbfa8756d, 0xb3645181, 0x5a101d6f, + 0xa3a64862, 0x634afe82, 0x687f3e16, 0xacf3fd53, 0xe796e0ec, 0x54bee329, 0x9f22d79a, 0xc324a745, 0x6ff251f7, + 0x0ecb5fab, 0x3664b026, 0x367f7481, 0x403235c2, 0xd19e95c1, 0xff1bbe12, 0xcc57d22d, 0xac62511d, 0x4113dd9f, + 0x52f79f44, 0xb1c9b07a, 0x20368db6, 0x96bdb360, 0xb876a64e, 0xcd84dbf0, 0xbbb61687, 0x71bd4e81, 0xdbbf41a4, + 0xbb3b4977, 0x8fe4a536, 0x9377390a, 0x62bee3c2, 0x61ca1e68, 0xf8d15e93, 0x062279a4, 0xe23dbc97, 0x3544503a, + 0x933226f0, 0x06192016, 0x47e6246f, 0x829dee07, 0x85fad981, 0xeb02cbe2, 0xbbdbfee8, 0x85c3d91c, 0xc0ca73d3, + 0xf1b2b6b2, 0x3adc965b, 0x221f5a7a, 0x7fe252c8, 0x3c0461b5, 0x4c0082b2, 0x0f9df26e, 0x4f4f721f, 0x41149dbe, + 0x32abf076, 0x5cf4a8ba, 0xf872083c, 0xfb2440d3, 0x935b61ae, 0x73f8a838, 0x1f2457ca, 0xf204c7e0, 0xed0e82da, + 0xb854817f, 0x2ccd0e10, 0x126510f3, 0xe83b30dc, 0xb9dcdd80, 0xdaca22c4, 0xb2367dd4, 0xc4696f9f, 0xaf77c90f, + 0x57295674, 0x143c489c, 0xcab31ee9, 0x54a99870, 0x77719186, 0xd2f56cb6, 0x27e03e9e, 0xd16662a7, 0x7b90b909, + 0xc834dd98, 0x6864e6c0, 0x694bf0d3, 0x17a01bfd, 0xd3637be7, 0x5fb0d314, 0xf6543ca4, 0xd81cfaa9, 0x2bd27656, + 0x1424e171, 0xbe388983, 0x54061840, 0x3d0325ff, 0xcc3d3f6a, 0x38bca8e5, 0xcc0ebad6, 0xefea5c10, 0xd61ddb1d, + 0xf8fa68f4, 0x6dfc4361, 0xbfa96ea5, 0x8c50b708, 0x05933162, 0x0f750f13, 0xb10e204f, 0x839a4c14, 0xe5b110a0, + 0x551c4dcd, 0xfcc00885, 0x8e49087c, 0xa042e911, 0xd9a4c80b, 0xd99897ea, 0x68ff8f6e, 0x6205fb51, 0x767edcb9, + 0x8c539f25, 0x827dd037, 0x91a555b1, 0x6079f1e6, 0x2867eee9, 0x9a943bf6, 0x110c7f0f, 0x65f146f2, 0x5896bc72, + 0x9c1037f2, 0x64dc4326, 0xc9d3610d, 0x381c152c, 0x29edf400, 0x0d967c9c, 0x16db93ec, 0x1d985a6d, 0xda8a9fc8, + 0x4df164bf, 0x111037b7, 0xde610adb, 0x393e2433, 0x4ff8b291, 0x9ba3d573, 0x4fa81428, 0xf3c36042, 0xa69e60bb, + 0xa10e1f49, 0xd43c6499, 0x3e91d9c5, 0x464f225f, 0x7c3630b9, 0x68d379ef, 0xa19ea6e1, 0x0577396b, 0xa6f43575, + 0x8216a8b1, 0xdc50a3c0, 0xf9e59a29, 0x5863c013, 0xb4a27cfb, 0x4ff4dcf6, 0x45eb13fa, 0x95e27dae, 0x544cec36, + 0xde4a46dd, 0x0c59c8cb, 0x656eac89, 0xcbd645d8, 0xb56dca40, 0xf95ea64c, 0xba7283f6, 0x66231853, 0xc3b3fc89, + 0xca2e4b55, 0x87744929, 0x89e6614f, 0xeb15912d, 0xae4c321f, 0x7946a400, 0x16ef768c, 0xc1a9d69b, 0x9a9273d2, + 0x9b70cd9c, 0x7fab2de2, 0x261bb0f4, 0xa5695949, 0xa585213f, 0xf6bd4634, 0x30c98bd6, 0x2f8171f6, 0x9c680589, + 0x16fc5c46, 0x9e595ece, 0x62b18bc3, 0x0ebd4190, 0xd033cab7, 0x270bf8ec, 0x014afb2d, 0x264739cf, 0xb296e6d2, + 0xe96ae1c3, 0xeef64f66, 0x594d8dab, 0x2b04c92a, 0x102eb947, 0xa5145b05, 0x0119aa82, 0x30f4e263, 0x12d3feeb, + 0xc95776ea, 0x2a10186e, 0x67e7e8bf, 0xa60088c2, 0xa199ccd0, 0x5ac65d69, 0x2fd6941f, 0x0ed667e7, 0x70fe2d6c, + 0xf320dd98, 0x15e5d9ab, 0xf1f6bf0d, 0x760f32cc, 0xed5975b9, 0xe13fab11, 0xcd61b18e, 0x3fa109c4, 0xf63a5098, + 0xe9718464, 0x9fffb50c, 0x330baf97, 0x9dbc7315, 0x936c53af, 0xe3ba7bda, 0xa379fa28, 0xb198ef0d, 0x4ac76742, + 0x436aa9e5, 0x6f126681, 0x2d2f6103, 0xcbf3903e, 0x19566ceb, 0x9ad0e889, 0x5b5ea53e, 0x125aa458, 0xae5b41cf, + 0x7a3d8ab3, 0x394e3142, 0x611ee49b, 0x4b41bc78, 0x01ddcd1e, 0xcd0916fc, 0x0c4901c0, 0xe97cc268, 0xd2755db3, + 0xe8ec4f06, 0xbfcd0878, 0x483115c3, 0x728b7d97, 0xb8bfb30e, 0x47d5420e, 0x09af8ba5, 0x696ac2ce, 0x7da810ba, + 0x23491c6a, 0x54ef4252, 0x6f8ac3af, 0x8922a0ef, 0x3351a0cd, 0x2d37587c, 0x22d8c95f, 0xaa4aa844, 0x65ae6b99, + 0x749a8368, 0x3b6bbc68, 0x539a37c5, 0x5f119721, 0x44ec5583, 0x745681bc, 0xa1f202d7, 0xc06f4b27, 0xeee03163, + 0xc2281775, 0xcb9fe674, 0x75e5e8a3, 0x31efc541, 0x968d2a77, 0x18a44b8d, 0xd8743257, 0xd814f535, 0x4156de80, + 0xa8dba04e, 0xe5b607e6, 0x64ccfbf7, 0xefc224c5, 0x8c36f694, 0x3a35fda1, 0x81bfa27a, 0xfddbee81, 0xcc46ae6d, + 0x423677e8, 0x650dd198, 0xd0b86bf2, 0x1709b75d, 0xcacd4625, 0x7cdde524, 0x44a48552, 0xa1f7a88a, 0x10566fb8, + 0x45bb35d4, 0xf60eaf9a, 0xa2b420ec, 0x4f90f995, 0xb433793f, 0xd80cb2b9, 0x42c110b9, 0xb4d73960, 0x44dc437e, + 0x12c5857f, 0x780776a9, 0x64a3387c, 0xfbd5411c, 0x6b7eefb2, 0x16cd9500, 0x0c183b01, 0xa4b0e06a, 0x1d0de0a2, + 0xaf1d1567, 0x93c6015d, 0x3762f787, 0x4144b86b, 0xb070cf96, 0x568d5d91, 0xb97607a6, 0xc0ea5320, 0xf43f4ee3, + 0xe8894cf6, 0xa234f396, 0x16f5f398, 0x6508aa5d, 0xeb8f6ddb, 0x54d842a4, 0x7a052f8b, 0xa3f5bd6c, 0x8eabb07e, + 0xf5202a8f, 0xc12059de, 0x932e9334, 0xc73ceada, 0x2b99fdfa, 0x6976df9c, 0x4200ac23, 0x5edf28de, 0xa3c6858c, + 0x4cd80129, 0x432a951f, 0x906d2b12, 0x028952b7, 0x054c920c, 0x0841be16, 0xe532c550, 0xbcdce833, 0xb3e56fd6, + 0xbfc0ce09, 0x1cdc32f6, 0x27c4a1fa, 0xdb916bc6, 0x060176ed, 0x8f3dd045, 0xd2bf6955, 0x040a23fa, 0x173c3c8a, + 0x15c11797, 0x120a63b0, 0x614d2179, 0xfe34d1fb, 0x5ca15804, 0xc7ea4707, 0x709bbb4c, 0x5d5a9d28, 0xc8b908c5, + 0x5243a8b4, 0x31ffc4b4, 0x3fc4227a, 0x8277f7e1, 0x905142f3, 0x82310cb0, 0x1886dd8a, 0xeede8a40, 0x0c99d69f, + 0x7130d9af, 0x645bb9ac, 0x8f3cf6c8, 0xc3c55a9a, 0x04b6417d, 0xd965a727, 0x98647139, 0xd11c422e, 0x12bfa70e, + 0xf641d986, 0xda371edb, 0xf33f10ca, 0x7bdee6ea, 0x1c3b295f, 0xdfd2e9d6, 0x0df717f5, 0x37434dec, 0xda89e7a7, + 0x32af69b8, 0x0b4c9b3a, 0x979b021e, 0x232690f0, 0xad456248, 0xed697bba, 0x3681ee0f, 0x0bbfc951, 0x720bc854, + 0xfdcfdf60, 0x9d78b081, 0xebb9ccbc, 0x02c347a4, 0x63b2a6d8, 0x636b46e3, 0xca6ada4d, 0x985e7763, 0x76435bbd, + 0x49ba4837, 0xef0f44c7, 0xfe70cc93, 0xdf89baf3, 0x278bab50, 0x0d93077d, 0xa82ea801, 0x9df427c8, 0x52f6f24c, + 0x1cdcdf5b, 0x7bb0d501, 0xb8d8a20b, 0x81377201, 0x48bbc27e, 0xb4fbfcdb, 0x0fdab2f7, 0x2b0f2b15, 0xa82a3b06, + 0x54d8bac3, 0xa0acf6ac, 0x24ad5556, 0xc49a1967, 0xf69f4726, 0xd95408c0, 0x0998e34c, 0x89e00f97, 0xa558fe2a, + 0xf9483b35, 0x3386c1b5, 0x99aedb5f, 0xb05910d6, 0xdb8d025c, 0xdbba7192, 0x2431266f, 0xe431c082, 0xecc06349, + 0x220ab10c, 0x18424bda, 0xd5cdbf68, 0xcbcb10eb, 0xf5a543c5, 0xea678cc5, 0xb37a6eaa, 0xfb033c08, 0x3a9b592e, + 0xf8485b67, 0x3beb4857, 0x2df2e224, 0x24213180, 0xe4157f20, 0x035b4b96, 0x98ecd662, 0x60fde091, 0xf7b2d9ed, + 0x74eee47f, 0xd20fa100, 0x7506fa95, 0x3084502b, 0xf93f8ed8, 0xe10fa949, 0x626e7858, 0xc386e305, 0xc5ae530c, + 0x046e0972, 0xd3dbbcf3, 0xa9aaadbe, 0x37b394b0, 0x097e4f41, 0xa9b2e95e, 0xd74a9991, 0x67f47839, 0x3c292ae6, + 0xa9d5f189, 0x854c9f92, 0x95312b3a, 0x3cd8bb21, 0xfa0ee69c, 0x64f0620a, 0x70e59d65, 0xc3f37cbd, 0xb381317d, + 0x119f3bd4, 0x8976ab39, 0xbaeb9060, 0x8e0f5e5f, 0xf3ea2c53, 0x74040b07, 0x02b763ca, 0x8e306317, 0xd01e4d95, + 0x10e54656, 0x5285e6f1, 0x01b0c131, 0x74c4d5b0, 0x5b3b0527, 0x94a9b510, 0x4e300ba1, 0xe3bb194d, 0x3675aeaf, + 0x677ba5a6, 0x08485245, 0x3763cee4, 0xba0a19e1, 0xa0fc8605, 0xb7d7b35d, 0x98587c8e, 0x5f115c57, 0xae286774, + 0x8543e156, 0x45c986fb, 0xa6c56967, 0xec524f07, 0x64169159, 0xb9498a55, 0xa6b89f00, 0x56b9e489, 0xf117c4f2, + 0x4a0e1fe6, 0xd3ad299f, 0x75103ea4, 0x956521b9, 0xb1d27c5b, 0xf57a118a, 0x88c3a6c5, 0x8cfbc8f3, 0x17069ed2, + 0x917af199, 0x9fa8b762, 0xb0179e66, 0xcadf6460, 0xc8a726b6, 0x5492be25, 0x3e87cd5f, 0xd746adb0, 0xa0ce7218, + 0xae30bc2d, 0x19ba84cd, 0xd301a62a, 0x495830ce, 0xf6157422, 0x1fc7f34d, 0x1f542b45, 0xb61fd27d, 0x263954ec, + 0x8921de48, 0x9252ba66, 0x69e835cd, 0xd773e407, 0x53b6bb33, 0x881d67fa, 0xa290e9ae, 0xef92a318, 0x00bf9d9a, + 0x5730d36f, 0xd96193a1, 0xfbc09c43, 0xb437ecc8, 0x0e881888, 0x60b5e320, 0xe1e85c90, 0xf85570f3, 0x8a43c19f, + 0x81b1f251, 0xc90542f3, 0x29ed19e7, 0x45bf4da9, 0xe7ec427f, 0xd33f0bcc, 0x64cd075d, 0x94a74cb1, 0xa0c9ad8a, + 0x2ba9d16c, 0xb63da599, 0x003d8a67, 0x82490a64, 0x7913320e, 0x2ce027ac, 0x865774a5, 0xa6de964b, 0xdbfad789, + 0x3de1933b, 0xaff358f9, 0xc4609871, 0xdc64e18a, 0x52dde424, 0xaaa2ec6f, 0xc969d931, 0x722c8183, 0xfb6948ed, + 0x82354c6b, 0xfe024b85, 0xd2b5bafe, 0xc056b900, 0x67629217, 0xbe435d7e, 0x1750abca, 0x69009a6b, 0x7469dfee, + 0xf4195c96, 0xb1d52cb0, 0xf57d776f, 0x9a51320a, 0x51526001, 0xc2956951, 0xbc4cc490, 0xec43f19f, 0xa4aa5444, + 0xe43d80e3, 0xa41f1a96, 0xe72d219e, 0xbdf1cbc9, 0x215f8991, 0x0dccbcc8, 0x08113a4f, 0xab00f5e9, 0xdf3005c3, + 0x28b9f970, 0x666be930, 0x0cbc1b0c, 0x9ef34059, 0xc003da5e, 0x737e5d10, 0x75bbf11a, 0xec3fc49b, 0xbc16e38a, + 0x23813a7e, 0xe47877eb, 0xa325e184, 0xef693202, 0xff0f1df9, 0x2271b599, 0x2387fcf5, 0x61b8ad93, 0xe340ceb3, + 0xebbddec9, 0x2476b12b, 0x02443004, 0xb90bca4e, 0x8e86aa6c, 0x1bbbfe42, 0x5d8614c4, 0xdaaa684d, 0x19cdbbb2, + 0xb8a50429, 0x7cc49268, 0x599ba18b, 0xc930054d, 0xb945965b, 0xef23378e, 0x1c9c0ea7, 0x53df3468, 0xaa257efd, + 0xcbd90a37, 0x896793df, 0xd8a516dc, 0xf9351484, 0x1c08518b, 0xf720e2b9, 0x38261da3, 0x3770472f, 0x8699a02a, + 0xcf47e1ea, 0xd176b4a5, 0x30c7a090, 0xec6cd4b5, 0xbb76dbb1, 0x9998c2b5, 0xb698eec0, 0xc679d926, 0xc3267f73, + 0x3a98ee73, 0xf3647954, 0x0522136d, 0x15e0d6b8, 0x724acf31, 0x633841d5, 0x2e26cafc, 0x2dab411c, 0x49ed81cf, + 0xc5a1b5cc, 0x4a185fb3, 0x7582547d, 0x303396cb, 0x64e832f7, 0x6c33670c, 0x93a90cf9, 0xa938153d, 0xf8fc4815, + 0x9d56a5a4, 0x079241d3, 0x286bf861, 0xb5e20073, 0x6f42529b, 0x545313da, 0x166b8afc, 0x71769517, 0x619783dd, + 0xf2c3dc81, 0xc879140a, 0xe44970be, 0xf5a66ccf, 0x1bb74cba, 0x637d3dc3, 0x482102e9, 0x1bf53d4c, 0x51e0c89d, + 0x0839e12d, 0xebd360e4, 0x4ceb9bcc, 0xed510327, 0x01297fcb, 0x58a55ec9, 0xc146ccef, 0x41ed4189, 0x823221b9, + 0x9a35ab10, 0x2c380f9f, 0xefebaeb1, 0x2cbf659e, 0x8892d970, 0xd934ca8b, 0xa4fdea58, 0x5d299abb, 0x32cb6c1d, + 0x39578a32, 0x5c980065, 0x48c7cd64, 0x73612abb, 0x13271422, 0x5b8e0086, 0xa3fd0ce8, 0x24ffce7a, 0xc9aa4f73, + 0x9d928482, 0x933ad70b, 0x71820575, 0x19732ac2, 0x81433f62, 0x31495c63, 0x9bf9eaf0, 0x04ee3771, 0x51263be2, + 0xf15b5dfb, 0xed56931a, 0x15e3c543, 0xd2db92f2, 0xfd6a250d, 0x85bc23b2, 0x6a0ae3b3, 0x8105814c, 0xdfbf3376, + 0x3483449e, 0xb6c9f52e, 0x21a8003a, 0x36f97c0e, 0x8167b62d, 0xb4446337, 0x98d8cc7d, 0x783a6bd8, 0x1ac5011b, + 0x3699c80e, 0x6651be3b, 0x4189c586, 0xf7ce971a, 0x10b7c690, 0x50fa9bc3, 0xba39e4d9, 0x9388e890, 0x02408dd5, + 0x237e9849, 0xd18fbd09, 0x419686b6, 0x4dbd7ead, 0x7e6b8858, 0x8820fa55, 0xf08f3d8b, 0x43d9b6b7, 0x43bcc207, + 0x83723d93, 0x019b2488, 0xe56086d3, 0xa1586f68, 0xbe6cb950, 0x4ac9410b, 0xa88d033d, 0x2e39fa4e, 0x2d6021e3, + 0x86a938fb, 0x140b2c3a, 0x06887b38, 0xbbcf090b, 0x7b394556, 0xe1563d3a, 0x8418b4b2, 0xd3a84552, 0x75827ebd, + 0xc519caa0, 0x9641b9b8, 0x005a3f8e, 0x11617e31, 0xc43942ce, 0x45d9cf30, 0x7e86ddf4, 0x26b53120, 0x411133f2, + 0x5ad0f295, 0x62bb3cb8, 0x5ef74905, 0x35d9d497, 0x3b6c907f, 0x3e5f7dee, 0x66f470e1, 0xd90c94e8, 0x2cb5338c, + 0xfcd0dd14, 0x4ea35b01, 0x83004263, 0x5aa9a2b4, 0x088da8a7, 0x60b52777, 0xff76d587, 0xa471746b, 0x89e98b8f, + 0x649efe1b, 0x41ed6bc4, 0x0bfc42ae, 0x9b86c6f8, 0x468b45ef, 0xb11bedbe, 0xab36640c, 0xaad89996, 0xc2f26918, + 0x3d1351d9, 0x39841f72, 0x4a345923, 0xcec3348e, 0x6717fc90, 0x7b0b4367, 0x18567943, 0x761cd531, 0xbd6f8a36, + 0x5f4b4a12, 0x13acb2fe, 0x5efb0c4b, 0x642730e8, 0x5c35a2bc, 0x01a43917, 0xdc532851, 0x746e458f, 0x5c1ea09e, + 0x44ead4dd, 0x1dba62b8, 0xba587b24, 0x113032e2, 0xcf18934a, 0x3669f403, 0x6310aed2, 0x5239bccc, 0xdd64f96c, + 0x517d18f1, 0xfb80c964, 0x89f4c16f, 0x9d34ccc7, 0xd5304e3c, 0x4dcf9432, 0x41108fc0, 0x7e8e163e, 0x19ad0df5, + 0xd4db06b7, 0xc6e44bc1, 0x807e0094, 0x509d96bb, 0xdb9f3206, 0x645f9621, 0x6197124e, 0x22520bef, 0xda4630f4, + 0x6237f5fa, 0x232ec7fa, 0xda95f980, 0x30c9e03e, 0x91a9594c, 0x0da5cffc, 0x37cd9446, 0xecb47225, 0x01a1896e, + 0xd93af248, 0xce33269b, 0xdad1e131, 0x1805bcb9, 0xfe36e178, 0x74d60036, 0x30f4b54c, 0xd54dd191, 0x0213b657, + 0x03b757c7, 0x9723ca00, 0x4160917d, 0xb7387c6b, 0x72919ece, 0x14337c34, 0xb5d8bceb, 0xb019b509, 0x60fdcc64, + 0xa773e04d, 0x7ab1d237, 0x0a59fa19, 0x6eeda912, 0x0be8d8cd, 0x261edc2e, 0x4bb9a1ad, 0x360fb395, 0xa2c3e777, + 0x9b0f3e66, 0x9769f32d, 0x96436530, 0x931b5577, 0x7418dc21, 0xd495bf6b, 0xfbf18f2e, 0x60915ebb, 0x083b49eb, + 0x74c5f174, 0x908d3b1f, 0x6147e3a8, 0x33000613, 0xd4f6c3b5, 0xaf91aab0, 0xfe34dc62, 0xe44e1377, 0x0000e40c, + 0xd1cd5bbe, 0xf5efe00a, 0xe5ecfb90, 0xf514ab4b, 0x9ec5e608, 0x7ac98060, 0xa2490089, 0xc9368d83, 0x514b7b8b, + 0x8870b39b, 0x3291c1e4, 0xb50b35ee, 0x41d5a7f6, 0xa8120c30, 0x1afb5861, 0x98e310f6, 0x0b8089ee, 0xd0614745, + 0xe69e5188, 0x9c6e1af6, 0x0c49f7fe, 0xd2bd61fd, 0x87973c49, 0x903bcecf, 0x571c22a1, 0xbfc1fd5a, 0x000449f7, + 0x4207f175, 0x21054c25, 0xbcc2a1b6, 0xa49cb3e7, 0x2e900840, 0xeb4361c7, 0x623fdfde, 0x62c5a1f9, 0x061d2b37, + 0x9aeeea25, 0xd56bb20c, 0x6a26996e, 0x2bab0302, 0x7c824a5e, 0x749a9504, 0xa2e36e55, 0xa2d4055d, 0x8fa68a66, + 0x993c8167, 0x0577422c, 0x2da5424c, 0xe3688308, 0xb4938bdb, 0x084cb5a7, 0x6ae4072c, 0x72df7af7, 0x23a7b6f1, + 0x12669bbb, 0xeb44ea40, 0x68410824, 0x044174b3, 0x2b8582e3, 0xf1a7dc29, 0xc40acc16, 0xb80ee885, 0x22c44feb, + 0xd6546df3, 0xb0b03014, 0x1802f50d, 0xaca01e46, 0xbcfb7526, 0xc94c8e60, 0x16699d97, 0x4e4078d6, 0x02f41a69, + 0xfac7d79b, 0xc6cf5027, 0x92c8378a, 0x314663ef, 0xfb74a03f, 0x359f8087, 0xbe667a82, 0x64783052, 0x5757ad3d, + 0x235e3038, 0xaec568f6, 0x39501af4, 0x314e2c49, 0x9aa505e1, 0x86a0ec51, 0x446f8db1, 0x183b4cf3, 0xf377343d, + 0x4f004874, 0xd400b165, 0x02017e4d, 0x5e567830, 0x052aa4b7, 0x5676a09b, 0x5f74ecfe, 0x93584b01, 0x1dfab417, + 0x9c00be0e, 0xfbaf28c1, 0x7697fa9d, 0x6c8e520d, 0x6f42a8d0, 0x723179d8, 0x53f651c5, 0x633c70ec, 0xfa884771, + 0x7a88e47f, 0x990aa4d7, 0x30af28c6, 0xf8c84062, 0x97ac0776, 0x5ff2949b, 0x12d9c86a, 0x862a218e, 0x96527b0c, + 0xe6dfd007, 0x1b136ab3, 0x0c44df4d, 0xa6288550, 0x5764c6f0, 0x42c6c633, 0xd38c08b0, 0x08523c81, 0x442a3009, + 0x1fd6b746, 0x9424516c, 0xbc328ade, 0x709242b2, 0xad82322c, 0xa03dce3b, 0xa9653d6b, 0x2ac2a556, 0xb5253bf9, + 0x1606aeb2, 0xb19a3bb6, 0xab826b4b, 0x38e35170, 0x3e3eec02, 0xd95a869a, 0x87b05bb6, 0x0e019e55, 0x8dceedb7, + 0xb7d912e1, 0xf8efa614, 0xf517cf41, 0xa4ae628f, 0xfef58450, 0xc3eb9d54, 0x136fda07, 0x0733f390, 0x4c0df250, + 0x14d15361, 0xc272d190, 0x218da730, 0xd181b716, 0xbdef2e77, 0x3581cd4c, 0xde544ed3, 0x29a2eabd, 0x4043771d, + 0x760a9bdf, 0xd7e6b5cb, 0x2fb368b6, 0xf8665bd4, 0x4008638a, 0xebd7af94, 0x916d75cb, 0x04c7ac0b, 0xe111c0e5, + 0x4273e5cf, 0x8f23bb15, 0xda62e5e0, 0xa4ff8796, 0x706c96bc, 0x50f42af5, 0x49c3df12, 0x1860754f, 0x434feaaa, + 0x0db56f16, 0x26069324, 0x43528c1c, 0xd156bdcb, 0xcb424f32, 0x0fc8279a, 0x79837566, 0x9ef7e853, 0x0eb51ad5, + 0x86dca4ac, 0xf32cc647, 0x44ffa8f7, 0x8e0b57b4, 0xa65aa582, 0x42d56b62, 0x657322a3, 0x2039804e, 0x84c90c95, + 0x6ee84c69, 0x21bc7b9d, 0xde4ae92a, 0x05499561, 0x2a4b5ce2, 0x67a9ad3d, 0x9be815d8, 0x3976cc4a, 0x15fc478c, + 0x81a5b7ea, 0x7924dc0b, 0x5eb7ad19, 0xd837b51d, 0x7d85a1ba, 0xf616d7fe, 0x9ea2ff8b, 0x756e2297, 0x050815d6, + 0xb7b8b9a9, 0xec31050d, 0x6c2640d7, 0xca664a57, 0x90b97567, 0xd78f28b2, 0x19ccc3ed, 0x11134c90, 0xe3070586, + 0x9016a78a, 0x6ef33372, 0xfab72287, 0xc516c96c, 0x658d6746, 0x381d9f23, 0x15ccf78e, 0xcd8b760b, 0xc10518a3, + 0xbd351033, 0x2d15f797, 0x8ba6fb2a, 0xe06008d3, 0x3efbb85b, 0xb7edc404, 0x8c32a229, 0xc97f250b, 0x2f9e1c11, + 0x9470d17f, 0x862a6482, 0x240a61a4, 0x7d06d9ac, 0x3867ab01, 0xd8e5b377, 0xe6ebd6ad, 0xb2da82d0, 0xef50e2f6, + 0xaaec34fc, 0x2de58c4b, 0x5bdfbb32, 0x555f5f16, 0x7d279f5c, 0xd34bbc7f, 0xd2040c8d, 0xaaf2e9ea, 0xae0c7deb, + 0x86aacec0, 0xf64c4de6, 0xeec38192, 0xcda81205, 0x58e88c5c, 0x6a811126, 0x34d763e1, 0x54de1fac, 0x4b38058d, + 0x2a019e6d, 0x23205b32, 0xa3f1bcb4, 0x585f5da7, 0x5ff8ac6b, 0x028949b9, 0x3b33e889, 0xb470ed47, 0x04031dd4, + 0xb12a5284, 0xdfb10ee4, 0xd6cbca30, 0xb99f07a1, 0x1a383894, 0xabbdcefa, 0x887f4dd8, 0x02f74aeb, 0xa2f3d0f0, + 0x01647df7, 0x3c40ffe7, 0xa3841f3b, 0xdbde361b, 0x3dbe3121, 0xbd3bacb0, 0xf8be6372, 0x992c7d80, 0xf4d25a31, + 0x5091a47f, 0xb8d38b5c, 0x550f2acb, 0xe736f077, 0x5b29b31d, 0xc5001375, 0xde3d9900, 0xdfe08d22, 0xb907924c, + 0x6e5af044, 0x4659ef7c, 0xcae40766, 0xfc98a52d, 0xb537be3f, 0x20c0f5a4, 0x8d5c4d51, 0x9f01dab1, 0xe769b718, + 0x60cd7448, 0xc104ea1c, 0xc6d31b03, 0xf72831e1, 0x43edce5a, 0x201e985d, 0x26d195eb, 0x220b7c67, 0x2fb3bbc1, + 0x2b50186c, 0x7c7e59d0, 0x955ee2ac, 0x335bcc92, 0x4dd82c78, 0x94e9654d, 0xd93cd867, 0x243d85c5, 0x7aef857d, + 0xb356af94, 0x7b898341, 0x4bfd1162, 0xa90ec784, 0x2b706e4b, 0x71ebd745, 0x2892e848, 0x7000e3ff, 0xf3d3a853, + 0xf9cfd73f, 0x09b76b2b, 0xc6b61789, 0x5e9ebdfa, 0xb77709a2, 0xf91ba5d0, 0xbb4839d0, 0xb5f022d7, 0x824d7527, + 0xb2dc5470, 0x6bfae4b0, 0xbabbbace, 0x6dbb8f4e, 0x7b510ed7, 0x9275960b, 0xe77c0d4f, 0x914c76c8, 0xbd2f7e91, + 0x448bb316, 0x883f0807, 0xb9d2ee9d, 0x78899dc9, 0x94031fcd, 0x5cd1461b, 0xf630da08, 0x68fda623, 0x178f0171, + 0x49b38888, 0x3fdfbf43, 0x0442336e, 0xa00832a9, 0xfee8e020, 0xe70475f0, 0xf5488789, 0x2df3b52a, 0xca220099, + 0xc4254945, 0x0863a1e4, 0x25b3df2d, 0x58c47fdd, 0x058098ed, 0x91a00739, 0x051bddb8, 0x0c73fc98, 0x369e194e, + 0x5adccfd3, 0x3a9dd8d7, 0xd83be573, 0x601e2f55, 0x00051a7e, 0xf41397e4, 0x329671f0, 0xc8eff9a6, 0x374b01a4, + 0xc42d75ea, 0x65535f73, 0x5032ee07, 0xf4f86ed4, 0xcd6e9454, 0x9c43ff10, 0x1d38547a, 0xe84fcc95, 0x3b2c72ae, + 0xdb38c9d1, 0x42a3c0cb, 0xe68be272, 0xcd491927, 0xa5ab887e, 0xe71ee94c, 0x9295f0ca, 0x2d105b13, 0x5c644274, + 0x9eb1691e, 0xdfb9882a, 0xcc1b0643, 0xd79bbf54, 0x630b86ce, 0x5272af21, 0x38aa5517, 0x429c9cbd, 0xbfb1a451, + 0x88244255, 0x73510629, 0x6fd7c29a, 0xb23d7af4, 0x83fcb222, 0x07136ea6, 0xd894d125, 0x53940486, 0x5488a115, + 0x71318408, 0x4c8a4377, 0x7dacde37, 0x48f9e8a9, 0x94496bbc, 0x35dcb1a5, 0x702be655, 0x456a34ff, 0x5edfc669, + 0x1eeb1589, 0xdbe4ff00, 0x88afcf76, 0x75cf04d5, 0x74771d9a, 0xaf597e52, 0xe518dde9, 0x0a479977, 0xad06f6b8, + 0xace66549, 0x1b295e04, 0x09910eef, 0xbfd4f536, 0x2be37b0d, 0x96888d2f, 0x7377ed49, 0xd6d051d2, 0x2b22d838, + 0xbdb1647e, 0x61f0531e, 0xe0369c5b, 0x8ce1f3d4, 0x5f433441, 0x73c8f3b9, 0x47784ad6, 0x8a4579e8, 0x8bc3914e, + 0xb6f603d5, 0x9a8f4539, 0x6a1af521, 0x4ce16bbc, 0x6f72181e, 0xe0f5076b, 0x80c83ab0, 0x6d98d1fc, 0xb1695cdd, + 0xd3c79081, 0x55b88f99, 0x518bed33, 0xfb8b2ce1, 0x585dfd3b, 0x614f7f3f, 0x5a3a7f32, 0x23b07ef4, 0xc6c81c4c, + 0x1662b7f4, 0xd4fa0b45, 0x7c002f1d, 0xe6da3bbd, 0xd6f2a90a, 0x82cc16a8, 0x91143490, 0x8f5a3009, 0x97fa2e86, + 0xdb16482d, 0xc6b1c45e, 0xf4a46b5e, 0x9693e8e3, 0x36f4cee5, 0x7a25dc39, 0xe3fbf071, 0xb66080b5, 0x7a6d9894, + 0xbd1d2f1b, 0x7b608f01, 0xd0dbfe4f, 0xc905cb1b, 0xa671eb06, 0xb302b5b1, 0xfe17a56a, 0x000b56bf, 0x9766e9d6, + 0xbeb2c2ec, 0xfe41e79d, 0x36bbedc4, 0x8da9f133, 0x17bd3a64, 0x7424e138, 0xc451c0d6, 0x33cd9887, 0xe110f9e1, + 0xb5a0adcf, 0x64262005, 0xb52be04c, 0x82472cac, 0x57f97786, 0x98390941, 0x2b02935a, 0x672cd318, 0x3b2d90f5, + 0xcadb0d92, 0x44de5f22, 0x3bc4a9b8, 0x523e071e, 0xe5f2d267, 0x843d8fcf, 0xb5e401b5, 0xac4fcd80, 0xf0817e85, + 0x1637498b, 0xa98dcbcd, 0xa45b90b5, 0xa35e5bdc, 0x75f9afb2, 0x3d820e26, 0x5f65c3a9, 0x1b2b9968, 0xfa3ce556, + 0xf13144b5, 0x599b955f, 0x062590cd, 0xb51d3399, 0x0bd8bfd1, 0xa55f2af0, 0xaaccf64d, 0xef7fc510, 0x3f6f105a, + 0x94a5cbff, 0x0f9a743f, 0xd481e772, 0x989deb84, 0x042e7362, 0xe3b3ac9b, 0xba13ab4f, 0x70002a9e, 0x034b615d, + 0x8d20f4de, 0xe12d75b2, 0x6db424cc, 0x7afaa4e1, 0x9eb8ad27, 0xf7c17f38, 0xe3c98fa3, 0x84e27859, 0xb16ab31c, + 0xe57b7e3b, 0x742df846, 0x110ca2c4, 0x6df84554, 0xcb14d831, 0x54a74f57, 0x289db93d, 0xdd1d5b95, 0x7180505c, + 0x5b60e046, 0x8b1c9035, 0xf36a2485, 0x6b9b76a6, 0xf8c816b9, 0x8d2d0f00, 0x8f69d031, 0x5eeb2e41, 0x8db79b06, + 0x38755212, 0x260d93de, 0xb8a027f4, 0x470c5e43, 0xa6078811, 0x7b4386a4, 0xb8a0cce3, 0xc75fdf33, 0xc3344ee7, + 0xdf09b36b, 0x8d03f74e, 0x5e24df46, 0xea140309, 0xb8fe4ab6, 0x675c1e51, 0x35db4ae1, 0x91e51bea, 0xf86e8246, + 0xf27c393e, 0x3317fc0d, 0x3e542150, 0xf026af3b, 0xecb0a0c1, 0x5c92b00b, 0x1f7512c7, 0xc300dbf8, 0x98954c56, + 0xf1604dba, 0x23a0fce5, 0xbcc7dc65, 0x5ab0d66d, 0x88bb69db, 0x089b2e2d, 0xcfa74264, 0xa658a312, 0x36be456c, + 0x56e3ddaa, 0x76ba10e1, 0x0db08346, 0x59203254, 0xa12c2e22, 0xdb70c625, 0x5903ee71, 0xf11f55c1, 0xf3d642fe, + 0x3e39e444, 0xb116c21b, 0x56822814, 0x52cbb21b, 0x89c58262, 0x0018e8c2, 0xc491b6d5, 0x116dd542, 0x961ab716, + 0x3aede2e5, 0x0a65c8ae, 0x949989a3, 0xbb9eae70, 0x51ae93db, 0xac25b469, 0x15dabd86, 0xbc45c55b, 0x53ed6ef0, + 0xc6bb8cae, 0x0737b422, 0xcd73060c, 0xce8471c8, 0x9665a727, 0x966f4e50, 0xcddad93e, 0x97d543aa, 0xf2890f8c, + 0x8588c5ac, 0x8d41531e, 0x394b28f1, 0xe6b78e6e, 0xd46c29de, 0x32ae62b6, 0xabba0847, 0x7370a911, 0x171cff8a, + 0x34cf90d0, 0x3518948c, 0x7b0ef6ab, 0x5672bbc9, 0x196ea5d5, 0xed1ebe48, 0x59f7390f, 0xcec02ffd, 0xa2d3cfc8, + 0xf75c0c71, 0x8e21b96d, 0x2f32dbde, 0xbe514fb1, 0xbfde37ae, 0x1689c9fd, 0x5d8f1a6d, 0xa6c7e795, 0x824af53a, + 0xbc450c21, 0xaa5fb6bf, 0x9372fe1e, 0x2f369e9f, 0x22051762, 0x7652743f, 0x63222d8a, 0xb8b71f11, 0x3a121831, + 0x8af89fc1, 0xe302c240, 0x9ee8b8a1, 0xeff2ad8e, 0x1ea713aa, 0x8e9eed69, 0x59863580, 0xaecd23f1, 0x5f96e5d0, + 0xc7fb9df4, 0x6901f3ab, 0x8fb75aa6, 0x02cfd89b, 0x6ec1bf25, 0xdaf49462, 0x8e5f70af, 0xca14bb3c, 0x585b2db0, + 0x6cbfbd14, 0xe67b2b80, 0x647f6f60, 0xd7b6f840, 0x0f1cac1e, 0x616afe08, 0x21e7c8ef, 0xf2fa8706, 0x1a896490, + 0x13bb14a9, 0x1ff55bcd, 0x4184b9df, 0x8f355156, 0x8ff4868d, 0xea338ba9, 0x310586ac, 0xcf960b88, 0x6826a43d, + 0x0ccdba4e, 0xb74bf59f, 0x94f7c458, 0x4e9c0e15, 0x53643be6, 0x7799af2b, 0x2fa778aa, 0x7718a4e0, 0x0aea6d35, + 0xf65a5fd6, 0x40b9eecf, 0x3d0cb253, 0x72d054e0, 0x1c51cba2, 0xc27061b4, 0xf76a3ede, 0x47273541, 0x45092882, + 0x9493d1db, 0xe592fd6a, 0xba74223a, 0xdd64aa31, 0x4ef82628, 0x3843cf98, 0x24b5d936, 0x40652d11, 0x3a8778df, + 0x00b0c1ec, 0x6908ed7e, 0xee2b5efe, 0x37756526, 0x5fd6c543, 0x5a39eb03, 0x8394ec3f, 0x890d1a1b, 0x3df48990, + 0x73f4433c, 0xe94b7ed3, 0xbe2e5969, 0x778999cf, 0x759eb3d3, 0x09e1eeb5, 0x5ad36068, 0x4c0b1803, 0xdc2fb626, + 0x2e7f8994, 0x5f615062, 0x909b6072, 0x2476fc4d, 0x0c3d4391, 0xa2ac044a, 0xfebf05eb, 0xa7cd51bb, 0x0624e598, + 0xaeb53af8, 0x01f19e31, 0x71a319cb, 0xd2a772d3, 0x17a32689, 0x79d50b5a, 0x4b1695ce, 0x10dc6d55, 0x63beccb7, + 0x555ff775, 0xedeaa143, 0xcbbaa02c, 0x8ef22513, 0xdff692f0, 0x6db09651, 0xa228af97, 0xf8711097, 0xb8cde0b1, + 0xf9fdc167, 0x64b9182b, 0x7fbcb3a6, 0x2184a0f3, 0xa93d3b37, 0x65d24444, 0xa66be4ac, 0x3d8ab1f5, 0xeb4d4cdc, + 0xd415b334, 0xe6428144, 0x5ae4eb27, 0x5333c6ce, 0xf9e07733, 0x91119a3c, 0xba3eb314, 0x08f0d8d7, 0x8e99805d, + 0xab03a37f, 0x7297ad19, 0x7e6d8975, 0xa66650b5, 0x9df95483, 0xb3324321, 0x6ddf4c45, 0xfe6a64a1, 0x78193a51, + 0xf41be1e1, 0x84ac3d17, 0x68cd48d0, 0xf679d949, 0xe0f52dea, 0xada40594, 0x8a340c05, 0x9e4f5479, 0x1a64a97f, + 0xf4bfc7cc, 0xd0c3d025, 0x174816da, 0x84eb7e64, 0x570bbeb9, 0x85aec5eb, 0x2bcba4f4, 0x9f8c9153, 0x552eac7f, + 0xf5750476, 0xa2c7581d, 0xd222a02e, 0x36552575, 0x6c1d0bf3, 0x8ceaf269, 0x7a85794d, 0xa094d178, 0xbf080b75, + 0x001bb178, 0x0d205999, 0x20a0f4a5, 0xd0541710, 0xf8767cb9, 0xc40a3b60, 0x921d0547, 0x555a499d, 0x0f1d6bd3, + 0xf3ec3bd3, 0xf429f394, 0xde0e5f07, 0x59caa2aa, 0x2336964b, 0x83a483ef, 0x37e4ce55, 0xeb1638d7, 0x5caf941e, + 0xca71203f, 0xe708c972, 0x371b424a, 0x6f1e7cde, 0xdfb10fbc, 0xbaf61086, 0x32f6d114, 0x0589a9a7, 0x558dbb90, + 0xd0e7bc27, 0xf70f503d, 0xa5b521e8, 0x8e11e8bc, 0x6e821a0e, 0x75338f58, 0xb1c337f7, 0x9671008b, 0x92f5e076, + 0x31ab718c, 0x1857838d, 0xdab6566a, 0xd66a70ad, 0x083f3a87, 0x663627d6, 0x6601c735, 0xe4cb443f, 0x5ac198d9, + 0xa187522d, 0x20e5eb03, 0xe03c6b70, 0x200dfbe2, 0xba71d078, 0x5e036536, 0x84d33a06, 0x99a1ab4f, 0xee75c356, + 0x61062ba0, 0x186de906, 0x42995af1, 0x68c96c9b, 0xa966b367, 0x371e0bb1, 0xdca2c0ab, 0x5f63b0ae, 0x615a9211, + 0xaef24ac9, 0x304f9526, 0xcc585d09, 0x86b7ac60, 0xb5cd2c45, 0x0e9e6d01, 0x5dcf7c4a, 0x27b46e3e, 0x97836a48, + 0x5a7b646a, 0xab0bc253, 0xea9bfe8a, 0x0e9b31df, 0x6ce2d962, 0xab09417c, 0x4fa45413, 0x8a8a4bfb, 0xa4125929, + 0x74e8b44b, 0xcbdb5a40, 0x5d03f9e4, 0x1af5292c, 0xf672b29a, 0x3a74d9a8, 0x444d8fd9, 0x75398193, 0x39e43816, + 0x7fe2b0b9, 0xd7c3e98c, 0x15a41e3c, 0x26b6af6a, 0xe9bea036, 0x75d7af96, 0xbeac5b39, 0x998f1a03, 0x733a20a2, + 0x07d47bac, 0xbf2568c7, 0xed1d987d, 0xd4171f2e, 0x808fcdd2, 0x112d3e79, 0x4744113c, 0xa2dca432, 0x09ef5d73, + 0xcdb21bd3, 0xd755d9d2, 0x2da577f2, 0xb8b99c30, 0x3ad7c5d0, 0xd1883fed, 0x4a9894c0, 0x53368026, 0xd39649b7, + 0x6ed374be, 0x4a4759e9, 0x309be16d, 0x54a8ad9f, 0x524a388a, 0x77329bc3, 0xb44ba241, 0x3e3917eb, 0x70885162, + 0x1f6941b4, 0x51d5cc6d, 0xc5a02104, 0x1f0623ed, 0xd5b07094, 0x9aca049e, 0x007f0cce, 0x2811ba9d, 0xcfdec7a4, + 0xd777c073, 0xf0dc8b98, 0xeb545208, 0xd0eabef3, 0x65a371bb, 0x657c66c3, 0xd44de80e, 0x9ad049aa, 0xaf706299, + 0xe6e0ef7d, 0xd99d98e5, 0x63eba286, 0x445c14e4, 0xfb9484f2, 0x7604d244, 0x2c4bc067, 0x6106bed4, 0x62391d5e, + 0xf23affa0, 0x8425b4ee, 0xe9550de7, 0xefeafb3f, 0xe52272cd, 0xf201e225, 0x9c2a111e, 0xd145595f, 0x499dd2b0, + 0xf984ac77, 0xe0f8288f, 0xe778e620, 0x6a0a0d14, 0x8b3435f8, 0x91523b4b, 0x132e0bde, 0x98eddad1, 0xabaa01a6, + 0x91b12ac5, 0x42da8f5b, 0x5158c5e2, 0xc5978809, 0x459aa906, 0x3cf78c19, 0x50754df4, 0xd6bff480, 0xa489f41a, + 0x9793e02c, 0x8d96da35, 0xd430fc67, 0xe119214d, 0x32947c99, 0x0376e929, 0x9eb6803d, 0xee4eefea, 0x63bd1af9, + 0x84d5416d, 0x0619bd28, 0x54e7d27c, 0x4c540945, 0x946778a0, 0x74f5ed9b, 0x6e6ef025, 0xa343c79b, 0x4fe4d021, + 0x75ca0cfc, 0xe9d967e5, 0x3179cea3, 0xd172da5d, 0x2eeb4299, 0x624ac577, 0xb1467ff6, 0x43e4d1ae, 0x1972543c, + 0x839abfc2, 0x5b3451ce, 0x1398a12e, 0x1faee88a, 0x92280f40, 0xf737439c, 0x2857b58b, 0xcc3ee631, 0xb91faca9, + 0xf94b4f92, 0xf915f5ef, 0xc3536b22, 0x599029de, 0xc31033a8, 0x4dff5b06, 0xbe3f8a6e, 0xb3e3edd3, 0xace5a5eb, + 0x100c2ae7, 0x7d83d064, 0x773a63ec, 0xe3014824, 0xfaf2fba8, 0x789862f4, 0xcd307596, 0xeee1b566, 0x41d81174, + 0x12a9672f, 0x8812cf01, 0xfb217b40, 0x2ed5f6a5, 0xb374f09a, 0xf4169099, 0x4bbaf01e, 0x65bfc71a, 0x03003a66, + 0x0b46a9d5, 0x922405cf, 0xcf68a332, 0x36d1cd52, 0x6ac90a6a, 0x0bb4ffd0, 0x65d92d08, 0xb68c35f5, 0xc1bcaf87, + 0xb41d1aed, 0xd6eb71b0, 0x419d5fa1, 0x7a0d9573, 0x51d9c5e7, 0xd1d9fed3, 0xfe37d31c, 0x8a80f948, 0x309b92d0, + 0xec5d25c6, 0xcb0a00b8, 0xbeb7ba0f, 0xfb9652e3, 0x103bd8cd, 0x9baec4a6, 0x188221e7, 0x08e85ce1, 0xcde0a08d, + 0xd51b898d, 0xd33d37d0, 0x741f76d1, 0x88bd31e1, 0x385a7487, 0x36ecc2a1, 0x363dff64, 0xb600105f, 0xa71cb348, + 0x55eca11e, 0x943a2302, 0x6aec5110, 0xc64d2e44, 0xfd266672, 0x689ccf78, 0xe8146f27, 0xf2d5fc6b, 0x1f2dc544, + 0xebddb78b, 0xac6869a1, 0x79309295, 0x20872a42, 0x7e61d758, 0xf03d19dc, 0x39ce62d0, 0x32418856, 0x96b69415, + 0x7fa7f94d, 0xf4b13e9d, 0x9272363c, 0x8e781486, 0x95bd13e8, 0x3b02b9a3, 0x921b050f, 0xe1256486, 0x89ccfb10, + 0xeacf6c49, 0x27746273, 0x9824f7e2, 0x3b4b8045, 0x23fdb700, 0xba233381, 0x44e497d1, 0x0412738a, 0xb204d208, + 0x2b83e7bd, 0xe92e25a5, 0x4dbe7501, 0x886efbb5, 0xc9c95c50, 0x4cebf915, 0xd21c2c9a, 0x7b3c296d, 0x78e9e2ff, + 0x91f6a710, 0x528eed3b, 0xd8adee06, 0x042d35d6, 0xf2c22f2c, 0x0b1f778f, 0x67af4254, 0x3d11d965, 0xf66bf928, + 0x21aeb863, 0x7a676f47, 0x4d32ec3b, 0xdfd06051, 0x54c2438d, 0x9a134730, 0x3f7120b2, 0x1a99ca5a, 0x43c08f9a, + 0xde5f7921, 0x21076fc1, 0x8cdccc14, 0x8b3cef62, 0xdc7ea1ac, 0x2fcf0cf8, 0x14568718, 0x28ca658e, 0xbfa7714f, + 0xf5b82b2f, 0xc71246fb, 0x17dd9133, 0xb6049fa2, 0x4845a6cc, 0xaf15e692, 0xc3e26dd6, 0x7ac4dd1b, 0x90aafc55, + 0x86493c3f, 0x001c5cc7, 0xb41e278b, 0x0bc5f7cc, 0x3230f454, 0x20ad625d, 0x2face16c, 0x1c544552, 0x4b8e0d01, + 0xba651965, 0xbe3f4e3d, 0x28aa438e, 0x461e70c2, 0x65c32205, 0xed6171cf, 0x202fe798, 0x89623710, 0xbd8ad5a1, + 0x64d3b908, 0x27e22009, 0x45e1c149, 0x24257913, 0x3788eeae, 0x66eeef60, 0xbe677187, 0x26580ae8, 0x2cf08661, + 0xb5870931, 0xbf81a3e7, 0x003e0d49, 0xad1fdc64, 0x0c164a53, 0xaac79fc6, 0xd6b7f1e6, 0xfd328cac, 0x6a8d0cc0, + 0x03c62f6d, 0x4e486de5, 0x5f31242a, 0x764bfa3f, 0xced84c71, 0x621c33d6, 0x55a15c4e, 0x6bdef73c, 0x54fc2ec2, + 0x7beaf598, 0x3c1a7b40, 0x5c8f56dd, 0xd4109aac, 0x157c1842, 0xc61b99de, 0x02b33320, 0x018ce43d, 0xd048a8fd, + 0xe10b550c, 0xb530b24c, 0x7d8fe0fb, 0x61d8d493, 0x67fd08fa, 0x2b8ef3c2, 0x971052b7, 0xf95613b4, 0x688783d8, + 0x471f7485, 0x5f8a4a3d, 0xcca97ae0, 0x47eca789, 0xed68513e, 0x4925003e, 0xaea50525, 0xfe35aab0, 0xc0b01202, + 0x903f6167, 0x88c603a1, 0x25ad2452, 0xd22420a7, 0xdf18df5d, 0xee4a2c1b, 0xa67e3d49, 0xcacb8872, 0x97577b8b, + 0xac9fed0e, 0x8882773b, 0x6ffbe6eb, 0x393157cb, 0x7c95011c, 0xf605a7e7, 0xa53151e3, 0xf1a7ecc8, 0x011ac2c3, + 0x8c4f4752, 0x43701f51, 0xf6d67528, 0x256469a5, 0x95267760, 0x13c88646, 0x0d80bc3a, 0x40f05621, 0xdc86e54e, + 0xe5a1fbb8, 0x5d84b4c9, 0x6e5b1672, 0x5efa3735, 0xdd89dfbd, 0xa7c65f49, 0x55817f71, 0x1d725043, 0x19299caf, + 0x52483033, 0x1d66b79b, 0xccb26779, 0x01c01a72, 0xe226d722, 0x8b2666b9, 0x878bdc0f, 0xaf1aa1a7, 0x1b000ad2, + 0xee51895b, 0xdd82d5ad, 0xacf4c1b9, 0x1d05f1c7, 0xc097a0d3, 0x6f7422f7, 0x6467c3c9, 0xcb0013f6, 0xd528a330, + 0xf0cfafe9, 0x322f266e, 0x2f7dfb8b, 0xd779c345, 0xa6a892b7, 0x2bc16b4f, 0x0f9db01b, 0x7e408e6e, 0xbe1681c1, + 0x3c55be67, 0x1effee41, 0xc7b73e19, 0x5aebe0c8, 0x92e1cb28, 0x93aca5ea, 0x7adc66a2, 0xd2dd1e52, 0x20beef6f, + 0x9e81aa87, 0x9cd5f991, 0x041ae6ed, 0xec8b04b5, 0x2f2063bc, 0x2a9a3386, 0xb45f596a, 0x4ba0cad2, 0xbdf6bd1b, + 0x202dadf4, 0x79868afb, 0xe0c38a18, 0x8c919ef6, 0x1872d975, 0x27c19d23, 0x91da2786, 0x30ef8009, 0xa7c16ce0, + 0x3b7811b4, 0x4529af91, 0xe397bbe5, 0x61b3d7cc, 0xfae95e7f, 0x8cd83b48, 0x0ed4a155, 0x0eee75d1, 0xf2e9903a, + 0x2339d8b9, 0x7e98ea35, 0xc54a50f5, 0x1edc0592, 0x2928ce85, 0x12ca8273, 0x785aed40, 0x0feec701, 0xda50764a, + 0xf9ae0b50, 0xd097c26f, 0x14c7925d, 0x0e37053b, 0x5113570a, 0x800db711, 0x29134bbc, 0x70c4d25f, 0xa49e0fbb, + 0xcec15226, 0xfe30ea57, 0x2cbcb6b4, 0x3ff3e28f, 0xc5676ed9, 0xf9653838, 0x978cfb7b, 0xfdc2b00a, 0xed6b384b, + 0x30241d5f, 0xcaeee2c6, 0x79ffca5f, 0x1c1141bc, 0x957d8b68, 0x074c8a24, 0xcce64c7a, 0x0b896a5f, 0xb001a370, + 0xbde0d646, 0xc81b958a, 0x0dcd0604, 0x8e3aad62, 0xfa0610f3, 0xaa859e12, 0x1b176646, 0xe6a03470, 0x81087246, + 0xc440f1c7, 0x9b87a9aa, 0x2b09fe4d, 0x091c2610, 0xbbf17e9a, 0x46e9adc6, 0x69ec0a2e, 0x64ed1e23, 0x93757216, + 0x33bb7732, 0xa7fe1c82, 0xd99c507e, 0x68cff3ff, 0x498bfeb5, 0xe3ebe3d2, 0x5d39410a, 0x87085e8c, 0xf1e213ae, + 0x22c02a94, 0xd96c1d02, 0x20554115, 0xf1569a92, 0x2551c94e, 0x24308464, 0x811d73d2, 0xa4578d61, 0xf79a67c9, + 0x9d968f68, 0xcd6ee19a, 0x7be037fb, 0x2b0f4c74, 0x002aa2e0, 0x3382b976, 0x1506d312, 0x49e30513, 0x68e46b8b, + 0xfc6c2eb8, 0x7ecd11ea, 0x6a50ae0d, 0x151b1246, 0xf2826a23, 0x2b4eceed, 0x67ffb615, 0x1ad98200, 0xc9cfb01c, + 0x49f57df7, 0xe5322c67, 0x099d0bfd, 0x8e6dc218, 0x91f535e3, 0xf2cb6912, 0x6f1ba893, 0x5c6b973d, 0x57c72dc8, + 0x8cfc52cd, 0x1e7e4e40, 0xfdbcf00c, 0xe2081610, 0xbfc28f82, 0xfa068b77, 0xab2521ea, 0x49dc14ce, 0x3b3264f3, + 0x59a84b4a, 0xa7d3c91b, 0xa22e3937, 0x04f3c703, 0xc6f441a6, 0x7590ccf6, 0x4f9d378d, 0xc22a1835, 0x7cb1fbf4, + 0x742bafe6, 0xa89a8fb5, 0xfa583c7a, 0x6c95ab40, 0x9802e1ca, 0xdeba6cf0, 0xc9e836ad, 0x7af190d4, 0x66716cf9, + 0x78cd2057, 0x8b96f164, 0xf16ead99, 0x1fd30d3f, 0x34af47b0, 0x51887c65, 0x3698fc6f, 0x0cfc7891, 0x7af5d640, + 0xf2d769e4, 0x1e51a9fd, 0x1b5dee4f, 0x5fdb9bad, 0x1a741fd8, 0xc71c9ee3, 0x6012ced2, 0x0bf5adb6, 0xb7d634fd, + 0x40c24d77, 0x8b7cbd65, 0xa74ef84b, 0xfb8705d6, 0xa7d99a61, 0x1f1fdbf0, 0x1e3dce97, 0xbd294e99, 0x707a324a, + 0xc6d2b852, 0x9cd899a6, 0x9ad7b7ca, 0x421d51e7, 0x6800acea, 0xb7b1c58c, 0x51cdd6a8, 0x2686b1df, 0x544f11aa, + 0x78d47b34, 0x6ed73a11, 0xd1c00b7e, 0xc1370fae, 0x488959d0, 0x1a89303e, 0xa0ae98c6, 0x5610fb2e, 0xa6e7452d, + 0x4ac5906c, 0xb506733a, 0x11384c61, 0x25ac32bd, 0xf93b1333, 0xf159b902, 0x96efb5a1, 0x0d6ddfc7, 0x0d02709a, + 0x8db7a7a8, 0x1f69f809, 0x60bf2268, 0x46a19fcd, 0x038d0c94, 0x433f4d88, 0x393233b2, 0x907f5e32, 0xb318c4a9, + 0x341ac29f, 0xb6c91a32, 0x0615dcec, 0xe5bd3436, 0x40eefc09, 0xb2446404, 0x68f0e21e, 0x9ac4edb4, 0xfe5046ca, + 0x649e869c, 0xfdcd3608, 0xf0f887dd, 0x069f215d, 0xb46b997a, 0x2524af47, 0xb62f4aae, 0x0fb4e1e1, 0xc5e85f04, + 0x32b40565, 0x0950c299, 0x257a03b3, 0x5dd0c6a6, 0x0a09a060, 0x95ea7090, 0xef08d748, 0x476625e8, 0x2d55d5d6, + 0x4f412599, 0x978300df, 0xa8672b7b, 0x4adf7eb3, 0xfa5c5a14, 0xa099db22, 0x753a9c99, 0xb7949cdf, 0x1501d53a, + 0xe074cb55, 0xf20227ea, 0x8c3158bd, 0xe82b885f, 0x3ed70362, 0x70ccf6c9, 0x85066a17, 0xbaf50542, 0x8118a224, + 0xf2632438, 0x50c04a00, 0xdde4da75, 0xb862428f, 0x9d017d8a, 0x5f6665fa, 0xd729f4c6, 0x6a978715, 0x65a11656, + 0x489d040a, 0x84efeccd, 0x616fc7c2, 0x4bc7082c, 0xbd6e06c9, 0x3813d5b8, 0x605531c5, 0xe53601f3, 0x819788e5, + 0xbd630b14, 0xec9936e8, 0x5e9181ba, 0x4f72854a, 0xb439dd84, 0x6ba84d56, 0x60c4a6ce, 0x86ffcc0b, 0xf4c66cc2, + 0xe1c8b0ed, 0x18e7a945, 0x3ba4732a, 0x5622e24d, 0xd5fab7ce, 0xf7dc3be6, 0x7da5cc64, 0x070a8019, 0xf4c23348, + 0xe0f75a3b, 0xa1cfcf36, 0x41664a39, 0x00b38573, 0x36555bc3, 0x77e0a515, 0xf811a1f7, 0x61452d01, 0xa55f178e, + 0xc169f9e9, 0x99cf4f36, 0x83d9cdc6, 0x223dade8, 0x6d33a03d, 0xa2442dd3, 0x4e0b334d, 0x57a0c204, 0xd6ae9153, + 0xe0f6a0cc, 0xdca31296, 0x49d5e72e, 0x6b09caf2, 0x54beff9e, 0x0cb97683, 0x25c9a0e1, 0xd96ea318, 0xc9e1d835, + 0xdc75e3d5, 0xf3bb7629, 0x99f4535c, 0x5421638a, 0x05977650, 0xeceb4c66, 0x5c4d89e8, 0xa0260843, 0xdfe1e413, + 0xb8e9fd2f, 0x2606ef2a, 0x50f5a34f, 0xaefc91ea, 0x3fcaba87, 0x52281134, 0x5653a3ab, 0xf71402aa, 0xdf8ea09b, + 0x95e5716a, 0x63bc6dc3, 0x39ae7953, 0x9aa65ec1, 0xc24efc7a, 0x293608e0, 0x40a0684f, 0x4006af1a, 0x86f9e8bf, + 0xf977446a, 0xbb877677, 0x577d8c4c, 0x6dc83a47, 0xe945527c, 0xa2ac88a6, 0x13d88cfd, 0xc8cf8b33, 0xf4975978, + 0x98a48a03, 0x49761698, 0x7640d532, 0x0a20fa74, 0x4dad8dec, 0x46bc5ba7, 0x4724f2e6, 0xd9f36611, 0x00121045, + 0xe4cbac47, 0xac08f16f, 0xd1d774a7, 0xea6ff8c6, 0x57cc896a, 0xe37f1a20, 0x4865c04b, 0xdf53c593, 0x65bf6780, + 0x80400589, 0xa63a0450, 0x0fe59add, 0xdca043cd, 0x66ba6cbd, 0x91af8c08, 0x69c8da4f, 0x245e7b3c, 0xef815972, + 0xda7d59e7, 0x222164a8, 0x9d5966dc, 0x9f677c44, 0xc5f0dd46, 0xc5c25b81, 0x77cc1a61, 0xbe9a9029, 0x7bf43e6c, + 0xae56b7ce, 0x875c4da1, 0x557d18de, 0x26b89b1f, 0x561424bc, 0x698f959b, 0x525324fe, 0x8b5ff4bc, 0x7bfd7f34, + 0x45ed6b2e, 0xffbabf0a, 0x6cae5315, 0xc55b050d, 0xb99d5797, 0x4eb6ff50, 0x8a7dd76b, 0x9ad1dce8, 0x2fb8844d, + 0xc0d72a1c, 0xfcaaf648, 0x7381bca7, 0x7470b360, 0x63359c66, 0xdfe8b6c7, 0x9aa4bbf7, 0x8579cdce, 0x9443c315, + 0xbf4aa4a9, 0xd32a44f9, 0x9d90bc88, 0x94eb928e, 0x21e35c91, 0x49bd2a0b, 0x56b418e2, 0x3b863134, 0xae5f2980, + 0x7162d98b, 0x3db49790, 0x8cc02cb2, 0xec8f1e60, 0x98790713, 0x9ad54a13, 0x2bf4917a, 0x77e05c1f, 0x1b974663, + 0x8b443f22, 0x7d84df6b, 0x79d3f498, 0xa96040dc, 0x05bfeb03, 0xd00c9d4c, 0xa69a6714, 0xd6aad713, 0x217e9116, + 0xc1ee0d87, 0x4f1303b2, 0xc8fad850, 0xa41554c4, 0x20b6c4c4, 0x7c06feac, 0xf178c786, 0xa26fb5dc, 0x1283b296, + 0xb5794035, 0x5f52043e, 0xb83b72c9, 0x9b79bd0f, 0xdeddd48d, 0x1bc8274d, 0xc7595692, 0x7d7c5f7d, 0x0e393f4a, + 0xf42ec4ee, 0x1050581c, 0x4a366384, 0x85bc409f, 0xf11d5ae2, 0x7dd1f264, 0x8d1b614e, 0x6c4dcad2, 0xbc3eaf7a, + 0x40dcbb64, 0x8bfb0298, 0x8d483b46, 0x23f61b9a, 0x56e59c4a, 0x63914d24, 0x13b746ee, 0x71c9d619, 0xcbcd6d34, + 0x4aa975ef, 0x81c9b225, 0xe6f2761a, 0x27229578, 0x200f89c3, 0x2cfebb22, 0xd3941744, 0x65e43725, 0xfc02408c, + 0x634973ec, 0xc2d6fb14, 0xaed1f9e0, 0x2d2e2032, 0x147e6378, 0x224f9213, 0xc96eb23b, 0x11a46741, 0x5a5c1061, + 0x212f1659, 0x21d5b759, 0x888cdd52, 0x55b4a6ce, 0x1e6be63e, 0x7fbd7708, 0xefcd874d, 0x56def04f, 0xce7413bb, + 0x9e5d6221, 0x9506d6b4, 0x442e13be, 0xf93be2b0, 0x93efe574, 0x47fc809c, 0x417a247d, 0x0306532a, 0xd4af0fa2, + 0xe37c2a97, 0xf6e29652, 0x1994a985, 0x258e9d68, 0xbcaf5779, 0x0c2f4e8b, 0x22810224, 0x97f4d996, 0xa3eb4057, + 0x6bf4b1d2, 0x7cb49923, 0xb63dac7b, 0xbff97085, 0xede7e31d, 0xb0bdf9f9, 0x67a94ce4, 0xa91c268a, 0xde1e4c28, + 0x3cc8fb7b, 0x156aff2f, 0xf2af6d28, 0xa4641e61, 0x8c6e1c4b, 0xb212eaef, 0x0cfa13cf, 0xc5b62d37, 0xf35fe5e5, + 0x170ee417, 0x607e8873, 0x4fa3be22, 0xb6a3ea80, 0xdd2ce532, 0x71224955, 0xdb5341a2, 0x5163b3eb, 0x6878e4ee, + 0x47d630ff, 0xd68c453e, 0x0c1014da, 0x26f6056f, 0x3ba62428, 0x292816ae, 0xb4567a96, 0xd3e8fc86, 0x5afc8450, + 0x841430af, 0xc2b9fde0, 0x5ccaa893, 0xf320a97a, 0x34d76334, 0x9ca7e4fd, 0xa104e83f, 0xbefa6547, 0xc2e3e5d7, + 0x78ba46ba, 0x91a32636, 0xc95a9f1a, 0xf74aad50, 0xf262df12, 0x0ec25879, 0xaa67bc81, 0xc8479639, 0x262fd7f2, + 0xded4292a, 0xf93a3519, 0x76d5ec59, 0xb04e5bd8, 0xb565fe2e, 0x499c9251, 0xce686873, 0x8b895c27, 0xb307257e, + 0x56d2e754, 0x02e7aa40, 0xd72f8363, 0x0ffa3a57, 0x5d1c07da, 0xe885ceb6, 0xe98f4fb1, 0xe83e8436, 0x1925de9f, + 0x8b080ef1, 0x2f8f740c, 0x80a2942e, 0x94c5d3b5, 0xb2d72573, 0x54395514, 0x1fe061d0, 0xfc15f69b, 0xad022e44, + 0x9853c0e4, 0xbb32e15b, 0x08992be2, 0xd4ab95b4, 0x7b93f18d, 0xae439b7c, 0x5f32b78c, 0x835afa7e, 0x29094bc6, + 0xd937fa43, 0x29672018, 0xfeb6f54c, 0xd1407a01, 0x5e6c4c71, 0x2400ca9d, 0x204cae72, 0xd671e7b4, 0xab29deee, + 0x4d7fb35a, 0xfa1b7c0f, 0xe5465a05, 0x3c1397f4, 0x0d638a91, 0x08ed0eb4, 0x0d2e3109, 0x934e5339, 0x69de1513, + 0x481a9321, 0xcc03b515, 0x010e6937, 0xcb68903e, 0xa3bb34c4, 0x05286439, 0x3c5b0099, 0xe4822505, 0x5b0f5e42, + 0x24a0ac3b, 0xdd4a2e53, 0x35b040ce, 0x95d92d06, 0xfb713224, 0x8c29ad6e, 0x05389700, 0x580f507f, 0x85595392, + 0xe25627c7, 0x2e012db1, 0xf184319f, 0xb08b8e83, 0xc40b7e3d, 0x13ccb151, 0x50cf66de, 0x54b591c6, 0x62d65a31, + 0x49c4fb68, 0xe93ba12a, 0x1e85bd79, 0x10c98bd2, 0xf9426241, 0x42d6cf4d, 0xe4beaa63, 0x5a47662e, 0x6259e8ce, + 0xae7e3d0e, 0x05fd1694, 0x2d1eb2bc, 0xf4507f6b, 0xffdf9bf5, 0x11a7732e, 0x8a9094f0, 0x0ec1c05b, 0xfb313d31, + 0x54876965, 0x043e4695, 0x4db42cdf, 0xb615f772, 0xd8147a77, 0x040cbc12, 0xadd06131, 0xfd6df804, 0xcf68093b, + 0x140934a9, 0x4c0ae0e1, 0x04eef5eb, 0x2371871e, 0x64003d7d, 0x44e28e84, 0x16bea009, 0xbb539e8e, 0x10de8d90, + 0xb33db88f, 0xa74dad98, 0x8d139de7, 0x9c47c2dc, 0x4cacc6d2, 0x4cc1ad39, 0x8a8016bf, 0x8b0261c3, 0xbf4850d1, + 0x6e0106dd, 0xc8cb79f3, 0x09e422e8, 0x95d05265, 0x8f9cd8b9, 0x283f1e9a, 0x265f562d, 0xf68a9160, 0x6b58d7a1, + 0xdb6089ce, 0x5248282b, 0x5d4bce78, 0x22518dec, 0xeec89108, 0xb6af7c0c, 0x12712265, 0x2eb8bfe7, 0x3cf94c13, + 0x3638b7a3, 0xefdd990e, 0xaa8b84d1, 0x0c2a9a03, 0xa45f7edb, 0xede07eb6, 0xf5042849, 0xde948387, 0xde833d43, + 0x48d4b67c, 0x55bd76a5, 0xe5972ee9, 0x290d80f0, 0x28515a4f, 0x2898e6df, 0x2d979455, 0xfb35c13d, 0xe81bce23, + 0xf1ba5d16, 0x2fca8b83, 0x883486b9, 0x9491efbe, 0xbc359a95, 0x5e2c4e9a, 0x6ba6622f, 0xaf0ab4b4, 0x015e2c18, + 0xe85fb332, 0x8c820036, 0x2e014254, 0x4b449dbc, 0x8a28c619, 0x9b9f51bc, 0x53a9e96c, 0x23c4f81c, 0x1b431f3a, + 0x27d9a7d4, 0xe033a3a3, 0x7769ac8f, 0xd543e4e9, 0x2fe68446, 0x4a45cc11, 0x2e9e6538, 0x43870428, 0xdd16e76f, + 0x7ae493f2, 0xa87b3f63, 0x018a8dd6, 0x430e5b1b, 0xb773072b, 0x01d4d716, 0xb7af1878, 0x715c6cd5, 0x8fcd7d78, + 0xbf55223f, 0xe559d7d9, 0x0b28aa07, 0xf951c6dc, 0xbd94458d, 0xf161401d, 0x3b5e0c0c, 0x1016c26a, 0xa5328fc6, + 0x2a3f2d03, 0x61264919, 0x9bb46e89, 0xffd4f136, 0x679ec805, 0x33098f50, 0x9386cae7, 0x63bd391b, 0x359621b4, + 0x7c44637d, 0x9062f529, 0xd1dafee5, 0x257610b9, 0xc054b5bd, 0x7a012639, 0xf7007084, 0x49b784a0, 0xf8b72bcd, + 0x94761374, 0x39359287, 0x41ee00a0, 0x8e4c4708, 0x1a270e6f, 0x22fd89c0, 0x274c45af, 0xa1ecf86a, 0xea2bbb7d, + 0x40257a97, 0x913462e2, 0x820b2ab8, 0x52f179eb, 0xa247d625, 0x85ff01e8, 0x0bb127dd, 0xfef5fb22, 0xada4f4af, + 0x35adc60e, 0xebc8375c, 0x2e38dd78, 0x5a61926a, 0x8a85175d, 0x27beadab, 0x248481a2, 0x0835dbb2, 0x05d0a83c, + 0xaffb3dc7, 0xcd95c8eb, 0xf253e7f7, 0x4fb1f394, 0xffb5b26e, 0x79e19fa8, 0x5f6390ab, 0x4fc547d6, 0xb2a23409, + 0x70997e20, 0x07fa5d06, 0xb552e300, 0xe1f7169b, 0xb8305893, 0x124595d3, 0xc1f8a38b, 0xd2099783, 0x7a4e4bfa, + 0xab786224, 0xb320ceed, 0xecf942ff, 0x4cf6e87f, 0xd2a09e89, 0xae29e1e4, 0x1156f275, 0xcac665b4, 0xb2fb6ccd, + 0x5c2b4667, 0x8ca10e94, 0x056de73d, 0x47bcea7b, 0x2b75cbad, 0xcc126a72, 0x759540b1, 0xd38b3b74, 0xedecd36d, + 0xd962642c, 0x5aa82f7b, 0xe2c2d91e, 0x5d57ac7f, 0x4b59963b, 0x3a929c5a, 0x026308bd, 0x8a4bdf65, 0xd0591e6f, + 0x8a35a1a6, 0xc9cc9679, 0xde358258, 0xd6a379f2, 0x67deea60, 0x3186058b, 0x26132a90, 0xa02b007b, 0x1c5573f6, + 0x26325fe5, 0x93b7ab43, 0x5ccba4e9, 0x5909ae29, 0x3742e4e0, 0xf1b2797f, 0xd340340f, 0xc5844cc6, 0x2dfe8c5c, + 0xdc8d2960, 0x4264da48, 0x96558d91, 0x588bdc9d, 0xb18cd44a, 0xa8a91d73, 0x9fff0d13, 0x790fa140, 0x4c4a31bc, + 0x317626cd, 0xcddf2c54, 0x1afd90cb, 0xdd42ec9d, 0x87fd19e5, 0x683cb15f, 0x2f602491, 0x65274dd6, 0xfa4eb86d, + 0xbb8a392b, 0xd5cb01f1, 0xf0d3c169, 0x0d3f2f53, 0x85e17ffc, 0x794096f1, 0x966b5b50, 0x6b5d384b, 0x6001d2ae, + 0x4af25be9, 0x58deb9a2, 0x3e34d780, 0x0b6117d5, 0x396ea7dd, 0x25eb2111, 0x197b72ff, 0xf6eb1a12, 0x0eb16fe8, + 0x0f0bbe6f, 0x0cec3015, 0x5d77fe10, 0x757836b0, 0x6e5da73d, 0xb45d9e88, 0x77bdbbc8, 0xa3cd65b5, 0xcf9de0f3, + 0xdbd55e14, 0xc676a34e, 0x84738342, 0x05b9cefe, 0xb1b370dd, 0x9f570246, 0x80762b30, 0x1e846518, 0x8605d89f, + 0x25e9344a, 0x28f5cd1d, 0xa4d69e57, 0x9ac0298f, 0x9ac9cbf2, 0xbb786cfb, 0x09bb59e6, 0xe003391a, 0xf2d78b2f, + 0x49f11677, 0x581d9fa8, 0xd888979f, 0xdeb80ffa, 0x6de97436, 0x62f91c63, 0xf57e088c, 0x9119294c, 0xf0f51e5a, + 0x6b82e831, 0x6d319573, 0x869d3940, 0x16a89b83, 0xaca27d6b, 0xee7df749, 0x93e9bc02, 0xf049f0ad, 0x316cfd2f, + 0x2d10fd02, 0x13b5e137, 0xc52ad261, 0xd770dce9, 0x281a7391, 0x249d8e3c, 0xb659d8b8, 0x205dd247, 0x73ab71f6, + 0xacbbcc9a, 0xeff80dda, 0x00a7197f, 0x5f4c0dd4, 0x35eb8512, 0xe9f70995, 0x5be698e7, 0x40c122a4, 0x2d5d3f50, + 0x7ec716ea, 0x911a7aea, 0xaafcfc68, 0x56b1d5b7, 0x0ea79373, 0x925a7328, 0x4122a1b9, 0x4902fe24, 0x9d10ad1a, + 0x54b99496, 0xd67d0088, 0x83ff037e, 0x1d6d73ef, 0xd44c448b, 0x0575a9d5, 0xdee75dd7, 0x7d13b31f, 0xc8938539, + 0x944ab93f, 0x7d0a7936, 0x00571c6f, 0xb2de0a71, 0x15e87034, 0x04a87dd4, 0x37972780, 0xd866fe76, 0xbdfe1ef8, + 0xada4d2fd, 0x29402246, 0x79e641df, 0x4214852f, 0x3ca272ab, 0x56073f1a, 0x2e3ca5c1, 0x7252399e, 0x826799ca, + 0x524acfd7, 0x4344c6d2, 0x12ec2357, 0x507c8898, 0x9a71dc35, 0x8d02ac0d, 0xc0359b74, 0x70e9f150, 0x3b0fb623, + 0x8191dbdb, 0x65d27220, 0xe7cd2496, 0x5e8a4923, 0xab20fbcd, 0x33c72576, 0x9eaa06a6, 0xfe78ca2e, 0xd185c71b, + 0xef3453cf, 0x2aa6eade, 0xd8609927, 0xc41db9a3, 0x642fbf6c, 0x774928de, 0xc5742bf9, 0xc348f1e0, 0x5f622259, + 0xe42b15e7, 0xe4b0b4ec, 0x97b974bf, 0x09c84a79, 0x84498689, 0x6bae0316, 0x56de20a7, 0x915b33ff, 0x934ae1c3, + 0x4d26116c, 0x1ca55372, 0xa9937f73, 0xa77129ac, 0x3e368f1d, 0x92d76384, 0x9b444176, 0x43e379e9, 0xe1973c11, + 0xfe8666cf, 0x025498f6, 0x773b43b6, 0xdf7aab9a, 0x79134c39, 0xb01557a9, 0x038eff48, 0xa04bbbf0, 0xf1e3f127, + 0x1134eb7e, 0x0350691d, 0xc958cdc4, 0x785192ae, 0x49ee8e39, 0x0e8ed3b5, 0x2051e607, 0x9a1bd2d3, 0x4f4dd7d4, + 0xc85ca0f5, 0x4d50e548, 0xad243809, 0x279e3611, 0xe6d99456, 0x6e5fd488, 0xd604a584, 0xf7ce1835, 0x4f74fea5, + 0x9123d235, 0x521dfd41, 0xfad6ac34, 0x2130415e, 0xf79db5e6, 0xea91d2e2, 0xdef79296, 0x10f4525f, 0xa264766c, + 0x5ffa6904, 0x2dfa294e, 0xa59c1ea2, 0x1e7562da, 0xfd3ee88a, 0xa8188976, 0xa02cd46e, 0x31d0274c, 0xbb960bfe, + 0x6c3c02f4, 0x1450adea, 0xda5d22c0, 0x0925b910, 0xacc025c5, 0x3c476321, 0xc51ee799, 0x86a84aa0, 0xca7194b3, + 0x15136f57, 0xa0187064, 0x36befac4, 0xba8ef789, 0xf6356f68, 0x94e85e9d, 0xc04fc354, 0xab553a0c, 0x6e1c37c1, + 0x2e9ccbef, 0xca2adc33, 0x7797d493, 0xfeca8790, 0x758ad973, 0x3e75542f, 0xe277aecf, 0x7bd484d2, 0xa8742352, + 0x51853d23, 0x0af0dc80, 0xa6f26ae9, 0x617a9d94, 0x216f891d, 0x01f678cc, 0xc5c9e439, 0xc4652c79, 0xe7e6e051, + 0x00fd4e7f, 0x5ea58888, 0x332f3613, 0x05fce922, 0xafb98210, 0x83f431d4, 0xe9e66db3, 0xfe8eb679, 0xa443c58d, + 0xf85167e2, 0x253d3456, 0x2459ec96, 0xf78d2a1f, 0xad4e7afe, 0xcf818b57, 0x86e26668, 0xeec50163, 0x1000afc8, + 0x836ee004, 0xb162b091, 0x51c46e20, 0xbf3e673b, 0xd6f7f418, 0x6c7a8f98, 0xeeb9b7c2, 0x4813f3b8, 0x61cf30f2, + 0x369404e2, 0x96e67888, 0xa35d152b, 0xe816576a, 0x163dec68, 0x2df7a361, 0x44cf8f05, 0xc8d410c8, 0xf5683c2e, + 0xcbb22f3b, 0x993de905, 0x5df24ef2, 0x913d34eb, 0xf3a7c02c, 0xf3e47c5f, 0x1737f9cc, 0x289f135e, 0x99ce936b, + 0xf6e13309, 0x7baa4dea, 0xd36f4782, 0x565c1617, 0xe130dcf7, 0x5f6a6a5e, 0xd88de3c6, 0x194e3ce1, 0x331d1158, + 0x7675fa96, 0x45ac186e, 0x83a5c702, 0x3600d6d6, 0x564145f4, 0xfeea0371, 0x5e8a5bb5, 0x026c7bff, 0xd210095f, + 0x83f2f153, 0x52b5e5ef, 0x5d40c093, 0xa504511d, 0x07eae55e, 0xa4cb8a8f, 0x6d791859, 0xef775b04, 0xd80c41b4, + 0x5015236b, 0xffe10e86, 0x95bb3bfb, 0xa31865f5, 0x8a54c941, 0x3b035b0f, 0xc04e8c31, 0x6306403a, 0x5de0060f, + 0xb72db725, 0x3f269b48, 0x2656742b, 0x08486e3e, 0x48dd5af6, 0xd261d482, 0x56cabf7f, 0x8c783249, 0x7c61b490, + 0x6a7b5dc8, 0x82acbb90, 0x0ed7df1f, 0x5248a389, 0x8f52b66e, 0x47b32fdd, 0x1f8966e1, 0x23f5c15b, 0x984399aa, + 0x2401a27d, 0xe87bedb5, 0xb386e0ec, 0x4ed865dd, 0x5e2acd43, 0x28622e4e, 0x7b4006c1, 0x8c15d264, 0x770bbe1f, + 0x92f353c5, 0xd002e3b2, 0x1c382623, 0xd1b1ca27, 0x1fa0344b, 0xb9e51435, 0x2ae0f052, 0x217591cd, 0x3ab80cbe, + 0x3a91fdd4, 0x4bfc9822, 0x922b1ce8, 0x3880bb6e, 0xc16c0367, 0xcd062d1f, 0xe548c3db, 0x8d474e43, 0x21aa1188, + 0x2a5696c8, 0xa1655d08, 0x8c06d45a, 0xb3d4362b, 0xef0268ce, 0xf16b2c37, 0xe3209770, 0x7aff5c00, 0x40191678, + 0x7b9b0fb8, 0xdbe0098a, 0xc4dc7573, 0x91da6e88, 0x0b0df673, 0x7f73ed5a, 0x317da33f, 0x029847fb, 0xf131fba6, + 0xe67f6e69, 0x4ff0bc07, 0xe984c432, 0xfbe0f349, 0x5520c08f, 0x623e911c, 0xb6df06d9, 0x78b49be3, 0x589108f9, + 0x299ff472, 0xd760d865, 0x6df8fac3, 0xaac6563a, 0x472bb4da, 0x77985605, 0x7131987a, 0x4c9a6236, 0x3f18f649, + 0x3eb29f3a, 0x13ca458e, 0xda2bb7a7, 0x9bdb3fc7, 0x5a0f7384, 0xc5ded2e6, 0xb97baf5b, 0xfd0d079c, 0xee61ad46, + 0xeeb03554, 0x26f5062b, 0x578021e0, 0xb34b7112, 0x3ccd03cc, 0x10578a41, 0xe135d3b8, 0xa02cb5ee, 0xb7900396, + 0x556815fc, 0xf2ba4996, 0x871cbc14, 0xc060509a, 0xa2db4b44, 0x29b4353b, 0x7782dd5f, 0x12ac0e7f, 0x7c367e0a, + 0xdf9f3382, 0xbb8e2dac, 0xb8d165b1, 0xb8bfc1e7, 0x54bb0b90, 0x7c171897, 0x0c8191c5, 0xc4e2a59b, 0x5e82bb1e, + 0x56b7c594, 0x126ffb6c, 0x5e47e2a4, 0x7b98691a, 0x6f0f6ebe, 0xec6afcb0, 0xdf6572f7, 0x4a24c987, 0x1db815fd, + 0xdcd74928, 0x1afb9b0d, 0xb8f76a7a, 0x51465e13, 0x337cd422, 0xe5edeb4b, 0xcdcc5657, 0x9f70a5c8, 0x6a2d715f, + 0xc1ea7fd2, 0x7a265c60, 0x393a166f, 0x89f83701, 0xe462cb64, 0xb9e91d1a, 0x5cff7a81, 0xa49cc71d, 0xcb41396b, + 0x3716d45e, 0xb4b91537, 0xce828f0d, 0x008b562b, 0xc6184ff2, 0x916705dc, 0x95b25f6d, 0x648d5e6b, 0x8d6759b6, + 0x612e2ede, 0x4bcdd140, 0xfd51f2eb, 0xfdd573fb, 0x8f2a15e7, 0x962d45a2, 0x7296ed66, 0x2a34fbb8, 0xae4a33de, + 0x33463e76, 0x28b4983d, 0x77920442, 0x632df6b1, 0x4463561d, 0x00cb33da, 0xc568ff61, 0xc70fd0c6, 0x120858f9, + 0x3ee247bc, 0x787dc1c8, 0xc519b8ae, 0x57df88a9, 0xf0e8bac3, 0x8980575c, 0x113e1165, 0x55a3ee9f, 0x73594876, + 0x20973ebb, 0x438bd839, 0x45b80b93, 0xd2bddb42, 0x2a5d365d, 0xb6384c11, 0x1f75bb5f, 0xf4c58bce, 0x81797e8a, + 0x75c40e8b, 0x50ba9476, 0xfeffc3ca, 0x78249cb4, 0xdb298c18, 0x6c4bdd7f, 0xf7424bd2, 0xd678502f, 0xe301c107, + 0x75a5b9a1, 0x7e0c6604, 0xc3cd91b6, 0xc5027fd3, 0xafd7a7af, 0xc760c8bd, 0x22309cbc, 0xcc8dc132, 0x115d0d9e, + 0xd751c735, 0xd430a0ec, 0xdb85bd81, 0xe96b4ad9, 0xad35ea0f, 0x398af11e, 0x2fe63a26, 0x4712b677, 0x8b85ca6e, + 0xc1b059aa, 0x79529802, 0x7114c7ba, 0x1a8c7b71, 0x34b4e612, 0xafcb1fae, 0x931a9d75, 0xd8bbd43a, 0x1abf431c, + 0x7a21736d, 0x2dfa83ee, 0xe3ea1035, 0x62099f3f, 0xf3082cbd, 0xd182badb, 0x05464564, 0x857318bb, 0x57307065, + 0xcfe3cdfe, 0x44cdfc87, 0x8bddfa63, 0xe1cca977, 0x0d22f38f, 0xa6b65f6c, 0x2f2c8ee5, 0xc98143cf, 0xa1fff0e9, + 0x85eb9841, 0x6d1daf21, 0x2e8e1827, 0x3d253f7c, 0xe55f231d, 0x319da0ac, 0x3d83fa61, 0x7daf4548, 0x191753dd, + 0x971c56fc, 0xccc5d6de, 0x72357d54, 0x1aabd32b, 0x08ae6b9b, 0xd8917d9b, 0x196e67fe, 0x49b9d4fb, 0x037c12e2, + 0x48983fdb, 0x69dbd643, 0x5a72d02a, 0x37b19870, 0xe05db444, 0x36c86783, 0xacf963a7, 0x261a6392, 0x15831cca, + 0x5eb7573c, 0x8f2aacd0, 0x7c480012, 0xc1ac95b7, 0x0a0ff96a, 0x9ca00f46, 0xd9e37352, 0xc7d5e8d4, 0x0cbdf546, + 0x67657657, 0x9b98103a, 0x375aa95b, 0x765a9355, 0x79f7937f, 0xe69f99b3, 0xc78223c5, 0xc2f31bcb, 0x3907591b, + 0xc4010de7, 0x738056c3, 0x5c04e508, 0x3f51939a, 0x9996a48c, 0x8fe0ce46, 0xaa2fe534, 0xd6ce8fb9, 0xa352f21d, + 0xdae69899, 0x5b0db716, 0x54951ce0, 0xde28dd07, 0x8b8942e1, 0x13d7e149, 0x517cfe8a, 0xed64252c, 0x8a8a4631, + 0x6fad5d07, 0x3c578209, 0x20469ae6, 0xd0db5fdd, 0x50289c7f, 0x4a497bb9, 0x1f2ef6fd, 0xa6ea352e, 0x0f096f6b, + 0x413c151d, 0x3a67ce8b, 0x4e96905d, 0x866d00fc, 0xe7395103, 0x39e7f10e, 0x2d9a7cbf, 0xccc9719b, 0xb64fa295, + 0x88ff7018, 0xf00dd8c9, 0x75e6af11, 0x2b197f84, 0x0fe6d084, 0x48ea0093, 0x8638737e, 0xff496693, 0x47d8ce43, + 0xb15258c6, 0x4f2e8856, 0x4fe55b63, 0x2e0be6ba, 0xffaee470, 0x619f6c1d, 0x3c930784, 0xb1a79209, 0x73a464cd, + 0x38cad443, 0x994725ea, 0x7b0c0c44, 0x8ecee008, 0xe3702baa, 0xfb17345a, 0x0223a7b0, 0xce806057, 0x2ad8a377, + 0x16109bcd, 0xe6ee1a67, 0x663dbd4e, 0x006763c8, 0x40eadc72, 0x39ae1a23, 0x6b250b66, 0x11d00f2a, 0x017a7f4e, + 0x50c328a1, 0xc4c4273e, 0x4724df4b, 0xdea8d389, 0xe3ca0b03, 0x21ef90d4, 0x1ac54a4a, 0xbe87c860, 0x444253a6, + 0x59f4c7f2, 0x8baad3d8, 0x15f1841b, 0x3ee0e707, 0x713e3376, 0x6b5cdc71, 0x5185d3b1, 0xbce9bd5a, 0xc4485a84, + 0xadebf1b9, 0x68dc9d91, 0x4ccd0fb2, 0x20f0f776, 0x56072c4f, 0x205ffd54, 0x0cb9b15e, 0x11bc2126, 0xe1d739a2, + 0x6285b6bb, 0x8e9d1625, 0xf686912e, 0x0d0d9b44, 0x044e0400, 0x848b0202, 0x1c60e641, 0x3b1d59a2, 0xf524ef83, + 0x551ea347, 0x5925815d, 0x050e375a, 0x6fa4da2c, 0x6ea732cb, 0x093f0da4, 0x60422eff, 0x98fb015e, 0x474565c1, + 0x575d85c9, 0xd5426b4f, 0x0073ca73, 0x577a60d6, 0xeb3e15da, 0x19723534, 0x3f664a72, 0x51a5d990, 0x681044e5, + 0xd4d67dcb, 0xcaa2d54d, 0x8ec19b8c, 0xed712ef2, 0x489dc7a4, 0xeb6f588c, 0xb5d29b93, 0x2cd82a27, 0xc7aed4d5, + 0x8ffcd692, 0x1b3fab62, 0x58d28a64, 0x76b52fde, 0xaed14471, 0x58c15d2f, 0xd6e0a409, 0xd49c03b5, 0x4087ce9f, + 0x41f06bc6, 0xd9c88d0e, 0x0d887d78, 0xf748c0db, 0x35822763, 0xe4c0fe55, 0xcc3c5414, 0x88180f70, 0xc9b88a07, + 0xb7e1c39c, 0x9e9aee38, 0xa79a7db6, 0xab334d92, 0xd9af9640, 0x56146167, 0x6b154ad7, 0xd2865221, 0x0432482a, + 0xc3d242dc, 0xc88104e4, 0xfd40ec21, 0x279df0b2, 0xad9523f6, 0x0cf1ff6e, 0xd1bdd751, 0xc96841b1, 0x8eb0d6a1, + 0x9b0bde97, 0x4de5f7c8, 0x07c19fa1, 0x195efe69, 0xb29a18de, 0x2982177a, 0xdb1d28a1, 0x345a3946, 0xda48fb97, + 0x64f61756, 0x7affdf99, 0x50eca15a, 0x0d1cf730, 0x227aefab, 0x282a7284, 0x83d114e0, 0x01492370, 0xcc11ea57, + 0xbffaa2b3, 0xaa08ccca, 0x1f0a612a, 0x5edc293a, 0xbfd5906e, 0x3811f791, 0x60d5c352, 0x7a0e3439, 0x66f1e40e, + 0xd50b8986, 0x1f6a1328, 0x51fcb17c, 0x6d22a697, 0x522c243b, 0x9792961f, 0x0c2e3c76, 0xd5a988d2, 0x2a8dab97, + 0x420ccddf, 0x2777cae8, 0xcec3838b, 0x6e704b31, 0x074aff34, 0xdebe6cdf, 0xd407cb75, 0x3de95ef6, 0x7c3a3642, + 0xcf93a10c, 0x5647f984, 0x5c789a42, 0xc862876b, 0x89e0d973, 0xc2e57494, 0x643c12a8, 0x6d88ccbb, 0xd6b627a9, + 0xda6111cf, 0x6b0cba4d, 0x1016706f, 0x18348ea5, 0xa2bb3c8d, 0xea2e64de, 0x4284e471, 0x2ce992f9, 0xc221d35f, + 0x0b84d556, 0x16ac9c50, 0xfc0f37b7, 0xdcfe6771, 0x824c16d2, 0x54c6ec44, 0x3466ea28, 0x0f9f8633, 0x6148d6a6, + 0x337d5a5e, 0xd42fd3f5, 0x89da51a9, 0x1bcdbc18, 0x2b48b4f6, 0xb736cc02, 0xa12153ee, 0x005eca88, 0x018e579b, + 0x07dbdc91, 0x87be77c4, 0xfca3a212, 0x083d1117, 0x4c304f21, 0x1a947e88, 0x18265d73, 0x180ed91f, 0xd7cd3482, + 0x94239b44, 0x6a842c3f, 0x2bbe3ac2, 0xec78c6af, 0x4f04f1de, 0xb2a88ed1, 0x61bb3fbf, 0x0b327910, 0x7a7006f4, + 0x3da174df, 0xbc4293a9, 0x01127aec, 0xd16dd0c7, 0xd75fe022, 0x9f431063, 0x85008f22, 0x6afdd43b, 0x3e7521de, + 0x0daef6cd, 0xe043d482, 0xe4fb2747, 0x717b23fd, 0xd4fda094, 0xcc2e80b1, 0x1e585a08, 0x580345d0, 0x43f8b7da, + 0x7748d633, 0x24897b78, 0x7a283d16, 0x0bd182cc, 0xa274d645, 0x87635b1a, 0xa2ad763a, 0xe257b642, 0x3f47395e, + 0x5fb54a11, 0xb50df874, 0x7d3356dd, 0x0b632d0e, 0x19472678, 0x13c2ba9d, 0x0510d277, 0x8e1e2f27, 0x05ac228b, + 0x6e267487, 0x71cb40f6, 0xc30180ed, 0xa63487d1, 0x6bd40769, 0x6aea29b2, 0x01893e74, 0xcfbb333b, 0xd59551cc, + 0x501abc0f, 0x66f08deb, 0x56c1c841, 0x1f6f93cb, 0x0137d6c0, 0xf4887d6e, 0x000f9d45, 0xe3974ada, 0x2fe0ba70, + 0x9446e446, 0x6a10f08c, 0x51f53628, 0x0d8e5d9b, 0x484036ab, 0x232c6cb2, 0xefd23018, 0x340ae825, 0x7ff3c91d, + 0x23262327, 0xc77d7faf, 0x63e78811, 0xcfc9d06f, 0x4cb6520c, 0x7f5ea6f6, 0x1e667fb6, 0x725c03af, 0x9f01310b, + 0x231fab72, 0xbaed3d73, 0x988348d9, 0xca9dca15, 0x02641d02, 0xd4808137, 0xc57f58ba, 0x4cfcc9b4, 0x553cf356, + 0x9f451d06, 0xc397eb86, 0xcff1d8a0, 0xe19aabaa, 0x8beccd68, 0x0cb4d017, 0x2f366828, 0x8a3f5424, 0x2bfe080b, + 0xf4bb3cee, 0x1c389176, 0x6d760a6e, 0x456b2c29, 0xc4564718, 0xebe27399, 0xa802e63c, 0x9b11db4b, 0xffcaa353, + 0xec9368a4, 0xf4df6bc5, 0x07da77c4, 0xab4f9e09, 0x67389b2a, 0x87d3893a, 0x89ebe4d6, 0xc9cb6857, 0x3b1e4b1a, + 0x4a3fcd10, 0xed41d38a, 0xbbbc56b2, 0xe21c8fc9, 0x327077e3, 0x15738114, 0x0db94a5f, 0x1c1d3670, 0x6aaff454, + 0xe8973eb1, 0x7afa2cd4, 0x14952a70, 0xc15368df, 0x8540a154, 0xebb76eee, 0xd1bc1d2c, 0x2c4e10b2, 0x5a988ea0, + 0xbd823881, 0xd34e4a1f, 0xaabd6734, 0xb4804f4f, 0x93f8f18b, 0x51f41b5c, 0x6117e07d, 0x57acefdb, 0x1763f3a8, + 0x382877cd, 0xa94f8a0b, 0xca9875c9, 0x72932ed4, 0x5515c8e7, 0x0139b898, 0xe0541e27, 0x42d39a51, 0xf5ad7c5d, + 0xe1b3b119, 0xd74e45fb, 0xe0f2c6cb, 0xcc1e9303, 0xa0adfb49, 0xafab7417, 0x93e7ceb2, 0xaf90ee7f, 0x1ee8f861, + 0x059048b1, 0x78fd9b1c, 0x684cdfec, 0xdc704b2d, 0x717f7bcf, 0x0920fa94, 0x2bb09704, 0xca9a1d39, 0x81f734a6, + 0x6b729e09, 0xa777a8e5, 0x250e5075, 0xd7afe06a, 0x49376130, 0x1a927b35, 0x3d4702ed, 0x5026b9d2, 0xd086eea7, + 0xb649c654, 0x0b5be24d, 0x7b6d8c3a, 0xdee394a0, 0x7fd93b46, 0x01c74fc7, 0xc74d94f8, 0x695a9e1f, 0x4567a03e, + 0x77e1488d, 0x9a32acce, 0x45620508, 0x8b4c59a0, 0xe42c0468, 0x5339d895, 0xe36d1d4b, 0x98946ef8, 0xd6fbf34a, + 0x0e2e508b, 0x239d60d9, 0xd64671ee, 0x2a1caa57, 0xa8e29fd4, 0x4893c391, 0xc136f3a1, 0x0224e548, 0x014632d6, + 0xd47a91fd, 0xfc961009, 0x42245a8e, 0x0b7b1a00, 0x093f2621, 0xfbea66c5, 0xdab3af98, 0x583f266f, 0xe8eb2750, + 0x4a7a8c24, 0x7407949c, 0xb36dd109, 0xc2e9269e, 0x1970f963, 0xca4558b9, 0xa28c3ea5, 0x448890b8, 0x8ae60804, + 0xfb4ec9b1, 0x797ef4cc, 0xd1622465, 0x1f3a5fc6, 0x23f8a6ca, 0xb2a5d742, 0x851c8ffb, 0x17bbd053, 0x90002af3, + 0x550b5a10, 0x87885088, 0x4545ebcc, 0x363a81dd, 0x43ce24f0, 0x35becd5b, 0x5acc4595, 0x68251b06, 0x59661b3f, + 0x7fda874e, 0x8963368e, 0x46162091, 0xb400340c, 0x774db875, 0x0855087f, 0xdd65cdd8, 0x3b0e3fc5, 0xb000fb29, + 0xf0b75954, 0x42546ef5, 0xa581b034, 0xa17c26b9, 0xf6e6c5c2, 0xd9815059, 0xeb968380, 0x17f5f067, 0xdb153eb9, + 0x016053d5, 0x2defbf19, 0x9fe7f708, 0x4590af8c, 0xbda9b6c0, 0xab1edc25, 0xf30d18ef, 0x22010db9, 0x9d5f1757, + 0x5e54b120, 0xe023d84c, 0xadcbaaa1, 0x686cf4f3, 0x395fe0c9, 0x8274b97f, 0xed5de2bb, 0xab6fda71, 0x2878e57a, + 0x518f3604, 0x461171c2, 0x81ce74dd, 0x9eacfc35, 0x4e8e1881, 0x94e84fc7, 0x65b31508, 0xae559d6d, 0x05af1637, + 0xa30c25fc, 0xf7fb56f9, 0x1a6ce1c5, 0x07dcebcb, 0xa02477a6, 0x9ec07a4a, 0x133dbc66, 0x0db26acd, 0x6a368f5f, + 0xa3615211, 0x065e7b54, 0xe76bc48f, 0x09b639a8, 0xd64e7d3e, 0xcf442d22, 0xbf8bd81a, 0xdef4adaa, 0x674e1912, + 0x36baa6d2, 0x2734c747, 0xa34c7789, 0x32de65f8, 0xb49a34eb, 0x32990c2e, 0x3f64e864, 0x062f4381, 0xc0544063, + 0xd86fea48, 0xd6bf1c01, 0x907c2e31, 0xbe6e36c7, 0xd88598de, 0x36212b8b, 0x7cc69329, 0x3f7f6b7b, 0x711792e0, + 0x7f00e9f5, 0xdbcf7d97, 0x5836f3e4, 0x6ec0b48d, 0x8915ec7e, 0x5c72a18c, 0x80b9d943, 0xc2e0d74f, 0x9c3f107a, + 0x4d9b0c22, 0xd877aa95, 0x1f3d961c, 0x5a755977, 0x06c0a4fb, 0x20d2d809, 0x04bcb1e7, 0x4c1e20eb, 0x3066eb83, + 0x3185701f, 0x52fc49a0, 0x38b9ca26, 0xd17b6791, 0xae89fca1, 0x5c1f5d3d, 0x82a30cbf, 0xcba96c14, 0x0836e6b7, + 0x9256c8b4, 0x07bae388, 0xbbdc8416, 0x5b1dccf7, 0x47e226ce, 0x097a7edd, 0x153d11ec, 0x8a44759b, 0xf496a1e4, + 0xc022309c, 0x413283a7, 0x29632304, 0x24d760ce, 0xf9c74d39, 0x13944a09, 0x9fee5c54, 0x0eb5dcba, 0x7a60ca4c, + 0x0b59e364, 0x69759721, 0x0c9b95b5, 0x3fe1b2fc, 0xd2a1bc47, 0xf3734392, 0x15525b6c, 0xed21f794, 0x7599006d, + 0x98ee011e, 0x610455f8, 0x20094b90, 0xa1a46ae7, 0xb6d87c17, 0xd978d4e9, 0x95aaecb8, 0xa576154f, 0xfcc65a5d, + 0x940d8cc4, 0x4e0cd0fa, 0xb4353342, 0xed6e0939, 0xf6f28bff, 0x74534389, 0x725fcf9d, 0x287a4670, 0x1d0f5237, + 0x772c351c, 0xc10dd65c, 0x3e0036b8, 0xd3290a6c, 0x513c1671, 0xde6b1234, 0x8de59251, 0x61c04337, 0x9ca9eda8, + 0x82568ae3, 0xa6a3a53f, 0xa9d0f9f3, 0xff5993ad, 0x92933bef, 0x16376670, 0x1d6aafcf, 0x77dd11ef, 0x8aa3d858, + 0x6373660b, 0xfeaf7817, 0x752fbe29, 0x44d33186, 0x376ca1f2, 0x64b43400, 0xbb42014c, 0x21b55bbd, 0xc96b3f9a, + 0x7b0cfc80, 0x772bd779, 0xf306ff50, 0xcdf92955, 0xe831b9de, 0x04b5ca36, 0xb9a5d130, 0xfa073df8, 0x8bf6f655, + 0x12825564, 0x644c837b, 0xd8944f70, 0x8dda2855, 0x290f0b79, 0xf0b5ddcb, 0xe39b41df, 0x1d3d3aad, 0x02ae04cb, + 0x3981f887, 0x9d5c23d4, 0x00c83058, 0x568e37a7, 0x3088e375, 0xf996b794, 0x2ac3af73, 0x4e868b25, 0x7f46833e, + 0x9b8d2ea2, 0x9bacdbb2, 0xd6ed216c, 0x35e8698a, 0x827e18de, 0xc168bf78, 0x10d665fa, 0xe0cf48dc, 0xacc73f2c, + 0x65b355d9, 0x3bc883cf, 0x0c2377f8, 0xff61853a, 0xc079e404, 0x3e89ace2, 0xaf4109ed, 0x8d1fbf12, 0x205950af, + 0x0af69139, 0xfff0c63e, 0xe95fb3b6, 0x525a3e95, 0xd92eaf16, 0x1c7b720b, 0xc78480a1, 0xd721074e, 0x39c1b5cf, + 0xab73cb20, 0x12892b5c, 0x8ab25e66, 0xf88f5b5e, 0x517c729b, 0xb72a4310, 0x8f23164e, 0xafd459d4, 0x4380e646, + 0x1bf744c3, 0x213c3ecc, 0xe83a5c77, 0xf8f7e2a5, 0x579c906c, 0xa658b24f, 0x49292166, 0xe1a47763, 0x71a5ff46, + 0x60aab8c1, 0x73babc95, 0x2166e530, 0x1dbd14ec, 0x7cb4a3d9, 0x9ce7d6e7, 0xb7f60c9b, 0xfbb45cd2, 0xce5c1bb1, + 0x10d4c674, 0x0e5dea96, 0x6f6a397c, 0xddb5d148, 0x0a1d20f3, 0x7c6fc897, 0x4ad3d739, 0xdbd5d89a, 0x004d2776, + 0x9e8d3c58, 0xc05bb7f3, 0xbf7b1e57, 0x565d5819, 0x8fabe58e, 0xe3c12585, 0x5b100ba9, 0xcf769b67, 0x0e2c1e04, + 0xfda7f204, 0xe92fce89, 0x8708d2e6, 0x25b433a9, 0xda8199cb, 0x94a45e70, 0x811d08c0, 0x2c6898e1, 0xb73d4c7a, + 0xe6ebd6e9, 0x486e1796, 0x68304ab5, 0xee5d01a8, 0x31c3659a, 0x1b801e46, 0x863a57bb, 0xe0724e46, 0x3eca9491, + 0xcec2bdcc, 0x748079ea, 0xc4d317c7, 0xe695efb3, 0x5bcc2843, 0xcecccfc1, 0x57c77a51, 0x05684cb8, 0x0d38d3f4, + 0x8a48ad94, 0x3fea54cf, 0xe266b6a2, 0x690f4236, 0x1b235e66, 0x8c9000ce, 0x5ea79887, 0xe1a5014a, 0x79dfedba, + 0x2b1af9bb, 0x3ed51433, 0x5783c599, 0xee53a906, 0x76025e5d, 0x49a710c9, 0xc47d7646, 0xaabadcdc, 0x46ef7811, + 0x85a3c228, 0xb2af1703, 0x3adc7ea3, 0xb5b90686, 0x9b7d54fd, 0x1cb55200, 0x4d651149, 0x8832b35e, 0xe5f9cd42, + 0x10147bdf, 0xede30ff2, 0x3cbe9777, 0x41a80ea1, 0x885c2a66, 0x522d778a, 0xd1f2eb43, 0x0e460859, 0xe4f565cd, + 0x8ef00d4d, 0x30f7c565, 0x31941a5d, 0x23f46e05, 0x906f143f, 0x484ea557, 0x4d9813b5, 0x06b9eeb3, 0xa308e9eb, + 0x63041631, 0x4499641e, 0x831c472f, 0x90b57ec7, 0x3d7e7b2d, 0x26b0b700, 0x7cedcc91, 0xb60b22bb, 0x4f00f208, + 0x0144597e, 0x69a4af24, 0x967018d9, 0x9e546819, 0x35ec67a9, 0x164bcde6, 0xe36a243f, 0xa4b5313d, 0x050548bb, + 0xcfa0f7a7, 0xd596af59, 0x84ce92cf, 0xaa818a99, 0xdd1e26cb, 0x8658ae78, 0x1ce02f90, 0xf2fdac2e, 0x2f3d501a, + 0x8f1792de, 0xe13f2cf3, 0x4ff47fb8, 0x1f9fcba5, 0x916172c5, 0xed2b6dbe, 0x97d8b8ab, 0x7f054ee5, 0xfff6b87b, + 0x1aed8313, 0x22404030, 0x6501395b, 0x315cf86d, 0x2bd6de58, 0x58f1dfe3, 0x34391bde, 0xf5d0ef0f, 0x9f078598, + 0x0fae2116, 0xf8fa28f9, 0x6ac5d88c, 0x3fdeecb7, 0x36394306, 0x66651322, 0x1671abdd, 0xd7537711, 0x08f00ceb, + 0x61eeecb7, 0xdc9797fd, 0xa0b80f82, 0xf7ef454e, 0x9b0557c3, 0x283a4336, 0x019630b2, 0x22197284, 0xa4087bf5, + 0x918505e5, 0x79862e42, 0x75660997, 0x9f0dca88, 0xbf87a012, 0x28ff53ac, 0x5dfdf4f2, 0xaa5c1bce, 0x815bea1f, + 0x8a29fb0c, 0x8d6b27f9, 0x37ee480a, 0x725c825b, 0xcf4c56d5, 0xef8148fa, 0x5348a672, 0x5a824aa2, 0x961cbf6e, + 0x775e0b70, 0x83431bb1, 0xc5bee9da, 0x4c57c769, 0xdf156665, 0x679bb7f2, 0x061cbe91, 0x4be5bf35, 0x339971cb, + 0x3e1c59b0, 0x5051a266, 0x931289bf, 0x45525b5f, 0x7ba6d89e, 0xff0c555b, 0x7b2c590a, 0x3f85879c, 0xd9ba59bc, + 0x0473ea67, 0xd7e708be, 0x042ddc7e, 0x36ab9566, 0xc7744fc4, 0xfcdd56af, 0xaaa9c9a0, 0xa836f6ba, 0x1af6f2f2, + 0xd5a37074, 0xce7b7450, 0xa9b26268, 0x5c0dfea3, 0xe7afc249, 0x809d838d, 0xebe84d76, 0x961e1ab3, 0xde2f7bfb, + 0x37664a2b, 0x2800e48f, 0x8515d7cd, 0x469e0a05, 0x05758350, 0x92e54e8c, 0x8868f0c7, 0x8b130e79, 0x36b6de0d, + 0xef519c82, 0x047973d9, 0xb5bb9a7d, 0x7d8e2e1e, 0xe5cd9c00, 0x6de399d4, 0x3d843ad4, 0x52ad9f24, 0x66155bb5, + 0xa59e3306, 0xd2d6b027, 0xcfeaa166, 0xfacb2068, 0x6ef8ced3, 0x5620d1e4, 0x6d1f3170, 0x715348ef, 0x7fcd80c7, + 0x41d9b3cb, 0xeb7e2553, 0xaec259ee, 0x2aea1b9d, 0x2bae3c71, 0x102b0ccf, 0xaa3dbd2e, 0x47d1dacd, 0xa483acb5, + 0xa892bdb0, 0x59a169e9, 0x8b814089, 0x4b1dc0f4, 0xb990d75e, 0xad0bb4ee, 0x5ef4a31a, 0x311aca67, 0xaa274277, + 0x6500733b, 0x227dc690, 0xd6cd6341, 0x0de0a553, 0xeac698b0, 0xba784864, 0xf235121a, 0x5b68ff0e, 0x45c58a5a, + 0x41801720, 0xa4cfdb11, 0x3d852c03, 0xcf8c7107, 0x9dfd441a, 0x74c25a5c, 0x1fa4b2a6, 0xfe2b1daa, 0x77c9efc3, + 0xa97d6db2, 0x4b1955d5, 0xecbab03b, 0x36a272c2, 0x866e9e46, 0x05614e28, 0x7600102d, 0xac856aba, 0x8a7b9069, + 0x20f991ec, 0x860d638e, 0xcfe1e8e4, 0x8e033512, 0x1b260962, 0x3ea8de03, 0x82af17cb, 0x910e77ef, 0x11d1904f, + 0x2e6d1d4d, 0x103dea03, 0xe0bfaf68, 0x3264750e, 0x9266ee2f, 0x711d4171, 0x20fe8898, 0x9e1ed8eb, 0x0a060d50, + 0x23154611, 0xab5ad2fc, 0x1b28da35, 0xf652e4eb, 0xb1fdc89c, 0xfb528c38, 0x86e3f747, 0x11e59d0c, 0x1bb57565, + 0xa3c0233d, 0x41127cff, 0x3d66df55, 0xf0fbc2bd, 0x3c7dfaa7, 0xc7418fe7, 0xf3797d48, 0x816bc408, 0x31b65fe6, + 0xb37b7722, 0x18d1b590, 0xe80a14c9, 0xf22d1b95, 0x7aad5fd9, 0xa275d586, 0xe17f9477, 0x0fa22454, 0xfc79d1de, + 0xfd3b6731, 0xefd3e728, 0x1fa2f29f, 0x1bb57d1c, 0xc64803b2, 0x3354bd29, 0xd4b9ae3b, 0xc9b043f5, 0x38f2ac3f, + 0x801a2afb, 0x35173471, 0xd6429897, 0x78510d98, 0x090c49b6, 0x0f99da49, 0xb7ceb9ab, 0xa3415967, 0x8e5cb28b, + 0x3874106c, 0x249debdb, 0x7b08d7e2, 0x3917f8fa, 0x3e906b4b, 0x381b2052, 0x5d09939c, 0x96275e6c, 0xb2aa3eed, + 0xc5fb6efa, 0x3e3dfa46, 0xcd520e7c, 0x170909ae, 0x6e23b70d, 0xc0abfc1e, 0xaa0e889d, 0xfb1679fc, 0x9f496b13, + 0xf63a4367, 0xc59018f3, 0xd17037fb, 0x33ca4ab0, 0xe1c1b24d, 0x26b7d135, 0xb1ce21e0, 0x052fa86d, 0xd6c2cc2d, + 0x1d21fb63, 0xaefe30ff, 0x9dfd9120, 0x45376d15, 0xd1e8f96f, 0x4247951f, 0xd6fc1ac3, 0x135e4223, 0xaac95468, + 0x74a46ebd, 0xd8de6364, 0x99f5917c, 0xbdb78791, 0x62ecabc7, 0x4ef3a316, 0x42cbb6d9, 0xcfc1889a, 0x30394e37, + 0x7645648c, 0x521cefbf, 0x31f13e6a, 0xff8819b0, 0x1b7031c3, 0xd25fb1f8, 0x7f32430c, 0xa5f7042e, 0x6021d593, + 0x1abc38a2, 0xb95aeda9, 0xebcc3089, 0x76b626a5, 0xacf09b8f, 0x8b13843b, 0x6110958f, 0x4465b812, 0x78b55edf, + 0xf54eb463, 0xbd02f930, 0x0f713fbd, 0x41d932ce, 0xd08c25cf, 0x51059923, 0x5fd39c21, 0x35df7078, 0x8fa8dd4b, + 0x7d9481d7, 0xddc61c8d, 0x579d3103, 0x17a48ce4, 0xb327c2e0, 0xaf1c5cd9, 0x2e9ee38b, 0xbb24956c, 0x4d557b53, + 0xb735a002, 0xf21a029b, 0xfc164928, 0x4b0e874c, 0xd7ab7bdb, 0x8a25e1d9, 0xe3f95557, 0xe7af3861, 0x6bc1abc3, + 0x20252e9d, 0xf43e9135, 0x94c8f687, 0xf7901fc2, 0x38b5ef4a, 0xae7e1c07, 0x2695730c, 0xfffca274, 0xd4d76c91, + 0xfcd736cb, 0x4f2c1e67, 0xa605c4f1, 0x7a26d470, 0xc0f7e28a, 0x232ed177, 0x1d4f39b3, 0x4fb0e113, 0x54298fd3, + 0x1fdfc567, 0x26564765, 0x914d29b8, 0x4685b12f, 0xb6331c59, 0x4349b48f, 0x2d92852c, 0x06f30500, 0x62bffcea, + 0x2fcf8ec9, 0x74bec3b7, 0x28841e39, 0x61fee834, 0x16b95ce5, 0x4991d3d1, 0xb1b4d073, 0x9577c538, 0x0621e9a9, + 0xfbf126ac, 0xbfb844b9, 0x9128c9e0, 0x2baea9d9, 0x6c6318b7, 0x2a881731, 0x0533e048, 0x295800f2, 0x0a0896f8, + 0xd51bc1af, 0xcf26d5df, 0x049562e9, 0x94407dd4, 0x6b8e831f, 0x11187106, 0xa4b0735c, 0x5bdec664, 0x5f55305d, + 0x3a107602, 0x9a430314, 0x355da0b7, 0xe7f35593, 0x4c0e226a, 0x12425fc4, 0xa88065ef, 0x4bb3b93e, 0xa2f195fc, + 0xc9720109, 0xb6392b34, 0xe296806b, 0x18ec656d, 0x194a6b0c, 0xf1c0a2f5, 0x5587045c, 0xe845a126, 0x2384d225, + 0x6cc92ece, 0x09e26b24, 0x1aa66f90, 0xa65bf97f, 0x48dcd70b, 0xecdf7c22, 0xcb8dfcd9, 0x8a6681c7, 0x20aa833b, + 0x363bd5bb, 0xcbf357e4, 0x2d3d2784, 0x9faa8522, 0x10d67858, 0xc1acd18b, 0x495b870e, 0x3dcd5d38, 0xc648a7f4, + 0x74db02af, 0x4e720c30, 0x4db66632, 0x8171511c, 0xd6552654, 0x5e22a041, 0x3c920bf7, 0x7a086727, 0x317d163a, + 0x2466187c, 0xf6e431c4, 0x19c555c8, 0xb6b9b434, 0x07a39840, 0x92cca4a0, 0x8f3c5167, 0x92f76479, 0xa536d93d, + 0x3963c384, 0x41fa81e2, 0x2cd5ef42, 0x421bd450, 0xbdea562c, 0x00221a46, 0x94f66e7f, 0xad67d4ec, 0x7641fc97, + 0x113fc7d9, 0xf1823219, 0xbf59b863, 0x336ccf7f, 0xfdc2d254, 0xcd238828, 0x0cea17dc, 0xe73ddc50, 0x87d092b2, + 0x1d8e4fcc, 0x3a00c858, 0x45343a36, 0xe0dfb6a7, 0xb5fc5ba5, 0xeed8c3e8, 0x209461f4, 0xdb7d2c95, 0x78f131d8, + 0x15358960, 0xd1c26d2d, 0xd7a04853, 0xb0627a09, 0x4050bed2, 0xc2e683b3, 0x8988e44d, 0xb0ff66f8, 0x610492be, + 0x89f8eeb3, 0x7c25ace2, 0x7fc39c1c, 0x17bfcdde, 0x0285f6f2, 0x65244abc, 0xa28af9b8, 0x829f3948, 0xd4af9483, + 0xebd6768f, 0x3e06f00b, 0x08ce4e82, 0x3e3d49b1, 0x5db8569c, 0x6dad2627, 0x2cf677b2, 0xbe2db14c, 0x71c79a44, + 0x765dcf42, 0x3b5c2f06, 0x3e753104, 0x8c1f2fdb, 0x70fe62a5, 0xe3c1ec2f, 0xc3e2beae, 0x1bb499f6, 0xb35353eb, + 0x78627ec1, 0x900b8c8c, 0xc466d179, 0x41233dea, 0x26f4ee05, 0x8f5ba05e, 0x4f67f9d1, 0x77abc7b9, 0xbb4191a5, + 0x335b8e05, 0x346c8a0f, 0x26dd46db, 0x63ee8466, 0x36c955d1, 0x224a0704, 0x72595e90, 0x73d460e2, 0xdc680da4, + 0xbc3b8e30, 0x7c92a825, 0xd633be2c, 0x5b2b0f90, 0x1f05947a, 0x5b201cd4, 0x4b9fc8ad, 0xcca120ae, 0x78d9265b, + 0xce050aec, 0x50ddd658, 0x3ed8279a, 0x4c0ada0f, 0x01a556e6, 0x3f488fd6, 0x071d2bb1, 0x4c704432, 0x7b56f4c3, + 0xb708530d, 0x5e4ddbe0, 0xcf38f961, 0xf68661c3, 0x7d9514e2, 0x3a2ac26f, 0xa0fe75a8, 0xe65665ab, 0xdad2f19f, + 0x1c316d10, 0xa28c6abf, 0x540da63b, 0xbc92c91e, 0xac26a189, 0x158cc0bc, 0xd4c34e43, 0x6acdc273, 0x7c9c258e, + 0xd1d00ba6, 0x31abe3d9, 0x1516657f, 0x0ac8ba4b, 0xca7fbd62, 0xcffc1688, 0xfc8ed4d4, 0xdc3e6b2e, 0xc22e702a, + 0x5d9fcac5, 0xe0f09671, 0x5477fc14, 0x9c9d3780, 0xd0a8c693, 0xc5a9f408, 0xb0cb94cb, 0x970029d1, 0xfa1c135e, + 0x70026572, 0x2e1b1a9d, 0xca381074, 0x36b3ab36, 0xe744425a, 0xe4340b05, 0x269a0b72, 0xdd7cb219, 0xf4d19e93, + 0xd9a0011d, 0xb6165b83, 0xc3860428, 0xbaee30ea, 0xeb9c942a, 0xa5018ba5, 0x559c0b1b, 0x92b73eaa, 0x208b2618, + 0x356a3209, 0xf2dc2d45, 0x9cc49437, 0x3d498565, 0xd2278569, 0xec982177, 0xd2636b42, 0x1532f4dc, 0xc08f6d1f, + 0x6b901d4d, 0x69f35180, 0x566dfa3f, 0xf31d58ae, 0xb89abc16, 0xdbb2b4f2, 0x36013366, 0xf388da8c, 0x51cc9ace, + 0x1f77a576, 0x16dc81d6, 0x3a458ea1, 0x3939bb71, 0x4ff52622, 0xc5dbf816, 0x0ceaafc7, 0xed9be841, 0x81ae92aa, + 0x74759f8a, 0xb0e4ea3b, 0x75296ed2, 0x657c2a32, 0xbf9263b1, 0x00703b27, 0xa77e7567, 0xc4e97837, 0x868e6b1f, + 0x3db5208b, 0x883c6bb0, 0x25a09dc9, 0x17d7c7a4, 0x97f09989, 0x22ba60f1, 0x25daf14f, 0x6febafc7, 0x8febca96, + 0x3a1b2b70, 0x04ccc2c1, 0xbc6c5572, 0xe6cd1a66, 0xf4dcc0bd, 0x121c9b26, 0x9d245651, 0x187b218b, 0x049e665d, + 0xc99539c2, 0x208b8898, 0x34d9d7ea, 0xff130ef4, 0x58805135, 0xda0bf5ab, 0x37fbc205, 0xf49098bf, 0x78ef3a0f, + 0xeff3359b, 0x17777c44, 0xbb84b796, 0x83e16af6, 0x5a876e4b, 0xc108176c, 0x71ac8c2b, 0x981fca40, 0x51292d3e, + 0xc61c6507, 0x731caba3, 0x51de4f22, 0x16c49db0, 0x94dda0ee, 0xa37aea4d, 0x11d388c1, 0xd97ac9b3, 0x631098cf, + 0xe5f662f2, 0x0059b1cd, 0x9ab73248, 0x9541ec34, 0xe113b816, 0xdb05e5d0, 0x906a3b0d, 0xed2fefbf, 0x84ea7772, + 0x2c77eb77, 0x420922c3, 0xbf6f7885, 0xcbb17985, 0x9a6dff4c, 0x69729d2d, 0xb110045e, 0xfad14210, 0xd5c10e4d, + 0x7a335524, 0xee4b451e, 0xb323ff3c, 0x54a344f9, 0xd650fd2c, 0x30bcc115, 0xf0939038, 0xf45acd17, 0xb418d5e6, + 0x4878258f, 0x10298d7b, 0x4b740ffb, 0xb64c1c23, 0xbdcd55d7, 0x0c007d88, 0x9cdebf00, 0xc7e93300, 0x0c80d996, + 0xf3f95f8f, 0x72acb74c, 0xa9979eba, 0x3b38fe8a, 0x8082aa72, 0xddb2aa76, 0xef346c55, 0x078a9af9, 0x724aed44, + 0xe3e223f1, 0x418c9c99, 0x022aeb97, 0xb42c3637, 0x665ab93b, 0x2b62cf4a, 0xd14c5ead, 0x188f9198, 0x14a9e0de, + 0xfcba0bc7, 0x93c45682, 0x88d28187, 0x7089fb78, 0xe0db814b, 0x8c59e2e7, 0x84b7fe00, 0x1d205462, 0x03b4143c, + 0x03b52560, 0xb45267ee, 0xeca65dfc, 0x069479a2, 0x77a2481d, 0xda5ca00d, 0x7fa4656d, 0x9217f99d, 0xad6fe929, + 0x1bd497cb, 0x556b69a3, 0x7bab80b5, 0xe00ed258, 0x67836dca, 0xe56f9ac7, 0x8e5c55e6, 0x0c73140a, 0x4030e105, + 0x6e5cf031, 0x1ef71239, 0x04ea32b9, 0x81179886, 0x9eb35f1d, 0x12bfc131, 0x0b63c2c2, 0xd7952e31, 0x85c1e6aa, + 0x1e10295b, 0x9b39a764, 0x4030348a, 0xea2b1125, 0xe77ff24b, 0x4e235df4, 0xe0a48b83, 0x53678d3c, 0x03bbcafa, + 0x0da51d66, 0x05c33595, 0x55fee480, 0x5b746000, 0xec40d61b, 0x4830cb53, 0x64043532, 0x09719346, 0x439265d6, + 0xefdda2c8, 0xbec7efef, 0x81b7df76, 0x5361a4c9, 0xe0ad01fb, 0x97f5117e, 0x05be6995, 0x59464af1, 0x654e5a6c, + 0x7551d912, 0x3e4cc67b, 0x746c521d, 0xda7a54f2, 0x977d1ff3, 0x335e730f, 0x2d7176ea, 0x80a597be, 0x6e71378d, + 0x0e32edeb, 0x0112f978, 0xaec798f4, 0x313ffdd2, 0xb4e7508b, 0x6dca403a, 0xb0e91966, 0xad0bd3e8, 0x64b95dca, + 0xff36cbba, 0xab4d88a8, 0xd26f7c14, 0x386a8fcf, 0xa3560f38, 0x72c5c77a, 0x35f60c09, 0x9a449c67, 0xcd2f3e07, + 0x2c9a7511, 0xf3df0ef7, 0x5f1f3b80, 0xdcb7d8b9, 0xf54585a6, 0xc9807004, 0x0e8b3ce6, 0x42014224, 0x9aeb05ac, + 0x426f1e37, 0xaa635f30, 0x23eb66d8, 0x7e8dd193, 0xf5f30c34, 0x9d991828, 0xd664cd0a, 0xdc174045, 0x4a3653fa, + 0x99ca8fac, 0x34996a8e, 0x65d21861, 0x9ccb1aca, 0xdcf00be2, 0xc970c686, 0x212de460, 0x0fa461d3, 0x12c7395d, + 0x9ae6a48d, 0x6e5da50d, 0xc031a04d, 0x4ae51982, 0x25e5c105, 0x7c2fe8ef, 0xee67e2cb, 0xcf95aa71, 0xa63686fa, + 0xac70ddaf, 0x75addbee, 0x5a98d3e6, 0x1e29de84, 0x30d44fae, 0x9b0eb562, 0x7c07124b, 0xe935c0e5, 0x70d2080d, + 0x05c02e5c, 0x08efb5f2, 0x5c16ef17, 0xe73259d6, 0x0f3d8899, 0xa6f07b89, 0x050eb84e, 0x9e4a10fe, 0x70d49353, + 0x86cf8d86, 0x7f7ab837, 0x1345c57f, 0x48cc4c83, 0x9af14ac3, 0xa09940d3, 0xb1a4a986, 0x8c3ef7ce, 0xdd8d91d5, + 0x8b77175f, 0xf63a6158, 0xc2213e21, 0xc9e00bcd, 0x801fa331, 0xd8426d26, 0x3dc7b159, 0x47d53426, 0x1b6749de, + 0x962bf8c7, 0xb1756522, 0xc538d055, 0xb2d87202, 0x24019d3d, 0x6e9c4ee5, 0x743e6332, 0x2d06b88a, 0xdd38b5ed, + 0x2c8ce932, 0x697f8f02, 0x1c4f96d2, 0xcc890165, 0xf3141a7d, 0xac55b66e, 0x5b63bf0c, 0xf62442fe, 0x3ce6c916, + 0x5005161c, 0x8478b056, 0x0623c0e6, 0x96214342, 0x8799a521, 0x9e158b70, 0x2a47d5ad, 0xf1589b0f, 0xe8c54e53, + 0x8c0c8569, 0xdaebee66, 0xbb118529, 0xc9674297, 0xfa5d616c, 0x0185dc6b, 0x6e24ed9f, 0xc66b701d, 0xd78c4d9d, + 0x3acf955c, 0x83b15697, 0xff0c60b5, 0xc1d6540b, 0xb230bed8, 0xce0f6b07, 0x29d3f188, 0xf3a165a4, 0x71368abb, + 0x050619fa, 0x54f756e0, 0x6a19af50, 0x217528f6, 0xd3e58dc5, 0x51203c4e, 0xcf8f4be8, 0xac7af612, 0x2da7c8bc, + 0xc3092163, 0x9fdd46fe, 0x6f9cc70a, 0x68bba092, 0xffa86cac, 0xcb0a279a, 0x5803d6c4, 0xe48addca, 0x6166dbcc, + 0x44de1aa4, 0x8618c6ce, 0xff3e97f9, 0x276ebfd6, 0xa3330e77, 0x5ffe7e9a, 0x639805df, 0xd2beb353, 0xdb4f6cc9, + 0xc091c958, 0xfae0ded7, 0x0176cfcd, 0x718c8b89, 0x8e1feb07, 0x31792f40, 0xe54f324a, 0x70d7d026, 0xa27ae5e2, + 0x55eb3151, 0x60b32fd7, 0x2416b57b, 0x97671bf6, 0xd908c210, 0xc11b5255, 0xbae6cfb7, 0x99e04ba4, 0xea34170f, + 0xfdb63c79, 0xfca8392f, 0x36fab38f, 0x8730174c, 0xddfc3ebc, 0x6cf8e784, 0x39d389ee, 0xf9296664, 0xe0638e28, + 0xbe079d0e, 0x316bc92f, 0x56f0ef99, 0x9b532bb9, 0xd1d4c8ae, 0x6dc9c3e3, 0xe3764e4b, 0x9d2ff124, 0x003af665, + 0xb7cbad72, 0x4b692cdb, 0xd347ee4a, 0x6356c01a, 0x31022304, 0x3a5631a5, 0x84c3b1a5, 0xb5ba154a, 0x08b09fd3, + 0x4a063cc2, 0x7e4f47e7, 0x8397ad18, 0x520c2cc2, 0x0a8beca9, 0x39fc3313, 0xbc518e8d, 0xc8aafe8c, 0xb34fa434, + 0x24f20aa2, 0xd6418889, 0xc04f66bc, 0x00b8163b, 0x014465b0, 0x5aa74b05, 0xd5160948, 0xa19b257f, 0x51726e90, + 0x52bb2ecc, 0xc4b21f07, 0x263781d7, 0x311568ed, 0xa522a383, 0x9f8f459d, 0x5fe602d0, 0xf85479f3, 0xb83fa717, + 0xf19bb923, 0xebb23be0, 0x860053f2, 0xdde497a8, 0xa4b1effb, 0xdb4b8730, 0x41092848, 0x37acde02, 0x11079421, + 0x850b66db, 0x8af58458, 0x7b29a73d, 0x3df7eb96, 0x4c5cb608, 0xb8a71b7f, 0x9a6ec8cd, 0x31916791, 0xf23cc96d, + 0x03e0a8f6, 0x0adb5fa9, 0xd662f2f9, 0x627011cf, 0xb7d33e89, 0x2a22b6a5, 0xb07b6fb9, 0xab837ea0, 0x47db81f6, + 0x931fe6ef, 0x0dc18e8a, 0x7b664f34, 0x295bfb5a, 0x82b6af9d, 0x9f2eaf4b, 0x9c3b8cac, 0xd7d189b3, 0x9f625a1a, + 0x9aa7fe3a, 0xd9f6a150, 0x5ff1a695, 0x4b05d828, 0x179cb8c0, 0x3c14828e, 0xede98a02, 0x92c0550f, 0xcf6aae85, + 0x477052da, 0x6a5500d2, 0xc668f406, 0x283a88e3, 0xa3c7e16c, 0x98557292, 0xf3e7c54d, 0xdbbc5e31, 0x1a5ed686, + 0x75333c0e, 0xef64a47c, 0x5b6fcc3a, 0xebe817af, 0xce2595bc, 0x8abb0b85, 0x4b4d21a1, 0xc07fe528, 0xfc5143bc, + 0xa7dc9041, 0xae8781bf, 0xb80e7af2, 0x649f2279, 0x134ab6c1, 0x3d234402, 0xeeb674b5, 0xe8805520, 0x9b8074a9, + 0xf3bac9e7, 0x07fc1a4d, 0x84369550, 0x3488a480, 0xeddb088f, 0x15df2af4, 0x588ed32a, 0xb9d43e72, 0xa37ed70b, + 0xba646d8d, 0x2fdc6be7, 0x7a9e34c6, 0x86d7e208, 0xc56dac34, 0x1a6679c2, 0x8597768d, 0x71afb504, 0x5b5c6ffd, + 0x38a5879c, 0x15b8a31e, 0xb2621762, 0xdc8b0a97, 0xafb83e99, 0xb4acf0e4, 0x6518b5cf, 0x878984b4, 0xed335a52, + 0x4b5ce4ba, 0x954eb008, 0xefff270c, 0xcd8cc2b7, 0x0d7150c5, 0xb15670f5, 0x369a3502, 0xb940864e, 0xf71ccf4f, + 0xe83b8210, 0xa68c4d4a, 0x6dc883ae, 0x73ea6cbd, 0x66cd2f41, 0xa17bc952, 0x8ed5658a, 0x907c8731, 0x7eed8553, + 0x37cfe6bd, 0x87992a48, 0x5022a951, 0xd2e4ea99, 0x17a08741, 0xc05fb106, 0x831064bc, 0x5d190aae, 0xf1ddc5c6, + 0xc32dc30d, 0x2231a149, 0xd555b4f5, 0x397e9fec, 0xca387365, 0xe145bfb7, 0x3c3f07fa, 0xf061081d, 0x3621e42d, + 0x1ff63d48, 0x22c5b0c6, 0xaa8f7e93, 0x2072a477, 0x2ea5a3aa, 0xbe6bb168, 0xbfa96b7a, 0xd9a73c9f, 0x4808c10e, + 0x3887bc82, 0x18eea11e, 0xdd83c644, 0x11ac35fc, 0x9f519a19, 0x54f10c36, 0x62440603, 0xdc1cbb79, 0x6c8d7c10, + 0x16802177, 0x57d6a6ce, 0xd50d1122, 0x6a6037d5, 0x02fc80fd, 0x5e4f40cb, 0xd9f27c17, 0x4e8db377, 0x302d2ef9, + 0xaed73925, 0x7d71325f, 0xa8b7f188, 0xadb5f676, 0x28a03473, 0x449b2bf4, 0x7b17f625, 0x8aa9a477, 0x978651d7, + 0xdc6878da, 0xc6ce04f6, 0x06561a7e, 0x15946916, 0x52eec9c8, 0x9b19f900, 0xbd4610e4, 0xfdb8a675, 0xfa8285d5, + 0x19128405, 0x845afb49, 0x9168244e, 0xc9f1ded9, 0x0090ca24, 0x50068c8e, 0x91a96f57, 0xa58d451f, 0x1eccfeb4, + 0xf3f210d7, 0x6ee45c15, 0x5eaf514b, 0x1e5c3211, 0x8d09dac2, 0x63fdfa2f, 0x5572b20e, 0x7ed1eeea, 0x864d9e36, + 0x938ce252, 0x966dc348, 0x04ac8a16, 0xa28e2486, 0x53776f23, 0x62cc62ac, 0x497bc18b, 0x2189a78a, 0x800aa523, + 0x29fbb514, 0x6261ade3, 0x155ed975, 0xe1877621, 0x1295e13a, 0xea03031c, 0x8fe856dd, 0x1c095a58, 0x96de7105, + 0x53029198, 0x2a642619, 0xb64d598f, 0x80fe8d6a, 0x2f129373, 0xb64aeb74, 0x062b659c, 0x28e2d916, 0x9bf2f115, + 0x83320f3f, 0x1b3ca9d0, 0x6a4580fa, 0x37448391, 0x8f1f69d8, 0x847e7f5e, 0x545a3914, 0x2a94424c, 0x22f9acfa, + 0x706eff40, 0x15c1700c, 0x7ea9ecb4, 0xe1955a23, 0xe5ef4cba, 0x920688a9, 0x155e7354, 0x0dc19561, 0xff3bb064, + 0x930ba652, 0x67b1ad4c, 0xe472d32f, 0xa2d85389, 0x68353625, 0x3fafdcdf, 0x72d37c07, 0x6d5a5d8d, 0x8548eb9e, + 0xfc8d1715, 0xe4a80c89, 0xe874b941, 0x4bafbce8, 0x982b0828, 0xc6c18dc6, 0x509c2b13, 0xd108bdd2, 0xa3952636, + 0x65f8799d, 0x7ae159ee, 0xa07c0621, 0x484e96e9, 0x453a5b75, 0xd5e40435, 0x9bebbced, 0x212b86af, 0x3b7b7456, + 0xfc52a636, 0xe1b75bfa, 0x272b7f98, 0x08b844d5, 0x75679b32, 0x2b7d40c9, 0xbcff230a, 0x6b3ba12e, 0x4cf1dd88, + 0x83dc71e9, 0xaff3dcee, 0xd54297c4, 0x1538529f, 0xf8f9775c, 0xe991fbf7, 0xc491afaf, 0x9d599f29, 0x4d191fdf, + 0x570cc9d8, 0xa640a034, 0xcd1d7b12, 0x84dae3ba, 0x6f8f92a9, 0x116aad8e, 0xdb1476b5, 0x1cecc2b9, 0x160e2d37, + 0x8d64723f, 0x4ec00276, 0x43cbe17c, 0xb52d9444, 0x6d0fcbc3, 0xcbffe351, 0x40b13dab, 0x966098c4, 0x6a0e2231, + 0x5cd75179, 0xc6a74abe, 0xfff2849a, 0xcd3aff11, 0xf13afe37, 0x87bf3beb, 0x50a5ff90, 0xd0bb33e5, 0x495306df, + 0x013a859d, 0x9f96f20e, 0xfc006161, 0x49f7fb2b, 0xa8e8e08e, 0xe16b659e, 0xd15ea06c, 0x30b8c28f, 0xf6b2277d, + 0x856004b4, 0xdfa199f1, 0xc0b38cc8, 0x44e877ef, 0x6b62a1d9, 0x62777856, 0xaac3158c, 0x1013c1b8, 0xb26f25c9, + 0x48df931a, 0x2756736a, 0x2def2ff2, 0x3e750afa, 0x4c9b25da, 0x6da58c8b, 0x2f23aaf9, 0x72ce270d, 0x573508e6, + 0xf4193166, 0x66e57698, 0xde0c8137, 0x4ee4ddf9, 0x7000e73f, 0x26e66b9b, 0x950ce099, 0xaf225e39, 0x3f11a514, + 0xa29e29ca, 0x27f1d182, 0xbc800b87, 0x6fb0d7c3, 0xf08849d9, 0xc7989aab, 0xa4ada165, 0x092af3e4, 0xcc52ee6f, + 0x5bbefc9c, 0x4ca0d804, 0xe31f148c, 0x92dede19, 0x2b5ccfc1, 0xb5e75a01, 0x146a4011, 0x92ce3977, 0x8381fc85, + 0xe838cbca, 0x0ffd85ab, 0xf20f49da, 0xe82f9380, 0xe8e11644, 0x17cdf975, 0xaafa5bb3, 0x9bb9cce2, 0xd9f6d1ec, + 0x3daa870d, 0x888dffa7, 0x396f7e02, 0x49a4f0b2, 0x32e29577, 0xdf725f57, 0xaeb4d861, 0xe1a48ff4, 0x610dd97f, + 0x07303d80, 0xa07e1b44, 0xd0e8a640, 0x2da55571, 0x6c37d517, 0xcf0e53e4, 0x8133fccb, 0x507bfda9, 0xa227794b, + 0x8aca1cd5, 0x24ec4e02, 0x6ea82cbb, 0xc8fa2bd0, 0x37a10c82, 0xffb92907, 0x676dd554, 0x7dee13f3, 0x4e6865e7, + 0xa01e4085, 0xa14d0998, 0x94482748, 0xce1c1cdc, 0xcd95efbb, 0xffa6e59c, 0xf8b7cb4a, 0xe7eb654d, 0x0620020f, + 0x544493c3, 0x0ef4ab3b, 0xf1758f6f, 0x5fddc41b, 0x932d0643, 0x386f2a9a, 0x905e7595, 0x4ed31c9c, 0x943d4487, + 0x1164e1ea, 0xcf072897, 0x1ba7fb5a, 0xb2ea320f, 0xf39f37e4, 0x41bfa017, 0xee15ee0a, 0x73bf2024, 0x813a46b4, + 0x41b8c812, 0xdecc42eb, 0xe210f726, 0x2b6c20c5, 0xa6e60056, 0xa121ffe6, 0x819dcac8, 0xf0092abc, 0xf5fbbf36, + 0xb18187ae, 0x57c5ea80, 0xa208d74e, 0xd050de02, 0x3d34a672, 0x72d50ffc, 0x213441e7, 0x0f6df504, 0x06b2e710, + 0x7702071a, 0x21324071, 0x849d4fef, 0x01ff3bd3, 0x0d2abb11, 0xc22e8a79, 0x7e1ae7cb, 0xb3fff80f, 0x889b29d9, + 0x029ae5ed, 0x3a5695bd, 0x5a89a447, 0x971423d0, 0x02ed5725, 0x07059c89, 0x24b9af86, 0x9bde6c8f, 0x2370c594, + 0x49b22dbe, 0x71ae1e61, 0x7e6f4b01, 0x2a1e2e25, 0xa56dc453, 0x9413b4e0, 0x606767e9, 0xa0af3a6c, 0x1af0771f, + 0x33355986, 0x15c6a995, 0xa672ac98, 0x879f346d, 0x0e5b1e9b, 0x21ccb8bc, 0xda52e18d, 0xf48c430c, 0xbe459b8b, + 0x14be041f, 0x90db3e7a, 0x1ec2124d, 0x46659753, 0x690c3f8a, 0x47d5a94c, 0xc56e7b15, 0xb2bd862d, 0xc783ad0b, + 0x6b94c076, 0xd6c1f927, 0xf0608093, 0xdfebadb8, 0x04108b48, 0xb3d0c07f, 0x40279288, 0xd7b6c5b4, 0xa33b2571, + 0x5b24a448, 0xe1dcd477, 0xe8630a57, 0xb056591a, 0x7bf8824b, 0xdd446915, 0x0d1468d2, 0x3842af95, 0x66039acb, + 0x883350f5, 0x808a1b93, 0xaa48151c, 0x614ab41d, 0x2e5fc6b7, 0xc211918a, 0x20f11223, 0x55ce7ab9, 0x1d735ac9, + 0x8abff59a, 0x951e1eae, 0x85b6dd7b, 0xf5e15c31, 0x1ac03666, 0xf3bf22bc, 0x2954111f, 0x2d93ed66, 0xbb684a3a, + 0x1082a76f, 0x9c679405, 0x924431ec, 0x7cfeeb07, 0xd5da2cfe, 0x95fdad28, 0xad77b6bd, 0x28b0f938, 0xaa8805fa, + 0x2d455cba, 0x55cbe77d, 0x4a5cb47e, 0x1f7179bc, 0xefbd57a5, 0xd2052245, 0xf62580ea, 0x4c127225, 0xf8c343d1, + 0xc6c6681a, 0xb0ac7039, 0xf80bfb09, 0x830be828, 0x55f6d3b3, 0xdf8ee8a9, 0xb1dc8545, 0xc6e6225c, 0xc5050ac6, + 0xb74788f9, 0x8f0b19d5, 0x6c82880f, 0x700eafcb, 0x60925622, 0x50a8e0de, 0x5756b44a, 0x5981fa9c, 0x0333c3a7, + 0x23f12988, 0xc24fde2d, 0x9b787b50, 0x80cc5fee, 0x055e03e2, 0x2e5bd0f3, 0x28bc90a3, 0xdf1c3ee4, 0x26f0b1b0, + 0xef2019db, 0x163fd4a0, 0x85c123d9, 0x5f44d4b5, 0xb7fced74, 0x4dff0d6f, 0x6aedfa03, 0x29b59b72, 0x19f485a5, + 0x6174545f, 0x9ddf4c0c, 0xf043e1e0, 0xfab9a22e, 0xa8046669, 0x07038d08, 0x76f5de23, 0x8cab9afa, 0xb08bbbd0, + 0xbd0f6dbb, 0x30302a46, 0x1d9da103, 0xbdfcd0bf, 0x52dc6d3c, 0xe5168249, 0x13416b95, 0xb7c661a8, 0x9779768a, + 0x47e475df, 0x8ded69d1, 0x0d7648b6, 0x7fa28c1a, 0x330ee031, 0x5475e1c1, 0xe0227d5b, 0xa7caa6cc, 0x42187e1a, + 0xb27b4773, 0x4657f4d1, 0x0115f008, 0xe8de1486, 0xa0f8dfe4, 0x4e81d614, 0xf705b94f, 0x10a601f6, 0xc9255397, + 0x278df6fa, 0x268c8b3e, 0x3c40681c, 0xee5976d9, 0x4062709f, 0x86bcad2d, 0x17d0afde, 0x283bdfcb, 0x297edc13, + 0x246e5fbf, 0xd26eb137, 0x85a16fce, 0x5ddff52e, 0x126170e2, 0xd419a12d, 0x3558bdb8, 0x93417486, 0x03c75929, + 0x4696f2b1, 0x2bf0735b, 0xa82910c6, 0x2cf972d5, 0x30425112, 0x9d25676d, 0x90f76d0a, 0x07fc2a2a, 0xfc687e14, + 0x3c74424f, 0xa34e941b, 0xf11b9b76, 0xcdf292b7, 0x1b02a0e8, 0x8c1a43e1, 0xb697b14c, 0x76f5ee71, 0x32723e15, + 0x108f5959, 0x6a8fce09, 0x320a3884, 0x6db28bf8, 0xd53a88af, 0xe331bbb5, 0x9cdefebe, 0xc4146b1b, 0xb73a74d6, + 0x7fa139cb, 0x70018d7f, 0x94f626fa, 0xb2bb3daa, 0x1c6a9fdb, 0xd532b5e0, 0x6822058c, 0x64870696, 0x29334952, + 0x89bbde98, 0xb65484f4, 0x23e6ceab, 0xdadeb3ef, 0x6b0c56b4, 0x0eb1b51d, 0x2c6ae159, 0xc657648b, 0xfe99ad6c, + 0xd3f927cf, 0xc7d9bb2d, 0x78231528, 0x78095a6c, 0x4a261f19, 0x885a47f3, 0xfa468d44, 0x4597aad5, 0x73847810, + 0xeb368f11, 0x5d195353, 0x74221111, 0x2e89308d, 0x6a125176, 0x1e105244, 0x6b570ba8, 0x6ca4b7b9, 0xf9fa1dce, + 0x2e7702df, 0x3bd0de99, 0x53507435, 0x6595689d, 0x8bbd9fe9, 0x0e7ae568, 0x5976a4fe, 0x5465b6ef, 0xe878a410, + 0x5aba11d1, 0x63d2c0e0, 0xf87764bf, 0x49e3d678, 0x676d923f, 0x3784bd96, 0x2a81b1da, 0x2fcaa568, 0x9a331352, + 0x46e54dcb, 0x347c1f67, 0x634a7a77, 0x2631f74f, 0x1752350d, 0x334b8ab5, 0x9955b1f9, 0xfdaeb291, 0xa773ba16, + 0x35c85e99, 0x4c4d8bfe, 0x71899de3, 0x4861415b, 0x91e42f83, 0x318cb799, 0x6b2cf210, 0xf95b014b, 0xb60edc6d, + 0xe45c7548, 0x09418d00, 0xd6f72714, 0xb8d2c688, 0x438dc509, 0xf4b30d70, 0x2f78fa3e, 0x87757012, 0xa0747ed7, + 0x609f4e32, 0x8930d122, 0x516a2488, 0x63782ee1, 0x677fa8c6, 0xdc2e67af, 0x097958ea, 0x0a3d12fb, 0xbf6997bd, + 0x16257745, 0x587578b3, 0x39bef343, 0xc22180b5, 0x8a88a194, 0xa3baae93, 0x9fe7b7c6, 0xc13a9e3a, 0x0230e72f, + 0x50a16f27, 0x1b379099, 0x1aa76592, 0xa76ca348, 0x1ed5d79a, 0x28ab7b49, 0x299594c1, 0xbfba4552, 0x01f24d6e, + 0xf4922ea4, 0xb4e05b37, 0xc3dd1615, 0x3c06e8e4, 0x4a8ad17d, 0xe51718f3, 0x8427365e, 0xb70c5ee7, 0x6c37f62e, + 0x3836c541, 0x2fa81449, 0xe97a416e, 0xfdb0a32d, 0xb4c8f046, 0x5a803024, 0xf95c0423, 0x72143292, 0x3520d447, + 0x6aa31284, 0xfbe76462, 0x23f667c0, 0x5e1af6ce, 0x0e571b4e, 0x71eadfc4, 0x11c3206b, 0xdfc9d9ae, 0x26ff9768, + 0x16a32335, 0xaf3a4270, 0xee6ba67e, 0x6bfff43d, 0x92e94f96, 0xa42a24bb, 0x2ce8de0d, 0x4e8900ff, 0x0fb111b2, + 0x5156bbe1, 0x19869beb, 0x00998903, 0x0109d039, 0x68169926, 0x6888877a, 0xab907ace, 0x517d042b, 0xf32403c7, + 0x9a2dcf17, 0x65bc133c, 0xda49fb23, 0x666591cc, 0x36080718, 0x0e9e6a28, 0x1df74029, 0x560ee2f2, 0x2d7ad6db, + 0xec8ac356, 0xcd782824, 0x6ee6718a, 0x2489e018, 0x45380747, 0xc6aaab72, 0xc4aeb976, 0x4b5fd176, 0x56d01c52, + 0x85a6e792, 0xd11fc0a6, 0x7d9c5dfa, 0x5f02c3cb, 0x6ec41e5d, 0x9b06355d, 0x8a6b8431, 0x20a67a46, 0x61625840, + 0xa80343cf, 0x69c7d4f9, 0x9b424d80, 0x2b5f6126, 0xd34405c2, 0x30cf9852, 0x05595c09, 0x3aa31c6a, 0x2f6d984e, + 0x5a3ac0e4, 0xf70cb091, 0x02f0baaa, 0x3c7a0f04, 0x99d930a6, 0x20fe2f16, 0x9a839aef, 0x6156cb87, 0xe64d04c7, + 0x548761ca, 0x2be240b7, 0xec202c53, 0x1a6f1b85, 0xf0d73775, 0x988c1a20, 0x87f8d890, 0x1be5f4db, 0xdf8b0d89, + 0x0bd74773, 0xff364e96, 0xb5985ee1, 0x1face861, 0xed92d7af, 0x34279a98, 0x47396a29, 0x0debb108, 0x660933e9, + 0x3558e44c, 0x27ee15e6, 0xbc416c5c, 0x4e63a2d3, 0xe29f4765, 0x89323340, 0x41b128a6, 0x82b03ba4, 0x5adfb63f, + 0x68d0da97, 0xb0e8b310, 0x52b2af6f, 0x941bd148, 0xafdd80b9, 0xfdc0e28f, 0xab76741a, 0x91ef5bc7, 0xb42a5376, + 0x6413ba09, 0xd13bf8e3, 0x19c005d5, 0x30c60abe, 0x7faf3025, 0x9c0d55b9, 0xd74270ba, 0x22397da9, 0x2d37002e, + 0x948045cd, 0x2e6a1ab4, 0x6001ca81, 0x9fceac1d, 0x53265c57, 0xe67990c3, 0x30df0964, 0x085eba7c, 0xd79785f5, + 0x015c8f34, 0x26b5618c, 0x572ffdc3, 0xcb7c6efc, 0x0d396a72, 0xdc5ba6d3, 0x9487b52d, 0x734ae521, 0x323bfe11, + 0x75eda77c, 0xcab2ee4c, 0x333537fe, 0x966c1654, 0xcb06f59e, 0x08cf5ef7, 0xd922ebe0, 0x442b62f7, 0x13aa05c9, + 0x23ef2f57, 0x0e5e936c, 0xd5e30e95, 0x8c1f390a, 0xf1a8d855, 0x03092ed4, 0xe0be66be, 0x12613541, 0x8836a73d, + 0x72e91444, 0x7b6e9e19, 0x6770ef3f, 0x3d4c3e11, 0xa551fc30, 0x6acffabb, 0x8d0461d3, 0xcd7c11ea, 0xa058650e, + 0xb5af3f63, 0xd7c72310, 0x89996dd1, 0x45ddddd0, 0x714dd262, 0x40c9899d, 0x93b516c6, 0x13c38ab0, 0x8f655617, + 0xa788b67a, 0xf5f534d3, 0x91000fde, 0xbe39c975, 0x1fa49583, 0x6bc41700, 0xeccc3186, 0xaac89d2f, 0x3ac36429, + 0x4e559c4f, 0xfa76ae5c, 0xa54bcc3f, 0x582fa019, 0x601d0a53, 0x1177f559, 0xd7538323, 0x140b075e, 0x0de7b9f5, + 0xf914cd55, 0x5a1cdfb2, 0x27843800, 0x687c5c6b, 0x3592ee25, 0x0d8043d9, 0xed37229a, 0x1334ff2c, 0x8aa36947, + 0x41304a23, 0xad924b66, 0x535316a6, 0xefa91fa6, 0x99865e8a, 0xdee66a10, 0x0c6b34d1, 0xbb447d03, 0xfbd1c1af, + 0x1b2f9b30, 0x1fa87057, 0x7979f79d, 0x22bd3b6d, 0x4839c8f3, 0x561d7c2e, 0xc2ed09ed, 0xab9d9c45, 0x00282bc7, + 0xaa5f2dc1, 0xf0decb87, 0xe4e262fd, 0x9ea7c937, 0x2e91f05d, 0x29fa6e7c, 0x589af698, 0x65ce72fa, 0xe94b226b, + 0xee110622, 0xfef14923, 0xaeb74b76, 0xd512d16d, 0xa43db851, 0x0ff005cc, 0xbb8a669f, 0x9a37737a, 0xc7f3a4e4, + 0xce663011, 0x01d93e66, 0x9a79f011, 0x182f1d57, 0xbb997e05, 0x51a5f868, 0x5026cf8c, 0x541b2afb, 0xb0357292, + 0xdf887e66, 0xaffb056e, 0x8bdc84d5, 0xbcd6d0f1, 0x5aeca172, 0x89dd1e4d, 0x4cde142f, 0x2ae46685, 0xf1f8683b, + 0x75c5f91e, 0xed764bcc, 0x6bfdbddd, 0xfbbc7820, 0xba0a87e7, 0x16bd6e21, 0x64208676, 0x7592e859, 0x77f17e7a, + 0x45d102da, 0xf08b5e98, 0x9062818a, 0x36ebdd06, 0x286fc746, 0xe2b94456, 0x867ba065, 0x014d0703, 0xd59a6bdd, + 0x66ae55bb, 0x94b2de64, 0x5c658b4d, 0x513a070d, 0xc5800ee5, 0xa33e99c7, 0x5ad0aa11, 0x5f8a702d, 0xec567ead, + 0x303bc93c, 0xd51fa879, 0xfd71ff63, 0x2c14b25f, 0x3090bc32, 0xe1f16063, 0xcec11be8, 0x37c7ed1c, 0x3ac47310, + 0xcc7a2aba, 0x6a06740a, 0xf07dbf07, 0xcc51c7f8, 0x7b19f202, 0xcc254be3, 0xc43eb860, 0x37229372, 0xd32ee18c, + 0x47c97eb8, 0xa3074ba3, 0x19cf1f33, 0xbf0ba866, 0xec5e40b6, 0xa46de06f, 0xc4e22ba6, 0xde9f475c, 0xfd6f06c9, + 0xb5ce42a0, 0x07c91f7c, 0x4a7eaee2, 0xcc3512c3, 0xeeeaa493, 0x69355fb7, 0x0fabe2ba, 0xb8235f49, 0x9575c22b, + 0x85917191, 0xb7e150d5, 0x52714a43, 0x0bea31bc, 0x15d46f14, 0x4d9ceb60, 0x2b75f13f, 0xf2cdf13c, 0x22f89612, + 0x06b23cc8, 0xb286ec49, 0xd14d51d2, 0x6dc74093, 0x09deb8ad, 0x423003e8, 0x0fb86d7e, 0xb7931352, 0x3f15e768, + 0xce2e6053, 0xce820c0b, 0x39969159, 0xf58f6c2c, 0x17e3000b, 0x054550fc, 0xcce890f0, 0x1e7e1663, 0x881394d0, + 0x5035d6d7, 0xbf4ded66, 0x92c6b059, 0xe71e34d8, 0x66040859, 0xdfaf3d7d, 0xf7a88eba, 0xa69c22a1, 0x3f98601f, + 0x157f64fe, 0x8efc006f, 0xbe741083, 0xd582182c, 0xd1c721e2, 0xe8f7c15d, 0x042d5608, 0x4845a6bc, 0x67ce7309, + 0x2ef301d6, 0x767ef04d, 0x378cc80c, 0x1a67645a, 0xc6bf9998, 0x3148a4fb, 0x402db3f2, 0x5a565288, 0x8c824566, + 0x6a09c4c5, 0x0139d0a5, 0x24190a3b, 0xfcb9c44c, 0x908037e8, 0xa1b45979, 0xc1c28dd8, 0xd4660368, 0x094d38bd, + 0x4464d821, 0xd1fbbd5b, 0x477d1c5e, 0x49c9e4fd, 0x6d292204, 0x06685867, 0x5e163f4b, 0xb3d2ccb2, 0x1de6a635, + 0x4109efb6, 0xcca5bc55, 0xe72f0e50, 0x2d0df549, 0x1cbb2295, 0xf949f37c, 0xe977db79, 0xd6603080, 0xf3961734, + 0x41dbcade, 0xe44cd224, 0xe57a21f4, 0x15d6e904, 0xe9780399, 0x6b10b970, 0xc530b49c, 0x1a203c58, 0x8e145aab, + 0xdf75c21d, 0xc923c810, 0x29c3582a, 0x952f1091, 0x6fd55f4b, 0xb2dd1c9a, 0x28e73773, 0x0f0a2387, 0xa75a65fc, + 0x841f4ca3, 0x0cfba305, 0x50e92eff, 0x5b02ac28, 0x3416d995, 0xc2ed9457, 0xd132c124, 0x9c859390, 0xa4f2b1d7, + 0x7aa35973, 0xe8ff0066, 0x88ce939e, 0x975d89ab, 0x21cc33e8, 0x3aa0234d, 0x64a89ddb, 0x771910f5, 0x7ac895bd, + 0xe9d2e065, 0x050daef4, 0x808a542a, 0x494ffee0, 0xd59d8b99, 0x571e90a8, 0x717d47f9, 0xe833f960, 0x84896f7a, + 0x3c50eac0, 0xc428d923, 0x42255956, 0xeb3fa42b, 0x060f6c65, 0xd99a206f, 0x4024f207, 0x4d95be31, 0xc3be8937, + 0x7abcad25, 0x47e877c2, 0x414d7f2c, 0x4d789275, 0xafa6e333, 0xc421c820, 0xca7d02f0, 0x92cbb6ea, 0xfdc16e8f, + 0x2e474b1a, 0x0db44f12, 0x8dbf6bc5, 0x8cf93902, 0x7cbf9cf7, 0x6652eab7, 0x19f9452f, 0xdfc02ba4, 0xe67a30cc, + 0x96cc47a3, 0x514a5ddc, 0x49745467, 0xfe7b7b1d, 0xe36cb0c6, 0xa017f6fd, 0x66e2526b, 0xbff15e89, 0x1020d23a, + 0x8f002bc5, 0x47aeab4e, 0xe0f80a37, 0x48df92a2, 0x74785480, 0xc3f03b90, 0x719cc254, 0xe86fe8e4, 0xbd5709ec, + 0x5a0d8360, 0x19eb423e, 0xe8a4590a, 0x6b625fc8, 0xb587c720, 0xb7518ac1, 0x908b288c, 0x07f8ae54, 0xb5d3a315, + 0x8fa056b4, 0xead99143, 0x5865f5f3, 0x622733bd, 0xd00d4c4e, 0x365406db, 0x089fd9d7, 0x2326c4cb, 0xdf3a6613, + 0x671f9573, 0x08952705, 0xbc56e67c, 0xa8f65d12, 0x607cbf2e, 0xe1feb2ea, 0x10f55dfe, 0xe0dbc989, 0xb68abd18, + 0xd73160c0, 0xf836d33e, 0x34c9bdd8, 0xe893aa38, 0x68a24948, 0x8ce047ac, 0x7ac9eb06, 0x97ea3c8e, 0x2964a8e6, + 0x8cb41b49, 0x567b2ca3, 0xc42d06ce, 0x1fe5708f, 0xcd3fd57f, 0x86a50126, 0x60e1f91f, 0xa17191e1, 0xc029e0ab, + 0xa5b0e130, 0x25e8a781, 0xfd9835fe, 0x73a79d9d, 0x2e943bf0, 0x90fd117d, 0xa75111e2, 0x0cf291bb, 0x9864533d, + 0x6d2cc765, 0x7583bf4a, 0x56a42ca6, 0xf4e1dd36, 0x48e985e9, 0x91697466, 0x84fe477f, 0xb2ec50da, 0xba432f62, + 0xad470c18, 0xd9d82759, 0x22b7c4fe, 0xbdcf293a, 0x61a79d69, 0x527c2cd5, 0x0a32d39a, 0x2ebeaa19, 0x20bd5163, + 0x630f6a37, 0x6c621c77, 0xa5c5b4f9, 0xd74f3af4, 0x0851615f, 0xf56f733b, 0x0398dfcf, 0xb3da4c98, 0x7583b3cb, + 0x82837e00, 0x387f9b4d, 0x69a7de14, 0xe1285139, 0x497eaedc, 0x0e77c541, 0x583b9787, 0xdc8f2093, 0x7e38d155, + 0xa1def861, 0x67ac81b6, 0x15c4ad89, 0x3b1ab578, 0x4c02f0fb, 0x68fb9868, 0x2c649404, 0x41bfdbd3, 0x4a5335eb, + 0x1c7d5496, 0x91af5222, 0xf1048224, 0xfdc96ada, 0xece576fc, 0x11fabdbc, 0xda7fe528, 0x0dcaeb98, 0x9eab2278, + 0xbfc5b050, 0x968d6c65, 0x73a152c9, 0x96afb943, 0x8423e786, 0xf5724591, 0xa2b95e95, 0x25d86ea0, 0x2acbd2a1, + 0xdb33db83, 0xa6b2fc95, 0x1814a37d, 0xa983c41c, 0x0e28c8de, 0xcfc6e05e, 0x3e2e7422, 0x967e18e6, 0xdec391a9, + 0xf8c1cdaf, 0x466b05a0, 0xcd0bc501, 0x47856b62, 0x3f6753c9, 0x7c7f66bf, 0x0d2f24ff, 0xe2dcae9a, 0x6881242b, + 0x247ef3cd, 0x5ed35a8f, 0xe32fd120, 0x1fff2873, 0x0a6aff48, 0x51337b9a, 0x03baeffa, 0xf370b7e5, 0xa2828d7c, + 0xa6d9e560, 0x1da4646f, 0xd9b76042, 0xf12f593c, 0x38d490c3, 0x1d08d9c5, 0x6252bd2c, 0xd0465521, 0x6c429df1, + 0x2e8d7856, 0x5d58c5d3, 0x19234d9c, 0x711d4b2a, 0x47d69a24, 0x7a3d7d58, 0x06a5dcf9, 0x2a73c392, 0xf483bc9a, + 0x9377be88, 0xdd3fdd7a, 0x642a2c64, 0x4301c667, 0x0e5ca558, 0x5f6453c9, 0x550f5898, 0xbcbb4509, 0x8e606308, + 0x8a283d3a, 0x8f59b5b9, 0xd87f97a9, 0xea71f25c, 0x7595be93, 0xfd2c2e15, 0x9949a5a2, 0xebe688e3, 0x412a0663, + 0x882a376f, 0xea86b809, 0x9eb9b08f, 0xbcc70db7, 0x3b3f77bd, 0x963962e5, 0x785268c3, 0xc6885d94, 0x97158093, + 0x75b596f9, 0xa2ba4e88, 0xe1f6e7c9, 0xbb05d8d6, 0xf398ef64, 0xdcbdd911, 0x1e43e9a7, 0xd87a394c, 0x38fe3806, + 0x1dc59842, 0x31a5b092, 0xc8a51eab, 0x9be1ad08, 0x220ab635, 0x19c5770a, 0x919daf08, 0x5d9f0ea8, 0x3a11dddd, + 0xa6c5c760, 0x9836b704, 0xe8eb92df, 0x380b4b38, 0xa46e1e56, 0xa5bd2346, 0x5c3f37cb, 0xb8d8e7a3, 0x008e2b1d, + 0xb5c037fb, 0x78b5432d, 0xeb157ac0, 0x40079395, 0x63bb26ba, 0xb6281df3, 0x4bb9f2ae, 0x358f95d1, 0x9a34f9a1, + 0xb4217c45, 0xc4748d9c, 0xee82b7a0, 0x274ff722, 0x027cbec8, 0xef144399, 0xb4174dbf, 0x0b7ea567, 0x09066566, + 0x79b9ba59, 0x774354fa, 0x5aeea9bc, 0x11c35199, 0x33b18edf, 0x1a98605d, 0x55c6087b, 0xdc8ba586, 0xb404f060, + 0xd4674c4a, 0xe93d56df, 0x1f957c69, 0x5cd46c84, 0x1a34483c, 0x2824366b, 0x830985c6, 0x42680aed, 0x87a1d75a, + 0xbea94b99, 0x43fc4aed, 0x05a14a9e, 0x610d282c, 0x00bf5a10, 0x24c7b75e, 0xa987af8e, 0x2beefc14, 0xfd04eaac, + 0xd7cda449, 0xbdf2b5ae, 0x8a7a932d, 0x55181e88, 0x483a7084, 0xa7725b67, 0xf171c068, 0x85e95a67, 0x2b238176, + 0x8ca0e92d, 0x1efd03cf, 0x5f30b7c2, 0x35ce7c70, 0x6d29a66f, 0x7edd31c7, 0x5ed2bccd, 0x8b64a1e4, 0x6cf1052f, + 0x7a264905, 0x48381744, 0xacd7af2a, 0x3fc21a68, 0x0a32f1c1, 0xfa8cee53, 0x23a188ea, 0x96f928db, 0x65e5f721, + 0x8896be3e, 0x79c95f23, 0x85e254bc, 0x6bd0a976, 0x4614cb4d, 0x8fd4eebc, 0xb77ae8ba, 0x46eee69a, 0x32613b7a, + 0xe05b6f63, 0x8f82714d, 0x80760a51, 0x87ae6b02, 0xd8ddc924, 0xeb74f446, 0x9c656f90, 0xd0c86289, 0x85f3cafc, + 0x798a9bc2, 0x5f9ae71d, 0xe57223ff, 0xd10e8f7b, 0x73683787, 0x7949fbe0, 0xacef31fd, 0x2fb39308, 0xa0a78e77, + 0xca63d164, 0xfb105716, 0xd545708c, 0x99a64231, 0xf66c73fc, 0xd6981d9f, 0x1195bce9, 0x5f84c3c6, 0xcf043146, + 0xc349d591, 0x978f2a3a, 0xc1f3c56e, 0xa22597bb, 0xdf5e8ca5, 0x57f3a5cd, 0x3c75db23, 0xd8a0cae3, 0xcb464739, + 0x92a22fb8, 0x137fc573, 0x48f08f51, 0xfdddfaec, 0xcef4f563, 0xd00cf064, 0xc2277f6c, 0x15e0c731, 0x2e2380fa, + 0xc4a21ba8, 0x2c0a6f11, 0x40fb3ab0, 0x8badbc83, 0xc046c55c, 0x1d4a2ce4, 0x0fdbb21e, 0xb89f7579, 0xcc20dfdc, + 0x4c3c076a, 0xee2e189e, 0xf7bc4389, 0x30aa2723, 0xc6637341, 0x76d22379, 0xba9c24da, 0x0d549221, 0x2b521f83, + 0xb96ce6e4, 0x9a270570, 0xef2d2d8b, 0xf630de88, 0x1d68f148, 0x755be74f, 0x572dda3d, 0xc880d1bb, 0xa480a2bf, + 0x0275abc4, 0x134e76b3, 0xc1fc7bc2, 0x10d382dc, 0x77eb11f9, 0xef7ec99a, 0x1e89321b, 0x80c89381, 0xd92394f2, + 0x920c3ff1, 0xd51a8aad, 0x924a2de8, 0x93f76e70, 0xbc58895e, 0xec93cd47, 0x34a49aeb, 0x63337226, 0x91a38da2, + 0xf6fec034, 0xdb582cdf, 0x7d2f5d23, 0x84256a8d, 0x54298cd1, 0x5f6f5aa3, 0xd63b9872, 0x06b68f5d, 0x301927c3, + 0xfb58d6f1, 0xfc85feac, 0x529041f3, 0xf281120d, 0x5b435dc1, 0xea1ad755, 0xeba93607, 0xa160bec8, 0x686be916, + 0xa9a0fe45, 0x11b3a017, 0x9695e787, 0x1a527686, 0x27c5c5a3, 0x7b7fd69b, 0x3698269b, 0xf1b338c7, 0xcf7a981d, + 0x374c8d8a, 0x47551372, 0xae7df52d, 0xee4f0314, 0x022dac8d, 0xf86683c3, 0x85e0514c, 0x34296669, 0xd90c2666, + 0xd25cd66c, 0x1ade45f6, 0x20e261dd, 0x1a708f5b, 0xd0afd891, 0xf4f216a2, 0x5131f618, 0xa5cb3590, 0xc96a4607, + 0xa4f59362, 0x2f1a843a, 0x2d7a3af1, 0x523448ce, 0x67e0e60b, 0x7f413934, 0x691e9a09, 0x1be3964b, 0xa72ba854, + 0x50f01bcf, 0xfeeed1c7, 0xc92a0f45, 0x4ef0303e, 0xdaea127f, 0xd3d2813f, 0x85da1e4a, 0x77e8a4ba, 0x9551d67b, + 0xb53f2fb8, 0x91e5e71f, 0xabf57b37, 0x823b212e, 0x521276c8, 0xac9aa4e6, 0x9aea28a9, 0x958b2606, 0xecb21b4e, + 0xdfc34544, 0xd9f73c63, 0xc338d301, 0xd5d1e1e0, 0xfa5502fd, 0xc22446c6, 0x915e4456, 0xf7cdc94d, 0xcd014f53, + 0xf8ea9521, 0xe4f76a36, 0x3957c7ef, 0xfb86e904, 0x1271140d, 0xfab4d396, 0xcf55cdf5, 0x68b1b0a5, 0xce9a1e33, + 0x1df7dee0, 0xa260c05f, 0x79110388, 0x1caf33f6, 0x119e80a8, 0x265c3877, 0xba7df2c6, 0xb2a3dcf3, 0x101d735e, + 0x7af10c1f, 0x4b660584, 0xd63164cd, 0x6fb408d2, 0x178f79c5, 0xbcc9d5fc, 0xb267d6a4, 0x6e818671, 0x92c12e49, + 0xfee90383, 0x6e1df870, 0x0d56153b, 0xdd64cf3b, 0xb92931dd, 0xd405a17e, 0x63134d9c, 0x78e7d0ce, 0x3a745fb6, + 0x718ddf30, 0x3a67d066, 0x809dd98a, 0xc35c229f, 0xdb973329, 0x202b6f3c, 0x98aa0410, 0xfdc8e66c, 0x12346da3, + 0xc23c79fb, 0x00e41bee, 0x4babde46, 0x3506be8c, 0x4b94ad26, 0xd9b73b51, 0x9709ae21, 0x62be514c, 0xd682c41f, + 0x44fccf59, 0x71b82161, 0x0adb26c8, 0xe940782a, 0x069e023e, 0xef3158b0, 0x9c09c0d5, 0xc4e11a2f, 0x29ceae0e, + 0xaae48adf, 0xfb41665d, 0xac69ad28, 0x45c70eb0, 0x547bfee3, 0xa1f628d0, 0x1435461e, 0x5e26a820, 0xbaf3dc4d, + 0x30a85064, 0x7e057d6c, 0xdb925ea4, 0x0d53c190, 0x0c4e8096, 0x97025ace, 0xe3be59e3, 0xea38f3b1, 0x36fbe9e3, + 0x00e6164d, 0x63c37718, 0x3f8876cc, 0xbe3b5ff0, 0x4f78c178, 0xa0db503a, 0xa5e8ec92, 0xac65eb90, 0x1b64374e, + 0xc25dc447, 0x43c77668, 0x9ac81ae8, 0x8b2148c2, 0xc7be06f3, 0x665e717d, 0x7d2fb20c, 0xdce2ed08, 0x58ddd50e, + 0xe8490fc3, 0x352aed9a, 0x6048a136, 0x64d4154b, 0xe322afbd, 0xb9849208, 0x2b48d3e8, 0xd397eccc, 0x97bc4508, + 0x73e959f4, 0x8d8e4399, 0xbe0b252f, 0xba4f63d3, 0x0926ec84, 0xa9bd06ab, 0x5c85ad05, 0x2333dc9d, 0x5da9bc25, + 0xa5363feb, 0x83fede6b, 0xa309e4d7, 0x9360f873, 0x1ee0c145, 0x1da29d11, 0x78c65ca5, 0x7e8f898b, 0x8c67b9cd, + 0x59658b21, 0x68048374, 0x386b93ba, 0x72ed6748, 0xff4c680c, 0x7e63ac11, 0x2df9ac85, 0x64c19090, 0x046e16d2, + 0xfa34c209, 0x1ad2918c, 0x3cbe6b0b, 0x21835054, 0xd49f2562, 0xbd6eb102, 0x600ddafb, 0xb3d85b99, 0xc011c65b, + 0x9f10af35, 0xd4da6016, 0x46b957ea, 0xe3ebf5e4, 0x6d0aafeb, 0xa3793fcf, 0x4dadcd1e, 0x8e870d9c, 0x9ce85a0d, + 0x296eee8f, 0x4d615420, 0xdba06c72, 0x2df30826, 0xd9420c66, 0xfd2254ba, 0x0a23d765, 0x6f198fab, 0x0a7d772e, + 0x110114fe, 0xf02300f7, 0x1ba482f5, 0xe0e468dc, 0x6e3d2b68, 0x5ff55968, 0x2ee48683, 0xb91a9d11, 0x4f25380a, + 0x440c103f, 0x10e84d1f, 0xffae36cb, 0x505cd8f9, 0x481341a1, 0xea09785d, 0xfabd7bb0, 0x3c64e43e, 0x3bce8420, + 0x82588c96, 0x85d97742, 0xfeafb100, 0x4e7f7e6f, 0x33795900, 0xe1d159e7, 0xc808b506, 0xd8d6ce67, 0x4fde6d1f, + 0xdd512033, 0x8db1ac08, 0xb9631c38, 0x768c85cd, 0xa0bbb47c, 0xf0f58a5f, 0x992d77f4, 0xe791c080, 0x4bc33751, + 0x7f9ab91b, 0xbb1c9a81, 0xf8db8248, 0xc07e14e5, 0xd28a2c03, 0x2bd38dae, 0x653f023f, 0x98ce4e04, 0x374d0ca1, + 0xf8eff233, 0x088979ec, 0x1d964906, 0xdbca29de, 0xd5a42b45, 0x4fea1e02, 0x0061bb02, 0x592d6b35, 0x93575f87, + 0xea5faf9c, 0x7f8bd1d9, 0x4a0b3e50, 0xdc342977, 0xb659d1da, 0x182c62df, 0x806152a1, 0x62f44913, 0x0c3074f2, + 0x4f66b079, 0x0180fda7, 0x37462db6, 0x35405bc2, 0xfca474f6, 0x2b6a05bf, 0xdeb75149, 0x260e1ed9, 0x90725e71, + 0x99566cc0, 0x4b140ea7, 0x04e04c5f, 0x79f13cf4, 0xb3014f91, 0x17f05104, 0xe4514c22, 0xc8320441, 0x1c69dd26, + 0x688b7ebd, 0x3570da4c, 0x1fb280ec, 0x7dca108b, 0xa2af28a0, 0xc43f41fa, 0x5a26dd83, 0xae40a89f, 0x9230bb91, + 0x89151243, 0x00ce1886, 0xba41cc84, 0x82b2f07a, 0xc427319b, 0xf26a40bc, 0x7a43dae9, 0xa943734b, 0xb08bed6d, + 0x0f2f3b25, 0x23deb49c, 0xce5b94cb, 0x43b06766, 0xb8e060ff, 0xa2e3adef, 0xb288b9b7, 0x1878c4f9, 0xcfef961d, + 0x385c8bf9, 0xc00e4b34, 0x143e494b, 0x3bfd4ab7, 0xab86b20f, 0x7bac5887, 0x9adb004b, 0xe2f7386a, 0xcf63de88, + 0x122982c5, 0x23fe0be6, 0x86869a24, 0xb9a0294f, 0x3cac3a2d, 0xa989d551, 0x46cca422, 0x93850592, 0x7703cbf2, + 0x5ddb8806, 0x7b8671d8, 0x84297390, 0x084bbc5c, 0x4e8a85b5, 0x546d2b9c, 0xe640d2ac, 0xbc41fc34, 0x49c66e5a, + 0x1243b6ff, 0x4d5b7b00, 0x423a4259, 0xd82b35f3, 0x84d79ad8, 0x6076f45d, 0x368e650e, 0x4646bf20, 0x5c6d7fce, + 0x2d317ae5, 0x26446213, 0x9002ccb9, 0xfcd0b157, 0xf22b192b, 0xc476494c, 0x556cb31f, 0x3ec6632c, 0x9fd8ce9f, + 0x4785dc41, 0xc1948223, 0xff525386, 0x987fb97e, 0xf6a4a318, 0x672f9c85, 0x25c841ba, 0xb4f6c245, 0x3a0e57a4, + 0x33c3d16e, 0xbffef1e0, 0x8f0f1f59, 0x24539ed9, 0x2e13a99a, 0x55e3c346, 0x746c9d2e, 0xf0ff32f9, 0xd10b6be9, + 0x8dab44bd, 0xb641b6bb, 0x97cf1e58, 0xcd847351, 0x4c2eb2e9, 0xf77f44b3, 0xd1491f39, 0x425f7737, 0x0785ba56, + 0x2009894d, 0x061834b4, 0xa3fdb6b4, 0xcc71c4a9, 0x4de227d5, 0xdec56827, 0xc4b1042d, 0x101fcb36, 0xe4ab8111, + 0x641c756e, 0x6a8e7fc8, 0xb9ed36ae, 0x5c893b22, 0x932318d6, 0xf20d2c4a, 0xb3f23214, 0xf05e2843, 0xdb19a0ec, + 0xbff91375, 0xc06e6a8c, 0x80d3cacc, 0x93bf9da2, 0xcaf82bfb, 0xf01a9338, 0xe9840283, 0xc595ad44, 0xc06693a7, + 0x19cceb32, 0x830bbca8, 0xb6201d49, 0x55e02c55, 0xb112c15c, 0x87ab11fc, 0x4953f795, 0x19b871ca, 0xfe6a7e44, + 0x2a68ef1d, 0xa3c9761a, 0x93e20657, 0xa069b571, 0xa74b6a49, 0x9b839f55, 0x7102b945, 0x8b708cb2, 0x04e438ee, + 0xb1ad3842, 0x39685293, 0x79c7c7d5, 0x47cb9ac8, 0x2ad472ee, 0xddcdfe2b, 0x889f417e, 0x2cca9e32, 0xefa76a2c, + 0x386c44b5, 0xc92ca154, 0x2905429e, 0xe22a1faf, 0xc68a365a, 0xbcf74cbc, 0xd551085f, 0xdf95e0bf, 0xfd16caa8, + 0xf9b3b860, 0xc75c05bd, 0x834bee54, 0xefec7a2d, 0x3daafd31, 0x1302cb58, 0x338360df, 0x4764527d, 0xfbaa8d76, + 0x08ddf5a3, 0x83f5cdb6, 0xbb343fd8, 0xd5db52e9, 0xdc0858d4, 0xaa7e3037, 0xb630fb70, 0x93e92179, 0x999b1fd8, + 0x632f415d, 0x89edb642, 0x3b489d22, 0xfeeaf4cd, 0xba70aee2, 0x4ce0f2ce, 0xecf0b998, 0x376c6c60, 0x24fd7a0e, + 0x408f86f2, 0x87a27b7c, 0x8e3526b6, 0x52f2e875, 0x4202eb8b, 0x2e956f79, 0xfae24b19, 0x14956ba8, 0x84187c48, + 0xd23582db, 0xb8ce36db, 0x884319b6, 0x79a6ab12, 0xf3028592, 0x18f25623, 0xd8584e85, 0x12fbb469, 0x96675019, + 0xe9dd4f8d, 0x6b8755ee, 0x0642af8c, 0x1d36aeeb, 0xaab9b1a6, 0xeb16651c, 0x2aad844a, 0x75011c0d, 0x01f817db, + 0x3202e9f9, 0x8002c09a, 0xb7611350, 0xe670b86b, 0x513e0364, 0x303d52c3, 0x59a27a83, 0xb0ae03bd, 0xc4623216, + 0xbda1ee6d, 0xb1b091f0, 0x66419520, 0x159dabb2, 0xc60f10f1, 0x8adc241c, 0x6379637c, 0xc13f56c4, 0x3d782add, + 0x5332eb29, 0x84fe40b0, 0x6f9b8c25, 0x98cd698b, 0x3c91bdcd, 0xabe0d203, 0x6a8aa0bf, 0xc632b0d5, 0x9322f4e1, + 0x016a5c06, 0xe0950643, 0xeabba82a, 0xfb4839f8, 0x6b361b2c, 0xe4f6ef57, 0x5f8304e2, 0xe0faf284, 0x2618ceb6, + 0x3bb2a83b, 0xbdb29c20, 0x6d403939, 0x3ba28775, 0xbb8cdb4f, 0x12c73bf4, 0x7222a5fd, 0x92ab50ba, 0x43da5016, + 0x64ee03c7, 0x6dffebea, 0x904dfeb8, 0xeb94e8e5, 0x9dbfb4c0, 0x97c4bfef, 0xade596e5, 0x7ef69e2a, 0x17320da8, + 0x9f7c13d7, 0x32f79678, 0x0f706522, 0x8ce1745c, 0x585e66f6, 0x0d2a7163, 0x3cc6e32b, 0x72d36b41, 0x3e1b11ca, + 0x55d79b6d, 0x140a8f9c, 0x97ab5875, 0x0857d741, 0x55aa8080, 0x06eb0366, 0x5b0e8207, 0x34b63684, 0x452bc34d, + 0xccb578de, 0x4d99f00e, 0xe70d25e2, 0xe1d5215d, 0x92a6fe29, 0x0d77a657, 0xbda29c3c, 0xb8562c64, 0xcca110bf, + 0xeae87c1f, 0x6b34cb6d, 0x6494cc4e, 0x465c44ad, 0x5a3b54cd, 0x4cfe7f81, 0x0e3c6be6, 0xe9ba4a4f, 0x0dc93cb0, + 0x027321ab, 0xc15a5b08, 0xa664014c, 0xf697e467, 0x44a269ac, 0x33f137a3, 0xabf5407d, 0xca8e6bb0, 0x0a7e2c23, + 0xf230d10a, 0xff28513e, 0x825e106c, 0xc1466a7b, 0x6122f876, 0x3247a996, 0x0ae704ba, 0xb6ec4908, 0x286c2d8f, + 0x17121e18, 0x93e74fc0, 0xc13aa8f0, 0x41445738, 0x1a575229, 0x2857e08b, 0x7fa223bf, 0x1892d7f1, 0x00b0029f, + 0xd1d8eb69, 0x9f1b6c19, 0x1c426422, 0xbc8953cc, 0xa3f9906c, 0x86709420, 0xb084924a, 0xa456d362, 0xf7dedf70, + 0xa1e3f1a8, 0x4ebebb35, 0xb305cb47, 0x48f6e463, 0x7f7d8d30, 0x5a6fea38, 0x5353403e, 0x2727da5f, 0x44d5b2b5, + 0x3deb16ce, 0x738b6122, 0xe92ef69a, 0xf201ae0d, 0xee1ad0ed, 0x6aceb8ae, 0x781abeee, 0xc22f11c3, 0x725414ef, + 0xce2cb6ac, 0x7daf54f6, 0x020c6a3b, 0x031f4d75, 0x1894d62c, 0xca0fffeb, 0x37e7ee88, 0x665209c1, 0xa008877f, + 0x82a4ff49, 0xc9da567a, 0xaeebf726, 0xcf4ff7b7, 0x1cb2ffdd, 0x14e1649b, 0xd9aed141, 0x8241505c, 0x945b3efe, + 0x92c9f3af, 0xc1d522f2, 0xd3275946, 0x6897893a, 0x1f8ad80c, 0x98d22b23, 0xe6536db7, 0x956643b2, 0x6cbecc9b, + 0x6b9eee15, 0x60b1db83, 0x3df8aff9, 0xad0a31bb, 0x2588ce18, 0xf41abab5, 0x7d9a5df5, 0xbdc0c8d2, 0xc485e2eb, + 0x2e4dd81c, 0x303a8e0f, 0xdb8b29c3, 0x130fbff2, 0xcf73e690, 0x2e9f6e44, 0x42746365, 0xff310d6d, 0xf14b2f34, + 0xd88e9bf0, 0x57596e94, 0x7f8eb7ff, 0xc63d10cd, 0x27c57500, 0x8835deb1, 0x7b95bb12, 0xa3b252bc, 0x268f9a2f, + 0x5c9394bf, 0x1c529ea2, 0x4252b9ad, 0x6a3b2d80, 0x0dc6feb3, 0xe0c40df3, 0x374bcb37, 0xb4d1c43c, 0x6ec6c7bc, + 0xf70acc55, 0x05e2c03b, 0x9163d181, 0x1fe75757, 0x9797b609, 0xe7eb0eca, 0xcf91858e, 0x630c482b, 0xa2664016, + 0xcf252e2c, 0xba74c429, 0x39d45de8, 0xc65cf355, 0xd00171ef, 0xab5627b7, 0x40bf85cb, 0xbc457dd8, 0xc8acba4c, + 0xcfbb5410, 0x347a2c10, 0xd1604f45, 0x57253fd0, 0x5eca4d94, 0x154e8213, 0x499a301d, 0x93045fa6, 0xefa553aa, + 0xb705df61, 0xd6a02d02, 0xdca87a42, 0x58164b08, 0xfe6ee14c, 0x93de9e35, 0x7cb009da, 0x614edd7f, 0x997318a0, + 0x48d06a83, 0xeb3b8173, 0x7c9124e7, 0x129a9f69, 0xde4f1843, 0x4daae4fa, 0xc98dd5b2, 0x80711f0c, 0xb8b98432, + 0x6afd6a7d, 0x237cafd6, 0x6a1d1739, 0x1e1f4a7b, 0x4d60807f, 0x0eb5f5cf, 0xac17a5c1, 0x059def00, 0x63915622, + 0x0b4f04f7, 0x47e05a6d, 0x6f26843c, 0x32160f10, 0x09f2a524, 0x6e20ed8c, 0xa924c322, 0x3eb781a5, 0xef91377f, + 0x38e1b708, 0x2377eb80, 0x8f273417, 0x6c7ff686, 0xd6521cfe, 0x6411172d, 0x08e7fb30, 0x9c42a17a, 0x77da3386, + 0x8c54d79a, 0xffe9890d, 0x1d26f69c, 0x0843ea34, 0x0d7a00d2, 0xc71d06ed, 0xfe1f1ee1, 0xfcf60c5f, 0x49ecfda5, + 0x9744b9a5, 0x79ad037b, 0xf3295254, 0x9408d62e, 0xd2089a2b, 0xa96e44b0, 0x6d2105e7, 0x2308dc62, 0x7b3e3a59, + 0xb90d6712, 0x2bed7c63, 0xcc6e3906, 0x802ba1e4, 0x6c101187, 0x9209a3b6, 0x3439b4e8, 0x5a7ca881, 0xe87104b3, + 0x2c7d7aef, 0x4c88062d, 0x2767e555, 0x778a2832, 0x81671bea, 0x8cdd4a62, 0x87c7a182, 0x1811cb3f, 0x24a1f263, + 0xeb7f5b86, 0x17825365, 0x5d38951a, 0xfb43192a, 0x35ec7106, 0xf3839f6a, 0xd014dba9, 0xeccb6dfc, 0xdfdde2ac, + 0x6a78f6f8, 0xb957a08a, 0xa5a0b438, 0x594340c8, 0x27cf297e, 0xc3531989, 0x6266822b, 0x3cc2973a, 0xb7ba1b49, + 0x4554e92b, 0xdd8a4781, 0x80747c80, 0x5c84f275, 0xf1e08a54, 0x63b26a54, 0x9ee3cfb2, 0x2c1ab180, 0x928e0c6a, + 0x713ef5f9, 0xcb29fd81, 0x466e19cb, 0x73ad7994, 0xcd0d9fd2, 0x95079e9c, 0x3e1840f2, 0x98d188fe, 0x2d263787, + 0x4e80f9c6, 0x21fc932c, 0x481fe8d4, 0x7dd09c8f, 0xcb37f3d6, 0x4b7fda18, 0x611b8442, 0x0837659c, 0xed809f4e, + 0x27e20788, 0x921eee7f, 0xcaca8019, 0xc1a5915b, 0x95793086, 0x854fb687, 0x95387c17, 0x13affa9a, 0x1265dfd3, + 0xd4c14211, 0xb8bf4b9d, 0xeda029c3, 0x3bd88257, 0x906052eb, 0x7fa9d26e, 0x5f931a21, 0x62f488b5, 0x7c7a907a, + 0x11b3c083, 0xc2086416, 0x73a7b773, 0x9f315b19, 0x4da67f4e, 0x281c65ee, 0xa8d6dc9e, 0x1f326fbb, 0x60c7c2c8, + 0x7e8e109f, 0x303ffd8a, 0xa798de65, 0xe16520d1, 0x4981fc85, 0x45062f9b, 0x791bd730, 0x66413565, 0xea800adc, + 0x702dac0f, 0xcbdd9f5f, 0x3befe01c, 0x862716c7, 0xea2b2db1, 0x031554b3, 0x57ffa93d, 0xf4180050, 0x6353c01d, + 0xa4e1dc65, 0x77fbd09c, 0xb28f5fbd, 0x30c98b29, 0xeeafffc5, 0x92da180c, 0xdf55797e, 0x26480696, 0xc4987f79, + 0xbf505e85, 0xdfbfe6ae, 0x87158545, 0x85fb4f1c, 0xc53a518c, 0xea8af677, 0xd2c690f7, 0x43ae70eb, 0x9f08b876, + 0x9ed2951d, 0x3a76e31b, 0x6a06a676, 0x4eb0b6ca, 0xddcb040a, 0xea0102e6, 0x282778dd, 0x8aa8b52c, 0x18d36192, + 0x7b1f0b55, 0x7d91cc0d, 0xdb7ac4a7, 0x32360de5, 0x14829eac, 0x2c95b007, 0xd6e9b3ab, 0x7d185625, 0x1fe119d3, + 0xbb3709e7, 0x61a6e000, 0xb8d0cadb, 0x9b4cb940, 0x6ae4177e, 0xb33635df, 0x4e4504be, 0x2d121cb2, 0xfab87ac9, + 0x3462c954, 0x1a0150ba, 0x17b687db, 0x5674a163, 0x51633558, 0x48473e80, 0x9931c6b3, 0x7714e2df, 0xeda4889b, + 0xaf8bf3a2, 0xe45125e2, 0xd8eec389, 0x3bcd4aab, 0x31d624dd, 0x73ea8618, 0xe4f90245, 0x5c1c2928, 0x939562f1, + 0xcb07f20e, 0xf6473ea2, 0xcc9e6d5a, 0xeb32102c, 0x3aedf395, 0xd039d1e6, 0x8e497920, 0x9edaf04c, 0x7a06cf73, + 0xfe59d5f0, 0xba1e7f7d, 0x4e8457ee, 0x9532de6c, 0xbc44b684, 0x83618a8f, 0xba8f22fd, 0xdfc70430, 0x6ec19e87, + 0x8a0d57fb, 0x65aed5f4, 0xe53ce265, 0x029476d2, 0x9f23b29e, 0xed79a6bd, 0x13069276, 0x809fd09b, 0x224aae37, + 0xc0c17e86, 0xc8d090e2, 0x9a054495, 0xe3b2f645, 0xe4a56607, 0x7fde5923, 0xa6085047, 0x3c6915dd, 0x86260a92, + 0x6a5df8d7, 0x9c3f8490, 0xdec2d54f, 0xcf8f4791, 0x05ce2b7e, 0xb0431e8e, 0xc15df93b, 0xbef32666, 0x8fed613a, + 0xde33e3da, 0x211f455f, 0xae7e74cb, 0x91e869ca, 0xd0222242, 0x17f532fe, 0x36e871c5, 0x03dce7e6, 0x2cc404a0, + 0xf5edd78b, 0x62f3b643, 0xfa3b3a73, 0xdf60e9fc, 0xa6f36270, 0x9f944a27, 0x5e9b7903, 0x30577d11, 0xc74251c1, + 0xf391e655, 0x9afd385a, 0xd0915089, 0x34b582c6, 0x8e53c189, 0x590998a3, 0xb404735e, 0x99feca36, 0x82b4b314, + 0xf03b7437, 0x8d3f7c7c, 0x6202c4b6, 0x7de08a50, 0x80831a0c, 0xaef3c25e, 0x7ebdaa43, 0x295d363f, 0x164eed08, + 0xf7b56d05, 0xba0d366b, 0x2fec815a, 0x32dcff60, 0xbe52bef3, 0xc9e5c7a3, 0xe23a6d46, 0xb3d16f0e, 0xd33e9f56, + 0xb7e14024, 0xb1687701, 0xc318a032, 0x6b1fbd29, 0x6d0fd67c, 0xc6813c3a, 0x9073dfe4, 0xb2a52f69, 0x603d5aa8, + 0x186dc23a, 0xb19fe058, 0x15918a0f, 0x7f92f1d9, 0xb0f63360, 0x44510629, 0xeec4d38e, 0xfe0b2224, 0xed9c0c36, + 0xfbcc251f, 0xf996b3c0, 0x54d757af, 0x258bb9e1, 0x6fd36ccf, 0x288cdcf8, 0x72c84a79, 0x60424c28, 0x96f5d1e7, + 0x72b80daa, 0xfb019cdb, 0x3a3d4edb, 0xcbdbe00f, 0xab692ab6, 0x830f8156, 0xa1d3c549, 0x5f8f79c3, 0x7baa8fd8, + 0xecab0d98, 0xf0f7d0c0, 0x8dad9dcd, 0x6b48dda0, 0xdf173050, 0x8145c9a0, 0x1049d16e, 0x049989e7, 0x703af244, + 0xb38ced37, 0x0e76aea6, 0x92e6f482, 0xf17be074, 0xaff66620, 0x4a608449, 0xd70ab9fe, 0xd74634f0, 0x261a0c08, + 0x689fdcd5, 0x29df6cf8, 0xc605bced, 0x94af3610, 0xa44e705a, 0x0207465f, 0x8c9a79a2, 0x6936e1ca, 0x6479a67c, + 0xf597ee5d, 0x4daef02b, 0x774dc7d4, 0xd1a64c2f, 0x23ea116e, 0x1d454a88, 0x6d911501, 0xea803fa1, 0xc6273e3a, + 0x2d079197, 0xb1b335dc, 0x577c8c01, 0x32e2cc6e, 0x038e6d90, 0x3f738501, 0xc378c547, 0xfcf4333e, 0xbaf35831, + 0x7903121a, 0xdb90b023, 0x15afe0c8, 0x676dfe3a, 0xdefbb420, 0xe430eadc, 0x0738825b, 0x330753c1, 0x1f466aa3, + 0xa4689c72, 0x6f58520a, 0x85069376, 0xabbb46ca, 0xfd92fa75, 0xe28f301e, 0x5592fcb2, 0xf3227250, 0x376b6b87, + 0x2335fddc, 0xe7ba9e99, 0xecf78d87, 0x8dd13660, 0x11078673, 0x7f5220a1, 0xefc0f15d, 0x114212d3, 0x3de139e3, + 0x270fa8dd, 0xc84e0acc, 0xba9019cd, 0xc5e6b026, 0xe92a73fa, 0xfa730c30, 0x9a455713, 0x91adc37b, 0xeb2cb387, + 0x40e8442a, 0x9ff1fbc3, 0xac001903, 0xa8506003, 0xc4fde392, 0x1692156d, 0x859645df, 0x404ff85f, 0xfdab6112, + 0x18c12a6c, 0x8bdfc89c, 0x3598cc83, 0x6ff6a0ff, 0x2eafc9cf, 0x6afe2e6c, 0xfe3f08e9, 0xbb4c48af, 0xdb1d8ec6, + 0x8ccf8cc4, 0xc3926353, 0x80be628c, 0x147967d1, 0x3fe08b19, 0x639e60d6, 0x7e215332, 0x0b89fcaf, 0xdc00eb8d, + 0x1bb3d406, 0xa89f7406, 0x24fce5de, 0xf0367b8f, 0x1772ac68, 0xa8d0fc36, 0x6ee98359, 0x796c26b5, 0xc2a62942, + 0xa7951fe8, 0x7f8252c3, 0x3c1be70c, 0x026c93bb, 0x2b503aac, 0xec0813a5, 0x15c1a7f3, 0xca14fc91, 0x9e7fdc33, + 0x01964477, 0xc85fb08c, 0xf80fc8e7, 0xef15b674, 0x9b3c6950, 0x7c47952d, 0xf766889e, 0xa68397f1, 0x413dff04, + 0x4c1e9a8d, 0xbd491c31, 0x8489fdba, 0x04252ae3, 0x519d743d, 0xcbf9c49e, 0x602f0a8b, 0x869f2a37, 0x5c1e0f2b, + 0x4b8a048f, 0x6b53487b, 0xfdac92ee, 0x54b61b8e, 0xc6c8fdab, 0x72e8a273, 0xf40ff63d, 0xb3665b0f, 0x8e59fe8f, + 0xb5988047, 0x0143dc98, 0x6fd3cfa4, 0xb32bac7e, 0xfecd3882, 0xe0a0d15d, 0xcad22874, 0x7c6b940c, 0xa8cdb0f9, + 0x72470124, 0xdb1221e1, 0xd7829485, 0x678562fa, 0x53abe324, 0x47600e3d, 0x2a6a335e, 0x080c14a7, 0x3345d7cc, + 0xaad76996, 0xeef40110, 0xa915ee2c, 0xebcde8ba, 0x3fd4346e, 0x647214b2, 0xe9733910, 0x4043bea1, 0x8d22c47b, + 0xcf8d9a43, 0x47e89244, 0x794f454a, 0xb3bd8762, 0x66ac5905, 0x5883b375, 0xf862b736, 0xbf756b76, 0xdf64d157, + 0xe037c950, 0x7095b31a, 0xc9b5ce54, 0xdad7e13f, 0x3a9a1027, 0xcb3574fb, 0x322c86c0, 0xfc72571c, 0x139bf113, + 0xc34deec7, 0xcb980e73, 0x8124753a, 0xe0489b39, 0x1d22cd0b, 0x67a12c77, 0xf12f524e, 0x6c0465a2, 0xc42bbcf2, + 0xf436f6b3, 0x46bcd2b7, 0x8c68b296, 0xefcbe89f, 0x4ed5c126, 0x89b24488, 0x70d65c2b, 0x5dfda8d7, 0x67f36712, + 0x8d77b693, 0x746112d8, 0xe7f0b447, 0x1ffe0a92, 0xb245b5f5, 0x49f7d4cd, 0x748b1414, 0xc46faa81, 0x016eb1d6, + 0x2a503221, 0xd7998f8c, 0xcf30a1ff, 0x077412a9, 0x4dfd8994, 0x3042fed4, 0x7f75d127, 0xca3c08a5, 0xc1cb8859, + 0x741dfd0f, 0x53de09dc, 0xa57e79e3, 0xa497b5fa, 0x339005d5, 0x09706216, 0xf36b7050, 0x04c2805c, 0x8c842139, + 0x9dd68e9a, 0xc302da42, 0x25ebad71, 0x74d409b2, 0x03ccfd5f, 0xf290336e, 0x87047d86, 0x4b3df387, 0x9a31d2de, + 0x4184f1bf, 0xdfce45d4, 0xefba63b2, 0xa7c0e30b, 0x9fe5a169, 0x2b720240, 0xa4ca82ce, 0xce0f2bce, 0xfec26a56, + 0xd8baf7bb, 0x28777211, 0xd7cca5da, 0x90b57c7d, 0x019cd44f, 0x5ad0b2b6, 0xc9cd1118, 0xf4788ec4, 0xf635ebca, + 0x733662fa, 0x014ecb07, 0x631b612c, 0xf6f1ee20, 0x025802b9, 0xc1df060f, 0x221dd0c6, 0x30ae42b6, 0xd04e76a7, + 0xea484f71, 0xfdc436fd, 0x0cdf59a4, 0xb45d0c8b, 0x7d6c328f, 0x1b23b68b, 0x560b992e, 0xff934b2a, 0x7aa80d0a, + 0xcd85bfd1, 0x768105f7, 0x28b48ec0, 0x7f7feee4, 0xd5021a31, 0x52cda083, 0x837e153a, 0x6c28940e, 0x033adf6b, + 0x30bf28ea, 0xb9506e70, 0x4b96b146, 0x74f42f5b, 0xa00b70d7, 0x349a00cc, 0x7890251c, 0x21d15e70, 0xe4381e5c, + 0xf2bf38e7, 0x93d6c28b, 0x5099bdf3, 0x6458c127, 0x6092b451, 0xbf46f9dd, 0xce6d1a4b, 0x384f1232, 0xc8905405, + 0x4f8c01eb, 0xe47b32eb, 0x70ca0cde, 0x1bc70607, 0xfa331c31, 0xdb97a5df, 0x8fd546fa, 0xc6d08b8f, 0xb4bccf9b, + 0xaf1996fb, 0x7724ddaf, 0xb7638a89, 0xaf7f4b66, 0xf00a2634, 0xfc51ecf6, 0xf569e515, 0xfdda31c7, 0x8cc8166e, + 0x2152b1cc, 0x6399dfec, 0x7a204153, 0xb3752fab, 0x8209a322, 0x1366cacf, 0x2bf608b7, 0xabf7a49f, 0xe8d9d580, + 0x0a6c3e3f, 0x6bf981d6, 0xfb1a31ae, 0xa4a28904, 0xfc9f3bbc, 0x4238e795, 0x1161bd4b, 0xa68aa810, 0xf6782094, + 0xf37d24cc, 0x86c57557, 0x177b147a, 0x22b84961, 0x1a954c4c, 0x9d660fed, 0x96970ffa, 0x5d3f3c13, 0xff5b7829, + 0x30d9981a, 0xac3dfae0, 0x920b2491, 0xdc83f192, 0x7a5475f1, 0x7c7d7a08, 0xcf2ffa17, 0xe81092e9, 0x6c7d5387, + 0x18874fe9, 0xba46071b, 0x1a8a2dff, 0xb3b61a83, 0x6e71c64e, 0x7a71ca30, 0x18a5d409, 0x1b8e3b3e, 0xf57c1bd3, + 0xda1d8663, 0x681171d6, 0xe356cddd, 0x87a156b1, 0xc090741c, 0x7af781b7, 0x7e0a9011, 0x1bffdf3a, 0x5fbb0ebc, + 0x51586abe, 0xba22d0a7, 0x90b1a28f, 0xf47b3dde, 0xe10c3e7d, 0x948b64f6, 0x66aff03b, 0x488634f8, 0x62d79fe7, + 0xf39038eb, 0x66c8a3cb, 0xad2b5b98, 0xe40ce5bd, 0x029973ec, 0x0da9736f, 0x184be3ef, 0xa9c0acd8, 0x1965eac1, + 0xb3a2e187, 0xfc328c3c, 0x9d31baba, 0xd1daa917, 0x6454013b, 0x4898fcfa, 0xd149ebaa, 0xdf5ebd0b, 0x53ff085c, + 0xdb2dc41a, 0xe14e1c2b, 0x5d6234eb, 0x171dab34, 0x4227c9ad, 0x99b35eb1, 0x37265f87, 0x6e77baa2, 0xb32302f8, + 0xb5d17219, 0x2a276583, 0xec946599, 0x9d7704e0, 0x626e905c, 0x22282b60, 0x60c4fac3, 0xfba893d9, 0xe8b61036, + 0x81279c9d, 0xa83acd00, 0xb9dbea25, 0xd71526bb, 0xf761f9e2, 0xefdeca1d, 0xaa9be970, 0xc09d023e, 0xf4c62426, + 0xdd7e8226, 0xdbdaafa6, 0x07446e32, 0x975cea02, 0x32451bd0, 0xb6d91525, 0xe6ee59b6, 0xed7cfdf0, 0xa8170f4f, + 0x2aac55ec, 0x6973e860, 0x701b469e, 0xbefa0145, 0xccf59583, 0x83ed8d8b, 0x7633f045, 0x597cabd0, 0xb1bc5370, + 0xb2f339bd, 0x29d9b4b7, 0xfa4b4b84, 0x492c0641, 0xb9e43c0a, 0x0faa2966, 0xfd80d814, 0x428d3bb0, 0x10f39e55, + 0x086170af, 0x1b6ad9a7, 0x6030e538, 0xccb3978f, 0x77e354b9, 0x71d69f73, 0x55e05e1f, 0x3249aaf4, 0xe93b8a53, + 0x0e53126a, 0x0d1f5f98, 0x487e17de, 0x69b0ed8d, 0x931278ba, 0xddbe90af, 0xc1984109, 0xe51e3087, 0x83f382a8, + 0xa47aaf42, 0x7b353807, 0xcf376b35, 0x4138bd9e, 0xd3a25163, 0x5df038c0, 0x381cf5c7, 0xaa471a87, 0xb9bdf05e, + 0xc71112c5, 0x56b56b70, 0x67e0d511, 0xb834f39b, 0xf230f010, 0x372401ab, 0xb0723ed3, 0x1687b2cd, 0x11512f78, + 0xaef9c65c, 0x3ec85228, 0x4347effa, 0x2788ab4e, 0xa55285bb, 0xb704479e, 0x90eb1620, 0x8841b850, 0x166fb600, + 0xba982682, 0xa2ad633d, 0x64bb6019, 0xb98fb285, 0xf11bc863, 0x840d7ae7, 0x69c970a1, 0x0d8d371b, 0x5a7f091d, + 0x6aad24e6, 0x085eace7, 0x68716c4b, 0xbb514c44, 0x5f67b1a4, 0x7dd4826f, 0x2f8d28e9, 0x0fada05d, 0x177142a0, + 0x20646115, 0xb7704f6a, 0x91afba0c, 0x580ce299, 0x81a5e5fe, 0x5190f8de, 0x05c98872, 0x99a70b6f, 0x511184e5, + 0x0568eb01, 0x0188c3fd, 0x1e6973bc, 0xb37d0ca2, 0xe8e4b07a, 0xef71e2ab, 0x7f029774, 0x688ed5c6, 0x42197859, + 0x68a60807, 0x41ae56b7, 0x0f126a3c, 0x4e7d9a9c, 0x8f8d843e, 0xd15ac239, 0xb01b2149, 0xb25ba452, 0x82c793db, + 0xf0080fa3, 0x1dba430a, 0x0640e8fb, 0x368daf3f, 0xf3705ce2, 0x9e33f9f5, 0x1568a107, 0x7a5bedc6, 0xc9551b60, + 0x10200432, 0x8a186d11, 0xf86027c0, 0xaa930426, 0x63536590, 0xc45d015b, 0x5388a524, 0xa83dc645, 0xfa020759, + 0x17ebd4c0, 0xa06fab84, 0xdf7dd13e, 0x7e6a76da, 0x799fe364, 0x5f4f3c98, 0x01fdcc65, 0xd9a039ff, 0x51ca5b1e, + 0xb95e52bb, 0x9c28035c, 0x3e65cfa5, 0xe9c91f00, 0x20cc5746, 0xb95affd1, 0xc5108f86, 0x185d3d21, 0x406c6f76, + 0x3dfa781e, 0x4a69bd55, 0x7332bbf0, 0x27545d81, 0x38f5c9c3, 0x1293ce94, 0x7583030e, 0x59885dd4, 0xeadb669a, + 0x778e24c0, 0xcae2ffb9, 0x1688c471, 0xb1c92ac2, 0x8a2bf308, 0xb982b0d6, 0x49397618, 0x9845f1f0, 0x5b07a4c7, + 0x83a2a416, 0xb2fcc389, 0x9624a94d, 0x094718b5, 0x91a9319c, 0xbd48a016, 0x57d76e02, 0x46bfbdf5, 0xb61e70e4, + 0xff433d62, 0x3530e0bd, 0x4b713bbb, 0xadc97c71, 0xc7710074, 0xaefcb45f, 0x95afabed, 0x5cc61e9f, 0x58153fcb, + 0x1417f227, 0x25c79183, 0x05ecf70a, 0x1eb69021, 0xb06cd2e7, 0x7676153f, 0xb8be6230, 0x50aaa236, 0x465e4678, + 0x57708736, 0xd67b16c5, 0xff165653, 0xefb86584, 0x6e4c1e81, 0x364ebbc6, 0xed225c28, 0xcd9336e6, 0x0af6b84b, + 0xa2454eb2, 0x4faa8413, 0x734de25f, 0xca43a53e, 0x5da4154f, 0x3a021e9c, 0x3b983dbd, 0xa7b8a4dc, 0xac939295, + 0xfdada5ca, 0x138534de, 0x727130fe, 0x15ba52be, 0xbfdb7584, 0xc2affa79, 0xfb93b6a7, 0x1587cacb, 0xf0bd4de9, + 0xbc212fc5, 0x98cba3d1, 0x6e92e6a0, 0x4729b6e9, 0x91230308, 0x395a34e4, 0x787b77e2, 0x020b359b, 0x87008674, + 0x0386ac4c, 0x9ed01572, 0xad47a55a, 0xe7bc36d6, 0xa0643977, 0x460f8137, 0x28f00049, 0x82ab1913, 0x77dd5629, + 0x7b335bdb, 0xa0a0992f, 0x54304f2a, 0xcabfbe5c, 0x10cacbbc, 0x330cf863, 0x9b05dca7, 0xe234ab6f, 0x7f157dd7, + 0x405f9a6d, 0x5c24ae80, 0x765d161e, 0x20501241, 0xc744417e, 0x632fe10d, 0xa50c1413, 0xa83adb72, 0xadae7d45, + 0x3d7caeb9, 0x374f8dbb, 0x1ee999cd, 0x6bc1545d, 0x5703fdf4, 0x4866b71a, 0x60926bfd, 0xcd8c9887, 0xd97d96a6, + 0xfa4ba42e, 0xe9de6460, 0x92777c56, 0x66832f89, 0x89f5a069, 0xbcea80b7, 0x5f756d55, 0x4b3d3f7b, 0x1ec89d54, + 0x151a2634, 0x3bcdcb0c, 0x0cf27430, 0x63e123ed, 0x08f9939a, 0x0f76a2ed, 0xb0a85e9a, 0x8796ee75, 0xd04d57a1, + 0xc1499c6a, 0xc117fbb6, 0x06d300cf, 0xaa8ddeff, 0xaf61cf28, 0x6c5064f1, 0x76c51b08, 0xd33e247f, 0xfdd41944, + 0x97909658, 0xcab5b0f9, 0xe06f4e35, 0x979a2f6a, 0x68f8817a, 0x8eadc06a, 0xe6a6e558, 0x4eb900ed, 0x20c868bf, + 0xb9145f05, 0x6fdfbfcd, 0x78f870ac, 0xfbdcb177, 0x795b2139, 0x97582d03, 0x243a8d05, 0x174d7883, 0x82f5dc9f, + 0x9ec0e2ec, 0x92160a1c, 0x59391936, 0xefbb794f, 0xd9523c5b, 0xfb829c11, 0x6d474cc4, 0x7d1cba18, 0x4387d03d, + 0xd463a013, 0x3e3d8843, 0x84e55a01, 0x7b3f24ae, 0x8076de1a, 0x79ddbb29, 0xf2e935f4, 0x540a7f1d, 0xa06c1904, + 0x213daac1, 0xf4e6dfd4, 0xed8b330d, 0x79335901, 0x2fe72578, 0x859fe16f, 0x638c34e5, 0xddd4f2a2, 0x0991e3de, + 0xcf491d90, 0xe646c808, 0xb35fa7f6, 0xf93ec081, 0x7f3f30a4, 0xbd2a4ec8, 0x52f2aa0f, 0x4d33a31a, 0xf71bf95e, + 0xb70dd793, 0x5bf0d3e7, 0xb4755b58, 0x080c8332, 0x0989ad1b, 0xab990adf, 0xf6d23aae, 0xd1dd302d, 0x3e85b88b, + 0xe9570ab3, 0x6a1fb56c, 0xad9a2ba6, 0xb07a07d8, 0x5c3f4f2f, 0x71fea347, 0x62264f76, 0x0f9531b5, 0x1cbc674d, + 0x9ce542b4, 0x36330607, 0xb0518613, 0x3bd2d53c, 0x34d5e71e, 0x40d0a3be, 0xca2f8344, 0x1aa433b9, 0xa1287b7e, + 0xe531041b, 0xfb0ec20c, 0xfd0ffdc8, 0xd526e4e0, 0xdbc7dc1e, 0xc6eeacc6, 0x4acd6f08, 0xd46eeb93, 0x327ad853, + 0x34d391d8, 0xaeaffc51, 0x4459f89c, 0x910e1c9e, 0x6b36ac6e, 0x254601db, 0x8a9e3632, 0x8abc7cd7, 0x8f2ce475, + 0xce531756, 0x680ce9b6, 0xb068720d, 0x8f162ce8, 0x857c77f4, 0x60f6f99e, 0x8986ff34, 0x2151e636, 0x862c77fc, + 0xfe1adf73, 0x613081ec, 0xff84d997, 0xbdc15428, 0xa4354b6c, 0x55f0fd68, 0x604bb22c, 0x574b3eb3, 0xe9b1594d, + 0xafdfd282, 0x1539fce7, 0x87013302, 0x16698763, 0x1b9c1d2f, 0x1933ddc1, 0x1c0e3948, 0x05026c82, 0xebfcac26, + 0x22dd5012, 0x66d6ceb8, 0x1d04699d, 0x4ce32fa7, 0x2d37b8ec, 0xe4704b9b, 0x7dc3b517, 0x59d61055, 0xb2cef59c, + 0x3d87b11c, 0x2acb06c7, 0x289cadb7, 0xfc7821e3, 0x18bbb655, 0xdec37bce, 0xefd7a4b6, 0x1c5a77fb, 0x90f4a49c, + 0xcf07d294, 0x3b53ffcc, 0x32115006, 0x032314a4, 0x80da6200, 0x4a6c8274, 0xc2951096, 0x9f052a3a, 0xb272559c, + 0xae6d360a, 0xcfe779a7, 0x39128c06, 0xec83e76f, 0xd8c9363c, 0xa6332f0d, 0xa042cfcc, 0xd2496257, 0x24857ea2, + 0xd6ac51ae, 0xa52f0b01, 0x3029d2ed, 0x0eeda433, 0x28f4f1ca, 0x1f8797dd, 0x76f80b51, 0xf940228e, 0xc56f4d0c, + 0xc31954b3, 0x93a31a10, 0x213d85f4, 0xa9dc1879, 0xa5e27f4b, 0x1b73ac59, 0xf147e899, 0x2cef1666, 0xacd55221, + 0xc80d4314, 0x0393ef94, 0x19bf7e68, 0x716e4a7a, 0x254bbd24, 0x53a3b605, 0xe6c2bf4b, 0xacfda049, 0x0606a69d, + 0xa01e7bf0, 0x619cd2d7, 0x34685134, 0x684f89ea, 0xd0fab72a, 0xcf754ff4, 0x95710576, 0x6b98d9e0, 0xdb1c3bf4, + 0x672d08e6, 0x42c61542, 0x4ca69fb4, 0xc5aba6e7, 0x42388406, 0xa2344ab7, 0x16ab0e69, 0x15637288, 0x273fd213, + 0xcd568454, 0x6da4707b, 0x09f2bba8, 0x2bac0fb9, 0x472fce36, 0x3fcdff50, 0x551d26fc, 0x7447b68a, 0xe759fcb1, + 0xa16fb0e1, 0x6e7cfee3, 0x3fad17b9, 0xac5de4c6, 0x60c72059, 0x42263e01, 0x72e9a1f4, 0x18520cd2, 0xb5963d82, + 0x3f3f9d01, 0x7255c4d7, 0xbc87fb22, 0x0811221b, 0xc2660067, 0x30f2b3f0, 0x43c7692d, 0x1b6271a8, 0x2e99dd7d, + 0x8023f17d, 0x9a2c7af0, 0xaf8ceb66, 0x038c2ab1, 0x2f72c91a, 0xa0815f3c, 0xf201e51b, 0xc22d2a80, 0x85d1c1cd, + 0xcecd2b6f, 0x8dd6456e, 0x0108c0ca, 0xcd3cee9c, 0x1603375f, 0x0942832d, 0x97b37dbd, 0xaa6fa871, 0x0240a730, + 0x839f7913, 0x0e60ffa5, 0x218369c2, 0xbd1e72ac, 0xc17db15c, 0xe0226789, 0x9f85c540, 0x5d33db0b, 0x10909dee, + 0xc6257b64, 0xef3d09bd, 0x060e2bb6, 0x1bf11940, 0x9337dcee, 0x0dce740d, 0x6a7608bd, 0xb9902712, 0x54018e7e, + 0x09748ee9, 0x265a92c7, 0x5f70d2f2, 0x194bc925, 0x5c91d54e, 0x0a63372d, 0xfb0454b6, 0x7029e314, 0xbfe38868, + 0x706b20ce, 0xb18d3687, 0xea43e1b1, 0x006f9f85, 0x7c228343, 0x4aa30d71, 0x779c0045, 0x3c6ab1f6, 0xfa628123, + 0xf9726291, 0x7764c44f, 0xa0cc8c54, 0xba01331f, 0x3518148d, 0x0f03e764, 0x733d7981, 0xfa15e4e1, 0xa9e50fe1, + 0x43181ba4, 0x2c9aa879, 0x1fa5569d, 0x34fcdac5, 0x2a2cf920, 0xa33f8423, 0x3c6bb2b7, 0x09fd1f91, 0x8fe83ec0, + 0x4fb16810, 0x9a0baf86, 0xdda418ef, 0x58b061f9, 0x3468e577, 0x57ef1fcb, 0x8657d1cf, 0x7543292c, 0xd35591dd, + 0xf440dcf6, 0xaefc41ec, 0xc687608b, 0x5e2bc87f, 0x2031f27f, 0x6b0a59f2, 0x1486fb97, 0x19cdaec4, 0x010579da, + 0xcd1abe90, 0xeb621136, 0x231172b3, 0x4c41931c, 0x2b12ca83, 0xf0929fce, 0x440f4eac, 0x96acf40b, 0xe5c91d49, + 0x8b305782, 0x330e488e, 0xd224f45c, 0x6f0e8a23, 0x473c8ea1, 0xf4c7bd25, 0x7dbd3f2c, 0x4d0a0af8, 0x91d1d8c0, + 0x2541d4aa, 0x8eb4764e, 0xb1635246, 0x0e2f4328, 0x35683704, 0x3f3f2ef3, 0x25bfcce6, 0xec29fb9c, 0x205ef232, + 0x5119ffde, 0x2f93c918, 0x53c898af, 0xc2dcc106, 0x74c53a46, 0x3e79b469, 0x3b747713, 0x7fce01d7, 0xe25eb862, + 0x13da27e4, 0xa1f875b7, 0x46b7eef8, 0x7611bae7, 0x1e4245eb, 0xdc4842fd, 0xdc4f5aae, 0xa01b0875, 0xa40bba17, + 0xa7972226, 0xf68ae8e6, 0x38918095, 0x83489758, 0x16b157d7, 0x56a43c6d, 0x5b330dd7, 0x6b1284e4, 0x04dbe173, + 0x0bc96868, 0xd74b4c78, 0x31d16599, 0x187a0339, 0x18f60707, 0x2eba9b0f, 0x564a3ed8, 0x81e20155, 0xb5229881, + 0xa14fc4f5, 0xbbbd6294, 0x8cd2cdf8, 0x17dfc56a, 0x0147eeaf, 0x7351deda, 0x4d4adc3f, 0xc398770b, 0x7240ffae, + 0x03178535, 0x1dc214f6, 0xe8b13b51, 0xf419827d, 0x75461f17, 0x9d4379d7, 0xb15ebb51, 0x55ba534d, 0xaf0108f2, + 0xabd18b53, 0x38870b57, 0x0ab6349c, 0xf8fcedf9, 0x04882020, 0x96b680f8, 0x69bd38a2, 0x13d4d899, 0x347c34a6, + 0x8344f78f, 0xdea6359c, 0xe6dd7887, 0x572da3e1, 0x87c9841a, 0x178fa435, 0x8f180848, 0x88a8867b, 0x1c42c040, + 0xdbf97a63, 0xd432f469, 0xa280d879, 0xd9fc2ae2, 0x2d2bab59, 0xcd380e6c, 0xcbe90db0, 0x6997ee46, 0xcd8b0f8b, + 0x945a1921, 0x11c50dfb, 0x582c9934, 0xf1d7d14d, 0x359818bc, 0x20ba58ac, 0xd28ea04c, 0x48039e94, 0x6d61e2fb, + 0xf9f005c6, 0xe0542794, 0x20dbe6d4, 0x34111356, 0x6b2309df, 0x311a7a3d, 0x2b4adf54, 0xbfa9673b, 0x5073a759, + 0x946a393b, 0xb2e5ceff, 0xb91b21b9, 0xd0cd5476, 0xa6d78c65, 0x038c362b, 0x919720a9, 0xb0d4c36d, 0x0377bbc4, + 0x35a65e04, 0x5fbf12b3, 0x0677a8b7, 0xd51d5f6e, 0x6fb37dd6, 0xbf09eef8, 0xd65af436, 0xec79b6a3, 0xd4a2bda5, + 0xfdbdaf5a, 0x3d112f29, 0xd2a5da2e, 0xe09f702b, 0x6230958b, 0xc569ba39, 0xfd9aaeab, 0xae136911, 0xb37e9614, + 0x178fd6fe, 0x89c41453, 0x775e1d50, 0x942983d1, 0xdf685de3, 0x5726d4a1, 0xfe2f791f, 0x7b7b1705, 0x7403b144, + 0x44f0cb4b, 0x04e2905a, 0x48906b13, 0x4c4d1cf4, 0xc8985a3b, 0x62266015, 0xc99daebc, 0x16ffbca6, 0x549cb337, + 0x2efc1d99, 0xc4c091af, 0xd79e1710, 0x257ad89e, 0x49c8de5c, 0x261262c2, 0xe2f89fd2, 0xba5f91ab, 0x84c0b1be, + 0x2bca46e4, 0x9605e429, 0x06c3802b, 0xe4281a4c, 0x193f66a4, 0xbf53d7ab, 0xa36789e8, 0xa3f843ac, 0x5e69da1a, + 0xc335b79c, 0x69776bc5, 0x18a33cfc, 0x16efed0b, 0xa0c7bc29, 0xeed5a602, 0x587c93cb, 0xf821c8bd, 0xb2a442e8, + 0x132d292e, 0xb71db234, 0xf9c7c286, 0xa6cb1a6b, 0x8413c0f1, 0xfcc94352, 0x2126046e, 0x1ddca6b1, 0x1cb63d0e, + 0x14d5fc83, 0x2a3ed181, 0x1f2b4495, 0xb5c9f700, 0x9d3d2628, 0x5c1d3357, 0xb85c3f2b, 0x9f714137, 0x2efa9578, + 0x7a88aeaf, 0x5a20840e, 0x03a55706, 0xd64e1aae, 0x57131fbc, 0x93481cc5, 0xf2c5dd27, 0x606b17d8, 0x17abaddc, + 0x2b8beb71, 0xecd58de3, 0x5eae2607, 0x31d46538, 0x7a3e1a0a, 0xfc5a3278, 0xc95ddb56, 0x62e2a53d, 0xb1bbcb13, + 0x3fd97cb6, 0xb586dd8e, 0x3cac2a11, 0x41a3aebb, 0x5fc13e01, 0x6db788d3, 0xa784cd54, 0xdfa25775, 0xbe2314ab, + 0x54740b95, 0x4a330372, 0x05b3d556, 0xc0175ee6, 0x407a3b88, 0x98095d03, 0xbe05bddc, 0x08c18651, 0x261c10e5, + 0x202c765a, 0x9727aa46, 0x678ac59d, 0xa6e60efb, 0x8ef20f94, 0x42fa8345, 0x2c51f677, 0x2f98b24b, 0xe27cddac, + 0x7838a8d0, 0x6ba628fc, 0x5da2859f, 0x5d650e86, 0x054e0dd1, 0x221fd572, 0xb921aad6, 0x4f2dfbb1, 0xc5bd520f, + 0x944338f1, 0x03c7cefe, 0x35fd9c2a, 0x1a4c84e4, 0xfa9ff388, 0x9bbf6b9a, 0x260eaabe, 0x6a57c67a, 0xf5027584, + 0x0415546f, 0xbfa54690, 0x71bb67e1, 0x03c42890, 0x07e4a86b, 0xbd932a6e, 0x01bdfc3e, 0x6b79e1be, 0xe6f70dc5, + 0xc7d7a2bf, 0x5e8df609, 0xccce5158, 0x29503c05, 0x93308e17, 0xa716ea03, 0x6ed1df5a, 0xfbec2ef9, 0x6c5578a3, + 0x3b306e9e, 0x1f9487ff, 0x36f2cf5a, 0x42661325, 0x0d2bb00d, 0x70e4d99c, 0xf6f86c7c, 0xc50e56cc, 0x2ec9a4bd, + 0x2d500952, 0x400aac5e, 0xcf207920, 0xbeda7a37, 0x2a1fb99f, 0xa764a7e3, 0xbf781a07, 0x435a7d18, 0xbd58eb71, + 0x5b52ef7a, 0xcc69835a, 0xa050d60c, 0x1ea23db1, 0x19000724, 0x0cf78cdf, 0x58c5e2ed, 0xcb731aab, 0x006268a7, + 0x5bade705, 0x410a41ed, 0x781fce74, 0x66fab63a, 0x46319b44, 0x4d64b2c7, 0x647a5216, 0x5f85667f, 0x987efe82, + 0xd52f2463, 0x68df9ae7, 0x7f3be804, 0x2b672a50, 0x6f80c7f1, 0x6cd8f43f, 0xae6d659f, 0x271c226a, 0x41330b1d, + 0x49fd5e75, 0x4295a78a, 0x92b990da, 0xe26f9a85, 0x41d53fbe, 0xa357d115, 0xc6458adc, 0x68ee5ce5, 0x698dce4d, + 0xb471fcd1, 0x28b45ad6, 0x7ef57a5a, 0xbc5c330a, 0x877ee4dd, 0x1ee3938f, 0x714f3d4a, 0xeb514f9a, 0x686d8d4f, + 0x42056f7e, 0x5612b9e5, 0x5cc44818, 0xde04ab52, 0x3d15d8f0, 0x12edf128, 0x721179d1, 0x453edc4b, 0xe4101e8f, + 0x295cc716, 0x9428cf4b, 0x777f4a09, 0x46dbb2d0, 0x67b5b2e3, 0x16308dd6, 0xc724c1bd, 0x3d84b78c, 0x7e26850c, + 0x44b67c8c, 0xf9829631, 0x0dc40c4b, 0x1a84d7f2, 0xc7174eac, 0xef501cab, 0xe1afb5db, 0x672e5fe4, 0xe22a22ca, + 0xf62e9511, 0x73080094, 0x7a38b752, 0xfb4e925f, 0x2bdc0476, 0x5810781e, 0x09a786c9, 0x7b3fb564, 0x5ee9a473, + 0x18f72276, 0x8c0ab6a8, 0x741cf4c9, 0x1a91cb8b, 0xf88c3ae1, 0x4f5d40af, 0x4f178b67, 0x1c6f594c, 0xc9444c8d, + 0xcc3d015e, 0xdbfe6364, 0xe35e46d8, 0xa94dac9f, 0x7ff7d7ae, 0x3245d5ba, 0xf44845a1, 0xa7b6b468, 0x8d5c3d01, + 0xecf1ba27, 0x4702099f, 0xa5a08c89, 0x7d440a33, 0x11b2883a, 0xe2e8ea93, 0xee8d8685, 0x495ba058, 0xdb639d03, + 0x97a6c8aa, 0x8f542555, 0x1476a5d8, 0xef84ac7d, 0xe7b5bd72, 0xe734ddf2, 0xd99cdd75, 0x6bbf16f3, 0xcc2b42b6, + 0xe0de4e59, 0x98cea59b, 0x77c6e9a7, 0x614416b5, 0x0289cd2c, 0x462349aa, 0xa40e58a0, 0xbc553368, 0x0f310acf, + 0x6b73930e, 0x819a53d4, 0x0f54970a, 0x77ce7a4c, 0x53c515a4, 0xad19943c, 0x542417d4, 0xf347cf39, 0x8c95e44a, + 0x696a9bb1, 0x6533c7a6, 0xa8c7a833, 0x90a31186, 0x0c8de96b, 0x389edb04, 0x12a7419f, 0x04091119, 0x8af8b42a, + 0xb21e5470, 0xec8d5653, 0x28e83b71, 0x4193dcda, 0x65c0e509, 0x80a34c78, 0xadc768bd, 0xe6f53897, 0x4fa8fc50, + 0x37511007, 0x0c1d926e, 0x1ac75437, 0x75b3dafd, 0x0b897ea5, 0x302927e9, 0x0a26aff7, 0xf20b88f3, 0x4ca34074, + 0x9b0de269, 0x37213805, 0xc85b9a00, 0x56ec9049, 0x3a0d45e1, 0x92c282f8, 0xa3ac8f7a, 0x3c97447c, 0xa426a176, + 0xf7c1bcf3, 0xc99bff56, 0xc8e5082f, 0xfe200457, 0x11bdda96, 0x407fcf5e, 0x1d2bc5bb, 0x0ccca8ec, 0xf98d0b81, + 0xff766bda, 0x740feca0, 0x683c2e7d, 0x8e25e8f7, 0xcc179e64, 0xa913fed2, 0x7206529c, 0xefa0ce5b, 0xf4767141, + 0x5571a7b6, 0x25e7d713, 0xa3522579, 0x1319f9d1, 0xf343c3c0, 0xa3f6f1c4, 0x3cf1b49c, 0xe4f60126, 0x3dcb0043, + 0xc702907e, 0x0adea5b1, 0xa60d96d3, 0xbc2f89b8, 0x7974991f, 0x9afc1e8c, 0xd531a2ea, 0x53b7363c, 0x89e28de5, + 0x5c96d768, 0xa4fefe0c, 0x7a19e7bc, 0xec69f61e, 0x5d3b32e6, 0xc364ef41, 0x8f77550b, 0x87cdc836, 0xbca86f15, + 0xba7f803b, 0x7578c498, 0x12ca2577, 0x4a471182, 0xc0459cf1, 0xf82239ff, 0x6323c3a8, 0x31c007c0, 0x89bf096a, + 0x82f7097c, 0x5dc0883f, 0xfbb3c3aa, 0x88b0d118, 0xbdcb3296, 0x8f3cfcfe, 0x5d1587dd, 0xb5b5fcc7, 0xbd5ac66e, + 0x6d1d7617, 0x06a0ed5b, 0xe7c74894, 0x8d4d109d, 0x319492e2, 0x9fb195e6, 0x921a24a3, 0x34f4014b, 0x817db592, + 0x16734e68, 0xcb9a11b3, 0xe6f674bd, 0x6269435a, 0x4fbbf648, 0x3021a81c, 0x6d9cd789, 0xbbeb44ea, 0xdc3c8a1c, + 0xe3acf928, 0xa9d645c0, 0x2417f1fa, 0xfd531da1, 0xf1b23c34, 0x63e0303e, 0xfb726316, 0x989e484d, 0x2213bf60, + 0xc81eebe7, 0x9ba7a374, 0x0264ff0f, 0x572ddd47, 0x1bc48f51, 0x6d9dfbbe, 0x0ac388e9, 0x62d2929b, 0x45409114, + 0x735312b9, 0x80a13347, 0xcc21190c, 0x90d8a7e2, 0xf6f76929, 0xe80daa89, 0x16cc5274, 0x04bee3c0, 0xa9a4fb71, + 0xbec23d98, 0x0cabb651, 0x61bdeeb2, 0x7107a255, 0x064ddb91, 0x1d71ae13, 0x67c85ff0, 0x58a0939f, 0x8a8ac7db, + 0xc3ee2b04, 0x723bf14e, 0xb87dd6a8, 0x9aa5cfe2, 0x1227ffe3, 0x688de1b5, 0x17dbc261, 0xb358a973, 0x0b8f1687, + 0x2f7b09b3, 0xb2e8e35b, 0x4719f753, 0x4d1a9044, 0xe92ce944, 0x67868a97, 0x2229564d, 0xe25026cf, 0x97b95c0b, + 0xf510b92b, 0x7bd94d32, 0xf012f748, 0x4ec10f06, 0x45bf1030, 0x1152deb2, 0x9be8ff24, 0x08275d25, 0x764f0c54, + 0xc4590b4b, 0xc10f403c, 0x56c7c826, 0xca04e97f, 0x57ef4232, 0x4d4f9fae, 0xa2329189, 0x794901cb, 0xd7000b31, + 0x8836302a, 0x48dcbe3f, 0xb9e4b90f, 0xf01dac55, 0xa9ecbea6, 0x923848af, 0x1d28fd2a, 0x9c103063, 0xf9cfe451, + 0x4d644bd8, 0x258a3ea9, 0xf74a7364, 0x0855cfe8, 0xd823edfa, 0x44dcac10, 0x1b2257da, 0xadfa485f, 0x02d1401e, + 0x5bcfa64e, 0x02ea4911, 0x33117f2e, 0x0b119b85, 0xe55e35ec, 0x8d092113, 0xb4ca3952, 0x8e88d964, 0x9048c075, + 0x429b2e0f, 0x30ff3f9b, 0x34aadf0d, 0x4420f921, 0x61214dcd, 0x3dadbe61, 0x17c3e381, 0xf95d1f2c, 0xed27dc99, + 0x644d07aa, 0x5b7f2439, 0xa4177303, 0x613e2b7b, 0x73f205d1, 0x9b48aaec, 0x1833d4f2, 0x12f170c7, 0x17630c70, + 0x7b71e7c7, 0xc809194a, 0x44441f13, 0x429b11b9, 0x7bc0eaec, 0x5688631a, 0x19b1cced, 0x5e068452, 0x02a8fc3d, + 0x57bbcce9, 0x15d758af, 0xd640e53f, 0xf4e175ba, 0xd1783659, 0x3e5c8585, 0x651c602d, 0xb193490c, 0x74eb9d6d, + 0x6eb53069, 0x9e92e8b6, 0xa4adf917, 0x65f116db, 0x961da720, 0x8c3eac33, 0xb50f40e9, 0x42ad59a3, 0x760755bf, + 0xe4dc09af, 0xdfe6d174, 0x4b1c21bb, 0x1a5fbec6, 0xa0658098, 0xc733edd9, 0xf5d0ec5d, 0x64ccf423, 0x55d75413, + 0x9d36f03a, 0x1e4ce880, 0xf71bae3d, 0x390daa92, 0xd05ab337, 0x33d24adb, 0xa0ecd497, 0x21f976c7, 0xabd5393d, + 0xd94984e4, 0xd91815f9, 0x748cf48f, 0x363210e1, 0x15cc21a6, 0xc88fcd66, 0x4702b058, 0x3ce5fb92, 0xacf8dcb6, + 0x7059560e, 0x7c2f9f4a, 0x0beeb588, 0x5fa5bc2b, 0xdfe5a82f, 0x1e1c2fac, 0x1d680c98, 0x51a896fd, 0x93a0475c, + 0x4c14b461, 0x96f4bdce, 0x5367135b, 0x8afb8168, 0x836f5a54, 0xdeb1dd35, 0x17eb5228, 0x974701eb, 0x539111f1, + 0xb129d29e, 0x6729be4f, 0x6485e7fb, 0xb643b8ee, 0xf1d17ab7, 0xdb2d82c4, 0x5229b61e, 0x24fabb6e, 0x145b4c2a, + 0x35c6b672, 0x545c12a2, 0x2f07d1a0, 0xef79a1a3, 0xe81bd163, 0x76229db8, 0x5f88c2a9, 0xea06cb9f, 0xa5877e96, + 0xd0dbbada, 0x2a37c204, 0xe84f7b32, 0x972b1af1, 0x9c9d532f, 0xa186d083, 0x39405c95, 0xdae0ce87, 0x136f80bc, + 0x5bb734e9, 0x79bdca35, 0xdd2676e6, 0xc09e5ac4, 0xd97ef03d, 0xf3456b60, 0xfb37114b, 0x53b41627, 0x717bdd87, + 0xcfd28e94, 0x4e6b8185, 0x7768af99, 0x0ce5272d, 0x3a5cd274, 0x5bee57aa, 0x29e04786, 0xb7135c78, 0x5d5f4e22, + 0x268c4fff, 0x44de61e4, 0xb78b3ca6, 0xf411af0f, 0x607173af, 0x72018d0e, 0xcba511a0, 0x45ac60ae, 0xe55b2d41, + 0x3949f837, 0xda0be40a, 0x28580ba2, 0x0178f4c4, 0x680a3c62, 0xab855423, 0xe840d310, 0x5894d9a5, 0x4e6c6210, + 0x3eda22d4, 0x77117836, 0xd4c4d76e, 0x54990476, 0x5e143bbe, 0x08c72b25, 0x3732844c, 0x82ce476f, 0xf25334f2, + 0x0123ca02, 0x1e385914, 0xb8051490, 0xad909cc0, 0x8f39bb0d, 0x0afeb5de, 0x2e2347fd, 0x6e568272, 0x4eb58cc7, + 0x87ef52d7, 0x0a88f186, 0x93f0c1c5, 0x660e690a, 0xc2db39e3, 0x6b0c4a62, 0xc4a5e272, 0x49f0192a, 0x2f157308, + 0xa1fe783d, 0xaf6fb6df, 0xa2b3ffdc, 0x6d2886b8, 0xa25dcd08, 0xb5e02d6b, 0x54183f36, 0x40b8b715, 0x8890f664, + 0x08be233f, 0xd747be0e, 0x83e6bb59, 0x536f8a82, 0xaa37867e, 0x4f26c124, 0x1696e829, 0x3c923309, 0x8e54dd6b, + 0x6e83297a, 0x9809e3ec, 0x41b76d38, 0x9aac71eb, 0xd8cec2a1, 0xc230dcd8, 0x55e7f8fc, 0xa99a4dc6, 0x155e1cb5, + 0xcbe73af8, 0x721f6074, 0xaf1f2ffa, 0xc81617c3, 0x5ba0430f, 0xb2bf55a8, 0xb89b9116, 0x170b6177, 0xf2c8f950, + 0xf321d7b6, 0x3836bcc9, 0xbf315ece, 0xbd9ee6c6, 0x2adf771d, 0x675c6d34, 0xa3ec6cf1, 0xa1d4ebd9, 0x96f41c9b, + 0xbab6ba21, 0xb2311d0b, 0xbe62820a, 0xcebfb0e5, 0x3d26c93a, 0x53678095, 0x37e358c4, 0x4b8e38e3, 0xe1d3d299, + 0x14b173fa, 0xa8834a89, 0xf885d3d6, 0xc98832f5, 0x1768a606, 0x180fe912, 0x72a97d7a, 0x8c6716c9, 0x38ab7201, + 0xbe0d825d, 0x0ebfb8c7, 0xc730477c, 0xeb79294b, 0xa0b170db, 0x40467034, 0x291e1b12, 0x128b602c, 0x1d6ab211, + 0xc8077a1b, 0x04d6a8e3, 0xe82ca9bf, 0x79a6b198, 0x342ecfaf, 0xe52e9f38, 0xdbd0598d, 0xdfbc4b9c, 0x49336350, + 0xe1b07040, 0xc7cae060, 0x5ace9904, 0x0641ff46, 0x60c4d714, 0xbcb02f85, 0xd296ef1a, 0x6d4a7190, 0xe4f304e9, + 0xf30ad8bd, 0xc525ccfd, 0xd11e47a8, 0x3bd1af6b, 0x794bfa25, 0x50ba2708, 0xda337a73, 0xf0f72002, 0xd12f9289, + 0xf9cbaaa4, 0xbca79501, 0x912c5752, 0x911dda2c, 0xd76633fb, 0x09262e02, 0xa91faf65, 0x5c94d598, 0x55f1c145, + 0x468f6850, 0xea25a64c, 0x943eef74, 0x3ad18227, 0xb363f122, 0xf1625257, 0xed6b6faa, 0xca63bd7c, 0xfc09f363, + 0x39607c30, 0xfd05d293, 0xd012d200, 0xfdf527a9, 0xe0d78466, 0xffb66403, 0x3efc5767, 0x639ad86e, 0x1b6fb3ea, + 0x47d14557, 0x1164730a, 0x85d6ca7c, 0x2efe4ca6, 0xab11157b, 0x791e0d06, 0xd1d90c87, 0x7c6e29b3, 0xb70a7a1e, + 0xe78abf5e, 0x6d4a7bc6, 0x1e0b28ae, 0xf55abf75, 0x4352f844, 0x25239b6d, 0x575da3e9, 0xe46d8fde, 0x70893333, + 0xde3ccaa4, 0xb21fbd06, 0xded8437c, 0xe97fce1d, 0x565dd473, 0xa8404446, 0xe8dbec1d, 0xd303c3de, 0x2ec82463, + 0xa52f9737, 0xed7def97, 0x1cb67698, 0xec9b4726, 0x1fb9f565, 0x62729170, 0x37689d2c, 0x61b201ae, 0xb0c435dd, + 0x9e4cecbb, 0xa0a2a7c2, 0x17e45aef, 0x7349f3f0, 0x333860bf, 0x6c9af209, 0xd6084721, 0x223f95ea, 0x9fa2847d, + 0x3bd5cd61, 0x9e22d4f5, 0x3308a7cc, 0xdcd69735, 0x1c1a6d7b, 0x3aef6776, 0xc4e3ea3d, 0x2245acf8, 0x1437aa44, + 0x98d14f2f, 0xf5b638a6, 0x19ae9ce9, 0xa038fd68, 0x9fc79dbb, 0x410256c7, 0x4d025f3e, 0xaeb59e5c, 0x22fb0e16, + 0xeccf9ffc, 0xb0a84536, 0x3cf5f541, 0x612bb81b, 0xbdf27522, 0x11357de7, 0x3f3fd26a, 0xe68d5849, 0xf5d4e24b, + 0xd22c59cc, 0x7fc16a61, 0x69a8541c, 0xe9042701, 0x3fbe1069, 0xb4911903, 0x313d629e, 0x3bb418a9, 0x928cac2f, + 0xd3958426, 0xe13cb96e, 0x873be494, 0x12d218fb, 0x7430102c, 0x8029020a, 0x05d06f09, 0xa4f0e92e, 0xc9ca6912, + 0x59d08f15, 0x0077e83a, 0xaa7e0875, 0xa90baf6f, 0x264c2482, 0x790c1bc2, 0x736cf125, 0x34dbfcce, 0x92528a4c, + 0x41e6dde9, 0x4f589602, 0x68f6231f, 0xc5665a60, 0x95d3bfe4, 0x10b2b973, 0x7207a468, 0xe99f5edc, 0xa5518c4e, + 0x17a35900, 0x6fbfaabe, 0x4182792d, 0x1c680ebf, 0x1cf8b732, 0x4997c38f, 0x768d75f4, 0xbc04af10, 0x0ad6bdba, + 0x94abc120, 0xcf728974, 0xbb32cf5d, 0xd4539be3, 0x7ded504f, 0xf2d5b39a, 0x96225af9, 0xc8f4697a, 0xb4778c1b, + 0x0623836b, 0xfd63963d, 0x080e5d3e, 0x967f9992, 0x066ecd11, 0x46e70cd7, 0xb3b928f4, 0x85ac5945, 0x5e7768e8, + 0x4d788e07, 0x84a516f6, 0x553abb4f, 0x462e8959, 0x8d1cc171, 0xf9d85867, 0x9e9d15a0, 0x6cae9b64, 0x6ed6d3f7, + 0xcbfc81b0, 0xaaf0ccdd, 0x02e9ccc2, 0x05031ef5, 0x37f8a504, 0x03531df1, 0xb130701a, 0x87a0ee79, 0x732c4dfb, + 0x57ddda02, 0xf584b0a6, 0xcc315c8c, 0x144ac266, 0x24636d01, 0xaa4745a6, 0xe9853183, 0x53fcc4a1, 0xad6fcd45, + 0x18fb2049, 0x67fc7689, 0x84987096, 0x372b7fb1, 0xe92e2e0f, 0x813a9bec, 0xf6f7cfd7, 0xfda99a9d, 0xa24d8134, + 0x486ebc4a, 0xde90e8ae, 0x404f2b0f, 0x7b84e238, 0x737de591, 0x74c092a8, 0x97a22870, 0xe789340b, 0x212431e7, + 0x08c9fb30, 0x8e757599, 0x69f19606, 0x7b56127f, 0x4b646844, 0x3f8fb13e, 0xb044c6aa, 0x44407a90, 0x178d99b8, + 0x473ca156, 0xbcbd466a, 0x916da519, 0x312877f7, 0x22a99f80, 0x691fa0fc, 0x39a16df3, 0x12dc4455, 0xbc517d04, + 0xf8b5ff5a, 0xa3a78263, 0x21be159c, 0x489cef86, 0x58f90c0c, 0x749a51ae, 0x132668df, 0x13a57ef4, 0x5309150c, + 0x3e4b7371, 0x956619d8, 0x74cbbe21, 0x97781d9a, 0x04d587f2, 0xa0632b0c, 0x8c3912f7, 0xbf18952c, 0x0ae82d93, + 0x8de33106, 0x4b4fe214, 0xc90e4a54, 0xee1def95, 0xd5e66dae, 0x949fab21, 0x80f4ee2f, 0x07202d77, 0x442532b7, + 0x37b89e72, 0x83b23911, 0xfcce9bbe, 0x9544428e, 0x9d753588, 0xf564d34a, 0xb26265e2, 0x933d0f5a, 0x3a6b1407, + 0x7b5d3fd9, 0x7b185c5d, 0x711ee290, 0x6f8c1fe0, 0xb579ac05, 0xae3b1268, 0x16dc3a9a, 0x416e74f4, 0x204090d8, + 0x633015a2, 0x172d8cfa, 0x14dcd4a5, 0x3bd5a4d3, 0x2dbe2c6d, 0x0dd01d33, 0x6170c0bd, 0xf7118e51, 0xb3a9cc08, + 0x2f43f6bb, 0x53be0c48, 0x08f586c6, 0x0496f79a, 0x26a9b216, 0xf6750d28, 0xcafb59bd, 0xdb5148d8, 0x33cae61d, + 0xea468d3c, 0x7c40653e, 0xe6b62ace, 0x8add12bd, 0xe3c7fa5f, 0x245c3bbc, 0x2bd90689, 0xcbc41aaa, 0x5edae124, + 0x692b17e1, 0x517e621e, 0x36c21349, 0x95d9120c, 0xc793ce68, 0x4b3137d1, 0xe77f38de, 0xe0839770, 0x2ac850c6, + 0x5c88716d, 0x706ebf84, 0x33446bd8, 0x9e286cad, 0x078dae8e, 0x56a7ab64, 0x9833fa47, 0xe1ddc6bc, 0xd777cf69, + 0x11787f09, 0x0404ea6c, 0x1c270444, 0x12af6569, 0x56e6c31d, 0x60746ba5, 0xd53c5b1f, 0x79693915, 0xebd57855, + 0x686a443d, 0x80181730, 0xc4812e05, 0x15f7a365, 0x86b9932c, 0xbf0f11e6, 0x4fe29dff, 0x5b3abbe6, 0xd11109ab, + 0xa383edf7, 0xffa1e3ba, 0xec1a92f2, 0x06d0764c, 0xf4745706, 0x034723dd, 0x46678cf7, 0xbd4e11e2, 0x61971723, + 0xbc810701, 0x6f3fdb4f, 0xfacf3785, 0x2d365d4c, 0xd19f181c, 0x3be1decb, 0x6c00ecc9, 0x7d0f81fd, 0x841845ed, + 0x6dec4a0d, 0xd071bc4a, 0xd4e24a0e, 0xc4440322, 0xf558a2d9, 0xf6cf60a6, 0x12c36e91, 0xead6c8b2, 0xc278b0b6, + 0x5037a711, 0xe6e64a6f, 0x3a130d9f, 0xa73963e1, 0x52d9ebaa, 0x12724fd5, 0x289f2dee, 0x2226a7f5, 0xb4138e1e, + 0x8b765eac, 0x0514d366, 0x0aadff17, 0x7f21cb0c, 0x36e682b3, 0x5b06f194, 0xc4bfa544, 0x01845996, 0x2cf9840d, + 0xc4dc3825, 0x07f2e9bc, 0x5d2de42d, 0x9c45fc96, 0x51de3b04, 0xb3e6279c, 0x050c098d, 0xce49ff7c, 0x695219d5, + 0x0f5085c0, 0xfc4aef7e, 0xf2c09e19, 0xb867a4c6, 0x8f1a3bc4, 0x5214fc25, 0xeef024a2, 0xd0136e6a, 0x34cbf6d1, + 0xae1c10cb, 0xfdaec83b, 0x4aebddf5, 0xcbdfc6cf, 0xe05b5188, 0x5d0d7baa, 0x32a3b676, 0x3c62bc19, 0x6da9c16a, + 0x7607fdac, 0xcc503237, 0x53211dcd, 0x94fe9f5e, 0x1fb39c78, 0x789dccbe, 0x16d81fe7, 0x5a3f908c, 0xbaf989c2, + 0x1d53f5ff, 0xbb7b806a, 0x14db8d54, 0xccb3d8c7, 0xc6fa95d9, 0xa7238cdf, 0xa6830709, 0x3eed2ec9, 0xcc680457, + 0x0e86d0d2, 0xe9dd6efd, 0xf01a25e2, 0x0dc94d5a, 0x8b21893b, 0x9353aa57, 0x46bd143e, 0xdd33cd67, 0x7803df5d, + 0xf28d7d97, 0x7a9c42c8, 0x1813bdfe, 0x0960fe16, 0x684c5e82, 0x0cbc435f, 0x8b5fcdc0, 0x7e0cb5c5, 0x06861323, + 0x59aaccc2, 0xaf48b95f, 0x7856ff08, 0xf43fabeb, 0xf78272ae, 0xe98a40c5, 0x2d3a0aee, 0x19a09877, 0x70bb9bf7, + 0x812a4e16, 0xdc904c83, 0xe6c6cc84, 0x5cf4375b, 0x088268ad, 0xf0b0c4c6, 0xdee9dbc1, 0xa918c429, 0x21246957, + 0x835dfe6f, 0x02107dfc, 0x30013771, 0x207293fc, 0xb722c40a, 0x17ba0448, 0x2c46a709, 0x884ebe2e, 0x993cc7f4, + 0x85420c25, 0xb52e5558, 0x6284890d, 0xd782ac4a, 0x5c602d46, 0x69c73238, 0x7f508f60, 0xed93dc68, 0x6b6cbbff, + 0xe3131c68, 0xcdbcf2b5, 0x76a2fc40, 0xdef735c0, 0xb01e5aa9, 0x80d52175, 0x818a91e3, 0x71d4cca3, 0x6a7d70c7, + 0xf2eb32c7, 0xdd2598ae, 0xceeece25, 0x7ee2df55, 0xfac68e89, 0x1f8ece62, 0x204f7e7f, 0xa5240774, 0x70dd2a1d, + 0x77ba3caa, 0x5b362a57, 0xf59c591b, 0x67563344, 0xf7f1a76a, 0xfe38db6f, 0xfdc66968, 0x8083c6a4, 0x59f69b79, + 0x3c96748b, 0x3c1beb78, 0xccbc3168, 0x83259c18, 0x639b5a45, 0xdf3c328d, 0x0cd7cc8e, 0x4d802f25, 0xa953359c, + 0x83caa97a, 0x60d80dab, 0x021db16c, 0xe7b3c3fd, 0x8dff089a, 0x3dfc2a75, 0x4654029f, 0x6e8b2c6b, 0xd514ab2d, + 0x52b30ca9, 0x142f038b, 0x24699ada, 0xa6bd0530, 0x493e5136, 0xb2568971, 0x8fb32ac4, 0x53a8e060, 0xcce29361, + 0xde531d33, 0xd6cada60, 0x57ef8f4d, 0x6c10ef1e, 0x6aa2feb6, 0x06157e53, 0x0309c05e, 0x9476e764, 0xd1bed0d6, + 0x522a13ae, 0xf2df7221, 0xd745da91, 0xa2a0aa9a, 0x2313a20b, 0x48fa01f9, 0xf918133d, 0xd1a4156a, 0x2f84cba4, + 0x58307437, 0x85e2a882, 0x14a76b44, 0x1d12a1d7, 0x1f64791c, 0xcb648de0, 0x6776b17d, 0x97806773, 0xb5b9a3c3, + 0x703045d7, 0x98420928, 0xf20d0635, 0x1d9470a4, 0x8a91b58e, 0xa983b415, 0x151f6e0a, 0x7570656b, 0xe2beb542, + 0x5c698970, 0x5a264df7, 0x9d744fe7, 0x49b81652, 0xbe9cae73, 0x068b0db5, 0x739a0b09, 0xf8e6bf13, 0x6fe0158c, + 0xb57813fe, 0x9ad21a38, 0xb8a596ac, 0x46a1cd98, 0x5a7a33bb, 0x264e265b, 0x62d2b932, 0x64cb3558, 0x45466008, + 0xb403cf4f, 0x10e7d45b, 0xb30857a5, 0xe75dcb1d, 0x2cd071d5, 0xee4e5145, 0xdbc6b7f9, 0x516796a7, 0x690e9664, + 0x1ef003be, 0xcb8c9a8a, 0x950b98bf, 0x322da9a1, 0x6f685545, 0x52897e84, 0xf4f55978, 0x88ad8f05, 0x0239811e, + 0xf266b650, 0xb808801c, 0x4d5fef5d, 0xa0437248, 0x3fcde42d, 0x4f61240f, 0x901fee6e, 0x7b2f5dbd, 0xfa337ac1, + 0x352f39cf, 0x98b07153, 0x4a51ef44, 0xf47fe593, 0x8e46ebbf, 0x3e1f206b, 0xaa6accbb, 0x95ce23a7, 0x1468cc69, + 0x98c49c5d, 0xbc682b0d, 0x20ab7824, 0xc01a1f5b, 0x004517d1, 0x7dd73ba4, 0xf5809e52, 0xddbc382b, 0xcff1718e, + 0x0b29cb96, 0x028199fb, 0x9ded5846, 0x6c45d753, 0x9d2e8c73, 0xf8c3f7df, 0x980c1212, 0x0fd1051e, 0x534d593e, + 0x44aa2de7, 0xee10f6c2, 0xfaddae61, 0x08dcbc39, 0x2a146a94, 0x8fb45718, 0xeeae093d, 0x2e733e91, 0xb5f234b2, + 0x78d53b24, 0x3b09ca07, 0xaac6e921, 0x81785b3e, 0x92c75640, 0x9da7a96d, 0xf14027bf, 0xc2b32b1f, 0xdb4055f3, + 0x6eb4ff42, 0xc3197f78, 0x0a19c764, 0x953cf8fe, 0x389543c5, 0x717014b6, 0xce4f0ba6, 0x4cb8c1fc, 0x0e92e8fe, + 0x21eadcec, 0xf3e34e12, 0x1b3a63b2, 0x00dcfedf, 0x90016a12, 0x6a035f7f, 0x0d3b6b46, 0x477fe1f8, 0xe104cb73, + 0x5b648200, 0x9fd13a16, 0x51408bac, 0x0695fcb9, 0x9ca6c814, 0x25cb90c8, 0xb744fa1c, 0x6ef543f7, 0x842a020f, + 0xc4a6b2a2, 0xca300702, 0xb756f441, 0xf9a2ea54, 0x61bf4611, 0xb5f34ea7, 0x651fc04b, 0x48771097, 0x52c2096c, + 0xa5f7da0e, 0x2c9f645a, 0xdb54d407, 0xa78ff4bd, 0x843c3564, 0x16d3759e, 0x314aa5d7, 0x28ea1a72, 0x483cbd5d, + 0x254ea06f, 0x0f1816ef, 0x29ef9919, 0x9b37878b, 0x5ea31ab0, 0x97c52514, 0x22edca56, 0xad00a177, 0x7ebbad22, + 0xb1cbe540, 0xfa416bd7, 0xf9e37fdd, 0x97e6a380, 0x49ba9d06, 0x76ad711e, 0xed983a80, 0x6bdbbf0d, 0x2514dc29, + 0xc386694b, 0x70f9ed33, 0x10f72cb0, 0xb2ab5840, 0x8c53b913, 0x1e51f676, 0x2dce6388, 0x4f6ee543, 0xec5cf069, + 0x90395065, 0x80610334, 0x6f22981f, 0x120a9e6a, 0x5c5dc344, 0xd4bc44f8, 0x6c034240, 0xf4930464, 0xb91fac3f, + 0xee475445, 0x604d39ff, 0x5a046b41, 0xb3ff3999, 0x35617c7a, 0x84119314, 0x17fee10c, 0x5b27c6ae, 0x13bd33e7, + 0xd49a336f, 0x3d5f1525, 0x2411767a, 0x56392580, 0xa57b3ac4, 0xb76f67f5, 0x519feb62, 0x5e6d270f, 0xc232dd94, + 0x6fd72e67, 0x4ed886e3, 0x173e1958, 0x45e790cb, 0x4a5e221d, 0xb16f5282, 0x49af6751, 0xf9ef54fb, 0x1e291bb0, + 0x70033dbd, 0xca6a4363, 0x8227ed45, 0xb7e25b9c, 0xfa645c25, 0x6934cfda, 0x38c560f7, 0xaa5e2a6b, 0x3623429e, + 0x1a51fd69, 0xab815b4c, 0x33751e62, 0x860fa679, 0x0889470f, 0x5179668d, 0xf9d474a0, 0x4cd86458, 0xfdf76f2e, + 0x6641c20f, 0xfd973711, 0xa3f4e128, 0x1bb5790f, 0xcb8a133f, 0x41950aaa, 0xe182f3c7, 0x1e834fe0, 0x33668839, + 0x8915a578, 0x4b0f3cf0, 0xf1964cf5, 0x842e6307, 0x21059a1a, 0x575e314d, 0xeda4a979, 0xa3e9d7c5, 0x9fa5b9aa, + 0xca2857ba, 0xbd2f0d03, 0xf1622442, 0xbee64c44, 0xf7a59862, 0xead0ee13, 0x84a9602a, 0xbf437406, 0xbd219416, + 0x70fe4be3, 0x56aa150f, 0xafa1059a, 0x292970fe, 0x33537ccd, 0xf7c1cd7b, 0xeb6a9428, 0xd9df01b0, 0x5a2f676d, + 0xd922d0a9, 0x79ba8707, 0x32b681ab, 0x9c564bb3, 0x157a767b, 0x55565f76, 0xb004208f, 0xa9833e0a, 0xc865f0cb, + 0x2e21e1ee, 0x4a2ba535, 0x7dff353c, 0xb4f6b82d, 0x0f0773fd, 0x8280effa, 0xf5478751, 0x107639d4, 0xc1751469, + 0x599ce431, 0x72a62957, 0x8dc5f7b9, 0x432dc917, 0xcec43dfe, 0xb31bdbd9, 0x34a98cf2, 0x7226dbf6, 0x750f29ce, + 0x863d1382, 0x06452621, 0x36192299, 0xa24ad2f7, 0x5c7210e7, 0x63e331a7, 0xa48fc628, 0x5f210023, 0x7a0de3cc, + 0x00f2263f, 0x56935027, 0x278a1165, 0x4fd43387, 0xb3e3f868, 0x79b8c7e0, 0xcf8d5b5d, 0xd02d1a9c, 0xc103cd04, + 0xfd9a3921, 0xef0e5cc0, 0xc35b5d44, 0x6243de51, 0x82cac10b, 0x7f59ee98, 0x1af0eaa3, 0x807a222f, 0x0aee8db9, + 0x0740f716, 0x66dbcf79, 0x16a69a98, 0xcc1ee6e9, 0x94555812, 0xfd5d83af, 0x761f7902, 0x12ff89a7, 0x4350cd74, + 0x150ce51c, 0x3ca179e5, 0xb877ba51, 0x6130a343, 0xb233c37c, 0x7413167b, 0xe17f00e2, 0x866b223a, 0x6f44c36b, + 0xf640b45d, 0xb04dc1d7, 0xfc350d19, 0x2f421a40, 0xc868fbf4, 0x64f0019a, 0xdf842238, 0x52074cea, 0xefc66147, + 0x13f22990, 0xeff2c159, 0x3bf31ea2, 0xa823f86e, 0xddbd4a4b, 0xfcbe7376, 0xc0b5330a, 0x48af1c32, 0x4b0fee48, + 0x46549ec2, 0x227bfdfd, 0x6863c194, 0x852c786c, 0x40183d72, 0x2982c6cc, 0xda3cec47, 0x2907028e, 0x4a650a97, + 0x44209fbf, 0xc4482328, 0x6e1ee8ff, 0x79aedc67, 0x4212b9b2, 0xcee515b7, 0x422b4bcf, 0x6aec2c94, 0x128dd420, + 0x0ac230f3, 0x0ec0a4a0, 0x4f851b04, 0x0a0d0d45, 0x667933e3, 0xf47df967, 0xe9a90621, 0x0b86a51e, 0xde071ed5, + 0x31e3e6a8, 0xef4fae87, 0xa1542105, 0xe8a7d1fd, 0x6d391fe1, 0x37064800, 0x78f21c2f, 0xca9f8ad7, 0xaa456a94, + 0x1f8ebd9f, 0x29b9fb78, 0xdff7f31f, 0xa220094a, 0x61675ee9, 0xfb5bce2d, 0x109daf31, 0xea3c4fd8, 0x271c3b7c, + 0x1193e4cf, 0xed8e71b2, 0xc7edccc8, 0x5819f794, 0xa8078699, 0x12902466, 0xee5a9828, 0xfd77f985, 0x593cf03b, + 0x9e391e35, 0xb2e4f4fb, 0x627b1bbe, 0x53d4e75e, 0xf91f58b6, 0xa97c3e10, 0x6f9f1fa1, 0x99ce3e1a, 0x98a69208, + 0x49da542d, 0x0b15a7e1, 0x6db4d969, 0xfa962f48, 0x6f9f96d1, 0xc03e9004, 0x1668bed4, 0x744cc67f, 0xb77901aa, + 0xa08ebeb9, 0x5fc8b14a, 0x326ed78f, 0x455d188c, 0xf6b75569, 0x34f5f23e, 0x0adad8b7, 0xda414595, 0xf08d2466, + 0x0cd61cfd, 0xdcc4ad27, 0xd16760ea, 0x14a54f1e, 0xea05963a, 0x7255664f, 0xe4459451, 0x9613cca5, 0xbffd7b9e, + 0x497ef220, 0xb56d9a9c, 0xe58f02ea, 0x000478df, 0xc176e9cc, 0x9a8f5b2e, 0xa64d531f, 0x787441cb, 0x980aaf2f, + 0xe083e305, 0x29105e13, 0x2eda019b, 0x7a61c197, 0x69ec7a8d, 0x8b9ee0c7, 0x1d7a5d06, 0xbaaa3af3, 0xd570e801, + 0xf6f07416, 0xa03f48e8, 0xc54338ad, 0x88ba9886, 0x3617dad5, 0x1e5eb6c6, 0x5c24b53e, 0xcaa67857, 0x9ad26ebe, + 0xedee9a2e, 0xbf26e170, 0x8c7f5464, 0x33e076b2, 0x77e339b7, 0xba9d667a, 0x817f3512, 0xabf4a552, 0x93dccd9d, + 0x81f6341e, 0xf9e46d03, 0xce9fd70b, 0x73b4ca6f, 0x59e42d3f, 0x8a2914d6, 0x9ec9c6b3, 0x64c7360d, 0x77ad9eb0, + 0xa85b3b1f, 0xd94004b8, 0x2b55dcfc, 0x140c3bcb, 0x0b8ed0fc, 0xaeedcc35, 0xc471b70b, 0xebc39e36, 0xf8e91d4a, + 0x971b262b, 0x514f3d6e, 0xfc88ec80, 0x06bea317, 0xee796ac1, 0x6f47d079, 0x45634391, 0x6048ca62, 0x7ee578b0, + 0xe688168b, 0xca9a035e, 0x7ac7a1b8, 0x1892e8f1, 0x4fe3e133, 0xf9309231, 0xcd7eb772, 0xecc5033b, 0x847cd564, + 0x95855a7a, 0x969d02db, 0x0ea49d7c, 0x75522f97, 0xb289ce2c, 0xf3b9397b, 0xd290c6f5, 0x76e6e69f, 0x1384a2ec, + 0x5de4a053, 0x1546b614, 0x7f2c1e9f, 0x654c7519, 0x9842d32f, 0xd6672338, 0xb0da93f4, 0xeaa06a59, 0x9dd1b679, + 0xca7698a0, 0x70fb7442, 0xa710709d, 0xa3b309cc, 0x28cf3cdd, 0x5e403bca, 0x31eafbb6, 0xb4c5553f, 0xd7c52861, + 0xbde20757, 0x23429385, 0x3793ed22, 0xee6de551, 0x6538309d, 0xe9678417, 0x5d904e45, 0xa9b886de, 0xd045220e, + 0x6bfda8b2, 0x5e171e73, 0xf9913860, 0x2b47c370, 0xef4324b7, 0xf11e84fa, 0x3e8a8305, 0x4f214b7d, 0x97d6ae7e, + 0x3641034b, 0xcd600fa2, 0x2a9463df, 0x81505c9a, 0xa1b60834, 0x38bf9e5f, 0x7a6b84e2, 0xa4111bfb, 0x167c7460, + 0xd3dea9c5, 0xae6d018d, 0x7cd7eddd, 0x9c74765f, 0x89bc7f49, 0x9cb54906, 0x976d7332, 0xb194c897, 0xd6b38b1b, + 0x8bfaa806, 0x2014e84c, 0xc4a757b6, 0xa856664c, 0x6235ff8d, 0x360b31d6, 0x9d73c955, 0x71e80d63, 0xc1a69fe2, + 0x641a1969, 0x73b1ac6a, 0xa99b9868, 0x214246dd, 0x20130d2d, 0xabf8fd7f, 0x7f58e523, 0x72dc7c9d, 0x7403a8f1, + 0x03e98cf0, 0xa2cb4681, 0xd50d3098, 0x4f62344c, 0x98016d89, 0x50dce795, 0xfd88c516, 0xc3bae32e, 0xdaaac345, + 0x085f449b, 0x87b911a5, 0x4158a42f, 0xb34b0aad, 0xf8d0fa21, 0xd1f67111, 0x5a7df5e3, 0xd9f5c32a, 0xb32aeaa1, + 0xdbb2e3de, 0xc85b9a0a, 0x2a80945d, 0xb55e3ff4, 0x64c3aeb4, 0x8c81b00f, 0x02f15ff4, 0xf9364c44, 0x04e62099, + 0xcd47e163, 0x01a66fe9, 0x7d68580d, 0x41227cdd, 0x609b2883, 0x2b9ba7bd, 0x8af4a0b5, 0x4bafa7cb, 0xf6ef68bb, + 0x5f5c8bf4, 0xf2617659, 0x6cde1eb6, 0xf7e2f2b6, 0x1873a45d, 0x4274035b, 0x892bdc27, 0x18a56d24, 0x92682286, + 0x0514d524, 0x8622c694, 0x783ecb5a, 0x6a921bd7, 0x376e5946, 0x38b5bd95, 0x26ee2d84, 0xa17d6cf0, 0xb97fd320, + 0x875d8a24, 0xfc746814, 0x884f4b64, 0x9a082ab0, 0xa77496a5, 0x7e6562ba, 0x6c50d524, 0x7fce08cc, 0xb3c78fb9, + 0x7ebaebf6, 0x35a22505, 0x94abea35, 0x73ea800b, 0x989faaa1, 0xc92765a7, 0x7517963f, 0xee065b72, 0x0e098aaf, + 0x90a12412, 0x98219c65, 0x6bc348bd, 0xbc71eeb3, 0x8d2807e6, 0x858616eb, 0x6da3eca1, 0x123079aa, 0x6918b324, + 0xf153de76, 0x4916d421, 0xca11d19b, 0x94af0a48, 0xb59ec526, 0xc04a105c, 0xe691663e, 0xab837408, 0xb6e2df22, + 0xb83f6727, 0xce967e50, 0xc6cc8aa7, 0x5faa2551, 0x82661d4b, 0xf4906755, 0x7069134a, 0x600da863, 0x9a7441ac, + 0x0771704c, 0x23142199, 0x2d92820a, 0x4988a04e, 0x2e979b70, 0x543f4289, 0x1076628d, 0x71bf3158, 0xdfe5d66f, + 0xeac27374, 0xada5ca20, 0xee2d70d8, 0xf6d9906e, 0xcf14f9ec, 0x75174cf8, 0x313dfc50, 0x0d6fb969, 0xa68275d1, + 0x10cf81d6, 0xffb4964e, 0x410573d4, 0xe3a50998, 0x3ed60444, 0x6b72dc5e, 0x68d19f63, 0x91e04596, 0xc282b63c, + 0x8248516a, 0x071ccfc7, 0x9845825b, 0x0bb10a2d, 0x9bf1c873, 0xa3d0d849, 0x412a49a3, 0xcc4deb6f, 0xcbbff14b, + 0xa634e9f2, 0x64acb8c0, 0x2d6f5e32, 0x827d1d53, 0xacfabb41, 0xb7ce56f8, 0x24c23517, 0xbe99869c, 0xb4fd2144, + 0xa3dd1852, 0xcf6468e0, 0xb476c8c9, 0x41ce04a6, 0x2077b634, 0x99016bae, 0x6d6f047f, 0x3350003c, 0xbf76402a, + 0xc661ce93, 0x52cb1707, 0xbd529c86, 0x454bd28c, 0x81bb3f2d, 0xfc3089c5, 0xdcedd226, 0x1d3d82e3, 0xa1a94555, + 0x1a7b5c98, 0xe1d575a3, 0x48b838b2, 0x8f2ba60c, 0x86b75987, 0x2c882cb0, 0xe94f48aa, 0x60606fe1, 0xcdb27d71, + 0xcb887a7a, 0x07bf101d, 0x46bc3588, 0x1dc3d0b8, 0xf78988ba, 0x307514d6, 0xae710c74, 0x6c93d537, 0xdeb10725, + 0x8047ef57, 0x6768022e, 0x4e0a5b47, 0xd2d7ff7a, 0x5f9e6b52, 0xe9553fb1, 0x14ff86ee, 0xaae46723, 0x1997e34d, + 0x797a8ac7, 0xae1ed036, 0x21be6874, 0x9a55be68, 0x312b945e, 0x3884ed15, 0xa435c18a, 0x5e2751d3, 0x8733a3e8, + 0x9d557153, 0x78b319af, 0xf4c8bd96, 0x2f822904, 0x13879a41, 0x0f7c58db, 0x99dfa38f, 0x773f63b6, 0x99f7a8a0, + 0x864e7f3c, 0x3712371b, 0x25d05b97, 0x6c238797, 0x3d886920, 0x22efdd58, 0x6f191fa6, 0x7f47361a, 0xbbc03a2b, + 0xb5eb3e9f, 0x5dd8dac8, 0xbfe68a46, 0xa7eb6135, 0xc942aa4b, 0x9ac7430f, 0x4acb5afd, 0x5f85364a, 0x2f3ea1f7, + 0x96d54d9a, 0x2412a629, 0x5830e947, 0xfdc5dcfa, 0xc4236d8b, 0xee1fa437, 0xec4f7d7b, 0x0bfd6eb7, 0xdbc6e3f3, + 0x605760de, 0x9eb8a994, 0x837442d4, 0xcb56be61, 0x0ea309be, 0x0dc4e27e, 0x314572b8, 0x6c788599, 0xc240d4ce, + 0xe348d084, 0x48c484a0, 0xb0e51013, 0x4673ae6b, 0xd7e28243, 0x59b09931, 0x9dda49db, 0x652ce55e, 0xf377dfa5, + 0xaca17450, 0xbbc988d9, 0x6ef917e4, 0xa20746af, 0x7b67824d, 0x29634207, 0x2621ff5e, 0x7271dcc5, 0xe0ebcd14, + 0xe7a3f70f, 0x9465dfda, 0xcd97cb77, 0xc39cfdc7, 0x97379333, 0xf853945c, 0x669e732e, 0x77c6e427, 0x1be6a725, + 0x68cd6a75, 0x0f50c48b, 0x3d255dfd, 0xa2a7f3af, 0xa8d9f796, 0x8fb0229b, 0x4cfe403d, 0x981bfe79, 0x944db238, + 0x16344bb8, 0xcd657733, 0x38d63c87, 0xa7d8fcdc, 0x80e2454a, 0x7ca45d5d, 0xa0cc9f86, 0x128836b3, 0xabea6368, + 0x169231d5, 0x8e84affe, 0x2c12a134, 0x84d56e8a, 0xdc767286, 0x539b0d92, 0x1799952b, 0x872660e3, 0xf2276a9e, + 0x27692afb, 0x515a06b8, 0xa569973f, 0xa83a910e, 0x807304d1, 0xf52b2375, 0x6cbf0a70, 0x1f218255, 0x6a0dd6d9, + 0x28158414, 0xb810d44c, 0x539c0cb0, 0xd4af9a26, 0x50a29cb0, 0x3951753c, 0x48f61673, 0xad3a22ed, 0x234699a8, + 0xc296648a, 0xb8814903, 0xe3d2a366, 0x01b88e5a, 0x38309f3f, 0x55786663, 0x40bb9fba, 0x89e2bf8c, 0xb4c7b715, + 0xbb0d1a16, 0xcd37ad45, 0xa089411d, 0x344a0d47, 0x2eaf9d2f, 0xea0b9f97, 0x0c8d6fc1, 0xeb8db97c, 0xeac4fa5b, + 0xa0dfe577, 0xc198a36c, 0xae624fd5, 0x996ffa87, 0xeca8b1ca, 0xbb21a639, 0x227f0817, 0xf03fb920, 0xdcb2ec89, + 0xe287c365, 0xfdf0e539, 0x0894fe17, 0xc8c7f28c, 0x894c2b7b, 0x855688b0, 0xf5e5390d, 0xb71032e4, 0x3a9945e1, + 0x4f8879a6, 0xdb99c627, 0xc99dcef1, 0x12d058af, 0x7781661c, 0x583c6242, 0x1e8b5551, 0x243a9e80, 0xe55829f7, + 0x70cd2cad, 0xe123389f, 0x6b4d480b, 0xbe68b433, 0x8567ffd2, 0x0063bc69, 0xf622af27, 0xe2159c9a, 0x3ed24c20, + 0xcf11cb2b, 0x43763adb, 0x24f48dad, 0x8180fee2, 0x965cb99d, 0x8713f723, 0x2cd995cf, 0x6f8a7986, 0xe57ac604, + 0xacc6624d, 0x8da0e957, 0xfad8d493, 0x5be40ba2, 0xb5762fcd, 0x82dbd7b8, 0x27ee528c, 0x5fcd1a95, 0xf958ab6b, + 0x1a25c9e9, 0xe5c06f0e, 0xf645bff5, 0xd212f862, 0x9b88d9e0, 0x27428b33, 0xddb8744e, 0xfab5dc6b, 0x678cb42b, + 0x16b7f9f9, 0x066a4be3, 0x61a0126b, 0x210eb0d3, 0x83611d16, 0x1b889d6c, 0xbc835ac4, 0xe9308f6d, 0xe7784c99, + 0x1ac19d2f, 0xcbb9afb3, 0x975c2c6a, 0xee14c527, 0x46217eee, 0x6874d79f, 0xff6afd39, 0x8f657201, 0x1e8dbdee, + 0x0974c7b3, 0xd3ac5e3c, 0xa34615c0, 0x21ddd4c5, 0xccf572df, 0x4c490b3b, 0xd306c858, 0x59b40d7e, 0x86792f09, + 0xd19904a4, 0xa52152e8, 0xcd69233e, 0x8f001b20, 0x01d2f831, 0xd6b2ef69, 0xc43f769a, 0xe142ed44, 0x3d5562cf, + 0xda76a717, 0x7f36a213, 0x4deb2ecf, 0x6dfaa91a, 0xe25f3465, 0xb91336fb, 0x75a7a68b, 0x65b6ca6d, 0xc6412221, + 0x3a59a475, 0xe9888ffc, 0x8a379bf2, 0x2e7f085b, 0x3502cfc5, 0x2ad84d1f, 0x97776408, 0xd08a78c8, 0x59177559, + 0xc4a1dea9, 0x47561c7e, 0x31d7ff8d, 0x258160f3, 0x713142ce, 0x10e6fab9, 0x580c16ad, 0x818ff275, 0xb304a313, + 0x36330cc9, 0xece41366, 0xcf4612db, 0x3ad6c941, 0xb5211714, 0xf66895fa, 0xd0ea7297, 0x573fbc8e, 0xc5b08f7a, + 0x0987f8af, 0xd03532c0, 0xa83d4ee4, 0xdfe5007b, 0x6df53a2a, 0x4626c1ab, 0x28def8d1, 0xc7cee1d2, 0xc6daba9b, + 0xb833bdc2, 0x63a9d5e3, 0x0b515e1a, 0xe7faa98c, 0x4ac0202e, 0x1b8a892a, 0x1f42e9de, 0x0da83f42, 0x65facc0b, + 0x7dcd62b1, 0xb68eb7a6, 0x72be2b4a, 0xbb34b458, 0x103c755c, 0x7abf2cdf, 0x7f914703, 0x8eb741be, 0x865a19e8, + 0x5f6b7989, 0x11a15843, 0xdb43d2f8, 0xd9465cda, 0x6b48840a, 0x65e3facc, 0x547c3f83, 0x192a0bae, 0x087d34fa, + 0xbd49e1b3, 0xae2439c2, 0x1c9b547f, 0x796c4bc0, 0xca7b6add, 0x67f39521, 0x07ba1b66, 0xe4e2bd6d, 0xf2fc2eca, + 0xb2ac3479, 0xbdb896f2, 0xebdde7c9, 0x73e1217c, 0xe82da8d9, 0x7194b56e, 0x81014d19, 0x6203d28f, 0xab3be424, + 0x8fd570f6, 0x2b88c92f, 0xf29c1c0f, 0x07b77865, 0x549be189, 0x3c651bd4, 0x6b853d41, 0x271bb8bd, 0xe3a13ae0, + 0xb4eb0301, 0xafac7e00, 0x9e8436c0, 0x13d536a0, 0x0f760e73, 0x7b976c8e, 0x7e2d2ed2, 0x876f7216, 0x67ddaf74, + 0xa7a6dc6b, 0x421519e0, 0x49403bc6, 0xc9b6dbee, 0x4e6bcb47, 0x31c8414c, 0xaa6677d2, 0x7cfa1cc1, 0x938274ca, + 0x614a7236, 0x12d183b8, 0xf4c65c8f, 0xd63d2aa8, 0xe2e06346, 0xf6426d4e, 0x014b235d, 0xaab43c55, 0xccd99eb7, + 0x1a659020, 0x4f44b6b0, 0x6d7b2048, 0xf0eda5b0, 0x6691684f, 0x2a5d1f14, 0xccdd1b60, 0x58e04d0e, 0xf930a3c0, + 0xfdbacede, 0xe55d2506, 0xda3e1338, 0x39e86b04, 0x01c4fe72, 0x02a7300a, 0xf4148208, 0xd80f861e, 0x4885b07e, + 0x048efb4f, 0x53e71253, 0xb0283358, 0x30d5c90d, 0x378ed51d, 0xb56390f1, 0x5d59951a, 0x46d01918, 0x8e7210e4, + 0x8fcf5797, 0x4bb7250b, 0xc4db3a53, 0x15d70ac7, 0x99f7a8ef, 0xc9f69c0c, 0xbabe9258, 0x09c98e7b, 0xcf8c94af, + 0x9797f9c1, 0x702f75dd, 0x62378c7a, 0x57ce1386, 0x42fdd083, 0x12fad989, 0xe41425dc, 0x4ba3cfb5, 0xf3d64d5c, + 0x8e0cb676, 0x05df2a3b, 0x251f1572, 0xc09407c7, 0x04db3421, 0xe68df015, 0x2070ffc2, 0x20f2f5e9, 0x57c27d4b, + 0x156876d4, 0x922a7d43, 0xbf44cf1f, 0xcc839535, 0x76a475be, 0xf014145e, 0x06b69830, 0xedbfe50e, 0xbedd720a, + 0xf576eb88, 0xf8a76f4b, 0x92ceebcb, 0x06cc4a31, 0x20171575, 0xcc1b71e7, 0x90830512, 0xf054c5a9, 0x725b5936, + 0x86db2b77, 0xa13235a3, 0xfbec1ee6, 0x0b633be4, 0xcb471939, 0x023e7b51, 0x0938fa7d, 0x338d7799, 0x1d70065d, + 0x251ce167, 0x096663cb, 0xca467bcf, 0x833a3d0e, 0x8204eb13, 0xf1e00ab2, 0x09b129dd, 0x7f7fa403, 0xd668981b, + 0x28cfc50d, 0xc82fb56a, 0x0c428cac, 0xcfa54c49, 0xb44bc8da, 0x6585b009, 0xb12e1c4f, 0x2ee2875a, 0x6632e73c, + 0xa07000e7, 0x2fe3b63c, 0x72851dd4, 0x37be0a4e, 0x23f48528, 0xa1be8bcc, 0x5fd1aa34, 0x8df58a6b, 0xd24d5548, + 0x94e8076b, 0xc51927a8, 0x3d9d8fed, 0xfb379d6f, 0x31cfde8a, 0x3ded60c9, 0x8971c33f, 0xcf153894, 0x763ba264, + 0x8a09797d, 0x9ef31a73, 0x60267c97, 0x079d4aa2, 0x2aa90740, 0x6d8cc036, 0x1781c02f, 0x7da04adc, 0x2d5bcb1a, + 0xbd9a85e6, 0xd85a1427, 0x1514a83c, 0xf74c6749, 0xe60edc09, 0x55c73275, 0x9aa7f76d, 0xbabf4fae, 0x47480d13, + 0x957a846f, 0x34edeb25, 0x35f2c8b9, 0xf914eae4, 0x50872677, 0x753f29f2, 0x905a2678, 0xe4911dd2, 0x5da669cd, + 0x45af686f, 0xe9f1577d, 0x4782cc32, 0x1cbfbbca, 0x2ce72fd6, 0x5155a18b, 0xe160e15a, 0x3e2dec6f, 0xbb119bed, + 0x23ac5bda, 0x10a0d777, 0x8d5c312f, 0x35f14c09, 0xcac4b699, 0xa043eaf8, 0xd0953c0f, 0x95b5a1f5, 0x2f01b028, + 0xbd9d7501, 0xc1f4de5e, 0xf6f21aaa, 0xcdb510c8, 0xfaa3390e, 0xe207dbeb, 0xf880b3c6, 0x3f9584dc, 0x773d064b, + 0xd56c1887, 0xe0515650, 0x91885545, 0x78962a43, 0xc5352ff8, 0x90953173, 0xb2107f78, 0x1b17191d, 0x519f5db2, + 0x94d2c5a0, 0x45eeef3b, 0x40919e2e, 0x5f2c0cd9, 0x11952cf2, 0xa8bb1ff4, 0xf804a989, 0xbbf0709d, 0xd08cce82, + 0xf362f3fd, 0xf7ae6944, 0x740bdc60, 0x0afeac9d, 0xd5f16138, 0xe7f92f17, 0x241d4e49, 0xdd298adf, 0x9d6725d4, + 0xa013c7f5, 0x926fb183, 0x4baddc80, 0xc010576b, 0xec79fda7, 0xdc76b004, 0x74e28200, 0x7bcfe9ff, 0xc8dd5324, + 0x8527d895, 0xa0809176, 0x7dc124ec, 0x0a721013, 0xb903ce34, 0x365f0941, 0x033208dc, 0x02f0cca5, 0xa0fcaba2, + 0x4ac6ba50, 0x87272747, 0x4513cdfc, 0x1f45722e, 0x24e8cb8b, 0xcdd6e4eb, 0x75b2d61c, 0x06bc3ddc, 0x319b74e1, + 0x7f6295c5, 0x87c3b647, 0x5b6c9d29, 0x4ac9d780, 0xa67b909f, 0x10e12134, 0xe7328a36, 0x4ea19b6e, 0xeb15d675, + 0xd593d814, 0x452f2e1f, 0x733056a0, 0x2dd3bcfa, 0x8edf32f0, 0x3a58f431, 0x4121d0e4, 0x3e40b029, 0x24783ef2, + 0x169742e4, 0xdc68de31, 0xb4763b34, 0x51f6e937, 0xcfdf4a7d, 0xc9eaf625, 0x55d0c7cc, 0x68dd6b62, 0xd7d155ef, + 0x1fb3536e, 0xaf2e3b90, 0x865bbe7e, 0xec035e1c, 0xcf775832, 0xe2244e39, 0x8ee4d48f, 0x6058d562, 0xe913d364, + 0x1643f432, 0xad06d677, 0xbfcedbf8, 0x3d81ab8c, 0xf83b34eb, 0x210ca9c3, 0xe7f63797, 0xf1921479, 0x76a0665f, + 0xb4748a9a, 0xa9d00cae, 0xae106312, 0xd28e0893, 0x19e027e2, 0x9920d450, 0x6a700f53, 0xcb536f47, 0xdefb597a, + 0x96ec25c2, 0x30ee9d0c, 0xd3cfe590, 0x42920a38, 0xc01c3925, 0x350af840, 0xe9b1f605, 0x4454234d, 0x03209027, + 0x87ae73cd, 0xd1a90e84, 0xd15d5373, 0xf9bc1d33, 0x95da32f0, 0xa06dac6a, 0xc5602603, 0x16d31d23, 0x317a218d, + 0x1334e128, 0x633c6b86, 0x0acbea4b, 0xe7915aca, 0x0adee6a8, 0xb42326c4, 0x674ad34a, 0x84bd184b, 0xcde97909, + 0xd8208fc2, 0x841ac8a2, 0xe0681588, 0x17e41a29, 0x5973b641, 0x81633eea, 0x444eba8b, 0x9c5c0736, 0x4fdae0ca, + 0xc01628f9, 0x6ce026e4, 0xcc021b18, 0x877a2b5d, 0xae15ef47, 0x7fac55da, 0x489d039a, 0xe683b832, 0x2dc9f1bc, + 0x2f63aa36, 0x028d0cb1, 0x8db36397, 0x4ea431b7, 0x84b08781, 0x3e35f8c6, 0x5dd1a26c, 0xfea664ee, 0x1200a625, + 0xf7bb0868, 0x83e7617a, 0x393082bb, 0x717004ca, 0x1c276372, 0xc6e75a04, 0x57189de1, 0x4fdb3ea6, 0x805a718c, + 0xdf6e32fc, 0x87b13c6f, 0x307e06f7, 0x1f5305a5, 0x81f290c0, 0xf6929c03, 0x5437145c, 0xfb8be18c, 0xd3b969d1, + 0xbd35080c, 0x10d2f7cc, 0x265f8ea4, 0x3dd93f54, 0xbb5c7bc2, 0x7e325c3e, 0x75ef4946, 0xe9080ef6, 0x028b242f, + 0xd2fbfe9d, 0x42ebacd9, 0xfd95b3bc, 0xe27509ed, 0x1a712364, 0x1acbf8be, 0x86a75b2a, 0xa8eab26c, 0xc46bc77a, + 0x22312338, 0x31c91ee6, 0x6e82e0b3, 0x1294b0ca, 0x1b3a3d0f, 0xf6a9a19c, 0xe446be8e, 0x9a20de1f, 0x6f95d052, + 0xc435ec63, 0xa761282f, 0x30631b32, 0xe3e14d78, 0x0a0cbac7, 0x7d879644, 0x9e9ec6cb, 0x5df8ca44, 0xdad7977e, + 0xbfc6459b, 0x2f583b51, 0x42209922, 0x15782e9a, 0x35ce40ee, 0x19682273, 0x94b5af54, 0x928ad952, 0xf29003f9, + 0x6e77835c, 0x6346be7f, 0x03147cb1, 0x98b32ad4, 0xd8d07797, 0xaaa711c8, 0x0dd5dd35, 0x9c3121d6, 0xb49cea86, + 0x6f6159a3, 0xfea264a9, 0x194c534d, 0x29ef4188, 0x1bac0586, 0x913583ff, 0x6ff54d7c, 0x983da7e0, 0x5f62b955, + 0x22d7b6bf, 0xb7174db0, 0x3cab20dd, 0x2dd8c727, 0x57533d7f, 0xbeb20e11, 0x84c1e3c4, 0x80a787dd, 0x7a426196, + 0x8c219b44, 0xe3bf4521, 0xb903e73d, 0xbe779901, 0xd2bd00bc, 0x24607b35, 0x129370b0, 0x58944c50, 0x97333b6e, + 0x93b2b858, 0xed3cb885, 0x0152bc71, 0xc0897bad, 0x87f43a40, 0x217403ab, 0x5055a17d, 0x7dedddbf, 0x1c743ebd, + 0xd004407d, 0x1d293ddf, 0x8300bf29, 0xc65dfe1f, 0xa5154b5d, 0x7fe5b21d, 0x4c7eed44, 0xbf294f90, 0x1b975258, + 0xeaf2b7d6, 0x812a6598, 0x081ddad1, 0x430ec669, 0xe572996e, 0x7be7e0f6, 0xf543ef0a, 0xa8b4a1a1, 0xf9fb2420, + 0x0e0b4d7c, 0x7054e75f, 0x67e3e342, 0x728e9375, 0x5ff3a520, 0x982083a2, 0xbfeee127, 0x801ba4bd, 0x3f558e27, + 0x59defa6e, 0xdb3f309a, 0x384b0e6a, 0x6065519b, 0x7500d4ea, 0x608efdbe, 0x2ef8d412, 0x5a876009, 0x7f95e03f, + 0x078b3107, 0xcbeef17e, 0x9e8a6b7b, 0xadde6f5e, 0x45b5cb53, 0x63f9ada3, 0x518c12bd, 0x06134fa2, 0xfb2323fb, + 0x6da227e9, 0xb73d0f0a, 0x73db9daa, 0x6e9e5d81, 0xfaa31aae, 0xc745d12c, 0xd19be49e, 0x4eed50cd, 0xf76e9935, + 0x192d23c7, 0x8a535cc8, 0x668d2c14, 0xe7fbd2eb, 0x7e5f9278, 0xed0c6b41, 0xcb6e9003, 0x23bb7237, 0xb8d462dc, + 0x18ff9283, 0xde7b17a0, 0x01e9cd95, 0x19de8c72, 0xfb84bbec, 0x94079e22, 0x637a0031, 0x810d6dd7, 0x119dca74, + 0xeddef2f9, 0x85a28b91, 0xa5d2c3d4, 0x8d8844c6, 0x6c850ff5, 0xa320a9f9, 0xbdd22bd0, 0x12bfad97, 0x713243bd, + 0xab600e71, 0x756b3733, 0x4121654a, 0x4c37d39e, 0x155ff585, 0xf3a38e83, 0x8b8c6764, 0x98be941e, 0x10788f78, + 0xabc80ab0, 0x56bce4f6, 0x3151dd59, 0xcc1be057, 0x8d7816b1, 0xf19be061, 0xf9493d8a, 0x831b951d, 0xb5efa534, + 0x50220d1d, 0x502d809e, 0x7ebb66fd, 0xf9ae3add, 0xb9796e0f, 0x5b272da8, 0x1ce93958, 0x42413b6c, 0x869ac523, + 0xd3954b56, 0xcd145c91, 0x778032e8, 0x70294a73, 0xd2d3024e, 0x90cf29b0, 0x82d17920, 0xe500cd51, 0x8c62c48f, + 0x4cbaa90b, 0x0e4c1862, 0xc0591033, 0x516e1654, 0x4f639d80, 0xb5e95875, 0x77761e8f, 0xe45a1e60, 0xf0b6edaf, + 0xf3fd6cf2, 0x0ab60fd9, 0x8ff83702, 0xfd6d7e2a, 0x35235fa5, 0x0c88ac17, 0x0189c841, 0x66954975, 0xaed8989b, + 0xfc71ac7e, 0xd8cfb9e9, 0xc9610f94, 0x17433cac, 0xda09a8ee, 0x5824c58c, 0xd32a7d76, 0x88d3817a, 0x0afdbaaf, + 0xe796d1cb, 0x53435615, 0x037192ab, 0x9b865846, 0xe8d1705d, 0xbbb0702f, 0x142245a4, 0x75ae935c, 0xd41dd028, + 0xe3a588ce, 0xd5841b3a, 0x52b66777, 0x47829003, 0x2cd74f20, 0x408e2b99, 0xad34f0d6, 0x015388ac, 0xeaadfa57, + 0x117a3e10, 0x90f16e07, 0xfaeb7982, 0xfc5f0445, 0x1bbd338d, 0x4165f34a, 0x23d6a515, 0x6d385950, 0x0382d3fe, + 0x5974a3ea, 0xd6e1b161, 0xb6b7bdb6, 0xae42ebb9, 0x35a06afe, 0xf77057ac, 0xb260bcbd, 0x0aa5ef85, 0x93242a85, + 0x58b48fc5, 0x5e94ebeb, 0xee1cf1cc, 0xc2be1206, 0x74404278, 0x9570d526, 0x4e104fee, 0x41478ec2, 0x6d10f75b, + 0x18e1f2ae, 0xd2489415, 0x72b9b69a, 0x16499cea, 0x6c3a467d, 0xe7761911, 0xda5a9d7e, 0x3f771f41, 0xb8429fcc, + 0xf25e126e, 0xc3ec3b80, 0x54d9fc24, 0xa8ea97cd, 0x0a7b1e68, 0xa869a0b2, 0xbe4a3cea, 0xf27029dc, 0x89320ff8, + 0x5e540400, 0xa9a7e0a6, 0xc0cac92c, 0x8484572f, 0x778590ad, 0x2bbddd86, 0x59595857, 0x42e756b2, 0x991d99a7, + 0x5a58bbaf, 0x6dfdbb9c, 0x5c9800bd, 0x299cc9c1, 0xab6ca095, 0x3641c7d4, 0x18e21220, 0x34e48c2e, 0xcc4d5ef0, + 0x0af1393b, 0xce69f5dd, 0x3d2da258, 0x137877c1, 0xa17ce026, 0xe015d083, 0x593f21c4, 0xaa491801, 0x0b47c219, + 0xc4db3d76, 0xfc8a639f, 0xc36d460d, 0x3575b0de, 0x3bb11ccc, 0x4cae7c1a, 0x508fdd9f, 0x63f9958d, 0x854f1a99, + 0x09dbd7c2, 0x9a7faf67, 0x7337cb40, 0xc38c91d5, 0xa685ce53, 0xe80bde1c, 0xfd75d135, 0x50eeec0e, 0x9062bcb8, + 0x2d96c922, 0x98709c03, 0x2dbf4053, 0x05b3d1f8, 0x6bad9948, 0x3d4604ea, 0x0dbdff25, 0x4eb9a23b, 0x74049907, + 0x51b0953e, 0x4b18b616, 0x218353c0, 0x23107518, 0x938571e4, 0xf30bdff1, 0x45e617a4, 0xc791ba04, 0xf9835a51, + 0xc7ebb331, 0xd7a197c3, 0x4025e34d, 0xf4d0150e, 0x752839eb, 0x66c5c25d, 0xa8d80cb8, 0x2e7fec7f, 0x5fff5cc2, + 0x8620aed7, 0xce9be122, 0xf206afb7, 0xd4537179, 0xb50319ca, 0xb99ff723, 0x8a132e91, 0x3a719181, 0x6845a79e, + 0xca2e1550, 0x4465e55d, 0xf4e5a953, 0x06de9a6c, 0x27b59ca6, 0xc9c19da8, 0x7b60d4dd, 0xfbfea45d, 0x5a77b604, + 0xbacc3ec1, 0xadebd1fe, 0x05097289, 0xd93cf406, 0xe1d5c33f, 0x9184e205, 0x83424e81, 0x587a2c08, 0x7a8b43c8, + 0x1562a7c9, 0x173fc8c6, 0x858a8dd1, 0x88d7d274, 0xe7810eec, 0x51a119e5, 0x49d394ad, 0x49aba13d, 0x0823bcc6, + 0x8c9efd59, 0x1796b7bb, 0x95537052, 0x26058cdb, 0xc841f517, 0xe85a9dff, 0x80883468, 0x9b80a172, 0x52cd1f68, + 0x03bc23cc, 0x4cc6681f, 0xb543226c, 0x977db888, 0x27c2b716, 0x120b47cc, 0x17c8b0db, 0xd813531d, 0x79876d5f, + 0xaa929faa, 0xd7b56772, 0x24b7d8f7, 0xcbc0c181, 0x2de36b37, 0xc0ed8218, 0x72eadcf0, 0x9d9e8e0a, 0x5a907e95, + 0x1565963a, 0x47578c6a, 0x7d51f322, 0xe1e7ec0b, 0xa3e29876, 0x4b83c58b, 0x3df7741a, 0xfc1cfb16, 0x7063dc06, + 0xab1dea7c, 0x176c4481, 0xa4891c81, 0x68c8e4d4, 0xfc8b5f8c, 0x0251202c, 0x38e2694e, 0x4f981e13, 0x5d75835b, + 0x6aaf4be0, 0x20e01c30, 0x7436bd9c, 0xa3cf9b85, 0x06faf8f4, 0x99f9f5f0, 0xa4bf3bfc, 0x0f0548c1, 0xb7b9e0c5, + 0x2e2017eb, 0x6e17274e, 0x4246f483, 0x7836cb87, 0xa9bea6d2, 0x51724e51, 0x4c270d9e, 0x6512c253, 0xdcc98e17, + 0x864644cb, 0x403c40db, 0xc0c418ed, 0x2177f13f, 0x36a4fd21, 0x89da1171, 0x8b58aa04, 0x7d97401e, 0x3bc093dc, + 0x85da5e45, 0x03e52bcd, 0xb94b4b55, 0x78fd8d29, 0x43097d33, 0x8459fbe3, 0x8779bf2e, 0xe3793c45, 0xd5d4f10b, + 0x0a827b59, 0x03b2210f, 0x1b106bf4, 0x21d6fe3f, 0x7eb053a8, 0xceb8f546, 0x5bbe6782, 0x680cab38, 0x52d50bb5, + 0xc87f609d, 0x5c3ab4d1, 0x8d3516d6, 0x8cb719d1, 0xf8b72f44, 0xa2c32665, 0xd0086a41, 0xe6a867ab, 0xceb996fb, + 0x7c871ae9, 0x9a22d602, 0x05f38780, 0x6fa0a7df, 0x2f3203a5, 0x00aec8ae, 0xaed9bbf0, 0x71d0ce05, 0x3c07e37a, + 0x1120100d, 0x185f3916, 0x4270a0c4, 0x6d4a5152, 0x6d118553, 0x24322c82, 0xb9fcafc7, 0xf2b40e7c, 0xd7f0a646, + 0x0f19b418, 0x8930c7f2, 0xd3fbf2e1, 0x6a4517c1, 0x70b8c4b2, 0x662906a0, 0x5137a1af, 0xf2975f11, 0xfd273662, + 0xa97ffed5, 0x8a30175a, 0x519d3672, 0xd3485620, 0xe64b1424, 0xc3504672, 0xe31be45a, 0x3ae1f32f, 0x294c1e8d, + 0x42aa8539, 0x674dc1e4, 0x05d4f225, 0x34a0a2c3, 0x89dc9763, 0x241020cd, 0xffbe71b9, 0xbc25ce3c, 0xe3a72ba2, + 0xa35f9722, 0xb54cf888, 0x4e89db65, 0x7a5b0179, 0x99ecb632, 0x95b6ed28, 0x818a22ce, 0x93f61a56, 0xa430c56c, + 0x94ce1db5, 0x11053f9b, 0x71d9afb1, 0x35b245ee, 0xf2e052f2, 0xf7d230b2, 0x882a2f16, 0x535a4c75, 0xb3ec5bf6, + 0x21cab2c3, 0x0d195acf, 0x5fdd7472, 0x65b1f2bf, 0x31f7c03c, 0x8c3375fd, 0x46db8076, 0x6629bc94, 0xe4da8df6, + 0x86b2e588, 0x5b8e84df, 0xa1448dce, 0xc6811498, 0x17168a5f, 0x4df0c200, 0x1095af56, 0x07d76109, 0xd6463ed6, + 0x2813917d, 0x88e3a704, 0x6a693270, 0x64a6a16a, 0xf48f87ec, 0xaf0cdfcb, 0x8d85fe93, 0x8cb83945, 0xc4735c45, + 0xa19ea67c, 0x564cc770, 0x34e182ff, 0x6c10cb18, 0xcbdc2f97, 0xeb229a44, 0x5994603b, 0x10e9d425, 0x8f45f3c9, + 0x7c1a799e, 0xffe05d01, 0x92aeeb03, 0xb5a0c536, 0xdedebe1e, 0xe387d78c, 0x311a3c88, 0xccc629d5, 0x685de5d9, + 0xdef0baa9, 0x0aede4dd, 0xb3e3246a, 0x68b0b4d6, 0xa41a6426, 0xe37c99d3, 0x11f3265a, 0x79a7da47, 0x631b7cc3, + 0x1bb2ce5d, 0xfa52c5a7, 0x62e086e3, 0x8a8dccd3, 0x40845ecb, 0xa886f960, 0x3ac995a5, 0xc9d34571, 0x972273be, + 0xfd04240b, 0xe77808b2, 0x782025b4, 0x51ba9604, 0x7e806af3, 0x66381881, 0x992c2cc1, 0xccb16296, 0x9ac20fbc, + 0x0a3f340a, 0xba307331, 0x0d2a1442, 0xb682de80, 0xaaabb8fa, 0x98ad71b3, 0xeebe7848, 0xc00d65c9, 0xaa16a97b, + 0x063ce7b1, 0x9e746fa1, 0x01d32112, 0xc99772cb, 0xe8916ac2, 0x8d1be999, 0xb04febe1, 0xb92b5b95, 0xe3f993f9, + 0xb93b1c5b, 0xd65b581e, 0x06f22688, 0xd02d6684, 0x0a8830cf, 0xd9797202, 0x845034fc, 0x9b7a4ff0, 0x8b405119, + 0x2ad54e7c, 0x51429267, 0xd060eedd, 0xa25b5aaa, 0xc07d913b, 0x3a25f08e, 0x1d192d6b, 0x824a4c32, 0x08bac1a4, + 0x02ae91a6, 0xa075245f, 0x241d9627, 0xee528aa8, 0x1076f4cd, 0xfc19b972, 0x6c5b6d4a, 0x690d5f30, 0x4e5b0252, + 0x982d2699, 0xc6901e49, 0xd9eb8eb2, 0x7bd05057, 0x64d467e7, 0x3c9d92d4, 0x90dca39b, 0xcc1ca580, 0x681794d6, + 0x2fabc514, 0x2872772a, 0xced4b291, 0x96517892, 0x631b22e0, 0x11a3b0c9, 0x6d1527be, 0x30c48ea1, 0x7452212f, + 0x4e6ad817, 0xc899455d, 0xe151c751, 0x39aab2b9, 0xff8bb5a0, 0x8aecffd6, 0x8ac66a9a, 0x7dfa9861, 0x9727a0db, + 0xc443dc6b, 0xa788d8cc, 0xc39ae3f0, 0x90c4ee7a, 0xfeaac63e, 0x8f2e1628, 0x4c66da32, 0x8d1f8f31, 0x895968a9, + 0x3ed80b2d, 0x46c4cf89, 0xbc155705, 0xaae8001b, 0xf4b88911, 0xfd6958b2, 0x40256454, 0xb0a9e2de, 0x69cc29f8, + 0x40aa1322, 0x48c648eb, 0xe2b55015, 0x4166307b, 0x02af3758, 0xe1c82e22, 0xef6ff35d, 0x5d59c852, 0xb6a60b7e, + 0xc12a91fe, 0xf9680aee, 0xc40889b3, 0x26b1e5ad, 0xf7ce8f46, 0xf1c6289d, 0x6b145f28, 0x84fcc228, 0x293d6e5c, + 0xa5ed947b, 0x83db4cf0, 0xfbd5da9d, 0x22f2a445, 0x0259e437, 0x04234bb5, 0xb0475b16, 0x96a7342a, 0x395396f1, + 0x5ed4e5b7, 0x695d83f9, 0x9ea73828, 0xded23f51, 0x3d4610b9, 0xef338869, 0x724cdfa4, 0xdf50b9ae, 0xbcad406e, + 0x51d13e2d, 0x7ee8482a, 0xb09cfe4b, 0xe2aeaf46, 0xeabccc6b, 0x0d2efb02, 0x463ca5b1, 0xa241520f, 0x490bd6b4, + 0x5a77321f, 0x56555716, 0x8980b730, 0xc30678db, 0xc8fe2215, 0x109ae5d6, 0xf31ffb98, 0x6edd0480, 0x383120b8, + 0x552d85ac, 0xc7a46d85, 0x4ee1735b, 0xa5233fb3, 0xaf3731f5, 0x9b8c6f79, 0x2c744141, 0x6407e5fe, 0xbcb67379, + 0x20a4d8fe, 0x6beecdd1, 0x374d6eb3, 0xc376d8f9, 0x0b097711, 0xae881ecc, 0x46539443, 0x0238ee8b, 0xa8977298, + 0xe6e170a0, 0xfd27e1fe, 0x3471b510, 0xbd2584b8, 0x31ccfe0c, 0x32b362a0, 0x1d4b46b6, 0xc4325c44, 0xe80dee9e, + 0x31dfc1c3, 0x1b248bd9, 0xbe01fdd3, 0x520fc7ff, 0xdfa7fda4, 0x62b29b6a, 0xe36d5058, 0x8ed9ed58, 0x47efb4d6, + 0x105583fb, 0x8da9e1dc, 0x536cff30, 0x38029f54, 0x6182419a, 0x26cc202f, 0xddc22ab6, 0xee478475, 0x2258dcf2, + 0x2de67cdb, 0xe1b65e3f, 0xb186c192, 0x4b0eb28f, 0xecf2ccd0, 0xdf0257e0, 0xc65c14bf, 0xc0c924c2, 0x11359a56, + 0x290e38d9, 0xde200e60, 0x7fd3a0dc, 0x981e1a1d, 0xaf15b10b, 0xfd4574fa, 0x15c7af88, 0x3a06060f, 0x380e8535, + 0x2b84d910, 0x94184194, 0xa94180e2, 0xa92344a8, 0x9d509a94, 0x342ac718, 0x2c39035f, 0x14e26ad8, 0xdae2fc74, + 0xc2bebcea, 0xe0a09629, 0x3b101dca, 0xf9d77881, 0x853ebcb0, 0x650e59cc, 0xf8dbf807, 0xa0cf5285, 0xf6c43034, + 0xa5dc1b02, 0xcdb68e77, 0xfe5995db, 0xd8907abb, 0xa5b3a6e8, 0xa5aa2f96, 0x6f9c0c28, 0xdf29551d, 0x8edfdf03, + 0x166e4865, 0x39bba330, 0x55d4e352, 0x0bc4c8fa, 0xe355051e, 0xf9bd9b39, 0xd4103723, 0x2a15a0c1, 0x6fa01f5d, + 0xd3f99654, 0x051d03d8, 0x41af231b, 0x4f8a701a, 0xe3d59085, 0xd8ff98bc, 0x780e110a, 0x59841c9a, 0x60700a1a, + 0x896de41f, 0xa01b53b8, 0x3d2dd13b, 0xfddf0e0a, 0x4e7d19a1, 0x94751c73, 0x5fff6c9e, 0x8819629c, 0x5779840a, + 0xb6792eee, 0x8ae12a70, 0xea11ad1a, 0x083a866c, 0x31fbd6b4, 0x4588d804, 0x0e1ad320, 0x81582332, 0x3ef41822, + 0x0ea9d3f7, 0x5357e634, 0x25659cd9, 0x18b3990e, 0x718c1f03, 0xbde83394, 0x729900d6, 0xcd6e896a, 0x1e11db57, + 0x6d6c0242, 0x340c75cb, 0x23dfa780, 0x9859eb4e, 0xf93d387f, 0xd7c50b40, 0xcae4b913, 0x7c24df6a, 0x8141675c, + 0xeebbf51d, 0xe2b40b80, 0xeac550f9, 0x75142615, 0xbadb1593, 0x339382f4, 0x20e478ca, 0xfa2a6351, 0xff1ff93a, + 0xead59d8a, 0x968d8798, 0xdb3844bb, 0x7bbf2c56, 0xecc6007c, 0x00a54eb9, 0xc60b68ae, 0x219bfc23, 0x0106f338, + 0xd3518b21, 0x4803b043, 0xdbed070e, 0x7e3d6b9e, 0xc82d280c, 0xcbb446ee, 0x6d2bc962, 0xd18d0850, 0x286f053c, + 0x1599c71d, 0x4a04f69b, 0xb6970921, 0x35fd0194, 0x87db3804, 0x4bfdfb94, 0xe63df391, 0xb9929a68, 0xc325fec2, + 0x17ac6f5d, 0x81016c79, 0x25f29194, 0x1b326e9d, 0x609618e0, 0x4b828ee9, 0x8e0b28e9, 0xb08e88e7, 0x6eaef535, + 0x4354caa1, 0xc163eb06, 0x2a414500, 0x9075b60f, 0xa0701246, 0x2c974c5f, 0x82cc73f9, 0xa4b87908, 0x59f8a913, + 0x226f6a87, 0xfb6297d3, 0x728ec806, 0x901fc30e, 0xd6de513e, 0x63887658, 0x2c77a3b1, 0x7409ae7f, 0x1ed0c51c, + 0x74cd7c80, 0x76f997fb, 0x56ba9314, 0x1eaac7de, 0xdc833cfa, 0x1636ce78, 0xc4db3097, 0x4a044986, 0xf2ece657, + 0x88bf7107, 0x65e5b9fa, 0x763123f9, 0x89609e0b, 0xf3bb363a, 0xf8d290f1, 0x55187728, 0x99d26042, 0xa8e55365, + 0x2ad0d900, 0xd1731761, 0x944e9e54, 0x28ea2d25, 0x801e3a7e, 0xb35dc65d, 0xd37f350e, 0xf1cc3a95, 0x65c246db, + 0xe36ab7ab, 0x65a59ca5, 0x66409437, 0xf447d7f7, 0x19c90cc8, 0x097847ad, 0x9b3c9f7f, 0xb8412fe5, 0xb12763b5, + 0xfcafcf08, 0x115aa51e, 0x5ae9d949, 0x91f1da7b, 0x61ba808d, 0xae8fc2d3, 0x3552168a, 0x342cbd32, 0x978913ee, + 0x18865daa, 0x8fc75055, 0xbe5ec299, 0xca25dfe8, 0x7f4f2c8c, 0xfcd28795, 0x7a3958e2, 0x053ddf92, 0x212f6965, + 0xd7254320, 0x48bfc1e8, 0x24e627e4, 0x910d73d7, 0x81642efe, 0x979600de, 0x3280c451, 0x859e154d, 0x6e6d1906, + 0xd8d7d9b7, 0x5234191f, 0x765f6c19, 0xacc4b100, 0xd9222556, 0x69bfebcd, 0xbec95b19, 0x9b10dcca, 0x4fd3f927, + 0xf98723cb, 0xebe39d22, 0xafa807a0, 0xeefa16ef, 0x81f7c052, 0x7739a2ad, 0x16e4b3b5, 0x5328150e, 0xdb34ece0, + 0xd19d6fd5, 0x9a2b4d95, 0x6b966412, 0x3a58d1f9, 0xb7ea67e1, 0x46cf93cd, 0xdb1f286f, 0x203b8c1e, 0x36ceb93e, + 0xaa05cda6, 0xc1aa4f56, 0x5e914538, 0xc0c31f1d, 0xfcd7da6d, 0xa1a0aa18, 0xff5fd691, 0x7a975769, 0x94490cea, + 0x1df01e09, 0x74aabd1a, 0xb978bc28, 0xa215e21e, 0x63d13826, 0x7576f126, 0x178e65ae, 0xdc31b535, 0xeb837293, + 0x56d27669, 0x822a612e, 0x3e7af5da, 0x6a90c3a1, 0xefaf0113, 0x1369331a, 0x45a0986e, 0x24b40861, 0xbc77effc, + 0x75a051c6, 0xe2cb5598, 0x4e277dc5, 0x1e8f4400, 0xcaacff1a, 0x9ab5680b, 0x97456c25, 0x792c6997, 0xd635b5dc, + 0x6dbd8234, 0x8cc6b585, 0x486435f9, 0xf64f62ae, 0xb6e52a44, 0x7d5149e6, 0x359ac17d, 0xa693090f, 0xc44a0eca, + 0xafbbe817, 0x58eb1a70, 0xa495405b, 0xa2acec68, 0xc80a8f48, 0x5b753d27, 0x1b98006c, 0x256e4ead, 0x4f8aac1c, + 0x4e8a30cd, 0x07a8a71d, 0x34a19c91, 0x6550998b, 0x0469de91, 0x2aba4f22, 0xb2b99499, 0x1369b6ec, 0x634da5ce, + 0xf574e80a, 0x19b3d5fc, 0x914d6e75, 0x4668ab2a, 0xf9f3e8b0, 0x30bf4e72, 0xd01cff7b, 0xbae44554, 0x7588615b, + 0xc861caa4, 0x52295a75, 0xd09165cd, 0x9530c779, 0xf8350f82, 0x1503380c, 0xde557953, 0x2c1a6915, 0xb05f175e, + 0xc39173c6, 0x4e1e4cf9, 0xdddab9a3, 0x691f1fb9, 0xd7086c25, 0x31c49cd9, 0xe861a869, 0x9410333f, 0x8d49b3ad, + 0x1020d44d, 0x2ed19d53, 0x62391631, 0x17884ed6, 0xae966a6d, 0xdce6cb56, 0x1ea6c027, 0x3436d71a, 0xafe05dda, + 0x7680b946, 0x8d24f865, 0xc324ab91, 0x702add2b, 0xa7fd5761, 0xdb7e0b1d, 0xed2e9bc1, 0xca4f64eb, 0x2c8b7de3, + 0xacf8d4df, 0xefc68f76, 0x92a00371, 0x07efabd7, 0x4b530fd0, 0xd4406f96, 0x0405b668, 0x8d358efb, 0x9670ad64, + 0xb93bfb65, 0x4228d146, 0x6a986a86, 0x20fd08ea, 0xa7a6119b, 0x63c9f2da, 0xa064074c, 0x6012be18, 0x604f348d, + 0x5b98a438, 0x03d7c7e9, 0xfcfb4c48, 0xd863304b, 0xd038f2a1, 0xbe96dd52, 0x78ff073e, 0x87a01ab8, 0xb48fd4a2, + 0xf0f5f7b7, 0x6b8fd826, 0x8abc2fed, 0xc50d0e54, 0xc32199f6, 0xa0714bc0, 0x17992fa4, 0x4f4d9a7e, 0x6c52a114, + 0x4b0b3880, 0x062ce874, 0xc9acfb0f, 0x8db78abf, 0x47d95ae8, 0x68164b90, 0xd2a1dcd8, 0x07382ef0, 0xd6dea5b5, + 0xead48da2, 0x9feb63fc, 0x61896ba7, 0x8c079117, 0xaa2dce45, 0x067eaf74, 0xe28119bd, 0x1aab3da1, 0x59c94da3, + 0xc49c867b, 0xe727b0fb, 0xbcb96534, 0xd1c29ec9, 0xdc1c31be, 0x3b1cfc9f, 0xa6790daf, 0x7b53e6c5, 0xd9593556, + 0x4eda1e03, 0xee0a9c0e, 0x03e53aff, 0x2d4d52d7, 0x8dd10352, 0x4a0bfb12, 0x890ace7e, 0x90177493, 0x2e24dd5a, + 0xee0b229a, 0x7ebfd737, 0xc30ae1b7, 0x008c9be1, 0x5be7326c, 0x4b328818, 0xcd61b2d5, 0x84938d78, 0x89280f98, + 0x81f5f81c, 0x39fd6537, 0xc62c0d50, 0xeea7aed8, 0xce0685c8, 0xa89d9017, 0x2a15c16b, 0x276a663a, 0x12f03323, + 0x9bc75728, 0x56d82a05, 0x22b0d8f8, 0x537e14fa, 0x98879d55, 0x6f5e5c99, 0x25807360, 0x3e02ce0d, 0xadae2525, + 0xe90567db, 0x0076b865, 0xfb3e4032, 0xe1bb38ba, 0xcb0e7a53, 0x9555cf71, 0x840ec265, 0x1339e7f9, 0x0b20a28c, + 0x50589d68, 0xc8e8e994, 0xb0ff010f, 0x07fc88d1, 0xb33c7ec3, 0x39fb233d, 0x45d6d907, 0xe05ae262, 0x98de24ef, + 0x59323a80, 0x4bd8706c, 0xc3d60f94, 0x4403992d, 0x74e1084a, 0xdcd25006, 0x57fc4dfc, 0x810aa84c, 0x9332df2d, + 0x8c1eca03, 0x8456e57b, 0x8712a65a, 0x11cc4a9b, 0x94366c5d, 0x6e2d6c4a, 0xe8e7dc2f, 0x8749dba9, 0xd3b9c8ed, + 0x15d223ff, 0x44ac0c40, 0x70b8714d, 0x60e783a6, 0x38163f47, 0xee21f379, 0xf47e9851, 0x07044efa, 0x34eaab96, + 0xbe7e3db4, 0x1ced368b, 0x5ae5264c, 0xf337adfe, 0x834c7233, 0x03b5e48e, 0x2d7d6c34, 0xc586499c, 0x0d9019b4, + 0xe2fbfdf9, 0xddc55053, 0x113ba87c, 0x18b711d3, 0x8f9a33c0, 0x5f159cba, 0xf216026a, 0x4ce58615, 0x000baa2d, + 0x9a2939f0, 0x61ee6cbd, 0x2c003095, 0xb43d0a77, 0x4f8968ec, 0x843f0fe7, 0x00eea9d1, 0xf457858b, 0xa5645601, + 0xcc7ff20c, 0x782a8429, 0x42ddd83d, 0x3016fa02, 0xb3770f4f, 0xba547829, 0x643ba8e9, 0x12e123fc, 0x8edba373, + 0x1e0fe9bf, 0x63e85687, 0xe97ec665, 0x15bb3a3e, 0x0e06a9e1, 0x38428939, 0x9771b5aa, 0x4bb33d7f, 0x0621fab7, + 0x31edfae8, 0x0220a2e4, 0x3c7885c2, 0x61be648f, 0xe4a30441, 0x5211c00d, 0x6cd3d70c, 0xc1cd3adb, 0x8c783904, + 0xb04fdfcc, 0xc03b338b, 0x50c17318, 0xcccb276c, 0xd8cf8a9f, 0x64d75e5e, 0x953d2490, 0x70e38c35, 0xb739de6d, + 0xbee3de7c, 0xfc504257, 0x8591c16f, 0x6ba1fdb9, 0x99b9ec2f, 0xf91f2da4, 0x3be9a86d, 0x911356ed, 0x5b884f77, + 0xa919407a, 0x97c8625e, 0xf7d271a2, 0xaf188753, 0x125738fb, 0xe8d61789, 0x06c6cd3c, 0xc0b7fb7c, 0x850d2376, + 0xcac588ee, 0x65c146d8, 0xafd90e5c, 0x5e8a03ae, 0xa4ec83e9, 0x91f68654, 0xad2e261e, 0x575cd71d, 0x8e11b3a1, + 0xd6488939, 0x862196ee, 0x7f13f5af, 0x75641e76, 0x5e8cb049, 0x6ccdf985, 0x6b228370, 0x5d3cdfc6, 0x0756b15f, + 0xab637bb0, 0xc67f97b1, 0x0ce23738, 0xb657f260, 0x0f70bad6, 0x866cd04f, 0x098f1b74, 0x1dcbed43, 0xd609b65e, + 0x2a466faf, 0xa430eecc, 0x7cb49ac2, 0x4dfaa56b, 0xfd60284a, 0x87af8293, 0x9daf0d66, 0xc128cc7e, 0xb6f4cac4, + 0x7f78246d, 0xa4ce862b, 0x6f4c01d3, 0x72cce46e, 0x4eeec89b, 0xcb983bb7, 0x899a2863, 0x94758444, 0x015576d1, + 0x0937dd84, 0xea2e848d, 0xc9784818, 0xbc43f3c6, 0xb7decfc9, 0x472a3c85, 0xbecf3aed, 0x883ee072, 0x4e1357be, + 0xb470396f, 0x698cf584, 0xabd9b5ae, 0x87720b62, 0xc4c30975, 0x34661211, 0xdb524a21, 0x4501a206, 0x562a9dd7, + 0x63aa7f18, 0x07b16a48, 0x85a8593b, 0x8b3b8bee, 0xbab12899, 0x52a19dc2, 0x6305c740, 0xca70f2ef, 0x9de144e4, + 0xaa80c72c, 0x18ac39b8, 0x7393e8fc, 0x09941063, 0xf904dc25, 0x4f977847, 0x33918cce, 0x0c42b9b0, 0x0cdc8136, + 0xd625f1e1, 0x4ebf18d8, 0xc57aae16, 0xad70908a, 0x3840feb5, 0xf018e161, 0xbdb4eb44, 0xab97707c, 0xb6d20d5c, + 0xce51d55e, 0x9cb8ea90, 0x3e8f8cfe, 0xd3e44adc, 0xe68a116e, 0xb3e87860, 0x4d38f0a3, 0x8dbae7e6, 0xcd10f37b, + 0x128a7b33, 0xffba63de, 0xeafad193, 0x2e38320f, 0x322db014, 0x5ee17e49, 0xf2d411ec, 0xeb55023e, 0x2a5ccfc7, + 0x5e59686d, 0xfe311617, 0xd5cfb2e5, 0x44e69a38, 0x9b3c833f, 0x4e44a8c7, 0xc0c57bb2, 0x49251fc1, 0x68e126e5, + 0x2a2db3de, 0x728d2105, 0x73e09ca4, 0xb74b68a5, 0xed4608fd, 0x91183183, 0x20a5e4a5, 0x4ad8d388, 0x65f70887, + 0x8be7803d, 0x9de9aaef, 0xb49f5711, 0xcb09964f, 0x3c71753e, 0x4a8a925a, 0x27636b65, 0xd060dcb7, 0xb44e0f95, + 0x7db5706a, 0x68843f4b, 0x0d8f068c, 0xa0d3b60f, 0x6a1b6ddd, 0x2e751a35, 0xec4505e8, 0x63edf8a6, 0xec60726f, + 0xab443ee8, 0xf57bb69f, 0x8a25c50b, 0xf2dcea29, 0x2ebd907d, 0x5e1b3a81, 0x8798b260, 0xcf35e285, 0x1d257f77, + 0xad9502e1, 0x8d212523, 0xc67b250d, 0xa8bd6cb5, 0x117c5584, 0x809b4a38, 0x5114826e, 0x4e2fc4fb, 0x94ee433e, + 0x4ba6f37a, 0xab14124a, 0xcdd877a7, 0x3b7717f0, 0x7fb7d993, 0xc0db0130, 0x6691abbd, 0x302eb9da, 0x3ceb13ba, + 0x6422392a, 0x1a41b217, 0xfcd6f62a, 0x2506b9ae, 0xdd896a00, 0xf4bff2b1, 0x8c43fd6a, 0x9c23e45c, 0x4782c29f, + 0x402163eb, 0x713994df, 0xf8663f0f, 0x2c36edd3, 0xbcdf872c, 0x7b780d4a, 0x5d058ade, 0xb41851e1, 0x1c452eae, + 0x7748af2d, 0xc112187f, 0x5f444dd2, 0x945f3af8, 0xd366c03b, 0x785f4f26, 0x91abe857, 0xce157dd7, 0x8bdd0ebb, + 0x78f3a8e3, 0x2a74c68a, 0xb4a05fa8, 0xdc7191fc, 0x08106ea6, 0xdcf59a30, 0x2cf6fa0a, 0x3ef24205, 0xe080cd84, + 0xbb7885fc, 0x0fd92c2f, 0x091c292d, 0x9d2550af, 0x22743c01, 0xdaa6970b, 0x1d2909ad, 0x6f6af466, 0xa651f97a, + 0xfc5ea252, 0x2866a04d, 0xf0b55d8c, 0x8eaf44de, 0x9caaa1c4, 0x89a2e617, 0x5f37624b, 0xec69094a, 0x436ec3d0, + 0xf3434f0e, 0xec00a830, 0xa50f0780, 0x28f6d362, 0xc37da424, 0xa278734e, 0x9e8e0427, 0x4e943a12, 0x4ad23487, + 0x88c24b28, 0x6be8e40c, 0x883d3192, 0x56edddae, 0x89e61c23, 0x58ff13bd, 0x6e04340b, 0x5c9ca8cb, 0xdc95f6da, + 0x5d832e87, 0xd4623938, 0x382b3cb0, 0x701ab950, 0x6e0fcc2c, 0x0812ea70, 0xd299bd09, 0xa05ce4a8, 0x55e76dcb, + 0x2888c0b0, 0x1790ec04, 0x8d9ee293, 0x7c703064, 0x41453445, 0xe71e2b15, 0x53fee3b7, 0x0916c9af, 0x181c451c, + 0x4e73b6d3, 0x21f30ab3, 0xb9890454, 0xca383b79, 0xc2dbf03d, 0xb28e4952, 0x33de4d65, 0x70249d36, 0xe015c19d, + 0xf047f94d, 0x81eefce4, 0xe0e70758, 0xb081507a, 0x504645f6, 0x903d9104, 0x589b9ca3, 0xab33c722, 0x5fe024ef, + 0x6d40e48f, 0xfb79a3e8, 0x9cbfe22c, 0x54c6fff5, 0xf5680b82, 0xf2f68488, 0x9dc13c7d, 0x21928e0a, 0x8bebf1c6, + 0x8f509240, 0x378bbf20, 0x67f939fe, 0x2f0b2362, 0x78e76a6f, 0x1a11d3de, 0xd31a80e2, 0x836786d3, 0x62244e15, + 0xe05b8fb6, 0x25e72831, 0xb7d4dbf7, 0xdc9eaf4b, 0xe010acb3, 0x1f5c4ce6, 0x9821ab3d, 0xf72554bd, 0x54aef24d, + 0x660d3201, 0xce5d125e, 0x82296750, 0x09e7b151, 0x792e6d4d, 0x13fa72f5, 0xfba06eaa, 0x0b045b9b, 0x634d1977, + 0x62923f82, 0xe717b7e8, 0x21f2cdd6, 0x8858ef8e, 0xea4cba76, 0xe140b4ea, 0xc7987f44, 0x75fca4f8, 0xeedda0e6, + 0x7be91d3c, 0x14eebb41, 0x8d36787f, 0x1c212fd2, 0x797e75e9, 0xd557410e, 0x742b9c17, 0x26d2e894, 0xb5d26ffe, + 0x3d502bed, 0x61ad2b95, 0x744b2df3, 0x5c94f675, 0x56df45ab, 0xf12ecfc8, 0x14446455, 0x58ff7ee3, 0xca42bbaa, + 0x935db65e, 0x8fac2576, 0x7bc3ec63, 0x462823df, 0x908ef1d9, 0x0712259d, 0x779c54c8, 0xa09b9c9f, 0x240aa91f, + 0xb48c8f26, 0x707d3c18, 0x81877e1d, 0x5b534acb, 0xabdc2061, 0x88453357, 0x124d2344, 0x51b11e83, 0xb38f377b, + 0x0009a559, 0x444315f8, 0xf3fc5fbf, 0x5762b27d, 0xd718c8a0, 0xfcff871a, 0x9ea627c4, 0xbe3fee99, 0x36c0db21, + 0x79ef9023, 0x7ce14733, 0xe1158202, 0x799bf746, 0x9f1d9cbd, 0xca6d7bca, 0x44eb4a42, 0x9263e50f, 0x6628bbe4, + 0xdcbeac3f, 0x1018dcbf, 0xe5639ae3, 0x345fd11a, 0xcce3e9f0, 0xe33fd198, 0x850aa739, 0x30a033b9, 0x3b6e6c07, + 0xe3e4917e, 0x371ba98c, 0xea7b9524, 0xb99408b1, 0xb5549a11, 0x906b0caa, 0x54afedb6, 0xb243b79a, 0x78561a6a, + 0xb21085f1, 0x7cce28a6, 0x8b6e9fe3, 0x7c28b8cb, 0x4d311ae9, 0x0159135f, 0x84e80053, 0x30f4eb43, 0xb3c01dd4, + 0x37278e0e, 0x1ad35f4a, 0x56754422, 0x0a2ec79e, 0x3a82ffa4, 0x3469476c, 0x48f6ec5a, 0x44f7e342, 0x0e122e3b, + 0x46d65b15, 0xef5d7d48, 0x8369c962, 0xa2a2ace0, 0x163014cf, 0x9e967d11, 0x99c87784, 0xbc41307c, 0xc45bd715, + 0xa7ca2898, 0x1235a42d, 0x3d2b7791, 0xac52ae8a, 0xac43fc7c, 0xcc656cfa, 0x44660da6, 0x562b916a, 0xbc83be47, + 0xce48bc17, 0xe6973ab8, 0xe376f84e, 0xf89e5f70, 0xa1295ad4, 0xdc9a8da9, 0x59e96dce, 0x9feeef16, 0xe848e37c, + 0xb3764553, 0x34b47d65, 0x8c4ccb17, 0x8c53d73e, 0x1556a46a, 0xd458c7cb, 0x9e68a163, 0xf8475408, 0x11ac9532, + 0xccb267bf, 0x0e617ecf, 0x528e3bcc, 0xe43b6278, 0xe7df80d9, 0x49ce87d3, 0xee075a2e, 0xd0635881, 0xa510399d, + 0x32d9155d, 0x07b9c7a1, 0xbc7804ab, 0x2f29c53d, 0x3b22905d, 0xffb61714, 0xebaecff6, 0xe2df00d9, 0xbe33cad4, + 0x00be57cf, 0x404b3ac0, 0xc942298a, 0xc54b4d16, 0xb0cb4de9, 0x4ff52ad5, 0x840fd5ce, 0x14d9084e, 0xf7962e47, + 0x869c8572, 0x6e0cd83e, 0x1b5576d2, 0x79eea6c6, 0x143bcb33, 0x0b0d5efc, 0xad327fed, 0xd5c6edf2, 0x6ef70c22, + 0xd0e6dde6, 0x693d26ff, 0x5c69cc8f, 0xc4db6d4a, 0xcdbcbff6, 0x76726c8f, 0x63e812c1, 0xef15fdce, 0xef042d5d, + 0x64dfef62, 0x3fb27741, 0x2f70d044, 0x1dd73f02, 0x1354161a, 0x16afc7b1, 0x98114799, 0xbcc465c1, 0x54ca35b6, + 0xa17eee39, 0xca900c67, 0x5723dc07, 0xf0036752, 0xb8a0d694, 0x065225f0, 0xd412e977, 0xfd533f65, 0x28fd1f99, + 0xe6353742, 0x694828bb, 0x1dd909c3, 0x63d72e31, 0xf571ac0d, 0x87d5b197, 0x4d1092c8, 0xcb10fce7, 0xf838598f, + 0x67d25077, 0x8a5becb2, 0xe9cf7396, 0x22059edb, 0xcf66e06a, 0x1450cbc0, 0x02a5a5ff, 0x788014c1, 0x6138f9d1, + 0x1b093b0b, 0x6d3216fd, 0x4fa24c39, 0x61a70a6f, 0x4716b25e, 0xf398c640, 0x728b4e74, 0x409fdc58, 0x7271b14f, + 0xf0d6755c, 0x121a1e89, 0x1459b0d3, 0x7985735c, 0xfe2b74f2, 0x41a43c3d, 0x41eddc91, 0xfca5aee5, 0x7cca9e94, + 0x87321a52, 0x48a7cfbe, 0xade47f69, 0xe7c0f37b, 0x66d84392, 0x891f7321, 0xb99c6425, 0xdf65058f, 0x548d7925, + 0xa7d8a3d4, 0x730a8595, 0xa751ad96, 0x91218af0, 0x1d820eba, 0x993d6be6, 0xb7f18fa1, 0x9955dfd2, 0x2c0898e3, + 0x71b3fae5, 0x0b2324f2, 0xa8156960, 0x9b64f2d9, 0x1e39ed41, 0xc7e99c61, 0x95be5e49, 0x00314206, 0x9af30f0e, + 0x3fb5b7f7, 0x83be12a3, 0x38973ca7, 0x9ffcd5eb, 0xe90166bc, 0xb723de46, 0xe64a46ed, 0x2b979790, 0xabf45460, + 0xec9a8c91, 0xafd8bad9, 0x22699b2f, 0xdbd90242, 0x53963b01, 0x2524b9ed, 0x8f45f2e4, 0x4764ece3, 0x4cdc18b0, + 0x338e3699, 0xc097b0f0, 0x646b74b4, 0x72e12d7a, 0x413b0677, 0x67893f3e, 0xd1fb64f6, 0xb29871f3, 0xc146bd74, + 0x977ed87d, 0x803fe212, 0xa8aff6d4, 0xab3ae0ed, 0xd78f3faa, 0x57ba5b50, 0x4bab2d88, 0x11784076, 0x188b8437, + 0x1f04737c, 0x1b887ce0, 0x42d3ddc9, 0x045ef017, 0x772219e8, 0x99b85077, 0x73128314, 0xacd57b07, 0x717de5e9, + 0x9e2e98f2, 0xd1cd443f, 0x849aad7e, 0xc79c4c08, 0x4f0f8af7, 0x1a536aae, 0x98153cd5, 0x9d5eba81, 0x1500197a, + 0xf1d2b928, 0xe3cf6323, 0x0c82e721, 0x217fa8ae, 0xb6f3ab9e, 0xdeef2aa6, 0xa136b75a, 0xf49c830c, 0xa17d97a8, + 0x23598588, 0x55ec0a01, 0xb1dd9437, 0x1e4575f9, 0x6348a6ca, 0xacdd5b06, 0x8f793ad0, 0xe1e80d7f, 0xf8e29aba, + 0x8fe71610, 0xa6798e09, 0x572e1af8, 0xe667e738, 0x95a494f6, 0x86211926, 0xb4946641, 0x89ec0340, 0x988a1562, + 0xd2f68c60, 0x7b999145, 0x151e1a8c, 0x39f9e609, 0x79823f4b, 0x4658bdca, 0xf20b5ad4, 0xd4095e8e, 0xc24315cf, + 0xcaa427ff, 0x8cb00c79, 0x7b4b68c7, 0xcc84395e, 0x7a327e46, 0x2f0d19f8, 0x3e3b1abd, 0x0b442551, 0x748bce95, + 0xf21054fd, 0x2c93bc48, 0xad738403, 0x3fc8b0b2, 0xdd575cbf, 0x889c3151, 0xc271dcf6, 0xe335e326, 0xb1f90962, + 0xb537002e, 0x241b7040, 0x9d5aa791, 0xca4f04f5, 0xd6685109, 0x3468e098, 0x39342bd5, 0x04ad2058, 0x083e6018, + 0x4be46c81, 0xa34d3c64, 0x270d24b5, 0x391015e6, 0xf936d3f4, 0x738fcd8f, 0x171fbd7f, 0x4908e902, 0x523668cf, + 0xa6b4060c, 0x05632c65, 0x9f0008ff, 0x8be4df9b, 0x2be0b01a, 0x2794f174, 0x71096ab9, 0x4540a023, 0x9d5a64b5, + 0x2a5d6886, 0x5971ad79, 0x58d91e4f, 0x265716cb, 0xc1cb5588, 0x71637105, 0x4391e9d3, 0x17769007, 0x8381261d, + 0x94320804, 0xbcee48dc, 0x05d37287, 0xb2b06177, 0x91ca65b7, 0x8e749a05, 0x5bef2921, 0xb8df5146, 0x4ee31386, + 0xfedfbf56, 0x2c2f4558, 0xbc707117, 0x084bcc5d, 0x069a226f, 0xf1965078, 0x46ecd9df, 0xa9ab71d6, 0x68c648fd, + 0xfb5ec570, 0x6b992063, 0x12cb06fd, 0xdc9d3335, 0x8815787d, 0xa76e2a79, 0x69720caa, 0xe66a3c97, 0x9895677b, + 0xbe4f2fb8, 0x63fa0d09, 0xeb1846dc, 0x39ceb6c6, 0x814f008c, 0x05e747ed, 0xb3f85f5d, 0x3b5fe5de, 0x9e92b9d5, + 0x8710277c, 0xb7ce514b, 0x628a218c, 0xe94a67f4, 0x09667a84, 0xbb3fd7d2, 0xc4e1bba2, 0xc16dc96e, 0xc25a76ad, + 0x663d7e7c, 0xe741c2ff, 0xc6f3e966, 0x85b63e93, 0x123dca7d, 0x194761e2, 0x1e784732, 0x998227cf, 0xb8246777, + 0xf623c553, 0x28ed44d2, 0xf679ebfe, 0x57c9effd, 0x5fd44c35, 0x6456f934, 0x337165f1, 0x87bb6a22, 0xcbb4c0a2, + 0x929b42c9, 0xcf7709ab, 0xa1eccdfb, 0x77e19446, 0x9974df83, 0x3eb54346, 0xe72c4a42, 0x46271c83, 0x6e312e70, + 0xa7f1d9bd, 0x3459fef6, 0xab68072a, 0xf7e282d0, 0x55848582, 0x8b98e798, 0xb4ddc9ef, 0xe6d97e25, 0x260a4bf4, + 0xafd2f5be, 0x567c433b, 0x108c9f05, 0xb7946186, 0xf6884510, 0x90d8008f, 0xe05d6aa6, 0xdc159ed5, 0x451280e5, + 0x4551ecfc, 0x678cac26, 0xc79877f5, 0x70cbf0eb, 0xd86f0300, 0x379b8a83, 0xd9c0f1cb, 0xaf4d1a30, 0xef50a1d4, + 0x9f552f7f, 0x57e28bad, 0x58064af1, 0x896bd954, 0x47e81bd7, 0xdf70c1a3, 0x005dcf84, 0xe950ae52, 0xcf25a797, + 0x30ce420f, 0x4360e88a, 0x7db63a1d, 0x0dc9eca9, 0x0e44df0c, 0xd8a1d56f, 0x9dcb8779, 0xc4b5fe36, 0x03151471, + 0xcaf2a814, 0xc02fbd25, 0x00720fda, 0x376ddee2, 0xc859d389, 0x336d0a4c, 0x629b28cd, 0x43330d4b, 0xb6c7c9b2, + 0x3d2fc8f9, 0x374a9614, 0x0926e916, 0x96cf2305, 0x3952c6b7, 0x2a300c1e, 0x4ba278f7, 0x91d1616f, 0x48385d02, + 0xd56f3d37, 0x002f43a6, 0x64ee637f, 0x5bd9e1b2, 0xf41d2718, 0xa9771ca1, 0xd40a518b, 0xff8c05cd, 0xa842c223, + 0x03bc6e7e, 0xac134b83, 0xc323cc68, 0xe385835a, 0x9e21ee1e, 0x31fd4eed, 0x883688c9, 0x6d935b8c, 0x06f7783d, + 0x0ba58711, 0xd6908496, 0xdf705254, 0xd5924e99, 0xe92fdd0a, 0xd5c5e3d6, 0xf0590b8e, 0x58839c1d, 0x5d94b341, + 0xe88a1bb7, 0xd37e22d4, 0xfc70cdda, 0xdf9f58fa, 0x40116369, 0x1c834c19, 0xb5548a01, 0xc768a781, 0x73bb4fbb, + 0x7b1076ff, 0xc4df1a96, 0x2a6652b3, 0x39e7436a, 0x0c996248, 0x0d8c69d9, 0x414bf568, 0x3ceef744, 0x834b81a7, + 0x71c3945e, 0x98ef3436, 0x62999577, 0xc98b9eeb, 0x8845a646, 0x35a0bc03, 0xc7de89f5, 0x38f886a3, 0xc28a01f2, + 0x9958c81e, 0xdacea660, 0xeb18d9ff, 0xf24daf86, 0xd422238e, 0x9103c8ed, 0x5e93a2c1, 0xa429716f, 0x09c601e1, + 0xec4c4571, 0x4f8d1216, 0xa266c3e4, 0xd46215e2, 0x7388bd0b, 0x6866111b, 0x76572f56, 0xa2bf2d61, 0xe45b8b00, + 0x817d114a, 0x3a3984c3, 0xcb3a6b78, 0xe303a768, 0xab409c72, 0x9efa9f47, 0x80a08e62, 0x72863ad4, 0x5ef34e9b, + 0x5051fd4e, 0xead7d349, 0x7f1a3ca4, 0xe984f93f, 0xe225490f, 0x321764f4, 0x7b74008c, 0x84795940, 0xfde29b1b, + 0x13764aa4, 0x25f12cb7, 0xdbf5ff25, 0x7f629cd2, 0xdc366815, 0x087f2a42, 0x29d1a758, 0x0bd9f38c, 0x279dd4c6, + 0xf3115708, 0xfa81d8f7, 0x5018b958, 0xbb78f46a, 0x693a62a6, 0xf69dd3e9, 0xd1302806, 0xa547e757, 0xdf883fb8, + 0x2f4f601b, 0x4fa74e2f, 0xd3849e2e, 0xf40d5502, 0xfced5380, 0x00d4bb55, 0x5a3ab57c, 0x756eb790, 0x93f05c43, + 0x660b1b12, 0x2553cf30, 0x9f906930, 0x4436e1c7, 0x31029f5d, 0x0f3efe76, 0x8049906f, 0x86abea8c, 0x9099f120, + 0x04daacb4, 0x8635ebb5, 0xa6f5b61c, 0xcbbaeb5d, 0xbe165ba9, 0x532fef9d, 0x7231cbd6, 0x1312aa41, 0x9e8397de, + 0xedc25b31, 0xb04d9c24, 0x3740240a, 0x9aaa9bf9, 0x5cc77a45, 0xded6e84b, 0x5fad7eee, 0x0545e548, 0x82a29513, + 0x124721bc, 0x01483278, 0x55d49c3b, 0xfe8cc70f, 0x43fcb0a5, 0x396c0732, 0xb489deaf, 0x2838df8d, 0x27be8496, + 0xc0ececb0, 0xff7b42e1, 0x6341a839, 0x827feddc, 0x47b10c8f, 0xe5dbe45b, 0x1b8f2cb3, 0x2f8a8813, 0xff800fdd, + 0xa7e5cc5a, 0x4d343f88, 0x24fecb02, 0x598ae949, 0x3887f4a4, 0x5d3545f0, 0x2afbcdf9, 0x5b299b30, 0x9eca6f7f, + 0xbcd50121, 0xa761577d, 0x029bdc41, 0x3778da5a, 0xf419b614, 0x7027473f, 0x540c1bd7, 0x8f30733a, 0x510dedc1, + 0x3a7a7ee3, 0x180732c3, 0xf375f9fa, 0x76ae3dd1, 0x60833fa2, 0xb72ca312, 0x174e5a37, 0xec27b353, 0xbdfc5d09, + 0xd14b7ed8, 0xd43bee11, 0x0a884e2f, 0x10da7cd8, 0xd9566e8c, 0xf4356ac6, 0x4e537872, 0xb79f82d8, 0x78bab156, + 0x271d634a, 0x2961f886, 0xb614d751, 0x6f35cc47, 0xcc6134b9, 0x0808e24e, 0x3f107ce9, 0xddadc805, 0x7261fc38, + 0x34e69b5a, 0x038d9900, 0xabcbb5dc, 0x811634ff, 0x2e0a92c3, 0x900878f4, 0x1e549fe2, 0x07c1fc12, 0x03fd6d57, + 0x32a2617f, 0x050a50d9, 0x265945fe, 0xcd336f5c, 0x818b4666, 0x09e8de04, 0xc729c490, 0x0403a930, 0xb19fd255, + 0x962600d6, 0xb3879c5d, 0xadb48c41, 0xca2b3cc3, 0x8c90833e, 0x3082b539, 0x42b695df, 0x26fe417d, 0x2e5497de, + 0xe74c8b60, 0x3b53de75, 0x7377b29c, 0xb7c27483, 0x2b0ff298, 0x9663de11, 0xda00707c, 0x0a27ab7c, 0xe234f675, + 0xb33348cb, 0x9a74ab5d, 0xa8bf7d21, 0xf0c52254, 0x63e9b760, 0xf7b3210e, 0x069bf663, 0x971ca9f8, 0xcd531b2e, + 0xa9a0db4b, 0x1410aacf, 0xb6fc4cc8, 0xdfb3239d, 0x6deb2e8f, 0xeaa45e52, 0xc2d4c0c3, 0x6d763625, 0xc627944a, + 0x36577117, 0x5bc3089d, 0x534872b2, 0x93858293, 0x890539e6, 0xa7e7eaba, 0x70c95670, 0x8507e8c7, 0x4274b1c7, + 0xcf267c70, 0x077ce3c3, 0x249f27f3, 0x9aa1606b, 0x84101591, 0x40b290e0, 0x0db6dd8d, 0x3a8bafd3, 0xcfcbf980, + 0xffc20f11, 0x56a2ee69, 0xa61c4306, 0x794db822, 0xefa7a610, 0xd5b89b6a, 0x68df2a74, 0xcfcb3d9c, 0xb8c74db6, + 0x5362ac14, 0xcdddbc95, 0x43009ebe, 0x7e30eebd, 0x19d2fffb, 0x918fa7f2, 0xc40c1fb8, 0x30d69a6c, 0xc71ab5aa, + 0xf2483d5c, 0xb6df5bc6, 0xd83b0294, 0x1ec3d763, 0xae9dbbd6, 0x5c9c0e46, 0x07490768, 0x5fa4762f, 0xd1ee965d, + 0x754635e1, 0xe0c07fd4, 0xd457fa39, 0x7bf37c32, 0x5b188cbd, 0x9ca52da4, 0x7684f7e9, 0x45e4cf15, 0xd692aa68, + 0x89be6d72, 0xa61b74fe, 0x102e372f, 0x8c4680c7, 0xc3d10e48, 0x577beed4, 0xc6c41423, 0xc5a5ab02, 0x3764d461, + 0x3ca82a65, 0xac188da7, 0x3ec10563, 0x94878df7, 0x42623e91, 0x11889f97, 0x0bfb325d, 0xd707b501, 0x8edda63e, + 0xea3a18ba, 0x11b3484e, 0x79469319, 0x98aa87c3, 0xc63f40a3, 0x9288fb66, 0xa7e19f60, 0x17796a3e, 0x65638dfe, + 0x9ba6eb6d, 0x97d98fc0, 0x7e61e18c, 0xc2ddebb6, 0xd32ed00c, 0xc32334db, 0xefa7f893, 0xc3a26d50, 0x2409b2e0, + 0x943514a8, 0x5b7bca01, 0xfddade7b, 0x86902bfb, 0x8981d194, 0x5638c439, 0xc7ff1d06, 0x3be8823e, 0x571e768d, + 0x28fd8ef9, 0x73834f52, 0x69486c5a, 0x67459040, 0x02e75221, 0x7ef952c1, 0x3f73d3cc, 0xaf241342, 0x5088658c, + 0xf3444da0, 0x3e84f736, 0x8cda047a, 0x4fffece8, 0x229fc92b, 0x9e8f7855, 0x2cba7ad0, 0xce432d55, 0xa5290da2, + 0x9dc3454b, 0x77fcf7d0, 0x816275fb, 0x01948593, 0x8dd8abb0, 0xfc01e121, 0xe3aa2227, 0xef756373, 0xd27ad4bb, + 0x3b8e3700, 0x54f76e02, 0x55ac2359, 0x1531a448, 0x01e40902, 0xd8bd4c93, 0x3749b0dc, 0xeebbe5ec, 0xeae951f8, + 0x1cbdef38, 0xf5601d56, 0x07a51bb4, 0xb7cbcf84, 0xa1a6752c, 0x8fb611f6, 0xd0f93652, 0xf966f4a9, 0x9413d0e6, + 0xfd5914f5, 0x6fb88834, 0xf4d42895, 0xf1136562, 0xf04c21a3, 0x20ab4997, 0x08615c5a, 0x4dbb6d32, 0xa3c9a244, + 0xe7341735, 0x0be6b030, 0xe2690c93, 0x3c5f4bb0, 0xaac3169e, 0x815b0b60, 0x4c5ec1f9, 0x60d4f376, 0xb3e81ca0, + 0xc34af676, 0xc9cd9bde, 0x513dc3bf, 0xb606c8c0, 0xd9ad83a7, 0xad596aa2, 0x7edab7d1, 0xe67d25f9, 0xbf83214f, + 0x97fe7d25, 0xe081e844, 0xa124c014, 0xed631b80, 0xd3474c7b, 0xef420dc2, 0x17d03498, 0x00b77949, 0x2972d5ba, + 0x12d87e67, 0x8f161377, 0xd4a4b6f2, 0x772ffeb4, 0xa4afc21a, 0x886a10c4, 0xe0a8d3dc, 0x38671885, 0xc914cbea, + 0x7c881da0, 0x2f2410cb, 0x8d92d35b, 0xa34bacab, 0x3ddbac3c, 0x3f553300, 0x7dc7831a, 0x8618c645, 0xd2566aab, + 0xac927974, 0x901e8df2, 0x453ad8fd, 0x4e275ef6, 0x045ede2a, 0x0ed59b27, 0x5bea8bb3, 0x92f50deb, 0x92e735a9, + 0x223c6dc6, 0x3df4cb0b, 0x4ca0183d, 0x52e8b84b, 0xe489a1be, 0xb3a83ae7, 0x4e79d4dd, 0x9bfb991d, 0xe88f826a, + 0x398475ef, 0xfb14eb7b, 0x7bee602b, 0x067cf2b0, 0x2d7b823d, 0x0b040432, 0x13317109, 0x4d8c585c, 0xd746ce23, + 0xc2604225, 0xa6cdbffc, 0xf26ee374, 0x90ae100e, 0xac5ee317, 0x7af2b13f, 0xe035c9a6, 0x7bd5fc0f, 0x6a45001c, + 0x44a3e6d0, 0xbe1d9194, 0xf31c2b92, 0x0493765b, 0xe96e6457, 0x5e31d213, 0x056250f2, 0x865d06f2, 0xa66e0b57, + 0x1ccb4b30, 0x4066ede2, 0x05e19a47, 0x60499048, 0xc086b420, 0x2b5278e0, 0xc97a3f53, 0xe523ff02, 0xff2ca80b, + 0xa011c8c8, 0x8f8777fd, 0x8e8d051c, 0x8df19a53, 0xe07bb7f6, 0xe17fa27e, 0xb9c1a99b, 0x5fe01e2c, 0x89bb251b, + 0x3c6b2cfc, 0x988cb7c7, 0xbab30c35, 0x55be67d8, 0xcf0cd6bf, 0xab5a9e8b, 0xca6bae9d, 0xa3385b1c, 0x350a462d, + 0xfbd349f0, 0x8b483e53, 0x5c6d8225, 0x44f83797, 0x1c458888, 0x3fbc6c5f, 0x0cba379f, 0x566a8938, 0x5b978581, + 0xcceb3bfd, 0xd094e312, 0xe41604c0, 0x8157930e, 0x6f9931d2, 0x957603b1, 0xcac6537d, 0xa932e6f9, 0x06ce8f47, + 0x6b6a9556, 0xefb8f8a0, 0x0363b97b, 0x5796f318, 0x33f8d07d, 0x6a82cde7, 0x9d4df582, 0xd057d02f, 0xe11dbb17, + 0xe1bf3008, 0x5c13a278, 0x7df6d200, 0x7a598a52, 0x6de02044, 0x7338a6d4, 0x5c3aa955, 0x27e4e8bd, 0x83ef1ec8, + 0x93ff1a59, 0xd5389ae3, 0xd4ea8447, 0xe67c3ece, 0x5bb297a8, 0xf9ed6002, 0x6d050bfd, 0x8fd11d9c, 0x131ae014, + 0x55368606, 0xe19b6c9d, 0xbedb14c4, 0xbc73483d, 0xf6a5021e, 0x4cf8c58b, 0xec0cb872, 0x0ba91802, 0xa61e2bc9, + 0xb4b4c817, 0xfe62ceec, 0x17659bfd, 0xfc6fc0c2, 0x37f88423, 0x9686b664, 0xfea66e55, 0x1a6e6b37, 0xf5f864c2, + 0xc6727975, 0x51c06b68, 0x64f3dbfc, 0x7a9c6efb, 0x8bf561de, 0x25545de8, 0x8c683d5b, 0x493c042e, 0xf72d9e5b, + 0x4aa545af, 0xaa5ca483, 0x7b9b3daa, 0x543ef502, 0xadacda82, 0x19f1c200, 0xd6e273a1, 0xbafdc8ad, 0x752d53bf, + 0x9e11d5c8, 0x566ca152, 0x7bacab6d, 0x21b3e3b6, 0xad58f365, 0x9daf3ec0, 0xcf50f174, 0xe9c0985a, 0x2e6c4311, + 0x8083e906, 0xcb06a164, 0x92b54c23, 0x6f355934, 0x292f84c2, 0x7e72a5ff, 0xffee335d, 0xa06dd114, 0x008d1011, + 0x5a42f355, 0xf360d97a, 0xdd5fff79, 0x95d62818, 0x12f7ef89, 0x24b5c0b6, 0x5ea474a0, 0x9557c956, 0x04d1fe77, + 0x797aa64e, 0x6a381382, 0xbd8a80ac, 0xbf0f85ba, 0x181b4dd7, 0x34ad85b9, 0x253d98a1, 0x27352c72, 0x7401de0d, + 0xa4c5fb0c, 0xdceec583, 0x70c18960, 0xdec1c5be, 0xcaf16684, 0x1e7d634b, 0x39d7642d, 0x2e238a67, 0x8b98cbd6, + 0xe9eed005, 0x7861feae, 0x31f3f1e1, 0xe91019eb, 0x4df8585c, 0x693ad0ef, 0x759aa3ab, 0xde46bd07, 0x9ee73d73, + 0x088bf67f, 0xeb13719f, 0x4266b8f0, 0xc27f0e8f, 0x17102890, 0xad3902c8, 0x95cb76b8, 0xb2c55e61, 0xf2bf2166, + 0x91c620c8, 0x85e71e3e, 0x3a8d2851, 0x7716f6c8, 0x3ab5ed73, 0x3edc9741, 0x23ccc634, 0x2073c42f, 0x2d11f9e5, + 0x4e221ef5, 0x5a3f5d6e, 0xb314eea2, 0x630d5495, 0x01fa536c, 0xcc1e49c8, 0xc5af3cfe, 0x8a7596ee, 0x79a6c485, + 0xf398eb4d, 0xe9f3f854, 0x3de34a51, 0x8d13d628, 0x330eca15, 0x541fa030, 0xa7304179, 0xa2b93063, 0x7773561b, + 0x0e90367a, 0x92693c0d, 0x072dccf8, 0xd72a8c4b, 0xc5ed5aa4, 0xa1624537, 0x72ed74a7, 0xe8b70ad2, 0x1fb4467e, + 0x33adff9b, 0xf26e94c4, 0xf1ceb6ba, 0x2d77171e, 0x814db57c, 0x9b4846ba, 0x52d8103e, 0xbf6de149, 0xed93ed62, + 0x133736f1, 0x64f1e8c5, 0x12c11148, 0x9285f826, 0xd932c175, 0x0f69b440, 0x6aca7f70, 0xc0df6994, 0x4023e0cc, + 0x4a4e27ca, 0xfc6b78c8, 0x716d82c8, 0x369a97ec, 0x6df83f8d, 0xc58b3399, 0x9f29df5b, 0xf583d6b2, 0x8d46c090, + 0x5571f659, 0x21965867, 0x44d5210c, 0xf925553c, 0x5f42b936, 0x8f844a7b, 0xdccfec45, 0x23e1e3cb, 0x8a79479e, + 0x71ba788d, 0xf15962f4, 0x8ee60397, 0xaa62776b, 0xf51ce974, 0xb2e91ffc, 0xa752994d, 0x5cc991a3, 0x58cd51dd, + 0xebaa4ea1, 0x050c4914, 0x4aee55ea, 0x89807ad3, 0x03063643, 0x295659fa, 0x01744faf, 0x03971f59, 0x2b64f697, + 0x52001689, 0xc3b01d22, 0x3a1d25cc, 0xe084af52, 0x900a013d, 0x3e7bdfbc, 0x4baeb2b1, 0x15141f7d, 0x3fbbf55f, + 0x6197a01e, 0x3562cd2a, 0x638e9cd3, 0x12bbadc0, 0xde8a2cc2, 0xe7f0f752, 0x56e2c314, 0xcad1ce17, 0x2c76850b, + 0x0368afa8, 0xa061952d, 0xae72b34b, 0x1fa8b4bb, 0x2d35d934, 0xb6439a95, 0xfbcd8c29, 0xcf2c87cd, 0x4e4b6671, + 0x866d8dae, 0x7eb450ef, 0x8ffbcbb9, 0x9fbe7218, 0xc5e281f4, 0xc1f868e7, 0x9e373075, 0x32ae28b6, 0x7436176c, + 0x8f58ee46, 0x2f7dcb1b, 0xf0aa36cd, 0x2d705ca2, 0xf29fe42e, 0x4bcc35b9, 0x4aa56657, 0xf51dd9f6, 0xd047f975, + 0x6b4b3d2e, 0x6ab63253, 0xc31d970d, 0xea84d1c4, 0xb17eb5ac, 0xa580f1c4, 0x6eb6db47, 0xbd7ca721, 0x4c484a81, + 0xee9569d5, 0xc8dc75e6, 0x4b61c003, 0xbc3df8a7, 0x7b888805, 0xd57bcfc3, 0xf83a4c83, 0x4431d2cf, 0x9aa702e3, + 0xd20d3df7, 0xcd441343, 0x496aefe6, 0x7f2ffce6, 0xf20b5b13, 0xb76ebcac, 0x04d9e070, 0x919d1473, 0x144b89d8, + 0xaea6e9ba, 0x5cbe117e, 0x51307ee8, 0x71acb267, 0xc9ef1f17, 0x70d720dd, 0x0e1f878c, 0x06d3be23, 0xef6d254a, + 0x66d8474e, 0x6cb50bad, 0xd39ae0e7, 0x11ab7181, 0xa776290f, 0x97fc0c44, 0xf7794644, 0x4f55ddf6, 0x4d23755b, + 0x1167d08d, 0xbeec8951, 0x8b23776b, 0x6171926c, 0x8dc9dc3f, 0x8232fda6, 0x5e1e8d2c, 0x2861bbfb, 0x8df0e009, + 0x09b7c913, 0x21d320d4, 0xa106d043, 0x63c749b2, 0x01b5ecbc, 0x2a53e1aa, 0xd9d58428, 0x6d97d16c, 0x8b2171c7, + 0x6ff5de92, 0x36ba981a, 0xf7ce3429, 0x91d1369b, 0x43d8ddb9, 0xc7c5e7f6, 0xc653b1fb, 0x4cf67a4d, 0xdda650b3, + 0xee4aff0a, 0xfbb591f5, 0xe5049a2b, 0x3309d877, 0x916ee245, 0x7093636d, 0x499eac60, 0x918d6a4d, 0xe9c986da, + 0x010c4ebd, 0x6c0f9aee, 0x10595cb8, 0xaa39e0c7, 0x7e2ef6c7, 0x8f973e0b, 0x3ba5420f, 0x2a7721f7, 0x38cde5ab, + 0xf875866c, 0xa2607f6e, 0x2b6d12e5, 0x23ec8af7, 0xf3ea48ab, 0x76227d6c, 0xb3bb8310, 0xaa737a29, 0xb07d767a, + 0xfe60008b, 0x4080bf64, 0x0902208a, 0xb127bf09, 0x99ebd668, 0x19c0200e, 0xd84bdd93, 0x8c21f212, 0x5987bcd6, + 0xf909b67e, 0xc49becca, 0x70d22613, 0xa17121e5, 0x482edde5, 0x96e23edd, 0x16b16903, 0x3e5eaba5, 0xa7133a13, + 0x044952d2, 0x23b71a2b, 0x87d94596, 0x5877dbcf, 0x77b6a483, 0xc653a9a1, 0x55f53f84, 0xff3e8bed, 0x9768dd67, + 0x0d27bf7f, 0x5b277611, 0xc12fa541, 0xf17e58fb, 0xfd6a28c6, 0xfe5e382c, 0x8b625af8, 0xf6d1eb1d, 0x719cdede, + 0xe24a4ead, 0xd2a1119d, 0xc01cd678, 0xf324113f, 0x2023a047, 0xdca5d054, 0x509a127c, 0x0872b009, 0x2d126ba7, + 0xe24dadfb, 0xcc6414fb, 0x2e094349, 0x5ce796b5, 0x9e160246, 0x833ac80c, 0xce175ac6, 0xdfbb0e65, 0x760db7c0, + 0xe76c421d, 0x34ad762b, 0x5fcc7508, 0x9cc86e72, 0xad464d95, 0xf5efd333, 0x3be87f0e, 0x62b4f18e, 0x8818e8c1, + 0xc11bafc1, 0xccdf8254, 0x4ff2a205, 0x4675a1df, 0x3d5661fe, 0x6b7786ed, 0x809a7e9b, 0xaf547a69, 0xccd63c20, + 0x472eba09, 0xf66a068e, 0x2470a0ca, 0x1c027dd0, 0x4b54d27f, 0x0ad16862, 0x8ff4605b, 0x302afd96, 0x5f8c809f, + 0xf28d3586, 0x69d21f6e, 0xe3030921, 0x75e7b7e5, 0x310719a8, 0x324e0fe5, 0x1ab879db, 0x11212921, 0x658a2942, + 0x03a7ccf6, 0x5ad81bdf, 0x437d3e74, 0x2f18c053, 0x51b3623a, 0xf66dcbbd, 0xaca2c3d8, 0x1b11731a, 0x300539db, + 0xadb2f5ee, 0xc1d8e2ac, 0x2ecf1d1a, 0x82afc47d, 0x894a357c, 0xba99ca57, 0x8b07b2c0, 0xd92737dd, 0xb3446802, + 0x02c1efe5, 0x436b1422, 0x6b12f5bd, 0x75c34a85, 0x3c13b3f0, 0xe78a632f, 0x04c72172, 0xa5622671, 0x0b3b1508, + 0xbe96c8d1, 0xcfc2d6c7, 0x5c0e85b8, 0xb153fdb8, 0x0a7c91fa, 0x298dca03, 0xa397710f, 0x78e2cb97, 0x4651432c, + 0x3435e01c, 0x2e048c0a, 0xd340838f, 0xf2a87ff6, 0x1d5f7559, 0xd265f353, 0x6b5f383a, 0xb12a817e, 0x624d8887, + 0x9256a1b5, 0xa8730eea, 0x796cc987, 0x9588db53, 0xf3d6a165, 0x5dd6c945, 0x121922ca, 0xe072bf57, 0xcb0c7c01, + 0xb6d687cf, 0xd0cbdf0a, 0x4466c8aa, 0x82552fea, 0x639b1c97, 0x27c09458, 0xf68a6ecb, 0xb2574352, 0x451b84a8, + 0xf00c6c82, 0x03ee61e6, 0x4a6abf4d, 0xfb885051, 0xdebd0a68, 0xfa1f8de2, 0x2d064fb6, 0xc928e353, 0x50d36d12, + 0x3e63c12d, 0x9726df17, 0xfa9ecf37, 0xf314c44c, 0x6c8d6d42, 0xd3a6d602, 0x926b8913, 0x57946238, 0x98c50687, + 0x67a61fc2, 0x2b8f68da, 0x51c131be, 0xfec1b897, 0xed80a185, 0x9846a19c, 0x1f8b08e6, 0x1c56aecc, 0x0aa5f33a, + 0xadb470e1, 0x88f370e6, 0xf2d442d9, 0x6a2bb0ff, 0x0b663608, 0x65c9a22c, 0x15b9c38a, 0xf2e45b94, 0xf2c48e5c, + 0xd77aa4f7, 0xe12a6143, 0x4d61b80e, 0xc839a974, 0xe3a929de, 0x7130c09f, 0xa1676495, 0x767503a0, 0x5cb3b47b, + 0xc41d01c3, 0x0afeb3fa, 0x43adc78b, 0xc655a885, 0xa097c778, 0x63b24385, 0x28fa3f5f, 0x989eca0b, 0x84fcc326, + 0x612b2490, 0xb0cab57c, 0xf0870419, 0x958015d1, 0x03444698, 0x4d6a2876, 0x851012bf, 0xc64c1e0a, 0x57c31635, + 0x5663d8d1, 0x8db2dbbb, 0xdb1fb7c9, 0x2511a756, 0x50b81def, 0xdf15baf3, 0x4006c64c, 0x1c07eae5, 0x2e1a0e9c, + 0xa996fd94, 0x553098ba, 0x2de13569, 0x235170fc, 0xa6040a68, 0x871e2361, 0x051a1771, 0x1531cba1, 0x42d7d599, + 0x06e1fac0, 0x702adca9, 0x0dc07c34, 0x779ad5de, 0xe31917fc, 0x75eb75df, 0x4496e57c, 0x2beec899, 0xb9445090, + 0x73f4ae4a, 0xc135bda6, 0x7a0f2898, 0xea1100ed, 0x6f8efde7, 0xa54bb35e, 0x1c1b7583, 0x6bf6fd73, 0xf132fdd5, + 0x11e44237, 0x42e7d492, 0x4c38813f, 0x1127fce4, 0xc7e8e1b6, 0x8cfdd14b, 0x92431875, 0x4e79e955, 0xa474e463, + 0x8d8833a6, 0x2a73af39, 0xf819d146, 0x2b8c0f06, 0xea8200e3, 0xec2ca818, 0xa460134e, 0x00723be7, 0x72deb26c, + 0x1f76ec71, 0x323a0d80, 0xc4ecc2ca, 0xc67e777a, 0xd4c0a667, 0x385ed334, 0x42b5c16c, 0xb7d018e0, 0xbed3fa74, + 0x6b52cfe5, 0x396717fd, 0x842f8b79, 0xf8dff79a, 0xaa627a22, 0x3aec5f93, 0xfc9e06a1, 0x554622c6, 0x39af12c5, + 0x95ebd011, 0x84ad73bd, 0x2c9bc225, 0x3a11a8ed, 0x1116f88f, 0xc3c0f75d, 0x0644ca3e, 0xf595b629, 0x0fc1e692, + 0x3a343f2e, 0xa0f07b04, 0x22c3e44b, 0x45b00740, 0xaee51b18, 0x62b97b47, 0x7304dc2e, 0xa9ebdf95, 0xf4fbf311, + 0xbc38931f, 0x3176fd10, 0x818407ab, 0x5dff7138, 0x20cf9969, 0x18d342db, 0x8af78f16, 0x12be7b7b, 0xd402b901, + 0xdd73d385, 0xdf216a31, 0x3698b636, 0x7a6923b5, 0x4a6f031e, 0x83e867e4, 0x2207f440, 0x1899dc32, 0xe3a4b314, + 0xae2aab91, 0xc063c126, 0xcc599bf5, 0x8c3dca84, 0x68f43054, 0x0a2c3e52, 0xbe2a3b4a, 0xa9d7d495, 0xb0f5255b, + 0x430d49b6, 0x0acd6bf5, 0x2bba9fed, 0xdd07a35b, 0xa9fd06ff, 0xb3178f85, 0x056a5f28, 0xf1606ae7, 0x7a6e205c, + 0x815f003c, 0x909d5cf0, 0xf7b6b46f, 0x3b375609, 0x548d018f, 0x58313bf4, 0x8ac951b6, 0x3389f07c, 0xfd61466a, + 0x1c21e9b4, 0xf9ea818a, 0xb80d123a, 0x2a669ef2, 0x8e17b7f9, 0x80b119ee, 0x4ac4db8b, 0xbaf9e5d6, 0x0a7af019, + 0x2d7ac37b, 0xdc81841e, 0x5e0eda46, 0x51a349cc, 0x42626b35, 0xabe9f830, 0x4329c5c6, 0xebdd1b04, 0xe1c91427, + 0x1e1d14e0, 0xfd2f3c1e, 0x54f8be33, 0x836bf05d, 0xbb57069a, 0xb80ea2d7, 0xae1a271c, 0xe9c4b7bc, 0xeebe2b1c, + 0xc39ecb98, 0x30d932c9, 0xdac5b646, 0x930ec4aa, 0x8f86d1e5, 0x8db9b177, 0x71a5d5ea, 0xd2cb1e85, 0x6eb3ff2d, + 0xededabc6, 0x07801732, 0xf3f67f74, 0x710868b8, 0x9a1a5f4b, 0x5194fa2a, 0xfc57a8c2, 0xfdea0047, 0x9c63c780, + 0x15049170, 0x17f74b37, 0xbe8994f2, 0xf631dbc9, 0xe7ebc6b3, 0x7e798ff2, 0xddf0582b, 0xe18ce823, 0x167f5f79, + 0x0f689139, 0xa1d973f0, 0x6e7ac55f, 0xeebd0c44, 0x9c61fdca, 0x7a583b98, 0xbbbad90b, 0xd19ca0dd, 0x3f77fd90, + 0x2c3c2447, 0x25705302, 0xdc50dccb, 0x937483bd, 0x8c40dea5, 0x1cbee31b, 0x156c3760, 0x1606a17a, 0xa7e14ae5, + 0x5ffd9433, 0x4fa31ad4, 0x27f0c3cf, 0x40a1be15, 0xa7e72713, 0xe4b5618e, 0xb36f7b93, 0xda707a54, 0xe47d5dbb, + 0x4710ef84, 0x4b058d44, 0xbc8488db, 0xcc5071fe, 0xcf821f6c, 0x44ab9048, 0x27df3522, 0x493f4373, 0x297351d3, + 0x343c0ac2, 0xed75fcef, 0x7c91b0e5, 0xa55f538c, 0x491b4b2e, 0xa064137b, 0x8492e554, 0x717f8998, 0xeb706817, + 0x302e70d5, 0xa67daa9a, 0x9f6dc6ee, 0x28dd88f1, 0xf831599a, 0x840f42ba, 0x1b610f0f, 0x2878be1b, 0x99586521, + 0x1a5a92b6, 0xc2af7eef, 0x04a3ee42, 0x7ecdab98, 0x6705ec39, 0x15f6d366, 0xeb1ef14d, 0x9007d198, 0x9f74c757, + 0xc7ad8132, 0xec7a80fe, 0x488fd1e4, 0x840c567c, 0x5b46d0e5, 0x03147bfc, 0xb93cdade, 0x67b50d0c, 0x125c84a9, + 0xc0352457, 0x7d38787a, 0xd6a2a2de, 0x48ac38fc, 0x6f064287, 0x1c818680, 0x8ec44b41, 0xd7082b32, 0x77312a07, + 0x53b071fd, 0x8c96989a, 0x00f726f9, 0xc8d9de78, 0x0096ac8a, 0xa5db7fc6, 0x37dc7e17, 0xfdb87c80, 0xefec180a, + 0xdf689127, 0xb7d89256, 0xdb0bf1f1, 0xb445df50, 0x86e751fb, 0xc4875c26, 0xbd882a0b, 0x55b2c95a, 0xb43ab782, + 0xf9961485, 0x91f2bf59, 0xefd8d0ea, 0x55bcabce, 0xcb171766, 0x6b05d431, 0x29714830, 0x30695c2a, 0x3b33c291, + 0x4df5cc4f, 0xe807ba75, 0xd963215b, 0x9c1a916f, 0x4e4bdf2b, 0xc2ac6ad4, 0x057c88ba, 0x0aae2421, 0x86a51c3b, + 0xb36088e6, 0x48f509bc, 0xe49c6110, 0xfc5d9a27, 0x976aad8c, 0x873819f8, 0x7f437585, 0x86a951d6, 0x88d127f2, + 0x1b66820a, 0xbe2c8bf1, 0xc287f77f, 0x2bb7bdf0, 0xc2a799c1, 0x4916aed8, 0x327eefaa, 0x84a7e4f1, 0x5bd2f5a2, + 0x706b0ae1, 0xfd075a93, 0x9216c947, 0xa538a55f, 0xd8c45afb, 0xfffdc954, 0xd2eb7425, 0xec8775c0, 0xb20f8a30, + 0x6789fff0, 0x6e70b5d3, 0x5ad8456d, 0x63ba8e24, 0x1e5275ad, 0xbf41cb19, 0xff45d179, 0xccc80b61, 0x997013b6, + 0x86444bd1, 0x62bd0d71, 0xba6c4ab3, 0x1110aaf5, 0x7e7144c2, 0x0e28817b, 0x9a720ede, 0x27e48dc6, 0x00f617dc, + 0xf370e533, 0x285ee864, 0x3c38d463, 0xcea380eb, 0xb645e8b1, 0x54aeedb0, 0xe938b370, 0xbcfa6df7, 0xda649e3b, + 0xb90731b9, 0xe59fefcf, 0xe08c4c8c, 0xd655d1bc, 0xdf5e43f8, 0x99623014, 0x1f90dfc9, 0x04e73ac9, 0x8b9323dd, + 0x06b943c8, 0xfe05ff19, 0x59591374, 0x41566519, 0x8916ca6d, 0x3d475aee, 0x11eec8d0, 0xe501c47b, 0xbc2826d1, + 0xa979b0c5, 0xcc68da40, 0x49f7c9ea, 0xd0d85959, 0x8a0d6346, 0xac63686e, 0xbe1d7c92, 0x1c518e1d, 0xf2d5bd84, + 0x9faf8941, 0x6aff8206, 0x1c3a2541, 0x1bb4e76f, 0x027ead08, 0x54254833, 0x6e3c8010, 0x586d1b57, 0x97b86a49, + 0x28077b2c, 0x4c74b492, 0xb7aa1da7, 0x7c3071cb, 0x4d957901, 0x92ab1256, 0x3591b639, 0xdc8f00a4, 0xf9ba6332, + 0x11257d26, 0xddc775c6, 0x263f3271, 0x5b529718, 0x63066796, 0xdfc0a775, 0x546406a6, 0xb292fa48, 0x5d435276, + 0x06be2887, 0x7eefa89c, 0xde7ce14b, 0xb8f83aeb, 0xc9285d7a, 0x4a82a67c, 0xc8f74aae, 0xc58cf7b9, 0x4b92a7a4, + 0x4bbae962, 0x3c38e18c, 0xf4935d79, 0xfa38dd16, 0x70bd37bb, 0xfe339d80, 0xccbb94fd, 0x08c0ef16, 0xffccde8e, + 0xa6504067, 0xebde9faa, 0xeda95270, 0x9ef13501, 0xca2bb031, 0x50d09d93, 0x3df69608, 0x3b402306, 0x4e7402b0, + 0x815cc604, 0xb947abfd, 0x9f15c4a1, 0xcde30c96, 0x04c764b2, 0x988bd284, 0x238a5306, 0x0a043a48, 0xeb376b97, + 0x4dc0fc6f, 0xf6c4d4e6, 0x40dd360b, 0x711ae61f, 0x796ebb99, 0x5768915e, 0x41c19218, 0xc11649f3, 0x832e6423, + 0xa7fee358, 0x47b30691, 0xb5ca7a57, 0x5f07f87a, 0x3b5e2a18, 0x80e8d76e, 0xa67c796f, 0x4709aa3c, 0x240c9066, + 0x3582eba5, 0x677a762f, 0xaf8b6d75, 0x63896c2f, 0x7cc8efa4, 0x5b201f66, 0x60f113e6, 0x6920c710, 0xd3395801, + 0x84728140, 0x5499ca9c, 0x00be5386, 0xc9d3c634, 0xe36c45b0, 0xd696c5c7, 0x9c04961e, 0x40511a67, 0x8d301100, + 0x4545537e, 0x45719cb1, 0xfd884593, 0x6a4d5051, 0x64684d1e, 0xb6d88b68, 0x96b282f9, 0xede9081c, 0x193327ba, + 0x0817718b, 0x648effd1, 0xaf1a47d2, 0xea7666a2, 0x3bbda827, 0xae3457cb, 0x46d50428, 0x2ca0a03e, 0x72594371, + 0x10095740, 0x1e69d194, 0x078031cd, 0xdb0772b7, 0x5506ff09, 0x927d237a, 0x0f28eab7, 0xedc2141e, 0xbdf247ab, + 0xc28c36af, 0xc9dc509e, 0xccb7d211, 0x062e9e27, 0xe9971b18, 0x8ab1f4c4, 0x345b171e, 0x9af3c740, 0xbce26f8b, + 0x97605938, 0x37f47afc, 0xb0ea5a0c, 0xb19ced92, 0xae1a4c34, 0x1eb6f06b, 0x6894011d, 0x634dca85, 0x01301bd2, + 0x49ee6d29, 0x20b18862, 0xa0d6183e, 0xddd2b3c3, 0x659762b8, 0x4b76298d, 0xbb3cbdd1, 0xfd506ac8, 0x9f7bfa24, + 0x20bd8f53, 0x12bb9eae, 0x0484d701, 0xa875f836, 0xdf719689, 0x45ff62a3, 0xc165132b, 0x92c62de4, 0xb7bbf009, + 0x199c58aa, 0x7434e115, 0x8236a0a0, 0xf93493bb, 0xae665fad, 0x4ba5cabc, 0x4352bf03, 0x28946806, 0x2c91d3eb, + 0x22566324, 0xd8db9d3f, 0xb0af7269, 0x51dc35e0, 0x575a9a4f, 0x1941c696, 0x76666f95, 0x7cbd1751, 0x89e1e14d, + 0xdbefb262, 0x45e2e22c, 0x9865fb10, 0x77f81196, 0x0ff20fc9, 0x81e014cc, 0x8ca6e206, 0x95ba1ffc, 0x8bc51c98, + 0x7ba6a89c, 0x286213db, 0xe47c13cc, 0x5ab9a159, 0xe5aac372, 0x4123d4da, 0xc0a160bb, 0xf0645541, 0xa921a570, + 0x3e17c138, 0xf412738d, 0xc14ebf90, 0xb0d55bb9, 0x56048562, 0xf3c7ec7e, 0xe7b6837b, 0xda7d1b77, 0x499f40fb, + 0xabcfac89, 0x3f477d9a, 0x35bbc2c0, 0x85cad8cf, 0xebffa425, 0xe93db543, 0x8c081f2e, 0xe1feec94, 0xe29a5612, + 0x211cf5ea, 0xdae1a494, 0xc22993d2, 0xacce9097, 0x4fbf5f3f, 0xd8f67760, 0xc54b28f6, 0xea93286a, 0x349c8798, + 0x463e5c73, 0x6182a645, 0x18ea19ad, 0x2650f611, 0x4ad98805, 0xe34416a4, 0x67dcf114, 0x66a3ff65, 0x9e6f63bb, + 0x08519908, 0xae552586, 0x9a0bcb58, 0x6876d32e, 0xf03b38b9, 0xb48a6a76, 0xbc9e4af5, 0xcf287c14, 0x65b88d3e, + 0xa5e4746f, 0x6e185811, 0xcb153750, 0x6ad6a3e2, 0x1e4dd443, 0x3dabc10e, 0xf5a75205, 0x24a283f4, 0xeccbf8cc, + 0xc642c578, 0xb5ca8d98, 0x0a2e07dc, 0x4c610964, 0xde5e16e6, 0x8217d838, 0x914a2630, 0x133b82ef, 0x8723c7d1, + 0x36210703, 0xeb49187c, 0x050c5674, 0xda8c4346, 0xc29780d0, 0xa7aa084c, 0x628c5bbe, 0xd9e4e510, 0x8f0ad32e, + 0xff49f5bf, 0xb87c7555, 0x34390a21, 0x40ae2e29, 0x7bdec6c6, 0x699019c3, 0xb0ef1103, 0x6fee4c1b, 0xfbf03e6e, + 0xb4b646de, 0x2135d57a, 0x34f4b06d, 0x249ec4fd, 0x39404886, 0xc7ab1396, 0x55da5d95, 0x75e0f22e, 0x78b470c6, + 0x6f8b16e6, 0xc921e776, 0x35067c5c, 0xd686513e, 0x2392469d, 0xc5f97f15, 0x06aa6a29, 0xa43835ef, 0x9f642ad7, + 0x548ac481, 0x094a8e0f, 0xc3ed3417, 0x8cc2775c, 0x58c3f5fe, 0x92838fa9, 0xff9cc492, 0x3e61796c, 0x144dcd80, + 0x5f1e698c, 0x796a57b5, 0xbcefe7b9, 0x39c67ced, 0x46dc40cd, 0xca26afdb, 0x57ab41b6, 0xdeb4999a, 0x803f8919, + 0xaba84bc3, 0x028f3e93, 0x920b3880, 0x754705fa, 0xbe50ff45, 0x144573c1, 0x0f215d85, 0x58a43a97, 0x6fdf953e, + 0x0d0fa19e, 0x87c37220, 0x76311446, 0xc3f3f18c, 0x60f3bd5c, 0xf33ee467, 0x6cf30273, 0x80ecbebd, 0x0c858cf9, + 0x66ef9258, 0x2a2cdb55, 0x719dcefc, 0x47427cca, 0xe71d6772, 0x839d776c, 0x942bdc4e, 0x3564f2be, 0x9f077016, + 0x7ca6724f, 0x034de7f3, 0x5c605858, 0x9cded4ac, 0x074583d6, 0x5c86fbaf, 0x80a5dc3f, 0xe5274b40, 0x33e814cb, + 0x7e6d6308, 0xcf7ff69a, 0xeb08134b, 0xeacacde5, 0x08e74d96, 0x510d144d, 0x494f0563, 0xd2c44149, 0x5f626b3a, + 0xcc48124c, 0x9bc4dad1, 0x1ae90c5e, 0x9574ce10, 0x2658917e, 0xbc19de0e, 0xeb5b119d, 0xa6f54668, 0x0b1cdd0a, + 0x828e92ca, 0x700a395d, 0x89b96928, 0x664dbec2, 0x999d844b, 0x18cf9c33, 0xde8be8ed, 0x8dc0dff8, 0x69d9f15e, + 0x87eaedac, 0x4c166e99, 0x46e03548, 0xe295c562, 0x883edc51, 0x42e57f6a, 0x4aad20b8, 0xb03c17a1, 0x5f4575d3, + 0xe9653b78, 0x7641688f, 0xef91b314, 0xc0a9b468, 0xceccdb61, 0xaa744277, 0x28c5181e, 0x9d4942c6, 0x42b0a9fb, + 0xfe6e781a, 0x62495fe0, 0x18af0107, 0xf1283d3b, 0x9ae7f8ef, 0x294d0224, 0x90e1404b, 0xabd81cf2, 0x00a3f93d, + 0xfb328e9c, 0x6984bccc, 0x5528d655, 0x15beebe3, 0x3bfa897d, 0xc985e287, 0x43c6514a, 0x1350b0fe, 0xe4fcf599, + 0xc177148d, 0x53915d91, 0x0b537e6e, 0x6c82834a, 0x3d293588, 0x40e12509, 0x06e74388, 0x16a33d05, 0x8bf85d8d, + 0xcee2e5c8, 0x0ff1c475, 0xd5ad8356, 0xb1337155, 0xa8a7ee72, 0xa6c74d1f, 0xaf2d348e, 0xfba58421, 0x68150529, + 0x07b444af, 0x4c86fe1b, 0xff397e5a, 0xaffc9f22, 0x34c8bdec, 0x70f3fdf2, 0xf2750cb5, 0xfe7209a6, 0xd5f89b1c, + 0x29c3a598, 0x2de94928, 0x6e4a195d, 0xf4b79eb9, 0x2b8a253d, 0x9f214bfa, 0x2e25dd06, 0xaefa88e9, 0xe0d7f2dc, + 0x9cc47328, 0x7f3232fd, 0x6d44f2e0, 0x7278eb74, 0xb18712f7, 0xf9f7f496, 0x1f05b9c0, 0xed98b1d8, 0x48c8f508, + 0x74fa266c, 0x7c7d6a86, 0x1e3fb28c, 0xb2454bed, 0xa3f18425, 0xac846fb0, 0x68d50d8e, 0xd2f1fce6, 0xbe480c7c, + 0xd8253d54, 0x9231f52e, 0xb4db3e5f, 0x800e9be0, 0x99fc2135, 0x56b64128, 0x4ca98bf1, 0xd522d653, 0x250270ae, + 0x07652c46, 0x046ddbd3, 0x68b37a71, 0xba641460, 0x90bf18cb, 0x2ad09aca, 0xb315a079, 0x8f324469, 0x9df49d87, + 0xbf75005a, 0xeb69d3ba, 0xc03bcebd, 0xb88c5030, 0x7c337b81, 0x434d3ca0, 0xd42e4b1e, 0x61c03b04, 0x627df7e3, + 0x6b407748, 0x41d1e9fc, 0x25527415, 0x013533c7, 0x6d3b2e69, 0x1af44ed8, 0xcc333046, 0x77e230a3, 0x1f61ab7c, + 0xd8fc937b, 0x758688b3, 0xebb618ba, 0x5bf91dcb, 0x10b4e6b7, 0x896c7bfa, 0xaa505e5a, 0xf63809f4, 0x7f02cf04, + 0xaf3e9d25, 0x1438a3f8, 0xa28b1b81, 0x76ed966f, 0x72d495fc, 0x41eb0340, 0x089bbe84, 0x9cb0478e, 0xbf900b84, + 0x0e00961b, 0xbfb6fa00, 0x091344c4, 0xa731406c, 0x1087836f, 0x4c31e7e3, 0x71fdd4f7, 0x6356c07a, 0x59238696, + 0x1a38e06f, 0xc695cedc, 0x76e22e74, 0x2d17709e, 0xef586f76, 0x687b4274, 0x31ac3d96, 0x497e18af, 0xb01cab75, + 0x29d4bc20, 0x4938ca79, 0xdd1d96d2, 0xbb8df453, 0x2f6ebb9e, 0x95c85c90, 0x95ba8af9, 0xf058b20c, 0x03334053, + 0x7b1477e4, 0x58052fb5, 0xd8b29635, 0x3a0c743e, 0x405f23ba, 0xc257cb5b, 0x5c3a1c77, 0x331f25ab, 0x60d02c4b, + 0xf5eefd64, 0x5304a091, 0x53be2ef0, 0xff255291, 0x50d127a8, 0xd493a494, 0x16985831, 0x82396e2d, 0x7c5de9e7, + 0xf328be41, 0x08083397, 0xcc502eab, 0xc3e9c981, 0x9559d98a, 0xa62b08f8, 0x1ef4c072, 0xed9a96d1, 0x9ddb3a3e, + 0x223e790c, 0x5ced2681, 0xd1711726, 0x307ac2a4, 0x3401c76d, 0x835b4754, 0xb5a5bb9f, 0xa4796403, 0xea53db3c, + 0x9d8c36c6, 0x5f3ae662, 0x35a1474f, 0x40fc85f3, 0x369e89a6, 0x1d4228d1, 0xf1f3fa81, 0xbbcd369a, 0xa0cc3d15, + 0x6dd8b058, 0x0a825107, 0xe1a4d231, 0x3ccafc04, 0xa7f8c3cc, 0x7e6c10c5, 0x184c40df, 0x6aaa1251, 0x2f7114d1, + 0xe3068011, 0x62621553, 0x9b2b0f04, 0x4e791e6c, 0xc20e9817, 0x53f33046, 0x2a7e0d58, 0x9a2415f4, 0xedd69049, + 0x81ad3b08, 0xff2f21cf, 0x6b951d2a, 0x2a08317c, 0x20000517, 0x9fd664a9, 0x6b6130a8, 0x8913849d, 0xc1d6d5ff, + 0x664ebb49, 0x1b86032a, 0xd2f8d34e, 0x86df92e1, 0xb035cf3c, 0xb0c70463, 0x3fbc7dac, 0xcaa5c5c6, 0xc0407c93, + 0x0a9363b1, 0xfa97659d, 0xeca1f8c0, 0xbf96df1f, 0x5b2f94d0, 0x6a7eba5b, 0x1497b5a2, 0x838c1125, 0xa4583091, + 0x74a8550c, 0x1e4787f3, 0xffbd06e5, 0x4320adb5, 0x0130ef2d, 0x4987c9c3, 0xe8442c59, 0xd1c43539, 0x0c4b4dae, + 0x744c3cc7, 0x56ad8f89, 0x8ad48807, 0x468939b8, 0x7f1ddc24, 0x23dc2ce7, 0xdd017b47, 0xd2ffe217, 0x171c2ba4, + 0xedfff4a1, 0x62c1c1ec, 0x37b38cc1, 0x145580df, 0x208eec4c, 0x284db2e6, 0xdffad819, 0xb2d6c621, 0xfdaaf89e, + 0x7c0e41ad, 0x63c35d5e, 0x5f03d1e6, 0xf8d0407c, 0x1cc5d6e1, 0xd055db5a, 0xe9672a5f, 0x62f8e203, 0xd5508138, + 0xbe995749, 0xa33ef900, 0x37382d1a, 0xb01272f9, 0xc49074e6, 0x59ad2ec3, 0x262aa7ab, 0x637038b8, 0xaaa32c92, + 0x637b080f, 0x69129e95, 0xe588b689, 0x3df6fb07, 0xa8e59d89, 0x44ad8c43, 0x3607e922, 0xb999e724, 0x0bed4fe1, + 0x2c1aac9d, 0x274e2954, 0x8473d283, 0x79d4a604, 0x19bcdb65, 0x00fa1976, 0x2875f4fb, 0xe90641a4, 0x933eb6ef, + 0x9b50c2ca, 0x1811372c, 0xa5d4d81f, 0x86b325ad, 0x2785d627, 0x672ef1d4, 0x0eeec3df, 0x38b07c67, 0xc8150eec, + 0x59c62543, 0x320b3714, 0x117ad3ce, 0xf24fc5fa, 0x11728ec9, 0x625321a3, 0xda8d7b8e, 0xd85aa107, 0xc10435e4, + 0x4754b618, 0xa82b4d93, 0x68f7715f, 0x6d162bfd, 0x007af943, 0x2691abdf, 0x896529f6, 0x465c502c, 0x07164fb1, + 0x5e3c0764, 0x88ce71c5, 0x5b9e7b12, 0x67adff6a, 0xa6e02960, 0x68cea52b, 0x065b6071, 0x48a0fd6b, 0xbfcb2a61, + 0x9eab105d, 0x14728e47, 0x2ef7a0fd, 0x04ad281d, 0x28f40bbe, 0xe0ac19a8, 0x7d3ec902, 0x04f90253, 0x96374800, + 0x6a057f76, 0x6ac1d446, 0x198b9377, 0x42a62da0, 0xe82715d3, 0xabf6d641, 0xacfd2093, 0x55529b86, 0xb36b760b, + 0x81452bda, 0xf5058906, 0x16d8c495, 0x1b8d7635, 0x09d4faa6, 0xe59c6683, 0xa00688a4, 0x5bc2235b, 0x0e0c9064, + 0x308b8a1f, 0x6bed473f, 0xb4b4dd1b, 0x9d97bd82, 0xcd1e3ded, 0x542fcfbd, 0xa21292c9, 0xdc5e5c53, 0x7948a070, + 0x460942c0, 0xc4d4b8bd, 0x34f8472a, 0xfdc2f968, 0x808a07d0, 0x7941d417, 0xd88ac730, 0xc341659c, 0x82cbfaf2, + 0xa7aba9f9, 0x95e4ba78, 0x432c7f97, 0xaf241f20, 0xcac0c9f4, 0x1fae494f, 0xf7d242f1, 0xae179118, 0xbe3cee7f, + 0xdda37bd9, 0xeb3bdd60, 0x6ab9aff6, 0x7f56fee0, 0x3ba26eab, 0x47895e9e, 0xf8a9c846, 0x7d38961e, 0x638bc36b, + 0xf06214b8, 0x0c66ed11, 0x9a26f8eb, 0xc4660691, 0xbf89da88, 0x42f84916, 0xf1488793, 0xb033ea50, 0xee14d106, + 0xd0159eb5, 0x61321900, 0x717e9313, 0x2f299e68, 0x5c593a90, 0x0b7c6129, 0x88766cb0, 0x14d19248, 0x9568ca2b, + 0x888de7dc, 0x994e3b83, 0x33101e05, 0x7e2f5981, 0xef515b37, 0x7f97156e, 0xee44fd3b, 0x0f12b601, 0xaf16cbb0, + 0xb506811a, 0x85e37ea4, 0xcfc43f6e, 0xe050cf1a, 0x7ea9b528, 0x6a65aeff, 0x2ed4c0e6, 0x9bf0d45c, 0x2a83a755, + 0xdc5b4565, 0xed4bf1f1, 0x78f6813d, 0x52d806b6, 0xafc80d90, 0x9186b40c, 0x28805660, 0x3e11d06c, 0xa97ed961, + 0xcd3cd754, 0xdd8759d5, 0x1a257d1a, 0x2b0478e0, 0xa182b5ee, 0x485d31c0, 0xad02789d, 0xad4f13b9, 0xb9c0f3c7, + 0x9c5c8e54, 0x10b3e155, 0x248ac49e, 0xdd33e77f, 0xf7fa3385, 0x7baa970f, 0x5559d4ae, 0xa5670287, 0xec605c56, + 0x0152b45d, 0x461706f2, 0xea43b9e5, 0xa30d07f2, 0xc2aec3f2, 0xc291a8b4, 0x9d76203b, 0x6e402fb1, 0xc7379c13, + 0xac42311b, 0xa33a8798, 0x3ec09c44, 0x4a69c3bf, 0x497022da, 0xa3c6a032, 0xc13af4b9, 0x25e27da6, 0xa922420a, + 0x7f5a4608, 0xf0d62905, 0xb698788a, 0xa1c16e4a, 0x774ef149, 0xabd102ac, 0x145d3d89, 0x439500fb, 0x43b2c8d6, + 0x2b30a054, 0xd1a8f06a, 0x06937acb, 0x28ba157c, 0xa3d6ae3f, 0xaa91b572, 0x1767a1fb, 0xf09cbb1f, 0xddee9b23, + 0xba4832c9, 0x49e6af82, 0x20eb8cf9, 0xc1b49cfc, 0x8871295f, 0x793d4889, 0x7d08a9bc, 0x450eb866, 0x84760a57, + 0x530cea79, 0xf1f01751, 0x0e6790cc, 0xfa31f772, 0xa935d63a, 0x503eea76, 0x3526fc9b, 0x1706270a, 0x0fcfd6f3, + 0x6bc436d0, 0x19f1415e, 0x42299f3e, 0x91f46654, 0x2ff16ff8, 0x0a825a78, 0x67ddff22, 0xec5facbe, 0x69be5a08, + 0xe8dcd42f, 0x96491ca0, 0x75d22a89, 0x9345a738, 0x7974b3a9, 0x7c2789a0, 0x1aed27ff, 0x771b5f3c, 0x3e1343c0, + 0x9cea094f, 0xa303e466, 0x753f2c30, 0x4d262860, 0x62521618, 0x663f45ac, 0xa1bb36dd, 0x2b92b2c9, 0xc82dac93, + 0x9e392c55, 0x18fbbd28, 0xcd61736b, 0x2ad51c89, 0x237d6f13, 0x2273ac77, 0x2d36b930, 0x7e05db7c, 0x18722955, + 0x2e624eb5, 0xf3395aa9, 0xe65ab26c, 0x4a3ddb82, 0xd00735c4, 0x4fb3a466, 0x17b92d93, 0x0e57ab98, 0xfef70a42, + 0x6863535b, 0x2042a454, 0x954a86fc, 0xd5c874f3, 0xf3f861ab, 0x25736926, 0xc5b61637, 0x14f04599, 0x8320178a, + 0x0a41dc6e, 0xd09e0c9d, 0x994e5c05, 0x2a22aab1, 0xf61c305f, 0xd2dae159, 0xfedbcc88, 0x04f598a9, 0x2bb0f76f, + 0x1e8bf8b8, 0x7d9ef6f4, 0xf44a27d8, 0x886c9603, 0x32b50112, 0xaa5daf1d, 0x9cc16b31, 0xcabe4428, 0x566500d7, + 0x1e03add4, 0xde973262, 0x1f954c65, 0x9da51a65, 0xe734ab3a, 0xe579a77d, 0x5deaa59a, 0x3247bd5d, 0xcc37e00b, + 0x1bc98688, 0x7d2c1ee8, 0x003f7ca4, 0x32fbc30d, 0xab59885b, 0x80573252, 0xf09d27d8, 0xf6fb07ae, 0x9eeadfb2, + 0x5c71ed1d, 0xec348b6c, 0xd8ff0b77, 0x2a54b274, 0xfe1da770, 0x8b153d9f, 0x283a3461, 0x5594c84e, 0xd2779cf5, + 0xf12f88e8, 0x37bce9a5, 0x74e5357c, 0x5e04dda5, 0x482d0f6b, 0x317ef275, 0x817b091d, 0xa66e0f3f, 0x46d19157, + 0x207c6bc8, 0xd941cde3, 0xc185c4c5, 0xea2f442a, 0x426ed81c, 0x3d292e7c, 0xb78e7b03, 0x02ce99e0, 0x0d6d0002, + 0x55400c07, 0x498f80f6, 0x6ff89cbd, 0xde00c233, 0x7862489d, 0x155f052c, 0xace8d1d9, 0xe5c869de, 0x53897976, + 0xa1307091, 0xb8e807bc, 0x25cd4866, 0x70b2c41b, 0xe57ddfbd, 0x8fea78c9, 0x0de21685, 0x239a2f0b, 0xc46f383b, + 0x95c7e04f, 0x2b2cd0d9, 0xe10c8361, 0x945dd6d2, 0x95bed650, 0x7e53d9d0, 0x27c392e4, 0x62fdbfc0, 0x436d130e, + 0x519d950d, 0x259acba8, 0xdc4ec8c0, 0xd414f3d1, 0xe10deeda, 0x651b8b62, 0x718fde8d, 0xd3ef6c59, 0x3ab74372, + 0x185e64d3, 0xe6009119, 0xc57d59fb, 0xe59db672, 0x272b611e, 0x8debacfd, 0x4624a812, 0xeaf07f9e, 0x50782e2c, + 0x01edc26b, 0xb1a04783, 0x5267500e, 0xe917899a, 0x2da6b4a7, 0xbe9abae8, 0x6f07574d, 0xc389c4ba, 0x0c4a2173, + 0x38d6285a, 0x2147a6d8, 0xcf1843bd, 0xdb8b3022, 0xf5785333, 0xf07fe146, 0x728d965e, 0x7a59a9a0, 0xef3537f4, + 0x3ca98f1e, 0xf80441ff, 0x62c1642c, 0x5e297026, 0x3b5fb404, 0x7d1027bb, 0xa73a9ef3, 0x5681333a, 0x300112c9, + 0xf6a41dbe, 0x8b36cf9a, 0x7afafd9e, 0x5259054b, 0xbbd7f4a3, 0x248e1b22, 0x1ecfcebb, 0x2caa43a5, 0x6ddd79ab, + 0xc4269d4e, 0x2764ced4, 0x7aadd1fa, 0x8780b81f, 0xaec44261, 0x94108984, 0xd2b2c014, 0x755932a5, 0x6894f620, + 0x7233f96f, 0xd7275f75, 0xdc007ef8, 0x1e8143f9, 0xb6255f02, 0x4960a1d4, 0xe4d53c40, 0x79a5e5dc, 0x62fc3eb9, + 0x61dbc5eb, 0x454473c6, 0x7411ba7c, 0x90ce83c2, 0xb8a5f26b, 0xb18ffd2d, 0x7b8d448c, 0x0ea9b5bd, 0xf6a647a3, + 0x1dd534c1, 0x2f4dff35, 0x7bb99630, 0xfe192fd9, 0x5677a5ad, 0xc1056482, 0xf4f09b9a, 0x6678ca1c, 0x472337a1, + 0x79b2dda9, 0xa74e2bfd, 0x3e2df863, 0xa270e082, 0xed4bd8e3, 0xf5a09f45, 0x40c6a90d, 0x8b106266, 0x5893568e, + 0x9d8292af, 0x90440eab, 0xfd7e7f3f, 0x7642d60d, 0x8b3308c0, 0x474fed04, 0x64906017, 0xb11545d5, 0x34cfbaf5, + 0x99679b5a, 0xf26004c1, 0xfcc4efe9, 0x455bed11, 0x2f902675, 0x6fb7d711, 0x9f2f5072, 0x200ec961, 0x004180dd, + 0x7568465b, 0x66503476, 0x67d9f708, 0x14e63024, 0xd5306cdf, 0xb19d07d8, 0x8475fb28, 0x6e7ffed1, 0x045745b3, + 0xe53c00a6, 0x7a6b2e1b, 0xcee3dbad, 0x22b1a842, 0xcf46abd4, 0x724e13f0, 0x2ddc2801, 0xb6d113ba, 0x3489d3ce, + 0x43aeefdc, 0x6cfbcba1, 0x7b779912, 0xb11743b9, 0xc5af46b3, 0xe2f2e5e9, 0x8a8a5fd0, 0x8f305930, 0x39fb8132, + 0x5a884bc7, 0x0527ef01, 0x81673eed, 0x7eb11d21, 0xef9a737a, 0x0adec51c, 0xe4c25070, 0x4fd58823, 0x72b91b6f, + 0x88d5f534, 0xde575ca4, 0x600b33dc, 0xeee2ace8, 0x2862568d, 0x7c68f2ce, 0x60a8bca5, 0x8addc3a8, 0x0677262e, + 0x1e40d72f, 0xfca71c65, 0xec770177, 0x019aefdd, 0xf42638ce, 0xbffbad93, 0x163b058f, 0x3ed90d56, 0xf7e5c1d0, + 0x4ff274e6, 0x50f3d496, 0x364434ff, 0xe1a3fd3c, 0x080e4995, 0x1d0f6947, 0xa2ef0a2a, 0x715c4a20, 0xfe91aa5e, + 0xd13c2771, 0x9f5ac2e4, 0xf5b139fa, 0x33117834, 0x645cd835, 0x57c4b12a, 0x5684b7dd, 0x3619d6c9, 0xbd4aad86, + 0xdd66d960, 0x492cd608, 0x967054f5, 0xaba3633b, 0x21aa84d9, 0x4c6d06c7, 0x53aa8a1c, 0x25b67b85, 0x4c526436, + 0x246fd6f2, 0xe1e5f76d, 0xf1549c51, 0x89a6162c, 0x739a0a96, 0x82d12863, 0x7cee9fa3, 0x1f0863d9, 0x4c251935, + 0x09b6abc1, 0x1a93d504, 0xfd9c2d42, 0xe1fc0ea9, 0xe1504cf4, 0x38d2a938, 0x9d488d1e, 0x25255613, 0x5b9922b7, + 0x5aa51e44, 0xd23e9610, 0x9b84834f, 0x55161d47, 0x6ecbb957, 0x6dd476c2, 0x00989a27, 0x1e0e80f6, 0x5c817759, + 0x7728b022, 0x7a3f4180, 0x5b49c603, 0x49600628, 0x6f566afa, 0xd7a1fa61, 0xaa469f3b, 0x17aa8e62, 0x703b5cdd, + 0xb020e681, 0x50261b38, 0xb79c23c4, 0x899b748d, 0x3e1588bf, 0x403ce2f3, 0xb50e7d59, 0x0ee21c4a, 0xafb5c2da, + 0x7354d491, 0xbad87b7c, 0xb32e33b6, 0x6ce675ab, 0xd17ef3b6, 0xd34b2e3b, 0x9d416010, 0x7a3a9f3e, 0xcf5fc91e, + 0x22561dea, 0x9b3db0c6, 0x5a0601a7, 0xa6bdfcb3, 0x09d43dd1, 0x44730c00, 0x88cd00ae, 0x513893f7, 0x1c789e8c, + 0xcfc12121, 0xcd5f7306, 0x366608f2, 0x3f33c165, 0xaae7d618, 0x89ea7117, 0xd3069b0f, 0x3c2140d0, 0xf1a9edff, + 0x96bb33b8, 0xfdace3e0, 0x606c21dd, 0x835d2229, 0x2afb5b12, 0x76212b12, 0x06495311, 0xd4f0e157, 0x54d11098, + 0xb1b602b8, 0x64fd5a8f, 0x422cc605, 0x8354205c, 0x922dfe74, 0x9a2a8064, 0x084100a6, 0x6cf06dc5, 0x139fe7b9, + 0xf3a9e95a, 0x39c2b654, 0xa00d99b0, 0xb306d495, 0xb583071e, 0xf0812b2c, 0x6adf2c9d, 0xd7e54949, 0x3e5967dd, + 0x5ba75c88, 0x4fd5e0ab, 0xb716f0b7, 0x7039d7dd, 0x99a6d83d, 0xed5c14ea, 0x9d630870, 0x807dfb11, 0x14449d07, + 0xbc1759f0, 0x56df6f68, 0x1a29bcec, 0x624d6961, 0x6b6245ea, 0xc08d029f, 0x6f0bc0ee, 0x03555525, 0x80db4d66, + 0x5ab1b885, 0xf10a291f, 0x5b496532, 0xc1abe1ce, 0xecbf6672, 0xa104c219, 0x4d49ea7a, 0x897d8821, 0xc39f6462, + 0x783a9d3a, 0x2ad8787a, 0x606d8a1b, 0x0acc8925, 0x91dc4ead, 0xc37f3e7a, 0x1ae8cb51, 0xb78693e3, 0x4c387bb8, + 0x7a8402bd, 0x3a3711fd, 0x9d6fe485, 0x2bb6dd18, 0x75617513, 0xd63d50a0, 0xc2a459b9, 0x56cdd791, 0x1e173705, + 0x60e926b8, 0xd424180f, 0x8a8004c0, 0x4f9ad9e1, 0xe7ca6e8e, 0x782d8219, 0x9a36ebb2, 0x561e50b2, 0xf2ac2fea, + 0xb4abfa82, 0x0ffd1bb3, 0x5605a911, 0x756ff47e, 0xc8367c9f, 0x2bb0bb0a, 0x81a4cf5f, 0xb849f3ff, 0x800bd8c5, + 0xcd22c8b5, 0x5c0b0f02, 0x0d5daca3, 0x151334b1, 0x8ab24258, 0x7b7814b8, 0x78ee1399, 0xa63afbed, 0x076d33a7, + 0x13f7d922, 0x008eea54, 0x7022fec9, 0xcd820bd0, 0xbc45a729, 0xf00fcfd9, 0x9fb834b2, 0xf2abd9a9, 0x9adc15ae, + 0xf6b7b332, 0x10d14616, 0xf6172d76, 0x41e793d8, 0x39c7cda3, 0xffc28355, 0xa0eb43fe, 0x91968d4e, 0x4c4ac535, + 0xdff0939c, 0x69f74921, 0x6f1ba0e5, 0x4b5a8dd8, 0x44986bf9, 0x0e3661f9, 0xbdafafb5, 0x75e36d67, 0x1e72a2db, + 0xf4418036, 0x8bcc9639, 0xb1509ee7, 0x97c8f7ba, 0xf0d70e4e, 0xe3142bf5, 0x4767eafe, 0xf73ac7ff, 0x2b606900, + 0xe09bb013, 0x1466ec62, 0xb5b15098, 0x8700edaa, 0x667db4d9, 0xffd1460f, 0x54158a69, 0xbe7c5169, 0x6597f348, + 0x11d4a40a, 0x20c2fa6d, 0x76bde67b, 0x0cd41bfa, 0x75926fb1, 0xc079b15e, 0xfc261891, 0x51e0530f, 0xa26e2ca2, + 0xf4e669a4, 0x8315b548, 0xa01cddba, 0xfeb0aedf, 0x2356a7b2, 0x8d5710d5, 0x8408ccc5, 0xd637e0c0, 0xcf3cd1b4, + 0xe93daef9, 0xb0f080d0, 0xb54cb9b1, 0x76e66832, 0x1a5c8f18, 0xd3a46a52, 0xba8a2222, 0x87b61795, 0x6b2ab102, + 0x2bf6225d, 0xf0bf2cff, 0xfce614b3, 0x53ee9d42, 0xf57063b2, 0x68814e28, 0x05ad3593, 0x5059789d, 0x03333a97, + 0x77fa51d7, 0x4159b99f, 0x55ee444c, 0x6295e40a, 0xd63f6f00, 0xb829bd5b, 0x1d404a74, 0x806bd695, 0x7bc26bfd, + 0x9c60b52e, 0x256df146, 0x24193e84, 0x05848296, 0xd23ad31f, 0x4c52a3c4, 0xebdbe1e6, 0x49824aa0, 0x5418c15a, + 0x9a7ca5a1, 0x39e61a70, 0x9506f276, 0x88dc8039, 0x74027381, 0xf4b022fe, 0xe2513e32, 0x41518a5e, 0x2c8f8a9d, + 0x36083d6f, 0x9fa01523, 0x16aba668, 0xae3dbe2d, 0x57d8c9c7, 0x201d911d, 0x1c9d4194, 0x664afac1, 0x5e9d4805, + 0x16472bf8, 0x6153e4b8, 0x9f53c0be, 0x3f01e72f, 0x549e3ed1, 0x45080ac0, 0xec4a0c2e, 0xc339fe03, 0x77bdecb4, + 0x69168c77, 0x1559023e, 0xb47e43fd, 0x85dae024, 0xe2739dca, 0x346c0b7d, 0xe0900364, 0xe1e7be21, 0xda00bc3f, + 0x076a8476, 0x611c52ec, 0x419f227f, 0xb4240db4, 0xb16819f3, 0x05b9e560, 0xef06606a, 0x377a1eeb, 0x5a586e9f, + 0x110bf355, 0x2ca7a082, 0x622535b0, 0x7099b917, 0x118a5df4, 0x052a24f7, 0x852e4910, 0xf671f036, 0x5f338101, + 0x52bff4af, 0xe8a7fcfe, 0x58be1f61, 0x3d9aaa40, 0x0037e3a8, 0x125f1bc9, 0x1ad079ac, 0x3502e3b3, 0x54c3001c, + 0x859deef2, 0xeda821bf, 0x9a0fa9fb, 0x2f94d87d, 0xcfbd19a7, 0xcdbc0d78, 0x8432e5d4, 0xfc4949f7, 0x36a1df8b, + 0xc7d81e83, 0x916d14df, 0xc04051fc, 0x714aabe8, 0x556d4a69, 0x3bf3217a, 0x8329d576, 0x53df6177, 0xe1ed5273, + 0xdf65278e, 0x1fad0b80, 0x09abf888, 0x7e5a4705, 0x8c6749b7, 0x39a76ebc, 0x36d30915, 0x5a1180e6, 0x5bba2606, + 0xa621498d, 0x13403333, 0xfcae8713, 0xcc6a074a, 0x66d43a83, 0x181068c6, 0x8ed639e0, 0x2e981629, 0x700676f5, + 0xbbf563d7, 0x5ec219ae, 0x0a3efad0, 0x572bea07, 0x8d611b8a, 0xed996933, 0x5b80c01c, 0xbbc10e2e, 0xbc4c7c6a, + 0x065dc7a7, 0x8fcf25e7, 0xd13e861c, 0xce045e38, 0x0bc68c0f, 0x7a858025, 0x96b8defe, 0x45e9b796, 0xc7d4d2e4, + 0x57744b4f, 0x4c96497d, 0xf9928505, 0x113c3ae2, 0x73535952, 0x3a9a875a, 0xa8404954, 0x6a497c6f, 0x9a8530a9, + 0xda34beef, 0x46250808, 0x7b19917f, 0x866efb2f, 0x6edc696c, 0xdf083a00, 0x60d6d978, 0x711a073c, 0xe89d8ffa, + 0xd00241e6, 0xd89dc810, 0xe2e45ca3, 0x2ee189c5, 0x3bf45b6e, 0x3b95a3dc, 0x7702b6e4, 0x71f53727, 0x3aa0597c, + 0x310392de, 0x6e105663, 0x80df0723, 0x9e02a929, 0x253beccd, 0x0756c65c, 0xd88e343b, 0x305daabe, 0xd3f141ec, + 0xee467048, 0x09740370, 0xf4aae472, 0x2e6ae4ba, 0x53163aec, 0x6343a2e8, 0x9002e638, 0x926bfaa9, 0x60450756, + 0xb09918c1, 0xa1f0670d, 0xa4d81f17, 0x1aceaee5, 0xfe394ee7, 0x5f834fc4, 0x1fb278d7, 0x8fd4aa5a, 0x3dcfc5bc, + 0x84e55cc4, 0x1fb72eaa, 0xbf1eb1ef, 0x88144f34, 0xce1d3d01, 0x38a0f34b, 0xe521b47e, 0x79596059, 0xf62324ec, + 0xfa5e4271, 0xd124c93a, 0x552d97d4, 0x7700237d, 0x42bf7002, 0x5d7952f5, 0x61413777, 0x7d8c0ffd, 0x9395ac1c, + 0x2ebd448f, 0x40a3066b, 0xc95eb1ab, 0x0e5f02aa, 0x1fedadea, 0xf1beaeaa, 0x5064b304, 0x031a03f8, 0x444d333c, + 0x13a65345, 0x53c71fff, 0xe231591f, 0x362ce2a0, 0x661b2f02, 0xcb60c6cb, 0x4fbe5cf6, 0x60d73652, 0x6b0a3980, + 0x0f89aa46, 0x7784355b, 0xc9657263, 0xf0bf6ed2, 0x90505064, 0x5279dc6a, 0xc8932185, 0x25e7622f, 0x975bf3c5, + 0xc12c4330, 0x65f02029, 0x8cd1fbcf, 0x4f28e5f3, 0xb8d22a57, 0xd6f141a9, 0xb4926661, 0x4f9c8991, 0x6782f597, + 0xa5fb22f5, 0x089e9348, 0xae97c3b6, 0xf19414ca, 0x16a3f97d, 0x1ff71d95, 0x11ef502f, 0x1dc5c88f, 0x5efbd0bd, + 0x25ae24ae, 0x42bd9795, 0x1f36ec57, 0x2729d386, 0xd89af184, 0xa8f021e5, 0x3af552a0, 0xeb2f1bef, 0xaa8fd8f0, + 0x462aa97c, 0xbebb9b15, 0x8c6b0526, 0x6a677e3a, 0x3d19ba0a, 0x6adec64a, 0xbc617477, 0x53ddce5f, 0x782078f5, + 0xde68faf0, 0xb084d6d5, 0xb4d6a43d, 0xa71a2253, 0xfec62f8c, 0x928fef11, 0xe3fea072, 0xf244378b, 0x331e0fc5, + 0x7a6bc384, 0x9e9f77d0, 0xfdae274f, 0xa24f7fd4, 0xca49fbed, 0x8ec1bfd8, 0x8804bd9b, 0x65080138, 0x9c0eaa55, + 0x384cafdd, 0x17b5f71c, 0x4665604f, 0x59f9fde9, 0xf394fe62, 0x0f328439, 0xb4298215, 0x5edcadd0, 0xf4b430a8, + 0x804a0221, 0xe06542be, 0x67662118, 0xcb4633f4, 0x7aa1b433, 0x4bcbf3b8, 0x1ee8779e, 0x593c86a2, 0x00b866d4, + 0x329eed29, 0x4bb11ee1, 0xc08f9d7b, 0xda1b18f7, 0x23c3ab15, 0x6da2a89d, 0xea22c772, 0xb1b5ab23, 0x05b3fba6, + 0xb1002dfe, 0xf0d3b85b, 0xd429f59d, 0x240867f0, 0x6db693d3, 0x180185c5, 0xb4c17580, 0x6552ffc2, 0x9e430aa5, + 0x22e58738, 0x2a550fbf, 0x6baeec55, 0xc8d04800, 0x2aec4259, 0xcf329589, 0xcc1efa71, 0x5f6224c1, 0x17e99261, + 0x674e953d, 0xc45637af, 0x26e5baf0, 0xc8bb787b, 0xa4c9b798, 0x8d4ba4a1, 0xf248c99c, 0xea208119, 0x3d235cb6, + 0x974ebc21, 0xd9108bca, 0xcafb3a8b, 0xaf1a5105, 0xd986bbdc, 0xfb41d078, 0xab5ffbc5, 0x201b39f0, 0xcbc06d33, + 0x8d3d1aba, 0x8f205d5c, 0xaa88aa96, 0x14fd115b, 0x8f0b82a6, 0x2445c2eb, 0xb3b28a3a, 0xd04d9d5a, 0xed8d4fc2, + 0xdcb62048, 0xbc163fd4, 0x6a26b0a9, 0x769febc6, 0x44457428, 0x069b45f3, 0xe08a5e80, 0xfc54105c, 0xedf71227, + 0x1e92c0df, 0x6619e65c, 0xe81bec72, 0xfc2f83ec, 0xd2171e97, 0x5adc3c46, 0x42bafdba, 0x3db77b08, 0x3acfdb51, + 0x237a6ccd, 0xbdf80a1c, 0x215a4599, 0xfe3a81d7, 0x2af7b146, 0xdd72c021, 0x83b7e18a, 0xe4533caa, 0x63ae1d75, + 0x1f7a635b, 0x64347665, 0x62347fce, 0x6db6443d, 0x7aaa720d, 0x80024db5, 0xdecd44d2, 0x278eaf6e, 0xad09b294, + 0x293a8247, 0x435225c8, 0xd2ce5def, 0x7a50fe07, 0x2641b6f1, 0xcd1d3f8f, 0x755b50b0, 0xfd6f9a22, 0xd73e78f3, + 0xe2ecebfc, 0x89ed723f, 0x7af17328, 0x6a78f721, 0x4aa80db8, 0x1be668e0, 0x46f42b7b, 0xfb34edc9, 0x8f1f6809, + 0x27e9c2dc, 0xbefd8035, 0xb0effe44, 0xaf0db17b, 0x304f1850, 0xefa6bb3e, 0xd007c1fb, 0x3eaebe26, 0x128abc0d, + 0x72ae2300, 0xc0b6ed22, 0xcfef73f8, 0x8566c743, 0xaa9ed88d, 0xb6c8034a, 0x7a617769, 0x85401275, 0xa3fac4f6, + 0x88b8634f, 0x372a6a9a, 0xa520b504, 0x7e0c1eb7, 0xfb83a35e, 0x951a0d38, 0x2234be51, 0x28e60e61, 0x20335526, + 0x67a0228f, 0x27da6a0c, 0x3e33eaba, 0x3311a2ec, 0x87624b05, 0xfe6484d6, 0xfa39af51, 0xfa382760, 0x32ff7e25, + 0x7e589647, 0x184da1a7, 0xfcc6eab6, 0x242c7580, 0xbe04140a, 0x40f12a14, 0xd6e0ff95, 0x7dfa70da, 0x348ac38f, + 0x88326443, 0x1f533d9c, 0x09c6b577, 0xbf528310, 0x9f72f0cb, 0xfc3bf53a, 0xc7faf15e, 0xad78ff30, 0x6a57de65, + 0x73e79e4a, 0x6da58a55, 0x4cdb2aee, 0x9f1da4dd, 0xb99c35dd, 0xf3e84923, 0x27bf5582, 0x87e55614, 0x5b4342fa, + 0x81a2ee9a, 0x279c7ed8, 0x3bb35d56, 0x4b793ab9, 0x31e0abbd, 0x8150ecd9, 0x074cf557, 0xefa7b273, 0xce7edeb4, + 0xb80ac5a4, 0x8742e571, 0x00ca4a44, 0x5bf404d5, 0x34b48068, 0xb3b6482e, 0xb3615fbc, 0x54bcbbad, 0xe8317f68, + 0x3d37ae19, 0xbbb5ef15, 0x14e56e1a, 0x36f7e5f0, 0x50196fa8, 0x4cb0c1e7, 0x558f2f53, 0x2d99d356, 0xe7f91d2a, + 0x7f10e62a, 0x6f789d8a, 0x059119ea, 0x4fa47db0, 0xe55aae5b, 0x87df05a2, 0x470c31e2, 0xe4be9fd0, 0x98d3af34, + 0xf87f2c4d, 0xe21b870e, 0xaac256f9, 0xd4942ce9, 0xdf75db7b, 0x4da99d4e, 0x5d5e8caa, 0x1815c321, 0xf532b7e1, + 0x8ac8c519, 0x172fb46b, 0x51bdd729, 0x7f5c5666, 0xf0568f08, 0xb9220cbc, 0x37c47c49, 0xadf45de9, 0x6f478373, + 0x393525d0, 0x75670ac6, 0x18cd6a2b, 0xdf484896, 0x9dfea794, 0x0197fab7, 0x8896caa6, 0x7c180cbf, 0x4a9231f0, + 0x1806593e, 0xc8577687, 0xc931a91c, 0xc5bcf17a, 0x86e0c8e9, 0xbdc8bc0a, 0xf90daeaa, 0xb9771186, 0xdb18df95, + 0x2263406c, 0xd6a40240, 0xc4a766a7, 0xaf3e6ced, 0xc07b8aaf, 0x9e8a8a00, 0x9cb1af5b, 0xfa83cb6c, 0xb8b70921, + 0xbc556b97, 0x98d47237, 0xd0151742, 0x532de176, 0x0d8ab3a5, 0x7c645832, 0x0c9d2438, 0x51aac2a3, 0xb7093cf2, + 0x8322553d, 0x0f8d293b, 0xe453c557, 0x6756cbe9, 0x30ca7887, 0xe6b9181e, 0x476e5cda, 0x5d088d04, 0x7d03623a, + 0xaec97a6e, 0x6c7bb61f, 0xcef5bdce, 0xe57392ac, 0x018772b8, 0x3ddfc0e5, 0xe29efac4, 0xc173e4b2, 0x7a259e63, + 0xa90de5ee, 0x0b8014b4, 0x96f37b48, 0xd68eb882, 0x622d8bdb, 0xc6635b34, 0x2d50ba66, 0x82e0f42d, 0x2d8b4e4a, + 0xfe696eb2, 0x668c70c9, 0xf3c3a50a, 0xe73d0ce0, 0x9c50494a, 0xe87b6fb7, 0x3dc36f1d, 0x39a8afda, 0x250700ac, + 0x3e1997b7, 0xc140b2e4, 0x983364ef, 0xd8746178, 0xa5e88f19, 0x29c8913c, 0x4557632a, 0x1704f801, 0x661e45a1, + 0xedb87c7e, 0x4ce042f8, 0xbf430cbc, 0x8036c5e7, 0xc28c0255, 0x2d1b0591, 0x0c8b1dd7, 0x3a885e7f, 0xca72cedb, + 0xed7fb424, 0x19ee3258, 0xdcad10c6, 0x42681426, 0x9ebac4f8, 0x900b25e3, 0x5f96c1fb, 0x7fc3a258, 0x06bea725, + 0x01f7a335, 0xc57dd0a7, 0x128f27fc, 0xd9456151, 0x92ec622b, 0xd0a081af, 0x91dc8b4c, 0xb001e1a3, 0xa7894e81, + 0x651dc59f, 0x1d98e4fc, 0x8f784652, 0xa2ec73e8, 0x663de259, 0xf0d46e6d, 0x2225ff2f, 0xdbeb4858, 0x37d91659, + 0x4e4cf983, 0x754bd7c4, 0x93960fe7, 0x15d46b1f, 0xadbc9b42, 0xd54dd7e8, 0xb9464f26, 0x9480e822, 0xae872b0b, + 0x4e8559c1, 0x92a5a727, 0x65ba99d5, 0x9c7f9e77, 0x153182cb, 0x24073d14, 0x8af6c19b, 0x00f6924e, 0x4b513442, + 0x493a150e, 0x2802570f, 0x839b250c, 0x58fb0e48, 0xccd2dc40, 0xe2388577, 0x2119724b, 0xaeb5a9f1, 0x246d31b1, + 0x4f6caa5c, 0xb013f224, 0xb2b1c5eb, 0x01e40f29, 0x8816942b, 0xeac118e0, 0x4afefd00, 0xb4a27aa0, 0xe736ab27, + 0xf74eb052, 0x06d2824f, 0xfc08e7ed, 0xcf5ad14e, 0x459e163a, 0xa0f4dc15, 0x0fc515e1, 0x3c84ca32, 0x7cb02fac, + 0x026e00d6, 0x36565618, 0xaef580aa, 0xfa125402, 0x77cece78, 0x9d8fa9ad, 0x27d42733, 0xd0b84b15, 0x1226b29b, + 0xef53eaa5, 0x14f13e5a, 0xb6d23b32, 0xa88c085d, 0x120c6095, 0xd8c4c61b, 0xdfe0e568, 0xb47da2bf, 0x3d15d546, + 0x5053bb29, 0x4649ceb8, 0x3b8eeca1, 0x237a391c, 0x1d0e34d0, 0x9cee3342, 0xc1f05fe5, 0xf6268972, 0xa11e9414, + 0x0c0dee06, 0xa47af830, 0xf3845d2a, 0x82a9b49b, 0x52bd5342, 0x8cc72985, 0x9cbb1ffb, 0xab63aa1c, 0xeb73bf9c, + 0x16a36866, 0x9d5e7a9c, 0x4aa122a0, 0x38c8042d, 0x9e92f252, 0xcbc31ce7, 0xaaf789f0, 0x5607feeb, 0x7b5e8fe8, + 0xf518d503, 0xf1080875, 0xbd7ba660, 0xcba936ce, 0x83bcff42, 0x74ba5863, 0xa0f398e9, 0xd2329891, 0xe4e2451e, + 0x9b80a1ff, 0xb2902a64, 0x8465bda2, 0x7291818f, 0xf652006e, 0x12645814, 0xc11aa27c, 0x8630f85c, 0x9f32daf4, + 0xd35092d8, 0xc9a654e1, 0x46791b45, 0x3ac9bad0, 0x56e801e4, 0xafeba822, 0xf1941bea, 0x1775757e, 0x76b50218, + 0xdcf37528, 0x7511e94f, 0xb928ba39, 0xd0538a8d, 0x6038075a, 0xca78b8a1, 0xeb50c241, 0xee7ad324, 0xa25941d7, + 0x7629eb8b, 0xf19616bf, 0x6c74d374, 0x3098c25b, 0x84447ffe, 0xa249eff1, 0xd8f678f2, 0xe72cedf8, 0xec20578a, + 0x78d604ee, 0x970519d9, 0x585b90f7, 0xa0bad3d1, 0x4e262822, 0x5e8aa018, 0x559f3221, 0x67ad7629, 0x94234a78, + 0xf9b3996d, 0x9cdbdbf1, 0x70d14650, 0x86e978fd, 0xf173dffd, 0x831d70a3, 0xb5c875bf, 0xc9ee8747, 0xf7878e21, + 0xadd6d1df, 0xb66b8c1f, 0x40460ef1, 0x709de90c, 0x5b48d918, 0xda4cea0a, 0x16f3628f, 0xe0464f4a, 0xa45f2d84, + 0xbeb11747, 0x4d986c40, 0x0e49a3a1, 0x41d0a823, 0x434cbf2c, 0x33978124, 0xb3bb26f7, 0xa91538d2, 0xc78850ab, + 0x41ce2f7b, 0x38511425, 0xf8ac10e4, 0x31f2bae4, 0x5d0b0a1b, 0x832f1ee2, 0xb330eed1, 0x7ae3f6ac, 0xed93f633, + 0xe9a2bf5d, 0xe6ead42c, 0x4a613652, 0x25c2ffd7, 0x539d544e, 0x5215420f, 0x6fd2b32c, 0x3a09731e, 0xee8dd956, + 0xce2f8c83, 0xbb6aeb78, 0xf3162a15, 0x09e25d35, 0xef196c79, 0x3e26e582, 0x0a5da40a, 0x25ccd6d7, 0x2681cb43, + 0xee565886, 0x6adb4ef5, 0xa8793f99, 0xd2a13992, 0x86e20ef8, 0xeb9b3a3c, 0xc63c8d10, 0x01d792df, 0x4dfa0522, + 0x153558d7, 0x32439dee, 0x5c48502f, 0x10128cb5, 0xa110cc03, 0xbdaf2417, 0xbaa09b2d, 0x6a90504d, 0xa3e4e104, + 0xd0c0992a, 0x7ffb4700, 0xc6f5f356, 0x984a166b, 0x5b064b8a, 0x1f222e47, 0x84d8e7bd, 0x8d0efee8, 0x45d4929e, + 0xe1c6d364, 0x39c32719, 0x21c70a80, 0x39948c3e, 0xe1e35737, 0xef26b1a1, 0x8f6088ad, 0x75b9f5c1, 0x14c4cbf9, + 0x5b2c4bf3, 0x0da4d500, 0x1b82377e, 0x349b10b2, 0x6c5f368d, 0xb5ac3e77, 0x40250272, 0x7741b6ec, 0x30d45295, + 0x0beb614c, 0x62ace2b3, 0xe8ef8fab, 0xd99573f3, 0xce50ef25, 0x6501b9dd, 0x236a38ef, 0x972af9a3, 0x75204890, + 0xeb7192f7, 0xb19a68d8, 0xa6793282, 0x236c17d3, 0x350b07e7, 0xe118a72f, 0x5d284ddb, 0x3e7f00e4, 0x68507c20, + 0x588a39ac, 0x22d6d0be, 0x789914d0, 0x846a22f1, 0x020a5e7b, 0xf25c0c0e, 0x3456bf6a, 0x40fa375e, 0xf39698f7, + 0x83bbd0d6, 0x7227107e, 0xf23286ab, 0xe78d2b71, 0x72ecee89, 0x627768c9, 0xf2c47999, 0xa66fb09c, 0xc1b2cfb2, + 0xfa47649f, 0xea7a0dd8, 0xe9fe1b95, 0x23551c33, 0x845c66d7, 0x05391e3d, 0x5ad9a8b6, 0xb842a875, 0x51a398c8, + 0x84e8d242, 0xa7f55411, 0x6a18cb86, 0x741d90c2, 0x55e111f2, 0x2400175a, 0xa12a8dd9, 0xf40fa63a, 0x8c0b1995, + 0x8f259fb1, 0x76346120, 0x74cbaeeb, 0x92a06cfa, 0x265bab1a, 0xa5ecd441, 0x4adf46d3, 0x1e3baed6, 0xce0dd23d, + 0x85d7ecf7, 0xfc073e79, 0x5efb6444, 0x201de272, 0x31af4131, 0x74755d98, 0xaeba9ca0, 0x23eb9525, 0xfba36a88, + 0x6b2a7e31, 0xb3d7b7aa, 0xc516dc9e, 0x30725240, 0x9e4c400f, 0x14d2c7fb, 0x6ef31f30, 0x980f603f, 0x3e6bc4c2, + 0x5d383546, 0x3da5ac22, 0x0496f201, 0x26455999, 0x75d1c661, 0xa82f8a54, 0xa581fded, 0x6b235360, 0xde009304, + 0x8e200285, 0xba6af626, 0x68f9d51f, 0xf00d7339, 0x226691f8, 0xdbff62e8, 0x68261a99, 0xb643ae41, 0x5da92c2e, + 0xb8819039, 0x543c62ad, 0x801f1d11, 0xb64ef4c9, 0x46259410, 0x8403fe9c, 0x25300e82, 0x91b936e2, 0xf0f5d17b, + 0xd11a66b9, 0x25d42939, 0x5954fce4, 0x3ae0f5da, 0x279c90ce, 0xdc28b97c, 0x670f5258, 0x97d5c683, 0x438b02bf, + 0x4e67fea6, 0xc7ae0781, 0x6f80e0d0, 0xb922d50e, 0x2ce48a03, 0xe945780c, 0x7fcce13d, 0xbd7195ae, 0xf63a94fe, + 0x4c04b526, 0xb9e05ea6, 0x0fff5af8, 0x4c603533, 0x7137261a, 0x181bd23a, 0x874743c5, 0x571d881d, 0xb8ebd7c7, + 0x3d09ff6a, 0x76884ebe, 0x3055d93a, 0xced26f09, 0x6ec3aa53, 0xecfc4760, 0x73b1ad9c, 0x4f4109f1, 0x32471631, + 0x7a2b5465, 0x39394c93, 0x7655711a, 0x6ee8d77f, 0x67b84fdd, 0x00dd48a4, 0x0493c091, 0xe73f90bf, 0x145684e4, + 0xf4b6787a, 0x200696fc, 0x9d3aed0e, 0xaf9b46bb, 0x1f5174f6, 0x78eb4d85, 0xa24e7526, 0xc20d6282, 0x7e70fb2b, + 0x5895a59b, 0x9ecfa1ac, 0xe65c69df, 0xa91fcf43, 0xaf3550d4, 0xc5133b73, 0xf5a3368e, 0xcefa0662, 0xd9874f61, + 0xbacd4bf4, 0x2467e31a, 0x0ee6c02c, 0xe1239dbf, 0xd9d8e752, 0x86274c48, 0xf1b98321, 0x1205b533, 0x446e7095, + 0x43ccc83a, 0x652b2456, 0x5ce93e14, 0x71951708, 0xfb5a717a, 0x2ca97cf5, 0xf641fa04, 0x0a7f3638, 0x3eb4b1e0, + 0x12b62f02, 0xfb8fcc07, 0x99c23c61, 0x2db2ddce, 0x740527e4, 0x7b46084e, 0xe8b0bea8, 0xfafb5571, 0x4b794a1f, + 0x8dad13cd, 0xddd01d4a, 0x94987008, 0x190124ff, 0x75fa0c08, 0x71eb2bd5, 0x7ed68d33, 0xa0fcafdd, 0xf0246618, + 0xd2ebaf0f, 0x5ebf590c, 0x68139d68, 0xa92ead0a, 0x4ef43c1b, 0x05fee298, 0x538ae9c2, 0xd6ee7330, 0xdf619fa9, + 0x6be74278, 0xe67a1c03, 0xdc277125, 0xd715f030, 0x21fab039, 0x3beae9fd, 0x2bc0da8d, 0x41c24e0b, 0xfc46b0cc, + 0x9be30567, 0xd73e177d, 0x3f1d38ae, 0x35f603de, 0x0ef03e8d, 0x4549237b, 0x8170b830, 0x7c90b040, 0x911a0ab1, + 0x6dba2ab0, 0xd005f9dd, 0x0330ba49, 0xe8287f26, 0x011b5609, 0x2c8f2f6b, 0x8bc1b658, 0x7578e524, 0x80640ac7, + 0x2210d99c, 0x914d4dc2, 0x5eeb2ef7, 0x483564f0, 0x5d6617f7, 0x6542581a, 0x8295ff45, 0x42a44a8d, 0x27ef0a44, + 0xc46b7a99, 0xa61a707e, 0x24ab8e6c, 0x7df10a4e, 0xf589ad92, 0x232e61c6, 0x61831a7a, 0x39e09237, 0x105dfdb3, + 0x4d617503, 0x1d7d6af1, 0xc00a73a8, 0x44075e1e, 0x80c52b4c, 0x69a98836, 0x8d612728, 0xe909a524, 0xdd69fd31, + 0xf01e283d, 0x8d53a32b, 0xfa667493, 0x568291f6, 0xd35d0f6f, 0xec672795, 0x345ce5e9, 0x88785d8c, 0x0df4aa22, + 0x7c48d28d, 0x14655a26, 0x111b0583, 0x25ca1ee7, 0x9ce8c6e1, 0x974fd83e, 0xb51b8c67, 0x7ca2ced0, 0xd668f63b, + 0x302e8fd7, 0x75d11f8a, 0x8de97ff0, 0x08a49a00, 0x4d06f156, 0x3c44e728, 0x0d7daeff, 0xfb1290d3, 0xf1b0c151, + 0xad585ced, 0xe42da18d, 0x0a7bf9c9, 0x20b9a4ec, 0xda343c36, 0x4b70b158, 0xbf9c86ee, 0x39752d42, 0x9137d10f, + 0xd0c85fbb, 0x0b1ab928, 0x749fc96f, 0x03e55cda, 0x86e733ac, 0x75b97d20, 0x0c1df70b, 0x70e1475c, 0xc2656f73, + 0x31e127aa, 0xa7e8b63b, 0xd717a5ac, 0xf6111b8e, 0x0f4ba9fc, 0xe250ee2b, 0x3d05233c, 0xba3fe2e2, 0x24b5ae1a, + 0xb17d0878, 0xdd9da82a, 0xd2908175, 0x6c0a9e80, 0x563688bd, 0x3151a6f1, 0x4c3bb2a8, 0x6db301b7, 0xe9dbc87a, + 0xa23c2f3a, 0xbf965fdc, 0x20000354, 0xdcd6415a, 0x09f28574, 0x5eaa6954, 0x820df505, 0x48869ac8, 0x6cf1cf0f, + 0x43394a25, 0xdbdc85f9, 0xe6b80050, 0xaf45c776, 0x27b7d2f7, 0xb68bade0, 0x269c1666, 0x9fd9c7dc, 0x225060f4, + 0x55e1b6d0, 0x1f7e6cb1, 0xfd2887de, 0x22a4dc4d, 0x17b78b33, 0x365be8ee, 0x3c50d3c2, 0x0eaf903f, 0xf337b33c, + 0x93c06b10, 0xdefa9b70, 0xb2632261, 0x6258f14b, 0xb5b10dd2, 0x76309eee, 0x1ddb90ef, 0x6ba8aed8, 0x0fafa7d2, + 0x46ad4053, 0x3a5a8784, 0xe27b73d6, 0xeffed838, 0x4fdc881d, 0xbc71d5df, 0x5320c764, 0xdb1e76a7, 0x1648e57a, + 0x524a8612, 0x9d5d4689, 0x58ff1f27, 0xe15c6906, 0x827a3c72, 0xafce9ae1, 0x1c7801f7, 0xb78b2f8a, 0x12d90f19, + 0x9581b411, 0x4594c3be, 0x1e48a897, 0xaa61d691, 0x4bc72810, 0xe8930f96, 0x30942025, 0x0662231d, 0xd94418ae, + 0xb61ebaca, 0x7feeee57, 0x773a579e, 0xe76b54b5, 0xed21aac8, 0x89bc9ce0, 0x5120d0b6, 0x09bfce58, 0xc3eba043, + 0x2e2e29fc, 0xaeb0031b, 0xbf26699a, 0x68deb940, 0xe40a89b6, 0xb83d0da4, 0xa974c3a4, 0x696cde7d, 0x06415512, + 0x3bfb146f, 0xc0014505, 0x8f4e514c, 0x5d27eb8a, 0x5c7f0437, 0x5fc6991f, 0x07dddc07, 0x65e8f711, 0x29b67acf, + 0xe8f83430, 0xc21dd908, 0xfbba9540, 0xef8086a9, 0x97c2fe89, 0x6527d5be, 0x22fe21a7, 0x6c53f922, 0xbd3fba05, + 0xe9ca86b8, 0xbfe9dcde, 0xb7c74416, 0x395f2100, 0xfc93821d, 0x386afbac, 0x2bf0749d, 0x96861ca1, 0x89c61396, + 0x0797bbeb, 0xf00da51a, 0x40e56cb6, 0xf35ecf7d, 0xec3e157a, 0xc5e732af, 0x8fafb3b0, 0x4b70f388, 0x1fc57be0, + 0xa2a6b40b, 0xdb32a95a, 0xacafa5fb, 0xd14a5d4e, 0x6078e940, 0x8597bc29, 0xde3a2915, 0x7d1bdb0c, 0x4fff29bd, + 0x556e8d58, 0x7f87beda, 0xf402413a, 0x92ac2a37, 0xa8b13f88, 0xec5a6b36, 0x8703bba2, 0x751dba1b, 0xf71c506e, + 0x3ada4177, 0x4123c8df, 0x3b8726a7, 0xa1b53886, 0x25549b3f, 0x5e070e0c, 0x55519582, 0x642b68e6, 0x425b8a33, + 0x5cbf695f, 0x38603b66, 0xba63ee69, 0xa1df3d5c, 0x47cc9df4, 0xe1013d4d, 0xc58798b9, 0xe772070b, 0x23ed383f, + 0x1cc9ecef, 0x247e5802, 0xda79ef7a, 0x3f332b76, 0x4d8982a8, 0xcff86f04, 0x00974f16, 0xad633aaf, 0x7014a050, + 0xd7b00968, 0xe8365752, 0xda312352, 0x0171ecbb, 0xd8858575, 0x449a27b2, 0x6b65fe41, 0x1a0267bc, 0xe3b8dfa5, + 0xb7d0f47f, 0x94ae5ecd, 0x566d7ae4, 0x81859b64, 0x9156dcec, 0xf856c617, 0xc2e298d8, 0x9f4f829a, 0x975ff6e5, + 0x79245b8c, 0x53e6c021, 0xde7413f6, 0x4928f24b, 0xd3e3fee8, 0x068f1ec6, 0x5861d398, 0xf4c9fedc, 0xbdac9a00, + 0xd603bf61, 0x3f3794da, 0x56d25d04, 0x4c744b58, 0xd3b27c6d, 0xf292ea56, 0x2b654177, 0x8329bc49, 0xe197e65d, + 0xc02c05f2, 0x529343b1, 0x79204b52, 0xb978a2c7, 0xd34f2374, 0xb2aaf0a7, 0xc1ae9381, 0x67bb5dc9, 0xe5f149c9, + 0x3843abfe, 0x8d59959e, 0x3a79b069, 0xcf8d3d22, 0xab470d01, 0xa2e0eed4, 0x9abc60c3, 0xacd31e74, 0x31b5edac, + 0x6e29501f, 0x741af80b, 0x1a450e64, 0xcee70ff6, 0xf9dee644, 0x3474bbfe, 0x87f51a52, 0x13d01d96, 0x23b7afd4, + 0xb527682d, 0xd9e28079, 0xccbf8a80, 0xcfe5a918, 0xb5b4585f, 0xbd32cc8b, 0xa3eaf7b8, 0xee61d862, 0xce751797, + 0xe74d8f01, 0x6992b3b2, 0x3ce73819, 0xcdc3b495, 0x0a7c2f28, 0x688d73aa, 0xbc8544c7, 0xfe3f95e9, 0x6408abd2, + 0x4c2ec5d5, 0x2f8b8e8f, 0x498435ae, 0xf0285962, 0x97b40bb8, 0xfd137823, 0xfa1cb331, 0xe90eef0b, 0x8d67611e, + 0x170de073, 0x37d74ff6, 0x2e4f2097, 0x8f0bd03d, 0x5fad50ac, 0x510bb216, 0x9ebb64d1, 0xee490366, 0x480723a7, + 0xa7fb3e09, 0x7ba311b1, 0x833243ee, 0x549459ac, 0x542a58b3, 0xf3a7c187, 0x26538ee5, 0x619e5198, 0x7f450ed6, + 0xe39e4051, 0x928cd4fa, 0xb74b31da, 0x1bb6ea1c, 0xd1f0f43b, 0x1bee4426, 0x6c655a67, 0x92d45e19, 0xa3996b88, + 0x8f703f2e, 0x1d3e8822, 0xe8ee8397, 0x070a8f21, 0xe7a17e8c, 0xb1d36625, 0x3c3adab7, 0x81e4a01f, 0x01e1f840, + 0xb4c65818, 0x8f6594e0, 0xe0eb2dfc, 0x0d806ba3, 0x18f2ddfa, 0xd57f2e18, 0x28925c56, 0x895a2684, 0x7171c1a3, + 0x7c017847, 0xd81dca0d, 0x572b7def, 0x8d9b482c, 0xf93dc40b, 0x5d6d7cd3, 0xc33b13e4, 0x75e52990, 0xdf097592, + 0x3528ac97, 0x06827951, 0xd25fa174, 0x80fb481b, 0x6b59e6de, 0xe04b625a, 0xd27e0ecd, 0x063cac89, 0xd0d489cb, + 0xa8b00d0e, 0x485320de, 0x60c970b8, 0xa1619184, 0xfec47395, 0xd94b0477, 0xc68d2c91, 0x6394d423, 0x6574ecb4, + 0x4b2b3554, 0x77172117, 0xcd241be7, 0x587c09d0, 0x3ce924f2, 0xce6f39c7, 0xe941bf35, 0xb5de7da8, 0x62a58932, + 0xfa64fbd7, 0xdd3d332c, 0x92d5ae77, 0xd7a69d02, 0x437c2a74, 0x923214e9, 0x532faee1, 0x7691df25, 0x06dd979c, + 0x74d713a7, 0xb3834394, 0xdd59f775, 0x9b09d98b, 0x8faf9e34, 0xa9e6748b, 0xc48fcb7d, 0x145c2d71, 0x7bfdff11, + 0x874585f1, 0x5afe72b5, 0x457f8668, 0x63c70d97, 0x69ecb214, 0x0c3d86d8, 0x9c212af1, 0x0dc90657, 0x6f266c37, + 0x338603e4, 0x9be328e3, 0xf44e6576, 0xdbfde08a, 0xcccc9949, 0x94e79fab, 0x85d487b7, 0x50876607, 0x4f7c8966, + 0xfb44f52c, 0x57e7ea9a, 0x31c8b849, 0x775c1558, 0x2fd83577, 0x33bf199e, 0x8951fbf8, 0x06f919a8, 0x14a87e04, + 0x60053ace, 0x26839ffd, 0xc30ee679, 0x1437de4b, 0xf948d299, 0x6a384a9f, 0x5740db3f, 0x00bb5ad1, 0x1fd4c66c, + 0xa30f5508, 0xb82884a9, 0x8eed93f1, 0xa0a987fc, 0xe2e0356f, 0x813b5df3, 0x480bb2f6, 0x1af803a0, 0x86d6b60a, + 0xee6e142b, 0xaa0eeaec, 0x878a7a17, 0x9a0b550a, 0x270b18f8, 0x2fbb06d4, 0x976f1162, 0xbb59d2e9, 0xa1557a33, + 0x9a0e32e0, 0xc328423a, 0x588d5c30, 0x153d1c49, 0x855ff17c, 0x4bc0b8c1, 0xc1558908, 0x25fcca55, 0x7d55af3f, + 0x1367c20c, 0xd520b65b, 0xb9fcf6e5, 0x2de49e66, 0xb4a350f0, 0x5a03d319, 0xd821ec93, 0x2f25d284, 0x3c439979, + 0x60fd9c4e, 0x9eb19bd3, 0xf5c0f98f, 0x4ff6cefa, 0x6feb2fc1, 0xe2495cb6, 0x07dcce25, 0x55c0a0b7, 0x10ee7886, + 0xf8242dea, 0x8259b61f, 0xd567e30e, 0xa88cb906, 0x3e0d1f0c, 0x0be823d0, 0xbbdd1512, 0x5dc48810, 0xd35ef416, + 0x88c65c2b, 0x1c5e867d, 0x60cfc552, 0xe52cc3db, 0x6c6422ab, 0x62b713f8, 0x14c67697, 0x6359f40c, 0x42a608b9, + 0x4038f476, 0xe6212786, 0xd966ca0e, 0x339a1aad, 0xa7defae5, 0x93611903, 0x2f3a25a4, 0xa1f04619, 0x12915d6b, + 0x492d47fd, 0xbdd4da9a, 0x1d5aa494, 0xa66cdbda, 0x411e3dca, 0x59882596, 0x6970b35d, 0x102a6431, 0xcc1cb3c0, + 0x53ec36ec, 0xe3600f88, 0x48d7ec95, 0x616ba15c, 0xcd979a3b, 0x445495e1, 0xf6d2f38a, 0xb1ae1825, 0x4812ecb4, + 0x02123951, 0x5dbc2bf9, 0x4c86c29c, 0xb07f1eef, 0x16629f4f, 0x118f0eea, 0xdbe879d9, 0x1fc309b9, 0x0e20710e, + 0x9acb763d, 0xe41bef0d, 0x61f1abdd, 0xa6c8fccc, 0xde899858, 0x13682609, 0x23e38cbd, 0x9425cfbe, 0xda7220f6, + 0xd2180a8a, 0xec2978a6, 0x7e835e45, 0xa8fea4e8, 0xecc1d47d, 0x3c9e4172, 0x78501ae7, 0xf8841e9b, 0x0e24d5e1, + 0x3bd2d100, 0x2dfba736, 0xfc05c8fc, 0x75abd882, 0xf34a00bf, 0x58829253, 0xff034a51, 0xe7fea730, 0xd82f1962, + 0xf473ba99, 0x0baed8c2, 0xbe2f38d0, 0x7825250e, 0xf59043c5, 0xdcc5091e, 0xa208b73e, 0xf96b051b, 0x27086407, + 0x6430f606, 0x5b47bea1, 0x0d4368cf, 0x6658a3e6, 0x9c808716, 0x467b025f, 0xa3f012f2, 0x14fa2d89, 0x0b9d75e3, + 0xcb226d68, 0x93930cd8, 0xf2a8a3f1, 0x14b64013, 0xee34c86e, 0x3adbc02d, 0x8b413bb9, 0x11d8bfe7, 0x8c20b2b4, + 0xd70554c9, 0xcab6b02b, 0xf96a1991, 0x1d19f1ea, 0x6b0b586d, 0xf3cb3e98, 0x76897c36, 0x4a8d2102, 0xd820ce5c, + 0x009db5b1, 0xda6e6d6e, 0xb660a642, 0xab625265, 0x086bfc5d, 0x947b1f20, 0x204747ed, 0xb6c89474, 0x119a0b03, + 0x9e0d7c66, 0xcee0a799, 0x822332d3, 0x0f850541, 0x9d50690e, 0xbc97d82c, 0x83965be6, 0x57003ee8, 0xf5c7aca3, + 0x670cdb2a, 0x4ca447e5, 0x80990735, 0x982555a0, 0x34fe39ad, 0x5df9f750, 0xe58e4b86, 0xf6454ef0, 0x65fad983, + 0x5f346ac1, 0xbca8bba9, 0x2c35351b, 0x37762cd1, 0x4178e80a, 0x00a7a4f4, 0x25ddd9ef, 0x9296178c, 0xf46049dc, + 0x36f86075, 0x941ee9f5, 0x8bc038ad, 0x5967d15c, 0xd6f93081, 0xf3d0f1ed, 0x073af303, 0x484540e8, 0x7ea8bf59, + 0x60572fff, 0x452df6f1, 0x410bc38a, 0x7ea6b239, 0xc68b3fe2, 0x58754a23, 0xd1435f99, 0x82a045b9, 0x79991a43, + 0x7500b008, 0xf1d8deb3, 0x85af8d13, 0xa759f4d0, 0x19a5fb91, 0xb50e6c67, 0x6eda6337, 0xd3695116, 0xc49f94db, + 0xea2e5b96, 0x10c662f3, 0xaca652a7, 0xfce243b4, 0x14e87d09, 0xce961ef5, 0xee2c3ebd, 0xaf46e4e5, 0x0a775715, + 0xf404a735, 0xbb72289e, 0xbc4b04dc, 0x2a8a7346, 0x1442e566, 0x36bc7fcb, 0x596c15dd, 0x81ac9f1c, 0xf05af261, + 0x4b665193, 0x28ba4ec6, 0x19a22fd3, 0x91e2126c, 0x0b264821, 0x182a5377, 0xd6808382, 0x07801f3b, 0x80c64295, + 0x5f6729b2, 0xb2ce9a0b, 0x94258f46, 0xd6599548, 0x99fdaa34, 0x59d25e3b, 0x81bcdce1, 0xc7938bf8, 0xe9078d7e, + 0xa89f4d0f, 0x9ca325b0, 0xde1174a0, 0x4e63592e, 0x41a60b02, 0xa69cee9f, 0xa2b07bac, 0x80e8f163, 0xa58cbb54, + 0xa077b9b3, 0xd98a6c05, 0x51dd3eb9, 0xd5ef41d9, 0xbefc6163, 0xdd587f3c, 0xeb4fc3c5, 0x47203eff, 0x9b563452, + 0x690786ad, 0x99500d96, 0x70b1414e, 0xf7f2531f, 0x3c87b2eb, 0xff631215, 0xccb4ff7c, 0x36c633d7, 0x12d7a33c, + 0xa5813768, 0x9a411c9f, 0x50a0e2d8, 0xe2dbf275, 0xc7d07007, 0xfdaae6d7, 0x6acab6f3, 0x51ba9e10, 0x2971852d, + 0xe7c937c8, 0xb85b6ea9, 0x00c4260c, 0x2c7fe806, 0x72574f4a, 0xb2ae02b0, 0xdf7320c0, 0xe6010446, 0xc5e2bbb1, + 0x2b86a641, 0xf55d8421, 0x8407ae11, 0x08e825a1, 0xbaf62807, 0x498542cf, 0x0fa33d91, 0x554621f7, 0x90696038, + 0x130cc826, 0x9868a42f, 0xf9673ce2, 0xb271d6ea, 0xa9b87ec8, 0xb9478be7, 0x2ff2210f, 0x753a431b, 0x89d48d13, + 0x6c6e26c1, 0x2c67ad8b, 0x2daa8af5, 0xbd05b6ad, 0x31835a88, 0xba1a7a26, 0x5269d7a8, 0xb79d9693, 0x00645a24, + 0xccbc072c, 0xdd560dd3, 0xacbc0578, 0x999f82d8, 0x4b736b73, 0xefba5361, 0xb2331359, 0xbf0411cd, 0xa1225b58, + 0x8e1220b0, 0x5a8a1088, 0x0691e582, 0xbaac91f0, 0x420c1a61, 0x07c4be04, 0x88f43339, 0x07d9fad2, 0x465642fb, + 0x72fbfd16, 0x831f6e89, 0xd5f7905f, 0xfbc8c546, 0x7a20a4c4, 0xada45c4c, 0xa391ad55, 0x15a30e03, 0x84884a9d, + 0x382e9296, 0x69efac85, 0xd5fe649c, 0x95db092a, 0x349baa02, 0x1a816ae9, 0x86e7fb8b, 0x6bf62550, 0x7278d817, + 0xfbd2e006, 0x1bb9f37a, 0x2ffa75a2, 0x82961e8e, 0xf703edc5, 0xd0a1ab82, 0x2bbc2b9e, 0xeca55edc, 0xe77fc921, + 0x0515c51b, 0xe26f3d2b, 0xe829749f, 0x16532997, 0x9f77b9df, 0xa74ff517, 0xdb410a52, 0x958a2acc, 0x0ea35a02, + 0xad234d41, 0xd5dfb7e7, 0x4d3e3adc, 0x837bdee7, 0x0b5e914e, 0x40242b79, 0x0747d6f8, 0xda1c720f, 0x31528d89, + 0x339a5da8, 0xe293f9ee, 0x7520a3de, 0xb92a2793, 0xf440e642, 0xcd50d663, 0x2f4014d9, 0x9ce5342b, 0x57ef872b, + 0x27f14b5b, 0xf224876f, 0x2caef6c7, 0xc08f0a67, 0xa0790774, 0x2c21f290, 0xceacd200, 0xd7001c4f, 0x6763c92e, + 0x7c11bb0d, 0x9e3040c0, 0x3de340a9, 0x3b2b3ead, 0x54213aaf, 0xd3f8360d, 0x3d1a6cf8, 0xe55ef581, 0x91a31da7, + 0x21b5eac2, 0x3c311f38, 0xaefb36c9, 0x30fcf760, 0x1ea7a8ff, 0xb559e526, 0x4925e695, 0x7a524da5, 0x9a704958, + 0x41e01bb3, 0xe1f5330b, 0x031023ce, 0x6246fc98, 0x94b008d4, 0x3d4ce399, 0x3d843e39, 0x4a8a6902, 0xd840d56d, + 0x4d0ea9a5, 0xba576401, 0x066dda98, 0xf6ea0835, 0xb3527fdb, 0x6a9e008b, 0x5a02dda1, 0x2f94f184, 0x7e1dccf5, + 0x2708602f, 0xccbf1baf, 0xfd09d1ac, 0xf93600f0, 0x40788da1, 0x7c419135, 0xbb44cc8a, 0x2d10e59a, 0x96321270, + 0x79a59ca1, 0x6fd353f3, 0x56217c67, 0xa2ca8710, 0xe5117ab6, 0xf8d35409, 0xde3e01e0, 0x054b01d6, 0xd175ddc1, + 0x75c8739a, 0xcc96005b, 0x840a9da2, 0x16df62c5, 0xd2816d28, 0x1746325a, 0xf163eff1, 0x85c9318c, 0x6f2b3dca, + 0xbbdb5886, 0x0e78afa1, 0xf42440f0, 0xef820889, 0x0c08a96a, 0xda4f1d97, 0x382ecc95, 0xd54350e3, 0xd0d35be0, + 0x228553fa, 0x46bee872, 0x3a6f1faa, 0xb607f43c, 0x69d771a8, 0xa512dc41, 0x9cbfd903, 0xa60c33e5, 0x6ff72a8f, + 0x58bcf217, 0xd0c041fa, 0x633a38c8, 0x4d320764, 0x9f3a7b4b, 0x6212d707, 0xbed81dc9, 0xc5db1a59, 0xe2de9f77, + 0xfd5bc36e, 0x8f0efcd5, 0xab8406f3, 0x4327007d, 0x3b2c6171, 0x86eec43a, 0xfd11fc8c, 0x0a40d8f1, 0x85776fac, + 0xbd31c15d, 0xf9104f77, 0xcfb00649, 0x31c68218, 0x4a2c9861, 0x46a27618, 0x4cc7ce7a, 0x2be0a911, 0x43a8ca5c, + 0x9a6fe784, 0x86f470ce, 0xd2643026, 0x4e1927fb, 0x52ac2b86, 0xe7640653, 0xc866089e, 0x9195f606, 0x5786a4f5, + 0x89f09b99, 0x9533ae0c, 0x3f678a78, 0xfef34c6a, 0xb62edf9c, 0x857f61f7, 0x032bf0d7, 0x572b4844, 0xcd5d9cb3, + 0xfdeed2ea, 0xbb409b67, 0x9a7f9a1f, 0xd1419e6e, 0x64f1802d, 0x3de2b52a, 0xa6ca150c, 0x782e8f47, 0xbe33bfb0, + 0x25f08daf, 0x37315e9c, 0x02a42546, 0x68854042, 0xcf5e390d, 0x5ad0b9d2, 0x0b45ada3, 0x957aea6f, 0xf4459f36, + 0xb7abcf45, 0xc695d94e, 0xdb8e0b70, 0x67a4f9a4, 0x9b79993c, 0x44c66493, 0x68f10487, 0xf3590c8c, 0x072e9b91, + 0x396d0af1, 0x2b40b5e2, 0xd5e90664, 0xa6ddbacf, 0x0ada5427, 0x6c4bea3f, 0xc39d8957, 0x3faba31f, 0x4b7bc5f4, + 0x4bdde7d8, 0x43c53101, 0x33bab3e3, 0xc2b0cdb7, 0x802f469d, 0xab4f5abc, 0x43d7e905, 0x548bb409, 0x7325dd47, + 0x5df208ef, 0xcab935f9, 0x76ce85fa, 0x9dba7a9f, 0x75e02841, 0xd4b160af, 0x95b1b651, 0xa7358c1b, 0x444a2453, + 0x340eec9f, 0xfe788d10, 0x9ee65b03, 0x8f5be0d5, 0x415a7f26, 0x72417966, 0x78cdd8ff, 0x2455c94d, 0x30227666, + 0xd3c233d6, 0x0c96a614, 0x31335d76, 0xf4a0c0af, 0x3e51feb5, 0x2f806b30, 0x5e68366e, 0x62b427cd, 0xb1e23d3d, + 0x553eccba, 0x31f4b9e1, 0x466d1671, 0x1a4fefe1, 0xfd2dd175, 0x0527ada8, 0x02c9a956, 0xa1bc72f9, 0xacd50263, + 0x26928618, 0x13601d83, 0xaeb27ff8, 0xdddc2131, 0x1b8a682d, 0xbd7760b2, 0x56e87330, 0x826324fd, 0x84cd7b48, + 0x68a66ecd, 0x6cf22573, 0xad5f7731, 0xa6710c15, 0x33d65697, 0x66e0cb83, 0xf8c2002f, 0xf37adcfb, 0xffd0bc4e, + 0x6c232463, 0xaa72c8ea, 0x5f8a01fd, 0x9a4a153c, 0x76d53f6a, 0xa77aece4, 0xc010f7b5, 0x7f2f19f2, 0xd5b9158f, + 0x9c1a6770, 0x0aad14f4, 0x1728d59d, 0x24528d90, 0xca6a2536, 0x794039e9, 0x1827b8c2, 0x3f7c1341, 0x66599b22, + 0xcc59d186, 0x6e4d0ac9, 0xa4065fa7, 0x8f859dc7, 0x41509651, 0xa5628f0a, 0xa132cd5c, 0x0d3b8bca, 0x1e343824, + 0x6eb2e391, 0xd708fda6, 0x218a7534, 0x008e4416, 0x75d263bd, 0x8519a7fe, 0x5ee76499, 0x940984f6, 0xb5fcba80, + 0xbf2150a0, 0x5e302f91, 0x89750cc0, 0x4df178e4, 0x5a09fd46, 0x1f78433c, 0xe2829982, 0xd7ef1428, 0xefb49fa9, + 0x3e7b4790, 0xe19e8782, 0xbb44dd91, 0x87417bd4, 0x82b51689, 0xec204b3b, 0xcd9660aa, 0xc1d3f048, 0xd08c2b1a, + 0x86b07d0d, 0x255cce38, 0xbe4d6e84, 0x3d09efae, 0xa453bf7b, 0xf71c96fa, 0xe48cd344, 0x2944c914, 0x1a85af8a, + 0xe86219c3, 0xab0f577a, 0xdc08b77e, 0xccf16fda, 0x39e39ace, 0x9c56184b, 0xe3ed1fef, 0xabf26276, 0xd48ae342, + 0x10a94271, 0xa1a4de39, 0x30841804, 0x101b66fd, 0xd7ea5fea, 0x145c6072, 0xee4483a3, 0xe0b5bfa2, 0xabf71b03, + 0xe891b484, 0x21fb00f3, 0x7d4398ca, 0x68fd1b77, 0x0a5b62fe, 0xa91a1a6b, 0x0125a35e, 0xfa1c4770, 0x7b5abc45, + 0x6e18bb57, 0xdc039b7b, 0xa6f9bf29, 0x2e9d6ba8, 0xb3220d81, 0xb1938bdd, 0x3d29cc7e, 0xac4b6693, 0xacfd8113, + 0xb3c06e46, 0x27d49846, 0xcab402b4, 0x5fb2401e, 0xc25747f9, 0x02fda164, 0xb07d61a0, 0x8bbf5eac, 0x9b29fd5d, + 0xfa365775, 0x55b036a5, 0xf155774c, 0x4da40129, 0x7d191732, 0xade2779b, 0x7c5580d8, 0x4a1492c4, 0x87ef210a, + 0x43b3af48, 0xbfe0e040, 0x0918b164, 0xf4c17ab6, 0xc2e18ff3, 0x84a7c783, 0xe6bf78ad, 0x37cf5431, 0x2c4969bd, + 0x8553e1c0, 0xae0cf1dd, 0x9897f8ed, 0xd5b003fe, 0x0463dfec, 0x55e8bd2d, 0xb844bbe2, 0xa7b3389e, 0x978af6e0, + 0xda5a6b43, 0x1e958cf1, 0x8578e7c7, 0xa7c81c48, 0x878a2f37, 0xebde982e, 0x2a9166c0, 0x6be7f966, 0x7970d0a6, + 0xb13d76b8, 0x6e984a6e, 0xb76a60b8, 0x2fb7eecc, 0x28602f3c, 0x698a962d, 0x76f70015, 0xa6fb5361, 0xf3874e1c, + 0x26ffe88f, 0xff42a74c, 0x85caa558, 0xeec6cb84, 0x75b5dd00, 0xf11c77ea, 0xd9ac3f72, 0x164a3d92, 0xf9687320, + 0x40b75874, 0xf6461894, 0x74cff2fd, 0xe142a3f8, 0x2ab59427, 0x26b9c91a, 0x14d043e0, 0x052492e2, 0xf72f06a4, + 0x493bc538, 0x47335b89, 0x282d4e0d, 0xaada03a2, 0x150f9f5f, 0x99ff52e6, 0xb0f9b846, 0x0e2b14bb, 0x9ceb8c97, + 0x7bf34c36, 0x81ab9c33, 0xd8dc8010, 0x32b05507, 0x3f61af4e, 0xc617b9ca, 0x773e7fda, 0xed841390, 0x19a34c50, + 0x0d8cfc59, 0x57396afa, 0x0b803ae0, 0xb2c67a28, 0xa1aa5e40, 0xc9118168, 0x9fc61c38, 0x80cfa25a, 0x319ab25a, + 0x56b29919, 0x48c2812c, 0x72b5cf14, 0x86bfde59, 0xdec3227d, 0xdd4f88c5, 0x2aba4047, 0x57b61026, 0x336fe164, + 0x5d9c4ed3, 0xfcca747e, 0x3e760791, 0xd65fb56c, 0xde0dd767, 0xb1e98abf, 0xfffa573e, 0x6f1bedaa, 0x7c81f00e, + 0x6b59c267, 0xd60764a1, 0x8468ddeb, 0xe3852568, 0x8c9f5eae, 0xa4e2d18d, 0x05fab7cd, 0xeb5de2c2, 0x04e808cc, + 0x7a1ed8b1, 0x73923f8e, 0x93f12451, 0xe08a8932, 0xbc21bfea, 0x5e5dce47, 0x4fcc9497, 0x8d464eb3, 0xef0aaa8c, + 0xb912aaa0, 0xd7fd07d3, 0x1aab6c03, 0xef9eda5e, 0xd2bf4ba7, 0x666d8a54, 0xbba779b5, 0xadc23852, 0x1d7ac839, + 0x64fb0ec1, 0xacd89e7b, 0x51cd9e60, 0x49960146, 0x35f871b8, 0x1c0845a0, 0xa1d02757, 0x1ce42f14, 0x1d328acd, + 0x8b069a1c, 0xc4465b4c, 0xc4485e7e, 0x0a4600c8, 0xaa45d6bd, 0x4abe1ffe, 0xd23907f4, 0x8cdd6860, 0xa2fa99d1, + 0x23e1f9c9, 0x64334aad, 0x770eef86, 0xfd9e2d4a, 0x5d528ffb, 0x765e737c, 0xd9585cec, 0x3c47427e, 0x7a61b390, + 0x9196dff4, 0x4370b66a, 0xe077f2c4, 0x5361761f, 0x80d50ac0, 0x1ae26d21, 0x8408d316, 0x182e6491, 0x091bded6, + 0xee7bbc0b, 0x0fda5da6, 0xbd1ba459, 0xc70ee683, 0xd1f8d081, 0xe15cf166, 0x57272a35, 0x61acea69, 0xba9d4d9d, + 0xb3d90928, 0x9fe572ec, 0x39ec00bc, 0x72d29afa, 0xcbdfffb7, 0x9f4a8c9e, 0x8228d6c7, 0x9811363b, 0xc48cd30f, + 0x360ca503, 0xd8f3676e, 0x6d22606f, 0x64f5e190, 0x68c1e97f, 0xf79eec3d, 0xa1b94651, 0xb0d195fa, 0x43e47759, + 0x94141803, 0xd20298fa, 0xad05e3c1, 0xab89c3ef, 0x596d3533, 0xeaaba38c, 0x4dfd1f8f, 0xf6f43c62, 0x4d9d52b5, + 0x501e5c73, 0xe53a37c3, 0x7fd84c6a, 0x526d4aa6, 0x97d3dbf7, 0xa986dbf7, 0xe80ef28a, 0x2da344ef, 0x1b95ec89, + 0x2aa93ab1, 0x3eab513c, 0x381b27fc, 0x91706e7f, 0x86123846, 0xb6206208, 0xb99da22a, 0x2275b68e, 0x4d359f88, + 0x87070aaa, 0xec78bbda, 0xeb5fff1c, 0x0a51f74f, 0xb823e79f, 0x20e5ac0d, 0x44a2f682, 0xd9177373, 0xc5171050, + 0x7f090683, 0x56bd7cba, 0x8dd9d04b, 0xc83d715e, 0xa6f6f696, 0x82434238, 0xcef030f1, 0xdf41fa87, 0x0567b92c, + 0x54cc23aa, 0x4fb06d82, 0x5404bb0a, 0x1a13051e, 0xa89c8aff, 0xe5d500ac, 0x4304d74a, 0xcb11e37b, 0x4fbae640, + 0x0c858ab3, 0xf19e28c2, 0x2a9bf27f, 0x28809041, 0x38e8eadd, 0x0b0ceb17, 0x97514e6e, 0x27797b85, 0xddf15d5e, + 0x351a82b2, 0x6c2e88f0, 0x85734841, 0x0073f7bb, 0x39aef1c0, 0xa79254d0, 0x32813cdb, 0x61d98c1a, 0xe743a8c9, + 0xc48def4d, 0xb27ab5ef, 0x17f9cadc, 0xf0048122, 0x1e5e18b0, 0xfbdf5a6d, 0xde8f29f9, 0x55f606a0, 0x963f0f15, + 0xbd633b4c, 0x72f097bf, 0xce128485, 0xc1f59e12, 0x1a8d54d3, 0x1d5ff0a4, 0x4517e77f, 0xdf96cb85, 0xb04b9ea1, + 0xdda4782a, 0xcea1f631, 0xf047434a, 0x725bc5a4, 0x66dfd403, 0x7d11b6ff, 0x7155bedc, 0x997f3e7b, 0x51e5909d, + 0x5eee7655, 0x6d773606, 0xc195698f, 0x8e15e454, 0x4615d24c, 0xee16337a, 0x8a25bacb, 0x685473cb, 0x874f77be, + 0x91099801, 0x506e4354, 0xfa425ae3, 0x84c5c94b, 0x8f675995, 0x27e424f8, 0xe021d1f7, 0xed1f77e6, 0x5dda592b, + 0x343137f8, 0x79902929, 0x2e9da7c5, 0xf2082549, 0xfa2d80f4, 0xc3530296, 0xd3771532, 0xe00b6a35, 0x3a1dc9d8, + 0x727ff43d, 0x948907b9, 0x2bc0bcb2, 0xc34a621e, 0x9a3ddc99, 0xdc99a8d8, 0x647dc566, 0xd2a6d2c2, 0x0848d3af, + 0x2985be3d, 0xb14c0d2c, 0xfb69e657, 0xd020f0ae, 0xa825e3ff, 0x3fe6867d, 0x61974fd2, 0x4059460e, 0xde725169, + 0xf1b69939, 0xdf3cc8dc, 0x9d2e10f6, 0x0361ff51, 0x84802d73, 0x43db62a1, 0xa031b219, 0x83ac55a2, 0xd004755c, + 0x5ab0da61, 0x1a671918, 0xd2ea9243, 0xb4fcdc44, 0xd08fc7c5, 0x2a9ce67f, 0xf15aaf8e, 0x146062d0, 0xd39bc854, + 0x51bcad88, 0xb192e458, 0xd248e0d7, 0xe707c658, 0x61c40582, 0x41b132dd, 0xc0558a9f, 0x5b7c824f, 0x376ef725, + 0xa41885bb, 0xe07f824f, 0xf256b9f6, 0xa5730af4, 0x0e7858cb, 0x2829a003, 0xff22125d, 0x58cd8d6c, 0xbd1a8d6e, + 0x0aab8821, 0x57d54881, 0x9ef3180a, 0x6407a41b, 0x602afa35, 0x0bb381fd, 0xc10217d3, 0xdf6a6fd1, 0x7660b282, + 0x6ba289a9, 0x9f3719be, 0xfee7e379, 0xa8914a62, 0x1f291958, 0xf1a395e6, 0x9a10295c, 0xd116b9f4, 0xe1c7cb4b, + 0x7d02247a, 0xd1f97f89, 0x4a03bbfc, 0xd4a2115e, 0x70f95857, 0xa1f74c25, 0x70043dc3, 0x8fe55221, 0xc3980832, + 0x8d4875d9, 0xcf2cc651, 0xa5813308, 0xde482836, 0xd15f209d, 0x7e9644e0, 0x2883839d, 0x780aedd9, 0xfa309e3d, + 0xd29a888d, 0x45099a7c, 0xbe372345, 0x42137438, 0xd6e59680, 0x490f63c8, 0x9710aae6, 0x01ae9be3, 0xb29a1c9f, + 0x13a2d976, 0x2b9bd1a0, 0x0d3c23da, 0x52ee60e9, 0x827959ba, 0x895feb2b, 0x3938ba51, 0xcb147b55, 0xdde71640, + 0x65a7ee9c, 0x727e4eb4, 0x5f1649c7, 0xbd87cb78, 0xe4879283, 0xcd2456ca, 0x0ac0350a, 0x4658c16b, 0x7053d360, + 0xcac648a1, 0x75e125f0, 0x618549a9, 0xefeb9d3f, 0xa4af0bf2, 0x3c399b25, 0x715cad71, 0xc31e08e3, 0xb735bd7f, + 0xe2211087, 0xf2ef34e7, 0x27f5998b, 0x02d40639, 0xe881aec0, 0x1d1f8881, 0x0930af97, 0x2f7da364, 0xbc525f3f, + 0x62c3606c, 0xf65376a1, 0x3d237721, 0xdaa36cbd, 0x84d39f57, 0x26a59503, 0x844d31c9, 0x3c298d83, 0xf4d70f0e, + 0x88a9402c, 0xb1b06259, 0x26c780e8, 0x4309f3f1, 0x35bf5b03, 0x3c2ca8bd, 0x1c277797, 0xd624652f, 0x6c297089, + 0xbba001d8, 0x35b42528, 0xd7f7ea3e, 0xda5527dc, 0xfd1a1478, 0xf26706db, 0xe8b8516c, 0xb6c6d754, 0x3bec7ff4, + 0xfa9b802d, 0x3b4258c4, 0x19ff0be5, 0x3e20cdf6, 0x539a595c, 0x6a5446e4, 0xaf0ece62, 0x6500b243, 0x5f6b8345, + 0x24872ff9, 0x9a1409da, 0x4939430d, 0xfa88cbef, 0x3d53447d, 0xe8c9a5da, 0xfd74f829, 0x5b14473d, 0x301c63dc, + 0x065b9c94, 0x8d237765, 0xe8e24932, 0xee3cbec9, 0x70165e9f, 0xccb8b8f6, 0xbc2058ba, 0xcc1032d8, 0xd7bd1f54, + 0x7cd94be5, 0xaf8b805f, 0x2bc43805, 0x8d2596e8, 0x11555e42, 0xd39e3e0c, 0x0e157235, 0x7be3e97e, 0xb076460f, + 0xcd0a1402, 0xd3588a42, 0x958c7f47, 0x625336aa, 0x821dcc58, 0x961fd6f2, 0xbe692c95, 0xf3d46c61, 0x8d26a0db, + 0x314a3c40, 0x71f6d450, 0x7d98ee53, 0x29feaf4c, 0xc7ba88ca, 0xf6a975d4, 0xeab51d35, 0xf913acc0, 0x64068963, + 0x6da2bb75, 0x9fbd04e6, 0x9f99b572, 0x1d105f1e, 0x85dc0ff4, 0x6679d3fd, 0xf4b3587e, 0x26c714c9, 0x86c4ecc8, + 0xac1b90e7, 0x6e234784, 0xafc3c187, 0x1eae7ea3, 0xbb049963, 0x7a4c3b45, 0x96ae4331, 0x743fbd08, 0x0a416922, + 0xda28df77, 0xf4912308, 0x8c730242, 0xa40199a7, 0x8cc7b0f7, 0xbe073cd5, 0xa247502b, 0x227adf5e, 0xeeb59cfc, + 0x43622f22, 0x76276aae, 0xd9988aef, 0xc10996e4, 0x494d1e05, 0x9c6d70bb, 0x7ca2665d, 0x56daeb19, 0xc646c4b9, + 0x860ebec5, 0xf9309060, 0xfea4bc08, 0xe145396b, 0x79c966b5, 0x251ad69e, 0x1e605e77, 0x9a717f64, 0xe4f65ab0, + 0x5b09c779, 0x8c7c88df, 0xa6d09299, 0x56302273, 0x9947ca58, 0x6acff4e6, 0xe2bd3c4d, 0x31b6db90, 0xe12d3607, + 0xc56a644b, 0x0f4f8a1d, 0x8c8b34db, 0x73bad0e1, 0x6f0a9057, 0x6846723f, 0x8979434a, 0x3df78a9a, 0x4085a82a, + 0x377663a7, 0x0961f8bd, 0xf023d62a, 0xf5146ee4, 0x56bdea59, 0x4f43dcb5, 0xfb78e6a9, 0xeca00f74, 0x93562a18, + 0x1a59bc78, 0x5c4e89c6, 0xa419478d, 0xdaac6da7, 0x7b84febf, 0xb7bb9307, 0xd5ae55b6, 0x1f97b530, 0xfcdbb0a0, + 0xe0b6859a, 0xe4590948, 0x4eafbaca, 0xe1e97716, 0xc2945f10, 0xa5c0f85f, 0x4ac2bb3b, 0x35cc07e0, 0x76c6468b, + 0x9637f2ed, 0x2570dcf8, 0x204386b2, 0xbb15c1ab, 0x84d8a1ac, 0xd367c87d, 0x7e0b30e1, 0x3cb1467b, 0x30ae16ad, + 0x2649f697, 0xd81a8170, 0x65916dba, 0x52c0b3b1, 0xf534b271, 0x5706d177, 0xdb4f850f, 0xf16fa437, 0x3d3a4886, + 0xc5da2774, 0xdbe4a97e, 0x42c60368, 0x4f1e890f, 0xa1d72027, 0xcc128518, 0xaf5628b7, 0x5f6375bd, 0x7ac0678b, + 0x847de4b5, 0x5bb874ee, 0x1cc9b3e3, 0x353f45c6, 0xdd2ac179, 0x80e18c83, 0x00097429, 0x17de1ebc, 0x468962a7, + 0x10320733, 0x9fce6282, 0x9daa47db, 0xb45917f9, 0x2df7eb8d, 0xc0874627, 0x78b36f71, 0x9c545313, 0xc811c008, + 0x681133ba, 0x25c41b7f, 0xe5a3f1a6, 0xff400b09, 0x2ade24ac, 0xc3995d19, 0xc0f4dde8, 0x58e18758, 0x997870bb, + 0xa35242c4, 0x68a85c61, 0xcee84683, 0x3f3afb23, 0x1dbdb305, 0x1a8a7a0e, 0xfa8b74ad, 0xa9ca7fee, 0xe29f9365, + 0x9769dc70, 0x1d430332, 0x3ae6e97b, 0x6a4956de, 0xcfb402e8, 0x5790972d, 0xbcfa22b2, 0xf96713f3, 0x5c07775d, + 0xaf74c9c0, 0x5788390d, 0x992625d4, 0x4bd1052b, 0xc2f2897c, 0x0d2b777d, 0xced2cc30, 0x8fc64677, 0x114221d2, + 0xbfb2959c, 0xc6211bc1, 0x830be993, 0x4f4b3bff, 0x220b577f, 0x5f943494, 0xb081c947, 0x1d5646ec, 0x4f459b14, + 0x4862b07f, 0x856b7b5e, 0xca6e8e3d, 0x38089a3e, 0x42d6bd25, 0x5ff37152, 0xca8f14ba, 0xe0f7dd8b, 0xb98bb466, + 0xb0d4ccaa, 0x389f408d, 0xe02471d0, 0x3a3f10be, 0xf4c8d948, 0xec3997d0, 0xb49a2b5b, 0xcada22e7, 0x1786586f, + 0xe2a25e83, 0xae2b6f69, 0xd048a888, 0x468bae79, 0x20472e14, 0x0ec99c31, 0x42cf3d8a, 0xb54a97df, 0xaf146b1c, + 0x75582b27, 0x9de6af04, 0xa7005739, 0x150a24dd, 0xa8c22c4c, 0x633a86d5, 0xb7539ed3, 0x865ffc48, 0xad6b6874, + 0x26f67a84, 0x54797ef8, 0x6c2fd2d7, 0xa51320c9, 0x79566716, 0xfb27947b, 0x7e88762b, 0x0f5690c2, 0x0d6cf387, + 0xcab93878, 0xfa539738, 0x85aed1d3, 0x479a95b6, 0x7fd8c74f, 0x4535f85a, 0xba9303c4, 0x652b7acd, 0xd74fe80d, + 0xb9c758c1, 0x70dd1a3d, 0xb04ec074, 0x2d039b5f, 0x51e85926, 0xc5cc94ea, 0x8e31e17f, 0xf467b089, 0x1ce21a7e, + 0x9f625f79, 0x3dcbffeb, 0x23347f0b, 0x94d2255c, 0x56a58c97, 0x4579902d, 0x5c15a896, 0x0fbfc260, 0xe4cfed6b, + 0xb4dfdfbc, 0x8bd0ed78, 0x46d71699, 0xc18b081e, 0xb10bbd55, 0x7e8dff46, 0x389a63fa, 0x4f218efe, 0x9f18e4c9, + 0x4cbf8097, 0x5d698c0c, 0xb609f898, 0xbcfa5410, 0x6e3babbc, 0x1b94eb6b, 0x8e1e97ea, 0x964a2ac4, 0xe431415e, + 0x869eb4a3, 0x90b17ddf, 0x90782184, 0x3a95bc2b, 0x4454ab98, 0x81027d3e, 0x504849c5, 0xab13871b, 0x35991fe0, + 0xbd93be13, 0x2c03ba05, 0x6b150d96, 0xefe0907f, 0xd66509ed, 0x021992c6, 0x111f860a, 0x9f726f7c, 0x8cec726d, + 0x679e2e5e, 0x6ed3d5eb, 0xbfb3a17d, 0xf5184ac1, 0xcd780a57, 0x50e79a34, 0xc3f9c47c, 0x63a25657, 0x2234f450, + 0xdfd3992e, 0x44f8eb77, 0x6888a71a, 0x13da5a44, 0xd2cb2dfe, 0xe4312a24, 0xd79e6c53, 0xfdc72c08, 0x727abd8b, + 0xbe525521, 0xbbb8f040, 0x6ba649e2, 0xf5ce97b6, 0xd37fd33d, 0xdd009f04, 0x49e48a2b, 0x255ab389, 0x95ae6134, + 0x64b56f80, 0x14bf2f95, 0x82bfc5e2, 0xea1276e5, 0xc8e0c7c1, 0x8be3a478, 0x0347f591, 0xc597fc34, 0x15020fd9, + 0xc8b46d72, 0x5d8a7059, 0x9f20bea1, 0x3db66481, 0x088cff35, 0x2ac85fb2, 0xf5e6eb55, 0x6b1c769b, 0xd23a543d, + 0xc6dd224e, 0x4f383555, 0xf15ec575, 0x645df6ea, 0x0a68db35, 0x2828bd77, 0x66796659, 0x34017aad, 0x4e6e42ea, + 0xab265f19, 0x7af95db4, 0x97471eaa, 0xa636d881, 0xc3a3bb26, 0x081f8482, 0xa2f77553, 0xa0304066, 0x76fd2e95, + 0xafd498a2, 0xd1096d4a, 0x58037ee8, 0xb6d2eaf3, 0x898e5953, 0x0abd3add, 0x624676ee, 0xe874584d, 0x628d57ff, + 0x34cb7a82, 0x73b68a38, 0xb903aac7, 0x0d86cde5, 0x1529a6e3, 0xb8f0b32b, 0x5fda7ad4, 0x2d781f73, 0x504264f0, + 0xa56dfcfe, 0x1b8a1812, 0x286135b7, 0x05a89982, 0x72e62957, 0x59c7cf61, 0x35747cf7, 0x6d18d8eb, 0xd4f879bd, + 0x1395e08c, 0x0d96a496, 0x5d92481c, 0x86f2e1e6, 0x8b8e2e5a, 0xd365c844, 0x7c85ec9d, 0xc7a1320b, 0xdeb73ee7, + 0x703e4727, 0x41dfa897, 0x4b2a45fe, 0xfd48de8d, 0xa49012e6, 0xc239c634, 0x1635d9e3, 0x95e9bb9b, 0x82dc28e1, + 0x2d4449ee, 0x539353dc, 0x82ed9acd, 0x3de4c1b4, 0x147c753b, 0xeaaca1c4, 0x809f44cc, 0xbd279969, 0x5193ef1f, + 0x9a831899, 0x1610a709, 0x41f6c3ed, 0xcb0dc39e, 0xc5308099, 0x453452a3, 0x3fbe29c4, 0x87d4b2e3, 0x857a4900, + 0x61aec369, 0x2d3e6179, 0x2cf444ab, 0x806d719f, 0x6df9dc40, 0xad9b5f34, 0x974cdeb5, 0x262f9e62, 0x4e209c50, + 0xc06464b2, 0x8fb58f04, 0xdf4a6ead, 0x6045dbc6, 0x70e81c45, 0x9579cc8b, 0xd75eba8f, 0xd7a75f2e, 0xfd634f0a, + 0x490f6cdb, 0xf20fd33c, 0xf75b3da3, 0xd36b45ad, 0x30e307f6, 0x7812356b, 0xb231b164, 0xcdaf2d4a, 0x3a35b8b3, + 0xef651595, 0xd839d770, 0x9212f38c, 0x07f1ca57, 0x843f4827, 0x87f40d03, 0x156372f3, 0x38ec14ab, 0x56a31dae, + 0xf250676b, 0xcddde06b, 0xa5d0f303, 0x091a7921, 0x343b5132, 0xcb06b999, 0xb9c41016, 0x680d7d52, 0x217ef715, + 0x5d9ec4e1, 0x7ab62e3b, 0xfc879d93, 0x7ef2f149, 0x0bdc6dbe, 0x1bcb8140, 0x61027584, 0xc3ab4fd1, 0x51851cb1, + 0x02e21c8e, 0xdaa5858c, 0xc9f101d0, 0xc67c2cec, 0xf467afc6, 0x72cea9fd, 0x74bd0a98, 0x6037d904, 0x22981b1c, + 0xbdb8b67e, 0x5085717f, 0x343ebf7d, 0xab76d61d, 0xb38d8fdf, 0x836e5be4, 0xf78ca91a, 0xb2881e3b, 0x14560999, + 0x9e78543b, 0x9c557b20, 0x21a44f47, 0x4b8679d0, 0x70e89e9a, 0xe6c9b840, 0x6c199a96, 0x5b3db4c6, 0x59dbd38c, + 0x58688a9c, 0xa46b82d4, 0x96b5d2c5, 0x30afc0ab, 0x7b68ee58, 0x933f6404, 0x196e7cad, 0x55818f88, 0xb9034e93, + 0xcace7ac7, 0x54b62bc6, 0xe3fdc507, 0x43822dba, 0x1e5ff00e, 0xe72cbf06, 0x748a474e, 0xe331272b, 0x84d54036, + 0x51651bc1, 0x800636fe, 0x9fd427d3, 0xf188b6d4, 0x33a26a5d, 0x18c2fb58, 0x0ccae070, 0xcaedace1, 0xf1d5179a, + 0xeb6a73ee, 0x183680da, 0x5d91181b, 0x23697467, 0xe83ef37d, 0x22c2f543, 0xd584555d, 0xf30c5a58, 0x50678ab3, + 0x0b7d44c7, 0xf4ac804e, 0xdbe0ce36, 0xa5e86703, 0x2385006f, 0xd2deacb7, 0x065b11e9, 0x4ba4329c, 0xbc50161e, + 0x7117f3a3, 0x4a537e64, 0xabdf05d8, 0x8702fdf8, 0x6b4a6051, 0xefc4ffa5, 0xb954d912, 0xd572c224, 0xd3f29112, + 0x03c07d60, 0x791fdcb7, 0xcfb3d51d, 0xe52f8d68, 0x4a9dc0d4, 0x2ae1d2ff, 0xb4a24f79, 0xd0a99ea4, 0xb16f15a1, + 0x918c0ccf, 0x43e2c4b5, 0x8d8f05c9, 0x56004a26, 0x5da27c32, 0xf3fb0c11, 0x762526aa, 0xc17e92da, 0x6912571a, + 0xf5138cdf, 0x3620f729, 0x5b803538, 0xc5fc4d93, 0x0a2c908c, 0x2292a828, 0xb8f114ef, 0x8a6a49ef, 0x7f49ea47, + 0x2b7565f2, 0x0866b961, 0x237f887f, 0xcd0eac87, 0x41a5248f, 0x9c5c2f2b, 0xbc16a2a3, 0x659192f0, 0xc12624e6, + 0x6c009e93, 0x80096651, 0x8ebdcae6, 0x6e5752df, 0x75b69a59, 0x770fd198, 0xf2af1726, 0x383703e7, 0x268e380c, + 0x1424cd79, 0xcf31eaa8, 0x35be392c, 0xb7932db4, 0xa2e649f8, 0xa41a79e8, 0x4eda3827, 0xa0c5b5c6, 0xbb812f35, + 0x8e1b884a, 0xf567f4d7, 0x7fd8bbe6, 0x720c9105, 0x2d4b8392, 0x77644fea, 0x0fe74257, 0x3032cf03, 0xf7fe6ac0, + 0xab7a76c3, 0x07f89333, 0x378ff1cf, 0x57cb6f00, 0xb7b5d71f, 0x7c44c2d6, 0x86286ac7, 0x1eefc477, 0x0230e0ca, + 0x81489b82, 0x569f52ae, 0x2e4a8936, 0xddce82a4, 0xc143a55e, 0x1975b024, 0x155e2ec3, 0xa9e8a750, 0xfd9dc796, + 0xd113ebb3, 0x4f29d321, 0x6dc2254a, 0x177c60ca, 0xddad4d5b, 0xd95db9b4, 0x6f90a426, 0x675efe51, 0x0a41a4fb, + 0xf00e71dd, 0xaf821f9c, 0x07722750, 0xd6f46be4, 0x23ed3a62, 0x69702789, 0xbff1c639, 0x82e4323b, 0xebaec35e, + 0x8d7e8f6c, 0xc033950a, 0xc41d3bfd, 0xc833cdb5, 0x06961afa, 0xf9f26428, 0x20f29dca, 0x66dcfc35, 0xe5661a7f, + 0x3c419cff, 0xa867f0b0, 0x0831ebea, 0x54fb40a6, 0xad0d1174, 0xc162c16f, 0xc6e08a81, 0x0a01ea45, 0xd734427d, + 0x4ba6dc98, 0x6ca6aa27, 0xd4c802a1, 0xe83077c6, 0x2da87ef8, 0xb97d8235, 0xabd56e61, 0xeaf11b7c, 0x9c7fbf52, + 0x42841be6, 0xdaee8ca6, 0xf20e54e9, 0x0e6a49b5, 0x8aca04b0, 0xa176d9b9, 0x4878add6, 0xb88511ce, 0xb0b2d045, + 0x7b756eca, 0xf3b8a09f, 0xc7cabc44, 0xccdf04f7, 0x53de49fc, 0xc4f86111, 0xa224228b, 0xc51a293f, 0x5f1f1720, + 0x9ee7d486, 0x4f7bd973, 0x0314d7d0, 0x25788d4d, 0xb541b92d, 0x8d20621c, 0xc249c050, 0xc797c36a, 0xefcdd8d9, + 0xa6c79490, 0x2edf4474, 0x31248d71, 0x8b935e69, 0x90330fd3, 0x5bdfece8, 0xa942b33c, 0xe1bb174a, 0xe39481f2, + 0x99bef68a, 0xcbb88955, 0x815942fd, 0x0115ada7, 0x87b51264, 0x82d01c66, 0xd348b9c3, 0xb60caecd, 0x5da3d270, + 0xd0b8b409, 0xf5551b38, 0xb9794636, 0xf4b63632, 0x40de3b1d, 0x2ca9cf4c, 0x3bf9c391, 0xb82283cf, 0x01ecf582, + 0xafbf9685, 0x31cfe4ef, 0xfb5920cb, 0x9435a2fb, 0x610d9b1f, 0xcf615483, 0x4d6ebfdf, 0x60bc2c63, 0xd75723bd, + 0x6e7904c2, 0x9307ca95, 0x8c54939c, 0x1efde59c, 0x7241fdaf, 0x5f58308a, 0x381d4074, 0x368dabf3, 0x88cb0072, + 0x6b31a3ae, 0xc33d4b91, 0xe3a9fb25, 0x9cbde8ba, 0xfb3b021a, 0xd3aa7c46, 0x513c7488, 0x8cb2011f, 0x7a603821, + 0xfe5c3f74, 0xd1527b89, 0x8752ecaa, 0xf43130ac, 0x40e4bc0b, 0xb09e3841, 0xfb687c9d, 0x552582a2, 0xedce5830, + 0x23b111a7, 0xfc3d47bb, 0x38c1981f, 0x01593275, 0x135073a5, 0x825243dc, 0xccf1cc60, 0xee1cfacf, 0xcf579727, + 0xda89aca4, 0xae11fdc5, 0xc80d4af1, 0x3db177c6, 0xa3b1440e, 0x7f009a6f, 0xf728c138, 0xbd4c49f1, 0xdaeed81f, + 0x40986ac3, 0xdf70da31, 0xcd136b03, 0xc8da74c6, 0x0e78a062, 0xc9919dd2, 0x48c241bf, 0x78a81d61, 0x14585171, + 0x38e0b26b, 0x69f9450e, 0x1bfe1790, 0x49c05d86, 0x55a115a0, 0x83120e64, 0x570b6aaf, 0x32d441cd, 0x640d1bdc, + 0xbc38d065, 0x8481fb6e, 0xb43b8f93, 0x53fa0762, 0xacb2f944, 0x0b379a1d, 0xb9345407, 0x3c73b5e2, 0x6d3332f2, + 0xe0317235, 0xf49fffae, 0x165965db, 0xf2ea8f86, 0xc7804201, 0x6228e2fe, 0x3df8cd30, 0x2d6d41c3, 0x153b3a21, + 0xcb8a9dd7, 0x204bae97, 0x036b6163, 0xe88956b0, 0x3dec991d, 0x5d95f288, 0x3a77fc25, 0xc6aa1843, 0x2df9bd7b, + 0x2a0683b8, 0xe8265ee3, 0x26f4ae26, 0xbe54a31d, 0x42070e9d, 0x0493aa08, 0x17dc2058, 0xca808b35, 0xba6f4284, + 0xb4afbaee, 0x98dccc4e, 0xf386b4dc, 0x9053e777, 0xaf3b8442, 0x62af46a8, 0x80151956, 0xab8acf22, 0x2d778c21, + 0x609323f2, 0x20189e21, 0x6cdb9499, 0x06c70692, 0x2281befc, 0xc9997d6a, 0x520316f8, 0xf27d789d, 0xd693c7b0, + 0xb8ade3f0, 0x5caae045, 0xa52e7606, 0x9736f22d, 0xb6b86893, 0x6b0a2368, 0xd2506c0e, 0x6f3e400c, 0x783b8dce, + 0x1330bdaa, 0x101581be, 0x0164b827, 0x5f9c46f2, 0x7d21e0ab, 0xb8278182, 0x62d5bdc5, 0xe81fc650, 0x9415edfd, + 0x462e49ad, 0xed61a03a, 0xa1c677d9, 0x9eb2bc55, 0xe70a4433, 0x94b495d7, 0xda50d2d5, 0x48aa2f32, 0xb2ecf1f8, + 0x4529d6fb, 0xe04df174, 0x4880e334, 0x8f9272ee, 0x62b4e141, 0xcfe52c63, 0x3d6f288c, 0xcc1786b7, 0xd8fc0d6b, + 0x0fdabbae, 0x39fb4d3a, 0x172e47f9, 0x6156e3fc, 0x04985537, 0x8f6c182f, 0xa2dae841, 0x87d430a8, 0x965afed2, + 0xb011ce84, 0x3e199a48, 0xa70261fe, 0x52edd6ed, 0x58a04a0c, 0x6ebb2ee5, 0x6407319b, 0x79a2b7e6, 0x8cc1c2be, + 0xbab704dd, 0xf815a6a0, 0xe4124911, 0x523b7146, 0x81f4eeac, 0x0fb4b69d, 0xb2bf80a8, 0xe338999e, 0x5cd8cb4a, + 0x30d44648, 0x35415239, 0xcffaaa8a, 0x8ae86cca, 0x6ce689e3, 0xf6eef561, 0xf5511ef6, 0xee7ea15e, 0x70ba5571, + 0xe8c7dc93, 0xd9ab49fd, 0xaca9a10d, 0xb84bec44, 0xe0a2c583, 0x9dd22200, 0xcced5f2d, 0x0ec092f0, 0xbfd020d0, + 0xf658f5e5, 0xfcc077d8, 0x796002c6, 0x202f9eaf, 0x0731229d, 0xe0d247bc, 0x16a9ea4b, 0xef536adb, 0x08387311, + 0xac624ff1, 0x964b2af8, 0xd331062b, 0x5ec732f0, 0xb4f30841, 0xfa62f954, 0x785b1d04, 0x372b700e, 0xed822f15, + 0x110ac1b4, 0xa677f062, 0x81446344, 0x1529124c, 0xb890118d, 0xf3301c1f, 0xda82f6f7, 0x71586897, 0x2f776fd7, + 0x69391f36, 0x58ec04d6, 0xf2eeeab4, 0x52a5167d, 0x362d07e7, 0xf276b6fd, 0xad1eb522, 0x303f15c3, 0xbd1bd6dc, + 0x62c21456, 0x178f6c9f, 0x7348f0ff, 0xa2fe0a28, 0xfa1c7ad7, 0xb653a448, 0xcb4dc430, 0xf1e8f4bb, 0xf1e1d492, + 0x5fdc1077, 0x836236ed, 0x8054cd78, 0xe32e8f7f, 0xcd04bfdb, 0x16f25621, 0x6d98154d, 0x3d793fb3, 0xc84f1325, + 0xf740006c, 0xd6a351d1, 0x9cdb5d12, 0x4458f46d, 0x739dd95e, 0xf0e16ea9, 0x3c7261db, 0x2e8f8712, 0x84f5ac68, + 0x183daf94, 0xd6ed93b2, 0x68c9d855, 0x33c34ec1, 0x7d624b32, 0x028042c6, 0x94c48991, 0xdac43023, 0x12527509, + 0x16c5b0fd, 0xf3bda088, 0xd8d69dd0, 0x53b250b2, 0xda0ebca8, 0xcdf13f17, 0xbec72dfe, 0x98aa6f34, 0xcc4a06a8, + 0x1e031e3e, 0x542c149d, 0x1c90fa78, 0xb369b492, 0x04b2f16b, 0x3a12fc39, 0xfdb706aa, 0xb6e64468, 0x9fb868cc, + 0x9a1cda53, 0xd427b543, 0xed16bb43, 0x8e26d5c0, 0x6d61ea52, 0x43a224c8, 0x30c0b857, 0x1e7049d6, 0xd92423bd, + 0x119030d6, 0x3069ab95, 0xa33a7d04, 0x1ef3ecc0, 0x37acf8f6, 0x6e8d789e, 0x2d98726b, 0x4a68e9cf, 0xf873273b, + 0x54d14c69, 0x87718f80, 0xb984b967, 0x5f1ff6ed, 0xac557674, 0x0c8ab11d, 0x8a128385, 0x8c0239d2, 0xe874e138, + 0x1c728d81, 0x58ea22a3, 0x36aebac2, 0xb4d4cd68, 0x613454cb, 0xef45ee7f, 0x5861d5fb, 0x0583c348, 0x59623bba, + 0x2b1e3d31, 0xa4081dd6, 0x21e26e6e, 0x8dfb38cc, 0x397cd086, 0x4ffb8bc7, 0xfcb3cbdb, 0xc16728f7, 0x617dba33, + 0x052f9a1f, 0x0068ae17, 0xebc36931, 0xe80a7f74, 0x274e8d9f, 0x40bc90d0, 0x4690118d, 0x674aea81, 0x5d27eed0, + 0x30b64252, 0x1d6200fe, 0x25ad5cb9, 0xad4e5782, 0xed4b4995, 0x936cc54e, 0x49b30d74, 0x18d56221, 0x0ed9761b, + 0x2cbcf4fb, 0xb3925ca3, 0xbc3733e7, 0xf599c6b1, 0x250d73e6, 0xeef3b584, 0x7bc2da4a, 0x89329384, 0x92884095, + 0xededa97a, 0x9b2d966c, 0x378c38f1, 0xe642a01c, 0x12a5a7db, 0xfd888599, 0x389cfdb7, 0xc1be817c, 0x854989cb, + 0x30121d3a, 0xf12a2048, 0xb706868d, 0x8e4e97fd, 0xa97a5a52, 0xf358dc23, 0x56b5e33f, 0x6d186eed, 0xa6165484, + 0x6bce33dd, 0xdd39822f, 0x9030a9a3, 0xc3de4890, 0xc16df530, 0x66dc0d89, 0xd0d148f6, 0x672ffa69, 0x6908d2dc, + 0x950d240c, 0xd6bb9f7c, 0xf540f35b, 0xf0031840, 0xe538dc86, 0xc3613cf9, 0xb63b811b, 0x3baf1d35, 0xc73e77ce, + 0xcc3fb120, 0x41c95a53, 0x71b81b45, 0x2a963591, 0x74ff2db1, 0x497b509e, 0x671a68a6, 0xbc7d94db, 0xc13550ca, + 0xfe1f4dac, 0x9ece4a48, 0x042ff877, 0xda24fe36, 0xa78d6d2d, 0xc1881239, 0xf8b0505d, 0x4f1c3f37, 0x0487ee89, + 0x086417b8, 0xeee10724, 0xe4cda3bc, 0x5db697d7, 0x3f154353, 0x884eb136, 0x0305139c, 0xd5fd552d, 0x41ff4682, + 0xfb1c1c81, 0x926c93b5, 0xbdf20e80, 0xe2c3714f, 0xbb5877f7, 0x454ab021, 0xb4ae4f7f, 0x8dd876a3, 0xedc6a7dd, + 0x025c5b3b, 0x30b4a7ad, 0x3d18c8c2, 0x024d3144, 0x77f8447d, 0x58297824, 0x4bc4eca7, 0xcad63159, 0x153d84f1, + 0x36b07a17, 0x378f430e, 0x4fddfd8c, 0xe35386ae, 0x4746d758, 0xa3f2b119, 0xe6d6468f, 0xa8793483, 0x9921b403, + 0x4a311d8d, 0xe8b395f9, 0x7bd00337, 0x256dd7ac, 0x6da7e9f2, 0x06a658d6, 0x126e72f2, 0x9c28f2ca, 0x278292b9, + 0x71a30c35, 0x1c92182e, 0xc149bed0, 0x7d3457dc, 0x1ceab5fe, 0x06c84fd2, 0x5c115101, 0x1456132c, 0x5451308c, + 0xf875c9af, 0xc1174231, 0x5b0891e5, 0x13b02268, 0x1de14580, 0x9410e5fa, 0xab8ca6b9, 0xf152542f, 0x8cc697fd, + 0xc32730f6, 0xca5c4904, 0xc60bda2a, 0x4e9936a3, 0xd5da3e2d, 0x57748851, 0x6d08677b, 0x5a2c339a, 0x9cedd7b3, + 0x368fa3cf, 0xf09c809d, 0x220e0cdc, 0x36eed1b9, 0x0c071176, 0xb7e55656, 0xae393ae8, 0x0b662f9a, 0xf07b674b, + 0xec7b9b82, 0xb87fae62, 0x32b05f17, 0x19f8028f, 0xab77645a, 0xf553d9a9, 0x4168978d, 0x4b0bb76e, 0xd34f6000, + 0x286c41c3, 0xd7e8d15a, 0x1ce0d7fb, 0x9aae1f3a, 0xac1c2674, 0x9abe0c7e, 0x40e28d15, 0x76506294, 0xdc056ab6, + 0xaae2fed4, 0xc1bcf7b3, 0x561bcc98, 0x779139b3, 0xd381b53c, 0x44f4f44f, 0x69354558, 0x4debac0d, 0xbd788a97, + 0x3b6abc06, 0x80c0e657, 0xe71d960f, 0x04f23a18, 0x6fe4f52f, 0x9868a383, 0x7578df8b, 0xc965d4c1, 0x35a0bc7d, + 0xb3ccf5c8, 0xde4801e2, 0x7ab0d644, 0xe1cf0e11, 0x7f0d1221, 0x9e67c534, 0x95223613, 0x76964217, 0xad8b234e, + 0xada05e1d, 0x40a302dc, 0x58f1afcd, 0x25a000e8, 0xd6eea0da, 0x797f1a66, 0x3e01e261, 0x38b26ad4, 0x73f91da1, + 0xf5a1bbf0, 0xf957ac18, 0x2418def1, 0xa6a015e9, 0x9af318b5, 0x3cc871d4, 0x836b794f, 0x3ca5dad8, 0x8fced705, + 0xe0191a97, 0xef291c3e, 0x6c36bca2, 0xa1330456, 0x048282bf, 0xf4ef2269, 0x07159886, 0xdbc19aaa, 0x33bb64e3, + 0x560fb324, 0xbc0dc721, 0xa5fdf4fc, 0x69c25adc, 0x9cc6e172, 0x4c73c4b8, 0x6611e44b, 0x04b7f0bb, 0x4f58b80e, + 0x2cc44211, 0x24b7df0a, 0xe84891e4, 0x9730c35e, 0x4ee72b45, 0x9e349731, 0x73a6c66b, 0x929007ba, 0xcce56bdf, + 0xdfc790f1, 0x8a89e58c, 0x4d8d8f45, 0x3ec63c00, 0x88e996f6, 0x86ba8f9e, 0x04fef9e4, 0x9ba27032, 0x131b1a73, + 0x1dfc9be1, 0xf557cd52, 0x2c3caff5, 0xeea6ed3f, 0xe4213a6d, 0xb0984d32, 0x494fc60a, 0x63cdf5c2, 0x85c571d0, + 0xdbe10b7a, 0x64638ad8, 0xea4a3726, 0xf1b60c1c, 0x908d87cd, 0xe4aaa972, 0xabadb576, 0x6b6f7442, 0x14cc397a, + 0x217e08ab, 0xda07247f, 0xc075b729, 0x9b812ed8, 0x7f34c2dc, 0x630a2ab7, 0xf318e0de, 0x9094bbfa, 0x7b80365f, + 0x08f29c09, 0x048635a5, 0x0ea5184f, 0x1178c1bf, 0x294b137a, 0xc77358fd, 0x8f726b6f, 0x16eff25f, 0x657de66e, + 0x1f1e2e7c, 0x9731d28f, 0xb50468cb, 0xb0f026a2, 0x3f474346, 0x55a9fbcc, 0xe71aba4c, 0xefb28007, 0x1330b13f, + 0x496b507d, 0x32ab08ff, 0xd326008d, 0x45fc8371, 0x245aa3fb, 0x9a14ea0e, 0xf7abd411, 0x1f8abe67, 0xb9fb1de5, + 0x37fc43d2, 0xe5702dd3, 0xb8b3e0ee, 0x49c84286, 0xfeb86adf, 0xcbb5d761, 0x954750ba, 0xa7445891, 0x2bba9e73, + 0x01ae3dee, 0x21d28dc8, 0x9b68407e, 0xd92c85fc, 0xa1e4a8b8, 0x05b034f6, 0x91a95d34, 0x29b5e5f6, 0x036d5ab0, + 0x95aaf6b9, 0xa1bfaab9, 0xb4c849b3, 0x7b1034e0, 0x86ea3706, 0x5376d1ff, 0xf57952cc, 0xb6418db3, 0x3391780d, + 0xbd0f02ea, 0x7d688196, 0xd279d83f, 0x4a3f0cfe, 0x31cf8aff, 0x5129ef8d, 0xe0782fe4, 0xfba6a9e0, 0xec207420, + 0xef06a20f, 0x812b8726, 0x54d468cc, 0x329aedf2, 0xc8f4c94c, 0x1018be6b, 0x14190f0f, 0xfa872001, 0x50b153c2, + 0x56e97bee, 0x0996fe70, 0xdec45ba6, 0xeae7ed7c, 0x678272b5, 0xd6d06203, 0x8a01f848, 0xf6cd951f, 0xff7283cd, + 0x647ac57f, 0x1987ed5b, 0x37f23258, 0xc6d06ac9, 0x64fb9898, 0x71179e1a, 0xd94c83c9, 0xff78389c, 0x9811da28, + 0xf0c2d4fd, 0xf7dc369f, 0xd4e28c72, 0x1346e00a, 0x7da64339, 0xd488e9e1, 0x61797b12, 0xec59e724, 0x051d45c7, + 0xff7137cd, 0x6587ac7e, 0xce07c79a, 0x9bb32825, 0x347daadb, 0x6c972a3b, 0x0d2da2af, 0xc7dd295f, 0xe2d5c3ab, + 0xb80d93f3, 0x6859de5f, 0x9fde53dc, 0xe51ea6da, 0xa7d7ee54, 0x9a616246, 0xcc94641c, 0xb0e7608c, 0xa71ae2c8, + 0xcaae3d43, 0x311460eb, 0x3bfe4ce7, 0x09048242, 0xd355b457, 0x6af2d2cf, 0xf5878992, 0x2f85de1e, 0x7a7ffd99, + 0xa70545da, 0x7c8d1fa2, 0xf9e887ad, 0x3a554488, 0x57d2d770, 0x2aaab27d, 0xf938aa0f, 0x64a2b36a, 0xbfea49e5, + 0x2fde4e16, 0x2136907a, 0xcecbfff4, 0xdc54b694, 0x084134bd, 0x1b35869c, 0x8023ccad, 0x5293c3e1, 0x38f9fef6, + 0x07062f4e, 0xaf5cd5da, 0x2aa2c4e7, 0x7f414f94, 0xb3990a6e, 0xf5d06549, 0x717fe25e, 0x9da4f446, 0xda75e914, + 0x90f9a88b, 0xaf0a1d80, 0x3594adfb, 0x70d0d8ef, 0x5732b50b, 0x7b145609, 0x27184e4b, 0x84e8afca, 0x4ff58088, + 0xaa019f02, 0x6d6b73f9, 0x2c762bf4, 0x2320a047, 0xde095aa0, 0x7ca9f84f, 0x072549fe, 0x0f98607c, 0x9049f221, + 0x6328a387, 0x69c52732, 0xf7f5e4c6, 0x2c0c4599, 0xab8555b7, 0x73f155b2, 0xe4720378, 0xe30204e8, 0x963e6e3d, + 0x33e3e8ad, 0xd5ced070, 0x03cf7d54, 0x2ff06939, 0x3d46c721, 0x90416cc7, 0xdd36e556, 0x55c76cc5, 0x348f93f3, + 0x97c5e71e, 0x856b5cab, 0xb033f7b7, 0xaf9f561b, 0x40ff0fa5, 0x412d2f4c, 0x0708acf5, 0x9175406b, 0xbf2f2bea, + 0x001c93eb, 0x2ef73da1, 0x1f6242ce, 0x7821bed8, 0x2af6325f, 0x523847a4, 0x53064e6d, 0xc6167328, 0x0eb10d65, + 0x60960f32, 0x0dcee2a3, 0xa31604ce, 0x9d3423d3, 0x071fbd57, 0xe45fc121, 0x66ede637, 0xe5201c17, 0x1c4e5c5f, + 0x4992ec18, 0xc69f49ab, 0x419eb5d5, 0x134b5fc4, 0x53651b64, 0xafe252e7, 0xd9236256, 0xe11ceb3e, 0x1acc80ba, + 0xbb5759de, 0x2ec89e6d, 0x66bfd6ba, 0x9e310871, 0x9a6706e0, 0x7338e196, 0x69048bba, 0x7eca5249, 0x4a785f5e, + 0x859cfdd9, 0xad459a4d, 0x3a39da05, 0xe6a08583, 0x695442c7, 0x0377cc6c, 0x754e1590, 0xfa78d24c, 0xd0dc2a5d, + 0x3c839ce3, 0x9264bba1, 0x83bc052e, 0xf2d88dfe, 0x7393e6fc, 0xce89a5f0, 0x6b4145ca, 0x91ae5dfa, 0x3cf89f37, + 0xddea9d1b, 0xc9ab96a3, 0x61183d1b, 0x69538196, 0xddb1d58d, 0xbe5dc2ef, 0xfb595444, 0xbc3b9252, 0xc5d02b5c, + 0xf989d123, 0x15a4dbb1, 0x45c0e14f, 0x29e99313, 0x72372868, 0xc477f0f0, 0xfc4bd70b, 0xe493e9f3, 0xedf81fc9, + 0xbbdd4fb9, 0x7e621493, 0x42e73c53, 0x82b70e39, 0xade0fc1a, 0xc214373a, 0x8793c6db, 0x49ce121a, 0x9b846751, + 0xb2a73c58, 0xc9592b6f, 0x642be787, 0xc6aa0236, 0x2c8b4737, 0x63b5152f, 0x4be1ff88, 0x1b6abaf0, 0x6d761b72, + 0x9b0b31df, 0x07dc01fb, 0x8bc20e26, 0x71f4e617, 0x079efe77, 0x25c7f98e, 0xea528d43, 0x8b060d30, 0x8e5f2775, + 0x1221cfdd, 0x6ad2154a, 0x7bc2c77a, 0x0f01f211, 0x5d6e0844, 0x88e9849d, 0xddc3cd82, 0x248f4441, 0x762dfc55, + 0x62887968, 0xff7b831e, 0xd6745e3d, 0xfe2a9041, 0xab5068c1, 0x90c6a1fc, 0x89eee61f, 0x936072ef, 0xab008d45, + 0x09b8d6f5, 0x044b5559, 0xa9affb9a, 0x7586487c, 0x1989f401, 0x0595b108, 0xd43ee456, 0x55036e14, 0x48b298c8, + 0x9fef9705, 0x25c5cff0, 0xe9105ac7, 0x7ef4d565, 0x3292eb87, 0xe5baa253, 0x9015a50e, 0x42f4a3ff, 0x84c995da, + 0x864d9857, 0x65632292, 0x18b40b2e, 0x1d6ea159, 0xa2e24122, 0x6e22b5a9, 0x841653cf, 0xc3d54a17, 0x4c4704d1, + 0x8ef96232, 0x22328896, 0xd65158b7, 0xf90f43af, 0x14356f5a, 0x4d94c25d, 0xfa5d127b, 0x2fd75d07, 0x82950a35, + 0xdb3e789c, 0x20088d0b, 0x36ee669b, 0xce27fac6, 0x6ed872b6, 0xe5810553, 0x6a5b5de2, 0x63b8cdd7, 0x7a8bc14a, + 0xcf52e2ee, 0x7a22da32, 0x150ac2cb, 0x3003f99d, 0x23d37a60, 0x9eb79bce, 0xa6306597, 0x4fff8e77, 0x095a02ae, + 0xf6b4ab86, 0x40779237, 0x3b89d702, 0xe1020cde, 0x4188ad76, 0xb258bef8, 0xff861917, 0x81e98b9e, 0x928b7884, + 0x48ae330a, 0x34dae89d, 0xe93bcded, 0x0fe91dc5, 0x9927192e, 0xbf3c751d, 0xdbce4682, 0x787c6c98, 0x8882df87, + 0xaa80ae23, 0x596217b7, 0x3223f05a, 0x76674173, 0xfbda8944, 0x69dc52fd, 0x9086812d, 0x9f7b90d6, 0x67c09e4c, + 0x09b8fb7d, 0xcef3b456, 0x1c59a44f, 0xac057ef8, 0x0f5f70c0, 0x7602ec73, 0x53233a5e, 0xd1227116, 0x7b44ae81, + 0x74bc785f, 0x05d94259, 0x7408ed67, 0x44c7e4f2, 0x5192fe2b, 0x6f8e3451, 0x173a2139, 0xecfd4579, 0xdf6a8798, + 0xcc197045, 0x56aab959, 0x8357a073, 0x9bbcbfd0, 0x51962720, 0x9b392a70, 0xadd817a0, 0x05710115, 0xaecb73b7, + 0x6afcc740, 0x71d22d9b, 0x820ab97f, 0x88dfa12d, 0x717054c3, 0xd84a342b, 0x1e285cab, 0xe9195743, 0x5ca88259, + 0x20a934e0, 0x41c51249, 0x0c417d37, 0xaceb7704, 0x37df9fdb, 0xdcc69037, 0xabf65331, 0xb74e8c92, 0x7a61f672, + 0x4b65ee9a, 0x8e2978de, 0x49928758, 0x5b85c7c2, 0x710886d1, 0x1c8552cb, 0x2db67dd7, 0x693fa2b8, 0x7da1c3aa, + 0x0e66931e, 0x17900062, 0x2d2b3698, 0x2ff7bb33, 0xa9b575b6, 0xe7ffa582, 0x9e15be69, 0x81845e60, 0xe9de8f91, + 0xc5a47f0f, 0x319f0a28, 0xed1ca32c, 0xf3e9945b, 0xca741e2a, 0xba0d98c9, 0x02e960a0, 0x0a7ad64c, 0xb3eaf141, + 0x9bdbc3cb, 0x2cbfc5c0, 0x40a797ef, 0x4b6f4cd6, 0x896c02aa, 0x3c1bafea, 0x1c869ea3, 0x00943d19, 0xd81eb571, + 0x5cf4713b, 0xe86f7c87, 0xfdd27b35, 0xccf6644e, 0xf4663858, 0xed7bd8ac, 0x2e898cfb, 0x0f87ab04, 0x1075aec9, + 0xa717a3c7, 0xf58bda88, 0x70d6ac2b, 0xc59de5a0, 0x87fe5289, 0xe0c7db6b, 0x6714f3f2, 0x621b70c9, 0x3baba46d, + 0x38599f87, 0x69d3d070, 0x8d7398d6, 0x10e8f166, 0x283bd15d, 0xf6b8ff30, 0x78b2cd36, 0x3a40cc6b, 0x7e1f7340, + 0xb7ae9e5c, 0xbf27a0e7, 0xee3e6674, 0x89b4e42a, 0x8e7e4d46, 0x50c3af2b, 0x8203c454, 0x76978723, 0x86101a61, + 0x7b8f9e20, 0x2c2f545f, 0x631cb45c, 0x47cf1226, 0xa7a9452c, 0x8afae227, 0x9a1e0c3e, 0x28cf2466, 0x2c9725ea, + 0xe5636856, 0xd80f46d0, 0xac881f27, 0xb7ad7e79, 0xfa84d573, 0x730af7d6, 0xbc19e92e, 0xf43dc841, 0xdfbe47e3, + 0xedcb1b24, 0x8c92a63c, 0x488b1295, 0x2d7a4ccb, 0x7868a1d0, 0xd6bc58e0, 0xe37338cf, 0xed5f5db7, 0x2a7d2920, + 0x47306749, 0xe8863c07, 0x91312720, 0x3e1ccf71, 0x9059cf74, 0x8242c0d2, 0x4637f886, 0x1cab94d8, 0x92441f8b, + 0x31ee9c00, 0xfff3637c, 0x4bd85854, 0xde4d190e, 0x03483720, 0xbb120a12, 0x6ac07180, 0xc13b7169, 0x4730a850, + 0x92d1cca6, 0x2fb2294d, 0x4f9ea8fe, 0x27b65fbc, 0xc579b13e, 0x4f46a100, 0x2c1e7697, 0x395e94eb, 0x87b41bd4, + 0x02f7b0ee, 0x0e3b1baa, 0x555eca19, 0xfeb6bc8c, 0x4c255759, 0x040aeddb, 0x3f7ea2fd, 0x40fbeec7, 0x6ff09c7f, + 0xb921bf00, 0x0d04bfb1, 0x2c2b8ea6, 0x16d1409c, 0x39ab5a66, 0xd5b5740c, 0x1d04ba05, 0xa6424fc4, 0x090a4838, + 0x02d3cd3a, 0xae24543d, 0x16719888, 0x8d6b5daa, 0x440a9a4d, 0x2f6b84bd, 0xf4540c4e, 0x3fdf8c17, 0x700d5f34, + 0xd26e5c3c, 0x7a5cd40b, 0x10ffaed9, 0x00099658, 0x7b07925a, 0x8e283589, 0xf3bb88da, 0x4aa61008, 0xcb486549, + 0xf828cb26, 0xbda48437, 0x9cf4229b, 0x911c4984, 0x9821f2c4, 0xce4a17ef, 0x20df2b9a, 0xac7067f8, 0x13c5b208, + 0x1e4ca981, 0xb74c3bc1, 0x808cdec2, 0x27f388e1, 0x6d2604ad, 0xed95a6eb, 0x7b309478, 0xddb43fb1, 0x426dff60, + 0x9cef4038, 0x3837f4d2, 0xfca18fe9, 0xdf06a575, 0x3e92a138, 0x07baf0a1, 0xc9018f70, 0x1147a14d, 0x877cc44d, + 0x9f4130d9, 0x97d52b37, 0xc9370102, 0xf878f8b7, 0x1e61c434, 0x273cf929, 0xce478123, 0xe5c861e0, 0xaa7bc2f5, + 0xa4e477d7, 0x3956eeef, 0x3a2f8c6a, 0x81253916, 0xff613050, 0x0c060fb2, 0x94040ce4, 0x7f617e06, 0x2e41768c, + 0x3b6e40f7, 0x53129b16, 0x43edfb67, 0x478032f1, 0x99f67a88, 0xf2fd80c8, 0x858ddac2, 0x852bf3ea, 0x0ff7b37b, + 0xee04886b, 0x7094db82, 0xfe5b955f, 0xdafb65d7, 0x515c1dce, 0x3abbb709, 0xff536829, 0x621cce28, 0x71ee78e3, + 0x00709208, 0x3ae36828, 0x6a2faa5a, 0xb52f7862, 0xbdddc9a7, 0x9ced1299, 0x0dcca4eb, 0x6c41471d, 0x8c01d64e, + 0xe1d152ba, 0x1bc80d5f, 0x944fb78a, 0xe4272ec8, 0xaeaed5a5, 0x89492d1d, 0x4de15ec2, 0x31443108, 0x63f45dac, + 0x9f076c4a, 0xa56bf741, 0x51dafb9f, 0xb1bc6282, 0x02d7f4b2, 0x2152bc76, 0x14918b08, 0x8476aebe, 0xbe032579, + 0x3c8adf38, 0xe0841725, 0x8970b160, 0xc4635cc1, 0x0c9f3992, 0xf9e84b88, 0xf41da993, 0x04a60360, 0xa22bc565, + 0xab229563, 0x70611867, 0x971bc146, 0x084917d5, 0x0026b068, 0x4a8d501b, 0x1ed4d715, 0x93ca5fa5, 0x9dd89382, + 0xbc4ad472, 0xe92ad1b6, 0xb8ff746b, 0xc748dae5, 0x06f9dbbb, 0xd6a6a984, 0x2c7b3446, 0xc674b76e, 0xdddd845b, + 0xa4e8cec3, 0x77437a9a, 0xfb980a75, 0x61fb2da9, 0x3ca19586, 0x8165be2a, 0x1e3aa775, 0x32e30f73, 0x6b95df50, + 0xce12f170, 0x6242ef60, 0x013e0236, 0xf10f6ae5, 0x0a56d36d, 0xe0413aeb, 0x13d5dee2, 0x226127fa, 0xf4d5d49e, + 0x02c45cff, 0xcff263f8, 0xe2f217f7, 0x62a644cf, 0xc59bfed0, 0x1715a943, 0xf7d20487, 0xe035769a, 0xb3bb37c1, + 0xdfb55b8d, 0x8befec53, 0x2129343d, 0x0c3280c1, 0x49bf1ab0, 0x336fec9d, 0xdea618d4, 0x09a4256d, 0x4ffbfdae, + 0xd071f0a9, 0x2c04663e, 0x93bf3820, 0x2c07676a, 0xe71db1e3, 0xba7ad862, 0xb4d2e5c9, 0xecca9cbc, 0x653e4c96, + 0x885fc333, 0x150dcab5, 0x360a31e1, 0x0e1f2c2b, 0x6a6c2683, 0xb4079181, 0x013a26ee, 0x45744040, 0xfc9c3457, + 0x6586eb38, 0x3472a796, 0x8bd5e1cf, 0xdf337c62, 0x30940799, 0x17cc87b0, 0x3924a461, 0x5f806d31, 0xf3f672a0, + 0xe8d01cbf, 0x77f7ff45, 0x5e0b56ac, 0xa02adf2f, 0x963cdb9f, 0x49a163b3, 0xdd5df8ed, 0xdcd138d3, 0xb64b195b, + 0xb212a20f, 0xfccb6da1, 0xf0fd502d, 0x44272357, 0xea68ffe4, 0x93a08457, 0x90d2df52, 0x62885564, 0x406e5349, + 0x251ba539, 0x2a44d6c0, 0x698e5a46, 0x8e2cc6c0, 0xdb38da79, 0x128c9e50, 0x7cc71d0e, 0x2f7ec89d, 0x987a071c, + 0xa9ea0b77, 0xf5d9c903, 0x74f8e3f6, 0x3bbdf9c3, 0xd49a5901, 0x9d1e6e13, 0xc207a7bb, 0xfb278e23, 0x373e8053, + 0x3bc12547, 0xe9bc9dff, 0xef445bfd, 0x715be9de, 0x31294696, 0xe546c8ba, 0xe166f965, 0xc7c70db7, 0x421b5ca7, + 0x64b99025, 0xc6f6733b, 0x515e70f1, 0xbbb657ac, 0x600ac859, 0x6f9a8f45, 0x639bd218, 0xd6d637af, 0x3650cff4, + 0xdfdb0f0f, 0x90fbe414, 0xff51092b, 0x8d961121, 0x61ee06ad, 0x1ef9a0bc, 0xc3d31058, 0xf7824609, 0x492446d6, + 0x2e813ef0, 0x00f15f44, 0x5849bae7, 0x59b10930, 0x48e2f9e0, 0xae95eb52, 0x5b5bba3f, 0xa4bd5a07, 0x1bf78d32, + 0x0f96c0e7, 0x3c5f6738, 0x237e9f76, 0x3a072d7e, 0x37b3b3f1, 0x322bd7da, 0x9fa41680, 0x75abc5d9, 0x4070018a, + 0x3c214fa4, 0x9ace2515, 0xc406106d, 0x2545ae12, 0x5b40509e, 0x933a28cb, 0x75986025, 0xfed3393c, 0xf64d614d, + 0xfbc56fd6, 0xc83e197d, 0xf5b01298, 0x7d73867f, 0x4fd05a8b, 0x7066d026, 0x076ca6fd, 0x43a832a6, 0x3661dfb2, + 0x3773e05c, 0x4d4bbadc, 0x4c327905, 0xdd64faa9, 0x567caf15, 0x9af936c3, 0x2bc83022, 0x5ddf4248, 0x784583ab, + 0x3c0ca402, 0x69f3ca07, 0x6ea09322, 0xfcc41c48, 0xdaee586f, 0xe99d1f09, 0x35d432f3, 0x2f89efa8, 0x2ea1f24b, + 0x16f5da77, 0x3e9ad30d, 0x0c08009d, 0x8ca82d89, 0xadd253a3, 0xb5031bfc, 0x48131700, 0xb2185962, 0xba856ecf, + 0x12746042, 0x00251192, 0xd08bed12, 0x02471ff3, 0x73fee1b6, 0x7a0c1753, 0xdcaf9ff3, 0xbbd100f0, 0x667aaa98, + 0x3dcf9d3c, 0xb4cb017b, 0xfc4d9e3c, 0x99614148, 0xc33ad25c, 0x2a54a37e, 0xbd57a7cc, 0x51a29fdc, 0x1a1f0057, + 0xb7370fe8, 0x1f14cff9, 0xded928a7, 0x30a05ca0, 0x5e085604, 0x7a7513b3, 0x26fd3577, 0x391e8100, 0xdeff079e, + 0x27e6ec3b, 0x0ee5d3e1, 0x3c15c264, 0x6b82b616, 0x0de89539, 0xaa577b2e, 0x45e82bff, 0xa4dcae8f, 0xbd3d0eda, + 0x3132eb29, 0x284f8691, 0xcd641495, 0xe7abac5b, 0x39883235, 0x51f07ed5, 0xe8dd464a, 0x09124509, 0xe5dc9d3c, + 0xdb868dc9, 0x1fa7fdda, 0x6aebb448, 0x0c2959a1, 0xe9305267, 0x962fcf6d, 0x665a7b5f, 0x0d64b053, 0x33645c85, + 0x480d7a6d, 0xd25cb6ad, 0x50338502, 0x517a1a95, 0x09e0553b, 0x2cfcc8e7, 0x3af09546, 0xc99a870f, 0xc4db6735, + 0x297f1a2e, 0xad26d7a5, 0x746a5719, 0xacc3234c, 0xacca57e5, 0x19f26491, 0x063a6b3d, 0xf28b570f, 0x3f86cc7e, + 0x39978cc1, 0xb33880d8, 0x941de399, 0xe3aba136, 0xdf683529, 0xc7902c89, 0xf33a66e6, 0x1123afdc, 0xbeab7005, + 0x289309cb, 0xfff11431, 0x440269f3, 0x6d206fd1, 0x8b4861bf, 0xf69c21e2, 0x247e3a50, 0x94ffd64e, 0x80b0dc56, + 0xb29d8df6, 0xf19baf90, 0x92324381, 0xc4a8b00f, 0x4f0e8262, 0xa2dc354e, 0xd5b8a0bb, 0x381d2664, 0xa133e429, + 0x4cf51701, 0x8d3685dc, 0x502c8b8f, 0x539b3aca, 0x8f9038f3, 0x0258a23a, 0xb4144c64, 0xaac61f9d, 0x71e0d082, + 0x4a318eba, 0xc2b80b07, 0x76e5f232, 0xb47e7cec, 0x614bc51e, 0x09b13ed6, 0xedea49ea, 0xfecde7a3, 0x848b3119, + 0xfbd5511a, 0x62a25055, 0x806486c4, 0x9ad5bb94, 0x22313994, 0x33cf596f, 0x201d17ff, 0x7438059e, 0xcad73279, + 0xf7a34c0e, 0x2b88fffb, 0x8954cd31, 0xe4ce2c79, 0x924bc9fc, 0x5cb5b063, 0x423bda43, 0x3e468701, 0x8a651016, + 0xc07aeabe, 0xeae3945d, 0x5311c012, 0x9caddc1d, 0x63c45511, 0x56404d5d, 0xd9d5133b, 0x2d63b038, 0xc95b0549, + 0x4fb31d54, 0xead37f49, 0x67a5bacd, 0xd68f644d, 0xead93ffe, 0x7ad49996, 0x3588c2bb, 0x8ce53a61, 0x131397ef, + 0x77f76c89, 0xf893b9b0, 0x8e35f66c, 0x685e30eb, 0x4d97dcb5, 0x4da9b6fd, 0xe2418183, 0xc51d0427, 0xb4aa8b13, + 0x48cfc2b5, 0x8a58d41f, 0xb8d7f943, 0x54bd027d, 0x0c2603a2, 0x79836980, 0xbac18d87, 0x4c367d95, 0xd0232465, + 0xacfaafde, 0x37714f85, 0xa747fb50, 0x047defc6, 0x30d610b2, 0x25758804, 0x22923654, 0x42221093, 0xb34065eb, + 0xce6eca3c, 0x9c3d55be, 0xfc1d3a91, 0xea2ea96d, 0xc02853d8, 0x4f2c22d6, 0x89a39265, 0xcad3b9f3, 0x4973bf16, + 0xa16c5803, 0x8017598f, 0xf2df1c85, 0x65e3f245, 0x9f2cd4d6, 0x6f9a829c, 0x08139fce, 0x2146e840, 0xe3c99c32, + 0xb9bca0fd, 0x9c3f01d5, 0x5e0e5bab, 0x9771ed1e, 0xc0cb90e5, 0xb195b0e0, 0x2e482906, 0x4c743705, 0xa90989f9, + 0xb6a77c9c, 0x9e457010, 0x5c19bb7c, 0x7ed242b5, 0x310a57e7, 0x17203a9c, 0x4fb3d3f9, 0x70d937ab, 0x4e1c0da2, + 0x944aabb2, 0x643f8de9, 0x1dc027d9, 0x4226b942, 0xabe8df5d, 0xc5abc5cb, 0x9b64a202, 0x53362714, 0xd00b48ea, + 0xac4777e6, 0xbf1b206c, 0x58f1c8d5, 0x61337f53, 0x4f9a1eef, 0x86bb7edb, 0x695f2b71, 0xe8414b15, 0x4797c9db, + 0x4afb7017, 0x171cf748, 0xd0e258e5, 0x4d7f0070, 0x710b598c, 0xbb26b719, 0x7ac3ae5e, 0xf42b909b, 0x9fa64da3, + 0xde37690e, 0x30451b08, 0xc0817e8b, 0x28ecc558, 0x16195ce2, 0x82d60376, 0x1ee3e06a, 0xd1800cf2, 0x26d93337, + 0x8108e471, 0x0413d848, 0x1779c069, 0x6e64340c, 0xc3813a61, 0xd727f43e, 0x4a799195, 0x5e5a336c, 0xe3f9acf7, + 0x6df86d84, 0xb5ec6863, 0x0061e5e3, 0xbffee46f, 0xabd116e9, 0xcbffb4c4, 0xce427928, 0x9eded4af, 0x9a7a7144, + 0xee588ae7, 0x96aef2c3, 0x194ee729, 0xa4281409, 0x71d5c6f7, 0xebc2eec6, 0xacac00f7, 0xcdcd0c4e, 0x5d543197, + 0x2a49e3e4, 0xef89046c, 0x1aeab780, 0x493608ca, 0x3b6c5dbe, 0xc1aa52ca, 0x1a19a71d, 0xd42cae73, 0x0859bc82, + 0xb41180fa, 0xc1b2d82c, 0xf2546741, 0x75b967eb, 0x4c10af6f, 0xdf86525f, 0x1fce39e5, 0xe9e891f0, 0xbe8ed312, + 0x772e0758, 0x573122c8, 0xb6781e2f, 0xef153316, 0x5edaf560, 0xde3f111d, 0x61c3612f, 0xfd7801e8, 0xd5448027, + 0x7f543096, 0x6ce063ab, 0xc9f2629f, 0x742bc0f5, 0x3344ac56, 0xca05d409, 0xcf097bfc, 0x48b6d4ff, 0x31c2976e, + 0xb80a57f7, 0x2619329c, 0x89880251, 0x465206de, 0x2eaddb5c, 0xfed273fe, 0xdec90d76, 0x3c797ab3, 0x47cbd98d, + 0x93369d82, 0xa12168b9, 0x2eab7b00, 0xefd33092, 0x0098f702, 0xd952a614, 0x4e2ea9d5, 0x3493a864, 0xc44016dd, + 0x199e50c2, 0x1d5fa745, 0x6dbadfe3, 0xab4f8286, 0xe7a39e2e, 0xf351b25a, 0xaa0f6832, 0xf9eab78a, 0x546f851c, + 0x1db0f93c, 0xa3da9de5, 0x49bf42a4, 0x3e6a3c94, 0x81cfd8e4, 0xfcb2ebd9, 0x1696dc80, 0xad4735e2, 0xa2e017ff, + 0x074ca328, 0x8aead8d6, 0x92153fd8, 0x9b3cf461, 0x61b23744, 0xa023178f, 0x39152d37, 0xc35c6d86, 0x0472edef, + 0x86791535, 0xc15f543c, 0x094587a9, 0x5cae7683, 0x789e4005, 0x1edfc46e, 0x4bba8a2b, 0x4836953e, 0xc2b560b1, + 0x036bcae1, 0x31bb0c50, 0x7a46e15c, 0x6f44d055, 0x95e6cfe4, 0xce91d684, 0x31850ffc, 0x2cc911f3, 0xfb34b1c8, + 0xf1ad7520, 0xb5e2ea3e, 0xf6a3bab9, 0x037f2684, 0x6c31fe67, 0x30336502, 0xf67932bc, 0xa87e6dc7, 0xaf485b91, + 0xc07e349a, 0x3a62cbb2, 0x6c372f2c, 0xd854add4, 0x17943cb6, 0xf4156821, 0x2dce0900, 0x904b83f9, 0x3a426a72, + 0xb63f262f, 0x6396cf2d, 0xcd4b69ea, 0x49e188a4, 0x89ffe215, 0xce33d25a, 0x682e17d6, 0xb5f80c45, 0xd9d299ca, + 0xdb6a0a89, 0x8ad119d1, 0x9b8617b7, 0xa4fe0d10, 0x0f2192e8, 0x69577bd8, 0xb5e7ae23, 0x0b10d548, 0xc22058d7, + 0x01db76a1, 0x4211f86e, 0x6e1f1972, 0x377370de, 0x7136aa73, 0x864b5b3c, 0x94d30432, 0x2f26f72f, 0xc2074105, + 0x2097ea2b, 0x68548d40, 0x226919a2, 0x34180515, 0x8d09103c, 0x28d4a846, 0x9207e76e, 0xff1e757d, 0xfb530459, + 0xc1ddb562, 0xfdc86b72, 0x62a960fd, 0xa5480265, 0xe169ec28, 0xc18aca3a, 0x3ad0038d, 0xb7a55943, 0xde494498, + 0x6bbfe93e, 0xac18509e, 0x8abb23d2, 0x89af0e4b, 0x18c4569d, 0xfcca1c31, 0x386397b2, 0xcda440c3, 0x034f0373, + 0xa6f1b5f7, 0xb2534d52, 0xa159a7b2, 0x22c753ea, 0x3be585d8, 0x861326b6, 0x23a9e3d9, 0x0b01e7b9, 0x4317dd77, + 0xbc26e714, 0x0bb94c79, 0x9b62310f, 0x48ac2c30, 0xeb60ce39, 0x597ae841, 0xa42b5d65, 0x230bf13a, 0x4a6a6c53, + 0x77cf5a65, 0x081764ae, 0xd268dc58, 0xd91ee530, 0xc3411daf, 0xdbd37d3c, 0x048ba103, 0xb9ebc053, 0x46f80d74, + 0x3d3566fb, 0x6701b491, 0x851d9e98, 0x5055fa66, 0x5380359b, 0x4a4bf87e, 0x7c41f09f, 0xe93f45e6, 0x55496b0c, + 0x6f62a42d, 0x89953333, 0x1f21047a, 0x65a97dca, 0x3d61ffa8, 0xf5a1cd00, 0xd7f60c4b, 0x29aea388, 0xa5a6b497, + 0x56259fc8, 0xec1abf35, 0x5374c621, 0x44758674, 0x85e304d9, 0xedd99269, 0xf5c0bab3, 0x52fef8ec, 0xd3e20df3, + 0xbb308498, 0x61aeace7, 0x13f42e75, 0x2e4309d1, 0x524b4507, 0xecaecd05, 0x4c6d0bf3, 0x3497c2e5, 0x266f55af, + 0x61836cf5, 0x254ed055, 0xbeca08a2, 0x69c80178, 0xa60806c9, 0xd5cef247, 0x7a187644, 0xa86db948, 0x204df3c6, + 0x614039af, 0x3242d5fb, 0x6acfc1e4, 0x915d67aa, 0xa7021c98, 0xa9a497b0, 0xd98b036f, 0x9f96b3e9, 0x7f5ce476, + 0x6345cebe, 0x790d8496, 0x9ce5ae69, 0xc88c7c59, 0x840813cd, 0x86a123da, 0xf5058eaa, 0x79511fd2, 0x4acc0c92, + 0x07a2565e, 0x08f23e95, 0xbe02ff8d, 0x736eb34a, 0xfaa8c63b, 0x68f6b367, 0x99434adc, 0xd0dccac2, 0x4c4a8ce7, + 0xda760f4c, 0x353f6754, 0x042e5054, 0x2c190dde, 0xcf8e8877, 0x275ef6d5, 0x64fe06c4, 0x0fdc1a9d, 0xe8c03f6b, + 0x29d7da2a, 0x44e42ed3, 0x5455961b, 0x8ce08de4, 0xcf18284a, 0x51b2f9c5, 0x998f4184, 0xa4ab2bd0, 0x1f26acf7, + 0xdcf93cd1, 0x1a89cf35, 0xedd53fd0, 0x2c56c29b, 0xdbc83d3a, 0xf4f459d9, 0xa1f8b60e, 0xacb135b2, 0xea01c65e, + 0x09f3883f, 0xcbd9e621, 0x7b70f620, 0x519bac94, 0xf73bd9af, 0x95c6463e, 0x8877beec, 0x880c6cd8, 0x5cb1408a, + 0x4f44b852, 0x95968e30, 0xb1675850, 0xf18e5cdb, 0x359c3da8, 0xd2d13ce0, 0x9cad2507, 0x5695a5f5, 0x49f94c6f, + 0x9d3f00f6, 0xcdafcb70, 0x8444d829, 0x1895ee76, 0xbe083c5e, 0x709144a9, 0xfa70b206, 0x37531f98, 0x3f594e41, + 0x14c6ee48, 0x827d409e, 0x1c4da35a, 0x7fd03a68, 0x46563a36, 0x6cba05d7, 0xeb037c0f, 0x599c7741, 0xd9297373, + 0x55a649b1, 0xb17c5f10, 0xd5674e50, 0xb2040780, 0x4ec13f7e, 0xd29ffab0, 0x6a76d84a, 0xdeea0c71, 0xe2eb2651, + 0xe64a372a, 0xc8c0aee7, 0x91a17340, 0xe98912b1, 0x89f8375a, 0x257f218f, 0x44967151, 0xa9015784, 0xb39cc8ac, + 0xe083fa68, 0xb80a9825, 0xf70d02c5, 0x893929e9, 0xe67d5e92, 0x25289b15, 0xc68e2200, 0x9bf82ebd, 0xaf54f186, + 0x7fae80b3, 0x26c0e432, 0xd2e6f157, 0x74d0f27a, 0xd5b0fc39, 0x8d442531, 0xe2695cb6, 0x708bf9f1, 0x2854f3fe, + 0x77b7c394, 0x4a8d568b, 0x885a5496, 0xac562cdc, 0x2184ecc8, 0xe1e78a32, 0x3a5ba7f2, 0x1d8e014a, 0x0c134273, + 0x85e6febd, 0x09b37ae5, 0x362ebb63, 0xf6a4390f, 0x7c2452a0, 0xe6ade23a, 0x09a62040, 0x036cdd12, 0x868acbf7, + 0xf525cea9, 0x76f0938e, 0x11a27928, 0x3ca8eb3b, 0x72c288a1, 0x2b6632a3, 0x37584c67, 0x6a45d262, 0x718f2d83, + 0xf38880c8, 0x3c16daf7, 0x804b0772, 0xd9bbcebb, 0xe18a7b12, 0x635944cb, 0xfa887c2f, 0x64822efa, 0x7213dd0c, + 0x95a53de0, 0x9035435b, 0xbb0156f2, 0x8e9e2a14, 0x81d4c5f8, 0x8a21db2f, 0x724879b8, 0xb915467e, 0x6802604b, + 0xa880123b, 0x94ec6132, 0x78d82c2a, 0x63aa750c, 0x96436cb8, 0x691d663c, 0x030496da, 0x346bb3a4, 0x2aaf0120, + 0xe74b799c, 0xa7d1b7f3, 0x6bc27714, 0x541132aa, 0xb2b6d616, 0x3cd3fda2, 0x30e4c6a9, 0xf632f4a9, 0x650a2df6, + 0x9e9b30e0, 0xeb0e41b4, 0x6bf2515c, 0x2ffe663c, 0x5e360962, 0x8834b1d7, 0x595d6544, 0x5ccc5039, 0x9826e31a, + 0xf27cd1c5, 0xbb059f69, 0x867cf1b1, 0x564009f3, 0x17fece4c, 0x6a77a991, 0xc932ba22, 0xac92f58f, 0xd916bf9a, + 0xa0e949c8, 0xcf5eaad9, 0x8498f704, 0x3f982ef6, 0xd66161ef, 0x60bdbe06, 0x90ffdac2, 0x6a0d9701, 0x7f60b948, + 0x6bd607e9, 0x00492386, 0xfa7ed7dd, 0x6004d56e, 0xdc3daa65, 0xcfc0677c, 0x32925637, 0xf2ccad95, 0x346edcb1, + 0x78064adb, 0x486c2a6b, 0x38ca7d4a, 0x334d11d2, 0xfb29379e, 0xdbde7110, 0x9abb1532, 0x6df29b38, 0xcf0afdbf, + 0xd4b8c41d, 0x72ceb421, 0x146b4ae7, 0x4096e932, 0x016943ba, 0x567baf33, 0x2f9a08d4, 0x52c0f48c, 0xad9ff490, + 0xf31394f6, 0xbad9389d, 0xb4b4b544, 0x23c1dde7, 0x7215d765, 0x4d7cc899, 0x888482e4, 0xcb98bbce, 0x5351a592, + 0x54b52c55, 0x0648070c, 0x3b034186, 0x32389930, 0xb8453df4, 0xf7d62a0c, 0x2571262b, 0x7aa76926, 0x9f73598d, + 0x0a200000, 0x66764815, 0xe3aafec1, 0xf513e1cc, 0x571a5809, 0xb8a197a3, 0xd45e7907, 0xfb48828e, 0x2bd36c75, + 0xe38f46d3, 0x0f7495e6, 0xa8a7c5b1, 0x97799032, 0x8bcf44a2, 0xa5cff535, 0xec250fcf, 0x42146041, 0xbf90722c, + 0xe9c00bc6, 0x3a7eb69f, 0x0b9b86a1, 0xd6e3669c, 0x0a5ad94d, 0x231e785c, 0xfe98a89f, 0x309aa866, 0x2cf27a0c, + 0xd7aa26b1, 0x24ed6652, 0x53f7fbfc, 0xd9d7930d, 0xca2f2c54, 0x7af45166, 0x0d709596, 0x7ed0f2ec, 0x4801ff41, + 0xd71dde1f, 0x30adcd62, 0x92073071, 0x03cb33fb, 0x9d74c51d, 0xeba43a02, 0xf5c7e700, 0x0e074ebc, 0x47b2e300, + 0x9becbd67, 0x21655993, 0x1977aeaf, 0x96aeff3c, 0xae6091ab, 0xe52bc546, 0xcc8cf9c5, 0x55671614, 0x81f0dcd7, + 0x001d2036, 0x798a4d1f, 0x77c5b27f, 0x0be0a42b, 0x7d4411ee, 0x3fe18db8, 0xb982d7b8, 0x9a67328e, 0x159ed59b, + 0xce4afa3a, 0x4f8929d2, 0x3a8d077f, 0xe4f525db, 0x23990cbf, 0x6acf4346, 0x90c52863, 0xb36a8d6a, 0x3d5aeaef, + 0xa6d30fef, 0x62844d5f, 0xaa0e1d31, 0x0013695d, 0x0a3aeded, 0xdb812b9c, 0xf16c5243, 0xda112275, 0x8530977e, + 0x6ea8d3eb, 0x5a66a3f5, 0x17de7a90, 0x816d6312, 0x3c566986, 0xb9224992, 0x0237b44b, 0xde45df7f, 0x97784eb0, + 0x16b2c50e, 0xf458dde9, 0x71f5fba5, 0xf069e8be, 0x5db37a78, 0xd346620a, 0x02a849a3, 0xd76fa708, 0xb7fc0e96, + 0xa2e54e4d, 0x5658c77d, 0xaa007039, 0x45d9f8a5, 0xe72fac40, 0xeeac1b97, 0x6f17546c, 0x8db4bd90, 0x08961ce1, + 0x67283a11, 0x57976797, 0x3b1700a6, 0x3c80a6cb, 0xde0848c2, 0x7ea274d3, 0x7dbe36a3, 0xd547b5ac, 0xba340a97, + 0x9c05ae36, 0xf9ab1215, 0x7227c935, 0xc83eb0c6, 0x5c293c0c, 0xa38d2205, 0x663e214e, 0x099d6283, 0xd53a95b3, + 0xd14ea913, 0xf7268aa9, 0x6246df39, 0x86e3b646, 0x17836289, 0x74959375, 0xf6318ae8, 0x2e0cc9d3, 0x75b7b406, + 0x5941d18d, 0x460593e1, 0xde099935, 0x84b56697, 0x4cdd0b3a, 0xd024669f, 0x54c240f6, 0x883834db, 0x28afb187, + 0xa9c9247d, 0xb407fa66, 0x53109f0a, 0x57a338ec, 0xbdf13933, 0xb9762fc5, 0x61933cbc, 0xb7b5a7a6, 0xd42c338e, + 0x401865a9, 0x89f9f04c, 0xe0458943, 0x58fbe943, 0x9b06896f, 0x6be81dfc, 0x7a903fcf, 0xacdf2569, 0x54d9f0d4, + 0x8828361e, 0xe1dbbe3a, 0x7946dab3, 0x9d48dbaf, 0x3da19bcc, 0x8bf16ffb, 0x4846fa45, 0x7597e453, 0x33425582, + 0x15346093, 0x6a553585, 0x12a4c8d8, 0xb360dd97, 0x421b7063, 0x027ec199, 0x14dd7660, 0x2bd2b290, 0xbb9baaba, + 0x12c9b459, 0x5f0cffdb, 0x629e1e95, 0x8873b43d, 0x30841684, 0x4d34b900, 0x93ce7f66, 0x4f904d68, 0x13a0cc04, + 0x8eb3d606, 0x3072d526, 0x2850b628, 0x1f0bb292, 0x35e9fd86, 0xba6e24e1, 0xe82bebba, 0x2d7095d8, 0xea24bff2, + 0x0fda304a, 0x522fea3f, 0x2b2b1ef2, 0xe81e3314, 0xfef3bf13, 0xfe1e3fb7, 0x82913fca, 0x8aa76c0e, 0xbe1288f2, + 0xa54d5668, 0x63fc4a1b, 0x71aea354, 0x2fde0762, 0x9b71a92f, 0x43fa035f, 0xbd1698f4, 0x4d93474f, 0xb9554625, + 0xc532119f, 0xccc789d6, 0x86e0062f, 0x2dc3d2af, 0x5756ec13, 0xba5772f2, 0xa7b7792c, 0x3b1cce26, 0x285142c8, + 0x1340c8e4, 0x38a60bab, 0xf9072a66, 0xbbbbbf9f, 0x287ee8b4, 0x3d3cc1f4, 0xc7c710d6, 0xba534f95, 0x690de5f6, + 0x043dd9e9, 0xc244305d, 0xcb608c13, 0x295e6f64, 0xf3be17c1, 0x1c039590, 0x375dea40, 0x73f77104, 0x0646b49e, + 0xfb0614d2, 0x7ce8063b, 0x56448b93, 0x1e73837e, 0xf255effb, 0x4cbc4854, 0x417a9a2b, 0x1af74322, 0x75767b97, + 0xfc62fbc2, 0x23be239b, 0x8cfa55b5, 0x9cde97c4, 0x99e3125c, 0xe0cb82cd, 0xfd9b61a8, 0x8c3b924a, 0xab9658f9, + 0xf26fa66c, 0xb62b4aa6, 0x2e641ced, 0x1c7b679b, 0xc7f2c64b, 0x9c31eef2, 0xe7089c83, 0x7b585a47, 0x37980a6d, + 0x575d2af8, 0x24c6ced8, 0x77d28b30, 0xc63185eb, 0xb4416121, 0x0ea1b7f5, 0x84c59889, 0xf4a6c411, 0xfb8af737, + 0xdf6c2e67, 0xfc034c7b, 0x31d5eadf, 0xcb55bde9, 0x63c17317, 0xf771e155, 0x6f21cb2e, 0xb32d7405, 0x765e3de3, + 0x8d1e2955, 0x61440201, 0x85c3bd5f, 0xebcda300, 0xaf1c6276, 0x67e5984c, 0x128de644, 0x2ecf9f22, 0x108f89c3, + 0x76dbbf52, 0x5f61b2ff, 0x0852bda8, 0xad9784bb, 0xf76420e7, 0xb78575cb, 0xb9b8d0cf, 0xc3244f0f, 0xb8062f02, + 0xa7c230fc, 0x17e318db, 0x4d31ca3c, 0x5b2aeb25, 0xb5cac775, 0x3c3cfeee, 0xb5627586, 0x5e75be15, 0xda4b2a2f, + 0x15fce719, 0x4a94856f, 0xea7cddba, 0x607e94fb, 0xe39f4324, 0x93706170, 0x7d6cf155, 0x3b2b440b, 0x453f85ea, + 0xff43e430, 0x3e1718c3, 0x2f816ff4, 0xd8d3d26c, 0x2c11de14, 0xb7b6eec0, 0xef87cf13, 0x6a1cc5cf, 0x8e74b15c, + 0xa6480508, 0x3ec0d299, 0xda385d26, 0x14d57f11, 0x67f5c55f, 0x8edc3221, 0x326828df, 0xf37a8e09, 0xc361ac53, + 0x4c2c7e5a, 0x7b022d69, 0x6d5e75d6, 0x4004e1e2, 0xd6e6f4f3, 0xbcbd985e, 0x5be8b66a, 0xe5d89f67, 0xd3c4a4c1, + 0x0d98799b, 0xd8028cdf, 0x34a7630b, 0x0768f12f, 0x2fc93800, 0xd7096a9d, 0xcb3e138d, 0xfee38447, 0xc57db19c, + 0xad7fd1d1, 0x8adb572e, 0xf412cb51, 0x178d9871, 0xa9968d8a, 0xb0f760ee, 0x46d65207, 0x52db25c5, 0x31dcf994, + 0x105d05c7, 0x0f9f2c68, 0x764320f4, 0x329c6fdb, 0xca3664d3, 0xa5993cb7, 0xd80e8ad0, 0x344a9e96, 0x28da8c62, + 0x3b841bd8, 0xf4337c9b, 0x57f36668, 0xb9b7afad, 0x21496aac, 0xe5a660d4, 0x81a9ef22, 0xd4612dc3, 0x23a619b4, + 0x8fd4e968, 0x72441a28, 0x0abfc519, 0xac81ea4e, 0x1a5523f6, 0xd6ac2f50, 0xa62620b4, 0xb4ff1566, 0x46089298, + 0xcfabe7fd, 0xf3761212, 0x2c81d882, 0x90ccdc31, 0x2acd9067, 0x9263d2cc, 0x3563ad6f, 0xdf0abd95, 0xa30bf315, + 0xba72a845, 0x25f1962b, 0x29d011a1, 0xcd9a0a65, 0x69b4a574, 0xd1cbccc2, 0xc2cea464, 0x67a66681, 0x6d5a3519, + 0xc59f4a90, 0xbff4642d, 0xbadc67e0, 0x7331f70b, 0x3bed8d58, 0xdcdb36c7, 0x0691f006, 0x3f50b269, 0xb36661c9, + 0x84534e78, 0xc2c0d536, 0x978ce48e, 0xbcbd571f, 0x3bd9f337, 0xaa1bd777, 0xb2b3b80c, 0xab89efe6, 0x1f905b52, + 0x6d89b61f, 0x7a27e35a, 0xfa50c289, 0xd246322c, 0xcf1b6e47, 0x3cdcb158, 0x3c062543, 0x1140efd3, 0x8334c7c1, + 0xca1c39b3, 0x2ca98552, 0xeceb9669, 0xcf38411f, 0x69cc59cc, 0x9b56fca8, 0xa88d6a29, 0xf2a83b35, 0x98c572de, + 0x2350c2f5, 0x1859bd85, 0x2dfb9f5d, 0xccdc685d, 0xbd7cb62a, 0x2608bbcc, 0xce46fc06, 0x928d7263, 0x15f29a53, + 0x69fa6544, 0xbb3e04ca, 0xdcfbd1ac, 0xe22d850d, 0xad967bf2, 0x3f7221d1, 0xccaea8c2, 0xe3ffc413, 0x0b2ad509, + 0xb19cbe29, 0x6cd6fb29, 0x0302ada6, 0xb7ab58e8, 0xda66c3fe, 0xd378851c, 0x25abfbb2, 0x8d8a3cec, 0xcd172177, + 0x3443122b, 0x3cbec88f, 0xaa8c8337, 0xa715c23e, 0xbad516ee, 0xba105e12, 0xa3b50637, 0xa821af50, 0x7bca29b1, + 0xb562de71, 0x6c3717af, 0xaae4ab0d, 0x6a48a867, 0xf70c4eef, 0xd1d480ab, 0xbbc4383f, 0xe9f8c5a9, 0xe3ac2ca6, + 0xa073beae, 0xd8450a40, 0xa76e0890, 0xa2fb8b1d, 0xf11c47b5, 0xe6eb1ee6, 0x5d1e2d11, 0x1aad7b98, 0xa6673435, + 0x7c8f3986, 0x26a971fd, 0xe04854f0, 0x1e718eda, 0x0690d27e, 0x4aad8651, 0x84851b88, 0xcf3018b6, 0x4185a3a3, + 0x6ed9342f, 0xde7e54ca, 0x344c4b85, 0x0f4d91de, 0x88bd52c9, 0x3667e0a6, 0xc628fcd3, 0x456f2ca6, 0x99b883b5, + 0x60eb7ba3, 0x0a252686, 0x2540dff2, 0x324149d2, 0x9274c0e1, 0x93f476fd, 0x60e8f520, 0x30ea2e26, 0xe936259c, + 0x3789f636, 0xd342c672, 0xdb35d881, 0x208e8805, 0x64556e2d, 0xf7007587, 0xa1aa3f56, 0x04945375, 0x27548a8a, + 0x58d8dfaa, 0x9a22b70c, 0xc657af33, 0x470dbc6f, 0x115e0df8, 0xc3586918, 0xadcc31e4, 0xc3199ffa, 0x7669af33, + 0xebcb53bd, 0x974ccb27, 0x901fb1d4, 0xd9526939, 0x026676d3, 0x85ec6796, 0x85a82800, 0x4134d25f, 0x19e00acd, + 0xe8b68745, 0x1ea5b152, 0x79220b8d, 0x363e8e1c, 0x6a6f02c7, 0x56de130a, 0x5f00015c, 0xc51c57fe, 0xac26466d, + 0xca796c3c, 0x348c4a3c, 0x63e53f91, 0x4f5187d5, 0x566d7206, 0xe6fe7867, 0x067a1220, 0xf3a8edb6, 0xf442d3a3, + 0xa858fe65, 0xe24e4d79, 0xc8544ca2, 0x57e43ad5, 0x5f57a255, 0xf73e695c, 0x7a4b0dfe, 0x41587c49, 0xe785928d, + 0x4c266d17, 0xc7bab847, 0xaf8470b0, 0x4465d045, 0xf16a133f, 0x476d88fb, 0x6558374a, 0x55f7dc77, 0xc70550eb, + 0x16109548, 0x92f23b13, 0x8b882824, 0xb312cf79, 0xc9d39129, 0x1e3ecb0b, 0xa9d7715a, 0x12c7a71f, 0x33fc6a5c, + 0x626d178e, 0x1041d7a1, 0xbe8e1089, 0x45c782ac, 0xc027bf90, 0xcde5b4a1, 0xd6daad68, 0x29e2f2de, 0x2db78ec1, + 0xe05006c1, 0x34475d0a, 0x304561af, 0x391737e7, 0xb47acb2d, 0xdbd77f6d, 0xb3b27fee, 0x5f90f34e, 0xad7a6c5b, + 0xbfa9cc07, 0x4673e11c, 0x5d0b0467, 0x3c779d3f, 0x077a8a22, 0x42ff3828, 0x11dc9411, 0x89eeea01, 0x671e4172, + 0x868fe986, 0xef7d75c8, 0x2419a2eb, 0x4dc618b7, 0xd229f34f, 0xefca8717, 0xe59e7dc7, 0x9b9c2099, 0x574ec17e, + 0x1e27fb8b, 0xb91a1e24, 0x14c89a41, 0x019696cb, 0xbba44856, 0xdd4b3d32, 0xc4bce3dc, 0x0c895256, 0x3a2e3cea, + 0x0ed6a73a, 0x9c47d93f, 0x044024b4, 0xd54af0be, 0x32742b8e, 0x2949d2d5, 0x28c6859a, 0x1cbbad8f, 0x02e493cb, + 0x318ad49a, 0xfb200d4e, 0x96d72539, 0x2096ade5, 0xc381a1ca, 0x54545281, 0x62f978f9, 0xa7bb35e0, 0xda3fd38b, + 0x3987d138, 0x15527d5d, 0xfeb3ddaa, 0xb62c37ec, 0x4f81e98d, 0x90b4a0ba, 0x314db1ed, 0x177a60f3, 0xa200c6de, + 0xaf2717b6, 0x0c6373ad, 0x0faaa8ec, 0x398777a2, 0xf71ef309, 0x0a562c4c, 0xc013b376, 0x15868310, 0xf56f7fa2, + 0x1ddb87be, 0x78319426, 0xaeb159ad, 0x6177f55e, 0xd54a5e0a, 0x87b6deaf, 0xb526daa5, 0x1809d4c7, 0x73d6e1e3, + 0x691aea97, 0x1ee5f97e, 0xd5f7d201, 0x6aec697e, 0x53471bfe, 0x3bc6d5ac, 0x925dba14, 0x7e20417b, 0x50f750e5, + 0x0ee17274, 0xafa5204f, 0xf6bebb7a, 0x56a7a84a, 0xd6f0f90a, 0x3a89a3d2, 0x5add9c9c, 0x93d50abd, 0x29347029, + 0xd51e8876, 0x8c8007c8, 0x791fd710, 0x56caecca, 0xa39b9506, 0x0a9aea3b, 0x099560f7, 0xf03e83f4, 0x9edac46e, + 0xc195308b, 0x99d8c830, 0x592f0749, 0xa3149a09, 0x3e9ae370, 0x46d7f763, 0xa78cb846, 0x1e21e0e0, 0xbcaf22ee, + 0x63202e4f, 0x5b1a38da, 0xb21c0c2e, 0x46e5e0fe, 0x1596ef43, 0xaf0bb8fd, 0x566e54c2, 0xd85c1110, 0x92394139, + 0x2c3482a5, 0x47ca47ea, 0xaf1720bd, 0x5743c3de, 0x2429f98c, 0xa3374976, 0x8deece99, 0x5e6f2554, 0xa3704652, + 0x821b3e7d, 0x03977f40, 0x1478f7b4, 0xdbba8d09, 0x36fe8acb, 0xcde54dc8, 0xe2e77767, 0x7d29cbae, 0x46b5e9f5, + 0x3933df78, 0xf3a249a1, 0xf9138a16, 0x369b45fd, 0xdad03930, 0xe80abdf0, 0x72112c1b, 0x2b486667, 0xd2c30c10, + 0x32b4ec76, 0xad649e55, 0x8dbd15ec, 0x702b8538, 0x3f2b6e1b, 0x4c60df50, 0x905890d8, 0x10ccd050, 0x9c308bc8, + 0x802ffc3f, 0x8df2ff2c, 0x4279a8ce, 0xc83ffa06, 0xdeeffdfa, 0x5d952890, 0xaf0a4e1b, 0xa1458c86, 0x3b11cc71, + 0x49f3cfac, 0x0e2677ea, 0x0f44bed1, 0xb06fbde5, 0x2e029323, 0x92809aeb, 0x330daa41, 0x3e358494, 0x017cba07, + 0x2e5807d1, 0x675aea99, 0x02542b9a, 0x46becb5d, 0x3a61d887, 0x8bedf010, 0xfc509f56, 0xaa3f1b20, 0xaa467bfd, + 0x65a7787a, 0x94a95f64, 0xbc0b8603, 0x3c9d3878, 0x7624d8fb, 0x8ec74bc8, 0x12c029a6, 0x4304e8a6, 0xb6785a8f, + 0x2bd40ece, 0x8c430407, 0xb8b2ca0d, 0xe82d8ab5, 0xdbe978a7, 0x83ecd3c1, 0x1fa19033, 0xa5861d66, 0x9aab40a8, + 0xe7976930, 0x9e21bb55, 0xadce6764, 0xb6e98cfb, 0x6b3984d3, 0x020be0ad, 0x9d1364b4, 0xd49d7314, 0x622016eb, + 0x85636648, 0xa6f93237, 0x4187fdc6, 0x0a605c32, 0xdc4b8fdd, 0x794a157e, 0xe8091558, 0x7aba0d0d, 0x5f5bf67f, + 0x830e430d, 0xc74c870e, 0x0dc3fd71, 0x0632a13a, 0x9599059d, 0x9529c9c9, 0xfb63f97a, 0x2f8a6923, 0x438d5a87, + 0x2e6d9e88, 0x33c07750, 0xb017ed67, 0x98f4425e, 0x8a3d2bdf, 0x8bbc2a08, 0xbebba588, 0x3fd60a04, 0x1cc13e16, + 0xadef12f1, 0x341b6932, 0x1ba99a46, 0x29011035, 0x3121725e, 0x0edc8667, 0xce138306, 0xb2efcb21, 0x65c04ecd, + 0xc7b0ef6b, 0xade7d1f1, 0xe5bad0c1, 0x76ecf0b2, 0x3cc4f1ad, 0x1b036305, 0xc72add64, 0x37982465, 0xfed758e4, + 0x531029dd, 0xe2f068e2, 0x0569deb1, 0x7bde4464, 0x03cdb6e3, 0x13f551e5, 0x8bf5303e, 0x4419dddf, 0x8c02f10a, + 0x58607301, 0x73cff86c, 0xfccc9d32, 0x9001f5a3, 0x59a319f9, 0x1a47c4c1, 0x21b92223, 0x3880279b, 0x5b156f11, + 0x23f0e4c1, 0xba693bfc, 0xec6d5c89, 0x4f1585fd, 0xd30eee20, 0xbb6937ae, 0x5e593414, 0xf01c8fea, 0x62eb77a9, + 0x92c11b79, 0x5e3017a7, 0xebba7e5f, 0x39a932eb, 0x4c8fbfda, 0x1c7cd86d, 0x221d3ddf, 0xd976473f, 0xabcbf8a5, + 0x9aac84cf, 0xe0687de2, 0xbdceb750, 0xae3ffb30, 0x60937a20, 0xf642e30f, 0x9395f4cf, 0xeaa67631, 0x52a19fa8, + 0xf9506437, 0xc0dd7ead, 0x0116829a, 0xe0f1cb42, 0x7edc8d7e, 0xc199f3f9, 0x17d16dfa, 0xe1ba26c0, 0x5d94ff98, + 0x59696a0b, 0xc0329838, 0xf9db5076, 0x4b9eff42, 0x8aba048e, 0x3b2cc528, 0xc984586f, 0xac94b1a5, 0xc0c9e3e1, + 0xe21de53b, 0x351c57a2, 0xd48e4d04, 0xe2ab24b7, 0xf258d152, 0x03aa222c, 0xb77a43cb, 0x4999dbbc, 0xc8ecf44c, + 0x874554b2, 0xad7516b5, 0x3cf56caf, 0x90709628, 0xe96870a6, 0x3707b551, 0x37a934ac, 0x98c88ecb, 0x357cbdd4, + 0x3149c559, 0x55368292, 0x3a986bb8, 0x359a778e, 0x76a95ba3, 0xccf79f10, 0xa736b81f, 0xf1f05696, 0x5f2186e7, + 0x4e79cd85, 0xbb570839, 0xb237d1cd, 0xb54948ad, 0xab23ebb3, 0xa8e2539b, 0xf3622466, 0x4422101f, 0x0824280a, + 0x0f4cc4c4, 0xc08b6153, 0xd8cffb47, 0xda0cf680, 0x68988922, 0x46d78073, 0x156f7ea1, 0x4224216d, 0xf66c2cc7, + 0x61ccd5a4, 0x6ebdc922, 0xe7e3c348, 0x7f39b5cf, 0x04320c0e, 0x8f0938cd, 0x58db3036, 0xd2edb495, 0xf689b466, + 0x05af0f40, 0x83087716, 0xbd6d29de, 0xa30c02e0, 0xffbb098d, 0x5d475d6e, 0x4f7dc30d, 0x90f8210d, 0xa12a1904, + 0xe0fc4a10, 0xab8304b6, 0xc7c81535, 0x7e35a548, 0xca4f52a9, 0x8eef5446, 0x354cbe6b, 0xc6fc7fd5, 0x498449ee, + 0xb12b770e, 0xa204af97, 0x3b94fbed, 0x4a75d054, 0x90780f56, 0x93147bb2, 0x51d4fe43, 0x74e4bc06, 0x7719e525, + 0x4fe27181, 0x377209d8, 0x55e7ac26, 0x9801c23c, 0x9662452f, 0xd238c09f, 0xca0db7fc, 0xb8e83161, 0x78a5ba86, + 0x0554533f, 0x82eb9a6e, 0x8ca2ae33, 0x671e2223, 0x7d2ff067, 0x4fd0bcc4, 0x5dcdee5e, 0x8d187fcf, 0xd72e65ed, + 0x348ced80, 0x97dbd5a3, 0xa434bca1, 0x57c80b13, 0x7454bc32, 0x4df00788, 0x48f40927, 0xb60c8e59, 0xd0bc4f5c, + 0x1723701b, 0xa70b9bd0, 0x0ffcf96e, 0x37db062a, 0x99c92c44, 0xd0c02768, 0x1a00973d, 0x14cb0ab6, 0x3c2640c6, + 0x2a81d68d, 0x64de25da, 0xccd9fcb4, 0xe161a5f3, 0xcd1ce447, 0x0f560e54, 0xf19222ef, 0xc444259c, 0x3b922852, + 0x6f86a462, 0xb1fd3410, 0xb908178a, 0xd4002511, 0xb65c72ef, 0x44181dc4, 0xedfcf485, 0x8ed7e983, 0x377d75fc, + 0xeb60dc7a, 0x8bd6c98d, 0x6860039a, 0xe170fd7d, 0x69427462, 0x801e43cd, 0x647f2b06, 0xa55c559a, 0xf5913bc3, + 0xcaa4fe5f, 0x0d3ad1e9, 0x321fb23f, 0x5a15fa3f, 0x61d15b2b, 0x036bcb1b, 0x33a01d93, 0xee178f2c, 0xa90838d9, + 0x0da96c89, 0xe21c264b, 0x0521fda3, 0x96d3eede, 0xec5e14df, 0x1bdf4d77, 0x0f1bc305, 0x1d0ba3af, 0x583bc764, + 0xed41a668, 0x656a35ba, 0x17c8d558, 0x749d3cd7, 0xb6996b6e, 0x50d9c3d6, 0xb8bedb4b, 0xf6c3d06b, 0x3bf776c7, + 0x65fea06e, 0xf7149856, 0xad6e5143, 0x7a7c2d82, 0x93460630, 0x441eb88a, 0xed425bac, 0xaa843149, 0xa2aac8eb, + 0xb7a17c15, 0x2097b60f, 0x9ad5177c, 0x1be004b7, 0xf1048c85, 0xc596fbef, 0xb27c1a42, 0xe89cd0cc, 0xff876adb, + 0xcabca370, 0x1fb1d956, 0x43f29661, 0xebf1da58, 0x09920847, 0xe48a059c, 0xcc9e35f4, 0x708553ae, 0x9efbf2fc, + 0x8fcbe8de, 0x55332357, 0x15794928, 0x8dc35b46, 0x361934ba, 0x450e9328, 0xfe29ac7c, 0xc4bbd0be, 0xa0760d5f, + 0xec15b95b, 0x596bfa9b, 0x4e82d4b2, 0xe8eacba4, 0x607ee5f9, 0xee3d0b55, 0x2c3cd77f, 0x6aac3741, 0xf4b8657e, + 0x2225d28e, 0x81777238, 0xd425f351, 0xe0f6f7e4, 0x0d8165ff, 0x432536a0, 0x4d0fe0e7, 0xc03474c1, 0x5f041470, + 0xb5153fb3, 0x8d2615c7, 0x7cd63344, 0x5c3884b3, 0x36ff0242, 0xa7104b0a, 0x23e0bc3e, 0x67670c8c, 0x6170bfe4, + 0x9c5b443d, 0x3c81694c, 0x5664784f, 0xb735237b, 0xd2a528fc, 0x5c2f3a26, 0x04acedf4, 0x806ddda6, 0xf7aeedfa, + 0xf12cc3be, 0x5dd1e49a, 0xe955ee54, 0xf6139fe9, 0xde2fa70d, 0xdbf357a5, 0xa5b2d066, 0xadb2f9f4, 0x7962dfa0, + 0xd3e869a4, 0x7d41aac9, 0x9071cd97, 0x96c72e6d, 0x6e966850, 0xafc39e72, 0x95e8d03d, 0x562a2376, 0x1ad98f7a, + 0x94698c0b, 0x6d89070e, 0x6d12ca3c, 0xc25da58c, 0x3364f3da, 0x560a0f7c, 0xf2da0d23, 0xc09cae51, 0xa74f3c24, + 0x34cd9c0d, 0xaca48ad0, 0x75be9664, 0x633be76b, 0x00c555f9, 0x3cb8e020, 0x50c2fe7f, 0x0677bec0, 0xc921f633, + 0xb216e4df, 0xb2fa2625, 0x36002b3f, 0x65189611, 0x4d6c1066, 0x5935b9db, 0xe0f4e57c, 0xaf49abfb, 0xb1ad8284, + 0x59b8e1e2, 0x5e87942d, 0x8340935a, 0xce91ee32, 0x15e9dd12, 0xa6ad1f27, 0x5a23aa9a, 0xa4b8b47e, 0x02d970e5, + 0xaf0bd687, 0x6b752afc, 0xa10db520, 0x658ae82c, 0xf8821d20, 0x21396f99, 0x1f1655d3, 0xf453e6bf, 0x92b72c0f, + 0x0c780162, 0x10af30b5, 0x42d4780b, 0x234726a4, 0xb9cb5d91, 0xdf638ae6, 0x95ee49b4, 0xaad3f3b8, 0x570be08e, + 0x59c515f3, 0xced02af8, 0xb182350c, 0x4d21488e, 0x52b10f81, 0x7a8c3c8d, 0xf55b90b5, 0x295cb6dc, 0x38736792, + 0x2449e392, 0x57c88599, 0x22b9357b, 0xf73f2a9e, 0xd52ad37e, 0x2462a06a, 0xbc4f712d, 0xf2276b65, 0x551f2898, + 0x2a90d745, 0xad2c8cf5, 0x428cb86a, 0xe8afa7e8, 0x12a46e23, 0x348bc28b, 0xb7379d07, 0x71e4681f, 0xdbfa2a4f, + 0x699e3e0f, 0x4c20a51b, 0x6b816d9d, 0x1c11d87a, 0x8e71e40f, 0x5f2cc324, 0x186a7e9b, 0x8d64227e, 0x40e50710, + 0x115dda9e, 0xf1182f82, 0x035ee319, 0x13417035, 0x7880aebd, 0x1eba5c75, 0xf8a3b4f0, 0x5daa41b3, 0x80f740b3, + 0xc6e5d4e3, 0xc629bcca, 0xa427eda1, 0x86dad440, 0x8b97dfda, 0x9ddc8f74, 0xa8ca991d, 0x1716cbdb, 0x774234ce, + 0x32d49ae5, 0x9fcd04db, 0x24e309ba, 0x6a9eb6a0, 0xab87f801, 0x2b5c025f, 0xa4c12af1, 0xc48a454d, 0x48381313, + 0x916de653, 0x7b0dbfff, 0x8d5dafc9, 0x758881ab, 0x3daa7229, 0xa22ab828, 0x68710909, 0xfc9b7b3c, 0x98a3612e, + 0xfd78a21d, 0xd43c1020, 0xc0661c74, 0x6c63aeca, 0xe50a063e, 0xeb3899a5, 0x289a3f8b, 0x0aaae2a3, 0x58bdc89e, + 0xa0d00444, 0xd615c0d9, 0xe384df28, 0x01c7a950, 0x01a50a54, 0x910485c1, 0xa00a3fe6, 0x51496a1b, 0x63bbc03b, + 0x92136f47, 0x83d69a14, 0xf2e69dc4, 0xa934cf1b, 0x3b71bbe0, 0x1a1851b5, 0xfbb07b86, 0xc79fce3b, 0xd273a060, + 0xacc286a0, 0x992e05cc, 0x44948ab0, 0x13347743, 0x32907d37, 0xedd0dcb3, 0x4c291546, 0xb8656d37, 0xcf1b7ff0, + 0x40dff3e6, 0x471a77a4, 0x9f66b8a5, 0x6873bfb6, 0x710bfdd8, 0x9ebe7a43, 0xe0d6d7bb, 0x6ff93f07, 0x6cbf8633, + 0xd115c9a8, 0x905a7964, 0x28cb78c1, 0x5be6a432, 0x3da27aba, 0x410a6bc1, 0x9de245f9, 0x18c6a4b8, 0x9a70f206, + 0x61ec525f, 0x3d95ee85, 0x107c1ebf, 0x268732c8, 0xfa962ec3, 0xd10606a7, 0xcff44dd7, 0x3b9f4f71, 0x4501f6dc, + 0x76369239, 0xdf29448e, 0x079c4487, 0xb7069eea, 0x06baf5e0, 0x9113f6eb, 0x12c4bc00, 0x8d84d499, 0x31018d18, + 0xf7deb9c4, 0x2ae70ffd, 0x6e482df6, 0xeffd0086, 0x0a499afa, 0x5017ce10, 0x61b247b1, 0x3ebd1e62, 0xb844f375, + 0x58eeaaed, 0x3d0bb234, 0x971fa809, 0x57c4381b, 0xa4ed9ac0, 0x85f8743d, 0xe917a988, 0xd4c47acc, 0xb623c4e8, + 0x4933f09e, 0x5686117a, 0xb60abade, 0xc0dc25e0, 0xf55aafca, 0xbf912fba, 0xffa41231, 0x6647affe, 0x72523992, + 0xdad6c533, 0x6e6fab1b, 0x3d51bc0e, 0x83ba0663, 0x56bf842f, 0x44320371, 0xf3eaa481, 0x8942ed11, 0xc81cdb34, + 0x5b27774e, 0x40c2ec9b, 0xd5d302ec, 0xff0c4ef3, 0xc80e4d29, 0x82452909, 0x1a44b460, 0x94a68a60, 0xd0f26a14, + 0x04eaf6dc, 0x2773c503, 0x1c07a8f7, 0x1b2a273d, 0x9694df2f, 0xf7d7698e, 0x98012c5c, 0x32023ab9, 0x057ce125, + 0x8395f38e, 0x91abde28, 0x7377bff1, 0x3ff7d95d, 0x2f696bf8, 0x4f55fabc, 0x5b5a84fb, 0xdba71a9c, 0x002ced23, + 0x220ebd37, 0x635e067a, 0x1dfb9cc8, 0xdab1529b, 0xec10852c, 0xfe8408e9, 0x5de0c595, 0x977ff91b, 0xe1df2b31, + 0xda0d5c3f, 0xeb274a7d, 0x8cc920da, 0x0f8a3e71, 0x849fb4f2, 0x5d522a3b, 0xb9cd52ab, 0xe64093fb, 0xadd373fd, + 0x28271d1c, 0x917784cd, 0x399bcd07, 0x16034b87, 0x99334de0, 0xaf9560b3, 0x6bba1fcd, 0x8bad1e86, 0x4ff0fc05, + 0xa5535304, 0x56553ef4, 0x11812ca2, 0x53956a23, 0xf43619fc, 0xcbdc5426, 0x48aa1611, 0x12ebd87a, 0xbc2bc6f3, + 0xd6064804, 0xb6120dce, 0x990799cc, 0xddcf21d0, 0xf9f631d5, 0xc6020b04, 0xd60bf11c, 0x192a4e6d, 0xbd898eef, + 0x9f73a267, 0xfa19671e, 0x7ff5ccd4, 0xdfec575a, 0x584bb3bd, 0x45752f16, 0x6893c011, 0x89a6da56, 0x49349362, + 0xd29a170e, 0xc663562a, 0x21657a50, 0x27268054, 0xd484bb31, 0x39378582, 0x58c88c3a, 0xc15846d4, 0xc2517acd, + 0xe3d1c759, 0x31d3f9e4, 0xa637362d, 0xdfd95fff, 0x137e2cb4, 0x7887116a, 0xa9b1e2e8, 0x3b72ab8a, 0x8ecd72ba, + 0xa83063b1, 0x8ed7dd31, 0xbf4eaadf, 0x14f8b988, 0xeb4dbfd6, 0xa9dbc9ce, 0x4fb64ad3, 0x74f2b57d, 0x9026a7bd, + 0xd031a780, 0x4fe31b20, 0x858c8f93, 0xc09a5e22, 0xe9523f79, 0x265c4446, 0xaaaaa9b4, 0xccb41a46, 0x7f56c087, + 0xd43ac780, 0x9a1119c7, 0x9713a1f8, 0x1b541dd9, 0x0192f385, 0x0b3831a2, 0xd6b56a11, 0xda1b9798, 0xf235d419, + 0x25d82998, 0x242cd3ed, 0xfdb0afaa, 0x778269fc, 0x459b26ee, 0x7ed5cbba, 0xef432acf, 0xe74156dc, 0xee7f20e2, + 0xd0f64406, 0xc9907b08, 0x519c179d, 0x12325241, 0x0d9bcd75, 0x61c944fa, 0xc238fe1f, 0xe7c02c53, 0xe59294f1, + 0xeb5fc51e, 0x82c58401, 0x530b68f5, 0xbc7a2b29, 0xc8341e42, 0x09385883, 0xe73a39d8, 0x22e73ba6, 0x0a343a05, + 0xb38946f4, 0x6a36042f, 0x8f71716a, 0xb0adb49e, 0xb6914eb6, 0x1ed80e45, 0x5a7c381c, 0xa52aeb90, 0x89427392, + 0xc7b6caed, 0x6c6fe9d9, 0xc58dadda, 0x40861e49, 0x0fbb840d, 0x1bc9f955, 0x5aa3370e, 0xf2be4a82, 0xf02d23df, + 0x6e763ff5, 0x0169252d, 0x866c7ffb, 0xfbecdfb2, 0xd12a7d2f, 0x704b5681, 0x16deb972, 0xeab390b2, 0x3b90dfef, + 0x3834df20, 0xd63d4b94, 0xe0c6e6c7, 0xfb733031, 0x40540b01, 0xd509a959, 0xc3332178, 0x788adbbe, 0x5243b17b, + 0x3db5692d, 0x1f6cf614, 0x44db9071, 0x625b3c01, 0x5e8c410a, 0x351ce599, 0xaa53a974, 0xcd107b49, 0xb337d4a5, + 0x864ca85a, 0xc9bdbc3d, 0x7a9cc16d, 0x994227d2, 0x4bad6fab, 0x816b26b4, 0x8fec5ef6, 0x4598dd57, 0xda14c82b, + 0xf334298f, 0xb5a8fff6, 0x640beebc, 0xe25d0bc3, 0x78d8dba7, 0x5e2edf3c, 0xd83eb073, 0xfe8075cd, 0x6531fb19, + 0x615d3484, 0x266df9ef, 0xf28b3de7, 0x5e80b53f, 0xd2ff5440, 0xf82b7688, 0x0b788ac8, 0x6f4062f1, 0x40184715, + 0x0f56f2ae, 0x300d3418, 0xf3088e52, 0x42882c72, 0x25533739, 0x6bcf3795, 0x03411acc, 0x2e1fcd23, 0x31bb0710, + 0x1765f818, 0xf8fefba0, 0x2b1af5db, 0xfa99149f, 0x39b187ce, 0x2921a30e, 0xfc364fdb, 0x0f7cb401, 0x987350b3, + 0xf285dade, 0xfbfd5f61, 0x60531d87, 0xad29721e, 0x1a52a8c8, 0xb47b1baf, 0xdd238695, 0x1c93e419, 0xb80b806c, + 0xe313018f, 0xf5be68bc, 0x2758cc9a, 0xf338e3b0, 0xccfb9db7, 0x501f20ca, 0xdf9bbc08, 0x14641bc0, 0xd6830952, + 0x653bd509, 0x65a74902, 0x1097798b, 0x0d7adb6a, 0x8968e8f0, 0x88c5084a, 0x5bd5febc, 0x9ef5d876, 0x00229c6b, + 0x6cb68dd2, 0x2d87b771, 0xd65ac4e8, 0xa56733e6, 0x64804d52, 0x58d7d5e9, 0x437bf2e4, 0xe864a06f, 0x5785764e, + 0xcd6c25ab, 0x76160beb, 0xad202fc0, 0xc69e4a90, 0x44239ffe, 0x7466e16e, 0xd0c437b8, 0xd88dc289, 0x3f4c9337, + 0x0ac4b5b3, 0x470a5b1a, 0x30f5d0f3, 0x1ba803e0, 0xaa87726d, 0x905f3cd5, 0x3bec0399, 0x2129af37, 0x773c7743, + 0xefda0000, 0x919e94f7, 0xa5ce481a, 0xeeae83eb, 0x1ab98f97, 0x3cd581ff, 0x102355d0, 0xc14cd694, 0x5036c815, + 0xa31045a1, 0xa0c9e206, 0x82f31154, 0xb10ddd84, 0x27ecabf3, 0xe8716ee7, 0x833398d7, 0xeff92444, 0xc0484388, + 0xc17949bb, 0xba52a733, 0x1fec7c24, 0xbc52ec95, 0x0386df05, 0xdf78bf9e, 0x455226b6, 0x29ff0aa2, 0x6e705f8a, + 0x1ef9797d, 0x09a54ad6, 0x16161b0d, 0xfd82581d, 0xc395b81c, 0xe7ba9bf4, 0xd034e7ba, 0xcfac6f36, 0x0cd5deb7, + 0x1dbe711a, 0xd196d66f, 0xf964dc81, 0xca185aa1, 0xfce45a16, 0x6a90d83c, 0xf61a57f4, 0x5e678e50, 0xa0087dc9, + 0x0a5c152f, 0xa83fce2f, 0xa5263025, 0xdcc2a55b, 0xb28d2e9c, 0x491f99a5, 0x2bc2e8c7, 0x55be3185, 0x42f19990, + 0x4a85382a, 0x76012dd0, 0x90dd8ed5, 0x4e8c4e7d, 0x9de55afc, 0x48adb4c6, 0x84f62dba, 0xa2195b55, 0x17e9bec6, + 0xf9e56d11, 0x2b67732e, 0x469c2cc0, 0x442c0087, 0x804e70c8, 0x93dac3a5, 0x74d34e8e, 0x8c4bda9d, 0x539cf786, + 0x32e8b72d, 0xeb9d8c92, 0x28eacde7, 0x2ecbc46a, 0x29dc34f1, 0x64f53d21, 0xba09a8f7, 0x5cd75fc0, 0x8bcf70f7, + 0x670bb08d, 0xd6491cf4, 0xf71139cc, 0xa8598d62, 0x151ac2db, 0x666723bb, 0x58ee3583, 0xc0005c3f, 0x3f4b593c, + 0xf5976f54, 0x3b2c8d0c, 0x5e877d2c, 0x10333ca4, 0x1fe2f866, 0xa63c6ba0, 0x7c181472, 0x54b075d4, 0xb2175f0f, + 0xf9bdf2aa, 0x256b9de0, 0x3edaa053, 0xe3577ae6, 0xa579ac01, 0x908da957, 0xab53dfa5, 0xcb6525df, 0x5b107e12, + 0xef094277, 0xc085e476, 0xe3e812d0, 0x1ac89228, 0x935a9a90, 0xda12e2fa, 0xaa3e7ccd, 0xec313646, 0xfa483687, + 0x7487cf2a, 0x8ce11cf6, 0xf764f55e, 0xb8ddfce3, 0xa5aa7e7e, 0xfc86bc18, 0xc16bdc96, 0xa0636ea0, 0x6752b2af, + 0x0860bfee, 0x6367f074, 0x27fee7c3, 0xa983ba21, 0xea533178, 0x7b47619f, 0x983b8f95, 0xe1cadea2, 0xca6d193c, + 0x7284d044, 0x68355879, 0xaa2e2566, 0xf7f32ac4, 0x7d937e2a, 0x81286e54, 0x2e80ae8a, 0x67afdec1, 0xd6b9c72d, + 0x913bf1bd, 0xd27309b8, 0x176f5f29, 0xb298162b, 0x90488b58, 0xd28668db, 0xf9f0147b, 0xd24d0c04, 0x1af247c3, + 0xf0b712eb, 0xeb263c5e, 0x8d85052b, 0xf3fa0938, 0xc12487ed, 0xf5619fbc, 0x5a5ed01f, 0xd69da773, 0x9af6df21, + 0xf61040b3, 0xb5953c12, 0xf9d79803, 0xdbd97ff0, 0xd49ceb9a, 0x9c0f0635, 0xc5dfe3c5, 0x512a508f, 0xdbc0152a, + 0x04a945c3, 0xef343f99, 0xfaee501f, 0x6bd58b77, 0xad866edd, 0xf9266e0c, 0xba5c0560, 0x481e51a1, 0xa0ad5601, + 0x9f0ec8b1, 0xb1da18e6, 0x627811f2, 0x9e2b86a5, 0x2d769f64, 0x78616f0b, 0xbb6c3d90, 0xbcf19fe6, 0xd37982a5, + 0x2282d94b, 0xeea94e9d, 0xf1fe1f32, 0xdd5f895a, 0xa6787ea8, 0x744b5e8a, 0x865fe76e, 0x9594a68a, 0x12475080, + 0x3ae7d738, 0xc9d800ea, 0x79b95661, 0x9b305325, 0x25324200, 0x94e29d80, 0x8230eca0, 0xeac1e526, 0x37c3107b, + 0xaefe6150, 0x9f9906ba, 0x5a954657, 0x053f4d5a, 0x0052bb6c, 0x5c8c9fb4, 0x7f503c06, 0xd295ea7f, 0xc512318f, + 0x7c5b2ee2, 0x18439414, 0xceda611c, 0xe003be68, 0x53342bc5, 0xd9503ccc, 0xdf603e43, 0x4636cf62, 0x2fed1c03, + 0xa28e306d, 0x887d71b7, 0x4ed850fc, 0x67c8eae4, 0x73ed3b37, 0x3a89fdc2, 0x56b63b11, 0xb27f93bd, 0x53d1124b, + 0xb14b9423, 0x465852f5, 0xe6ae68b2, 0x92d60d88, 0xf43ca6fe, 0x5807a940, 0xfbc44413, 0x110ee827, 0xfa6d56ac, + 0xc0ea8321, 0x4e5dcc96, 0x197dbfab, 0x0b75b718, 0x444a784f, 0x0243fa46, 0x57c657c7, 0x781e9b6b, 0x8c4f6671, + 0xb8b28d56, 0x63530a74, 0x73708ee7, 0x3bf3558c, 0x36a8ee9c, 0xce234370, 0xa25367aa, 0x836e2a81, 0x8006a1e1, + 0xf423d2d4, 0x0f06cd6c, 0xe875dd71, 0x14152c18, 0x87bd2bf7, 0xc1842a63, 0x845bf56e, 0xb80cc6f7, 0x89846ef9, + 0x64398c67, 0xab399323, 0x622a5349, 0x05e88b27, 0x10fcec14, 0x63ba31d3, 0x114c858c, 0x9e0a6d1a, 0x719dda15, + 0x8738d8bd, 0x35a6f189, 0xe23be2d4, 0x40bf68d0, 0xeb101942, 0x1dc86bcf, 0x8edee1bb, 0x68a0100b, 0xd5802be6, + 0xe2587530, 0x4516e1b1, 0xb26bdeef, 0x35e688e3, 0x9dcdcc94, 0x3d5f0f28, 0x7b756d43, 0xb49846bb, 0xd242382a, + 0x22394e41, 0x58d33f16, 0x49db8535, 0x36e2a9e6, 0x3464255c, 0xef64ff73, 0x639e42f2, 0x50e34ede, 0x23777f73, + 0x3a0636d9, 0x428f5844, 0xacb57ad1, 0x1bc5505f, 0x52beffa9, 0xcc623330, 0x882e1058, 0x4d68b0ad, 0xe73b3d8d, + 0x078ef2a8, 0xa5e4a11e, 0xebc5b19d, 0x044a520d, 0x4717a44d, 0xd9354eaa, 0x279d16f1, 0xd479e8c3, 0x5caea4c5, + 0x81364a21, 0xd0c082a2, 0x4fd60a8a, 0xdbfb4081, 0xcd0e6ace, 0x0c57ae9b, 0x855491b2, 0x6a8f08e8, 0xb55bbdcb, + 0xb0c57891, 0x2f21ed05, 0x0378bb6f, 0xc50fd7c4, 0xa7b30c09, 0x4c446448, 0x01e14ffd, 0xe70cc5ec, 0xd4d1e404, + 0xfffeb1f3, 0x63ab1f2d, 0x9b4b0334, 0x86d0aa2c, 0xf24c5b9c, 0x218ff2ce, 0xe09ac4b1, 0x9d094c7c, 0x2b3029cd, + 0x346fc2dc, 0xbfe58fd0, 0x1dffefce, 0x66908c20, 0x1a9de864, 0xce674207, 0x84a76617, 0xe40ec99f, 0x5421dc66, + 0x2b2dda45, 0xc30ab343, 0x1330d93e, 0xc8947338, 0xc7d1ed91, 0x7b7173e8, 0xf409e9c7, 0x93df3067, 0xafa397d9, + 0xedded304, 0x57228ef8, 0xa2c72a08, 0x9533d7f8, 0xacbe5535, 0x27958cf6, 0xeea9fb37, 0x7fe0d3f6, 0x2198a6fe, + 0xb0a653fc, 0xbf1fee6f, 0xa3766299, 0x9f0de70b, 0xef71fd22, 0x0304bb0a, 0x1ffe3b09, 0x10c98a09, 0x7947386c, + 0xdfbc7d1b, 0xf211e1fd, 0x3595a33a, 0x85924bf1, 0xb7fdb870, 0x55db27a3, 0x3752d5e6, 0x5e6e7df4, 0x6a450248, + 0x1c23cb89, 0x80744937, 0xa41e325d, 0x5c0fbf30, 0xd0b734ce, 0x9a9e99a7, 0x3324e8d0, 0x0b18bf9c, 0x98124ad3, + 0x3a1e431a, 0xb05ef11e, 0x85a23896, 0x75026d0f, 0x96540aa6, 0xa346bcbe, 0xcc0acf52, 0xa8ac7d32, 0x326f5d4a, + 0x212b4623, 0x0bc46da6, 0x6b4066f4, 0xa0ee4127, 0x89c3a47c, 0x08f64b9e, 0x92543fd3, 0x6778acc4, 0x4d5a5391, + 0x99fc4dd4, 0x8057645b, 0x2f50dbdf, 0x244fb594, 0xdaf775d6, 0x41860577, 0xd61f01ae, 0xcb317dad, 0xdb82c9fa, + 0x066518c1, 0xadf87384, 0x9b7487c6, 0x1dfe5e46, 0xd0124a66, 0x9ea822b9, 0xaa9cfcaa, 0x981b90b1, 0x6eedc705, + 0x517a13a7, 0x42fb2381, 0x86392847, 0xd9c46154, 0xa31d737b, 0xb27103e9, 0x52d213e3, 0x619cffbc, 0x6d981164, + 0x0abef2e1, 0xb2ccf595, 0x3b99b2e8, 0xf3cf6e9c, 0xe6318817, 0x8423c3fd, 0x7409f16c, 0xe4f10662, 0x147aff24, + 0xee1d8589, 0x18312ba9, 0x7ce03b4c, 0xb3ae21d8, 0x2f8199ca, 0x5ce57763, 0x53eb7fbd, 0x5d747b2f, 0x10331cc5, + 0x0d054d6e, 0x664de3f9, 0x8ec7c42f, 0xdff7c7f4, 0xc1eb3992, 0x7a4acaf6, 0xed7ab8b7, 0x660fcd9a, 0x4888d6e2, + 0x522c197c, 0xcf24b18e, 0x0e451aef, 0x41edb002, 0xa19d0d39, 0xed21202d, 0x6a2048c8, 0xe80be182, 0x3f1b966d, + 0x6117b0cc, 0xf44a85d6, 0x0ead7ad3, 0x74f7a89e, 0x4e30c8db, 0x3d54f506, 0x7cb14412, 0x537faf03, 0xd7649792, + 0xda785bbc, 0x7dbf7970, 0xdbf3f967, 0xdfa6b35c, 0x525b64ce, 0x661d27ed, 0xd4980f39, 0xac801d00, 0x3adc5f3e, + 0x7c44543e, 0xe11ec0f3, 0xace9d2ab, 0x4053edaa, 0x39cbf4a5, 0xc8d04067, 0xb899df6e, 0xdc9ef345, 0x3ddd99c4, + 0x108abc01, 0x2fa47dcf, 0xbcfa6c35, 0x6c5a629e, 0x02c5f682, 0x6b1487e0, 0xa1b1e7fd, 0x0fded78c, 0x78e142ef, + 0x32477c57, 0x78115a3e, 0x21ffa648, 0xe6e7ed37, 0xd8d656a4, 0x972530dc, 0x3e6723b4, 0x32951c60, 0x490cbb56, + 0x76cba7b6, 0x910342c8, 0xba2887f9, 0x9c131323, 0x804afba6, 0xb5a3a66d, 0x7de620f1, 0xefdee6fb, 0xe663cc80, + 0x0c0e8097, 0x0231aea0, 0xa716c037, 0xfee18f4f, 0x50ecbbc9, 0x82fb550a, 0xa650d605, 0xe5ff6e30, 0x7c08aca0, + 0x4dfcd1cd, 0xe9f9db4b, 0x7914b429, 0x3c62e6d1, 0x7b73b0c8, 0x52a875aa, 0x4b2346c8, 0xc7a9a8b4, 0x1ea67d34, + 0xf572fbe2, 0x5e258d1a, 0xafff15d7, 0xa25879c5, 0xe60d9b4a, 0x0718851a, 0xc8c60983, 0xe2d5cc16, 0x4b2755e3, + 0xdaefe3a8, 0xb785962b, 0x2e314cb9, 0xbb62e381, 0xa4c6bc1f, 0x2778279f, 0x8e09dc44, 0x95c163ac, 0x14acd4ab, + 0xdc01ffb4, 0x8c8ac7ae, 0xcd136185, 0xece704d9, 0xbec6b19c, 0xdf3bbab0, 0xe8ddbda4, 0xafdf0a6c, 0x49589eaf, + 0xf3a53ec8, 0xbaa05339, 0x8b4220ca, 0xfff0ad9e, 0x380a233e, 0x09af539f, 0x087aacb3, 0x0929ecb7, 0x9059a4eb, + 0x3fc6bdaa, 0xb4bf1438, 0x4e4a9703, 0x36b2979e, 0x414132b1, 0xbe578298, 0x7d44cfdc, 0x1250f5e1, 0xd51a77a7, + 0x1038bcfa, 0x3228e916, 0x7a9c0826, 0x212c1c63, 0x90102362, 0xc15defcf, 0x93106d15, 0x8ece8efb, 0x9555c58e, + 0xe091f9df, 0xa00991d9, 0x7569765f, 0x9ef90347, 0x8c5d9aa1, 0x8807f99f, 0x77d5ebd6, 0x461fc10f, 0x734f04f5, + 0xda0a85ae, 0x71f82325, 0xa1cc3b5f, 0xe96c2351, 0x738f52fc, 0x5cd32501, 0xaf8fc57b, 0xa7b2bf99, 0x23a23fc5, + 0xb2a2e9dc, 0x3251131b, 0x7eba1e01, 0x7fab4f25, 0x8af28ab1, 0x7315bc07, 0x47f106a0, 0x9ac70f0d, 0x610554e0, + 0x4c119842, 0x5be86c34, 0x061219a1, 0xbde468d6, 0x2e4fc8bb, 0xf0be1586, 0x76d923ca, 0xb5b09e98, 0xb59569f6, + 0x57172eb8, 0x8846741a, 0xf813f76e, 0x3a32ffbf, 0xa7004ea6, 0xcd159721, 0xb7f71c8a, 0x5a0f7ba1, 0x962d12e0, + 0xef6785b3, 0xd9177362, 0x9a559d63, 0x0a03aa8d, 0x92125946, 0xa563828d, 0x18ce6941, 0x32d635d0, 0x573892e5, + 0xce9e7fa0, 0x19d967d7, 0xb66c545b, 0x785db12d, 0x9f011605, 0xa6315cdc, 0xeb703c30, 0xfbe41116, 0xa11271c1, + 0x12c555be, 0x836db4fc, 0xf8b18da9, 0x0027861e, 0x5f6d99ba, 0xed8a3dd4, 0xca5e2b6e, 0x98a58b43, 0x75d10ee9, + 0xc84991a2, 0xed8e5d94, 0x878e1fdb, 0x63f77e53, 0x29f6e2d7, 0xaac1726b, 0x00244e1e, 0x38bf2097, 0x931e6e44, + 0xe1817656, 0x1a55dd7c, 0x4eed402f, 0xde87a65a, 0x5d368eea, 0xb76bf846, 0xaec36571, 0x27374bfb, 0x80f4c6d6, + 0x1a9b961d, 0x32920f2a, 0xe85f9a15, 0xf6c4b5bb, 0xcdbead38, 0x3aef1712, 0xaf60698a, 0x006f1514, 0x1ab09306, + 0xb9f44b4d, 0x8f5318ae, 0x86da276a, 0x9b11b18d, 0x6e536607, 0xb28b23f3, 0x033be5d8, 0x4ea403b4, 0xd7f8bb1f, + 0xd5d49021, 0xac94c765, 0xf3269dfe, 0x3d80e97c, 0x433c0b7d, 0xf431ac99, 0x571e8abb, 0x12ccac3a, 0xf31323b0, + 0xb207f4bc, 0xdbc54579, 0x1af4d93b, 0x84ca57be, 0x136b4dd0, 0xabcddbef, 0x4af93c34, 0xbdd6abe3, 0x4e4bb9c9, + 0x162bd91c, 0xafa531ed, 0x0d276689, 0x620234ac, 0xfe729253, 0x94c1c458, 0x781c4a3e, 0x487065f5, 0xbf39a70a, + 0x72a6e00f, 0xe5d42f3f, 0x35b35354, 0x4146f020, 0x590bf231, 0xd1219fc4, 0xb434c82f, 0x95e66068, 0x7494faff, + 0x08afc73b, 0xa591ae1f, 0x2aa56d0c, 0x4f71e25e, 0x9fbea8ad, 0x8d808302, 0x1f38ae03, 0x5ef6a989, 0xf0ec39f7, + 0xa6829d6a, 0x4fe6d569, 0xe810f1eb, 0xa4b6a4bc, 0x09ba63b6, 0xd40715ed, 0xd67897f7, 0x9f5c6a1c, 0xe9ad90de, + 0xacef178d, 0xfd076950, 0x2bc340a6, 0xcf6ba237, 0x5987c2c3, 0x4c03167f, 0x746c986e, 0xdd8bef38, 0xe8d9e546, + 0x43624e7d, 0x3af32487, 0x3dcceac7, 0x55474d8a, 0x3c1fc7e8, 0x2142a112, 0x42ed465c, 0x442632d0, 0xce830cfb, + 0x06f5ce26, 0x6169fbf7, 0x99bb20f8, 0xed5dab5d, 0x597c5d64, 0x5ec2096f, 0xc0c37c0e, 0x9629fd33, 0xfaf67487, + 0xc97a75ea, 0x33eade03, 0x24991a4e, 0xfc16324e, 0x7f984fb5, 0x963a3d42, 0xa3e4ae54, 0x59745088, 0x0f47d4d6, + 0xc684878e, 0x1b817db5, 0xf68d8681, 0x73d0e8bd, 0x07945ed5, 0xf2546cb6, 0xca7f2d8d, 0x8eab4492, 0x0ee9576d, + 0x6ab3ba89, 0xd6f0a067, 0x4788ed46, 0xd2e36de0, 0x6f7b4369, 0x1c975e01, 0xc4c1ff5b, 0xd3e50401, 0xefc29829, + 0x9673664b, 0xec186b61, 0xae996e29, 0x60271ded, 0xc72e2e63, 0x78c18345, 0xe8c760c3, 0x288d8b18, 0x4cee6414, + 0x9a5a94cc, 0xe8ed9a03, 0x83475baa, 0x8a314caa, 0xe2a50d57, 0x493b0877, 0xadcb6fd3, 0x86b46965, 0x436878b6, + 0x619d1272, 0x0fb0f33e, 0x0a529c06, 0xb81512c7, 0x6990f1b2, 0x3275dd10, 0xe75f4090, 0xda318467, 0x36b89796, + 0xc1dca7f2, 0x1b426d18, 0x13e1abbb, 0x82f4e28b, 0x4af7d61e, 0x9de273ea, 0xbaa60704, 0xfd9f38d8, 0x6b0cdaae, + 0x49dff859, 0x59f3251b, 0xfe4e917f, 0xb09acae5, 0x5d4796e5, 0x34e2d84f, 0x29b58afe, 0x59278fb8, 0xee4e71d7, + 0xf69f39a4, 0x254da680, 0xcc00ffbe, 0xaced8e0d, 0x579bd296, 0x468f47df, 0x99920e37, 0x88a55a75, 0x17a58b2b, + 0x00fb10cf, 0xf2b756dc, 0x1581b298, 0xe50467b5, 0x3ee1eb6a, 0xe193e861, 0x48319ecc, 0x493911c7, 0x643a3252, + 0x54e01046, 0xec038c3e, 0xbccf636a, 0xa8256fcb, 0x614a5c79, 0x842006cb, 0xa51c24c6, 0x2a12bfff, 0x6a10a205, + 0x42903538, 0x74e90417, 0x50cd2e19, 0x9f94892d, 0x952ec64c, 0x20a5b98d, 0xf4c21d4a, 0xf0200c76, 0x10fcb9f2, + 0xe3e25f16, 0xf8e3b67e, 0xcd06f7aa, 0x82fbdffe, 0xa2972d71, 0x41ce88bd, 0xd8964c8c, 0xb514f301, 0xaa0f8f9a, + 0xf69d1b89, 0x85f1ec1c, 0xa511ac26, 0x719db344, 0xeb435da5, 0xbcaed322, 0xe4d9c761, 0x8b64d4c5, 0xa94a555c, + 0xae690240, 0xea893774, 0xa0014013, 0x20a4c8a7, 0x91051c6c, 0x1bf27dc7, 0x7029b87e, 0xf1556cfb, 0x093a6fee, + 0x3541216a, 0x2288f2be, 0x8532eb7e, 0xb2959f47, 0xbedd68ff, 0xe005eba0, 0x28dcd72d, 0x4e948880, 0x84d04d24, + 0xd3c61aa4, 0x9c997f4b, 0xffa2ff58, 0x1206e2aa, 0xc1c0f8ba, 0x517545b3, 0x927d7ebc, 0x5cb8f897, 0xceea8ebc, + 0xea94b665, 0x65f81144, 0x97d2d5ea, 0x4039d00c, 0x36e6bd7e, 0xd9655365, 0x4ce09dae, 0x5e4abb83, 0x7bc9f08b, + 0xb50d5314, 0xd13c3c9e, 0x0a769f2c, 0x0cacebf7, 0x856a193c, 0xb9bcec24, 0x248a5913, 0x70b856dd, 0x578cba3f, + 0xbc81e52f, 0x85ad7cb3, 0xf1ef5d96, 0x16f91eaf, 0xa6f92c0b, 0x10bf0de2, 0x2567f090, 0x9c685326, 0xabdde1f2, + 0x8124c6a3, 0x3f63a9f6, 0xc28cb6f0, 0xc70b0cee, 0x16dadd71, 0xb412a3d6, 0x34576bd0, 0x5ea73110, 0x1512f043, + 0x42037a0a, 0x5d4c055c, 0xd2a76b17, 0x6af1600c, 0xe9eb94cb, 0xf221462c, 0x18661df2, 0xd114e325, 0xda954339, + 0x80c59dd2, 0x86c2a5e4, 0x3a4e5344, 0x7741991f, 0xda47235c, 0x4c7ab89c, 0xb5e39c99, 0xb35bb6cf, 0x8a39fbd6, + 0xbd8b5f92, 0x07f4a835, 0x7dedd432, 0x550589cb, 0x1e4b8453, 0xf0bc5bfa, 0x342be015, 0x455ed2d6, 0xf5182242, + 0x5935d810, 0x248b149c, 0x459057dd, 0x250505f0, 0x77ca769f, 0x816abc52, 0x5e622bd3, 0xf2959565, 0xf7c1ce16, + 0x1bb583cc, 0xe40d6b22, 0xe20c65ec, 0x70d95155, 0x9a104e30, 0x67d5725d, 0xc28688fc, 0x61538bcb, 0x186a63ab, + 0x91b99dbf, 0x0facd56d, 0xc4a26aaa, 0xb8cd72ab, 0x43d8952e, 0x52d3b7c8, 0x07412d7b, 0x71038a19, 0x15a72b27, + 0x1c9d2184, 0x1a09a50c, 0x930c8c47, 0x029986b9, 0xcf0cddd5, 0xfc450d80, 0x92a9d696, 0xc87de8f3, 0x69a180e5, + 0x4f095ba7, 0x03f64589, 0xfc0c09b4, 0x1063eff9, 0x2b2137e5, 0xe69c3034, 0x28669ba9, 0x90b04554, 0xabc4e7d0, + 0x9222d7dc, 0x7ac43072, 0xde22055b, 0x5a55f24e, 0xfdd1f2fd, 0x10ad3404, 0x0e1514da, 0x4e977440, 0xa016143c, + 0xc9420493, 0x4ce08c6b, 0xefa37fa3, 0xf7f29c28, 0x081521e6, 0xcde658d4, 0xd230bece, 0xdd56f654, 0xef81f4f5, + 0xa104f0e5, 0x1a2ba176, 0x0fde477d, 0x20358399, 0x731e88ba, 0xf064bdd9, 0xba574771, 0x3d3bbd69, 0xda8e9940, + 0xc2ba0368, 0xb41b61bf, 0xb7191c15, 0x85ecc79a, 0xf643d4e0, 0x91f4b713, 0x8c19abe9, 0x5da22f47, 0x932eb667, + 0x0b1f94c4, 0x3195fc5a, 0xdf27b9b9, 0x1c0e6043, 0x88da533b, 0xdf9382d5, 0xdecac810, 0x671e4278, 0x1ae21dfd, + 0x2c80132f, 0x7c690648, 0x3172d9ca, 0xc5b1e5b3, 0x75f991d4, 0x2f27e428, 0xb72b2052, 0x98edb58e, 0xea758710, + 0xd884e9d4, 0x16b7977d, 0x252f4398, 0xbb885898, 0x97d319ac, 0x82d569ab, 0xf5c1d018, 0x8e63e3d3, 0x41791231, + 0x8ee435b2, 0x347e00a5, 0xc0055e68, 0x4b4c5a86, 0x0a982fe0, 0x079d7d4a, 0xf270fddc, 0x808f78ac, 0xf2b1096d, + 0x5e558ba7, 0x18592a3a, 0xfa26a9b7, 0xf42452ef, 0x42d571b5, 0xb8efc84d, 0xf26f022e, 0xd18c2f99, 0x03a3122b, + 0xe3c4945b, 0x564d3598, 0x2e4b03e9, 0x9d4c7d93, 0xc2dbee9e, 0x17af66f7, 0x796d230e, 0xe348fccc, 0x5ed4bfac, + 0x25e95f5a, 0xb7b63133, 0x78c00e9b, 0x73170b96, 0x9798234c, 0x5a7f7ea4, 0x61715dec, 0xcf821c1a, 0x13c3fd82, + 0x7f9488e5, 0x62ceae31, 0x1e0ab3b4, 0xe070d995, 0xa45441fc, 0xab5ed447, 0x5cd0c75a, 0x4d7bd464, 0xc33b4572, + 0x8b97a16b, 0x962cfc21, 0x692a253b, 0x96bdc544, 0x238d1400, 0x5014411e, 0xd7322a3a, 0x302ff844, 0x549e5490, + 0xc9e2373e, 0xb6616f71, 0x6899a4f5, 0x2bb68dae, 0x73977ff1, 0x32b40d58, 0x0cfe7152, 0xf74d5899, 0x428bb9f6, + 0xcd3d2117, 0xcde16420, 0x4ea19de3, 0x659d43ee, 0x0399be21, 0xae1ea5e3, 0x5947bd9c, 0xb26a8eb8, 0xc7b13afe, + 0x305970dd, 0xed9f872b, 0x0f97885d, 0x1394f017, 0x6e3f9f99, 0xc4f424a1, 0x1535ffb1, 0x36aaabf1, 0xcda535fb, + 0x8335238b, 0x7c732006, 0xd8316504, 0x21d64cfc, 0xb940c167, 0x2a58bd14, 0x377ca502, 0xc3c5e554, 0xf6a73fd7, + 0x283d0838, 0xffa6219a, 0xb2d9f59a, 0xc29d4b50, 0x3424a7f6, 0xba5b09aa, 0x87531f26, 0xc2605a55, 0xe83fdd21, + 0xfd78776b, 0xa2c65637, 0x9f539c97, 0x13c2474c, 0xbc973c5e, 0x656b66ef, 0xa38d96ea, 0x2dab180d, 0x4ee854de, + 0x456cd55e, 0x165ce943, 0xbb7a33f2, 0xf1dbf81f, 0x5f6820fb, 0x79287c5f, 0x6d25321d, 0x3a2dd7bb, 0xf6500c4a, + 0x55e5dd52, 0xce7e68d9, 0xfca2f5b4, 0x1466be83, 0xed7bbefa, 0x0e7b7937, 0xc4241ba2, 0x7555491c, 0x58bef80c, + 0x84f2508d, 0x798aa71b, 0x5b6c4743, 0x75a7f44a, 0x75cf06a5, 0x223f2d17, 0x8af1dfe1, 0x2a430862, 0xda091738, + 0x453cdb29, 0x2d6ba564, 0x6e2de157, 0xe3ccc385, 0x7d082cfa, 0x2e40c2f2, 0x1c498fac, 0x8b6a80dc, 0x09e5643b, + 0xc67391d1, 0x0dad4720, 0x21e83055, 0x907e7a4e, 0x2e2df31c, 0xb9cab257, 0x9694ff74, 0xf5f81471, 0x12771986, + 0x02cbafba, 0xb5734b09, 0x31ba437b, 0xe09e6f20, 0x7903d0aa, 0x80a6f154, 0x67df596e, 0x13268a0e, 0x994e2bd9, + 0x32815263, 0xa7c21701, 0x85a99e74, 0xd9b90191, 0x3c86fecf, 0x2e05851f, 0x8211fe59, 0xf0cd04a8, 0x5cdfaeda, + 0x76bf962e, 0xf14e153e, 0xb8627a5f, 0xc88f9601, 0x343051a2, 0x4e46ce64, 0x135518fc, 0xffaf2d22, 0x06110e5b, + 0xf249a0a6, 0x4932ce53, 0x7dc55e73, 0x2b6b8857, 0x8d59f602, 0x6ccd7e59, 0x8b837747, 0x69ef17bc, 0x59ac4644, + 0x22b53145, 0xa7affacf, 0x03ed45a9, 0xf2e141f2, 0xd0e4ba35, 0xa74f39a4, 0x98577eac, 0xef40533c, 0x1382f6e9, + 0x2e8937ee, 0x39974025, 0x6083047a, 0x24a611bd, 0x7b53d1cd, 0x411b3300, 0x836b165f, 0xa077ad68, 0xe038717f, + 0x0c70952a, 0x9980fb08, 0x2d44766e, 0x37ee5142, 0x4d1cb891, 0x288ba648, 0xb5269d52, 0x8650f767, 0x08b8b294, + 0x47bace6e, 0xb0e926bf, 0xac7e40fd, 0x6e1f3f60, 0x27c3b3ba, 0x471c54d7, 0x3f7076ee, 0xe030b483, 0xccccfd70, + 0x1d10ce25, 0x90d62e5c, 0x056cf3c4, 0xbc50e2a4, 0x767d297e, 0xd2b365a8, 0xfd7d4ef2, 0xa08077eb, 0xe110a327, + 0x2c42f025, 0x00ec4d4e, 0x6c307507, 0x1718f6da, 0xfbe73073, 0x45c00b09, 0x337460d1, 0x449e6df7, 0xc2e5b01e, + 0xc1e68e2c, 0xda15eb16, 0x8aae43cc, 0xceb61621, 0x844e864f, 0x37f99b93, 0x66923519, 0x33722873, 0x09281b26, + 0x6b79ad7a, 0xad1973af, 0x574b8291, 0xea18cef6, 0xa3e657af, 0x74a10bcb, 0xb9a919c9, 0x6582c188, 0xa5cd4278, + 0xd9a06e80, 0xa5cfb18b, 0x32693ff1, 0xb3113daa, 0x0ea23af2, 0x49f9b31d, 0x88aee4fa, 0x429a61ca, 0x8894c527, + 0x89b14483, 0x44c6887e, 0x2607a2db, 0x581daf4d, 0xec889a29, 0x66d93d5f, 0x6d7b501f, 0x032fb6dd, 0x218ed9bc, + 0x6556e7ed, 0xdd9f5d89, 0x0f34b75b, 0x508a1cf7, 0xcdaeb8e6, 0xeaff0987, 0x9eaaa697, 0xddac0d73, 0x10ea37c2, + 0x8fe51869, 0xd3705b40, 0x9c1f13df, 0x39e4aaae, 0x3a235ec7, 0x5bbd4ffd, 0x2ea10b06, 0x111f0855, 0x822b2931, + 0xb36d7574, 0x69b2b562, 0x6064ae21, 0x180ae0e7, 0xa5ae6f96, 0xc39bf286, 0x6d1ba1b9, 0x232ecddf, 0xf73ded59, + 0x15be595b, 0xf1342df4, 0x7a55a917, 0x11fbc8e3, 0x575f38b5, 0xa7decd2e, 0x2d786f84, 0x6cc0aa8b, 0x4e8767f6, + 0x83993708, 0x045c5126, 0x82ccc3a3, 0x138e2bb8, 0x5f148839, 0x47bc9591, 0x043f5986, 0x4a22adcf, 0x61bc8a5e, + 0x33a354e3, 0x9cb95243, 0x5cd6a3cf, 0xb3e07ea3, 0x9f0854d6, 0xb14973fe, 0xb19b4f42, 0x4f64ebec, 0x43432256, + 0xcd19c2e6, 0x87693153, 0xa363f8cd, 0xa68da064, 0x1c3aa46c, 0x6f7c9fa7, 0x8c1fb65c, 0xd904377c, 0x0d066eb0, + 0x9920c882, 0xc0c0e43e, 0xfd29a9c7, 0x651b295d, 0x1e87cf91, 0x22d5a5bc, 0xcb7c3b55, 0xcdee61a5, 0xac9e7316, + 0x8f5840e7, 0x552ab89b, 0x7c990aff, 0x98c02ed6, 0x365de50c, 0xbc70dc7c, 0x98828485, 0xa1aade2d, 0x00b2c6ca, + 0xc3e99dbf, 0x9a09284b, 0x498f2e40, 0x7b97d1e5, 0xefcea2cd, 0x1d4267ae, 0xe147961e, 0x80e0898a, 0xf03673ac, + 0xf408ada8, 0x45e1faa1, 0xd52a7823, 0xb8d436b4, 0xe9b91568, 0x1ef30b4f, 0x2fe256e9, 0xacbe07c1, 0xb17a102f, + 0xf3f23000, 0xd79f1179, 0xad690945, 0x0ce80473, 0x20186412, 0xc607490d, 0xb3887dc9, 0x1b7f1932, 0x15e9cab6, + 0x0c382cb7, 0xfdddbe71, 0xcb436125, 0xde4aa73a, 0xc52eb40c, 0x5b076451, 0xbedb33c1, 0x2f2280ba, 0x2be18706, + 0x88254650, 0x5a87474f, 0xf41f9532, 0x907d6bf0, 0xfaa372b6, 0x79f68c89, 0xfeb75a1b, 0xa11afbb5, 0xc0c6123d, + 0x3969a605, 0xda400af2, 0x22b5a5ce, 0x60c0a30c, 0x1d3fcb03, 0x49ff9b51, 0xcfc577c3, 0xef53dc58, 0xbdcfdefb, + 0xea4b22e0, 0x76c86e2b, 0x760a1303, 0x2bde695c, 0xf2b892ec, 0x0378041b, 0x0d885806, 0x6ddd97cf, 0xaf460fb8, + 0x1909ae85, 0xf6075819, 0xe17540ec, 0xf417bd38, 0x7943a4d5, 0x0eef8b22, 0x1a15384c, 0xe95c76b5, 0xf1d4be40, + 0x19a0482e, 0x0d026773, 0x05b1597c, 0xe73ac318, 0x3df707e4, 0xe0fb6deb, 0x2b0e247d, 0xbff6c7b3, 0xd2a9e266, + 0xe57d6cec, 0x1a0cbc44, 0xbbb4c41f, 0x3dd5a1eb, 0x9a2116ce, 0x1c8422ad, 0x19a2017a, 0x3dc7a653, 0x4d7e1327, + 0x5e7ea435, 0x237dce74, 0x7ffbeeec, 0x9378baf4, 0x368b7833, 0xa1e36889, 0xb3e60832, 0x226c91cb, 0x3fd7c4ff, + 0x483cb6be, 0x5852678b, 0x7f9dbd25, 0xfc4ea737, 0x4c8680c3, 0x80801c41, 0xbcbbb98f, 0xd73eecdc, 0xecd92151, + 0xfc5bf0fa, 0x3c840423, 0x93531f37, 0x4127e6fd, 0xdfdc57ed, 0xe438ae71, 0x8dc5e5ff, 0x4c90fc6c, 0x78e2eea0, + 0xe4217360, 0xd3712339, 0x738fc455, 0xe5f6f44f, 0x297c10c2, 0xf048bf30, 0x86ca7854, 0xafa3f8b2, 0x1f8e776a, + 0xf7af5483, 0x812d50ed, 0x9baff31e, 0x78e08eb3, 0x33fe47c7, 0x8bcd86e6, 0x93fa03f7, 0x525b3e0e, 0xbbe2bc29, + 0x6b8240e1, 0x3d069c09, 0x5859b55c, 0x5a5328fb, 0xd940295a, 0x3d8e0751, 0x85e3de68, 0xfba5fa7a, 0xfbae3a1a, + 0xce27c017, 0xc35fb414, 0xdf96291e, 0x13b25dc7, 0x32867e90, 0x2dcdef9d, 0xd1630d0a, 0x925574f1, 0x57f3002f, + 0x8b6f802e, 0xdd6c955d, 0x073e097f, 0x2e768265, 0x5b6176b8, 0x73962ce5, 0x67f4c6e2, 0x22edd577, 0x92e95d73, + 0x3bbd5827, 0x054e4c0e, 0x7432c477, 0x84553eb3, 0xc88da550, 0x1a776b2e, 0x6ea279a1, 0xf1a16f33, 0xb0bb0513, + 0x6753bfe1, 0x10a0ec52, 0x76512b68, 0x2d5e472f, 0x37f3cfea, 0xb3002feb, 0xb4a5501e, 0x8b67b86f, 0x9a31149a, + 0x5a667e2a, 0x18b2187a, 0x9351a282, 0xc8c14d23, 0x9572b9c5, 0x46b5b3f3, 0xaed69988, 0x5b8e9574, 0x0fcb9c18, + 0x81e957e7, 0x10e439c4, 0x932a97ed, 0xbf8b4cf7, 0x8eb47750, 0x96256e87, 0x5693c274, 0xd1b2e285, 0x4af89293, + 0x08db83a1, 0x1a88e764, 0x54af832d, 0x158dfca9, 0x6362f717, 0x219e2ca0, 0xa25b6bc8, 0x0c7830a4, 0xa55e617f, + 0x3cd2810a, 0x16a0500a, 0x0aaeafd9, 0x46ad31ef, 0x2d48b0ee, 0xf818fcdb, 0x636ba4f6, 0x7ad54978, 0x52682807, + 0x09db4003, 0xfb22aa48, 0x9d1c6e14, 0x360e7b97, 0x532bdc83, 0x6e93df69, 0x66eedd79, 0x89cfeb83, 0x0a7280e5, + 0x48b3852d, 0x752bc5cc, 0xfb54fd23, 0x805b0c47, 0xee4076d9, 0x5b12302f, 0x549ed3c9, 0x3ff25103, 0x18111181, + 0xf791b944, 0xce46b70d, 0xfec94a1e, 0x9435afce, 0xe2d5ed3b, 0xf5443397, 0x4ddd3e34, 0x8fad5bfa, 0x439a5205, + 0x755f3c6b, 0xabd5e7a7, 0x206cbd9d, 0x80beebc4, 0x473b22aa, 0x8666fced, 0xab3d3f88, 0x38725c30, 0x44fb3c17, + 0xedb6b002, 0xb60c474f, 0xdd484be1, 0xe0b8ca3c, 0x851b5afa, 0xf68cd01c, 0x2ad79a68, 0xcefad5d0, 0xfadc06ed, + 0xc9c0402e, 0x101bd90f, 0xaeb1e9f2, 0x2ec56995, 0x62f211be, 0x05603b00, 0x66c641e1, 0xc2f19892, 0x94cbc1ed, + 0xc49992d0, 0xbbc93441, 0xe1e2bc1e, 0x810b3961, 0x5d4b270e, 0x0127e5d6, 0x1fb4f279, 0x9b3eb45c, 0xd6de42cf, + 0xd6a08bb8, 0xcda26e9b, 0x322f6bb6, 0xf46bca5e, 0x60b2cb50, 0x0aba5112, 0xa2453463, 0xfe6bfdcf, 0x6402194b, + 0xba1f7e32, 0x68d522cd, 0x3684d713, 0x04ffedc3, 0xf614291e, 0xc61bf681, 0x844396db, 0x529a6935, 0xb6236542, + 0x5ec418a6, 0x6a6ba31c, 0xc5cca127, 0xd7d15e10, 0xfac78296, 0xd2bab5d3, 0x7c2b37c5, 0xf33bb672, 0x6e52a599, + 0xd609b613, 0xa0fc1cda, 0x57df991a, 0x34795008, 0x81a19c09, 0x71ce71d2, 0x821de295, 0x350adf7a, 0x00e8c63b, + 0x2e9de168, 0x57200c40, 0xd5ea6799, 0x13104f9d, 0x55b075f3, 0x51befb2b, 0x322705d8, 0xb663aa6a, 0x67d9176b, + 0x89fc489f, 0x149784be, 0x97552632, 0xb87ebfe5, 0xd8c151fc, 0xadc5bc97, 0x8d85e2ca, 0x26edf3b0, 0xe791f64d, + 0xa3a36d75, 0xef010c06, 0xa76e86bc, 0x1cd4f655, 0x450d2a92, 0x6c3a419b, 0x5858ab03, 0x956424af, 0x3454bef0, + 0x495284e6, 0x80a0f1d8, 0x0f26336f, 0x1350acd9, 0x140521f3, 0x1e3d97ff, 0x9119973f, 0x9e3fa510, 0xec527f38, + 0x3496bba3, 0xbf7c5dd4, 0xeb82e14e, 0x155cb59c, 0xde405548, 0x22bbffab, 0x112a6515, 0x8d2758c3, 0x2f3063f9, + 0xa41a350d, 0x44d7bd94, 0x92dfdde9, 0x7316f7f7, 0x975886b5, 0x649f3f51, 0xff6b2dd0, 0x754dc9fb, 0x724d6fc2, + 0xc1fab524, 0x97ce55e8, 0x9c36441a, 0x7ee6047a, 0x18af4cc4, 0xcfedffae, 0xb6997e2c, 0x24a74307, 0xa10181ec, + 0x724e1408, 0xf0d15a0c, 0x17ae2ba7, 0x8e52f32b, 0x38da8854, 0x43d55cb9, 0xc7bb78d8, 0xd7c37505, 0x42456f8d, + 0xb869811f, 0xfbf021c6, 0x4eee7183, 0x6fd3b703, 0x7fdc9072, 0x1e2c8fe4, 0xde6c1550, 0xdba58456, 0x7aca849f, + 0xe6a10707, 0x3cdd2746, 0x3c7f7712, 0x1fb08e4a, 0x65ad2c74, 0xea19b628, 0xaaf6bd48, 0x0c8dc878, 0x993eb8e2, + 0xe24a2e6b, 0x57f7e193, 0x60f9ffef, 0x2cb05c71, 0x56ff178e, 0xc8263327, 0x965b2ceb, 0x17655d57, 0xb993bccd, + 0x24afb1e7, 0x7a54afab, 0x1f37c7b2, 0x2e69ff83, 0xd6f83ae9, 0xd24e4218, 0x84fc4322, 0xc70ee7a5, 0x7a36de25, + 0x30155094, 0x2d85e42e, 0x67749609, 0xf1aa31b3, 0x1bdf5144, 0x9548c0a3, 0x5049b17d, 0xd84f6b01, 0x4030abb0, + 0x45e505ac, 0x49c5c18b, 0x357ea4ff, 0x01055cc9, 0xa6c9890a, 0x5d6c170f, 0x1cf0443a, 0x10a5fbff, 0x6e4457aa, + 0x5e8504e3, 0x95b444e4, 0xf9216a0e, 0xf30867a6, 0xd44db573, 0xa086ecf6, 0xf4481a4b, 0x63702417, 0x35538821, + 0x2e68dcba, 0xc81916e1, 0x8a50f1d9, 0xd00bd14f, 0x2f897649, 0xf104a7dc, 0x13bb6a50, 0xbc772d67, 0xeda32de5, + 0x0939d121, 0xfdd044d4, 0xe91aa3a5, 0x9ae5071d, 0xe046df66, 0xf7bde72d, 0xea470834, 0xe224a2d7, 0x246c2c2e, + 0xaff30cb5, 0xb0dd6b7b, 0x03a22e33, 0x6a3102f8, 0x9da5ecc0, 0xbec292d8, 0xcb34b49a, 0x215b0616, 0x5de999f6, + 0x4dc16677, 0xb234116d, 0xe0a9ee70, 0xe3756185, 0xda8c086f, 0xa580bc9a, 0x10747ea4, 0x054701bc, 0xd41867f8, + 0xbf32e4fa, 0x70d65456, 0x6cb4cb8b, 0x7c7eb2da, 0x99f03d9c, 0xfb9664fe, 0x34679706, 0xfea11f15, 0x777a4900, + 0xf33957f1, 0x0deb41c4, 0xce876cbf, 0x1dcbb20f, 0x14421650, 0xd6e3961c, 0x0e377b73, 0x644094cd, 0x8f980538, + 0xd1acaf14, 0xd447fae8, 0x9d8c06b5, 0x5de4949a, 0x9b72d9d2, 0x57485c6d, 0x02eef910, 0x08517c24, 0x2f58207b, + 0x84d2ce80, 0x686eab1b, 0x8fd2536c, 0x5af6e310, 0x39105ed8, 0xf059e45d, 0xcf48b112, 0x15310a71, 0x9afd9802, + 0x6ff5f471, 0xd03e87b8, 0xe4ed7ac4, 0x25b53ea9, 0x837334d1, 0x7086a585, 0x49d73078, 0xec13b765, 0xbbca0c61, + 0x8a87febc, 0xbfc34875, 0x62f560bf, 0x4c177260, 0xbef15842, 0xead53270, 0x847cb399, 0xca604df1, 0xf48a685f, + 0xc819f830, 0x40fe555e, 0xdcd0e328, 0x879dac4c, 0xfce263b4, 0x8740b75c, 0x3fd82d7e, 0x65ce8bf2, 0xb6a5c940, + 0x189eb42a, 0xfa0c5fe7, 0xcbe6ee2c, 0x37dd5931, 0x9b9ca44c, 0x10e89718, 0x41923250, 0xad961398, 0x4587d8cb, + 0x203beda9, 0x083c6557, 0x808ab1e2, 0x2b8b56de, 0xa79a8c37, 0xe02718b1, 0xfe117cb3, 0x969e0a36, 0xd844a548, + 0x82ea1a0b, 0xe4021599, 0x837e9399, 0x7d45ef37, 0xba8f2261, 0x49a81304, 0x24248892, 0x1bcf4169, 0x4d09ccb5, + 0x8e2ad90d, 0x8380c9c0, 0xea5fc808, 0x953b64d0, 0x094c1252, 0xcd98d8d8, 0x1a4c2061, 0xe8ba9276, 0xd77e4080, + 0x071f4388, 0x485823d1, 0xffe613a1, 0x53df2838, 0x7e3151a9, 0xbf7ce4b1, 0x96b5bcdf, 0x4c39dea7, 0x0aa5f513, + 0x6aedd2d6, 0xb1527aee, 0x8608c948, 0xda0a1375, 0x6cc7d653, 0x96813234, 0xab2bd375, 0x973ceed1, 0xee6744e6, + 0x3d376573, 0x792d47ce, 0x534ee882, 0x6933f619, 0x49487bb1, 0x253dee1b, 0xc672fa95, 0xace76397, 0xfbdf947d, + 0x141c3ca7, 0xdb1e8f72, 0xb9168796, 0xa38a4fa1, 0xd42e2aa4, 0x026b6ca7, 0x5ccaec78, 0xb1df956f, 0x3a59d8c6, + 0x0ffd9b66, 0xff663d34, 0x64010c05, 0xb57d06bd, 0x580d555f, 0x2bd0ee53, 0x47505a25, 0xf29839a6, 0x9b86ec98, + 0xe3f810e9, 0x433d2a8b, 0x213bba5e, 0xc0edda61, 0x50a3ff4a, 0x67156441, 0x1c9c1f74, 0x3fd7c494, 0xd889e84d, + 0x6c1cc0ef, 0xbff9f412, 0x81f96ed2, 0x60c861c9, 0x1c1706e2, 0xbe096122, 0x2dccae3b, 0xbfa9396c, 0xfb48c44f, + 0xae502fc2, 0x1c0b38b4, 0x932c3a4a, 0x27034ec7, 0xd605494d, 0xbfbff6ad, 0x12bd09a6, 0x87a660db, 0xa0e98ab1, + 0xe080a1d5, 0x651aae63, 0x735ec345, 0x14e929e4, 0x6c128632, 0xf734dbf9, 0xcdb1f830, 0x88c4b280, 0xfa52c805, + 0xca5b940a, 0x555942f5, 0xf94cf447, 0x079907bc, 0xc50d2164, 0xb04e0974, 0xa44a7986, 0x08cd0e82, 0xbe46f4dd, + 0x4b97dc20, 0x700156a0, 0x0ed7c848, 0xbce4bca8, 0x03836012, 0x55501a42, 0x04ceb5ba, 0x58ce97ba, 0xb6fff0fb, + 0x5e3437b8, 0xa7a03ab8, 0x657be151, 0x5bc9625b, 0x39c70b67, 0xed7f3388, 0xb7838ae3, 0xb919af40, 0x8d30859d, + 0xef1eaf68, 0xa3b96d4b, 0x6948b8b3, 0x431a02d4, 0x69caad5e, 0xf9feac6b, 0x8855ef6c, 0xad1b6cd0, 0xd7964ff3, + 0x9938ee6f, 0x616c6cad, 0x3de61b2d, 0x557c1b58, 0x3791c9aa, 0x67ccb544, 0x5538638c, 0x1715ef5f, 0x1c05109a, + 0x077c4e4c, 0xa335673c, 0x296fdcf2, 0xc7b7185c, 0xdff63e49, 0xa2f06a7b, 0xb431238a, 0xc4426a52, 0x8b790f27, + 0xd93e17df, 0xbe7edf11, 0x015b949f, 0x5baa2303, 0x3b85f376, 0xf617f759, 0x10da8e9b, 0x375a1700, 0x27b13085, + 0x19517044, 0x768538fe, 0x9cdce234, 0xbd56e1a5, 0x78f12f70, 0x89b90877, 0x6931a6b6, 0xc4269463, 0xcc17b425, + 0x9f5ab072, 0xc042bba6, 0xd16dfc9f, 0x2e044b86, 0x53d63357, 0x13a6287e, 0x36a3684f, 0xf7984bf4, 0xf3dd4f12, + 0x02dc0cfc, 0x0b842a39, 0x125cfb19, 0x55843a20, 0x4e413674, 0xf69ec8c9, 0x9183a158, 0x1e78389b, 0xa0787229, + 0x515d8f76, 0x9a1cb156, 0xc7e3d64f, 0x8bf7b391, 0xe895c945, 0x6438e13a, 0xdc9b8f2d, 0x3712d6d7, 0x639af20f, + 0xc8030877, 0x3065a4f7, 0xaaa66eab, 0x9d141e3b, 0xdcc498de, 0xccc9a90c, 0xb7ae2bc7, 0xfe400699, 0xe3b78787, + 0x84aafaaa, 0x15340be2, 0x24647b76, 0x9998552c, 0x7acdf94f, 0xc2191847, 0x792f98ff, 0x4a0b47dd, 0x0ff3777e, + 0xa99d4d68, 0x0a093ff5, 0x9caba6b3, 0xa8f9e7df, 0x16d9b4fd, 0x526ffbb0, 0xc7105ce6, 0xbaddb2d5, 0xc87d0ca4, + 0x80811f5f, 0x0ac76a72, 0x402aa4cc, 0x751dc8ef, 0xdcc0843d, 0x78e8e291, 0x3b3bdb7f, 0xd222de33, 0x430fd954, + 0x15620106, 0x14feade8, 0xf81085f6, 0xa7c4671d, 0x2156a250, 0xe8f9c0a9, 0xdfb064dd, 0x4bd0e360, 0x26c3929e, + 0x15fe7482, 0x98763715, 0x650de19c, 0xf7a0ecea, 0xc008d9e6, 0x74c7061b, 0x8759e0fb, 0x44991233, 0x044adaf7, + 0x9c96a2fc, 0x761f28a8, 0xb5672e7f, 0x34819ef9, 0x88ed4349, 0xf1d816e7, 0x8c904bfa, 0x0572c7f5, 0xb3a7ac51, + 0x86d3c3cf, 0x72332e1a, 0x1af66c54, 0x3ee35548, 0x78def02c, 0x498b598a, 0xeffb9f6c, 0x94401864, 0x3fb43766, + 0xe6b9a772, 0xd02bde61, 0x4c48e762, 0x8193fd3a, 0x9dccfb4b, 0x06d40183, 0xdc8e8d2c, 0x28910a95, 0xda70c399, + 0x3f641732, 0x2fd7b495, 0x50b39d40, 0x0f69b442, 0xaf47c8ad, 0xd6e9e0d8, 0xcb9000e7, 0x846ffdb0, 0x6ac46788, + 0x2c744d7d, 0x3ce7bba9, 0xe1729bb4, 0x257e8ed2, 0x4040ca02, 0x0fb5b32f, 0xf5d0f715, 0x2d49c6f6, 0xf5b35cd0, + 0x8d572b41, 0xd64c768d, 0xe963449e, 0xe022fc5b, 0x59811ee8, 0xbc399ca5, 0x8b7d33c4, 0x7f1c2d0c, 0xaa8b3f86, + 0x3b513d73, 0xdc060806, 0x645e7f48, 0x369d63a3, 0xe949be93, 0x697bd8c2, 0x3f2bc433, 0xdb1d0620, 0xb0035ab0, + 0x17fd6ce5, 0xd7bd4c78, 0xebfaa753, 0x403f505e, 0x7ac5cbb9, 0xe19640fe, 0xbe9e52c7, 0xe93ae812, 0x82d76712, + 0xb5bdca13, 0x1453df03, 0xf4ad16e2, 0xba62595f, 0x00c35033, 0x2598b521, 0x18c709f0, 0x86eb7205, 0xd42fc4a0, + 0x6023a885, 0x5285d900, 0x6567b566, 0x5eb4fe3b, 0x6c44f590, 0xd0c63cb5, 0xa9b7452c, 0x48beafa6, 0x93a613ec, + 0xcb18464c, 0x003bd4a8, 0x60c84e95, 0xbef8a427, 0x9acc89a3, 0x66a0049c, 0xf3df1219, 0xd96eb9a4, 0xfb29de46, + 0x7ebc9cf0, 0xafc2f218, 0x01829454, 0xbc9bff9c, 0x719e3bd0, 0x549b8333, 0x09c96da7, 0x2324ff0d, 0x29dd2fe4, + 0x2776430b, 0xbae22c49, 0x84feb57c, 0xba6fae2d, 0x9f23da74, 0xe07a3f8b, 0x99d94b9a, 0xd898f8d1, 0x7d961b07, + 0x4f7252a4, 0x1963f985, 0x156d2ab4, 0xf521f717, 0x87e20e4b, 0xb09d9c00, 0x2e96484d, 0x413ab9f6, 0x4d515e40, + 0x41a75e9f, 0x0c80ac83, 0xcf4eed2d, 0x5f3c55a5, 0x6d139b61, 0x2b917f58, 0xcabd2f2b, 0x4865d312, 0x8cc2aa06, + 0x26afe406, 0x4527812d, 0x94cf37d0, 0x105d1a26, 0xef258ed2, 0x42efcc17, 0x175c290f, 0x4a327be7, 0x12336a02, + 0xf5d67baa, 0x208c0638, 0xe744b5f3, 0x524589c9, 0xb9ee8cae, 0x7b3bd947, 0x6edf741a, 0xd593b26b, 0xb0f7c1d9, + 0xb1c97cf6, 0x4e348b62, 0x629587ad, 0x280b9f36, 0xd93fbac5, 0x2ee3d814, 0x4e413bbf, 0xa663a27c, 0x1579bbd7, + 0xbc11b6bd, 0x68c862b1, 0xa221e73e, 0x0183151c, 0xa20808f3, 0x43a40664, 0xbe1d94d0, 0x62cf4401, 0xb399f394, + 0x96e3a3e2, 0xe19f9f95, 0x6204a603, 0x3286fa9c, 0xd8e7a7ac, 0x02e1b5a0, 0xae6b20ac, 0x5a18339c, 0xcd236327, + 0x708467a2, 0x6ac1b335, 0x91632d9a, 0xb97b1d10, 0x85a2725f, 0x10c55f79, 0x8617479c, 0x6c431d9f, 0x1d93d2c4, + 0xc9ed0cb1, 0x57b09842, 0x415d8d6d, 0xa03fbf93, 0xcb00ea82, 0x359768ae, 0x625be179, 0xac836a2b, 0xc90fd051, + 0x18c50b47, 0x02aa9ff6, 0x16a66c2f, 0x62830f31, 0x01a1aa3a, 0xb594cef5, 0xf274d057, 0xe28226d7, 0x42724b28, + 0x3da87dd5, 0x0908fbc3, 0x71506cab, 0xf39afd90, 0x9236ee9f, 0x579aebd7, 0xb72ee1cf, 0x217b0572, 0xfcf7376a, + 0x89a13ee5, 0x2156c1c9, 0xdd5465a6, 0xa357c829, 0x48398012, 0x29bf36e5, 0xf324f534, 0xb368e225, 0xe1e59f64, + 0x84788aa3, 0xde16b064, 0xdf27baa0, 0x77de866b, 0x08693d77, 0xe6519736, 0x9884f270, 0xfe7429bf, 0x8edb0873, + 0xecc1215a, 0x5aa37072, 0x0d8eae0c, 0xa0ea1619, 0xc6bfb35d, 0x5224fe51, 0x41143824, 0x9cf5cf32, 0xede4cac6, + 0xbbc248a1, 0x1b7e4ea7, 0xfc3d3960, 0x4005c45a, 0xfc283c6e, 0x2eeec151, 0xc679e680, 0x33905853, 0xc32c91d9, + 0x3ee9ca7b, 0xd358d21a, 0x9d17c4f9, 0x5261b12a, 0xd6b9414d, 0xdc9a8e77, 0x3aef7a4d, 0x83e4db0b, 0xded521b1, + 0x53005900, 0xfc345984, 0xbb473b35, 0xbfd485dc, 0xd60e4df6, 0x2f494777, 0x0a33867f, 0x61eea88a, 0xc1e46c57, + 0x19520ab8, 0x4e1130b2, 0xd1a06ee7, 0x983f8fc8, 0x19dc2a08, 0x7ffc89e5, 0x3f419105, 0x1781b443, 0x8be03c93, + 0x38716854, 0xd1d04e06, 0xb1af28de, 0xb5395ea5, 0x3b720331, 0xdf08480b, 0xc3f5c0ac, 0xbfe1cb70, 0x7a71993d, + 0x6b667f1d, 0x40f03574, 0x465eec33, 0x2d778b93, 0x1a45d971, 0x58907548, 0x3766c7c8, 0x293c710f, 0x9a95ec67, + 0xd038c8d6, 0xc4d3cffe, 0x98ff8151, 0xa07aa673, 0xf37b547e, 0x4a12f1c4, 0x750695aa, 0x0540248e, 0x8cb0aa94, + 0x6fbc24b5, 0xa0a31786, 0xec1a02e3, 0xb6c8e0bb, 0xfc792379, 0x7bf32d60, 0xbead6130, 0x773388d0, 0x0309c9e9, + 0x8d032339, 0x04ea00b4, 0x77afa168, 0x6362e3c0, 0xefb3d6d3, 0xdb062f5b, 0x407c265b, 0x462c199e, 0x236edd95, + 0x2690729b, 0xc31bc58a, 0x16dbeccc, 0x9363206e, 0xb06f17b5, 0x7cf1c77c, 0x68cd2edd, 0xe0eaae18, 0x24de5a03, + 0xaf020628, 0x55b4d312, 0x72fc54e2, 0x6306e61c, 0xdf78bab2, 0x65eb27d5, 0xaffe81fc, 0x2f6f8d1b, 0x644b71ca, + 0xe2ba019b, 0xa4053916, 0xe89ffde1, 0x64bccb96, 0xe086dd8a, 0xc07c4bcf, 0xfca17764, 0xa1ab3ebd, 0xd83dec02, + 0x3074b661, 0x1acd906c, 0xc68ce70f, 0x0b842ecc, 0xe00c87f7, 0x6237fb48, 0x4e07d955, 0x02198916, 0x10de9b52, + 0x439e7db6, 0x2bcfec4b, 0x72d50fee, 0x3fb666c6, 0x63e32139, 0xee9b1cc5, 0x7b3684b7, 0x4f8673e4, 0x9d8de5f6, + 0x856a8ad4, 0x6d0083b4, 0x96df1d8c, 0x7488f147, 0xcc25cedf, 0xeb464384, 0x12cbb9d1, 0x85b416f9, 0x799d8c7d, + 0xea12ea68, 0x2ee0d084, 0x538a6b88, 0xda69b8ea, 0xbbcd9d5c, 0xffc80c91, 0x1694ec0d, 0x5157e1b7, 0x2b23d035, + 0x5518da9f, 0x70df0f50, 0xcc4b585c, 0x4724c3b2, 0xfdb5ba49, 0xaf09b549, 0xd1764a9e, 0xff63f8e0, 0x3a197292, + 0xa7072fee, 0x28d2ecba, 0xba2ad3c7, 0x828c515f, 0xb805692f, 0x9e6218f5, 0x04f4fba4, 0xb35187a2, 0xff36d759, + 0x7e36c194, 0x6b820bd6, 0xaabfea40, 0x77f4f258, 0x10eb801a, 0x330f2dd8, 0x96a113e1, 0x4ccdfc4f, 0x55f14139, + 0x78900d96, 0x36f034d8, 0xd8ac8b6c, 0xe745343d, 0xc9b76d55, 0x8efd95b7, 0xcf9542e6, 0x254a1dff, 0x30bdb5ea, + 0x06fa79ef, 0xd4108cda, 0x8a47df96, 0x39f7fc70, 0x52028b21, 0xdc682d9c, 0x28c32f88, 0x059f75bf, 0xce7b7c26, + 0x65d8c264, 0x5efecc0d, 0x7c0b5acb, 0xc22bd65c, 0xf50839f8, 0xb71bf2b9, 0x45adb649, 0x78e7d00e, 0x6af4fca6, + 0xfc4899ef, 0xfc9e4726, 0x3b7074cf, 0xfcf12895, 0x28b420cd, 0x9374ce05, 0x1b22f9f0, 0x411e3836, 0xc7663a9e, + 0x00a45b22, 0x0e8dc429, 0x52d5ba0e, 0xafa5c001, 0xd4886eaa, 0x79a8aea5, 0x71b71895, 0x6e12b2cb, 0xe35e8d5b, + 0x8830af30, 0xc7e8625d, 0x8d98a4b5, 0xca6e99c1, 0x5f94686e, 0xa6a37650, 0x65ab7806, 0x52030f82, 0xafe1e7d7, + 0x7d2f220f, 0xd02cccc6, 0x7913633d, 0xf3406a5a, 0x40fe2548, 0x69ce323a, 0x15a3edfc, 0x10725161, 0xa076462d, + 0x01186085, 0x3a74fa89, 0x42e4425f, 0x97aecc07, 0x343198bc, 0xb01b6804, 0xaa43beb5, 0xca84702e, 0x6cb694dd, + 0x3251ef36, 0x68931f43, 0x164f0d05, 0x00f7b39d, 0x62400e86, 0x36cff1e1, 0xe9c63b1a, 0xb8dbce8c, 0x76be87ce, + 0xe6f12404, 0xfddae36a, 0x8da676ca, 0xe263f65d, 0x1c1edb59, 0xd9985f42, 0xc800c1e1, 0x05d36cda, 0x71581f76, + 0xbc87bc67, 0x5093fd0d, 0xa704ab26, 0xe84e051b, 0x36cb8a4c, 0xb8e18b1a, 0xa40816cd, 0x79710c81, 0x9575e83f, + 0x8a14da22, 0x6c45bd3e, 0x08fdc95a, 0xf83d57db, 0xa7529e0a, 0xe4d9c768, 0xab84ac31, 0xfe8b727e, 0x409cee51, + 0xc528c67b, 0x56b396d0, 0x8b70f518, 0x8288ec0f, 0xfe7b7603, 0xa572a5c5, 0x215e7b78, 0x98e282d1, 0xd3799ded, + 0x67d6a89a, 0x54313406, 0xf88478b0, 0xc986ec02, 0x118430bd, 0x4f2078b8, 0x11a69cd8, 0x8144faf0, 0x25f827ea, + 0x63b16a39, 0xf4b759f1, 0x1c560136, 0x58bf5087, 0x2c239870, 0x5722f768, 0x59e60b5a, 0x26d38039, 0x61af8906, + 0xca6660f7, 0xcc0f5a85, 0x9f8828a2, 0xbccc654b, 0x49f23975, 0x8328a14c, 0x322c578e, 0xbdb94872, 0x4b338ca4, + 0xff413968, 0x736308cd, 0xc9e92589, 0x43dd731b, 0x1892965e, 0xbd2a9c4c, 0xb5c74bb3, 0xdc2c3ba9, 0x2dcc0149, + 0x8f3dbf06, 0x8b8c20fd, 0x5c4f5cd9, 0x86708a32, 0x7a980186, 0xe67e4dad, 0x6ee9575d, 0x95bc3fbc, 0xc0976124, + 0xef3c30d9, 0x2fe1bdf1, 0xabf2bd1e, 0x76872d71, 0x9ec99bc7, 0x2ccdbdf2, 0x9103161f, 0x6fb36067, 0x9df71012, + 0xf85568a4, 0xe92c4e77, 0x656d1da9, 0x317febee, 0xfe05d989, 0xb8332d95, 0xbd5ea9d6, 0x6a5dc60f, 0x1e385f2a, + 0xb0e03d6f, 0x511edc22, 0xe6997f52, 0x13c6ce5f, 0x4b8ed727, 0xce5e9cd4, 0x35ce7468, 0x9b299a4b, 0x71f7b1df, + 0x445353cd, 0x97b0e649, 0xdd579024, 0xb35eafec, 0x5aabeb92, 0x79fc11ec, 0x07f577e8, 0x4c138124, 0xd9bb0e7f, + 0x1d61c61f, 0x8abcc198, 0x6d76d30c, 0x4c085751, 0xb2efb633, 0x9009f4c4, 0xc217acdd, 0x234d8144, 0x90388bb8, + 0x1c374670, 0x2272722d, 0x70ab1ad2, 0x3cffb06c, 0x579a77d7, 0xd7e07bf5, 0xd1cc20f3, 0x98f893a9, 0x8074cf5d, + 0xccfbe951, 0x5fffa63d, 0xe2ab53c9, 0xc0940b25, 0xad4d89ad, 0x4fbf9776, 0x41cee2a5, 0x25562200, 0x85df642a, + 0x760611f6, 0x50e9d5a2, 0xddcaa3d2, 0xb96fa67b, 0xaf3d1292, 0xf9c11070, 0x919a749d, 0x7973d3e4, 0xae7d0761, + 0x16625379, 0x474ffc85, 0x821e3870, 0x2bfdcf98, 0xb80f8790, 0x5db63f2a, 0xb2e5e5fa, 0xe8e214ae, 0x568ed134, + 0xd956b337, 0x76a60a69, 0xd5d3c011, 0xe92b717e, 0x22d49fbf, 0x7aa725c1, 0x189e7dab, 0x9bdcdd04, 0x3f0a9ed1, + 0x3cbb79df, 0x96582920, 0x3b20925b, 0xa7e246d3, 0xe79548d3, 0x61925dff, 0x12b79d8f, 0x9b79fdc4, 0x7bb58d1d, + 0x9b3248af, 0x26304bec, 0xfb681575, 0x403064d8, 0xd21f52fb, 0x709ede93, 0xadc8b8b0, 0x75d7dbd7, 0x24b769ce, + 0x0608797f, 0x31093f7e, 0xe32047fc, 0xa626a85b, 0x489eb40f, 0x73ecf062, 0x82634b59, 0xed700342, 0xa3664f23, + 0x75188f7f, 0x7f0dfb8c, 0xff998288, 0x818d0d05, 0x76f00fca, 0x416c41a5, 0x1aee25c4, 0x8cdfa468, 0xcc84eefc, + 0x37e1752c, 0xcbd9b676, 0x61deb096, 0x35d263bd, 0x6bd33047, 0x5a277217, 0x96662092, 0x450d70f1, 0xbbdeb7e3, + 0xecda6767, 0xecafca95, 0x6619becb, 0x319c46ab, 0x304f54ef, 0x9878c003, 0x1b0d0da7, 0x02e81dd3, 0x5549dca0, + 0x2d45db8f, 0xaa15877b, 0x3555c919, 0x9157f4fd, 0x22ff8d85, 0x9d131c58, 0xd2e0c475, 0xde48a3e8, 0xd2f97305, + 0x1b631356, 0x3ae1193c, 0xa0bc579f, 0xcb7f8571, 0x55f3352c, 0xbc7307c2, 0xd8fa3690, 0xe552bc59, 0x8dfe457b, + 0xd1734d7a, 0x96ce61a1, 0x655860da, 0x6c80e314, 0x3bd34e01, 0xefc751ec, 0x671164ec, 0xc237acb5, 0xcce6b17c, + 0x138158c7, 0x717935b1, 0x0731e439, 0x2c9beca6, 0xd90199fe, 0x2dba4e21, 0x781788a2, 0xe26a1bf4, 0x6e802625, + 0x4a9b5da3, 0x77bfe1e1, 0x71e2db33, 0x803d60e5, 0x67959999, 0x7aea37f2, 0x303678a7, 0x3e424da4, 0x3b788d09, + 0x11562a48, 0xcb624f54, 0xfa0ba1af, 0x00e5966a, 0x3554c577, 0x27188aa2, 0xee60440e, 0xd4cd3974, 0xbea19c93, + 0x631815fe, 0xbd876bcf, 0xe662ae9f, 0x085fbed0, 0x2bbd58b5, 0x2991faec, 0x6703f56a, 0x3a06f591, 0x9d59abc6, + 0xa94eda2f, 0x5da367a8, 0x2e2fe90f, 0x65231754, 0x1738ce4e, 0x09a2d631, 0x3e58305b, 0x2ef06d79, 0xde97b66f, + 0xd3466eac, 0xdcb9a554, 0x24020a0b, 0xaa36a157, 0xddb390ab, 0x6da41464, 0x290ae571, 0x7064c276, 0x2ef4553a, + 0xea2ee421, 0xf41a92b1, 0xb1be11a9, 0xdc819ef1, 0x0894cc1e, 0x69948206, 0x62ef6df5, 0x06c52d39, 0xb6aca0ad, + 0xdb5714d2, 0x3ed0b52c, 0xe56b4724, 0xdf7137f0, 0x25b7bc91, 0x160f7daa, 0x8147be08, 0x253a5f1c, 0xaccc73a8, + 0x08c2c7aa, 0x3a968729, 0x7392991d, 0xa4150be9, 0x60333787, 0xbd3d6bd3, 0xea01b592, 0x8fdeb61d, 0xcfdd9094, + 0xf247b107, 0x0f1a49c7, 0x93a426c9, 0x58d2f80e, 0xcf405630, 0x5053c43a, 0xb91f70c4, 0x4d3be1d8, 0x7e0edcf1, + 0x1a1c236c, 0xd4bc09ad, 0x275335a0, 0x8e6cd35e, 0x5fefda8e, 0x3dc0f93a, 0x490d05a5, 0x336334a7, 0xb546ff92, + 0xfdcd413f, 0x0da99587, 0xe28d1153, 0x77efa71c, 0xaedaa4c7, 0x37cb781d, 0xbc9d79a6, 0x61f515c7, 0x0dbefbb9, + 0x0b37778f, 0xbcd9cb43, 0xfb5f22cb, 0xc1598cd2, 0x085fad6f, 0x34805734, 0xa45de80a, 0xf9fc130d, 0x2418c964, + 0x809d18be, 0xdca0a555, 0xf945e18a, 0xea0989e6, 0x2b7ac819, 0x46d3521b, 0x915efbb5, 0xd8c78e4e, 0x542e41a7, + 0xd356448b, 0xdb16de3a, 0xf3a46b2a, 0x7aed996d, 0x45db9011, 0xae2de3a9, 0x8b2579bd, 0x6c1108ae, 0x7b46b156, + 0x25d5ad4e, 0xecfe888f, 0x983bbbca, 0x9cde0859, 0x4444de52, 0x931edc62, 0xb68f26f4, 0x299b8fd3, 0x11a957ff, + 0x041ff16d, 0x21a73d6d, 0x9a331c19, 0x9074b069, 0xa5abca10, 0x321520ed, 0xff99e5b8, 0xef1d0f97, 0x6e911e70, + 0xf804f4c5, 0x4a79e3ff, 0xd31a6986, 0x74f2df38, 0x33c8c64d, 0x1e357a76, 0x60ee5af4, 0x149f5ad2, 0x695f1bf0, + 0x3962201c, 0xe5930dc2, 0x0fd9f877, 0xfc779e64, 0xc5d782ac, 0xcd09f9c2, 0x7de9607e, 0x76da6c24, 0xae14cabf, + 0x55893be4, 0x562d2344, 0x6eb8bb39, 0xb5da8750, 0x15685b50, 0x05db1411, 0x99f54e3c, 0x9f0790f7, 0x2d79b377, + 0x7b253e0c, 0x8f032ebf, 0x50338df8, 0x0b750326, 0x9721f518, 0xd4de765c, 0x99adc5f1, 0xc78fce50, 0xcb30c981, + 0xb5aecc9f, 0xdc775a51, 0x81a5d959, 0x99c2837b, 0x8fbea31c, 0x165b298f, 0x67dc3547, 0x8b7accd1, 0x29da0c17, + 0xd60767e4, 0x5054380c, 0x6d598ad2, 0x61bdab38, 0x2f248f8f, 0x7a87d473, 0x7aad6f63, 0xf655460b, 0xeaf86861, + 0xe423adf1, 0x17562568, 0x6ecfa7d3, 0xfd080d30, 0x9bd5a2a3, 0xd3b9a3fb, 0x4d4d3b21, 0x561ce30c, 0xe22ff5f6, + 0x40051f8b, 0xe9ee21d3, 0x43ecabc5, 0xad6bd578, 0x1de2100e, 0x509d6d7d, 0xe0e353c8, 0xefc75ebc, 0x64172275, + 0xdc31dbec, 0x04f7ec9a, 0x715ac2ac, 0xccc8b7aa, 0xc70210be, 0x2bd04d32, 0xc3f072f4, 0x0412dec0, 0xdc30c21e, + 0x3f037cdf, 0x46768833, 0xa27707d9, 0x50ddc532, 0x8681a324, 0x00447676, 0x6d5fc9b8, 0x1a59ebe2, 0x877b39a1, + 0x736c2832, 0x8d533ed6, 0x93b5c396, 0x8582d436, 0xdd75528d, 0xf834f98d, 0xa5b8ffa7, 0x6d816289, 0x2c76b871, + 0x4794ffba, 0xf1609c1f, 0x49419a08, 0x14385805, 0x81a27f0c, 0xa274aabe, 0x4336c95f, 0xf1009d92, 0x14cd691a, + 0x76715f7b, 0x219f780c, 0x060ca24c, 0x7f55ef08, 0xd57f6fbd, 0x5d4be898, 0x158f3c64, 0x1f8b08e9, 0x8bdcafae, + 0x6895a5f7, 0x80c9315e, 0x7e991b31, 0x8aad4d20, 0x1406a30a, 0xe12e3dcd, 0xd99b5acf, 0x3ea6a936, 0x73301187, + 0x63a9517a, 0xbf070e52, 0xfaa46eaf, 0xb8d79b3d, 0x270311ee, 0x9eec7455, 0x9160fd21, 0x4fbbf33e, 0x8bb80cbb, + 0x1e842c3d, 0x59b9bb04, 0xe06cee1b, 0xc57cfff0, 0xdf7a9934, 0x70125c26, 0x17cfffa6, 0xddffd6f8, 0x61a488aa, + 0xc87cd1d2, 0x43bdeaf4, 0x38d6768c, 0x6fb901b1, 0xdf570fcb, 0x007a5820, 0xb273a247, 0xd1512047, 0x6ee21060, + 0xb430ad31, 0x4afbe7aa, 0x4e6dcc98, 0xf37a261e, 0x5ad21d5d, 0x0e90915d, 0x2c6411f2, 0xa22cbc33, 0x979180cf, + 0xf771c232, 0xc3af6bbe, 0x86037b5f, 0xe0dbcf4d, 0xc8a4cae6, 0xaf92326c, 0x0fce6aed, 0xa654c4fd, 0xa23a26f3, + 0xac088b26, 0xded8c48e, 0xf94455c5, 0x739aff1d, 0xed00e0fd, 0x91c0c837, 0x6d2f9307, 0xe772dd32, 0xb69f67c1, + 0x6124dc49, 0xf2a969d2, 0xd9ca6a30, 0x3bb78612, 0x79291d1e, 0x9e419f99, 0xa3f81169, 0x549ef83d, 0xdf73a81d, + 0xe3952095, 0x02829f6d, 0x8d056a90, 0x10fdc58a, 0x2ee8b1fc, 0x139ba34c, 0xe6528f3c, 0x95ecfa7e, 0x81bf10f7, + 0x064fe0c0, 0xd0dda336, 0x4239c7c7, 0x1f096a3f, 0x7db44a05, 0x99b396f1, 0x4431c009, 0xd3353e44, 0xd872c3b4, + 0x1e07da32, 0x9bc42d43, 0xd4830dc8, 0x0dfbb0b8, 0x4eb8147a, 0x9adaae1f, 0x97942370, 0x2e526a4a, 0x07691f5d, + 0x0cf31f69, 0x7f562548, 0xa030b2bc, 0x38504bb9, 0x0aa72c9e, 0x5246642b, 0xcf44f3f9, 0xcc149d06, 0x05368a2e, + 0x0f517d4b, 0x0f2b1fb8, 0xa065a570, 0x7825cdbe, 0x19a21573, 0x5beafbef, 0x88ce14ee, 0x6a4f2fdd, 0xfbc22091, + 0xd4f4e61f, 0xe86509d4, 0x1e41f692, 0xb208021b, 0xaa607e4e, 0xd4583973, 0x0099e2ae, 0x8c21cc31, 0xcc8f9bfc, + 0xd7ed470b, 0x26e24a30, 0x3d1472e5, 0xa8b85055, 0x7ff03e49, 0x28674880, 0x74efb981, 0x2c3245f4, 0x5ece8e9e, + 0x0688e0b5, 0x70b45589, 0xa32dc06f, 0xab7a2269, 0xb867db20, 0x3ad4315a, 0xf5a1def3, 0x00856e45, 0x70ce1466, + 0xeab8bca9, 0xdc42012a, 0xeec06983, 0x22c7c9c9, 0xc4ccd0ac, 0xe54ec9a1, 0xce2ef50c, 0x8032a847, 0x5aab8a1d, + 0x9a8a5b31, 0x21fe7281, 0xef83ba70, 0x88fe2f7d, 0x2e23f46b, 0xd5bf44eb, 0x27e374f1, 0xf7ba4c6b, 0x470201dd, + 0x8f1389a8, 0xf83ec693, 0xe680b666, 0x8a70385b, 0x7982c549, 0x72ee50ba, 0xe05812d7, 0x9930657c, 0xd7eccc93, + 0x897e341d, 0x59ab5c5c, 0x3a106334, 0x8c5dedd8, 0xe7333318, 0x41cf0ed9, 0x88c88a58, 0x0f9111ef, 0xfa987a49, + 0x1af56b00, 0x6f1266cb, 0x21ade7c9, 0x8e0bcf92, 0x5e96a3bc, 0xe40aec46, 0xdf4f7d91, 0x92f7aac3, 0xd147b9ee, + 0xd02d8908, 0x86eac934, 0x5de88388, 0x1432215c, 0x3c3ec193, 0x885fdc2a, 0x3882f20f, 0xd59a21dd, 0x84717bf8, + 0x68784513, 0xe1746f4f, 0x5ca0a94b, 0xa074f908, 0xf05be2da, 0x2c9f7b0c, 0xe06f6b2e, 0xafcdc44d, 0xc744bce9, + 0x94fd3a09, 0x0e52676f, 0xadba6a06, 0xd2b179b0, 0x87eba072, 0x9343e940, 0xbb8f5c2d, 0xf6402c9d, 0xd64f22bb, + 0x98ac2c62, 0x19bed524, 0xf34eb446, 0x4385d121, 0xc00ec3e2, 0xca566232, 0xf33930af, 0x86641252, 0xe3c8a9fe, + 0xccb833b6, 0x192dded5, 0x7e1d1c9f, 0x91c62627, 0x2e9673a3, 0xab436926, 0x0a613e01, 0xc669325d, 0x074ff14f, + 0xde65cbde, 0x324e42c8, 0x726608ea, 0x74ec2f0c, 0xedfe987b, 0x43104ac4, 0xdd363f9a, 0x7827e3be, 0x5e8bb021, + 0x951eee1a, 0xcc2baaba, 0xcf34ec17, 0x89ce6b9d, 0x473ec9e6, 0x228dd67e, 0x8058b58a, 0x8acbc568, 0x84bd6af3, + 0x76ff5c77, 0x213f9d62, 0x3ef3ce61, 0xf439fbb1, 0x80c58888, 0x7141ca77, 0x1f2f905b, 0x8a6ea1e8, 0x881ae994, + 0xc2da2c53, 0x9d397798, 0x028c429e, 0x7b64af75, 0x995df0a7, 0x2d16f9bc, 0x626710b7, 0x795ece1b, 0x47c8b861, + 0xb323aca7, 0x0d62290c, 0xed1a7cee, 0x16caabbf, 0x2ad440ed, 0xe589d979, 0x7d1f94b2, 0xb795a78c, 0xa07c8bdd, + 0x7f1b5064, 0x25f1aa59, 0xab1bfe84, 0x0541892b, 0x845c6ead, 0xdce5cc84, 0x266f9273, 0x77435c2a, 0xad012819, + 0xf26289a1, 0x839e4b9a, 0x055c24a6, 0xc70fbdda, 0x4001d652, 0x0c159e2b, 0x02e616b8, 0xa4602321, 0x3bf85c95, + 0x55b1b173, 0x342314e1, 0xfbdcac0b, 0xb255a45a, 0xfbbcbde7, 0x096644bb, 0x623ba653, 0x199ebfe5, 0x01ce3c90, + 0x60e85fb6, 0x9ac3c56c, 0x08c07dad, 0xbf3f479c, 0x1848818d, 0xd239fcf0, 0xf82dbe6a, 0x41d71396, 0xc20b2c4c, + 0xf0a054ee, 0x83b629fe, 0x8fce9ff2, 0x4a385042, 0x407c65fb, 0x6c66f6b2, 0xb0a401d3, 0x56a331b8, 0xbf7f1db8, + 0x40bcb152, 0xd5733aac, 0xae6f214c, 0xc35857c9, 0xd23bf3a6, 0xdad143bb, 0x5869598a, 0xa49e97f7, 0x3c20aac6, + 0xdafe010d, 0x05ff29c5, 0xadae4e21, 0xd2e19871, 0x214499b0, 0x53752137, 0xa3ea46aa, 0xf6ed2069, 0x36bcdd66, + 0xa08010ad, 0x7c881fa7, 0xf5cdbbd1, 0x75202de0, 0x19fa5c4c, 0x8c4f6356, 0x311465d7, 0x2e088e9e, 0x5ffc47ea, + 0x9a18647a, 0xb36e0a69, 0xab0b579e, 0x98f8693a, 0x7d8fe2a0, 0xd5e96cdc, 0xbc70b871, 0x2530d8f1, 0xe113fcaf, + 0x46eccde8, 0xb16284d6, 0xbaadca5d, 0x6bab590f, 0xdb334c29, 0xd916f9d3, 0x015b250f, 0xa60d8f53, 0x1fb83842, + 0x0ddd442e, 0x3a19501d, 0x9af33a4b, 0xb94c0a78, 0xc10b73ba, 0x129c3a93, 0x4dacd5f5, 0x0226a887, 0x69b45ccc, + 0x40e8325c, 0x5a0fb3b4, 0xfcd93c93, 0x572c9541, 0x27084441, 0x12cafa67, 0x8538617c, 0x0b57d51b, 0x3ad8a310, + 0xee6993be, 0x71c3933c, 0xc1a9f32a, 0x5c34affc, 0xeec5f2c7, 0x66cd843b, 0x62f33d59, 0xd585472f, 0x816d518c, + 0xd97262d6, 0x5d3af753, 0x476e3e71, 0x552bc93b, 0x81bad9e2, 0x0be58638, 0x1f6cd97f, 0x981ef129, 0x14a51b2f, + 0xe393ddc7, 0x23d6b885, 0x2521b217, 0x2b57cadc, 0x97334ace, 0x6db863d4, 0x5fc36421, 0xd52c023c, 0x196a3743, + 0x915a7d9a, 0x7be20675, 0x5e0251a9, 0x5e5e4d6d, 0x3bc48e0d, 0xa35dcb7d, 0xe76d0c57, 0xe9925f67, 0x2e68048c, + 0xe6c1d44e, 0x11e78d47, 0x70123057, 0x7e699193, 0xbab0890a, 0x4fa0adb2, 0x8df114f7, 0xddbdc16c, 0x1002479b, + 0x34271d5a, 0xa0f589f5, 0xd8d378f6, 0x42e72101, 0x5ded887b, 0xbe6a2eb5, 0xefabe82a, 0x83065d34, 0x3b3a9e77, + 0x1a92851d, 0x4ff68f41, 0xe545c1a8, 0x461a4801, 0x47427877, 0x284d92ce, 0x2af1c5db, 0x0422c081, 0x3ffd5444, + 0x88dae012, 0x9288613f, 0xacbf92e6, 0x8af58ae7, 0xa3e412d8, 0x1e584ae7, 0xde8f020d, 0x3b1cf6c5, 0xc5f93d2d, + 0x522da810, 0x67ca30bc, 0x9bd44ff1, 0x3d95b68d, 0xd2860e16, 0x40d223e2, 0xbdf986d8, 0x393b0017, 0x4f0afca2, + 0x892d7a9a, 0xedc9b3d9, 0xeb14d463, 0x8af8cabb, 0x00beecec, 0xd039339d, 0xe8bd1153, 0x0276ebd0, 0xf9eee808, + 0xe0683dbd, 0xd9a75b6d, 0x9f5f5071, 0x04ea387b, 0xad65634a, 0xb6d7f19f, 0xfccb9d64, 0x89c4c73a, 0x455a02ff, + 0x1f53011d, 0x757a1bf7, 0xdf793c50, 0xdcf65e30, 0xbcf15f4e, 0xa5a3d7a9, 0xce02bacd, 0x0f9aa380, 0x1190c0bf, + 0xfbedc1e6, 0x31fee7ec, 0x797baae0, 0x2dcda185, 0x7b1dcc71, 0x19e1cac2, 0x2fb950c8, 0xed0f0382, 0xf6ff1e2d, + 0x4a826ae4, 0xa6ff6bcf, 0xfeb4af23, 0xecb640cc, 0x5ab919f6, 0x6d1fbdea, 0x612b38fd, 0x3f1c159c, 0xb5a6c0c9, + 0xacd78c61, 0x5cfb5247, 0x587c7cd4, 0xa7132d55, 0x9d74f104, 0x7873ffeb, 0xc91c1953, 0xd6576e66, 0x22ab9852, + 0xadaba095, 0x1c189253, 0x61c2f39f, 0x39db579d, 0x717ac8f1, 0x6f13e486, 0x52bad3f9, 0x3fb3960c, 0x5b5f20d7, + 0x76f8f257, 0x6592dd73, 0x44091adb, 0xbe83e0d0, 0x86172fd5, 0x0b0e8410, 0x96ce41bf, 0xef739f16, 0x7f2f5941, + 0xb4d7f144, 0xb2d62761, 0x3f9d77cd, 0x3493f3c1, 0x2affa7f0, 0x2b13ca4d, 0xab0c05fb, 0xe2c2828c, 0x23c811be, + 0x4b4d9bd4, 0x58cb611a, 0xed33baf7, 0x5e95fb82, 0x33c50e4b, 0x24bd72ea, 0xca6322fb, 0x9277d356, 0x1ae05017, + 0xb4a3f05d, 0xa2919546, 0xab926844, 0xec011f7d, 0x3ec573a4, 0x3128906f, 0xf939da94, 0x3231e844, 0x01aa4ec0, + 0x6f07583a, 0xe03719eb, 0x57334e17, 0x8d4bcda8, 0x3af08ef7, 0x2a7a2c87, 0x556e0001, 0x395b37cf, 0xcb2ea562, + 0x426cb6c5, 0xb34079ad, 0xa4dd8f47, 0x08c8a52b, 0xe7c7be00, 0x43a81b7a, 0x89993323, 0x40d14fc7, 0xef2bc2c9, + 0x4bd0ccff, 0x5e355d04, 0x7759aeb5, 0xe2828cbf, 0xabe6b5dd, 0xdef9fd45, 0xcabc2187, 0x70c4d6cb, 0x58e9833e, + 0x93191b38, 0x118e5332, 0xcf71e5ae, 0x80dee23c, 0x68c12cef, 0x2da1c59c, 0x9366e31d, 0xf6c6928c, 0xd107df42, + 0xa2787819, 0x4f9b772a, 0x3ba11c65, 0x4af15ad1, 0x8eb200df, 0xf033354f, 0xf1fbf48a, 0x961151d0, 0x412a02e8, + 0x7c0faa46, 0x156e3599, 0x451a0366, 0x734a0fc1, 0x0c46f4a7, 0x62985728, 0xf7d1d503, 0x51c63e63, 0x2699eb3c, + 0x0bffc484, 0x52b2d1b4, 0x24dd1df7, 0xff849557, 0x7fd97725, 0x5fab6146, 0xa92242f1, 0xa58ea319, 0x65896aed, + 0x3634684e, 0x667b9078, 0xd4859e99, 0x3b8f5afb, 0x095ddca7, 0xbea6ac76, 0x328aa027, 0x98e761f5, 0x45148542, + 0xcca28eb8, 0xa97ab4e5, 0x07288f7f, 0x30745493, 0x11c473c2, 0xd6719ae0, 0x95c17f00, 0x036511ad, 0x76f84f47, + 0xc0e46d3a, 0xcd579e7d, 0x5f3fe623, 0xa852e23c, 0xecefff7c, 0xd6cdf5c8, 0x793110f1, 0xc21ba788, 0x331a7a63, + 0xf107d5fc, 0x42efee2e, 0x9969b7aa, 0x980b21d3, 0x40114003, 0x5e8ce5a5, 0x9733448c, 0x36a40053, 0x7a74e12f, + 0xdd155bdf, 0x45c297e5, 0x6d1a4a03, 0x272d0db2, 0x6ccb54eb, 0x13e700e2, 0xfe7f66cd, 0xfcb6e67f, 0x4a9e4c65, + 0xc1676178, 0x3ba7c22a, 0xa1737f1e, 0xa7f4ee52, 0xfad03425, 0x1e1ba0c1, 0x480238d3, 0x6dc2559d, 0x33003291, + 0x2ed8e47d, 0x98e09ebd, 0x6c22f773, 0x9f89d747, 0xa3639bfb, 0xcec61043, 0x4501ee20, 0xcc0361da, 0x1fd175f3, + 0xe1252d5f, 0x3666c791, 0x7866e40c, 0x635e475f, 0x5e80cd61, 0x629b8dff, 0x31525dd8, 0x86ad2168, 0x5c1ad502, + 0xf24c7c1c, 0x0d88311a, 0xb68d4b18, 0xb26bc963, 0x4386c88d, 0x7ddbdab7, 0x406e1b2b, 0xe6d62490, 0x25b77340, + 0xc39ef450, 0x693c556b, 0xc83ea1f1, 0x1e962da6, 0x8e3b5caa, 0x76518cc5, 0x980b0c18, 0x66d9a09e, 0x575acd53, + 0xe701cca3, 0xec2d9d2d, 0x6a64c9bb, 0x86aa4e9a, 0x7bbcc74f, 0x487ba026, 0x1d81e93b, 0xaad8288a, 0x79d76f1b, + 0x75015559, 0xe4a1befb, 0x17b0621c, 0x76550855, 0xc50e0d75, 0x3947e7fb, 0x8fe63422, 0x14c4cf78, 0x61e8f824, + 0x7e61f685, 0xb02a1bba, 0x7d76c00a, 0x3ab2adb3, 0xb3eb3191, 0x480746e1, 0xc1078145, 0x8d2df6e1, 0x631897a7, + 0xbd3d83ed, 0x6ff8ee9d, 0x7abc06d4, 0x96a89a09, 0x06b41c1c, 0xb015650f, 0xf6f721e0, 0xadf69827, 0xc74075bb, + 0x7fb1c111, 0xb6a98f57, 0xba6f9d7e, 0x9199ec5f, 0x9f92f2c6, 0x08e59443, 0x31688656, 0xa9f37c01, 0xb51c22f1, + 0x5f5de2c7, 0x3ea63c9c, 0xdbb94d12, 0x2ae1a3d6, 0x3317cf21, 0x22a4b1f7, 0xe377be6c, 0x1e98dcf8, 0x194f8629, + 0xe65fc0c8, 0xbd0706db, 0xde7b56a5, 0x150d4dfa, 0x50cd7fb9, 0xe77901c2, 0x370991ee, 0xc23b4b5d, 0xe824d7ca, + 0x98be4542, 0xca1f04cd, 0x8c995b61, 0xd97d7835, 0x839189e1, 0xf41ff215, 0x99d59583, 0x0467a3d1, 0xaf3da310, + 0xebcefed2, 0xd91aad9f, 0xe3ebb282, 0xc96107ef, 0xc10e8560, 0xe5b1da72, 0xdc889da8, 0xd35f3e0f, 0x10b418cc, + 0x74072ec3, 0x182ed8e2, 0xda8e5d22, 0x41df4b2b, 0x55e4d003, 0x3c17a1ee, 0xf63b1d86, 0x3f26b25b, 0x2b28410d, + 0xe0f0964a, 0x911e5793, 0x63575b93, 0x19bea982, 0x9e16c752, 0xd10fc179, 0xe6e88147, 0x4c89e52a, 0xb1347f2d, + 0xe49f34b5, 0x7fa38361, 0x744c296a, 0xf852c9d1, 0xe6c4d356, 0x3c29c5c4, 0x7601f875, 0x3e1ebb69, 0xc0fee643, + 0x15a1926a, 0x9b63a2a3, 0x46e195d6, 0x6d0b0512, 0x29920dcb, 0x6df2b2bc, 0x3d1061bc, 0x62094121, 0xfca8d7cf, + 0xac390727, 0x3c93c05d, 0xbf43f045, 0xe51b3fc5, 0xf2e1bcf3, 0x2ffaea1e, 0xdaed23c6, 0x495f3b3c, 0x405f3d14, + 0xb285fe39, 0xd616f4a4, 0xb833b433, 0xbd534840, 0xf2448b03, 0xacdfd86f, 0x5e6a31c0, 0xce20fecc, 0x5727d8e6, + 0x0f8f4635, 0x396e0f23, 0x6bac9e11, 0xeb9ccf32, 0xf95e2efe, 0xeb14627b, 0x0d88976f, 0x45223166, 0x61e00cf6, + 0x79b8b642, 0xf27625e6, 0x2cae88a9, 0xbcb419d7, 0x866cc9e6, 0x26e50256, 0xa2c9209f, 0x62fe1630, 0xd27d054e, + 0xa19839da, 0x719db85e, 0x4e98b8d7, 0x078c9de3, 0xc054f8a4, 0xf150b4eb, 0x22d576d8, 0x85df5fe3, 0xb1ef03f3, + 0x7562cfdd, 0xc81df021, 0x40accab6, 0xf5e61c86, 0x1a001555, 0x5d6cbd57, 0x1c8bf550, 0x114af6b4, 0x3795e3f9, + 0xd3a4456b, 0xc39644a5, 0xb4ae0db0, 0x9161d36b, 0x52258466, 0x6ac3188b, 0x1da4cddd, 0x31839ca2, 0xce6e8b94, + 0x92a72e00, 0x54def847, 0xbcf6ac82, 0xa32f70a1, 0xfd74eb6f, 0xdbb9752a, 0xa660ad9d, 0xfef233aa, 0x301c13ea, + 0x9bb28f15, 0x680bcb87, 0x1e679bb6, 0xcbcf26b6, 0x4403b451, 0x2f6bb5ba, 0x9ed6eb50, 0x6c87fc8d, 0x826cf742, + 0x61454725, 0x594d2512, 0x9f8d4382, 0x1dd55c84, 0x1c1b9927, 0xf4c5c57c, 0x80e8445d, 0x6d057528, 0x16b871e3, + 0xac502aa3, 0x95501c18, 0x47d4207d, 0x9335542c, 0xe584864f, 0x909a94ce, 0xceaf718f, 0xa70f9cb2, 0x21d79c89, + 0xc85aadb5, 0x8db28791, 0x7b1c87ac, 0x157a0d58, 0x1473e076, 0x82a89ba1, 0xdb752771, 0xb342ee62, 0x58ef1dc1, + 0x1161bc03, 0x11903c16, 0xea5d250b, 0x485e5db2, 0x457237cd, 0x31ea6d29, 0x49484121, 0x7f718fc4, 0x8d784c12, + 0x2737b2f1, 0xb18e8a22, 0x856a6cc2, 0x0f70d317, 0x1c401646, 0x2b0491a9, 0x7cf9cb4c, 0x3273d49d, 0x1eb93088, + 0x24b21385, 0x4e70d153, 0x006c4029, 0xdb2cada3, 0x42bea7b7, 0x5a4fa14f, 0x07c79aa1, 0x4baf20ce, 0xce48f1f3, + 0xce746aa0, 0xd7dec518, 0x75585595, 0xe4c22f1e, 0x2dc38d42, 0xeb32807f, 0x650fec55, 0x5a6f9ba7, 0x0e08b886, + 0x6879b6d2, 0x61c222b0, 0x238e9aa8, 0xd13be8c2, 0x2aaf708f, 0x60917736, 0x86a9bff2, 0x6ce01295, 0x91fb5421, + 0x08b33295, 0x8695c546, 0xb072546a, 0x812538d6, 0x9787ac84, 0xdd18787a, 0xa1cc937d, 0xff877770, 0x194474b2, + 0xab54fd00, 0x980b96f1, 0xeb444435, 0x04f522d9, 0x6bb6bec1, 0x37f96313, 0x9ae8a825, 0xfcb4aa55, 0x0d419b7a, + 0x5444ba32, 0xc6cbbae7, 0x5a93e91c, 0xae758b39, 0x8264dcdd, 0x325a4e77, 0x1662b200, 0x8aff1c5d, 0x5efa7894, + 0x3f5d6ec8, 0xd138d7f3, 0x8a9f2451, 0x61caebc9, 0x6d3d549e, 0x6f80910c, 0x8c4674c7, 0x3936e8f9, 0xe735e726, + 0x5e7f381d, 0x1fe447de, 0x4b93c6eb, 0xd18951cf, 0x1f4e81ce, 0xc4e4326a, 0x37f120d2, 0xd4fbbdab, 0xa3377f42, + 0xcc29039b, 0x7bacef94, 0xc08036db, 0xe2b463da, 0x0235da19, 0xceaceec7, 0x733105b8, 0x85ece903, 0x3ab73c8e, + 0x87300a83, 0x98706087, 0x7b43ae89, 0xb83a5753, 0xaeaedec8, 0x2de69059, 0x8a698a78, 0xe8da76d4, 0x071e1640, + 0xb06470f5, 0x74959627, 0xa0f4fc71, 0xf7b2f4ea, 0x7c6cb25b, 0xc1c2a105, 0x2f533940, 0xafd030bb, 0x3cc2eb66, + 0xa2f8c023, 0xdac95c03, 0x3fe2839a, 0xe23916fc, 0xd94edff2, 0x5f525d55, 0xbc6391cb, 0xfbd5b1d0, 0x32a22ab7, + 0x3d8c3bc0, 0x4a961324, 0x47177af8, 0xe74e3c42, 0xde37be46, 0x9cd77f45, 0x9f641c78, 0x9bcc138d, 0xc47f5d85, + 0x5667dc47, 0x0210c9b2, 0xd5ff06e7, 0x0b2f1a68, 0x1f76167b, 0x56b770c7, 0xcb7f7b3a, 0x7ddd21b3, 0x982845e6, + 0xa86adb8d, 0x312564de, 0xd1b3c67a, 0xc061759d, 0x2f956c32, 0x93c2e834, 0xb17929da, 0x9830bdda, 0x9a3b368c, + 0xdf3fcfa4, 0xebf381c6, 0x2c10aecb, 0x62c14053, 0x202622a4, 0x9606f7b8, 0x318798e5, 0xab297952, 0x50705520, + 0x6577f513, 0xf8fb0a12, 0x8f15c7b1, 0xcbee306f, 0xdf96f107, 0x9259821b, 0x3b26b28f, 0x82208e44, 0xa136db95, + 0x98c18740, 0x22cabd1e, 0xf99c10fe, 0x86db2a54, 0x2a4f83bf, 0xd3675566, 0x1d021058, 0xf780f0ff, 0x70af3f07, + 0x3c6f1140, 0x7a5cedf8, 0xcafe259c, 0xddbd7441, 0x555565b7, 0x97ec4386, 0xc7af6155, 0x27b3306d, 0x60e4d967, + 0xfd5a2424, 0xd570196e, 0x26b9eb5b, 0x4f466700, 0x2ac4709a, 0xc64f4dd5, 0x90b747e1, 0x20e64425, 0x11e0e4c2, + 0xe3f7e89d, 0x9b955998, 0xecb1dd01, 0xbb5cb6fb, 0x4bdc0ba9, 0xca20b11d, 0x22a474f9, 0x55d727a9, 0x77537ae1, + 0xad564b87, 0xe6871b8f, 0x0c9796e0, 0x8a118464, 0xa82a5cbf, 0xf4953bd2, 0x490e1df1, 0x460ef456, 0x319ecffb, + 0x88b5b401, 0x8d890532, 0xdd301d06, 0xcb8382f0, 0x0d6e7996, 0x0d0759ab, 0x37eb20b1, 0xe038af62, 0x48b7aea4, + 0x788fd72b, 0xa90aa60e, 0xab90ea77, 0x9e10e83a, 0xf2645ff2, 0x2f38c311, 0x73148081, 0xc2f55b32, 0x78b51d61, + 0xff180cd8, 0xc42667d7, 0xff82f74f, 0xf8d149b8, 0xe13160f4, 0x5d8e8a53, 0x33d74b53, 0x462d9b54, 0x349f8f38, + 0xd60d9758, 0x324341a7, 0x960a97a9, 0xc7c18ab8, 0x1fec9862, 0x7f1c5fc0, 0xc0870f37, 0x9326e6c1, 0xb4733c44, + 0x92404316, 0x697a0ef2, 0xaa5e3dc4, 0x1cfa92f3, 0xbe87f926, 0x6ab898ac, 0x130f0132, 0xf1294363, 0xb5a52ebc, + 0xd3f8470b, 0xf3eb5d0b, 0x79304847, 0xb487e821, 0xf4f56528, 0xb35b7f94, 0x0c750b73, 0x289a2bd3, 0x190912e0, + 0xd4e4b06f, 0xb68c9d67, 0x65b23c68, 0x634e95b0, 0xd1ee1043, 0x881fe28e, 0xaede9b05, 0x4a638405, 0x127d2cf1, + 0xcb5c99e1, 0x37ec0579, 0x50228101, 0xb1c8006f, 0x35aea92c, 0x6a29abec, 0xef49ebf3, 0x0de3cd43, 0xd04fdbc8, + 0x2e1ff219, 0x641bc484, 0xc0801941, 0x818801b3, 0xdfcfaad3, 0xc70bfc1d, 0x39d30fb3, 0x67670cd7, 0x540dd07f, + 0x2e5182b1, 0x8b2ffda1, 0xabea2eae, 0x2633fa07, 0xb120b060, 0x045dce24, 0xacf98101, 0x50ceebd9, 0x91672c47, + 0xd1072cbe, 0x3bb4be2b, 0xf27bc857, 0xd5dc0d41, 0x098b713b, 0xfc679513, 0x0d388bd2, 0xd762ecb9, 0xf142676d, + 0x0278f8fe, 0xdad6ffa8, 0xbdb57cf7, 0xe68f7c7e, 0xc6f0b75d, 0xcbee1425, 0x8ef2706b, 0x6139f79e, 0x17d7415d, + 0xc8f2b738, 0x4023f573, 0x6638bcde, 0x8297d1a4, 0xfc98269c, 0xd431a340, 0xf3f12232, 0x2978e872, 0xf12de076, + 0xb16021b1, 0x0bb6d1b4, 0x9e6479e3, 0x3e76e9ee, 0xfc9954cb, 0xbba5894f, 0x0f616aac, 0x680f16ab, 0x4df6f85d, + 0xaa22390b, 0xb49f3001, 0xee0c9973, 0xd5732652, 0xbfab5d30, 0xb07a144c, 0xc4da2aab, 0x47f2c3e2, 0xde4a470e, + 0x097fb42a, 0x134865aa, 0x0e499690, 0xdc0a7841, 0x7ffe0f79, 0xcace4193, 0xdbf596b5, 0x41f016f0, 0x829c6df4, + 0x4152bdae, 0x5bbeb812, 0xd6ce8dfd, 0x5b76f537, 0xc0b73196, 0xf82ff1e3, 0x419c6c39, 0x06f186c8, 0x60a9e1f4, + 0xae826581, 0x5178dc19, 0xf780110f, 0x1d485eb8, 0x3351b25a, 0xd38937b6, 0x4f075a9a, 0xdf046604, 0xd74e9659, + 0xe5edd27e, 0x2db4a59d, 0xe96187f7, 0xb6ec8793, 0xadb49256, 0xd6f83346, 0x8f59237a, 0x037d9267, 0xfe88e139, + 0x5e5a4950, 0xab84cc52, 0x865feaeb, 0x53e12773, 0x8a1ff409, 0xc9afc89f, 0xf3b0427a, 0x27874f07, 0xba1c3e6a, + 0x0f85607f, 0x9cfb17f8, 0xe52e6086, 0xd0f796e5, 0x7b91ae43, 0x11b8fd3f, 0x79c56b21, 0x38d6b5dc, 0x64c7cb6d, + 0xaa5c201a, 0x2fcda68d, 0x1ae87f98, 0x47ba3e07, 0xbabc0a22, 0xd9dc67e1, 0x3d30a4dd, 0x15a7aad0, 0xb84731cf, + 0xef01c533, 0xea652842, 0x1329b493, 0x0c6a3a79, 0xf65ce10d, 0x5b455c77, 0x668dd1f9, 0xc1cd735f, 0x6f0cc6e0, + 0xa32c1b1e, 0xfe547d24, 0xbfddf62b, 0x08d73db0, 0xe57bdc57, 0xab51110f, 0xa2f5c571, 0x8f554db5, 0xb661086d, + 0x88991e5d, 0x4e5796bb, 0x73c58019, 0xc1da0459, 0x8957073e, 0x867f8261, 0xfc3264cc, 0x4b841483, 0x1e5087da, + 0xc4314b8e, 0xdf3a5577, 0x1a9aaf28, 0xacb85737, 0x5e9c9e79, 0x2a55a586, 0x5486bf92, 0x911032f8, 0x9c237884, + 0x9c45a7ed, 0xe18d33b4, 0x510df8c0, 0x7f2c86d4, 0xdf662c57, 0x93e73627, 0x224388ef, 0x10c2929c, 0x80a87384, + 0x7f091655, 0x497793a4, 0xc23864b8, 0x77256c3e, 0xc43ee1ff, 0x75563ecc, 0x0ddb9a3b, 0xcb84cc22, 0x42016047, + 0x102c0085, 0x80958e99, 0x1da2ce8a, 0xf8b26d60, 0x184637c2, 0x6313e88b, 0xec51792a, 0x6d078645, 0x65381e9a, + 0xc6c67b57, 0xcae78db7, 0x6c56fbb6, 0xfb154038, 0xa3f42182, 0x61b4e6f9, 0x8f171f4b, 0x0e364ba8, 0xd8f35867, + 0xe246dfdc, 0xef3cdd8e, 0x03ba23ea, 0xa64ceda9, 0x4a01b90b, 0xd9887768, 0xb29b4434, 0x9d1096b7, 0x2ee75757, + 0x5393744e, 0x39fe2830, 0x130eb093, 0x6ee93623, 0x3d5de04f, 0x8c21cbfd, 0xe8566b2e, 0x93bbe755, 0x6de1c661, + 0xdc844f01, 0xe13ed456, 0x09bafdea, 0x646749b0, 0x3cf07990, 0x100a898c, 0xa23adb1c, 0x7fdf5415, 0xc3566018, + 0x09830763, 0x85dace50, 0x7dbb8bed, 0x742b08cf, 0xb00e34d9, 0xdc238c9e, 0xae24691f, 0x12c7b8e3, 0x0948604a, + 0x39940e5e, 0x7db384cf, 0x928a6f58, 0xf9f8d100, 0xda8a2cf5, 0x4d2bc25f, 0x8e528c26, 0xa926affa, 0xe5dacb0d, + 0x8b07428c, 0x8ab491ee, 0xce469318, 0xde439c87, 0xed3cfc57, 0x9ebbf195, 0xcf8e8ce4, 0x06523ec4, 0xb089bfc0, + 0x3a05b138, 0xde043e1d, 0xfe79971f, 0x5a3aa826, 0xfdc7d233, 0xdac621f4, 0x3fcea95d, 0x29333eab, 0xc092ff0d, + 0xe3125db4, 0x5482f1e6, 0x2dd1a7a5, 0xcc9fd7f4, 0x9107e3d4, 0x5483deca, 0x02fc1026, 0x7da5f934, 0x588f278a, + 0xa302d263, 0xbf7eefeb, 0xb74bcdb6, 0x39bca6ec, 0x803c39b8, 0xe08bce51, 0x2fbfb3cf, 0x3324c315, 0xd912d25a, + 0x14973d9c, 0x19e9a2bf, 0xf24e80bf, 0x9662294e, 0x1ff01306, 0xcbab7807, 0xcddd1ee8, 0x880e1cde, 0x0bd6a36d, + 0x22b61d10, 0xbaae1d85, 0x9026e9e8, 0x3851f1df, 0xedbdb05d, 0x9278d3ef, 0xed3c6d15, 0xcc9d96dc, 0xe55b2877, + 0x0807d012, 0xe15c50fa, 0xe636f803, 0xd72cdd01, 0xcf2f1beb, 0x012d5a16, 0x8601aca1, 0xc12dec60, 0x8a1b16eb, + 0xd771321e, 0x525eed0f, 0x841227b7, 0x68da2be1, 0x1d5b86c8, 0xe8f33b99, 0x573d5636, 0x956419c3, 0x86e90ea9, + 0x2c284962, 0x3a90f4f3, 0xaf547360, 0x074e64fa, 0xd511b3ba, 0xa53568b7, 0x3f28c1e3, 0xe07112f7, 0x0d535d65, + 0xc281fe18, 0x1e815f60, 0xd93ddfab, 0xe55b13ec, 0xaeb8bde8, 0xd649a6b9, 0x0b182578, 0x15efb051, 0x8facc0a1, + 0x476fe584, 0x23d43f93, 0xd5971746, 0xdb4676cf, 0x016db207, 0x5411baf4, 0x5e18f1dd, 0x2c46333f, 0x07338a52, + 0x8ba1c69d, 0x17d9540f, 0x84dd0136, 0xaa84eaf3, 0x210092ae, 0x67fd4f12, 0x64cde364, 0x2b833676, 0xc8183c98, + 0x06a2a679, 0xbff38cf2, 0xf323499b, 0xb49a2c73, 0x99f9f511, 0x0ea0191f, 0x12fde2c3, 0x493d5dc9, 0xe18e3b0d, + 0x9783d90e, 0xa394f3a1, 0x8eb75279, 0x1144c69a, 0x38a7fc18, 0x0a37c52f, 0x3d7d16ee, 0xd7994d52, 0x9d1bb94e, + 0x33882f4e, 0x2f316a0e, 0x8ba2aa5f, 0x08f42a55, 0xcab27003, 0x8398ddde, 0x35e11ef8, 0xabda0126, 0x49ab6b9a, + 0x1e8e58e7, 0xb28dbfc0, 0xe23bb499, 0x1fe84c7a, 0xbe5ff6b2, 0xc3d7273e, 0x59ec6e7a, 0x1daa6e6e, 0x5fdc80b9, + 0x471f0d30, 0x0f6abcda, 0x3b56eb55, 0x56d7589e, 0x0094f09f, 0xaeefb192, 0x257db36f, 0x8d21776f, 0x7e88e74d, + 0xa6ec159f, 0xbe7f6f3e, 0xefdaa5a8, 0x6ec45f10, 0x9527900f, 0x7dd19092, 0x4302d093, 0x5c5c6122, 0x945e3207, + 0x0e5e0560, 0x5b9b9837, 0xd78262ff, 0xab648675, 0xc649e3a9, 0xd1d09f08, 0x6ac7f536, 0x718b67a5, 0x3449ae43, + 0x0ff597fa, 0x6b3ef065, 0x90451a5e, 0x5edd2a6f, 0x558aff3a, 0x61cf0521, 0x97b1d957, 0xa7ba72a1, 0x36d8eaa3, + 0x75dae618, 0xc57aaae1, 0x3a1b32f7, 0xa9c0d1be, 0x2518f26b, 0x468b3abc, 0x7d017c8e, 0x2d9231b2, 0x88eb8202, + 0x55101d88, 0xf5afd3dc, 0x04364431, 0xbebae242, 0x00d3179b, 0xbdf34670, 0x0d944e4f, 0xa1424c06, 0x051f1b24, + 0x5a7f3c7b, 0x27a655e3, 0xfa182cfe, 0x62d09d7b, 0xea215b61, 0xb2294bd8, 0x4c60288a, 0xd8d85a2f, 0x11147e1c, + 0x0e004ba6, 0x9b740ebd, 0xb3e9f56b, 0xce331cc4, 0x927763c1, 0x953fbf57, 0x93be2fc8, 0x9cc4195e, 0x736557be, + 0x6993aacb, 0x4236abd6, 0x3bbf5c9d, 0xd94484de, 0x0520a7c0, 0x353215ad, 0x5add962f, 0xd48c06d8, 0x9b4f2520, + 0x677754ff, 0x45345199, 0x4dd22e63, 0xc0ae0a74, 0xe24468b9, 0x7d3838be, 0xbfb43985, 0xf553f80c, 0xdc61e406, + 0x76be970c, 0xaae7ce84, 0xd18c877a, 0xb03bb09a, 0xa714cd33, 0xa6fb8412, 0xa9f1d916, 0x375138eb, 0xa6ac48a1, + 0x89ddafb8, 0x04c14d1a, 0x8378eef4, 0x28445155, 0x9f1c1cb4, 0xada90113, 0x12d59049, 0xdaab7215, 0x1eb9a079, + 0xfa85d546, 0x1fd6be44, 0xdd3ae889, 0x70f0d6b3, 0x42141685, 0x0278b9d0, 0x2c4dfdcd, 0xe33f4621, 0x8cfaf4af, + 0x9c44f166, 0xf0d08925, 0x484f1d4a, 0xcd798298, 0xf970cb9f, 0x7423f021, 0xa5b0c14c, 0x99ed1399, 0x9cdf6724, + 0xe6e0d724, 0x79bc52b1, 0x472bf633, 0xdf27073e, 0x08c99154, 0x07a91937, 0xddbf85e9, 0x04a5de82, 0xd8dda6e5, + 0x18b5990c, 0x8a78b78c, 0x60a54f54, 0x5c399ad9, 0x43141be5, 0x10992eb6, 0xfaf2980d, 0xfad6d788, 0x5718c9c3, + 0x47ef7e97, 0x46f1ccb0, 0x52e10c6a, 0xa0ef431c, 0x315fdf7d, 0x91cf518c, 0xe9aa518a, 0xbc39dc8e, 0x429f27d8, + 0xa3a3318a, 0xe5db5d5a, 0x5754a451, 0x14c7db1e, 0x00d2b59e, 0xa58648ee, 0xf4bcade2, 0x18c37444, 0x3d422dab, + 0xb5a55e24, 0xd71cc077, 0xeaf0a633, 0xe532729a, 0x4f44dbf6, 0xdc028e3d, 0x21ba8af7, 0xe91a1304, 0x9a3d48e5, + 0x4c5fe7b8, 0xd7e6542d, 0xd15b53fc, 0x1296d78b, 0x6c9b81fb, 0x01850931, 0xc9578593, 0xeb6f2295, 0x4f567f4c, + 0x393e768f, 0x2b6850af, 0x099f3ee6, 0x36127429, 0x214fa5f9, 0x8210b456, 0x6c1725f9, 0xd022b5b6, 0x12f2a3e5, + 0xf59d2f9c, 0xbdd6cca5, 0x85f4690d, 0xe37a69d7, 0x1513ff55, 0x0f849541, 0x8ad26803, 0x9d09d84e, 0x37a06924, + 0xf29f33a9, 0xc3114722, 0xe7b9aef9, 0x8d91cb2a, 0xb3affcfe, 0x8f998c1e, 0x76e63b0e, 0xf707dd8d, 0x4693c14d, + 0x4cdf9ab7, 0x210d19a0, 0x3577eb41, 0x61eb2092, 0x00af2324, 0xa9c5a799, 0x82cb447f, 0x86f399f0, 0xef4cc89c, + 0x88ba616c, 0x07b9bcf7, 0xcee354b7, 0x4ff28c8a, 0x2c957b95, 0x7cdf4d19, 0xc21bf6d1, 0xdb53fef9, 0xf1bf4fa5, + 0xcfd5e882, 0x763f7d53, 0x4f1ca36f, 0xc1e56ba5, 0xa806bab7, 0x1f82c45f, 0x3c57b4f2, 0x89d09dc5, 0x12c618f9, + 0x250fa1c9, 0x00d351e7, 0x890f1100, 0x047b06e3, 0xb86b791e, 0x60b0f63c, 0xf22eb3a8, 0x64f1dda6, 0x944c3d41, + 0x1e222415, 0xddbb7f20, 0x4d06aac5, 0xc5a283cf, 0x8d757009, 0x6cdcbb8c, 0x32f102e2, 0x36b9d990, 0xffc9d715, + 0x91d6b8d2, 0x68071cfe, 0x0f671859, 0xfd46f914, 0xd200e644, 0x445b6871, 0xa3717923, 0x86346d8a, 0xda98f5de, + 0x4a5da66a, 0xbc889f3c, 0x1e0f7b42, 0xa8eebc87, 0x01810b95, 0x19fdf485, 0xedee241e, 0xe433e088, 0x8ab80802, + 0xcacfc46a, 0x642301e0, 0x67d56f7e, 0xca3c2137, 0xec6e2f2d, 0xad6e8e40, 0x18eebd79, 0x6f3342cd, 0xd6900dd0, + 0x9852965e, 0xb11a117a, 0xab82a639, 0x41ff7e1e, 0x9aa818fc, 0x64578413, 0x439b00fc, 0xa2b51ea8, 0x7bfb849a, + 0xef5357aa, 0x07bde7c7, 0xbc3d4c56, 0x9a5b4aa6, 0xdc89593d, 0xdaa4cfbf, 0x26fe5586, 0x4b6d4310, 0x243f4b5b, + 0x5fd0a32a, 0xd9a70bd7, 0xd7554361, 0x763b0dfe, 0x118486b0, 0xc2fbed8d, 0xb1532936, 0x9041c6e5, 0x326a6204, + 0x5777958c, 0x324fd032, 0x1813fe2b, 0x45fe1900, 0x559677af, 0x25ad8c65, 0x091872b9, 0x24dda3e1, 0x0ef5602d, + 0xae8daf3c, 0x00dd4c54, 0x246fde59, 0x397f000c, 0x8ba50083, 0x9b425d6c, 0xc2bea6dd, 0x9fd2ee1d, 0xc206ca2b, + 0x10d2aef3, 0x2e0a4fdb, 0x61004835, 0x33556a48, 0xcc9a3e32, 0x919bab08, 0x09367204, 0x3a172841, 0x81366e64, + 0x8380e507, 0x9f4a701e, 0x6d7c8ab6, 0x560c9b6d, 0xf4db65c2, 0x7bf33f71, 0xec873ce9, 0xee707e27, 0x64b711a4, + 0xe7888145, 0xc4e0fe49, 0x16911651, 0x2985e6dc, 0xc6ed4279, 0x4d4b200f, 0xf0ff5dfe, 0xe40d1b05, 0x42b86da3, + 0x4dfc0591, 0x75508436, 0x8f7b6cb6, 0x4e66488c, 0xac769d0e, 0x9f9773fc, 0x5ac91aca, 0x863c41d4, 0xbff1e151, + 0x0c0b754f, 0xa1e95ab0, 0xee58ae78, 0xcd1b41ca, 0x85e6d07b, 0xe0d967dc, 0x2cfb90ca, 0x4cc5b73d, 0x3e3a9e3b, + 0xf87ab4b6, 0xd7f28d21, 0x9b2bc731, 0x425dbadf, 0xb0075a26, 0x742a4617, 0xe115329b, 0xdd8d3df9, 0x880b228c, + 0x94fb4bed, 0xac865501, 0xc743605c, 0xe8dc20a5, 0x55316a92, 0x1f598140, 0x61d4b617, 0x933a7d10, 0x5eb08390, + 0x541db5ef, 0x95e8c138, 0x921f4c4f, 0xb0924fba, 0xc73f15f7, 0x5ea6b966, 0x47f3e02a, 0xda495d0d, 0xd4f063cb, + 0x6a926c09, 0x4cf19900, 0xcb3273ca, 0x79bde263, 0x2c6c55f5, 0xd8dd55be, 0xde49d737, 0x06161357, 0x03f5c0df, + 0x77097016, 0x56598431, 0x1d6f0266, 0x1732745b, 0x6478f27e, 0xec158844, 0xc35ee025, 0xfeef21e2, 0xb9382089, + 0xfa37e458, 0x681f0c69, 0x0a3bf684, 0xa8a33150, 0x023c4b5c, 0x0dedd906, 0xd517730e, 0x261df267, 0x15831471, + 0x119c09fe, 0x18004d51, 0xed43469c, 0x42a6ebe3, 0x4757b0cd, 0x9090ebde, 0xbf8c7384, 0xdb799cbb, 0x11577b62, + 0xd8ca301e, 0xc266f0d3, 0xf4e1445c, 0xc5fbc988, 0x8d6f629d, 0x9d9235bc, 0xd6688438, 0x9d1dddf8, 0x689c33ee, + 0x38cd72e8, 0x844abaf9, 0x3ebcd508, 0x8d86b26d, 0x6cacb2eb, 0xcd327381, 0x88627cf3, 0x6806b018, 0x257be97e, + 0xc9b4e3c4, 0xd0b84640, 0x8c5ccbd2, 0x5bbc2945, 0xd5b59788, 0x7e55023d, 0x970bafc9, 0x2305ae98, 0xb646b0fc, + 0xe8fa62ef, 0xe5da77e7, 0x01dedd5f, 0x84a20955, 0x7fc3ee94, 0xf9403830, 0x63e5f4e1, 0x9e06391a, 0xba4c3b92, + 0xa79d4daa, 0x39220069, 0x3b4a9fc7, 0x31208c03, 0xad0b3bad, 0x71e3f353, 0x6f242a9c, 0x61cbb083, 0xb12f3ed6, + 0xfd7fee58, 0xf6cdc91e, 0xe90f3f9a, 0x9a22b153, 0x3f705f79, 0x7e1d2165, 0xc7ea3be2, 0xc6eb47c8, 0x199eaeb2, + 0x67cac249, 0x7ca3f274, 0xe448da05, 0x5d637172, 0xa94bc2cb, 0xaadb15fb, 0xe19d8401, 0x57afc046, 0xe5dea221, + 0x9dbb7b3b, 0x2e39dd91, 0x7bdb8394, 0x92a9a229, 0xccb9686d, 0x2e196371, 0xf405844a, 0x3dedf4ff, 0x90033a47, + 0x3ec211f5, 0xfd9a178a, 0xdffb3981, 0xbd168ecf, 0x111fbe78, 0x69587270, 0xb01a3348, 0x95178fde, 0x5f045277, + 0x50e5c97c, 0xeb60309b, 0x2a5d359c, 0x057c3c10, 0x1b3c32e4, 0x167afbe2, 0x7aa5428f, 0x3e731e10, 0x8b72a9e4, + 0x627a7927, 0x3375ef9c, 0xea6f4ecb, 0x2c02b2c0, 0x3e910fac, 0xe0958282, 0xa555286a, 0x30c41c16, 0xc8b8266f, + 0xd4ac6c71, 0x3fe0730f, 0x4ec71841, 0x8d6877b5, 0x8d17a39c, 0x80a04a17, 0x6884db68, 0x4613c594, 0xffcbaae4, + 0x34ef828d, 0xaf66c036, 0x02e11cff, 0x1956e1cb, 0xfd14c480, 0x1021b715, 0x2cd0b342, 0x4ca08c1e, 0xc43fbb31, + 0x7d192196, 0x224edda6, 0x3423e380, 0xdc9ef212, 0x185ba806, 0x3e7daad2, 0x65781dba, 0xb5f17b6d, 0xe155e6d8, + 0x05937cf1, 0x311d9e60, 0x3e0fc182, 0xc94b09e7, 0x5fdd2cf6, 0x90af1587, 0x1f24f3f7, 0x828eafb1, 0x8d05ed6b, + 0x5399adc8, 0xa66444f6, 0x26926e61, 0xe2573260, 0xebde3e2b, 0x72960040, 0x48340748, 0xc523d1e1, 0xc14708f5, + 0x611c939a, 0xd565403a, 0xfa19aa43, 0xea09a850, 0x4ba77112, 0xc2170ef2, 0x245e1b0d, 0x4c88d2b5, 0x1a9b5467, + 0xb2132a3e, 0xa41d8085, 0x1cf0fdd2, 0xe2a493e2, 0x5e1c480b, 0x06b35ee3, 0x05c77887, 0x2b5c5f04, 0x9fbf44fd, + 0x63a3d25f, 0x6f1f7221, 0x5ee162cb, 0x490e0d8a, 0x1091697e, 0xee3c8a18, 0x35c30a44, 0x2c822292, 0x17da9f23, + 0x7268d301, 0x3508f84d, 0x9d5f6c56, 0x2a644aa2, 0x70534375, 0xa2d509ba, 0x2ee829ec, 0x4e8f36e7, 0xedd8e101, + 0xfbc75a1b, 0x3c526f98, 0x479ef580, 0xe5edbc06, 0x73e43176, 0xff776605, 0x4485eb45, 0x78410623, 0x0e73d91a, + 0x3e200df1, 0x99f766ab, 0xaf582658, 0x6e77e7ec, 0xc0c69b1c, 0x9ec4996b, 0x942b584e, 0x7b4caa0b, 0xacd47213, + 0x8f953931, 0xdba9235c, 0xf883f9e7, 0xb91ccabb, 0xb579f0ae, 0x34a0ea28, 0xac01d39f, 0xfc47e71e, 0xffb654f1, + 0xc67381c2, 0xabe11357, 0x41275435, 0xce153ba9, 0xaa906e92, 0x7452f120, 0xeee0f651, 0x417e4c8b, 0x0966579f, + 0xc4224b97, 0xa7826c3a, 0x853a23de, 0xf4e9dde1, 0xaccb1721, 0x6e0e16d6, 0xa0b9cca6, 0xc48d9e67, 0x1e4fd503, + 0x92160356, 0xcdbae74c, 0xf31a333f, 0x5a9bda7b, 0x052ffee4, 0xf4a18351, 0x61119964, 0xd3843e30, 0xf6f36c9d, + 0x791f324e, 0x7e49ff28, 0x72502d99, 0xdb910fa1, 0x6e725281, 0xafdf1900, 0x4773602a, 0x2cfcc98e, 0xb1944412, + 0xc64a521a, 0x16ae44ca, 0xb8b0cbfe, 0x56948d74, 0x79f65479, 0x2780eacb, 0xe4b15acc, 0x1e63c586, 0x48d6221b, + 0x6c122f27, 0xd7820a2d, 0x7753e620, 0xfdc1a6f9, 0xc9bfc13c, 0xeae02bd8, 0xb7f50af3, 0xe4261df0, 0xa2dd8d6d, + 0xc5a55b90, 0xf60c3b9d, 0x339f6018, 0x4bf919c2, 0x00ebde17, 0x30ea6673, 0x68f7d0b4, 0xc67b2550, 0x7a478f82, + 0x3ca503b6, 0x10844c8a, 0x26333ef4, 0x3c6f704d, 0xd15cb29f, 0x4b156f8c, 0x5b495b83, 0xd99d12d2, 0x7a1fb410, + 0xa47fc8dc, 0xe48d7096, 0xa338999d, 0xc1a23b85, 0xc09fa2a1, 0xb62130f9, 0xbe8c5c15, 0x8a005c07, 0x5f63b5ac, + 0x44cec651, 0x910c53aa, 0x3c75759f, 0x68ea25b4, 0xd9af1100, 0x48419bf3, 0xa8979ceb, 0x6e1832e1, 0x104de665, + 0x758a5504, 0x25ab0b2a, 0x45e2bf8a, 0x035014cf, 0x3b60f840, 0x63456ccd, 0x1377f045, 0xf986e022, 0x9c234434, + 0x2432a34b, 0xba89d4a4, 0x861579a8, 0x79f309a4, 0x6481a300, 0x219ba839, 0x40d836c2, 0xb63ee94d, 0x87bb7491, + 0x653acaf9, 0xff31367a, 0x564c3c66, 0xdb123658, 0xf1288144, 0xfdcc614b, 0x2d514234, 0xb9b6ecff, 0xb9a9ce78, + 0x8250e2a1, 0x35d7725d, 0x3f2d4d98, 0x2210927b, 0xe0a5e4f8, 0x33361958, 0xcbe1bc10, 0x9db695a5, 0x27dc5708, + 0xbbead6c3, 0x08900e4e, 0x12abc81c, 0x05977bd3, 0x2c840573, 0x47970e96, 0xcae00527, 0x1516f3db, 0xc2942740, + 0x9f755ab4, 0xde7f7f4b, 0x789e1975, 0x8b5f1c8f, 0x214913af, 0x3c12d87e, 0xe0f66573, 0xc49b5ea7, 0xa3c29360, + 0xea284bd9, 0x2d6fc47a, 0x33ae97a4, 0x37aa05c0, 0x0450f5ca, 0xaaf64f9a, 0x4ffc6fc1, 0x6b8c3138, 0xf9e8dc8a, + 0x9afe2573, 0xd1965644, 0x1f6f1e56, 0x8ef42190, 0x8a4665fc, 0x13e71035, 0xe519d73b, 0x76c943d7, 0x71cc143e, + 0x6e58d2da, 0xe6254d86, 0x56d937eb, 0xba373356, 0xef903858, 0xa6afd9b8, 0x7aad337b, 0x01da2982, 0xe0987bfe, + 0xe65402a3, 0xeea5c357, 0x10719e7c, 0x431f80d6, 0x95fb980f, 0xd4df2353, 0x30e245f9, 0xc628b239, 0x35961c97, + 0x4d095b4c, 0x78086aca, 0x57c05fcb, 0x24b8f82a, 0xa9733b02, 0x212a0bb0, 0x7b788913, 0xdc4e0d63, 0xe33f5de8, + 0xd6329f8b, 0x070f8bac, 0xc5f2282a, 0x2257c306, 0x33d41d01, 0x14ee48a1, 0x205a7d5f, 0x6c1c34e8, 0x3ab4ccf3, + 0x480a403c, 0x9c5a5145, 0xa69013ac, 0xb5f9041d, 0xde8a6597, 0xe1e492d4, 0x30d71887, 0xe05b48e4, 0xe65eb443, + 0x243fcbd2, 0x2cb052cf, 0xfd745e1e, 0xd823e1b7, 0x62ad7123, 0xf1b5bcf7, 0x33435981, 0x7283f133, 0xf1cb1fd4, + 0xe25ea7bb, 0xf5e7c9b1, 0x607f3aef, 0x33caa035, 0x241e73e5, 0x299f81cb, 0xd257909a, 0xcf89a258, 0xf4c760ab, + 0x0352597f, 0x1793e020, 0x3b648254, 0x16906255, 0x38d9cdfb, 0x25e94ea3, 0x190d9110, 0x1a5b44fb, 0x405825ef, + 0xd559974a, 0x064c7706, 0x549d9cee, 0x94e5db21, 0x961134bc, 0x0946464b, 0x19914e7c, 0xbc0f1aa9, 0x680e2c0e, + 0xe324719a, 0x4d87fe38, 0x4ede74c7, 0x31061f98, 0xd40a36bc, 0x1b6ecae4, 0x421e69ea, 0xe5cc69dc, 0xda4fdfae, + 0x66e2c0ec, 0xe10d7a20, 0xbd2e9495, 0xd31b4e0a, 0x1e617a7c, 0x1da02c4e, 0xc5de4ad6, 0xd8d5b7ef, 0x52c04635, + 0xf5d28e6b, 0x048074fe, 0xceb13809, 0x2cd6b5e8, 0xa8ec2fb6, 0xa3302db3, 0xd5ed753b, 0xc618ffe5, 0xafb014b9, + 0x7598ae13, 0xe58c96af, 0x2c75f4ca, 0x3a785d17, 0x8c8f082e, 0x4691344f, 0x01b377ab, 0x4c75f4ca, 0xe8550d12, + 0x3a6fd4a6, 0x3a3ede4b, 0x346da1fb, 0x81f7cf96, 0xec628ac7, 0x07d8b9c4, 0xbde393e1, 0x8d36c8a0, 0x831db0cc, + 0xc4bca32f, 0x558a48e0, 0x8efe2553, 0x0038d156, 0xf1607f8e, 0x8eecefee, 0xb1888522, 0x50751932, 0x5e0deb0e, + 0x0b9270b8, 0x3e019797, 0x618e73bf, 0x26e50523, 0x5ab09b20, 0x241031da, 0x46877916, 0x083fb894, 0xed194590, + 0x5101e29b, 0x4dc08d32, 0xd6702a52, 0x153f3b4d, 0xd2e96914, 0xb7617515, 0x1b196e20, 0x302e7d07, 0x19e420af, + 0x32402210, 0xc9587dbf, 0x881573a3, 0x837ee7e5, 0xe8722c43, 0xd9e56bb2, 0xd14623d4, 0x443a7295, 0x975732f0, + 0x37575ea2, 0x2d528d29, 0x150209eb, 0xef7fda67, 0x3495accf, 0x66633fa9, 0x54093bce, 0x6eecc05a, 0x5f03708b, + 0xd4a3e430, 0x225bfdf0, 0x75cafba3, 0xc1cfcfc0, 0xc9db150b, 0x407d9fa9, 0xebc3ecdd, 0xdffc8317, 0x16b489c0, + 0x2b71cd9e, 0x18385caa, 0x88e04d4a, 0x89097873, 0x4432abe2, 0x3563b821, 0x550fab68, 0x48ff9cbb, 0x8a8d1f7b, + 0x835624f6, 0xa8f196d6, 0xb041681b, 0x07df24e5, 0x69a09e0a, 0xfc1d30b7, 0xb632863a, 0x0993292c, 0x8998822b, + 0x7105ce85, 0x9815b9b4, 0xbb4a030d, 0xa7fa2eda, 0x33b20840, 0x25f53b95, 0x004732bc, 0x11c9a5c6, 0x66a2aca6, + 0x16aabffe, 0x888f64cc, 0x46d534df, 0xd073019c, 0xa54675a2, 0x3f69bfed, 0x24aca970, 0x646951fe, 0x1b935d5c, + 0xa027c052, 0x6cfba72c, 0x2c98b42f, 0x4316d856, 0x96f42152, 0x9a0ccfb4, 0x067364d0, 0x9577c90c, 0xc0f3f8a3, + 0xc85b70d9, 0x64e4ed7b, 0x3d456afc, 0x2a3badd3, 0xe4652ca7, 0x5a235b44, 0x57214908, 0x3841e9fb, 0x1cceb139, + 0x5a1ed443, 0xc1165a07, 0xecde9d8e, 0xb8fb997a, 0x8286bb9d, 0x9e2a0939, 0x8472a1f3, 0x752a381b, 0x9ff25aee, + 0xa3f332bb, 0x18521817, 0x497df60d, 0x102a6986, 0x9171c3b7, 0x8a86019f, 0x28a69ba3, 0xc496797b, 0x7960ff49, + 0x264bb1a8, 0x9d0e6574, 0x12dadacf, 0x53f8d6c0, 0x2f85a848, 0x4ab2d7a8, 0xe3ede56a, 0xced022ac, 0xc4429716, + 0xedbe65e6, 0x8f1b804e, 0x124570b8, 0xe8672f5e, 0x634068f7, 0x4d904994, 0x195302d8, 0xa0291251, 0x853f6e61, + 0xbac37ae1, 0x1b500bb5, 0x76a5897e, 0x9da071ee, 0x4a040005, 0xcdf681d4, 0xa2a587c4, 0x0b9a5a09, 0x7e689ee8, + 0xa82e15c0, 0xa945ec3e, 0x5ecff26a, 0x57353ade, 0xaff58907, 0x8dd2b86e, 0xf933c538, 0x7e71996c, 0xb55658c5, + 0x3d5f2c0c, 0x6ac53e4b, 0xf52d3ba2, 0x1e657891, 0xa5ad7cb0, 0x82277e54, 0xf2b4814f, 0xc8075e3d, 0x7ee94432, + 0xe973269d, 0xd5c38379, 0x480c6da0, 0xb4688153, 0xa9317f26, 0x35ee81cf, 0xa461b299, 0xabf150bd, 0x9deaaf11, + 0xa1f2f76b, 0x968d9624, 0x7c16ed66, 0xed6fef97, 0xf4da49d3, 0x98b3f5d7, 0x915bb317, 0xd2cee07b, 0x0fc83776, + 0xab6c7a13, 0xbc8f3d3a, 0xd345e347, 0xa48486f6, 0xe28647e0, 0xc08c0de8, 0xd450301d, 0x9b4ee503, 0xa97ca9ba, + 0x6ceaa9ae, 0x1682d0e1, 0x591e2b74, 0x916cf5ec, 0x6a5ce801, 0x77017ca6, 0x5dd108d2, 0x36256c3a, 0x5fe8aed4, + 0x4f9eee51, 0xfc6fe0d5, 0x82a50b55, 0x7c7bfe8a, 0x2ff1d5a9, 0x961c0a3b, 0xbccf9dd8, 0xfa8490a4, 0x2317bf63, + 0x070f3ab5, 0xa042abc4, 0xe78c3a22, 0x52ba3d56, 0x8d4fbda7, 0x1d99ab7a, 0x7afc0a35, 0x28b9350c, 0x51d141a6, + 0xcfa8d5bf, 0x19bd7658, 0xc8421a2e, 0xd52f629b, 0x000a3411, 0x75d05b37, 0xa795855b, 0x41510cd6, 0x1f40c014, + 0xebea1b77, 0xa0719a9f, 0xb7f8ac90, 0x2050a942, 0x9a788c58, 0xe59c4147, 0xd17fae72, 0xa2cade36, 0x41417be8, + 0x2e7a897c, 0xd748078d, 0x9f5ff033, 0x2ad5160b, 0xb8325581, 0x1c4ae855, 0x3fdb5e52, 0xfd3d4b55, 0xbb374a8d, + 0x770a70bd, 0xd0c323fc, 0x2659e977, 0x7a2e4462, 0x09a2da74, 0x7cec044a, 0x83cf2f71, 0x3b6b65db, 0xd46d028c, + 0x6eda59cc, 0x950fda95, 0x39977ac8, 0xce6cf805, 0xbc19713a, 0xdeba41d9, 0xc87e0ada, 0xfc010f11, 0x2c57a837, + 0xc4875009, 0x3c6afce7, 0x1e2f50fe, 0xf9dd1c1e, 0x60408002, 0x4feb748a, 0xa2226c66, 0xb74e2530, 0x86253ef2, + 0xe4f32e3b, 0x9d4eef04, 0xbfc6fe7a, 0x321dba39, 0x72efde7b, 0x9c1227a0, 0xe89c9523, 0xdb38508d, 0x29993977, + 0xb62ddb22, 0x77e5c449, 0x12a6e863, 0x7893bf56, 0x6f6cf001, 0x5b7388ed, 0x669274ec, 0x709d50df, 0x6c4b9731, + 0x78a4f40b, 0x027393de, 0xafe29341, 0x71085474, 0x89b1c4b2, 0xd43eccff, 0x4a538780, 0x35f1427a, 0xf96a033c, + 0xab0b5ca1, 0xaebb97c4, 0xba03b95f, 0x55ee3e96, 0x3dd1737e, 0xf41ce965, 0xb078a8a6, 0x63b5810b, 0xe95652a4, + 0x0ea041c3, 0xfcc9193c, 0x6e9b1cee, 0xd0928f65, 0x6c600986, 0xc705c24b, 0x839a5f44, 0x165fb3df, 0x57146b4c, + 0x85b0a574, 0x8f423fbd, 0x6d0831f3, 0xf5cf59b2, 0x75c01a40, 0x4a617ce4, 0xb5b77010, 0x6364f4ec, 0xa824452a, + 0xb1792a97, 0x33fa91df, 0x863f8e96, 0xaded72c6, 0x9695267c, 0xccf90782, 0xcf09e197, 0x8e3869b1, 0xb549905e, + 0x1711395c, 0x6e1d0e2f, 0x98958e5a, 0x40911c24, 0x0bb0f066, 0x13927b0b, 0x1a0fb240, 0xd6f92d54, 0x53d7804e, + 0x8dbc60c1, 0x98f7b1a4, 0x07e5e6b0, 0xaf1dbe4c, 0xba68553b, 0x5293366a, 0x786bedc2, 0x311cb7e9, 0xb6462af8, + 0xdfd00181, 0x6e553901, 0x8af45841, 0x70a8475a, 0xd1b3938f, 0x96622c10, 0x4603a087, 0x12686935, 0xab225999, + 0x8d9f1e2d, 0x57d72910, 0x52cd20fa, 0x01571c69, 0xc6abbf29, 0x074e3a9e, 0x94dc2f66, 0x1b413c21, 0x716f7712, + 0xb9b233db, 0xa2d51209, 0x85da319d, 0xaa92cb9b, 0xff02bbf0, 0xb269ff9e, 0x42bbc348, 0xeb1618e5, 0xf9ec39d0, + 0xbf396ed7, 0xf4bd66be, 0x9a8bcfaa, 0x05ca193f, 0xd2013a04, 0x19199b30, 0x201047cd, 0x7bb5fd18, 0xc738f6d6, + 0x838a0588, 0xb8a7c133, 0xfa50e965, 0xedc1b5b5, 0xe5b560c5, 0xc96696ec, 0xef91f906, 0x88815f01, 0xa41832cd, + 0xc8014122, 0xdfcdc17c, 0xd24ca5b4, 0x7e7b01ba, 0xada5c785, 0xf5c65d08, 0x0a010c71, 0x1d2a73ef, 0x2204db09, + 0xc47d2594, 0x3d4c601a, 0xc7ead538, 0xe4e8e8d8, 0xc79ca9c4, 0x574bffe0, 0xabf93c14, 0x6baf0b87, 0x63871520, + 0x9a1a23e0, 0x8061c6ee, 0xecc95e93, 0x72cb4bb3, 0xdd828222, 0x5f4ac9f3, 0xa62f6821, 0x054a9ca2, 0xfef102da, + 0x8af7a723, 0x03d4a183, 0x39da1b47, 0x04ec32df, 0x9db123d0, 0xd241f7a5, 0x213e1433, 0x0c68758d, 0x893341dc, + 0xe955406a, 0xff5676f8, 0x7d37ff30, 0xf0e6500b, 0x10caa677, 0xf42c9627, 0x22a49eee, 0x764859a4, 0x3fa671c9, + 0x394b83e1, 0x71823194, 0xbea05ec0, 0xa23512f9, 0x7dc99f55, 0xed591476, 0x9a125377, 0x542843fb, 0x20c5f7bf, + 0x0c7c44d7, 0x12fa20b8, 0xcb306d1a, 0x8b8decd0, 0x8e7e87b3, 0x49391889, 0x7bae0247, 0x00a05aec, 0x83246358, + 0x63ad52f0, 0x1608fc6e, 0xa34820e5, 0xe4019070, 0xda24d9b5, 0x91e1b7bb, 0xa36221a6, 0x6d39c72b, 0x236d2f29, + 0x7e13ca88, 0x367e9517, 0xa672eb3b, 0xf53267c7, 0xbd3fefe0, 0xe53e97d8, 0x07f352aa, 0x4d80901d, 0x492dd6af, + 0x9ed29a73, 0xff49f2d6, 0xe5fafc36, 0x4e75786d, 0xe9fbe57b, 0xf20b4a8e, 0x3992f4c6, 0x348a4c17, 0xa4b8c3f5, + 0x70775e72, 0x6666a0a3, 0x9c4ad813, 0xbde5f638, 0xeb509458, 0x7d68db56, 0xd51b24ca, 0x93d6eb01, 0xe813d1c0, + 0x37810301, 0xb8ec3699, 0x0f2f07fc, 0x1f786de9, 0x066d1f59, 0x4f3a4fba, 0x4b6fb00d, 0x85794d1e, 0xdd3fc9c6, + 0xd865f0f4, 0x5393fc47, 0x2bbda5c8, 0x5045e671, 0xe04c426b, 0x0ed86b7d, 0x6b509270, 0x710368d8, 0x69e9fe59, + 0x1f4caaca, 0xfd33ffa6, 0x8463d492, 0xfd94875d, 0xd130611f, 0xbfb00bee, 0xbef27a6a, 0xa5221aa0, 0x06f8df27, + 0x3bfab35f, 0x314c2376, 0x951affe3, 0xd0485d58, 0x2984ce84, 0xdfd72fd8, 0xc7097fc5, 0xb8d4b6b6, 0xeec08694, + 0xce9b866f, 0x0c1418fb, 0x43683c77, 0x2e55f51c, 0x2b9146b2, 0xaeff4ebc, 0xb4411e03, 0x221cb89c, 0x1bf64f6a, + 0x5de0a981, 0xa4f2d42b, 0xd2c6f9a9, 0x3fbd346c, 0x9fbd0274, 0xd3bb6382, 0x3ba2a9b9, 0x5e703ca0, 0x5eeb8830, + 0x78291219, 0xccc2efa3, 0x25e8ed83, 0x9a0840f4, 0xcc4fe8dd, 0x25f7bec6, 0xc0bdd524, 0xb91ee7c6, 0xcadcd084, + 0x72f378c4, 0x02dc474c, 0x8127e7a8, 0xeb930d22, 0x7c670da5, 0x1a40695d, 0xb8970665, 0xeb767825, 0x7f4a2737, + 0xd729a735, 0xdb21fd28, 0x3f52cc06, 0xe60c5a9e, 0x59dfb251, 0xdaabfc9b, 0x7dc41896, 0x3d752d29, 0xd1ad0f02, + 0x0edad926, 0x6188c8a1, 0x4f809b09, 0xc7acd439, 0xfc9f8047, 0x00807a7c, 0x2cbace5e, 0x8ad634fd, 0x5f23f118, + 0x2275f71a, 0x37fc8fcb, 0x57155119, 0x2e9b1a48, 0x41943b26, 0x518b3746, 0x8617e6e7, 0x89388fd7, 0x3b15debf, + 0x89df96ae, 0xc7af6a4f, 0xe49bde37, 0xb9cf943e, 0x382e7c9f, 0xcef42399, 0x45fbbe68, 0xbf0249ff, 0x2e8ae5dd, + 0x5f12c263, 0x97db50b9, 0x330e682f, 0x8cb2ac02, 0x4b2746e4, 0x80858d04, 0x3c930d5b, 0xa36a380e, 0xe2b9f16e, + 0x618ab426, 0x02249b41, 0xcbd18ecd, 0xff3aa629, 0x74d1856f, 0x4420b21c, 0x47dfa9b6, 0xfd5b5772, 0xc73ff967, + 0x3334f862, 0x1480dcf1, 0xd6938291, 0x3925fdba, 0x426e8b02, 0xd671b269, 0x4c3b0a01, 0x4444257e, 0x865fa6d5, + 0x4b628d72, 0x7d628f39, 0x09c382e7, 0x6e714369, 0x1fd51a22, 0x742f1d9c, 0x447a6279, 0x15ed76ea, 0x0a95aa8b, + 0x54b3826c, 0xcaedbb1b, 0x6250a154, 0xafd1a416, 0x9110e078, 0x9d41c98a, 0x9c7a9148, 0xc32d6c3c, 0xf22de590, + 0xa1c5a21e, 0xec9a6958, 0x488c200f, 0x048cd011, 0xb49371d8, 0x0a0566fb, 0xba1939cf, 0xc298853c, 0x3a0f7663, + 0x304d0fb7, 0x4471f76e, 0x459b53e3, 0x68411f22, 0x49070f39, 0x545b5a94, 0x3af7a99c, 0x89084c41, 0x6041f723, + 0x8b52a88e, 0xeb185745, 0x7ecebdb4, 0x61cba4f3, 0x244a8521, 0xc1c8f88a, 0xc3004d2b, 0x84795433, 0xd36f94d9, + 0x68d31d22, 0x6acc0295, 0xcca19df0, 0xfc12bcb9, 0x88c66f19, 0xcdc02b9a, 0x71a560ce, 0x599bdd3d, 0x75f6e064, + 0xcac70003, 0x4c11fee4, 0xb6c48d0c, 0x2357a8c9, 0xd6d5dd96, 0x2ba04a0c, 0xc57996d9, 0x79ccef92, 0x515868ff, + 0x8c5257a8, 0x1e974475, 0xbca63369, 0x570a947f, 0x91d9c254, 0xd5806f82, 0x6b9bc238, 0xa915dd57, 0x756ee2ac, + 0x2f43c749, 0x7de983c8, 0x6d691e2b, 0xe7f7f31c, 0xcf397e19, 0xa9557354, 0xe1390978, 0xc3690464, 0x6244973e, + 0xaf440ec6, 0x4664a17a, 0xd6008c97, 0xe2ca7758, 0x3fff6b4a, 0xff14dc31, 0x6c2163ce, 0xabf3881c, 0x6df57d3b, + 0x80d334c0, 0xf436d8f2, 0xe7d6e460, 0xea192e2f, 0xbe7af855, 0xd4bc0abe, 0x07b79cde, 0x9ea72363, 0x0664806b, + 0x1c721f64, 0x2dd4ff65, 0x66c05fb8, 0xc8fdf8f1, 0xeab71ef3, 0xbaad1e60, 0x01583ee8, 0xc6ef63fd, 0xe8125e0a, + 0xbf247a64, 0x904eea1d, 0x66c958c5, 0x003b47a9, 0xb027a732, 0xa9d2648f, 0x26e7801e, 0xf261d20b, 0xfc376c55, + 0x7fc67024, 0x1ab337d1, 0x065e3404, 0x8d1abb37, 0xac480734, 0xa8604e78, 0xf3692cab, 0x01963bfc, 0x8e2b8ed1, + 0x748dd6ae, 0x0aadb63d, 0x0cd76f7d, 0x37afed2a, 0xf3125b98, 0xb71d07b8, 0x6e80cff4, 0xe8b9b466, 0x574d21b8, + 0x820d43f5, 0x3fdd2e00, 0x98fbac7b, 0x3d1d90c0, 0x19ac4384, 0x74152ac8, 0xbf46ea65, 0xa120dd4d, 0x11856c6a, + 0xc91c97db, 0xf1fef111, 0x723c62d7, 0x4bcdd999, 0xb1e95435, 0x2f9a5e15, 0xea928443, 0xc5f00223, 0x3c9112a6, + 0x54a21957, 0x1f1e2514, 0x864e12c2, 0xb24a9cf4, 0x7f47771a, 0x78ba4a4c, 0x773c760c, 0x068a0c5b, 0x2f89bab9, + 0x777cb51f, 0xb003fffc, 0xe4839650, 0xaddcfc19, 0x0389c6e1, 0x6dbb1b21, 0x84ab0d23, 0x415803fb, 0xd824da7d, + 0xc9f65ad7, 0xf2f10d1e, 0xce95f279, 0x764078fc, 0xcc7bba83, 0xad04a6de, 0xbc3bdd1a, 0x9dbe8bbc, 0x79c898cf, + 0x32fa2778, 0xcf82c572, 0x4caaa083, 0xc0ef7c75, 0xbe810f26, 0x8ad739a1, 0xc0b3409d, 0xeed28db2, 0x800b92cf, + 0xc334cdfd, 0xb6d354f4, 0xf1305c75, 0x8ab6f6e9, 0xd2242ec6, 0xb537e577, 0xd02fe587, 0xe0fc56c5, 0xbfc2ab9c, + 0x4cd819a9, 0xff7bda27, 0x08e9ef14, 0x30797e64, 0xe31d3524, 0x8979b375, 0x6a371661, 0x0e53cb6d, 0xd5a2279c, + 0x5ed1f3f1, 0x9c4ff3fc, 0xdce8af4a, 0x04fb79a8, 0x6a4717e7, 0x0474ee04, 0x410efede, 0x0b2d45f2, 0x447fdbdc, + 0x4bf2c561, 0x452b37f3, 0x348741b1, 0x2cdaca38, 0x50fc2da1, 0xa681d0fa, 0xa06887a8, 0x133f8c46, 0xf6e8af2a, + 0xfe5147f4, 0x99ce2675, 0xd6897483, 0xd4c1694f, 0x6e3f5a7f, 0xffafbc12, 0x4a1da34f, 0x727ba7e1, 0x75945c92, + 0x1f50a157, 0x72f12bcf, 0x1cdbdfd9, 0x76475c5f, 0xa0491ba1, 0xc55aad00, 0x28a35860, 0x11e195fc, 0x3fb644d7, + 0x5fcf8925, 0xcd1844f7, 0xa0b17207, 0xab6420a2, 0x8cfcfb65, 0xb687c9e7, 0x7cb7942e, 0x0c5dc405, 0x7a24e6cf, + 0x88baa105, 0x65027d7a, 0x95483d23, 0x1b4e0ba3, 0x53f778d3, 0x84be332c, 0x32eed212, 0xf5f21681, 0x8f6b16a7, + 0xd594b2ea, 0xdef61783, 0x20205dca, 0x79e56ca2, 0x78d1be6c, 0x3fc766a2, 0xe554bb37, 0x75d86900, 0x4d4a4fbb, + 0x00a762df, 0xdb245f0f, 0xb5f51ddb, 0xb38220e8, 0x3ecfdb77, 0xbc80e6bc, 0xae6bbf91, 0x5a1dd126, 0xc4d97449, + 0xa5aa112a, 0xa3db5ded, 0xd52a7f23, 0x00190917, 0x433dd6cc, 0xe44fcd49, 0xaae906e0, 0x7cf6f4b2, 0x6718f903, + 0x4c2f354a, 0x2238d9c9, 0x82714943, 0x8c8fb679, 0x016f1742, 0xa484f4a0, 0xa0c2d54a, 0xb52476ba, 0xda427252, + 0x1bbe0145, 0xdbc700f5, 0x8381721b, 0x5b0da404, 0x1fa47418, 0xd69ba562, 0x40bd4041, 0xae7a70f5, 0x63cdc7ee, + 0x9d2fc9eb, 0x463be839, 0xcb671af3, 0x499f9db1, 0x86ffb47d, 0xa1dddc9c, 0x8d8c8d66, 0x966af3c4, 0x7abc905e, + 0x6a11f4b5, 0xa268bd0c, 0x2c4540fe, 0xc9a746e9, 0x78ae48b3, 0xb61a63a6, 0x6874eb60, 0x519fe7d4, 0x583fd619, + 0x046d806a, 0x2e2f964a, 0xfc77d2b6, 0xc5696c42, 0x544482d0, 0xaf4d7ac2, 0xb079df2d, 0x0e2ff9d6, 0x3c299021, + 0x17e67c5a, 0xc9cb2cca, 0xb0877903, 0xcfb9fd8a, 0xa5125f6e, 0x1ac8bc52, 0x03fb8a2b, 0xe8db5b72, 0x2906b0aa, + 0xea1356a4, 0xe552a577, 0xd5a826c9, 0x72437a9d, 0x40df08fc, 0x473d44e3, 0x7999c14f, 0x3e6eb61d, 0x1dd59255, + 0x153586ee, 0x8e52ef3d, 0x6b879c15, 0x68044c6c, 0x18b9a6e2, 0xa46c783d, 0xdf557db5, 0xfa1e2532, 0xdc0901ec, + 0x869b2e6d, 0x5bd465f5, 0xaebfa9fd, 0x9f2f24c3, 0x17df0220, 0x737bc7e8, 0x5bbacd0e, 0x94abdaff, 0x264099fd, + 0x71d7813e, 0x026e81f0, 0x5bf65ae7, 0x9ec7630d, 0xb5beea33, 0x033d6119, 0xceff0c73, 0xd882f43e, 0x4af039e9, + 0x36649e6e, 0x6df3da33, 0x2d309459, 0xb0ae5aa0, 0x321c28db, 0xf752b3dc, 0x06bd2c0f, 0x325ae487, 0x399ccb8a, + 0x134366d7, 0xa9846fc6, 0xb861e244, 0x845eaec3, 0x1f474a89, 0xa7cee284, 0xf1b8bd31, 0x91d323d1, 0xe83ef38a, + 0xeb55a617, 0x34f45f1d, 0x0e6cfb99, 0xe8f6e50d, 0x17374bd4, 0x695452e1, 0x7c8da230, 0xbc782642, 0x26615c91, + 0x176a055a, 0x36999734, 0xbd652ea3, 0x434cdf04, 0x21df2698, 0x3e1d2beb, 0x76b47bbc, 0xf0539d2a, 0xea226178, + 0x135acba5, 0xe84efe7d, 0x42fc1be1, 0x246d6d62, 0x16af09c1, 0x9634d175, 0xac2a5357, 0xd5f5f238, 0x63ed9afc, + 0x2ad5bafc, 0xbc22b4ea, 0xa5906ac3, 0x3d78e717, 0xee331aab, 0x6795b011, 0xee8b1bd9, 0x14b82750, 0x59c0af6b, + 0xe93926ae, 0x368cae62, 0x36a2edf6, 0x142c5fa1, 0x1a2be46b, 0xbb62b224, 0x4468971b, 0x33c5d731, 0xe4d1f902, + 0x452c4507, 0xb6d1c02f, 0x56e8aa9b, 0xa0abe2f4, 0xe87a4190, 0x011e5dc6, 0xa2780059, 0x8c72fa06, 0x10522619, + 0xff9519d3, 0xd27f802f, 0x82154ba7, 0xcfa00dbd, 0xb9d6c36a, 0xccc99fe5, 0x57aa8b05, 0x263bca8a, 0xc0b10ee6, + 0xb9e0ae83, 0xefca3a32, 0x3255ceaa, 0x54bf5c11, 0x6d9fe506, 0xc9961b74, 0xd458e41b, 0x244be784, 0xe0c61e2c, + 0x0cae436f, 0xd5b7571d, 0x62d79efe, 0x916e4e7c, 0xce248a3b, 0xc8901646, 0x2fa64889, 0xd3e4ab74, 0x52926ad9, + 0xa3c21ec8, 0x9c373525, 0xafc5405c, 0xd3918b71, 0x176104c1, 0x61e49cad, 0x8b1dfbfa, 0x9effafc3, 0x69145803, + 0xb58fd42b, 0x1df6c509, 0xee25ab28, 0x4a3d005a, 0x8cbb6b80, 0xe3386f59, 0x98605130, 0x3b748546, 0x6d68b1d9, + 0xe27a18f9, 0x15d90d39, 0x61cce1be, 0xe69548ed, 0x9ce29b4f, 0xc3de1c6f, 0x22eb2607, 0x4c4cdaf0, 0x001d9b68, + 0x9c044861, 0x7816e4d7, 0x0e57c738, 0x5a51d329, 0xf731d75d, 0x565f4686, 0x95ee0890, 0x604f63f9, 0xd77587c1, + 0x5caf9748, 0x64a74ce3, 0x5ae858c6, 0x35e921b6, 0x54fe8d06, 0xb5b41542, 0x286d4013, 0x6006e319, 0xac8150d0, + 0xe5c2e648, 0x4d5f4408, 0xeb19e443, 0x81178631, 0xe8c8e34d, 0xb6c8b291, 0x85dcde1b, 0xb388b554, 0x7eb9fac6, + 0xc127f3ec, 0x9a4cc33e, 0x8922ce5c, 0xe6d3d8fd, 0x93ddef2d, 0xb594941b, 0x76e32865, 0x1ce5c9cc, 0xe159997d, + 0xdc914a0b, 0xcd0c193c, 0xf99befed, 0x50b6196f, 0xce33c424, 0x09a75641, 0xceb4acc7, 0xff57002c, 0xb0e57e1c, + 0x40546b4f, 0x61a4d43b, 0x56a918f5, 0xbc5cfed6, 0x9b5bd813, 0xcaede8c2, 0xedc5d5e6, 0x61ac8e2a, 0xe6af1916, + 0x73a8cf78, 0x6fcb57db, 0xd44d83d9, 0x6da04ead, 0xbe8a17b3, 0xa8c38ce8, 0x86af84b5, 0x890621ec, 0xdbe97ab0, + 0x396b39e4, 0xd1437f64, 0xd7e65196, 0xfc90cd4b, 0x27c5e62f, 0xe5b8e50f, 0x02a2e2af, 0xb226c34d, 0x7107c314, + 0x3a9c7bf8, 0x4a6d8092, 0xd399c9d2, 0xf5fba5eb, 0xb81b8142, 0x38fa3ff8, 0xfa76150b, 0x7e046d1b, 0x3c241344, + 0x4d365353, 0x26421605, 0x5c44cfe0, 0xaaa6919b, 0x226a2c64, 0xade3348b, 0x3505bda5, 0x9c4a672a, 0xc3ece42f, + 0xf369e025, 0x0ad24c82, 0x406a7063, 0x5a1a8aa0, 0xae0ae509, 0xc765b2eb, 0x84ab9ca5, 0x9ea359b4, 0x18f813d8, + 0x181f99c1, 0x67f22493, 0xc71a50bc, 0x209ccc31, 0x245b6ea6, 0x74f84c08, 0x4d58c8ed, 0x6d77d484, 0x298331bd, + 0xa26b7732, 0x81c3eac2, 0x7d549421, 0x9c4b76ad, 0xe813d84b, 0xb9b58b6c, 0xe912c152, 0xc046afd4, 0x7ebebe8b, + 0x3ed6bd7d, 0x6276354a, 0xcf7b28b5, 0x4ee94fb1, 0xd15517c4, 0x6ec36b4b, 0x45e61849, 0x51405aa2, 0xc37a394d, + 0x9bf970de, 0x4a92728f, 0x726064d5, 0xef2c19f1, 0x9612ba11, 0xafc59fb2, 0x224ae7db, 0x6c646ef4, 0xef66e6da, + 0x44afca54, 0x0bbee791, 0x2f0b2967, 0x6ced4cb2, 0xa76478e2, 0x0fe20e76, 0x9acdb446, 0xb746e67e, 0x49e54124, + 0x203cd97e, 0x565ecbf3, 0x6ab44b0f, 0xe0537d37, 0xf8c39a0e, 0x863eb4ff, 0xbc413607, 0xfcc87199, 0xc3b69ba3, + 0x19c3f7d0, 0x6704fb05, 0x60d1ca86, 0x940a6fd4, 0x6087732d, 0x7806f663, 0x08c1d2e3, 0x70278d2c, 0x65dbd740, + 0xd1b141c3, 0x0a4e67d5, 0x84bb60e4, 0x94b8d544, 0x4e74dec4, 0xf355fb55, 0x80ffc2e8, 0x797a1a54, 0x16ce0023, + 0xae11d9b6, 0x8a78b0bb, 0x928184c3, 0x7ca45cab, 0x3a38550b, 0x671becd5, 0xdfb72cc7, 0x155bd14b, 0x3ae3708a, + 0x438e8b60, 0xc02fc8ba, 0x65167bc9, 0x9aa139c2, 0xb927b49e, 0xb4ba59dc, 0x1a804a3b, 0xbcc73611, 0x07ab5d7a, + 0x2a2d82e3, 0x706f2744, 0xb507a697, 0x2a1fc2e5, 0x2d039958, 0x871b0f25, 0x4f2f98d4, 0x3929af56, 0x04cd19c1, + 0x2d05631e, 0xa71e0149, 0x7cd7f1c6, 0x5af7ff03, 0xb5a29b1d, 0x0ead37bf, 0x83dc73d5, 0xfc938f1b, 0x4c7cd620, + 0xd9717c4c, 0x1ee13f8c, 0x668e2f93, 0x60e9d48c, 0xfd7bf7d7, 0x3589fce0, 0xfc04639e, 0x0bb8d187, 0xe68b8857, + 0xeaff80aa, 0xd5fcb22f, 0x0427c8ef, 0xfd57eeb1, 0xe13c537a, 0x36b8d835, 0x5366cf4d, 0x4b8c2f53, 0x49faade7, + 0x6cfb3085, 0xc31b7cfc, 0x31efebee, 0xf955eada, 0x873baa46, 0xe83a4fc1, 0x48c0cccc, 0x96d47216, 0x876a365c, + 0x9f49d03c, 0x1de4c6b6, 0x060e5041, 0x5dbdbd3a, 0xf7a60a45, 0x079da6f5, 0xfd4e2369, 0x7fdcaa57, 0x9860ed51, + 0xe83bcc5a, 0xe11006a9, 0xba54e55f, 0xb6eca477, 0x3fb0900f, 0x646794ff, 0xaadb2730, 0xbfb3eb71, 0x4db51b1a, + 0xe65f642c, 0xe27dc13d, 0x26c25599, 0x4468c736, 0xd73bdb13, 0x4bebb7c8, 0x03af0b52, 0xa160eb0f, 0x8628fa4d, + 0xf30fb609, 0xda396845, 0x35c44eb9, 0x748c3344, 0x6b81cb92, 0x034fe277, 0x6c10e23c, 0x372b24a7, 0xab9d9a49, + 0xb1a776c2, 0x82ba375c, 0xc25e8332, 0xb00ba478, 0x849d8457, 0xdee7c51e, 0xb5819e50, 0x04a74804, 0xf1c7e08c, + 0x1aa5181b, 0x9ffe13e0, 0x80663ad4, 0x9a03b21d, 0xc11af956, 0x5d7d1c61, 0xe94544d5, 0x30c471ac, 0x29190cdd, + 0x8b0263cb, 0xa1d8e66a, 0x3036d43a, 0x6b08a2e5, 0xea18325d, 0xe4877fa0, 0x0a560873, 0x9225afd9, 0x149f2815, + 0xeabdd861, 0xc6b94aca, 0x1c2aee9a, 0x1489015b, 0xd9111b8f, 0x91a33289, 0x16d966bd, 0x35d4f368, 0x25adca9b, + 0x1cbde0c7, 0x3468cd98, 0x707f2823, 0xca940c56, 0x31563003, 0xbba0e036, 0xcdd6632a, 0x81539681, 0x2be29405, + 0xb9b173b5, 0x9e770827, 0x07328b95, 0x2f1e572d, 0x9836af48, 0x65c03e00, 0xa64de6b8, 0x9b50e535, 0xb4444f77, + 0xed349588, 0xc08c4195, 0x4b6aa269, 0x76c42958, 0x6d484f66, 0x5b11aff1, 0x46a0cd5c, 0x883ca511, 0x0174f429, + 0xf92434c8, 0x1a02c26b, 0xbad24c68, 0x30d13daf, 0x8de5f824, 0xb8f7461b, 0xfa7cba41, 0x913c2f11, 0x81cd7fe9, + 0x058d1a3d, 0x984f52ea, 0x2357ca54, 0x83e30462, 0xae22763b, 0xe030ef32, 0xa4898aa6, 0xecb0f4aa, 0xd491b02f, + 0x3e388bc6, 0x73710f07, 0x243d7fa9, 0x2e4ef084, 0x02b35181, 0xf866e084, 0x7b6c0986, 0x63612d73, 0xa4bc1832, + 0xa95fc77c, 0xd098546e, 0xaa4414e5, 0x8fcfe7f6, 0x8d35a453, 0x66800578, 0xf9108074, 0xbf43a311, 0xc02f12a4, + 0xdc88b063, 0xc7ac0dac, 0x95a8eddd, 0xe1c267ea, 0xf71ef85d, 0x83fbd812, 0xf5666959, 0x58a1288e, 0xf39e0d77, + 0x2aceec56, 0x7bce0f15, 0x879889e4, 0xe2240605, 0x4a4c2bfc, 0x7e146886, 0xedfaba90, 0x3d4cb861, 0x55c4d5a1, + 0x7263e089, 0x937c71fc, 0x12cb3a7a, 0x80b9df21, 0x981b039b, 0x5ee9238c, 0x04ae32c5, 0x5218f402, 0x30f33d95, + 0xbc4f58bb, 0x7030fc69, 0xd1914b8c, 0x87be2c58, 0x841a8a91, 0x7d245d68, 0xa121ee39, 0xab73fed3, 0x31d52af1, + 0x3fe177e1, 0x889ed816, 0xa042f44c, 0xdb48029c, 0x26cae80b, 0x42803a27, 0x76b1d663, 0x8655648d, 0xd8aa0858, + 0x49604e37, 0x5aba0253, 0x012c2d1f, 0x8d7ddf2a, 0xf2172a4f, 0x1d08ea34, 0x1087e9f7, 0x0a84d10d, 0x3bcd19d9, + 0xa574e2a6, 0x69a4b077, 0x25c66dbd, 0xa5c2edf9, 0x75974fac, 0x5e6f41d8, 0x8fdbc2fb, 0x184e5b85, 0xcbaacb94, + 0xa371e7e8, 0x4533c05b, 0xe435e36b, 0x091f86fe, 0xe4e0543f, 0xc3f92162, 0x17d9136d, 0xcd91d5eb, 0x061d569c, + 0x01024be4, 0x6b2f6d87, 0xd75f4efb, 0x985ccd47, 0x1becdbfb, 0x9944df09, 0x5ed6af57, 0xfe4144cc, 0x575864cf, + 0x48d658cc, 0xbb4372d6, 0xd7bd0d79, 0x6b89c1e2, 0x488351e0, 0x1e4a677b, 0x3f0fecee, 0x38384010, 0x8ec359d8, + 0x84b6c6c5, 0x4d6ef0b6, 0xcf98aad4, 0x37c631fe, 0x63642742, 0x74ca90e6, 0xc64b2967, 0x978436e7, 0x38ed1aea, + 0x4878839d, 0x4842ff2c, 0xaf76db8e, 0xb0e5147d, 0xb3d7c2a5, 0xb830250f, 0x1699b954, 0xb8ba2ce9, 0xaa9f27c0, + 0x42f43ba6, 0x8fbffc80, 0x872a0467, 0xcd3b47d1, 0xfd153904, 0xd531d2b4, 0xdc206445, 0x604f9fe0, 0xf104c05d, + 0x05c238a3, 0xceffd7ae, 0x9b6ce08b, 0xa6e48b0d, 0x88c31f0e, 0x36dc556e, 0x1cf6f65e, 0x20e031f6, 0x699b5a2e, + 0xe98a6d67, 0x7ae8b101, 0xb87937da, 0x9e29500a, 0xc0da7e84, 0x4f19a4cd, 0xe52ac0e3, 0xb4da4f35, 0x54d17209, + 0x3580d2d7, 0x76c0d19a, 0x0cbcfb5f, 0x71340e72, 0x4809d5d2, 0xd93496ed, 0x7f456a81, 0x7846289d, 0x1796d803, + 0xf61a212b, 0x469a0695, 0x23af1646, 0xddecbd39, 0x87d90adf, 0x6a0c11c8, 0xb1aad413, 0xa5d2fe7b, 0x8af66fa5, + 0xfa31cc8d, 0x02161311, 0x24f2fcd6, 0x562c2709, 0x16c43905, 0x9d6f008c, 0x0a807913, 0xb7471e1f, 0x85736113, + 0xc8c3f610, 0xb084d5dd, 0xf474e211, 0xf6fdfe15, 0x74b79357, 0xae597aee, 0xf11f93b6, 0xa83be799, 0x5d21143d, + 0xfca2549a, 0x006d9905, 0x9eb59bc9, 0x2b109f9c, 0xb35cfa65, 0x10ab91ff, 0xf12afd22, 0x5c37b05f, 0x1c8e75d8, + 0x62112c12, 0x48f5fc10, 0xe88397da, 0xd4d4aa99, 0x9075c9dd, 0xd5f18f16, 0xa3e09125, 0x740dc093, 0x77922523, + 0xc760c768, 0x25dc91db, 0x5c4c2908, 0xdced0ab7, 0x311e0361, 0xc81722cd, 0x9118014f, 0xe769e54e, 0x53c478c4, + 0x5d1398bb, 0x5d68b6ac, 0xb07674a5, 0x1a991272, 0x7c5ece2d, 0xda38b93d, 0xb1fd08d4, 0x8d1b6994, 0x526d4d74, + 0xeb84c80c, 0xad2d4772, 0x3f7ae3a7, 0x5797ae5f, 0x5dd1dbbc, 0x752f0da8, 0xe7473f25, 0x97377dc4, 0x19094083, + 0x32694e43, 0xfbbf8f23, 0xc5fbdb8d, 0x4ce1f8cb, 0xc506e465, 0x49a24e16, 0xe7e4191b, 0x8a755daa, 0x19582865, + 0xe0749ade, 0x19a44027, 0xd796989f, 0x9ac75606, 0x93a9e148, 0x1ce32d85, 0x868e0371, 0xc44d7c4d, 0x715faaac, + 0x772dc27d, 0xfa5a059e, 0xffed114c, 0x268ab0d9, 0xddd33bb6, 0x2145060f, 0x37c41f8a, 0x1168a04d, 0x49f58999, + 0x9c6ef167, 0xe4a13ffc, 0xfea71e46, 0x53c8510c, 0x02a74502, 0x08607bbf, 0x39f8456a, 0xd69a6fe5, 0x7bc4b879, + 0x8dd06abb, 0x0cf29480, 0x300d6774, 0xbf8d96f6, 0x96473bb5, 0x3c90a048, 0xfb37986f, 0xc5a00c2e, 0x2a05e297, + 0x274a92ba, 0x354b379c, 0x9f9db554, 0x2f72ccb6, 0x0058cdc9, 0xa1a1c38d, 0x3e37b6f7, 0x79a2d228, 0x4f2369e9, + 0x86258f26, 0x9a9c6820, 0xeb69f856, 0xa9298812, 0xce4012f0, 0x9aded287, 0xf85529f3, 0x8af89dda, 0x00a6ba0e, + 0xf9562fcf, 0xd2a48e3c, 0x77d734f3, 0x323dc4ad, 0xbdb24bfa, 0x0ce6c798, 0xfd9d8a43, 0x21d9811b, 0x6e17278a, + 0xb5ef616e, 0x73e423b5, 0xae74a04b, 0x0846dfd4, 0x56f0d929, 0xc7a521e1, 0xd0027487, 0xd5843a70, 0xc27dde61, + 0x2396d9d0, 0x308f0bb5, 0x880515a5, 0x5cdcb629, 0x2fa4c630, 0x5df86719, 0xf5a4811b, 0x1773eb07, 0xffce6253, + 0x7f48f8fa, 0xaa488c1b, 0x87e4923b, 0xecb34e8f, 0x0640d799, 0xb64323c1, 0x9169090b, 0x67ff6068, 0x30527bf5, + 0x3ce34a81, 0xcbbdb0cb, 0xac293d64, 0x913e7111, 0x8bbcc80d, 0x460c6d1f, 0xd960fcfb, 0xb04cbfde, 0x825a65b9, + 0x11fbdde9, 0xcc2b7fa6, 0xfcfb0dd9, 0x324a286f, 0xca16a16a, 0xdb0b3091, 0x6685ff1e, 0xfb88d5ad, 0x8babbead, + 0xfd2a20c7, 0x3adee043, 0x566980b9, 0xbaa80b48, 0x5c75e5a4, 0xa093c906, 0xbac7a3a5, 0xd3f89f9f, 0xfbfcea1e, + 0x8d0c8a0d, 0xbd5552b6, 0xbeb3c8cc, 0x6d577bea, 0xc0d992af, 0x8d633eee, 0xed91eb55, 0xecf7bc04, 0xaf789dbb, + 0xe97d07a3, 0x2c52ac7e, 0x4a5e4888, 0xe2853b2f, 0x6416cead, 0x0c2ed4e7, 0xac27977c, 0x1995109a, 0x47d94907, + 0x03c136fc, 0xb3bb2078, 0x46544150, 0xd7ff0d67, 0x33378ead, 0xe40c8705, 0x18856aa0, 0xd1a96af9, 0x43869fa1, + 0x3ef06176, 0x9b83049d, 0x868ffbae, 0x6e4499b1, 0x94809708, 0xb2863963, 0xa8e30318, 0xc2da130a, 0xbd0fbe6d, + 0x0dc94c94, 0x37803aa3, 0xda6b4197, 0xe7306404, 0x7b795ff9, 0xa48c21e5, 0x884d22b3, 0xe9761bc9, 0x00fbd5ff, + 0x20e61060, 0xe0161322, 0x5ca5a28b, 0xbbd7b892, 0x6759a99f, 0x4c12a60f, 0x47c15d2a, 0x8f3166dc, 0xee41e497, + 0xf07fc009, 0xedeeef82, 0x0b33acae, 0x7852bf30, 0xd6ef7ab2, 0x16d1e497, 0x7430c5df, 0xeae80f51, 0xfbc230b6, + 0x67dcafdd, 0x1d5f2ed8, 0xbeb30dc2, 0xe00f2e0e, 0x5ca08dbe, 0xd0ac82eb, 0x3e3b2caa, 0x4b70693a, 0xf6a57f25, + 0x342e3fe4, 0xa5076e36, 0x9642a244, 0x9b6b6c3e, 0x5e9a73fc, 0x6d859b80, 0x0f17289a, 0xbea9b21c, 0xc115a11f, + 0xa29b6bde, 0xed2e3d21, 0x1559bd25, 0x82b59b78, 0x981bb163, 0xea83fabf, 0x6b7d919e, 0x4cafedb6, 0xfcad030d, + 0x69e2b586, 0x70544161, 0x6d1d71ab, 0xb080fa69, 0x21497536, 0x12f94734, 0xf6bafbb5, 0xb6540b4d, 0x151618ad, + 0x6c9bf075, 0xc805e31c, 0xae8bdd1f, 0xb3062090, 0xae6b9d32, 0x839bc1bd, 0xf200e546, 0xc1756b96, 0x1930dd1c, + 0x7560a319, 0x91b01f2e, 0xb588e68d, 0xd89cc3e2, 0x41e9a640, 0x1fa5b909, 0xbee7f5ab, 0x996da492, 0xa2d1db59, + 0x70977280, 0xe2a8e345, 0x1346ae37, 0x36f5d516, 0x0ed4df07, 0xe70ab159, 0x58d933e1, 0x7b40e537, 0x99453bb0, + 0x5c19b434, 0x09433361, 0xd7526b54, 0xde4bda51, 0xb89a9253, 0x8b79482f, 0x59051e3a, 0xe531527a, 0xe91dd1ab, + 0xc059c00a, 0xbd410959, 0x0c75aa84, 0xb190c110, 0x1c779a81, 0xb065f6c4, 0x0f465437, 0xcf991010, 0x036f1daa, + 0xf672d881, 0x0fd26cfb, 0xa1d91c53, 0xd12338cc, 0x06ffc608, 0x945fd7e1, 0xd00c08e1, 0x30c5caff, 0x81994162, + 0x63136fb8, 0x2a1d1b4f, 0x6299e37a, 0x2e692564, 0x25feb321, 0xfd0951e7, 0x02f410bb, 0x9659f067, 0x40f3a663, + 0x922aedca, 0x18b9505d, 0xac820077, 0xbcf7a072, 0xa7216a10, 0x8bcf1c46, 0xe2a3463f, 0x68f411ba, 0xe8053f35, + 0xd84a4d2a, 0x75596b0b, 0xbd21b174, 0x8b484557, 0x55d02fe9, 0x1fdf560a, 0x0f3b7c9f, 0x2d172ab7, 0x97998123, + 0xceb647b2, 0x30102c9d, 0xe76e12be, 0x94232f2b, 0xed230809, 0xad50bb5a, 0x596ef1f3, 0x2b23823e, 0xb98ff8e8, + 0xe916a575, 0x8f673b8a, 0x36498fd3, 0xdef52ce3, 0x5f830402, 0x190f3351, 0xb7722991, 0x9b97ebb6, 0xb8663a98, + 0x80a256c9, 0x4b79519b, 0x58617299, 0x33c2fc1a, 0x79109bfc, 0x6355d8ec, 0x45df76fc, 0x012e7fc9, 0xa3f06690, + 0x989844b4, 0x7907f8ae, 0x6786ce9a, 0xa69e26c1, 0x4a162127, 0xc98e0b64, 0x1a05a156, 0x56309f85, 0x758d023b, + 0xc932c053, 0x99b4c218, 0x513cb28a, 0x2e38e902, 0x77d3e8e4, 0x1e99d56a, 0xaa6955c6, 0x4db388f1, 0x02d90614, + 0x36e0c289, 0xd9e65c60, 0xe77f8edd, 0x8946e5eb, 0x1f66bed8, 0xed58a351, 0x9905c461, 0x66564451, 0x7d14d441, + 0xef1339a0, 0xb7ca4116, 0x71abe36f, 0xb60e033f, 0xd2152625, 0xbf9cbbec, 0x998ea373, 0x941d7c3d, 0x5ff8e48f, + 0x863db54e, 0xbbb11984, 0xdd1356b6, 0xab641719, 0x2ab7ef2f, 0xa3d0c48f, 0x4bf1242a, 0xe5b97c76, 0x32a002e0, + 0xbd62d919, 0xfe975133, 0x216cf7ef, 0x45fbe521, 0xf98e23db, 0x3203f14f, 0x8abb9ea7, 0x4b78a1e0, 0xf0d7bc39, + 0x155cfd13, 0x1c44cac2, 0x95369cb1, 0x39cd9fc0, 0x5282e992, 0xffa0bbed, 0xe240f874, 0x3b09b802, 0x12cb5adc, + 0xe9423d7a, 0x403b3b99, 0xada092a7, 0x851c9b3b, 0xa625666e, 0x4d0e4f20, 0x49264c96, 0xa9c8500e, 0xd37d3b86, + 0x2097eb9c, 0xf32f1257, 0xc0192de0, 0x19dabed1, 0xdfb4bf06, 0x0b48ee2d, 0x1c835ac4, 0x4dec0b93, 0x7cba2caf, + 0xf549869c, 0x56c583be, 0x3945fff3, 0x001326b2, 0x378e14e6, 0xb3e69f2c, 0xfdc779ec, 0xe5be49ae, 0xaf038b61, + 0x5c0e7601, 0x015e2fb9, 0x6d185718, 0x363fe840, 0x3729c985, 0xa9b7f3aa, 0xa41de646, 0x63304b95, 0x0e6f2f2a, + 0x9bd59621, 0xc727cf4d, 0x447b0668, 0x751b0274, 0xc471a558, 0xec36f7b2, 0x7197547e, 0x64ce56c0, 0x8a427870, + 0xb7ae9c1c, 0x668abd5c, 0x8e4547c6, 0x9314c4fc, 0x31f3d18f, 0xd79c70ac, 0x4a9964bd, 0x45b622c2, 0x194900d2, + 0xb4cec415, 0x0f1a06e9, 0x11ab7e81, 0xc1aa577a, 0x435c0123, 0xb69be672, 0xc0dd624a, 0xb19ba18b, 0x7b2c886e, + 0xe9c03883, 0x18672c52, 0xbf1d36bb, 0xca9eca65, 0x38d962e8, 0xbc868257, 0x3850610a, 0x1c61bb26, 0x2a43e991, + 0x190c204a, 0x3da50b3c, 0x532ac88e, 0x70d92dd1, 0x7e996aac, 0x48340e35, 0x23c40874, 0x53f80b08, 0x13aac22a, + 0xb0e5104e, 0x0841aa35, 0x08c604f0, 0xb868f069, 0x44354236, 0x17d599fe, 0x96f09d81, 0xad9c877f, 0x0b07e5f1, + 0x15863e3c, 0x93098f25, 0xefd8b0d0, 0xdbc8bcf6, 0x7d29dab3, 0xb6e320c5, 0x9bab36a4, 0x090b7288, 0x4073b1c3, + 0x816a84c0, 0xe5c09250, 0x0e393eac, 0xd0046c40, 0xae8195c4, 0xd95739a3, 0xcdd14bbc, 0xb8ca0d4c, 0xcb53351c, + 0xef7e8c65, 0x7ad1fa05, 0xa7f1bd6a, 0xece7d46a, 0xfd04c54d, 0xfd06781f, 0xd00d36fa, 0x0123f7c1, 0x57ced070, + 0x9b81695f, 0x0253d88a, 0x43140383, 0x90683d04, 0x1e96a371, 0xb6b0de28, 0xbcf4bde3, 0x2c820ee0, 0x60607660, + 0x9c45ec04, 0x5197ff12, 0xac0123ce, 0xc878bf39, 0x10d53fb0, 0x6a10a03d, 0x5f8a3c6f, 0xd51f1d29, 0xfe1aa78d, + 0xd8511674, 0x1870d3f9, 0xb34852aa, 0x588b753b, 0x04deb5b6, 0x644f0241, 0x96b860db, 0xbb021b4f, 0xdc367d73, + 0x3f728e73, 0xfd32476e, 0xf80b6c86, 0xe9ad667e, 0x6440d5cf, 0x6310eb93, 0x255b65c0, 0x8be87382, 0x0ef9ccff, + 0xd2d04ed2, 0xe176ad60, 0x72a3e7d5, 0x6a67199e, 0x0468f2f1, 0xb464a605, 0xe4a59db8, 0x16ffafe7, 0xaa4fc1e5, + 0xcbbe2a8f, 0xb8eeeed1, 0xd8fe9496, 0xe901bd5f, 0x592d67e1, 0x24b42f4d, 0x71236485, 0x15737190, 0x17c78dde, + 0x26bcfcdc, 0x29db3082, 0xf5b56154, 0x0bfecb75, 0x075c6ff0, 0x78df3c11, 0x06b057e2, 0x3f56ec9c, 0xeb098e9f, + 0xbd4a6deb, 0xa1a6219a, 0x015b1f52, 0x077f7b16, 0xbce1b1f7, 0x148dc062, 0xbd09592e, 0x3caa6596, 0x6eddca97, + 0x8f6ea1fa, 0xd2744d88, 0x8c6ee33d, 0x604f5e73, 0x721601c7, 0x72429731, 0x7d461b8b, 0x399d9e56, 0xb9012dfa, + 0x19592b10, 0xba8df0f8, 0x5d1e18ef, 0xe71c4f18, 0x59dec154, 0x97a42b03, 0xafcab452, 0xbbca6af3, 0xf159abf6, + 0x1a948446, 0x7b79f199, 0x0595d7c3, 0x17223885, 0x44299253, 0x0f10334a, 0x0c509d86, 0x2ea282a5, 0xfa13aca6, + 0x0353fdbd, 0xbd1905b7, 0xf63f502f, 0x688b8339, 0x6905d4b8, 0x494eff1b, 0x71e8bf01, 0xafce7257, 0xf7856e39, + 0xf20a09b0, 0x2c6b4cc8, 0x189ad723, 0x3cd16805, 0xac98696c, 0xf79d0bb9, 0xbab37f8c, 0x4b727868, 0xd5f9d2ca, + 0xd7ddc349, 0xcbe339f9, 0x98b645dc, 0x9f2535eb, 0x1b236709, 0x1874620b, 0x00265fc6, 0xffe28865, 0x237fdc88, + 0x9f7d2108, 0x74a57286, 0xd5eaba94, 0x05f0af4a, 0xf0a47254, 0x6714089f, 0x3cbb5406, 0xf5d7b491, 0xcd885d5b, + 0x7e48fc43, 0x51bd8468, 0x2c8b0729, 0xfea85ca2, 0x3ebc36c6, 0x14cf65b4, 0x6985e6e3, 0x05cf1e8c, 0x63bae428, + 0x2701ae24, 0x78b410c7, 0xb542df9b, 0x64b4ceea, 0x4658ff6d, 0x8c9e84a8, 0xe20b8385, 0xdec337fc, 0xb8256f7f, + 0xa8dd042b, 0xe9acaa94, 0x1c40a0bd, 0x61ee5a30, 0x89e045e1, 0x417a52cc, 0x269c40a2, 0x56e715c7, 0xd0d3f48f, + 0x2e03266a, 0x4871e428, 0xc7bb2b44, 0x1744cd72, 0xa6106205, 0x327686bb, 0x2bb8c03d, 0x54a0df98, 0x725aa032, + 0xb4b9e61c, 0xb164fb57, 0xeaed6e4c, 0x11cf1c4c, 0xf2e4b02c, 0x5578b729, 0xe45a0396, 0x03c6b2bc, 0x39e2f648, + 0x25aaa0d3, 0xbcf11a41, 0x2193258e, 0x07a3411a, 0xa88a4782, 0xa0302e0f, 0x4d9311fc, 0xaf42bf7b, 0x6eb7a1de, + 0x48a6549b, 0x5abaead6, 0x0a9970c0, 0x8a60ed7a, 0xd3af3fa1, 0x290ea2ca, 0xa7e83016, 0x8052ff1b, 0x89c67075, + 0xe0ced1bc, 0x800e4cf3, 0x98c12258, 0x3919a7e8, 0x18ace016, 0xee06d8ed, 0x9a4c029b, 0x6e7c8c28, 0xb5ae8ce6, + 0x90710505, 0xcf5b562d, 0x57bf7493, 0x31bffaff, 0xd60cc976, 0x5e7902d8, 0xf18da021, 0xf05fcbe6, 0x1fb0141b, + 0x084068a6, 0x04325cf1, 0xadc95576, 0xb3ca876f, 0x031e1500, 0x5f0f4d4c, 0x375a1508, 0xacda134f, 0x59112add, + 0x7ac89fb3, 0xb8567c7b, 0xfc765231, 0x96a9c25f, 0xa905725c, 0x92750e4c, 0xa425d2cf, 0xa3c4d821, 0x79fed15d, + 0x727e9995, 0xe3440b98, 0x285c5887, 0xf12a8bce, 0x2e0318d9, 0x3990138f, 0xcc991159, 0xac09f7d3, 0x698a02eb, + 0x6430ffba, 0xcc20379a, 0x219fc743, 0x0dbb5f00, 0x6e6080e9, 0x165a8d61, 0x6c98e417, 0xc4c86f41, 0xbf1e57ea, + 0x4acf3f01, 0xe36a865c, 0x2c5474ca, 0x354b51e0, 0x7d787ac3, 0xfd91bcb0, 0x9d478ebd, 0xe801924b, 0x0d12bf0d, + 0x40058fa8, 0x92b8fcf7, 0xbf490071, 0x1195d75c, 0x266b0398, 0x3c0961ac, 0x93fc5f40, 0x27426b3d, 0xfa13e9f4, + 0x5452f4fe, 0x307cb0a6, 0x4abcd238, 0x3fc15c85, 0xb33b8091, 0x74be9e28, 0xc1b2a427, 0x11d03684, 0x1389a2f9, + 0x30183015, 0x5e56730f, 0x1a50ed29, 0xfc8d20c0, 0xb375590f, 0x63dbea3b, 0x72e0eef5, 0x185f4896, 0x144cb4f5, + 0x789294e8, 0xd1d4c6a3, 0x9a03e169, 0xa48dfba8, 0x6f2d9b23, 0xa6b9fb21, 0xaad77a71, 0x99d175b9, 0x9da366c8, + 0xa0e29d9a, 0x2acfc22b, 0xa0d69336, 0x84e0410f, 0x58aed144, 0xb539fcc5, 0xe62928f5, 0xc8b53488, 0x4ea227df, + 0xbb567d2f, 0xb209b1a9, 0x4f7804c5, 0x5bdfc4e1, 0x27ec80dc, 0x37b43bab, 0x6a33f454, 0xdb66b6d3, 0x8266ebbf, + 0x071b2849, 0x17784382, 0x9c33666c, 0xd628011c, 0xee8a8904, 0xbb67e059, 0x7b15bbcf, 0xe6d9c86f, 0x27275cdd, + 0xabdfc048, 0x0407aada, 0x06d83692, 0xc33c6186, 0xec50ad6b, 0x4bbb928a, 0x0ecc5992, 0x7fa03c00, 0xd6e5e335, + 0xd2fb4ac1, 0x41565c5e, 0xcbc589f4, 0x8fdaaabf, 0xf538b4c7, 0xc25b28b4, 0x68c33b65, 0xeb2389fd, 0x36d05530, + 0xe80414b5, 0xa246135a, 0x24c80247, 0x9e9c5307, 0x0d04d7b7, 0x22c07449, 0x5a581b2d, 0x3a6c44cc, 0x6d9b043a, + 0x2cad0f88, 0xf060742f, 0xabd7b9ad, 0x5d21f9eb, 0x69abfc8c, 0xa550ec5c, 0xbf53ab10, 0xb70a67c5, 0xddd56c77, + 0x83bfc23b, 0x8c575d7f, 0x9fc9c02a, 0x7bff43da, 0x1593f995, 0xffe3b6ba, 0xcfc54a70, 0xdfb3cea0, 0xcc9b5542, + 0x4fae903f, 0xc605a676, 0x1c5e2b65, 0xe9403b19, 0x7e0163a9, 0xc8f86bca, 0x111862d6, 0x3407043c, 0x9ebb5ed6, + 0xc3d4e98d, 0xd317c64d, 0x3d1af080, 0x1af1d640, 0x4cd9b2a3, 0x81e7e74e, 0x023b7654, 0x58fd40ee, 0x86d3d552, + 0x7fb44311, 0x361d073a, 0xaf8fcc3a, 0xfd96af82, 0x03d97877, 0x4ae76d97, 0x79f8d9a0, 0x810803f4, 0xf5305ca7, + 0x187eb7c3, 0xced0de02, 0xd2c5e341, 0xa9e3c2cd, 0x8ba9c74a, 0x64fc332e, 0xcb02fff5, 0xcb6e4a8c, 0xcdfcbc60, + 0x99b2f024, 0x3dd54408, 0xfe5bf739, 0xb27b716e, 0xed218405, 0x7b74a838, 0x596143e1, 0x7e2e6a7d, 0x21e4b361, + 0xd096017c, 0xc2ff4db2, 0xc3723d27, 0x4699d680, 0xdfe8e7a2, 0x14332bae, 0x4d32b73c, 0x589bf573, 0xba9e7b01, + 0xe744d5b7, 0xbbd6db5b, 0x99045ba3, 0x50ca3a8f, 0x23bb1634, 0x5a0188fb, 0xf28e09a1, 0x90f951e1, 0x7ba6cd41, + 0x81366ac3, 0x6486cfa8, 0x44caddf4, 0xbcc538d9, 0x595ed179, 0x769435c6, 0x58a336c0, 0x2b70d4dc, 0x1496aaff, + 0xf214662c, 0x5b8179e9, 0xbf6012e2, 0x67916a14, 0xbc2ee5ca, 0xc75a6e69, 0x9449f0db, 0x54315237, 0x26a119ae, + 0x27732b7a, 0x8ac17d81, 0x22a3fab5, 0x213d433a, 0x12dbd6f5, 0xfb32471e, 0xd4c3f688, 0xd26deeac, 0xf4053e98, + 0x9ce54467, 0x827d5f2c, 0xfd8fba78, 0x56247930, 0xf8d706ae, 0xf359d27f, 0x46ec7cb4, 0x51da3c35, 0x2b8de673, + 0xcf17d98a, 0x3666fc4e, 0xcde7e162, 0x08bb8bca, 0xcc958025, 0xc350020a, 0xd0b7e1c0, 0x30da4055, 0xbfbb6d76, + 0xc15a79d3, 0x902c55a7, 0x0c033ba6, 0xc1512a87, 0x04a374fb, 0x20ea932f, 0x725d0ed8, 0x927b72c8, 0xadeb5fea, + 0x39628d1e, 0x6e3b5307, 0xc7ac3dc9, 0x1197b084, 0xda33a5ec, 0x05a2cc03, 0x9fa0b116, 0xa8b6c18f, 0x5bc056c8, + 0x33e6bbb6, 0x2dd412c3, 0x414d51a1, 0xa003faf4, 0x84d7392d, 0xd4ffd417, 0x1ec166c0, 0x773098c3, 0x7ac864e7, + 0x962aefe9, 0x545ec08e, 0x7ee9e0f2, 0x8a4d6af4, 0xdcd9f25b, 0xa8d51253, 0x279d5125, 0xa9769d76, 0x45ad9a25, + 0x52d5ade5, 0xb077cab6, 0x95016b0b, 0xa11693bd, 0x2b5f7622, 0xb6c4dbcb, 0x039ea56a, 0xe9f5766d, 0xd9e4634f, + 0x4ec2f4b9, 0xcc09b2ad, 0xf93098c0, 0x6d81fe59, 0xca9abec1, 0xfed94b9a, 0x73524065, 0x8087a24b, 0x81c9e85a, + 0x8214dfee, 0x7f4312b1, 0xf1e00dcb, 0x60abc8e1, 0xea8851ef, 0x05c1ad94, 0x34da8283, 0xbaee3965, 0xc77f9068, + 0x42e85eb6, 0x7b6527d7, 0xb9abc0dd, 0x271d7337, 0x677ab0f1, 0xfdacac78, 0x6fafb992, 0x95e70bc9, 0xd3b50542, + 0xbe587458, 0xa54d5cce, 0x9892609a, 0x61365d08, 0x17593e28, 0x3ffc96fc, 0x1b9c09a3, 0x917a4acb, 0x8e62e59a, + 0x38d6d1d3, 0xea736a2b, 0x7716ddb0, 0xd01f66ef, 0x9dab5ea3, 0xf1e96d20, 0x9809780c, 0xa911de76, 0x9d097da7, + 0x211ad471, 0x70e389cb, 0x735fdd25, 0x185bce24, 0x344bdf66, 0x94c72517, 0x66ba1400, 0x64857920, 0x012b939f, + 0xc1c8d4e3, 0x91693b9c, 0x281db2c4, 0x2c8769dd, 0xdb39c6cd, 0xefd6de68, 0x9feec55c, 0x9a4ee243, 0x36668dd1, + 0x7853ea27, 0x21bc55fb, 0x5462b24b, 0xce56e386, 0x8db50c68, 0x4a78d3f7, 0x88254022, 0x3875822c, 0xcb3bbf2f, + 0x69238e44, 0x9b4181af, 0x910a8062, 0x6935c751, 0x1d78e8fe, 0x1fd086a6, 0x0bb972c1, 0xaede087f, 0x451eed0c, + 0xa8d84ea4, 0x6a6b7b29, 0x060bb322, 0xd5216020, 0x2a69802e, 0x78571e45, 0xc487a077, 0xbdde346c, 0xde93ee33, + 0x5007fb9a, 0xeef8aeb3, 0x1bde44cc, 0x38647f83, 0xedebbe63, 0x34548643, 0x19f5daf3, 0x2a50b3db, 0x1916a3c4, + 0xd885c0ab, 0xd5fde2db, 0x79630c04, 0x2ee81ee9, 0x1035ea68, 0xe13a4969, 0x6eafb57e, 0x50933ce1, 0xfd87f15f, + 0x9b0dc143, 0x3cc09fad, 0xe9154500, 0xae617d7c, 0xcc3a6090, 0x43ae99a1, 0x0ac982cd, 0xf30e31df, 0x41df8768, + 0x63709964, 0x2243b968, 0xf9cf7672, 0x907190ea, 0xffbaf4c2, 0xa632f63e, 0x2ba21921, 0x1f9e9518, 0xeba592bf, + 0x88024f94, 0x2f16e929, 0x1fd924b5, 0x6af843c1, 0x662dcd3a, 0xeb7ba6eb, 0x477902f9, 0x25ee8b1e, 0xf2dcc22e, + 0xda31dfbe, 0xbd7cb410, 0x8513e6bc, 0xdd9b0800, 0x5f1968ae, 0x1201b1ff, 0xbef73f97, 0xda598fbd, 0xf69d52fd, + 0xcf6ac45f, 0x226fef8d, 0xc32d5b36, 0xab97abcc, 0x229e243e, 0x69cda4e6, 0x1aa28851, 0xa30c0471, 0xdd90562d, + 0xfb8ecfb9, 0x565c1b3f, 0x005b3873, 0x4125ca0e, 0xb53ce23c, 0x991f118b, 0xd1ba2b72, 0x7944deda, 0xcef469f5, + 0xc32b7f80, 0xae31f801, 0x54b6105a, 0x2cf98541, 0x536ccf18, 0xb9608cc5, 0xf58bdb2d, 0x635653dd, 0x6c4627a7, + 0x57164b2e, 0xfed59fec, 0xde2a243a, 0x4e67a975, 0xce533eed, 0x8cfb642d, 0xfa672758, 0x93726bca, 0x6ee5fef4, + 0x0ee54dee, 0x57935f77, 0xe78ceab3, 0x0d39e9c2, 0x979995fb, 0x714f9427, 0x25722784, 0x21cde9c2, 0x71212d3f, + 0x543b0ec5, 0xc031f8c9, 0x5e6ec7a0, 0xdd1d5cb3, 0xed5d3c76, 0xb4576288, 0x92dde484, 0x12647d00, 0x69703757, + 0x2d3becfe, 0xbe1a5859, 0xe4e2542d, 0x3e3745c2, 0x6c94788a, 0xb48965b9, 0x487f5ce4, 0x77ec72d1, 0x5d5276c0, + 0x8709fff1, 0x04727498, 0x9b6e1bd5, 0x0eabac10, 0x71672595, 0x3474f592, 0x119919a2, 0x6cae686f, 0xa93a1926, + 0x2dea7bff, 0x6d26271a, 0xd21827b6, 0x24019274, 0x1873c0d1, 0xb797eed6, 0x6ec828cb, 0xd221926c, 0xf6002965, + 0xef00594b, 0x56ac7f44, 0xf5736891, 0xc44c0714, 0x7e850254, 0xaf29b64f, 0x933c587d, 0x94176c70, 0x047d7734, + 0x4f35258b, 0x5eb37f54, 0x899309d5, 0x3236076e, 0xe71072f6, 0xfe69f9a3, 0x786ee5e2, 0xc7b613f4, 0xcd7a541b, + 0xb1f9590c, 0x800b89c4, 0x32ba6ea6, 0xb77960ff, 0x9e2621d2, 0xed38b08b, 0xd8405feb, 0xd0f53f9e, 0x0ca18bde, + 0x2f72ad55, 0xc147e704, 0x3acd5258, 0x270b9d0f, 0xbdaf9621, 0x1e2ed9b8, 0xad3cf805, 0x29b2c3fa, 0x9febf731, + 0x06805caa, 0xd8a53b3d, 0x79a1e5b8, 0xeed428f0, 0xcccb9b9b, 0x265020a7, 0x33fed2d6, 0xfc2bc1bc, 0xc992a4bf, + 0x68db28d5, 0x1ba3bc33, 0x7debd820, 0x7ff9f6d4, 0x32965235, 0x8532a246, 0x1f83939b, 0xd75f83d4, 0xca8a754c, + 0x1bc0ea4d, 0x099c6cbb, 0x75988e0c, 0xa2db8f5b, 0x46160677, 0xdff8ad30, 0x0e681c83, 0xbe08128a, 0x02fe0461, + 0xe53910f7, 0x7f29ccdf, 0x1724a1fd, 0xd7385cb3, 0xafb42bf2, 0x805115c1, 0x572258d8, 0xba833ed2, 0x99b35143, + 0x24ac7c59, 0x59f4585f, 0x40574875, 0xd39f48f6, 0x71848639, 0xfc27b910, 0x14463b4e, 0x917feb18, 0xb0d18c33, + 0xfa3f012d, 0x7dfedca5, 0xd0084508, 0xff0c4065, 0x5357ec18, 0x97c640bf, 0x4eca36c1, 0xccc5ea65, 0x20a9a9e1, + 0xd50e12dc, 0x8333da38, 0x8964afcf, 0x7d12c525, 0xd16e4814, 0x60a4b926, 0x6601260f, 0x82260bf9, 0xd3f3c7ba, + 0x616ac6b3, 0x0f9473f8, 0x68e8587a, 0x84ee9ed2, 0x2fb84fc9, 0x95700b96, 0x9fcfcd33, 0xb4610b5d, 0x2ab89618, + 0x31675a1f, 0x5b7b0ac9, 0xd199dff6, 0x137247de, 0x8ddb7035, 0x44222404, 0x847b9dfc, 0xb84c7128, 0x1676423a, + 0x275200e3, 0x3d25290d, 0xa1fd2db3, 0x4c37a6db, 0xb64abbb1, 0x11ebc3ca, 0xe07c6067, 0xcb66535d, 0x14fb2c53, + 0x671d6ccc, 0x680eb8b8, 0x514e718a, 0xdd716f1a, 0x5b66ae71, 0xe4736136, 0xff5c4f24, 0x00275a2f, 0x13172a95, + 0x4bba9efd, 0x6c174325, 0x0e53b106, 0x41fc4bc8, 0x6b399108, 0x7db57c3c, 0x714cb5f7, 0x5e216c00, 0x6174ca72, + 0xc2003f6a, 0x6573b284, 0x3427eb77, 0xebdd7f32, 0x0ec979e2, 0x1727b25b, 0xb36e9376, 0xb958c994, 0x046d7e00, + 0xf91f3f85, 0xd8d9657e, 0x39fbc0b7, 0x4f0d8069, 0x555809f0, 0x33c4263a, 0x2b677b11, 0x5362e5ab, 0xa042586c, + 0x10319cbc, 0x7c2d6fa7, 0x0f28a300, 0x27438166, 0xad9ea15a, 0xd69886f2, 0xc3e8e489, 0xa30eedb9, 0xd6a75466, + 0x248979fd, 0xfaed98f0, 0xb93f4a0e, 0xc497b767, 0x77858f37, 0xbb20f169, 0xb6df4fbe, 0xaf4e226d, 0x75ad6ff4, + 0x45b0fa6a, 0xa3b804d6, 0x92262757, 0x46094757, 0x05f517aa, 0xe515680b, 0x76c86ade, 0x4fc2cfb4, 0x2c0a44e2, + 0xcc384dd4, 0x33e0daa9, 0xe002e9c1, 0x2cddab23, 0x64e55051, 0x5f1b964e, 0x643c542b, 0xc44332ff, 0xaaaf3d0e, + 0x3108a53f, 0x6222d4e7, 0x5527cf0a, 0xb00a49ad, 0x4bb5b608, 0x1262c46b, 0x101246b4, 0xb0633c90, 0x3963a57d, + 0xff81bbf9, 0x74f7dd38, 0x4a302162, 0x9720ce2b, 0xf41222e1, 0x0e7bbc6e, 0xd541c986, 0x6e09300c, 0x025d9b11, + 0x769077bf, 0x7a03335c, 0x2ba8cf02, 0x6d3b8e4f, 0x99d097d9, 0x4a77fd92, 0xa91d723d, 0x3bf77fe2, 0xad8b98f9, + 0x38a023ec, 0x94c64813, 0xfbb63aa6, 0x1a0c5cdc, 0x31653503, 0x6c9f8330, 0x289dab67, 0xf16b8ee7, 0x2c151b4c, + 0xae7cceb8, 0xfa6c5cd8, 0x89d11b85, 0xbdca2830, 0x3a570de1, 0xe23c2dd2, 0xdcd86384, 0x6cc1b494, 0x6d42b582, + 0x17af6240, 0xa8ac6091, 0x546465c6, 0x5b2ba2c1, 0x779229fd, 0x952ad2a4, 0x7ffb6333, 0x1cef62fb, 0x76347a11, + 0x7a19f040, 0x529dd1ed, 0xdf2adf71, 0xef6839e3, 0x0cc39c76, 0x0c304dac, 0xebfd6989, 0xc01feaed, 0x15fe10fb, + 0x5c9eee46, 0x7a1ce43a, 0x735b2554, 0x11e052a5, 0x7c44e343, 0x28f9fb56, 0xccd5cbc4, 0xbae93ef6, 0x3355047c, + 0xee3735d9, 0xfff1a05a, 0xcee85acf, 0xfe6880d6, 0xd36b3c03, 0xa0993162, 0x26a19376, 0x794b5fe8, 0x1965a507, + 0xdbe0aec5, 0x7d4fd30c, 0x21af936a, 0xe26776a5, 0xc66ed883, 0xf9ecd8ea, 0xe92dc606, 0x018ecb40, 0x0afc98c2, + 0x33de605b, 0x7cd73ac6, 0xfa36271a, 0xfd1358c2, 0xb0ba1706, 0xc2a27899, 0x6a3970fa, 0xd420cddb, 0x785aea1b, + 0xf69a5850, 0x10cb44b7, 0xbb6c1356, 0xf945e9b5, 0x6b916a2e, 0x9fff43cf, 0xdd24aae9, 0xe69dcdb4, 0x44a2b140, + 0xad76f307, 0x6b288d5f, 0xd2a959f9, 0xc40ec7d5, 0xeef525d3, 0x6703a294, 0xce8b9278, 0x54cb7403, 0x456e176d, + 0xb40a305f, 0x3d1c57ee, 0x6e9779b8, 0xb20d299c, 0x2f9931a8, 0xdb8d7241, 0x7b072093, 0xdadf4762, 0x19109741, + 0x6e62aeee, 0x861a27bf, 0xdc01854a, 0x6fc06370, 0xfa89b2c5, 0xa02aaefe, 0x8fe55d96, 0x2cd37d43, 0x9ce2f242, + 0x33937ff1, 0x532d37fa, 0x84f06a19, 0xa536d1dc, 0x112597fe, 0x892aef33, 0x1d21d30f, 0x603c4524, 0x35cc167a, + 0x6bfbdcf6, 0x42377e20, 0xc5464dc0, 0x10539c0d, 0xde4a09e8, 0xb5ee19b3, 0x287f36f0, 0x8932e809, 0xced3e69e, + 0x4c5da28f, 0x17c679dd, 0x8628c236, 0x5fd9d1bd, 0x1fa89ba1, 0xd948cb50, 0x5cd51c70, 0x47427607, 0x198db9d2, + 0x1e0601ed, 0x3ecf997f, 0x21ae1fe7, 0x2f934950, 0x8ec88643, 0x79e1b51d, 0x69d18be0, 0x7dca9fd6, 0x22459b95, + 0xfbab836b, 0x0e649a85, 0xee412b1f, 0x2c47db81, 0xbc8f2e89, 0xcc9b0f77, 0xd01537f0, 0x474a004f, 0xc3e3c464, + 0xc6215e7a, 0x06c96520, 0xe9e50b59, 0x18679477, 0x8547ada3, 0xdb49b953, 0x31183352, 0xad823b9e, 0xec6fddc2, + 0xecf4610e, 0x7f6b37a1, 0x3c25a985, 0xe464173c, 0xb60a6062, 0xb93a0a4c, 0x85c3e9e7, 0xcd232e64, 0xe76f9825, + 0xb22dcf00, 0x40b5b2b0, 0x8fd1620d, 0x9af0d795, 0x3196dc85, 0x1726a21e, 0xde9cd567, 0xd65f1dab, 0x8516a172, + 0xaa83204a, 0x6985c275, 0x0e455b13, 0x5f6f03d6, 0x2149c23b, 0x55fddedf, 0xcb31e47c, 0xcc8b0a71, 0x66c0104b, + 0xb94f17b0, 0xf32ca575, 0x910cb0e8, 0xd730b671, 0xd7ea8045, 0xa3cea49c, 0x0ed93013, 0x891bb31b, 0xa531b609, + 0xaee2c75e, 0x0e25e04e, 0x51e3509c, 0xdef3f65d, 0x88540c34, 0xcd5bd09a, 0x099652c7, 0x7973b3a1, 0xc28ad4fe, + 0x3350c546, 0x63511bb9, 0x61ddbc9f, 0x33b2e6f1, 0x77e1bc7b, 0x9b0f7731, 0xec37f475, 0x38ff8b93, 0xcbe63ece, + 0x3c4f8876, 0x864bffa7, 0xf24099aa, 0xcbec496c, 0x16ccbf23, 0xeca5e069, 0x0974f316, 0xa1862ab7, 0xd1dcb52d, + 0x3df22237, 0x2395fab8, 0x51d98608, 0x99df6ec6, 0x09278a60, 0xea3ff5c4, 0xfc5a1ece, 0x8ae841cf, 0x23355fcc, + 0x4a0e1dba, 0x03170717, 0x08c0b570, 0xbf7375e7, 0x76f3e12a, 0x985fd983, 0x43f30e43, 0x19a3c0ba, 0xe73c9ce6, + 0x2d6a2ab2, 0x46115279, 0x996a1679, 0x1f4cd61b, 0x1dbd2978, 0xb792cf64, 0x9934157e, 0xaf349f91, 0xe7d71675, + 0x71e5bf53, 0xa3e13934, 0xaa0a2d5b, 0xcb3fed47, 0x05ecc569, 0x23eaf281, 0x118e9657, 0x68fdc7fe, 0x2cfdd9a8, + 0x016c5bad, 0x1c72e47e, 0xf929febb, 0x5b0ce71e, 0x8a3f8704, 0x2ec7158f, 0x6597a3fc, 0xb45e0a93, 0x31acb975, + 0x9becae69, 0x30ac2c53, 0x2f0a559b, 0x561dc69f, 0x1855f1f4, 0x964af187, 0x9728c1ce, 0x87a6fb02, 0x3c719dc7, + 0xa4d6838f, 0xc7e248ca, 0x24d19f23, 0x81513be5, 0x6799a2e9, 0xc4dda870, 0x28a822d5, 0x0ab3d89f, 0xb7385d36, + 0x539475a9, 0xa851ee53, 0xbb90021f, 0x47ec6c57, 0xa2ff7604, 0xcc469c71, 0x9fcdc29c, 0x69dc4c9b, 0x6f2268ad, + 0x7e6703f4, 0x548bbb73, 0xe07f3e53, 0xb651744a, 0x3ee259f8, 0xe800c6c0, 0xfe5ad1d5, 0x45417f00, 0x0ef584dc, + 0x5e6fd485, 0x08b38b10, 0x0759df49, 0xa2193354, 0x9d3759dc, 0xfaa222ba, 0x41b4d379, 0xb492051e, 0x94dedbf6, + 0xfccc58f2, 0x6d2e0820, 0x77cf4a6d, 0xc8a041ec, 0x2bdcb5dc, 0x399fd1ea, 0x2c17ff16, 0x9331abcc, 0x8e4724ae, + 0x4c8df76a, 0xeae4def7, 0x657f5481, 0xb9fb831b, 0x02785b2f, 0x13ea06da, 0x1b0b37ba, 0x2adc65ab, 0x2bdb7417, + 0x32220518, 0x0d518d6c, 0x65bc5475, 0x89c25e0b, 0x0d966d3c, 0x4bb81b85, 0x351e3e61, 0x159531aa, 0x90555429, + 0xfe10ea28, 0x290c345d, 0x17618625, 0xce09b8d1, 0x4fb49e0c, 0x212d4295, 0xcc87528b, 0xe89826a2, 0xf4c96086, + 0xbf9023eb, 0x0e6f5dc2, 0x4356f6fc, 0x10f663fd, 0xa372f41e, 0x871e4d87, 0x0608432a, 0x2018e3ac, 0x4da7bee9, + 0x56522eba, 0xb5085446, 0x7fa0a8f3, 0x5496d55a, 0x9d579e6d, 0xfa50eec7, 0x51664d58, 0xe28bc26c, 0x5cd5892f, + 0x20f61dd7, 0x0f40c69c, 0xd9b086ff, 0x923a5655, 0x9f06e917, 0xe75ccddd, 0x0d699356, 0x1ca45d22, 0xa7f89d8d, + 0xac89d4af, 0xe1d8d2c1, 0x4dd55888, 0xb4abc045, 0x1dfe6842, 0xf135319a, 0x1d036b93, 0x284c368d, 0x444beafb, + 0x3d35db9a, 0x69ea6b68, 0xc1e01862, 0x5ffa5564, 0x7b045d99, 0x844da5d4, 0xc87b9cab, 0xcf96386d, 0x887e15de, + 0x7b083bad, 0xd8a653c0, 0x5eed20c2, 0x93e0f4e5, 0xe58d76d7, 0x684b1cfb, 0xe466332c, 0xb2935caa, 0xf1d1f04c, + 0x707b1efb, 0xcafbad4c, 0x8da6a06a, 0xe1911d90, 0x490bbcfb, 0xb0a59e93, 0x4d608a51, 0x84083027, 0xef89949b, + 0xc5b54a78, 0x4a4592ee, 0x9d77ac4b, 0xba1d66ca, 0x0596c09d, 0xcd341346, 0x080e904e, 0xcc0a96e5, 0xbd6a8158, + 0x297a9502, 0x85947eb0, 0x3c4f83f9, 0x66707249, 0xfeaa75b0, 0x1bec61dc, 0x0ee93654, 0x9c3d1e88, 0xc154256e, + 0x1ccfd5c0, 0xfedd5d85, 0x161bc1a1, 0x59a90abe, 0xc9fc3469, 0x9ab961e7, 0x01b92cfe, 0xdc9f5e25, 0x7cd26ccd, + 0xf79ce54c, 0x4541f78f, 0xe7eaeb7f, 0xf9ee04c4, 0x408f0a1d, 0x1cb4f28e, 0x63608e45, 0x02032cdc, 0x78207937, + 0xc152f975, 0x0cfce10c, 0xa6c4a4c3, 0x0089bd90, 0xffcf5a41, 0x8e9a623a, 0x92cf5218, 0x4eccea34, 0x15cc7120, + 0x431d69f5, 0xe634e480, 0x74d240b6, 0xdd49e3ca, 0x0dffdb4e, 0x63d1dd4e, 0x4e4288db, 0x5d376a63, 0x08e6fcc3, + 0x7e396519, 0xca5cefac, 0x03f40731, 0x93c075e9, 0x0e06961d, 0xc1414595, 0x80d314ef, 0x895161be, 0x6045fd1d, + 0x46e28568, 0x13bbe547, 0xfc101cae, 0x2bbde289, 0xf01f112f, 0xf2492294, 0x393e62be, 0xc0be3769, 0x9ba5ace8, + 0x01abef71, 0x21f91a6a, 0xb6a9bc0d, 0xe317ccfa, 0x5416b7ee, 0xf934ae6e, 0x2b5c057b, 0xc16b8e69, 0x3ea7fbd7, + 0x81d57c17, 0x5274a7e1, 0x083a8001, 0xde244d7a, 0x244a642c, 0xbdd032e7, 0xa6f8a116, 0x4d4a9479, 0x6a7ab145, + 0xd14512b3, 0xda97f066, 0xa71535cc, 0x00ae08ab, 0x95708123, 0x5e4d3143, 0x15931008, 0xbe198b16, 0x71989e75, + 0x13aea508, 0x1f570f2b, 0x38a8fac0, 0x58c0339a, 0x9321bda0, 0x56d1a4e5, 0xfd783d9f, 0x111108c0, 0x20927806, + 0xc0167d92, 0x6b9cacc9, 0x5275d540, 0xf31e3af0, 0x20facc8b, 0x7d708d50, 0xf8f02f55, 0xbe1df197, 0x7263cf37, + 0x4dbb5543, 0x15edd551, 0x3ebf1c65, 0xcc3abda4, 0xa09c9554, 0x81f09270, 0x7518d282, 0xc16c1e18, 0x1b600dd5, + 0x4509f892, 0x7e2955c6, 0x0a122a3c, 0xcdbd5426, 0x3e329f2d, 0xb5d4d1d0, 0xbe9a3a17, 0xc48a4a77, 0x1e45605a, + 0xc5fcdf3c, 0xc67cf5bb, 0x4e387d6c, 0x6a9bf867, 0x235018c8, 0xedf63e83, 0x6db027f5, 0x68537204, 0xf1cd88ba, + 0x8a706d68, 0xe41c85a7, 0xe5a92a58, 0x7f2d8260, 0x9ea1315f, 0xe58f2627, 0x756d017f, 0xc1ba198d, 0x7b9962e0, + 0xd4e31681, 0x2a5727f8, 0xc2b5e24f, 0x9146272a, 0xff6df454, 0xc78f8a19, 0x94b176be, 0xfc432a76, 0x27842cc6, + 0x65839af5, 0x54a34567, 0x8c41b69a, 0x5ebe51a0, 0xe930d933, 0x0ceb7396, 0x35074ad2, 0x4e807d3b, 0x5d1a9c05, + 0xf586edc9, 0x91b29e49, 0x79bd6b15, 0x69e4f000, 0xd581be8c, 0x3f628e22, 0x2344aef0, 0xbe96c2cd, 0x1beed762, + 0x4db9e849, 0x3ac17e4b, 0xc76dc4ec, 0x8cd36633, 0xa2293d2c, 0xf4e68c18, 0xe61a9ea7, 0xeabb1d60, 0x3fa3a01f, + 0x02e6e0e1, 0x989c55a8, 0x221c69dd, 0x955464a1, 0x561572e2, 0x03f6837a, 0x75cc39a0, 0x1954bf4c, 0x6d041349, + 0x6fb1c171, 0xd74db1f8, 0xa7eb0101, 0xab9e55c9, 0xcacc7039, 0xf0e27529, 0xfd4c1913, 0x8b6aa1ab, 0x49a62564, + 0xec2e4d68, 0x308c0a29, 0x6b6ace13, 0xd4a479f1, 0x5a43fe58, 0x96286973, 0xe98ddda1, 0x2c20335b, 0xa7c1939b, + 0xaed027e5, 0x0784ea01, 0x3e9a76ef, 0xa7136b57, 0x25b5c71f, 0x70ea9a37, 0x1151323e, 0x421d95fa, 0x64a6fb33, + 0x6a391139, 0x79f82188, 0xd370e2ca, 0x97e1248d, 0xdfb322cd, 0x731025a1, 0xdf79bb57, 0x6dbad0cc, 0x03d1ab8d, + 0x3fe1c9c5, 0x28dc7164, 0x78a35dc8, 0x1260539d, 0x31fa1455, 0x7cffa131, 0xea38859c, 0x247674ba, 0xa590cabb, + 0xc15689b7, 0xb832e662, 0x76227e69, 0xc845a6b7, 0x77c30483, 0x15a01e9a, 0x36cc2101, 0x34b9409f, 0x50e5c32f, + 0x02161015, 0xcc257629, 0xa130f02b, 0x9ac2b55b, 0xe26efdaf, 0x006dd960, 0x90177793, 0x74553260, 0x6e9b938f, + 0x134859b8, 0xbc7e7da7, 0xa6ca1091, 0xadf9f48b, 0x5ccd63b9, 0x1468ab72, 0xaec666a2, 0x44b59412, 0x1f5477ff, + 0xd46e33c4, 0x22f256a3, 0xeefc200a, 0x12a14574, 0x19d0095e, 0xdcf21322, 0xc6b37f20, 0x88356f85, 0x230297f7, + 0x31dc2314, 0xca2a517a, 0xcb5774d2, 0x2f1940b2, 0x4214db78, 0x8ab0d527, 0x2d5b1700, 0xfc4b4503, 0xb0cc02e2, + 0xcc711ae3, 0x1833a441, 0xfad7ef97, 0x3ac101a2, 0x485cb822, 0x3a0ff0e0, 0x233c1c01, 0x86db7429, 0x961b7b56, + 0x5a20c035, 0x0cb7b760, 0x88ccfca8, 0x98d7e9b6, 0x2fecf403, 0xbba6790c, 0xad9221c5, 0x79d0f2c4, 0x308f9486, + 0xc74bbda7, 0x90d618a3, 0x559c9cc3, 0x7c5b3d33, 0x4d72ecee, 0xc1b5cbd4, 0xa21409d3, 0xac36f240, 0x323239bd, + 0xf68e9a06, 0xa9e67e89, 0x625abb85, 0x0130266b, 0x26b7a7bc, 0x107ae2cb, 0x24ab42e1, 0xb4a87e5f, 0x69170485, + 0x8edccd75, 0xb662a020, 0xea546f22, 0xcd3a56df, 0xf3c25f56, 0x2887c48b, 0x8f8fdadc, 0x7860d603, 0xd7c0c0d8, + 0x12ea029c, 0xcae9da95, 0xdeef67ac, 0x82a0e8d8, 0xbe484ab8, 0xaa64fb1e, 0x0b10d28c, 0x22776651, 0x1782edd8, + 0x1f87a58d, 0x8cfb1db0, 0x7be8f149, 0x6133bebe, 0x315a7beb, 0x89584ea0, 0x59fdda42, 0x33a49506, 0x44ec2641, + 0x75fb4d7c, 0x4cfec5f4, 0xecede465, 0x955f4d2c, 0x29936dfc, 0x06a3975c, 0x60dca0ec, 0x1f4c8367, 0x9013274d, + 0x5a0a0857, 0x5beaabf9, 0x761428ae, 0x29a3a5f2, 0x1ff2db1e, 0xed0d912b, 0x36ba2690, 0xdb5913f4, 0x7502a66b, + 0xd2f33734, 0x9dc1e125, 0x5efcd9a5, 0xb1aa046a, 0x7e7e03e9, 0x6ea4967d, 0x5e67d240, 0x05359594, 0x94dbdf70, + 0xcf55377a, 0xa263dbb2, 0x72ffe269, 0x50b8fc99, 0xde4f30d8, 0x41b50dd8, 0xbfec2aba, 0x57ef5607, 0x1dab12ba, + 0xf25ab4c8, 0x4dc35652, 0x0a6bd42c, 0xa8d17963, 0x72502621, 0x3ba4a5ca, 0xdeda2eec, 0x830c4fa9, 0x98a989df, + 0x30b94411, 0xc0927ad0, 0xd0395c94, 0x356a8007, 0x4ff4cb61, 0x60c21a73, 0x98133335, 0x9d8e01e9, 0xe09f23da, + 0x808a48c0, 0xf43552cc, 0xf5259339, 0x540cb21b, 0x9de23f3f, 0xe0d0d408, 0x6cd367c4, 0x606894f0, 0x55784ffd, + 0x5ada09c0, 0x03e1c284, 0x8c211194, 0x559a3e74, 0xc4901e0c, 0xcf69f2a8, 0xbb7addc8, 0x2cbcca07, 0xcbe0c6aa, + 0x203c9ac0, 0xdf513847, 0xa97324e1, 0x36ea803e, 0xe30e3a4f, 0xbb30d08f, 0xe772d655, 0xd8caf536, 0x6e489c8d, + 0x928564b0, 0xdb0f5e2b, 0xb2a083ef, 0x8b0cf51a, 0xdae39c67, 0x631ae09a, 0xd42da44c, 0xb3065cf4, 0xdfffb927, + 0x525da3b9, 0x65f7d93e, 0x234c883c, 0x75a8cec6, 0xa577b5a5, 0xb982f1fe, 0x044c2871, 0xef08e254, 0xa0c61d4f, + 0x12666839, 0xa769ae61, 0x173f665f, 0xef8a7c70, 0x1413fe85, 0xe20e6123, 0x1b19dd92, 0xfc829f25, 0x6eaefda6, + 0x4e3f7a23, 0xa90ae367, 0x3b26a8e7, 0x708c247d, 0x592ec10c, 0xb5dcc177, 0xa64e5e18, 0x178e9ddf, 0x8492c0b9, + 0x44b22b84, 0xfc21a1b2, 0xd8b577cb, 0xff467318, 0x38240efc, 0x6d580bd0, 0x4f497313, 0x85a3a97e, 0xf824d822, + 0xcc24bba7, 0x3f699726, 0x46509af8, 0x7a152b70, 0x26c90eee, 0x4de1e940, 0xc1dbe938, 0xdb2e78f2, 0x23134dc6, + 0x59aa71df, 0xe424f7b3, 0x42265fd9, 0xc4dcf3f3, 0x98b67c69, 0xbe92e4b9, 0xb39cebd6, 0x1508b903, 0xaf76c38c, + 0x4364b0dc, 0x73356689, 0x82b9fa68, 0x667a78dd, 0x1e969980, 0x9495f30f, 0x86e2fc6a, 0x364d28d5, 0x9705fb3e, + 0x2961b970, 0x22ac210a, 0x521687e0, 0xd6943ef7, 0xcf4127e0, 0xf063afb0, 0x31fe1e69, 0x96c52012, 0x1fa76e3a, + 0xc71f159c, 0x15588dbb, 0x0597b5ab, 0xda5dd646, 0x7372cd01, 0x07fa400b, 0xcf9c8ddf, 0xf9367433, 0x2bba1497, + 0x963eb115, 0x79ee095e, 0x65a87ebb, 0x76d572fa, 0x6b147f0f, 0x7f9b74d2, 0x40ae6808, 0x6d3a018d, 0x0c363a03, + 0x6d614f06, 0xe5f9f70a, 0x74919252, 0x21cd1432, 0xab258540, 0x8269657e, 0x114b7da0, 0x26864331, 0x78f30d1a, + 0x9615e3ae, 0xc72a2f16, 0x47678145, 0x27652c9b, 0x0d1ff3ba, 0x7b095d87, 0x5fca6540, 0xdb0377cd, 0x2e496f6b, + 0x05022370, 0xeb02f548, 0x090b0e6b, 0xa92481cd, 0x2e6fabf0, 0x3c24d542, 0xb74154a6, 0x1b64ccfa, 0x15940ca4, + 0xff3cb1ca, 0x0c3d4d16, 0x1a4649c8, 0x3346b939, 0xee81e84d, 0x51f248c3, 0x6c2e7591, 0xb026adb8, 0x8a42761c, + 0x7e07613e, 0xa5898739, 0xa8fba734, 0xae3ea3a8, 0x5d2eabaf, 0xb7d1ea4b, 0x7582e5e2, 0x133aa9a9, 0x2bb82470, + 0xa4ed5330, 0x192cebf1, 0x554fcf0d, 0x469d889a, 0xcf70f9b7, 0x4595effc, 0xae93bd8c, 0xd56d3aeb, 0x4dc858c2, + 0x3109c184, 0x0a181eac, 0xf9c2bd37, 0xb6bc9bca, 0x7fa9e6ef, 0xfd456f4d, 0x7573e8e2, 0x1517e1c8, 0xf227af18, + 0x8e35ba3a, 0x762fc384, 0xdf3c90ca, 0xbc19df4b, 0xcc686d84, 0x2bfce88b, 0x04bc5e72, 0x73969861, 0xf6cdb840, + 0x92e4531b, 0xea05cb4b, 0xce3d2f11, 0x8eed290d, 0x01c4a256, 0x315678ed, 0xb4f6d134, 0x40742fe2, 0x35d89c75, + 0xfcefe6ef, 0x9c971da6, 0x83678717, 0x5f2852a9, 0x0bed5a50, 0xb6c9ac4b, 0xd0141f87, 0xd69513ee, 0xccd181a5, + 0x98f324d6, 0x914bd39c, 0xd7ad248b, 0x3cfe9d27, 0x493c1226, 0x56c59224, 0x3ce8d473, 0xf1394593, 0x88e6d852, + 0xf8e93abb, 0xe56f4f9f, 0xd90c86ef, 0x9bffa887, 0xf4de45db, 0x00ca1d6e, 0xd617dc25, 0xa10b0b48, 0x988f02e6, + 0x66c4be94, 0x6ca01cf4, 0x0ebfba54, 0x5e21a2a9, 0xc895766b, 0x14572069, 0x306aadbb, 0xb2f9e5ac, 0x15524542, + 0x4e3e6e1a, 0x0f214e80, 0xe8c9d23f, 0x3693579c, 0xdfe6f607, 0x37d6dafd, 0xe0680207, 0xb1a2cc95, 0xbeb0c346, + 0x3d3361f9, 0x02be1acb, 0xeb4469a9, 0x9cd3ed3d, 0x189e8c6e, 0x496620c2, 0xe9d74db4, 0x48e1f1e4, 0xcaf0ef36, + 0x18a9e6e8, 0xe206bfbd, 0xfe996164, 0xcfa64114, 0xc2996414, 0x8bf48fa0, 0x6b996b21, 0xee57bc0f, 0x5ca8bdc0, + 0x1b152045, 0x0155abab, 0x6b16577b, 0x19dda4dc, 0xe5f85242, 0xde147d3a, 0x12353fef, 0xb00a2813, 0x3d9e276b, + 0xbe9bf115, 0x8417d8e0, 0xa3052474, 0xe55daf6f, 0x1d1ed5eb, 0xe6992865, 0xeaa302f3, 0x5a927744, 0xd1d41c43, + 0xc84dda77, 0x91e44c6a, 0xe1d89c80, 0x394a6431, 0x1cfa0d5f, 0xa1262554, 0x4733d02d, 0xadf36cd0, 0xfacfc7d0, + 0x73405a67, 0x95ecb49c, 0x83c96da1, 0x0f5148e8, 0x4f4f51c9, 0x48cb8a51, 0x64da35ee, 0x17b28426, 0x95510efe, + 0x1ac0c255, 0x465cbb67, 0x640ce212, 0x59236630, 0x28f6647e, 0x18b76e18, 0x8a7c9d5d, 0x7c36f1b8, 0x35201640, + 0x41c66f61, 0xc98a2c72, 0x4163d5d0, 0xa24e664a, 0x74d24250, 0x8041484d, 0xa565473e, 0xbc7e62f0, 0x4bd6cb61, + 0x78bcae51, 0x3b4ea36c, 0x1611212a, 0x020742eb, 0x857afb26, 0xb0e6afee, 0xff6046c7, 0xcdbc50ef, 0x6e54cc29, + 0x4e597671, 0x73a7e851, 0x1b283b09, 0x2fb69f2f, 0x86bf1954, 0xdfaf0794, 0x0f769390, 0x3cb81796, 0xb92554ed, + 0x20a6dc8c, 0x9dbb2838, 0x9d3adc48, 0x5adca2fd, 0x46ca3724, 0xcc4bf8d0, 0x7ea5e780, 0x5966b2af, 0x275d5266, + 0xb0907ece, 0xbc209571, 0x871817b9, 0x7952d38c, 0xb7da09aa, 0x57a85073, 0xc49deee2, 0xd17ca291, 0x6d813442, + 0x1a8cf23b, 0xe174f57c, 0x2b5d1aeb, 0x21606bd0, 0x5f920a66, 0xab961fa7, 0x39239368, 0xcd948aaf, 0x2ab89f11, + 0x308bafd8, 0x416d261c, 0x41e38834, 0x4d50c12d, 0xb09a2ba3, 0xfc358cd1, 0x737c6f96, 0xca4d6749, 0xe2802659, + 0xd923490b, 0xc0ae6f1d, 0x39f9c635, 0x2440ebe8, 0x5e2563c2, 0xa39d63dd, 0x33ff2557, 0x0eacdf91, 0xefb92e11, + 0x89a87dfa, 0xfdebed45, 0x7c32b3a8, 0xc8d412a5, 0x1976d74d, 0xa7071b43, 0x2f6be137, 0x9b06c49e, 0x76ea165e, + 0x4eed428c, 0x352e940c, 0x52783be3, 0xdfbd68f4, 0xe03ffe89, 0x3dcaf3e8, 0xd5ef64fc, 0xae5e91c7, 0x7d08c9a3, + 0x1ccd8d22, 0x75eec3fe, 0x9ca32a9a, 0x27e8e01f, 0xfb269abe, 0x05efb437, 0x2f29abf9, 0x7e44d88f, 0x16562753, + 0xb2445dd6, 0x71ead8bb, 0x99caed46, 0x535345d9, 0xc3755864, 0x37314ed1, 0x991c0d3b, 0x86bf9cdf, 0xfbb2c7b1, + 0x8f479f66, 0x7be3784f, 0xd0ab006a, 0xb691e538, 0xe0617acc, 0xf049ecb3, 0x20ec27c3, 0x665b3336, 0x2717d132, + 0x1f35217c, 0xa1fe096f, 0xa1625e7d, 0x0a6c00d0, 0x183cc730, 0xb577fb35, 0xb5f6f11a, 0xf474f59b, 0x9bf0b73d, + 0x7ae9b66a, 0x434b215a, 0x565808b3, 0x082fbfa9, 0xb9f159fe, 0x7d3a86b4, 0xbf7be3c1, 0xcd2a4ad0, 0xe36f7889, + 0xb3270676, 0x54290af5, 0xd90dff13, 0xb375f1db, 0x01f3425c, 0x5c2acf7f, 0x0e7bf546, 0x0f00e862, 0x53e5e759, + 0x41d5b3bf, 0x9fcd06e0, 0x70758ebe, 0x0478792a, 0x9e1c1f99, 0xe4706b29, 0xd5f16811, 0xd5991551, 0xddd66554, + 0x8ca6a661, 0x40947195, 0x5b3315a6, 0x72b3db01, 0x53873d07, 0x1dcbf8e3, 0x43ac048f, 0x29edb51f, 0xa62d4dc6, + 0x6a100315, 0x26dbffb8, 0xf6d7356f, 0x1d4c596d, 0x7e19ace2, 0x0b2f9fe6, 0x27c753b8, 0xcb20706b, 0x68e253e8, + 0xa3de2ece, 0x963d5033, 0x9c06604d, 0xd7b25f0a, 0xc975cf37, 0x2aa8b464, 0x3b088e7b, 0xeb12a435, 0x98a8ce35, + 0xe506b86b, 0xeb1783fe, 0x620f3dd0, 0x1df3ce21, 0x7bb0fa8e, 0x147a57a3, 0xb25ef3f5, 0x6bbcafe7, 0x7503f7ed, + 0xf8ab19db, 0xe462f6d5, 0x27b2855f, 0x6c97b13d, 0xa85ab122, 0x465ed81e, 0x9d0f5a0e, 0x14dbcfd9, 0x1ff12788, + 0xbb241c6b, 0x71724b04, 0xb7b2c717, 0xb6ffd04f, 0xa7095b96, 0x0f5bc791, 0x9fed708f, 0x068f0869, 0xb7032fad, + 0xcaa223ce, 0x239a2c9a, 0x900b09c8, 0x67712709, 0xf5f205ff, 0x30d84f20, 0xbcda3ee1, 0x536fbb5a, 0x1b7377be, + 0x29cd330c, 0x6f671992, 0xf2a81a52, 0x5a81ceda, 0x574d1b8b, 0xadd19a03, 0x9126038b, 0xb065064c, 0x8dd6ae84, + 0xa75a36ee, 0x3261d885, 0x7a4d1f94, 0xfc29d2c4, 0xb47ebd88, 0x5423079e, 0x3971fffa, 0x0a8ffc97, 0xc2daac6d, + 0x531a5163, 0xf3cebbe9, 0x8c83fedd, 0xd11ddec3, 0xeab9a28d, 0x2a6a19d5, 0xb31c018e, 0x685a9fd3, 0x5bcba15c, + 0xca68d72a, 0xb95a856f, 0xc978a6de, 0x5c9e6065, 0x7519a378, 0xf21fb939, 0xbf511065, 0x4712c392, 0x8cb04861, + 0xc9ed9a80, 0x4b7d8fae, 0x80899721, 0xdfd39d4a, 0xa0314f50, 0x382bfe08, 0xa93317d5, 0x1c18b644, 0x133984ab, + 0xf788a652, 0x9bab727f, 0xf2ea5762, 0x7630b69d, 0x06cceba7, 0xab6c9700, 0x4ed5bfeb, 0xa423ca0d, 0x8a0c4b61, + 0x70f3a4d7, 0x4f3c6bd5, 0x644c8fba, 0xaf8f9e61, 0xb0c55cfd, 0x5ed301d7, 0xff820899, 0xb22f92a2, 0xae8f8ed8, + 0x8ebd3b90, 0x02c974a0, 0xed6396d1, 0x0b08c816, 0x32469aa1, 0xdef829c9, 0xfacd4364, 0xb68c88dd, 0x4716f7d4, + 0x641409c1, 0xe896d382, 0x6a24949a, 0xe1094956, 0x6ad76fc6, 0x2c22cde9, 0xdc122ac5, 0xa43c5c6c, 0x3febcd1a, + 0x2726bc4f, 0x330a1352, 0xbe0f2796, 0x3f9f2bbe, 0x1dbef733, 0xf26c425b, 0xe643f340, 0xe2d9421e, 0xcf1e4605, + 0x369c8198, 0xb1b3f1dc, 0x16e3dc24, 0x74ff22a3, 0xb5ef0eb9, 0x208eb731, 0xad146c17, 0xbe908e18, 0x6ad90d65, + 0x3f0360ca, 0xff7cb960, 0x7e237b69, 0xa5993381, 0x40dc3378, 0xa9f926bc, 0xe9a08592, 0xb6d67454, 0x12f34cee, + 0xd3dbd2e9, 0xce4fc54e, 0x717f8017, 0x3dc897df, 0x44726a0e, 0x4623e9c2, 0xcc34a551, 0x1a5ac8a6, 0xdd826ece, + 0x89d96dee, 0xfd22ec01, 0xd5029daa, 0x651d28d4, 0x773c4120, 0x6815acc2, 0x74e54091, 0xa07bcb07, 0x9b85ff66, + 0xc98d9038, 0xa66021d7, 0xffacb64c, 0x400ab073, 0x32c8481e, 0x61ceba25, 0x888ba41e, 0x3403fe14, 0x427ef930, + 0x7189018b, 0xa6c4b9b9, 0x6bc558d4, 0x8955d36a, 0x8b87f4c7, 0x05f685f4, 0x0a51fc53, 0xef258c60, 0x67375241, + 0xd98370c1, 0x4df15cce, 0xba259249, 0x38526373, 0x0c0c3420, 0x88a6fc21, 0xf5a90ddf, 0x89c598d7, 0x9887760b, + 0xc30213a7, 0x0452f882, 0x5018414a, 0x5b64258e, 0xaecabb82, 0x23753834, 0xcff0bfb3, 0xb0043146, 0x28655029, + 0x3f5cf8eb, 0x158a4cec, 0x9577ed02, 0x8eb772f2, 0x63c9bde4, 0x56e48130, 0x14cc7b50, 0x57332604, 0x69605ae9, + 0x02c2313d, 0xbb722ee6, 0x27cd4318, 0x34d668a0, 0xdec8b795, 0x10a311a9, 0x3ccc3a43, 0xab6fa4ad, 0x102286fb, + 0x94657c32, 0x3f6bb6d6, 0x751527d9, 0xd110b38d, 0x95b3337a, 0x79723903, 0x9d39d963, 0xbb0d8eed, 0x650356c7, + 0x64e30e72, 0x5be7fd20, 0x05b6acfa, 0x06d6e819, 0x852e1d1d, 0xcab58beb, 0x28f0c491, 0x3b8b792e, 0x0cf39c5d, + 0x6099e243, 0x0b4bbd32, 0xa6954d50, 0x2b526e8e, 0x0ca8ace9, 0x9b566e3c, 0x50e8ad6d, 0x00115c02, 0xcaf6deac, + 0xcbc5be23, 0x21d54555, 0x121fb8ff, 0x7f093fcb, 0x63e62027, 0xe8e178ab, 0x2dccb008, 0x996a0993, 0x84cfdaa6, + 0xd591875f, 0x68c8ca94, 0x085660a2, 0xd93a97f9, 0x21d9c16e, 0x1c17eab9, 0x2095f8b9, 0xbf737281, 0xc2368d28, + 0x93d66a8e, 0x7a45a734, 0x35cc1cae, 0xb45750f0, 0xd5a0851b, 0xe65acc15, 0x5c5a0a80, 0xd8fb0564, 0x48cd4ab7, + 0x2aa5d018, 0x3db6dd13, 0x0a2c18c5, 0x752bef1b, 0x9c4b722d, 0x84d6cb7c, 0x97cdba0c, 0x0a097f80, 0x98ce4f30, + 0xa6fb4bfa, 0x37d3a580, 0x8e7dcfb9, 0xfb69b496, 0x18096a8a, 0x2dbec39c, 0x6cc6dcd5, 0x90ac7c40, 0x8efed80b, + 0xa52fe1c7, 0x1e5f598c, 0xbc4a8679, 0xebe3211a, 0x58f33779, 0x416ddc30, 0x9917ba43, 0xe55cec88, 0x2fe794df, + 0xb6aa34da, 0xba8f112e, 0x30190deb, 0xa7e7e131, 0x171a84b3, 0x82a066ce, 0xa0d1e4d9, 0x438bcb10, 0xb4583015, + 0xfdecdd0b, 0x196086c3, 0x7675cec8, 0xc43cfdbd, 0x04f059bf, 0x840ff561, 0x73b064c3, 0xb22ea0ca, 0x965f12c9, + 0x2b0fd40e, 0x29aa70b3, 0x17d8f1ee, 0x47a40e38, 0x9cddc307, 0x818cd323, 0x907a56e7, 0x764e80aa, 0xeb8e3b1c, + 0xc0c7b6f9, 0x0a06963e, 0x9720c912, 0xe09fd11d, 0x8b2ca503, 0x9e24cb01, 0x1b3ff549, 0xebdae0f4, 0x0094a44b, + 0x21c42a2a, 0x07055bde, 0x6c2b4b8d, 0xb2211186, 0x511fc6ca, 0xad4a153f, 0x56bbb723, 0xb0b3d05c, 0xef93cb5c, + 0xf9d53772, 0x0d01ca81, 0x94081e15, 0xe670339a, 0x904f0d81, 0xb16b16cd, 0x03314aee, 0xd32845cc, 0x4d64a1a1, + 0xa1d63b7d, 0xdc139d29, 0x456bdded, 0xab061bab, 0xd4539ea7, 0xe623c5d2, 0xd5c213d0, 0x70c3534a, 0xc4158767, + 0x84465436, 0x5e8637c7, 0x688231e7, 0x91010983, 0xbfdd9ea9, 0x3cb2a779, 0x8ce708cc, 0x6965b801, 0xe7b03ffc, + 0xfe2834bb, 0xbc178a03, 0x1a2018a5, 0x5157549b, 0xa4be32d9, 0x53eac863, 0x33311917, 0x6b198a92, 0xf6b79601, + 0xe8041b84, 0x64414719, 0x31289fc6, 0xe8aef24b, 0x9a5d0a58, 0xac774136, 0x87d91e1b, 0xf91d9079, 0xdbf6c120, + 0x0517b9c9, 0x1eda8bd2, 0xbc7efa70, 0xe4dc1276, 0x3455bfac, 0x9d4b24b9, 0x5fbec86b, 0x086460ea, 0x516d7d1f, + 0xe334ab38, 0xbdeffbf7, 0x7a445e92, +}; + +#endif // LR11XX_FW_H diff --git a/src/modules/LR11x0/firmware/lr1120_transceiver_0102.h b/src/modules/LR11x0/firmware/lr1120_transceiver_0102.h new file mode 100644 index 0000000000..386b5262f2 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1120_transceiver_0102.h @@ -0,0 +1,6890 @@ +/*! + * \file lr1120_transceiver_0102.h + * + * \brief Firmware transceiver version 0x0102 for LR1120 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0102 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1120_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[LR11XX_FIRMWARE_IMAGE_SIZE] = { + 0xd4f4f892, 0x4f88d2e8, 0x355f8ea3, 0xe9ee2cf1, 0xd6578539, 0x6b0e9cad, 0x6e5daf47, 0xdfdee0ca, 0x9ca5f626, + 0x0f774b57, 0xabb97fd1, 0xffe358a1, 0xd4bfca48, 0x7ea0c5a2, 0x4f7a3fa5, 0x1ad6e64a, 0x063efa4e, 0x9e148f23, + 0x88a79dbe, 0xe78e77c5, 0x7c196e6a, 0x5dbb9ba9, 0xc547467e, 0x8fdc62a6, 0x3b74ef4e, 0xe53bad91, 0xed898bfe, + 0x768a496a, 0x05d77b4a, 0xe652440f, 0x080cd49d, 0xd29e7c1e, 0x13b1fe3f, 0xb5299ae5, 0x7a042b8d, 0x1e2131ea, + 0x8da4d60e, 0x298c18c7, 0xa4670cdf, 0x7923db13, 0x4b4b3cd5, 0x84ea99ed, 0xe3885ce4, 0x0933b2a0, 0xfba6fc5e, + 0x41b33bdb, 0x259e276b, 0x48693108, 0x73ac878d, 0x3854670f, 0x795814d1, 0xfca3030a, 0x7752eba6, 0x8066eb91, + 0x69514574, 0x8f71ee40, 0x9e648b56, 0x7d39f506, 0x1a1fff6f, 0xae25a599, 0xad5601b9, 0x6223cfa1, 0xc5c703c1, + 0x5ac82c43, 0x1129209e, 0x969b03b3, 0xdd649bad, 0x4f4d0166, 0x88158ed3, 0x4387ecb8, 0xfc076a98, 0x04ea1831, + 0x98675914, 0xe13bb056, 0x8d1693d7, 0x6bcca533, 0xc228a11f, 0x63367162, 0xa8621def, 0x5dcd9195, 0x7828c45e, + 0xd0a4b017, 0x4b221c4c, 0x632cb0e3, 0xe22d0f09, 0x3a132748, 0x933ebbd1, 0x7cba189a, 0x2e8766c0, 0x63f6c43c, + 0x6f2e92ae, 0x49a9cdac, 0x438ce833, 0x142555f2, 0xea141ce7, 0xac365257, 0xa669bf71, 0x6a0777e1, 0x9b916104, + 0xd4edff2a, 0x7d922eae, 0xda0f0328, 0xbb5f40c2, 0x44597435, 0xf24e19cd, 0xb30f90e8, 0x941fedc6, 0xb53a3a46, + 0x6dfdd387, 0xdaefacb5, 0xa43badbe, 0xa6e7a8ed, 0xd9823aeb, 0x343dfe6e, 0x788593c2, 0xd12a6997, 0x4712e94a, + 0x1ab96bde, 0x6ace1ec2, 0xe950b862, 0x85e5bc12, 0x8da9a977, 0x6f7d9bd8, 0x65cbb8fd, 0xde2f9bed, 0xb9a3eb15, + 0xa0cb8379, 0xb4eb2f0b, 0xa9e5652f, 0x993f43fe, 0xc7a562b3, 0xece5fe60, 0xd224cc43, 0x7eb57be7, 0x9d8434eb, + 0x3336a65d, 0x92afd3ae, 0xe6e419db, 0x7ae33b2d, 0x5b5cd830, 0xa368debc, 0x41cc6ca2, 0x6f70007a, 0x13bead48, + 0xe5386785, 0x872c3378, 0x2f566524, 0x71876121, 0xe7ac9007, 0x4637d3c7, 0x43b8d432, 0x81dba23c, 0x469c6feb, + 0x72305fd1, 0x47cdcb6f, 0x57f87755, 0x1d648ce4, 0x214045f6, 0x763f02d5, 0x1c7f4023, 0xf39ded6b, 0xc8adf58d, + 0x7d4016ba, 0xb4747831, 0x76fe2f74, 0xb2b58c64, 0x134bffd5, 0xc82b43c0, 0x23ed15e7, 0x4052c917, 0xb0011b3c, + 0x395bfbc4, 0xe0740cf7, 0xfd0deb2b, 0xe6dc7ddb, 0x0836cc04, 0x4f29785d, 0x3ff43cf1, 0x971aff29, 0x50de2da9, + 0x2ab56039, 0x2134ae79, 0xe69ecfea, 0x24462889, 0xbbabd4ad, 0x4f672caa, 0xf4a4f1a7, 0xb8c88bff, 0x1e3dca1c, + 0x7942d463, 0x0b892fdc, 0xe7d18e02, 0xeb644723, 0x4aedee12, 0xa127aa1e, 0xc8c2f137, 0x28dc14a5, 0x9db0e6d2, + 0x3afff107, 0x042937f8, 0x527f23f0, 0x929aeecc, 0x4b3ccafc, 0xc131e0b0, 0x1ae5f9ad, 0xb37265d7, 0x021bf23c, + 0xf462c743, 0xce6268e2, 0xe9fedc5d, 0x30bdbd6c, 0x6fb0ed16, 0x54c515c5, 0xd571a231, 0xae4e4ea6, 0x49248fec, + 0xc197af13, 0x5a8b3766, 0x8c93fbf4, 0x57336439, 0x0e5f41c0, 0xf9428bc9, 0xff150af5, 0x4fa7af48, 0x3e347a7c, + 0xf70af0c0, 0x3899bfea, 0x0fc407ac, 0x1c056456, 0x6bf52087, 0x46082213, 0xaa134237, 0x14c6efa3, 0x84fa0054, + 0x5c8b3b44, 0x1f4ee290, 0x2edc873e, 0xe382af31, 0xc7f996df, 0x12ddda56, 0x8202820b, 0xcf704fef, 0x2b496b7d, + 0x6b997867, 0xf40e4348, 0x907160dd, 0xb0fbdc97, 0xbb260690, 0xcc3ba462, 0xa244a1c5, 0x5e111c74, 0x020d04bc, + 0x0be4bbe7, 0xdc2da3d8, 0xd867bcb3, 0xad2d0560, 0x259aea0c, 0x4e4be421, 0xcc17c564, 0xa34cdda3, 0xac027a1f, + 0x549804a6, 0x9055214c, 0xc0b7c726, 0x8596a406, 0x8315ef16, 0x3f9adc46, 0x42f22844, 0xb6159859, 0xf59141b5, + 0x798f3c96, 0x2d8d1696, 0xd1fe257c, 0x27ab561f, 0xd431265e, 0x16cc3292, 0x62f8dcac, 0x4b4526f8, 0x9bd16d12, + 0xe34e7beb, 0xed0943db, 0x9ffb3be1, 0xd5ab4a67, 0x3cf8abb9, 0x55b4866e, 0xbe859688, 0x7a6818b7, 0xa5aea79d, + 0x04db2be2, 0xc40e9830, 0x30881c38, 0xbca38ec7, 0x36d19546, 0x8fe2b09e, 0xed457756, 0xb63c59c0, 0x92d02921, + 0xc00d7cd9, 0x57c5a7e0, 0x0d598163, 0x01b8bf14, 0x70ddc3c5, 0xe26536ab, 0x902d3acc, 0x1e1b93cf, 0xb56d0152, + 0x363a9544, 0x7c8446d3, 0x91a8dd50, 0x47961349, 0x30ad2e7c, 0x276c2ca5, 0x7b8a5c92, 0x1382cf02, 0xc09174f8, + 0xd33189c2, 0xb3efe4a9, 0x6b96291b, 0xf7c4498c, 0xfffd54e7, 0x18f43d96, 0xb785606f, 0xa0cbfed7, 0x838ae501, + 0xdc753f86, 0xf1a762af, 0xfdf09b5c, 0x4a1e69be, 0xea211376, 0x44a1305b, 0x9bf8d517, 0xafe04a8a, 0x0470025a, + 0x676d2733, 0xf71702b4, 0x202d079f, 0x3df281c3, 0x096acfe2, 0xde317ec2, 0x5420eced, 0xcb556163, 0x202842c4, + 0xe1b5aae7, 0x3d1eb5c8, 0xb4dc4f24, 0x647d11c8, 0x6675a9ab, 0x0adf134b, 0x509ea2dc, 0xc568b0bc, 0x1d784914, + 0xa6991abc, 0x60d0f6f7, 0x87351d51, 0x8d9600ce, 0x5dfd7301, 0xac08bb32, 0x57e0fc51, 0xd3948f6c, 0xc9b79658, + 0xed8c0cec, 0xc85499b8, 0x721ae1f7, 0xdeb8fe6b, 0x77bf8afb, 0x2db003b6, 0x0868e6f7, 0x8ae0b374, 0xcfbb85e9, + 0x7924ae69, 0xc5ea6e9e, 0x1aae3103, 0x88388483, 0x0432bf4f, 0x33ddc081, 0x5eb52433, 0xe2b0a6c3, 0x9df2318d, + 0xca023f95, 0xac8ad305, 0x3e66bf32, 0x52010005, 0x29a97259, 0xcd25c197, 0x93e8b5b7, 0x1ee22d25, 0x05e15b08, + 0x3a224875, 0x39c33dcb, 0xa416acc9, 0xf1ff03b2, 0xf7c39a36, 0x344d25b8, 0xbac0ef42, 0x76de37d1, 0x1e6755a7, + 0x1caa5a70, 0x6853c6d6, 0x03901388, 0x242386e1, 0xa6cea4f2, 0x7addaf5e, 0x87f2ddc4, 0xdac2b79f, 0x19ce17a9, + 0xc6b03777, 0x59df40c7, 0xbabe1e07, 0x7c42b47a, 0xf7eb8b9f, 0x51a25bb9, 0x92c52150, 0x91b8d168, 0xd451d7dd, + 0x36a95937, 0xb5254e3a, 0x513589b8, 0xcd2ff1a4, 0xa97af12b, 0xe98331d2, 0xe224d244, 0x273654ae, 0xc40d0d0f, + 0x448cf57c, 0xb6228d5d, 0xe71e61f2, 0xf66ea951, 0x7cb73a1c, 0xf85e9b95, 0x672f0bac, 0x73b71222, 0x218247da, + 0x5b9d2736, 0x76f4b7b5, 0x5ed069f5, 0xbf2f285b, 0x17f97d96, 0xd7422153, 0x58f78cfe, 0xc44978bd, 0xfb2dbcac, + 0xc55554c8, 0x33db2de0, 0x27138275, 0x30ed81f1, 0x365bd2f0, 0x014d661c, 0xd871e11b, 0x72bb4f2a, 0x050e3d58, + 0x6344c276, 0x01bb83eb, 0x313a7331, 0xac7ebd0f, 0xfd82e0ae, 0xf537a0b9, 0x4372d84b, 0xe7c792e7, 0xf52d1bd0, + 0xd7b3a8b9, 0xf2a458e1, 0x93e16627, 0x1fa0741a, 0x0723a805, 0xe8fe0219, 0xc4a2d136, 0xc30c9249, 0x74606dc3, + 0xdd8084aa, 0xbdbb5428, 0xa7157d7f, 0xcf6a6d5c, 0x4ca2885e, 0xba367576, 0x8d266262, 0x2d6eddc7, 0xda6ebd6c, + 0x23f561de, 0xab7116bc, 0x7b4852ea, 0x22efa84f, 0x76aec382, 0xec99b02d, 0xdc9227b7, 0x334f9118, 0x0bdfa4b4, + 0xd33b2fc8, 0xb3e6eea2, 0x06b513f0, 0x6c0aff4d, 0x438eb5ca, 0xa7ca6829, 0xb5c0e9f8, 0x77d1b70d, 0x52d44986, + 0xf7b1b4e8, 0x470f6be4, 0xb233bf17, 0x6cedd356, 0x21e9a8c8, 0x90f2f7e9, 0x55136998, 0x57508489, 0x292c2ecc, + 0x702993e8, 0xfe2d8ea3, 0x76335aec, 0xf6138437, 0x9c1062db, 0x79559f01, 0x568a17d3, 0xc77b806f, 0xdeb0326c, + 0xedb67939, 0xb527c477, 0x2f392f8f, 0x507b0a17, 0x0b3adbb1, 0x3891a25d, 0x8573b028, 0xc6229427, 0xb266fcca, + 0xaa58ebb8, 0x0044c981, 0x9db57156, 0xe41d8bea, 0x678f9d81, 0x922ebc4a, 0xc8b984a7, 0x66a58fb1, 0x47a6305d, + 0xf9a00593, 0x313f9988, 0x0fb4a481, 0xd2b05e6e, 0xee21f927, 0x9d08fc52, 0xa592b5d6, 0xc2bc670e, 0x0a6cdbc9, + 0x94587152, 0x8dcda718, 0x40925986, 0xb66e0d2a, 0xdbf3cfa2, 0x56430f39, 0x4636bb3f, 0x936530cf, 0xdfe0b9f1, + 0xb993796b, 0x87257eb0, 0xa60963c4, 0xd1e74578, 0xd9df2cad, 0x43c97804, 0x167251c5, 0x5387fc5b, 0x17b0c10f, + 0xaaeb7490, 0x77bddd09, 0x9f33b9e3, 0x4bac5237, 0xbf236266, 0x74683669, 0x43f11f0f, 0x6ade53e0, 0x192369ad, + 0x59f77002, 0xfac44180, 0x2953e44d, 0x1fdb114e, 0xf669889b, 0x2b61acc9, 0xe4352267, 0xdfb7b4e4, 0x761b8ee1, + 0x0acc7b2e, 0x3b92007d, 0xb228ba02, 0xe4c4d50d, 0x647b4812, 0x47821f20, 0x27b3d6da, 0xae98df94, 0xfee4df50, + 0xfe499b01, 0xb3e773e9, 0x358e60dc, 0x421a877d, 0xf26d1736, 0x29c76b5d, 0x0de3e4f9, 0xcff1ae74, 0xec735e1d, + 0x77b5ea15, 0x9c56eb26, 0x652c9bf3, 0x54f38e8c, 0xeea8654e, 0x0ac0fbbe, 0x016a2078, 0x04d1498d, 0x2ddef79e, + 0x9a3c3f3e, 0xbedc5b3a, 0xb1d8e12c, 0x565cd3e1, 0xa7572f0d, 0xc3b6827f, 0xe54d56b6, 0x2d0fd02c, 0x94f1707f, + 0x8d778787, 0x773a0350, 0x62f1c2f7, 0x38fccc2d, 0x153f0aba, 0xe9ccfdae, 0x77978286, 0x2e9c2382, 0x5ab40377, + 0x9f0340d9, 0xcb5c31d9, 0x8af6afa3, 0xbf61fb2c, 0x5b207e5f, 0xb9aef3e1, 0x19888db8, 0xd484eb05, 0x9b93b0b5, + 0xa1c56680, 0x36dcd925, 0x49927465, 0x2829ca2a, 0x758366b0, 0xd03fbb63, 0x1d6b1283, 0x24b65a95, 0x196d07ad, + 0xdd29cabd, 0x1aafbb2b, 0x8da9f4ae, 0x50cb58d4, 0xb5076573, 0xe9e4afdb, 0x38e565fe, 0x9aa4d6a1, 0x0d79199d, + 0x7a122361, 0xcea2ac31, 0xa28722e8, 0x9a66ddde, 0x7c105026, 0x905d0d87, 0x375c81dc, 0x0793854c, 0xc47a14b4, + 0xdbca2756, 0xb86da3b9, 0x695a14dd, 0xabab15fd, 0xa3955050, 0xae7d8ff4, 0xb5edd9f4, 0x9cca1c50, 0x84a8f5c8, + 0x1553511d, 0xf0aadf07, 0x92f7081a, 0xcd550682, 0x042d9acc, 0xc8a6d807, 0x6629a7fa, 0xa80169c2, 0x1a94c68a, + 0x7d9a3885, 0x6c3f80fe, 0xb1fdffb4, 0x20ea5bad, 0xa6ed1857, 0x5cca96f0, 0x0cf235df, 0x5355eb1d, 0x778c2809, + 0xf678abae, 0x02a841fc, 0x99f74867, 0x835bf54d, 0xc38b9dc9, 0x1b0936b9, 0x0b15cdbd, 0xb2d79182, 0xb8a52cd7, + 0x1bb8406f, 0x621c1f0e, 0x33e0eba7, 0x2afa47ab, 0xa5116915, 0x7b98f6f7, 0x5e6355fd, 0xd692018d, 0xfda2b7b7, + 0xdd8b1a9d, 0xe5bfc9ba, 0xef1f5adc, 0xe06ad7bb, 0xaf620d0b, 0x947198b9, 0x8cd5edc7, 0xca7391a7, 0xdfcee062, + 0xf849934d, 0xd8acb4ba, 0xcbb13d3e, 0x60777893, 0x59481560, 0x4c3e3d2a, 0xc37185c2, 0x62d406a7, 0x5ac51db0, + 0x48c0d015, 0x34c369d6, 0xce939010, 0x53745749, 0xf6448e0d, 0x54ac4974, 0x9671f8f1, 0x6d0aeec8, 0xe2bdaa99, + 0x800777c0, 0x06056028, 0x90b7f459, 0x9fc8daa5, 0x63de230c, 0x4922abca, 0xd49f0606, 0x4a31f9a3, 0xf7b43224, + 0x5bfa1717, 0x0c06a0fe, 0xd72b95c3, 0x5ef6c224, 0x9ee4bd11, 0x369b02e8, 0xfe2668fe, 0x3c03dbcd, 0xd73abf6d, + 0x443463eb, 0x7dd7a249, 0x7ef30a16, 0xd067f186, 0x6e687799, 0x1ff311e2, 0x9aaf257f, 0x024ddd28, 0x066f5fc6, + 0x54b5b3e1, 0xffec6a78, 0x3877758c, 0x037c9315, 0x7fe61cf5, 0x05b9a1a2, 0x17147b19, 0x03adf5f9, 0xcba1cf52, + 0x64f5d1d7, 0xde9059ef, 0x6b03a677, 0x10179c2b, 0x3c2aad34, 0x1f17db04, 0xc0fc820c, 0x426d9530, 0x2afc4500, + 0x4626337a, 0xd979ce23, 0xef48927e, 0xf3db2f86, 0xc025c9c2, 0xc7e280e0, 0x7ed91650, 0x0caf69af, 0x87326780, + 0x7c516316, 0x3f2d12f8, 0xf41a88d9, 0x2c097836, 0x8a031626, 0xca539478, 0x49287a80, 0x23ac4019, 0xf5bc30ab, + 0xf178ef00, 0x2047b5d0, 0xacc55587, 0xb15100c7, 0x4b2d83bf, 0x32aa65ea, 0xd6d8b524, 0x0ad4a4dc, 0xa0f153c1, + 0x29a87ab7, 0xe14f6be1, 0x62d398d9, 0xd182c464, 0xfb8295b5, 0xe2b0e739, 0xadf43c97, 0x39b165d7, 0x287913e9, + 0xe375cda3, 0x5d01d073, 0x63da4cfc, 0xd8d26d4d, 0xf2e6ceed, 0x1d45bfe2, 0x6967beba, 0x902e5b0b, 0x375e0fe8, + 0xf7cbf5e8, 0x690bad52, 0x2b0d570c, 0x4830d9fd, 0x501344b6, 0xc6ab2f86, 0x67b12ea7, 0x1b85bf19, 0xeb8470a6, + 0x5ffd0d9c, 0x54bc625c, 0xf312086d, 0x13630775, 0x969b114b, 0x04b45c1f, 0xdb746b87, 0xa9fe4947, 0xa3bce045, + 0xa848992c, 0x69f751c2, 0xc8c01189, 0x5f7757a8, 0x87154694, 0x6a1ddea8, 0x210cb254, 0x6fb1f6df, 0x34d3cbaf, + 0xb11cfba3, 0xa625bb3c, 0x70638620, 0x32b33452, 0x9905ecfb, 0xbf2b0fcf, 0x4b27377a, 0xd118234d, 0xc838d9d2, + 0xf976e8b9, 0x2d6d0719, 0x753f2730, 0xbf6408b6, 0xff47e4b0, 0x05a566ac, 0xa596e72b, 0x3d600116, 0xc4d54ac2, + 0xd6b9df4d, 0xee6d548e, 0x391beca0, 0x06668b1d, 0x1acfbd9a, 0x4b4059f4, 0x857b9ab2, 0x82635233, 0x08509d20, + 0x0c638a64, 0xad1c5390, 0x49aee3d3, 0xca26c2d5, 0xe3d68146, 0x99d72f1b, 0x7bc2a35b, 0xf2c4e4d7, 0x98c4602c, + 0x72673044, 0x99264051, 0x076d6ea0, 0x39a0d3a8, 0xbefe0afb, 0xed62b1bf, 0x8262d41f, 0x2e6dae0c, 0xff8ff299, + 0x34ed9186, 0x808cbfdd, 0x5af6a5aa, 0x96a2eecb, 0x4b9cec4c, 0x5a6b4474, 0x2294e4be, 0x0a1859dd, 0xa6d2b695, + 0xf28c10f9, 0x76014db2, 0x9b47296a, 0xa644ffe0, 0x05336d82, 0x97622677, 0xc9c3db6c, 0x6685385b, 0x25dcd80b, + 0x2b79cbe3, 0x9f43518d, 0xe69378c5, 0x95d4ab20, 0x49067ecb, 0x2797ce90, 0x993a22a6, 0xf3befe22, 0x46ee6998, + 0x8bd22901, 0xb51bc3c4, 0x9643fe7f, 0x43f211aa, 0xb12e15ea, 0x06c7179e, 0x06cc1949, 0x1eabfced, 0x50d121a8, + 0xfa49f700, 0x95875f6a, 0x8c43d622, 0x29a3f55a, 0xf668119d, 0x74557ec7, 0x9f5f68cf, 0x72485a25, 0x3d2639fe, + 0x258cb56f, 0x58af5c4f, 0xf364cefb, 0xd03d6488, 0x80aeed37, 0x50feaff9, 0x81591a47, 0x11d50098, 0x7a96599b, + 0x991da261, 0x276bff00, 0xdbfe9367, 0xc4c2121b, 0x4388223a, 0x5d8d0350, 0xd0de5baa, 0x19994a2b, 0x9e705a1b, + 0x76158efa, 0x2de8c4f4, 0xdf4331c2, 0x78fe8f9b, 0xd7d6e0ce, 0xf70ebf41, 0x49260a3b, 0x23481deb, 0x07a3d05a, + 0xd5b8fbcf, 0xc41924d5, 0xb3adfa8a, 0xe56d0d29, 0x3a3095a7, 0x472b3039, 0x6f925e85, 0xaf41ca59, 0x60bd82cc, + 0xff4b23bf, 0x22425143, 0xd14407c6, 0xb28d3283, 0xc3ed586e, 0xea299374, 0x6cedfd5b, 0x6f6d7e21, 0xa8db6876, + 0xd6b84fdc, 0x880cb8c8, 0x5dd2a6b0, 0x3c74e603, 0x474ebf14, 0x7a8cba3b, 0x2623bbdb, 0xae2bf6e4, 0x8d154ff0, + 0x216b80ac, 0xada3914c, 0x70c1862a, 0x110bda4e, 0x98e9df8c, 0x03811d0e, 0x8667bc24, 0x8b970e4e, 0xae538ef3, + 0x1f24e517, 0x97046efd, 0xa1d301eb, 0x42f95cf9, 0xc96c3241, 0x111ab577, 0x4c85fdab, 0x5278bc4e, 0x78103cce, + 0x973de5f4, 0x7af903ca, 0x19355249, 0xa3242091, 0xc81a9126, 0xf74d6419, 0xfda32318, 0x98c46e16, 0xeca66bb1, + 0xe8bca86c, 0x4599a8ae, 0xb556d207, 0x77ae327f, 0x74343cfe, 0x983f6c65, 0x4579fcc5, 0x7b8fec97, 0x06912054, + 0xbc811df8, 0x90944274, 0xf698ba28, 0x50c6b20d, 0xaab41364, 0xd7dbf3e6, 0x1a05cef1, 0x549e0df5, 0xd4b6adbe, + 0x7ed4c36a, 0xfc0d5560, 0x2b1e015d, 0xf4a300c8, 0xde142dc8, 0x04d49c4a, 0x45c87b9d, 0xdb4e5cdc, 0xe1926222, + 0xb8a063bf, 0x256a8af0, 0xe142f134, 0x39d3d4e3, 0x08abdc8c, 0xd77f6ade, 0x1f783319, 0xddfb43a4, 0xa2a0613a, + 0x11328c5f, 0xee0e711f, 0x7b61f14a, 0xe38a90f9, 0x205ad734, 0x0f2e0794, 0x47c7e0f5, 0xbba3aaf3, 0x53c5d316, + 0x2241a6f1, 0xa9e4d498, 0x8600d93f, 0x4783a2fb, 0xd55600db, 0x398db0ff, 0x19219101, 0xd649dd08, 0xb59da38e, + 0x41bb34f2, 0xd11a1289, 0x21c220f9, 0x29e6c9c0, 0x8b6fd350, 0x5f593fe3, 0xb2c131be, 0x5ae17a52, 0x9d122709, + 0x6216e5fc, 0x8f8782d7, 0x403964c8, 0xffd04f4d, 0x12761a3a, 0xb81a6976, 0x3d44fb6d, 0x33162de9, 0xbe53fdf0, + 0xc6e1df1b, 0x875af6e9, 0xc60d8028, 0x49ab41c4, 0xb4fa13ab, 0xd5a4fa6d, 0xb0d000e7, 0xe84cb92c, 0x8f70ad2a, + 0x4c871b40, 0xd867ea9c, 0x2502e9c8, 0xdf936b2e, 0x133abaf4, 0xa0c834d6, 0xe748fa4f, 0x7a22916b, 0x561f7971, + 0xd930a25d, 0xbdf72d1d, 0xc76b243b, 0xbdb2e339, 0x49b84ec6, 0xcaa51f1e, 0x4d92c94e, 0xe5ceb6ff, 0xefe8237d, + 0x628330d7, 0xff50c681, 0x48020d5e, 0xdbf8b9df, 0x7c9a0c93, 0x07c218b5, 0xb04e0dad, 0xe623ab0f, 0x3e64f02c, + 0xa59f598a, 0x09f8657b, 0x41173625, 0xcc593d10, 0x49d97d57, 0x35f55c0f, 0x24a72482, 0x789184f1, 0x1b1b0ffe, + 0x7d5238bf, 0x24f2f2e5, 0xbcf77fa2, 0x718961dd, 0xe18f45c8, 0x9065e949, 0xc998a5d9, 0x73048a2e, 0x7ae6b06e, + 0xe51e15e0, 0x8ee1eef4, 0x4bb2f19c, 0x7eed75d6, 0xff152e90, 0xa734af0d, 0x2c4df279, 0x712cf840, 0xd15bed24, + 0x22a106c5, 0xae6508b7, 0x30704245, 0x9f06e73f, 0x67333c1e, 0x6ee07bde, 0x18684260, 0xbe70456a, 0xd03a0695, + 0xdef77110, 0x8096aeae, 0x885c16c3, 0xeefef126, 0x7333357d, 0x7fcae80b, 0xb98fb128, 0xab7c9324, 0xb235c30b, + 0xa18ccd83, 0xec636faa, 0x9e84664b, 0xae9c718d, 0x2dcea525, 0x3e3993b8, 0xd2a2f8a1, 0x2ed751ba, 0xdeb2b0e6, + 0x3822c28d, 0x48da9cb0, 0xdfa2aded, 0xfc879bc2, 0x84cb3295, 0x46c3ccf1, 0x110634ac, 0x5f3dc46f, 0xfa9acaed, + 0x29a2c8cf, 0x03a65568, 0xbdfc6720, 0xbd9870a9, 0x98c9ae15, 0x4698b09e, 0x45ff18f7, 0xf6197177, 0x311bccdc, + 0x6b937d8d, 0x9aebae81, 0x2231e105, 0x9b49b1e3, 0x465b5365, 0xeef0312e, 0x7911718d, 0xa9d9d86a, 0x436f9e66, + 0x2fb4f785, 0x39f69c1b, 0x6b8fce09, 0xe6cbdb02, 0xd652c59c, 0x7f7de20b, 0x056d020a, 0xf13d9dae, 0x624e9ecc, + 0xac77cdee, 0x439cf983, 0x93580298, 0x92556375, 0xf67b79e4, 0x08812b16, 0x237858a8, 0xe3aa2c72, 0x629e53dd, + 0x4735074a, 0xb3b308dd, 0x89a4b427, 0xba942329, 0x69be970c, 0x4aa974e9, 0x89507aea, 0x299b7bac, 0x41bbfc73, + 0xb5f39464, 0x6e49f5ce, 0x01b30f19, 0xbc6f295c, 0x888de911, 0xf96e9862, 0x49a63d95, 0x3d455803, 0x33ce8ec0, + 0x6129d743, 0x51def589, 0xd0e7ec8f, 0xc925adce, 0xe187d5c5, 0xe7233c37, 0x13c37de0, 0xb21f159c, 0xa0c8d9e1, + 0x32844aea, 0x7b5d8345, 0x17b46123, 0xf8eefcd0, 0x3de8993f, 0x110f923c, 0xb86833e2, 0x64097311, 0x9504a543, + 0x6039b8a2, 0xb04d88ec, 0xc56d33fa, 0x2fce359e, 0x60cf220b, 0x059de80e, 0xc7983afd, 0x5aed66a6, 0x270c27d1, + 0xd5a1b783, 0x783d5b33, 0x2f7a7cf5, 0xad04ad0c, 0xadf745e5, 0x007003f6, 0x30ed42d0, 0x533ed822, 0x2442f5bc, + 0x91007e7c, 0x8ce5eb60, 0x3e9b77b8, 0x649a07cc, 0x05c4e22e, 0x3a2bf192, 0x3dbd1a6d, 0x1c047175, 0x9160512d, + 0xdadaefc4, 0x16972f88, 0xd827a229, 0xd3a34179, 0xff698922, 0xf73b2640, 0xe9f5005e, 0x1851d0b6, 0x9f94787c, + 0xca5298d4, 0xf4cd8cb7, 0x940453b7, 0xa3ebc5e4, 0x34da3b06, 0x8464c209, 0xcff81b8d, 0xa3d3fe56, 0x3c34e397, + 0xb3d8b310, 0x6bfe67f3, 0x00b44479, 0x12920ccb, 0x2bd85d0c, 0x5d9e92e4, 0x858cf763, 0xc23b1717, 0xab9aaeed, + 0x2e538ed3, 0x02c28174, 0x5a0ea334, 0x74d51121, 0xbb1a82c9, 0x4ee96f86, 0x142942dd, 0x7e68fe24, 0xc1f3bbad, + 0x26a6e4a4, 0x21f3fb09, 0xe299ecfd, 0x6980b4bc, 0xa3e91612, 0x3d0097c1, 0xc3424df1, 0x86e7653a, 0x63e1050c, + 0x5e9d61d1, 0xa6c28a3c, 0xe92b7192, 0x09f30252, 0x4723bcff, 0xbacf47ce, 0x0fef1075, 0x08c84d0f, 0x55f231ca, + 0x8a42ee1b, 0xcf5c9a5a, 0xa38d4d18, 0xcda9d672, 0x566dc57c, 0xcd0d2044, 0x5cadba07, 0xd36dece0, 0x0abf40f9, + 0x4993baaa, 0x66958333, 0x61ce946a, 0x57d98961, 0x99a6759c, 0x830fe7e8, 0xe3256b9b, 0xa8a8ab7c, 0xcf3ea829, + 0xe41ad604, 0x95777996, 0xfb30e34f, 0xce93c638, 0xb20a3975, 0xb8546263, 0x6f115460, 0xee9f6a5c, 0x02a827e4, + 0xe08d0014, 0x4e6a5e23, 0xe6e6c2ef, 0x255f20b7, 0xfc4e021f, 0x7954c4a5, 0xc863701e, 0xe8a8c503, 0xe89416fc, + 0x51cec9c6, 0xcc25e18d, 0x537f9fb8, 0x78d7664f, 0x56bbb52f, 0x4d237621, 0xb09b7dcf, 0x564aecab, 0x460a34bb, + 0xc7a46460, 0x4e365366, 0x986437ce, 0xcc0dc4cf, 0x7125d059, 0xdda3ccc6, 0xb7791989, 0xd6225a10, 0x6bb2bb69, + 0x855eb143, 0x7b0dbaef, 0x5693dd68, 0xe99c6794, 0x7d405d1e, 0x6a5c4ebf, 0x04159da7, 0xc856ef9a, 0xf0ad0e35, + 0xb1a7171a, 0x7b70cb92, 0xe5d0b0bc, 0x0458d482, 0xbed1bd02, 0x58ea931d, 0x9e610768, 0x183b85f1, 0x011bf3a3, + 0xd768ebdf, 0xe52d7f9a, 0x8fdfe604, 0xe54ef9f7, 0xb3fad21c, 0x853f7fdb, 0xeecb8c14, 0x983c7b1e, 0x8fb5305a, + 0xdf216bff, 0xe7843102, 0xb54cc00f, 0x57041aea, 0x6aed901e, 0xebd4ff3c, 0xae1ee888, 0x9f3ae65e, 0xdf91fd8e, + 0xd8d7294c, 0xee4faf1c, 0x322becaf, 0xdb0a9463, 0xc8e7c3b7, 0x286cbbe2, 0x882678ed, 0xbad18f6f, 0x01b725bf, + 0x3e94270d, 0xbdfabe0e, 0x37deca16, 0x3d815544, 0x210e7f07, 0x90c3dd45, 0x64dcfde5, 0x867647d8, 0x24d0450b, + 0xae930135, 0xa5a05797, 0x83d739cb, 0x6671522d, 0x5f1f7f9c, 0x2236a237, 0xfc167cb0, 0x25814cf9, 0xa8efecac, + 0x7abd4a34, 0xda0b728a, 0xa8e058f7, 0xb1be0205, 0xc0784253, 0x26fba62b, 0xfa22f08b, 0x27b616a7, 0x70e4d526, + 0xc5256e36, 0x25ffb229, 0x9ecdcbab, 0xcbed9c45, 0x81c50f1f, 0x9094d754, 0xfc2a33aa, 0xdce09e75, 0x63eece2b, + 0xb9d844e2, 0xc71eedcb, 0x24c66daa, 0x18cf9c54, 0x0b647ed0, 0x1cc35070, 0x883da0ed, 0x6eebf739, 0x1ad98cd6, + 0xf67e425c, 0xf909730f, 0x1c36c693, 0xf1d41b0a, 0x8f857123, 0x50c5d67d, 0xb3bfea9d, 0xe9c4f574, 0xfb2a0946, + 0x1dd78585, 0x8a6c7bc6, 0x3ed354a5, 0xfd579934, 0xebf26eb3, 0xa1af2a19, 0x91b51324, 0xb72b6518, 0x23767a85, + 0x4bbef500, 0x7ad41838, 0xed3e32b4, 0x3f1248d6, 0x92a0421e, 0x8285172c, 0x18ad2c3f, 0x8f9202d4, 0x3d264c0f, + 0x82fbf0b0, 0xa3df460b, 0x97c12c2a, 0x10041386, 0xc0d2a049, 0xfb9b7965, 0x4d5275b1, 0x47e9c982, 0x043c27f7, + 0x7fbcb50a, 0x1e8fcb56, 0xb7540027, 0x3d01b265, 0xc404f7e7, 0x60baf07f, 0xdb388c76, 0xe85e372c, 0x4631dfdb, + 0x5a122c20, 0x5271ac42, 0x335727ca, 0x81682865, 0x3fb7c2af, 0xc7e25e5a, 0x8c9c09a3, 0xb9e91b82, 0x7e894cce, + 0xa87fff01, 0x840a31a3, 0xec3c9ecf, 0x4b5a9ec1, 0x6c895d36, 0x05850451, 0xc5e448f3, 0x108e00b7, 0x444eacad, + 0x375b9c0f, 0xc3d4f4df, 0x498b1865, 0xcd8f1d35, 0xfb1ef843, 0xf7a8ed54, 0x0b7dea01, 0x876cdecc, 0x4740e853, + 0x2801a101, 0x66d4cc12, 0x95da26e3, 0x0679549d, 0x1d1e84bb, 0x6d9d90eb, 0xcc67bedc, 0xd5fb90da, 0x51366389, + 0x8b7c7020, 0xc38c6010, 0xdbaf3135, 0xda373f6c, 0xb7242b4a, 0x77462a4f, 0xf86342d3, 0x4411101f, 0xf12d1aeb, + 0xc7cbb87d, 0x9df17077, 0x80042af8, 0x54d5fc4c, 0x33a1dd28, 0xff2f3577, 0xe673e1ff, 0xb1e929bc, 0x7b1b3ef9, + 0xad83c582, 0x86b41ad5, 0x7d4edfa7, 0x69f8a853, 0x532dcde6, 0x2edd2e8a, 0x67b5f54f, 0x93073aa9, 0x9c1cada4, + 0xae525401, 0xf906e43f, 0x0d38349d, 0x4ada8be3, 0x3da611fd, 0xa600098a, 0x8ab34e20, 0x0f5c0769, 0x51f7bcea, + 0x434eea13, 0xd780acc9, 0x077b1189, 0x845e8639, 0x8badf526, 0x61e32ad7, 0xddcb4abc, 0x7cd688c1, 0xa598c834, + 0x955519cc, 0x7e0c2bbd, 0x1e6833f5, 0xdef60d2f, 0x57886fef, 0xedbd6b1e, 0xdfe0440a, 0x9d56b2a8, 0xfb71dd0e, + 0x4954f056, 0x1a5f34fe, 0xe8b3bd1c, 0x2214b404, 0x3095f1fc, 0x3854a374, 0xfaa947e8, 0x60db6ac2, 0xe25d8024, + 0xe71719b7, 0x9e22d2df, 0x4771161f, 0x069d92e6, 0xffdd60f6, 0x9d9d4863, 0xe2ac342d, 0xf5c15969, 0x91eb8493, + 0x50a7221a, 0xeea8b9e0, 0x1a4170d1, 0xce98faca, 0xae325668, 0x071f33b7, 0x9fa29314, 0x4daed636, 0x0420c83c, + 0x1f3a3aab, 0x663a76b1, 0xe08125f8, 0x3b9773d4, 0xb55c0d66, 0x65e399fc, 0xc8172e2c, 0x9d72c3f0, 0x1748fa40, + 0xf6de9581, 0xfc603fd6, 0xb68a00ef, 0x8242c2fe, 0x4dc3809e, 0x60fbbca6, 0x21789941, 0x00a701cc, 0x3690181f, + 0xf4776794, 0x81c1915c, 0x80065f46, 0xe25469fa, 0x281e05b1, 0xdec244be, 0xbf827b0f, 0x81d3073e, 0xf0925960, + 0x69815b91, 0xc6e0fd3a, 0x2a067311, 0x17322708, 0xa6355f30, 0x2f322285, 0x38e384f2, 0xf054a639, 0x79a04707, + 0x97538e54, 0x0979ca43, 0x924efc1f, 0x8bf92ac3, 0x60c6a419, 0x81459c1d, 0x5db54b51, 0x0ed85d3f, 0xbcd68d28, + 0xd2d4bceb, 0xe2c4da37, 0x28a52377, 0x118b19f3, 0xc92701d8, 0x3c0b1857, 0xaba76c05, 0x99ef1f74, 0x013541bd, + 0x07651f4e, 0x58735ac4, 0x6082eb56, 0x8e3dce4f, 0x50b5f0c3, 0x38e11504, 0x19804b96, 0xb1fc8a78, 0x4d0b955e, + 0x7651b886, 0x8cc64d10, 0xdc26c25f, 0x231bcf3a, 0x72641334, 0xd4cba1fe, 0x3a2d9321, 0x9cdf704d, 0xdce97cb0, + 0x6575fb5a, 0x341084ad, 0x9e16d868, 0x3c10f8f7, 0xa655a60d, 0x26c06f80, 0x8e32d306, 0xc860a1bd, 0x61bbd7d2, + 0x608e2b56, 0x589b8921, 0x9ac45078, 0xea31c54d, 0xfb729649, 0xdee6cecb, 0x2cee2aff, 0xb33a95ec, 0x13f78248, + 0x5c6c767e, 0x18421386, 0x114a784d, 0xb81b8bc8, 0xb96b6a6f, 0x370aef50, 0x3b2fec4a, 0x86f4f4b4, 0xb32ecff9, + 0x3d7c6af8, 0x1232c194, 0xe0826cd3, 0x85892b49, 0x482dd81b, 0x0d4d7171, 0x3d3957eb, 0xc162f0e8, 0x82f70074, + 0xf276d729, 0xc1abf070, 0xcff818a3, 0x183ecd3e, 0x84c15861, 0x0becf521, 0xf7513f5e, 0x37c645ec, 0xb863284c, + 0xd6253cac, 0x5f615780, 0x79654d6e, 0x991ba771, 0x7d312834, 0x8d7cd8e7, 0x98046d96, 0x30a2bd8d, 0xfda1ef21, + 0xc2dd805f, 0x481ec139, 0xb2a0fc80, 0xf95415b5, 0xd276b2a3, 0xdc8bb232, 0x6349578c, 0x66a4933b, 0x61fdbbe9, + 0xb4d01745, 0xf3cf1966, 0x85788a5b, 0x52a9546c, 0x7fc36103, 0xa5da8967, 0x0aaa8c2e, 0xb80d7316, 0x9d4ca883, + 0xc33faf83, 0x0d65e0f0, 0x4ce14d4c, 0x29d81edd, 0xdd2a6088, 0x0e7a0f1f, 0x9b914992, 0xbba73bae, 0xd378f681, + 0x6da8bc30, 0x3abe97b7, 0x6f4ce65d, 0x4f88ce15, 0x746c9216, 0x081ce546, 0xb947a476, 0xd407fc99, 0xd473f7fc, + 0xdfcb187a, 0x98ab3329, 0x653abd94, 0xe68379ba, 0x4ae9a0ab, 0xb98f3d91, 0xec23547a, 0xb55c1904, 0x9b129b97, + 0xc65da49d, 0x691081db, 0xf5475a02, 0xbd8d524f, 0x494ea328, 0xc0978daf, 0xea48fbd7, 0xb6edd0fb, 0x6a81ff72, + 0x7ac9e9d3, 0x05eef64f, 0xc83a1bae, 0x562a3224, 0xf4c8ad37, 0x4db83d5a, 0x761df5cd, 0x48b4d8d3, 0x44272e64, + 0x3f2c936a, 0x405abbfe, 0x8f16d3bb, 0xd1932d8e, 0xc5c5fdf2, 0x989b1cc2, 0x406b5d6d, 0xd1b3e502, 0x1cbf2b3c, + 0x7f2598bc, 0x4f3db255, 0x3c7418fb, 0x87a48bb4, 0x21eaf642, 0x886f2e39, 0x81759dd5, 0x969d87c3, 0x7e8d0aca, + 0xaff01cff, 0x68c03972, 0x668f2f04, 0xecd772af, 0x626ef59d, 0x26a9ff78, 0xd5360579, 0x9dd865ce, 0x96e1462c, + 0x6d7601e6, 0x6f296fd7, 0xddfafb8f, 0x71d1c61d, 0xa101bc5b, 0x1958f414, 0x4371b833, 0x36d7b46f, 0xa0313d61, + 0x383984a4, 0xc4031a09, 0x5c3a6c95, 0x7116cba1, 0x9b6c583e, 0xebfb34ee, 0xb6ebc454, 0xd37d2c78, 0x97ec5d10, + 0xcc21f1a1, 0x67605985, 0x0f44c46d, 0xe29d6757, 0xad4cc60d, 0xaf4040a3, 0x533746db, 0x0421c78c, 0x3f396861, + 0x8751b499, 0xd9f1c664, 0x1334ef88, 0x132b1067, 0xa173da7f, 0x03ac68a7, 0xdf1d6fb5, 0x6b5aef66, 0xa7bb474e, + 0x5a0d0cb3, 0xd7d2b12a, 0x9261ebaf, 0x9e1de54d, 0xe462a21d, 0xb23ae2f5, 0x15ce3be8, 0x2f401a12, 0xd0c2ca1b, + 0x519cb870, 0xeedbd71d, 0x4e6b0466, 0x6d2a5131, 0x8c2ad013, 0x8e4c9f51, 0xc5430f11, 0x8291cf18, 0xfe70ec21, + 0x3d77c159, 0x0c7c5bf7, 0xfc109604, 0xdf3ca923, 0xd7ced166, 0xf98a7d73, 0xa4dda7dc, 0x42776569, 0x6d54d17b, + 0xb309ba6f, 0x2cf945e6, 0x607d5af8, 0xfdc081aa, 0xcd2523d0, 0x805edb28, 0xf722afe1, 0x8649fc50, 0x5c5d8791, + 0x5d34eb6f, 0x3d0cf6f1, 0x18bde051, 0x0e932e94, 0xd836a014, 0x34a070ba, 0x9059d475, 0x2b10f68a, 0x2d6f4e91, + 0x5d8a4f7f, 0xc3814e95, 0x2bd4c0a9, 0x67a9eb61, 0xb85e9b9b, 0xf5061444, 0x6435de07, 0xd6b2f8a2, 0x92a62541, + 0x05abe595, 0x502921aa, 0x5db30904, 0x6ba31431, 0x27ac3099, 0x76629459, 0x71db7c92, 0x0082083e, 0x795fcb0c, + 0xff229576, 0x4901f6b0, 0xd889929a, 0x21baa821, 0x1e2a5c51, 0xb1df0f36, 0x089649b6, 0x72cb65c4, 0xef632a94, + 0x49b1b203, 0x74176ff6, 0xfaf9cdef, 0xbec385cd, 0x93cf0060, 0xb8475f2f, 0x4821b6e1, 0xe7e346d2, 0xb2f934d2, + 0x20e9f809, 0x52c7f9aa, 0xa2d8a24e, 0x25eedf43, 0x8472e5b7, 0xb9deb05b, 0xb8082c3e, 0x114a6db8, 0x28f7b42f, + 0x2e610b92, 0x19990b49, 0xa7acbe32, 0x6b9f36d1, 0x271ef93b, 0x07b2efd1, 0x1201f07c, 0x089d554c, 0x3e59661f, + 0x5decfe9b, 0xd92792fd, 0xf1900f49, 0x6fb273c2, 0x77eeef67, 0x07f475e4, 0x3a5e9e65, 0x1af28aa8, 0xa6206b1d, + 0xd24a954b, 0xa18782f6, 0x9224070f, 0x2bcee774, 0xb2f3e38d, 0x83897a8c, 0x89422aa6, 0x45178b00, 0x40e0cc19, + 0x48e157c6, 0x6d594dd9, 0x42efdebe, 0x2f3cf671, 0xa9d62916, 0x44fb3f79, 0x0dcf272f, 0x2cf641cc, 0x70629760, + 0x3835691e, 0x684ffd90, 0x7234ddf1, 0x8c47184d, 0x7d6826f5, 0x3536ef57, 0x9184e4db, 0x9272a5ef, 0xbda743fe, + 0x192eab2a, 0x8253b572, 0xe66ed48d, 0xc67a7f73, 0x83752cb0, 0x71124a13, 0x252372da, 0x11a1b3f2, 0x589d659a, + 0xb1731851, 0x406b3a6c, 0x47f5f0f6, 0x29df1ef8, 0xa6be6a5d, 0xb26374cd, 0xbc4332d1, 0x83183d65, 0xc101f2a8, + 0xe6d57f96, 0x0f39cb43, 0xf07c0472, 0x5975db04, 0x3c3ff113, 0x501ccb55, 0xabb980cf, 0xa7eda195, 0xf2047132, + 0x99c9eb19, 0x4a361062, 0xa1bc75d7, 0xcd15a6d3, 0xeb19e8e3, 0xc41b6e64, 0xc9f5f2df, 0xc0d40a1c, 0x0473a995, + 0x21c1569c, 0x2bd05287, 0xb3a8870f, 0x4ff5d9de, 0xc5b85934, 0x2e749c2c, 0xad0e95f5, 0x81a1ecd7, 0xfa428a53, + 0xb7c5e5bf, 0xadd146c6, 0x933154b1, 0x79098431, 0xa5a32bc0, 0xab19257e, 0xca99ac5c, 0xaa511ead, 0xba2d503d, + 0x9b5f8b01, 0x769a6155, 0x66e329b6, 0x0521a91e, 0x1646e8f6, 0x3cfee83b, 0xc8eca6b7, 0xb9d6c5f0, 0xd48464da, + 0xb6f96b51, 0xf29ab954, 0x8c25c3c8, 0x8104efbc, 0xb0ed439f, 0x3e68e221, 0xa34bdb20, 0xaac67e75, 0xaa85b593, + 0x778f3f65, 0x49309d28, 0x74b5ab2e, 0xdd01e3c5, 0x6648ba4a, 0x18a161b9, 0x880ead46, 0xab894080, 0x86855512, + 0x0d7884ca, 0x307636fa, 0x8e76bcf6, 0xf034fb5b, 0x041247b1, 0x3ca1cc38, 0x6b731f7e, 0x9ec09bc6, 0xfacd4e36, + 0x02e0c079, 0x0b21f06c, 0xfe7c3a1e, 0xd4a02bc1, 0xb168d5f7, 0xcba3a5ab, 0x06ca681a, 0x51574872, 0x55e455f1, + 0xaf2beea8, 0xbdc9ed82, 0x7ccfad42, 0x9877fa34, 0x758c3736, 0x16854c52, 0xa209be95, 0xf7a873e7, 0x0a392591, + 0xdae4e54e, 0xe499154a, 0x02c14eed, 0x65f47bd4, 0x9ac67eef, 0x76ebbaec, 0x266feac7, 0x4e428f2b, 0x0d6a0d5b, + 0x64a7d085, 0x0dc74480, 0xebffd654, 0xfa8cfe89, 0x98c56de7, 0x2cb0ba66, 0xc728915e, 0xf49ca911, 0x4b43403e, + 0x75e884ac, 0x266fe1f5, 0x488845ec, 0xbf9eba5d, 0xc5de03a9, 0x2c2c86aa, 0x0055f3ae, 0xddb201db, 0x9638db01, + 0x66bd2f45, 0xb07799b2, 0x63238336, 0x138f7bae, 0xc75bb331, 0x5984150a, 0x32f0f652, 0x987af2a3, 0xd5c66b30, + 0x0ab348aa, 0xcb295595, 0x08307708, 0x457b51ed, 0xd4e425e0, 0x8ab173d2, 0xe8345348, 0x003dc2bf, 0x86e575f6, + 0xfb45647d, 0xeb54ecc0, 0x356d0d94, 0x994d5fe5, 0x8a317b77, 0x0699702b, 0x68d6956b, 0xc2dbd5f5, 0x64e10405, + 0xbe4258ce, 0x7831c23b, 0x8ab105a3, 0x981ca2b8, 0xddfd9fbd, 0x4e6ee3d7, 0xd0b5813a, 0x3c3a6d54, 0x76592a49, + 0x33972344, 0x4ba191c8, 0x29647ba5, 0x270dfaf7, 0xe7ad6ac4, 0xc8acd829, 0x1cf6d0cb, 0xa5c82687, 0x9276407c, + 0xe29bfa93, 0xd4438558, 0xefaadfe8, 0x1c4ca754, 0xc192d25d, 0x960182b1, 0xb249be0e, 0xda168585, 0xb3ec08c6, + 0xbaa53007, 0xc522f114, 0x528f88a5, 0xda38e417, 0xe1c260b1, 0x03989b2e, 0x6bb1c9c7, 0xc5042127, 0x86d52176, + 0x174e117d, 0x4005165a, 0x278cb9f9, 0x0d9941ca, 0x7ea731d7, 0x881387f3, 0xfd80043c, 0xd7f14669, 0xc10cf419, + 0x410e4226, 0x763f1a9c, 0x0485d02b, 0x258a8a48, 0xb58e165a, 0xdfb73419, 0x7a5a3fc4, 0x679f8ae4, 0xb98f6e6f, + 0x9f62d2c2, 0x2a9fecf8, 0x588008d6, 0xb2b42a79, 0xe79d66f6, 0x36f16e85, 0x226ecddd, 0x17e149ac, 0xec59d5d8, + 0x603ed931, 0xf657ae94, 0xe99cd71c, 0xfdad1184, 0x999949f4, 0xe1fb5635, 0x24694518, 0x0b09a8d6, 0x710c3097, + 0x8f98d93f, 0xbb43cad4, 0x5c8aabb0, 0x86777509, 0x5c68e6c8, 0x78880176, 0x3ed82433, 0x2d8666b6, 0x583b77fc, + 0x536496c5, 0x90edebbd, 0xa281f2fb, 0xfa8443cc, 0x297d6ee5, 0x84e6945c, 0xddc349b8, 0xe72c85f0, 0x873cafa2, + 0xdd03d139, 0xa37c448b, 0xe753b8fb, 0x784bfc3c, 0xb4edde78, 0x352cf40d, 0x9351b32c, 0x074ecf34, 0x357826d3, + 0x9894e4f3, 0x0fab21f3, 0xe42cd07f, 0xc445ea9f, 0xad89e32c, 0xdc718b51, 0x62ff78af, 0x48f0e12b, 0xd4b374bd, + 0xd9034a7d, 0x58429eb5, 0xee33a4b5, 0xc062188c, 0x2bb159b3, 0x5ee9684b, 0x9085d1ff, 0x44febbd4, 0xe147e0b4, + 0xed26000d, 0x48ccf2bc, 0xdcb06a5b, 0xb263743a, 0x6c507c68, 0x9e02252a, 0xc743916d, 0xd23532a8, 0x96963fc9, + 0xbb1a51ab, 0x8ebbc14d, 0x0970d0b5, 0xa43b554e, 0x216d097f, 0x3cbf5dac, 0x0a5f635d, 0x61a3e7ca, 0x2645b770, + 0x9390cb4b, 0x333b5a2b, 0xafda1373, 0x1af7c5c0, 0xfe391930, 0xe8b208a7, 0xe715c7d7, 0xd1401df4, 0x97833abc, + 0x8b2f8bb5, 0xa473562d, 0x5e2358ff, 0x826ecebe, 0x5957b65e, 0xb70cc02b, 0x91b2e7c1, 0x50a95917, 0x980cd96e, + 0xb4ef8479, 0x2a7ea907, 0x7d66baca, 0x5f768aa5, 0x275c58df, 0xedb0c056, 0x9b57e989, 0x86ee2807, 0x18ce0b34, + 0xef7bd820, 0x8d8a172a, 0xb57aaba8, 0x2bcf87b3, 0x088b6131, 0x0d2ea5a3, 0x200ec9ae, 0x796c949b, 0x0e4cfef3, + 0xb9fd47e9, 0x2902c492, 0x6754e611, 0xdf4ad837, 0x1f62454f, 0x64ff511d, 0x4e1677c6, 0xa59d2b53, 0xb02a7b47, + 0xcb89f116, 0x4904c549, 0x2636f11d, 0xae2c38f1, 0x73b08571, 0x9534e0e1, 0xb8dbb069, 0x9a716f31, 0x861608ed, + 0x4bcd919d, 0xba3fd688, 0xdd0d7a2d, 0x8e098435, 0x4ecc0dc7, 0x73517cca, 0x75314d2b, 0xa6c9a1f2, 0xeb36bda0, + 0xe59fcbca, 0xf7faa5b8, 0xd0dd6e5e, 0xc1319110, 0xac44f4b8, 0x678c249a, 0x52247748, 0x4fa0c145, 0x9269c1ab, + 0x3cc77b2f, 0x875ffb35, 0x854859fd, 0x67f60c62, 0x9dc8446f, 0x48aa654e, 0x162f9509, 0x152819c6, 0xa7a4bead, + 0x8a09ea77, 0xfb6c8b38, 0x6e4febd6, 0xc1490b93, 0xafd0170d, 0x78b54e06, 0x9fb1395f, 0xea09a7b4, 0xcd01d011, + 0x06de9bf8, 0x0e3a03a6, 0x1873b75d, 0x261fccd8, 0x40078b27, 0x5bad511a, 0xed95a95c, 0xcfc46138, 0xf7c43b46, + 0x02999bf5, 0xf46e4658, 0xc4d3042b, 0xee7fea0a, 0x86270bae, 0xf13f5108, 0xe6749c4f, 0x8b9311ef, 0x41d6050d, + 0xbad4a04e, 0x61209f31, 0xd0414b01, 0xbcb68c97, 0x66cf2c85, 0x8429c3bc, 0xd16fe1e9, 0xfc45d845, 0xed754f02, + 0x4cf40da2, 0xeff95e42, 0x558f7788, 0x0d181be9, 0x440f00b5, 0x3328d44c, 0xc60baf98, 0x304d4203, 0x8f7682eb, + 0xb79bfec9, 0x5ba6449c, 0xdb20cf34, 0x7583d877, 0x25f03db6, 0x60d21929, 0xfec67c23, 0x28abff66, 0xb270f2ff, + 0xcea690e1, 0x52d0b793, 0xdce0c58d, 0x2956e789, 0xee0a6833, 0x62b554d6, 0x25141c1f, 0xe0ced8e9, 0xea51d5b4, + 0x02fef6d2, 0x1cb94528, 0x32248083, 0xda67daac, 0xdbee9eea, 0x02cf2473, 0xbd8ba1ad, 0x40fba5c0, 0x743cc368, + 0x02a41915, 0xf45344b2, 0xff095296, 0xa4f99115, 0x886a8531, 0xdf49c8d0, 0xfffc01a8, 0x5e390ed1, 0xbb826af9, + 0xc8ad27a8, 0x9d229234, 0xac9e1b91, 0x2c909c1f, 0x81131900, 0xc2a3470e, 0x8ed14ad3, 0x1c392b96, 0x9219adc5, + 0x276260ce, 0x45751e70, 0xeeb73f37, 0x5973487f, 0x3696f185, 0xf8d26e76, 0x63886b43, 0x13b650f4, 0xef0db3da, + 0x31f5cb57, 0xe3691fd6, 0x3feabc66, 0x83eb534f, 0xf2f0b509, 0xcfe1d19d, 0x39cc48c4, 0xe7b2a3a8, 0x1367ff28, + 0x13ce8450, 0x39819f2f, 0x3af5e528, 0x40dc5b48, 0x3e6f4823, 0x8a259c22, 0x1bcadca9, 0x9d9b2df1, 0xfe8a23ad, + 0x8270a434, 0x565b63e6, 0x1a647c71, 0x48a58842, 0xb96dd84a, 0x3d971933, 0xbfe118ce, 0x5d7c71e5, 0x9ca4b350, + 0x89513b1c, 0x2a70cd45, 0x8d7b2862, 0xbe82ae25, 0xb381bebd, 0x7c211a46, 0x707809bf, 0x35612c53, 0xc8ecbde5, + 0xfced9e0d, 0x634427a8, 0x557e42e3, 0xba8b31dc, 0x154f8a1f, 0x4b9129e0, 0xf45fed85, 0xdec2052b, 0xb42f1116, + 0x2c02c656, 0x81b81215, 0x1f97f3a5, 0x72196d5f, 0x1ad84431, 0xe6b5f44a, 0xcb3bfd20, 0xac8d3839, 0x7941f73c, + 0x3d51b456, 0x0257c7c6, 0xe999bc38, 0xeb156015, 0x6e36e71e, 0x8d48b223, 0xc4ce504c, 0x2c0ee7da, 0x15a02079, + 0xc28b45b5, 0x46ee7251, 0x6c2612b3, 0x9a7e2b43, 0x4a1f7959, 0xd27eddc1, 0xfd53a095, 0x1790221d, 0xa3f5aab5, + 0xe520d4f8, 0xeac5c429, 0xebcf792f, 0xc6a95bf9, 0x0f9a0267, 0xde9f5cbb, 0x341da9d4, 0x9b9e1f61, 0x893b554b, + 0xef0853a2, 0xdbc22d8e, 0xd0b094a2, 0xc63e8113, 0x4317c1c6, 0x5b31e132, 0x416dd7ae, 0xa3cc210c, 0x6dc7d616, + 0x18c9d45a, 0xa0d5954f, 0x2c926ae6, 0x863e8fe3, 0xe5691cbb, 0x81043272, 0xa5494fe0, 0xdb8822ec, 0xb2ad670a, + 0x610c5160, 0xad35b20b, 0xbbe53dcd, 0x910e4dc6, 0x664cc715, 0x07f5123c, 0x9b6b9e14, 0xc5389017, 0x523e9522, + 0x7d93b0a9, 0x3504dd0e, 0x68881695, 0x162199ff, 0x1772bf19, 0xf41faa30, 0x321e3826, 0xbff22275, 0x513971ad, + 0xecf73ee1, 0xe1b23422, 0x4f7b9c02, 0x239db54c, 0xd7f7807f, 0x4ccc0297, 0x667c24fc, 0x82229a5a, 0x8d5221e3, + 0xc56b51a5, 0xf47eef63, 0x1f7d1c4b, 0xd9968785, 0x85c97010, 0x0b7acb3e, 0x6ff8fe4b, 0x69d6ea31, 0xe705ec5a, + 0xa8b9d67b, 0xca5a0505, 0x6265c417, 0x2a868ac9, 0x12b79504, 0x7ad67c1a, 0xe481fa9d, 0x721e318c, 0xefb33ab8, + 0x5e35e902, 0x9dd1862a, 0x42e46cd1, 0xf4fa015a, 0xb9acacd9, 0x0362a7e3, 0xeea41cea, 0x3eac0cae, 0xae5f3c92, + 0xbd948378, 0x090c0497, 0x4fdae890, 0x7573c576, 0x8cc482ac, 0x8e5c4911, 0x54c7ef42, 0x0620be4a, 0x86782452, + 0xb0ec0e8a, 0x8b74695e, 0xd0d7fd8f, 0xc8e9a8b0, 0x89eb8d45, 0xc6019489, 0x144f356e, 0x8ec1c681, 0x3db9e652, + 0x41ce38d2, 0x209c58b4, 0xf808e745, 0xf76cbcf1, 0xe7eb2eb2, 0x734fe5a7, 0x4b053e03, 0x602085ca, 0x1de9ed43, + 0xb5d1c081, 0xc5d2193e, 0xe04f3910, 0x95e7e698, 0x040cf4de, 0x2519378f, 0xeab6e742, 0xd5537f88, 0x41a2e29d, + 0xc755ea3a, 0xb4f0a016, 0x6388bc5a, 0x01d0be1f, 0x70cd8f1f, 0x83f5e1de, 0xe7143d2f, 0xe71f2e82, 0xf98d038d, + 0xd3975190, 0x64deaec3, 0x7e6f451b, 0x8ea7421e, 0x438acdd5, 0x53d8abec, 0x7ff89128, 0xb60d104a, 0x53580098, + 0x8946171f, 0x4f59dde0, 0x7f9a1cda, 0xc8015f2f, 0xfa09e05a, 0xf1a5a08b, 0x80330674, 0xd49d37ac, 0x7b037200, + 0x44dd75e5, 0x81a0d21e, 0x8b15cd41, 0x2c945724, 0x064fe36d, 0x105797a3, 0xb36f0401, 0x44b8c1df, 0x07526290, + 0x3cef1d91, 0xff8a46d9, 0x3db2dee1, 0xa2be2bcc, 0x03799cee, 0xf15bfebe, 0xdd9ed7ea, 0x678ab89f, 0x6118a382, + 0xbc958139, 0xd9760bff, 0x9f30d8cd, 0xaa5154cc, 0x5f49e2a0, 0x8e0c65b7, 0x7d863027, 0x514a05f5, 0xba075f1a, + 0xfa326188, 0xa603a62b, 0x6d9604a7, 0x9ccad247, 0x820ee5ed, 0x268122ed, 0x00675074, 0x8ab2472e, 0x5230ae6f, + 0x3678dbca, 0x1c14ef21, 0x1be1ff9c, 0x218df538, 0x0b94316b, 0x989c589d, 0x243ad8c0, 0x83f67ab6, 0xcb6463db, + 0xb55ad96c, 0x6e4c45e1, 0xf15f3002, 0x32001c40, 0x5ed73848, 0x37fefeb3, 0xf6efba38, 0x55de711d, 0x5095eaaa, + 0x023e9fe7, 0xb7bbf44f, 0x47d815d8, 0x1da8217f, 0x8118f56d, 0x6b861bec, 0xf82dd084, 0xd60d7f85, 0xca319a50, + 0x9249ba3a, 0xb7645ef4, 0xf5534864, 0xc88a907a, 0xecb3d6e4, 0x17d149dc, 0xb0cf7341, 0x4e0f9a27, 0xaae4e27e, + 0xe3f8b880, 0xcb407085, 0x35828677, 0xc75eb363, 0x0b6b8a80, 0xabdc2040, 0x8a0b7a04, 0x4493200f, 0x92f9da5c, + 0xc7a13f4a, 0x0e415159, 0x37a51f68, 0x1a39111b, 0xeb931184, 0xe1a63534, 0x6d52dece, 0x0d0a7ba7, 0xad3e9b10, + 0xb4e3d6f9, 0x45259d3b, 0xb45d240d, 0x14ae8cf3, 0x3de37257, 0x5f6ef15d, 0x8f251777, 0x9cfcc6ed, 0xef2c682f, + 0xca8fbbc9, 0x5d55ba4d, 0xdd9acea7, 0xaab9e742, 0x9f5b921d, 0x54a4c569, 0xd045b7f8, 0x9388f4ea, 0x3926951e, + 0x65ba07de, 0x5933bb97, 0x24f8b958, 0x3bb58243, 0xb0ba712a, 0x3e338a24, 0xa1c4d83f, 0xa4ef0762, 0x51da636b, + 0x47bf0f71, 0xe42bc4bb, 0x64913f4a, 0xad893a7d, 0x2c13fc6f, 0xa303768b, 0x1ced8a68, 0xbfd2de01, 0xa9a8d05d, + 0xc4bbf3c3, 0x3d86d734, 0x615df4ed, 0xd7cdedb4, 0x27586c5d, 0x0e157db2, 0xfec121e1, 0xcf678aac, 0x69eb7bef, + 0x50e2ba1b, 0x10cb5c2b, 0x31eed13a, 0xdfe2765e, 0xa3355ba6, 0x2b120ab4, 0xfed0acf3, 0x64aa1854, 0x6382bf32, + 0x5bc7566d, 0xca7e6fcc, 0xfbd28dac, 0x5dd1e0ff, 0xc1b3bea0, 0x89719d43, 0x577399d1, 0x1f80f404, 0x3429e77d, + 0x1df45ea6, 0x38b17c71, 0x5f173db2, 0x3782bf81, 0xf470da6f, 0x0d27ee95, 0x30f48b38, 0xcdf40f2f, 0xd6ba777a, + 0xdacacbc6, 0x3dead54d, 0x92b538e0, 0xe3e59070, 0xedab8446, 0x607095c4, 0xd7433cc9, 0x109b2150, 0x2819befa, + 0x2f614ddd, 0xc60c38cf, 0xa12add85, 0x3a31be88, 0x0697219c, 0x54cb47af, 0x974e69f7, 0x844ddfb7, 0xea47f783, + 0xf9128513, 0x09246de8, 0x6b703c0d, 0x9f1578bf, 0x2b62d24f, 0xc8d05931, 0x332ee945, 0x102f54e1, 0xd6ddaaa6, + 0x65458036, 0xabfcfe19, 0x7e946b22, 0x70ba61d2, 0x28371072, 0xd193efe2, 0xd5ce807f, 0x7599c19e, 0x4fc49fa8, + 0x80274597, 0xb90378bb, 0xa5d3bf06, 0x5a139f47, 0xc9e3ec13, 0x5d3f5634, 0x8595d205, 0x4703edb9, 0x291621ff, + 0xb00fb5e7, 0xaf5041ae, 0xe45b3935, 0x4b2885ba, 0x4b700415, 0xcbf7e89d, 0xaa05d3ce, 0x76f7c2e6, 0xffd20bc4, + 0xd769cc0c, 0x07370a02, 0x2cc921f9, 0xc3dd3164, 0x6b33a502, 0x6c2df74d, 0x748c65b3, 0x2527b042, 0xeb9d0afa, + 0x11d0be03, 0x90f4bb1f, 0xcaec25fa, 0x131fe4d3, 0x116b141c, 0x082494c3, 0x02aa2693, 0x89c9baa9, 0x50f7b3fe, + 0x4bfd882c, 0x1b3678b6, 0x2dc9cd85, 0xd8254736, 0x6cc3bb56, 0x97a3ab81, 0x2814f297, 0xbc5fd3f9, 0x20368705, + 0x7aed5fe0, 0x802591f3, 0x738e253a, 0xbe81c8ea, 0xbc37af64, 0xb9e990eb, 0x3678fa96, 0xff1ffb33, 0x4b4833be, + 0xaa92b1d6, 0xf0fcd803, 0x38ef1a5a, 0x871d49ec, 0x0ea8edad, 0xf97eef96, 0x369e2a84, 0x35a7596a, 0x6ad4a12e, + 0x35a2b3e3, 0xef73ac33, 0x9ccf8676, 0x9882c671, 0x77f90fd4, 0xc9257de3, 0xcad269bd, 0x707119b3, 0x3869abac, + 0x0bc8ec72, 0xd1df8d92, 0x3f8c599d, 0x9f07a58a, 0x9c99f0b1, 0xa95e16c2, 0x768a273b, 0xab449532, 0x66570877, + 0x4ce63e90, 0xbb1974b1, 0x705fb545, 0xe9c60456, 0xc25f00db, 0x4456e1a2, 0x315f6e59, 0x02e30bde, 0xbf8433c2, + 0x4a6b845d, 0x2007ad8b, 0xca189242, 0x3f4aba62, 0xfc47da79, 0x35053230, 0xaf82a660, 0x1082c1ac, 0x87a30e67, + 0x05bf092f, 0x51979f27, 0xdbe16187, 0xed6f43cc, 0xb227c533, 0xb434380e, 0x6db6c073, 0x02769814, 0x061602e0, + 0x50a4a547, 0x93567e6a, 0xd9c5c192, 0x1843f1b6, 0x632fc890, 0x18cace06, 0x677dd22c, 0xe81455cd, 0xefe3f3b4, + 0xf4894a1d, 0xd55bdb3c, 0x88eb2ee5, 0x02cd2fca, 0xf7b8d619, 0x2df149d6, 0x54c59142, 0x27837cb8, 0xc041c8c0, + 0x70ec0acf, 0xe540cd93, 0xf6dd4aa3, 0x4f0241c3, 0xff240333, 0x64e4b7f9, 0x9701824e, 0xc7c04c00, 0x476ddefa, + 0xb2bdc363, 0x29aae738, 0x0d10cc0e, 0x690e68aa, 0x2a3f7759, 0x86c41029, 0x4d72a2b7, 0x0e0d8b67, 0x0c23f2ef, + 0x347517dc, 0xc2d0fcfb, 0x8bd912ca, 0x78c20d3c, 0x9376a849, 0x90e513b1, 0x652de0c3, 0x84c62133, 0x55366d87, + 0x8b58a5c1, 0xc037517e, 0xcb6cde78, 0x7a30ed9f, 0xfd260caf, 0x5891fa6d, 0x2617b568, 0x57ea8104, 0x2b3a165a, + 0x05c276f4, 0x455ec798, 0x631528a9, 0xe1d4c56a, 0x84fdcd2c, 0xf4ae27ef, 0xdcd94a35, 0x3d1905b0, 0x9534c555, + 0x827db41e, 0x48d064f9, 0x088ef5b0, 0x5ce28fc3, 0xd9ee127d, 0xdc6d50fb, 0x46f087fa, 0x3110a381, 0x0e17fcdf, + 0x9ddc35c1, 0x3da838aa, 0x181ddedb, 0x43f64209, 0xa6796fd2, 0x8e7c42f1, 0x199d14a7, 0x619e9139, 0x2c32321b, + 0x16a98c6a, 0xf82f21be, 0xb00713b1, 0x599578b1, 0x5b8258c5, 0xdc47bf44, 0x5597ede3, 0x4f39b321, 0x82b478dd, + 0x444dbe01, 0x0b1c5d67, 0x58a83b5b, 0x0ecdcb87, 0x1ab93a3d, 0x0c3988fc, 0x00772e25, 0xf0e8f213, 0x40530261, + 0xf5a91b82, 0x70995d2d, 0x7f2a49c6, 0x94858eb6, 0x98c714a1, 0x30ae8d31, 0xa85d4790, 0x7871d408, 0xfdbced1a, + 0x3d24bf6b, 0x1f6f929b, 0x9c3de251, 0x965ca7a8, 0x70187a55, 0x11e2f3f0, 0x1292d156, 0xa6e4e29f, 0x1d29ff5d, + 0xaad5b50f, 0x49d303d8, 0xabfbe535, 0x2e7b994f, 0x305dee9e, 0x6f3b3343, 0x1d085b23, 0x9ec740a7, 0x658dea49, + 0x03796ef1, 0x66712caf, 0x885cd4e9, 0x0c51632e, 0xbc2c318b, 0xc2d25eff, 0x08daf7e1, 0xa3868abb, 0x8865ec61, + 0x21300d2c, 0x378bbe50, 0x176bdbc2, 0xd094b59f, 0x48a359e6, 0x3623904a, 0xc5fe5b0f, 0x74946caf, 0xc7bb0241, + 0x7affceb3, 0x3972f26c, 0xb3da4206, 0x0f069f59, 0xade2fc9f, 0x6f3c5fb9, 0x8298eaad, 0xbf399d97, 0xf3c8b123, + 0x20d2c8b8, 0xe4b786cd, 0xb8b3a04d, 0x3a0548cb, 0x87ae79dd, 0xc9728b7b, 0xae853071, 0xd28ea15f, 0x0aff4521, + 0xd094cd06, 0x6778636f, 0x76c8c2f8, 0x11005677, 0x7506b9ca, 0x7549fdd5, 0x3dd0bcce, 0x3ab6ff19, 0xcb7a902f, + 0xf7f6b2c5, 0x7819d76e, 0xca03356b, 0xff977629, 0x2fe3b80b, 0x5ff53c12, 0x03211b65, 0x1b173b27, 0xbb178a78, + 0x45acb920, 0x65ba3128, 0xccb2479d, 0x373b0b21, 0xecf0f652, 0x95695269, 0x56924600, 0xc71f72e4, 0xb6469f29, + 0x632eea19, 0x1554f671, 0x79e77da5, 0x85f671a6, 0x01adf60d, 0x425636ca, 0x3e513d71, 0x78f8dfc1, 0x2944df28, + 0x9e73fa0e, 0x39e085cc, 0x06fe2e0f, 0x2cfa0698, 0x2b6dc51e, 0x4d38a25d, 0xe2b45fcf, 0xe113da04, 0x118e6f1b, + 0xdbf4621f, 0x1bf079b4, 0xdf964e35, 0x9c3d99a0, 0x89da4bf1, 0x9d22af99, 0x9d4ca58a, 0x46f36d56, 0xc9130996, + 0xf0f5ce65, 0x0089a4c8, 0x67d0294c, 0x479c730f, 0xb5454748, 0xc518336d, 0x11b9c2e2, 0x7fbb75bd, 0xd18787be, + 0xff7dd7ee, 0x3994e139, 0xab5da366, 0xf686422a, 0xdf5c59c2, 0xc0f81a62, 0x91939382, 0x67c1836a, 0x1066a06c, + 0x2edceabb, 0x77603560, 0x7ca466bf, 0xb7b640fc, 0xba9986e4, 0x5561d79b, 0x595d2744, 0xb4dc5dda, 0xf59ee027, + 0xd9784ec3, 0x56807008, 0xcf6e3ceb, 0xd3a832f1, 0x2e9ebd89, 0x1013e0c7, 0xcb371364, 0x227ea912, 0x54fbbf1b, + 0x7a5d80e9, 0xe0d0c249, 0x93197b63, 0x01d45ce7, 0x491e524d, 0xf61c05bb, 0x1cb70c68, 0x610c66f9, 0x9ca168c6, + 0x115b9803, 0xfe5f8ed7, 0x94e46bde, 0x3508ef97, 0x082a0aa2, 0xb3377de6, 0x9f6c527b, 0xf52f5715, 0xc9f017a3, + 0x51d280b2, 0x64d85481, 0x1e132399, 0x404ca568, 0xa144a9ac, 0xda4f3bff, 0xca8b0253, 0x1f597994, 0xb9934026, + 0x97101dd9, 0x6dee8b2f, 0x300f333f, 0x08f663b5, 0x208c7aff, 0x72777d6b, 0x7815d184, 0x6ee341d9, 0x82740f33, + 0x78edb4cf, 0x29f5cda7, 0x54a9e9a8, 0x73f360c0, 0xccdf8ec0, 0x7ad65d10, 0x5f2adc2f, 0xfadeea73, 0xdecae708, + 0xa6362653, 0x79edcf4f, 0x81cb4ba2, 0x54939b43, 0x0af841d1, 0x61687c21, 0xfcd48e88, 0x2ac28381, 0x692efb63, + 0x6805d4ab, 0x97968b51, 0xce61c97d, 0x578aeebb, 0x2c23838e, 0x59f83c38, 0x786c2bb9, 0x62808eb0, 0x6c242fe2, + 0xd0ace6a1, 0x74711f5a, 0x4cc83956, 0x8ae09d15, 0xbb200162, 0x7bd6ab07, 0xbe18f9f8, 0x2ceaf921, 0xf645e5b5, + 0xc560e2b0, 0xdbb6f202, 0xca886270, 0x565bdcc5, 0xf78938d8, 0xaa82ed57, 0x0f0f1102, 0xb4bd7d6f, 0xe4fb3c3b, + 0x49acb9c9, 0xd24fa70f, 0x6ff4ef0b, 0x393305ad, 0xbe685ff3, 0x3ab22d33, 0x0f9d77ec, 0x82057246, 0x34738544, + 0x83d5b3f5, 0x2e4566b1, 0x1e0e413d, 0x07c0480f, 0xc42b3911, 0x11ed18b6, 0xddd9eb36, 0xaa3c4845, 0xfd4712da, + 0x47aa0f32, 0x550a9f11, 0xc73688d9, 0x35484c67, 0x93f686d2, 0x82d180ad, 0x6052dd6d, 0xe0ab7c30, 0x04890afa, + 0xedefdd4b, 0xf193b8a7, 0x43cc9c93, 0xb5ff5d88, 0x0d891871, 0x053490b2, 0x2e7c7315, 0x6e1aaef3, 0xab401fd9, + 0xe9088360, 0xd968ce67, 0x60f14b1f, 0x8342c256, 0x77157b04, 0xb4061693, 0xdd09ac0c, 0x756faa0a, 0x9f1210dc, + 0xf54851bd, 0x0bc9d31e, 0x784bb5ff, 0x1c3b52c7, 0x117e99fd, 0xacf69c26, 0x90f328d9, 0xc838f8e4, 0xa0ed300c, + 0x3a149fc3, 0xa9a7272f, 0xd89fcbce, 0x94b54b16, 0x173eaae5, 0x255387f7, 0xb441de91, 0xb03808c5, 0x00c0f990, + 0x7011939c, 0x9dfb16a0, 0xd7defc13, 0x14a74e5f, 0x629a5fd9, 0x864e96df, 0x4fa547eb, 0xdd3cd358, 0xffccb53e, + 0x02cf46f2, 0xa5c266eb, 0x5515a4a2, 0xd1b6a90f, 0xd42ebc1f, 0xe4f093ce, 0x84f5fdee, 0x46073f90, 0x6faf7ed5, + 0x3ce1d8c5, 0x456fd312, 0x501473e8, 0x08e30001, 0xf8e4cdd5, 0xdfdfe3ef, 0x9bc0e7e5, 0xd92bf6c3, 0x3819ee12, + 0x13c123a6, 0x59942796, 0xd96d16c1, 0x36aed636, 0xaa981749, 0x8d7da275, 0x909ced43, 0xdaea7ccf, 0x78e1f438, + 0x45d85e2a, 0x4421fb95, 0x1acd9110, 0x5acbafd9, 0x9449077d, 0xeb8eb063, 0x3d32ab9a, 0x3e3f5703, 0x632f44dd, + 0x33bafcd8, 0x9cfb58f9, 0xd74a4090, 0x6056a0b0, 0x111f7924, 0x2a44ad13, 0x8308fc7a, 0xcff8ace0, 0x713a3376, + 0xbae74fad, 0x695981db, 0x73965dff, 0x17ba057a, 0xb3610d5d, 0x61e54a29, 0xabbb023d, 0xef459c90, 0x4f410c3e, + 0x033bd23f, 0x4c871021, 0x84524482, 0x9b1bad7b, 0xa6403151, 0x23e26c75, 0xb7db34e0, 0xde00806b, 0x3465a3b7, + 0x3e61db34, 0x09c64bf9, 0x0d75c43a, 0x2ba6855a, 0xae88263f, 0xf0d37a05, 0x81dc5bdc, 0x7bf437eb, 0x46e5b246, + 0x4707aac5, 0xd463fe1f, 0x51d7e86d, 0xc75c084e, 0x0efe7bbe, 0xd818b30d, 0x3cf57d78, 0x9d7b5c84, 0xa2b2f863, + 0x2f67b0da, 0xc6dd0686, 0x7cea8a38, 0xfe47bd4a, 0x6a4141d1, 0x85a0c498, 0x729887d3, 0x09af188e, 0xffca25c9, + 0x353cbe6c, 0xc5478a3f, 0x13d1b343, 0x57de5913, 0xea33aa9a, 0x95c92aca, 0x2a16caf9, 0x3877ea44, 0x21be04fb, + 0xe31d25b5, 0xe6d0a628, 0x6a074c17, 0xcb11ed55, 0xf7a2a7b3, 0xa3a532fa, 0x9b23b0b0, 0x66d42bce, 0x924a5cba, + 0x3ee1be46, 0x2f2f56f6, 0xd9daa228, 0x5bc964f3, 0x37e1d21f, 0x60cec4a8, 0xf2464323, 0xd8dc5f8e, 0x975501c6, + 0xc5c69abd, 0xf5d33033, 0x4ba0d56c, 0x98b01f5a, 0xdee8b9dd, 0x1e744b6f, 0x0808b4e5, 0xe6223460, 0xa92e65c3, + 0x51d5b059, 0x4c4cde74, 0xe3c41c95, 0xb97b4431, 0x4b398d07, 0xf43eed48, 0x12fc8557, 0x7a39be28, 0xa01c75c0, + 0x47353568, 0x10ef7ff0, 0xcfa70d0f, 0xec15f7cc, 0xcf4b9991, 0x0b46c1da, 0x33971e3d, 0x54ceef6e, 0xed821e62, + 0x041cd2b8, 0x4c31199c, 0x444bf1dc, 0x81f76dd1, 0xaa42bc6d, 0x0f6832ef, 0x1dc1510e, 0xbd9cf717, 0x373fd8d3, + 0xece37b85, 0xeab6b1be, 0x0796bdce, 0x628409de, 0x2271202b, 0xf327a14b, 0xbcae9308, 0x3ae47313, 0xc08b6580, + 0x23e0c5fa, 0x7547255d, 0x81c97926, 0x4907976e, 0x3e287e8c, 0x848b6849, 0x92adfa9e, 0x884def74, 0xedc5a37e, + 0x9d12424a, 0xa879a56b, 0x347b4fb3, 0x304bc84f, 0x2f3f48d2, 0x8feb8f42, 0xd7357162, 0xb2c79962, 0x5ec71503, + 0x4d7b3f84, 0xe8e44647, 0xc3a73484, 0x0ae98ba3, 0x8d2d567b, 0xed6addc5, 0x59ccd259, 0x3b7eebe5, 0x67a3b984, + 0xcf4a490e, 0x6c077d72, 0x04c2675f, 0x5082c437, 0xb87145e0, 0x994e23e7, 0xe822e4db, 0x6c8b0e0a, 0x8dde5189, + 0x8abd7325, 0x29d52a34, 0x56633981, 0x8ee3685e, 0x091daac9, 0xf3f7bcfe, 0x9c18a8d7, 0x92ad7208, 0xfcd8c638, + 0x6a6bfc52, 0x73d0de49, 0x331d9cb4, 0x0f87e004, 0xdb612447, 0xa2eaf689, 0x35601f6a, 0x820b476f, 0x3aaf51de, + 0x976118e2, 0x96598dba, 0x6679c052, 0xf13973e0, 0xcfe2bb79, 0xc9896d7e, 0x79ecfc86, 0x76d317a8, 0x5f51652f, + 0x0a4db1f7, 0xdd110245, 0x17b3d227, 0x770dd23c, 0xd1a8e957, 0x072b3152, 0x2fb56445, 0x643709f0, 0x296d1819, + 0x71430d68, 0xcb6a3841, 0xb476e4ff, 0xc5be92bd, 0x8c37971f, 0xf947c33d, 0x12596c4c, 0xff0fa4b7, 0xec067ca5, + 0x838ba6bc, 0xe11de645, 0x1addd7a2, 0x60dc6c18, 0xaa6afa7a, 0xd5162982, 0x7ef36c81, 0x9af58982, 0x55419553, + 0xad838eb0, 0xbd773d16, 0x016033a6, 0x682296a9, 0x04438398, 0x00e0f945, 0xeaade7e4, 0x82788d6b, 0x8d31a08d, + 0x7f070c93, 0x2ba31a22, 0xfbd87f49, 0x2b53afd8, 0x260d179a, 0xb0fb22f4, 0xfdea6b0d, 0x370cfc91, 0x04519835, + 0xb4af74b7, 0xa4bdf02a, 0xb5ec62a1, 0x0db9f3a4, 0xc76997e4, 0x5d9e5e7d, 0xbce2fc38, 0xc2c19e12, 0xd4f0813b, + 0x90b33d28, 0x9105ffa3, 0xce53b706, 0x3df0aa0f, 0x2688805d, 0x9c45531a, 0xc93bde50, 0x66b72aa6, 0x939707b7, + 0x0a5d38f1, 0x902541bd, 0x7a426f0b, 0x91f39a54, 0xe2eeee19, 0xde9059f5, 0xccdcf5f7, 0x4787f752, 0xe52519f3, + 0x02447e29, 0x8027d940, 0x9e3a4c09, 0x73a443b3, 0xc0ad2584, 0x208399c1, 0xb19fd2c7, 0xace95a28, 0xcdad9cd7, + 0x0b335dbc, 0xd03107c3, 0x344d956d, 0xef970435, 0xc34be6a3, 0xb07eac5b, 0x45f5f534, 0xee989762, 0xd8008366, + 0x2cf75f00, 0xc96d2db3, 0xcf519a73, 0x1f47ff5a, 0xa1cdc421, 0xec53805d, 0xd89ff0e3, 0xd9128a03, 0x0a4985ad, + 0xddf33877, 0x5c68b1b5, 0x46c5189c, 0x917c1d6c, 0x99e1c81b, 0xb01020d0, 0x5c36c66a, 0xa2bcd529, 0x36374072, + 0x5517a3ad, 0x35288958, 0x412320a7, 0xf52801eb, 0x5108a1fb, 0xb341b2e2, 0x571f2815, 0xcb348414, 0x1c622f83, + 0x4bb9e4f3, 0x1a50660c, 0x095ddafd, 0x96e03fea, 0x3cb335f8, 0xe0567a81, 0x9ec99458, 0xf7517da1, 0x34cbd123, + 0xea101e9a, 0x42f3d271, 0x23f2ed7a, 0x0bec94e0, 0xc9f32022, 0xe8cabe3d, 0xb11faead, 0x3ada3fd2, 0x90b47bb2, + 0x7950f0dd, 0xfae6ebef, 0x67cc144d, 0xd9ef4a93, 0x184cae72, 0xbf019145, 0xb6bfc32d, 0x263c463f, 0x695ef3e3, + 0x645cf628, 0xe52cb4b5, 0x5a9ae2e2, 0x938b391b, 0x39122a5e, 0x86255564, 0x670073ae, 0x6550471f, 0x00106171, + 0x19c28946, 0x0388d720, 0x50eec9ed, 0xfe3c88c6, 0x46f2adeb, 0xeaddff30, 0x85dc77a1, 0x8c31a3c0, 0xa9112d7f, + 0x400794ea, 0xd734acc5, 0x9c2efee4, 0xf4634515, 0x9a962ea7, 0xb8d63b86, 0x6a848594, 0x7a177ba5, 0x0a5233e1, + 0x2e5a3aad, 0x0d61e12d, 0x4db8811d, 0xcc76edd3, 0x57d1f3ca, 0xc69f65f7, 0x6e0d3531, 0x2e1e1fa8, 0xdcc3807a, + 0x8119a819, 0xdfa14aef, 0xfe9bdba2, 0x17c7f0f3, 0xdcd8c400, 0x4ac4fa93, 0x4e3fd63e, 0x6a45228d, 0x63caf993, + 0x5f5d5a68, 0xdc81a5b2, 0x9ad360b9, 0x8ec48edb, 0x7d23ed4d, 0xc1cbafae, 0x825a7afd, 0xd6ba2ff2, 0x33619978, + 0x6fb235e0, 0x383645b6, 0x4bed7b56, 0x7d8a3321, 0x4c691db0, 0xbb33fe1b, 0xd9825540, 0xd5ede301, 0xef39125a, + 0x06699b3a, 0x8b4fb827, 0x2edbfdd5, 0xaa0e5b09, 0xf06e5eb8, 0xa4f559b9, 0x769f4e25, 0xb29da124, 0x42be2c2e, + 0x86dfa607, 0x4be4552b, 0xa19e474a, 0x1129a642, 0x63d573fb, 0xdceb2797, 0x8559dd30, 0x23570ad0, 0x7c3295eb, + 0x30cbe2b5, 0xf9ea238d, 0xe09a48e1, 0x932af8ee, 0x68d13e05, 0x4495681c, 0x66731036, 0xb7fac76c, 0xdd8d1e3d, + 0x01ef4508, 0x410e1a1f, 0x20c9cb61, 0x3e269e13, 0x3af0bab8, 0x1a9ed539, 0x551fef21, 0xf125e1d3, 0xdf213a33, + 0xcd7ffccb, 0x6eff26ae, 0x208542e4, 0x686e76b9, 0xb8c09391, 0xdbd16b5c, 0x4c329b3c, 0xf7e34dde, 0x09b6b3e2, + 0xcb5acf48, 0x4f6f21be, 0xaadc8202, 0x1653c80d, 0xbcea6ac2, 0x0d841dba, 0xe3060a18, 0x0148271d, 0xa7c74be6, + 0x3b2eba3d, 0x10062660, 0xe92ce21a, 0x34f41ea2, 0x0f174ff7, 0x37719662, 0x03233ca5, 0x8ad8e3da, 0x63045543, + 0x883f766f, 0xa401c57d, 0xed199f05, 0x29b0249b, 0x1d180f03, 0xb68f08cd, 0x0630c564, 0x5337c058, 0x3d58a58a, + 0xd5838583, 0x6fa3f83b, 0x7fe790cb, 0xcfb91862, 0x7c35254c, 0x28342e8b, 0xd95954c4, 0x39bcba7a, 0x0db8a9cf, + 0xad3ff7e1, 0x2f37fd70, 0x731a6e3b, 0x27575ff1, 0x771a9916, 0xfadf74f5, 0x5efdf92e, 0x1844908c, 0xd99c51c4, + 0x444a790d, 0xc069ae12, 0xfd68d527, 0x192f8897, 0x5a9d1bc0, 0xe7f405c0, 0xeaa8421f, 0xa49649c1, 0x23519815, + 0x2344de50, 0xcee992e0, 0x35031bec, 0x4ddbefcd, 0xecd35d29, 0x82b2892d, 0x4cc86b05, 0x30c3ab43, 0xc987004a, + 0x8d7c647c, 0xd055e83a, 0x6054093c, 0x6a268238, 0xbc158dde, 0xd2803da7, 0x601e85d6, 0x705885c3, 0x80a7c9de, + 0x3613caec, 0xfcf60bb0, 0x0b22787f, 0xdb182309, 0xa953323a, 0xfaec91ea, 0x3e295a48, 0xc19c9927, 0x6c0a7534, + 0x1e7d3082, 0x9ad0fe82, 0xe6e852b2, 0x9c2d02d7, 0x3af4753a, 0x76860ca8, 0xda9b465f, 0x8db14729, 0x7a4d63b8, + 0x3053c96b, 0xcd1b4bc9, 0x48739385, 0xf4f6848e, 0x7d3756fe, 0x9e8604ef, 0xbd9b980d, 0xa36deb0b, 0xc4f105d2, + 0x83ea7dbd, 0x67e229ba, 0xfa3ea2c8, 0x255d4e3a, 0x87b0bc34, 0x33711db7, 0x670ccfd1, 0xd6bcfccd, 0x17d526c8, + 0xdfbc04bc, 0xe1d092e2, 0x7230ce22, 0xa030828a, 0x3e794c27, 0x699c2e3f, 0x64b08c73, 0x48181440, 0x79f3ad8a, + 0x65e04f3b, 0xb18b8404, 0x3660562f, 0x3b95ec1d, 0x7bf89d19, 0xf02d5a65, 0xfb995fae, 0x522d9861, 0x2e5aec40, + 0xc7b15d87, 0xe7806c00, 0x4239155d, 0x699497be, 0x1b3d9d18, 0x4cc616c8, 0xaf7ccefd, 0x7a7565e8, 0xdc981526, + 0x5b7ebf2d, 0x55bc731f, 0x12e8c419, 0x99e7fb79, 0x24e7d1f7, 0xb0f32935, 0xfd52e834, 0xf4ed4796, 0x4f15b87a, + 0xd2cac56e, 0xb8440ae7, 0xbc7fce69, 0x6f079830, 0x75cf085b, 0xbc741d7f, 0xb6a86b54, 0x68373fda, 0x5002522e, + 0x54a5c80e, 0x9c20bcbb, 0x297880af, 0x36a60447, 0x793b9682, 0xb4f2a25a, 0x33e27e9e, 0x55a2333f, 0xfb2d9319, + 0x3e08b5f8, 0x74656cd6, 0x42b20744, 0xe7f7fa16, 0x4b77cb01, 0x6cecbca6, 0x51294f4e, 0x490f02b8, 0xa690fef1, + 0x806600e2, 0x9985ab6a, 0x80d06304, 0x4d1d9c84, 0x9d7d6e47, 0xb0eb58b6, 0xddb5a3e6, 0x7ca2793f, 0x74935459, + 0xb2edf6fb, 0xa978da57, 0xa14557bb, 0xa2c4eec1, 0x966113a0, 0xd6ea4e41, 0x848fd562, 0x7254d322, 0xa1cd4d69, + 0x7e36349a, 0xee88702e, 0xdd2bd5f2, 0x006b4ac0, 0x8b21629b, 0x95562658, 0xceadc9c9, 0xfe9720a4, 0xa7192706, + 0x78c40ff1, 0x381f0d67, 0x759118ba, 0xdd6d8f8a, 0xd5f7e09b, 0x17d2bcbb, 0x1fc8ebd2, 0xc3bf01d1, 0x4cdd9f60, + 0xef10701c, 0x6af0ad8b, 0xd126e178, 0x7f1741ec, 0x8a549ac2, 0x84409796, 0x6e2cf5de, 0x78c7f561, 0x14962423, + 0xdafd7d93, 0x5e1f5b8a, 0x12ca6f2d, 0x31db5384, 0xdb4348c6, 0x1a7d692f, 0x85f1d309, 0x7d0b8f2a, 0x0913abd3, + 0x68371715, 0xde43a73c, 0x58f37aca, 0xcd53541a, 0x7fa042a2, 0xdf4bb642, 0xf56ab710, 0xa38e630f, 0x918a1a21, + 0x5abbbdd6, 0x9a320b61, 0xc40b39a5, 0xa837cca2, 0x2307a350, 0x5e1f2fb4, 0x6c69d072, 0xe6bcc350, 0x561c2f97, + 0xfeb7e742, 0xd774bf53, 0x40dcce41, 0x9ba6c6a7, 0xa0acfe63, 0xc65701f0, 0x4dd12694, 0x1090e773, 0xd15f4760, + 0x643b8a5b, 0x0528613d, 0x7f418c32, 0x45e5f4a6, 0x4c5572ab, 0x122986ce, 0x509fef67, 0x390bf215, 0x92450d3a, + 0x7b4997a3, 0x988ad784, 0x6be94e61, 0xda6ec42e, 0x4e121b09, 0x4a8df335, 0x0e7894b6, 0x9112abfb, 0xab050e51, + 0x0071d8e5, 0xa8484834, 0x5e9c2da9, 0x66a60aea, 0x0b28815e, 0x47f607b7, 0x941c4040, 0x134e71e8, 0xe3d8b044, + 0xe19804be, 0xf5593a71, 0xc3ee3723, 0x4df837a0, 0x822e6cc5, 0xcdd3e17b, 0x46b9ebb8, 0x70c0fac7, 0x1623b864, + 0xf147e081, 0xdf5a66e3, 0xdbffcf4b, 0x4d58c2b6, 0xbd8a9d5d, 0x1a655dfa, 0x3cc17bda, 0xe74be358, 0xefd9ac80, + 0xf9d262a7, 0xe95d90a2, 0x8c46a471, 0x26cd79e2, 0x2a0f7416, 0xf45191bc, 0x30df6471, 0x384ada5d, 0x1aec6fa4, + 0x419cb779, 0x06199ac8, 0x4670fe8e, 0x1de2e2a0, 0x7b214649, 0xca6404f0, 0x88966fbb, 0xaa4db4f7, 0x6ca350ef, + 0xb4ea2676, 0x51cf1304, 0x38fdd7e0, 0x3187c4a8, 0x2efc2bc2, 0x900145f4, 0xe1c20433, 0x6d8cab4d, 0x152ba52a, + 0x5edc4587, 0x156a72af, 0x9d744db6, 0x793895d5, 0x0e4bc3d5, 0xf1ba354d, 0x525b91bb, 0x800b5e43, 0xe92b58b8, + 0xd1f8384f, 0x0d03cc11, 0x2683f03b, 0x33d7a59e, 0x7929df55, 0x9882c4e1, 0x00985ef0, 0x0b9f97ee, 0xe0a3622e, + 0x5b59268a, 0xcf9e5d2d, 0xaabe4c9e, 0x5033b7af, 0x0206f484, 0x6a40f318, 0xab22892d, 0x5b28906f, 0x4cec4d2b, + 0x637ffccc, 0x59ee72e8, 0x9e87a43f, 0x7f6d408d, 0x33c1d426, 0xdf7f122e, 0x18aaf2cb, 0xb7905212, 0xea76f66e, + 0x7c1fd589, 0x969650fd, 0x80bae88e, 0x7e7b8d42, 0xbbb3c132, 0x7c4c2c44, 0x4db7d39e, 0x70cb0fb0, 0x4b0887b2, + 0xe3bc9500, 0xf0384e53, 0x72407328, 0x55c9cf39, 0xe382403a, 0xc110ca7a, 0x41b49adc, 0x7289f755, 0xc94d27be, + 0xf12dc3ab, 0x11c82425, 0x2af5a966, 0x2fcf7faf, 0x5b32e892, 0xb8c25ac3, 0xd7a7fd1a, 0xdb3df8cc, 0x1fe44443, + 0x3b93e734, 0xfbe1483b, 0xdadcec51, 0x619d7613, 0x8d361f6f, 0x7a48c07f, 0x977235dd, 0x2beebb5c, 0xa7950be4, + 0x310d8ebc, 0xdca5c8c4, 0x1494bf65, 0x4f28daad, 0x1cae768c, 0x75a93496, 0xf38ebfa9, 0x49afe7c4, 0xdac54e0d, + 0x5b357d56, 0x2807cce1, 0xc1329381, 0x96b0b03d, 0xfd8a8a92, 0xe10c8d63, 0xf91157e3, 0xb127af1e, 0xf8a45849, + 0xe8866465, 0xaa7627a0, 0x312deb0e, 0xc255a23a, 0x6c9f0238, 0x2515e96d, 0x666635e6, 0x8c130812, 0xca7b645d, + 0x6fd41c70, 0x32e9e7e8, 0xcd7bd228, 0x636e6a67, 0x662fe84e, 0x4d865eae, 0x14c7bd0e, 0x97420037, 0x720b657a, + 0xd5b4a8f6, 0xc73a4e6b, 0xcc3284cd, 0x94bb29b0, 0x4b099584, 0x11c50eeb, 0x622dab64, 0xea13536e, 0xce9f66ff, + 0x19c31431, 0xbc73f17c, 0x47a819e4, 0xf3e46dfc, 0xee283dd1, 0xe1184ada, 0x4a20db6d, 0x5ca7d9cb, 0xd31f3da8, + 0x23f09692, 0x34b4a4fc, 0xee321b7a, 0xde97645b, 0x893d0c67, 0x91a3506f, 0xc450e22f, 0xa3f0293f, 0x8ea092fa, + 0x5e7a26c1, 0xfec142bd, 0x29853da7, 0x5b37cab1, 0x109c4f68, 0x0d56d0c7, 0x2c39c7d6, 0x47548f2b, 0x06d933d7, + 0x7cfa1ea9, 0xefc91686, 0x363b10c1, 0x73c0bad9, 0xcbdca727, 0xcb998b22, 0xb230cd31, 0x452fadc2, 0x1f708994, + 0x6e224460, 0xd2a4ef00, 0xea6c4373, 0x56baac0e, 0xbc3122a3, 0x80576836, 0xeec9744f, 0xadadf3b0, 0xb570bf47, + 0xc42b695d, 0x0a321fac, 0x495251b1, 0xb02d130c, 0xf3865cee, 0x87dfae55, 0x0920a049, 0xe7e066fd, 0x4336f01a, + 0x019692c5, 0x4b49ccc9, 0xe3a169c8, 0xae5cc8bb, 0x6d5d2e04, 0xa2709d36, 0x7f32715a, 0xe5e55482, 0xf9b81a33, + 0x76322084, 0x68c55b59, 0x3509f9ff, 0x0b2ce776, 0x09db7d0a, 0x411ac982, 0x282313de, 0x1dcbd9e4, 0x19903437, + 0xcf5d5790, 0xad201ca9, 0xa9b85c90, 0xcc636860, 0xcb452830, 0x9b268ae2, 0xb2b043a3, 0x86d3498a, 0x84268317, + 0x9b26e478, 0xcabb6672, 0x0e431429, 0x060ec051, 0x091541c1, 0x6a38a459, 0x42fa55bc, 0x7dfa9613, 0x2c51688f, + 0x28eba945, 0xab1bce4b, 0xbe57593d, 0x882267d2, 0x36fcf8e1, 0x6d4c662c, 0xe977f453, 0x9f82450e, 0x365458d5, + 0x81a87de5, 0x757b899c, 0x4fbc5b16, 0x95146396, 0xca72cf1b, 0x2ac05886, 0x30f2bda3, 0x4e9f6401, 0xd995c301, + 0x69f9bcae, 0x38ca10c7, 0xaf567e9f, 0x850f946a, 0x4af0ca48, 0x86d181df, 0xc496341f, 0x1f74b183, 0xc507a40d, + 0xa52dbabb, 0x6d907a64, 0x44065578, 0x6ccd4b59, 0xc725608f, 0x89b04343, 0x0bc1783d, 0xfa634fb7, 0x1d7a9ee0, + 0xff8b8223, 0x4f3a867e, 0x91096641, 0xf5dc1d91, 0x2d8b9153, 0x69661e42, 0x878b36a4, 0x1aa24a40, 0x2f9fd154, + 0xd69632e5, 0x69919023, 0xccddebbe, 0x426af554, 0xd6bd9913, 0xd76004e9, 0x77e75e0a, 0x5a2a04b8, 0xdd1e764c, + 0xfbfbb0e3, 0x62084111, 0x5d113eff, 0x2cb36b7b, 0xc1630f13, 0x6420f6a9, 0xd91771de, 0xaedf34e0, 0xfeceb491, + 0x8bc06e24, 0x03ae121b, 0xfb4af2b3, 0x8e015497, 0xae114849, 0xa96065bc, 0x0afb5999, 0xac3688fc, 0x41b9018f, + 0x6cedc6fb, 0xd5672384, 0xbaed5637, 0x829049d2, 0x8c861f11, 0x2e41b256, 0xda887e99, 0x42311701, 0x42450352, + 0x33712300, 0x1244f9ff, 0x5c415baa, 0x6cc92f8c, 0xed5668bb, 0xa1436690, 0x36165c77, 0x95272c3a, 0x266bb7cc, + 0x31757b7b, 0xdb27a6e2, 0x09761526, 0x448e5252, 0xeba802c1, 0xbf503681, 0xbcdf7203, 0x5d869341, 0x87cabfd9, + 0xd4c9d0bb, 0x76dfdab2, 0xf3437e0e, 0x67ce0641, 0xa3c736f6, 0x24fe3ee8, 0x694606f2, 0xd6d08b21, 0xaa9aef42, + 0xc3bd9d55, 0x0d2ee168, 0x2fbc7dc0, 0x08cd95e3, 0x2c72abd3, 0x24defc3a, 0x86e25fe7, 0x85280814, 0xe74c593f, + 0x32b3184b, 0x6ff97a94, 0x75e08605, 0xf02272ea, 0x6a62437d, 0x690bd9e8, 0xe4274e5e, 0x75ebc5f6, 0xa478f4cb, + 0xc2bb477c, 0xaa8ea079, 0x0f32d7fe, 0xe4602ac0, 0xd84ffd7f, 0xf6d3be03, 0x89a23d53, 0x25e42db5, 0xa8ec7708, + 0x5b228e72, 0x939da770, 0x91abe03c, 0x14a867b0, 0xcbd21f2b, 0x9ced748c, 0x544d35a1, 0xed937dea, 0x5784c91c, + 0x94254ceb, 0x66eb83b9, 0xcc0f3691, 0xa4faae28, 0xef66d17b, 0xf5080ce3, 0x814b9944, 0xa89bb40b, 0xbb5f57d6, + 0x60f6f524, 0x36ecfdef, 0xdf213fec, 0x0cb3ea58, 0xf5f987ef, 0x85cd770e, 0x03181799, 0x9f9d55eb, 0x774dbe1b, + 0x9f32b41b, 0x01e065ef, 0xcd1a043d, 0xe45b8265, 0x58a99c71, 0x4ef7105f, 0x5ea566b8, 0xafd6b376, 0xe2bd5db3, + 0x767b600e, 0x1430656b, 0xad0f2bfd, 0xf7a5fc9a, 0x021c8794, 0x35bb211e, 0x5499c2b7, 0x55dd2dba, 0x33836606, + 0xced6afe4, 0x65fc7417, 0x052f6f5a, 0x38211b02, 0x6facaaef, 0x7811b949, 0x878ee9d0, 0x67b6bda2, 0x201cfda1, + 0xa3405996, 0xe9fbe3e2, 0xf807c110, 0x197380c4, 0x6c08626e, 0x970f3d3b, 0x0013a304, 0xe1f5f791, 0xc1253cf3, + 0xc9e09b33, 0xc55c0f6d, 0xf444638d, 0x7946224f, 0xa8c9f869, 0x8d7414c8, 0xa9c72b39, 0xac7a1045, 0x07ffb55a, + 0xc5ec0cb4, 0x0e505e74, 0x8b4270da, 0x98e26454, 0x44f3be6b, 0xd27aa5d2, 0xc6d5461b, 0xedff9899, 0xf8191d78, + 0xb07c1219, 0x3b280102, 0xdf2e0394, 0xe8cc790d, 0xd8913785, 0xb9764fc4, 0x2087d599, 0xafdd5923, 0xcba270e1, + 0xe98b8469, 0xe0844e49, 0x71e6c181, 0x190c7014, 0x46f28201, 0xf3f8914c, 0xbc895e0d, 0x58698431, 0x8e32cfe5, + 0x86d9ac54, 0x2b0758c1, 0x79b013a4, 0xe782426a, 0xb6797a19, 0x69126728, 0x413c309e, 0x1b3c3759, 0xf0f96e3b, + 0x6596255a, 0xcdbc6485, 0x424013dc, 0x92e7758a, 0xb31e7f4c, 0xfe94a241, 0xbc735e6c, 0x09ff968c, 0xde18f875, + 0x3f30cd71, 0x8bff0675, 0x8523e27f, 0x25ddc1d4, 0x539ae921, 0xc4c74083, 0xc7052ad0, 0xb02b4248, 0x8577c790, + 0x9ff43424, 0x6b5bdb79, 0x6984e09b, 0x5c795b37, 0x807a6d3d, 0xebc90b27, 0xe48e9920, 0xeece2590, 0xac46b894, + 0x757fd04b, 0x86397ddd, 0xb8247b32, 0x179faec7, 0xdc64dc7e, 0x1ebf8cf1, 0x5e19d92b, 0x46072f91, 0xe9eda107, + 0x31653190, 0x2218f484, 0xcf787fdf, 0x6443aa80, 0x163cd10b, 0x17959c46, 0x0d4b9d41, 0xa125fa4a, 0x54202799, + 0x93d2b55c, 0xd473d27d, 0xee60ae48, 0x46044f6d, 0xbbe51d15, 0xa47e5d6c, 0x2db0e3eb, 0x78d4a1d1, 0x561b3314, + 0x56a7ad75, 0x79395d52, 0x5cccfd24, 0xd4c57c26, 0x062e1c86, 0xb5922b44, 0x4279565c, 0x14044485, 0x4c0b8cca, + 0x99127a9d, 0x984457e9, 0x730850c9, 0x1e149629, 0xc4f0c14c, 0x39626605, 0x5ae07050, 0x88c7868b, 0x6af8cd19, + 0x75671dec, 0x345a8b83, 0x4ba2a384, 0x94a86ced, 0xbe33bf88, 0x199f8701, 0x1d10308a, 0x790e9aea, 0x80a839b7, + 0x723231a2, 0x5fb8eada, 0xc1abace4, 0xc5b64a70, 0x0a355a46, 0xf21308b8, 0x157d814f, 0xc330b896, 0x18c93560, + 0x313470b8, 0x09b825a8, 0xcc0fabe6, 0xcab56c0b, 0xf92561e6, 0x05eb2381, 0x11d74a6b, 0xd7727751, 0xd47a4d1c, + 0x90ff7d46, 0x7983230c, 0x7a8acc64, 0xf1724c73, 0xd568463b, 0x28a46382, 0x69396b92, 0xf43774f9, 0x21420a1e, + 0x67edc252, 0x90efdfb1, 0xe6c38c48, 0xd837000b, 0xf4a58cb3, 0xc63ce3c7, 0xd8908c88, 0xf00ba8ff, 0x34cfa23c, + 0xdf0657c3, 0x6aef4baf, 0xecb309be, 0xabb553f8, 0x5f7bc881, 0x6263403d, 0xefb86821, 0x44bfe9e9, 0x25b47f5a, + 0x86f7bbc4, 0xbdcc7102, 0x82582b78, 0x58e6f67f, 0x18b62c47, 0x3080d3fd, 0x169ede1d, 0xb0e89570, 0x2f33e9c5, + 0x98c46d80, 0x45cc197e, 0xd4f575b3, 0x4f7ca820, 0x54cae5dd, 0x5dbf4bb5, 0xa34726ec, 0x2170b4ef, 0x3386197a, + 0x35e95048, 0x9625c05d, 0x742d851c, 0x3d8facb0, 0xc82988a8, 0x8f638115, 0xe40ca3c7, 0x004c9b91, 0xcd2b70bb, + 0x58910129, 0x71b7269f, 0x4a6c62d4, 0x5d04e009, 0x0dd2b2ba, 0xe85dba6d, 0x7559ffd2, 0xf1a7c899, 0xec53f268, + 0x5b6e5f58, 0xf09c526c, 0x93b4c39f, 0x8fe86851, 0xf74e94b0, 0xa68f2580, 0x0485c024, 0x3195b88b, 0xfeef0de5, + 0x0d676ffb, 0x597e827b, 0xd95fae4e, 0x0121b3ba, 0x4cb46cec, 0x8aa78ca6, 0xa1e46354, 0x1295de47, 0x56fad02a, + 0x9761682c, 0xf153fbe7, 0x979588e2, 0xf07bdb22, 0xd73f26f2, 0xf7e5ba21, 0x6e20c44f, 0xdb800cdf, 0x7fe2c319, + 0xdb76a43c, 0xe811d1f0, 0x4919d6c7, 0xe4e5c9de, 0x1fac7a0d, 0x272dbae3, 0xba251ee0, 0x9f77b5ad, 0x9040d561, + 0x7664d86c, 0x1ccee18f, 0x245c16d6, 0xc20a133d, 0xb97990ee, 0xe9f12918, 0x6cbbecbd, 0x93622e3f, 0x5e034f97, + 0x9d0f73dd, 0x8fc237f7, 0x7849e060, 0xff79b246, 0xe19d6975, 0xa520b979, 0x39c1e3ee, 0xdb84b8b3, 0x7c2add4e, + 0x4f20fa4f, 0xa2ec558c, 0x52dd5c11, 0xe9d10c1a, 0x7e15bfa6, 0xad379d7e, 0x94cb42f2, 0xdfc8d5ff, 0x390b8a9b, + 0x867b0b86, 0x465b6ccb, 0x46e90c94, 0xbe7c0411, 0xc586849d, 0x61956cf7, 0x398c9eaf, 0x6a9db152, 0x13e12c8b, + 0xaf449508, 0xc941087e, 0x2921404e, 0xd4413869, 0x0278ebea, 0xc05b6028, 0x5378ec2e, 0xc15e657d, 0x087707fd, + 0xc72fbb32, 0xa0943cd3, 0x8133defa, 0x28589d99, 0xf6a7a86a, 0x0a024221, 0x464fc7ae, 0x854df13b, 0xeadf325d, + 0x21f922b4, 0xd3aba0c6, 0xcfd854ce, 0x4310bc72, 0x3c0d29c5, 0xf98f6c20, 0x9fcacf1b, 0x292a68b6, 0x748620d8, + 0x0fd5afe1, 0x64006985, 0xdcec3752, 0x408637fd, 0x858fdeda, 0x693cf01b, 0xafa6089b, 0x52ff7f57, 0x1d37d993, + 0x8144dbc4, 0xe80fb23c, 0xf6bc1ea9, 0xf87aaba1, 0x1b0ef637, 0xb60e2133, 0x989f43ee, 0x9a18297a, 0x3661bbea, + 0x827169ae, 0xdfb4af51, 0x6464fdaf, 0x7c53e4ed, 0xe8d485ba, 0x48a20f1c, 0x9878b840, 0xc582384c, 0x1f3e233a, + 0x31c92756, 0x20c1f5cf, 0xcd5524e0, 0xcdc672b8, 0xc8239c17, 0x4c8dd28e, 0xcb671931, 0x4be0c20c, 0xbade3c3f, + 0x39708d00, 0xb38dbee8, 0x15e217e8, 0x539a7f96, 0xa29da515, 0xf5f5983a, 0x9bc386d0, 0x1412e51d, 0x1c4b8627, + 0x8433a8cc, 0x7abd6eb4, 0xe8442711, 0x8414e8a4, 0xabaeaa51, 0xd21229d0, 0x2dc3b728, 0xadd39880, 0xb3411909, + 0x1130e204, 0x3d30178f, 0x3579bc52, 0x8c8f0223, 0x57c83f8b, 0x6afcf008, 0xa5da3595, 0x57bff3c0, 0xf1c04679, + 0x148dbb39, 0xad435725, 0x4a96dcf6, 0x0bc4e402, 0x7ca73987, 0x4e54f713, 0x4204c77e, 0x0b5bcc35, 0x470eb5ad, + 0x88f1f00a, 0xd407e53e, 0xdda5243d, 0x858ae5c2, 0x48e63ead, 0x3e2f7626, 0x2fb3f4ac, 0x07cb509e, 0xdf15e1ce, + 0x11e137df, 0xaa663fd6, 0x2afd2859, 0x2b1943b7, 0x1a0398f8, 0x511cb9db, 0x9a1f07fd, 0x120f6a87, 0x8040c6c2, + 0xf0b6d010, 0x66fb89d7, 0xde2735a9, 0x55da0f15, 0xbff5da77, 0x705d66e0, 0x99463a41, 0xcc197a83, 0x0175fc10, + 0x2f8476aa, 0x445d744d, 0xfb36ed30, 0xefbe4350, 0x867496df, 0x78f4ec5b, 0xd0246665, 0x1f19ff5c, 0x12f33db6, + 0x49b7d099, 0xd3e458f0, 0xc8802a2d, 0x6fd77820, 0x9f47f611, 0x2ad72d1d, 0x8fda01ee, 0x76d1a30b, 0x58e80ce1, + 0x0a205399, 0xa233f0b4, 0xac8faf63, 0xe46e45b6, 0x9c25c222, 0x754f6855, 0x214b22b4, 0xc7109971, 0xe34f0471, + 0x68a5164f, 0x0729cf6d, 0x7ef3c508, 0x78af9f62, 0xdd01e653, 0xd75c8d92, 0xb3a5a611, 0x03fcee01, 0x8ba65a2b, + 0xee06b8eb, 0x22a0fa80, 0x2b638302, 0xe73d85ae, 0xf47d73b6, 0x37da3b88, 0x3266c9fd, 0xe2e730fc, 0xecd78df7, + 0x2628121b, 0x61374ddc, 0x24992c7d, 0x873efdf2, 0xc1f2263d, 0x60a03776, 0xf1f22cef, 0x4fe2034b, 0x6aee979b, + 0x702f7fbb, 0x0baee6bd, 0xecfeb5fa, 0x4937123a, 0xad881b57, 0x3f28d7aa, 0xb9c0f96b, 0x767e088a, 0x3ed03fad, + 0x60040476, 0x0f260114, 0x912c46f1, 0x4f917f6b, 0x8247bd4a, 0x0817570d, 0xb45eecc2, 0x51b3b56b, 0xa6053ff7, + 0x3cb69d17, 0x6fd49d8d, 0x0a1fe39c, 0xc6a2be9d, 0xa98cb4db, 0x5589cfeb, 0x60d175f6, 0x2cd56492, 0xaea885be, + 0x02b8deb9, 0x26e0c15e, 0x0ad39a51, 0x516a5fd4, 0xb5557285, 0xf030ad76, 0x9cd9df5d, 0x556c090c, 0xe4a3687f, + 0xe884ea48, 0x8e1d2994, 0x0b1901b4, 0x4ceb2ac5, 0x91fc83b0, 0x2f07b6bb, 0x47bb8b39, 0xc18c8d58, 0x8903f638, + 0xb0498199, 0x00a61710, 0x737a3da7, 0x98ea5df8, 0xf0675995, 0xa313b7a5, 0x223136db, 0x6d755e54, 0x4d963be3, + 0xe10c0e8e, 0xd9cef981, 0xe4ebd9fd, 0x58c70bd0, 0xa533db3e, 0xc88c05d1, 0x91a96b19, 0x084ec61b, 0x57ef3756, + 0xd6f35028, 0xebe00554, 0xb6ca2d51, 0x3de91fb1, 0xf44acf59, 0x353ab923, 0x236f28bd, 0xa093d2b7, 0xdf69225d, + 0xea69cffb, 0x3f8e21a7, 0x486f83be, 0x817111e5, 0x0527a57a, 0x493dd597, 0x2b389102, 0xfde1daa8, 0x6902fffc, + 0x69c3903e, 0xf9f65848, 0x338d592e, 0xade02d76, 0x81b06de4, 0x815c3b81, 0x79c500c8, 0xd6565749, 0x4b37d392, + 0x8f563ec1, 0x1747439a, 0xcba29f4e, 0x6c022feb, 0xd3514a34, 0xb33cecc8, 0xb27fff2f, 0x67d2c477, 0x2e5351b6, + 0x964ae6a2, 0x7511813f, 0x4139824d, 0x59ba8052, 0x61920090, 0x67df9218, 0xbb15049a, 0x0399c941, 0x4b0af0d8, + 0xd7561a39, 0x78d60ce0, 0x3430fbef, 0xa8932d71, 0x12dc9678, 0x6dbd516c, 0x119779e0, 0xb8db9de3, 0xada8048e, + 0xe98b3d31, 0x303f3d9e, 0xabf36e16, 0x1e5a5a8d, 0xd7f201a5, 0x283b4229, 0x270c6a9f, 0x2c7fdd4d, 0xd1d6227c, + 0x96bb5a2a, 0x3ae581ae, 0x2380474b, 0xa9b28366, 0x9fdb002a, 0xe1e3cc46, 0xb3b4bc56, 0x8099d309, 0xd40e87e0, + 0xe9a7cf1a, 0xe34043af, 0x62ce8cab, 0xb1bf674f, 0x2c630983, 0xd74d166b, 0xefd27249, 0x5d92cc66, 0xdecfb5d4, + 0x1c175d6f, 0xc015f180, 0xa2abd9a0, 0xcf949c86, 0x7cc626fe, 0x574ee122, 0x1f5d1610, 0x75aa7e2a, 0x938bd49b, + 0x055c957c, 0x982dc7bf, 0xbf4a3b77, 0x9c871a03, 0x0b081bae, 0xe154e061, 0x38e9def5, 0xd9e8892b, 0x74029078, + 0x872e72f0, 0xf52db564, 0xa7f496df, 0xf7ba8a8f, 0xe7a64252, 0xf62af81d, 0x144db7ed, 0xaa3d951a, 0x2a381d33, + 0x0df0a29a, 0x671305e7, 0x15dbf275, 0x91721309, 0xb96b9dca, 0xdcf921d0, 0xe56b409f, 0xf1bd9bfd, 0x2cfe42d0, + 0x090d0eb0, 0xa2daf1ac, 0x4be49d74, 0x1283830f, 0x75b7725f, 0xa9fd20ff, 0x87f61e4e, 0x0d908022, 0xf7a331b1, + 0x22f429df, 0x8b5cf35a, 0x88823d65, 0xad75e867, 0xf2ad982b, 0xd0be2535, 0xaf2e03ca, 0xd5e3e262, 0x660163c3, + 0xdda7648f, 0x28100196, 0xb6e13de7, 0xc37099cc, 0x51acb1f6, 0x61fee93c, 0x1fda48db, 0x38bd3a10, 0x1fe8e32d, + 0x41555279, 0x3ffa9d8e, 0x4dc2d1f2, 0xab270294, 0x766a48a7, 0xc49c4bfa, 0x7ac2af0b, 0xb366e91f, 0x6b08e7d4, + 0x38e482fa, 0x3168286b, 0x6027a933, 0xe542a93a, 0x38ab112e, 0x4aa27575, 0x53dc8db4, 0xb4f546c5, 0x2f37915f, + 0x7ba7035c, 0x91146811, 0x1532dacb, 0xa304032e, 0x97a0b341, 0x66122e1d, 0xd8294d79, 0x2b403f5b, 0x73c02f9f, + 0x3c901320, 0xe839d330, 0xe4482345, 0x80e70cec, 0x32f20a94, 0xd0f517ae, 0x3e0708ff, 0xcf46b906, 0xedd72c66, + 0xd24fd390, 0xa16fc2f6, 0x323db6d8, 0x3c005fd5, 0x128910a5, 0xd21ecb85, 0xa769f4be, 0xe80b7113, 0xefbb1ee0, + 0xb8dc1f63, 0xdbee670c, 0x40cf9e3b, 0xf8f3685d, 0xc530eb8e, 0xac6b48eb, 0x8b8c2228, 0xab7ce4ea, 0x46b03aff, + 0x1e6a36db, 0x5ea4edfe, 0x6248c9e4, 0xc35fe6e5, 0x44ac9bb3, 0x8fd2a07c, 0x62a8ec79, 0x735cb6ba, 0x89812fca, + 0x421c9dea, 0x726f7cd1, 0xff4b4e0c, 0xd4296923, 0x77266789, 0x38ce1a19, 0x8b56b869, 0xd8bf7ceb, 0x58cf309b, + 0xa4f94769, 0x496335f7, 0x109964b5, 0xd49f1ad9, 0xc5406d79, 0x59aaef4c, 0x26da92dc, 0x05c194b3, 0x4df664fe, + 0xbab4acff, 0x13057cee, 0x9ff3ced5, 0x92f6a16e, 0xb05c4e2f, 0xb141789c, 0xf149a23e, 0x2c0b8977, 0x026ab3c4, + 0x4c30a835, 0xf203e853, 0xa354b45e, 0x839cbb2a, 0xf6504e4b, 0x64e7d967, 0x1588260b, 0x190bf6ed, 0x0cd485e8, + 0xba313621, 0xe4c374b6, 0xa6d7d182, 0xd1a8995b, 0x90041b6b, 0x4c9c9edd, 0x434f622f, 0x02c4d053, 0x4bb2d8cc, + 0x105def49, 0xd7913d3e, 0xb58ee891, 0x7737de1f, 0x3eca22ba, 0x1ad3dea1, 0xfa5911a0, 0xce198630, 0x185752cc, + 0xf5c5cde3, 0x3b78c12d, 0xc33c4fff, 0x543d8a7c, 0x83dbd432, 0x01566843, 0x2f70dce2, 0x5b7c71c1, 0x931a09e9, + 0xa7837b27, 0x352577c4, 0x37bcb424, 0x719ae79c, 0x3e39798b, 0xa61b7bc1, 0x72a1944b, 0x9aef3780, 0x49fae986, + 0x85cdde1b, 0xb4ec3ba1, 0xa06fe287, 0x7f49f011, 0xd0f4d732, 0x95be39a1, 0x2779485f, 0x6305f981, 0x59980b2c, + 0x5b96f588, 0x343cd697, 0x413d6f3a, 0x5b5f0ac9, 0xfdbc5134, 0xa9841102, 0x4a75a9cc, 0x5520b620, 0x1ba699c9, + 0xd1bfc478, 0xa807b0f2, 0xb28f8d89, 0x2ef5ccf7, 0xae94ddb4, 0x14ccbc68, 0x502357c4, 0xc61dbd95, 0x1b337684, + 0x077a8d8d, 0xe51d8af6, 0x65a2b4dd, 0xe437337f, 0x8ef9ffc2, 0x8455b4ee, 0x0aaddf9d, 0xfa506b13, 0x55653596, + 0xcaeef2ad, 0x06e84a69, 0x87dca737, 0x40d98a28, 0x1080a87f, 0xc33af11a, 0xcd972be3, 0x4420dfb3, 0xc0c9e12f, + 0x3a603072, 0xcb202c40, 0x94e39d2c, 0xd3882592, 0x3806609f, 0xc3d276b8, 0xf59fd5d9, 0x25b293df, 0x41b5ad72, + 0x85bfaabe, 0x2cf7f967, 0x267dfe78, 0xc0f5aec0, 0xd941f2c4, 0xb8109773, 0xda0858fe, 0x67d5b599, 0x64b29ee0, + 0xdc0bd07c, 0x75378396, 0xfd916a9e, 0xcfbd08d4, 0xa55ef8d5, 0x452d9e89, 0x7ee1a650, 0x04a13f78, 0x02f392b7, + 0x2a6e799b, 0x2277fde8, 0x580d7fd3, 0xf98e910c, 0xdc9c05b8, 0x8377abde, 0xe3f7ce0b, 0x4df3445c, 0x67c6be19, + 0xb34996f9, 0x0a7e7e45, 0x0229a05d, 0xc7e7ab2b, 0x5a79d1fa, 0x5538f955, 0x7d999b85, 0xe51a0c83, 0x54ce2f5f, + 0xb6a42efd, 0x8f600532, 0x647f8ca3, 0x8212784a, 0x604d62c4, 0x0477c3ac, 0x3136616e, 0xd1b2d55a, 0x413c9e9b, + 0xea7128b5, 0xdfe17ee6, 0x77d8b644, 0x743276ab, 0xd03199b9, 0xf0b94760, 0xac36d5cf, 0xf9395eac, 0x5590c602, + 0x58ec5b8e, 0x6ab6cd46, 0xbbe5a741, 0x3b8bc430, 0x598956b1, 0xeeb2daa0, 0x5003b51e, 0xa7ab039a, 0xdaabd216, + 0xeeaaf06b, 0xba6a7348, 0x3fee5ba9, 0x95ce4eaa, 0x482399b2, 0xebbd6348, 0x7064885e, 0xc0628af6, 0xc7220ca1, + 0xa4257108, 0x2b18a06a, 0xd37d477f, 0xae4bb128, 0x1bce7d35, 0x0d41adf7, 0x0710c19d, 0xe5d0bf69, 0x50b2439b, + 0x65994f7c, 0xb01ae5f9, 0x4bbd7ae6, 0xc374f455, 0xb5ce3a05, 0x8247ea9e, 0x16859f68, 0xa6b0a713, 0x47ed2901, + 0x8774cd8d, 0x2edde3de, 0xf4bc8418, 0x2d9e27d4, 0x68863f6a, 0x91e6bcce, 0xfc3fb1e0, 0xe2501655, 0x4111369a, + 0xe7ca3aaa, 0xc440054b, 0x3e8eb91c, 0xbef4f2a2, 0xc58cd68f, 0x55d2f80d, 0x874be8e6, 0xc246a3d9, 0x8f390380, + 0x2626b66f, 0x0bef45a9, 0xe48e480e, 0xf23afd6e, 0xe9498db1, 0x3c920c7d, 0xcd96a735, 0xf80a3a5f, 0xee940a9c, + 0x35ae8789, 0xb71e5fa3, 0x7c33a96f, 0xdcdd5583, 0x41ccd0a8, 0xab7552a2, 0xbf5174ef, 0x1abf696f, 0xb3016229, + 0xfa418cd7, 0x644ed821, 0x0ac04779, 0x96e7da67, 0xb1875742, 0xa527e81d, 0x85d52b19, 0x69ad193a, 0xd882d5c8, + 0x028a3fe2, 0xe405a9ae, 0x4eff4a42, 0x93647973, 0x27967bac, 0xa134a741, 0x8cde39a1, 0x304dda33, 0x0582c730, + 0xac769177, 0xd98a8341, 0xf38daa88, 0xa46b52e7, 0x653f7d25, 0xcd27f872, 0x310ddfb0, 0x3e7fae26, 0x635a4a02, + 0x9007b46a, 0x2cdda420, 0x08792898, 0x6dbb48f5, 0x03a873df, 0xa5c463d2, 0x42c1663c, 0x311cb7ed, 0x8b2c0771, + 0x3354d79c, 0x612c4a7f, 0xd54b8bde, 0xf1f74411, 0x9516c37f, 0x84c4ea36, 0xa113950c, 0x4f1325b5, 0x2b2a1631, + 0x2f522b93, 0x89a1926d, 0x2fbd7ded, 0xe5c3afd6, 0x7c38a92d, 0xdca28153, 0x002068be, 0x13890ac8, 0xaa54343b, + 0xcaee91f0, 0x102775a0, 0xdb510816, 0x57ba65cc, 0xb9b5b091, 0x00f1b1b7, 0xea09db5c, 0x764f21eb, 0x8390211c, + 0x582cceac, 0x98b07914, 0x8041a7bf, 0x4b74f27c, 0xf8849e1b, 0x6079996f, 0xd2024b51, 0x2c0b07b7, 0x31eee128, + 0x97224156, 0x9215f3f4, 0x95987a64, 0x2e6b4939, 0x92c3648b, 0x78a17fe2, 0x0b20989d, 0x1a3af726, 0xb6c6f4ab, + 0xa6ad1132, 0x38afb6e8, 0x2dd6b7b6, 0x6a658062, 0x2e417f39, 0x1ae6b7ac, 0x5729ffa2, 0x4d222116, 0xa68b9680, + 0x19efb8e3, 0x5d01f83e, 0xac115a1c, 0xbf3f4ed2, 0x3e787d69, 0xdb46e022, 0xd704fba2, 0xd43124e2, 0x80132924, + 0x33a1cf69, 0x7729419c, 0x72b9096e, 0xc8411cad, 0xcc3a5e3a, 0x01d58880, 0x3d8ef1a8, 0x5ee1dce0, 0xc21ac19a, + 0x8f9dc0d9, 0x0c2a9bab, 0xd010bbdf, 0x10e823e2, 0x75b9fef7, 0x1fee716a, 0x8bd641bc, 0xaea43c66, 0x7d396658, + 0xb4229d74, 0xd7aa0189, 0x0e9937fb, 0xb45752fb, 0x917359a4, 0x53afce6d, 0x90c0a2cb, 0x1328eecf, 0x4b249803, + 0x80d7550d, 0xc87b0933, 0x303446a5, 0x63b5d3b3, 0xfb0017bd, 0x60f4f368, 0x224a0e6e, 0x59c43f09, 0xe3257eb6, + 0xe61ec495, 0x37def1cb, 0xbd2633de, 0x8b42d5ac, 0xaec99801, 0x20fd6a80, 0x22536312, 0x3e0c2030, 0x9324bac0, + 0xb0b6d87f, 0x22e8c761, 0xbb78b985, 0x60925cda, 0x50fa8b0d, 0xae8654ab, 0xfdc1773c, 0x29897e1d, 0xe9ca8e6c, + 0x21b28e60, 0xd65bd311, 0xb973161d, 0x0fa9e8a6, 0x12bfdc71, 0x334466a6, 0x02073695, 0x169bc51a, 0x78b2a045, + 0x8da4cc57, 0xc18f1a61, 0x5b67c346, 0x045b68c0, 0x6b1a2bd8, 0x6b81b093, 0x8f793e2a, 0xc8d8637e, 0x12e9ac3e, + 0xef47e825, 0xbf5eb870, 0xf8a40bb9, 0x0e60b4a7, 0xf315c4a9, 0xd1a83533, 0xacd63af8, 0x5a0882df, 0xf2b3ef0c, + 0x332a1cb8, 0x58743720, 0xff53b653, 0x24f69ecc, 0x08fe50c7, 0x0992088c, 0xe63189a5, 0xd2f288d5, 0x549fde9e, + 0x7900888d, 0x14d0513a, 0xc1975b9c, 0xfdc5e3c2, 0x2d5e826e, 0xb555b60c, 0x02fa115f, 0xdc2ba8b3, 0xa21599ab, + 0x0dcc80a6, 0x82c2beba, 0x305706f9, 0x20832dc5, 0xe8b4507b, 0x06e40ef1, 0xcb78f447, 0x5e889db8, 0x357b17a1, + 0x341061f1, 0xeae56895, 0xe740b843, 0x0ba86272, 0x1a8991e4, 0xe777f57d, 0xe4fc5a46, 0xb44ad30a, 0x9549f264, + 0xe7cbc32a, 0x49470445, 0x35f92277, 0x79407681, 0xa2f8f060, 0x2e972b44, 0xf353e724, 0xf1a4b595, 0xa64c7861, + 0x862e391a, 0x89c16b3f, 0x0b26a72f, 0x2a9c6d57, 0x10b5dc59, 0xac21ddcd, 0xe2199797, 0x62ab98ab, 0x9ddcf8fd, + 0xaf6c9fb0, 0x13062497, 0x7ba5fcf6, 0x38f3d514, 0x75efc5ae, 0x3d000087, 0x3cf0661c, 0xbba1be57, 0x50875b66, + 0x4d1bbc68, 0x2b3337a3, 0xc33cc33e, 0xb9097a24, 0xa85b97c6, 0x57e9acb9, 0x33727dcf, 0xe96a60ad, 0xe044cbab, + 0x2d5cae81, 0x694fcbe4, 0xf1c30c4c, 0xf40d71e1, 0xb3150844, 0x4ff22cb0, 0xe35bda94, 0xb392c2f2, 0x4bfa5c46, + 0xdd36d8cc, 0x48f897f6, 0xd1d2d9d5, 0x0c026383, 0x2699038a, 0xf3c4b9cf, 0x1c6fa35a, 0xb8382cca, 0xaac22cc6, + 0xe3bedc0f, 0xe4ae4e6b, 0xcf0b9f6c, 0x0663720e, 0x421154db, 0x9f733c47, 0xd2f13bb1, 0x6bd43337, 0xcc49a609, + 0xbb046422, 0x94358b89, 0xa4b70ddb, 0x6cfa0046, 0x818061de, 0xbd0110fb, 0xd082ed66, 0x3cac56d3, 0x19f02dc9, + 0xb582a445, 0x18cb2860, 0xcd7d5024, 0x9e18952f, 0x31be6929, 0xa123b1cb, 0xf107a7c0, 0xfeddedcf, 0x1a5c7065, + 0x5b900386, 0x1b08081f, 0xa4892dd3, 0xbc320846, 0x2dc2e4b5, 0xe2225b90, 0x6dc28380, 0x5e4b7f48, 0xdc421543, + 0xc614bab0, 0x40de1ef3, 0x67611f46, 0x53755bfb, 0xce63d7c1, 0x4ec41426, 0xd927927e, 0x29ae649f, 0xb7c7eb9a, + 0x12609051, 0xa22b6b14, 0x3dab1464, 0x41158df1, 0x2fc5cc24, 0x33306bc7, 0x8580fdc0, 0x6e6128ee, 0x66797a6d, + 0x90752675, 0xb315e02e, 0x446ff04f, 0xe34e50d5, 0x3f89d982, 0x456937dc, 0x371d1ef2, 0xe6b122b1, 0x907917c3, + 0x6762b479, 0xea22a2f2, 0x3337fa05, 0xd53ab155, 0x6593152b, 0x5f455f24, 0x68d4f40b, 0x03ce045a, 0xe069c789, + 0x200e9d98, 0xf6e02569, 0x83b5a8e8, 0x74e57604, 0x8b939ee9, 0x79223129, 0xe9ad93b1, 0xc107eaf5, 0x6302f8d3, + 0xbcb1f020, 0x710903f4, 0x22133773, 0xbadb3c56, 0x0b12bb5f, 0x79404ccf, 0xcd414f6a, 0x1259ee43, 0x264250ab, + 0xa5d11453, 0x4be19495, 0x7645b068, 0x38892873, 0xe16a9d98, 0xca847bbf, 0x516c60ce, 0xf7ddfdea, 0xae1b0e04, + 0x9b7e77dc, 0xed5055a3, 0x02ad41b9, 0x45f45a97, 0xc2a1adbb, 0xa2c52eef, 0x50ad5c61, 0x704ea141, 0x74bd5242, + 0xfe06691b, 0x5a8b30dc, 0xb3eee0e4, 0x1709c8aa, 0xc94acf16, 0x06958204, 0x213a3758, 0xdea7b838, 0x1d007542, + 0xc2a83a05, 0x90450ba4, 0x62c0ce0b, 0x41ca6c28, 0xd9d14285, 0xaece21ec, 0x8bc66402, 0xfa3bdfe6, 0xc9dc74fe, + 0x4d59ac66, 0xc94a5541, 0xecf3a33e, 0xf3c88b00, 0x11092714, 0xed7da185, 0x1c52e805, 0x12942083, 0xefc90c2c, + 0x87d7fff5, 0xd5f0fc53, 0x5c9b6ef3, 0x5bc8f211, 0x20d9c9f5, 0xdc590d19, 0x8735d461, 0x85be796b, 0x98efd14b, + 0xef04c021, 0x6fcdf778, 0x7a2261fd, 0xdbe35a3d, 0xdb351c60, 0xcca1030e, 0x77bc01b3, 0x69e3666d, 0xaf83269e, + 0x4c464070, 0xfd8265cd, 0xaa6a0a0a, 0x1c9cb45c, 0x075a885b, 0xf8ac58f3, 0x7f4323e2, 0x3e0b2597, 0xbf73a23a, + 0x726e5fd1, 0x2bcca17a, 0x1ee59cf9, 0x68f384ee, 0xd65a80c8, 0xd49f3054, 0x045278d2, 0xb8b64b36, 0x07d59665, + 0x0783c345, 0x1aab0f24, 0xfe0cf638, 0x38a6dc44, 0x7c7fa25e, 0x7ae20f40, 0x16c39f0b, 0x06c50c12, 0xf29dde70, + 0xc9b12f95, 0x1879a364, 0x6271479b, 0x008e94a3, 0x2a76a086, 0x697a2e47, 0x66af0e30, 0xd7b2bb49, 0x95b18591, + 0xfd185e02, 0x2a7feccd, 0xa1aa91d3, 0x5ee0e963, 0x7413d300, 0xc0208d64, 0x3365930f, 0x51113847, 0xd42aa6ac, + 0xd3cb59c7, 0x64e49a0f, 0xcd7aad00, 0x31acdf26, 0x40cf868d, 0x8744c057, 0x1c177ee3, 0x08614c5a, 0xc4003d86, + 0xe95b81f3, 0x7c06bbf2, 0xc0bf7ca4, 0xbb4048de, 0xcd197dde, 0x1e3c0ad5, 0xc53d358f, 0xb69850c0, 0x0ab57998, + 0x27e61612, 0x85d1eba4, 0x0b6f7cb7, 0x6a99c55f, 0xc10aaf9c, 0x7399208f, 0xfeba19af, 0x5aad97a7, 0x5e43b3cf, + 0xa641a6b2, 0x644c5395, 0x58cfa2e3, 0x9a1d7654, 0x358eea02, 0xa7ef6ee5, 0xe0abfd6b, 0xa1c1557f, 0x7d8da6e4, + 0x6ee6c001, 0x369ed3f3, 0xc639714f, 0x396891c1, 0xdd126efe, 0x93183578, 0xc6cf7c46, 0xb3f3ee9a, 0x3502f54e, + 0x789c1e88, 0xec99269b, 0x0dc71e36, 0x4684338b, 0x07f85eca, 0x0f4cecf5, 0x10d32c2d, 0x499df479, 0xd6b46ed7, + 0x3a2e297a, 0xcbbb5a9f, 0x19705b62, 0x6ed884a8, 0x62ecb269, 0x54a200a2, 0x7fd9ee61, 0x75cac4b2, 0x8136dd77, + 0x43033701, 0xd6353673, 0xcfbc50c5, 0xf50fa8ef, 0x315882c2, 0xe018d519, 0x90600c32, 0x27e48619, 0xa798fa14, + 0x2191fa9d, 0xe51c53e4, 0x868c2fcb, 0x914b3099, 0xb8a76f1d, 0xa6541459, 0xc89c7d56, 0x2e96b362, 0x48ff02f4, + 0x90671a84, 0x7b2fe8f8, 0x787c774c, 0xf481b657, 0x8fc7c5a5, 0x1e0e13ac, 0x07ac00f5, 0xa283e97f, 0x89d5c898, + 0xb20f27f5, 0xd0440536, 0xe4fb10f8, 0x75b6cf83, 0x0713184c, 0xadfc375a, 0x7bc45abb, 0xab2d68ee, 0x7f42e095, + 0x8a57319d, 0xfa8d53a7, 0xe2f1d845, 0xfdef75e2, 0xd3a6e4b4, 0xb42f96dc, 0xd6322948, 0x8e3964ba, 0x81769448, + 0x984ada86, 0x8e96fe66, 0xad90e3c7, 0x70bd01c1, 0xa0e8da69, 0x6d96a739, 0x28f676a9, 0xf3c3e277, 0xa1e4a855, + 0x4dc1d7ac, 0xdf870fb3, 0xb8e507df, 0xebc41cd6, 0x307453cf, 0xdb1ff3b5, 0x6a9a80f4, 0xa27652a2, 0x3852bf2e, + 0xcee19d7a, 0x320dbb71, 0xa765f07d, 0x139cd90a, 0x2c810ff4, 0xf96d65dc, 0x7bc77421, 0x118ed5d1, 0xee8d0fb1, + 0xd6d95aad, 0x30b24251, 0xe67f2d3e, 0xf91ef662, 0x467fc5f5, 0x606cdfd5, 0xee0d891a, 0xf85a0ec2, 0x34a97ea9, + 0x4dea1321, 0xc981aa9e, 0x21fce0f0, 0xdc958f43, 0xb02eb4f4, 0x5c3afeaa, 0xed5ff80c, 0xea4ba293, 0x183b50d5, + 0x6efd0d9b, 0x76c386d2, 0x7a19a143, 0xc84fa4bb, 0x0361918b, 0x6e83fa79, 0x2ae413dc, 0x914f8e04, 0xc88ea5aa, + 0x08639d16, 0x7c8e5d63, 0x697ab020, 0x456042d3, 0x9794b869, 0xb59a3d01, 0x18a3ed22, 0x052cf45e, 0xbc13844f, + 0x83498033, 0x3f510cbc, 0x8eb61def, 0x9c3759c1, 0x5e0faae2, 0xfcef19e1, 0x9dd6b2be, 0x8c3bcf5d, 0x7b280718, + 0xf7a49242, 0x1f0a92e5, 0xa6ceef16, 0x3c47303a, 0xb710b87f, 0x172585ef, 0x89064746, 0xbb9a6096, 0x990f8a64, + 0x6b6578e7, 0x62c8435e, 0xfce43e7d, 0xbe36e55c, 0x1e4ecf50, 0xdecd29db, 0x008a31db, 0xb31f7aba, 0x23a30f20, + 0x413bd1b7, 0x65be60cf, 0xd9aab26a, 0x66a53326, 0xc3514048, 0x0b0ebdea, 0xd5ce1bcb, 0x097ad650, 0x78305baf, + 0x2f6eefca, 0xdcd6ab80, 0x5aaed9a9, 0xbf6b73be, 0xa422b421, 0xbd575dd3, 0xc258db5d, 0xf83818ff, 0x8334f7c3, + 0xcf37888c, 0xe2cef21d, 0xb1596072, 0xd01a258e, 0xd1c572b9, 0xeb2f2f62, 0x33f3daec, 0x56c3320b, 0x112da9c9, + 0x5d60a080, 0x9415f928, 0xc3fbf992, 0x60c13ed9, 0xb94d90ec, 0x6abf3b26, 0xc24c9dc9, 0x7d36cc4d, 0x008ae227, + 0x1de33ce0, 0x1cf97b71, 0x27e303cb, 0x7dd8f386, 0x7701f063, 0x1eabdf9c, 0x872fde65, 0x6cb73131, 0xf5376e17, + 0x286f6f77, 0xb701349b, 0x3907f82f, 0xb14a9fa1, 0x1afa0f98, 0xfacdf59e, 0x67e757a8, 0x666fb39b, 0x5e573204, + 0xaecce470, 0x0030e3ac, 0x56999077, 0x60c2bc69, 0xa24a511f, 0xe7f43dab, 0xc4dc3c1d, 0xb6c69f4c, 0xc20e482d, + 0xd8fd5ef9, 0x0933b677, 0x2a564f18, 0x502e9189, 0x9bb873a1, 0xa55ba6a7, 0x33c97c5f, 0xa6a18935, 0x45050598, + 0x69885193, 0x203eb3a9, 0xf6e5a1b5, 0xe5eada9c, 0x8cbf755d, 0xcad37f80, 0xe760e6fa, 0x08fcae88, 0x12c243cb, + 0xec5d7f6c, 0x46d7a6d2, 0x62fd332c, 0xa2cf8019, 0x5a4dce7e, 0xc1d1073c, 0x0d3049a1, 0xc3cb3414, 0x6596a76a, + 0xafa64441, 0x74fd7557, 0x221c6b84, 0x3a55d30e, 0xe5cd8e25, 0xbe36bb56, 0xcb7b71a8, 0xdff20ef6, 0xb58a95eb, + 0xbd49f796, 0x3572af5c, 0x33ce6781, 0x019e263a, 0x9f294903, 0xf44a4781, 0xa895f124, 0xb35a7e60, 0x879a7f20, + 0x214c52d7, 0x75451f4e, 0xd9d0737c, 0x97c2061a, 0xd8b2afbd, 0xaa184540, 0xd51e3243, 0xb34b9541, 0x5fab49b3, + 0xe4e0ac48, 0x75329c73, 0x104e3138, 0xbce89d3c, 0x95ab3b80, 0xe8beede7, 0x8b92b3da, 0xf055aa3c, 0xafe3b8dd, + 0xfe17aad5, 0x22a839cc, 0xee4dcaa6, 0x8c874ad4, 0xc42c2831, 0x2c2be57a, 0xfe600a20, 0xa64c9e6d, 0x68d14c16, + 0x7f04a548, 0x701265c3, 0x55245557, 0xf59e3566, 0xd282d421, 0x0635951c, 0xea08bb8a, 0x8fcd2be0, 0x5348a532, + 0x00b3f859, 0xe41e2537, 0xc386a8f4, 0x54ddfc78, 0x6b25c817, 0xdc893d68, 0x420d2fba, 0xa4cb80b3, 0x04995fa3, + 0x900a240f, 0xebb7589e, 0xda5943a7, 0x6907ab6d, 0x8c8f259c, 0x640ea2ab, 0xc43184ca, 0xf0aa7051, 0x7a44bfac, + 0x4ff878a3, 0xd55a145c, 0xefc2f793, 0xcdb2c8d2, 0xce7a83fa, 0xf7c466d6, 0xd3a17a9c, 0xf1c79130, 0x908d9dd0, + 0xf812f3ea, 0xdcfb7d21, 0x14387e86, 0x9a6b7f26, 0x69af30c2, 0x05dc1126, 0xe108e705, 0xf7b83392, 0x3ae5e1fe, + 0x9106ed47, 0xf1bec328, 0xa9e1968c, 0xa7a6b7fa, 0x40f79033, 0xd679724c, 0x2d00475f, 0x208b2e5e, 0x5ebd064e, + 0x18e2a0ed, 0x6bb42c48, 0xdfdb5f14, 0xe92ca317, 0x98fb55df, 0xe045e5be, 0xaba94def, 0x09b517e5, 0xa233c662, + 0xfb92cda0, 0x8b85b515, 0x697f1343, 0x35d61fcb, 0x9e9660ea, 0xc68b7061, 0xfde14257, 0x13117bcc, 0x99651c39, + 0x604f1c6b, 0x7766d700, 0xaadd0c00, 0x796bcbea, 0x5acddc50, 0x6b5c3e52, 0x380b2c93, 0x57077ac3, 0xfa7d0db1, + 0xa7df658c, 0xedf0fbdf, 0xb288ff9e, 0xa8fc9dc4, 0x958ec4f2, 0xa62a66de, 0x59e6617c, 0xf392910f, 0x3261667d, + 0x8dcce751, 0x90ec1b71, 0x01e70827, 0x6cd3e46f, 0xd39f8ff4, 0xfebb8e06, 0x5431ae89, 0x142ff197, 0x7d427a7c, + 0xcc72b5a0, 0x804c2450, 0xa3f26fe9, 0x379b419b, 0xa549b332, 0x5c391830, 0xea559a4f, 0xcc45226f, 0x12a29c88, + 0x5cb81343, 0xf6a32bcf, 0x734abb10, 0x4f9ce4cd, 0xdc670463, 0x1fce73ba, 0xbc97b166, 0xbaf7e555, 0xd1856aa2, + 0x2fb7b8b2, 0xd78b157f, 0xbfc226bc, 0x717022bc, 0xfbc5a98b, 0x9eb3ca3d, 0xbd8e0225, 0xa8aaac6c, 0x39847c54, + 0x3a8a4d46, 0x293eaf70, 0x60a54809, 0xd4593686, 0x92e794d3, 0x39e3e8cd, 0xbc238279, 0xb7fc39ee, 0xe653b218, + 0x3d44dd02, 0xf310be8a, 0x3dc42608, 0x0a43f5d2, 0x9273b82d, 0xce7e928f, 0xc288537d, 0x34d9f94f, 0xdae026f8, + 0xc97174fa, 0x1abc5761, 0xc71d46de, 0x4104a114, 0x99ad9506, 0x2dff7efb, 0xbc8b775d, 0x3f0c4ce4, 0x4fd9888f, + 0x7de0dffe, 0x2937a3e9, 0x1ee057d8, 0x23295ac3, 0x54f1fc52, 0xe8c8d51e, 0x0e501bee, 0x174cb5a1, 0x7ce7f75d, + 0xfa1b21e2, 0x80edcc3a, 0x8b615118, 0xae4440a4, 0x6bba2fef, 0x4c7a0200, 0xe20aa267, 0xabec35fd, 0xe6ee7606, + 0x99673195, 0xccf11719, 0x2dd1e144, 0x2cb9cb23, 0x195976ca, 0xc3ddc708, 0x2768dd98, 0xe1cfa04d, 0xbea33899, + 0x1f98a41f, 0x79b8de23, 0x1f92ab0b, 0x3e302e7c, 0xb99c7d97, 0xec400a15, 0xfd602f14, 0x35d648e0, 0xa135497e, + 0x2970a540, 0xe57e1e43, 0x5dde0de5, 0x77690f2c, 0xc44e4a75, 0x97db4888, 0xb063da9b, 0x38b0f669, 0xa502c6df, + 0x78499ece, 0x4eb50a7c, 0x9bcd0cfe, 0x1646e920, 0x347d09f2, 0xc58a2a0c, 0x990240a0, 0x2d8e7eec, 0x259efe59, + 0x5ac578cf, 0x8d04d138, 0xf3b53bdb, 0x024ea602, 0x30411a48, 0x98d864b1, 0x20e6c0b8, 0xa85d998b, 0xc6801a3d, + 0xb552934e, 0xabf3ad14, 0xf04f1ebf, 0xa2200076, 0xb9f25e03, 0xee1f47e7, 0x8e261a3f, 0x505bcf53, 0xa3d7094d, + 0x2c86b97b, 0xf941b0d5, 0x9259705a, 0xe231ae48, 0x080bb891, 0x5291d3ee, 0x27ebecd5, 0x98e42bfd, 0xf048dd47, + 0x69969df0, 0x316069f1, 0xbef27ed5, 0x9ebe902c, 0xf9b43562, 0xfe4737ca, 0x5f464e17, 0xf6fe24f7, 0x13712be9, + 0x92a10e95, 0x6a6e420c, 0xf01f33b5, 0x76d922a9, 0x5094067a, 0x25825a00, 0x9786a920, 0x4220e38d, 0x3bee1b4d, + 0x91ee0ca7, 0x07d861b5, 0x1bbe0a7b, 0xa0d1e47c, 0x0886ab29, 0x66e3f71f, 0x35ca8b7d, 0xce8abd13, 0xc982517d, + 0xd0e79c42, 0x24913729, 0xdb89df93, 0x6e48ddb6, 0x89398e93, 0x75218877, 0x63ffc4ca, 0x070425a0, 0xb3f09e72, + 0x838f5718, 0x1d6c0369, 0x215a68e6, 0xc289eb65, 0xb2ef7de6, 0x0366b255, 0x3393b139, 0xbbae4f83, 0x6184ef47, + 0x20bb69c0, 0xf493fa89, 0x6009dce6, 0x0ea5ba2c, 0x334d6b3b, 0xeb4a3e75, 0x8d649f78, 0x679b23cc, 0x152bd038, + 0x62341e29, 0xf011a757, 0x6f230a9e, 0x6e0170fa, 0x6e74dbbf, 0x72bbadd0, 0xa6d6281a, 0x475aabca, 0xbbe5fa62, + 0xd182d277, 0x6fb7d36b, 0x0d48a51f, 0x1b6126aa, 0x16d3cd64, 0xa1d56a48, 0x4bfa3c53, 0xe369c113, 0x22af385b, + 0x0964f8ae, 0x6abafade, 0x769f9546, 0x10643721, 0xc6c138f0, 0x97af5350, 0x40d25c1f, 0x1fd4f95a, 0x77eb6d7b, + 0x2dc519d1, 0xca016d6d, 0xcd08cf54, 0x8f3b24c6, 0xaa1cb40c, 0x9914ac0a, 0xbc7c60b2, 0xa514d921, 0x921e1631, + 0xb59129e3, 0xaa471ae2, 0xf3c1c4c0, 0xc1993a35, 0xf352cee9, 0x34bcf211, 0x4c3f2101, 0xbe4770be, 0x1fa91269, + 0xd7aaa691, 0xf2488526, 0xc485d9e3, 0xd20db0c5, 0x459c1850, 0x3564eb3d, 0xba7fd9ea, 0x6f086f80, 0xda408dbb, + 0xf6f08dd3, 0x3b07e7ba, 0xc4a269b0, 0xa3a76b23, 0x67cdee73, 0xc0856472, 0x4e41e81f, 0xf72b5ded, 0x9b0a1571, + 0xbaf9d755, 0x621ef8e7, 0x75d5cb24, 0x5297f3d1, 0x33455c5a, 0x85cf181d, 0x83ba978c, 0xf79077ea, 0x0231bc5f, + 0xb117610b, 0x8ec10a69, 0xbf3e6d1a, 0x150a0fc8, 0x3abe6c45, 0x04efeb96, 0xeef37095, 0x830d2783, 0xa88dbef0, + 0xb5aaff39, 0xce915ed6, 0xe929d639, 0x9e028641, 0xe3dd7da4, 0x98fe059b, 0xe01acaeb, 0x7272879e, 0xdbace5fb, + 0x7d177879, 0xec0a5eb4, 0x29fbe4fd, 0xb0ae9027, 0xe9bd1698, 0x67351c3c, 0x9f195b83, 0x8f6618fc, 0xd8207749, + 0xacc9e14e, 0xbe99a8b1, 0xcb6d1d80, 0xa5f4bf8f, 0x1a003990, 0xe9cdea45, 0xd0a3ca0e, 0xc1859c7d, 0x6812c96c, + 0x7ca7e8b8, 0xe3d8e838, 0xcbe88735, 0x1ee57b77, 0xa887a3ac, 0xc9bc56a7, 0xfb46cca1, 0x7727a95d, 0x58dbbfce, + 0x3b968e67, 0xe1543e31, 0x4399edc7, 0x77ae23c3, 0x4a0241a8, 0x71bb10ef, 0x13e9b394, 0x321a193d, 0xb0887b74, + 0x60e3c2cc, 0x80afebc6, 0x7ab9328e, 0xdccf3061, 0xf9da4c27, 0xafc01cb5, 0x899fb08f, 0x0582f4bb, 0xbd5b3386, + 0x3ae0bc60, 0x93b78144, 0x02f19293, 0xdafdfdc5, 0x93649fa1, 0x2b01afd7, 0x1861fb6e, 0x00e8d1ed, 0xfe98d40c, + 0x55db9c4c, 0x1df51eba, 0x27bb4c22, 0xf558f1f4, 0x0ec4f3e9, 0x82cdb292, 0xaf1f6618, 0x707ce1e6, 0x1811fac5, + 0x2afec708, 0x01730a98, 0x5c99c091, 0x0964edf5, 0xaded2ca9, 0xe0d2f157, 0x0c6d64ac, 0xfcf01e94, 0xfed42819, + 0xe5deafe7, 0x8596b769, 0x221018fe, 0xaede6dab, 0xf8a80783, 0x02c4f6ea, 0x47c924c7, 0xfb24dbf1, 0x8e1afa7e, + 0xf891c0d6, 0x1e59695d, 0x81db3a4c, 0x8aa565b0, 0x9fa27fce, 0xda726b5c, 0x2838969b, 0xf0b530fc, 0xda025e60, + 0xa1b53b43, 0x9387c5c9, 0x1e1de6db, 0x9b4392bc, 0xd3737285, 0x12275f7b, 0x30d10d56, 0x0a53e72b, 0x8139e372, + 0xaac09f58, 0xb59643e8, 0xb6debb46, 0xa6abe73e, 0xfd3a8280, 0x2218c91f, 0x5096c70c, 0x2e11ad78, 0xcd7b67e4, + 0x2326de94, 0x89ea1c83, 0xf136b403, 0x64b44933, 0x6764d2ab, 0x6f0a715e, 0x30d72ea2, 0x9450f416, 0x35782907, + 0x082367ed, 0x03ffbbc6, 0xf54ef798, 0xb657b6b4, 0xbc4a5639, 0x7f11abe3, 0xfc1a26c4, 0x9902b394, 0xbcf1f783, + 0x9d422067, 0xd373e71c, 0xbd4a7f68, 0xeb75e594, 0xcdd333e0, 0x8a0e03a0, 0xfba78464, 0x8543dbcb, 0xe44cca58, + 0xe2a4fa38, 0x16c6d1f7, 0xe0ca29bb, 0x92632a81, 0x17f319ff, 0xd31798a8, 0x1760c329, 0xc40534ed, 0xd35338f6, + 0x23edf770, 0x974140b9, 0xf48f45af, 0x7ed067e2, 0x654e8173, 0x25b31c1e, 0x402455cd, 0x1fd04831, 0x698f68bc, + 0x5e5587c7, 0x867cc337, 0x2f753e81, 0x9873fcf4, 0x9744c5de, 0x7d42f570, 0x0bb25a9e, 0x6c5087ad, 0xa7bfdd61, + 0x31f04e5c, 0x18040edc, 0xbaa2d606, 0xceca74ad, 0x48dab90d, 0xb86d613e, 0xc531e52c, 0xe579b8f5, 0x6339d5c5, + 0x276fe394, 0x7deae94d, 0xb5408a06, 0x56313b35, 0x6af0c1b5, 0x4f8afcc0, 0xf3d744dd, 0xab679753, 0x21bbc27d, + 0xd728aa3c, 0xc7a4cdd7, 0x17a3fccf, 0xa3436f04, 0x65f89316, 0x8803b211, 0xbe93b765, 0x9cd3520d, 0x83200133, + 0x859e7222, 0x7ede04f3, 0x3cd22360, 0x6c6bf1aa, 0xa0a9e872, 0xe9ebed29, 0x0c3260ce, 0x836e0211, 0x15bec7e7, + 0x2e87356f, 0x001fb71b, 0x77055f4a, 0x264e5353, 0x9c6b0bed, 0x4aa3a96e, 0x0ce8fbfc, 0x85b6a402, 0x3436ce54, + 0xe8827491, 0x7954a168, 0xc7874dfd, 0x5a740e70, 0xa6a2e11b, 0x7049a947, 0x7a7187c2, 0x48623c72, 0x46373f86, + 0xa262b00a, 0x0f958cba, 0x78884318, 0x28a29408, 0x0215da16, 0xca0718ff, 0x173f089d, 0x4e54acb8, 0xbe67581a, + 0x93799763, 0x22d7f05e, 0xd4e1bee8, 0x56ded6bf, 0x37781c40, 0xd1e7e558, 0xf54c5bd9, 0x12753766, 0x7765dc56, + 0xac22c87a, 0x883240c0, 0x1e0c2130, 0x90920b05, 0x550df76c, 0x0412bfce, 0xe59590d9, 0xecb31973, 0x8be96147, + 0x886c15c5, 0xc09e6dad, 0x2f4662a5, 0x8854d322, 0x6c1c1bee, 0x6ba87360, 0x333e0a9d, 0x13846325, 0x590c1787, + 0x59d4ecd2, 0xa58fda07, 0x35432cdf, 0x473d1c59, 0xea079a99, 0x07094864, 0x57bf2fe8, 0x985665f3, 0xd99a92b7, + 0x8612cb4d, 0x09a55158, 0x7063dd52, 0x85c6c5dd, 0x82e94ba0, 0x263ca0d1, 0x656caed7, 0xd031f2e7, 0x85660b99, + 0x3db199d6, 0xe4dba28c, 0xf99276b3, 0x605b46eb, 0xdfbd9857, 0xe413af58, 0x4e4893f7, 0x772c6e9b, 0x2a0ac2c0, + 0xe6696d9d, 0xbf99d6fd, 0xf3c90744, 0x454f5d3d, 0xe07f1bd6, 0xe829c6b6, 0xf3504fa0, 0xdc22d23d, 0x018e86d3, + 0x944845e0, 0x35649f4c, 0x7a3dc3d9, 0xaa9431f9, 0xe81bcfaf, 0xc1a0a1b3, 0x480be8c3, 0x513e54b2, 0xe0a9bd24, + 0x05285b03, 0x2b9c8dc7, 0x0b4cd875, 0x37bd9d64, 0x4da2aa92, 0x3aa4beab, 0xe9093f41, 0x48b0886a, 0xf08b7643, + 0x481b7e6f, 0x7cc23fda, 0x5e8aa71d, 0xeb576abf, 0x87c1d2c7, 0xf6f8dd20, 0xa8e1656a, 0x10c1a460, 0x45f6760b, + 0xb0292cac, 0xb4022845, 0xca2cc68a, 0xb1a27cc4, 0x1afed02f, 0xdfee0079, 0x134563e2, 0x90ff054c, 0x2ecb986c, + 0xf86eadba, 0x2a204d98, 0x950ed180, 0x5e667b64, 0xa66d544d, 0xf537d528, 0x87334b61, 0xca5686e4, 0x507990bf, + 0x8b0bed9f, 0x3b0a32b9, 0x1cbed364, 0xfdc1aeaf, 0xf598f29f, 0xc2fded32, 0x2b0b248a, 0x661f286f, 0x064fb470, + 0x7662376e, 0xa96b4c47, 0xfa40ce9e, 0x985a93e2, 0x7cb19d86, 0xbb3f7a7f, 0xe149f390, 0xe5ae09cf, 0xb076d6ed, + 0x9ed3ee5f, 0x1c4dd1a4, 0x39a87392, 0xd15d72dc, 0x4d1412fc, 0xab8c163c, 0xdd96b39c, 0x432447e9, 0x81270e44, + 0xc61b116e, 0x98c4e138, 0xbf7d164a, 0x3457202a, 0xb2854836, 0x42652ef1, 0xb0402ca8, 0xd07bc9bc, 0xfdf302d1, + 0x4085c7e0, 0x864ca466, 0x7b166878, 0xec5ec79f, 0x61598bc3, 0x3dc92396, 0xbc3de9c1, 0xc438dc46, 0x24b5fd7f, + 0x2b4ab4f4, 0x8e83c499, 0x0916e3fb, 0x266ba5e4, 0x3d106fa8, 0x504516f0, 0x125ee90c, 0x5ab08342, 0xea614cc6, + 0x70cb387f, 0xbbd833cb, 0x4bc193dc, 0x6a33df8a, 0xaa210aeb, 0x10b71bf2, 0x76b8e8ce, 0x3dd62fc9, 0x67517c0a, + 0x588fe065, 0x7348a0b1, 0xe8ab95fc, 0xba58931c, 0x062187ea, 0x68dda7cd, 0x989c5ffa, 0x5de2f3f6, 0xddd7e76f, + 0x896e5a35, 0xa12ba40d, 0xe0372e5d, 0x51cb7193, 0xf645c7c4, 0x4ae90c22, 0x4115317f, 0xaaaf405d, 0xa1aa7f94, + 0x5acfadef, 0x2e60c749, 0x2268bdc0, 0xa80bc4f1, 0xf8f0d060, 0xb9cd792a, 0x8172d05a, 0xb43f1c23, 0xd70dbe68, + 0x1efbff39, 0x1b54ac1a, 0x3a92c368, 0x324a8752, 0x64c4c5cc, 0x2942d84a, 0x2a29d91a, 0x472021b4, 0x5768c6aa, + 0x5d797f1c, 0x8683711a, 0x6bb57ee2, 0x9a68bbfd, 0xf9ae55f3, 0xdaabafff, 0x0e9288aa, 0x71d3a6ae, 0xbbcae062, + 0xd127494b, 0xd4860fff, 0xa2f7fcbc, 0x4aa40552, 0xcde58a8d, 0x7d79bc6c, 0xd7aafcb6, 0xa405ad99, 0xdbf0b0d4, + 0xd2c91e61, 0xf3163ce2, 0x66833314, 0xac46204c, 0x4077560a, 0x97ad69c5, 0x46eee045, 0x55b95797, 0xc3ddd604, + 0xca59e248, 0xbd2af570, 0xfbd2e3dc, 0x6e46817f, 0x715ada1f, 0xd65ebbb9, 0x2ec77dfa, 0x2e4258b4, 0xdb09d428, + 0x2802bb8b, 0xc1c2c22e, 0x72dd9116, 0xc96d5d92, 0x65ec1abd, 0x68e50149, 0xb7f858ff, 0xb4801d3b, 0x42cac810, + 0xf7ac2e06, 0x117cae37, 0x08b8785f, 0xe8bedaa8, 0x8a587a7a, 0xf1239cee, 0x9c9aab44, 0x79802306, 0xfe1d319c, + 0xd5f4a501, 0x56d44491, 0x8dd574d6, 0x1d9dc3e8, 0xb3e09aa7, 0x096609f5, 0x6b652b78, 0xebcfcc3f, 0x6511f7ba, + 0xb739b497, 0xb5b1f724, 0xe791118b, 0x0ea5098c, 0xf285e0cc, 0xa190dce0, 0x5123fe70, 0x0cba9146, 0x2d76ccf5, + 0x73ada04a, 0xfd0db514, 0x20ce2166, 0xc8571575, 0xd0fac5bd, 0x3d49c805, 0x9a4688a1, 0x7ce648fe, 0x0882ec3b, + 0xd48d6258, 0xdbe5c57c, 0x5aec6a15, 0x424de7a2, 0xb0f00572, 0x198298be, 0xaff68fcb, 0x546f2c5a, 0x909899b8, + 0xb9002587, 0xafbb02a8, 0xeee91155, 0x4d466175, 0x37fb758c, 0xd2d1d811, 0x6285a1b1, 0x5c7605cc, 0x962169cc, + 0xf31cfeab, 0x2cb09528, 0xb92e5350, 0xc2548332, 0x78c1db19, 0xf0a80425, 0x5e1fd34b, 0x4b12dbda, 0x628b173e, + 0xbedc0a89, 0x57544075, 0x3eed260a, 0x5c4ae826, 0x66e63420, 0x9bfe4563, 0x4db6413f, 0x8ffcad15, 0x39899a44, + 0x1cb18c04, 0x9ced7e6c, 0xcdba325c, 0xa9d528c0, 0xaf2f1d8c, 0xb6f1a5b3, 0xab214f62, 0x2437df66, 0x4e454429, + 0xb7c8d5b9, 0xd54ed994, 0xed19c312, 0x2459c51c, 0x45faef97, 0x8b0d69f7, 0x9713c9eb, 0x0a893ad3, 0x977938d4, + 0xbb393a0f, 0xab8723e0, 0xebee6677, 0x5ee8107c, 0x76f91385, 0xae3eca8d, 0x079b75dd, 0xef0a1609, 0x4f27fd98, + 0x305940e7, 0x0b73995f, 0xb47725a5, 0xe7024136, 0xfc4655ed, 0x29212295, 0xa635a38c, 0x64f1b4cb, 0x3a67126c, + 0xf905abb3, 0x5373fe0a, 0xd3477894, 0xd76c1627, 0x1e23df65, 0xd74cd6a4, 0xa902474b, 0x0ad7f028, 0xa4915327, + 0xd4c61127, 0x58d525c0, 0xf122efe5, 0x3e859925, 0xe27207af, 0x1b34a737, 0xea2bc438, 0xfdc656b4, 0xb55bbe56, + 0x6522c591, 0x1c18a676, 0xe371f432, 0x44df9753, 0x8ff01f31, 0xe9ac5fe9, 0xdc42538c, 0xd253789e, 0xc5f95dc0, + 0x9059117b, 0xd0617738, 0xeede9093, 0x0b629442, 0x98ae9d8d, 0x8130bcf4, 0x184278f8, 0xc0422725, 0xd3074ea5, + 0x8df793f9, 0x10496355, 0x49ff817a, 0xf6184728, 0x71a4e84c, 0xe4e0e50e, 0x40b1c137, 0x8ca05e72, 0xa742ea14, + 0x539d01f9, 0x66f005ff, 0x0ba5267c, 0xbc18a10b, 0xead8ab74, 0x4ae31d79, 0xce85ce2d, 0x12c85ca3, 0x993dc7e7, + 0x5798af93, 0x4a1f092e, 0xfcb40505, 0x9d3814da, 0x11362577, 0x559ae6d3, 0x813a8dbb, 0xf23f7ff0, 0x7e0beff3, + 0x0dc723e5, 0x238477b9, 0xc1cf0b2c, 0x053d50a2, 0xa4b8d884, 0x45ddcc01, 0xb6f0d302, 0xf65d7f4e, 0x5d8fe45e, + 0x86720b10, 0x35997141, 0xa8f91baf, 0xa4d6df03, 0xfedeae1d, 0x626c7890, 0xd447c9a0, 0x2aa2a5c9, 0x69850da3, + 0x3d868206, 0x89ecfd0b, 0x227662b0, 0xa81d0f20, 0xe42a166c, 0x4f6c61a3, 0xc113cf38, 0xc1f01b2b, 0x0f9f78be, + 0x9eaf4ed1, 0x5521305a, 0x57a3877e, 0xfdccd2e1, 0x67e953b4, 0x0d73e09d, 0xe0793fb2, 0xa277782e, 0xf6f5988e, + 0x9a51924b, 0xbd280dcc, 0xf2fac81a, 0xca316ac3, 0x21e31636, 0xfa31cba5, 0x3609c61f, 0xad77f49d, 0x35643d1d, + 0x10b07f17, 0x0e4a39e9, 0x95376347, 0x5af7c236, 0xfa07633a, 0x5a50fffb, 0x51745ea3, 0xf700d0b2, 0xb1583b4a, + 0x38bf440e, 0xaf96b5cf, 0x0e784e91, 0xe209e6cb, 0xc0747d61, 0x73158acb, 0x7b23e999, 0x5d98cfe1, 0xe75350b1, + 0xfd524312, 0x25300116, 0x1a79c41c, 0x481b3010, 0x67d8fb98, 0x9b12cc60, 0x27252cea, 0xaf4e15f1, 0x9e0edf13, + 0xd4d8e6bc, 0x60bb79f3, 0x508af9d8, 0xeb9294ee, 0xe0b85f6c, 0xc57870a8, 0x5b42fa85, 0x3e308979, 0x13bab9a3, + 0x0dc0ffbf, 0x73fe2681, 0x58e4f391, 0xc2b00cb6, 0x8f560c42, 0x63c72792, 0xcf64fbb6, 0xe2b0136f, 0x80f99f88, + 0xe49c048e, 0x403d40bb, 0x55fb266c, 0x6d682ecd, 0x9d4e24af, 0xa0e3cbe6, 0x930c7d59, 0x403a89a4, 0x04235cd2, + 0xfb6030f9, 0x71d47b28, 0x7d862c53, 0x15a985e7, 0x3daea632, 0x30f56bb3, 0xee506316, 0xd1354c54, 0xb687c58d, + 0xebda9306, 0xff005e9c, 0x7ca216f5, 0xb74418e4, 0x089eaf46, 0xc53ab13f, 0x67b1dad9, 0xd1c85219, 0x2ead10ff, + 0x251ef104, 0x89622c6c, 0xa44144be, 0xf24ce129, 0x08f9f37f, 0x10c0f877, 0x1aefb264, 0xf34498cb, 0x8d47fa62, + 0x62e88640, 0xa6d60a80, 0xb50e6125, 0x32d8a79e, 0x27118719, 0x723c8c40, 0x900a1ae5, 0x5adb4579, 0xc5e163bf, + 0xcf80b05d, 0x6e250029, 0x4c066fac, 0x4dbd7f81, 0xfd760054, 0x0901ecb0, 0x54dca319, 0x9e24a4db, 0xdda4bf2b, + 0x3b4dfccb, 0x91378d4b, 0xd121980b, 0x897b795a, 0xd7bfd5a4, 0x1454df98, 0x04c5e42c, 0xb6fbaee4, 0xee47d4df, + 0xf2ed7490, 0xb73350ee, 0x66190c4c, 0xf58e2cfd, 0x8fca3264, 0xfaff46c5, 0xc9730fe6, 0x69e50661, 0x989fd949, + 0x7431c9f2, 0x12be8811, 0xd59b96be, 0xe01ebab3, 0x62b6aeca, 0x541172fd, 0x0df90c87, 0x55a86b9c, 0x27b8c05b, + 0xd9ca9e29, 0x332611cc, 0xd63bbc9d, 0x761eb959, 0xea3f4072, 0x4089a882, 0x07ff6eaf, 0xbc4b1d90, 0x12e45f2d, + 0x826ff224, 0x8064852c, 0xcec8defa, 0x1c0d85ba, 0x94ea26bf, 0x00857ab1, 0x6b201a18, 0x7c557277, 0x23674860, + 0x6d0bfaf7, 0xfabe23da, 0x978d8a67, 0x590215c8, 0x8c17c3ef, 0x97bad888, 0x276572f7, 0xfe4cba5b, 0x1a5101f2, + 0xe2aaaaf7, 0x93c00c4f, 0xf96a606a, 0xd7482e7a, 0xebc35b29, 0x9b5c23fb, 0x7670ede8, 0x1660dcaf, 0xc1f3328d, + 0x29db6662, 0x0ba6326a, 0x8606301c, 0x41abf347, 0x1ed9b2ff, 0xf96ca3ec, 0xd7a30fbd, 0xd9ded781, 0xd708eb46, + 0x52dc3fd1, 0x2420a54f, 0xe87c4f7a, 0x3740c3e8, 0xfbc1fb20, 0x04671a66, 0x7d208eff, 0x3d6e5bf5, 0x3bdbaa53, + 0x66ed89a5, 0x58176b36, 0x79a94a6c, 0xcd400913, 0x997f9415, 0x8b75f18f, 0xb147aac4, 0xad94c733, 0x632a8304, + 0x5eaede36, 0x74701509, 0xf5623004, 0xadadc76e, 0xab0aaa1b, 0x720c720f, 0x094caf25, 0xe746586b, 0x7a62a223, + 0x27859a48, 0x749a0106, 0xcfbbc3e8, 0xc199cfd4, 0xdfd94889, 0x597fcc0d, 0xb05a7af0, 0x667b7186, 0x49886eee, + 0xddd5ec21, 0x4e1b4a16, 0xbdb33d6a, 0x965a8be7, 0x437c3592, 0x23dac2f0, 0x6b0bc7bb, 0x30237464, 0x538fd7e0, + 0x42b8fec9, 0x2ede056b, 0x28843e45, 0x38536e16, 0x88dd82c3, 0xe413b044, 0x41fda958, 0x9ec678dc, 0x4f8a66b0, + 0x9c179002, 0x9956aa1f, 0x4a991798, 0x9e1fdafe, 0x3c71ce52, 0x902cdb11, 0xdf0ddac9, 0xb44dc488, 0x58c32f48, + 0x2f1c432f, 0xa1225b59, 0x66c409ed, 0xecf72b68, 0xb8f08479, 0x5400bebd, 0x732a6752, 0xd4267b69, 0x824d6a2e, + 0x6e4ccbd1, 0x43eaa207, 0xcd6acddb, 0x25e25f9a, 0x201cc0e7, 0xa2e8639a, 0x102432c7, 0x02986400, 0x1509aa9b, + 0x5beefb9c, 0x5d5315a3, 0x108bd7a4, 0x14f7c028, 0x80d71c6f, 0xe03a3b70, 0x258a699b, 0x394cc374, 0x0e644c96, + 0x5fce881d, 0x69aaf7fc, 0x92ae8a1d, 0x21c6bf09, 0xa035a51b, 0x0e49593c, 0x1d518f9c, 0x362590e3, 0x16716c99, + 0xf22a9c27, 0x8b6c0484, 0x566041e3, 0x4f5033f7, 0x93132838, 0x1d3c5d8b, 0xf0cd9ee4, 0x1c3a1a7c, 0xa69c3cfc, + 0x5dc11026, 0x6d2c5ad6, 0x00c559ba, 0xca0cca16, 0xb54a3345, 0xb3636850, 0x97bde29e, 0x5239a960, 0xa3bb2edf, + 0xe01db9b6, 0x9bf7b0b0, 0x64cb57c4, 0xaeeebeb5, 0xfe5eabd4, 0x4568771a, 0x8209abb0, 0x7447273f, 0xdeab5117, + 0xaee08773, 0x53bf5921, 0x17fb4f95, 0xc9d7948f, 0x1c9d2df3, 0x843616e9, 0x9ead58e8, 0x2bd5016f, 0x13710b74, + 0x70af602a, 0x2dbc0f96, 0xc15b93c2, 0xdb1e9c70, 0x03fad36f, 0xa3ed1980, 0x20544085, 0x395a2330, 0xde5e1331, + 0x89c4f208, 0x8d0f2f52, 0x0ce82839, 0x4bf53ebd, 0x1bf5bc08, 0xb3ea75e3, 0x6a6d4925, 0x5455086c, 0xced7d5fa, + 0xd11f928a, 0x64d8a747, 0xdbff5dfd, 0xa6efd782, 0x564230e2, 0x5eeca30b, 0x9fb60036, 0x9c9b782c, 0xd137d4fd, + 0x1fb6dfa9, 0xf4776311, 0xf42f1117, 0x20620652, 0x712d4e6e, 0x29097b49, 0x64209d11, 0x31090238, 0x9acd129a, + 0x50f39e1c, 0xbbda3503, 0x5c491fde, 0x0469a59f, 0x1a8cc805, 0xd6d442f6, 0x61708a26, 0x74a4c527, 0x9385eeaa, + 0xdd51f981, 0x5c29764e, 0xff83435e, 0x3d0c8705, 0x4f39e152, 0x5db41810, 0xd86eb191, 0xdbef2ed7, 0xef4efb18, + 0x1b411a8b, 0x910b0e25, 0x85e11333, 0x522e8d2b, 0x1ec97d57, 0xab5e9ce8, 0x359bcb01, 0x4e142cdb, 0x5db6e7eb, + 0x20c9a747, 0xca80b136, 0x85e47073, 0x8384a826, 0x7623f37f, 0x9d6ecf6f, 0xd8b2e2b2, 0x59f0c169, 0x24ddb2ac, + 0x65055f26, 0xafadcbde, 0x38f44726, 0x2d98f234, 0x25a82518, 0x7fdafa2c, 0x76578af6, 0x887bfc5c, 0x719fbacf, + 0x17e046a1, 0x6f6ed1a4, 0x7ee5a2b9, 0x8fd53eb9, 0xb9fff033, 0xc1e5b27a, 0x1ec5e08b, 0x98509257, 0xd312b466, + 0xe4155d75, 0x400b7e18, 0x4a9bdc1a, 0x3979a87e, 0x3291fd4b, 0x3570bb2b, 0xe518fea2, 0xd1121300, 0x932a29e0, + 0x69d36b30, 0x540b8238, 0x697e0944, 0xe99f1567, 0xa5e8b127, 0xb22b8ee2, 0xf785dd53, 0xbcab56fc, 0x107eb02e, + 0x48c36314, 0x90b052d8, 0xa30f7516, 0x24291927, 0xca33d40e, 0xce6bcf5a, 0xaefc5815, 0x30a5e954, 0x71866fc7, + 0x981c5018, 0x9d575275, 0xacc1ef03, 0x748f98dc, 0xea06a4b6, 0x89e44072, 0x047a3d55, 0xd1139f39, 0xc8b07079, + 0xaa12cf58, 0x0868a363, 0x145632b0, 0x6a247beb, 0x34109370, 0xa8137ee7, 0xca8ed2c7, 0x0af4a38d, 0x2c054e37, + 0xf6a09af5, 0x4cbd3720, 0xe09cd05c, 0xf9052603, 0x8e9c2922, 0x3c063497, 0x0e5be73f, 0x0710c3a1, 0x9fa4e4b9, + 0x473b90c8, 0x428a6d2c, 0x727bbc03, 0xf0a7b15e, 0xeb14644c, 0x1f1631b2, 0xe0639148, 0x2071409e, 0x46089f22, + 0xc28e2df1, 0xc09f7408, 0xefe21df9, 0xe5c6d298, 0xf6d52dea, 0xfac2d809, 0x664dd575, 0x5efe7c14, 0xd91362da, + 0x2b076c05, 0x5d9b2913, 0x87a096e9, 0x3fdd6d88, 0x892856c5, 0xb6186004, 0x734aa33a, 0xd13ae85b, 0xbb89274a, + 0xb2802c7f, 0x422c346e, 0xfada2124, 0xc74a7bb9, 0x8510cc70, 0x763bcda4, 0x1c768468, 0x69faebcd, 0x060fe7bb, + 0xc6ec49b1, 0x2e3fe9e8, 0xfb60da10, 0xc22c03ad, 0xaa33a770, 0xc99c4a62, 0xf16f137a, 0xb859acca, 0xc1f80c21, + 0x0e24d770, 0x6b03f05f, 0xac620772, 0xa6bad29a, 0xf0518490, 0x5d29a5d0, 0xc7d83f2e, 0x045ff71e, 0x56a719ec, + 0xa6bc5c17, 0x1a164fca, 0x2b616b03, 0x73c49393, 0x321870e5, 0x18a658b2, 0x465e8f92, 0xec507eb2, 0x3e1eb13c, + 0x1feb7dd6, 0x62e60617, 0x09f8946d, 0xe410a0c6, 0x97787558, 0x473cf9b7, 0x6c4b461f, 0x05b156a1, 0xc7c94dbc, + 0x9dd92e8c, 0x6c130c15, 0x2be782be, 0xcc9fedf8, 0xcc6b1eec, 0x71850353, 0x2506d4c8, 0xc4d7e0be, 0xdc5abe37, + 0xc5748c4c, 0x7df556be, 0x3e207749, 0x30ed4760, 0x973051b7, 0xea0f0188, 0x2fdf9630, 0x6794ff2c, 0x43be1fb3, + 0x0be13685, 0x801b65ea, 0x54aa6a2d, 0x7b30cc34, 0x23517bb3, 0xdf588022, 0xb4cc19d3, 0x0e09aaa5, 0x8dd0ae07, + 0xb2446b8c, 0x47a169ba, 0xe2f11531, 0x625f5212, 0xa4be5561, 0xa89842c1, 0x9dbac9fa, 0x289dce6c, 0x931452f1, + 0x6fe3be0a, 0x5fd54301, 0x37cb3b49, 0x22558a00, 0xbde017ef, 0x8586b66c, 0x89a9d1ec, 0x54032883, 0x13577d5c, + 0x11d5db2c, 0xaaa182e3, 0x21c29315, 0x4ccf864b, 0xb4278919, 0x297d29f6, 0x9b0b5631, 0xf5010d60, 0x36a222ee, + 0xed0c2fa9, 0xb501355b, 0x75aba9cd, 0xdc8b9ae7, 0xa825ccc5, 0x7d06abf4, 0x75d6e0f5, 0x6bd523bf, 0x64b2aa45, + 0xaeb4eb39, 0xe716b76c, 0xb44a62a8, 0x3e29b161, 0x2de5207a, 0xbb57cb35, 0xc4ca2e7f, 0x29772711, 0xf770c601, + 0xf7815ba1, 0x7b2e7894, 0xa5b338be, 0xf1990d4a, 0x95dd9442, 0xa5d9f009, 0xd49e1f98, 0x19a4d034, 0x2e51946c, + 0x4161bd79, 0x8a046310, 0xcca6b79b, 0xad7f4583, 0x650ae421, 0xb3ca9f3e, 0xa46a2b7d, 0xe12af384, 0x4e5a5b81, + 0x09d5403e, 0x9207da4c, 0x63355de3, 0x5487c39f, 0xe64876d5, 0x7780fb8f, 0x9171e814, 0x64676f69, 0xa139769c, + 0x9043ab41, 0x697c218a, 0xe4b5f527, 0x4210dbf2, 0xad999037, 0xb98af917, 0x0b619114, 0x53437320, 0x359b981f, + 0xa1b12147, 0x48ab4631, 0x8c754c06, 0x6decd882, 0xd4994ce2, 0x9edbf0bc, 0x8e28e9a0, 0x1b6eaea6, 0x8911649c, + 0x7aa1195e, 0xbc60cacb, 0x1ad0b080, 0x880043ba, 0x1140bf71, 0x8a7ff555, 0x1816ee94, 0xa4c87155, 0xb6c8d39b, + 0x1a00ed46, 0x32f3eb87, 0x7f368629, 0x7d455eb9, 0x6aa47796, 0x708ea87f, 0x7dc706f1, 0xb92f5e12, 0x1c652cfb, + 0x43374e4b, 0xa7cd40a3, 0x6b2de39a, 0x502021f2, 0x6d38273a, 0xaceb9853, 0x6c715c24, 0x18c4659c, 0xb0629039, + 0x23f77a3d, 0x3f518378, 0x0c90b6ca, 0x2601af51, 0x9f9a48c8, 0x14889472, 0x301276ca, 0xe376c2c4, 0x999ae949, + 0xb450ec56, 0xf9ae1682, 0x4da86e01, 0x0ccad902, 0x575fd924, 0x77351ddd, 0x35b73e8b, 0x56a4ce82, 0xa527aac9, + 0xf4be271e, 0x51f4c573, 0xf081199c, 0x0109ad75, 0xa9326ed4, 0xf3f6a4ca, 0xa4ef22ae, 0x7168615b, 0x6e73fd12, + 0x315611cc, 0x46685634, 0x22f6e071, 0x9a665ace, 0xdcb029b4, 0xaf569716, 0xf2478205, 0xa1808bb4, 0xc26f878c, + 0x731cf895, 0x020d58f7, 0x2f7cc8ed, 0x1708aa5d, 0x6018c691, 0x1c2796f1, 0xf101ba7a, 0x247f60ac, 0xfc6c074d, + 0x9f896a36, 0x1ad46ffb, 0x10d0e057, 0xba8b883d, 0x60ae1b36, 0x089eac34, 0x8b355a60, 0x4179251f, 0x5218e432, + 0x7830d6c0, 0xd823d22d, 0x9016728c, 0x628ca72a, 0xdac54f9d, 0x46efe8db, 0x98a882a2, 0xed39eab1, 0xd9661828, + 0x373bdf9c, 0xa404abd9, 0x4d67f5d9, 0x1352a3bb, 0x39d852eb, 0x35d4ebb0, 0x4e6cbfce, 0x06cad2ce, 0xbca894d4, + 0x7ecbceb4, 0x9f5e744f, 0x7a361bfe, 0x7208ce91, 0x16f8614a, 0xf9e6b3b3, 0x254e4ab3, 0x7c45d933, 0x56abd29b, + 0x41332b58, 0x5c2dbef9, 0xc861f4a3, 0x009aa82b, 0x48cba6ee, 0xf382a91f, 0x85fd0aa5, 0x98638a43, 0x5534c7a5, + 0x39ee110f, 0x1a70416c, 0x61aa6978, 0x258d308a, 0x754db350, 0x9b73c142, 0x9916aaec, 0x59625770, 0x72ef5907, + 0x8f7c8146, 0x5dc7aa12, 0x3ce534da, 0x06b48c64, 0x25c0059b, 0x55dcdabb, 0xc73dedb1, 0xdf4539be, 0x21d49788, + 0x4d2a5ab2, 0x23729c62, 0x6c8ff1f9, 0x84ff1341, 0xd5d1b0d2, 0xcbf4d64e, 0xde168845, 0xe85a3e27, 0xe4e0cd5c, + 0x744105b2, 0x528087bf, 0x4f8b9a3f, 0x97ac1397, 0xfb088bdb, 0xdf6cef46, 0xbcc560f3, 0x39eb2277, 0x73521535, + 0xa6e8c323, 0xdc7770dd, 0xba40332d, 0x9bfefd95, 0x4926b572, 0x76acb0b1, 0x5567c254, 0xf64bff15, 0xe8740796, + 0xe898422a, 0xb52e2baf, 0x4785575b, 0x95aa5793, 0x8063ada9, 0xd4d15310, 0xa119c28d, 0x9565466f, 0x215013db, + 0x808c7414, 0x17793908, 0x62bab80a, 0x9daf0855, 0x4c3a9066, 0x2b55082a, 0x14cf5c6d, 0xc073e7de, 0xf1e23295, + 0x144268ee, 0x38bb49ec, 0x15d7335e, 0x311e7854, 0xf4a9a679, 0x3011d4f8, 0xaeee8dce, 0xc7cb12df, 0xd790dc92, + 0xa4f3f1f3, 0xc89f4e4e, 0x46240bf8, 0x8b39a2b3, 0xa95322b3, 0xbc70afb8, 0x4e27876f, 0x56adc17a, 0x5eae2477, + 0x1b494a54, 0x6d3f33d8, 0xbad27e74, 0x451243b8, 0x1f4ef818, 0x6c479321, 0x67bb9f81, 0x820a82ea, 0x61489b9c, + 0x160c7812, 0x05150d57, 0x0b7f156d, 0xab0f65ab, 0xf155a2f0, 0xace03b98, 0xdd0e27cd, 0xe335c71f, 0x628ae8b5, + 0xaec45975, 0x891097f8, 0x65389927, 0xefaed25c, 0x8b915f5d, 0x150d3690, 0x6498dc1f, 0xd3264abd, 0x22fd7560, + 0x1fb2f5bc, 0x8c058bde, 0x00c84156, 0x23efeb39, 0xe035fbd6, 0x9907a544, 0xc551bdde, 0x4315eb1b, 0x497f1a79, + 0xde76ba57, 0xfe6fc2e5, 0xe70cb0e7, 0x82b9b4ce, 0x6749b183, 0xd6fc3145, 0xf5bdd7c8, 0xce7a2476, 0xd6315fec, + 0xaea1eee4, 0xb0e427e2, 0xca03e113, 0x17d0c4ae, 0x7bdc74aa, 0x52a96704, 0xc828f3c7, 0xb31e5520, 0xaeb769fa, + 0xafe49ca8, 0xc43b929e, 0x7acfe1ce, 0x441e6e0f, 0x2e08d32a, 0x100b2310, 0x4b14292f, 0x8e3e44d1, 0x3187fbc3, + 0xeae89b36, 0x7178233a, 0x6d7a0852, 0x77d65dee, 0x6ead3a8e, 0x66c790e0, 0x5442465c, 0xb21efbe4, 0x07007e2f, + 0x98bcdbc3, 0x76b6cc45, 0xe7a14e8b, 0xa2bce583, 0x513d9150, 0xe1439e1e, 0x02ef491f, 0x79593e2c, 0x59926c11, + 0x541fd07c, 0x7a2623ab, 0xe5b6bd24, 0xd98aa952, 0x8b4e12c8, 0x7affd5ec, 0xcd8cdd73, 0x16cf42bf, 0xafcf5278, + 0x7f20990e, 0xd591cf37, 0x74ae4339, 0xb9690b31, 0xdced1f15, 0x6856b459, 0xbdd5021a, 0xec0a836c, 0xbb06a78d, + 0x8fbe2da8, 0x9fa74cf6, 0xedef4bad, 0x298a0cc1, 0x9da0a5a2, 0xffb49fac, 0xa03437a8, 0x673f8e5b, 0x2dcda9f6, + 0x507dffde, 0x52141d83, 0xd88fb1a9, 0x7db02340, 0x34eed0b1, 0x3e2e7112, 0x4149fbac, 0x2126aa7f, 0x6e77c7ea, + 0xee8a9491, 0x4ab03e24, 0x1318c95e, 0x766d2ae7, 0x8624f50a, 0xa176ac32, 0x7c595d80, 0xcf2b3f7e, 0x7354dadb, + 0x92eea2f2, 0xfb275399, 0x1e9ffd06, 0x6eb88b6b, 0x590ba65b, 0xf016de19, 0x3561cc5b, 0x2721a7a5, 0x4213628d, + 0xab7f0950, 0xe677d76f, 0x8cbad46a, 0x414a7326, 0x47216f50, 0x53f338ea, 0xed0f088a, 0xc3f89cb9, 0x6b7bb10c, + 0x874e8f65, 0x82854ce2, 0xa5ebf820, 0x11f551ad, 0xcdd5ae9d, 0xac621576, 0x8436a3a3, 0x256813fb, 0x8f049b15, + 0x5316ed01, 0x45695675, 0x678fce68, 0x28863390, 0x583e139d, 0x63d2026a, 0xf80c5c6e, 0xb5861dce, 0xdbba5c21, + 0x922d87fb, 0xcfbb4636, 0xee4f792e, 0xe33e6382, 0x4cb3710f, 0x0df263a7, 0x4153c148, 0x04d48101, 0x3fc369d9, + 0xe1bb24fc, 0x1023226c, 0xd780b8fc, 0x2b146ea5, 0x48eaeac5, 0xcc9676d7, 0x9d224faf, 0xb153c1e0, 0xa57e4de1, + 0xe9b9a484, 0x7769a26a, 0xe9382a11, 0x7e11f134, 0x9638f0c8, 0x99b3ab94, 0x69dfb325, 0x09d04cc4, 0xad507452, + 0x0cb9918e, 0x99c53323, 0x4345c3b5, 0x63a269e3, 0xd6d1534b, 0x970b8e75, 0xf7aa3440, 0xbd81763e, 0xd602279d, + 0x4ffab1d9, 0x248d4dbe, 0x814a3875, 0x21ef8154, 0xa8769552, 0x04f33063, 0x4b57fabd, 0x7dc0e59a, 0xac571d75, + 0x0fb71ba3, 0xcdfd1d95, 0x1eec857f, 0x98c4c56d, 0xee47be3b, 0xe1d44167, 0x6068e1b1, 0x3ee9ac6a, 0xaab72984, + 0xfa3c9315, 0xacc57f98, 0x06a5a2d6, 0x40dbd733, 0xb9868bd9, 0xa98f05fe, 0xb9bd76a7, 0xaedd33a5, 0xe3fd3f8b, + 0xcc1f2a94, 0x0c2094a5, 0x0e492131, 0xf456067c, 0xdfbb043b, 0xf7ac2adf, 0x54482070, 0x40c32de1, 0xbf132608, + 0xa968dea3, 0x1bdd3684, 0x0293bd39, 0x14ddd108, 0x0c8f30aa, 0xaf6eb8d5, 0xb0db46ec, 0xf2a5a258, 0x41753885, + 0x95929ae3, 0xfa02f8bf, 0x86f3b3f1, 0x706b6df0, 0xfc27387d, 0x018d112c, 0x936fe12a, 0xae2a5e05, 0x580ddde2, + 0x8d4c2afa, 0x71d0a317, 0xd4e82218, 0x7f9ba5fa, 0x47c8fb2d, 0x9a2f8709, 0x55a61f16, 0x0ec125cb, 0xf03334ed, + 0x040bfd58, 0x508eb5c4, 0x202808bb, 0x32b235c0, 0xd10d1dd2, 0x4c85783a, 0xd26e581a, 0x26f47a25, 0x995af9b3, + 0xf7a31e6e, 0x71a6e385, 0x1324f0f7, 0x7437b1bd, 0x891c61a3, 0xcef0f4a4, 0x3126f9c7, 0x4c372f21, 0x4a61f50e, + 0x04713baa, 0xebc8d55b, 0x3b9a7f4d, 0x48cb00c0, 0xe24a04ba, 0x9d8f188c, 0x31f7d72f, 0xa3406734, 0x53d3f739, + 0x02859cfa, 0x98adc1cc, 0xea00b02d, 0x05ae8662, 0x2f95ef6d, 0x951aac2d, 0x119068d0, 0xa373cb16, 0xa5287238, + 0x62dab103, 0x5e3cfaea, 0x726fe5b7, 0x71f1a2da, 0x4e936ffa, 0x5d5761fb, 0x644b4624, 0x6fb5a1eb, 0x28284342, + 0xf68a17ab, 0xab9b915d, 0x9191620e, 0xe25702a7, 0x5646fc7c, 0x41564001, 0x73ba0d16, 0x616b0d86, 0x7eff94e7, + 0x03b1c834, 0x75d73cd3, 0x5da18cf4, 0x5568e208, 0x15d39d3c, 0x979983e9, 0xe88605d7, 0x6a8e8009, 0x0373d822, + 0xd9efcf7f, 0x973e49e9, 0x9cab6fb7, 0xac86c6f5, 0xd0f32021, 0xccbd0602, 0x80ed7113, 0x2a838856, 0x849e2f1e, + 0x7c9ccd93, 0xc654a9a9, 0x083d1ff5, 0x4498b841, 0xb688392e, 0x126839bb, 0x7570912e, 0x60129bc8, 0x5a06483b, + 0xbffec6c6, 0x1987c9ae, 0xe0a355f6, 0x2482c1a0, 0x47b68d3e, 0x31c360e9, 0xdbf762cc, 0xc2c752d3, 0x23a0cc96, + 0x97340704, 0x7f4bbe7d, 0xaeff8953, 0xcdfce1de, 0x6c15708a, 0x4ea9cdcb, 0xc9612d2b, 0x1acc6b01, 0x854fbeab, + 0x01155525, 0x0fc6fdf1, 0xdfd70eaa, 0x03061a29, 0x86fbb00c, 0x18136437, 0xb3b7d241, 0xb59dc1c3, 0x50af825c, + 0x2e824f8e, 0xcba0b4df, 0xa2548a68, 0x3f5c77de, 0x80f2290e, 0xeb2c6cce, 0x5ac1039f, 0xac2379c1, 0x36fdd3d0, + 0x3e9643f1, 0x2701b4f9, 0x026761d0, 0x5b8601ab, 0x3b4d8424, 0xfe8e6a4b, 0x6481950e, 0x3d65a996, 0x8f04d122, + 0xde22a6a4, 0x2d44ad76, 0xd97edb35, 0xcbca60eb, 0xca4b569e, 0x80dccafd, 0xfcd14700, 0x304122c0, 0xb95b8e54, + 0xa13f17e2, 0x2d43f8f8, 0x12446173, 0x2208469b, 0x4cf6ab07, 0x1b2fe2dd, 0x09df072a, 0x97250fb2, 0x9a1d60a9, + 0xbbd5c6d9, 0xf84b408c, 0x64ef7630, 0x37ba974c, 0x0e84f86e, 0x8ce74e45, 0xb4c5ee35, 0x32bb97a6, 0x5f8b352c, + 0x40a08505, 0x396a14c3, 0x909892e7, 0xb3135cc0, 0x2c289126, 0x65818602, 0xeb0981b4, 0x51fd674c, 0x2b2dfec9, + 0x096a78f9, 0x00d210e6, 0x8f1d6817, 0x2fbc37b6, 0x40dad669, 0xf10e06ce, 0x3e8933b5, 0xdeb67ed4, 0x3f109143, + 0xdaae041b, 0xe22d751e, 0xa0e72082, 0x6b9de30b, 0x120fa88b, 0x1d31a695, 0xf9f3a6aa, 0xa9c604cd, 0x7b6868a0, + 0x5841347d, 0xa7d66261, 0x5ca363ef, 0x023f20df, 0x3ff3866a, 0x4a53c4ff, 0xc5ddb53c, 0xb0ad0f01, 0x85cb9793, + 0x36ea832c, 0x678dce8d, 0xa724d607, 0x202f72f3, 0x47ef60d6, 0x89c2db08, 0x4cd22146, 0xdbed406e, 0x923c9b04, + 0x57a97650, 0x3e6920e5, 0xd1bcbf03, 0x27d33c89, 0x792e250a, 0x98aea109, 0xa2bfedf8, 0x16762cd0, 0x44aba3e7, + 0xd0969b3a, 0x516e5c7b, 0xb787e713, 0x7a8d0b54, 0x2da96bdb, 0x8093ab52, 0x0f7a56f4, 0xfb9c0097, 0x549b9345, + 0x4dcbe919, 0x6fe33286, 0xec2f4654, 0x31352157, 0xe1e95c57, 0xd190b32d, 0x402da6f7, 0x4f3bb9e9, 0x1ca10aaa, + 0x3b3ac6f7, 0x5633b8d5, 0xc35c40de, 0xa7150015, 0xaa0b2872, 0xec604067, 0x2d983d06, 0x6ea8456a, 0x6d69c975, + 0x61640d0e, 0x36306ec6, 0x20b26ce0, 0x3922fb9c, 0xf0b1a57e, 0xb6d2e827, 0x2f501b48, 0xa6ea23e3, 0x9e056a8d, + 0x50b2c0d0, 0xfd7c5dcf, 0xb4357632, 0x7d8ea368, 0xf91ab7d0, 0xac63476c, 0x1c8809be, 0x8baa1971, 0x00f099a2, + 0xb2228fe2, 0x0edc997b, 0x47e5987d, 0x69d582c0, 0x6b30cf41, 0xbd09aefc, 0x05200e9e, 0xdf712efa, 0x6e79718f, + 0x225325ba, 0xb1f764ff, 0x998e1f5b, 0xca1e6be5, 0x4fab43d9, 0xba0850fa, 0x8b4fcf29, 0xa29cc5ca, 0x67df5192, + 0xf4798252, 0x6a27ad79, 0xf76097d0, 0x72005930, 0x8ec51742, 0xa1118d80, 0xff4bdadc, 0x094d7c82, 0xf7a79322, + 0x1877c7a0, 0xa38a7f95, 0x87299c72, 0x4e798882, 0x87e5394d, 0x4f92fc48, 0x81f2714f, 0x034d0ed7, 0xdc92e703, + 0x5f5f719d, 0x53b6e825, 0x01ccfad8, 0x1f32a207, 0x3d8bdaaa, 0x3a484821, 0x8a6b8cb4, 0x7306653c, 0x0f73e6c4, + 0x7493432a, 0x7b18ad55, 0xe6c455ab, 0xe01451fd, 0xdec89118, 0x33cc5fa7, 0x94d179b6, 0xf27c3717, 0x51bf10d3, + 0x444df811, 0x7c9b479f, 0xc617a73b, 0x917b0950, 0x2aa3ba9b, 0x6ac37798, 0x0922d94d, 0xfacf9142, 0x1d802e5b, + 0x916f0ba0, 0xc8f3d66d, 0xa1fb48db, 0x7e6b5e7e, 0xbe8f3d5b, 0x58af1de3, 0xde97262c, 0xac5af89a, 0x73f5b9b7, + 0xdd06e891, 0xfae24917, 0x05c1fd2e, 0x6d1751df, 0x4db17439, 0x17e4cf86, 0x003a4bf9, 0x00f6683f, 0x32d99dba, + 0xe618f067, 0x37b2d7a9, 0xe9238f4d, 0xd81cdaac, 0x836a5f80, 0x7b398349, 0xc5c7db1f, 0x5c1cf447, 0x9fd4dace, + 0x4c967fe8, 0xac8b65da, 0x11cb2ce5, 0xecca6241, 0xb87309ff, 0x64398521, 0x750274d7, 0xca767c0a, 0x27d0ca81, + 0xc812c9fc, 0x7dc91e6c, 0xbb05a42c, 0x9c192f81, 0x3a3e4928, 0x0f2a461f, 0x434fc2b7, 0x5a82c8ff, 0x389d53be, + 0xbc24bb7b, 0xa60c29ec, 0x53b1cfbe, 0xeec2c519, 0xf73a07d6, 0x0d050bbb, 0xf8fa2a55, 0x1979b86e, 0x393e1667, + 0x57d16007, 0xc8d3a493, 0x7bdb15cb, 0xe2241173, 0xa2952c78, 0x2f347690, 0x8967119a, 0x5dfeb53a, 0x7c62b7ca, + 0xf36540f5, 0xd7189c8b, 0x45e45cfa, 0x8020ffd8, 0xfe23d8bd, 0x074fb896, 0xfdf03fa7, 0x1eb36ee6, 0x96b84d3d, + 0xe08f8bc4, 0x2f3337aa, 0x4736815a, 0x73f08734, 0x18cf9d74, 0x16760bf8, 0xc9e275b6, 0xd46af64d, 0xd8fff8a1, + 0x6d397232, 0x0c6700d9, 0xbb8735a9, 0xffcc7d92, 0x12b4cb20, 0x32562e38, 0x3423f456, 0x719eb169, 0x50b0d75c, + 0xb5f209cb, 0x9d558149, 0x3144d55a, 0x72bc594d, 0x0f7bcf2e, 0x8f4b9f78, 0x1dd98e9e, 0x21c1d9c2, 0x8a9eac58, + 0xdec77d2f, 0x89e2e4c9, 0x6c2e4a03, 0x3712877f, 0x4d444bf7, 0x9e4c4c1c, 0x64e51b22, 0x2e682bc8, 0xef413272, + 0x2deff287, 0x4cde085b, 0x480de8ec, 0x98188358, 0x254d04e3, 0x55843ce7, 0xd0a3be12, 0xb92c275a, 0x9e89377c, + 0x061f8643, 0x871bac7b, 0xf2b5d4a0, 0x2b3cbebc, 0x03d7c553, 0xbb6a393f, 0x1d9077cb, 0x49c7b283, 0x684b5faf, + 0xd447afaf, 0x8fb79882, 0xa62d846d, 0xbc3716e0, 0x76d1a83d, 0x493eead5, 0x968db717, 0x8e6e136d, 0x26bf0b26, + 0xfd5b0e96, 0x7953660c, 0x342e1ceb, 0x17d6a282, 0x0b2e90c7, 0x98a5b91f, 0x85aef055, 0xc5b78d20, 0xa7fbdd96, + 0x183c9705, 0xaba1c88f, 0xd1abd085, 0x877d785b, 0x920d30d7, 0x5f9da3c7, 0xd7d3e4c7, 0x11c5d80f, 0x2438a28c, + 0x28f787ab, 0x4f43c69c, 0xfb074522, 0xfc162188, 0x16434662, 0x4d364a79, 0xa78c5188, 0x5e587284, 0x553126c6, + 0x4340d813, 0x50f247b7, 0x2cbbfc9c, 0xc4496a5b, 0xf2a0a074, 0x717a714f, 0xd5f85a9d, 0x93b33602, 0xde7c1656, + 0x261ae463, 0xe01a1147, 0x8ef5d6ae, 0x5341e062, 0xf13c7b04, 0x41bfa161, 0xde05160c, 0x2792ae51, 0x4ce67c05, + 0x2453169e, 0x4ca95abc, 0x533452aa, 0x6f76d2ee, 0xf2ee7764, 0x5d201a7f, 0xc5506f24, 0xa263fe4d, 0xbed30834, + 0x5eb2e9b8, 0x6d41c507, 0x3eeea9aa, 0xee09c6f9, 0x0860fcdc, 0xf82923a4, 0x2f4311b3, 0x44bde54b, 0x1987baa7, + 0x58b15a07, 0xe0a92b86, 0xd367a6f2, 0x6ff67fa5, 0xa8ff5b55, 0xb178b644, 0xac506035, 0xaba34f82, 0xe120a1bf, + 0xf2a43028, 0x5ab1929f, 0x1ddd1e0a, 0x95f15271, 0x3cc2bc40, 0xab2e4f47, 0xddebf516, 0xa5f94ffd, 0xd4c65eed, + 0x4cb95c63, 0xea6d6aae, 0xd646d96a, 0x774eb2e9, 0x66d761d6, 0x0832556c, 0x90a9ce1f, 0x90999bc9, 0x25b839b6, + 0x4a0408b5, 0x7f431ed7, 0x05ef0121, 0xb861272c, 0xd81a4bc2, 0x567e543d, 0xe6278588, 0x3238feca, 0xe3b98eb8, + 0x81c90b95, 0x26dbc3b6, 0xfc9dcda2, 0xc0aeb81c, 0x5aa585ca, 0x455279b7, 0xaeb640d5, 0xb5f9d93a, 0x98f02346, + 0x350847f8, 0xe8f57d79, 0xeaa50de3, 0x095033fe, 0xf1b89c7f, 0x286b64d9, 0x7b3467bc, 0xd5a742ff, 0x96edb7ff, + 0x43ae24aa, 0xb82fae99, 0x7af6b644, 0xafd76680, 0xa019e388, 0x3343c22d, 0x24db2baa, 0x83c501f9, 0x679f5007, + 0xe6b0cf4d, 0x9d104e1d, 0x53bae175, 0x712fb392, 0xa82621a8, 0x10624441, 0x9399583a, 0x999de29a, 0xe301a698, + 0x3c5fef60, 0x0864f791, 0x84ea0585, 0x6f650bbe, 0xcc460376, 0xb1d7ac48, 0x6c16d3da, 0xe20316c2, 0xd1e27843, + 0xb6bd526d, 0x6a690c63, 0xa75d60cd, 0xa077c2ac, 0xc0998d09, 0x66d97e65, 0x556a648c, 0xeb9a7649, 0x1af11926, + 0x68b382cd, 0x7a375f9a, 0xbb9a8715, 0xff69f301, 0x4ff981e1, 0x4c3a5124, 0x1af6e96c, 0x60347c4b, 0x81848f76, + 0x5307a3bb, 0x4ec88635, 0xd4f3be88, 0x93994895, 0x3c70d76a, 0x9064f08d, 0x0da15742, 0x7c8bf683, 0xc9e227d6, + 0x4b22965d, 0x5032be0c, 0x2d491275, 0x1906d423, 0x8c7acf26, 0xf741da69, 0x539439d2, 0x29398255, 0xe85b78bf, + 0xa267891b, 0x97f5c6b9, 0xafaff6c4, 0x414752e0, 0xa2e6c29a, 0xf6dee6ef, 0xc3633dda, 0xe012b5b2, 0xec1adb70, + 0xbbcbec43, 0x8e2cddc8, 0x23975505, 0x8a509c08, 0x10e5fb15, 0x73f353f8, 0x79d90e12, 0xeaf478d1, 0x5d4f0e5e, + 0x8b91515d, 0x613f62e8, 0xf29d8f1f, 0xeb3bf1d4, 0x378bacea, 0x4720a15c, 0x5e75ddbc, 0x9e61b55a, 0x145cdaa1, + 0x57edc6bf, 0x6b50947a, 0x726701d1, 0x787b3797, 0xf04e23ca, 0xf247d1ec, 0xcbc7633f, 0x667d7035, 0xeaeb95ce, + 0xb6254412, 0x946a12f0, 0xe9ca56ac, 0x5425ae7a, 0x640561e4, 0x5626a27f, 0x2edd1e9f, 0x0df36620, 0x8a168e2c, + 0x47a7d665, 0x30072ec5, 0xc4926167, 0xb2851664, 0x5dfaff52, 0x7cb09534, 0x4f2a8b9b, 0x9b939159, 0x3ed6536b, + 0x9e190a46, 0x19f47f69, 0x8a6127e5, 0x94ac9766, 0xeacf6246, 0x5605a597, 0x6724acfd, 0x4a43ccd8, 0x56c58ba5, + 0xf9c2e53a, 0x6bc0f625, 0x7b56190e, 0xe1f6bf9a, 0xe15dffca, 0x9e92de2b, 0x04a31a6b, 0xe262aa29, 0x0898c511, + 0xf7ebe762, 0x1e10fc9f, 0x67f302ac, 0x72abfbe7, 0xa83908b3, 0x9756eaa6, 0x3062caff, 0x915b145d, 0x0234f833, + 0x2cb0c768, 0x33c3db76, 0x3298b008, 0x232f0bf8, 0x97f39340, 0x864f7ecf, 0xe46d22e0, 0xa74a7207, 0x1eb2d725, + 0x9bd723b5, 0xd6c43582, 0x40a1432f, 0xdc2862cf, 0x8b43c9e3, 0xe610a6a4, 0x453cea86, 0xb9e89284, 0x009c7335, + 0x8e0dea31, 0xc6a4f8cc, 0xa0df1b7a, 0xea0fcbbe, 0xc920a77c, 0xd554081b, 0x2e2db942, 0x7bc9a249, 0x7dd6c11b, + 0x472e86ce, 0xb1165536, 0x24cd894b, 0x719a8112, 0xc2fb1822, 0x5ba2aeed, 0x361ab63e, 0xd72c8c94, 0xbe2b2c32, + 0x36c0017e, 0x3019ffb8, 0xa5efc7c5, 0xb4c020e1, 0x50d6ce86, 0x50abcc16, 0xedc7abe8, 0x603b2e95, 0xd2f24864, + 0x2683eb65, 0xc6849085, 0xb5cb0d6a, 0x6f7a5749, 0xd14141b0, 0x0fa08e13, 0xd1b4fd8e, 0xc7c9f105, 0xc78419e7, + 0xe9837c0b, 0xaddfc851, 0x9b8a8449, 0x3551a18d, 0x4c5f227a, 0xb796b4a3, 0x26af478e, 0xde1d91af, 0xc9df752a, + 0xe95beb7b, 0x93bb60ad, 0x8a3c9694, 0x155c800f, 0x999f900e, 0x203669af, 0x0f25a381, 0xc36ecd43, 0xe8f13dfa, + 0x03b351ec, 0x7c30818e, 0xf9608ce7, 0xdfc3a12c, 0xc6e49bd7, 0xda59f96f, 0xb94a688e, 0x2d9a1faf, 0xfa46f37d, + 0x1ecab65b, 0x9085f3ef, 0x8234aa73, 0xd3084fec, 0x4f8cc620, 0xfbf985ee, 0x3a57cd65, 0x64f3c3de, 0xf37a92a6, + 0xcd8d628f, 0x35b6f51b, 0xa62381e7, 0x48366ff2, 0xe2693ff9, 0x43a1b3ba, 0x152cbf7c, 0x10ccbbac, 0x4030fe0a, + 0xef896114, 0xe93248ab, 0xe12270be, 0xd8b8df79, 0xafbc08c5, 0xd1d58e20, 0xe87084fc, 0x5d2f4e5a, 0x58a4c6d9, + 0xe1f5c5f8, 0xebb1ba96, 0xdb5fad22, 0x45a1566a, 0x848ee1d3, 0xf921b96b, 0x720519a4, 0x6cef95ef, 0x7f4af4de, + 0xded81305, 0x3529361a, 0x3aeb46e8, 0x8e942af1, 0x52eb93ac, 0x828a667d, 0x7de76da2, 0x6b9977d3, 0x46950357, + 0x3b4615bd, 0x75eac847, 0x7d489020, 0xfaeb234e, 0x38f91fff, 0xb66eee71, 0xb9047f7c, 0xf6ab3bf2, 0xb723de53, + 0xe47af99a, 0x80f155b8, 0xfeff119e, 0xd9f28770, 0x27f4580b, 0x56ddfeac, 0x8296e085, 0x83629788, 0x2d8df254, + 0x8b55fa4e, 0x521e38cb, 0x6ad4c5ee, 0x4b83bf3c, 0x62da2efd, 0x4db08c6d, 0xb3c3d8ec, 0xaad22f33, 0xc49be2cd, + 0xee403abf, 0xbc874fb8, 0x93f94ce7, 0xa977ab14, 0xfd355627, 0x43ceafa0, 0xf002fe06, 0x776a5576, 0xaaea6dad, + 0x20c83341, 0xbdfab66c, 0x8f0015dd, 0xb4328bca, 0x59af5852, 0xcce31eab, 0x829d62d8, 0x72cf3c91, 0x23a6dfb0, + 0x2f5bffb2, 0x6b85336d, 0xf4d51e32, 0x029d9c84, 0x4ff8cc53, 0x0de0703c, 0xd419658b, 0x140b198e, 0x3e89a5cb, + 0x00b4b683, 0xccdcceff, 0x4a46abfe, 0xe0f69709, 0x7079d795, 0x62753e29, 0x0d12ac72, 0x17b6764a, 0xb049c943, + 0xcd1001bd, 0x1d0a5476, 0x624c9a22, 0x0433031a, 0x85a66c46, 0x9bcef275, 0x9dae89b7, 0x193ea430, 0xacefaf4b, + 0x6046401d, 0xe2d6426c, 0xf1dcaf3b, 0x27cf9d24, 0x8299354d, 0xe9b01d65, 0xe5b0e90a, 0x322313ea, 0x42bcf391, + 0x6d291552, 0xf9e61f92, 0x3b5d1f07, 0x639c3469, 0x956168d5, 0xdd3c8e89, 0xc449aa57, 0x0549d659, 0xb28a23dd, + 0xf572b5f8, 0xd1783969, 0x9e911006, 0x21e85a83, 0x1d3e5aed, 0x6e6f46fc, 0x5375e79a, 0xf2d4fc69, 0x1c17706d, + 0x03854174, 0xb8b766b3, 0x17502bce, 0x24f5da76, 0x70259cc0, 0x9c9c68ce, 0x2fa094fc, 0xf7212495, 0xd63f39ec, + 0xcf2cf301, 0xa9f9c459, 0x2d0ce874, 0x7bc957c8, 0x21a4ae91, 0xe40e3535, 0x8c75eab3, 0x5b210351, 0x6a260533, + 0x856ca5f8, 0x86498345, 0xf3a1f490, 0x628b7e05, 0x4f487db8, 0xc25f353c, 0x8637cec0, 0x6574aaae, 0x82dd2c6e, + 0x11ded859, 0x71e86a54, 0x26093db8, 0xec84c2bd, 0x9d35edcc, 0x4f375810, 0xcbb07847, 0x250c3cd9, 0x906199e5, + 0x1bea8a9b, 0xe3182f37, 0x990f6a90, 0x26f21c0c, 0x77003f08, 0x7de750d2, 0xf35f5e20, 0xfdee1cac, 0xffb9b23f, + 0xa8534bbe, 0x7c979aa5, 0x65a3eda3, 0x9f712521, 0xd5dca1c1, 0x8d71c19e, 0xbbc6ae98, 0x4d064186, 0xaef426d7, + 0x517b14a7, 0x43a39b0d, 0x2b7aad9c, 0x813ff46c, 0x32912c65, 0xc3f5f1ed, 0xa1d58eb2, 0x5415877c, 0xe133c436, + 0x9909a079, 0x410b9cbb, 0x2c06744e, 0x1cb46890, 0x3d237ff8, 0x11fe2edb, 0x39ae1e44, 0x739b991a, 0xa783575a, + 0x84f1294d, 0x4422e410, 0x9893a6f0, 0x6d748e23, 0x6b2446c9, 0x21ccc31f, 0x1de161d5, 0x994157fe, 0xfa5ddf7f, + 0xa789c546, 0xdacc79ce, 0x51317025, 0x8d7c06eb, 0xcfc02395, 0xab526188, 0x8455667f, 0x59dc4a93, 0xd9b07d3f, + 0xf33a7d20, 0xf7b02f11, 0x3ad5953c, 0xf3ae5eeb, 0xdaa512a9, 0x6ba8ef2b, 0xc7fbcd3c, 0xbd4668c6, 0x425bfd45, + 0xa5194b3c, 0x42b34ff8, 0xbecdcbef, 0xc209a52c, 0x537a6c76, 0xc07bf3cc, 0x5de357a8, 0x4e20337b, 0x9a0129f5, + 0x56289ddc, 0xe09d27e5, 0xe2c05627, 0xb891ff65, 0x6d7a32f1, 0x5d8a1cda, 0x4fe1a0f1, 0xd3950c1f, 0x833a1c98, + 0xd588465f, 0xed043df8, 0x50e7dacf, 0x50256818, 0xbee6b41b, 0x47ecbf76, 0xe89d6e49, 0xaec9bc8c, 0x90bd9143, + 0xb13b453b, 0xbb1efaa5, 0xbeb7f6b8, 0x28462d1c, 0x514d6b40, 0x3d3eeba1, 0xe0e3b477, 0x7db435d5, 0xf4737ccc, + 0xb548cb6c, 0x70fc1f4c, 0x8d566c0e, 0x58e80640, 0x7222d0d4, 0xbe27450f, 0xcc969385, 0x8d2a3e2b, 0x802b77ac, + 0x85bb82b6, 0x83385021, 0x73d27d0b, 0xef29f586, 0x51ad0c26, 0xbcc0f05a, 0xf82c0e7e, 0x3c6d10c1, 0xa2fc1a26, + 0x453e7326, 0x7729cb53, 0x17d9f8a2, 0x4eb0128a, 0x823680c8, 0x3eb3fd58, 0x3a168d5b, 0xd6d7cc55, 0x88aab83f, + 0x6bdb1693, 0x23bf681c, 0x6a7cfa25, 0x052babce, 0x1dd94618, 0x1056b106, 0xa01c5421, 0xb71c8ad7, 0xe7040cdc, + 0x95dda57d, 0x4490e38c, 0x39714e33, 0x5c6e52b5, 0xe8e9a202, 0x00232758, 0x758573cd, 0x3dcbc692, 0x41bb3e9a, + 0xe4d6abf6, 0xa0ae8235, 0x99185e66, 0x01b8ec58, 0x872196b7, 0xe521cf2b, 0x8b73fe68, 0x9fbe637b, 0xe0f42b70, + 0x67c6c4f2, 0x1a2c371a, 0x7047aa3c, 0x94c0d1d6, 0x68bd4bba, 0x96bdf0e2, 0xf279b3c6, 0xfc3fc2da, 0x3d400901, + 0x220ab959, 0xf0581d5e, 0xf3f99611, 0x6231a118, 0x1ba59e35, 0x0e6529a5, 0x4173fb25, 0x46205358, 0x3e8e15cc, + 0xd0d0fe07, 0xc7c4facb, 0x2fd5f348, 0x7e55c22e, 0x349c83c3, 0x8e11b41a, 0x52a098be, 0x2fa0f896, 0x7b4e84f3, + 0x8f64c6e9, 0x174aa1f6, 0x63330280, 0x3de48be5, 0x297a530d, 0xc2d453ef, 0xd3237df2, 0x7eac3cd2, 0x846edbb4, + 0x81358464, 0xe5be5b01, 0x79367c88, 0x43bbb705, 0xb5ebed17, 0xb24d4a04, 0x92226c3b, 0x7c5d7a9f, 0x668199c9, + 0x2b7feebb, 0x6149704b, 0x43b5a1ee, 0x4dbb2454, 0xc8ddf020, 0xf324b0e8, 0xfdd12034, 0x20d8e3fc, 0x9c7963b9, + 0x13e4b8d4, 0xae417954, 0x0069df05, 0x8c69ef82, 0x68231a8a, 0xbc6ef596, 0x3684436f, 0x34200460, 0x59a75b96, + 0x5aac9331, 0x29390764, 0x68b8a132, 0x854d0083, 0xde7a5bf2, 0xc3e843c3, 0x954a6a04, 0x98e05f3a, 0x9f6bfaec, + 0x0541fdf3, 0xdb3a65af, 0x64e4d6b3, 0xf32d8ce0, 0x26bb4a23, 0x689d67d5, 0xb1d659ae, 0xffa5c210, 0x66d641cc, + 0x8616f62c, 0x9d371246, 0xbb0b676c, 0xca6f2e60, 0xe39773a1, 0x34639202, 0x1ab4017e, 0x4c00b984, 0x51307b22, + 0x38577663, 0x81021bdf, 0x9a608c08, 0xded4fa1f, 0xcad56213, 0x1a8c41b4, 0x7fa3d4ed, 0x7dea75ba, 0xd50c8e72, + 0x82d95045, 0x21d95cda, 0x78d9125d, 0xd27fd5ba, 0x2c82a39d, 0xbc0d0449, 0x04ac8873, 0xf042fdc5, 0x4026bacc, + 0x271d7ba2, 0xf642c436, 0x85c4c41e, 0x921f1a0d, 0x5c8808d9, 0x2880c930, 0xfc207aad, 0x8f3c7697, 0x0e8969a7, + 0xc14ce8b0, 0xa2f625d0, 0xccf7bd3d, 0xf6d6fee4, 0x80667a10, 0xbc114448, 0x748fe075, 0x7b732d6d, 0x93d6228d, + 0x0b55ff6d, 0x74825f05, 0x96061d7a, 0x6b6f7a72, 0xf26f9fe8, 0xc478f963, 0x48485510, 0x89b10a0b, 0x43147cf7, + 0x6b47c05d, 0xf185a5f4, 0xbf1402e8, 0xb4a1be30, 0xc43cb230, 0x6de2778b, 0x9a1b3861, 0x77b55d3f, 0x05e1f2c8, + 0xe4178e99, 0x6cb3f8f4, 0x2d3d2f28, 0x85258214, 0xa1502748, 0x658aa087, 0x2e6a6282, 0x62b1af7e, 0x596a7f73, + 0x2edc71f7, 0x41a0f850, 0x56986947, 0xf6ee9ce2, 0x2fbfacd4, 0x4de3969a, 0xf107d907, 0x02f9f083, 0x5df9a0f3, + 0x43c131ce, 0x03ecd860, 0xdc380eca, 0x1cebc208, 0x29b9c1d0, 0x5f9c0737, 0x8d9a6f42, 0x4bc33670, 0x993e29cb, + 0xa711e392, 0xba2b38a2, 0x55c0c35e, 0x427a2a57, 0xba38702c, 0x7a148cc2, 0xe045d2d0, 0xc70a1cd3, 0x43082be5, + 0x7d65653f, 0xc10d5f05, 0x4b3ff1a7, 0x1dbf3d27, 0xbc9b1b4a, 0xc1e1631a, 0xec5960b3, 0x3a3a5e74, 0x862763b6, + 0x7f101d6d, 0xb162e168, 0x52767874, 0x004f09c5, 0x5402cc01, 0xbc942ab1, 0x9dfe0207, 0x7b2935f4, 0x9ca0c769, + 0x6bd484bc, 0xc66e5349, 0xabd415ff, 0xd88f1d7b, 0x735cd144, 0x279dc393, 0xb10af153, 0xbb4d5f02, 0x7669cb49, + 0x28274ae9, 0xbaad7c66, 0x44b6a377, 0x5687b0b0, 0x1d7e56c2, 0xda634acb, 0x9124e4c5, 0xeb7f04ac, 0x5de02c27, + 0x04f24e8d, 0x19a2b49f, 0x077e7ab8, 0x40ee8861, 0xa9fa3464, 0x25e63ddd, 0x829598f6, 0x1ac6c174, 0x3e64593c, + 0x7acce2b4, 0x6a3e0e37, 0xf578b741, 0xafff99e4, 0xbd723dbc, 0xe2485c41, 0x50bf52fc, 0xd093a7c9, 0xf3ccd4d6, + 0x5a11e596, 0x48d1847f, 0x33126f21, 0x690d0efe, 0x69850960, 0x07ecec47, 0x7e55fd41, 0x2a1a03e4, 0x45ae0cb6, + 0x16369044, 0x03c4513e, 0xc9e0438a, 0x46737e0b, 0x457dd785, 0xec3e2360, 0xa030db42, 0x9aa498a7, 0xb02a19bc, + 0x508aa0b8, 0x238b1a2b, 0x2bcbad90, 0x831524cf, 0xf9f58c3c, 0x4a1757db, 0x1df61e3f, 0xefb2e638, 0x48c080ab, + 0x70e669db, 0x19bbbf43, 0xd3b0b82f, 0xa8226fee, 0xc277ce4d, 0xd2db4153, 0x07fedc43, 0xeec62aa3, 0xe1dd94fd, + 0x29a48662, 0x360bea07, 0x271f6c8a, 0x613c5389, 0x601f15ac, 0x042f5a0a, 0x3365224e, 0x8b41c347, 0x37e8bf68, + 0x9ce3a121, 0xebe484cc, 0x8ca352b3, 0xb524a930, 0xcaa04c55, 0xda3f3f7c, 0x391b86d6, 0x3fe6ecba, 0x6afad6e3, + 0x1961a667, 0xed5c622e, 0x0d16c3ec, 0x29fac65c, 0x305c8843, 0x2dc2ba3c, 0x02de3f0f, 0xf2337cb4, 0x8f175c94, + 0x9f79941c, 0x8efc2220, 0x77a19695, 0xfc71063a, 0xd806201e, 0x0a4f9235, 0x45b1f13e, 0x82e21f2a, 0x733b89bb, + 0x4931d706, 0x66e91369, 0x5a20713d, 0xc58ca1e9, 0x7ac95a44, 0xfda8f1bd, 0xaca825fa, 0xffa482ed, 0x530af716, + 0xc993e2eb, 0x66c28518, 0x5583ff79, 0xc6dcfbb2, 0x75c4b8ed, 0xaaacdb35, 0x83d4584a, 0x76bb6dd7, 0x7d63656c, + 0xe80eb982, 0x779c21a0, 0xd59ea7b3, 0x31783c6c, 0xcab8cf77, 0xce072dff, 0xeaaa199d, 0x68a2879b, 0x7aa43dc8, + 0x41338ee3, 0x18c4d576, 0x28fe702d, 0x30d2536c, 0x4bc89e2a, 0x4dee3a79, 0x58e667fa, 0x454d278d, 0x3bb65ae8, + 0xd25525d7, 0xb6055a7f, 0xc0d3ef12, 0xbf94b5e3, 0xa30765ec, 0x2c1e30a7, 0x8f28828b, 0x08f5dee1, 0x012748ae, + 0x26faff79, 0xf575602f, 0x6b17428e, 0xe6486ca9, 0x69b2150d, 0x749c0a5d, 0x21f29aca, 0x360e1509, 0x81209784, + 0xa4f4812d, 0x1f0d9eba, 0x5a056c8a, 0x94d85a8a, 0xb5f1d197, 0x13420736, 0x7dc9cf72, 0x35f1765b, 0x2952c1a1, + 0xee0c9681, 0x9b8a8625, 0xa0cc50de, 0x969d5587, 0xdffe62d8, 0x468a395a, 0x052ca87d, 0xffb41c0f, 0x9b6eb355, + 0x4d6227c2, 0xc5be5227, 0x68485521, 0x28eea4bb, 0x74e6d294, 0xd76e3a73, 0x44283140, 0x5054e300, 0x4f694a28, + 0xe06c2455, 0x10f3d616, 0x297f400a, 0x73c41992, 0xe0806632, 0x4ac98467, 0x789da7ba, 0xdd6b2b0e, 0xee0a33aa, + 0xa5b0dad6, 0xdb0acf4f, 0x78cb648b, 0x19928e4e, 0xa995d0ad, 0x658e6444, 0xec1c4886, 0xed2d5463, 0xda6f36ba, + 0x8f9c76dd, 0xdcd14c69, 0x2280ca80, 0x0c3d5427, 0xdcc7debe, 0xe3f83ac6, 0xd54c07a1, 0x4ac27ec0, 0xbfcfc445, + 0xeca25453, 0xc73824b2, 0xeac634ea, 0xd0b95c78, 0xe1bc442e, 0xd2c8575d, 0x983d1a06, 0x5f106e3a, 0x79436694, + 0xbf60025d, 0xd7005ce6, 0x686ef26d, 0x87b4fab9, 0x2c32f5b2, 0xa363efed, 0x58b1c4d9, 0x402dee1e, 0xa5d55e77, + 0x2058d42a, 0x327624c6, 0x6ef09472, 0xbae612f7, 0xd32f4a3c, 0x6e3ae76c, 0x3c353b09, 0x029c2d52, 0x783fe7f0, + 0xe5d216de, 0x9b1bd183, 0xbdac17f0, 0x99d49ccf, 0x90d2bd59, 0xeceefdd9, 0x7282a2b6, 0xa7975300, 0xab39f2f3, + 0xb1d67140, 0xb98e5c20, 0x1e5a2f5e, 0x5320183c, 0xa90bddba, 0x26414e00, 0x9e51d0bc, 0xb462ac78, 0x8b43b0bb, + 0x7b95d7f0, 0xab111075, 0xce15158e, 0x8996aa71, 0xc050cba0, 0xb3d15356, 0xfb2b5038, 0x5254c5ba, 0xe29ed9e4, + 0x442e1b9d, 0x0355eb24, 0x7d90bacd, 0x38be6c6c, 0x19011c5e, 0x402b9bf5, 0x8249356a, 0x9f476a09, 0x0d1b8514, + 0x5933c628, 0x642e6b28, 0xfbb1706c, 0x6f90ecf5, 0x0f2ee452, 0xe7b76596, 0x2b08de88, 0xf4883a13, 0x0d533209, + 0x21d6a238, 0xae258b1f, 0x1b515ce5, 0x2102da2c, 0x2540dec4, 0x2e3f86c2, 0x92cdb541, 0x1294b59b, 0x09e3ae49, + 0x81ca35b9, 0x29056d6b, 0x6e76468d, 0x7748c24f, 0x43362489, 0xfaeb383b, 0x42e438db, 0xa1314bcb, 0xae0b780d, + 0x8500425b, 0x680e69dc, 0x86f5057d, 0xffe3e3ff, 0x90ef335d, 0x9a4e597f, 0x3cd4c765, 0xbc6cd704, 0xc693090b, + 0x2c8fd383, 0xf9b93b02, 0xe579451b, 0x8d0b3a3a, 0xd4bfdbf2, 0x6555eb95, 0x8795731f, 0x084dd82a, 0x5dabfa7e, + 0x08d7791a, 0x10a791d7, 0x5697a786, 0x8cdc1f06, 0x3ce17588, 0x237406b0, 0x5322f285, 0x6042b5d5, 0x64447ac1, + 0xacc6585c, 0x288a8fc4, 0x2cc068d0, 0x90d26383, 0x27864ce0, 0x142ac209, 0x5ffb92c7, 0x70c662ab, 0xf918d0fb, + 0xf1246814, 0x3734734a, 0xde5c0cb3, 0xfff4c5ed, 0x43b8f7fd, 0x83283ad8, 0xc5eedaef, 0xce34b0e9, 0xff36f051, + 0x0a9ae8c0, 0xe6d6c871, 0xcb7f9bd1, 0xf0d5031d, 0x0e8813f2, 0x7ced807a, 0xe66322aa, 0xa6ad760c, 0x7678ebcf, + 0xb4e44422, 0x380b1085, 0x460db7cc, 0xd81a94af, 0x060a3060, 0x9e732c03, 0xe5180150, 0x4d24c1fe, 0x0ce661c8, + 0x325ec415, 0xe3425809, 0x80a7d8bb, 0x44ce82db, 0xc663e240, 0xbb953444, 0xf34c2838, 0xf425b8c3, 0x43d429e0, + 0x656951c5, 0xb4427ac3, 0xfbe4b830, 0xa3aaceaf, 0xf0196aed, 0xa549a36b, 0xdaaa22e8, 0x0887f36e, 0x3921d2fc, + 0x7055cd83, 0x72666e5e, 0x2d31ed10, 0x410cacbc, 0xb1918413, 0xd77f14bd, 0xc1dc2048, 0xa29f4126, 0x8533c260, + 0x8755f137, 0x2b21fe37, 0x58339225, 0xa7235a64, 0xdab18a7d, 0x70516e03, 0xb69ae62c, 0xd1cf9b99, 0x169565a9, + 0x89ac512b, 0xa8c322fc, 0xbac9958f, 0x6226b7cd, 0x41a4e900, 0x30992079, 0x5db33c10, 0x409f6681, 0xfed20e81, + 0xb20e97da, 0x85fde6bd, 0x5a2f81ec, 0xa31c74ad, 0x41feb6fd, 0x8021b36c, 0x41cd2395, 0x3c51cd81, 0xd0952eba, + 0x3c7388a3, 0x244375b6, 0x68aea91a, 0x9af63fdd, 0x73e678e3, 0x0364c92c, 0xd83f8a96, 0x185f725b, 0x173cbabd, + 0x0097c0d8, 0xe1865740, 0xd9b9cca8, 0x93eb46c5, 0xdb9a0065, 0x154fb2ee, 0x499c0e39, 0xaa76d4a3, 0xfe633eeb, + 0x99d6c9b4, 0xd546ecad, 0x158ed3e0, 0xc1dcb38e, 0x851bdd45, 0x9ccd3fb7, 0xaee35a9c, 0x2d50cece, 0x1f0d59d2, + 0x22d645ef, 0xdc6b984e, 0x1f0664ce, 0x6bb3439a, 0x931bd6d6, 0x93292de2, 0x923a86df, 0xb19806c8, 0x685be899, + 0x25634cfa, 0x2e6b01d5, 0x492ca186, 0x5af69881, 0xe7356aa1, 0x17778273, 0xb00a1793, 0xc2aaa159, 0x06ff21ef, + 0xf95c22ab, 0x1de3ed01, 0x0d95b392, 0x21d3791e, 0x9f3236cf, 0x974fb682, 0x9429bcce, 0xac268af7, 0x3d74c0bd, + 0x261fb639, 0x9b22cd9c, 0xac282a8a, 0x2dca57b0, 0x480fafd9, 0xe2966ee9, 0xfa5fe47c, 0x821f4851, 0x443c05ac, + 0xa412c5b5, 0xc668eddd, 0xd0b7a45f, 0xdb2d7633, 0x0c78d2fe, 0x64bcc41f, 0x24c2c956, 0x2ab6c421, 0xba8b34cb, + 0x87939ac5, 0xea4e8893, 0x9d03fa5b, 0x95c2121c, 0x1a4321fc, 0xc81e9791, 0x7e51af64, 0x424d8b63, 0xd8fd58bf, + 0x5daa1622, 0x5a932263, 0xe0ba834b, 0xec7fe2bc, 0x85554005, 0xc727c739, 0x1555a88b, 0x2661395f, 0x4fe39e9b, + 0x16dbc4d0, 0xc57f557d, 0xa1a72927, 0x9a1ac0eb, 0xa77367e7, 0x1b4ec5f0, 0x6da05016, 0x1663e09f, 0x9aee71ac, + 0xd9401d29, 0xe2225792, 0x736d1e3b, 0xb2a7fec3, 0xaeefce82, 0x6d523f56, 0x4a34cdb3, 0x377aca0e, 0x9688bb2f, + 0x9f410a22, 0xecbc05c2, 0x59779dcb, 0x693d9100, 0xd63f35ef, 0xcc452b74, 0x7da57334, 0x84401a60, 0x89b59bef, + 0xba24ee15, 0xdd15bf52, 0x805023e3, 0xa7b7e629, 0xcaa0bd98, 0x814d8aac, 0x8da7d7d2, 0x85ee9b47, 0xdf182cca, + 0x3f978a92, 0x5167cc1e, 0x90bebc5a, 0x6f36d63b, 0x2f63b027, 0x78b2f608, 0x0ce45fb3, 0xa212ba58, 0xd1d4b552, + 0xc0d0dde3, 0xc366f3be, 0xa4ed71aa, 0xd52293a9, 0x55e33e65, 0x066d4462, 0xcd925772, 0x45eae458, 0xd06d270d, + 0xaa19d680, 0x7705b3f3, 0xb95c0b97, 0xd37066bf, 0x1041ca88, 0x2bccfcab, 0xf72b74bf, 0x39b6ee90, 0x540868b8, + 0xd0212b80, 0x7bce67e5, 0xa39c5d2f, 0x06f48bd2, 0x76c5b2d5, 0x93879131, 0x9230ea11, 0xa42adb65, 0xd5bfa3ac, + 0x5061f6c5, 0xf957b407, 0x908860f7, 0xc30c0ce6, 0x0ebef4bb, 0x215fedbf, 0xc8783f25, 0x94aa76f4, 0xed32ba36, + 0x0f8e97e1, 0x81112c92, 0x2647889c, 0xd9f2c43f, 0x5fdfe76a, 0x8a0e409e, 0xbe8baa0d, 0xde6c9313, 0xb864f97a, + 0x5a21b82b, 0xa4a08fa5, 0xae5acffc, 0xfc86907b, 0x475b5572, 0xbe145e49, 0x3e969c0f, 0x210845a7, 0x355e3996, + 0xe7733f62, 0xb3ed2815, 0x48509198, 0xf7685686, 0x9330eac1, 0x6a18b116, 0x2ecbeebc, 0x19d7a186, 0xe95a7c5e, + 0x641e29c0, 0x9b81fcc8, 0xc34708b5, 0xbe1f5f10, 0xd4fb956e, 0xa3ab2745, 0x98681212, 0x5a633731, 0x8bc98dd3, + 0x373c3437, 0xb1a9ca10, 0x82fcd83f, 0xcd313ee5, 0xa5600dde, 0x7af2defe, 0x68061e60, 0x159c87fd, 0xd35aa092, + 0xf5a85c51, 0xde6ae60f, 0x12e7c21c, 0x94ff4cdc, 0x2a6b2713, 0x1bef3620, 0x40ffef9f, 0x3075998f, 0x5443f001, + 0xe3692031, 0x28634f85, 0x984e5db1, 0x33f8f0f7, 0x5f5a3e62, 0xafc418a2, 0x3457e045, 0x04bca509, 0x3ab9111b, + 0x9b710ba4, 0x4f05055c, 0xcf904f6c, 0x7d722b17, 0xe1b54bff, 0xaad363a7, 0xbdfe5ce1, 0x0618c9dc, 0x944c2a89, + 0x24d28b63, 0xae5571db, 0x6e08355d, 0x32946353, 0x3c7f35ea, 0x08f2b808, 0xb5fa8103, 0xa8881c9d, 0x178578b4, + 0x6479c9bf, 0x53b11318, 0x6a791421, 0x0214cb6c, 0xc5e96d01, 0x53629a2d, 0x7501ecc5, 0x64b46a0b, 0xc4f94280, + 0x67aa4a67, 0x22602d53, 0xe3e51ada, 0xdb7aa1c9, 0xea27750a, 0x0f9bde34, 0x311cc3d3, 0x111db522, 0x9416df43, + 0x022690f2, 0x791c03f2, 0x53bb52af, 0x5f9c9437, 0x24774610, 0xe763b777, 0x769f3ad7, 0x52b4a3db, 0xc9b46af4, + 0xddf13ac3, 0x9d93920f, 0x045a985d, 0xefd81c0d, 0x737dac6f, 0x1240e50f, 0x9accb267, 0x8c767f6c, 0x5456af3d, + 0x065801a5, 0xe68eb9c2, 0xddc93276, 0x5b088cb7, 0x444d7391, 0x7161a7e5, 0x868a85e6, 0xec86da76, 0x06632ebc, + 0x4da42947, 0x6e7be77a, 0xddfbd6fb, 0x5e45b3f9, 0x138b2f3d, 0x10ebc42a, 0x24e6abee, 0xeb2bd141, 0xf3121097, + 0x0e9b979f, 0xf76d9b1b, 0xd2085bca, 0xa8e15c4a, 0x62fd67b5, 0x75436ac0, 0x82a99d64, 0x05e86e03, 0x2faa8b30, + 0x6d0a1a8a, 0xda9a2165, 0xc85f0631, 0xa05c4215, 0x3ec53b17, 0xd1dc3dbe, 0xfc50bc42, 0x6b8c5c8f, 0x0f9af843, + 0xb4134ac2, 0x817aba43, 0xc72bb1c3, 0xe1610230, 0xf7e75f31, 0xa8d52f80, 0x9323b837, 0xc3dbd6f7, 0x6807ba3d, + 0x395b8b53, 0x7b292c37, 0x104483c0, 0xab56a746, 0x14b1c56e, 0x3fe0ea2a, 0x5a382299, 0x921d4597, 0x1f3592fe, + 0xe5899956, 0x36fda939, 0xbd61b25d, 0x233d565e, 0x535965d7, 0x20cb313a, 0x1cbc6d49, 0x8817d63b, 0x17b97f06, + 0x3e5ba6ee, 0x39baa6d0, 0x761964de, 0x052f96b8, 0xab108870, 0x413ef410, 0xb79af2e5, 0x6114297d, 0x058785b3, + 0x51015995, 0x74221026, 0xf8426ce5, 0x26e9b722, 0x31ee291a, 0xfdcd59ec, 0xe637ef54, 0x12500b39, 0xc2533814, + 0x4910e3ef, 0x5a4c54dd, 0x397ed526, 0xe49b9c30, 0xea08d95d, 0xce09cee6, 0xe30cabaa, 0x8478fc8a, 0x939e16df, + 0x966d503b, 0x2fc74ef4, 0x8756bbd8, 0x9c963974, 0x7ac390ff, 0x04dcfb7a, 0x0f9a9aea, 0x64f57714, 0x08246477, + 0x3d77b38c, 0x6608b1a2, 0x3d769919, 0xb6acb5a0, 0x63f89de8, 0xebd18af5, 0xfb1125fc, 0x7469558b, 0xd10fe016, + 0x4508f12b, 0x84f84a2f, 0x5ab98927, 0x5e5db5da, 0x7db84783, 0x2b3f71e1, 0xdfc79b9a, 0x9ef7b4fe, 0x21214d93, + 0xc8f64ce4, 0x3d2e8d0d, 0x0c60d9cc, 0x71ae4177, 0xcd6fa6cf, 0x21f45a24, 0x0e681f99, 0x92be1cd2, 0x99d2baae, + 0xade3bf28, 0x5de777a3, 0x230d70f0, 0x2ef2d898, 0x880342ad, 0x082d1e52, 0x6cb055dc, 0x614a9904, 0xd27a9ba7, + 0x2742f66e, 0x7dd23b71, 0x03bc532d, 0x4447993c, 0x5e38c378, 0x8ef313e9, 0x2f513cd1, 0xa85edabe, 0xd4ddc788, + 0x5260b732, 0x826c9a4d, 0xb8490b72, 0x880ad0f0, 0x34917cd0, 0x2e2159ee, 0x05a7d073, 0x70fdab8a, 0xb439374f, + 0xaa292895, 0x0489bc5f, 0x98f002fc, 0x4915faf8, 0x82460d6d, 0xf2a1419f, 0xcf50cfdf, 0x6dbbb24f, 0x66ffb9bc, + 0x90efab71, 0xf7c98575, 0xa7173686, 0x086387d1, 0x1ed88329, 0xa038721b, 0x33d99805, 0xca84e5c1, 0x84e62637, + 0xea1130e7, 0x13225e2c, 0x1906ac7f, 0x4c7ac20b, 0x872d0cc6, 0x8035f671, 0x336f992c, 0x7ae31e9c, 0x0cf6db7b, + 0x713454f6, 0xc7e2e5f7, 0x3a6ba50c, 0x5e313e68, 0xd7cd1cd4, 0xc9da2490, 0xa9355e47, 0xc3776a23, 0x6f4c155f, + 0xfc0656ae, 0xe5b2784a, 0xc2aeeb67, 0xb829f5c7, 0xd2ccbaa8, 0x79a79014, 0xaf961c6a, 0x05ff01a7, 0xb821f048, + 0xf69a70ea, 0xb01d1624, 0x9a2c45bd, 0x8da74e07, 0x721fe9a5, 0xbaa907f4, 0xc8d23bb3, 0xfea15f86, 0x5b37202e, + 0x3b5f9fc8, 0x486748c6, 0xb7fd99d9, 0xe9365786, 0x684fbb99, 0x3b5e45ee, 0x96f1660e, 0x83edaf2d, 0x70b6a369, + 0xeea39096, 0x06e6cf46, 0x3c06def9, 0x9408453e, 0xed32408e, 0xa42c5077, 0xc5ee6aea, 0xe3f39a94, 0xd971f624, + 0x9457bd23, 0x2d77aafa, 0xd9f03e23, 0x70fc1359, 0xf517b7bb, 0x888f2e94, 0x0144f342, 0x433fe0e6, 0x9e6cfcf8, + 0x51551852, 0x2c6bc76f, 0x9c40e392, 0xc7666241, 0x3d2bad50, 0x7212d597, 0x926627e3, 0xa4de5287, 0xc1c4d4b1, + 0x179d3324, 0x4f442256, 0x1f7c29aa, 0x1486bb48, 0x43cfc9f6, 0x06e515f3, 0xbfd82f1e, 0x88782668, 0xa80fa2d1, + 0xb8cf1b14, 0x7b815731, 0x2c11268d, 0xd1c19ad8, 0xcfa00bf3, 0x6cd7640b, 0x8d0d2d41, 0xf643e519, 0x1c029707, + 0xcd67d49c, 0xa8bb5159, 0x84ba7b1f, 0xcc864e0c, 0x600e4073, 0x8a2c3f4d, 0x51f16a4a, 0xe152d9e5, 0x0bc001c3, + 0xad637e88, 0xeb610611, 0xf88cdd22, 0x674beef0, 0x22578a0d, 0x9eb7a975, 0x2a81e932, 0x422d6d2c, 0xa5bddce7, + 0xce45acc4, 0x6c1932f8, 0x9e411a3d, 0x902e2250, 0xc622d4fc, 0x4fde4c47, 0x2ffdf2af, 0x8e90f358, 0xcba7b3c5, + 0x27365a22, 0x8287d7e8, 0x3b8b4fa4, 0xc68e1835, 0xfe89d336, 0x494f3d0d, 0x1dbfc53f, 0x0bdab7fb, 0x9168de5c, + 0x87606a8d, 0xa7d16e4f, 0x70e8cc06, 0x4cba24b1, 0xcbbfb5d0, 0xd0c12e88, 0x155d4906, 0x379cc795, 0x8f860616, + 0x27c53b8c, 0x78461263, 0x5b9d79f5, 0x14ff9e0b, 0x8c893f95, 0x7194a398, 0xdec392ed, 0xcd42c64c, 0x0431cdbe, + 0x78195157, 0x769a6818, 0xb529849a, 0xdd3ee4b8, 0x7ebac48b, 0xfeb634f9, 0xb5171a42, 0xf6c366af, 0xf36eb2b7, + 0x5eb3b12d, 0x701eff80, 0x5e445191, 0xc94fa8db, 0x7592a650, 0x41bbd967, 0x5ef90fea, 0x002c8801, 0x66f7ad0f, + 0x8773ab1e, 0xb3846de8, 0x714c80ea, 0xffbd9797, 0xb0cdc5cb, 0x258b45f9, 0xf2bcf66f, 0x5c32073e, 0x910315ec, + 0x20dd8bcd, 0x046edbf7, 0xc11968cf, 0xb634bb81, 0x11ab126a, 0x025b9a47, 0x5ca246db, 0xeb527df4, 0x9ccfa9b9, + 0x10c9573f, 0x00070add, 0x51f74003, 0x9ab2f703, 0x690888db, 0x38f1d213, 0xb8863e67, 0x3b4d19a7, 0x2c8e13c5, + 0xc7713c1e, 0x236f421c, 0x606c05e2, 0xbdcd9f6b, 0x8b82e744, 0xc6859176, 0x8834a461, 0x951072f8, 0x13dfd0b3, + 0xb76b414b, 0xcb51feba, 0x5a01cf3e, 0x4dd54198, 0x59098306, 0x30dbb9b2, 0x3220d528, 0xfd686d97, 0xfbf7759d, + 0x3fbb4396, 0x3a94866b, 0xecd596e0, 0x6fb47ebf, 0x2e1ab9e4, 0x87a58e07, 0x4f5fe2f6, 0xe24f5803, 0x3100042a, + 0x3c125c49, 0xfd9a94b0, 0x2c680a76, 0x9e25fe3c, 0xf994c724, 0x255584e4, 0x9e66a141, 0x53b6851b, 0x46053ff5, + 0x150f05a6, 0x76943013, 0xb4a3872a, 0xcd307398, 0x4bfb517a, 0xa52a5979, 0xbac6e7b7, 0xdf40f9da, 0x2e07f8f1, + 0x7f8e0096, 0xf1e433d9, 0xd09c34b1, 0xdc19b71c, 0xf013ac08, 0x403d3650, 0x6c5acf5e, 0x24754108, 0x0c94cb1e, + 0x5a81c585, 0x771a60a4, 0xaf60cc56, 0x8655def6, 0xdd40078d, 0xb54acb07, 0x43e2ecc9, 0x38c28f6a, 0xe32b5752, + 0xfe772dd2, 0xf043d5a7, 0xa6683d4f, 0x85f69140, 0x20462d59, 0xc42c3851, 0x124fa111, 0xce7fc3af, 0xacb416d0, + 0x3b9a8645, 0xe417a020, 0x868ea4b1, 0xf3190763, 0x6dd8822d, 0x33c795b1, 0x9af16df9, 0x81b39871, 0x968b60d2, + 0x65accd7b, 0xa712ec16, 0xa01fba71, 0x186c61fb, 0x2aad48da, 0x3a98025a, 0xd1c871c5, 0xd120c48c, 0x74d9b356, + 0x4cc426f7, 0xfa8a066a, 0xabe244fa, 0x545873d9, 0x745affee, 0x3ab18f51, 0xfd2cee3a, 0x4e132ed6, 0xaf9ab9bc, + 0xde29ac98, 0x7855140e, 0xc1fc0f52, 0xd2a3c77c, 0x4feb77c7, 0x88314f18, 0x1e67f796, 0x4c0fdce3, 0x55bd3e54, + 0x88c9feb5, 0x330ac120, 0x16e5787f, 0xe52ae6e4, 0x8cb31b7d, 0x2f276f26, 0xf5643f5e, 0x9c8a8be0, 0x447735f1, + 0xddd8c3af, 0x51e175b5, 0x722d8a97, 0xb7f761f2, 0xf01c880b, 0x6486ba25, 0xa55c0920, 0x1eb8d704, 0x11eeeac3, + 0x28697dce, 0xe445a543, 0xc14272b3, 0xd816f885, 0x72a65f13, 0xde69d692, 0x13cab040, 0x601204aa, 0x928d3979, + 0x77eaf90f, 0xa33b2ade, 0xf3d9aec1, 0xfca80050, 0xd5f002a0, 0xcf05ac5e, 0x369c410a, 0x653324b6, 0x08d01000, + 0xd649a12b, 0x9e4888c1, 0x5fa7705f, 0x04ae8770, 0x168392ad, 0xc39fb861, 0x0a1fa297, 0x90a45366, 0x1716cd94, + 0x5a51e258, 0xcf9dafc2, 0xa75df3d1, 0x1eff3f76, 0x3f3fb755, 0x517d9700, 0xb13d2e9c, 0xf228c69c, 0xa92e57ac, + 0xd90e38f3, 0xdcee9892, 0x737023db, 0x9d050a6c, 0xc681b99a, 0x4638d5c2, 0x7550c77b, 0xe818faa6, 0x40a27b3d, + 0x68055f1f, 0x3dcba101, 0xc719d00d, 0x3fe76942, 0x93bc3c21, 0x8baee927, 0x79696f77, 0xca9f0775, 0xe68c3bed, + 0xf513bdfe, 0x2016d193, 0xccc21c4a, 0x341b9684, 0x7fdaad20, 0x275c9b75, 0x40e86ebc, 0x2a3a3266, 0x7b6419c3, + 0xfa50f699, 0x6fdd0845, 0x8e339dc1, 0x80f8b089, 0x04323f81, 0x4b8e2a83, 0xcaca920f, 0x8b6e8587, 0x9d7025b1, + 0xfc306bc6, 0xa7aaa1cd, 0xf81d2017, 0x9a13cac0, 0x9c98a334, 0xad40b5aa, 0x305066f3, 0x6d2376ff, 0x683e2e7e, + 0xa070c8e1, 0x706f1b59, 0x24d19a7d, 0x9d5d2bbe, 0xa590919a, 0x8e0e048b, 0x4f0b16ff, 0x1abaf9d8, 0x8588665b, + 0xb63bc84c, 0x73999b9f, 0xbb1070cc, 0x2a1e24d6, 0xa9b1ad8a, 0x8307ef45, 0xcf5c01de, 0x395f6f8d, 0x7f0ecef8, + 0x2826fe60, 0xf7ea8052, 0xd72b34be, 0xc15fbbe7, 0x62fd3555, 0x942cfe5d, 0x2641a577, 0x9ae41dcc, 0x9595b467, + 0x61269174, 0x59bdc10f, 0x90802604, 0xd15e144d, 0xa2d0ef1d, 0xaf8fd87f, 0x0c808369, 0xd95e5384, 0x3359637b, + 0xd0fff4d6, 0x00ceb842, 0x8d5f304a, 0xfd43d9e6, 0x47d83c49, 0xa906456c, 0x02f019ef, 0xb166a167, 0xa15cc36c, + 0x49eb88ee, 0xe7342442, 0xe741de75, 0x7c8c03c2, 0xb2d03f70, 0xb0408d4b, 0x71034fe7, 0xa881fbdf, 0xeaa04574, + 0xad262b59, 0xe01ad157, 0x42c79310, 0xef19b4d8, 0x2574ab57, 0x01f34b4f, 0x58d13259, 0x38192a67, 0xee863dea, + 0xc43a25c7, 0xf6fef533, 0xfcceea88, 0xc1f904a2, 0xdb8de79c, 0x290c88bd, 0x3fde8849, 0x59ecc948, 0x6d0599be, + 0xf57d884f, 0x7fbec07f, 0xe9204771, 0x007b98cc, 0x80a5657b, 0xde2f223d, 0x0b97fdb1, 0xac7077e4, 0x90c1da7b, + 0x26c5a845, 0x2b834f29, 0x8205e831, 0x03d637e6, 0x53f11ccf, 0x9094fb0f, 0x0ed48585, 0x18ec562b, 0x90f4f136, + 0xc77d5a41, 0x81ab5d64, 0xbbcfcd47, 0x7c3ce4a2, 0x95095e59, 0x3235f744, 0x50dc62fb, 0x5492e284, 0x751f20e3, + 0x250b4894, 0xf81fb1b3, 0xb4a950a2, 0x33268a15, 0x4b422625, 0xd1e66a05, 0x1cf989f5, 0xd8ac48e4, 0xb69da896, + 0x1fe6a948, 0x55bec301, 0x22ca630b, 0xa04c77d4, 0x62bdf44e, 0x23fc4d2d, 0x50212981, 0x09941485, 0x9ff1d204, + 0x3c47aee1, 0x172b866c, 0x8ab30d77, 0x00e5e9d5, 0x219dec04, 0xe84afb32, 0x5463161d, 0x42af6d37, 0x55ce23ab, + 0xff07d04e, 0x94ca2337, 0xb0a88ef6, 0x9383ec8f, 0x3e53fd5e, 0xd8008950, 0xc18ecece, 0x1107c6aa, 0xe2ef54af, + 0x3024d1d0, 0x9b11a702, 0xf26b53d8, 0xa077da34, 0xdcdf69fc, 0x47043dec, 0x0370ffa2, 0x3b2741bb, 0x9edad3f3, + 0xe36752bf, 0xec9e3513, 0x95ec6d50, 0x08bc440c, 0x7d5d3c53, 0x71993831, 0xfb79daff, 0xe6614c5c, 0xb23520d1, + 0x75a11f32, 0x1e741d64, 0x81c2ce37, 0x7e33e06a, 0x8dee02db, 0x15196840, 0x07878abe, 0x71567aac, 0x54d24686, + 0xcae731d5, 0xcc9c4af9, 0xe5e002d7, 0x7fc172e0, 0x294db86e, 0x4bb672fd, 0x2a5f4d36, 0x4d2a2783, 0x20a9ad62, + 0xd64f4d23, 0xb5c7a920, 0x7970e073, 0x9a03271b, 0x20faec67, 0x79e56854, 0x858f12c8, 0x4f3d44ab, 0x4677f563, + 0x62330413, 0x65b942cb, 0x7fd3de08, 0x06bbe941, 0xa86f2dd0, 0x44a0b22a, 0x5f562d91, 0x128da02b, 0xa90190ab, + 0x830328e3, 0x1dfa6478, 0xd351330a, 0xde6a7fbc, 0x1954c648, 0x704739e6, 0xd77d072e, 0x39813b30, 0xa706f353, + 0xc7f9bbc0, 0x9557bf33, 0xf9e7fca3, 0xb3cb3d45, 0x8f247a7a, 0xf306c060, 0x36286d64, 0x6fdb33fc, 0xa7fb1457, + 0x0aa03a5c, 0xdc82228f, 0x881c599a, 0x5753d991, 0xbf846554, 0x7fb1fa7a, 0x2c3d215a, 0x76343b5f, 0xbd27b271, + 0x94b10045, 0x9c92b00a, 0xdb6dea26, 0x0e90bc9b, 0xaeaffb14, 0xdb3de624, 0xc9224dec, 0xd2e7676b, 0xbfffa7d0, + 0xda2aeeea, 0xa0b2834a, 0x1e78622e, 0x0acca5a3, 0x6afb7e2a, 0x3efe4381, 0x135cfdd4, 0x560d1d7a, 0xe75435da, + 0xf62c1485, 0xf9ac3b04, 0x190f5864, 0x36dbb3f5, 0xec771e01, 0x0a84a584, 0xcf8923d8, 0x27c4cfd0, 0x97296476, + 0x829e57e1, 0xdb01600b, 0xf607f714, 0xebf896d9, 0xd0d32ca6, 0xa8c41e41, 0x5b5f0d56, 0xf31a2e21, 0x3c124dff, + 0x2b579a72, 0x529e8bce, 0xb908ee52, 0x53f3c66b, 0x0d7ee858, 0x268907fb, 0x04006dcf, 0x55ff4026, 0xcdf55270, + 0x942bcffe, 0x34be631a, 0x6ba21b90, 0x9eff9d35, 0xafeee791, 0x2eb34737, 0xd9d63806, 0xf9802166, 0xc62a30a5, + 0x1aa5ebae, 0xb5bd6c15, 0x96cabb95, 0x8055bd61, 0x941c6c1a, 0xd60964a6, 0x7c408616, 0xea790f85, 0xd8df3857, + 0x2641a37b, 0x9b886216, 0xb9c412d2, 0xb83c9779, 0x72f9659c, 0x6cb056d5, 0x4ffbe1f9, 0xf220d30e, 0x5c4b5d2d, + 0xee77ca6d, 0x751b85df, 0x4fc3096a, 0x63533203, 0xf3f93133, 0xc8e29d2f, 0xd473ca18, 0xd82758fd, 0x2d3286a7, + 0xf45f5c0e, 0x1a03f754, 0x9c70956e, 0xaf99c05b, 0xfe80ae20, 0xc141a2b2, 0xf827ae24, 0xa9eca63d, 0x8ef9187f, + 0x2e35e3fc, 0xa7e44631, 0x556e2bd8, 0x4e26e459, 0xe3c47825, 0x5b65f650, 0xa546db4f, 0x0056a536, 0x306092d6, + 0xf0b15715, 0x97f5e24c, 0x667205f8, 0x8b7e4b32, 0x4668e89b, 0x9bc1eabc, 0xb851209e, 0x54fff735, 0x51a788f0, + 0xc42b35ce, 0xec28e69a, 0x4faf008d, 0x82193dc5, 0xa4eafc05, 0xb5ee46e4, 0xbde37027, 0x682f6a0d, 0xdbac21e5, + 0x8c6a4671, 0xb299410b, 0xa09d3033, 0x4c948029, 0xbc47f728, 0x91c03c63, 0xd523d025, 0x00a0bc99, 0xea6e6999, + 0x112707c8, 0xddeb4757, 0xc9819394, 0x17a4188e, 0x2cf0f735, 0x55540ca9, 0x7de8ccc3, 0x0cf02426, 0x301ccc6c, + 0xd0badce7, 0x3be79117, 0x237001de, 0x53996ab4, 0x0515a9d6, 0xbce08138, 0x4b7a4cc2, 0xfb359399, 0x9364863d, + 0x42208ea1, 0x029ca2a3, 0x06f131fa, 0xf708633a, 0x3a6605e2, 0x2c0d41d1, 0xe9f5096d, 0x7fba864e, 0x4f2a8668, + 0x93e634a7, 0xd722a05d, 0x3d3781ab, 0x567b5697, 0x987eec66, 0x78a2b017, 0x873a4ab2, 0xffe813ad, 0xf6ffccce, + 0xab8f0d9e, 0x30f834da, 0x360363f1, 0xec256234, 0x2cb807aa, 0x60cc2507, 0xfa12486a, 0xf2505e99, 0x4826a40d, + 0x8cf16766, 0x9413dc41, 0x58ae8ce6, 0xdf2f5a32, 0x14e043de, 0x4873238a, 0x5619095c, 0x8ef0bb66, 0xfa0c7754, + 0xa1c94122, 0x11ed54c2, 0x15617b27, 0xac9f5b63, 0x7faee166, 0xfcbe62fe, 0xb72fe053, 0x8a05c2ea, 0xbb319c74, + 0x0926b21d, 0xc1d69def, 0x05022163, 0x4c14aaf8, 0x2f5a0cac, 0x2f56abeb, 0x6d18f118, 0x433d31b9, 0x782e2243, + 0x948486ae, 0xddd124f4, 0x06e3aff9, 0x2f28264b, 0xd2b6ac0e, 0xd8cdad23, 0xb0f28c21, 0xb4b67d53, 0x83dd7133, + 0x4ff0d375, 0x28edcbbc, 0x499f7208, 0xb06240cd, 0x763c2570, 0x35a0e490, 0x351daa77, 0xd5d312ae, 0xbc0460f6, + 0xf67081fa, 0x45f766e3, 0x5ca28436, 0xa6118354, 0x7358f8a6, 0x60729e0c, 0xe9590a2c, 0x6b948775, 0x1d8335cd, + 0x08cdbcb1, 0xe1467a4b, 0x06b11c84, 0x6de44f69, 0x3e92ac97, 0xfc1e3e76, 0x1c103861, 0x8eb3a952, 0x507acab5, + 0x6a025347, 0x32351708, 0xd2da5554, 0xeabe5a67, 0x5a05b1b0, 0x55dab226, 0x02bb5b81, 0x48bb70a4, 0x6ff0f2ac, + 0x545091fc, 0xd37543b6, 0xcc49d733, 0xe920638e, 0xf428eb29, 0x6b426349, 0x44aaf97a, 0xe0261e01, 0x42fe7b9b, + 0xb1305b7a, 0x3e043ccb, 0x19872fb3, 0xae985b01, 0x1e0a1319, 0x71284a1c, 0xb2fb3d9b, 0x7fd0c028, 0x891cc3b8, + 0xbc57a794, 0x98a5e1df, 0xd7dcf00e, 0x993ce1cc, 0xfac7b91e, 0x76686e3d, 0xc8b12b1b, 0x65f1b1e7, 0x1e40a7ed, + 0xb631794f, 0x1c4b6a0d, 0xb1ba3064, 0x0167c0ce, 0x3e68446f, 0xac72b14c, 0x8ef51d03, 0x7feef652, 0xbfc851e8, + 0x1eb6f98f, 0xd7592b6c, 0x7103edbc, 0x9437495e, 0xf5d0c7a5, 0x28c92ff3, 0x0502b0b6, 0x22848b2d, 0xd7bf0107, + 0x49a80a70, 0x914e5765, 0xbeb5ced5, 0x03b07548, 0x07f29908, 0x4222e3bc, 0xf6893054, 0x10b0ce2e, 0x216b24f2, + 0xa175a21f, 0x8615ab88, 0x28e2f58c, 0xabfb6d49, 0xc67a55a0, 0x4e41402a, 0x89b355a6, 0x6924e92d, 0x066149d3, + 0x80583073, 0xb9d8b1e5, 0x4f2c68b9, 0xbffc560a, 0x847a4781, 0xbe0aa613, 0x14866551, 0xe83d6796, 0x78c5a8c4, + 0x03f9cf08, 0x79972f5d, 0xcb7ae4d7, 0x77707191, 0x2bb82544, 0x118cbbd1, 0xcbfc1586, 0xf783cc29, 0xf8b5175f, + 0xa3fea5bb, 0xe46619d3, 0xdf135817, 0x144263d0, 0x3b264f2f, 0xa0a188db, 0x8d1eb020, 0x83a40b68, 0xd268e82d, + 0xfb6f2848, 0x8eb99d85, 0xa67f0106, 0x1a7de2c2, 0x0877c83c, 0x534783b4, 0x37b7c8f3, 0xf6b53e59, 0x3d47b3bf, + 0x8b0d19b6, 0x555e54f4, 0x2a213502, 0x11e654d6, 0x20f11709, 0x2ac7d42f, 0x5fcc2ead, 0x89bed161, 0xcb1f1457, + 0xe190ab2a, 0x36cef901, 0x298f43ea, 0xde1009f5, 0x691efd20, 0x5e51a05b, 0xe2ff486d, 0x29ca9f86, 0x745c83dc, + 0x142ed742, 0x03a9dfa5, 0x0620c092, 0xc5711f59, 0xf244c8b5, 0x0db08ab3, 0xc1ec5858, 0x03dc5206, 0x57640151, + 0x207db350, 0x44ffc26b, 0xacda8c47, 0x9a28f857, 0xb383efad, 0x43387b29, 0xc7bdfe8b, 0x79cd12c8, 0x78c4bbd5, + 0x907c2b90, 0x88559ee5, 0x19c0da50, 0x2721a741, 0x6e240ec1, 0x192f3802, 0x9daf78ff, 0xf646cd2f, 0x50b90fd3, + 0x4c5fb6b2, 0x9e497d3e, 0xfcfea708, 0x3a57fe83, 0x83333a66, 0x90c2ef6a, 0x8d89bfc2, 0x27f4bf73, 0xaf02632e, + 0xa2174514, 0x995d1949, 0xd35e8e5c, 0x4bd6eee2, 0x4ef9bf0d, 0xae0b9171, 0x57ef8b7d, 0xd279025a, 0x4d472954, + 0xc5797345, 0xf1b37666, 0x03018eba, 0x1adfa6a0, 0x24bc6704, 0x40ac02ef, 0xad20e433, 0xd6ff9d74, 0x3c629c6c, + 0x1de58c8b, 0x0ac37e7c, 0xef600203, 0x10c13718, 0x599e9da0, 0xffae3b3c, 0x5e381229, 0x80a660b4, 0x6299f040, + 0xb7e50e60, 0xe425a214, 0x05169257, 0xfca2b1b7, 0x77d7fec9, 0x54c94681, 0x0ab49196, 0xa591b54b, 0x94893517, + 0x8d0b1438, 0xa22ce4a5, 0xc5437e13, 0x37e7f50d, 0x4eeb3853, 0xa1da6dd1, 0xadab3691, 0x5c133621, 0x04f7bf92, + 0xeab8993e, 0xf610ec61, 0xbaefe1b8, 0x2194f8c6, 0x4949ea2f, 0x107ac3fd, 0xecd07c58, 0x5b9ec04d, 0xf54e668f, + 0x1a7fb5f4, 0xc5b9a402, 0xa27c8c20, 0x2acaca4a, 0x9d817fec, 0x2acd679f, 0x993541f5, 0xeb5ac033, 0x0c433e9a, + 0xf02e036a, 0xc36fda28, 0x4ec3eec7, 0x7f7490b4, 0xb005b54b, 0x80369071, 0x94f8c9fe, 0x43dcd044, 0x9e0c8832, + 0x277f62e1, 0xcdecbde0, 0x53b436a7, 0x4a1fe3ed, 0x3c76ea47, 0xaa1057e2, 0x86ed150e, 0xa3434fe9, 0x2a44698b, + 0x88ddf3c0, 0x2e19bbf7, 0x7569635c, 0xa1f7e78a, 0xe8adc903, 0xfbc41dc2, 0xdd6c07d8, 0xe2213794, 0x7b5b2aef, + 0x41718c06, 0xff8ee10d, 0x24ccf6a8, 0xcae83a61, 0xbad1bb84, 0x0ad4e8b2, 0xe92560ca, 0x34b972a3, 0x93efd346, + 0x61f1d4e6, 0xe692863f, 0x767de898, 0xfb06d3a5, 0x57e27733, 0x11b1aa2b, 0xc13c41fe, 0xd54517a8, 0xb6d266b7, + 0x54748074, 0xf1607840, 0x6bb741de, 0x517534c2, 0xb6a0ab4f, 0x72ab010f, 0x9ad064f5, 0x874d5dd1, 0xaede7654, + 0xa398c41f, 0x1e684cf8, 0x5830c2ca, 0x3ef52eaa, 0x72f6a062, 0xa380bec6, 0x91357b96, 0xcc8dec3d, 0xfb7d6c9a, + 0x6d81d4a9, 0xdffd4738, 0x275cddaa, 0x089563c8, 0xde8cfbe5, 0xe03147c3, 0x4c1988e1, 0xee8cba74, 0x806332c0, + 0x4a29d675, 0x920e5da8, 0x4fcb35c2, 0x2c04233f, 0x3c931917, 0xff3f4992, 0x346b2c51, 0xf8b2e5fa, 0xfb0746f9, + 0x17d7e41a, 0x3972bd1f, 0x63aaa4a7, 0xaecfb388, 0x2ed8baf8, 0x13205b1d, 0x45a6bed2, 0x84432c24, 0xa491da37, + 0xea3a1174, 0xbd0bc3a4, 0x294b8b17, 0xf8b1ca87, 0xb69f8f77, 0x6c596259, 0x742e3fcf, 0xb7b10305, 0xb4006399, + 0x0b31b272, 0xc85cd998, 0x003ff102, 0x49d39854, 0x6c8f44c4, 0x47d91040, 0xe8752f09, 0xafda88ba, 0x45ed2d51, + 0xcbe61505, 0xb56a5f0c, 0xa26e43da, 0x40d3ec16, 0x815f03f2, 0x0f600c48, 0xb6d35916, 0x4e3361d5, 0xcc90be49, + 0x207dbe71, 0x1560ba7e, 0x7b4908bd, 0x09d26d50, 0xaa44984b, 0x709b5a31, 0x2739d69e, 0x84ba1f16, 0xfec45c7f, + 0x4ef44127, 0x9e934303, 0xc544add9, 0x920086fd, 0x2934b002, 0x54fe4b2e, 0x8b6e9d86, 0x545857b9, 0x1e0a1050, + 0x17251c79, 0x58197ba4, 0x3d6ef2d2, 0xac79b97a, 0xf3615d77, 0xc4a1323e, 0x80ac6527, 0xf45fe364, 0x82570b36, + 0x8cce6b13, 0x31bb1afb, 0x26508ea0, 0x9bdef8db, 0xaa5709ae, 0x9780855b, 0x030d1eeb, 0x76ec4e89, 0xba1cc2bf, + 0x2ea77346, 0x7d23f1e5, 0xbf72facb, 0x9f7baad9, 0x54b553f0, 0xdb1e6a2e, 0x6a77434d, 0x52c54585, 0xb3c678a4, + 0xbe9213a0, 0xd3d595d7, 0x01195417, 0xb75d0f7b, 0x4e05ee6e, 0xad7b925e, 0x13243c49, 0x0e220b01, 0xb670e874, + 0x90fa069d, 0x700656c9, 0xc6119f63, 0x6b8fbc3d, 0x17fc61db, 0x15818ab2, 0x5e765080, 0xbd462d6d, 0x3c4446ba, + 0xff4347de, 0xf67cae99, 0xd04c1b78, 0x1fe030fb, 0xc2a48c81, 0x52a35b17, 0x8b053456, 0xa335ee9b, 0xd4fd1e36, + 0xb9818bdd, 0x0ff94e7b, 0x9297934c, 0x58145157, 0x02852ee0, 0x8ef629d8, 0xc4eee9f1, 0x36174e35, 0xbb77cfa7, + 0x5b011838, 0x8dd437ad, 0x7273ea0f, 0xcedd8064, 0x97e81b44, 0x9e1ca96e, 0xe2035fbf, 0xb4d2742f, 0x6f196dc1, + 0xd7a058fb, 0x6f20c07b, 0x8d77123c, 0x96eeb1ec, 0x8e6c8c75, 0x0dff2610, 0x6f7ff501, 0x040ba64e, 0x48d2b475, + 0x441f45cc, 0xc693fb0f, 0xa131ef8c, 0x2ec207bb, 0x9cf524b8, 0xccdab7c1, 0xa8e4f0ef, 0x8df5b8d2, 0x0b5bd73b, + 0xff10a560, 0xd59e6cb0, 0x373418ad, 0xbc40b406, 0x9caf065d, 0x23e1dc34, 0xcee53de3, 0xf2888255, 0x1cb964b9, + 0x716d8ffd, 0xdf21371a, 0x5aa73228, 0xac6c51b3, 0x3df71ea0, 0xf3519228, 0x3050b875, 0xf16bac23, 0x7da79b87, + 0xa2c8ad4b, 0x53d0f314, 0x9617aedf, 0xebd83d83, 0x57141a76, 0x10fc3010, 0xc6390d63, 0x5ab513a6, 0x45c79e7a, + 0x5ff22dbf, 0xed2c07b1, 0x5490c9cb, 0x76e9c238, 0x4c8758e3, 0x115cdc39, 0x12298276, 0x493f903f, 0xd37da203, + 0x52f89af2, 0x5bde9031, 0x06a8fef6, 0x0b899557, 0xe30d20dc, 0xf06bd674, 0x1a205aa2, 0x1aa356be, 0xfd34c03d, + 0xa8b0035b, 0x27bfa309, 0xbdc8ddfd, 0x637e34b5, 0x046f3d8c, 0xa1ba0dab, 0xc1b2453e, 0x3d05d3f4, 0x9883abe1, + 0xd49e8e01, 0xb4fbc47c, 0xec268f36, 0x46a85472, 0xe3a56e0f, 0xc7ff5482, 0x91c81aa3, 0x94c29e8b, 0x4e50dcf2, + 0x325a11ff, 0x00717f17, 0x9ccf52c0, 0x63ecb1ad, 0xca77c6a3, 0x5cd66758, 0xc51caf2a, 0x6f255716, 0x068461cd, + 0x73dbd9a8, 0x83333b1f, 0xa776a3b2, 0x87e8ee30, 0xa50b5488, 0x3a244a61, 0xdfc7f8d1, 0x2177abd4, 0xbc10821a, + 0x944023f0, 0xa1422473, 0x80b05c8b, 0x01a15af4, 0x7512a55c, 0x17a3d639, 0xd7b621d8, 0xf81d6d47, 0x8f14797d, + 0xcb24df61, 0x5e2f6e6a, 0xd4d5e661, 0x174093e6, 0x2420279e, 0xd406789b, 0xb186203e, 0xdf6b8041, 0x29b0a5a0, + 0x28ece7c0, 0xec15dc03, 0x0d450e11, 0xd1a6e261, 0xc99cd7be, 0x2e92e087, 0x5d373b4c, 0xea58b052, 0xa5454eab, + 0x71c43d97, 0xc6344a55, 0x8c0f0d8c, 0xeb65b42b, 0xd5594149, 0x4063a99c, 0xac2b216c, 0x93d8aab1, 0xf95851e5, + 0x501fed8a, 0x229d1d1d, 0x72038b8f, 0xcb99cdee, 0xed4a174f, 0x1a191d4a, 0x0bc81f10, 0x7f39e0f7, 0x1bf42adb, + 0x50154766, 0xff244a7d, 0x476a9236, 0x9ec3c003, 0xb9c6141a, 0x8f9e5665, 0x95a11fba, 0x0cf17da3, 0x09a6c1b5, + 0x23ad379b, 0xc1c90099, 0x6d07ccf2, 0xe5484353, 0xd9970171, 0x56c30977, 0x43dea4a6, 0x5dc9887b, 0xbcc8864b, + 0x9202d35d, 0xdc2ea2c3, 0x17a2e378, 0xa0148bbb, 0x94564877, 0x918d5606, 0x05dd7250, 0x4b7f4912, 0xfd99b05a, + 0x6113e54b, 0xee8b798d, 0x50c86c93, 0xc4f764b5, 0xe29d0747, 0x7a41dc29, 0x19511dfc, 0x372a5ba9, 0x2d6e4f5a, + 0xf719bce3, 0xc4859a1f, 0x086f2267, 0xb94daaf0, 0xc59354aa, 0xc49f1d15, 0xc26883da, 0x107f58a7, 0xd95f4b6e, + 0x1995c570, 0xecdff4ef, 0x83e2381b, 0x77a18a89, 0xca126399, 0x646daab3, 0xe29c2181, 0x5fb039b7, 0x955e8d05, + 0xfa0cb9a1, 0x4b854c56, 0xa5969293, 0x95f5df28, 0xc6773caa, 0xea450b73, 0xf1948e86, 0xd419ad7c, 0xf2778d88, + 0x8f15b00c, 0x122e0494, 0xef82baec, 0xa90b237c, 0xaeffd632, 0xd78bb78b, 0x5322718c, 0x1672373b, 0x2f7a0b35, + 0xd156f0b6, 0xcfab75ac, 0x3767306a, 0x6cf320be, 0xcd20788a, 0x29c06863, 0xcab9fd7d, 0x551fb576, 0x1cc57b93, + 0xaae23928, 0x917f5e48, 0x6a559e6d, 0x11f5b2f1, 0x0ab38fc6, 0xea863167, 0xfda5a89f, 0x9ce3d2db, 0x458d380f, + 0x239b4c49, 0x22817945, 0xb1c33b1c, 0x594a19b9, 0xd40b2f81, 0x6f7e0a6a, 0x95f16fac, 0x960ffd80, 0xa6379a8a, + 0xd23ca028, 0xe3d754f4, 0x74419a66, 0x2166f8ac, 0x838586f4, 0x225edfc0, 0x13addd6b, 0x8509e81a, 0x594c0573, + 0x2fd959fe, 0x9dc4f662, 0x23945f74, 0xe1dcdc15, 0xb212d4fc, 0x1f422e20, 0x9e34a355, 0xc4e40396, 0x2fcf0612, + 0x1eddbf7c, 0x6e04ca51, 0x9947273d, 0xe47daceb, 0x7fc6933d, 0xed76cf27, 0x77bad597, 0xc5276363, 0x060b00d7, + 0x1e843387, 0xd024ca46, 0x8477b619, 0xd19ee1d2, 0xa6cf3e31, 0x0661654f, 0x70333917, 0x15b10fc8, 0x9801b224, + 0x99eafcab, 0xb8793b1c, 0xcd1069ae, 0x177aeb6b, 0xe582ad0b, 0xe5255439, 0x29768e1b, 0x86feb4dc, 0x6347fdbc, + 0x0537106c, 0x02a8d94a, 0x018db3f8, 0x5bb14771, 0x7ab5d6eb, 0x06781dcc, 0xc075c1e1, 0x1601a5ef, 0x3937aaac, + 0xa943dafb, 0x731a6d01, 0x7b803919, 0x74f038e6, 0xcd80ebed, 0xcb29d2a1, 0xdb1c4ac9, 0x2cd9d64d, 0x0529d7fc, + 0x1ba1b32f, 0x4bd0b823, 0x334ca540, 0x28faf09a, 0xfb7e5961, 0x83733e53, 0xf5623f5d, 0x9db4c304, 0xfe02b133, + 0x35898be6, 0xc7808b75, 0xb47697e5, 0x73cca6c1, 0xd1a22348, 0xe7815f27, 0x107383e0, 0xd4e9dd63, 0x0724eaa0, + 0x1ce61735, 0xfb974261, 0xe425f029, 0x2d59d70a, 0xf99b105c, 0xba82cafa, 0x979d0b07, 0x02a2dd44, 0x3b39c882, + 0x8e615872, 0x2ddb6b81, 0x636cc84f, 0xb8525992, 0x9661bbbd, 0x9769c010, 0x7d1eb6a7, 0x41781e13, 0xfca2d512, + 0xf39b172c, 0x94cc78a1, 0x8f16d003, 0x64c81da2, 0xfb46f2c1, 0x40187dd6, 0x1b1f37c2, 0xcd92a254, 0x8dc1ac6a, + 0x64247973, 0xbc7915d9, 0x7cf8567d, 0xbc6301fc, 0x28af3a49, 0x4e0cea6f, 0x828990c1, 0x5abcb814, 0x2b4fd01a, + 0xc54ca917, 0xcb3a6ba5, 0x37070d7f, 0x5eae3936, 0x7fb7a6f4, 0x6de2744e, 0x5c5b25f8, 0xdfe0a142, 0xcf7acf81, + 0xaf5b0f56, 0x9930206a, 0xc3d2aed3, 0x8218d44f, 0xd0306ce5, 0x5d48834b, 0xf07aedb7, 0xcf59f989, 0xecb07e11, + 0x31af896b, 0x41ee2c78, 0x56206728, 0xf35870fa, 0x3200b79a, 0x925dbe78, 0xba72e366, 0xdc74e53b, 0xa913653f, + 0xe3ca4482, 0xc976a6a0, 0x5db5b192, 0xc3ce00de, 0x64cd09fc, 0xb692c259, 0x3cb9b834, 0x1eba6dd2, 0x72ee1567, + 0x3fd4b794, 0x0fd4049b, 0xa315a0b2, 0xb004326b, 0x9ee37d64, 0x6b356ec5, 0x472037db, 0x732493a8, 0x04cc1d6f, + 0x826262fb, 0xe1cd3f51, 0x9507de97, 0x755e9d72, 0xaac510be, 0x2a8f5ee2, 0x69a60d1c, 0x2f49cb36, 0xc6a3294d, + 0xab311ae5, 0xc4475764, 0x68274e3d, 0x0c3a4b50, 0xce88a142, 0x6b186885, 0x945b5009, 0x96accf77, 0xc2196f6f, + 0x3a153815, 0x554c1274, 0x9f7923d6, 0xc6527297, 0xee2a10c3, 0x943f9b95, 0x60fdc4bf, 0x7db53110, 0xafb3d6bd, + 0xf650b4dc, 0xc650f25f, 0x16909674, 0x11074ecf, 0x0b970acd, 0xa6f8e46c, 0xdfee77c8, 0xd9607d91, 0x8293d65b, + 0x5616295d, 0x33d07509, 0xa1651505, 0xc455fb6e, 0xaad74839, 0x68b0e718, 0x7c3d1133, 0x40ea6af1, 0x8d917e8d, + 0x60c2c7e4, 0xc5d78c5d, 0x78e85551, 0x5fde13f5, 0xc6a8bebb, 0x52a42eb1, 0x0fb19f9a, 0x24b42cb8, 0x02a201d6, + 0x149fa87c, 0xff8f8c4f, 0x52b98200, 0x6484cb5f, 0xf1506d7c, 0xa9881566, 0x7cae43fd, 0xe764e023, 0xfdb3cb8f, + 0x60e9b285, 0x9b2cf3b3, 0xf1dac5be, 0xb69a5b4b, 0xee17b7d6, 0xba856f0a, 0x57ba495d, 0x9bb83cd4, 0x021cc2af, + 0x41498153, 0xda8efb9c, 0x4a09c178, 0x751de2c9, 0x41ccf33c, 0xa47b52ca, 0xe4d9d374, 0x23bce2e8, 0x0a210267, + 0x94953dba, 0xe08aa49f, 0x5c5845ea, 0x6ed83525, 0x4b690ae2, 0xa0986abd, 0xde764d64, 0xabcf3381, 0x77229065, + 0xcb9d776e, 0x8fa1996f, 0xb6cd26c0, 0x8941ff0c, 0x6d68ee6e, 0xb054365e, 0x32998831, 0x4a2ea875, 0xd1e2ff23, + 0x284d5884, 0x60a08b5e, 0xe5f92744, 0x1fd7c0f8, 0x6eb6bcf9, 0x3bfcf828, 0xae2492ee, 0xea10553f, 0x9f3db204, + 0x73531112, 0x1f1677a4, 0x8eee0175, 0x9a05d530, 0xa097c909, 0x2a496778, 0xa064c742, 0xd0f10eb4, 0x70187591, + 0xd6210495, 0xe397228c, 0xeaf57dec, 0x612b3f6f, 0x5d6f5c12, 0x79714881, 0xaecb7161, 0xf8a9fcec, 0xfacd43bd, + 0x4531c766, 0xe9b66259, 0x8f5dba6c, 0xc14ca30f, 0xa8cbf434, 0x1627b5a3, 0xa9ac13e6, 0xcf3f8925, 0x1cef3b18, + 0xad92fcf7, 0x87ec7f1f, 0x2529cca9, 0x511496fb, 0x4e69c291, 0x684d53c2, 0x47f85764, 0x229ac122, 0x4d0d34d9, + 0x9ea14812, 0x167ba8a9, 0xd07dc0d3, 0x0f67fa24, 0x4cddda19, 0xd9256071, 0x90c7d608, 0xc46a636b, 0x61efe63b, + 0xb8e1f5f5, 0x124ae42b, 0x9d43b09f, 0x5049c863, 0xad0dd93a, 0x16ddfb2b, 0x1062531d, 0xdd4254f8, 0x36465832, + 0x6593a720, 0xa702fd2f, 0x5cfab99b, 0xb01e776a, 0x5a351edc, 0x3402ed41, 0xb8efe06d, 0x61b64b2f, 0xbbe0f602, + 0x03f54f7b, 0x3a4cb6f9, 0x0eadc5b7, 0x2a3c2f55, 0x339e574a, 0xdfdab8db, 0x1107a0e0, 0x38030533, 0xbcea68bf, + 0x13a01176, 0x02d4e1e6, 0xe0a30d86, 0xd16022d8, 0x1067f268, 0xeca8ab24, 0x7cf9571c, 0xd2c9fb34, 0xb3d1a823, + 0x9d4b7bc6, 0xfa43f48e, 0xd8096329, 0x8ada0f5b, 0x2e55cb45, 0x071935a4, 0xf4ae9337, 0x19252cb0, 0x24adb475, + 0x7441b0a0, 0x0ebed6a3, 0xa6685392, 0xb9c20ad9, 0x948a935a, 0xd431f074, 0x46ecbfef, 0x4431c2bc, 0x13e607ef, + 0x87524749, 0xd14d2912, 0xcfbaf74d, 0xf4ff4f33, 0x0eb37941, 0x73b1828e, 0xb0c94f18, 0x525a3e0b, 0x6bd8e75a, + 0xdc31fab8, 0x1e671606, 0xb6eee79f, 0x7d1a3465, 0xa741bce5, 0x7dffd9fd, 0x6c45b343, 0xb3a1e7de, 0x387e0d0b, + 0xf1de377f, 0x73d6059f, 0xb541b37f, 0x1cf87a90, 0x679f5ac7, 0xd6b8a279, 0xc09e8ca1, 0xb681647e, 0x14a98bcb, + 0x02134e28, 0x1c04166b, 0xf8054626, 0x30f7eb7c, 0x6df429e0, 0xbd99c8f5, 0x15e6ca7f, 0x1a1eb246, 0x6aea4506, + 0xb65d54e7, 0x5b71779a, 0x1cbd80d8, 0x3139987c, 0xaec46089, 0xac693479, 0x76e62d4e, 0x81cd9f57, 0xc4bc8ce9, + 0x17d4cfcb, 0x90de842d, 0xbb8aeb6d, 0x1887ccc8, 0xd61f7577, 0x6155f8a9, 0xf4e6af89, 0x6036aeec, 0x65c16a4b, + 0xdd4b76bd, 0xe6d20ff0, 0xc2ee87dd, 0xde1fc288, 0xe2660ca2, 0xf83f2d8d, 0xfad2364f, 0xa6ffcde2, 0x651dbf23, + 0x2098e38f, 0x48e6a8cc, 0x4a258434, 0x9fab3d03, 0x7ffd77cd, 0xf128a649, 0xeb5c270c, 0xb0a88493, 0xe3c9468e, + 0xd07a752d, 0x42d9fcac, 0x9bf80da2, 0x1c91937f, 0xa191c232, 0xb33fc1d4, 0x6ba579ec, 0x03451e53, 0x10513b73, + 0x74055e9a, 0xdfa9a450, 0x98d94f67, 0x64840166, 0x94ac7f62, 0xbe76b6d6, 0x7bd94ec0, 0xccb40a32, 0x1a6d8d5d, + 0xcea948cc, 0xfe65aece, 0xbee5ef65, 0xeb26e79c, 0x9e2c2818, 0x5f4ef0cf, 0xf7632571, 0xafa29e77, 0x34a7baa8, + 0x5d2a2a7a, 0xffea730d, 0xf6b91b2a, 0x98858f4c, 0x5d55bd1b, 0x64f553b9, 0xe2abd776, 0x090f6356, 0x34c8e508, + 0x04e084f8, 0x9c9156ed, 0x0f1d232e, 0x86c083d6, 0x76583e79, 0x4305bd29, 0xf60c99f3, 0x5024fe14, 0xc7e2dcf4, + 0xdc939454, 0xa2e597ee, 0xf1b9608b, 0xc71ba5f7, 0xee6918e6, 0x84f972f9, 0xd7c45f36, 0x5e6e6912, 0x6d9a38dd, + 0xb0b3a147, 0x6bcf09af, 0xeae4c6d7, 0xa646c22b, 0x63eb7558, 0xc628bc4c, 0x438bc853, 0xcfc575a6, 0x54309d3d, + 0x8978bb01, 0x4d2815a6, 0x5f779b34, 0xbef7b8f3, 0xfb24f9bd, 0x8b35639a, 0xda691c13, 0x13dc2ffd, 0x2b5afccd, + 0x3d8b5ae3, 0x28c7b32b, 0x80b95837, 0xb8fd4199, 0xea0604c9, 0xd21c1832, 0xab094455, 0x9c4a675a, 0x20e76fde, + 0x893a86ed, 0x738863e9, 0xf3fe9ee1, 0xcd69a966, 0x93b6b52d, 0xd819e7ed, 0x3681c4e0, 0xf70a4751, 0x82592853, + 0x7342798d, 0x4c1862e1, 0xb58e9def, 0xdea7ef05, 0x22b85715, 0x694fce78, 0xdcf07a86, 0x659d34e6, 0xf752e797, + 0xa9737d00, 0x3f8eaccb, 0xc8ba759b, 0x2729ac9a, 0xbf400212, 0x812e8b96, 0x6bb77f37, 0xbc91c828, 0xb6a66cbd, + 0xba036824, 0xd56e9992, 0xd5dfc249, 0xd28fdf39, 0x420f1749, 0xcf93bf21, 0xf0167f8c, 0xfdf206f1, 0xce67b546, + 0x50224168, 0xb60e6d29, 0xdfa8ca81, 0x1dbd1238, 0x1524d416, 0x421e8775, 0x9aa6b1bb, 0xd9236fdc, 0x8955765e, + 0xba5c468f, 0x61fed1aa, 0xbf914a82, 0x3f011d12, 0xd724f677, 0x95ae7494, 0xf52aee5c, 0x6164dbac, 0x79090039, + 0xcccf8364, 0xa3fd3652, 0x5932b3a8, 0x54505d5d, 0xb45964f8, 0x01f9c0b4, 0xfe24f53d, 0xebb16e03, 0xe70889ad, + 0x9e0937c2, 0x825551cc, 0xd6186ad0, 0xdbc4976f, 0xe9a96f34, 0x28a2edc2, 0xb9a78003, 0x5ded6d61, 0x36a256f3, + 0x6d014a27, 0x1e217314, 0x0e3b9c98, 0xce751ca5, 0xac01ca35, 0x5e82680b, 0x1f55bde9, 0x427d53fc, 0x74a3757b, + 0x7f2e4b79, 0x1c1aa03c, 0xafef5b0b, 0x891f921c, 0xcc7ab3a7, 0x22674022, 0xaba9a1b2, 0x3ac75a82, 0x86d4101f, + 0x30130a36, 0xd9bb91ff, 0x099df09b, 0xc7f6d01b, 0x44817dc6, 0x7098f23f, 0xc14275b8, 0x977bebca, 0x5583981e, + 0x32dd4596, 0xe005a6a0, 0xa8aa40b8, 0xdf9d1f1d, 0xebd64414, 0x55fcf50c, 0x60c98d99, 0xb4c547b8, 0x07968a23, + 0x2c687f10, 0x056488ea, 0xf924b75a, 0x01c1c799, 0x641faf6a, 0xe691ccb5, 0xcb67184b, 0x8d479f1c, 0xb03cf52f, + 0x4eeaa8be, 0xbc72008f, 0xdcc6e241, 0xce0f269f, 0x32a51cb4, 0xafd85884, 0x851ad04c, 0x1698163e, 0x776a6315, + 0x25ee38e7, 0x1f67c4ec, 0xf13b378a, 0xbad93b94, 0x9dd5ccbc, 0xbb386ef0, 0x9fbea96c, 0xc1ce769c, 0x1778b8b8, + 0x934637be, 0xbbe8cb4e, 0x4212faa5, 0xa18441f3, 0xee10ade1, 0x2333e4b9, 0xf15a5c67, 0xe83ec26c, 0xbc82b8f2, + 0x9997a2c4, 0x9447460f, 0xbfcd3adc, 0x54ebb30c, 0x3a325fd6, 0xeb780836, 0x88754ac1, 0x39244bc5, 0x2197d362, + 0x25676bf3, 0x264745ae, 0xf2d46d84, 0x175f462d, 0x4fc11462, 0x4980b483, 0xeb32f48d, 0xac4a5fa6, 0xc8587062, + 0xdc48c8d8, 0xc1b13e3a, 0x7b68503e, 0xb4fdaf4f, 0x0c87fc85, 0xf3689432, 0xba70a12c, 0x758da549, 0xe5e291fa, + 0xc585a41a, 0x68c78865, 0x6887a189, 0x3cf88190, 0x9e040988, 0xde250cc8, 0x449025c0, 0x0dd01c83, 0x41a2b31f, + 0x4a2ffe2d, 0xf501700d, 0x3c57c6fd, 0x515421dc, 0x9c4d2e73, 0xafd03315, 0x235797cf, 0x89cecb8a, 0xb9e280c4, + 0xfc3537a9, 0x26ea6ffa, 0x60d8b35b, 0xfb4a6fbf, 0xb4629ce8, 0x7b2af414, 0x5884c770, 0x03197a69, 0x59632bb9, + 0xb34c9d5e, 0x0773da24, 0x7a4a7c5c, 0xa4a872c9, 0xf3fee722, 0xd5be3061, 0xdeb14477, 0xa2077a32, 0xd28755fa, + 0xc0740a6f, 0xdf6e476e, 0xab827257, 0x1bbbb2f9, 0x2fe81051, 0xcaa9da62, 0xc4bdc43d, 0xa7e8339b, 0x296bdc8e, + 0x0176a4db, 0x893d51a3, 0x5d36576d, 0x00f76341, 0xc25e835a, 0xe3e839b2, 0x29b8c11e, 0xc5db10f6, 0x8742b544, + 0x8d622e2d, 0x84cbee08, 0x47bf9ede, 0xd307d4a1, 0xdf5b3527, 0xb7ed55ec, 0x25881fc3, 0xd2a938b5, 0xf49c13ba, + 0xb575a73d, 0x2da16e16, 0xc5a1c75d, 0x8a9ca746, 0x859dfd6a, 0xac80f747, 0xc6b93130, 0xc92f918e, 0xccff1fd4, + 0x69758d40, 0xafe96e42, 0x5e729fee, 0xaf45d6be, 0xd4dceaab, 0xf3011e8d, 0x86cb93be, 0xa2cc0290, 0x1f92e3bd, + 0x31dfa554, 0xbca95f99, 0x12274da0, 0x67894f1a, 0x6a021551, 0x37a3f78c, 0x996c7492, 0x37bac14e, 0xddc81858, + 0x384f288d, 0xddebdb88, 0x686fb863, 0x67d74073, 0x140652e9, 0x92462845, 0x80d8c71b, 0xf7a97f18, 0x350a0e61, + 0xfa1fff43, 0xaf65661b, 0x41d44f7a, 0x915dfb15, 0x855ec46b, 0xf0416b70, 0xd12fb336, 0x4907dd43, 0x8056b983, + 0xeae6b9d6, 0x79ca182f, 0x69e6e260, 0x5d168e8a, 0x4d0af58c, 0xc5fc6471, 0x36a9dfec, 0x7ea780f8, 0xae608a00, + 0x08073590, 0x9e33af69, 0xda9a1481, 0x03038cbe, 0xb035e837, 0xc0881610, 0xa952487d, 0xb7d10174, 0x0e575560, + 0x52313237, 0xd795d9d7, 0x6dbb36af, 0xc3ba9345, 0x2c76d62a, 0xbd842404, 0xea6ac99f, 0x150c8473, 0x37aa5ee1, + 0x23b49b76, 0x21f97fd5, 0x23af1c48, 0x38101abb, 0xb991de77, 0xf72c0ffd, 0xa3fa68bb, 0x30f1403b, 0x17dc88b8, + 0xc171fb38, 0x0ea4b05f, 0x7ab9294c, 0xa8d79d1e, 0xe2f9ec76, 0x1a58778b, 0xf6a3da30, 0x1cad53a1, 0x45cb9942, + 0xd0fdc5b8, 0x07b0e660, 0xe1a054d4, 0x87d10ad2, 0x13a4c6c5, 0xd04d18e7, 0x6de29e7d, 0x5574cf47, 0x64144cc3, + 0xf1cc700b, 0xc588a788, 0x368b3eb2, 0x6f755ed8, 0x5713a909, 0xca35b7fb, 0x35260b14, 0x07592cc3, 0x466bd627, + 0xf71540a3, 0xa2ca0544, 0x38dfc489, 0x0a16e7af, 0x64768b6e, 0x199d584d, 0x239afee5, 0x56aa019a, 0x871a8de3, + 0x73b2b59c, 0x36aee166, 0x779e9b32, 0x1e595926, 0x64b3407c, 0x33b9ff36, 0x2fd2758c, 0x554e3485, 0xd5a9462b, + 0xce993984, 0x72524a21, 0xe458d986, 0x8cf2ce79, 0xd6b366ea, 0xe7369ca6, 0x062cac92, 0x16bcd07d, 0x64ee5fb1, + 0x9ee8d97a, 0xef007ba2, 0xe6df3d30, 0xb41c3266, 0xfc3ee7e5, 0x3b858cc4, 0x90766832, 0x1b017835, 0x04089e9d, + 0x820db196, 0x7aae2d24, 0x4b221f0f, 0x1a71258e, 0x26613a3d, 0xe9744cda, 0xba09881c, 0xa3d4f111, 0xdc5c510b, + 0xd14e79d6, 0x19b4cc7f, 0xc7fa608d, 0x44d62ec3, 0x65179371, 0xfd8dd2e1, 0x4979e26d, 0x3d8f06ae, 0x609f4ee5, + 0xfa0a4864, 0x96e6fee7, 0xf6234f15, 0x162e7280, 0xb4e4bfa8, 0xf1f5cc35, 0x9932d6ec, 0x20239f72, 0xdb937889, + 0x11282197, 0xc3defc60, 0xcb47ad9e, 0xe84ddbb5, 0x33833c6b, 0xa67db69a, 0xa7dc7973, 0xa71f1c77, 0x9be9ac6f, + 0x170df0ae, 0x1fb03736, 0x90c85fd2, 0xe4599b00, 0x216631c8, 0x931025fe, 0xaafc9439, 0x37b1c4e9, 0x7bad115a, + 0xc981b6fb, 0x557c9b89, 0xf50e3606, 0xd1f9c3dd, 0x7a415d9f, 0xf0f9cd19, 0x1f0b2e38, 0x2217309e, 0xa51048a6, + 0xa1424623, 0x6e54f8ab, 0x4e8b824e, 0x893adc3a, 0xfd075c95, 0x5af98e00, 0x41cf0124, 0x0459837c, 0xd29d43b7, + 0xc7977a3d, 0x156c63b1, 0xd4919e2a, 0x6c70dfe3, 0xd550cf64, 0x0d1caa97, 0xdcdd9ed0, 0xc257da01, 0xe89a628b, + 0x3b5ba150, 0x28810780, 0x75267345, 0xdf743650, 0x7ed6979b, 0x4ed29745, 0x9318727b, 0xfea76e86, 0x84c9167c, + 0x7748fed1, 0xd9169764, 0x1223ae28, 0xb09cd7c8, 0x1f2fc233, 0xcd862c2c, 0x5950e651, 0xc05bab1b, 0x3cfeb71e, + 0x197670d3, 0x8f3d2850, 0xa5398a47, 0x18c0155d, 0x7853f18e, 0x3cb2cc45, 0x4140fee6, 0x67ba9841, 0x18f36b6b, + 0x46965c6c, 0x5e251b11, 0x638979e4, 0x226be1d3, 0x3a88a05c, 0x285fbc32, 0xebd50af4, 0x29c571a4, 0xcc435332, + 0xcba9c776, 0x2ab8deb4, 0x522c47b9, 0xe1cda7f0, 0xca63a997, 0xa904ad4e, 0x110fec25, 0x55e5d545, 0x16a3ecce, + 0x318f7154, 0x1c13cc38, 0xbe84740b, 0xb3dc8494, 0x0e7c1232, 0x544e1144, 0x37c78c7f, 0x61dd8393, 0x5a08715f, + 0x7ae10083, 0x346d500e, 0x11130caf, 0x1eb204be, 0x1d685993, 0x8e2897cb, 0xde6d4da7, 0xeb7237f0, 0x67325794, + 0x971d5c98, 0x7fca9795, 0x822796ac, 0x8d8dbd05, 0x7c5ab12d, 0x83354ce0, 0xd2ce5acb, 0x03b5a3d3, 0x1f152ae7, + 0xc3ef8dd2, 0x61b15aa8, 0x0fe7f275, 0xc205fb78, 0x2d3c5807, 0x9c1dd198, 0xd14a0da4, 0x309c239e, 0x85fd11c1, + 0x6340a8fb, 0xd4a71d6c, 0xbb605cac, 0xd3c41e45, 0x33f775f3, 0x7c36e719, 0x09bbf9c4, 0x5d83c949, 0x052998b2, + 0x66e4b2e1, 0xa93cfc23, 0x4ff32d85, 0x662571e6, 0x42e28136, 0xefec3351, 0x44015e6b, 0xbfe42881, 0xbfd48d7f, + 0x3702d75f, 0x82b9c60d, 0xfabc6125, 0xdcbbc8c9, 0x81855121, 0xd3e53fcd, 0x6a157865, 0x52eb84d8, 0x25ac704e, + 0xe3128077, 0x2eb05ba5, 0x46bbdf0a, 0x72a8c373, 0xe428c23c, 0x4abde1d4, 0xcbd46e59, 0x9488ea9a, 0x7fea17a5, + 0x91ac02ed, 0xcd934e95, 0xf495c687, 0xce5e3758, 0x3591431d, 0x12c6d041, 0xdb2877fa, 0xf215cb6a, 0xae850de2, + 0x239ded57, 0x1b7a6877, 0xebac2d0d, 0x49e6e6d9, 0x5ea5dfb7, 0xea82d369, 0xf353df89, 0x02d007f7, 0x8374bb13, + 0x5e0c8c54, 0xbb179dcc, 0xd64bd3c8, 0x12025d1a, 0xdee4a031, 0x4f58f57f, 0x4d9ace63, 0xbfbdf1ee, 0x1a3c6316, + 0x21f44aa8, 0x38805c5a, 0xf286d3e4, 0x69badce0, 0x75875b7e, 0x09e4ff24, 0xfaaba8c6, 0xdc5e170f, 0x5c324822, + 0x2fad370a, 0x49aad4b5, 0x96e039ca, 0x212ebb53, 0x84bc837c, 0x483c38a6, 0xa07e36a4, 0x1aae2115, 0xf5bad2ca, + 0x67630a90, 0xcedbf72e, 0x6a20ae9a, 0x4efdcffd, 0xed541e6f, 0xa4094d1d, 0xc3eb5085, 0x5d72b628, 0xec40ccbf, + 0x3ccdc827, 0xa9be747b, 0x4492df00, 0x2a395199, 0xdb55ed07, 0x05d87b7c, 0xdc4002b4, 0xce9c5ad9, 0x1abb8a1c, + 0x48ebe347, 0xb9812dfa, 0x62c6b2a0, 0x8ce34c05, 0x079fc18e, 0x80804db0, 0x2bc0d90d, 0x4fbe92a4, 0x93f88ed1, + 0xa2403069, 0x9b37109b, 0x59443356, 0x7cf6e863, 0xf4a9816f, 0x89d2d315, 0x8528b98d, 0x46839386, 0xcd24c57c, + 0x9c232dc1, 0xcdf5d974, 0xc28da21e, 0x5b524380, 0xc5c1e6d6, 0xfa93f660, 0x5c3e4bde, 0xc3024e15, 0xa3f929bb, + 0xa2a21555, 0xa05cdd43, 0x67dd258e, 0xc06a43c8, 0xf40b3000, 0x37a0ea71, 0x686a87c0, 0x82bb8007, 0x5ee57667, + 0x74ce00c8, 0xa59397fb, 0x5881201c, 0x7b15b62f, 0x7408ee48, 0xb62a456a, 0xf748e563, 0x6b79f407, 0xf5f529e9, + 0x0713c5de, 0xc67a87dd, 0x821909ff, 0x2d7b6383, 0x2eb6d73c, 0x5874613a, 0xf8d68298, 0x15ef368c, 0xfcf38c86, + 0x4b80e033, 0xb4f67e76, 0x07002bc7, 0xea411ffa, 0x7b6c0026, 0xb5eb4297, 0x3dc9f6b8, 0x89541b57, 0xbc67787f, + 0xf5bf6230, 0x765acd74, 0x43f48c75, 0xfac34119, 0x9f1f018f, 0x32e72340, 0x0c442584, 0xdddc120b, 0xb85fc9f4, + 0xc309c3d3, 0x0137ad2d, 0x8a170dc4, 0x935b8358, 0xb4e12ea5, 0xc1d42571, 0xcf331ceb, 0x08aaf6d9, 0x68cecbca, + 0x2b4193e0, 0x748cb5bc, 0xd9596e68, 0xdb0208e9, 0xcb31f9e0, 0x22fcbeff, 0xf34e8a88, 0x848c6638, 0x230f3778, + 0xa23e665b, 0x9fc371c5, 0x651af1dd, 0x6d099c61, 0x35e3cf13, 0xe9a92b99, 0x531ffb1a, 0xdecea626, 0xe38015df, + 0x72b2fa81, 0x5307c231, 0x4699f50b, 0x6ee71e09, 0xb3af5194, 0x4f6327f9, 0xa9a407e6, 0xf2fb1537, 0x01d752b7, + 0x2c6bb937, 0x4e30cec1, 0x3d931dcb, 0x346ff751, 0x72e32bc4, 0x4a636f42, 0xb894ed32, 0x5340d960, 0x99b97e0e, + 0xdc895a9b, 0xc7d2c7dd, 0x9ed76bf6, 0x6beb6573, 0x0e825c83, 0xbaad63b9, 0xb07f9dc2, 0x3b32747f, 0x92f312a2, + 0x71cdce9c, 0xf1665b28, 0x15e85890, 0xc43921e6, 0x0df02574, 0x73beeb8e, 0xbf8398fc, 0x6b8fc82a, 0x8625dce6, + 0x836343af, 0x17f3afe3, 0x95d81ee1, 0x74620b80, 0x2895228f, 0xd0e70df0, 0xb54796ea, 0xf77aa4b4, 0x204ce0a8, + 0x5b16491c, 0x2b2c7e08, 0x5ab3a450, 0x3cac6b4b, 0x63c1de60, 0x666004e3, 0x86be1753, 0x7c10f6b8, 0x7ef02f01, + 0xe8c85b7f, 0x4f3ad0cc, 0xd6fbf10a, 0x8203ff04, 0x3b9a7ab9, 0x616458f9, 0x4946cd7e, 0x2ff9495f, 0x597942fa, + 0x53ad4eec, 0xc76f1275, 0x42574046, 0xc16f1452, 0x312c6671, 0xd1799651, 0x159c5f2f, 0x12e871ba, 0x51149b21, + 0x21bf745a, 0x57355f9b, 0x3eb9594f, 0xf067eaa0, 0xc0ba7ba2, 0x2c36a2ba, 0x677477de, 0xca553d5b, 0x18ff587d, + 0x3d573480, 0x9cb536e2, 0xee44ceef, 0xf8058c97, 0xc2775388, 0x92dafe39, 0xe450f149, 0x37441350, 0xb5686b66, + 0x5b1603c2, 0x3efd494b, 0x0d1f54d1, 0x2f8170eb, 0xf21a8caf, 0x89c17d85, 0xfc0843d9, 0x74a5e344, 0x35db9ed4, + 0xba9f005b, 0x14cb3e60, 0x5c74081d, 0x90d90e5d, 0xc9f40934, 0x2869cb7a, 0x3ed8e824, 0xa456f226, 0xb8e419d3, + 0xc013ac6c, 0xcb556e05, 0x84556b2d, 0xe1d91729, 0xd4017df2, 0xaacf55e9, 0xc7a82af6, 0x198bcaff, 0x948aa23d, + 0x20dc1819, 0xf73076ad, 0xa5cccb8e, 0xe038e199, 0x8e5a26e0, 0xe51619ef, 0x1a004a53, 0x1489c1dc, 0xf55c2024, + 0xffc015f0, 0x0d2ba611, 0x88fffaa2, 0x931beba2, 0xf3d9c904, 0xe770bb9d, 0xc7c16b97, 0x5ad5f45b, 0x7b477d43, + 0x5aca66f8, 0x5e50d5e7, 0x938949bf, 0xfdffd3c9, 0xd6b461ea, 0x9ad7c1f6, 0x515a17ce, 0x22f75469, 0x5a58c56e, + 0x6a77f57f, 0x5de5d5ea, 0xab8a55d7, 0xd3ba06e5, 0x1016f75a, 0xec9d5646, 0xa0317c73, 0x8fe2ebd6, 0xe4050fdf, + 0x290e2267, 0x94725871, 0x2e50dc36, 0x7a93967b, 0xe2fd11c2, 0x98b3e003, 0xb63b18ee, 0xb450c4d0, 0x0df9bf91, + 0x78ef0a3a, 0xada8d44a, 0x51a7bd86, 0xa6da4943, 0x5a20f755, 0x03a74b05, 0x13fdd4e1, 0xb97c55e6, 0x6782d845, + 0x444b530a, 0xe591fb03, 0x947a2356, 0x97305c82, 0x9def5c4f, 0x76151d81, 0x0928f075, 0x30331341, 0x8b8dfe7e, + 0x917781fa, 0x23b722c4, 0x08f119db, 0x8a31e4f9, 0xccb48f4c, 0x03268142, 0x3020b5da, 0xf2989d04, 0x58334c3e, + 0x7722dc91, 0x39d03ceb, 0xd1f2d2e5, 0x2aec3a89, 0xef2762a1, 0xc69fa31e, 0x472b44f9, 0x03cde963, 0x30b6f8b3, + 0x28effde7, 0xaea7e81b, 0x17a439f6, 0xb6ee7ff4, 0xd8cd544b, 0x21658280, 0x9f40da8a, 0x1ea9936e, 0xa5a2c509, + 0x84bfbaf4, 0x711ea4cd, 0x37f0b258, 0xc97f22ac, 0x4490de85, 0xf7b3a12f, 0x3a1d541f, 0x4d9bd7b0, 0xde770b39, + 0x76be731c, 0x14d307e6, 0xcf2c0109, 0xa6a4a169, 0xe69e085f, 0x73d8e408, 0xc2cec167, 0x36a9851f, 0x03880fac, + 0x3e08b810, 0x9d7bfca0, 0xd619a192, 0xfaee1d7d, 0x7915519a, 0xa5abebe5, 0x79d82d50, 0x52102d4d, 0xd4372a49, + 0x4a075202, 0xd7dd2f95, 0x3361d29a, 0x38746488, 0x05e79da7, 0xcb8f90fb, 0xcb30c113, 0xb7647a84, 0x77a4ddfa, + 0xf2935977, 0x0f6c17ab, 0xb8a7145f, 0x7f36ce4e, 0x327dd56f, 0x24ab5cd0, 0x3235ed8e, 0x210b7404, 0x8ec36815, + 0x1b9c9d7b, 0x0a52c58b, 0xc4104360, 0x1ace761e, 0xe676cfb3, 0x8c3838aa, 0xa544224d, 0x17cf4d05, 0x98dccef1, + 0xee0a6656, 0x75ab778f, 0x59eb9dda, 0x236bca41, 0xdc7fba63, 0x4f8eedcc, 0x44779c88, 0x1f1f96ab, 0x1822011a, + 0x3b57c4d3, 0xdf42bf5f, 0x2d7b344d, 0xea917080, 0xa1f10948, 0xa7d05109, 0x3a72c3ec, 0x1eae4ce8, 0x24fb070c, + 0x0ae9aa9e, 0x9c4438aa, 0x85a3dadf, 0xcc0a5b3f, 0xdeffd494, 0x4aec7ea9, 0x3fd07054, 0xb0422e48, 0xfc469e9f, + 0x30e237f4, 0x5535470f, 0x290a1914, 0x517a2852, 0x46ac8839, 0xf737f938, 0xde293f6f, 0x87ec19f4, 0xb72580d5, + 0x39ba6eb6, 0xa1b7237c, 0x3d3118c7, 0x26ce0fb9, 0x012d8509, 0xb74aa5d3, 0xcf4d5440, 0xbd93dd8d, 0xce18338b, + 0x73c72636, 0x1f621efd, 0x73f4a2fe, 0x325e8eab, 0x20f5427b, 0x54c24cd8, 0x801a7c05, 0xcefab972, 0x59c9d0ca, + 0x3c410f0f, 0xe3e8230b, 0x62fd484a, 0x7ada9de2, 0x3d0b7017, 0x35d2d03b, 0xf45ceaac, 0xe6fe0c69, 0x895d48fd, + 0x91bf9735, 0x6020d351, 0x0f49010b, 0xba512657, 0x3d2275a5, 0xe3d5d282, 0xb177615c, 0x48634f07, 0x6b593def, + 0x0d083e50, 0x6ba3b66b, 0xe8754b69, 0xd9e8906e, 0x9e98ea82, 0xb2aee4b3, 0xbc418022, 0x3e1bb084, 0xbd2753e6, + 0xe511617e, 0xb504831c, 0x97ceb066, 0xe1f91746, 0xa12bb824, 0x0e26069b, 0x9bc1ff30, 0x7564d141, 0x11956e46, + 0x63f36c31, 0xa3258018, 0x262d9c46, 0x673e9b6f, 0x444fbcd2, 0xcd9a78a8, 0xb78a95e7, 0x76c24f88, 0x2341c737, + 0x286e4a2d, 0x7a147fd5, 0x45db3452, 0x74364761, 0xe3f19664, 0x41a8929d, 0xaab22261, 0x6d65a44d, 0xec4fe1c1, + 0xc3f62584, 0xf09636d0, 0x45605d66, 0xe848c96c, 0xf4b25fb6, 0x0ad7127a, 0x7871ccde, 0x2cd6091b, 0x7692038b, + 0x4fc490c2, 0xe91aa24b, 0x5d1004d9, 0x6fa5565a, 0x913b1d13, 0xa3f99715, 0xb005ded5, 0x2a2ee77d, 0x2fa00d07, + 0x5244043c, 0x2fe4b87a, 0xf73bf8fa, 0x0ba6331a, 0x3b531784, 0xe700026e, 0x8d634241, 0x08632fde, 0x6e0269f8, + 0x13990c60, 0xf5fb6c6b, 0x1c2ed10d, 0xb4582447, 0xe7e81fc3, 0x3775c4c2, 0x07e378c0, 0x8d1b0b8a, 0x2a5539cf, + 0xc1bf942e, 0xb47741dd, 0x83e2d84e, 0xb643c6f1, 0xf9a04545, 0x6f397f25, 0x994dd4c8, 0xb9dcd95c, 0x69f6a708, + 0x563b1c87, 0x7e9186d2, 0x4f148966, 0x33ac4ca7, 0x889ceef6, 0x0f0b7cb6, 0x3f6fab58, 0xdb32475e, 0xc09acc63, + 0x3dd36c1d, 0xf27f1008, 0x1e181e12, 0xb094bc60, 0xb076fcd1, 0x625ad5fa, 0xca3d6fa1, 0x548b6fb2, 0x0c8b0af1, + 0x6f619a32, 0xa26e61a7, 0x19fe9587, 0x8280c45a, 0x44325801, 0x5c8513bc, 0x116e8a32, 0x51978475, 0x8dd77cea, + 0x6c794630, 0x265a9000, 0xa08a3ac8, 0xadf74859, 0x73304fe3, 0x04478e4c, 0x271feb9f, 0x652105e1, 0xae9f2188, + 0x27a4ab9b, 0x4f78d3cb, 0x0b2a5955, 0x7d6843e7, 0xa2330bd7, 0xe80d15f9, 0xce292518, 0x7a75c55a, 0x5e3bd02f, + 0xfaf26f53, 0x5f300d63, 0x0d5ebc02, 0x9ce64a2c, 0x4536efe8, 0x7d899e9a, 0xb30be71a, 0xb8c6d4cb, 0x0e90b7fe, + 0x540a86c4, 0xe9c4cd4f, 0x79b608d1, 0x58ec3bc0, 0x96df04d9, 0xdca9fc20, 0x7a2702cd, 0xda455d4e, 0x7423bff3, + 0x2b6e4251, 0x79dca6cd, 0x0fb3e77d, 0x0329c812, 0x7f0d4fe0, 0x970e4dd0, 0x02f9105c, 0x1261e25c, 0x1d56369b, + 0xa3e90377, 0x458a05c2, 0x2c62b4fe, 0xe856a7ef, 0x65d9fdea, 0x2f718f2a, 0x0086da60, 0xc7c0d8d2, 0x8e7a6fa3, + 0x2c39717b, 0x3f778681, 0x3bb48741, 0x5f17ac61, 0xf0e03e41, 0xd6a33c23, 0xf4224cb1, 0x8bd47495, 0x64dd47e1, + 0x004da8e2, 0x8691d774, 0xe3d477a4, 0x41205635, 0xd7afd5d9, 0x2b8368f0, 0xeb9ff66a, 0x9d677cb2, 0xf523ad58, + 0x11aa8241, 0x84fbf2b9, 0x9e3ad353, 0xafb561f0, 0x26db9317, 0x70e5ce83, 0x1dfd4bf8, 0x598ad6e8, 0xefd03ea3, + 0x884587ca, 0xaa2b890b, 0x78730ef1, 0xa6a7eb70, 0x215ede69, 0xac1ee4ff, 0x07859c88, 0x268865fc, 0x38114366, + 0x61fe4561, 0x275d50ac, 0x024aaab8, 0x6f72a3b9, 0x97083d54, 0x0a62be28, 0x6638b562, 0x11adabb9, 0x3cbd83c0, + 0xcbf2b292, 0xa33411a5, 0xfdaa3635, 0xa03e6655, 0xf10590d1, 0x6e1ea816, 0x086e1713, 0xe03ff41f, 0x2e944929, + 0x414da242, 0x0a2fb892, 0x3de8e3e3, 0xa4a551e9, 0x42eded72, 0x8e907eb5, 0x9d292133, 0x2de11648, 0x564a71b7, + 0x31d86178, 0x0ad624b4, 0x30142ee4, 0x86db4ba0, 0xf8b20099, 0x4447a74a, 0xe32d526b, 0x91cea0fe, 0xbfe75e8c, + 0x886598e0, 0x75054708, 0x43b729d9, 0x57280207, 0xa948db40, 0x653904af, 0x0fa7cf96, 0x76183b32, 0x8c22bceb, + 0x4bc90a6f, 0x8e2fb38e, 0xc313cd23, 0x2e18ca59, 0x9db68b5a, 0xb6e502aa, 0x4cfe4847, 0x95d9fda7, 0xd0e374ae, + 0xfbe17057, 0x54229d72, 0x11896853, 0x2402ea62, 0xae269bcc, 0x06cd68b7, 0x7da92366, 0xc9117efa, 0x9aae6cc5, + 0xd4a516ec, 0x6fc4b867, 0x31e02925, 0x0f191f88, 0xf79ec727, 0xd0c5dafd, 0x0202feb8, 0x266c6345, 0x7f42bfc0, + 0x74fd459d, 0xb62260bd, 0x56a18d1b, 0x58ded350, 0xf314ca7d, 0xd44d9a45, 0xb5818cff, 0x151d4d1b, 0xa9c54f3e, + 0x40fa2094, 0x8db5519d, 0x31d3933b, 0x2379f958, 0x8ea20160, 0x14e7a786, 0xc4a5afb5, 0x9844d697, 0x5c2492c7, + 0x68c4f7f0, 0xa22cc3e2, 0xc310b5f2, 0xac0a1497, 0xfec95e79, 0x91ae9c39, 0x07de1e99, 0xbbdeb20e, 0xda31bc7f, + 0xf2239721, 0xcdc9dea4, 0x19bf3aea, 0x99372faa, 0xed155d1f, 0xa7a444a5, 0xe6a6764e, 0xbfd73057, 0xaa25ea19, + 0x7bf5b929, 0x85e030fa, 0x41bd258b, 0x5cd928ab, 0x223cb55e, 0x4695c8ee, 0xc1f3bdde, 0xdd8e0a9f, 0x3a8a870a, + 0x8b3d4bfb, 0xf1b856fe, 0x22649f9c, 0x24bd2c16, 0xcc6cf999, 0x58b8062f, 0x548251d3, 0xeb7f4439, 0x9d8364a5, + 0x34e39a20, 0x177c0166, 0xf112c925, 0xfe3e46fa, 0x3a237b1c, 0x2f05a117, 0x494ac7c7, 0x9661071c, 0xc3976fa4, + 0x987832be, 0xf88d60a7, 0x14f2de19, 0xcca86ae2, 0x1837f947, 0xbae81def, 0x6d1c0c42, 0x90661020, 0xb59f52ad, + 0x3744da1c, 0xc493b807, 0x0b101cc5, 0xb8a37a32, 0x1899a39a, 0x2dd5de3d, 0x9255432c, 0x426bbc65, 0xc09d00a4, + 0x1278191d, 0x8e2603d1, 0x79344bcd, 0x33d7aaae, 0x1b2dabe7, 0xe5610553, 0xd70c18d8, 0x0a336bc9, 0xf54affe5, + 0x5e33837c, 0xc248c23e, 0xb5b760f7, 0x1af985aa, 0xa6b2ab82, 0x36594210, 0x2421afbf, 0xaaa47f68, 0x8cb0f22d, + 0xd19c0d17, 0x2ffc6d32, 0x6be2271c, 0x168429af, 0x610722fa, 0xe3b9f765, 0x80ba16d5, 0x8e481eb8, 0xa371b541, + 0x0e55c291, 0x65263237, 0x4d5ab7f6, 0x94c76548, 0x23d13875, 0x5ad4c0e8, 0x047e6581, 0xf6206199, 0xa6baf068, + 0x34800210, 0xf3739e17, 0x1ed002d0, 0xf943a0ca, 0x5b724e3c, 0x054ffb8f, 0xa73a6934, 0xa5aec1f0, 0xb59a418d, + 0x71ab3715, 0x8130a954, 0x9f485da0, 0x460d1051, 0x6153bb0e, 0x20b03bad, 0x674fc81d, 0x122eb5a9, 0xe7c23d5e, + 0xb86ea0d7, 0x77c4b180, 0x4b069a4b, 0x5fd79e79, 0x753bad5b, 0x3b822b58, 0xb3eabf4e, 0x6f48effd, 0x3ed38ceb, + 0xffdaa25e, 0x7e13ebe1, 0x8dc5de88, 0x9a74d95b, 0x9dcff7fa, 0x8ab3ada6, 0x8613d8e6, 0x4b66cb7b, 0x111f57e8, + 0xaf2bb5e7, 0x0549fb53, 0x2c7d6913, 0xd2ed52cb, 0x85be879d, 0x246d9d9c, 0x00cca92f, 0x97fe150f, 0x2cb007b0, + 0xde990b73, 0x3b60a5b4, 0x2f845a13, 0xaed110fa, 0xbdf6cb52, 0x2bb92a38, 0x21f5ee86, 0x42d739eb, 0x5be91dcf, + 0x0310525e, 0xbc536ef7, 0x5ee24bdd, 0x51935486, 0xab07658c, 0x0eaf676e, 0x71d59e9d, 0xf2bf5b2c, 0xb7d86108, + 0x626af447, 0xe2980485, 0x416bf947, 0xe732a930, 0xe670c211, 0xc79b48d0, 0xaa51abb0, 0x400d0799, 0x9fcf2303, + 0x7212658f, 0x1de42aac, 0xd180c245, 0x00b5cafe, 0x7cc356f1, 0x868b207a, 0x3f17db45, 0x5764709e, 0x88433059, + 0x1adcaa3b, 0x3d90b71f, 0x498fc2b0, 0x75e2dec3, 0xbf65e334, 0x02601c42, 0xc0b265e6, 0xe2ff8bf3, 0xbb6d237a, + 0x0bba1317, 0xb8df2e4d, 0xe2a9a5b3, 0x49db5335, 0xd42c9fc3, 0xef5a84f8, 0x6223ed90, 0x3857ae88, 0x6902cbf1, + 0xc13f97a0, 0xc90ef2aa, 0xd8d634ab, 0xc3ab4cc1, 0xeda1e75c, 0xd9bc6f09, 0x7047f7a0, 0x07706f15, 0xd4072ee8, + 0xed4c2486, 0xb1c67634, 0xb001d1d1, 0xd8a2c311, 0xa7f006eb, 0x5c4525da, 0x863b9d30, 0x08234f92, 0x4477f1db, + 0x3f0aac97, 0x5f83a31c, 0x4da0d8b9, 0x8b317e32, 0x94345cf4, 0xef1c20d9, 0x93b33390, 0xa101167d, 0x1e733985, + 0xaf3a4ed9, 0x62688804, 0x3b140d6b, 0xa5384a44, 0x670cc9a2, 0x11836649, 0xff366265, 0xf2abc488, 0x9674bca4, + 0x2f509816, 0xf33431c7, 0xfba20d75, 0xce5d5088, 0x9550fbaa, 0x8f30e38b, 0x8c9d5685, 0xedd35be6, 0x8eb7c6a3, + 0xc46ca1e3, 0x178ca326, 0xee192d5b, 0x027a9d1a, 0x419460c6, 0xb4a8e05c, 0x33767944, 0xb3a4ab20, 0xa155ee0a, + 0x63cc8274, 0x2a0e9786, 0x4c084f8a, 0x0a6b12cc, 0x5301e231, 0x1a3a129c, 0xa58a8a3b, 0xa2fe249b, 0x633e8f49, + 0x0f264ffd, 0xa8da5c89, 0x9e9b9918, 0x05304e44, 0xc42d8e9b, 0x71d01c2f, 0x95a52c87, 0xdf9f4818, 0x29ebe008, + 0x1ccae97a, 0xb4161d35, 0xe5cf3ff2, 0xa2d3093c, 0x77525e44, 0x647ace97, 0x772038b1, 0xcf739a1d, 0xd071fb47, + 0x7a0db46a, 0xf603587d, 0xed662825, 0x2ce9fc28, 0xae1b278d, 0x34c817fd, 0x274b02e7, 0xfcbd1ea5, 0x62969086, + 0xe7367809, 0x3b6b47bd, 0xccc8a6a5, 0x0fb93ac1, 0xeef0e55b, 0xd4c05606, 0xa37a79b2, 0x18bd886d, 0xd8db1826, + 0x7cafb501, 0x901c7b65, 0xa2dc3dad, 0x2dd4da4d, 0x5a472f6b, 0x6e82570e, 0xaf78f901, 0xa7976322, 0x16bda963, + 0xf80df660, 0xa4856753, 0x60c448d0, 0x151deda2, 0x5e7093f0, 0xc27042f8, 0x8ba290da, 0x411b14d4, 0xf6c6dd14, + 0x3b5dd243, 0x1b90ce4b, 0xf3180c08, 0x87a7b5b8, 0xbc9c3ca5, 0x8a07fd1f, 0xebd1a5c2, 0x99ae2ffe, 0x142e09b7, + 0xf5ce54aa, 0x99d5cebd, 0xbd790bfa, 0x3d02fe8e, 0xae1c8a1a, 0x7deb20f0, 0xc2b2448f, 0x6742cb01, 0x7ec86a0b, + 0x77635671, 0x3ee5721d, 0x9167e9e2, 0x6d3b1fc0, 0x9fa46894, 0x1d462f2e, 0xcd9f00b5, 0x5f51a298, 0x05841303, + 0x23e37d8e, 0x9e3a8c89, 0x1caddfab, 0xb3ca5a45, 0x270994e5, 0xd4e628f2, 0x83c1d7ea, 0x4d2bf358, 0x5a4e628b, + 0xc740a734, 0x4d073516, 0x3762fc35, 0x62745693, 0x42596192, 0x636ab11a, 0x74ccd978, 0x5720aedf, 0x6f9fd81e, + 0x4b27e153, 0x719ba569, 0x253c50eb, 0xa2c6b29b, 0x99fd7490, 0x003f1ccc, 0x55e3cf13, 0x7b377fef, 0xa165d385, + 0x6f6ecb53, 0x5e093fe4, 0xcc2d95f2, 0xee176726, 0xa6d633f7, 0x4d878065, 0x2a073664, 0x295a7537, 0xbd423db8, + 0x4c99508d, 0xbe3b00a2, 0xdf8406ad, 0xaebb987f, 0xf9a75014, 0x245409b9, 0x22b1b667, 0x4552c813, 0x1858b849, + 0xb44e1f20, 0x2af6ee03, 0xcbb59b78, 0xfdef5747, 0x3a6d7589, 0x89a75689, 0x72b84b57, 0xc23a0a4d, 0x112ef974, + 0xcf751aed, 0x28001bf3, 0x9a531a64, 0x563be78f, 0x03514bc8, 0x35a3847f, 0xce9b9ca8, 0x5dc89a6e, 0x9f8031f3, + 0x5cd1e7c5, 0x209f3ffd, 0x06b68b14, 0x2a31b897, 0xdbd81fe2, 0x45bce08e, 0x970a0665, 0x0e2ad04a, 0xf84b8311, + 0xf277bb3c, 0xe84109e9, 0x6ff57838, 0x4a52d70b, 0xa0ec355a, 0xeb946811, 0x2e648c91, 0xdc1e2e45, 0x8d626630, + 0xb58b19eb, 0x9cc4113b, 0x1e3bb099, 0x53c5dad5, 0x6a8504ed, 0x324ef4d3, 0xab34a43f, 0xeb836373, 0x533c465c, + 0xe691418d, 0xd1ec033c, 0x2bfcb4a6, 0x58168cb9, 0x3788d372, 0x6a4cfda3, 0x44f738f1, 0x19286a8a, 0x310328a1, + 0x9d449afd, 0xd3704c24, 0xd3addfba, 0x0208ac9c, 0x695b4d44, 0x384ec966, 0x62615d76, 0x73cded98, 0xd7c693ea, + 0x77b67766, 0x4b23f993, 0x1b1d1d64, 0x06866e98, 0xcd6e6532, 0x18817a14, 0xa538e036, 0xc12a22ed, 0x28703cc9, + 0xe3972199, 0x437613f8, 0xddf9cafd, 0x31c6d990, 0x512dfee1, 0x942138af, 0x36f8b23e, 0x701e5a5f, 0xd8f5bf6d, + 0x11f1e777, 0x35ef77b7, 0x80f0f5ef, 0x605caa83, 0x3c6f83aa, 0x3441962e, 0x43aff978, 0xee90d1dd, 0x65e48a83, + 0xcd427188, 0x301088e5, 0x1b039ce8, 0xbb5f3e88, 0x1670124e, 0x459e53e8, 0xbf275b6b, 0xf529e22d, 0x2a103a9a, + 0xb004136e, 0xbc1d5d85, 0x74abed49, 0xc824b936, 0x95483038, 0x3916a284, 0x96a0d395, 0x9c5cd3fd, 0xed111291, + 0xf08fd8c1, 0xab73b9a3, 0x0c697363, 0xae392fc2, 0x422a63bd, 0xad08066e, 0xc88f1687, 0x073a6dfd, 0xfef430f6, + 0xd5b8e28e, 0x67ca0b54, 0x009961c5, 0x344e1f1e, 0x47c40102, 0xd830d835, 0x18a25fdd, 0x0b077ffc, 0xe12a6d6d, + 0x911c966e, 0x7a9a567a, 0x9318b58f, 0xe4012367, 0x93b8b094, 0xe0ffb4a6, 0xeb78743e, 0xe16c3fc2, 0xf960f1cc, + 0xe127acc7, 0x91792823, 0x484a4993, 0x477393bd, 0x27ebfee1, 0x918295eb, 0xf002a25e, 0xb75f7512, 0xc95a6fd8, + 0x8a0cc852, 0x53fd8165, 0xf6b3e043, 0x176aea4e, 0x1a7c9082, 0x54e3d725, 0x34f9d34c, 0x883143fc, 0xd2f2f7ec, + 0xe4bf1589, 0x93e4f13f, 0x1e443399, 0xe6472faa, 0x31a5615d, 0x73571441, 0x8ede70a6, 0x00352b9d, 0x26fb5450, + 0x79457fd6, 0xb4bab905, 0x94c12039, 0x4b4ac979, 0xe50491dc, 0x39320c11, 0x2436fa45, 0x796c0810, 0x7fb3942d, + 0x2534a235, 0x594a6c5d, 0xbda6a01e, 0x411c22a0, 0x02a223e5, 0xaf71aa11, 0xa01ea487, 0xc167d6c0, 0xe2186d07, + 0x8bdaddea, 0x1cadc467, 0x1c4fc00b, 0xd8aa7125, 0xdf27633f, 0xa1b3b40e, 0xa98a1008, 0x8e6e761e, 0x43bcc1f8, + 0xfba0be76, 0xdc065859, 0xe131b8fe, 0xa145628d, 0x0ffd5910, 0x7f04b6f9, 0x014b4516, 0xe5a0da68, 0xe41a6746, + 0x4523e82d, 0x4f68a5ae, 0x413f4d94, 0x206db891, 0x8478a40f, 0x25169009, 0x0d5e10b0, 0x81dacc6c, 0xa39b87f5, + 0xb5b4a89d, 0xb01826e6, 0x3969dfbd, 0x8ebd48fd, 0x0072358e, 0xcacca7d8, 0x999c288a, 0x53788e65, 0xf8cb5aa7, + 0xc22b0bd1, 0xab9c76e2, 0xa48c5eda, 0x90ee7cce, 0x3ad3059e, 0x4eddda00, 0xcdc50f2c, 0x29a09cf8, 0x2d2e63fe, + 0xa96c4555, 0xe80a5a9b, 0x78bfc475, 0xa29046a1, 0x1d4aa514, 0xe7302ea5, 0xd267a670, 0x91c4c9fd, 0x86a93900, + 0x388cb381, 0x5df04f9e, 0x0bf58dab, 0x88249f5f, 0x82ccd911, 0x3d76fb68, 0xecd20aa4, 0x7defb7aa, 0xe8a37f01, + 0x05e1e819, 0x567b5c1f, 0x0db7e593, 0x28aac24f, 0x738f34de, 0x06082af4, 0x2ac28e7c, 0xb6cc888e, 0x93ea56f5, + 0xfbfb5848, 0xe66955f5, 0x4d80851e, 0x0c0ccabe, 0x7939af25, 0x5a600d13, 0x4d9a639a, 0xe3413eaa, 0xfa69246c, + 0x75846851, 0xaf4dac62, 0x026fbddc, 0x267c430e, 0x35104da0, 0x5d664776, 0xf4d31fac, 0x0afef650, 0x10161b02, + 0x80a7dd5d, 0x39424746, 0xbbc6938a, 0x5720ea3a, 0x265e1542, 0x2b5ed372, 0x5e4a2340, 0xe79aeec0, 0x9f7330cb, + 0x6004abfc, 0x94484120, 0x151536ac, 0x629174d0, 0xfb725598, 0xc1f35a74, 0xaa767ae2, 0xac548d9f, 0x3ee1600a, + 0x5d7127fa, 0x7fff8c98, 0xb4d72bf8, 0xf8c6dacb, 0xa31d7117, 0x74f0acce, 0xc68a9e2a, 0xca43fb2b, 0xf4d6bbf7, + 0x748c6460, 0x2c7fbb34, 0x53a8f4e7, 0xd62de97f, 0x0bc4b028, 0x7d8590e4, 0xd666d4e3, 0x2432f9d6, 0xe2280c42, + 0xe318ca52, 0x6dac2ef3, 0xb4feae09, 0x11836e65, 0x71fc14f7, 0x2d3e8b08, 0x3d6d8f4f, 0xdb730e17, 0x5c504f2d, + 0xb963d6b4, 0x48b9975e, 0x9630d893, 0x8a506a52, 0xbc2c454a, 0x2ac7d6c8, 0xf929f858, 0x34e49b6f, 0x5598589a, + 0xa936dab4, 0x9191c8e2, 0xdb8ddf83, 0x4485bbba, 0x62b56fd2, 0xb19799af, 0x1f6ba2d9, 0xcd8b8ab4, 0x4e8855b9, + 0x51a04956, 0xa86cbaa1, 0x845f49be, 0x97f3d7b6, 0x575fec90, 0x91ab5880, 0xe894db36, 0xe5272895, 0x04dd996e, + 0x2cc419b1, 0xaa1d4424, 0x6dec3ebc, 0x4057edaa, 0x7adde7f3, 0x3aea6e57, 0xabfda16e, 0xd2e7cb2c, 0xa7c99f6d, + 0xe319f771, 0x65d93a52, 0x56a2b3fe, 0x3f3ffd35, 0xdfa146c3, 0x7c4b7318, 0xc3650cf9, 0x22ff2d7c, 0xe66e14d8, + 0xe31dbfbb, 0x02049607, 0xe5947f2c, 0xa5f5b119, 0xc9ca1d43, 0x27df2e30, 0x4805b45e, 0xed7715a8, 0xee54cbdf, + 0xd19e6119, 0xee7d9c7f, 0x7d53c14b, 0x8fe46ec1, 0x779e2185, 0x28769649, 0x608f9455, 0x0d5f1c33, 0x27dc3f3a, + 0xc9c845f7, 0x6f527c1e, 0xd70fb895, 0xfe151abe, 0x8ae616e2, 0x0fa8bd2b, 0xfbe05a68, 0xe16906ff, 0xea9bceea, + 0xcfdef1ad, 0xf666a141, 0x86c4f32a, 0x6b5a116c, 0xfc0d0edf, 0xd5019a69, 0x07bd51a1, 0xa6121551, 0x5a94dab3, + 0xb35baeeb, 0x87ead478, 0x9560128a, 0xdfb21276, 0x2f89b5e0, 0x2e1a76c5, 0x343b05ae, 0x7032a2ea, 0xe33455b0, + 0xb4752d76, 0xaf40618b, 0x7b135aca, 0x1a90524a, 0x6d4a4dbb, 0xb0cda7ab, 0xdb6d0da0, 0x9337fd60, 0xe704afce, + 0x6b1fbbdf, 0x8544ae8c, 0x4a6a935a, 0xeb4f81a2, 0x041660c7, 0xf9845e91, 0xf245c682, 0xfa50dfc5, 0x4004cdff, + 0x97f84329, 0xb8b125e3, 0x22f15d05, 0x15a04305, 0xe4a9680e, 0x50eee4f9, 0x134cf166, 0x963945c7, 0x8830b46a, + 0xf5b35063, 0x48f13b81, 0x60f85aea, 0x7779cf32, 0x38e6af0d, 0xf7cc0e4f, 0x201cf96a, 0x73557686, 0x76c54113, + 0x536a6ce9, 0x9104e5e2, 0x9a991d8d, 0xc6d174a1, 0xb0166866, 0x21676421, 0xa95c4735, 0xb1acd17f, 0x12c44ac7, + 0x6efa4d19, 0xbfe7f8c4, 0xd7d8b0d4, 0xb3d31342, 0x19c8b932, 0xbb03e66a, 0x3c146bfc, 0x417c44bb, 0xbcf531b2, + 0x07e10dc5, 0xa8ef4a89, 0x3aaae345, 0x1772b6c3, 0xf285da32, 0x64a2f86d, 0x263180d2, 0x181abe5d, 0xb7d763b5, + 0x776fadee, 0xdf96f7e0, 0xcfbfa3d1, 0x88067a6b, 0xcebbd8b6, 0x85e2b0d3, 0x7dbcba19, 0x2725a0d8, 0x0d2d95e1, + 0x03260b7c, 0x16b6d08e, 0x138bcf92, 0x79ea37a1, 0xbf2092e7, 0xbf7046a2, 0x460a51f1, 0xbe2a5c28, 0x0c253895, + 0xa5a63d15, 0xa6625d78, 0x770f9897, 0x4498d3cb, 0x07db1026, 0x2c46dde2, 0x6f66a12e, 0xcde2de89, 0xbc40241c, + 0xd06e8d89, 0x5c64262c, 0x54027cdb, 0x949772fa, 0x3385df1c, 0x17593d46, 0xbe2b34cd, 0xaeaf259c, 0xe1e2a5ca, + 0x3f03b43c, 0x7fdb04ca, 0xfa988fdc, 0xdd75cbf2, 0x15d435a8, 0x758adfcc, 0x9ea6797f, 0xf047085e, 0x9aebd89d, + 0xa82488af, 0x0e9411b0, 0x5c3e4110, 0xd99661ff, 0xf2e18d98, 0x4d732823, 0xf1d5967d, 0x133e56fc, 0x068cfc83, + 0x4e005dee, 0xa0608f46, 0x071038a6, 0x163c45da, 0x891577f2, 0x82ad636d, 0x43569287, 0xda47fc5e, 0x58c00b59, + 0x6ff366c6, 0xed57858e, 0x23ca64ed, 0xa93590fb, 0xe0874bde, 0xd80c7d78, 0x87ce308d, 0x79795083, 0x805457b3, + 0x8aeb30ff, 0x29bddd9c, 0x903a177b, 0x31cc6f86, 0x8a0c7004, 0x6eeb0582, 0xb4e54a53, 0xfb95de88, 0x21cf95b3, + 0xb6d3c0c5, 0xdbde8718, 0x0bf0d275, 0x49926d66, 0xcfec9db3, 0xf286bdfe, 0xfb35e5fb, 0x6a8b9903, 0xeec4262d, + 0xc49681c7, 0xd1b3e5a7, 0x08929b0a, 0x2b7fd202, 0x7932d5cd, 0x68552a9e, 0x366e2491, 0xc306d126, 0xe0827406, + 0xca829a67, 0x8036dad1, 0xe1552de0, 0x3e964787, 0xd879a970, 0x1b3e8ef9, 0x6727062e, 0xc8f9c5b7, 0xb84ad3a4, + 0x45836013, 0xe3e39232, 0xfe653ba0, 0x327469a5, 0xf4d58114, 0x06c13039, 0x6b49702a, 0xdc48dfcd, 0x091d276c, + 0xa2f4fcf5, 0x9de7e211, 0x5bfbda51, 0x9dfec263, 0x92e6fc27, 0xa9494104, 0x340790d6, 0xc55cb931, 0xf4d2de3c, + 0x72394a10, 0xa0bad8b3, 0x28baf33c, 0x8fd433c1, 0xf46b752b, 0xb6335ba9, 0x6649c5c2, 0xcd996c7c, 0x057fa2db, + 0xb8ff6182, 0x5db0d97b, 0x935ce899, 0xdcef0fb9, 0x7efb4d98, 0xff603424, 0xbf635192, 0xab091506, 0xe6d795f2, + 0x2d5aed39, 0x0a55f4d6, 0x13c000ca, 0x0d6f32ae, 0xf4e8ae3a, 0x448fefea, 0x3e7e24a0, 0xcf3f1e2a, 0xc7ac2a11, + 0x2f2312c4, 0x45ef16dd, 0x655800fe, 0xab464089, 0x103125a1, 0x2045e567, 0xad672b3d, 0x57eec1b6, 0xa3125446, + 0x4322c845, 0xff80f2e5, 0x769eab87, 0x77809f34, 0x4529a639, 0x68da621a, 0x3ff8650d, 0xeb4728ef, 0x122bc843, + 0x633a357b, 0x5ff3c780, 0x29c0a7d7, 0x5ed817cc, 0x9b26d259, 0x34b42ca2, 0xdcb77d6f, 0xbe2cc183, 0x27744b06, + 0x79ce6e1c, 0x37519c70, 0xd081de7b, 0x9638f206, 0x5192c27b, 0x7c2692a7, 0x7f856cbd, 0x74448341, 0xfbf5f902, + 0x81e363b9, 0xa59bf25b, 0x1f07e8db, 0x09e9050a, 0x43336c10, 0xb69fb043, 0xd9b94a07, 0xdeed5f8f, 0xdf3d9848, + 0x872f2364, 0x40d8f673, 0x52e8bba3, 0x1d7de488, 0x9073786d, 0xd7bfe8e0, 0x833d050a, 0x75bcfb45, 0xaed64904, + 0xa096166e, 0x4d93fff2, 0xb163c7fe, 0x2b18e015, 0xd88af00e, 0xf9e2e52a, 0xa9c1366f, 0xaa7515b9, 0x0fea15bf, + 0xd10aa79c, 0x74337d31, 0x7d352ca7, 0x75738e96, 0xf17b250d, 0xf9bc2d60, 0x9f21d008, 0x84b84e8e, 0x33a2108a, + 0x91b9eb56, 0x7fee85bf, 0x2991b9ef, 0x97b92852, 0x60a8b3d6, 0x2361d831, 0x502515ae, 0xfc03e316, 0xe67508f3, + 0x81b8b51f, 0xc6d49e57, 0x7a88b93b, 0x93ca3710, 0xaff4d3ee, 0x2ed7bbf9, 0xa094b75c, 0x1e0af1b8, 0x539132cd, + 0xc1f10d85, 0xc809faf7, 0x9167256b, 0xa2e3ef68, 0xe4019d7d, 0x72f4cb33, 0x47bd2858, 0x06134695, 0x44f8b6b2, + 0xa2b757be, 0xc82d3305, 0xf507f175, 0x884a9d39, 0x35a4db9d, 0xe4157a9d, 0x02065b00, 0xbdca87ba, 0x9c1875ce, + 0x0c8290c0, 0xbd57dd77, 0xe3676b64, 0x470bd04e, 0xd68802a0, 0xa83b1e61, 0x84db0366, 0xc913fbec, 0x3b92098f, + 0x52da8752, 0x0223671b, 0x245f6a17, 0xe82f5541, 0xd432df68, 0x20da57a9, 0xcdf16605, 0x69292c6a, 0xc5f1d698, + 0x0c7c7906, 0x819cb563, 0xf5043db9, 0x46ade517, 0x67094ec0, 0x1c61e0d0, 0xcaa06694, 0xa1ee5ea9, 0xfeb150fe, + 0x934a4af0, 0xbcb7a25d, 0xecfe1cfa, 0x350d6de7, 0xddabf1b7, 0x5bac0b93, 0x1dd353fc, 0xb7397d0a, 0x17b7ad01, + 0xa9b1b68b, 0x0d6d5cc4, 0xcbb245b9, 0x2c052042, 0x8671980a, 0x978d13e9, 0xf13c5c67, 0x5a2e1d91, 0x14ea8dae, + 0x68e879cb, 0x5139bb9b, 0xf81c0c00, 0xb17cbcc7, 0x383de360, 0x30717241, 0x24dc2dc7, 0xa45ac630, 0xbda25ffb, + 0x46b32824, 0xab7cef17, 0x4edcf694, 0x9abe5f62, 0x21c7854d, 0xad7727a6, 0x5b1e7abe, 0x6a8c906e, 0xacc11582, + 0xd5852994, 0x32540433, 0x445a70ef, 0x1f4f9153, 0x3117ee3f, 0x7eb3fdb2, 0xd07cc00e, 0x396a2472, 0x965ffbdb, + 0x71b1ac02, 0x6b128f2b, 0x3fe79784, 0x21955a75, 0xe0a04cee, 0x2b8d78c0, 0x74e08c54, 0x2ab2442f, 0x95423ba5, + 0x4ce51fb3, 0xece26aa4, 0xd1101705, 0x76f21a59, 0x70f11d48, 0xfecfb0eb, 0x50260ee9, 0x9c33e5e0, 0x7fc75959, + 0x4a969dee, 0xd5e546a1, 0x1f639721, 0x33c91364, 0x9789ba57, 0x475c9c72, 0x7997bf13, 0xcfef9a49, 0x2051a25b, + 0x973263fe, 0x397611de, 0x3727a1c2, 0xcb3d2818, 0x924e86cb, 0x381da6a2, 0xb0070461, 0xd4a76e00, 0xc1dbf31b, + 0x0560dc3d, 0x26ddfa52, 0x56c15110, 0x0dc18cec, 0x418c21c4, 0x2e0ef814, 0xbb5cac52, 0xce48c14c, 0x92245567, + 0xa69c35d6, 0x23d9dd68, 0xe826fd45, 0x3dc32d65, 0x1e6c06b8, 0xcb213604, 0xc801cec4, 0xffe48ca3, 0xe3f10b2d, + 0x9da0d9d5, 0xbb20a55e, 0xa5ac8d85, 0x43ac7e38, 0x43b28c21, 0x6454c168, 0xaf8739ed, 0x4d7d58b8, 0xa15ce697, + 0xda7df6da, 0x11401edc, 0x87bc7b1c, 0x01a7ad48, 0xb8fef12f, 0x64d44563, 0x8dd77099, 0x9b08e4a7, 0x4e350481, + 0x0a8002d6, 0x17c45f10, 0x10f96aab, 0xcced9a37, 0xc6a3cae6, 0x484f54dc, 0x84b5edc8, 0x3d6e4358, 0x2ed79823, + 0xffb78e3a, 0x55b0c634, 0x5555388e, 0x6efda1bc, 0xb0b97c4e, 0xd25f205b, 0x0cddeb5c, 0xaa42f15b, 0xf5f5d911, + 0x891df13f, 0x0d89bf82, 0xe49c609e, 0xc789d364, 0xf33ad727, 0x5018f8b1, 0xa6c37a12, 0x26afeaac, 0xf22fc8c1, + 0xd56a4869, 0x91a20e13, 0x641f2b8d, 0x7d6c65c3, 0xac211789, 0x6e9febfc, 0x0980e1a5, 0xfdad4770, 0xaea856ad, + 0x0a570863, 0xedad19e0, 0x0a514339, 0x93625ea9, 0x70a78988, 0xdd96ab5b, 0x562e69db, 0x89b50198, 0xb2ea5859, + 0xc4f9fb03, 0xab865d0e, 0x2fd10760, 0xf8f03f16, 0x36417d54, 0x614e0a21, 0x6a88f03d, 0x09d77d93, 0x9d0d8a56, + 0xbf94ac86, 0x3a72a6f9, 0x5221a4cd, 0xd9b6143c, 0xc8ca5828, 0x2260f56a, 0x014b19e1, 0x798b1ace, 0x56e1780f, + 0x6339dc8d, 0xcd00d0f3, 0xcee57624, 0xb5b76bd6, 0x32de184e, 0x9dd36edd, 0x97fead4a, 0x30c9c4af, 0xefab864f, + 0x22f7d15b, 0x43266b99, 0x13733803, 0xb1262505, 0x96b504b7, 0x5ff7912d, 0x1487eef7, 0x5bc5c887, 0x8739a7fd, + 0x812dd582, 0x31538db1, 0x8cf8efa8, 0x6b2f0308, 0x307d5615, 0x0b05c354, 0x9fb1c9d0, 0xb82597c1, 0x8ef442c9, + 0x9d37aae2, 0xccec8b85, 0x0dcd617c, 0xaf21f611, 0x681e3ee1, 0x03252f66, 0x41b91cf5, 0x93687df3, 0x74de845f, + 0x84c6a0bd, 0x46670cd7, 0xe8920958, 0x0637f2d9, 0x11125509, 0x0a4e89c9, 0x72b98747, 0x0cfa44d1, 0x2dca27af, + 0x73192e8f, 0x780da5df, 0xdee4cae9, 0xf2597cf1, 0xadabd695, 0xd99d064a, 0x359533b0, 0x87030d24, 0x7bdc8e46, + 0x68087fe7, 0xdd3bb3db, 0xe33bde74, 0x657f9747, 0xdf13c0e2, 0x303fb2c5, 0x2644d676, 0xe133730c, 0x76250f67, + 0x69df9a4a, 0x1eeca16d, 0x107cb17d, 0x74bb1f2c, 0x234564a9, 0xc5557a23, 0x2f7018f7, 0x5c1eb9bd, 0xd412efca, + 0x5fa98bcd, 0xf5f6a904, 0x5d914cf9, 0xdf6950d4, 0xc180a0e3, 0x2f21acbf, 0xa15b5e6c, 0xb1a1720f, 0x1e350c15, + 0x5f4224ed, 0xac29f888, 0xe0c7b4e4, 0x2c7ae98e, 0x1ad6b3f6, 0x7f93b474, 0xf0759f30, 0xedaaaaf6, 0xfd5104a7, + 0xcfb11d51, 0x60f5ca8b, 0x63d5b040, 0x91f8e299, 0xfa04101c, 0xc30031f9, 0xad7c9adc, 0xd78f3087, 0x4b7faee1, + 0x1b1e9b17, 0x78176a7b, 0x7dab2b01, 0x582a7334, 0x9931796f, 0x121347e2, 0x60cf2cb1, 0x9bb35d3d, 0xa52f0ad6, + 0xc0757122, 0x111f91f2, 0x3ff6cd87, 0x4aab51cf, 0x5929a91c, 0x141d0ecf, 0x8c739267, 0xd89af9b1, 0x420866c1, + 0x18701ffe, 0xb2669887, 0x9e94b92b, 0x3ed8f6ac, 0xeeacf52e, 0x10c27883, 0x483a4a59, 0xbb00cb6e, 0x81c8cc99, + 0x6855524c, 0x47875c0a, 0xeea2eb2a, 0x764df91e, 0x838648d0, 0x460a4980, 0x3053250a, 0x173f6c83, 0x1fa4fb1f, + 0x82c4f478, 0x6edcb106, 0x8e0f2977, 0x5d9abf39, 0x081e186c, 0x28c48282, 0xbd7b3230, 0x4b977633, 0xf5ae1c32, + 0x723332b1, 0x139ae955, 0x06d6686b, 0x767e852a, 0x23b25393, 0xb17e98de, 0xd81cf565, 0xe85f6eff, 0xd4f9b155, + 0xf181f118, 0xee85b459, 0x2b56535c, 0x7b5e55c1, 0x4ef0393a, 0xefb03e5e, 0xafadcb7d, 0x9c375f90, 0x14d0ed83, + 0x58add18d, 0x3857f7b5, 0xe12d7505, 0xc0c49115, 0xdf59336e, 0x8e5b3e2c, 0xfedb7b62, 0x5f6321c7, 0x1a18b8c8, + 0x49f0252b, 0xad86f17b, 0xad45b6e2, 0x8a1a0128, 0x1250d544, 0xcd6e864b, 0x1b9d686a, 0x414675f8, 0x3c9bdd91, + 0x9ecb97c1, 0x795fa320, 0xcb648f50, 0x734ea0a1, 0x05783809, 0x8e7d8d1f, 0x59328902, 0x0af261e6, 0xbae98f3d, + 0x62f36e51, 0xb3ddfa00, 0x53e12988, 0xd3a31227, 0x09a86a04, 0x4b3517ae, 0xe54c5e30, 0xf0e2d955, 0x52597d95, + 0x1ff206b5, 0x06ceab5b, 0x89a1be38, 0xef457542, 0x679e6b73, 0x58b1a790, 0xa46247a5, 0xde49d121, 0x99de156c, + 0xd9fbbdc8, 0xe75e7eda, 0x2c1984af, 0x87fc0995, 0x1bd469a5, 0xc08cbb5f, 0x82b0bb27, 0xe5b00bcb, 0xe0d0e5da, + 0x80bf6a26, 0x99659cf3, 0xe28d92ca, 0x6a28f41d, 0xa4c3e18b, 0x30a4b7f0, 0x41a2e27f, 0xfae7834f, 0x06b0ea5f, + 0xf573f532, 0x1043c59e, 0x4adeb157, 0x7ffcfe51, 0x91a16276, 0xed94d9d3, 0x5b43d7b9, 0x3f63c405, 0xaeb1e6af, + 0xcd246aac, 0xc42d8e12, 0xeb232f59, 0xe718bd5c, 0xa3607322, 0x5950bcdb, 0x98f2f6e8, 0x99ddd55a, 0x7fac1bb3, + 0x15f87fe0, 0x57b1b220, 0x6bc2168b, 0x22b872aa, 0x863e25dd, 0xd1efe09c, 0xb6d1cd87, 0x36e837cb, 0xff4593b9, + 0xac5f34d8, 0x6cf815fc, 0xb17f43ac, 0x7d5d2dda, 0xcab53525, 0x9632772f, 0x7b950a3f, 0x4aea010d, 0x3c6214a2, + 0xc02387fa, 0x90e0998b, 0x859a256a, 0x547b4d7c, 0x564c2bcb, 0xa3a5b6fd, 0x0698cbd2, 0x6e6998d6, 0xced9400f, + 0xae1b4997, 0x854647f7, 0x4bf1043a, 0x16eb5513, 0x8069412e, 0x7895a435, 0x35fa8546, 0x1ceb7b1a, 0xe79c46b4, + 0x7c31f955, 0xf95349d0, 0x0d20944e, 0xa428c287, 0x051a992f, 0xbedb961f, 0xbaad3ec6, 0x476b9a12, 0x45a77ac9, + 0x59030e8d, 0x8fa4e127, 0x820382e7, 0x64ac8947, 0x0c9ec9aa, 0xb3143b92, 0x96f263f0, 0x5d5acb5a, 0xd76cbceb, + 0x005fd16d, 0x56aa7980, 0x0e4a3931, 0xbea82ffc, 0x7caae20f, 0xf6e104ea, 0xa71e6db6, 0xa5952ced, 0x95a5c1f2, + 0x710cbafa, 0xcfe727ab, 0xbc4db022, 0x7ad4bd4e, 0x8d1a56d4, 0xfcadc457, 0x8f4f6346, 0x36ce91c8, 0xdb19e03c, + 0xbcb2508f, 0x52f7826f, 0xc9570afb, 0xa0855fe5, 0x5661165f, 0x14fa8e6c, 0x3bf1176c, 0xafd484e5, 0x40cc0afd, + 0xcfb86a17, 0xfa5fdd6b, 0x3524db5f, 0x86aca038, 0x15625247, 0x4c9ef5a6, 0x3b5a2cbb, 0x5123ee79, 0xb489edc8, + 0x4249b5f9, 0xdc1616d9, 0x7cebf454, 0x3a22fd6c, 0x21099cf2, 0x69b49ffc, 0x47811cda, 0xa0806bd3, 0x927e3207, + 0x37136024, 0x54a38468, 0x26c979bd, 0x0e7d6346, 0x623d6425, 0xbeec1e88, 0xce38d084, 0x07e4f212, 0x5d051932, + 0x81402fbb, 0x2da6af11, 0x6e65ec71, 0xe6a4899c, 0x6c348482, 0xb7e09424, 0x072040f3, 0x1d5b2aa5, 0x1f6c7d9a, + 0x28160858, 0x144ace7c, 0x92c4aa40, 0xef1ed4e1, 0x378dabc7, 0x4df667bf, 0xe0fe9223, 0x8724ce9a, 0xb1c5ef1b, + 0xc4331902, 0x5c371684, 0x406d7324, 0x531f099e, 0x025af6c4, 0x26a9bf88, 0x49a7acd5, 0x762f8d07, 0x1f7c5309, + 0xb7af1a3a, 0x770f45ec, 0x7a4b7ad8, 0xc26daafa, 0x2f8e3d4d, 0x91bf6e28, 0xf66f0664, 0xf484b07c, 0x8963db15, + 0xb6f35ffa, 0x5b4b2acc, 0x92a59a1e, 0x1b949449, 0x5d03dbea, 0x2178b38f, 0x33ecd85d, 0x9f67420a, 0x763fc46f, + 0xb56d7b0e, 0x5cf24c45, 0xd838f2a7, 0x154dbb85, 0x36359094, 0xa6c4c85a, 0xfb114a5b, 0xb0a7dda6, 0x9f0707eb, + 0xfb861fdb, 0x45e18474, 0xc566027e, 0x277deb1b, 0xda1e96c5, 0xd9f6a6e7, 0x4cb4ff65, 0x08b37144, 0x1ec102aa, + 0x12d7992a, 0xe78d35ad, 0xa29c22f0, 0x1bbb1a9e, 0xac7fa270, 0x6bc627f9, 0x787e4092, 0x308d756f, 0xc247c607, + 0x2bfde647, 0xc002873c, 0x289d0405, 0xe11bcf75, 0xab6d46f4, 0xf18f3d9e, 0xb46664d3, 0x3de3e1db, 0xeb705eef, + 0x2d8c617e, 0xc4cfb13f, 0x9526dd9b, 0xda1b3180, 0x6db63a8a, 0xcc28ecf1, 0xaab5b7e1, 0x0ecc1bb7, 0x45fd744f, + 0x0932c3a7, 0x44173f67, 0xa6d2d127, 0x5688e24a, 0x11e85695, 0x066d601b, 0x976647c4, 0xe9b13995, 0x74af5103, + 0xfb45e720, 0xf85ac4ec, 0xdab30cb0, 0xdbba9a16, 0xd5e55ae9, 0x843ef7e9, 0x61a21d77, 0xca354b41, 0xa5951774, + 0x25a799e8, 0xb7fc42c9, 0xc98f5dbc, 0xbc2a7faa, 0x8b5d39d5, 0x15c03549, 0x93a239ac, 0xaa54f5ff, 0x3273f33c, + 0xd5959852, 0x7263a347, 0x292105cf, 0x1801e240, 0xc2a78f88, 0xd339c657, 0xc204048a, 0xa4036579, 0x2880e73a, + 0x803d5c19, 0x57a0e304, 0xbb83b76a, 0x1c7c6b7d, 0x8bf9a451, 0x57374c29, 0xdda4f462, 0xfeeb87b8, 0x9ff38ccf, + 0xf20bf436, 0xc789ab2d, 0xa497e18b, 0xd61c36d2, 0xd3591f2d, 0xbfead960, 0xfe0bbec9, 0x529b02ac, 0xf0e93407, + 0x1213cf1f, 0xa14f1e31, 0xef08724d, 0x97c572e8, 0x0f0ad4ab, 0xdea3efa2, 0x25a94fb9, 0xc9f1752e, 0xbb0f0eb1, + 0xae6383ee, 0x6c3fcc47, 0xbcd7d887, 0x301b55be, 0x45286645, 0xe1e2680f, 0x1e3bc2fe, 0x00911cb6, 0xd35b6c96, + 0x933ecb73, 0x6d9bd0dd, 0x07a8f166, 0x176d990b, 0x07807a51, 0xc880dd16, 0x30b70c8f, 0xf7a8421f, 0xaa05c204, + 0xcde29aa2, 0x5bb2e8b5, 0xdf6d23a5, 0x7246d220, 0x9980c2e3, 0xeae610be, 0xb5e0e02f, 0x465f9af9, 0xcd2976cb, + 0x2650e315, 0x615a4538, 0x31928582, 0xc8f57c47, 0xa0311fe0, 0xbf78f81c, 0x10c643bc, 0x5cf09050, 0xeb1f3b78, + 0x55060bf4, 0x775dd4a1, 0xfefd631e, 0xa115072c, 0x85169c5c, 0xd6087b9b, 0x7a789d86, 0x9829c3d9, 0xdd192f5a, + 0x8d0523b6, 0xba95d431, 0x0cb2eae0, 0xae7d0173, 0x45929f2f, 0xb47580ca, 0xa3fc56f4, 0x6bda6523, 0xa1cd3426, + 0x5b1f6c41, 0x70e8292f, 0x4731c729, 0x43dc9e66, 0x4c2c0da3, 0xb2b12d5b, 0xf5d11f0e, 0x6e770449, 0x57fee16f, + 0x7528dd22, 0xf01fe958, 0xfd541918, 0x39658ed8, 0x1e3ad66d, 0xab82ef3e, 0x9957bc7b, 0x83127de4, 0x896afb80, + 0x0b04b7c7, 0x37d5beaf, 0xb2b99226, 0x93095938, 0x761fb45e, 0x685d0259, 0xd0725eaf, 0x3e55e437, 0x2722347f, + 0x53d2fd55, 0xca2a0b2a, 0x0aaee68c, 0x91ef2432, 0x19364001, 0xbe42f218, 0x2f0918f2, 0xe6531755, 0x18aba5d3, + 0xdb94c6eb, 0x5accd137, 0x2e996102, 0xdd97a980, 0x934b0042, 0x722008de, 0x0509ce73, 0x2fc54556, 0x86a7350e, + 0x65e91a54, 0x566faf42, 0xfcb8de8c, 0x2a60e2b1, 0x18604a36, 0xb5c5cd8b, 0x5d438561, 0x24f75cb5, 0x99716527, + 0x8d55a065, 0x8a71d611, 0xbff54488, 0x58b809a4, 0x55e867b3, 0x95677c32, 0x327e6768, 0x84e1303f, 0xa19dbab9, + 0x7e479e98, 0x86f4e688, 0x14e4f9f7, 0x7b93d8b5, 0x663baf7b, 0xa380f8aa, 0xea5e8f24, 0x5a88c54b, 0xb5622705, + 0x1d93b7e3, 0x19fa0099, 0x864f8a7d, 0x28a70124, 0x358c9b95, 0xa061a7ea, 0xdbc7fd73, 0xfe32fc32, 0xd80ff812, + 0x5dcd2f1f, 0xc15ce788, 0xf0bed74f, 0x382ce77b, 0x0dc138cf, 0x8c19d81d, 0xa5b51edb, 0x050b4605, 0x092e32db, + 0xae275644, 0xa5479ad6, 0xb71b52f2, 0x8505e0fd, 0x5e2e06cd, 0xd60c9037, 0xd357ed2a, 0xb71dc174, 0x4d2c3ae8, + 0xebdb34e8, 0x80262eac, 0x382620dc, 0x0090bb61, 0xeed073aa, 0xeae4ed76, 0xaf2a3563, 0xfaf2e683, 0x23b64fc9, + 0x7eb8b9c2, 0x6df7a5ed, 0xc9653356, 0x0cc32ddc, 0x7c682040, 0x9cbf89f2, 0x441d0888, 0xa0e13507, 0xe63a686a, + 0xa9298a73, 0x0138a7fc, 0x980ac9c0, 0x0a09fdd2, 0x2405168d, 0xd97cf217, 0x29fd4baa, 0xab26cd30, 0xb6424b88, + 0xc407c67f, 0xeaf3ad7a, 0x3775579d, 0xd28e8210, 0xf2ef9a36, 0x6dd0e264, 0xa3fb431f, 0xc0e0b0aa, 0xbb643f84, + 0xbf6c543b, 0xbd8abc86, 0xf59f5cd1, 0x15a52033, 0x9becf42c, 0x01d8f485, 0xa49069ee, 0xf51a0898, 0x3664ca89, + 0xa79b9374, 0xa6cb336b, 0x7b4a7f49, 0x3c424e5b, 0xb6216dd9, 0x771e3eb6, 0x2da774d7, 0x8b1c5e85, 0x947aae4f, + 0xce4e102c, 0x10f510ba, 0x7f11e8f1, 0x344d15bc, 0xf4bada48, 0xcc9e070a, 0x02af41aa, 0xe6d09a4a, 0x99eee853, + 0xf7d6c1f9, 0xab9edf38, 0x2f5242ef, 0xf3639268, 0x65c275a3, 0x51b23694, 0x004aa0a9, 0x595ec341, 0x62b2969c, + 0x3bf18dfe, 0x27cf71f5, 0x53d1410b, 0x9251a82d, 0xc941336c, 0xd5762f35, 0x3a80eb2c, 0x965c9064, 0x30d8e49e, + 0x866128cc, 0xa083643b, 0x91dec005, 0x51b607bc, 0x9b8cf0a9, 0x84eec698, 0x1aaa7dd4, 0x579ff0c5, 0x1e877ca0, + 0xed03b249, 0x227ed141, 0x20a4ac7f, 0x1b49563b, 0xb503053d, 0x7154646f, 0x0a9c150e, 0xa5c430cc, 0xa0b09e4e, + 0xcf17de1b, 0xeed93e0e, 0x2d51f111, 0x4c3aa003, 0x6403ba3d, 0xc59b379a, 0x6a7a3528, 0xfd536b46, 0x60064fd7, + 0xebaeaca2, 0xf4a0ee58, 0x727217c1, 0x0ac7bc4d, 0x920fd1ff, 0xbaf12104, 0xd3959e49, 0x3770ab29, 0x223bfadf, + 0x2da5b93a, 0x8e7e7ccb, 0xc617c464, 0x6fd66540, 0xce16d0f2, 0xb8acd4f6, 0x5dcf796e, 0xe71fcee3, 0x257f8959, + 0x638f0741, 0x51f57e4e, 0xea43f0d7, 0xb004fa97, 0x813137d2, 0xc6f289e5, 0xe5a32f09, 0x091741b1, 0x031f27b8, + 0x47ec039f, 0x08ad693f, 0x0aff903f, 0xb501662a, 0x1e9812a8, 0x53bd94ea, 0xd0109ac1, 0x0d0e7e78, 0xb99f7c16, + 0x52c9ce29, 0x0185e366, 0x5771b023, 0xe2633679, 0x1ff0f222, 0x53737348, 0x991eb5c3, 0xbc04989a, 0xf1e6d09f, + 0xf83e098c, 0x417e19b8, 0x2aa78e9f, 0x06bf7ab2, 0xb21c1e34, 0xf320cd91, 0xbfb969f8, 0x3c4fcf63, 0x1dca9d73, + 0x43d2a3ab, 0x647c9599, 0x81eb1f48, 0x4a01014c, 0x453b7c30, 0x690c5add, 0x72776bb0, 0xe7dd3f8a, 0x152fd9fe, + 0x9e3645e7, 0xd3b48d8c, 0xb17bfa4a, 0x0072311f, 0xf17c0700, 0x1fb97aa5, 0x09e8075c, 0x5d306c3e, 0x05ca993f, + 0x5ac53ed8, 0x9316f076, 0xb0602f1d, 0xe6dffff2, 0xae594b03, 0x027b3b38, 0xa2bffd11, 0x9478b9db, 0x2fc44461, + 0x59122616, 0x6a1b7dca, 0xde6c41e9, 0xab1ec5f3, 0x643288b7, 0xadfad6b8, 0x0c15bbcf, 0x12b1ad95, 0xb254d326, + 0xfdb89d29, 0x93e4b567, 0x44afb061, 0xb831ad51, 0x2312f2f9, 0xbba3bb95, 0x35cf28c7, 0xac25f405, 0xb10d0af5, + 0x3353230b, 0xa95dfb0e, 0x6277feb1, 0x7681d70d, 0x20546ec1, 0x13f24c7d, 0x129ec276, 0xda985af5, 0x4f85da77, + 0xda94c2e8, 0x4870007f, 0xbf8a5222, 0x2127d6c9, 0x2870afc0, 0xd7e67ea9, 0x4ac46282, 0xc5da708c, 0x37d841e5, + 0xa989a27e, 0x17dfa7a5, 0xbfa90ccd, 0x8fd79a4a, 0x23d62f6e, 0x37979719, 0x32bc7ec1, 0xb9a82c8e, 0x56ad0318, + 0xc29b9bc5, 0x765273d1, 0x898b39be, 0x2d38b973, 0x650f6ea5, 0xe86b14a1, 0x09502f9c, 0x9e5035a8, 0x3f91c270, + 0xdc6c9dc1, 0x4488596d, 0x0977606e, 0x88a67fd1, 0x9695927d, 0x90457005, 0x484f1747, 0x2c0a0d10, 0x93dc8e5f, + 0xa56bc296, 0x9516c84e, 0xd362ce9d, 0x9ef87a9e, 0xa5fa6b26, 0x080ccdc1, 0x5e3faec5, 0x0476e443, 0xdc8dd026, + 0xb5323252, 0x84900a3e, 0xb03c62a7, 0xb6cc9f12, 0xe840c549, 0x717917a4, 0xb5550303, 0x35e8b952, 0xb45ace31, + 0x477cebd9, 0x8c359150, 0x6087ba9c, 0x5a09f5b4, 0xe6ab14c6, 0x02070a67, 0xa65b98ac, 0xff1cd365, 0x3f38347e, + 0x29ff955a, 0xc220b458, 0xa11f6a72, 0x32bc8d26, 0x24f1394c, 0xf89049ba, 0x11c5b319, 0x722485e3, 0xe7503d0a, + 0x61509486, 0xcc0c6b79, 0xc9364bbd, 0x03c2ee43, 0x22fc7e39, 0x7f86e75b, 0xe39710ca, 0x27244313, 0x9e0567d7, + 0xb41024e9, 0xf90dd4de, 0x2e63b9c9, 0x50bb92a2, 0xe97bf5e1, 0x0d707596, 0x4275b4c9, 0xcbc5e68d, 0x06e630db, + 0x3a4fe90d, 0x7f59b237, 0x2ef8dad0, 0x6b2bef60, 0x78076f4e, 0x97e66059, 0xe587d8f6, 0x986a12f4, 0xd2d00d7e, + 0xf61777de, 0x7a7b76f9, 0xd6b309a4, 0x23d2f358, 0xa0520185, 0xf5286b7c, 0x4bea009f, 0x99664cc1, 0x8528df5d, + 0x9e4da86a, 0x04e6c326, 0x095f122d, 0xccd857f3, 0x7fe72432, 0x536f7764, 0x73470439, 0xf599e270, 0x426a7834, + 0xd9a4e98b, 0xc15feebb, 0x19f3b2da, 0x30e86eb6, 0xb7c56b97, 0x770f93e6, 0x92bef290, 0x28f73fff, 0xd2220128, + 0x076ece5a, 0x0ec4daf4, 0x187300c0, 0x2975f4b6, 0x3dd267d8, 0xdaa5b41d, 0x7831eb36, 0xb1a4c7e3, 0xa4ecc3b7, + 0x4fdb9a8d, 0xa8ea0ae3, 0xe321afc9, 0x3c2c4787, 0xf98cd29c, 0xb92aea02, 0x656b3dcc, 0x0827d3a1, 0xd5e6f525, + 0x62bafaab, 0xd9d25aa3, 0x1c2d597e, 0x986550e0, 0x2fa6e4e7, 0x1af147a2, 0x27de295d, 0xfe8f3594, 0x26506f07, + 0x328f42df, 0x75e51805, 0xdb87e0b8, 0x61a18f58, 0xe89effd2, 0xf4881dd8, 0x27f72a98, 0xf692177a, 0x2705c0c2, + 0x6ff2e500, 0x8c5e92aa, 0xab5eef79, 0x3afa9b15, 0x1cb149fe, 0xf9503371, 0xd94c54a2, 0xe5ccc5d9, 0xe34e6e57, + 0x3711dbc7, 0xf408d922, 0xdfd1ef4d, 0xffa311ee, 0xdfd58955, 0xa16808c3, 0x53ab7e4a, 0xd92473b3, 0x0d5424de, + 0xe0b20238, 0xabcea3f3, 0xb04e30c4, 0xec4e98cc, 0xb57eef91, 0x0cd55393, 0x8f4bc746, 0xfddb4e41, 0x79d1fd65, + 0xc03ccee8, 0x24728045, 0x52eedc5c, 0x0ddbd214, 0xc0593990, 0x3ac5586b, 0x1eedfb07, 0xfa4cbab5, 0xf1e6ce1b, + 0x1fc34bd2, 0xf3a13a8f, 0x7e30205f, 0xf6b13e02, 0x944dfe48, 0x0738c754, 0x9b06106e, 0x32963f39, 0xb9d2aeae, + 0xec1afe4f, 0xe73e68f5, 0x74883d36, 0xcf177c20, 0x223b2a02, 0xf3cddcfc, 0x7868e4dd, 0xa768b562, 0xd5031bfc, + 0x12e77cd5, 0x502f298f, 0x44b3abcb, 0xd3f6ec9b, 0xbf2619a7, 0x05269f4b, 0x777e551b, 0x8c0e065f, 0xcb3a6ac0, + 0x9b4dc166, 0xa9c588d9, 0x371fa74c, 0xd62a22fb, 0xae0c5a47, 0x77f5ef13, 0xebc76941, 0x0cabddf9, 0xfaeed607, + 0xbe8137e7, 0xf363eab1, 0x807f5d2d, 0x1a146c46, 0x008a6dba, 0x45ccc4e8, 0x2de3f04a, 0xb4e18239, 0x13e81ad4, + 0x82ee8299, 0xf0fa3e43, 0x122c403d, 0x61892c23, 0xa0ab9aba, 0x88b39adc, 0x4ab1e527, 0xa75ac047, 0xd4dc4d81, + 0x696117ae, 0xd818ad71, 0xb5a6c036, 0x610bc05f, 0xdfcd83e8, 0x21fcbda2, 0xbf2c221a, 0xbb0525f9, 0x5a6989c1, + 0xe880157b, 0xbb7f276e, 0x20a1fdd2, 0xa6812ed3, 0xd13d7eab, 0x40d61c52, 0x310cb149, 0xc26c88f0, 0xd2241692, + 0x7d99493c, 0x0938c28f, 0xe476b844, 0x43030cfd, 0x334729e6, 0xe0a346ac, 0xb4e68f77, 0xc85ad5f6, 0xef6cd2ab, + 0x3fe20fbc, 0x9ca2d45b, 0x0f68a137, 0xa71f8fdd, 0xf443a169, 0x0b02a297, 0xdb363f4a, 0xc1f3167c, 0x8b99ff81, + 0xde434d96, 0xaabfc64c, 0xa0924daf, 0x60213253, 0xd937bc48, 0xcfcd94b9, 0x2596fe45, 0xafb966f7, 0xf61cba3e, + 0xaac6f205, 0x910d5f8b, 0xfd267775, 0x6a7e4a2f, 0xcd25616e, 0xd0a9ee78, 0x7fce6207, 0x7ac0761b, 0x79bc24d1, + 0xbec337f5, 0x81b0d9c9, 0x9ba9c36a, 0x6f238a99, 0x3fea9218, 0x0b006f7a, 0x14a45ff8, 0x4e036da0, 0xc7f0da8f, + 0x59fc984a, 0x0b4c4541, 0x6e473a77, 0xaef60855, 0xf13f097a, 0x6bbcb8da, 0x89cc2ee1, 0xe0de81c9, 0xf417904b, + 0xb3cd27d7, 0xfcdbf100, 0x4a9a5921, 0x7fa3596a, 0x373714a6, 0x8cc8d71e, 0x148f9d9f, 0x15fd94ee, 0xc18177f2, + 0xa430dcba, 0x86f2a07c, 0x2115b507, 0x71efba00, 0xa291cc73, 0x6a1e0ab1, 0x854ea040, 0xc45602ce, 0xe1732f44, + 0xb024418c, 0x9af402f8, 0x585afdc0, 0x36f62036, 0x9ad613ff, 0x548356c0, 0x5a73fa9d, 0xc9db3277, 0x379a2260, + 0x3d89549e, 0xb7d85b28, 0x7b5bf551, 0x3ed6c76a, 0x284c523f, 0x1559851c, 0xd5f5d86c, 0xf1174de6, 0x90e9b60d, + 0x35c8ec41, 0x639ddce5, 0x3eb0c15f, 0xe8714e99, 0x489f4cea, 0xb3387884, 0x7c8f0b1f, 0xd518f5f1, 0xeca813ae, + 0x342b4c5b, 0x101b109c, 0xe31cc8fc, 0x785e90e7, 0xa0cccaab, 0x1462769e, 0x56521158, 0x4a45d9fe, 0xe1da54fe, + 0xdb8565aa, 0x51a47015, 0x28e80fc6, 0x9432e736, 0xd7ca67f5, 0x9d724a56, 0x863c5251, 0xbc0faf98, 0x1ec0141a, + 0x3ec74b5f, 0x190ea310, 0xbd8ac0ec, 0x250e8b36, 0x5311d533, 0xfa2526b5, 0x9ad564d4, 0x975b0566, 0x60552a05, + 0xb4fc153d, 0x37773bac, 0xfe57b4fd, 0x0cd2e6ba, 0xef0e214d, 0xb846d36e, 0x74b7282f, 0x79ba7aca, 0xd29480eb, + 0xbb5900d0, 0x77c01fce, 0xd0af32cf, 0x63b0456c, 0x355d80d5, 0x23b8bc56, 0xb2b89eb7, 0x78931546, 0xcd3bc402, + 0x64c0a3bb, 0x578ca239, 0x2b3798f5, 0x03c39006, 0xc7bb65d6, 0xaaa37277, 0xabcad297, 0xd6a609b2, 0xd8092a1b, + 0xf55d3c07, 0x4218f997, 0xdb9a086e, 0xf9288d6c, 0x3abde10d, 0xc1c5d5ba, 0xee7f9bf6, 0x643783e7, 0x8814ef76, + 0xae46bae3, 0x00a8c871, 0xdeace1f4, 0x27642af0, 0xea17b16d, 0xb493987b, 0x9e02d7fd, 0x9fb45536, 0x09ac0a64, + 0x371c2ac1, 0x4abe62a5, 0x5a1b7fbc, 0xa5fb9e8d, 0xc18fb595, 0x601519d7, 0x43f3092f, 0xc41cb43d, 0xd16adeea, + 0xe76d39cf, 0x0a282380, 0xa8858346, 0x9ce1198a, 0x76c4e741, 0xb9ebbf9c, 0xdb8b2de9, 0x2d669422, 0x4ed15c26, + 0x3ac2fbcb, 0x2c143a76, 0x4b6b3151, 0x9a141d45, 0xf1c2bd45, 0x7a754a27, 0x5b9bed69, 0x2658ef68, 0x7be749d2, + 0x054deb07, 0x569c63bb, 0x38fa7ca5, 0x5aadee45, 0xbd6d249d, 0x796ef4aa, 0xc5ed56ca, 0xe30b9f9b, 0x71ffc905, + 0x1c69cdf2, 0xfe4d2c87, 0xc4580cd1, 0x5fa4e796, 0x7166fdf5, 0x4787978e, 0xdbe966cc, 0xdc4b00e0, 0xd144cb32, + 0x620eac73, 0x773fea39, 0x6674392c, 0x7fe0aa17, 0x8db661ae, 0x855356a4, 0x2ccdbc1b, 0x9049292c, 0xd5431415, + 0x43c9dc05, 0x618457d8, 0xfed57c68, 0x234b64f5, 0xc7f96be6, 0x2aa4ed58, 0xacd11fa7, 0x6a6cd08f, 0x16063d66, + 0x46b96c6e, 0xd1a4393d, 0xa9f2b8e7, 0x3525bc1d, 0xa544ca8d, 0xc3625451, 0x44d22ff8, 0x2372ed71, 0xa72e5d80, + 0x250e6b63, 0x26141a8b, 0xa26c3506, 0x60806848, 0x8c9e60e1, 0x299df15d, 0xc62fd807, 0xe43f19cc, 0xa338761b, + 0x78d3d2d8, 0xcc37e9d0, 0x005de7c3, 0x30cbdb1d, 0x225e5a22, 0x85872903, 0x76c26737, 0x3d844c71, 0x68ac1977, + 0xe0faf281, 0x853b1b06, 0xb624436e, 0x90ebac2a, 0x880f55e4, 0xe4f003dd, 0x16d9b234, 0x3dbf3236, 0x552096c4, + 0xdb9238b1, 0x5e00642c, 0x508c752b, 0xf2c031ec, 0x68f1aeb7, 0x9406b639, 0x0bd3c94f, 0x549e8a01, 0x1e3fdc73, + 0x79a0873e, 0x5f103f4c, 0x23ef0547, 0xa70f6e57, 0xdd0cb98a, 0x4bc89952, 0x434bca6a, 0x8087e6d5, 0xbaee7173, + 0x106590a5, 0x05107a51, 0xa2aad577, 0x1982c0e5, 0x8de679b1, 0x3f710267, 0x69a040fd, 0xecc5d779, 0x90d1e228, + 0x90be30dd, 0xe01ef43c, 0x2f92418d, 0xee6f4258, 0xa146a849, 0x6c79e1f9, 0xbce334d5, 0x4df58dfa, 0xd15e3697, + 0x41b0f326, 0x8e55d836, 0x3d8e9862, 0xba1a2936, 0x294326aa, 0x6e669b73, 0xf74bf8d8, 0x7a4572d9, 0x59266468, + 0x40079584, 0xa6918fd1, 0x181fef85, 0x0e4d0dde, 0x335bc1db, 0xe6809500, 0xda3a1b5b, 0x0ef252f7, 0x130c1852, + 0x60700b83, 0x7e7b74f2, 0xd2575b95, 0xb29c929c, 0x430ac798, 0xc61d426c, 0xb900c77d, 0xa78d6dca, 0xe278b5dc, + 0xc86a0d9b, 0x2290ddad, 0x06cb8776, 0x71f767cb, 0x4196bcaa, 0x157b348f, 0xee17bdc4, 0x25ed5ed3, 0x77e5c699, + 0x70170e76, 0xed5b17d4, 0xf9a0cbf8, 0x2830ff51, 0x038d0b22, 0x7419d989, 0x5f7efedc, 0x3e9c4e76, 0x5d8c7b80, + 0x1fa1c5fc, 0xfb63bc87, 0xbd006614, 0x650cd6f3, 0x8ca8a06f, 0xe8ca5080, 0x56467f2f, 0xf7b7d6c1, 0xc03df18c, + 0x50942e7e, 0xf84c9955, 0xd07a9663, 0xd3d5ceb5, 0xf7e26b76, 0x76344575, 0x5bb66a83, 0x8a4ec7f4, 0x648c5dc6, + 0x7ac01b41, 0x97c98017, 0x4ae02a53, 0x329e2e67, 0xb16a7dcb, 0x7f1cbe8c, 0xe73fed00, 0xb9e9ab73, 0x12a88197, + 0xbeea9460, 0x622eb776, 0x94a0b9e8, 0x7ec376e1, 0xcd084159, 0x61cb73d5, 0x89cda37f, 0x83a52a80, 0x264e0add, + 0x33853f0b, 0x59f3cf40, 0xc9992e34, 0x65a8338e, 0x513b81a1, 0x981c2a1b, 0x5714c3fa, 0x8ba50022, 0x5b092cc1, + 0x19166515, 0x012fa1d9, 0xc1bb326f, 0x65685c5d, 0x394e5b1e, 0x7b15a3b7, 0xa3697012, 0xc9376c5c, 0x0a91a639, + 0x74e9d45f, 0x5c443925, 0xa423bed0, 0x2b75682d, 0x27d31d9c, 0xdbd2af18, 0x42aa83b1, 0x623153c7, 0x471c2e01, + 0x6fbb57fb, 0x071ba604, 0x0046c546, 0xd0d54b2d, 0x5db413b3, 0x1b42d56d, 0xc5850946, 0x473aac17, 0xba0c3427, + 0x533a2f15, 0x0a008254, 0x60866b2a, 0x6c145494, 0xd3452cbf, 0xd785439b, 0xd0f1e0fb, 0x0855b32d, 0x88b221f8, + 0x13fd1a8e, 0xf2d21474, 0x6dad3cff, 0xb3379f8c, 0xac3aa0c7, 0xb8373279, 0x35ca9579, 0x25110c11, 0x6530fc9a, + 0xcfc26fdb, 0xad1f8d5f, 0x92ff751d, 0x50d94cec, 0x7332a808, 0x8f2d16cb, 0xd56f1517, 0xfa629a31, 0x70c6d39b, + 0x6551144a, 0x0002c2e7, 0xfcd4b6fa, 0x9dda93ed, 0xfc260b82, 0xd6bf8de8, 0xb3dadb26, 0xb42082ed, 0xe20d9ff4, + 0x0079a5e6, 0xa46a567a, 0xfdcac546, 0x6847e911, 0x648c2805, 0xacff1962, 0x8116e8e3, 0x2d686caa, 0x703f33c5, + 0xf6af5144, 0x751705a7, 0xf4477044, 0x1954e114, 0x5d30c4f5, 0xd6beaba4, 0x1efd8d09, 0x06f8616b, 0xf1d79d35, + 0x7edf4f59, 0x14b1f652, 0xcd756210, 0xf6c535de, 0xf188dc88, 0x9832142d, 0x258735e3, 0x3967dbab, 0xb0bb5871, + 0x35514dd2, 0xee9729f5, 0x30ea04f0, 0xb39bba70, 0x0dd24be4, 0x2f06e497, 0x0da4d956, 0x82f5c7a2, 0xff84fe87, + 0x74afcb44, 0x7f6c051c, 0x7d1234b8, 0x59aceb3c, 0x7a45aee4, 0xb3ae9956, 0xbc50d348, 0x8333f3d9, 0x14f8aa4f, + 0xbdd94f32, 0xe29ecdc8, 0x0f645412, 0xf5515cf7, 0xaad6b7ba, 0xd7ddbfb5, 0xf0c38818, 0x8677c7d3, 0x0c2a0caf, + 0x81de263d, 0x246c77a8, 0xf3a14c72, 0xe13bd947, 0x06c04661, 0x4a655c0e, 0xb18be311, 0x21037d9d, 0x13c0ab31, + 0x61addfd5, 0x055afc9f, 0x56a38820, 0x6777ac50, 0x19b3855f, 0x687d48c8, 0xd31e2c4e, 0xf29c996a, 0x3f7f2220, + 0xd3824469, 0x13bb56dc, 0xc9770cae, 0xce56bed0, 0xe926623a, 0x8a143167, 0xeccdd4fd, 0x1fc2f38c, 0x672b3ae7, + 0x8315e7a9, 0xa6dadf59, 0x2e30c306, 0x8bccc36c, 0x4bbd6667, 0xd096a028, 0x1e551089, 0xb81db1cc, 0xf6e0fb2a, + 0x67b8e752, 0xee3060db, 0x33a6d0c4, 0x2b81e08a, 0x84bf0ed8, 0x793a3d8d, 0xeed9033e, 0xb30b1f0f, 0x1f44a5e8, + 0x0d3f9a9c, 0x91ec5be8, 0xefba9b1a, 0xb227b3dd, 0x8cf8332e, 0x9df73191, 0x03f408fc, 0xc99aed69, 0xb6607920, + 0xda21abf2, 0x50b48fd3, 0x110b493e, 0x5b60131b, 0x06581ca3, 0xec50c276, 0x8ab4bf71, 0x05a72064, 0x73b89fa7, + 0xac433601, 0xef3f100e, 0x4532aefb, 0x4843547b, 0x8884065b, 0xe2f0ae77, 0xfa92120b, 0x6a6a6c3f, 0x08a67037, + 0x87673ade, 0x1dec1c4b, 0xefba45e9, 0xac9d5116, 0x9ace7013, 0x3de885d4, 0x36981df7, 0x5bb78e6f, 0x0375bad0, + 0x866916ae, 0xc8af9273, 0x50716161, 0xde46d5f6, 0x84231d6a, 0x2711a758, 0x300bb668, 0xdfc7c8a9, 0x4bed2e53, + 0xfe09a65f, 0x0087cbaf, 0x9e1e5c98, 0x9dcd758d, 0x4c2fef6d, 0x081ac5ed, 0x74769157, 0xa4e18826, 0x25aa8b02, + 0xb6fa9f34, 0x613cffc4, 0xe5feea07, 0x3fd4eb0d, 0x4b166e3f, 0x553870b2, 0x5ac1d156, 0x68a86b95, 0x3c60a367, + 0x78b32c4f, 0xe178a60f, 0xadae1c1e, 0xe67398ec, 0x67aacaf6, 0x42f2f31e, 0xa64d641d, 0xf78c5882, 0x12b51e84, + 0x79627226, 0xae96257a, 0xc890e982, 0x2fee2c66, 0x0c70c8ec, 0x121aa467, 0x973cc360, 0xcdaa5d45, 0xc3b903be, + 0x4a639d41, 0x158e1a6b, 0x20a1c63c, 0x656b2f90, 0x1df38d9d, 0xb8d058f4, 0x416121be, 0x645d3dfd, 0x510381aa, + 0xa368eaac, 0xcc714291, 0x1f654895, 0x92624c62, 0x6abf2a0f, 0xaff2567a, 0xdb1de947, 0xeaa19564, 0xe2cc3b4a, + 0x688b6443, 0x59a7a780, 0x4bef41c3, 0xe5dcff6a, 0x2ef5a37e, 0x30af737e, 0xb6dd8c05, 0x894fa7ab, 0x69660973, + 0xbf31f534, 0xe1a55e00, 0x1f4ca599, 0xaf168399, 0xf83d4e01, 0x30880c20, 0xc459171d, 0xa90d0244, 0xbadc0358, + 0x50eda17f, 0xff006e0b, 0xb086968f, 0x3f3005a0, 0x27d4c665, 0xc1916687, 0x660d96cf, 0x429ce359, 0xdd5351a5, + 0xb78f9e18, 0x6fe062bb, 0x73dd62f6, 0x9963cc18, 0x7d179c81, 0xcab796ad, 0xb5a399d6, 0xa7cf2f49, 0x213693e1, + 0xc5a8a31f, 0x6c204b52, 0xad2e8d47, 0x2e61f302, 0xd5deb7db, 0x2752434f, 0x1c794e81, 0x5f5b259a, 0xaf6413b2, + 0xeffe38e2, 0x8800a4b1, 0xf0287141, 0x9226b5d1, 0xb8cbac1e, 0x4d8fe457, 0x7057864e, 0x2343299f, 0x3bc73630, + 0xd2182d76, 0x23dc3606, 0x36a9334e, 0x892d3aa7, 0x83d25a6e, 0x3b9aeedd, 0x1e69f64a, 0xa00dcc9b, 0x2b6a2b3f, + 0x451e54b3, 0xcb636209, 0x0af90dfd, 0x164859dd, 0xdd562399, 0x75b6d4d5, 0x7235fb92, 0xda740f57, 0xd98ac16a, + 0xd57f99a5, 0x18ecb131, 0xb658e8c6, 0xb5245c0e, 0xadedd267, 0x3b0b62b3, 0x57ca74bd, 0xf259fce7, 0x6ee45478, + 0xb550a294, 0x6d455754, 0x9fa401ec, 0xe4d6bbe6, 0xdbaa261c, 0xf5c2e8a2, 0x5198bba8, 0xf15603a2, 0xe72b3fff, + 0x4bc18542, 0x98eaeffb, 0xa4c5522d, 0xb925eede, 0x8e290859, 0xfd47cf48, 0x1c660137, 0x6d2fff84, 0x3efaa895, + 0x6fca9113, 0xdad3025c, 0xa1ca2bac, 0x5ffd129b, 0x20fc5793, 0x18d9f34a, 0x06e8ffbf, 0x18b2443e, 0x493cac38, + 0x4d105efd, 0x72f1fa62, 0x33db4320, 0x4522e7db, 0x95491398, 0x4f658823, 0xc6e3e629, 0x3ced30fe, 0xc22625ed, + 0xff5592dd, 0x2ee5884e, 0xf6bff1b7, 0x123b9298, 0x0d5c67b8, 0xed663539, 0x03dbd3a1, 0xd03d24c2, 0xe8944f04, + 0x8a2dd6c0, 0x6a348a9e, 0x4c4c47b0, 0x3a0d1019, 0x8a92f21f, 0xb0d43666, 0xb24ee43d, 0xe3f1db41, 0xccdd889e, + 0xbccac5b4, 0xf0a8d311, 0x3c629622, 0xbed5d533, 0xfb3f4da8, 0x41831932, 0xfcd01fd4, 0x9e19f1f9, 0x9988fb8f, + 0xf3ea08d8, 0x35edf35d, 0x712597f2, 0xffa687a9, 0xcc26dead, 0xc6b38185, 0x7ddd900e, 0x3fa8aeb0, 0x93bee390, + 0xd0dc23b6, 0xb52e4ed2, 0xb004862a, 0xddae9f7a, 0x07802188, 0xbc7f7bad, 0x30dd419d, 0x4aea5152, 0x2a7a146d, + 0xaf74eefe, 0x280ff9bd, 0x613f8863, 0x4705e44a, 0x1de993d7, 0x65ddb3b3, 0xba134e10, 0xc4d37308, 0x2b4fd802, + 0x9e6bedce, 0x39a798ab, 0x3f00c7df, 0xd5fb924a, 0x308c99a3, 0x5ec3bebb, 0x97c030e5, 0xa10c6060, 0x84936c6f, + 0x1ddd5ec2, 0xed353975, 0x15018372, 0xa0e23a95, 0x9ec4c5e9, 0xd195c12a, 0x4c4a867e, 0x99cd58ea, 0x48f5c7fb, + 0x7a43e82b, 0x508cd7e4, 0xe69caecb, 0x50eeda9b, 0xa629a26f, 0x6a3b4194, 0x93f599f8, 0xf29305bb, 0x5e56b3fd, + 0x7e49e2e1, 0x81311975, 0x6d007df9, 0x4cf212a0, 0xc9e5f4ef, 0xe56d2a40, 0x1cf0f152, 0x031a682c, 0xf202e7c3, + 0xc098100f, 0x623e06e7, 0x4d3819a5, 0xe82b4320, 0x1b88ca32, 0x27011b9d, 0x953600b7, 0xee3909a4, 0x405af5bc, + 0xb729605c, 0x894961b8, 0x9d65e9c2, 0x9c9c93d5, 0x5b544972, 0xf3579f7a, 0x55f9b788, 0xb07de435, 0x52d6906a, + 0x9964c600, 0x0b64a5a3, 0x22fcefdb, 0x22821037, 0x3d802a2a, 0xa6f8398a, 0xdec5d1c6, 0xdf0e41c5, 0x3290fe8e, + 0x6fa13bad, 0x415f70d7, 0x7ae462e4, 0xa384fa45, 0x5be976e5, 0xc9080a07, 0xce89e580, 0x81935b39, 0x1d31b369, + 0x1ac4515f, 0xcae6900a, 0x8c1b9990, 0x892238eb, 0x834336d2, 0xb66c2fba, 0x9681fa73, 0x0a44b1e3, 0xd3454f8a, + 0x612be583, 0xe1e7f3f8, 0x1aa936ad, 0x66c2b141, 0xe0d49c76, 0xe17ba5db, 0x27d377d9, 0x2915d96d, 0xf3b54ae4, + 0x3d64a522, 0xb2ea3d49, 0x98e3159e, 0xff57bdaf, 0x14537823, 0xe10e13a2, 0xee64a081, 0x963391fc, 0x745f461f, + 0xc9d4f4fa, 0x43fbb857, 0x3d0d822a, 0x5a48b945, 0x7c0f9fc8, 0x7c1026a5, 0x2d95e551, 0x5accefc7, 0x5021b23a, + 0x55ca9c03, 0xa6377d37, 0x535d9cfc, 0x46acd289, 0x7cd71e54, 0xdf8976be, 0x04de3ad0, 0xd666cdb9, 0xffec5803, + 0xb3bfe85e, 0xda1c934d, 0x5d2e4fcb, 0xb8bb2955, 0x54190ee4, 0xe3eb83da, 0xdabe722f, 0x566949a2, 0x70f74efc, + 0x60a4cdf9, 0x55036bbc, 0x7e1574ea, 0x845d0667, 0xdf6beef8, 0xaa8d4e5f, 0xa36f9b06, 0xc18e69cd, 0xc469c9ad, + 0x9d3a1942, 0x69258de3, 0xa26a997c, 0x83421043, 0xc31c2fa8, 0x7687694c, 0xdb4959eb, 0x49d0095f, 0x43f506df, + 0xdb087f54, 0xe13d393d, 0xfe7ee64c, 0xe2796ad3, 0x0603541d, 0x0437b403, 0x7bd91116, 0x6870978e, 0xa423baf8, + 0x1ac32b4b, 0xf58e5c18, 0xb760bdf2, 0x53e20969, 0xb61084db, 0x33bd9ff3, 0xb46f48f9, 0x36861543, 0xb57f964e, + 0x87859492, 0xe187a9e0, 0xc7a00727, 0x1cc61f17, 0x9e4818e2, 0xbee110b1, 0x7ee115d8, 0xcb529d54, 0xb3ee57cc, + 0xbe80f0b8, 0xb9e86f6d, 0x4c889b0d, 0xd5bba80d, 0xbcc56ff7, 0xcc23fc8c, 0xf950df67, 0xfa365577, 0xf7bceffa, + 0x7a66a559, 0x3f746d94, 0x3a765e07, 0xcb8ea382, 0x835ecfce, 0xca36f3e7, 0xf88de298, 0x3059f752, 0x7f9573db, + 0x4b351d4d, 0xa9004ee1, 0x706ac6d6, 0x8a930543, 0x5f5ba8e6, 0x951dc1ee, 0x0f912313, 0xc95adcc6, 0x17cb6949, + 0xd5b141e0, 0xa28edc71, 0x2ea16b58, 0xd97ca4eb, 0xf28dc1cf, 0x870e9b4c, 0xc3f197c9, 0x45500b2e, 0x8e49a5e8, + 0xc02b43d0, 0xa1a67a6a, 0x0c5aa028, 0x857b4fbb, 0x9056b1a5, 0x5829f801, 0x1be86901, 0x6fa723e5, 0x36b4765b, + 0xae993b59, 0x1b8c17bf, 0x98433047, 0x7d34ff4f, 0xc4329364, 0x79c3a378, 0xd3f0f08c, 0xa619bef5, 0x6f83e4c8, + 0x5c38c3f8, 0x3acbc1ee, 0x2de4457d, 0xb7c4a265, 0x13cf8e75, 0xd66e1d75, 0x250823c6, 0x540cb3f7, 0xd2a8995d, + 0xc8f8fdcd, 0x239b224f, 0x588b81db, 0xe37ad206, 0x984d37d8, 0x61a9bc69, 0xce43a15b, 0x4329a9c1, 0xccc51374, + 0x0603f20a, 0x3c9ecef3, 0x66a2f358, 0x8a1f895d, 0xd98760be, 0x5c932fc6, 0xc38c3a64, 0xe3ae10b8, 0x7f29d9ac, + 0xba1ab20e, 0x2a0f3f12, 0x2ca63189, 0xc76fef7e, 0xda7dee73, 0xaa0d84eb, 0xea0db132, 0x871aec35, 0xe10fe96c, + 0x0e9b59c5, 0x98b44e1f, 0x1e96908e, 0x58c2b6f2, 0x16d4f959, 0x4c38cf12, 0x0c7c8402, 0x365b1d21, 0x5211eb3d, + 0x3577b70c, 0xbc3c34c9, 0x7227be4a, 0x8538c510, 0x802b0e76, 0xa326db1f, 0xa52ffdbf, 0x3d623ed2, 0xfaaadd4c, + 0x5ef3bc75, 0xb597ac85, 0xa7b5fe5f, 0x5c0af598, 0x3efdbc26, 0xb6ee884c, 0x15b5572b, 0xd60faa92, 0x27c643a2, + 0x0b948022, 0x7d9d5097, 0x27c9a3fc, 0x15a8aead, 0x3cb64b33, 0x404831dd, 0xa841c11e, 0x35836480, 0xe258ae90, + 0x1ebab2a6, 0x8ed833de, 0x834bb799, 0x193f6782, 0x92cd554d, 0x222edf42, 0x6e5e0c44, 0x56948394, 0xe9e75bd4, + 0xdd8e7724, 0x2d989bfe, 0x5125859d, 0x5f8487a2, 0x59ac1411, 0x82f6f8da, 0x216c87c2, 0xd63e0db0, 0x329ff1da, + 0x1693f473, 0xd719f15b, 0x873d3ffe, 0xf50efab5, 0xc2427131, 0x38bddab2, 0xd6824564, 0x2f9ff9a3, 0x3b6d8c9d, + 0xf644bab5, 0x5bf2f06e, 0xccd9abf7, 0x52c4c2d4, 0x930fe1bc, 0x0acdf2e0, 0x4083a37a, 0xcb81f8aa, 0x823d7679, + 0x788d3cab, 0xf1996fda, 0x09d5110a, 0xb7f3944f, 0x3faddbb6, 0x79944361, 0xeb3a6145, 0x515a4ca0, 0xc98a5a51, + 0x47d5a25b, 0x9106e4c9, 0x0d89e08a, 0xd6a2ba64, 0x346ba7d7, 0x9de49a34, 0x13dbfc07, 0x0592a9c0, 0xcbbce7d8, + 0x60514b7f, 0xbe548499, 0xc776ca54, 0x7510e322, 0xe9548759, 0x270b22d4, 0xee012abe, 0x7693bf18, 0x755d01de, + 0x7f600855, 0x657301c3, 0x113659af, 0x22ae794c, 0xb281dfea, 0xabe3d8d8, 0xc4a26c63, 0xb1d26f03, 0x13db9566, + 0x78771329, 0x39c2af6f, 0x74e1f2e3, 0x881ec1c1, 0x45801dbe, 0x3996e828, 0x65cbec35, 0x795ab712, 0xb4a34047, + 0xb7e30f92, 0x71a19ee4, 0x7dbb0990, 0x303f302a, 0xfbfd2e6b, 0xb9b7c016, 0x9e19d204, 0x55247424, 0x8abd9cd7, + 0x9d129438, 0x9385d0a2, 0xebca2209, 0x9fb2556d, 0x9814d003, 0x06af725b, 0xf6bd18e8, 0xb4faec20, 0xee072af8, + 0xc2cd6f6e, 0x0dab1637, 0x47ca0057, 0x19320ce3, 0xbc47c043, 0xbe5ea2c2, 0xbced9014, 0xddc0bd27, 0xee9309ee, + 0xc96d5152, 0xaa6f0066, 0xc47c6389, 0x1ab0d0de, 0xddd8ebb8, 0x3078cd02, 0x3aebf3ba, 0x74331b6e, 0x2518fd94, + 0xc642d185, 0x63d66002, 0x49d54820, 0x6498a3bc, 0x9313bc34, 0x7c3a61d0, 0xdd9a9491, 0x28c286fd, 0x717df4e9, + 0x1b667743, 0x0622b1d6, 0xfc936229, 0xeaac87a6, 0x2458117d, 0x5e77177a, 0x3bf26361, 0x5454a7ac, 0xece312cf, + 0xd7727213, 0xc2a08923, 0x6c3097f6, 0x8f675882, 0xa8a7fd2c, 0x11864974, 0xbbdb0567, 0x713ea781, 0x8c2b7019, + 0x5306982b, 0x7356cd91, 0xff28420f, 0xc9eb26ca, 0x345c052d, 0xb62435e2, 0xa70a92b9, 0x2c94446f, 0xf04bf777, + 0xf65b84ea, 0x1f2690ac, 0x21577051, 0xafeb5941, 0xfdc4341b, 0x004a4507, 0x93f2c30c, 0x26f6c4a4, 0x190e2313, + 0x51973b06, 0x270927a3, 0x86c71efc, 0x994a8a81, 0x24dffb0c, 0xa748409f, 0x1c0ce3e0, 0xca053e1e, 0xdb5ff3f0, + 0xfe8c90c5, 0xa8f255d6, 0x50aeecf4, 0x8b69b275, 0x5fc044cd, 0x3a4031a1, 0xfe0408df, 0xd588089b, 0xa0f67acf, + 0x36d200d5, 0x7ba5e9e7, 0x99f70b73, 0x0c13552a, 0xe3803f3a, 0x607435fc, 0xcf77459a, 0xd59f4c90, 0x3cc4b714, + 0xb8fe4877, 0xf40bd510, 0x0be0f998, 0xba2b2118, 0x636be3e5, 0xc352cb0f, 0x49976a9d, 0xcd9b6a05, 0xeb8318a0, + 0x2bd4cd6b, 0xb786fb1d, 0x1dbe1922, 0xd1bf68ea, 0x451822f0, 0x1b72015e, 0x747e57a5, 0xc6574659, 0xc45488cc, + 0x6b1006de, 0x48afeaa7, 0xf035b94f, 0xb3fb874a, 0xfa4fe3be, 0x79707642, 0x1ee0593d, 0x5898e56e, 0x313d69e4, + 0xc14bbce3, 0x1e1d5494, 0xc2d177fc, 0xed914a02, 0xbb518b35, 0x5c1ffa7f, 0xf4770577, 0xd3c14531, 0x5caef5f8, + 0x810184a0, 0x0ac5724c, 0x481c7083, 0xaca8ece0, 0x3a289e44, 0x67404882, 0x8914d6a6, 0x4c7e219c, 0x38dcd8e7, + 0x9a55d337, 0x01ec34c3, 0xdfbb5238, 0xe12e3961, 0x02688504, 0x6052fe31, 0xb88a3ce3, 0x17eb1133, 0x5e7944f4, + 0x2dad4ac4, 0xe7adc1e4, 0xd5446c49, 0x676e9f1a, 0xca355d1f, 0x8da2d4b5, 0xc0ba0973, 0x3a59d90f, 0xbe83c2eb, + 0x9232c70c, 0x5a5fd6d5, 0x2d63e563, 0x0b7c5c6b, 0x3e819c79, 0xe1a41ea3, 0x952653a3, 0xd1082a6b, 0x04b50eba, + 0xe9116032, 0xefe99297, 0x8396a692, 0xf48fdc66, 0x659725b3, 0x2ff350e2, 0xe72c34f9, 0x6eb75554, 0x2ca980de, + 0x7fe4915d, 0xef0c93f6, 0x8699a7a9, 0xb51c76cc, 0x94969ff1, 0xfc1898ec, 0x942c6958, 0xd3b0c2f5, 0x4aeeef25, + 0x2b198ed9, 0x6b374b85, 0x457a2d92, 0x39bf0b0f, 0x05737306, 0xff83ee76, 0xc3f724eb, 0x8a6b513e, 0xa89e0d86, + 0xad8a2eba, 0x2eee3efb, 0x844a18b7, 0x657acde1, 0x8e26d325, 0x34da59ff, 0x6d6bf1f0, 0xbed38ebf, 0xc3161d4c, + 0x1b18910f, 0x2ee8c7ed, 0x1f2e9465, 0x8ce35640, 0x363d5112, 0x915adbcc, 0xca146558, 0x5f73bc4a, 0xccdc3a86, + 0xf6d27b53, 0xd91aa908, 0x4b4ff8d8, 0x3978f5c4, 0x0d66c7bf, 0x207ea790, 0x20284809, 0xc73cc441, 0x08a4b6ec, + 0x9641dbbe, 0x305f939a, 0x3d1871ef, 0x81792361, 0xf73dc888, 0x13f763c1, 0x64e594e2, 0x6b037eaf, 0xec4b0e4d, + 0xdeb2963e, 0x33fc5e1e, 0xcd6a5976, 0x5463b42e, 0x5f6a6b57, 0x3ee1fa74, 0x9e33f131, 0x633eaf11, 0x5a97c21d, + 0x649beb61, 0x56613182, 0x3625f85d, 0x3f43cda1, 0x98d09f1e, 0x1f8d9555, 0x612310b5, 0xfc55aeee, 0xaefda3f9, + 0xc642e90c, 0x7a3624f6, 0x28af4800, 0xd706906f, 0x9893194a, 0xcef35a0c, 0xc294d40a, 0x038d548f, 0x5409d5ae, + 0x7f158a08, 0xc47c9bc9, 0x8c0991e5, 0xe37cf2e6, 0x0af795ae, 0x626da922, 0x87256b5d, 0x670609ba, 0x13737bb7, + 0xaee477d4, 0x1ff504d6, 0xffd7a32c, 0x93d6ca9e, 0x1cd2686c, 0x33e27ed1, 0x0f4fcdf8, 0xa2fd1b06, 0xc1c0fdef, + 0xed7f1599, 0x853ef548, 0xb8f6a78e, 0x8a63a8fb, 0xc46304bb, 0x307058c9, 0xbf19ffd9, 0x1fe88cf3, 0x11c327ea, + 0x4695cf5c, 0x26c54377, 0x66e186f7, 0x6c09ed64, 0x254cb167, 0x39a9ea73, 0x1a4c4d3f, 0xccab5b5c, 0x2991592f, + 0x5e0970cf, 0xe32044a0, 0x89b6b67d, 0xcf1d5076, 0x9bc75300, 0x81320170, 0x5ea2e674, 0x0893f6a0, 0xb592f227, + 0x7e708e44, 0xa39095e3, 0x00704963, 0x6571fdce, 0x867df625, 0x13ad7a53, 0x11c7162e, 0x6b100b85, 0xc3f73492, + 0x5a4a3583, 0x9ef1f274, 0xd52e6112, 0xd4844228, 0x60b5dd27, 0x5b1ef3d2, 0x1ea88ea5, 0xb2072490, 0xe7cb5ac9, + 0x18153659, 0xdc441bc1, 0xaf9602c0, 0x49a81359, 0xc0263844, 0x74b7471d, 0x430a1b40, 0xac9978bd, 0x7481d366, + 0x4fe743fd, 0xd278e609, 0xea4bb048, 0x41365a79, 0x40a5c4d0, 0xd9885685, 0xa32360c7, 0x5b73ff72, 0x22bb5587, + 0xa6aa38e9, 0x8e8ef5f8, 0xe8f21622, 0xae956990, 0x3fe1ae0c, 0xb7a5719c, 0x34cd73a8, 0x07888f9e, 0x08d6bfc1, + 0x17050f44, 0xa45466a8, 0x88022523, 0x9ccd6cd8, 0xfecbf243, 0x11a844f3, 0x3e75e77a, 0xc48d48f1, 0x3d4c3a5c, + 0xd7058fd6, 0xa6ca02d6, 0xa929b3d3, 0xa6e89089, 0xb740acc6, 0x97faaeb4, 0xe99219fc, 0xaf9a2936, 0x5900a829, + 0xa2fc74e0, 0x3ed00c3e, 0xc72c93be, 0xfc06c705, 0x36d3a358, 0x9d9ee3b6, 0x14a8d29d, 0xb56ebf9c, 0x94245768, + 0x5aaf1bb1, 0x99d98ddc, 0xabfe1dfe, 0xc5aea4be, 0xa8e8d0c6, 0xd8d8bae1, 0xa207d4e7, 0xff835ec3, 0xe3dbc3b1, + 0xee698e92, 0xc023e880, 0x493a3460, 0x6eee9f7b, 0xd32e8d7f, 0xe78298e7, 0xba5ac743, 0xba9eed98, 0x9ffca663, + 0x239801da, 0x82f6878a, 0xb0a73bbc, 0x705cefa1, 0x11339543, 0x3f5acf32, 0x653d0a19, 0x6fa6a98b, 0xa75e70ec, + 0x0deeb0de, 0xe2025919, 0xc27ea9a8, 0xbadba2d6, 0x2f10556c, 0xdaa498e8, 0x83c762d8, 0x621dc3a6, 0x8c47acaa, + 0xa9e9f32e, 0x1a10261d, 0x48016367, 0x6ba179c6, 0x38a8de91, 0xca074335, 0x01cc139f, 0x491b6efb, 0x7962d4a6, + 0x19db413e, 0xef50bf89, 0xdbb088aa, 0x90d2e002, 0xd69495c7, 0x76dc8b30, 0x5525c093, 0x6496f65e, 0x5c4d2a30, + 0x180c1ad8, 0x1c595f1e, 0xe4c7478e, 0xc7057307, 0x36d3204e, 0x8505c2bd, 0xfcf1cdc9, 0x64d6f7b9, 0x4d7da022, + 0x75840d1d, 0x3b0775c1, 0xda35aff4, 0x84d6b182, 0xc792e4f1, 0x80028b64, 0x54d7280f, 0xba3178f2, 0xa66f9d0c, + 0x816a2ed9, 0xc234a5c0, 0xd1fb9de6, 0x1ee166a4, 0xa1966197, 0x5640c93f, 0x12ec25ff, 0xe63921c6, 0x927edefe, + 0xebe59d9e, 0x9774acf0, 0x29cc5bb3, 0x68ecd77e, 0xa62835e1, 0xcabbf484, 0xf83967dc, 0x8798c821, 0x79389bfb, + 0xcaa15342, 0x663cbd4d, 0xea60a3b6, 0x1ad0a49b, 0x5a774815, 0x881d7201, 0x3e48296b, 0xb3a8da30, 0x4506e05f, + 0xc75d2b2d, 0x292408bc, 0x9c05fd49, 0xd92adcd6, 0x5e1e1686, 0x928b6ced, 0xdf1e8ed7, 0x833bcc6a, 0x620d3d3d, + 0xe83b37c3, 0xadd6f369, 0x6f84dbf0, 0x56f24fa0, 0x3dfd1d83, 0xed871e51, 0x9354e293, 0x5d124a7b, 0x1c3cd8b7, + 0x13d029c0, 0x8ccc03bd, 0x627d8f5d, 0xb05d75cd, 0xe99b59b1, 0xa4642de6, 0x0ad85a16, 0x12a7801f, 0xb7e1ed6b, + 0x50d0947c, 0x86a4a31d, 0x6dc9aaa1, 0x5b0e7cbd, 0x7ae9c9c5, 0xbd889343, 0x767b63ea, 0xd9d7f31c, 0x92d0efd9, + 0x0fb48994, 0x55b6ce16, 0x8a02b4a9, 0xbc1375ff, 0x7a9ccc0a, 0x87b6e3c0, 0x35b84fcd, 0x6b4b9f95, 0xd7c852b9, + 0x61ef72ad, 0x464b5d28, 0xf4c23dc5, 0x7eb9c05d, 0x6fe1b431, 0xa6b70692, 0xb18d3d69, 0x8b439513, 0x43b5c228, + 0x121157a4, 0x9dfdf7d8, 0x31aae6a9, 0x29fc90c8, 0x42893576, 0x6a3fb433, 0xac8d1284, 0x0762d0f7, 0x09fb40e1, + 0xcd8df215, 0x425ccbe7, 0x89290018, 0xddba01e9, 0x4ba0a356, 0x1f16ad85, 0x3b010cdd, 0x8d0d64ff, 0x58894b9c, + 0x1fcde0df, 0x3fbe92d6, 0x6b2b5239, 0xfe030cbd, 0xdca3643f, 0xc2bb8eca, 0xa9930fee, 0xca9a1da9, 0xf3f1e603, + 0xfc020fc4, 0x2db83b0b, 0xdcd2029e, 0xfb19bfbe, 0xeafe9cc0, 0x9320b5dc, 0xc5b4f77a, 0x69dbd592, 0x5c49ea20, + 0x9905a0e4, 0x775ba0db, 0x89f88238, 0x8d82827b, 0xbcae8922, 0xdcf8453e, 0xb844c6c5, 0xa657d54e, 0x766f16de, + 0x64b804db, 0xced6e2f7, 0x611cd1ca, 0xf71adfca, 0x3e28755c, 0x59f48e2e, 0x1b7ca5fe, 0x485e370f, 0x3d7f712d, + 0x172244ad, 0xa6e9e11e, 0x7b8a4889, 0x2a5db4c0, 0xb1495fd5, 0x30cc9eed, 0x6004b06c, 0x0906f93f, 0x59d80040, + 0x64196882, 0xd3313b0f, 0xa3cf4017, 0x6106c1bd, 0x97ca9097, 0x8085fd62, 0x5c65e6a2, 0x5ea3cb13, 0x9a8154c3, + 0x30b7f0b5, 0xba873045, 0x4b5f5d24, 0x2ee7a72d, 0xd6e7ec06, 0x35377bbe, 0x97d00de8, 0x4eb49374, 0x7131a27d, + 0xf3973e36, 0x1a005e3a, 0x9e9c8801, 0x61f05edf, 0xc67c5f48, 0x5a341c2e, 0xf1daf87e, 0x3bc20e60, 0x4538949b, + 0x13d8014b, 0x6cf66ac5, 0xcd2beb6c, 0x4533a412, 0xe9d94ff9, 0xd112812e, 0x34530d75, 0xa7fec233, 0x09b6e6f9, + 0x27d814e2, 0x99feec65, 0x4c5f0286, 0xf9eb5019, 0x74368044, 0x2102b284, 0xf090825e, 0xc1d055df, 0xe96f69ce, + 0x544c5518, 0xcb17a08e, 0xbbdbf48f, 0x460489e1, 0x91b74e0d, 0x34b8b0ad, 0x41d6b5b9, 0xebc0f564, 0x374b6a98, + 0xb1e72cbc, 0x00eca893, 0x2bf03c5a, 0x2a14ab19, 0x8443abfd, 0xb92e7919, 0xd1d8e254, 0xc1a25baa, 0xc3a1d545, + 0xe5144d61, 0x3bb69d3c, 0x2323c316, 0x980014e3, 0x2aee23f8, 0xd2314444, 0xd33e6a6e, 0xf1ad8532, 0xac6e886b, + 0x704f937d, 0x2cd298dd, 0xeb879c7e, 0x2ab5a049, 0x90c1a1ae, 0x6ad66c51, 0x3c1a64c6, 0x20935872, 0x2c0be4f6, + 0x18829f90, 0x0bdf301e, 0x7d9075a2, 0xdcf843ca, 0x66c36ad1, 0x22c484e3, 0xa6ae1a41, 0xf00c30b5, 0xecd08cb2, + 0x1a83d999, 0x9c201764, 0x025b1788, 0x3bc2fb68, 0xc871a946, 0xb49f56fa, 0xfcd63029, 0xb0bb7ae1, 0x28610426, + 0x03dc54ae, 0x977adf4f, 0x3ec72b03, 0x9862211f, 0xcf2abb46, 0x510c1c6d, 0x33e8f4bd, 0xe83cd447, 0xd8ac26ef, + 0x9a7ba2c7, 0x14883bff, 0x9986287f, 0x6ab045da, 0xcee145f2, 0x7d67d5e6, 0x4ce1e4b7, 0x5b60bf65, 0xe2c7175a, + 0x30e9a253, 0xb36858b5, 0x6ea603bd, 0x612a7f72, 0x7e695262, 0x14c28ed8, 0x79a86e83, 0x5fa27f29, 0x5f75d081, + 0x3439bf2e, 0x912d30af, 0x8f8c0cc6, 0xee9e983e, 0xf475675d, 0x6c36cd3a, 0x415ed071, 0x988d17e5, 0x50fc2dae, + 0xa19a72e4, 0x47e23234, 0x6709ff1f, 0x13adfa07, 0x880e322d, 0x0bced92c, 0xa12e0da2, 0x3564b2ea, 0xe8b979f8, + 0xf9eb9b46, 0xa33a1e7d, 0xff8d4c41, 0x56a9fe8e, 0x6e7cca91, 0x4d9bd018, 0xebc08afd, 0xa9070daf, 0x0a63069f, + 0x75087d77, 0x57b17957, 0xd2454352, 0x2629c2d7, 0xd522d80a, 0x7e803ccd, 0x74892d36, 0xdc63e412, 0x91f33be2, + 0xad126c03, 0x7f7ec3b7, 0xe02670f9, 0x6bae24e4, 0x0e142189, 0x48226520, 0xee6a4805, 0x0b4c504e, 0xb4b91009, + 0x9c7d1391, 0xbd1e424a, 0xe9d8d9f8, 0xa7d051f0, 0xdc9c665d, 0xc9d6ea77, 0x9fc8fba6, 0x56721681, 0x0b1f0f6f, + 0xfaaf1a6a, 0x9799903d, 0x990d19eb, 0xe4cdb9a5, 0xe967247e, 0x486337f9, 0x4d8699c6, 0x5eb59767, 0x18958d03, + 0x6185c123, 0xdbc8e58b, 0xf19a9599, 0x84228b3a, 0x91e8b513, 0x2ec574a1, 0x282d1824, 0xa981739d, 0x32aae2ef, + 0xd1709269, 0x7c35e419, 0x10db83e9, 0xe5b74d99, 0xa5bbf673, 0x0104cba1, 0xfcd69b55, 0x66635061, 0x21f9c37f, + 0x7322462b, 0x7da7c7a4, 0x0e94b6f3, 0xc4982956, 0x3676e41f, 0x2cb54a24, 0x55b3a731, 0x72c894b3, 0xf8907b07, + 0x9682e202, 0x837138a6, 0x41a0e3a7, 0x7d58028e, 0x3c773691, 0xe7969157, 0x0ecf4950, 0x9e76b498, 0xbf317c9b, + 0x575dee01, 0x79d909a5, 0xb2e43cca, 0x4702c188, 0x5cb4aaef, 0x2f3fde8f, 0xdb0822dc, 0x5de8712d, 0x5ace37c1, + 0x7e73f19b, 0x601e6d2a, 0x59f71c5e, 0x8b00d599, 0x3b301fea, 0x420f650f, 0xba0bf3c1, 0xc1133dd8, 0xad992c6f, + 0x578652f6, 0x3aebc876, 0x649b752b, 0x82e056bc, 0xa3247b82, 0xe2932b2f, 0x86972900, 0x7c6a140b, 0xb806951c, + 0x994810b8, 0xc1f603d6, 0xa6c67d82, 0x7aef4da1, 0xbe9d32b0, 0xc1a78f9d, 0xf2557e9c, 0xfab78b3e, 0xacc8252d, + 0xb2abfa3e, 0x92ca47da, 0x67e7ca25, 0xfc0694ac, 0x76aa9492, 0x065e1ced, 0xd83c39ee, 0x5f9407ea, 0xdb411e00, + 0x14c3d0e3, 0xb82cfb52, 0x5d791322, 0x1633603c, 0xae9cd724, 0x54cc84ea, 0xca171bc0, 0xc60ec6d9, 0x270062da, + 0x5829a8b3, 0x962aa20b, 0x615ba0af, 0x829f18de, 0x80f0f77a, 0x8710f680, 0xa2521993, 0xc7493806, 0xb79fa41e, + 0xae572c1f, 0x7fb7adae, 0x3569d6b7, 0xd5c8047b, 0xdb39f28d, 0x2a9a8901, 0xba3e071f, 0x7a6328ec, 0xf931c2ca, + 0x6427d6f5, 0x7a4aa21c, 0x320e2ec6, 0xee7aaaa1, 0x9afb97f1, 0xc04f55a5, 0x47620650, 0x573dcc05, 0xacb7c63c, + 0xdd90b7a8, 0x5e068f3a, 0x5a523dbf, 0x74ce70fa, 0x5303703c, 0x2ac65e26, 0xf0837e13, 0xc8412022, 0x101332d8, + 0x1b7204ee, 0x3169bd51, 0x3a466fe6, 0xde189903, 0x45c793d3, 0xc43f3d0e, 0xdea4438e, 0xc29e30c6, 0x16587746, + 0x60207b5a, 0xd73857d5, 0x3f95247e, 0x96a18def, 0x2e8c1afc, 0xdc293efb, 0xd27822ba, 0xcd57e3ec, 0xa4d9de82, + 0x11bec3d8, 0xf6e20d7c, 0xc94a51e0, 0x70199807, 0x3a0ee8c9, 0xe2454cc9, 0x6b4c24f4, 0xebf8f020, 0xdfbcdaf4, + 0x1cb45192, 0x59dd468d, 0xf78514c5, 0xc13d967a, 0x7e038a77, 0x465be566, 0x67221cba, 0x1c3bcf61, 0x2f9e57e9, + 0x1dee9402, 0xf2136886, 0xdae12dd8, 0xe4b20bd8, 0x36788343, 0xc17ad3cb, 0x51d8f05b, 0xaba289c4, 0x42968a9b, + 0x58bebef8, 0x50d7c122, 0x983edb89, 0x3c3071ec, 0x56616b34, 0x20d23625, 0x5812b3ab, 0xa9742c9e, 0x6ff4857c, + 0xd5d3f6b6, 0xb7f97e13, 0x9bf0fef6, 0x9edf7dfc, 0x72ceb868, 0x7266b5bb, 0x59b8c56d, 0xe7f1429e, 0x5ae54304, + 0xdad9a004, 0x284bcea4, 0x7a142695, 0xba2ad32a, 0x3b4de364, 0xc142e242, 0x2fac51f4, 0x106faa19, 0x353b70de, + 0x60170ba6, 0xf9025baa, 0x8abea04e, 0xa35cf1bd, 0x77cce584, 0xdd3c431c, 0x000132b8, 0x83ac455b, 0x7509b8dc, + 0xfe857ba2, 0x20456142, 0x9bd0bcd5, 0x6d061723, 0xb17cc6bb, 0xe8987e74, 0xcda947c5, 0x17dccc84, 0xbf0357e7, + 0xf21a5c8a, 0x3882cee8, 0x65b2ba16, 0x9ce762c9, 0x44d83c62, 0x989dafd9, 0x48b8d5df, 0x07e0332a, 0xeacaa9c5, + 0x41bd6306, 0x72fa5bfd, 0xce5ab0b6, 0x8406f009, 0x19c670df, 0xcebb8dea, 0x58e27b5f, 0x9ee06915, 0x047f4f11, + 0xbfc22674, 0xbc71fdfb, 0xd39c6795, 0x6b4ef012, 0x79c3f469, 0x3e0d9d79, 0x44fb7ea0, 0xe25b9b0f, 0x53117d57, + 0x75067dea, 0xc483d022, 0x1312909d, 0x8fc3753d, 0xeb82d1aa, 0x2bc6693a, 0x5955d3c0, 0x119a9f95, 0x7dbdaae8, + 0xb70d06a7, 0x00cf3a03, 0x2a8e7a67, 0x23d653d2, 0x5fef992e, 0x6061d7ee, 0xf77acd24, 0x4d241c1d, 0x1a0bb1e5, + 0xded554ff, 0xb24d4431, 0xd9c7d5c4, 0x433aa9b1, 0xa29d0529, 0x14fc1bb1, 0xadc86fd5, 0x218a083b, 0x5ba61007, + 0xcac5b628, 0x1d3a2a0d, 0x2d64b10e, 0xe65995cc, 0xd81a779b, 0x722f0421, 0x1ba253c7, 0xc45bd3f5, 0x8806761f, + 0x9d7d3bca, 0xff01f23e, 0xc4bfe109, 0xa575c417, 0x408fdc9c, 0xbbb199fe, 0x0b5df86d, 0x7c1239c1, 0xba776500, + 0xc0fcb62d, 0x62a4ea69, 0xffe0adbf, 0xcb02bcc5, 0x4a609143, 0x7f025ab2, 0x4842b29a, 0x9c00fda5, 0x2e8647f3, + 0xb908a04b, 0x0044e713, 0x891fbc8a, 0x5d473439, 0xc94bea7d, 0xd84edac3, 0x65640d9b, 0x059c98f9, 0xcc19a8f0, + 0x690b9058, 0x7a4e5b36, 0x762fa0f2, 0xd150177a, 0x65bad48c, 0x5b4dc037, 0x60f308d1, 0x1349901f, 0x2b574ccf, + 0x635ec015, 0x9d3a10c4, 0x3510e464, 0x635a3c0d, 0xd253d21a, 0x2cc98b56, 0x971bf54b, 0x01600fd4, 0xe6225c50, + 0x579745d5, 0x9ee7f34a, 0xac670263, 0x988b2913, 0xb8d16bc7, 0x7949d610, 0x95335ec5, 0x498a7734, 0xf3345df0, + 0xc266c247, 0xa9cfa091, 0xe4e28dab, 0xabef6f27, 0x33d84d65, 0xc4381f88, 0xfa8c8329, 0xbf3d00d9, 0x2d6b6d5e, + 0xb8c416dd, 0x3ac70083, 0x74391a30, 0xccd754fe, 0x191b86c0, 0x259b8639, 0xd2f452bd, 0x532987f5, 0xa27aa4f9, + 0xb2c995f2, 0x66eff244, 0x9b4c260c, 0x9f7cc4a2, 0xf5e83c9b, 0xe8961601, 0x66655481, 0x44e57a84, 0xae7a1ee5, + 0x7343cae2, 0x3f9533d6, 0xd9d0ed07, 0x4a7008fe, 0xc433b1c0, 0x36e27210, 0xdc846040, 0xe42341ca, 0x7ad2d55d, + 0x2eb53c01, 0x5b7a00f3, 0x4a42ab6a, 0x2c17319f, 0xa4c46cc1, 0x4a094d09, 0xa11e82ba, 0x5786d6c3, 0x47b0fbf6, + 0xac4c8473, 0xdf587348, 0x5399e695, 0x73ec2602, 0x835269b2, 0x06410e1a, 0x37762e54, 0xd3091753, 0x41a9c43d, + 0x6b9be8f9, 0x1e873d05, 0x8554f261, 0x5eca11c7, 0x465a8a13, 0x77983de6, 0x4ee1e333, 0x74cf35f9, 0xb14a54a0, + 0x88867b39, 0x2fdbe3ff, 0x8cd82732, 0x5ee285ad, 0xfff37f8f, 0xabde2faf, 0x7523c2bc, 0x611057a4, 0x0fef6692, + 0x5f30b17d, 0x85f56b65, 0x447d7487, 0xdd2c6e1e, 0xd715a8ea, 0x3ebdd446, 0xb211df39, 0xcf33abad, 0xc8a60e71, + 0x0ec2c329, 0xe19339fd, 0x0fbc6f81, 0x335b9b08, 0xe18fdef3, 0xc76f12bf, 0x50b2efe6, 0xea2ac51a, 0x5badef56, + 0x3af4849c, 0xf89029f9, 0x64c949f4, 0xfd5701f3, 0x7c7806ca, 0x9b6f6159, 0xa6d9da77, 0xc605fb13, 0x2a2286bd, + 0x5847314c, 0xd5c9080b, 0xd3957f04, 0x9793649f, 0x807aa143, 0xb465edd3, 0x542ffbc7, 0x18ad9d90, 0x8d15cf3b, + 0x16a40910, 0x9eb272e9, 0xe751ec0a, 0x69b0a027, 0x5b7ba90d, 0x6b5bed32, 0x5ae6c115, 0x1305aebf, 0xa45acf8c, + 0xef1b3157, 0x00d1dfbe, 0x1fab041e, 0x7a6732fe, 0xc7436bc9, 0x108c44f4, 0xef8c576b, 0x376a80e9, 0x34e5d21d, + 0xb4ead779, 0xb519a62a, 0xf2fea90b, 0x4f88eb02, 0xc1d7f82a, 0x414ff706, 0x387b75d5, 0x615782d2, 0xe7b5fa1a, + 0xd77982f4, 0x395a514d, 0x9578a9ef, 0xb28e85da, 0x95b56534, 0xaaee7167, 0xd0db8e2d, 0x9021d9cb, 0xb10782f3, + 0x645f0ad4, 0x44b2ec81, 0x3c49b966, 0x851cb966, 0xd87ca082, 0x2d5a612b, 0xee575b91, 0x5a33b99f, 0x12a2d5c8, + 0xa2c06fd9, 0x1bf5b91b, 0xbdd2d47f, 0xfab3b3bc, 0xacd991a3, 0xa3a6673f, 0xf6cacf91, 0x45708996, 0xd938cbca, + 0xdfbad12e, 0x255262b0, 0x70f3f074, 0xa11ab9bd, 0xdeff4d14, 0x3761f0a3, 0x6f6240d8, 0x19696552, 0x5d7c479b, + 0x7a8ee2d0, 0xb96a5bbc, 0x0ed71fcc, 0x6c01e9fa, 0xf93360e1, 0x04892b78, 0x91a8f6e3, 0xf9d2e847, 0x738aaf76, + 0x9c5239bc, 0xc56983e9, 0xce57b1fd, 0x4eb665e5, 0x75dade5a, 0xdf02f10c, 0xea573ac0, 0x1e93e039, 0xd28aadab, + 0x343e4caa, 0xc000176b, 0xc9928d5d, 0xab3f4cf7, 0x40ea131c, 0x7af65084, 0x4b9d26cd, 0x7235f4a5, 0x24659b0a, + 0x38666b5e, 0xc8dcd799, 0x511d3eff, 0x7c4c5ac4, 0x08a907e1, 0x667e7d0d, 0x9fb242b7, 0xbc6d09aa, 0xf9cc5924, + 0x325b866b, 0xd0675743, 0x045029fc, 0x26548b4f, 0x0a368ebb, 0xd745719f, 0x78098d60, 0x80d27afb, 0x419e0d29, + 0x76342962, 0x320fd20b, 0x6be2efe7, 0x568d1127, 0xa7f91d50, 0xc6000bde, 0x6a1fb284, 0xcf71cb3d, 0x662be3ff, + 0xfdd1183a, 0x81b71a02, 0x1ae2d8b8, 0xd11b38a8, 0x729f2388, 0x1f35f6e4, 0x9735cad3, 0x8a9219cf, 0x3a95e360, + 0xe766ce4f, 0xcd3b2bce, 0x6658388d, 0x70a7ea6a, 0x0647a31d, 0x59f01ba1, 0x8e7e40f8, 0xa7c2320f, 0xcf44c20f, + 0x0df24e04, 0x5caa0f39, 0x6fc11340, 0xae12d742, 0x7174216f, 0xb0d28211, 0x7b9c5109, 0x09bb60b4, 0x4a62b449, + 0x79a96df1, 0xa7cad942, 0x8fdc6711, 0xfb8bfa84, 0x494ded9c, 0x5c4ab615, 0x8148f334, 0x2eb4bf71, 0xfb503fa5, + 0xcf0f72ca, 0x6ef3ea31, 0xd129df63, 0x3c40606a, 0x7e8f8227, 0xcebe76db, 0x29058b78, 0x134387c8, 0x0f0373ea, + 0xa30895b5, 0x560d1a37, 0x7e375d5e, 0x8652fc26, 0x52b5cf9a, 0x56b0b9dd, 0x18ea1248, 0xffb34d66, 0x356b4353, + 0x4be05002, 0xa405bbe2, 0x6d6dbb71, 0x6f081f67, 0x21abfb63, 0xa78f8d40, 0x448bd5b2, 0x1563a90d, 0x3981dcef, + 0x8e33892d, 0xe6c650e6, 0x26eb309c, 0x821414e5, 0x1e67232c, 0x6bcfdc5d, 0xb5d825f3, 0x513b8365, 0x5e108ddc, + 0x6424ca6f, 0x1d945708, 0x5f8a985a, 0x14796b22, 0xc1319092, 0xd3abf54c, 0xfc1eeaf6, 0xb973e7ed, 0xc683c8d0, + 0x548f2b18, 0x3ebf59bf, 0x18fab2d9, 0x891b5eac, 0x74e030db, 0x1a4208b1, 0xba42044d, 0x42cacd10, 0x6cc6fcca, + 0x1027535b, 0xb9e7aeee, 0x93828e36, 0xf177e908, 0x28020f0f, 0x9054f35d, 0xa5bf6441, 0x48ab0c7b, 0xfbe24c08, + 0x7280656a, 0x3b6ea4eb, 0x95d8fa3d, 0x5255bbe2, 0x512811a9, 0x31828855, 0xd0572a40, 0x35176a5b, 0xc62266fd, + 0x5942b8ca, 0x3a25e3ae, 0x8e130fac, 0xf96b52c9, 0x1a28a6df, 0x86efa22c, 0x0096d9af, 0x16253899, 0xb89efc71, + 0xe579c1e7, 0xc45785c4, 0xc51fd7db, 0xf7d1f54f, 0x947b0c3e, 0x83a8e3c3, 0x6dd574ff, 0x70e1d76e, 0x0e57c9f5, + 0xe91c431a, 0x6d38c8db, 0x7d7f43bc, 0x5c2c36bb, 0xd1efef09, 0x7730c8f4, 0xe4d30848, 0x7fed7a6a, 0x2c826633, + 0x5e656d5b, 0x385130bb, 0x29c67ffd, 0x3f6a57d8, 0x5cfc9e0c, 0xdfbc28c0, 0x780ff141, 0x989e6038, 0xa9310fea, + 0xf3e06097, 0x46d0c8f4, 0xbddf3b27, 0x20f900b2, 0x2a46cebf, 0x3c3abcb9, 0x85ee8379, 0xb85b6fd3, 0x2e908037, + 0x65553c7f, 0x922b085b, 0x77cdfba7, 0xcc42d654, 0x5ae05f4b, 0x6b278cf3, 0xa731f7f2, 0x33b9a3b8, 0x49adbe10, + 0xbff813a9, 0x176be501, 0x351344bb, 0xb812ae17, 0x8b19bd6b, 0x194d977f, 0x45a5ff33, 0x562f6876, 0x6fd9834f, + 0xaf073dba, 0xb60da6fa, 0x7292f04a, 0x1efb4a7b, 0x37cdfcae, 0xbae07dd8, 0x5936d457, 0x4b31c288, 0xb6720c63, + 0x78b07fe1, 0xd53cfcc0, 0x4c8f2339, 0x07072bbf, 0x1374ea2a, 0x837118b0, 0x408cd4f5, 0x55dee10b, 0x1558f017, + 0x0996cdec, 0xcd472dea, 0xc88e4498, 0xc8becb23, 0x8b1227d0, 0xa40dbbca, 0x5fe5f9ea, 0x4e1ef67f, 0x1af6216d, + 0x4e301717, 0x3f9ad0b5, 0xa6b4e8f0, 0x3dc1a313, 0xbc36d235, 0x089b9945, 0xdbdc605e, 0x3cd8ab5c, 0xf894884e, + 0xaac6558f, 0x14635a81, 0xd29aa25a, 0x304ce4dc, 0x148b6d78, 0xbac7dc06, 0x63cb0423, 0x155db6cf, 0x3d72e027, + 0x50d985d3, 0x88ae128d, 0xf2b4e629, 0x0b5f7b61, 0x75b6208d, 0xb50be7c6, 0x4b19331c, 0x72d4a282, 0xa133c5f3, + 0x881388ed, 0x257bf09a, 0xe3fb5c89, 0x3a526e37, 0x6f929d50, 0xa42c1e1f, 0x855a7c91, 0x0f8aa9c4, 0x008e592b, + 0x1574aaa5, 0x9fca2326, 0xf365fa96, 0x13a33b74, 0x36f364b4, 0xc77d79aa, 0x4f25e6cc, 0xa276329e, 0xdb0198a2, + 0x0dff36e2, 0x75558f21, 0xdea302ce, 0x935d8d6c, 0xf22b1993, 0xfeddfca1, 0x3c61fd47, 0xa4556c12, 0xca1a3b07, + 0x3e4b837b, 0x02ed433c, 0x211fb51b, 0x4ddd87f7, 0x2b6a7cb9, 0x30169169, 0xb87dd5b5, 0x9b06adaa, 0x9462610c, + 0x9d913021, 0x087bfe68, 0xd53ce7a5, 0xa4c6bf89, 0x3a5e6d34, 0x7a9e80a0, 0xb219c087, 0x55c59ac2, 0x5e48864a, + 0x9cac33cd, 0xbdbbdf81, 0x96e06af5, 0xabcde47e, 0xade54c61, 0x477f6740, 0x81b22e24, 0xd4a3e025, 0x2291d370, + 0x3c5f849c, 0xc3de823b, 0x263fd83e, 0x49cf54e1, 0x1f0dabdc, 0xea1c84b5, 0x812383cd, 0x40556fc2, 0x35d78893, + 0xddc3ed0b, 0xcbc4e15b, 0xd79e487e, 0xdb428899, 0x9a959b00, 0x8ad21baf, 0x8358404f, 0xb946b8f2, 0x8e924d29, + 0x3f083713, 0x6cb388f1, 0xf1137782, 0xc09f3113, 0xba4d6bf3, 0xe3af320e, 0xcfd822cc, 0xbe014c80, 0x50488980, + 0x4892ca51, 0xa6de66fb, 0x6adf3f19, 0x48046ad2, 0xb0790b37, 0x4bb4a547, 0x6c969c69, 0xe44133ce, 0x5aa41a6f, + 0x1713b76f, 0xe3f4c5da, 0x7b93fd13, 0x3331a45c, 0x0e9d9e78, 0x567e2ddb, 0xf2b30935, 0xb5fc8542, 0x6591f5e2, + 0x4b90c712, 0xe9e1779a, 0x01c42ac6, 0x5ed71c91, 0x45144268, 0x385cf905, 0x75fae24f, 0x35ac3553, 0xb446b40e, + 0x182a8524, 0x40ac23ca, 0x8bf26837, 0x0e85df95, 0x30ce08fa, 0xb87afae5, 0xc38e0095, 0x8e3f9fa8, 0xf7ce30df, + 0x25dd551d, 0x35925f66, 0xe221e853, 0x5205809a, 0x1848ddb0, 0x286273dc, 0xfd14e20a, 0x3e54b2dc, 0x0e25810d, + 0x823920c8, 0x881889bd, 0x627a5706, 0xd1fe9c71, 0xd528a209, 0x0298efc2, 0xdca4beb8, 0x0ebbf37a, 0x954a87a8, + 0x605261d3, 0x037b62da, 0x5b5735bc, 0xf061603b, 0x9169cde4, 0xfb7d98e0, 0x8735dea2, 0xace30d75, 0xb2099365, + 0x5407b2af, 0x69b58411, 0x87109b0f, 0xe5d79857, 0x17148d55, 0x0a17b9b8, 0xf7393f90, 0x34aaa4d5, 0x9b24551c, + 0x9bd000b6, 0x9152bb6d, 0x9a9174ca, 0x3988e3ee, 0x6b4d97a0, 0x2fe25c7f, 0x9b82adda, 0xec2a8d31, 0x722604b5, + 0x3966d187, 0x845d07e6, 0x9d3743e0, 0xc21d479f, 0xf0db6e57, 0xaa322953, 0x3d614493, 0x64dad24d, 0xd4270bc4, + 0x1b4ae937, 0xf69b7639, 0xe528dddd, 0x916781c8, 0xedb0841d, 0xc158721d, 0x8f05f7da, 0x611aa80b, 0x690985c7, + 0xcedd112d, 0x850c4746, 0xf916d707, 0x277e7de6, 0x31b7aad3, 0x93cc39e8, 0x424eb1e6, 0x9d1c0b39, 0x4b730a3c, + 0x65e0ef07, 0xc01ec929, 0x11e981e6, 0x678e3f29, 0x1f9c6ddc, 0x7e3959c8, 0x8ecdf701, 0x5934efe6, 0x46f67394, + 0xbb63990c, 0x2c75dca2, 0x808a80a9, 0xe33c8f96, 0xf9f45e07, 0xb8cee8d0, 0xad118030, 0xe883c945, 0x6ef2378c, + 0x3ddcd022, 0x014eab43, 0x26ae9e33, 0xbde4735c, 0xaf2e98ec, 0x40626141, 0xb8be6a67, 0x5a6528d7, 0x57dd4cf6, + 0x1851dd18, 0x67d419e5, 0x0dd2e5a7, 0xbacacc9f, 0x6aca3b12, 0x8fb0bbf8, 0x8c84600e, 0xed02cb47, 0x2dde7c72, + 0x23967e70, 0x8dca87b9, 0x78fdabee, 0xc8e254c5, 0x9596f8fc, 0xda39cee1, 0xc11a2a36, 0xf206dc57, 0x59b84a80, + 0x9a210143, 0x81d891d3, 0xc2232ad2, 0x0426f654, 0x0319ad4b, 0x3202a629, 0x15585d5b, 0x7841f0f5, 0xefc4eb6a, + 0x16d28ce3, 0xd32d8a7b, 0x733a5443, 0xa44f14ac, 0xe17b92c1, 0xcd1c627e, 0xb0ed777f, 0xf989c760, 0xbd9d2af0, + 0xfd9c124c, 0xc0d82435, 0x48e3a39b, 0x6b22174e, 0x76d5fa5c, 0x9fecf191, 0xd6c03daf, 0xd53f4bac, 0x044dfd1b, + 0xaf625aae, 0x528f6f1e, 0x4f338189, 0xfb24c487, 0x7dab04a5, 0x5de0beae, 0xd578c06e, 0xa4171f04, 0x3ea2ea94, + 0xc52bde83, 0xbf51da19, 0x11e72231, 0x35cac343, 0xa07aa387, 0x874dc9a9, 0x9e8ba129, 0x428021a6, 0x66913366, + 0x7b41b3c6, 0x36479809, 0x51a111ef, 0x8d9c2900, 0xcacec007, 0x49897f2a, 0x84f2471a, 0x98451580, 0xd33eec16, + 0x30ed6afb, 0x724663b5, 0x9af0839d, 0x31030e59, 0xc3ba02a5, 0x7b7c2ea8, 0x5b624d03, 0xf3a06d85, 0xa9fb5a02, + 0x0f0eeb66, 0x225aa099, 0x45193a43, 0x7c8d0bbd, 0x960851ba, 0x0c7af4ad, 0x1f9a3230, 0x5ed2c952, 0x09bc31a8, + 0x5e406b0a, 0x15111077, 0xa8147e59, 0x40e964c7, 0x60bfe4c5, 0xd02fa9ad, 0xb5e19444, 0x1ec6e171, 0xdb5e16c2, + 0x38f3f75c, 0x83f526a1, 0xd5f40a15, 0x7e25e622, 0x6741c28c, 0x110b7659, 0xa6e28a61, 0xa1132281, 0x832d5545, + 0xfec69b62, 0x36790bef, 0x0e1cea24, 0x47e96ee6, 0x582ade92, 0x8acb0726, 0x3687b1c4, 0xb1c268f1, 0x842aa60e, + 0x6da9b792, 0x51061c27, 0x72a98270, 0x255cfd03, 0x1e252734, 0x045b3967, 0x8bb6cabe, 0x2e1715b6, 0xf0188be6, + 0x6d4bdf3d, 0x427c71c0, 0x083b5c5c, 0x3bb89d8d, 0x0ae6cf29, 0x813232fb, 0x0fb00951, 0xca1c9340, 0xba7aca4b, + 0xfd1ed7f3, 0xf0e5d15f, 0xbd582be3, 0xf76b04d2, 0x8a3ed59d, 0xe91e9643, 0x25a056ee, 0xf158738d, 0x8226c97b, + 0x7f051549, 0xfa51968f, 0xe991c8e2, 0x141ba0c4, 0x2a2fc079, 0x0796c703, 0xfdd2ef04, 0x33677ea2, 0xbd540467, + 0xaffa07f7, 0xfa9bae43, 0xd7a54558, 0x03a60549, 0x031c1e89, 0x6f353ef7, 0x0b834bfd, 0x09b6a8e1, 0x3f9e1947, + 0x5705f783, 0xb4455579, 0xc69223fa, 0x8c013150, 0x36c3844d, 0x37c6c576, 0xe2dc66e5, 0xde7bccf4, 0x112745b3, + 0x4e8091d9, 0x9725b885, 0xe109d136, 0x7de69aef, 0xfe50ae3a, 0x4403fffa, 0x45d202ab, 0x63a07535, 0xb640cda8, + 0xc7bab5a8, 0x4cba8550, 0xf1aae0e7, 0xb3fdae48, 0x7ac0bf4b, 0x988293b2, 0xe3c502d3, 0x2e3335e9, 0x5a7a7fcb, + 0x8aee3450, 0x6f2ea1d4, 0x737620c6, 0xaffcb5b9, 0x15644ff4, 0xa3563544, 0x094f8cdf, 0x937d6d74, 0x254d0592, + 0xa3eca92e, 0x60a8587d, 0x7af080ff, 0xc150726b, 0xcd4316e4, 0x74373d7f, 0x20aced85, 0xc96a8b74, 0x36c40d39, + 0x543637b6, 0x74f757ad, 0xfa670d79, 0x0dd65664, 0x15998d6e, 0x15b3a316, 0x29555178, 0xb8999419, 0x006d88e4, + 0x5cc84d8b, 0x34c76a07, 0x7deeff48, 0xe622fb06, 0x99ef4399, 0x4d2b301a, 0x4746c1ed, 0x22896c69, 0x9f78f183, + 0x0f189f33, 0xed0efd89, 0xa3a49656, 0xf2e17459, 0xbf9fa179, 0x44c5f62c, 0x748beadb, 0xda77699a, 0x26835662, + 0x8d23abae, 0x3a847e4d, 0x2f97efcd, 0x4e4ec8dd, 0xc28e900a, 0x4d14d0f5, 0xa9098716, 0xee50147d, 0x80f0fe6b, + 0x08ad7d24, 0x34fc70f0, 0xbc73d221, 0x0cd1e4f4, 0x6b6bd3bb, 0xc638a977, 0xa1e26420, 0xc1c78226, 0x81f57e62, + 0x61350a83, 0x4a69835a, 0x4413e773, 0x8241b648, 0x03b186a1, 0x9254583f, 0xa9ca8b40, 0x44d51097, 0x192178f9, + 0x63c46033, 0x9e2d34ce, 0x127b9aef, 0x14f988d7, 0x535a3dff, 0xcf1f40cc, 0x94598add, 0x20e63e39, 0x9cc33330, + 0x61972a0d, 0x1f657e02, 0x82dd843e, 0xf18e3d84, 0x6bc6a4e4, 0x416991c3, 0x3084a6b2, 0x8615d395, 0x33614ab1, + 0x99aa7e51, 0x2491f630, 0x79404a27, 0xca4b1f5a, 0x4fcd98ef, 0x14a30621, 0xbf42f1a2, 0x95ff05c6, 0xb4aefa02, + 0x9ea062f7, 0x37f8dd31, 0x7154d433, 0x71b81f59, 0x59ac39ed, 0xefae9800, 0x35288826, 0x48f274c7, 0x48a99cfd, + 0x420a4f0d, 0xa88f7a44, 0x8e7d3a7d, 0xd9d72b62, 0x014673af, 0xc7a1e4ef, 0x45427d6e, 0xeaa14eff, 0xabe17ce1, + 0x9cdc792d, 0xe55cd4ca, 0xc56d604d, 0xf39b0e5e, 0x34430c1c, 0x0354de5e, 0x0933d299, 0xeb65b609, 0xb44d3561, + 0xf55c4a6a, 0x79a4dabb, 0xb824eb2a, 0xe03b92be, 0x6c3b9c18, 0x6498dec0, 0x3b4449e7, 0xda5d8c71, 0x5d2040ca, + 0xc6350b2f, 0x776bd415, 0x9554d308, 0x4ba50a65, 0xda6ed548, 0x022142bf, 0x81b17d45, 0x95ab0022, 0x54c6b09d, + 0x6c70e288, 0xa28b5ff1, 0x2d523e97, 0xb982c2c5, 0xe603a72e, 0x5a2696c0, 0x0e561bdc, 0x1aba4f22, 0xf769c4d4, + 0x7a7b72f6, 0x9f2cb655, 0xba9c5854, 0x81b32e1c, 0x490f2596, 0xcacbd40f, 0x41a766fe, 0x07426d63, 0xb4cdfafe, + 0xaa0bc498, 0x6045b129, 0x8af2ddbb, 0x91497868, 0xa8b33446, 0x141311e2, 0x8b7b24e2, 0x1fe641c6, 0x3c1f770a, + 0x23a4b82a, 0xa5043eb4, 0x6ec4548c, 0xa76ff42f, 0x6807fee3, 0xc9272efc, 0x4288ee07, 0xac2dbb3c, 0x4c798d62, + 0x8c4864c7, 0x5625c758, 0x0eafa549, 0x261aa37c, 0xd93b2c05, 0xc16b3346, 0x6b685caf, 0x4cfcac8e, 0xcf2e78f1, + 0x6f394186, 0x823f9744, 0x0d3c3f4f, 0x16340915, 0x88f58d50, 0x9852529c, 0xe3bcc099, 0xc642b65b, 0x6560ba44, + 0x2109cfcd, 0x53549494, 0x49865037, 0xdfff7285, 0xe9b3ea8d, 0x56f521e3, 0x4a06df97, 0x78425474, 0x5225f467, + 0x335e2c38, 0xa9035903, 0xf9eae083, 0x0ce049dc, 0x36ac49de, 0xb19aac4a, 0xb9b9fed7, 0x3b135552, 0x9f340d2d, + 0x3e2d6c7e, 0x44168860, 0x6ac9a322, 0xec92cf9f, 0x55d228d2, 0xbbc9346a, 0x12afcb38, 0xec704614, 0x1aa4b4e3, + 0x882a20bd, 0x529e1823, 0xec3afd1f, 0xd05ee453, 0x7177af49, 0x9344d911, 0xfcd98535, 0xb6ed9915, 0x2c804c6d, + 0x45b5b2d9, 0x294fa249, 0x7a016f1d, 0x2f619e5c, 0x909d3cd2, 0x51a8651a, 0xab8bd739, 0xf71992c2, 0x4d49d839, + 0x6795f9c9, 0x0b2369aa, 0xbd335111, 0x5db94862, 0x18a97ada, 0x62fd2269, 0xeaeb74d0, 0xd4e60be4, 0x0e028e1b, + 0x570c9560, 0x44afd1fb, 0x0476c5dd, 0xb886aad9, 0x18105211, 0x790629e3, 0x06a8a051, 0x2cacb2fd, 0x1d75076b, + 0xfcbb0190, 0xe05f7857, 0x00753890, 0xabc2116b, 0xcd266526, 0xe965d19f, 0xd314868b, 0x7d2bd990, 0xf9155997, + 0xe5997340, 0x84b2b979, 0x2cf12c87, 0xaa15d1b4, 0x30f7fdb7, 0x5f282599, 0x9e1c51b0, 0x6d70edcf, 0xf1933a0d, + 0x4096af3d, 0x72142368, 0x9cbc3c0d, 0xa2b2239f, 0xef14685e, 0xa0c5d4fe, 0x4e55e200, 0xb92bf3ae, 0xc17c6956, + 0x45b7c53f, 0xd68a0228, 0xdf4bb030, 0xbda7c798, 0x69af8a9e, 0x49246f2f, 0x5ce25236, 0x53197b9b, 0xff47c08c, + 0x98b654d7, 0xa3120cbc, 0xa29f1522, 0xf06338e1, 0x355e3a1f, 0x5762ef6b, 0xf5362e44, 0xb1153f0f, 0xb76528f9, + 0x925e0b87, 0xd63c3d35, 0x85cd4b8b, 0x5a90ca49, 0x89e7f50c, 0x84f7b34e, 0xfece4d37, 0xfcd0156b, 0xfc68ccfb, + 0xb6bb77b8, 0x0ae885c4, 0x81da2306, 0x3efe1079, 0x2cb8547a, 0x36321980, 0xc9ee482c, 0xcca8b10c, 0x291b4d9b, + 0xed87ed79, 0x896660be, 0x18ced28c, 0x5d15d77a, 0x7db29403, 0xb0decf67, 0xd3c29eaf, 0xf8158bb9, 0x35ab059b, + 0x0efaa09f, 0xe21a9ad6, 0x70bdc55f, 0xc54861a7, 0xbd4dc6ea, 0xff1e80c9, 0x8f018bfa, 0x6a14f01c, 0x9e24474b, + 0xf1096744, 0x3b2c0635, 0x23d56267, 0x59b6e531, 0xd455204e, 0x476b2543, 0x868d92fd, 0xe9c68182, 0x377a4663, + 0xf4c5bec4, 0x3de175a0, 0xb85bfb4f, 0xca3b0bae, 0xc97cd444, 0xe3abce86, 0xc26d3cf9, 0x712b3ea3, 0x53d3426c, + 0xfe625b3e, 0x8ff7c052, 0x86b8903c, 0x03c43b64, 0x7e3cdb91, 0x7fd6d35c, 0x20522453, 0xb2283412, 0xdda3c320, + 0x86d753fe, 0xa7e57cd0, 0xb3e53f9a, 0x54c3fe1f, 0x14e7fda6, 0x0c960b5a, 0xfbec64a4, 0xacf639f9, 0x7a9ad610, + 0x8624bbe3, 0xbf8ca084, 0x8a7ccda1, 0x6e52594b, 0x92497dc3, 0x4d3fdad6, 0x5fd0e7fb, 0x3dc13d25, 0x3273f67e, + 0x8646c715, 0xb7188a22, 0xe51f3e7f, 0x8d4169a1, 0x4b59f6a1, 0xc728e53c, 0x9b74086c, 0xcfa73fe4, 0x89bf66a5, + 0x7413ebec, 0x52d564b6, 0xfa2d08fe, 0xb5ac5c63, 0xa3793be4, 0xddadb410, 0xec9da976, 0xb58bcfd2, 0xd63b513d, + 0x9e37ec42, 0x3e464cc4, 0x087f6a08, 0x83e6e30b, 0x7fea2a1a, 0xaef36da0, 0x0e876055, 0x5a741cd9, 0xa8efbdf1, + 0x5939ddec, 0x49d747b0, 0x1d842349, 0xdaa540a6, 0x7c188fae, 0x296b5cd3, 0x26db8d4e, 0x28481767, 0x52b6977f, + 0x2704cbe2, 0xda449063, 0x10d4fd8d, 0x45ebb3cf, 0x37fec118, 0xd820a96e, 0x13e1b8ec, 0xad4cb95a, 0x9dcca3fb, + 0x7616ee45, 0x4e5e691f, 0xdf07604b, 0xbffd875d, 0x55d9d25b, 0x11bfe82e, 0xd851073f, 0x0c1993e9, 0xfb7347c4, + 0x9ebb974a, 0x2f257ac9, 0x3a8f4ef0, 0x24093c9b, 0x2dc09728, 0x2c3a7af5, 0x572e599f, 0xd2059c0c, 0x5058349f, + 0xb39e8b71, 0x73dd2476, 0xc3fd9604, 0x7e6b1d5d, 0x1dcaa548, 0x1fb01478, 0x653febfc, 0x0797b9ed, 0x027d12fd, + 0x29e93dae, 0xf8d93408, 0xc07ffc4e, 0x264a83d6, 0x40093aa6, 0xd1f3b89f, 0xa316d3dc, 0xb934408a, 0x2657aa55, + 0x12e8ba73, 0xe66ee605, 0xe3985a0c, 0x398aa6b8, 0x41f07f7b, 0x912cdf83, 0xb3b7a5bf, 0xfaa14ff1, 0xd8306a55, + 0xae3dcd49, 0x3cbd58b3, 0x4f490b24, 0x707949b3, 0x017fc48b, 0x101724be, 0x35bc225f, 0x16eb8adf, 0xc39ba49c, + 0xb8c8e65e, 0x45bb707a, 0x7095d27a, 0x9f940224, 0x12af8c2d, 0x660477cf, 0xfcbc5db8, 0xa5e61671, 0xdc46a832, + 0x9ca4e2e4, 0x5a02775a, 0x54102735, 0x099d2c42, 0x7e747278, 0x936814a4, 0x304884b0, 0xdecaadc0, 0x34a41d73, + 0xcb83d372, 0x7d4a7092, 0xd062fc7a, 0xccb35905, 0x326702d4, 0x7afe4722, 0x433b53d7, 0x5e1a7908, 0x84658b90, + 0xb61ab5b5, 0x9bfd0896, 0x7949baad, 0x2e59b13f, 0x725c09c1, 0x5d93b4c8, 0x66345d44, 0xad200926, 0xe730336c, + 0xfce03914, 0x8e95237e, 0x967a1819, 0x72ece5fa, 0xfc3b7e44, 0x01b8d313, 0x5c567c2a, 0xddc3688e, 0x088dcc74, + 0xa8fcf115, 0xa0bb86e6, 0xf8e9b90d, 0x59e6e1f9, 0xb203eb54, 0x9c2161e6, 0xcaa3f1ee, 0x7bef5157, 0xcf1a48f8, + 0x2027f746, 0x024e046c, 0xe53a6c34, 0x324a4284, 0x76261e64, 0x4d0c818d, 0xe935ebdb, 0xa88cb3ef, 0x8bd6e2d1, + 0x98798c42, 0x3f8b2c33, 0xaa6d8145, 0x5c121551, 0xd0c6796e, 0x1effda2c, 0xfa9fbcb9, 0xe2fbb70f, 0xe0bd12e1, + 0x81314de6, 0xf6d4174a, 0x6eb78ed3, 0xac325c88, 0x702edf9e, 0xa40869a8, 0x273b0d38, 0x08bab2d6, 0xae4ef089, + 0xfd4db5f3, 0x01569024, 0x272f8723, 0x52b6ef98, 0xd0ee0a58, 0x8130829e, 0x72009f17, 0x7402e29c, 0x589ece5f, + 0x54564513, 0xe4b2f31c, 0x75fe28c3, 0x1d084402, 0xb8f04e58, 0x1ce052c3, 0x8df682d9, 0xeedfd09d, 0xb4eac90d, + 0x9ca8ccaa, 0x400ab1c9, 0xed179eb8, 0x3d30ba27, 0x5ce6bb86, 0xa8fcac89, 0x67ed53ef, 0xc7cf2a04, 0xebbb2a2f, + 0x90be23d8, 0xa7b01914, 0x4e600d62, 0x990f306e, 0xc619a8a6, 0x8bbac8f4, 0xc35fcabd, 0x93fac517, 0x2385c0c6, + 0x800cad65, 0xcac2ba45, 0x760ed62d, 0x4c8e8361, 0xf7c94f4d, 0xec6cc60f, 0x98451268, 0x6717918d, 0x5cdeebe1, + 0xd6bf2d77, 0x428236ab, 0xe4f9c183, 0x00a4f285, 0x9cf636ef, 0x901b412c, 0x2c3db0ea, 0x00fcc535, 0xab7cfc38, + 0x94a70cce, 0xf79e23e6, 0x1897cdbf, 0xc272f2c9, 0x2a59fa17, 0x1b97f35f, 0x5f435e3e, 0x2d97b84a, 0x9215aa0c, + 0x39854f89, 0x75e72eb7, 0x27f9cd5e, 0xbd1fca00, 0x22296329, 0x8afa09fa, 0xec5d6da6, 0xa8276356, 0xa5369f62, + 0x5eba8b9e, 0x9bb50836, 0x45b20112, 0x9cd1813d, 0x5a6d86fb, 0xe1970d86, 0x9a554c2b, 0xe2e864cd, 0x3ec27225, + 0xfe67e0a3, 0x2da2a4a5, 0xf19ff0a9, 0x6486ccd0, 0xf6f4204a, 0x0b0a6fe6, 0xb344c26a, 0xbaf1316f, 0xff15915d, + 0x64561f36, 0xf7bc9bed, 0x5a128c10, 0x49d9ceed, 0x4f6c2570, 0x43210733, 0xcc381d77, 0x806465a3, 0x5fb7f706, + 0x418ee8db, 0x9971349a, 0xca4f815e, 0x60fdaece, 0x4cfa293b, 0xa64a4da4, 0xa95136c0, 0x886f08f2, 0x496f93f6, + 0xa41cedcf, 0xfdfc3dfd, 0xe4e2cced, 0x45175bf8, 0x7b7cde8c, 0xdbcc9efd, 0x4579df4b, 0xcd24148e, 0xa1b3a805, + 0x2d5b2e67, 0x2b2df8e9, 0x710cb519, 0x876f887d, 0x999b21c1, 0x189d606d, 0x6b509337, 0xb09b8451, 0xabce306b, + 0x7d80b0db, 0x8cc2655b, 0xddf82d38, 0xd2875ced, 0x8e35a7af, 0x97b5a73f, 0x3fef905c, 0xc0e20c42, 0xc1019dd7, + 0x2e73085b, 0x0cb4e375, 0x44f79061, 0x523f3d2b, 0xe3c0d055, 0x9f717c20, 0x77ddc935, 0xc7b4eb18, 0x71420f17, + 0x9c9dc379, 0xd5be1a96, 0x5668eb94, 0x6469d312, 0x20c66147, 0x22aaa6c8, 0x2cd1953a, 0xf1eb1782, 0x40054fc6, + 0x8ab7cfcc, 0x20a8398b, 0x6f14ab1c, 0xd1300c0d, 0xe6b1cde2, 0xbf17f5e5, 0xfc7b94fc, 0xbb345292, 0xc0033f02, + 0x54f82719, 0x4d355622, 0x91be49ce, 0xdcdc7965, 0x3b0026b8, 0xc7bcb1a2, 0x556f4dd8, 0x1fe3a81b, 0x2044573f, + 0x0ef13faa, 0xda2827af, 0xbcd587df, 0xdd982f55, 0xad6cad53, 0xb0cf3073, 0x2e770d96, 0xefbe32cd, 0xbf502ae1, + 0x078a854c, 0xdc6b5945, 0x7b75e059, 0xa280daca, 0x7ead1add, 0x67e8c05a, 0xf65fe0ab, 0x73e8b4d9, 0xd55bdde8, + 0x2892a10b, 0xb3eb69fc, 0xf0385d88, 0x944a8d06, 0xce930e10, 0x89778165, 0xe24bc276, 0x7d655b67, 0x5161b176, + 0xc0ad874e, 0xae51636b, 0xce2f79a5, 0x494da868, 0xd4460d0d, 0x5a76a6cd, 0xd9fafbbf, 0x72373967, 0xa5fddb6d, + 0x94c93233, 0x84898f65, 0x3da6d3ac, 0x1d19b15d, 0xe85ce87e, 0x5ead62c2, 0x7620912c, 0x53a01307, 0x8b5dd813, + 0xe3c8146c, 0xe29a0f21, 0xa9c0321d, 0xc5ca78f6, 0x5c5243db, 0x03669a2b, 0x2689602b, 0xe5036223, 0xfc6531e2, + 0xbc04c202, 0xc6424010, 0x85a42f9a, 0x61e69e05, 0x6f5499a1, 0xd2b4ef3d, 0x5c557f54, 0xfb01aacd, 0x4f9bdb1d, + 0xd2547688, 0x42e56e39, 0x3da8019f, 0x32b4071d, 0xc6b24730, 0xe01846de, 0x17d3ea2a, 0x5fe9cbbb, 0x26ef3d06, + 0x7398c479, 0x50f3c7a3, 0xe34e05b2, 0x70b6d88b, 0xa2b771bb, 0x99d57281, 0x15ca81ed, 0xaed2562d, 0x788bedcd, + 0x2e2c2581, 0x4df974d5, 0x05e58aa5, 0x3f46eeae, 0x42c5fe8c, 0x17281849, 0x85c09679, 0x4a2f9695, 0xf2e4371d, + 0x3936c749, 0x4c2be080, 0x9039ce1f, 0x9baa4e9b, 0xa7f05e04, 0x6fe4d76b, 0x33a0180d, 0x8802b1fa, 0x008b6551, + 0x31f3fc80, 0x687e3c72, 0xbf39ce07, 0x4337305b, 0x9bc51a57, 0x03ded6ea, 0xc067da52, 0xc7e9522d, 0xe2f596d8, + 0xef2de02f, 0x5448a758, 0x70e4ccbe, 0x0e92f1cb, 0x207101f7, 0x40181611, 0xc2aee1ad, 0x4611003a, 0xc222f061, + 0x890dbbfc, 0x5f471557, 0x6233bd04, 0x76fc04dc, 0x031bf790, 0x9183a2ee, 0x416923ad, 0xc741123b, 0xe6c61ddb, + 0x5747caad, 0x2657deb7, 0x67b21dc7, 0x18405c6c, 0x45ccbbcb, 0x7442d355, 0x7cc173d0, 0x928f3345, 0xa36eaef3, + 0x6d2791ab, 0x0cb47c33, 0x7f96797c, 0xa2af2f0f, 0x462e1ff5, 0x935cf63f, 0x3f6e8dd7, 0x58382048, 0x46735019, + 0x1f4a51d0, 0x12f2ee43, 0x4b0a87b2, 0x1738946d, 0x96785fd5, 0x824f32c0, 0x023fdda4, 0xcfc17625, 0x3cf068d2, + 0x14a7de82, 0x314a9f82, 0x21384bf7, 0xb4b4f997, 0xa1ecf365, 0x18af8dbc, 0xf797133c, 0xc94b4552, 0x4674e0d9, + 0xd0e3d544, 0x94c1c18e, 0xc79ad011, 0x9317c9c5, 0x7ea0d0ed, 0x3182de3f, 0x8631dd57, 0xb3f1cd14, 0xda8ce982, + 0x74a56faf, 0x7f97cfca, 0x501e2904, 0x3de4f771, 0x4d3fe441, 0xba28f089, 0x5eaed446, 0x8f570ad1, 0xc818b674, + 0x4cfbb3f8, 0x41be9f80, 0xaef5e730, 0x9abed091, 0xd413f93c, 0x1db7d012, 0x4cb3df16, 0xc90d8016, 0x5ad48c0f, + 0x8d3cc9a6, 0x1bb0fe30, 0xd2edea36, 0x365e2258, 0x882f2265, 0x224efab6, 0xa5e7d730, 0xa70d70ed, 0x9eda9685, + 0xd2862b13, 0x4fc7f379, 0xccf29f64, 0x57eaae12, 0xfc98186a, 0x73d5f839, 0xe8821414, 0x80969d70, 0x7b59490f, + 0x86d96b15, 0x82b13b67, 0x07e76d9d, 0xdc697ede, 0x513b3b27, 0x600baa8b, 0x2da3521b, 0x0c8c20b0, 0x964e3c68, + 0x7f3844c4, 0x2fc1acac, 0xfbb2d09a, 0x10d2bfb1, 0x953c7dc7, 0x161e27b6, 0xf5b09d6f, 0xcbcde06b, 0x489cc908, + 0xab5baf9a, 0xa1ca2531, 0x8a9b4c7b, 0xdb28d5e7, 0x9b907e7c, 0x40bc458d, 0x28482ff4, 0xcc391498, 0x0d8d0f56, + 0xb7730414, 0xc67c1498, 0xcce6821b, 0xa0d95609, 0x44db75f8, 0x72613441, 0x21170113, 0xecab0298, 0xa836dbaf, + 0x8dd998b0, 0x596d7eba, 0x9126ecaf, 0xd1763e40, 0xbca3e520, 0x7294a844, 0x7bf2e2a0, 0x4fe19f0b, 0xe3116a8b, + 0x35bd64a4, 0xc10fc66c, 0x91d27700, 0xc42eeeab, 0x16bb92ff, 0x0848269a, 0x9bac1223, 0xaa767215, 0x61cb0b32, + 0x6b858a70, 0x737b31b6, 0x61d32f90, 0x679c1fd0, 0xa4aba2e0, 0x6e94e279, 0x20955114, 0x1cdaf906, 0xa7b4e493, + 0xf50ff253, 0x7bb8037e, 0x8e9af7cc, 0x7b95ed2c, 0x35569072, 0xfd80dedf, 0x2b799d88, 0x33a0c1e2, 0x57181b72, + 0xbbc80055, 0x69f259d9, 0x1ea53968, 0xf0197132, 0xe3510b1a, 0xfbc3fcf1, 0x9f1950ad, 0x582efcb1, 0xe1184727, + 0x75eacc85, 0x9675b5e5, 0x2f474a0d, 0x60b68f05, 0xb4726d25, 0x5aff2fd1, 0xf40146db, 0xedfa8d1e, 0xf82d6275, + 0xa35e6def, 0x1f97a1d4, 0xcf0dd0f2, 0xf4684b3a, 0xf26d5cbe, 0x54f96414, 0x4c8c5591, 0x8efec631, 0x774ae19c, + 0x01bcdfae, 0xde242df3, 0xe79c5ab2, 0x4418afe0, 0xab195b59, 0x54d668b0, 0xf26aad23, 0xa7da5d30, 0xba450f8a, + 0xbfeded4a, 0x10389c38, 0xb7211aa1, 0x97d114be, 0x8e3364fd, 0xb20be8a3, 0xcb64d300, 0xa2e3a9b0, 0xb2c1a9be, + 0x9ce5b7be, 0x907ab18c, 0x962d88de, 0xbf19f04a, 0xe2fcfec8, 0x4d011fe4, 0xd27f4964, 0x7dc72eea, 0x85750d79, + 0x87c6c34c, 0x57520aa8, 0x0d06cd93, 0x4ce12eb3, 0xf5b93591, 0x37f7f343, 0x346c53d5, 0x551264d0, 0x24701644, + 0x27a719c4, 0x16c58a6e, 0xfcd99925, 0x9e509a44, 0x25d9a10b, 0xa71f38c9, 0xad3942e7, 0x67bda65d, 0x8b38b427, + 0x12467017, 0x3cb853bb, 0x91db74e0, 0x701637c9, 0x5e65f044, 0x006d2ddf, 0x7aac3f3e, 0x9ddf0400, 0x7297f044, + 0xe2186a18, 0x10ebb1f9, 0x18f2f295, 0x5122cc4c, 0x0ea046f0, 0xb1dec54e, 0x78efa79e, 0xb1a3b1a3, 0x22c7262e, + 0xe3aaf4c1, 0x6943f111, 0x3451b6bc, 0x1ab58303, 0x3d808756, 0x2adfae72, 0x77bc0482, 0x583bae17, 0x3cc1abb2, + 0x644d5e43, 0x1e9bc4fe, 0x99845a8a, 0x8b2243bd, 0x55d6bf6e, 0x9693ff8f, 0xe96f2e3e, 0x224bbaef, 0x9250b393, + 0x55738e8c, 0x07cb253f, 0x0b583726, 0x0664bc65, 0xcc49152e, 0xb0ee455f, 0x495fcdac, 0xb76e535f, 0xaa17099f, + 0xabc74ca6, 0x67d5b64e, 0x28bbf903, 0x227b1fdc, 0x1baf8747, 0x0d5fab09, 0x1ad164d2, 0x7b0b648d, 0xf46b6bab, + 0x8806a65c, 0x5922463e, 0xd5570587, 0xc8f0bc2a, 0x85f233fc, 0x1400195a, 0x47298233, 0xd77bd239, 0x61b2e4d3, + 0x80b9bfe1, 0x1d80a201, 0x2ab194fa, 0xf647c136, 0x61bd9e43, 0x2c0c1177, 0x1aafeae4, 0x7af35899, 0x03d0e99e, + 0x0faf9f04, 0x70d288d7, 0xfe21e5ce, 0x8d9ce7a5, 0xc7ab4d6a, 0x4dc357b2, 0x6ed6c624, 0xdbc560bc, 0x848002c8, + 0x2ebd5c79, 0x9248ffa2, 0x7a45488c, 0x50a10ffa, 0xb0538ffb, 0xb40b53ef, 0xa61ae975, 0xec665afc, 0x46e8ed6f, + 0x476686be, 0x2b60f709, 0x2d80a0bf, 0xaf571d4e, 0xca9c8ed1, 0x00cc8285, 0xff67fbbf, 0x2569db68, 0x1dc29ca2, + 0xc11398d2, 0x302b74cb, 0x8e204c1e, 0x0e61a37e, 0x890ae55e, 0x5d9d7bc1, 0x7fe9256e, 0x12eaf446, 0xc32010da, + 0xd17490cc, 0x5e26526b, 0xe6cb0808, 0xce6450ed, 0x9343db87, 0x4c93dd27, 0xe4a34524, 0x6d0277ee, 0x87c1b1ba, + 0x502f7cec, 0x2ddf9bfc, 0x19614b79, 0x060ccc42, 0x09cb868d, 0x6ef30d63, 0x2a4cb3a6, 0x1c40025d, 0x75ae6b7c, + 0xaa2b88cd, 0xeb7db956, 0x76b01ebe, 0x309fa417, 0xef8c5c2b, 0x826d4a33, 0x9c49c0c9, 0x54ee6f42, 0xb13ee124, + 0xb344dbf3, 0x97ae238a, 0x7a76fbb9, 0x553d19e7, 0xcf27dd07, 0xddb1e533, 0x1882f6d7, 0x54c47c37, 0xc8f06e4d, + 0x9c5482ae, 0xf6298dc1, 0x9da41cf0, 0x8f4cdf8e, 0x85cef02a, 0x9fb5b0d8, 0xf0803baa, 0xfc4e9d87, 0xd2d02162, + 0x6566747c, 0xe748dac3, 0x5c2f9be7, 0x88d841c7, 0x97ef597a, 0x16353516, 0xd0bde0f8, 0x40763d1e, 0xf6d74128, + 0x970e0220, 0x1df3088e, 0xb8473018, 0xc1d6f5d1, 0xb5e4df2b, 0x011ce8d1, 0xfaf41ebb, 0xaa5b288d, 0x0698e6fb, + 0x43d52a3a, 0x0e11301f, 0x217ec13f, 0x6f4a802a, 0xe979ed10, 0x3cc87adb, 0x63d56b38, 0xb66632d9, 0xfa1df4d8, + 0xdabb5a00, 0x25185fb8, 0x5b550cca, 0x3765ba25, 0xf3a28b21, 0xb46bf8fa, 0xcd3f44c6, 0x14df9d60, 0x34df3efb, + 0xb58d10b5, 0xf246b161, 0x41eb70e7, 0xddcaa1b9, 0x6e81292c, 0x6ea2af2e, 0x06c0b4c9, 0x71ab7a84, 0x629870a2, + 0xf7887e5a, 0x1de6ccd7, 0x52b9cad4, 0x9823f2ee, 0x4cecf1a1, 0x1143486f, 0xfea2ea97, 0xa67a8853, 0xf3a29ba9, + 0x03382c92, 0x75e0ffed, 0x252bed28, 0xb06100cc, 0xc78c03f5, 0xf544b159, 0xfc024a0f, 0x0665630d, 0x6680e476, + 0x5e309b41, 0x20485667, 0xdb085780, 0xb38e6d4b, 0x4a72bef7, 0x72098377, 0x13afa8da, 0x0c767ffa, 0xe0e68211, + 0x50651f3e, 0x199d4218, 0xb0002164, 0x926bb29a, 0xba06ec92, 0xca08dc10, 0xfb0d5ffa, 0x57aa3cd0, 0xc5e03d8b, + 0x6db0eadf, 0x9c07a32a, 0xd50f6a48, 0x0fd0868d, 0x58425f5b, 0x548f9df6, 0xcae0a21f, 0x8b3e648c, 0x9786dc9e, + 0xcaf94e4e, 0x4d58b065, 0xebdfd2b2, 0x1e50425c, 0x64ec44ca, 0x070c463d, 0xfc8e7a15, 0x8623fd54, 0x753309f1, + 0x7659bd7d, 0x857bccb2, 0xc074729e, 0xac2e4b42, 0xe6a147e7, 0xc9cadd4a, 0x0b7084a2, 0xbebd86e1, 0x785ec081, + 0x98524d6b, 0xfc84aac7, 0xdaf5ffbb, 0x18470dae, 0xc744a6d0, 0x9b8ace44, 0xa64ad9d6, 0xd92d5680, 0x89d4cfa9, + 0xdd601da1, 0x268c7e2e, 0x86a9c682, 0x020fe8d1, 0x84992a82, 0xf144fecc, 0x89a63636, 0xcbfb1cd0, 0x8ac84ac7, + 0x0051a841, 0xcb61f59b, 0x5c003dd8, 0xf7a4b9fa, 0x28c8e89c, 0x4d3dffdd, 0x08efc8d2, 0x47167703, 0x0dda904c, + 0x629bd90b, 0x6fa865b0, 0x21649750, 0xa3857a61, 0xc4cb7fbc, 0x0efd45b1, 0x52fe157f, 0x8e8729f6, 0xaf24fa37, + 0x0576116c, 0x9296cdb7, 0xc91a139e, 0x525d4d71, 0x7ca79ec8, 0x10cbf95d, 0x6de80c42, 0xa4daa665, 0x18432532, + 0xd079dd16, 0x2cc7698b, 0x28491258, 0x7580afb8, 0xcda13bac, 0x8e7cde94, 0x636cc529, 0x832808db, 0x56b15d48, + 0x847cfa36, 0x14e7bfdc, 0x377298e5, 0xcbbf4d62, 0x4720d321, 0xbe942a48, 0x558f397c, 0xfecf2db4, 0x32bd2d0d, + 0x4524a5aa, 0x794cfd7f, 0xac860d2d, 0x3e2eca15, 0x7f2589cc, 0x875973e4, 0x23388f68, 0xf23eb9fd, 0x919b0c1a, + 0x2ab9f35d, 0x189e973a, 0xfaaad533, 0x9c0707ba, 0x2a19dc4a, 0x1e23894f, 0x562bae0c, 0x1cdda016, 0x1091c65b, + 0x3992e3da, 0x82eb0577, 0x5f8be800, 0x9db29881, 0xa7155375, 0x9e5a96ce, 0x21d0164f, 0x6a1139f3, 0x4dd5bc84, + 0x13bc97f6, 0x62339988, 0x856098a1, 0x6a4e5fb1, 0xb04679c2, 0x0928fdc2, 0x4a0aaf6c, 0xeee2d07f, 0x84fd9278, + 0xd851eb91, 0xad6e7d88, 0x7f6eb8a0, 0x00a6d787, 0xf34a2e47, 0x6e7825be, 0x4d96b293, 0x272e8569, 0x06f96415, + 0xb90c35bb, 0xd0299698, 0x42b125b4, 0x158ef06c, 0x55743d11, 0x532a3803, 0xbb7c535b, 0x95d9eeb2, 0xf73e995a, + 0x371bdff9, 0x8e60cc5f, 0xa8dc572a, 0xd908f676, 0x58b4825a, 0xd8bd0112, 0x4f018f29, 0x3c62008d, 0x5b0f1be6, + 0x15709cf5, 0x09632796, 0x9102c6be, 0x7214bea1, 0xcef07cda, 0x78ac2dcb, 0xd0b36e3d, 0xe4a1b1ca, 0xdd4bcd3f, + 0xe8909cce, 0x89a1ab92, 0xc90881cf, 0x3faad833, 0x31034973, 0x7df1651b, 0xcfb8ca2e, 0x7634b5e1, 0x9a473c18, + 0x2dc3bb23, 0x1cc162b0, 0x16e51f77, 0x53ed6655, 0x6aa5e213, 0xee94bf1e, 0xe554929c, 0xcf427511, 0xbf33f330, + 0x6aae2438, 0xfa9ec5c1, 0x3557ba93, 0xec92f760, 0xe9100cb8, 0x76d4bff5, 0xf8a3e09b, 0x106b5be2, 0xae128754, + 0xa956838b, 0x44a7bff7, 0xa797fa22, 0x934db7b6, 0xc3675b93, 0x5e75d86a, 0xe818be01, 0x7de4416c, 0xd6cc9304, + 0x99ac81ec, 0xf0ee2f04, 0x8ccdada0, 0x864efa24, 0x230c74b4, 0xe69f4801, 0xd93e694c, 0x484d9fcc, 0x67c0d682, + 0x9486513f, 0xbb397561, 0x213a7afa, 0x936b831b, 0x18d3710e, 0x9c546514, 0x39a8c72b, 0x3b28f93e, 0x73dfd7b4, + 0x60b935c0, 0x9080fe71, 0x5580d922, 0x7fa4a5b2, 0x16f3505c, 0x0037546e, 0x6b50dc08, 0x868b51b5, 0x8d45a2db, + 0xc7fa5296, 0xc79a1ed6, 0x8ae9f10a, 0xf987d4c8, 0x96b5a9b3, 0x267eb797, 0xa4dd52b3, 0xb084cfbe, 0xa5c2ad15, + 0x49a4cec5, 0xbaf58ab8, 0xb2d543bc, 0x874aa957, 0x951b8e73, 0x0806ff48, 0x7b9bbe22, 0x48a29649, 0x09190c0d, + 0xe24f2c8f, 0xf5e662aa, 0x0ce0fbfe, 0x6f6a5f9b, 0x89db8239, 0xd8bcccb6, 0xbd05bd60, 0xd11b6f2f, 0x6334a37e, + 0x7770c392, 0xc572ecc5, 0x0a8f3d55, 0xa1005f66, 0xb13519cf, 0xfa17f2ac, 0x6c3b0d3b, 0xf08cbbdc, 0x1f8af01a, + 0xfc834b09, 0xe63cd8c2, 0x8d22209d, 0xac2e1db1, 0xca203c31, 0x1823cf31, 0xcd625744, 0xb291e6bc, 0xdc5d3279, + 0xeea19697, 0xf957afa3, 0x74eac1c2, 0x7992c955, 0x1001db08, 0x764e7aa1, 0xd1bf3a3a, 0x8a859030, 0x635106a7, + 0x15f6ab80, 0x7d8c62f9, 0xe8d4a562, 0x08470e03, 0x52eff58a, 0xc165ff78, 0xacbb166a, 0x13cdfb2a, 0xc7030814, + 0x688ac91b, 0xb7363e0d, 0x8091e6e6, 0xff4fc2b3, 0x58ba0a29, 0xc95d461f, 0x9c3fba89, 0x68bc925e, 0x963a7e28, + 0xe625368a, 0x880ee70a, 0x7618ac5d, 0x92f6e4de, 0x98be3284, 0xe00e6f7f, 0xaf835aa1, 0xaaf5e576, 0x3b0e819a, + 0x6741a342, 0x7fa2470d, 0xeaac48ce, 0x84e6d9c0, 0x081d8be1, 0xaf40809a, 0x8b44da95, 0xc9e3bd94, 0xcdaae8e3, + 0x1fcc82f0, 0x0e3e6702, 0xc6a49d55, 0xded6e282, 0x615f78e3, 0x8eb7cf03, 0xd29bed1a, 0x7348cf6f, 0x9638b477, + 0x5b5e0e85, 0x7345e769, 0x30618945, 0x849602c3, 0xf5caf9c1, 0x57400ae2, 0xff21e41b, 0x8cbbfc89, 0x3c0820fc, + 0x59f071e7, 0x37961c79, 0x552d7a82, 0xfe1d8e68, 0xaa8bce2b, 0xf7bea9f8, 0xea3b4282, 0xc87e7607, 0x768ece37, + 0xe85926b6, 0x0c2ea785, 0x84c0a090, 0xed2b7a5e, 0xa14a9b0b, 0x62a5d07d, 0x027e21a0, 0x9826e3cb, 0x6680b4fc, + 0xd34bc186, 0x4a8f2a52, 0xc52fdc1d, 0x6ce0967e, 0xffec3a4a, 0xbff225b1, 0xcafdc67f, 0xd941d949, 0x4f779c42, + 0xaaf85190, 0x490c4cc7, 0x29054e58, 0xc5f2c8ce, 0x4e162890, 0xe40078ca, 0xc1d44a02, 0xcd85bb3c, 0x47272c68, + 0xef1397f8, 0x5f7827e0, 0x05f6462e, 0xec056794, 0x8123bca8, 0xc27975fb, 0x6967fce8, 0x58d58cb3, 0xb5997168, + 0x31b6ffe2, 0x5aa07e22, 0x9869393e, 0xfa5694f5, 0x5b15c9c4, 0xaab51402, 0xabd6e864, 0x9b4dddad, 0xa115aa07, + 0xcd1670ea, 0xc225bf4a, 0x77b04eee, 0xbf148ee6, 0x3e87f17c, 0xb72b0362, 0x38f2b654, 0xeb7b754d, 0xf3807a78, + 0x41e46428, 0x41967038, 0x7b193119, 0x9fd369b6, 0xb80ef94a, 0x1e6c2817, 0x495e5222, 0xa72c304a, 0x1b91a018, + 0x3a1381c9, 0x3982d09b, 0x98a86468, 0x6ed7ebc3, 0x7bfe7ae3, 0xd2f99d47, 0xd383e4b6, 0x96ca6086, 0xbbcf3dff, + 0x591a98e8, 0xfb18806b, 0xc6560f01, 0xf7db7a25, 0x5076ecee, 0xaf1aa918, 0x0983bf0c, 0x525b64d0, 0x01dd1538, + 0x53645250, 0x76b91563, 0x90433d91, 0x464a19fe, 0x09b9ed10, 0xd0993c14, 0xb6875bb1, 0x46bff193, 0x2b48dff1, + 0x0f26bbd3, 0x2e55af21, 0xb6a14b1a, 0xe6ca84dd, 0x9a98d03c, 0x6e0205da, 0xba23681b, 0x75b99739, 0xe905dcba, + 0x01e26d2a, 0xc94e0cfc, 0x3f17d3e1, 0x601bc476, 0x9916b069, 0x25c9399f, 0xf990827d, 0x7b7f2f7d, 0x8007d85e, + 0x869a2858, 0x67abc413, 0x23877ce7, 0xb1ef24b9, 0x3025a414, 0x53ce6563, 0x71c18d76, 0xb3067b24, 0xd8800ebb, + 0x66bdd54c, 0x0438dc82, 0x4fb0fd3f, 0x31d1a96e, 0xfe148ab6, 0x18b7db3e, 0xb0e33d7c, 0xfd29451a, 0xbe622779, + 0x535e1a1f, 0x7c5a9ecb, 0x966c14e6, 0x65471274, 0x1937189d, 0x1d10462c, 0xe83747b9, 0x7d017471, 0xf3584b8a, + 0xa3855b31, 0x78be2aca, 0xb6d1c8f2, 0xed4270e5, 0x4832fd7f, 0x2e4ad51a, 0x6d70121d, 0x9a24837d, 0x2b92a6c9, + 0x60027ddb, 0x59ba5cf5, 0x1fb92611, 0xcb656c32, 0xca26a580, 0x92be1f33, 0x3460f41e, 0xa861c5c8, 0x90061735, + 0x415b816f, 0x76ef68c0, 0x41d75b51, 0x8b88d526, 0x03f66d92, 0xb4950f58, 0x41dbfd3a, 0x0fb5ec74, 0x38aa9a5b, + 0x19979704, 0x53aa2abd, 0x715d6ae7, 0x2300db34, 0x468482e6, 0xf93a99cb, 0x0dbb34aa, 0x2bf79a4c, 0x31aa77e8, + 0x23762f74, 0xa640b433, 0x53254175, 0xd1012854, 0xf34e8f34, 0x259a7141, 0x05c58ad7, 0x6e66a4ce, 0xb1a12330, + 0xcd8e3c11, 0x98a7fbe6, 0x21db2f91, 0xe5856805, 0x4e6e5a72, 0x481aac67, 0xce412dba, 0x92aae100, 0xecbcb27a, + 0xaf9a4b71, 0x1d3e927d, 0x7fcbf46d, 0xd1f01c39, 0x9351497d, 0xe28e7cd0, 0x13701d3b, 0x5a0da1b5, 0x6c9c250e, + 0x7bcbfe3e, 0x3b425d37, 0x45c0d22d, 0x93d7cd1a, 0x83bd4bbc, 0xd22f7719, 0x0b18d1bc, 0x7100ae58, 0x7f1dabfb, + 0xbd42f0c1, 0x660dc9f1, 0x0348a985, 0xf6154f44, 0xcffc6dd8, 0x5d419b78, 0x75e32f2c, 0x5acce8a2, 0x75af9368, + 0x7523d877, 0x0abf2061, 0x7c594f4a, 0x30a637eb, 0xbe384706, 0x29162383, 0x9fce3458, 0xef16ce4d, 0xaf667e2b, + 0x1e39fcad, 0xec67957d, 0x078d4c1d, 0x2eda448d, 0x5d48ed30, 0x662ab873, 0x7f9dd04f, 0x8a46a9a9, 0xcaf4dc3e, + 0xfcfa08b0, 0x8a8ff997, 0xd37172b2, 0xbdc22994, 0xd227b649, 0x9206a682, 0x0f5c8807, 0xe1d61982, 0x7b00f465, + 0x630ab721, 0x7ccee24a, 0x631862ed, 0x46e7fc12, 0x8fae1ba8, 0x11a44d32, 0x112e9f0f, 0x59a1f282, 0x76bb74ad, + 0xf7a997e7, 0x44d0e757, 0x8e76c04d, 0x320ff45f, 0x4cce7e7c, 0x2594059b, 0x34d23d16, 0x7aa270ef, 0xf56b16e7, + 0x75efa738, 0x860df81f, 0x6e15aa99, 0x3e585ef2, 0xdfebad6b, 0xf75c35e7, 0x5f063f5c, 0x37650cf4, 0x38588bba, + 0x57ec5cae, 0xb1cd3931, 0x899e3cab, 0x6e5101fd, 0xf3cee790, 0xb4fc5cce, 0x634f7a4b, 0xdfc63ed2, 0x2f0c4c5c, + 0x8fe5917a, 0x81e45db8, 0x2dc13cda, 0x2dab56c5, 0xe937eb59, 0x5c9fe34d, 0x8a363999, 0x6ac5819f, 0x4d35b59d, + 0x4331a4d2, 0x48b55e35, 0xd92c2fa1, 0x365090c5, 0x841b9a3e, 0x2df68733, 0xa907bf35, 0x684ea0fa, 0xec0d5b87, + 0xb6f2ec3a, 0x41572f4f, 0x05b78b43, 0x809a9a9a, 0xc11f0067, 0xc2c7950c, 0x311ab478, 0xbbee7b22, 0xeb6549c3, + 0x656ae2fc, 0x8c582a2a, 0xbf3a8e4c, 0x5d8edefd, 0xf50d2d91, 0x4d15aa58, 0x80572245, 0xac0eff46, 0xcd85f43d, + 0xc9d4cd33, 0xa2b35936, 0x1617da9d, 0xe5457ffa, 0x164ca196, 0x9b96e4f7, 0x95396cbd, 0x91a677c7, 0x7a0679e2, + 0x4c71def7, 0x1262c549, 0x96da26f6, 0x525318b9, 0x5c88cf4f, 0x98ff8276, 0x4dd5bd37, 0xe8549c50, 0xd504d2a2, + 0xd548008a, 0x075dd5a0, 0x5387cd82, 0xe204df0e, 0x0abd19d9, 0xeb16824a, 0x9d244a61, 0xdd6ff0b6, 0xa7e4b656, + 0x4e8d9757, 0xd279a93a, 0xd6d58dfb, 0xace4b288, 0x3ce2e25a, 0xd7201adb, 0x4403ff93, 0xe8cf8370, 0x69e8c817, + 0x55124b75, 0x291ca8cb, 0xbe8e6a84, 0x3a3ad3ba, 0xcc144237, 0x01bae302, 0x9f2416a1, 0x8a4057d7, 0x0925264a, + 0xb72d042e, 0x279abd75, 0xe03162de, 0x148d40f0, 0x2f738c87, 0x1f2ebb48, 0xd877490a, 0x8b45c999, 0x7f2ea121, + 0x4dce5c86, 0xcba513a2, 0x014fe021, 0x1781ddc4, 0xb7a717c4, 0x38fcc971, 0xd3e9d760, 0xaa393eea, 0x5cc5f92d, + 0xdd15936f, 0xc4a52230, 0xdabd5631, 0x9f84c4cf, 0xc8d00456, 0xb650eab6, 0xe78abc75, 0xcc3a1c65, 0x67250e4f, + 0x20acaafd, 0xfbf4d8f4, 0xc060e18a, 0x6e94baa8, 0xcc4419cd, 0x19e92011, 0xfa87592d, 0x0910cd06, 0x0d242e65, + 0xd95a6ee8, 0xcf5aec05, 0x5489c99f, 0x57424de2, 0x973d8ae4, 0xe4dccc66, 0x4d6e64a4, 0x96145dda, 0x3553b606, + 0xe3f1916d, 0x4d3c4200, 0x4798fef2, 0x63dcde46, 0x9fff855a, 0x5c92e1e4, 0xcb458816, 0xb0fdd4c5, 0xe0031230, + 0x9c5de947, 0x19373d75, 0xe474e01c, 0xfe1c1a37, 0x66652519, 0xfc0d01c5, 0x95626e20, 0xd64bf599, 0x2847dffe, + 0x187f5485, 0x4a091794, 0xb9db784b, 0xa7937a8a, 0x7811d939, 0x87ab4a1d, 0x123c06fb, 0xc0938cd0, 0x93c7ed31, + 0x13202346, 0x56ea2bcc, 0x935b7e77, 0xfb09736d, 0xfa6da24d, 0x89e4e725, 0x371bfcd3, 0x9314736b, 0x0fbdc8b7, + 0xb18775bb, 0xf2b9973d, 0xf5be4d19, 0x8f6421ec, 0xa6a92dd5, 0x157f031b, 0x1b0f2b15, 0x58b5e7a5, 0x2c7f61cb, + 0x5f8b31ad, 0x7d219012, 0x77a8a1b3, 0xe825cb1d, 0xdfa91b15, 0xdd07c056, 0x5217450d, 0x4b4c434e, 0x0df83928, + 0xc5ca6d05, 0x9508d6d8, 0xffbdc054, 0x35694c00, 0xf0b40c5f, 0x2c4e7b6c, 0xd6759b9c, 0xca3c2659, 0x33993b7c, + 0x73b123c7, 0xaf115d57, 0xca35daca, 0x80e19cd4, 0x24b097ed, 0x5b1376f6, 0xf112bcab, 0x2f93f885, 0x52a90699, + 0xcd1689bd, 0x8a067a93, 0x00d1be01, 0xf3b6cb7b, 0x8da0f0b3, 0x546e07e7, 0x410a725d, 0x95f1556d, 0x6c56f68f, + 0xe71d640f, 0xe27fd951, 0xd397b463, 0xdf8b2542, 0x79d3f4e5, 0x6055c949, 0xaaf1f276, 0xe3682667, 0x94eb9632, + 0x20524849, 0x1516abb5, 0x0f3ffcb7, 0x643d17f8, 0x03f77aff, 0x2551247c, 0x88206358, 0x15187228, 0x52074465, + 0x0fe4fd36, 0xbdf444b2, 0xa1a02a97, 0xcf2e13f1, 0x1baf36ac, 0xbade4db3, 0xc0c15fd9, 0x8a6a1b26, 0x396dbec2, + 0x43708e51, 0xd51779f1, 0x8ed1af90, 0x014de7af, 0xf07f8b48, 0xbe3c24f3, 0x17de4ce3, 0x1375441a, 0x91eca32a, + 0x7ffe3a92, 0xf5e490b4, 0x522a12a1, 0x4b9608ba, 0x065420db, 0x2f1a6fdf, 0xe2682c14, 0x35320a41, 0x1af4cc63, + 0xeffd3925, 0xc858d63e, 0x46f45a00, 0xb8b8f2b8, 0x5cf14a42, 0x3310d37b, 0x39eec8e0, 0x0e311317, 0x6b1301c4, + 0x7364ab5a, 0x50d69cde, 0xb7789a3e, 0x4ca09bdf, 0x127d8f2b, 0xa8b851f3, 0xae63bdc7, 0x340b7eee, 0xe4be8ba4, + 0x336616b5, 0x6ae53483, 0x5f192893, 0xc274cc73, 0x5e45ecfd, 0x3176b4d8, 0x633f4131, 0x199414c5, 0x02cd03c0, + 0x9caa373e, 0x605edd1c, 0x6f3e0bca, 0x661e37c5, 0x68329f94, 0xe4fe4a08, 0x13193b58, 0x06a2e62c, 0x7d6b0b15, + 0xb427ca7e, 0xb0259d53, 0x5f354a53, 0xe4dbafe3, 0x3d918e01, 0xc28cd64b, 0x48faa211, 0xb2fb4283, 0x6a4c37ce, + 0xc00a63f0, 0xb54ddb50, 0x3e4df2d3, 0xccb730b5, 0x5108d964, 0x0f7cce6f, 0x5367973d, 0xe2faf47b, 0x9b127f2a, + 0x8069a81e, 0x8876557d, 0x9ae821f5, 0x88d909e0, 0x95debb9b, 0x49c65bfc, 0xa8b8ad40, 0xff66d11f, 0x2e149679, + 0x7bf8e13b, 0x5295f426, 0x35879396, 0xad59bc5d, 0xa9d07861, 0x33fcd19f, 0x7d744f3d, 0xea50475f, 0x5362daaa, + 0xdeec69bc, 0xfb88f4f5, 0x5034b273, 0xc4e03eae, 0x8c9694fe, 0x438a63a3, 0x56834c41, 0xdbf6074e, 0xb478bc75, + 0x5eb680ba, 0xb3e8cf5a, 0x4043cd4a, 0xaff3f39a, 0x8065efc5, 0x08e8239f, 0xf74e1c24, 0x1f7e0aef, 0x63ffe383, + 0x6d6873a9, 0x17687522, 0xbf7c3c3c, 0x4d5cc15e, 0xd3a61499, 0x5ab55c1e, 0xb8ac6ffd, 0x6fff7338, 0xfe9cd43a, + 0xa8d91924, 0x50a5ed97, 0x764db904, 0x1483c489, 0x9d7a1507, 0xe5c6e85b, 0xc0058f64, 0x2c82d7d1, 0x4cec222a, + 0x79f54ae8, 0xb32d9fda, 0x3d40ec15, 0x386210ae, 0x9fb42c38, 0xa24eff9f, 0xe59f0f62, 0x010e739b, 0x79762f2a, + 0xd9f68098, 0x4b2a7f48, 0x048b6b7d, 0x788af259, 0xb304c8e7, 0xeabb5019, 0xacbd6f87, 0x0b3a5abd, 0x3dff6400, + 0xa9f40560, 0x31d840b9, 0xd739ec2c, 0x25220a97, 0x7feb6832, 0x32f684bf, 0x37a47ed6, 0xc4a35fc7, 0xa4cd8389, + 0x7a50ba01, 0x00ec04e9, 0x71e5e3fa, 0x33758cbf, 0x3475df46, 0xe644c189, 0x9b78e170, 0x4aa24627, 0x02777c59, + 0x607fb34d, 0xf499ede7, 0xea9f753c, 0x6be0394d, 0x0440a887, 0x1424fce9, 0xd183b0c5, 0xa96b1738, 0x61162a05, + 0x3b8fc838, 0xdca7f405, 0x0f70e38e, 0x2bc38b3d, 0x50908c84, 0xc98136d9, 0xb5d4d11a, 0x90716f1f, 0x78f1723d, + 0x2a7b69d5, 0x2b1d5693, 0x5522b1cf, 0xcdb41217, 0x72c5e740, 0x56be6f51, 0xbac19aaa, 0x616ff964, 0x99b946a5, + 0x8434fb27, 0xd5fdc469, 0x2b7efacb, 0x00984cb9, 0xe9a8d0c1, 0x14c25277, 0xdf840847, 0x9a998ffe, 0xa127319f, + 0x6ed4e414, 0xb7d5cbda, 0x3c35db3a, 0x08f74349, 0x89cd5036, 0xc953c252, 0x8617230d, 0xf42ffe85, 0xe0873b36, + 0x3bb93e02, 0xbd58ee50, 0xccc7b28b, 0xeeee5f10, 0xf51dcfd4, 0xc5204ff2, 0xf5f81b17, 0xb0542f6a, 0x1eae7030, + 0xba442c39, 0x9a5dd283, 0x3860d3eb, 0xb4a42169, 0x3b73ace8, 0xd7da5353, 0xb0f82301, 0x47a6f62e, 0x5b525549, + 0x2d32f72e, 0x193cc9d5, 0x9ee06a28, 0xed2f23ed, 0x0eb450a9, 0x97c544d7, 0xbd5b8656, 0xa3961406, 0x58e56c8f, + 0x879d48a5, 0xe06f472d, 0xcb68227e, 0xd85e5186, 0xea004bd8, 0xe0a38c36, 0x210ff72b, 0xc4e85d59, 0x7edfcadc, + 0xfaf02706, 0xa4e26a8c, 0x96c8de4f, 0x2464bfb6, 0xc9d0bf59, 0xf716fcad, 0x69e2be0a, 0x3f2d5bde, 0xa6ef06bc, + 0x045183f0, 0xc2f69955, 0x4075f454, 0xf68118e4, 0x6feb3350, 0x0f1b9303, 0x3ea9ab72, 0x1feff0b6, 0x16028206, + 0x259be494, 0x179f957b, 0x1338dee1, 0x5c2c06e4, 0x0f641ec5, 0xe1843190, 0xd687c704, 0x65e129da, 0xcb09a767, + 0x135c2a29, 0x31e3e5d9, 0xdff2c9a4, 0x93b159cf, 0x45762949, 0x9e72e025, 0x87b9561d, 0x2e8bae0d, 0x4fa13d6e, + 0x199ed783, 0xd0ac3bb4, 0x411b9e76, 0x241d9db9, 0xe63e280d, 0x444c3a00, 0x5a3dbcb1, 0x9981e6e9, 0xd89e1a61, + 0x5fb0cc15, 0x175b966e, 0xe879f9ea, 0x4cea2fec, 0x2bc5342a, 0xe424d1d7, 0x091039e5, 0x44b61ddd, 0x833043bd, + 0x05d599fa, 0xdcdcae65, 0x1346aacb, 0xfd5c45f2, 0x80b0f75c, 0xd0e931ec, 0x2ffc32b8, 0xa7ff9502, 0x248481d0, + 0xa7d1eb04, 0x32396b83, 0x7e87e1ed, 0x65dbf091, 0x4757f84a, 0x16d0dae7, 0x25c724e7, 0x19a3b1bd, 0xb4d23f3e, + 0xbc83672a, 0x195c201f, 0x2d849ca9, 0xc40ebe3a, 0x5f71d81e, 0xcb20903a, 0x86272662, 0x6d23d599, 0x4486d647, + 0xf57c203b, 0xdbf68308, 0x90511ab3, 0x80ad9650, 0xbc5b64c9, 0x2aad62d3, 0x5dd4b015, 0x4c6a9477, 0x92c0a586, + 0xe40e77cd, 0xe69da21a, 0xb7943da9, 0xddc92abd, 0xb6469517, 0x1f08b2ad, 0x5a608339, 0xf8d13344, 0x45e18334, + 0xcbc5344a, 0x86f54334, 0x819750b4, 0xfa8213cd, 0xf4166347, 0xf0888e4e, 0xe5dc5d8e, 0x3897490d, 0x052a4b56, + 0x1d60946a, 0xa3fa5112, 0xa3f6bda1, 0x2ca313f1, 0x2d3976af, 0xf2fefd53, 0x37a2fa56, 0xc58b8d3d, 0x6a8dac1b, + 0x3806ffa6, 0x69b69f5e, 0x2c2772be, 0x9ccffe3a, 0x59c57a70, 0x094c8715, 0x569ebf6d, 0x56d5c800, 0xcf47bc0c, + 0x519c3cd0, 0xbe9842ad, 0xde4badf6, 0xec6d0f8c, 0xdb6c345c, 0x4099a44c, 0xa3538b8c, 0xc89ac813, 0x913ed4c1, + 0x111c1cf8, 0xf9cc5a42, 0x5473baba, 0x8d353f13, 0x93a76cbb, 0x506f55a0, 0xc48fd5c5, 0x3f9799a1, 0x84035577, + 0x4ac48b55, 0x853a3eba, 0xdb0fa36e, 0x8593311b, 0xd2e3bd15, 0x0cbe6394, 0x535ea1a2, 0x5ebf9bc2, 0xd1aa2dad, + 0x86a667dd, 0x4825e15a, 0xa188871c, 0xe8168daf, 0x09b14db4, 0x2e0d86ae, 0x04bd0dfa, 0x1f14caf0, 0x21d712d5, + 0x5fcbaf89, 0xd406b0b9, 0x0a2a5523, 0x7943086a, 0x13584646, 0x27c7299e, 0x0e0cd890, 0x1a0a462a, 0xee4939a9, + 0x0f59b0e8, 0x1c7c93f5, 0xbb9ad143, 0x1cc0e20a, 0xc9f630b6, 0x04eb330e, 0xb86973fc, 0x6c6002c1, 0x048ccb1c, + 0xabd53b79, 0xf020af34, 0x55013d7b, 0x8aae6078, 0x751076a0, 0xf8e1b65f, 0x903ddd35, 0x72572b9e, 0xea5a914b, + 0x160effe2, 0xf34f93fc, 0x0129c781, 0x3d0e7354, 0x24e1f9b2, 0xd1cef026, 0x4f583cc2, 0xba78e62e, 0x54e972e1, + 0x0be62bc0, 0x1802dc05, 0x830faf4c, 0x77507030, 0x52ab15e9, 0xcd9c055a, 0x8ddb6e35, 0x694ce72e, 0xfcb3b6d2, + 0x1c3fd196, 0x4069b475, 0x59619884, 0xccaa09ee, 0x7bb9028c, 0xeb1fd852, 0x6a8fd0b5, 0x28f29d14, 0xc498ad07, + 0xd13aa4ff, 0xac9b5687, 0xa9e84573, 0x6a5ae768, 0x07528990, 0xb542a90b, 0xbf72c7cd, 0x14b4fbfb, 0x8df0db31, + 0x24e4f214, 0x8c40ce5d, 0xad5177a5, 0x2c329c48, 0xb35d0d34, 0xc45d15eb, 0x23f38e53, 0xdd57a641, 0xba1d8129, + 0x8ff08a24, 0x72f8a239, 0x474cd79d, 0xf0b355d6, 0x0c26f993, 0x860e973b, 0x5f4acb5d, 0x18e45a07, 0xe7cba021, + 0xbeeffd01, 0xc21d88da, 0xeff96bac, 0x63a0a1f9, 0x383caffd, 0x1c836ef5, 0xf5ef8e11, 0xfb215204, 0x0bcaba59, + 0x7bc9611e, 0xee8925fc, 0x7e3c0e7d, 0xc0c903c6, 0x8ec917d9, 0x9adff563, 0x2e66ab06, 0xcbe253dc, 0x135f0cb4, + 0x7a74f58e, 0x3370b09b, 0x75bb1dab, 0x78caef22, 0xa14e32a2, 0x312b53f3, 0x2547bb74, 0xf65d9d0a, 0x1c38b76c, + 0x39a50d91, 0xb76ac77c, 0xba44967a, 0xb80a0229, 0xe213c02a, 0x6282b097, 0xcc51ef86, 0xdddf5118, 0x2d4a48c2, + 0x7db5e110, 0xbbaa4cea, 0xa1ad6884, 0x46765a29, 0x4cbef5c3, 0x3fcc5113, 0x29a37313, 0xca2e1292, 0x639568ae, + 0x5c44c67a, 0xfc2c8bea, 0x57e8194d, 0xcd6910ff, 0x53ce866e, 0x48265985, 0xaddeb4c4, 0xd3c4f4fe, 0xeaddfe7d, + 0x2786f2d8, 0xc0ef5128, 0x4d745950, 0xb624f38d, 0xd833a49d, 0xebe0f0a6, 0x9d8caa40, 0x0f41533e, 0xd1440441, + 0x9a3c8ce1, 0xb41bf22f, 0xead377a6, 0xb28bf627, 0x1b1ffeaf, 0x052be1db, 0xd2dcdf5c, 0x255cc9a3, 0x00a446e8, + 0x2451494e, 0x07aa8005, 0xa698cae2, 0x3d023302, 0x9b854a55, 0x17f839bd, 0x75800e8d, 0x6ddc8f57, 0x58b27e7e, + 0xbf8543a9, 0xe4915ef3, 0x17986f25, 0xc97b62bb, 0x5a1e6ae6, 0x4518992d, 0xc0005520, 0x5fc06ba3, 0x1e39def1, + 0x55ed7ed4, 0xdcd68ad0, 0xfc5657cc, 0x09c2d497, 0xa9fde23d, 0x8d5449a9, 0xa5b98045, 0x794ed331, 0xe53dcbf9, + 0x1a5f9345, 0xef787ecd, 0x5703af6b, 0xd668a43e, 0x1446d797, 0x6909fa9c, 0x420d537e, 0xb1501db4, 0x8cff414e, + 0x50c9f94b, 0xd9a2806b, 0xe6c055be, 0xfb4ef0d5, 0x68d5c66b, 0x8e2fa33d, 0x53d51645, 0x2d097c3b, 0x318743a4, + 0xf1f1e129, 0x3f021fb6, 0xcf4e6984, 0xeed269ed, 0x8dbf0bb7, 0x73d14363, 0x7fa17da3, 0xc22a5aca, 0x757035bb, + 0x70389e16, 0x3a3b8f7d, 0x1ecf29ac, 0x9e231b4b, 0xc19894ba, 0xa5d4dea9, 0x61c7f439, 0x5fe83911, 0x12fc7532, + 0x3ff744c6, 0x94335395, 0xfaf25d27, 0xe3a47fef, 0xa4908fae, 0xddc0a000, 0x5b67c3a4, 0x2b6755d7, 0xd383ac17, + 0x5e56a3f0, 0x7a6f8aa0, 0xace94868, 0xf513bb47, 0x031dcaf1, 0x3d2acd4a, 0x5f4a07a7, 0xec732a10, 0x11ad221e, + 0x0cb35cc3, 0xc4f7cee6, 0x87eb8ad3, 0xe108dc0c, 0xb6955723, 0x76a18f13, 0xa5b3b9a3, 0xde4453f3, 0xff36d2a3, + 0x181b2912, 0xb2e4f75c, 0xcbcd1db4, 0x2f478f9b, 0x8200f580, 0x84ba6f1e, 0xc1116a26, 0x26d87363, 0xb3212dad, + 0xcc1b63d9, 0x0b6bd61e, 0x11cf6cf2, 0xea5156b5, 0xf3d97d71, 0xb09e92d3, 0x803a97c2, 0xa233c078, 0xf4f64a7a, + 0x793c2833, 0x49000fcd, 0xacce94fd, 0xfe06570e, 0x2a8eb594, 0x6dcc522f, 0x1aab885b, 0x2c469021, 0x5b41a76d, + 0xe1ae7c2b, 0x318b5eec, 0x2bf64320, 0x8dd8c7f2, 0x4490ad9f, 0x8b69e615, 0xa25d4358, 0x4e44c146, 0xf454df3b, + 0x6ad74e68, 0x1d483249, 0x4126f302, 0x0b2bc52b, 0xc39b3eb0, 0x458a870d, 0x662282a2, 0x413e60c7, 0x2352ea95, + 0xe93d5898, 0x60f5df44, 0xd4f731b7, 0x256de1d2, 0xb3a936a0, 0x3387ff9c, 0x759c5f87, 0xb1b35487, 0xd906069b, + 0x71e1e23e, 0xa639d0a9, 0x54cd809f, 0x7133b835, 0x396f73c6, 0x3808218e, 0x9a2ee396, 0xe519e8f3, 0xc6e09617, + 0x422ed061, 0x49e57730, 0x23c93680, 0xb4df7ab3, 0xa6695db5, 0x32cb4616, 0x0e250a64, 0x9c566ffb, 0x717cf85d, + 0x28b8dd8d, 0xa707a6c4, 0x58d2c176, 0x8c0cf2f4, 0xad2002e0, 0x14bc1df8, 0xf4a6e6b9, 0xd12c427d, 0x0548bcd0, + 0xc0773d33, 0x4c821fe1, 0x8ce57092, 0x9f9365bf, 0x406c682f, 0x08b7e37b, 0xb99a1188, 0x746e62ed, 0xe1f9c537, + 0x0e8914bb, 0xfb7226d9, 0x9cbb9679, 0x4c85378d, 0xc028d0f4, 0x77e83173, 0xf0c69ea6, 0x984d269b, 0xc3debdfc, + 0x5ae1fe48, 0xe2085a70, 0xb2205e8c, 0x6c003676, 0xb7cb682e, 0x36ca96d9, 0xdebacbba, 0x2967f707, 0xab7b321e, + 0x23d815e9, 0x91408d48, 0xbe3eabcb, 0x40b2ace7, 0xfe069c8e, 0x5ea3f379, 0x660a097a, 0x1b67ac5f, 0xb6a802b1, + 0xa1c46734, 0x0ba78596, 0xce1aa635, 0x99c56b06, 0xa40fe149, 0x8cef88ef, 0xaf0b4290, 0xc202e98f, 0xc66094a4, + 0x197b57c2, 0x3cc102de, 0xa2a4c023, 0x3a091381, 0x5d09534f, 0x936921c9, 0x94ccd409, 0xa508a2c6, 0x9c2a01d7, + 0xce747441, 0xaaa42439, 0x9d8650ea, 0x0768038f, 0x30a7a83f, 0x847fd06e, 0x454b649b, 0x6b2ceaca, 0x8077ba68, + 0xf59fd262, 0xc76997c3, 0x7d2ec6f4, 0x88be73d5, 0xb38250f7, 0x254b29e5, 0xc23c6eba, 0xeeee5a51, 0xea8c3109, + 0xf9e32546, 0x4a4bf3c6, 0xb307e58c, 0x90cd40ec, 0xf23020b3, 0x9671f004, 0x45e80bf7, 0xfddaaaa3, 0xfe2a18cc, + 0x9ba6dcf1, 0xd5a2da96, 0x649c0680, 0xfcb5b4ca, 0x7705d95e, 0xab157aca, 0xd8b44582, 0x4718310d, 0xccf8de2f, + 0xa8f20d9b, 0xd6a0fd6b, 0x61e849c0, 0x70372a08, 0x286903c8, 0x5243a08e, 0x485de469, 0x53933bee, 0x3e2b7443, + 0xb8eba135, 0x5ad8f79b, 0xf99ca6ce, 0xd79f40a1, 0x8260c02e, 0xdec34181, 0x6e0c49c6, 0x580ef955, 0xe1da7787, + 0x159d54a7, 0x96e32e7e, 0x84fa52d3, 0xe98b4fb8, 0xe30d94c8, 0x32f97605, 0x260222cd, 0x55a16699, 0x29150257, + 0xba5add54, 0x7d631350, 0xb6c24d8a, 0x3286459f, 0xdeb86752, 0x60bb1563, 0xb5cbfec6, 0xfc0df43a, 0x04746d7a, + 0xc3aaf338, 0x831fdfca, 0x514e181e, 0xf887fa04, 0xe8da4f91, 0x0e8bfc0c, 0x4f20067e, 0xc446db1d, 0x7d50a11c, + 0x11bfdf3e, 0xd1f3a134, 0x79d9ca06, 0x9f69087b, 0x66a4c77a, 0x1123fd5e, 0x1ff01103, 0xfd35b152, 0xc7746abd, + 0xc022dc53, 0x43fa71e8, 0x3cc3b7c9, 0x7db00698, 0x7e6492ea, 0x60a1b59f, 0x15224b84, 0x3b8129d5, 0xfdc7108a, + 0xf12ff269, 0x848f0dde, 0x20709124, 0xbe1c1f59, 0x7b02ec07, 0xe0a33de7, 0x30f71ef1, 0x7170e14f, 0xae14ddca, + 0xb1385957, 0xfb43b4aa, 0x38a57f55, 0x40483ee8, 0x11d1e8ce, 0x43b73e18, 0xcd9a9a7e, 0x8f17e5c0, 0x0809b6ec, + 0x5d19f811, 0x2b192e2a, 0xf7c3a882, 0xe2989ac1, 0xe19e0b4c, 0xd4a764a9, 0xfb765be2, 0x43430c01, 0x033d4e65, + 0x98c27740, 0xb743ae4c, 0x981b2a6f, 0x216ca921, 0xc5e68305, 0xaa3d25c5, 0x8bfac11e, 0xeeb430c2, 0x0402a712, + 0xd75d9570, 0x6140f640, 0x0c6ba95d, 0xef36ecd5, 0x9d01eea5, 0x8dc5e697, 0xc95c5646, 0x4430d8cf, 0xadb09ad3, + 0xaf579c8c, 0xb9c2c479, 0xe9070596, 0x35def6bc, 0xa5ae695a, 0x12d88c68, 0x7b38e710, 0x485781f0, 0xa64cc3cd, + 0x59868e33, 0x57ef9694, 0xbe3cbdc7, 0x812250cd, 0xafdc418f, 0x2c334b66, 0x66f29410, 0xdb672d54, 0xd7fa7005, + 0x04bbda72, 0x401bffe1, 0x3bda6397, 0xdee83d74, 0x48b3aa51, 0xf93dbae4, 0x82bf0135, 0x5cb42b27, 0x6de9561b, + 0x5ef79d2c, 0x88dff390, 0x3351447b, 0x07e1428c, 0xc8bda40c, 0xfcd480dd, 0x3daf5080, 0x8fe69930, 0x7808f812, + 0xe766ccea, 0xa2cedf0b, 0x77f34424, 0xa66c1f6f, 0xf3258a41, 0xc70f2655, 0xd2cbb785, 0xa025c1dc, 0xbb881f7d, + 0x566c847b, 0x0cb91725, 0x82717b6e, 0x65640c2b, 0xe84dcd4c, 0x3996e783, 0xcfaa4040, 0xfb587f4a, 0x8e4cc3b8, + 0x04429bea, 0xb0265f81, 0x736ee1f5, 0x697c860d, 0x8a1af001, 0xf06b4c16, 0xb7ac862a, 0xfad91c79, 0xdbcb11b3, + 0x500ff8ac, 0x5bebc40c, 0x189906a6, 0xf81d951e, 0xbd0ea254, 0x67fd7c9a, 0x8ba67f0a, 0x6bd4c4cd, 0x749348ef, + 0x5c7851e9, 0x4545ec8d, 0x9a11d0dc, 0xe613f4d7, 0xea620597, 0x643c09d5, 0xa5d345aa, 0x0772efd9, 0x75476323, + 0x1404e994, 0x90667e47, 0x7eb45cd2, 0xf967432b, 0x25e487e2, 0xcf0a719b, 0xe49545c4, 0x334d265f, 0x2a65734a, + 0xd6dbf7ca, 0x143c6015, 0xe7c97b9e, 0xa3ec429b, 0x570fb54e, 0x879efdab, 0x35d300df, 0x79ea1597, 0xd3466419, + 0xdc998e31, 0x7884e42b, 0x04eb3a80, 0x4fbb937c, 0x0b4c5556, 0xfddf2b5b, 0x58ea0116, 0xf8adc97b, 0xfa881c15, + 0xae59f679, 0x68eaa16f, 0xb30d11c8, 0x1203ae1e, 0x2f50500d, 0x7c2db2e7, 0xa2682496, 0x59b64575, 0x134c87ce, + 0x5385dc43, 0xa6d57c87, 0x8d1ef7fc, 0xf3fa2706, 0x9d2e9baf, 0x86a09eac, 0x926921e7, 0xe4074b71, 0x4407db57, + 0x3b38f3da, 0xad8c5204, 0xca9e682a, 0xe444b374, 0xd9b74b89, 0x7edc955e, 0x3a2cc324, 0xb6efbe36, 0x31e34581, + 0x08cb3c89, 0x43cef42b, 0x87e952fa, 0x384c9fc9, 0xa2d0e85b, 0x92155fa4, 0x78526818, 0x50217e21, 0x03b6c68f, + 0x8f179628, 0x68ac57db, 0xbc39cf6e, 0x205356c0, 0xab6fb87a, 0x5e8d62ff, 0xcd188de1, 0x4bcbaa66, 0xfc30c0b4, + 0xd0c94117, 0x9c578496, 0x0728f8df, 0xf4ac0aff, 0x05de8ae3, 0xead59668, 0x401c636b, 0x3b9772eb, 0xa9e9f758, + 0x0f4d86ae, 0x1790cca7, 0xa01d6e89, 0x96c1b43f, 0x28a57afe, 0x38154623, 0x98a4228f, 0x61486495, 0xe368476b, + 0xf34cdccb, 0xb1a47fda, 0xaef23da3, 0x00f81eb5, 0x81319f77, 0xeb3be582, 0xe4ce82c8, 0xff99fe3f, 0x1bb596c5, + 0x6372c300, 0xb41355e9, 0xdcbf49f8, 0x551145eb, 0x9b2fff81, 0xdbee7a47, 0xe5733b3b, 0x58a873e1, 0x0835e5b0, + 0xc3cf2d6e, 0xc6a183ca, 0x13a376f4, 0xd5c212a1, 0x3e5928d4, 0x35b2bb90, 0x3247d775, 0x542bd4f1, 0x214acf89, + 0xbb604a66, 0x310818d1, 0xa6f5af34, 0x6758b5bc, 0xee8bcccf, 0x827435ff, 0x5591ae0d, 0x490a54f8, 0x69744653, + 0xa2d788a0, 0xf1412f35, 0x88bece88, 0x29dc3ef4, 0xf5644571, 0xf0decd24, 0x46d33676, 0x33d3cc24, 0x3602f75f, + 0x6dd4006f, 0x83c3ed11, 0x65795ebe, 0x069d7894, 0x4a2752ce, 0x6d9e2dc3, 0x65513f51, 0x0eebc88a, 0x7947b81c, + 0xf3f4bd7e, 0x3ad6458b, 0xcb946a6e, 0xc04b4dbe, 0xce3fa44d, 0xc698ad94, 0x575e3267, 0x243dee3a, 0x90d6d049, + 0xc752d14f, 0x9f746fac, 0x575b1384, 0x0db439a5, 0xbfc95843, 0x85aca0cc, 0xa5705415, 0x66109124, 0xbd211492, + 0xaae499e4, 0xdec5db59, 0xcdec24e4, 0x7ca1917a, 0x170f90a2, 0x3fb15654, 0x4d02010d, 0x7ba50abf, 0x03fb767f, + 0x052f8579, 0x92a78ba1, 0x3db55bc2, 0xe2eb5378, 0x0e27cff6, 0x9dbe77f7, 0xf81a5260, 0x40ce1d1e, 0x8327cb82, + 0x55b309b3, 0x7b60a0d7, 0x2e298adb, 0xb686641c, 0xfe7dfbfc, 0xc2ed292e, 0xb175378e, 0x6153e11d, 0x3f6741a4, + 0x1be112c2, 0x9bcd6f2a, 0x49a3b594, 0xaafdfa56, 0xcdadc04e, 0xd6429846, 0xb50ce717, 0x3003cdc3, 0x9d5b29d0, + 0xbeaa35be, 0xf39452ea, 0x0573b75d, 0x378bafdb, 0x5dbaa155, 0xbbc25b47, 0xcea32a06, 0xbbaff2f9, 0xf5a8be0c, + 0x2c740fba, 0x06ce0382, 0x01235d4b, 0x6f314d35, 0xbcbf0eaf, 0x9c7e8995, 0x8bf1f9c8, 0x97935984, 0x3739209d, + 0x8386ec22, 0xea6e693d, 0x220ee75e, 0x7ff17b4b, 0x09c8df7b, 0xdbd742d6, 0x14e3c186, 0xf9ac7a3d, 0x8ea455ca, + 0x3b84368f, 0xa8ee6d47, 0x34edbf1f, 0x5a0f7f5d, 0x399a0869, 0x3d948a65, 0x1bfbfaf0, 0xb8650c09, 0x4930b379, + 0x57cf4738, 0xb02dde58, 0x6bf4b916, 0x5b8ace5f, 0xf3f41b2c, 0x86af27d0, 0xef77ecc9, 0x2df518ab, 0xa2a9d222, + 0x67045a55, 0xb1aff902, 0x9f448531, 0xf4613c13, 0x1d54af57, 0x9932406c, 0xbd5999a3, 0x5f48ff55, 0xd0967582, + 0xab27e665, 0x26e25c32, 0x6af1b630, 0x9e1b4f52, 0xc4a21587, 0x3858ea9f, 0x091b9c06, 0x57a15813, 0xfdb9d5b7, + 0xdbc47c92, 0x52c49bee, 0x6d3d1fd2, 0x2e02fa8a, 0xd6b8d7e7, 0xcb3b04b1, 0x2d182da1, 0x4540e2df, 0x6a1dedb6, + 0x9fa2cd27, 0x5ff6c336, 0x4f93405d, 0xc8dde1fb, 0x11ce947e, 0xff1f0c68, 0xac722053, 0x4b417845, 0x7a4e1367, + 0x3be7dfdc, 0xd057e238, 0xc20efc93, 0x0c0b2702, 0x8b8cd0c6, 0xac3a7e00, 0xb2f83b88, 0x8f20a9b2, 0x6dd7dc91, + 0x13c3595c, 0x4825159a, 0x88ef3908, 0xdbb05e98, 0x0d43c495, 0x2c155474, 0x0cd8f148, 0xd9060416, 0xfb58f173, + 0xdca6ec4a, 0x06df582e, 0xa734facf, 0xb22b649e, 0xd8156f24, 0x282e00bb, 0x368274ee, 0xc95a3dc5, 0xf91153ae, + 0x07f65ef3, 0xa4bda372, 0x9937ec58, 0xf7a0496b, 0x2be21203, 0x4f3ef476, 0x2277998f, 0xef248c50, 0xea2db838, + 0x61639d35, 0x96c08bb0, 0xe1849b2a, 0xe46471ab, 0xb3c3f94d, 0x0ccf134e, 0xc99773aa, 0xe72e8b5e, 0xd6f947c1, + 0xdd9093a6, 0x9e0f992a, 0x402d59de, 0xf45999de, 0x1a31b2d8, 0x48f22024, 0x35dc2bf4, 0x4959f0c0, 0x351a9a2f, + 0x247a161c, 0x97d1a9d3, 0x9ae1ddd7, 0x634d348d, 0x17d52ccb, 0x66286d77, 0xc07bfcf3, 0x3aa354d2, 0x47230b91, + 0xd622282b, 0xfa166a79, 0x7cf44cf0, 0xa460cd8e, 0xf41f2aad, 0x7afd47c4, 0x1fec884c, 0x309d7ed0, 0x3ba5fe79, + 0x8f60ee38, 0xdcef2521, 0x36416bbf, 0xd2d08e29, 0x47902d01, 0xe33a7c98, 0x8ce45a92, 0xa708f955, 0x4f37761f, + 0x40493943, 0x60ce03de, 0xe00ea35d, 0x3f18c723, 0x8c3f339c, 0x51dd6027, 0xe3c2491d, 0x53e225e7, 0xa4e01fc7, + 0x6bded75a, 0xbb515809, 0xd98057de, 0xc817fbd7, 0xe5bad646, 0x61e4c691, 0xa259114c, 0x272f18bb, 0x56f0a02d, + 0xa6618159, 0x19f26292, 0x61311eef, 0xf70fcfc1, 0xa7869991, 0xddb748ad, 0x0311206b, 0x3bf0072d, 0x61a5dd9e, + 0xe7c19560, 0x5c1ef6ee, 0x26cc301e, 0x159c34b7, 0x31801453, 0xd25ba8b7, 0x4ace5bbe, 0xff2a2787, 0xf76acb79, + 0x7330b47b, 0x928b0afb, 0x8d1bfe4c, 0x198aba25, 0x6fa1afa4, 0x7a542381, 0x100f02cd, 0x204956a9, 0x3b8ea362, + 0xbdc633ee, 0x72bf3747, 0x6ac15269, 0x43dae625, 0xe481f5d7, 0x558a24ba, 0x27c57095, 0xed5d4dce, 0x1f0f244f, + 0xff4a2b37, 0x7b016f40, 0xd3f00c49, 0x26a384f5, 0xd2a79abd, 0x4787489f, 0xb5cbf3e6, 0xb1274641, 0x09556b81, + 0xd3de2e22, 0xea827fe6, 0xd9cb3071, 0x8867fb6b, 0x9375b8be, 0x78d83729, 0xc411f1bb, 0xb9cd9ee1, 0xb8fcec66, + 0xaf192785, 0x17cedbcb, 0x2a5edbdc, 0x53ac9424, 0x3a78f38e, 0xd0231f3d, 0x473f4e33, 0xb5393b74, 0x45c15a06, + 0xe28f4b0f, 0xa8d81180, 0x8e0fd63c, 0xae942190, 0x24cb003d, 0x9e6fc576, 0x8a0fff1b, 0x1f65f5c6, 0x1528a62f, + 0xde380eca, 0x875a1870, 0xaf67b89e, 0x8e2bf7d9, 0xbe92aabc, 0x8f2a80fc, 0xfa289f02, 0x34c7607b, 0x29cbfc6d, + 0x4b182a04, 0xa2df58bd, 0xb27bdb2d, 0x399402df, 0x40e1b25b, 0xa1207a1e, 0x3ea9db29, 0xd786587e, 0x20d8b418, + 0xcd943605, 0x5e38758c, 0xf09093e3, 0xbe1b4b20, 0xbe594de5, 0x7bc8ee4e, 0xa963defb, 0x48214dc5, 0x2f6a632d, + 0x1bcb0eca, 0x403ce352, 0x2192977d, 0x3c0515d6, 0x36c19a0b, 0xd3a581da, 0x3bc6c25a, 0xb0b65198, 0xa79122fe, + 0x67292a9a, 0x2029a42b, 0xf497493e, 0x857381a2, 0xbac248b6, 0xcda16e0d, 0x17dcf0d2, 0x62ec4d2d, 0x64d78ec5, + 0xf5b97bc9, 0xf26409b8, 0xe42f6377, 0xbe40b7bc, 0x19083fc5, 0x6bf532e1, 0xf0e0994d, 0xf5574c53, 0xe232e9cc, + 0x087cffcb, 0xd6ff1737, 0xace77dc6, 0x088014b4, 0xc8d7a819, 0x2ea90611, 0x9674c7c3, 0x6a1cedb2, 0x3300ea3e, + 0x2f09d04f, 0x8ca207be, 0x2b4c6d74, 0x77e93beb, 0x186bbbc5, 0x7fb669d4, 0x323f50bc, 0xe9b77fe8, 0x3c979f1a, + 0x75219c43, 0x567e92c7, 0xa746b7c0, 0x9eeb48a8, 0x0b50da09, 0xbefe9b9e, 0x7844ae39, 0xdf047668, 0x75c6b4e2, + 0x468e68a6, 0x23f084aa, 0x92478611, 0xa8dea7f9, 0x601ec83b, 0x1368e98f, 0xa0f4cfc2, 0xa46806ca, 0xd82e069f, + 0xe30ccb05, 0x65d7521d, 0xe49def3e, 0x953a1eb9, 0x18eb481b, 0x564fd16e, 0xcf859dd2, 0x291140db, 0xc5f0f74a, + 0x385012bc, 0x9937cf54, 0x8922bb18, 0xbe5beb49, 0x0a18d6a2, 0x122b1fcb, 0xd64dc37a, 0x3a9e9674, 0x7a4ef032, + 0x452ef773, 0xf409c9b9, 0x0f4a9a37, 0x213361fa, 0x0a8e95e8, 0xc9542772, 0xd7b75b45, 0x775fc15a, 0x2b0ff530, + 0x2a4c9012, 0xae05c4a8, 0xa269bec9, 0xdf7e336e, 0xa00afb0a, 0x12723181, 0xe9bde95d, 0xd438ec11, 0x9f79b9df, + 0x9a76cd60, 0x9c980039, 0xdd99bbc1, 0x082dc5e2, 0xf1cc90d4, 0x5442abf4, 0xdff7ae52, 0xb34cb0b8, 0x398372f7, + 0x29cb6b28, 0xa8a3418a, 0x8735c728, 0x16093d7d, 0x7023f000, 0xda214edc, 0xa24efb4c, 0x1e85bdb0, 0x166a73e0, + 0xf60ad65c, 0xfb30b1c6, 0xa33dcb36, 0x3b5aebb7, 0xee684bef, 0xa42a1eda, 0x1a0919b9, 0x068b3a2e, 0x0f60b187, + 0x44d39434, 0xf5258975, 0xc28d32ca, 0x37ff0020, 0x538c2768, 0x2ec7dc29, 0x64dd47a3, 0x120e1218, 0xb5188e9e, + 0x13a9a4e0, 0x5ffe4198, 0xc7d6aa52, 0x10ce5b7d, 0x9166b279, 0x222893fc, 0x000199ab, 0xfb2cec71, 0x70f00d1f, + 0xc2c1ae2a, 0xdb69e18f, 0x3156ac10, 0x5e75ccc6, 0x8a278791, 0x03c7f558, 0x13e1dd85, 0x063b736c, 0x47e08301, + 0xc5adcc9e, 0x77e177b3, 0xf9870844, 0xab69081b, 0x5c4952d0, 0x611f5185, 0x996e6535, 0x28d403c2, 0xfefefe74, + 0xc981dadd, 0x27f55879, 0xd67a65aa, 0xec1fffb6, 0x1aa3e9b4, 0xaa28befc, 0x8daa8b96, 0x6c175fab, 0x99938932, + 0xbb6046c2, 0x35c8716a, 0xf371a580, 0xb4a64c89, 0x42df5c04, 0x4c9a31e2, 0xcc133f68, 0xdee36ce3, 0x654ab464, + 0x26f1d304, 0xed56cacf, 0x1cddbb62, 0x2732a0f9, 0xadcecab6, 0x096f3d35, 0x1ebdae49, 0x391208d5, 0x9f9491b3, + 0x37ed158b, 0x66b55f6d, 0xf8545c74, 0x122bc9df, 0xde62692c, 0xa5868ffd, 0x47b42a4a, 0xe69c2eb8, 0xf5b6cc7b, + 0x007bed40, 0x1aff0474, 0xd0e39636, 0x5f530d11, 0xd87719d9, 0xd3722284, 0x28cb555b, 0x41bf5672, 0x782eeedb, + 0x92c15f09, 0x60e08cdc, 0x7f7ab743, 0xe248b8ff, 0x382dbe62, 0xce1ad2ef, 0x27e2bc31, 0xdbae345d, 0xfa0b8af0, + 0x56ee53d3, 0xe13f8b54, 0xbe948079, 0xf98bba10, 0x3748356b, 0x1acb66a7, 0x5fc4bfb0, 0xbc105943, 0x3a43005e, + 0x28ab7c14, 0x19192531, 0x1711352a, 0xe0ee0a1d, 0xaf2c95c6, 0x844134b9, 0x99727ea5, 0x86bec715, 0x0eae2cd1, + 0x0add917d, 0xc094c806, 0x701690f4, 0x19433095, 0x5a06ec00, 0x3683a515, 0x0397fedd, 0xe6254c48, 0x9a470663, + 0x6fbbfa49, 0x13c3583d, 0x507ad1e1, 0x652ded59, 0x0fb949aa, 0x6f8774ff, 0x2a98d2b0, 0xe6da2079, 0x0cd4046b, + 0x384e76a7, 0x80efa19d, 0xe19c9feb, 0x495b21e4, 0x7233efcc, 0x33f908f9, 0xbd8f4ef2, 0x90f35a60, 0x63649aea, + 0x63e6b294, 0x9cac0bf9, 0x609cb396, 0x97e4bc86, 0x811cea85, 0x833bba39, 0x42bde702, 0x0905937b, 0x06e31080, + 0xc5e74081, 0x8f202822, 0x11de61e5, 0x0f677efd, 0x988cf7a8, 0x84027db0, 0x412841ca, 0x5cda8b3f, 0x2e25793e, + 0x270d5252, 0x2e00dc87, 0x697698cf, 0x07c4611d, 0x4662018d, 0xf519742b, 0x0bfb7809, 0x8d850de6, 0xf2e778b3, + 0xb17e23f5, 0xfed63c78, 0x0a91cbcc, 0xd36e3f51, 0xf4e8e5e8, 0xd9e768e8, 0xb96f81e7, 0x025558a7, 0xad052712, + 0x50020846, 0x1921db41, 0xb56bc2ff, 0x65eb7feb, 0x9b25057e, 0x8aa274dd, 0xae0c02cf, 0x6982ca32, 0x7c1bb219, + 0x53fc0c69, 0xfcaced0c, 0xa0174ff0, 0xdfb39cd1, 0x6e19661f, 0xc634a1b3, 0x3696a6a0, 0xa84951c3, 0xe3947fba, + 0x10b6cc05, 0xb311034b, 0xb57f0073, 0x19d391ee, 0xda365705, 0x51d3ba1a, 0xb6e05a5a, 0x433c51dc, 0x431490c6, + 0x75a7b737, 0x31f4b0dd, 0x52b94ea8, 0xe5f4c2f3, 0x98ecd97a, 0x19b8854b, 0x87b642e7, 0x57b17eb2, 0x9d1608e4, + 0x9201f6cf, 0xad676501, 0x172241ad, 0x2d142ce8, 0x0fa9f182, 0x980b7833, 0x3a069cd7, 0xb2d2de47, 0x8584bf4c, + 0x4b26f776, 0x9e1e375a, 0x1a7ca531, 0x89e0cba0, 0xa1dbf0fa, 0x034272fe, 0x1ce2966b, 0x12bee2f8, 0xf080f8ca, + 0xe764e9f3, 0x254007ff, 0x4e86b676, 0x5a4dc844, 0x3792330f, 0xa2890174, 0xfc85b67c, 0x0e017c7d, 0xf0e5d353, + 0x0363b782, 0xdc7d9c64, 0x10df5e6b, 0xba5b2303, 0x1232c227, 0x585d1cd3, 0x4b6a5c32, 0xc56d0435, 0x443f268a, + 0x0fffbe28, 0xa7a89062, 0xb9a4f77b, 0xefb6b14b, 0x2f8784e2, 0x67759aea, 0x8b77088a, 0xa46bacad, 0xe615fb97, + 0x76574743, 0x13f3176a, 0x69f2d0ba, 0x6f9680e2, 0x8c706622, 0x18bb95ce, 0x4c076d8c, 0xf4bbc30a, 0xb5bdc6c2, + 0x95f0e575, 0xc7435a2e, 0xf98ec4b5, 0xf84c2497, 0xafaffe4a, 0x7a6cac4c, 0x132d51ae, 0x5340013c, 0x7c6652e2, + 0x75691e34, 0xdd28ef69, 0x49c56b7e, 0x4857e6f4, 0x83d6b199, 0x01a3d068, 0x219fa20d, 0xcfcb591c, 0x5c24ff14, + 0x5ac5d31a, 0x44f98ad4, 0xaf3f3a72, 0xf024bfed, 0xeafdabff, 0xf370f75d, 0x7081f3df, 0xea3dca23, 0x5bf5cd5f, + 0x524cf7a5, 0x0e39462c, 0xdacf2b7a, 0x04e6c4e8, 0x146ffbc2, 0x37b565f2, 0x909882c6, 0x2b6f9a14, 0x0b1504be, + 0xdf78557b, 0x5b7720f9, 0xc2f7a85d, 0xb73ec496, 0xfa0affc3, 0x2a99922e, 0x01ba4a67, 0xeb08f7f1, 0xd2843a1e, + 0x693017bc, 0x5a6ee88f, 0x2efc5cfa, 0x1abd0699, 0xe1b636f0, 0xe537e3ff, 0xdcb79179, 0x6bad575d, 0xa48b8acb, + 0x057fe259, 0xa6821524, 0x63c2f25c, 0xcb303b9e, 0x07812eba, 0x57bcbf0e, 0x07344705, 0x1a4935e4, 0xc02fab69, + 0x26a5f88e, 0x3305ebd3, 0x06b91ecd, 0x9fc11234, 0xfded8b78, 0x54ffef09, 0x9bc51fda, 0xcdee8e0d, 0x4cad4e97, + 0x570fb102, 0x4189dc16, 0x1e88b6d3, 0xb2fb9270, 0xa3e00716, 0xe6fe2812, 0x33e13c9a, 0x0ccd53a4, 0x80afcbfb, + 0x7a9ce12e, 0x1370aca3, 0xa5aa7bbd, 0x927b11ac, 0x8b63b48e, 0x5adb5801, 0xf7bba60e, 0xb508ba9d, 0xd4b204eb, + 0xe0baab4d, 0x0d13b01f, 0xb83e8897, 0xfa889175, 0xacf0bb7b, 0x40de0a27, 0xb967cfc1, 0x46bbd276, 0xbfd36c20, + 0x2852dc2d, 0x47d1b6b7, 0x78a3a653, 0x8de1d67d, 0x5eca7f9f, 0x80d1a192, 0xa0439874, 0x6de2b5bb, 0x81613756, + 0xf78f4240, 0x2b6528c2, 0x14622c5a, 0x93af94eb, 0xdfeb7152, 0xa1774bf5, 0xd13cdfee, 0xdc99ca8b, 0xfe595996, + 0xcb733e3a, 0x00e9a3b9, 0x9e77cafb, 0xf35a0c43, 0xd6d633a9, 0x7aea394d, 0x28e35faa, 0xcc6cae51, 0x6aae19e5, + 0x12b87053, 0x33f9f8d5, 0x4cca7be0, 0x87ee1b79, 0x146165e1, 0x0ec540bf, 0x4985afdd, 0xbad80105, 0x67bb336a, + 0xbce2f3c4, 0xc54d4c2b, 0x89cc7ab3, 0x36756934, 0x1e9ebe56, 0xf74d53f3, 0x8121cd1e, 0x4e2a0461, 0x41b5db6b, + 0x8b398ab7, 0x71270008, 0x4f2f8dec, 0x036e99c6, 0x29a434d4, 0xa0e6d12c, 0x8f5d6c63, 0x06393502, 0xe1f12853, + 0xf98d6097, 0x983c5be2, 0xd8b242ad, 0x25cdc85b, 0xab718fe7, 0x4ff1d4de, 0xfc204e0a, 0x846be492, 0x1a0bae8f, + 0x0c0bff53, 0xdb92fc09, 0x209146f6, 0x84d0c3d9, 0x36668f91, 0x61e27250, 0x6c17ab96, 0x67fddad4, 0x922c1f89, + 0xd4a3d7ab, 0xd110172f, 0xdd98e630, 0x0fa2804b, 0xf6694787, 0xfe499a5b, 0xf82fbec1, 0x07c020ce, 0x7bd4d489, + 0x8ac0213c, 0x395e4c79, 0xc57ba921, 0x4f7d7f27, 0x736d6576, 0x34f41423, 0xcb3ca566, 0x98b9cf54, 0x36186d3b, + 0xd75fa51d, 0x2f94396e, 0x6cbe5ea2, 0x1a54bac4, 0xf38c8383, 0x0a296f3e, 0x8d7021a4, 0x1c5fdf3b, 0x3fc25cf8, + 0x9bcb72f6, 0xb449a3e5, 0xa3f9af2d, 0xdc19491a, 0x8539db67, 0xc2b9ee94, 0xd2187500, 0xbb86b09a, 0xf868a005, + 0x57cdfe05, 0x6af9dfd0, 0xda8979a4, 0xa0416a5f, 0xa45601f1, 0x666f5cf1, 0xc474910d, 0x594eba76, 0x945ed50a, + 0x3524c55a, 0xd91c6caa, 0xb222349d, 0xe2c412d9, 0xb4907766, 0xb0bd6ea1, 0xbff6c808, 0x5ff6c66f, 0x7b0aacdc, + 0x54d62d2a, 0x56856b94, 0x64343d61, 0x25766d92, 0x8ca96ed3, 0xf3f6cf6f, 0x0037aa15, 0x5b5c283f, 0x283853fa, + 0x647199fc, 0x90ff5e80, 0x95291665, 0x69b92c55, 0xa431f928, 0x5dd1b8b3, 0xa3722edc, 0xf8c43365, 0x1cd90e97, + 0xce87d31f, 0xee82b357, 0x862c91f5, 0x770e7eb3, 0x231d392a, 0x6a17bc7c, 0x4c65c176, 0x26a3cd79, 0xd8ee9bfe, + 0x5d883aef, 0x88dc48e2, 0xa976b05b, 0x6f9f9faf, 0x21f7eca9, 0x27698a1b, 0xf92f7873, 0xcfc92ed4, 0x71d2a74e, + 0xd205ad74, 0xeb8d8771, 0x50b2e6a8, 0xf4fa25a7, 0xe9cedf18, 0x597aa6ec, 0x71b88e60, 0xf6685e22, 0x6661ef4b, + 0x15d37c5f, 0xb0409bc9, 0x4e8a2a75, 0x3057fabf, 0x1aa72645, 0x9954fadb, 0xc1c26c32, 0x8738f075, 0xe9375e17, + 0x29b3e7a7, 0x045af40d, 0xf95d5f1a, 0x70d74521, 0xb61b5911, 0xb77cb2ac, 0x8e73b3b2, 0x127a83a7, 0x73384682, + 0xdee59cf0, 0x6aa43832, 0x9c7913fb, 0x3100e7d3, 0xe768c1bb, 0xf31c4d68, 0x2a93136e, 0x69dd7ca1, 0x0f37d409, + 0x6bb9289b, 0x6d9e021a, 0x94354885, 0x6bfa34d4, 0x1d93173c, 0x34825729, 0xee87c5a3, 0x8abd5893, 0xdbedbaf2, + 0xdf33c24e, 0x58a473ef, 0xb1ba95e9, 0x12e39eee, 0x34b78679, 0x8f9a9636, 0xd778b8b9, 0x71521535, 0x6c24087e, + 0xce6dcdfa, 0xeca19062, 0x652807ca, 0xf4f8b606, 0xb0254c77, 0x1839dd4b, 0x22257d6d, 0xf3fbb682, 0x63d4bf3f, + 0x2e11e910, 0xae46f4b5, 0x54b116d9, 0xce6d05fb, 0x365a3fc4, 0xfd780340, 0xd22a578d, 0x50da8b69, 0xbe6f7cd4, + 0xede0d6fe, 0x9ef71b70, 0x646ce1f4, 0xe1e9b381, 0x8a5e346a, 0x1f02711e, 0x19a8c643, 0x7aa4f018, 0x3633de16, + 0xecc3145d, 0x0bd0302c, 0x55c73053, 0x7a21c878, 0xf248f046, 0xd1ab55c9, 0x4211bc70, 0x1eeeec79, 0x9037c012, + 0xb64dbf67, 0xb17f7b70, 0x26eb6ade, 0x62fb5dba, 0xa3ab225d, 0xdf9f3a0e, 0x5b4baeaa, 0xca49697d, 0xcacf5f3a, + 0x32ab8120, 0x8115451a, 0xa3d5c7a2, 0xa8559c3e, 0x47dc2208, 0x7cd6afc7, 0xab7f9a1c, 0x18444e11, 0x84555cf4, + 0x4004fc49, 0x197b76e0, 0x302c153c, 0x6d8dec28, 0x70ea2d07, 0x53017429, 0x5264769d, 0x8ece3aaf, 0xf12f9147, + 0xd9d1a434, 0xd8adc548, 0x8ed400fc, 0xed4623b2, 0x2e5a6e8c, 0x5d470cff, 0xc3d0ae79, 0x36ea6379, 0xfa1da697, + 0x2ae0bc7b, 0x60f9e9ad, 0x46247a90, 0xa5afb6a2, 0xa2393b68, 0x32acaf5d, 0x7452fa26, 0xafac836a, 0x210089d9, + 0x77610aaa, 0x4256fa4f, 0x99c17144, 0xf4dc5205, 0x758e5ec4, 0x702ad7a2, 0x2fcbcede, 0xd4275711, 0xff61a60a, + 0x11f1feb5, 0xc7dbb227, 0x75eb6569, 0xe020a6e7, 0xe46e3ced, 0xb26f1e7e, 0x8eb630f4, 0xe582ed7f, 0x8183dc0d, + 0x184c1beb, 0x6d31b88a, 0xf044dd5e, 0xb3d401c1, 0xf0e51344, 0xa6688987, 0xd2ca5e35, 0xaad441a7, 0x57e72d04, + 0x1215cf46, 0xddf8e411, 0x99a4c134, 0x5883db16, 0x03d5dda8, 0x1f38182a, 0xc8ecaa7b, 0x4b6158f3, 0x5d853680, + 0x187ebb21, 0xecfe64ba, 0xb4cde209, 0x92a39ac5, 0x382f4fd9, 0xa5ee95ec, 0xb60d4b91, 0xd3aaade6, 0x036f53c0, + 0x48be01ac, 0xea4026a0, 0x81f6380a, 0xc70c751f, 0x28067057, 0x9f276fcb, 0x9c7f143b, 0x4ea1dbb2, 0x3075bd17, + 0xcaa0b95e, 0xf9b38e19, 0x64b6b6a6, 0x462472b4, 0x3f0dbfec, 0x11dfcad9, 0x9325c5db, 0x5709eb63, 0xecf990b7, + 0x55809405, 0x73ff3abc, 0x5ca0fb24, 0x25853832, 0x4d30771c, 0x85036ef4, 0x4a4104b3, 0x54408c55, 0x20008e60, + 0x37b22d60, 0x283ca33e, 0x4754f561, 0x8607491a, 0x88978542, 0x4c8ad486, 0x5dabee84, 0x154fd236, 0x272368c6, + 0xd52133f3, 0xfd77c4fe, 0x489a7d4c, 0x4cf70628, 0x9cee481e, 0xb9a2bfea, 0xc5dbbe6c, 0xdfdb0a7b, 0xc5895a05, + 0x56148782, 0xb49c5add, 0xc8daa650, 0x95826e3d, 0xa1d72ffe, 0xce56035d, 0xe1913227, 0x11163e87, 0x0582b74c, + 0xc9f8cf99, 0xcb150409, 0xe1bb8210, 0xb4702fa8, 0xac996168, 0x13eeff38, 0xa6314763, 0x53744784, 0x2fdf990b, + 0x77fa42f3, 0x81f99f07, 0x5a28e81c, 0x35943417, 0x2acc05c7, 0x9668ecf5, 0xc4b6a265, 0x491c8975, 0x04d00915, + 0x4df71d5a, 0x2bc231a2, 0x4a0b1158, 0x4898bc14, 0xe92bc87c, 0x2b684dfc, 0x4937a49e, 0x13b7d1db, 0x9c8991a9, + 0x4e1dea8a, 0xbe1b6779, 0xc96fad57, 0x54ed46b8, 0x764f0ca5, 0x6d63c152, 0xed856015, 0xe82f8a7a, 0xb8114855, + 0x82bfcbfa, 0x18344ca5, 0x5f2828a3, 0x3f423ece, 0xe038de22, 0xe5abc5ae, 0x6cd6b8c7, 0xe4276411, 0x223fab7a, + 0xfa418459, 0xfefb133c, 0x9e150643, 0x22e8b2fc, 0xb5d4eb71, 0xa78585c6, 0x7af88136, 0x93d305aa, 0xe12faab3, + 0x0b790fed, 0x70047367, 0x34d1310b, 0xf152198f, 0x3582d46c, 0x59ff74f3, 0xc68abb1c, 0xf3fb3d5d, 0x1665936a, + 0x4d42b467, 0xc8a80f58, 0x6442e825, 0xd0e4bdc6, 0xedb22328, 0x2e763d7b, 0xaa797443, 0xd98f3a2e, 0x0ee0265a, + 0x9b827b2e, 0x0fdd049b, 0x2edb1de0, 0x72823a3f, 0xc4323857, 0xe1ae5c6c, 0x5492a3d3, 0x98bb89ac, 0xd3285382, + 0x23f4b58a, 0xcf83045e, 0x1497a05a, 0x6d8a9946, 0x47ba358c, 0x6df6f146, 0xf1d5961a, 0xc7a396f4, 0xb35a7667, + 0x5ff3ef8e, 0x21dc913a, 0x7e26640f, 0xebc4bbb5, 0xdb9b83b6, 0x8ce889e7, 0x359e58ca, 0xb007fbba, 0x1c201a30, + 0x57afe3c2, 0x2c8d9be1, 0xa1c63635, 0x525075f4, 0xaece02dc, 0xca9d9659, 0xae64cb26, 0x18ec76b2, 0x17168953, + 0x349a5f14, 0xb759de72, 0xd39d2a2c, 0x5381e874, 0x23cd3166, 0x503b3cf6, 0x2b146629, 0x188b83ad, 0xcc252bc1, + 0xd2624103, 0xab623806, 0xb0b2dbb3, 0x7fd2c6f8, 0x5ff2654b, 0x4d0f0178, 0x6dbbf582, 0xe50a6776, 0x454a4e41, + 0xad628693, 0xea2f96da, 0x63a61d7c, 0x92806296, 0xff643ae9, 0x129bf08b, 0xd2746e8d, 0x7f0b3e09, 0x7901beb3, + 0x9357407d, 0x7604253a, 0xaa891af6, 0x95ef172d, 0xc1fc0e06, 0x2855996d, 0x5f1f93b1, 0x1487193e, 0xbdba51a7, + 0x272a9490, 0x6e06b560, 0x66820366, 0x607a7ef9, 0x5fb41685, 0xad10cac5, 0xb897001e, 0x79c46cd6, 0xaeae2d82, + 0x73d9f64f, 0xea03826d, 0x3fd30419, 0x1d31729e, 0xd6962112, 0x5e52c2d9, 0x70882c45, 0x2d8519db, 0x6ab266a0, + 0x4a5599c3, 0x0debb06a, 0xa99283f7, 0x7eb657cf, 0x20414a9c, 0x672926f1, 0xaa6db581, 0x3dc1736e, 0x04c58fb9, + 0xb2a0d3be, 0x0a5bce16, 0xa3f87b8a, 0x26e8a951, 0x98e5ac17, 0x7d293432, 0x23a5cb3f, 0x1f72d5fc, 0x382d434b, + 0xde5028f2, 0xa16ffe38, 0xe5b7dcf6, 0x75f965ab, 0xe1411ed8, 0x52bdc72c, 0xcdd1728f, 0xcae8a550, 0xc52c30f4, + 0x70bc7e96, 0x0ef91323, 0x7ef6c6bf, 0x7118d16b, 0x014bcffd, 0x8d8833d1, 0x1595cb2e, 0x3e938a81, 0x8b66fd3f, + 0xdfb83092, 0xb4052ee6, 0x493acedc, 0x92fc7364, 0x17fdd45a, 0x83bb32a1, 0x3d6f7d50, 0xc9a812e0, 0xb51d540c, + 0x207e362d, 0xd1519fa1, 0x437207d2, 0xc2ea53c8, 0x37bac0cb, 0xdaa959ff, 0x4868cfea, 0x3bfb7212, 0xf5319ce9, + 0x6d1f5138, 0xa4e0bc76, 0xa243b530, 0xa3ae409b, 0x4f5afbbe, 0x0426b7de, 0xb599ab5a, 0x4aca7a9a, 0x4a013f60, + 0x478447b4, 0xef3454e3, 0xe04d3f3f, 0x10c2965b, 0xa9a1561e, 0x7855c7db, 0xd5492f60, 0xb91731ce, 0x1b23a40d, + 0x139aff83, 0xaf6fced6, 0xfa7e32ce, 0xe7c68a8c, 0xb9235541, 0x320b1aab, 0x4c5188ad, 0x3daeba08, 0xe1e480c7, + 0xd374e923, 0xe2d3d899, 0x0cee48ca, 0xc54752b1, 0x3dce7208, 0x7e6efb2b, 0x2cc1bba5, 0x737e6aab, 0xcea50780, + 0x23631726, 0xbc9e30ae, 0xd7e2f4d3, 0x00816968, 0x759e5f78, 0x0ef9a9d6, 0x085174cc, 0x1d4831cc, 0x8aeb919d, + 0xa28519ae, 0xc1c828c8, 0x63da5a91, 0x460dffa1, 0x93cbf6e1, 0x6cf85e78, 0xaf4804a2, 0xcf22a60b, 0xbda9c462, + 0xbf8da94a, 0xec02147e, 0x70deb93d, 0xc216fc02, 0x0172c81f, 0x7c442a6e, 0x5a3ed101, 0xa541a494, 0x0a6c8626, + 0x2cf0b91d, 0x1defa0d7, 0xa048ddad, 0x3cc379f5, 0xafd9e034, 0x5ca4b9de, 0xeb3ff5bf, 0x54b013c2, 0x91ee4534, + 0x3a096bfd, 0xe7bc8454, 0x4501f0b9, 0x9712c0f6, 0x419d2c04, 0xe2db6ca7, 0xbe4404d4, 0x3a1f0432, 0xb68e274c, + 0x269de9ca, 0x3acc056f, 0x6e4ae81a, 0xf6791373, 0x33558708, 0x8df4c0ff, 0xb465ceb9, 0x1331cdc1, 0xe9aa9270, + 0x2f97ea74, 0x5872177f, 0x14b1cdce, 0x28aa8101, 0x8f001ecc, 0xbf572c98, 0x9baec0f7, 0xde992082, 0x38ea75b7, + 0xcaf67bce, 0x05b9b0a9, 0x084ec022, 0x63cc1912, 0x5a1a825e, 0xdd1dcc03, 0x75acdd4f, 0xd876df48, 0x4811bf49, + 0x85d6f686, 0xca0e24f7, 0xbd0f8a59, 0x62ce6b0e, 0x4c7c4420, 0xd159ce23, 0x3b229312, 0x0a536691, 0x73780168, + 0xaa645b82, 0x9562bc6f, 0x9d2ac53c, 0xde9a30b8, 0x011d930f, 0xcb013890, 0x4f088532, 0x071b828d, 0x8510c16b, + 0x69a5258d, 0xae651c62, 0xc7ae190a, 0xbba1f886, 0x7079d0da, 0xc9be309c, 0x76499995, 0x1ede3259, 0x7c402ad6, + 0x4f3c7fa6, 0x2f09d256, 0x187fb4b0, 0xba622291, 0x9b3dcbb2, 0xddddb3d9, 0x814bf1d3, 0x9d0e8fd3, 0x345228b6, + 0xcc74df2e, 0x5e74bb64, 0x0d402bb7, 0x5d2f27f2, 0xfe7379ae, 0x0d12060d, 0xc420ceb5, 0x761600ec, 0xf6c93e18, + 0xaca27417, 0xce277ec1, 0x378f9a26, 0xaecdc58c, 0xbb8fdfda, 0x223b944b, 0x3da45c45, 0x4327e2b7, 0xce2ab3b2, + 0x07d56c10, 0x7938f5a2, 0x10bd28c2, 0x926aa892, 0x25842a89, 0xeba490c2, 0x6323c31f, 0x63b8184c, 0xa9c51ad5, + 0xb26ae30e, 0xffcdeeae, 0x55679998, 0x6f8a0ef6, 0xec6ada37, 0xa537e1a8, 0x5a3ca646, 0x796aeac0, 0xc9758af0, + 0x9b98bb81, 0xe1123324, 0x404e0fa1, 0x87568923, 0xbcf0e511, 0xda793403, 0x6496a0ba, 0x8cb20ba2, 0xe91be1eb, + 0x8e08c456, 0x7265c78d, 0xf2dcfbc0, 0xe3e90c6f, 0x7cfbc805, 0xf7f6587b, 0x10e316c7, 0xc8a3450b, 0x5ac9ed8b, + 0x784e7694, 0x7c327e6a, 0x385cc5aa, 0x17181fbe, 0xd591854c, 0x4b90b7ce, 0x07359d36, 0x4222a244, 0x77730c14, + 0x84cbc38c, 0xdb4ea144, 0x7bdf9808, 0x4463cc5a, 0x4a7c63d1, 0xe77aad93, 0xb5e6544e, 0x0f11d22f, 0x2aa39d01, + 0xf12f37e4, 0x4790c80e, 0x4e9c647a, 0x65a4eefd, 0x0d805996, 0x9c5b12f2, 0x4f223666, 0x61c8a905, 0x402b9073, + 0x69d66ea3, 0xccb0ed7c, 0x10b76d9b, 0xdc17621e, 0x72df2a48, 0x14a4ede6, 0x22a4aa42, 0xb190f075, 0xda64fc10, + 0x8dc3b6d8, 0x57355387, 0xb77753e3, 0xc9f60dd8, 0x322873e6, 0xa63d3c5a, 0xaa5a1405, 0x83b01cc5, 0x59caa06c, + 0x60a7679a, 0xba3fffbc, 0x115e6c78, 0xf9d53d0f, 0x156502be, 0x23863a4c, 0xeef8533c, 0x38df6ab4, 0x6688fed0, + 0x4e244239, 0xad8176cb, 0xe85d09f0, 0x46482890, 0x8e84c144, 0xeb95a272, 0xf96d5568, 0x50712dce, 0x851801d2, + 0x3e327029, 0x0a7530b4, 0xd9a0ccd1, 0xb0004c10, 0x6814106c, 0xe5f0e378, 0xe1c3a06c, 0x0568167b, 0xc98f2a49, + 0x81b30e5b, 0xca600317, 0xe3cedb91, 0x2e4c2765, 0xe9bed1dd, 0x2e81cde1, 0x47143b2e, 0xee8db977, 0xda19010a, + 0x9828b86c, 0x52b5ec73, 0x3c6cf714, 0x6e06ce25, 0xc3b167d2, 0xec28efdd, 0xeb5f317e, 0x2d800b45, 0xbc9c66a2, + 0xad00f7b4, 0x8de98e5d, 0x42efe401, 0xb2d76a82, 0x0bce7cf5, 0x3d82a187, 0x54596446, 0x5efb5e89, 0x51d5e3a8, + 0xba48e535, 0x67a4e602, 0xd4dd5af2, 0x87277755, 0x6af91469, 0x6349f3ef, 0xdedb23b8, 0xbb0168bf, 0x70ce5a19, + 0x9d165e07, 0x4036e010, 0x7ca7427b, 0x63b57444, 0x9d926af4, 0xfd05927d, 0x8eb6dca5, 0x07da75eb, 0x70f4aba8, + 0xdf940234, 0xb2b144ea, 0xbc676561, 0xf3dd24be, 0x0d8afacb, 0xb4456c39, 0xfdbcacd0, 0x9ef7e496, 0x9b22f22b, + 0x5730dad5, 0x2de683c5, 0xd640bb37, 0xd295e5bc, 0x1a12a1e5, 0xfba2270e, 0x10b4cc8c, 0xbc48b093, 0x209aa958, + 0x2f953ba7, 0x06774a75, 0xe2b9ecc4, 0x608a0cba, 0xe6d8fb78, 0x90ab32cc, 0x6cbeb485, 0x3b46a8d1, 0x14f6f869, + 0x90ce4081, 0x9471fb3b, 0xd31f00ca, 0x575b5dca, 0xa0c54be4, 0x72100561, 0x4cbd298b, 0x789784cf, 0x6e424337, + 0x880a95a0, 0x09cb2ad3, 0x1d81c544, 0xcaa12d53, 0x4920270f, 0x2d0e7853, 0xbacf8c7a, 0x23b0578b, 0x118dfbbb, + 0x7b4f37f1, 0x1e4f85e9, 0xb4159feb, 0x2c277d00, 0x0055604e, 0x8c3cd628, 0x61cea805, 0x477d94d7, 0x3a2e14eb, + 0xa0b04a27, 0xb5a00072, 0x2087c666, 0x716d1907, 0xfc34dab6, 0xe99e934e, 0xae970e44, 0xff8b6510, 0x94cfe2c6, + 0x12d4804d, 0x3d621f79, 0x7bad8594, 0x124952b3, 0xf22ce5ad, 0xde05ad88, 0xa5c4124e, 0x56002c30, 0x3c173ffb, + 0xe43aee14, 0x7b930967, 0xd0dec2df, 0xc585b506, 0x851122f2, 0x4e371180, 0x69886a34, 0x2b36c219, 0xa07260a7, + 0x33cda092, 0x6c8fdd79, 0xff00eaf4, 0x8d92e487, 0x2988033d, 0xc3fc03de, 0xa33557a7, 0x2c530d55, 0xfbfa6283, + 0x4885e8ff, 0x8846e899, 0x79fc2661, 0x7bee2d32, 0x89502c2d, 0xc1e80d24, 0x0920abf6, 0x59422c97, 0xcf6d4aae, + 0x4f6c9659, 0x814c8da4, 0x264cace4, 0x4e7a4a1d, 0x63b8453b, 0xe404e817, 0x035c4539, 0xce1e7fe6, 0xaca5c565, + 0x6da74eec, 0x3949fad2, 0x782261b7, 0xc0acb7f1, 0x352cb334, 0xb24598f5, 0x58852617, 0x35ba99bf, 0x55a0ca02, + 0x934fecf8, 0x5fd90778, 0x870e69f1, 0x4bb1cceb, 0x0b62fe8d, 0xe16b13f9, 0x42a1a505, 0x5e8622a1, 0x848a353c, + 0xa9ecad3b, 0x5ecf765a, 0x993eda60, 0xbdf077d2, 0x0da620c1, 0xd7eeeab2, 0xc43cb0ec, 0x0c4d5e02, 0x8df12ef2, + 0x579c7317, 0x29aacf64, 0x22d1b2e3, 0x95ad158d, 0xf1ab1865, 0x47da1bcd, 0x11f77659, 0xdb60d0ff, 0x217ba993, + 0x2f3acdef, 0x42aaeb38, 0x9d49522b, 0x9526b71e, 0x159ff316, 0xe8c76d8d, 0xfea29d96, 0x53ec91d6, 0xe26e4151, + 0xaaf3ef3a, 0x28b9e338, 0x548917c7, 0x1004e56b, 0xd1940e9a, 0x5081a098, 0x96bd3c82, 0x41ae4c69, 0xd74455c7, + 0x5d077137, 0xebe24b89, 0x62a5b3ea, 0xcd3ea1a8, 0x08bbbfe7, 0x5b4cdfdf, 0x1f268987, 0x3c68433a, 0x9de45229, + 0x1fa81636, 0xa957f77d, 0x21383bd2, 0x1125a1ea, 0x7bca1fbf, 0x9b3da016, 0xde31a248, 0x1028be6a, 0xfef15cd5, + 0x33262ac1, 0x2e849b99, 0xb9641ddc, 0x961715a2, 0x7c93d8a2, 0x6a673da2, 0x8a1f1a44, 0x061f103c, 0x83f75ac3, + 0x981b8c87, 0xb3840905, 0xc8395a34, 0x364e78ff, 0xe4ac42c3, 0x1a766899, 0xcaff3adb, 0x280f26d4, 0xa27c3757, + 0x6edd6959, 0xf6e65e34, 0x5f35713e, 0x380005e1, 0xa25fe4b1, 0x98e47159, 0xf6fc3c12, 0x2740dae1, 0x4cd1aa0e, + 0x9a0f1dfc, 0x0ac9f41f, 0xafc971dc, 0xe692d5e6, 0xd39529cd, 0xce4c7400, 0x74fa10f3, 0xb58cd057, 0x273904bc, + 0xf03b7a43, 0xef9ac73b, 0x80d43c13, 0xc06d586a, 0x7bec95dd, 0xc1b23b0a, 0x9378010e, 0x15066399, 0x3dd94a48, + 0x4c73d072, 0x5f1f9773, 0x130c17da, 0x4e4d2466, 0xa5085887, 0x4f04807b, 0x2447af29, 0x8135ac08, 0xe4265d55, + 0x9ade7da0, 0x703f9b73, 0x9df41671, 0x7eaf5cd7, 0x2014bc81, 0xab7a885f, 0x7db9fabf, 0xfe2a2fd4, 0x5400298d, + 0x29f65d52, 0x07c96e72, 0x3ddeb230, 0xba5d66c1, 0xde88533f, 0x805bb8d5, 0x8f4ed04a, 0x39794132, 0x6341de78, + 0x2bfe8227, 0x911697ff, 0xc5aec6c2, 0xcc40133c, 0xbd68a51d, 0x6c6426d3, 0xa5e8469f, 0x4fbb337f, 0x7b0cffc5, + 0xbc84a25a, 0xfd56d8e9, 0x44e5a533, 0xb5a3a7ab, 0x65fab48f, 0xe50e19e0, 0x7e00833e, 0x1cfb1648, 0x91d8e313, + 0xd3752edc, 0x072e1d85, 0x4e07bcdc, 0xe111bbd3, 0xfe9cada6, 0x9abc1938, 0x6da35bfc, 0x09af4b80, 0x22a48350, + 0x7a3014d5, 0xe4be0fe8, 0x18363a14, 0xdbff7db9, 0x7e97d1de, 0x68b87c63, 0x0594cbed, 0xfbfdbe1f, 0x0cd89295, + 0xd2dc2d60, 0x237fb9b4, 0xa6ec5ceb, 0x156e4c0b, 0x1f61e3bc, 0x6165cbb7, 0x3ab82985, 0x689ad453, 0xa20eb500, + 0xdd6cebaa, 0x89bb20ab, 0x1fcdaf51, 0xa2b7dc9e, 0x8842267a, 0xea4e2b68, 0x849f5de6, 0x3843f7df, 0xdaf3c918, + 0x25ac9291, 0xf0b2f842, 0xce3b267b, 0x9e2efe99, 0x983b5b7b, 0xec0f6133, 0xb53d8feb, 0x068107c1, 0xb92ae30f, + 0x14811d9e, 0x6704f375, 0x60089e8b, 0x9e5f6cb6, 0x03c30403, 0x791ff031, 0xaf27b300, 0xc27bb931, 0x00157043, + 0xa7e72697, 0xcb849dc2, 0x18673daf, 0x241d4798, 0x76718f00, 0xbc1a1e98, 0xbb432fe7, 0x7ce04176, 0x063cc7dc, + 0xbb92040e, 0x68085bbb, 0xa0b390d7, 0xb8bf4a3c, 0x7286ed2e, 0x50fe5bd1, 0xbbc407e1, 0x0b2a2ea7, 0x00800d21, + 0xa84c7027, 0xe32cbddb, 0x31f93abf, 0xc60eb02c, 0xcfe80483, 0x0109b6db, 0xc6ba9004, 0x1dfd8b65, 0x33ddfc8b, + 0xa7ae140e, 0x9a02cfdf, 0x2972da22, 0x84ebdf5c, 0xf3a754b4, 0xba7c2b9c, 0x377423af, 0xb0a39ce2, 0xcc697cbf, + 0x80861c02, 0x59c5112e, 0xebaa1f86, 0xa6155e2b, 0x434f54a2, 0x4b9c36e7, 0xace16cd5, 0xe1c2282c, 0xd701f79d, + 0xa4527297, 0xec6f59a2, 0xb0aa7d56, 0xd3e31e59, 0xa4bc1568, 0x731701a0, 0x199c1baf, 0x9feb5ae5, 0xc0095bbe, + 0xd51ace41, 0x61b91401, 0x98facda8, 0xeab44e74, 0x656de54e, 0xea64a23d, 0xac772c50, 0x4605b137, 0x47fd4093, + 0x96c7aa8c, 0x1a7142bc, 0xff9d9a84, 0xc63a46bb, 0x9b517a84, 0xe37450d9, 0xc41be74a, 0x2eb4ead4, 0x3c92aa2d, + 0x5b676bc4, 0xa4ff9543, 0x81299e27, 0xf52f4bcd, 0xc10b8ae0, 0x7e1c4435, 0x64fbb458, 0xaf6868ac, 0xf5e99673, + 0xd8827a50, 0x0c2f36c0, 0xe2990f91, 0xb7725ef3, 0x05b1153b, 0xcb9a4a03, 0x0705c8e9, 0x65faa592, 0x2f935fba, + 0x9dcc5b5f, 0x55f16d58, 0xc4a021bf, 0x930884c2, 0x9ddf936c, 0x0a35cc23, 0xd5a402ae, 0xe1351b6b, 0x6b7ad07f, + 0xdd575c15, 0x98d6ac22, 0xf62b342a, 0x5d11a666, 0xaf2b5304, 0x1c838f53, 0x6b935ccf, 0x7755019c, 0x9282df69, + 0x26ca02a3, 0x2939df2c, 0x0419cb0f, 0x13efd3a2, 0x0852031c, 0x180708c6, 0x4cb481e4, 0x2dec2d84, 0x40ceed05, + 0x92a75be0, 0xb34740ec, 0x297339a3, 0xcd39a8c5, 0x1eb71bb1, 0xc3687687, 0xeb1660c6, 0x935c98f0, 0xe61e731c, + 0xf7a431df, 0xdecef2f8, 0xa5e33f03, 0x96b00ebe, 0x82b717af, 0xd01d6242, 0x44f9d86b, 0x20acd679, 0xe4387792, + 0xf7a8145e, 0x782c8e8c, 0xf94e523f, 0x1665fda2, 0xad871ac9, 0x297faba8, 0x448a81c5, 0xd00073c6, 0x70b65a54, + 0x1628d4e4, 0x4292fcff, 0xcc0aa230, 0x5aea3623, 0x561983d2, 0x9f1692e7, 0x56329126, 0x19359355, 0x93f43935, + 0x8fc17acc, 0xafa41f44, 0xf0cb0a5c, 0x45ef616a, 0x1ec24be8, 0x8b5ad487, 0xa4160d55, 0xd5318ab1, 0x7879b7ea, + 0x30a3ea13, 0x3b5f071d, 0x4264eb14, 0xcf38dc12, 0x37c5b3c4, 0x16a56f98, 0x79e699d6, 0x819fb6b3, 0xe5046675, + 0xc0e01ad0, 0x4b07babd, 0x77300cd2, 0x7ec2772d, 0x9554baab, 0xca894981, 0x1bef1155, 0xf843df9b, 0xaad08062, + 0xe8001ce0, 0xa3b59c7f, 0x138a127a, 0xf6a65849, 0x8a4d72d9, 0x6d67eab8, 0x75faf422, 0x0811cbec, 0xe14fde99, + 0xd4710637, 0x10ff984c, 0x8e700805, 0x7cf57010, 0x9ce96b5d, 0x6742738a, 0x34a692bf, 0xfcd87a17, 0xf753afd0, + 0xda682ad8, 0x29577a31, 0xbc43bf09, 0x84ca7505, 0x83322b3a, 0x0a240bea, 0x9aabb682, 0x04023f33, 0xea56e4a5, + 0xfb121ad0, 0xb11f79f9, 0x70b51baf, 0x5d7dff60, 0x1dd03a12, 0xf15eb8ba, 0x7eaeef6c, 0xd2e46572, 0x28798575, + 0x63699096, 0xd80d113a, 0x8857a17f, 0x4ec15365, 0xfdf9d5f3, 0x75aa32d7, 0xd218420f, 0x560fa060, 0xcb5ca105, + 0x70e5478b, 0xf9a0a713, 0xfac0e709, 0xc49a8f8b, 0x3912c161, 0x295aec25, 0x366a0bd3, 0x84837a6e, 0xaa1d5410, + 0x0209e205, 0x96328197, 0x52c042e5, 0xfacbdbdd, 0xa369d968, 0x0c2a206d, 0x58282cec, 0xff90849e, 0xcf3482aa, + 0x9f9bf0c1, 0xa02592d4, 0xa65bc902, 0xecf6ed12, 0xa4abb288, 0xdde818af, 0x4a010f20, 0x8e3366e7, 0xd85663df, + 0x4353c7d1, 0x16d85576, 0x8c9cdec2, 0x519eb474, 0x587a4abf, 0xbf657616, 0x45144591, 0x0adb1173, 0x7b793971, + 0xe41b2a28, 0x05a3c761, 0x264ea5f1, 0xa5f1dcd3, 0x38158eef, 0x8ba6a577, 0xae06ef33, 0xec8d163b, 0xba6bbea7, + 0x79464669, 0xd6f5c43a, 0x7d6aa7ca, 0x8cc3315b, 0x364d1ede, 0x9f7252a2, 0x102c4b93, 0xe1dbba48, 0x15809871, + 0xf5eb8a28, 0x66dd90ac, 0x2737cd26, 0xda1a8645, 0xa50fd074, 0xb5ff4a48, 0xfb0eb389, 0x358ac466, 0x7dc21a76, + 0xf7c4bc05, 0x59bf295e, 0x74331077, 0xda274b02, 0x78cfcff7, 0x8e465509, 0x83187368, 0x3bc25d26, 0x7edcb037, + 0x3a9a4d6c, 0xb4665018, 0x19f78d65, 0x598bab03, 0xbe39ea5a, 0xdab98677, 0x899d1a96, 0x8908defe, 0xcdcc2aa0, + 0x08d9d1b5, 0xd30c5569, 0xfc8c6269, 0x7e14525a, 0x88ef7dac, 0x65cd6b0c, 0x4879e87b, 0x77ed38aa, 0xcde527ad, + 0x4bf41456, 0x4ac2ac1a, 0xf81b9a84, 0xeed64434, 0xa89d8e6d, 0x370967a5, 0xc9c5c11b, 0xf1a0c1cb, 0xb1d97677, + 0xa6283053, 0x791f783e, 0x5a981ee1, 0x6cffe382, 0xdbb69f20, 0xab5cbff0, 0xb8387f71, 0xc7f9460c, 0x685f5ced, + 0x4f2b9956, 0xdca9856b, 0x56816cfb, 0xd173c024, 0xae903715, 0xa525d4ef, 0x10175bbc, 0xa806d5a1, 0x493d52fb, + 0xf4b769e2, 0xdab7105e, 0x8562a985, 0xf620c061, 0xaa5f7e5e, 0x4ba054bf, 0x426ce719, 0xa413be95, 0x0139a451, + 0xefa53b24, 0x9de94adb, 0xb6008817, 0x0b0eae30, 0xcff413f5, 0xac1edf47, 0x4b226185, 0x413f73fa, 0xdd3c3ff2, + 0x4d0a20ed, 0xb6cee559, 0x4107c940, 0x12d5a141, 0x97b45bd2, 0x72dd943b, 0x65bff95a, 0xfa8aa6fd, 0xf60f6b8f, + 0x26639156, 0x70100962, 0x8c103f0d, 0x325bbea6, 0xddae1dfd, 0x9255f2b4, 0x0b47746c, 0x43e8a078, 0x0cca0543, + 0xc3439ee8, 0x30e49e24, 0x5d015e9a, 0xd3049563, 0xb543ecd6, 0xc968c996, 0x2e21b3a9, 0xec60c540, 0xe08ba075, + 0xa5a80064, 0xe9474460, 0x3dc9c746, 0xb9522153, 0x7fbe0863, 0x595b00c4, 0x8c5a2703, 0x05e7e48e, 0x26c6ff0f, + 0xa0e99cca, 0xd14dd17d, 0x06182b8d, 0x5f118ba2, 0xcf8de773, 0x10623e69, 0x0f038695, 0x338203dd, 0x89f13405, + 0x654069c7, 0x2017b138, 0x71f8c75e, 0xf0a0c966, 0xaaa240cb, 0x53fc585b, 0x3f5ed8c3, 0x925a07a6, 0x5748d563, + 0xc308034c, 0x690cba36, 0xb613feb7, 0x61410ae5, 0xb6d8fb05, 0x36bee799, 0x6af16cf5, 0xd31c6072, 0x5b6739c0, + 0xf2078e84, 0x623e2d4c, 0xd8dda8d4, 0x0ce59d88, 0x3b781960, 0x1795b2d4, 0xb0347ded, 0x9130fe1d, 0xa66f75bd, + 0x341ea8b0, 0x67010936, 0xb987a9f3, 0xde2ea6bd, 0xdac29de3, 0x96ee6e5e, 0x917a57a8, 0x1bec1652, 0x7881226b, + 0x1173d231, 0xfaa5a692, 0xeefeb683, 0x82416423, 0x52cece5f, 0x0831999b, 0x7fea277e, 0x277df27d, 0x4abcb50a, + 0xe50b00c4, 0xcefa85bf, 0xbed16181, 0x2eb77186, 0xaf70b27c, 0x5328f922, 0x8ed7f65c, 0x20c22823, 0xc815b172, + 0xce94e036, 0x45a7eb8e, 0x337f84f7, 0x4ef49bd7, 0x5ffbc359, 0x518b386b, 0xf94af11b, 0xc7ce2368, 0xe08b7a06, + 0x6751820c, 0xa97a0c0c, 0x24acce6e, 0xa49ed437, 0x8d0a8245, 0x76a869a1, 0x7e7b874b, 0x90cd3952, 0x593b54e9, + 0x81916f2e, 0xf5488133, 0x0b7f6254, 0x9bfcda34, 0x87006da8, 0xf6cc72ed, 0xb2cad80b, 0xcedbac78, 0x988c7ef9, + 0x3649c7f9, 0x4728907a, 0x79953b49, 0x0a6adb1b, 0xdcd4243e, 0x742ba30d, 0xd606b2be, 0x08cf6056, 0x42d1a8a0, + 0x1301f578, 0x53bcb4d4, 0x5f7b04f7, 0xc79bc409, 0xc0d74e4c, 0x9c9aa8c8, 0xe892eb90, 0x7d290655, 0x23f1e8da, + 0x6afad3e4, 0x5c309a45, 0x56fce95c, 0x40f111ec, 0xdad822e6, 0xc4319e1f, 0xfb3fbc1d, 0x8b1cf29f, 0x9185016a, + 0x534a6b1a, 0xcec81725, 0x259cc183, 0x88ea9aa9, 0x3d8ff0e9, 0x0831cae0, 0xca60c2b0, 0xbbc16480, 0x5a54e177, + 0xc32161af, 0xc7c45abb, 0xd5cec3b7, 0x5eac6681, 0xd00b227d, 0x7664c41f, 0xefad7e32, 0x5afe9976, 0xcc36c508, + 0xc1eb6bf5, 0x06ffc6c9, 0xfde47bf8, 0x53dc350a, 0x8ab1ec2e, 0x8aae69ae, 0x4f10e2b9, 0x1f628d8e, 0xa9c8a371, + 0x53d770c0, 0xeb7e8643, 0x37504b1b, 0xacc77a80, 0xa219783f, 0xf7b7ca45, 0x20047dbe, 0x515ff849, 0x06fd9295, + 0x4a1d9ef2, 0x6869aced, 0xbb8706bd, 0xd6b313f3, 0x1705a570, 0x5b702b78, 0xf895d441, 0x3576555f, 0xcce6f106, + 0x12891fa2, 0x56e2a576, 0xbf2cd077, 0x173fe1c3, 0x827d8f72, 0x97a9c435, 0xb91f3d5b, 0x8edd4934, 0x786d9e4d, + 0xc51d866f, 0xead8a64f, 0x0a09656f, 0xe30a2499, 0xedc163fc, 0x0882e298, 0x6251f520, 0x2a4e2d6b, 0x7ead4b7f, + 0xb0148e90, 0x1d90378c, 0xabf87e34, 0x53227636, 0xf11e9ed1, 0x027a5c56, 0xd55d0858, 0x029cf71a, 0xca859415, + 0xb7b5de78, 0xd434355d, 0xe04dd5aa, 0x97cd6408, 0x92c9dc72, 0x50bbdef1, 0xd65a0cd9, 0xfe48c609, 0x040dc398, + 0x1cdeabb6, 0xf9d4c847, 0x821675e0, 0x2a5e5f02, 0x41883531, 0x5e2492d2, 0xef932885, 0xe25b74f7, 0xd14922e7, + 0x3ec1c37e, 0xb742f3ef, 0xf6f0807e, 0x12de5ac3, 0x66b8f144, 0x2594d462, 0xd49358a7, 0x0b8c5ae3, 0x07a0fcfa, + 0xf116deb9, 0xd9f66052, 0x74146d44, 0x95aa1b0f, 0x3e32b938, 0x3dd00248, 0xebd42068, 0x999d8ee1, 0x5b89eaf6, + 0x8bd30074, 0x071cc8c2, 0x4c7a8020, 0x9cd38ffd, 0x55a6b8b7, 0x1c42be05, 0x0b0550cd, 0xadeafc75, 0x577d08cf, + 0x95fe8b0c, 0x255d02ab, 0xad6fdf2b, 0xd34907dd, 0xb236f187, 0x5a500618, 0xb8b0d4aa, 0x40e74edd, 0x03f79208, + 0x0b3d873e, 0x3e4dce08, 0x98a080d4, 0x66aa2574, 0xe9e9f68a, 0xd00a93aa, 0xaef51d23, 0xf507fbcc, 0xec41a6d8, + 0xd5efd9cb, 0x216196b9, 0x239de3c9, 0x96f234d8, 0xf970b722, 0x30568849, 0x0a33afa8, 0xd2013ae2, 0xa796313d, + 0x844d6f4f, 0xe3d0aad4, 0x51aab36d, 0x716b03a7, 0xf75135d5, 0xdca1899d, 0x511e0452, 0x5faae8c1, 0x8bd2c0d7, + 0xf8f67485, 0xbc3c1e4a, 0x34a7b294, 0x77fa88b1, 0x83bc22b0, 0x7f2ca77a, 0x8b5eea59, 0x51b1203e, 0x59b40f7e, + 0x15eb0e8f, 0x63b6a139, 0xa1fe704f, 0x0ee9c01a, 0x2b8a9f9f, 0x84468b78, 0xf0eb357d, 0x240800cb, 0x350210dc, + 0x80a2eb42, 0x8ff70438, 0x5b692840, 0x28bf67ce, 0x18bfa449, 0x50b3ee96, 0xe8028476, 0xbd667c98, 0xcdd5abce, + 0x8afababd, 0x1414befc, 0x90739f92, 0x8ed8b239, 0x1b05d8ad, 0x6c18a688, 0x52f0d131, 0x46de25ab, 0x741717e8, + 0x31a5be14, 0xcedccd5f, 0xd1545de4, 0xe15317d5, 0x5373d7b8, 0xcce1d4ab, 0xb4d8d61a, 0xab95d6e0, 0x2de9bad8, + 0x23848b68, 0xb47da424, 0x2437897f, 0x8a771609, 0x6b53d55b, 0x4bd8b3a4, 0xc08bea68, 0xb9b9a1ec, 0x72eb96f4, + 0xcdba7d3b, 0xbf705b15, 0x0030d5be, 0x55cfa6d9, 0x8107a95d, 0x6ad8d068, 0x33ac0b76, 0xa194bfdf, 0xfe80be1d, + 0xd700dba4, 0x257263e1, 0x89e191a8, 0xeaa88c1c, 0x317f861c, 0x5342f6c2, 0x7abfb8a9, 0x761b710a, 0x3058f378, + 0xc57290d1, 0xc9fb948b, 0xb65c83ae, 0x9b041adc, 0xc86c211b, 0x1017dedc, 0xab10ea8c, 0x0e0ba410, 0x0469ec21, + 0xd1a9d898, 0x01d59ca9, 0xbb90a70a, 0x44462927, 0x1cc617b2, 0x1ad97676, 0x7a5b53ca, 0x000cb15a, 0xddf05ee0, + 0x6d02a02e, 0xab912d96, 0x49124462, 0x3435e42b, 0xf6fd46c8, 0x2ba2788d, 0xc09cafa0, 0x5b691a68, 0xa143e837, + 0xaec3712c, 0x109ff4e8, 0xab997402, 0xfdab357d, 0x8bdd2152, 0x457ef195, 0x879e6acb, 0x4c7e3d3a, 0x43219b13, + 0x1d804f5b, 0x6063aa69, 0xab670c5b, 0x3bed18ff, 0x025b8980, 0xc677a652, 0x4c4279db, 0xc4efbb0f, 0x00344381, + 0xf7fcfd1b, 0x64f6ca1d, 0x53c274b7, 0xcfd0d1b6, 0x086fe6dc, 0x10ac594c, 0x604b1000, 0x5b82c92d, 0xdebb59ae, + 0x832dccf2, 0xfefd0f24, 0xbe3642e9, 0xd9981f7d, 0xe7e93a7f, 0x14a6c24e, 0x61724b45, 0x5e13b8e4, 0x6d81dfd2, + 0x13f3d4ea, 0xb9c27867, 0x206b0f66, 0x01267a87, 0x596bee66, 0xef6f5786, 0xaf8be633, 0x4cea6df2, 0x976321e3, + 0xe691b6f8, 0x8ab24578, 0xdb5deb82, 0x3cb6c5e5, 0x307d6d01, 0x733f429f, 0xcf66740d, 0x50c1c64d, 0xcec95c1a, + 0x9a9c08b5, 0x95768462, 0xa5e04650, 0x6535e8ee, 0xb8a5b86f, 0x5f878eaf, 0xff5a77f9, 0xd1155bd0, 0x0c877133, + 0xaec315e4, 0xbb6e6f89, 0xcb9e34e8, 0x15700de0, 0xd598a071, 0x97d1bec8, 0xfbeb2e76, 0x4f30af48, 0x0699a940, + 0x82ca34b3, 0x02a79cde, 0x943dbd93, 0x74c93ef0, 0xffe730dc, 0x8a0a9e3c, 0x44137dc9, 0x6c9977c3, 0x6867a457, + 0xbfcd431a, 0x59279b4c, 0x99f0f91e, 0x179ea106, 0xf57a4f65, 0x2c42d9fe, 0xabe158fa, 0xb1517645, 0x367ca819, + 0x349f49c9, 0x623b6fff, 0x9e49d9b4, 0xd6d7e8b9, 0xb799c575, 0xe739f949, 0x75996c42, 0x092e6ce5, 0x1cb18934, + 0xa102c6b4, 0x8a258ded, 0x25064073, 0x9411a55d, 0x7a767bcf, 0x2c8c6cbf, 0x234124d0, 0x12cea2e1, 0x14ec05aa, + 0xf84fbdf7, 0xf00d6581, 0x7a365a55, 0x1bb9386b, 0x772fcc5c, 0x4846bbb8, 0x77ec92d2, 0x14936e1c, 0x0df5c68c, + 0x9bb9ce65, 0xba5a969d, 0x19a61d20, 0x983c912d, 0x04b8122d, 0x1f3ea550, 0x4618021e, 0x789e7fc9, 0x0edbe220, + 0x60c1f1a2, 0x370f3ee7, 0x343993e2, 0xab7f55cf, 0xa1df2f04, 0x82a34046, 0x5445bb16, 0xbe103dc8, 0xa558e622, + 0x5c30c4bc, 0x91bbc2a3, 0x530c57b5, 0x0cb3d396, 0x65119c9b, 0x6e6eaac5, 0xb6a24c00, 0x622b02ab, 0xc4fcd7f0, + 0x3cbffe39, 0xd39a2937, 0xa8eb3846, 0x0b562f2f, 0x6c2c7612, 0xe8d200de, 0x8039da33, 0x20e05af5, 0xff30da7f, + 0x9541e30a, 0x84414111, 0xab25ba75, 0xe8caa9a0, 0x03fe1473, 0x752c9b84, 0xf7d09018, 0xf5b73518, 0x9454097e, + 0x7f17eec3, 0xe9c5a2e9, 0xadfba3aa, 0xa4246d0d, 0xe14b8230, 0x8a7dc2f7, 0x66429e3b, 0x279171ab, 0xaa390838, + 0x49ac404b, 0x393cdea6, 0xbf47c026, 0x9e0fe3d2, 0xa09e8b6f, 0x7e446c1e, 0xfe0c9d1d, 0x4e69320d, 0x420a6861, + 0x8cce1d39, 0x22c3a73a, 0xc268146f, 0x177b8706, 0x94feb922, 0x44f16807, 0x4367a17d, 0xf921069d, 0x1c7bce67, + 0xe045a967, 0x3411c552, 0xf5740060, 0xc14d38dd, 0x76c4f04a, 0x2fe4fdcd, 0x5962ff3f, 0x1c896410, 0x6d52af72, + 0xd212574a, 0x23e17219, 0xdd57ea7a, 0xcbb20b4e, 0x302dd85b, 0x0af923e4, 0xb298a562, 0xdbdcb5bb, 0x3ef20377, + 0x5f0d7af3, 0x2eb6bbf0, 0xcbdafc63, 0xc2b5d26e, 0x1493d5aa, 0xcc47f030, 0x5a7cd514, 0x32a8f2cf, 0xeefc6379, + 0x28e212c7, 0xe32715fd, 0x603458c0, 0xc92322ff, 0xc2dc8b7d, 0xf5bd18b7, 0x5a927194, 0x262ec879, 0xf4962562, + 0x1600ff5b, 0x5bdff75b, 0xbacd20e0, 0x47290040, 0xc5b5dc5a, 0x4c5a7f8c, 0x4ee8245e, 0x5b074f23, 0xb8507bf4, + 0xf7ee3fb0, 0xc9238fee, 0xcf476a0c, 0x99288755, 0x938fd742, 0x22385e18, 0x16436155, 0x0ab56ee9, 0x03d00cb7, + 0x412bd813, 0xe6cfd2cf, 0xf466653a, 0xdc5d95b2, 0x8013fa01, 0xa3788b0c, 0xdd93fe39, 0x0d911ba2, 0x07bd326c, + 0xdcf1e898, 0x27857b9b, 0xbfb39171, 0xa4eda7a8, 0xc55c3d14, 0xee21b5a8, 0x1c1a764a, 0x2745d020, 0x4230685a, + 0x71bd77cb, 0xdcaff5e1, 0xe262412b, 0xa214ce2c, 0x06f797e4, 0x47430c2b, 0xdd642ed9, 0x16b6f7ba, 0xebecd5de, + 0xd5cca173, 0x9a2099dc, 0x48865d64, 0x7b1bbce6, 0x0ad097b3, 0x701bfebb, 0xeeb73610, 0x07aa867b, 0xc6c048ab, + 0x10b94fe8, 0x202c2328, 0x71c64fee, 0x341e638c, 0x57c99b75, 0x09bedbe3, 0xa606c8c3, 0xbcd69766, 0xf05ad068, + 0x0ebc1d39, 0xce156423, 0x3d09b9c4, 0xc0612001, 0x1ef33791, 0xb7b50f1a, 0x87960529, 0x224393b6, 0x6f660d75, + 0xa282e00a, 0xbb798e95, 0x2fa3248d, 0xf8fbd1d9, 0x8b681ebb, 0x1ca4e5c0, 0x073f1e53, 0xc2cab3e9, 0xb52194dd, + 0x52efa2b3, 0x1ac2c003, 0x6b398053, 0x8f1ae1ff, 0x07dd41e5, 0xce41602e, 0x303b86df, 0xeedd721f, 0xbb31a045, + 0x3d9169d7, 0x57e5ce7e, 0x38f13df9, 0x769fba6a, 0x18ba9a85, 0x6376d93e, 0x887283cd, 0xa36e9761, 0x5abeae49, + 0xfc5a2684, 0x0f4c959c, 0xa7bb8b20, 0xdd7a0a7f, 0x593839eb, 0x9a3368bc, 0x0072b716, 0xe00a61ba, 0xfab373be, + 0x34a11cde, 0x68228993, 0x363ab7c4, 0xcfd74756, 0x48089435, 0x55152999, 0xbc8a0960, 0x3e938eb8, 0xb3a3a082, + 0xec347673, 0x47d1b424, 0x22f9cb82, 0xf07e91de, 0x6aae3bae, 0x4a1ebdeb, 0x357591d6, 0xdec9ce32, 0x5e6c2a8f, + 0x8397c758, 0x4c859a00, 0xb72176f7, 0xeed79e4b, 0xe773b182, 0x05b6569d, 0xb7258c23, 0x816ad0a1, 0x5e803d4d, + 0xb0358d47, 0x886a780f, 0x8a6ab8fb, 0x6fe3230f, 0xec701288, 0x92e3c894, 0x531d769c, 0xbb1b0d9c, 0xa828c7f7, + 0x93ba9cfb, 0x26e13b65, 0x3fd57fa8, 0x36cc7f32, 0x8e924339, 0x53f9d548, 0xaa681e05, 0x4ba606f9, 0xc4dbedc5, + 0x3f356862, 0xc677289c, 0x2b402c51, 0x260b825b, 0x9e1169ec, 0x6fc74069, 0x9714a8e9, 0xbc9ab80b, 0x652ce1dc, + 0x0aefd74f, 0x9c57eaed, 0xb4458d79, 0xd12809cb, 0x32796f96, 0x305d05e1, 0x45914817, 0xa47a36d0, 0x9b7d2ef0, + 0x39a51787, 0x679e7452, 0x6ea4377b, 0xb66c9849, 0x3d68d174, 0x49e23097, 0xbe325a78, 0x2ef67f0a, 0xaf35b979, + 0xa7ede632, 0x0aaff567, 0x96875195, 0x33b4e882, 0xfd4af004, 0xc0850439, 0xe15063de, 0x5ea5c816, 0xe5c32dff, + 0x684e7c33, 0x21cbce40, 0x3eeff745, 0x72791669, 0xb432e9dc, 0x7915cccb, 0xcf6b71de, 0x038f1997, 0x4e9a5e0c, + 0x3008aa52, 0x8ed3a2f0, 0xc3233a59, 0xbb392e07, 0x629d9df8, 0x38b93c93, 0x1ae3c295, 0x7ca449e1, 0xc1466c64, + 0xbf7c82fe, 0x4ba1e1e5, 0x5e84dd9e, 0x4280b300, 0xe5ffe023, 0x2bd57709, 0x45a3c176, 0x6344bb07, 0xe1b4533e, + 0x21e6a502, 0x45fc0623, 0x1ba0ebd9, 0x5e937621, 0x6c98dba2, 0x1d4a4700, 0x7108e59d, 0xea0c6434, 0x8967f984, + 0x36a11d6e, 0xd7f1b2d6, 0xee11fbaa, 0x07ead144, 0xbcd1924d, 0xb9aa4fca, 0x0d19aee7, 0x36a93438, 0x18503bf6, + 0x92e12049, 0x3e7638c1, 0x8a5cfc32, 0x81db8ee1, 0x88b30b72, 0x20d429ce, 0x97f3da74, 0xae2b0735, 0x12e3c0dc, + 0x5b8c41d7, 0x242a8b79, 0xe352268b, 0xb9159281, 0x7a90cf39, 0x25065803, 0x53691725, 0x4606744c, 0x0d4a62eb, + 0x4343eb81, 0xf2da2eed, 0xa6f87f73, 0x2a72aff0, 0x154993af, 0xb0992d70, 0x47c1dc27, 0xdbbf97fa, 0x7f3fd914, + 0x14bff4fa, 0xf828c65a, 0x8d478bae, 0x431b4797, 0x32da854a, 0x34fb2dba, 0xfdd3fdf9, 0x6979ded1, 0xd3b30f70, + 0x1ec17cc8, 0x67a6d699, 0xab15f498, 0xf70a4a5b, 0x50888e66, 0xec9524ae, 0x033d1fd6, 0x93e1ba0a, 0xad32e1a9, + 0xa128a746, 0x89b4afd0, 0xec608348, 0x5b309cb9, 0x3a77accf, 0x5542bb0f, 0x1630d264, 0x2d7476d5, 0x37fd323f, + 0x6f26ae9e, 0xe88e8757, 0xeda2d307, 0x75341252, 0xc6340caf, 0xc631235b, 0x2bf74d21, 0x47064065, 0x123d5d8d, + 0x44620ba5, 0x2f6ef65b, 0x3cd5d410, 0x6f9a9c42, 0x7192467c, 0xe95c98dc, 0x88b7dd4a, 0x43e3c233, 0x53a0937e, + 0xb467f74c, 0x04a97539, 0x57d9cdc8, 0x6ef42e09, 0x1d8521a1, 0x5fe6708f, 0xf98e9a16, 0xfe6b4480, 0x1dde4e2a, + 0x65c27399, 0xb970d5c8, 0x54fa19b2, 0x519d1669, 0x77834a25, 0x5b04a8a9, 0x51602be6, 0xf6b5a054, 0xb0f5973f, + 0xa513a368, 0x6c19d1a3, 0x4ffd689d, 0x00445b71, 0xd3301e4f, 0x60a349df, 0xaeedec37, 0x2dde21a3, 0x37cecee6, + 0x20629f6c, 0x6a7089b4, 0xa6c25310, 0xe28ea00e, 0xad7c046d, 0xdf76758e, 0x58a5be10, 0x3979f837, 0x21d71b48, + 0xb4a21c6a, 0x99aaabbb, 0xb7a23170, 0x84d796de, 0x923e8ff4, 0x531e5689, 0x0cc7d00d, 0xd752b09a, 0x2347e5ee, + 0xd9fbc376, 0xbf9f663d, 0x066a8ff6, 0x77c4b1d1, 0x3d9be939, 0xab6aa1e3, 0x8b0cdda6, 0x722ebc23, 0xd78fde5c, + 0x1ae22ee6, 0x12949e63, 0x56c4d46e, 0xb4485389, 0xc071900f, 0x59bdb01d, 0x93252deb, 0xde554334, 0x2be8d873, + 0x7944d7e7, 0x42215881, 0xc673a9cc, 0x75f2256a, 0x39575358, 0xcc032e04, 0xd689a7cf, 0x1a2e26c0, 0xc0b4fcd0, + 0x2fb655ca, 0x7b8f9024, 0xbf656419, 0x3a282a41, 0x2514edfb, 0xd0b5d362, 0x7583e180, 0x7f1b0f7b, 0xcc38d310, + 0x3d80b29b, 0x3b342ee2, 0x3b701d23, 0x376bc3e9, 0xac13df61, 0x26521696, 0xbdcb895b, 0x60653d07, 0x01036fc1, + 0x145a434f, 0xde1cca6f, 0x09f3d0ba, 0x95b6e182, 0xdbab2f0c, 0x9f473380, 0x8fec5644, 0x15248ba2, 0x63e1ced9, + 0xdaf45d4c, 0x6af89ed6, 0xcf32fa15, 0x54e8abc9, 0xa48814bd, 0xf1378b52, 0xb6f122cd, 0x995cbe5c, 0xf7e30e81, + 0x2501c0bc, 0x2f363d3b, 0xdcb2f1ef, 0x263897ec, 0x1611c60e, 0xa1738d7e, 0x32a25344, 0x7d38abc0, 0x5eabbc18, + 0x77027a34, 0xe893b7e0, 0x8a89ec35, 0xfc95877b, 0x2f1b43d2, 0xb66d9492, 0x56879309, 0x4a0e8d7d, 0x21331205, + 0x4d44380b, 0x6c3b911f, 0xcbc8d4f0, 0x3d66af64, 0x4869c413, 0x78022562, 0x19631679, 0x4a9ac1ce, 0x27902a3a, + 0xf744d4b6, 0xfc4309fd, 0x8fc29791, 0xb8393bfa, 0xe283fff0, 0xed89348c, 0xe0131492, 0x811af06a, 0x6aa234a9, + 0xe5e34f80, 0x63a22296, 0xc9f241a0, 0x9da8e9eb, 0x78d9a6d4, 0x1fdab968, 0xa30ea7d9, 0x424b28f4, 0x1886f99d, + 0x950aacfe, 0x3bb5ea61, 0x6ab4eebd, 0x12216719, 0xb0e1bb20, 0x6a59681c, 0x1d75afec, 0x05bd20d2, 0x125ce567, + 0x9b77a23b, 0xaa79eb14, 0x6759621a, 0x5d5ab38d, 0xea31f897, 0x8d6f5eb0, 0xec4327c5, 0xa6c97eb8, 0xe36eb8cd, + 0x8b7220d3, 0xb15c7c21, 0x7c8c745c, 0xe389096f, 0xe330edc0, 0x9375b937, 0xebb848b8, 0x5fad5a77, 0x87017952, + 0x9e52d4b8, 0xddc35613, 0x1192b1e6, 0xb92ab1bc, 0x993909e3, 0x18931a8b, 0x8b1cc4ca, 0x0a53245b, 0x715e7875, + 0x017315ff, 0xc07fe117, 0x8078776c, 0xe26dac26, 0xbb8fd970, 0xc1a4d03f, 0x23ecaecb, 0x4a0c0ee1, 0x2ca4de16, + 0x340a8001, 0x947d958d, 0x448fef77, 0x43e0bb80, 0x03bff644, 0x9a7f73ce, 0x566d8a50, 0x0bcc171c, 0x130c3372, + 0x8d85ca8f, 0x2ca71635, 0x29c2ab3e, 0xd34559c7, 0x25fdd825, 0x1d9c0bea, 0xed4aa0f5, 0x78560e47, 0xb56fbcf8, + 0x8364a952, 0x79d2ead9, 0x45e60cac, 0x47b794e6, 0x5130d50b, 0x301ba44e, 0x534ad79e, 0xcd5de838, 0xae1c6c6e, + 0x5084f903, 0x5fce6efe, 0x62f81037, 0x01d6d23b, 0xcb1187e7, 0x5d4681c2, 0x19e8ec97, 0xe9bcb538, 0xbc84a401, + 0x3c0e4567, 0xc39b1017, 0xf791c0cf, 0x010c023d, 0x73ac0ab9, 0x208e7f41, 0xef2f94ea, 0x7c1a1c7b, 0x6fed6a61, + 0x27f92625, 0xde2bcf94, 0xd5c504fd, 0xb73d736d, 0x9842ae5f, 0xfba03155, 0xf573ac6e, 0x2e8c3935, 0xc82da0c7, + 0x81bd704a, 0x5767d689, 0x8eb64b64, 0xe0af1410, 0x0e0f18a0, 0xa48d4ff4, 0x4360c1d4, 0x3b95b734, 0x74de67d3, + 0x0b8f51b0, 0xe0e34265, 0x265670ed, 0x5126b550, 0x5e5c74a0, 0xe4a1c00f, 0x2fa930c0, 0xcd8bf2b5, 0x88c5a4c3, + 0x6dc6c814, 0x6f707fb4, 0x11e66f9c, 0x5587b6ca, 0x008ce8ba, 0x0ab65d24, 0xc2b16f2b, 0x79b8a1f6, 0x380c3560, + 0x8593d1b2, 0x12dc2b0f, 0xa61296bf, 0xe8d023fe, 0x8ad5517d, 0x03e5f71e, 0x321a682f, 0x83363f3e, 0xd2c96916, + 0x3d66ab30, 0x731f3f69, 0xe89d3361, 0x54395043, 0xb0e91704, 0x77874438, 0x8627e9ee, 0x3e4eeb39, 0x697912f6, + 0x4ade516c, 0x3790bafc, 0x67546686, 0xf767d337, 0xba119ff5, 0x67d1ad09, 0xe681dc0e, 0x98c809d1, 0x154d80b4, + 0x76f5b2de, 0x4cffa11b, 0x44b78cac, 0x9a829f82, 0x960cc899, 0xdafb6add, 0x90e0098e, 0x3cfb0882, 0xf4761bac, + 0x983b0551, 0x58aa207f, 0xbb1129be, 0xbe2b5cfd, 0xf604c13b, 0x40f5fe5b, 0xdb80182f, 0x0e74f135, 0x492af6fd, + 0x9d5892f2, 0xf7641944, 0x13e203f4, 0xe12e59ea, 0x80ae8104, 0x585c615d, 0xeffad430, 0xc52da9bc, 0x6b3adbff, + 0x114ad440, 0xd85e397e, 0x2dec56db, 0x4960ba58, 0xe6ef73e5, 0x5446ae62, 0xf7811150, 0xf3d84318, 0xbcc5afaa, + 0x814b6f8d, 0xdc65139d, 0xdb88964c, 0x3a700aff, 0x5499eef3, 0xc5f06d65, 0x05124a89, 0xcd54ed91, 0x8ba4fe3d, + 0xd5fcc808, 0x24e6e387, 0x5354555e, 0x76ad7383, 0x06dc7fe8, 0x8525fe73, 0x35889f84, 0x1439c839, 0xb4ffd4ff, + 0x461343c4, 0x980ba5e1, 0xbc8adde7, 0x1ddc4d43, 0xd6536a50, 0x80434bc4, 0xc280eaf4, 0xa9858318, 0xb158ba5b, + 0x099d7242, 0x8af807b7, 0x53ffabfc, 0x5d2c0d15, 0xa922f4ad, 0xb153ba9d, 0x0ebb841a, 0xa1ea76db, 0x7703f4a1, + 0xe1787337, 0x4a414138, 0x682ab304, 0x6d45c8da, 0x77b36c2f, 0x56273e0e, 0x05b4149b, 0x6c65808f, 0x512daeb5, + 0x61a8a551, 0x3ccc17f3, 0x36d53eb2, 0xdb245178, 0x271f9f3f, 0x0776516b, 0x296ed198, 0x93598934, 0x2cba9c11, + 0x1e5ce925, 0x64ac2040, 0x876752cb, 0x94fa16e1, 0x18d4a9c2, 0x46f4349c, 0x5e6ce85a, 0xf0a10e39, 0x662be725, + 0xcc882c2d, 0xc489483d, 0x879af4a0, 0xdcc6c098, 0x84d9cd78, 0x4ca33beb, 0x16f9dc87, 0xf560cbff, 0x25934571, + 0x9373f92d, 0x93da87c4, 0x5672dae4, 0x0e792e94, 0x31fd1595, 0x60f6e4b6, 0x1b525c30, 0xc7bc3a9f, 0x8cf7da75, + 0xaa73a231, 0x2df2e5c2, 0x6503f9e8, 0x3c3b62ca, 0x4ffd9288, 0xc3442d08, 0xdc2f31ce, 0x0d2ab622, 0xa8a802df, + 0x91fe2f79, 0x0e215a81, 0x2cbf23e4, 0x818dd24b, 0xa1c63fed, 0x6e281d82, 0x1bfbea14, 0x9fcb607f, 0xbe38f46d, + 0xade92ac4, 0x530439aa, 0x47be423c, 0x5b6f20c1, 0xdd536e63, 0xfe0336d5, 0x8dd536a5, 0xc8071414, 0x59328000, + 0x0415ff6a, 0xdf89802b, 0xe53dad79, 0x3f64cee7, 0x090f5bdb, 0xe2b00b19, 0x37d09b4d, 0x966ff015, 0x3dd80966, + 0x7ffacb2b, 0xab45c5a4, 0x48b541ac, 0x013f826b, 0xbb8c4cb9, 0x8ee49fe1, 0x63127472, 0x2410da34, 0x63112d58, + 0xb4c64d12, 0x3fedd44f, 0x03c161ba, 0x41ca41f6, 0xc0b25c3b, 0x41b2293a, 0x4c258dec, 0x3546f4c8, 0x3d773db1, + 0x2f5150fb, 0x203cf12d, 0x9ca19c62, 0xec102af9, 0xcda0f8c6, 0x2414b87d, 0xc9da2f56, 0x128322bf, 0xdf9a30ed, + 0x48eb3629, 0x62df1445, 0x84b32169, 0x08d0deb1, 0xb67e8f11, 0xb7cfee6f, 0x50af4f4d, 0xae2aeb8f, 0x0d30f64d, + 0xee22eafd, 0x6a5b15c9, 0xa86218d7, 0xd3e79774, 0x1c9bd72c, 0x09078328, 0x0ead9d59, 0x01283d27, 0xe1b83a4a, + 0xb4ae264a, 0x8dfdc68c, 0xaa6f3f8d, 0x6bca13f5, 0xabe0a205, 0xd385f96f, 0xc49cd747, 0xc90750be, 0x1ceb587f, + 0x73ba4f5d, 0x220fcd1c, 0xda1f00f5, 0xe96e3f2f, 0xf05f91fa, 0x2437caf3, 0x3dbd298e, 0x72e7fdf1, 0x1e870e5e, + 0x794ba7ae, 0xfbee74c3, 0xbe628194, 0xb42dba5c, 0x0343fe0c, 0x95970dd4, 0xe36038b6, 0xe060dfe4, 0xe661dbf8, + 0x8e675eb2, 0x339e4f07, 0xe603cab7, 0x3fe73cb7, 0xb6ffd0a2, 0xf1a3851f, 0x3a469788, 0xd3d00307, 0xcce40a25, + 0x440f3336, 0x56167f46, 0xa9150518, 0x79a78de2, 0x51cb6ffa, 0x82e299ac, 0x1538170d, 0x87051133, 0xf1e2d762, + 0xbb43502e, 0x2e80b2f3, 0xa62f9769, 0x38c349e4, 0xcf918cad, 0x3ffe85e4, 0x61059ff4, 0x8c42562d, 0xbbe3f510, + 0x3e166433, 0xa7ec6230, 0x584015c7, 0x4fda2da3, 0xd6914978, 0x947084a7, 0xba8fe1d1, 0x0a3da8e2, 0x001b5629, + 0x469db5bb, 0x7b416071, 0x35aedbb8, 0xab5aa9ed, 0x60be6dda, 0xd8af2b82, 0x6e338cb1, 0xd43f6ef3, 0xf4f0dfe6, + 0x70cb43f0, 0xff7ad25d, 0x5bde2695, 0xd6dd1d29, 0x5019f8ff, 0x5e46479f, 0x5d1b86d3, 0x6bca2320, 0x8a09f45b, + 0xfc83b998, 0xfcab2f3e, 0xd62f22d8, 0x959f5c2a, 0x87bd3cb4, 0xc77b89eb, 0x6bd501a4, 0x101e7fa0, 0xab41fdb6, + 0x3e1bd667, 0x3e54c9c6, 0xb754af13, 0xe540dcf0, 0xb7f8cf66, 0x0fd9ffd4, 0xbc327a5d, 0x30c78f60, 0xff9a75d1, + 0x60eb363b, 0x2dc6b774, 0x02cf1075, 0x34cf02cc, 0x245ebb64, 0x54d6f0c9, 0x5de1075d, 0xe2adc4eb, 0xa5b003f6, + 0xf77a1018, 0xefaa49d1, 0xcff705ee, 0x2d4b2c23, 0x6f045d03, 0xae74a651, 0xfcd5436d, 0x4ae43700, 0xc3cbe538, + 0x6f768163, 0x3b461ea8, 0x0c3ecf3a, 0xeb002c06, 0xa546a2e7, 0x6adb1b7b, 0xedc94f2b, 0xe6503cfc, 0x932a1127, + 0x07a95b50, 0x1c645082, 0xeea92341, 0xae989cdb, 0x5bd338ac, 0x04b72539, 0x55e9b461, 0x5c42f0d3, 0x4ff69259, + 0x6a71e44c, 0x351f9e86, 0xa0b0712c, 0x87c7a250, 0x259fd4d6, 0xc71dc057, 0x353691c4, 0x4b0a5ea0, 0xbd58648e, + 0x21a498d3, 0x2f79ac9a, 0x48fb47af, 0x4192e248, 0xabd81488, 0xd55137da, 0xf477a56b, 0x89bf7053, 0xe2fb090e, + 0x82034fda, 0x86b8f918, 0xf9f1eed8, 0xfc521efd, 0x43c0ecf0, 0xe8b4a5fc, 0x7fb0de55, 0xa2a16c7d, 0x47737703, + 0x49f61a7d, 0x1468044b, 0xbee19829, 0x473cc066, 0x06af740a, 0x59fbda3e, 0xed398c2c, 0x7eb73942, 0x9cc816c2, + 0xe9fac679, 0xd705abf1, 0x1a2c6c07, 0x22933abd, 0x2b3413ae, 0x5476528b, 0x79be3f5f, 0x773fac56, 0x2ad5a860, + 0xe4f30426, 0x8b3c7517, 0xff80e614, 0x89ebf253, 0xad4c7114, 0xd1dfcd04, 0x1d2c0fb0, 0xccc5294d, 0x8134cf74, + 0xd775791e, 0x502a6282, 0x39588b71, 0x2e009de6, 0xe47c8ae2, 0xa755324e, 0xd9d68a4a, 0x0d4d87df, 0xdda82435, + 0x22781ebb, 0x27ae5433, 0x43fea664, 0x71434fbe, 0xd734940a, 0xca562d03, 0xd220155d, 0x27eadb8c, 0x5e547a01, + 0xbca36c9e, 0xc9af5dae, 0x57c6bab3, 0x9b1803bf, 0xf78f3101, 0xec390b55, 0xaa62222f, 0x2038fe58, 0x5c4668ec, + 0xc09cffe5, 0x6a75ec2f, 0x38eeacf8, 0xc816c225, 0x84d45c1a, 0xeb2ca89e, 0x554d73b3, 0x3855400b, 0x71075ed4, + 0x396aa367, 0x273a1dcd, 0xc265db7f, 0xc919bee1, 0x8de87bf7, 0x0eee47a4, 0xc23cff74, 0x1abf682d, 0x87af0a60, + 0xe84491c0, 0x34e0a6ba, 0x01c3bd0a, 0xb3d15e7d, 0xff014950, 0x3e06b76a, 0x209301fa, 0x9a2498d4, 0x792f6fe1, + 0x0d5d4c2b, 0xa1f0d68e, 0x1c8e4156, 0x3eaed7d3, 0xa9b0cdf7, 0x7b694254, 0x73b7e16b, 0xb4553dfb, 0x2780b096, + 0xc69cdcfc, 0x8505dddc, 0x89e3f793, 0x5d3e2df7, 0x4fd48c29, 0x5220617a, 0x81d90406, 0xb035b582, 0xd5bde729, + 0xc5ae3d74, 0xeba66f5d, 0x0fdf94e3, 0x8a1a0460, 0x2bb1fb76, 0x9b114663, 0x196e76b5, 0xd0122834, 0x42b78232, + 0xcc01c145, 0x0ea411ec, 0x16b18e27, 0x7441faf2, 0xe8e5558b, 0xf3380a60, 0x3ec15565, 0x77ed3e84, 0xb7d1c7a1, + 0x3d637da2, 0x7836cc39, 0x6f194793, 0x85a4317e, 0xde36a083, 0xf75e9602, 0x42eda86c, 0xc8e65088, 0x3b06bb75, + 0xde2e9314, 0xc2fe5cc6, 0xb5f1cb5c, 0xc25ed65e, 0x533f9efa, 0x1ad9cc9d, 0x6b9648aa, 0xe4a927a4, 0x83822ec9, + 0x932969ef, 0xc31f924e, 0xdbb4aee6, 0x971c1d97, 0x5044254e, 0x9c3e23b1, 0x573f9946, 0xa6be8ca3, 0xb654d9d6, + 0xb3c27a4e, 0xa76fd99e, 0x02116b63, 0x3912e7cd, 0x56f4a3f3, 0x0fa2a66d, 0x23fb13f3, 0x58bd04bf, 0x6067657e, + 0xb4b41d10, 0x824be965, 0x7a33dbee, 0x51537d31, 0x1df403dd, 0xeb0e622c, 0x4a3cfa14, 0xd671acfe, 0x83194b38, + 0x22b976e6, 0xcaad4279, 0x26fb64b2, 0xf86df4d5, 0xfac4de1a, 0x68624649, 0x4abfa12e, 0x01280370, 0xb37bf5c1, + 0xdc7e641a, 0xa6c463b8, 0x25835ed3, 0xf68c1812, 0x218f6c24, 0x8bd30fdd, 0xbd1bb8f8, 0xf9ef8d26, 0x5a5fe510, + 0xd5a8bf45, 0xe036924b, 0x6a806989, 0x12de208f, 0x3d4ec604, 0xcefe511d, 0x4354bc56, 0x1c977876, 0x9153c08e, + 0xe509787f, 0x2c89016d, 0xd4e2ce0b, 0xf36632fb, 0xf914ed19, 0x70dca29f, 0x46c49543, 0x79cc5928, 0x15ea4081, + 0xfcf97254, 0x210251ab, 0x6507d406, 0xb779b07d, 0x43e3a680, 0x3806f89d, 0x58b4b813, 0x3340ef22, 0xabd484fb, + 0xb2e35fe3, 0x7892da9c, 0x53ed6f71, 0x08cbe53b, 0xc16eed0a, 0x8bc734c0, 0x566c3c75, 0xbe1838f6, 0x93b2fde6, + 0xddb4cd35, 0xddf2a4ea, 0x3783e377, 0x2115f253, 0xd5b7bc84, 0x0f066027, 0x99dbc327, 0xf559f428, 0x4893d5db, + 0x3b7fd50d, 0x4e8a21ae, 0xd08af666, 0x470d08a3, 0xedc8846d, 0x4de4e888, 0xc6059fd6, 0x7f7154da, 0x94e45936, + 0xf28c56ac, 0x82adcae5, 0xd5b2ef15, 0x6e11ad4e, 0x1c300747, 0xc1d5c1f2, 0xd1c2ccf7, 0x9bd8f22c, 0xfca63458, + 0x57ce5dca, 0x472e587a, 0x9747e4f6, 0x421d0b2f, 0x64919e2b, 0x64a732ae, 0x33a46caf, 0x6dbc8d79, 0x90a0da04, + 0x119a50e8, 0x3175933a, 0x785addca, 0x05152cd6, 0x98ce9d9b, 0xa89a57cf, 0x0849e172, 0x9239042d, 0x6ec0b9c4, + 0xf2c34442, 0x054c366b, 0xf18fc196, 0x595221b5, 0xf344f1c6, 0x5f38f9d9, 0x4f17a09d, 0xa4bcfbe9, 0x93216f4f, + 0x7d0982df, 0xcf92c757, 0x1c51c2da, 0x20e548f5, 0xaee143b8, 0xa494280f, 0x60e5013e, 0x3c478b31, 0x5d721c04, + 0x41ccee68, 0xf7cdc295, 0x0f68f363, 0x029d671d, 0xc06eee1c, 0x39a35721, 0xb84c42cf, 0x4ed64d8f, 0xfc46d1b1, + 0x13028f25, 0xa7f8ae07, 0x88dfea58, 0x5195a113, 0xf0b19d8b, 0xe73fd84e, 0x693bdcde, 0xb29248f6, 0x98c19501, + 0x0f3d2158, 0xc82ec601, 0x9de75807, 0x7705220a, 0x568a27a3, 0xb9d22cde, 0x3ab0d6ae, 0xc4b70f09, 0x4b0a3706, + 0xc6d10cdd, 0xa1968610, 0xeb240fa2, 0x93eb3260, 0x2dc491d5, 0xf524921a, 0x211d9bed, 0xbbbe4613, 0x8ba682fe, + 0x9d03c9b1, 0xa1b049e4, 0x9a8b6616, 0xbcf08a55, 0x74a19ce6, 0xf59388c7, 0x1f569eb2, 0x7d186807, 0xf4c9f1d3, + 0x585d0c85, 0x599c28bc, 0x824d80f6, 0x24dab019, 0xce2efa76, 0x8cb2971f, 0xe970a27e, 0xf21f9493, 0x97b6a4e8, + 0xf3d27927, 0x395e4cb3, 0x101ec7ab, 0xb74df5f1, 0x46a1d534, 0x74981c23, 0xc960ba02, 0x6c98e5d2, 0xa4d7226d, + 0x88be6c71, 0x5116799e, 0xb8649b79, 0x1077410f, 0x579507e9, 0xbd24fef8, 0x931f2c51, 0xe2bf73cb, 0xd415c48c, + 0x11bf0f83, 0x65d57598, 0x4c082757, 0xcac4b3d7, 0x32224ca1, 0x43ec6296, 0x6025357d, 0x4c0a86b1, 0x2f380000, + 0xd810c89a, 0xe7f77e6a, 0x30afa026, 0x6b1df75b, 0x9889a4de, 0xf22a6e37, 0xb82a0f19, 0x00903511, 0x9e6a4fc3, + 0x4697fc44, 0x1e7e8687, 0x4d17a78d, 0x168cec94, 0x384073bf, 0x43686b74, 0x555c014e, 0x4f8b56f0, 0x76b60931, + 0x34641b1a, 0x981afc6e, 0x881b92f8, 0xdbeab518, 0x8c54bec7, 0xb1eb1063, 0xbeece649, 0x922178af, 0x6bb93db9, + 0xb35d15d4, 0x21114d1e, 0xaad619cf, 0xa58232df, 0xf19938d9, 0xa64e8858, 0x16b14e9e, 0x35df281b, 0xfdae2286, + 0x458ae375, 0xcb7cdb82, 0x87e9a438, 0xfbc415f7, 0x7ec604de, 0xf6ec37b4, 0x908b208b, 0xcaaafbef, 0x128c0d2b, + 0x20b03526, 0xbe812322, 0x0cd5a4d8, 0x77e1b362, 0x2a59df27, 0x355e2d97, 0x67f2750c, 0x3b525c9a, 0xdc7224c2, + 0x165d8b47, 0x21f944a9, 0x5e9ff432, 0xbf234b0b, 0x18edf871, 0x42a541ed, 0x1aee88b3, 0x4044b076, 0xee87142f, + 0xa582e477, 0x2a08b1a5, 0x080e1892, 0xda0119bc, 0x52eced03, 0xf41584bc, 0xe7d00717, 0x71338959, 0x240fd882, + 0x1fcfb12f, 0x3d7c45e8, 0x13ef2c6f, 0x8f92e762, 0xb49aae73, 0x78f27803, 0xdf5b4404, 0x43823d35, 0x0b90957c, + 0x8717bbbe, 0x9f297340, 0x33e6e5b5, 0x751a50a7, 0xf883d02b, 0x8998da84, 0x28700ba8, 0xa7b02c87, 0xc2c337d7, + 0xdeb62bc6, 0xda380dbe, 0xe67f1540, 0x6709bef5, 0xaf084eac, 0xc1900cf6, 0x5f9302e1, 0x54857a01, 0xe0750d26, + 0xaad02b65, 0x00bcfb8d, 0x95232729, 0x5c19a86c, 0x56a40224, 0xed35974e, 0x8345633b, 0x0a8ed2c4, 0x88f22d4d, + 0xf94b6f47, 0xdefa64be, 0x706da4f3, 0x6b6196ce, 0xcd013a7e, 0xf019e2e2, 0xd5dc90e2, 0xf680827c, 0x7e283d4d, + 0x4417129d, 0xbc460f46, 0xfa5fd27f, 0x9b6f5d17, 0xa0c96f47, 0x0af8e8ef, 0xfac6368a, 0x3d10f7c3, 0xcee8baa0, + 0x152c288c, 0x0a46872a, 0x2e4cfaeb, 0x13a1220a, 0xd08b13b7, 0xd8d5870c, 0x0fc9d892, 0x4339d463, 0x2f13fc74, + 0xdabab799, 0x61603b9a, 0x62793bca, 0xf5c6a684, 0xbfa55946, 0x0617b9ce, 0x54d2445c, 0xc7e9c12a, 0x1053e3e7, + 0x5dd79b3f, 0xd5e274c7, 0x876cda11, 0x144cc27f, 0xde541652, 0x74e86caf, 0x1594ff7a, 0x359acec1, 0x31bef948, + 0x1fd89ab4, 0x34360cc7, 0x07cbc5f2, 0x9c773cac, 0x555f3c5d, 0x5c55dd8f, 0xb9a13e78, 0x1cdca5a2, 0x82667d25, + 0x24b15c55, 0x136ca96f, 0x2e93a30f, 0x22873a82, 0x587a7d59, 0x5c3ad70d, 0x05b8557b, 0x266d4556, 0x05a1b1f2, + 0x4b567c1d, 0xe44b37ee, 0xf5f936b1, 0x510ab987, 0x62814e30, 0x38af8463, 0x3b54fb4a, 0x2e743380, 0x75f3058b, + 0x37c9dcf1, 0x398963e7, 0xe613c0a8, 0x2178c406, 0x7f5a9864, 0x32b71b93, 0x64c1c4e3, 0xa4bde893, 0x7523b275, + 0x6c455907, 0x8eb118bf, 0xc26683d7, 0x11e60c5e, 0xf6a886c3, 0x12c1b7f0, 0x452cd752, 0xbe73d920, 0x7ab43cdb, + 0x0c1d33dc, 0xe725080c, 0x6076a032, 0x42a4c027, 0xc57e300e, 0xa5b28034, 0x831a9d2b, 0xb5adff28, 0xec66deb3, + 0x5c2d9c64, 0xb31e1bd2, 0xfbefacca, 0xda30e7c4, 0x9fb18c7a, 0x2cdbb28f, 0x3e1ff782, 0x8e8f1e79, 0x7edbb150, + 0xc54af1e3, 0x35b56c61, 0xcd365e51, 0x9014157a, 0x51702807, 0x1a489bcd, 0xd1439082, 0x466da0ee, 0x6dc80a2d, + 0x38511bbf, 0x0796e765, 0x65bda49e, 0xa0a50957, 0x8106d200, 0xcbf9ea51, 0x07d4bdff, 0xe2088b1a, 0x827e83e0, + 0xd5c655f0, 0x147159c5, 0x53d8310a, 0x6ec72c6c, 0x89eaca24, 0x8aac8f1f, 0xdd03bb3c, 0x32fdef6c, 0xa1d403e7, + 0x253b170f, 0x51341013, 0x5dc4144c, 0xf34e44af, 0x6ce64f9b, 0x2ce2f83c, 0xc7d0c6e7, 0x78e8dea5, 0xcb7aa519, + 0xb832226a, 0x2b184fad, 0xfcac7dd1, 0x886e9f3b, 0x85e46f76, 0x3406e145, 0x9c5da1b0, 0x4e391cea, 0xb49e44ce, + 0x01b78f41, 0x675bbd4e, 0xfdc696a3, 0x4db9c29c, 0xeb2c0a8d, 0x3253f31f, 0x1f842c45, 0xd8419b3f, 0x099b17f4, + 0x2bf5ae1c, 0x50cd2d25, 0xc4cb7a3f, 0xb48f2f5e, 0xc05516f9, 0x898392ee, 0x263426a5, 0xa1f7984c, 0x02ec424f, + 0x25b3ee2b, 0x10a53aff, 0xd4aad7c9, 0xf093bce4, 0x7de3533c, 0x7f3c2804, 0x9df629bd, 0x0e9c259c, 0xedaa38e7, + 0x956ce2fb, 0x12a9951e, 0x3ac96086, 0x0cb6fac3, 0x5e11af41, 0x9d5bb0c1, 0xf56d4c2b, 0x0f289afe, 0x07aee95a, + 0xcc9cdfa9, 0xe883e9a6, 0x085dbf2f, 0x60e5a611, 0x9af830bb, 0x409c3fc0, 0x8dddafb2, 0x2d7113f3, 0x05f1502e, + 0x9573e572, 0x8eff325f, 0x1b2a4d33, 0x0650542c, 0x6b3393b1, 0xecae8227, 0xb05163c8, 0x89e0d725, 0x06fb26a7, + 0x869aa7cf, 0x3f9c5b11, 0x1622fd9c, 0x8218629c, 0x391505cd, 0xc2a5f6dd, 0x3505c45e, 0x691fa14c, 0x9f25fe83, + 0xd248d7cf, 0xa4cb1f21, 0xaa3aa26a, 0x32bac5a2, 0x739b276a, 0xe20364bc, 0x411459d9, 0x529846ed, 0x9ba328f0, + 0x54269a0f, 0xf5d4764e, 0x9578dfbd, 0x32700373, 0x47938a85, 0x41a4061c, 0x32604149, 0x3fee33fa, 0xb229d479, + 0x5b529317, 0x7e333ec0, 0xd65da3f6, 0xd65cd1b1, 0x5701a84b, 0x7b1503e0, 0xc985455c, 0xbc05e88d, 0xc46c590b, + 0x883cab55, 0x124fa146, 0x48aabe1b, 0x57d73c53, 0x9874c431, 0x3c6de849, 0x2016ef53, 0xf55e52c6, 0xe899a3d4, + 0x97736e65, 0x3a45a24a, 0xc1d1e77f, 0xce1e7a39, 0x34bc46eb, 0x71de99d5, 0xdf08a347, 0x56974430, 0x174ddec6, + 0xd49bd050, 0xfb8c9b59, 0x2fa30417, 0xa051e633, 0x3b018727, 0x6f853a5f, 0x8b0d6b3e, 0x06a22b62, 0x9642c3ca, + 0x68ba7149, 0x829a8ffe, 0xc33e1068, 0x76d30528, 0x3c3094d2, 0x352e6419, 0x29a0182e, 0xc0b7ccb5, 0xfc7d3b8e, + 0x703d480f, 0x5d6fb1a5, 0x367dd636, 0x0f3ac551, 0xc81b98a4, 0x6a4fef7c, 0xdbe3dbda, 0xff225763, 0xaa84eb03, + 0x415b9b8e, 0x7b2eff16, 0xd5bbcd33, 0x2d3f8074, 0xd9070fa4, 0x99e1cea2, 0xd9bd5e6f, 0x9fb95d41, 0x440f661a, + 0x1eb54eff, 0x79833265, 0x6107e4ff, 0x333eaf39, 0x3ed2ffec, 0x063d6978, 0x9c17726d, 0x732a72d2, 0x71a343dd, + 0x4f7d5487, 0x7f9cb8c8, 0xc6c69daf, 0x09452b25, 0xc36aa178, 0x334ed624, 0xe20f6f06, 0x4510348d, 0x11ea787e, + 0x5b984a73, 0xf1d71d51, 0xd7bb28a7, 0x9f62ab5d, 0x086dc922, 0x189f0bec, 0x5cbcc61a, 0x772bc2c6, 0x72dc460c, + 0xf52b0a69, 0x1c6e53aa, 0xfdd2e75d, 0x088da6d3, 0xccb98655, 0x6bb92b01, 0x8592175d, 0x6c9da103, 0x92dbec5b, + 0x6d3e0aef, 0x0f2677af, 0x34686823, 0xfa70e253, 0xee640ec1, 0x472bcd29, 0x38ff1590, 0x1158d749, 0xd9381910, + 0xc83d93be, 0x1c0fe81d, 0xd2e7340a, 0x37a9bce2, 0x2c35a5a8, 0x065cf5e9, 0xab073a1c, 0x39291554, 0xc5bbfa6f, + 0xf60123f8, 0xc0149e11, 0x422b2b41, 0xa37d8fe5, 0x86515612, 0xf80d5617, 0x88d76fea, 0x1143db6d, 0xe5c43c09, + 0xfeaacccf, 0xd68c131d, 0x879f4a39, 0x4ee65007, 0x8bdd44d2, 0x26d52812, 0xd0a6fa30, 0xe1481fe9, 0xe502ea01, + 0xf1172ad8, 0x06064ef5, 0xdbb413e8, 0x47a3cf4e, 0xcfd53b57, 0xf84d65a9, 0xc084ab7b, 0x9d7e60ec, 0xde76277b, + 0x949331cf, 0x62852bef, 0xfcf32a61, 0x548be9ef, 0xa0ceaba5, 0x34f00ffe, 0x7a0a2b3d, 0xd3d25dc6, 0x38250237, + 0x919d9201, 0x728ce7f5, 0x9d8e0887, 0xeb32caf2, 0x5db3a7fb, 0xfbc0ca50, 0xce30345a, 0x22e71464, 0xa2f3b93f, + 0x16293110, 0xf01bf486, 0x4b7070f4, 0x257c793b, 0xe5f82c53, 0x864edca4, 0xe3e52074, 0xeb1bda88, 0x07cf1038, + 0xd970388f, 0x4a2ded68, 0xa301016e, 0xfb98564d, 0x422d61cc, 0xa2dbd0ff, 0xbecd6cef, 0x0bef9e1c, 0x9c847080, + 0xc64d8073, 0x8c0fa10e, 0x13d6163e, 0x94980f61, 0x4abeee15, 0x4d9ed6c3, 0x3501a472, 0x434f2619, 0x525247ca, + 0xbc0681d2, 0x89197045, 0xe4cd13b5, 0x937b1b72, 0xa4628f7e, 0x613b94b3, 0xdc60c0fe, 0x5231dc4c, 0x6860ec70, + 0xa6c674a0, 0xe3f4d9b4, 0x87f8a3a3, 0x03be28a4, 0xa581f037, 0x18d55248, 0x9f868cb0, 0x4c2f250b, 0xe5959804, + 0x32c5f14e, 0xb8e83a8e, 0x05dae3a3, 0x6b5bbdba, 0x4fcab6ed, 0x6a2790b3, 0x6ca6c87e, 0x50dc6ab7, 0xbc46e19b, + 0xa55fd919, 0x7f96ea6f, 0xdd736d81, 0x52ebeb49, 0xf89fd389, 0x542be155, 0x778a5352, 0xe532ac59, 0xa078d07a, + 0x9be71eb8, 0x7f2158cf, 0xfcfceed4, 0xf39567a9, 0xba317130, 0x065d035a, 0xe8dcd20b, 0x7439faf9, 0x03ef9859, + 0xc8c90c0d, 0xacfe8674, 0x862b7c16, 0x1cd7e078, 0x2b55689e, 0x00451d82, 0x04a0f016, 0x1d9c6df7, 0x8e261d76, + 0x9a1927a2, 0xd1955c0d, 0x48326a3f, 0xeae38f7d, 0x71860c22, 0x09798b95, 0x2c6ad048, 0x4af4b227, 0x7c8036ac, + 0xe35bc880, 0x62101866, 0x8dfa5204, 0x05d39fd9, 0x99da0586, 0xc32b2d66, 0x37457809, 0x6af0259a, 0x119a08a1, + 0xe528ce8a, 0xc096b0df, 0x8dc7ae2c, 0xa27d58fc, 0x9e6ce3ec, 0x78e81a7d, 0x69aa4a08, 0xa1380fc8, 0xb21821f8, + 0x6a1eab5b, 0x644f8ead, 0x46e6fd09, 0x32733b17, 0x548def7b, 0x95e4eefa, 0x09e471eb, 0x23c99a05, 0x3e0c9ff6, + 0x9e9e3f2e, 0xc71c9f39, 0x44202fb9, 0x65887e97, 0xa6b6447e, 0x91b323ca, 0x6f9975da, 0x1c1dd406, 0x13839eb4, + 0xafd77d7d, 0x74c7cfeb, 0x60153665, 0xbd51618c, 0xd9c0d58b, 0xc236e1ea, 0xa21e8c9d, 0xbb226d47, 0x5042619d, + 0xc0318add, 0x1be484bc, 0x8c48e4ae, 0x4ca56480, 0x4c246af0, 0x54f9ae0b, 0xe08f6794, 0xafd544de, 0x571071d6, + 0x76ba688c, 0x62e0f7d8, 0x75def34f, 0xd4c804db, 0x81462ea6, 0x1d5dfc2b, 0x944f3b1e, 0x01da772c, 0x9f13e0bb, + 0x130905be, 0xe4159006, 0xa0cc9a29, 0xec951acb, 0x8cf960fc, 0x922ec054, 0xd15177ce, 0x4701abaf, 0x7c5bb02e, + 0x9c6a776d, 0xe6456ee8, 0xcd72c3ef, 0xaec1f952, 0x909af6be, 0xaea3bc00, 0x558105d6, 0xb0bee769, 0x93441416, + 0x2088504b, 0x21fb02c0, 0x5769c5f9, 0x703e5a79, 0x9e105b46, 0x91a35c7f, 0x56d3b4dc, 0xd04f4a44, 0xedbcf647, + 0x877a32fb, 0x1ab06e3c, 0x917b6f43, 0x33e06b7b, 0x0974ae31, 0x8f41f35d, 0x093b4776, 0xc37956b0, 0xf93d7aa4, + 0x9ae8a91b, 0xc717c4f0, 0xc154bf5e, 0x89e61ff6, 0x9153b6af, 0xa46546cf, 0xca6047a0, 0x6e467e25, 0xef947ec3, + 0xef839839, 0xcc4d25bc, 0xe86d65e8, 0xa52e14c2, 0xb35b1551, 0x5652675f, 0xd94589ab, 0xed61ce37, 0x5f3e79f2, + 0xec3ef362, 0x6c7ed31b, 0x8d562e19, 0x970a54fd, 0x49ff4d4d, 0x6d27803a, 0xa48ef3a2, 0xcb61327e, 0xe7827245, + 0xcf5ce237, 0x01cb40c6, 0xd0601b5b, 0xa44c5f3c, 0x345d7689, 0xa3974b2b, 0xaaea3f23, 0x5dc810bd, 0x01c21201, + 0x33e1082c, 0xeb01c95c, 0x9353bb5c, 0x9affd22f, 0xcdcf20d2, 0xb1ab27ec, 0x96cd558a, 0xbbc85065, 0x3a0fef95, + 0xbf41a14a, 0x66715442, 0x4d58d4d0, 0x35d647ff, 0xfb1ff189, 0x4c5ed95d, 0xbbebb20f, 0xe74bb798, 0xd4262e98, + 0xf95335df, 0x4ec94886, 0xff863eaf, 0x5440ed89, 0x86b59e6b, 0x84dd2ee1, 0x341a01e0, 0xceeec0c0, 0x7dd42555, + 0xea7a0b93, 0x5b2c6a6d, 0x6ebd1b95, 0x326f539a, 0xb87ddfd7, 0x5b68c8e1, 0x19bcd8c7, 0x99e1a2c5, 0xd6fed0bb, + 0x9c962ca9, 0x7bc53f40, 0xd5fc94f7, 0x12f9c584, 0x5a040938, 0x83bc2e61, 0x49ff3f85, 0xd542db20, 0x8f345926, + 0xbef6b3c9, 0xdce85d87, 0xd57de666, 0xc603585d, 0xfb0e390f, 0x00fabd7c, 0x74bda59a, 0x0383a854, 0xa088d4f0, + 0x1d80341f, 0xc02d0b66, 0x185a4866, 0x447f2e16, 0xe8d13068, 0x43cb58ad, 0x8a278812, 0xffe0e7ef, 0xd478b430, + 0x253a3ca9, 0x7433e2ba, 0xc4f2c01a, 0x79fe6db8, 0xcd8fc313, 0x08178dfc, 0x2beb3e78, 0x5532388d, 0x91a0a6bb, + 0xd8ec833f, 0x76906180, 0x17f02ae6, 0xa7870654, 0x0bd92fd3, 0x2fe748f9, 0xf4d00098, 0x5ae02ae4, 0x5fca32bb, + 0xe015c6b0, 0xd9f700cd, 0x525d7eb7, 0xa0bcc664, 0xbde6c892, 0x5e0615dc, 0x0a2350ea, 0x6bcab326, 0xe4be0d66, + 0x4e9225c4, 0x87272dbb, 0x4aa2c3dc, 0x1a62e8ff, 0xa16fba34, 0xcc2e22c2, 0xb953bd73, 0x3d0a6b84, 0xc81d12dd, + 0x5aeb4a36, 0xed1b395c, 0xc0be6b42, 0x76da0e6d, 0x954eaf24, 0xe472fc5c, 0xd2493977, 0x33ec6a10, 0x70c562b4, + 0x99ac3b2e, 0x4f892fd3, 0xf60140e8, 0x473ad5e8, 0x50343250, 0x6cb15bdc, 0x1701c903, 0x7638c204, 0xe21b07b6, + 0xf23eed5d, 0x782b4ba9, 0x11f9a1ce, 0xa4165e6e, 0x02b5ca26, 0x71b3f6d0, 0x2048ba51, 0x227d08ae, 0xa73d045f, + 0x9d04b4d5, 0x8c336e75, 0x36b7034a, 0x6968519a, 0x1aeb23ea, 0x46041397, 0xcd409890, 0xa646dd07, 0xf7b57596, + 0x65ba33fe, 0x6d57cdbd, 0x8e182eb7, 0xaf6e6d90, 0xd551d5a0, 0xf394d3c4, 0x10cdb99c, 0xb605e677, 0x0dca2690, + 0x0705d0cd, 0xd73b304f, 0xe9a1afe8, 0xc9a0d69e, 0x20e85c21, 0x31647a33, 0xba6bac3b, 0x3c621464, 0x48da4438, + 0x34ab3886, 0x03ea03e1, 0x3f8766ab, 0xbc606c6d, 0xfb46eb0d, 0x7369adb9, 0x8dda337c, 0x685948ef, 0x7949f2db, + 0xce3e6027, 0x4b7e9d98, 0xd61ace88, 0xcf77be42, 0x9f53caa9, 0xbfbb5873, 0xff7b302f, 0x460c644a, 0x69847f20, + 0x81f74e85, 0xc290a5a6, 0x6caaa23e, 0xd17efac8, 0x25138451, 0x6dd7e258, 0xf67bb2a6, 0xd7cc5018, 0x9c873e7e, + 0x6768ea65, 0x2d09fb31, 0x5ebe2784, 0x9e93658e, 0xa9a20d9b, 0xb27caa85, 0x4504ac75, 0x6062a1be, 0x774ae53d, + 0xaf6853c8, 0x5fca10dc, 0x157a7407, 0x3899d622, 0xad8750c7, 0x4ef9826d, 0x8d041061, 0x6b036fd2, 0xa8da65b2, + 0x90608b8e, 0x78c5f89e, 0xf5f40aa5, 0x40cfba08, 0xdff90b72, 0x2cd5170e, 0xe7003fb0, 0x3cd81138, 0xd4c96019, + 0x4dded48a, 0xf3db2a25, 0x206e96db, 0x7530ea68, 0x081e5824, 0xfe68bd59, 0x8340e16b, 0xed523f89, 0x71d9a86e, + 0xcbec7e5b, 0xebbe5473, 0xecc94abc, 0x4df12f2c, 0xecc7ca9a, 0xecabbc33, 0x93111cf7, 0x554238e4, 0xbbbfb3ce, + 0x0fa68fd1, 0xfdc08f68, 0x30ab12e3, 0xce3ef606, 0x2c598e24, 0x3a167332, 0x72495e64, 0x24327ffe, 0x3ea282eb, + 0xc842ac63, 0xaad329e7, 0x4e2661b0, 0x36a7ad7f, 0x35dd90f1, 0xd2467d81, 0xc1fc11aa, 0x889a95d5, 0xc93b580d, + 0x79ffeec3, 0x9d838128, 0x26f466bb, 0xa925ad39, 0x62b1a904, 0x4e8a01cf, 0x5e8bc3c8, 0x57ed45f6, 0x179a6eb6, + 0xb7f8a1fa, 0xe7680bee, 0x3e64e24d, 0x28de525b, 0xc601ffa3, 0x05226ea2, 0xb53ee700, 0x2408227f, 0x76cff815, + 0xd96b11e8, 0x7bcdc174, 0x1d514971, 0x47d9ab98, 0x3cf38305, 0xd8128631, 0xd0b466b3, 0xc9ef4515, 0x96c7cf05, + 0xf0d66a7d, 0x53789e21, 0xcc1f9d49, 0xdd6757a7, 0xd768dcee, 0xa3862bae, 0xe481091b, 0x3382f923, 0x309e8986, + 0x49cc4e60, 0xde1ea980, 0x47ab960c, 0x6c088a06, 0x81f4cee3, 0x08cfdc37, 0xb08f8747, 0x6ae576ca, 0xcd46509e, + 0x35901bdc, 0xeb644e5c, 0xd97b448c, 0x310e042d, 0xd5877978, 0xa31b823d, 0x48d170c8, 0xf2e1d5fa, 0xeedcd045, + 0x3a23dd46, 0xca5d5c0c, 0x58268705, 0x047c1e70, 0x08cb7765, 0x113bed8b, 0x47cf1687, 0xd3e60c79, 0xd3133dad, + 0x83350543, 0x3698b56d, 0xa8182eeb, 0x66ddc1ba, 0xc26454e2, 0x3909c1c8, 0xb21453e7, 0xa68647c1, 0x3e9fd122, + 0x5f665a1a, 0x6d7f8567, 0xd4c894d5, 0x4d4382cd, 0x37a306fe, 0x0893c031, 0xcf744cf4, 0xb35745bb, 0x784cfbea, + 0xd5159235, 0x68d09c8a, 0xd2a92bef, 0xc6f2a238, 0xe1a4448f, 0x1de70af4, 0xd31d1716, 0x5f5f8afd, 0xc68352d3, + 0x9c24a215, 0x10bc3fcb, 0x6dcea616, 0x8aaf75f3, 0x8dea70c2, 0x242f7105, 0xe3773a4d, 0x11075830, 0xbc8e7f0a, + 0xe833c95b, 0x110b3597, 0xadcfe230, 0x7b0d9f81, 0x5b0a4a71, 0x10d4e534, 0x181dd6d5, 0x9a494995, 0xab74b15d, + 0x9a0d392e, 0xc3c34f95, 0xbe0ccd47, 0xacb7cd69, 0x770ef6cc, 0x2d529f7a, 0xbb4ad0fe, 0x9c0a15e7, 0x8067af25, + 0xa7ad6fa4, 0x0f7ce820, 0xef1140e5, 0x522eb061, 0x30aa9a12, 0xc1d628d6, 0x42245948, 0xa0539a17, 0x7af8a886, + 0xae619f0d, 0x745d957c, 0xda2199c2, 0xf040e53c, 0x06e42413, 0xbfc01838, 0x71c6554e, 0xec487f35, 0x681d426c, + 0x75e2076d, 0x91fbc98e, 0xafb139f4, 0x7f54fbf5, 0x450c5e4c, 0x212fd024, 0x5b81098d, 0xa3f6056b, 0xba285915, + 0xc3877c4f, 0x951f847c, 0x37ecc15f, 0xab9f264c, 0x9ca67c0e, 0x8676d096, 0xe60dc563, 0xaf2c8b20, 0x80d10db4, + 0xdc3bbc73, 0xdd7829cf, 0x0c8f296b, 0xbc0b9300, 0xf6d990d8, 0x82b06f57, 0x633df5b2, 0x00e607c3, 0x33822cc4, + 0x26e05dbd, 0x6992c1e3, 0x32bc1b0e, 0x33ff43dc, 0x19b2957b, 0x70d72b32, 0xff93c7fa, 0x51bf508c, 0x5bfdf135, + 0x7a632aad, 0xd3edfc47, 0x0bbfaac5, 0x4217c887, 0x4e7d1d04, 0xe0fb34fa, 0xaf109392, 0x1f4bcef9, 0xe7255043, + 0x60447538, 0x54f7c621, 0x733ab8a3, 0xe86ff634, 0xa72e2ee1, 0x7de5b7ba, 0xf54395c1, 0xcdbf13ed, 0xf8e0c3c7, + 0x6ac01564, 0x43a98608, 0x3ef7fef8, 0x621f83da, 0xab6de70e, 0xa23a939e, 0x5791279a, 0x929e0d9a, 0x51836fa1, + 0x7659746e, 0xa5ab4380, 0xf16aa5ca, 0x6d393a27, 0xecb47bc8, 0x1b7289d6, 0xb6e3e435, 0x1d08d72a, 0x2c901db2, + 0x9f2b609c, 0xe174e6c9, 0x672ca50a, 0xd25d80c6, 0x7a792b8a, 0x6521222b, 0x5b4a5f36, 0xd0e32696, 0xad0b9072, + 0x58d2d49c, 0xc604293e, 0x8c167be1, 0x5f8cae69, 0xba4873aa, 0x18de6e7b, 0x3bd54273, 0x41693fa9, 0x49527a67, + 0xd637b22e, 0xf9ce1e69, 0x0a7345df, 0xfe85bfb9, 0x5ee54f20, 0x10b2aa04, 0x47978c8b, 0xec8908f3, 0x53c53334, + 0x1fbc976b, 0xe8ccb5b1, 0xad542541, 0xdc4a9805, 0xcb8237b0, 0xcf9f8557, 0xc563bcec, 0xb64d5f97, 0x0fa89d3f, + 0x383ace8c, 0xf4f6e041, 0xc5bec31b, 0x06e6966b, 0xdede3e5b, 0xfe671752, 0x12ff805d, 0x67513814, 0xf848bd20, + 0xfed28bf2, 0x54c4c711, 0xb718a4fb, 0x4e92c0cb, 0x42e00d31, 0xae44fd82, 0x69880d2b, 0xd750a431, 0x83e3df20, + 0xe54943ba, 0x082d5e31, 0x17b928cb, 0xd1c64eb2, 0x1618add7, 0xd9793fb7, 0x69a299db, 0x35722022, 0x65ee2d80, + 0x9c444bc1, 0x2fc81202, 0xdd83b603, 0x58c7f3be, 0xefe645eb, 0x8add60b8, 0x343a9e87, 0x7408461a, 0x5b252889, + 0x9e7ab6c6, 0x2a8e3482, 0x01a36260, 0x103c71e7, 0x18cdc915, 0x2cd1f30c, 0xa7098bcd, 0x4452ac79, 0x033d81e6, + 0xe27cdf9c, 0x2fe5256f, 0x3e9a0d0c, 0x73814333, 0x0bb7f6f1, 0xeaa1c9aa, 0x832ece91, 0xfd1666a7, 0x53b41b85, + 0xc83670d4, 0x6bc2a370, 0xfa5aa8d4, 0xc35b2846, 0x4bd6a9e7, 0xe56b2704, 0x053eaa9c, 0xfbc1d8fe, 0x4f0513bf, + 0xce13a37b, 0xc91e2865, 0x4e18415f, 0x149911d8, 0xe29087f4, 0x4e15eced, 0x0d4badfc, 0xebe7e96c, 0x08ccc618, + 0x01d57dc3, 0x8c2c70e0, 0x873881e7, 0x435fc4ba, 0x4fc47318, 0x5b8e371d, 0x1338e672, 0x38c70ba7, 0x664c6b69, + 0x63b8c126, 0x3118205b, 0xed6718db, 0x8a01ba2e, 0x667e2f58, 0x97ca7a7b, 0x9a6ed6be, 0x5a2721fd, 0xbe5a2c19, + 0x12d87e44, 0x3a8369ec, 0x624ab1e8, 0x93d040a8, 0xbe3a1688, 0x16c221a9, 0x6265ca26, 0x451a8dcd, 0xcb42c195, + 0xa80d3451, 0x186cbe9b, 0xba4fae21, 0x29852c13, 0x0ca03cff, 0x00a1aade, 0x672da729, 0xb91c1ba5, 0x1de2bb9c, + 0x4308943d, 0xdf595f97, 0x554d59fe, 0x4eee6860, 0xe4d3e3ac, 0x40644477, 0xffc49995, 0x37fdc6a5, 0xec3be259, + 0x5bb181a6, 0x0181105f, 0x7b938dac, 0x5ba6f95d, 0x3111b489, 0xe1260410, 0x0a31e6cc, 0xb533c5cc, 0xc17acf91, + 0x573e1617, 0x4fd83b94, 0x7797651f, 0x74e269cb, 0x4f68c40b, 0x31d6ef8e, 0x24dabf25, 0x333d04a8, 0xd4454806, + 0xa26089b3, 0xb48be14e, 0x4ec44cdd, 0x074f1b5a, 0xaee9c3cb, 0x78da10b8, 0xc2dad211, 0x5da4833a, 0x58b91728, + 0x5d63f45e, 0x89abd3e9, 0x0290fe4a, 0x35450cd0, 0x1a95e42c, 0x56a49a49, 0xd3364eaa, 0x8677584c, 0x7466ebd0, + 0x456c1a9b, 0xbb3e6030, 0x65e17104, 0x4a6c1f43, 0x7246c87b, 0x60951edd, 0x97a1acbc, 0x120bf41f, 0x477f9850, + 0xf71e771b, 0xfce71e66, 0x9871b285, 0x1fa81e62, 0x46971f83, 0x0d4f2742, 0xb9fad5f0, 0x43f5d744, 0x28b8ef81, + 0xe315a3f6, 0x43c7ee6b, 0x69d186f1, 0x1ba5fcdc, 0x851cb73c, 0x900cfc56, 0x4c32101b, 0x74d4a944, 0x6a5ba06f, + 0x385e6de1, 0x36434e5e, 0xb32f32ee, 0xe1d2b37a, 0x662ca471, 0x64b5777d, 0x8e687727, 0x141f17be, 0xe8bf8669, + 0x00a693f9, 0xd1fb5ee0, 0x5dd61ea5, 0x44f5d5d7, 0x0fef4f3f, 0xcff41896, 0x67af4a45, 0xff639dd6, 0x83f2e6e6, + 0x0e4a2d38, 0x8340cbd8, 0xb016cc59, 0xfe7c6e01, 0x5ac1ff76, 0xdbf274a2, 0xcddff611, 0xc49c53e3, 0xca90d6fe, + 0x8ec804df, 0xebdfb689, 0xcb26c805, 0x21041169, 0x90abc844, 0xbb0f44e2, 0x23417f21, 0xe3bf14be, 0xb667ee93, + 0xd3047b8c, 0xe4dc5c23, 0x9932eed8, 0xf4ab6e7b, 0x9fc12d1b, 0xe2cbb531, 0x2dda520f, 0x0f392004, 0xf45c505a, + 0xc71f65dd, 0x11cf55d4, 0x466bc888, 0x8b102e48, 0x25e54c31, 0x485a0d76, 0xf90a5d51, 0xeca3b108, 0x1a7fdc51, + 0x5b06c6e7, 0x4089860c, 0xc01b6346, 0x67189885, 0x8b9e7e2c, 0x1713e419, 0x3d4ad6b1, 0x7141ce96, 0x6e994b68, + 0xdad3d870, 0xc9026ce1, 0xc6c02ed0, 0xf0467a0f, 0xb8ddce59, 0x73bf2322, 0xd23dc90d, 0xc4527435, 0xd661b923, + 0x3d43d566, 0xcfdf4e99, 0x1da6491f, 0xb686c2d2, 0x5ce50e8c, 0x34be945e, 0x38be7058, 0x7456e158, 0xe12e28d2, + 0xd4217009, 0x68bbfcf9, 0xd7bab138, 0x63447cec, 0x4f9636d7, 0xe97bacc7, 0x4a3a989e, 0xe96c5526, 0x219c76b5, + 0xad21a33e, 0x8dbed0b3, 0xabfaabd5, 0xd501b0d0, 0x2d32ca7a, 0x548dd536, 0x4a151a80, 0x1cefb2be, 0x75837903, + 0x8fbbc86b, 0xef412de2, 0x01050228, 0x6cd3674a, 0x0c10ac77, 0xc6b58370, 0x326bca88, 0x16d54cda, 0xb18bb2a5, + 0x9526827b, 0x75fa88b2, 0x76cf5786, 0xb8038046, 0x49d627f1, 0x0a53e086, 0xeaa0a596, 0xf1c2754c, 0x990f0b63, + 0x63a64e2e, 0x5500166a, 0xa7363c00, 0x117bd9b4, 0x5b621c37, 0x587b9c59, 0x815623c1, 0x00e2b0a6, 0x907fdef6, + 0xf64d6419, 0x07ffc920, 0x4fb7bc4c, 0xb7856c1a, 0x9281eec2, 0x45265f99, 0xe4e4a089, 0xab4b1666, 0x0549c7b9, + 0x4df578b7, 0xbbe8b845, 0xc012ef91, 0xc4513d4e, 0x2a06990a, 0xf9540885, 0x70c14b7e, 0xd6f8bd67, 0xb36c2616, + 0x131d7d9c, 0x2108d274, 0xa0ca8cd3, 0x4b73f759, 0x1965e067, 0xc024cc0f, 0x9fce8c2f, 0xcb872fb7, 0x46f6b2d5, + 0x134a2e25, 0x4409e8e2, 0x45441e04, 0xc3d0a0f7, 0xa4ccc3c5, 0xc576039e, 0x8b6b6677, 0x9be9a1c7, 0x67c6a975, + 0x0e4503d1, 0xa396f010, 0x82b680b7, 0xa3823ef4, 0x3cb061e1, 0x6b53363f, 0x2e2cfdc0, 0x28963990, 0x9c26ab43, + 0xce98c00e, 0xbf5cffa5, 0xb0b7b522, 0xf8fb3efa, 0x60e84a25, 0x63398a38, 0x912d0c8f, 0x4135ff6e, 0xa27c2936, + 0xadd3453c, 0x231ab4f7, 0xeb2aca3a, 0xf50bce93, 0x0dbced10, 0x610b5dd8, 0x1f2f7276, 0xdb1b6776, 0xf13de54a, + 0x6cb3d1e9, 0x7efad938, 0xb4d4ff61, 0x2da339b1, 0x9c25ddea, 0xa3768bb1, 0x37908773, 0x8eee5667, 0xe34672a0, + 0x6c9a08f5, 0xbdc30cfd, 0x03746ea3, 0x136dae86, 0x8c13e9d8, 0x800b971c, 0xfb51b2af, 0xd363905b, 0xb224c0bc, + 0x10339e82, 0x861b018f, 0x600be797, 0x5f9cd774, 0xd35c09e4, 0x7ee65a3a, 0x546660ea, 0x20bc08ff, 0xf1533ac1, + 0x7eebf4d3, 0x4c6848f9, 0x5b1d197d, 0x3a45e275, 0xa49d6575, 0xeaeee48c, 0xb9646f1a, 0xd1e2f0d0, 0xe0bad8a0, + 0x72d3c410, 0x3c169cea, 0xe2a3ad85, 0xeef7f98d, 0x4adaf420, 0x94cca8a1, 0x2d7b71e4, 0x2123cd9b, 0xb1509fa0, + 0xde9df0e3, 0x88a65c29, 0xa3dbf387, 0x8aa5b30a, 0x958e5dbf, 0x1a1ab99a, 0x9a84fe74, 0x2bcf681e, 0x8b1f98f4, + 0x1d20ab15, 0xf6d380c3, 0x063cba62, 0x96ad607b, 0x6f3044e6, 0xe674a790, 0x4d04879b, 0x94f2fadf, 0x574f7eb2, + 0xcb2dbd29, 0x6ca56307, 0xf2d3ffd5, 0x1a924340, 0xebb4faa0, 0x4a7256ef, 0xe2c8a1ef, 0x45160208, 0x0f405f50, + 0xa6de8daf, 0xe00dea18, 0x4c6e3352, 0xbbfab057, 0x1474bf49, 0x912bcf1d, 0xdb9500ab, 0xb5cd218a, 0x0a95440e, + 0x740fe13c, 0xd56f9ff1, 0x0d43696c, 0xe188208c, 0x9601e65f, 0x305c0cf2, 0x9aa552d9, 0x9509efd1, 0x21164815, + 0xdb2da2fc, 0x489a81a3, 0x2f351e9d, 0xe3a00f4d, 0x8cec1445, 0xffeb824c, 0xfbd10e01, 0xa70e1aab, 0x00cc961b, + 0xc74c24aa, 0x199ffac7, 0x573fa6c3, 0x2d78858e, 0x8417d9bb, 0xf12c63a6, 0x790dc50c, 0xdcd9556c, 0xd5b1e21b, + 0x87161db8, 0x3ac9cfaa, 0x1b0d8361, 0xf2d4c590, 0xc27c25bd, 0xdb9e38d4, 0xb01b5eb6, 0xd634f667, 0x663c1be4, + 0x20c9e67f, 0x4b91e6af, 0x03fa07d8, 0xc465a82b, 0x01cda297, 0x10a5ea6e, 0x38a59043, 0xb7e0ead0, 0x830638b2, + 0x5bc23e2b, 0x93eacd69, 0xae643b05, 0x10803dd1, 0x83a77638, 0x8eae786d, 0xc3fe8649, 0xe0c48484, 0xd99aacc7, + 0xff4495e1, 0x8a9d4202, 0x1c4a85e6, 0x6b5ab53d, 0xcdfc9010, 0x0b26f329, 0x550f3c22, 0xc55ba6eb, 0xbf9c640b, + 0x803480e9, 0x4fa1ac61, 0x190de29c, 0x7f0a8680, 0x2de69fe0, 0x78f1fd1e, 0x7bc88472, 0x13706a7d, 0x72978dd6, + 0x5d4095ad, 0xfe2e4509, 0xd042ab24, 0x69cf0d65, 0x1be93bfd, 0xef8e5f69, 0x9c365686, 0x75ec268c, 0x8f43b0df, + 0xcd3f81fe, 0x85158437, 0x753603b7, 0xaff6fb6b, 0x2a30bce8, 0x68511711, 0x7d0053a7, 0x9fd0d887, 0x16a86fdf, + 0x33c2827e, 0xa4c4fcf4, 0x0f9a6a38, 0x875fadcf, 0x49987fbd, 0xebcc763d, 0x6776c2af, 0xbd699311, 0x39f57d61, + 0x8a272aa2, 0xda3678a5, 0xf2ed26e0, 0x447a4dcb, 0x98ccbc77, 0xcf1c4e4f, 0x923003ac, 0x0746065d, 0x62449cee, + 0xe0df7807, 0x7a7619a6, 0xa52e5195, 0x0c8efa3e, 0x00bcf241, 0x462a9609, 0x9cb6c828, 0xa7582a77, 0x8cca96a1, + 0x09191950, 0x159064b5, 0x92e19451, 0xf667dc46, 0xc1c9ddc8, 0x90269f86, 0xc2de8522, 0x022a565b, 0xb63634f2, + 0x2e7731c7, 0x4804b783, 0xffce801a, 0xe03701dd, 0x350833e7, 0x599c5880, 0x6c2ae660, 0xcf8ff5cc, 0x79d46b18, + 0x4ae38b7e, 0x0b485560, 0x079ab577, 0x40410b23, 0xf0cd70c2, 0x6af6dd55, 0x299f6a4b, 0x50d9ec4c, 0x181c726f, + 0x657077b7, 0x404ffbfc, 0x2fc080a5, 0xabe2bb8c, 0x3eae618e, 0x81015988, 0x95cb331a, 0xce8d7757, 0xad1b7184, + 0xb146b19e, 0xcd26b4f7, 0x9aaea108, 0xbfbe478e, 0xe2f4effd, 0x79787336, 0x45db2a71, 0x7d3f4ac5, 0xe539399d, + 0xa48d109d, 0x2d82434b, 0x78d5e394, 0xef8b5e5f, 0x38466c66, 0x9011a15b, 0x95d452a9, 0x3d21c907, 0x6a1a2df2, + 0x831f8f18, 0x1a0232b3, 0x2df691aa, 0x0bcea4fa, 0x5c80ec04, 0xd0f0da0a, 0x6004d567, 0x4f659079, 0xbbf82337, + 0x262bb9d5, 0x49b0d890, 0x6e0aac4e, 0xfc7863ee, 0xabe06e68, 0x62248308, 0x9e7453a2, 0xc6b6cb4e, 0x9acfd76e, + 0xc1231a4d, 0xc7de2bca, 0x863b26d9, 0x63f968be, 0xadcb7224, 0x0f02359d, 0x7023586e, 0x7758910b, 0x26141e1b, + 0x601f2a77, 0x0f46a0f4, 0x0ee3503c, 0x22fae0a0, 0x8d241e1f, 0xb790126a, 0x2cf6adcc, 0x5286647e, 0xacbfac7b, + 0xbe13df51, 0x10c0254b, 0x33b09b3a, 0x21d8ac9a, 0x0025898d, 0xfbd888bc, 0x58ebbf02, 0xf445537f, 0xb547cedc, + 0x0e785a32, 0xaf374b02, 0x211cfe85, 0xe3b794e4, 0xdc74b61f, 0x83ed8aee, 0x3db8c513, 0x7d2383d8, 0x324b67e2, + 0x91c8a6b8, 0xa09bef08, 0xbb44a4ca, 0x7c2f6c11, 0x09855588, 0x120821e4, 0x2c5d376d, 0xc50a6bd5, 0xd23097aa, + 0x4455a9af, 0xed00f97c, 0x1c94ff50, 0x2c67575e, 0x6c9f9d44, 0x83221179, 0xd6d274c4, 0xb59a7097, 0x4a895001, + 0xcc955d43, 0xee1389a7, 0xb726c0dc, 0x55c2365b, 0x80a11e52, 0x93022448, 0xc7eda76a, 0xb91a661f, 0xac4a619b, + 0x96b0edad, 0x39c2acde, 0x0f364379, 0x4e84ffa4, 0xf5a2cca7, 0xd31b5459, 0x8ad97e12, 0x6b2deb0b, 0x98cb27b1, + 0x7d81e5a6, 0xc32ad2c1, 0x40b6139e, 0x4b8e87d4, 0x30c273a2, 0xfedcd103, 0x65cc9216, 0x51c7778c, 0x03757d02, + 0x6232c535, 0xf7ea8318, 0x9d2863ba, 0xb2a2809f, 0x954a24f0, 0x3cfcaffa, 0xe91545a7, 0xc3e3b57a, 0x6cd4e59c, + 0x7e8aa889, 0x01ea6e82, 0xbe84afd2, 0x8e48ddad, 0x20e52e37, 0xd69f0bd2, 0x531bca8b, 0x6417e825, 0xc0b1193c, + 0x2496b453, 0x8e12db5c, 0xe3ccd831, 0x80063e04, 0xa07ca344, 0xb431da30, 0x4a5f3813, 0x20f2118d, 0x98e8ff0f, + 0xdaf314b5, 0x1d189fee, 0x4daa13c4, 0xb664594f, 0x0517d4c6, 0x1e38fb50, 0x8e914f82, 0xa7e64f52, 0x1623e651, + 0x6f97a81e, 0x8f585238, 0xad38c77b, 0x8e91fc78, 0x5d556ecd, 0xa409a9a8, 0x61496dd3, 0x1826d4e9, 0xe34dec5d, + 0x702b23e0, 0x589f2d35, 0x25cd1517, 0xbb960e4f, 0x606019a4, 0x24dc3600, 0xc3decd59, 0xd4cae84f, 0x9c356cbf, + 0x43ea5160, 0xc502c7e6, 0x2dcff742, 0x0bce2e48, 0x29af08b7, 0xcc3d59b8, 0x01f2c3ce, 0x35073757, 0x647841ab, + 0x2755e593, 0xb6190340, 0xa4c0d4b3, 0x5db156f0, 0xd894c023, 0xb71081bd, 0x3101239b, 0xd3eabaff, 0x30d6cab5, + 0xfe075b57, 0xf1b6badd, 0xb58f91bf, 0x44ec5518, 0x2675f878, 0x63bc057f, 0xc9c150dc, 0x809ce74e, 0xafc382e2, + 0x6edc836f, 0x005db0fa, 0xed631e5d, 0xaad6ac20, 0x4af727f1, 0xb1c7b81a, 0x0513fb05, 0xa618b6dc, 0xf2c4373c, + 0x201f936c, 0xf6f3484c, 0x9adedc06, 0xb4418479, 0x09eb9d63, 0xf9d9e842, 0xe3336099, 0x680ca7ae, 0xc4c8f912, + 0xe4567623, 0xf8634177, 0x6739ef06, 0x584b3c48, 0x2efb12d4, 0x3bde8a66, 0x87cc5648, 0x10160167, 0x6f5394b8, + 0x8a7491cb, 0x98cedf1e, 0xfe3cc2cc, 0x61693295, 0xc71deed4, 0x444ddf3c, 0xafcce847, 0xa1028939, 0x7df736de, + 0xa8b29984, 0x515b0cab, 0xccf7de08, 0xcd736d2a, 0xe79f3c7a, 0x0e6b53f1, 0xfe118d52, 0xf9cdffca, 0xc740558e, + 0x3edd79c3, 0xb610cca1, 0x366895ea, 0xee2c264f, 0x63bc36d6, 0x5b80ca72, 0x3b38bcf7, 0x27c171aa, 0x7de2ba00, + 0xab97671c, 0x9ae2fb4e, 0x15d73366, 0xfc934d7c, 0xe99740e9, 0x2f304299, 0x2548620b, 0x2c2a9a47, 0x668f9994, + 0xebae4555, 0xf4ea60af, 0x7d74508c, 0x3448d5e6, 0xdea21672, 0xab603907, 0xdaa6cdb8, 0xe825c4b6, 0xbe0fb300, + 0xedacfbba, 0xb68d776d, 0x0079a32a, 0x3539a7cc, 0xd1b96db4, 0x55014ff6, 0x66cfcd52, 0x54300288, 0xe18bdf6b, + 0x8c3ec40c, 0xd99b259e, 0x098234db, 0x263f6141, 0xdeb182a6, 0x91cdc1e5, 0x7b194c40, 0x8dc8c4f8, 0x60d1fa10, + 0xf940dd5c, 0x3f06b4f4, 0x54a874b7, 0x26f399b6, 0x55b46160, 0x34cb0b2e, 0x24350449, 0x587378ba, 0x8b07c881, + 0x336a9965, 0xddd9d30d, 0x0a92531e, 0xefb3d4bd, 0x41fb5068, 0xce531ea0, 0xde935272, 0x1eb76f02, 0xf9353c53, + 0xbbb0d244, 0xe2eec5a4, 0x095e054f, 0x3b5f0fc0, 0xf122982a, 0x9bc08d0c, 0xfc9a3cde, 0x898be9bd, 0x62dd4e97, + 0x9d13e8a3, 0x5772ec60, 0xfde59e66, 0xf5091553, 0xc8693e87, 0x984d77ee, 0x6a0b12b4, 0x16809e4d, 0xf704f975, + 0xea82dd89, 0xa0a4011f, 0x11311622, 0xc7b59d2e, 0x72febd54, 0x6fa9c268, 0x767c6120, 0xe2957dcc, 0x90927d21, + 0x464b0d74, 0x9ea7d083, 0xc5b4def5, 0x6feb63ed, 0xdc08220f, 0xfe685910, 0xe6af5a69, 0x0779f31c, 0xcfdd0052, + 0x767fb50c, 0x20372e4e, 0x9e57d6c1, 0x3249f961, 0x18460b27, 0xbd2cc131, 0x1dc97f46, 0x176b7086, 0xe7d2525a, + 0x784a7cc5, 0x4285e1a2, 0x7abb4e37, 0x07d5d0b5, 0x9eb69fb4, 0x4ffc6248, 0x1fb3aba6, 0x4c25e562, 0x7fdc3dbf, + 0xc1ba9ded, 0x5a3f87ad, 0x34c57d6e, 0x2fdb0b06, 0x1fe6ef41, 0x7cca26f4, 0xd9b2cca1, 0x9d544f8e, 0x29f2c907, + 0x77a866ec, 0x5431eddd, 0xe27cb67b, 0x10561841, 0x4a6c4c1c, 0x75ece604, 0xbeec6b5b, 0x1287053f, 0xd10721a3, + 0xe6f4fd2d, 0x3926c955, 0xa6113b85, 0x2671995f, 0x50f7ad30, 0xe099fa43, 0xf4c064f8, 0xe91bb83c, 0xa1fd1891, + 0xa8ee574a, 0xac3f03ab, 0x82a290f3, 0x3cb8bd9f, 0xa5507930, 0xbcfe9e86, 0x141fe13f, 0x27c1483f, 0x9cf05583, + 0x056e4a8c, 0xfcd880e6, 0x85eebbb2, 0xafa34c41, 0xa403d9fe, 0x54f8fb66, 0xb194e06e, 0x5c14a3cd, 0x0c779b97, + 0xd03c1c16, 0xe743cc3a, 0x0c4138aa, 0xc1e81abe, 0xc150b179, 0xa86dd9fa, 0x066a6325, 0x6faa30fc, 0x1a614b6a, + 0xdb5d1d4f, 0x8de0cd18, 0xedc431cd, 0xd48c77a0, 0x1ef3d876, 0x02ad9a12, 0x339a0eb3, 0x6aee3412, 0x139195ae, + 0x0199b5b1, 0x44437f95, 0x83af76c0, 0x5c7871bd, 0x3904cef8, 0xbbb78648, 0x14c69633, 0x6d25c221, 0xbf6948e0, + 0x2874fa5b, 0x0a5ca787, 0xb51b7bbe, 0x5e46d3a1, 0xc56f1ec7, 0x2eb0b420, 0x5666ac98, 0x5fa2b40e, 0x3f592d6c, + 0x296f090f, 0xfeb25024, 0xd4e60670, 0xa6a15670, 0x8afbd1c7, 0x0534c6f3, 0x585cabaa, 0x392aa215, 0x67c57be5, + 0x1eaa5ae2, 0x82c5edb8, 0x9a2890e6, 0x41e82abf, 0x1bbeb7b5, 0xbed57be4, 0x025307b3, 0x3cd842fa, 0x59271a69, + 0x2d2e2f57, 0x73e48126, 0x0bb0b1af, 0xb8247ce8, 0xc0789323, 0x5d496381, 0x75834a17, 0xd7487dd5, 0xaac2e500, + 0x07d80986, 0x83a1b305, 0xc575104f, 0x5c3903f0, 0x68800888, 0xebe62b08, 0xf26e89a3, 0x72241e8e, 0xe890fb86, + 0x20f9679f, 0x1a8ac7f0, 0xe2bf2cbc, 0x46fba8f6, 0xf3eff211, 0x5678de47, 0x279c304d, 0xe930a264, 0x2ba6e2da, + 0x31eb8a38, 0x99cbd822, 0x568371db, 0x2b666dd1, 0x04c72102, 0x29476fc1, 0x187e22ed, 0x88ebbb69, 0x07a46b3c, + 0x924c1546, 0x428a9b46, 0x9d535c9d, 0xd7ffc30f, 0xc0fbc9b0, 0xc4d52dac, 0xb06cc3e4, 0x1ff176bb, 0x69967f43, + 0x794f17ed, 0x818e4fdf, 0x1112adff, 0x42282a25, 0xfdbc31fb, 0x855f942d, 0xcbf13fc5, 0x8a1a45fa, 0xfc477eea, + 0x224e6c91, 0x82d68617, 0x00b6307f, 0xbf21bcb5, 0x2518f409, 0x68f74567, 0x5d2282b8, 0x8b4dbe02, 0x5bab13c1, + 0x8e8b76cc, 0x6118c617, 0xf7524382, 0x67b3a050, 0x880c6ebc, 0xc8370a6f, 0xb01f821a, 0x02055254, 0xafd1dc7a, + 0xf600e165, 0x7e6548b0, 0xdc8964b8, 0x1be0f7a2, 0x94e51154, 0x7e0c609b, 0x31230869, 0xb31abd85, 0x5ae5fa5c, + 0x5a860249, 0x14d51fe4, 0xa0e56d8d, 0xe211890d, 0x53d54a64, 0x0b357bc4, 0x7d2eb246, 0x4682442a, 0xa70b57f4, + 0x5ba04e51, 0x2bb17a0b, 0xe7acc397, 0x7c7c5833, 0xeeb1b3b1, 0x71df956b, 0x85426fa2, 0xff8e9b99, 0xfb166996, + 0x42cef38b, 0x03704b63, 0xd5a574c4, 0x398f5a6c, 0xe7649861, 0xaf5641d9, 0x6dc2f3f9, 0x21878a3b, 0xf5bf4104, + 0xf50d3b1a, 0xa237463d, 0xb226322c, 0x041e9702, 0x963fc177, 0x85a6878f, 0x0d853ea2, 0x000425ac, 0xe97b0976, + 0x272ee83c, 0x37854faf, 0x68c3b282, 0x6a744e1f, 0x7ab8c8d4, 0xc68481c3, 0xf110a935, 0x8a18edb0, 0xf1bab1d9, + 0x7d15260f, 0xb4f2ec13, 0x6423eadc, 0x0212125d, 0x8baaca07, 0xc9c8e60f, 0x9b953e39, 0xb450a393, 0xb84e41d2, + 0x8bcdde08, 0x87e737e5, 0xfb546b46, 0xf5c3a9b1, 0x3702baa9, 0x3162e6e8, 0xc31d772c, 0x6587f51d, 0x066b94b1, + 0x706b9ee1, 0x7a2d290c, 0x244969ed, 0xf813a693, 0x21b7d6bd, 0x0bb14788, 0xf8a25c69, 0x6387d92b, 0x637da981, + 0xfca915f3, 0x22556758, 0xf670c65e, 0x52add709, 0x0c688ea3, 0x232cdb1c, 0x03a217bc, 0xfa2f9411, 0x8a0c6f6a, + 0x45c2c809, 0x9d587123, 0xbf42ed17, 0x3b4341f9, 0xf063a82d, 0x948f4f87, 0x15dcd038, 0xd20d434f, 0x908360da, + 0xab89d015, 0x6ab2f87f, 0x6644926b, 0xe47282e0, 0x48c95e8d, 0x9805c823, 0x9e763b00, 0x521f8776, 0x2857d2c8, + 0xeeb1534f, 0x94497944, 0x11d389c3, 0x13a5a231, 0x2ee78aad, 0xceddadb9, 0x95c5742f, 0xbce6afad, 0x0d5c47ef, + 0x92b7d070, 0x5b8d6e54, 0x525da938, 0xb2c8ff68, 0xe26a2a66, 0xc2d8ff33, 0x4b4b03b0, 0xb10c7f1c, 0xb7f13d97, + 0x55209b7e, 0xaf8961de, 0x013ece74, 0x12f436b1, 0x9d71c695, 0x49bf0e10, 0xae7d4956, 0xa8c8097b, 0x13fabf92, + 0x557ad9a5, 0x485b4b0b, 0xf4a0f75f, 0xa600b4d4, 0xacd0da9f, 0x192410b9, 0x657ddaea, 0x623c5056, 0xa77a7cf1, + 0x5f63d680, 0x54651207, 0x3de29781, 0x19405df2, 0xeb0a060f, 0xbb9d93eb, 0x425fd4d9, 0x543b6c2a, 0x9b138386, + 0x64b04cfa, 0x7dd7125e, 0xba786685, 0x72e8bfe0, 0x75bed4f7, 0x6b017f18, 0xff9dd1ab, 0x39f92f90, 0x092e03b3, + 0xf28a1e52, 0x81039a37, 0x09a4b306, 0x092b87e3, 0xdd111438, 0xabbe647a, 0x963564be, 0x8412c9f7, 0x44abbff1, + 0x727f58ed, 0x9252a14c, 0xb3519592, 0x10648fb0, 0xf31c18aa, 0xc804b43d, 0xebfb89d2, 0x9438d2a5, 0xbae80e52, + 0x214560ce, 0x4ac5457a, 0x3668f118, 0xb0ceb38b, 0x2da555cb, 0x5bde5995, 0x851213ed, 0x14387ec0, 0xf37ea8ff, + 0xd554de45, 0xb7b7cc68, 0x33f80d7a, 0x96c9346b, 0x255018ec, 0x83b04b14, 0xb0d9f7f7, 0x9de1b4c7, 0x7a5f33fd, + 0xeed4ea4c, 0x981be22c, 0xcb1cf479, 0xc477ec86, 0xe899dd34, 0xc4793de6, 0x83046e92, 0xec0de27c, 0x88ab95bf, + 0x47adfda2, 0xd71d7848, 0x881a343c, 0x8ddc4927, 0x072decc1, 0x2e5baf6f, 0xe3b4d911, 0x5a359c41, 0x16685f8d, + 0x66e973e1, 0x727df88a, 0xc9e84a0c, 0x0f4d079d, 0x41352079, 0x89b77a23, 0xc14c1b1a, 0x2e354a75, 0xf22c5ed6, + 0x84973772, 0x8fa0d16e, 0xc6270378, 0x1c817a71, 0x4c334cb5, 0x97f3914e, 0xaf600d3e, 0xf61b9b99, 0x8c2a82b5, + 0x785e8009, 0xee143c13, 0xd65a0ba8, 0xb77d7cc6, 0xc70f575b, 0x2c2b6f47, 0xb4be4611, 0x145a38a2, 0x4b7e82aa, + 0xc247d610, 0xe883e02a, 0xb37de771, 0xa6f6e5d7, 0xb063ffb0, 0x99798833, 0xb59f4e9a, 0x25d5bd94, 0xd25fb565, + 0xf4eaaf6d, 0x00dbb98b, 0xe581ddf8, 0x44b43cab, 0xd8691bdf, 0xa20eaf07, 0x61e2027f, 0x192c48bf, 0x37de7aaa, + 0x72b684f5, 0xaf3d3cea, 0x8027fb56, 0xab5d5003, 0x20d5ac53, 0xbc6fe5ad, 0x01e88eaf, 0x82941627, 0xb5dcedcf, + 0x16f259de, 0x75a82953, 0x1e9c0823, 0xff5de671, 0x35b51b4e, 0x758699df, 0x2422f83a, 0x5e3d9da3, 0xad498508, + 0xfd66450e, 0x514f8342, 0xeda71018, 0xe14c4329, 0xd220d8c1, 0x1987bc21, 0x8d681b26, 0xf292b8be, 0x7546eae5, + 0xe424fb36, 0x8b963333, 0xadf79814, 0xbd080161, 0x2dfc279b, 0x51e50ff0, 0xeaade9b3, 0xea69f576, 0x5a30d557, + 0x5b51486d, 0x2b2993ba, 0x2819ef8a, 0x27ee8a29, 0x00f3a574, 0x40206102, 0x087d9a79, 0x26d90a3e, 0xde9b2b8a, + 0x9c645eb3, 0xf0a726e8, 0xadd769f2, 0x5ce902fd, 0x0cd6c44b, 0xc3911dc6, 0xe16c0ddb, 0x543d5128, 0x64224e94, + 0x39916207, 0x628a2d60, 0x02bc6fe9, 0xfefbfb40, 0xf0f66056, 0x4d6b56a1, 0xac90239b, 0x8ce2ee4d, 0x192874dd, + 0x509735fa, 0x0a6ec519, 0x281354e7, 0x17c41b41, 0x1c2cb5ae, 0xaec5c17f, 0x750e3d36, 0x06b1709c, 0xa9b76422, + 0xeb22f88e, 0xecc2a343, 0x789a7515, 0x5021b043, 0x9461cede, 0x663ffb14, 0xc31a7df1, 0x5050467e, 0x1ebc00a5, + 0xc06c2ef4, 0xf058e9f6, 0xdca2509f, 0xe8e37c73, 0x14f2ad18, 0x796c8885, 0xd9334609, 0x4195b278, 0x9ecd33c9, + 0x45bea1be, 0xa3466cc0, 0x8f63dde1, 0xf01e570d, 0xdf457d42, 0x146bd1c9, 0x5c421340, 0x426a73c9, 0x13acb5c0, + 0x2235d5b6, 0x73a406e2, 0x4005ee66, 0xc80ac802, 0xd89f34ff, 0xb1e28bb1, 0x438d80a9, 0x771aaa26, 0x081db90f, + 0x8cc7a0cc, 0x44e6c4c9, 0x170237f1, 0x3bdec52b, 0xd423aae3, 0x88e18231, 0xa8e759df, 0x2315d71f, 0x628f7889, + 0xb6bfa0e1, 0xbed1e2ad, 0x23e9cdb0, 0x9e5dd657, 0x253677d2, 0x1d83f301, 0x8761c9d0, 0x1c04be37, 0x6d5baebc, + 0x0f9e0628, 0x8d7371da, 0x2a3fe9a3, 0xbd4fc583, 0x9205fbb4, 0x78c7e453, 0xbb826801, 0xfc5c928c, 0x8e036c5d, + 0x8d7f98fd, 0x9d32c720, 0xee540e56, 0x7c2b348b, 0x35579497, 0x1bc4108a, 0x8c9cfa54, 0x6050e6f8, 0xeff8575b, + 0x873f0953, 0x5103b8a8, 0xff4bc0e7, 0x3496f645, 0xcd7f7426, 0xa4593ad7, 0xd13afc75, 0x9adce205, 0x57340e8f, + 0xc151a791, 0x1d7e925b, 0xdae562fc, 0x372d6c7a, 0x284d34b3, 0x260023aa, 0x876f002e, 0x6291a6ad, 0x67c9c68e, + 0x0777cee1, 0xc46278cb, 0xd6a022b0, 0xb9dea931, 0x2af009c4, 0x1c8a704c, 0x3a4919d8, 0x1eaf4f2c, 0x4a30fc69, + 0x95df6385, 0x4641afab, 0xe1ba2628, 0xf6c16baa, 0x62ac782c, 0xbb910322, 0xb4b9fc46, 0x36dd6069, 0xf4ada382, + 0x3376448c, 0x2578340f, 0xfce8f1d8, 0xd5c6fc9b, 0x34be71ef, 0x5dded5c1, 0x2170e839, 0x32d39204, 0x4c934166, + 0x1c68025f, 0xdf20cdb8, 0x5a2bc4b5, 0x48b15e9f, 0x4007222c, 0x2c74b917, 0xf497c144, 0x9e8ce41d, 0x3a9a9db3, + 0xf1e84072, 0x4cc1c15c, 0x03c9c663, 0x846a84e4, 0x99037377, 0x7451e521, 0xe02f411c, 0x217f4996, 0x2ec10eb7, + 0xbb627930, 0x1728e649, 0x91174a65, 0x2fdb0116, 0xa8311bb1, 0x04aaa191, 0x55adbfa0, 0x5615bc8f, 0xc65f1366, + 0xccf661a2, 0x3503fbb0, 0x41de8b8d, 0x0d115d64, 0xa7123be4, 0x4113ead9, 0xbea65d09, 0xb41f5c21, 0xce55c2db, + 0x2dcedc64, 0x37aeb0ac, 0x7735fd44, 0x16704133, 0xa4382e8f, 0x46f1171a, 0x6a730c70, 0xf0bd7218, 0xc33d2a1a, + 0x02b219a6, 0x9b399923, 0xc72c457e, 0xbd369e30, 0x5c0354b7, 0x21969b9e, 0x8ef42afe, 0x53cd4f8b, 0x0134b1b5, + 0x8a79e8c2, 0x4e1c5798, 0x754a658e, 0xb91abb36, 0x3fab1804, 0xb5144329, 0x5f07051a, 0x11d5f654, 0x48d2edce, + 0x45738f28, 0x931086f8, 0x9f5434f2, 0xa0fb4369, 0xdc116cba, 0xb18a62c5, 0xa190e9da, 0x429e806e, 0xd0e8d24e, + 0x3c78d966, 0xf8e015b8, 0xd7cfab21, 0xb5518e4c, 0xc0461d54, 0x3a2e9d41, 0x4b3500bd, 0x03c483ad, 0xc99ec589, + 0x2b1f6340, 0xb367607f, 0xc2f08b0b, 0xe8663945, 0x69fee589, 0x0c5895d8, 0xc5046670, 0x9596796e, 0x8434c009, + 0x02453a64, 0xa3604c43, 0x9a4d5c5e, 0x2a6fb6c6, 0xd082b464, 0x7897593e, 0xaa221953, 0xe65e932a, 0x1ae9d01f, + 0x3190e86c, 0xa984ecb4, 0xabb00c54, 0x441950cf, 0x3d670005, 0x0e4c9f92, 0x0444239f, 0xb51cdef4, 0x12e84184, + 0x20894a77, 0x60f8615f, 0xcecc7e3a, 0x9488a801, 0xdf8283dc, 0x96468dd1, 0xb50bb953, 0x047ab93e, 0x8f7b055a, + 0xce50e017, 0x2e429160, 0x70fd2242, 0x4739a4bd, 0x4118a862, 0x6e9bc46d, 0x3f5b6b94, 0xcc5a677c, 0x3573500c, + 0x28a5b868, 0xbbf9797f, 0x18d763a8, 0x19ff7902, 0x89ebb103, 0x6706683e, 0xaadb1f6c, 0x6c140aa6, 0xcbdc5229, + 0x245f9e9d, 0x46b4756f, 0x7095f736, 0xf873d90d, 0x69b6b5f6, 0x69402a70, 0x1516c633, 0xa4980b58, 0x7b5818ac, + 0x8a9a6551, 0xd4e9c2cc, 0x22342691, 0x3b147af0, 0xc1f08e90, 0xb0a69bf2, 0xbc6b8f85, 0x1bae1e96, 0x1eee6549, + 0x8699f6f8, 0xe6464afa, 0x62ea3bed, 0xd4272faf, 0x5588c1f2, 0x6edc92ea, 0x8daea484, 0xec45c00d, 0x4eb6eff5, + 0x7921d48c, 0x88f93dab, 0x42080ce7, 0xcfff9423, 0x53256092, 0x27b047f5, 0xf2ba3bb1, 0xf74cc57d, 0x0c04ed34, + 0xc66d90bc, 0x0e5ba0e7, 0xc799da66, 0x1dd39243, 0x64e280ae, 0x53cac9d1, 0x3c286d01, 0xaf3f7241, 0x75127eb7, + 0x1dfb36b7, 0x92fbc306, 0x7aef76b1, 0x4d9cd038, 0x03935a56, 0xc5c9b7cd, 0xe209bb73, 0xb08baa11, 0x85e292a8, + 0x6406ddaa, 0xd36ae720, 0xa7feaa29, 0x616332b4, 0x2b466f76, 0x218dcf9b, 0xe8b81f0f, 0x041c4c88, 0x37106d8a, + 0x1d612011, 0x2212f9fb, 0x862f17b5, 0xf5520188, 0x7385f253, 0x663259dd, 0x592ef854, 0x26899dde, 0xc7aab8b6, + 0xb291f9a8, 0xe5ddacf8, 0xfe883cdc, 0x3ee0252a, 0xa2007545, 0x73c65d7a, 0x231617fc, 0xd5f49c39, 0x9beb9681, + 0xf856ddba, 0xe3cff8df, 0x69a86528, 0x20f2eca7, 0xbf73f736, 0xcdf737a3, 0xf38d8660, 0x0e2389c7, 0xcbd892c8, + 0xc879c13f, 0xdc917089, 0xebb1c64a, 0x09abab28, 0x38eaa825, 0xe27b88b9, 0xc3f5d2a4, 0x25fa6060, 0x155a8649, + 0x939fd8e6, 0x2a88a85d, 0xb38ceb46, 0xdcacc267, 0x7666c123, 0x83ac0d46, 0xfacfb582, 0x5a03625d, 0x6d630c39, + 0xea588079, 0xa49e87c7, 0x0f662edf, 0x29db9af6, 0x8fbaf969, 0xccd24921, 0x3117eb25, 0xf04af7cf, 0x8041d9b4, + 0x0c0632e9, 0x7242ee50, 0x52235711, 0xe81037cf, 0xebc54e71, 0xbda8938b, 0x4e8e824e, 0x54e3962c, 0x343d2c3e, + 0xc33181c2, 0x87a40870, 0x8d4d4f68, 0xe4f0a372, 0x4b953b26, 0x9e562d54, 0x81accd42, 0x9acd1a77, 0x4894b7dc, + 0x46e9b611, 0xf337ea58, 0xbf343c13, 0x18442362, 0xe3cbf9dd, 0x52530e1e, 0x4ec1867d, 0x81c2ab99, 0x749236db, + 0x9d8e548f, 0x24c4174c, 0x59e06254, 0xdee52107, 0xeebe8505, 0xecd22bf4, 0xd2c50447, 0xcd013436, 0x8925b7b9, + 0x2a82f464, 0x036610bd, 0x9486a677, 0xc6d1f22a, 0x5247d43b, 0x4d5148f4, 0x7a9da584, 0x2b41b346, 0x12107021, + 0x41153d00, 0xb7384eda, 0x79d8a770, 0x49e12243, 0xa0756be0, 0x768ad451, 0x9ef486a0, 0x7020f27b, 0x3c8939ad, + 0xa3a59150, 0x44ff05eb, 0x30c262a8, 0xdec52b94, 0x89485c6f, 0xe31372f4, 0x92afe685, 0x66efa466, 0xc9c93043, + 0xc8549d41, 0x88c73d8c, 0x9adfb37e, 0xeee3d6ca, 0x878b9d30, 0x17ab26c3, 0xbebdcecd, 0xd76d898c, 0xc97eda94, + 0x6e9ba25a, 0x7910ec24, 0xf4e37446, 0x057963b0, 0x03507336, 0x92d5c72b, 0x6b0d815a, 0xbfd407f9, 0xfc072355, + 0xb7336879, 0x85827b9c, 0x1d9b77e1, 0x8d3360dd, 0x9ae92b64, 0x06c71f64, 0xa7a0b45f, 0x0fa6b0b9, 0xb544ea9d, + 0xec4dbb1b, 0x5d51cd01, 0x7af95bb3, 0x112dc08d, 0x406aec8e, 0x08155d41, 0x24ae9fe8, 0xb205e5f1, 0x1a4b2481, + 0xeefcf8ea, 0x2d7e70d2, 0xfc4f518b, 0x518e8283, 0xd130737c, 0x7643138e, 0x5e9bfc12, 0xa447341a, 0x091edcc8, + 0x158535e6, 0xf3035403, 0xa0ad91ac, 0x1f18e376, 0xc179d6e4, 0x7fefc961, 0xa045c707, 0x074ae965, 0x0534eba7, + 0xf4ce4fe7, 0x2ab5de0d, 0xd74e5787, 0x1aea9727, 0xf43b6725, 0x9d623bb0, 0xe1b26112, 0xc5b39631, 0xb2b6f2cb, + 0xc2aa6b23, 0x491ca6e1, 0x006a13b9, 0x76e17443, 0xa9599090, 0x545604ad, 0x2243d7a1, 0xe101e677, 0x2f549f50, + 0x1543a100, 0x042927f7, 0x92a34e9b, 0x43e293af, 0x5d5ef792, 0xa7d6a85e, 0x05fb8d7d, 0xd58e2b8c, 0x593f0ec6, + 0xe346f50e, 0xc75435ed, 0x06665580, 0x9c169043, 0xbd6b2a5d, 0x05c1907d, 0xbe66e760, 0x1a58ad82, 0x327f91b7, + 0xba5790d0, 0x7de82db3, 0xddc5d4a6, 0xdabd442a, 0xf226bd6e, 0xe3ff10b2, 0x96f10c4d, 0x3c26c974, 0x313dfaab, + 0xdffff242, 0x1cdf900d, 0x2ca43519, 0x02e3ee15, 0x15e6659f, 0xd4bdc32f, 0x5f4608ad, 0x583a70fe, 0x9277967a, + 0xde4d6b09, 0xd8daa73b, 0xb4c2d093, 0xce92eba5, 0xb5ec95b3, 0xe5542fed, 0xc50ce902, 0x1f8aca0e, 0x356163fb, + 0x4aab1b6c, 0xdd88c088, 0x1ffb26dd, 0x7a6af7b7, 0xaf2612b9, 0x0182fc32, 0xda535578, 0x9d649e0e, 0xe37a3374, + 0x4dfd3e8f, 0xcd5110d5, 0xd5cf1ed1, 0x7ee971b0, 0xfb5eca44, 0x6737deea, 0x0f931060, 0x9448a184, 0x74f88929, + 0xd34927ec, 0xbe48849d, 0xc4ebab36, 0x4e6a86ac, 0xc55adcf4, 0x49d40675, 0xdf352c3d, 0xc9421cb3, 0xec7fc3d6, + 0x67f6e025, 0xba857fc1, 0x392ed5b8, 0x80d44fc5, 0xffc15575, 0x1895cb75, 0x9bd300e8, 0xc291ffa3, 0x404e522e, + 0x4bad5df1, 0xb7d61676, 0x3a37db13, 0x1244f5e1, 0xc99e5fc1, 0x06c11aee, 0x684bc533, 0xe899ae14, 0x491b9d19, + 0xb8fa73f4, 0x6c5f5784, 0x2026f735, 0xc40aad3d, 0xf212cecf, 0xdfa39b17, 0xd3f7fbc9, 0xcb192eee, 0xe1be2274, + 0xf2236f77, 0x4187891d, 0x0adcfff3, 0x52b9ee5f, 0x83a688d5, 0xe07500c3, 0x14c987c3, 0xd8bbd698, 0x4dbfced3, + 0x35e7ed4e, 0x9547b294, 0x0af49fc6, 0xb8e42ff3, 0x701cd3f9, 0xfba74cf5, 0xbe0bf6c0, 0xce8bc097, 0x27bcab81, + 0x21d9f780, 0xa2a8613d, 0x9f43f9b6, 0xd5acfc4f, 0x1f0f9d07, 0xb08258df, 0xaab8aea0, 0xf3441ab6, 0x288e19dc, + 0x6bd8d90c, 0x71231fec, 0x93efc5c0, 0x08622dec, 0x8e9ecff3, 0x1e6623ce, 0x559012bd, 0x082f57ca, 0x18ec9dc2, + 0x72ec7b60, 0x13c820f2, 0xb45ff102, 0x913ecc00, 0x6939920c, 0x3a9c2ff0, 0xfd86fddc, 0x894375da, 0xb2058dbc, + 0x215a9678, 0x21223b83, 0xc62d6da5, 0xc26574d0, 0xf1bc2415, 0x01335e22, 0x49276199, 0x155b5456, 0xade251af, + 0xa3642edb, 0xb5f91c7d, 0x50d6e872, 0x2be5fae5, 0x0e16bcc6, 0xcc3d33a0, 0x1a5b630d, 0x98d9b446, 0xbcbe3025, + 0x9edfeb75, 0xcf6ed148, 0x2c6e2378, 0x14870ae6, 0x35e69437, 0x345331c0, 0xcc13ef94, 0x8c0f2bf6, 0x5c3c3090, + 0xd4420139, 0x5f782bd5, 0x024539c0, 0x8c24e19a, 0xeb4137f2, 0xe4d5da69, 0xa2de0fd8, 0x3d0a8e92, 0xdf53adee, + 0x1f5b8582, 0x88dd58c8, 0x9ef101ac, 0xb5b7fcce, 0xd3e881db, 0x19a1c43c, 0x2a5605d6, 0xcb172650, 0x27f99d38, + 0x90f4124d, 0xc1563da7, 0x9d9970ba, 0x1f8cd527, 0x7c810244, 0xe80df641, 0x3f87ecfc, 0xbfffff02, 0xbc5ce29d, + 0x070273c2, 0x83f89f71, 0x528ada46, 0x9ba483c5, 0xa22969a8, 0x3c055adc, 0x377e23be, 0x3f3a8e63, 0x82c13a8f, + 0xbbebf0b8, 0x62756530, 0x54bca91d, 0xbba727e2, 0xdb8ca2b6, 0x90d28c11, 0xaecaddf7, 0x1ba2ec43, 0xf1d91d18, + 0x2c32212c, 0x86e0d281, 0xfc8c35a0, 0x096f411a, 0xc2440329, 0xf2b4db3a, 0xf114db36, 0xc61f379c, 0xf89bb31e, + 0xb2b0c8db, 0x024eb604, 0x15b37022, 0x6aabe156, 0x05f9a067, 0xaf03b984, 0xa20ee390, 0x5051ae6a, 0x6eb67443, + 0xe57e37dd, 0x3970c6b4, 0xcaf68c52, 0x0996f788, 0x75e27b5a, 0xa4db655f, 0x79d62b54, 0xe16a2f75, 0xdc7bef96, + 0x11fd38e8, 0x25a97777, 0xcf3f8414, 0xf125d99e, 0x2a5c9130, 0x74da1aca, 0x2b3f7d8d, 0x375b1b65, 0x57a79cf2, + 0xdb707c1f, 0xb17846f5, 0x496dcb52, 0xc58fc3fa, 0x3b71e80b, 0x68be76f5, 0xa116aa48, 0x2afe3c45, 0x89d98510, + 0x47234eb6, 0xf424ebc6, 0x6b85cfa6, 0x60db1663, 0x9785761d, 0x20026abd, 0x4cdcd31c, 0xc6b9c5a2, 0x56117469, + 0xa120deea, 0xa5e7bdf9, 0x6fb45ed8, 0x9dea52af, 0x6a4d7e5c, 0xf1fe994a, 0x7e2ad52a, 0x477c781c, 0x3c67dc82, + 0x0a9e1bd8, 0xfcc142b9, 0x3408ab2e, 0x81970ebd, 0x6280a8db, 0x10b611c9, 0x66f2deac, 0x7148f395, 0x3a08126b, + 0x2f45feda, 0xe7f692d8, 0xff705521, 0x1ead41a0, 0x79daaa77, 0xe22b6e76, 0x1f8387fc, 0x5a688abc, 0x118584ad, + 0xac76ff44, 0x64067f4b, 0xb774ed6c, 0x591fddfd, 0xe6dbc1d4, 0xe96ce0fb, 0x4173e43d, 0xe8dfceee, 0x6b5c0b26, + 0x2576da14, 0x7036fd8f, 0xcb455a84, 0x544797ee, 0xb8b285e6, 0xe18d9a81, 0x2680cf95, 0x902b006d, 0xfd1c5598, + 0x0c6dc457, 0x2b7fec3d, 0x203eb0f6, 0xc497defd, 0xb1cf1f8e, 0xb187074b, 0xc7b31691, 0x9ae524eb, 0x2d697cbf, + 0x0d5244e8, 0x2db9c905, 0x0f726fe7, 0x38a9e99f, 0x77fd0e78, 0x013af32d, 0x654b5e68, 0xd11c1819, 0xe338ac17, + 0xfb84cf42, 0xdfd77594, 0x2421418a, 0x38c1c3a0, 0x675135e1, 0x83f1b1f0, 0x9708dca6, 0xdfa9816a, 0xa7b2bfdf, + 0x67c3a3cf, 0x13b19b4d, 0x380bdb26, 0xc1da7952, 0x3a8efcb9, 0x11260f8e, 0x8b9cb106, 0x435dddbd, 0x8d32c041, + 0xaf1e7f42, 0x1eca4bca, 0xbb16cb44, 0xe4f3b91e, 0xa4e38bbb, 0x3fe65aa1, 0x4fe43550, 0x767171b5, 0x034d7455, + 0x21688e3a, 0x4c6f0afd, 0x298d2edd, 0x5c70d296, 0xecad841f, 0x4d72bc69, 0x8f075af2, 0x78d33ced, 0x81998926, + 0x594d3985, 0x4b07a044, 0x79365c8a, 0x4ee5f1b5, 0x431e0c05, 0x7730ed4d, 0xf6044a2a, 0xa660b288, 0x0c18b8ad, + 0x72a65ac0, 0xdc8571b5, 0x63ce27bd, 0x6792f964, 0x50c634dd, 0x1ca6a813, 0x470147a0, 0x3b13825b, 0xe9539ac1, + 0x2278ce88, 0x714d5fdb, 0xab163ceb, 0x18ef078f, 0xefe72057, 0x7b970cba, 0xeeff656e, 0xd033399a, 0x6201d330, + 0x5991b8f2, 0x9f3c740f, 0x825f87bd, 0xaf7016ef, 0x0dfee631, 0x8232ae38, 0x6945abb4, 0x90d49e32, 0x547c8571, + 0x36ad2d70, 0xbfd24f0f, 0x56680836, 0x7dac430e, 0xc43d1680, 0xf1a78ee6, 0x349cc644, 0x890baa1f, 0xad4338ea, + 0x82e2245d, 0x35bb2405, 0xeca8907d, 0xbb5a0a07, 0x72f074a2, 0x80d4b5d5, 0x064d8a31, 0xc3a8fe6a, 0x55f97823, + 0xce41ac34, 0xc326c614, 0x2fa0b3f2, 0x797043bb, 0xa25aa7d5, 0x77e1893c, 0xe8fe225d, 0xf178773c, 0x656bb46d, + 0x388a4729, 0xcf70451f, 0x70f13ff1, 0x00104315, 0xe068fbe8, 0x44f8412a, 0x303aa8d2, 0x4a5c186b, 0x15f1e665, + 0xf9659ff1, 0x5bd55014, 0x944fa537, 0x123c9ddc, 0x8856dcec, 0x2f73420d, 0x734ee343, 0x5bb8bcca, 0x26f71af6, + 0x5bc58fef, 0xf125f3aa, 0xb6945318, 0x56dd1345, 0xa77782d0, 0xfdbe05c1, 0xe88208ee, 0xfc057241, 0xa126c94a, + 0x0a4dc2f5, 0xb8760207, 0xa6e6423b, 0x7f2c58b0, 0x094c465b, 0x2c292ba6, 0x76a5772a, 0x47924ce3, 0x36d7c37c, + 0x0f818d50, 0x6ee6a274, 0x1588242e, 0xac65bd22, 0x40e0eb6c, 0x2488e86c, 0x06060662, 0x5a76c354, 0x8584a2bf, + 0x584bb58d, 0x825e7070, 0x9f529e50, 0x1fff8666, 0x56f54ff4, 0x9c4c0705, 0x64529159, 0x9ba611ee, 0x40f402d6, + 0xac57aeca, 0x1ea5c32f, 0xedd275ac, 0x3093c156, 0x1962308f, 0x20c30f54, 0x6163dc02, 0x08d1e320, 0x4431779c, + 0x175b58b0, 0xfabf6baf, 0x1b28c866, 0x81f50536, 0x838883a2, 0x5102f745, 0x2f12f3a5, 0x44415cec, 0x8523f837, + 0x660c8e6e, 0xc7e3ecf7, 0x40d0524d, 0x0be2621d, 0xb998a69d, 0x6fe5b6a5, 0x228ec484, 0x6b780d78, 0xf4a45abe, + 0x71810e66, 0x1ee281f3, 0xe9b60c98, 0xc604d829, 0x9569fcd0, 0x0488d1fc, 0xc51cb2a7, 0x3993b477, 0xfa85d874, + 0xcbeed44b, 0x7d237a03, 0xc607c9c3, 0x95eae329, 0xbbdc6c3e, 0x5a1705ec, 0xe6197b5c, 0xfdefe50a, 0x4a5b4f25, + 0x39deff22, 0xe2cbf433, 0xe14145bc, 0x6810e1cd, 0xb0d3927b, 0x36ea88bd, 0x7acd24f0, 0xe09b97a0, 0x9e2be7a3, + 0x48bf50a7, 0xc9d357d1, 0x4d11d50d, 0x2ff507d4, 0x90705d55, 0xf3952091, 0xc2d68489, 0x84f2bd19, 0x2abd8785, + 0x226d5309, 0xf3798a8b, 0x0c172e1e, 0xd93f413c, 0x4730013c, 0x6ca9b442, 0x8abc2fe7, 0xe65d39e1, 0xd1288a7f, + 0xe36b6706, 0x83f68dc8, 0x1b8b24a2, 0xe012e23b, 0xcb53f831, 0x7f7f783d, 0x54aab011, 0xd44e3bb1, 0xe34933ef, + 0xc01a3306, 0x55c8cd87, 0x2ad31d0c, 0xec2f9e1d, 0x47dec831, 0xba69ae2c, 0x02116987, 0x72e3eba9, 0x807b03be, + 0xfaed4289, 0x03744f72, 0x7d57336b, 0x4c482831, 0xf556e3c1, 0x3b9eef2f, 0x9801e9b8, 0x9d57eaa0, 0xfb27abb2, + 0x2ee1e0e1, 0x84b9b319, 0xcd16d179, 0x635e24bd, 0x86c5f32f, 0xd4e4b582, 0xe1ce54df, 0x1e7c0a87, 0x0d806dab, + 0x40932bf1, 0x2143001d, 0x9a840216, 0x4b600e74, 0xdbc7620a, 0x63b3a474, 0xc43c2f2a, 0x6ae3f14b, 0xa2b90902, + 0xa83155e9, 0xd3e3b9ab, 0x9138819f, 0x2cde2327, 0x8bad6187, 0x39526c98, 0xd0da68a1, 0xf74de8ed, 0xa1b4c0d3, + 0x70608917, 0xe039e70e, 0xe43c0640, 0x3a48350e, 0xb12bc70f, 0xe954ce8a, 0x78187120, 0x422181c4, 0x69fee14c, + 0xb6ece8d7, 0xf0c45b7d, 0x57e98df3, 0x907ed7cb, 0x7a869c2b, 0xfc0a436c, 0x6a964581, 0x11b22c53, 0x9760e829, + 0xfb943737, 0x9011be2d, 0x0527cb26, 0xa68d1ed1, 0xb696daa4, 0xa5b1d531, 0x6d282e1d, 0x7e8de4ae, 0xcb8ae328, + 0x022f526a, 0xc9ef14f0, 0x4bbc0961, 0x9b26bff3, 0x1dd3141f, 0x73e4727a, 0xa3fba969, 0x9b1eaa84, 0x4439cfbb, + 0x3f7edf0d, 0x9643f3c7, 0xcf4ca543, 0xcfab1b08, 0xd875f077, 0x34bb0b28, 0xc2c33e06, 0xba4c5812, 0x7d4e96fe, + 0x1f907180, 0x915bc56b, 0x151c8c77, 0x49ac3e75, 0xa7ea9583, 0xcf1e7de9, 0x3df4ae10, 0x14e9a7c2, 0x31490549, + 0xfcb42971, 0xbf78c089, 0x23b12b14, 0x5520cb54, 0x8075c9e5, 0xf6ced19c, 0x79be94e1, 0x3a3e4b23, 0x8775d406, + 0x39b201a4, 0x3e848e46, 0x0f568363, 0x9337d293, 0x40de64df, 0x1aedfbb7, 0xd01075f1, 0x5681b7a1, 0x05626d6d, + 0x44959150, 0x86265dd8, 0xa41595fd, 0x78e83209, 0x96ae3de6, 0x7eccee7f, 0xe0d9036b, 0x88fe1676, 0x5ac8c64f, + 0xc8c256c7, 0x7afede78, 0x91cfb1ce, 0x9c491db4, 0x08dc005a, 0x4229a183, 0xdf9f2931, 0x819cc192, 0x9b4b1f94, + 0xc74379e6, 0x0ea92242, 0x2f57ef30, 0xe550b2c6, 0x9b2d6efc, 0x224337f1, 0x411e56ee, 0xfc12c1ca, 0x24db72d2, + 0x3745dcc6, 0xc8b89f93, 0x626b8931, 0x745e5b4d, 0x390b9a8f, 0xe2e597a1, 0xf62d9731, 0x45f3f57c, 0x3d34b223, + 0xc22c60e8, 0xc01256f8, 0x8a94cab9, 0x20e143b2, 0x711f1ef5, 0xf52ee145, 0xf92d3564, 0xa06c1893, 0xf976ae8c, + 0xe14db1df, 0x3c18d0db, 0xeeb943fd, 0x21836687, 0xd0bf4e80, 0x7f944304, 0x8fa16aca, 0x7cd52d17, 0xd26ff7e4, + 0xbdb41f16, 0xb5e9d5e1, 0x4cc122ac, 0xa8494644, 0x840254ee, 0xd4f26c7b, 0x78f49c9d, 0x68b34a49, 0x01511563, + 0x723cef5b, 0xff3f3634, 0x7871a635, 0xc43a8563, 0x31b49478, 0x045fc340, 0x15ace06b, 0x958c928d, 0x11d2b456, + 0x9745d531, 0x1864468c, 0xcf81d4e0, 0xf09cb666, 0xf57b3317, 0x8fe6f477, 0x96169884, 0xa3a3c3f1, 0x0e76c81f, + 0xff20048c, 0x2748cc1f, 0x2d0f343c, 0x6e3409bf, 0x4f8c153d, 0xa052616d, 0x4f14bc09, 0x1451947d, 0x98a7ede7, + 0xbfe8811f, 0x001d6ac1, 0x340f7b2c, 0xc5f89128, 0xb7bf9a8b, 0x830b6443, 0x07807324, 0xb94d7cd5, 0xa9dc686f, + 0x95a359b3, 0x63ba33e7, 0x95afff1e, 0xbb5450d3, 0xbe934730, 0x99771438, 0x3fba1204, 0x2260a453, 0x1ea9ffde, + 0x435a4092, 0xddf61ce8, 0xb89c17a6, 0x586d3161, 0xd1c38667, 0x49637a4f, 0xb288c9f9, 0x3391019b, 0x1c752c3f, + 0xe4691787, 0x3492d67e, 0x50b782a8, 0xff8dbe31, 0xa68eaaf8, 0x479c816e, 0xe2e93ed1, 0x368e0fe2, 0xe54b0cc0, + 0x6800987e, 0x9184ab7e, 0x48ec5a6e, 0xef92a29a, 0x5e8fd097, 0x3eca6f2f, 0xca67c5c5, 0xa5ef822b, 0x94596739, + 0x2883ec4c, 0x7e965dc2, 0xe412f4ba, 0x10b5409e, 0x13a9e5cc, 0x81eadffc, 0xbe18bfda, 0x2ac5f6af, 0x828b70a3, + 0x12a851dd, 0x4ff598b8, 0xbeafbeee, 0x2ff2a769, 0xef609d4f, 0x15ef13f1, 0x1e0f5f38, 0xb8e43f9e, 0x7f4fa314, + 0x4e309bd9, 0x2dd964d3, 0x496c32a8, 0xd217ca89, 0x531a8ca4, 0x9f06c0ef, 0x279938d8, 0x376a104d, 0x8692b5f2, + 0x94df4c12, 0x7b271a8b, 0xbdd0e646, 0x39dc187a, 0xbc27ad61, 0xc348b705, 0xe82856dc, 0xbea71352, 0xa749eb25, + 0x06ab931b, 0x88d282b2, 0x6fa16e90, 0xce465d0b, 0xfad79f99, 0x62156e83, 0x80f73267, 0xb02a29e2, 0xb6636a18, + 0x1d2eaede, 0xf61605ec, 0x13adb17e, 0x8443e224, 0x8ace819b, 0x5a9ad530, 0x852a01fe, 0x12437c33, 0x0c27061a, + 0x2a9e4dae, 0xaf867929, 0xad8819a3, 0x3ee41c11, 0xddf7e926, 0x3b77f99c, 0xd27c0612, 0xb818a9f5, 0xa33b36fa, + 0x0ab1b6d5, 0x25d63023, 0xff704354, 0x0363ccae, 0xd604601e, 0x75c9fa49, 0x634b3eb7, 0xdef75f49, 0x971d2b35, + 0x90b05b08, 0xe4237b4c, 0x480c4165, 0x8b305ec8, 0xaa04754b, 0xb9e1b734, 0x3565fbdb, 0xdb6ac9d9, 0x19a8843b, + 0xcfaaa247, 0xe9862170, 0x14181a12, 0xf69cec41, 0xf932d5ca, 0x986101b3, 0xbde59023, 0xf039c80b, 0xd645f58a, + 0x0075ad61, 0xd3a4f14d, 0xffacb6af, 0x5b6778b3, 0xd540edee, 0x24332f7d, 0x739fbcd5, 0x054e8c3d, 0x75e038e2, + 0x9da8b187, 0x2227b36c, 0xd19b8059, 0xf418f49d, 0xbf5bed6b, 0xe1e22bb8, 0x64a35a34, 0x4658675a, 0x48a8a568, + 0x14c4dc13, 0x91c0f8f9, 0x6914fea9, 0xec63f82a, 0x26bfbb0f, 0x22c7fa69, 0xdefd6bbe, 0xbe54a70b, 0xb972e606, + 0x8d9705cd, 0x05e9fc2a, 0x51ab4aa1, 0xeab74bb4, 0x94afe6bc, 0x650d86b1, 0x745ad1af, 0xb0fc1933, 0xed3c9bd7, + 0x35bd6f1f, 0x929bd94a, 0xbc07d4e5, 0xe12520d1, 0x33045409, 0x37a88d9c, 0x06b54c9f, 0x663972f2, 0x7596526a, + 0x9cb63bf0, 0x541c7d3b, 0x12a2b8ca, 0x845724a0, 0xe3821803, 0xbc3b049e, 0xcafca9aa, 0x3dd7b9a7, 0x1f181790, + 0x5dc328a8, 0xbdcd8dca, 0xf081161d, 0xc10a5597, 0xf9f305f5, 0x3e976990, 0x8a0e911c, 0xe97d7d6b, 0x00686e35, + 0xae789834, 0xa61321ca, 0xd2481ae7, 0xc0f89231, 0x143f274d, 0x779a8371, 0xe5a848c6, 0xa4cfbf8e, 0x5bb391b5, + 0x4cba8bdc, 0x0c61926e, 0x7b15b578, 0x0efda551, 0x3fce8965, 0xbee3c9aa, 0x3686189d, 0x594aa4ce, 0xbcbf61e1, + 0x37426694, 0xb18ab961, 0xe5354294, 0xfabcf5e9, 0x48377af0, 0xc42e440e, 0xc1529f05, 0x8662cdbc, 0xace168dd, + 0xe9bbdfcc, 0x2c697421, 0x1d8a8e11, 0x9ce42763, 0xca133a0a, 0xa97b828e, 0x207baf10, 0x57113ab8, 0x1db74eaf, + 0x581cb23a, 0x8e654e9b, 0x970040b8, 0xde81285c, 0x82f040ca, 0x2555b087, 0x5de658b7, 0xad826a3b, 0x6e66f2b0, + 0x110ea170, 0x270f6270, 0xa6e71dc1, 0xf2756d05, 0x3adf73c8, 0xafaf321b, 0x940eab9b, 0xe5ac225d, 0xe480300e, + 0x20679a46, 0x2136153d, 0xcf1b9b2d, 0x7cf6d04c, 0x03496a26, 0x65f899fd, 0x1484801f, 0x124acb06, 0xf01198df, + 0x7dd3b53c, 0x8bc135c5, 0x8601637f, 0x6b5f80f0, 0x3d8ff333, 0xecbfc08a, 0xe6016fbc, 0x07d13176, 0xa85d4ec6, + 0x88e71d69, 0x2228624e, 0x054927c3, 0xd442b4e2, 0xb5a5d1cc, 0x5cf1ebf3, 0xdb266389, 0x433e59fe, 0xe0dade0b, + 0x3ee529b9, 0x46469e02, 0x08716697, 0xb83f43e2, 0xc3aabb4c, 0x7bdfca6b, 0xcf518b7e, 0xe0d8f3b6, 0x9ab96290, + 0x090e92dc, 0xf63cb719, 0x8b070608, 0xe4c7cd32, 0x562a14d2, 0xa4d40689, 0x4a41cdfc, 0x0bd59745, 0xb76650f3, + 0x1377227e, 0x2c96fcea, 0xe438277c, 0x11808e7f, 0xc29d75e6, 0xf7733e83, 0x6bd1e8e6, 0x32fcd994, 0xe899c9cb, + 0x907424d1, 0x0efd7f9f, 0x187be44e, 0x9ed0887d, 0x1be50c68, 0xabbe9d3d, 0x1a4b0409, 0xe7be7061, 0xe87fa71c, + 0x3a4281eb, 0x5d8d4a48, 0x2522456e, 0xd76ad03c, 0xf0ea2ebd, 0x7eb17c18, 0x37ed774a, 0x64857f15, 0x584e02d6, + 0x947c7a94, 0x787d0854, 0xfc12f505, 0xb58affb7, 0xe8d8a523, 0xf5d28ad0, 0x9fe8ef8e, 0xbeb3c0cf, 0xe3015322, + 0x7ad72568, 0x1372b87b, 0xab223838, 0x792a42fb, 0x5d42afd8, 0xb9fe5fe2, 0x579e41e9, 0xfbd87025, 0xe0cc56ab, + 0x8e73ca50, 0x43213443, 0xe5efca42, 0x9796ba36, 0x528d86f0, 0x98a0126d, 0xc2382204, 0x2f7ebfac, 0xb0662a3c, + 0x90150901, 0x9e5e41a8, 0x825691e7, 0x4d7532d3, 0xc30d3ea3, 0x2420118d, 0xeddbb530, 0xf2d44db3, 0xc9df47fb, + 0x2e806976, 0x146327c7, 0x800efb6a, 0x53a7355b, 0x81c37b78, 0xfe28bcab, 0x34675e10, 0x4860a7a2, 0x56e00c82, + 0x1df46089, 0x98767476, 0xa736ee70, 0xb3cc575c, 0xbae9a9f1, 0x963ed285, 0xb7e97716, 0x347f168f, 0x2abe5db6, + 0x29cc35b3, 0x5f170162, 0x39331eaf, 0x620415c4, 0xc3e2baa1, 0x51d1790b, 0xdcf70ea1, 0xb55e03cd, 0x7ad4e671, + 0xa207d845, 0x3021ea07, 0x2e663a1a, 0x10dbe171, 0x07cbccbe, 0x14adf5a8, 0x4f1a2565, 0xaf9236ed, 0x9adaf679, + 0x137ad973, 0x078ee679, 0x8c59fc01, 0x0aa8e669, 0x4a5a770b, 0xec7ad99d, 0x64233585, 0x88be0020, 0x2e82d405, + 0xc0565810, 0x5a13f80c, 0x5fbae26b, 0xf9ccdb87, 0xbb6404b1, 0x6ce6d6f7, 0x71f24695, 0x0d72da06, 0xa5a93f61, + 0xe73c50c7, 0xa62c6d06, 0xc8adef8c, 0x0088b144, 0xf191909f, 0x016df966, 0x1b75a02d, 0x217c8526, 0x59c1c557, + 0x0b619e0d, 0xccecb52e, 0x67198f5f, 0x863381c4, 0xce0a388e, 0x49e75d02, 0x21a3f519, 0xa720625d, 0x1f072613, + 0x33ece0c8, 0x9d744495, 0xd2cce2f3, 0x0baa5f96, 0x664d0e53, 0x04c1e09d, 0x7122b31a, 0x22bcb206, 0x9c0b5050, + 0x751b1bf3, 0xf33ea7c6, 0x8fc422f0, 0x211ee482, 0x8bfaba8e, 0x54ce50ca, 0xdd11c504, 0x558834b3, 0xd6e0571b, + 0x4e7c023b, 0xfb563b60, 0x8a48aecb, 0x9a30c798, 0x35508979, 0x894dde1c, 0x96ca31a8, 0xc0e977f5, 0xf8acc629, + 0x2cccd2d1, 0x77af05d0, 0xc823577a, 0x5da9f870, 0x65b43484, 0xd70f6ec4, 0x566eff68, 0xe7e6fb76, 0x1f603e2f, + 0x8e342e1a, 0xe794a358, 0x6f450ec8, 0xabbea97b, 0xea4f6bcd, 0x0810dcde, 0x7ebb7e6f, 0xf96e1185, 0x329d59c5, + 0x758d128c, 0xfc082529, 0xd36b0342, 0x87de34c6, 0xb3e65420, 0x1703a497, 0x63e528ce, 0xcbd1c9b8, 0x35c6ba2f, + 0x0b88cbea, 0x3906a79b, 0x406ce074, 0x99b97739, 0x2bbe4ec3, 0x57650212, 0x6d341354, 0x9c0ae301, 0x99770e77, + 0x5c3ff49f, 0x44817146, 0x4f3bcec7, 0x0b3efc38, 0x605d6999, 0x729460eb, 0x2dcfd21b, 0x16e24d84, 0x028c5ad1, + 0xf637ca38, 0x5caf0a63, 0x76819910, 0x78d5694e, 0x512790e6, 0x224e3b62, 0xbcf7a1df, 0x3648276f, 0x9d309a4f, + 0xc4e0e060, 0x71a5f9f3, 0xa128cf29, 0x71e4affe, 0xaf463162, 0x43399cd9, 0xda25a520, 0x518ce22f, 0xbaa45a14, + 0xc3e3a932, 0x8a88e2e6, 0xd1edc131, 0xa6d37f75, 0x0aa3ae92, 0x05e8d72f, 0xad9cd447, 0xc6337e60, 0xf2fbbfbf, + 0x70ff3c9e, 0x7c6877fe, 0x5dc8c4ad, 0x8b170b4f, 0x9bde3436, 0x6f78f2e7, 0x0a743808, 0x9bca499e, 0x91e7ed48, + 0xb9988717, 0x91678bf7, 0x2aed66d1, 0xd9131838, 0x801d5959, 0xc8e6f78f, 0xd4c0cbf8, 0x90bff447, 0x0356e5af, + 0x44db4498, 0x8203362d, 0xf85f72f8, 0xceecb67b, 0x9c1c539b, 0x28e89119, 0x89f934ec, 0x17c9a121, 0xf0f10893, + 0x34483567, 0x580b74fa, 0x6a0eaa6e, 0xdd43b773, 0xdae7ad2b, 0xceba057e, 0xccad5dac, 0xa997fea0, 0x89a64a98, + 0x0b89b6ad, 0x4f4121d8, 0x2c3d69d4, 0x293debf5, 0x9bddea6d, 0x0e86b022, 0xab701f49, 0x4ac729c4, 0x0acb881f, + 0x837cd7a7, 0x0ba995c1, 0x45ca4e84, 0xdb827876, 0x3b66b92a, 0x6d5eec17, 0xbcf2ff76, 0x1a3d0cf5, 0x9bde794d, + 0xf01b4967, 0xfd7ab4a1, 0x7b5e1c4c, 0x8bf337a5, 0x6665ef6b, 0xb78eb952, 0x7b6c1638, 0x64b7cd98, 0x561cee81, + 0xb24a05e5, 0x41f73927, 0x179f753d, 0xbceb7d4c, 0xdd129c13, 0x5ecb3e6a, 0x48f0db79, 0x19f1c3f7, 0x74223cf8, + 0x15da9be9, 0xf7bb8b77, 0x33e822d4, 0x980226d3, 0xd482b904, 0xe77ee4a6, 0x83247ee6, 0x31bc2123, 0xb5c92ad6, + 0x9081b9b8, 0x94d00851, 0xd942e2d9, 0x1715f327, 0xbe055aa0, 0x3b0a971c, 0xe6972a8e, 0x3783f6ae, 0x8846822c, + 0x72995095, 0x055463fb, 0x90cf75a2, 0xbbf4038d, 0x9e3be1c2, 0xfa98be96, 0x1b160263, 0xc5b4e132, 0x9971ef92, + 0xd6ad6797, 0xecfa288b, 0x206d07de, 0xedddfbef, 0xb3405a60, 0x09be685d, 0xdf9ff444, 0x6e1684c1, 0xee0aa8ed, + 0xf3fad5b0, 0xd2c023ea, 0x4f10db29, 0xa225b17c, 0xb0005fce, 0x57807cf6, 0x08599087, 0x61057844, 0x4ea8b5d3, + 0xf102e530, 0x7cf72399, 0x0074f694, 0x3e90c1a3, 0x22fe0680, 0xce75af70, 0x007b89cd, 0xd395bbfd, 0x917b524c, + 0xfaa698f7, 0x8a6595f7, 0xbd017208, 0xb19efbbf, 0x073657da, 0xb40121ab, 0xb77874b0, 0x960549a8, 0x7b43c9bd, + 0x3e1f4aa4, 0x6ff5635a, 0x96c2d5eb, 0x3c853569, 0x1872f302, 0xe3ab22cc, 0x62e9e59a, 0x7f64423a, 0xbe136b85, + 0x3c6750da, 0xcd61cdb6, 0x0d5a54c7, 0x9119bee2, 0x97289961, 0x68f4bbd1, 0x49e7d625, 0x745d4b22, 0xd476bf3a, + 0x86a6a1f8, 0x1d7da825, 0x366e1a85, 0x76a532db, 0x4908f06c, 0xaf2d3374, 0x7162d898, 0xc8ddf616, 0xdc512137, + 0x6fe3267d, 0x975c666f, 0x6813e401, 0x38dd7e9e, 0x663a0b0e, 0x790301c0, 0xb39d13d1, 0x0491d9a0, 0x2768dcb8, + 0x3997011a, 0x42d81f50, 0xd4f1780a, 0xafe08be0, 0x6b921d29, 0x9529b8db, 0x118ca6c6, 0x882b560c, 0x2322d1e2, + 0xee9597bf, 0x9c58f2d6, 0x7f16d89b, 0x0f7c0869, 0xc8068961, 0x38a9e4f6, 0xac5ed930, 0xad65d619, 0x7b9338ef, + 0x4565a906, 0x64d454f1, 0x9e5850ed, 0xc0fac8c4, 0xe9ec2dff, 0x04aab4f0, 0x99a9686b, 0x08817be4, 0x32952b18, + 0x07fb26ff, 0xcb1e31ae, 0x245ecbcd, 0x039ec7b5, 0xe0c3b4ef, 0xeaff2d2d, 0x7fbc6cdf, 0x63515e1c, 0xf181bca5, + 0xdaef0b84, 0x7c9f47d5, 0x00a13fa6, 0xaea6ed44, 0xe7d31b3f, 0x0d9cb321, 0x8cd0eec8, 0xcc95bfa7, 0x34c5a4bb, + 0x86dc47b2, 0x7749f73a, 0xb98f8ef3, 0x05fcbc95, 0xed93b812, 0x7486c1f0, 0x4357456d, 0xcee1cffb, 0xb2f68b98, + 0x624c4a06, 0xa5f6d3b1, 0x19993f76, 0xd79063c0, 0x4d43d5e3, 0x1e66ef3e, 0x50ffddde, 0x55dcb526, 0x895fa017, + 0xc604b4f9, 0x951ba96a, 0x014f411b, 0x03dde194, 0x67db40d7, 0x8ce9cd50, 0xff2181d0, 0x6d3dc8d6, 0x965eae84, + 0xc4dec0b8, 0x579e1d29, 0x9369460a, 0x94674963, 0x93f949d1, 0xe6149ba5, 0x012ebabd, 0x56cdd777, 0xd5fd28c7, + 0x074f1d80, 0x2965082d, 0x8332792a, 0x975c1358, 0xb20142f5, 0xbffc9762, 0x7b1b3062, 0x382ccd73, 0x9e1133f6, + 0x5942c280, 0x5e770290, 0x3cd6fec7, 0x8eadca51, 0x8747d312, 0xa5ab88c8, 0x3c409678, 0x0212d8c3, 0x69eaefc5, + 0xcd6091ef, 0x516f8535, 0x3788f658, 0x9a1d52bd, 0x5e5a6cf7, 0x12930623, 0x5ba68049, 0x23679854, 0xdcea88d7, + 0x6bda83e6, 0x8afb1546, 0x0fb104ce, 0x5f59fb57, 0x0445e02c, 0x6b968011, 0x91b36b55, 0x9b08b248, 0x0b259385, + 0x903fe0fe, 0xccaf4970, 0x2c506794, 0x22616d7e, 0x17322683, 0x520f4665, 0x33e9f158, 0x9ce26f35, 0x384060e2, + 0xb781898e, 0x5d69fa92, 0xe7bb4a2e, 0xf055c162, 0x7d496ea8, 0x3c7c2c24, 0xc47a3450, 0x89aa424c, 0x9c07f444, + 0xc86f6f34, 0x703496e8, 0x9a32f2cf, 0xfee8a7e3, 0x1f3448fa, 0x23bd0323, 0xdeecebf7, 0xdfadf3f3, 0xb78a0291, + 0x5a44b045, 0x8a70523e, 0xabbe055e, 0xdc1dd99b, 0xd414089c, 0xbc662c59, 0x80f9c423, 0x55a0f7f1, 0x850cf33f, + 0xea8e1d28, 0xb84e505c, 0xccc5cacb, 0x0a473be1, 0x94f940b3, 0xf69f57fc, 0x08efaf0f, 0xe9fc792c, 0x4b5c6b6c, + 0xea49c1f0, 0xd2ca08e7, 0xf4e32755, 0x6f806549, 0x02064662, 0x3fc54de1, 0x4016f378, 0x7b48d41c, 0xfc2b7a13, + 0xc047d1d4, 0x6643e09d, 0x7521df0e, 0xbb963716, 0x8ca1361d, 0x6c06237b, 0x1a42a141, 0xc49575a8, 0xf0948c62, + 0x62a04c2b, 0xb6bad81d, 0x8f8a65ab, 0xc3152fc0, 0x6160cb48, 0x2a47c95b, 0x5cfff316, 0xd4bb451d, 0x897370d9, + 0x733027cc, 0x7b45cbda, 0xef10d9dd, 0xc3d979f1, 0x9237c800, 0xa147fcbb, 0xdb59ce08, 0xe28d43bc, 0xdef0a759, + 0xb88850a4, 0xec8aeea1, 0x924e9801, 0x042f8bdb, 0x5a8d2a56, 0xb28034f5, 0x5f004618, 0x1ad14151, 0x7936cefc, + 0x6c4bc816, 0x4511de2d, 0x06c0d9e3, 0xaf53ff53, 0x10b77a67, 0x58231b21, 0x6cbcd0e1, 0xa6f8025c, 0xbd4d1f28, + 0xefaf55f8, 0x8898c5fb, 0xdeb7029d, 0x55ecb25f, 0xbd8a1707, 0xd2f33e64, 0x07b07c02, 0x8c6ae043, 0x133eed64, + 0xee7f4367, 0x86b6a57a, 0x9a148c6c, 0x142a40bd, 0x8cd55bd1, 0xea21ef35, 0xcd29be77, 0x65002546, 0x52c258aa, + 0xc29e2d7f, 0x302e4568, 0x6b403f37, 0x009eab19, 0xf84b5def, 0x5edddd84, 0xedd6e3e8, 0x19a2ff6e, 0x111776a9, + 0xc0411caa, 0xd4bced42, 0x3912ded1, 0xccd0d154, 0xaa45d411, 0x4f38b3df, 0xed50add5, 0x3642c202, 0xed64fca3, + 0xb1f5b1ca, 0xec47f399, 0xa480404c, 0x0e0424ac, 0x30c3195c, 0xf84227ce, 0x72eae669, 0x89300257, 0xe6c36ced, + 0x71f2eaa7, 0x0f42c10a, 0xa0156a7f, 0xaaf2c825, 0xe765d10f, 0xa663d575, 0xa3ddd0c4, 0x99d41ab3, 0x0cb17630, + 0xae883f5d, 0x72af6976, 0x1717aa8e, 0xa0a475ff, 0x0e8c4377, 0x4be657b9, 0xbacd55ab, 0x1b1c96d7, 0x7961809b, + 0x831b877f, 0x84f66c3a, 0x92c8c0a2, 0x55146b68, 0x5073fcaf, 0xdedc89ba, 0xccd12497, 0x15e31c02, 0x14635930, + 0x4e262a29, 0xe475b2cf, 0x31ac0ad8, 0x30360d3d, 0x650bcf57, 0x143e1e8d, 0x198e638e, 0x4f046d9a, 0xaad6f854, + 0x35f753c7, 0x1b265d26, 0x61f69a70, 0x43a2671a, 0x4f146309, 0xe7fa0297, 0x970269bf, 0x8a2325f5, 0xd0157182, + 0xf36e0bb0, 0x5b6c4bc2, 0x5700a304, 0x8fe30e6d, 0x8dbf39fd, 0x25131b9c, 0x5c599663, 0x469033c4, 0x4d4f265c, + 0x3d68f4fa, 0x71e696b9, 0x072d00d6, 0xc02a05bd, 0xb83f505e, 0x69486080, 0xa4925caf, 0x98cd3e03, 0xd65e30a2, + 0x6b5f2dd2, 0xa41c764b, 0x863ae296, 0xe5991a4f, 0x3aa59c43, 0x7901a721, 0x7bcea7cb, 0x70dd39a8, 0xc5a2650f, + 0x242a1fe2, 0x6c418629, 0x5d692979, 0x87f12318, 0x7f1f5da2, 0xadd7ad1c, 0x5b0295df, 0xbab52760, 0x739e47e9, + 0xd4318b0f, 0x23649ca0, 0x1bee6369, 0x4801605b, 0x01c70c7f, 0xc3326114, 0x8d6ce3fa, 0x9e7c924e, 0x0206f5cc, + 0xafa0caf3, 0xb2f51cb6, 0x6d164bc3, 0x7fe62164, 0x5d7de925, 0x70884d32, 0x7c16e38d, 0x76bc7d31, 0xee8390e2, + 0x6a38a972, 0xbfd5cd41, 0xea1be436, 0x4d4a6fec, 0x27dc99f8, 0x1e2d9821, 0xeccd968d, 0x69337bef, 0x86f01364, + 0xa9e48c0f, 0x537037c0, 0xd33ebd54, 0xba19b0c5, 0x9cea1e9f, 0x96c82fa5, 0xeab09c6f, 0x9f77e309, 0x5c26b714, + 0x0b6fd7f9, 0x8406b11a, 0x0ae7d0ea, 0x6e3b746e, 0xce7466b9, 0x7f034114, 0xc2a59e83, 0x61cdb714, 0x7570e3b2, + 0x8f6982f3, 0x70d068ee, 0x3545a0ed, 0xcdd02ba6, 0x5f107ff0, 0x7b834c26, 0xbdea9343, 0x49333efc, 0xc88b51e5, + 0x1c8dfd9c, 0x19f9f534, 0x0e265ea0, 0xf784050c, 0xecff0a7e, 0xc7ce3b7c, 0x4df079a2, 0x22a6cafd, 0x05993e42, + 0x574cecce, 0x60cba1ab, 0x2d20d01b, 0x84c1a1e8, 0x9065d667, 0xb63fdca8, 0x3ed4571b, 0x0c247f80, 0xb0235713, + 0xc6b35400, 0xf877bcad, 0x8e1eb0f0, 0x034ecc8f, 0x539ab31d, 0x8753edf4, 0xbafab9dd, 0xe6fa5d67, 0x0e99fee2, + 0x53bedb24, 0x342958fd, 0x08909b49, 0x0e1bc28d, 0xbefcad26, 0x1af70156, 0x15559665, 0x6f338b76, 0x7a90110f, + 0x0c47abcc, 0x6520cc1c, 0xdc097f04, 0xc096c551, 0xfef16ac5, 0xc8958a71, 0x2eb7d6c4, 0x099dbaaa, 0xb32cc2ab, + 0x7009d71b, 0xc24c79a3, 0xde0a7eee, 0x4649439e, 0x938fc728, 0xbe757739, 0xbed8c71e, 0x96ddb049, 0xde400033, + 0x0167d15c, 0x0393703b, 0x6b7c9e15, 0x58f65772, 0xa8e45466, 0xc280e24d, 0x4a7d9ddc, 0x7fa6702b, 0xaac7fda8, + 0x81da1903, 0x6cd3ec3d, 0xd5246cd0, 0xa95252a1, 0x672db33c, 0xa81c0f63, 0x45b1955e, 0x3df31bae, 0xd16bdba3, + 0xc3e70610, 0x1f982088, 0x67b28d39, 0x1e67140f, 0x42c5396c, 0xa7378a38, 0xd5944dc9, 0x3fd8c5c0, 0x8887a129, + 0x76f13244, 0xb65b2dbc, 0x129a99bc, 0x104bc3b4, 0x2c53eef9, 0x19c24bcd, 0x6e7aff4a, 0x39cd4d6e, 0x5b8b0aa7, + 0xb8e957e2, 0x38777a1d, 0x15b3455f, 0xa54c79fe, 0x45d169cc, 0x1ce99c5c, 0x786ce18f, 0xc54d4f8b, 0x423ba636, + 0x343df4d8, 0x8efd5c77, 0xc733bccc, 0x626c1c11, 0x561dc3f2, 0x56c0ec19, 0xb3981639, 0xde756191, 0x5f8f15aa, + 0xbded8f1d, 0x0c5786e2, 0xfcedb9f8, 0xf44564e4, 0xe12f4362, 0x51a006be, 0xc04c3eff, 0x384d9c43, 0x2e36c382, + 0x93ca6e67, 0x3552f277, 0xc6a67317, 0x709b2df6, 0xbb8ddbef, 0xcd641fe0, 0x0ab3ad98, 0x95dcb87b, 0x7e2b60ca, + 0x14a05297, 0x69423287, 0x39202bfd, 0x4d2ea8a1, 0x43c4552f, 0x24c71b7f, 0x6a4f9703, 0x93e66add, 0x70a73319, + 0x1fc2bea4, 0x3a0e628a, 0x6241bcdf, 0x897890c1, 0x0aebdb0a, 0x2db57b64, 0xdb589c64, 0x358e9595, 0xa1014f58, + 0xb5e351e7, 0x3a651fa6, 0x8da5f7e6, 0x1ab6c8cf, 0xb7d0099d, 0x9522102f, 0x72417ae0, 0x369147d8, 0x86bc4baf, + 0x063ad507, 0x17eef327, 0x1332022f, 0xe3b8161f, 0x8ee987f1, 0x1fc98bc5, 0x18f2ded0, 0x29afd8e9, 0x838166da, + 0x9ad2f7f7, 0x116b8217, 0x49da090c, 0x755b2f68, 0x95591192, 0x92773e15, 0xe5690a08, 0x4775bd15, 0x67342ae3, + 0x9aa20aed, 0x0654ea4e, 0xa995dcc8, 0xdb24c36f, 0x7f511b48, 0x58ed546e, 0x1b0778dd, 0xf2dd5da4, 0x6d7c949e, + 0x1dcf0372, 0xff39ca44, 0xd0ccd049, 0x878f72d2, 0x22d31e5e, 0x6472ee6a, 0x6859f07b, 0x58e70877, 0x406aa07d, + 0xfd0b1e1a, 0xca64a125, 0x21dd195c, 0x3b61dbb1, 0xe5a9a811, 0xa5ee6221, 0xed0eca4d, 0xcf9bf573, 0x14992a08, + 0x0f9d666f, 0xdffe3e80, 0xc1863aac, 0x324420e6, 0x401eabec, 0x232caf16, 0xa1f5deeb, 0xec8650bc, 0x1a495ee2, + 0xe0ee4f39, 0x10f29cca, 0xcbebfbc6, 0x68bfd969, 0xbcf62bbf, 0x3b9df745, 0xcaa6a120, 0x0842cffe, 0x728a954f, + 0x536b32ee, 0x0f153c4a, 0x8ca45282, 0x8c92bd71, 0x4d66beb8, 0x6c6260cc, 0xfbb76d79, 0xc0f4894e, 0x86424a57, + 0x7d81d538, 0xcf98e77c, 0x45d32a68, 0x62f2e33d, 0x90739141, 0xdeb86940, 0x6bfc6d14, 0xbf7a73f8, 0xef274b8a, + 0x9bfd15d9, 0x426e7d80, 0xa0497f06, 0xc9a25ae1, 0xa8a1cddc, 0x8813dbb2, 0x364bcb23, 0xea47cd2d, 0x619d1843, + 0x395f1c31, 0xa3fb17b9, 0x57843fae, 0x31a8bde5, 0x218ddf62, 0xb2a75903, 0x9f5f2a88, 0xb0b32535, 0x512bd462, + 0x1c50d6e8, 0xcb593c10, 0x8388baeb, 0x8a25893f, 0xdb990dfc, 0xb5267f80, 0x23928e1e, 0x5cb81560, 0x867208ad, + 0x85e59393, 0x45cf4824, 0x5ecd7b36, 0x18fe4f0c, 0xda4ad633, 0xf8b34f58, 0x7a072d92, 0x503555e7, 0x8727ddf2, + 0x75d665ed, 0x2a24691b, 0x465f6d66, 0xb751af4a, 0x639ec6a8, 0x4f685c91, 0xe57b7f3a, 0x94efbe60, 0x262c9936, + 0xde8a76a6, 0xcf0574f9, 0x6d40dc02, 0xdba2a2d4, 0xd70de20b, 0x16258e5d, 0x476f5ec3, 0xd34b72da, 0x297f9def, + 0xf0c1c971, 0x50d0ce74, 0xbdc9ef86, 0x546977f3, 0xc7d375a0, 0xff82c873, 0x8f93f994, 0x0caa2fd6, 0x6f7406e2, + 0x0ca80b87, 0xafb59128, 0x3f80c780, 0x752462cd, 0x3f3d6b4c, 0x83102fb4, 0x61a53937, 0x632db954, 0x1bd6e54d, + 0x9d1bc8c5, 0x32034898, 0xf82179d1, 0x65da4e82, 0xe0984e65, 0xbf2eeb51, 0x602b4e00, 0x036ebe95, 0x6827867d, + 0x5ad4c2aa, 0x8fc669f8, 0x2b597629, 0x018affe9, 0x582c81a3, 0x22901c72, 0x46ae6f1a, 0xb59d74af, 0x45f8229b, + 0xc955f601, 0xb7504189, 0x87959a45, 0x7e6baab1, 0x090a5e92, 0xd1353525, 0xf344d283, 0x47749039, 0xa4a19f87, + 0xa12cd5a1, 0x08c21ab1, 0x78ab96e4, 0xf377d77e, 0x866c7301, 0xb6736190, 0xf80eaa85, 0x742db2b7, 0xc5a660fd, + 0xe1cbed94, 0x1fabfadd, 0xfb9f4bf2, 0x3307ed56, 0x02e32aac, 0x5772c6ab, 0x43051ac0, 0xed435d07, 0xe02d2884, + 0x525ed468, 0x3d05e102, 0xd8c52612, 0x0000da2b, 0x1e17346c, 0x9e272b0a, 0x446accb8, 0xdc418fe4, 0xda02bbb1, + 0x164ee7fe, 0x9cb466e9, 0x9b3c854a, 0x0012792b, 0xfbb6385e, 0x4f258f12, 0xe3a150f9, 0xbf972d94, 0x79c54895, + 0x64808f5a, 0x643cfbda, 0xc608630b, 0xa70ebab1, 0x12e6167c, 0x4c6667a8, 0x842e03f6, 0xbadaf8c0, 0x7c69a119, + 0x458400aa, 0x1b6433de, 0x23b77a53, 0x8f80a259, 0x3b52e9df, 0x9b284a0a, 0x6524db01, 0x076b50ac, 0x9121f637, + 0x8514310e, 0x7bd444bd, 0x63fbad36, 0x41b12b4b, 0xb2da3119, 0x1abb66a2, 0x688afef8, 0xd3c6fe93, 0xc3334ab6, + 0x3730aefe, 0xccf9072d, 0x9870f5ad, 0x65b6fec7, 0xda828f83, 0x559f82c9, 0xdb134d9c, 0x1eddaf65, 0xe7ad5517, + 0x8c3f6cc7, 0x451d8452, 0x3f75a920, 0x397bc6f9, 0x43ba670b, 0xbd70448c, 0x0d9c026e, 0x6b729407, 0x53202d6d, + 0x8ea11244, 0x49662c9e, 0xee8d3832, 0xb16c5006, 0xf2aeba62, 0xdf358147, 0x4d2ed27e, 0x7b78cb85, 0xf4bf4815, + 0x56dd8a11, 0x90a4eb4a, 0x2a1527e1, 0x0378ac94, 0x22b79b14, 0xdf9fbea4, 0x44897164, 0xaa912e98, 0x1f17b2c8, + 0x75e90ab7, 0x7544b468, 0xe14594eb, 0x805fb3d5, 0xd59f9091, 0xf0e5d037, 0xff7eefed, 0x3f956a4d, 0x191a9b63, + 0x7d44826f, 0x43ebf14e, 0xfb8ebfa7, 0xd7e1f89a, 0xdd6f399e, 0xa04a3587, 0x18befb32, 0x8731f551, 0x5ebdd957, + 0x6a0f287d, 0xe7360abb, 0x0622f981, 0xda31356b, 0xa306a55c, 0x2ef853d8, 0x818fbd6a, 0xfb6a01d7, 0x00a3eb46, + 0x63655427, 0x023a7118, 0x10df2b5d, 0xb4fe40e9, 0xce3fb61a, 0xd9cf5253, 0xf5f3998e, 0xb0162493, 0x89a18f15, + 0x18ddf10a, 0xa6aefa71, 0xa2d7d6db, 0xdc23e746, 0xc4e63b73, 0x57040bd8, 0x8422bc7c, 0x3dcbc80c, 0x0565546a, + 0xf114fc26, 0xa163d923, 0x06608d86, 0xc21dff9a, 0xa1dad33e, 0xe6e8b94f, 0xdb0fcc3e, 0xcf4c6904, 0xcf446247, + 0x2970bbc1, 0xd273df31, 0xf3a28653, 0xfffb894f, 0xdac609e8, 0x870bde68, 0x2f0fb50f, 0x5280fe30, 0x7c1c9281, + 0x89a51687, 0x7d122414, 0xaf17dbd8, 0x298a78fa, 0x898d11cc, 0xa6fb5f76, 0xf578f2ca, 0xc9eda983, 0xd85fe292, + 0xcb7fa051, 0xd2e9d447, 0xa2aa2174, 0xf7d61f7e, 0x9b6bb63a, 0x40cbf76a, 0x29761796, 0xe59ba6f9, 0x7f80ca6e, + 0x63304824, 0x4e4bfdfb, 0xcdb9a986, 0xd9cd72ad, 0x92348197, 0xa485477d, 0x73192fea, 0x58549d09, 0xba410b3f, + 0x5b5db894, 0xc372d50b, 0xa3c5b18c, 0xe9204d86, 0x737431a5, 0x0f9759da, 0x65abecdd, 0x8fce7538, 0x5d111ed0, + 0xf0f2c772, 0xd0347891, 0x0a047a35, 0x59f86286, 0x0ec61f5a, 0x9a065f3f, 0x2dc02be1, 0x1dc179a5, 0x3b58be27, + 0x8caba12b, 0xc5c1a531, 0xd27ff8cb, 0x9c6e5a7b, 0x6dcafadf, 0x22b20ff6, 0xa418ff8b, 0x76ff264b, 0xc92722fb, + 0x0b5f7d07, 0x95eb517d, 0x927ec5f1, 0x328432ef, 0x5d45f78a, 0x0a02c90b, 0x0affb1de, 0x91f4e9d1, 0x6afb8295, + 0xaef172be, 0x879e2d51, 0xa4da79d8, 0x698cc3f5, 0xe4dfc56b, 0xc7cf255b, 0xd7d3068e, 0xfd0d491f, 0xdfa8e36c, + 0xdd71dc9c, 0x8ad21251, 0x8edd0743, 0x34b44e0b, 0xe2981ade, 0x73373746, 0xaaebd4c2, 0xdb1c6f7b, 0x9b606b11, + 0xeefddefc, 0xd03d9083, 0x8bc8a109, 0xf82609f0, 0xe3eb08bb, 0xb750c498, 0xd0a08c16, 0xa7aeb716, 0x7024250d, + 0x3e0bdc37, 0xd6268a59, 0xd224fe24, 0xe3a75ea5, 0x1fad906b, 0xfcb14140, 0x7a137751, 0x2e48eeb6, 0x3ab60832, + 0x21685a3c, 0x132db43f, 0xca17d203, 0xf5886207, 0x452d8cb3, 0xc9dda61a, 0x416dc08b, 0x8ae595f4, 0xc8b3b156, + 0x3bf44c0e, 0xff046ae7, 0xeeb82364, 0x102b186f, 0x5784dfd2, 0x675dc185, 0x93d7f709, 0x9e8d74ae, 0xfef91dfa, + 0x448fe6ed, 0xb9b944ab, 0x79a5087e, 0xeed4cfaa, 0x85f99afb, 0x0dea8fd7, 0x48e69ffc, 0x229b3f76, 0x5af71c26, + 0xa1b2a4d7, 0x4ed32cb3, 0x9b309244, 0x2b3ff109, 0x7a763d77, 0xc714123b, 0x937ca423, 0x6ca21312, 0xb15aae3a, + 0x726f84a2, 0x064ffb95, 0xeb5d5c46, 0xe00ea6d1, 0xecc18c57, 0x1669ac1d, 0xf6e43407, 0x6e94b5f8, 0x33a9ed09, + 0xb8a606cf, 0x1e0cdeed, 0xbec6857c, 0x66cefaec, 0x866c9002, 0x05ed639c, 0x87394697, 0x09686825, 0x64805f1c, + 0x9280a24d, 0x5d19762e, 0x54497abc, 0xf2e53e90, 0xd6964795, 0x79bc6cdc, 0x52807125, 0xb9be2eaa, 0xedb6c212, + 0x392451c1, 0xfc622056, 0x3c439301, 0x5e58182f, 0x5952a51a, 0xf09b0777, 0xccb4cd30, 0xf28bfc97, 0xa34fa1c2, + 0xe9bfa982, 0x7a281228, 0xca846986, 0xce50829d, 0x93693f65, 0x1d6c3cf1, 0x214fc4cc, 0x7b330212, 0x81efaadb, + 0xb71892e3, 0x2d57d533, 0x5f972a30, 0x0317b25b, 0xb0783deb, 0xbe9c7084, 0x3550372c, 0xe5d124aa, 0xd56a250c, + 0x7b10df91, 0x604ef95c, 0x09a46e2a, 0x9f90d4d1, 0x4330b45c, 0x23374688, 0x5094a714, 0x79bf8b49, 0x35b95921, + 0x9c49ba16, 0xb5b6ad71, 0xd25ab015, 0x443814e0, 0x8ca3e641, 0xc73d1a02, 0x09473069, 0x565adce7, 0x61eacb61, + 0xabeb8a0e, 0x6fa464cc, 0x247ef33c, 0x39866cfa, 0x7a2db786, 0x51d810ef, 0xcd446cf6, 0x59491a3d, 0x8f538c10, + 0xa69c9efd, 0x74829eb3, 0x565cc430, 0x7532d218, 0x9a1105b1, 0x9b6281c1, 0xc51aef6b, 0xcbdf0e34, 0x3a3ed596, + 0x8adb0c74, 0xdaf69903, 0x16766e22, 0xee2e2c71, 0xb7180c9c, 0xe6fed841, 0x6e1fefdf, 0x9c09f64f, 0xce243314, + 0x4a08c8a3, 0xd49b1bea, 0x47799d68, 0xb7627f8f, 0x1945a679, 0x14c31564, 0x1eea4007, 0xb257c1e7, 0xc6d2685b, + 0xf49ab444, 0xa286da3b, 0x2f135042, 0xf7828a08, 0x7b3eefa1, 0x0bbb2982, 0x044c1601, 0x5e346e79, 0x19190d93, + 0x2fcd8f03, 0x1cfce4b1, 0x0d7913a2, 0xa1db2235, 0x2ab4bccb, 0x37ea6a03, 0x24b5366c, 0xaab8ad1d, 0x318bdcaf, + 0xce81f716, 0x4e8d4abc, 0xa1b475df, 0xa654ab57, 0x7b0cd114, 0xa9e728fd, 0x7ae3b22f, 0xee4f710f, 0x4194999b, + 0x28edfcaa, 0xc4ca72d9, 0x3027ec0f, 0xe9e284d9, 0x05de61f2, 0xc6a53253, 0x89d4db3a, 0x56473242, 0x71766a68, + 0x435df89f, 0x657c7b01, 0xa2a1f29d, 0x619ee01a, 0x2ba31139, 0xec93aa2d, 0xbf21e48d, 0xc12eb110, 0xcece30f9, + 0x127ac5c2, 0x0375e765, 0x2b4694a8, 0xe1b263ac, 0x715df161, 0xe87ae46f, 0x271e2e47, 0x44a039a3, 0xbd8ab4a9, + 0x0437730c, 0xc46085d6, 0x181294bc, 0x28060b1f, 0xc0394ac3, 0x3f2ce5b9, 0x72f6678d, 0xe519fb41, 0xdb791c0d, + 0xec4bca64, 0x6974e644, 0x176a2a97, 0xd566d035, 0x57801473, 0xfc714d3d, 0xd660dd5e, 0x03641927, 0x4b04cbba, + 0x6d86e8c5, 0x5b3c0c24, 0x277b10e5, 0xb605515d, 0x42c2b2b6, 0x9c013a81, 0xfeb809d9, 0xd5694f23, 0x0594e389, + 0xd5b6ee0b, 0x816eeb75, 0xf698ded4, 0x64c74d2b, 0x9854899f, 0x299d914a, 0x2dac5956, 0xdd2a4b54, 0xf627c9ef, + 0x1d20e0fb, 0xe1e822be, 0xe4ee475d, 0x28ba6435, 0x4fa4ee69, 0xe138a347, 0x3960dbc9, 0xf3a7077f, 0xba50f767, + 0xe1316485, 0x49c4bed2, 0x4dc6e85a, 0xeef15ac0, 0x2ceefa90, 0x65fe1039, 0xc6d22f02, 0xbb1b569f, 0x9f612368, + 0xef3c548d, 0x980234fe, 0x736c6263, 0x5889e1f9, 0x3bcfa986, 0x6e5bd6a2, 0x4ddbc59f, 0x38b8b06b, 0x13dbda13, + 0xe0d472ed, 0x0f3ec3ab, 0x054a5477, 0x6487836d, 0x6c464d83, 0x676f0fdd, 0xf241d0ae, 0x1f37b102, 0x106361ad, + 0x8c84b7a7, 0x281499df, 0x55579474, 0xd22c6b71, 0x9dc0538e, 0x894a8a5b, 0x5068a568, 0xe10c8b48, 0xfa851759, + 0xac446250, 0xba9c8697, 0x3b847ec7, 0x6ea7f69c, 0xb96ff54b, 0x27c28427, 0x51587462, 0xf525e38f, 0x9cce0eba, + 0x6bc3e89b, 0x6bf6680b, 0xc6a40cd8, 0x26c1f368, 0xa3096fa2, 0x0535c700, 0x003e4513, 0xc8cf1dc1, 0xd82133c4, + 0xcade3b5b, 0xe4df0693, 0x9c804944, 0xdb8b2acc, 0x81fa5ce3, 0xff4d960f, 0x850c5c72, 0xe4873842, 0xcfa8ae27, + 0x09c3dfbe, 0xa57614ab, 0x6269f4c8, 0x30338585, 0xedb7a8b1, 0xdbea2748, 0x7164739a, 0x55834397, 0xeda7b91f, + 0x116613b2, 0xf7b6efa9, 0x3be77480, 0x18047bf4, 0x26f25cc8, 0xee73d8e0, 0xd347f92b, 0x8a6a2b88, 0xfba606c6, + 0x53505dec, 0xa73f37e2, 0x5f0102c8, 0x142b40a7, 0x80a59b63, 0xa8f8250f, 0x08b1c756, 0x93be5ada, 0xc3f9423b, + 0x38cd7bba, 0x3a27c852, 0x25bc7c06, 0x65fea777, 0xb6e0ae37, 0x35d2b008, 0x9b53e65a, 0x7b69b6bc, 0x72116de8, + 0xc5151db5, 0x387c173b, 0xfe0735cc, 0xe91f7d88, 0x0518552b, 0x0d0f5c75, 0x2653f114, 0x069a4dc3, 0x3bac74e2, + 0x6874ee43, 0xf68a9ad3, 0x77503778, 0x5709128c, 0x9e3b954e, 0xdc7e2c1f, 0x8b129862, 0xc57524f4, 0x1a196a50, + 0xf2837edc, 0xc0fe8e73, 0xca17662c, 0xdf4759ee, 0x6de2b399, 0x221c2cc0, 0x617c39be, 0xd4763489, 0x28596073, + 0xab816264, 0x68e9e298, 0xecc04789, 0x12b41ab2, 0x06d0a851, 0xdb8c4924, 0x09bdfa81, 0x900280ca, 0xc2f5520d, + 0x9b391af4, 0xc413fb5a, 0xd8833c5b, 0xa2edce46, 0x47c7f6a4, 0x47592b0e, 0x4b32706b, 0x4757f4fb, 0xce335b9e, + 0x46da1b25, 0x5c0848cd, 0x5c9300b5, 0x12532843, 0xc1aa5ca7, 0x577fcd3f, 0xbf8b1b87, 0x930668bb, 0xc8029baf, + 0x1937bd60, 0x9e48fa73, 0x5c51cf85, 0x3bd21126, 0x204264d1, 0x690b95c0, 0x74ed0824, 0xcba8e999, 0xa9b89395, + 0x9d8139f8, 0x6a1c1d7e, 0xe06814a8, 0x4bfe603e, 0xa47ff183, 0x40598386, 0x3f4f4cf9, 0x8f2aa118, 0x5d90d5f9, + 0x1281cba1, 0xabf61c74, 0x3c669d28, 0xb6ce4ab1, 0xbfb5deee, 0xa1c705f9, 0xacc564ef, 0xeff09139, 0x527e0853, + 0xb14fe764, 0xde3896bf, 0xa6b8e39f, 0x6d6006e0, 0x268f30f2, 0x9284b59c, 0x5977d436, 0x502afc17, 0x4374b8b1, + 0xb46f545a, 0xa3e31b7f, 0x525a2d02, 0x3f574701, 0x782a5f25, 0x6199eeb4, 0x4fb24aec, 0x772a41f4, 0x9bac9947, + 0xdb15b672, 0x748842b4, 0x4840810b, 0x9466207f, 0xbb0367f8, 0x6bf9135f, 0x1c8c345c, 0xdfd34c98, 0x0a54b63d, + 0x0e9bae53, 0x1ef04583, 0x49f28de0, 0xd4da7bc6, 0x6189a082, 0x81e5e439, 0xd75e2b4b, 0xf1da5af0, 0xc31f59dc, + 0xf59663a3, 0x8aa63bdb, 0xb8caf7fc, 0x5d3ed4f1, 0xa916a5c4, 0x655f3134, 0x7b97fbf4, 0x078949f1, 0x792fd5d8, + 0x402dfd92, 0x1e77e3b8, 0xcadeedf1, 0x3d26abd6, 0x732afc76, 0x22d33773, 0x62226dcb, 0xfde0ad03, 0x1e6d223b, + 0x1e7d5aab, 0x73b26985, 0x8a3a3de4, 0x630d0389, 0xaffc8c8a, 0x403e870a, 0xcf278526, 0x4abe6594, 0xd4ab7804, + 0x0b168700, 0x0bcc6422, 0xb7d1e53c, 0x6065db32, 0x8186b932, 0x8b51553f, 0x9a6e2eb3, 0x18c4cfde, 0x677589e6, + 0x41fad6db, 0x303861b1, 0x0122c52b, 0x642ef30b, 0x2064afa2, 0xfd8d5578, 0xfb283c29, 0xc0dd1b85, 0x7dde4a36, + 0x09585ba2, 0x5b3a56b8, 0xd0b8653a, 0x188b27db, 0xddacb525, 0x7fd50471, 0xea2da3fe, 0x00d7e705, 0x2815d892, + 0x3b652570, 0x519ffb8b, 0x88cc1c0b, 0x85edb678, 0x46311db6, 0xea2c47d1, 0xe4d45e1c, 0x50d517ab, 0xd9f8096e, + 0x452010c9, 0x356f02ee, 0x2b8cafb7, 0x1868a6c2, 0xa1525ec3, 0x3c643596, 0xfa8a43f0, 0x8c264271, 0xe4fbe269, + 0xd9a729d1, 0x914ecae3, 0x34b13ac0, 0x621c8945, 0x0680d300, 0xc305c63d, 0xcb1025e2, 0xd544e761, 0x29e5702d, + 0x63685d69, 0xb2fbdbaa, 0x4d9244b2, 0x714d0e5d, 0xb40a3802, 0x296e24a6, 0x40e90e6c, 0x4fda03b8, 0x4b4b04c2, + 0xe97088ad, 0xc08cfdcb, 0xf9603738, 0xa35ef181, 0xccc203a9, 0xe7fbc91a, 0xfaa9433f, 0x6e8606b9, 0x655be5fc, + 0xb1be08cc, 0x4922bf21, 0xbee01edf, 0x95651b19, 0x9174b4c6, 0x2a8cc2ef, 0x068c9aa8, 0xc487f064, 0x07b20a96, + 0xe18b1edd, 0x6512ffb6, 0xd2b20415, 0x069a4458, 0xc883160b, 0xea38391d, 0x119835ef, 0x2ece3e0a, 0xb61c8711, + 0x05bef00b, 0xcca759fc, 0x9fc79eac, 0xd15e9bdf, 0x39334c57, 0x9cbdd405, 0xea003e8f, 0xf008006f, 0x3adcbbb6, + 0xcb85aa69, 0x5528ffb1, 0x0e7d45bb, 0x996aef0e, 0x906a3cd1, 0x49848731, 0x469a0169, 0x2623a754, 0x444b7110, + 0xb622b03c, 0xe8e4740e, 0x52bb1e3d, 0x2e91636f, 0xe713feb1, 0x3321611f, 0xa32d5c70, 0xf7e624c6, 0x048d2806, + 0xbd307f03, 0xb369ce38, 0x67477bc6, 0xad24d197, 0x71576ec3, 0x89982066, 0x9be493b5, 0x364a1933, 0x9c9ab8a2, + 0x7be15e4e, 0xdc512bd5, 0xd63e64c7, 0xcef4a7e2, 0x69fa71db, 0xc9603914, 0x2794f848, 0xffb3a3b9, 0x37534c52, + 0x587f0b84, 0x4d38066e, 0x7439b34c, 0x6bb195c7, 0x7447c322, 0x7e4dad56, 0xf581f66c, 0x5b51d83f, 0x3dc7e92d, + 0xa3593ec7, 0x8a60c374, 0x576d1ace, 0x76bc4422, 0x0ce45891, 0xc1a7ced4, 0x43475a76, 0x43610101, 0x8f7ee12e, + 0xc841c23f, 0x659f0c00, 0x95f78977, 0x3ca0690b, 0xfe4686d7, 0x1c4ae69c, 0x7a88346e, 0xec63355b, 0xe286aaa6, + 0xaa3fc8e7, 0x062a9b7f, 0xdaec441f, 0xe9b81a50, 0xbdf160a8, 0xaac4ec7d, 0x5bced99d, 0xc1271a72, 0x383dfe87, + 0x9731b7d2, 0x7e608a39, 0xe26eb2fd, 0xa5b1456d, 0x1e4cf1b9, 0x6702e750, 0xc17cb1c5, 0xefa42c5c, 0xf03d0492, + 0x59110555, 0x42dad21b, 0x54428951, 0xf0af00ab, 0x56e5fe4d, 0x9cf33186, 0x7e53c818, 0xb45cffc5, 0x79288fb2, + 0x165ace17, 0xdefc7d7b, 0xa494688b, 0x07ee91f1, 0x977f10c5, 0xf1f77f7b, 0x847df647, 0x3068e3e9, 0xdfbcbbbc, + 0x9f7e199b, 0x1f9098f4, 0x1be0bb4f, 0x92201add, 0xa960f34f, 0x281740ab, 0x235daf64, 0x4813ca94, 0x7c32e13e, + 0x31bcbbca, 0x127646f3, 0x48e0e20a, 0xf44cf300, 0xd88d5f6e, 0x9b77582d, 0x71ac7cb5, 0x3715f9a6, 0x4356ae1c, + 0x29b98bda, 0x14cce9dc, 0x47351932, 0xb8c36281, 0xcba64cdf, 0x83295bf1, 0xd836111a, 0xfe38cd6e, 0x8c85d922, + 0xf01321e2, 0xf9e60381, 0x991c2853, 0xe4ac6594, 0x94e1854c, 0x347b3d26, 0x79bbc680, 0x7d02f3b7, 0x4ea092c3, + 0x83dfe32f, 0x17abb528, 0xf1fb05b2, 0x428628aa, 0x11b5f4fa, 0x77175e19, 0x312c5591, 0x3c57e7c5, 0x14e7e629, + 0xb640f1ca, 0xb194ba6d, 0xe072e2d9, 0xde426632, 0x01615e7b, 0x5a9f748c, 0x03f141be, 0x79064ff6, 0x52d7154d, + 0x1f0cbc03, 0x0ff62fc9, 0x169ebfe8, 0xa0aa1068, 0x0b5da8f1, 0x8ecff687, 0x211d225d, 0x69de778f, 0xe4d8869a, + 0x56815d5b, 0x5df8ce2f, 0x747d5705, 0xe1fbb0af, 0x9e6b29ae, 0x4e8821f4, 0x2d3ac6dc, 0x35f74230, 0x59edc9ef, + 0x706aafeb, 0xcf5031d1, 0x59fdc5dc, 0x1d1dcaf9, 0xed504ac7, 0xc7a42fa7, 0x3ff57935, 0x3c150973, 0x910a6ba7, + 0x1e1a5bed, 0x441aafc0, 0x0adf154b, 0x811095a7, 0xcc0d6cfb, 0x023d654f, 0xac190ec9, 0x77cf88ae, 0x6311bfe5, + 0xa29f33bb, 0xbe8ebde3, 0x1e1ff502, 0xde8a71e5, 0x69497319, 0x568e207e, 0x67450cdf, 0xc07143da, 0xf579c078, + 0xd4462721, 0x252970fe, 0x49c1760b, 0x19f1538c, 0x7bd2e991, 0x7c6dcff7, 0xe60fbbb5, 0xe6497954, 0xb4e23b64, + 0x48147622, 0x24d74626, 0xd7e23d8f, 0x2ad753b6, 0xa1c68151, 0x68e66b7c, 0x8fb8ea45, 0x1674c829, 0xed576e09, + 0x863464b4, 0xb999eebd, 0x89ae204a, 0x0e555c05, 0xe413c71c, 0xae7d83aa, 0x907e6f2b, 0x07b830c6, 0xc28ed8c6, + 0x768e53fa, 0xc081b87c, 0xc1d55909, 0xd5c1fcb8, 0x39e18768, 0x46bb982d, 0x164534b0, 0x9cd07530, 0x10d06969, + 0xd487fd50, 0xb983815f, 0x4bf800f4, 0xda0bcf52, 0x311080cb, 0x7dda8ce0, 0x855274a6, 0xda85b88d, 0xfb0948b6, + 0x711c3b41, 0x45e1a0f6, 0x9b3155f0, 0xc4684039, 0x600bc45f, 0x60b10a10, 0xa2707f6d, 0x9146e302, 0xaff3665a, + 0x8b6957a2, 0xbb844c2d, 0x60aba539, 0x86759c31, 0xb5af1583, 0x6a76cb2b, 0x7abc3dc6, 0xd557f131, 0x93bb5120, + 0x82feaee0, 0x13911de1, 0xaa9e7390, 0x9b58e57d, 0x07126a9a, 0x1a0386a8, 0xcd19e8fb, 0x224d0e68, 0x618922ff, + 0x0c40fb73, 0x07b40950, 0xdb60732b, 0x06d6c7f7, 0x4c83af87, 0xdab1cb3c, 0x6de5d132, 0xe373b12e, 0x9c29900f, + 0x8b032558, 0x553072f2, 0xcc18e0ff, 0x312b808b, 0x2f67dec8, 0x4849a63e, 0xac3a7cbf, 0x92f430d4, 0xf5172562, + 0x09f46862, 0x0d0973b5, 0x98579fb8, 0x8a3c7e12, 0x0681bf02, 0x9854b4a3, 0x412f3d8d, 0xa9c4b8ef, 0xf71cd011, + 0x71832a17, 0xeb3a5663, 0x16396840, 0x75244c9c, 0xa72e84de, 0x7bde215b, 0x8288edca, 0x8fe54198, 0x5aa8a56b, + 0xc845d852, 0x4a98356a, 0x33fd2b46, 0x1250de7b, 0x85fd6c3c, 0x6e5009f6, 0x795146d7, 0xa70a466f, 0x9b29ce45, + 0x7bad5ae4, 0x1ae169a8, 0xa2d3ea51, 0x3afa6576, 0x2f487b74, 0x38337d4c, 0x20247d51, 0x4ddb39e8, 0x2ad02063, + 0x7e9e1e79, 0x83cba688, 0x20f494ac, 0xf827886b, 0x969f8003, 0xd823fa58, 0x14e6a97c, 0x4c23afa8, 0x482105ec, + 0x0373c897, 0xf43354be, 0xe020d598, 0x60d59e98, 0xc5cf8b82, 0x9e3a263f, 0xceca53a3, 0x88e27e66, 0xff54887b, + 0xb9c6fd53, 0x5012b99c, 0xa5c4904b, 0xe7c81912, 0x1667d02c, 0x4ff495ef, 0xa96f7988, 0xfdb3b942, 0x688e924b, + 0x34d2e4c7, 0x3da4f090, 0x29d5ad6f, 0x74e4e795, 0x70b5e152, 0x22466d17, 0x4bf53545, 0x0f065a98, 0xe003074e, + 0x8b442bb8, 0xd9967a76, 0x39188b3e, 0xd68e7e99, 0xf6110ab3, 0x92ca7406, 0xa0b32649, 0xd0a7b72f, 0x1969dadf, + 0x2c9e4b22, 0x7790b6b3, 0xeddc83a8, 0x34099d53, 0xe7d22aa7, 0x1a265c8a, 0x8137ce22, 0x158506d8, 0x3213fcfd, + 0xd54e84ea, 0x651cc306, 0xc16a6b8e, 0x2b206485, 0xfd089331, 0xcef7cf97, 0x12f8d014, 0x8be509a3, 0x8630f007, + 0xaf7c399e, 0x45ad9dfc, 0xa1e8492d, 0xbce7fc7e, 0x56736edd, 0x6b60febe, 0x8517f91c, 0xb97f9747, 0x72629479, + 0x0782b09d, 0x46d9c847, 0xad68a483, 0x8048f99a, 0x17c7f2d8, 0x724b67c9, 0x27ef4720, 0xfe943cc3, 0x0587f4a2, + 0x3cf3fa07, 0x093678c3, 0x60390b77, 0x90e7345e, 0x5c23fd7b, 0xa107adfd, 0x2eb86d27, 0x1ab84065, 0x7ab4a0d7, + 0xfbb0842f, 0x5a817da7, 0x8a1eee80, 0xe707945e, 0xcabb81fb, 0xbb531384, 0x6c67e04f, 0x1b8e8e70, 0x55306a48, + 0x5dc019ed, 0xdf7c09d9, 0xb74802f3, 0x250bb41d, 0x8a84024c, 0x64eb6fbe, 0x2641d057, 0x5868f195, 0x53fac846, + 0x43f0bac6, 0xbea876ec, 0x3c653453, 0x34956d27, 0x6fcda577, 0xb6a42584, 0x41251628, 0x0091065a, 0x17231a8b, + 0x2a2ae695, 0xfa27c3d7, 0x6e82447e, 0xb2bc9b3d, 0x2dd7c5a5, 0xde2fa0e8, 0x1cef98d8, 0x5fed8247, 0x579e58b4, + 0x5ef52fd4, 0x248e2cf5, 0xa4e7f1bb, 0x65f864b1, 0xd327ff2a, 0x6cd36fac, 0x9cc61442, 0xf07ef62e, 0xcf567bc5, + 0x8f1c43f4, 0x4abbf19a, 0x8f42aa4a, 0x6ac1c6e0, 0x1856b823, 0x46fd4d82, 0x0d35d73c, 0x69e71eaa, 0x37082392, + 0x688e1187, 0x7eacb2a7, 0xa78be8d4, 0xadcc7d31, 0x87008904, 0x537aeb99, 0x489bf189, 0x86e98374, 0x11169a9f, + 0xe90e81d4, 0x5ecc5e11, 0x0ac3b5a9, 0x932ee89d, 0xdcae0979, 0x19ca70a3, 0x7af53df1, 0x5e511922, 0x40f3a246, + 0x00269b04, 0x1a6b7b8f, 0xdfeadd60, 0x9c4a1369, 0x7b135d1b, 0x259e5e2e, 0x89549807, 0xd63194ba, 0x4d12c54e, + 0xb5030407, 0xe8a51c44, 0x8a18d7d1, 0x95cbafef, 0xdcb4b080, 0x667fe3f1, 0x4d5384df, 0xb2dbcc2a, 0xf484f408, + 0xb89ec0dd, 0x9c9fd8c4, 0x6e863c58, 0xa3706c74, 0x001b645b, 0x7148032b, 0xfede0507, 0x5c69ff2e, 0x537f7a2b, + 0x6ef2545f, 0x114743d5, 0x546545c5, 0xc1e14e62, 0x311a875e, 0xe35c9fc0, 0xf097df87, 0x5ad43311, 0xeaa99c96, + 0xf16ff5a0, 0x7fb01726, 0xf1b1e5ea, 0x9d919cb8, 0xf99b976b, 0xcaa9c73c, 0x102e658b, 0x6bd48591, 0xfb387eed, + 0xf37ad47a, 0x8f09f1e1, 0x8946e516, 0x0a787eed, 0xc00bb125, 0xb6eea79b, 0x041f5a2c, 0xb5b33ec4, 0xc6fcb51d, + 0xbc3bd35b, 0x603ed182, 0x636fb0f4, 0xed55f5d1, 0x900f907d, 0x34a4fbd0, 0x79831a9a, 0xb2fed25c, 0x0ae1e991, + 0x883a924b, 0x4e138675, 0x3b814670, 0x7753da6c, 0x55990437, 0xc45e3273, 0xa0d3b99c, 0xbd586f6b, 0xbea945f7, + 0xadb827b5, 0xf2ae78ab, 0xc7ec2149, 0xa700a440, 0x3948477c, 0xfd8dcbe7, 0x22aeff17, 0xfc1bdc02, 0x2769a817, + 0xe9d237e0, 0xb592197a, 0xb2a078bb, 0xf4ccc6a7, 0x658dd14d, 0x04f98e18, 0xa3dff2a9, 0x1c190a8d, 0xa8573ce5, + 0xf707cc9d, 0x392cc0fd, 0x8f7df813, 0x09e77d68, 0xeb78312a, 0x20195bbe, 0x55b1f709, 0x7c0f6706, 0xea6aeaaa, + 0x725ce7bf, 0x93afa389, 0x503fc7c9, 0xbd7ffed8, 0x32cff3d8, 0xbdb6f8e0, 0x49b739b0, 0xb45c7139, 0x21fb13a3, + 0x99e2d3f8, 0xa551f860, 0x28551e29, 0xc10b5af1, 0xa630e1ab, 0x8953abf9, 0x164aae18, 0x0ff35f47, 0x7f0c3056, + 0xc5f7cc40, 0x4a130f28, 0xbc533003, 0xa00b3ffa, 0x135cc62b, 0xeb6e4e4c, 0xe25a89a8, 0xef5be6bd, 0xfe289f8f, + 0x3b22bc42, 0x6d1fcc54, 0xe301a1b7, 0x4e38d5df, 0x69987df8, 0xdaeaa002, 0x0c09a17b, 0x2e2134ba, 0xbd47eb05, + 0x28922f0c, 0x6d2b3184, 0xcf17a92f, 0x45132c69, 0x8037e4cd, 0xe8943c95, 0xdf94f165, 0x65fe9177, 0x8cda38e1, + 0xaaf30a45, 0x5783b4d1, 0xc56ac6d2, 0xc6be9792, 0x57510dab, 0x766d03ec, 0x57b0ba14, 0x0bd1bdbc, 0x05dec8e8, + 0xd3fd4676, 0xaadaa716, 0xc9fe1968, 0x20087891, 0xfa725c4e, 0xd8677479, 0x13b0cbbc, 0xe15830fd, 0x706562b5, + 0xb083657c, 0x3c13b445, 0xb1e52eee, 0x778a2a76, 0xacb2403c, 0x2d883ac4, 0x3acab7e0, 0x9763cf29, 0xd6d0af82, + 0x9194f8bc, 0xcbcf3ab1, 0x1713ab2f, 0x84ca0290, 0x73c3aa39, 0x363210c2, 0x361c96d9, 0xa53ebc7a, 0x5a791519, + 0x73c57913, 0x443cb55b, 0x0cd156dc, 0x104d7a31, 0x242403ec, 0x653ed80f, 0xa145f4ab, 0x66cedaaa, 0x3ee64aa7, + 0x3a28a02c, 0x2be768a4, 0x21b4a486, 0xc948212c, 0x43780d41, 0x41cc55c6, 0xee6e0bda, 0xc85e376a, 0xb0f958a3, + 0xd6536f20, 0xad34f3cf, 0x631f7a32, 0xee909be3, 0x1821c340, 0x9a2e74b0, 0x72d613f6, 0xd524da3b, 0xcd3b5e79, + 0xcf3e5d82, 0x4e3b2c93, 0x1a4599ff, 0x0f70b501, 0xd84cbf29, 0x0e98174b, 0x3981f47c, 0x7686a544, 0x9d908690, + 0x946dc52d, 0xe8e5145a, 0xca24bc79, 0x2fc6d918, 0x0cec817c, 0x44510dcc, 0x4585d93b, 0x3ca94feb, 0x2aa72ec9, + 0x9689c525, 0x550b9f83, 0x082c41ad, 0xd33c4899, 0xe0512bec, 0x4f411037, 0xfb08df7d, 0xc076e06a, 0x7e4fb433, + 0x3ccf0024, 0x6dbc7aab, 0x1c93da35, 0x9f3dca42, 0x9f85a2c7, 0x19daa81e, 0xbcacdf59, 0xbc9e568e, 0x3e192181, + 0x03d07792, 0x5ecab510, 0xf9bad985, 0x9eab0df3, 0x853ffbda, 0x8f10d3c7, 0x780aaabe, 0xdb5fcd2d, 0xec9c129f, + 0x4e1b72a4, 0xcf883829, 0xe552bb88, 0xb639aa1a, 0xb0d5a9cb, 0x0f69f018, 0xf678e552, 0x63a62070, 0xfad6fa44, + 0x52041677, 0x69d3529e, 0x4aae2b09, 0xeae962e5, 0xcccfc6b9, 0xb6ba67c7, 0x55060b76, 0x2cb8fadb, 0x07c9e5f7, + 0x8f803876, 0x9ac71455, 0x3229d972, 0xa807080e, 0xbb869e69, 0x74df8373, 0x7a658ae1, 0x42b8b4e5, 0xe2c57904, + 0x2de2c135, 0x6ea3ca97, 0x5ef627c3, 0x512e77d5, 0x1f206bfe, 0xca096976, 0xff3a4ba6, 0x17b75504, 0xe4bb2dc2, + 0x95a6e766, 0xce3ba3b5, 0x4cef4605, 0x8920599a, 0x3d6d24b9, 0xf08a7488, 0x309ae787, 0x2bd8b305, 0x9138af3f, + 0x0913ea33, 0x61f58abd, 0x5b058c7a, 0xd998800e, 0xfca013c1, 0xe31a1ebf, 0x44e20b8a, 0x484dde51, 0x54922945, + 0xc9130469, 0x5bfef384, 0xe1e4e78b, 0x6210bee4, 0x550decb5, 0xeb63972c, 0xaf44a743, 0xa1e87b31, 0xac5c8bf3, + 0x50644b5c, 0x62ec9846, 0x8d5a340d, 0x5e803a26, 0x2d0ef260, 0xd9b75578, 0x7f72ce8c, 0xfcc3b8a5, 0x3227aa5d, + 0x86d70ee3, 0xad443eae, 0x5cb13f97, 0x216f4f0b, 0x9a88aaf0, 0x824ae632, 0xd59856e7, 0xf048a462, 0xf7f1826f, + 0x2116d933, 0x26718abb, 0x91151e6f, 0x487d9282, 0x73ba2dc7, 0xb40be01a, 0x165c01b1, 0xf9fe278e, 0xc4866d50, + 0xcb9156cb, 0x8b852fee, 0xf6d256bb, 0x1abcd6d6, 0x60b49eb2, 0x5d47b9d2, 0xb2c99fc4, 0x98ce7b3b, 0x0c649310, + 0x4c0dbdce, 0x5f0cb622, 0x1e6ce6dd, 0x8749156c, 0x9e3d995a, 0xabb1d0f5, 0x5541bb87, 0x798de88c, 0x989c640c, + 0x7a1d013a, 0x164289f8, 0x6dacdaad, 0x4804e8be, 0x7c9c65a7, 0xbc4575b5, 0x132172c0, 0x307ddef6, 0xcc94a533, + 0xec662693, 0x2d266553, 0x9dc0e250, 0x90cb2599, 0x05a63086, 0x0866284f, 0xb483d54c, 0xeb15fc49, 0xc8bcc2c2, + 0x79e877f5, 0x373e1519, 0x861c5579, 0x2b771f39, 0x9809634c, 0x5b0a64f2, 0x8a6bbb1d, 0x7455e84c, 0x0340f6d0, + 0x473cd339, 0x6d7f53db, 0x8e6752e4, 0xdddeb950, 0x8947fd1a, 0xb83fb11f, 0x3e25d3c8, 0xe008ec73, 0xb3f527c2, + 0x967b29a1, 0x2be59c82, 0x8a5ed633, 0xeea75045, 0x0f0827f1, 0x50920640, 0x50be4de7, 0x089046cd, 0xb2962a7a, + 0x5620d2d8, 0x99f55798, 0xe83ba4c9, 0x9da9feac, 0xdb8176f6, 0x8b9eef2d, 0x0faf1bef, 0x14046f40, 0x75e865b5, + 0xacb6d4d9, 0x9434ae64, 0xdab750d4, 0xcafe760e, 0x986dee56, 0xf9c14c32, 0xa1fe82ed, 0x1faa0e27, 0x5da3d156, + 0xc288e90e, 0xf3b22124, 0x00669b6a, 0x0fe97b9d, 0x708535da, 0xc0ca43b8, 0x09dd7760, 0xa3b0b8f8, 0xba00784e, + 0x35d83a57, 0xe2d3dc5a, 0xb7c7fdb6, 0x8baa6cde, 0x4e2aa97a, 0x9ba7d0de, 0xa8298478, 0x56c4dee2, 0x15d4d0e6, + 0x171f4766, 0x2222aa56, 0x25a17fe3, 0xcb720891, 0xedcf6280, 0xf0eafba9, 0x6ac4e3e0, 0x11de501f, 0x655ba4ff, + 0x9b02e65d, 0x1c31342d, 0xf711a612, 0x4df4ef09, 0x9ca94528, 0x0cd646a5, 0xc71ed4b0, 0x30d4f68f, 0xa266049a, + 0xdcf0415a, 0x0ae186f3, 0xff03e36b, 0xdc81953c, 0xc6639998, 0x100678ad, 0xcc900371, 0x43cae1db, 0xbd56c917, + 0xcdb3f496, 0x5f8bd28e, 0x2855e68d, 0x0bd44cfe, 0x486eff2e, 0x47a4ba65, 0x61897e53, 0x264df6a3, 0xe729fce1, + 0x523bfc60, 0xc0117639, 0x2f8b0e5d, 0xf7d5a549, 0x5ce4bae1, 0xd098e15b, 0x653e0af1, 0x850d2ffe, 0xbd4aa056, + 0x5611f0c7, 0x4b0e1217, 0x9db3f7c8, 0x55b24de3, 0x24ddc778, 0xafb7f913, 0x93d186ea, 0xc4eb3515, 0x5e9390d4, + 0x2d265a62, 0xc34f016c, 0xfb8b3b15, 0x1f4156ce, 0xac40aa1e, 0xceb68958, 0x652f632b, 0xf709b798, 0xa185845f, + 0xe1134e9c, 0x950c6a9e, 0xb5bf2fec, 0x592f6e8e, 0x5b11ed41, 0xa9df8675, 0x1f264f73, 0x7f1933cc, 0x107a3bd7, + 0x1ad26a0c, 0x27c97900, 0xcce94367, 0x6bda7779, 0xd667b59a, 0x0d65666e, 0xe8ec0a0e, 0xc305b4ef, 0xcd1e3436, + 0x28c1dcad, 0x324eb6e4, 0xa54b5f85, 0x808118b3, 0xafe28d27, 0xd82c69dc, 0xfd93b47e, 0xcd0a3d7a, 0x0cfa4ff8, + 0x811279b5, 0x0093fb97, 0x25e7fd59, 0xae813342, 0xece70335, 0xaf70b826, 0x9c3321c4, 0x6610632c, 0xef56e4ba, + 0xc60b1c50, 0x072377f9, 0x7702a6f4, 0xe4bae29a, 0x671e88ab, 0xa4aaca4e, 0x38e9114a, 0x11cbf7c5, 0xb0fb5804, + 0x30eb7bd1, 0xecea17c6, 0x3b73e26e, 0x2bd19d4a, 0xb39a74fa, 0x05e739ad, 0xb8858a2d, 0x13fb72ad, 0xe477fb9a, + 0x230a2a0f, 0xd9f8b9d7, 0xd4d61252, 0x5dd96c2c, 0x6d9ca338, 0xa76d6228, 0x703a5941, 0x4511aceb, 0x2a126fa8, + 0x9749402c, 0x4890a496, 0xefb41cda, 0x667a3e79, 0xa009383e, 0xb7656c50, 0xa3c66354, 0x79c86bc2, 0x83bda8aa, + 0xc61938f5, 0xb991d521, 0xa2d9c37c, 0x93a4883c, 0x70c406ca, 0x44f16f50, 0xedb37ac4, 0xd2888387, 0x987925c5, + 0x1ad1cb71, 0x6f17c0a0, 0xeaeca298, 0xcf59e954, 0x742efb0e, 0x7ab90a78, 0x38578088, 0x94d22834, 0xc5f976bb, + 0xb0a9ca8a, 0x84682b8e, 0x0df44a8a, 0x4f311db3, 0xb2d7c263, 0xbf5eee26, 0xa09c04e2, 0x60d63876, 0x6051a8c0, + 0x1ea4d093, 0xcc0756a7, 0x147e2443, 0x64530a94, 0x890b0262, 0x5148c393, 0x1b6c1194, 0xb6d30915, 0xed3075cc, + 0x08fde36d, 0xb2eab62c, 0xd5e09e77, 0xda41aaf3, 0x4c58cd3a, 0x2db43558, 0x0b14b8c5, 0x1e291d26, 0xe94c17c9, + 0x686ab710, 0xf158e3b4, 0x91e3c419, 0x1214e986, 0xa356d07d, 0xb489e202, 0x4edbd95b, 0xe9d4b058, 0xef71314a, + 0xa32acd84, 0x0c1dec0f, 0x4a8a802c, 0x503fbd06, 0x30c4de3c, 0xb38a9f9d, 0xc8b32855, 0x4f3926f1, 0x0ad6d4ea, + 0xb03896a1, 0xe02f8d7b, 0xbd37b61f, 0xc785724e, 0xecf815f6, 0x0b073b6f, 0x40edef52, 0x68358305, 0x56584142, + 0xd8016ce3, 0xa9361512, 0xef239ef8, 0xc4119c13, 0x5584faf5, 0xdeb3f15d, 0x5117a96f, 0x6c4282c9, 0x90f8562c, + 0xf2e19f50, 0x149e512a, 0x7683716e, 0x1baead18, 0xa278b6f3, 0x59c99ae2, 0x3c63cc53, 0xf122035a, 0x15872a18, + 0x2510d0df, 0x30cab661, 0x9fe8acd5, 0x9396aabe, 0x87bf1cb3, 0x44976704, 0xea820f84, 0xd6ef6b4a, 0xf8b72d4b, + 0xf7a599f0, 0x0ead1ff5, 0xd7284869, 0xcd0d0a14, 0x5f99e354, 0x9cdf7385, 0x8abd61ef, 0x485f54a4, 0x28e1c0f0, + 0xeba47f2b, 0x3b5173c4, 0xeeec706f, 0x61fcd974, 0xb7e01b5a, 0xffde045f, 0x7f284c8b, 0xe0e3f4d9, 0xd4079551, + 0xe6035bbd, 0x673de7ae, 0x4084d6fd, 0x5e222dfb, 0x8fb79f8a, 0xa4e3885b, 0x27eb73d0, 0x7839aa89, 0x00c4136d, + 0xbd200c5a, 0xba5deeec, 0x572a5a8e, 0xa217424b, 0x40193682, 0xc5037807, 0x5e8c0e1c, 0x4df824d4, 0x0dcf2420, + 0x6b22e4ad, 0xaccbd532, 0xe858ba59, 0x92d7354d, 0x3303dc4e, 0x01b63934, 0xecb216ae, 0x1f810a04, 0x5cd22c78, + 0xf7a3d191, 0x3f14d639, 0xc7ac389e, 0x083d3df5, 0x5b634da4, 0xd18fe029, 0x56c83fa3, 0xceb36130, 0x51eadfbd, + 0xee87b929, 0x27a5b138, 0xa7569bc0, 0x0e57b521, 0x7077f237, 0x162373b7, 0x1a31fd3a, 0xe703da7a, 0x81871e9c, + 0x9c86969d, 0x2549561a, 0xb6798073, 0x961db9c8, 0x8f24f471, 0x8cd3388c, 0x00a79e0c, 0x3cdf4525, 0xc7cbb2a4, + 0xf0f3f7c2, 0xf575f04e, 0x63e3dce5, 0x18ba3436, 0xf4b7df46, 0xaf0d0b1b, 0x2bada1d0, 0x13afd5b5, 0xdad5ae56, + 0x4efa9517, 0x10d7b66d, 0xcce33d44, 0x9a80b115, 0x06d6cef5, 0x8b72e920, 0x041314b2, 0x280e0cbd, 0x8910e117, + 0xb767123f, 0x8e28e34a, 0x2bc94566, 0x958f8d0a, 0xde400079, 0x9f183a05, 0x972e4ea4, 0x7c888d72, 0x29d08200, + 0x3aa8a6f5, 0x2835f4b2, 0x7d702fdd, 0x746d1b03, 0xdfb4aac1, 0xb0cc46cb, 0xec717cc3, 0x832313cb, 0x88056056, + 0x456b0ace, 0x9350feb9, 0x247916f2, 0x7b48b986, 0x7fecb109, 0x88acde86, 0x28cd278a, 0x5e5e8a71, 0x76bacb25, + 0x86d40e95, 0x9a0979b1, 0x7bed7525, 0x99daf428, 0xc13059bb, 0xb1909f50, 0xe8e5fd53, 0x24bd068d, 0x419573e5, + 0xd5b7e719, 0xb22b3f91, 0xeeeced94, 0x9f580c96, 0x4c99ba4c, 0x91d7777b, 0xd4c5c96a, 0x11e7ce08, 0xde4b47a8, + 0xbf3b4880, 0x3c53b197, 0x1aa1aab6, 0x8ee64b06, 0x3d648ccb, 0x190288e0, 0x2c3a0a1a, 0x62d0a2df, 0x98e8d17c, + 0xe3313b8e, 0x0876be0d, 0x4acbaaea, 0xe7b6112d, 0xfc541eb5, 0xc945ca34, 0x9a6036e9, 0xa13b036c, 0x2a4ebc7d, + 0x0f3595dd, 0x4f617951, 0xb405c84e, 0x982ea3cc, 0x74e8ecbe, 0xc7f5b129, 0x81d78a52, 0x79da65c4, 0x3274c4c1, + 0x9436e304, 0x75aeee0f, 0xb9c74425, 0x69dd46dc, 0x795af121, 0x60287ab5, 0xaa12c8ce, 0x9240c73a, 0xddb153ab, + 0xa754452d, 0x4f0dcf5c, 0x9d681386, 0x46b002d2, 0x73e08679, 0x3761e066, 0x07377dce, 0x91b9a33c, 0x7e62f0e9, + 0x278dd0cf, 0x0dfc0f92, 0xa20eda1f, 0xb71b51ea, 0x5f0961ed, 0x02fd4f1e, 0xf128be8a, 0x326555cb, 0x318bd945, + 0x7f229241, 0x80405bec, 0xfcb389c1, 0x4747e6e1, 0x5eb6fb21, 0x2ed6cf16, 0xacb498aa, 0x0ec35446, 0xc68d79b5, + 0x4b3fc1ba, 0xd2999719, 0x44129124, 0x1d2b4cf5, 0x65ff22b4, 0xc66de5e0, 0x3c50dd78, 0x223b5252, 0xa2f82279, + 0xc268dee0, 0xe538ce0d, 0xc77728f8, 0xbf7fe3c9, 0xfb3a2b5c, 0x8be58f5f, 0x0cc5f6a4, 0x7e103283, 0x85cec3da, + 0x622eaa15, 0x50b28854, 0xe58e07ed, 0xdc49eaa8, 0x2d64f76d, 0x56591240, 0x7ab2a1cf, 0xe299e584, 0x0c4dd256, + 0x39393573, 0xfd5bb565, 0x038e27e0, 0xa61fbca1, 0x1cddffa9, 0x218a4d3f, 0xb43daec5, 0xc1fe1c24, 0x6e1a8e65, + 0x9de9799f, 0xed1202c1, 0x7919a3b5, 0xa32cac6f, 0x2fc9678c, 0x6fa8fa1b, 0x57e6bc3b, 0x4a19c842, 0x46ee7078, + 0xb52c3dc7, 0x1207d61a, 0xea3e19c7, 0xfaeaae97, 0x4fa7aafb, 0xd7903b59, 0xcfe7d5a8, 0xe9ebae9e, 0xdaa0965a, + 0x6973fab4, 0xe84f34fc, 0x2361ec85, 0x7978759b, 0x548b48f0, 0xe021560a, 0x07b4ca67, 0xa8a30eff, 0x1ba69007, + 0x393ef646, 0x3c13ef1b, 0x975560d4, 0xd10755d8, 0xf94ab576, 0x5414c897, 0x7ea14f5d, 0x0b2a8e53, 0x498b5dd8, + 0xfcf1f1d6, 0x8f0d8191, 0x9f95f929, 0xb97afad1, 0xdf4b56c4, 0x4ee06836, 0x243def9c, 0x366f6c7d, 0x9bd97de8, + 0x0c0a6844, 0x099ac409, 0x1912b641, 0xcb8f9ca3, 0xc2dbc49e, 0x5a114a89, 0x3634ce90, 0xf93dee76, 0x6ad10e9b, + 0x4452ef89, 0xe7d8ec12, 0x0622efdf, 0xe7e94cd4, 0x1a27dd83, 0xa40459f8, 0x91eb94cf, 0x24f2816b, 0x85bf3f43, + 0xbdb24bf9, 0x02656c9a, 0x3c70f231, 0xf74fee99, 0xf3aeb1b9, 0xc11b5b53, 0xfaf9ceb2, 0x4c9d4bd5, 0x1df770f7, + 0x6080046d, 0x5c2fe78f, 0x07c5be1e, 0x044128f4, 0x1d9eb98e, 0x1a01cc75, 0x0ba83f5d, 0x31e9e766, 0x6e5287c0, + 0xc1dd6344, 0x47ba2771, 0xa2d91f13, 0xfab44f76, 0x49a253a8, 0x2dd405cd, 0x0f43c7be, 0xcd23e9fc, 0x78f09588, + 0xffcc38ae, 0xc35b6048, 0xd31bc972, 0x4ce20f4f, 0xf06acd74, 0xb7c9ad51, 0xec70c23d, 0xf815aee7, 0xfeb07ddc, + 0x3f350f70, 0x98e13048, 0x46649294, 0x1d353c1c, 0x16b48c59, 0x7af8da6e, 0x44a18964, 0xb6604788, 0x4147389d, + 0x05b18a70, 0xbe335c16, 0x1d48a8ee, 0x7e85d1b6, 0xf70ecf36, 0x799b735a, 0xb5d497ca, 0xed094ad9, 0x848cfb98, + 0xff9d9897, 0xe0b1aadd, 0x251bd382, 0x30ca88f1, 0xd9c8bb37, 0x6d049676, 0x4252a6de, 0xd2f24954, 0xa06f6116, + 0x8c2365e6, 0xf69b4e39, 0x28714686, 0x00c90112, 0x38498711, 0xc203339c, 0x46dc2925, 0x11441440, 0xce174633, + 0xccc4f466, 0x50e961c8, 0xe0ed1a97, 0xde9c36f8, 0x215f375d, 0xdccf956e, 0x4de50f6c, 0x5e3a1e38, 0xd4c9eb59, + 0x46ef4493, 0x8730b064, 0xa4683270, 0x593f0ffd, 0xf84a3a0f, 0x624332ec, 0x075730d6, 0xb8b3a326, 0x4301adef, + 0x2007eb6b, 0x2907bc09, 0x96edce86, 0x2816c461, 0x4c3c037d, 0x3247ada8, 0xd86f0fe3, 0xa2a61229, 0x4d1ccc6a, + 0xe12498ab, 0xeb3ea4a0, 0x4ade4ea0, 0x81b43e51, 0x37b206f6, 0xe7853346, 0x4b2c9487, 0x321db31c, 0x85f629aa, + 0xfd9a26ef, 0xbb95e183, 0x4f7c6724, 0x3807357a, 0xaf7d9028, 0x09c4e92b, 0x156e2da6, 0x0b19344b, 0x1349a2a8, + 0xaa2edb4f, 0x5a2ce483, 0x5101369f, 0xb6c47d28, 0xc1557d1b, 0xe2852f1a, 0x31debabc, 0x489dfa3c, 0x2e064c31, + 0xec2a258d, 0xeb4f91de, 0xf863b2d3, 0x536da591, 0x8953b6b0, 0xb02f2166, 0xda6c4153, 0xfc459cb7, 0xc0c6b6af, + 0x3e823294, 0x06c38b58, 0x9a0229ee, 0xb6412f56, 0x65a7255e, 0x5259c343, 0x6c08c4e6, 0xdd3dc7c1, 0xa34a2d78, + 0x4e546b8f, 0x3975d17b, 0xb1b632ce, 0xd89ff225, 0xefc62d0a, 0x5628ab3d, 0x949fbd4c, 0x40bc38c9, 0xdbfa8dd2, + 0x8b60206e, 0x22c595fc, 0x56f762e8, 0xe715dceb, 0x391ad7df, 0x09481dd7, 0xe21d69ee, 0x6417cf50, 0x63fc5800, + 0x8d03ade3, 0x292bb050, 0x1307e431, 0x4882dce9, 0x6389f576, 0x4a10406f, 0x1da4f7e1, 0x519d8574, 0xa101377f, + 0xc603fa6f, 0xf84be7c2, 0xd1ac5280, 0x4b9cb36f, 0x73952bfc, 0x77981672, 0x24bda150, 0xb2e7b6fe, 0xf5277e45, + 0x5271c554, 0xeeb7fb5d, 0x8f364b0a, 0x25ba4076, 0x308e6490, 0xe3a24789, 0x01afa0cd, 0x73b8d87b, 0x5daf39c8, + 0xb3bfd21a, 0x4c5e6b9b, 0x0d9a9187, 0xd831af90, 0xd87cabde, 0xedeef317, 0xa84cf7e0, 0x54abe3e2, 0xa5bdf132, + 0xa699f90f, 0x906d946e, 0x7b4aa6ad, 0xcf151917, 0xde3bb82d, 0x9fbd42b2, 0x63ed7d9a, 0x9b7f08b7, 0x3a62be02, + 0x8eb49b69, 0xfe7d58f4, 0x182bd261, 0x6a33586e, 0xce8e797e, 0x22500196, 0x94bedfa9, 0xbeb0abdf, 0xf0065e6c, + 0x88f74dfc, 0xa23eea6c, 0x15d85a7c, 0x73e16ec2, 0xe6f159df, 0x57498405, 0xe6619fbc, 0xb12f0104, 0xa42528df, + 0x15c37fce, 0x71c53fcb, 0x560109a8, 0xbd008557, 0xbb7fd70a, 0x7627cf2b, 0x4ec3d8ca, 0xbe00fba5, 0x430a6c33, + 0xb9ad9d16, 0x7cb6458c, 0x288745c5, 0x5e56e7ea, 0x7df7218a, 0xb1eb9a24, 0x7859728c, 0x3bcf6978, 0x4a058392, + 0x1976cd35, 0x984cb573, 0x551ea1bb, 0x17ae8115, 0x7fc80d9c, 0x3e53d86a, 0xce8e9dd8, 0x70e4883d, 0x5cefd6c2, + 0x4f20c462, 0x3a52a7c3, 0xeff3abfa, 0x0f234d49, 0x7729828b, 0x029ad7e2, 0xd0035758, 0xbd8c70e1, 0x849625b4, + 0xfde21d93, 0x12bfa138, 0x4201e043, 0xbdf4fba4, 0x16b0dfe7, 0x991aec31, 0xf7699c43, 0x854be22a, 0x50e8be7e, + 0xc4ac01d7, 0x3a6825eb, 0x4adda235, 0x412fca72, 0xfdd7aaf9, 0xe988a953, 0x7021c1dd, 0x7e4f4d80, 0x21db48c8, + 0x41edfce0, 0x605388d8, 0xa3d99fef, 0x4ebf1925, 0x7ae15ccc, 0x6c120f52, 0x64bbff64, 0xc8b92099, 0x40651e61, + 0x1873af36, 0x36b4d447, 0x521ef201, 0xfd326876, 0xf2392671, 0xcd8524f7, 0x58f785de, 0x9c6953f9, 0x5c8e5a28, + 0x62c26bf6, 0xb1d51779, 0x2ce04e0e, 0x1eaff693, 0xdee24850, 0x3479f329, 0x998e2168, 0x5dcbfa04, 0x37dd7147, + 0xa1abb901, 0x56dec8e5, 0x627a77c5, 0xeb37ddbf, 0x3a9456b9, 0xc66d6ee2, 0xda8fb0e0, 0xb3072cd2, 0x540c7b39, + 0x5cbf0da1, 0x6e968a3a, 0xf8e31da5, 0x32760e2c, 0xb72aba7a, 0xb41825a0, 0xed4b1f5c, 0x8d1b9367, 0xd9d7a4bf, + 0xf0796760, 0x474ebf7c, 0x86165d01, 0x29817c53, 0xfa099a58, 0x48627104, 0xa6ad6f82, 0xa1ea723a, 0xc9591315, + 0xff947e86, 0x75de44f2, 0xb87ce2b9, 0x571506fb, 0x2197e3e6, 0x0c901ad7, 0x05fcefdb, 0xf8693b09, 0xd5638286, + 0xbccf1b38, 0x44bddade, 0x5dac2af3, 0x9edb297d, 0xe60b1b83, 0x71a7f7bd, 0x17143b7a, 0xed4605c8, 0xdda54bdc, + 0x15c3cdf7, 0xa30e4926, 0xc4ddbc37, 0x1d02bc82, 0xff29cf48, 0xbcde4f5b, 0xee7eb7dd, 0xbd6890e8, 0xfc6f3f08, + 0x8543ea64, 0x65979027, 0x3a37ba90, 0xd9281acf, 0x24c2f0b7, 0xa0fa1f56, 0x0ec733ff, 0x16fb404b, 0x5c6972cf, + 0x556e6131, 0x8479cbf6, 0x66d3cf30, 0xcafd32a9, 0xf082c5a1, 0x331ae4ce, 0x6eae8e41, 0x1782b6a0, 0x22602cd8, + 0x4480e6a1, 0x90a4852f, 0xb70c94f4, 0x68f2f405, 0x3eac4d87, 0x79ff5c52, 0x21df3589, 0xed9e7846, 0x37b1f2a7, + 0x101a276a, 0x095084d5, 0x1d371480, 0x01af4aed, 0x0fc957b2, 0x6622b53d, 0xb5111a1e, 0x36ff9bda, 0x16614329, + 0x602529f8, 0x4b73aa69, 0x07a70f5a, 0xeb084040, 0xb45da111, 0x038f5de3, 0x19506dba, 0x25ba5c67, 0xedbdc0d2, + 0x1aaf6e07, 0x13d19f66, 0xd951cab6, 0x2ecc0b85, 0x5a4ded61, 0x4c4992a7, 0x60afa8bf, 0x068af72d, 0x3d9700b3, + 0x8cc4fcfd, 0xeccf1490, 0x8a764f2e, 0x50029ee1, 0x02a3574b, 0xdf942e63, 0x57cd4345, 0x23055927, 0x1ceea148, + 0x0500931b, 0x3d4c62a5, 0xf4bf45fc, 0x1ea8a82b, 0x48582dd7, 0x8b0e0a9a, 0x3544d097, 0xe1d99e98, 0x256d3f33, + 0x4d0f98e9, 0x29b40b51, 0xfbdd838b, 0xbbc4d027, 0x023e7536, 0x59fec4e2, 0x2d32113d, 0xa126d859, 0xa2c0e49c, + 0xbc3d22d9, 0xf7f3765c, 0xea52b756, 0x24a78dc3, 0x720fd0b2, 0x96158a0b, 0x42300b21, 0xda87d4d8, 0x9db29775, + 0x19e91cf3, 0x3616a782, 0xa0899dfc, 0xe941fd7b, 0xd7b88d2b, 0x3f31de49, 0xee36e7ba, 0x99629ca7, 0xe3f7f8e0, + 0x96809f04, 0x421c2a5f, 0x1edfcbd3, 0x2bdb6f96, 0xebfb9d70, 0x8727597c, 0x7bc62872, 0xe024004c, 0xf66c2616, + 0xbc8ececb, 0xe69d1455, 0xd96a4f4e, 0x5a3e204a, 0xe4e5c7a6, 0x5ad03335, 0x2e1836aa, 0xbbd18642, 0x7d09a9f8, + 0x8f013ec8, 0xe7f60ce8, 0x693d78d1, 0xccc9fd3a, 0x47121304, 0x8cef644d, 0x69191110, 0x0e540775, 0x9c786373, + 0x45faf896, 0xc1a09637, 0xa0ae31c7, 0xb8802f21, 0x390b9bce, 0xcc67cd73, 0xffe5e5d5, 0x22d453e3, 0x95c32acb, + 0x49cff1c4, 0xf2855e81, 0xf493a09e, 0x05154772, 0x98ae7a32, 0xa6f7aab2, 0x7446bf01, 0x417f0ca8, 0xee6a9212, + 0xcbdcbd05, 0x43294dc2, 0xe6c876f2, 0x1f3ac15d, 0x29c7a6bc, 0x92ca5e60, 0x95ab4601, 0xb43a4c9e, 0xd11b6134, + 0xfe240c4c, 0xb990ee0f, 0x45690a80, 0xe58e5e09, 0xf7b08381, 0xc3e01809, 0x740e9795, 0x92359b40, 0x53a35c05, + 0xb4e60863, 0x2ffc51df, 0xb0361e64, 0xd6295e18, 0xf5956648, 0xec43c9f8, 0x2e912434, 0x50955491, 0xc022d954, + 0x7153a2d4, 0x1e315c27, 0xb2c7d941, 0xe9f4de9e, 0x63501a11, 0xbd13ee68, 0x7cd41a22, 0xf4979cf3, 0x0fa60eb1, + 0x63244614, 0x8a9b3928, 0x6166bc8e, 0x076dab3d, 0xc471c30a, 0x0f1b4e1b, 0x2c79d1e4, 0xf0c0932a, 0x5b4b549f, + 0x018d8e46, 0x6f7526b1, 0xfd0463ec, 0x75399969, 0xf0783772, 0x684a6b94, 0x336cd87b, 0xa007b8c4, 0xeab1f3db, + 0x2200fd56, 0xff6dca47, 0xef664c04, 0xd6247db2, 0x87ec4089, 0xb3a3953d, 0x6f5bf44d, 0x1a943165, 0x127ade76, + 0x3fb61423, 0xcbb424e0, 0x5a76e481, 0xb6f8111c, 0xea30afdc, 0x8d431c8d, 0x7515f341, 0xcb8d8b48, 0x98137d12, + 0x2bc1c9dd, 0x6c17063d, 0x9dccb02a, 0x0ea834a1, 0x19b7599e, 0x0af38cec, 0x117e1fc4, 0x03ad449b, 0xb5eca8ee, + 0x5821f4ed, 0xaeee43bf, 0xd87eea83, 0x6c99ac8d, 0x8654af40, 0x5573d99d, 0x9ac5b941, 0xe78e04b3, 0x45e215a5, + 0x2cbdf329, 0x3e297d01, 0x929ddf8c, 0xeb6fa43b, 0x0880af13, 0xe8314374, 0xf6b4c848, 0x9d3a4b93, 0x8d7979e9, + 0x13967b61, 0x273e9a7f, 0x4835f722, 0x480851b8, 0xa475b965, 0x5db48010, 0xe64b3339, 0x4066c245, 0xa9d53869, + 0x3045bc46, 0xbd013561, 0xa9f70bbe, 0x1c04ded1, 0x2c7a6d04, 0x03eb5a3a, 0x0612bdb2, 0x0e7c57f7, 0xd181f8e9, + 0x5c8edb20, 0xca38a70b, 0x8503ca44, 0x4737f7b4, 0xf65c6a8e, 0xa67f128b, 0x5e2027b4, 0x4bb4a7be, 0x4ebefafe, + 0x6b5e3e46, 0xe9a91608, 0x35158435, 0xc9440e80, 0xf809ca85, 0x54499dc6, 0x76014a50, 0x74089f79, 0x5b7d67e6, + 0x3f09cb6a, 0x5cdabaa0, 0x18ba9afe, 0x1ef62ca2, 0x882f6748, 0x1978a240, 0x6d7ca72c, 0x2f94823e, 0x8226c84a, + 0x33a74ce1, 0xe1e71bcb, 0x78441f75, 0xbf6ee5f7, 0xdd0bb499, 0xa355e279, 0xced6c56d, 0x315d8b3f, 0x09c7c0b9, + 0x07c88337, 0x95ab5dc9, 0x1de88b07, 0x8a01f7ca, 0xcf852502, 0x6a0931a4, 0x71e8e7c9, 0x3ddf67d3, 0xf0b949bb, + 0xe62a4a54, 0x34e5e4f4, 0x7472ba92, 0x191431c2, 0xe8f8bb37, 0x64e9ebda, 0x3b99c31a, 0x25a28454, 0xc5ab4e77, + 0xc4f6aa3f, 0x3851a635, 0x3c3ee7a4, 0xaf88d4f5, 0x705a9fe3, 0xd5145388, 0x0d3cce73, 0xca4f3436, 0x4b957400, + 0xd1ad2865, 0xf62737c9, 0x1f904dae, 0x87a1dc11, 0x99c9dddb, 0x038ce7a2, 0x15b1c17c, 0x8efac663, 0x8fff9d18, + 0x60cae647, 0xdf5dfe90, 0x24c62505, 0x0abb6bef, 0x4fb34380, 0xa7956ee1, 0x5f4333ff, 0xb35a62a8, 0x11bb4c1a, + 0xa8cd3ea7, 0xeb6e0760, 0x26a2aaa1, 0xa77cd4e5, 0x70287164, 0x68b448e6, 0xb630797b, 0x87313edf, 0xe8c67ed3, + 0x32fa0223, 0xff64af3b, 0xbd4623fb, 0xa4d87703, 0x6e15b266, 0xdde38f82, 0xe8926a48, 0xabaced74, 0x8f009fad, + 0x1707bf02, 0x8c9c8912, 0x67152481, 0x967e4754, 0x0293c90e, 0x849e4074, 0xb2dfcb71, 0x91ecb0bb, 0x18fbfa22, + 0xe651bde1, 0x4d68c06e, 0xf1c63890, 0x9a8680f5, 0x0d1ae837, 0x4617f536, 0xb7b17a9b, 0x42db3eb7, 0xef25656a, + 0x1fd36c05, 0x447e6344, 0x1907f3ed, 0x4ee6418a, 0xab13dfaa, 0xc9f8a4e9, 0xfaddead2, 0xe51896e8, 0x73506060, + 0x19b8bc8a, 0x8c3bc2e7, 0x1f5192c2, 0x6ac523ea, 0x9f41b082, 0xc5219ebe, 0x96fc5c8c, 0xbb6669f9, 0xcf508d0f, + 0x558c7a57, 0xd4c7cd7f, 0x25834d8f, 0x7bf00fc4, 0x0b292793, 0xcc674d29, 0x818551b3, 0xf7eadce0, 0x0f2aed5a, + 0x9e1a5558, 0x6242462b, 0xce6e1d09, 0xbf8d52dc, 0xcf1ae8c3, 0x9f12e0a7, 0xd4132539, 0x656d7ab3, 0x6a079166, + 0xa0f1524a, 0xfb611ea1, 0x8dbb35fe, 0x1ddc654f, 0x9a7f6dcc, 0xcc99fa56, 0x378e35e6, 0x52999e19, 0xdc425a93, + 0x1a1dd404, 0xc957a84d, 0xb1a7298b, 0x0b8e835e, 0x489a4d1d, 0x64c02698, 0x9c7b834b, 0x1f02778f, 0x8e356038, + 0x6097e270, 0x2e60cf20, 0xdb374420, 0xa0f336b4, 0x68f59afb, 0x62294d83, 0x2c5b7853, 0x9b2c8000, 0x3469d50e, + 0x2e3462f0, 0x649d3951, 0x1c9a7024, 0x080f593a, 0x7d0a0c1d, 0x55f22b00, 0xaf58755c, 0x489d26f7, 0x1a6a7d44, + 0x038de53b, 0x0124b030, 0xbe21dfe7, 0x28ef0ae6, 0x3f69eeee, 0x013bdb78, 0xdfef4491, 0x06bf5994, 0x24c33d6a, + 0x2ae1734b, 0x49a9ce12, 0xf99ba5ff, 0x5cf34817, 0x185d58a2, 0xd12bedef, 0x02d11e39, 0x9d7a29c0, 0x565f3478, + 0x7247245d, 0x18aedaa8, 0xfd880faa, 0xa99eb5ab, 0x6a86ef25, 0xa23f02e3, 0x36a6f386, 0xffa060c4, 0xceafa0c3, + 0x366ec2f2, 0x06bae9af, 0x123066cf, 0x010ae022, 0x4c14e268, 0x9b646942, 0x51178f7d, 0x58253c4c, 0x2b435272, + 0xac914b2f, 0xde6c2db9, 0xd7736c86, 0x2c5e6ba3, 0x26fb0396, 0xa4b68027, 0x44ae2b81, 0x0b63a8e0, 0xe2d42eab, + 0xd97c1d73, 0xe6d9bfa5, 0xa992d369, 0x0bc0a7ef, 0xd384f80b, 0x8cc619cc, 0xd3c6d881, 0xc0fbd817, 0x77d891d6, + 0x7a97d906, 0x30d361ac, 0xa46b790a, 0x8766133d, 0x2bf8b02f, 0xd58378af, 0x7a506091, 0x0e418459, 0xc596714d, + 0x0dccec54, 0x06d3b026, 0x60c83353, 0xfdd8f3f7, 0xbbc3c2d1, 0x2ca22693, 0xe514c7c8, 0x33270ca3, 0xed15334d, + 0x33215127, 0x96357a65, 0x4461412b, 0x52c7926f, 0xc744a581, 0x0125fb35, 0xf4e2b870, 0xcbb853a3, 0x948d1617, + 0x08f86d76, 0xffd0a8c4, 0x0345a7d3, 0x2d57483d, 0x08ec4356, 0x64e6684e, 0xc422ebe6, 0xdcb072cc, 0x405084f2, + 0x3b2e4d26, 0x39fc8f15, 0x6522a065, 0x5ca0c248, 0xb811dc65, 0x626fbbef, 0xb3b65c6e, 0xd4c47f06, 0x86c4d889, + 0x49165be6, 0x03455f7a, 0xfc5200e7, 0x9223e56d, 0x5ddf2e62, 0x9c3b583e, 0x98e46f8c, 0x9d1330e6, 0xe782b82d, + 0xd813777a, 0xc484b7ba, 0x856561af, 0x4e7d549e, 0xc381357d, 0x2d7ab3df, 0xc57d30c7, 0x478c4c4b, 0x3a039009, + 0xf5eb8739, 0x6ec52f4a, 0x361f0de3, 0xe7210d68, 0x6837455f, 0x6629ed0c, 0x2a1fcc8a, 0xb932d7b5, 0xb5c7e858, + 0x7fa07fcf, 0xa2986dd0, 0x979ca524, 0xed9b4732, 0x650a603d, 0x953a8a21, 0xda91406e, 0xd05e157c, 0xf61313cc, + 0xeeb26de9, 0x0fec35e2, 0x6fe3a675, 0x54a6eea4, 0x1bb1e935, 0xddd1a91f, 0x9673683c, 0xeb0402d8, 0x41f9bcc4, + 0x6dc92ffb, 0x9e69d2d2, 0xf090b7f2, 0x170de959, 0x2bedc6f9, 0xb1c55161, 0xf81f6a05, 0xe23e87a4, 0x18f63b79, + 0x7cefe490, 0xfc70d207, 0xd4368ef2, 0x8ffc57c8, 0xb4798ec1, 0xfeb3914d, 0xbbcd297a, 0x5daad7e0, 0x43984f09, + 0x0e5adbd3, 0x95f7b4e2, 0x67de49aa, 0xeaa75700, 0xc6dcba36, 0x96ac5fe7, 0x631f1eb7, 0x1ce54c89, 0x990a8078, + 0xde0ae869, 0x84083261, 0xa5eba1fb, 0x45606b6c, 0x5885c584, 0x697c9243, 0xe563a503, 0x1595fc7c, 0x9463b759, + 0x5e667e1b, 0x4b098e15, 0x51f0498c, 0x049513ab, 0xce5101e6, 0xbfe78654, 0xc4a42188, 0xa7f0db0d, 0x911ab3b5, + 0x7d4d7ed7, 0xa5404e00, 0xb58586de, 0xd68e8e0c, 0x2d8fc2c2, 0x4bfe3ade, 0x5842f586, 0xf8b3e9b9, 0x668e4a83, + 0x11b5d051, 0x47281ec8, 0xd3bbb812, 0xa47a026d, 0x2c275ab1, 0xeca6b855, 0x5e5b983c, 0x22f775d9, 0x2ec28e55, + 0xfbe9aad2, 0xb98a9d07, 0xdfb5c60e, 0xb8d01cb4, 0x271f4c93, 0x61b44a0f, 0x8249bc1c, 0x5096982c, 0xaa3e4317, + 0x94f0003e, 0x7391ade1, 0x330e698c, 0x9478302e, 0xe7182456, 0x5988cc2d, 0x013e0fbc, 0x22eb6d40, 0x0d5dd3fc, + 0x4195a512, 0x57ff560a, 0x2cb78625, 0x49b24a09, 0x844d6196, 0xf32bafcb, 0x12ce434c, 0x00eb3f5f, 0x31063c86, + 0x47c97b1a, 0x18e4e7bc, 0x4ddd7f3c, 0x90c0bd21, 0x1c58194b, 0x8a8a3547, 0x3582e0e1, 0x3f817533, 0x97e8c7ad, + 0xc8716cb8, 0x20f59744, 0xe47e742c, 0x3993b6ed, 0xa5816a59, 0xca947c80, 0xe2148a0e, 0x66bda88e, 0xff37e0b7, + 0xccb089a7, 0xc1a31b4a, 0xb523a265, 0x1370e6cc, 0x6874cda0, 0x9e36f7c2, 0x7d16590a, 0x28618a63, 0x69c62789, + 0x560277d8, 0x9f2c9f7f, 0x4ad05b40, 0x072ea1b1, 0xdd8824f2, 0x79d178be, 0xf832f401, 0x98860b5d, 0x7fc59b00, + 0x04a9a67d, 0x3643dfe6, 0x07583c5f, 0xf9e53213, 0x82cc89a2, 0x9aec2336, 0x5ee9fc90, 0x8eb3b412, 0x5cb4567f, + 0x2353b8ef, 0xc19e6b24, 0x975ce62a, 0xf10abc21, 0x1c3e845b, 0x553022aa, 0xb3bab186, 0xc1def70d, 0x961290b6, + 0x126c14a6, 0xa626a67d, 0xa4e4eb8a, 0x5b157811, 0xa435fb2a, 0x809fcbd0, 0x6154f3b6, 0xa6128f60, 0x47a2bd1a, + 0xc9d00ad8, 0xfff37f66, 0x2038039c, 0x27454193, 0xa243016d, 0x0f9774e4, 0x566dd935, 0x918d708d, 0xe5ad53a3, + 0x0259d33e, 0x40289c4e, 0xe36ae87d, 0xe7a60614, 0x0bce9bf0, 0xe7f71a8d, 0xd3b75463, 0x643bc003, 0x69bfe35d, + 0x8e523358, 0x0cc37c4c, 0xfb9420f1, 0xcbbc10a5, 0x35dadb99, 0xba9a16ca, 0x31e0db74, 0x29438f12, 0x4eccf27b, + 0x37e15fd0, 0x7a054f9e, 0x7389dd8f, 0x09fb2dea, 0x3758b188, 0x0c335d9d, 0xb4ba2f96, 0xc8bcebbd, 0x719b9046, + 0x2bc353ba, 0x2cd60776, 0x1ebe74c2, 0xa4522373, 0x6433c7e4, 0xb0b8fc82, 0xe6990f8a, 0x659ca79c, 0x4a65613a, + 0x4ac898f2, 0x3e59adf4, 0x99bfb9b5, 0x48b23d08, 0x03e9137f, 0xb767cd88, 0x664d95cb, 0x1bdc2e8b, 0x3c4c472a, + 0x261cf42b, 0x778410ed, 0x07a58569, 0xfefcc86f, 0xf6e9d7f7, 0x8a573801, 0xd9608d90, 0xa48fb6f1, 0xc660415f, + 0x132aaae4, 0x1ef9a04a, 0xf0389649, 0x95b874c4, 0x2d714ef8, 0x7b270037, 0xd0567859, 0x75ba2c30, 0x20778af8, + 0x8ea781fd, 0xc20f2875, 0x3e3eb940, 0x38cf6d84, 0xc4879e1f, 0xcfaab5f7, 0xfd515dc3, 0x425d39da, 0xffb504eb, + 0xe65b3ac5, 0xada5d346, 0x88a2fe77, 0x8c1dde0d, 0x19174d8f, 0x6482f6df, 0x9cad62f7, 0x95703ad5, 0x529f4649, + 0xc7874e6a, 0x95d36b93, 0x0202d456, 0xa4a85da1, 0xb20016c0, 0x62c24393, 0xf55080ce, 0x8d238c6b, 0x5db3a58e, + 0x6e69d632, 0x388de1e1, 0x7273f49c, 0x5e4aa3c3, 0x3a7a1d3e, 0xb94a8aa2, 0x18e28aeb, 0x2f9ac0e1, 0x6ce54feb, + 0xef7ed468, 0x74965e39, 0xf00f483f, 0x9ce4450b, 0x4b8cd858, 0x20cfd868, 0x53883f8b, 0x62bcf1aa, 0x816b688f, + 0x4d447078, 0x4b404978, 0x42163937, 0x23cb14c5, 0xe138e788, 0x61b8b0a0, 0x44e992b3, 0xb97b252d, 0xa3fcd3e4, + 0x030f9377, 0x7d9e1a05, 0xa624fba0, 0x2bb8f92c, 0xc9910835, 0xca9d564e, 0x0e372f07, 0x27e8d4a1, 0x024b03e0, + 0x41277082, 0x0c171f9c, 0x89fac94e, 0x5c285eb2, 0xc05bba96, 0x49e353da, 0x95f84b35, 0xa540727c, 0xf597e10e, + 0xe70bde0e, 0xdaa2f42c, 0xb08075fc, 0x321ebeff, 0x556f1e6c, 0x11fb7dda, 0x40dbb043, 0xf9a43304, 0xcd56000a, + 0x26637e1e, 0x401a4b2d, 0x2484ec44, 0x979702a8, 0xf34fa09f, 0x5c992f17, 0x2c27f09a, 0xceb39541, 0x42a23103, + 0x297cc736, 0xf95a4535, 0xdba82706, 0xa865ddeb, 0x2b2af7a4, 0x06aaecc5, 0xb95c46d1, 0x2cbd1061, 0x37309ff2, + 0xd5045714, 0xf83da794, 0xdf7495ba, 0x2ea30037, 0xc41271d4, 0x3351a2e9, 0x9a15dd30, 0x830f32ed, 0x533e86c9, + 0xd8cf95ce, 0xc2970f96, 0xb7c45e1f, 0x057ae160, 0xc0d24094, 0x84db48a3, 0x9de555e2, 0x60ada98a, 0xdabff8a7, + 0x0fdfec0b, 0xcc95a23a, 0x803c7c69, 0xe80ddafc, 0x092c7d44, 0x6774fafe, 0xd6384084, 0x7f8db2db, 0x47d2c816, + 0x59ce4754, 0xc67bc2a5, 0x09f95072, 0xc9994cce, 0xf9d031b0, 0x4964df76, 0x293082ce, 0xfe471d6d, 0x50d819b2, + 0x2439906c, 0xad76cee3, 0x000a41c4, 0x6d2da26e, 0x3e9fdcbc, 0xaad13142, 0x452aa9cc, 0xd420bd8f, 0xf741709f, + 0x7b9ddd3a, 0xe69ca369, 0x35bb7417, 0x16c1fb9b, 0x076cd208, 0x194735d9, 0xe78c5c45, 0x5027b355, 0x7b71a368, + 0xd6a31fcc, 0x59f6825b, 0x958cc062, 0x44d5c531, 0xac9752af, 0x0a4f2495, 0x172b6a14, 0x0138e97a, 0xa03a63f3, + 0xdac2d9db, 0x776eeffc, 0x755be8f9, 0x116e2501, 0xf911b99e, 0x5a22ef16, 0xf17c9cea, 0x03bbb87e, 0x03be320e, + 0x1a90b822, 0x8b99efcb, 0xf4b56c25, 0x0ca19ba4, 0x7acdf98a, 0x0d3584cd, 0xc767dd60, 0x56a76bbd, 0x0a3e774a, + 0xcf8c2051, 0x5256f363, 0x66bfeac4, 0x279787ee, 0x6fe47737, 0x3d5d60a6, 0x3869f5a0, 0x943a291e, 0xf9c09a1a, + 0xb5f5dbb6, 0xad6bf314, 0xb0c6e9d1, 0xa3b37a74, 0x1c06de29, 0x3bc96e69, 0xacc6d061, 0xec5d5b37, 0x58070aa1, + 0xd90d8b4f, 0x1fd00d0b, 0x2b593d6e, 0x7c4522ae, 0xe54ed4ee, 0x0457fd68, 0xcab51c54, 0xf69a77ca, 0x3b004986, + 0x5435a28a, 0x962040e4, 0x7080df19, 0xdc3af408, 0x5408b7da, 0x64afd03e, 0x83da1c93, 0x96e503f7, 0x9236d090, + 0x17d99bf8, 0xb686d7e5, 0x29b89674, 0x0956fd9d, 0xada125b4, 0xa0016397, 0xf4fd74f6, 0xb29557cf, 0xb0241a85, + 0x25f8d926, 0xd46110dc, 0xe3f351f3, 0x268815b5, 0xc2a9bd4f, 0x15b7d567, 0xbeae59e1, 0x20067050, 0x8ffd0888, + 0xcf15a783, 0x73e344cc, 0x1a400337, 0x6daeb62d, 0x4043ec42, 0x879d3800, 0x63c7f1ff, 0x7708adda, 0x138336cd, + 0xe03d3cc2, 0xdf67d01c, 0x6af6f82b, 0x593bba4a, 0x80911b1b, 0x24a78aee, 0xb8d51f58, 0xff3acf25, 0xe1f9caa4, + 0x415ac947, 0x7880422b, 0xa8133cc2, 0xa91d0852, 0x8d6408c1, 0x36db5f23, 0x68bfcceb, 0x3d970f1c, 0xbd01a927, + 0x890a2567, 0x878e2cb6, 0x9883db0d, 0xbbc6a069, 0xfbba9045, 0xaf46d11b, 0x62f76238, 0x4fe9164c, 0xae03e2ff, + 0xb69ac1a8, 0x54f76fae, 0xce9859ca, 0x30816f4e, 0xac92e808, 0x638c9a2b, 0x0c88a340, 0x12a15792, 0x053cd2ac, + 0x26867637, 0x937bacec, 0x0197680a, 0xe455d2e7, 0x2b362f54, 0xe4ae23ce, 0x4cac0ec9, 0xd2d2a32d, 0x823a2380, + 0xad80c26f, 0x0802961c, 0x99e2e379, 0x619cf85a, 0x5ac75b1d, 0x32c19e56, 0xf23ad913, 0x5cd14ed6, 0x9a76dca4, + 0x39b71870, 0xe8885ec2, 0xd32f49f9, 0x414608db, 0x3340bbc1, 0x8c832f3e, 0x80b9a18f, 0xf1b82e61, 0xd6f1fab4, + 0x112b87be, 0x669f8fc9, 0xd93ede86, 0xf7bd95aa, 0xcd91e21e, 0xc7aaa310, 0xe61c908b, 0xc55f51e1, 0x07c55ab1, + 0xbcedd2a9, 0x39e624c5, 0x53a25486, 0xb14f6039, 0xf34f6a81, 0xa7f07822, 0xdee96586, 0x6eb3d8f8, 0x18c145d5, + 0xb5f8ba51, 0xd5037ef7, 0x0bbe490c, 0x1204fdba, 0xe7cba92e, 0xeb060027, 0xf6857b1a, 0x421a75b8, 0x54f864e0, + 0xdfa76372, 0x5653303c, 0x190a9f88, 0x1296188a, 0xa282f697, 0xcd3ab733, 0xaad45068, 0xb80284d8, 0x31fdd709, + 0x01c00820, 0x682486f1, 0x806a5932, 0xb7e1f6c5, 0xa9e21bf4, 0xc73fd5ea, 0x3def6f76, 0x561e09a0, 0x242bf6c9, + 0x39c51515, 0xf4d4b7bf, 0x534398a1, 0xcc453846, 0x98d5fe2b, 0xbe476750, 0x71a19c24, 0xab301fb5, 0x538fec9a, + 0x7d7bb49a, 0xd41f2106, 0x892c7539, 0x9a3a9a45, 0x93af9c2a, 0x9b5e9d4a, 0x731c2e73, 0x592cd330, 0x57f1720a, + 0x2b5efc8d, 0x1efc08f8, 0x7a47a485, 0x2cd4affa, 0xfdbfcc4e, 0xe1e8e5f6, 0x2b1005f9, 0xd65dab0b, 0x376efa9c, + 0x98f35f2d, 0x23448055, 0x3ed37a34, 0xa98324e1, 0xd0ebbb15, 0xd5cfed84, 0xc82c6242, 0x9634de9d, 0xa80d9707, + 0x1d86bb87, 0xff83e995, 0x6f2f468d, 0x5343e566, 0xc877c025, 0xe6e2a945, 0x05357e0b, 0x4894c416, 0x8ae7afbd, + 0x248e7922, 0xe11ff250, 0xdada908e, 0xee070b7b, 0x1a57316b, 0x6de4b797, 0x3c34ee78, 0xf970deb2, 0x06090552, + 0x0b904d33, 0x97e7fd2c, 0x27bbcbe4, 0x9e2a8445, 0xd4a7d398, 0x414efe33, 0x60563690, 0xb4e86ab5, 0x03ce8fb7, + 0x0d5bba00, 0x4084bfde, 0x2bbd74a6, 0xddd88b59, 0x14afa941, 0x43e3b5a3, 0xd1eb9fe0, 0x8c053336, 0xac83eec8, + 0x3c4d9e80, 0x82177fa6, 0xff7a43e3, 0x55c4a3cd, 0x53b735a4, 0xdc8d42d2, 0x1726ada2, 0xdef58a01, 0xee52fb81, + 0x877ce4e0, 0xa9e7514e, 0x79e11c8a, 0xcd68870f, 0x61fc86f4, 0x44cff6ec, 0x3f564a77, 0xbd2225ad, 0x3bb2b30e, + 0x6e0a9a5b, 0x68b7ab1e, 0x48b3916b, 0x7b846016, 0x6ee31f25, 0x742d7bc3, 0x54de4f5b, 0x557afbca, 0x55dd5c79, + 0xd97cc7d4, 0x80275a93, 0x61bf6ec1, 0x72dc63bb, 0xdb37c2a5, 0x134e6f00, 0xe5023551, 0x8fef78d3, 0x2a6001e7, + 0xea814088, 0x4bc916fd, 0xc74786dd, 0xebc79521, 0x79815e8e, 0xd6029894, 0xd8726ae8, 0xa663ecf0, 0x8fb1b84d, + 0x01ba8373, 0x995770cf, 0x2ff0c7c1, 0xbe81e8d6, 0x26d88b2b, 0x027e74fd, 0x95eee23a, 0x5646d4ab, 0x78437b0c, + 0x7e405f95, 0x5e34572d, 0xbf4294d3, 0xe412087d, 0xd7a1cc46, 0x39b6aaf8, 0xa65821b1, 0xbd29f8b0, 0xed3d5077, + 0xa7d38795, 0x49543a80, 0xa067beaf, 0xfc159c6c, 0x9682ab9c, 0xf0ff57ba, 0x7f72901f, 0x9ccfa67a, 0x72c84437, + 0x532c1cf4, 0x8629b0e7, 0x7824b3bf, 0x8371f0b8, 0x663e0ded, 0x63b011fe, 0x50d0546a, 0x4c896001, 0x87164c17, + 0xcc5a2575, 0x58ef1788, 0x30eb306e, 0x5ddec629, 0x9418b6d8, 0xab27362d, 0x57f80204, 0x30750173, 0x9b6bcf5e, + 0xe556b9bc, 0xfecc82fa, 0xeeeef60b, 0xb0507945, 0x39bebba1, 0xbcb370c8, 0x547c238e, 0xbc45d535, 0xbdc30565, + 0x9ca6fa3e, 0x2792c0a0, 0x97924a2f, 0xb55b850e, 0xeebd528a, 0x1de5a950, 0xc0d05db1, 0x96bbf414, 0x4a2da01a, + 0xa64dec88, 0x80f94f38, 0xc59960b2, 0xceb760b4, 0xbb7c6153, 0x99bd0675, 0x8a4846bb, 0xc1825883, 0x6380b24e, + 0x47ab56ed, 0x4c624d32, 0x01517a5a, 0x3280db1d, 0x277649dd, 0xcc5c02d4, 0x11ae210a, 0xaaf90242, 0x33012993, + 0xbf1fb8ac, 0xba777663, 0xd6752cd6, 0xa1fe7c3c, 0x6c40ca37, 0x2aa6fea9, 0xcc651c46, 0x729b98a7, 0x82cc921b, + 0x2e9c7083, 0xc7fb4bdc, 0xf78108a7, 0x6c3904c8, 0xe9f2a0a3, 0x2ae9ff76, 0xd13b142c, 0xd448b2ae, 0x9805ab3d, + 0xe4bac505, 0x867f86d1, 0xcb70b037, 0xf1a8be7c, 0x2f1620ee, 0xb265376f, 0x42884648, 0x179b2141, 0xa996c17b, + 0x320c9cfc, 0x0bf5122f, 0x6ed7158a, 0x5158f6f8, 0xb61359e3, 0x56e68690, 0xf90758a4, 0x36d37f46, 0xba37b54b, + 0x1e388173, 0x5f9be2cd, 0xb19d941d, 0xffc0b935, 0xf9534ef5, 0x37aa19dd, 0xc4a11bfc, 0x500642cf, 0x589b2411, + 0x36eed3df, 0x282df6f1, 0x1b6758a5, 0x2dbd5ea0, 0x548fbbfe, 0xb2713265, 0x6014adae, 0xad1b52a3, 0xecf644b9, + 0xc40735d5, 0xce426205, 0x8c930ab1, 0x2992154b, 0x5bc14a77, 0xdd0f7bd1, 0xd436b00b, 0x1ae22796, 0x9b06efc9, + 0x55b926f0, 0x03c93f5f, 0x887cd0c4, 0x93172527, 0x92e11793, 0x00e698a4, 0x8cee50ba, 0x2de10320, 0x1aa2c2ce, + 0xebc90bd6, 0x8eb129c4, 0x2a8ff539, 0x51ba4b1d, 0x0443c845, 0x18b83fde, 0x9dff6a57, 0x57075749, 0x97c8e0b3, + 0x3f742be6, 0x17d2d8d7, 0xa0dc2785, 0x9dca5805, 0xb32c1223, 0x08e22d9b, 0xabb9ec70, 0x18c61c78, 0x0b59dc4d, + 0xfd92c79c, 0xeb56765d, 0xbe17b492, 0x99e3183f, 0x86ece013, 0x5c3515b4, 0xf730caaf, 0x16e8bbdc, 0xdc4cc662, + 0x4cfc8bb6, 0xbb582d89, 0x969f6491, 0x71349a34, 0x053919fb, 0x27eb115e, 0xbe9c6ead, 0x6bbaea2c, 0xd67113f7, + 0x8d513f41, 0xdc9add98, 0x32673e19, 0x21caf7e8, 0x5698cf7f, 0x7108509d, 0xdb4f3be6, 0xd2e4d642, 0xbcee0633, + 0xd63197b5, 0xb90130fc, 0xe0ef3dfd, 0x8e513357, 0x3e7c2213, 0xe0be7d89, 0xecb047b5, 0xc4ccf7f3, 0xdf297192, + 0x38f9ec5c, 0x3e2b0b5e, 0xae2b9ab4, 0x5c897c17, 0xeac830a0, 0x606a498b, 0x0ffaec6e, 0xe275112f, 0x2c40f03b, + 0x8cb5b5f7, 0x035d76de, 0xaf107b2c, 0xc9d324b7, 0x02427e05, 0x3fc89a91, 0xf1e41337, 0x1b97e005, 0x5cbf71e8, + 0xab88a7fb, 0x4e0f214a, 0x8cdfac80, 0x1c152653, 0xbc18ca61, 0x887bdc98, 0x4346cda0, 0xd5b3e650, 0x2498684c, + 0x45abf5c1, 0x2611c510, 0x309c4707, 0xd740b866, 0x20bf1482, 0x5647194c, 0xfdaf58ef, 0x88ffe288, 0x91a36fc8, + 0x58d7fe12, 0x0c3543c3, 0x822861ed, 0xa99d744b, 0x052f9913, 0x0b128cb9, 0xdfd4ef48, 0x7891d341, 0xa68ddf9a, + 0xf3845a66, 0x2622be17, 0x712953b1, 0xb3bbc8c4, 0x181395f0, 0x94f9e340, 0xacc4e4cb, 0xe83c3240, 0x8ab96e15, + 0xe4736719, 0x60c2475a, 0xb48a3f62, 0x8f61bb35, 0x06aac93c, 0xce55a3cf, 0xeb971614, 0x5a01b9c4, 0x5cb4463d, + 0x1612636d, 0xf56102eb, 0xa0ff0fa3, 0xffe1544e, 0xbdb3a6d5, 0x7caa8300, 0x4ccbfc6c, 0x74b32024, 0x8c58f00e, + 0x8706b3a6, 0x819700ad, 0xa964cd0e, 0xc9b81984, 0x6404af72, 0xcbeab2e1, 0xd6799103, 0x0455462b, 0x6c68e9b7, + 0x24478679, 0x80ea8b30, 0xab3053c5, 0xa361004f, 0x69c6e7ec, 0xe73c320d, 0x201c065c, 0xb20fc137, 0x17852c91, + 0x71f6a904, 0x0c6bab52, 0x3aa416c8, 0xd153d1ab, 0x3867a7d1, 0xc1770911, 0x0f380961, 0x471f767c, 0xb7bab985, + 0xae7d9d47, 0xe24fd646, 0xc0360bc2, 0xbe58c9a4, 0x1253c179, 0xb4b06a87, 0x988eb747, 0xe8986936, 0x5a5d755d, + 0x51b7570c, 0x5c785aff, 0x61432170, 0x9cfc9347, 0x2d6c1711, 0x67243732, 0x6430a45d, 0xf085ab56, 0x9665e863, + 0x08e09aa1, 0x06d9f21f, 0x99fbec4d, 0xb414efd3, 0xe54f9388, 0x12d75f9b, 0x39c76674, 0x68b1f257, 0x05b8620a, + 0x2c14dad2, 0xa92a816f, 0x35294e2d, 0xbec16bb7, 0x431100a2, 0x8fea711e, 0xb6895c44, 0xe8893825, 0x76ee369c, + 0xdbd8b7bf, 0x7b72be78, 0x336bceba, 0x5016b8ac, 0x52781154, 0x1cea2df4, 0x8faed04c, 0x598ced0c, 0xe80e0734, + 0x6bae980e, 0x6b4ac23c, 0x5f7bfe22, 0xe83766c8, 0x13e05fa0, 0xbafeba2d, 0x6b59bdde, 0xa5ef7de0, 0x6a1d3b99, + 0xba3464fa, 0x69ab4d42, 0x3c3ae9a1, 0x698b20a3, 0x92ba5bd4, 0x2f9cada9, 0x99a1bc7e, 0xb8eb5734, 0x5c12f243, + 0x2b47c4f0, 0x2c2632ed, 0x7c9da9ba, 0x78603d26, 0x67b93668, 0x355deab7, 0x7d8f521b, 0x593bf199, 0x1484a128, + 0x01478993, 0xea00e843, 0x55e62457, 0xfe66cd9d, 0xb6ba13a2, 0x90843318, 0x94de8cb6, 0xf4039991, 0x67c59a48, + 0xd4317864, 0x112c480b, 0xc2ffafee, 0x8f3b8f2f, 0x552432d1, 0x58a5c280, 0x966b0430, 0xa1fece71, 0xcdbe5197, + 0xdff8e340, 0xa2a5725c, 0xfd937e7c, 0x15d95b44, 0x12818711, 0x4a6d329c, 0xb51fba03, 0xff8d0596, 0x0cf53011, + 0xc5af4fce, 0x70a47342, 0xf52e73fc, 0x8d0dce78, 0xe5bf7738, 0x2d6b3671, 0x23716ded, 0x63ff6bf0, 0xe28b49ef, + 0x6afee243, 0xd8927ec7, 0xc6b8cc73, 0x22075aea, 0xb9eb2351, 0xdcd858c9, 0x1c1e7abe, 0x7ef173c5, 0x9bc533d5, + 0x8efc81d9, 0x53b1ecaf, 0xaf66513b, 0x3912844e, 0xf58f52dd, 0x0c8c1c45, 0xea9247fd, 0x8e5c9eb7, 0x4e4d62f6, + 0xd643167c, 0x040ee7d5, 0xf5dd6d34, 0x78aa4d76, 0x28250371, 0x4a593fe4, 0xa5d26883, 0x076014ec, 0x9129a5a5, + 0x2faffb5b, 0x27f638e0, 0x0b4e5b59, 0x04c89fc4, 0xea33468d, 0x121d7dc1, 0xc7d666bf, 0x0716fd7c, 0xf63def47, + 0x0a051cdc, 0xe839a8a5, 0xf1665ab1, 0xfb44c733, 0xa503d03c, 0x11307a74, 0x76d95fa9, 0x2701b0e3, 0xb6539e99, + 0x6c0bb747, 0xcf21b1cc, 0xaae7ee70, 0x1e955c78, 0x08163f3b, 0x1d651450, 0xf4d96fdc, 0x7dd1ed7f, 0x6ec3f77e, + 0xec3e1592, 0x2e2a03c5, 0xdb50cbd4, 0xc202e0c5, 0x2d3bd55a, 0x3a57a927, 0x85ae8860, 0x5530061e, 0xd09153c0, + 0x9b57ddcb, 0xbc41c565, 0x6812dd26, 0x22617a01, 0xf6e7762a, 0xa6c0139a, 0x6dbab618, 0xdf1ed939, 0xc35d07b9, + 0x48bff68a, 0x29b77cfe, 0x639050ce, 0x8f8dc62f, 0x807c5bec, 0xfab4ea04, 0x9b016805, 0x53aaa3d8, 0x86e1278b, + 0x9abfc645, 0x817a4fee, 0xedd788f2, 0x1b0f3200, 0xf7c022dc, 0xda5e2531, 0x221ba22f, 0x19c6370f, 0x6d9a87b7, + 0xd5d3d3c1, 0x9e68326f, 0x8334c93e, 0x49962198, 0xb5b8a81a, 0x326ab8ce, 0xd0a151d2, 0xbabfe1aa, 0x4ea009b5, + 0x40a3110e, 0x28c52ddc, 0xc25f15e9, 0x0c8a083c, 0x623bac08, 0x952d5963, 0x53c38bf1, 0x1f8292b4, 0xe7871622, + 0x51bdd934, 0x9b53d79d, 0x0ac89510, 0x6cebdd27, 0x7d4d3f33, 0x4e00f83e, 0x0ec1d63d, 0x4db374bf, 0x2e27df27, + 0xcb099011, 0xe2632259, 0x039b164e, 0x8c1505d7, 0x2f988bab, 0x29e9b513, 0x00feb9ad, 0xaab5c007, 0x44de4c3a, + 0xfe965d86, 0x3d9ab553, 0x4881cb8d, 0x22eef16b, 0x4ad23b6d, 0xf76cadcb, 0x914acb56, 0xa68674c8, 0xa014e525, + 0xbdd75eb3, 0xd5e3a937, 0x5358fcf7, 0x55cf015a, 0x5975057d, 0xf85776cb, 0x23dbbfae, 0x66d911da, 0x92cb186e, + 0xd766b8b8, 0x2c9d7d4a, 0x8929394a, 0x3851efc8, 0x4b6f6872, 0x88529290, 0x7d39b779, 0xc5755153, 0x7ec90f85, + 0x0ca2807b, 0x15e847e1, 0x8d8d6489, 0x5be1b5fc, 0xfc1b3e3b, 0x09c0636d, 0x6b805e98, 0x01dfb5ff, 0x37bfa925, + 0x26216bf1, 0x4c7d053e, 0xee488d84, 0x0572f2fa, 0x781c1bc7, 0x6ea0d6cc, 0x199eba69, 0x17ec4873, 0x48416307, + 0x8450ea87, 0xf03c46ea, 0x76eea33c, 0xf6c5fc70, 0x67969424, 0xe102b229, 0x22405d36, 0x0dc73d8e, 0xe63d36cb, + 0xe081e4f0, 0x7c352506, 0xee803cbe, 0x230f9e90, 0xd787f8b6, 0xe4cc0828, 0x0985ff7f, 0x148c0063, 0xcb64fa18, + 0x56f9ed10, 0x9b966730, 0x9e2b075b, 0x9bddb632, 0xe9279526, 0x6ac5830e, 0xeece26aa, 0x3871ce4c, 0x9906cec3, + 0xf7105368, 0x890bd9cf, 0x68599533, 0x16170319, 0xf1340bca, 0x6f8bafe1, 0x570c023d, 0x6f43c004, 0x5b5d405c, + 0x224c3c26, 0xb9c1155c, 0x15ad76a8, 0x6552e203, 0xa200ce3d, 0x555c1f58, 0x91798f8b, 0xf8a9f3dd, 0x2ce7f761, + 0x464bdff5, 0xcddd23b9, 0x474ff8aa, 0x8779025b, 0x051d0575, 0xd2bad02d, 0x83a7fe19, 0xd8c07f33, 0x678daa08, + 0xb9122654, 0x6a300209, 0xf93fad9b, 0x02f8b5fb, 0xbb9a0628, 0x7f2a3057, 0x3bb1cc6f, 0xa94bff65, 0x30c80bd6, + 0x4e202885, 0xebab0340, 0x2e7094d6, 0xfbf3582d, 0xd7e3218a, 0x9ed683db, 0x5161bb63, 0x0b65c1f2, 0x53dcd97b, + 0x2cda5b1e, 0x70deb291, 0xd3d149d0, 0x41f3b6e7, 0x5be3004c, 0xebb4c043, 0xdf3b8769, 0xac6c816d, 0x2ae9fe74, + 0x9d2c8c7d, 0x64614b6e, 0x84e96db0, 0x5a4f4ec1, 0x4100dcd8, 0x1371a4b7, 0x809f7ca9, 0x657cb854, 0x82f2b8a9, + 0xf02d4a4b, 0x81ab90b8, 0x465b6cc7, 0x3b60b06a, 0x4dca08a9, 0xb495742a, 0xaa03f667, 0x124c24b0, 0x4310257f, + 0x7bd09830, 0x1b280d9d, 0xb724817a, 0xf0fe10a9, 0x2b572357, 0x8e1fb562, 0xed39d8de, 0xc4483bbf, 0x283bc418, + 0x70914bfb, 0x4573144e, 0x97459742, 0x536a9e01, 0x2c9afcc8, 0x5fb50366, 0x5b923062, 0x47eebe3d, 0x6056388c, + 0x4cc6d56f, 0x17884149, 0x233e745d, 0x92383a76, 0xa4bff406, 0x85fa42b0, 0x159a992b, 0x0a92d82b, 0x1494d8cd, + 0xbb40e56e, 0x2ed09383, 0xa8aa2345, 0x2f8cc0c9, 0x5dae2996, 0xb9373244, 0xb3c79741, 0xbda87a6e, 0x68c40302, + 0xe36a74cd, 0x4bcba453, 0x462059c2, 0x5e99d8bd, 0x57f17df8, 0xcdb78ee5, 0xd7e82094, 0xb6c4d784, 0x612f10f9, + 0xbcfdec75, 0xf147c465, 0xce8d65a3, 0xb6ea0f46, 0x39100ba2, 0x9fd0c118, 0xd495effa, 0x542e845e, 0xea3b2251, + 0x3633c16c, 0x4f43b6b6, 0x128ceaa0, 0xc099bda9, 0x4f8399cd, 0xc91db5bc, 0x74652a23, 0x3972daf8, 0xff168f4e, + 0x4eaa083f, 0xc004124d, 0xb69247e8, 0x197035cd, 0xd84b63fd, 0xf394c189, 0x3aae1291, 0xd71feef1, 0xa4d4eba1, + 0xcbf2ad59, 0xde6d0e20, 0x6e5bc412, 0xa14cd0fe, 0xa48ec194, 0x3efc4be8, 0x7f0bc40e, 0x8a73cc67, 0x706697e9, + 0x2f8172d4, 0x2b647a18, 0xd6a5fb75, 0xf039ee16, 0x48da151a, 0x2d6c1c8e, 0x500911fb, 0x045a93ad, 0x68cfd0fe, + 0xdd2e4b53, 0xc00662bc, 0x97eae00c, 0xe2f43009, 0x511b8376, 0x9d7fa83e, 0x56cd84e7, 0xd7c89fe8, 0xceab8830, + 0xeb3b54b6, 0xcdde93f4, 0x718296de, 0x501ee7bf, 0xb718824f, 0x841aaf88, 0x1681ecf2, 0xa32ac5be, 0x04283424, + 0xdb4ea854, 0x96a856ef, 0xef4264ca, 0x5cedc237, 0xa7401055, 0x4768f31d, 0x51936ff2, 0x9b21c19f, 0xa62a4ae4, + 0x7dad5436, 0xd6c4f7a9, 0x9b03ec59, 0xb5b9a1ed, 0x0ac355d6, 0xe391aff7, 0x190df33d, 0x057528eb, 0x2e0beff7, + 0x9ff1c2f1, 0x90b50927, 0xac4e5a0d, 0xc3a1317a, 0x19560486, 0x768ceee4, 0xc74c24db, 0x8f140c06, 0x2589442b, + 0x8e728fd2, 0x2918679f, 0x2916c434, 0xaafe7a54, 0x664c6751, 0x675d4cb5, 0x8b8e4b7f, 0x85e22c84, 0x65596ba8, + 0xe992bc10, 0x2b1cffd2, 0x5c59c258, 0x34f7b749, 0x5b9d1dbf, 0x2f1ae075, 0xd37e4a3a, 0x613684e7, 0x86a53bc9, + 0x064526ac, 0x6fc6e86c, 0x60c18206, 0xc34dce62, 0x9a80970a, 0xd7f5d266, 0xee9d9306, 0x8def39db, 0x91d89e81, + 0x93b0bac1, 0xc76030a7, 0xb513a4fc, 0x1e588462, 0x004fece1, 0xa6e1572a, 0x625484f9, 0x9bc934c8, 0xf1296be4, + 0xcc1309f0, 0xd756c47e, 0xaa89dbdd, 0x3d1fd943, 0x0d2a7ff3, 0xf7027c18, 0x5f03e082, 0x287f73b9, 0x71111c4e, + 0x375cbbe5, 0xfd2b9a70, 0x4ba297b6, 0x2d443205, 0xe6b8d263, 0x0bbf423e, 0x4fe22eb4, 0xf030f7b7, 0x6a103881, + 0xc35b3645, 0xe93c6f00, 0xed8b9d16, 0x29bc07a2, 0x4e473cd8, 0x4a097cd3, 0x4796e527, 0xe790c56b, 0x4ccc2667, + 0xd9fa4537, 0xdb4da1eb, 0x0ba02a8f, 0x1192ab04, 0x37300d7a, 0x5c871790, 0x67bdc9b3, 0x9a9e5871, 0xfe8e08c1, + 0x08d02b43, 0x6228fc39, 0x55c6e13f, 0xf7d86f4a, 0xfef01021, 0xb5066022, 0x59d70aca, 0x4b0810f7, 0x8ad932a1, + 0x8920b677, 0xa10c2242, 0x1c07d257, 0x099f9be5, 0xe5a180ce, 0x358f3d2a, 0x364baa2f, 0x8ce34c14, 0x28ec4969, + 0x2a382720, 0x535d3f8a, 0xb1e92b55, 0x5382b201, 0x15696d14, 0x08937dd7, 0x28076b9e, 0xd704ae8b, 0x6a528e7c, + 0x1c1eb74a, 0x01205d50, 0x2d889ee0, 0xe5229761, 0x3dab1065, 0x16d11d33, 0x043966cf, 0x09cb3579, 0x371a91e7, + 0x271d483a, 0xa1f2c926, 0x40802cec, 0x75a74292, 0xc03d37f5, 0x0313bcc5, 0x6dcf6b0f, 0xd86fb7a8, 0xc1b07a66, + 0xc5684b3f, 0x1f8da5f8, 0xc731c3c5, 0xf42c66dd, 0xbcaa75b0, 0x49e92cb5, 0x960a7b98, 0xdf2313b0, 0x6da6d1d8, + 0x054325b8, 0x4869964d, 0x2fb7d1e5, 0x0a33e4bd, 0x808cfb94, 0x0833b9a0, 0x14ca2e29, 0x4f33286a, 0x9a7fa32d, + 0xfbc7b107, 0xf6d34380, 0x21ee071d, 0x550c10e6, 0xb03e0188, 0x214fdd24, 0x880c8ad8, 0xff58836d, 0xf4d013ce, + 0x3be1756b, 0x2fae6a70, 0xd3ad09b5, 0x711a6744, 0xb38fa300, 0x7293a9ac, 0x67561ef8, 0x4cb547c1, 0xa7947dd6, + 0x8a8242a1, 0x912b6195, 0x8c457afe, 0xd5c50e08, 0xd240bbce, 0x801f3d66, 0xac3b4298, 0x9a0eb2f7, 0x9937c1d4, + 0x4bf227a5, 0x8b6c5818, 0x1be343b4, 0x197dba5a, 0x81a04abf, 0x966ab92f, 0xb0c2868b, 0xe3ea4ca1, 0x90b3a160, + 0x943d074a, 0xd2bd6fef, 0x0802a0ce, 0xa4bed37c, 0xee050d94, 0x9cd176e3, 0xc59b2636, 0x6f1d0821, 0x04bdc1cf, + 0x0d3a1704, 0x2bb4fa18, 0x58900d40, 0x72c28883, 0xb5a832d5, 0x868a023d, 0x82236ae8, 0x13dd9c81, 0x41a1d717, + 0xa2fa4ac4, 0x05e0d35b, 0xa7acf17c, 0xf43018be, 0xff4ff375, 0x4cd420ff, 0x2c8696a6, 0xeaf3fad0, 0x30ce63ea, + 0x4c647eff, 0xfba0a3cd, 0x96398e1e, 0x8267cf2a, 0x894af070, 0x2f180d28, 0x36a36607, 0xe64986d9, 0x572eb355, + 0xdb572455, 0xa24aca5f, 0xc264002f, 0x5c8ffaa4, 0x49009288, 0x1fabb456, 0xe572e3e1, 0x87caaddf, 0xc04bfe72, + 0x198c26c9, 0xdc8a5b18, 0x0cf6fc0b, 0xc34a5968, 0x2264e64b, 0x47d24a1b, 0xcebc201b, 0x826081ae, 0x0d6283b0, + 0x6e6e9123, 0x4b5ba658, 0x6e8754aa, 0x59c9c319, 0x597b92c5, 0x2640b2df, 0x3bf20ea5, 0x52f10d53, 0x70b2ac43, + 0x0bac79db, 0x4cafb7d0, 0x11d6e7de, 0xef15b8c1, 0xc7023d3a, 0x991fe71e, 0xb5a6bf08, 0xaf3383cd, 0x2c82591c, + 0xeb23a8e5, 0x00654cb7, 0x6ef3ee91, 0xe933734a, 0xff4f518b, 0xfdf9b67b, 0xe98b369f, 0x797e3966, 0xd26cda97, + 0xedf5de8c, 0xdac485ec, 0xfc43e69c, 0xd2254aeb, 0xc1c09dc9, 0x8f3d5f5e, 0xd3ef16ff, 0xa730e6e2, 0x2c626d25, + 0xa2a23121, 0x2fbb8fca, 0x27ed23f1, 0x080be80f, 0xc9dd538a, 0x5c86e3f6, 0x94ec8837, 0x12284e32, 0x66942a72, + 0xfdfabee1, 0x7788432a, 0xe0157861, 0x433678f6, 0x85313c5f, 0x01dc328e, 0x12c36247, 0x7fa8d91f, 0x5222ff4c, + 0xe37596e9, 0x65ee2bf0, 0x07c7c6ac, 0x6397577b, 0xfbd2d2b7, 0x5acf7bbb, 0x591017a8, 0x7f4bb4ca, 0x628b393f, + 0x2ab0f7fa, 0x8e0177bb, 0xb877ddf8, 0x1a41d241, 0xaca79085, 0xfb81140d, 0x73f61728, 0xa6c151ee, 0xbc707cd8, + 0x538819e9, 0x2e3741d7, 0x418140ec, 0xb710da7e, 0xc36e879b, 0xaf6a9496, 0xb9de18f5, 0x1989af87, 0x2219375e, + 0x6601c9ce, 0xbc726790, 0xfab070de, 0xe6103049, 0xaf3072bc, 0x33060e5a, 0x80adc9cb, 0x9be7b608, 0x843146ac, + 0xc1df1794, 0x17e83016, 0x9de3d2d9, 0x0dba653a, 0x5c015550, 0x1946ead9, 0x97227256, 0xb511c471, 0x88b5f4f8, + 0xd70159ea, 0x8e9b9511, 0x7661a037, 0x331b2471, 0x36b42086, 0xae5371a2, 0x4210f45f, 0x9412df7c, 0x30c25c24, + 0xdb2458d7, 0x6cba9750, 0xfa79e5c9, 0x7f71d87a, 0x7f441b6e, 0x52130277, 0xea50d43a, 0x3d6d2862, 0x8c35dff3, + 0x9e8c37fa, 0x727790fa, 0xac5363bd, 0x0a0a65bf, 0xe9eb900d, 0x2c425bb8, 0xad51b888, 0xc2f94f11, 0x3040ffc9, + 0x2c8f611c, 0x7afb6e91, 0xea5562ec, 0x38c5819d, 0x3c31599d, 0x8bba36ec, 0x030c4612, 0x57318c39, 0x562f932b, + 0xf61f8a6b, 0x6255d7bd, 0x405a95fc, 0x8ef73a60, 0x5b31eb0a, 0x1db76a3a, 0xc91cf200, 0xfc31bdc8, 0xa86dc5b2, + 0x6fabc88b, 0xc00fe0cf, 0x7f180231, 0x1352bd94, 0x12d4d8cb, 0xf827b9a0, 0xf78113aa, 0xbff20e36, 0x54855fdf, + 0xc03f9a07, 0x93d7ba87, 0x1862fb68, 0x8cd1bd79, 0xe57ad2df, 0xa62ae161, 0x89bff9dd, 0x9f6f6a7e, 0x88267873, + 0x3dba386b, 0x760acdbf, 0x963d0bd8, 0x53f1e56b, 0x0b252e92, 0x2b802b53, 0xe6ef4a9b, 0x639e12ed, 0x0c376f85, + 0xbf5e5c05, 0xed8bb049, 0xdca95b38, 0x53d772f6, 0xc71abebc, 0xc16591da, 0x50af2120, 0x12ef28d7, 0xe44a892f, + 0x12456957, 0x31cc1622, 0x1b92f45d, 0x0072985e, 0x002b62ed, 0x24d7d4ef, 0x2ff6c54e, 0x59cf9459, 0xcf819178, + 0x2e699b1c, 0xc06c6e55, 0x1e2e93d8, 0x81917529, 0x9069b424, 0xe157f0c7, 0x03d65295, 0x1308b3c7, 0x2bdfd647, + 0xfd8b8d77, 0x9ab7ed23, 0x6fdee875, 0xcce87387, 0x6018e6a2, 0x114e2823, 0x3ad407bb, 0x36cf5848, 0x88019b2e, + 0x69e52cc2, 0x59ebf765, 0xd0e591f7, 0x3bcc44ef, 0x187148ed, 0x1b8d58cc, 0x0f7e5bb4, 0x49894f54, 0x2e88e2e1, + 0xd38fbe04, 0x2688a77f, 0xb40ea4ae, 0x2614ae7b, 0x0e31f7e5, 0x5299d66d, 0x15fa032d, 0xd9734197, 0x90ea7446, + 0xd6cba8cc, 0x7c39f201, 0xaca9528e, 0xa65c2ef7, 0xfbd7f804, 0x1bb4b3bc, 0x9b860c36, 0x46dde3d9, 0x57772f72, + 0x9e746229, 0x7607accc, 0x01c95873, 0x1927db11, 0x33bb5046, 0xd16c1a7d, 0xd515a76d, 0x3f0b7fb5, 0x1988dc0b, + 0x927f8e97, 0x30de7307, 0x877de432, 0xd6b522b0, 0x184125c8, 0x822107a8, 0x9bfa5093, 0xe0a522bb, 0xaf60ebf8, + 0x0a556899, 0xcfcb1101, 0xe47382e9, 0xd07dbf24, 0xcf294c1c, 0x52e97e5d, 0x31285af7, 0x9e43ae11, 0xf091a12f, + 0x7e2df891, 0xe590a09f, 0x609627d3, 0x63973c2a, 0x24d9c2ad, 0xc4ff5bf3, 0x6370c357, 0x5371d7ec, 0x7e78866f, + 0xa1a657fa, 0x5accc94e, 0x03861a6f, 0xf2866c4d, 0x30117472, 0x09e5190c, 0xfe7c0897, 0x33e20f08, 0x2f1e510d, + 0x9f678249, 0x7ec701f7, 0x57b15ad6, 0x1ad5e5d5, 0xae9744a9, 0x329e20e0, 0x26dc605d, 0x76ddb5d0, 0x7104d447, + 0x04662688, 0x48280fd6, 0x01a43dac, 0xb6152de6, 0x3e374606, 0x09b7407d, 0x1312a39c, 0x5344dac4, 0xff761f8a, + 0xbb56ac16, 0x15d79f4b, 0x6e9da951, 0x98e2ec1d, 0x598c7aba, 0x1247c566, 0xddcf2b48, 0xccc073e2, 0x9aab16a7, + 0x0334d401, 0xbfc3fe5f, 0x76169f7a, 0x2177eb57, 0x6a9c5269, 0x64d4a543, 0xf4db3944, 0x056f97d3, 0x68371281, + 0xc4ad9664, 0x6a090717, 0xc16767a5, 0xd1cbba9c, 0x1c6bcbcd, 0x3700690f, 0x10ae9b52, 0x397dc0ed, 0x84bf3ef6, + 0x9c4fc58b, 0x8bb14abc, 0x2c507f9a, 0x566734f6, 0x354aba2f, 0x16a162fb, 0x9f99864e, 0x30bb91f3, 0xe6899290, + 0xb9f2316d, 0x8d6052cd, 0x78cfbe5a, 0xdabf4a5d, 0x6dcad9a9, 0x0c0fb8d0, 0x7cf01bf5, 0xefa6ae06, 0x6113cf85, + 0xdb5f2f81, 0xebb0a08d, 0x8de9ef14, 0x357c4341, 0x86f0b784, 0xbbc0892f, 0x839d7ffb, 0xdaf252f2, 0x6a9a9996, + 0x292b35a0, 0x01e3186f, 0x796d70b1, 0xdf15eb86, 0xae6c208e, 0x5239f586, 0x4ce78c49, 0x653fe236, 0xdd47a4e7, + 0xdb3af560, 0x5439558b, 0x3e8c1260, 0x7f29fe3a, 0xa5d1fc8b, 0x6098bb9f, 0x7c99f2db, 0x2a1756bf, 0x0cb485a9, + 0xf2dc9680, 0x8e3a1952, 0x3c2d4b6d, 0xdd8dc3bf, 0xc4bd7499, 0x151c5a6b, 0xe2e4de30, 0x5af57c67, 0x217bd09c, + 0x8e1e3465, 0x3019b129, 0x53c83a75, 0x78710f2b, 0x430cface, 0xac0a88d4, 0xfba71679, 0xb5fbb7b9, 0x5ae9209a, + 0x648c9c76, 0x5a56cc4d, 0x63f895b6, 0xe8be6378, 0xdf2c831a, 0xb80c8a9f, 0x1e6aa5be, 0xd3b4de95, 0xed62ab16, + 0xef909597, 0xef0bd0a9, 0x2d6fb279, 0xb4e0fe38, 0x67da21a0, 0x59d5439b, 0xbb5d7c66, 0x781972fa, 0xdce77b50, + 0xf172ec8a, 0xa9f9b14e, 0xe741baf3, 0x465e3c20, 0xae53bba7, 0xdcf13062, 0x81ab7961, 0x122d8acd, 0xa282c60c, + 0xa1fdd944, 0xbb37e7e9, 0x67b6b6d6, 0x1d2b339f, 0xa47f9903, 0x784bc749, 0x8c7daf25, 0x69d14be6, 0xa62a48ef, + 0x7f87341c, 0xfcc66993, 0xd16b9818, 0x50b8d695, 0x4ee78f4b, 0x53615d30, 0x776a9b85, 0x1629bf26, 0xdb1c80c8, + 0xda42836f, 0x36a1fbec, 0x8228c7f5, 0x8fe839df, 0x91ba42d2, 0x31c77338, 0x0b6e4241, 0xb6e8bca6, 0xa8a28444, + 0x69c9f0c2, 0x964a4d57, 0x45c81bcf, 0xe6142fd0, 0xe3721ddf, 0xd95d6eb9, 0xa415a5bc, 0xfbc03f48, 0x83d946d7, + 0xfff62e82, 0xcc2c8a85, 0x778e2efe, 0xa3162021, 0xb04af2a8, 0xa7ff4fa2, 0x5b1c5acf, 0x9d28eac5, 0x924dd7c3, + 0x04a39312, 0x9f2c4da8, 0xa84bf8e1, 0x4047c161, 0x8347f557, 0x2f491a9a, 0x3f8abc0b, 0xe7180eae, 0x9664e3dc, + 0x038bd34b, 0x028b94cd, 0x089e1249, 0xa6752a9e, 0xd144aff0, 0xa8866dfd, 0xed348eba, 0xceeb80fc, 0xcd4b979d, + 0x06ca4d57, 0xff9830c1, 0xf664b879, 0xbd5e729e, 0x8783c040, 0x4592faea, 0xce6a5437, 0xaaa760d2, 0x0929882d, + 0x95a5c899, 0x235fb18c, 0x506c8c5d, 0xb94dd7dd, 0xf8a8f3c1, 0xd06a0cbc, 0xd2ea6c0a, 0x9b5379e5, 0xacf74c53, + 0xd5453cc5, 0x2627d0d2, 0xb3b8a777, 0xf61a4890, 0xf2a60e8d, 0x994182f1, 0xc31714b3, 0x8e60b55c, 0xe667c7a2, + 0x4e6f89f1, 0xd679c8c3, 0xe013a121, 0xce31d1bb, 0x1c037383, 0x757bda94, 0x24f1f83d, 0x662c7d75, 0x1d6968e1, + 0xd321d2cc, 0x9dbee832, 0x44f1d964, 0xa86d4fd8, 0x31cbabd8, 0x7a445cb7, 0xb1919dd7, 0x1ee1b239, 0x75e62bfd, + 0xe8b35e08, 0x97118c68, 0x5bce2c78, 0xf2280012, 0x10c1592a, 0x4ba93662, 0xc4d0d6a2, 0x27d4203c, 0xa18c4077, + 0xe6e4d869, 0x21e25091, 0xf281ae8f, 0xbe67b54b, 0xf69ad728, 0x27f48990, 0xeb7f8a5d, 0x270da90f, 0x88917be1, + 0xcacec501, 0xf41bce59, 0x93c570c1, 0x3c19431a, 0x08e9a4b6, 0x2ad9f973, 0x297dfca2, 0xf4c8f807, 0xc0d55c6c, + 0xf4a19efb, 0x9760edc6, 0x04b79e69, 0xc07248d8, 0x921ed3b4, 0xfc10fe68, 0xa84fb265, 0x812f8fc5, 0xf26c2783, + 0x7b7f6073, 0x33d34604, 0xb3edf89c, 0xa0e3eb66, 0xf475735e, 0x81dbf1a9, 0xa20da194, 0xf07a9136, 0xb12fcd38, + 0x7b104f3c, 0x66127865, 0xd629fd38, 0x3f6c4984, 0x23377bb9, 0x2815a2db, 0xe77b3a01, 0xf9c46e91, 0x0265371b, + 0x88f8263a, 0x73de656c, 0xd3969ee5, 0xf6282b25, 0xbc2beacb, 0x0fffcdae, 0xb2be1c5e, 0xf5f765b8, 0x3e6d1d5f, + 0xd8c82075, 0x84518f0c, 0x98e15880, 0x1ebc1d19, 0x2bb5e13a, 0x2cc1855e, 0x512850f4, 0x39323b66, 0x37967bf7, + 0x65b1243e, 0x32d896be, 0x36ecc392, 0xfe43fe2d, 0xaa2f10ca, 0x2b973240, 0xbcce1887, 0x2cdcf16b, 0xdc687971, + 0x132801f9, 0xd533cfc7, 0xb5b23faf, 0x723ab741, 0x0a65eb12, 0xf60905ab, 0x8ef43953, 0xf246ff19, 0x3b61bb37, + 0x35a73bdb, 0x2e0fb270, 0x53a4638d, 0xe5ecd718, 0x5dcbc181, 0x2f972767, 0x90a4636a, 0xeab2f55a, 0x73cf7233, + 0x43cc1dd0, 0x27cf454c, 0xcf1b4fda, 0x5cea22f8, 0x42b8c48a, 0xae2cfcc2, 0xc3cfee30, 0xa070c4d8, 0xce47907f, + 0x4730752e, 0xa10e2143, 0x2734aa54, 0x71474b80, 0x11b50434, 0x90bbca3e, 0xd38e6dbd, 0x7759f72e, 0xf1bacf60, + 0xa09131c7, 0x91650355, 0xbc112223, 0xf52e72f5, 0x96131193, 0x02828359, 0xa77c6bee, 0x93856adf, 0x9a5b759f, + 0xaa5ecf35, 0x845c0734, 0xd852e124, 0x70622a8d, 0x1e2f0fd3, 0x33c075f1, 0x5ae33090, 0x275e2446, 0x165c9944, + 0x67f54d4a, 0xb89c1c9e, 0x1b3200e9, 0x9e99c407, 0xec3b1963, 0xa4b0bbf9, 0x79c9155d, 0x6c6eeb9a, 0xf6ce1c82, + 0x22c87395, 0x04fa360f, 0x4dcd0d2f, 0xeffeea40, 0x362810f1, 0x8ad16d83, 0xea6c7eeb, 0x8d470171, 0x9e37d756, + 0x688bd088, 0x089ff874, 0x27a6374b, 0x3773b360, 0xa9873b0b, 0x9a194c3b, 0x535cc2fb, 0xf81b903c, 0xad2ce257, + 0x3a414cbc, 0xf2e91373, 0x13b682fa, 0xafbdfcdb, 0x9a4e006f, 0x8cdf9476, 0x6caa0fb1, 0x9d32ae08, 0x05317530, + 0x76160c11, 0x5af0f639, 0xead64526, 0x001f6296, 0x881dd05b, 0x9105d366, 0xcf9580ab, 0x553ab350, 0xb6410719, + 0x6de751d4, 0xea1ac5fd, 0x4426d9a3, 0x17763cfa, 0x6ee1fe00, 0xb7e2158c, 0x728ac5db, 0x2f25937b, 0x90cd3809, + 0xd3576327, 0x16015e30, 0x01a32b41, 0x714f6ff8, 0x3995595b, 0xee37773a, 0x4d4c9ce6, 0xe53a53a8, 0x7978c160, + 0xe7c9659b, 0xdc713436, 0xb9dfbd7a, 0xb73589d1, 0x8b3374cf, 0xbbd6b28d, 0x32781963, 0xd8c67330, 0xf8e25396, + 0x9b9deaa1, 0xe3e7a74e, 0xc79ff323, 0x20826e97, 0xb87583ae, 0x8e1d689d, 0x34b1d44f, 0x35c6069b, 0x9f7c7daa, + 0x68e8d87f, 0x46959303, 0x2564bfcf, 0x8ac216db, 0x9460f505, 0x87380947, 0xd01a8e34, 0x5b1e8faf, 0xa12366d0, + 0xfaf03e5e, 0x35abcbbf, 0x472ad8eb, 0xbe58542b, 0x7723e443, 0x36b9f069, 0xd66f9950, 0x3882f2f1, 0xcc244a53, + 0xc3a7de24, 0x3059e7e4, 0xd5b49335, 0xaffb9d41, 0xc366a3cb, 0xc9211a65, 0x43221d12, 0x3ff54599, 0xf9aba5d4, + 0x245e0267, 0xc2817761, 0xbf9ab7f7, 0x6e82c7e5, 0x27176df5, 0xa235cadf, 0xda7dd7c6, 0x274f4036, 0x1f91b778, + 0x1e1c5ebc, 0x3437f5e8, 0xd2d79732, 0xefe90389, 0xcb752a82, 0x5cca6ebf, 0x282c5342, 0x80cce9f4, 0x8f3704e1, + 0x30393a3b, 0x19ce2f80, 0x43e2ae48, 0xc5b1e898, 0x0ac9e5c9, 0xf030bfe6, 0xa55ec995, 0xcaf7de34, 0xdc832c89, + 0x425273bf, 0x65fe8275, 0x7d36bd7a, 0x278bbac0, 0xbd263132, 0xbb985037, 0xaef746a5, 0x1d708d3c, 0xd38c2591, + 0x4c0de89d, 0x2af682cd, 0x277aff0f, 0xd734e8ef, 0xf66470b0, 0x3f01604e, 0x1bdc31eb, 0x77ad9232, 0x35f3a2c3, + 0xd4296564, 0x30712d43, 0xccb53f4d, 0xf3d53238, 0x69836eb3, 0x45190dca, 0xdac98988, 0x0ac943ae, 0x30af1d35, + 0x730a6750, 0x84d7b4da, 0x8cf794b8, 0x073aeb6d, 0xd96122a0, 0x287dc4de, 0x02f70157, 0xb0671dcc, 0xc104b1dd, + 0xec9e6266, 0xd8125dfc, 0x9cc28232, 0x3ce18d87, 0xf2138fb7, 0xa5bccf6e, 0x5c9c125b, 0x539c9b1e, 0x2707b0d9, + 0x00eed475, 0xb321283c, 0x0bb55f29, 0xef220e49, 0x9918a0b3, 0xf918e059, 0x722dc516, 0xcdfa6e0a, 0xfd845be3, + 0x7d4a5203, 0x835fcd59, 0x3fe5890c, 0xfec5a3ea, 0x901b5832, 0xd2b9b90b, 0x69838d7b, 0x4c3d6a9f, 0xf68e2b02, + 0x40592eb7, 0xf6d76561, 0x2874fea8, 0xa881ad9e, 0x439dff5b, 0xa6caf006, 0xa5c35190, 0xdd3775b5, 0x8cfae0ef, + 0xcd79cd1c, 0x1c457413, 0x5a36acbb, 0xb5b611f9, 0xa858486f, 0x15f75b98, 0x4b54ef2e, 0x6f1acae2, 0x12fdf9cd, + 0x03cc17a8, 0xb8f6e72e, 0xafc81063, 0xc9b58b5c, 0x026e5ddd, 0x3d468c98, 0x6246f745, 0x2a834f65, 0x91ff48c2, + 0x222e5155, 0x63ebba35, 0xb12cfe1d, 0xdd35e247, 0xb16d49d6, 0xc2915df1, 0x900043d3, 0xe6154d02, 0x3aa63f5a, + 0xa99e1b99, 0x9d40a4aa, 0xf143d8d2, 0xb71b320d, 0x7783c3de, 0x3d3801c8, 0x12038a8b, 0xeb23b92f, 0xe760d773, + 0x1207c60c, 0xaedb0224, 0x993df11d, 0x62255b1d, 0x0f4bb6e9, 0x9e95fae0, 0xcee70b71, 0xf3cd322b, 0xd5dcc3bb, + 0x95f3ac16, 0xa76f536d, 0x35d54b3a, 0x0bd0457b, 0x800da966, 0xf226f851, 0x9a68f13d, 0x5b29aae8, 0x8e3f07c7, + 0x71c1891e, 0x7c9a8233, 0x374c1527, 0x59cce28b, 0x6f260fc9, 0x9f61fa03, 0x07852d2a, 0xd1ded60e, 0x85574815, + 0x78fa98b9, 0x5b2d239a, 0xcc80eeef, 0x7ff4217d, 0x7d3f4adb, 0x69a83747, 0xdfb3bb14, 0xf27ce6b1, 0x658af55a, + 0xeca0b851, 0xad01148a, 0x745894b8, 0x71c6c1a4, 0x1fe72c80, 0x77b3b240, 0x5be92440, 0xa18797c0, 0x508d11a6, + 0xc5b19fb6, 0xa972ddf0, 0x16f6ef05, 0xf4e4b936, 0xb9c6bcc9, 0xf24410d5, 0x7f931235, 0xd9096a3d, 0x780217af, + 0xcfddba87, 0x07d0f393, 0xff9d6faf, 0x5964a2bf, 0x5d93c23c, 0x879db6f2, 0xbbf5d63a, 0xa9491bc9, 0xb96fd89c, + 0x8da1aa6c, 0x0a9b96d0, 0xed5ca8bb, 0x43bafb03, 0xdaea46eb, 0xd26814eb, 0xb3a2b8de, 0x1756f7c3, 0x6266e92a, + 0x415c9e41, 0x8e3999e5, 0x44f86118, 0x07c7920b, 0x7aae056d, 0xd3e3bdc5, 0x1581c857, 0xece327dd, 0xb4117d45, + 0x60cffa77, 0x030f5a0c, 0xbff42761, 0xcfd254c5, 0x43e8bc6a, 0x4ca75cf2, 0xe4ad5e37, 0x0be2a345, 0x4bc96e07, + 0x2b3935e6, 0x9a084457, 0xb3a71626, 0x73cd2f2c, 0xd576bc4a, 0xc0b91b98, 0x58e34a9b, 0x6b3070a8, 0xe3107ed1, + 0x2322c5ae, 0x5b717ce1, 0xd0e89415, 0x6e6b2841, 0x4c440072, 0x3886c1a1, 0xc5f33fd2, 0x37a7baa2, 0xa347e86a, + 0x60ba311d, 0xe6bc54ce, 0x0318aac9, 0x1638fc3e, 0x775554ca, 0x5d200386, 0x9c0758e5, 0xc44bbde0, 0x4a4fd1d1, + 0x700afce9, 0x2f165542, 0xba76ff5a, 0xddbd3f18, 0x07f81dbf, 0x380586e9, 0x92a951cd, 0x95b08589, 0x2e0a7e84, + 0x75e4605f, 0xa4a83054, 0x003bbfa4, 0x3792ef9d, 0xcf5e73c9, 0xcdf56a53, 0xa92f0d43, 0x610b2efb, 0xb6035207, + 0x0242ecc4, 0xba4423eb, 0xc3f81bc2, 0x5f3b5d10, 0xd69bf73a, 0xd66ed398, 0x14a0d454, 0x5a915691, 0xe208c605, + 0xae82008b, 0x87c19a7d, 0x4134ac89, 0xbfa90833, 0xbf7e029e, 0x80380d6a, 0xfcdda0ce, 0x86b5eef6, 0x7b2cdaec, + 0xcfd4f630, 0xe88668c4, 0xd535d902, 0x42d8ad3a, 0x16691544, 0xc8c60abd, 0x6114ea84, 0xaeb7c4ba, 0x900eca2b, + 0xb37d8d52, 0x851b18f0, 0x20e48cac, 0xa57ace5e, 0xcee70e18, 0x92a97297, 0x512e427a, 0xda67843f, 0x9e05fbcf, + 0xb591bf91, 0xd9f83193, 0x57523a42, 0xd3c35871, 0x03b8cb3a, 0xa5648fbc, 0x554e6c2a, 0x04613d27, 0xb5e282bd, + 0xde58f1b0, 0x3709dc6c, 0x9f482aef, 0x719bc804, 0xceaabe61, 0x5fa88b56, 0x34ed183d, 0x0e8c4061, 0xa0149ea1, + 0xcb7a03fe, 0x841f06a9, 0xdf83a2a0, 0xbdaf19de, 0x59b80c51, 0xfdc564d1, 0xd043e57a, 0x7b4810f9, 0x8b0fdb4d, + 0xa1e1fdbf, 0x25e89e87, 0x44204d27, 0x79488387, 0x13d3220f, 0xec5ce7f5, 0xb3ee98dd, 0xf67c5053, 0xd019a374, + 0xd4c467e9, 0xa3168bd2, 0x4c5e074b, 0x86339af6, 0x08dde194, 0x07aa4d37, 0x1ca8fd25, 0x9c713340, 0x543b0a29, + 0x20219ca0, 0x2b77bfdc, 0x171324f5, 0x17f980e6, 0x508dc1cc, 0x5201e25c, 0x73a94f04, 0x3a487390, 0x5f9ea391, + 0xeafd317f, 0x58cbe598, 0x8aa80c0d, 0x1724a67f, 0x091431a6, 0x89497ae3, 0x3e823623, 0xab28688a, 0xd8e895f6, + 0x0d6ce310, 0x591b93c8, 0x6c745935, 0x0cc911dd, 0xd0236c66, 0x7bc5d45f, 0x0bd8a90d, 0xf2bb768a, 0xc48559ab, + 0x2acbbffb, 0x6de1d17e, 0xf1d0d480, 0xea148152, 0xf51ae92d, 0x2333ba51, 0xaedbe4eb, 0xce7695f4, 0x7fbb4c38, + 0x944829ac, 0x7902a65e, 0x00d9232c, 0xbaef10ae, 0x0c640f63, 0x5162db20, 0xd499143e, 0xd9d77d12, 0xae5c4c35, + 0x43e485ff, 0x1d5046c7, 0x99f2275b, 0x625d29ac, 0xadbdb7ab, 0xddb95620, 0xd1aa4f28, 0x679b3369, 0xf09c11ca, + 0xb2a81d86, 0x128b89ac, 0x2464c678, 0xa4c93cbf, 0x89f7e9cf, 0xc4549803, 0xced0c309, 0xe9db5aea, 0xa06a8e3c, + 0x5a9cdeeb, 0xfaa6e7d9, 0xc014276a, 0xfc5f5178, 0xc2aec471, 0x3031f646, 0xc3cc9ff4, 0x857c73cb, 0x7c8a0ab7, + 0x29a3d246, 0x5ea1a213, 0xa909a306, 0x49423c6a, 0xe8464693, 0xa6650026, 0xe117a932, 0x0636722a, 0xbd0a4e85, + 0xb962cf68, 0x2c8f0d7e, 0x625e30aa, 0x147026b6, 0xee49fffb, 0xa9cea52e, 0x21e6d149, 0xfa381374, 0x29cc51d1, + 0xaf776592, 0x63472e53, 0xd06e3350, 0xe661ce41, 0xb00978b4, 0x0e4614ab, 0x0935964a, 0x14bb3560, 0x6269d2fd, + 0xff8ea27b, 0x15962127, 0x962352ae, 0xb79ff87b, 0x20d06444, 0xd07bf24c, 0xf798e1ff, 0x02ea79fc, 0x00c6c563, + 0x538d537a, 0x99d4f97c, 0x1c7bf592, 0xc85dbe6c, 0x8e4a5618, 0x9cc0d49b, 0x38be1fb4, 0xef52a2ff, 0xf0fd75ca, + 0x50c25671, 0x9ba58201, 0x1c608867, 0xa374cf80, 0x9d3a582a, 0xb0826ec0, 0xcb5b0d60, 0xea6e634d, 0xaa46107a, + 0x1ec854d5, 0x797132e4, 0x1e875c53, 0xbc0c471d, 0xb69f9361, 0x54c2f6dc, 0x53d759ce, 0x56a20693, 0xa55f0a0d, + 0xa2fb5a37, 0x77c11c34, 0x271c459f, 0xca3b868c, 0xecc07240, 0xbf826198, 0x77df2f79, 0xf9581985, 0xfb3e3823, + 0x615c4764, 0x6a9c6bf0, 0x0be5f40b, 0x049c2dab, 0x9b98d7a0, 0x3da6a287, 0x5bb01298, 0xe0081ad8, 0x6c61420b, + 0x3cdab866, 0xaef5a903, 0x30993411, 0xbc17e767, 0x6a66a18b, 0x829c689b, 0x030afbb6, 0x17751848, 0x9c02b02d, + 0x6bcb9da2, 0xbdbcee66, 0x97d87fbf, 0x15344580, 0xe502ebf6, 0xc3cdab39, 0x27cf8e04, 0x79804369, 0xf996bd55, + 0xd2ae24a4, 0x72d10cd6, 0xe46901ec, 0xabd3562f, 0x19cd86d5, 0x6df6ad39, 0x1f3427be, 0x98e7fd65, 0xb685c4ef, + 0xd595fe72, 0x90cb2a66, 0x1e94b694, 0xca42d1bd, 0x73ba6557, 0x3ffd1d02, 0xe6e0ee6c, 0xdaa459b0, 0x4c398f04, + 0x038fc2ea, 0x409a819c, 0xc904dc82, 0x87d37b9b, 0x25b32efc, 0xd1846b8e, 0xfdac80dc, 0x79de8dbf, 0x259f3e6c, + 0x93618395, 0x571e342f, 0x2a105278, 0x19deb63d, 0x464ba512, 0x5d5d20fc, 0x3a81c2a7, 0x6faca64f, 0x97b6ca99, + 0x6252c189, 0x1c583dac, 0x128c6729, 0x697490eb, 0x09dc0ec6, 0xf94ebdea, 0xc8808912, 0x43e70b0d, 0x95ee5c2a, + 0x1688745b, 0x6005509f, 0x55c26ae3, 0xbb75763a, 0x24046771, 0x6ae1d42a, 0x6d523635, 0x99a81e9b, 0x5472dcfe, + 0xa27af336, 0x669861c6, 0xe6f89c03, 0x65a28b36, 0x26a0fe4f, 0x9f0aa06d, 0xa002bb98, 0xfa72b1c0, 0x4a686914, + 0x740a97bf, 0xd0f1bf09, 0x5801c8ff, 0x69b3b1cc, 0x1a864563, 0x458bed95, 0x8f769b28, 0xc2b91ca6, 0x23671f26, + 0x0bfda1aa, 0x9bd24315, 0xb1efb8e0, 0x811c8745, 0x25899f4e, 0x5c07cafe, 0x1c575694, 0x839c9752, 0x15ecf135, + 0x7a8e5e20, 0x9d634134, 0x1f6f5765, 0x4b89463d, 0x4d2a860a, 0xa5c91e78, 0x28048e2f, 0xdede0460, 0xba8c8a83, + 0x09371587, 0x8fd3238b, 0x121c1fe5, 0x8cc58b3a, 0xb781e769, 0xd34abb54, 0xeadd4ba9, 0x5efd47fd, 0x2e58e726, + 0xe226dd39, 0x07bd02b8, 0xefd36344, 0xa7d67475, 0xaebc2a0d, 0x0e481d9c, 0x679db143, 0x608a57a8, 0x7a655033, + 0x1660dedf, 0x74aebb3e, 0x65cc9377, 0x13b67071, 0xb5931309, 0x21249027, 0x768018fa, 0x83f135a7, 0x740b516c, + 0x4884d940, 0x578eba16, 0x9378f0da, 0x90778a2c, 0xba270e56, 0xff808dda, 0x7c58b1bd, 0x41a38ea7, 0xe8fadf83, + 0x7a14c587, 0xd00bd512, 0x65259eee, 0xc9293001, 0x10eb9c1e, 0xee820993, 0xdc09ba28, 0xe7dfe9dd, 0x490aef2f, + 0x8afe827a, 0xd7703de9, 0xe5ed425e, 0x79e4c84c, 0xa6df7fae, 0xd7da8f13, 0xfddcb98d, 0xb617e9cf, 0xf17664cc, + 0x8d699c6b, 0x0f7d376f, 0x0672fb90, 0xf991af33, 0x9aa83d81, 0x2110d8a1, 0x51517afd, 0x4bf5780b, 0xf9932087, + 0x08d8c956, 0x8fc72d85, 0x74f7a44d, 0x3e08adb7, 0x70adfe04, 0x7fee92e4, 0xd49d0c89, 0x35cbc827, 0x29094c5e, + 0xf32130b6, 0x3947ed41, 0xc3d253ec, 0xfbb88c82, 0xd846405c, 0x984a1488, 0x62f826fc, 0x64fc124f, 0x6ed84c31, + 0x4a7f64e1, 0xdd49fdd7, 0x39626af8, 0x02775532, 0xb3bfcdf7, 0x3a56a5b7, 0x034e4153, 0x407398a2, 0xc738e4ef, + 0x15177bc8, 0x7ad0540a, 0x6e163265, 0x51714469, 0xfa74be0d, 0x4516d210, 0xeef0297b, 0x7aab4437, 0xc1c7460b, + 0x03ffa2c0, 0x1dc4a2b8, 0xae215c19, 0x407bb528, 0x25a01350, 0x97011f52, 0xdd665d18, 0x7dc6a2e1, 0xde7e4278, + 0x1a947b32, 0x1c3f84e0, 0xa976f329, 0x8cfaec1e, 0x4cdf2597, 0x174051f9, 0xd7a712b3, 0x78cd7ca4, 0x4aa9929b, + 0xe3195c08, 0x5b228541, 0x8ee11a44, 0xa6be5628, 0xadbea186, 0x31919048, 0x54613747, 0x2e723585, 0xf489d537, + 0xe1fafb63, 0x696069e4, 0xfb01ee2a, 0xceb060a9, 0x880bed01, 0xe16e7ad2, 0x5ce29095, 0x80507ed2, 0x894c541b, + 0xc45e1d64, 0xee955200, 0x29d8957f, 0xfcb00e95, 0x9a64ba98, 0xfbc861fb, 0x643e424e, 0x258bbdf9, 0xe04d87ba, + 0xccbf7537, 0x885ed231, 0xc2855ef3, 0xe6b1500d, 0xa8b41c16, 0x897fd84b, 0x1f97e440, 0x96f28e28, 0x80abea29, + 0xb2017fc2, 0x66929814, 0xc9d386d7, 0x44fa697f, 0xa9e53729, 0x55234de0, 0x483d2749, 0x419bef3d, 0xf886d949, + 0x999e6c70, 0xa5f4141e, 0x868303f0, 0x86bda3cd, 0xac45bebf, 0xe3cea699, 0xcfc5a518, 0xefabcc78, 0x9af0adc0, + 0x00277680, 0xfa93fe1e, 0x8802b89c, 0x5f290f77, 0xc2c7b628, 0x7d11de7e, 0xc44b1de9, 0xe262af80, 0xfd2eee24, + 0x7ad0d472, 0x5e795f4b, 0x8ca27986, 0x6a5f5e42, 0xb581bb47, 0x86968da3, 0xe282f6cb, 0x8eb27fa5, 0xeee6ce86, + 0xc61649c9, 0xb58c9599, 0xddefc504, 0x027c8566, 0x4285511a, 0x4b218238, 0xa60c7551, 0x9c5d395e, 0x73c3788b, + 0x5138d7f4, 0xe6b28495, 0x8c9c934c, 0xea44eb88, 0x43994527, 0x78294a33, 0x58eab411, 0xc196f074, 0x6f9bbe38, + 0xf57c451e, 0x69fee6c4, 0x6c897973, 0x4b290178, 0xb31c3d8d, 0x9afb7de7, 0xae1486ef, 0xad45f4c2, 0x46947f7d, + 0x8b919bd8, 0x2c7f1d86, 0xb8e77e63, 0x1ea68de7, 0xeaa25b50, 0x2c9b3777, 0xf79539ca, 0xdcbe53da, 0x0d7d1f14, + 0xee23bb3a, 0x464d11bf, 0x14c1838e, 0x665e0905, 0xbd71b23c, 0x166c9808, 0xd7ad7102, 0x5542eac4, 0xf19f0686, + 0x1bd10ed4, 0x55456d75, 0x236dd9c6, 0x3c3445ba, 0x408e15d9, 0xf169fbd9, 0xfdf32f74, 0xbb7ba937, 0x78f55ad6, + 0xef2865a8, 0xfba6a99e, 0x3f14acc6, 0x48db2d54, 0x94065835, 0x811bf3c0, 0xa85adc59, 0x242cff70, 0x65619e59, + 0x394b487c, 0xae0de1b8, 0xa315d6e0, 0xf59f7e1b, 0x12d813e1, 0xf86c5c21, 0x6ee2f1ed, 0xb66f78b7, 0x62928aea, + 0xb999865e, 0x0140a35f, 0x928dab46, 0xc991ace0, 0x9dd8c15f, 0x9ca2b59b, 0x9f4d5428, 0x9e627be6, 0x1303b5b0, + 0x79a5cb91, 0xe7adb903, 0x649a79c1, 0x842a61d6, 0xa51e4757, 0x3633e832, 0x8d7cdb9d, 0x5c7d613c, 0xededfa93, + 0xb29bc1eb, 0xe98b6170, 0xad3c0199, 0x9eb5ef86, 0xb16cb815, 0x8deb58c6, 0x0aed762d, 0xff3ff9f7, 0x17def4d6, + 0xd4c1611f, 0x99e12370, 0x3312f637, 0x3f79f96e, 0xfc25d5ef, 0x7b74f31d, 0x73d89cdf, 0xc2ecf3c7, 0xe46faeb0, + 0x70493ed5, 0x0e561fd0, 0xb5a6dd27, 0x3c0b876d, 0x37d37ebc, 0xe8629cac, 0xea3ac2f7, 0x8baa73f7, 0x2e8361f5, + 0x8259786d, 0xcc93970d, 0x3bbb5e6b, 0xb9c41eb8, 0x0018b05d, 0x672bfa9c, 0x4993004d, 0x39826d16, 0xae02e93b, + 0x90a89002, 0x71718156, 0x35b857a0, 0x4b1da202, 0x115aab31, 0x6d208436, 0xe23ccd19, 0x8cff2e41, 0x288a72f1, + 0xfcb7493b, 0x1243f8ed, 0x1fabcc55, 0x015192c5, 0xc1da4b10, 0xcbba7843, 0x4b18f93f, 0xc865a081, 0x6a468c87, + 0x691332de, 0x719c7a52, 0xb16b260d, 0x60664999, 0xd05dd296, 0x4b4d6ac4, 0xeab2b4a9, 0x1bd124c9, 0x55ac568f, + 0xbc2a4473, 0x8a44cee6, 0xe8479eb6, 0x488ee1fa, 0x42a57cb2, 0xca43ebd7, 0x28ad1b41, 0x43edb969, 0x2096cc01, + 0x4770f57a, 0x91bcf4fe, 0x8707f039, 0xfb8a5050, 0x80fb921f, 0x58e02efe, 0xb0073e24, 0xed40b3e7, 0xd388c475, + 0x0dae5cd0, 0xea9c89f2, 0xa21d1fa1, 0x8a59043c, 0xb004581a, 0x2b654dd3, 0x098174c1, 0x5c1b07a1, 0x3f2ea55f, + 0xd246d677, 0x1ad325e2, 0x85570640, 0x6ace01ae, 0x8023af39, 0x0391db3b, 0x5ad9c521, 0xdf446913, 0xf2902cf5, + 0x097dea5a, 0xa42c28d3, 0xea06b4f7, 0x212ba23c, 0xe4fec4b7, 0x7dd828d5, 0x995f292b, 0xa8835e3e, 0xf81f135e, + 0xdf4a71d9, 0x3d381c36, 0x1f487265, 0x962fabc7, 0x0e0521d8, 0x4ed73cc7, 0x219698f1, 0x0c1f586d, 0x69af3732, + 0x95983526, 0x2b9cfc13, 0xfacbab5f, 0x39091314, 0x940cbb75, 0x43ef9a34, 0x1623f095, 0x155f9a74, 0xeef0b8aa, + 0xfa7d0b42, 0x9e99ba9c, 0xd8f38e33, 0x459968d6, 0x6ff134ea, 0x56694c49, 0xd6dc64d2, 0x92e5b81e, 0x4d98c66e, + 0x875d2c87, 0x389a96e9, 0x2e0731ff, 0x029f0f4f, 0x2bd67c99, 0xdb59233e, 0x69dbf297, 0x93c139cb, 0x14083d88, + 0x236c478a, 0x310909f9, 0x6d2de0bc, 0x6084e6a7, 0xebbe9884, 0xd08cd6b0, 0xb3eb3ba4, 0xd83d3a59, 0x6bdb128a, + 0xc0fa4849, 0x87ec2fc6, 0xd6f97ae3, 0x822521b0, 0x025065b4, 0x2f9988f5, 0x6c815008, 0xf90eb4e5, 0xd246a709, + 0x574b1f99, 0x948ff885, 0xd61a7c8d, 0xf27435a5, 0x71e22ff2, 0x56173a1e, 0x5b5a0436, 0x0bb2a3d2, 0xe25bb6b7, + 0x45aaab4a, 0x5f158305, 0x21131aec, 0x40b44518, 0x2fc29343, 0xce12caba, 0x06dde545, 0x4ff6e6f5, 0xde460d85, + 0x18103a35, 0x0663a462, 0xd5bf01af, 0xd4c55b21, 0x5ce3a739, 0x405e2ae8, 0x0b65a046, 0x7fd719e9, 0xe60495ce, + 0xe447eda5, 0x278397e7, 0xb5cf763f, 0x1a728901, 0x8833c144, 0x2410d288, 0x25ee2555, 0xf7689162, 0x836e6184, + 0x0cf64c4a, 0x87869c3c, 0x7c70e2a1, 0x4773d613, 0x85489b6c, 0xd241ab33, 0x6b3876e2, 0xd7430605, 0xb700e56d, + 0x2c327047, 0xf70623ef, 0xe2090c32, 0xc8601d2e, 0x0e970531, 0x97c4531c, 0x2807b917, 0x4f34eff6, 0x1352eea4, + 0xd9e00c19, 0x7df56779, 0x27c2b0bf, 0x1c8bb0d0, 0xd470a1ee, 0x9a6db0a6, 0xc953f0dd, 0x02ad0502, 0x0ec56c9c, + 0xadc65a5e, 0x113815fd, 0x50b91718, 0x2f18d1ba, 0xa141b434, 0xdd6a2558, 0xfa654d3c, 0xf17101ee, 0x02eecb13, + 0x423bd90b, 0xbcb4737c, 0x8d299981, 0x8801ab98, 0xced37d5a, 0x938b09e7, 0x8b5e2985, 0xe3c2d230, 0xe59c99eb, + 0x880f9a56, 0x9ddd9ba2, 0xedd6f698, 0x14095198, 0x5f0246c2, 0x04354a9f, 0x3de41b56, 0x9cfecb78, 0xb03c29ec, + 0x79f409d8, 0xb385319b, 0x6b22c7b4, 0x4ffc3791, 0x060792fb, 0x7bb7068e, 0x6d809b4b, 0xe81a4227, 0x991012ed, + 0xebf36076, 0x40f62b0e, 0x087283b1, 0x1a9af5ea, 0xc0bb0c64, 0xa04d1626, 0x5fbb3531, 0xba48c296, 0x23339b7b, + 0xc4398e28, 0xfe8e1ed4, 0xf162bb85, 0x7385872d, 0x77ce8df6, 0xcd79edce, 0x7949aa4e, 0xeb4bffe8, 0x27f7d796, + 0xe5f4cdd9, 0xf5c214fc, 0xbe97a512, 0xddd2bf00, 0x704bc61e, 0xf8369d8d, 0xee43adb4, 0xc97b7912, 0x5ca415ba, + 0x39993bd4, 0x6775c7ef, 0x09b904f5, 0x02149ffc, 0x28a37712, 0xfa624aec, 0xc023ac98, 0xacf72dd1, 0x493b12c9, + 0xe2d56496, 0x32e9870e, 0x42688f88, 0xb338f21c, 0xdf40fe69, 0xed4dad91, 0x111e0b03, 0xb645b9ad, 0x4db6e728, + 0x3b35a096, 0xf8bc92e3, 0x7ef96329, 0x9cbf1875, 0x98d99924, 0x11c0c1a2, 0x5f03f696, 0x20f5a67a, 0xf4c3a76c, + 0xe59cb721, 0x5f1c6e2e, 0xa2cd42eb, 0xd467346b, 0xb8f66d17, 0xc234493d, 0x7dc7a918, 0xab907872, 0xd8eb5f32, + 0x5e7b9f5c, 0x2502c496, 0x1c84df83, 0x66b3d12d, 0xd9032f9d, 0x47b9958a, 0xc29ee1ce, 0xc16c2e13, 0x4db153f7, + 0x6cdda637, 0xadbafa28, 0x74e02122, 0xeceb9aa6, 0xc157ea99, 0xa3c698d6, 0x9202dabe, 0xe3b8d86a, 0x7a00bd14, + 0xad52b030, 0x62e24b7d, 0x6ad41a31, 0x29ef7370, 0x41d6643c, 0x13b9f2a3, 0x23f77186, 0xbb8c5119, 0x968234a9, + 0xc89f9b89, 0x841f1af7, 0xf1334376, 0x738e5ef2, 0x15d9145c, 0x7a939a67, 0x9a7d175f, 0x7b85ab45, 0x2e45837a, + 0xe6be60d1, 0x119e75dc, 0x3df7de35, 0x517a238f, 0x3151400d, 0xb755202c, 0xd1309b2b, 0x6ac1d0b4, 0x929109b5, + 0x4b2430a0, 0xd4fc925f, 0x9d33cbfa, 0xcb66c795, 0xb2607bc7, 0xcd9de432, 0x7d4c015b, 0x772f5c96, 0xa89059dd, + 0x9c84efd8, 0x99d6d180, 0xc37da150, 0x1241d6f9, 0x1d5541d2, 0x83564ba8, 0x6650512e, 0xf4c328fb, 0xdd1c112c, + 0x0d02f1e7, 0xf3caeecf, 0x983a37e7, 0x63ad00e2, 0x1e951c73, 0xf330a068, 0xdb5a9aca, 0x05c3e5d7, 0x114149c0, + 0xcb86da33, 0x6827bd0a, 0xd3bf088d, 0x2879554c, 0xfb22d423, 0xeb412446, 0x7f721c8b, 0xcc15de42, 0x7e4d4f65, + 0xb2b7c1ba, 0x7a36e1b4, 0x662924e8, 0xc48c23f9, 0x7845d9e9, 0x3692a796, 0xef0352e4, 0x8863cbd8, 0xfe351bc7, + 0x4cca88c1, 0x9226554e, 0x10a10400, 0x62218037, 0x41fecf74, 0x2fe3d995, 0xa51814c6, 0x03b80a43, 0xad56ec7e, + 0x0cf46230, 0x498ec8df, 0x94ad2c37, 0x9ed7ff5a, 0xba549814, 0x26a66cfe, 0xb17f1e8f, 0xf7e74e35, 0xf339720c, + 0x3d11b07c, 0x4e1002c0, 0x31f32c66, 0x7c77bc51, 0xea0df2f3, 0x6071ac8e, 0x39997728, 0x60554412, 0x00b79283, + 0xe8f9fa11, 0x91b85fba, 0x7f555ff3, 0xe7c63158, 0xc0820566, 0x711ea595, 0x93aa5644, 0x396e4d75, 0x0f838c9f, + 0x7d4b9f42, 0x811eb10b, 0x4b6ee9f4, 0x79f618ff, 0x14f3abdf, 0x7aa8e81a, 0xcb3045a8, 0xb92160f5, 0x5a56e663, + 0xa9fdaae2, 0xf46430ff, 0x55cd424e, 0xa1c99a24, 0xda5a477e, 0xefb17eec, 0x75ae4710, 0xa3d9be83, 0xe5fc5b82, + 0x5d6eff0d, 0xbe0201a5, 0x5d33e409, 0x30843b2a, 0xe8c1cab8, 0x9691ba14, 0x4e8d930e, 0x9758d972, 0x5b4bb285, + 0x9f6022b7, 0xc2e362b5, 0x12956ab5, 0x0e88549f, 0xb60b1f0d, 0xcb428bf1, 0x86b2a542, 0x30ed78d7, 0xd828c7b1, + 0x6ea0fc47, 0x92315d0c, 0xdb95d2dd, 0x42be9ffe, 0x21b33cd7, 0x76d06b6b, 0x16f68a4c, 0xe20cf33e, 0x6af71004, + 0x1ea08e82, 0x6a2069cb, 0xbcdff8aa, 0xc0cc70e5, 0xc163de0b, 0x6fce4be0, 0x5288af6e, 0xc23e62de, 0x6bcb958b, + 0xfbf961a3, 0x283988a8, 0x6727fdb4, 0xc6e92802, 0x3925ecd5, 0x2772b658, 0x8c1354d2, 0x9d109fb9, 0x6f915cf4, + 0xcd3a3f08, 0xc4ae5122, 0xf3af262a, 0x65f8111f, 0x96df6edd, 0x2ad5c1a8, 0x535847ba, 0x157ae75d, 0x4249071c, + 0xe7092391, 0xc3d5822c, 0x7a62e2c5, 0x5ba716db, 0x10da4593, 0xf8ff777e, 0x6e06f09d, 0xd38db78d, 0x9357558f, + 0x0e9ce7c5, 0x464e1d59, 0x7602033f, 0xaf4334e8, 0xed9131e6, 0xb0e67155, 0x07919468, 0x2ac7ab1f, 0xb21edc4d, + 0x56b4fc9c, 0xab604a13, 0x530ef0bc, 0x748f9314, 0xa38317fe, 0x71b4bd86, 0x8da4c19a, 0xd491f19b, 0x78ead445, + 0xfd4073af, 0xcd88aeed, 0x804e1c7a, 0x636d01ee, 0x2f767a52, 0x8898dfed, 0xb985bcd3, 0xbd714676, 0x6e6899d8, + 0xbf34f911, 0xe8421725, 0x62f5b011, 0x83f304fa, 0x03b11750, 0x98c94bd9, 0xb545f1fa, 0x1b7c2771, 0xd50af758, + 0x48365081, 0xd4768263, 0xc3368273, 0x1a271e3c, 0x23169548, 0x5f9f1c30, 0xecfb08c3, 0xabfa6430, 0xe4438a78, + 0x5aa0e5d5, 0xc53aa595, 0x7422fc5f, 0xdfb3cb52, 0x72f1f808, 0x32c12215, 0x1dbd1709, 0x09f6d469, 0x58a14bdf, + 0x4d328bfd, 0x6a75df49, 0x2566318d, 0x3f97b7c9, 0xcdf0897d, 0x8cac57fa, 0x1544c369, 0x5f8a8368, 0x5901daaf, + 0xe7c9b7f6, 0x14d73935, 0x3b74b735, 0xdb3f7bfe, 0x01881a36, 0x8bc65d7b, 0x055fe3e0, 0x21c473c7, 0xfe7b6976, + 0xc78d5d59, 0xd631bc3a, 0xbddbdade, 0xdabf9012, 0x36633930, 0xf5d3a479, 0xcba4763f, 0x5cad8394, 0x4c711794, + 0x6d044395, 0x5089c46c, 0xfb7c91d3, 0x33635dee, 0x1c7d67a1, 0xafee82e5, 0x755c3d0a, 0x67607176, 0xf37dc15d, + 0xe6a0c367, 0xc9441b62, 0x130c42dd, 0xbae96f85, 0x6d548b0b, 0xcd9c43b4, 0xcd0df380, 0x731110af, 0xaedf701a, + 0x49462a78, 0x022d6cd3, 0x9b317afc, 0xcf9992da, 0x2c12a18d, 0x4c7f19c3, 0x768da276, 0x7d1486b6, 0xdc3705fd, + 0x40977d87, 0x06f83e8c, 0xd5435ed8, 0x8f0a3b54, 0xb2fcaf84, 0xd2c7f0bf, 0x9f797351, 0x4f97d7eb, 0x1dfd43c1, + 0x92da4351, 0xb65fe40b, 0x8acd744a, 0x22a2c05c, 0x1f1f0de5, 0xf09c190a, 0x571566c9, 0xc3d4c51e, 0x3b57766f, + 0x77c5c394, 0xf656f0c9, 0x7edabcd7, 0x84b40f38, 0xfd4026cc, 0x5da1b7a0, 0xb35925b0, 0x56a003fc, 0xf403e671, + 0x5eb3f5eb, 0x00d726b3, 0xafcb8238, 0x74497bc4, 0xb4ab991b, 0x53c498b5, 0x0124465b, 0xffe31a19, 0x826aa3b4, + 0x2cd6ad3a, 0xa42073cd, 0x9f9e060d, 0x0f285262, 0xb0eb53b3, 0xd8393b5a, 0xeae896c0, 0x06c036e2, 0x3bfd0aaa, + 0x93bed6c4, 0xb4fe213e, 0x143079fb, 0x29e66b47, 0xbf5f1dcb, 0x8ff58447, 0xfd0e81f1, 0xc559b04d, 0xbbd932c9, + 0x227acce1, 0x8b94da8d, 0xece1f985, 0x6c6f41c5, 0x1ef92bbc, 0xd216a218, 0x2cffb3bc, 0x139970f8, 0x79f46a04, + 0x4eafb7ab, 0xf5fc0d0d, 0xd2cd06c3, 0xfb7226e3, 0xdac0ab42, 0x12fadbb7, 0xc236d5e0, 0x59a48401, 0xbcd9c682, + 0x6bf1e557, 0x8144fb51, 0x5d0ca7bf, 0xef07113a, 0x4a1c3be1, 0x9a534126, 0xc40f1373, 0x074f0b4c, 0x22d8fc41, + 0x3db12dd4, 0xd3549dfe, 0xe4de9b58, 0xa291b44d, 0x26f73818, 0x5da38350, 0x59944232, 0x54b70a52, 0x09c7682d, + 0xe8f92ec0, 0xd3d7ffa2, 0xcb91413a, 0x7b6c4da4, 0xd81f8793, 0x2df74d6c, 0x8c118d2d, 0x5bddd12c, 0xc5a588ef, + 0xe0150b30, 0x0674cca6, 0x4ad21352, 0x46513388, 0x94c87eb8, 0xdf471933, 0x958d500a, 0x69351f95, 0xa96b9743, + 0x75ad92a9, 0x28127914, 0x41fc674d, 0xe2444057, 0xc728af7e, 0xc5d72179, 0xa687e4a6, 0x064b327b, 0x7c7ea5a2, + 0x188cb979, 0x2151890f, 0xb63d34a8, 0x9c0bd8fb, 0x10e0bc49, 0x33926da0, 0x70738f2d, 0x1d32498e, 0x8b1489c2, + 0x5211dd14, 0x6f43f814, 0xa73902a8, 0x61562194, 0x8b02e000, 0x04dab1d5, 0x6a99eac2, 0x57466f68, 0x5839c24e, + 0xe063a594, 0xd35bc19f, 0x448bc20e, 0x73d3c82c, 0x6cdf2b41, 0x71cd3541, 0x4998d263, 0xa31be85c, 0xced2217b, + 0x4448f29c, 0x4fd936ed, 0x5882a593, 0xbbd6f67f, 0xff97141c, 0x68562d03, 0x178b4981, 0xd33e891e, 0x5cfc1446, + 0xd72b7909, 0xa58618b6, 0x96fdf579, 0x0d70cebb, 0x34ff4d4a, 0xda380ba8, 0xd4493ef7, 0xf9c1c856, 0x93e67d6a, + 0xe76c34b5, 0x2c03caa4, 0xf6e3a75f, 0x256378be, 0x0f6babf3, 0xd1148f49, 0x2ff97d22, 0xe2cb9881, 0x236c30b8, + 0xbb115484, 0x46e526f1, 0x38e266e1, 0x2d2df796, 0x4218d1ae, 0x70cf0971, 0x429307d7, 0xa3ba104a, 0x8e0a934a, + 0x91a9d09c, 0x93fb3126, 0x07e6c232, 0x866ee227, 0x12e95603, 0x83d48ed5, 0x7d83a699, 0x46e96ef9, 0x79955e52, + 0xbb2a0488, 0x378a4002, 0x35590a5d, 0x0b4602c9, 0xd85d2e59, 0x6dd05258, 0x04848b8f, 0xf385302d, 0xe719442d, + 0x46d019e6, 0x36527078, 0x5b5b05bc, 0x7d82b35c, 0xe1da26b7, 0x066f60f3, 0x76bef325, 0x90118c97, 0x71f45b34, + 0xe1b69a68, 0x97b976f6, 0x3756d708, 0xf0b0a322, 0x432a240d, 0xcd562ce0, 0x0e165e9c, 0x648319a7, 0x9014ba00, + 0x86792dc8, 0xce608d03, 0x64556639, 0x655a3b05, 0x4a4fb8dd, 0x58b028fd, 0xc071b9d6, 0x68f5bf57, 0x9b4e1f76, + 0xf376d2d7, 0xc6362046, 0xea970856, 0xca644f7c, 0x2c205a54, 0x93be0e82, 0xfcaab7eb, 0x61a51050, 0x3f1a552b, + 0x98c010bf, 0x7fa2bc66, 0xd5babe76, 0xc43ec015, 0x966b1d42, 0x20495411, 0x2b3f45ba, 0x40295a19, 0xae29e352, + 0xdcc6f927, 0xe46c2233, 0xe63efeb2, 0xcadb4bc1, 0xb02b5054, 0xbc467891, 0xc02a92dc, 0x64be01f7, 0x7959aaad, + 0x4e7ea6d3, 0xcac833c2, 0x554c1810, 0xf1bb381e, 0xb3404b79, 0x178c9ce3, 0x58048963, 0x19eadc95, 0x2f4b271e, + 0x73ff18a6, 0xc9c009a0, 0x92e02e84, 0x96383f54, 0x9f677ea5, 0x50ee8085, 0xadde4a1b, 0x1eda0f47, 0xc6a5b865, + 0xdc36248b, 0xf3674083, 0xf5569fa0, 0x6b975c38, 0x6cd7394c, 0x69026977, 0x023aead0, 0xefd0a138, 0xb5b6971a, + 0xca15c463, 0x1fc85f67, 0x584b9263, 0xcee547e5, 0x17bea0ef, 0x0952856b, 0xcc182cc6, 0x815a7d8c, 0xf095b277, + 0xc1846d59, 0xbaa5d5c9, 0x23941f7f, 0x3c35069a, 0xadadf32f, 0x68f0582a, 0x5c0ba566, 0x4ac70903, 0xff4ff9d4, + 0x23409d08, 0x647f6816, 0x23322522, 0x114a3853, 0xe20ab1d1, 0x0da5918a, 0xcdf2b50d, 0x7acca01f, 0x0a76a111, + 0x8f0704bc, 0xba99d53e, 0xae02ddf2, 0xa2798ca1, 0xe13b5e11, 0x40177b05, 0x669f22b6, 0x17499be7, 0x9844825d, + 0xf63f902d, 0xe10c9d0a, 0xa5d03e50, 0x994920eb, 0x177c6fd6, 0x0cda4e8c, 0x0f0026a3, 0xdf011fad, 0xe82ad759, + 0x535f5eb6, 0x9a183845, 0x3324a6a9, 0xa6f24392, 0x81e60494, 0x3b970fa5, 0xa2d93305, 0x38b514a4, 0x1bcb7963, + 0x85f804b9, 0x0d04dd71, 0x99b52b02, 0xc96ecf25, 0xeb0c7f8a, 0xc07377ac, 0x2a8093e1, 0xc58ecd42, 0x09b50e64, + 0x2788021b, 0x9591cbe7, 0xd28bcb64, 0x130421f0, 0x0badf8e6, 0xf30a09c3, 0x8209b0b7, 0xa83b3e0a, 0xd92a1362, + 0xd44a0eb7, 0x8e130ab1, 0x01705b8b, 0xcb97fdfa, 0xd8add789, 0x07655228, 0x8226c879, 0x94b6d928, 0x479dff70, + 0x45afafb6, 0xf6d197d0, 0x31c28a0f, 0x443f4694, 0x73f7e8dc, 0xf66b7c87, 0xa9dec80b, 0xc58e4135, 0x16d04917, + 0xd2cf2dde, 0x8ef4f42e, 0x414da098, 0x00b78b3c, 0x01437f69, 0x70f0c1bb, 0x01adf61f, 0x8e5c0330, 0xb1145f03, + 0xd4ceee73, 0x3c49cdf0, 0x65841e85, 0x7cd6032b, 0x41b4151d, 0xf091f0f2, 0xeab55ace, 0xaf6f9f57, 0xef26a3f7, + 0x65341ad0, 0xf257bc57, 0x54352132, 0x30797d6b, 0x2ecd8c66, 0x28775867, 0xc9103331, 0x494f4c7c, 0x4285163a, + 0x5a905848, 0x8e3787db, 0x5593f2fe, 0x08cbd894, 0x98b58407, 0x52bff2b0, 0x1c29925c, 0xd295b40d, 0x0e6f598c, + 0xad99d88f, 0x5de0ecbc, 0x9625c3be, 0x3b7d5ee5, 0x9dd37cd5, 0x42f52f64, 0x2b304250, 0xbdc4321d, 0xc3e6fd29, + 0xf1e24927, 0x54625db3, 0x075064b7, 0x0dfa56da, 0x8af4d69d, 0x01139ceb, 0x1f17b50d, 0x7c79036a, 0x972ba0b3, + 0x454e7baa, 0xd1e5e85d, 0x0ae45d31, 0x61ad4b39, 0x0f2bf770, 0xdc0addc7, 0x6c9d4899, 0x580a82e8, 0xbd1eb48a, + 0x893c6b2a, 0xb3411b15, 0x83725458, 0xfa3a84a3, 0xb47d44fd, 0x6d78779d, 0x29c59a42, 0x53715a6a, 0x276301be, + 0x5ed1f3a5, 0xf041661a, 0xa43f0d6c, 0xf92ee9d9, 0x8afcf1d2, 0x63fcd553, 0xe443b4f5, 0x59ade4b8, 0x4d5975db, + 0x0d121e4c, 0x92694b07, 0x621f8702, 0xd11a7974, 0xce935c4f, 0xab8f2652, 0xf1711148, 0xff63f6d8, 0x301b88a6, + 0xdaae26e0, 0xcb7d8b10, 0x222c6ca5, 0xfd4117b6, 0xd715b7b3, 0x9246ae3c, 0xdca424cc, 0x71e5a132, 0x15a0f7d4, + 0xe125954d, 0xa6ae86cd, 0x645f26db, 0x0e6f3726, 0xefa0b22f, 0x86d16431, 0xc0c93837, 0xdee93180, 0x7e9112da, + 0xd931682d, 0xadc9e26a, 0xb3c33233, 0xbb1c1dfc, 0x5f65917e, 0x2a5149ec, 0x5fce0899, 0x05fa8756, 0xe1174236, + 0x17ab2bd3, 0xf4f0237f, 0x89fafcb1, 0xe1a6a286, 0x9abfe902, 0xdf931b8a, 0x4d7bd78d, 0xbf38d14c, 0xda889cda, + 0x3ca63cfa, 0x58c54da6, 0x4c42034f, 0xa801c2ee, 0x06c5618c, 0x1632fbba, 0x6b9a2ddc, 0x0a4b6d71, 0xa6c3412d, + 0xfad94d0e, 0x6e6886b8, 0x947cf994, 0x311951cd, 0x1970a7bb, 0x3b2c15a5, 0xcedc5ec4, 0x6943bc16, 0xf9f86052, + 0x4cdfd643, 0xc8bd44cc, 0x2ece9bec, 0x573b828a, 0x6c2b8a52, 0xd9f46231, 0xdab68efb, 0x46a681b8, 0x73b1390a, + 0xeb472404, 0xc7ccdf1a, 0x78f5c4c5, 0xdb5fe890, 0xc00d24e3, 0xe6432fab, 0x4d983e23, 0x00acf809, 0x4a7b3035, + 0xc777d730, 0x3ae6a8aa, 0xa450feb6, 0x0bfc0ba9, 0x0c1d5792, 0x97d81971, 0x2bae62bf, 0x5c73e19a, 0x809d9459, + 0x36d96727, 0xf21e06be, 0xba9e3eab, 0xe6ead39f, 0xb7bb8e80, 0xd8d8b7b0, 0xafd2756a, 0x6508e587, 0x10f7d1b3, + 0x47253546, 0xa817d943, 0xc6d4bc8a, 0x4d60fb9b, 0xe856a29b, 0x6e422b89, 0x970015e4, 0xfaf5ba27, 0xff293841, + 0xb467b1bf, 0xb807808a, 0x30105290, 0x09ba1a01, 0x13d84c0a, 0x341261f2, 0x015e4220, 0x53bee000, 0xcb1f2f11, + 0xf79b65a9, 0x1916ac3b, 0x103db98b, 0x011cc41b, 0x449d6522, 0x49d3829b, 0x1241fa88, 0xa8ff2d04, 0xa1d922a8, + 0x8260d2d0, 0x3af9faa4, 0xc1bff93a, 0xd1f85ecf, 0x849acb3b, 0x6946d8ee, 0xe7c22401, 0x043798b0, 0x17f1296c, + 0x862608ee, 0x812df422, 0x74305512, 0xa1d6647b, 0xb1cfbc56, 0x5c8d22d5, 0x179773a9, 0xdc59774b, 0x113206d0, + 0x1d1480ef, 0x547a9d31, 0x79ce5564, 0xfadeef1c, 0x1b430e23, 0x0b92811d, 0xdd45536e, 0xea040530, 0x5a17d2d9, + 0x790a0ee8, 0x6bb1fedb, 0x192fa4c7, 0xbd6b6c75, 0x0e7ec62d, 0x5dd5b26b, 0xfcc51d2a, 0xcb689a58, 0x9020a2d2, + 0xbe555860, 0x88df34e0, 0xadf18b46, 0x63a185ec, 0x20053241, 0x74ab868b, 0xeaa08a1a, 0x84c995a1, 0xcf4bcf50, + 0xb9ff6a14, 0x218ee66f, 0xfc979418, 0x36aae6c7, 0x7b2feb88, 0x144835d1, 0xb86b3ef3, 0x97946260, 0x5f1843a6, + 0xdc76492e, 0xd0aba61d, 0x03d08b1c, 0xbb4a2134, 0xf3209f0e, 0x0e81be07, 0xea68045c, 0x7ef1db26, 0x9cf6d3ec, + 0xc56aa453, 0x7e44a0ba, 0xba3f6de7, 0x99edfddd, 0x6297e032, 0x8e81647e, 0xfba74990, 0xb8324ca9, 0xbffde81f, + 0x96ea53b1, 0xafa0e083, 0x0462ea31, 0x77b7e5fa, 0x2004a59d, 0x11a8302f, 0x93c9a683, 0x8c1ecb06, 0x3fa88ffc, + 0xd00cc341, 0xe91a259d, 0xa53484fc, 0x31edc9b6, 0x8ae6d67f, 0x8951c97c, 0x37484e2c, 0xcf9ea221, 0xbffe07fe, + 0x02f1fa61, 0xfe5db5ca, 0x70146a3d, 0x6dab779c, 0xab13ae31, 0x05812725, 0x4ae6743c, 0xf51d6fd8, 0x29535d49, + 0xa175d762, 0xa508578f, 0x370d0f61, 0xdd36d8cd, 0x8a321920, 0x0f293d2e, 0x5e2b1a6a, 0xdd37a5b9, 0x31531dd3, + 0x5e8de28f, 0xe28e6d68, 0xedacdceb, 0x8666d0ec, 0x94954e9d, 0xd744e726, 0xfbdfce2e, 0x6dd73a3f, 0xccb6b501, + 0x51243692, 0x64e92903, 0xc91ddb22, 0xf0ed1f66, 0x4286ea38, 0xc539bc80, 0xec8d0948, 0x978f9630, 0x835df5d7, + 0x3ad1e436, 0x49917e3b, 0xb89e745a, 0x22d5ec2c, 0x29ff3a17, 0xebcdd36e, 0x4e7b7891, 0x65161cba, 0x2a3e8907, + 0x21e54fbb, 0x362e2ba4, 0x46d8e332, 0xd20913a4, 0xd107f4ea, 0x9a01d93f, 0x0ba8b62b, 0xea827b07, 0x1a2ce552, + 0x4a56888f, 0xe9a86209, 0xd8687df6, 0xb69de398, 0xef93418e, 0x3de11533, 0xd57b68dd, 0x291637bb, 0x64cd9fcc, + 0x631f770c, 0xd159776f, 0x2027b2de, 0x15523ccb, 0x94b0b453, 0xbf258a2b, 0x26b6792d, 0xccb23fb3, 0xe6b3b803, + 0x9f648fa5, 0xdcbb45ee, 0x8b1c954d, 0x6f1047bf, 0xc5220e0d, 0x94ce58dc, 0x1b770747, 0xc908297e, 0x593be9d4, + 0x6a4a884d, 0x1ca78e6d, 0x29ce022f, 0xaa05b5b7, 0x166884d9, 0x57b7a9db, 0xb423e3be, 0x4f538c03, 0x0d4407ce, + 0x783c1699, 0xc83e45e5, 0x23d9d00a, 0xaeaa8926, 0x208412f2, 0x2c29e7e7, 0xfbb49bcc, 0x085b3ae5, 0xbc5e3caf, + 0xf13a78d8, 0x0220ad54, 0xc522cf83, 0x808e456e, 0x42536335, 0xe5816952, 0xd2e8981f, 0x516cbf13, 0x89c2f54c, + 0xd650fec4, 0xc921bd42, 0x4c108b5a, 0x28f31378, 0xe9adbbc4, 0xeb23d7ff, 0x205562a1, 0x0fb7d7da, 0xb78742da, + 0x463bea31, 0xbe867f19, 0x4769070c, 0xf4ec53b2, 0xf856a24a, 0xee0ec774, 0xfb1d4ff5, 0x825e4317, 0xedd96bb1, + 0x1ed818a4, 0x59f919f9, 0x2d20d000, 0x8a5b1a07, 0x4074957d, 0xaf50beb3, 0xa15e6282, 0xf9669249, 0x5256c051, + 0xc79e83bb, 0xe31ba545, 0xff9afd62, 0x958c20ec, 0x4e0233fe, 0x455f244a, 0xb00d6976, 0xe0208a96, 0xe4ac6954, + 0xe39eb954, 0xe7b8c026, 0x6b18ce93, 0xc85f07a4, 0xece091ad, 0x6c816807, 0xcbb45151, 0x23c8b81c, 0xbc5b888d, + 0x26ff62ca, 0xd26362bd, 0x6a57fff7, 0xb0b3f08d, 0x48c65e42, 0xe742f7fa, 0x63bc79be, 0x847599a2, 0x320ff0c3, + 0xfdb5a4ec, 0x3e9ccf88, 0xb22f867a, 0xd0a40d5c, 0xcd58c733, 0x3e949ec0, 0x911afe67, 0x15205939, 0x3ad5f5cd, + 0xa4b6fe35, 0x93e774d9, 0xdeeb61a6, 0x5fa2ddf4, 0x7e737625, 0x605c2233, 0x858fb52b, 0x1f953d56, 0x191a3b1c, + 0x7cda46cf, 0xf020578c, 0xe2ed09ab, 0xd5e58b5c, 0xa8cf7360, 0x917586e9, 0xa8a566e2, 0x7fe361dd, 0xbdef6fa8, + 0x4331e780, 0xabd8113f, 0x092c2da2, 0x3e3c56ba, 0xdea07b90, 0xa34f751f, 0x3f9761cb, 0xcfdda5f9, 0x83784adb, + 0x14e9e0a0, 0x7e5761d4, 0xb6bd2a6f, 0xef6de007, 0xdde4f604, 0xa0d41f08, 0xa5a23c17, 0xb42f130d, 0xa813fc79, + 0xc658b2ba, 0xe51352c5, 0xde5306f8, 0x264c0517, 0x6970f6b0, 0x689182e0, 0x80f6ed5f, 0x84b4a7d8, 0x5218535e, + 0xabfbc9ff, 0x3ed2b060, 0x5bdc634a, 0x7ebe05a3, 0x553ad471, 0x9c99f60f, 0xd463f40f, 0xc12bc40d, 0xa9cac977, + 0x17ad9da0, 0xc2e05803, 0x1483be56, 0xa61965bc, 0x57ac5ecf, 0xd88b223b, 0xd11e1eca, 0xaa015b28, 0xbb62cc24, + 0x3b518d4e, 0xe918e4c4, 0x7722ca50, 0x7d2b0e30, 0x42b62e6b, 0x55422d6f, 0x29029751, 0x9ba8b195, 0x1016beac, + 0x5eb9a4a4, 0x9f82d8eb, 0x3034ac7b, 0x56f04c40, 0xe68e24ce, 0xec5a16c0, 0x4d17589e, 0x883fcd89, 0x961216ee, + 0x5152ff70, 0x3739b132, 0x02e8caf8, 0xddc66b27, 0xbb911be6, 0xb60c63e9, 0xa1fad3c1, 0xc7992f87, 0xf87c1f5c, + 0x5b7c2688, 0xef8ac038, 0xaeba80b2, 0x5cce778f, 0xfb6729df, 0x5d5fc68e, 0xa9651f50, 0x4485881c, 0x1d284b31, + 0x2cacf2fb, 0xc6fc1f58, 0x4c7944f9, 0x2f016d17, 0xa80c8ef9, 0xc30bba18, 0x7eb71f25, 0x1bb3aca6, 0xfc55fa60, + 0xe6fb259d, 0x9b2fb509, 0x5b858469, 0xe21654c7, 0xc4c4062a, 0xe0f280b5, 0x3889b62c, 0x19a21025, 0x4a25fde1, + 0x5bc625fb, 0x4efb827d, 0x6bdec88e, 0x9f354b0f, 0xd4bc8ab2, 0xeb3e36ca, 0x54f5c667, 0x43bdda5d, 0x042ed9d0, + 0x5051964f, 0xdfcdd24d, 0x3ba6f352, 0x2e0423e2, 0x1387c3f0, 0x6e7405d4, 0x191a286f, 0x48e6349b, 0xf2b5be37, + 0x57c271ea, 0xbfce4be5, 0x0d6978a7, 0x69f0395c, 0x0c9c83cf, 0x6fecec78, 0x007df4e8, 0x0c7c36a9, 0x15728197, + 0xa0458f8e, 0x87159e16, 0xbf3bfe11, 0xfaeabd86, 0xeccbfba4, 0x1ba7a334, 0x29f6a166, 0x13cb811f, 0xa887149a, + 0xe048bf7d, 0x5607f113, 0xab0be850, 0xd4f30b61, 0x76e24b0e, 0x5f7f3024, 0x25f7d8d0, 0x58f99ede, 0x25c55673, + 0x9182f94a, 0xeceb0157, 0x01bc0eb1, 0x67d06206, 0xf009ccd6, 0x36d73cc7, 0xf21a6cca, 0xdc3a58b5, 0x128160c0, + 0x2d442738, 0x988cf5fe, 0x4eeba0b2, 0xb195a117, 0xefc87655, 0x4265ab4c, 0x126e5fb3, 0xbb224e66, 0x2b4c93c2, + 0x293574b5, 0xe8e9de20, 0xabfa531c, 0xd75a0f06, 0x1222cb28, 0xc29ffdb9, 0x2be7f9b3, 0x457b108a, 0x7782a5cd, + 0x88163837, 0xd39750e4, 0x814d835a, 0x7a76a34a, 0xe39bc2c5, 0xc1715e2d, 0x4789c391, 0xcdcb8b48, 0xc04d92a2, + 0x473d4a06, 0xe33d9def, 0xf3ff4600, 0xa0c57887, 0xf41c884b, 0x0bbc166f, 0x2f3808ee, 0xfe60eea6, 0x590f9762, + 0x51180fbe, 0x0b226ea3, 0xc1da1549, 0x8ef9b77a, 0x267b2ac7, 0x1bb8f170, 0x78f7a0c4, 0x31c2f253, 0xdc0a7c7f, + 0x4c6b5f3a, 0x48ef6755, 0x30858f74, 0xc100a911, 0xa3d5108e, 0x23ba1567, 0x2679f488, 0x45be844c, 0x9984e452, + 0xe4286b93, 0xbf2070a8, 0x17e857ad, 0x74337be9, 0x17d45bdc, 0x87eced40, 0x0907fd32, 0xb35bde9a, 0xab6aaf0a, + 0xa5822048, 0x06c00f43, 0x77b3d792, 0x934c14eb, 0x566488a1, 0xe72cfe14, 0x52cbf0da, 0x973739e2, 0x2e70440d, + 0x5d7a4672, 0x52d854ef, 0x177285a8, 0x46292f74, 0xa2320531, 0x63d45c16, 0xb097a12b, 0x03102d02, 0x1c40c78a, + 0x2ab9bf79, 0x3b8c5915, 0xa3555540, 0xab5262d6, 0xab339aec, 0xd41a8bb3, 0xd7871728, 0x019af08d, 0xac0ed966, + 0x7b608baf, 0x55453e74, 0xd2936d3e, 0x86d10dbd, 0x4af61e8e, 0xe5e86eaf, 0x0110ff92, 0xe3bb4d69, 0x3572a1ed, + 0xc96d72cd, 0xaede4e80, 0xd9072328, 0xf1b46654, 0xa0f5a65d, 0xc6021d05, 0xf1d8e561, 0x73b55af3, 0x30794cc4, + 0xa58bd563, 0x773c5005, 0x4b595eb1, 0xd5cda4da, 0x66205c3e, 0x521e97ca, 0xd5ed6d63, 0xb1ec37e7, 0x18768c39, + 0x67781050, 0x4d39d7c6, 0x17fa51ab, 0xbf1806ce, 0x6d4d04ca, 0xe334110b, 0x388fc6a6, 0x92320c09, 0x3deda201, + 0xa4ce1672, 0xd6860edb, 0xcce66d5d, 0xa0221268, 0x04d3e1f6, 0xd53283a3, 0x317f76b7, 0xd9377f51, 0xb200ed21, + 0x4f1b5caa, 0x69fd13ed, 0x55eccb3f, 0x6a6fa036, 0x6cc9dafa, 0x5f9f61c4, 0xe65459c0, 0x461db4e1, 0xd6efb851, + 0x77e13f8c, 0x73f9d6eb, 0x1103f5c2, 0x74278953, 0x12cd7c3f, 0x10de35b8, 0x881687cb, 0x9534e52d, 0x97930b93, + 0x0bfb2626, 0xe8735a46, 0xf652b91d, 0xc2c9953e, 0x927c4829, 0xaff4110e, 0xf35cc6d5, 0x62f18f2a, 0xfbd131aa, + 0xd4bd94f5, 0x3288e741, 0x07ab58c6, 0x3424379c, 0x83de91a6, 0x9d32c619, 0x2f6ab731, 0x357acd8f, 0x349d74c9, + 0x3ba3b1e3, 0xfeb89be7, 0x98942da2, 0xb8ba1b40, 0xe70a0ce2, 0x3111900e, 0x24c9a7fb, 0xe32c119b, 0x04d8807e, + 0x838714c6, 0x9d72da9d, 0x077fc9f1, 0xce907bc0, 0xff3d3e15, 0xcc22d204, 0xfcd002c1, 0x9814b750, 0x55dc6f68, + 0x564265ce, 0x7632e688, 0xd6d0226e, 0x7441f868, 0x78d29da4, 0x3cd26d5c, 0x9e76eb1a, 0xea566285, 0x00d63e79, + 0x9ed42c6c, 0x819d4312, 0xd07e7f9b, 0x7b1f0876, 0x94eb6408, 0x413aed64, 0x1587851b, 0xcd981850, 0xbdaeab82, + 0x5692af81, 0xdc3d29e7, 0xe3d9c159, 0x426a0397, 0x059e086e, 0x65bd9498, 0xd2446b68, 0x0e8f94b1, 0x616ad527, + 0x0abb604c, 0xd7e20880, 0xf8cf1f25, 0x9158aab2, 0x5cd273ce, 0x30ac0003, 0x69d072a0, 0x19e820be, 0xc8a17d35, + 0xd623ec36, 0x4837762d, 0xc868a6f4, 0x6f86ba0f, 0x080adcc9, 0x7eed0681, 0xec9ea1c9, 0x0e94225d, 0x71efc81f, + 0xcf82f68f, 0x8b73939e, 0x28f03b50, 0x8eaacec9, 0x41988287, 0x8ab090cd, 0xee6d99b0, 0xa6145d84, 0xf97ebc05, + 0xbe10997e, 0x82636545, 0xe021cbd0, 0xd0beef88, 0x888eb08a, 0x8ac948a5, 0x3e25fde6, 0xe26a876b, 0x311e99bb, + 0xf927f086, 0x7dbb5e83, 0x2c81a9be, 0xa9d31358, 0x8160d330, 0xd6971b44, 0x8af25ab2, 0x2057985b, 0xd51927bd, + 0xfc20c96b, 0xe9be0fe2, 0xb27fc319, 0x21a53858, 0xb3f5defc, 0x31ed5282, 0xbeb63ca8, 0x0137ce8a, 0x4ec27b96, + 0xcbb325d4, 0x4dd220e7, 0x29bf9c22, 0x2d1192da, 0xcd583677, 0x4eac967b, 0xa627332b, 0x7d8800b2, 0xa10e611e, + 0x9afbd604, 0x756b03b6, 0xcb084fa3, 0x300a916a, 0x9d029132, 0xbd7a94ca, 0x01ef322a, 0xe323f22c, 0xd315da33, + 0xae382d74, 0x4c7f8cea, 0x6da32d1e, 0x34552aaa, 0x854f5932, 0x8529c710, 0xc07073c9, 0xde98cfa1, 0xf1188f9a, + 0x43e159c9, 0xf1c3d0ad, 0xcb6efb46, 0x91982473, 0x7bb152b8, 0x2de59c9a, 0xca910b6f, 0xc095b4f2, 0x2444a128, + 0xc51812b2, 0x1c20e76d, 0x97ef4644, 0xeebad8cf, 0x8b4f8d7a, 0xe0c3030e, 0x68fee6a4, 0xa8f207fb, 0x8a4d6837, + 0xd74ec1a8, 0xdb3d86df, 0xc6130788, 0xed17e068, 0x79b78b01, 0x45544e2b, 0xb91522c1, 0x54df4d11, 0x02224bfa, + 0x47b37177, 0xe954ea39, 0x1f0aa96a, 0xd8f54b29, 0x2f039789, 0x96a08d96, 0x7e4da388, 0xaeddddb2, 0xaee475f4, + 0x908ca822, 0xbeaa2fe0, 0xe4289745, 0xe275e63d, 0x74cfd882, 0x2ecdbcf7, 0x1694beda, 0xbf1ceb11, 0xbe04787f, + 0x76134168, 0x1cb378da, 0x433dc638, 0x900f917b, 0x8a6b0e20, 0xb48458ce, 0x3507d278, 0xb093ad52, 0xa80ae96d, + 0xac1c3695, 0x5500c8de, 0x62587fea, 0x53a17627, 0x4bdaf066, 0x4efe5bf8, 0x0a7e54e6, 0xe25100a8, 0x41b97e89, + 0x095aaef1, 0x479918b1, 0x68444a94, 0xd9e74102, 0x6942cc92, 0x85b5b66a, 0xecbd7697, 0xb4c35f81, 0xd2afcdcb, + 0xf7ed3796, 0x1972f35d, 0x3b4a4b67, 0x6d95f0ef, 0x4d671d84, 0xa1a8aeda, 0xfba0228f, 0x5dac2f04, 0xbad38de9, + 0x5641a613, 0x99ab7545, 0x1952eedf, 0xa1343abc, 0x3fbd6947, 0x74ac517e, 0x40329c13, 0x0c9d21ce, 0xd35bca2f, + 0x6e9a0e62, 0xe949a2d6, 0xa5a46848, 0x52902d21, 0x878999b0, 0xa2df618a, 0x50948bda, 0xcc714a5c, 0x509597e3, + 0x51ac1f7f, 0xf95b1e86, 0xbecebd25, 0xc1b86e2e, 0x52361ea3, 0xac3db1cb, 0xc994e55f, 0x6afbdd6c, 0xd87c983f, + 0x1ddd7c49, 0x3be97306, 0xe0cad405, 0x8d8b0dd8, 0x93b4a5d9, 0x0636132f, 0xd37ed072, 0x0dbb7f3a, 0xf0571d95, + 0x2fb2bf9c, 0x0400d99b, 0x938e63cf, 0x9ee012fc, 0x5a88df46, 0x2a753c3a, 0x3fa1a0a8, 0xcf8a85ca, 0x8c28908c, + 0x38dac97a, 0xcc5302f0, 0x095641e3, 0x9db06401, 0xd0736c47, 0xcd5a6fa3, 0xba5722c1, 0x471ac1f4, 0x27dcf992, + 0xb3b88b9b, 0x0005af4b, 0x06e7a117, 0x2ca8c1a5, 0x8a32f472, 0x247e08f2, 0x38e3360a, 0x0cbea744, 0x8fa1286d, + 0xb018d224, 0x23e25ddd, 0xe841db8d, 0x523e8c98, 0x04b745c3, 0x5aa3cfa0, 0x8ebaba24, 0x2adf2dba, 0xf3bc7f3a, + 0xeb0bf7e9, 0xd28390ea, 0xcfec0c50, 0x605068ec, 0x8d4ba2cc, 0x77b7919a, 0x8ce953c7, 0x87811887, 0xae3dfb9a, + 0x0ca9597c, 0xd9646886, 0x8060233d, 0x48933e20, 0xeca29088, 0xbc79dbfe, 0x799d8abc, 0x356e1c23, 0x67ae81b5, + 0xf5f92cc9, 0xf30ffff7, 0xbf4bd356, 0x66264c94, 0x88dbcdbf, 0xa730d7b5, 0x24670b2a, 0x49a1e65f, 0x9d7b926c, + 0x06d06755, 0x2cfe088e, 0x5a02df8f, 0x6c50b3d4, 0x4f3069df, 0x70dd0883, 0xb4ed46e2, 0xf24bcc0a, 0xaf43a772, + 0x69268d50, 0x543bf806, 0x35641c9c, 0x6d529141, 0x28a01f89, 0x86ad6b4e, 0x7bab051a, 0x42e38d32, 0x0d40306b, + 0xebf81d80, 0x62ccb665, 0x3bf6b35d, 0x091a9171, 0x7d75a944, 0xae84e64a, 0xce1c1ca6, 0x66624b40, 0x5481dd19, + 0x52ab4e66, 0xdcff9ce8, 0x32dc464b, 0x325b7366, 0xce5aaa72, 0xd7cedb3a, 0xe3faa972, 0x4b6c9fa5, 0x2cc9acb5, + 0x14e6b575, 0x388efec2, 0xe6d3f3a9, 0x4382b0a3, 0xb3b0c0fb, 0x5181ca3d, 0x13af41e3, 0xe90da07e, 0xb1c9ae20, + 0xe4b99c87, 0x2b87e2bf, 0x7b085338, 0xef810f78, 0x807efbf1, 0x5e4a32c0, 0xfd508699, 0xff501df4, 0xdea71e14, + 0xb6991a4a, 0xcdb2ae7b, 0x78113041, 0x88fc38f8, 0xd1bee96a, 0xbb3092b3, 0x33ca57cd, 0xdcd98a7c, 0x45e67dd9, + 0x02074e18, 0xb785c5e5, 0xc843a53e, 0x17f7a898, 0xa2d4fff5, 0xa1d81b84, 0xa60ef7ab, 0xc86b1379, 0x7b22324b, + 0x36efa0d8, 0x8a1220ab, 0xf992a37e, 0x2d0e2521, 0xa25ac868, 0xe3765667, 0x4c4483a3, 0xca050e46, 0x209db9b5, + 0xccd129b4, 0x873e4c27, 0xef09d1d7, 0xf00d948b, 0xe27a8219, 0xaf991ece, 0xc94bba08, 0xbf0c1971, 0xc85055f5, + 0xe87006d6, 0x2d685da1, 0xf7221861, 0x85e2baa6, 0xd2e56127, 0x0e92fc97, 0x80287a10, 0x5c7ffa81, 0x0f2cb9b7, + 0x620058b7, 0xc2610865, 0xdff943aa, 0x00d7eb23, 0x5187334d, 0x00b493cb, 0x26b15f9e, 0xc2a90f32, 0x1f7dc514, + 0xa6c77281, 0xc9a5c4c1, 0x6e5d57d3, 0x2cce66e8, 0xf1ef6f4d, 0x9e2575ee, 0x30c997c2, 0xba0c43e2, 0x587f8648, + 0x13b6a6d4, 0x16d9bc0c, 0xe8498076, 0x29495239, 0x6ddd37c3, 0x1ac780d9, 0xf7e7f8cc, 0x43d8480d, 0xdaf62a78, + 0x5d03a383, 0x834db6d4, 0x417a508a, 0x32d0c88a, 0xd5dc9f1b, 0x4a5c0423, 0xfe141773, 0xdc61272c, 0x5fb05a09, + 0x9fd360af, 0x0eb8fb5c, 0x4b6e1050, 0x026994d3, 0x1a5cbfab, 0xc07a24da, 0xe297ada6, 0xdb764dc5, 0x8148579d, + 0x996a8a8e, 0x1faab79f, 0x1321c46a, 0x37465169, 0x5f2f9942, 0x84c70ca3, 0xfb772ad2, 0x89a0a767, 0xfe38ad4a, + 0xb3474a1c, 0x63c22299, 0xae7d2367, 0xd80407fa, 0x00f12b1d, 0x13e42df3, 0x89181732, 0x5d863958, 0x042b8fd9, + 0xd4c6debc, 0xa8ac5316, 0x8e83d01d, 0xd128d52b, 0x1cd337a3, 0x10a0b0a7, 0x08726342, 0xfafafeb1, 0x9df0a08a, + 0x825e5272, 0xfc82b216, 0x07168ce7, 0x94c55749, 0x483a7320, 0x8d8be5ec, 0x27627e98, 0x9f508927, 0xfdc550cb, + 0x8632d0f5, 0xffa18546, 0x28325696, 0x7e1961e3, 0x5a320638, 0x7beb1047, 0x40a9fc7a, 0x6f25aa86, 0xd8c61f45, + 0xa106460f, 0x6957deff, 0xf234e697, 0x79279344, 0xb1705a67, 0xab07bb8f, 0xe12ba1c5, 0xeee4889d, 0xaafdb4f8, + 0x548e51ad, 0xcc6a0e4f, 0x72ebea9d, 0xbd16b35e, 0xd1473d51, 0x3491176b, 0x7f6bc2e8, 0x68c860f1, 0xf096c308, + 0xa4959044, 0xa492ed8b, 0x8551c3a4, 0x0a4fd372, 0x51075709, 0x0257bce4, 0xc53a16f5, 0x6691e01a, 0x153d8d36, + 0x44279bd7, 0x7e469162, 0x3e165ad5, 0x9d64be22, 0x79397878, 0xc9459f86, 0x5ad28db8, 0xd4bd342f, 0x7b9f9642, + 0x8853e3cc, 0x092c82b2, 0x36c9162a, 0x54b933f3, 0xa83c0528, 0x50bd7765, 0x2f149b56, 0xb05451f4, 0xd2323180, + 0xf4f34d7a, 0xef4de238, 0x80efde41, 0x6079a220, 0xafa38832, 0xb05a8797, 0x1264a26b, 0x48f24354, 0x4ba05728, + 0x3d8d9778, 0xbb5686d4, 0xbec49e75, 0xa0e2a62b, 0x0016ba5d, 0x52c86511, 0xfc2c3452, 0x3e17099a, 0x8f9fc3c7, + 0xca631266, 0xf4e9e329, 0x39eee0ef, 0xa3375248, 0x966ae621, 0x4c6c7a4c, 0xc90dd523, 0x6d2dc66a, 0xee77f64c, + 0xdc82da06, 0xdd895d10, 0x2e7d0e6d, 0xfae997cb, 0x7b51fb27, 0xb0086052, 0x70f9aea6, 0x2e994171, 0xc7e3b7aa, + 0xfaa8d888, 0x66b5bd74, 0xe85ceb86, 0x660b4d1b, 0x3acac950, 0x01b0adeb, 0x43db5b68, 0x451ff733, 0xa1b9ea89, + 0xfbabea91, 0x91cd7dcf, 0xcc1b5fda, 0x2e35f660, 0x48ddc007, 0x096056e4, 0xaf633e67, 0x4ff312f3, 0x7be39656, + 0x3b5c39f0, 0x0326c870, 0x8a87913e, 0x5d29bc2b, 0xc1c4e963, 0xcda9a9b8, 0xa685d96b, 0xaa130f7e, 0x1f8b57fe, + 0x6a589bab, 0xcb71e0c9, 0x47d70591, 0x13d27474, 0x619bc7db, 0x8ff46876, 0xf4f7bd80, 0xcbe873f2, 0x5ba33f14, + 0x99b4801b, 0x06ad9ea7, 0x96f986b1, 0x7d9c76d0, 0x22830e2a, 0x767d94a4, 0x481b4240, 0x7d4e76c6, 0x608d601e, + 0x68d3890e, 0x89b2e81b, 0x67a0e3cc, 0x23984121, 0xec83c7f1, 0x8b944f35, 0xaa563d33, 0xdc03f2c8, 0xd9a10854, + 0x15353431, 0x2d90a511, 0xac87337f, 0xe144e48a, 0xf6eaca54, 0x7aa25204, 0x16c85648, 0x6ebab6d3, 0xd1a03551, + 0x2133746a, 0x3f07ac4b, 0x5274470d, 0x384b6e8e, 0x0ee866ac, 0x6c16066b, 0x614cb380, 0x80e48dcb, 0xab9a54c0, + 0x4b4e39e6, 0x398c9aff, 0x230f3b57, 0xacf676b8, 0x0c4461d9, 0x7d32f4fb, 0xaa0e2418, 0x7ddd74ef, 0x1eb081a6, + 0x97702955, 0xa5681a1b, 0xc2cdf139, 0x16398c26, 0xec4918c1, 0xbcf20148, 0x3f0885f0, 0xe747a110, 0xf6a3503a, + 0xe721ece2, 0x26cbc6b9, 0xcf22f0fa, 0xef1e2825, 0xe32144d5, 0x8c6f490c, 0x5aa166d5, 0xbe955a83, 0xad6a6266, + 0xa88aabae, 0x9545a28a, 0x6ab8711d, 0x75d0c251, 0x0a5caf2c, 0xbd19cb27, 0x954c7777, 0x34a8840a, 0xfa0d6926, + 0xd9900cf9, 0x40f38944, 0x3288d2a4, 0x5ed2ed25, 0xeac629c8, 0xd8f27e8d, 0x0109b75e, 0x20af113b, 0x6206a721, + 0x20a82f98, 0x857c11ba, 0xc981c335, 0xb325b148, 0xcf28f1c1, 0xd2007664, 0xd1925776, 0x6b7d2cd2, 0x034d37c5, + 0x1505404b, 0xd8056e1e, 0xae778149, 0xf87ad9ea, 0x115358b0, 0x17c6ea70, 0xc8d87f4e, 0xed059ec8, 0x43913e43, + 0x5a2ca0b0, 0x098665fe, 0xf2883769, 0xeb1e6ee1, 0x5d6a518b, 0x003e10a1, 0x60c05e88, 0x21f4f054, 0xeb1c4e80, + 0x4c80f2ff, 0x16fd381c, 0xd7f628b8, 0xb760e746, 0xcde13f75, 0x847614df, 0x88c9168e, 0x1b9050cd, 0xd79d1393, + 0x32da8f91, 0xf41a81a2, 0xb1bfc737, 0x988c8b25, 0xb4a24ed3, 0xa1e33fb7, 0x7f01789f, 0x0db1a092, 0x9dc85c99, + 0xde980989, 0x9e1699f0, 0x00dde341, 0x9cf204a6, 0xc80fa678, 0x3d65b0e4, 0xadea3f52, 0x57faac3e, 0x2777fad3, + 0x9326fc01, 0x9731fe76, 0x40787b8a, 0x585a9bbe, 0xad202359, 0xa7c83402, 0x6a5205d7, 0xcac0a4c9, 0xf22db4db, + 0x5258f6f8, 0xd2eceac8, 0x9f7b9cc0, 0x2251a293, 0x1f35f8e2, 0xae61ca86, 0xc33f6135, 0x65026601, 0xbe855ef0, + 0x12df1b20, 0xa93e00e4, 0x503c5f27, 0x8cd4e26a, 0x2fd99a46, 0xd6be7ac0, 0x8ae3cdfa, 0x8c5f3e57, 0x9363dd71, + 0x9e0b7f81, 0x550b8fb2, 0xf8445b18, 0x3ff70651, 0xc8497e47, 0xaa1ee231, 0x7202e87a, 0x721ebf14, 0xe2874530, + 0xa6456c78, 0x4cef7508, 0x33ec40f0, 0x274c0728, 0x9852381e, 0xca30afce, 0x79c20a09, 0x019f74e5, 0x74f845a1, + 0xd4bdbb9a, 0x4325a900, 0x4f150fa1, 0x46ef49b0, 0x3990bc8d, 0x5a358b67, 0x70b8ee49, 0xa802d6df, 0x8d5a9674, + 0x028e4ee0, 0x574f5135, 0xa36c0888, 0x844e9fa1, 0xf40015b0, 0x61b702c5, 0xbbcf8b6c, 0xa61c224c, 0xdcf97abf, + 0xbc0b044a, 0x06723c56, 0x5c4dee0f, 0xb9942cb4, 0xfe928340, 0x1d72a580, 0x2df0ce1b, 0xa49a414a, 0x54bceafc, + 0x32831073, 0xc0d860ed, 0xc561242f, 0x996d4c50, 0xb36e99ea, 0xe4fcfbd7, 0x8cc26e45, 0x4174904f, 0xdc476197, + 0x35bae1c7, 0xfe32346b, 0xbf767378, 0x31037fc8, 0x767eb145, 0xf251e25d, 0x1b7322d1, 0x3a575acb, 0x68f8c124, + 0x17898d68, 0x74b307b8, 0x66328f65, 0x7f8a0cbe, 0xb8a3dcf5, 0x42e21967, 0x2ef3fcbb, 0xb19d6442, 0x117ac02d, + 0xb56dbf18, 0x018d775c, 0x5d6bb9ef, 0x3e0f630c, 0x4ab5d835, 0x66ef8701, 0xa9ad4992, 0x3582651d, 0x52a1ff82, + 0x294fb44f, 0x4e59505f, 0x5601f9a8, 0xd08b9c6c, 0x1ee58532, 0x120cf3c7, 0xe7ad5ba8, 0xb8c35614, 0x40f0a76f, + 0xbb78e484, 0xbac37e03, 0x97679603, 0xa423683b, 0x617c0092, 0xe3388eee, 0x9556ecc3, 0xb478b19f, 0xf042b366, + 0xd17bc890, 0xc1083ffc, 0x9205f947, 0x25733ec8, 0xd391f328, 0x5756ba95, 0x539cc1c1, 0xe64de332, 0x4fe4f54a, + 0x385b2482, 0x0b2f9ebe, 0xbdefee72, 0xbbdd9a8a, 0x6464cf65, 0x32981f18, 0x58ba876e, 0x948ea79a, 0x84450780, + 0xa0a26c22, 0xaa267dc3, 0x4fd6a49c, 0x600f55b9, 0x6833f6b2, 0x31ae89ee, 0x2dd00352, 0x9c7e31a5, 0xfd2c3771, + 0xd5a9aef9, 0x439e1c57, 0xf173ef5f, 0x34b55d2a, 0x36a159f7, 0x363ebe0a, 0xad1a3c2f, 0xf53c3bd2, 0x59d621d2, + 0x31afb51b, 0xc24bb334, 0xe062ffc6, 0xaf61f5af, 0x318d45af, 0x1a0266d5, 0x44c12da3, 0x3863b148, 0x9b20cbba, + 0x1bcf1f4c, 0xd0a98a76, 0x0b7be995, 0x3c1c7c46, 0xe53ca776, 0xb39e5645, 0x5a3c379b, 0xdb9ea927, 0xaedd8a09, + 0xbb7dd6b9, 0xe8004eda, 0x8761e52c, 0x10a9dbf2, 0xee1dfc42, 0xeda3e51e, 0x70a17c61, 0xa0bb5691, 0x308e2742, + 0x9bd0e926, 0x1f043f21, 0x38e9dba1, 0x64c5a124, 0xa1893477, 0x0c0c0de8, 0xebf98a45, 0xe27ef2ab, 0x4a8d5f33, + 0xc88a6af0, 0x99192711, 0xf72957f8, 0xf6a77c91, 0xcbba2fb8, 0xff4e387b, 0xa7d5998a, 0xf77396f0, 0x5b1b691e, + 0xfd738ad3, 0xb5bd2e3b, 0xd636f1b4, 0x8068a2b3, 0x7f78668f, 0x22ed9b5c, 0xa42d7a9b, 0xb283b9d7, 0x4f62aee4, + 0x545ddb7e, 0x1c3e0507, 0x8ab89eac, 0x803a7f1e, 0x0cc62b61, 0x174da3fe, 0x64db7dd4, 0x7a5fff42, 0xbcf0a50f, + 0xe6222dd1, 0x8df26df3, 0xaedb55ed, 0x9efa05f4, 0x655afc32, 0xf8d494c5, 0xef31d80c, 0x42407352, 0xcb4f8c7f, + 0xf5f04233, 0x22c40bcd, 0x4df5a537, 0xb523d34e, 0x7f98f884, 0x8d5600c7, 0x1f1b7130, 0x37bb5425, 0x9bd23bf9, + 0x52199381, 0x14528bd1, 0x0e5c6abb, 0x33a2fc27, 0x62cdb268, 0x6b399aad, 0x9281cac5, 0xb8a32e15, 0xccf864eb, + 0xdf84f8a7, 0xbacda5ad, 0x1a6bac8d, 0xf44aec8a, 0x1b847144, 0x544eb7d9, 0x4972f640, 0xb874c652, 0x9ce7d7a4, + 0xf6e70527, 0x4999750e, 0xf7fbf336, 0xce180974, 0xd1ea96ec, 0x206fd9f5, 0x6500c3f7, 0x55d3fc79, 0x6553b4ac, + 0x129cdb2f, 0x13a5ef0a, 0xc452a89e, 0x1b3c7be8, 0x854907d9, 0x4385996d, 0x5c995467, 0x8d341a14, 0x7270f6db, + 0xdf098bdb, 0x45d7da5e, 0x7986ca9d, 0xc44ec984, 0xad0e1217, 0xa5895405, 0x92961903, 0xf9c17f15, 0x733397c9, + 0x94c81361, 0xfaf5a036, 0x69eb871a, 0x7adfc399, 0xba1a5ae0, 0x4e954218, 0x4db3df32, 0x8dc4452d, 0xdb82ccfc, + 0x060aa89f, 0xac23dcf1, 0x67942f2b, 0x9d7d5a5b, 0x726b7f2f, 0xa9052b84, 0x9668361f, 0xee948b1b, 0xa0591067, + 0x8b4ba8df, 0x2576e58d, 0x531c9621, 0x74ace280, 0xdf1d2593, 0x53d7016c, 0x5acad221, 0xafeff860, 0x2b31889e, + 0xe29ad34d, 0xef25cd11, 0xaa8a6a10, 0x2002074a, 0xf27f4a78, 0x4bc921f2, 0xbf8e3355, 0x7ae5f086, 0xd5a0f207, + 0x6ef6ed64, 0x8009acf3, 0x940e4020, 0xc92e9701, 0x3ade843b, 0x9aa11caf, 0xc0cb1ada, 0x68e2be6b, 0x982a8472, + 0xbb24b80e, 0x9b86a34c, 0xf842cb5a, 0xc82a58d6, 0xc5c0ba69, 0x807dddc5, 0x199d6ebe, 0x68ef280f, 0xadb71a9a, + 0x59a0e1ce, 0x5ded3aee, 0xb17cf28e, 0x8d0f74a6, 0x4b57c0ee, 0x40046ccf, 0xbcb64767, 0xce66d231, 0x468a4870, + 0x633fb133, 0x12a1639c, 0x5935d435, 0x920ecbcc, 0xe09535b2, 0x80d09f30, 0x6de46064, 0x0f2da286, 0x5bcd4611, + 0xdd09de2d, 0xa9c06202, 0x7aafe204, 0x4cd0feae, 0x3ef34be2, 0x014ba505, 0xdf0ef1cb, 0x2e82e975, 0x91e7751c, + 0xb080639e, 0x11348d0a, 0x6ea4f698, 0x289eac92, 0xa3e9c44a, 0x128aabf9, 0x944c6ecf, 0x5af5b99e, 0x8732ab61, + 0xb357da61, 0xdd4a084b, 0xfdbe356a, 0x9bbdcc56, 0x9837456d, 0x2e71b88b, 0xbca4a3f3, 0x69236fa3, 0xb4cbf079, + 0xd87d4b89, 0xfda028bb, 0x6a292546, 0xefdc329a, 0x672b7a18, 0x81582381, 0x204d9532, 0xcde08f1f, 0x738afeaf, + 0x4a92b331, 0x2c19d43c, 0x4f1ba8f5, 0x9b0c6eac, 0xf9842482, 0x5907d62e, 0x57b2c539, 0x66897142, 0xe49ca4c8, + 0x18674285, 0xc2abbb77, 0xa790b840, 0x68a2561d, 0x932b9b6c, 0x38813f0c, 0x32993ead, 0x05e04d23, 0x71ac6cfe, + 0x3e31ca2e, 0x3a81344c, 0x77c6c601, 0x8e925311, 0x716bc969, 0xcd72c5f7, 0x2f80c0b9, 0xc9f11d2a, 0xd9b2f75a, + 0x7b175a5b, 0x2e26770b, 0xf098da13, 0xcabfbde8, 0x3ee3f610, 0x9d605ee0, 0x3ee57c5b, 0x7ad5c291, 0x7f3a5a0d, + 0xb11df28a, 0xde186464, 0x8ad28bf8, 0x711b82df, 0x1276457b, 0x46b32880, 0x5079e221, 0x236493e1, 0xa6147163, + 0xac97ad6a, 0x3c890385, 0x5ae311ae, 0x417bdd79, 0x29bd4161, 0x664cf534, 0x87a9524f, 0xa50a9e96, 0x4d42f3be, + 0x0010e731, 0xa140e49f, 0x2a4601ab, 0xbe3c3906, 0xe0ad7857, 0x00d2f149, 0xd0dc1326, 0x4444223a, 0x08b1c7ff, + 0x2600bae4, 0xfbc6f708, 0x8ae1abcf, 0x89292cb2, 0x15dd6b29, 0x8f61b19d, 0xcc30c5bd, 0x90e196ec, 0xa9fc6b9b, + 0x07729f6c, 0xf9a1ec72, 0x896067d4, 0x94690a52, 0x409e2bf0, 0x89b5676c, 0x7e32a23f, 0x03d36d70, 0x7eeacf49, + 0x5be7d202, 0x16e9a7f8, 0x072130ff, 0x0b9dbefb, 0x6bbf645f, 0xc377952b, 0x06c3d23b, 0x2999c4c3, 0xa7d86726, + 0xbb74ca2c, 0x2e60ef1a, 0x86b908d1, 0xe4e08e88, 0xdfc74157, 0x870bcb8f, 0xe02d21e2, 0x2cbcb44a, 0xa58bc01d, + 0xdcb1ef93, 0x4f7eea5a, 0x9f198096, 0xc43cb580, 0x55b46f3e, 0x087e41ab, 0xbf52d7f6, 0x9ff2229e, 0x3fc7a87e, + 0x2cee196c, 0x8f186bdd, 0x03f26405, 0x39a2cc15, 0xe47e67a2, 0x9069a943, 0x895f435c, 0x54097d68, 0xb181396c, + 0x09743a36, 0x2b0133a1, 0xd565ad36, 0x252c942f, 0x33e45dfd, 0xacce19a3, 0xa8b0aef9, 0x0f277fc2, 0xd78f3b2d, + 0x96773a27, 0x7e11ac2e, 0x73c3640e, 0xd0ba71d1, 0xf56eedc0, 0x820a21d2, 0x6e0b1a72, 0xf313c26f, 0xd4c7c12a, + 0x24534d5e, 0xc9778abf, 0x900b7e9d, 0xfc58674a, 0xd3ba6bca, 0xde489583, 0xd22b398d, 0xd220ab15, 0x942bb60a, + 0x8d5919e6, 0xb4b489b6, 0xb6c7e3a0, 0xb2558a94, 0x511a048a, 0x178d5297, 0xe3bac3d0, 0x00f9f604, 0xe6029881, + 0x7abc0da6, 0x478fda1a, 0xbeb65aad, 0xcb2dc8df, 0xdc19c637, 0x401b86a9, 0xdaeae4a2, 0xa7d513a7, 0x5808c8db, + 0x04986391, 0x150bbda3, 0x7e772a5d, 0xa561a9dc, 0xab40cf3c, 0x887362a9, 0x4c1a782d, 0x7017023f, 0x3dcf2e7d, + 0xc11a3c27, 0xff92b7b7, 0xf8237d7e, 0x9fcbc931, 0xb1a3cbe9, 0x5342e7b4, 0x833103a3, 0xf121c9d4, 0xd3ec3fdd, + 0x6060bf7f, 0xcecccfb8, 0x239066b0, 0xcd82cff8, 0xfc67cbec, 0x3eb63303, 0x9f7eb431, 0xe871a441, 0xef23375e, + 0x3d2b82b5, 0x44935ecf, 0x398a03a2, 0xe430cf97, 0x48af542d, 0x132c9ef0, 0x1b99f1a1, 0xb8e93e6c, 0xf51b9720, + 0xb1cec6d1, 0x94bc2698, 0xd427d116, 0xdef322c3, 0xce6bdd8d, 0xdc1c21d2, 0x4c8ae0a5, 0xfa3f3c29, 0x3f2fc7c2, + 0xf2cbdff0, 0xd2943f91, 0x801e15c6, 0x84ffa436, 0x242c7149, 0xba8a4c77, 0x74c41ec8, 0x7e620b74, 0x8076a507, + 0xabb5ceee, 0x352952ae, 0xcf39c730, 0xf39d799b, 0xcc1f0910, 0x906c7656, 0x0abcc660, 0xf2e98305, 0xbba848ef, + 0xf231acd7, 0xd287153a, 0xe2ae7693, 0x072f0467, 0x7cf00b70, 0xc614a8b0, 0xd67430c9, 0x26fe1d1d, 0x59b400fd, + 0xccac8db0, 0x12aa340f, 0xcbacb519, 0x83f0de8d, 0x04c0087b, 0xcfd97c71, 0xd2926518, 0x4db7a42c, 0x6bdacc63, + 0x044f263c, 0xefaece2a, 0x948f29a1, 0xaf0a6044, 0x30c87480, 0x8c1e4237, 0x4f307933, 0x54befc24, 0x9f67be7e, + 0xcd7a56a6, 0xda92a550, 0x3ba30055, 0x11d6cd38, 0x5e7bc698, 0x6f1c7258, 0x99adde45, 0xe83cd0cd, 0x11c37aca, + 0xa8793721, 0xd706a86c, 0x55ece63e, 0xbb09cfcb, 0x8d6201ee, 0xd230ec84, 0x3877ad9b, 0x4c73d368, 0xcb9cd4dd, + 0xde9170bd, 0x1ed00092, 0x58568f3d, 0xd3d83b89, 0xbb67ddea, 0xfe7bfcf4, 0xd7548c10, 0x78756bad, 0x17b03246, + 0xdb25c927, 0x43c633d9, 0x99a4bf09, 0xc126ae05, 0xfb658ea1, 0x30924ffd, 0x51d35d0c, 0x14e81dba, 0x86fe20bb, + 0xc46ce88a, 0xdef921b6, 0xd0c2848a, 0xd215baf8, 0x6be43b1b, 0xb5f612aa, 0x7a33a123, 0xfd7aa82b, 0x1cfcd03c, + 0x1c4f309f, 0x4ea0d73e, 0x5eb83663, 0x4fcc3ccb, 0x0f21c645, 0xa80c117b, 0xe088b791, 0x82a9b16d, 0xf44ce2ba, + 0xd578b9a4, 0x4b5ab4f4, 0x4f38cf4f, 0xa3365818, 0x446ecf76, 0xd92ecdef, 0x4e9fc5db, 0x5a653d53, 0x923c6ea4, + 0xb5c38c2d, 0x797521d8, 0xbd08b9a2, 0xa33667ce, 0xf9bde0d1, 0x085539e9, 0x090ea7f8, 0x6dc041ca, 0x15ef63b9, + 0x08b55b7f, 0x009e7b4f, 0x34e6a2fa, 0xcb7ca467, 0x820c8062, 0x2bd21c19, 0x6a5870a1, 0xe0f0331b, 0x41cf40f4, + 0xbeccba95, 0xca40b8de, 0xcb1f36ef, 0x5925c9e5, 0xa653b0bc, 0xeb31d567, 0x51e52a64, 0x895dce54, 0x21be1f93, + 0xb88cfb4e, 0xa4952c75, 0xc3f47fed, 0xc984b781, 0x1a4a0b03, 0xc0402c3b, 0xd131f87b, 0x93802f01, 0x902775e4, + 0xf54eeb2c, 0x446da8cb, 0x902d4942, 0x2ec08901, 0x11d01d3d, 0x87868328, 0xca2f7cf6, 0x608a10a3, 0x1ba9b28a, + 0xfa31a152, 0xc9d3e224, 0xc5b92c28, 0x2d3355b5, 0x92cb1564, 0x742694dd, 0x648884ca, 0xfdc10c7f, 0x6cc146fd, + 0xa6e74d0e, 0xc0eb7030, 0x46cd16fe, 0x3b3dcb84, 0x868af88a, 0xe2de54b4, 0x55329ed9, 0x8ef077ed, 0x82a51c82, + 0x6c77d441, 0xfebecec5, 0x78eb0ba2, 0x995d93ab, 0x294e7e7b, 0xbf61dc66, 0x41e111eb, 0xf3de6e98, 0xf4afab85, + 0x3450961c, 0x3bf9ddf4, 0xf95d90e7, 0x590b6a6b, 0xff827980, 0x5b47b8c3, 0xcdba028d, 0x66ae888d, 0xeacda94d, + 0x577df646, 0xcb5313da, 0x2831d965, 0x3d12eaab, 0xe7367a3a, 0x129a8a1e, 0xd3c42d3a, 0xb770d401, 0x4b86a81c, + 0xd899a0af, 0xdfe0b90b, 0xbf70eba1, 0x42e058e3, 0x015787f3, 0x61dd8876, 0x81878e21, 0x409804d5, 0x7afefa64, + 0x742aa75e, 0xf9c8d733, 0xf7fb1c60, 0xd9b7f9bf, 0xc344d449, 0x8fe53274, 0x8b3a9acf, 0x1f21571b, 0x24a66ea4, + 0xa3bf11ba, 0x6a4bab45, 0x3b1d9908, 0x26eee2f9, 0x21b7d511, 0x1fa10c54, 0x52e1d561, 0x30949ea4, 0xe4d64c7c, + 0x06416411, 0x69052b47, 0x6fdb9705, 0x0c5627f3, 0x25ee34be, 0xde929666, 0xa20c4394, 0x45428354, 0x3bcb192c, + 0x497bf0dc, 0xe74327e6, 0xaa4a71f8, 0x136d75cd, 0x195d6410, 0xd3dfc217, 0x7f19f575, 0x736873d5, 0xa121f1ab, + 0x66103b37, 0x8109f109, 0xf8d25b3b, 0xbb013390, 0x5c4ac31e, 0xbef27532, 0x34ec4e0a, 0xe8713de8, 0x083783b0, + 0xa435f918, 0x2d1c92fb, 0xf3dcb3e9, 0xbf9df609, 0x7e699489, 0x2af6e409, 0xfa7e17a4, 0xb7b2ad21, 0xd1ea4a3b, + 0x69bbd222, 0x9d4c0ce3, 0x1f471288, 0x61bf4f99, 0x3cbcff5b, 0x92ebf403, 0x54a6d7e6, 0xf4327e5e, 0x71e2944a, + 0x246f9ee9, 0x075974ad, 0x6ac7a2f4, 0xbf84c24d, 0x0d462fac, 0x8be466d8, 0x216326d4, 0xf42c08bb, 0xa97540bd, + 0x85d48460, 0x655eb274, 0x519cecbb, 0x71b35c17, 0x8c5c2c05, 0x63adee26, 0x444bbc54, 0xdc843de7, 0xbd036b7b, + 0xa6b4aac9, 0x9e2f2d22, 0x9b1a7c07, 0xade3ecb7, 0xd26a3c3d, 0x4d7c8410, 0xd6f3142b, 0xafe2bdd2, 0xe76972ff, + 0x0b0491f3, 0x34de9798, 0xe629b208, 0xbb02565f, 0x684534ec, 0x547a7878, 0x4dc9d8fc, 0xf757723a, 0x24fa65d7, + 0xd3934418, 0x6784ce98, 0xc3abb6d6, 0x7b88fca0, 0xa321fe57, 0x0f24b8d5, 0xdd4ce152, 0xf146533f, 0xefbd6d1f, + 0x432f188c, 0x6ebcee54, 0xc4e31336, 0x4d97e3e3, 0x522bcaf9, 0xc3403b43, 0x78307908, 0x6e27d22c, 0x89b1d7f7, + 0xff45edfd, 0x39d4b854, 0xa408eefa, 0x68be0494, 0xb29a0b11, 0x63f24977, 0xee0d5841, 0x31936ca0, 0x84d63d8e, + 0xec307ffc, 0x98815192, 0x26aa8abf, 0x5656a678, 0xd5ee5306, 0x214d7d94, 0x2aca5d08, 0xd4b2a46e, 0x0e6d056d, + 0xe3cc986d, 0xa7f3724a, 0xcd7b04f1, 0x3c00ee16, 0x7ea8d669, 0x5bec43b0, 0x7e66cb3d, 0xdad2cdbe, 0xb64a87cc, + 0x731969d0, 0x24196852, 0xa40b908a, 0x16d70ff3, 0xae1bc65d, 0x61271098, 0xf2512bd4, 0xd15eaf78, 0x401fdff7, + 0xc5c12fbc, 0xbf50a6f4, 0x2dbf9487, 0x5cac463e, 0xa47cd051, 0xe8c53c98, 0x25746a4b, 0x10fe81bc, 0xd5038a1a, + 0x01f73fd1, 0x355cc896, 0x0c6ac8d8, 0xc3c24eff, 0x57744f00, 0x977c9dc2, 0xf0c318f3, 0xeb99b641, 0x93ca271a, + 0xb2d0c086, 0x6287cdce, 0x1ea7cd14, 0xb6b64e2f, 0x3250e8db, 0xc9c3e1d7, 0x059ac3d9, 0x05b28b83, 0x0b5bbfe0, + 0x034272a3, 0x69229a46, 0x4cc8c915, 0xcdd9d2f1, 0x3ad32727, 0xaacbabae, 0x3ce33873, 0x3e5fd1d9, 0xe2ee3eca, + 0x9e47c60e, 0x76379e39, 0xfea3a0b8, 0x80318943, 0xb4726c49, 0x187fcc74, 0xcfab7d1d, 0x277bd4e3, 0x2278bd04, + 0x64d2997a, 0xce08fc9f, 0x745f4ea7, 0x99f3571e, 0xaf66083d, 0x659905c3, 0x76fdbf52, 0x2cdda011, 0xfbf5bcd0, + 0x7ba51110, 0x9358ecca, 0x89293f26, 0x83c1e9bc, 0x8034833b, 0x175a37d5, 0x8ff16a74, 0x3187c2a8, 0xa8bfa574, + 0xf6f3b116, 0xc8a4a165, 0xec4e5f71, 0xfd5d186c, 0xc327d593, 0xb048246f, 0x90f15eac, 0x547c8353, 0x650ba1e0, + 0xd7769c94, 0x21a96f80, 0xb9729346, 0x44aa3836, 0x310ce57f, 0x9a30390a, 0xcfa39a58, 0x9984be77, 0xfea2065a, + 0xbe998edd, 0xc3ea7268, 0x143c9e5a, 0xa217ada4, 0xf39b9001, 0x9db244d8, 0xa7dbf79c, 0x7cfdaf4a, 0x8c5d2751, + 0x7efcb8a1, 0xe6711ad7, 0xe9dad301, 0x126ddbfd, 0x7d4880da, 0xcaa16407, 0x3e3ed5af, 0x37384eaa, 0xa73165b7, + 0x0afc3054, 0xe9360d64, 0x00fbcc11, 0x52ea279e, 0x9ce3399c, 0x4f171d91, 0x593d2651, 0x28326885, 0xe891b9b6, + 0xc3b3e9da, 0xcfc5009e, 0x83bcb23e, 0xc18f189f, 0xcd9a5148, 0xfd3d038c, 0x10afc465, 0xc6dd4bfe, 0x2bb78575, + 0xe9075351, 0xe34be414, 0x79c5a48d, 0x76cafc7e, 0x6453330a, 0x94ec8ae2, 0xdabc5bad, 0x67e21f23, 0x60e4b682, + 0x0655bc8b, 0xc29a0cc4, 0x37f19d7c, 0xa6fa7f88, 0x7697ecac, 0x1899f928, 0x489c0604, 0xb0ec98e9, 0xac5fe172, + 0xda7c5c6d, 0x1549a0db, 0xaf42727d, 0x307c66c8, 0x5571fc5e, 0xbde9c9b3, 0x7830cc81, 0x536fd4ed, 0x3d838637, + 0x70e7750c, 0xde9d5618, 0x837e79cb, 0xf57ae2c4, 0xc2791c88, 0x03906706, 0x314aaddd, 0x37ad530c, 0x16da5836, + 0x30abae46, 0xe1e4e57c, 0x4ab5ea3b, 0x479dde57, 0x1556c9c2, 0x1482edef, 0x1cf8b350, 0x5af950e7, 0xe27fdb34, + 0xb40a729b, 0x63e07f00, 0x9db7053c, 0xed4a08c6, 0x3ecd3f6b, 0xe94df535, 0x934ead67, 0xb73f7740, 0xf33fe3ad, + 0x9be70836, 0xe9c134e1, 0x5c2952a8, 0xb699421e, 0x5a876fff, 0xaa0db3f3, 0x4cf7639c, 0x3914c96a, 0xea831321, + 0xa5ccebc5, 0x59397d5d, 0x085599ff, 0x5042300b, 0x733827de, 0xc58feb96, 0x5c712414, 0x0faa6f26, 0xffc5394d, + 0x04cc07da, 0xfa54fc6f, 0x6863b797, 0x1bb43306, 0x635575f8, 0x574b31f7, 0x2f0a2268, 0x9809dc9c, 0xe81d4e35, + 0x8616eb04, 0x30c63ff9, 0xf8869b35, 0x4d3caf19, 0xac3500b4, 0xa67683fb, 0xddcfd80d, 0xca98e0e8, 0x165c954d, + 0xe8d1a6f4, 0x90468f7b, 0x2adaf4a4, 0x3867dfa8, 0xd94e39b5, 0x4d5a45d5, 0x98251324, 0x55db13d6, 0x51db0e56, + 0x916d11dd, 0xc03e54d2, 0x001c6966, 0x2c82ba63, 0x22750860, 0x769741a8, 0xe4320311, 0x7cadff46, 0x5f187250, + 0x2d6c8ea5, 0x57f51b9d, 0x8f3c8378, 0xe5525d08, 0xc72f1cd4, 0x7073dfb6, 0x6adba4a7, 0xcdcbdeb5, 0x1d91af1d, + 0xa1ad36e0, 0x6327d0ae, 0x79055bb9, 0xfc48d3e7, 0xfb6b5cd5, 0xd113c246, 0x9b58e691, 0xa8532629, 0x45b3d628, + 0x3ccf3b39, 0xc5025b22, 0xb849541b, 0x7931188f, 0x017c7f6d, 0x355f299f, 0xb94a0418, 0xdafe789b, 0xdb293d95, + 0x80712f8b, 0xa6063653, 0xf248df55, 0x641e36be, 0x5d1a6f3c, 0xf28ab9bc, 0x5efa81f4, 0xde89f837, 0x8cf06f81, + 0xca0b7c8c, 0x3eb6b13a, 0x3805b0fb, 0x3ff75446, 0x7702f930, 0x907072c5, 0xeaca0906, 0x99bc9985, 0x0a5b92b5, + 0x7718d350, 0x95f5f149, 0xeb870185, 0x83072f4f, 0x53a4a425, 0xe8ac328f, 0xaece8e59, 0x217a3abd, 0x7baabe72, + 0x11c81e39, 0x17f2fe63, 0xa699d2bb, 0x9e80b396, 0x544ebf04, 0x2670c9f8, 0xcb3e72e5, 0xfc11997c, 0x77686f36, + 0xfd2bd667, 0xe8b8b164, 0x69960b32, 0x00e533cf, 0x965d2360, 0xc48e6c26, 0x36cde568, 0xb1a4f4fd, 0x30a34326, + 0x284a93ef, 0x2c998eaa, 0xaaab4d3a, 0x4a26324a, 0xf7dcabaf, 0xaf157fb5, 0xd91eeb68, 0xa7bbc3e4, 0xe3753239, + 0x84eaacf1, 0x5184660e, 0x92e05542, 0x14aae8b5, 0xced0f247, 0xaa3e9fe2, 0xd343d067, 0x03beb091, 0x57517151, + 0x68901d35, 0x2aeb8a2b, 0x53fe610a, 0x10931ec9, 0xf80ed553, 0xe1311cd6, 0x174168d6, 0x716735cd, 0x36867992, + 0xf38c6057, 0xad0f1f29, 0x64197f88, 0xc89a9bbe, 0xa8285681, 0x332e0740, 0x6d941518, 0x920be7f2, 0x9ca044de, + 0x4d14a2e8, 0x26e63149, 0x40061d3a, 0x4763c433, 0x780a45c8, 0xabe81888, 0x1435e5ed, 0x3721f82c, 0x683657f9, + 0x4dfd9e32, 0x531bcc94, 0x753c140d, 0xdabc598c, 0x48833791, 0x3170f2a5, 0x9b122d92, 0x9a16abbf, 0x5132a9c5, + 0x46cb72f0, 0x7115a721, 0x0a472065, 0x3908d17c, 0x91feb3ce, 0xa60af01c, 0x415c4031, 0xb1a035cc, 0x35c9b02b, + 0x99a27da5, 0xd6ca1eab, 0xb76a25ae, 0x457ca034, 0xd4783596, 0x584e72f4, 0x561fa6e4, 0x5ec80904, 0x14099b98, + 0xdd7cb702, 0x5199edbc, 0x86df5776, 0x42991fd1, 0x8ce01e3b, 0xc7779de0, 0xb023a60e, 0x166f3a50, 0xbced05bf, + 0xdcd72af2, 0x60ff2a48, 0xf005200e, 0x85e7d5ed, 0x22658071, 0xe209cd53, 0x4e115de4, 0x82e33944, 0x84990e13, + 0xd1c888da, 0xdc8785f3, 0x78a82689, 0x2a45f484, 0xa2487c18, 0xbe2ad50f, 0x07a767b1, 0x01d5db92, 0xf71600c7, + 0xdfaefb30, 0xadd2c1f1, 0xf08d31c9, 0x91e29ba4, 0xfa9a0c28, 0xbf51c2e6, 0xb316fb7e, 0x5cb3d9ec, 0x9f7e168b, + 0x0baf7d45, 0xa8694019, 0xc1ff60ca, 0x9b9b2efe, 0xb6dec4a8, 0xa36d429a, 0xb2858d16, 0xed39bbba, 0xb8809f0f, + 0x8e2d8201, 0x779c3994, 0xb3ca2531, 0x9f3797b7, 0x1cda5216, 0xd9729b00, 0x0f1d91fe, 0x991ab0dc, 0x899e69fd, + 0xfae6c0a1, 0x90d4aba1, 0xd0fe8c24, 0xe9e7aef9, 0x55a68ab0, 0xcfde422a, 0xf34bf5f1, 0xbccfa065, 0x834291ee, + 0xf476818a, 0xf6462ce2, 0xe4e38c41, 0x2b2e8187, 0x0d2a6d4a, 0xe6bbd35c, 0xb61290bb, 0x4a0ecd76, 0x9b6b38cd, + 0xe22f14a0, 0x2e0c7e8e, 0x8a8180a3, 0xa890721b, 0x9e9a72de, 0xc94563fe, 0x5f42a1e1, 0x2e15e796, 0x824d1496, + 0x94243778, 0x56d4889b, 0x75c1f2fa, 0x73bbe80f, 0xac8858fb, 0x6937f5e5, 0xf9fc5176, 0x4e91860a, 0x40af7a88, + 0xa2ff7b67, 0x2cfee7c4, 0x1660edb0, 0xaabbe86f, 0xbbbd5028, 0x4e45f53e, 0x3049030a, 0x62849042, 0xf3bdd317, + 0x6ebfc461, 0x777404d4, 0x011f4aa1, 0xf8c27677, 0x9a820ec3, 0x4a9c0ae3, 0x3e286179, 0x8e537651, 0xc15c981a, + 0x83d91961, 0x3f74132b, 0x380d6daf, 0x6390f39e, 0x0dde2fc4, 0x816bd831, 0x0ba949e2, 0x940daa7c, 0x3bd7a856, + 0xc2647dcd, 0xe7ec191e, 0x83cbdfd3, 0x819451d9, 0x5dbffba4, 0x9354adcf, 0x904af534, 0x3267372d, 0xe484b98a, + 0xfce85493, 0xe110915f, 0x7601b6eb, 0x6204c1ed, 0x7cb49d21, 0x89a9c473, 0xecc05a3d, 0xa1708fff, 0xeabb620d, + 0xcccf72e5, 0x05ea83a3, 0xd214e843, 0xbd644755, 0x4ace9994, 0x3796e1c6, 0x80d21bb2, 0x33e38097, 0x757a571b, + 0xc23771aa, 0xe68f3ac2, 0x7bff4e38, 0x7e5d4ed6, 0xc780a269, 0x5b7424e4, 0xcc4b3e54, 0xde84d1eb, 0x5e490b5f, + 0x3123a5e3, 0x5db10ed5, 0x9a225016, 0x994ff03a, 0xbafce19d, 0x727b2be9, 0x9e20ab8b, 0xa0753d06, 0x6f11723c, + 0xac9053c7, 0xf69f3c0b, 0xca69f19a, 0xa96e5191, 0x804118b9, 0x235a6bf4, 0x03eec4a1, 0xa1f31395, 0x7f502820, + 0xf9c984ec, 0x4ca0ea82, 0x53a7f90e, 0x96bbe461, 0x2872eca7, 0xacb0d0e3, 0x8429b929, 0x4bf9dea3, 0x3ccca2d1, + 0xc6b8d180, 0xd86e6b43, 0x4593ec3f, 0x036e6998, 0x158ee316, 0x702698b7, 0xbb8849da, 0x4da06350, 0x7b72200e, + 0x4bca9ab7, 0xab4ad05d, 0x87182298, 0xbd4cbdca, 0x819f5a40, 0x53ee1439, 0xfb1c3feb, 0x7fdb0499, 0x82d994d0, + 0xc6fa294a, 0xc6d454fe, 0xaec61760, 0x10fdfa0c, 0x0900c50f, 0x52428616, 0x58dac38c, 0xff8bd910, 0xf2feee61, + 0x116b1d51, 0x71de4398, 0x7d5b6b10, 0x708ba4a5, 0x7cc7d38d, 0x604e145b, 0x2b6d5448, 0x206f5496, 0x95590b16, + 0x80c4a09c, 0xc066a221, 0x34a7d8c5, 0xaf5eb545, 0xa9e59be2, 0x44b4892e, 0x47e9e9d9, 0xf440951e, 0xabbf47e1, + 0xa65828e7, 0x5380f10e, 0x34da215c, 0xce2e7ddd, 0x6857d8f0, 0xd2a8ad84, 0x82bee544, 0x61e1a39e, 0x5b7587ea, + 0x11f536a5, 0xdc9fda56, 0xc9993710, 0x6ba29b08, 0x1f383fc5, 0x6e73188b, 0x3154ed65, 0x9660359e, 0x8dc68a89, + 0xdb65d9cf, 0xd220dc35, 0xd3e28851, 0xa5ab31fc, 0xbead014f, 0xbbdf2459, 0x2f9a80a9, 0xec4bb77c, 0x309b34f5, + 0x9e053e15, 0x1089c03f, 0x587ca11b, 0xcdef8974, 0xa83ad33b, 0x086769fc, 0x3b8a9eb0, 0x349e49f1, 0x8aa1944a, + 0x52dbe878, 0x281904df, 0x54a40995, 0x7dc1f64a, 0x6493cc32, 0x4cf79290, 0x06423c53, 0x5e329507, 0xed153bed, + 0x573fca3c, 0x9ced9fa0, 0xe3a0c248, 0x6979401b, 0x568ea30d, 0xd7b9439f, 0x342c0ff9, 0x48527a5e, 0x41a54461, + 0xc59e2e34, 0x82ca6840, 0x73fcc2f2, 0x2d733696, 0x03684bbe, 0x8a23855d, 0x6726085f, 0x0484cede, 0x004581d1, + 0x55c6b033, 0xded82fb5, 0x615df56a, 0x7ce4cd0b, 0x1d22aea6, 0x5dc37673, 0x164602d1, 0xeb7bf26f, 0xa54e562a, + 0xb224b12c, 0xe44701b9, 0xdc16177d, 0x84a1f538, 0xfa2ebf47, 0x5059cfec, 0xcb17752b, 0xb893dc99, 0xf97e2dae, + 0x6e8f03c3, 0x0a403a04, 0x33b81c48, 0xc1ef081c, 0xf0e4506b, 0x42eb9080, 0xf54441dc, 0x2cbae8c7, 0xc9879982, + 0xfdff7f30, 0xc45c1649, 0xc4962226, 0xb1421025, 0x40d2b64e, 0x041bcd35, 0x0bb858d3, 0x60feb845, 0x92079f0a, + 0xe2729c3a, 0xfbd33363, 0x0af2541b, 0x3058c80c, 0xd935e0e8, 0xaad3973a, 0xdeaacabc, 0x13590fdf, 0x23dca1b9, + 0x7866d6d8, 0x5039725e, 0x70983b2c, 0x81bea285, 0x945c2561, 0x0826d75c, 0x4f7b430e, 0xf14a49a8, 0x214ab4f7, + 0x1ae072b1, 0x148c2e0b, 0xdee6a9c3, 0x3f52ab8d, 0x31fb38ce, 0x8c5d1085, 0xba3bdd6a, 0x01a4f3a2, 0xdf88edb7, + 0xddcc5511, 0xf0ea1bc9, 0x3e403fae, 0x4e798323, 0xea53003d, 0xa3228ef3, 0xd317af62, 0xc5ce0077, 0x3af726fc, + 0xafa0ae54, 0x4b9ad648, 0xd39f823d, 0xa9264708, 0xbf480915, 0x55282a89, 0x48a54dd9, 0xd2187304, 0xb80f3ac5, + 0x8a178949, 0x32294231, 0x93cfcdde, 0x488986b7, 0x8edce71e, 0xbcb402d8, 0xe9fde4c7, 0x9da3423e, 0xc8f7d224, + 0xfea5d9fe, 0x65e89eea, 0x3322b014, 0x9427ef5b, 0xee09b44d, 0x86f4a2b9, 0xd3b7dccf, 0x0b8d91df, 0x93446e2d, + 0x60855d07, 0xe1dae752, 0x33845f27, 0x6bd47784, 0xe4f672ef, 0xeff8e828, 0x86d628f8, 0x6dc335cd, 0x03e76717, + 0x573fb620, 0x357ee4dc, 0xa95fb68c, 0x064ca9c1, 0xab2b25d2, 0x0f63e76f, 0x1443fb60, 0x3488dd9c, 0x41c2f52f, + 0x93ee984b, 0xa124e497, 0xe9fdf3b0, 0x817efad5, 0xf5622419, 0xd28417af, 0xcc9a6fe9, 0x90378f36, 0x42e9ebc6, + 0xb7a5e403, 0xd2697148, 0xb6fcb19d, 0xb0d38804, 0x8aa3f5d3, 0x48a516bd, 0xf595726f, 0xb5c303a0, 0x439bd44a, + 0x5393e37f, 0xf872759e, 0x38c31ee2, 0xfdd98317, 0x9ffe1fcd, 0xa47766b2, 0x63c84c63, 0x4d058732, 0x4fde5348, + 0x9e54d5de, 0x51a96198, 0xac014a24, 0x95a99d5f, 0x4babc33f, 0xfe2ea95d, 0x197ac2ac, 0xcec6c987, 0x5bc4d6d4, + 0xbeefee7e, 0x88f01b2e, 0xd2bb66f3, 0x5e14e88f, 0x125aff87, 0x9c5b02de, 0xd1352b7d, 0xa046d11a, 0x39d90b6a, + 0x88e329b0, 0xabc516ba, 0x2b6329e0, 0xd4bd8c54, 0xb9adb562, 0xa1ce69ca, 0x93385a4b, 0xe2897d80, 0x6a239ccb, + 0x0e195c5e, 0xa8fefb62, 0x7c25ada7, 0x9ab78ba3, 0x5e607552, 0x4b4dc5e4, 0x6084c9ed, 0xf2102de9, 0x26fda92c, + 0x1af78622, 0x6bb8002a, 0xf371d12c, 0x9baace4d, 0x8ea9d236, 0x541a0b4e, 0x5b0852f3, 0x18ce2498, 0x37ccf094, + 0x2a89958d, 0xf9b4d4c0, 0xa3d2c1da, 0x99f99b46, 0xfcd13e7a, 0x35faf71e, 0x6d7682c5, 0xa0a380fc, 0xf7ea4fd8, + 0x5be8bd10, 0x36341e15, 0x7a269bbe, 0xecaa653a, 0xd1aa8709, 0x50c23d1b, 0x09d9a5b6, 0x2828c0f9, 0x9a3f8bc5, + 0x4cd3863e, 0x4ee221ad, 0x8d2fb9e0, 0xbe10ab6f, 0x7297c363, 0xdace9296, 0xa6829b7f, 0x51a71338, 0x1d062ed5, + 0x31756b2d, 0x1bb45c3e, 0xaccb127a, 0xfd44938e, 0xee710b13, 0x46b260df, 0xcf39780b, 0x3e7d33ca, 0x83ea2918, + 0xc2834d2a, 0x4acc37d9, 0x6b8716db, 0xd1f6d5fc, 0xf5f07069, 0xdb4028b1, 0x99b87f64, 0xf6ab605f, 0xfef8f642, + 0x07a05d5d, 0x79426a96, 0xb8bcf8c5, 0xdcb2d150, 0xde127688, 0x712ce7b7, 0x9ea2c8bb, 0xc5b72c96, 0x5b1dacaa, + 0x33a1500d, 0xf35e073f, 0xfb331521, 0xbea07496, 0x6628c4ec, 0xf812b35b, 0xd0642691, 0x28efe5ef, 0xa461ad59, + 0xe5d45bb3, 0x8f979df1, 0x5fc2f7b6, 0x088515cf, 0x3a0ada30, 0x121af7e5, 0x043de87a, 0xe53c7960, 0xd8b751b2, + 0xcbdfefc1, 0x6ddcbb16, 0xfa283435, 0x95012dfb, 0xbb7577d7, 0x6a858008, 0xd970cecb, 0x1b37823b, 0xff66821e, + 0x35cb4e5b, 0x30176d4f, 0x2f282a56, 0xd3f84be2, 0x64e14196, 0x44498568, 0xb348ab46, 0x056cd22a, 0x023cbebc, + 0xe76fad77, 0xbb3471cf, 0x1ac397c7, 0x327b27de, 0x2cc78f32, 0xe2658c01, 0xf3eedc7c, 0xfc6844da, 0xce1761cb, + 0xeac3ba6e, 0x14f2b983, 0xc9c78c79, 0x6fc16c74, 0x41b3975f, 0x05982be1, 0x5b2ba96e, 0xb0ddbc4e, 0x0339e5ed, + 0xcddb8629, 0x773710c7, 0x649f0501, 0x53beafe3, 0x33815115, 0x00ac39cb, 0xb75c9de9, 0xd783e0d1, 0x4f04088c, + 0xb85c2c6b, 0xd64f68d5, 0x9341fb07, 0xe96f2481, 0x49ee0174, 0xd98d22d7, 0x1e4f6a74, 0x63797171, 0x472d9408, + 0xef25cef9, 0xef8808c0, 0x2d288a2a, 0x052c8e2f, 0x0fd29c50, 0x3c3c4c84, 0x574b38a8, 0xf92c153e, 0x91c135fd, + 0xe0550576, 0x03ea8ce9, 0x0e01af63, 0x91507cdf, 0xfd6df240, 0x592ec5df, 0x89378b4f, 0xa987a3bd, 0x5fac7e56, + 0x398a8824, 0xd1f58a25, 0xc05cf10a, 0x2490026b, 0x05a77389, 0xe72b20a8, 0xdf1413a0, 0xf84dddc4, 0xffc78f65, + 0xbdb530f1, 0x70c6062c, 0x0268a908, 0x11529e7b, 0x00d7781f, 0x159f44a2, 0x452daf1f, 0x2432c49a, 0x763c695b, + 0xa9bef793, 0xc51c5dd5, 0xfb218059, 0x0207b1c0, 0xb1af9466, 0x46fa49d4, 0x6246c3f2, 0xa5da8dcd, 0x798afdd2, + 0x83c0077b, 0xfadce6bc, 0x768dd516, 0x664de593, 0x1cd607e7, 0xf9e429b7, 0x18fab6d9, 0x920c01df, 0x4bf09d75, + 0x9727ba22, 0x43052f20, 0x0d0be0ca, 0x2cf28370, 0x007b47c7, 0x76254055, 0xd30ed41e, 0xeff06890, 0x99afef35, + 0x5541ee52, 0x9fa508f0, 0xe7911e08, 0x923ec1c4, 0xda74cc78, 0x73f535dd, 0xbf20780f, 0x69c95aba, 0x27b54122, + 0xf4aa1c5c, 0x995c9a20, 0xe802550c, 0x82913036, 0x2855c617, 0xed45c494, 0x6be84046, 0x477a76b9, 0x40a33c9f, + 0xddad6683, 0x64ea0023, 0x93729347, 0x50039025, 0x9ab14748, 0xbe07b5bc, 0x102d72ee, 0x37d707f0, 0x5d907990, + 0xf87cd6f4, 0x1c359227, 0x8ff93423, 0x61a8e8de, 0x0be424b1, 0x2001bea5, 0x3ea01e7d, 0x78f0ab6e, 0xeb49e82a, + 0xae56245f, 0xaca108ce, 0xdbab5b84, 0x587b47d8, 0x279d73aa, 0xea3bf9f1, 0x5430e8f5, 0xb9acbcb8, 0xab21a393, + 0x5828349a, 0x4d9f7d69, 0x6bb30b77, 0x58cc6433, 0x58add54e, 0x76c87441, 0x8db733dd, 0x7012907a, 0xe82bd0db, + 0x684781f3, 0xecacddaa, 0x9ca280f3, 0xd5802c6d, 0xcedf8bee, 0xf75fd50e, 0xf507969e, 0x1669abc7, 0x306ae092, + 0x4f1640c6, 0xa7644070, 0xd7ad6762, 0x48e0aac0, 0xe51bda53, 0x78bdf0a8, 0x24bcbec8, 0x266f1a15, 0x7073b45a, + 0xb08a350b, 0xeb09a7b3, 0x94471f18, 0x91ec7a05, 0x4158b5ce, 0x2098577b, 0x904c6871, 0x114bc1d8, 0xd3f698a2, + 0x15dd3b9b, 0x3f43bd91, 0xe6bbec83, 0xaf32f06f, 0xe5178a17, 0xf3733d90, 0xc77f52b4, 0xf94987be, 0x5e9a3847, + 0x953b309c, 0x637fda1f, 0x841b41aa, 0x85fae535, 0x5c9b903d, 0x73ceef32, 0x21191215, 0x378337df, 0xd92aea21, + 0xb61678d9, 0x7f2e5c6d, 0x6e49e429, 0x267425bf, 0xdbf008c2, 0xb76dccd6, 0x060ce6ee, 0x059e51ef, 0x43e6ae82, + 0x719b92fc, 0xf6b00392, 0x30939c56, 0x656b74c8, 0x933f7c93, 0xeca4cecb, 0xea0c9aea, 0x831ad8a8, 0xc719d4d5, + 0x4657dd06, 0x9a389a7c, 0x1696eaf5, 0x7a1d14fb, 0xf39bdbd3, 0xa1395d11, 0x3d15588e, 0xa385d7e3, 0x2729d80c, + 0x6d07e144, 0x44e75a0d, 0xcf80ff7d, 0xb7ba6878, 0xcf8a1bfa, 0xa71aa8bf, 0x11d408fa, 0x86ecdd1e, 0xa5d4ef94, + 0x676298f2, 0x369a9305, 0x6637fd96, 0x8a35acd4, 0xabaa9fff, 0xc872c407, 0xedf80b0b, 0x694cb597, 0xaf906adf, + 0x98f79b7f, 0x5d32577c, 0x5abae49b, 0x5e11c4d1, 0x61e8774c, 0x8c9414ba, 0xb6f46549, 0xee90e8d5, 0x6f93f0e4, + 0x59f0e0c4, 0x3fad57f4, 0xcee0597f, 0xac4d0c52, 0xc3401983, 0x2ef0799a, 0x58cec703, 0x4ad35afe, 0xaeeefacb, + 0xae32f7b2, 0x7af0b4ef, 0xa99b7eda, 0xdb0d5ed1, 0x1df8b9f5, 0x8892f44c, 0x762955a2, 0xe9776641, 0x45d949d4, + 0x2d3a8600, 0x38e24bcb, 0xb36c9f31, 0xa736e0bf, 0xf1be209f, 0xcee996ad, 0xe968443d, 0x7c86bb5d, 0x5a96f91a, + 0x307e49e6, 0xcd69c1b2, 0xef4c5656, 0x6ef6667c, 0xa5ef1344, 0x1f397bea, 0xfb0c8545, 0x1510aaab, 0x3c415a73, + 0xbe248dd1, 0x98bef7e6, 0xb08b9e6d, 0x81c9b6b9, 0x8639e93a, 0xc681aa05, 0xbef5e597, 0x2d40f07c, 0x65b3a0fc, + 0x9544be5d, 0xa843072c, 0xc07512a9, 0xa3be1f0d, 0xbf7c1438, 0xaf2a01b0, 0x32bad8fe, 0x641a5a1d, 0xf2d92842, + 0x9774b145, 0xad475615, 0x0cbd5521, 0xe80ca733, 0x356ab808, 0x2364c5a9, 0x60aac8e8, 0x54b873c0, 0x4f5cb57c, + 0x7ece31eb, 0xccecd033, 0x3ceba23b, 0xb0bfd991, 0x4bb86140, 0xeb9b8e61, 0x276a2d37, 0xfc9c88da, 0x6f16e841, + 0x82ac5fd7, 0x6c445709, 0x7a977a8c, 0x469c466b, 0xcf8d5329, 0x9ca6e095, 0xa36e71df, 0x30e98a23, 0x7d83b4ec, + 0xf95a0ca4, 0x458d25df, 0x6ea49596, 0x1b9560b7, 0x0ca92f0a, 0x0a3c5518, 0x81b22bcf, 0x95b5bbe1, 0xb3bdada4, + 0x39488618, 0x6dee86df, 0xef17ff83, 0xb489ba5a, 0xe204b88e, 0x063c1b97, 0x9520dc72, 0xb1bfbcd7, 0x11bcb60d, + 0x5d5be0c1, 0x261fa4fe, 0x1f6f0229, 0x984c172b, 0xa1a4be55, 0x148ee923, 0xef74846f, 0x130085a5, 0x16aca77e, + 0xb91f376d, 0x9d134b23, 0x68fbacfb, 0x6d99bcd9, 0xbaeeb86f, 0xfb63552a, 0x14d0289a, 0x07d95dec, 0x64ba4005, + 0x79ecf41c, 0x89ed209b, 0x9b068410, 0xf35e427e, 0x2d1881cc, 0x3a2375d3, 0x08999305, 0x91eaac25, 0x8c6dd73a, + 0xba084a3b, 0x02f48cd3, 0x0929252a, 0xca9d8183, 0xa55f854d, 0xcff35084, 0x150bc56c, 0x447db6ef, 0x43eae694, + 0x7da61b48, 0x57bdb1b6, 0xeb76710d, 0x9d50eff6, 0x820f30e4, 0x3daedf18, 0x0febade0, 0xbbd5ff19, 0xe0bc0ea1, + 0xbd342b48, 0x18b1e7ae, 0xa6cd9a27, 0x69999637, 0xf76009b9, 0xfb0ea4ee, 0x5b77fb6f, 0x61143905, 0x73b71497, + 0xf747454b, 0xf9305932, 0x4300ed5e, 0x25af431f, 0xd130f370, 0x8c9f2435, 0x97a63954, 0xa2159359, 0x0e8c3ca9, + 0x7f14673a, 0xe5e28716, 0xf60e3eb0, 0x657730e2, 0x89b2de1f, 0x4d1a1644, 0xa543570d, 0x1d892873, 0xf9427ba3, + 0x6231de0f, 0x8d43be1b, 0x9a11b405, 0xe7650c9a, 0x70a16a5a, 0x23310080, 0x0b9eb0f4, 0x70ffb9f7, 0x13628be6, + 0xa7075cc8, 0x6f5e282a, 0x9d705835, 0xcded229a, 0x24cfc0c2, 0xc8f0ed65, 0x04cda3f3, 0x76e15fa7, 0x280e5758, + 0x599fe3d9, 0x5b396070, 0x6fd88015, 0x73770ee5, 0xd6d7cb37, 0x73941e63, 0x3fdca19a, 0x885ffdcc, 0x0a56699d, + 0x228f8bd0, 0x11d34fc4, 0x03f0df3f, 0x72ffd163, 0x57a254bf, 0x88b44a91, 0x557c67d9, 0x27311bf6, 0x9c463d1b, + 0xaa1fb0c3, 0x0eb3edfa, 0xd1f20b69, 0x2148c32d, 0x9ae388ba, 0x70948983, 0xcc5af187, 0xfb929e1c, 0x802ba04e, + 0x2bf1de67, 0x7a8ba66f, 0xe16351f5, 0x27872275, 0x8bdf2128, 0x1cb75b9a, 0xf6ee08fb, 0x1dec17a6, 0x3dfd5d8e, + 0xa35e1da5, 0xc751f6db, 0xbe888115, 0xdd64c984, 0xb8bf0bd4, 0x5d0e4fde, 0x934d2099, 0x5df8b1de, 0xa54e4eb8, + 0x5ec6f30e, 0xbafcbd27, 0xac858ad3, 0x8ed6b94f, 0x497e7332, 0xe1d5240d, 0x577659e9, 0x68e61bc7, 0x783b4e1b, + 0x90e7a1dd, 0x248bec40, 0x3d4e1b44, 0x4d63792f, 0x1109bc08, 0x49f05d90, 0x91486352, 0x58336937, 0x631a9d45, + 0xf3858007, 0x3cd1381b, 0xbbd65e37, 0x16d91f5c, 0xb67baa43, 0x966fd0eb, 0x1c1ed634, 0x3ce57618, 0x7d034820, + 0xf79068bf, 0x607a1c1a, 0xe33b3c9b, 0xbafe598a, 0xc22cb8ab, 0x2123217c, 0x98eac975, 0xc70a97c5, 0xbe693111, + 0xa88ae5a2, 0x2d98384a, 0x7dda8395, 0x6da7b849, 0x22720b4f, 0xd9109679, 0x18af63ee, 0x5708f364, 0xa68570cc, + 0xda3b9292, 0x3706135f, 0x14fc40b0, 0xf152eef9, 0xde3f7d7a, 0xf08c8a61, 0xad7cc78a, 0x0d6c69d5, 0xa3f2bac1, + 0xabf72a39, 0xfe545d80, 0xcaa1787c, 0xbc77a112, 0x44dc0db9, 0x62dc87fa, 0xeaf701c8, 0xe36b6966, 0xc2c0e23c, + 0x706177ca, 0x8a5ff23c, 0xb430e94a, 0x99573ea5, 0xb7cea4cb, 0xd55e0c1a, 0x8b184cd3, 0x97bda173, 0xf5d4279b, + 0xb78d8e9e, 0x82685059, 0xd6f74f03, 0x0c7fb53a, 0x4adffc73, 0xd9af428d, 0xa85c4980, 0xded170f2, 0xb515a307, + 0xccc19439, 0xbed7b63b, 0x7015be07, 0x4b1bdbea, 0x1b6b9420, 0x2d518672, 0x85d0c9c0, 0x86e22a22, 0x68ab2c66, + 0x6f192ad1, 0x3efd195b, 0x0b2b9250, 0x8f9d2afa, 0xb67c5b48, 0x97ebdc80, 0xac3b26a9, 0x19c33782, 0xfb17b69f, + 0x71e39773, 0xd35f5b0a, 0xd81f832e, 0x9441b7c7, 0xd681114f, 0x9108aead, 0x599e43d8, 0x30fd99f3, 0xc78c8bf1, + 0xcd400b99, 0x0b8184cf, 0x6e893623, 0x6c8e6bca, 0x4ae3e32a, 0xeb769909, 0x514eadd1, 0xd7d7addb, 0x7a86808b, + 0x52cbd157, 0x1de5115b, 0x86adf854, 0x83fea726, 0x5eb103ec, 0x1955ed02, 0x1cf5aa08, 0x985a067e, 0xe728cc13, + 0x6a3417ab, 0xc8eb36ce, 0xb2be7a08, 0xd9940809, 0x4aa06b4f, 0x68bafc0e, 0xf6c05b90, 0x0d1a4f2f, 0x0e671449, + 0x4d22c454, 0x2420017c, 0xe58801d3, 0x12f2c943, 0x25c65fa4, 0xda316680, 0xb2c6ea32, 0x98fd50d2, 0x94c9f3f8, + 0x456252db, 0xdc3d4efe, 0x008afb03, 0xefe05c27, 0x59d13220, 0x390f61c5, 0xabcf22da, 0xf67d0ff1, 0xb178a4a7, + 0x84d9dca3, 0x02942a36, 0x58ecf884, 0x600c7b8e, 0x08d6fc3c, 0xcba7553c, 0xc69ab240, 0xcc321d57, 0x6a1bee03, + 0x75bd81be, 0xb6db4640, 0x4950a894, 0x85aed48b, 0x87c3d31b, 0x4c29b4a9, 0x61e26c60, 0xccda5b7b, 0xb10390e0, + 0x1c9707cc, 0xf2026c94, 0xac5d31f3, 0x9a2e574d, 0x77ac3a27, 0x67e39e21, 0x2a8471e3, 0xf9e10d5e, 0x24cb35ab, + 0xd819439d, 0x1cfef3ed, 0xff8d7bc3, 0x04dfaaa6, 0xb1d6bb9a, 0xdc7f08d5, 0x7b002001, 0x1c2bdc33, 0x1e301349, + 0xfc819e1b, 0x90303252, 0x2dfdd81d, 0x5ccf5788, 0x7c7421d4, 0x0e999a6f, 0x5140beda, 0x89044ff1, 0x811045eb, + 0x91dd0d83, 0x6dd6f526, 0x27775f57, 0x26b86e96, 0xe7a321c8, 0xaab9e086, 0xed7a9863, 0x21bdd5ef, 0xfee3c909, + 0x7d0b69ed, 0x856e0b31, 0xac18ab2a, 0x8aa16c09, 0x75470bc2, 0xcbf3e962, 0x38e6aeb0, 0x49dc7252, 0xe353f5fd, + 0xf2b4eb3d, 0xb0ba84bd, 0x000a736e, 0x673bd2df, 0x835982d7, 0x205c5d04, 0xb26693c7, 0x19c298c1, 0x2a9016c8, + 0x20a75203, 0xda7eccf1, 0x1e239c9f, 0x3659f816, 0x3bfe9afe, 0x0feac587, 0x05cd831c, 0x727abdb8, 0x19ea10f6, + 0x348457ee, 0xdcc85827, 0x5bedd067, 0x5c3ba8c0, 0x498403a3, 0xa5cb0769, 0x1db97ad9, 0xcd821153, 0x5953bb0d, + 0xe4701d21, 0xd03ea7e5, 0x36724fa5, 0xce0f0b1b, 0xe64c1341, 0x069e7f31, 0xdf63daf7, 0xee97a533, 0xb58222be, + 0x636e7ae7, 0x5fbea43d, 0x94e08512, 0x22403fce, 0x59c3c136, 0x63b20a2e, 0x7d6a2488, 0x0c014c03, 0xf869730e, + 0xd3252073, 0xce03d6a7, 0x2b355d1d, 0x165778ee, 0x01aa39cf, 0x905c790c, 0x5c6cc18d, 0x99fae889, 0x4b9e6372, + 0x2c5368e5, 0x0353f982, 0x16b0a6f4, 0x2fcffd60, 0x05345c92, 0x02248af8, 0xd57126b6, 0xd41461f4, 0x28bdee13, + 0x5a30073f, 0x0a5605fe, 0x152ab55b, 0x5084ba74, 0xbb4b1973, 0xc2922544, 0x18c62bae, 0xdc5e7291, 0xe8a5250b, + 0x4cda7c80, 0xbb36ec32, 0xd611c899, 0xca9ca5ca, 0xb84ce48f, 0x7d60e3df, 0x65068ed8, 0xfb24edf5, 0x3cf09500, + 0x6a42231e, 0x47494562, 0x0576a3db, 0x72b200fe, 0x394d462a, 0x89982c2a, 0x02c87fcd, 0xe22071de, 0xbcd8432f, + 0x2e0991d8, 0x991930c0, 0x02074833, 0x6dd4f452, 0x14e796bd, 0xad401146, 0x666f495f, 0x5ffb3762, 0x35e1a22f, + 0xeab71138, 0x53ec790c, 0x9fecaec8, 0x3c962ef9, 0x18b0a8e4, 0x1def4664, 0x3d75b81f, 0x06176a45, 0x965d8dd3, + 0x44fd5b24, 0x58d80a3e, 0x3885a6fc, 0xe7ef4457, 0xad468bb4, 0x5f22c9a4, 0xf41e8681, 0xbf8210a4, 0x888d3124, + 0x58e79f0d, 0x2d43a411, 0x3130d28f, 0x27646902, 0xf92c7c6b, 0xab77a877, 0xecd14ce9, 0xc1aad2c4, 0xda22d0c5, + 0xf8862765, 0x8c02effa, 0x83d216ec, 0xb274b928, 0x74d5a74d, 0xb712f563, 0x179bee58, 0x3fb631c1, 0x84ff893b, + 0xc769a779, 0x17f09d9e, 0xaef70b67, 0x9cf1eec1, 0x8fcc51d6, 0xf4954c05, 0x00806cfd, 0xc14d0037, 0xe439b767, + 0x7300a54c, 0x09523b5a, 0xf810cdb8, 0xa408ad31, 0x09ea9cec, 0x4f9887ac, 0x36aa7471, 0xa6da24d2, 0xa05a1376, + 0xcb38da29, 0x080fa531, 0x1cc3de94, 0xcc3fc77f, 0xd6d963a6, 0xbb0bc4ed, 0x26193e41, 0xc474dac5, 0x7ff63c5c, + 0xcbedb2bb, 0x1c8d8a3d, 0x2a61c025, 0x97db0113, 0x38b24e6e, 0x77267f6a, 0x58e8552b, 0xae203c64, 0x3f86428d, + 0xbdfb2d2b, 0xa56a1cd0, 0xb3fec835, 0x40692b71, 0xc6c8bfab, 0xaa264e5c, 0x4b899485, 0x8b63784b, 0x133e9dd4, + 0xa6e93b42, 0x9acfccb0, 0xdebcd4d3, 0x21e9443e, 0x79a0b290, 0xbba9382a, 0x4cb2093a, 0x3652528d, 0x0a3f406e, + 0xf2b3c174, 0xdfb72dd7, 0x849aaf9f, 0x938cfc0b, 0xb2996f81, 0xa797c17a, 0x0cc539ca, 0x7934cd3a, 0x79a9b835, + 0x9b218326, 0x8b06f7ad, 0x8bc6696f, 0x52bf4956, 0xabe30529, 0x5cffeb13, 0x48c1f554, 0x07be466b, 0x1ed09f84, + 0xf0c17fd2, 0x53bf53d6, 0xf6980350, 0x97ec05c5, 0x29414516, 0x1915ac8a, 0x164f52f3, 0x1752a8ba, 0xc83c763b, + 0x88f2bd2b, 0xaf3cf68b, 0xb90c4731, 0xb2771377, 0xab4c656c, 0xeb3faf25, 0x6f658282, 0xee280b3c, 0x533b632a, + 0x9038e814, 0xc8fd98d6, 0x01db3520, 0x16c21aed, 0x41bbaf20, 0x3141bf91, 0x02196973, 0x9347540e, 0x297918a1, + 0x11ec76fa, 0x86478956, 0x9bb6a4d1, 0x2a558070, 0x119cc528, 0x91c7670c, 0x0e7d1e61, 0xb9e5181a, 0x74d32a01, + 0x1bde6263, 0x6c96ad8e, 0x6c51b972, 0xb3950457, 0xebc7c7c7, 0x36e59353, 0xe28b50a5, 0xb9f9238f, 0x2ef5d5aa, + 0x2430a48c, 0x181af747, 0x489c2092, 0x4d2bf27b, 0x96589f01, 0x869581ee, 0xdd97993b, 0x7f096de5, 0x3ed4d7e3, + 0x4ff8cf36, 0xc7a108cb, 0xb5928852, 0x760fdeb8, 0x3367830d, 0xaa1e5e08, 0xe510a2e1, 0x66cebc98, 0x3f5d8f73, + 0xaaebb9b1, 0xf0e24d21, 0x98742517, 0xc214d826, 0x4f6e43c5, 0x5f857731, 0x4cd9c6f2, 0x506e4f1a, 0x97195a00, + 0x3aa17131, 0x97f042ff, 0x464d5faa, 0x406474d6, 0xa841a87f, 0x6fc22fd6, 0x66acbb9d, 0x2fcc32d2, 0x93314b70, + 0x98d782a9, 0xce2de064, 0xab5c41a6, 0xa9ca93f6, 0xd5bb4e03, 0x34a9e5bc, 0xeb577629, 0xc5140339, 0xd3212040, + 0xd9ca695a, 0x30014513, 0x198b62c6, 0x3e0d44ab, 0xd2bf31d3, 0x7e651687, 0x185a8dcb, 0x12f01cb9, 0x3c11c080, + 0x42fefd17, 0x8d6b94f9, 0x759e351f, 0xdec69715, 0x8a7badf8, 0x4de733da, 0x30fcd27e, 0xcb747d12, 0x1ebaa478, + 0x3c0a36ec, 0x6ded43ce, 0xe0e3766f, 0x31e35e98, 0xadb89d61, 0x123cf19d, 0xa63b68d4, 0x7df846b3, 0xce4f263c, + 0xf20f6cee, 0x1fe9521c, 0x65db090c, 0x3a484d22, 0xf47e2682, 0xafe1999c, 0xcfa471c3, 0xf72e21e2, 0x45c9d132, + 0x8d46a380, 0xe16980bb, 0xb53c3e23, 0xd00a4e16, 0x115bbe0c, 0x65f88025, 0xe4e70d29, 0xd254d37a, 0xd3ee6353, + 0x15d01c21, 0xbd10f521, 0xc75a05ec, 0x496238b2, 0x7a3f0558, 0x82069547, 0xe1366e89, 0xaaa78559, 0x5a9f4976, + 0xe52ef8dd, 0xff7bfa0d, 0x6352f397, 0xc1885b83, 0x1f5315d4, 0x99a7c89b, 0xacdca79b, 0xe309ebe5, 0x597052ef, + 0x422d033c, 0xa26eccfa, 0xb4ed91a8, 0xfd044bdd, 0x95cac6ff, 0x8d3650b8, 0xd0707a09, 0x927cfb24, 0x95044806, + 0x2eb0fede, 0xc99ebfde, 0x12220086, 0x35cdc73c, 0x261042a4, 0x97d004fd, 0x00d33898, 0xc16f1a94, 0x987952fa, + 0x4dc51bc9, 0x731d797e, 0xda05ac7b, 0x545219c6, 0xa0fd5981, 0x2c3c6723, 0xfdfacc6a, 0x747d61e9, 0x93521d95, + 0xc0029c0e, 0x2db73b0e, 0xd94ba54f, 0x7f587f91, 0xa4f80ce4, 0x7027f0a9, 0xa394a46d, 0x41abb633, 0xbb4fc44b, + 0xf8a5b5b4, 0x57604a5e, 0xd268f5de, 0x47be8fb6, 0xd7c7df3a, 0x8b0ea90a, 0xd85ca294, 0x67d0a875, 0x913486f9, + 0x6ac48277, 0xa2300927, 0xe48cfa5e, 0x73d2af88, 0x443e55ba, 0x7b5c7264, 0xbddfbb35, 0x183c24a6, 0x8ff95b1a, + 0x066f4cad, 0xc2e578b1, 0x3c6d9b8a, 0x925641d2, 0x53bc2757, 0xcff76864, 0x486381bf, 0x1471e553, 0x32a592fa, + 0xa3b8bc18, 0xdb2aa43f, 0xb3194bf9, 0x197929fc, 0x0ee42020, 0xafe23acd, 0x33116cb2, 0xf86056f7, 0x6a8b4f3c, + 0xc98fa957, 0x10458a98, 0x5ece89cb, 0x12e509ea, 0x5c214d25, 0x289b8e8e, 0x25c38ca1, 0x8ac47752, 0x81e97177, + 0x7ed607bb, 0xa9758dc8, 0xb2d14084, 0x3c5ad022, 0x77727694, 0x6b58d253, 0x32b7d1fb, 0x023162de, 0x5402845e, + 0xd01dfe6d, 0xe9da5883, 0x988ab306, 0xa72bc7e2, 0x45711f07, 0x83f769b3, 0xcb85e9e2, 0x696f2851, 0x89701e1a, + 0x7f2a9372, 0xc7640e45, 0x381ec629, 0x51b0ca4f, 0x6de23c1b, 0x9a2d44c8, 0xb39f1a9c, 0x062ca66a, 0x8b7bbde2, + 0xf4354f9b, 0xea30627c, 0x3f967b48, 0xeaf41ca6, 0x1fde18ed, 0x764b1c9c, 0x2dd575ac, 0x7ffa5b00, 0x3833fb08, + 0x0dbb9623, 0x82f7bffa, 0x88e4e9ac, 0x37145003, 0x1274de76, 0x0953d25d, 0x8da3dc6b, 0xf6c6e806, 0x7b7b7496, + 0xee6b5220, 0x530dd946, 0x5a03ee14, 0x55edf87b, 0x906b602f, 0x5123c585, 0x256883fb, 0xb6512499, 0x85bdf6cd, + 0x4869f8c4, 0xe0e825c1, 0xc43883ba, 0x87c77c1b, 0xc7090d14, 0x58ca4156, 0xcebac1da, 0x5b3ed1e2, 0x9486c2c9, + 0x56e72c01, 0x89f5b31e, 0xaf0a0aab, 0x6e6d98f6, 0xb9856872, 0x41c0d9da, 0xd1a58a32, 0xc77beef6, 0x3d043193, + 0x7985653d, 0x38934836, 0xd9941595, 0x18f1bd76, 0x420a0a40, 0x3480ba8c, 0x5d779ce9, 0xcc8161f8, 0x4afd7580, + 0x30a1aa3e, 0x8e44435e, 0xd63c0688, 0x2004e456, 0xacbc2cf2, 0x83011324, 0x45164912, 0x5802302e, 0x9b8f9ebb, + 0x67ff6973, 0xf90c3407, 0x05136f5d, 0xf7bb238e, 0xc37b7c3b, 0x2709dfea, 0x867015b2, 0x7d9f2f78, 0x6c1711e6, + 0x5aac7fff, 0x15d6fb0b, 0xe9e3176c, 0xb5ddd6dc, 0xcb479189, 0xf409da66, 0xb0bb6d27, 0x4a45eeb6, 0xea3d6fa4, + 0x5e78d934, 0x2d9ca8b5, 0xdde08e00, 0x1eb3c834, 0x66215504, 0x48c385c8, 0x9682fb1c, 0x5b48e15e, 0xdd50a0a7, + 0x5b55a4ce, 0x9063ef9e, 0x4763e37d, 0x68571aff, 0xa5f9853c, 0x6f064b74, 0x785f31ad, 0x509f5392, 0x58fd60b4, + 0xd3dcb3ff, 0x5b13ed47, 0x41cfe566, 0x1dbf7f19, 0xeded5d64, 0x70c7dc50, 0xb3a40fe1, 0xa6930356, 0x91da4a4c, + 0x2c259174, 0x8cb6c5b5, 0x83618e59, 0x90f10081, 0x510c7d98, 0x2f78d47c, 0x5a9c2b63, 0x2b2528e4, 0x62f50477, + 0x267f94d3, 0x523aeea1, 0x81698377, 0xcf097bc8, 0x68d24cf3, 0xf6623058, 0x2ccd8dbb, 0xa20c355d, 0x1a1f45a2, + 0x140cb0d7, 0xc62ecca8, 0x2452dcd9, 0x6baea733, 0x29b9de54, 0x795cc1d8, 0x6fd862fa, 0x63b8e0c8, 0x80aaa6c6, + 0xd67a9a52, 0x37e5395f, 0x06c30613, 0x509a6f3d, 0x869a4b83, 0x4c80043d, 0x2ca425cb, 0xefeed6b8, 0x523af8d1, + 0x16504891, 0xf46ab8e8, 0xe1e33a15, 0xaff07697, 0xd49782c6, 0x9e618004, 0x11c8c4ca, 0x92f1b029, 0xabc6c296, + 0x85c88206, 0xc5ec7bae, 0x1f5df4b0, 0x5177f317, 0x0c9c8c33, 0xc4c395a8, 0x83e872ab, 0xd20cd752, 0x5e1759f3, + 0xad72d97c, 0x0054e652, 0xd5a780a6, 0xc12b55fc, 0x6a8ab9d4, 0x71f5e4c1, 0xe9edf81e, 0x4c7696a7, 0x7f103205, + 0x7917898f, 0x31401811, 0x6d2fe2dd, 0x4e50d264, 0x1ea6e51f, 0x78ccaea9, 0x721e4756, 0x6cf5adc4, 0x93e6b18b, + 0x625d7399, 0x77bfd924, 0x3f4aa679, 0x525d3ac0, 0x5818ff9a, 0x2a84802e, 0x7603a8cf, 0xd7060b74, 0x6d77921e, + 0x7ee84c8a, 0xa4546a61, 0xc8c6ff49, 0x72ea7d53, 0xdf8c9d03, 0xb44540eb, 0x5335e33e, 0xe3647fc3, 0x5e0f2c57, + 0x2d9708c3, 0x9191cfb3, 0x85a336f5, 0xece967a5, 0x2e74de8f, 0xf9d871aa, 0xd9e1ce7c, 0xb1fcd83b, 0x264c3ea5, + 0xc9311cac, 0xb32f0b18, 0xa9f85032, 0x1333934c, 0xed66ba15, 0xa21b48c5, 0x880751ec, 0x7e799819, 0x6efd2a87, + 0xf06e7688, 0xdc53188b, 0x525c9e79, 0xe74966e5, 0xcafba25c, 0x8b38e4dd, 0x65f2548d, 0x2962cea7, 0x757c2f51, + 0x20ac3dec, 0xab139d6e, 0x6ae32085, 0x7ee1e289, 0x44ea82b6, 0xa6e29ad0, 0x2cce99fa, 0xbefa6bf2, 0xebec33b1, + 0x43be021e, 0x6ba1f886, 0xf78fa12a, 0xca07609c, 0x50d30c6e, 0x5afdfcc9, 0xd6d04e73, 0xa209cc5c, 0x4c70a673, + 0x185342ba, 0x917d9f95, 0xc17c7fe3, 0xe600c79c, 0xb198b071, 0x0b6c76f3, 0x96ebce89, 0x10212f07, 0x30ab5e83, + 0x98ec5003, 0x0a956181, 0xd325d74c, 0xecb33538, 0x7b35d7fe, 0xcca16de1, 0xa8275cee, 0x67c59de0, 0x44776250, + 0xd4cb8620, 0xdefe08a9, 0xe3a5ef86, 0x8b41a555, 0x959cc7cf, 0x26d2dd5e, 0x4060439b, 0x72026e4c, 0x1afbe480, + 0x7e1f5ec7, 0x3e7bbfc9, 0x940eef90, 0x31672312, 0xb67b3b20, 0x1e9a9aff, 0xd7076341, 0xf91c2a2f, 0xe730259f, + 0x26f23bdb, 0x892fe484, 0x7cf4f155, 0xe5d10709, 0x9d6a3c4c, 0x8fd0ef2e, 0x1e6d91a6, 0x68dd01e2, 0xc8d2c3f2, + 0xf7ac9d63, 0x55a23cbe, 0x22f4c06e, 0xad72971e, 0x658fecf9, 0x0bd3985b, 0x36fafea4, 0x1fe84b51, 0x0598e5d9, + 0x04af7b69, 0x1e97fecc, 0xd00cefb3, 0xc6c0ea64, 0x641e25dd, 0x5706e837, 0x1a9a6f8a, 0x808d2b1e, 0xc416524c, + 0xf31556d5, 0xdb86d44d, 0x36572907, 0x4e098af9, 0x8b0e178a, 0x163c1185, 0x6c98f73e, 0x610c56ec, 0x186bb5f7, + 0xb9cf2ea8, 0xf1d6b1b6, 0x49334982, 0xfed1c329, 0xd21d9334, 0xd1cf44e4, 0xd702b24c, 0x5e022aea, 0xdfae1caf, + 0x1994f517, 0xbaee2490, 0xa5afb6f4, 0x2fe2d274, 0xd15c3fc8, 0x562ae2c8, 0x4f69e906, 0xdeb3f3fe, 0xe9266759, + 0x5a47c1fe, 0x848cef30, 0x60a584be, 0x5e83d1a1, 0x780504a1, 0x6337cc73, 0x2c853c4b, 0x017f756f, 0x6c629492, + 0x7956359e, 0x097bd493, 0x9ac7729b, 0x17747176, 0x6cef645f, 0xae8ea358, 0xf383c842, 0x687ad290, 0xb289c923, + 0x2679e2c4, 0x04cd76e9, 0x1eec9dca, 0xcf529c99, 0x2195eb65, 0x7dbae840, 0x55130bb8, 0xb7a50fa0, 0xb51ca19f, + 0xcd817420, 0x1a364fa5, 0x994a5800, 0x73fba263, 0x93f4d9d4, 0xd1d1a991, 0x6ac94dd5, 0x5595359a, 0x16e75340, + 0xed406a47, 0xd615f5aa, 0x1f771b1f, 0xe45364c8, 0xcc22edb6, 0xb6c821dd, 0x805853a2, 0xbecbd767, 0x5cc19ac4, + 0xb998e0b6, 0x7f52d745, 0x94f33ad7, 0x6b4e19c8, 0x0efb7e4c, 0x766a1614, 0x45768a20, 0x04b18058, 0x121ef371, + 0x02a013fd, 0x818db7c4, 0x9b3d45e9, 0xeec1f428, 0xad3e9b3e, 0xb6e27ce2, 0x2e98b064, 0x773c6184, 0x4b3949e7, + 0x53d7e34e, 0xc75ee456, 0xaedf4553, 0x127ec114, 0x13532835, 0x31093637, 0x7a10aa06, 0x7960fc2d, 0x1598b247, + 0x94e2ee4a, 0x1e3f034a, 0x72becc4b, 0x8cd8d764, 0xb7552573, 0x5c6de6f6, 0x54c4d58c, 0x68bdfe95, 0xb43e218b, + 0xffea43a5, 0x492cbdd1, 0x686509d9, 0x2244ce78, 0xda997ef0, 0xc34459dc, 0xf2a877e4, 0xb9cb2a38, 0xe7a63fc4, + 0xcf2463f0, 0x4259e7ce, 0x57f03e69, 0xe10d2cfa, 0x0ce3a6a7, 0xb441b24f, 0xdaa09fca, 0x51d528a2, 0x2b491946, + 0x8af72634, 0x689d6596, 0xb3545588, 0xb858fe16, 0xea42659a, 0x76436b7b, 0x8594ace0, 0x1802f554, 0x0be78b4a, + 0x9213c76c, 0xed92e229, 0x3280f6e0, 0x304b35f7, 0x3cc90a80, 0x0173f4d5, 0x1da882e1, 0xcd0d8676, 0xcdd84b76, + 0x4c44b5ef, 0x0d2bcd87, 0x67d384eb, 0x3e20cdf6, 0x539a595c, 0x6a5446e4, 0xaf0ece62, 0x6500b243, 0x5f6b8345, + 0x24872ff9, 0x9a1409da, 0x4939430d, 0xfa88cbef, 0x3d53447d, 0xe8c9a5da, 0xfd74f829, 0x5b14473d, 0x301c63dc, + 0x065b9c94, 0x8d237765, 0xe8e24932, 0xee3cbec9, 0x70165e9f, 0xccb8b8f6, 0xbc2058ba, 0xcc1032d8, 0xd7bd1f54, + 0x7cd94be5, 0xaf8b805f, 0x2bc43805, 0x8d2596e8, 0x11555e42, 0xd39e3e0c, 0x0e157235, 0x7be3e97e, 0xb076460f, + 0xcd0a1402, 0xd3588a42, 0x958c7f47, 0x625336aa, 0x821dcc58, 0x961fd6f2, 0xbe692c95, 0xf3d46c61, 0x8d26a0db, + 0x314a3c40, 0x71f6d450, 0x7d98ee53, 0x29feaf4c, 0xc7ba88ca, 0xf6a975d4, 0xeab51d35, 0xf913acc0, 0x64068963, + 0x6da2bb75, 0x9fbd04e6, 0x9f99b572, 0x1d105f1e, 0x85dc0ff4, 0x6679d3fd, 0xf4b3587e, 0x26c714c9, 0x86c4ecc8, + 0xac1b90e7, 0x6e234784, 0xafc3c187, 0x1eae7ea3, 0xbb049963, 0x7a4c3b45, 0x96ae4331, 0x743fbd08, 0x0a416922, + 0xda28df77, 0xf4912308, 0x8c730242, 0xa40199a7, 0x8cc7b0f7, 0xbe073cd5, 0xa247502b, 0x227adf5e, 0xeeb59cfc, + 0x43622f22, 0x76276aae, 0xd9988aef, 0xc10996e4, 0x494d1e05, 0x9c6d70bb, 0x7ca2665d, 0x56daeb19, 0xc646c4b9, + 0x860ebec5, 0xf9309060, 0xfea4bc08, 0xe145396b, 0x79c966b5, 0x251ad69e, 0x1e605e77, 0x9a717f64, 0xe4f65ab0, + 0x5b09c779, 0x8c7c88df, 0xa6d09299, 0x56302273, 0x9947ca58, 0x6acff4e6, 0xe2bd3c4d, 0x31b6db90, 0xe12d3607, + 0xc56a644b, 0x0f4f8a1d, 0x8c8b34db, 0x73bad0e1, 0x6f0a9057, 0x6846723f, 0x8979434a, 0x3df78a9a, 0x4085a82a, + 0x377663a7, 0x0961f8bd, 0xf023d62a, 0xf5146ee4, 0x56bdea59, 0x4f43dcb5, 0xfb78e6a9, 0xeca00f74, 0x93562a18, + 0x1a59bc78, 0x5c4e89c6, 0xa419478d, 0xdaac6da7, 0x7b84febf, 0xb7bb9307, 0xd5ae55b6, 0x1f97b530, 0xfcdbb0a0, + 0xe0b6859a, 0xe4590948, 0x4eafbaca, 0xe1e97716, 0xc2945f10, 0xa5c0f85f, 0x4ac2bb3b, 0x35cc07e0, 0x76c6468b, + 0x9637f2ed, 0x2570dcf8, 0x204386b2, 0xbb15c1ab, 0x84d8a1ac, 0xd367c87d, 0x7e0b30e1, 0x3cb1467b, 0x30ae16ad, + 0x2649f697, 0xd81a8170, 0x65916dba, 0x52c0b3b1, 0xf534b271, 0x5706d177, 0xdb4f850f, 0xf16fa437, 0x3d3a4886, + 0xc5da2774, 0xdbe4a97e, 0x42c60368, 0x4f1e890f, 0xa1d72027, 0xcc128518, 0xaf5628b7, 0x5f6375bd, 0x7ac0678b, + 0x847de4b5, 0x5bb874ee, 0x1cc9b3e3, 0x353f45c6, 0xdd2ac179, 0x80e18c83, 0x00097429, 0x17de1ebc, 0x468962a7, + 0x10320733, 0x9fce6282, 0x9daa47db, 0xb45917f9, 0x2df7eb8d, 0xc0874627, 0x78b36f71, 0x9c545313, 0xc811c008, + 0x681133ba, 0x25c41b7f, 0xe5a3f1a6, 0xff400b09, 0x2ade24ac, 0xc3995d19, 0xc0f4dde8, 0x58e18758, 0x997870bb, + 0xa35242c4, 0x68a85c61, 0xcee84683, 0x3f3afb23, 0x1dbdb305, 0x1a8a7a0e, 0xfa8b74ad, 0xa9ca7fee, 0xe29f9365, + 0x9769dc70, 0x1d430332, 0x3ae6e97b, 0x6a4956de, 0xcfb402e8, 0x5790972d, 0xbcfa22b2, 0xf96713f3, 0x5c07775d, + 0xaf74c9c0, 0x5788390d, 0x992625d4, 0x4bd1052b, 0xc2f2897c, 0x0d2b777d, 0xced2cc30, 0x8fc64677, 0x114221d2, + 0xbfb2959c, 0xc6211bc1, 0x830be993, 0x4f4b3bff, 0x220b577f, 0x5f943494, 0xb081c947, 0x1d5646ec, 0x4f459b14, + 0x4862b07f, 0x856b7b5e, 0xca6e8e3d, 0x38089a3e, 0x42d6bd25, 0x5ff37152, 0xca8f14ba, 0xe0f7dd8b, 0xb98bb466, + 0xb0d4ccaa, 0x389f408d, 0xe02471d0, 0x3a3f10be, 0xf4c8d948, 0xec3997d0, 0xb49a2b5b, 0xcada22e7, 0x1786586f, + 0xe2a25e83, 0xae2b6f69, 0xd048a888, 0x468bae79, 0x20472e14, 0x0ec99c31, 0x42cf3d8a, 0xb54a97df, 0xaf146b1c, + 0x75582b27, 0x9de6af04, 0xa7005739, 0x150a24dd, 0xa8c22c4c, 0x633a86d5, 0xb7539ed3, 0x865ffc48, 0xad6b6874, + 0x26f67a84, 0x54797ef8, 0x6c2fd2d7, 0xa51320c9, 0x79566716, 0xfb27947b, 0x7e88762b, 0x0f5690c2, 0x0d6cf387, + 0xcab93878, 0xfa539738, 0x85aed1d3, 0x479a95b6, 0x7fd8c74f, 0x4535f85a, 0xba9303c4, 0x652b7acd, 0xd74fe80d, + 0xb9c758c1, 0x70dd1a3d, 0xb04ec074, 0x2d039b5f, 0x51e85926, 0xc5cc94ea, 0x8e31e17f, 0xf467b089, 0x1ce21a7e, + 0x9f625f79, 0x3dcbffeb, 0x23347f0b, 0x94d2255c, 0x56a58c97, 0x4579902d, 0x5c15a896, 0x0fbfc260, 0xe4cfed6b, + 0xb4dfdfbc, 0x8bd0ed78, 0x46d71699, 0xc18b081e, 0xb10bbd55, 0x7e8dff46, 0x389a63fa, 0x4f218efe, 0x9f18e4c9, + 0x4cbf8097, 0x5d698c0c, 0xb609f898, 0xbcfa5410, 0x6e3babbc, 0x1b94eb6b, 0x8e1e97ea, 0x964a2ac4, 0xe431415e, + 0x869eb4a3, 0x90b17ddf, 0x90782184, 0x3a95bc2b, 0x4454ab98, 0x81027d3e, 0x504849c5, 0xab13871b, 0x35991fe0, + 0xbd93be13, 0x2c03ba05, 0x6b150d96, 0xefe0907f, 0xd66509ed, 0x021992c6, 0x111f860a, 0x9f726f7c, 0x8cec726d, + 0x679e2e5e, 0x6ed3d5eb, 0xbfb3a17d, 0xf5184ac1, 0xcd780a57, 0x50e79a34, 0xc3f9c47c, 0x63a25657, 0x2234f450, + 0xdfd3992e, 0x44f8eb77, 0x6888a71a, 0x13da5a44, 0xd2cb2dfe, 0xe4312a24, 0xd79e6c53, 0xfdc72c08, 0x727abd8b, + 0xbe525521, 0xbbb8f040, 0x6ba649e2, 0xf5ce97b6, 0xd37fd33d, 0xdd009f04, 0x49e48a2b, 0x255ab389, 0x95ae6134, + 0x64b56f80, 0x14bf2f95, 0x82bfc5e2, 0xea1276e5, 0xc8e0c7c1, 0x8be3a478, 0x0347f591, 0xc597fc34, 0x15020fd9, + 0xc8b46d72, 0x5d8a7059, 0x9f20bea1, 0x3db66481, 0x088cff35, 0x2ac85fb2, 0xf5e6eb55, 0x6b1c769b, 0xd23a543d, + 0xc6dd224e, 0x4f383555, 0xf15ec575, 0x645df6ea, 0x0a68db35, 0x2828bd77, 0x66796659, 0x34017aad, 0x4e6e42ea, + 0xab265f19, 0x7af95db4, 0x97471eaa, 0xa636d881, 0xc3a3bb26, 0x081f8482, 0xa2f77553, 0xa0304066, 0x76fd2e95, + 0xafd498a2, 0xd1096d4a, 0x58037ee8, 0xb6d2eaf3, 0x898e5953, 0x0abd3add, 0x624676ee, 0xe874584d, 0x628d57ff, + 0x34cb7a82, 0x73b68a38, 0xb903aac7, 0x0d86cde5, 0x1529a6e3, 0xb8f0b32b, 0x5fda7ad4, 0x2d781f73, 0x504264f0, + 0xa56dfcfe, 0x1b8a1812, 0x286135b7, 0x05a89982, 0x72e62957, 0x59c7cf61, 0x35747cf7, 0x6d18d8eb, 0xd4f879bd, + 0x1395e08c, 0x0d96a496, 0x5d92481c, 0x86f2e1e6, 0x8b8e2e5a, 0xd365c844, 0x7c85ec9d, 0xc7a1320b, 0xdeb73ee7, + 0x703e4727, 0x41dfa897, 0x4b2a45fe, 0xfd48de8d, 0xa49012e6, 0xc239c634, 0x1635d9e3, 0x95e9bb9b, 0x82dc28e1, + 0x2d4449ee, 0x539353dc, 0x82ed9acd, 0x3de4c1b4, 0x147c753b, 0xeaaca1c4, 0x809f44cc, 0xbd279969, 0x5193ef1f, + 0x9a831899, 0x1610a709, 0x41f6c3ed, 0xcb0dc39e, 0xc5308099, 0x453452a3, 0x3fbe29c4, 0x87d4b2e3, 0x857a4900, + 0x61aec369, 0x2d3e6179, 0x2cf444ab, 0x806d719f, 0x6df9dc40, 0xad9b5f34, 0x974cdeb5, 0x262f9e62, 0x4e209c50, + 0xc06464b2, 0x8fb58f04, 0xdf4a6ead, 0x6045dbc6, 0x70e81c45, 0x9579cc8b, 0xd75eba8f, 0xd7a75f2e, 0xfd634f0a, + 0x490f6cdb, 0xf20fd33c, 0xf75b3da3, 0xd36b45ad, 0x30e307f6, 0x7812356b, 0xb231b164, 0xcdaf2d4a, 0x3a35b8b3, + 0xef651595, 0xd839d770, 0x9212f38c, 0x07f1ca57, 0x843f4827, 0x87f40d03, 0x156372f3, 0x38ec14ab, 0x56a31dae, + 0xf250676b, 0xcddde06b, 0xa5d0f303, 0x091a7921, 0x343b5132, 0xcb06b999, 0xb9c41016, 0x680d7d52, 0x217ef715, + 0x5d9ec4e1, 0x7ab62e3b, 0xfc879d93, 0x7ef2f149, 0x0bdc6dbe, 0x1bcb8140, 0x61027584, 0xc3ab4fd1, 0x51851cb1, + 0x02e21c8e, 0xdaa5858c, 0xc9f101d0, 0xc67c2cec, 0xf467afc6, 0x72cea9fd, 0x74bd0a98, 0x6037d904, 0x22981b1c, + 0xbdb8b67e, 0x5085717f, 0x343ebf7d, 0xab76d61d, 0xb38d8fdf, 0x836e5be4, 0xf78ca91a, 0xb2881e3b, 0x14560999, + 0x9e78543b, 0x9c557b20, 0x21a44f47, 0x4b8679d0, 0x70e89e9a, 0xe6c9b840, 0x6c199a96, 0x5b3db4c6, 0x59dbd38c, + 0x58688a9c, 0xa46b82d4, 0x96b5d2c5, 0x30afc0ab, 0x7b68ee58, 0x933f6404, 0x196e7cad, 0x55818f88, 0xb9034e93, + 0xcace7ac7, 0x54b62bc6, 0xe3fdc507, 0x43822dba, 0x1e5ff00e, 0xe72cbf06, 0x748a474e, 0xe331272b, 0x84d54036, + 0x51651bc1, 0x800636fe, 0x9fd427d3, 0xf188b6d4, 0x33a26a5d, 0x18c2fb58, 0x0ccae070, 0xcaedace1, 0xf1d5179a, + 0xeb6a73ee, 0x183680da, 0x5d91181b, 0x23697467, 0xe83ef37d, 0x22c2f543, 0xd584555d, 0xf30c5a58, 0x50678ab3, + 0x0b7d44c7, 0xf4ac804e, 0xdbe0ce36, 0xa5e86703, 0x2385006f, 0xd2deacb7, 0x065b11e9, 0x4ba4329c, 0xbc50161e, + 0x7117f3a3, 0x4a537e64, 0xabdf05d8, 0x8702fdf8, 0x6b4a6051, 0xefc4ffa5, 0xb954d912, 0xd572c224, 0xd3f29112, + 0x03c07d60, 0x791fdcb7, 0xcfb3d51d, 0xe52f8d68, 0x4a9dc0d4, 0x2ae1d2ff, 0xb4a24f79, 0xd0a99ea4, 0xb16f15a1, + 0x918c0ccf, 0x43e2c4b5, 0x8d8f05c9, 0x56004a26, 0x5da27c32, 0xf3fb0c11, 0x762526aa, 0xc17e92da, 0x6912571a, + 0xf5138cdf, 0x3620f729, 0x5b803538, 0xc5fc4d93, 0x0a2c908c, 0x2292a828, 0xb8f114ef, 0x8a6a49ef, 0x7f49ea47, + 0x2b7565f2, 0x0866b961, 0x237f887f, 0xcd0eac87, 0x41a5248f, 0x9c5c2f2b, 0xbc16a2a3, 0x659192f0, 0xc12624e6, + 0x6c009e93, 0x80096651, 0x8ebdcae6, 0x6e5752df, 0x75b69a59, 0x770fd198, 0xf2af1726, 0x383703e7, 0x268e380c, + 0x1424cd79, 0xcf31eaa8, 0x35be392c, 0xb7932db4, 0xa2e649f8, 0xa41a79e8, 0x4eda3827, 0xa0c5b5c6, 0xbb812f35, + 0x8e1b884a, 0xf567f4d7, 0x7fd8bbe6, 0x720c9105, 0x2d4b8392, 0x77644fea, 0x0fe74257, 0x3032cf03, 0xf7fe6ac0, + 0xab7a76c3, 0x07f89333, 0x378ff1cf, 0x57cb6f00, 0xb7b5d71f, 0x7c44c2d6, 0x86286ac7, 0x1eefc477, 0x0230e0ca, + 0x81489b82, 0x569f52ae, 0x2e4a8936, 0xddce82a4, 0xc143a55e, 0x1975b024, 0x155e2ec3, 0xa9e8a750, 0xfd9dc796, + 0xd113ebb3, 0x4f29d321, 0x6dc2254a, 0x177c60ca, 0xddad4d5b, 0xd95db9b4, 0x6f90a426, 0x675efe51, 0x0a41a4fb, + 0xf00e71dd, 0xaf821f9c, 0x07722750, 0xd6f46be4, 0x23ed3a62, 0x69702789, 0xbff1c639, 0x82e4323b, 0xebaec35e, + 0x8d7e8f6c, 0xc033950a, 0xc41d3bfd, 0xc833cdb5, 0x06961afa, 0xf9f26428, 0x20f29dca, 0x66dcfc35, 0xe5661a7f, + 0x3c419cff, 0xa867f0b0, 0x0831ebea, 0x54fb40a6, 0xad0d1174, 0xc162c16f, 0xc6e08a81, 0x0a01ea45, 0xd734427d, + 0x4ba6dc98, 0x6ca6aa27, 0xd4c802a1, 0xe83077c6, 0x2da87ef8, 0xb97d8235, 0xabd56e61, 0xeaf11b7c, 0x9c7fbf52, + 0x42841be6, 0xdaee8ca6, 0xf20e54e9, 0x0e6a49b5, 0x8aca04b0, 0xa176d9b9, 0x4878add6, 0xb88511ce, 0xb0b2d045, + 0x7b756eca, 0xf3b8a09f, 0xc7cabc44, 0xccdf04f7, 0x53de49fc, 0xc4f86111, 0xa224228b, 0xc51a293f, 0x5f1f1720, + 0x9ee7d486, 0x4f7bd973, 0x0314d7d0, 0x25788d4d, 0xb541b92d, 0x8d20621c, 0xc249c050, 0xc797c36a, 0xefcdd8d9, + 0xa6c79490, 0x2edf4474, 0x31248d71, 0x8b935e69, 0x90330fd3, 0x5bdfece8, 0xa942b33c, 0xe1bb174a, 0xe39481f2, + 0x99bef68a, 0xcbb88955, 0x815942fd, 0x0115ada7, 0x87b51264, 0x82d01c66, 0xd348b9c3, 0xb60caecd, 0x5da3d270, + 0xd0b8b409, 0xf5551b38, 0xb9794636, 0xf4b63632, 0x40de3b1d, 0x2ca9cf4c, 0x3bf9c391, 0xb82283cf, 0x01ecf582, + 0xafbf9685, 0x31cfe4ef, 0xfb5920cb, 0x9435a2fb, 0x610d9b1f, 0xcf615483, 0x4d6ebfdf, 0x60bc2c63, 0xd75723bd, + 0x6e7904c2, 0x9307ca95, 0x8c54939c, 0x1efde59c, 0x7241fdaf, 0x5f58308a, 0x381d4074, 0x368dabf3, 0x88cb0072, + 0x6b31a3ae, 0xc33d4b91, 0xe3a9fb25, 0x9cbde8ba, 0xfb3b021a, 0xd3aa7c46, 0x513c7488, 0x8cb2011f, 0x7a603821, + 0xfe5c3f74, 0xd1527b89, 0x8752ecaa, 0xf43130ac, 0x40e4bc0b, 0xb09e3841, 0xfb687c9d, 0x552582a2, 0xedce5830, + 0x23b111a7, 0xfc3d47bb, 0x38c1981f, 0x01593275, 0x135073a5, 0x825243dc, 0xccf1cc60, 0xee1cfacf, 0xcf579727, + 0xda89aca4, 0xae11fdc5, 0xc80d4af1, 0x3db177c6, 0xa3b1440e, 0x7f009a6f, 0xf728c138, 0xbd4c49f1, 0xdaeed81f, + 0x40986ac3, 0xdf70da31, 0xcd136b03, 0xc8da74c6, 0x0e78a062, 0xc9919dd2, 0x48c241bf, 0x78a81d61, 0x14585171, + 0x38e0b26b, 0x69f9450e, 0x1bfe1790, 0x49c05d86, 0x55a115a0, 0x83120e64, 0x570b6aaf, 0x32d441cd, 0x640d1bdc, + 0xbc38d065, 0x8481fb6e, 0xb43b8f93, 0x53fa0762, 0xacb2f944, 0x0b379a1d, 0xb9345407, 0x3c73b5e2, 0x6d3332f2, + 0xe0317235, 0xf49fffae, 0x165965db, 0xf2ea8f86, 0xc7804201, 0x6228e2fe, 0x3df8cd30, 0x2d6d41c3, 0x153b3a21, + 0xcb8a9dd7, 0x204bae97, 0x036b6163, 0xe88956b0, 0x3dec991d, 0x5d95f288, 0x3a77fc25, 0xc6aa1843, 0x2df9bd7b, + 0x2a0683b8, 0xe8265ee3, 0x26f4ae26, 0xbe54a31d, 0x42070e9d, 0x0493aa08, 0x17dc2058, 0xca808b35, 0xba6f4284, + 0xb4afbaee, 0x98dccc4e, 0xf386b4dc, 0x9053e777, 0xaf3b8442, 0x62af46a8, 0x80151956, 0xab8acf22, 0x2d778c21, + 0x609323f2, 0x20189e21, 0x6cdb9499, 0x06c70692, 0x2281befc, 0xc9997d6a, 0x520316f8, 0xf27d789d, 0xd693c7b0, + 0xb8ade3f0, 0x5caae045, 0xa52e7606, 0x9736f22d, 0xb6b86893, 0x6b0a2368, 0xd2506c0e, 0x6f3e400c, 0x783b8dce, + 0x1330bdaa, 0x101581be, 0x0164b827, 0x5f9c46f2, 0x7d21e0ab, 0xb8278182, 0x62d5bdc5, 0xe81fc650, 0x9415edfd, + 0x462e49ad, 0xed61a03a, 0xa1c677d9, 0x9eb2bc55, 0xe70a4433, 0x94b495d7, 0xda50d2d5, 0x48aa2f32, 0xb2ecf1f8, + 0x4529d6fb, 0xe04df174, 0x4880e334, 0x8f9272ee, 0x62b4e141, 0xcfe52c63, 0x3d6f288c, 0xcc1786b7, 0xd8fc0d6b, + 0x0fdabbae, 0x39fb4d3a, 0x172e47f9, 0x6156e3fc, 0x04985537, 0x8f6c182f, 0xa2dae841, 0x87d430a8, 0x965afed2, + 0xb011ce84, 0x3e199a48, 0xa70261fe, 0x52edd6ed, 0x58a04a0c, 0x6ebb2ee5, 0x6407319b, 0x79a2b7e6, 0x8cc1c2be, + 0xbab704dd, 0xf815a6a0, 0xe4124911, 0x523b7146, 0x81f4eeac, 0x0fb4b69d, 0xb2bf80a8, 0xe338999e, 0x5cd8cb4a, + 0x30d44648, 0x35415239, 0xcffaaa8a, 0x8ae86cca, 0x6ce689e3, 0xf6eef561, 0xf5511ef6, 0xee7ea15e, 0x70ba5571, + 0xe8c7dc93, 0xd9ab49fd, 0xaca9a10d, 0xb84bec44, 0xe0a2c583, 0x9dd22200, 0xcced5f2d, 0x0ec092f0, 0xbfd020d0, + 0xf658f5e5, 0xfcc077d8, 0x796002c6, 0x202f9eaf, 0x0731229d, 0xe0d247bc, 0x16a9ea4b, 0xef536adb, 0x08387311, + 0xac624ff1, 0x964b2af8, 0xd331062b, 0x5ec732f0, 0xb4f30841, 0xfa62f954, 0x785b1d04, 0x372b700e, 0xed822f15, + 0x110ac1b4, 0xa677f062, 0x81446344, 0x1529124c, 0xb890118d, 0xf3301c1f, 0xda82f6f7, 0x71586897, 0x2f776fd7, + 0x69391f36, 0x58ec04d6, 0xf2eeeab4, 0x52a5167d, 0x362d07e7, 0xf276b6fd, 0xad1eb522, 0x303f15c3, 0xbd1bd6dc, + 0x62c21456, 0x178f6c9f, 0x7348f0ff, 0xa2fe0a28, 0xfa1c7ad7, 0xb653a448, 0xcb4dc430, 0xf1e8f4bb, 0xf1e1d492, + 0x5fdc1077, 0x836236ed, 0x8054cd78, 0xe32e8f7f, 0xcd04bfdb, 0x16f25621, 0x6d98154d, 0x3d793fb3, 0xc84f1325, + 0xf740006c, 0xd6a351d1, 0x9cdb5d12, 0x4458f46d, 0x739dd95e, 0xf0e16ea9, 0x3c7261db, 0x2e8f8712, 0x84f5ac68, + 0x183daf94, 0xd6ed93b2, 0x68c9d855, 0x33c34ec1, 0x7d624b32, 0x028042c6, 0x94c48991, 0xdac43023, 0x12527509, + 0x16c5b0fd, 0xf3bda088, 0xd8d69dd0, 0x53b250b2, 0xda0ebca8, 0xcdf13f17, 0xbec72dfe, 0x98aa6f34, 0xcc4a06a8, + 0x1e031e3e, 0x542c149d, 0x1c90fa78, 0xb369b492, 0x04b2f16b, 0x3a12fc39, 0xfdb706aa, 0xb6e64468, 0x9fb868cc, + 0x9a1cda53, 0xd427b543, 0xed16bb43, 0x8e26d5c0, 0x6d61ea52, 0x43a224c8, 0x30c0b857, 0x1e7049d6, 0xd92423bd, + 0x119030d6, 0x3069ab95, 0xa33a7d04, 0x1ef3ecc0, 0x37acf8f6, 0x6e8d789e, 0x2d98726b, 0x4a68e9cf, 0xf873273b, + 0x54d14c69, 0x87718f80, 0xb984b967, 0x5f1ff6ed, 0xac557674, 0x0c8ab11d, 0x8a128385, 0x8c0239d2, 0xe874e138, + 0x1c728d81, 0x58ea22a3, 0x36aebac2, 0xb4d4cd68, 0x613454cb, 0xef45ee7f, 0x5861d5fb, 0x0583c348, 0x59623bba, + 0x2b1e3d31, 0xa4081dd6, 0x21e26e6e, 0x8dfb38cc, 0x397cd086, 0x4ffb8bc7, 0xfcb3cbdb, 0xc16728f7, 0x617dba33, + 0x052f9a1f, 0x0068ae17, 0xebc36931, 0xe80a7f74, 0x274e8d9f, 0x40bc90d0, 0x4690118d, 0x674aea81, 0x5d27eed0, + 0x30b64252, 0x1d6200fe, 0x25ad5cb9, 0xad4e5782, 0xed4b4995, 0x936cc54e, 0x49b30d74, 0x18d56221, 0x0ed9761b, + 0x2cbcf4fb, 0xb3925ca3, 0xbc3733e7, 0xf599c6b1, 0x250d73e6, 0xeef3b584, 0x7bc2da4a, 0x89329384, 0x92884095, + 0xededa97a, 0x9b2d966c, 0x378c38f1, 0xe642a01c, 0x12a5a7db, 0xfd888599, 0x389cfdb7, 0xc1be817c, 0x854989cb, + 0x30121d3a, 0xf12a2048, 0xb706868d, 0x8e4e97fd, 0xa97a5a52, 0xf358dc23, 0x56b5e33f, 0x6d186eed, 0xa6165484, + 0x6bce33dd, 0xdd39822f, 0x9030a9a3, 0xc3de4890, 0xc16df530, 0x66dc0d89, 0xd0d148f6, 0x672ffa69, 0x6908d2dc, + 0x950d240c, 0xd6bb9f7c, 0xf540f35b, 0xf0031840, 0xe538dc86, 0xc3613cf9, 0xb63b811b, 0x3baf1d35, 0xc73e77ce, + 0xcc3fb120, 0x41c95a53, 0x71b81b45, 0x2a963591, 0x74ff2db1, 0x497b509e, 0x671a68a6, 0xbc7d94db, 0xc13550ca, + 0xfe1f4dac, 0x9ece4a48, 0x042ff877, 0xda24fe36, 0xa78d6d2d, 0xc1881239, 0xf8b0505d, 0x4f1c3f37, 0x0487ee89, + 0x086417b8, 0xeee10724, 0xe4cda3bc, 0x5db697d7, 0x3f154353, 0x884eb136, 0x0305139c, 0xd5fd552d, 0x41ff4682, + 0xfb1c1c81, 0x926c93b5, 0xbdf20e80, 0xe2c3714f, 0xbb5877f7, 0x454ab021, 0xb4ae4f7f, 0x8dd876a3, 0xedc6a7dd, + 0x025c5b3b, 0x30b4a7ad, 0x3d18c8c2, 0x024d3144, 0x77f8447d, 0x58297824, 0x4bc4eca7, 0xcad63159, 0x153d84f1, + 0x36b07a17, 0x378f430e, 0x4fddfd8c, 0xe35386ae, 0x4746d758, 0xa3f2b119, 0xe6d6468f, 0xa8793483, 0x9921b403, + 0x4a311d8d, 0xe8b395f9, 0x7bd00337, 0x256dd7ac, 0x6da7e9f2, 0x06a658d6, 0x126e72f2, 0x9c28f2ca, 0x278292b9, + 0x71a30c35, 0x1c92182e, 0xc149bed0, 0x7d3457dc, 0x1ceab5fe, 0x06c84fd2, 0x5c115101, 0x1456132c, 0x5451308c, + 0xf875c9af, 0xc1174231, 0x5b0891e5, 0x13b02268, 0x1de14580, 0x9410e5fa, 0xab8ca6b9, 0xf152542f, 0x8cc697fd, + 0xc32730f6, 0xca5c4904, 0xc60bda2a, 0x4e9936a3, 0xd5da3e2d, 0x57748851, 0x6d08677b, 0x5a2c339a, 0x9cedd7b3, + 0x368fa3cf, 0xf09c809d, 0x220e0cdc, 0x36eed1b9, 0x0c071176, 0xb7e55656, 0xae393ae8, 0x0b662f9a, 0xf07b674b, + 0xec7b9b82, 0xb87fae62, 0x32b05f17, 0x19f8028f, 0xab77645a, 0xf553d9a9, 0x4168978d, 0x4b0bb76e, 0xd34f6000, + 0x286c41c3, 0xd7e8d15a, 0x1ce0d7fb, 0x9aae1f3a, 0xac1c2674, 0x9abe0c7e, 0x40e28d15, 0x76506294, 0xdc056ab6, + 0xaae2fed4, 0xc1bcf7b3, 0x561bcc98, 0x779139b3, 0xd381b53c, 0x44f4f44f, 0x69354558, 0x4debac0d, 0xbd788a97, + 0x3b6abc06, 0x80c0e657, 0xe71d960f, 0x04f23a18, 0x6fe4f52f, 0x9868a383, 0x7578df8b, 0xc965d4c1, 0x35a0bc7d, + 0xb3ccf5c8, 0xde4801e2, 0x7ab0d644, 0xe1cf0e11, 0x7f0d1221, 0x9e67c534, 0x95223613, 0x76964217, 0xad8b234e, + 0xada05e1d, 0x40a302dc, 0x58f1afcd, 0x25a000e8, 0xd6eea0da, 0x797f1a66, 0x3e01e261, 0x38b26ad4, 0x73f91da1, + 0xf5a1bbf0, 0xf957ac18, 0x2418def1, 0xa6a015e9, 0x9af318b5, 0x3cc871d4, 0x836b794f, 0x3ca5dad8, 0x8fced705, + 0xe0191a97, 0xef291c3e, 0x6c36bca2, 0xa1330456, 0x048282bf, 0xf4ef2269, 0x07159886, 0xdbc19aaa, 0x33bb64e3, + 0x560fb324, 0xbc0dc721, 0xa5fdf4fc, 0x69c25adc, 0x9cc6e172, 0x4c73c4b8, 0x6611e44b, 0x04b7f0bb, 0x4f58b80e, + 0x2cc44211, 0x24b7df0a, 0xe84891e4, 0x9730c35e, 0x4ee72b45, 0x9e349731, 0x73a6c66b, 0x929007ba, 0xcce56bdf, + 0xdfc790f1, 0x8a89e58c, 0x4d8d8f45, 0x3ec63c00, 0x88e996f6, 0x86ba8f9e, 0x04fef9e4, 0x9ba27032, 0x131b1a73, + 0x1dfc9be1, 0xf557cd52, 0x2c3caff5, 0xeea6ed3f, 0xe4213a6d, 0xb0984d32, 0x494fc60a, 0x63cdf5c2, 0x85c571d0, + 0xdbe10b7a, 0x64638ad8, 0xea4a3726, 0xf1b60c1c, 0x908d87cd, 0xe4aaa972, 0xabadb576, 0x6b6f7442, 0x14cc397a, + 0x217e08ab, 0xda07247f, 0xc075b729, 0x9b812ed8, 0x7f34c2dc, 0x630a2ab7, 0xf318e0de, 0x9094bbfa, 0x7b80365f, + 0x08f29c09, 0x048635a5, 0x0ea5184f, 0x1178c1bf, 0x294b137a, 0xc77358fd, 0x8f726b6f, 0x16eff25f, 0x657de66e, + 0x1f1e2e7c, 0x9731d28f, 0xb50468cb, 0xb0f026a2, 0x3f474346, 0x55a9fbcc, 0xe71aba4c, 0xefb28007, 0x1330b13f, + 0x496b507d, 0x32ab08ff, 0xd326008d, 0x45fc8371, 0x245aa3fb, 0x9a14ea0e, 0xf7abd411, 0x1f8abe67, 0xb9fb1de5, + 0x37fc43d2, 0xe5702dd3, 0xb8b3e0ee, 0x49c84286, 0xfeb86adf, 0xcbb5d761, 0x954750ba, 0xa7445891, 0x2bba9e73, + 0x01ae3dee, 0x21d28dc8, 0x9b68407e, 0xd92c85fc, 0xa1e4a8b8, 0x05b034f6, 0x91a95d34, 0x29b5e5f6, 0x036d5ab0, + 0x95aaf6b9, 0xa1bfaab9, 0xb4c849b3, 0x7b1034e0, 0x86ea3706, 0x5376d1ff, 0xf57952cc, 0xb6418db3, 0x3391780d, + 0xbd0f02ea, 0x7d688196, 0xd279d83f, 0x4a3f0cfe, 0x31cf8aff, 0x5129ef8d, 0xe0782fe4, 0xfba6a9e0, 0xec207420, + 0xef06a20f, 0x812b8726, 0x54d468cc, 0x329aedf2, 0xc8f4c94c, 0x1018be6b, 0x14190f0f, 0xfa872001, 0x50b153c2, + 0x56e97bee, 0x0996fe70, 0xdec45ba6, 0xeae7ed7c, 0x678272b5, 0xd6d06203, 0x8a01f848, 0xf6cd951f, 0xff7283cd, + 0x647ac57f, 0x1987ed5b, 0x37f23258, 0xc6d06ac9, 0x64fb9898, 0x71179e1a, 0xd94c83c9, 0xff78389c, 0x9811da28, + 0xf0c2d4fd, 0xf7dc369f, 0xd4e28c72, 0x1346e00a, 0x7da64339, 0xd488e9e1, 0x61797b12, 0xec59e724, 0x051d45c7, + 0xff7137cd, 0x6587ac7e, 0xce07c79a, 0x9bb32825, 0x347daadb, 0x6c972a3b, 0x0d2da2af, 0xc7dd295f, 0xe2d5c3ab, + 0xb80d93f3, 0x6859de5f, 0x9fde53dc, 0xe51ea6da, 0xa7d7ee54, 0x9a616246, 0xcc94641c, 0xb0e7608c, 0xa71ae2c8, + 0xcaae3d43, 0x311460eb, 0x3bfe4ce7, 0x09048242, 0xd355b457, 0x6af2d2cf, 0xf5878992, 0x2f85de1e, 0x7a7ffd99, + 0xa70545da, 0x7c8d1fa2, 0xf9e887ad, 0x3a554488, 0x57d2d770, 0x2aaab27d, 0xf938aa0f, 0x64a2b36a, 0xbfea49e5, + 0x2fde4e16, 0x2136907a, 0xcecbfff4, 0xdc54b694, 0x084134bd, 0x1b35869c, 0x8023ccad, 0x5293c3e1, 0x38f9fef6, + 0x07062f4e, 0xaf5cd5da, 0x2aa2c4e7, 0x7f414f94, 0xb3990a6e, 0xf5d06549, 0x717fe25e, 0x9da4f446, 0xda75e914, + 0x90f9a88b, 0xaf0a1d80, 0x3594adfb, 0x70d0d8ef, 0x5732b50b, 0x7b145609, 0x27184e4b, 0x84e8afca, 0x4ff58088, + 0xaa019f02, 0x6d6b73f9, 0x2c762bf4, 0x2320a047, 0xde095aa0, 0x7ca9f84f, 0x072549fe, 0x0f98607c, 0x9049f221, + 0x6328a387, 0x69c52732, 0xf7f5e4c6, 0x2c0c4599, 0xab8555b7, 0x73f155b2, 0xe4720378, 0xe30204e8, 0x963e6e3d, + 0x33e3e8ad, 0xd5ced070, 0x03cf7d54, 0x2ff06939, 0x3d46c721, 0x90416cc7, 0xdd36e556, 0x55c76cc5, 0x348f93f3, + 0x97c5e71e, 0x856b5cab, 0xb033f7b7, 0xaf9f561b, 0x40ff0fa5, 0x412d2f4c, 0x0708acf5, 0x9175406b, 0xbf2f2bea, + 0x001c93eb, 0x2ef73da1, 0x1f6242ce, 0x7821bed8, 0x2af6325f, 0x523847a4, 0x53064e6d, 0xc6167328, 0x0eb10d65, + 0x60960f32, 0x0dcee2a3, 0xa31604ce, 0x9d3423d3, 0x071fbd57, 0xe45fc121, 0x66ede637, 0xe5201c17, 0x1c4e5c5f, + 0x4992ec18, 0xc69f49ab, 0x419eb5d5, 0x134b5fc4, 0x53651b64, 0xafe252e7, 0xd9236256, 0xe11ceb3e, 0x1acc80ba, + 0xbb5759de, 0x2ec89e6d, 0x66bfd6ba, 0x9e310871, 0x9a6706e0, 0x7338e196, 0x69048bba, 0x7eca5249, 0x4a785f5e, + 0x859cfdd9, 0xad459a4d, 0x3a39da05, 0xe6a08583, 0x695442c7, 0x0377cc6c, 0x754e1590, 0xfa78d24c, 0xd0dc2a5d, + 0x3c839ce3, 0x9264bba1, 0x83bc052e, 0xf2d88dfe, 0x7393e6fc, 0xce89a5f0, 0x6b4145ca, 0x91ae5dfa, 0x3cf89f37, + 0xddea9d1b, 0xc9ab96a3, 0x61183d1b, 0x69538196, 0xddb1d58d, 0xbe5dc2ef, 0xfb595444, 0xbc3b9252, 0xc5d02b5c, + 0xf989d123, 0x15a4dbb1, 0x45c0e14f, 0x29e99313, 0x72372868, 0xc477f0f0, 0xfc4bd70b, 0xe493e9f3, 0xedf81fc9, + 0xbbdd4fb9, 0x7e621493, 0x42e73c53, 0x82b70e39, 0xade0fc1a, 0xc214373a, 0x8793c6db, 0x49ce121a, 0x9b846751, + 0xb2a73c58, 0xc9592b6f, 0x642be787, 0xc6aa0236, 0x2c8b4737, 0x63b5152f, 0x4be1ff88, 0x1b6abaf0, 0x6d761b72, + 0x9b0b31df, 0x07dc01fb, 0x8bc20e26, 0x71f4e617, 0x079efe77, 0x25c7f98e, 0xea528d43, 0x8b060d30, 0x8e5f2775, + 0x1221cfdd, 0x6ad2154a, 0x7bc2c77a, 0x0f01f211, 0x5d6e0844, 0x88e9849d, 0xddc3cd82, 0x248f4441, 0x762dfc55, + 0x62887968, 0xff7b831e, 0xd6745e3d, 0xfe2a9041, 0xab5068c1, 0x90c6a1fc, 0x89eee61f, 0x936072ef, 0xab008d45, + 0x09b8d6f5, 0x044b5559, 0xa9affb9a, 0x7586487c, 0x1989f401, 0x0595b108, 0xd43ee456, 0x55036e14, 0x48b298c8, + 0x9fef9705, 0x25c5cff0, 0xe9105ac7, 0x7ef4d565, 0x3292eb87, 0xe5baa253, 0x9015a50e, 0x42f4a3ff, 0x84c995da, + 0x864d9857, 0x65632292, 0x18b40b2e, 0x1d6ea159, 0xa2e24122, 0x6e22b5a9, 0x841653cf, 0xc3d54a17, 0x4c4704d1, + 0x8ef96232, 0x22328896, 0xd65158b7, 0xf90f43af, 0x14356f5a, 0x4d94c25d, 0xfa5d127b, 0x2fd75d07, 0x82950a35, + 0xdb3e789c, 0x20088d0b, 0x36ee669b, 0xce27fac6, 0x6ed872b6, 0xe5810553, 0x6a5b5de2, 0x63b8cdd7, 0x7a8bc14a, + 0xcf52e2ee, 0x7a22da32, 0x150ac2cb, 0x3003f99d, 0x23d37a60, 0x9eb79bce, 0xa6306597, 0x4fff8e77, 0x095a02ae, + 0xf6b4ab86, 0x40779237, 0x3b89d702, 0xe1020cde, 0x4188ad76, 0xb258bef8, 0xff861917, 0x81e98b9e, 0x928b7884, + 0x48ae330a, 0x34dae89d, 0xe93bcded, 0x0fe91dc5, 0x9927192e, 0xbf3c751d, 0xdbce4682, 0x787c6c98, 0x8882df87, + 0xaa80ae23, 0x596217b7, 0x3223f05a, 0x76674173, 0xfbda8944, 0x69dc52fd, 0x9086812d, 0x9f7b90d6, 0x67c09e4c, + 0x09b8fb7d, 0xcef3b456, 0x1c59a44f, 0xac057ef8, 0x0f5f70c0, 0x7602ec73, 0x53233a5e, 0xd1227116, 0x7b44ae81, + 0x74bc785f, 0x05d94259, 0x7408ed67, 0x44c7e4f2, 0x5192fe2b, 0x6f8e3451, 0x173a2139, 0xecfd4579, 0xdf6a8798, + 0xcc197045, 0x56aab959, 0x8357a073, 0x9bbcbfd0, 0x51962720, 0x9b392a70, 0xadd817a0, 0x05710115, 0xaecb73b7, + 0x6afcc740, 0x71d22d9b, 0x820ab97f, 0x88dfa12d, 0x717054c3, 0xd84a342b, 0x1e285cab, 0xe9195743, 0x5ca88259, + 0x20a934e0, 0x41c51249, 0x0c417d37, 0xaceb7704, 0x37df9fdb, 0xdcc69037, 0xabf65331, 0xb74e8c92, 0x7a61f672, + 0x4b65ee9a, 0x8e2978de, 0x49928758, 0x5b85c7c2, 0x710886d1, 0x1c8552cb, 0x2db67dd7, 0x693fa2b8, 0x7da1c3aa, + 0x0e66931e, 0x17900062, 0x2d2b3698, 0x2ff7bb33, 0xa9b575b6, 0xe7ffa582, 0x9e15be69, 0x81845e60, 0xe9de8f91, + 0xc5a47f0f, 0x319f0a28, 0xed1ca32c, 0xf3e9945b, 0xca741e2a, 0xba0d98c9, 0x02e960a0, 0x0a7ad64c, 0xb3eaf141, + 0x9bdbc3cb, 0x2cbfc5c0, 0x40a797ef, 0x4b6f4cd6, 0x896c02aa, 0x3c1bafea, 0x1c869ea3, 0x00943d19, 0xd81eb571, + 0x5cf4713b, 0xe86f7c87, 0xfdd27b35, 0xccf6644e, 0xf4663858, 0xed7bd8ac, 0x2e898cfb, 0x0f87ab04, 0x1075aec9, + 0xa717a3c7, 0xf58bda88, 0x70d6ac2b, 0xc59de5a0, 0x87fe5289, 0xe0c7db6b, 0x6714f3f2, 0x621b70c9, 0x3baba46d, + 0x38599f87, 0x69d3d070, 0x8d7398d6, 0x10e8f166, 0x283bd15d, 0xf6b8ff30, 0x78b2cd36, 0x3a40cc6b, 0x7e1f7340, + 0xb7ae9e5c, 0xbf27a0e7, 0xee3e6674, 0x89b4e42a, 0x8e7e4d46, 0x50c3af2b, 0x8203c454, 0x76978723, 0x86101a61, + 0x7b8f9e20, 0x2c2f545f, 0x631cb45c, 0x47cf1226, 0xa7a9452c, 0x8afae227, 0x9a1e0c3e, 0x28cf2466, 0x2c9725ea, + 0xe5636856, 0xd80f46d0, 0xac881f27, 0xb7ad7e79, 0xfa84d573, 0x730af7d6, 0xbc19e92e, 0xf43dc841, 0xdfbe47e3, + 0xedcb1b24, 0x8c92a63c, 0x488b1295, 0x2d7a4ccb, 0x7868a1d0, 0xd6bc58e0, 0xe37338cf, 0xed5f5db7, 0x2a7d2920, + 0x47306749, 0xe8863c07, 0x91312720, 0x3e1ccf71, 0x9059cf74, 0x8242c0d2, 0x4637f886, 0x1cab94d8, 0x92441f8b, + 0x31ee9c00, 0xfff3637c, 0x4bd85854, 0xde4d190e, 0x03483720, 0xbb120a12, 0x6ac07180, 0xc13b7169, 0x4730a850, + 0x92d1cca6, 0x2fb2294d, 0x4f9ea8fe, 0x27b65fbc, 0xc579b13e, 0x4f46a100, 0x2c1e7697, 0x395e94eb, 0x87b41bd4, + 0x02f7b0ee, 0x0e3b1baa, 0x555eca19, 0xfeb6bc8c, 0x4c255759, 0x040aeddb, 0x3f7ea2fd, 0x40fbeec7, 0x6ff09c7f, + 0xb921bf00, 0x0d04bfb1, 0x2c2b8ea6, 0x16d1409c, 0x39ab5a66, 0xd5b5740c, 0x1d04ba05, 0xa6424fc4, 0x090a4838, + 0x02d3cd3a, 0xae24543d, 0x16719888, 0x8d6b5daa, 0x440a9a4d, 0x2f6b84bd, 0xf4540c4e, 0x3fdf8c17, 0x700d5f34, + 0xd26e5c3c, 0x7a5cd40b, 0x10ffaed9, 0x00099658, 0x7b07925a, 0x8e283589, 0xf3bb88da, 0x4aa61008, 0xcb486549, + 0xf828cb26, 0xbda48437, 0x9cf4229b, 0x911c4984, 0x9821f2c4, 0xce4a17ef, 0x20df2b9a, 0xac7067f8, 0x13c5b208, + 0x1e4ca981, 0xb74c3bc1, 0x808cdec2, 0x27f388e1, 0x6d2604ad, 0xed95a6eb, 0x7b309478, 0xddb43fb1, 0x426dff60, + 0x9cef4038, 0x3837f4d2, 0xfca18fe9, 0xdf06a575, 0x3e92a138, 0x07baf0a1, 0xc9018f70, 0x1147a14d, 0x877cc44d, + 0x9f4130d9, 0x97d52b37, 0xc9370102, 0xf878f8b7, 0x1e61c434, 0x273cf929, 0xce478123, 0xe5c861e0, 0xaa7bc2f5, + 0xa4e477d7, 0x3956eeef, 0x3a2f8c6a, 0x81253916, 0xff613050, 0x0c060fb2, 0x94040ce4, 0x7f617e06, 0x2e41768c, + 0x3b6e40f7, 0x53129b16, 0x43edfb67, 0x478032f1, 0x99f67a88, 0xf2fd80c8, 0x858ddac2, 0x852bf3ea, 0x0ff7b37b, + 0xee04886b, 0x7094db82, 0xfe5b955f, 0xdafb65d7, 0x515c1dce, 0x3abbb709, 0xff536829, 0x621cce28, 0x71ee78e3, + 0x00709208, 0x3ae36828, 0x6a2faa5a, 0xb52f7862, 0xbdddc9a7, 0x9ced1299, 0x0dcca4eb, 0x6c41471d, 0x8c01d64e, + 0xe1d152ba, 0x1bc80d5f, 0x944fb78a, 0xe4272ec8, 0xaeaed5a5, 0x89492d1d, 0x4de15ec2, 0x31443108, 0x63f45dac, + 0x9f076c4a, 0xa56bf741, 0x51dafb9f, 0xb1bc6282, 0x02d7f4b2, 0x2152bc76, 0x14918b08, 0x8476aebe, 0xbe032579, + 0x3c8adf38, 0xe0841725, 0x8970b160, 0xc4635cc1, 0x0c9f3992, 0xf9e84b88, 0xf41da993, 0x04a60360, 0xa22bc565, + 0xab229563, 0x70611867, 0x971bc146, 0x084917d5, 0x0026b068, 0x4a8d501b, 0x1ed4d715, 0x93ca5fa5, 0x9dd89382, + 0xbc4ad472, 0xe92ad1b6, 0xb8ff746b, 0xc748dae5, 0x06f9dbbb, 0xd6a6a984, 0x2c7b3446, 0xc674b76e, 0xdddd845b, + 0xa4e8cec3, 0x77437a9a, 0xfb980a75, 0x61fb2da9, 0x3ca19586, 0x8165be2a, 0x1e3aa775, 0x32e30f73, 0x6b95df50, + 0xce12f170, 0x6242ef60, 0x013e0236, 0xf10f6ae5, 0x0a56d36d, 0xe0413aeb, 0x13d5dee2, 0x226127fa, 0xf4d5d49e, + 0x02c45cff, 0xcff263f8, 0xe2f217f7, 0x62a644cf, 0xc59bfed0, 0x1715a943, 0xf7d20487, 0xe035769a, 0xb3bb37c1, + 0xdfb55b8d, 0x8befec53, 0x2129343d, 0x0c3280c1, 0x49bf1ab0, 0x336fec9d, 0xdea618d4, 0x09a4256d, 0x4ffbfdae, + 0xd071f0a9, 0x2c04663e, 0x93bf3820, 0x2c07676a, 0xe71db1e3, 0xba7ad862, 0xb4d2e5c9, 0xecca9cbc, 0x653e4c96, + 0x885fc333, 0x150dcab5, 0x360a31e1, 0x0e1f2c2b, 0x6a6c2683, 0xb4079181, 0x013a26ee, 0x45744040, 0xfc9c3457, + 0x6586eb38, 0x3472a796, 0x8bd5e1cf, 0xdf337c62, 0x30940799, 0x17cc87b0, 0x3924a461, 0x5f806d31, 0xf3f672a0, + 0xe8d01cbf, 0x77f7ff45, 0x5e0b56ac, 0xa02adf2f, 0x963cdb9f, 0x49a163b3, 0xdd5df8ed, 0xdcd138d3, 0xb64b195b, + 0xb212a20f, 0xfccb6da1, 0xf0fd502d, 0x44272357, 0xea68ffe4, 0x93a08457, 0x90d2df52, 0x62885564, 0x406e5349, + 0x251ba539, 0x2a44d6c0, 0x698e5a46, 0x8e2cc6c0, 0xdb38da79, 0x128c9e50, 0x7cc71d0e, 0x2f7ec89d, 0x987a071c, + 0xa9ea0b77, 0xf5d9c903, 0x74f8e3f6, 0x3bbdf9c3, 0xd49a5901, 0x9d1e6e13, 0xc207a7bb, 0xfb278e23, 0x373e8053, + 0x3bc12547, 0xe9bc9dff, 0xef445bfd, 0x715be9de, 0x31294696, 0xe546c8ba, 0xe166f965, 0xc7c70db7, 0x421b5ca7, + 0x64b99025, 0xc6f6733b, 0x515e70f1, 0xbbb657ac, 0x600ac859, 0x6f9a8f45, 0x639bd218, 0xd6d637af, 0x3650cff4, + 0xdfdb0f0f, 0x90fbe414, 0xff51092b, 0x8d961121, 0x61ee06ad, 0x1ef9a0bc, 0xc3d31058, 0xf7824609, 0x492446d6, + 0x2e813ef0, 0x00f15f44, 0x5849bae7, 0x59b10930, 0x48e2f9e0, 0xae95eb52, 0x5b5bba3f, 0xa4bd5a07, 0x1bf78d32, + 0x0f96c0e7, 0x3c5f6738, 0x237e9f76, 0x3a072d7e, 0x37b3b3f1, 0x322bd7da, 0x9fa41680, 0x75abc5d9, 0x4070018a, + 0x3c214fa4, 0x9ace2515, 0xc406106d, 0x2545ae12, 0x5b40509e, 0x933a28cb, 0x75986025, 0xfed3393c, 0xf64d614d, + 0xfbc56fd6, 0xc83e197d, 0xf5b01298, 0x7d73867f, 0x4fd05a8b, 0x7066d026, 0x076ca6fd, 0x43a832a6, 0x3661dfb2, + 0x3773e05c, 0x4d4bbadc, 0x4c327905, 0xdd64faa9, 0x567caf15, 0x9af936c3, 0x2bc83022, 0x5ddf4248, 0x784583ab, + 0x3c0ca402, 0x69f3ca07, 0x6ea09322, 0xfcc41c48, 0xdaee586f, 0xe99d1f09, 0x35d432f3, 0x2f89efa8, 0x2ea1f24b, + 0x16f5da77, 0x3e9ad30d, 0x0c08009d, 0x8ca82d89, 0xadd253a3, 0xb5031bfc, 0x48131700, 0xb2185962, 0xba856ecf, + 0x12746042, 0x00251192, 0xd08bed12, 0x02471ff3, 0x73fee1b6, 0x7a0c1753, 0xdcaf9ff3, 0xbbd100f0, 0x667aaa98, + 0x3dcf9d3c, 0xb4cb017b, 0xfc4d9e3c, 0x99614148, 0xc33ad25c, 0x2a54a37e, 0xbd57a7cc, 0x51a29fdc, 0x1a1f0057, + 0xb7370fe8, 0x1f14cff9, 0xded928a7, 0x30a05ca0, 0x5e085604, 0x7a7513b3, 0x26fd3577, 0x391e8100, 0xdeff079e, + 0x27e6ec3b, 0x0ee5d3e1, 0x3c15c264, 0x6b82b616, 0x0de89539, 0xaa577b2e, 0x45e82bff, 0xa4dcae8f, 0xbd3d0eda, + 0x3132eb29, 0x284f8691, 0xcd641495, 0xe7abac5b, 0x39883235, 0x51f07ed5, 0xe8dd464a, 0x09124509, 0xe5dc9d3c, + 0xdb868dc9, 0x1fa7fdda, 0x6aebb448, 0x0c2959a1, 0xe9305267, 0x962fcf6d, 0x665a7b5f, 0x0d64b053, 0x33645c85, + 0x480d7a6d, 0xd25cb6ad, 0x50338502, 0x517a1a95, 0x09e0553b, 0x2cfcc8e7, 0x3af09546, 0xc99a870f, 0xc4db6735, + 0x297f1a2e, 0xad26d7a5, 0x746a5719, 0xacc3234c, 0xacca57e5, 0x19f26491, 0x063a6b3d, 0xf28b570f, 0x3f86cc7e, + 0x39978cc1, 0xb33880d8, 0x941de399, 0xe3aba136, 0xdf683529, 0xc7902c89, 0xf33a66e6, 0x1123afdc, 0xbeab7005, + 0x289309cb, 0xfff11431, 0x440269f3, 0x6d206fd1, 0x8b4861bf, 0xf69c21e2, 0x247e3a50, 0x94ffd64e, 0x80b0dc56, + 0xb29d8df6, 0xf19baf90, 0x92324381, 0xc4a8b00f, 0x4f0e8262, 0xa2dc354e, 0xd5b8a0bb, 0x381d2664, 0xa133e429, + 0x4cf51701, 0x8d3685dc, 0x502c8b8f, 0x539b3aca, 0x8f9038f3, 0x0258a23a, 0xb4144c64, 0xaac61f9d, 0x71e0d082, + 0x4a318eba, 0xc2b80b07, 0x76e5f232, 0xb47e7cec, 0x614bc51e, 0x09b13ed6, 0xedea49ea, 0xfecde7a3, 0x848b3119, + 0xfbd5511a, 0x62a25055, 0x806486c4, 0x9ad5bb94, 0x22313994, 0x33cf596f, 0x201d17ff, 0x7438059e, 0xcad73279, + 0xf7a34c0e, 0x2b88fffb, 0x8954cd31, 0xe4ce2c79, 0x924bc9fc, 0x5cb5b063, 0x423bda43, 0x3e468701, 0x8a651016, + 0xc07aeabe, 0xeae3945d, 0x5311c012, 0x9caddc1d, 0x63c45511, 0x56404d5d, 0xd9d5133b, 0x2d63b038, 0xc95b0549, + 0x4fb31d54, 0xead37f49, 0x67a5bacd, 0xd68f644d, 0xead93ffe, 0x7ad49996, 0x3588c2bb, 0x8ce53a61, 0x131397ef, + 0x77f76c89, 0xf893b9b0, 0x8e35f66c, 0x685e30eb, 0x4d97dcb5, 0x4da9b6fd, 0xe2418183, 0xc51d0427, 0xb4aa8b13, + 0x48cfc2b5, 0x8a58d41f, 0xb8d7f943, 0x54bd027d, 0x0c2603a2, 0x79836980, 0xbac18d87, 0x4c367d95, 0xd0232465, + 0xacfaafde, 0x37714f85, 0xa747fb50, 0x047defc6, 0x30d610b2, 0x25758804, 0x22923654, 0x42221093, 0xb34065eb, + 0xce6eca3c, 0x9c3d55be, 0xfc1d3a91, 0xea2ea96d, 0xc02853d8, 0x4f2c22d6, 0x89a39265, 0xcad3b9f3, 0x4973bf16, + 0xa16c5803, 0x8017598f, 0xf2df1c85, 0x65e3f245, 0x9f2cd4d6, 0x6f9a829c, 0x08139fce, 0x2146e840, 0xe3c99c32, + 0xb9bca0fd, 0x9c3f01d5, 0x5e0e5bab, 0x9771ed1e, 0xc0cb90e5, 0xb195b0e0, 0x2e482906, 0x4c743705, 0xa90989f9, + 0xb6a77c9c, 0x9e457010, 0x5c19bb7c, 0x7ed242b5, 0x310a57e7, 0x17203a9c, 0x4fb3d3f9, 0x70d937ab, 0x4e1c0da2, + 0x944aabb2, 0x643f8de9, 0x1dc027d9, 0x4226b942, 0xabe8df5d, 0xc5abc5cb, 0x9b64a202, 0x53362714, 0xd00b48ea, + 0xac4777e6, 0xbf1b206c, 0x58f1c8d5, 0x61337f53, 0x4f9a1eef, 0x86bb7edb, 0x695f2b71, 0xe8414b15, 0x4797c9db, + 0x4afb7017, 0x171cf748, 0xd0e258e5, 0x4d7f0070, 0x710b598c, 0xbb26b719, 0x7ac3ae5e, 0xf42b909b, 0x9fa64da3, + 0xde37690e, 0x30451b08, 0xc0817e8b, 0x28ecc558, 0x16195ce2, 0x82d60376, 0x1ee3e06a, 0xd1800cf2, 0x26d93337, + 0x8108e471, 0x0413d848, 0x1779c069, 0x6e64340c, 0xc3813a61, 0xd727f43e, 0x4a799195, 0x5e5a336c, 0xe3f9acf7, + 0x6df86d84, 0xb5ec6863, 0x0061e5e3, 0xbffee46f, 0xabd116e9, 0xcbffb4c4, 0xce427928, 0x9eded4af, 0x9a7a7144, + 0xee588ae7, 0x96aef2c3, 0x194ee729, 0xa4281409, 0x71d5c6f7, 0xebc2eec6, 0xacac00f7, 0xcdcd0c4e, 0x5d543197, + 0x2a49e3e4, 0xef89046c, 0x1aeab780, 0x493608ca, 0x3b6c5dbe, 0xc1aa52ca, 0x1a19a71d, 0xd42cae73, 0x0859bc82, + 0xb41180fa, 0xc1b2d82c, 0xf2546741, 0x75b967eb, 0x4c10af6f, 0xdf86525f, 0x1fce39e5, 0xe9e891f0, 0xbe8ed312, + 0x772e0758, 0x573122c8, 0xb6781e2f, 0xef153316, 0x5edaf560, 0xde3f111d, 0x61c3612f, 0xfd7801e8, 0xd5448027, + 0x7f543096, 0x6ce063ab, 0xc9f2629f, 0x742bc0f5, 0x3344ac56, 0xca05d409, 0xcf097bfc, 0x48b6d4ff, 0x31c2976e, + 0xb80a57f7, 0x2619329c, 0x89880251, 0x465206de, 0x2eaddb5c, 0xfed273fe, 0xdec90d76, 0x3c797ab3, 0x47cbd98d, + 0x93369d82, 0xa12168b9, 0x2eab7b00, 0xefd33092, 0x0098f702, 0xd952a614, 0x4e2ea9d5, 0x3493a864, 0xc44016dd, + 0x199e50c2, 0x1d5fa745, 0x6dbadfe3, 0xab4f8286, 0xe7a39e2e, 0xf351b25a, 0xaa0f6832, 0xf9eab78a, 0x546f851c, + 0x1db0f93c, 0xa3da9de5, 0x49bf42a4, 0x3e6a3c94, 0x81cfd8e4, 0xfcb2ebd9, 0x1696dc80, 0xad4735e2, 0xa2e017ff, + 0x074ca328, 0x8aead8d6, 0x92153fd8, 0x9b3cf461, 0x61b23744, 0xa023178f, 0x39152d37, 0xc35c6d86, 0x0472edef, + 0x86791535, 0xc15f543c, 0x094587a9, 0x5cae7683, 0x789e4005, 0x1edfc46e, 0x4bba8a2b, 0x4836953e, 0xc2b560b1, + 0x036bcae1, 0x31bb0c50, 0x7a46e15c, 0x6f44d055, 0x95e6cfe4, 0xce91d684, 0x31850ffc, 0x2cc911f3, 0xfb34b1c8, + 0xf1ad7520, 0xb5e2ea3e, 0xf6a3bab9, 0x037f2684, 0x6c31fe67, 0x30336502, 0xf67932bc, 0xa87e6dc7, 0xaf485b91, + 0xc07e349a, 0x3a62cbb2, 0x6c372f2c, 0xd854add4, 0x17943cb6, 0xf4156821, 0x2dce0900, 0x904b83f9, 0x3a426a72, + 0xb63f262f, 0x6396cf2d, 0xcd4b69ea, 0x49e188a4, 0x89ffe215, 0xce33d25a, 0x682e17d6, 0xb5f80c45, 0xd9d299ca, + 0xdb6a0a89, 0x8ad119d1, 0x9b8617b7, 0xa4fe0d10, 0x0f2192e8, 0x69577bd8, 0xb5e7ae23, 0x0b10d548, 0xc22058d7, + 0x01db76a1, 0x4211f86e, 0x6e1f1972, 0x377370de, 0x7136aa73, 0x864b5b3c, 0x94d30432, 0x2f26f72f, 0xc2074105, + 0x2097ea2b, 0x68548d40, 0x226919a2, 0x34180515, 0x8d09103c, 0x28d4a846, 0x9207e76e, 0xff1e757d, 0xfb530459, + 0xc1ddb562, 0xfdc86b72, 0x62a960fd, 0xa5480265, 0xe169ec28, 0xc18aca3a, 0x3ad0038d, 0xb7a55943, 0xde494498, + 0x6bbfe93e, 0xac18509e, 0x8abb23d2, 0x89af0e4b, 0x18c4569d, 0xfcca1c31, 0x386397b2, 0xcda440c3, 0x034f0373, + 0xa6f1b5f7, 0xb2534d52, 0xa159a7b2, 0x22c753ea, 0x3be585d8, 0x861326b6, 0x23a9e3d9, 0x0b01e7b9, 0x4317dd77, + 0xbc26e714, 0x0bb94c79, 0x9b62310f, 0x48ac2c30, 0xeb60ce39, 0x597ae841, 0xa42b5d65, 0x230bf13a, 0x4a6a6c53, + 0x77cf5a65, 0x081764ae, 0xd268dc58, 0xd91ee530, 0xc3411daf, 0xdbd37d3c, 0x048ba103, 0xb9ebc053, 0x46f80d74, + 0x3d3566fb, 0x6701b491, 0x851d9e98, 0x5055fa66, 0x5380359b, 0x4a4bf87e, 0x7c41f09f, 0xe93f45e6, 0x55496b0c, + 0x6f62a42d, 0x89953333, 0x1f21047a, 0x65a97dca, 0x3d61ffa8, 0xf5a1cd00, 0xd7f60c4b, 0x29aea388, 0xa5a6b497, + 0x56259fc8, 0xec1abf35, 0x5374c621, 0x44758674, 0x85e304d9, 0xedd99269, 0xf5c0bab3, 0x52fef8ec, 0xd3e20df3, + 0xbb308498, 0x61aeace7, 0x13f42e75, 0x2e4309d1, 0x524b4507, 0xecaecd05, 0x4c6d0bf3, 0x3497c2e5, 0x266f55af, + 0x61836cf5, 0x254ed055, 0xbeca08a2, 0x69c80178, 0xa60806c9, 0xd5cef247, 0x7a187644, 0xa86db948, 0x204df3c6, + 0x614039af, 0x3242d5fb, 0x6acfc1e4, 0x915d67aa, 0xa7021c98, 0xa9a497b0, 0xd98b036f, 0x9f96b3e9, 0x7f5ce476, + 0x6345cebe, 0x790d8496, 0x9ce5ae69, 0xc88c7c59, 0x840813cd, 0x86a123da, 0xf5058eaa, 0x79511fd2, 0x4acc0c92, + 0x07a2565e, 0x08f23e95, 0xbe02ff8d, 0x736eb34a, 0xfaa8c63b, 0x68f6b367, 0x99434adc, 0xd0dccac2, 0x4c4a8ce7, + 0xda760f4c, 0x353f6754, 0x042e5054, 0x2c190dde, 0xcf8e8877, 0x275ef6d5, 0x64fe06c4, 0x0fdc1a9d, 0xe8c03f6b, + 0x29d7da2a, 0x44e42ed3, 0x5455961b, 0x8ce08de4, 0xcf18284a, 0x51b2f9c5, 0x998f4184, 0xa4ab2bd0, 0x1f26acf7, + 0xdcf93cd1, 0x1a89cf35, 0xedd53fd0, 0x2c56c29b, 0xdbc83d3a, 0xf4f459d9, 0xa1f8b60e, 0xacb135b2, 0xea01c65e, + 0x09f3883f, 0xcbd9e621, 0x7b70f620, 0x519bac94, 0xf73bd9af, 0x95c6463e, 0x8877beec, 0x880c6cd8, 0x5cb1408a, + 0x4f44b852, 0x95968e30, 0xb1675850, 0xf18e5cdb, 0x359c3da8, 0xd2d13ce0, 0x9cad2507, 0x5695a5f5, 0x49f94c6f, + 0x9d3f00f6, 0xcdafcb70, 0x8444d829, 0x1895ee76, 0xbe083c5e, 0x709144a9, 0xfa70b206, 0x37531f98, 0x3f594e41, + 0x14c6ee48, 0x827d409e, 0x1c4da35a, 0x7fd03a68, 0x46563a36, 0x6cba05d7, 0xeb037c0f, 0x599c7741, 0xd9297373, + 0x55a649b1, 0xb17c5f10, 0xd5674e50, 0xb2040780, 0x4ec13f7e, 0xd29ffab0, 0x6a76d84a, 0xdeea0c71, 0xe2eb2651, + 0xe64a372a, 0xc8c0aee7, 0x91a17340, 0xe98912b1, 0x89f8375a, 0x257f218f, 0x44967151, 0xa9015784, 0xb39cc8ac, + 0xe083fa68, 0xb80a9825, 0xf70d02c5, 0x893929e9, 0xe67d5e92, 0x25289b15, 0xc68e2200, 0x9bf82ebd, 0xaf54f186, + 0x7fae80b3, 0x26c0e432, 0xd2e6f157, 0x74d0f27a, 0xd5b0fc39, 0x8d442531, 0xe2695cb6, 0x708bf9f1, 0x2854f3fe, + 0x77b7c394, 0x4a8d568b, 0x885a5496, 0xac562cdc, 0x2184ecc8, 0xe1e78a32, 0x3a5ba7f2, 0x1d8e014a, 0x0c134273, + 0x85e6febd, 0x09b37ae5, 0x362ebb63, 0xf6a4390f, 0x7c2452a0, 0xe6ade23a, 0x09a62040, 0x036cdd12, 0x868acbf7, + 0xf525cea9, 0x76f0938e, 0x11a27928, 0x3ca8eb3b, 0x72c288a1, 0x2b6632a3, 0x37584c67, 0x6a45d262, 0x718f2d83, + 0xf38880c8, 0x3c16daf7, 0x804b0772, 0xd9bbcebb, 0xe18a7b12, 0x635944cb, 0xfa887c2f, 0x64822efa, 0x7213dd0c, + 0x95a53de0, 0x9035435b, 0xbb0156f2, 0x8e9e2a14, 0x81d4c5f8, 0x8a21db2f, 0x724879b8, 0xb915467e, 0x6802604b, + 0xa880123b, 0x94ec6132, 0x78d82c2a, 0x63aa750c, 0x96436cb8, 0x691d663c, 0x030496da, 0x346bb3a4, 0x2aaf0120, + 0xe74b799c, 0xa7d1b7f3, 0x6bc27714, 0x541132aa, 0xb2b6d616, 0x3cd3fda2, 0x30e4c6a9, 0xf632f4a9, 0x650a2df6, + 0x9e9b30e0, 0xeb0e41b4, 0x6bf2515c, 0x2ffe663c, 0x5e360962, 0x8834b1d7, 0x595d6544, 0x5ccc5039, 0x9826e31a, + 0xf27cd1c5, 0xbb059f69, 0x867cf1b1, 0x564009f3, 0x17fece4c, 0x6a77a991, 0xc932ba22, 0xac92f58f, 0xd916bf9a, + 0xa0e949c8, 0xcf5eaad9, 0x8498f704, 0x3f982ef6, 0xd66161ef, 0x60bdbe06, 0x90ffdac2, 0x6a0d9701, 0x7f60b948, + 0x6bd607e9, 0x00492386, 0xfa7ed7dd, 0x6004d56e, 0xdc3daa65, 0xcfc0677c, 0x32925637, 0xf2ccad95, 0x346edcb1, + 0x78064adb, 0x486c2a6b, 0x38ca7d4a, 0x334d11d2, 0xfb29379e, 0xdbde7110, 0x9abb1532, 0x6df29b38, 0xcf0afdbf, + 0xd4b8c41d, 0x72ceb421, 0x146b4ae7, 0x4096e932, 0x016943ba, 0x567baf33, 0x2f9a08d4, 0x52c0f48c, 0xad9ff490, + 0xf31394f6, 0xbad9389d, 0xb4b4b544, 0x23c1dde7, 0x7215d765, 0x4d7cc899, 0x888482e4, 0xcb98bbce, 0x5351a592, + 0x54b52c55, 0x0648070c, 0x3b034186, 0x32389930, 0xb8453df4, 0xf7d62a0c, 0x2571262b, 0x7aa76926, 0x9f73598d, + 0x0a200000, 0x66764815, 0xe3aafec1, 0xf513e1cc, 0x571a5809, 0xb8a197a3, 0xd45e7907, 0xfb48828e, 0x2bd36c75, + 0xe38f46d3, 0x0f7495e6, 0xa8a7c5b1, 0x97799032, 0x8bcf44a2, 0xa5cff535, 0xec250fcf, 0x42146041, 0xbf90722c, + 0xe9c00bc6, 0x3a7eb69f, 0x0b9b86a1, 0xd6e3669c, 0x0a5ad94d, 0x231e785c, 0xfe98a89f, 0x309aa866, 0x2cf27a0c, + 0xd7aa26b1, 0x24ed6652, 0x53f7fbfc, 0xd9d7930d, 0xca2f2c54, 0x7af45166, 0x0d709596, 0x7ed0f2ec, 0x4801ff41, + 0xd71dde1f, 0x30adcd62, 0x92073071, 0x03cb33fb, 0x9d74c51d, 0xeba43a02, 0xf5c7e700, 0x0e074ebc, 0x47b2e300, + 0x9becbd67, 0x21655993, 0x1977aeaf, 0x96aeff3c, 0xae6091ab, 0xe52bc546, 0xcc8cf9c5, 0x55671614, 0x81f0dcd7, + 0x001d2036, 0x798a4d1f, 0x77c5b27f, 0x0be0a42b, 0x7d4411ee, 0x3fe18db8, 0xb982d7b8, 0x9a67328e, 0x159ed59b, + 0xce4afa3a, 0x4f8929d2, 0x3a8d077f, 0xe4f525db, 0x23990cbf, 0x6acf4346, 0x90c52863, 0xb36a8d6a, 0x3d5aeaef, + 0xa6d30fef, 0x62844d5f, 0xaa0e1d31, 0x0013695d, 0x0a3aeded, 0xdb812b9c, 0xf16c5243, 0xda112275, 0x8530977e, + 0x6ea8d3eb, 0x5a66a3f5, 0x17de7a90, 0x816d6312, 0x3c566986, 0xb9224992, 0x0237b44b, 0xde45df7f, 0x97784eb0, + 0x16b2c50e, 0xf458dde9, 0x71f5fba5, 0xf069e8be, 0x5db37a78, 0xd346620a, 0x02a849a3, 0xd76fa708, 0xb7fc0e96, + 0xa2e54e4d, 0x5658c77d, 0xaa007039, 0x45d9f8a5, 0xe72fac40, 0xeeac1b97, 0x6f17546c, 0x8db4bd90, 0x08961ce1, + 0x67283a11, 0x57976797, 0x3b1700a6, 0x3c80a6cb, 0xde0848c2, 0x7ea274d3, 0x7dbe36a3, 0xd547b5ac, 0xba340a97, + 0x9c05ae36, 0xf9ab1215, 0x7227c935, 0xc83eb0c6, 0x5c293c0c, 0xa38d2205, 0x663e214e, 0x099d6283, 0xd53a95b3, + 0xd14ea913, 0xf7268aa9, 0x6246df39, 0x86e3b646, 0x17836289, 0x74959375, 0xf6318ae8, 0x2e0cc9d3, 0x75b7b406, + 0x5941d18d, 0x460593e1, 0xde099935, 0x84b56697, 0x4cdd0b3a, 0xd024669f, 0x54c240f6, 0x883834db, 0x28afb187, + 0xa9c9247d, 0xb407fa66, 0x53109f0a, 0x57a338ec, 0xbdf13933, 0xb9762fc5, 0x61933cbc, 0xb7b5a7a6, 0xd42c338e, + 0x401865a9, 0x89f9f04c, 0xe0458943, 0x58fbe943, 0x9b06896f, 0x6be81dfc, 0x7a903fcf, 0xacdf2569, 0x54d9f0d4, + 0x8828361e, 0xe1dbbe3a, 0x7946dab3, 0x9d48dbaf, 0x3da19bcc, 0x8bf16ffb, 0x4846fa45, 0x7597e453, 0x33425582, + 0x15346093, 0x6a553585, 0x12a4c8d8, 0xb360dd97, 0x421b7063, 0x027ec199, 0x14dd7660, 0x2bd2b290, 0xbb9baaba, + 0x12c9b459, 0x5f0cffdb, 0x629e1e95, 0x8873b43d, 0x30841684, 0x4d34b900, 0x93ce7f66, 0x4f904d68, 0x13a0cc04, + 0x8eb3d606, 0x3072d526, 0x2850b628, 0x1f0bb292, 0x35e9fd86, 0xba6e24e1, 0xe82bebba, 0x2d7095d8, 0xea24bff2, + 0x0fda304a, 0x522fea3f, 0x2b2b1ef2, 0xe81e3314, 0xfef3bf13, 0xfe1e3fb7, 0x82913fca, 0x8aa76c0e, 0xbe1288f2, + 0xa54d5668, 0x63fc4a1b, 0x71aea354, 0x2fde0762, 0x9b71a92f, 0x43fa035f, 0xbd1698f4, 0x4d93474f, 0xb9554625, + 0xc532119f, 0xccc789d6, 0x86e0062f, 0x2dc3d2af, 0x5756ec13, 0xba5772f2, 0xa7b7792c, 0x3b1cce26, 0x285142c8, + 0x1340c8e4, 0x38a60bab, 0xf9072a66, 0xbbbbbf9f, 0x287ee8b4, 0x3d3cc1f4, 0xc7c710d6, 0xba534f95, 0x690de5f6, + 0x043dd9e9, 0xc244305d, 0xcb608c13, 0x295e6f64, 0xf3be17c1, 0x1c039590, 0x375dea40, 0x73f77104, 0x0646b49e, + 0xfb0614d2, 0x7ce8063b, 0x56448b93, 0x1e73837e, 0xf255effb, 0x4cbc4854, 0x417a9a2b, 0x1af74322, 0x75767b97, + 0xfc62fbc2, 0x23be239b, 0x8cfa55b5, 0x9cde97c4, 0x99e3125c, 0xe0cb82cd, 0xfd9b61a8, 0x8c3b924a, 0xab9658f9, + 0xf26fa66c, 0xb62b4aa6, 0x2e641ced, 0x1c7b679b, 0xc7f2c64b, 0x9c31eef2, 0xe7089c83, 0x7b585a47, 0x37980a6d, + 0x575d2af8, 0x24c6ced8, 0x77d28b30, 0xc63185eb, 0xb4416121, 0x0ea1b7f5, 0x84c59889, 0xf4a6c411, 0xfb8af737, + 0xdf6c2e67, 0xfc034c7b, 0x31d5eadf, 0xcb55bde9, 0x63c17317, 0xf771e155, 0x6f21cb2e, 0xb32d7405, 0x765e3de3, + 0x8d1e2955, 0x61440201, 0x85c3bd5f, 0xebcda300, 0xaf1c6276, 0x67e5984c, 0x128de644, 0x2ecf9f22, 0x108f89c3, + 0x76dbbf52, 0x5f61b2ff, 0x0852bda8, 0xad9784bb, 0xf76420e7, 0xb78575cb, 0xb9b8d0cf, 0xc3244f0f, 0xb8062f02, + 0xa7c230fc, 0x17e318db, 0x4d31ca3c, 0x5b2aeb25, 0xb5cac775, 0x3c3cfeee, 0xb5627586, 0x5e75be15, 0xda4b2a2f, + 0x15fce719, 0x4a94856f, 0xea7cddba, 0x607e94fb, 0xe39f4324, 0x93706170, 0x7d6cf155, 0x3b2b440b, 0x453f85ea, + 0xff43e430, 0x3e1718c3, 0x2f816ff4, 0xd8d3d26c, 0x2c11de14, 0xb7b6eec0, 0xef87cf13, 0x6a1cc5cf, 0x8e74b15c, + 0xa6480508, 0x3ec0d299, 0xda385d26, 0x14d57f11, 0x67f5c55f, 0x8edc3221, 0x326828df, 0xf37a8e09, 0xc361ac53, + 0x4c2c7e5a, 0x7b022d69, 0x6d5e75d6, 0x4004e1e2, 0xd6e6f4f3, 0xbcbd985e, 0x5be8b66a, 0xe5d89f67, 0xd3c4a4c1, + 0x0d98799b, 0xd8028cdf, 0x34a7630b, 0x0768f12f, 0x2fc93800, 0xd7096a9d, 0xcb3e138d, 0xfee38447, 0xc57db19c, + 0xad7fd1d1, 0x8adb572e, 0xf412cb51, 0x178d9871, 0xa9968d8a, 0xb0f760ee, 0x46d65207, 0x52db25c5, 0x31dcf994, + 0x105d05c7, 0x0f9f2c68, 0x764320f4, 0x329c6fdb, 0xca3664d3, 0xa5993cb7, 0xd80e8ad0, 0x344a9e96, 0x28da8c62, + 0x3b841bd8, 0xf4337c9b, 0x57f36668, 0xb9b7afad, 0x21496aac, 0xe5a660d4, 0x81a9ef22, 0xd4612dc3, 0x23a619b4, + 0x8fd4e968, 0x72441a28, 0x0abfc519, 0xac81ea4e, 0x1a5523f6, 0xd6ac2f50, 0xa62620b4, 0xb4ff1566, 0x46089298, + 0xcfabe7fd, 0xf3761212, 0x2c81d882, 0x90ccdc31, 0x2acd9067, 0x9263d2cc, 0x3563ad6f, 0xdf0abd95, 0xa30bf315, + 0xba72a845, 0x25f1962b, 0x29d011a1, 0xcd9a0a65, 0x69b4a574, 0xd1cbccc2, 0xc2cea464, 0x67a66681, 0x6d5a3519, + 0xc59f4a90, 0xbff4642d, 0xbadc67e0, 0x7331f70b, 0x3bed8d58, 0xdcdb36c7, 0x0691f006, 0x3f50b269, 0xb36661c9, + 0x84534e78, 0xc2c0d536, 0x978ce48e, 0xbcbd571f, 0x3bd9f337, 0xaa1bd777, 0xb2b3b80c, 0xab89efe6, 0x1f905b52, + 0x6d89b61f, 0x7a27e35a, 0xfa50c289, 0xd246322c, 0xcf1b6e47, 0x3cdcb158, 0x3c062543, 0x1140efd3, 0x8334c7c1, + 0xca1c39b3, 0x2ca98552, 0xeceb9669, 0xcf38411f, 0x69cc59cc, 0x9b56fca8, 0xa88d6a29, 0xf2a83b35, 0x98c572de, + 0x2350c2f5, 0x1859bd85, 0x2dfb9f5d, 0xccdc685d, 0xbd7cb62a, 0x2608bbcc, 0xce46fc06, 0x928d7263, 0x15f29a53, + 0x69fa6544, 0xbb3e04ca, 0xdcfbd1ac, 0xe22d850d, 0xad967bf2, 0x3f7221d1, 0xccaea8c2, 0xe3ffc413, 0x0b2ad509, + 0xb19cbe29, 0x6cd6fb29, 0x0302ada6, 0xb7ab58e8, 0xda66c3fe, 0xd378851c, 0x25abfbb2, 0x8d8a3cec, 0xcd172177, + 0x3443122b, 0x3cbec88f, 0xaa8c8337, 0xa715c23e, 0xbad516ee, 0xba105e12, 0xa3b50637, 0xa821af50, 0x7bca29b1, + 0xb562de71, 0x6c3717af, 0xaae4ab0d, 0x6a48a867, 0xf70c4eef, 0xd1d480ab, 0xbbc4383f, 0xe9f8c5a9, 0xe3ac2ca6, + 0xa073beae, 0xd8450a40, 0xa76e0890, 0xa2fb8b1d, 0xf11c47b5, 0xe6eb1ee6, 0x5d1e2d11, 0x1aad7b98, 0xa6673435, + 0x7c8f3986, 0x26a971fd, 0xe04854f0, 0x1e718eda, 0x0690d27e, 0x4aad8651, 0x84851b88, 0xcf3018b6, 0x4185a3a3, + 0x6ed9342f, 0xde7e54ca, 0x344c4b85, 0x0f4d91de, 0x88bd52c9, 0x3667e0a6, 0xc628fcd3, 0x456f2ca6, 0x99b883b5, + 0x60eb7ba3, 0x0a252686, 0x2540dff2, 0x324149d2, 0x9274c0e1, 0x93f476fd, 0x60e8f520, 0x30ea2e26, 0xe936259c, + 0x3789f636, 0xd342c672, 0xdb35d881, 0x208e8805, 0x64556e2d, 0xf7007587, 0xa1aa3f56, 0x04945375, 0x27548a8a, + 0x58d8dfaa, 0x9a22b70c, 0xc657af33, 0x470dbc6f, 0x115e0df8, 0xc3586918, 0xadcc31e4, 0xc3199ffa, 0x7669af33, + 0xebcb53bd, 0x974ccb27, 0x901fb1d4, 0xd9526939, 0x026676d3, 0x85ec6796, 0x85a82800, 0x4134d25f, 0x19e00acd, + 0xe8b68745, 0x1ea5b152, 0x79220b8d, 0x363e8e1c, 0x6a6f02c7, 0x56de130a, 0x5f00015c, 0xc51c57fe, 0xac26466d, + 0xca796c3c, 0x348c4a3c, 0x63e53f91, 0x4f5187d5, 0x566d7206, 0xe6fe7867, 0x067a1220, 0xf3a8edb6, 0xf442d3a3, + 0xa858fe65, 0xe24e4d79, 0xc8544ca2, 0x57e43ad5, 0x5f57a255, 0xf73e695c, 0x7a4b0dfe, 0x41587c49, 0xe785928d, + 0x4c266d17, 0xc7bab847, 0xaf8470b0, 0x4465d045, 0xf16a133f, 0x476d88fb, 0x6558374a, 0x55f7dc77, 0xc70550eb, + 0x16109548, 0x92f23b13, 0x8b882824, 0xb312cf79, 0xc9d39129, 0x1e3ecb0b, 0xa9d7715a, 0x12c7a71f, 0x33fc6a5c, + 0x626d178e, 0x1041d7a1, 0xbe8e1089, 0x45c782ac, 0xc027bf90, 0xcde5b4a1, 0xd6daad68, 0x29e2f2de, 0x2db78ec1, + 0xe05006c1, 0x34475d0a, 0x304561af, 0x391737e7, 0xb47acb2d, 0xdbd77f6d, 0xb3b27fee, 0x5f90f34e, 0xad7a6c5b, + 0xbfa9cc07, 0x4673e11c, 0x5d0b0467, 0x3c779d3f, 0x077a8a22, 0x42ff3828, 0x11dc9411, 0x89eeea01, 0x671e4172, + 0x868fe986, 0xef7d75c8, 0x2419a2eb, 0x4dc618b7, 0xd229f34f, 0xefca8717, 0xe59e7dc7, 0x9b9c2099, 0x574ec17e, + 0x1e27fb8b, 0xb91a1e24, 0x14c89a41, 0x019696cb, 0xbba44856, 0xdd4b3d32, 0xc4bce3dc, 0x0c895256, 0x3a2e3cea, + 0x0ed6a73a, 0x9c47d93f, 0x044024b4, 0xd54af0be, 0x32742b8e, 0x2949d2d5, 0x28c6859a, 0x1cbbad8f, 0x02e493cb, + 0x318ad49a, 0xfb200d4e, 0x96d72539, 0x2096ade5, 0xc381a1ca, 0x54545281, 0x62f978f9, 0xa7bb35e0, 0xda3fd38b, + 0x3987d138, 0x15527d5d, 0xfeb3ddaa, 0xb62c37ec, 0x4f81e98d, 0x90b4a0ba, 0x314db1ed, 0x177a60f3, 0xa200c6de, + 0xaf2717b6, 0x0c6373ad, 0x0faaa8ec, 0x398777a2, 0xf71ef309, 0x0a562c4c, 0xc013b376, 0x15868310, 0xf56f7fa2, + 0x1ddb87be, 0x78319426, 0xaeb159ad, 0x6177f55e, 0xd54a5e0a, 0x87b6deaf, 0xb526daa5, 0x1809d4c7, 0x73d6e1e3, + 0x691aea97, 0x1ee5f97e, 0xd5f7d201, 0x6aec697e, 0x53471bfe, 0x3bc6d5ac, 0x925dba14, 0x7e20417b, 0x50f750e5, + 0x0ee17274, 0xafa5204f, 0xf6bebb7a, 0x56a7a84a, 0xd6f0f90a, 0x3a89a3d2, 0x5add9c9c, 0x93d50abd, 0x29347029, + 0xd51e8876, 0x8c8007c8, 0x791fd710, 0x56caecca, 0xa39b9506, 0x0a9aea3b, 0x099560f7, 0xf03e83f4, 0x9edac46e, + 0xc195308b, 0x99d8c830, 0x592f0749, 0xa3149a09, 0x3e9ae370, 0x46d7f763, 0xa78cb846, 0x1e21e0e0, 0xbcaf22ee, + 0x63202e4f, 0x5b1a38da, 0xb21c0c2e, 0x46e5e0fe, 0x1596ef43, 0xaf0bb8fd, 0x566e54c2, 0xd85c1110, 0x92394139, + 0x2c3482a5, 0x47ca47ea, 0xaf1720bd, 0x5743c3de, 0x2429f98c, 0xa3374976, 0x8deece99, 0x5e6f2554, 0xa3704652, + 0x821b3e7d, 0x03977f40, 0x1478f7b4, 0xdbba8d09, 0x36fe8acb, 0xcde54dc8, 0xe2e77767, 0x7d29cbae, 0x46b5e9f5, + 0x3933df78, 0xf3a249a1, 0xf9138a16, 0x369b45fd, 0xdad03930, 0xe80abdf0, 0x72112c1b, 0x2b486667, 0xd2c30c10, + 0x32b4ec76, 0xad649e55, 0x8dbd15ec, 0x702b8538, 0x3f2b6e1b, 0x4c60df50, 0x905890d8, 0x10ccd050, 0x9c308bc8, + 0x802ffc3f, 0x8df2ff2c, 0x4279a8ce, 0xc83ffa06, 0xdeeffdfa, 0x5d952890, 0xaf0a4e1b, 0xa1458c86, 0x3b11cc71, + 0x49f3cfac, 0x0e2677ea, 0x0f44bed1, 0xb06fbde5, 0x2e029323, 0x92809aeb, 0x330daa41, 0x3e358494, 0x017cba07, + 0x2e5807d1, 0x675aea99, 0x02542b9a, 0x46becb5d, 0x3a61d887, 0x8bedf010, 0xfc509f56, 0xaa3f1b20, 0xaa467bfd, + 0x65a7787a, 0x94a95f64, 0xbc0b8603, 0x3c9d3878, 0x7624d8fb, 0x8ec74bc8, 0x12c029a6, 0x4304e8a6, 0xb6785a8f, + 0x2bd40ece, 0x8c430407, 0xb8b2ca0d, 0xe82d8ab5, 0xdbe978a7, 0x83ecd3c1, 0x1fa19033, 0xa5861d66, 0x9aab40a8, + 0xe7976930, 0x9e21bb55, 0xadce6764, 0xb6e98cfb, 0x6b3984d3, 0x020be0ad, 0x9d1364b4, 0xd49d7314, 0x622016eb, + 0x85636648, 0xa6f93237, 0x4187fdc6, 0x0a605c32, 0xdc4b8fdd, 0x794a157e, 0xe8091558, 0x7aba0d0d, 0x5f5bf67f, + 0x830e430d, 0xc74c870e, 0x0dc3fd71, 0x0632a13a, 0x9599059d, 0x9529c9c9, 0xfb63f97a, 0x2f8a6923, 0x438d5a87, + 0x2e6d9e88, 0x33c07750, 0xb017ed67, 0x98f4425e, 0x8a3d2bdf, 0x8bbc2a08, 0xbebba588, 0x3fd60a04, 0x1cc13e16, + 0xadef12f1, 0x341b6932, 0x1ba99a46, 0x29011035, 0x3121725e, 0x0edc8667, 0xce138306, 0xb2efcb21, 0x65c04ecd, + 0xc7b0ef6b, 0xade7d1f1, 0xe5bad0c1, 0x76ecf0b2, 0x3cc4f1ad, 0x1b036305, 0xc72add64, 0x37982465, 0xfed758e4, + 0x531029dd, 0xe2f068e2, 0x0569deb1, 0x7bde4464, 0x03cdb6e3, 0x13f551e5, 0x8bf5303e, 0x4419dddf, 0x8c02f10a, + 0x58607301, 0x73cff86c, 0xfccc9d32, 0x9001f5a3, 0x59a319f9, 0x1a47c4c1, 0x21b92223, 0x3880279b, 0x5b156f11, + 0x23f0e4c1, 0xba693bfc, 0xec6d5c89, 0x4f1585fd, 0xd30eee20, 0xbb6937ae, 0x5e593414, 0xf01c8fea, 0x62eb77a9, + 0x92c11b79, 0x5e3017a7, 0xebba7e5f, 0x39a932eb, 0x4c8fbfda, 0x1c7cd86d, 0x221d3ddf, 0xd976473f, 0xabcbf8a5, + 0x9aac84cf, 0xe0687de2, 0xbdceb750, 0xae3ffb30, 0x60937a20, 0xf642e30f, 0x9395f4cf, 0xeaa67631, 0x52a19fa8, + 0xf9506437, 0xc0dd7ead, 0x0116829a, 0xe0f1cb42, 0x7edc8d7e, 0xc199f3f9, 0x17d16dfa, 0xe1ba26c0, 0x5d94ff98, + 0x59696a0b, 0xc0329838, 0xf9db5076, 0x4b9eff42, 0x8aba048e, 0x3b2cc528, 0xc984586f, 0xac94b1a5, 0xc0c9e3e1, + 0xe21de53b, 0x351c57a2, 0xd48e4d04, 0xe2ab24b7, 0xf258d152, 0x03aa222c, 0xb77a43cb, 0x4999dbbc, 0xc8ecf44c, + 0x874554b2, 0xad7516b5, 0x3cf56caf, 0x90709628, 0xe96870a6, 0x3707b551, 0x37a934ac, 0x98c88ecb, 0x357cbdd4, + 0x3149c559, 0x55368292, 0x3a986bb8, 0x359a778e, 0x76a95ba3, 0xccf79f10, 0xa736b81f, 0xf1f05696, 0x5f2186e7, + 0x4e79cd85, 0xbb570839, 0xb237d1cd, 0xb54948ad, 0xab23ebb3, 0xa8e2539b, 0xf3622466, 0x4422101f, 0x0824280a, + 0x0f4cc4c4, 0xc08b6153, 0xd8cffb47, 0xda0cf680, 0x68988922, 0x46d78073, 0x156f7ea1, 0x4224216d, 0xf66c2cc7, + 0x61ccd5a4, 0x6ebdc922, 0xe7e3c348, 0x7f39b5cf, 0x04320c0e, 0x8f0938cd, 0x58db3036, 0xd2edb495, 0xf689b466, + 0x05af0f40, 0x83087716, 0xbd6d29de, 0xa30c02e0, 0xffbb098d, 0x5d475d6e, 0x4f7dc30d, 0x90f8210d, 0xa12a1904, + 0xe0fc4a10, 0xab8304b6, 0xc7c81535, 0x7e35a548, 0xca4f52a9, 0x8eef5446, 0x354cbe6b, 0xc6fc7fd5, 0x498449ee, + 0xb12b770e, 0xa204af97, 0x3b94fbed, 0x4a75d054, 0x90780f56, 0x93147bb2, 0x51d4fe43, 0x74e4bc06, 0x7719e525, + 0x4fe27181, 0x377209d8, 0x55e7ac26, 0x9801c23c, 0x9662452f, 0xd238c09f, 0xca0db7fc, 0xb8e83161, 0x78a5ba86, + 0x0554533f, 0x82eb9a6e, 0x8ca2ae33, 0x671e2223, 0x7d2ff067, 0x4fd0bcc4, 0x5dcdee5e, 0x8d187fcf, 0xd72e65ed, + 0x348ced80, 0x97dbd5a3, 0xa434bca1, 0x57c80b13, 0x7454bc32, 0x4df00788, 0x48f40927, 0xb60c8e59, 0xd0bc4f5c, + 0x1723701b, 0xa70b9bd0, 0x0ffcf96e, 0x37db062a, 0x99c92c44, 0xd0c02768, 0x1a00973d, 0x14cb0ab6, 0x3c2640c6, + 0x2a81d68d, 0x64de25da, 0xccd9fcb4, 0xe161a5f3, 0xcd1ce447, 0x0f560e54, 0xf19222ef, 0xc444259c, 0x3b922852, + 0x6f86a462, 0xb1fd3410, 0xb908178a, 0xd4002511, 0xb65c72ef, 0x44181dc4, 0xedfcf485, 0x8ed7e983, 0x377d75fc, + 0xeb60dc7a, 0x8bd6c98d, 0x6860039a, 0xe170fd7d, 0x69427462, 0x801e43cd, 0x647f2b06, 0xa55c559a, 0xf5913bc3, + 0xcaa4fe5f, 0x0d3ad1e9, 0x321fb23f, 0x5a15fa3f, 0x61d15b2b, 0x036bcb1b, 0x33a01d93, 0xee178f2c, 0xa90838d9, + 0x0da96c89, 0xe21c264b, 0x0521fda3, 0x96d3eede, 0xec5e14df, 0x1bdf4d77, 0x0f1bc305, 0x1d0ba3af, 0x583bc764, + 0xed41a668, 0x656a35ba, 0x17c8d558, 0x749d3cd7, 0xb6996b6e, 0x50d9c3d6, 0xb8bedb4b, 0xf6c3d06b, 0x3bf776c7, + 0x65fea06e, 0xf7149856, 0xad6e5143, 0x7a7c2d82, 0x93460630, 0x441eb88a, 0xed425bac, 0xaa843149, 0xa2aac8eb, + 0xb7a17c15, 0x2097b60f, 0x9ad5177c, 0x1be004b7, 0xf1048c85, 0xc596fbef, 0xb27c1a42, 0xe89cd0cc, 0xff876adb, + 0xcabca370, 0x1fb1d956, 0x43f29661, 0xebf1da58, 0x09920847, 0xe48a059c, 0xcc9e35f4, 0x708553ae, 0x9efbf2fc, + 0x8fcbe8de, 0x55332357, 0x15794928, 0x8dc35b46, 0x361934ba, 0x450e9328, 0xfe29ac7c, 0xc4bbd0be, 0xa0760d5f, + 0xec15b95b, 0x596bfa9b, 0x4e82d4b2, 0xe8eacba4, 0x607ee5f9, 0xee3d0b55, 0x2c3cd77f, 0x6aac3741, 0xf4b8657e, + 0x2225d28e, 0x81777238, 0xd425f351, 0xe0f6f7e4, 0x0d8165ff, 0x432536a0, 0x4d0fe0e7, 0xc03474c1, 0x5f041470, + 0xb5153fb3, 0x8d2615c7, 0x7cd63344, 0x5c3884b3, 0x36ff0242, 0xa7104b0a, 0x23e0bc3e, 0x67670c8c, 0x6170bfe4, + 0x9c5b443d, 0x3c81694c, 0x5664784f, 0xb735237b, 0xd2a528fc, 0x5c2f3a26, 0x04acedf4, 0x806ddda6, 0xf7aeedfa, + 0xf12cc3be, 0x5dd1e49a, 0xe955ee54, 0xf6139fe9, 0xde2fa70d, 0xdbf357a5, 0xa5b2d066, 0xadb2f9f4, 0x7962dfa0, + 0xd3e869a4, 0x7d41aac9, 0x9071cd97, 0x96c72e6d, 0x6e966850, 0xafc39e72, 0x95e8d03d, 0x562a2376, 0x1ad98f7a, + 0x94698c0b, 0x6d89070e, 0x6d12ca3c, 0xc25da58c, 0x3364f3da, 0x560a0f7c, 0xf2da0d23, 0xc09cae51, 0xa74f3c24, + 0x34cd9c0d, 0xaca48ad0, 0x75be9664, 0x633be76b, 0x00c555f9, 0x3cb8e020, 0x50c2fe7f, 0x0677bec0, 0xc921f633, + 0xb216e4df, 0xb2fa2625, 0x36002b3f, 0x65189611, 0x4d6c1066, 0x5935b9db, 0xe0f4e57c, 0xaf49abfb, 0xb1ad8284, + 0x59b8e1e2, 0x5e87942d, 0x8340935a, 0xce91ee32, 0x15e9dd12, 0xa6ad1f27, 0x5a23aa9a, 0xa4b8b47e, 0x02d970e5, + 0xaf0bd687, 0x6b752afc, 0xa10db520, 0x658ae82c, 0xf8821d20, 0x21396f99, 0x1f1655d3, 0xf453e6bf, 0x92b72c0f, + 0x0c780162, 0x10af30b5, 0x42d4780b, 0x234726a4, 0xb9cb5d91, 0xdf638ae6, 0x95ee49b4, 0xaad3f3b8, 0x570be08e, + 0x59c515f3, 0xced02af8, 0xb182350c, 0x4d21488e, 0x52b10f81, 0x7a8c3c8d, 0xf55b90b5, 0x295cb6dc, 0x38736792, + 0x2449e392, 0x57c88599, 0x22b9357b, 0xf73f2a9e, 0xd52ad37e, 0x2462a06a, 0xbc4f712d, 0xf2276b65, 0x551f2898, + 0x2a90d745, 0xad2c8cf5, 0x428cb86a, 0xe8afa7e8, 0x12a46e23, 0x348bc28b, 0xb7379d07, 0x71e4681f, 0xdbfa2a4f, + 0x699e3e0f, 0x4c20a51b, 0x6b816d9d, 0x1c11d87a, 0x8e71e40f, 0x5f2cc324, 0x186a7e9b, 0x8d64227e, 0x40e50710, + 0x115dda9e, 0xf1182f82, 0x035ee319, 0x13417035, 0x7880aebd, 0x1eba5c75, 0xf8a3b4f0, 0x5daa41b3, 0x80f740b3, + 0xc6e5d4e3, 0xc629bcca, 0xa427eda1, 0x86dad440, 0x8b97dfda, 0x9ddc8f74, 0xa8ca991d, 0x1716cbdb, 0x774234ce, + 0x32d49ae5, 0x9fcd04db, 0x24e309ba, 0x6a9eb6a0, 0xab87f801, 0x2b5c025f, 0xa4c12af1, 0xc48a454d, 0x48381313, + 0x916de653, 0x7b0dbfff, 0x8d5dafc9, 0x758881ab, 0x3daa7229, 0xa22ab828, 0x68710909, 0xfc9b7b3c, 0x98a3612e, + 0xfd78a21d, 0xd43c1020, 0xc0661c74, 0x6c63aeca, 0xe50a063e, 0xeb3899a5, 0x289a3f8b, 0x0aaae2a3, 0x58bdc89e, + 0xa0d00444, 0xd615c0d9, 0xe384df28, 0x01c7a950, 0x01a50a54, 0x910485c1, 0xa00a3fe6, 0x51496a1b, 0x63bbc03b, + 0x92136f47, 0x83d69a14, 0xf2e69dc4, 0xa934cf1b, 0x3b71bbe0, 0x1a1851b5, 0xfbb07b86, 0xc79fce3b, 0xd273a060, + 0xacc286a0, 0x992e05cc, 0x44948ab0, 0x13347743, 0x32907d37, 0xedd0dcb3, 0x4c291546, 0xb8656d37, 0xcf1b7ff0, + 0x40dff3e6, 0x471a77a4, 0x9f66b8a5, 0x6873bfb6, 0x710bfdd8, 0x9ebe7a43, 0xe0d6d7bb, 0x6ff93f07, 0x6cbf8633, + 0xd115c9a8, 0x905a7964, 0x28cb78c1, 0x5be6a432, 0x3da27aba, 0x410a6bc1, 0x9de245f9, 0x18c6a4b8, 0x9a70f206, + 0x61ec525f, 0x3d95ee85, 0x107c1ebf, 0x268732c8, 0xfa962ec3, 0xd10606a7, 0xcff44dd7, 0x3b9f4f71, 0x4501f6dc, + 0x76369239, 0xdf29448e, 0x079c4487, 0xb7069eea, 0x06baf5e0, 0x9113f6eb, 0x12c4bc00, 0x8d84d499, 0x31018d18, + 0xf7deb9c4, 0x2ae70ffd, 0x6e482df6, 0xeffd0086, 0x0a499afa, 0x5017ce10, 0x61b247b1, 0x3ebd1e62, 0xb844f375, + 0x58eeaaed, 0x3d0bb234, 0x971fa809, 0x57c4381b, 0xa4ed9ac0, 0x85f8743d, 0xe917a988, 0xd4c47acc, 0xb623c4e8, + 0x4933f09e, 0x5686117a, 0xb60abade, 0xc0dc25e0, 0xf55aafca, 0xbf912fba, 0xffa41231, 0x6647affe, 0x72523992, + 0xdad6c533, 0x6e6fab1b, 0x3d51bc0e, 0x83ba0663, 0x56bf842f, 0x44320371, 0xf3eaa481, 0x8942ed11, 0xc81cdb34, + 0x5b27774e, 0x40c2ec9b, 0xd5d302ec, 0xff0c4ef3, 0xc80e4d29, 0x82452909, 0x1a44b460, 0x94a68a60, 0xd0f26a14, + 0x04eaf6dc, 0x2773c503, 0x1c07a8f7, 0x1b2a273d, 0x9694df2f, 0xf7d7698e, 0x98012c5c, 0x32023ab9, 0x057ce125, + 0x8395f38e, 0x91abde28, 0x7377bff1, 0x3ff7d95d, 0x2f696bf8, 0x4f55fabc, 0x5b5a84fb, 0xdba71a9c, 0x002ced23, + 0x220ebd37, 0x635e067a, 0x1dfb9cc8, 0xdab1529b, 0xec10852c, 0xfe8408e9, 0x5de0c595, 0x977ff91b, 0xe1df2b31, + 0xda0d5c3f, 0xeb274a7d, 0x8cc920da, 0x0f8a3e71, 0x849fb4f2, 0x5d522a3b, 0xb9cd52ab, 0xe64093fb, 0xadd373fd, + 0x28271d1c, 0x917784cd, 0x399bcd07, 0x16034b87, 0x99334de0, 0xaf9560b3, 0x6bba1fcd, 0x8bad1e86, 0x4ff0fc05, + 0xa5535304, 0x56553ef4, 0x11812ca2, 0x53956a23, 0xf43619fc, 0xcbdc5426, 0x48aa1611, 0x12ebd87a, 0xbc2bc6f3, + 0xd6064804, 0xb6120dce, 0x990799cc, 0xddcf21d0, 0xf9f631d5, 0xc6020b04, 0xd60bf11c, 0x192a4e6d, 0xbd898eef, + 0x9f73a267, 0xfa19671e, 0x7ff5ccd4, 0xdfec575a, 0x584bb3bd, 0x45752f16, 0x6893c011, 0x89a6da56, 0x49349362, + 0xd29a170e, 0xc663562a, 0x21657a50, 0x27268054, 0xd484bb31, 0x39378582, 0x487964b6, 0x94396188, 0xe4917542, + 0xa243c806, 0xf04d9c7e, 0x13e36f0f, 0x3e56853c, 0x1f8ccc79, 0x77389bb6, 0xe13d3c11, 0x24ec9848, 0x81eaa369, + 0xb04bd96f, 0x688a2464, 0x386b0f6c, 0x70fb7da7, 0xf5c953a3, 0x562ea5b3, 0xeb8f4a88, 0x71cb2963, 0x11a831b8, + 0x7cc1c295, 0xb565674b, 0xac3a57e7, 0x1db39dba, 0xfbb0ec50, 0x5db19d50, 0xa75cc7b6, 0x53591381, 0x091a1ad5, + 0x972a0d19, 0xe4e154f8, 0x4dc12d6a, 0x173d395b, 0x29599a78, 0x66d5c606, 0x9d4843b1, 0x2fefb020, 0xae587ede, + 0x54547da0, 0x997c02fb, 0x160d9b14, 0x607cb2a5, 0xb6066c30, 0xc9ad9d13, 0xfaab8241, 0x48440489, 0x9829d6ac, + 0x2474404a, 0xc0495ed9, 0x2829c325, 0x85a710d8, 0x0d9bcd75, 0x61c944fa, 0xc238fe1f, 0xe7c02c53, 0xe59294f1, + 0xeb5fc51e, 0x82c58401, 0x530b68f5, 0xbc7a2b29, 0xc8341e42, 0x09385883, 0xe73a39d8, 0x22e73ba6, 0x0a343a05, + 0xb38946f4, 0x6a36042f, 0x8f71716a, 0xb0adb49e, 0xb6914eb6, 0x1ed80e45, 0x5a7c381c, 0xa52aeb90, 0x89427392, + 0xc7b6caed, 0x6c6fe9d9, 0xc58dadda, 0x40861e49, 0x0fbb840d, 0x1bc9f955, 0x5aa3370e, 0xf2be4a82, 0xf02d23df, + 0x6e763ff5, 0x0169252d, 0x866c7ffb, 0xfbecdfb2, 0xd12a7d2f, 0x704b5681, 0x16deb972, 0xeab390b2, 0x3b90dfef, + 0x3834df20, 0xd63d4b94, 0xe0c6e6c7, 0xfb733031, 0x40540b01, 0xd509a959, 0xc3332178, 0x788adbbe, 0x5243b17b, + 0x3db5692d, 0x1f6cf614, 0x44db9071, 0x625b3c01, 0x5e8c410a, 0x351ce599, 0xaa53a974, 0xcd107b49, 0xb337d4a5, + 0x864ca85a, 0xc9bdbc3d, 0x7a9cc16d, 0x994227d2, 0x4bad6fab, 0x816b26b4, 0x8fec5ef6, 0x4598dd57, 0xda14c82b, + 0xf334298f, 0xb5a8fff6, 0x640beebc, 0xe25d0bc3, 0x78d8dba7, 0x5e2edf3c, 0xd83eb073, 0xfe8075cd, 0x6531fb19, + 0x615d3484, 0x266df9ef, 0xf28b3de7, 0x5e80b53f, 0xd2ff5440, 0xf82b7688, 0x0b788ac8, 0x6f4062f1, 0x40184715, + 0x0f56f2ae, 0x300d3418, 0xf3088e52, 0x42882c72, 0x25533739, 0x6bcf3795, 0x03411acc, 0x2e1fcd23, 0x31bb0710, + 0x1765f818, 0xf8fefba0, 0x2b1af5db, 0xfa99149f, 0x39b187ce, 0x2921a30e, 0xfc364fdb, 0x0f7cb401, 0x987350b3, + 0xf285dade, 0xfbfd5f61, 0x60531d87, 0xad29721e, 0x1a52a8c8, 0xb47b1baf, 0xdd238695, 0x1c93e419, 0xb80b806c, + 0xe313018f, 0xf5be68bc, 0x2758cc9a, 0xf338e3b0, 0xccfb9db7, 0x501f20ca, 0xdf9bbc08, 0x14641bc0, 0xd6830952, + 0x653bd509, 0x65a74902, 0x1097798b, 0x0d7adb6a, 0x8968e8f0, 0x88c5084a, 0x5bd5febc, 0x9ef5d876, 0x00229c6b, + 0x6cb68dd2, 0x2d87b771, 0xd65ac4e8, 0xa56733e6, 0x64804d52, 0x58d7d5e9, 0x437bf2e4, 0xe864a06f, 0x5785764e, + 0xcd6c25ab, 0x76160beb, 0xad202fc0, 0xc69e4a90, 0x44239ffe, 0x7466e16e, 0xd0c437b8, 0xd88dc289, 0x3f4c9337, + 0x0ac4b5b3, 0x470a5b1a, 0x30f5d0f3, 0x1ba803e0, 0xaa87726d, 0x905f3cd5, 0x3bec0399, 0x2129af37, 0x773c7743, + 0xefda0000, 0x919e94f7, 0xa5ce481a, 0xeeae83eb, 0x1ab98f97, 0x3cd581ff, 0x102355d0, 0xc14cd694, 0x5036c815, + 0xa31045a1, 0xa0c9e206, 0x82f31154, 0xb10ddd84, 0x27ecabf3, 0xe8716ee7, 0x833398d7, 0xeff92444, 0xc0484388, + 0xc17949bb, 0xba52a733, 0x1fec7c24, 0xbc52ec95, 0x0386df05, 0xdf78bf9e, 0x455226b6, 0x29ff0aa2, 0x6e705f8a, + 0x1ef9797d, 0x09a54ad6, 0x16161b0d, 0xfd82581d, 0xc395b81c, 0xe7ba9bf4, 0xd034e7ba, 0xcfac6f36, 0x0cd5deb7, + 0x1dbe711a, 0xd196d66f, 0xf964dc81, 0xca185aa1, 0xfce45a16, 0x6a90d83c, 0xf61a57f4, 0x5e678e50, 0xa0087dc9, + 0x0a5c152f, 0xa83fce2f, 0xa5263025, 0xdcc2a55b, 0xb28d2e9c, 0x491f99a5, 0x2bc2e8c7, 0x55be3185, 0x42f19990, + 0x4a85382a, 0x76012dd0, 0x90dd8ed5, 0x4e8c4e7d, 0x9de55afc, 0x48adb4c6, 0x84f62dba, 0xa2195b55, 0x17e9bec6, + 0xf9e56d11, 0x2b67732e, 0x469c2cc0, 0x442c0087, 0x804e70c8, 0x93dac3a5, 0x74d34e8e, 0x8c4bda9d, 0x539cf786, + 0x32e8b72d, 0xeb9d8c92, 0x28eacde7, 0x2ecbc46a, 0x29dc34f1, 0x64f53d21, 0xba09a8f7, 0x5cd75fc0, 0x8bcf70f7, + 0x670bb08d, 0xd6491cf4, 0xf71139cc, 0xa8598d62, 0x151ac2db, 0x666723bb, 0x58ee3583, 0xc0005c3f, 0x3f4b593c, + 0xf5976f54, 0x3b2c8d0c, 0x5e877d2c, 0x10333ca4, 0x1fe2f866, 0xa63c6ba0, 0x7c181472, 0x54b075d4, 0xb2175f0f, + 0xf9bdf2aa, 0x256b9de0, 0x3edaa053, 0xe3577ae6, 0xa579ac01, 0x908da957, 0xab53dfa5, 0xcb6525df, 0x5b107e12, + 0xef094277, 0xc085e476, 0xe3e812d0, 0x1ac89228, 0x935a9a90, 0xda12e2fa, 0xaa3e7ccd, 0xec313646, 0xfa483687, + 0x7487cf2a, 0x8ce11cf6, 0xf764f55e, 0xb8ddfce3, 0xa5aa7e7e, 0xfc86bc18, 0xc16bdc96, 0xa0636ea0, 0x6752b2af, + 0x0860bfee, 0x6367f074, 0x27fee7c3, 0xa983ba21, 0xea533178, 0x7b47619f, 0x983b8f95, 0xe1cadea2, 0xca6d193c, + 0x7284d044, 0x68355879, 0xaa2e2566, 0xf7f32ac4, 0x7d937e2a, 0x81286e54, 0x2e80ae8a, 0x67afdec1, 0xd6b9c72d, + 0x913bf1bd, 0xd27309b8, 0x176f5f29, 0xb298162b, 0x90488b58, 0xd28668db, 0xf9f0147b, 0xd24d0c04, 0x1af247c3, + 0xf0b712eb, 0xeb263c5e, 0x8d85052b, 0xf3fa0938, 0xc12487ed, 0xf5619fbc, 0x5a5ed01f, 0xd69da773, 0x9af6df21, + 0xf61040b3, 0xb5953c12, 0xf9d79803, 0xdbd97ff0, 0xd49ceb9a, 0x9c0f0635, 0xc5dfe3c5, 0x512a508f, 0xdbc0152a, + 0x04a945c3, 0xef343f99, 0xfaee501f, 0x6bd58b77, 0xad866edd, 0xf9266e0c, 0xba5c0560, 0x481e51a1, 0xa0ad5601, + 0x9f0ec8b1, 0xb1da18e6, 0x627811f2, 0x9e2b86a5, 0x2d769f64, 0x78616f0b, 0xbb6c3d90, 0xbcf19fe6, 0xd37982a5, + 0x2282d94b, 0xeea94e9d, 0xf1fe1f32, 0xdd5f895a, 0xa6787ea8, 0x744b5e8a, 0x865fe76e, 0x9594a68a, 0x12475080, + 0x3ae7d738, 0xc9d800ea, 0x79b95661, 0x9b305325, 0x25324200, 0x94e29d80, 0x8230eca0, 0xeac1e526, 0x37c3107b, + 0xaefe6150, 0x9f9906ba, 0x5a954657, 0x053f4d5a, 0x0052bb6c, 0x5c8c9fb4, 0x7f503c06, 0xd295ea7f, 0xc512318f, + 0x7c5b2ee2, 0x18439414, 0xceda611c, 0xe003be68, 0x53342bc5, 0xd9503ccc, 0xdf603e43, 0x4636cf62, 0x2fed1c03, + 0xa28e306d, 0x887d71b7, 0x4ed850fc, 0x67c8eae4, 0x73ed3b37, 0x3a89fdc2, 0x56b63b11, 0xb27f93bd, 0x53d1124b, + 0xb14b9423, 0x465852f5, 0xe6ae68b2, 0x92d60d88, 0xf43ca6fe, 0x5807a940, 0xfbc44413, 0x110ee827, 0xfa6d56ac, + 0xc0ea8321, 0x4e5dcc96, 0x197dbfab, 0x0b75b718, 0x444a784f, 0x0243fa46, 0x57c657c7, 0x781e9b6b, 0x8c4f6671, + 0xb8b28d56, 0x63530a74, 0x73708ee7, 0x3bf3558c, 0x36a8ee9c, 0xce234370, 0xa25367aa, 0x836e2a81, 0x8006a1e1, + 0xf423d2d4, 0x0f06cd6c, 0xe875dd71, 0x14152c18, 0x87bd2bf7, 0xc1842a63, 0x845bf56e, 0xb80cc6f7, 0x89846ef9, + 0x64398c67, 0xab399323, 0x622a5349, 0x05e88b27, 0x10fcec14, 0x63ba31d3, 0x114c858c, 0x9e0a6d1a, 0x719dda15, + 0x8738d8bd, 0x35a6f189, 0xe23be2d4, 0x40bf68d0, 0xeb101942, 0x1dc86bcf, 0x8edee1bb, 0x68a0100b, 0xd5802be6, + 0xe2587530, 0x4516e1b1, 0xb26bdeef, 0x35e688e3, 0x9dcdcc94, 0x3d5f0f28, 0x7b756d43, 0xb49846bb, 0xd242382a, + 0x22394e41, 0x58d33f16, 0x49db8535, 0x36e2a9e6, 0x3464255c, 0xef64ff73, 0x639e42f2, 0x50e34ede, 0x23777f73, + 0x3a0636d9, 0x428f5844, 0xacb57ad1, 0x1bc5505f, 0x52beffa9, 0xcc623330, 0x882e1058, 0x4d68b0ad, 0xe73b3d8d, + 0x078ef2a8, 0xa5e4a11e, 0xebc5b19d, 0x044a520d, 0x4717a44d, 0xd9354eaa, 0x279d16f1, 0xd479e8c3, 0x5caea4c5, + 0x81364a21, 0xd0c082a2, 0x4fd60a8a, 0xdbfb4081, 0xcd0e6ace, 0x0c57ae9b, 0x855491b2, 0x6a8f08e8, 0xb55bbdcb, + 0xb0c57891, 0x2f21ed05, 0x0378bb6f, 0xc50fd7c4, 0xa7b30c09, 0x4c446448, 0x01e14ffd, 0xe70cc5ec, 0xd4d1e404, + 0xfffeb1f3, 0x63ab1f2d, 0x9b4b0334, 0x86d0aa2c, 0xf24c5b9c, 0x218ff2ce, 0xe09ac4b1, 0x9d094c7c, 0x2b3029cd, + 0x346fc2dc, 0xbfe58fd0, 0x1dffefce, 0x66908c20, 0x1a9de864, 0xce674207, 0x84a76617, 0xe40ec99f, 0x5421dc66, + 0x2b2dda45, 0xc30ab343, 0x1330d93e, 0xc8947338, 0xc7d1ed91, 0x7b7173e8, 0xf409e9c7, 0x93df3067, 0xafa397d9, + 0xedded304, 0x57228ef8, 0xa2c72a08, 0x9533d7f8, 0xacbe5535, 0x27958cf6, 0xeea9fb37, 0x7fe0d3f6, 0x2198a6fe, + 0xb0a653fc, 0xbf1fee6f, 0xa3766299, 0x9f0de70b, 0xef71fd22, 0x0304bb0a, 0x1ffe3b09, 0x10c98a09, 0x7947386c, + 0xdfbc7d1b, 0xf211e1fd, 0x3595a33a, 0x85924bf1, 0xb7fdb870, 0x55db27a3, 0x3752d5e6, 0x5e6e7df4, 0x6a450248, + 0x1c23cb89, 0x80744937, 0xa41e325d, 0x5c0fbf30, 0xd0b734ce, 0x9a9e99a7, 0x3324e8d0, 0x0b18bf9c, 0x98124ad3, + 0x3a1e431a, 0xb05ef11e, 0x85a23896, 0x75026d0f, 0x96540aa6, 0xa346bcbe, 0xcc0acf52, 0xa8ac7d32, 0x326f5d4a, + 0x212b4623, 0x0bc46da6, 0x6b4066f4, 0xa0ee4127, 0x89c3a47c, 0x08f64b9e, 0x92543fd3, 0x6778acc4, 0x4d5a5391, + 0x99fc4dd4, 0x8057645b, 0x2f50dbdf, 0x244fb594, 0xdaf775d6, 0x41860577, 0xd61f01ae, 0xcb317dad, 0xdb82c9fa, + 0x066518c1, 0xadf87384, 0x9b7487c6, 0x1dfe5e46, 0xd0124a66, 0x9ea822b9, 0xaa9cfcaa, 0x981b90b1, 0x6eedc705, + 0x517a13a7, 0x42fb2381, 0x86392847, 0xd9c46154, 0xa31d737b, 0xb27103e9, 0x52d213e3, 0x619cffbc, 0x6d981164, + 0x0abef2e1, 0xb2ccf595, 0x3b99b2e8, 0xf3cf6e9c, 0xe6318817, 0x8423c3fd, 0x7409f16c, 0xe4f10662, 0x147aff24, + 0xee1d8589, 0x18312ba9, 0x7ce03b4c, 0xb3ae21d8, 0x2f8199ca, 0x5ce57763, 0x53eb7fbd, 0x5d747b2f, 0x10331cc5, + 0x0d054d6e, 0x664de3f9, 0x8ec7c42f, 0xdff7c7f4, 0xc1eb3992, 0x7a4acaf6, 0xed7ab8b7, 0x660fcd9a, 0x4888d6e2, + 0x522c197c, 0xcf24b18e, 0x0e451aef, 0x41edb002, 0xa19d0d39, 0xed21202d, 0x6a2048c8, 0xe80be182, 0x3f1b966d, + 0x6117b0cc, 0xf44a85d6, 0x0ead7ad3, 0x74f7a89e, 0x4e30c8db, 0x3d54f506, 0x7cb14412, 0x537faf03, 0xd7649792, + 0xda785bbc, 0x7dbf7970, 0xdbf3f967, 0xdfa6b35c, 0x525b64ce, 0x661d27ed, 0xd4980f39, 0xac801d00, 0x3adc5f3e, + 0x7c44543e, 0xe11ec0f3, 0xace9d2ab, 0x4053edaa, 0x39cbf4a5, 0xc8d04067, 0xb899df6e, 0xdc9ef345, 0x3ddd99c4, + 0x108abc01, 0x2fa47dcf, 0xbcfa6c35, 0x6c5a629e, 0x02c5f682, 0x6b1487e0, 0xa1b1e7fd, 0x0fded78c, 0x78e142ef, + 0x32477c57, 0x78115a3e, 0x21ffa648, 0xe6e7ed37, 0xd8d656a4, 0x972530dc, 0x3e6723b4, 0x32951c60, 0x490cbb56, + 0x76cba7b6, 0x910342c8, 0xba2887f9, 0x9c131323, 0x804afba6, 0xb5a3a66d, 0x7de620f1, 0xefdee6fb, 0xe663cc80, + 0x0c0e8097, 0x0231aea0, 0xa716c037, 0xfee18f4f, 0x50ecbbc9, 0x82fb550a, 0xa650d605, 0xe5ff6e30, 0x7c08aca0, + 0x4dfcd1cd, 0xe9f9db4b, 0x7914b429, 0x3c62e6d1, 0x7b73b0c8, 0x52a875aa, 0x4b2346c8, 0xc7a9a8b4, 0x1ea67d34, + 0xf572fbe2, 0x5e258d1a, 0xafff15d7, 0xa25879c5, 0xe60d9b4a, 0x0718851a, 0xc8c60983, 0xe2d5cc16, 0x4b2755e3, + 0xdaefe3a8, 0xb785962b, 0x2e314cb9, 0xbb62e381, 0xa4c6bc1f, 0x2778279f, 0x8e09dc44, 0x95c163ac, 0x14acd4ab, + 0xdc01ffb4, 0x8c8ac7ae, 0xcd136185, 0xece704d9, 0xbec6b19c, 0xdf3bbab0, 0xe8ddbda4, 0xafdf0a6c, 0x49589eaf, + 0xf3a53ec8, 0xbaa05339, 0x8b4220ca, 0xfff0ad9e, 0x380a233e, 0x09af539f, 0x087aacb3, 0x0929ecb7, 0x9059a4eb, + 0x3fc6bdaa, 0xb4bf1438, 0x4e4a9703, 0x36b2979e, 0x414132b1, 0xbe578298, 0x7d44cfdc, 0x1250f5e1, 0xd51a77a7, + 0x1038bcfa, 0x3228e916, 0x7a9c0826, 0x212c1c63, 0x90102362, 0xc15defcf, 0x93106d15, 0x8ece8efb, 0x9555c58e, + 0xe091f9df, 0xa00991d9, 0x7569765f, 0x9ef90347, 0x8c5d9aa1, 0x8807f99f, 0x77d5ebd6, 0x461fc10f, 0x734f04f5, + 0xda0a85ae, 0x71f82325, 0xa1cc3b5f, 0xe96c2351, 0x738f52fc, 0x5cd32501, 0xaf8fc57b, 0xa7b2bf99, 0x23a23fc5, + 0xb2a2e9dc, 0x3251131b, 0x7eba1e01, 0x7fab4f25, 0x8af28ab1, 0x7315bc07, 0x47f106a0, 0x9ac70f0d, 0x610554e0, + 0x4c119842, 0x5be86c34, 0x061219a1, 0xbde468d6, 0x2e4fc8bb, 0xf0be1586, 0x76d923ca, 0xb5b09e98, 0xb59569f6, + 0x57172eb8, 0x8846741a, 0xf813f76e, 0x3a32ffbf, 0xa7004ea6, 0xcd159721, 0xb7f71c8a, 0x5a0f7ba1, 0x962d12e0, + 0xef6785b3, 0xd9177362, 0x9a559d63, 0x0a03aa8d, 0x92125946, 0xa563828d, 0x18ce6941, 0x32d635d0, 0x573892e5, + 0xce9e7fa0, 0x19d967d7, 0xb66c545b, 0x785db12d, 0x9f011605, 0xa6315cdc, 0xeb703c30, 0xfbe41116, 0xa11271c1, + 0x12c555be, 0x836db4fc, 0xf8b18da9, 0x0027861e, 0x5f6d99ba, 0xed8a3dd4, 0xca5e2b6e, 0x98a58b43, 0x75d10ee9, + 0xc84991a2, 0xed8e5d94, 0x878e1fdb, 0x63f77e53, 0x29f6e2d7, 0xaac1726b, 0x00244e1e, 0x38bf2097, 0x931e6e44, + 0xe1817656, 0x1a55dd7c, 0x4eed402f, 0xde87a65a, 0x5d368eea, 0xb76bf846, 0xaec36571, 0x27374bfb, 0x80f4c6d6, + 0x1a9b961d, 0x32920f2a, 0xe85f9a15, 0xf6c4b5bb, 0xcdbead38, 0x3aef1712, 0xaf60698a, 0x006f1514, 0x1ab09306, + 0xb9f44b4d, 0x8f5318ae, 0x86da276a, 0x9b11b18d, 0x6e536607, 0xb28b23f3, 0x033be5d8, 0x4ea403b4, 0xd7f8bb1f, + 0xd5d49021, 0xac94c765, 0xf3269dfe, 0x3d80e97c, 0x433c0b7d, 0xf431ac99, 0x571e8abb, 0x12ccac3a, 0xf31323b0, + 0xb207f4bc, 0xdbc54579, 0x1af4d93b, 0x84ca57be, 0x136b4dd0, 0xabcddbef, 0x4af93c34, 0xbdd6abe3, 0x4e4bb9c9, + 0x162bd91c, 0xafa531ed, 0x0d276689, 0x620234ac, 0xfe729253, 0x94c1c458, 0x781c4a3e, 0x487065f5, 0xbf39a70a, + 0x72a6e00f, 0xe5d42f3f, 0x35b35354, 0x4146f020, 0x590bf231, 0xd1219fc4, 0xb434c82f, 0x95e66068, 0x7494faff, + 0x08afc73b, 0xa591ae1f, 0x2aa56d0c, 0x4f71e25e, 0x9fbea8ad, 0x8d808302, 0x1f38ae03, 0x5ef6a989, 0xf0ec39f7, + 0xa6829d6a, 0x4fe6d569, 0xe810f1eb, 0xa4b6a4bc, 0x09ba63b6, 0xd40715ed, 0xd67897f7, 0x9f5c6a1c, 0xe9ad90de, + 0xacef178d, 0xfd076950, 0x2bc340a6, 0xcf6ba237, 0x5987c2c3, 0x4c03167f, 0x746c986e, 0xdd8bef38, 0xe8d9e546, + 0x43624e7d, 0x3af32487, 0x3dcceac7, 0x55474d8a, 0x3c1fc7e8, 0x2142a112, 0x42ed465c, 0x442632d0, 0xce830cfb, + 0x06f5ce26, 0x6169fbf7, 0x99bb20f8, 0xed5dab5d, 0x597c5d64, 0x5ec2096f, 0xc0c37c0e, 0x9629fd33, 0xfaf67487, + 0xc97a75ea, 0x33eade03, 0x24991a4e, 0xfc16324e, 0x7f984fb5, 0x963a3d42, 0xa3e4ae54, 0x59745088, 0x0f47d4d6, + 0xc684878e, 0x1b817db5, 0xf68d8681, 0x73d0e8bd, 0x07945ed5, 0xf2546cb6, 0xca7f2d8d, 0x8eab4492, 0x0ee9576d, + 0x6ab3ba89, 0xd6f0a067, 0x4788ed46, 0xd2e36de0, 0x6f7b4369, 0x1c975e01, 0xc4c1ff5b, 0xd3e50401, 0xefc29829, + 0x9673664b, 0xec186b61, 0xae996e29, 0x60271ded, 0xc72e2e63, 0x78c18345, 0xe8c760c3, 0x288d8b18, 0x4cee6414, + 0x9a5a94cc, 0xe8ed9a03, 0x83475baa, 0x8a314caa, 0xe2a50d57, 0x493b0877, 0xadcb6fd3, 0x86b46965, 0x436878b6, + 0x619d1272, 0x0fb0f33e, 0x0a529c06, 0xb81512c7, 0x6990f1b2, 0x3275dd10, 0xe75f4090, 0xda318467, 0x36b89796, + 0xc1dca7f2, 0x1b426d18, 0x13e1abbb, 0x82f4e28b, 0x4af7d61e, 0x9de273ea, 0xbaa60704, 0xfd9f38d8, 0x6b0cdaae, + 0x49dff859, 0x59f3251b, 0xfe4e917f, 0xb09acae5, 0x5d4796e5, 0x34e2d84f, 0x29b58afe, 0x59278fb8, 0xee4e71d7, + 0xf69f39a4, 0x254da680, 0xcc00ffbe, 0xaced8e0d, 0x579bd296, 0x468f47df, 0x99920e37, 0x88a55a75, 0x17a58b2b, + 0x00fb10cf, 0xf2b756dc, 0x1581b298, 0xe50467b5, 0x3ee1eb6a, 0xe193e861, 0x48319ecc, 0x493911c7, 0x643a3252, + 0x54e01046, 0xec038c3e, 0xbccf636a, 0xa8256fcb, 0x614a5c79, 0x842006cb, 0xa51c24c6, 0x2a12bfff, 0x6a10a205, + 0x42903538, 0x74e90417, 0x50cd2e19, 0x9f94892d, 0x952ec64c, 0x20a5b98d, 0xf4c21d4a, 0xf0200c76, 0x10fcb9f2, + 0xe3e25f16, 0xf8e3b67e, 0xcd06f7aa, 0x82fbdffe, 0xa2972d71, 0x41ce88bd, 0xd8964c8c, 0xb514f301, 0xaa0f8f9a, + 0xf69d1b89, 0x85f1ec1c, 0xa511ac26, 0x719db344, 0xeb435da5, 0xbcaed322, 0xe4d9c761, 0x8b64d4c5, 0xa94a555c, + 0xae690240, 0xea893774, 0xa0014013, 0x20a4c8a7, 0x91051c6c, 0x1bf27dc7, 0x7029b87e, 0xf1556cfb, 0x093a6fee, + 0x3541216a, 0x2288f2be, 0x8532eb7e, 0xb2959f47, 0xbedd68ff, 0xe005eba0, 0x28dcd72d, 0x4e948880, 0x84d04d24, + 0xd3c61aa4, 0x9c997f4b, 0xffa2ff58, 0x1206e2aa, 0xc1c0f8ba, 0x517545b3, 0x927d7ebc, 0x5cb8f897, 0xceea8ebc, + 0xea94b665, 0x65f81144, 0x97d2d5ea, 0x4039d00c, 0x36e6bd7e, 0xd9655365, 0x4ce09dae, 0x5e4abb83, 0x7bc9f08b, + 0xb50d5314, 0xd13c3c9e, 0x0a769f2c, 0x0cacebf7, 0x856a193c, 0xb9bcec24, 0x248a5913, 0x70b856dd, 0x578cba3f, + 0xbc81e52f, 0x85ad7cb3, 0xf1ef5d96, 0x16f91eaf, 0xa6f92c0b, 0x10bf0de2, 0x2567f090, 0x9c685326, 0xabdde1f2, + 0x8124c6a3, 0x3f63a9f6, 0xc28cb6f0, 0xc70b0cee, 0x16dadd71, 0xb412a3d6, 0x34576bd0, 0x5ea73110, 0x1512f043, + 0x42037a0a, 0x5d4c055c, 0xd2a76b17, 0x6af1600c, 0xe9eb94cb, 0xf221462c, 0x18661df2, 0xd114e325, 0xda954339, + 0x80c59dd2, 0x86c2a5e4, 0x3a4e5344, 0x7741991f, 0xda47235c, 0x4c7ab89c, 0xb5e39c99, 0xb35bb6cf, 0x8a39fbd6, + 0xbd8b5f92, 0x07f4a835, 0x7dedd432, 0x550589cb, 0x1e4b8453, 0xf0bc5bfa, 0x342be015, 0x455ed2d6, 0xf5182242, + 0x5935d810, 0x248b149c, 0x459057dd, 0x250505f0, 0x77ca769f, 0x816abc52, 0x5e622bd3, 0xf2959565, 0xf7c1ce16, + 0x1bb583cc, 0xe40d6b22, 0xe20c65ec, 0x70d95155, 0x9a104e30, 0x67d5725d, 0xc28688fc, 0x61538bcb, 0x186a63ab, + 0x91b99dbf, 0x0facd56d, 0xc4a26aaa, 0xb8cd72ab, 0x43d8952e, 0x52d3b7c8, 0x07412d7b, 0x71038a19, 0x15a72b27, + 0x1c9d2184, 0x1a09a50c, 0x930c8c47, 0x029986b9, 0xcf0cddd5, 0xfc450d80, 0x92a9d696, 0xc87de8f3, 0x69a180e5, + 0x4f095ba7, 0x03f64589, 0xfc0c09b4, 0x1063eff9, 0x2b2137e5, 0xe69c3034, 0x28669ba9, 0x90b04554, 0xabc4e7d0, + 0x9222d7dc, 0x7ac43072, 0xde22055b, 0x5a55f24e, 0xfdd1f2fd, 0x10ad3404, 0x0e1514da, 0x4e977440, 0xa016143c, + 0xc9420493, 0x4ce08c6b, 0xefa37fa3, 0xf7f29c28, 0x081521e6, 0xcde658d4, 0xd230bece, 0xdd56f654, 0xef81f4f5, + 0xa104f0e5, 0x1a2ba176, 0x0fde477d, 0x20358399, 0x731e88ba, 0xf064bdd9, 0xba574771, 0x3d3bbd69, 0xda8e9940, + 0xc2ba0368, 0xb41b61bf, 0xb7191c15, 0x85ecc79a, 0xf643d4e0, 0x91f4b713, 0x8c19abe9, 0x5da22f47, 0x932eb667, + 0x0b1f94c4, 0x3195fc5a, 0xdf27b9b9, 0x1c0e6043, 0x88da533b, 0xdf9382d5, 0xdecac810, 0x671e4278, 0x1ae21dfd, + 0x2c80132f, 0x7c690648, 0x3172d9ca, 0xc5b1e5b3, 0x75f991d4, 0x2f27e428, 0xb72b2052, 0x98edb58e, 0xea758710, + 0xd884e9d4, 0x16b7977d, 0x252f4398, 0xbb885898, 0x97d319ac, 0x82d569ab, 0xf5c1d018, 0x8e63e3d3, 0x41791231, + 0x8ee435b2, 0x347e00a5, 0xc0055e68, 0x4b4c5a86, 0x0a982fe0, 0x079d7d4a, 0xf270fddc, 0x808f78ac, 0xf2b1096d, + 0x5e558ba7, 0x18592a3a, 0xfa26a9b7, 0xf42452ef, 0x42d571b5, 0xb8efc84d, 0xf26f022e, 0xd18c2f99, 0x03a3122b, + 0xe3c4945b, 0x564d3598, 0x2e4b03e9, 0x9d4c7d93, 0xc2dbee9e, 0x17af66f7, 0x796d230e, 0xe348fccc, 0x5ed4bfac, + 0x25e95f5a, 0xb7b63133, 0x78c00e9b, 0x73170b96, 0x9798234c, 0x5a7f7ea4, 0x61715dec, 0xcf821c1a, 0x13c3fd82, + 0x7f9488e5, 0x62ceae31, 0x1e0ab3b4, 0xe070d995, 0xa45441fc, 0xab5ed447, 0x5cd0c75a, 0x4d7bd464, 0xc33b4572, + 0x8b97a16b, 0x962cfc21, 0x692a253b, 0x96bdc544, 0x238d1400, 0x5014411e, 0xd7322a3a, 0x302ff844, 0x549e5490, + 0xc9e2373e, 0xb6616f71, 0x6899a4f5, 0x2bb68dae, 0x73977ff1, 0x32b40d58, 0x0cfe7152, 0xf74d5899, 0x428bb9f6, + 0xcd3d2117, 0xcde16420, 0x4ea19de3, 0x659d43ee, 0x0399be21, 0xae1ea5e3, 0x5947bd9c, 0xb26a8eb8, 0xc7b13afe, + 0x305970dd, 0xed9f872b, 0x0f97885d, 0x1394f017, 0x6e3f9f99, 0xc4f424a1, 0x1535ffb1, 0x36aaabf1, 0xcda535fb, + 0x8335238b, 0x7c732006, 0xd8316504, 0x21d64cfc, 0xb940c167, 0x2a58bd14, 0x377ca502, 0xc3c5e554, 0xf6a73fd7, + 0x283d0838, 0xffa6219a, 0xb2d9f59a, 0xc29d4b50, 0x3424a7f6, 0xba5b09aa, 0x87531f26, 0xc2605a55, 0xe83fdd21, + 0xfd78776b, 0xa2c65637, 0x9f539c97, 0x13c2474c, 0xbc973c5e, 0x656b66ef, 0xa38d96ea, 0x2dab180d, 0x4ee854de, + 0x456cd55e, 0x165ce943, 0xbb7a33f2, 0xf1dbf81f, 0x5f6820fb, 0x79287c5f, 0x6d25321d, 0x3a2dd7bb, 0xf6500c4a, + 0x55e5dd52, 0xce7e68d9, 0xfca2f5b4, 0x1466be83, 0xed7bbefa, 0x0e7b7937, 0xc4241ba2, 0x7555491c, 0x58bef80c, + 0x84f2508d, 0x798aa71b, 0x5b6c4743, 0x75a7f44a, 0x75cf06a5, 0x223f2d17, 0x8af1dfe1, 0x2a430862, 0xda091738, + 0x453cdb29, 0x2d6ba564, 0x6e2de157, 0xe3ccc385, 0x7d082cfa, 0x2e40c2f2, 0x1c498fac, 0x8b6a80dc, 0x09e5643b, + 0xc67391d1, 0x0dad4720, 0x21e83055, 0x907e7a4e, 0x2e2df31c, 0xb9cab257, 0x9694ff74, 0xf5f81471, 0x12771986, + 0x02cbafba, 0xb5734b09, 0x31ba437b, 0xe09e6f20, 0x7903d0aa, 0x80a6f154, 0x67df596e, 0x13268a0e, 0x994e2bd9, + 0x32815263, 0xa7c21701, 0x85a99e74, 0xd9b90191, 0x3c86fecf, 0x2e05851f, 0x8211fe59, 0xf0cd04a8, 0x5cdfaeda, + 0x76bf962e, 0xf14e153e, 0xb8627a5f, 0xc88f9601, 0x343051a2, 0x4e46ce64, 0x135518fc, 0xffaf2d22, 0x06110e5b, + 0xf249a0a6, 0x4932ce53, 0x7dc55e73, 0x2b6b8857, 0x8d59f602, 0x6ccd7e59, 0x8b837747, 0x69ef17bc, 0x59ac4644, + 0x22b53145, 0xa7affacf, 0x03ed45a9, 0xf2e141f2, 0xd0e4ba35, 0xa74f39a4, 0x98577eac, 0xef40533c, 0x1382f6e9, + 0x2e8937ee, 0x39974025, 0x6083047a, 0x24a611bd, 0x7b53d1cd, 0x411b3300, 0x836b165f, 0xa077ad68, 0xe038717f, + 0x0c70952a, 0x9980fb08, 0x2d44766e, 0x37ee5142, 0x4d1cb891, 0x288ba648, 0xb5269d52, 0x8650f767, 0x08b8b294, + 0x47bace6e, 0xb0e926bf, 0xac7e40fd, 0x6e1f3f60, 0x27c3b3ba, 0x471c54d7, 0x3f7076ee, 0xe030b483, 0xccccfd70, + 0x1d10ce25, 0x90d62e5c, 0x056cf3c4, 0xbc50e2a4, 0x767d297e, 0xd2b365a8, 0xfd7d4ef2, 0xa08077eb, 0xe110a327, + 0x2c42f025, 0x00ec4d4e, 0x6c307507, 0x1718f6da, 0xfbe73073, 0x45c00b09, 0x337460d1, 0x449e6df7, 0xc2e5b01e, + 0xc1e68e2c, 0xda15eb16, 0x8aae43cc, 0xceb61621, 0x844e864f, 0x37f99b93, 0x66923519, 0x33722873, 0x09281b26, + 0x6b79ad7a, 0xad1973af, 0x574b8291, 0xea18cef6, 0xa3e657af, 0x74a10bcb, 0xb9a919c9, 0x6582c188, 0xa5cd4278, + 0xd9a06e80, 0xa5cfb18b, 0x32693ff1, 0xb3113daa, 0x0ea23af2, 0x49f9b31d, 0x88aee4fa, 0x429a61ca, 0x8894c527, + 0x89b14483, 0x44c6887e, 0x2607a2db, 0x581daf4d, 0xec889a29, 0x66d93d5f, 0x6d7b501f, 0x032fb6dd, 0x218ed9bc, + 0x6556e7ed, 0xdd9f5d89, 0x0f34b75b, 0x508a1cf7, 0xcdaeb8e6, 0xeaff0987, 0x9eaaa697, 0xddac0d73, 0x10ea37c2, + 0x8fe51869, 0xd3705b40, 0x9c1f13df, 0x39e4aaae, 0x3a235ec7, 0x5bbd4ffd, 0x2ea10b06, 0x111f0855, 0x822b2931, + 0xb36d7574, 0x69b2b562, 0x6064ae21, 0x180ae0e7, 0xa5ae6f96, 0xc39bf286, 0x6d1ba1b9, 0x232ecddf, 0xf73ded59, + 0x15be595b, 0xf1342df4, 0x7a55a917, 0x11fbc8e3, 0x575f38b5, 0xa7decd2e, 0x2d786f84, 0x6cc0aa8b, 0x4e8767f6, + 0x83993708, 0x045c5126, 0x82ccc3a3, 0x138e2bb8, 0x5f148839, 0x47bc9591, 0x043f5986, 0x4a22adcf, 0x61bc8a5e, + 0x33a354e3, 0x9cb95243, 0x5cd6a3cf, 0xb3e07ea3, 0x9f0854d6, 0xb14973fe, 0xb19b4f42, 0x4f64ebec, 0x43432256, + 0xcd19c2e6, 0x87693153, 0xa363f8cd, 0xa68da064, 0x1c3aa46c, 0x6f7c9fa7, 0x8c1fb65c, 0xd904377c, 0x0d066eb0, + 0x9920c882, 0xc0c0e43e, 0xfd29a9c7, 0x651b295d, 0x1e87cf91, 0x22d5a5bc, 0xcb7c3b55, 0xcdee61a5, 0xac9e7316, + 0x8f5840e7, 0x552ab89b, 0x7c990aff, 0x98c02ed6, 0x365de50c, 0xbc70dc7c, 0x98828485, 0xa1aade2d, 0x00b2c6ca, + 0xc3e99dbf, 0x9a09284b, 0x498f2e40, 0x7b97d1e5, 0xefcea2cd, 0x1d4267ae, 0xe147961e, 0x80e0898a, 0xf03673ac, + 0xf408ada8, 0x45e1faa1, 0xd52a7823, 0xb8d436b4, 0xe9b91568, 0x1ef30b4f, 0x2fe256e9, 0xacbe07c1, 0xb17a102f, + 0xf3f23000, 0xd79f1179, 0xad690945, 0x0ce80473, 0x20186412, 0xc607490d, 0xb3887dc9, 0x1b7f1932, 0x15e9cab6, + 0x0c382cb7, 0xfdddbe71, 0xcb436125, 0xde4aa73a, 0xc52eb40c, 0x5b076451, 0xbedb33c1, 0x2f2280ba, 0x2be18706, + 0x88254650, 0x5a87474f, 0xf41f9532, 0x907d6bf0, 0xfaa372b6, 0x79f68c89, 0xfeb75a1b, 0xa11afbb5, 0xc0c6123d, + 0x3969a605, 0xda400af2, 0x22b5a5ce, 0x60c0a30c, 0x1d3fcb03, 0x49ff9b51, 0xcfc577c3, 0xef53dc58, 0xbdcfdefb, + 0xea4b22e0, 0x76c86e2b, 0x760a1303, 0x2bde695c, 0xf2b892ec, 0x0378041b, 0x0d885806, 0x6ddd97cf, 0xaf460fb8, + 0x1909ae85, 0xf6075819, 0xe17540ec, 0xf417bd38, 0x7943a4d5, 0x0eef8b22, 0x1a15384c, 0xe95c76b5, 0xf1d4be40, + 0x19a0482e, 0x0d026773, 0x05b1597c, 0xe73ac318, 0x3df707e4, 0xe0fb6deb, 0x2b0e247d, 0xbff6c7b3, 0xd2a9e266, + 0xe57d6cec, 0x1a0cbc44, 0xbbb4c41f, 0x3dd5a1eb, 0x9a2116ce, 0x1c8422ad, 0x19a2017a, 0x3dc7a653, 0x4d7e1327, + 0x5e7ea435, 0x237dce74, 0x7ffbeeec, 0x9378baf4, 0x368b7833, 0xa1e36889, 0xb3e60832, 0x226c91cb, 0x3fd7c4ff, + 0x483cb6be, 0x5852678b, 0x7f9dbd25, 0xfc4ea737, 0x4c8680c3, 0x80801c41, 0xbcbbb98f, 0xd73eecdc, 0xecd92151, + 0xfc5bf0fa, 0x3c840423, 0x93531f37, 0x4127e6fd, 0xdfdc57ed, 0xe438ae71, 0x8dc5e5ff, 0x4c90fc6c, 0x78e2eea0, + 0xe4217360, 0xd3712339, 0x738fc455, 0xe5f6f44f, 0x297c10c2, 0xf048bf30, 0x86ca7854, 0xafa3f8b2, 0x1f8e776a, + 0xf7af5483, 0x812d50ed, 0x9baff31e, 0x78e08eb3, 0x33fe47c7, 0x8bcd86e6, 0x93fa03f7, 0x525b3e0e, 0xbbe2bc29, + 0x6b8240e1, 0x3d069c09, 0x5859b55c, 0x5a5328fb, 0xd940295a, 0x3d8e0751, 0x85e3de68, 0xfba5fa7a, 0xfbae3a1a, + 0xce27c017, 0xc35fb414, 0xdf96291e, 0x13b25dc7, 0x32867e90, 0x2dcdef9d, 0xd1630d0a, 0x925574f1, 0x57f3002f, + 0x8b6f802e, 0xdd6c955d, 0x073e097f, 0x2e768265, 0x5b6176b8, 0x73962ce5, 0x67f4c6e2, 0x22edd577, 0x92e95d73, + 0x3bbd5827, 0x054e4c0e, 0x7432c477, 0x84553eb3, 0xc88da550, 0x1a776b2e, 0x6ea279a1, 0xf1a16f33, 0xb0bb0513, + 0x6753bfe1, 0x10a0ec52, 0x76512b68, 0x2d5e472f, 0x37f3cfea, 0xb3002feb, 0xb4a5501e, 0x8b67b86f, 0x9a31149a, + 0x5a667e2a, 0x18b2187a, 0x9351a282, 0xc8c14d23, 0x9572b9c5, 0x46b5b3f3, 0xaed69988, 0x5b8e9574, 0x0fcb9c18, + 0x81e957e7, 0x10e439c4, 0x932a97ed, 0xbf8b4cf7, 0x8eb47750, 0x96256e87, 0x5693c274, 0xd1b2e285, 0x4af89293, + 0x08db83a1, 0x1a88e764, 0x54af832d, 0x158dfca9, 0x6362f717, 0x219e2ca0, 0xa25b6bc8, 0x0c7830a4, 0xa55e617f, + 0x3cd2810a, 0x16a0500a, 0x0aaeafd9, 0x46ad31ef, 0x2d48b0ee, 0xf818fcdb, 0x636ba4f6, 0x7ad54978, 0x52682807, + 0x09db4003, 0xfb22aa48, 0x9d1c6e14, 0x360e7b97, 0x532bdc83, 0x6e93df69, 0x66eedd79, 0x89cfeb83, 0x0a7280e5, + 0x48b3852d, 0x752bc5cc, 0xfb54fd23, 0x805b0c47, 0xee4076d9, 0x5b12302f, 0x549ed3c9, 0x3ff25103, 0x18111181, + 0xf791b944, 0xce46b70d, 0xfec94a1e, 0x9435afce, 0xe2d5ed3b, 0xf5443397, 0x4ddd3e34, 0x8fad5bfa, 0x439a5205, + 0x755f3c6b, 0xabd5e7a7, 0x206cbd9d, 0x80beebc4, 0x473b22aa, 0x8666fced, 0xab3d3f88, 0x38725c30, 0x44fb3c17, + 0xedb6b002, 0xb60c474f, 0xdd484be1, 0xe0b8ca3c, 0x851b5afa, 0xf68cd01c, 0x2ad79a68, 0xcefad5d0, 0xfadc06ed, + 0xc9c0402e, 0x101bd90f, 0xaeb1e9f2, 0x2ec56995, 0x62f211be, 0x05603b00, 0x66c641e1, 0xc2f19892, 0x94cbc1ed, + 0xc49992d0, 0xbbc93441, 0xe1e2bc1e, 0x810b3961, 0x5d4b270e, 0x0127e5d6, 0x1fb4f279, 0x9b3eb45c, 0xd6de42cf, + 0xd6a08bb8, 0xcda26e9b, 0x322f6bb6, 0xf46bca5e, 0x60b2cb50, 0x0aba5112, 0xa2453463, 0xfe6bfdcf, 0x6402194b, + 0xba1f7e32, 0x68d522cd, 0x3684d713, 0x04ffedc3, 0xf614291e, 0xc61bf681, 0x844396db, 0x529a6935, 0xb6236542, + 0x5ec418a6, 0x6a6ba31c, 0xc5cca127, 0xd7d15e10, 0xfac78296, 0xd2bab5d3, 0x7c2b37c5, 0xf33bb672, 0x6e52a599, + 0xd609b613, 0xa0fc1cda, 0x57df991a, 0x34795008, 0x81a19c09, 0x71ce71d2, 0x821de295, 0x350adf7a, 0x00e8c63b, + 0x2e9de168, 0x57200c40, 0xd5ea6799, 0x13104f9d, 0x55b075f3, 0x51befb2b, 0x322705d8, 0xb663aa6a, 0x67d9176b, + 0x89fc489f, 0x149784be, 0x97552632, 0xb87ebfe5, 0xd8c151fc, 0xadc5bc97, 0x8d85e2ca, 0x26edf3b0, 0xe791f64d, + 0xa3a36d75, 0xef010c06, 0xa76e86bc, 0x1cd4f655, 0x450d2a92, 0x6c3a419b, 0x5858ab03, 0x956424af, 0x3454bef0, + 0x495284e6, 0x80a0f1d8, 0x0f26336f, 0x1350acd9, 0x140521f3, 0x1e3d97ff, 0x9119973f, 0x9e3fa510, 0xec527f38, + 0x3496bba3, 0xbf7c5dd4, 0xeb82e14e, 0x155cb59c, 0xde405548, 0x22bbffab, 0x112a6515, 0x8d2758c3, 0x2f3063f9, + 0xa41a350d, 0x44d7bd94, 0x92dfdde9, 0x7316f7f7, 0x975886b5, 0x649f3f51, 0xff6b2dd0, 0x754dc9fb, 0x724d6fc2, + 0xc1fab524, 0x97ce55e8, 0x9c36441a, 0x7ee6047a, 0x18af4cc4, 0xcfedffae, 0xb6997e2c, 0x24a74307, 0xa10181ec, + 0x724e1408, 0xf0d15a0c, 0x17ae2ba7, 0x8e52f32b, 0x38da8854, 0x43d55cb9, 0xc7bb78d8, 0xd7c37505, 0x42456f8d, + 0xb869811f, 0xfbf021c6, 0x4eee7183, 0x6fd3b703, 0x7fdc9072, 0x1e2c8fe4, 0xde6c1550, 0xdba58456, 0x7aca849f, + 0xe6a10707, 0x3cdd2746, 0x3c7f7712, 0x1fb08e4a, 0x65ad2c74, 0xea19b628, 0xaaf6bd48, 0x0c8dc878, 0x993eb8e2, + 0xe24a2e6b, 0x57f7e193, 0x60f9ffef, 0x2cb05c71, 0x56ff178e, 0xc8263327, 0x965b2ceb, 0x17655d57, 0xb993bccd, + 0x24afb1e7, 0x7a54afab, 0x1f37c7b2, 0x2e69ff83, 0xd6f83ae9, 0xd24e4218, 0x84fc4322, 0xc70ee7a5, 0x7a36de25, + 0x30155094, 0x2d85e42e, 0x67749609, 0xf1aa31b3, 0x1bdf5144, 0x9548c0a3, 0x5049b17d, 0xd84f6b01, 0x4030abb0, + 0x45e505ac, 0x49c5c18b, 0x357ea4ff, 0x01055cc9, 0xa6c9890a, 0x5d6c170f, 0x1cf0443a, 0x10a5fbff, 0x6e4457aa, + 0x5e8504e3, 0x95b444e4, 0xf9216a0e, 0xf30867a6, 0xd44db573, 0xa086ecf6, 0xf4481a4b, 0x63702417, 0x35538821, + 0x2e68dcba, 0xc81916e1, 0x8a50f1d9, 0xd00bd14f, 0x2f897649, 0xf104a7dc, 0x13bb6a50, 0xbc772d67, 0xeda32de5, + 0x0939d121, 0xfdd044d4, 0xe91aa3a5, 0x9ae5071d, 0xe046df66, 0xf7bde72d, 0xea470834, 0xe224a2d7, 0x246c2c2e, + 0xaff30cb5, 0xb0dd6b7b, 0x03a22e33, 0x6a3102f8, 0x9da5ecc0, 0xbec292d8, 0xcb34b49a, 0x215b0616, 0x5de999f6, + 0x4dc16677, 0xb234116d, 0xe0a9ee70, 0xe3756185, 0xda8c086f, 0xa580bc9a, 0x10747ea4, 0x054701bc, 0xd41867f8, + 0xbf32e4fa, 0x70d65456, 0x6cb4cb8b, 0x7c7eb2da, 0x99f03d9c, 0xfb9664fe, 0x34679706, 0xfea11f15, 0x777a4900, + 0xf33957f1, 0x0deb41c4, 0xce876cbf, 0x1dcbb20f, 0x14421650, 0xd6e3961c, 0x0e377b73, 0x644094cd, 0x8f980538, + 0xd1acaf14, 0xd447fae8, 0x9d8c06b5, 0x5de4949a, 0x9b72d9d2, 0x57485c6d, 0x02eef910, 0x08517c24, 0x2f58207b, + 0x84d2ce80, 0x686eab1b, 0x8fd2536c, 0x5af6e310, 0x39105ed8, 0xf059e45d, 0xcf48b112, 0x15310a71, 0x9afd9802, + 0x6ff5f471, 0xd03e87b8, 0xe4ed7ac4, 0x25b53ea9, 0x837334d1, 0x7086a585, 0x49d73078, 0xec13b765, 0xbbca0c61, + 0x8a87febc, 0xbfc34875, 0x62f560bf, 0x4c177260, 0xbef15842, 0xead53270, 0x847cb399, 0xca604df1, 0xf48a685f, + 0xc819f830, 0x40fe555e, 0xdcd0e328, 0x879dac4c, 0xfce263b4, 0x8740b75c, 0x3fd82d7e, 0x65ce8bf2, 0xb6a5c940, + 0x189eb42a, 0xfa0c5fe7, 0xcbe6ee2c, 0x37dd5931, 0x9b9ca44c, 0x10e89718, 0x41923250, 0xad961398, 0x4587d8cb, + 0x203beda9, 0x083c6557, 0x808ab1e2, 0x2b8b56de, 0xa79a8c37, 0xe02718b1, 0xfe117cb3, 0x969e0a36, 0xd844a548, + 0x82ea1a0b, 0xe4021599, 0x837e9399, 0x7d45ef37, 0xba8f2261, 0x49a81304, 0x24248892, 0x1bcf4169, 0x4d09ccb5, + 0x8e2ad90d, 0x8380c9c0, 0xea5fc808, 0x953b64d0, 0x094c1252, 0xcd98d8d8, 0x1a4c2061, 0xe8ba9276, 0xd77e4080, + 0x071f4388, 0x485823d1, 0xffe613a1, 0x53df2838, 0x7e3151a9, 0xbf7ce4b1, 0x96b5bcdf, 0x4c39dea7, 0x0aa5f513, + 0x6aedd2d6, 0xb1527aee, 0x8608c948, 0xda0a1375, 0x6cc7d653, 0x96813234, 0xab2bd375, 0x973ceed1, 0xee6744e6, + 0x3d376573, 0x792d47ce, 0x534ee882, 0x6933f619, 0x49487bb1, 0x253dee1b, 0xc672fa95, 0xace76397, 0xfbdf947d, + 0x141c3ca7, 0xdb1e8f72, 0xb9168796, 0xa38a4fa1, 0xd42e2aa4, 0x026b6ca7, 0x5ccaec78, 0xb1df956f, 0x3a59d8c6, + 0x0ffd9b66, 0xff663d34, 0x64010c05, 0xb57d06bd, 0x580d555f, 0x2bd0ee53, 0x47505a25, 0xf29839a6, 0x9b86ec98, + 0xe3f810e9, 0x433d2a8b, 0x213bba5e, 0xc0edda61, 0x50a3ff4a, 0x67156441, 0x1c9c1f74, 0x3fd7c494, 0xd889e84d, + 0x6c1cc0ef, 0xbff9f412, 0x81f96ed2, 0x60c861c9, 0x1c1706e2, 0xbe096122, 0x2dccae3b, 0xbfa9396c, 0xfb48c44f, + 0xae502fc2, 0x1c0b38b4, 0x932c3a4a, 0x27034ec7, 0xd605494d, 0xbfbff6ad, 0x12bd09a6, 0x87a660db, 0xa0e98ab1, + 0xe080a1d5, 0x651aae63, 0x735ec345, 0x14e929e4, 0x6c128632, 0xf734dbf9, 0xcdb1f830, 0x88c4b280, 0xfa52c805, + 0xca5b940a, 0x555942f5, 0xf94cf447, 0x079907bc, 0xc50d2164, 0xb04e0974, 0xa44a7986, 0x08cd0e82, 0xbe46f4dd, + 0x4b97dc20, 0x700156a0, 0x0ed7c848, 0xbce4bca8, 0x03836012, 0x55501a42, 0x04ceb5ba, 0x58ce97ba, 0xb6fff0fb, + 0x5e3437b8, 0xa7a03ab8, 0x657be151, 0x5bc9625b, 0x39c70b67, 0xed7f3388, 0xb7838ae3, 0xb919af40, 0x8d30859d, + 0xef1eaf68, 0xa3b96d4b, 0x6948b8b3, 0x431a02d4, 0x69caad5e, 0xf9feac6b, 0x8855ef6c, 0xad1b6cd0, 0xd7964ff3, + 0x9938ee6f, 0x616c6cad, 0x3de61b2d, 0x557c1b58, 0x3791c9aa, 0x67ccb544, 0x5538638c, 0x1715ef5f, 0x1c05109a, + 0x077c4e4c, 0xa335673c, 0x296fdcf2, 0xc7b7185c, 0xdff63e49, 0xa2f06a7b, 0xb431238a, 0xc4426a52, 0x8b790f27, + 0xd93e17df, 0xbe7edf11, 0x015b949f, 0x5baa2303, 0x3b85f376, 0xf617f759, 0x10da8e9b, 0x375a1700, 0x27b13085, + 0x19517044, 0x768538fe, 0x9cdce234, 0xbd56e1a5, 0x78f12f70, 0x89b90877, 0x6931a6b6, 0xc4269463, 0xcc17b425, + 0x9f5ab072, 0xc042bba6, 0xd16dfc9f, 0x2e044b86, 0x53d63357, 0x13a6287e, 0x36a3684f, 0xf7984bf4, 0xf3dd4f12, + 0x02dc0cfc, 0x0b842a39, 0x125cfb19, 0x55843a20, 0x4e413674, 0xf69ec8c9, 0x9183a158, 0x1e78389b, 0xa0787229, + 0x515d8f76, 0x9a1cb156, 0xc7e3d64f, 0x8bf7b391, 0xe895c945, 0x6438e13a, 0xdc9b8f2d, 0x3712d6d7, 0x639af20f, + 0xc8030877, 0x3065a4f7, 0xaaa66eab, 0x9d141e3b, 0xdcc498de, 0xccc9a90c, 0xb7ae2bc7, 0xfe400699, 0xe3b78787, + 0x84aafaaa, 0x15340be2, 0x24647b76, 0x9998552c, 0x7acdf94f, 0xc2191847, 0x792f98ff, 0x4a0b47dd, 0x0ff3777e, + 0xa99d4d68, 0x0a093ff5, 0x9caba6b3, 0xa8f9e7df, 0x16d9b4fd, 0x526ffbb0, 0xc7105ce6, 0xbaddb2d5, 0xc87d0ca4, + 0x80811f5f, 0x0ac76a72, 0x402aa4cc, 0x751dc8ef, 0xdcc0843d, 0x78e8e291, 0x3b3bdb7f, 0xd222de33, 0x430fd954, + 0x15620106, 0x14feade8, 0xf81085f6, 0xa7c4671d, 0x2156a250, 0xe8f9c0a9, 0xdfb064dd, 0x4bd0e360, 0x26c3929e, + 0x15fe7482, 0x98763715, 0x650de19c, 0xf7a0ecea, 0xc008d9e6, 0x74c7061b, 0x8759e0fb, 0x44991233, 0x044adaf7, + 0x9c96a2fc, 0x761f28a8, 0xb5672e7f, 0x34819ef9, 0x88ed4349, 0xf1d816e7, 0x8c904bfa, 0x0572c7f5, 0xb3a7ac51, + 0x86d3c3cf, 0x72332e1a, 0x1af66c54, 0x3ee35548, 0x78def02c, 0x498b598a, 0xeffb9f6c, 0x94401864, 0x3fb43766, + 0xe6b9a772, 0xd02bde61, 0x4c48e762, 0x8193fd3a, 0x9dccfb4b, 0x06d40183, 0xdc8e8d2c, 0x28910a95, 0xda70c399, + 0x3f641732, 0x2fd7b495, 0x50b39d40, 0x0f69b442, 0xaf47c8ad, 0xd6e9e0d8, 0xcb9000e7, 0x846ffdb0, 0x6ac46788, + 0x2c744d7d, 0x3ce7bba9, 0xe1729bb4, 0x257e8ed2, 0x4040ca02, 0x0fb5b32f, 0xf5d0f715, 0x2d49c6f6, 0xf5b35cd0, + 0x8d572b41, 0xd64c768d, 0xe963449e, 0xe022fc5b, 0x59811ee8, 0xbc399ca5, 0x8b7d33c4, 0x7f1c2d0c, 0xaa8b3f86, + 0x3b513d73, 0xdc060806, 0x645e7f48, 0x369d63a3, 0xe949be93, 0x697bd8c2, 0x3f2bc433, 0xdb1d0620, 0xb0035ab0, + 0x17fd6ce5, 0xd7bd4c78, 0xebfaa753, 0x403f505e, 0x7ac5cbb9, 0xe19640fe, 0xbe9e52c7, 0xe93ae812, 0x82d76712, + 0xb5bdca13, 0x1453df03, 0xf4ad16e2, 0xba62595f, 0x00c35033, 0x2598b521, 0x18c709f0, 0x86eb7205, 0xd42fc4a0, + 0x6023a885, 0x5285d900, 0x6567b566, 0x5eb4fe3b, 0x6c44f590, 0xd0c63cb5, 0xa9b7452c, 0x48beafa6, 0x93a613ec, + 0xcb18464c, 0x003bd4a8, 0x60c84e95, 0xbef8a427, 0x9acc89a3, 0x66a0049c, 0xf3df1219, 0xd96eb9a4, 0xfb29de46, + 0x7ebc9cf0, 0xafc2f218, 0x01829454, 0xbc9bff9c, 0x719e3bd0, 0x549b8333, 0x09c96da7, 0x2324ff0d, 0x29dd2fe4, + 0x2776430b, 0xbae22c49, 0x84feb57c, 0xba6fae2d, 0x9f23da74, 0xe07a3f8b, 0x99d94b9a, 0xd898f8d1, 0x7d961b07, + 0x4f7252a4, 0x1963f985, 0x156d2ab4, 0xf521f717, 0x87e20e4b, 0xb09d9c00, 0x2e96484d, 0x413ab9f6, 0x4d515e40, + 0x41a75e9f, 0x0c80ac83, 0xcf4eed2d, 0x5f3c55a5, 0x6d139b61, 0x2b917f58, 0xcabd2f2b, 0x4865d312, 0x8cc2aa06, + 0x26afe406, 0x4527812d, 0x94cf37d0, 0x105d1a26, 0xef258ed2, 0x42efcc17, 0x175c290f, 0x4a327be7, 0x12336a02, + 0xf5d67baa, 0x208c0638, 0xe744b5f3, 0x524589c9, 0xb9ee8cae, 0x7b3bd947, 0x6edf741a, 0xd593b26b, 0xb0f7c1d9, + 0xb1c97cf6, 0x4e348b62, 0x629587ad, 0x280b9f36, 0xd93fbac5, 0x2ee3d814, 0x4e413bbf, 0xa663a27c, 0x1579bbd7, + 0xbc11b6bd, 0x68c862b1, 0xa221e73e, 0x0183151c, 0xa20808f3, 0x43a40664, 0xbe1d94d0, 0x62cf4401, 0xb399f394, + 0x96e3a3e2, 0xe19f9f95, 0x6204a603, 0x3286fa9c, 0xd8e7a7ac, 0x02e1b5a0, 0xae6b20ac, 0x5a18339c, 0xcd236327, + 0x708467a2, 0x6ac1b335, 0x91632d9a, 0xb97b1d10, 0x85a2725f, 0x10c55f79, 0x8617479c, 0x6c431d9f, 0x1d93d2c4, + 0xc9ed0cb1, 0x57b09842, 0x415d8d6d, 0xa03fbf93, 0xcb00ea82, 0x359768ae, 0x625be179, 0xac836a2b, 0xc90fd051, + 0x18c50b47, 0x02aa9ff6, 0x16a66c2f, 0x62830f31, 0x01a1aa3a, 0xb594cef5, 0xf274d057, 0xe28226d7, 0x42724b28, + 0x3da87dd5, 0x0908fbc3, 0x71506cab, 0xf39afd90, 0x9236ee9f, 0x579aebd7, 0xb72ee1cf, 0x217b0572, 0xfcf7376a, + 0x89a13ee5, 0x2156c1c9, 0xdd5465a6, 0xa357c829, 0x48398012, 0x29bf36e5, 0xf324f534, 0xb368e225, 0xe1e59f64, + 0x84788aa3, 0xde16b064, 0xdf27baa0, 0x77de866b, 0x08693d77, 0xe6519736, 0x9884f270, 0xfe7429bf, 0x8edb0873, + 0xecc1215a, 0x5aa37072, 0x0d8eae0c, 0xa0ea1619, 0xc6bfb35d, 0x5224fe51, 0x41143824, 0x9cf5cf32, 0xede4cac6, + 0xbbc248a1, 0x1b7e4ea7, 0xfc3d3960, 0x4005c45a, 0xfc283c6e, 0x2eeec151, 0xc679e680, 0x33905853, 0xc32c91d9, + 0x3ee9ca7b, 0xd358d21a, 0x9d17c4f9, 0x5261b12a, 0xd6b9414d, 0xdc9a8e77, 0x3aef7a4d, 0x83e4db0b, 0xded521b1, + 0x53005900, 0xfc345984, 0xbb473b35, 0xbfd485dc, 0xd60e4df6, 0x2f494777, 0x0a33867f, 0x61eea88a, 0xc1e46c57, + 0x19520ab8, 0x4e1130b2, 0xd1a06ee7, 0x983f8fc8, 0x19dc2a08, 0x7ffc89e5, 0x3f419105, 0x1781b443, 0x8be03c93, + 0x38716854, 0xd1d04e06, 0xb1af28de, 0xb5395ea5, 0x3b720331, 0xdf08480b, 0xc3f5c0ac, 0xbfe1cb70, 0x7a71993d, + 0x6b667f1d, 0x40f03574, 0x465eec33, 0x2d778b93, 0x1a45d971, 0x58907548, 0x3766c7c8, 0x293c710f, 0x9a95ec67, + 0xd038c8d6, 0xc4d3cffe, 0x98ff8151, 0xa07aa673, 0xf37b547e, 0x4a12f1c4, 0x750695aa, 0x0540248e, 0x8cb0aa94, + 0x6fbc24b5, 0xa0a31786, 0xec1a02e3, 0xb6c8e0bb, 0xfc792379, 0x7bf32d60, 0xbead6130, 0x773388d0, 0x0309c9e9, + 0x8d032339, 0x04ea00b4, 0x77afa168, 0x6362e3c0, 0xefb3d6d3, 0xdb062f5b, 0x407c265b, 0x462c199e, 0x236edd95, + 0x2690729b, 0xc31bc58a, 0x16dbeccc, 0x9363206e, 0xb06f17b5, 0x7cf1c77c, 0x68cd2edd, 0xe0eaae18, 0x24de5a03, + 0xaf020628, 0x55b4d312, 0x72fc54e2, 0x6306e61c, 0xdf78bab2, 0x65eb27d5, 0xaffe81fc, 0x2f6f8d1b, 0x644b71ca, + 0xe2ba019b, 0xa4053916, 0xe89ffde1, 0x64bccb96, 0xe086dd8a, 0xc07c4bcf, 0xfca17764, 0xa1ab3ebd, 0xd83dec02, + 0x3074b661, 0x1acd906c, 0xc68ce70f, 0x0b842ecc, 0xe00c87f7, 0x6237fb48, 0x4e07d955, 0x02198916, 0x10de9b52, + 0x439e7db6, 0x2bcfec4b, 0x72d50fee, 0x3fb666c6, 0x63e32139, 0xee9b1cc5, 0x7b3684b7, 0x4f8673e4, 0x9d8de5f6, + 0x856a8ad4, 0x6d0083b4, 0x96df1d8c, 0x7488f147, 0xcc25cedf, 0xeb464384, 0x12cbb9d1, 0x85b416f9, 0x799d8c7d, + 0xea12ea68, 0x2ee0d084, 0x538a6b88, 0xda69b8ea, 0xbbcd9d5c, 0xffc80c91, 0x1694ec0d, 0x5157e1b7, 0x2b23d035, + 0x5518da9f, 0x70df0f50, 0xcc4b585c, 0x4724c3b2, 0xfdb5ba49, 0xaf09b549, 0xd1764a9e, 0xff63f8e0, 0x3a197292, + 0xa7072fee, 0x28d2ecba, 0xba2ad3c7, 0x828c515f, 0xb805692f, 0x9e6218f5, 0x04f4fba4, 0xb35187a2, 0xff36d759, + 0x7e36c194, 0x6b820bd6, 0xaabfea40, 0x77f4f258, 0x10eb801a, 0x330f2dd8, 0x96a113e1, 0x4ccdfc4f, 0x55f14139, + 0x78900d96, 0x36f034d8, 0xd8ac8b6c, 0xe745343d, 0xc9b76d55, 0x8efd95b7, 0xcf9542e6, 0x254a1dff, 0x30bdb5ea, + 0x06fa79ef, 0xd4108cda, 0x8a47df96, 0x39f7fc70, 0x52028b21, 0xdc682d9c, 0x28c32f88, 0x059f75bf, 0xce7b7c26, + 0x65d8c264, 0x5efecc0d, 0x7c0b5acb, 0xc22bd65c, 0xf50839f8, 0xb71bf2b9, 0x45adb649, 0x78e7d00e, 0x6af4fca6, + 0xfc4899ef, 0xfc9e4726, 0x3b7074cf, 0xfcf12895, 0x28b420cd, 0x9374ce05, 0x1b22f9f0, 0x411e3836, 0xc7663a9e, + 0x00a45b22, 0x0e8dc429, 0x52d5ba0e, 0xafa5c001, 0xd4886eaa, 0x79a8aea5, 0x71b71895, 0x6e12b2cb, 0xe35e8d5b, + 0x8830af30, 0xc7e8625d, 0x8d98a4b5, 0xca6e99c1, 0x5f94686e, 0xa6a37650, 0x65ab7806, 0x52030f82, 0xafe1e7d7, + 0x7d2f220f, 0xd02cccc6, 0x7913633d, 0xf3406a5a, 0x40fe2548, 0x69ce323a, 0x15a3edfc, 0x10725161, 0xa076462d, + 0x01186085, 0x3a74fa89, 0x42e4425f, 0x97aecc07, 0x343198bc, 0xb01b6804, 0xaa43beb5, 0xca84702e, 0x6cb694dd, + 0x3251ef36, 0x68931f43, 0x164f0d05, 0x00f7b39d, 0x62400e86, 0x36cff1e1, 0xe9c63b1a, 0xb8dbce8c, 0x76be87ce, + 0xe6f12404, 0xfddae36a, 0x8da676ca, 0xe263f65d, 0x1c1edb59, 0xd9985f42, 0xc800c1e1, 0x05d36cda, 0x71581f76, + 0xbc87bc67, 0x5093fd0d, 0xa704ab26, 0xe84e051b, 0x36cb8a4c, 0xb8e18b1a, 0xa40816cd, 0x79710c81, 0x9575e83f, + 0x8a14da22, 0x6c45bd3e, 0x08fdc95a, 0xf83d57db, 0xa7529e0a, 0xe4d9c768, 0xab84ac31, 0xfe8b727e, 0x409cee51, + 0xc528c67b, 0x56b396d0, 0x8b70f518, 0x8288ec0f, 0xfe7b7603, 0xa572a5c5, 0x215e7b78, 0x98e282d1, 0xd3799ded, + 0x67d6a89a, 0x54313406, 0xf88478b0, 0xc986ec02, 0x118430bd, 0x4f2078b8, 0x11a69cd8, 0x8144faf0, 0x25f827ea, + 0x63b16a39, 0xf4b759f1, 0x1c560136, 0x58bf5087, 0x2c239870, 0x5722f768, 0x59e60b5a, 0x26d38039, 0x61af8906, + 0xca6660f7, 0xcc0f5a85, 0x9f8828a2, 0xbccc654b, 0x49f23975, 0x8328a14c, 0x322c578e, 0xbdb94872, 0x4b338ca4, + 0xff413968, 0x736308cd, 0xc9e92589, 0x43dd731b, 0x1892965e, 0xbd2a9c4c, 0xb5c74bb3, 0xdc2c3ba9, 0x2dcc0149, + 0x8f3dbf06, 0x8b8c20fd, 0x5c4f5cd9, 0x86708a32, 0x7a980186, 0xe67e4dad, 0x6ee9575d, 0x95bc3fbc, 0xc0976124, + 0xef3c30d9, 0x2fe1bdf1, 0xabf2bd1e, 0x76872d71, 0x9ec99bc7, 0x2ccdbdf2, 0x9103161f, 0x6fb36067, 0x9df71012, + 0xf85568a4, 0xe92c4e77, 0x656d1da9, 0x317febee, 0xfe05d989, 0xb8332d95, 0xbd5ea9d6, 0x6a5dc60f, 0x1e385f2a, + 0xb0e03d6f, 0x511edc22, 0xe6997f52, 0x13c6ce5f, 0x4b8ed727, 0xce5e9cd4, 0x35ce7468, 0x9b299a4b, 0x71f7b1df, + 0x445353cd, 0x97b0e649, 0xdd579024, 0xb35eafec, 0x5aabeb92, 0x79fc11ec, 0x07f577e8, 0x4c138124, 0xd9bb0e7f, + 0x1d61c61f, 0x8abcc198, 0x6d76d30c, 0x4c085751, 0xb2efb633, 0x9009f4c4, 0xc217acdd, 0x234d8144, 0x90388bb8, + 0x1c374670, 0x2272722d, 0x70ab1ad2, 0x3cffb06c, 0x579a77d7, 0xd7e07bf5, 0xd1cc20f3, 0x98f893a9, 0x8074cf5d, + 0xccfbe951, 0x5fffa63d, 0xe2ab53c9, 0xc0940b25, 0xad4d89ad, 0x4fbf9776, 0x41cee2a5, 0x25562200, 0x85df642a, + 0x760611f6, 0x50e9d5a2, 0xddcaa3d2, 0xb96fa67b, 0xaf3d1292, 0xf9c11070, 0x919a749d, 0x7973d3e4, 0xae7d0761, + 0x16625379, 0x474ffc85, 0x821e3870, 0x2bfdcf98, 0xb80f8790, 0x5db63f2a, 0xb2e5e5fa, 0xe8e214ae, 0x568ed134, + 0xd956b337, 0x76a60a69, 0xd5d3c011, 0xe92b717e, 0x22d49fbf, 0x7aa725c1, 0x189e7dab, 0x9bdcdd04, 0x3f0a9ed1, + 0x3cbb79df, 0x96582920, 0x3b20925b, 0xa7e246d3, 0xe79548d3, 0x61925dff, 0x12b79d8f, 0x9b79fdc4, 0x7bb58d1d, + 0x9b3248af, 0x26304bec, 0xfb681575, 0x403064d8, 0xd21f52fb, 0x709ede93, 0xadc8b8b0, 0x75d7dbd7, 0x24b769ce, + 0x0608797f, 0x31093f7e, 0xe32047fc, 0xa626a85b, 0x489eb40f, 0x73ecf062, 0x82634b59, 0xed700342, 0xa3664f23, + 0x75188f7f, 0x7f0dfb8c, 0xff998288, 0x818d0d05, 0x76f00fca, 0x416c41a5, 0x1aee25c4, 0x8cdfa468, 0xcc84eefc, + 0x37e1752c, 0xcbd9b676, 0x61deb096, 0x35d263bd, 0x6bd33047, 0x5a277217, 0x96662092, 0x450d70f1, 0xbbdeb7e3, + 0xecda6767, 0xecafca95, 0x6619becb, 0x319c46ab, 0x304f54ef, 0x9878c003, 0x1b0d0da7, 0x02e81dd3, 0x5549dca0, + 0x2d45db8f, 0xaa15877b, 0x3555c919, 0x9157f4fd, 0x22ff8d85, 0x9d131c58, 0xd2e0c475, 0xde48a3e8, 0xd2f97305, + 0x1b631356, 0x3ae1193c, 0xa0bc579f, 0xcb7f8571, 0x55f3352c, 0xbc7307c2, 0xd8fa3690, 0xe552bc59, 0x8dfe457b, + 0xd1734d7a, 0x96ce61a1, 0x655860da, 0x6c80e314, 0x3bd34e01, 0xefc751ec, 0x671164ec, 0xc237acb5, 0xcce6b17c, + 0x138158c7, 0x717935b1, 0x0731e439, 0x2c9beca6, 0xd90199fe, 0x2dba4e21, 0x781788a2, 0xe26a1bf4, 0x6e802625, + 0x4a9b5da3, 0x77bfe1e1, 0x71e2db33, 0x803d60e5, 0x67959999, 0x7aea37f2, 0x303678a7, 0x3e424da4, 0x3b788d09, + 0x11562a48, 0xcb624f54, 0xfa0ba1af, 0x00e5966a, 0x3554c577, 0x27188aa2, 0xee60440e, 0xd4cd3974, 0xbea19c93, + 0x631815fe, 0xbd876bcf, 0xe662ae9f, 0x085fbed0, 0x2bbd58b5, 0x2991faec, 0x6703f56a, 0x3a06f591, 0x9d59abc6, + 0xa94eda2f, 0x5da367a8, 0x2e2fe90f, 0x65231754, 0x1738ce4e, 0x09a2d631, 0x3e58305b, 0x2ef06d79, 0xde97b66f, + 0xd3466eac, 0xdcb9a554, 0x24020a0b, 0xaa36a157, 0xddb390ab, 0x6da41464, 0x290ae571, 0x7064c276, 0x2ef4553a, + 0xea2ee421, 0xf41a92b1, 0xb1be11a9, 0xdc819ef1, 0x0894cc1e, 0x69948206, 0x62ef6df5, 0x06c52d39, 0xb6aca0ad, + 0xdb5714d2, 0x3ed0b52c, 0xe56b4724, 0xdf7137f0, 0x25b7bc91, 0x160f7daa, 0x8147be08, 0x253a5f1c, 0xaccc73a8, + 0x08c2c7aa, 0x3a968729, 0x7392991d, 0xa4150be9, 0x60333787, 0xbd3d6bd3, 0xea01b592, 0x8fdeb61d, 0xcfdd9094, + 0xf247b107, 0x0f1a49c7, 0x93a426c9, 0x58d2f80e, 0xcf405630, 0x5053c43a, 0xb91f70c4, 0x4d3be1d8, 0x7e0edcf1, + 0x1a1c236c, 0xd4bc09ad, 0x275335a0, 0x8e6cd35e, 0x5fefda8e, 0x3dc0f93a, 0x490d05a5, 0x336334a7, 0xb546ff92, + 0xfdcd413f, 0x0da99587, 0xe28d1153, 0x77efa71c, 0xaedaa4c7, 0x37cb781d, 0xbc9d79a6, 0x61f515c7, 0x0dbefbb9, + 0x0b37778f, 0xbcd9cb43, 0xfb5f22cb, 0xc1598cd2, 0x085fad6f, 0x34805734, 0xa45de80a, 0xf9fc130d, 0x2418c964, + 0x809d18be, 0xdca0a555, 0xf945e18a, 0xea0989e6, 0x2b7ac819, 0x46d3521b, 0x915efbb5, 0xd8c78e4e, 0x542e41a7, + 0xd356448b, 0xdb16de3a, 0xf3a46b2a, 0x7aed996d, 0x45db9011, 0xae2de3a9, 0x8b2579bd, 0x6c1108ae, 0x7b46b156, + 0x25d5ad4e, 0xecfe888f, 0x983bbbca, 0x9cde0859, 0x4444de52, 0x931edc62, 0xb68f26f4, 0x299b8fd3, 0x11a957ff, + 0x041ff16d, 0x21a73d6d, 0x9a331c19, 0x9074b069, 0xa5abca10, 0x321520ed, 0xff99e5b8, 0xef1d0f97, 0x6e911e70, + 0xf804f4c5, 0x4a79e3ff, 0xd31a6986, 0x74f2df38, 0x33c8c64d, 0x1e357a76, 0x60ee5af4, 0x149f5ad2, 0x695f1bf0, + 0x3962201c, 0xe5930dc2, 0x0fd9f877, 0xfc779e64, 0xc5d782ac, 0xcd09f9c2, 0x7de9607e, 0x76da6c24, 0xae14cabf, + 0x55893be4, 0x562d2344, 0x6eb8bb39, 0xb5da8750, 0x15685b50, 0x05db1411, 0x99f54e3c, 0x9f0790f7, 0x2d79b377, + 0x7b253e0c, 0x8f032ebf, 0x50338df8, 0x0b750326, 0x9721f518, 0xd4de765c, 0x99adc5f1, 0xc78fce50, 0xcb30c981, + 0xb5aecc9f, 0xdc775a51, 0x81a5d959, 0x99c2837b, 0x8fbea31c, 0x165b298f, 0x67dc3547, 0x8b7accd1, 0x29da0c17, + 0xd60767e4, 0x5054380c, 0x6d598ad2, 0x61bdab38, 0x2f248f8f, 0x7a87d473, 0x7aad6f63, 0xf655460b, 0xeaf86861, + 0xe423adf1, 0x17562568, 0x6ecfa7d3, 0xfd080d30, 0x9bd5a2a3, 0xd3b9a3fb, 0x4d4d3b21, 0x561ce30c, 0xe22ff5f6, + 0x40051f8b, 0xe9ee21d3, 0x43ecabc5, 0xad6bd578, 0x1de2100e, 0x509d6d7d, 0xe0e353c8, 0xefc75ebc, 0x64172275, + 0xdc31dbec, 0x04f7ec9a, 0x715ac2ac, 0xccc8b7aa, 0xc70210be, 0x2bd04d32, 0xc3f072f4, 0x0412dec0, 0xdc30c21e, + 0x3f037cdf, 0x46768833, 0xa27707d9, 0x50ddc532, 0x8681a324, 0x00447676, 0x6d5fc9b8, 0x1a59ebe2, 0x877b39a1, + 0x736c2832, 0x8d533ed6, 0x93b5c396, 0x8582d436, 0xdd75528d, 0xf834f98d, 0xa5b8ffa7, 0x6d816289, 0x2c76b871, + 0x4794ffba, 0xf1609c1f, 0x49419a08, 0x14385805, 0x81a27f0c, 0xa274aabe, 0x4336c95f, 0xf1009d92, 0x14cd691a, + 0x76715f7b, 0x219f780c, 0x060ca24c, 0x7f55ef08, 0xd57f6fbd, 0x5d4be898, 0x158f3c64, 0x1f8b08e9, 0x8bdcafae, + 0x6895a5f7, 0x80c9315e, 0x7e991b31, 0x8aad4d20, 0x1406a30a, 0xe12e3dcd, 0xd99b5acf, 0x3ea6a936, 0x73301187, + 0x63a9517a, 0xbf070e52, 0xfaa46eaf, 0xb8d79b3d, 0x270311ee, 0x9eec7455, 0x9160fd21, 0x4fbbf33e, 0x8bb80cbb, + 0x1e842c3d, 0x59b9bb04, 0xe06cee1b, 0xc57cfff0, 0xdf7a9934, 0x70125c26, 0x17cfffa6, 0xddffd6f8, 0x61a488aa, + 0xc87cd1d2, 0x43bdeaf4, 0x38d6768c, 0x6fb901b1, 0xdf570fcb, 0x007a5820, 0xb273a247, 0xd1512047, 0x6ee21060, + 0xb430ad31, 0x4afbe7aa, 0x4e6dcc98, 0xf37a261e, 0x5ad21d5d, 0x0e90915d, 0x2c6411f2, 0xa22cbc33, 0x979180cf, + 0xf771c232, 0xc3af6bbe, 0x86037b5f, 0xe0dbcf4d, 0xc8a4cae6, 0xaf92326c, 0x0fce6aed, 0xa654c4fd, 0xa23a26f3, + 0xac088b26, 0xded8c48e, 0xf94455c5, 0x739aff1d, 0xed00e0fd, 0x91c0c837, 0x6d2f9307, 0xe772dd32, 0xb69f67c1, + 0x6124dc49, 0xf2a969d2, 0xd9ca6a30, 0x3bb78612, 0x79291d1e, 0x9e419f99, 0xa3f81169, 0x549ef83d, 0xdf73a81d, + 0xe3952095, 0x02829f6d, 0x8d056a90, 0x10fdc58a, 0x2ee8b1fc, 0x139ba34c, 0xe6528f3c, 0x95ecfa7e, 0x81bf10f7, + 0x064fe0c0, 0xd0dda336, 0x4239c7c7, 0x1f096a3f, 0x7db44a05, 0x99b396f1, 0x4431c009, 0xd3353e44, 0xd872c3b4, + 0x1e07da32, 0x9bc42d43, 0xd4830dc8, 0x0dfbb0b8, 0x4eb8147a, 0x9adaae1f, 0x97942370, 0x2e526a4a, 0x07691f5d, + 0x0cf31f69, 0x7f562548, 0xa030b2bc, 0x38504bb9, 0x0aa72c9e, 0x5246642b, 0xcf44f3f9, 0xcc149d06, 0x05368a2e, + 0x0f517d4b, 0x0f2b1fb8, 0xa065a570, 0x7825cdbe, 0x19a21573, 0x5beafbef, 0x88ce14ee, 0x6a4f2fdd, 0xfbc22091, + 0xd4f4e61f, 0xe86509d4, 0x1e41f692, 0xb208021b, 0xaa607e4e, 0xd4583973, 0x0099e2ae, 0x8c21cc31, 0xcc8f9bfc, + 0xd7ed470b, 0x26e24a30, 0x3d1472e5, 0xa8b85055, 0x7ff03e49, 0x28674880, 0x74efb981, 0x2c3245f4, 0x5ece8e9e, + 0x0688e0b5, 0x70b45589, 0xa32dc06f, 0xab7a2269, 0xb867db20, 0x3ad4315a, 0xf5a1def3, 0x00856e45, 0x70ce1466, + 0xeab8bca9, 0xdc42012a, 0xeec06983, 0x22c7c9c9, 0xc4ccd0ac, 0xe54ec9a1, 0xce2ef50c, 0x8032a847, 0x5aab8a1d, + 0x9a8a5b31, 0x21fe7281, 0xef83ba70, 0x88fe2f7d, 0x2e23f46b, 0xd5bf44eb, 0x27e374f1, 0xf7ba4c6b, 0x470201dd, + 0x8f1389a8, 0xf83ec693, 0xe680b666, 0x8a70385b, 0x7982c549, 0x72ee50ba, 0xe05812d7, 0x9930657c, 0xd7eccc93, + 0x897e341d, 0x59ab5c5c, 0x3a106334, 0x8c5dedd8, 0xe7333318, 0x41cf0ed9, 0x88c88a58, 0x0f9111ef, 0xfa987a49, + 0x1af56b00, 0x6f1266cb, 0x21ade7c9, 0x8e0bcf92, 0x5e96a3bc, 0xe40aec46, 0xdf4f7d91, 0x92f7aac3, 0xd147b9ee, + 0xd02d8908, 0x86eac934, 0x5de88388, 0x1432215c, 0x3c3ec193, 0x885fdc2a, 0x3882f20f, 0xd59a21dd, 0x84717bf8, + 0x68784513, 0xe1746f4f, 0x5ca0a94b, 0xa074f908, 0xf05be2da, 0x2c9f7b0c, 0xe06f6b2e, 0xafcdc44d, 0xc744bce9, + 0x94fd3a09, 0x0e52676f, 0xadba6a06, 0xd2b179b0, 0x87eba072, 0x9343e940, 0xbb8f5c2d, 0xf6402c9d, 0xd64f22bb, + 0x98ac2c62, 0x19bed524, 0xf34eb446, 0x4385d121, 0xc00ec3e2, 0xca566232, 0xf33930af, 0x86641252, 0xe3c8a9fe, + 0xccb833b6, 0x192dded5, 0x7e1d1c9f, 0x91c62627, 0x2e9673a3, 0xab436926, 0x0a613e01, 0xc669325d, 0x074ff14f, + 0xde65cbde, 0x324e42c8, 0x726608ea, 0x74ec2f0c, 0xedfe987b, 0x43104ac4, 0xdd363f9a, 0x7827e3be, 0x5e8bb021, + 0x951eee1a, 0xcc2baaba, 0xcf34ec17, 0x89ce6b9d, 0x473ec9e6, 0x228dd67e, 0x8058b58a, 0x8acbc568, 0x84bd6af3, + 0x76ff5c77, 0x213f9d62, 0x3ef3ce61, 0xf439fbb1, 0x80c58888, 0x7141ca77, 0x1f2f905b, 0x8a6ea1e8, 0x881ae994, + 0xc2da2c53, 0x9d397798, 0x028c429e, 0x7b64af75, 0x995df0a7, 0x2d16f9bc, 0x626710b7, 0x795ece1b, 0x47c8b861, + 0xb323aca7, 0x0d62290c, 0xed1a7cee, 0x16caabbf, 0x2ad440ed, 0xe589d979, 0x7d1f94b2, 0xb795a78c, 0xa07c8bdd, + 0x7f1b5064, 0x25f1aa59, 0xab1bfe84, 0x0541892b, 0x845c6ead, 0xdce5cc84, 0x266f9273, 0x77435c2a, 0xad012819, + 0xf26289a1, 0x839e4b9a, 0x055c24a6, 0xc70fbdda, 0x4001d652, 0x0c159e2b, 0x02e616b8, 0xa4602321, 0x3bf85c95, + 0x55b1b173, 0x342314e1, 0xfbdcac0b, 0xb255a45a, 0xfbbcbde7, 0x096644bb, 0x623ba653, 0x199ebfe5, 0x01ce3c90, + 0x60e85fb6, 0x9ac3c56c, 0x08c07dad, 0xbf3f479c, 0x1848818d, 0xd239fcf0, 0xf82dbe6a, 0x41d71396, 0xc20b2c4c, + 0xf0a054ee, 0x83b629fe, 0x8fce9ff2, 0x4a385042, 0x407c65fb, 0x6c66f6b2, 0xb0a401d3, 0x56a331b8, 0xbf7f1db8, + 0x40bcb152, 0xd5733aac, 0xae6f214c, 0xc35857c9, 0xd23bf3a6, 0xdad143bb, 0x5869598a, 0xa49e97f7, 0x3c20aac6, + 0xdafe010d, 0x05ff29c5, 0xadae4e21, 0xd2e19871, 0x214499b0, 0x53752137, 0xa3ea46aa, 0xf6ed2069, 0x36bcdd66, + 0xa08010ad, 0x7c881fa7, 0xf5cdbbd1, 0x75202de0, 0x19fa5c4c, 0x8c4f6356, 0x311465d7, 0x2e088e9e, 0x5ffc47ea, + 0x9a18647a, 0xb36e0a69, 0xab0b579e, 0x98f8693a, 0x7d8fe2a0, 0xd5e96cdc, 0xbc70b871, 0x2530d8f1, 0xe113fcaf, + 0x46eccde8, 0xb16284d6, 0xbaadca5d, 0x6bab590f, 0xdb334c29, 0xd916f9d3, 0x015b250f, 0xa60d8f53, 0x1fb83842, + 0x0ddd442e, 0x3a19501d, 0x9af33a4b, 0xb94c0a78, 0xc10b73ba, 0x129c3a93, 0x4dacd5f5, 0x0226a887, 0x69b45ccc, + 0x40e8325c, 0x5a0fb3b4, 0xfcd93c93, 0x572c9541, 0x27084441, 0x12cafa67, 0x8538617c, 0x0b57d51b, 0x3ad8a310, + 0xee6993be, 0x71c3933c, 0xc1a9f32a, 0x5c34affc, 0xeec5f2c7, 0x66cd843b, 0x62f33d59, 0xd585472f, 0x816d518c, + 0xd97262d6, 0x5d3af753, 0x476e3e71, 0x552bc93b, 0x81bad9e2, 0x0be58638, 0x1f6cd97f, 0x981ef129, 0x14a51b2f, + 0xe393ddc7, 0x23d6b885, 0x2521b217, 0x2b57cadc, 0x97334ace, 0x6db863d4, 0x5fc36421, 0xd52c023c, 0x196a3743, + 0x915a7d9a, 0x7be20675, 0x5e0251a9, 0x5e5e4d6d, 0x3bc48e0d, 0xa35dcb7d, 0xe76d0c57, 0xe9925f67, 0x2e68048c, + 0xe6c1d44e, 0x11e78d47, 0x70123057, 0x7e699193, 0xbab0890a, 0x4fa0adb2, 0x8df114f7, 0xddbdc16c, 0x1002479b, + 0x34271d5a, 0xa0f589f5, 0xd8d378f6, 0x42e72101, 0x5ded887b, 0xbe6a2eb5, 0xefabe82a, 0x83065d34, 0x3b3a9e77, + 0x1a92851d, 0x4ff68f41, 0xe545c1a8, 0x461a4801, 0x47427877, 0x284d92ce, 0x2af1c5db, 0x0422c081, 0x3ffd5444, + 0x88dae012, 0x9288613f, 0xacbf92e6, 0x8af58ae7, 0xa3e412d8, 0x1e584ae7, 0xde8f020d, 0x3b1cf6c5, 0xc5f93d2d, + 0x522da810, 0x67ca30bc, 0x9bd44ff1, 0x3d95b68d, 0xd2860e16, 0x40d223e2, 0xbdf986d8, 0x393b0017, 0x4f0afca2, + 0x892d7a9a, 0xedc9b3d9, 0xeb14d463, 0x8af8cabb, 0x00beecec, 0xd039339d, 0xe8bd1153, 0x0276ebd0, 0xf9eee808, + 0xe0683dbd, 0xd9a75b6d, 0x9f5f5071, 0x04ea387b, 0xad65634a, 0xb6d7f19f, 0xfccb9d64, 0x89c4c73a, 0x455a02ff, + 0x1f53011d, 0x757a1bf7, 0xdf793c50, 0xdcf65e30, 0xbcf15f4e, 0xa5a3d7a9, 0xce02bacd, 0x0f9aa380, 0x1190c0bf, + 0xfbedc1e6, 0x31fee7ec, 0x797baae0, 0x2dcda185, 0x7b1dcc71, 0x19e1cac2, 0x2fb950c8, 0xed0f0382, 0xf6ff1e2d, + 0x4a826ae4, 0xa6ff6bcf, 0xfeb4af23, 0xecb640cc, 0x5ab919f6, 0x6d1fbdea, 0x612b38fd, 0x3f1c159c, 0xb5a6c0c9, + 0xacd78c61, 0x5cfb5247, 0x587c7cd4, 0xa7132d55, 0x9d74f104, 0x7873ffeb, 0xc91c1953, 0xd6576e66, 0x22ab9852, + 0xadaba095, 0x1c189253, 0x61c2f39f, 0x39db579d, 0x717ac8f1, 0x6f13e486, 0x52bad3f9, 0x3fb3960c, 0x5b5f20d7, + 0x76f8f257, 0x6592dd73, 0x44091adb, 0xbe83e0d0, 0x86172fd5, 0x0b0e8410, 0x96ce41bf, 0xef739f16, 0x7f2f5941, + 0xb4d7f144, 0xb2d62761, 0x3f9d77cd, 0x3493f3c1, 0x2affa7f0, 0x2b13ca4d, 0xab0c05fb, 0xe2c2828c, 0x23c811be, + 0x4b4d9bd4, 0x58cb611a, 0xed33baf7, 0x5e95fb82, 0x33c50e4b, 0x24bd72ea, 0xca6322fb, 0x9277d356, 0x1ae05017, + 0xb4a3f05d, 0xa2919546, 0xab926844, 0xec011f7d, 0x3ec573a4, 0x3128906f, 0xf939da94, 0x3231e844, 0x01aa4ec0, + 0x6f07583a, 0xe03719eb, 0x57334e17, 0x8d4bcda8, 0x3af08ef7, 0x2a7a2c87, 0x556e0001, 0x395b37cf, 0xcb2ea562, + 0x426cb6c5, 0xb34079ad, 0xa4dd8f47, 0x08c8a52b, 0xe7c7be00, 0x43a81b7a, 0x89993323, 0x40d14fc7, 0xef2bc2c9, + 0x4bd0ccff, 0x5e355d04, 0x7759aeb5, 0xe2828cbf, 0xabe6b5dd, 0xdef9fd45, 0xcabc2187, 0x70c4d6cb, 0x58e9833e, + 0x93191b38, 0x118e5332, 0xcf71e5ae, 0x80dee23c, 0x68c12cef, 0x2da1c59c, 0x9366e31d, 0xf6c6928c, 0xd107df42, + 0xa2787819, 0x4f9b772a, 0x3ba11c65, 0x4af15ad1, 0x8eb200df, 0xf033354f, 0xf1fbf48a, 0x961151d0, 0x412a02e8, + 0x7c0faa46, 0x156e3599, 0x451a0366, 0x734a0fc1, 0x0c46f4a7, 0x62985728, 0xf7d1d503, 0x51c63e63, 0x2699eb3c, + 0x0bffc484, 0x52b2d1b4, 0x24dd1df7, 0xff849557, 0x7fd97725, 0x5fab6146, 0xa92242f1, 0xa58ea319, 0x65896aed, + 0x3634684e, 0x667b9078, 0xd4859e99, 0x3b8f5afb, 0x095ddca7, 0xbea6ac76, 0x328aa027, 0x98e761f5, 0x45148542, + 0xcca28eb8, 0xa97ab4e5, 0x07288f7f, 0x30745493, 0x11c473c2, 0xd6719ae0, 0x95c17f00, 0x036511ad, 0x76f84f47, + 0xc0e46d3a, 0xcd579e7d, 0x5f3fe623, 0xa852e23c, 0xecefff7c, 0xd6cdf5c8, 0x793110f1, 0xc21ba788, 0x331a7a63, + 0xf107d5fc, 0x42efee2e, 0x9969b7aa, 0x980b21d3, 0x40114003, 0x5e8ce5a5, 0x9733448c, 0x36a40053, 0x7a74e12f, + 0xdd155bdf, 0x45c297e5, 0x6d1a4a03, 0x272d0db2, 0x6ccb54eb, 0x13e700e2, 0xfe7f66cd, 0xfcb6e67f, 0x4a9e4c65, + 0xc1676178, 0x3ba7c22a, 0xa1737f1e, 0xa7f4ee52, 0xfad03425, 0x1e1ba0c1, 0x480238d3, 0x6dc2559d, 0x33003291, + 0x2ed8e47d, 0x98e09ebd, 0x6c22f773, 0x9f89d747, 0xa3639bfb, 0xcec61043, 0x4501ee20, 0xcc0361da, 0x1fd175f3, + 0xe1252d5f, 0x3666c791, 0x7866e40c, 0x635e475f, 0x5e80cd61, 0x629b8dff, 0x31525dd8, 0x86ad2168, 0x5c1ad502, + 0xf24c7c1c, 0x0d88311a, 0xb68d4b18, 0xb26bc963, 0x4386c88d, 0x7ddbdab7, 0x406e1b2b, 0xe6d62490, 0x25b77340, + 0xc39ef450, 0x693c556b, 0xc83ea1f1, 0x1e962da6, 0x8e3b5caa, 0x76518cc5, 0x980b0c18, 0x66d9a09e, 0x575acd53, + 0xe701cca3, 0xec2d9d2d, 0x6a64c9bb, 0x86aa4e9a, 0x7bbcc74f, 0x487ba026, 0x1d81e93b, 0xaad8288a, 0x79d76f1b, + 0x75015559, 0xe4a1befb, 0x17b0621c, 0x76550855, 0xc50e0d75, 0x3947e7fb, 0x8fe63422, 0x14c4cf78, 0x61e8f824, + 0x7e61f685, 0xb02a1bba, 0x7d76c00a, 0x3ab2adb3, 0xb3eb3191, 0x480746e1, 0xc1078145, 0x8d2df6e1, 0x631897a7, + 0xbd3d83ed, 0x6ff8ee9d, 0x7abc06d4, 0x96a89a09, 0x06b41c1c, 0xb015650f, 0xf6f721e0, 0xadf69827, 0xc74075bb, + 0x7fb1c111, 0xb6a98f57, 0xba6f9d7e, 0x9199ec5f, 0x9f92f2c6, 0x08e59443, 0x31688656, 0xa9f37c01, 0xb51c22f1, + 0x5f5de2c7, 0x3ea63c9c, 0xdbb94d12, 0x2ae1a3d6, 0x3317cf21, 0x22a4b1f7, 0xe377be6c, 0x1e98dcf8, 0x194f8629, + 0xe65fc0c8, 0xbd0706db, 0xde7b56a5, 0x150d4dfa, 0x50cd7fb9, 0xe77901c2, 0x370991ee, 0xc23b4b5d, 0xe824d7ca, + 0x98be4542, 0xca1f04cd, 0x8c995b61, 0xd97d7835, 0x839189e1, 0xf41ff215, 0x99d59583, 0x0467a3d1, 0xaf3da310, + 0xebcefed2, 0xd91aad9f, 0xe3ebb282, 0xc96107ef, 0xc10e8560, 0xe5b1da72, 0xdc889da8, 0xd35f3e0f, 0x10b418cc, + 0x74072ec3, 0x182ed8e2, 0xda8e5d22, 0x41df4b2b, 0x55e4d003, 0x3c17a1ee, 0xf63b1d86, 0x3f26b25b, 0x2b28410d, + 0xe0f0964a, 0x911e5793, 0x63575b93, 0x19bea982, 0x9e16c752, 0xd10fc179, 0xe6e88147, 0x4c89e52a, 0xb1347f2d, + 0xe49f34b5, 0x7fa38361, 0x744c296a, 0xf852c9d1, 0xe6c4d356, 0x3c29c5c4, 0x7601f875, 0x3e1ebb69, 0xc0fee643, + 0x15a1926a, 0x9b63a2a3, 0x46e195d6, 0x6d0b0512, 0x29920dcb, 0x6df2b2bc, 0x3d1061bc, 0x62094121, 0xfca8d7cf, + 0xac390727, 0x3c93c05d, 0xbf43f045, 0xe51b3fc5, 0xf2e1bcf3, 0x2ffaea1e, 0xdaed23c6, 0x495f3b3c, 0x405f3d14, + 0xb285fe39, 0xd616f4a4, 0xb833b433, 0xbd534840, 0xf2448b03, 0xacdfd86f, 0x5e6a31c0, 0xce20fecc, 0x5727d8e6, + 0x0f8f4635, 0x396e0f23, 0x6bac9e11, 0xeb9ccf32, 0xf95e2efe, 0xeb14627b, 0x0d88976f, 0x45223166, 0x61e00cf6, + 0x79b8b642, 0xf27625e6, 0x2cae88a9, 0xbcb419d7, 0x866cc9e6, 0x26e50256, 0xa2c9209f, 0x62fe1630, 0xd27d054e, + 0xa19839da, 0x719db85e, 0x4e98b8d7, 0x078c9de3, 0xc054f8a4, 0xf150b4eb, 0x22d576d8, 0x85df5fe3, 0xb1ef03f3, + 0x7562cfdd, 0xc81df021, 0x40accab6, 0xf5e61c86, 0x1a001555, 0x5d6cbd57, 0x1c8bf550, 0x114af6b4, 0x3795e3f9, + 0xd3a4456b, 0xc39644a5, 0xb4ae0db0, 0x9161d36b, 0x52258466, 0x6ac3188b, 0x1da4cddd, 0x31839ca2, 0xce6e8b94, + 0x92a72e00, 0x54def847, 0xbcf6ac82, 0xa32f70a1, 0xfd74eb6f, 0xdbb9752a, 0xa660ad9d, 0xfef233aa, 0x301c13ea, + 0x9bb28f15, 0x680bcb87, 0x1e679bb6, 0xcbcf26b6, 0x4403b451, 0x2f6bb5ba, 0x9ed6eb50, 0x6c87fc8d, 0x826cf742, + 0x61454725, 0x594d2512, 0x9f8d4382, 0x1dd55c84, 0x1c1b9927, 0xf4c5c57c, 0x80e8445d, 0x6d057528, 0x16b871e3, + 0xac502aa3, 0x95501c18, 0x47d4207d, 0x9335542c, 0xe584864f, 0x909a94ce, 0xceaf718f, 0xa70f9cb2, 0x21d79c89, + 0xc85aadb5, 0x8db28791, 0x7b1c87ac, 0x157a0d58, 0x1473e076, 0x82a89ba1, 0xdb752771, 0xb342ee62, 0x58ef1dc1, + 0x1161bc03, 0x11903c16, 0xea5d250b, 0x485e5db2, 0x457237cd, 0x31ea6d29, 0x49484121, 0x7f718fc4, 0x8d784c12, + 0x2737b2f1, 0xb18e8a22, 0x856a6cc2, 0x0f70d317, 0x1c401646, 0x2b0491a9, 0x7cf9cb4c, 0x3273d49d, 0x1eb93088, + 0x24b21385, 0x4e70d153, 0x006c4029, 0xdb2cada3, 0x42bea7b7, 0x5a4fa14f, 0x07c79aa1, 0x4baf20ce, 0xce48f1f3, + 0xce746aa0, 0xd7dec518, 0x75585595, 0xe4c22f1e, 0x2dc38d42, 0xeb32807f, 0x650fec55, 0x5a6f9ba7, 0x0e08b886, + 0x6879b6d2, 0x61c222b0, 0x238e9aa8, 0xd13be8c2, 0x2aaf708f, 0x60917736, 0x86a9bff2, 0x6ce01295, 0x91fb5421, + 0x08b33295, 0x8695c546, 0xb072546a, 0x812538d6, 0x9787ac84, 0xdd18787a, 0xa1cc937d, 0xff877770, 0x194474b2, + 0xab54fd00, 0x980b96f1, 0xeb444435, 0x04f522d9, 0x6bb6bec1, 0x37f96313, 0x9ae8a825, 0xfcb4aa55, 0x0d419b7a, + 0x5444ba32, 0xc6cbbae7, 0x5a93e91c, 0xae758b39, 0x8264dcdd, 0x325a4e77, 0x1662b200, 0x8aff1c5d, 0x5efa7894, + 0x3f5d6ec8, 0xd138d7f3, 0x8a9f2451, 0x61caebc9, 0x6d3d549e, 0x6f80910c, 0x8c4674c7, 0x3936e8f9, 0xe735e726, + 0x5e7f381d, 0x1fe447de, 0x4b93c6eb, 0xd18951cf, 0x1f4e81ce, 0xc4e4326a, 0x37f120d2, 0xd4fbbdab, 0xa3377f42, + 0xcc29039b, 0x7bacef94, 0xc08036db, 0xe2b463da, 0x0235da19, 0xceaceec7, 0x733105b8, 0x85ece903, 0x3ab73c8e, + 0x87300a83, 0x98706087, 0x7b43ae89, 0xb83a5753, 0xaeaedec8, 0x2de69059, 0x8a698a78, 0xe8da76d4, 0x071e1640, + 0xb06470f5, 0x74959627, 0xa0f4fc71, 0xf7b2f4ea, 0x7c6cb25b, 0xc1c2a105, 0x2f533940, 0xafd030bb, 0x3cc2eb66, + 0xa2f8c023, 0xdac95c03, 0x3fe2839a, 0xe23916fc, 0xd94edff2, 0x5f525d55, 0xbc6391cb, 0xfbd5b1d0, 0x32a22ab7, + 0x3d8c3bc0, 0x4a961324, 0x47177af8, 0xe74e3c42, 0xde37be46, 0x9cd77f45, 0x9f641c78, 0x9bcc138d, 0xc47f5d85, + 0x5667dc47, 0x0210c9b2, 0xd5ff06e7, 0x0b2f1a68, 0x1f76167b, 0x56b770c7, 0xcb7f7b3a, 0x7ddd21b3, 0x982845e6, + 0xa86adb8d, 0x312564de, 0xd1b3c67a, 0xc061759d, 0x2f956c32, 0x93c2e834, 0xb17929da, 0x9830bdda, 0x9a3b368c, + 0xdf3fcfa4, 0xebf381c6, 0x2c10aecb, 0x62c14053, 0x202622a4, 0x9606f7b8, 0x318798e5, 0xab297952, 0x50705520, + 0x6577f513, 0xf8fb0a12, 0x8f15c7b1, 0xcbee306f, 0xdf96f107, 0x9259821b, 0x3b26b28f, 0x82208e44, 0xa136db95, + 0x98c18740, 0x22cabd1e, 0xf99c10fe, 0x86db2a54, 0x2a4f83bf, 0xd3675566, 0x1d021058, 0xf780f0ff, 0x70af3f07, + 0x3c6f1140, 0x7a5cedf8, 0xcafe259c, 0xddbd7441, 0x555565b7, 0x97ec4386, 0xc7af6155, 0x27b3306d, 0x60e4d967, + 0xfd5a2424, 0xd570196e, 0x26b9eb5b, 0x4f466700, 0x2ac4709a, 0xc64f4dd5, 0x90b747e1, 0x20e64425, 0x11e0e4c2, + 0xe3f7e89d, 0x9b955998, 0xecb1dd01, 0xbb5cb6fb, 0x4bdc0ba9, 0xca20b11d, 0x22a474f9, 0x55d727a9, 0x77537ae1, + 0xad564b87, 0xe6871b8f, 0x0c9796e0, 0x8a118464, 0xa82a5cbf, 0xf4953bd2, 0x490e1df1, 0x460ef456, 0x319ecffb, + 0x88b5b401, 0x8d890532, 0xdd301d06, 0xcb8382f0, 0x0d6e7996, 0x0d0759ab, 0x37eb20b1, 0xe038af62, 0x48b7aea4, + 0x788fd72b, 0xa90aa60e, 0xab90ea77, 0x9e10e83a, 0xf2645ff2, 0x2f38c311, 0x73148081, 0xc2f55b32, 0x78b51d61, + 0xff180cd8, 0xc42667d7, 0xff82f74f, 0xf8d149b8, 0xe13160f4, 0x5d8e8a53, 0x33d74b53, 0x462d9b54, 0x349f8f38, + 0xd60d9758, 0x324341a7, 0x960a97a9, 0xc7c18ab8, 0x1fec9862, 0x7f1c5fc0, 0xc0870f37, 0x9326e6c1, 0xb4733c44, + 0x92404316, 0x697a0ef2, 0xaa5e3dc4, 0x1cfa92f3, 0xbe87f926, 0x6ab898ac, 0x130f0132, 0xf1294363, 0xb5a52ebc, + 0xd3f8470b, 0xf3eb5d0b, 0x79304847, 0xb487e821, 0xf4f56528, 0xb35b7f94, 0x0c750b73, 0x289a2bd3, 0x190912e0, + 0xd4e4b06f, 0xb68c9d67, 0x65b23c68, 0x634e95b0, 0xd1ee1043, 0x881fe28e, 0xaede9b05, 0x4a638405, 0x127d2cf1, + 0xcb5c99e1, 0x37ec0579, 0x50228101, 0xb1c8006f, 0x35aea92c, 0x6a29abec, 0xef49ebf3, 0x0de3cd43, 0xd04fdbc8, + 0x2e1ff219, 0x641bc484, 0xc0801941, 0x818801b3, 0xdfcfaad3, 0xc70bfc1d, 0x39d30fb3, 0x67670cd7, 0x540dd07f, + 0x2e5182b1, 0x8b2ffda1, 0xabea2eae, 0x2633fa07, 0xb120b060, 0x045dce24, 0xacf98101, 0x50ceebd9, 0x91672c47, + 0xd1072cbe, 0x3bb4be2b, 0xf27bc857, 0xd5dc0d41, 0x098b713b, 0xfc679513, 0x0d388bd2, 0xd762ecb9, 0xf142676d, + 0x0278f8fe, 0xdad6ffa8, 0xbdb57cf7, 0xe68f7c7e, 0xc6f0b75d, 0xcbee1425, 0x8ef2706b, 0x6139f79e, 0x17d7415d, + 0xc8f2b738, 0x4023f573, 0x6638bcde, 0x8297d1a4, 0xfc98269c, 0xd431a340, 0xf3f12232, 0x2978e872, 0xf12de076, + 0xb16021b1, 0x0bb6d1b4, 0x9e6479e3, 0x3e76e9ee, 0xfc9954cb, 0xbba5894f, 0x0f616aac, 0x680f16ab, 0x4df6f85d, + 0xaa22390b, 0xb49f3001, 0xee0c9973, 0xd5732652, 0xbfab5d30, 0xb07a144c, 0xc4da2aab, 0x47f2c3e2, 0xde4a470e, + 0x097fb42a, 0x134865aa, 0x0e499690, 0xdc0a7841, 0x7ffe0f79, 0xcace4193, 0xdbf596b5, 0x41f016f0, 0x829c6df4, + 0x4152bdae, 0x5bbeb812, 0xd6ce8dfd, 0x5b76f537, 0xc0b73196, 0xf82ff1e3, 0x419c6c39, 0x06f186c8, 0x60a9e1f4, + 0xae826581, 0x5178dc19, 0xf780110f, 0x1d485eb8, 0x3351b25a, 0xd38937b6, 0x4f075a9a, 0xdf046604, 0xd74e9659, + 0xe5edd27e, 0x2db4a59d, 0xe96187f7, 0xb6ec8793, 0xadb49256, 0xd6f83346, 0x8f59237a, 0x037d9267, 0xfe88e139, + 0x5e5a4950, 0xab84cc52, 0x865feaeb, 0x53e12773, 0x8a1ff409, 0xc9afc89f, 0xf3b0427a, 0x27874f07, 0xba1c3e6a, + 0x0f85607f, 0x9cfb17f8, 0xe52e6086, 0xd0f796e5, 0x7b91ae43, 0x11b8fd3f, 0x79c56b21, 0x38d6b5dc, 0x64c7cb6d, + 0xaa5c201a, 0x2fcda68d, 0x1ae87f98, 0x47ba3e07, 0xbabc0a22, 0xd9dc67e1, 0x3d30a4dd, 0x15a7aad0, 0xb84731cf, + 0xef01c533, 0xea652842, 0x1329b493, 0x0c6a3a79, 0xf65ce10d, 0x5b455c77, 0x668dd1f9, 0xc1cd735f, 0x6f0cc6e0, + 0xa32c1b1e, 0xfe547d24, 0xbfddf62b, 0x08d73db0, 0xe57bdc57, 0xab51110f, 0xa2f5c571, 0x8f554db5, 0xb661086d, + 0x88991e5d, 0x4e5796bb, 0x73c58019, 0xc1da0459, 0x8957073e, 0x867f8261, 0xfc3264cc, 0x4b841483, 0x1e5087da, + 0xc4314b8e, 0xdf3a5577, 0x1a9aaf28, 0xacb85737, 0x5e9c9e79, 0x2a55a586, 0x5486bf92, 0x911032f8, 0x9c237884, + 0x9c45a7ed, 0xe18d33b4, 0x510df8c0, 0x7f2c86d4, 0xdf662c57, 0x93e73627, 0x224388ef, 0x10c2929c, 0x80a87384, + 0x7f091655, 0x497793a4, 0xc23864b8, 0x77256c3e, 0xc43ee1ff, 0x75563ecc, 0x0ddb9a3b, 0xcb84cc22, 0x42016047, + 0x102c0085, 0x80958e99, 0x1da2ce8a, 0xf8b26d60, 0x184637c2, 0x6313e88b, 0xec51792a, 0x6d078645, 0x65381e9a, + 0xc6c67b57, 0xcae78db7, 0x6c56fbb6, 0xfb154038, 0xa3f42182, 0x61b4e6f9, 0x8f171f4b, 0x0e364ba8, 0xd8f35867, + 0xe246dfdc, 0xef3cdd8e, 0x03ba23ea, 0xa64ceda9, 0x4a01b90b, 0xd9887768, 0xb29b4434, 0x9d1096b7, 0x2ee75757, + 0x5393744e, 0x39fe2830, 0x130eb093, 0x6ee93623, 0x3d5de04f, 0x8c21cbfd, 0xe8566b2e, 0x93bbe755, 0x6de1c661, + 0xdc844f01, 0xe13ed456, 0x09bafdea, 0x646749b0, 0x3cf07990, 0x100a898c, 0xa23adb1c, 0x7fdf5415, 0xc3566018, + 0x09830763, 0x85dace50, 0x7dbb8bed, 0x742b08cf, 0xb00e34d9, 0xdc238c9e, 0xae24691f, 0x12c7b8e3, 0x0948604a, + 0x39940e5e, 0x7db384cf, 0x928a6f58, 0xf9f8d100, 0xda8a2cf5, 0x4d2bc25f, 0x8e528c26, 0xa926affa, 0xe5dacb0d, + 0x8b07428c, 0x8ab491ee, 0xce469318, 0xde439c87, 0xed3cfc57, 0x9ebbf195, 0xcf8e8ce4, 0x06523ec4, 0xb089bfc0, + 0x3a05b138, 0xde043e1d, 0xfe79971f, 0x5a3aa826, 0xfdc7d233, 0xdac621f4, 0x3fcea95d, 0x29333eab, 0xc092ff0d, + 0xe3125db4, 0x5482f1e6, 0x2dd1a7a5, 0xcc9fd7f4, 0x9107e3d4, 0x5483deca, 0x02fc1026, 0x7da5f934, 0x588f278a, + 0xa302d263, 0xbf7eefeb, 0xb74bcdb6, 0x39bca6ec, 0x803c39b8, 0xe08bce51, 0x2fbfb3cf, 0x3324c315, 0xd912d25a, + 0x14973d9c, 0x19e9a2bf, 0xf24e80bf, 0x9662294e, 0x1ff01306, 0xcbab7807, 0xcddd1ee8, 0x880e1cde, 0x0bd6a36d, + 0x22b61d10, 0xbaae1d85, 0x9026e9e8, 0x3851f1df, 0xedbdb05d, 0x9278d3ef, 0xed3c6d15, 0xcc9d96dc, 0xe55b2877, + 0x0807d012, 0xe15c50fa, 0xe636f803, 0xd72cdd01, 0xcf2f1beb, 0x012d5a16, 0x8601aca1, 0xc12dec60, 0x8a1b16eb, + 0xd771321e, 0x525eed0f, 0x841227b7, 0x68da2be1, 0x1d5b86c8, 0xe8f33b99, 0x573d5636, 0x956419c3, 0x86e90ea9, + 0x2c284962, 0x3a90f4f3, 0xaf547360, 0x074e64fa, 0xd511b3ba, 0xa53568b7, 0x3f28c1e3, 0xe07112f7, 0x0d535d65, + 0xc281fe18, 0x1e815f60, 0xd93ddfab, 0xe55b13ec, 0xaeb8bde8, 0xd649a6b9, 0x0b182578, 0x15efb051, 0x8facc0a1, + 0x476fe584, 0x23d43f93, 0xd5971746, 0xdb4676cf, 0x016db207, 0x5411baf4, 0x5e18f1dd, 0x2c46333f, 0x07338a52, + 0x8ba1c69d, 0x17d9540f, 0x84dd0136, 0xaa84eaf3, 0x210092ae, 0x67fd4f12, 0x64cde364, 0x2b833676, 0xc8183c98, + 0x06a2a679, 0xbff38cf2, 0xf323499b, 0xb49a2c73, 0x99f9f511, 0x0ea0191f, 0x12fde2c3, 0x493d5dc9, 0xe18e3b0d, + 0x9783d90e, 0xa394f3a1, 0x8eb75279, 0x1144c69a, 0x38a7fc18, 0x0a37c52f, 0x3d7d16ee, 0xd7994d52, 0x9d1bb94e, + 0x33882f4e, 0x2f316a0e, 0x8ba2aa5f, 0x08f42a55, 0xcab27003, 0x8398ddde, 0x35e11ef8, 0xabda0126, 0x49ab6b9a, + 0x1e8e58e7, 0xb28dbfc0, 0xe23bb499, 0x1fe84c7a, 0xbe5ff6b2, 0xc3d7273e, 0x59ec6e7a, 0x1daa6e6e, 0x5fdc80b9, + 0x471f0d30, 0x0f6abcda, 0x3b56eb55, 0x56d7589e, 0x0094f09f, 0xaeefb192, 0x257db36f, 0x8d21776f, 0x7e88e74d, + 0xa6ec159f, 0xbe7f6f3e, 0xefdaa5a8, 0x6ec45f10, 0x9527900f, 0x7dd19092, 0x4302d093, 0x5c5c6122, 0x945e3207, + 0x0e5e0560, 0x5b9b9837, 0xd78262ff, 0xab648675, 0xc649e3a9, 0xd1d09f08, 0x6ac7f536, 0x718b67a5, 0x3449ae43, + 0x0ff597fa, 0x6b3ef065, 0x90451a5e, 0x5edd2a6f, 0x558aff3a, 0x61cf0521, 0x97b1d957, 0xa7ba72a1, 0x36d8eaa3, + 0x75dae618, 0xc57aaae1, 0x3a1b32f7, 0xa9c0d1be, 0x2518f26b, 0x468b3abc, 0x7d017c8e, 0x2d9231b2, 0x88eb8202, + 0x55101d88, 0xf5afd3dc, 0x04364431, 0xbebae242, 0x00d3179b, 0xbdf34670, 0x0d944e4f, 0xa1424c06, 0x051f1b24, + 0x5a7f3c7b, 0x27a655e3, 0xfa182cfe, 0x62d09d7b, 0xea215b61, 0xb2294bd8, 0x4c60288a, 0xd8d85a2f, 0x11147e1c, + 0x0e004ba6, 0x9b740ebd, 0xb3e9f56b, 0xce331cc4, 0x927763c1, 0x953fbf57, 0x93be2fc8, 0x9cc4195e, 0x736557be, + 0x6993aacb, 0x4236abd6, 0x3bbf5c9d, 0xd94484de, 0x0520a7c0, 0x353215ad, 0x5add962f, 0xd48c06d8, 0x9b4f2520, + 0x677754ff, 0x45345199, 0x4dd22e63, 0xc0ae0a74, 0xe24468b9, 0x7d3838be, 0xbfb43985, 0xf553f80c, 0xdc61e406, + 0x76be970c, 0xaae7ce84, 0xd18c877a, 0xb03bb09a, 0xa714cd33, 0xa6fb8412, 0xa9f1d916, 0x375138eb, 0xa6ac48a1, + 0x89ddafb8, 0x04c14d1a, 0x8378eef4, 0x28445155, 0x9f1c1cb4, 0xada90113, 0x12d59049, 0xdaab7215, 0x1eb9a079, + 0xfa85d546, 0x1fd6be44, 0xdd3ae889, 0x70f0d6b3, 0x42141685, 0x0278b9d0, 0x2c4dfdcd, 0xe33f4621, 0x8cfaf4af, + 0x9c44f166, 0xf0d08925, 0x484f1d4a, 0xcd798298, 0xf970cb9f, 0x7423f021, 0xa5b0c14c, 0x99ed1399, 0x9cdf6724, + 0xe6e0d724, 0x79bc52b1, 0x472bf633, 0xdf27073e, 0x08c99154, 0x07a91937, 0xddbf85e9, 0x04a5de82, 0xd8dda6e5, + 0x18b5990c, 0x8a78b78c, 0x60a54f54, 0x5c399ad9, 0x43141be5, 0x10992eb6, 0xfaf2980d, 0xfad6d788, 0x5718c9c3, + 0x47ef7e97, 0x46f1ccb0, 0x52e10c6a, 0xa0ef431c, 0x315fdf7d, 0x91cf518c, 0xe9aa518a, 0xbc39dc8e, 0x429f27d8, + 0xa3a3318a, 0xe5db5d5a, 0x5754a451, 0x14c7db1e, 0x00d2b59e, 0xa58648ee, 0xf4bcade2, 0x18c37444, 0x3d422dab, + 0xb5a55e24, 0xd71cc077, 0xeaf0a633, 0xe532729a, 0x4f44dbf6, 0xdc028e3d, 0x21ba8af7, 0xe91a1304, 0x9a3d48e5, + 0x4c5fe7b8, 0xd7e6542d, 0xd15b53fc, 0x1296d78b, 0x6c9b81fb, 0x01850931, 0xc9578593, 0xeb6f2295, 0x4f567f4c, + 0x393e768f, 0x2b6850af, 0x099f3ee6, 0x36127429, 0x214fa5f9, 0x8210b456, 0x6c1725f9, 0xd022b5b6, 0x12f2a3e5, + 0xf59d2f9c, 0xbdd6cca5, 0x85f4690d, 0xe37a69d7, 0x1513ff55, 0x0f849541, 0x8ad26803, 0x9d09d84e, 0x37a06924, + 0xf29f33a9, 0xc3114722, 0xe7b9aef9, 0x8d91cb2a, 0xb3affcfe, 0x8f998c1e, 0x76e63b0e, 0xf707dd8d, 0x4693c14d, + 0x4cdf9ab7, 0x210d19a0, 0x3577eb41, 0x61eb2092, 0x00af2324, 0xa9c5a799, 0x82cb447f, 0x86f399f0, 0xef4cc89c, + 0x88ba616c, 0x07b9bcf7, 0xcee354b7, 0x4ff28c8a, 0x2c957b95, 0x7cdf4d19, 0xc21bf6d1, 0xdb53fef9, 0xf1bf4fa5, + 0xcfd5e882, 0x763f7d53, 0x4f1ca36f, 0xc1e56ba5, 0xa806bab7, 0x1f82c45f, 0x3c57b4f2, 0x89d09dc5, 0x12c618f9, + 0x250fa1c9, 0x00d351e7, 0x890f1100, 0x047b06e3, 0xb86b791e, 0x60b0f63c, 0xf22eb3a8, 0x64f1dda6, 0x944c3d41, + 0x1e222415, 0xddbb7f20, 0x4d06aac5, 0xc5a283cf, 0x8d757009, 0x6cdcbb8c, 0x32f102e2, 0x36b9d990, 0xffc9d715, + 0x91d6b8d2, 0x68071cfe, 0x0f671859, 0xfd46f914, 0xd200e644, 0x445b6871, 0xa3717923, 0x86346d8a, 0xda98f5de, + 0x4a5da66a, 0xbc889f3c, 0x1e0f7b42, 0xa8eebc87, 0x01810b95, 0x19fdf485, 0xedee241e, 0xe433e088, 0x8ab80802, + 0xcacfc46a, 0x642301e0, 0x67d56f7e, 0xca3c2137, 0xec6e2f2d, 0xad6e8e40, 0x18eebd79, 0x6f3342cd, 0xd6900dd0, + 0x9852965e, 0xb11a117a, 0xab82a639, 0x41ff7e1e, 0x9aa818fc, 0x64578413, 0x439b00fc, 0xa2b51ea8, 0x7bfb849a, + 0xef5357aa, 0x07bde7c7, 0xbc3d4c56, 0x9a5b4aa6, 0xdc89593d, 0xdaa4cfbf, 0x26fe5586, 0x4b6d4310, 0x243f4b5b, + 0x5fd0a32a, 0xd9a70bd7, 0xd7554361, 0x763b0dfe, 0x118486b0, 0xc2fbed8d, 0xb1532936, 0x9041c6e5, 0x326a6204, + 0x5777958c, 0x324fd032, 0x1813fe2b, 0x45fe1900, 0x559677af, 0x25ad8c65, 0x091872b9, 0x24dda3e1, 0x0ef5602d, + 0xae8daf3c, 0x00dd4c54, 0x246fde59, 0x397f000c, 0x8ba50083, 0x9b425d6c, 0xc2bea6dd, 0x9fd2ee1d, 0xc206ca2b, + 0x10d2aef3, 0x2e0a4fdb, 0x61004835, 0x33556a48, 0xcc9a3e32, 0x919bab08, 0x09367204, 0x3a172841, 0x81366e64, + 0x8380e507, 0x9f4a701e, 0x6d7c8ab6, 0x560c9b6d, 0xf4db65c2, 0x7bf33f71, 0xec873ce9, 0xee707e27, 0x64b711a4, + 0xe7888145, 0xc4e0fe49, 0x16911651, 0x2985e6dc, 0xc6ed4279, 0x4d4b200f, 0xf0ff5dfe, 0xe40d1b05, 0x42b86da3, + 0x4dfc0591, 0x75508436, 0x8f7b6cb6, 0x4e66488c, 0xac769d0e, 0x9f9773fc, 0x5ac91aca, 0x863c41d4, 0xbff1e151, + 0x0c0b754f, 0xa1e95ab0, 0xee58ae78, 0xcd1b41ca, 0x85e6d07b, 0xe0d967dc, 0x2cfb90ca, 0x4cc5b73d, 0x3e3a9e3b, + 0xf87ab4b6, 0xd7f28d21, 0x9b2bc731, 0x425dbadf, 0xb0075a26, 0x742a4617, 0xe115329b, 0xdd8d3df9, 0x880b228c, + 0x94fb4bed, 0xac865501, 0xc743605c, 0xe8dc20a5, 0x55316a92, 0x1f598140, 0x61d4b617, 0x933a7d10, 0x5eb08390, + 0x541db5ef, 0x95e8c138, 0x921f4c4f, 0xb0924fba, 0xc73f15f7, 0x5ea6b966, 0x47f3e02a, 0xda495d0d, 0xd4f063cb, + 0x6a926c09, 0x4cf19900, 0xcb3273ca, 0x79bde263, 0x2c6c55f5, 0xd8dd55be, 0xde49d737, 0x06161357, 0x03f5c0df, + 0x77097016, 0x56598431, 0x1d6f0266, 0x1732745b, 0x6478f27e, 0xec158844, 0xc35ee025, 0xfeef21e2, 0xb9382089, + 0xfa37e458, 0x681f0c69, 0x0a3bf684, 0xa8a33150, 0x023c4b5c, 0x0dedd906, 0xd517730e, 0x261df267, 0x15831471, + 0x119c09fe, 0x18004d51, 0xed43469c, 0x42a6ebe3, 0x4757b0cd, 0x9090ebde, 0xbf8c7384, 0xdb799cbb, 0x11577b62, + 0xd8ca301e, 0xc266f0d3, 0xf4e1445c, 0xc5fbc988, 0x8d6f629d, 0x9d9235bc, 0xd6688438, 0x9d1dddf8, 0x689c33ee, + 0x38cd72e8, 0x844abaf9, 0x3ebcd508, 0x8d86b26d, 0x6cacb2eb, 0xcd327381, 0x88627cf3, 0x6806b018, 0x257be97e, + 0xc9b4e3c4, 0xd0b84640, 0x8c5ccbd2, 0x5bbc2945, 0xd5b59788, 0x7e55023d, 0x970bafc9, 0x2305ae98, 0xb646b0fc, + 0xe8fa62ef, 0xe5da77e7, 0x01dedd5f, 0x84a20955, 0x7fc3ee94, 0xf9403830, 0x63e5f4e1, 0x9e06391a, 0xba4c3b92, + 0xa79d4daa, 0x39220069, 0x3b4a9fc7, 0x31208c03, 0xad0b3bad, 0x71e3f353, 0x6f242a9c, 0x61cbb083, 0xb12f3ed6, + 0xfd7fee58, 0xf6cdc91e, 0xe90f3f9a, 0x9a22b153, 0x3f705f79, 0x7e1d2165, 0xc7ea3be2, 0xc6eb47c8, 0x199eaeb2, + 0x67cac249, 0x7ca3f274, 0xe448da05, 0x5d637172, 0xa94bc2cb, 0xaadb15fb, 0xe19d8401, 0x57afc046, 0xe5dea221, + 0x9dbb7b3b, 0x2e39dd91, 0x7bdb8394, 0x92a9a229, 0xccb9686d, 0x2e196371, 0xf405844a, 0x3dedf4ff, 0x90033a47, + 0x3ec211f5, 0xfd9a178a, 0xdffb3981, 0xbd168ecf, 0x111fbe78, 0x69587270, 0xb01a3348, 0x95178fde, 0x5f045277, + 0x50e5c97c, 0xeb60309b, 0x2a5d359c, 0x057c3c10, 0x1b3c32e4, 0x167afbe2, 0x7aa5428f, 0x3e731e10, 0x8b72a9e4, + 0x627a7927, 0x3375ef9c, 0xea6f4ecb, 0x2c02b2c0, 0x3e910fac, 0xe0958282, 0xa555286a, 0x30c41c16, 0xc8b8266f, + 0xd4ac6c71, 0x3fe0730f, 0x4ec71841, 0x8d6877b5, 0x8d17a39c, 0x80a04a17, 0x6884db68, 0x4613c594, 0xffcbaae4, + 0x34ef828d, 0xaf66c036, 0x02e11cff, 0x1956e1cb, 0xfd14c480, 0x1021b715, 0x2cd0b342, 0x4ca08c1e, 0xc43fbb31, + 0x7d192196, 0x224edda6, 0x3423e380, 0xdc9ef212, 0x185ba806, 0x3e7daad2, 0x65781dba, 0xb5f17b6d, 0xe155e6d8, + 0x05937cf1, 0x311d9e60, 0x3e0fc182, 0xc94b09e7, 0x5fdd2cf6, 0x90af1587, 0x1f24f3f7, 0x828eafb1, 0x8d05ed6b, + 0x5399adc8, 0xa66444f6, 0x26926e61, 0xe2573260, 0xebde3e2b, 0x72960040, 0x48340748, 0xc523d1e1, 0xc14708f5, + 0x611c939a, 0xd565403a, 0xfa19aa43, 0xea09a850, 0x4ba77112, 0xc2170ef2, 0x245e1b0d, 0x4c88d2b5, 0x1a9b5467, + 0xb2132a3e, 0xa41d8085, 0x1cf0fdd2, 0xe2a493e2, 0x5e1c480b, 0x06b35ee3, 0x05c77887, 0x2b5c5f04, 0x9fbf44fd, + 0x63a3d25f, 0x6f1f7221, 0x5ee162cb, 0x490e0d8a, 0x1091697e, 0xee3c8a18, 0x35c30a44, 0x2c822292, 0x17da9f23, + 0x7268d301, 0x3508f84d, 0x9d5f6c56, 0x2a644aa2, 0x70534375, 0xa2d509ba, 0x2ee829ec, 0x4e8f36e7, 0xedd8e101, + 0xfbc75a1b, 0x3c526f98, 0x479ef580, 0xe5edbc06, 0x73e43176, 0xff776605, 0x4485eb45, 0x78410623, 0x0e73d91a, + 0x3e200df1, 0x99f766ab, 0xaf582658, 0x6e77e7ec, 0xc0c69b1c, 0x9ec4996b, 0x942b584e, 0x7b4caa0b, 0xacd47213, + 0x8f953931, 0xdba9235c, 0xf883f9e7, 0xb91ccabb, 0xb579f0ae, 0x34a0ea28, 0xac01d39f, 0xfc47e71e, 0xffb654f1, + 0xc67381c2, 0xabe11357, 0x41275435, 0xce153ba9, 0xaa906e92, 0x7452f120, 0xeee0f651, 0x417e4c8b, 0x0966579f, + 0xc4224b97, 0xa7826c3a, 0x853a23de, 0xf4e9dde1, 0xaccb1721, 0x6e0e16d6, 0xa0b9cca6, 0xc48d9e67, 0x1e4fd503, + 0x92160356, 0xcdbae74c, 0xf31a333f, 0x5a9bda7b, 0x052ffee4, 0xf4a18351, 0x61119964, 0xd3843e30, 0xf6f36c9d, + 0x791f324e, 0x7e49ff28, 0x72502d99, 0xdb910fa1, 0x6e725281, 0xafdf1900, 0x4773602a, 0x2cfcc98e, 0xb1944412, + 0xc64a521a, 0x16ae44ca, 0xb8b0cbfe, 0x56948d74, 0x79f65479, 0x2780eacb, 0xe4b15acc, 0x1e63c586, 0x48d6221b, + 0x6c122f27, 0xd7820a2d, 0x7753e620, 0xfdc1a6f9, 0xc9bfc13c, 0xeae02bd8, 0xb7f50af3, 0xe4261df0, 0xa2dd8d6d, + 0xc5a55b90, 0xf60c3b9d, 0x339f6018, 0x4bf919c2, 0x00ebde17, 0x30ea6673, 0x68f7d0b4, 0xc67b2550, 0x7a478f82, + 0x3ca503b6, 0x10844c8a, 0x26333ef4, 0x3c6f704d, 0xd15cb29f, 0x4b156f8c, 0x5b495b83, 0xd99d12d2, 0x7a1fb410, + 0xa47fc8dc, 0xe48d7096, 0xa338999d, 0xc1a23b85, 0xc09fa2a1, 0xb62130f9, 0xbe8c5c15, 0x8a005c07, 0x5f63b5ac, + 0x44cec651, 0x910c53aa, 0x3c75759f, 0x68ea25b4, 0xd9af1100, 0x48419bf3, 0xa8979ceb, 0x6e1832e1, 0x104de665, + 0x758a5504, 0x25ab0b2a, 0x45e2bf8a, 0x035014cf, 0x3b60f840, 0x63456ccd, 0x1377f045, 0xf986e022, 0x9c234434, + 0x2432a34b, 0xba89d4a4, 0x861579a8, 0x79f309a4, 0x6481a300, 0x219ba839, 0x40d836c2, 0xb63ee94d, 0x87bb7491, + 0x653acaf9, 0xff31367a, 0x564c3c66, 0xdb123658, 0xf1288144, 0xfdcc614b, 0x2d514234, 0xb9b6ecff, 0xb9a9ce78, + 0x8250e2a1, 0x35d7725d, 0x3f2d4d98, 0x2210927b, 0xe0a5e4f8, 0x33361958, 0xcbe1bc10, 0x9db695a5, 0x27dc5708, + 0xbbead6c3, 0x08900e4e, 0x12abc81c, 0x05977bd3, 0x2c840573, 0x47970e96, 0xcae00527, 0x1516f3db, 0xc2942740, + 0x9f755ab4, 0xde7f7f4b, 0x789e1975, 0x8b5f1c8f, 0x214913af, 0x3c12d87e, 0xe0f66573, 0xc49b5ea7, 0xa3c29360, + 0xea284bd9, 0x2d6fc47a, 0x33ae97a4, 0x37aa05c0, 0x0450f5ca, 0xaaf64f9a, 0x4ffc6fc1, 0x6b8c3138, 0xf9e8dc8a, + 0x9afe2573, 0xd1965644, 0x1f6f1e56, 0x8ef42190, 0x8a4665fc, 0x13e71035, 0xe519d73b, 0x76c943d7, 0x71cc143e, + 0x6e58d2da, 0xe6254d86, 0x56d937eb, 0xba373356, 0xef903858, 0xa6afd9b8, 0x7aad337b, 0x01da2982, 0xe0987bfe, + 0xe65402a3, 0xeea5c357, 0x10719e7c, 0x431f80d6, 0x95fb980f, 0xd4df2353, 0x30e245f9, 0xc628b239, 0x35961c97, + 0x4d095b4c, 0x78086aca, 0x57c05fcb, 0x24b8f82a, 0xa9733b02, 0x212a0bb0, 0x7b788913, 0xdc4e0d63, 0xe33f5de8, + 0xd6329f8b, 0x070f8bac, 0xc5f2282a, 0x2257c306, 0x33d41d01, 0x14ee48a1, 0x205a7d5f, 0x6c1c34e8, 0x3ab4ccf3, + 0x480a403c, 0x9c5a5145, 0xa69013ac, 0xb5f9041d, 0xde8a6597, 0xe1e492d4, 0x30d71887, 0xe05b48e4, 0xe65eb443, + 0x243fcbd2, 0x2cb052cf, 0xfd745e1e, 0xd823e1b7, 0x62ad7123, 0xf1b5bcf7, 0x33435981, 0x7283f133, 0xf1cb1fd4, + 0xe25ea7bb, 0xf5e7c9b1, 0x607f3aef, 0x33caa035, 0x241e73e5, 0x299f81cb, 0xd257909a, 0xcf89a258, 0xf4c760ab, + 0x0352597f, 0x1793e020, 0x3b648254, 0x16906255, 0x38d9cdfb, 0x25e94ea3, 0x190d9110, 0x1a5b44fb, 0x405825ef, + 0xd559974a, 0x064c7706, 0x549d9cee, 0x94e5db21, 0x961134bc, 0x0946464b, 0x19914e7c, 0xbc0f1aa9, 0x680e2c0e, + 0xe324719a, 0x4d87fe38, 0x4ede74c7, 0x31061f98, 0xd40a36bc, 0x1b6ecae4, 0x421e69ea, 0xe5cc69dc, 0xda4fdfae, + 0x66e2c0ec, 0xe10d7a20, 0xbd2e9495, 0xd31b4e0a, 0x1e617a7c, 0x1da02c4e, 0xc5de4ad6, 0xd8d5b7ef, 0x52c04635, + 0xf5d28e6b, 0x048074fe, 0xceb13809, 0x2cd6b5e8, 0xa8ec2fb6, 0xa3302db3, 0xd5ed753b, 0xc618ffe5, 0xafb014b9, + 0x7598ae13, 0xe58c96af, 0x2c75f4ca, 0x3a785d17, 0x8c8f082e, 0x4691344f, 0x01b377ab, 0x4c75f4ca, 0xe8550d12, + 0x3a6fd4a6, 0x3a3ede4b, 0x346da1fb, 0x81f7cf96, 0xec628ac7, 0x07d8b9c4, 0xbde393e1, 0x8d36c8a0, 0x831db0cc, + 0xc4bca32f, 0x558a48e0, 0x8efe2553, 0x0038d156, 0xf1607f8e, 0x8eecefee, 0xb1888522, 0x50751932, 0x5e0deb0e, + 0x0b9270b8, 0x3e019797, 0x618e73bf, 0x26e50523, 0x5ab09b20, 0x241031da, 0x46877916, 0x083fb894, 0xed194590, + 0x5101e29b, 0x4dc08d32, 0xd6702a52, 0x153f3b4d, 0xd2e96914, 0xb7617515, 0x1b196e20, 0x302e7d07, 0x19e420af, + 0x32402210, 0xc9587dbf, 0x881573a3, 0x837ee7e5, 0xe8722c43, 0xd9e56bb2, 0xd14623d4, 0x443a7295, 0x975732f0, + 0x37575ea2, 0x2d528d29, 0x150209eb, 0xef7fda67, 0x3495accf, 0x66633fa9, 0x54093bce, 0x6eecc05a, 0x5f03708b, + 0xd4a3e430, 0x225bfdf0, 0x75cafba3, 0xc1cfcfc0, 0xc9db150b, 0x407d9fa9, 0xebc3ecdd, 0xdffc8317, 0x16b489c0, + 0x2b71cd9e, 0x18385caa, 0x88e04d4a, 0x89097873, 0x4432abe2, 0x3563b821, 0x550fab68, 0x48ff9cbb, 0x8a8d1f7b, + 0x835624f6, 0xa8f196d6, 0xb041681b, 0x07df24e5, 0x69a09e0a, 0xfc1d30b7, 0xb632863a, 0x0993292c, 0x8998822b, + 0x7105ce85, 0x9815b9b4, 0xbb4a030d, 0xa7fa2eda, 0x33b20840, 0x25f53b95, 0x004732bc, 0x11c9a5c6, 0x66a2aca6, + 0x16aabffe, 0x888f64cc, 0x46d534df, 0xd073019c, 0xa54675a2, 0x3f69bfed, 0x24aca970, 0x646951fe, 0x1b935d5c, + 0xa027c052, 0x6cfba72c, 0x2c98b42f, 0x4316d856, 0x96f42152, 0x9a0ccfb4, 0x067364d0, 0x9577c90c, 0xc0f3f8a3, + 0xc85b70d9, 0x64e4ed7b, 0x3d456afc, 0x2a3badd3, 0xe4652ca7, 0x5a235b44, 0x57214908, 0x3841e9fb, 0x1cceb139, + 0x5a1ed443, 0xc1165a07, 0xecde9d8e, 0xb8fb997a, 0x8286bb9d, 0x9e2a0939, 0x8472a1f3, 0x752a381b, 0x9ff25aee, + 0xa3f332bb, 0x18521817, 0x497df60d, 0x102a6986, 0x9171c3b7, 0x8a86019f, 0x28a69ba3, 0xc496797b, 0x7960ff49, + 0x264bb1a8, 0x9d0e6574, 0x12dadacf, 0x53f8d6c0, 0x2f85a848, 0x4ab2d7a8, 0xe3ede56a, 0xced022ac, 0xc4429716, + 0xedbe65e6, 0x8f1b804e, 0x124570b8, 0xe8672f5e, 0x634068f7, 0x4d904994, 0x195302d8, 0xa0291251, 0x853f6e61, + 0xbac37ae1, 0x1b500bb5, 0x76a5897e, 0x9da071ee, 0x4a040005, 0xcdf681d4, 0xa2a587c4, 0x0b9a5a09, 0x7e689ee8, + 0xa82e15c0, 0xa945ec3e, 0x5ecff26a, 0x57353ade, 0xaff58907, 0x8dd2b86e, 0xf933c538, 0x7e71996c, 0xb55658c5, + 0x3d5f2c0c, 0x6ac53e4b, 0xf52d3ba2, 0x1e657891, 0xa5ad7cb0, 0x82277e54, 0xf2b4814f, 0xc8075e3d, 0x7ee94432, + 0xe973269d, 0xd5c38379, 0x480c6da0, 0xb4688153, 0xa9317f26, 0x35ee81cf, 0xa461b299, 0xabf150bd, 0x9deaaf11, + 0xa1f2f76b, 0x968d9624, 0x7c16ed66, 0xed6fef97, 0xf4da49d3, 0x98b3f5d7, 0x915bb317, 0xd2cee07b, 0x0fc83776, + 0xab6c7a13, 0xbc8f3d3a, 0xd345e347, 0xa48486f6, 0xe28647e0, 0xc08c0de8, 0xd450301d, 0x9b4ee503, 0xa97ca9ba, + 0x6ceaa9ae, 0x1682d0e1, 0x591e2b74, 0x916cf5ec, 0x6a5ce801, 0x77017ca6, 0x5dd108d2, 0x36256c3a, 0x5fe8aed4, + 0x4f9eee51, 0xfc6fe0d5, 0x82a50b55, 0x7c7bfe8a, 0x2ff1d5a9, 0x961c0a3b, 0xbccf9dd8, 0xfa8490a4, 0x2317bf63, + 0x070f3ab5, 0xa042abc4, 0xe78c3a22, 0x52ba3d56, 0x8d4fbda7, 0x1d99ab7a, 0x7afc0a35, 0x28b9350c, 0x51d141a6, + 0xcfa8d5bf, 0x19bd7658, 0xc8421a2e, 0xd52f629b, 0x000a3411, 0x75d05b37, 0xa795855b, 0x41510cd6, 0x1f40c014, + 0xebea1b77, 0xa0719a9f, 0xb7f8ac90, 0x2050a942, 0x9a788c58, 0xe59c4147, 0xd17fae72, 0xa2cade36, 0x41417be8, + 0x2e7a897c, 0xd748078d, 0x9f5ff033, 0x2ad5160b, 0xb8325581, 0x1c4ae855, 0x3fdb5e52, 0xfd3d4b55, 0xbb374a8d, + 0x770a70bd, 0xd0c323fc, 0x2659e977, 0x7a2e4462, 0x09a2da74, 0x7cec044a, 0x83cf2f71, 0x3b6b65db, 0xd46d028c, + 0x6eda59cc, 0x950fda95, 0x39977ac8, 0xce6cf805, 0xbc19713a, 0xdeba41d9, 0xc87e0ada, 0xfc010f11, 0x2c57a837, + 0xc4875009, 0x3c6afce7, 0x1e2f50fe, 0xf9dd1c1e, 0x60408002, 0x4feb748a, 0xa2226c66, 0xb74e2530, 0x86253ef2, + 0xe4f32e3b, 0x9d4eef04, 0xbfc6fe7a, 0x321dba39, 0x72efde7b, 0x9c1227a0, 0xe89c9523, 0xdb38508d, 0x29993977, + 0xb62ddb22, 0x77e5c449, 0x12a6e863, 0x7893bf56, 0x6f6cf001, 0x5b7388ed, 0x669274ec, 0x709d50df, 0x6c4b9731, + 0x78a4f40b, 0x027393de, 0xafe29341, 0x71085474, 0x89b1c4b2, 0xd43eccff, 0x4a538780, 0x35f1427a, 0xf96a033c, + 0xab0b5ca1, 0xaebb97c4, 0xba03b95f, 0x55ee3e96, 0x3dd1737e, 0xf41ce965, 0xb078a8a6, 0x63b5810b, 0xe95652a4, + 0x0ea041c3, 0xfcc9193c, 0x6e9b1cee, 0xd0928f65, 0x6c600986, 0xc705c24b, 0x839a5f44, 0x165fb3df, 0x57146b4c, + 0x85b0a574, 0x8f423fbd, 0x6d0831f3, 0xf5cf59b2, 0x75c01a40, 0x4a617ce4, 0xb5b77010, 0x6364f4ec, 0xa824452a, + 0xb1792a97, 0x33fa91df, 0x863f8e96, 0xaded72c6, 0x9695267c, 0xccf90782, 0xcf09e197, 0x8e3869b1, 0xb549905e, + 0x1711395c, 0x6e1d0e2f, 0x98958e5a, 0x40911c24, 0x0bb0f066, 0x13927b0b, 0x1a0fb240, 0xd6f92d54, 0x53d7804e, + 0x8dbc60c1, 0x98f7b1a4, 0x07e5e6b0, 0xaf1dbe4c, 0xba68553b, 0x5293366a, 0x786bedc2, 0x311cb7e9, 0xb6462af8, + 0xdfd00181, 0x6e553901, 0x8af45841, 0x70a8475a, 0xd1b3938f, 0x96622c10, 0x4603a087, 0x12686935, 0xab225999, + 0x8d9f1e2d, 0x57d72910, 0x52cd20fa, 0x01571c69, 0xc6abbf29, 0x074e3a9e, 0x94dc2f66, 0x1b413c21, 0x716f7712, + 0xb9b233db, 0xa2d51209, 0x85da319d, 0xaa92cb9b, 0xff02bbf0, 0xb269ff9e, 0x42bbc348, 0xeb1618e5, 0xf9ec39d0, + 0xbf396ed7, 0xf4bd66be, 0x9a8bcfaa, 0x05ca193f, 0xd2013a04, 0x19199b30, 0x201047cd, 0x7bb5fd18, 0xc738f6d6, + 0x838a0588, 0xb8a7c133, 0xfa50e965, 0xedc1b5b5, 0xe5b560c5, 0xc96696ec, 0xef91f906, 0x88815f01, 0xa41832cd, + 0xc8014122, 0xdfcdc17c, 0xd24ca5b4, 0x7e7b01ba, 0xada5c785, 0xf5c65d08, 0x0a010c71, 0x1d2a73ef, 0x2204db09, + 0xc47d2594, 0x3d4c601a, 0xc7ead538, 0xe4e8e8d8, 0xc79ca9c4, 0x574bffe0, 0xabf93c14, 0x6baf0b87, 0x63871520, + 0x9a1a23e0, 0x8061c6ee, 0xecc95e93, 0x72cb4bb3, 0xdd828222, 0x5f4ac9f3, 0xa62f6821, 0x054a9ca2, 0xfef102da, + 0x8af7a723, 0x03d4a183, 0x39da1b47, 0x04ec32df, 0x9db123d0, 0xd241f7a5, 0x213e1433, 0x0c68758d, 0x893341dc, + 0xe955406a, 0xff5676f8, 0x7d37ff30, 0xf0e6500b, 0x10caa677, 0xf42c9627, 0x22a49eee, 0x764859a4, 0x3fa671c9, + 0x394b83e1, 0x71823194, 0xbea05ec0, 0xa23512f9, 0x7dc99f55, 0xed591476, 0x9a125377, 0x542843fb, 0x20c5f7bf, + 0x0c7c44d7, 0x12fa20b8, 0xcb306d1a, 0x8b8decd0, 0x8e7e87b3, 0x49391889, 0x7bae0247, 0x00a05aec, 0x83246358, + 0x63ad52f0, 0x1608fc6e, 0xa34820e5, 0xe4019070, 0xda24d9b5, 0x91e1b7bb, 0xa36221a6, 0x6d39c72b, 0x236d2f29, + 0x7e13ca88, 0x367e9517, 0xa672eb3b, 0xf53267c7, 0xbd3fefe0, 0xe53e97d8, 0x07f352aa, 0x4d80901d, 0x492dd6af, + 0x9ed29a73, 0xff49f2d6, 0xe5fafc36, 0x4e75786d, 0xe9fbe57b, 0xf20b4a8e, 0x3992f4c6, 0x348a4c17, 0xa4b8c3f5, + 0x70775e72, 0x6666a0a3, 0x9c4ad813, 0xbde5f638, 0xeb509458, 0x7d68db56, 0xd51b24ca, 0x93d6eb01, 0xe813d1c0, + 0x37810301, 0xb8ec3699, 0x0f2f07fc, 0x1f786de9, 0x066d1f59, 0x4f3a4fba, 0x4b6fb00d, 0x85794d1e, 0xdd3fc9c6, + 0xd865f0f4, 0x5393fc47, 0x2bbda5c8, 0x5045e671, 0xe04c426b, 0x0ed86b7d, 0x6b509270, 0x710368d8, 0x69e9fe59, + 0x1f4caaca, 0xfd33ffa6, 0x8463d492, 0xfd94875d, 0xd130611f, 0xbfb00bee, 0xbef27a6a, 0xa5221aa0, 0x06f8df27, + 0x3bfab35f, 0x314c2376, 0x951affe3, 0xd0485d58, 0x2984ce84, 0xdfd72fd8, 0xc7097fc5, 0xb8d4b6b6, 0xeec08694, + 0xce9b866f, 0x0c1418fb, 0x43683c77, 0x2e55f51c, 0x2b9146b2, 0xaeff4ebc, 0xb4411e03, 0x221cb89c, 0x1bf64f6a, + 0x5de0a981, 0xa4f2d42b, 0xd2c6f9a9, 0x3fbd346c, 0x9fbd0274, 0xd3bb6382, 0x3ba2a9b9, 0x5e703ca0, 0x5eeb8830, + 0x78291219, 0xccc2efa3, 0x25e8ed83, 0x9a0840f4, 0xcc4fe8dd, 0x25f7bec6, 0xc0bdd524, 0xb91ee7c6, 0xcadcd084, + 0x72f378c4, 0x02dc474c, 0x8127e7a8, 0xeb930d22, 0x7c670da5, 0x1a40695d, 0xb8970665, 0xeb767825, 0x7f4a2737, + 0xd729a735, 0xdb21fd28, 0x3f52cc06, 0xe60c5a9e, 0x59dfb251, 0xdaabfc9b, 0x7dc41896, 0x3d752d29, 0xd1ad0f02, + 0x0edad926, 0x6188c8a1, 0x4f809b09, 0xc7acd439, 0xfc9f8047, 0x00807a7c, 0x2cbace5e, 0x8ad634fd, 0x5f23f118, + 0x2275f71a, 0x37fc8fcb, 0x57155119, 0x2e9b1a48, 0x41943b26, 0x518b3746, 0x8617e6e7, 0x89388fd7, 0x3b15debf, + 0x89df96ae, 0xc7af6a4f, 0xe49bde37, 0xb9cf943e, 0x382e7c9f, 0xcef42399, 0x45fbbe68, 0xbf0249ff, 0x2e8ae5dd, + 0x5f12c263, 0x97db50b9, 0x330e682f, 0x8cb2ac02, 0x4b2746e4, 0x80858d04, 0x3c930d5b, 0xa36a380e, 0xe2b9f16e, + 0x618ab426, 0x02249b41, 0xcbd18ecd, 0xff3aa629, 0x74d1856f, 0x4420b21c, 0x47dfa9b6, 0xfd5b5772, 0xc73ff967, + 0x3334f862, 0x1480dcf1, 0xd6938291, 0x3925fdba, 0x426e8b02, 0xd671b269, 0x4c3b0a01, 0x4444257e, 0x865fa6d5, + 0x4b628d72, 0x7d628f39, 0x09c382e7, 0x6e714369, 0x1fd51a22, 0x742f1d9c, 0x447a6279, 0x15ed76ea, 0x0a95aa8b, + 0x54b3826c, 0xcaedbb1b, 0x6250a154, 0xafd1a416, 0x9110e078, 0x9d41c98a, 0x9c7a9148, 0xc32d6c3c, 0xf22de590, + 0xa1c5a21e, 0xec9a6958, 0x488c200f, 0x048cd011, 0xb49371d8, 0x0a0566fb, 0xba1939cf, 0xc298853c, 0x3a0f7663, + 0x304d0fb7, 0x4471f76e, 0x459b53e3, 0x68411f22, 0x49070f39, 0x545b5a94, 0x3af7a99c, 0x89084c41, 0x6041f723, + 0x8b52a88e, 0xeb185745, 0x7ecebdb4, 0x61cba4f3, 0x244a8521, 0xc1c8f88a, 0xc3004d2b, 0x84795433, 0xd36f94d9, + 0x68d31d22, 0x6acc0295, 0xcca19df0, 0xfc12bcb9, 0x88c66f19, 0xcdc02b9a, 0x71a560ce, 0x599bdd3d, 0x75f6e064, + 0xcac70003, 0x4c11fee4, 0xb6c48d0c, 0x2357a8c9, 0xd6d5dd96, 0x2ba04a0c, 0xc57996d9, 0x79ccef92, 0x515868ff, + 0x8c5257a8, 0x1e974475, 0xbca63369, 0x570a947f, 0x91d9c254, 0xd5806f82, 0x6b9bc238, 0xa915dd57, 0x756ee2ac, + 0x2f43c749, 0x7de983c8, 0x6d691e2b, 0xe7f7f31c, 0xcf397e19, 0xa9557354, 0xe1390978, 0xc3690464, 0x6244973e, + 0xaf440ec6, 0x4664a17a, 0xd6008c97, 0xe2ca7758, 0x3fff6b4a, 0xff14dc31, 0x6c2163ce, 0xabf3881c, 0x6df57d3b, + 0x80d334c0, 0xf436d8f2, 0xe7d6e460, 0xea192e2f, 0xbe7af855, 0xd4bc0abe, 0x07b79cde, 0x9ea72363, 0x0664806b, + 0x1c721f64, 0x2dd4ff65, 0x66c05fb8, 0xc8fdf8f1, 0xeab71ef3, 0xbaad1e60, 0x01583ee8, 0xc6ef63fd, 0xe8125e0a, + 0xbf247a64, 0x904eea1d, 0x66c958c5, 0x003b47a9, 0xb027a732, 0xa9d2648f, 0x26e7801e, 0xf261d20b, 0xfc376c55, + 0x7fc67024, 0x1ab337d1, 0x065e3404, 0x8d1abb37, 0xac480734, 0xa8604e78, 0xf3692cab, 0x01963bfc, 0x8e2b8ed1, + 0x748dd6ae, 0x0aadb63d, 0x0cd76f7d, 0x37afed2a, 0xf3125b98, 0xb71d07b8, 0x6e80cff4, 0xe8b9b466, 0x574d21b8, + 0x820d43f5, 0x3fdd2e00, 0x98fbac7b, 0x3d1d90c0, 0x19ac4384, 0x74152ac8, 0xbf46ea65, 0xa120dd4d, 0x11856c6a, + 0xc91c97db, 0xf1fef111, 0x723c62d7, 0x4bcdd999, 0xb1e95435, 0x2f9a5e15, 0xea928443, 0xc5f00223, 0x3c9112a6, + 0x54a21957, 0x1f1e2514, 0x864e12c2, 0xb24a9cf4, 0x7f47771a, 0x78ba4a4c, 0x773c760c, 0x068a0c5b, 0x2f89bab9, + 0x777cb51f, 0xb003fffc, 0xe4839650, 0xaddcfc19, 0x0389c6e1, 0x6dbb1b21, 0x84ab0d23, 0x415803fb, 0xd824da7d, + 0xc9f65ad7, 0xf2f10d1e, 0xce95f279, 0x764078fc, 0xcc7bba83, 0xad04a6de, 0xbc3bdd1a, 0x9dbe8bbc, 0x79c898cf, + 0x32fa2778, 0xcf82c572, 0x4caaa083, 0xc0ef7c75, 0xbe810f26, 0x8ad739a1, 0xc0b3409d, 0xeed28db2, 0x800b92cf, + 0xc334cdfd, 0xb6d354f4, 0xf1305c75, 0x8ab6f6e9, 0xd2242ec6, 0xb537e577, 0xd02fe587, 0xe0fc56c5, 0xbfc2ab9c, + 0x4cd819a9, 0xff7bda27, 0x08e9ef14, 0x30797e64, 0xe31d3524, 0x8979b375, 0x6a371661, 0x0e53cb6d, 0xd5a2279c, + 0x5ed1f3f1, 0x9c4ff3fc, 0xdce8af4a, 0x04fb79a8, 0x6a4717e7, 0x0474ee04, 0x410efede, 0x0b2d45f2, 0x447fdbdc, + 0x4bf2c561, 0x452b37f3, 0x348741b1, 0x2cdaca38, 0x50fc2da1, 0xa681d0fa, 0xa06887a8, 0x133f8c46, 0xf6e8af2a, + 0xfe5147f4, 0x99ce2675, 0xd6897483, 0xd4c1694f, 0x6e3f5a7f, 0xffafbc12, 0x4a1da34f, 0x727ba7e1, 0x75945c92, + 0x1f50a157, 0x72f12bcf, 0x1cdbdfd9, 0x76475c5f, 0xa0491ba1, 0xc55aad00, 0x28a35860, 0x11e195fc, 0x3fb644d7, + 0x5fcf8925, 0xcd1844f7, 0xa0b17207, 0xab6420a2, 0x8cfcfb65, 0xb687c9e7, 0x7cb7942e, 0x0c5dc405, 0x7a24e6cf, + 0x88baa105, 0x65027d7a, 0x95483d23, 0x1b4e0ba3, 0x53f778d3, 0x84be332c, 0x32eed212, 0xf5f21681, 0x8f6b16a7, + 0xd594b2ea, 0xdef61783, 0x20205dca, 0x79e56ca2, 0x78d1be6c, 0x3fc766a2, 0xe554bb37, 0x75d86900, 0x4d4a4fbb, + 0x00a762df, 0xdb245f0f, 0xb5f51ddb, 0xb38220e8, 0x3ecfdb77, 0xbc80e6bc, 0xae6bbf91, 0x5a1dd126, 0xc4d97449, + 0xa5aa112a, 0xa3db5ded, 0xd52a7f23, 0x00190917, 0x433dd6cc, 0xe44fcd49, 0xaae906e0, 0x7cf6f4b2, 0x6718f903, + 0x4c2f354a, 0x2238d9c9, 0x82714943, 0x8c8fb679, 0x016f1742, 0xa484f4a0, 0xa0c2d54a, 0xb52476ba, 0xda427252, + 0x1bbe0145, 0xdbc700f5, 0x8381721b, 0x5b0da404, 0x1fa47418, 0xd69ba562, 0x40bd4041, 0xae7a70f5, 0x63cdc7ee, + 0x9d2fc9eb, 0x463be839, 0xcb671af3, 0x499f9db1, 0x86ffb47d, 0xa1dddc9c, 0x8d8c8d66, 0x966af3c4, 0x7abc905e, + 0x6a11f4b5, 0xa268bd0c, 0x2c4540fe, 0xc9a746e9, 0x78ae48b3, 0xb61a63a6, 0x6874eb60, 0x519fe7d4, 0x583fd619, + 0x046d806a, 0x2e2f964a, 0xfc77d2b6, 0xc5696c42, 0x544482d0, 0xaf4d7ac2, 0xb079df2d, 0x0e2ff9d6, 0x3c299021, + 0x17e67c5a, 0xc9cb2cca, 0xb0877903, 0xcfb9fd8a, 0xa5125f6e, 0x1ac8bc52, 0x03fb8a2b, 0xe8db5b72, 0x2906b0aa, + 0xea1356a4, 0xe552a577, 0xd5a826c9, 0x72437a9d, 0x40df08fc, 0x473d44e3, 0x7999c14f, 0x3e6eb61d, 0x1dd59255, + 0x153586ee, 0x8e52ef3d, 0x6b879c15, 0x68044c6c, 0x18b9a6e2, 0xa46c783d, 0xdf557db5, 0xfa1e2532, 0xdc0901ec, + 0x869b2e6d, 0x5bd465f5, 0xaebfa9fd, 0x9f2f24c3, 0x17df0220, 0x737bc7e8, 0x5bbacd0e, 0x94abdaff, 0x264099fd, + 0x71d7813e, 0x026e81f0, 0x5bf65ae7, 0x9ec7630d, 0xb5beea33, 0x033d6119, 0xceff0c73, 0xd882f43e, 0x4af039e9, + 0x36649e6e, 0x6df3da33, 0x2d309459, 0xb0ae5aa0, 0x321c28db, 0xf752b3dc, 0x06bd2c0f, 0x325ae487, 0x399ccb8a, + 0x134366d7, 0xa9846fc6, 0xb861e244, 0x845eaec3, 0x1f474a89, 0xa7cee284, 0xf1b8bd31, 0x91d323d1, 0xe83ef38a, + 0xeb55a617, 0x34f45f1d, 0x0e6cfb99, 0xe8f6e50d, 0x17374bd4, 0x695452e1, 0x7c8da230, 0xbc782642, 0x26615c91, + 0x176a055a, 0x36999734, 0xbd652ea3, 0x434cdf04, 0x21df2698, 0x3e1d2beb, 0x76b47bbc, 0xf0539d2a, 0xea226178, + 0x135acba5, 0xe84efe7d, 0x42fc1be1, 0x246d6d62, 0x16af09c1, 0x9634d175, 0xac2a5357, 0xd5f5f238, 0x63ed9afc, + 0x2ad5bafc, 0xbc22b4ea, 0xa5906ac3, 0x3d78e717, 0xee331aab, 0x6795b011, 0xee8b1bd9, 0x14b82750, 0x59c0af6b, + 0xe93926ae, 0x368cae62, 0x36a2edf6, 0x142c5fa1, 0x1a2be46b, 0xbb62b224, 0x4468971b, 0x33c5d731, 0xe4d1f902, + 0x452c4507, 0xb6d1c02f, 0x56e8aa9b, 0xa0abe2f4, 0xe87a4190, 0x011e5dc6, 0xa2780059, 0x8c72fa06, 0x10522619, + 0xff9519d3, 0xd27f802f, 0x82154ba7, 0xcfa00dbd, 0xb9d6c36a, 0xccc99fe5, 0x57aa8b05, 0x263bca8a, 0xc0b10ee6, + 0xb9e0ae83, 0xefca3a32, 0x3255ceaa, 0x54bf5c11, 0x6d9fe506, 0xc9961b74, 0xd458e41b, 0x244be784, 0xe0c61e2c, + 0x0cae436f, 0xd5b7571d, 0x62d79efe, 0x916e4e7c, 0xce248a3b, 0xc8901646, 0x2fa64889, 0xd3e4ab74, 0x52926ad9, + 0xa3c21ec8, 0x9c373525, 0xafc5405c, 0xd3918b71, 0x176104c1, 0x61e49cad, 0x8b1dfbfa, 0x9effafc3, 0x69145803, + 0xb58fd42b, 0x1df6c509, 0xee25ab28, 0x4a3d005a, 0x8cbb6b80, 0xe3386f59, 0x98605130, 0x3b748546, 0x6d68b1d9, + 0xe27a18f9, 0x15d90d39, 0x61cce1be, 0xe69548ed, 0x9ce29b4f, 0xc3de1c6f, 0x22eb2607, 0x4c4cdaf0, 0x001d9b68, + 0x9c044861, 0x7816e4d7, 0x0e57c738, 0x5a51d329, 0xf731d75d, 0x565f4686, 0x95ee0890, 0x604f63f9, 0xd77587c1, + 0x5caf9748, 0x64a74ce3, 0x5ae858c6, 0x35e921b6, 0x54fe8d06, 0xb5b41542, 0x286d4013, 0x6006e319, 0xac8150d0, + 0xe5c2e648, 0x4d5f4408, 0xeb19e443, 0x81178631, 0xe8c8e34d, 0xb6c8b291, 0x85dcde1b, 0xb388b554, 0x7eb9fac6, + 0xc127f3ec, 0x9a4cc33e, 0x8922ce5c, 0xe6d3d8fd, 0x93ddef2d, 0xb594941b, 0x76e32865, 0x1ce5c9cc, 0xe159997d, + 0xdc914a0b, 0xcd0c193c, 0xf99befed, 0x50b6196f, 0xce33c424, 0x09a75641, 0xceb4acc7, 0xff57002c, 0xb0e57e1c, + 0x40546b4f, 0x61a4d43b, 0x56a918f5, 0xbc5cfed6, 0x9b5bd813, 0xcaede8c2, 0xedc5d5e6, 0x61ac8e2a, 0xe6af1916, + 0x73a8cf78, 0x6fcb57db, 0xd44d83d9, 0x6da04ead, 0xbe8a17b3, 0xa8c38ce8, 0x86af84b5, 0x890621ec, 0xdbe97ab0, + 0x396b39e4, 0xd1437f64, 0xd7e65196, 0xfc90cd4b, 0x27c5e62f, 0xe5b8e50f, 0x02a2e2af, 0xb226c34d, 0x7107c314, + 0x3a9c7bf8, 0x4a6d8092, 0xd399c9d2, 0xf5fba5eb, 0xb81b8142, 0x38fa3ff8, 0xfa76150b, 0x7e046d1b, 0x3c241344, + 0x4d365353, 0x26421605, 0x5c44cfe0, 0xaaa6919b, 0x226a2c64, 0xade3348b, 0x3505bda5, 0x9c4a672a, 0xc3ece42f, + 0xf369e025, 0x0ad24c82, 0x406a7063, 0x5a1a8aa0, 0xae0ae509, 0xc765b2eb, 0x84ab9ca5, 0x9ea359b4, 0x18f813d8, + 0x181f99c1, 0x67f22493, 0xc71a50bc, 0x209ccc31, 0x245b6ea6, 0x74f84c08, 0x4d58c8ed, 0x6d77d484, 0x298331bd, + 0xa26b7732, 0x81c3eac2, 0x7d549421, 0x9c4b76ad, 0xe813d84b, 0xb9b58b6c, 0xe912c152, 0xc046afd4, 0x7ebebe8b, + 0x3ed6bd7d, 0x6276354a, 0xcf7b28b5, 0x4ee94fb1, 0xd15517c4, 0x6ec36b4b, 0x45e61849, 0x51405aa2, 0xc37a394d, + 0x9bf970de, 0x4a92728f, 0x726064d5, 0xef2c19f1, 0x9612ba11, 0xafc59fb2, 0x224ae7db, 0x6c646ef4, 0xef66e6da, + 0x44afca54, 0x0bbee791, 0x2f0b2967, 0x6ced4cb2, 0xa76478e2, 0x0fe20e76, 0x9acdb446, 0xb746e67e, 0x49e54124, + 0x203cd97e, 0x565ecbf3, 0x6ab44b0f, 0xe0537d37, 0xf8c39a0e, 0x863eb4ff, 0xbc413607, 0xfcc87199, 0xc3b69ba3, + 0x19c3f7d0, 0x6704fb05, 0x60d1ca86, 0x940a6fd4, 0x6087732d, 0x7806f663, 0x08c1d2e3, 0x70278d2c, 0x65dbd740, + 0xd1b141c3, 0x0a4e67d5, 0x84bb60e4, 0x94b8d544, 0x4e74dec4, 0xf355fb55, 0x80ffc2e8, 0x797a1a54, 0x16ce0023, + 0xae11d9b6, 0x8a78b0bb, 0x928184c3, 0x7ca45cab, 0x3a38550b, 0x671becd5, 0xdfb72cc7, 0x155bd14b, 0x3ae3708a, + 0x438e8b60, 0xc02fc8ba, 0x65167bc9, 0x9aa139c2, 0xb927b49e, 0xb4ba59dc, 0x1a804a3b, 0xbcc73611, 0x07ab5d7a, + 0x2a2d82e3, 0x706f2744, 0xb507a697, 0x2a1fc2e5, 0x2d039958, 0x871b0f25, 0x4f2f98d4, 0x3929af56, 0x04cd19c1, + 0x2d05631e, 0xa71e0149, 0x7cd7f1c6, 0x5af7ff03, 0xb5a29b1d, 0x0ead37bf, 0x83dc73d5, 0xfc938f1b, 0x4c7cd620, + 0xd9717c4c, 0x1ee13f8c, 0x668e2f93, 0x60e9d48c, 0xfd7bf7d7, 0x3589fce0, 0xfc04639e, 0x0bb8d187, 0xe68b8857, + 0xeaff80aa, 0xd5fcb22f, 0x0427c8ef, 0xfd57eeb1, 0xe13c537a, 0x36b8d835, 0x5366cf4d, 0x4b8c2f53, 0x49faade7, + 0x6cfb3085, 0xc31b7cfc, 0x31efebee, 0xf955eada, 0x873baa46, 0xe83a4fc1, 0x48c0cccc, 0x96d47216, 0x876a365c, + 0x9f49d03c, 0x1de4c6b6, 0x060e5041, 0x5dbdbd3a, 0xf7a60a45, 0x079da6f5, 0xfd4e2369, 0x7fdcaa57, 0x9860ed51, + 0xe83bcc5a, 0xe11006a9, 0xba54e55f, 0xb6eca477, 0x3fb0900f, 0x646794ff, 0xaadb2730, 0xbfb3eb71, 0x4db51b1a, + 0xe65f642c, 0xe27dc13d, 0x26c25599, 0x4468c736, 0xd73bdb13, 0x4bebb7c8, 0x03af0b52, 0xa160eb0f, 0x8628fa4d, + 0xf30fb609, 0xda396845, 0x35c44eb9, 0x748c3344, 0x6b81cb92, 0x034fe277, 0x6c10e23c, 0x372b24a7, 0xab9d9a49, + 0xb1a776c2, 0x82ba375c, 0xc25e8332, 0xb00ba478, 0x849d8457, 0xdee7c51e, 0xb5819e50, 0x04a74804, 0xf1c7e08c, + 0x1aa5181b, 0x9ffe13e0, 0x80663ad4, 0x9a03b21d, 0xc11af956, 0x5d7d1c61, 0xe94544d5, 0x30c471ac, 0x29190cdd, + 0x8b0263cb, 0xa1d8e66a, 0x3036d43a, 0x6b08a2e5, 0xea18325d, 0xe4877fa0, 0x0a560873, 0x9225afd9, 0x149f2815, + 0xeabdd861, 0xc6b94aca, 0x1c2aee9a, 0x1489015b, 0xd9111b8f, 0x91a33289, 0x16d966bd, 0x35d4f368, 0x25adca9b, + 0x1cbde0c7, 0x3468cd98, 0x707f2823, 0xca940c56, 0x31563003, 0xbba0e036, 0xcdd6632a, 0x81539681, 0x2be29405, + 0xb9b173b5, 0x9e770827, 0x07328b95, 0x2f1e572d, 0x9836af48, 0x65c03e00, 0xa64de6b8, 0x9b50e535, 0xb4444f77, + 0xed349588, 0xc08c4195, 0x4b6aa269, 0x76c42958, 0x6d484f66, 0x5b11aff1, 0x46a0cd5c, 0x883ca511, 0x0174f429, + 0xf92434c8, 0x1a02c26b, 0xbad24c68, 0x30d13daf, 0x8de5f824, 0xb8f7461b, 0xfa7cba41, 0x913c2f11, 0x81cd7fe9, + 0x058d1a3d, 0x984f52ea, 0x2357ca54, 0x83e30462, 0xae22763b, 0xe030ef32, 0xa4898aa6, 0xecb0f4aa, 0xd491b02f, + 0x3e388bc6, 0x73710f07, 0x243d7fa9, 0x2e4ef084, 0x02b35181, 0xf866e084, 0x7b6c0986, 0x63612d73, 0xa4bc1832, + 0xa95fc77c, 0xd098546e, 0xaa4414e5, 0x8fcfe7f6, 0x8d35a453, 0x66800578, 0xf9108074, 0xbf43a311, 0xc02f12a4, + 0xdc88b063, 0xc7ac0dac, 0x95a8eddd, 0xe1c267ea, 0xf71ef85d, 0x83fbd812, 0xf5666959, 0x58a1288e, 0xf39e0d77, + 0x2aceec56, 0x7bce0f15, 0x879889e4, 0xe2240605, 0x4a4c2bfc, 0x7e146886, 0xedfaba90, 0x3d4cb861, 0x55c4d5a1, + 0x7263e089, 0x937c71fc, 0x12cb3a7a, 0x80b9df21, 0x981b039b, 0x5ee9238c, 0x04ae32c5, 0x5218f402, 0x30f33d95, + 0xbc4f58bb, 0x7030fc69, 0xd1914b8c, 0x87be2c58, 0x841a8a91, 0x7d245d68, 0xa121ee39, 0xab73fed3, 0x31d52af1, + 0x3fe177e1, 0x889ed816, 0xa042f44c, 0xdb48029c, 0x26cae80b, 0x42803a27, 0x76b1d663, 0x8655648d, 0xd8aa0858, + 0x49604e37, 0x5aba0253, 0x012c2d1f, 0x8d7ddf2a, 0xf2172a4f, 0x1d08ea34, 0x1087e9f7, 0x0a84d10d, 0x3bcd19d9, + 0xa574e2a6, 0x69a4b077, 0x25c66dbd, 0xa5c2edf9, 0x75974fac, 0x5e6f41d8, 0x8fdbc2fb, 0x184e5b85, 0xcbaacb94, + 0xa371e7e8, 0x4533c05b, 0xe435e36b, 0x091f86fe, 0xe4e0543f, 0xc3f92162, 0x17d9136d, 0xcd91d5eb, 0x061d569c, + 0x01024be4, 0x6b2f6d87, 0xd75f4efb, 0x985ccd47, 0x1becdbfb, 0x9944df09, 0x5ed6af57, 0xfe4144cc, 0x575864cf, + 0x48d658cc, 0xbb4372d6, 0xd7bd0d79, 0x6b89c1e2, 0x488351e0, 0x1e4a677b, 0x3f0fecee, 0x38384010, 0x8ec359d8, + 0x84b6c6c5, 0x4d6ef0b6, 0xcf98aad4, 0x37c631fe, 0x63642742, 0x74ca90e6, 0xc64b2967, 0x978436e7, 0x38ed1aea, + 0x4878839d, 0x4842ff2c, 0xaf76db8e, 0xb0e5147d, 0xb3d7c2a5, 0xb830250f, 0x1699b954, 0xb8ba2ce9, 0xaa9f27c0, + 0x42f43ba6, 0x8fbffc80, 0x872a0467, 0xcd3b47d1, 0xfd153904, 0xd531d2b4, 0xdc206445, 0x604f9fe0, 0xf104c05d, + 0x05c238a3, 0xceffd7ae, 0x9b6ce08b, 0xa6e48b0d, 0x88c31f0e, 0x36dc556e, 0x1cf6f65e, 0x20e031f6, 0x699b5a2e, + 0xe98a6d67, 0x7ae8b101, 0xb87937da, 0x9e29500a, 0xc0da7e84, 0x4f19a4cd, 0xe52ac0e3, 0xb4da4f35, 0x54d17209, + 0x3580d2d7, 0x76c0d19a, 0x0cbcfb5f, 0x71340e72, 0x4809d5d2, 0xd93496ed, 0x7f456a81, 0x7846289d, 0x1796d803, + 0xf61a212b, 0x469a0695, 0x23af1646, 0xddecbd39, 0x87d90adf, 0x6a0c11c8, 0xb1aad413, 0xa5d2fe7b, 0x8af66fa5, + 0xfa31cc8d, 0x02161311, 0x24f2fcd6, 0x562c2709, 0x16c43905, 0x9d6f008c, 0x0a807913, 0xb7471e1f, 0x85736113, + 0xc8c3f610, 0xb084d5dd, 0xf474e211, 0xf6fdfe15, 0x74b79357, 0xae597aee, 0xf11f93b6, 0xa83be799, 0x5d21143d, + 0xfca2549a, 0x006d9905, 0x9eb59bc9, 0x2b109f9c, 0xb35cfa65, 0x10ab91ff, 0xf12afd22, 0x5c37b05f, 0x1c8e75d8, + 0x62112c12, 0x48f5fc10, 0xe88397da, 0xd4d4aa99, 0x9075c9dd, 0xd5f18f16, 0xa3e09125, 0x740dc093, 0x77922523, + 0xc760c768, 0x25dc91db, 0x5c4c2908, 0xdced0ab7, 0x311e0361, 0xc81722cd, 0x9118014f, 0xe769e54e, 0x53c478c4, + 0x5d1398bb, 0x5d68b6ac, 0xb07674a5, 0x1a991272, 0x7c5ece2d, 0xda38b93d, 0xb1fd08d4, 0x8d1b6994, 0x526d4d74, + 0xeb84c80c, 0xad2d4772, 0x3f7ae3a7, 0x5797ae5f, 0x5dd1dbbc, 0x752f0da8, 0xe7473f25, 0x97377dc4, 0x19094083, + 0x32694e43, 0xfbbf8f23, 0xc5fbdb8d, 0x4ce1f8cb, 0xc506e465, 0x49a24e16, 0xe7e4191b, 0x8a755daa, 0x19582865, + 0xe0749ade, 0x19a44027, 0xd796989f, 0x9ac75606, 0x93a9e148, 0x1ce32d85, 0x868e0371, 0xc44d7c4d, 0x715faaac, + 0x772dc27d, 0xfa5a059e, 0xffed114c, 0x268ab0d9, 0xddd33bb6, 0x2145060f, 0x37c41f8a, 0x1168a04d, 0x49f58999, + 0x9c6ef167, 0xe4a13ffc, 0xfea71e46, 0x53c8510c, 0x02a74502, 0x08607bbf, 0x39f8456a, 0xd69a6fe5, 0x7bc4b879, + 0x8dd06abb, 0x0cf29480, 0x300d6774, 0xbf8d96f6, 0x96473bb5, 0x3c90a048, 0xfb37986f, 0xc5a00c2e, 0x2a05e297, + 0x274a92ba, 0x354b379c, 0x9f9db554, 0x2f72ccb6, 0x0058cdc9, 0xa1a1c38d, 0x3e37b6f7, 0x79a2d228, 0x4f2369e9, + 0x86258f26, 0x9a9c6820, 0xeb69f856, 0xa9298812, 0xce4012f0, 0x9aded287, 0xf85529f3, 0x8af89dda, 0x00a6ba0e, + 0xf9562fcf, 0xd2a48e3c, 0x77d734f3, 0x323dc4ad, 0xbdb24bfa, 0x0ce6c798, 0xfd9d8a43, 0x21d9811b, 0x6e17278a, + 0xb5ef616e, 0x73e423b5, 0xae74a04b, 0x0846dfd4, 0x56f0d929, 0xc7a521e1, 0xd0027487, 0xd5843a70, 0xc27dde61, + 0x2396d9d0, 0x308f0bb5, 0x880515a5, 0x5cdcb629, 0x2fa4c630, 0x5df86719, 0xf5a4811b, 0x1773eb07, 0xffce6253, + 0x7f48f8fa, 0xaa488c1b, 0x87e4923b, 0xecb34e8f, 0x0640d799, 0xb64323c1, 0x9169090b, 0x67ff6068, 0x30527bf5, + 0x3ce34a81, 0xcbbdb0cb, 0xac293d64, 0x913e7111, 0x8bbcc80d, 0x460c6d1f, 0xd960fcfb, 0xb04cbfde, 0x825a65b9, + 0x11fbdde9, 0xcc2b7fa6, 0xfcfb0dd9, 0x324a286f, 0xca16a16a, 0xdb0b3091, 0x6685ff1e, 0xfb88d5ad, 0x8babbead, + 0xfd2a20c7, 0x3adee043, 0x566980b9, 0xbaa80b48, 0x5c75e5a4, 0xa093c906, 0xbac7a3a5, 0xd3f89f9f, 0xfbfcea1e, + 0x8d0c8a0d, 0xbd5552b6, 0xbeb3c8cc, 0x6d577bea, 0xc0d992af, 0x8d633eee, 0xed91eb55, 0xecf7bc04, 0xaf789dbb, + 0xe97d07a3, 0x2c52ac7e, 0x4a5e4888, 0xe2853b2f, 0x6416cead, 0x0c2ed4e7, 0xac27977c, 0x1995109a, 0x47d94907, + 0x03c136fc, 0xb3bb2078, 0x46544150, 0xd7ff0d67, 0x33378ead, 0xe40c8705, 0x18856aa0, 0xd1a96af9, 0x43869fa1, + 0x3ef06176, 0x9b83049d, 0x868ffbae, 0x6e4499b1, 0x94809708, 0xb2863963, 0xa8e30318, 0xc2da130a, 0xbd0fbe6d, + 0x0dc94c94, 0x37803aa3, 0xda6b4197, 0xe7306404, 0x7b795ff9, 0xa48c21e5, 0x884d22b3, 0xe9761bc9, 0x00fbd5ff, + 0x20e61060, 0xe0161322, 0x5ca5a28b, 0xbbd7b892, 0x6759a99f, 0x4c12a60f, 0x47c15d2a, 0x8f3166dc, 0xee41e497, + 0xf07fc009, 0xedeeef82, 0x0b33acae, 0x7852bf30, 0xd6ef7ab2, 0x16d1e497, 0x7430c5df, 0xeae80f51, 0xfbc230b6, + 0x67dcafdd, 0x1d5f2ed8, 0xbeb30dc2, 0xe00f2e0e, 0x5ca08dbe, 0xd0ac82eb, 0x3e3b2caa, 0x4b70693a, 0xf6a57f25, + 0x342e3fe4, 0xa5076e36, 0x9642a244, 0x9b6b6c3e, 0x5e9a73fc, 0x6d859b80, 0x0f17289a, 0xbea9b21c, 0xc115a11f, + 0xa29b6bde, 0xed2e3d21, 0x1559bd25, 0x82b59b78, 0x981bb163, 0xea83fabf, 0x6b7d919e, 0x4cafedb6, 0xfcad030d, + 0x69e2b586, 0x70544161, 0x6d1d71ab, 0xb080fa69, 0x21497536, 0x12f94734, 0xf6bafbb5, 0xb6540b4d, 0x151618ad, + 0x6c9bf075, 0xc805e31c, 0xae8bdd1f, 0xb3062090, 0xae6b9d32, 0x839bc1bd, 0xf200e546, 0xc1756b96, 0x1930dd1c, + 0x7560a319, 0x91b01f2e, 0xb588e68d, 0xd89cc3e2, 0x41e9a640, 0x1fa5b909, 0xbee7f5ab, 0x996da492, 0xa2d1db59, + 0x70977280, 0xe2a8e345, 0x1346ae37, 0x36f5d516, 0x0ed4df07, 0xe70ab159, 0x58d933e1, 0x7b40e537, 0x99453bb0, + 0x5c19b434, 0x09433361, 0xd7526b54, 0xde4bda51, 0xb89a9253, 0x8b79482f, 0x59051e3a, 0xe531527a, 0xe91dd1ab, + 0xc059c00a, 0xbd410959, 0x0c75aa84, 0xb190c110, 0x1c779a81, 0xb065f6c4, 0x0f465437, 0xcf991010, 0x036f1daa, + 0xf672d881, 0x0fd26cfb, 0xa1d91c53, 0xd12338cc, 0x06ffc608, 0x945fd7e1, 0xd00c08e1, 0x30c5caff, 0x81994162, + 0x63136fb8, 0x2a1d1b4f, 0x6299e37a, 0x2e692564, 0x25feb321, 0xfd0951e7, 0x02f410bb, 0x9659f067, 0x40f3a663, + 0x922aedca, 0x18b9505d, 0xac820077, 0xbcf7a072, 0xa7216a10, 0x8bcf1c46, 0xe2a3463f, 0x68f411ba, 0xe8053f35, + 0xd84a4d2a, 0x75596b0b, 0xbd21b174, 0x8b484557, 0x55d02fe9, 0x1fdf560a, 0x0f3b7c9f, 0x2d172ab7, 0x97998123, + 0xceb647b2, 0x30102c9d, 0xe76e12be, 0x94232f2b, 0xed230809, 0xad50bb5a, 0x596ef1f3, 0x2b23823e, 0xb98ff8e8, + 0xe916a575, 0x8f673b8a, 0x36498fd3, 0xdef52ce3, 0x5f830402, 0x190f3351, 0xb7722991, 0x9b97ebb6, 0xb8663a98, + 0x80a256c9, 0x4b79519b, 0x58617299, 0x33c2fc1a, 0x79109bfc, 0x6355d8ec, 0x45df76fc, 0x012e7fc9, 0xa3f06690, + 0x989844b4, 0x7907f8ae, 0x6786ce9a, 0xa69e26c1, 0x4a162127, 0xc98e0b64, 0x1a05a156, 0x56309f85, 0x758d023b, + 0xc932c053, 0x99b4c218, 0x513cb28a, 0x2e38e902, 0x77d3e8e4, 0x1e99d56a, 0xaa6955c6, 0x4db388f1, 0x02d90614, + 0x36e0c289, 0xd9e65c60, 0xe77f8edd, 0x8946e5eb, 0x1f66bed8, 0xed58a351, 0x9905c461, 0x66564451, 0x7d14d441, + 0xef1339a0, 0xb7ca4116, 0x71abe36f, 0xb60e033f, 0xd2152625, 0xbf9cbbec, 0x998ea373, 0x941d7c3d, 0x5ff8e48f, + 0x863db54e, 0xbbb11984, 0xdd1356b6, 0xab641719, 0x2ab7ef2f, 0xa3d0c48f, 0x4bf1242a, 0xe5b97c76, 0x32a002e0, + 0xbd62d919, 0xfe975133, 0x216cf7ef, 0x45fbe521, 0xf98e23db, 0x3203f14f, 0x8abb9ea7, 0x4b78a1e0, 0xf0d7bc39, + 0x155cfd13, 0x1c44cac2, 0x95369cb1, 0x39cd9fc0, 0x5282e992, 0xffa0bbed, 0xe240f874, 0x3b09b802, 0x12cb5adc, + 0xe9423d7a, 0x403b3b99, 0xada092a7, 0x851c9b3b, 0xa625666e, 0x4d0e4f20, 0x49264c96, 0xa9c8500e, 0xd37d3b86, + 0x2097eb9c, 0xf32f1257, 0xc0192de0, 0x19dabed1, 0xdfb4bf06, 0x0b48ee2d, 0x1c835ac4, 0x4dec0b93, 0x7cba2caf, + 0xf549869c, 0x56c583be, 0x3945fff3, 0x001326b2, 0x378e14e6, 0xb3e69f2c, 0xfdc779ec, 0xe5be49ae, 0xaf038b61, + 0x5c0e7601, 0x015e2fb9, 0x6d185718, 0x363fe840, 0x3729c985, 0xa9b7f3aa, 0xa41de646, 0x63304b95, 0x0e6f2f2a, + 0x9bd59621, 0xc727cf4d, 0x447b0668, 0x751b0274, 0xc471a558, 0xec36f7b2, 0x7197547e, 0x64ce56c0, 0x8a427870, + 0xb7ae9c1c, 0x668abd5c, 0x8e4547c6, 0x9314c4fc, 0x31f3d18f, 0xd79c70ac, 0x4a9964bd, 0x45b622c2, 0x194900d2, + 0xb4cec415, 0x0f1a06e9, 0x11ab7e81, 0xc1aa577a, 0x435c0123, 0xb69be672, 0xc0dd624a, 0xb19ba18b, 0x7b2c886e, + 0xe9c03883, 0x18672c52, 0xbf1d36bb, 0xca9eca65, 0x38d962e8, 0xbc868257, 0x3850610a, 0x1c61bb26, 0x2a43e991, + 0x190c204a, 0x3da50b3c, 0x532ac88e, 0x70d92dd1, 0x7e996aac, 0x48340e35, 0x23c40874, 0x53f80b08, 0x13aac22a, + 0xb0e5104e, 0x0841aa35, 0x08c604f0, 0xb868f069, 0x44354236, 0x17d599fe, 0x96f09d81, 0xad9c877f, 0x0b07e5f1, + 0x15863e3c, 0x93098f25, 0xefd8b0d0, 0xdbc8bcf6, 0x7d29dab3, 0xb6e320c5, 0x9bab36a4, 0x090b7288, 0x4073b1c3, + 0x816a84c0, 0xe5c09250, 0x0e393eac, 0xd0046c40, 0xae8195c4, 0xd95739a3, 0xcdd14bbc, 0xb8ca0d4c, 0xcb53351c, + 0xef7e8c65, 0x7ad1fa05, 0xa7f1bd6a, 0xece7d46a, 0xfd04c54d, 0xfd06781f, 0xd00d36fa, 0x0123f7c1, 0x57ced070, + 0x9b81695f, 0x0253d88a, 0x43140383, 0x90683d04, 0x1e96a371, 0xb6b0de28, 0xbcf4bde3, 0x2c820ee0, 0x60607660, + 0x9c45ec04, 0x5197ff12, 0xac0123ce, 0xc878bf39, 0x10d53fb0, 0x6a10a03d, 0x5f8a3c6f, 0xd51f1d29, 0xfe1aa78d, + 0xd8511674, 0x1870d3f9, 0xb34852aa, 0x588b753b, 0x04deb5b6, 0x644f0241, 0x96b860db, 0xbb021b4f, 0xdc367d73, + 0x3f728e73, 0xfd32476e, 0xf80b6c86, 0xe9ad667e, 0x6440d5cf, 0x6310eb93, 0x255b65c0, 0x8be87382, 0x0ef9ccff, + 0xd2d04ed2, 0xe176ad60, 0x72a3e7d5, 0x6a67199e, 0x0468f2f1, 0xb464a605, 0xe4a59db8, 0x16ffafe7, 0xaa4fc1e5, + 0xcbbe2a8f, 0xb8eeeed1, 0xd8fe9496, 0xe901bd5f, 0x592d67e1, 0x24b42f4d, 0x71236485, 0x15737190, 0x17c78dde, + 0x26bcfcdc, 0x29db3082, 0xf5b56154, 0x0bfecb75, 0x075c6ff0, 0x78df3c11, 0x06b057e2, 0x3f56ec9c, 0xeb098e9f, + 0xbd4a6deb, 0xa1a6219a, 0x015b1f52, 0x077f7b16, 0xbce1b1f7, 0x148dc062, 0xbd09592e, 0x3caa6596, 0x6eddca97, + 0x8f6ea1fa, 0xd2744d88, 0x8c6ee33d, 0x604f5e73, 0x721601c7, 0x72429731, 0x7d461b8b, 0x399d9e56, 0xb9012dfa, + 0x19592b10, 0xba8df0f8, 0x5d1e18ef, 0xe71c4f18, 0x59dec154, 0x97a42b03, 0xafcab452, 0xbbca6af3, 0xf159abf6, + 0x1a948446, 0x7b79f199, 0x0595d7c3, 0x17223885, 0x44299253, 0x0f10334a, 0x0c509d86, 0x2ea282a5, 0xfa13aca6, + 0x0353fdbd, 0xbd1905b7, 0xf63f502f, 0x688b8339, 0x6905d4b8, 0x494eff1b, 0x71e8bf01, 0xafce7257, 0xf7856e39, + 0xf20a09b0, 0x2c6b4cc8, 0x189ad723, 0x3cd16805, 0xac98696c, 0xf79d0bb9, 0xbab37f8c, 0x4b727868, 0xd5f9d2ca, + 0xd7ddc349, 0xcbe339f9, 0x98b645dc, 0x9f2535eb, 0x1b236709, 0x1874620b, 0x00265fc6, 0xffe28865, 0x237fdc88, + 0x9f7d2108, 0x74a57286, 0xd5eaba94, 0x05f0af4a, 0xf0a47254, 0x6714089f, 0x3cbb5406, 0xf5d7b491, 0xcd885d5b, + 0x7e48fc43, 0x51bd8468, 0x2c8b0729, 0xfea85ca2, 0x3ebc36c6, 0x14cf65b4, 0x6985e6e3, 0x05cf1e8c, 0x63bae428, + 0x2701ae24, 0x78b410c7, 0xb542df9b, 0x64b4ceea, 0x4658ff6d, 0x8c9e84a8, 0xe20b8385, 0xdec337fc, 0xb8256f7f, + 0xa8dd042b, 0xe9acaa94, 0x1c40a0bd, 0x61ee5a30, 0x89e045e1, 0x417a52cc, 0x269c40a2, 0x56e715c7, 0xd0d3f48f, + 0x2e03266a, 0x4871e428, 0xc7bb2b44, 0x1744cd72, 0xa6106205, 0x327686bb, 0x2bb8c03d, 0x54a0df98, 0x725aa032, + 0xb4b9e61c, 0xb164fb57, 0xeaed6e4c, 0x11cf1c4c, 0xf2e4b02c, 0x5578b729, 0xe45a0396, 0x03c6b2bc, 0x39e2f648, + 0x25aaa0d3, 0xbcf11a41, 0x2193258e, 0x07a3411a, 0xa88a4782, 0xa0302e0f, 0x4d9311fc, 0xaf42bf7b, 0x6eb7a1de, + 0x48a6549b, 0x5abaead6, 0x0a9970c0, 0x8a60ed7a, 0xd3af3fa1, 0x290ea2ca, 0xa7e83016, 0x8052ff1b, 0x89c67075, + 0xe0ced1bc, 0x800e4cf3, 0x98c12258, 0x3919a7e8, 0x18ace016, 0xee06d8ed, 0x9a4c029b, 0x6e7c8c28, 0xb5ae8ce6, + 0x90710505, 0xcf5b562d, 0x57bf7493, 0x31bffaff, 0xd60cc976, 0x5e7902d8, 0xf18da021, 0xf05fcbe6, 0x1fb0141b, + 0x084068a6, 0x04325cf1, 0xadc95576, 0xb3ca876f, 0x031e1500, 0x5f0f4d4c, 0x375a1508, 0xacda134f, 0x59112add, + 0x7ac89fb3, 0xb8567c7b, 0xfc765231, 0x96a9c25f, 0xa905725c, 0x92750e4c, 0xa425d2cf, 0xa3c4d821, 0x79fed15d, + 0x727e9995, 0xe3440b98, 0x285c5887, 0xf12a8bce, 0x2e0318d9, 0x3990138f, 0xcc991159, 0xac09f7d3, 0x698a02eb, + 0x6430ffba, 0xcc20379a, 0x219fc743, 0x0dbb5f00, 0x6e6080e9, 0x165a8d61, 0x6c98e417, 0xc4c86f41, 0xbf1e57ea, + 0x4acf3f01, 0xe36a865c, 0x2c5474ca, 0x354b51e0, 0x7d787ac3, 0xfd91bcb0, 0x9d478ebd, 0xe801924b, 0x0d12bf0d, + 0x40058fa8, 0x92b8fcf7, 0xbf490071, 0x1195d75c, 0x266b0398, 0x3c0961ac, 0x93fc5f40, 0x27426b3d, 0xfa13e9f4, + 0x5452f4fe, 0x307cb0a6, 0x4abcd238, 0x3fc15c85, 0xb33b8091, 0x74be9e28, 0xc1b2a427, 0x11d03684, 0x1389a2f9, + 0x30183015, 0x5e56730f, 0x1a50ed29, 0xfc8d20c0, 0xb375590f, 0x63dbea3b, 0x72e0eef5, 0x185f4896, 0x144cb4f5, + 0x789294e8, 0xd1d4c6a3, 0x9a03e169, 0xa48dfba8, 0x6f2d9b23, 0xa6b9fb21, 0xaad77a71, 0x99d175b9, 0x9da366c8, + 0xa0e29d9a, 0x2acfc22b, 0xa0d69336, 0x84e0410f, 0x58aed144, 0xb539fcc5, 0xe62928f5, 0xc8b53488, 0x4ea227df, + 0xbb567d2f, 0xb209b1a9, 0x4f7804c5, 0x5bdfc4e1, 0x27ec80dc, 0x37b43bab, 0x6a33f454, 0xdb66b6d3, 0x8266ebbf, + 0x071b2849, 0x17784382, 0x9c33666c, 0xd628011c, 0xee8a8904, 0xbb67e059, 0x7b15bbcf, 0xe6d9c86f, 0x27275cdd, + 0xabdfc048, 0x0407aada, 0x06d83692, 0xc33c6186, 0xec50ad6b, 0x4bbb928a, 0x0ecc5992, 0x7fa03c00, 0xd6e5e335, + 0xd2fb4ac1, 0x41565c5e, 0xcbc589f4, 0x8fdaaabf, 0xf538b4c7, 0xc25b28b4, 0x68c33b65, 0xeb2389fd, 0x36d05530, + 0xe80414b5, 0xa246135a, 0x24c80247, 0x9e9c5307, 0x0d04d7b7, 0x22c07449, 0x5a581b2d, 0x3a6c44cc, 0x6d9b043a, + 0x2cad0f88, 0xf060742f, 0xabd7b9ad, 0x5d21f9eb, 0x69abfc8c, 0xa550ec5c, 0xbf53ab10, 0xb70a67c5, 0xddd56c77, + 0x83bfc23b, 0x8c575d7f, 0x9fc9c02a, 0x7bff43da, 0x1593f995, 0xffe3b6ba, 0xcfc54a70, 0xdfb3cea0, 0xcc9b5542, + 0x4fae903f, 0xc605a676, 0x1c5e2b65, 0xe9403b19, 0x7e0163a9, 0xc8f86bca, 0x111862d6, 0x3407043c, 0x9ebb5ed6, + 0xc3d4e98d, 0xd317c64d, 0x3d1af080, 0x1af1d640, 0x4cd9b2a3, 0x81e7e74e, 0x023b7654, 0x58fd40ee, 0x86d3d552, + 0x7fb44311, 0x361d073a, 0xaf8fcc3a, 0xfd96af82, 0x03d97877, 0x4ae76d97, 0x79f8d9a0, 0x810803f4, 0xf5305ca7, + 0x187eb7c3, 0xced0de02, 0xd2c5e341, 0xa9e3c2cd, 0x8ba9c74a, 0x64fc332e, 0xcb02fff5, 0xcb6e4a8c, 0xcdfcbc60, + 0x99b2f024, 0x3dd54408, 0xfe5bf739, 0xb27b716e, 0xed218405, 0x7b74a838, 0x596143e1, 0x7e2e6a7d, 0x21e4b361, + 0xd096017c, 0xc2ff4db2, 0xc3723d27, 0x4699d680, 0xdfe8e7a2, 0x14332bae, 0x4d32b73c, 0x589bf573, 0xba9e7b01, + 0xe744d5b7, 0xbbd6db5b, 0x99045ba3, 0x50ca3a8f, 0x23bb1634, 0x5a0188fb, 0xf28e09a1, 0x90f951e1, 0x7ba6cd41, + 0x81366ac3, 0x6486cfa8, 0x44caddf4, 0xbcc538d9, 0x595ed179, 0x769435c6, 0x58a336c0, 0x2b70d4dc, 0x1496aaff, + 0xf214662c, 0x5b8179e9, 0xbf6012e2, 0x67916a14, 0xbc2ee5ca, 0xc75a6e69, 0x9449f0db, 0x54315237, 0x26a119ae, + 0x27732b7a, 0x8ac17d81, 0x22a3fab5, 0x213d433a, 0x12dbd6f5, 0xfb32471e, 0xd4c3f688, 0xd26deeac, 0xf4053e98, + 0x9ce54467, 0x827d5f2c, 0xfd8fba78, 0x56247930, 0xf8d706ae, 0xf359d27f, 0x46ec7cb4, 0x51da3c35, 0x2b8de673, + 0xcf17d98a, 0x3666fc4e, 0xcde7e162, 0x08bb8bca, 0xcc958025, 0xc350020a, 0xd0b7e1c0, 0x30da4055, 0xbfbb6d76, + 0xc15a79d3, 0x902c55a7, 0x0c033ba6, 0xc1512a87, 0x04a374fb, 0x20ea932f, 0x725d0ed8, 0x927b72c8, 0xadeb5fea, + 0x39628d1e, 0x6e3b5307, 0xc7ac3dc9, 0x1197b084, 0xda33a5ec, 0x05a2cc03, 0x9fa0b116, 0xa8b6c18f, 0x5bc056c8, + 0x33e6bbb6, 0x2dd412c3, 0x414d51a1, 0xa003faf4, 0x84d7392d, 0xd4ffd417, 0x1ec166c0, 0x773098c3, 0x7ac864e7, + 0x962aefe9, 0x545ec08e, 0x7ee9e0f2, 0x8a4d6af4, 0xdcd9f25b, 0xa8d51253, 0x279d5125, 0xa9769d76, 0x45ad9a25, + 0x52d5ade5, 0xb077cab6, 0x95016b0b, 0xa11693bd, 0x2b5f7622, 0xb6c4dbcb, 0x039ea56a, 0xe9f5766d, 0xd9e4634f, + 0x4ec2f4b9, 0xcc09b2ad, 0xf93098c0, 0x6d81fe59, 0xca9abec1, 0xfed94b9a, 0x73524065, 0x8087a24b, 0x81c9e85a, + 0x8214dfee, 0x7f4312b1, 0xf1e00dcb, 0x60abc8e1, 0xea8851ef, 0x05c1ad94, 0x34da8283, 0xbaee3965, 0xc77f9068, + 0x42e85eb6, 0x7b6527d7, 0xb9abc0dd, 0x271d7337, 0x677ab0f1, 0xfdacac78, 0x6fafb992, 0x95e70bc9, 0xd3b50542, + 0xbe587458, 0xa54d5cce, 0x9892609a, 0x61365d08, 0x17593e28, 0x3ffc96fc, 0x1b9c09a3, 0x917a4acb, 0x8e62e59a, + 0x38d6d1d3, 0xea736a2b, 0x7716ddb0, 0xd01f66ef, 0x9dab5ea3, 0xf1e96d20, 0x9809780c, 0xa911de76, 0x9d097da7, + 0x211ad471, 0x70e389cb, 0x735fdd25, 0x185bce24, 0x344bdf66, 0x94c72517, 0x66ba1400, 0x64857920, 0x012b939f, + 0xc1c8d4e3, 0x91693b9c, 0x281db2c4, 0x2c8769dd, 0xdb39c6cd, 0xefd6de68, 0x9feec55c, 0x9a4ee243, 0x36668dd1, + 0x7853ea27, 0x21bc55fb, 0x5462b24b, 0xce56e386, 0x8db50c68, 0x4a78d3f7, 0x88254022, 0x3875822c, 0xcb3bbf2f, + 0x69238e44, 0x9b4181af, 0x910a8062, 0x6935c751, 0x1d78e8fe, 0x1fd086a6, 0x0bb972c1, 0xaede087f, 0x451eed0c, + 0xa8d84ea4, 0x6a6b7b29, 0x060bb322, 0xd5216020, 0x2a69802e, 0x78571e45, 0xc487a077, 0xbdde346c, 0xde93ee33, + 0x5007fb9a, 0xeef8aeb3, 0x1bde44cc, 0x38647f83, 0xedebbe63, 0x34548643, 0x19f5daf3, 0x2a50b3db, 0x1916a3c4, + 0xd885c0ab, 0xd5fde2db, 0x79630c04, 0x2ee81ee9, 0x1035ea68, 0xe13a4969, 0x6eafb57e, 0x50933ce1, 0xfd87f15f, + 0x9b0dc143, 0x3cc09fad, 0xe9154500, 0xae617d7c, 0xcc3a6090, 0x43ae99a1, 0x0ac982cd, 0xf30e31df, 0x41df8768, + 0x63709964, 0x2243b968, 0xf9cf7672, 0x907190ea, 0xffbaf4c2, 0xa632f63e, 0x2ba21921, 0x1f9e9518, 0xeba592bf, + 0x88024f94, 0x2f16e929, 0x1fd924b5, 0x6af843c1, 0x662dcd3a, 0xeb7ba6eb, 0x477902f9, 0x25ee8b1e, 0xf2dcc22e, + 0xda31dfbe, 0xbd7cb410, 0x8513e6bc, 0xdd9b0800, 0x5f1968ae, 0x1201b1ff, 0xbef73f97, 0xda598fbd, 0xf69d52fd, + 0xcf6ac45f, 0x226fef8d, 0xc32d5b36, 0xab97abcc, 0x229e243e, 0x69cda4e6, 0x1aa28851, 0xa30c0471, 0xdd90562d, + 0xfb8ecfb9, 0x565c1b3f, 0x005b3873, 0x4125ca0e, 0xb53ce23c, 0x991f118b, 0xd1ba2b72, 0x7944deda, 0xcef469f5, + 0xc32b7f80, 0xae31f801, 0x54b6105a, 0x2cf98541, 0x536ccf18, 0xb9608cc5, 0xf58bdb2d, 0x635653dd, 0x6c4627a7, + 0x57164b2e, 0xfed59fec, 0xde2a243a, 0x4e67a975, 0xce533eed, 0x8cfb642d, 0xfa672758, 0x93726bca, 0x6ee5fef4, + 0x0ee54dee, 0x57935f77, 0xe78ceab3, 0x0d39e9c2, 0x979995fb, 0x714f9427, 0x25722784, 0x21cde9c2, 0x71212d3f, + 0x543b0ec5, 0xc031f8c9, 0x5e6ec7a0, 0xdd1d5cb3, 0xed5d3c76, 0xb4576288, 0x92dde484, 0x12647d00, 0x69703757, + 0x2d3becfe, 0xbe1a5859, 0xe4e2542d, 0x3e3745c2, 0x6c94788a, 0xb48965b9, 0x487f5ce4, 0x77ec72d1, 0x5d5276c0, + 0x8709fff1, 0x04727498, 0x9b6e1bd5, 0x0eabac10, 0x71672595, 0x3474f592, 0x119919a2, 0x6cae686f, 0xa93a1926, + 0x2dea7bff, 0x6d26271a, 0xd21827b6, 0x24019274, 0x1873c0d1, 0xb797eed6, 0x6ec828cb, 0xd221926c, 0xf6002965, + 0xef00594b, 0x56ac7f44, 0xf5736891, 0xc44c0714, 0x7e850254, 0xaf29b64f, 0x933c587d, 0x94176c70, 0x047d7734, + 0x4f35258b, 0x5eb37f54, 0x899309d5, 0x3236076e, 0xe71072f6, 0xfe69f9a3, 0x786ee5e2, 0xc7b613f4, 0xcd7a541b, + 0xb1f9590c, 0x800b89c4, 0x32ba6ea6, 0xb77960ff, 0x9e2621d2, 0xed38b08b, 0xd8405feb, 0xd0f53f9e, 0x0ca18bde, + 0x2f72ad55, 0xc147e704, 0x3acd5258, 0x270b9d0f, 0xbdaf9621, 0x1e2ed9b8, 0xad3cf805, 0x29b2c3fa, 0x9febf731, + 0x06805caa, 0xd8a53b3d, 0x79a1e5b8, 0xeed428f0, 0xcccb9b9b, 0x265020a7, 0x33fed2d6, 0xfc2bc1bc, 0xc992a4bf, + 0x68db28d5, 0x1ba3bc33, 0x7debd820, 0x7ff9f6d4, 0x32965235, 0x8532a246, 0x1f83939b, 0xd75f83d4, 0xca8a754c, + 0x1bc0ea4d, 0x099c6cbb, 0x75988e0c, 0xa2db8f5b, 0x46160677, 0xdff8ad30, 0x0e681c83, 0xbe08128a, 0x02fe0461, + 0xe53910f7, 0x7f29ccdf, 0x1724a1fd, 0xd7385cb3, 0xafb42bf2, 0x805115c1, 0x572258d8, 0xba833ed2, 0x99b35143, + 0x24ac7c59, 0x59f4585f, 0x40574875, 0xd39f48f6, 0x71848639, 0xfc27b910, 0x14463b4e, 0x917feb18, 0xb0d18c33, + 0xfa3f012d, 0x7dfedca5, 0xd0084508, 0xff0c4065, 0x5357ec18, 0x97c640bf, 0x4eca36c1, 0xccc5ea65, 0x20a9a9e1, + 0xd50e12dc, 0x8333da38, 0x8964afcf, 0x7d12c525, 0xd16e4814, 0x60a4b926, 0x6601260f, 0x82260bf9, 0xd3f3c7ba, + 0x616ac6b3, 0x0f9473f8, 0x68e8587a, 0x84ee9ed2, 0x2fb84fc9, 0x95700b96, 0x9fcfcd33, 0xb4610b5d, 0x2ab89618, + 0x31675a1f, 0x5b7b0ac9, 0xd199dff6, 0x137247de, 0x8ddb7035, 0x44222404, 0x847b9dfc, 0xb84c7128, 0x1676423a, + 0x275200e3, 0x3d25290d, 0xa1fd2db3, 0x4c37a6db, 0xb64abbb1, 0x11ebc3ca, 0xe07c6067, 0xcb66535d, 0x14fb2c53, + 0x671d6ccc, 0x680eb8b8, 0x514e718a, 0xdd716f1a, 0x5b66ae71, 0xe4736136, 0xff5c4f24, 0x00275a2f, 0x13172a95, + 0x4bba9efd, 0x6c174325, 0x0e53b106, 0x41fc4bc8, 0x6b399108, 0x7db57c3c, 0x714cb5f7, 0x5e216c00, 0x6174ca72, + 0xc2003f6a, 0x6573b284, 0x3427eb77, 0xebdd7f32, 0x0ec979e2, 0x1727b25b, 0xb36e9376, 0xb958c994, 0x046d7e00, + 0xf91f3f85, 0xd8d9657e, 0x39fbc0b7, 0x4f0d8069, 0x555809f0, 0x33c4263a, 0x2b677b11, 0x5362e5ab, 0xa042586c, + 0x10319cbc, 0x7c2d6fa7, 0x0f28a300, 0x27438166, 0xad9ea15a, 0xd69886f2, 0xc3e8e489, 0xa30eedb9, 0xd6a75466, + 0x248979fd, 0xfaed98f0, 0xb93f4a0e, 0xc497b767, 0x77858f37, 0xbb20f169, 0xb6df4fbe, 0xaf4e226d, 0x75ad6ff4, + 0x45b0fa6a, 0xa3b804d6, 0x92262757, 0x46094757, 0x05f517aa, 0xe515680b, 0x76c86ade, 0x4fc2cfb4, 0x2c0a44e2, + 0xcc384dd4, 0x33e0daa9, 0xe002e9c1, 0x2cddab23, 0x64e55051, 0x5f1b964e, 0x643c542b, 0xc44332ff, 0xaaaf3d0e, + 0x3108a53f, 0x6222d4e7, 0x5527cf0a, 0xb00a49ad, 0x4bb5b608, 0x1262c46b, 0x101246b4, 0xb0633c90, 0x3963a57d, + 0xff81bbf9, 0x74f7dd38, 0x4a302162, 0x9720ce2b, 0xf41222e1, 0x0e7bbc6e, 0xd541c986, 0x6e09300c, 0x025d9b11, + 0x769077bf, 0x7a03335c, 0x2ba8cf02, 0x6d3b8e4f, 0x99d097d9, 0x4a77fd92, 0xa91d723d, 0x3bf77fe2, 0xad8b98f9, + 0x38a023ec, 0x94c64813, 0xfbb63aa6, 0x1a0c5cdc, 0x31653503, 0x6c9f8330, 0x289dab67, 0xf16b8ee7, 0x2c151b4c, + 0xae7cceb8, 0xfa6c5cd8, 0x89d11b85, 0xbdca2830, 0x3a570de1, 0xe23c2dd2, 0xdcd86384, 0x6cc1b494, 0x6d42b582, + 0x17af6240, 0xa8ac6091, 0x546465c6, 0x5b2ba2c1, 0x779229fd, 0x952ad2a4, 0x7ffb6333, 0x1cef62fb, 0x76347a11, + 0x7a19f040, 0x529dd1ed, 0xdf2adf71, 0xef6839e3, 0x0cc39c76, 0x0c304dac, 0xebfd6989, 0xc01feaed, 0x15fe10fb, + 0x5c9eee46, 0x7a1ce43a, 0x735b2554, 0x11e052a5, 0x7c44e343, 0x28f9fb56, 0xccd5cbc4, 0xbae93ef6, 0x3355047c, + 0xee3735d9, 0xfff1a05a, 0xcee85acf, 0xfe6880d6, 0xd36b3c03, 0xa0993162, 0x26a19376, 0x794b5fe8, 0x1965a507, + 0xdbe0aec5, 0x7d4fd30c, 0x21af936a, 0xe26776a5, 0xc66ed883, 0xf9ecd8ea, 0xe92dc606, 0x018ecb40, 0x0afc98c2, + 0x33de605b, 0x7cd73ac6, 0xfa36271a, 0xfd1358c2, 0xb0ba1706, 0xc2a27899, 0x6a3970fa, 0xd420cddb, 0x785aea1b, + 0xf69a5850, 0x10cb44b7, 0xbb6c1356, 0xf945e9b5, 0x6b916a2e, 0x9fff43cf, 0xdd24aae9, 0xe69dcdb4, 0x44a2b140, + 0xad76f307, 0x6b288d5f, 0xd2a959f9, 0xc40ec7d5, 0xeef525d3, 0x6703a294, 0xce8b9278, 0x54cb7403, 0x456e176d, + 0xb40a305f, 0x3d1c57ee, 0x6e9779b8, 0xb20d299c, 0x2f9931a8, 0xdb8d7241, 0x7b072093, 0xdadf4762, 0x19109741, + 0x6e62aeee, 0x861a27bf, 0xdc01854a, 0x6fc06370, 0xfa89b2c5, 0xa02aaefe, 0x8fe55d96, 0x2cd37d43, 0x9ce2f242, + 0x33937ff1, 0x532d37fa, 0x84f06a19, 0xa536d1dc, 0x112597fe, 0x892aef33, 0x1d21d30f, 0x603c4524, 0x35cc167a, + 0x6bfbdcf6, 0x42377e20, 0xc5464dc0, 0x10539c0d, 0xde4a09e8, 0xb5ee19b3, 0x287f36f0, 0x8932e809, 0xced3e69e, + 0x4c5da28f, 0x17c679dd, 0x8628c236, 0x5fd9d1bd, 0x1fa89ba1, 0xd948cb50, 0x5cd51c70, 0x47427607, 0x198db9d2, + 0x1e0601ed, 0x3ecf997f, 0x21ae1fe7, 0x2f934950, 0x8ec88643, 0x79e1b51d, 0x69d18be0, 0x7dca9fd6, 0x22459b95, + 0xfbab836b, 0x0e649a85, 0xee412b1f, 0x2c47db81, 0xbc8f2e89, 0xcc9b0f77, 0xd01537f0, 0x474a004f, 0xc3e3c464, + 0xc6215e7a, 0x06c96520, 0xe9e50b59, 0x18679477, 0x8547ada3, 0xdb49b953, 0x31183352, 0xad823b9e, 0xec6fddc2, + 0xecf4610e, 0x7f6b37a1, 0x3c25a985, 0xe464173c, 0xb60a6062, 0xb93a0a4c, 0x85c3e9e7, 0xcd232e64, 0xe76f9825, + 0xb22dcf00, 0x40b5b2b0, 0x8fd1620d, 0x9af0d795, 0x3196dc85, 0x1726a21e, 0xde9cd567, 0xd65f1dab, 0x8516a172, + 0xaa83204a, 0x6985c275, 0x0e455b13, 0x5f6f03d6, 0x2149c23b, 0x55fddedf, 0xcb31e47c, 0xcc8b0a71, 0x66c0104b, + 0xb94f17b0, 0xf32ca575, 0x910cb0e8, 0xd730b671, 0xd7ea8045, 0xa3cea49c, 0x0ed93013, 0x891bb31b, 0xa531b609, + 0xaee2c75e, 0x0e25e04e, 0x51e3509c, 0xdef3f65d, 0x88540c34, 0xcd5bd09a, 0x099652c7, 0x7973b3a1, 0xc28ad4fe, + 0x3350c546, 0x63511bb9, 0x61ddbc9f, 0x33b2e6f1, 0x77e1bc7b, 0x9b0f7731, 0xec37f475, 0x38ff8b93, 0xcbe63ece, + 0x3c4f8876, 0x864bffa7, 0xf24099aa, 0xcbec496c, 0x16ccbf23, 0xeca5e069, 0x0974f316, 0xa1862ab7, 0xd1dcb52d, + 0x3df22237, 0x2395fab8, 0x51d98608, 0x99df6ec6, 0x09278a60, 0xea3ff5c4, 0xfc5a1ece, 0x8ae841cf, 0x23355fcc, + 0x4a0e1dba, 0x03170717, 0x08c0b570, 0xbf7375e7, 0x76f3e12a, 0x985fd983, 0x43f30e43, 0x19a3c0ba, 0xe73c9ce6, + 0x2d6a2ab2, 0x46115279, 0x996a1679, 0x1f4cd61b, 0x1dbd2978, 0xb792cf64, 0x9934157e, 0xaf349f91, 0xe7d71675, + 0x71e5bf53, 0xa3e13934, 0xaa0a2d5b, 0xcb3fed47, 0x05ecc569, 0x23eaf281, 0x118e9657, 0x68fdc7fe, 0x2cfdd9a8, + 0x016c5bad, 0x1c72e47e, 0xf929febb, 0x5b0ce71e, 0x8a3f8704, 0x2ec7158f, 0x6597a3fc, 0xb45e0a93, 0x31acb975, + 0x9becae69, 0x30ac2c53, 0x2f0a559b, 0x561dc69f, 0x1855f1f4, 0x964af187, 0x9728c1ce, 0x87a6fb02, 0x3c719dc7, + 0xa4d6838f, 0xc7e248ca, 0x24d19f23, 0x81513be5, 0x6799a2e9, 0xc4dda870, 0x28a822d5, 0x0ab3d89f, 0xb7385d36, + 0x539475a9, 0xa851ee53, 0xbb90021f, 0x47ec6c57, 0xa2ff7604, 0xcc469c71, 0x9fcdc29c, 0x69dc4c9b, 0x6f2268ad, + 0x7e6703f4, 0x548bbb73, 0xe07f3e53, 0xb651744a, 0x3ee259f8, 0xe800c6c0, 0xfe5ad1d5, 0x45417f00, 0x0ef584dc, + 0x5e6fd485, 0x08b38b10, 0x0759df49, 0xa2193354, 0x9d3759dc, 0xfaa222ba, 0x41b4d379, 0xb492051e, 0x94dedbf6, + 0xfccc58f2, 0x6d2e0820, 0x77cf4a6d, 0xc8a041ec, 0x2bdcb5dc, 0x399fd1ea, 0x2c17ff16, 0x9331abcc, 0x8e4724ae, + 0x4c8df76a, 0xeae4def7, 0x657f5481, 0xb9fb831b, 0x02785b2f, 0x13ea06da, 0x1b0b37ba, 0x2adc65ab, 0x2bdb7417, + 0x32220518, 0x0d518d6c, 0x65bc5475, 0x89c25e0b, 0x0d966d3c, 0x4bb81b85, 0x351e3e61, 0x159531aa, 0x90555429, + 0xfe10ea28, 0x290c345d, 0x17618625, 0xce09b8d1, 0x4fb49e0c, 0x212d4295, 0xcc87528b, 0xe89826a2, 0xf4c96086, + 0xbf9023eb, 0x0e6f5dc2, 0x4356f6fc, 0x10f663fd, 0xa372f41e, 0x871e4d87, 0x0608432a, 0x2018e3ac, 0x4da7bee9, + 0x56522eba, 0xb5085446, 0x7fa0a8f3, 0x5496d55a, 0x9d579e6d, 0xfa50eec7, 0x51664d58, 0xe28bc26c, 0x5cd5892f, + 0x20f61dd7, 0x0f40c69c, 0xd9b086ff, 0x923a5655, 0x9f06e917, 0xe75ccddd, 0x0d699356, 0x1ca45d22, 0xa7f89d8d, + 0xac89d4af, 0xe1d8d2c1, 0x4dd55888, 0xb4abc045, 0x1dfe6842, 0xf135319a, 0x1d036b93, 0x284c368d, 0x444beafb, + 0x3d35db9a, 0x69ea6b68, 0xc1e01862, 0x5ffa5564, 0x7b045d99, 0x844da5d4, 0xc87b9cab, 0xcf96386d, 0x887e15de, + 0x7b083bad, 0xd8a653c0, 0x5eed20c2, 0x93e0f4e5, 0xe58d76d7, 0x684b1cfb, 0xe466332c, 0xb2935caa, 0xf1d1f04c, + 0x707b1efb, 0xcafbad4c, 0x8da6a06a, 0xe1911d90, 0x490bbcfb, 0xb0a59e93, 0x4d608a51, 0x84083027, 0xef89949b, + 0xc5b54a78, 0x4a4592ee, 0x9d77ac4b, 0xba1d66ca, 0x0596c09d, 0xcd341346, 0x080e904e, 0xcc0a96e5, 0xbd6a8158, + 0x297a9502, 0x85947eb0, 0x3c4f83f9, 0x66707249, 0xfeaa75b0, 0x1bec61dc, 0x0ee93654, 0x9c3d1e88, 0xc154256e, + 0x1ccfd5c0, 0xfedd5d85, 0x161bc1a1, 0x59a90abe, 0xc9fc3469, 0x9ab961e7, 0x01b92cfe, 0xdc9f5e25, 0x7cd26ccd, + 0xf79ce54c, 0x4541f78f, 0xe7eaeb7f, 0xf9ee04c4, 0x408f0a1d, 0x1cb4f28e, 0x63608e45, 0x02032cdc, 0x78207937, + 0xc152f975, 0x0cfce10c, 0xa6c4a4c3, 0x0089bd90, 0xffcf5a41, 0x8e9a623a, 0x92cf5218, 0x4eccea34, 0x15cc7120, + 0x431d69f5, 0xe634e480, 0x74d240b6, 0xdd49e3ca, 0x0dffdb4e, 0x63d1dd4e, 0x4e4288db, 0x5d376a63, 0x08e6fcc3, + 0x7e396519, 0xca5cefac, 0x03f40731, 0x93c075e9, 0x0e06961d, 0xc1414595, 0x80d314ef, 0x895161be, 0x6045fd1d, + 0x46e28568, 0x13bbe547, 0xfc101cae, 0x2bbde289, 0xf01f112f, 0xf2492294, 0x393e62be, 0xc0be3769, 0x9ba5ace8, + 0x01abef71, 0x21f91a6a, 0xb6a9bc0d, 0xe317ccfa, 0x5416b7ee, 0xf934ae6e, 0x2b5c057b, 0xc16b8e69, 0x3ea7fbd7, + 0x81d57c17, 0x5274a7e1, 0x083a8001, 0xde244d7a, 0x244a642c, 0xbdd032e7, 0xa6f8a116, 0x4d4a9479, 0x6a7ab145, + 0xd14512b3, 0xda97f066, 0xa71535cc, 0x00ae08ab, 0x95708123, 0x5e4d3143, 0x15931008, 0xbe198b16, 0x71989e75, + 0x13aea508, 0x1f570f2b, 0x38a8fac0, 0x58c0339a, 0x9321bda0, 0x56d1a4e5, 0xfd783d9f, 0x111108c0, 0x20927806, + 0xc0167d92, 0x6b9cacc9, 0x5275d540, 0xf31e3af0, 0x20facc8b, 0x7d708d50, 0xf8f02f55, 0xbe1df197, 0x7263cf37, + 0x4dbb5543, 0x15edd551, 0x3ebf1c65, 0xcc3abda4, 0xa09c9554, 0x81f09270, 0x7518d282, 0xc16c1e18, 0x1b600dd5, + 0x4509f892, 0x7e2955c6, 0x0a122a3c, 0xcdbd5426, 0x3e329f2d, 0xb5d4d1d0, 0xbe9a3a17, 0xc48a4a77, 0x1e45605a, + 0xc5fcdf3c, 0xc67cf5bb, 0x4e387d6c, 0x6a9bf867, 0x235018c8, 0xedf63e83, 0x6db027f5, 0x68537204, 0xf1cd88ba, + 0x8a706d68, 0xe41c85a7, 0xe5a92a58, 0x7f2d8260, 0x9ea1315f, 0xe58f2627, 0x756d017f, 0xc1ba198d, 0x7b9962e0, + 0xd4e31681, 0x2a5727f8, 0xc2b5e24f, 0x9146272a, 0xff6df454, 0xc78f8a19, 0x94b176be, 0xfc432a76, 0x27842cc6, + 0x65839af5, 0x54a34567, 0x8c41b69a, 0x5ebe51a0, 0xe930d933, 0x0ceb7396, 0x35074ad2, 0x4e807d3b, 0x5d1a9c05, + 0xf586edc9, 0x91b29e49, 0x79bd6b15, 0x69e4f000, 0xd581be8c, 0x3f628e22, 0x2344aef0, 0xbe96c2cd, 0x1beed762, + 0x4db9e849, 0x3ac17e4b, 0xc76dc4ec, 0x8cd36633, 0xa2293d2c, 0xf4e68c18, 0xe61a9ea7, 0xeabb1d60, 0x3fa3a01f, + 0x02e6e0e1, 0x989c55a8, 0x221c69dd, 0x955464a1, 0x561572e2, 0x03f6837a, 0x75cc39a0, 0x1954bf4c, 0x6d041349, + 0x6fb1c171, 0xd74db1f8, 0xa7eb0101, 0xab9e55c9, 0xcacc7039, 0xf0e27529, 0xfd4c1913, 0x8b6aa1ab, 0x49a62564, + 0xec2e4d68, 0x308c0a29, 0x6b6ace13, 0xd4a479f1, 0x5a43fe58, 0x96286973, 0xe98ddda1, 0x2c20335b, 0xa7c1939b, + 0xaed027e5, 0x0784ea01, 0x3e9a76ef, 0xa7136b57, 0x25b5c71f, 0x70ea9a37, 0x1151323e, 0x421d95fa, 0x64a6fb33, + 0x6a391139, 0x79f82188, 0xd370e2ca, 0x97e1248d, 0xdfb322cd, 0x731025a1, 0xdf79bb57, 0x6dbad0cc, 0x03d1ab8d, + 0x3fe1c9c5, 0x28dc7164, 0x78a35dc8, 0x1260539d, 0x31fa1455, 0x7cffa131, 0xea38859c, 0x247674ba, 0xa590cabb, + 0xc15689b7, 0xb832e662, 0x76227e69, 0xc845a6b7, 0x77c30483, 0x15a01e9a, 0x36cc2101, 0x34b9409f, 0x50e5c32f, + 0x02161015, 0xcc257629, 0xa130f02b, 0x9ac2b55b, 0xe26efdaf, 0x006dd960, 0x90177793, 0x74553260, 0x6e9b938f, + 0x134859b8, 0xbc7e7da7, 0xa6ca1091, 0xadf9f48b, 0x5ccd63b9, 0x1468ab72, 0xaec666a2, 0x44b59412, 0x1f5477ff, + 0xd46e33c4, 0x22f256a3, 0xeefc200a, 0x12a14574, 0x19d0095e, 0xdcf21322, 0xc6b37f20, 0x88356f85, 0x230297f7, + 0x31dc2314, 0xca2a517a, 0xcb5774d2, 0x2f1940b2, 0x4214db78, 0x8ab0d527, 0x2d5b1700, 0xfc4b4503, 0xb0cc02e2, + 0xcc711ae3, 0x1833a441, 0xfad7ef97, 0x3ac101a2, 0x485cb822, 0x3a0ff0e0, 0x233c1c01, 0x86db7429, 0x961b7b56, + 0x5a20c035, 0x0cb7b760, 0x88ccfca8, 0x98d7e9b6, 0x2fecf403, 0xbba6790c, 0xad9221c5, 0x79d0f2c4, 0x308f9486, + 0xc74bbda7, 0x90d618a3, 0x559c9cc3, 0x7c5b3d33, 0x4d72ecee, 0xc1b5cbd4, 0xa21409d3, 0xac36f240, 0x323239bd, + 0xf68e9a06, 0xa9e67e89, 0x625abb85, 0x0130266b, 0x26b7a7bc, 0x107ae2cb, 0x24ab42e1, 0xb4a87e5f, 0x69170485, + 0x8edccd75, 0xb662a020, 0xea546f22, 0xcd3a56df, 0xf3c25f56, 0x2887c48b, 0x8f8fdadc, 0x7860d603, 0xd7c0c0d8, + 0x12ea029c, 0xcae9da95, 0xdeef67ac, 0x82a0e8d8, 0xbe484ab8, 0xaa64fb1e, 0x0b10d28c, 0x22776651, 0x1782edd8, + 0x1f87a58d, 0x8cfb1db0, 0x7be8f149, 0x6133bebe, 0x315a7beb, 0x89584ea0, 0x59fdda42, 0x33a49506, 0x44ec2641, + 0x75fb4d7c, 0x4cfec5f4, 0xecede465, 0x955f4d2c, 0x29936dfc, 0x06a3975c, 0x60dca0ec, 0x1f4c8367, 0x9013274d, + 0x5a0a0857, 0x5beaabf9, 0x761428ae, 0x29a3a5f2, 0x1ff2db1e, 0xed0d912b, 0x36ba2690, 0xdb5913f4, 0x7502a66b, + 0xd2f33734, 0x9dc1e125, 0x5efcd9a5, 0xb1aa046a, 0x7e7e03e9, 0x6ea4967d, 0x5e67d240, 0x05359594, 0x94dbdf70, + 0xcf55377a, 0xa263dbb2, 0x72ffe269, 0x50b8fc99, 0xde4f30d8, 0x41b50dd8, 0xbfec2aba, 0x57ef5607, 0x1dab12ba, + 0xf25ab4c8, 0x4dc35652, 0x0a6bd42c, 0xa8d17963, 0x72502621, 0x3ba4a5ca, 0xdeda2eec, 0x830c4fa9, 0x98a989df, + 0x30b94411, 0xc0927ad0, 0xd0395c94, 0x356a8007, 0x4ff4cb61, 0x60c21a73, 0x98133335, 0x9d8e01e9, 0xe09f23da, + 0x808a48c0, 0xf43552cc, 0xf5259339, 0x540cb21b, 0x9de23f3f, 0xe0d0d408, 0x6cd367c4, 0x606894f0, 0x55784ffd, + 0x5ada09c0, 0x03e1c284, 0x8c211194, 0x559a3e74, 0xc4901e0c, 0xcf69f2a8, 0xbb7addc8, 0x2cbcca07, 0xcbe0c6aa, + 0x203c9ac0, 0xdf513847, 0xa97324e1, 0x36ea803e, 0xe30e3a4f, 0xbb30d08f, 0xe772d655, 0xd8caf536, 0x6e489c8d, + 0x928564b0, 0xdb0f5e2b, 0xb2a083ef, 0x8b0cf51a, 0xdae39c67, 0x631ae09a, 0xd42da44c, 0xb3065cf4, 0xdfffb927, + 0x525da3b9, 0x65f7d93e, 0x234c883c, 0x75a8cec6, 0xa577b5a5, 0xb982f1fe, 0x044c2871, 0xef08e254, 0xa0c61d4f, + 0x12666839, 0xa769ae61, 0x173f665f, 0xef8a7c70, 0x1413fe85, 0xe20e6123, 0x1b19dd92, 0xfc829f25, 0x6eaefda6, + 0x4e3f7a23, 0xa90ae367, 0x3b26a8e7, 0x708c247d, 0x592ec10c, 0xb5dcc177, 0xa64e5e18, 0x178e9ddf, 0x8492c0b9, + 0x44b22b84, 0xfc21a1b2, 0xd8b577cb, 0xff467318, 0x38240efc, 0x6d580bd0, 0x4f497313, 0x85a3a97e, 0xf824d822, + 0xcc24bba7, 0x3f699726, 0x46509af8, 0x7a152b70, 0x26c90eee, 0x4de1e940, 0xc1dbe938, 0xdb2e78f2, 0x23134dc6, + 0x59aa71df, 0xe424f7b3, 0x42265fd9, 0xc4dcf3f3, 0x98b67c69, 0xbe92e4b9, 0xb39cebd6, 0x1508b903, 0xaf76c38c, + 0x4364b0dc, 0x73356689, 0x82b9fa68, 0x667a78dd, 0x1e969980, 0x9495f30f, 0x86e2fc6a, 0x364d28d5, 0x9705fb3e, + 0x2961b970, 0x22ac210a, 0x521687e0, 0xd6943ef7, 0xcf4127e0, 0xf063afb0, 0x31fe1e69, 0x96c52012, 0x1fa76e3a, + 0xc71f159c, 0x15588dbb, 0x0597b5ab, 0xda5dd646, 0x7372cd01, 0x07fa400b, 0xcf9c8ddf, 0xf9367433, 0x2bba1497, + 0x963eb115, 0x79ee095e, 0x65a87ebb, 0x76d572fa, 0x6b147f0f, 0x7f9b74d2, 0x40ae6808, 0x6d3a018d, 0x0c363a03, + 0x6d614f06, 0xe5f9f70a, 0x74919252, 0x21cd1432, 0xab258540, 0x8269657e, 0x114b7da0, 0x26864331, 0x78f30d1a, + 0x9615e3ae, 0xc72a2f16, 0x47678145, 0x27652c9b, 0x0d1ff3ba, 0x7b095d87, 0x5fca6540, 0xdb0377cd, 0x2e496f6b, + 0x05022370, 0xeb02f548, 0x090b0e6b, 0xa92481cd, 0x2e6fabf0, 0x3c24d542, 0xb74154a6, 0x1b64ccfa, 0x15940ca4, + 0xff3cb1ca, 0x0c3d4d16, 0x1a4649c8, 0x3346b939, 0xee81e84d, 0x51f248c3, 0x6c2e7591, 0xb026adb8, 0x8a42761c, + 0x7e07613e, 0xa5898739, 0xa8fba734, 0xae3ea3a8, 0x5d2eabaf, 0xb7d1ea4b, 0x7582e5e2, 0x133aa9a9, 0x2bb82470, + 0xa4ed5330, 0x192cebf1, 0x554fcf0d, 0x469d889a, 0xcf70f9b7, 0x4595effc, 0xae93bd8c, 0xd56d3aeb, 0x4dc858c2, + 0x3109c184, 0x0a181eac, 0xf9c2bd37, 0xb6bc9bca, 0x7fa9e6ef, 0xfd456f4d, 0x7573e8e2, 0x1517e1c8, 0xf227af18, + 0x8e35ba3a, 0x762fc384, 0xdf3c90ca, 0xbc19df4b, 0xcc686d84, 0x2bfce88b, 0x04bc5e72, 0x73969861, 0xf6cdb840, + 0x92e4531b, 0xea05cb4b, 0xce3d2f11, 0x8eed290d, 0x01c4a256, 0x315678ed, 0xb4f6d134, 0x40742fe2, 0x35d89c75, + 0xfcefe6ef, 0x9c971da6, 0x83678717, 0x5f2852a9, 0x0bed5a50, 0xb6c9ac4b, 0xd0141f87, 0xd69513ee, 0xccd181a5, + 0x98f324d6, 0x914bd39c, 0xd7ad248b, 0x3cfe9d27, 0x493c1226, 0x56c59224, 0x3ce8d473, 0xf1394593, 0x88e6d852, + 0xf8e93abb, 0xe56f4f9f, 0xd90c86ef, 0x9bffa887, 0xf4de45db, 0x00ca1d6e, 0xd617dc25, 0xa10b0b48, 0x988f02e6, + 0x66c4be94, 0x6ca01cf4, 0x0ebfba54, 0x5e21a2a9, 0xc895766b, 0x14572069, 0x306aadbb, 0xb2f9e5ac, 0x15524542, + 0x4e3e6e1a, 0x0f214e80, 0xe8c9d23f, 0x3693579c, 0xdfe6f607, 0x37d6dafd, 0xe0680207, 0xb1a2cc95, 0xbeb0c346, + 0x3d3361f9, 0x02be1acb, 0xeb4469a9, 0x9cd3ed3d, 0x189e8c6e, 0x496620c2, 0xe9d74db4, 0x48e1f1e4, 0xcaf0ef36, + 0x18a9e6e8, 0xe206bfbd, 0xfe996164, 0xcfa64114, 0xc2996414, 0x8bf48fa0, 0x6b996b21, 0xee57bc0f, 0x5ca8bdc0, + 0x1b152045, 0x0155abab, 0x6b16577b, 0x19dda4dc, 0xe5f85242, 0xde147d3a, 0x12353fef, 0xb00a2813, 0x3d9e276b, + 0xbe9bf115, 0x8417d8e0, 0xa3052474, 0xe55daf6f, 0x1d1ed5eb, 0xe6992865, 0xeaa302f3, 0x5a927744, 0xd1d41c43, + 0xc84dda77, 0x91e44c6a, 0xe1d89c80, 0x394a6431, 0x1cfa0d5f, 0xa1262554, 0x4733d02d, 0xadf36cd0, 0xfacfc7d0, + 0x73405a67, 0x95ecb49c, 0x83c96da1, 0x0f5148e8, 0x4f4f51c9, 0x48cb8a51, 0x64da35ee, 0x17b28426, 0x95510efe, + 0x1ac0c255, 0x465cbb67, 0x640ce212, 0x59236630, 0x28f6647e, 0x18b76e18, 0x8a7c9d5d, 0x7c36f1b8, 0x35201640, + 0x41c66f61, 0xc98a2c72, 0x4163d5d0, 0xa24e664a, 0x74d24250, 0x8041484d, 0xa565473e, 0xbc7e62f0, 0x4bd6cb61, + 0x78bcae51, 0x3b4ea36c, 0x1611212a, 0x020742eb, 0x857afb26, 0xb0e6afee, 0xff6046c7, 0xcdbc50ef, 0x6e54cc29, + 0x4e597671, 0x73a7e851, 0x1b283b09, 0x2fb69f2f, 0x86bf1954, 0xdfaf0794, 0x0f769390, 0x3cb81796, 0xb92554ed, + 0x20a6dc8c, 0x9dbb2838, 0x9d3adc48, 0x5adca2fd, 0x46ca3724, 0xcc4bf8d0, 0x7ea5e780, 0x5966b2af, 0x275d5266, + 0xb0907ece, 0xbc209571, 0x871817b9, 0x7952d38c, 0xb7da09aa, 0x57a85073, 0xc49deee2, 0xd17ca291, 0x6d813442, + 0x1a8cf23b, 0xe174f57c, 0x2b5d1aeb, 0x21606bd0, 0x5f920a66, 0xab961fa7, 0x39239368, 0xcd948aaf, 0x2ab89f11, + 0x308bafd8, 0x416d261c, 0x41e38834, 0x4d50c12d, 0xb09a2ba3, 0xfc358cd1, 0x737c6f96, 0xca4d6749, 0xe2802659, + 0xd923490b, 0xc0ae6f1d, 0x39f9c635, 0x2440ebe8, 0x5e2563c2, 0xa39d63dd, 0x33ff2557, 0x0eacdf91, 0xefb92e11, + 0x89a87dfa, 0xfdebed45, 0x7c32b3a8, 0xc8d412a5, 0x1976d74d, 0xa7071b43, 0x2f6be137, 0x9b06c49e, 0x76ea165e, + 0x4eed428c, 0x352e940c, 0x52783be3, 0xdfbd68f4, 0xe03ffe89, 0x3dcaf3e8, 0xd5ef64fc, 0xae5e91c7, 0x7d08c9a3, + 0x1ccd8d22, 0x75eec3fe, 0x9ca32a9a, 0x27e8e01f, 0xfb269abe, 0x05efb437, 0x2f29abf9, 0x7e44d88f, 0x16562753, + 0xb2445dd6, 0x71ead8bb, 0x99caed46, 0x535345d9, 0xc3755864, 0x37314ed1, 0x991c0d3b, 0x86bf9cdf, 0xfbb2c7b1, + 0x8f479f66, 0x7be3784f, 0xd0ab006a, 0xb691e538, 0xe0617acc, 0xf049ecb3, 0x20ec27c3, 0x665b3336, 0x2717d132, + 0x1f35217c, 0xa1fe096f, 0xa1625e7d, 0x0a6c00d0, 0x183cc730, 0xb577fb35, 0xb5f6f11a, 0xf474f59b, 0x9bf0b73d, + 0x7ae9b66a, 0x434b215a, 0x565808b3, 0x082fbfa9, 0xb9f159fe, 0x7d3a86b4, 0xbf7be3c1, 0xcd2a4ad0, 0xe36f7889, + 0xb3270676, 0x54290af5, 0xd90dff13, 0xb375f1db, 0x01f3425c, 0x5c2acf7f, 0x0e7bf546, 0x0f00e862, 0x53e5e759, + 0x41d5b3bf, 0x9fcd06e0, 0x70758ebe, 0x0478792a, 0x9e1c1f99, 0xe4706b29, 0xd5f16811, 0xd5991551, 0xddd66554, + 0x8ca6a661, 0x40947195, 0x5b3315a6, 0x72b3db01, 0x53873d07, 0x1dcbf8e3, 0x43ac048f, 0x29edb51f, 0xa62d4dc6, + 0x6a100315, 0x26dbffb8, 0xf6d7356f, 0x1d4c596d, 0x7e19ace2, 0x0b2f9fe6, 0x27c753b8, 0xcb20706b, 0x68e253e8, + 0xa3de2ece, 0x963d5033, 0x9c06604d, 0xd7b25f0a, 0xc975cf37, 0x2aa8b464, 0x3b088e7b, 0xeb12a435, 0x98a8ce35, + 0xe506b86b, 0xeb1783fe, 0x620f3dd0, 0x1df3ce21, 0x7bb0fa8e, 0x147a57a3, 0xb25ef3f5, 0x6bbcafe7, 0x7503f7ed, + 0xf8ab19db, 0xe462f6d5, 0x27b2855f, 0x6c97b13d, 0xa85ab122, 0x465ed81e, 0x9d0f5a0e, 0x14dbcfd9, 0x1ff12788, + 0xbb241c6b, 0x71724b04, 0xb7b2c717, 0xb6ffd04f, 0xa7095b96, 0x0f5bc791, 0x9fed708f, 0x068f0869, 0xb7032fad, + 0xcaa223ce, 0x239a2c9a, 0x900b09c8, 0x67712709, 0xf5f205ff, 0x30d84f20, 0xbcda3ee1, 0x536fbb5a, 0x1b7377be, + 0x29cd330c, 0x6f671992, 0xf2a81a52, 0x5a81ceda, 0x574d1b8b, 0xadd19a03, 0x9126038b, 0xb065064c, 0x8dd6ae84, + 0xa75a36ee, 0x3261d885, 0x7a4d1f94, 0xfc29d2c4, 0xb47ebd88, 0x5423079e, 0x3971fffa, 0x0a8ffc97, 0xc2daac6d, + 0x531a5163, 0xf3cebbe9, 0x8c83fedd, 0xd11ddec3, 0xeab9a28d, 0x2a6a19d5, 0xb31c018e, 0x685a9fd3, 0x5bcba15c, + 0xca68d72a, 0xb95a856f, 0xc978a6de, 0x5c9e6065, 0x7519a378, 0xf21fb939, 0xbf511065, 0x4712c392, 0x8cb04861, + 0xc9ed9a80, 0x4b7d8fae, 0x80899721, 0xdfd39d4a, 0xa0314f50, 0x382bfe08, 0xa93317d5, 0x1c18b644, 0x133984ab, + 0xf788a652, 0x9bab727f, 0xf2ea5762, 0x7630b69d, 0x06cceba7, 0xab6c9700, 0x4ed5bfeb, 0xa423ca0d, 0x8a0c4b61, + 0x70f3a4d7, 0x4f3c6bd5, 0x644c8fba, 0xaf8f9e61, 0xb0c55cfd, 0x5ed301d7, 0xff820899, 0xb22f92a2, 0xae8f8ed8, + 0x8ebd3b90, 0x02c974a0, 0xed6396d1, 0x0b08c816, 0x32469aa1, 0xdef829c9, 0xfacd4364, 0xb68c88dd, 0x4716f7d4, + 0x641409c1, 0xe896d382, 0x6a24949a, 0xe1094956, 0x6ad76fc6, 0x2c22cde9, 0xdc122ac5, 0xa43c5c6c, 0x3febcd1a, + 0x2726bc4f, 0x330a1352, 0xbe0f2796, 0x3f9f2bbe, 0x1dbef733, 0xf26c425b, 0xe643f340, 0xe2d9421e, 0xcf1e4605, + 0x369c8198, 0xb1b3f1dc, 0x16e3dc24, 0x74ff22a3, 0xb5ef0eb9, 0x208eb731, 0xad146c17, 0xbe908e18, 0x6ad90d65, + 0x3f0360ca, 0xff7cb960, 0x7e237b69, 0xa5993381, 0x40dc3378, 0xa9f926bc, 0xe9a08592, 0xb6d67454, 0x12f34cee, + 0xd3dbd2e9, 0xce4fc54e, 0x717f8017, 0x3dc897df, 0x44726a0e, 0x4623e9c2, 0xcc34a551, 0x1a5ac8a6, 0xdd826ece, + 0x89d96dee, 0xfd22ec01, 0xd5029daa, 0x651d28d4, 0x773c4120, 0x6815acc2, 0x74e54091, 0xa07bcb07, 0x9b85ff66, + 0xc98d9038, 0xa66021d7, 0xffacb64c, 0x400ab073, 0x32c8481e, 0x61ceba25, 0x888ba41e, 0x3403fe14, 0x427ef930, + 0x7189018b, 0xa6c4b9b9, 0x6bc558d4, 0x8955d36a, 0x8b87f4c7, 0x05f685f4, 0x0a51fc53, 0xef258c60, 0x67375241, + 0xd98370c1, 0x4df15cce, 0xba259249, 0x38526373, 0x0c0c3420, 0x88a6fc21, 0xf5a90ddf, 0x89c598d7, 0x9887760b, + 0xc30213a7, 0x0452f882, 0x5018414a, 0x5b64258e, 0xaecabb82, 0x23753834, 0xcff0bfb3, 0xb0043146, 0x28655029, + 0x3f5cf8eb, 0x158a4cec, 0x9577ed02, 0x8eb772f2, 0x63c9bde4, 0x56e48130, 0x14cc7b50, 0x57332604, 0x69605ae9, + 0x02c2313d, 0xbb722ee6, 0x27cd4318, 0x34d668a0, 0xdec8b795, 0x10a311a9, 0x3ccc3a43, 0xab6fa4ad, 0x102286fb, + 0x94657c32, 0x3f6bb6d6, 0x751527d9, 0xd110b38d, 0x95b3337a, 0x79723903, 0x9d39d963, 0xbb0d8eed, 0x650356c7, + 0x64e30e72, 0x5be7fd20, 0x05b6acfa, 0x06d6e819, 0x852e1d1d, 0xcab58beb, 0x28f0c491, 0x3b8b792e, 0x0cf39c5d, + 0x6099e243, 0x0b4bbd32, 0xa6954d50, 0x2b526e8e, 0x0ca8ace9, 0x9b566e3c, 0x50e8ad6d, 0x00115c02, 0xcaf6deac, + 0xcbc5be23, 0x21d54555, 0x121fb8ff, 0x7f093fcb, 0x63e62027, 0xe8e178ab, 0x2dccb008, 0x996a0993, 0x84cfdaa6, + 0xd591875f, 0x68c8ca94, 0x085660a2, 0xd93a97f9, 0x21d9c16e, 0x1c17eab9, 0x2095f8b9, 0xbf737281, 0xc2368d28, + 0x93d66a8e, 0x7a45a734, 0x35cc1cae, 0xb45750f0, 0xd5a0851b, 0xe65acc15, 0x5c5a0a80, 0xd8fb0564, 0x48cd4ab7, + 0x2aa5d018, 0x3db6dd13, 0x0a2c18c5, 0x752bef1b, 0x9c4b722d, 0x84d6cb7c, 0x97cdba0c, 0x0a097f80, 0x98ce4f30, + 0xa6fb4bfa, 0x37d3a580, 0x8e7dcfb9, 0xfb69b496, 0x18096a8a, 0x2dbec39c, 0x6cc6dcd5, 0x90ac7c40, 0x8efed80b, + 0xa52fe1c7, 0x1e5f598c, 0xbc4a8679, 0xebe3211a, 0x58f33779, 0x416ddc30, 0x9917ba43, 0xe55cec88, 0x2fe794df, + 0xb6aa34da, 0xba8f112e, 0x30190deb, 0xa7e7e131, 0x171a84b3, 0x82a066ce, 0xa0d1e4d9, 0x438bcb10, 0xb4583015, + 0xfdecdd0b, 0x196086c3, 0x7675cec8, 0xc43cfdbd, 0x04f059bf, 0x840ff561, 0x73b064c3, 0xb22ea0ca, 0x965f12c9, + 0x2b0fd40e, 0x29aa70b3, 0x17d8f1ee, 0x47a40e38, 0x9cddc307, 0x818cd323, 0x907a56e7, 0x764e80aa, 0xeb8e3b1c, + 0xc0c7b6f9, 0x0a06963e, 0x9720c912, 0xe09fd11d, 0x8b2ca503, 0x9e24cb01, 0x1b3ff549, 0xebdae0f4, 0x0094a44b, + 0x21c42a2a, 0x07055bde, 0x6c2b4b8d, 0xb2211186, 0x511fc6ca, 0xad4a153f, 0x56bbb723, 0xb0b3d05c, 0xef93cb5c, + 0xf9d53772, 0x0d01ca81, 0x94081e15, 0xe670339a, 0x904f0d81, 0xb16b16cd, 0x03314aee, 0xd32845cc, 0x4d64a1a1, + 0xa1d63b7d, 0xdc139d29, 0x456bdded, 0xab061bab, 0xd4539ea7, 0xe623c5d2, 0xd5c213d0, 0x70c3534a, 0xc4158767, + 0x84465436, 0x5e8637c7, 0x688231e7, 0x91010983, 0xbfdd9ea9, 0x3cb2a779, 0x8ce708cc, 0x6965b801, 0xe7b03ffc, + 0xfe2834bb, 0xbc178a03, 0x1a2018a5, 0x5157549b, 0xa4be32d9, 0x53eac863, 0x33311917, 0x6b198a92, 0xf6b79601, + 0xe8041b84, 0x64414719, 0x31289fc6, 0xe8aef24b, 0x9a5d0a58, 0xac774136, 0x87d91e1b, 0xf91d9079, 0xdbf6c120, + 0x0517b9c9, 0x1eda8bd2, 0xbc7efa70, 0xe4dc1276, 0x3455bfac, 0x9d4b24b9, 0x5fbec86b, 0x086460ea, 0x516d7d1f, + 0xe334ab38, 0xbdeffbf7, 0x7a445e92, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1120_transceiver_0201.h b/src/modules/LR11x0/firmware/lr1120_transceiver_0201.h new file mode 100644 index 0000000000..3580b75765 --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1120_transceiver_0201.h @@ -0,0 +1,7741 @@ +/*! + * \file lr1120_transceiver_0201.h + * + * \brief Firmware transceiver version 0x0201 for LR1120 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2023. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0201 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0xe40ec3f1, 0x2e6de364, 0x0d111e22, 0x8dc5a2be, 0x0c18ca63, 0x7b889c65, 0xfeb6adcf, 0x8b791a54, + 0xddf3a6bf, 0x02188526, 0xac067920, 0xe6d4cbe8, 0xa5ca8f53, 0x4bfe40e5, 0xe5ada82c, 0x37c51fb1, + 0x88ce3d00, 0x360e89b9, 0x5ee5d6f7, 0x578fa140, 0x00180cf6, 0x9b4cbfbd, 0x40674014, 0xfe842c37, + 0x6f84a6d8, 0x70fc4093, 0x886f6d55, 0xd7d37f4f, 0xf99e47d1, 0x3b374794, 0x9a709d84, 0x65739853, + 0x4644f6c5, 0x231b2af1, 0xefd62326, 0xd693dcc5, 0x12315db1, 0x75ee45f5, 0x7c59a82a, 0xbe22b929, + 0xe73a743c, 0x44ab34d7, 0x685463f6, 0x469544dc, 0x01f4dc74, 0x6ebf6e8e, 0xd539fc92, 0xc4e350e1, + 0x48abf1cd, 0x431a73fe, 0x1c633fd9, 0xdade0f08, 0xacccbf48, 0xf52ebb42, 0x91e19ba2, 0xd0cb7d32, + 0xdc797424, 0x6d74dfe9, 0xd27dfca8, 0x3ae15b8a, 0xfcdef529, 0x0b94e47d, 0x3226f748, 0x29536f99, + 0x1dfada00, 0x9c8e569c, 0x3bc29e33, 0x91a9af70, 0x8889f606, 0x8f84d835, 0x8ce91881, 0x522b9626, + 0x10729b89, 0x5d02c83e, 0x5136b4e2, 0xdc2fba67, 0xfdab6cc5, 0x7fd59154, 0xc26ea7a7, 0x1ff1eba7, + 0x0d310185, 0x1050bb71, 0xf4a5d713, 0xfbc5b05c, 0x6153c840, 0xec6cfa8c, 0x0d96d7a8, 0x0e875768, + 0xeb501a70, 0x600f73d2, 0x3a955fa8, 0x1b1fd283, 0x7f8456b1, 0x5cfbe8fd, 0x8a9f5752, 0x37e0649e, + 0x27fb29f4, 0x3cbd574f, 0xfeb05899, 0x3d51932b, 0x9147642a, 0x6fad2c52, 0x0dc2b4ce, 0x73e105db, + 0x28b5bfff, 0x9ed799dd, 0xa28ed15e, 0x7d4eb427, 0x8d094088, 0xb2a6be1c, 0xf75afaea, 0xef17ffcc, + 0xe1f76f9e, 0xd817793f, 0x2f99e7f8, 0xef70c8a2, 0xa4061620, 0xabcfe341, 0x874163f4, 0xad756660, + 0x221791d0, 0xaef80ad1, 0x7cf34652, 0x7bd9d24f, 0x7567aa46, 0xd3e903da, 0x773649c5, 0xc589bc99, + 0x3bb41141, 0xd2e015d6, 0x637233e1, 0xf72017b3, 0x0481ea5d, 0x1224b644, 0xc665c5cb, 0x1a2c4bfd, + 0x48ed2452, 0x3de0a196, 0x00df0753, 0xfed65933, 0x181404f6, 0x57caf71c, 0x19f478ad, 0xd708f21c, + 0x2aa3c2b2, 0x2dc003fa, 0x490a8b9c, 0xed5ba562, 0x22665570, 0x01952eb0, 0x4d2dce49, 0xdabc0982, + 0x0e31c790, 0x241df08f, 0x67b1c2ac, 0x005a6d8a, 0x18b00513, 0xd9b38dd5, 0xe46ae3ac, 0x45035a8c, + 0xc69aed99, 0x30d0b876, 0xdc159623, 0xe7d9b456, 0x6b8d2903, 0x28cf7333, 0x2d6476f9, 0x6f7c1cc5, + 0xed4330d3, 0x6e216049, 0xf2735e26, 0x0ac79954, 0xe15398c6, 0x0130cc17, 0x70d9868b, 0xd8d32910, + 0xfb7f5927, 0x5d1c3f70, 0x815c4647, 0x0af57688, 0xdabd2b1e, 0x07a71ab9, 0x09c52f4f, 0xe561a24c, + 0x581edb20, 0x2e0fa97b, 0x3b547c55, 0x9e01e36d, 0x8943c65b, 0x6fea899f, 0xe3a0ec14, 0xb1982827, + 0x02b8073c, 0x22bafda5, 0x87b243c1, 0x5cdc01bb, 0x617882c8, 0x0dff981a, 0x5e29faeb, 0xca496777, + 0x43d6481e, 0xd8c60437, 0x07d54d08, 0xea20a304, 0xd0d45b9f, 0xcf74e74a, 0x177111e8, 0x95db4b03, + 0x36ea0540, 0x29ea47ed, 0x665e189f, 0x025c6808, 0x93c57e05, 0xc67de2fb, 0x45708591, 0x7a7aeada, + 0x6c9dd57b, 0x7a44605d, 0x3c8977c2, 0x4bdce9e6, 0x28db3804, 0x8c56573e, 0x09631d56, 0x2a724d7f, + 0x8c0609b6, 0x7f0960ea, 0xa18518f6, 0xdd7e920b, 0xec1b8770, 0x7f96a17c, 0x633f3dba, 0x18014101, + 0xaa4b20e7, 0xbf8a5e55, 0x5bc2d168, 0xea06674d, 0xe1e73072, 0x522a29c0, 0x20ba501c, 0xc6d7f581, + 0xb00123b7, 0x9e6c0b4d, 0x6b927f7f, 0x55da5252, 0xf1079b70, 0x7469e045, 0x030eea1b, 0x4dfc7d01, + 0xe1cb83f3, 0xacd94447, 0xc4d12251, 0xdaf94f42, 0x05592c6d, 0x41f3a0af, 0xf3565e48, 0xc1aef963, + 0x59e63065, 0xc5c9525a, 0x1231410c, 0xd8628e88, 0xed068d0c, 0x9359680b, 0xd1436640, 0xbdf2ef8e, + 0xcaba90f6, 0x965451b4, 0x07495a7c, 0x137cc872, 0xea47a11f, 0x36d12f5e, 0xc7b3b5f3, 0x6d31cda9, + 0x43bd5be8, 0x54ef0c94, 0x41a067f8, 0x3ab6f0d9, 0xd820034c, 0xd82da17f, 0x269d649e, 0xa69661f0, + 0x3ce52fb9, 0x26b86525, 0xf9b5491c, 0x7c35b78b, 0xc6e02dd3, 0x2b2624be, 0x7f23eb4d, 0x75ba6dbf, + 0xa6c39e7c, 0x4e5cfe73, 0xe48d096b, 0x961e102c, 0xc1423d23, 0xc99bdc93, 0x37134552, 0xa33fe30f, + 0x2cc89518, 0xda5abfce, 0x94ee724e, 0x7e1d6835, 0x6b4062ea, 0xabb1c2c7, 0x41456f4f, 0x22e68ab0, + 0x228c74ce, 0x72b5ca97, 0xdf13940f, 0x479a6c2c, 0x44c195d6, 0xd697172e, 0x22498cba, 0x9686a7cf, + 0x413c229d, 0xbdff69e4, 0xa9315a2e, 0x4ca07eec, 0x3807c883, 0x42926256, 0x09597130, 0xd304fa96, + 0x705706e5, 0x639c7028, 0x0636da58, 0x1902f513, 0x6382cd74, 0x3fc63b26, 0xcd488860, 0xa90fd9c7, + 0xe43bc778, 0xdeada1bd, 0x9e7d6d17, 0x98eddb79, 0x651ff08d, 0xe222c80f, 0x79ae1fc9, 0xad0c47cf, + 0x9d109d65, 0xdc96637a, 0xdffd92b9, 0xe84eecac, 0x2704010c, 0x05e4356b, 0xae5aa731, 0x5895026a, + 0x42324740, 0x6e94d98d, 0x76361653, 0x48b9a9d0, 0xc5e9fabc, 0x4c272ae2, 0x68fbc40e, 0x35e6680e, + 0x61f2388c, 0x1bdec364, 0x167b4d44, 0xedb19c46, 0xf2187b54, 0x540d1eea, 0xb8286b79, 0x8853903f, + 0x0d12b185, 0x326036d2, 0x6bf0b228, 0xc3626e79, 0x0e9695a2, 0xac50540b, 0xe87a0d9c, 0x27f7d55a, + 0xe66a3007, 0xc4b49109, 0x442d924a, 0x84b07bce, 0x910f9151, 0xd360750d, 0x5617e9a5, 0x88c37f5a, + 0xaa5eae4c, 0xc7184736, 0xb70a9b46, 0xff8144cd, 0x3849e135, 0x46b51c36, 0x8caae394, 0x39bbffce, + 0xa0c4ed29, 0x8350042e, 0x04a35f4a, 0x4fe0a450, 0xe242081a, 0x0aa9e5f3, 0x51960292, 0xd72bdbe0, + 0x58b82e18, 0xb2e4b92a, 0x5cebfbfe, 0x8d056832, 0x4e7b6ddf, 0x01d26c30, 0xdb48799f, 0xe97355a5, + 0xd96de1a8, 0x5babbac2, 0x406617b1, 0x1e1f5913, 0xfedbf0c4, 0x87659d04, 0x92ece485, 0xdd26f48d, + 0xecfff816, 0x2a34cab4, 0x839ec846, 0xc3795624, 0x68a69c18, 0x97e03ee6, 0x41b126de, 0xe74114ad, + 0x071d4aa5, 0x42b1d7d7, 0xdd6e320f, 0xb1bf147b, 0x5c010500, 0xf9061061, 0xef679550, 0xa49a4e6b, + 0x0a9c6fc7, 0x7b7d53c8, 0xb97322de, 0x62db6b8a, 0x5303285f, 0x320eb2dd, 0x4c8a3093, 0xde1e245f, + 0x1800b9cd, 0xc91fe5ef, 0x6499e145, 0x7ffb2aed, 0xddda2aad, 0x10066083, 0x4428daf4, 0x7bb2e635, + 0x87f7fc86, 0x087d21f2, 0xf11aa163, 0x24720973, 0x7587975c, 0x071a4d39, 0xc7423b91, 0x41f9ff06, + 0x20775014, 0xff194563, 0x3eb58d41, 0xd89e8070, 0x307d3097, 0x956f7544, 0x589e3f34, 0xd0841f1b, + 0x3750e630, 0x7b94dcf5, 0xc453eb0e, 0x5ef748f9, 0x466df6cc, 0x3798574e, 0x9280b939, 0x8e31bbb5, + 0xbdc031ed, 0x2f18c603, 0xf06d4b8d, 0x48fa47d4, 0xdb3cb9f2, 0xdbd1e7b3, 0x34548ecb, 0xb5c49cdb, + 0xbe9bb505, 0x7d1b510a, 0x81eba1d4, 0xd8050ed3, 0x8a8a0b2a, 0xfb1c5683, 0x3d3caeb2, 0xe18396ab, + 0x81f204a0, 0x59239b6f, 0xd6abacef, 0xcd5c383c, 0xf39d1af2, 0x914bb11a, 0x789a41f5, 0x23f86560, + 0x478967bf, 0xe093a757, 0xcc4276bd, 0xce079c1a, 0x3ec7c33f, 0x90f34ade, 0x5f21db48, 0x23f5f140, + 0xa22bb2cc, 0xba350d6f, 0x46f443c8, 0x09190c7f, 0xb6eb626a, 0x24467e15, 0x9e43d7de, 0x6b21fff4, + 0x0a0e8e92, 0x09fb820b, 0x76f3a4a3, 0x92f4f7f0, 0x5d4bcc26, 0x2b50f745, 0x08b59798, 0x07708ad1, + 0x36ddd45e, 0x387b7ff0, 0x7945c097, 0xa2baecfd, 0xf5be5fe7, 0x8930f167, 0x42c72953, 0xd25f5340, + 0x507f6bcc, 0x36c21989, 0x93767a17, 0xc6054067, 0x118e1547, 0x24b8069d, 0xfc76e317, 0x1c615e99, + 0x96c77d55, 0xae6f898f, 0xf6f36ac1, 0xac17557f, 0x21f5840f, 0x08621cd3, 0x00a347b2, 0xe6cc9e57, + 0x5912e4b4, 0x1006a740, 0x801aad25, 0xedb47631, 0xde32b0f4, 0xfb7b262a, 0x9884c3a4, 0x75535e5f, + 0x6f9af504, 0x2fb51c94, 0x661c30b8, 0x22a17e21, 0x3df66ea7, 0x7dda27be, 0xda018141, 0x918ce60f, + 0x8f7c0961, 0x207fb421, 0x53db4c48, 0xa10df6a5, 0x3c033421, 0x18eb6ba9, 0xb9c7b329, 0xcbdd2296, + 0xdd9dd657, 0xc8b6a378, 0x1b94117b, 0xa3922d58, 0xcdfd0235, 0x74726e0a, 0x96334460, 0x9b1fe4ac, + 0xfa48ab8e, 0x5cb775ae, 0x5f08fb99, 0xd366b9a6, 0x7eca65c3, 0xa552b3ba, 0xdf9ac3be, 0x6912b66a, + 0xecf73cea, 0x007627d9, 0xb9d83768, 0xde22003a, 0x4d035afd, 0x90b5b22b, 0xb3ad2456, 0x8a55984f, + 0xe79a55b6, 0x901f70b4, 0xc346b458, 0xc2e6713a, 0x5a33bcee, 0xc6f492ac, 0x4dad49b6, 0xd734a033, + 0x875ccce3, 0x11203e2d, 0x71eabdc4, 0x131d39b1, 0xc20ffd51, 0x9158abab, 0x6dbd2e74, 0xbf2cef29, + 0x57567956, 0xc8194833, 0x58799124, 0xc6f555f7, 0xafc6eb07, 0xe01e9a22, 0xb1ca2c70, 0xfed533aa, + 0xb866fa88, 0x4f8cfee3, 0x5952fc73, 0xed8f1876, 0xa5096725, 0x23d86851, 0xee779f43, 0xa1a818ec, + 0x42eac5d5, 0x83135291, 0x77d13c6e, 0xbf7b6128, 0x0e375e51, 0xe159e6eb, 0xbfa983a5, 0x3fe1bd14, + 0x96a3ea82, 0xc79f15da, 0xa60c9d3b, 0x2e37eb15, 0xe4365e59, 0x2fef36a0, 0x5abbd132, 0x084bca4e, + 0x8f7a850a, 0x0341eb6c, 0x5c2b3e57, 0x3498b743, 0xfe6ab7ed, 0x53fea1d7, 0x64648f99, 0x2e6310e3, + 0x743805e3, 0x7967fb5a, 0xfbe76d5e, 0xe99cbe27, 0xeeef70b5, 0x6d585d42, 0x61f2a42e, 0xd1e7b4e6, + 0x13413674, 0xe21685e4, 0x1dd181f9, 0xc28c4515, 0xf3c49d76, 0xfc94d76c, 0xbc6d1a14, 0xf3510748, + 0x658bb39a, 0x5d33455f, 0x90c4dd1c, 0x41cd68f9, 0xbdbbcb79, 0xddfdd6e8, 0x09d612a3, 0x49dd01d8, + 0xdc126853, 0x4a01503c, 0x8e6b6398, 0x5b8485b0, 0x8c284c47, 0xb9fda882, 0xc4c18ac2, 0x81410da9, + 0xbd5784f6, 0xe66add51, 0xd575c9a5, 0xeb06cb25, 0x715e4411, 0x8b9ab71b, 0xb7efe2dd, 0xef35121d, + 0x17afdb8f, 0x3a1f9247, 0x24a1cc91, 0xf5354ba6, 0x3272e42d, 0xae2bcfdc, 0x34ee8e3a, 0xd5311927, + 0xa25560e1, 0x989e0c0f, 0x415487e6, 0x9da46ca8, 0x883597a0, 0xef78d40d, 0x47149e96, 0x1dce2659, + 0x42bf135a, 0x5d08049f, 0x3ce6d987, 0x63adcd9f, 0x35dcfdda, 0xb616ff1c, 0x53c869c2, 0xb8b586b5, + 0xefa504c2, 0x0afa7844, 0x74028bae, 0x5a6a0f7f, 0x68eeba1e, 0xbadbf367, 0xe715ac5a, 0xb268e353, + 0x727d47d6, 0x84ae1fed, 0x5852020e, 0xa870eaaa, 0x0089aa5a, 0xb763ff7a, 0x1cbc90d9, 0x16b6b30a, + 0x1e75c533, 0xfe57889a, 0xa8f7167b, 0xccae26d1, 0xf69fe3e2, 0xe0f76b1a, 0xc66f4e93, 0xdf693ed6, + 0x46546416, 0x0d05aa81, 0xd60ca6cc, 0x49b86460, 0x08ec51fd, 0xe7d30c2b, 0xeb9e5e51, 0x669c29f3, + 0x5b8cf813, 0x609b5189, 0xad292614, 0x26a3723c, 0x5d8d4535, 0x49072ceb, 0x4bb3e2aa, 0x12cdb0fd, + 0x69a0fbef, 0xd98d11fc, 0xb0d4052d, 0xcef41f6d, 0x5db45c29, 0xc453554b, 0xaa1ddaff, 0xa72e76c5, + 0x0eb7290f, 0x0ac45d31, 0xa1a25812, 0x4deb6dca, 0x124a325e, 0x7eede869, 0x46a1e96a, 0xc5117a11, + 0x8da6447d, 0x7c282a36, 0x2384ac5c, 0x6d7e54a8, 0x0d41ddd2, 0x569f27db, 0x22bb8767, 0xad21e2d2, + 0xcb103544, 0x197e82ce, 0xe3fe14ce, 0xaf12203c, 0x169661a4, 0xc252c4dc, 0x66e19b27, 0x68e4bbea, + 0xd82cccf6, 0x0d349c4a, 0x8d8d5e78, 0xfc7d335c, 0x8cf86f3a, 0x06d975a7, 0x09c71324, 0x3f5aa823, + 0x84faf886, 0x6818b29d, 0xd46c5a07, 0x724a2699, 0x29042d00, 0xf1d57313, 0x34d5a4a1, 0xd45f29d1, + 0xf2713de1, 0x5bc19f34, 0x5a8ade5e, 0x00190277, 0x04623762, 0x9527b2b8, 0x2c0083f4, 0x4207c0b9, + 0x1bd83f03, 0xdb6ae33b, 0x37d56f3b, 0xe358bf9b, 0xf641829f, 0xd97e4d6c, 0x82f1accc, 0xcfd43ed1, + 0x9a58703b, 0xa041968a, 0xd695107d, 0xa4f14a93, 0x6fe0b643, 0xc4cf9257, 0xb75760e6, 0x418d9ea4, + 0x20c06586, 0x69807861, 0xa9022c67, 0xc86b0fce, 0x0637f21b, 0xe25d0dbf, 0xeb5bb006, 0x3bc700a0, + 0x83bef377, 0xcf6e658a, 0xf7e8a5d4, 0x1321fa54, 0x18fca65c, 0x2adc9b53, 0x2cb99e0d, 0x3d416b85, + 0xedadb937, 0xb28d5bc7, 0x1ae71790, 0xa596d115, 0xc5cb6896, 0x2598e1dc, 0xacf369f7, 0xa75656b8, + 0x52995bd8, 0x3d3a681e, 0x2c566af5, 0x43106812, 0xaf3ebcfc, 0xe5123036, 0xe8095019, 0xb2fca0fe, + 0xd6253deb, 0x9c849a1c, 0xfdf97762, 0x51e1712e, 0xf08a718c, 0xe07b5bbf, 0x34c4db6e, 0x1f8449d1, + 0xeecda332, 0x508d3011, 0x10be3f2a, 0x891e57d0, 0x7d9ef348, 0x47231aa1, 0xa998c903, 0xa9cbdfd6, + 0x8a8d00cc, 0xff4a6529, 0xb64eaf84, 0x28c81acb, 0xfc575901, 0xa7146947, 0xf4bdc3d7, 0x8078d96d, + 0x2f2d4b0f, 0x125200bc, 0x341d3a5e, 0xf5d68555, 0x16ffc99e, 0x7df19c48, 0x5700f668, 0xdebcfc90, + 0x1a35205a, 0x44dc6018, 0x27be5024, 0x565e75c5, 0x12e120cd, 0x66d09d59, 0xd0aea7d2, 0x077441e1, + 0x9ab809ef, 0x490499c5, 0x155a11f9, 0x65227553, 0x9f6edc33, 0xe84b05d8, 0x21d87be8, 0x185a20ef, + 0xb1eaa6d0, 0x751b2ec6, 0x7f42e55b, 0xd737f306, 0xe8c279bc, 0x72c6b83a, 0xa5c4f56d, 0x06f332b5, + 0xa37a7db6, 0x39d56e79, 0xdc709d60, 0x36d754ee, 0x32cdbccc, 0xc909efea, 0x1cdccd97, 0x6b6ff676, + 0xdfca29da, 0x8ccf9b70, 0x6728b432, 0x6551ba2b, 0xb5c76020, 0x9b1e9478, 0x1aae6422, 0xe063519d, + 0x6ef3b1c9, 0x8242f41f, 0x18340f77, 0x3a6ef03e, 0x2153a27f, 0x7f620d5a, 0x60a514b4, 0x5bb45530, + 0xede53976, 0xc759437b, 0x21bb37ac, 0x07985b34, 0xb223e369, 0x1a5f2dd0, 0x24208eae, 0x9a0dcf21, + 0xf8e09d53, 0xc1f0ab46, 0xb7b2a483, 0x126b982a, 0xd8aa41ef, 0x1924c1e0, 0xf939fad2, 0x76911417, + 0xb6fdb601, 0x69f006db, 0x93a0cce8, 0xbe366640, 0x9b9cc086, 0xdf834c27, 0xd69b80cf, 0x0361220f, + 0xfbf5562a, 0x604f6da8, 0xa4a4dcee, 0xfeaee9bf, 0x9f895dbe, 0xa865f4dd, 0x1260a93c, 0x473930c2, + 0xde5d7983, 0x965faa62, 0x42f1aff8, 0x00d3c529, 0xebe14412, 0xaa24c7b1, 0x3694af7c, 0xbb48e444, + 0x3ba7b594, 0x2525d7ab, 0x864069d6, 0x3ab20b06, 0xe0abc6d4, 0x5f2b28a3, 0xdccdc2ec, 0x35f0897a, + 0x5f6af545, 0x8222ab0b, 0x20529b31, 0x7353d707, 0x641fde8c, 0x9d8f3be4, 0x1e93d223, 0x8db8177f, + 0xbacf47ec, 0xf7300bab, 0xbbd170fd, 0x7f551c4d, 0x7548d78c, 0xcf548b00, 0xcb3c5a1d, 0xa94ce464, + 0xba1c3f16, 0x8797720c, 0xf645871c, 0x3a13c4e0, 0x75c8a8b0, 0xac5f9cf3, 0x64e15295, 0x5b9a7975, + 0x5003b699, 0x95a730c2, 0xe3f06bce, 0xba597cc6, 0xe31afca0, 0x85d9447f, 0x1d06ea0f, 0x0d533a38, + 0xd6135187, 0xf14298bf, 0xd7fb741d, 0xd9d11cf1, 0xb23dd90e, 0x94aebb89, 0x2665fd1f, 0x9e6b3c70, + 0xcd7580c3, 0x947c2f8e, 0x5f59d777, 0x2eac07a4, 0xa290813e, 0x9ec6d20a, 0xea45a6a4, 0xbf2a9bd7, + 0xaa2a411d, 0x4577b56b, 0xaa254779, 0x14542fb5, 0x3a7bb0db, 0x59327fbd, 0xbce6ea3d, 0xa9f9a42a, + 0xcdcf0036, 0xebd6e6dc, 0x5e7a175e, 0xa7fd7f48, 0x385ea602, 0xab9bd93a, 0xd095f162, 0xe289e4d4, + 0xa4cb30a9, 0x221c4c2e, 0x33e57ca8, 0xace3e0ad, 0x4fe8f7c3, 0xf98158cc, 0x2f0beebe, 0x64910a12, + 0xaf42c2b3, 0x93c322d0, 0x91dc75fa, 0x699501bd, 0x3cea495e, 0x38db4604, 0x0de5bb07, 0x5090972a, + 0xf24ffd64, 0xcd7e92eb, 0x47e52a8b, 0x20f7df88, 0xa8ef60ee, 0x0e5cdb8c, 0x3aa8c655, 0x0135fe7a, + 0xe54b93f3, 0x867da1c4, 0xf31ded07, 0x6ef1c757, 0x3e2f4f34, 0xc72b1f36, 0x4e0242d6, 0xc98ac3e2, + 0x9099c94a, 0x5a3163c3, 0xd8b834d6, 0x6c10bdae, 0xdfc62be1, 0xbf38d48e, 0xe5dafba3, 0x3602619f, + 0xc0a6e2d0, 0x940c5d18, 0x96dd2d6f, 0x1f7d8077, 0x6e3348f0, 0x3158e352, 0xd7336941, 0x0bb7615f, + 0x3eb1e398, 0x2b52c836, 0x25bed2b9, 0xaa656241, 0xb4409137, 0x16640ed8, 0xcea1f92c, 0x01fef729, + 0x6726fc85, 0x1828b5f5, 0x874dec34, 0x1d98b75d, 0x599974f5, 0xff4b15ab, 0xd5deda5f, 0xe01a6021, + 0xa4f4541e, 0xa74739f9, 0x246a5eb9, 0x5d5cd126, 0x5c62ba91, 0x672e513a, 0x73b23c9c, 0x5b7bd2a3, + 0xc149dee7, 0xb40f7997, 0x83805929, 0xd6c8102b, 0x9b6e0af8, 0x9838db3e, 0x5da26aac, 0xa10ac01f, + 0x5973b5cb, 0x1a3854e4, 0x8a7a8766, 0xa5c018f7, 0xdceb878f, 0x752f3fa0, 0xf23ea57f, 0x202aabc6, + 0x32d44679, 0x52de69ca, 0xee416873, 0xf5c49c5a, 0xe812dc1f, 0x8359c59d, 0xa8a7b0c0, 0xa0c6818c, + 0x35997fb9, 0xfe86d380, 0xe3eb11fb, 0x794b5f8b, 0x7d9d97da, 0xf86b3455, 0x1bcf107d, 0xaac3bdb1, + 0xbedcd7bf, 0x6861c03f, 0x95ecced1, 0x80649272, 0xf19560c1, 0x65ca922a, 0xa98e1e19, 0xabab946f, + 0x6f2abae1, 0xa050776c, 0x3c4c535d, 0x2602043d, 0x4c8ecd01, 0x794bb0ea, 0xcb3455bf, 0x3eb879bb, + 0x15b4270d, 0xe2d91679, 0x18f7d8f4, 0x0aa35557, 0x3fcf52ec, 0xa82e7ac8, 0xb0c590ae, 0x795962d2, + 0x6feced52, 0x07b0d3df, 0xdf6a1ac2, 0xeccce470, 0x13686956, 0x787697c5, 0xe236cd32, 0xccb5c26c, + 0x80adbde8, 0xc7a56e48, 0x4045febe, 0xe95f62bd, 0xd7c079c6, 0xa64109d5, 0xe5b58b5a, 0xe9481c06, + 0x4a09405f, 0xbb72da56, 0x6be6def1, 0x431ad614, 0x906fcc3a, 0xdacf2e3e, 0xd730df18, 0x5a0752f1, + 0x50349f63, 0x0be2ab24, 0x8adde467, 0x37aeedc7, 0x3f094a6a, 0x46785eb0, 0xf0ec8b8e, 0x1603596f, + 0x50f7d6d0, 0xc596fe60, 0xf87cdcf2, 0x58fd7e05, 0xa0b147bf, 0xc966fdb0, 0x8bb7944e, 0xb01b3dd3, + 0x154dc0be, 0xcc46ffd8, 0xfc602dc8, 0xc2e4a5cd, 0x28560ceb, 0x2cb85a45, 0x25741843, 0x65765334, + 0xf2153505, 0x7cf0933b, 0xe6032269, 0x6ce42c4d, 0x84d79493, 0x7c544b51, 0x83a2f6d6, 0x15825146, + 0x4c97c5fa, 0xa30bc268, 0x7229ab6c, 0x3b8b2405, 0x4d2a5839, 0x4f81fc43, 0x5d3c150f, 0x55eb8007, + 0x9ac52976, 0xe48f44c1, 0x26f80ad1, 0x0ff7f2aa, 0x6e0bc4fe, 0x42888da3, 0xd2985a02, 0x076a0b41, + 0x57d8fa11, 0x6c15c8bc, 0x559e17b6, 0x149686f3, 0xd60699f3, 0xe97314e2, 0xdcb81f26, 0xfada49bb, + 0x2311fa89, 0xf2955cbc, 0xff27a561, 0x1262a3d4, 0xe4a013b6, 0x6c362bb5, 0xc44364ea, 0x1181e36b, + 0x5ff77355, 0x09d541f1, 0x0cb45f19, 0x81647b8d, 0x48933610, 0x4a7d90d7, 0x0fe629bb, 0x747cdaf8, + 0xea936a10, 0x4eba9753, 0x367e67bf, 0x3d47bd1c, 0xa52ab29b, 0x9e4dabd3, 0x09492aa2, 0x4efcba3b, + 0xd4aea759, 0x77c71e45, 0x27fdae3f, 0x4061e717, 0xe28335dd, 0xdf3a1be3, 0xeb189d3d, 0x59fc56cf, + 0x80f0be61, 0xbd4934bb, 0xf8e20cbd, 0x31aa0ea9, 0xe4fe73fa, 0x1dc61ff6, 0x2762cf7b, 0x48428f51, + 0x6a01f3dc, 0x72dabd5a, 0xb9bc87d7, 0x5c5199cc, 0xe57d7f53, 0xa4369df0, 0x448bea52, 0xee3dece3, + 0xa382c4bb, 0x57e80796, 0xf9562ac6, 0x410fd3df, 0x1e0ec03e, 0xf50552b8, 0x9ec16fd1, 0xa89c1671, + 0x79073870, 0xd1746885, 0x3fed4990, 0x8a7a072c, 0x9e79adbf, 0x0878b061, 0x2414db8e, 0x540fcb03, + 0xa021864a, 0x7d99cd74, 0xf3b05204, 0xfc6a8097, 0x31cd9709, 0x9ff6b18b, 0x3d30aab6, 0x6a067f56, + 0x743def41, 0xe55729fc, 0x2948ee26, 0x59459eef, 0x455c5933, 0x91eeb9c0, 0x9bd6d2a5, 0x4699825d, + 0x4f83c32f, 0xeedfca03, 0xf79f70ad, 0xb98d16a3, 0xa082260c, 0x96e2a9bc, 0x17f13876, 0x82fc417b, + 0x6c38c121, 0xf037e782, 0xda5d351e, 0x379d556d, 0x013cd2e9, 0xfe964b86, 0x87ffd641, 0xefb0a44f, + 0xc9f61088, 0xbd9df719, 0xc4e793ca, 0x8a3c4d59, 0x200c5d9c, 0x57ff7a4c, 0xc161c39e, 0xc9f15106, + 0xe7084106, 0x8b65ae2c, 0xcd653f9e, 0x46d5fe6c, 0xc7444371, 0xb00a219a, 0x917ce844, 0xe5339d49, + 0xa816382f, 0x41b4abcf, 0xbcc36b3c, 0xe14a47a4, 0xe82f26fc, 0x70642f97, 0x09c3ec40, 0xf0f39839, + 0x7838388f, 0xeb19a121, 0x971756fd, 0x005867df, 0xe5dde703, 0x53a7e478, 0x2bd9bd4e, 0xb1e668f8, + 0x208e7e01, 0x03d7316d, 0x28acd3b4, 0x7263f4c7, 0x5040ec6c, 0x0114f9dc, 0x8071f319, 0xb091c8d4, + 0x8ec2de06, 0x739ea1c0, 0x0568cb86, 0x2c9fc0c6, 0x5c5c5197, 0x0b3d6d23, 0xe0a44e0b, 0x7c20319a, + 0xa4e2aa23, 0x3907de2b, 0xf0626313, 0x0060481b, 0xdbfb40cc, 0x2355ee51, 0x23019fad, 0x86e40b9e, + 0x2a3fc38f, 0x4ba48f2b, 0xc699e4b3, 0x0b59a0af, 0x63ebc03a, 0xb4b72acf, 0x90f529f8, 0x5af1ab09, + 0x0f65c132, 0xfef8d284, 0x89a1aa67, 0x339e1f88, 0xd015909c, 0x4f4aafed, 0xb2ecd8d2, 0xb7d46231, + 0x588f101f, 0x5caa1707, 0xa8865598, 0xb193551b, 0x7f669997, 0x806515fb, 0x08c8830c, 0xce05649a, + 0xc6fce92a, 0x9af488db, 0xc51d1652, 0xd2d836ec, 0xdf08de8c, 0x78c368f6, 0x14923f1c, 0x2bb126e2, + 0x22428659, 0x8b189093, 0x2d7375f8, 0xfb3c505a, 0x094fd854, 0x2649fa5b, 0x4ab54b9e, 0x20558ff6, + 0x2108a3f5, 0x44cbef3d, 0x610fa394, 0x3d87f96b, 0x4bea0907, 0xe886d34e, 0xa142cd42, 0x89889610, + 0x9b1f739f, 0x08aa0536, 0x4066be6f, 0xad3994fa, 0x0161b1ed, 0x32a0558c, 0xa8e42956, 0x1bd330c3, + 0xaaf832a7, 0xfa1da89f, 0x5afc1a9a, 0xe52ca062, 0xe6673acf, 0x98136bd7, 0xefc19228, 0x05c7e39c, + 0x8cfefc4e, 0x6ace948e, 0x4af8d3ff, 0x6297d20e, 0x88fe5b9e, 0x48f2426d, 0x1745c951, 0xb02e5fae, + 0x5405597b, 0x48bcdead, 0x86e00766, 0x5253a92c, 0x4b0a5fe6, 0x928c00da, 0x79c09f4e, 0x8c1e3051, + 0xaf8ca94c, 0x75e5285d, 0x59aa8010, 0x36acf4e5, 0xe4a8d6a7, 0x3b4fa73e, 0x6d1b40ba, 0x1cd84347, + 0x3aef6ee3, 0x1b1fdfad, 0x827d1479, 0x70d38158, 0xf71b3f2d, 0x8e430cfb, 0x8ae336eb, 0x1b2e9a29, + 0xc610fd7c, 0xacb770bf, 0xae6350ec, 0xd0f8bb2c, 0x215fe071, 0xcbc4e7ce, 0x613ed258, 0x1df9358e, + 0xa700d6c1, 0x5d2f7220, 0x04bd4e9d, 0x90e02963, 0x14e3fd08, 0x224edbec, 0xb7c19636, 0x85468a5a, + 0x93efce59, 0x69d250fc, 0xec2876f6, 0x49dc3dcf, 0x412e2208, 0x0d6084e8, 0x39a1ac3c, 0xdd91abca, + 0x50bbb2bc, 0xa76783bd, 0xfe5ff480, 0x7275634c, 0x476d6d7b, 0x9650880e, 0x44b0cb64, 0x52a2b4cb, + 0x4d0da1d6, 0xb833f48a, 0xb96d2803, 0xb9665ab6, 0x3226a5c3, 0x0738bbbd, 0x522c9e58, 0x20aec2ec, + 0xcfd3145e, 0xbc94655f, 0x90214e84, 0xa9144507, 0xc21247f9, 0x09fef625, 0xe91839ec, 0x5c452c10, + 0x1bc8f664, 0xe9d2f833, 0xced529d4, 0x21295352, 0x16aa5abf, 0xd52ce199, 0xdd309264, 0x7e3beb74, + 0x2e1edf0e, 0x10644584, 0xf21ce68e, 0xe628195c, 0x4533b164, 0x578277d0, 0xc0502aa5, 0x12f16639, + 0x82b2c582, 0x94f5be06, 0x76a599bb, 0x47f2c39e, 0xe79b2432, 0x37047f4d, 0x50fcf0c5, 0x505171d9, + 0x47b86725, 0x0fdd488f, 0x4f45959c, 0x27dd3bae, 0x6ce4d670, 0xaecdc80b, 0x562eaf33, 0x4f817abf, + 0x783c7a92, 0xb03bb05e, 0x93179c08, 0x7ac3f7fd, 0x005f6451, 0x9d90aff3, 0xa03f78f3, 0x83900f7b, + 0x2025f9f5, 0x5946ecb6, 0xa94a8d99, 0x21e7b23f, 0x7c027f51, 0x8ebc45d4, 0x0128b098, 0xc6e4a02d, + 0x0648feaa, 0x6d4e2840, 0x5556f3e3, 0x26eaae79, 0x45b8783f, 0x16604a12, 0x8ce0ad2c, 0xb7095c4a, + 0x81f3600e, 0x038aaeeb, 0xb7ae13d6, 0xd8a6a60a, 0x720d2657, 0x765d36de, 0x48e02d6a, 0x40e85a3a, + 0x574c8204, 0x6a2b0ce2, 0x584e8e31, 0x6f0f7945, 0x6e79ba1e, 0x3448a78f, 0xf7fe13a9, 0x8583295d, + 0x4899ee44, 0x9da3219d, 0x392c6f8c, 0xe3bbf10f, 0x6d9ee64a, 0x7318d65b, 0xe5b8c19c, 0xc7f6745d, + 0xdd1654ab, 0xe644c8b0, 0xbf18ac85, 0x90fbb505, 0xd015bb10, 0x40de472c, 0xbd369d10, 0x6c4ef075, + 0xc91ee678, 0xeed6f8ee, 0x3f493086, 0x114b142f, 0x63e7518c, 0x9b7cd9fd, 0x47541b3e, 0x4bfff2a5, + 0x9872065d, 0xe581c160, 0x441caeca, 0x106fa5ed, 0x7ad46754, 0x8b6e1749, 0xe8ec7aae, 0x5212a8a0, + 0x8e1785b1, 0x8c3fb093, 0x47a5708e, 0xb8b00292, 0xded8234d, 0xc2dce4d3, 0x71666d54, 0xce726ddc, + 0x32515d42, 0xd8a2db1b, 0x10039b7e, 0xe8cc981c, 0x11ca3487, 0x44a6796e, 0x4a02a99e, 0x8e8198a5, + 0xe28aadc3, 0xb552c40c, 0x087dab84, 0xa0e119f0, 0xd9d20554, 0x96293883, 0xb4166988, 0xa2bfb42c, + 0xb277ecb6, 0x59de4fa8, 0xb4d145b6, 0x4e9992a8, 0x471f3b27, 0xdc52de08, 0x92bf7cd8, 0xb16dceaa, + 0xbee5c27e, 0x33726eb4, 0xf8dcf069, 0x3c36201e, 0xfaf3c7ee, 0xa44658ea, 0x4a32369b, 0x64574d3f, + 0xe81fd429, 0x09367bb5, 0xfd676b89, 0xd75868fe, 0x3b019e85, 0x528beaf7, 0x5e83b61e, 0xdf756e8a, + 0x48e5f913, 0xee442e89, 0x95686829, 0xa8d2d113, 0x16343319, 0x7b1c1863, 0x25af5458, 0xb24d9637, + 0x2479859c, 0x6374320c, 0xbaf20ee7, 0x63022777, 0x0bc98b0a, 0x252711c6, 0x7ffe7865, 0xaa04e00d, + 0x634a9a4b, 0xd98d1440, 0x188f03f9, 0x34b0e895, 0x85c1291f, 0x453cf4a6, 0xf278c103, 0xc3daa4f0, + 0x5e56ce06, 0x6453d0b8, 0x6f27c07c, 0x7f717034, 0x88fcc532, 0x95d41a2f, 0x711c153e, 0xdd3916e6, + 0xb128b7a2, 0xd9c0862e, 0x930ed335, 0xf74d1625, 0x1af23d50, 0x2b07c2f9, 0xe7e0ea19, 0xce8c301f, + 0x4fffae39, 0xa45edb4e, 0x4f0c2d52, 0x10ba175e, 0x32392e71, 0xb25eafeb, 0xe6d06785, 0x12988523, + 0x25314a30, 0x9ab25ecf, 0x6440fd6f, 0xf65ad039, 0x44c43775, 0x0ac2e26a, 0x4be32d12, 0xe8e77b05, + 0xb2562c14, 0x6c517023, 0xf81392d4, 0xaec8f89b, 0x3160297e, 0x90d7ad2f, 0x16aad2bc, 0x04c3434b, + 0x92be4d24, 0x7fe6d22f, 0xa991d69c, 0x75e6db0d, 0xc8fbe8ae, 0x733c4a95, 0xc2e13868, 0xf072a740, + 0x1dd05714, 0x2d018ba0, 0x4da5d752, 0xdb787bd2, 0x57d60e32, 0xb3227a1f, 0xdfcdab51, 0x6cf084d2, + 0x922b58f9, 0xa46c2caf, 0x77552017, 0x7db6a565, 0x9656d4df, 0xf32c6a1b, 0x83c21da8, 0xfac0c813, + 0x54cbef5a, 0x237c854b, 0x1c10f780, 0xb0c9930f, 0xc5ac7cbf, 0xb6bc3d61, 0xac9fbaff, 0x7abee254, + 0x0c2a044d, 0xf6e7a25d, 0x316a2d6d, 0x0bbeb3db, 0x754a5349, 0x8dc06928, 0xdae98580, 0x544c05bf, + 0xe1659f13, 0xa0ccc02c, 0x424bb2a8, 0xcd85cad5, 0xa35592be, 0x41bef1f4, 0xdc7292c1, 0xdd45b14b, + 0x15db16f3, 0x9fb10ac6, 0xb6848492, 0xded95f31, 0xa8b07a07, 0x3d4444da, 0x76c02596, 0x9fbd96c1, + 0x84267fca, 0xb5eeb898, 0x03bb2177, 0x80b48361, 0x18a51425, 0x88979c35, 0xb4c78ee1, 0x8262e91c, + 0xa77a2537, 0x42c1d877, 0xf9069666, 0x8d43f19d, 0xa8c3101d, 0x640d63eb, 0x5c5f9624, 0x1596f7de, + 0x169f5a76, 0xf73c3690, 0x8ce6bb69, 0x7d87b2a9, 0x9fe3c277, 0x2535167b, 0x8c31e4d7, 0xaccc16d0, + 0x1d8bdd1d, 0x1dfcf578, 0x967839f6, 0xa23eb074, 0x41fe0731, 0x9a0b6850, 0x35df8d84, 0xd81e0e03, + 0x02ae7c48, 0x0d93d6e4, 0x715217cc, 0xcef64b7e, 0x1b798f0d, 0x3249a075, 0xb72410cb, 0x19afc5de, + 0x872a8513, 0xa57d6311, 0x7a1925eb, 0x7dd3b577, 0x453d8250, 0x18453453, 0x175d52f8, 0x23e41045, + 0x42e8c6c5, 0x58a364f1, 0x79869a4a, 0x217a152d, 0x1e69640e, 0xc26f1a51, 0xc8690d64, 0x215e6258, + 0x9bbb1a15, 0x3864b04a, 0x7512e26d, 0x49e07680, 0x987889ee, 0x967cfb3e, 0x2aa8ea72, 0x2022dc99, + 0x70317a92, 0xb5075533, 0x0c35fd74, 0x5cfc784d, 0xb2d915dd, 0x4ef75f49, 0x283244bc, 0x2389835b, + 0x5da7330e, 0xcc40dd8b, 0xe8ecf896, 0xd2f72fd4, 0x4ef571d7, 0xc66fd884, 0x8369beaf, 0xde7b381c, + 0x2768fdd5, 0x0fcb8c23, 0xac80a71a, 0x9003de03, 0x985e9c32, 0xa76fe5ea, 0x1b2c1705, 0x460d1d57, + 0xf7d02e44, 0x480c20e8, 0x5f99767d, 0x5e63ea66, 0xd8439129, 0x5e380a12, 0x03b9e1b5, 0x604a9b3a, + 0xc27f2bb4, 0x3e9240f5, 0xf6fc8c1c, 0x645a8d51, 0x22d09a28, 0xb7eab246, 0xe336bf88, 0x8c2bc2ac, + 0xf3407f72, 0x942d91ba, 0xdfdd7c11, 0x6d5545fa, 0x9c73f44c, 0xd09c3131, 0xd72c2617, 0x57092a9e, + 0x7e495ac6, 0x594c701e, 0xddc23229, 0x50d34ecd, 0xf9360ec5, 0x450a98e5, 0x29b75aad, 0x41acb518, + 0xad27c2f0, 0x6d7eac57, 0x9fe34802, 0x04809995, 0x383e9fd3, 0x28ad366d, 0xb1feb8cb, 0x857c204a, + 0x7cc1ded2, 0xe839ef98, 0xe87e0c60, 0x819fbf63, 0x4e6c6659, 0x46a6d5af, 0x65fb499b, 0x9b39e72f, + 0x83ee37f0, 0xa3f66856, 0xd66178ff, 0x499711b3, 0x22d15f9e, 0x93968950, 0x5f71f698, 0x6a366613, + 0x16cd5a03, 0x7f0b2fd3, 0x9e2a2112, 0x9041cc8b, 0x3ace099e, 0x1bf73b62, 0x2f77f68b, 0x2f886066, + 0x62494906, 0xbb7e696f, 0x141b3abe, 0x78314af6, 0x1d2b2d06, 0x1a6ccd31, 0x00f75ddf, 0xebfb9940, + 0xa01aaf46, 0x86c1b48a, 0xedfa6b3c, 0xcce4945d, 0xf2a86aaa, 0x47923682, 0xea04c1a6, 0x0e44aa8b, + 0xfc846493, 0x91775801, 0x0d02d954, 0xa56c0429, 0x25ba0363, 0x2f7bd38a, 0x04895b59, 0xb0c44c17, + 0xca4f2fff, 0x8be1d0b7, 0xce9964dd, 0xe5605a9f, 0xf4ca686f, 0xcc05c321, 0xc6f87517, 0x178438f8, + 0x0c32d93d, 0x025f6f9f, 0x0d9b28f2, 0xec5c0d07, 0x440e1a1d, 0xbeb33c3c, 0xf9a4f4e2, 0x1533d217, + 0x25bf7c24, 0xfd05e27c, 0xedfe0a92, 0x620a7e2b, 0x57c8e4f2, 0xc84f113f, 0xbbd45c4a, 0x04ea7573, + 0x46f0a169, 0x58e6c01b, 0x6fc63a1c, 0x2acd80ec, 0xd8fd0d14, 0x8bd726b2, 0xca02ea67, 0xb80c9eb8, + 0x8c251c81, 0xf8134e56, 0xa35bc05a, 0x06c9c70f, 0x1e564858, 0x0d886592, 0x4c286bc1, 0xa062f732, + 0x23cfc25a, 0x230670fc, 0xeec0a784, 0x9212d090, 0x0fa9bbbf, 0xd2cfb258, 0x1c522223, 0xbb930ac6, + 0x1b081fe8, 0x6a62b50c, 0xb7c0d9b1, 0x29f6f90d, 0xf3380418, 0x4d918688, 0x74244761, 0x5e22d62b, + 0x7b80f452, 0x472da952, 0xcc45e891, 0x31b07d3d, 0x84ea6937, 0xe8c85ec2, 0xe81a124c, 0x7762a4f7, + 0x23afd789, 0x2d730eea, 0x64595c46, 0xbec12827, 0x1a75eaf1, 0xdd6cce28, 0xdda2f060, 0xafad3c81, + 0x4e765cbd, 0xbbe67674, 0x07d9eae8, 0x8685ee5c, 0xb89a7e44, 0xd331f2cf, 0xfa6a570b, 0xd0bb0464, + 0xa6e81308, 0x853a2632, 0x1cdaee5e, 0x167e3821, 0x10fcbdd4, 0xea4c5aff, 0x646a380b, 0xeec6815f, + 0xa4db4723, 0x6414f896, 0xf421e0fd, 0x23980084, 0x0e3bafd2, 0x5775950e, 0xb878de30, 0x1f0a4401, + 0xbcafca7d, 0xa8384a64, 0xb8bab0bf, 0x36e81e41, 0xbccceebb, 0xc8be648e, 0x97b64081, 0x2e90be1b, + 0xda6af37d, 0xc917ee8c, 0x57541511, 0x566b2982, 0xcab6d81c, 0x98ae1b13, 0x026deeb6, 0x5294bec2, + 0x4520e6da, 0xaacb1eb2, 0xab62f310, 0xf929607d, 0x39680654, 0x9b7fcb03, 0x7fff099a, 0x08eb3f1f, + 0xaf6be42a, 0xe00e6fbd, 0x95c9b2eb, 0x7ed40176, 0x5a953762, 0x5f818112, 0xa7ac04ef, 0xc2c80994, + 0x6df8dc53, 0x2dc13e1f, 0x8d4813e3, 0x0875e550, 0x5c224761, 0xc1f2741f, 0x72b22a41, 0x19fa390c, + 0x3dbbc1a1, 0xe81207a5, 0x48fc5481, 0x135fb830, 0x8e389950, 0x7c4f94cc, 0x574cf0e9, 0xcd27247b, + 0xedcbda73, 0xcc7b8124, 0x1ec9b66c, 0x11c55f1d, 0x35f39f02, 0xacd26a6a, 0x4982daa9, 0x21a6313b, + 0x7a9ef44a, 0x20d17a8f, 0x7f87ad9a, 0xfc8ab5f8, 0xe1e52524, 0x3aeda48f, 0xd9d4ac0e, 0x7b88eebb, + 0x9a34ecb6, 0x1043fe70, 0x116e2614, 0xc3f85e2b, 0x6f4551e6, 0x709ced30, 0xfc77b1bf, 0x7d50b3c0, + 0x7574a8cd, 0xfb715b07, 0x4c070657, 0xc866b34a, 0xa3637b84, 0xad26a597, 0xadba840d, 0xa9ec0d8d, + 0x0cd42b3a, 0xc1723a85, 0xf2df2cde, 0xa3a51109, 0x482d2cab, 0x07ccddb4, 0x70837113, 0x4bf813e3, + 0xdd89900e, 0x1db832b2, 0xa170e449, 0xf5886f2e, 0x3b197fb2, 0x34802864, 0xf6a1f01d, 0xfa232ced, + 0x1711e822, 0xac109d08, 0x18ae3306, 0x4144feaa, 0xdbe26b88, 0x453b887e, 0xa1acfaf4, 0x9ab4338b, + 0xa6b98f85, 0x040b2b95, 0x432d5bf0, 0x5d0bc44c, 0x5830827b, 0x0cc7073b, 0x0cd8d123, 0x62209d9f, + 0x73607ec4, 0xafc713c8, 0x618fa749, 0x64a91c46, 0x527ab4ca, 0x41b83ac0, 0xfadf83cc, 0xca88034c, + 0x21e2f17e, 0x4fa57850, 0x5bfdc0c5, 0x05008529, 0xece7946e, 0xbca69e61, 0xa69173a3, 0xb818b013, + 0x9ba7a02f, 0xc2bcb5ae, 0xa050ef53, 0x534ea2a3, 0x42b9be8b, 0x20517810, 0x35dd4f6c, 0xcea906ae, + 0x55e3bbba, 0xd4f7745f, 0xb760c263, 0x729b3011, 0xc4475b2c, 0x25c2e07f, 0x9b4621c4, 0xecb6bbe0, + 0x73cd8641, 0x795c3f56, 0xc8eaf41e, 0x72f71762, 0x58db237e, 0xdc7154e6, 0xc6f88614, 0x6e643fd1, + 0x76c3a6fb, 0xce701e77, 0x894198cc, 0xfb14a217, 0x8ee59b63, 0x827f891e, 0x202e28ef, 0x4d9e99f7, + 0xbf48a87d, 0x6546c6de, 0x983d2485, 0x59f1936f, 0x2428aed4, 0xdb4d045a, 0x116b772c, 0xc14e4989, + 0x0a6aa5fe, 0xd16c0e12, 0x8354d2d9, 0x7246039f, 0xd885a852, 0x60652d59, 0x06cbce82, 0x842b1d17, + 0xd94da3dc, 0x936a5cac, 0x23f62356, 0x54a5dd01, 0x18a42164, 0x68425260, 0x2386593b, 0x4d0b3be6, + 0x4e4d03b2, 0x98938458, 0xd5d77cef, 0x6535658d, 0x9242f620, 0x5e9ea2c6, 0xbf048994, 0xc9dd9631, + 0x87a2bf25, 0xc7d2f4d8, 0xd8af5d0c, 0x8d08bed6, 0x4947d061, 0xbc835dc2, 0x4824461b, 0x7378735f, + 0x4cce1243, 0x3a6832dc, 0x59c12e0d, 0x79730a5e, 0xcd3e091a, 0x90a2a489, 0xad13390e, 0x84c38e08, + 0xc23b2a77, 0x491265fa, 0xbdd326e3, 0x52946900, 0xe7f1f602, 0x76737512, 0x0a200bfd, 0x99845c91, + 0x56be583f, 0xff8477f2, 0x985168c3, 0x3fff09f8, 0xbda2b2b1, 0x27b54c46, 0xdcd03cdc, 0x11d1798d, + 0xcc6485ca, 0x94572a08, 0x7ff7fd89, 0x498c9bc7, 0x1e5d46a2, 0x34b14f24, 0x591351b4, 0x613138de, + 0x6a88d5af, 0x77881a75, 0x41f7e36d, 0x29c174c9, 0x949f0564, 0xc582b71d, 0x32a4b080, 0xce41ed63, + 0x8771661f, 0x3c98e591, 0xc470b993, 0x7977a820, 0x4cef96a9, 0xcdc3f2a0, 0x96efd563, 0x1c329d64, + 0x94cb953f, 0xe5195b62, 0xc9a1a20e, 0x3b1750af, 0xbaf3f63c, 0x79130c9c, 0xe113cbd0, 0xd9f6b1f9, + 0x54855f48, 0xfc1d1871, 0x61d6968c, 0x6e2804ba, 0xe25517a5, 0x8cd2d8b0, 0x58a1b9f4, 0x8c0503c4, + 0x1daff1ee, 0xfb9b9f49, 0xb8fc3fe2, 0xfdc92800, 0xd72a7747, 0x0292d587, 0x5580b69a, 0x4b4464de, + 0xa8089e4f, 0xb87494b6, 0x73696b0b, 0xfe7b79ce, 0x47c1bf09, 0x9546ec78, 0x111045f8, 0x383f7e65, + 0x6a77a36b, 0xa02e22f3, 0xabd17ac1, 0x923f0a70, 0xdd51669b, 0x180d5016, 0x021eea38, 0x7cb7f029, + 0xc72910bb, 0x152f64fe, 0x21e315b6, 0x9bc70dd5, 0xaa4b80bc, 0xb47ae09a, 0x28af12fd, 0xc5709eb1, + 0x33d2d994, 0x2907c820, 0xb62fe3cc, 0xaace9c25, 0xd50c18ef, 0x6bc2bc70, 0xd07dd57f, 0x06906d5b, + 0x3de6e282, 0xb026f6e5, 0x1da7e5c6, 0x85b24e68, 0x1538ac35, 0xac5a9986, 0x7ab340dd, 0x3f570e03, + 0xebb16505, 0x52705c3b, 0xe2c733ad, 0x2a673c82, 0xbc9e8837, 0xe75c22cb, 0x55e8ab10, 0x06d938d1, + 0x2a30727c, 0x5589c4fd, 0xdce5a052, 0x5c6b093c, 0x04ebdce2, 0x43486ac0, 0xe1ec9f3d, 0x37d6b6e8, + 0xf5363b61, 0x8b8a65e3, 0xe0acd212, 0xcf7d2bad, 0x739f34fc, 0xf86b9f46, 0x8ec112d9, 0x94b2582c, + 0xd5566415, 0xfe829b69, 0x5318d301, 0xae03e30e, 0x14aaad57, 0xe1298a44, 0xbb8cf039, 0x440e65f6, + 0xb8b38e01, 0x4b28da5f, 0x1c423971, 0xdf5862fd, 0x82abf630, 0x7edd1639, 0x32cf7368, 0x16bd6c4f, + 0x8717f9c4, 0x30bdb93a, 0x4d82d230, 0xb5938a4b, 0x0394b6bc, 0x8d350fbe, 0x61d4e41f, 0xe379d081, + 0x570bde21, 0x5f2e4a51, 0xbc71fd28, 0xc2810ac0, 0xe627c1ff, 0x9763cd5f, 0x9ec1c224, 0x1ea810d9, + 0xf8274137, 0xdcd910e5, 0x5506f84a, 0x15d3dc00, 0x64af9845, 0xd2639137, 0xa83a000e, 0xa0e35426, + 0xb6e00f68, 0x428d0e1a, 0x04a2ccd6, 0xf9fa8ae3, 0xce99be44, 0x52687437, 0x282d1b3d, 0x50893e4f, + 0x4255fcd6, 0xd6cb35e2, 0x5a3b12fa, 0x430ffc9a, 0xd4d252c0, 0x99cd7038, 0x7f28a527, 0x24ca30b0, + 0xa3eb46dd, 0x328f62f7, 0x057438be, 0x28958410, 0x34544f69, 0x95b64347, 0x295958af, 0x43c0033f, + 0x58196e49, 0xa6f3abee, 0x5518ccca, 0x18c2668e, 0x129ad9aa, 0x6523011c, 0x27f0f6f7, 0xdf380f68, + 0x08e97125, 0x753f7cb3, 0x76a253b5, 0xd3d51f20, 0xe197aa3c, 0x8cc8166e, 0x6aded695, 0xa91b03e2, + 0xdce77cdf, 0x94f4ce28, 0xa1ed7329, 0xe51ef712, 0xcc0cd0be, 0xab80b777, 0xafeefeb6, 0x7f0730cd, + 0x3c39b3cb, 0x979fd512, 0x42acd3a6, 0xd42f1acc, 0x84c8493c, 0x2b65363e, 0xd2d77405, 0xc7ead739, + 0xe60464ec, 0x8d3e6383, 0xa91ea4e1, 0x534b77ee, 0xc0c89693, 0x65642e82, 0x94242295, 0x54597b9c, + 0x604a0d92, 0x0095944f, 0x9a1d5c02, 0x62e9fc68, 0x9f47c24c, 0x6ab51c9d, 0xc1ecb2bd, 0x03686311, + 0xcda4ec29, 0x1795a735, 0xee0765ae, 0x9503a212, 0x95e5601e, 0x26697424, 0xb41221c1, 0x0efac790, + 0x0be8fcc9, 0x2530bcaa, 0xe5c1c70f, 0xda8f3ee6, 0x6013e247, 0xf429c2e2, 0x64c920f6, 0x53af72cd, + 0x9a50a0dc, 0x26a54f5c, 0x3812d126, 0x43e93c26, 0x9e5ac0b3, 0xdbdcebed, 0x0cfff771, 0x0b32f85c, + 0x0f73b03e, 0x46fb075f, 0xb9c66f09, 0x779e5fbe, 0x9cf0057b, 0xdf70a542, 0xf58e0380, 0xbde90718, + 0x20960d8c, 0x10f3e2f2, 0x1737df91, 0x82287b24, 0xc8fb3107, 0x2c3db432, 0x39d65413, 0x0306fb4f, + 0x0c0c320d, 0x3bf62f09, 0xf01a126f, 0x0d74b007, 0x685e9f7f, 0xe79c2dc6, 0x07062561, 0x31b49a08, + 0xaa4b178c, 0x8181c3c8, 0xd6374c1b, 0xb29c55c9, 0xb5169f08, 0x907a41a5, 0x757dc88e, 0x9bb830e7, + 0xc2cb1c9c, 0x023e83af, 0xf9646860, 0x740be97a, 0xc8ead2dc, 0x3c695fd2, 0x9efd9b0e, 0x7b88d517, + 0xd995190c, 0xd3be42ac, 0x7b94e85c, 0x439e54d5, 0xa8b428af, 0xfe3a10d1, 0xf7f50d3a, 0x65c000ee, + 0x3805c6c8, 0xe20e4b89, 0x23c07f68, 0x5c2bf1f9, 0x4549a085, 0x6d9e4e4c, 0x3d91b1e4, 0x5968c5e3, + 0xb2222637, 0x75278b7e, 0x288c343b, 0x7270bf34, 0xdfd9f5bf, 0xb60b6c3d, 0x82266b8c, 0x43cdfaf3, + 0xee6703dc, 0xc120e48f, 0x6dfe4b23, 0x37a8a1ff, 0xbe36fae6, 0x01bbffee, 0x0349995f, 0xdc976588, + 0x8c9d9cbe, 0xd4639c5b, 0x09b09edc, 0x639e7e37, 0x45bc1c21, 0xe73d8404, 0x3194c48a, 0xbdc9b876, + 0x98a0a23c, 0x1aa96d07, 0x2ffebd93, 0x5e2cd99f, 0x6713bee8, 0xb621118d, 0xac14beb0, 0x9e0d62bc, + 0x98f02684, 0x1228c418, 0xbba95175, 0x32f1a3d3, 0x29c757f5, 0x68779c27, 0x46ede92e, 0xdaa86eb7, + 0x7eaa5a32, 0xe023b1f8, 0x535053c2, 0x47010222, 0xf56971fa, 0x93d50e47, 0x48905cbc, 0x2eb8382b, + 0xfba57aa6, 0xc93761d8, 0xf209403a, 0x050f0faa, 0x3d8b4a4c, 0xb4b2bf53, 0x0cdb93a9, 0x9022924b, + 0x776a27ed, 0x4c86e13b, 0xd14d7e9d, 0x89ce9a3f, 0x6c736dcd, 0x5b4a7d2b, 0xa1cfe3b1, 0x0a2834f9, + 0xe5b32656, 0x4681b819, 0x0bbfb724, 0xa82c8bb2, 0xce241857, 0xc27bd831, 0x833dfb9d, 0xc3ca3842, + 0xb0777421, 0x40090549, 0x3f9e7f05, 0x6edc1f25, 0xc698c5f1, 0x6df655a8, 0xaf1f6153, 0x1c066619, + 0xeaf8bc11, 0x6149c1e0, 0x0bbff305, 0x00a10150, 0xfce02a51, 0xeec7c2b5, 0x2b96e0e5, 0xaa4d6bc8, + 0xfbdcf679, 0xe0a1c166, 0xa7f4eb38, 0x0f56e3cd, 0x3a50c3b2, 0xf71940d4, 0x2997d013, 0xfee1a35f, + 0xd00374ee, 0x3d637765, 0xb78ca311, 0x771fba0a, 0x25067022, 0xad4a01c2, 0xc9e52f43, 0x044cf5e6, + 0x260d928e, 0x4a9b7083, 0x95addb7a, 0x5a32683f, 0x892218cc, 0xaa53df82, 0x61919ad7, 0x3d3913ea, + 0xe1bc8b03, 0x34b6df84, 0xd0873058, 0xa0a7672d, 0xc7f08a81, 0xc932f643, 0xa42bf53a, 0x72bb3aa5, + 0x09dcccbe, 0xa3cb0bef, 0x8ede04af, 0xc057f99c, 0x2e0ff3ad, 0x84143648, 0x8ec8124c, 0x3e3c6df1, + 0xb46e6fee, 0x56fdf9b6, 0x386e68dc, 0xc631ab40, 0xacf435aa, 0x6ec98853, 0xa55ef993, 0x8b4a9731, + 0xf122d4c0, 0x8bdb4297, 0x4bd5134b, 0x576cc8cd, 0x875f5d1b, 0x13bef1c4, 0xee650774, 0x6c7b7fee, + 0x4cad67bd, 0x1f2b440f, 0xfab360f6, 0x4b428844, 0x7843e7c1, 0x0953d1bc, 0xf8473e6f, 0x574ecbac, + 0xd4e30201, 0x5af19b6c, 0x54b39ba6, 0x8419ae6b, 0xd14a93eb, 0x52189397, 0x2b976cc3, 0x4419ed22, + 0xe485d087, 0x2591bc54, 0xcb874de1, 0x9c2c732d, 0xb5ff9ae8, 0xb6438164, 0x01889e30, 0x34289072, + 0x18570239, 0x6e1b674e, 0xbeea48eb, 0xd0e4829a, 0x08be90ae, 0x5b9ca691, 0xdbc58b5a, 0xc3c9af95, + 0xfd5bf333, 0x2a718ae4, 0x78537c25, 0x44c09504, 0x4c8a0e79, 0x1ef18d47, 0x79669a02, 0xfd2f1103, + 0xf11ca05d, 0xa94fb00c, 0x2db31914, 0xbb13ee37, 0xafef8d77, 0xa2844be3, 0x3b558b79, 0xef15052d, + 0x002215fe, 0x84dbd24c, 0xb1f75a16, 0xa6d5c504, 0xca936b68, 0x101f3144, 0x96cac4e9, 0x6278ee14, + 0x828ef9e8, 0x6931e9c0, 0xd0b67da5, 0x87928585, 0x9b3238f2, 0x3c7d78ca, 0x5f91d7db, 0xe94acc73, + 0x8902e466, 0xd98f78a8, 0xa60f5d3c, 0x25a82022, 0xfffbbc0a, 0x534df514, 0x2b37cb38, 0xbafe3a82, + 0x90532fe8, 0x70a0903e, 0xbe36985e, 0xe24afffa, 0x036504e0, 0x347c2674, 0x00d304f5, 0x093bbd4a, + 0x46f4e24a, 0x6532572a, 0xd73d5b6f, 0xe23052b9, 0x0e938cc6, 0xa45ddb8e, 0xa79dfa62, 0x9ff3ccfc, + 0x240170d7, 0x4a5c9d98, 0xfdfbe3e2, 0x10459172, 0x7b854d0b, 0xd75a4680, 0x9f467cc9, 0xa8c59361, + 0x90a75b03, 0xb7f1c6ae, 0xdb9e57b6, 0xd065e695, 0xca5e1b9f, 0xe3ef9efb, 0xf0e19316, 0x085538b6, + 0x2ff195a9, 0x4132c15b, 0xebe927d6, 0xb9b5ca10, 0x9fd56052, 0x68e0c8b1, 0xaf6b20bc, 0xa6658edf, + 0x3790387f, 0x4a96bad5, 0x2c6f6bfd, 0x1e5de12b, 0x430943e1, 0x16b7f7b5, 0xd0e9af7a, 0x9169f349, + 0xffb813b5, 0xaaf91a0c, 0x3a61674a, 0xa42537a8, 0x206b9e7b, 0x73520975, 0x9fb6be2c, 0x7431f462, + 0xb8912cc7, 0x5e177185, 0x266b1e82, 0x0965c71b, 0xdd1b4d6c, 0xf65e07fd, 0x5fc4c28d, 0x4cf31c11, + 0x01c77d09, 0x867e7735, 0x315ce8f4, 0xa652e10f, 0x27b39820, 0x1c2dfd8f, 0x6e5e4e6d, 0x120a33d0, + 0x39c460d4, 0x925dc1ff, 0x140f5804, 0x59dd5a88, 0x1ebdfcf3, 0xe874b819, 0x04e7aeb3, 0xeb946d71, + 0xcdbb95f7, 0xd0dcdbbe, 0x9e1a61ec, 0x3a86826e, 0x85e3d5bc, 0x09103cbc, 0x30110e51, 0x0e73db81, + 0xaad9f99f, 0x0d0e2c5d, 0x26a62e42, 0xf2c816d0, 0x6ed1daa0, 0x47cb8f9c, 0x7df60da5, 0xe2c0d60b, + 0xf43e9730, 0x4bf73120, 0x73d21cd6, 0x37ed3dac, 0x54064f43, 0x6d20fb04, 0xb3340066, 0xfa67b0bf, + 0x89b44cd0, 0x6744e241, 0x53d7ce49, 0xc356b70a, 0x87aa3353, 0xdf6d588d, 0x6093c469, 0x556eed62, + 0x4df75559, 0xbb872847, 0x10f00132, 0x0585eae7, 0x2138758a, 0xbb23c7b2, 0x802203bc, 0xff114264, + 0xf8b5aa45, 0xfebb1b6c, 0x19b00306, 0x5a829189, 0xb6517fbd, 0x795b7516, 0x9cfbee0c, 0x96408da0, + 0x7ffc8a04, 0x40244598, 0x058a4c1d, 0x3f711ade, 0xc9b591fa, 0xbc98d87c, 0x75792a3b, 0xcb3dd370, + 0x9df0e420, 0x7d528039, 0xc245e61e, 0x09b3ba2e, 0xa8de5461, 0x6f85a1eb, 0xbce9a5b5, 0x214f35ee, + 0xc45c4e8c, 0x89bac8de, 0x77b8a585, 0x56c5de3a, 0x4e839f12, 0x08ad3d02, 0xe8274b58, 0x7a44d40a, + 0x65cd3584, 0x6ade6918, 0x14a7e8d7, 0x952bc08f, 0x3ce44e93, 0x10fdc9eb, 0x98767710, 0x3d36629a, + 0xea030354, 0xddf9ec97, 0xeb449232, 0xff3eab2d, 0xf2af69f0, 0x329e390c, 0xeeda23de, 0x6ffff227, + 0x6f5137e2, 0x255f52a7, 0xb8184bae, 0xd59d0a56, 0x49119328, 0x550d8ef7, 0xbfb69e2e, 0xc85c9460, + 0x5857f890, 0xf4e4cfcf, 0x7f020eaa, 0xcf3fad0e, 0x0ef57b39, 0xcaa8b271, 0x64651042, 0x5b4d0304, + 0x1a2ddc47, 0xbc27ad4e, 0xd1a6ec93, 0x541002e5, 0x6bb5d173, 0xf5e6e1b0, 0x25a4c9d0, 0xcdcea94f, + 0xd319374b, 0x8c23d5e0, 0x221e9c35, 0x982818a5, 0xbab9e1c6, 0x3ba24a33, 0x71333e45, 0x77738087, + 0x868fe1ad, 0x3635d60e, 0xd4669742, 0x9c7ff02d, 0x1cd2dfc8, 0x77c9d640, 0xd3275013, 0xa67f727b, + 0x8ea31178, 0x16266057, 0xc97133d7, 0xda4c2d6c, 0xaf6033c8, 0x26af5419, 0xb3761de2, 0x5fd1d422, + 0x79df85c1, 0x18000528, 0x4c834e31, 0x3120b375, 0xbdcc1bd5, 0x95f96179, 0xc3404cac, 0x67dc571c, + 0x8b9733ff, 0x9416c0c2, 0x7a23fa7c, 0xbff46e68, 0x0d7f767b, 0x1f142462, 0x16a3288b, 0x79b61993, + 0x7719baea, 0xf2aad91c, 0x1133d310, 0xf5b27f9f, 0xab1160af, 0xf35a0c26, 0xf1169395, 0xfd53d4e9, + 0x0f034788, 0x8719ba0a, 0x611bd962, 0x387421c3, 0xca326f7e, 0x39cf9265, 0xef683ea1, 0xa3922a1b, + 0x5bd401bb, 0x69b81f0b, 0x84d6d86e, 0xb91e8f8b, 0xac8a3130, 0xf790c29f, 0x39cb7c75, 0xb9987c2f, + 0x460a4a35, 0x606d8ab1, 0x393e1cd2, 0x7056b085, 0x171c0d03, 0x12ec01e7, 0x67080ec6, 0x2a6076b8, + 0x9da1c938, 0x047c21f9, 0xab3de444, 0x22ad740f, 0x52cb9b3b, 0x83e6bd2c, 0xc1e6bff4, 0x5436b8e4, + 0x52bc10a3, 0x792c2e6a, 0x6710c999, 0x620bda54, 0x778520b7, 0xb85dec8a, 0xe0245d22, 0x40256436, + 0x83fd4736, 0x280d58d3, 0x4e56a5ff, 0x4a323ca1, 0xb0b6ceb9, 0xafb77f9a, 0x029f6392, 0x5f486cd8, + 0x0c56d148, 0xb1bf4fad, 0xa93b06ba, 0x6adfe1d3, 0x4a983980, 0xb8671844, 0x8cdd0e59, 0x9a7f480d, + 0x2874fec1, 0x72a62676, 0xa30c23fc, 0x48503c6f, 0x369ead08, 0x78ad1a54, 0xd609fc16, 0x6cc25be3, + 0xb3f6c179, 0xcbab69bd, 0x895f800b, 0x350d5e16, 0xd44506ee, 0xc8011dd6, 0xbd775558, 0xc125a3cb, + 0xe54a96ca, 0x321556dc, 0x984c15ee, 0xcee03738, 0xb8b549b7, 0x5b791ce0, 0x481c913e, 0x992f9f9e, + 0xec985575, 0x1d3b24c0, 0x81b0b50a, 0x2b355864, 0xce431b62, 0x27e3cf9b, 0xf94385f3, 0x5f12d48e, + 0xab2faf75, 0xc111e955, 0x5f1c5113, 0x565150c2, 0xfacca160, 0x3ef83bcb, 0xfe438847, 0xcfcb720b, + 0xa79d4ec0, 0x41cda260, 0x6d13d5c0, 0x006bf5e9, 0xcb04ebbf, 0x189212dd, 0x6f064aea, 0xb83c6d30, + 0x07b826b8, 0x98eb9769, 0xa873c198, 0x470cac19, 0xf0b7ccb4, 0xd2a65ecd, 0x0da9a12b, 0x85764a8e, + 0x596f46b4, 0xa95f63c1, 0x655cbacf, 0x1615b0de, 0xfdb36feb, 0x470e9359, 0x3a013ed0, 0x369f7a44, + 0xb0c78733, 0x1d851821, 0x38a6a98f, 0x87a89809, 0xbc986989, 0x4080e22a, 0xbfceedcb, 0xe14ce1d7, + 0x53227acc, 0x90b476cc, 0x390bb6c5, 0x03ae5177, 0x685b3edb, 0x2a4e108b, 0x3ab1c4f5, 0xab764e06, + 0x49c210b0, 0x0bf9c0e1, 0x5b341fa9, 0x1823b4b1, 0xf241e0ab, 0x15b59fd6, 0x3f2bd3c0, 0xed2d303c, + 0xe9afd0dc, 0xf59f564e, 0xf4a98d70, 0x458e75d8, 0x87094a57, 0x32acf02e, 0xdce2df3c, 0x95d82eb6, + 0x9a16103e, 0x39684577, 0x46fd9dc3, 0xdf8139cd, 0xb918deb1, 0x58279929, 0x86a36b3a, 0xb9ab322b, + 0xc7597be9, 0x2b871504, 0x160e88ad, 0xeaa72a50, 0x77d4a8a0, 0x0dc5cea0, 0x2d1198a3, 0x1764a45c, + 0x884edce6, 0x4465e852, 0xbc51a155, 0x8ac0ca87, 0xb928aa0b, 0xf123a1b7, 0x9912d1b8, 0x8abd7813, + 0x82e5b544, 0xc8eed441, 0xc055c419, 0xcc225c86, 0xdac05e19, 0x430d31f7, 0x95778262, 0x666440e2, + 0x994fddad, 0xbfce32fe, 0xa8b27ce3, 0x67e1c145, 0xbbdf6ab2, 0x3c833ec4, 0x92e730c2, 0x0a767cbe, + 0xc80c44e6, 0x915a3e49, 0x0c357558, 0x1e1ac329, 0x67d9b697, 0x2eaad8c3, 0xcaffa657, 0xc351a8ab, + 0x7b8b29ea, 0x76f0f18a, 0x60a63fa7, 0xc2ad2d44, 0x34551772, 0x15272211, 0xc098cbb8, 0xf8525a94, + 0x6d4d8bba, 0xd8af4fea, 0x7cf45a09, 0xf563497b, 0xa6894084, 0x94e56afe, 0x2370c7bf, 0xadecbe2e, + 0xb4161d38, 0x77a21d92, 0xe4c29ae3, 0xadeca666, 0xe1d9eb91, 0x876406ea, 0x936eb64b, 0xdcf033ce, + 0x792d746d, 0x4dcdf312, 0xecda9367, 0x28a6ecb3, 0xb63fb40b, 0xe662fcb4, 0xeee3901f, 0x45be9545, + 0x235e99a9, 0x12f0fc67, 0xd5a61824, 0x076170e1, 0x4b6099b9, 0xa531d2f0, 0xa494eb24, 0xbacd54b1, + 0x68c32cc2, 0x1c30c6bd, 0xa91c4ea5, 0xacf11816, 0x091c3e75, 0x72dbc00a, 0xce8762be, 0x28aa2da4, + 0xe7feba7f, 0xb29ce665, 0x6a4d46a6, 0x00d0f7ed, 0xc626b9b1, 0xc6385ae5, 0x78c79087, 0x0e7330b1, + 0x4a7e34cc, 0xa2823794, 0x28a3a41d, 0x94c9ce17, 0x4a506fb9, 0x46e0248f, 0x13634533, 0xc4559a90, + 0xdd0c44c7, 0x7f02588c, 0x4ef094c5, 0xcb5ae0f8, 0x1eab05d0, 0x5b2f635f, 0x26b08221, 0x0f538a2b, + 0xc270b91b, 0x4479834c, 0x62d31d60, 0x70fd2289, 0xd9c6dd55, 0x9641f319, 0xe07c4bf5, 0x8711165d, + 0x50e4893f, 0x03fb1f06, 0xaf1d8688, 0x80bfd228, 0x431236ec, 0x20b4f019, 0x0024e03d, 0xcf7388bd, + 0x32ec3642, 0x3f9ecc9a, 0x434053ae, 0xf6e66d32, 0x77186a0d, 0x60863d08, 0xe60bdf46, 0xa1276a16, + 0xc5f2456c, 0xd630a8a0, 0xc404f175, 0x16301125, 0xe6b34792, 0x220101c3, 0xb3584512, 0x0860d0f7, + 0x0d2272c0, 0x89d12ede, 0xeda7e2e2, 0xfe8724bf, 0xbe4197e3, 0xccbaf894, 0x06fca533, 0xc29bfae9, + 0xc46bc5a0, 0x0b7d5feb, 0x7f3ebd6f, 0x201a01b6, 0x017daf63, 0xeab888f5, 0x39be64fb, 0x30584d23, + 0xb265e50e, 0x3c5acc62, 0xdc55aae8, 0xc0a29456, 0x738194df, 0xaa579cba, 0xd7bd69d4, 0x54c3f2f2, + 0x636aec5e, 0xc6674b76, 0xabe71f29, 0x97a0f320, 0x0a8ac81b, 0x02e25dc3, 0xe0b98f2a, 0x83369863, + 0x8937d47d, 0x5a5c009c, 0x883e91ad, 0x965305ab, 0x622efff5, 0xa33ca13f, 0x80cbdefc, 0xb41959c2, + 0x0c33e256, 0x50a8db24, 0x952e4e58, 0x630d7458, 0x479d30af, 0xfac2d94d, 0xcabb1a96, 0xadac81bd, + 0x562bb49d, 0xb26da9df, 0xe67b02fc, 0x4732de4a, 0xeee28a8a, 0x92d54a03, 0xb0eb8925, 0x69bfa7e0, + 0xc4249aba, 0x0acb180b, 0x666de230, 0x14a4967d, 0x801f6cfd, 0x63bc060a, 0x95d3b6d6, 0x663f1df8, + 0x5ee5f62d, 0x63c27710, 0x01f9c33a, 0xdf893eec, 0xe4ed53d0, 0xe7c69542, 0x40955670, 0x8394862a, + 0x1d05300e, 0x0e6a59c8, 0x0a12263e, 0x4521d859, 0x63c7424e, 0xce0090fc, 0xf051d66a, 0xe3a68b99, + 0x91103a9e, 0xe82763d4, 0x2d61c67c, 0x81350f17, 0xa64bd5e7, 0x20b75dfe, 0xdb90b1c8, 0x8a46bf21, + 0x04fef463, 0x0964db99, 0x8578754d, 0x72c310e1, 0xc0b3aa52, 0x34dfe8b3, 0xe093a174, 0x26a9caee, + 0x37f72a49, 0x46971f48, 0xe976336f, 0xfcf80810, 0x507ed788, 0xc50db629, 0xd8ca3c68, 0x93cb9f1a, + 0xb6551ecd, 0x0b8abc67, 0xa9fa2eaf, 0xbbd4c56b, 0x81fa432b, 0x31773dd4, 0x51cf5a86, 0xb8d961b4, + 0x1e631302, 0x721787cb, 0xecb6e22e, 0x44b417cc, 0x67277e05, 0x858f46ff, 0x9eec65de, 0x9867f617, + 0x6ff6f995, 0xb71f852f, 0x05dbde20, 0x435f06c0, 0xff9ab304, 0x7c6609f0, 0xb3b5ffe3, 0x6cb9a3a0, + 0xa81ef1a2, 0x1231b006, 0x5aca0394, 0x6dc6b1c9, 0x00cc653c, 0xb57e768b, 0xfb029e1b, 0x6ddf1432, + 0xab146508, 0x9f520a89, 0xd008f551, 0x8a086f4b, 0x6923c302, 0x097bd130, 0xef5249f6, 0x9f93276d, + 0xf2dc44d5, 0x3658563b, 0x8b96fbba, 0x627fb205, 0x76bcb6a3, 0xf39b6b74, 0x3f6230a3, 0x5a1be947, + 0xbf1adf39, 0x1fb7b8a1, 0x4d3fda7c, 0x38de46ba, 0x370a1667, 0xaa513d45, 0x71ee8d37, 0xf96c2425, + 0xa6213986, 0x3f555d54, 0x4cd840d0, 0x3a0af49c, 0x89b46c71, 0x2e04f9d3, 0x3b1fbfa6, 0x14723dfc, + 0x9438c50e, 0x78b77664, 0xb80b689d, 0xf1b0d602, 0x31cc8ba1, 0x1b69fec2, 0xd92960ed, 0xbfe5b51b, + 0x4fc9696a, 0x17c8efd0, 0xbd4c7e6e, 0xc2c7a33c, 0x2a27b298, 0x56447038, 0x29d42109, 0x7baed68d, + 0xfbb4ebf7, 0xde2f040d, 0x392d46f0, 0x2d155b36, 0xcd5bfdb2, 0x2ccd2f7c, 0xc12a942a, 0xaa3a61f1, + 0xe5b197ba, 0xee69ca25, 0xf2143a5f, 0x5c69b012, 0x5aa28b08, 0xec409b55, 0xefb4795d, 0x95e44e2f, + 0x27de1d2f, 0x08e49d8d, 0xc035bd26, 0x73c78b85, 0x75052625, 0x5ac1244e, 0x51904566, 0x75e1e930, + 0x52ce5d64, 0x0fa16161, 0x89d3c506, 0x4fa8f994, 0xde459018, 0x4019c65c, 0xab9f0de5, 0xfc5f4de5, + 0xdae96b65, 0x01233af2, 0x40a0fdcc, 0xd1df3288, 0x965f041c, 0x8816a33f, 0x99e1646a, 0xa1927ab7, + 0x7e240862, 0x180aa7eb, 0xf692f9a6, 0xa9869b34, 0xb4beadb8, 0x0e766279, 0x1fd3b6be, 0x3e1fd4c3, + 0x8a36cfe6, 0x86476cd6, 0x00fbf86f, 0x27d6d8c1, 0x7367ddc1, 0x6d31ca40, 0x2d50dc00, 0xfc42014b, + 0xbfb4c69c, 0xb7257305, 0x3da5ed4e, 0x5026e307, 0xb33935ce, 0x45d8b7c2, 0xc28c438a, 0x10b571b1, + 0x129992e1, 0x6faee782, 0x7e960784, 0x74852edb, 0x66d2ea73, 0x85643e03, 0x91cf098c, 0xde027a19, + 0xf83ba5d7, 0x10fbb328, 0x000ca6d3, 0xfd6c0dac, 0x6d418768, 0x4421d07c, 0x58e55dfd, 0x04d56310, + 0xa1ef85aa, 0x7a3e96f4, 0xbf46c8db, 0x7dee0e3b, 0xef8bcd06, 0x7c0e925b, 0xd477e4ef, 0x136af48d, + 0x89b7049a, 0x683bc18e, 0x76da5d5b, 0x37281383, 0x1d55dfcd, 0x866a2e6e, 0xee8dcb47, 0x6ce808fa, + 0x7eed49dd, 0x3c431992, 0x699233d6, 0xb4726222, 0xf7545160, 0x56b0f751, 0xbe12f9e9, 0x0939a5ce, + 0xbb6ea623, 0xb9962d92, 0x09858330, 0x9540aa56, 0x34a8597e, 0xbd0c24b8, 0x71e2e572, 0x9ea45170, + 0x3e63d57f, 0x4962b5de, 0xa685555a, 0x2e2660e9, 0xb10ae040, 0xa3289f2a, 0x26539da0, 0x6731cd05, + 0x538cc416, 0x0f06849b, 0x696bc499, 0xc3ad994d, 0xe896239f, 0x11981575, 0x1bd5474b, 0x08a6ed9c, + 0x824220c7, 0xa190c735, 0x5c71d96b, 0xdc15d5d3, 0x2d361074, 0xa9dfe488, 0x5a517d89, 0xf376e938, + 0xdc151028, 0x899e9ef5, 0x1342acad, 0x9ee51e5f, 0xf736e9b7, 0x0ad105f5, 0x8752b8aa, 0xfd2b8934, + 0xce395f8b, 0x455ab0a7, 0x17ba98a8, 0x3c1e252c, 0xf9d254dd, 0x05fd22c6, 0x3140e9e6, 0x7e5d7f8f, + 0x76cc881e, 0xcc70d87b, 0x3fcfd8e3, 0x5c781c7a, 0xd16e5535, 0x8426f489, 0xce378b0f, 0xed0183d7, + 0xb552b2c9, 0xf3db0195, 0xeab5ebfd, 0xfc68dcc0, 0xd9e5dfe8, 0xe249f4a4, 0x6ed2c16b, 0x26d3a13b, + 0x47880c91, 0x436aa0b6, 0x67a339fa, 0x46ebab85, 0x2ec8faa8, 0x6eb0974f, 0x2288048c, 0x4a26e6e6, + 0xa472b9b2, 0xd0620604, 0x7e7da15f, 0x605db367, 0xe9f79228, 0x1bba4ec3, 0x284d9059, 0x1ea2b3a7, + 0xeed8a337, 0x77bc8b76, 0x3d8e0302, 0xe54cfb10, 0x68f39fef, 0x7fcd874f, 0x9a115bb8, 0x83b4c6d8, + 0x3e64981e, 0x96315d4e, 0x3b702893, 0x1c999404, 0x1050f134, 0x6a0fb29a, 0x1a504c3d, 0x56969dcd, + 0x19da69d1, 0xbb05bd00, 0x2c91d1be, 0x7fc0030f, 0x201a3d1a, 0xcb77644a, 0x6f5aff50, 0xbaf622f4, + 0xa37f05f3, 0x8565fead, 0x618f126d, 0x4dda4646, 0x7879f61f, 0x59b819ff, 0xd562f19a, 0xe78ab9fe, + 0x43eaa5b0, 0x3ae9bae2, 0xf76bce03, 0x32f7743a, 0x15315f14, 0x65df8ed0, 0xcc685f72, 0x4e2f6704, + 0x28f89b71, 0x3e3fbbe8, 0x961bafc8, 0xba97e931, 0x30cc075e, 0x2128d698, 0x48639325, 0xb84d5956, + 0x14a58b20, 0xb5cc3225, 0x9f4cd530, 0xaff707e9, 0x371a5e5c, 0xe2f01afd, 0x6ebc0d8d, 0x2a7e929f, + 0xad625f6b, 0x853e6e66, 0x4de7f450, 0x72626e1d, 0x8398cf68, 0xcc66ba30, 0x21ab128c, 0xbcad1008, + 0x1fb189cb, 0x01848f64, 0xba4335e4, 0x6d09745b, 0x58bdcf75, 0x82822a6d, 0x3ebaf3ac, 0x0892f622, + 0x6d5a89b8, 0x5aa5a513, 0xa0951529, 0xfd4df36e, 0x0fb4c509, 0x7c93b292, 0xd483280f, 0x53bbe2c8, + 0x1eb97e38, 0x78cc7882, 0x1ce2205f, 0xd67f8920, 0x12ab888c, 0xc4d2cb91, 0x24f64006, 0x8bda41ea, + 0x53a9116c, 0xd2329155, 0x253981aa, 0x2e4c4592, 0xb406d9b9, 0x49ed011d, 0x7fd5ee1e, 0xfd4d7573, + 0x68ae5116, 0x9e0d6c39, 0x0b7f7927, 0x03712675, 0x124ce8c5, 0xb618bd62, 0xcd523a47, 0x0cd03270, + 0xc0918724, 0x3b5815b9, 0x25dd1fa2, 0xfd328a1e, 0x80ec5e4d, 0xc7bb2cb7, 0x48e6cb97, 0xa6037637, + 0xdeb87df1, 0x89d0b16c, 0x011961c7, 0xb86ed6ed, 0x74898e21, 0x0c7a0a42, 0x471028c0, 0x9ea03725, + 0x52cb50fc, 0xa72974fa, 0x96e01288, 0xf5ef0048, 0x151970db, 0x523cace6, 0xfcc4ecb9, 0x18de5ebd, + 0xb9fd4b56, 0x2199bd31, 0xba3aef0c, 0xb816cbfe, 0xf5a539c0, 0x8b5f502a, 0x340a94a2, 0x140b105c, + 0xcd9f64af, 0x6a82aa0f, 0x462f9d13, 0x66031683, 0x78685fe1, 0x6d3db017, 0x70f360c0, 0x82e72386, + 0x13b8d263, 0xd391efef, 0x062cc4fd, 0xb40960ad, 0x17661eb2, 0x3a7fd9f3, 0x32adb79f, 0x46980893, + 0x2bc890ed, 0x590d6c1e, 0xc772b96e, 0x634b25be, 0x6a832357, 0x622f2337, 0x7469cc75, 0xa7867abf, + 0x00c094cf, 0x8c9bc607, 0x77eaa04b, 0xc473491f, 0x581ad89d, 0x554adaee, 0x014548ba, 0x723a53f0, + 0x15b88159, 0x4d651f00, 0x8c7b3e7f, 0xecf44920, 0x659773e2, 0x654d74bb, 0x6d2b4a1b, 0x61cb36de, + 0x81623803, 0x34d47ae9, 0xf81a0d12, 0x57207b21, 0x3ce89b4e, 0xd94df516, 0x7bdb9f02, 0xaf8cb841, + 0x1a5d76d2, 0x3b759408, 0xae75ad78, 0xe98e9372, 0x0c39ef12, 0x6016742d, 0x6746f998, 0x9a65077a, + 0x7fed7075, 0x6508f34a, 0x8f343e11, 0x2510e6d5, 0x42cc796e, 0xb1fb4fd9, 0x1e8376c6, 0xf8bfd45b, + 0x14bc1182, 0xc027d5dc, 0x56acec1a, 0x26e8a731, 0xbcc0014c, 0xb3bfdd3e, 0x756dbb26, 0x83f0b1ad, + 0x897c9c9a, 0x834ef2c2, 0x54e71fdc, 0x17a8d338, 0x2aa09542, 0xfce4d785, 0x17908c6e, 0xcfd6bdf2, + 0xa709d37b, 0xe7fecf39, 0x7373b36e, 0xfdcb3985, 0xc138d7fb, 0x5c4764ec, 0xa5411795, 0x38d2e30e, + 0x333652c4, 0xe0938b98, 0x6c7e0282, 0xa6ffe7ac, 0xeb008896, 0x42bdbf39, 0x93046523, 0x2adb2793, + 0xfa023be8, 0x2d18fab2, 0x50322214, 0x4047a955, 0x0d7b0159, 0xc8baac57, 0x28f682e8, 0x0e935ad5, + 0xf6d7eda0, 0x296d32e7, 0x04da0c87, 0xd62f881f, 0xc56f0c14, 0x54dbcf32, 0x0609066a, 0x7a51e5da, + 0xb56f2afd, 0x85dce396, 0x58277abb, 0x28900ba0, 0xf61671b4, 0xc7e03b70, 0xb9e31a26, 0x2292008d, + 0xe3498da7, 0xc8da0903, 0xce4c7df9, 0x0e0a506a, 0xfc06bf25, 0xa2119f14, 0xedddcb06, 0xae80e1be, + 0xb811591b, 0x79265c16, 0x9512e81b, 0xd23ffa00, 0x79827e71, 0x80aaa282, 0x07f93131, 0xc84254df, + 0xe4048eb0, 0x4efdd1c8, 0x8f598289, 0x53a541b8, 0xb2c044f9, 0x6933aa61, 0xdaa843cf, 0x94cd0f00, + 0x3537f81e, 0xbed17de1, 0xb8d4c952, 0xe3815aa1, 0x3fa456f0, 0x7ee8eeb2, 0x43471665, 0xdc2bdb71, + 0x16d38751, 0xc5f8f88e, 0x48280493, 0xcbfb3989, 0x4690b994, 0xf5574203, 0xe9c6530e, 0x19e914b0, + 0x3a1bb807, 0x65edce14, 0x21938d64, 0x5532d7d4, 0xd3e07879, 0xdcbec75e, 0xbc2ca8b1, 0xed3e798e, + 0x7ddd1cae, 0x4e6ae1ab, 0xb7e417f0, 0xfba89c55, 0xd68e63f3, 0x20654e50, 0xc36b97cb, 0x47f28cd3, + 0xf54c94b2, 0xf40ab188, 0x776eb3ca, 0x7981cbbc, 0x834a2b5a, 0x00b49843, 0x20e0760c, 0xf9389f50, + 0x1bf4ab74, 0xd31f2a90, 0x7bc2d846, 0xc1bb4820, 0x5eaba061, 0xdc842548, 0x7573e0ce, 0x55e5915a, + 0x2347e750, 0xb6a5706e, 0xe61276dc, 0xed9112e0, 0xe5d17789, 0x4b3af8da, 0xee7ea6ba, 0x1818910d, + 0x8a974ea7, 0x9d3143eb, 0xb364d063, 0x1f05cbbd, 0xca414065, 0xdb5bc059, 0x295d1dde, 0xad981ce9, + 0x430058b9, 0xea042fb5, 0xf48c4264, 0x4128ce4e, 0x0b92633d, 0x0511bb0c, 0xfeb03ef3, 0xed68b711, + 0xefd6d59f, 0x169d707b, 0xc6ee2456, 0xb5469e9c, 0x557d43c3, 0x7338b5f0, 0x622022ea, 0x7d41b575, + 0xfefdb71a, 0xe4b570a6, 0x0aa543f2, 0x84ae2929, 0x01ba90bf, 0xa3faf7a1, 0x4ccc893e, 0x5ccd3dd7, + 0x741e10e7, 0x5bbe38d5, 0x961e0cd6, 0xfc24cb10, 0x55879776, 0x2f8a7836, 0xb39c5f04, 0x07653715, + 0x0c5b024a, 0x8f8987c3, 0xd559cc23, 0xd74fa8c2, 0xe20459f2, 0x7fb45186, 0xadd00e2c, 0x0fa8e47f, + 0x1e89c7ab, 0x417df531, 0x2fd50286, 0x32af7603, 0x26dee3a5, 0x3415b834, 0x95b7aa35, 0x6f6c85d9, + 0x26a01ba3, 0xc1564c1d, 0x939c4ebb, 0x16fb0d47, 0xacadb8a6, 0xc5a711e9, 0xd22d38c8, 0xc4aa7427, + 0x22a15e78, 0x4b696f75, 0x5570f628, 0xc513be95, 0x66a409a8, 0xbb6769cf, 0xbb514e39, 0xf8304039, + 0xd8bb8442, 0xba8fbea4, 0xa061d6a5, 0xde1d0ffe, 0x0b520147, 0x40fd5971, 0x9f3ac244, 0x46744ceb, + 0xe1920dee, 0xcc674efd, 0xa2844aad, 0xf100a594, 0x0de47389, 0x360110a4, 0x8dd0cedc, 0xc663b5c2, + 0x263e5f86, 0x330ae2b9, 0x0fd925f9, 0x32de6b2d, 0x6af87324, 0x5886c75e, 0x44bc863c, 0x74b63a65, + 0xf4209f4b, 0x50b1bac4, 0x9ad36601, 0x3acd240f, 0xa6653306, 0x77f2aad0, 0xbc4202cb, 0x7a468e20, + 0x5d7a86f2, 0x48bbb75e, 0xc14f1480, 0x06a34681, 0xc4097593, 0x1c6d1487, 0x51888001, 0x584a984b, + 0xfa595e7d, 0x0bca4b2c, 0x856cdfbb, 0x78adc4f4, 0x9b2e5a0f, 0xbf82e18a, 0x89eae77b, 0x0dfea44f, + 0x47bbdc9c, 0x1a04dcc7, 0xd808d759, 0x2d1cc2e4, 0x42a81720, 0xd1dc4f00, 0x0e5ff078, 0x75d2f642, + 0xda6930e7, 0x6b5aa230, 0x78eaecc5, 0x3edbd31d, 0xd3eb9141, 0x27ebdbf0, 0xd7cca823, 0x2c0a93b8, + 0x074ac4c7, 0xf167c70a, 0x2ac2451c, 0x06ad521a, 0x0364639e, 0xa578316f, 0x3f96099a, 0x70f24157, + 0x6a912254, 0x8e923212, 0x423f2d9c, 0x7f04689a, 0xb8978a00, 0xc29d6f4f, 0x4eef525f, 0x51bc68ca, + 0x522292f3, 0x1b77c03a, 0xe8b65581, 0x523ed6d6, 0x6a6923a6, 0xe06c7f1e, 0xee906c53, 0x5588347d, + 0x10e1c0a9, 0xa91e99ca, 0x0f1fcd55, 0xec3ca15c, 0x5e66d26b, 0x02f169dd, 0x3d8b710f, 0x54d7e476, + 0x175ba123, 0x835bd420, 0xf1a0ab2c, 0xf289f61e, 0xb4f3acc3, 0x4a6910e0, 0xb0d95a2d, 0x0ada0a6d, + 0xf4a09836, 0xdf625eb4, 0xfddbe562, 0x6942a33d, 0x4f067d0c, 0x8b79d619, 0x518ae64d, 0xe7fd35ec, + 0x86ff1309, 0xb8a4ff98, 0x93b5111d, 0xfeda8b2f, 0xb05c7203, 0xf4f3d6fb, 0x86cc91c6, 0xb0d6910b, + 0x8d925c74, 0x06efc425, 0x32fa2969, 0x92c761dd, 0x49d6e573, 0xf07df448, 0xd970265c, 0x0b85cf5c, + 0x1b783547, 0x807f91dd, 0x613af8e9, 0xceab1064, 0xbd5bc01d, 0x4728d330, 0x3e5e38e5, 0xec1d2bcf, + 0xf341b0a1, 0xe7dfcac0, 0x9ed328cd, 0xec6f312f, 0x9bfbb8c8, 0x99f36184, 0xe796d355, 0x192ba1d7, + 0x8ced8c1f, 0x6c69c2ff, 0xf84df1eb, 0xe63642b8, 0x169d9dca, 0xb979c2a2, 0x6528b646, 0x1fd904b1, + 0xffed003a, 0x7b997da1, 0xba41f140, 0x1d61d3d3, 0xe865e252, 0xbf54aa47, 0xd43e85fe, 0x60540c23, + 0x3744981d, 0x2a685b51, 0x0b59141f, 0x45549383, 0xd824b706, 0x376b419e, 0x660be5bd, 0x4ceceb13, + 0xc988e04f, 0x73156475, 0x16bd44c8, 0xd026e868, 0xd088e8f4, 0x04ba5a6c, 0x035a3280, 0x14faa0ec, + 0xf025fe8b, 0x6fbbea2e, 0xd17c9e6e, 0xb6d02c7d, 0xd151bb7b, 0x40a80a7c, 0xce728b6e, 0x7e4e8703, + 0x0e140a4b, 0xcdff26a4, 0x6c237276, 0x20aa8873, 0x8b7b0a7c, 0x83e9265e, 0x22a9cff7, 0x80d05b67, + 0xd71f1add, 0xa948c6c1, 0xfcf2843c, 0xc5b4b133, 0x19926a17, 0xe4b40490, 0x1d79bd11, 0x08523110, + 0xd570c966, 0x0264ca84, 0x49819d97, 0x29f414ff, 0x7135cb1f, 0x2773c1e3, 0xbf6bd69a, 0x4dc62d49, + 0xbf2cc738, 0xe55a16ba, 0x8ff7e849, 0xedce915d, 0x7746e330, 0x79c563c0, 0x91e91346, 0x6b803e23, + 0xf32208ca, 0x01e2a70d, 0x6fa0eda0, 0x0955dba4, 0x3f9e390b, 0xeea89223, 0xe8a193ac, 0xe2d8f2e9, + 0x276a2851, 0xf7aa61ef, 0xa1ee109d, 0xe2f16162, 0x55d60998, 0x6210920e, 0x380582b4, 0xe0c73b9a, + 0xbc785d93, 0x56c4fb8f, 0xb56cc9bb, 0xd7cb0fa8, 0x1fb2d9f1, 0x6ea5cd5c, 0x026822ec, 0x4f6ba84b, + 0x81fa40da, 0xebd3b52e, 0x5d98b9c2, 0x27396dd8, 0xe3fe7da3, 0x0455cebf, 0x7badbdef, 0x33b3783a, + 0xb9c6d792, 0x79599ec2, 0x65c0e958, 0xeec7e643, 0xe6b19503, 0x4da246db, 0x6df17e10, 0x7923a5f8, + 0xaaf3e6bb, 0xd351d5e4, 0x5a43aee6, 0xd8d7b669, 0xb829b86d, 0xfb48b1ba, 0xf146b98f, 0x47e0b4bd, + 0x7e144225, 0x2e9587b7, 0x36342114, 0xe9956e97, 0xb28c6626, 0x37c3f81f, 0xf8eea643, 0xabd27275, + 0x5d89c939, 0x7cbd1330, 0xc882ab45, 0xfe99382d, 0xf939f24c, 0x0e64e53e, 0x6f69d93b, 0x7c50c9db, + 0x899a85d4, 0xd19556f5, 0x36b636fe, 0x636fa894, 0x8cf683a5, 0x31315139, 0xafeae98d, 0x5cbd097e, + 0xb745cd72, 0x4a1976b0, 0xb9e446d9, 0xdf65fc6a, 0xaface788, 0x391bebe1, 0x4ff720d3, 0xfa742390, + 0x95769ce5, 0x777682a5, 0xc1c6786c, 0xa642f6f3, 0x994eea5d, 0x0df04c58, 0x83045c78, 0xb39eb222, + 0xa36cc485, 0xa56ad9f4, 0x3090353f, 0x7a90abf7, 0xa675af07, 0xb169e3cb, 0x85d16432, 0xd0a51c60, + 0x2ee2ea31, 0x24053778, 0x64f5bdf0, 0x7a123665, 0xb96d0c29, 0xe31fae2b, 0x4a3e12a5, 0xd2e3560d, + 0x6fd9f2f6, 0x30886706, 0x8d9a5315, 0x982fd284, 0x45790e71, 0x34bf4194, 0x692527d8, 0xd3c33b87, + 0x53cb55fb, 0xf8482606, 0x87a9fc29, 0x22371e77, 0x167bd03a, 0xfea0ca6b, 0xad4b7cd0, 0xcfad786a, + 0xe4654aa5, 0x18708d36, 0x342d2ec8, 0x24284ebb, 0x55dbf228, 0x6f25cbb2, 0x7c811f19, 0x7f0f3eb0, + 0xb0d6022b, 0x63d7ca98, 0x293a3588, 0xfc91fabd, 0x8fbfe474, 0x45af6cb2, 0x82e25b1b, 0xbc9a2eec, + 0xc2c651f2, 0x2c066cb9, 0x1c9eb71f, 0xd0566ac9, 0x7c69c0e1, 0x24597472, 0x212e9640, 0xc7ac2ea9, + 0xb9fb13e9, 0x5727baf7, 0xc2713edc, 0xa854a806, 0x260894a5, 0x3d4aae34, 0x8747ce7f, 0x21485ee4, + 0xe5f954f6, 0x93627e86, 0x4d9f6d60, 0xe15ba5ba, 0x05f04cfe, 0xdfa04196, 0xc1cea4df, 0xc6ba27c8, + 0xf0ffc346, 0x9d7909e4, 0xd390e961, 0x7ffb531b, 0x6028f47a, 0xb1c7f99b, 0x663a1c95, 0xcd11c5e0, + 0xf24cca69, 0x1cfcf3d2, 0xe9db3e21, 0x49274fd5, 0x6e759fdb, 0x45b1ed6e, 0x27dd3297, 0xe06defbd, + 0xb0e43517, 0x0a2a5598, 0x387dd50f, 0x6dff1f66, 0x8d13e076, 0x40cb5171, 0xb3155804, 0x0d07263e, + 0x9b2a23fa, 0x90e42d39, 0x69dc0a10, 0x9442fa1b, 0x94428703, 0xcafea283, 0x44a9a58a, 0x8593965d, + 0x8b699ed9, 0xb925e515, 0xa288e73d, 0xd59bfee6, 0xead513fd, 0x5aa734e6, 0x40948f44, 0x273cf784, + 0x6d7d2045, 0xd4f1007e, 0xf1a13fad, 0x64db7093, 0xec52dc43, 0x3f2cf9f1, 0x59513985, 0x65e58c9d, + 0x1ea01997, 0xd087f7d6, 0xc0e457ca, 0x39e81cb9, 0x43b94869, 0x1fde0c9e, 0x380c6b03, 0x1c5fbe77, + 0xacd1f242, 0x8fc4ba40, 0x657ec418, 0xa087c7f0, 0x62c1e066, 0x3d891b88, 0x9e91cdf7, 0x9f9b4603, + 0x1f6e58df, 0x109d13b0, 0x3c431eae, 0x94b019e5, 0x5f97329b, 0x2f3e7b3d, 0x0ee6f868, 0xcef10a32, + 0x1e6a720b, 0x762d63f7, 0x5558203b, 0x7677ba25, 0xc7df6f27, 0xfa3e05c4, 0x910067a5, 0x50dd8f9e, + 0x65c6c698, 0xd0b3b377, 0xbef37fb3, 0x89ea4518, 0xf71eee82, 0xbc835b2c, 0xeb2ba372, 0x6a532167, + 0x17c7e888, 0x381b0d90, 0xfc08c7f3, 0x8a6647c6, 0x3360998d, 0x03d646db, 0xb465e18f, 0x3480ae34, + 0x2e2a20ed, 0xd0c9cf8f, 0x6da62e4a, 0x7c3f10f4, 0x91115ce9, 0x325f947c, 0xd9e82b61, 0x565b3c4c, + 0x2ce9962a, 0xae53860d, 0x16b1d001, 0xc895fe94, 0x190cc476, 0xa42cd55f, 0x4d71afcf, 0xa94eeb59, + 0x4c536efc, 0xc3d967a5, 0x6f25704a, 0xf93b67a1, 0x8ba9745e, 0x39747238, 0x24e24fc1, 0xd618714c, + 0x9bdf0ed0, 0xaf2a057c, 0x91ab9ab0, 0xb87cf9eb, 0x9a290543, 0x4d50a6f0, 0x3275ebf8, 0x6c964001, + 0xb8184092, 0xb096b3fc, 0xf144cac8, 0x554f5c63, 0xca4e22c1, 0xfe547685, 0x57678be6, 0x841ced1f, + 0xfd2ab3e3, 0xe9b515fc, 0xd1b75f1a, 0xa7216482, 0x22ddc931, 0x81866eea, 0xbd9e4844, 0x7da67542, + 0x98d23931, 0xf801de79, 0x17f62202, 0xdd8b4288, 0x239b2bcb, 0xdec84d87, 0xf8b27f1e, 0x9936e4e1, + 0x52ec62ac, 0x1cb8b761, 0x30dfb6cb, 0xdc6f565e, 0xd274c4d1, 0x877f4712, 0x977841af, 0xd232463a, + 0x7004995a, 0x093afb29, 0x26a9584d, 0xe8684b9e, 0x2f696b35, 0x2ed1db45, 0x17b386fc, 0xdca2b2ea, + 0xcb97387f, 0x7debd798, 0x6022220d, 0xb28b841d, 0x28fcd61b, 0x1713eed7, 0x138a7e8f, 0xa3b3f238, + 0x641c1505, 0x2c226579, 0xb0de4fe7, 0x68d745c5, 0xaa717525, 0x27055a6e, 0x4e083ca8, 0xda2cc243, + 0x2d5b1d16, 0x5e4b0b63, 0x81c5198e, 0x3bcb1757, 0x40a170a3, 0xd03e0ae6, 0x8ae87eda, 0xe4b598d1, + 0x5bf0117d, 0xd4b9e3bd, 0x72f3b7bc, 0xf73e2515, 0x52ecbe37, 0x8b3cea54, 0x23aa2b51, 0xb71031ea, + 0x288b6649, 0xa140de79, 0x0fb3fc0d, 0x8885a7f6, 0x4727e49a, 0x3016c152, 0x3382beff, 0xb11658af, + 0xa4a154f2, 0x541d3fad, 0xfbdb6923, 0x6bbe8261, 0x6a47c7bd, 0x98fe7b4b, 0x5d76fe03, 0x9351db42, + 0x26dffb24, 0x76019476, 0xf662033c, 0xa91f5e8a, 0x621aecc3, 0xaa647034, 0x205130ed, 0x52327ab6, + 0x00414d4d, 0xc74fa454, 0xfcd04b6c, 0x08915609, 0x77f14e32, 0xb041edec, 0xea22edb1, 0x68d01817, + 0x42574152, 0x8976b2ad, 0x6f8cc1d4, 0xd8065eb5, 0x15336d5f, 0xcbdcead1, 0x8c819286, 0xf9ff52be, + 0x7658798f, 0xa91d7924, 0x9ca960fc, 0x6f0855d9, 0x43f096a7, 0x55662058, 0xe3d0a453, 0x127591b5, + 0x63ee7d02, 0x60a9f3f0, 0x21cf6b75, 0xc75bc27f, 0xdfd0c77d, 0x0405a3f4, 0xbe83250a, 0x10572c47, + 0x6d265e27, 0x0f3d56de, 0x5fbfe5d2, 0x4c093924, 0x9ac9e94e, 0x5f00d85e, 0x34ef5991, 0xa0e779ee, + 0x8b00fcbd, 0xbbaac27e, 0x270062f6, 0x058572b3, 0xefc7d6c6, 0xbdc0763c, 0x1a8de438, 0x8047a5d2, + 0x47c85ad0, 0xa18fdd4b, 0x3d965816, 0xe8d6746f, 0xcc378048, 0x5e411655, 0x8e454d40, 0xab66faf8, + 0x6add996a, 0x34dedf27, 0x728d8783, 0xf6acd369, 0x03cee5a7, 0x0665656c, 0x11dc6004, 0xc260fbe7, + 0x861fe2f1, 0x49c0609c, 0xda5a96c6, 0x6269a1a7, 0x3e922acc, 0xe8294bf6, 0x72d2cde5, 0xab69fd0e, + 0x79df7eb6, 0x3865bf06, 0xd383e0f3, 0xea6c2534, 0x908232de, 0x2e41d9a6, 0x5ebcc00b, 0x3f21a7b2, + 0x5f7d5a89, 0xc4b45afc, 0x7e6e51a5, 0xd3b10b2e, 0xac5c56fe, 0xfd09c1dd, 0x1702217c, 0xfae10ff2, + 0x9e7083bd, 0x8abd7a69, 0xb4a65130, 0x65f2927c, 0xb71dd4b0, 0x27bcb4e4, 0xfb738c77, 0xa8925dcb, + 0xcdcd25f9, 0xc1aec5d9, 0x56bbc20b, 0x053b9191, 0x086a7f13, 0x30d61536, 0x384eebbc, 0xc37df9b9, + 0xad6c5113, 0x7827ae39, 0xf6f0858b, 0xf12cb06e, 0xd0544615, 0x784a0934, 0x45a15458, 0x7dbc3087, + 0x6825cd37, 0xa320620f, 0x559fd998, 0x402ae1b0, 0x3f623130, 0x6651c90e, 0x7c198a58, 0x9db50aed, + 0x5e424486, 0x8194dc4b, 0x4d319fc3, 0xf011d0ba, 0x5943c414, 0x77fe40dd, 0xb36d55a3, 0xe348202e, + 0x0d36f435, 0x3d934421, 0x6ceb8e63, 0x94ad7004, 0x0acfaf46, 0xae863d65, 0x244bedf8, 0xc5882178, + 0x794d89c8, 0x8c6f3193, 0x5705585f, 0x6e0f5c65, 0xb70831e8, 0x1c79b93d, 0x8b8f4434, 0x6faefa98, + 0x8171e8ea, 0x794f11cd, 0x9d8a7397, 0xce01c2b6, 0x0c82a1e5, 0x19b2cf02, 0x73d15aa6, 0x7686a1ad, + 0x5700e895, 0x8daec94f, 0x43e83e41, 0x42ff2512, 0x0027bfff, 0x237500ff, 0x34ce6fda, 0xb56ed1ad, + 0xfe073bfa, 0x8a58e0c7, 0x5ef3a542, 0xfccac7d1, 0x2578f7f3, 0xd0749e6e, 0xdd570fe8, 0x8e53dbff, + 0x7c2f9594, 0x146b95c2, 0x8452ff98, 0x8e6ba290, 0x018777bd, 0xfe2600e0, 0x1be9aa4e, 0x9702626a, + 0x6432d441, 0xa8c17f18, 0x332f2ea0, 0x7ec49ef8, 0xb0cb0f0b, 0xe2f36d57, 0xb1d9f641, 0xf170c2bf, + 0x894b65a2, 0x0c48c942, 0x9aa920d8, 0xd2fc5c05, 0x70f1a6e1, 0x3cf60967, 0x37ef0725, 0xbd3c5811, + 0xc7ee9a6a, 0x3ea6f6f4, 0x75a4105b, 0x1c7bc510, 0xb4f3ca7a, 0x63010710, 0xef4b0ceb, 0x5242fba5, + 0x18a732f1, 0xca3e0a6d, 0x26b97f13, 0x529de7f4, 0xeefc306c, 0xb14bb1a3, 0x7f265f93, 0x4daeb480, + 0xf3fb1155, 0x4e016dda, 0xf3f9b981, 0x7971fe3f, 0x0859c050, 0xa2a297c8, 0xaa477f49, 0x6267cc60, + 0x922509be, 0xd49bbb2c, 0xbde7f97a, 0xe68aba08, 0xccfe0bd8, 0xd7fc016a, 0x5610acfc, 0xe78e2a0d, + 0xd34db7dd, 0x91068997, 0xd09ff38d, 0x26290f5f, 0x0222c56c, 0x86b87778, 0x03f68bbf, 0x5dc7f806, + 0x02b0f688, 0x7e5c3112, 0x402c2ba1, 0xf7693590, 0xb2b7f3d2, 0x0f059c13, 0x72cbd5e4, 0x376d9713, + 0x68209000, 0x44f45215, 0x27797662, 0x7f6dc209, 0x6d08359f, 0x287a5e5c, 0xd76a9352, 0x03d72845, + 0xcea92af2, 0x43a5fbf9, 0x1381ec82, 0x38fa5ae2, 0xaecc8c66, 0x128e353c, 0x0ba6eba3, 0xc4578242, + 0x6edbe74c, 0x1a6828dd, 0xe4bb59ef, 0xcc23e36a, 0x04a42ba5, 0x92f0d2e6, 0x32111d94, 0xe01f6c5a, + 0x767b164d, 0xe623a3e1, 0x1da91eee, 0x5566e707, 0x05b00ab6, 0x94db5a17, 0xa26204b2, 0xee162739, + 0x84a26461, 0x9a1dbece, 0x2f484a64, 0x8cc811ab, 0x92bfaad4, 0x07ffeefa, 0x8935cce9, 0xdf4334a2, + 0xe01462ef, 0xa4a17072, 0x99e8be1c, 0xd4d72e52, 0x196af8cc, 0x75bca2ba, 0xefb4af3b, 0xdff80d33, + 0x699091ef, 0x9b9b30a4, 0x391e02b6, 0xbc385c2a, 0x9b297b44, 0xd550da50, 0xf39085a1, 0xf1203de3, + 0x6b688d46, 0x6c75d6f9, 0x8f658ead, 0xd80cc8b2, 0x83d591d0, 0xcd6cf4d7, 0xb9946422, 0x9da4460c, + 0x1214604f, 0x2fdc8188, 0x78b7eed4, 0x8ecd241e, 0x16e6ba1a, 0xda8a55ff, 0xe7fef17a, 0xf285c3bb, + 0xe61ec8e5, 0x1de05cb3, 0x6fed7e33, 0xc9b20977, 0xeb908754, 0x92cec037, 0xf33481ca, 0x0bad69cd, + 0x78a78a0e, 0xdda72774, 0xb5164593, 0x06f2a242, 0xb10a110a, 0xff3cdaf7, 0x532e9651, 0x8ff4d92f, + 0xecde7f28, 0xe974a827, 0xd0524bb4, 0x3e82757a, 0xd6f664d7, 0x33ae5f04, 0x085cf000, 0x55506486, + 0x42ea09b5, 0xb07e65ad, 0xf69aa43e, 0x36a1bbea, 0xda286ae5, 0xd4595542, 0xa73c321f, 0x2d34b2e8, + 0x975a4566, 0x108e8fa4, 0x41a6bcb8, 0xb648c553, 0x0a93bf43, 0x7ddcaa65, 0xc1fc0cf4, 0xe2209b24, + 0x2899b0ff, 0x938aa39a, 0x6ebeb60a, 0x8411ba6c, 0x6610ac3e, 0x8adf3c7e, 0x5f85e4f7, 0x0ccb5a35, + 0x8f9dcc06, 0xaff76fec, 0xa2e071ea, 0xeef744e1, 0xb28fc2f3, 0x2c3181cb, 0x9098b568, 0xb907756e, + 0xbe8eda17, 0x695924a6, 0x627f8708, 0x6b1504dd, 0xb5a95811, 0x3a7d513b, 0x873a7f39, 0x2d8a6329, + 0xb06b6ed8, 0x0822b480, 0x090e11f3, 0x93bb0491, 0x353cedc9, 0xf61061ad, 0x52f1c674, 0x1b6aaa9c, + 0x17cead7f, 0x8ea9957c, 0x7abf96e3, 0x27d14f5d, 0x5f3a55e4, 0x477ccfca, 0xc3058637, 0xd63e3e91, + 0xca0fc1b6, 0x260bf044, 0x350d12c5, 0x35fc0a04, 0x9f036f8e, 0xd59d7474, 0xafd13744, 0xf7fd0daa, + 0x6e11a2fd, 0x57990e4c, 0x87a9a9ae, 0x6f427398, 0xd85f834d, 0x8ef84e6f, 0xd83d2009, 0x22036136, + 0xb4fa60e1, 0x6d15fdf2, 0x29da303f, 0x303c7f89, 0x3942bdda, 0x56a379b1, 0xf1b5aa24, 0x36e2876f, + 0x9d3fc75b, 0xbb9966a8, 0x9e2730e1, 0x5cc5ee9d, 0xd7462d9d, 0x63b0ec67, 0x3eaccdb1, 0x03ab203a, + 0xda9a51c0, 0xfabadc4c, 0x7e208ace, 0x529f6262, 0xb8ced3fb, 0xfb4fcc34, 0x727e14cd, 0x711c0df1, + 0x97748e4f, 0xf5ec3c26, 0x99628c4c, 0x32d647b9, 0x8e262626, 0x99bbb1cc, 0x6c2f4a0d, 0xf8e637a3, + 0x296e11b0, 0xdc85800d, 0x25f512f9, 0x6537f361, 0xbf861d83, 0x0285b635, 0x9d5dda37, 0xa1e1ca56, + 0x6ce74f55, 0x95c01bf3, 0x27859b49, 0xb9d08b0d, 0x9105fa5e, 0x6b6b3b24, 0xb15cb9bf, 0x21cb2c63, + 0xab919016, 0x20599543, 0x3ca78de6, 0xd4651057, 0xef045ed2, 0x8ac8f00d, 0x4c867efe, 0x3bb0d7c6, + 0x77afb9a6, 0x6c0881da, 0x8f603e7b, 0x156e16cd, 0x0fc31ec2, 0x1d848ac0, 0xd8f27011, 0xd836f2bf, + 0x592c47e0, 0xe218d452, 0xc55930d4, 0x5fc18a73, 0x642bac72, 0x986c6302, 0x1d59d416, 0xabada385, + 0xe27b9f8c, 0xfcda2779, 0x131bf486, 0x550b87c9, 0x3332c213, 0xa39d59ed, 0x071c2be4, 0x77f77bc6, + 0x6def170d, 0xef932841, 0x7facde24, 0x81140ff3, 0xe2f9cd99, 0xcff9be74, 0x96c350ce, 0x5e04f652, + 0x40294320, 0xaf776047, 0xbd151c11, 0xa298c026, 0x8d0525d4, 0x4214570e, 0x14682393, 0x720ed153, + 0xac133bb1, 0xa876cfd1, 0x08103d23, 0x5047f73f, 0x1dabb5a3, 0x5e16198f, 0x047de190, 0x74a010af, + 0x064040f2, 0xa5ef8286, 0x8a88011b, 0x2733d3d9, 0x4a488a4a, 0x5a91188a, 0xc03a7e4d, 0xca1b305b, + 0x70d7a79a, 0x92946eb0, 0xfe5a9d9c, 0xf35e5e84, 0x411bfc75, 0x6bc0661c, 0x1af504d9, 0x01ac0c37, + 0x575e6e5e, 0x3475505f, 0x48a3a324, 0x561ab63a, 0x1a890e23, 0x1590ab6e, 0xd667c744, 0x4a9eb5fc, + 0x211bc46e, 0x9c9ede74, 0xb8614dfc, 0xc526ce7c, 0x9800bf81, 0x5fc08ac7, 0x31471edd, 0xe1963a23, + 0x93a93cd2, 0xad6317cc, 0x314d1caa, 0x316249fb, 0x3febe774, 0x855e7590, 0x621f3d4e, 0xb7af12ff, + 0x649230ed, 0xa2ca92e1, 0x221aa539, 0xedd5e819, 0xc9d7b5cb, 0x80f90bda, 0x8a1a52b5, 0x33d747df, + 0x12ede668, 0x4628dfc7, 0x3d6005cb, 0x115f34e1, 0x61c121d2, 0xddf3796a, 0x82d276d1, 0xfb91c2b7, + 0x8c84c6da, 0xe34ed3c4, 0x530d79c1, 0x56d5a54b, 0x16a8e8a9, 0x41f13aca, 0xc84c9eff, 0xba962717, + 0x27f11ebf, 0x881f69df, 0x0be65d5c, 0x81552e17, 0x8d19511e, 0x69e43172, 0x9c6acdcb, 0x3fcd25cc, + 0x812d50cd, 0x8e5c68fa, 0x2fc07921, 0x5c953640, 0x961f69da, 0x94aa5766, 0x24f92836, 0x2da71fac, + 0xd5f479a1, 0x8e9144f8, 0xd7982163, 0x6fe1f3d2, 0xf131aeae, 0xbb19169c, 0x76ceec67, 0x7dac94cb, + 0xaf950988, 0xc81ae660, 0x7aed4af1, 0x87b1e22f, 0xbba8b2bc, 0x2baca9e8, 0xb574f985, 0xe364e8a1, + 0x7b79a5b7, 0xc601a284, 0x61b0b8d3, 0x15e8241c, 0xc61311f8, 0x396aaa68, 0xb6f1a8bf, 0x3f040bf4, + 0x5fae4a57, 0x69a034fa, 0xb7ebcea5, 0xafeaa427, 0x0ee4f7c4, 0x4cf5cbc3, 0xbd43f0f4, 0x54611a56, + 0x38d0324e, 0x5ce84bc8, 0x5a2291b9, 0xae1fa535, 0x2726a1a4, 0x0ed1c644, 0x9479bb13, 0xe8c2a6d8, + 0xc7bddb80, 0x8d87b52e, 0xf78ac70d, 0x84858904, 0xfdddc090, 0xe61c00e3, 0xaa93762b, 0x182c3007, + 0x1798d4a3, 0xf7c1c402, 0x4390bc0b, 0x74dde27f, 0x21f6f074, 0xd46047e2, 0x8dc107d4, 0xe7720d93, + 0xc7c85953, 0x6babc003, 0xbfd488b3, 0xdadb1683, 0x63aac705, 0xaad37ee3, 0x860b9829, 0x39818568, + 0x0dd6ab78, 0x7957dfeb, 0xc941e4d4, 0x5ccf9e57, 0xe124e63b, 0xb323a265, 0x4456c24e, 0x7812cc18, + 0x68a113bc, 0xd2f86d3e, 0x648663b6, 0xd964b85e, 0x8788b526, 0x08d069ae, 0x74386f4f, 0x124999ae, + 0x6452a11f, 0x51d4aa59, 0x4e712419, 0xdb532d9f, 0x559ae09a, 0x98369c26, 0x39b02fda, 0x84d23d07, + 0xa2590d96, 0x2f627d62, 0x394e6282, 0xe7bae600, 0x9be1eef0, 0xcc227e9f, 0xb21b5b91, 0x0151176a, + 0x0088e327, 0x49119e99, 0x6fdfdb89, 0xe9b467de, 0xcd031fd6, 0xe34cd441, 0x9775a60b, 0x9de121fb, + 0x60a8c119, 0xa722a62d, 0x1655e203, 0x10522a18, 0xb2ec6133, 0x7f200812, 0x0da84923, 0x43cb1004, + 0x9b093a72, 0x0e0a16f7, 0x88d990cb, 0x06894f43, 0x685b6032, 0xdf013e9c, 0x040afc55, 0xbd410a64, + 0xd1702409, 0x46f38287, 0x43618de1, 0x6da65922, 0x455f86e6, 0x1608265b, 0x6f08da55, 0xcebad20d, + 0x7e5532eb, 0x4ec0cec4, 0x1ef636ef, 0xdda9c546, 0x3d8bb826, 0x5a2730f1, 0x7ace6308, 0x50696dad, + 0x9987f1f8, 0x9e52da5f, 0xdcb56307, 0x08a7a3d9, 0xf9af5c54, 0xe271ff09, 0xeecb81b1, 0x4d334a52, + 0xb8cc79e2, 0xf68bae54, 0x541df299, 0x37e943fd, 0x908b32e6, 0x8f9195d9, 0x90312a82, 0x8ba538a3, + 0xa8265e66, 0x7bf0df48, 0xc10a9d9c, 0xb6bdfac6, 0xe485758e, 0xa694c8e1, 0x3b2bfdab, 0x883cb45d, + 0x3a272376, 0x59a601ad, 0xbaa10dca, 0x74c050c1, 0x66fad239, 0xc15a7dd6, 0x700d3223, 0x8885e850, + 0x085b6ca0, 0x350b9a49, 0x2844aaea, 0x83e3c589, 0xa2bfa2a7, 0x77133758, 0xf7f0be97, 0xa81be978, + 0xce52f544, 0x3dda39ed, 0xbffe91a8, 0xb12bd2c5, 0x3ed2bd9b, 0x97a2734c, 0x69052add, 0x3a3b68fb, + 0x51207cf1, 0x91fed386, 0x89c99e53, 0x4198443a, 0x4548fcd9, 0x1af85a44, 0x8e383bcc, 0x997450a9, + 0xfa65a9e6, 0x62400135, 0xd8e44889, 0x30a9b78a, 0xf8815337, 0x7709b259, 0x108b9761, 0x16fd5969, + 0xf6796466, 0xd90eb17a, 0x0612d98d, 0xd3d2dbad, 0xf328a952, 0x54a93497, 0xf591a2c6, 0x431bfe7f, + 0xc5f3eb54, 0x5c4abbc3, 0x378d4e49, 0x4ca94038, 0xebbba933, 0x762e2dd9, 0xcc8462b3, 0xc212c362, + 0xe24bbae9, 0xf62c3097, 0x9dceaee3, 0x94394aa9, 0xe7d06c7b, 0x235e2c89, 0xab454e8e, 0x31d6f4cd, + 0xf3bb1e23, 0x25e40120, 0x997bda29, 0xb39256f2, 0xa3e7d50d, 0xaab2d068, 0x2136e3d1, 0x72754c06, + 0xb8160a04, 0xdc1878e0, 0x1cd2d747, 0xab129e36, 0xbf1803a0, 0x69cfa034, 0xf9b05258, 0x1f52f3a2, + 0xd965f641, 0x548a8cc4, 0x026b71e8, 0x4447a489, 0xb2efc620, 0x81746efb, 0xf165444a, 0x4d82a45d, + 0xdcaa6551, 0x7102ec2d, 0x0744fff7, 0x1b37b991, 0xcdece6cb, 0x0046a158, 0x48875bd6, 0x50c20b44, + 0x8f50a18d, 0xaf0dea25, 0xe98c8793, 0x641d29bc, 0x07dada41, 0xd2f5cd66, 0x2aea754d, 0xdb601ace, + 0x33bbd7b7, 0x01d68281, 0xeb229076, 0x08d3a84e, 0x8301010b, 0xab400622, 0x74b50b9e, 0x41b03bfa, + 0x625b8df8, 0x34008f88, 0x354271af, 0x3e57b42a, 0x2631a990, 0xce72e4b5, 0xbc3045d0, 0x1608b3c4, + 0x0aae8107, 0x7e45970b, 0x2dd0364f, 0x6879eac2, 0x458aac3e, 0xb0b522d8, 0x3b6c4aab, 0xf658d5de, + 0x17a3a11b, 0x0889c453, 0x9ed8202f, 0x0cd5b602, 0xd6f958d6, 0xdeae3dd8, 0xed90c419, 0x6e41f6d4, + 0xb4ca87f8, 0x2dd56e65, 0x80cdc751, 0x2c24eb1a, 0xfafa3abb, 0xc5e60c56, 0x3afbb1aa, 0x1ff871b7, + 0x06c057e5, 0x3a7d0d08, 0x762841cd, 0x4f520f3f, 0x6b83f59c, 0x5ab97fc5, 0x228f3337, 0x5105f1e2, + 0xf700540d, 0x18c7305a, 0xb6072b0a, 0xd06029b4, 0x31dfc887, 0xd97089bf, 0x85716e46, 0x6e8bf3fe, + 0x12600d71, 0xb5c7811e, 0x5b553756, 0x101782fe, 0xa736bed3, 0x64aae6cf, 0xb6b2707a, 0x2073a4eb, + 0x6178a4ad, 0x0efed3b9, 0xb26a749e, 0x1c237514, 0xd2d495ec, 0x337f6850, 0x67d125a1, 0x1d1db8ea, + 0x3890ace1, 0xeff55d2e, 0x9c9ae17b, 0x6b862c2a, 0x16a82e57, 0x4eb60910, 0x22bb32f5, 0x5c033111, + 0x61af4146, 0x55be967e, 0x451749fa, 0x80d2177d, 0x0d3a9d89, 0x77c90cf2, 0x14baf04a, 0xc6a7440c, + 0x89c6a380, 0x8799fb5d, 0x9293a717, 0x8380015a, 0xf5e17d05, 0xefc38286, 0x337766e5, 0x2ab1d702, + 0x1d350216, 0xbdb63095, 0x2c223b48, 0xf1549ca0, 0xa2fb62db, 0x795afc21, 0x39bb45ef, 0xa6aacda4, + 0xfaf1aa16, 0x7c95e643, 0x5adf2f31, 0xfc65dd6e, 0xe5ea9173, 0x27ccab93, 0x8333bed1, 0x49aca4d8, + 0xb1e6f46c, 0xcb41c77d, 0x1bdc0098, 0xaae04638, 0x5c01f5f3, 0x8ca9601d, 0x1c2919b9, 0xba6baef0, + 0xd185f1f2, 0xfbbb4237, 0x7ae95289, 0xc363feab, 0xe4215c5e, 0x67bd7f14, 0xd15b7d0c, 0x7a92c19a, + 0x964028a7, 0x1cf7922e, 0x551112a0, 0xf0ce5129, 0x4a51aa0c, 0x1cec5bf3, 0x74df48fb, 0x09bd1448, + 0xe1288080, 0x1a76b307, 0xa9274200, 0x1cac914d, 0x500bda1e, 0x992d3d43, 0xf1b3068c, 0x35aad603, + 0x14de4566, 0xd83b399c, 0xdeb6447c, 0x72b5a5ef, 0xfd7316ec, 0xdab1426f, 0x65ec3725, 0xa07563a8, + 0x0d02b85e, 0x7752aecb, 0x6b91f5b1, 0x793731a2, 0x97316aea, 0xfc4b75ec, 0x1ea14c08, 0xa2d51bb8, + 0x5207523a, 0x64024392, 0x08049d6a, 0xff4dd0aa, 0x12c47c36, 0x44cc7b5b, 0x2a2b88e1, 0x3ec5f932, + 0x971185a6, 0x65410728, 0x9b170cce, 0x313c7363, 0x68744124, 0xb6b202b2, 0xd12b75fd, 0xc2926a69, + 0x1a3e58e7, 0xb1da89f4, 0xb5a9fae4, 0xcebac828, 0xa4bcb901, 0xfe841791, 0xaec54119, 0x6d166aa4, + 0x19885e19, 0x3513e7e1, 0x3308b848, 0x44124402, 0x05158a58, 0x7057abd3, 0x9f8758f2, 0x94733fe8, + 0x99570c3f, 0x0d648549, 0xda65a6cc, 0xe236c467, 0xfa483ac1, 0xd569a147, 0x67f73f03, 0x6c5f2898, + 0xb08a861c, 0xdfd80e62, 0xf200113f, 0xf8ef4730, 0xc3ee568e, 0x5371252a, 0x4f8b6029, 0x537bc062, + 0x22420811, 0x6bc991dd, 0x34c14ddc, 0x03553e1a, 0xbb3082dd, 0x92a6362e, 0x424e0eb7, 0x166523ed, + 0xaca30c8f, 0x51c71790, 0x58351069, 0x975519a0, 0x38df6641, 0xf7983ff6, 0x548a0d27, 0x69c51dc8, + 0x53d119d6, 0x46790ba2, 0xb5cdcb94, 0x364cf8c5, 0xf10ab628, 0xe276b5f6, 0xa4f9e590, 0x9dcb488f, + 0xf237f46c, 0x9b19c009, 0x846113f5, 0x9679eda0, 0xf6cb7f5a, 0xc4a55b16, 0xf981bacb, 0x8f0cec14, + 0x376b6b9a, 0x2f799358, 0xc389b740, 0xccf7dc3b, 0x6179c275, 0x25667964, 0x236d3dd9, 0xb68e68ca, + 0x86d5aa62, 0xdd85aa84, 0x083e94f9, 0xfaddbd06, 0xdd7ca9d1, 0xb2da3b45, 0x95d61cce, 0x92ce2980, + 0x7378ec63, 0x0a734ae1, 0x3d1ee93f, 0x244fe647, 0xff0f3672, 0xcda9e0be, 0x814b820e, 0xe74ce191, + 0x69d942bb, 0x1f89e77d, 0xf38589cd, 0xeb22e305, 0x20b55299, 0x0a204850, 0xc2f3b24f, 0x78b881e1, + 0xe78ffd9f, 0x34bc6f1c, 0x3309766f, 0xca2dea07, 0x46edb0a3, 0x18a07afa, 0xcca656cb, 0xb7ac653e, + 0x1e82f98c, 0xe095c364, 0x9786cb91, 0xc4bac8e5, 0xbbc6dbe8, 0xdb48d4e7, 0x56e9694f, 0x7ac92cea, + 0x5745da19, 0x3468da93, 0x93143cfc, 0x70b3fa28, 0x4371fe51, 0x7672dfac, 0xbbf97cbb, 0x11a00041, + 0x9209ea21, 0x323fcb93, 0x7c078806, 0xa0595bba, 0xc1396a32, 0x60302022, 0xbe49c8de, 0xd44a7198, + 0x081299f0, 0x6d555e9e, 0x7b448d50, 0x3f4ae67f, 0x10d2e128, 0x16a9efe4, 0xf3d1a049, 0x296666c7, + 0xbe751fb1, 0xd8ac3222, 0x60cf2116, 0x69ee4a98, 0xb3697029, 0x6de33a94, 0x5a057506, 0xe17fce31, + 0x37507989, 0x29f4f409, 0x297734db, 0xc9497c44, 0xd6610167, 0x21e1c373, 0xde3b4d80, 0x8dbf7742, + 0x9b8bf402, 0xbfb58ea7, 0x712cd2c1, 0x0d3ec20d, 0xff72975c, 0xf8cb4c75, 0xec8447b1, 0xd64e4f87, + 0xf312cd7a, 0xbe9e9bfc, 0x721d7da8, 0x75700a5d, 0x1f3b77ee, 0x84eeff5d, 0x1e23b721, 0xd055da9f, + 0x751df2fd, 0xf2fce34c, 0x82883287, 0x97782749, 0x60cd5c6c, 0xd0c000ca, 0x642e13b0, 0x55346d32, + 0x10dd7aa1, 0x1ef42d28, 0x422976b4, 0x9fe9ced2, 0x3c1535db, 0xea61a875, 0x6d82e911, 0x1970b0ec, + 0x58ff4980, 0xe2f28a43, 0x22b8a13b, 0xfe951dea, 0x9e33d739, 0xe32e9f6d, 0x3ce19f94, 0x2fe06adc, + 0x49980956, 0x4210c921, 0x31e9e79a, 0xc970d630, 0x13bf0fbc, 0x52a63078, 0x15c9c86a, 0x550d65d9, + 0xff5a7823, 0x257a7c78, 0x24a15b61, 0xd0817e3f, 0xadf9846c, 0x8849e2dc, 0x18940fd1, 0x55b6f760, + 0x252ad44d, 0x36e56fa7, 0x4a4dde4b, 0x6099b7f2, 0x1a746dc7, 0xa2fae27e, 0xeab9d7e0, 0x174c4a27, + 0x9953964b, 0xbda382ce, 0xf0fe65a1, 0xd597a38d, 0xf433b047, 0x81c33c49, 0xab5dd75e, 0x31435d80, + 0xea6d7d4c, 0xa76053ef, 0xa80b7dd6, 0x3d84536e, 0x68c06c50, 0x0a6d8aff, 0x80a1a22a, 0x6a667f7a, + 0x30ff0e17, 0x7ad915d6, 0x822f12cd, 0x334124d7, 0x228bdf8f, 0xc916ed62, 0xe395f442, 0xec4b59be, + 0xbe8437c7, 0x49cc582b, 0xee44cd2f, 0x65083c8a, 0xb8713346, 0x09e6c078, 0xc167793c, 0xc67d930c, + 0x1c523e7a, 0xe610c77c, 0xc1734860, 0x86281b9d, 0x519485b1, 0x69d1fcfb, 0xd11c1357, 0xbf833cad, + 0x75adc04e, 0xd59f89f8, 0x03493775, 0xa5c761ed, 0x3e07fde3, 0x1b40dd19, 0x5376c248, 0x81baff1d, + 0x061ed729, 0x4381f11d, 0xb40dcc6e, 0x3df2461f, 0x9141738a, 0x5261b90a, 0x01d6fb3e, 0xb31d4483, + 0x0bcd13b8, 0x0971a069, 0xdf465a2f, 0xf4b976fa, 0xdb052c14, 0x85ec7b8c, 0xad8c3e27, 0xf550e7e2, + 0x6841db10, 0x7013e771, 0x85c7b955, 0x6d46ba91, 0x0413fa66, 0x295db654, 0x9ade2c8f, 0xa545c53d, + 0x5f5539ec, 0xe5747017, 0x59b4e5bb, 0x5a2228a8, 0x7b1856c8, 0xc888b9a3, 0x57d50cde, 0x8de44507, + 0x0a5a0be2, 0x5565b7ae, 0x69c58cb6, 0xd86e0733, 0xbf75bf59, 0x44d47ded, 0x7149a7e9, 0x8695bfe9, + 0x8d92e45d, 0x0b1637ab, 0x8dfe5969, 0x1393ed74, 0x494e06a5, 0xcb2636cb, 0x1d5fb1eb, 0xb9a35fad, + 0xf81f000b, 0xf132b6f0, 0x506a28dd, 0x8105571e, 0x8f45fb9d, 0x8d454e37, 0xbba150b0, 0x49d2c1ca, + 0xd3d56bb1, 0x44183757, 0x1988375a, 0xcfdf259d, 0x463bd27f, 0x44411fee, 0x77d98080, 0xd59ad8a0, + 0x3e4584bf, 0x1b773ac6, 0x68f97d26, 0x89125666, 0x3967f848, 0xd08ce0b6, 0x63bcdd2c, 0xd0bb006b, + 0x3ea78400, 0xbc23f061, 0x5d3d5c94, 0x83562511, 0x141b466f, 0x2a933d57, 0x5cde2ebd, 0xfb8c8e85, + 0xa00ba478, 0x004da6ff, 0x412c0c77, 0xd04b2c5a, 0x5284e75e, 0x98ce30d7, 0x55d21384, 0xf75b1b70, + 0x1526e4a3, 0xfa129387, 0xd086592c, 0x78c43e87, 0xa377a03f, 0x165886ae, 0xecdcfb92, 0x950ddd6c, + 0xb0a8aef3, 0x2f8c64da, 0xf674301d, 0x7aec28a0, 0xea8ac139, 0x80aa9323, 0x5223c100, 0x1f09c2b7, + 0x9b90dab8, 0x7b9035e2, 0xe14e94ea, 0x067a52fe, 0x275a2226, 0xc47bd3d8, 0x36f26011, 0x62d49b83, + 0x6217f47f, 0xd1305624, 0xa38e04a3, 0x61ef452c, 0xe687ded6, 0x2a169c29, 0xfcaa4e90, 0xb016275f, + 0xf9ac2404, 0x2a8f745a, 0x9911ab0e, 0x9b795aa9, 0x50de14da, 0x5b44f37c, 0xc062ef37, 0x7cebf504, + 0x908dcbcc, 0xf551f785, 0x83d48a46, 0x8db9426d, 0x03346559, 0x35ea09be, 0xc8f1bfdf, 0xe33bede3, + 0x2a5ff2e9, 0x054aee85, 0x1be75739, 0x51790e56, 0x042eb08d, 0xdf06ed3f, 0x4f132563, 0x886be683, + 0x73fccd17, 0x4cbc7b97, 0x65d25f3f, 0x66d09837, 0xc4044913, 0x627f4bde, 0xa12d6440, 0x9e944b07, + 0xa4690362, 0x474e6cd5, 0x51b70078, 0xfc762bc0, 0x5ef16286, 0x3758786f, 0x5bc2ef6b, 0xb7bc4900, + 0x992e718b, 0xe7d7fd8a, 0xbb681cd2, 0xcd7dcb65, 0x28e8111e, 0xc5d1b2f6, 0x2506f51d, 0xff59f082, + 0x34045d40, 0xdceb78fb, 0x00906088, 0xeccd83a2, 0xaed78b22, 0x23c31120, 0xc0f47fbe, 0x2311590d, + 0xe204cfe7, 0xaed69c0c, 0xca96ac73, 0x3b3499a8, 0xea31d3fa, 0x73a4a88b, 0x9cbe1cd0, 0x56e00f49, + 0x4327008c, 0x3f07f565, 0x91807ffb, 0x68870c4b, 0xecd629bc, 0x2f0d0ae5, 0xf27354a6, 0x46fbd865, + 0x9661251d, 0x046bd9a4, 0x8bf77d9e, 0xf2064d55, 0xe8ffbff7, 0x26e71889, 0x901a673f, 0x3a3513ea, + 0xe0b1a870, 0xe8ede9aa, 0x6ca39c26, 0x4670f3e1, 0x0c873c33, 0x52a4d315, 0x7048fb1d, 0x7cb41103, + 0x4380e329, 0x00f282fb, 0xd8aa6bd6, 0xae269dd1, 0x089e8690, 0xd8320793, 0x59191aca, 0xfdb30b3d, + 0xe22e792a, 0xe241ea7f, 0x7d83877c, 0xa5ec8a39, 0x62284a15, 0xa8183548, 0x7e0025a2, 0xfff86f77, + 0xe1abc096, 0xcf7024ca, 0x1eaf44bc, 0x53de428c, 0xe516a8aa, 0xc5f6c5c0, 0xcc994d66, 0xcd854b90, + 0xb46d9782, 0x9a292039, 0x680cdc9f, 0xcb19998d, 0xaa6703ec, 0xd88f0974, 0x49cf15ac, 0x15b0df7c, + 0x2dfbf4b0, 0x2fd73dd1, 0xe0329421, 0xe1f84571, 0xfa9d8fef, 0xec66fa42, 0x0afd5df1, 0xf135b449, + 0xaf7e4e8b, 0x980a985f, 0x5dd31891, 0x479ea148, 0xb32feecc, 0x8193079a, 0xf41dbb41, 0xf78c483f, + 0x2c8ea6ea, 0xccf34f0d, 0xd6de9fe6, 0x81007e2a, 0x744dccdd, 0x5e5df33b, 0xfb170b12, 0xb6906953, + 0xcf914e5c, 0xfb5b0ad7, 0x9dc353f9, 0xce9545cc, 0x152641b9, 0xa7ec19b8, 0x1ec546aa, 0x1240f3d9, + 0xf1244e26, 0x52e50c60, 0x25948714, 0x7d26d161, 0x2feb3cd1, 0x4a356389, 0x27f9d2fc, 0x8e8a663f, + 0xae266a7a, 0x32835741, 0x3f3e62e9, 0x2d4fba11, 0x32dea58a, 0xb8512ea3, 0xd8f133d5, 0xdb3f2902, + 0x126dbf17, 0x7bacce6b, 0x235b0c77, 0x4e4eb6cb, 0x283a0b68, 0xa9601046, 0x3f5d3606, 0x86081b83, + 0x8ac47250, 0xaa5e772d, 0x361faa37, 0x7dc846d0, 0x6fbc3280, 0x80d5a57e, 0xbb6bbcc3, 0xeec461be, + 0x3ecff418, 0xfcb5c7b6, 0x13de0c67, 0x89b61e93, 0x9cc4f13f, 0x66346604, 0xa4022f3c, 0x5d690772, + 0x7e261191, 0xfb4d0e78, 0xe3710e49, 0x5d0b11d8, 0x0d63f15a, 0xe68fae4a, 0xc100ffd8, 0x4aa493b4, + 0x17d2ea25, 0x4516744d, 0xa1142267, 0x4eface2b, 0xefcb0fae, 0xd884800b, 0x5815502f, 0xd5fcae69, + 0x571591ca, 0x803783ab, 0x8db540d9, 0xa578fb9a, 0xa4294196, 0x245da334, 0x8f3dfaa4, 0xa8982cba, + 0x2f31820b, 0x0949993d, 0x6cbdff32, 0x20fe8d07, 0x3bc2686d, 0x0a718de5, 0xc17ef3ca, 0xd4f24ca6, + 0x89cbd2b0, 0x2c1ea911, 0xaeafbcd2, 0x443bfe58, 0xf235861f, 0x6e3f5e08, 0x199d4e7f, 0xca697301, + 0xdd5301cb, 0x94662cbd, 0x1618c7c8, 0x21e3ca2d, 0x2ab42526, 0x8b7fe894, 0xe87f4aee, 0x84015c84, + 0xbcfddc23, 0xe8b046e4, 0x317e4174, 0x60153615, 0x27914499, 0xf1092ff1, 0x19ba46ab, 0x9c043ccc, + 0x6b7c8e58, 0xe5f73271, 0x7bf1e980, 0xb481f3d6, 0x3ade6212, 0xa0cba899, 0x6b77c08f, 0x77a02e46, + 0x042d77aa, 0xfa233236, 0xf1804678, 0x1fe3a2fb, 0xc94229fa, 0xf7229bd2, 0xc6dfe2f2, 0x4d3264cc, + 0x6a91c08b, 0x86535eb1, 0xd2ac1038, 0x31590a0c, 0xebb729f7, 0xc8bdabd7, 0x074a4614, 0x20bbf76f, + 0x27ccd9a6, 0xc4bc57a0, 0x07f11ff9, 0x7399bb54, 0x9c098b13, 0xacb1e892, 0x04c71392, 0xb80f22a3, + 0x126b7878, 0xd322e124, 0x7d3931e3, 0xf84b4809, 0xf2bd7758, 0xcb5b7896, 0x035a10eb, 0x12a10ccc, + 0xcc729a71, 0xecd5f741, 0xeb9e5357, 0xb90247cb, 0xa3a824c7, 0x3f0e659b, 0x34c00b6a, 0xa82677e8, + 0x4c112534, 0x27fea215, 0xd1e8cb3d, 0xfcc0afe8, 0x53a6cf63, 0xe29fdb62, 0x1e62a70d, 0x89e6e6f4, + 0x90c9da10, 0xba3e48e0, 0xa7796635, 0xff61351e, 0x626e935a, 0x06f73731, 0x8d7be99b, 0x244b6599, + 0x5789529f, 0xaa11159d, 0x5c1a1f07, 0xa96d976c, 0x9d7b3224, 0x9fd67dcc, 0x75961365, 0xbae3707a, + 0xf6b63526, 0x9443e76f, 0x07481849, 0x662ba57f, 0x73092af9, 0x3b1f9a30, 0x9ea56107, 0x5dd36ab4, + 0xc476c7fa, 0x2a79564c, 0xedb27d26, 0x89d14ef7, 0xe4471218, 0xbcc660c2, 0x178b3715, 0x382151d4, + 0x1a8cec9c, 0xc39cea4b, 0xe26fb9d0, 0xa9e4b88f, 0x3a027c3e, 0xba1274cb, 0x8861531a, 0xd2b14ffb, + 0x62bde375, 0x162a1ab9, 0x8dbd63dd, 0x7de12d64, 0xaa5f3806, 0x0405821e, 0x44f0d964, 0x9220c4e9, + 0xfacc0392, 0xfc016ae8, 0xd438bf1f, 0xe757c6f0, 0xeb914427, 0x92596ef3, 0x58cf7d5e, 0x0bd4bd59, + 0xe63f7eef, 0x691a2b5b, 0x0491fc3e, 0x8ae21d4e, 0x450bdb9c, 0x91380202, 0x9009bd76, 0x1327677d, + 0xfd5420dc, 0x3f5716c0, 0x394cfb42, 0xc09335e0, 0x12bb497a, 0xefbf7a8d, 0x185d5868, 0xe8264c19, + 0x04822e14, 0x4fffa1f5, 0xae8be8bc, 0xbd822a3c, 0xc5361ac0, 0xc21b6455, 0x2810da4f, 0x50291af1, + 0xe6bdf23d, 0x2a23f5f2, 0xc460d93d, 0x43561c42, 0x0148ff78, 0x8946f9c9, 0xe589383e, 0x9924d608, + 0x7c217e8b, 0x926f992f, 0xf8f6bb13, 0x3c596ed8, 0x9a2619d2, 0x4c4e81f5, 0x92035310, 0xa83bca8f, + 0x7af1806a, 0x24a52025, 0xba9b8aeb, 0xb2feaba5, 0xc32b54ce, 0x74709732, 0x7784d797, 0x9bf7eb42, + 0xf3a2a2a3, 0xa491e7d3, 0x77e274d7, 0x9de967ce, 0xbe676070, 0x318e4451, 0xc1823381, 0x04a051ec, + 0x505c4715, 0x3b01bfeb, 0xf675d098, 0xe88257eb, 0xf66562c3, 0x824e487b, 0x035d5227, 0xa6895865, + 0x14396d01, 0xbd6bfb35, 0x7cf0ff7b, 0xbad77887, 0xc92685c0, 0x29a65e11, 0x733606ff, 0x3f4acff5, + 0xa78a3c30, 0x7cd4b24c, 0x1e1e8181, 0x153456b6, 0x05e6bced, 0x42d1ebab, 0x1b93ebfb, 0xb5b01ce8, + 0x4fbb9ca0, 0x4db2bbb8, 0x99ede6c6, 0x71da9c05, 0xa44e09cd, 0xc7b0793d, 0x280873a2, 0x3b98e317, + 0xc45b2cda, 0x521e556b, 0xbc66d30d, 0x2f23de48, 0x66b786d2, 0x6c4009aa, 0x2adf1eda, 0x1d668430, + 0x6acd533a, 0x198969fc, 0x71ecff8a, 0x616b0038, 0x940fd3f7, 0x92a85ce9, 0xbf39cb54, 0xea228ccc, + 0xd5fe630a, 0x6381bb15, 0x83de36d0, 0x0d68bbed, 0x7e0a5902, 0x3b5be81a, 0xec058a95, 0x4a5d53e5, + 0xfd9f0ee1, 0xf51a4dfe, 0x56fb1297, 0x7c0b297c, 0xb87b6e7a, 0x88ed9fea, 0x285bfb31, 0x716850bc, + 0xf21725fa, 0x4a217a89, 0xb5275292, 0x35c55714, 0x096b64ab, 0x454a0ecf, 0x8a5f1fd6, 0xbee1c8f8, + 0x74ebc70f, 0x07d99d75, 0xfea1efc7, 0xcea4c9f0, 0x96ccffcc, 0x921739cf, 0x252131da, 0x6138064e, + 0x35ea104d, 0xaa7e2065, 0x97b9e267, 0xebb84c62, 0x79fe8a2b, 0x5ba4e87f, 0x99d03ffc, 0x1b1295ac, + 0x06d2833d, 0x4b18f1e0, 0x173c2af6, 0x35329ecc, 0x77a5fe79, 0xb864859f, 0x55491555, 0x89f6fcff, + 0x3b534e77, 0x2822b18b, 0xf2e3baf7, 0xd3cb7921, 0x4f1dd3e8, 0x83184c40, 0xc628525c, 0x142a9e09, + 0x404a1380, 0x14ae689b, 0x03463029, 0xd2953601, 0x52120117, 0x302ea2d8, 0xd72743e2, 0xb4abaf37, + 0xacc89e57, 0x867dc3b1, 0x43bace90, 0x7d6055a6, 0xcd8d3b18, 0xc21fac6e, 0xff648264, 0x8a921475, + 0xe2a4f7e8, 0x931dbaae, 0x40ed0e63, 0x53441fa7, 0x577bff9f, 0xdde34ae1, 0xa70f6ce4, 0x95243b37, + 0xacabe634, 0x27eaa09e, 0xb11c2a26, 0x72a8dba7, 0x08587a93, 0x985fafe8, 0xfc948e19, 0x8e604aa7, + 0x908b67fb, 0x197e5ed1, 0x00d4c23a, 0xf791d069, 0x84774269, 0x37de6071, 0x975c16f9, 0x2211f76c, + 0xf6c611fd, 0x52554d2f, 0x41c00be6, 0x4eaa8e0a, 0xff256aaf, 0x1f1ee356, 0xf8717616, 0x6c12436e, + 0x51344249, 0xbc353847, 0x1cee1fb1, 0x3f89e373, 0x88708b69, 0x9acefdb9, 0x27c01146, 0x59e9d491, + 0x39b5bc0b, 0xd409f92f, 0x0f69bbda, 0xb23de7df, 0xe3e020e4, 0x6907f6fc, 0x6658fc28, 0xb40ca32a, + 0x0e40c759, 0x51fa0ff5, 0x4e396754, 0xbe1258f2, 0xb01ce735, 0x3eafd790, 0x05efa292, 0x5170e0d6, + 0x84d7a161, 0x8f8c584a, 0x113c66c3, 0x8f462e45, 0xf2b20327, 0xa6173846, 0x8c4ff631, 0x5649d7b0, + 0x0726c359, 0x4b4a05f5, 0x89f25c6e, 0xf0b94478, 0x1e74e0b6, 0xd9e575ef, 0xce4590a1, 0x162f46c6, + 0x28184c1a, 0x51dbcff4, 0x096b03b4, 0xd6cdd56d, 0xa2be99e1, 0x1d1f413d, 0x557c7beb, 0xbc6a8e25, + 0x753e7e7c, 0xe59d7c48, 0x4ae5af51, 0x3dd79d8e, 0x2f80def8, 0xf2258665, 0x187b9df2, 0x90b2c0a3, + 0x6d7d1845, 0x041d2f39, 0x0b546b12, 0x5b2f3f9b, 0xd9a0ea96, 0x6dd9c024, 0xb44bc6ff, 0x9e31927c, + 0x3fe41a75, 0xb16b8a74, 0x65b79856, 0xf500dc1a, 0x93441944, 0x934613a2, 0xafdce1b5, 0x109e24a1, + 0x97b75176, 0x9212c61e, 0x9120a593, 0x19003976, 0x5a527097, 0x626cd442, 0x538045d3, 0x3d54b9a1, + 0x62277816, 0x330c7bc2, 0xea462f90, 0xef8e3f19, 0x655197b2, 0x3a1e654a, 0xf459466e, 0xb26d5b29, + 0x74f08523, 0x3f35b53f, 0xf00ff4fd, 0xf7b4d038, 0x96ff98ec, 0x2bcb9c37, 0x8232b05b, 0x2156c123, + 0x046a8094, 0xd54be624, 0xd6d29014, 0xada21fa3, 0x60ff92a0, 0x20fc6951, 0x1bf9fc93, 0x1a47bada, + 0x959dd6d2, 0x2f13a07c, 0xef490fd9, 0x670936b7, 0xff08dcc8, 0x30ab213f, 0x5d167760, 0xe365f629, + 0xec0bc223, 0xb01aadf8, 0xec60c2d2, 0xbe5ba991, 0x0a7ca7e5, 0x529b2f82, 0xd49c68f6, 0xdb335004, + 0xf818de4a, 0xe8b089c8, 0xe910d900, 0x75eb528b, 0x80cf5451, 0xd525587e, 0x84812845, 0x4f9bffb3, + 0x25268d74, 0x99ae27a9, 0x1a3a60dd, 0x7b5c7d17, 0x29086e0e, 0x25a047d0, 0xa82af53b, 0x5a8a2d65, + 0xfeb0f3aa, 0x614fd2f9, 0x9e1d8b01, 0xdf5d68b1, 0x7c9a2d77, 0x97941dff, 0x09346e36, 0x5c63eb8c, + 0x45f1d381, 0xfb229717, 0x0452df0e, 0xfc4a5303, 0x7aae4d16, 0xd94ddbe6, 0x67745a48, 0xfbec7a2a, + 0x3ac58b42, 0x584b008b, 0xd97c83a5, 0x58ee5558, 0xc8a9741d, 0x2ecad0b6, 0xebbb977b, 0x06444e4b, + 0x0c9f23a9, 0x2407542e, 0x78114214, 0x45c88947, 0xf7c3c4d2, 0x486877aa, 0x76911fa4, 0xa64e06c7, + 0x45b6f990, 0x8b8a91bf, 0xe8eae26f, 0x6456c469, 0xe297b8c2, 0x9ad0ec0a, 0x46ef8d8c, 0xd9d54f47, + 0xe5527f39, 0xf3828a99, 0xa2313c78, 0x8191745b, 0x67eef295, 0x6411a381, 0x6da5cb5e, 0x9885e604, + 0xd11b0f70, 0x376b62cc, 0x5ce6fc50, 0x8c764318, 0xd5c12870, 0x76b78d7a, 0x49e149e1, 0x09f7932a, + 0x943091ab, 0x3d47e1e2, 0x3cfb693e, 0x91a0369a, 0x3b2906dc, 0xe9366bf2, 0x7528f693, 0x9fe17d28, + 0xea4b0e19, 0x856b8b96, 0x5740e66c, 0xee204ef0, 0x920f0024, 0x323c386f, 0x94aef782, 0x30bab47e, + 0x1775ff29, 0x98851c9a, 0x4a1cd749, 0x019b1ab7, 0x9c651bac, 0xf4e50efd, 0x6634d7c7, 0x6aa2a5c2, + 0xecfa9b82, 0xce889145, 0xc31de443, 0x6e98370d, 0x6bc37af2, 0xf037b55f, 0xd4ace060, 0xdc0c7f49, + 0xe623dd64, 0x02f97d71, 0x72b3c86e, 0x87f75b92, 0x0168fe4f, 0x4d6b79fc, 0xf87559aa, 0x6294ffdf, + 0xd61c8ea4, 0x76010859, 0xa5dd9c6d, 0x975aee94, 0x7df80cc3, 0x39d060f1, 0x0c8007b2, 0x862201e7, + 0x555a7175, 0x32ff1fe1, 0x96075acf, 0xf688b3e2, 0xf208f825, 0x0a028b37, 0x9edb106b, 0xfc480975, + 0x3a7ff721, 0x90870e2f, 0x51d1b09d, 0x020e96a8, 0x4586d9b7, 0x48ee9381, 0x605aff9d, 0x4c0a4d51, + 0x9e9b2f16, 0x2f029d76, 0x9c6937be, 0xec278702, 0x02e87a44, 0xebed8869, 0xd817a600, 0x995679c9, + 0x35cbccbe, 0x78d5d3e6, 0xea37892e, 0x9c5a6743, 0xbee3c5a8, 0x36a0d4f9, 0xd2a3d554, 0xd84ec478, + 0x1cb4165f, 0x2241befd, 0x2e0270c2, 0x12d5ff86, 0x133fd092, 0x9631b1f6, 0xcd20e5be, 0x8b4bf99f, + 0x65c01dfc, 0x03d25dc0, 0x864244c0, 0xa4f81d0e, 0xf94d34a5, 0x6b0c34bb, 0xb3c786e5, 0x2ea48546, + 0x29651b8a, 0xa05d5265, 0xef1e7e2e, 0x6b613f5f, 0xa53e18b0, 0xf89b6f84, 0x7af8751a, 0x4371b8cf, + 0x4066318b, 0x35acf4bd, 0xdc71f2de, 0x63ac0e54, 0x88ec404b, 0x1500ffe0, 0x2ad0e390, 0x63076519, + 0x3152da7b, 0x0a130d62, 0x44a25efe, 0x7bb81053, 0x9277dc4c, 0xb44de5ad, 0x83893a88, 0x279eeeb7, + 0x0cabd9e1, 0x2dedeab2, 0x6f2ad8a1, 0x7d81466d, 0x1ff2e7df, 0xa6fb5587, 0xa8ff41d5, 0x31937edd, + 0x5b19aa5c, 0xf37d3d11, 0x0388b09e, 0x2e9efa62, 0x5aa23915, 0x5edab98d, 0x1079a3d0, 0x0280bf89, + 0x0a57d9c4, 0x1795cc3e, 0x2240e7ec, 0xaf870613, 0x5b91cb4a, 0x3c4528bc, 0x1f807122, 0xd2591d3b, + 0x1ca5bfaf, 0xc7ba111f, 0x2754200f, 0xfe8aed33, 0xbfe4bd5d, 0xddad6844, 0x83aaa6b2, 0x9a00b299, + 0xee78bf59, 0x12624b0f, 0xbeb2195f, 0x1378248c, 0x81d98944, 0xe8d36aca, 0x6b2ea5a5, 0x0818b2d8, + 0x7e8aad3f, 0xfae65914, 0xe5ac51f4, 0x896500da, 0xb0ac6588, 0x7a389b4e, 0x763ffa45, 0x325d220e, + 0xbf5715a4, 0x159fa3b2, 0x2be92bab, 0x77fbb916, 0x5a62c5d1, 0xb17d59c1, 0x3e73d376, 0xf7fe6038, + 0x9c3ec169, 0x1034c9c0, 0x31604052, 0xd4fb19d3, 0xb1ef1cef, 0xed93a0aa, 0x97558037, 0x84ec2502, + 0x932fae93, 0xc36d995f, 0xe8047088, 0x0c6814e8, 0x44fd9744, 0x40a7c82b, 0x5b745bea, 0x2e6a938b, + 0xbaf939d1, 0xa10d8c50, 0xf8ed0b9c, 0x1a8e6467, 0x32fe4518, 0x4e761d3c, 0x1211722a, 0x6763dd73, + 0x32db6780, 0x84c4d10e, 0x4376bf40, 0x0f40b128, 0xfea108e4, 0x09082138, 0x7bb14c6b, 0x22464473, + 0x8423eb61, 0xd171a070, 0xba8e6c7d, 0x810df79b, 0xd0cc24f6, 0x4a0074e4, 0x4de50195, 0xc5f61390, + 0xa76af696, 0x87506ff7, 0x74b33e8b, 0x0c0065af, 0xbebc124e, 0x338ac0e0, 0x8ae05300, 0x9ce6991b, + 0xf0b7d341, 0xec5c3bc7, 0xe0ee7fdb, 0xb572751a, 0xfd5b3de6, 0xd1a85799, 0xaabe0b4d, 0x646c26b1, + 0x8e849800, 0xbb1797f8, 0x15215bc1, 0x1f039573, 0x289dba6d, 0x13b531dc, 0xdd7b2b91, 0x1645b667, + 0x44505ce1, 0x4ec37d42, 0xa3457052, 0xf8622a0f, 0x99c83715, 0x3c6a5ce8, 0x6e8e5c5f, 0xf23e7540, + 0xd7b13c1f, 0xb4cd5c50, 0x1bfae249, 0x43fda3cf, 0xd886b1db, 0xd3177f49, 0xd9cc70cf, 0xe3ca81af, + 0x5b512844, 0xa58cd16e, 0xe1444ade, 0xd89eefec, 0x7ca1f0dc, 0x05c67365, 0xfee7b25c, 0x5cb12d16, + 0x43b158bd, 0x2d22e630, 0xbebda29a, 0x943ec0a5, 0x11c07fd3, 0x33497f9d, 0x274289c0, 0x9c7fde8e, + 0x8630bc36, 0x50fdbb9c, 0xd5dba833, 0x628fae37, 0xc954a370, 0x8dbc3473, 0x9288b5f0, 0x9441ecef, + 0x9631a521, 0xe99139c7, 0x9b17f320, 0x69232aeb, 0x4032b8a6, 0x496f168c, 0xf0b486e6, 0x738a6c49, + 0x2dd7c7a2, 0xd1bed324, 0x40934aea, 0x64173390, 0x4ab316f6, 0xb344e615, 0xc4a4f1f3, 0xf3599db8, + 0xc19cd3a2, 0xe959cc6f, 0x4a8408d4, 0x88744fdb, 0x0fe5b2f0, 0xf9b4cfe9, 0x82e34d94, 0x0810996a, + 0xbaaf2ada, 0x16aa412a, 0xa8874f99, 0xd635f5d2, 0x090bda33, 0x9faa4659, 0x30085eed, 0xa8b5a959, + 0x96df9cd4, 0xfcb97817, 0xd36ec0ae, 0xf0de9038, 0x00e0ae5f, 0xc915233a, 0x1c8028e5, 0x6723a80f, + 0x36dd43f8, 0x81fd9580, 0x105bc648, 0x5d5d0897, 0xaa002947, 0xd6c35668, 0xe6f25be9, 0x8c5eccbd, + 0xb514babb, 0x656c0975, 0xaa28aa42, 0x47e4b4c8, 0x14a8fcc9, 0x42cef811, 0x435d70bd, 0x0e23aa58, + 0xb756f626, 0xd8270dc3, 0xce3add32, 0x2705ee2a, 0x6aace406, 0xefe90465, 0x071c5e6f, 0x10cec8f5, + 0xd397d8cb, 0xcd0ef524, 0x0a88eef7, 0x8149491c, 0xe4108054, 0xd6b0a292, 0x2b86e8c6, 0xb7795175, + 0x74b8609e, 0xaca40fe2, 0xb64ea36b, 0xb8db4f7d, 0x3ec0073b, 0xe9534e09, 0xc5a7dbb0, 0x5df98e0f, + 0x070046c9, 0xc0e4030e, 0x8024a0db, 0xc7e805c5, 0x2d40d5e4, 0x39b59b4e, 0xffd69b57, 0xa2c187c0, + 0xd06dca34, 0xccefb882, 0x0a763276, 0x7d3e75c8, 0x737bdfba, 0xa1bed914, 0xa91cecaf, 0x5275e9d0, + 0x899416df, 0x88147e35, 0xfd2207ea, 0x276cf4b0, 0xb9686988, 0xc1bfa7a8, 0xa0ec4fec, 0xddb43aa8, + 0x6ef16437, 0xf611cad9, 0x79ab29b8, 0x3c6d170b, 0x9a959840, 0x1c7b6055, 0xeef8c673, 0xc42664a3, + 0x38c58c41, 0xfeb2f269, 0x74c4828e, 0x284bb990, 0x7c732c89, 0xe6205068, 0x000fc2e3, 0x9565aef0, + 0x536d62e5, 0xfbed683b, 0x283b1830, 0x99d78806, 0xa54f6090, 0xd98b3486, 0xdb735da4, 0x885e9d38, + 0x90537667, 0x5a05e5b2, 0xb549ffad, 0x56991c00, 0xde710d27, 0xc0f89e47, 0x83fc4595, 0x45848c93, + 0xc5a125ed, 0xac6972b5, 0xc201e78c, 0xa313cde8, 0x9c0b27b6, 0xc824be65, 0xe1b217ec, 0x6822517c, + 0x8d5403a9, 0x2e3b6d6f, 0xf7395c1a, 0x37db390b, 0xa9057524, 0xe797f5ac, 0xf68bf315, 0xbe0822c2, + 0x6b4b6e58, 0x30af4024, 0xd729a1f7, 0x1c38b47f, 0x10a3dcea, 0xf13a0cf5, 0x366dff2b, 0xac5ed0fc, + 0x1208734e, 0xc61350da, 0xb477cfb0, 0x60699bd3, 0x8ac7b834, 0x2cbc7b2d, 0x0ed31015, 0xc711cd4a, + 0xd61df87c, 0x285b522b, 0x2eda7b1e, 0xac32aa1d, 0x329c6110, 0xb7347ef8, 0x57f47ac2, 0x6057e4bd, + 0x94cf9503, 0xa320b808, 0xc6996bbc, 0x20e14158, 0xd1f2f378, 0x334ae15a, 0x4ad1f96b, 0xd2ac7573, + 0xbf82db90, 0x2d7774a0, 0x68236a85, 0x1b3bdb55, 0xc3d0955b, 0x92d42a4d, 0xaa07060b, 0x50607187, + 0x2dba8dec, 0xf2611bc2, 0x325a75dd, 0x065f25c6, 0x7017a9c5, 0x7fb234d7, 0x3c93ea6c, 0xf43e1ef6, + 0x5f3b1716, 0x4d4cd77d, 0x4beb58c5, 0xfc55989b, 0x7a4d6c31, 0x41015ac4, 0xb1aa70c6, 0xcdf73d17, + 0x202e6aef, 0x24facba6, 0xb771bc9e, 0xd9d04284, 0xc1bef075, 0x143acd93, 0x691a3c5c, 0xf2fbaa52, + 0xb4d75e1a, 0xd142a6a1, 0x3213677b, 0x168fd7e3, 0xb9b8cdf2, 0x6150df9c, 0xea4c0bda, 0x8d3d3acb, + 0x1202bdf0, 0x3ad549ca, 0x5dbe5280, 0x27bb0a84, 0x49b9c06d, 0x73a2f3c9, 0x637a26f8, 0x93270109, + 0xb68f4f0c, 0xfad35acc, 0x134a6df3, 0x3de71297, 0x7222b02a, 0x43644207, 0xa48af686, 0xe7ded6f6, + 0x02d75f76, 0x14d2bbdd, 0xcddff1e0, 0x631c8b35, 0xd531fb75, 0xf699b9d9, 0x9617678d, 0xd7c90d88, + 0x1badd8e5, 0x958e3410, 0xfff58411, 0x75ec636c, 0x12cb2923, 0x393ca098, 0x1f2ff1be, 0x6aa2744f, + 0xee4ad272, 0x6f41d3b5, 0x23ab2952, 0x68688e3e, 0x0184d79b, 0x42f0b57e, 0x5c94024c, 0xe3da3f7b, + 0xb3823563, 0x5027abca, 0xba861a9f, 0x2f3b3386, 0xb72aabd1, 0x9d4cb785, 0x0432e17c, 0xb0dd2544, + 0x964d8bb7, 0x29fde3f8, 0x8f202108, 0xc7539076, 0x5c287520, 0x516e6435, 0x88943b22, 0x062e964e, + 0x349b742f, 0xf336a74f, 0x13ab1bac, 0x4a9d4257, 0xaac13522, 0xd76693e4, 0x8d9fd537, 0x04af6732, + 0x1852c476, 0x379ca99c, 0x07f58888, 0x54f17c12, 0x2f26fde7, 0xe6a38c65, 0xf726c6e5, 0xb216474a, + 0x841104d9, 0xa5ca0a1c, 0x720f276e, 0x180851a0, 0x7032c3a4, 0x9fb3fe93, 0xfd265218, 0xdf919726, + 0x43c0fbae, 0xe4934ce7, 0x4456ed15, 0xea9bb7d1, 0x5018ab59, 0x36f771eb, 0x5cea2de9, 0xa1612a23, + 0xc97ec559, 0x83e38b64, 0x8cb31bb4, 0x56bf0138, 0xf9270c8d, 0xc03cf18b, 0xef64290d, 0x6ad640dc, + 0xcdd80ea3, 0x06c05602, 0x10819a4e, 0x8cf1fd97, 0x45332446, 0xa5a5994a, 0xaabff77b, 0x18737726, + 0x7660956d, 0x2246e871, 0xf1498939, 0xf78b5ed1, 0x712e8fed, 0x6602ca4b, 0x4524f9e1, 0x47fd79d6, + 0x9175c768, 0x81b4e4ea, 0x43302ba9, 0x25877ef2, 0x0f6552df, 0xb9124aea, 0x8de452a9, 0xe0902720, + 0x3d2da269, 0x6d5c22f4, 0x11b96c2c, 0x0ab1932c, 0x974c8f6c, 0xd9025699, 0x5186c504, 0xaf9a4db0, + 0xb31854c7, 0xe669f707, 0x62beb87c, 0x20b8cc04, 0x94904090, 0xc5110c2e, 0xd8fee635, 0x275b5fd6, + 0x83238b65, 0xaac81cdf, 0x1f7aa400, 0x5b820f8d, 0x0ecdcb3b, 0xcb7f5df5, 0x33784483, 0xeaddbbdd, + 0xe1e388d0, 0x9d525b6e, 0xe72a7cb8, 0xe7e84621, 0xebfcc3c5, 0xbe1a343d, 0xf2c4d94b, 0x8f936a42, + 0xdfdf0dce, 0xb3b45844, 0xe1866b49, 0x1e572fa7, 0x52c24682, 0xcfbc0613, 0xd3ddabdc, 0x163884aa, + 0xb3cc1f4b, 0xf2675bf3, 0x063aeb14, 0x1c75396a, 0x327e5258, 0x1336a32b, 0x5792f2c3, 0xb918d414, + 0xc5e0b309, 0x0b8b271d, 0x3447f1ba, 0xeb9100d8, 0x4e3f9c05, 0x9a335b1b, 0xc93da1ee, 0x258eea73, + 0xd271f527, 0x77557cd6, 0xfc4eb3d2, 0x5cb3f7f5, 0x99f2d0d8, 0xcf5c2a9c, 0x578b0899, 0x792aa2d6, + 0x29542c46, 0xdf16fc1b, 0x4c7d28fb, 0x0de8f19b, 0xf6fbe049, 0xf9dfc154, 0x04685f58, 0xe9e78f46, + 0x6ecdcbb8, 0x2e8ed1a0, 0xaa78cf40, 0xeb18785f, 0x71532e57, 0xe251df15, 0xf1e197f0, 0x5e58f58c, + 0xd660e86e, 0x955f8953, 0xd57fa6f5, 0x79911469, 0x8ac4f3ee, 0xcd65e4b4, 0x813fa2de, 0x61e1b45c, + 0xd95c5643, 0xfa59c3be, 0x9104da5b, 0x78854af3, 0x11662240, 0xb1afcccd, 0x92a1bb69, 0x1dc369a3, + 0x11355dbe, 0x8c1ec3a8, 0x135c4a7e, 0x806bb98f, 0xe7261f62, 0x4701fd07, 0x751593a8, 0x89ac54cb, + 0x66e015eb, 0x1cef0f34, 0xf888d35a, 0x3228efeb, 0x804a001e, 0xa9268b46, 0x0eb91a0e, 0x07331087, + 0x050cbb4c, 0xf55d0f5c, 0xc67e4ca9, 0x58fad34b, 0x587f7ba4, 0x3dd7341e, 0xf3211960, 0xda4cbcb9, + 0xf5945f69, 0x2694c2a7, 0x2cf695ae, 0x5d7c23ad, 0xde39bf27, 0x684fddc5, 0x57c90021, 0x1a891ef2, + 0xed833831, 0x437a83b7, 0x85872ad3, 0x0d0baeac, 0xf4553f52, 0x6877d88c, 0x6cd49f45, 0x3e4df2ac, + 0xa4a12ff2, 0xf3837943, 0xdd7b25bf, 0x23962b3a, 0xa388bf00, 0x5a8318cb, 0xe0f97c7a, 0xbdd56110, + 0x299c9741, 0xf799b2d0, 0x85f5cfa3, 0x6ed93741, 0x72d2d6d5, 0xb959b8de, 0x0e6b2334, 0x5121ae90, + 0x3da58af0, 0xed296994, 0x8a39281e, 0x9fc223c7, 0xc4a2aa86, 0x3f8c198e, 0x202d9a67, 0x06e7329d, + 0x3ea032c0, 0x99d48f4b, 0xaaeddd59, 0xb48fee77, 0xf2cb8dbd, 0x4fcf2921, 0x259152de, 0xc1dc9056, + 0x72312c8d, 0xc155d0dd, 0xbfda8214, 0x4c13bd1b, 0xc0627c89, 0xf079aa75, 0xea70c1c7, 0x2584cba2, + 0x0ca60032, 0xcadfe7f3, 0x46f733a3, 0x8987712f, 0x2f34c30b, 0x63f92439, 0xe4ffa0a8, 0x020c7ecb, + 0xd138996f, 0x518790dc, 0x64b2fb64, 0x20434008, 0xc82b1b60, 0x141e6b6c, 0x0e74d5e8, 0x4c972462, + 0x72518a5d, 0x636e83f4, 0xccfd6bf7, 0x20e9c97b, 0xaa1622a2, 0xb8463891, 0x4a1ffce2, 0xef3a6b7a, + 0x2cc51fdb, 0x98939f9b, 0x17cc5e77, 0xd60c363b, 0x8ee72dd2, 0x7527679f, 0xe7201898, 0x89dc79da, + 0x1e194f83, 0xc2253dd7, 0xf3572d63, 0x91ea6959, 0x046b7295, 0x2f54e72f, 0x592a18c9, 0x00bd2542, + 0x0835fac2, 0x11054d9c, 0x0a4f399a, 0x5b4e642f, 0x705ac183, 0x5af37ad4, 0x293efc7e, 0x3c5e88f3, + 0xb871d920, 0x069d6f1d, 0x0e79e9ff, 0xc581018d, 0x0927fdd5, 0x50170086, 0xa22d343d, 0x1a772a4e, + 0x8b0e1d14, 0xb47a0b4c, 0xab466bfd, 0x661f90e0, 0x657b05b2, 0x572553a1, 0xf3798205, 0xfed682fa, + 0x417ee0e5, 0x4a34b373, 0xbef04297, 0x0d1213bf, 0x223a8495, 0x613e60c7, 0x9f22d04e, 0xec8bbe87, + 0x592a9615, 0xf892ea49, 0x6d023bbf, 0xaed6ceab, 0x4db77f31, 0xe92ad989, 0xe3f7fdc3, 0x9c6f8cf4, + 0xce3d9885, 0xae6c83d2, 0x1b7e9655, 0x2d117fe0, 0x7e1426be, 0x2664bfbf, 0x3b998db2, 0x8f1cd10b, + 0x95385fb6, 0xf576b255, 0x5b98d873, 0xdde8fd34, 0xcf3cb40d, 0x1b523304, 0x3923f71b, 0x5e1dc110, + 0x013b93d2, 0x087338a6, 0xcf059f20, 0xe9578220, 0x5243395e, 0x951a4819, 0x595465b4, 0xc0e491fa, + 0xa7583a24, 0x4caeac3a, 0xd113d9dc, 0x761d7cc6, 0x6311450d, 0xd1ea78ab, 0x2337a84d, 0x5ea76dd8, + 0xb83b99ea, 0xb41c9c65, 0xf0f4473b, 0x1cc58830, 0x57a1a72a, 0x6ca78eb3, 0x047d3194, 0xe4352034, + 0x972ea88d, 0x8b4db480, 0x56829ce4, 0xb3b83a42, 0x171036e0, 0xb443902e, 0x23b02d54, 0x8827327c, + 0x9d91b738, 0x25fc90ac, 0x2f95df4b, 0x715559d4, 0x53912c0a, 0xe91051f0, 0x278cc48c, 0x4bc657e6, + 0x1f35a082, 0x5e09e64f, 0xda1954fe, 0x4bfb3c96, 0xc67266a4, 0x1db729e2, 0x5249be68, 0xb8ab2f41, + 0xffce55ca, 0xcc106d5c, 0x55ac7d61, 0x892d97ec, 0x50c7a8dc, 0x980748f3, 0x18404bfb, 0xb0c02556, + 0xfd509868, 0x472fcbaf, 0xe3c967bb, 0xda0767f4, 0xb42d9449, 0xa8d1efa6, 0xa98a8e93, 0xc69833dc, + 0xf1937d49, 0x3de76654, 0xb61a9696, 0x6e811957, 0x873141c4, 0xb676efeb, 0xbf65922b, 0x797f5722, + 0xbd8667b2, 0x85ac7f88, 0x395b79c1, 0x5e12f863, 0xd53adc0e, 0xe152ca52, 0x644ff077, 0x2a8471a1, + 0xa0c51cc8, 0x120a8a34, 0x98328f13, 0xf118e3c8, 0x6163d142, 0x2404c32c, 0xf88f6724, 0xed086bb8, + 0xdbe1e7e0, 0x0cb51042, 0xe6f441f0, 0x6be1b84d, 0x104e6542, 0xb5a10cfb, 0xc13d71c7, 0x66832f35, + 0x2c50a685, 0xb2bbab62, 0x18f4b4c3, 0x613008c2, 0x8f8f2e48, 0x957faa59, 0x827112cb, 0xcd98e255, + 0x796fe2c0, 0xb8c69534, 0x1d428669, 0xf18e838c, 0x3d87e2e2, 0x9962cf55, 0x982df6bd, 0x1751931e, + 0xffb72927, 0xef597b83, 0x4aef5637, 0xeb9dc398, 0xfdfdd452, 0x04114cad, 0xcb4dc6db, 0x63658e33, + 0xb4cf180f, 0x5e9009f8, 0xff5523be, 0xec3131ba, 0x85f4f19f, 0xfd8d5915, 0xa2ec7992, 0x8defa6b2, + 0x0eaf634c, 0x409c76f7, 0x98f4ffc0, 0xfa781d42, 0xfef71609, 0xf7ba4d27, 0xfd30cca2, 0xc615893f, + 0x8a1f1626, 0xccdda154, 0xb9380acd, 0x0f714983, 0xef9261da, 0x7db098c1, 0x7b01bdb9, 0x63c0021a, + 0x851435ac, 0xfa438e02, 0x944b25d1, 0xb51d91a5, 0x0cfd333f, 0x7e39bbba, 0x1985889a, 0x8a7a4268, + 0xe42264fa, 0x4acb3e1c, 0xfb3a6f2b, 0x33628341, 0x895e5012, 0x7ec95a15, 0x62ca6bb0, 0x6be970a9, + 0x59c86da1, 0x400d9801, 0xda3035e2, 0x230ad8a7, 0x05be6ed4, 0xc91f63e9, 0xe3472b23, 0x5fb4cd49, + 0x52e2f100, 0xfaf3c434, 0x0b61a61e, 0xd75d0eb4, 0x40b83cd7, 0x9cf967a3, 0x9ed3e0dd, 0xafabd1c9, + 0xeb44ad41, 0x231d5645, 0xf9c89515, 0xad037bde, 0x9204ca48, 0x3e3afdbc, 0xc219bb8b, 0x13090ff8, + 0x99ed3e38, 0x56d70a64, 0x8e73e03d, 0x983f7502, 0xf6fed2a5, 0x8318f68b, 0xbc10bcf3, 0xcc2668da, + 0xb01e321c, 0x06df22ba, 0x30503227, 0x75770bb3, 0xc13f280a, 0xabbeec33, 0x0af033d1, 0x4c4cd71b, + 0xe83ad478, 0xce594f69, 0x1c16914e, 0x1ba8b286, 0x71830477, 0x43d56396, 0xf2ca6194, 0x35d9d1ac, + 0xe54210e5, 0xa8430b20, 0x7723d220, 0x8aaf8a62, 0x647f11f6, 0x691dd609, 0xacc9f9de, 0x3cf892b3, + 0x776b95fe, 0x1a079ba1, 0x153ce0af, 0xfe6aa27d, 0x43423fca, 0x2c2a5965, 0x5a2b9917, 0x202dcf0d, + 0xb364fbc9, 0xe5f8db79, 0x6b8f37e1, 0x4f24106f, 0xcb626a8c, 0x543d9bcb, 0xa1a69c88, 0x29350a37, + 0x4a4df730, 0x08a27385, 0xe7c8e6c4, 0xaaa65c5b, 0xb0afef2b, 0xd6e1f011, 0x66d90035, 0x4e8af534, + 0xc4a51663, 0x135882e8, 0x722caa60, 0xb663f3a5, 0x85ee0d5a, 0x3efafe1d, 0x2ab56c78, 0x1ac0955c, + 0xafda5fb6, 0x16b82000, 0x1e743c72, 0x54df3c77, 0xb444c367, 0x58b617b6, 0xaef0d1f8, 0xc203a9d9, + 0xfba7cbf3, 0xc4ecf035, 0xf200e5ff, 0xb166334c, 0x99cfae9c, 0x5ea140e2, 0xb8d8c000, 0x048429f0, + 0xf0195bf1, 0x1d211e98, 0x06e32a37, 0x2f57e45f, 0x5d87b63b, 0x757b0b18, 0x93ded378, 0x80b9cf7a, + 0x4a1f4b7f, 0x2affcbeb, 0xcb7b93b2, 0x01bc6bc5, 0x435a46c5, 0xc3fb03c5, 0x35cdd1ae, 0x81805819, + 0x84f6055d, 0xd4ba43eb, 0x08d66f29, 0x770a2cda, 0x8b6b71a9, 0x77a1db0f, 0x19173119, 0x9134de6d, + 0xa9d875b7, 0x62126ddc, 0xcaaa0be0, 0x0d6eb450, 0x35c29ac5, 0xb33d0688, 0x5229463b, 0x24c75f18, + 0x526585d2, 0x5327f587, 0xe09c8766, 0x004a933e, 0x2a8a8bcf, 0x87e93cc7, 0x38b2b1fe, 0xe65f4da4, + 0x9b6044d4, 0x133d8a2c, 0xccda8756, 0x8d40d43b, 0x0ce8c5c9, 0xef445759, 0x6cfdacf9, 0x3f7ea6ea, + 0x545205ce, 0xc9473943, 0x34d6725f, 0x7212632d, 0x5951f5fd, 0x0f38c6ea, 0xec720192, 0x43f3a78b, + 0xcd8e755e, 0xd3f6e862, 0x9d158d2f, 0x2daaf963, 0xe2bb394a, 0x51aa946d, 0x08806f52, 0x5c9ea682, + 0x8db1c6c4, 0x7f8f103c, 0xe020faca, 0x678ccb42, 0x3d1e046e, 0x0bad5f4d, 0xc523f2c6, 0x34ea9e10, + 0x84e93843, 0xe88a0d83, 0xe3ae458b, 0x41350fa0, 0x5be4f8a6, 0x40b059e6, 0x1d750883, 0xa7210103, + 0xb0d03c80, 0x7d73a7ee, 0xd7193cac, 0x75d3d339, 0xe3574c66, 0x2e08b1a4, 0x9999a5d4, 0xcc0327de, + 0xb28a6781, 0x9641d023, 0x6e3f6cdf, 0x7f50c297, 0xd963eff0, 0x524a8965, 0xd72a94b0, 0xecc52a51, + 0x05c46828, 0xfe5532c9, 0x055d6ffb, 0xf7b4fccf, 0xb69729fd, 0xab7304fd, 0xc39f7d30, 0xc3111957, + 0xac621e05, 0x2ed3b2a6, 0x29e2ba8b, 0x3dd8a192, 0x26824d87, 0xa0495191, 0xc86d2a7d, 0xf544b63d, + 0xe4e3fc38, 0xad89f1ae, 0xfab08ca3, 0x01c161fe, 0x88dd0b05, 0xe60a96c7, 0x25982b78, 0xdac68007, + 0x3f58769f, 0xf9d69f27, 0x4b45d21a, 0xa724d4ef, 0x47f1b696, 0x001f87cf, 0x45703f40, 0x049fd808, + 0xd01fcd70, 0x150765f1, 0x5ce3f5c5, 0x560f6a52, 0xc865e5f4, 0x7190e82d, 0xd94118b8, 0x86b6b388, + 0x0f1679e8, 0xdb1f7a79, 0xec694ab2, 0x3dcb2673, 0x1e9c1eb0, 0x3c4fb253, 0xd7c0623c, 0xe3a860a2, + 0x41383081, 0x53fed70f, 0xf88e9344, 0xa5b9cdec, 0xa5932b46, 0x632f44f8, 0xd21cc37f, 0x09de8172, + 0xc4483307, 0x5f5389e2, 0x8e4bc4a8, 0xc61f6167, 0x06d2247f, 0x1bdbc8d6, 0x4865387b, 0x03e9a06a, + 0x17c7f4b6, 0x8cc0583f, 0x5a7c6d44, 0x6407ea27, 0x4c9f0c8e, 0xa5247070, 0xc394b488, 0xc6e853f9, + 0xea6a4c82, 0xacf93bcb, 0xf9a4cda8, 0x5f3b2869, 0xe3758e39, 0xb3a0679f, 0x224a56d6, 0x1c649a46, + 0x453ea42a, 0xd2686a7f, 0x9763e7aa, 0x6167788a, 0x5cd4c89e, 0x65e383a1, 0x757f2050, 0xb2243618, + 0xb0eecaad, 0x5f545d14, 0x57af80ef, 0xb983946b, 0xe9749f93, 0x037f3448, 0x5bb59a1d, 0x55b9de62, + 0x78292657, 0x4c4e3358, 0x2a241c8d, 0xdf8090ef, 0x6239874a, 0x1863c594, 0x8d2f36cf, 0x410e4ba4, + 0x6ace4a68, 0x44778b9f, 0xd950d830, 0x675a83c0, 0x7440567e, 0xd46338ac, 0x31627b90, 0x22215318, + 0x4ac8d6f2, 0x492712c5, 0xbfd6d1cc, 0x839321f3, 0x129bec32, 0xaa3a182e, 0x582291e5, 0x0b43aff3, + 0xd852a278, 0x8712041d, 0x4f713ce0, 0x493abbc8, 0xac74c499, 0x9b327283, 0x2a3ee57a, 0x75ddfcf5, + 0x5de3a367, 0xab19dafe, 0xbf0cf357, 0xc419fa4c, 0xe53cfd13, 0x05e046b3, 0x917971d0, 0xab2885e1, + 0x1e6b0b91, 0xf5d9b364, 0xd0c01938, 0xda44749f, 0x769d45f2, 0xb8f3d211, 0x59e3f77b, 0xcb09bb91, + 0x804d95f3, 0xdd97e5f6, 0x2591c5d7, 0xd06c296e, 0xc74fe410, 0x28546d14, 0x2c5809bf, 0xadb878d5, + 0x4f24b319, 0x9ff2967d, 0xcc8be546, 0xc6fc5f7a, 0x89138d8d, 0x7ad8d2ed, 0x4086d0ea, 0x3f275d03, + 0xcd2e3b0a, 0x8485138f, 0x93788952, 0xb60c92c0, 0x033c738c, 0x1731163e, 0x8dcda81e, 0xa7157eb3, + 0xfc9b95e4, 0x4e83db48, 0xafb2de0d, 0x9ffb0144, 0xdf7fdc61, 0x1c13a111, 0x5c462901, 0x2fcea381, + 0x7d18cc5b, 0x947e0e71, 0x93bdb88d, 0x0b244ccd, 0x9e40fc1b, 0x5913a213, 0x055f371d, 0x74799d67, + 0xad6262fc, 0xe08d1784, 0x55f8e292, 0x572778a6, 0xce4a7271, 0x04f227a7, 0xb6672e5a, 0xec605ba3, + 0x4a340685, 0xb3e7e588, 0x05a40921, 0xc20e58fc, 0x7e3218b5, 0x9a96755b, 0x3608650b, 0xd56c5454, + 0x306937a4, 0x9ba0e80e, 0x5cb3f1f0, 0xe0758888, 0x02f84347, 0x847c426c, 0x87b1885f, 0xe31756e6, + 0xe8ea3461, 0x767c0888, 0xb0eb80d4, 0x709a1fc0, 0x795d494f, 0xda6e36e4, 0x622025ca, 0x649c7852, + 0x67f85796, 0x2305210c, 0x6817a87a, 0x594137f7, 0x7bb5916d, 0x92f123d1, 0x415c1603, 0x6bdaf246, + 0xe0dc6713, 0x32c92bab, 0x94e54690, 0x635ecbac, 0x5b330b7f, 0x31b0922c, 0x1f9d0b42, 0x722023a1, + 0x63fce2dd, 0x605ec8a7, 0xde238a84, 0xe472ce84, 0xda4fae4b, 0x0c3a0bd2, 0x2984531d, 0xf471a1f3, + 0xb7da96e3, 0x332f1577, 0x7f336b4d, 0xe04dc27d, 0x3b9e07f2, 0x4158578d, 0x50149025, 0x1d157a30, + 0x9a603f3d, 0x5acabfed, 0x3606555b, 0xd29d2dfd, 0x7c13493d, 0xe1fe984c, 0x278b925d, 0x82fa47a5, + 0xe1300bc6, 0x1a8574f6, 0xfe7a913d, 0x7b33118f, 0x474bc7b3, 0xb32714f1, 0xedf190e2, 0xdcf4e779, + 0x1ab56157, 0x633a5954, 0x6bfe4bb9, 0x309ea1a8, 0xdf41c760, 0x0cd4ad76, 0x6641fedd, 0x92800984, + 0xe6e54148, 0x58d446b6, 0x7a605913, 0xc456fec9, 0x7e75dea8, 0x2f529761, 0xb6b41cb3, 0x99f9b6ba, + 0x166e4f7b, 0x8c0734dd, 0xd46f10ca, 0x3d6f6819, 0x1e4da51a, 0x25a958be, 0xaf97d9ab, 0xe034581b, + 0x091c24fd, 0x9114433c, 0xd380081e, 0x51268506, 0xeff1bfdd, 0x30b8e29c, 0xf002dc16, 0xa160cc2b, + 0x494f92c8, 0xffd15adc, 0xfd656160, 0xd8e271f8, 0xd913f67b, 0xb283491a, 0xdbac209c, 0x99573472, + 0x9751177f, 0xec4484e7, 0x09cbf96f, 0x9a45059d, 0x60955858, 0xf0ef3716, 0xf8cba029, 0x7920d750, + 0x7d39f4d3, 0x2b155863, 0x45725da8, 0x0f26d96c, 0x61f3f7b8, 0x784cc747, 0xc2534b35, 0xe10d5564, + 0x1595e5b4, 0xf8a91daf, 0xc42e25b6, 0x7cbd2597, 0x25bde406, 0x464dd23f, 0x4cc3b4bc, 0xdecfce68, + 0x765a4048, 0xe17ff391, 0xb1dd52c9, 0x83399f2b, 0x02ab67ba, 0xae263243, 0x6c44c388, 0xb40e7378, + 0xc371e147, 0xdad45366, 0x4669b707, 0x9d69f357, 0x50c5ef0e, 0x820bd8c0, 0x4b863fae, 0x87d3dce8, + 0x5acd7989, 0xa6cc1c42, 0xf4fedbb3, 0x8c07a241, 0x0652f222, 0x394783da, 0xcb607c57, 0xdcfcf5a5, + 0x796b6714, 0xf2cd8186, 0xabb0d75c, 0x26efb43f, 0x1da1c993, 0xcce8ef58, 0xbf95a316, 0x1f248216, + 0x80c750ac, 0xe4e20b39, 0xf6510f29, 0x5def9c91, 0x9413e4b3, 0xb5ba8dd1, 0x3a4065c2, 0x2051105c, + 0x15a5a92f, 0xa9be9d63, 0x2d3dc391, 0xa5f6628a, 0xa9b3bc5b, 0xf6306704, 0x7d62a666, 0x697bab82, + 0x44893964, 0x74409854, 0xd24b1bf6, 0xd8c50c0f, 0xf451f203, 0xb0c38acd, 0x26ab51d0, 0xc464bbe8, + 0x61d0fcc3, 0x9be7ae92, 0xe6eded38, 0x910861e6, 0x84eb21c4, 0x13a9cf03, 0x0136f263, 0xd39c58bb, + 0x3fbfbd0b, 0x3322209a, 0x2d2e9459, 0xd4edd0ac, 0x18d2b09d, 0x504baf7e, 0x8383a8d3, 0x4c6648db, + 0xd939ab2d, 0xed22f81c, 0xac072ee7, 0xf389884f, 0x81ffad03, 0x04a330b6, 0x6922b617, 0x841d37f4, + 0xa9041a6f, 0x379a038f, 0x9fdc4b43, 0x08e6caf3, 0xc8b916b6, 0xfe03f56b, 0x9f5511f7, 0x9b4d1cb4, + 0x730e774a, 0x7c27b97b, 0x3be31c98, 0x04e572d0, 0xf263e6ca, 0xa70f9597, 0xbbf4fcae, 0x2c5780f2, + 0x85ef3ced, 0x81f1afed, 0xfd7e0e2b, 0xc4fb4608, 0x25312855, 0x27cf269b, 0x6fbc3794, 0xf5e45372, + 0x13814719, 0xd6570923, 0x68ba53a2, 0xdbd42b40, 0x4ae3ff24, 0xd42dd925, 0x56eb7a11, 0xbccdf1de, + 0xfa90a6e6, 0xefce43e6, 0x6cbc930c, 0x655e24b1, 0x9169202c, 0xa082d8f6, 0x36c97f04, 0xf8f10420, + 0xf534ecf8, 0xf21ff0c7, 0x4309a31c, 0x7baa1e15, 0x9be24b9c, 0x11c30275, 0xe265bd2f, 0x49619197, + 0x87f73ab0, 0xfa17a429, 0x50152f3b, 0xf57fa70f, 0xace42b0a, 0xe8ca93c2, 0xf647abf7, 0x0de10625, + 0xa87a7479, 0x890a4369, 0xd30f76a4, 0xa0a80ed6, 0x84663035, 0x6bd70fac, 0x96892e83, 0x85f0e741, + 0xe53ee594, 0x66a25309, 0x66aec272, 0x03620b99, 0xb1beb76c, 0xf443e771, 0x0e9d14da, 0xedef9526, + 0xf80476a3, 0xbf60dff1, 0xfcb1521a, 0x34cb7b36, 0x56ecbddc, 0xc7c11a7b, 0x02f1181c, 0x49f89570, + 0xdfe6ab0f, 0xd562beb8, 0x6abbf6b3, 0x945edf57, 0x5049fb5f, 0x67aa877d, 0xb50f5b7b, 0x205663e8, + 0x4c166275, 0x2d4f4963, 0xe1df9106, 0x288566f8, 0x2497f8a4, 0xbcae4391, 0xe5502081, 0x7f9fa429, + 0x1e6ce2dd, 0xba8e4509, 0x45bebafe, 0x5ee76ab5, 0xf1f3335c, 0xf1644119, 0x77ccdc00, 0xfc300351, + 0x33a32980, 0x3ed3872b, 0x560bf00c, 0x369af71e, 0xea5658dc, 0x191bdd38, 0x515d1c91, 0x5159a235, + 0x02b4c316, 0xebc043f6, 0x3035d4fe, 0xd8e30dec, 0x8ff4da3a, 0x129eb77b, 0x7e8c0fc6, 0x310f6a66, + 0xc53ce752, 0x3ff51cf1, 0x5bcb89ea, 0x7bf8c680, 0x43581afc, 0x8b72a6e4, 0xcea3e492, 0x59ee905d, + 0x90a57387, 0x7e558c3f, 0x01949211, 0xa6ea82d8, 0xa50aa50e, 0xee3d3a48, 0x11b9c708, 0x7271abd8, + 0x5604367f, 0xc5b3ed9f, 0x6a62ebde, 0x171f0dca, 0xdcab9660, 0x3d26a08b, 0x708d1203, 0xd131d32b, + 0x1d186ff6, 0xd5b65c78, 0xaea33406, 0x0a0b3b0c, 0x6602ceed, 0xd2c3d016, 0xc4cfabcd, 0x1b1a1def, + 0xba1ca6e0, 0x07e278e3, 0x024be73e, 0x57faa479, 0x2e9462f7, 0x6a7f493c, 0x508bb58b, 0xada2f74a, + 0xee095bbb, 0xec92378d, 0x8f0d0e87, 0xd96b2a1e, 0x3db2f465, 0xf9da2537, 0xe956ea43, 0x91032a80, + 0x79e0c37c, 0x3ac5e13a, 0x334456d4, 0x47ff9943, 0x2b7eea5b, 0x0e653280, 0x30b76722, 0x6d9e3a7f, + 0x2cde8d16, 0xa36a0dd9, 0x832ee03f, 0xadd96fa4, 0xb96d70e0, 0xdd0dc43c, 0x758b9921, 0x2e5c0565, + 0xe0851a45, 0x54f1d49a, 0x7caf71c6, 0xfab5f6ef, 0x643fb001, 0x48d5c8fb, 0xecd8a9f6, 0x960ed4c3, + 0x7f464246, 0x3070ea56, 0x0ffd31de, 0x28e7f3b2, 0xd8a1bded, 0xf64986b3, 0xc32a3b51, 0x54369336, + 0x864a90dd, 0x586ad235, 0xa53d6daf, 0xc888385a, 0xaa434298, 0x1fe6cf0a, 0x6ce60292, 0x8abb93ff, + 0x836765ad, 0x44bdcb69, 0x9ae170b3, 0x4e6c9812, 0x981e9346, 0x85e05db0, 0xb7c2ad8d, 0xa83e6500, + 0xf410d925, 0xe8946984, 0x61213fdd, 0x409e90b8, 0x78126aab, 0xb650494c, 0x8ba3aa9e, 0x36f0bce5, + 0x92c3494a, 0xbf7b6ff7, 0xe3353ecb, 0x0b422286, 0x5f2d71fb, 0xd89cdcb8, 0x70a73acb, 0x4fe4a071, + 0xb9c6b62a, 0x86218997, 0x82b6e0e0, 0x8e1b267a, 0x73af79b7, 0xadb85a94, 0x6e40fd6d, 0x0bbb8869, + 0x560fcdda, 0x116d4098, 0xbba9de15, 0x2b42f9aa, 0xb634cbc4, 0x62b3b32d, 0x2930e1f7, 0x6c3d88d9, + 0x0a3bc5f2, 0x0a9762ab, 0x6fe11174, 0xe427b707, 0xf4750c9c, 0x051f6d64, 0xde4bc7d1, 0x67b40277, + 0xc1ccf5ff, 0xd2efba52, 0x1588bdab, 0x91d52db2, 0x72f2b230, 0x5d88b8ce, 0xd1eae235, 0x190db811, + 0x7f317635, 0x5a243e59, 0xb86192d1, 0xf8c2a08f, 0x9605831a, 0xfb2fa2cc, 0xc777ac25, 0x531d6395, + 0x715082f4, 0xa03638a2, 0x8271856c, 0x44c32371, 0xdae4dcdb, 0x99f41ea0, 0x360c6025, 0x0f38c700, + 0x7b43306c, 0xd8c61f3f, 0x60070c4f, 0x7408315d, 0xafa7550c, 0x19bb648d, 0xf0fd059f, 0x8cb45d01, + 0x95649b6c, 0xfae7215e, 0xfc52ba46, 0x1c0bf9a4, 0xc8bba498, 0xbc91bc5a, 0x74344d09, 0x68c36be0, + 0x951d426c, 0xccfe4f2d, 0x74ffdabd, 0xbce7194a, 0xe03c17c4, 0x5005428d, 0x8b848aa0, 0x3bd68e47, + 0xa31b6a67, 0x52785edf, 0xec8c2c4c, 0x640b965f, 0x719bf44a, 0x4db6bba8, 0xe058a878, 0xdf98460a, + 0x0b1d7006, 0x2143603e, 0xba138ec0, 0x4c96b654, 0xb4f95f59, 0xa42977b1, 0x90df68ec, 0x02a96acb, + 0xeb2dbfb5, 0x92ad5081, 0xcb186311, 0xb8933cc9, 0x35a10f32, 0xc3f273d2, 0xe7cd081a, 0x0c1a7192, + 0x4669f242, 0x65ea253b, 0x4990efa6, 0xfa5bf141, 0x9d12f290, 0xa4c4fd35, 0x543e718e, 0xdeed0188, + 0x939821c4, 0x826e2048, 0x2b46a304, 0xe7eec3d4, 0xf321b4e9, 0x8059f769, 0x60f63dc9, 0x6d4b3162, + 0x06bc3e02, 0xc3513e53, 0x1540ff9b, 0xfb464820, 0x49d0c1d9, 0xc5b6e4d7, 0x77734072, 0x18f5a5bd, + 0x069483d9, 0xada8badb, 0xd9191162, 0xa07e1f85, 0xcd2449a2, 0x392d9723, 0x9446dc28, 0x257c41a0, + 0x5a7bcbe8, 0x0e071d4c, 0x888e30e0, 0xaa594e83, 0xc76b00ac, 0x735785d5, 0x2a469241, 0xb033d4ba, + 0x4034b9f1, 0x286fc65a, 0x62803026, 0x898b7ab1, 0x7b38789a, 0x097bd2d8, 0x29dce420, 0xb870e13d, + 0xcb714e49, 0x3d69b296, 0x728a3f20, 0x644f4eb1, 0xd560d9da, 0x189b2195, 0xbf65c843, 0xadef2b9b, + 0x06e07798, 0x5a5f9660, 0x1b06ebb2, 0x78b0299a, 0x500bd0d9, 0x2faa2af4, 0x0b5ede81, 0x25c43b15, + 0x770f7a47, 0xa2a51c69, 0xfb303190, 0x134eb895, 0xbef774e9, 0xf939b7bc, 0x8a9b5e54, 0x959d087e, + 0xe0403725, 0xb312991d, 0xfb74d4ab, 0xc413dfd3, 0x60c6296f, 0x3310f6aa, 0x35da6519, 0x4232dc4b, + 0x83e42c4c, 0x2c048a84, 0x8ed25641, 0x299fdac6, 0xf6fc11db, 0x6a4511d9, 0x5dd1aaac, 0xf644846d, + 0xebcb07e4, 0x2c70f6d6, 0x77d98871, 0xae332a65, 0xb0412cf6, 0x357e85e5, 0x36b48d34, 0x14c32e1d, + 0x060a7216, 0xd577d5cf, 0x54739aed, 0x46f91ed2, 0x099d8fad, 0xc609264f, 0xcc6c742c, 0x8e8cfc34, + 0xf72cd35e, 0xf298cb87, 0x3bd4ccb2, 0x6e6d5e26, 0xe1586311, 0xee781bd9, 0xe69e75ae, 0x2befc0bc, + 0x0483b86f, 0x0dea2de4, 0xe51a68e6, 0x7730e919, 0xf32f72fe, 0xebf6e908, 0xccc847ad, 0x64823d1c, + 0x90c949a6, 0xa2dc0db0, 0x9183037b, 0x190d71f0, 0x195eaf0c, 0xf6e756e3, 0xd3fb15d8, 0xb06f79bf, + 0xae6ba3bf, 0xa6f121ee, 0xe9deea0a, 0x736fd6ba, 0xf5ab95e8, 0x035a3246, 0x47c5e140, 0x115b745e, + 0xa6d8a609, 0xe00f387a, 0x0ed40487, 0xf82b7813, 0x9967b60a, 0x3527d9fc, 0x9bf3a34f, 0x59254a3a, + 0xa7410108, 0x7187ee6d, 0xe5d95c84, 0x7eee65da, 0xbd13f6e2, 0x9af5e7cb, 0xe8b74cc9, 0x05f1f636, + 0x9914d467, 0xea00e473, 0x72cb2a99, 0x04eb3b13, 0xbdd3c1d6, 0xae159fbf, 0xe56a3bb9, 0xa83091dd, + 0x96baf4b9, 0x3dfd79d2, 0x23398db0, 0xd498d70a, 0x5c8eb97f, 0x1d88a2fc, 0xf1b1c4d6, 0x9fe03a41, + 0xa3812084, 0xfd90dcc5, 0x888b2ea2, 0x990422ab, 0x282cc1e4, 0xfe99ae28, 0x4e062658, 0x49a0846f, + 0x5ea73458, 0xf9b2ad36, 0xf00a4f86, 0x12fd4d15, 0x0e36ad3d, 0x539b1422, 0x76d7c8ab, 0xeba4c5e4, + 0xc05205b4, 0x7d951582, 0x83d5aa28, 0xae28c005, 0xa93e6237, 0x66abfbea, 0x4ad713c7, 0xfdca7b7c, + 0xe0c0ac01, 0xf4bd32f9, 0xaa3c4b3a, 0xe9afd0c8, 0x842519db, 0x97df0244, 0x489c6e8e, 0x016d84a7, + 0x91ec6b65, 0x62f512ba, 0x97dd2c4f, 0x8aeedea5, 0x21e1d2b1, 0x7807b931, 0x77bc4d25, 0x7dd6d1e4, + 0x76c397fc, 0x1fc35503, 0x5dfe08c2, 0xfdfd5096, 0xddb7837b, 0xfbb40616, 0x08be1780, 0x386e7b3d, + 0xcd0bd7cd, 0x03af4410, 0xf0659f7d, 0xe6416c3e, 0xe392f7a8, 0xdba26e9b, 0x2c703502, 0x5262a06d, + 0x263eb856, 0xad1e4dfd, 0x7393c5bb, 0xc142d997, 0x54a72ecd, 0x214e34dd, 0x1253eaaa, 0x7978ec32, + 0xffc4c0a5, 0x630ce21b, 0xb213f9c7, 0x938f6fe0, 0x43e6782a, 0xde6a92fd, 0x61cecfdb, 0x2b45accd, + 0xdbee9525, 0x75cc99b2, 0x9911350c, 0x9bb8f3ef, 0x9c58f2bd, 0x4ac0eaae, 0x863d9f7c, 0xf530c3a9, + 0x480a494c, 0xd5177460, 0x1e92e10c, 0xcf140eaa, 0x3642a475, 0xd6acf27f, 0x7e24ce7a, 0x10665556, + 0xb6ba5994, 0x2b98cb6e, 0x0aee8d0f, 0x8b215e40, 0x490a51cf, 0x41990381, 0xd0a0e3bb, 0x4056b8f6, + 0xf6ea99ee, 0xe8169bf1, 0xa48556fe, 0x4e50e707, 0xc87884a4, 0x57e47232, 0x02062973, 0x06cb32a1, + 0x3822e6b9, 0xdad24782, 0xe5d29ac5, 0xfe97012b, 0x962a4cf4, 0x99279da1, 0x3806590c, 0xbe70338b, + 0x087612c7, 0x0ffd4df3, 0xdf156637, 0xfcb52504, 0x77216919, 0x125824c0, 0x26aa2b93, 0x81f0a1a4, + 0x14fd40ad, 0xbdeccc1e, 0x7ec50c5c, 0x2048ec1e, 0xc1be0757, 0xc7547570, 0x471e6246, 0x6c9f584b, + 0x568b64cd, 0x3a192a5f, 0xa7ed673d, 0x01f2c90e, 0x89f7f0dc, 0x051d120b, 0x8a6359fe, 0x66b7a718, + 0x2ecbfd3a, 0x9b1c62ca, 0x95364e24, 0x0728d354, 0x33d6895f, 0x0dadf33d, 0x01f5675f, 0x13a49749, + 0xab91754e, 0x0d16cace, 0xb0ba6c99, 0x04e3be95, 0xe4c532a0, 0x1553206f, 0x75d9435c, 0xf434ef5d, + 0x3feaf886, 0x05605e24, 0x941b9f1f, 0x9fd00cc2, 0x2f2ba530, 0x6391f367, 0x5fbcdd04, 0xaaae1904, + 0xc00c3371, 0x618cd41f, 0xc48a65f6, 0x6f276f68, 0xc8ae3302, 0xa92961b3, 0xe30c1858, 0x29bf056a, + 0x52b85aca, 0x34f18feb, 0x1f9eae8b, 0x85da6b0d, 0x03f8d425, 0x51381307, 0x59a55fe0, 0xd5cd1c2b, + 0xa7768e04, 0x47f87975, 0xe83e6abd, 0xce436b2e, 0xa3337262, 0x429f3e68, 0x35a90753, 0x562b7d03, + 0x8bb34fe2, 0x02f69984, 0x546bfb2b, 0x44bd3b79, 0xb0e5c757, 0x49698206, 0x3dc2f9b0, 0x43f5cd7b, + 0xb55921a1, 0x9e003140, 0xe2eb03ce, 0xf4baff0d, 0x52d3876c, 0x527dee7e, 0x9b4ce56f, 0xe32e7550, + 0x355c69c7, 0xb3915534, 0x8fe69682, 0x0ab83fbe, 0x6c2fba78, 0xb5b1dbc9, 0xa3976fec, 0xcfb95b81, + 0xdd65b981, 0xf2e873cb, 0x60cd36c8, 0x51cedce8, 0xb51a3677, 0xd9002df2, 0x2b2a2afa, 0x7bd63efb, + 0xe50ba987, 0x9ec2476f, 0x5014c18e, 0x8b797ce4, 0x9f06416a, 0xc1ecc2e2, 0xeaeb7675, 0x0ad0fdef, + 0x90ba2cc0, 0xd2d8999c, 0x182682d9, 0x5633e15e, 0x6b0d6184, 0xf45896da, 0x7305563a, 0xa73c2910, + 0x3f733236, 0x86a233aa, 0x1969962f, 0x982562d4, 0x8aee6a82, 0x95f302d5, 0x90f3c342, 0xc9808284, + 0x26b6a487, 0x221faaaa, 0x101deeb6, 0xa60e6d96, 0x98986206, 0x47e380c5, 0xe93eafa8, 0xe4094adb, + 0x7062d413, 0x6839054a, 0xcfc183da, 0xb28ee07a, 0x32dd4dd0, 0x85b3d833, 0xe028e154, 0xc3e7c85c, + 0x2f3b5e64, 0x74e15576, 0x8abca608, 0x6f22304a, 0x226b4a5b, 0xa26afb5d, 0x3d7768f6, 0x0190ffb7, + 0x0af27de3, 0xfca48b70, 0x5ee9d72d, 0xefa65524, 0x1aba1a22, 0x247ef1f4, 0x6289bbff, 0xccf526f0, + 0xd6b6ca5b, 0x4a94b450, 0x82015d7a, 0x1e770a03, 0xb8450775, 0xcfc3f9fd, 0xd11b9f4e, 0x16e960db, + 0x93b1f31f, 0x78965143, 0xc0a923c4, 0x7f5b51fa, 0xa8720762, 0xfb5a7528, 0x73a7ac8a, 0x83be4fca, + 0x05a7ce24, 0x97d068ea, 0x91dfe998, 0xb7494ffa, 0x7f7ad1e4, 0x332aabe7, 0x7b3d31c2, 0x1bf529d3, + 0xa993dc70, 0x9d1ca0ab, 0x5918bc16, 0x5535b317, 0x58fb2bd3, 0xdb9d1e02, 0x96e501e9, 0x7d7edef8, + 0x0ded0581, 0xd0e55678, 0xe2449f16, 0x088f1580, 0x385cd639, 0x2445b241, 0x59f7e6b0, 0x24f2d300, + 0xc6776739, 0xdd1ea001, 0xda8f2d78, 0x3eee5007, 0x94062bbf, 0x18beb43b, 0x39a9c57f, 0x7f399d7a, + 0xfe2ef2b1, 0x894baaab, 0xde13ced6, 0x3a53fd45, 0xfc463831, 0x5e359880, 0x0d7cea67, 0x7804eec9, + 0x8abdae15, 0x5e177641, 0x1bbadd27, 0x71e70375, 0xa1198a88, 0x7a4a1496, 0xe5cd7e73, 0x57a327bc, + 0xe26b3b2b, 0xca005668, 0x02e3f96b, 0x6e3fc8f3, 0xf1090215, 0xbc59eaee, 0x1f0e3be0, 0x40f36760, + 0x97385fcf, 0x4322bd02, 0x746d08cb, 0xc7dc35bc, 0xfab3e956, 0xc0812a50, 0x4993c8ca, 0xc294af94, + 0xcfe3e559, 0xbc41be70, 0xaa32464e, 0x3f56bb1a, 0x6907e75d, 0xd9a23ff2, 0x602b1dbf, 0xbf6eeb54, + 0xf45ee3ad, 0x920fe975, 0x53494960, 0x806324cf, 0x629c1bc3, 0xe5aff716, 0x88ad2c90, 0x2896cee4, + 0x3655c26f, 0xfe648165, 0x962bd1a2, 0x566f2adf, 0x099deefb, 0x077fb0f0, 0x1c3376ce, 0xf63259fa, + 0x350fa7a3, 0x02b2cc08, 0x31c8fbe4, 0x2fe50ed5, 0xc785af9d, 0x7324c7e6, 0x7b21b51c, 0x5299dfd0, + 0x7b751bfc, 0xde98381d, 0x4999541c, 0x10412baa, 0x66c9706c, 0x6705b299, 0x2f4cc4bf, 0xda822d2f, + 0xb7a2b5b3, 0xb6fa457e, 0x79f330c4, 0x4555633d, 0xd1f7e091, 0xf0bb4962, 0xc6805faf, 0x7d50e2f2, + 0xc57b6d58, 0x80c1e34b, 0xe5b10d6f, 0xab086f04, 0x041b1d00, 0xc88690bf, 0x91d25f6e, 0xe571ed44, + 0x3cdc6d21, 0x5123c0ca, 0x960382d7, 0x51a12cb8, 0xacdf46a8, 0xc4f17133, 0x1606d841, 0x9c9783c2, + 0xc5bded29, 0x7f13a485, 0x2b2459b6, 0x9eea7b20, 0x16bc3c4c, 0x7efc4e74, 0xad312d6a, 0x368a5571, + 0x1447f87e, 0x23eb8400, 0x237954df, 0x90d30287, 0xf5cd5524, 0xefa923b8, 0x9a334155, 0x2956eaf3, + 0x3089e811, 0x361d2713, 0x2e103075, 0xa86f14fa, 0x1223329b, 0x9078d6fa, 0xd0803eb4, 0x78563e2b, + 0x007dbbc1, 0xbeaa01a3, 0x773ef861, 0x6b6039ab, 0xedc7145f, 0xe93812fc, 0xde790771, 0x0efb5a6a, + 0xf75e1e0b, 0x844b0424, 0x229fb8af, 0xb1d78a52, 0xc6e716b1, 0x0c214bf4, 0xe457576f, 0x4dcbd277, + 0x5e75b509, 0x7f52fae5, 0x498fb3ef, 0xd2801a19, 0x18bf2a6a, 0x9680a563, 0x4f8535e2, 0xd7a0365b, + 0xacee199a, 0x8e7636a6, 0xb24552ec, 0x7137a6e8, 0x419f43a8, 0xc0934195, 0xbfda4345, 0x256a2a9e, + 0x7cd514b0, 0x65998b2e, 0xe5381e9f, 0x26d6dd9a, 0x5cd2e13f, 0x90ab9a7f, 0xf5f0b610, 0x23396f69, + 0xf90fb5c7, 0x74395259, 0xf0e08b02, 0x65b6e1ea, 0x6eb36083, 0xbc465e08, 0x7ac1b4fc, 0x38df26eb, + 0x74adc42d, 0x9dd6e157, 0xcedade7c, 0xa78e0a78, 0xd34982b6, 0xe51e89fc, 0xd09d61b6, 0x9a396f46, + 0x535c88c9, 0x4e72bc86, 0xcdf6823c, 0xfe66cfa9, 0x2b1d95a5, 0xc29f995c, 0x131db19e, 0x7a6973d3, + 0x7e53389a, 0x7217af0e, 0x139e2c14, 0xbc3e4fcc, 0xb531b614, 0x7c237d6d, 0x8c542baa, 0x5885bb82, + 0x05477276, 0x755ceec1, 0x56488973, 0xa6e121c3, 0x41df6a9d, 0x2f6e22ad, 0xf175f1b8, 0xf0059ca2, + 0x4ec50cf5, 0x65254f36, 0xcf4065a7, 0x9591fb77, 0x21d1ba67, 0x3db71ffd, 0x28b51218, 0xda78cc74, + 0x561a3a78, 0xd5dcf61f, 0x6421cb5d, 0x56270279, 0x59425e9e, 0x351c542f, 0xd59e5bd7, 0x5f3cba9c, + 0xfca89376, 0xfc11b735, 0xe6678cbb, 0xbe6b9bc0, 0xa0424efc, 0x94ad90ae, 0x173b0837, 0xc4fa078b, + 0x066ccdf0, 0xcd5761f3, 0xdd4f4993, 0x94ac5ba1, 0x413de172, 0x5f71137a, 0x7c190b5d, 0x8ffbc9dd, + 0xfd958770, 0xb0748520, 0xf9e21718, 0xba027189, 0xe95166cb, 0x34ea890d, 0x9b0d7b40, 0x448a4796, + 0x8c4b3028, 0x510d58ce, 0xca4e276b, 0x5dada6dc, 0x7a7aa43f, 0x2ff56acd, 0x4621356a, 0x229bdbb6, + 0x365b0cd7, 0x33a6db52, 0xf497b716, 0xfcc9f7ce, 0x9b36d703, 0xd882d179, 0xfe81a365, 0x6fafeaeb, + 0x114181bf, 0x2cd97ab3, 0x298561dd, 0x8fbd5691, 0xc369755b, 0x8dd28d3f, 0x5ebfe19f, 0x3794086a, + 0x8a1f34aa, 0x30170464, 0x7d7a202f, 0xf491ff66, 0x041f1419, 0x8965c3d2, 0x8f274976, 0xd11080d5, + 0x7ce35d4a, 0x714933b2, 0xf64ce1df, 0x2cc0d070, 0x67dc1191, 0xf32e5003, 0xe6f7f8a9, 0xc42c6fbe, + 0x52752e67, 0x60b56683, 0x83947f81, 0x3c5fbde9, 0xffe7d5fa, 0xe471004d, 0x6bf4726c, 0x0c03a881, + 0xd1bc018b, 0x62f4e90d, 0x6c5fa0fa, 0x1a9f7144, 0x8af89518, 0x5d6f4216, 0x9d2ae68d, 0x2387002f, + 0xb841c1c9, 0x94e49fb9, 0xee831064, 0x64873420, 0xc7bee12a, 0x3a10b2c1, 0xd8030dd3, 0x324f9208, + 0x4c156638, 0xa0f1173a, 0xb35a4e73, 0xe092f84b, 0x2519efd5, 0x8d7a08ad, 0xb2009d4f, 0x4003cfc1, + 0x48902f17, 0x0f6ece98, 0x79d6fc8f, 0xe522d90a, 0xac5a2777, 0x3054e53b, 0xe6e6cb2a, 0x2cf90579, + 0xb0be580e, 0xf5b7df67, 0x9cbfde92, 0x9e3ea9c6, 0x2204bf7b, 0xf0266a13, 0xcf02c4fa, 0x7be2fe71, + 0xc115ca16, 0xe5f2c380, 0x5e24abed, 0xebbf7a2c, 0xc5d337ea, 0x547c5e32, 0xc5bd9c74, 0x8466b4d9, + 0x2735cb10, 0x9714c33c, 0x8383ecb8, 0x02297e04, 0x5c492d25, 0xa6dd21de, 0x8fec092a, 0x6540e388, + 0xf5deae3a, 0x5549c461, 0xafe630c1, 0xa56205b5, 0xf88e9885, 0xfa209c1e, 0x00da25fd, 0xa6570238, + 0xffa83a80, 0xe8ece49d, 0xccd2f4e8, 0x2fd26bc4, 0x627b366b, 0xcbad4441, 0xdc96aeb7, 0x868b2fb1, + 0x16799ef1, 0x849e2e3d, 0x9154cca7, 0x64abfe2f, 0x27446330, 0xc8b15a7c, 0x5027537b, 0x363e6cf5, + 0xf94ba477, 0xe4851b49, 0xb32e20c1, 0x93e56bff, 0x0da4086e, 0x1ce663d0, 0x9a893f2e, 0xe4bfc832, + 0xc62d3664, 0xa8606882, 0xfb7256f8, 0x876a9d65, 0x03464377, 0xd6f82a18, 0x0ec3b46a, 0xa436ff9c, + 0x3085a236, 0x4d3b315e, 0x3d77acc9, 0x408c6009, 0x1747f1f5, 0xd27cdc88, 0x993cd9bc, 0x8ab70bac, + 0xc31e6dbb, 0xaf06c4b8, 0x828eb637, 0x6b8da532, 0x176d6616, 0x803958d4, 0x4a6f7e6c, 0x8f8caba9, + 0xf2641555, 0x6cc05736, 0x721e9117, 0x3297b3a4, 0x6a33bfc6, 0xcbd825b4, 0x6107e284, 0xa98c5250, + 0x6d805fd7, 0x21eb0029, 0x2d254417, 0xdfdeec6a, 0xd917a1a8, 0xa984df37, 0x605f79a7, 0x951d1285, + 0x40ccf72a, 0x1a516504, 0x14c3fba5, 0xa919be25, 0x06493b6d, 0x1b6fc055, 0x1dd92428, 0x69e87d15, + 0xee747cc1, 0xb3e5aba6, 0xda9356a4, 0x402df0f3, 0x4ee7291a, 0xbf4f6872, 0x3805a8b2, 0x7ef65c38, + 0xc8e0f684, 0xf809a469, 0x079f682a, 0x9066bb93, 0xdd89b17f, 0x3c8142e7, 0x68df5bbf, 0xedb09608, + 0x9b136850, 0x4748ab8f, 0xee4a8f78, 0x979824a9, 0x4319e31f, 0x44e96925, 0xc0ee461a, 0x61a6a223, + 0x831355e8, 0x9fd93f5f, 0x9e845adf, 0x98344552, 0x13d01ede, 0x2bb336b1, 0x1b427bcc, 0x871c3251, + 0x0bec3a29, 0x8c705f22, 0xfbc9ba8d, 0xcc467d2b, 0x10d9a0d4, 0x4a1efb21, 0x1434b935, 0x23edf81f, + 0xa621197b, 0x87a106a9, 0xa810a182, 0x75e3c4a0, 0xf6bb89f9, 0xc34840e1, 0x289404aa, 0xc002356e, + 0x06c61878, 0xf85a7885, 0xfc654bc1, 0x14503466, 0xb6f60e90, 0x647a4cc5, 0xf23d8358, 0x16067eb7, + 0xdd55108d, 0xba9a02d6, 0x5a1d1d46, 0xa842bca8, 0x3597175a, 0xc5d9cec9, 0x8f43def5, 0xf5a54338, + 0xc34e8d72, 0xcbfde342, 0xf320d11d, 0x0a8c3a56, 0x5d9e0134, 0x6e065937, 0x1beb7532, 0xbfe87058, + 0x0785de23, 0x1b774055, 0x75b7b7d9, 0x65dec86f, 0x5092cbde, 0x6ba38e77, 0xdcea3c60, 0xf40ad79a, + 0x0890e9ea, 0xf5c3bdc3, 0x80147d87, 0xb5d65584, 0xd2a5deb7, 0x033ba5da, 0x7465c1ac, 0x0e437be0, + 0xd95f60de, 0x59b2afd9, 0x41acf425, 0x343b405d, 0x7a602e6a, 0x3f45d133, 0x667a72f2, 0x85a0c12f, + 0x5ca30ace, 0xd90514a4, 0x6c42ff05, 0x05754a03, 0x9daf7cbd, 0xcd58fcb4, 0xc9e817a8, 0xb6fd6936, + 0x0bc1f28a, 0x63a85d6f, 0x66710b3b, 0x243c438e, 0x6b8565e4, 0x23640b26, 0x4c4decb3, 0xff73d2a4, + 0xc2e49913, 0xc411413f, 0x17cbfea5, 0x7fbe6d6c, 0xabde4f54, 0x4170e311, 0x990534df, 0x4a898819, + 0x65de5833, 0x6941cb5d, 0xb0d4118f, 0x453bb1a4, 0xb30c8ee4, 0xeac40e9d, 0x26424c22, 0x0d390c84, + 0x7d3baf4b, 0x50888006, 0x33b337ca, 0xadf5ba63, 0x87e308a4, 0xd8287994, 0xf52413f8, 0xfc20e677, + 0x9e8fdf3d, 0x39d7e883, 0x4df9da12, 0x283fcbb4, 0xf2da96c3, 0x6cc84919, 0xa591ddb5, 0xc1306e21, + 0x4d99c686, 0xae2f332d, 0xd2082f42, 0x8cecb059, 0x29a2ec63, 0x796a45fc, 0xbf00ea8f, 0xa4c0dc44, + 0xa03bee86, 0x82244472, 0xe35bf6e6, 0x932e9719, 0x0ebacd51, 0x8cb8459c, 0x81fa515e, 0xa7d643ea, + 0x165b88f3, 0xad6f61fd, 0xf9f6adf5, 0x0dc942e0, 0x746ae685, 0x77c02738, 0xd36e0f94, 0xb3199fe0, + 0xbd1af109, 0x36dceb50, 0x79f6aac9, 0xc0b02f61, 0x6565f57b, 0xc05069f1, 0x6709a30f, 0xcb4bbac4, + 0x981f3917, 0x361980f9, 0x40060c3e, 0x835f0a5f, 0x3dd1006e, 0x78631207, 0xe8075c20, 0x510ee560, + 0xe725b697, 0x43b06095, 0x7bf0c05f, 0xb43fd970, 0x4ea8fe3f, 0x9fb01f64, 0x3f110be0, 0xdf424787, + 0x404f4e0c, 0xe5ccc941, 0x4ba2fb3c, 0x18e4a919, 0x9761055c, 0x8019f618, 0x8714d8c8, 0xc1a55173, + 0xea19e9e9, 0xc091f33a, 0x14a3136e, 0x8d96fe22, 0xa014f7ea, 0x60e2c6c1, 0x867aa14e, 0xdb469a66, + 0xb95158ed, 0x9947b4dd, 0x19def8fd, 0x597e61d2, 0x764c8eec, 0x0e713837, 0x2bdb8520, 0x71a8da58, + 0x27fb5c1e, 0x5325ed34, 0x657f8765, 0x6c50b0cb, 0xe9c9e647, 0xb8f8e1f6, 0xcbbbc9c7, 0xad8de632, + 0x28a33c96, 0x7e963431, 0xdbb4e65a, 0x18b4e1b4, 0x7483b862, 0x0d19825c, 0x1dd34ad1, 0x434ab808, + 0x899cc906, 0x30c5a175, 0xe6724378, 0x2368f84d, 0x0f29a985, 0x8a6c3704, 0x69108f3b, 0x85d67773, + 0x51e8b5bd, 0x9acb4edf, 0xa02efcfc, 0xeb0109d0, 0xeed49aa2, 0x2d4281f5, 0x8dbfdf6e, 0x2d13e7bc, + 0x19937af0, 0xceaceeb0, 0x83328d5a, 0xabba9cff, 0x9b95ab8f, 0xa7f6fe45, 0x3e67429a, 0xdc7bf3ef, + 0xe940b81f, 0xc838a514, 0xd7ab1889, 0xf0fdd867, 0x6c93347a, 0x04148b2a, 0x7488efb0, 0x7c2d69b7, + 0x8581a0e9, 0xf3ae9863, 0xc6950baf, 0x5457e870, 0x60648d3b, 0xeda01994, 0xf3d46117, 0x003809a9, + 0x3d0f048a, 0x600c1a44, 0x1345ce5b, 0x6930264c, 0x5621a0ab, 0x2c4cc351, 0xc5c4fa19, 0xc815b5b3, + 0xa3f1f0b8, 0xa43216de, 0xc9255ea1, 0xeb54bd1b, 0xff065d76, 0x993530aa, 0x5cc37036, 0xe5f70f95, + 0xf383015c, 0x344fbbfc, 0xcf74c167, 0x71d1a7fb, 0xa2ba4d32, 0x7aff9e8d, 0xb5d903dc, 0x1465eec4, + 0xd43b2514, 0x44ad8c97, 0x8f142de8, 0xb7771040, 0xedf57528, 0xe01f8b4d, 0xf33bd44b, 0xa3c03ca9, + 0x824cfa73, 0x88a0efc7, 0xce37b632, 0x39d52753, 0x8aab67c2, 0x20ad8104, 0xc4cde9bc, 0x04f44cec, + 0x6f284f9d, 0x94d6ac8a, 0x33a2670e, 0x70c99963, 0xcc1bddf5, 0x26fb5022, 0x80d7ec76, 0x89e8e45e, + 0x1cc92d28, 0xd618fb88, 0xf1747b35, 0x86cf3e4a, 0xe439dc72, 0xeb3eee00, 0x847c85cf, 0x66722266, + 0x46b89a99, 0x495101ac, 0x4f239ff3, 0x63792ef0, 0xdf29ea49, 0x97169818, 0x87201496, 0xcbf93be7, + 0x302bd09c, 0x498e0935, 0xa3a178d1, 0x3e554cc5, 0x59df74a6, 0x4e88e469, 0x1c6c564d, 0x784df37b, + 0x21827974, 0x002c86ff, 0xd33f4783, 0x1d4e640d, 0xf96f5b9c, 0xe19faae6, 0x6b64d787, 0x5c4cd982, + 0x4863f093, 0x75c7ec71, 0x3d6787ec, 0x2f97c4a9, 0xf43e3bad, 0xe0f1614b, 0xfd4d17ca, 0x2ff45d6d, + 0x064a59c7, 0x415b03d7, 0xc452248f, 0x5b8f28e6, 0x4f794e77, 0xe329643c, 0x549dd70b, 0xc4da5cd1, + 0x5fcaf1b6, 0xfd974bf0, 0xd249d081, 0xc4992648, 0x3663bec0, 0xb31f62db, 0x52791153, 0xeb133c16, + 0x3885b639, 0xbd90c16d, 0x6549e779, 0xbc4f5aaf, 0x49f3a49d, 0x907eba0f, 0x43da91a1, 0x62392bd2, + 0xe8b4a3b0, 0xa2d2298b, 0x9e8965c7, 0xb1b1c581, 0x33865e66, 0x64cf3aad, 0xd39aeb1a, 0x63096f2c, + 0xc881b664, 0xf0f24d78, 0xdf80fe27, 0x4173708c, 0x8d8093e9, 0x3d3dcfea, 0xdc06981b, 0x463a2308, + 0x1b8073a8, 0xb66c834a, 0x0ae4676d, 0x12549773, 0x0676c89f, 0x07f6c99e, 0x9148c797, 0xd7b04ce3, + 0xd7c77b47, 0x417dd507, 0x74e22965, 0xaba6ff61, 0x3760d654, 0xd809427a, 0xc19fbd5f, 0xc48ff96a, + 0x8066f236, 0x608fbfe7, 0x001b83f9, 0xcdfd9e1b, 0x7bed3620, 0x15061b9d, 0xb1d070e7, 0xb634b0d3, + 0xde9b4266, 0xde9fd555, 0x82e0d4b6, 0x7f136809, 0xc93eff1f, 0x0fc015b8, 0x87d6035b, 0x120c12ec, + 0x87614256, 0x87c51048, 0x68ed660c, 0xdfad0c79, 0x16af09f1, 0xbdfb2bc3, 0xd2bd86d0, 0xf5d6665f, + 0x7d32bb9b, 0x5fc88349, 0x2dadb0ec, 0x0f2c5dc7, 0x279ff9e9, 0x94e79568, 0xf50ab887, 0x6c6e7f4f, + 0x5eda3f03, 0xe76b93fb, 0xcea4d910, 0x351b35cf, 0x68aa60be, 0x9bf8e82c, 0x50e631aa, 0xd6a42914, + 0x1e6d5efe, 0xf8cfb3f0, 0xa90a234b, 0x8e765539, 0x0c133182, 0x0b506985, 0x9266fbed, 0xf2505314, + 0x85da1396, 0xa185cea8, 0x073e992b, 0xb0eb96ec, 0x64f0d19f, 0x7faf71e1, 0x1e15f7d0, 0x53b7c862, + 0x6b0a0ef8, 0x34ba298f, 0x9fd6da2d, 0x3a58e7c8, 0x06af1d94, 0x9290298a, 0x9c8210c2, 0x2fb29402, + 0x3cf359cd, 0x39bb499a, 0x4ea47961, 0xd715f365, 0xa17aeee8, 0x7f35df3d, 0xb7a1b3df, 0x331ef181, + 0xc7c229b7, 0x6c89e16a, 0x7fdfb934, 0x0879bb6c, 0x939cbad3, 0x63257338, 0x3d5e65b0, 0x6f09ac89, + 0x1551a8a1, 0x0b47670f, 0x21497715, 0x5f7e82db, 0x2731aa12, 0x1a8648cc, 0x4c225583, 0xee0c7f36, + 0x34c7ee32, 0x250bf50e, 0xec7e6078, 0xbdbc493c, 0x686f198b, 0x445edb74, 0xb6f7b7e1, 0x3f46025e, + 0x4f20ad04, 0xb7fee18e, 0x837eb726, 0x99456c68, 0xa925499d, 0x81058a2d, 0xcc5d702f, 0xbdd403d1, + 0x38f6a4c8, 0x6ac6867c, 0x2f7185b2, 0x4cd6fb52, 0x4935848a, 0x9667c3df, 0x64f68804, 0x2cafa6df, + 0xca51b685, 0x919f9468, 0x541b7ded, 0x8ca26511, 0x029931c1, 0x1d88d396, 0xaf797545, 0xe51a166f, + 0x7278f875, 0xadda124f, 0x40794130, 0xc85cad3b, 0x3eadd759, 0x4c718e02, 0x29f81567, 0x7b9eea04, + 0xf1d6294e, 0x9627b253, 0x3d608fbb, 0xa98acf9d, 0x5ef0e87f, 0xae6e0cce, 0xb92c2d00, 0xc06609e7, + 0xd3c7f599, 0xdfc1bd87, 0x7c63d069, 0x019a27ad, 0x1d0d55bf, 0xf8cb4210, 0x74b4b06a, 0xd36594ba, + 0xb63edf2d, 0xde40dcd0, 0x0b0d3cb0, 0xa6b6263c, 0xd5e0b5a9, 0xc30deab2, 0x0b89d32b, 0xbeffb0c6, + 0xc4af3c4f, 0xa3951ce1, 0xa25259ae, 0x17453b47, 0xf2823fcd, 0xc4a6bdf9, 0xd0ec0686, 0xa937caa3, + 0x9f70cf0b, 0x68becb90, 0x2d096980, 0xe38d582c, 0x9befe770, 0x58434d53, 0x140c0601, 0x737362b0, + 0xe1a1b85e, 0xab3b24a8, 0x52bbe96d, 0x803c0ce4, 0x45c0b09c, 0x8c281c6a, 0xb31debae, 0x969a3cc9, + 0xfaac4c40, 0xad78b670, 0x288a7ebf, 0xb133e2f8, 0x65d7c4d3, 0xbfaa7964, 0x8f0709d6, 0x32ac7859, + 0x9abe9228, 0xb6ced587, 0xbedc5238, 0x11fe8fc6, 0x16ee81ef, 0x23b87946, 0xb3d0c8dc, 0xf07f9b34, + 0x80a7e660, 0xceb26afe, 0x0f099254, 0x5266be85, 0x3230d55a, 0x0cd3fc9d, 0x47e8a7d3, 0x9ca2d515, + 0x8102ffe9, 0x3e453383, 0x9db7e839, 0xb0946cd9, 0x6848c0ee, 0x3a2411ad, 0x4458187e, 0x5ee53d0e, + 0x47904599, 0x39eb0794, 0xfbd6d270, 0x1e1a7132, 0x97fbca27, 0xa4d03860, 0x012c6c37, 0x2100f3d1, + 0x62ed5e0d, 0x5c876504, 0x6927253b, 0x06b6aefd, 0x07876462, 0x57aa0376, 0x59701946, 0x49776b0b, + 0x2aad24e1, 0x5a627352, 0x01512191, 0xe2bf4cfb, 0x66ba74a8, 0x35fc3458, 0xf97b08e5, 0x2a7d1bc1, + 0xa231bce5, 0xa7bddb39, 0x2936030b, 0xda41db8d, 0xc7b78b5e, 0xbb48563f, 0xe5a0fc8f, 0x3d3392d9, + 0x43138596, 0x6a99d5a3, 0x5d44e47f, 0xdca8b606, 0x40c4da84, 0x342b3cbe, 0x0673f798, 0x337e04f4, + 0x95a019bd, 0xcb6bbf97, 0x1a602efd, 0x188ac0a2, 0x61f1f81b, 0x4913f280, 0x2bc5942e, 0x81d7cd98, + 0xc84dca16, 0xe7b31fb9, 0xdc5ae705, 0x07b09cc2, 0x28111030, 0x470e7c84, 0x896134d2, 0x7bcd3860, + 0xa602a552, 0x78c6edf5, 0xa9089fb2, 0xaa713776, 0x66deae38, 0x36d9c6a4, 0x426f3495, 0xae9c4781, + 0xf2d06125, 0xa35ffc6b, 0x71b7e200, 0x77225aca, 0x075fe1ae, 0xd6b8382e, 0xdfe8a35e, 0xb161ad9a, + 0x560b1462, 0x43109705, 0x0c98fe82, 0xe662f513, 0x4f8d5e2d, 0xe37d313b, 0x8cfbb2c3, 0xc874b279, + 0x68bf7a24, 0xfcd0f3f9, 0x5a1db389, 0x497fe2b8, 0x48a6b84e, 0x87440f70, 0x51a5c728, 0xc828b769, + 0x0ca54d6c, 0xa6ab376e, 0xdd1e5ea8, 0x3d8e42f0, 0x702f3523, 0xd4c6e798, 0x1c6db33e, 0x13531b8c, + 0x4eb51673, 0x9c90512f, 0xd01ff995, 0x5dc59e8e, 0xc6928ef3, 0x0b6e79d4, 0x6b6dbbb0, 0xbe2a86ce, + 0x3b142a10, 0xbb8e0cef, 0x7d98678f, 0xb1ef63f4, 0xc6b7650d, 0x310447ad, 0x9f0e46ea, 0xcdb33fbc, + 0x4eecfa4d, 0x6e675256, 0xb35e79fb, 0xd38faa17, 0x7550d40f, 0x1e045f16, 0xcc784a84, 0x12112654, + 0x45f37a92, 0xec2b39f5, 0x2befc709, 0xbf23253c, 0x0113e124, 0xc17bb997, 0x7ce4f19c, 0xff8a365f, + 0xe5bbf039, 0x729b7c3e, 0x2f38daa8, 0x60762f5c, 0xcd4d2162, 0x76673e4c, 0xd9206c4d, 0x35a638c4, + 0x75560881, 0x5b0b2ce4, 0xfaf33c64, 0xbbc216d0, 0x99c47571, 0xd80d0097, 0x980dcd31, 0x2bd98973, + 0x1ef0224f, 0x6d4be851, 0xede4bd9e, 0xd79396e6, 0xd9d1fb0a, 0x76be93aa, 0xaa813126, 0x96d84933, + 0x58491d0b, 0x1426f123, 0x228d00d0, 0xd85bffd1, 0xd34d20b0, 0x5d613992, 0x19c38af5, 0x4358d574, + 0x95ff623c, 0x55dff6bf, 0x9ca08e04, 0x692e1a6b, 0xc81d77fe, 0x9128cd7a, 0x585b1eff, 0x453bf97f, + 0x379ca8d1, 0x0a9ed98d, 0xf1e68f39, 0x1168fedd, 0x3cb70993, 0x4b8d81a1, 0x281f439f, 0x31853ce8, + 0x39853ac6, 0x6b147ebe, 0x2b4785fa, 0x3267a000, 0x7a4f1a77, 0xf2d050b9, 0x2f6f9407, 0x0d33c0f9, + 0x631102c5, 0xea474e95, 0x6ef56d34, 0xea8a3b6e, 0x6302472a, 0x3b522dca, 0x86f0585f, 0xfa849035, + 0xc7481305, 0x03fc008f, 0x746fb5af, 0x93c7fc83, 0x800dcd59, 0x6423b424, 0x5fbe38cd, 0x9fe820c9, + 0xac472457, 0x0f0075e2, 0x44457260, 0x4be6bef2, 0xdd6094b2, 0x28c75b0c, 0x13fb3ce5, 0x1d5646b4, + 0x69ed2d24, 0xc8d0f816, 0x3eec6d40, 0xdeb98b27, 0xce0141d2, 0xf1a78ca2, 0xcf66199e, 0x654e071f, + 0xcd460801, 0xfbca5c05, 0xe716c2a5, 0x66bf7e76, 0x87e06091, 0xd8e5ae2b, 0x4d06aeae, 0x5cd67d30, + 0xa5f53dde, 0x2ef84025, 0x23fbe6d0, 0x1d9abec3, 0x591f0a3b, 0x52697a9d, 0x4500f020, 0x324770d2, + 0x4228dc95, 0xa417fc04, 0x69b52912, 0x3bd0b8fe, 0x2f3beed9, 0xfb58d746, 0x820f89c6, 0x79d16dda, + 0xb16a76a1, 0x71b1df98, 0x5d3d3b92, 0x64b1d34c, 0x58c1aa4d, 0x431e5d8a, 0xed6ff30c, 0x876aff6d, + 0x10ea2063, 0x1ec5611e, 0xb6301c26, 0x5cb4ba36, 0x727baffe, 0x798002d7, 0x06f064f6, 0x239f972f, + 0x6cb018a8, 0xca7ad6d3, 0xa94a3b22, 0x32269459, 0xde9744e6, 0x926117c1, 0x1dcee6d8, 0x25a3f849, + 0x900ac887, 0xa43f30ba, 0x668ac308, 0x72dca90b, 0x2f61d67d, 0x8a157f90, 0x87ab97f2, 0xc49556b6, + 0x39c419db, 0x2f3ddbb0, 0x0b659791, 0xa8f849ae, 0x6cdfa1c9, 0x87bcd610, 0xefafa9a4, 0x626917cf, + 0xda0be81e, 0xd798e055, 0x1d452e09, 0x6e7a4c0c, 0x087756d5, 0x43f9e105, 0xecb9f544, 0xb9f9cb35, + 0x62e4fd52, 0x6d28d1eb, 0xc0b9f7af, 0x58f99e6f, 0xc790f141, 0xfa20191a, 0x0f28fe80, 0x8f4da0d4, + 0x7ebb9a51, 0x936820aa, 0x20d63060, 0x3acba0a9, 0xa1492b4d, 0x8a867cc1, 0xcb432862, 0x38761a0e, + 0x2e17fd0e, 0x0213fb02, 0x1d2f3d88, 0xe43c3761, 0xba2a91ab, 0xfe93629b, 0x923bd49c, 0x2fd69d7a, + 0x1bdc86a5, 0x64d5f597, 0x9d649c18, 0xcae46f1e, 0x876c30e5, 0xc6d39f19, 0x203e6034, 0x78059138, + 0xb33de54f, 0xad8ea767, 0x00f9fe75, 0xf8bda162, 0xa13527d8, 0x9680d17e, 0xb5a0a7b8, 0x9c100dc3, + 0x401e3322, 0x95bf0774, 0x3e41d81a, 0xc323ee1d, 0x1f694f1e, 0x9f133b7c, 0x09d947db, 0xd032c39c, + 0x9a28d983, 0xcab80bf8, 0x062afc6d, 0x1e273db9, 0xee5f90bc, 0x7a43f6cd, 0x90bba1a5, 0x56efa40f, + 0x654bb104, 0xd24d3919, 0x6a5ffed8, 0x38f7438e, 0x39dbc0a3, 0x3316af85, 0x940e7473, 0x8c175d1c, + 0xb98cd23a, 0x541d5f8a, 0x37c2e47a, 0x7428b1cc, 0x55700295, 0x0900b0e9, 0x79f49dda, 0xaf58aaad, + 0xc501015b, 0xd8b3ea56, 0x9da53147, 0x209daa06, 0x8080cf3d, 0xe5b64fb4, 0x48447ae3, 0xaeb6b090, + 0x516cd3f8, 0x718d44c8, 0x803c8a65, 0x8d1aa830, 0x43cede25, 0xbcea8beb, 0xff9afb15, 0xe80ce986, + 0xfb993a08, 0xbe559dd0, 0xbf38768f, 0x56ec3ad7, 0x52522e4a, 0xa89684a2, 0x16c1a5fc, 0x0a4448e3, + 0xdbd61731, 0x08a1949c, 0xc14cdd86, 0x3d85f2ad, 0x08c51fe6, 0x75a7aa15, 0x28b3550d, 0xa5879825, + 0xae68fff2, 0x179bd9e6, 0x97a4704f, 0xa85d5ce8, 0x5cb75d4c, 0xf7cb6be6, 0xb42ae10e, 0x053c325d, + 0xab17afd5, 0xe934c70b, 0x4e25917d, 0x830ee184, 0x9bcd5f19, 0x3a7386c4, 0xee094a50, 0x645d8926, + 0xa2a45f86, 0x8f5786cd, 0x9c17716d, 0x27fcd73c, 0x9dcc71a6, 0x220a6240, 0x868ad092, 0xee56dfd9, + 0x6cd58721, 0xe3b7b57b, 0x4ffa5613, 0x5156cd6f, 0xafd9734d, 0xf8a30aa0, 0xdffe0142, 0x4324cfa9, + 0xefc0da2c, 0x15c7f155, 0xaa5337ff, 0x27e6d43e, 0x670f2971, 0xdeb1c3db, 0xbb5da221, 0xcc148203, + 0xd46d3e96, 0xa5b0bc76, 0xb1e438ba, 0xbafabc4a, 0x9a75a413, 0x4dbbdce9, 0xe05bc252, 0x7945e2c8, + 0xfc1454ce, 0xd1c09edd, 0x2cf5189f, 0x25ed6872, 0x4a255179, 0x9a9c4390, 0x4a58d2b6, 0x6266f3a5, + 0x31d1f414, 0xd6321edb, 0x9d2af637, 0xbc73253c, 0x2a950acb, 0xba8c4ff4, 0xdfda9e3c, 0x6ccfccc0, + 0x51a487ac, 0xc10839b9, 0xf06889b1, 0x47e77a91, 0x0f2a48e5, 0x0d70024e, 0x1e6e2eae, 0x2e577380, + 0xc25cd074, 0x22e4a0f9, 0x30023f99, 0xbb0120da, 0x61bc6699, 0x87413819, 0xbd497377, 0x4be1232a, + 0x5eb6ce64, 0x5ad34b34, 0x79b268cd, 0x9016817f, 0x68b105c1, 0xc72b4cbb, 0x0e38dcfa, 0x4b719f9b, + 0x32f1fe98, 0x12e351a1, 0xb5a73538, 0xc6b60ec9, 0x1ea569a6, 0x71164b11, 0x194a0c4d, 0x9e4132ec, + 0x9f3f2436, 0xea782f81, 0x0b932615, 0x6464fcc8, 0xcaaa43d8, 0x7d768725, 0x0144c126, 0xc99cd376, + 0x7abffa02, 0x6a08b5ff, 0xb2d6543c, 0xc32b6395, 0x8670f0a2, 0x0798511d, 0x10e4face, 0xbd51d08d, + 0x8c32d672, 0xaa735efb, 0xf9c47a49, 0x7b8c9cfd, 0x07242100, 0x56522540, 0x18350ea5, 0x23dd9544, + 0x14af5bfc, 0x0d68be3a, 0x0b3c58d1, 0x67b27a2f, 0xd38717e0, 0x43d088f5, 0x44928ad1, 0x8e25adf3, + 0x589a8643, 0x8151d242, 0xdb57873d, 0x4e6db4f1, 0x48b1bf94, 0x735db1df, 0x0b84dcc4, 0xfbf221a1, + 0xaf1cab99, 0x201ba166, 0x3f7d7c82, 0xfe09f6ad, 0x48a6275e, 0x5c4f8349, 0xfdc5ae47, 0x04ac2209, + 0xacc0bbeb, 0xb30fd727, 0x3ac442eb, 0x41656a7a, 0x1282ae83, 0x104cf88a, 0xae262d47, 0x1e5eaf04, + 0x79c6cec6, 0xfaed7898, 0x0adbc618, 0xfbb60f9b, 0x7a18da7d, 0xf1f98d41, 0x6d6057f6, 0x5f1a1546, + 0x1fbf3fe8, 0x8f4c60a1, 0x0d72df11, 0x341eb3bd, 0x6b35453a, 0x18857f6d, 0x6b240e68, 0x1dae41f0, + 0x33e3287f, 0xda25555a, 0x70b050fd, 0x55ab81a2, 0x151b0c18, 0x60497755, 0xabd44389, 0xe65b5c78, + 0x9263f709, 0x4db6f313, 0xbc98c560, 0xda435d0f, 0x9da9442c, 0xd20b536c, 0xc726a454, 0x9e48e839, + 0xe1ca87f5, 0xa980ad98, 0x833eb12f, 0x7914526b, 0x75fe92ee, 0xc51f7a48, 0x464483b1, 0x39b793f5, + 0x043f39e1, 0x5f4f298c, 0x64bc0801, 0xda6d9863, 0x15d43ea4, 0xb2e221ed, 0xd095399a, 0xa77bfe4c, + 0xa0956a0e, 0x4d2ca6ec, 0x91d6b07c, 0x9a1cd154, 0xd6d2b1c9, 0x4f76a687, 0x2777d7c8, 0x9e190979, + 0xaa3ded80, 0x808e6c54, 0xccebfa11, 0x574b3980, 0xfe6381ad, 0xcd0e158f, 0xc4cd02ef, 0x736430b7, + 0xb9d2ffaa, 0x13b7a654, 0x1846814d, 0x6ab8f18d, 0x88bfabf0, 0xbbb59256, 0x3c1a3668, 0xc86526ac, + 0x1e9d16b2, 0x5df961f6, 0xe583bc4e, 0xc8a25d11, 0x8624e9d5, 0xb398e681, 0x591b9960, 0xedd0d0c5, + 0xf79d8866, 0x00e4a290, 0x7b8c0789, 0x98748ed4, 0x72b18cd1, 0x03365d98, 0xe01510e1, 0x6625992d, + 0x1275705b, 0xb5411409, 0x3f4105f8, 0x9dbf17f3, 0x3f746923, 0x1bf5a36f, 0xde25fc0c, 0x863a122d, + 0xdc029dd9, 0x38de3ae4, 0x811f7398, 0xdf9efd75, 0x2132c489, 0x0aa2a409, 0x29d66f92, 0xbfa5dc3b, + 0xee93f0b2, 0x76bb4604, 0x3a9eca09, 0xe90b412b, 0x34a7a27c, 0x126f20f2, 0x95cc6327, 0x1e6c6638, + 0xcf8685e5, 0x76999039, 0xba6650c9, 0x1566a691, 0x656e6cab, 0x2cf7fff7, 0xc3449a93, 0x2d651d1f, + 0xdedc7540, 0x427c6d84, 0xb5d9c7c1, 0xe8b9a93b, 0xe6c7a0c9, 0x0d7ae2b3, 0xe844ce61, 0x6550f76d, + 0x99dbaa70, 0x9982fe00, 0x296651de, 0xa845aa01, 0xcd452cb7, 0xbafe52b4, 0x3df0053f, 0x986af617, + 0x087d737f, 0xe2c20ecb, 0xaacb6d9c, 0xfff9dab8, 0xcd208fa1, 0xb729af71, 0x7b035d32, 0x7eaf61b2, + 0x0df0eba8, 0xa1fcd23b, 0x728fea50, 0x9218046d, 0xeedae818, 0xdb1ec459, 0xbb6e9934, 0xfa258cc2, + 0x45edb279, 0x7aa1302d, 0xe209294d, 0x7b19aca2, 0x0676f2e2, 0xed011631, 0x9f24f594, 0x21f3db57, + 0x79f44106, 0xe9b66bb1, 0x59de3cb0, 0xfe718737, 0x0ab218c5, 0xefe5f2e2, 0xb04b29bb, 0x0bc6ff59, + 0x6915e7cc, 0x3909a6da, 0xb9d3cc2e, 0x805ec0e3, 0x6f6c8794, 0xdafb131c, 0xb251f02d, 0xfa0d0ce9, + 0x5ef24a34, 0xcc7c2700, 0xe90c5772, 0x6aac8381, 0x6db6fdbf, 0xccf8c51c, 0x9acba022, 0x138372f1, + 0xd2bc23fa, 0x0552a03b, 0xdde7a5f7, 0x5c5136ee, 0xe9d86d95, 0x74d94980, 0xea8dff50, 0x1405805c, + 0xbd5eb8ec, 0xda43d6a3, 0x67058f60, 0x4b05ff51, 0x951aa4d4, 0x1d3e4012, 0x073e9207, 0x55157c24, + 0x65e4e00f, 0x6df9f12f, 0x533f1180, 0x41ee03c6, 0x760fdd3b, 0x8f9b8518, 0xfdf0bf7f, 0x7ade3b14, + 0x6ce6dd90, 0x5d86efdb, 0x24cb6d40, 0x12ab2574, 0xb9ce9dd7, 0x701cb1db, 0x24509a48, 0x0fc35c61, + 0x2815253a, 0x7eb0c4c9, 0xedf233cb, 0x5e5b43e5, 0x8aeba51e, 0x61026497, 0xb79c4250, 0x2f0f2e77, + 0xff6fc2ee, 0xfa0338c9, 0xd8e25e44, 0x3e68f471, 0x484c3a6a, 0xc9392345, 0xa3da6ef2, 0x49eefec8, + 0xcb893059, 0x318f92ef, 0x0d82e3b8, 0x5ad37aec, 0x99f7288a, 0x0df1eac3, 0xbd572b0a, 0x7c7d27d4, + 0x4d0a8b09, 0x347688d9, 0x34c9923b, 0x6b00aa59, 0x5ee9d124, 0xb5354c72, 0x8a18731c, 0xd916d89b, + 0xb0cf1210, 0x80e1ab12, 0xfa6d66e3, 0xbd6002f1, 0x35561aaf, 0xe0ee7908, 0xbd5e88f4, 0xb87465a3, + 0x9039378b, 0x28a28da5, 0x0f573593, 0x81942aa5, 0xc3005bdb, 0x182f9950, 0x52efde6e, 0x8c08e64c, + 0x8b59b0e0, 0xf5e27008, 0x9a3a0175, 0xc92d7083, 0x5dff0f03, 0x9f0ec605, 0x676d92a2, 0x4290127d, + 0x6b9af67f, 0x12a6d900, 0x1cc4f5ea, 0xeaf662c7, 0x4b68871f, 0xfaff4cc6, 0xffbf97ad, 0xb6bb88d4, + 0x0c786e2a, 0xdbbfdc1c, 0xf7a45680, 0xb92da0c1, 0xab3592a4, 0xfd74b9ec, 0x6fe5f4df, 0x7a9c4c11, + 0xdac47d65, 0xc50161e9, 0x205f2a82, 0x9d3b4252, 0x7d566249, 0xbf6449b8, 0x4743ac45, 0x6b1f1bd1, + 0x3807b2ec, 0x8bfe49ba, 0x1466cd2e, 0xfe913d6f, 0x7781c3ea, 0xe0d7d6bc, 0xbec24f0b, 0x8c8b309d, + 0x3e08dfa4, 0x9cb07ea9, 0x647e7306, 0xef917c0c, 0x63527fb3, 0x8776f6bf, 0x016f8fd6, 0x9ff22018, + 0x7e997843, 0x5d04fe9a, 0xfff628d3, 0xc30150ca, 0x2c2ceb54, 0x433c6f04, 0x0f050c94, 0x3b99c415, + 0xa659af7f, 0x7d4a581e, 0x79d8fdc4, 0xcd1bfb1d, 0x748e3d29, 0x608c8eac, 0x4a6c410d, 0x12fbb063, + 0x5053d9b7, 0x3d3f440a, 0xa1e395f6, 0x7cc2ff79, 0x58f096c5, 0xca87c6a1, 0x15be82f1, 0xef522944, + 0x59157e9e, 0x85e98b21, 0xb4c0f095, 0x4aff88f4, 0xecc8adb3, 0x22454570, 0x02ae230f, 0x2efdd0a1, + 0x8cdf9d77, 0x286e1c69, 0x42ce43d0, 0x3dc90bfd, 0x6fabb9ad, 0xbf19f5bc, 0xc7a9937a, 0x67c0452c, + 0xfdeafc04, 0xcc52d694, 0xfbf49685, 0xb6d28f8a, 0xea869076, 0x491d308f, 0xf21290a5, 0x57a75a98, + 0xa3630778, 0xf0c9b8af, 0x2f33cf51, 0x58801ca4, 0xdf2ba7e5, 0xf3ed3bb4, 0xd1278afd, 0x4747ccd3, + 0x7cc9aa4d, 0xc234e08b, 0xe20f0f1b, 0x961493d8, 0xb548d289, 0x3f24157b, 0xd66ba6af, 0x543a818e, + 0xace5c72c, 0x850de551, 0x564c23a8, 0x803618a5, 0x30618801, 0xda663742, 0x7c0a0453, 0xc5b4aec4, + 0x2da8f00c, 0x71e53a34, 0x3734e070, 0x00a86fa7, 0x786ba026, 0xb464fefc, 0x397578b4, 0x71888a2e, + 0x82699846, 0xfbabf038, 0xe86185e7, 0xe3149ae9, 0xa64fbb9d, 0x99bf7541, 0x6bc02b85, 0xafb0d9bb, + 0x3f27ae96, 0x2a5b6ef5, 0x3e94c795, 0xa3550745, 0x9cb35e11, 0xddf4df38, 0x7d1d85e7, 0x71e2fa2e, + 0x01ccad41, 0x9e30e013, 0x442c60d8, 0x021e3322, 0xb80c2ada, 0x8f846884, 0xbd45444a, 0x47f80a09, + 0x34bd1d00, 0x2d95430b, 0xb42f9ba6, 0x8813540c, 0x2f3f9026, 0xd94f06e5, 0xcaf67685, 0xf1b8fd5f, + 0x3a7b8adc, 0x463e7d6e, 0xa3bf79db, 0x2cbd508c, 0x95caf74e, 0x4755bb31, 0x91d4ec5d, 0x4d4a0c14, + 0xda61146e, 0x880cc1eb, 0x398f25c7, 0xc48d7125, 0xd01610fa, 0x11dd9088, 0x62cabc74, 0x42c6f4aa, + 0x4a18e83f, 0xbf08fdc2, 0xb58be09a, 0xbc0bb6d4, 0xff0bc7cf, 0x2a12e4fc, 0x5357dfaf, 0xc71ad110, + 0xd12a8240, 0x56173f91, 0x9d45fd25, 0xe6d04923, 0xd4e157e4, 0xb5c750d7, 0x0e99e5e3, 0x606bad5f, + 0xd76a91f2, 0x8653bd4f, 0x48bfbe02, 0x15ac331d, 0xfa8756df, 0xfe478014, 0x9aa17c91, 0x0a06821b, + 0xe140d17e, 0x51e67009, 0x3f5da18a, 0x1bb821d2, 0x3058554f, 0x31829ece, 0x5c790e25, 0xcc362e86, + 0x424126dd, 0x5e11ec57, 0x92442d88, 0x84fbd7b3, 0xa834da25, 0x20cbe712, 0x961166b2, 0xa7e5925b, + 0xe2874151, 0xa01748c2, 0x346f69ec, 0xb45afa64, 0xe73cde49, 0xe347991d, 0xcf1a2975, 0xc79a2fdb, + 0xc51da9ff, 0x50ae3677, 0xfe5bde04, 0xc35ecc04, 0xdb6446ab, 0x8867f22e, 0x0be6571e, 0xb47f42af, + 0x7bca9131, 0x7c80083f, 0x15157464, 0x6773e729, 0xe54f1d28, 0x21c43123, 0x9859c4c9, 0x7f4236c0, + 0x87b295cd, 0x0658bc70, 0xbe2a212f, 0xf2329754, 0x2d508ccb, 0xc94a6560, 0xc3191f7e, 0x476919dc, + 0xf68d2853, 0x48450e2c, 0x166f6bee, 0x45cdd077, 0xb4e95947, 0xab304ebd, 0x71d60f54, 0xc5a382f1, + 0x360aec27, 0x5236d003, 0xfe1f0ccf, 0xd58351cb, 0xb15e053b, 0x4a18ad26, 0xb912653e, 0xb458731b, + 0x92c84af6, 0x3c1c986e, 0x77f441b8, 0x3b808eab, 0x23d49aef, 0x599cc77e, 0x98e9b774, 0x662ac5a2, + 0x5e61f3f7, 0x092fe17d, 0x80c0d79a, 0x10aea875, 0x91a0ad0d, 0xc14fef7b, 0xb727c11d, 0x2aa82b73, + 0xd0baa0c2, 0xf2d6b34c, 0xdf6db4b1, 0x36903a51, 0x9c563b06, 0x3c1c15fe, 0x63c56226, 0x21cd895f, + 0x3852dcc5, 0xdf681b6d, 0x1f47ad5b, 0xb0994805, 0xf4c65d31, 0xfc64ff02, 0xa2a3f1f1, 0x1db72fee, + 0xbc6dee9b, 0xe2c1bf34, 0x61073c6e, 0x1a9c5f27, 0x94757a19, 0xf59321e8, 0x36cc10d6, 0x5c7ebb55, + 0x9fada725, 0xe816a6bb, 0xa77b7adf, 0xb4e9a10b, 0x8a56d5ef, 0x25d649a0, 0xaca1c6b9, 0xea0edbb1, + 0xdc85de8a, 0x26ef9108, 0x7664078f, 0xa6b8eaaa, 0x5896bbb0, 0xc15a1acc, 0x2a0d6e5e, 0xcfa86fe4, + 0xded27071, 0xf41bee6c, 0x273b56d7, 0xf81fe5ed, 0x4b769449, 0x3f5c4986, 0x73adcbbb, 0xf66cfc0d, + 0xd136979f, 0x177b2605, 0x8abde6c0, 0x95c19a38, 0xc0f33f27, 0xbf837914, 0x49a3daa1, 0xb603df62, + 0x39874858, 0x54869ca8, 0x46195cb8, 0xd076406e, 0xb5e72c3c, 0x1978f556, 0xfa6b7f27, 0xc76e51d8, + 0xa3508924, 0x46fa0179, 0xcf995b94, 0x4465d427, 0xf63b2635, 0x22db25d7, 0x69020b2b, 0x21d89e93, + 0xe03b487f, 0x44ca2893, 0x12c0bd6a, 0x2abac22b, 0xcea05dcf, 0x61b8b2b8, 0xb3c6627d, 0x7b14c64d, + 0xfd84674b, 0xa91636b0, 0x80d039d0, 0xcb0c1c26, 0xef996bff, 0x156f90d0, 0x5e08604f, 0xd4fe57bd, + 0xd4eca02a, 0x222c4a74, 0xee416534, 0xe6629876, 0xb5985280, 0x8adea23f, 0x5364fa7f, 0x7fb95d6c, + 0x7100a42e, 0xebd9933a, 0x4f342d89, 0x2003ab0f, 0x92043a29, 0xff23053f, 0x6fccedc9, 0xbff1962d, + 0x77832eff, 0xec416215, 0x5e061e21, 0x191a2e60, 0x78715085, 0x7dbf2852, 0x002e9bb5, 0x410f2106, + 0xd06ced0c, 0xda07d2e7, 0xd373c438, 0x5bbe03f7, 0x02c695bd, 0x13db8301, 0xad8357bb, 0xf8f1d1f9, + 0x74a08d65, 0x73093c68, 0x55594d52, 0x1bc41a74, 0x755aaba1, 0x5b1287b1, 0xaad8d331, 0x86a8422c, + 0x3481a90a, 0x638f2714, 0x865bf25f, 0x6a8d7339, 0x6e77c1c0, 0xaa0acfac, 0xc9d59c91, 0xe68ba430, + 0xe4803bc2, 0x576c6f4e, 0x0c99b726, 0x1d23714d, 0x88a1323a, 0x52265f23, 0xa0854cc2, 0x19d2d5fe, + 0x1f2837fb, 0x96aef3e4, 0xd259bab2, 0x4a0ff410, 0xef015680, 0x2f2e65ff, 0xf0008e90, 0x7183f1e3, + 0x5d19d24a, 0xae80e36c, 0x7d25b33d, 0x1a89b9bd, 0x44a2e096, 0xecb91e7b, 0x1996b03e, 0x37b0901e, + 0x11c29286, 0x808e31c6, 0xda490d20, 0xab216992, 0x79023242, 0x3cafbb21, 0xb3ecc821, 0x5388fb54, + 0x9c9c49f3, 0x3b2ed6ce, 0x68363faa, 0x8860b0a6, 0xe4d9eb54, 0xf4afac30, 0x8e27c1a3, 0x7661fb48, + 0x66cf0d07, 0xcb21473d, 0xaf3b00c5, 0x7abb41ea, 0x246afaff, 0xf13c7ae6, 0x6539caae, 0x4592fcea, + 0x2f8da00d, 0xf8b8d40e, 0x28c4d9e0, 0x8bf69faa, 0xa06879c0, 0xc1b8017f, 0xcddf9d1d, 0xe39d843d, + 0x8402f006, 0x8ae0d23f, 0x3757281f, 0x920bbc13, 0x1da3e13f, 0x0bbab994, 0xe359dcfa, 0x53ba01e8, + 0xc4b6447b, 0x0a33bf5e, 0x6ff8f591, 0xab8f8822, 0x36063b73, 0xe7762b61, 0x1d9225d7, 0xc2e01cae, + 0x50c2f2b3, 0x88cdb062, 0x1c7414a0, 0x8794d879, 0xd88f02a5, 0x41e2ba0a, 0xa4c1d38f, 0x49991a76, + 0x80872db1, 0xb2d6be86, 0x6cbfe357, 0xd3bf22d3, 0x0f67c79e, 0x1e10d6b8, 0xa47e5ae5, 0xafc9a010, + 0x52f01b0f, 0x357ffe2b, 0x6aaa2ef8, 0x4f14353f, 0xc194d40a, 0x6cf3979b, 0x9d097b81, 0xca80a360, + 0x1505a7ef, 0xf22122ce, 0x7d22ae61, 0xe319779f, 0xb7c6419a, 0x672fec54, 0x82044f08, 0x2e3ff862, + 0xc4b1016c, 0x7b651641, 0x2eb7bccc, 0xfbf15273, 0x64e5bd9e, 0x3cc26491, 0x99c9fb4b, 0x7989632b, + 0xf13d65df, 0xc861cbcf, 0xcf56c6ae, 0x84cb477a, 0xdf3743a4, 0x42688526, 0xd71f5b4c, 0x4c6332d2, + 0x6ebf3182, 0x0221c67d, 0xf8e20589, 0x4527db19, 0xc063e3cb, 0xd5148b29, 0x8ff99084, 0x9b4b12b6, + 0x6e763f05, 0x8fc8b118, 0x592129f2, 0xf22656c7, 0x14e75f9e, 0x4c1c4e26, 0xac469e62, 0xa42905d2, + 0x456ed01b, 0x38729c02, 0xd5aa943a, 0xd8420441, 0x5dbc9276, 0x54c63011, 0x1fe48563, 0x9c1c4bea, + 0x41719664, 0xc7f4e5ea, 0xf567cfa6, 0x696b55ed, 0x5ea63495, 0xd70b71e3, 0xe9d13c46, 0xdb22c8bd, + 0xf3895772, 0x22e0e6f3, 0x67e9ec0e, 0xc6b501b7, 0xb00e659c, 0x53ab3018, 0x40909bbc, 0x5282dad0, + 0x2a97e136, 0xcf97f0d8, 0xa85f4195, 0xe2e78ad6, 0x7c8fb1ba, 0xf11dc6ba, 0x5f4a2417, 0x5225dd19, + 0x0ba91cfb, 0x2ac05a45, 0x8d6a4fe0, 0x05230f29, 0x79e8e34b, 0x52118c43, 0x31e0f288, 0xdc3dda57, + 0xf3b48bd3, 0x8d37c4f8, 0x0a30a956, 0x0efe7755, 0x6ed37e6e, 0x96844181, 0xf370997c, 0xd0851c4e, + 0xf975fb30, 0xdc1126ff, 0x6fb7ab7f, 0x6e3d91b3, 0x291f5057, 0x35749889, 0x59097ae0, 0x3b08faca, + 0xbb3b7178, 0x084cd276, 0xd8cf20f9, 0xda3ecf6c, 0xbd1176cb, 0x67b9d9ff, 0x32088f18, 0x0bf9dfad, + 0xd37a6bc5, 0x88078074, 0x0a6a1e43, 0x18e803b8, 0xb7735382, 0x1b009389, 0xf202f644, 0xaeb1e0e5, + 0xe6492811, 0xe4ec5e16, 0xa8cc1a39, 0xb4ac50bb, 0xa18870cd, 0xbdbadeb7, 0xd3e8ce7f, 0x0399c51e, + 0xe0cba71c, 0xeea2345e, 0x802607c1, 0x65866f73, 0xc16e5a76, 0x8b582148, 0xfef9cf81, 0x3d625958, + 0xa7407f04, 0xdbe11e1a, 0xde6c8177, 0x27b76756, 0xa8095980, 0x6d61d372, 0x357cbd91, 0xf6422c1c, + 0xd02947a8, 0xdef3ec2b, 0xdacd0c98, 0xf70449ce, 0x6617533f, 0xccaf94b9, 0xa675b36f, 0xc3a0fea0, + 0x4b1dfef0, 0x3125f009, 0x12322da8, 0x5456ad17, 0x6793e3c5, 0xfea646b1, 0xe8367d05, 0x89a4dfd0, + 0xebe22360, 0xd6b44ccc, 0xfb6ed10b, 0x6bc93e89, 0xe77b2007, 0x242a4fd5, 0x3cccaa7a, 0x1fcbf438, + 0x8f483ddc, 0xdf0fb23e, 0xd0578047, 0xdb9d4532, 0xee2e079b, 0xb99d886e, 0xfa66f435, 0xe251cbd3, + 0xbe8a7d30, 0x0d2145c8, 0xb681f93a, 0xa2dcabe1, 0x6b2be6fb, 0xf332d979, 0x963ecfdd, 0x91d09d65, + 0xf75db0c6, 0x0a3eb622, 0x6c3dd7d4, 0x234ef0ab, 0x8ce9b753, 0x528bed5b, 0x100bd1bf, 0xeec81ed7, + 0xc2aa78dc, 0xa927aa20, 0x27fd1717, 0x2960ba23, 0x2a5e5e8f, 0x944f11f0, 0xab615655, 0xca9f09f5, + 0x1979728d, 0x81aab0df, 0xbef987dd, 0x6d9e7523, 0x160aac15, 0xa9fb9197, 0x614fbdb7, 0x1b4cd10a, + 0xf67eb3dd, 0x1c5da732, 0xb83b235e, 0xb615f972, 0x73e966b0, 0xb4a270e9, 0xcaf50433, 0x0a295574, + 0xf172a4cc, 0xce4340bf, 0x6dd1ad7b, 0x310f22b0, 0x9d157f9e, 0xff3619ba, 0xf78bd2f7, 0x5f1fa62f, + 0x7254d65a, 0xfd6e4a0b, 0xe6e7c2f9, 0x4696308a, 0x64fa3655, 0x4aeb00e1, 0x800c2c89, 0x9bd4ddca, + 0x3e2dd72b, 0x773e86b3, 0xc9c042a8, 0xb348c2f7, 0x7624488c, 0xb59ed9d9, 0x3c3f1382, 0x8c1b9bde, + 0xcdcd5a5f, 0x53a11051, 0xb56f5cc2, 0x43010c18, 0x12083285, 0xe981db54, 0xf87a3b62, 0x219639e1, + 0x76d51316, 0xbed9f7c2, 0x68cc362f, 0xeeff103e, 0x5d4394a9, 0xe51dc901, 0x0bb50e1d, 0x849ae0ae, + 0xeff57411, 0xc2b14466, 0xcefdb32c, 0x3cfe4ae5, 0xa460913b, 0x62116092, 0xa6f3fca4, 0x7621fe0f, + 0xb99d49e7, 0x102f5153, 0xc27b8e2e, 0xf902684d, 0x7b527661, 0xa58184a3, 0x685f49e2, 0x4e7b94dc, + 0xeb945219, 0xe9b7a7aa, 0xa05335df, 0x0b33ab26, 0xac9229f8, 0xc1038d5e, 0x8d1c23fd, 0x13fbabf7, + 0x708a6655, 0xd2bcd241, 0x68cf0042, 0xfa6b1864, 0xf85fb9cf, 0xf54d99e2, 0xf3874288, 0x68027e3b, + 0x24a1f86f, 0x62ca096f, 0x36fab498, 0xa99e2b94, 0x5ae0efa3, 0x9c6baeb9, 0x251606ee, 0xb6e0c7fc, + 0x3b468a8a, 0xddb9c480, 0x9cdbc3ac, 0x61fc32cd, 0xa6d39c57, 0x57fa88c5, 0xf4afdec0, 0xf21fe3be, + 0xcb05fcaa, 0xe95b5393, 0xac5d4566, 0xb5c7c680, 0x4285ebb8, 0x118b823d, 0x7ba5b928, 0x47b27847, + 0x1c454048, 0x3d40a62d, 0x9787ce40, 0x73f84d4b, 0xa5d5935f, 0x5ae477ea, 0x59ef569e, 0x78093bdf, + 0xd9531588, 0xd5a7bcbc, 0x0fefe82e, 0x84aae768, 0xe04e0b43, 0xfbc6ea52, 0xd166eb03, 0x1744541e, + 0xc9646ffb, 0xc779364b, 0x5a7faf42, 0xc866614e, 0xd9559e08, 0x923114f4, 0x1745fcbb, 0x93b28144, + 0x8303b738, 0xf44775cf, 0xb4cdc216, 0x5cffc30e, 0xbb3b6227, 0x106817dd, 0x2f4ea640, 0xfaabfd6b, + 0x9fbc33eb, 0x0a89e53d, 0x0070a9b7, 0x9236cc17, 0xd50a7fc2, 0x08e14ffd, 0x2742108b, 0x40deff73, + 0xd195d28e, 0xc88fdaf3, 0xb0d93d59, 0x724079fb, 0xee65eb84, 0x03c92d8d, 0xa963fdaf, 0x5db7f0a9, + 0xa8a0a330, 0x7a8c2ead, 0x6e745d6c, 0xac01f15c, 0x8d510eb2, 0xe4313c67, 0xde09b0d2, 0x6e0c7c89, + 0xe84835b6, 0x3f2c2dea, 0x68afe1b1, 0xf32893d6, 0xadbd0e6d, 0x769c734c, 0x6cdf18b3, 0xbdc3c984, + 0xa3ccec71, 0x6940c716, 0xf779aa52, 0x3f40995e, 0x870b29ef, 0xd1614f46, 0x830a0f26, 0xd180ff71, + 0x9a68c81a, 0xff1a4be6, 0x2091cbe8, 0xeb6608b3, 0x3f46ebe9, 0x02eaa843, 0xef1b4215, 0x3f1d9d9d, + 0x25db21fe, 0xd54fc1b9, 0x870b83f3, 0xf835eac0, 0x557b43d2, 0xb4e1fe29, 0xb005f4ca, 0x5cb33765, + 0x35af3377, 0x7157c2d5, 0x2b240388, 0x1750d20b, 0x8c1b6bff, 0xad11dee4, 0xcae30c06, 0x168f76f1, + 0x685c344e, 0xb7ac8a96, 0x061b6513, 0xd4807f28, 0x3398a0dd, 0x544674a6, 0x50f69c68, 0xbb6113af, + 0xec4b9c3b, 0xdae91e07, 0xa808ec2c, 0xe48ffb6f, 0x7fa8e3e9, 0x61711f49, 0xb193b396, 0x1dddd5a9, + 0x9936e1cb, 0xc7ac2851, 0xb7a9da31, 0x236dddc9, 0x616ff004, 0xb1217d6d, 0x4180826c, 0xb326ccc4, + 0xb00d2b78, 0x60561187, 0x9440d095, 0xfb3a96a0, 0x471ccea6, 0x26342b98, 0x14976108, 0xef1ada3f, + 0xb5c72b00, 0x75054441, 0x68b91f20, 0x78897c17, 0xe627e725, 0x7d3620e6, 0x6b807e30, 0xe5fe98b5, + 0xf15afed7, 0x877a8bd0, 0x00be5039, 0xd77fd993, 0x20d079ae, 0x9dc083f0, 0x8d17f4f9, 0x747210a9, + 0xd7ef85f6, 0x9c6c9fc0, 0xb8f63559, 0xeed4e6c8, 0xfb9bf060, 0x2a9a9c09, 0x1705370b, 0xeb77f272, + 0x9e977307, 0x9b84625b, 0xaaa1d81e, 0x4d40aa44, 0x4370c958, 0x9994e179, 0x1c88c7e0, 0x172a309a, + 0x7de2c1b2, 0xcfbb9778, 0x121f7726, 0x9def2b44, 0xe067866d, 0x150bb4eb, 0x0c8d183a, 0x33847ac4, + 0x9d57879f, 0x5d2f8733, 0xaf7d8440, 0xd77e05d1, 0xe6d35a12, 0x87162e93, 0xd8351a72, 0xff5d1be1, + 0x98ca8365, 0x91eacd64, 0x8e8c6551, 0xd9104615, 0xa8d1aa98, 0x00835463, 0x410c5992, 0x9c42332f, + 0x0d352598, 0x42cece35, 0xa68b98d2, 0xb961cb01, 0x7d5e7c0e, 0x4d2c9d31, 0x474a78af, 0x8d93947a, + 0x123bbbce, 0x5d51d9c3, 0xcf65d9f9, 0x53c80e3b, 0xfebd2304, 0x9c8270ee, 0x7df1e9b6, 0x4f5e27c9, + 0x6c3b45d4, 0xd365c24a, 0x6c844bcf, 0xcae2526e, 0x001ec0af, 0x4a4593af, 0xffa7c242, 0x9d7df771, + 0xf992268e, 0xe24a83ca, 0xed1dab55, 0x811fd13e, 0x32fb7374, 0x174502c6, 0x3909b2f2, 0x22968ef3, + 0xfb6d0c4a, 0x74d6a551, 0xd23f79a9, 0x4cce8169, 0x0cb9a1fb, 0x35818de0, 0xc55f3865, 0xb2a49328, + 0x5d65357c, 0x24a80cee, 0x734aa5c7, 0x7c1d610c, 0x3e76be24, 0x3236984e, 0x931abc30, 0xb6eca82f, + 0x6084c2f7, 0xe2ae14a3, 0xec76c93b, 0x939c79a7, 0xaf00d3dd, 0xff8e60c7, 0x7b5a06f6, 0x5098a64a, + 0x003488ff, 0x4e22a546, 0x6a0d45e2, 0x92c32f20, 0xb54085d5, 0x6e9b613b, 0x4e32312b, 0x3e1af1cc, + 0xcf03c2b5, 0x77715b22, 0xac6d7463, 0x874ddd0c, 0x397a61a9, 0x5d1ebd83, 0xbe05e34c, 0x60cdc6a0, + 0x44f98c35, 0x4726230b, 0x83203ad6, 0x4089e51f, 0x7fd93403, 0x080c1e28, 0x05ed2b2a, 0x97cedfec, + 0x67333400, 0x8d359a48, 0x1ddc155a, 0x0519f93a, 0xb9beef1f, 0x1e9d9ff5, 0x7eb01924, 0xa6033c9d, + 0x31106ad9, 0x96d7d1b4, 0xdeacb0b8, 0xc15ebfa3, 0x329c4359, 0x4f749b81, 0x1e4b5937, 0x114a3d28, + 0x5803b93a, 0x5f63680b, 0x8232e436, 0x223c573c, 0x50f0255c, 0x81c014dd, 0x450c1952, 0xde888aac, + 0x89823e90, 0x7e0c18be, 0x7cfc91b7, 0xf7adcab7, 0x4e094502, 0x1a07622d, 0x2c38c817, 0xaa0075f5, + 0x4128f5af, 0x75824607, 0xd098927a, 0x64997148, 0x72e52955, 0x99886784, 0x057ddbaf, 0x0dbe59d0, + 0xd52db16b, 0x2b91d3c7, 0xb549a34c, 0x03d8a62f, 0x0bb5d5de, 0x13cefd5c, 0x1794a045, 0x526844a9, + 0x5fba57c0, 0xd4c0bccb, 0x17ed7d79, 0xbdc185d5, 0xd1f4513e, 0xf775f463, 0x81b2c449, 0x6e37a783, + 0xa7306fbd, 0x233e07c2, 0x862fb978, 0x143394d2, 0x9987d988, 0xfd3a71a6, 0x1c238297, 0xd8d42a96, + 0x9c1d0c53, 0xa521c355, 0xfce7401f, 0x90ddbe44, 0xd5f5a540, 0xb2b8d0fc, 0x5ee8dd25, 0x231745ae, + 0x9470c612, 0x6fbc9687, 0xa69709fd, 0x7af1ef6c, 0xf068c5fd, 0xcafc8e1d, 0x8261a43a, 0xa933498f, + 0xebcac459, 0x715f3e80, 0xb5edb6e9, 0xe63b9157, 0xd893dcc6, 0x29481664, 0x04a3fbbc, 0xeb071156, + 0x5c5fd8cb, 0x226e75c9, 0x981f623d, 0x8a2af82c, 0xc49a56db, 0xdd96cd6b, 0x2a6f339f, 0x9e71b8e3, + 0x7a5098db, 0xc72b765b, 0xa5e30ce8, 0x9f8165df, 0x007fec99, 0xbc8d7287, 0xb53e160c, 0xc5af2fca, + 0x37619ed5, 0x1cdb6ecd, 0x5744c1a9, 0xfac720a5, 0x0325066f, 0xdf0f100e, 0x700b6937, 0xe958f02f, + 0x1709bae5, 0xbe312437, 0xe3b8a6c8, 0xd321276c, 0x64844b7e, 0x038abb8d, 0xb33050c2, 0xd8111b1e, + 0xca5bb9e7, 0x83d76f6d, 0xceefc6d1, 0xdeb01886, 0xe7353202, 0xf5899cb8, 0xf1e1206b, 0x11b0e576, + 0x9be996d5, 0x6084c3cf, 0xec2fc7c2, 0xca9d51e6, 0x6e5cf00e, 0xa9f09a61, 0x1a225dca, 0xa9f6d4ce, + 0xcc72d854, 0x945f2181, 0x6d59615b, 0x640ab0d0, 0xaf94c8da, 0xd6b29d09, 0xf6d17ca8, 0xbd1131e9, + 0xfeaab3d8, 0xb26f104b, 0xc23a5f77, 0x923cf47f, 0xf40a9d1e, 0x67986bcd, 0xde1915af, 0x53a80186, + 0x6b3301e7, 0xd5dc0173, 0x67c9e3f6, 0x9d73f833, 0x2a1dc7e0, 0x831b06a5, 0x36992e79, 0x160aae25, + 0xf22d946a, 0x45ff9dac, 0xf7d115ae, 0x7aa67be5, 0x9a1fc2d9, 0xeb90082a, 0xd98619fa, 0x919ee851, + 0x482343d5, 0x45895f2a, 0x763eec2b, 0xa36658e6, 0x9500167d, 0x860cad96, 0x77cc671e, 0x1dca93e0, + 0xc057bf51, 0x22a3dc9e, 0xa6d04044, 0xe2e332fc, 0x10e1d389, 0x582eeb0a, 0x21622998, 0x30d6a13a, + 0x5f2f9b34, 0xd03aba5a, 0x71b4c0ad, 0xf9b7235b, 0x658fac5d, 0x43e06bfb, 0x10e4df95, 0xccc8c776, + 0xc7f4427f, 0xd93e0bb5, 0xf6836b9d, 0x1c82ce01, 0x0b326570, 0x05bb6da2, 0xcdfcac83, 0x23ea0be5, + 0xec973430, 0x07235b61, 0x5477b1c1, 0xb26a2141, 0x4b0eafe3, 0x7409798a, 0xc0cf89d8, 0x7870a7a0, + 0xdae80dcf, 0xc28fc24f, 0x25b1cc67, 0x45c27a34, 0xdb142fc3, 0x15b15ddc, 0xc02fb581, 0xb6942fc1, + 0xbd278f55, 0x5a99b8e8, 0x6129f8f9, 0x3cf97983, 0xf9b4a579, 0x5c08aa03, 0xce0c520e, 0x8c3a82ad, + 0x94396be9, 0x8831f798, 0xdb75ac19, 0xa869ac02, 0x4dba6b56, 0x8a9b5241, 0xc2285459, 0xc9f15799, + 0x637cd164, 0x0c7f775c, 0x38d4d8fd, 0x80ce258f, 0x7fd9328b, 0xbce5e2cf, 0x263a8f7b, 0x325b1237, + 0x6910fee7, 0x0ab318b8, 0x220af006, 0x90554062, 0x250862ec, 0x69948a9d, 0x255c0c0e, 0xb4ee7567, + 0x53b19ede, 0xb2e7d430, 0x2f7503f0, 0x145c6077, 0x190cd2f0, 0x080c52ef, 0x81265a0b, 0x957805ef, + 0x9cf83181, 0x1a09dd43, 0x914de320, 0x8cebf094, 0x09373dbd, 0xe00f8637, 0x6c0fb3b5, 0xa46577ed, + 0x7cacbc13, 0x24b26d3e, 0xa28761f5, 0x253bad3a, 0x81ab1f32, 0x47c20e21, 0xf0a22b41, 0xe946205d, + 0x1fd622c9, 0x562cd01a, 0x64288388, 0x4fa49eb4, 0x7de9c9fd, 0x6828a00e, 0x192390b8, 0xe5270827, + 0xb4a1b5f5, 0x119c27b7, 0x479d2d41, 0x532de633, 0x85e12dff, 0x93bd83d8, 0x57ae2380, 0xa9208553, + 0xc4801f5c, 0x8d9ac4aa, 0x6674f076, 0x01660efd, 0x46fd32e7, 0xec1c0b12, 0x20161045, 0xd62ae7d0, + 0xbc7b3773, 0x85a149c7, 0x9c501fbb, 0x7a6ca801, 0x2ef62dc6, 0x1391f268, 0x6d4fca9f, 0x5af41aa5, + 0xb22df4a4, 0xf75fb38b, 0x5a65f6d2, 0x0962d4d7, 0xd08840c9, 0xf515fb34, 0xbcb47d32, 0xef6ed74e, + 0x68a6da9d, 0x3b4fc1cc, 0xd97b4ffe, 0xb6df81f2, 0x8c95b641, 0xc633e05d, 0xca2f0b95, 0xa5300229, + 0x583adeda, 0x96d3de3c, 0x3815405e, 0xd71c45ff, 0x78d95fab, 0x7d893ef7, 0x2453f5a1, 0x9dbe20d3, + 0x854174ef, 0x1c70a7ea, 0x3d7678c6, 0x497b59ec, 0xb4c6e9e2, 0xee47fb3a, 0xf8e631af, 0x2abd1c30, + 0x68f444bb, 0xfca6ddaa, 0x15c24589, 0x37ef2338, 0x7e4b9b04, 0x03784df2, 0xbc806117, 0x69451013, + 0x89d641a0, 0xe06e1abb, 0xcf088f9a, 0xcd6c360a, 0x63e60eb2, 0x2de92150, 0x3d687887, 0xe80d208f, + 0x7b6006ce, 0x9f342fa3, 0xe95d3b1d, 0xc1ec4926, 0x9e01a8ae, 0x03230b38, 0x2b0064e1, 0x064151f3, + 0x456ca863, 0xd08018b2, 0xae20980d, 0x570c341b, 0x10c884a5, 0x109de5be, 0x84ccc514, 0x2e2f4f8a, + 0x99d6976f, 0x234d06e9, 0xc4772a5e, 0x0e55da3a, 0xa9515f04, 0x7bc562a0, 0xb5eca923, 0xe8bcdb93, + 0x2776292b, 0x82d27398, 0x37625024, 0xc58a9023, 0x6f5c4e28, 0xad383c39, 0xe19fb6e8, 0xcfd54fea, + 0x7bbac32a, 0x599a0ba6, 0xd7fbb016, 0xbd8ef624, 0x99aa2468, 0x20ba8ec8, 0xc7312ad0, 0xe3b9f04a, + 0xac790202, 0x69ff9ffa, 0xc39b3e88, 0x15a0f4f7, 0x3341a663, 0xa88adb3f, 0xfa6f8d8e, 0xa0b59abc, + 0xaaacfdb4, 0xc83f96f0, 0x205cf4bf, 0x04af7b45, 0x17c86957, 0xdfbdd0a1, 0x2d0ed73c, 0xa7f3f5f1, + 0x973307ed, 0xaf25bf72, 0x2779643a, 0xca525808, 0x5be97715, 0xf2b04032, 0x95869d76, 0xcc5931cb, + 0x52618272, 0xae1b97cb, 0xd5d240ef, 0x27b857e5, 0x0399ce86, 0x1e875c05, 0xd5d7707b, 0x772119e9, + 0x7e72310e, 0x909355a8, 0x7dc60e1d, 0xe4abd5af, 0x24f82058, 0xa0a331a5, 0xb15be953, 0x394ae0e9, + 0x6238432b, 0x47b8a4fa, 0xb4a484a7, 0xe6a741f2, 0x83c8e3c3, 0x142286fa, 0x261864ee, 0xb9b5b66f, + 0x12ac5e7d, 0x1ce7012a, 0x98eafde9, 0x95f85fcf, 0x1d933552, 0x670be3ac, 0xee004778, 0x9278ba32, + 0xdecc62d1, 0xf7754dd9, 0xce9b5ec1, 0x31a02072, 0x7eefcbb8, 0x87f52053, 0xbbc7b86c, 0xef2a9ae6, + 0xaeaac93a, 0x193001c8, 0x8eb8c751, 0xa8ebd7e2, 0x8e75d87c, 0x6ff3ec1b, 0xfd57a055, 0x90f2b896, + 0x15ee0305, 0x3d96dbd6, 0xc1b0dda4, 0xa64f726f, 0x3f8fa2e5, 0x623b6e1d, 0xa989784b, 0x4caa62e1, + 0xfe863215, 0x5c9478a6, 0x7ad8294c, 0xcd390a2a, 0x5e6c3954, 0xc4338653, 0x6d153721, 0x0542e976, + 0xfb9389ed, 0x552252bb, 0xdf49e70d, 0x2cd9ddb2, 0xdabb0ee8, 0x58486b76, 0x2361b2dc, 0xaef80b5e, + 0x4ad2f00d, 0xb09045f4, 0xeaeed5f8, 0xe5181ac0, 0x39dcadd5, 0x55af0d2e, 0x46c3285f, 0xc0e354be, + 0x129a2856, 0x98faf3dc, 0xfba8e7e5, 0x6919bbbe, 0x7204bcaa, 0xb431176f, 0x7fd073ff, 0x4d32a0b4, + 0x5dfed231, 0x442b2937, 0xcaed2659, 0x8ea50016, 0x64655160, 0xcbf35d96, 0x273325de, 0xe6bcb101, + 0x3a511adf, 0xd00db84b, 0xb7034092, 0x78657920, 0x676c4131, 0x303c0048, 0x49dd4559, 0xef3735b4, + 0x50d2f0e8, 0x0e8b1b2d, 0x9d964f24, 0xff905c83, 0xcef6ebca, 0xea0a6068, 0x8655fd73, 0xaa662b04, + 0x6aa8128a, 0xf137f312, 0xe1aa6cef, 0xa7f570cf, 0x46efa719, 0xde327d8e, 0x0155f012, 0x32ca6bab, + 0x4da57e9e, 0x0f416ae0, 0x1081c39d, 0xb19872d5, 0x7e18f9bf, 0x52afe9f8, 0x8905bc7b, 0x0ff0360a, + 0xf7a73a3b, 0xaf167f7f, 0xdba2a34d, 0xa82de9d7, 0xd1e21873, 0xa9b9ecb4, 0xc3573b62, 0xf1c71453, + 0xd550652e, 0x83c6e3e0, 0x3dce549e, 0xfea24e63, 0x3215b6b5, 0x01d138a4, 0xcb6988a2, 0xeffb711e, + 0x1bfd586e, 0x8d2e6adf, 0xbd057201, 0xfa66651f, 0x6cc4d9cb, 0x57252f26, 0xfbf2ca54, 0x6ef839b9, + 0x4bc2ab87, 0x27559267, 0x2d9cca99, 0x78856b76, 0xf588e667, 0xb3cc58b2, 0x44aa045d, 0xc804987f, + 0x3223db32, 0x8bc71e4d, 0x49642f78, 0xd3376a28, 0x4507d25e, 0xbb1adc11, 0x55afdf62, 0xc40fe18b, + 0x0ef9b485, 0x1ee93810, 0x1635af4d, 0xed5d9412, 0xc27cbd9c, 0x99144b83, 0xeb6e7a62, 0xde3ed3f5, + 0xfb1acd64, 0x45e81beb, 0x73aceefc, 0xa58b64f2, 0x6f36550a, 0x9dfa55d5, 0x0af1f2e7, 0x6ab3f64b, + 0xe09a0ec0, 0x79e81717, 0xf62bfc91, 0x2201fc0c, 0x89e3d0cc, 0xdaf2e41f, 0x6b9c6811, 0x5e627eb1, + 0xfdfc7478, 0x9680799a, 0x27a3d47c, 0x148ecc2d, 0x897206db, 0x9a7cd53f, 0xf648a9bb, 0x9b2d504f, + 0x03c727ce, 0xd1d345d1, 0x2f785be4, 0x95412b5d, 0x2c87cb5e, 0x09238153, 0xe7ccb13e, 0x9ca1cffe, + 0x4d305d7e, 0x632c7619, 0x65e31237, 0x83bd935e, 0x356e6f55, 0x51793881, 0xe50a790c, 0xc9363210, + 0x3d2f62bd, 0x5dda7db4, 0x130922a7, 0x878e27ad, 0x6223ce58, 0xc3d1f403, 0x782418b0, 0x60d4d39d, + 0x41dde474, 0x62ead6c9, 0x94048ebb, 0xcd709f88, 0xf7b10845, 0x1583054d, 0x08eef22e, 0xf257e59c, + 0xd472c26f, 0x7f19005a, 0xe9893fcd, 0x8015dbd9, 0x3b47d11b, 0xcb1847aa, 0x91209cff, 0xd7f27c75, + 0xe1391c12, 0x6c774b9c, 0x6abe7744, 0xf9f2085a, 0xc6a502e2, 0x0f905487, 0xba782515, 0x255cf53c, + 0xb4bcb52c, 0x98fd0a9e, 0x7ed581c7, 0x6316ca9c, 0x228ea638, 0xb39d3540, 0x36861488, 0x1e97fb9b, + 0x08269fb5, 0x2cc79dd4, 0x77c494a1, 0xe8553291, 0xb50e1f92, 0x5ba71524, 0xd939f057, 0xf6c81d15, + 0xfd4a6197, 0xf32ff000, 0xa23f5f6a, 0xd24822fb, 0x5b86375d, 0x398f4df7, 0x66219e39, 0x30456b0a, + 0x8964273b, 0xb0bd8b94, 0xa88445c1, 0x6e1f2711, 0x14cd37c5, 0xb84da6f3, 0xde95ddb1, 0xdca60317, + 0xfd5b3bba, 0xb98fc9cb, 0x2e967d2c, 0xd721257a, 0xcd881906, 0x33f5bdc2, 0xd7e62e62, 0x60630c79, + 0xfb5e614f, 0xfc767588, 0x78467b8e, 0x242e5c35, 0xc2eef32d, 0x4dd2ef21, 0xfc028e47, 0x1d44ddf7, + 0x23912699, 0x6d9e6032, 0x2c153506, 0xf9555283, 0xfdf99704, 0x27e8318c, 0xe0b53a49, 0x45554776, + 0x3b1fc8e9, 0x0a6b6576, 0x865f6f8d, 0x97bc876f, 0xb6b5c31f, 0xfa25e05c, 0x40f83c5d, 0xd0937bab, + 0x0a577356, 0x764d8e46, 0x075fd855, 0xe81ad5dc, 0x8c389b6e, 0xef2acc51, 0x4547f3b5, 0xd9e57155, + 0x7358df6b, 0x7cb1289f, 0x8193d1c8, 0x46eb014e, 0xdf58e033, 0x6b4b7c07, 0x6d449af4, 0x2407bb3f, + 0xf03c7c64, 0x3476e9c5, 0x50d49db7, 0xa90f6f43, 0x9309040b, 0xa25d4037, 0xa027ff1d, 0xbd8f5690, + 0xadcb1cb0, 0x7b15d87a, 0x9a9270d2, 0xad41277e, 0xd9459aca, 0x61946c87, 0xc2c48596, 0x698e3098, + 0xeaf42c94, 0xf95232c2, 0x87e95451, 0x0ae86564, 0xc779f28d, 0xfe16a0e7, 0x6896e962, 0x7483731e, + 0x68e45d8d, 0xe3c13524, 0x9b1ac584, 0xabe12009, 0x92c2165e, 0x163d7d61, 0x09a98f3a, 0x9c5a192b, + 0x5bd76c3f, 0x91e0c5b9, 0x243fafc8, 0x6637e492, 0x8e8857c7, 0x9347e5b7, 0x3874b644, 0x9c0733f0, + 0x2854fc11, 0x6fb8a9e2, 0xdff94647, 0x45a59236, 0x1226fc40, 0xd75e7b98, 0x79e1cfc7, 0x68b72b6d, + 0xd53a8907, 0x635c23e8, 0x9bc1e62a, 0x0d2adac7, 0x571a373f, 0xe3e31956, 0x86da9d37, 0x327d5c96, + 0xea550de9, 0x28a8a7f7, 0x5ef3cda5, 0xf6e49cd0, 0x02eda616, 0x01dae12d, 0x532c83f2, 0x13773296, + 0x18ccff0a, 0xdad2ad37, 0x75e8a9eb, 0x3b3f9c32, 0x7a63f816, 0x6a079cb5, 0xa94f2dc8, 0x5083623b, + 0xe0101e4b, 0xef20024a, 0xd88a6337, 0x616ceb86, 0xb3b6e702, 0x0a527e87, 0x2a188e85, 0x253daf81, + 0xb4d8891f, 0xd8d1c797, 0x4d8a9ad4, 0xc889877e, 0x61db3084, 0x156284d6, 0x19294e4e, 0x5ac3486c, + 0x2e60ca78, 0xbe167cc1, 0x7f664be1, 0x8c0c0896, 0xb08b3abf, 0x8893c114, 0x8e6901ba, 0x0123b52c, + 0x1b36c1b7, 0x12cf0392, 0x4780e2c2, 0x83d11b67, 0xf5dda9d5, 0x15c47203, 0x6f47a17c, 0x82d1d440, + 0x697e0fa9, 0x45b7600d, 0xa705f16e, 0xea0b39bd, 0x8f489a4f, 0x347d82dd, 0xd648cb8d, 0x90f59cdd, + 0x25ef7344, 0x546c2108, 0x91e50980, 0x455c311f, 0xb8513109, 0x81d684e3, 0xc2d59459, 0x29e5fcfc, + 0x50a5a6df, 0x3f97f1e5, 0x4f6880fe, 0x5ec909c2, 0x41440279, 0x308fcfac, 0xe11d6903, 0x6bf176d8, + 0x7573e0f9, 0x3dcd26c9, 0x9cd64b31, 0x187248e4, 0x867f2ec4, 0x0bb33336, 0x58403ba5, 0xe366a521, + 0x6dccdc66, 0xd575b46d, 0xc1d7459c, 0x323f20cc, 0x07a6a53a, 0x17dbd451, 0xb47f7e27, 0xabc9a16c, + 0xd47c7e06, 0x1f8962f5, 0x22be1e86, 0x99ece316, 0x20637ec3, 0xebd73992, 0x853871d9, 0xe1bc7607, + 0x1bc4706a, 0x9cd5bf8f, 0xf0d41e95, 0x5a658389, 0x22fa3740, 0x075d742d, 0xe51a7d3a, 0x8fe1acf9, + 0x06c1f465, 0xbbf60999, 0x3e02e124, 0x54da2e52, 0x05ca68e5, 0xde5220b7, 0xacf4ba10, 0x7f28abb9, + 0x9df5cb77, 0x67c231b3, 0x70966847, 0x1661eb90, 0x993da08b, 0x02e8d596, 0x9e2d0c34, 0x04afbecc, + 0xb34ff028, 0x405c1c67, 0xbcc8ee17, 0x3830aa5e, 0xbf5f5d19, 0x87388810, 0x46c25985, 0xf2588ce3, + 0x37fd011a, 0xecb4dde6, 0x8481b303, 0xae4a2c1b, 0x02023026, 0x198f2efa, 0x87b136c0, 0x20477cfc, + 0xa6b89c86, 0xa20fd91b, 0xbffeec51, 0xf7ce4107, 0xaf39908b, 0x045750ca, 0x15c03ac4, 0x869739be, + 0x0d420552, 0xf10411d4, 0x4097b5aa, 0xf38d6607, 0xc6ab3c87, 0xe281892d, 0x9fefbd88, 0xc151f2a8, + 0xd93fb56b, 0x2f6d507e, 0x2631ac9f, 0x2e200ac8, 0xba686655, 0x6bc026a2, 0x1c9f265e, 0x0241f0ac, + 0x9e6650f8, 0x3507943e, 0xe554674f, 0x84574cb0, 0x469f4997, 0xcd2751c1, 0xaa0a0d2e, 0x27983b8c, + 0x88b61196, 0x35d40e0e, 0xbf3cfaec, 0xe656c95a, 0x56483267, 0x1c61ff11, 0xf27919b7, 0xb7e5cc24, + 0xc8c4707c, 0xa00bc6e3, 0x243089cd, 0x20fb895d, 0xf44e3ba6, 0xfd18eb72, 0x3a6bd5e4, 0xde62d39a, + 0x63b6beb7, 0xa494bb28, 0x25a4137d, 0x0e4a9120, 0xd17471b5, 0x7b5f10b8, 0x8372ff4d, 0x079ddcf2, + 0x520884ee, 0xb68349bb, 0x0c4aaea6, 0xd1701731, 0x4b1a4be4, 0xcfb938b6, 0xd0b974f4, 0x9306f5f2, + 0x54b20a5c, 0x98ea21b0, 0xf7379bf6, 0x4fe40e08, 0x374cac90, 0xa86a9e09, 0x32bcf378, 0xfb942601, + 0x583c89ca, 0x7cb9c292, 0x2feaaf67, 0xe6851641, 0xa2031c12, 0xc0171582, 0x9133dd13, 0x5f9e7340, + 0x0d9c819b, 0x92edb4a9, 0x81bf7494, 0xa259b37f, 0x34a3de96, 0xd7b8fa7a, 0xdf4ac486, 0xb7e697e4, + 0x8bc1d256, 0x7af13813, 0xfe02a6b0, 0xa66c7045, 0xe14c93bf, 0xb56c5cc6, 0xa55105ff, 0xde82b6e2, + 0x1e9403a4, 0x0cca846e, 0xff4fe896, 0xb0fc01ff, 0xf06a42e8, 0x9e9390a8, 0x43a1dcb5, 0x5d6eacd7, + 0x2cd80c39, 0x35c2e6b7, 0xc134d5ef, 0x397b8bd0, 0x3c33da2b, 0x6bd5650a, 0x44d92438, 0x56617659, + 0x8977ab1c, 0x963851e3, 0x1902163e, 0x8287ec29, 0x915c3e0c, 0x53b4270b, 0x2a8e579c, 0x2c9c4f56, + 0x41f6efb0, 0x04efb79b, 0x31ab9496, 0x2b00b3e9, 0xe9e870bd, 0xcaf9445a, 0x9fa2a46c, 0x4675ee8c, + 0xa26b9191, 0x65ba6ab5, 0xb96cda02, 0x16e66088, 0x5db699e2, 0x9c928677, 0xff516124, 0xe8bd0579, + 0x9e95024a, 0x65023a72, 0xd0276f2e, 0xba2cb552, 0xcd4b9b5b, 0xc646819d, 0x56733224, 0x975eabcd, + 0xfd85d5e9, 0x22fc7689, 0x5abc3033, 0xc31bf186, 0xcf8a5116, 0x6f43bed0, 0xed1d2f08, 0x81a2efbb, + 0xb8076007, 0xe2a8084d, 0xd7d11fde, 0x9fc545af, 0x7791b54d, 0x73834de9, 0xa2a1a723, 0x51f48320, + 0xa9de30f6, 0x9c4cf40a, 0x4177a4bc, 0xb8d0d13d, 0x1f2b8a56, 0x4927d7b0, 0xd4d88e99, 0x51b6cc2c, + 0xd0267ff1, 0x076c49f1, 0x4edb2fa1, 0x07a7083c, 0xf1fba5bd, 0x37a9ab0d, 0x1be862d3, 0x93492323, + 0x5b059033, 0x89b0a075, 0x70646ceb, 0xf2b8347d, 0xf5ebfb4b, 0x52f55ecb, 0xc79da24b, 0x46b9d138, + 0xe037416c, 0x3e429de1, 0x3182fd89, 0x7e970638, 0x64c8ca48, 0xbad3c6cb, 0x2a30c159, 0xdd6d54e9, + 0x3e35a8d9, 0xd02c9830, 0x254509d9, 0xc6439169, 0x4b4a409c, 0x2ad92928, 0x51abc3da, 0x55f33b1f, + 0xfd85f3a4, 0x2f65daa1, 0x46aca429, 0xed933b48, 0xe1f51022, 0xc55515b1, 0xca743733, 0xe520442b, + 0x7490a043, 0xbb915033, 0xb57288f4, 0x784b5541, 0xb7af32d9, 0x8a970af9, 0x01470bdd, 0x02eafadc, + 0x9ac359c5, 0xe4f43f56, 0x39f7584d, 0x48556062, 0xc8f1fda9, 0x43624d26, 0xeafa7f84, 0x628e099e, + 0x41f38312, 0x1a2c42fe, 0xba647943, 0x7db0718b, 0x9413cd8c, 0x67eefd88, 0x399b9de2, 0xb815a7d0, + 0x508be4fd, 0xa90d77a3, 0xdd410cc5, 0xc708fa5b, 0x69be3def, 0x35fcda5c, 0x86b970c9, 0x86fe8d73, + 0x7c44991c, 0x213474ef, 0xd7db1bbd, 0x6c3c2827, 0xd7747ea8, 0xfc1a971b, 0x2b5c6705, 0xc6327e6c, + 0x06a868c4, 0xfa246945, 0xc86fd34a, 0x8f73a188, 0xb44d27f7, 0xcaf767eb, 0xd54b1ca0, 0x20a182ea, + 0xf6994463, 0x2994667f, 0x736a4a26, 0x23617823, 0x661cb820, 0x9c5a99b8, 0xc97cf008, 0x210d3aee, + 0x5ce38499, 0xdad1e79f, 0x5a39e01d, 0x4013d0d8, 0x2e85d34e, 0xbd2bf4ee, 0x872e7b97, 0x2e94b8fc, + 0x16951dd0, 0x1321bd0f, 0x2554237e, 0x99921214, 0xc37bb0ad, 0xbb048ffe, 0xfaff14aa, 0x26c06ea2, + 0x48c68cfc, 0xa59bd238, 0x6520c657, 0x77d13971, 0x261a59de, 0x34e138c5, 0x98f869d5, 0x743fc9e7, + 0xa15a561d, 0xb220e21c, 0x6220eed0, 0x6201e4da, 0x3b1f0633, 0xaa822d49, 0xd6c88842, 0x11753094, + 0x3b667065, 0xe0ffd07b, 0x1d203b8d, 0x81c22eca, 0x7d71d7bf, 0x0174ee10, 0xe9484811, 0x8235859a, + 0x0f79c49b, 0x5c756c78, 0xc223d05c, 0xe3a5ab34, 0x7b4c8456, 0xe33617ef, 0xc2b65fe1, 0x30a8ad28, + 0xc9979052, 0x6e43c054, 0x489b65de, 0xf79a9019, 0x2ebb0bcb, 0xff791160, 0xa2cc1719, 0x07125790, + 0x32813b7a, 0xedc33929, 0x11286752, 0x6f31550b, 0xdf9a91e1, 0xc8bf8535, 0x05142e0a, 0x867eaa4b, + 0x66f4d95e, 0xd37deac0, 0x60078227, 0x6b28db25, 0x45f18ea8, 0x58ae22f5, 0xf2fc93fd, 0xe9dae8b2, + 0x04f5777d, 0xae8ae45d, 0x4fdbee52, 0xee9b17ff, 0x6b1788d0, 0x55cad71f, 0xb78e3558, 0x07a1d089, + 0xcae2ff21, 0x74154fe4, 0x1a8ababc, 0xd561fc9a, 0x26680e68, 0x461cde4c, 0xf3873df8, 0x049047b2, + 0x580dabb9, 0xb8b5831a, 0xc91e0e02, 0xc03e9001, 0x3cf2c725, 0x41489beb, 0xc8599fbf, 0x7f62009e, + 0x23d17a94, 0x7872abf9, 0x7cc0bfbd, 0x3c174cd7, 0xf2d3d695, 0x50a7ee7e, 0xee6bf808, 0x952aa505, + 0x9144cb18, 0x083caa08, 0xe77d5668, 0xcc25c804, 0xd6dc276f, 0x2fdd66b0, 0x988b4796, 0xc00dae7b, + 0xb795a1e1, 0xfaef8339, 0xe55ab039, 0xfdb80819, 0x914c2175, 0x75f4a485, 0x1844c4b1, 0x784aa5a8, + 0xfb3a229c, 0x90e1303d, 0x3b0a67b8, 0x41576a57, 0x88b5a7af, 0x4ae51c61, 0x527fd65b, 0x3956b014, + 0xb13b8ef4, 0x9c350873, 0x3d9bacc7, 0xa3a24beb, 0x53e7d5b4, 0xd92d3fbc, 0x63791a6e, 0x6d938df4, + 0x512ea92f, 0x832b5d6c, 0x476d907f, 0x3a73c47f, 0x0269766a, 0x4cdd6422, 0xa3d429fd, 0xb9e0f273, + 0x16c78ca0, 0x470a7f6f, 0x43febb21, 0xa547d743, 0x797522db, 0xb7bb6469, 0xc683b6f3, 0x34db1024, + 0x7b304b97, 0x990214ce, 0x8366dfdf, 0xb2eafb1a, 0x81db2cf2, 0xf02d02dd, 0xf5699968, 0x7abee9c6, + 0xa5b0f89d, 0x21db8971, 0x57278e97, 0x0a8eed58, 0xb3831369, 0x3813b443, 0x0678963e, 0x9822403e, + 0xce669cd4, 0xe5e75615, 0x2fdfad4c, 0x94bd83ca, 0x8a3bc4f7, 0xd659be01, 0xea333a07, 0x8c539511, + 0x7ee0f77b, 0xf262c6ed, 0x248f66e4, 0xc4c94d82, 0x626c1782, 0x8d475dae, 0xe32c1f09, 0x1c6acba5, + 0xd4d83a97, 0x623d5e85, 0xf39bc0d0, 0xaccd1c8f, 0xa4818740, 0x84ca8f16, 0xfdab3ab2, 0x887ec484, + 0x4139d361, 0x58f981e3, 0xab6706df, 0x8d1f3054, 0x75980922, 0x1fd6424b, 0x3cd75e22, 0x0c375d94, + 0x3653d289, 0x751a1ae1, 0x301e57bb, 0x0b3a4e09, 0x25e233ed, 0xdc0edb90, 0x2c8fd525, 0xaf0f715c, + 0x13a30b45, 0x0fb6152f, 0x9dc5b43a, 0x373d9ac9, 0xbf77e1ef, 0x5c8edd68, 0xdcd7a9c4, 0xfae75353, + 0x77a4b632, 0x6866436a, 0x3b1587b0, 0xc2054429, 0xe1e03475, 0x2525b9f4, 0xbae43e54, 0xbd6f93fb, + 0x38162cca, 0xb51e0d47, 0x27507a64, 0x3cbfca00, 0x930ec170, 0x046bcbf1, 0x2b24c818, 0x55cd1ce2, + 0x9e67fe2c, 0x8818c3e6, 0xe93c863f, 0x9000125f, 0x9aba2b54, 0x4f640154, 0x9fade5ff, 0x74d9b7e6, + 0xbfd7bc86, 0xd7badee0, 0xa507e333, 0x7ce0c209, 0xe4fe9cdd, 0xd938d7cd, 0xf1a926f8, 0xbb75ba88, + 0xdae9523e, 0xd6ae236b, 0x7158f5aa, 0x5fc82987, 0x8d755878, 0xc1088080, 0xc53708b4, 0x248c4e3a, + 0x39d395d5, 0xfd5351f4, 0xd26dc41f, 0xbdf55b68, 0x51a04414, 0x77f1688a, 0x2022f669, 0xbc50b3ed, + 0x802ed4d8, 0x2d1543aa, 0x9382d0e3, 0xb723f8af, 0x791ad136, 0x9b3cecca, 0x7ea5b209, 0x4f731bb3, + 0x6c35ea53, 0xe2b177ac, 0x44c5e5d1, 0xc13d29dd, 0xd0f38fe2, 0x15af4161, 0x094f0adb, 0xbe2280e2, + 0x0a166f7c, 0x5a95fea1, 0xfb697c9b, 0xec346fe5, 0x108cfc50, 0x88f34411, 0x4c09ff36, 0x4a89be67, + 0xc15235eb, 0x10222322, 0x123c96ac, 0xa8356fd0, 0x1d5553df, 0x09df8cc8, 0x34292c15, 0xcddab030, + 0x9f6e2e49, 0x9eeb5325, 0xddebd7b9, 0x35adda52, 0xf638b4d0, 0x08643e64, 0x687ec2ca, 0xe47c13a8, + 0x4e329fd5, 0xc2654aaa, 0xdd4382aa, 0x0a0a58b8, 0x9c8f4051, 0x128773f6, 0xfbe19618, 0x301742aa, + 0x3c0cc0de, 0xc648081b, 0xb432bcca, 0x91d139de, 0x5c7acf34, 0x1140a173, 0xb04f0fbc, 0x40e4e929, + 0xf840a624, 0xae99f406, 0x1f6c5e26, 0xeb682473, 0x68810627, 0x0ab0cd11, 0x57ad9aae, 0x98cae150, + 0xcd580650, 0x9ff93ef7, 0x54c56bb2, 0xef7a01db, 0xdc0e68f9, 0xe4378c3c, 0xeb4deb20, 0x63345f76, + 0x8a11fac6, 0xf84d057e, 0xe673bf06, 0x039a06f2, 0x19e56f69, 0xc7048847, 0xb48aa444, 0x5fa655a0, + 0x54aa8b28, 0xe84fd9e2, 0x95c481a1, 0x7febc440, 0x783a88d7, 0x0da78ca1, 0x51856b7c, 0x90221aba, + 0xecd9ec7e, 0x3e8b6250, 0xabb50616, 0xf07c396f, 0x757cdee1, 0x89013149, 0xaeefe818, 0xc1df1386, + 0xa48465f8, 0x547db3b9, 0xfa3a1f04, 0x292489ab, 0x1482215c, 0x357e1514, 0x08413f6d, 0x65ce2ce7, + 0xb4c02183, 0x8c3f63d2, 0xde9a066e, 0xf1542acf, 0x46a58f02, 0x85fc2a74, 0xc952ac70, 0x9d4c0e43, + 0x03b0527e, 0xd2256020, 0x065c8393, 0xf951c512, 0x388c65b7, 0x4afe9ffa, 0x294aef58, 0x2ee29945, + 0xccc9294b, 0xffe28380, 0x431c86fd, 0x135d2502, 0xf23c837a, 0x2cfd3bb1, 0x00cea9eb, 0x190af68c, + 0x17807b07, 0x1a572f7b, 0x3e8c96fe, 0xd4d7c575, 0xce80e0d9, 0x0ed9aa90, 0xfcc59d82, 0xe20e539d, + 0x8ea78cab, 0x3fa41052, 0x4b49b069, 0x6bb679de, 0x4118aa1e, 0xb64c4c06, 0x6ccb8aec, 0xab151e47, + 0x7b74e32e, 0xeb6a35dc, 0xd14c8931, 0x3649d01c, 0x6a8357b3, 0xa675f73a, 0xd7e01ac9, 0x0c06f5a7, + 0xd6807f20, 0x445ec271, 0x744d78bd, 0x39a131ff, 0x89c56262, 0x7b91d8b3, 0xe549036c, 0xb97485e4, + 0x44e15505, 0x64c5ce6c, 0x11b84955, 0x62025658, 0x8ce1340c, 0x6831bff4, 0x5364d44e, 0xfa915de7, + 0xcddfbe4e, 0x9b25d529, 0x14d1bc44, 0x1327ef86, 0x82539027, 0xe0bc8603, 0x0be6803e, 0x77539e72, + 0x9af59c01, 0xcd2044ca, 0xc9b30f1b, 0xe997972a, 0x5f6c50f5, 0x0872e625, 0x32ce70f9, 0x798c453d, + 0xd43dddb7, 0x2a3737d6, 0xd749a088, 0x79e2f5fa, 0xd215ddea, 0x39851ac7, 0xd3d34f91, 0xaf9c4cd3, + 0x0904ee1a, 0x35e7f472, 0xb67953bb, 0xbf7b7bc7, 0xfc75f986, 0x1af31c70, 0x1e635ab8, 0x763b087d, + 0xd8ba7d6a, 0x86ba00b6, 0xb2ea3365, 0xb2dca43c, 0xb8ed3fa8, 0xf6181a6d, 0x9b86eae1, 0x8324cdd7, + 0xe42d6d85, 0x33c44331, 0x73f7e89f, 0xc60b0855, 0x8d8cfadd, 0x5e2fbe03, 0x7e90adf5, 0xeecb8264, + 0x2cb39f3a, 0x7f957298, 0xeb9348ba, 0xa5fbf8f5, 0xa71ce3c5, 0xaef5e1d1, 0x46fef18a, 0x062e219b, + 0x778fc0bb, 0x7da01e99, 0xba5531ce, 0xd14f3a59, 0x141ef9be, 0x7ad82f26, 0x21816a1b, 0x132a3198, + 0x569700c0, 0x74d0f4f8, 0xa2c3d0b1, 0x1d83a48d, 0x4430e5b9, 0x9473ec9b, 0x9635c509, 0x2b0b6388, + 0xac6a857d, 0x995de14a, 0x865bb9d4, 0x23cc8c79, 0xa1812419, 0xbf8d5817, 0xf67210f2, 0xd3361ef1, + 0x28247e13, 0x788df73c, 0x121e89fb, 0xbda860c8, 0x8c3328b7, 0xa6dc8630, 0x3f247765, 0x934e8daa, + 0x12ab6df4, 0x22834958, 0x41bafd3e, 0x2e832bd3, 0xbdaf5fef, 0x43e50894, 0xabfdf6fc, 0x9bb23a22, + 0x78e31dd1, 0xaadc4a0e, 0x57143b8f, 0xfd5cc623, 0xbf466703, 0x8112ef43, 0x160732b6, 0x65d12db8, + 0x750d45fc, 0x109cc45f, 0x57af237b, 0xa935c9dd, 0x000d0c81, 0xfc55348d, 0x111607e7, 0xe7373a44, + 0x93d76ba6, 0xeb8b0b95, 0x323add41, 0x1f445744, 0xa48281dd, 0x655c0f38, 0x426d0df7, 0xa310cad7, + 0xdf9e6d89, 0x875e42c1, 0x285b0e56, 0xef8bd630, 0xa28e8280, 0x652a02e3, 0x4e18b67e, 0xa097f116, + 0xecca5c3d, 0xc05c2666, 0xe5764251, 0x7724839e, 0x6e4ca19c, 0x79d93eb2, 0x3876f3da, 0x01de051e, + 0x979e39dc, 0x3900a13d, 0xd5cbc663, 0x2ff862a9, 0x2d2f00d4, 0x4958cc89, 0xf5e86e6d, 0xa92ef525, + 0xc54266b4, 0x532a0652, 0x52861629, 0x79d59e47, 0xfe55c44e, 0x5c95e78d, 0x7d5e1747, 0x60211a34, + 0x06368070, 0xfc911355, 0x0eecc803, 0xf1276cac, 0x98b98a6b, 0x46657e07, 0x6d08872d, 0x8278df60, + 0x3741d5a2, 0x13ac97f5, 0x6afeb364, 0x38f1affb, 0x8398671e, 0x8b6009f0, 0xe9fa8366, 0xf9136c3d, + 0x220f7116, 0x784f3154, 0x79934c30, 0x57a4c2f7, 0xb7ccb016, 0x59ef8e48, 0xb6b9d237, 0xd161cd90, + 0xd25897e7, 0xd28023aa, 0xe081d4fa, 0xa1edcce6, 0x0901a3ad, 0x91990325, 0xd34e3145, 0x82749fb0, + 0x9d9f0a15, 0x969b926d, 0xe6c6230b, 0xb4312d98, 0x2c9019f5, 0x73770500, 0x83b8da35, 0x6acb3028, + 0xd143505b, 0x053c8231, 0x7b2b9671, 0x41f0a3e0, 0x2af443f8, 0x7ec31855, 0x2a97256c, 0x851c91a7, + 0x2cba2718, 0x78c00c3d, 0x2fdd78bd, 0xf1aeb153, 0x18363720, 0x500def11, 0x9a0aa9b6, 0x99a8b6b0, + 0xe252f3ef, 0x074f99e6, 0x53c22fbc, 0x48dcc895, 0x2f79d4c4, 0xb7854195, 0x0851fc06, 0xbbed11b3, + 0x6f9d80eb, 0xf0fe5461, 0x529366d5, 0x897c1bb7, 0x9cdf9a41, 0xcffa83b3, 0x69410263, 0x398497c0, + 0x702913f4, 0x42e22f19, 0x8add8d9c, 0x0c106761, 0x776a3353, 0x4b9aeb75, 0x2bab49e6, 0x8680c254, + 0x093a4a2a, 0xb120cee1, 0x440ee9d0, 0x466030a7, 0x0ff4cf7c, 0xf8d4b14c, 0xb32e8d50, 0x39511071, + 0x1c5e4e2b, 0xf31814d5, 0xd9c0a29e, 0x029eecf7, 0xa5b8e046, 0xacad9b49, 0x4e414622, 0x12847e58, + 0x5cf9f7a1, 0x70de750c, 0x0f27c53d, 0xcb7e9764, 0xf4bf164d, 0xa82c35ec, 0x56224402, 0x69e18ea8, + 0x24730bde, 0x70ad4401, 0x04b6e08e, 0xa06bece3, 0x04c7cc4c, 0xbec1ef08, 0x7f01707b, 0x109dbcb8, + 0xd814a489, 0x18a850b4, 0xfa4d9e87, 0xdf1df9c2, 0xad5d5a35, 0x1fef2cb3, 0x37454694, 0x93de8ef7, + 0x44dd8c9f, 0x77ba508b, 0x009dc3a2, 0x4ba18158, 0x8991a7a4, 0x999832da, 0x85d0195c, 0xa27a246e, + 0xb2e54853, 0xd7fc08c4, 0xd238bd45, 0x37902226, 0x173bcca4, 0x9f419bfd, 0x6182e7d1, 0x64eaee83, + 0x4d828698, 0x4a2df99d, 0x42e577b2, 0x81130840, 0xd6513a2c, 0xdca30d77, 0xe0e6ed27, 0xddd1e729, + 0x1853a91a, 0xf7569120, 0xce9792e3, 0x0ee544f7, 0x982b6b2f, 0x47b2ae35, 0x308432d0, 0xe9303041, + 0xb39d9743, 0xf03cb5a4, 0x138ecbec, 0x71390109, 0x2347a6ff, 0xddd9d468, 0xe180d9eb, 0xc2e95e38, + 0x46928374, 0x70fcac68, 0xfe9ed7d2, 0x4ce7d2a5, 0x5ea00d89, 0xa0d05cbd, 0xd8568dfa, 0x519ed821, + 0x818463fd, 0xb5ab899a, 0x95049440, 0x1bfcc656, 0x210d7769, 0xc29fc75d, 0x997085f2, 0x64c524d7, + 0x93d681c3, 0x52a0585e, 0x85694538, 0xe6424221, 0x282b3bfa, 0xc9d6d049, 0xd158571b, 0xae79b2a9, + 0x3f0fda8f, 0xeb88c140, 0x7af15290, 0x34035247, 0xf4d81a41, 0xfd5128f1, 0xa7387c98, 0xc97b68ab, + 0x50b5e200, 0x99f2e111, 0xf73efe60, 0x4b27f944, 0xfaa92ae1, 0x5e498145, 0x2dc24fa4, 0x80eacc1c, + 0x1008f0c2, 0x0f023e0c, 0xc67467e9, 0x6de636fb, 0xba345c7b, 0x0fe05a9e, 0xb9e7184f, 0x77c0bc04, + 0xc2b59719, 0x5a65d563, 0xf069d2cd, 0x062b7b63, 0xe752208a, 0x1f58fe90, 0xf57be416, 0x8745b360, + 0x2fa1f55d, 0xb7db2836, 0x152adf61, 0x5008992b, 0x0d81dcd0, 0xb9456f9d, 0x22290c64, 0x7709c9c9, + 0xad79bc29, 0x9865df72, 0x26be4de6, 0xe2f45598, 0xcfad0694, 0x6a04aff2, 0x1243083c, 0xa401ae4c, + 0x3e3a9768, 0xef8f9483, 0x5ee7f7c1, 0x53a2ba4a, 0xa72e2047, 0xb25c0e46, 0xa81e95af, 0x8791bb4d, + 0x43d64f74, 0x0e39b18c, 0x3ce88e4f, 0x2faa815a, 0x2605bfb2, 0x994f5182, 0x6579f34c, 0x67b7d19b, + 0x58cbc08e, 0x0e9e3d61, 0x15ad0dfa, 0xac6f9c22, 0xb8f7f4cc, 0xd4e8a361, 0xc93a5b86, 0xeaf78719, + 0xeb324005, 0x7edb016b, 0xfd94d22e, 0xa376b969, 0xe740b0c6, 0x95471f0e, 0x5c260923, 0xb5cdcf53, + 0x2227b803, 0x0c99f5c5, 0xbf02076f, 0x30ddc38d, 0xb353df81, 0xb475206b, 0xf88bc2ef, 0xd0a386da, + 0xfb947956, 0x93c984f2, 0x76754550, 0x6bb53071, 0x71374ee0, 0x5a29688d, 0x978f4bd8, 0x242e82b1, + 0x58613474, 0x68be433d, 0x653df89b, 0x9e8af5ec, 0x3ddea07b, 0x394de5a8, 0xc16e520d, 0x9ac9a5ac, + 0xd23f44d0, 0xeaf20542, 0xca3f3e45, 0x5bf8f1ff, 0x1818a11f, 0x769aafd7, 0x5bf50401, 0xbce4deea, + 0xcc63d3a8, 0x3939bb95, 0xddaaad06, 0x0e98d9c0, 0x2c34cd5b, 0x5a5ee3b7, 0xaa82d954, 0xebf9ed74, + 0x4ac965dd, 0xcbb2a39c, 0xf5393fcc, 0x4e38f8a0, 0x3c6926d7, 0x1246a12d, 0xd14176e7, 0xcb872979, + 0xb1c947a4, 0xcc98d35d, 0xf1857927, 0x0e498bfb, 0xeae8e6cf, 0xb0089cc4, 0xb40ebd0c, 0x215812b1, + 0xadc4a737, 0x7d28f83e, 0x5f8d36b4, 0x3af9fb7d, 0xcc17c903, 0xda9fce9c, 0xbc1fc5f5, 0xa1ad4189, + 0x8d3f24fa, 0xb5782d28, 0x0e0b9cdd, 0xf60eadd1, 0x3b1c4af2, 0xd945bbd7, 0x3a5e787e, 0x2d74c1ec, + 0x38cb809a, 0xb8499cdf, 0x1f540be1, 0x08caf0b2, 0xebf95012, 0xa483da53, 0x6dd500d3, 0xf462fd09, + 0xe673c063, 0x185ec62a, 0x9bb0dc3b, 0xc52c8289, 0xe5494d6c, 0xf0e50277, 0x487aaa0d, 0xd7ce0835, + 0x240d34a6, 0xf6caa31d, 0xa8d8c7ae, 0x29e95609, 0x098aa227, 0xcb683c43, 0xa2f681df, 0xc49ca17f, + 0xca1038f0, 0xfa6f2be5, 0x746c2a0b, 0x5d98f28e, 0xd38831fe, 0xb876db44, 0x540fe578, 0x51f72c66, + 0xc66c6f2e, 0x244f532c, 0xb7af45e4, 0xdf9c7ee3, 0x0b2ba16d, 0x1f4a52f4, 0xe5a01b09, 0x3cc193b2, + 0x6df8ce05, 0x8aa74900, 0xb7bef0be, 0x831f6af0, 0x4d70fae6, 0xdba3ad78, 0x1ef88e87, 0x6104b1a6, + 0x558acf5d, 0x08e0e9aa, 0x7069a88b, 0x82fa6210, 0x05a2bd75, 0x3047f3a2, 0x50e79fe8, 0xaadf3297, + 0x0b771f68, 0xdddae75b, 0x1a37eef2, 0xccaee490, 0x1590f915, 0x49e208e4, 0x565cfda8, 0xb004af2e, + 0x7542b004, 0x919f8676, 0x9afa8b63, 0x437f7c75, 0xd4f017b0, 0x64a7bdd9, 0x5d800cf7, 0x82e62461, + 0x8b2dcfaf, 0x67396f5c, 0xf636c5d8, 0xa962609d, 0xd1de894d, 0x6bab4f33, 0xab501f17, 0x9ad811b1, + 0x06026e6a, 0xe42c9e0b, 0x59544691, 0x3305c53e, 0x06e33062, 0x8f08f009, 0x5db86a04, 0xfd1f841a, + 0x01a5ae18, 0x80c8a242, 0x62f02736, 0x0beee3d9, 0x5765cd14, 0xa78f2697, 0x12391d87, 0x4f7b05e9, + 0x93eadd25, 0x54ef4101, 0xfb470fe1, 0x7ba832e7, 0x20cdd6fd, 0xeec61ee9, 0x19a3926a, 0xa432db42, + 0x0ea69a7f, 0xd6ee290f, 0xfcbf9268, 0xefb013e8, 0x77f5d29c, 0xde774d8a, 0xabff867e, 0x59c09b66, + 0x5f89b489, 0x717a970c, 0xdbc80b1d, 0xb0b90a18, 0xc0b339c7, 0xa63763aa, 0x543dd02c, 0xd6eae04b, + 0x79534e83, 0x6fb45107, 0xfb86afae, 0x487ba046, 0xa0c245d3, 0x8d162782, 0x1d9ab15f, 0x85860fc5, + 0xd098ac38, 0xa9936918, 0xc84bd92d, 0x5bb420e0, 0x814da63f, 0xb3d026ff, 0xb351d939, 0x51f2a6c5, + 0x51289327, 0x7a7d02b5, 0x31d3be07, 0xe526b82f, 0x910e1ef5, 0xad14bf30, 0x13a71985, 0xd5033ac5, + 0x1bea88d9, 0x5906e696, 0x6be6c038, 0x7c8fb4fe, 0x539932fe, 0xde1429e3, 0x221fa6fe, 0x8224de02, + 0x0d811f38, 0x142666c1, 0x8284ede0, 0x91f7860d, 0xc5ed90a4, 0x01fcec4b, 0x92b553ae, 0xfce72bed, + 0x0083f505, 0xb844cbbe, 0x8c1fba1f, 0x6afdb8ae, 0x864d1fdd, 0x11f9784a, 0x81694a02, 0xd0087124, + 0xb59197ef, 0x15351061, 0x6f55e7d3, 0x2c1f3544, 0xaf99b152, 0x95c693d7, 0x275775e6, 0x1e4f60d0, + 0xb24af82b, 0xf7626fbf, 0x5018a8cf, 0x5d5ab413, 0x2d573310, 0x74e0b4e3, 0x3a2a9cab, 0x6d8cbfbe, + 0x72b28622, 0x7f7139a4, 0xfa3c5381, 0x5126f23d, 0x17f91009, 0x9901de53, 0x893a4e92, 0xe1de6500, + 0x6aab8d77, 0xb135f0b3, 0x54c7cee5, 0xca76b18d, 0x92ba5507, 0x195ec5b7, 0x02e59f11, 0x2cdf15f0, + 0x1aa7d971, 0x93b9849a, 0x9df1803b, 0xad0d35bc, 0x4377ad0b, 0x1a06a4ae, 0x86166e31, 0x516e5509, + 0x467d5ca7, 0x0547186b, 0x0fdacc09, 0xe9fbbe2d, 0x07d8d36f, 0xabdc4337, 0x674b5572, 0x01cd86dc, + 0x1224205c, 0xf486d603, 0x9b287264, 0x3df67706, 0x8a389058, 0xbbcff644, 0xee940a65, 0x88a7bf2c, + 0x9a1b8842, 0x9326a87f, 0x7c3e46c7, 0x3cd36d3b, 0x1d70d47f, 0xafc35f40, 0x148e3af6, 0xd9a321b8, + 0x5c8a3710, 0xab8945bb, 0x96fd7b44, 0x29abf2ed, 0xc6bb08b0, 0x8d588a80, 0xd053d09b, 0x65fce91b, + 0x55c48abd, 0xa55cd716, 0x96190305, 0x634ec375, 0xdb2c7acc, 0xe152fd28, 0xc1af7be6, 0x704e5903, + 0x8ed77891, 0xfe515200, 0x0ccc7780, 0xffc8c126, 0xbaafc78c, 0x80e4c45f, 0x8642326b, 0xc812dc7c, + 0xf8a17631, 0x587a49b8, 0x346912dd, 0xbb0a7115, 0xd890f7fd, 0x691fc70d, 0xdace94e3, 0x1366f6e2, + 0x32112999, 0xb568b4e3, 0x1659a981, 0xa360dfce, 0x2ab11319, 0x08723d57, 0xe2276a25, 0x9963eed2, + 0x1278ef28, 0x89f00941, 0x7426e8a2, 0x65395610, 0x6a10935b, 0xa681f1ca, 0x73c18e5d, 0xbe31de13, + 0xb0e764e2, 0x681e2aab, 0x3fd6e5b8, 0x4dcd7196, 0xfc4eec10, 0x3e65a467, 0xa8653427, 0x5af4f6db, + 0x0ed45b2c, 0xcbb34c8f, 0x7b308416, 0xf7ed71d6, 0xfa7cc68c, 0x2c4f7583, 0x4145ae8e, 0x40a0e682, + 0x2ce06a6d, 0xcf707e02, 0xf8950bae, 0x46220ce7, 0x96c02982, 0xb7001f99, 0x78472c24, 0x9cca6fd2, + 0xad070638, 0x033579e6, 0x28bb81d6, 0x483be0eb, 0x0496ed79, 0xe8d94f2e, 0x0e423a6b, 0x2fa131a2, + 0x7d659e6e, 0xb348c12b, 0xdc7467e6, 0x0d81e524, 0xbf5d146a, 0xe0460f34, 0xb1086154, 0x8e27ec17, + 0xe2c42eab, 0x4a943064, 0x3ab810dc, 0x753655be, 0x05b4f564, 0xefa72747, 0x2b4b7489, 0x8bf4f66b, + 0x0264190c, 0x67dd471d, 0x40fe43b2, 0x049212b4, 0xf4993343, 0x33632dc6, 0x295999b4, 0x6573d87a, + 0x7f4572e6, 0xe86d4949, 0x9e02eef3, 0x0cbc5ecc, 0xe5834b4a, 0xa017869b, 0x3a25953f, 0x24499bf4, + 0x738b164a, 0x9a136881, 0x06b2abf0, 0x77f75e69, 0x01a11635, 0x13f2c6f4, 0x42a64b17, 0x998e1d0e, + 0xdfd8e45b, 0xcff69322, 0xdf28b7ea, 0x5b4b4e18, 0x21bf05bb, 0x5afd1145, 0x128232f8, 0xa5d6c7c7, + 0xf8e0c0fb, 0x6447f88d, 0x247f2c51, 0x4fcb901b, 0xe5c81ca5, 0xbe26d2ea, 0x7f377404, 0x5574c917, + 0xb647d8f7, 0x005cb049, 0x2d33cf6b, 0x69e1ccef, 0x8f4833ff, 0x686604cf, 0x90c3af08, 0x497589ec, + 0x859f58ee, 0x44eb5023, 0x28271e60, 0xce2c01a3, 0xed36345a, 0xc69ccefd, 0x0e763d9b, 0x366fa99e, + 0x02b609c3, 0xaa13b779, 0x31b5c5db, 0x15a10559, 0xd0d85fce, 0x0e920435, 0xe8476648, 0x5d1cc5fa, + 0x57c72845, 0x1d52020e, 0x7191a476, 0x88a9685d, 0x34c8e299, 0xc8f0eef3, 0x5f225a4a, 0x130fae95, + 0x663106c4, 0x576b6f85, 0xde5afe82, 0xdbe2a3d0, 0x9d03a9e3, 0xf481bc9d, 0x9d41fffb, 0xadbab67c, + 0x7e980b98, 0xbfb3dd1a, 0x43c8f30a, 0xced0f503, 0xda81a0df, 0xae2b510a, 0x9d51e324, 0x2d99786c, + 0x3661bae7, 0xc2bc475d, 0x67c50330, 0x10f1b17b, 0xd3def3b0, 0xd437ec7b, 0x1c50f181, 0x589da4c2, + 0xa77cadff, 0xddee1fef, 0x06a18ca1, 0x4d35deca, 0x40da518a, 0x9beca789, 0x8b0fcb63, 0x3efb79fb, + 0x0ae26b9d, 0xbeff5070, 0x3436fe74, 0x4e60f09b, 0x5a49c83f, 0x487fa257, 0x644c57cf, 0xf188fe33, + 0xbf16dbc1, 0xd18e808d, 0x22bf0850, 0x0f7c454e, 0xaa2e51be, 0x73b376c2, 0xb3c3d2c2, 0xa75e750c, + 0x66b3a5dc, 0xddf3ce16, 0xb646d30c, 0x0fe02bb2, 0x271ef869, 0xf8d5400a, 0x52945ade, 0x3cc3abbb, + 0x625bd548, 0x4e37bc10, 0xa4063582, 0xc9c3bf7e, 0x724a9384, 0xf618d2c6, 0x3112b8ed, 0x7e91b83e, + 0x3e39ddea, 0xb8e8140a, 0xc121be29, 0x55b68659, 0x3c583e21, 0x11d55c14, 0x7650d64f, 0x46612adb, + 0xafc16be0, 0x036b039d, 0xd764dc10, 0x7054dbb9, 0x22afb1b9, 0x26e99888, 0x73194331, 0x98846b82, + 0x37572dce, 0x08c2c9c8, 0x5296f0a8, 0xe1168414, 0x715c4007, 0xf7e581d1, 0xc18971ca, 0x85ede35d, + 0x21cf5117, 0x3c547411, 0x5620d7b3, 0x6fb6320c, 0x84989982, 0xb11f1ed1, 0xdb0a424a, 0x9fc4ef30, + 0xb0f0243e, 0x6a1ee218, 0x665a360c, 0xfe721b7d, 0x7ce87547, 0x0855f6aa, 0x085322e1, 0xee2974f1, + 0xa0925998, 0x5d037f18, 0xe3f1ed38, 0x5782f6fb, 0x061f5a71, 0x39a93241, 0xc7c88519, 0x1759ecc2, + 0xd3a0c5c1, 0xf5ebc094, 0xeb333a03, 0x2d07a3f5, 0x725300e8, 0xe4224e45, 0xb0a19981, 0x4ca58d29, + 0xe7cdb86b, 0x128c1e38, 0x84d61537, 0xf5c6fb72, 0xf727e70e, 0x523b7feb, 0x23732c47, 0x56e116fb, + 0x804df643, 0x63cf2553, 0xd7b02de2, 0x9e3e0028, 0xd30c1d75, 0xecf44f5b, 0x3fabcc07, 0xa0d0ab8b, + 0x78680c88, 0xe7710f0b, 0xadd39680, 0xe6778f7c, 0xcf2fe555, 0x5dc60ca1, 0xb65f7d46, 0xe1e9f452, + 0x661b6db9, 0xef32f54f, 0xd0368d55, 0x1a76e5fc, 0xccc605e8, 0xa4bf6881, 0xfb62f210, 0x0c565ee4, + 0xcc29539f, 0x8d58ed10, 0x05f667bf, 0x5229cfd0, 0x9ac9ee45, 0x4de2104e, 0x9a7bb035, 0x75257c4a, + 0xe1dca812, 0x42da4d73, 0x779be599, 0x473331c3, 0x8234e061, 0x6a907a31, 0xcd512ace, 0x90863c2d, + 0xb8aa0c22, 0x1b2eab2b, 0xa4bc8aaa, 0x4ec9bb35, 0xb1ab4aff, 0xbefc07fd, 0x23309650, 0x84579a67, + 0xda1afe95, 0xbbdaecb5, 0x4e015977, 0x3366f302, 0x4494a3c1, 0x7ec068a6, 0x3051fb87, 0x2d3d486d, + 0xf8145fca, 0xb377db0f, 0x24de8107, 0x3f3374b1, 0x02693931, 0x260ede95, 0x9c4fc6de, 0x23d32ea8, + 0xcfded63e, 0x7eaea1b0, 0xfff5ef73, 0xe07e92fa, 0xc1bd01dd, 0xa111a3f3, 0x9b951bd8, 0xd7a78b50, + 0x2d8f1c68, 0x9eb5e8c4, 0x8bda6abe, 0x79eabf1c, 0x8eb9c745, 0x67d371ab, 0xf6c5aeb1, 0x4b5376b2, + 0x034a9ec6, 0xc0e3e087, 0x311f46f0, 0xf4ce9741, 0x458e5cb0, 0xef7708f8, 0x1e2f8792, 0x2be4c140, + 0x1bceb4f3, 0xf4649990, 0x99525272, 0x213bbd0b, 0x740422dd, 0x6f3a279b, 0x8d3d7964, 0xcebd60de, + 0x36f5f052, 0xcf35f228, 0xd35e04fa, 0x98d58732, 0x0e741f25, 0x39b1ddf7, 0xf00224d1, 0x2e88499a, + 0x78cb5d33, 0x9121c108, 0x019a3a29, 0x50bbeba3, 0x664d4a15, 0xff36c2e8, 0x46a64a84, 0xfc83fe63, + 0x725d8b48, 0x4b95d6af, 0x586ae0fb, 0xd994dfa6, 0x81180270, 0xb8f317ff, 0x91ea4b1f, 0xbefa5104, + 0x556a227a, 0x3d2cfeb4, 0xe3b43a24, 0x14ff8302, 0xf75be5ab, 0xe8e7048b, 0xaacb2d6e, 0xd30dbc05, + 0x9d45e384, 0xa6637306, 0x332eccc3, 0x07833276, 0x15b15915, 0xb9520202, 0x098c60f1, 0xa49674cf, + 0x6b4313ba, 0x30e69f12, 0x52e9524c, 0x474502df, 0xa47baefa, 0x87c8eed5, 0x4e8eea44, 0x17fa20b3, + 0x2dd83322, 0xbc48953b, 0xc2798187, 0x9e11ea6f, 0x648bc0b1, 0xdb63aef3, 0xb017d4a3, 0x6f0bd85d, + 0x06acc306, 0x5ec823b0, 0xb59cc39f, 0xe83b2f38, 0x3f2a77d4, 0x79cbcd08, 0x646d1b68, 0x300fc3e4, + 0x3464e6df, 0x18efc697, 0x6cfb9c16, 0x1e1aae37, 0x7e40c188, 0xcd21eb05, 0x11ccb130, 0x9f4f3dab, + 0x787cbc06, 0x45894e6e, 0x28a55299, 0xb7439778, 0x2a9542bf, 0x6458d4f2, 0xc26298cd, 0xc3d7bff3, + 0xb1100696, 0x80ab24cd, 0xa0015e22, 0xb106055d, 0x0f72afaf, 0x4dea1276, 0x76d8bdc0, 0x92080299, + 0xc78525f7, 0xaca053a3, 0x06c7ea73, 0xa6a9ecca, 0x15bb7ad2, 0x52a1eaec, 0x45a5f91a, 0xdc9de76e, + 0x95c444eb, 0xc20ea663, 0x453ea47b, 0x1fe6315a, 0xcbe2d101, 0x2e7cb168, 0x4a6aee12, 0x4a1405fa, + 0xd441ce87, 0x76422d17, 0xc75c681b, 0x1a43bbdf, 0x75375ccf, 0x9f6d1547, 0x0bf1fad8, 0xc5de33b0, + 0x9de5e954, 0xf0e8fc36, 0x92b3e41e, 0x203f893c, 0x6cea08f8, 0xa12331a5, 0xf096028d, 0x7881800b, + 0x94fe2dba, 0x28c84547, 0x993a33b2, 0x839ce4eb, 0x7a47cacf, 0x6a78a294, 0xda76c3f0, 0xcc0e7c0f, + 0xd85170f3, 0x08d0b8a8, 0x27ac8066, 0x787f950e, 0xb7729ffa, 0x41dd8f90, 0xf2fd0681, 0x5fb7c89c, + 0x1444e8ae, 0x1792286e, 0xd988f507, 0xd41a3123, 0x172942b5, 0xfd9abfc3, 0x354569d9, 0x5dd9c928, + 0xda58494f, 0xc6666b7b, 0xa8951464, 0xc0e22db7, 0xbb6840f8, 0x4c3f30e0, 0xbde60052, 0x2cc49d90, + 0xe2deb2c4, 0xbe559059, 0x6f291bb4, 0xb36dade8, 0x2d588470, 0x9dd50e2c, 0x6499dc0b, 0x9e72faa1, + 0xf0eda07a, 0x5f42b0bc, 0xa14982d5, 0x26493958, 0xa9bb2a61, 0x24706a20, 0x466ea232, 0x163515cf, + 0xd64c4b51, 0xf3a4bb95, 0x43f11e09, 0x79885bd0, 0xa1f32e1a, 0xee538b69, 0x38ea5615, 0x196657d4, + 0xb856aa98, 0xa1940ed4, 0x29212fe2, 0x4595b22d, 0xb0368a98, 0x513d870d, 0x4fb7d1d8, 0x2de57306, + 0x09826183, 0x5e5d617d, 0x8180cc99, 0xdb7dd4f1, 0xf2cd04b7, 0xa2537585, 0x2de940a1, 0x876ce505, + 0x1460986c, 0xccb36624, 0xb00c4389, 0x02ded77a, 0x7b60647c, 0xfcfbb189, 0x3048644c, 0x16f905d9, + 0x262f081c, 0xbee48d34, 0xdd063293, 0x948b4f1a, 0xc8697aa1, 0x6a343132, 0xd8dbc671, 0x2b2917d4, + 0xbf0dfbde, 0x124d8fc6, 0x09fe7112, 0x3749c28e, 0xf451b59c, 0x4ffb7869, 0x1c10cde6, 0x507b0c53, + 0xe1d0daf2, 0x0e7c2eb7, 0x0b5474ab, 0x40a38f2f, 0x5fdc1938, 0x96ad7bef, 0x62386a7a, 0x9a2ead93, + 0xe28a62f6, 0x319b39e4, 0xb41b024e, 0x77b5bf8d, 0xd497d9d5, 0x2164bc45, 0xb527df9d, 0x5fdfadc7, + 0x6a2a6bed, 0x6e0c5c6d, 0xb08f5c95, 0x797675e9, 0x2a8f93d3, 0x0f2d7d68, 0xc82b3799, 0x3bafbf21, + 0x08207da2, 0xf976fc98, 0x7a05eaa3, 0x03bed2f6, 0x675aadef, 0xcf93bb90, 0x55257dbf, 0xb6420441, + 0x14676a7d, 0x3f797b8d, 0x786e69ca, 0x64bc8957, 0x288a8c87, 0x49a9a4ba, 0xedc9fd75, 0xc0c62797, + 0x5ab74c33, 0xb1393aa7, 0x6f0c52a5, 0xdd88cf44, 0x7425ac47, 0xb5c3b3e1, 0x951beae1, 0x187d92ef, + 0x1e2732fb, 0x16184e20, 0x5725a95a, 0xd50ae81c, 0xc1755758, 0x88957886, 0x2111bd94, 0xf97cdb3f, + 0x40ffbba9, 0x50f79bf8, 0x31d3c78e, 0xc47931f3, 0x2cffcd85, 0x39de93fa, 0x63ad8ca9, 0xf23d4f52, + 0xabf5ce5a, 0xc8eae12a, 0xccb38272, 0xd18c8750, 0x9f367bfd, 0x306c523c, 0x9cb98403, 0x2cc6ac33, + 0xaaa269ec, 0x7e58d6e3, 0x04c098ff, 0x1c1afbf7, 0xed03b646, 0x38b66ccd, 0x14f2e87f, 0xe7d7e983, + 0xf6ca46c0, 0x5ce76b3b, 0x853291b2, 0x306922c2, 0x26ca27cc, 0x8c3dd232, 0x2be801cc, 0x6ea3e937, + 0xb660bf8a, 0xe339e7df, 0x146c6b77, 0x3d2d4a4d, 0x6d2ef22d, 0x27b04e35, 0x5d8624e7, 0x5852f71c, + 0xf0de5e9b, 0x3f9c8256, 0x53304c39, 0x6d69704d, 0x7e47538f, 0x5a05c6d1, 0x6bdc726e, 0x1a0867f6, + 0x044bafd2, 0x8edf42c2, 0xbd439c65, 0x21b15d63, 0x74b8fd2f, 0x83189211, 0x2b2e246b, 0x407f927c, + 0x11e6df2b, 0x0a5e1368, 0x170b9624, 0x077cd664, 0x18b615ec, 0xe656b7c6, 0x5b5d46d5, 0x5164b5c6, + 0x51526420, 0xcb20d053, 0x32b6787a, 0x21f8ea80, 0xfec25fa8, 0x13c78a42, 0x999f0c97, 0xbb79caea, + 0x53f4649d, 0x3d61b775, 0x0d42f922, 0xe47419cd, 0x0bdb1163, 0xab73f251, 0xe2f4e659, 0xb4bc419b, + 0x4dd1b6a2, 0xbf87a757, 0x18a13406, 0x2895d241, 0x35dbebdc, 0x2923ae64, 0x03c9fb94, 0x54abd6ab, + 0xce6fb1a7, 0x23bb7e6a, 0x37fdeb56, 0x4015d28b, 0x96fe8634, 0x71daeda5, 0x77869002, 0xa908c011, + 0x0fda65eb, 0x050d350d, 0x9dc38255, 0xf04ec19c, 0x98280d52, 0x79c7a745, 0xc3b75d10, 0x19c2d98c, + 0x4145f18d, 0x4e0d50e3, 0x24bb2a85, 0x18f5a58e, 0xce51c8c6, 0x5193449d, 0xb2c3f732, 0xe836bb12, + 0x8eac0780, 0x87833c2f, 0x97d476d9, 0x4254184c, 0xbed9b73b, 0x752640b6, 0xfa637a9b, 0x3404e35b, + 0x5dcfcbf0, 0xbdf773fe, 0x8bf231ac, 0x02c6eecf, 0x0e31c903, 0x50730efd, 0x94f7c4b0, 0x5f7bb802, + 0x7c507d32, 0x81ced6f7, 0x4c496e8c, 0x381defd9, 0x6053165f, 0xe87fab87, 0xe3bd8332, 0x3b428fc1, + 0x5436e59a, 0xb2a217eb, 0xcf35687f, 0xee797b8e, 0x74462e1a, 0x8c207a73, 0xec1baf34, 0x5e142c75, + 0xfb7bc798, 0x66421df3, 0xd4d289d8, 0xaff61755, 0x5469ecf7, 0x7ad1461a, 0x4c3959b2, 0x3437a760, + 0xa6ad4497, 0x0fb31e04, 0x9ef4a9cd, 0x7c3fb909, 0x4a117594, 0x22a6180f, 0x48d2046d, 0xa1ef720b, + 0x6cba2f7b, 0x6b961983, 0x2c0357f9, 0xbed142a5, 0x3bf81bcb, 0x3d0557ad, 0x66e8e79a, 0xaa86f5ac, + 0xff98341f, 0xc5fd119a, 0xff8cec50, 0xbaf1108d, 0xc733e9f6, 0x65b2cf5e, 0x79930dad, 0xeaf640bd, + 0xbfabe047, 0xda135101, 0x4f5e5bbb, 0x4348e2e9, 0xc811f820, 0x41266141, 0xb48939e3, 0xa1d66a0b, + 0x4149afdf, 0xa4c016d7, 0x8d0c1307, 0x338ae64f, 0xae8cefed, 0x74b3d50d, 0xd44041a5, 0x2da3b872, + 0x44498560, 0x1f4c71bc, 0xb6c03c9a, 0x2719c320, 0xaf32e6a3, 0x9ed8e2df, 0x25b20d25, 0x93d78573, + 0xf97dfa6a, 0x20b7a655, 0x8cc527a6, 0x2ba7f7ae, 0x35e6e26c, 0xa4503c79, 0xf4bd106c, 0xf2eb803d, + 0x09093655, 0x2ea9f4d3, 0x49b44317, 0x2e2bd490, 0x547a9fec, 0xc60ad84d, 0xf4e689a3, 0xb5bf9b6f, + 0x6f87e46b, 0xb6e8b6a7, 0x5ded60eb, 0x69ec2fb3, 0x85f88f16, 0xa29f5cad, 0xf418e5a1, 0x3b5700e4, + 0x42258911, 0xcc01b230, 0xa67a5905, 0xe7fe65b4, 0x25053bea, 0xc739719e, 0x39b22958, 0x3c48c3e0, + 0x6e84ff66, 0x8dbf3ff4, 0x6e705cf8, 0xf24989df, 0xae433700, 0x3d0ec1f0, 0x895b6f81, 0x77d68092, + 0x4f581a32, 0x4e3a3152, 0xbdf19585, 0xf7ca0790, 0x1485ca6f, 0xf3e16ed9, 0x1559df72, 0x0d738fb5, + 0xf3b51c01, 0xf16a72d6, 0x120458b4, 0x9fbdf080, 0x138fe9ae, 0x045c79ed, 0x1a64e996, 0x5355a0df, + 0xc3c0af55, 0x24534d93, 0x57fed433, 0xe47f9c10, 0x536818d0, 0xf3134a8b, 0x4320a7d8, 0x134b57c0, + 0x058a86e5, 0xa890feb2, 0x5a7d44f9, 0x76fb86bf, 0x855b230b, 0x2f2c6cae, 0x0180d772, 0xd2147f39, + 0x870eeab4, 0x22d9a660, 0x93ff0ef4, 0x1111f4e1, 0xca4e3702, 0x61b91f27, 0x2a9dab4f, 0x71d2a6a9, + 0x89aaa97e, 0xdbb808fd, 0x5dea0eca, 0x614ce58d, 0x69c47b11, 0xdae9b09f, 0x90dd2582, 0x724c4ba5, + 0x60ae1c04, 0x0ee602df, 0xa030721b, 0x03e14528, 0x4bbb6062, 0xf1097b96, 0xb7edeecf, 0xf35e236c, + 0x25027d75, 0x094c51fd, 0x3f8a37ff, 0x006f3cb2, 0xdcc3726c, 0x7fedf0ad, 0xcb3e296c, 0x8aadaed5, + 0x9fcd4cd9, 0x9c889e48, 0x00ce6290, 0x77323256, 0xcaf8c2d5, 0x2865389d, 0x42de5bba, 0x76c72817, + 0x522f2274, 0xc7360b45, 0x6200a520, 0x3d9ba577, 0x2a16d245, 0x46406fee, 0xb1bb57cf, 0xf3af737f, + 0xf2503074, 0x4067f0e0, 0xbef9220d, 0x3c65dd44, 0x40fdbd11, 0xc155d93f, 0xde911c3c, 0x559c3504, + 0xa0ff5865, 0xb215b90e, 0x292610a3, 0xa0f3bf74, 0x56666185, 0xd055d257, 0x8baeadec, 0x92135e2f, + 0x7187973f, 0x4877da6a, 0xc68a60b1, 0x9a47e274, 0x7debe412, 0xaddac30e, 0x70aa6cfd, 0x4d8c640b, + 0x15963173, 0x2bcb643d, 0xc508dab8, 0xda1a22d7, 0x2d80ad4a, 0xb7ccf332, 0x558edb42, 0x495d7de6, + 0x946ab82e, 0xdd743e16, 0xe8e032af, 0x0088695d, 0xeb7913c7, 0x822cb102, 0x03e8f096, 0x1fd9d1e8, + 0x5453629b, 0x2a0b919c, 0xbb91802c, 0xe9438720, 0x856173e9, 0x52c73ee4, 0x342ea1df, 0x66e872fb, + 0x642e532f, 0xe2e4e38d, 0xa655d76a, 0xd437d836, 0x9b7b78af, 0xf3130b77, 0x4ae9e474, 0x4de438a4, + 0xe4079728, 0x69f9989e, 0xa1408d3e, 0xb77536ef, 0xcdf82231, 0xab391698, 0xbd5a45d4, 0x7eb568cf, + 0xbe94de04, 0x59484e3d, 0x052d64f9, 0xc4ec070a, 0xd93e50d2, 0x093dee53, 0xb325ca2d, 0xef04a711, + 0x9e3e3397, 0xa5ef2c90, 0x01fe1f3b, 0x7581cc4e, 0x31158eab, 0xd3deda82, 0x112480b6, 0xf6b94687, + 0x4346ba84, 0x8f84b6b0, 0x13dcb8ff, 0xddccf6ce, 0xe127cf74, 0x30bc518d, 0x8357ab63, 0x42bf6bc6, + 0x0920fe46, 0x873a758b, 0x5039f0bb, 0x7334dc29, 0x72fa4a38, 0x4259039e, 0xae30e1e4, 0x166c7110, + 0x3c039feb, 0xdfdd11e9, 0x673c79a8, 0x9d19c06e, 0x0900fb1d, 0xfc25f5da, 0xd2fcad23, 0x24e4bfcd, + 0xd9f24987, 0x6c278bd9, 0x5187582b, 0x3a01262a, 0x1267feda, 0xa255dd5f, 0xc0d02a36, 0x701fb0f6, + 0x26a04a9d, 0xd29ef554, 0x58b831f8, 0x30ad15cc, 0x95e8661f, 0x7449d32c, 0x179407b0, 0x8ff54244, + 0x152422bb, 0x9b04b5e0, 0x7887fc4a, 0x6ce11a7a, 0xb6d41172, 0xb6242c76, 0xfec63e2a, 0x28b7f16b, + 0xcae09b8c, 0x9a2a1c63, 0xf6d6da18, 0x7d15488f, 0x9b19eb95, 0xeb49b8d4, 0xecf26819, 0xbf1dabd1, + 0xff922ee0, 0x94823c95, 0x7644145f, 0xa23d4485, 0xb60491d4, 0x6913413d, 0xb0168cca, 0x3a434f3b, + 0xdafeca11, 0xb230d4c6, 0x04562072, 0x43c5c5f5, 0x97bfa980, 0x18b69132, 0xae6719c2, 0x7cb93585, + 0xc75ec00c, 0x60b672d0, 0x062ea9a1, 0x16518431, 0x403f61a5, 0x515b4e0a, 0x00c9a9b9, 0x9565d9d0, + 0x550b8550, 0xcf58462d, 0x264ebcd3, 0x29b6f02d, 0x91ef9ee8, 0xff2ed59f, 0x9d9320f8, 0xc1f9da63, + 0xd2afc564, 0x8ff8a356, 0x8d4fe47a, 0xc51a999a, 0xb85db0ec, 0xf60d8e09, 0x8782977f, 0x9bd8468c, + 0x711bce91, 0x71d216d7, 0x2a09ab95, 0x18eb69ca, 0x6e1f7449, 0x262ddca2, 0x43595d87, 0x0161ae13, + 0x41abd19c, 0x742906c7, 0xd528a6af, 0x8a62f154, 0x5302505d, 0xd3955454, 0x3b1e7439, 0x46a52b36, + 0x45fa8ef7, 0x414617bd, 0xb66d822c, 0x8028b201, 0x62935ce2, 0x516226c9, 0x44be2061, 0x61e76422, + 0x5193cdc4, 0x1886e6e5, 0x71b0a7e2, 0xd171f55d, 0x8591ca3a, 0x32f0449a, 0xa0b6db9a, 0xd2b4e901, + 0x98c6e491, 0xf7e8f46c, 0x83cebe36, 0x2cda9f05, 0x4adb60bc, 0x60631f05, 0xafdf3a85, 0x4e17625d, + 0xe59df572, 0x7c91ec10, 0x890d9f59, 0x04d4f595, 0x3e4eef4e, 0xdc960b36, 0x0d67d89a, 0x89f3dfc4, + 0x0b812321, 0xdcd0b1ce, 0x2a45df26, 0x90e01320, 0x8b9e97ee, 0x73e8155b, 0xdfc1b47a, 0x7e75709d, + 0x9130cfec, 0xee815929, 0xcd9accfe, 0x21d63ca1, 0x5f9b6f33, 0xded1e242, 0xf064bcc0, 0x373bf956, + 0xd3cee4d3, 0x1bfa8958, 0x86b19cf3, 0xb5e5ecd4, 0xea05c6ad, 0x55615f70, 0x9cb62a63, 0x873e2b05, + 0xefba8b15, 0xe58fec5c, 0xf1dd35fa, 0x34ba6873, 0x1e5e6048, 0x55359766, 0x3c37d8db, 0x5c8db5c3, + 0xaacbf96f, 0x69de88df, 0xcf662e7d, 0x7b0114af, 0xa5209dda, 0x21dedc0a, 0xcb87f036, 0x286f7514, + 0x8b5f40d6, 0x439f39dc, 0x4f1fe858, 0xb0dbf789, 0xb53796d7, 0xfe04c74a, 0x24a47772, 0x289fea4e, + 0x1295d7bf, 0xa625752a, 0x0c426587, 0xa96a33e3, 0xffe0d5ea, 0xf28eb695, 0x1803f50a, 0x4485d1f4, + 0x5dc25472, 0x330ba29e, 0x58f9776a, 0x88499b62, 0xae57e4f4, 0xc46dde2f, 0x0239f237, 0x45b70a21, + 0xf6857f47, 0x8b2c4dec, 0x0051b3fd, 0xb8a0f464, 0x6fa45cc2, 0xd777f51b, 0x06c4101b, 0xe53c14f4, + 0xc2a9e187, 0x949d6842, 0x310e8f1c, 0x01ed7ae1, 0xaf2f7408, 0xde73ab4c, 0x94f6cef6, 0xdab175cc, + 0x629c5232, 0xd573f336, 0xf1b6da0a, 0xc5848fa7, 0xb102b343, 0x89a263ac, 0x8d5c0ace, 0x531d8b2f, + 0x4bc88427, 0x2f313913, 0xd4ec9fed, 0xc24fd727, 0x5ef855c1, 0xf4dca3f9, 0xe01c8476, 0xfb167af6, + 0xd1eb74f6, 0x684d0452, 0x2d37cc4f, 0x8c7f4e69, 0xd24e61ad, 0xd51f3246, 0xed26e7a9, 0xccf4e36d, + 0x50015006, 0xbfbee8d4, 0xb3808054, 0xe16261d7, 0x848385cb, 0x5f959168, 0x9e47cc82, 0x8b1201b0, + 0xfc935c72, 0x6daf788c, 0x295ca268, 0xde2a8b34, 0x8ef89889, 0x0c1a6709, 0x00bb6565, 0xce00b476, + 0x1ac6446c, 0x5c535027, 0xd7e7fc9c, 0x0a41701b, 0x300d539b, 0x0dc03437, 0x44ac50dd, 0x665e0b9d, + 0xfb08f494, 0xc0a9add6, 0x7f1ad8d1, 0x4c10217f, 0x50f439f0, 0xbcb86d63, 0x2ee11e2e, 0x36b44a20, + 0x0fda96b5, 0x56403463, 0x24a2c0f2, 0xc0d8f7c3, 0x030825af, 0x4b253040, 0xd02b0cf2, 0x655246c7, + 0x2c710088, 0xa625a887, 0xbb19f5cb, 0x0646d828, 0x08cda107, 0x2d081b25, 0x6b242b20, 0xf64ab5b7, + 0xfcf01593, 0x6d9769b4, 0x7909c101, 0x0389901a, 0xafacf289, 0x9bc777ce, 0xe8858697, 0xd7611649, + 0x1ee0f88f, 0x5b9c9264, 0x3e2e75ac, 0x2d8a37b7, 0xd7af1407, 0x8e4679bf, 0x865fbc94, 0xb321c63f, + 0x414a8456, 0x808fc293, 0x6ffc9116, 0x8ac1aaa4, 0x8923d26a, 0x743f3c47, 0x6511c623, 0x9c02aee2, + 0x9aa099aa, 0x3dac8d35, 0xd0e96b8f, 0x31fa9975, 0xded3464b, 0x33a8fbbd, 0x6ca7587a, 0xdd598dc5, + 0xb2e475c6, 0x8177dd87, 0x494fa7a6, 0x8f3912e8, 0x26da4d7e, 0x7c9f1f37, 0x1f0a54a4, 0x9fd00626, + 0x4961e49b, 0x96c575df, 0xdc501a03, 0x5b640441, 0xc5abcece, 0xb51e0d79, 0xf33fd4aa, 0xcee64886, + 0x18eb8f90, 0xc8b66846, 0x53e9bd40, 0x2834dde7, 0x751bd22d, 0x879d07be, 0x89fa3af4, 0xdf2e7c89, + 0xeb5165b3, 0xeb0956bd, 0xc1b00ab6, 0x5b7c36c9, 0x5de46d20, 0x0911b00a, 0x6dc3c203, 0x0c4f1713, + 0xf2f46950, 0x60ac6127, 0x27c08f12, 0x60b9223d, 0x0e1c4445, 0xf2861535, 0x362c32c0, 0xdc54403a, + 0x3fb2bf0b, 0x9781c844, 0xd356a0fa, 0x826b6988, 0x784a3cb0, 0x9ef351a4, 0x1b71107a, 0x8456cf1f, + 0x666ca9f3, 0xfa0f5861, 0xa9e40f8f, 0x0e7278f6, 0xdb8d80d0, 0x2c423b49, 0x7c8c936b, 0x98e8fbcb, + 0x09ac97d2, 0x16a54b95, 0xd934ab46, 0x1173c774, 0xb14cca61, 0xfe6b7b6f, 0x35299cca, 0x5f5732ec, + 0x09c65cd1, 0x1aa6e562, 0x20327de6, 0x66c88b98, 0x0d5deebc, 0x6654f707, 0x49e7f6be, 0xb2ae9637, + 0xbb8ece57, 0x53062e31, 0xedc5f650, 0x235c8244, 0x9c12700a, 0xac373f1a, 0x2ea817d5, 0x7ddf4f37, + 0xdafff34b, 0x4ff09cc7, 0x123900cd, 0xaa3ca59b, 0xf5f3af23, 0x45618c69, 0xba003ee3, 0x12a25cc3, + 0x0292ae32, 0xa656c8ec, 0x18a4c5b5, 0xa62a9113, 0xabab8f0c, 0x0825d71b, 0x475766a6, 0x6cb404d4, + 0xe228eb5a, 0x3ae2ef49, 0xd434b26b, 0x3a84e783, 0xdc5840e4, 0x741fba21, 0x4413aa77, 0x0ce88a10, + 0x9d8e009a, 0xf1ca164b, 0x6a4b7bcc, 0x184a0056, 0xc4c7f2f1, 0xae9539c7, 0xa63a346f, 0x0c930153, + 0x03cf0f72, 0x4711d900, 0x5515f9cb, 0x897a3aa7, 0x1a5c1be8, 0xda1fc143, 0xcd7ee135, 0x7886f20e, + 0xd92be4c6, 0x847dd922, 0x4a91a839, 0x67a84303, 0x389562a9, 0xbcb9c700, 0xd6bdbc1b, 0xa56d9044, + 0x9777d52c, 0x1e9a17e7, 0x520f80bc, 0xdb2e739f, 0xb7f40d0f, 0x532e4b68, 0x48c504f0, 0xa5e91e37, + 0x794af643, 0xf436acf1, 0xaf6518c1, 0xf227c710, 0x31dc830a, 0xf938126f, 0x98745c8a, 0x0cb9a0e1, + 0x1542704c, 0xfc40cca7, 0xf8584e91, 0xfa7d4119, 0x82b1d455, 0x3d5f8068, 0xcffe0021, 0x92b34af4, + 0x0de5319f, 0x95a88eb6, 0x46727f26, 0xee31b329, 0xf8b5c5a3, 0xfdfc8c11, 0x025d5f72, 0xd72c299b, + 0x7f3956b9, 0xd3926999, 0xa810785e, 0x900b3e54, 0x2b99730d, 0x551d6c72, 0xf30f7c76, 0x8e386cae, + 0xa16162e3, 0x1e432079, 0xbf9e6982, 0x7b28ed29, 0x2b23301e, 0xc47bb9a8, 0x803362e3, 0xbf3bf122, + 0xfc5b4ece, 0xb547a4d0, 0x79a93149, 0x886a439d, 0x9435030e, 0x4820aa89, 0xf9ae511e, 0x25f9b866, + 0x30a91e65, 0x711b639c, 0xed2fb6c2, 0xf7b33b58, 0x96a6d522, 0xd4071999, 0x484dabdd, 0xcb5b2bfe, + 0x4cafdd8f, 0xadc1e8b2, 0xc44b5904, 0x89c08750, 0x398c8ff4, 0x7ec0e5ac, 0x94621bf0, 0x673a4d8c, + 0x43842d35, 0x44fb541a, 0x2ea9b611, 0xa925c47f, 0x581eae19, 0x1d29967a, 0x375c20a3, 0xd3d52b50, + 0x2f47411b, 0x95e9a49e, 0x8d97dc14, 0x496fb89a, 0x880fc2c2, 0xf949481d, 0xc517642b, 0xad0f730d, + 0xe119a437, 0x64a9b3cc, 0xce7d96eb, 0x7f51de24, 0x1d0db4fc, 0xf08f5f83, 0xa3803925, 0xf6cf0385, + 0xf3b579af, 0xf2ec8a9e, 0x242ff662, 0x3266866a, 0x95191d98, 0x0c53422c, 0x3d3198c4, 0x569fe86d, + 0x1f6758d4, 0x79375181, 0x2b9529b7, 0x21f9a4b6, 0xb898497a, 0x4f07b05e, 0xdda5d990, 0x49b43665, + 0xf1966f5a, 0x6042738d, 0x72cfd91e, 0x37c0457c, 0xf7ec03e5, 0x07f8e12e, 0x0fa7c84a, 0xbaa021ae, + 0x1bc62972, 0xf1bdc70a, 0x84ad0e8a, 0xba5cca6f, 0xd1d0e34c, 0x470a6015, 0xc3aa8bdb, 0xf2c9efdc, + 0xf170ba90, 0x8435cc3e, 0x9d761fbf, 0x89ac5cfe, 0x7ff90dd5, 0x2ba00bf8, 0x6b364fd2, 0x1ec945ac, + 0x2378e68b, 0xdfcb7899, 0xfa330c11, 0x46979042, 0x96d9f18a, 0xdd67960f, 0x9d7b3655, 0x8ed4c589, + 0x98e1c1fa, 0xe07c4f4b, 0x76115d67, 0x2e8d9339, 0x181cd80c, 0xda0b47d5, 0xb12ad26a, 0xdc142a82, + 0x5c7c16b2, 0xbe6361ad, 0x30d0aa76, 0x597974e4, 0xca1997d4, 0x41cc5c4b, 0x339542f7, 0xe7ce68b9, + 0xfc4daadc, 0xfb2767f1, 0xe6247cd2, 0x1398e6eb, 0x9c89a8f0, 0xdbb1f396, 0x4aec9b88, 0x157ba0a8, + 0x545e1857, 0xb5c1833b, 0x04b9f69b, 0x9f0fa2f3, 0x48c753d4, 0x600fc040, 0xd296974c, 0x04b247ed, + 0xb610913b, 0xc9e0618c, 0xe62a2c8c, 0x72f94c18, 0x94044107, 0xb1e00ca7, 0x873337e4, 0xc0e352f7, + 0xd3624146, 0xeedea5e9, 0x5c5f16f6, 0x0098abf8, 0x02d7a195, 0xe3b825ae, 0x4851664a, 0xe64f2329, + 0x1594c561, 0x70e0d71b, 0x918b6a48, 0x5d5bc31c, 0x8caa1c32, 0x05c547b4, 0xfd635011, 0x6623bf3b, + 0x9feffea3, 0x7ac79ae5, 0x5aa83234, 0x4614fde7, 0x27fb33b2, 0x6377d25c, 0x8437853e, 0x2ef448fb, + 0xd571626b, 0x72565db5, 0x7c175894, 0x6eb538cb, 0x51a99579, 0x57e79826, 0x31f1d5ca, 0x81a00d79, + 0x93b5a9f0, 0xdc9e0db0, 0x52077c68, 0x7cb7cb28, 0x296528aa, 0xf78cbca3, 0x5fe8e455, 0xf9a9f838, + 0x3889ef5c, 0x95fa54c7, 0x86a2ef3e, 0x0a2f5b58, 0x811c7d4f, 0x0d6154c5, 0x224aa3f8, 0xdf61fb0c, + 0xbbb66b03, 0x1e1e0cce, 0x3ef86560, 0x90c6d801, 0x697359b8, 0xe115a1ae, 0xa0d5f0fb, 0x33c240cf, + 0xf4298adb, 0xae0c7c94, 0x9612537b, 0x64d8a866, 0x1c1a5445, 0x76be3464, 0x4fe6603b, 0xde3fe7fe, + 0xd2ea184e, 0x6b37b66a, 0xf42e681e, 0xa39c1d18, 0x9a5a18b3, 0xbe76e6cd, 0x71e0b7da, 0x779b103e, + 0x1ffd6b59, 0x90bd594f, 0xf3b6b8f4, 0x09578b08, 0x205ac1be, 0xb9e6b531, 0x15d6d7b1, 0x4f904a8e, + 0x43909200, 0x1b4414c6, 0xe2906453, 0x664ec12b, 0xdd026bdf, 0x3845fa7e, 0x0c1667ef, 0xeb267226, + 0xbebca443, 0xe64a85d4, 0xc4faa676, 0x4ad86b80, 0x500bf706, 0xc7d2b902, 0x5d5b5159, 0x6347fb05, + 0xa99f7e95, 0xfed80b3c, 0xe3f0c86c, 0x41ca91a1, 0x2255a523, 0x5cd98ac2, 0xa08d0b78, 0xe1d61052, + 0x13d7c3d5, 0x7eaf98dc, 0xf668c48e, 0x76d375ac, 0xe6192755, 0xbebe9181, 0xf22630f9, 0x36d851cf, + 0x48070f50, 0x92c263de, 0x6a8e93b3, 0x27da5d5a, 0x00fd59f8, 0x92d5924f, 0xb0370af3, 0xb55ec8ad, + 0x304f5390, 0x1430365f, 0xa6f384f8, 0xf98f7d2f, 0x005ff3fb, 0x9240c51d, 0x476aee98, 0xc8731109, + 0x37c0f764, 0x3941c263, 0x325d4cfc, 0x6b0f3207, 0x4077474a, 0x9f99fe9e, 0x38291681, 0xdeae9739, + 0xf587b523, 0xd6eb32a0, 0xff6a1deb, 0x29850272, 0xe4bcf9d3, 0xbd96efd1, 0x935a8d85, 0x04f38a9a, + 0x9abd06c3, 0xd5fb039d, 0x17ff88ea, 0x798d84e2, 0xb83f1474, 0x1f568a15, 0xa69d3df8, 0x588ec806, + 0xaa62bf61, 0xa75b643e, 0x44bc2a5b, 0x2234c6bf, 0x6a90d3f4, 0x5a39ef2d, 0xb6172383, 0xbe7d6326, + 0xc01a6935, 0x54239804, 0x30d4a5f6, 0x73ea3cad, 0x6735239a, 0x9d9800ca, 0xcd9276e6, 0xd875ef8e, + 0xea3e4147, 0xd8b14f37, 0x17adb744, 0xccd9b74f, 0x625924d7, 0x8eedae2d, 0xe59282e6, 0xa1630d25, + 0x212b5e28, 0xa1484711, 0x5713a13f, 0x00cc8e01, 0x61ce4ac3, 0xf475c1d6, 0xde4af1e0, 0x0ce8d40f, + 0xea905e32, 0x5f4f8037, 0x480a2c63, 0x30291332, 0x3067665d, 0x8f656ab0, 0x5bbfbca1, 0x897d2b94, + 0xf0ef8895, 0x0d598b10, 0xf12ba53b, 0x03d85a55, 0x36ec7165, 0x450d018c, 0xb8d122f9, 0xdd2d36d4, + 0xb082c934, 0x3cd6418c, 0x116e1347, 0xd710c188, 0x21969bc1, 0xa4298605, 0x77612e53, 0xe63e939f, + 0x91019ba0, 0x8349187d, 0xfb8d5f66, 0x7fee1f76, 0x5726c38d, 0x107dd30f, 0x9cc31098, 0xd7850a09, + 0x42674a1d, 0x87786b2c, 0xadd67b7a, 0x3241dd23, 0x5100258e, 0x95ef11b0, 0xa687e739, 0x99114ec4, + 0x28e33b11, 0x3395fdc9, 0x83e9e88e, 0xcd1e5bfb, 0xe8581553, 0xb64a4c96, 0x6f0410a8, 0x45c9227e, + 0x34aa3c50, 0xdb3a3acb, 0xd81f9068, 0x8b522187, 0x59f2a2f6, 0xfac8be2b, 0x4c9b86ff, 0x46a68465, + 0xd30bfde1, 0xb56668c5, 0xaba88df4, 0xf5e6d1e7, 0xe11ab431, 0x429b84d9, 0x8a6f4e63, 0x6027b8cd, + 0x748ba781, 0x6885c829, 0x0bb09a0a, 0x0229bfd2, 0xc9f07a5a, 0x7fe9baa1, 0x6bf10740, 0x05b0a064, + 0x4b4d8c39, 0xbc790409, 0x0496b05d, 0x907a1ef1, 0x015e3edf, 0x8a10229f, 0x76ff4660, 0xa02a70fb, + 0xb23d6476, 0x18de4098, 0x17ad1aa2, 0x949144e3, 0x2983fafb, 0xcfb4a709, 0xa75a3548, 0xcc714e4b, + 0x514fd8ff, 0x80e4cf83, 0xec9eb1d2, 0x69703b6d, 0xb99059ad, 0x07678a5c, 0xeedc0220, 0x1c06fc33, + 0x04389052, 0x52d2187e, 0x6908c8b1, 0x64b181f3, 0xcedc1aaa, 0x9b8bbc90, 0xdde9cd54, 0xef3d8736, + 0x2900309c, 0x0d8e7edf, 0x1ea82a10, 0xf206fc93, 0xe03fe1cd, 0x11aab85a, 0x1c96d0fb, 0x24e2cc4f, + 0xfe67868f, 0xb177b101, 0xa54f83da, 0x0427b95e, 0x6e949bfb, 0x154e0096, 0x4241b882, 0xa6a1553e, + 0xfe83d660, 0x852342de, 0xaf01db08, 0xf7102eae, 0xdb31f724, 0x84aecd13, 0xf2d8496e, 0x41d8580e, + 0x2dbe5a20, 0x17a9158d, 0x3b54cbed, 0x67aba7fc, 0x66116c2a, 0x6e473397, 0x276924a6, 0xb3e2c6b7, + 0xbf700a2f, 0x614b46b0, 0x7ec2fc59, 0xd7188e52, 0x50934a67, 0x78e99a18, 0xdef2bccc, 0x1f36814a, + 0x5d264154, 0x0c50e69f, 0xdb101ffd, 0xac4eaf43, 0x5ad8e1ff, 0x053c699d, 0xb151ddef, 0xdb6128d1, + 0x7ebf0721, 0xb02046de, 0xc35422fd, 0xa7ffbd3e, 0x6a202361, 0xac2710b3, 0x8611e204, 0xd03078bf, + 0x66d5ca20, 0xa403dd1b, 0xe6d7086d, 0x90e4adda, 0x4fe50264, 0xab97098b, 0xcfc33342, 0x537ec516, + 0x22c92104, 0xa8471c28, 0x770a1b33, 0x2e874373, 0x0590648a, 0x90c544e4, 0xeb507563, 0x8519b37e, + 0x3cc87d59, 0x27dc14f5, 0xfa9966db, 0xce02efd0, 0x79167f35, 0x5b848a44, 0xc0f299e8, 0xb53f8b65, + 0xc1d0ddb9, 0x179809a0, 0x1bafc14c, 0xc60e926d, 0x3a5a1ebb, 0x6b9afae5, 0xe80d821b, 0x13ba8424, + 0xa5482751, 0x263ae64a, 0x0252966f, 0x6cbc96b6, 0xc289faa0, 0x18999c11, 0xadfa384f, 0xb061a450, + 0xf4dccbbf, 0x1c98ff1c, 0x8086279c, 0xf35774de, 0x0526a7a5, 0x1a4dd050, 0xeff11a2f, 0x07038178, + 0xf24bcdaa, 0x101f46ce, 0x9bdf8f91, 0xc8ed5507, 0x0aedd525, 0x1e4fbba7, 0x51f32509, 0x4229d6e8, + 0xd995ca8c, 0xd57e8ae3, 0x0acc35e9, 0xdcf06e10, 0x509219d5, 0x1c17903b, 0xc49593ab, 0xacdc2583, + 0x3edbf37d, 0xcfc14dda, 0x440a855d, 0x43a240c9, 0x4de1244c, 0xe20ade93, 0x437480d0, 0xa1732ccf, + 0xf118eda6, 0x861fbc04, 0x602f7779, 0x20b66a38, 0x34a3bda2, 0x6eee339a, 0x8b48f35e, 0xb84b261c, + 0x392171f1, 0x27c3f15f, 0xd444b3b5, 0x72605e75, 0xaeb4d7ee, 0x353c28be, 0x0f169e45, 0x934d4398, + 0xf779cec4, 0xbf15a9a5, 0x9865fc3b, 0x4b6475d5, 0xc2dc85ae, 0xd1441e07, 0x773f1549, 0xfaea9d53, + 0xbc7aa831, 0x690d3ae4, 0xc48758dc, 0x6d831bb1, 0xc159dda7, 0xac666bab, 0xe6f3c619, 0xd7e072b2, + 0x76a6c059, 0x8e500ec6, 0x9ea45045, 0x802552fd, 0x24d417c8, 0x0b4c0a25, 0x8d50b7a4, 0x4f9f7919, + 0x4e305e33, 0x2b336670, 0x145847dc, 0x7170321e, 0xd6156e48, 0xc0fed8e8, 0x6a47b136, 0x03f72fec, + 0x29d46f80, 0xae19ffab, 0xe2a0ae73, 0x6a85a88e, 0x182113aa, 0x841ebf85, 0xb34f0940, 0xd9476655, + 0x9c1016cb, 0x015067e8, 0x97272cc5, 0x06bf40e7, 0x811751a4, 0xb1dc1dc2, 0xa8b2935d, 0xe4dac14c, + 0xd813443e, 0x32f52ef8, 0xabde5482, 0xb7ceebd1, 0x8b678856, 0x10a687f4, 0xeaf05ac8, 0x79d84331, + 0x9e806477, 0x2904f62c, 0x81284cbf, 0xd7f6e05f, 0x2217bf8f, 0x862951c3, 0x240f3bd4, 0xda68dc31, + 0x3974c49f, 0xb92fc61d, 0x5d2703ca, 0xaa67f390, 0xf50ef8dd, 0x3512d2bf, 0xaf6b49cc, 0xe4051606, + 0xe6b2bc8d, 0x5684baa0, 0xfce4fa45, 0xdcbcb47f, 0x26950603, 0xb9ad4ed1, 0x247cc65c, 0x6687cb53, + 0x684916f4, 0x3b9107cc, 0x46b20f19, 0xb4d1187f, 0x8e69d830, 0x880b6a39, 0xe68c9125, 0xcc5404d9, + 0x06249adb, 0x7cde820b, 0x39316324, 0x3f95958f, 0x54999b95, 0x6559ef3f, 0xe93c8af1, 0x2e98e259, + 0x98b91074, 0x1d62526d, 0x66ee493c, 0x576fcfb9, 0xbb7c3abc, 0x9e15ede9, 0x40e6c23e, 0x36fcc06d, + 0x0efdab8f, 0x701a9452, 0x2ed2162b, 0xa86b286c, 0x145a029e, 0xebfdb4fe, 0x2d1bf833, 0x041de9fa, + 0xd51edb12, 0x2f92f594, 0x0d4ce706, 0x970fbeb6, 0x0fbb1ea3, 0x824b94b3, 0x35b0cb3b, 0xea0d50ab, + 0x49d414f8, 0x8f55fa47, 0x3a9b9373, 0x3f39bed8, 0x156322b8, 0x37eb0616, 0x999cd3c9, 0x7176045a, + 0x9a332955, 0x94274ebe, 0xe8ccf96d, 0x316a26e0, 0x0ccfa3f4, 0x1efbe18f, 0x19a191d5, 0x3b2eadfe, + 0xa7881eb2, 0x85e78c26, 0x3f635b10, 0xc517d6b9, 0x0dbe1078, 0x34eb02d5, 0xc0a4b7a3, 0x85268507, + 0x2ab93690, 0xca742b12, 0x2d098d2a, 0x5e36d472, 0x03faf539, 0x0ade7250, 0x3e230e36, 0x8d548140, + 0x79f346da, 0xd466e0b4, 0x7d21a353, 0x18de0db4, 0x013989e7, 0x87a6cd42, 0x0cd74ee8, 0xf0a88a9f, + 0x0d1ab85e, 0x20810815, 0xa7219949, 0xbb1bdec1, 0x1ee31f97, 0x797b1d93, 0x0809c1c6, 0x07238b82, + 0xb4cb84dc, 0xa7eacfdf, 0x631f3aee, 0x3490ab95, 0x8c19b4cf, 0x27b44b8e, 0x39959bca, 0x151bd4e2, + 0x893d13ec, 0x9329b5be, 0x70167c01, 0x50d49c16, 0x1ade8acf, 0x89fbf787, 0x8bb90ea8, 0x1444651d, + 0x34be4985, 0xb6c3b713, 0x6e2e8351, 0x60df91cf, 0xe593e800, 0x89adc803, 0x7f688859, 0xebac9b57, + 0x74886c55, 0xf4889a70, 0x10a5680b, 0x07be34bf, 0x4544dfc9, 0x917e297d, 0x0b5a3004, 0x7b994c4b, + 0x650083bd, 0x3bf58c31, 0x088cefac, 0x24bf03ac, 0xfa480329, 0x84f52c86, 0x5d8454f1, 0x3ed3e48e, + 0x2bce8380, 0x5eba5e6d, 0x030b2c51, 0xa952617f, 0x839ac2de, 0x0da38053, 0x42d8e1a2, 0x70b68660, + 0x0d757b93, 0xd3c62097, 0x5f4bec1e, 0x5ea94a76, 0x134b248c, 0x942ef78c, 0x379f5b34, 0x4c6110b8, + 0x150d727e, 0xe60fd7b7, 0x1a30c2bc, 0xb9e213f0, 0xe671889e, 0xc9ea8f08, 0xa784cf10, 0x310909ad, + 0x12d31c8d, 0x3861118b, 0xe906cb12, 0xb0ddd57b, 0xa460048f, 0x1362376f, 0xb2868dfe, 0xba1ec7a0, + 0x05d0d548, 0xbfecda21, 0x1046d765, 0x7f85fc40, 0x1a05ff6c, 0x7bbe1a35, 0xa11cd04d, 0xad39283b, + 0x1c14ca97, 0xd306ee0f, 0x5fc6adab, 0xf86e07a3, 0xd9de396f, 0xcbeec481, 0x03b5e12c, 0x22754b1e, + 0x390cf201, 0xb95e0183, 0xa4e238ec, 0x7a08ed8c, 0x3d779c14, 0x34825751, 0x2adf654d, 0x40fe7105, + 0xd1ca4a87, 0x8428f196, 0x97dd729c, 0x9e9a8085, 0xdb3204a9, 0x3a75dc3b, 0x8cd5f30d, 0xbdcf5920, + 0x6e9a5583, 0xa02004a2, 0x3d07991d, 0x34a3ff64, 0xe65d795c, 0xc183b33a, 0xa0491973, 0x8785f20b, + 0x50190ecd, 0xc3a9168e, 0x6c45d98c, 0x6a970cb7, 0x96de5968, 0xdc3b3807, 0xfcd1cce8, 0x6e3bf073, + 0xb2383efa, 0xef1768fb, 0xcabc0052, 0xf3aca83d, 0x86683cbd, 0x58a81e9b, 0x84155a72, 0x131a7bf7, + 0x850cc3ff, 0x8c5cf3f2, 0x663af506, 0x80d111ee, 0x983b8dfd, 0xac20d099, 0xe80ca0dd, 0x08909ccd, + 0x31e595bc, 0x8f3c22fb, 0xecbd68aa, 0x0e9653b2, 0x2d48f650, 0x00fc6df6, 0x0f278eb5, 0x002ad166, + 0x423c01e1, 0x32dc5a03, 0x63529f5d, 0xb6b7833a, 0xc93419fd, 0xcb02f959, 0x9990261b, 0x0627dd8d, + 0x2df5660f, 0x2ae356a5, 0xfd019032, 0x3d6c9840, 0x6c3f0bbe, 0xafd4f24d, 0xd930480a, 0x2187cd52, + 0xc76a84dc, 0xb3273478, 0x3664e0e9, 0x65fa411f, 0xb4ffc180, 0x099092cc, 0xfe3d883c, 0xf43a989b, + 0xbe907deb, 0x1227c56f, 0x0fbca705, 0x70734166, 0xc22fb714, 0x6835c5bb, 0x86d8c5c1, 0xb4bfcda7, + 0xbeaf28ce, 0x36168973, 0x6579385b, 0xa8839ca3, 0xf74e68f3, 0x9d07d6c4, 0xcf393231, 0xe2f68553, + 0x21381260, 0xefae3dc2, 0xbe60f118, 0x428dd418, 0xe57a6688, 0xd87b7e26, 0xf673a2aa, 0x597760c5, + 0xdbb2cf50, 0x3850b9b6, 0xf2d10991, 0xd149b5f6, 0xbf9fe0dc, 0x5d49a610, 0xc37aa909, 0xaa5b0194, + 0x455dfda2, 0xbdd9288b, 0x686f67d3, 0xecc151b9, 0xdd72c517, 0x63dd98b6, 0x111c1576, 0x6eb882c8, + 0x82a908de, 0xe41739b8, 0xbb2ca814, 0xf79b2a71, 0x9624ddf9, 0x962d49f6, 0xe5b3bc75, 0xe6f652de, + 0x767b672f, 0xb5735746, 0xb9dd2699, 0xa92ba1d3, 0x7000a7fc, 0xebc950a4, 0x31f70f26, 0xdbccb8fc, + 0xb273abeb, 0x4be38cbc, 0x8d06fa71, 0x878233e9, 0x4da54246, 0x568539ba, 0x62ccdbc4, 0x6d2682ee, + 0x785abede, 0x86eb6125, 0x909d0093, 0x6093a855, 0x2e4dbccc, 0xaf9603cb, 0x5d2b1081, 0xb66b7221, + 0x5a87c29d, 0x90243f68, 0x4be3e22e, 0x4448ea4f, 0x399edf38, 0xcd9681fc, 0x1b7d1aeb, 0x81169771, + 0x2bdfec37, 0x1ff29858, 0xbc2d9c6e, 0xa5c0207c, 0xe144ec34, 0xa0443288, 0xca5adbf3, 0xa3edb96e, + 0xf47ccb50, 0xc0c939eb, 0x2545a754, 0x9f0678fb, 0xde382416, 0x70283d12, 0x61aeab56, 0x326808f8, + 0x3507a861, 0x55f7f238, 0x87f4b060, 0xffc3aed0, 0x14649fa0, 0x43fd5122, 0x5675f272, 0xf32b22ae, + 0xd48d657f, 0xb4589bd0, 0x3f01940e, 0x5390537c, 0x0c409d33, 0x98e0cb80, 0xf90d86c2, 0x50b8091a, + 0x4495ed10, 0x996f5947, 0xe36f429f, 0x80776588, 0x6f9c3891, 0x933a5536, 0xeabf0768, 0x9198fa9b, + 0x4dd6d9c0, 0x24082cb2, 0x85aa1682, 0x19e7a0ec, 0xa484ccd1, 0x69febf40, 0xaf8fc93e, 0x221deb68, + 0xa0acbc8f, 0xc78fcc2f, 0x356ca4d9, 0xd42b5db6, 0xcb898329, 0x22a9c95d, 0xe40afb33, 0x704675ca, + 0x09fb41b2, 0x59766193, 0x70f1b3d6, 0xecd819d0, 0xdd476ca6, 0x3bcc9403, 0x253b7297, 0x64e537ed, + 0x3f753c7e, 0x0fdfeb9f, 0xb5415516, 0xc5faf234, 0x9cb304c5, 0xb093c7ab, 0xd1913f14, 0x2d4be89a, + 0xb648db09, 0x41ae3de7, 0x81580aa5, 0xe5f834e7, 0xba7834bc, 0x891bb73e, 0xb7ff55c0, 0xd556383d, + 0x120cd519, 0xa288787e, 0xae7fb673, 0xca168bbf, 0xe984decd, 0xc8b7476b, 0x7cfa3e8f, 0xbc1721dd, + 0xdc0b025a, 0x084da342, 0x784a8ca6, 0x4e0d7f00, 0xafcf2c8d, 0x2af79b2f, 0xc1a3f3cf, 0xa42262d7, + 0x34a3995d, 0xd823ef19, 0xb53b58a6, 0x42c6e2c4, 0xe29612ef, 0x7979d4c7, 0x2aa3f66e, 0x475c7c2e, + 0x76a9622f, 0x0899a2b6, 0xc58811c1, 0x288f9002, 0x0e39c872, 0xfc3fd7b0, 0xb57a5405, 0x8201412a, + 0x10588069, 0x468423e4, 0x8c595d21, 0x43317168, 0xd47b77e8, 0x64304ed2, 0x73a19ce7, 0xf6e3494f, + 0xbe1d4f03, 0xb9fc6865, 0x37bf5942, 0xcf1b088d, 0x7db34ab5, 0x5c3194ea, 0x5ee446b4, 0x5711f62b, + 0x6f20597d, 0xc19ec0f7, 0xc418f828, 0x55f2ad20, 0x412aec36, 0xe1767a93, 0x916fa88a, 0xb8785eb0, + 0xc1771414, 0xea40a2ab, 0x255e603d, 0x71c84feb, 0x40b6ef80, 0xf5c83ccf, 0x97b58578, 0x012ee02d, + 0xeb6a270e, 0x64096657, 0xc16fde2e, 0x40e0b299, 0x9413078c, 0x7d41e176, 0x98f28b90, 0x910be37d, + 0xf41c97fe, 0x0d55df03, 0x61b29286, 0xe51223fb, 0x05ae8fbe, 0x2dacb759, 0x0c1887e1, 0x29940308, + 0xf4d7c0c6, 0xa8266712, 0x2588e23e, 0x0aa0962a, 0x5450c6ca, 0x65847af8, 0x7e625ec0, 0xdb9fd193, + 0x7d73f028, 0x22d2dada, 0x946b4ef5, 0x392136dd, 0x6ba6e505, 0x3134c2ee, 0xe772160d, 0x1f0d8344, + 0x915e8c60, 0x414c56ad, 0x4093ace9, 0x2a740f5c, 0x9f62cbcc, 0x8168e71a, 0x4e915b6e, 0x62935215, + 0x6040967d, 0x8e9cdaa9, 0x25247b81, 0x9e237aa6, 0xee24e449, 0xe6e1fbda, 0xdde21e10, 0x46815262, + 0xa0f382bc, 0x99d74f95, 0x87affdf8, 0xbb2fc25b, 0x6095c3c5, 0x406593f3, 0xdf686fdd, 0x73852f97, + 0x23035fbd, 0x2dd74463, 0xd3c5167c, 0xcefe518c, 0x0f13bf59, 0xbaccfa26, 0x80e713cf, 0x3f53506c, + 0x91782bef, 0x28dd5cf8, 0xc878155a, 0x0ed0337f, 0xe956876b, 0x12c41e51, 0x7de3345a, 0xfdcc6615, + 0xabfb0d98, 0x465c9e39, 0xef6f2360, 0xae0cbcf8, 0x895153c3, 0xc7706e5e, 0x4c85014e, 0x8a5d16b0, + 0x0928eb4f, 0x50d4af59, 0xdf1592ed, 0x804480c0, 0x3cba8b0f, 0x23b95dea, 0x3e704c2b, 0x678e1142, + 0x705c39b8, 0x8ffa4955, 0xa4adcfdc, 0x8f3a8cdf, 0x848c18ee, 0xc7c4fa49, 0x0cd8f8dd, 0xb1f94666, + 0xceccfe63, 0x38623bcc, 0xb0e22fc8, 0xb049f38c, 0xb413d1e3, 0x49e0bfd6, 0x210363a2, 0xfe13009d, + 0x0d387847, 0xad316d5d, 0x5645f4af, 0x869e6d13, 0x9e8ee720, 0x45cc04fd, 0x851b7092, 0xaf14dfee, + 0xee89d964, 0x52ef615d, 0x8dda3ace, 0x8cbe0f58, 0x9098ca44, 0xe59c6d21, 0x9187ba9d, 0x5772ee2b, + 0xec3a3421, 0xff08d5e0, 0x2bb8460e, 0x65db1433, 0xc1df9826, 0xa7783ee8, 0x24d32202, 0x01d9396a, + 0xda64e892, 0x896ae8ce, 0x82c1c71a, 0xdcfe087e, 0xe079cf2f, 0x4e772668, 0x80d87a03, 0xdc7efddd, + 0xa5169ed7, 0x9251ed2d, 0x50e7f26d, 0xaa7a9aaa, 0xd49a5b82, 0xae637761, 0xb9cc0d74, 0x7a684dbc, + 0x69d0b24a, 0x518c3878, 0x09037d8a, 0x1b106ff3, 0xdcdfaedc, 0x9e65550b, 0x764201d3, 0xdc1d5016, + 0xd5a779c2, 0xfb79ac66, 0x4b8bb921, 0x38073d9f, 0x5dc41c6e, 0xe57bcdd3, 0x65474c66, 0x25c54f3c, + 0xc956f061, 0x4fccaee6, 0xd318b7ad, 0xe1d17121, 0x61091119, 0x41d280fa, 0xd8790424, 0x88676d93, + 0x9fdfd5da, 0x2c8f1062, 0x127d6eb2, 0x3602f169, 0x5fbdf038, 0x424c1178, 0x92a5f586, 0x40b54548, + 0xf4019dd2, 0x30378522, 0x9972ae73, 0xf2d558b7, 0xad66298f, 0x829f6271, 0x84ceff22, 0xfd9e3058, + 0xc9df4b71, 0xc0a5bac3, 0x9026be71, 0x8ce39264, 0x624aceca, 0x2eb2d578, 0x6ce26208, 0x3ff5089f, + 0x87d3b6e4, 0xda7dabe5, 0x9507bd65, 0x7deb9113, 0x8255564e, 0x2e4935fb, 0x5b96a376, 0x30eb38f3, + 0x564f87cd, 0x6b2b3753, 0xdc3c982d, 0x49f08c7d, 0x1b24a988, 0xacf134fe, 0x1437d483, 0xa01c142c, + 0x0295aaf0, 0x49c265ea, 0x7a817b2f, 0xa65f1659, 0x73bcf0b9, 0x5ca33a52, 0x77115d40, 0xd30aa216, + 0xf23c4732, 0xd936f063, 0x77c3a451, 0x5536a91b, 0x21f56286, 0xdb607c9d, 0x7fa20338, 0x94c8e26e, + 0x0c7f5d98, 0x9fb6d883, 0x90bd480f, 0x11deb08b, 0xf73f897c, 0x6a5d56cf, 0xf5c62f7a, 0xe11a0156, + 0x55c18bc1, 0x8469a5c1, 0xfd17a5b9, 0x647ff52f, 0x66140b6e, 0x64154ddf, 0x20e30900, 0x662d6921, + 0x7ef6e3bc, 0x9014b7da, 0xdd8541fc, 0x89b71759, 0x3b58e39f, 0xf12c9548, 0x39ffc77d, 0x001e4286, + 0x898470d4, 0x46ae42ce, 0x9badb3d0, 0xc96f09fe, 0xfd8f1e17, 0x7ab7975a, 0xf0a9e454, 0x68cbf608, + 0x7e652a16, 0x5e508905, 0x854c6797, 0x8731bd59, 0x2cd95240, 0xc40d24b9, 0x43aeb944, 0x9b18a99d, + 0x0b02bf4e, 0xf96a2a05, 0x2eaaaf44, 0x7144623d, 0x9f2686df, 0x7d265f37, 0x728ee3c6, 0x059c070a, + 0xd1d32973, 0x06ed36b2, 0xd22efac0, 0x36dd808a, 0x9d324c13, 0xcf446a56, 0xde3cfc36, 0x968f9da4, + 0x2750d3e4, 0xb76239b9, 0x86d8db48, 0xf3cfd862, 0xe287b94f, 0x6f740925, 0xfd1b1b28, 0x2641e932, + 0x44edf334, 0x6f26edc5, 0x23cd071b, 0x1ce96884, 0xfa483cda, 0xe2347340, 0x8ab62ce7, 0x67256133, + 0x0fa62c59, 0x74bffc45, 0xc3609d4b, 0x64cdd36b, 0x985dcf71, 0x343ae917, 0x540b5aa3, 0x074e65aa, + 0x99ddeec7, 0x239cfa72, 0xeaf90bb6, 0xbdbb969f, 0xf4a5dc1d, 0xb26a5374, 0x1d4a2133, 0x9af9fd7f, + 0xb9c4a49c, 0x91f04391, 0x5ecf1dd6, 0x41ea48f1, 0xc419f3dd, 0x2b7d9811, 0x98767438, 0xff180f05, + 0xfc14a5b9, 0x606a8c2e, 0xeea73f8a, 0x6cfc166f, 0x3a3911ad, 0x0d36fb4e, 0x334fe49a, 0x8e8409d8, + 0xbba607b4, 0x07313774, 0xda601e63, 0x20122b42, 0x74a1354c, 0xcf3f1ea8, 0x1cfd9527, 0x44b297e1, + 0xd779f056, 0x940759c1, 0x73448d04, 0x5fca940e, 0xed65fcc3, 0x0314b897, 0xfa88404a, 0xf6a34344, + 0xbedbe8e8, 0x9dddf14e, 0xc5e2394b, 0x0a64399e, 0xc4bdc6a5, 0x2f9946cf, 0x79596794, 0x5f04dd83, + 0xf404364d, 0x1b3851b8, 0x960b3b60, 0xdadae7e9, 0xb8491fc5, 0x39cdffdd, 0xae85f126, 0x4b7e5c6a, + 0x83a6a542, 0x4c8c5cf9, 0xecb9d8a2, 0xc3773cbd, 0x343343e7, 0x0d5b2c3a, 0xddd5d472, 0x27514e06, + 0xc1747cb4, 0xf285e885, 0xde2ff445, 0xaebeafe9, 0xc7e55072, 0x3998db83, 0x1eb39d55, 0x276a454c, + 0x08a1564c, 0xb992d3f8, 0xef43747d, 0x3d1dffae, 0xf2c47720, 0x624893fb, 0x5fe16cd5, 0xd662bf7b, + 0xbdf63d37, 0x1cbe248d, 0x3c80a709, 0xd20900ee, 0x70132365, 0x0f33b609, 0x5f34327e, 0xf1cb41fd, + 0x54226887, 0x9d57ec9d, 0x60406259, 0x260676a7, 0x9a7faa18, 0x2e782f23, 0x6230d8e0, 0x393c03ca, + 0x97b406ee, 0x6d910078, 0x76b86834, 0x13f7bfc5, 0x618afee9, 0x3272c980, 0x77670d9a, 0x868a437f, + 0xb1ec6582, 0xe5db2993, 0x40c5b868, 0xa955511b, 0x8cf3b1d6, 0xcaade852, 0x4f5358ea, 0xe9cfc566, + 0x4208ae40, 0x7bd11b79, 0x8de6054b, 0xbb0cc38f, 0xa0e47fb0, 0x96b6ec16, 0x56dd9a4a, 0xd8479d1a, + 0xdb3b4a0a, 0x9882900c, 0x3b0c746e, 0x723ab4bc, 0x4eb702f0, 0x07db4b0c, 0x9e379ce2, 0x6396697c, + 0xb1db23b9, 0xd2fda13d, 0x93f6e6ea, 0x2d13f352, 0x8f5dfb2d, 0x7c765d50, 0xf198ba82, 0xe4013b3a, + 0xb1126edd, 0xa6fd6557, 0x958bec9f, 0x2fb3a940, 0x699bcd39, 0x3c3680cf, 0xaf981278, 0x0dba6d03, + 0x9f670831, 0xef7eeca2, 0x79f2dae4, 0x36c9a638, 0xd5efb63e, 0x4605f027, 0x1264fa07, 0xcb728d1e, + 0xdc0f3ad8, 0x54bb1dff, 0x88266cf7, 0xee6793ae, 0xf77c37d4, 0x9c36757b, 0x9a81fd9c, 0xfd440a5b, + 0xd0e14735, 0x71d457db, 0xba343765, 0x6b3ed193, 0x633c8ad7, 0x1920f152, 0x662afaa7, 0xe4f0f19b, + 0xdb7f0dfe, 0x57f1c51c, 0x4072c891, 0xf38d2995, 0x40b56e64, 0x8b031d0a, 0x2fb418c7, 0xfc4f4976, + 0x23a1a076, 0x404f2a18, 0xae121a28, 0x458bcb32, 0x8cd08cf6, 0x36d81821, 0xedaf77a7, 0xb5eee955, + 0xb19a3ec2, 0xba57f04a, 0x9ca89699, 0x0a7b6693, 0x545fa1be, 0xbe571d5e, 0x0c9a2c7c, 0xd9f552be, + 0xf18ed10b, 0x360aa8f4, 0xac377dbc, 0xb7614f3e, 0x3e2b412e, 0xfef1fa58, 0xfe127467, 0x32201c4f, + 0x3f391fa8, 0x4b46e041, 0x070c2bc0, 0x55414bfc, 0x4779e1a0, 0x483dc6e3, 0x19447bd5, 0x7aacb15a, + 0xc663f187, 0x10c08913, 0x5df76dd6, 0xb0f8cbf7, 0x98002309, 0x53906bec, 0xb77944bc, 0xb22224fe, + 0x0d73de51, 0x21d6f764, 0x153c6633, 0x21e21cef, 0x22c90783, 0x2f8371d8, 0x2141a6cc, 0xbc83962a, + 0x5443f0c9, 0x5235c293, 0x2d4202fe, 0xceb4d91b, 0x1a489e26, 0x8eb3569b, 0x0298d459, 0x8ea96739, + 0xae74cf7c, 0x1f7c6367, 0x5d89e9eb, 0x5fd2273f, 0xed7671d2, 0xbbffe490, 0xade9d433, 0xacc70664, + 0xe7665df4, 0x729e844b, 0xfe6b34b4, 0xd11fcd8c, 0xfd031e21, 0x3209ecf0, 0xdb046ad7, 0x6b7c2570, + 0x0e6687f2, 0x1e78989a, 0x6cdae695, 0xaea8d69b, 0x5e593871, 0x8136a10f, 0x4f3956cf, 0x6dadb5b7, + 0x876ac3d2, 0x1016ffa7, 0x8032d1e0, 0x943a5532, 0x8adba7c1, 0x3055bda2, 0x2e63c692, 0xafb51897, + 0x1eaa94c7, 0x9b5a2942, 0xaa5a20e2, 0xa1a6eb0e, 0x358d5def, 0xcb43cdfa, 0xa47e96a0, 0xc1f03350, + 0x5de30a4b, 0x445e9996, 0x118ebcf9, 0x8cc2d932, 0x5fc70ba5, 0x7e1868ca, 0xd2dcc663, 0xe60f2e4d, + 0xea4a12b8, 0x004b2cbb, 0xde83257d, 0x90abe8e6, 0xe3fd581d, 0x927eb2d1, 0x63189582, 0x4555c12e, + 0xde889804, 0x88231794, 0x9692846c, 0x4a5dc60b, 0x3a402b79, 0xbe5796b2, 0x50d5f69a, 0x2872a447, + 0xe960182b, 0xdce53e8b, 0x30550c5c, 0x42859b3c, 0xf2e16ad3, 0x9265f4da, 0xdcff1b5b, 0x7266bfa7, + 0x80c8ffc8, 0x7293c36f, 0xe42d7ca5, 0x3aa40eab, 0x90c34e16, 0xd5455e1b, 0x4c9b16fc, 0x4f6aaac6, + 0x56667747, 0x5859177b, 0xd8a680b6, 0x1b694260, 0xd7f2cfd9, 0x9de754fa, 0xd669740e, 0xf01a7177, + 0x8940893b, 0x240c3890, 0x0f01ff6c, 0xb6a1e86a, 0x48faea68, 0x4153a7f7, 0x80493d1c, 0xc582879a, + 0xdabce155, 0xe9e9d1b9, 0xe0543b80, 0x469f122c, 0xae5994bd, 0xd24017c0, 0xa14f8765, 0x2d48c24f, + 0x57b8e711, 0x9877b1b7, 0xc01b86b1, 0x01cc920e, 0x02d51a8f, 0x3faff404, 0xc9228ac3, 0x280e700a, + 0xc8775ea4, 0x345242b1, 0xe94db299, 0x4782dd34, 0xb0bfb662, 0x819e2ff2, 0x993bd767, 0xef09d98b, + 0xc5a6929e, 0xe0c58b8d, 0xf3048503, 0x141afece, 0xea65f0f5, 0x7870f519, 0x13acff58, 0x5585605b, + 0xdc60c2ea, 0x451b4e14, 0x72311631, 0xc8112c9f, 0xec34959e, 0x52da16eb, 0x7f1d7ccd, 0x1ea62e09, + 0x370066fe, 0x45172492, 0x37131b48, 0xb4b349e5, 0x85215898, 0x0a71c165, 0x0ae3f25c, 0x62b76836, + 0x15b0b622, 0x556176d5, 0x59e2b8b8, 0x743ba35e, 0x82cbe490, 0xfe53718c, 0x47a022e4, 0x733ba60a, + 0xa9d74a16, 0xcf69424b, 0xac3b86f1, 0xe8086247, 0x91a08631, 0x79108a89, 0x3f0dc5e7, 0x7e953bb8, + 0xcd84495d, 0x613dda85, 0xdc190a87, 0x01c7381d, 0xa71c9a40, 0x110fda32, 0x31fe570f, 0x666aca76, + 0x647a1681, 0x77fa7801, 0xfbce0d5e, 0xff4be210, 0x7366dedd, 0x5f7d52d9, 0x9fd457f5, 0x8e73fbb5, + 0xb0e37b3c, 0xe07beb0a, 0x8bbd71d5, 0x510326c0, 0x438f1fa0, 0x304fa300, 0x3ceb8442, 0xebf96d4a, + 0x81975a75, 0x0d79e030, 0x01556cb5, 0x6d36ebb2, 0x08db2c32, 0x81ffb716, 0x184ebe36, 0x4eb284a2, + 0x7a133aba, 0x5c9dc3fa, 0x14e06c6b, 0xc227b156, 0x712e2f26, 0x61d44666, 0x59d6db5f, 0xf511315d, + 0xbcc9423b, 0xe28bf90c, 0x74e82247, 0xefad563c, 0xc7d1252a, 0xe3ba1c5e, 0x92838acc, 0xe2bd31bb, + 0x402c832e, 0x1be66793, 0xa9853f01, 0xdeacc87d, 0x082bbce3, 0x13e91a08, 0xa8603486, 0x5a5c25cb, + 0x5868c58d, 0x9f5a7459, 0x636f1e21, 0xd8e26238, 0xf892e2e7, 0x66167c74, 0xc980e42d, 0x20e7a616, + 0xb698eb22, 0x47001354, 0xb6d8dc3d, 0x08179cbb, 0x9b30b6e2, 0xc7238596, 0xdb37d3a6, 0xcf500f05, + 0xb3e5e15d, 0x77e82309, 0x0130958c, 0x8da0571d, 0xf0ac61f3, 0x697659e5, 0x7acdc66b, 0x69f7218e, + 0xc032f4c4, 0xd55d8c9f, 0x8575c79f, 0x93ae6982, 0x3f5716a3, 0xed5ca8f2, 0x9932cd60, 0x0feeaacf, + 0x4c9cd791, 0xfc5d1ce8, 0x4d851f02, 0xea6f063b, 0x10b4c723, 0x4fbf3b36, 0xc6b50822, 0x44f643c4, + 0x5b1e29da, 0xe3aff3ea, 0xd012a4f2, 0xae761588, 0xc1715b4e, 0x3be14b07, 0x6a7b156c, 0xe982abc3, + 0x3d3d514b, 0x33856f10, 0x09a52338, 0xdfea2e1d, 0x1992f344, 0x82c1152a, 0x58d4c376, 0xf63c9ae1, + 0xd7b32daf, 0x9da55a0e, 0xf07f354b, 0xbec7731d, 0x3b701b78, 0x5cf4b3ca, 0x088b2eb7, 0x572e0d9d, + 0x4f034429, 0x5b2eddaf, 0x877584f6, 0x3cd1d83f, 0xe255bb26, 0x1dcb7da5, 0xb7ba48fb, 0x0fe4996a, + 0xc7485ab4, 0x03b01c3d, 0x15775461, 0x37783f39, 0xe9065ded, 0x4b10c3ed, 0x5826cd4b, 0x2c8af766, + 0x345e974e, 0x1a35432c, 0x6ecb0d8b, 0x34707698, 0x06b0107b, 0xe34edb4a, 0xa69ff7d4, 0xd26a7bfa, + 0xe629ede6, 0x4325e1d5, 0xda225eae, 0x0a84e1b2, 0xcc16e111, 0xec1f24ed, 0xe2b4d213, 0x3bfaf294, + 0x3528efdd, 0x2747080e, 0x717131fe, 0x84530f1e, 0x4312f4c0, 0xed7a6ec7, 0x006b74ed, 0xbda1408b, + 0xef3234a7, 0x64815cf4, 0xa5ff3e6d, 0x485c6229, 0x145b2ccb, 0xb57c5b73, 0xe0618db4, 0x5f243945, + 0xa1b80d9c, 0xd8df92e7, 0x8cee2b52, 0x95f7bedb, 0x939c41da, 0xb7f6e254, 0xead26298, 0x36404b67, + 0x7dd3598b, 0x97d77f40, 0x675deb26, 0xe4e38214, 0x1b7a5639, 0x06e4607a, 0x151404c8, 0x97aa4096, + 0x78c5bd15, 0x82789aa1, 0xd7919064, 0xa750a102, 0xe9233377, 0x241a0051, 0xfff5e26d, 0x9f6c3e91, + 0x3964ccb2, 0x2ef483d2, 0x67a7ed59, 0xc9c7c06d, 0x9b58cda1, 0xfb05421f, 0x03ffda9b, 0x906cd900, + 0x752063f4, 0x0d5dc56a, 0xcb10794b, 0x5f33c3b7, 0x6bc6d0e1, 0x30f06adc, 0x3f70164d, 0x46078f21, + 0x023b4959, 0xb3ce9e56, 0xb84579d4, 0x3676bcd2, 0x5e4efa5f, 0x8294d78a, 0xbac1ebab, 0xf2de1dfc, + 0x9eab47b8, 0xf5e817f8, 0x38e55732, 0x3e5c461d, 0x802712f6, 0xeb68be63, 0x1603a644, 0xb27b43c8, + 0x6b44bc26, 0x9169fbb7, 0x3989dae9, 0x5759b6ea, 0x3a8f7556, 0x0cd69d0c, 0x4ed5a371, 0x01d08c89, + 0x81e7f7ff, 0x72d670ca, 0x2def4154, 0x5959bb0b, 0x747e8016, 0x64c4fa95, 0xc92e67b5, 0xc96bcbf8, + 0x343777ed, 0x6d24e3ee, 0xffa6ccb2, 0x3947c410, 0x9ba9f167, 0x0c5bb3a2, 0x3c5b7121, 0xdfef1b86, + 0x29a70601, 0x7199b753, 0xb936975c, 0x2415c51b, 0x11ac2018, 0x1d46f56b, 0x3fe07c29, 0xdfb34813, + 0x9a3cf39e, 0x78147d6b, 0x3bcacda7, 0xaf3ce82a, 0x9c66af03, 0x984ed842, 0x9b8fcbb5, 0x8463affa, + 0xfdff3f4c, 0xed5a52ad, 0x326dc396, 0xcd719e8d, 0x21d6dd03, 0xe5a87f91, 0xb9ccc24a, 0x1772a318, + 0xe42a836c, 0x4100536b, 0xa8f11b75, 0xed429d1f, 0xb94d21ec, 0x20af1521, 0xd851c247, 0x0df5006a, + 0x21e67328, 0x03c23c25, 0x376cafde, 0x53f58a2c, 0x2c77f054, 0x4612bb1a, 0xdd19f0b0, 0xa0404afc, + 0xea068b0c, 0x93c295ae, 0xe7b27fbc, 0xcdf8e06f, 0x7af4854c, 0xb3128d3a, 0x7b5ce24b, 0x14f98518, + 0x9541ec2b, 0xa43b36df, 0x4d0095d2, 0x2143197e, 0x06343b2a, 0xff65582f, 0xb075027c, 0x16335f2a, + 0x1aa568f1, 0x1f3bbb5b, 0x7a198b05, 0xd1b082a8, 0x651c7c2a, 0x92b366f8, 0x25175807, 0x16d63ca7, + 0x40279e50, 0x801a27e0, 0x3701f707, 0xf9a37012, 0x73d4dbbb, 0x631aeac7, 0x7357ad4a, 0x72775b1f, + 0x2a04b582, 0x54d62bcb, 0xc97cbe2a, 0x4dcbb8f5, 0xe5b3c712, 0xe71d276a, 0xe4d39f2c, 0x9b8eb3c8, + 0xadb2f38b, 0xb6ace972, 0xc775a748, 0x95e55079, 0x9888084e, 0xc36d0882, 0x988dd6ab, 0x2b04c53a, + 0x5b38d0fc, 0xa2750775, 0xc1ebbdbb, 0xb60a9730, 0x306430cc, 0xcb17590f, 0xf56b9707, 0x0238785c, + 0xe9ef7d79, 0x506e96f1, 0x8cf81b4a, 0x91ccf2a4, 0xac23db0a, 0x17d11afa, 0x43e1ade4, 0x2e13ce99, + 0xe3bb7fb3, 0xcf9bf22b, 0xe7209855, 0xb972f4b4, 0x943d326a, 0x673bec75, 0x37dbb41e, 0xa7ba5f40, + 0xfafe0f65, 0x5cc42903, 0x8d444e16, 0x2ba33f7f, 0xf046d1d8, 0x41e28154, 0x5c8865b4, 0xc851b1e9, + 0x2480e60d, 0xcb5d0748, 0x6aa87d2b, 0xd2dd2bd4, 0x8471eb39, 0xa6a6c15f, 0x55abaeee, 0x0a03b1e5, + 0xa5e28576, 0x3ef6e299, 0x69d664da, 0x79d128bc, 0xa4a9f290, 0x5ebaafc6, 0x49536e4d, 0xe8e64ee3, + 0xd23604e5, 0xbf03b662, 0x737df88c, 0x03f1c73f, 0x0cf38cb9, 0x80f328fd, 0x58d38eae, 0x229bb0f8, + 0x959a0bdd, 0x94319830, 0x68a6d754, 0x9cd3b30d, 0xad486037, 0xb3ce4579, 0xe88cf776, 0x90d7c7cf, + 0x55730b9f, 0xf78eb43c, 0x9bb69e2d, 0x0109cd3b, 0x565162a1, 0x90e36a7a, 0x43a7726e, 0xb88d5784, + 0x820b097c, 0x38e227dd, 0xd153af85, 0x9d573f14, 0x260e6d17, 0x3df19927, 0x69e5d16d, 0xc1c90382, + 0x6e046550, 0x4e391dd5, 0x6343af0f, 0x4f2706ed, 0xfa3fa685, 0x77014ae2, 0xd00aabb6, 0xfc58ac1a, + 0xef028199, 0x7d7dacc3, 0x32a06d3f, 0x894b9f6f, 0x2d98f05c, 0x945de01e, 0x1c734ead, 0x13796b67, + 0x6b4652a4, 0x3f83b26e, 0x1603ec02, 0x5783921d, 0x78155cf5, 0x6274d466, 0x505835fd, 0x0c55967d, + 0x6b9886e4, 0x075d26d3, 0x9da32790, 0x50dd505c, 0x6e8b794b, 0x0cd2a383, 0x182eefe9, 0x2af0fe57, + 0xe720ae9b, 0x6423e469, 0x4764ccd2, 0xf9f592ed, 0x34b39232, 0xf367c578, 0x004eb4d2, 0xb22977fb, + 0x4481ebc5, 0x13974ec1, 0x86f6695e, 0xe06f5865, 0x6dd9698c, 0x08f18c6b, 0x72c1dd00, 0x3ed469f7, + 0xa4722d6c, 0xf5e9f4f6, 0x7f85ccb1, 0xdd296a35, 0x07504321, 0xb724bf2a, 0xbee5546b, 0x84e1d328, + 0x522bfd93, 0xd0d3f586, 0xd9be124f, 0xaea6f692, 0x5cfee9f4, 0xa0c86fea, 0xab4b2900, 0xc1e48319, + 0xe455bbdf, 0xcb0344c5, 0x19e01d5f, 0x6b2dd9af, 0x2b712c6e, 0x9139be63, 0x5a78ac8c, 0x81e641ac, + 0x5bd34871, 0x328340db, 0x241cbd3d, 0x56cf4a82, 0xa19abae3, 0xa1cc9877, 0x98c791d7, 0x5b5c4ac4, + 0xffc515dd, 0x786d8511, 0xdd9f2212, 0x92bac3ba, 0x1e8b6760, 0x2c4c862d, 0x3452705c, 0x2d491724, + 0xb2cd30eb, 0xb0ed4424, 0x7dc49750, 0x51cc1a34, 0x4ccad808, 0x2332d5a0, 0xcc36eb1e, 0xba79d004, + 0x848a9d3f, 0xf2d3aa33, 0xc4aebb71, 0x2dc4830b, 0x6626bf45, 0x0bc9e8e3, 0x292aa5cd, 0x4fb2dee7, + 0xdf032493, 0xa6528a6a, 0x01c55aad, 0x47053a76, 0x3811a9b1, 0xafc3731c, 0x0631d7b6, 0x88b89351, + 0xc96d62aa, 0x256fef60, 0x74992842, 0xc754f547, 0xe27697be, 0xb9b0ea19, 0x6ffd3731, 0x012f239a, + 0x2f8f5653, 0x1c2d1e82, 0x3dd6f673, 0xfe139da5, 0x6c9fb7e4, 0xc7f71227, 0x02269fb5, 0xaee980aa, + 0xaefe34c8, 0xedf5dd5f, 0xdd013f61, 0x656b260b, 0x06b70532, 0xecfc5eaa, 0x97c48989, 0xb14130ba, + 0x4cb2e10f, 0xdefa66a0, 0xab439eb0, 0x6268634c, 0x486c22e6, 0xb97d0ce1, 0x66730a57, 0xb87ff375, + 0x6c809540, 0xd91f554d, 0x3c0f50cf, 0x053315d3, 0x0a8d1edc, 0x271b7e7b, 0xb8341ae9, 0xb389efcf, + 0xa95224f6, 0x9d824c61, 0x55e01c16, 0x84e3b51a, 0x0ee6430e, 0x879b5d90, 0x0e4fb344, 0x0192aaeb, + 0x2766ee5d, 0xe87bd860, 0x26c09215, 0x9c2b6dd2, 0x2d2c73f7, 0x7df35954, 0x3b0be168, 0xc0e0d0bc, + 0xeee32406, 0xf1ef7d9e, 0x5731e0cc, 0xb3d60bf7, 0x5f81d593, 0xb0c2dbf5, 0xfbebd5e2, 0x1c22b2fe, + 0x7ed24035, 0xd407e170, 0x069bd1b5, 0x9efde276, 0xf3d0a2f1, 0x79783779, 0x302a11e2, 0x75591c40, + 0xc09e56c0, 0x1ce86ffe, 0x4e8152d5, 0x9c9a9552, 0xc94cf3a6, 0x42d6d5d6, 0xe8a1374a, 0xb5e703b9, + 0x77b53b1d, 0x2e48000d, 0x89241bc3, 0x6a63819b, 0x12057811, 0x0261b63e, 0x8c4a2c92, 0x72ff446b, + 0x7a8d0cdf, 0x1b040dbb, 0x525d71df, 0xab438119, 0x2c1cac46, 0x561460a3, 0xafcc97b8, 0x9c222f13, + 0x9c53c7b8, 0x1a28010b, 0x5df2d453, 0x0924f514, 0xee54e915, 0x4d1edebb, 0xe59b0fee, 0x10037612, + 0x21aa8f5b, 0xb3e81a7e, 0x8d6637e4, 0x4f1ad6de, 0x25313b73, 0x35b68fe0, 0xad9d5903, 0xd831c820, + 0xff1bef59, 0x72efb6f7, 0x369da6bd, 0xe9fb97f3, 0x663a11e1, 0x18d4e67b, 0x82eb9892, 0x3b60f0c2, + 0x140095f5, 0xbf66920a, 0x4a5a7aeb, 0x293eef1d, 0x191ee6f6, 0x4df3cd8c, 0x5c385724, 0x66b6c02d, + 0x252d2935, 0x914e5ca8, 0x22ad1552, 0xf570a1d6, 0x6098f444, 0xcd44c24f, 0x85131df5, 0xf01d71d5, + 0x77010ebf, 0xd0b32a2e, 0xa0ea5ac2, 0xe900be6a, 0xb31a8453, 0x76a49160, 0x9a9dfb20, 0xce923560, + 0x023f471f, 0x4c62c814, 0x0b096720, 0xe8990594, 0xeff1f5bf, 0x556680d5, 0x7d2f9b8a, 0xe77d1134, + 0x6a04eafb, 0xccb83119, 0x204a22ca, 0x01fbdc80, 0x0468bf26, 0x88d88b3f, 0x99f319d3, 0x5d79662b, + 0x1bdd5840, 0x908d3345, 0x7aa14183, 0x1b729aab, 0xc67742df, 0xf5688256, 0xc8bdeff7, 0x066effde, + 0x3c85c24c, 0x4f3fb226, 0xe05fa9d0, 0x028277cb, 0x7a6f47b2, 0xc2138dc1, 0x91df663a, 0x3a3e400f, + 0x788f0026, 0x8b68f45f, 0x6d3fb16b, 0x62d70244, 0x1a2f6b8d, 0xd3f4bff2, 0xc4e38534, 0x5b9efa1f, + 0x9f8096e6, 0x85eff6bf, 0x7fc838b8, 0xfb13bfc4, 0xc38f6e56, 0x1f112beb, 0x9b19eabf, 0x487b2589, + 0x487aa74d, 0x8b5f74a7, 0xa1f65c6a, 0x8071eb9c, 0xd9a5e537, 0xea5aa787, 0x2212fdac, 0x3ff396b7, + 0x601ec18a, 0xf099a1ee, 0x3954a49f, 0x5020ca63, 0x198a7b85, 0xf1831eb7, 0xafa8dd07, 0x03d89795, + 0x8e11228a, 0x2889778f, 0x46c3350e, 0x3314cfe5, 0x774202bd, 0x9c69c29f, 0x8b183f4f, 0xab657beb, + 0x72d35654, 0x9155ac7a, 0x303415b7, 0xc86fb0c3, 0x0513afc2, 0xfc967fb1, 0x2114fe5d, 0xc8cde4bf, + 0x6c9072fc, 0x5902cdd0, 0x30f7095a, 0x7c4f2b66, 0x39c9427c, 0x60af4378, 0x15bb3ca4, 0x6710031a, + 0xc902c6ab, 0xd90bc551, 0x93cb7fbf, 0x18a71f47, 0x1c4545d3, 0x040e488c, 0x8dbec9d3, 0x355e649c, + 0x93a62e0d, 0xc4e600d6, 0x33e8ed52, 0x448c95ac, 0x825d6877, 0x7cf2431e, 0x586bdb10, 0x5ab09a21, + 0x7251cd6f, 0x613d1303, 0x7cc04728, 0x6cd3e067, 0xbba49e81, 0x162670eb, 0x375d2604, 0x7ac1484a, + 0xc397b737, 0xe4ec1fcc, 0x4777ebe7, 0x829ca37d, 0xdef4092d, 0x77dc7b8f, 0xe8867ce2, 0x79eb94a6, + 0x27407249, 0x28e96f3d, 0x3eb1d019, 0x28bb86b7, 0xab9dab62, 0x76480f4d, 0xd647655e, 0xc0689193, + 0x07943ff9, 0x265ef6de, 0x5e685970, 0x43869cd1, 0xfb65bc10, 0x80b63f82, 0xb497d2a4, 0x8a002e60, + 0x5d98c2f4, 0x052fbb3f, 0xc2d397f3, 0xe8bd991b, 0x8553f36d, 0x732f05fe, 0xca64bac5, 0x091d42da, + 0xe0264ece, 0x1b202b6d, 0x07f5e81e, 0x9c61a007, 0xf2be6e54, 0x787d0a3b, 0x08764692, 0x34cb0d50, + 0x36567fb8, 0x514b1706, 0x730562d0, 0x863687e1, 0x5f004bca, 0xd41e4c33, 0x4fa21990, 0x61276bf8, + 0xdd7914cd, 0x90624989, 0x8414ce6f, 0x2dbbe0db, 0x613c4431, 0x2316cc99, 0x0f1fd408, 0xb31da8e6, + 0x4cc2c914, 0x2a188040, 0x5a41e8b6, 0xdbb7ebe0, 0x3583b179, 0x0c2e0849, 0xddc66c34, 0x46754cd5, + 0x85c75273, 0x07b2f243, 0x49eb6e06, 0x3de99be2, 0x6d7f2513, 0x9c0a80f1, 0x0e3b422e, 0xa9888de2, + 0x2ed1b273, 0xe4d04ceb, 0xe996aa25, 0x4bd00cac, 0xdf9d585a, 0x2e13becb, 0xa12082c1, 0x25671b0b, + 0x80fbacbd, 0x19fb2f8c, 0xfd93ebcd, 0xeaf77a7d, 0xa0904ec3, 0xa20f4151, 0x5aaf6302, 0x830f0f53, + 0xa230d650, 0x5cacea89, 0x130e2a3b, 0x48d335fe, 0xedc2da75, 0xbf90c329, 0x1e576ab7, 0x2baaf5b3, + 0x01da6ef7, 0x4feb7532, 0x43f6462d, 0x6367cf07, 0xd7cd8962, 0x1c00b6a5, 0xb53e679b, 0x46f00765, + 0xac9ad1a9, 0x170009dc, 0x0d250651, 0x238a740f, 0x866b6600, 0x3a492af9, 0x0f71ec2b, 0x81bae836, + 0x8c20abe0, 0x864723a4, 0x3bf682a9, 0x0373066e, 0xbc00429a, 0xe7380e49, 0xe09b602d, 0xb9ac1c8a, + 0x7acc274e, 0x812b4552, 0x0fea9786, 0xb8943b92, 0x1bd1bf40, 0x9b6e0963, 0x5c8bcda4, 0x98372ce2, + 0x8004821d, 0xfafcb43f, 0xc51b6dc1, 0x6ea6b856, 0xa7e08c96, 0x2d07f87c, 0xbe74cb89, 0x7a1b5125, + 0xa1e81c16, 0x8c47cea1, 0xf8191896, 0xf9df3e4d, 0x1f8d87d9, 0x6b845987, 0x01372194, 0x8fd1b28c, + 0x822ea3a1, 0xd9d44938, 0xb89a5a6c, 0x5ec7484e, 0x09fe8a06, 0xdb30d51e, 0x0c343b96, 0xa6e13a0b, + 0x73052909, 0x59aa07eb, 0x39eb7044, 0x44e1a240, 0x109ff0ae, 0xd23ef565, 0xd2dfbde0, 0xd0e67ea8, + 0x93a188bf, 0xe5318925, 0xf93afcc4, 0x6ad28d03, 0xac91e85b, 0xf94f2c61, 0xb162e9bd, 0x1cd1dfa4, + 0x6f43885b, 0xfeccc40e, 0xa9ec6fb8, 0x30667528, 0xcb2b5a1f, 0xf2490ef3, 0x1bc9e3db, 0x149c2bc1, + 0x9b42adae, 0xb4ad18b7, 0x9fa7904f, 0x3bd2c5fc, 0x1c2341c4, 0xeff4eb97, 0x01bd7121, 0xb835455e, + 0x69933dd6, 0x112ca872, 0x384ae5f6, 0x128091f3, 0xbb8f9081, 0x3fe3f1f8, 0xfd7088a1, 0x1c9e55cb, + 0x0203d221, 0xfdc51959, 0xa9862f67, 0x4cb62dd1, 0xd2cf920a, 0x3113c9ac, 0x1ac23f4f, 0xc2a945e0, + 0x433f0b5b, 0xb13b36bb, 0x62fc2614, 0x8fb2e73d, 0x1d863a34, 0xe56c90cb, 0xf7f1bf1c, 0xdc84e4b1, + 0xa3368eab, 0x12c22da9, 0x4ec3f370, 0x201f81a7, 0x08d29595, 0x4f7458af, 0xd1a6ad46, 0xde598224, + 0xf93ddc6e, 0x5d1b597d, 0xd08af7d5, 0x36c62064, 0x91f7fe98, 0xf759dde0, 0x0d3439a3, 0x48dcf7e0, + 0x36afa196, 0x40505e5f, 0x1ae94f7a, 0xe61264b4, 0x9f349c24, 0xc512fbf1, 0xf060a993, 0x7801c580, + 0xc6cb322e, 0x9be4ac77, 0x01f2d38b, 0xd9d03730, 0x077271d0, 0xe539a323, 0xde3d90d5, 0xddbce04d, + 0x06d924ea, 0x245f3748, 0x1fd613a2, 0xb0f1e839, 0x6414dd21, 0xfeb200dc, 0x0ea6d4bf, 0x5d4944b0, + 0x2b1f9272, 0xf2313455, 0x7e2b4d35, 0xefed62af, 0x9d641f4b, 0x83780084, 0xd993dbf4, 0xf4d1a9df, + 0x59213448, 0x233f9521, 0x37823032, 0x73bd1945, 0x1f24c29b, 0x24969d82, 0xbfddb3f4, 0x3429e3bf, + 0xbd23acc0, 0xadbe2055, 0x220647e8, 0xb048df99, 0xdbdb842c, 0xb67c720a, 0x754bee93, 0x5054d849, + 0x702a57ee, 0x0cc1cef7, 0x6beadfa6, 0x14c0a59f, 0x9d91b767, 0xf6ebbaeb, 0xd76332a7, 0xab740166, + 0xb4a989e9, 0x3ae93c45, 0x4f731358, 0x0895956c, 0xbb8eada3, 0x272090fc, 0xd8021ea7, 0x23cbb7b1, + 0xcc451f76, 0x0aa9d20e, 0x82e1ecc4, 0xde22d608, 0x17ad350f, 0xfb89e5a8, 0x1c0b9589, 0x7ae97cbe, + 0x85eb9280, 0x40ef0d04, 0x138ae8dc, 0xad2f5000, 0xce9c9819, 0x2434a9af, 0x7fd95d9a, 0xe33cfaf7, + 0x470920f4, 0xee250988, 0xf81aae52, 0xf23dd5d7, 0x98197ec5, 0x7c9bbff6, 0x4afcd53a, 0x709583a3, + 0x13f4982d, 0x082aa5b1, 0x15965541, 0xa06c0ab3, 0x888ff9e7, 0x22e17278, 0xc53f7037, 0x2e69301d, + 0x83f0cde1, 0x883d1627, 0xc514178a, 0x17b9f814, 0xbc2c0890, 0x14d0c8ca, 0x6732893e, 0x5e1e6d6c, + 0x77c6e951, 0xeacb17f0, 0x9b754b93, 0xd9fed7e0, 0xd68a8e86, 0x00409673, 0x3f209dcb, 0xd55a92b9, + 0x177f8f11, 0x9a55ca91, 0xd630c59a, 0x1a4ba0c9, 0xd6ae9003, 0x985b1a13, 0x88b0e1ba, 0x111b370c, + 0xec559c17, 0x4b83af1f, 0x35691944, 0xed9d204d, 0x6eb5e229, 0x533a99d7, 0x88299607, 0x42734038, + 0xf74142bf, 0x1ad5f7ad, 0xf734af2e, 0x62e8be6e, 0x80f4105e, 0x0163f89b, 0x87543576, 0x1663a135, + 0x90ef5d9f, 0x4409a7e6, 0x2bc12b84, 0xa9ffc24e, 0x6c64dba4, 0x0838ff19, 0x1c7db3c3, 0x8ed449dd, + 0x377366a9, 0xd35ce4c5, 0xf3bb714c, 0x6e60bc64, 0x0fa93a29, 0xc5bb8336, 0x57e3e6bb, 0x472cc4b0, + 0x43e940ee, 0xc07c0ad6, 0xfe70df9b, 0xe418fa8f, 0x0c962a88, 0x91f8fb07, 0x789f7c78, 0x6e3bfff4, + 0x50a4c4d5, 0x643538cf, 0x3365613f, 0xcf1ac2ce, 0xefadcc98, 0xdac24fac, 0x582e637c, 0xab582060, + 0x61ec77b0, 0x8190ee7f, 0x8095b05a, 0x46201256, 0x85eb9b08, 0x346e1ed2, 0xed771835, 0x68cd30ce, + 0xd316206c, 0xc01ceb92, 0xdc8b7d67, 0x1334fb76, 0xf862680d, 0x5441335c, 0x24cb536b, 0x4d6473af, + 0x62430d71, 0xb395a00b, 0x645bbdff, 0xb3763f3f, 0x8d7b8c76, 0x04da58c8, 0xe3caa402, 0x49cb3013, + 0xbe20541c, 0x2d76ce00, 0x96b725ae, 0x2003260f, 0xe6de2472, 0x7e37e6c4, 0xb3c51279, 0xcbbed7dd, + 0xdf2c84bf, 0xfe8908b8, 0x7e3cbdcf, 0x9b685e5f, 0xf0b3b5b6, 0x96559cf2, 0x67efb537, 0xa249b2b1, + 0xf6788a3b, 0x582f4092, 0x4e1ab7af, 0xea328743, 0x234020db, 0x36e48ccb, 0x199b13f3, 0x054472b5, + 0x47b893ed, 0x542abda9, 0x87c96fb4, 0x07523ff8, 0x7f20619b, 0xad0773cf, 0xad37f85b, 0xd78abde6, + 0x73d7ead1, 0xed9ed2a7, 0x5980f3a7, 0x0f4e16d5, 0x08290beb, 0xd5f15c88, 0x4caabb73, 0xc3515628, + 0xbdc8471f, 0x7fbdeb11, 0x40bc92da, 0xb184aea3, 0xd4aaffa8, 0xd106b033, 0xe8524522, 0x6725f88b, + 0x152aef22, 0x757da1a7, 0x15876c6d, 0x7d2413ac, 0x12e1471c, 0x0074696c, 0xecffac5c, 0xf2f65c63, + 0xf26f39a4, 0x7b9d3c79, 0xd04a68af, 0xfe3dec3f, 0x284566b9, 0x3c48534f, 0x4798301f, 0xc08802ac, + 0xfc36b735, 0x209aff6f, 0x8e76344b, 0xd1a84597, 0x0e75c983, 0x8f7a2f97, 0x2e8c747b, 0xe50d0689, + 0x469d0614, 0x22374dbe, 0x822c3cc5, 0x547b2568, 0x40202064, 0x6208f9dd, 0x30e23516, 0xe6efd8de, + 0xa4cb421a, 0x01e7e509, 0xeefb2dd9, 0xd07eefc6, 0x5a5fe98a, 0x09a245f6, 0xb2f68bcd, 0x65d30255, + 0xdda8a2a9, 0xef97a925, 0xf2270a5d, 0x484dd729, 0x79020fde, 0xde8725b7, 0xf9ac7d86, 0x2fdb457a, + 0x76984d3f, 0x4a53df25, 0xb4bf36aa, 0x3cbe3148, 0x5e58e96f, 0x6f970914, 0x3fbdb09c, 0x5c79b318, + 0x985fee56, 0xc0ae0006, 0x43bbe8b4, 0xc8c3411f, 0x435390bb, 0x65078299, 0x07bf6410, 0x8e5128e8, + 0xb3b8f48a, 0xebc029fb, 0x8e8a5317, 0x04313299, 0xff885440, 0xcaf17b33, 0x28a47294, 0x40c09b16, + 0xffdb2f1a, 0xc345f3f8, 0xc94253f4, 0x5d70c767, 0xbbc85321, 0xb224ce2c, 0x26e811a5, 0x0b2a7bd0, + 0xb74efc26, 0xce800f3f, 0x16193e7a, 0xe54763bb, 0x16cbd8a8, 0xdd977709, 0x7b72d086, 0x3b1203d4, + 0xf68bf531, 0x9da2d2b2, 0x972825f4, 0xe9e00e22, 0xe83a0097, 0x68f70130, 0xc94fb63f, 0xe0280873, + 0x16954e0b, 0x0f0e9720, 0x0004677b, 0xf4380f47, 0x2339dc81, 0x609b6cfa, 0x9c11f639, 0x757c89ae, + 0x41d5f06b, 0xf43ad509, 0x5b9b5261, 0x7bc6630b, 0x43d25e7d, 0xa5bb5b30, 0x317e41ce, 0x4ed71a20, + 0x0f960e36, 0x2cd9d60a, 0xa6555525, 0xd434d8f8, 0xf863a221, 0x5f172100, 0x25fef831, 0xd57e9a9e, + 0xf7747eb6, 0xa14102ed, 0x01ea82cf, 0x8ef1ca26, 0x5f1a80ab, 0xc41a3466, 0x3bc78c70, 0xf2a7aadb, + 0xe58e71c3, 0x990483e3, 0xd8bf1a24, 0xa33cc58a, 0x187c75dc, 0x553e6f67, 0xb8dc7454, 0x19b3d8dd, + 0xd36de6e7, 0xa571fe81, 0x83acc14e, 0x9a8df3cf, 0xec4d51ec, 0xdb313188, 0xfd9839c6, 0xe841e6ca, + 0x268174d1, 0xa1eadda7, 0x5a206bd3, 0x556ac560, 0x70d05873, 0x2664cffd, 0x1a75817d, 0xc14b9670, + 0xd09ee605, 0x73dc5707, 0xa507a7e4, 0xe5424e80, 0xfe3e9a3e, 0xd21566ad, 0x326c0ec6, 0xb952df72, + 0x013042e3, 0x7da737ac, 0x1bf37b5d, 0xc4553b4c, 0xc2e7a7ad, 0x7052a96b, 0xc1fe777f, 0xeb70c5f1, + 0x0a9e9d53, 0x8871fdd3, 0xe89db655, 0x512d5a09, 0xad2e5edd, 0x7df9accd, 0xb37e5b3b, 0x9473ce86, + 0x29b19ada, 0x5c035530, 0x29392a27, 0x072fb1b9, 0x2c8de49c, 0xd324a826, 0xcf080ffe, 0x3f1b89ef, + 0x4547b2a4, 0xaf63f3de, 0x9f34178e, 0xba80dbc7, 0x58f880b2, 0x2aceb9d4, 0x6abe5e8d, 0xe9f95ac0, + 0x3825b914, 0xc78084fc, 0x724677c7, 0x3c99e585, 0xbd87edbb, 0xd245fc4e, 0xf32e74a3, 0xadca1d7e, + 0x92176876, 0x61e698c0, 0xa25d37ee, 0x6fef202a, 0x74bdb662, 0xa605e9df, 0x71be46bf, 0x4dd024c9, + 0x50ce6e19, 0xcd4286f4, 0x3919c4a8, 0xcebf2fa1, 0x3edc35b0, 0x0cef5eb1, 0x9397f2f9, 0xfe58a8d0, + 0xd494f0cb, 0xa1bbc232, 0x61154006, 0x3e4bea87, 0x5cbbeca7, 0x3a2fa097, 0x0f5581e5, 0xfa695163, + 0xbe3cd9f1, 0xc70d22d5, 0xac90cf27, 0x606b11d8, 0xea3c484c, 0x12a33af6, 0xa63e095b, 0xe8198698, + 0x3c7c93db, 0xa34b6e7b, 0xd4581f41, 0xd72e87f6, 0xa98b4ae2, 0x4d3b8d1e, 0xb940fd87, 0xc0f6be04, + 0x412d816e, 0x8e2783fd, 0x026b2531, 0xd48fd043, 0xec452f4d, 0x944bbbca, 0x413cdc66, 0xf5665fa8, + 0x99b2f775, 0x0eecfd6c, 0x879cdbe8, 0x1a658217, 0x8d0d1b91, 0x248881f4, 0x57d2be1d, 0xf9068f50, + 0x02e596f3, 0x4118b79c, 0xb8f84754, 0x09dfa92f, 0x5854ffe1, 0x585f13e5, 0x08964366, 0x5810161b, + 0xacfe8d8a, 0x70f948a4, 0xc841d697, 0x4ae50466, 0x135902dc, 0x2c5b0697, 0xbe8f2393, 0x4d2eebec, + 0xae96c24c, 0xd87133bd, 0x2388cc86, 0xe9adba58, 0x4f321f4c, 0xbd35bbf8, 0x487c9f51, 0x0d357343, + 0x6a02ba77, 0x2525c463, 0x8aa4d4d7, 0x751cb57b, 0xef44b215, 0x8340e9d0, 0x4a0e9760, 0x231ea7d4, + 0xb3daf068, 0x14098cc5, 0xbfbf1c98, 0x04e84b92, 0x689d5415, 0x3e7c1245, 0x345efb38, 0x1e566a4a, + 0xd7586eee, 0xd2125684, 0x454a1ab5, 0x1d065d9a, 0x32ac59fb, 0x02f76dd3, 0xa38fb905, 0x2de2d1c1, + 0x754e5cc6, 0x4c49c74c, 0x719d8245, 0xb3ec4a62, 0x40354679, 0x641d68e4, 0x2da80654, 0x87e8a30c, + 0x6853dab2, 0xcfa08a39, 0x88f221a9, 0x354049b0, 0xc84bdf17, 0x66d56444, 0x9cf05b64, 0x734afdc0, + 0xa1a5dae6, 0xe55d4e3e, 0xa4425a51, 0x9fc5a4cd, 0x9b628a63, 0x79ae034d, 0x6c5b41b5, 0xe03e6d77, + 0xaf553555, 0xae776cf9, 0x0cd7e2a2, 0x53d8ac09, 0xf62df02c, 0x14eb2fe1, 0x9605f5a9, 0x87511df2, + 0xf1ad3d54, 0x1f701764, 0x6994fd00, 0x8476d696, 0x4d3b4f88, 0xc2da9364, 0x59646550, 0xa5ab9755, + 0x1852fb58, 0x5499281d, 0x4822d7c7, 0x586d4d18, 0xa7a3036f, 0xc230b48b, 0xeb4cd529, 0x57a75706, + 0x865b68f7, 0xe6ad9f5a, 0x06d9eb3b, 0x54d56085, 0x6a2ac37c, 0x3bd341fb, 0x445391fc, 0x24ae059b, + 0xf546320b, 0x50743daf, 0x02b21a73, 0x859f534d, 0xfb4dd2f1, 0x7e6e7c51, 0x0489ad7f, 0x5893831d, + 0xdec83264, 0xc5a5a675, 0x020dbc49, 0x0b50d312, 0x266b2cc2, 0x332b3433, 0xa427cd0c, 0xd3ca235e, + 0xfd00e3e2, 0x1018160b, 0x2bf74168, 0x3a22f67f, 0xeefde4cb, 0x77ce49fb, 0x69fe60e5, 0xbe1bd5c5, + 0xe763caea, 0xce4bf7f0, 0xc0ff9a46, 0xb26929d0, 0x972f17c7, 0xff519eba, 0xca01c0f7, 0x9dd50a17, + 0xd66cff25, 0xb587a0b0, 0x5c76f853, 0xc603eb65, 0x698eabb7, 0x80463d7f, 0xe2ce93e4, 0x00721bf9, + 0x7f824863, 0xa1d87b39, 0x3c5b1d8a, 0xc8dafb77, 0x565199f6, 0xe2af511d, 0x1f436037, 0xd0eea032, + 0x3285b17e, 0x1a86fca8, 0xd0570541, 0xcd0ad2ca, 0x1146e451, 0xe9f99666, 0x63c4d333, 0xa95a9cf2, + 0x601d8c2c, 0x6b7493da, 0x80d65900, 0xbc137a9b, 0x22d46025, 0xb04cb339, 0x6f7753b4, 0x8a9cd8c1, + 0x67c2e998, 0xc0ef4b5e, 0x6187dc07, 0x76da5958, 0xbf4f5230, 0x578de734, 0x786a3322, 0x4242cb8c, + 0x5719dd74, 0xf6f05f59, 0x9b01d65f, 0xae7cae5b, 0x676735fd, 0x9c13133b, 0xd0c17359, 0xedbc20f0, + 0x13d08b17, 0x94550fc9, 0xaf062d9b, 0x77d56364, 0xd394f2a2, 0x3c609cee, 0x0fba0926, 0xac819867, + 0xd40f44ae, 0x970cee15, 0x95c112b5, 0x2621ac21, 0xcb4a96e3, 0x81ef140e, 0xe9c40fbc, 0x0766fbeb, + 0xb160d471, 0xa9538602, 0xe173b8ae, 0xbf0c2eb2, 0x0768f81b, 0x74a2c858, 0x842b3d7f, 0x88bdea92, + 0xcf444410, 0x1494dbce, 0xb2281476, 0xa5666cbd, 0x7386dafe, 0x962e0e0b, 0xd15538cb, 0x072ab3bc, + 0x37d585a2, 0x16428d50, 0x79322e48, 0x6cc8078a, 0xdaa3b510, 0x670dc695, 0x2fadddd9, 0x18470479, + 0x1de85dad, 0x45d5f1ff, 0xbd52a667, 0x9136ef15, 0xd3aa64fb, 0x0d63e161, 0x0b2837c0, 0x3409d5d0, + 0x677b3aa9, 0xd2302462, 0x2364c2ae, 0x02e77bfb, 0xbd851b71, 0x5bdfcc88, 0x5cc3668e, 0xa8788cb9, + 0x7157987c, 0x1186cb56, 0x4d68036f, 0xe1f9e686, 0x2254e28c, 0x0fd325b8, 0xb1f76fe8, 0xbb204730, + 0x7f2673fd, 0x480136a4, 0x62e13a60, 0xa3ed2f22, 0x627f3290, 0x87b1fee5, 0x85a26a3b, 0x796865e6, + 0x6c14abda, 0x28fda00b, 0x66df99c6, 0xf62716af, 0x30833bf7, 0x5128706c, 0x3b42095f, 0x1c642419, + 0xabf4888a, 0x82c8b499, 0xfb909dd8, 0x78b184d0, 0x8d32d43e, 0xe36c0e9b, 0x973bf220, 0x3c368a79, + 0x36c4cd85, 0xc0e27cfa, 0x5b35b228, 0xdad90134, 0x0ac525ee, 0xae12ce45, 0x0b8ff109, 0x18d526bb, + 0x1415d4e2, 0x573ea093, 0x6e2a2870, 0x5917a023, 0x30b1e18c, 0x9465082a, 0x8669a5ce, 0x2615ee68, + 0x5d367f97, 0x9dbbec81, 0x9084ab3d, 0x333c2741, 0xea7a7b2e, 0x2a9031bf, 0xa843e893, 0x0440e3f7, + 0x1c025b1a, 0x9a36c354, 0xc7f31d3a, 0x0ad72d03, 0x75a548c5, 0xf9aa9a5f, 0xf0d3ebf5, 0x00917d95, + 0x5e54cf18, 0x521533c5, 0x59d8bc15, 0x037625fa, 0xe16c715f, 0x57a16b54, 0x1f2822f1, 0x0b04c765, + 0x89e0c90b, 0x2fed4dfa, 0x7f025bba, 0x689b36c1, 0x8b3ab56f, 0xdcce8b17, 0xa4bc96db, 0xaeba3bc5, + 0x7c58a9f2, 0x59400031, 0x8fc0bed1, 0xd71bd673, 0xe5f85228, 0xde56cb84, 0x7413324b, 0x8db8bffc, + 0x368d82f9, 0x80b751c0, 0x458fbccc, 0x776e5d7e, 0x83d88ef2, 0x6755a475, 0xc39bbbd1, 0xd691206d, + 0x7ba4cfe1, 0x3d1863e6, 0x325e3d91, 0x08c53f4f, 0x08aa511b, 0xfeb605fc, 0xefda511e, 0x38b9f16f, + 0xe5cd4400, 0xa098c3bb, 0xd57c48ec, 0x7748a4a2, 0x4f546d97, 0x29b2076c, 0x685f7989, 0xab3b27e7, + 0xfac408a2, 0x282d0bee, 0x9109d51e, 0x38bf46e7, 0xb3fafac4, 0x8d0870fb, 0xa56affae, 0x3db086f8, + 0x3a240bf1, 0x32aae449, 0x1b49a6e8, 0x8536c49c, 0x25425111, 0xe68b7901, 0x04397616, 0xf8f1ff44, + 0x9504d3c9, 0x5dfaea9f, 0x193b229c, 0x8db5ae22, 0xbb8753a7, 0x0f9c68c8, 0x28907257, 0x30225ae0, + 0x342bf3b8, 0x6a0c0343, 0x9786ecdb, 0x1ae942d7, 0x03063145, 0x418fdc09, 0x2c961ef0, 0x6d5b5037, + 0x82d450e7, 0x093f1fff, 0x46102fa0, 0x2da91eaf, 0x6a842a96, 0x2612f7b4, 0xe38441e7, 0x08fdd109, + 0x4f538b8d, 0xa32d8234, 0xeea82198, 0x732ebf4e, 0xa58aebd7, 0x2194f70c, 0x49522ba0, 0xbc4fe390, + 0x7c011ad3, 0xbcd28b78, 0x2fc5121a, 0xbc4755ad, 0x7b256c1d, 0x6fbce77e, 0x1d937f72, 0xbf73500b, + 0xb1156a0a, 0x3e5f3623, 0x54fb1b79, 0x0d8ec47b, 0x256bcfac, 0x35c2332e, 0x1374f539, 0xd8a27fab, + 0xf4048d58, 0x683ec71d, 0xff0a607f, 0x672a3812, 0xbe0f302e, 0x4cb28ba5, 0x3fcf115d, 0xaa308807, + 0x30674c8f, 0x4352bca5, 0xb714df27, 0x99eed19e, 0xfea4993b, 0xcacd64e4, 0xe7c3ee9a, 0xd1ad864a, + 0x6fbf6a03, 0xdfc0df87, 0xec395a3f, 0xc8e3f0ec, 0x6d43ecdf, 0xdecd2d04, 0xc9804171, 0x6d30841f, + 0xe1c6addb, 0x5f71f2ff, 0xc50dcd1e, 0x4c4fe614, 0x62dd3953, 0x451a6ea2, 0x7340e6e8, 0x3b68a378, + 0xd60479d8, 0x72cf531d, 0xa6bf45b3, 0x90f6869a, 0x67d7eaba, 0xf287ec7f, 0xc6687081, 0x52a66811, + 0x95ebeab7, 0x407666ce, 0xc2d5d2ca, 0x17dcf70b, 0xa8bcbcb6, 0x50451174, 0xcf354a93, 0x62f46393, + 0xfd60ecf8, 0x2422c3f0, 0xc9130eec, 0xa74f0488, 0x05d6bbd8, 0x63100b38, 0x85b07270, 0x1969c6fa, + 0x95e91130, 0x688a3f89, 0x0aa442f8, 0xe8f83edc, 0x7f256d20, 0xee9f2dba, 0x96854b52, 0xf3132209, + 0xc3e8ec5b, 0x8e80a0af, 0xee4e38aa, 0x4ac12302, 0xe22aba85, 0xcf78d556, 0x93659ba9, 0x05bc60ba, + 0x1155e9b4, 0x091b3742, 0xdd6abbce, 0x51712d5f, 0xe0eeebe4, 0x65f33bb6, 0xc6a35845, 0x7c14a3e0, + 0x278043cb, 0x4c98a92a, 0x58de67a3, 0x4b70184f, 0x61bb5859, 0x66c0c3a8, 0x657e9ecc, 0x10bfd153, + 0xbdafdf2a, 0x6469ca49, 0x70b56343, 0x8dc0ea09, 0x874ae799, 0xd5078de8, 0x017cffe9, 0x8b10ce95, + 0xe55aa4eb, 0x580359a1, 0xa0fb8147, 0x3f636335, 0xb65c610d, 0x77c46159, 0x48e2467f, 0x7e6a8d04, + 0xeb10d889, 0xa04e7d1c, 0x9c18bc62, 0x16bf8259, 0x023a6e1f, 0xfbca8e9d, 0xee5060c6, 0xc424f730, + 0x9ae21e6e, 0xc3ebfa2c, 0x8a3592f7, 0xb9528466, 0xee125c68, 0xda056c15, 0x871f2962, 0x0d7c2289, + 0x12737d84, 0xfa92e14e, 0xeac9fedd, 0x1d71bc3c, 0x830a93f7, 0x54a1c861, 0xdb250fc5, 0xeb42bcd8, + 0xbb87328f, 0x0144bbda, 0x646950bd, 0x931cf65a, 0x491ee00e, 0x1f9470f7, 0xf9b6baad, 0xe9f55a42, + 0x9f3b3c0e, 0x17341c4c, 0xbc9c4bc3, 0xf720e8df, 0xa6327b53, 0xa9ce743f, 0xf9d16259, 0x547c0e7d, + 0xec59b6b3, 0x497f3113, 0x6f0c032e, 0x17c296c0, 0x62d1ca7c, 0x213039b1, 0x8e641e9e, 0xdff2e4fa, + 0x045d595a, 0xb54d35f0, 0x8fcce3e8, 0xccf1b219, 0x19925079, 0x543b681d, 0x8ae4b643, 0x37a9a92c, + 0x64713890, 0x445a0024, 0x3ac60e9e, 0xf41f9244, 0x2da639d1, 0x25df0075, 0x94aa5574, 0xb249eb6f, + 0xa94bc56c, 0x0f63c0d8, 0x05e8f722, 0xd1a8cb99, 0xeba061a0, 0xe4cca5eb, 0x086028ba, 0x0138e3e6, + 0xe19a977e, 0x46c3b803, 0xb8dc6423, 0x8da18f61, 0xfa97d142, 0x88332b4d, 0x71bc9651, 0x478d092b, + 0xe6050291, 0x743ad7de, 0x3c9c4c81, 0x8b43dbcd, 0x14cdca37, 0xa9993dcc, 0x52ab24d7, 0x02017282, + 0xaa8801d3, 0x86278703, 0x31d746a7, 0xa14acae0, 0x72c1720b, 0x48132ca1, 0xecad8d42, 0x6fb9a022, + 0x363e6d36, 0xa85bb3ed, 0xdd91840b, 0xbc7e3a1d, 0xfe9b2e0b, 0x5e9c59ce, 0x094d492f, 0xa70f0a38, + 0x9548e612, 0x737d840e, 0xdce2be6b, 0xad1233d4, 0xfa0a9ee6, 0x891b0b7f, 0x31dc9168, 0xfc1bee22, + 0xb6eb58d6, 0x34da04c8, 0xc179f989, 0x4cd9cfbc, 0xcbb9e9e5, 0x92806c8c, 0x1087f55d, 0x3350ac8b, + 0xedf5fbac, 0xc0e45a65, 0x99bc2010, 0x10891f19, 0x0274d6eb, 0x441961ed, 0x5d156495, 0xd3265cab, + 0x19c4d86b, 0xe3a738ef, 0xd3e64ff5, 0x59aac957, 0xaaa49143, 0x508298f7, 0x37d795c5, 0xb5288de3, + 0xd7cc1f1f, 0x98b0f068, 0xecb47326, 0x20c17a51, 0x0aa9f5c8, 0x628c8b30, 0x45471653, 0xafa9d8bb, + 0x26dfa3fc, 0x26e0cb2b, 0x51f9fe31, 0xe4324718, 0x31af952b, 0x994e6f90, 0x86d00386, 0xe65c7761, + 0xb055294e, 0xa2ce1a0d, 0x4bbaf033, 0xc87e9627, 0xf97208ae, 0x2863607f, 0x936d5424, 0x5fe3ea1e, + 0xc0db3a97, 0xd8db2795, 0x90b201ab, 0x417f31f1, 0xd04ee00d, 0x8e2523ca, 0xdeab9a57, 0x6fb78b38, + 0x97e4eda5, 0x56da6e61, 0xaf808eb0, 0x56a3f3c5, 0x7b455652, 0xbc8290d0, 0x5e521f05, 0xcbd399e7, + 0x6d89f5cd, 0x19044e5e, 0x00ff7d11, 0x872fa911, 0xd962fb00, 0x2459acbd, 0x92b36421, 0xeedf60fa, + 0xc681cc41, 0x57cc13af, 0x3fd81792, 0x193cd1fd, 0xcfba51cc, 0xcde9fc3c, 0xfa45f424, 0x821c8a62, + 0xbe268ec8, 0xd043d57b, 0x68a44c51, 0xf52887de, 0x3894b45d, 0x7e8810de, 0xdec5a6ac, 0xb01573f6, + 0xb65540f7, 0xe18c564f, 0xaeae364a, 0x913e9619, 0x98a55675, 0x059e4944, 0x3b08f72f, 0xe7b9c233, + 0xed07f824, 0x31936a8b, 0x366c32ce, 0xf726b61b, 0xc9bc0452, 0x0f920719, 0x3aa85df9, 0x3389ff9d, + 0xf41ca564, 0x0ac04553, 0x43e9951e, 0x2e3c1224, 0xa7129cce, 0xa4531882, 0x068de28b, 0xd41f341b, + 0xa486e555, 0x717f90ed, 0xda60fa40, 0x55f83170, 0x2c6a85be, 0x797ad433, 0x3d11856c, 0xbbe28158, + 0x965bffcd, 0x65791c95, 0x81762a47, 0xc7bef45d, 0xe96ec0bf, 0x428b10d2, 0x29fd5500, 0x29768c26, + 0x95566e02, 0x3214470e, 0x3a6bba6a, 0xb2c9c7d3, 0xe6626580, 0x51a81ab5, 0x07fa2637, 0xfc6f724a, + 0x74b89414, 0x96f0dc51, 0x38c66c85, 0x52db805e, 0x13d984a7, 0x0c8f7d61, 0x6acead5e, 0xfb215109, + 0xbb4c228f, 0xd361dede, 0xab444eef, 0xa5a83881, 0xc98636a3, 0x2bee39a1, 0x679542e5, 0xe2cca684, + 0x20236d05, 0xcc1f6c40, 0x5be9688a, 0x40e3bb84, 0x1be22976, 0xae0b5da0, 0x0aec14e3, 0xf97a5057, + 0xa52b7585, 0x39ab943f, 0x2fe4a518, 0x4b87c37a, 0x34e7bbbd, 0x5f3ffb04, 0xd53b2085, 0x6419dec1, + 0x6ef00316, 0xdf455116, 0xb5c37026, 0x559acd30, 0x8e723735, 0x4b766ee7, 0x34fa68ea, 0xded85803, + 0x927e6397, 0xac266f53, 0x4c3ea476, 0xde4cd089, 0x0507d2ef, 0xe0def0dd, 0x936c64d2, 0x1420b268, + 0xefcd60b0, 0x8db980f2, 0x080cd930, 0xa2048e10, 0xce2da077, 0xda879ca6, 0xdc018731, 0xa0bba06e, + 0x65a32b7e, 0xeaf10a9b, 0x2de6e66c, 0xdec7f3ec, 0xb440c7ad, 0xa26c16db, 0x8d6933d4, 0x32a62414, + 0x2ef00310, 0xbc21625c, 0xaa2b79ec, 0x28a9e77b, 0x15819d93, 0x604fb232, 0x1d0b45db, 0x719a2899, + 0xaea61329, 0x826826ff, 0x638977d9, 0x92b138e6, 0xc9377dec, 0x944dc329, 0x37c95c0e, 0xb63f79ae, + 0x7f0fd1ea, 0x2b9cfb73, 0xd274b767, 0xcd46564e, 0x7b0c13dc, 0x23a441e4, 0x68a94578, 0x2ca9df1a, + 0x7d4b9ab3, 0xefa24626, 0x1563cf02, 0x7804bfba, 0x6037039c, 0xfa1fab69, 0xa10af660, 0x65ba69ef, + 0xbd42ff8e, 0x0e6f4c93, 0xabb1bc8c, 0x2df5de3e, 0x89f0183a, 0x549e7897, 0x2ed6cfd3, 0x11b51b93, + 0x8ee0edab, 0x855411b1, 0xd1afbb03, 0x3f3636ce, 0xf8f15496, 0x298ad35a, 0xe3963271, 0x83d49546, + 0xdbc56fc8, 0x1db3282e, 0xdc7aec1a, 0x1142451e, 0x64bcbb18, 0x182cd06b, 0x604a610c, 0xafebb192, + 0xdd983a3c, 0x4863206c, 0xc0fa1132, 0x8a68dc45, 0x32b0c6cd, 0x65c2493d, 0x2a30209d, 0xf704de45, + 0x87ac5db5, 0xb9d2bd7b, 0xa107da47, 0xbd31a691, 0x062acbd8, 0xb3c4b263, 0xbffaff20, 0xfee41e68, + 0xbb0dad21, 0xc074593f, 0xb6188227, 0xc047d598, 0x1bcd8766, 0x79d4bc3b, 0x576cdf91, 0xd271b3c9, + 0x761bafa1, 0x7cc59155, 0x188927fd, 0xafb90ba6, 0xd9418602, 0x1d0935d0, 0x40215e36, 0x12bc5e65, + 0xccabbc49, 0x555e2bea, 0x4aacdd8c, 0xdfcf1db3, 0xbb482516, 0x97808c1e, 0x189b762e, 0x9d7b26ab, + 0xaba8c9df, 0x470f8770, 0x7ac2294e, 0xd225a6ed, 0xe3bca70d, 0x72330e60, 0x9ac8e642, 0x6a555f69, + 0x99bdff1d, 0x52497b74, 0x2f2a3691, 0x896c00b9, 0x706a9746, 0xfe610aeb, 0x871a6f7f, 0xd6f30fb0, + 0x209fe8be, 0x83f21742, 0x7a80ef88, 0x49899e88, 0xc312f7be, 0x81567629, 0x8491b0a3, 0x3adbd422, + 0x98d44bdf, 0x2d9c3324, 0x6c104c4a, 0x6957269a, 0x0d7333f1, 0x208c82be, 0x090905cd, 0x3ff25a8b, + 0xff66dfaa, 0x53644f07, 0xe4030c94, 0xc2c1b2c6, 0x6dd5ba98, 0x8823ef8b, 0x8ca88ce2, 0x5711ff4b, + 0xd6ed518c, 0x172053dc, 0x0aaea1ed, 0x14f6db3c, 0x75bebfe4, 0x234b5f12, 0x6e489611, 0x6f0dcd2a, + 0xb633aaff, 0x409f6a16, 0x8743876a, 0x8ad77ed0, 0x18f7e07e, 0x675c1790, 0x96d972f9, 0xdc1aded0, + 0x1e6e35f6, 0xef59b2c9, 0x9929cf38, 0x1f1ab515, 0x3f8e1974, 0x3c02b976, 0xddefa4c3, 0xa53597ac, + 0x9e9c3623, 0x3045b308, 0xaf9f6d2c, 0xe39beb6f, 0xbb69462e, 0x658e5182, 0x68f7fc51, 0x0ac5851d, + 0xcc174811, 0xcf337590, 0x08555888, 0x9629fe79, 0xef63f1b9, 0x711d9635, 0x8d59bb24, 0xcb0c8e71, + 0x91743c9e, 0x018f44f8, 0xec6c92f1, 0x3cad0a6e, 0xb7850e3a, 0xbd9abcaa, 0x960d8a69, 0xa31dd72b, + 0x2a99cdad, 0x9848f7b8, 0x83fffb51, 0xb64b10c2, 0xf2e42db2, 0x929f5d7b, 0x93a054f6, 0x21af81e9, + 0x5033e386, 0xd9f4eed8, 0x6bfd4f6e, 0xfa95ef0d, 0xdb7f6b46, 0x0ef180c8, 0x53cd4e5e, 0x144166ad, + 0x3b479ae3, 0xece2f120, 0x0a870f76, 0xb13c59a3, 0x75e9c4d5, 0xda1b0ec0, 0xc28d454c, 0x4f25ff6e, + 0xb151a5e2, 0xbd2e6654, 0xe4c6d4c9, 0x63c0fc0b, 0xe2b0337d, 0x1cb48a80, 0xa522a571, 0xcf676039, + 0xfed8022f, 0x5102b965, 0x059603d0, 0x8c6e6224, 0x1474a618, 0xc3abb2de, 0xae65d92e, 0xa30343a3, + 0x29963f88, 0x2433f9de, 0x571effec, 0xf72140e3, 0x2af040a1, 0x06d2a90b, 0xa83bfed0, 0xcd4ebe29, + 0x5e3102ca, 0x483351b6, 0xd9fcfb09, 0xf0099064, 0x61252f89, 0x28a4ce9a, 0x68305da1, 0x8e95f359, + 0x603de643, 0x331d7915, 0xde2949c7, 0xa37ab761, 0x66f59083, 0xec9e4b8f, 0x4a0ab9ed, 0xb064bcab, + 0x1ba5744d, 0x81172154, 0xa22543ff, 0x49644da3, 0x8a18815b, 0xc89d7912, 0x84ea48fb, 0x1792b3c7, + 0x75a6bbef, 0x3dc9f828, 0xd477cf5c, 0xfb15514c, 0x3a03a3ce, 0x35731c45, 0x0afb130e, 0x871701f2, + 0x9c1954c8, 0xf07f2c47, 0x95f74c98, 0xc4711f10, 0xd668163f, 0xe7fc2841, 0x3c44adc0, 0xa3b242e3, + 0x47f10682, 0xd343a71c, 0x6c876160, 0xe687780b, 0x54b83525, 0x1b2cfa0f, 0xd3e92228, 0xa1d87453, + 0x253c2dc5, 0xc74d53a3, 0x9840f0d3, 0xf0d78989, 0xfedebafd, 0xd4b8c616, 0x43d21315, 0xa66ecbcc, + 0x7ee91d08, 0xe836b64f, 0x4c34f083, 0x08882baa, 0xa1d4da2c, 0xacf0d098, 0x299a17f6, 0x82119cfd, + 0x0fd1fec3, 0x00fe0669, 0x067e727a, 0x9257390e, 0xf75a43a1, 0xf513578e, 0xe0172758, 0xba03696b, + 0x8ecdc6da, 0xbcfff369, 0x7e39cb1e, 0xf7ed6e30, 0x15579af6, 0x7463de05, 0x8879033c, 0x2619963d, + 0x3c62dcab, 0x66a17cbe, 0xebb03399, 0x15a9ce4a, 0x28d0e4b6, 0xcb28f985, 0xe4341879, 0x1d065fc9, + 0x6c80b323, 0x2f62055d, 0xc7415456, 0xd741759f, 0x06c04753, 0xdf240e1c, 0x65dc43d5, 0x28d626f4, + 0x78703ff8, 0xb7feb3d0, 0x880d83eb, 0x8dc07a06, 0xbe6d692e, 0x05261829, 0x5c8a1688, 0x1ad976e7, + 0x149fe681, 0x35a54749, 0x1f1147e7, 0x710019c4, 0x2dbe6f39, 0xe0c8da6c, 0x474b6efc, 0xde6affca, + 0x63bdef68, 0x75e67bc3, 0x2ed7caf0, 0x754c56ff, 0x82000bfc, 0xa2d653c6, 0x5cbd7f85, 0x77fadf94, + 0xa761f313, 0xf827a545, 0xcf727962, 0x9c32c4bf, 0xda4dcf48, 0x6fafc166, 0xa78a05a5, 0xddedc007, + 0xac1c5fc1, 0x064a00ea, 0x7bd859c7, 0x97184347, 0x94b7ee5a, 0x334ea313, 0xd00a7f92, 0x52484f2d, + 0xc8b59935, 0x5a627ac7, 0x38348c4c, 0xb561f86a, 0xd7fb4909, 0x6a5ffd4c, 0x0bd465bd, 0x1e836477, + 0x191de40d, 0x36e3ef98, 0xf0b04d79, 0x42e90da4, 0x71beed2c, 0xc5a37f4b, 0xac2be6e3, 0x9c5a770c, + 0xc395363b, 0xd5a1ef88, 0x61411578, 0x437d0635, 0xf692c3bf, 0xfb834514, 0x4a267cd5, 0x56f10a6a, + 0x7b154205, 0x3953f290, 0x628502ea, 0x6dfc7fb8, 0x8fdedd5a, 0xc9bd659e, 0x95db98ba, 0x5e5aafa8, + 0xca883dc1, 0x910204b7, 0xd1234784, 0x81fb0e98, 0x9a59dd76, 0x9061ed30, 0xabe23745, 0x067b70cd, + 0x8785fd7d, 0xe486da1d, 0x546f325f, 0x4dbf22df, 0x661218fa, 0x0fd5d070, 0x9a17547b, 0x32a09469, + 0x8b1ad6e2, 0xcf1ef20e, 0x7f794a12, 0xa0eaf093, 0x2ab53cf9, 0x3a00bc4b, 0x58a68f5e, 0xcad3eb93, + 0x15476d38, 0xa7d070cd, 0xb59ca8de, 0xe0dffd98, 0x01e24fd0, 0xa812033e, 0xd92f86b5, 0x837b8412, + 0x4110c149, 0x6fad9ad0, 0xe85fed45, 0x0418209f, 0xb7e09ecb, 0x72093c08, 0x50196251, 0xa38668f7, + 0xca7737e4, 0x00ea222a, 0x0f37b64f, 0x1674248b, 0x5a82603f, 0xd2d42429, 0x42b23469, 0x4bc01df4, + 0xc89f868b, 0x1e9ef683, 0xdfc388ef, 0x439b2148, 0x6bcf06c5, 0x3fe1c706, 0x08eadffe, 0x23f0fcca, + 0xd80ea5eb, 0xc5ccf7a2, 0x8061eaa2, 0x8a8366e8, 0xae1042dc, 0xc69bf9e5, 0xf3ed5c95, 0xde9a8702, + 0xf283f13b, 0xd0997981, 0x021f8ed8, 0xd4c44a72, 0xc055c25e, 0x7469f0fe, 0xba9ffa1f, 0xf2120d0f, + 0x417d1b32, 0xf930d1fb, 0xd42114a1, 0x245e7180, 0x95766e5f, 0xdd8afba9, 0x292ccbd4, 0x993b49c9, + 0x9df6ae5d, 0xbeac9615, 0x04cefa61, 0xca36c9fd, 0x117d5c67, 0xd51361d8, 0x7db66adb, 0xce9c3798, + 0xabbb9f46, 0x5d3dca92, 0x8be636b1, 0xd5ce6e39, 0x1270b895, 0xf580a7c0, 0x157ae13b, 0x4e6d61dc, + 0xdb6f477f, 0x0afa8262, 0x1a9041b0, 0x0e916483, 0x56266f7a, 0xaaa57dce, 0x5d4766be, 0x2c9089f5, + 0x6d1e3bd8, 0x4fd1e2a3, 0xdc13d84a, 0xec9ba3cc, 0x0d8315ea, 0xd029a50b, 0x02b16aa0, 0xbe2bfe9a, + 0xa7d317d5, 0xc73b9423, 0xbc8a8b81, 0x24012300, 0xed1c6809, 0x391bb6db, 0x4910845f, 0x135d1adf, + 0x576fbe38, 0x7af75cc7, 0x27c39d15, 0x65da3bc3, 0x38c42c1a, 0x706b4e07, 0x83754b2f, 0x2ae0cfdf, + 0xf134e39f, 0x8a8b3b89, 0x8315b8ff, 0x3d440414, 0xa8d4a73f, 0xb05f09b6, 0xc3374fc2, 0x74a544c3, + 0xe0868fdd, 0x71355b9c, 0xd4c80e1f, 0x190e447e, 0xf721b8b2, 0x47e7e72a, 0xf643095a, 0xc92b8137, + 0x1c8d4bd6, 0xdfe65be9, 0x23e4b316, 0xac7e5443, 0xcfa8676e, 0xf5b06c86, 0x644194d2, 0x4ec9603f, + 0x65ca10bd, 0x6392c023, 0xfad60890, 0xf1f46fc7, 0x92955cf4, 0xde675f8c, 0xcf52e792, 0xc128ded0, + 0x0867410f, 0x993d4321, 0x4d553af8, 0xa575a484, 0x630dc87e, 0xeeb25448, 0xa6486d90, 0x28115ceb, + 0x290298f4, 0xabd41a11, 0xd0ac29d8, 0x8eb89249, 0xde1098d1, 0x895ee263, 0x2d033422, 0x5cfde02c, + 0x8b0d1f49, 0xf9d5f19b, 0xee7e5188, 0x176eed46, 0x15f2d574, 0xaef9c1f5, 0xbdcd9849, 0x6f10c78c, + 0x51f2c782, 0xfde09c9c, 0x471dd4f6, 0x95c6312d, 0x840b7f85, 0x6a7cfa6f, 0x5a73b66e, 0x4ca1f79e, + 0xa2f9a17f, 0xbdef4e4c, 0xc26bb59e, 0x4ba45d94, 0xa7a83392, 0xe82f7344, 0x6c03664b, 0xd0cc3f2b, + 0x4168eb83, 0x9f73ac69, 0xc8d6e59f, 0x6b7419d8, 0xa59c9d44, 0xd749c57b, 0xe1306cc1, 0x6d7230c0, + 0x09ad803b, 0x866f08c6, 0xea75af26, 0x54aebb4e, 0x78e24dae, 0x6f894f79, 0xb6642818, 0x28b000c9, + 0x441a40b3, 0x2bccdea7, 0x3eae7cbf, 0xfa4d7566, 0xed443e41, 0xe2b3e848, 0x484ae9b6, 0x68fd3c3f, + 0xb0176621, 0xa371c351, 0x0034ed7e, 0xc8a518de, 0x33e978dd, 0x3e8f096b, 0xaa339a49, 0xb75fbc9e, + 0x45671ea3, 0xaca25269, 0x387bfb21, 0xac11ff97, 0x56a1097b, 0x8757bdb4, 0xf899471b, 0xa3e8c02e, + 0xe5b4e0bb, 0xef1d4845, 0xb2b5e449, 0x1dc79184, 0xf4cbb00b, 0x192831f5, 0x2e19331b, 0xd36e1cdf, + 0xf40a1cbe, 0xbf16b069, 0xc0759ca9, 0x61ea5014, 0x36bb7697, 0x58ea9481, 0xeb95f381, 0xb3f33917, + 0x813356cc, 0xd784f1d6, 0xbb511815, 0x92063f2a, 0x587fbd57, 0x1ae9ace8, 0x29d7b995, 0xfb912872, + 0x87eb2ee5, 0xb9c1545f, 0x69e30386, 0x6b562037, 0x6e61abf6, 0x51d0c7cc, 0xb492a604, 0x5e1591e3, + 0x96eecc78, 0x1b9c4f43, 0xb1b579db, 0x1b42f361, 0xab207e3a, 0x76388bf9, 0x08f91d2c, 0x71dab384, + 0x8e49931c, 0x9e0a4eb0, 0x5b69a011, 0x4e485ae8, 0x3854186e, 0x91af41af, 0xd39f78f1, 0x63a3d6d7, + 0x78364c22, 0x7400be10, 0x180cb2c4, 0xf98f320b, 0x8a27be4d, 0xa4cfa7db, 0xd92e7ae8, 0x74a643d8, + 0xbfe92334, 0x9e036141, 0x0b2494e1, 0x2b554051, 0xfa207c8d, 0x7ae939d9, 0x80fd51bd, 0x72578dd4, + 0x81614255, 0x8b0dcecd, 0x352dedbc, 0x6f98dc12, 0xe6bcbdf0, 0x66b4df43, 0x2795a8d5, 0x167a31de, + 0x3a318572, 0x8906f711, 0x4e689010, 0xa01e7df1, 0xea04b390, 0x74ede736, 0x1cf2109b, 0x6424419e, + 0x9bb6cbc9, 0x2f88971c, 0x8dd8265b, 0x871dab27, 0x0d34b5bb, 0x850ae7e2, 0x8892c7d0, 0x60b9b83a, + 0x231d37a4, 0x006491dd, 0x670d05d6, 0x28ed182c, 0xf57a5d5f, 0x7d3060b4, 0xc7ccf168, 0xcb392d8c, + 0xb36f4e09, 0x696beb0a, 0xbb47c6d5, 0xafc4af15, 0xbc9da282, 0x1b945221, 0x29119be7, 0x2c14d64a, + 0x59573347, 0xc46643e0, 0x472e2383, 0xdc056131, 0xb0d5490a, 0x0f2f9772, 0xa8ee1d7d, 0x1862b748, + 0xfa9c3f53, 0x31a6ec14, 0x9bb4a3d0, 0x0e063d53, 0xfe8d2d4e, 0x09835cf5, 0x9879916f, 0x56de62ff, + 0x85e714ad, 0xacfcf8f8, 0x833a3e3c, 0x5da4bca9, 0xc11c7ce0, 0x34e118fa, 0xd14c0eb5, 0x24d9806c, + 0xa431a69b, 0xd834c66f, 0x62b6ab19, 0x5b8e12a1, 0x0b0b46a9, 0x97a4ae7c, 0xa0011e83, 0x2c4b0b83, + 0x49f02d52, 0xef2500a3, 0x1b2ab73e, 0x7b4afa55, 0x95be8167, 0x7af08ebb, 0x011cadd5, 0xbb63945c, + 0x306ded3a, 0xcec7d33b, 0x335bb892, 0xb7f39372, 0xd524d794, 0x38e09a85, 0x6aba7b58, 0x0bf2c9fa, + 0xe3e149cd, 0xab0693e3, 0x46859054, 0x99fe5b86, 0x8924d89f, 0x3b2c4e7e, 0x3a9e38dc, 0x51f96c16, + 0xcfcc68f8, 0x14ba1635, 0x57342a6c, 0xa0578204, 0x989cff36, 0xc8e6cc40, 0x444e683b, 0x46426959, + 0x05938d22, 0xc14ce55b, 0x26435a5d, 0xf43fca2e, 0x33309d17, 0xe8d3c6c6, 0x243a9748, 0xf1b57e3c, + 0x694392fc, 0x29e6f0ad, 0x37a21b77, 0x4e7c2842, 0x6a2d5816, 0x7c714039, 0x79fdb2ec, 0x32fbdf48, + 0x0c466e82, 0x32bef2e5, 0xf80b8a52, 0x9b9ec4d7, 0xfd7ff5c0, 0xa9ba2b26, 0xaab042ae, 0x241adc45, + 0x95b90237, 0xa6e9eed6, 0xe3a5ecca, 0x71b86539, 0x20a7a1b7, 0x523ef253, 0x737c8bf4, 0xdf77e085, + 0x2c042480, 0x5d36b117, 0x880d4f69, 0x69c59991, 0x1bd98f69, 0x7d77948f, 0x71bfdb55, 0x057d22fa, + 0xb52a4ad3, 0xb7503f6c, 0xf9b03682, 0x49dc94b6, 0xaaf28711, 0x2d5ca870, 0x302cdc3c, 0xbdb5ed87, + 0xab4522c5, 0x1b860512, 0xbd6e9602, 0x16550134, 0x7a98a73a, 0xb3930f61, 0x692038af, 0x44df98ab, + 0x49a55544, 0x47ebad8f, 0xccf8500c, 0x135f1629, 0x6bb2fefe, 0xbde903d7, 0x19f8be7b, 0x0f18341c, + 0x994861f7, 0x0bfccf64, 0x1686d315, 0x9727734e, 0xbec056ed, 0xed315c0b, 0x8d87765e, 0x034b3822, + 0xe3dc16ed, 0xb12be313, 0xff7b2716, 0xf85a5637, 0xf0be1959, 0x2073208f, 0xefe864d6, 0xfbf9c90f, + 0xd8182371, 0x975a02fe, 0x4b11aa4c, 0x4f499f39, 0x0663d835, 0x78816a74, 0xa67fd98c, 0x1c6639cb, + 0xc9f9f328, 0xd95ec512, 0x534ae5ba, 0xccecc35f, 0x274274bd, 0x02e019f0, 0x6eb16fcd, 0xb4444b60, + 0x03d51ea6, 0x70a8f35d, 0x8d0b97af, 0x8a274047, 0x8d7f2edc, 0x6a76f06d, 0x12d8bd3d, 0x36dd48ce, + 0xf762da9c, 0x5ef0024a, 0xfe380587, 0xc0a0696b, 0xc000f52f, 0x926ad9bc, 0xe3d55d29, 0x033e9410, + 0x637ed612, 0xd1ea0452, 0xc93f1fb7, 0xd0234c63, 0x1d147827, 0x22e77824, 0xe55d3408, 0x3e6b5062, + 0x7ea0a059, 0x310da512, 0xc9295bef, 0x5dd61b6c, 0x959913a0, 0xd5545131, 0x1332f0ff, 0xb36e1781, + 0x169e4476, 0xafc6002e, 0xb568e7a9, 0x4c709f43, 0x65775d5b, 0x84ee218c, 0xeae481ed, 0xe664d176, + 0xfc088ab1, 0xadce443a, 0x9ec2d938, 0x13838ca9, 0x077274f4, 0x2f8b4ad6, 0x6bfa16d7, 0x18c23075, + 0x39695d1c, 0xbd2f7ff2, 0xd9a4cf99, 0x2f90c4d7, 0x11abdc22, 0x444741ac, 0x01bf13a5, 0xe51e7471, + 0xe220204c, 0xc42a84ea, 0xd16998a3, 0x82550b1f, 0xe06e8e64, 0x53709a8a, 0x8b3ee89e, 0x981b4a5b, + 0xf20fdc1f, 0xc5126ac3, 0xd9177962, 0xb28d9d81, 0xf3314c9d, 0xbf200401, 0x6479319e, 0x8b1c43f7, + 0x8d2195fc, 0x76ea9624, 0xc6eb3faa, 0x41e1134f, 0x232a9548, 0x52418398, 0xb381796e, 0xb7d96b5a, + 0x41de3a76, 0x7b8b9693, 0x1caf23db, 0xddde8ecc, 0x62a72474, 0xe24ea4db, 0x47af6fbf, 0xf9c83c3b, + 0xbc69e79b, 0xb7337acd, 0x276a45d7, 0x9748ac89, 0x18ffdab0, 0x4e99c758, 0x64d8e918, 0xe263b077, + 0xfb5c656a, 0x0006b5ec, 0x1eae5194, 0x06aeced1, 0xab97437b, 0x6441d425, 0xc50148c0, 0x150459aa, + 0x7b4a5958, 0xeb4b0f2e, 0x288c118e, 0x258e5c0f, 0xaaa9eedb, 0x330634a1, 0xb72e5f2a, 0xc1d877bb, + 0xab28827f, 0x618fa75f, 0xcc8decf6, 0x4338494d, 0xcd3e2b7d, 0x137aff5a, 0xd660c021, 0x2f1bc68f, + 0x59a5c9c6, 0x9dfd4184, 0x2d8a1ba1, 0x79b24f8e, 0x242dd1ff, 0xf899f737, 0x10bbdb69, 0xaa5f4cb5, + 0x1c448e4e, 0x19d8e8bd, 0xfe76f788, 0x8fa6bbe9, 0x42a7d377, 0xa69de5e2, 0x3b34f79a, 0x5538962c, + 0x3a334e91, 0x0a7bbbca, 0x43a63f56, 0x03bf886f, 0x20298c87, 0x3263026a, 0x297d18e4, 0xadc4ce3b, + 0x707e513b, 0x66d0ab64, 0xb396b409, 0xb4520784, 0x3333332a, 0xa50b1d6c, 0xf07c70a0, 0x5382a739, + 0x27120b58, 0x8674dbb9, 0x71b793d2, 0x90a3b427, 0x3973644b, 0x4c516c57, 0x9820d8c5, 0xffc811b5, + 0x5835e145, 0x58efcf87, 0x60015f13, 0xb9fc9fcf, 0x56093a2f, 0x840444c9, 0x88918bb3, 0xd1b3939f, + 0xa0b2a6ec, 0xda66dacd, 0x28989c12, 0xd6bdb277, 0x2a2d2224, 0x09fad512, 0x49f7f117, 0xdc0e87c2, + 0x5be30f61, 0x63f36bc8, 0x466e2b7b, 0x0b391ce2, 0x27e7787c, 0x48c97bfd, 0x870a24dd, 0x49ee59a7, + 0x71c3ae85, 0xfd25bcab, 0x132d1710, 0x0e5ed6b4, 0x2d098096, 0x15f53d53, 0x95c5b10b, 0x26d97b2b, + 0xe3f1589b, 0xf68291bd, 0x5d5d3e5b, 0xa7df651c, 0x1990986a, 0x49c9d3c9, 0xec9e7c33, 0xa19babec, + 0x21f607ed, 0xcd784f2f, 0x990d81d1, 0x9dec5281, 0x4fd20da1, 0x94ebf8e6, 0x1ac25551, 0x5a0cb1e5, + 0x3e82d422, 0xfc312fd7, 0xf5ff6f9b, 0xbdff45f1, 0xfe36f409, 0xf782ba1d, 0x11438992, 0x5c024887, + 0xf2fd0775, 0x3321961d, 0xf6202a9a, 0x0e60af3f, 0x10737cd4, 0xe57c4f7c, 0xf7a22b57, 0x2c357e7b, + 0x089b59a5, 0xc0c88730, 0x99e65355, 0x89b3a522, 0x7638ce8a, 0x5ff397cc, 0x763bf4f8, 0x780bfbeb, + 0x979069df, 0x369e0672, 0x171e1dfa, 0x8e6e5c29, 0xabfbd826, 0x98b672fd, 0xaae0c119, 0x867c5fc8, + 0x1c1626ef, 0x507d96d9, 0xc5784c64, 0xc7a64332, 0x6f5b875a, 0xa1eec191, 0x107f9110, 0x26d7345c, + 0xca896887, 0x3f0879fb, 0x7acf47b3, 0xc77cdec0, 0x5dd8b596, 0x4e472017, 0x74039f7e, 0x1e3a1816, + 0x3ad8cfcf, 0x20bfd746, 0xe38134eb, 0x0cb0bd5f, 0xb3eed9dd, 0xb25dfb6e, 0x08cbd7c4, 0x3941cf5c, + 0xaa5befe6, 0xb3e26517, 0x5ad4a316, 0xe52044d5, 0x6dc10368, 0xffe7ecf7, 0x32ada8e9, 0xf5157b76, + 0x1b5cf57c, 0x8022c9c7, 0x3869f99d, 0x56ad82af, 0x861c4d92, 0x9aa6d483, 0x8585004d, 0xd11270b4, + 0xa9fed132, 0xfe12459c, 0xd4647137, 0xa655aa8a, 0x6c6deb10, 0x911d0533, 0xc284f3bf, 0xe53955b0, + 0xb729b32d, 0xf7ec3d8a, 0x64a0dd65, 0x0850e5a1, 0x910d254d, 0xac2d6349, 0xd6e5a1e0, 0x4fe80052, + 0x2765585a, 0x34dd89f3, 0xb2849956, 0x047997d8, 0x5adc8736, 0x63321073, 0x07022169, 0x4b9fe8d4, + 0xd1bd8fdd, 0x1d7e0cdf, 0x7651b479, 0xa5f7b13a, 0xea87e85d, 0xfe29a129, 0x058e0da4, 0x3216b0f7, + 0xfb3bad06, 0x41198889, 0xd63ed61c, 0x81a7d469, 0xf58027f2, 0x6082a719, 0x8f41ad4b, 0xdfe29937, + 0x02f47797, 0x8d70e661, 0xa602dea4, 0x674da534, 0xa3b21b57, 0x083599e9, 0xdda008e6, 0x85dfa320, + 0x82eae412, 0x10ca8765, 0xb98d2f76, 0xd938e77f, 0x9f50a3d6, 0x25e4afd7, 0x43c46e85, 0x08c1ce66, + 0x55d4915b, 0x7fdbb2ac, 0x7477b4d5, 0x33e750ca, 0x7590bcd6, 0x33ac35dc, 0xb30932a2, 0xa410be42, + 0x5b4d9861, 0xfae97700, 0x378e821e, 0x73d4f20c, 0x9153b933, 0x6eaf065c, 0x216bcaf4, 0xee261424, + 0x96f0b939, 0x43fd2cac, 0x79a12b41, 0x6bd03e86, 0x5818cae6, 0xf53877df, 0x71d6c0cd, 0x1e6962a9, + 0xcc908c0d, 0x58de2000, 0x7a76fd67, 0x07b72c3e, 0xcab1c9c1, 0xa50885fd, 0x74555657, 0xef2bbb26, + 0x66a88c2c, 0xc73db6ec, 0xc1a690e9, 0x0403faa9, 0x01fd76cc, 0x148cad82, 0x00ee5bf2, 0x5a5b2b2a, + 0x26db040d, 0x452a064b, 0x34754da9, 0x721187e3, 0x9ca2808d, 0x3e1b6141, 0xfc8d7124, 0x33443c51, + 0x4b6c0a30, 0x2474ca9d, 0x37a40df3, 0xe361bb72, 0x3324cc4c, 0xbeed320a, 0xf3ff92a7, 0x951e796b, + 0xa8de3918, 0x15774b52, 0x167292c2, 0x3e1b10ab, 0x404268b3, 0x88e06106, 0x8acc9352, 0xaf34b325, + 0xf04b5386, 0xea7df842, 0x562cf04a, 0xbfff8cd8, 0xc30fcf3b, 0x6dc232ac, 0x655817ee, 0x9aa4ee30, + 0x549305ca, 0xc12858bc, 0x31b100e8, 0x087c9e4f, 0x2a45d225, 0x6b8cd28f, 0xfd0a234e, 0x63770886, + 0xa3d5b4a0, 0xbf563aa5, 0xe6a64dc8, 0x1414c690, 0xecbf6b3e, 0xf99994fa, 0x6d4688f4, 0xe2212129, + 0xb4924354, 0x949355f4, 0x3f2bca7a, 0xb8f34301, 0x1de16e89, 0x5f123f80, 0x5ef543c1, 0x3302e93f, + 0x2dfb37c1, 0x118da5af, 0xbda0f433, 0x31b11a83, 0x9290697e, 0x1a754f2c, 0xb3f4d1cb, 0xb68c06c8, + 0x1db6ad2d, 0x41b483b6, 0x597f7219, 0x81399b95, 0xe244a625, 0x17512041, 0xb363ec0f, 0x601df6ee, + 0x878429cf, 0x3c193cd7, 0xc5af1726, 0x35286b26, 0xdd16681b, 0x26f96e4c, 0x95eb58bb, 0xd359bbda, + 0x2d30c1aa, 0xe9541ce6, 0x1905ef50, 0xc097f874, 0x0b3b5082, 0xe0de05e9, 0x4407e43f, 0x21f7c247, + 0x4902dc1d, 0x492c66d6, 0x9650979f, 0xf430692f, 0xe59c9eba, 0xe7d1a370, 0x2ad5c9fb, 0x5b8123e7, + 0x1ff79c23, 0x4c585948, 0x451a821c, 0x46500578, 0x80ba465f, 0xef7b334d, 0xc11b121f, 0x02c45798, + 0x8c0cf35e, 0xe98b721b, 0xc661f592, 0x91433260, 0x44fc73e7, 0xf4e50b48, 0x65499b47, 0x0bd0fcca, + 0xa33541af, 0x05db63c5, 0x19c5328e, 0xbac52552, 0xc7707101, 0xdf5f6b4c, 0xe8af6c11, 0x60061947, + 0x122e4471, 0xd4d77e1e, 0xd145cf6f, 0x11373b5a, 0x8e504e9c, 0x030c349a, 0xbe8d1243, 0x536d1f83, + 0xfb64f16c, 0x808a08e7, 0x3209a653, 0xaae3de91, 0x5bf693b3, 0xfa0ea4f6, 0x64ba5146, 0x5ae66f6e, + 0xbfef920d, 0x77b4378d, 0x492d04e3, 0x03f8121b, 0x2e51f74b, 0x85fb5196, 0xaaed9495, 0x42e51f4c, + 0x42960d58, 0xc41bc11c, 0xefe2004d, 0x4019648d, 0x3890b915, 0xb5284da5, 0x0ab10922, 0x3d6a4c40, + 0x5bb3d3d0, 0xd8f202c4, 0xa88f1f06, 0x53081066, 0x017a43e9, 0xc6ad943d, 0x712231f3, 0x5783d651, + 0x097b22d7, 0x9729e717, 0xda2a0ddf, 0x135048c4, 0x633b9424, 0x93930fad, 0x476b3e6a, 0xd3be8067, + 0xc83e3ecc, 0xd665aa36, 0x4db0d647, 0xb0c7c436, 0x8ca47da7, 0x1639f233, 0xfa399b78, 0xfe2e7b07, + 0xc917e7ba, 0xc6f1e20c, 0x5339b864, 0x0f61f7b7, 0x6b551351, 0x58c67359, 0x703bad0b, 0x3accf6f6, + 0xbd2accbf, 0x40140b1e, 0xc487af92, 0x3e85e307, 0x4f686536, 0xd5a2f10a, 0x36d5fc33, 0x6f602d35, + 0x92087da4, 0xd1f65276, 0xa317db4a, 0x3b84e1ef, 0x01708120, 0x1a53a0eb, 0xd8095a30, 0x3d649d51, + 0x67be6f39, 0x7d566b13, 0x076334ad, 0xbdbbd5d8, 0x7766415b, 0xc5d5415a, 0x31f7efba, 0x6fa01868, + 0xba979c90, 0x975be8a5, 0xe1f1f925, 0x1eaffee8, 0xa9995b83, 0xd0c70276, 0xb174da0f, 0x8daa48eb, + 0xe71d8b0f, 0xde227c0d, 0xb75e6b71, 0x2e0a7899, 0x0dfaa4a3, 0x17d40381, 0xadafc223, 0xe5024e66, + 0xd38eb55e, 0x753773a5, 0x63318533, 0xebcf1377, 0x3a193753, 0x0c94cd5d, 0x6cc98b35, 0x97c79f68, + 0xdaea603e, 0x7c31f3da, 0x38ebecd5, 0x3ee778d5, 0xec0f94ce, 0xe3d0bb4d, 0x711f16c2, 0x6781ed5c, + 0xe5f0b98d, 0xa9997131, 0x25c80b28, 0x4d399bbd, 0x6cf86e26, 0x6d10ffe4, 0xb86de839, 0x9cf738fe, + 0x7b29ffd8, 0x0f3da343, 0xaa57cb38, 0x60cbd1d4, 0xf8b2c3f3, 0x894bd34b, 0x6b87e8bb, 0xde7a4cd9, + 0x1bff4637, 0xe80c5bb3, 0xa59f5557, 0xcce95b3d, 0xe3d5920e, 0x41a6f0d6, 0xab05b6ad, 0x4c658231, + 0xfdbfbd58, 0xc409b752, 0x0a05d046, 0x8bced7f2, 0xf92df682, 0x8001508e, 0xd1ad673f, 0x3ef70fbc, + 0x68c220c3, 0xcf0a8f42, 0xffaa9f4d, 0xa610a928, 0x956caf00, 0x658a4a16, 0xad70575b, 0x80322336, + 0x8b84f1d6, 0xde553729, 0xebf7eeef, 0x040a00c9, 0x8305fa2c, 0x4a9ef554, 0x07138d78, 0xc069219f, + 0xb597298b, 0x9c94eb6a, 0xb60ab9d2, 0x59aaedc4, 0x89320dee, 0x2ade9901, 0x77f36ffa, 0x6a6e1f46, + 0x715c0d32, 0xd416be31, 0x554f483b, 0xd341e3e4, 0xbfd808d3, 0x714fa074, 0x4ae23508, 0xfc34b019, + 0xf25e3c14, 0x02152f28, 0x298f5fc5, 0xa50fc18a, 0x76eea8b3, 0x27f37acd, 0x12e52e0b, 0xf054894d, + 0xb05713a4, 0xe5c285e3, 0x0d97d843, 0x44db6e00, 0x70de5696, 0xe20e46f6, 0xa6e71f23, 0x0d86eb05, + 0xd81aa76d, 0xbb6a78cb, 0xebea6b8d, 0x36af0d17, 0xbef4a694, 0xf4fb0ad8, 0xcb61f027, 0x45746829, + 0x44751ed0, 0x938e25e1, 0xd3938cb4, 0xd1cda325, 0x009278dc, 0xf10896fc, 0xd85a6f29, 0xf715eb1b, + 0xa313d496, 0x8a17ab9f, 0xcc6b28c1, 0xc27f8c01, 0x148234f0, 0x9c1445f6, 0x912a569a, 0xe8e19d3f, + 0x3c3f24d9, 0x6cb79876, 0x71330d1b, 0x56b948b5, 0xcf9720af, 0x189266e5, 0xe2829205, 0x2c6248bc, + 0x40386cac, 0xe5b3ce89, 0x05dd1597, 0x22b38eb2, 0xc2219c86, 0x44f19fa2, 0xa13b25d3, 0x079b724b, + 0x34d15c89, 0xeba0618a, 0x3dce4891, 0x5b295d93, 0x41863da2, 0xea40cc28, 0x65952709, 0xe06bbee0, + 0x320067f0, 0xdddddd7e, 0x41b52648, 0x0dd5a9c3, 0xcdc61fce, 0x6a114b2a, 0xe46b926f, 0x04015cd9, + 0xc36c0ee7, 0xe45975c7, 0x17d27e7b, 0xf5a992f3, 0xbe083696, 0xf2dde6b7, 0x5ef84a28, 0x86422afc, + 0xdfbd7b1e, 0xa2a9e440, 0xcca5bc66, 0x3bce5d7a, 0xc3bd8921, 0x9a73187a, 0x918bd936, 0xb7776adb, + 0x8d5b925f, 0x70a2bbb8, 0x845072c1, 0x6ad00a60, 0xcf968546, 0xbefb2ed2, 0x63734cdb, 0xa3ceebae, + 0xa4da8e11, 0xb67e9491, 0xe4e42e0a, 0xf36ab32d, 0x9974699b, 0xa13ea6b2, 0x15df4075, 0xc07a9464, + 0x6a2e19da, 0xe19ba4c8, 0x73f5b11d, 0x5c19da3e, 0x9e8d6b24, 0x1dfe1737, 0x504cde19, 0x5ecfcfb9, + 0x850e6ddb, 0xc774a3da, 0x5ba87b0f, 0x709cdd05, 0xf8dda036, 0x5241bd0e, 0xa03d3938, 0x90ed2436, + 0x803254db, 0x32387bd1, 0xef6569e0, 0x4226a2a7, 0xb519d18b, 0xe8c8ca22, 0xcc69cb42, 0x708daacd, + 0x441dc2df, 0x999cf447, 0x51d3f080, 0x62469a2b, 0x4ec8ae9f, 0x4a488373, 0xcde06754, 0x46a456f4, + 0x92bd8bdc, 0xff4d1260, 0x2088400a, 0x320f441e, 0x8f504596, 0x81afe4c3, 0xd28c6daa, 0x503cc51d, + 0x791f4e95, 0x579a66c8, 0x36d4a8ad, 0xd33dc71b, 0x43173f53, 0x633b8a49, 0x03babb2a, 0xee0ade2a, + 0xb4b5a1f8, 0xc3919901, 0xa20861dc, 0x365e9a8d, 0xa38145ef, 0xd7b0f022, 0xaf7f84e3, 0x85503a2c, + 0x7b477ad5, 0x095afeb5, 0x01186d4d, 0xf147c4aa, 0x835fb73f, 0xff681e2c, 0x2bd54af5, 0xeb72a596, + 0xc466d8d1, 0x5ae3a3f3, 0x261f4fce, 0xca6b3880, 0xf72f8239, 0x07a07d93, 0xd6c5c06d, 0x392f2f39, + 0x45c23e51, 0xa3de5771, 0xeefad88f, 0x45a3a997, 0xa58a6182, 0x5d101fef, 0x9ab1452a, 0x09324544, + 0x7386c201, 0x2dcf6448, 0x7d338d72, 0x8d11d4ae, 0xfbb15883, 0x766ec7b6, 0xdffa4015, 0x9fd9fa00, + 0xee488139, 0xbed86e19, 0xcb144ce7, 0xb62dd49c, 0x8ff04593, 0xf56a4c0c, 0xf5875a14, 0xbda20fd8, + 0x875ad98a, 0xdf6728eb, 0xcbe19260, 0x7f4b4d75, 0x4349fd36, 0x76074571, 0xfaf8c183, 0x342845f9, + 0xaa887e73, 0x07ea14eb, 0x6af5c604, 0xdc843676, 0x742c9f59, 0x4a6c5ce0, 0x6999ed16, 0xeed7a7fb, + 0x5bb858b4, 0x1c3d596e, 0x5fbc9fb7, 0x838e7a0e, 0xe0ccfefe, 0x8b872360, 0x993d6068, 0x8168bc47, + 0x7aab2fdd, 0xe1086b82, 0x871e5ad6, 0x2e5c66c1, 0x69b30b93, 0xf5633fb4, 0x5af31adf, 0x08535713, + 0x69b5533e, 0xc88233d8, 0x96e366d3, 0x1f523f6d, 0x97ad6ed8, 0xcf9b5968, 0x33b799e7, 0x67ebf957, + 0x99c0f0e1, 0xbfbc2915, 0xa8b1b952, 0x2e6c3091, 0x14bbcce0, 0x31983392, 0x7de795a0, 0xd68299c0, + 0xf9c4fbe3, 0x06402ecf, 0x2d65343a, 0x9d798763, 0x97265e8f, 0x0a097dca, 0xf7a79e48, 0xde7f5773, + 0x3b3836f9, 0xd21e0f5b, 0x77b025e4, 0x545ab007, 0x6a91cca8, 0xbd853b9e, 0x082c1f7b, 0x36d1bdc0, + 0xe8802e4d, 0x98ccf4ca, 0xd7715604, 0x03b35478, 0x44b109d3, 0xfa882cea, 0x5d06c6d6, 0x19ab1056, + 0x308ac87f, 0xbf042177, 0xefcac566, 0x2343dfd7, 0x138b6270, 0xe100e4d5, 0x71d97dd0, 0x22ef0d9c, + 0xd9194f77, 0x2a0fc703, 0x058afedb, 0xe12e2875, 0xeb4ab2fd, 0x23edf779, 0xbec39884, 0xe1f03065, + 0xe1a23282, 0x51889996, 0x9b054fbe, 0x3016153d, 0xccbdc2f5, 0xd5d7ba8a, 0x554cdcfb, 0x8ddae94a, + 0xf2b87e0c, 0x3e8d6ead, 0x68974ea7, 0x3cdc4d5a, 0x6f72d848, 0x2c780104, 0x14af45e6, 0x01c9c3b7, + 0xd1a5c71a, 0xe0b62c7e, 0x53012a0b, 0x317f4036, 0x850abcb8, 0x2ca74aa9, 0xac065316, 0xb98b35e8, + 0xe769471c, 0xabba8907, 0xa12bcb14, 0x7eb95589, 0x6431184d, 0xbce35078, 0x5a53f4e5, 0xdc09ae7b, + 0x8b101a50, 0x5a677a78, 0xb49aa63f, 0x8eb268bf, 0x57838a77, 0x92d445be, 0x75765c8c, 0x5cac7032, + 0x255b4515, 0xedfd585a, 0x74bc0965, 0x17a9313c, 0x7024c7f9, 0xfeec25aa, 0xb78e8fdd, 0x24e3daeb, + 0xb46ae993, 0xca450d8c, 0x7fa835d2, 0x2b8091bb, 0xa8c65660, 0x098b024d, 0x8f9a5d18, 0xa4779d17, + 0xdae01f91, 0x0761f85f, 0xca98c9aa, 0x04f35499, 0x620623d9, 0xca3f0e3f, 0x7ebaece3, 0x564a6a31, + 0x22222dea, 0x18683903, 0xb9d35543, 0xd3e40248, 0x67b84cb5, 0x8e1139e8, 0x6b600692, 0xdc4e391a, + 0x995d5ed9, 0x281cc4a6, 0x7f7e7d38, 0x8fe3b7d6, 0x6bea3e25, 0xbe742f31, 0xde4bec7a, 0xa4811085, + 0xd9bf75d1, 0x2aa32d0a, 0x05efd29d, 0x61cbae03, 0xb48113e4, 0x4758427c, 0xec149416, 0x53253f69, + 0x93d7038e, 0x38b1c431, 0xb2db457a, 0xbb1349f6, 0xd3549584, 0x5a0c69e2, 0xa7491394, 0xd407cf28, + 0x3e8d3d5f, 0x2aaf41f7, 0x30a408d3, 0x8740d30a, 0x0bd961cc, 0x3274e9a1, 0xa6e012c6, 0xa086778e, + 0x87ab7f23, 0x0c0a62ec, 0xfea3258f, 0x7f077722, 0x07f5f05c, 0x86248501, 0x6ea25f21, 0x8eee556f, + 0xa8500e69, 0x8de5ef91, 0x85afddaa, 0x390ea9df, 0x6d286839, 0x9f987d29, 0x18254749, 0x109cbc9c, + 0xf91fe7c7, 0x1ddefa79, 0x6ca482f9, 0xdf9a71e1, 0xa5a7e7c6, 0xdc32793e, 0xf7ecdcdf, 0x8065039d, + 0x57a70edd, 0x6e33daa4, 0xdf3862d6, 0xa15e1ace, 0x145999e4, 0xe241f434, 0xa59f1789, 0x94990a6f, + 0x82044561, 0xb1a37bd9, 0xf5654fbc, 0x65f5444f, 0x5f1a8eba, 0xe1cf182d, 0x943961f5, 0x88865438, + 0xf2243c73, 0xdabd74ed, 0x00f71bce, 0x0ed7fdd9, 0x3caca2d7, 0xb3b2c9c6, 0x360534c3, 0x2f04f96a, + 0x75fec923, 0x5b35407f, 0x6a2a3523, 0x1bf83973, 0x225d9b2d, 0x46ce54d1, 0x3dbe9ea5, 0xb61c0067, + 0xa8efe639, 0x0555e721, 0x04288844, 0x269622b0, 0xc79f4c43, 0xa412d055, 0x4c16132a, 0x96b5223d, + 0x64613656, 0x9b27aa14, 0xd28324fc, 0xed6fa7dd, 0x841e61ad, 0x804747c4, 0x28e7f2e9, 0xcb6d00f6, + 0x30862a84, 0x5c44409f, 0xafd639b6, 0x949dce7f, 0x2454971c, 0x286ccaf1, 0x82715108, 0xde433e0f, + 0x010344cb, 0xb6e5af91, 0x0732d432, 0x25b5b3ea, 0x560c5759, 0x2337fef9, 0xeb05656b, 0xa2bf537b, + 0xc47eae43, 0xc5104261, 0x60d2a1d4, 0x90c87865, 0x6db45d19, 0xc7af0dfb, 0x3a310bd6, 0x9b25f6d4, + 0x14cc0e64, 0x3843b841, 0x600ca341, 0x87f9874a, 0x5cc129d6, 0x2187a40a, 0x0d57d42b, 0x9306a0ad, + 0x4b7a1396, 0xc2bb639b, 0x1840de93, 0xabaeb411, 0xb80fc0ae, 0x6776aade, 0x8f9c9031, 0x4a7b3c25, + 0xbd30d303, 0xf1ba473a, 0x7b5481b1, 0xcd30c39c, 0xce35689d, 0xcc81d25e, 0x6b9b63b6, 0x97d94b67, + 0x059b9970, 0xeb076ac3, 0x93f19457, 0x3cbae07d, 0xf94a5c51, 0x84eabccf, 0x929f10b9, 0xfc28ae1c, + 0x84e83f21, 0x27673937, 0xecd8a407, 0x3e7d8b86, 0xfdf7bf45, 0xd8e28204, 0x6cf63343, 0x8894412d, + 0xb86ee346, 0xd64b86dd, 0x33b7e1b2, 0x8b19827d, 0xe2659e1e, 0x18071a27, 0xcaafe30f, 0x9748780a, + 0xb8450da4, 0xb267c48b, 0x44b4d2d8, 0x1e78a65f, 0x1f07e445, 0x690233a0, 0x8b360c5c, 0x5dda11b7, + 0xd5567bea, 0x203c9ae7, 0xc87c8a99, 0xe84794f8, 0x60338b54, 0xe5a6553b, 0x19d987b3, 0xec8b1bf1, + 0x7fbdeaed, 0x3da42e9e, 0x5a2ee489, 0xd3fe5f54, 0x9fef3616, 0xa76c4bca, 0x7be16d89, 0x9b637e65, + 0x59ebfb01, 0xc6570cdc, 0x391971dc, 0xfe189a60, 0xe75c2b4e, 0xd1c7f534, 0x932eadd2, 0x569aa6d9, + 0xd86ec4da, 0x4d932db6, 0xff06e45e, 0x64f95b06, 0x91481a50, 0x72ddb133, 0x366b799c, 0x05a34a95, + 0x658beda1, 0x64688b84, 0x6f3a0244, 0x7d45d85b, 0x49e23905, 0xaea66d98, 0xe2208c94, 0x321388c0, + 0x60a81387, 0xf54a4f9d, 0x09255958, 0x993b6ea1, 0x8f559c37, 0x35659489, 0xcc88120d, 0xba2f0ffd, + 0x836e957b, 0x4848c891, 0x3f8f0194, 0x95e11e6e, 0xa1a55050, 0x33cc624b, 0x06d39f01, 0xabad8124, + 0x872c762d, 0x3e2c6796, 0xc7ca3b27, 0x7de7f4ee, 0x6f0db494, 0x5f9a3492, 0x256f7eea, 0x3570a441, + 0x1ea995ef, 0x14cae870, 0x1483be20, 0xc5186504, 0x7b8f9b12, 0x76af554b, 0x66f24de9, 0xa6e11198, + 0x17f7c8f7, 0x19195faa, 0xc72b6f34, 0xdb99871f, 0x0975eaa7, 0x07f96726, 0x24fb869c, 0xde8a1bc2, + 0x4f72a3ef, 0x3131183e, 0x66069a2a, 0x9e502fce, 0x5fc7f0c9, 0x6785efe3, 0xb7847676, 0xadd24c49, + 0xac75161a, 0x3ba77a42, 0xf417d31a, 0x0f687553, 0xe3f95e2e, 0x0be6ed77, 0x9d4c381a, 0x9500f65c, + 0xcb5416ff, 0xd6508bc4, 0x6ff216ef, 0x8b32f752, 0xf5803432, 0x9c57b8ee, 0xcb9fb23d, 0x787b85cc, + 0x6a72d537, 0x05e28e29, 0x07b61706, 0xf7da47c5, 0x5bf25bee, 0xf20b01ea, 0x374646eb, 0xf2ed3808, + 0x3d4783e8, 0x9ea708c1, 0xcdbd6c03, 0xbf12de5f, 0xb4656a44, 0xb6e9dbc7, 0xda04e8ed, 0xce719aed, + 0x05c0e654, 0xce9671c1, 0xe513de6f, 0x6edc4505, 0xb29d8c39, 0x7c09caf7, 0x5f62994e, 0x29f59f8e, + 0xa650be31, 0x8bdfb082, 0x0c9abbf2, 0x09e593cb, 0x6f77124f, 0x1350c849, 0xe00db5f1, 0xa20e46e4, + 0x17a73461, 0x1c1e1c6f, 0xff14afa7, 0x4765a512, 0x0ba70171, 0x5f5b8623, 0x062a00dc, 0x73633701, + 0xd4321239, 0xc6ba027f, 0x3d97247a, 0x7a6a87f8, 0xe8a90e4d, 0x00223853, 0x6287763a, 0x0e634b6d, + 0xbc0a11e1, 0x922361f8, 0x972c8ec5, 0xac34e048, 0xbb274239, 0xe4a22356, 0x113e46ba, 0xe9c482f9, + 0xbda3d52f, 0x72068200, 0xf400a4f2, 0x135e223a, 0x3bd8f557, 0x88e27764, 0xebe6d2b9, 0x6c53af0e, + 0xd7d1acb0, 0x49b84bd7, 0x7f96ae95, 0xedb17ffa, 0x58e54e9a, 0x2d43df1d, 0x2d7cd42f, 0xce60b830, + 0xa2fab59b, 0x0b3fdf1b, 0x2ccd01f6, 0x2667d1ac, 0x94748b6a, 0x034a09ee, 0x9518a2da, 0xa4e079a0, + 0x71f2a968, 0xf910551e, 0x1d9ff54f, 0x55e69697, 0xc07f346b, 0x68ff21cc, 0xa262eded, 0xa3a07c4f, + 0xbfd6761f, 0x7ecb492b, 0x3687275a, 0xf458697a, 0xd61c4484, 0xe183a112, 0x227c8e01, 0x8e231404, + 0x4d4dad85, 0x90e7bf42, 0x3cd07870, 0xccc0a6d8, 0x91b114c1, 0x436241ec, 0x4234b3a9, 0x48ed9ee1, + 0x06c416ef, 0xf8c8c42c, 0x4559a135, 0x391f82bd, 0xc0719212, 0x8e44d12e, 0xbbe54335, 0xd8787b12, + 0x22739836, 0x67fb75dc, 0x19b96c22, 0x9f5be98f, 0xc18bd918, 0x3c9876eb, 0x3bef6792, 0x543c0e31, + 0x8d5d2cf8, 0x29551a68, 0x11c9ff57, 0x8ba76a52, 0x5183906d, 0x2ee3bd47, 0xc7494977, 0x90c80017, + 0x4f37c18b, 0xab783fe3, 0x933ba514, 0x0c1ad599, 0x496e0cc3, 0xf2e7aeab, 0xd890a989, 0xb559f60c, + 0x8bc95ba5, 0xe25aecd7, 0x4f7579ce, 0x275c8b6d, 0x455acb1b, 0x2887e69c, 0xb1afdc3c, 0xc2216871, + 0x339ea2ac, 0xe5f870b7, 0x770a70a6, 0xee92c33c, 0x52143413, 0x0f7bebd2, 0x502458b5, 0x5299f2b8, + 0x96262b37, 0x13d4d10b, 0xa9996a49, 0xa7f72337, 0x4e23a1a2, 0x234c4b93, 0x6636dc25, 0xb51178fe, + 0x2f7359c8, 0xa4d25c24, 0xca7cfb63, 0x22dcf3ae, 0xb109e81d, 0x7a839b88, 0xaaedc09b, 0x9676e15c, + 0xa8822637, 0x12832d80, 0x9440c2b5, 0xba0a8625, 0x6783ceae, 0x84df17a7, 0x45792752, 0x3b719f9a, + 0x22f4fab3, 0x573e9f38, 0xe7bab930, 0x251f9e60, 0xfb90f814, 0x95af1b71, 0x4b4a2cdc, 0x3ec230f7, + 0x03ba8023, 0xcc6b107b, 0x9a64c32b, 0x5eaed7f4, 0x8837fc93, 0x23adc630, 0x5d0bd4bd, 0xad0be9df, + 0x895c9ebc, 0xdd284ecc, 0xd9302d1c, 0xf16db81c, 0x11032690, 0x89d952c7, 0x303cc333, 0x6305fee3, + 0x403778e4, 0xdb542026, 0xa32644fb, 0x58f4fa7b, 0xfd2bfe04, 0x00e829b9, 0xbf8d28c5, 0xaa8ac539, + 0x062d9677, 0xc9fe5823, 0x5e805686, 0xb4dbad67, 0x5118900f, 0xd8dce04e, 0x6980f6da, 0x605b6073, + 0xb16fc2ef, 0x1c45d987, 0x387eb0d0, 0x07de80ca, 0x14ffd091, 0xcaf01f54, 0xa9592de2, 0x4a28c40f, + 0xdf595526, 0x7750e788, 0xab215998, 0x5ae8e450, 0xbc4628c7, 0xe0311356, 0x74c75cbd, 0x381cd272, + 0xd0c75aba, 0x33b92f7f, 0x4c84e9d2, 0xc730d1ee, 0xa58f9bc8, 0x294e06ed, 0x78d406f0, 0x99cee88a, + 0xf8f424d8, 0x07735da5, 0xdb66594d, 0xf17d3702, 0xccdc6be6, 0xd0e85b01, 0xdc7e14fc, 0x6a58f2b2, + 0xdebee93c, 0xcd1b18da, 0x66fcd386, 0xe3c63bd8, 0xcb9693b4, 0x5f94a123, 0x5e3008c7, 0x56897fe0, + 0x344f4fa9, 0xfa4aceb4, 0x60454cb2, 0x3dd2719e, 0xb03e66a6, 0x86f2c159, 0x0d1a69a8, 0x5baafdaa, + 0x9d0c399e, 0xc4441a78, 0xe1baeab0, 0x027aa411, 0x0d2d2726, 0x237db5d2, 0x0e4b55ef, 0x06f1d2ea, + 0xdfcd3920, 0x30fd17c0, 0x9307bc28, 0x52019b15, 0x68ab86d8, 0x9d272472, 0x51d99234, 0x1d3e7ad1, + 0x9ce3b0f1, 0xc3896d48, 0x4d30fcef, 0x9cc41a4a, 0xc881f2a6, 0x072c6060, 0x6e0aa8d6, 0xecb57f8b, + 0xbc4396a6, 0x67cc8d9c, 0x79428a90, 0xa8d3d454, 0xa78a3a92, 0x668394c3, 0xf691f7ab, 0x644a8084, + 0x15e9f7b1, 0xd0283d1d, 0xd618e0da, 0x5ab16cd1, 0x9be09107, 0x2321f04a, 0x296a760f, 0x43d2734d, + 0x400252a0, 0x98046e70, 0x9332ef49, 0xee8ff9dd, 0xf7ca9aae, 0x5edb7d9c, 0xbb3e61a6, 0xb945b772, + 0x89ddafb6, 0xea8c812f, 0xdf0aaf46, 0x5fad5db9, 0x574a8c13, 0xa2ef73bc, 0xd57dc59c, 0xccd50750, + 0x7d1f84a1, 0x1a5f3821, 0xac460f7b, 0x8e4321d8, 0x19805a50, 0xfe5da53d, 0x71b8a671, 0xf07651b2, + 0x66dfd8ee, 0x2a3ff1b9, 0xb2ae3d1f, 0xc9a13245, 0x57f4b89a, 0xecf219c3, 0x2fa07f35, 0x56af2f51, + 0xd9de899f, 0x94ae0c48, 0xdce1ed4f, 0x434d6b07, 0x78d42632, 0xdc4ae487, 0xd5dd0c33, 0xd94214d8, + 0xf5f1b8b2, 0xfd75b1b8, 0xa3167ef9, 0x7440c919, 0x2c3cbd73, 0x4d7c3ed4, 0x5a8a2439, 0x5651d9dd, + 0x81d78fef, 0x511e49f8, 0x37d1b6d9, 0xef0db11a, 0xdce83167, 0xecfd19c2, 0x4025f9aa, 0xea2aab71, + 0x2c358824, 0x0fbd7dbc, 0x7fb0bf3f, 0x416ad42b, 0xf3554942, 0x8d8e6cdd, 0x19c28c1d, 0x086f01b0, + 0x1647d74c, 0xd29f612d, 0xa2c8cd2e, 0x7ba43c72, 0x9b47d4bd, 0xe23f6d05, 0xf05f7ad0, 0xd1c90b9d, + 0x28b02afb, 0x0f8ffd51, 0x811f949f, 0xda7da7ec, 0x2141c178, 0x8e72bfce, 0x1f0749b6, 0x348d0b99, + 0xfb49a559, 0x789148f4, 0xf7a40e7b, 0x95873cab, 0xe537f637, 0xcf133e64, 0x675e69a4, 0x84950774, + 0xc4c22e7b, 0xe87810c3, 0x20bf7c68, 0xbe679f8b, 0x37143d16, 0x8dd3bd19, 0x1daaa55d, 0x146a25ee, + 0xf2a2648c, 0x589dc2eb, 0xce1a8a70, 0x47f42c4c, 0x9ba151ed, 0x92f2cbe7, 0xff7269d8, 0x888243fe, + 0x804c4c2c, 0x06a6d106, 0x46224187, 0x2902eaea, 0x0286113b, 0x7a80e85f, 0xd5fea693, 0xcc3a1bb5, + 0x1f39b176, 0x62c5b20b, 0xc515a403, 0x52ebfc63, 0x17618491, 0x2f696ddc, 0xecdbe4db, 0xdf691a46, + 0x718b3a66, 0xfc075435, 0xeac3231b, 0x00f12817, 0x5169468d, 0x853f1278, 0x5cca8aed, 0x38e37399, + 0x2391928a, 0xa0885e20, 0x97c5361a, 0xc36fae2a, 0x07f12b16, 0xfc880060, 0x52a384e9, 0xe0ba09d6, + 0x7ddac4f6, 0x9d83cb59, 0x1b0fbe00, 0x46a6d3e5, 0x99154dea, 0x4a09bd0c, 0xcfeb213c, 0x2f4f4e10, + 0xeab30688, 0xa0f15ce6, 0x6ccefe1c, 0xf0201db0, 0xb2bf7723, 0xd7826fe6, 0x36a90b83, 0x48334715, + 0xfb525952, 0xaaeeae38, 0xef597d47, 0xe98a61c5, 0x15b82631, 0x773d72d4, 0xe924c92c, 0x2cc7c5bb, + 0xced5985d, 0xa1cbd426, 0xe26c40dc, 0x5a4f6817, 0x944a8bf9, 0xa880cf81, 0xf7bc0ac8, 0xe8ff3233, + 0xb3b21989, 0x03fe1c1b, 0x8aed801b, 0x39d54bb9, 0x02cd3547, 0x6e790bc2, 0x41e840f1, 0xac8b06f0, + 0x782e7e30, 0x31d42456, 0xe5147fb5, 0x43c99991, 0xbb566554, 0x0394477b, 0xb2282068, 0x8f8636c9, + 0x4d128a2b, 0xcd4c2a8e, 0x8b6518a3, 0x0ff648ef, 0xbc50d920, 0x87254ed4, 0x17a5a647, 0xbf1e6e50, + 0x46838a28, 0x5ded9106, 0x4743217d, 0x58e5c631, 0xb88cddb4, 0x4980dcf1, 0x6c622d5a, 0xc1ab086f, + 0x34e1de7f, 0xb6ee4ed0, 0xe2bd569f, 0x67091e71, 0x7f9fad8a, 0xf01db8a4, 0xf97e1b66, 0x0b1a3699, + 0xbf7580b3, 0x49af2d2a, 0x773a08d4, 0xef5a4c35, 0x8ca1f59d, 0x364bfc98, 0xa400cf31, 0x4e10a742, + 0x1c815264, 0x4b162483, 0xc6fe3bf4, 0x8c6c9a9f, 0xe31446d1, 0xfec173fc, 0xaecb431f, 0x4681cc4b, + 0xc5da23d0, 0xb6072aa1, 0x5362db56, 0xcd8ba5d6, 0xa98d75b3, 0xb1588c1e, 0x15b92596, 0xaad37f1e, + 0xb2ada985, 0x56602b97, 0x05b5edfb, 0xdaffa1b9, 0x3766a907, 0x888839d6, 0x06d86bee, 0x773818a6, + 0x719c7a73, 0x2e3827a7, 0xe5623b91, 0x454ed8b8, 0x525960e9, 0x5b6bff88, 0xdf065aff, 0xb9cc093c, + 0x813049c8, 0x957d628d, 0x34e87443, 0xb5941ee7, 0xc97d51f4, 0x3bd34e3e, 0x9554960d, 0xb93c1fc9, + 0x8457a5e9, 0x39d6a8fb, 0x5967f773, 0x7a4e095a, 0x2fd72789, 0xa6b23dd0, 0x38ec990b, 0xad51d8ea, + 0xa227d0cb, 0x8865f52c, 0x1345d282, 0x1e06c4d5, 0x8107548b, 0x130ee7f7, 0x8c895fe0, 0x2637b6aa, + 0x9195134e, 0x7a3d2c0f, 0x97b3ad31, 0x05ed7b23, 0x462462c1, 0xc7e2e7a7, 0x7438940a, 0x4702afdb, + 0x668deeb6, 0xf0165758, 0x846803e9, 0x4c7f846c, 0x82037b54, 0x107ad082, 0x1922e84b, 0x1e437389, + 0x873eed7d, 0xea13846c, 0xa71bb5b3, 0xe70942fc, 0xa64cdfc7, 0x2270bc12, 0xe0401ca8, 0xff4f0ef2, + 0xcc8c9761, 0xe623dcd5, 0xf3f04d99, 0x0ed61b27, 0x96ff6073, 0xef6e0ca7, 0xb4c7fa1f, 0xa7a54015, + 0xfb91221a, 0xfef95e62, 0xd8258350, 0x53a9e651, 0x9f07425a, 0x6323e61b, 0xf6da7cef, 0x652e5eff, + 0x14d97051, 0x63d43aec, 0x411e25ca, 0x90db8f6b, 0x6affaa95, 0x339188f7, 0xb8a66953, 0x6e0ec06b, + 0x68ed2b46, 0x1bcaf321, 0x664387a4, 0x6aa9a3f1, 0xf880b5b3, 0xa18f8089, 0x99680a6b, 0x60ea820e, + 0x37c9350e, 0xfaeb9c70, 0xc48ac8c6, 0xdf749aa7, 0xa897cbd9, 0xf681ee0c, 0xdbbc1f67, 0x50470b29, + 0xc9d6b9ea, 0x4ced8f7e, 0x5f629098, 0x9278d997, 0xc3ecfbae, 0xe8e9c24e, 0xc5e7990f, 0x6c69c620, + 0x5cc9a0a1, 0x0023c927, 0x77eebe8f, 0x24ff07c3, 0x264f68d4, 0xcb9e2196, 0x1cc6f580, 0xcbcb106a, + 0x76abf569, 0x5a7a4fb9, 0xba847835, 0x2dbf6566, 0x889762c3, 0x9df5d05d, 0x7c096981, 0x9beef53d, + 0x3cd9d2a5, 0x23cc46fd, 0x7ac46a29, 0xacbdcc3d, 0xffed8ca6, 0x11d03e94, 0x6e007895, 0x8796f9be, + 0x7cf9575e, 0xa213ba14, 0x76f5d362, 0x96f61a97, 0x4d409247, 0xb5b091fc, 0x92aed167, 0xdb51678c, + 0xd202be34, 0x450fdf46, 0x2e074b8e, 0x085d486e, 0x91a93b00, 0xe58a9d2a, 0xa1a2ac9f, 0x18f91b88, + 0xd306585f, 0x422c792e, 0xf0e91d4d, 0xaab55eb5, 0x5c300968, 0x807fca16, 0x80fafe16, 0xf147c06d, + 0xbd9f2f10, 0x69aecfed, 0x8177dc22, 0x56d08a75, 0x745b3f63, 0x6acb3caa, 0x6ec6e284, 0xe5029182, + 0xd81a87c9, 0xae8839a4, 0x35d420de, 0x29e91d7a, 0x05076671, 0xd64f54d3, 0xd5d3c247, 0xdc6ad746, + 0x3d23750f, 0x07020cf8, 0x64f7a71e, 0x5aa3666e, 0xfed4a4d6, 0x57d93ca2, 0x1589d675, 0x5e1110ed, + 0x1c93cf54, 0xdad04f97, 0xe32437d4, 0x381cf64d, 0xaa49fd21, 0x198d5992, 0x6629cce0, 0xe511ecf9, + 0x8edeb7be, 0x942c4da9, 0x9a161adb, 0x0eae2a8b, 0x6e40776c, 0x299c6c71, 0xa71b735b, 0xdcaec854, + 0xc337ee62, 0x1cefbf61, 0xd72babdb, 0x261ca524, 0x2565ad8e, 0x764698e8, 0xcdbab2e0, 0xb8fe1b1e, + 0x57bedd28, 0x21e3579e, 0xfca56873, 0xd8b45021, 0xfe7d80f2, 0xe6d749c7, 0x74a9f06a, 0xe6731b3c, + 0x499f6fdd, 0x97862edc, 0x163503a0, 0x2e124c3c, 0x73fba2b1, 0xd8722684, 0x53aa3a55, 0x3327517b, + 0x7a4da0f2, 0x106e2204, 0x0c9cc9c8, 0x86cb56d6, 0x3c578bc3, 0xbb36882b, 0xf5ff646b, 0xe19d074f, + 0x2954723c, 0x5dd00562, 0x17f9b97e, 0xec7091cb, 0x8e8a726e, 0x042f46d0, 0xf91ec96b, 0x672e1e1e, + 0xd0fca573, 0x9b421129, 0xefbb6568, 0xfcf2c9af, 0xb83b7dd5, 0x194e557c, 0x2f35e749, 0xb0252db8, + 0x43325dcc, 0xea07329c, 0x31dade7e, 0xc9a5b5dc, 0xad99efa0, 0xa8607033, 0xbab752a0, 0x800718eb, + 0x70dc4dbe, 0x80a6638c, 0x54802c4e, 0xe2d4d185, 0xfd0e69ee, 0xe47a722a, 0x455ca996, 0x2e97e53e, + 0xf1fcc6e3, 0x22f7495f, 0x0714c6c4, 0xf3e1906f, 0x10d31c81, 0x31214249, 0xb73396af, 0x728c0f72, + 0x76e5ddda, 0xbfb6a1b2, 0xee7ae184, 0x84b84d4c, 0x41ed918d, 0xbc26a73b, 0x9992422a, 0x62c2a5ff, + 0x2dad5677, 0xc3d53ca5, 0xe5bce951, 0x9ee25596, 0x7125adde, 0xcc4278d6, 0x5d119bb2, 0x9c733d4f, + 0x88690104, 0x041fb19d, 0x326ff753, 0xfb816829, 0xba3d9da5, 0xad3b9879, 0x1d91ef2e, 0x46c96128, + 0x4879ba60, 0xddd8f68d, 0x63e2720b, 0x1fd990fc, 0x3e92bc48, 0x4778d38f, 0x3e7e5437, 0x9b1e39a2, + 0xba6e7beb, 0x5ab9cb6a, 0xcfe539dd, 0x08d38c75, 0xb5ad9c31, 0x959c2028, 0x8b83069c, 0xfe98adf6, + 0x48335cda, 0x8e6e1ce0, 0x218e4d7d, 0x0387ad41, 0x4d728606, 0x10698f28, 0x05226f43, 0x0e26fe5c, + 0x1068abfb, 0xe7077847, 0xad336572, 0xf3e2246d, 0xdee2ca49, 0xd50916cb, 0xab3916a4, 0x647007c2, + 0x2f7d587b, 0x754475cf, 0x4cdb4d22, 0x5ed5b590, 0x53d5a891, 0xe8ec3c45, 0x361c18b8, 0x7846d6e7, + 0x56ed394e, 0x5ec8a769, 0x80a8f721, 0x7a364bbc, 0xfcc1fbb4, 0xbe4a182c, 0xdc243329, 0xac015c14, + 0x4aa174a8, 0xdde1a35e, 0x3adcf63c, 0xa51278ff, 0x5c5b3d19, 0xc8ec638b, 0x87a4cfbb, 0xbefa59d3, + 0xcaf68a17, 0x00572ed3, 0x8773f695, 0x2780ca84, 0x62f3f45a, 0xdacd73c3, 0x94983fe2, 0x70f464eb, + 0x70ba1a39, 0x99acd7cd, 0xad0d33a3, 0x5acbd5b4, 0x9ce53e5a, 0x6ef8a11e, 0x488c70cc, 0x0ecce251, + 0xc5c1a489, 0x5dcf4315, 0x4de942f5, 0x3c5731d3, 0x8852133c, 0x48c54b5f, 0xf7b25ab5, 0x81e50059, + 0x4ed1a2c5, 0xf94dd9c5, 0x3d8000a8, 0x49ebc843, 0x304c9039, 0x025dc234, 0x55f69391, 0x5bb07bb1, + 0xdafc278b, 0xc6fa2ff5, 0x6ed0edc2, 0x906f88c1, 0x11261ef8, 0x89f35533, 0x36b0a15e, 0x7ac36a46, + 0xbefed218, 0x3d6940a9, 0x792ab8e1, 0xd26c4300, 0x6f3f661f, 0x0bf6e592, 0x82248683, 0x3a897a96, + 0xe69e339b, 0x83dd922d, 0x234d88eb, 0x969cc2c7, 0xbdb49822, 0x5e686fcb, 0x49260353, 0xd19b9f43, + 0x84145c32, 0xc04a00bd, 0xb0825e8d, 0xfd9b248f, 0xcb34a34b, 0x2d014168, 0x34122ffe, 0x42492cfb, + 0x227d97f3, 0x676614f3, 0xdb3bd658, 0x5c07f77e, 0xb24855fd, 0xa8b1b0a6, 0x6504b305, 0x0f1ed05e, + 0x0fadfea2, 0xa7b932fb, 0x4435d744, 0xa6e33ae3, 0xf6a922ac, 0x7c002385, 0x0c6bf025, 0x1ca945b9, + 0x16bf95d1, 0x11780b67, 0xa36f6ec0, 0x4e86227c, 0xe371353a, 0xe7008739, 0xf302f412, 0xafcb0af0, + 0xbc16c375, 0x3f0f450d, 0xb7694392, 0x526981f2, 0xb7f8338f, 0xccf670c1, 0x16103ad7, 0x99e09440, + 0x50eac6b8, 0x9c165744, 0x76d26ccd, 0x23550314, 0x8a684201, 0x3466effe, 0x4734573b, 0x9e2ceb00, + 0xa41e96d0, 0x2b3dbc21, 0x9cdeac2a, 0xc1a19a52, 0x77d536b6, 0x14a7c8f7, 0x8bd7b1e3, 0x55f0b240, + 0x8d69e103, 0x472f16dd, 0xc13e260c, 0x248da531, 0x3a2742fe, 0xa9cac7fa, 0x81ea141e, 0x8295b2db, + 0xc2f8cf92, 0xa4b87528, 0xf059d730, 0x9d05bfe7, 0xdf89c564, 0x48ca5595, 0xffcbb05c, 0x2e32b1c5, + 0x617d0871, 0x5e48b175, 0xabfa8e9c, 0x5076b918, 0x9b9edd22, 0x44a55b87, 0xb9673320, 0xa9de22c3, + 0xe0d9a7d3, 0xd0c1c232, 0x90c9c138, 0x81463636, 0x1162f338, 0xbe21600f, 0x865a2820, 0x2a4fb54a, + 0x1a88e545, 0xa77b56ed, 0x15ec8aa9, 0x1f696cc1, 0x1a63f6c6, 0x32945820, 0x26d8031e, 0x8df64f1b, + 0x8e196717, 0x87a1f05f, 0x5259c1b1, 0xaf52f5bc, 0x9af99184, 0x29c95b63, 0x60133f74, 0x459bc215, + 0xd142583a, 0xdb3c26bc, 0xb3ca79f5, 0x7ea854a7, 0xd6bc2fef, 0x8da4a1bf, 0x7a746361, 0x61a4eab7, + 0x1f42d8b3, 0x52a5859b, 0xe2f67e77, 0xf5ff9b2d, 0x1f4d4118, 0xae3895f3, 0xbc5fcbc2, 0x06da04e8, + 0x4bf22cfa, 0x9197a0c3, 0xbdf1c177, 0x38898ba2, 0x7898418b, 0x2fd3e297, 0xc4d262b0, 0x9d1bb27d, + 0xd4f3996b, 0xb6cc295b, 0x03046390, 0x498b67c4, 0x670a559d, 0xd0636760, 0xfa840b6b, 0xf23504cf, + 0xcd81053d, 0x718dd794, 0x2a1ef165, 0x07329dcd, 0xce4d2ce2, 0x1a62ce01, 0xf4dc0649, 0x546cc1e6, + 0x283b3165, 0x3df65059, 0x7fe7b970, 0xd1a329dc, 0xfe06b885, 0x5ca8ad02, 0xf5185351, 0xf9429922, + 0xb3d772a7, 0x640dce7e, 0x40fc1a69, 0xb1976db2, 0xd70764b9, 0x14dda779, 0x2b631294, 0x36aabbca, + 0x3fdab71f, 0xe9154678, 0x99ddc249, 0x85665844, 0x28af84b3, 0xef7d1bba, 0x4296066c, 0x2f64f22a, + 0x2815b6ba, 0x30e918cf, 0x38edbb60, 0x25929bdd, 0x9dda41a5, 0x3577a1de, 0x73583f49, 0x99994c01, + 0xd30e6883, 0x52801417, 0x06ce56f8, 0xad9f5c79, 0x3cda5491, 0x28df265d, 0x678fc68f, 0xcacd12b5, + 0xccda31ac, 0x0eb60ee3, 0xf22c868f, 0x3507ef8b, 0xae3a0061, 0xffe7c30b, 0x889aa785, 0x465cfe2a, + 0x628567ed, 0xa4b6860d, 0xe66628eb, 0xacf3a098, 0x1194e266, 0xe9168752, 0xa75c2059, 0x744ff7cf, + 0x41e46ba2, 0x581f0bbf, 0xbcc57035, 0xfa1ce1b1, 0x82ae9771, 0x1828e1b8, 0x8092c4ef, 0xbaca0da1, + 0x07113bdf, 0x6561152a, 0xe5c7e487, 0xe6c072eb, 0x856513f9, 0x0dffac4a, 0x5dde4371, 0x227a9902, + 0x0d522696, 0x2db18338, 0xd7b9f11c, 0xa7348ddc, 0xb49d22cb, 0x6ca80d4f, 0xad769164, 0xd526c0c1, + 0x95a96bd8, 0xe5e47bac, 0xc248abb4, 0x4361a047, 0xfac186c9, 0x34b58a49, 0x8ce9384b, 0x17ee9b0f, + 0x24d54781, 0x041e2708, 0x078e9f1c, 0x894a92f6, 0x29802d58, 0xad57b5a9, 0xa2ac99c1, 0xfa5850bc, + 0xe764e676, 0xe9c3c865, 0x248a9dc4, 0x1dafc398, 0x1bf24aac, 0x22f427d4, 0x1dac829e, 0x312bc7b6, + 0x210fda18, 0xd1422be4, 0x5b4aeb4c, 0x8c13eec4, 0x524cfa16, 0x813de15d, 0xd2fdd45d, 0xf053dbba, + 0xef0849f4, 0x12c2821e, 0x4be0bc52, 0x42f8b50c, 0xc81803c5, 0xed04d837, 0xc564e184, 0xaa0bd12f, + 0xa4d8750d, 0x45fa59f4, 0x84f17d60, 0x482763ba, 0x17a1f37b, 0x7235cc52, 0xed293862, 0x3c819e8b, + 0x4d92c043, 0x336a293c, 0x0c5b362d, 0x5f641930, 0x11dcc97a, 0x327babbb, 0x6c9402fa, 0x1df77546, + 0x172d4111, 0x17397692, 0x68699048, 0x11beb3f4, 0x2876d345, 0x961ad4bd, 0x6db193f8, 0x691a4f01, + 0xaf988b88, 0x6ac80609, 0x9c0da473, 0xf42a28a4, 0x9230a0f8, 0xc3a090fc, 0xcdb38769, 0x2650d6f8, + 0xfd74f90a, 0xde124c12, 0xc9cec5be, 0xca081c15, 0x0f64d2ed, 0xb3e3e6e7, 0xec408879, 0xf0b92835, + 0x3500d196, 0xfe12f8f3, 0x60dcd146, 0x073a8673, 0xc3996f3f, 0x2ecbbefa, 0x1bd36957, 0xcd16154a, + 0x9ee8c4ff, 0xefce5e4f, 0x0398bca0, 0x080a45e3, 0x3798b508, 0x832c9474, 0x933f119c, 0xd88b03fc, + 0xc99ad3e3, 0xb5482ce5, 0xe03e5674, 0x17296855, 0x3dcf06dc, 0xe096a489, 0xdf595d9e, 0x9f0b74a3, + 0x128c080b, 0x19bcf0b6, 0x6f1019d9, 0xa1fb8542, 0xf8bcc37e, 0x868db386, 0x17247496, 0x8f572200, + 0xdc935b52, 0x21788cf3, 0x78140477, 0xb8b93f50, 0xc17aecf2, 0x16f72b90, 0xb0294391, 0x6fb74c2c, + 0xe5af67ba, 0x0e208494, 0xd5c20488, 0xc6f2cadc, 0x6eea1c93, 0x27548903, 0x5ed60145, 0xe9edd2a3, + 0xa298a0bc, 0x29191132, 0x4e940c22, 0x2077f7a9, 0xf7b89b28, 0xbf8b92f2, 0x4ff21885, 0x28908b98, + 0xa1c56688, 0xa6be3691, 0x61ee75c3, 0x5821137c, 0x43e4f883, 0xacddb518, 0x4d9a04b1, 0x20aef6e5, + 0x2531822d, 0xc7b23d22, 0x602f04b2, 0x88ae1850, 0x776b106f, 0xa6576e8c, 0x6b701333, 0x839d8db9, + 0x34609105, 0x2563349a, 0xdd8419ec, 0xe2ed64a7, 0xd9116bf2, 0x49ab50c4, 0x58536694, 0x820d4748, + 0x6ec12437, 0xddc81e2e, 0x158501ea, 0xcc37200a, 0x82f9d9c5, 0x83406e07, 0xb1663f7f, 0x2517ef79, + 0xfb1406a6, 0x38b14d3b, 0x54afd700, 0xe34954dd, 0x4c675f68, 0x51a629b9, 0x0180144e, 0x95e22074, + 0x8d5d718f, 0x74ade629, 0x0af12b2d, 0xbf03c7b1, 0x3a1d88d9, 0x1f68903f, 0x1ef674a4, 0xf87f3453, + 0x9ac497da, 0xbe778830, 0xa2855f35, 0xb4bdbb09, 0xee0f73ac, 0x54251363, 0x03d03cff, 0x8944c42e, + 0xd629b66c, 0x8aabcebb, 0xc7eb0901, 0x8b6fa5b2, 0x0f0c34c0, 0xb6373d22, 0xdbc1b6c3, 0x432891c1, + 0x95653b11, 0xe0f5a8b7, 0x9fcafe62, 0xeebeccd2, 0x28045ffe, 0xb05c0dc1, 0x80cbe811, 0xa972f006, + 0xcaaae4e5, 0xdfaed9f4, 0xd3ec0c70, 0x6735cc52, 0xc7d4b6bc, 0xbd5617c4, 0x32ddf9b4, 0x1f94438e, + 0x6483e478, 0xa49a4513, 0x72ae63e5, 0x98a3bfb9, 0x1ae72495, 0x5f1be0d2, 0x2897aaf2, 0xcee5b05c, + 0x8ad6f7ed, 0x4246659a, 0x366e0e04, 0x357d9510, 0x48767bd6, 0x74d1cd16, 0x1ab22436, 0xecba8b97, + 0x9a0d71a2, 0x5172aa40, 0xf1d80f4d, 0xcdd90b5d, 0x20b88dc5, 0x2aa3c31b, 0x97718b39, 0xcb77ad3d, + 0x304fde0a, 0xe87dc764, 0x3e501d9a, 0x15829421, 0xd6334736, 0x247194ed, 0x307fc137, 0x50973462, + 0x1d4eeca9, 0x7840fc26, 0x489a61be, 0xba57590a, 0xbdb5459b, 0xed1d94c9, 0x5a14e383, 0x34f0b358, + 0xd3a5bd8a, 0xae16f1d2, 0x49f785e5, 0xfafa9c37, 0x1591ecf5, 0x93ed6eaa, 0x77164451, 0x03555a48, + 0xb8cbf809, 0xd7674343, 0x3222985c, 0x145b8be2, 0xe80754a0, 0x25e619a3, 0xe81c8bd0, 0x2c84286d, + 0xe6cb77a4, 0x0cd99d1a, 0x54209605, 0xc1c685ca, 0x23dd11b0, 0x655a978a, 0x96051fcb, 0xeeedc71d, + 0x1d22da26, 0x257bd92c, 0x34c7bd16, 0x6a32198b, 0xbc6a724d, 0x67bcfcb4, 0x0787d096, 0x06cda87e, + 0xf6368eed, 0xd3b86c41, 0xbb3a26d9, 0x3461d756, 0x083e9496, 0xeadf9880, 0x06810f95, 0x14175682, + 0x30e68c51, 0x05c13c4d, 0x804236af, 0x746dc904, 0x60b37411, 0x465d7581, 0x9cde253b, 0x5d9dcf0d, + 0xbf1f70a3, 0x76c6d6bb, 0x977906e1, 0x2b628d96, 0x717c6f64, 0x16b0e930, 0x5516b880, 0x839f4a32, + 0x4e099f25, 0x3efac1e5, 0x4c015e5b, 0x662d75c1, 0x6b36a2f8, 0x76716753, 0xd1c764b1, 0x638e0dd6, + 0xf629b5e6, 0x654a25fa, 0xf51af768, 0x213c2417, 0xc0acd051, 0x56a90734, 0x4a0ad066, 0x83dd78fd, + 0xb9dec720, 0x99d6664e, 0x694fb4e1, 0xf7b2138d, 0x0194ff90, 0x0a5bbe61, 0x78017a51, 0xddd12363, + 0x216a836d, 0x87cc0900, 0xf890406b, 0x8adc3cba, 0xbddb406f, 0x784cc3fc, 0xcffb49fb, 0x9e9c28c4, + 0x9a1b26c1, 0xeb57ed02, 0x6f96315c, 0x1d7c874b, 0x0a68d3ed, 0x2a2770da, 0x6e8ab61e, 0xebbb0c25, + 0x34c469f2, 0x0f893097, 0x588bf204, 0xf8e7bb49, 0xc3c65cd1, 0xb4571dce, 0xc31203f0, 0x82be88ce, + 0x84b19f02, 0x69eced49, 0x5d346a66, 0x270491ae, 0xd4b2e991, 0x0ce7fbb4, 0xcb3e409b, 0x77d29384, + 0x45d259c4, 0xd609ebc6, 0x08bd0204, 0x719313f6, 0x7f50392c, 0x560d1883, 0xe4237b48, 0x00a88c80, + 0x6afff35f, 0x32355996, 0xb7fd3043, 0x9d5b5379, 0xffd9ec52, 0x75e60cdc, 0xe2af2f4b, 0xdcaf3530, + 0x20b202b7, 0xa46a98df, 0x02f28020, 0x7535874b, 0x36fe4133, 0x7bf52c6f, 0x12a44ac7, 0x68c1c875, + 0x002acfc8, 0x4be7c00a, 0x658ee6db, 0x4ed832a2, 0x1dddb718, 0x8bb8af66, 0xd9d8acfa, 0x4fc08950, + 0x409a6de8, 0xf7020f58, 0x81314a75, 0xa4ed8462, 0x2d192c0a, 0x7990f89e, 0x491c3e59, 0x3d553380, + 0xd9f1522b, 0xd5367da7, 0xec8915b9, 0x437ff4f4, 0xbd4d1648, 0xd0c847d8, 0x58754c3d, 0x8b2d344c, + 0x0815d26d, 0x3b679ee9, 0x890143cb, 0x3c995193, 0x6df6e39c, 0x9e0f220b, 0xe0dd9953, 0xee968a8a, + 0x79c69e5b, 0x674af3fc, 0x1db0b7c1, 0x3f3dbcc8, 0x7594b48c, 0x879f3f2d, 0x38f94af2, 0xa02658a2, + 0x3594d6c1, 0x1ffcd480, 0xd76703e6, 0x661db3ce, 0x237e29d2, 0xc3820ce3, 0x3039a292, 0x5a94840e, + 0x9888db67, 0x7cbde226, 0x5c95305c, 0xa1dfb9b6, 0x777a61bd, 0x8b371b61, 0xee545413, 0x81c3a2e9, + 0x31e87455, 0xab7ffc7a, 0xe77e1318, 0x934b5ab6, 0x25dc258b, 0x44a0eb4f, 0x95d235c8, 0xbc149567, + 0x2f654445, 0xf807ed75, 0xc55bb620, 0x1cc28eb8, 0x1a12a7f5, 0x5bd2cfec, 0xc2836f9d, 0x99a2b4f7, + 0xeeaf3dc9, 0xd5d718e8, 0x334e8673, 0xcca61864, 0xdefe4e5b, 0xdd62173a, 0xb8510554, 0x5c7b6f5c, + 0xdb4f03cd, 0xd607d449, 0xd8abfd0f, 0x98b4dc80, 0x7c12843a, 0xc0e8debb, 0xf62fe2bf, 0x34f7676a, + 0x63324cfc, 0xc319d9f0, 0xb94f4c75, 0x61ffbbe2, 0x310526e9, 0x64f13a41, 0xdcefc089, 0xca22496f, + 0xb43f0ffe, 0xab270c25, 0x349c7b86, 0xd4f776a3, 0x1f5cb898, 0x5ae713e6, 0x57b43370, 0xb1b785b0, + 0xf3fe9d34, 0x917133c2, 0x11c92630, 0x655db49b, 0x1728e59b, 0xef6f96cc, 0x0ccdf2c3, 0xb62b9d8e, + 0x86be2039, 0x1b8f7b66, 0x7b678064, 0x97bf2aa8, 0xa0949236, 0xf7680453, 0x23bca018, 0x8afaf4ca, + 0xf777da8b, 0xda35095e, 0x595d2da9, 0x6bf32e57, 0xfb729ace, 0x2d2a0d6a, 0xff9ce71b, 0xf1403c13, + 0xa8c3e1e5, 0x18e5a4de, 0x9b1249b0, 0xb4ed44be, 0xa4cdfa5e, 0x2d76ea2b, 0x34cc8f8f, 0x4114db5f, + 0x5471a360, 0x466dd209, 0xbb6d9ace, 0xccb52e8b, 0xe6d6decf, 0x301ba262, 0x4d27c381, 0x2495f5af, + 0xf328cf7f, 0xb21089c0, 0x96c659cf, 0x46c59e9d, 0x4dcafe3d, 0x3023c9cb, 0x6328742b, 0xc3637d4f, + 0xd4039793, 0x0079575b, 0x67b91440, 0xf9a9f5fc, 0x7f021117, 0xcd7e2288, 0x78bc16a4, 0x1068d0a1, + 0x9cb6c4e4, 0x787a4865, 0x3ace0bc1, 0xcf7efa04, 0xeaf63f19, 0xdf59e51b, 0xb4275b84, 0xcadbdca6, + 0x0744b81e, 0xd23bf99c, 0x11c38a4f, 0xfc69660f, 0x1de8488e, 0xee8e2c81, 0x43ddad9b, 0x8331b68f, + 0x8b839130, 0xa81fee06, 0x5c39c9ac, 0x32dd8e00, 0xf9640bc3, 0x21e5077e, 0xdf1f26ba, 0x54a63e30, + 0x8119acf9, 0x90249d5e, 0x57301840, 0x040b7da7, 0x4c438dfd, 0x07c7350f, 0xc4316967, 0x43c4ed77, + 0xc73e1220, 0xb84277b3, 0x86c5f075, 0xedd81d82, 0x48808f62, 0xca3b78b4, 0xa0959374, 0x906b5918, + 0x9ca316ff, 0xa45e6288, 0x84c8e56e, 0x2882937d, 0xf2aae8ae, 0x23643029, 0x0eeda6cb, 0xa0f05eed, + 0x330a3fb8, 0xbd179c90, 0x5d0e0a53, 0x4878b59c, 0x348d1b81, 0x280b3518, 0x03f00170, 0x93de515c, + 0x00e57e7e, 0x5f3aa40d, 0xd7939da6, 0x2e460cab, 0x7e883d30, 0x1cb764f9, 0x4711bbca, 0x18fc707e, + 0xb6f6fc29, 0x8a8f5884, 0xf7665647, 0xf7ddebfe, 0x6c85cdce, 0xcb8c1048, 0x2f49ae5e, 0xc8b4e121, + 0x54e04c4e, 0xdef96c8e, 0x102cd415, 0x521cd9a8, 0x305ffb4f, 0x11b04566, 0xb2a244e7, 0xe663d032, + 0x0ed4a771, 0xc24582d0, 0xaf4ec9f4, 0xdf2b31b4, 0xd5739ce1, 0xc8c0704d, 0xf2dc5db6, 0xd4a613bd, + 0x55c94444, 0xd9035607, 0x6f65cebe, 0x38b87388, 0x3dbff035, 0x975eaefb, 0x6c9a0b7b, 0x36dfdf80, + 0x840988fb, 0x6d6b1dbf, 0x025a0b77, 0x653f9868, 0x19dfe00b, 0xa8f4750f, 0x5591798c, 0xc93c7b1a, + 0xdbef672c, 0xf42fe8bb, 0xc6844a94, 0x39b31cb7, 0xb388af37, 0x510cb77a, 0x2649472d, 0x4fc7c4c8, + 0x160448d5, 0x8afe7b1a, 0xfbbe1aa3, 0xc7b06c99, 0x121094c3, 0xc5c798a5, 0x73e7d02a, 0x69774024, + 0x61187f4b, 0x26407625, 0x6382939b, 0xd755f015, 0x7bc9d87f, 0xdb0d4bf5, 0x903128fd, 0x057c3bce, + 0x0f9f4d16, 0x1bb16ae0, 0xe4e78762, 0x1394ba01, 0x430a4f2e, 0x678d5224, 0x5b8a8963, 0xda5ca991, + 0x4c39071b, 0x8eb10458, 0xa0e5b9c0, 0xca2d1162, 0x32ed19ef, 0xe3233c83, 0xd3f23412, 0x2ee8787e, + 0x662b875c, 0x81190f18, 0xe514c3ad, 0xc5abf4d7, 0x8f19da2c, 0x87113c3e, 0xb43e20fc, 0x332acda7, + 0x1f44fea0, 0x56b76f89, 0x89f3e4f4, 0xa35d7eb3, 0xdb084d2a, 0x8864e131, 0xdaf828e9, 0xa37a8165, + 0x44aa39c4, 0x9963af4e, 0xf0723a3a, 0xb5f94efe, 0x0f0be909, 0x28eec859, 0x54fc1a81, 0x2094f3c8, + 0xca63f349, 0xe20207fe, 0xe4473240, 0x7ac5e09e, 0x446409e5, 0xf5dcf822, 0xf8f20541, 0x6fa7dd1e, + 0x82adf87e, 0xca6a219e, 0xc08fc97b, 0x8fbd9641, 0xa386e50c, 0xd20683b0, 0x7bcdddd1, 0xbacbd4e2, + 0x1b227a71, 0xede72846, 0xb619a652, 0xc226b477, 0x32bfd888, 0x255b6e05, 0xa8cd2903, 0xe340cf05, + 0x401cf873, 0x37430853, 0xfb01d909, 0x2553c2ff, 0xd3293ac2, 0xfedaf9ad, 0x2ee9b5c5, 0x7d5f7179, + 0x205ac0b4, 0x7364592d, 0x4f9c7e74, 0xc6141820, 0x2722a6c6, 0x75cd91f4, 0x33b75d5d, 0x162b0852, + 0xb14555d0, 0xda5e193b, 0xce6403be, 0x807b3fe6, 0xd210ae0a, 0x2fbd694c, 0x34248bbe, 0x8c8f6e9b, + 0x706668ec, 0x33e175a4, 0x5f476cac, 0x6947babc, 0xc5e7a5f9, 0x4683819a, 0xa3ccc580, 0x9a328ff7, + 0xf4044335, 0x0c99c92d, 0x23d2fe11, 0xdc5eb0fd, 0xaeab0fc5, 0xb5660731, 0xa401d176, 0x676b54b2, + 0x3f7833f9, 0x50177dad, 0xe9111174, 0xde38f103, 0xdc5accd0, 0xa95cc5c6, 0x4df119b0, 0xf8954960, + 0xce1eed51, 0xe377129f, 0x92c74a57, 0x105ba76c, 0xbbde675c, 0xee0b9d63, 0x48694f1c, 0x86d67589, + 0x50759f26, 0xe6bb5ba1, 0xfe251903, 0x695ae612, 0x41e04e80, 0x915b28a7, 0x9c3a430d, 0x81ba55ab, + 0x26eee95a, 0x7e7e3c2e, 0xa7e01a9c, 0x4681faf6, 0xd1548182, 0x6132d29a, 0x3b78ab38, 0x80230750, + 0x15825263, 0xd3971eee, 0x233b93a2, 0x2773864e, 0x878dc8e0, 0xc366e057, 0xc17920ac, 0x3bcf7bd2, + 0x3ffa486a, 0xd221190a, 0x699d38fd, 0xa351fbee, 0xbcf4e12e, 0x19aa24be, 0xf6c6fb75, 0x4f49efcc, + 0xac4927de, 0x3ee477c4, 0x2c91cc6f, 0x02c5a4bd, 0xe22b5ebf, 0x8b7c0892, 0x7540fa5a, 0x80304369, + 0xd41b41e0, 0x34731da1, 0x58769b7e, 0x9186c511, 0xcb6e4e79, 0x1d462fca, 0x9a889acf, 0x664cc10d, + 0x2d300b30, 0x8d0456bb, 0x189d7e38, 0x5d36f762, 0x6c7cfb15, 0xe176b17f, 0x306479c3, 0x4c76a292, + 0xfd6a3cae, 0xd83cf619, 0x4d7bd36a, 0x39e77aeb, 0x7b3a719b, 0x32c2c8c0, 0x03c54678, 0x2ad2401a, + 0x727a1d89, 0xf8a4c887, 0x1183230c, 0x5df247e7, 0xdd5ca5fe, 0xe6f21f61, 0xc7442cb8, 0x59254a0d, + 0x494c92f1, 0x34f6992d, 0x3c2ed6f6, 0x5b01c98f, 0x39fb3230, 0x73f0b281, 0xb7864e7b, 0xdb526d2b, + 0x2c8854a4, 0x8b2d847e, 0xc3a94b57, 0x0fc3f8d0, 0x62580d00, 0xbbd8d17b, 0x9560452e, 0xf0b95500, + 0x7114a21c, 0xf6167fff, 0x12595595, 0xcca6668d, 0xda6aa0ab, 0xd6bbb7be, 0xb1654c91, 0xef8847a7, + 0xef492316, 0x3e94c91e, 0xb1294c1a, 0xaffdf871, 0x96f0b93a, 0xc6b61ec5, 0x561c24e0, 0xadf8896f, + 0x090b5c60, 0x116b4a0f, 0xba514fe3, 0x5d6b1aa3, 0x66cf7c22, 0x10bf0ea8, 0x6dc87458, 0x3e5e7f71, + 0x753d5b55, 0xce536f30, 0x378ec655, 0x328591ba, 0xcf039e27, 0x1fa565b1, 0x1cc5aac9, 0x2c17b133, + 0x45fd4a63, 0x24230556, 0xa9c07b5f, 0x6fad9fc3, 0xff21a0ff, 0xdd798dd5, 0x69c11f4b, 0x8053229f, + 0x583ecaf8, 0x2794324b, 0xa694732e, 0xa28cd106, 0x67df57b2, 0x88d54905, 0x9fb2c244, 0xde4a33d5, + 0xb5c2aeac, 0x0cf91906, 0xbdffdfc3, 0x43f1b8d7, 0xb63b0773, 0xd06d3c69, 0x180fbcbd, 0xab4ce309, + 0xdea37029, 0xdbaba519, 0x7fab08f7, 0x279bc284, 0xdc6f51b9, 0xf2432472, 0x2c37aed8, 0x561be67c, + 0x5fafecc4, 0x21935a16, 0xd9ea468a, 0x2f5a1199, 0x63d9f0a1, 0x279efa70, 0x726ee5f2, 0x38117759, + 0x471c48dd, 0x8abce1e7, 0x888a6b65, 0xdc4d1cf9, 0x619cae1c, 0xad85323b, 0xd62f198c, 0x293c1e4e, + 0x4043abaf, 0x880cb5bf, 0x5693aed8, 0x1df5e592, 0x5858b64d, 0x680af603, 0x1d02e486, 0x06a0d01c, + 0x7bd35ed5, 0x46516add, 0x11f4513b, 0xcf368581, 0xc8ef9186, 0x7d6b8be3, 0xd34a8e05, 0xe64d7016, + 0xded65f51, 0xd681fc91, 0x1f9340ec, 0xc49c39ab, 0xcc831ba0, 0x2dd25f6d, 0xc87bf68d, 0xfaff425c, + 0xd7a9ebf5, 0x06ad7574, 0xc472e579, 0x48c83aab, 0x69ffd84b, 0x806e68e0, 0xd9f13efc, 0xfea83c65, + 0x712511e0, 0xab48d832, 0x7089370a, 0x345c8b99, 0x4bd3561c, 0x9b3fe2fe, 0xfeaba6c4, 0xe98b9e9f, + 0x90acbdfd, 0x1e69a43f, 0xf354a0a0, 0x5824be41, 0xc4b253d2, 0xd6563a71, 0x01c53aa6, 0x3e2101a7, + 0x4246b851, 0x386adb21, 0x5ecf2a4d, 0xe3c6e6dc, 0x55018fc5, 0xee533aae, 0x8643df94, 0x32d1157a, + 0x40b5802b, 0x3d840210, 0x5425f1d3, 0x655efa8e, 0x20b37f79, 0x970ec344, 0x1fe40056, 0x052ede4a, + 0x562956c8, 0xd4959c44, 0x076b901d, 0xa1c93ad5, 0xc8a79549, 0x5096f5c7, 0x3e2815a7, 0x83dd4309, + 0x63a9de47, 0x1b69bbd7, 0xfd0e7854, 0x104877c9, 0x64f44e0d, 0x2fe69f7d, 0xdc72292b, 0x4b04dfd8, + 0xaf17d30b, 0x497995bb, 0x195da401, 0xfe351f10, 0xa5ee3a8e, 0x42318919, 0xf3cc47b8, 0x33a74dde, + 0x2efdd73c, 0x9cf9f165, 0x7452a8ee, 0x89991a64, 0xe4bf1bde, 0xa883c39c, 0x38466742, 0x92845925, + 0x71afc5a5, 0x9920fce8, 0xf119a790, 0xed022a4f, 0xfcbfe693, 0x4a9074f1, 0xeb90108b, 0x6a51462e, + 0xfa11ee87, 0xe9b6e541, 0x56c49b84, 0xf6ca8227, 0xb7266e60, 0xa65c7a06, 0xac9dfd33, 0xc4d30638, + 0x593c2265, 0x0caba7a5, 0xac17c9bd, 0x50893a5a, 0x83288c0a, 0x31c6fb37, 0xe6501bf3, 0xcb671f47, + 0xd3ddf8b2, 0xfa9a728a, 0xb2367240, 0x40ba740e, 0x8ddae211, 0x80dc5f5c, 0xa3fc016d, 0xe0936b6d, + 0xc2720f84, 0x01282b2f, 0x61ea1003, 0x1541d660, 0x42c8dc23, 0x1dcd7f1a, 0xf6a1844c, 0x4798ea01, + 0xfe0e9e4a, 0x9ab62193, 0xdf4d8db2, 0xe3c3cd67, 0x63ffe8ea, 0x5ff9bc23, 0xdcf86493, 0x2a1909e1, + 0xdc4eade2, 0x8a8284c5, 0x844f0cc2, 0x8ee76fab, 0x69000e29, 0x857bc0b5, 0xa39b5546, 0x2a3c01f3, + 0x6be9c85b, 0x5ea3cd17, 0xf7dc1c47, 0xb7f9ded7, 0xf0bc1d0f, 0x1255599f, 0x983a3176, 0xd695cd55, + 0x0e691318, 0x5ba28094, 0x7df8e718, 0xd3287838, 0xbb6022e5, 0x8c97c090, 0x1051f118, 0x7b1aba72, + 0x5af6d6d4, 0x73610bdc, 0xf09824f1, 0xaa5d135c, 0x451bbe85, 0x2028e066, 0xb8738fb8, 0x026f5bc8, + 0x066b169b, 0x99e7290b, 0xe923530a, 0x4d388fb0, 0x9e1fab57, 0xbf75c068, 0x19d8ac74, 0x396e2bb3, + 0x60b5d39c, 0xc57421a9, 0xccc1d4ec, 0x1578dc87, 0xdf6aa28d, 0x71c0d539, 0x2a90b22a, 0x5df75e44, + 0x4123bd2b, 0xd60bb49b, 0xd43c9227, 0x64280378, 0x35ccbec3, 0x06a8d78e, 0xa517655e, 0xc76ef4b2, + 0x3ec70307, 0x642bca95, 0xacdd36f9, 0x449acdf6, 0xdc6f6be7, 0x9c1a1ef6, 0xb7944350, 0x9c702ab2, + 0x87678f05, 0x7e504408, 0x3e5e2edd, 0x772823ef, 0x301de1f1, 0xdbd60db4, 0x774d8709, 0xcc0a370c, + 0xa0fc1066, 0xd1c92d2e, 0xd83249c9, 0x2e22c324, 0x962e2908, 0xac8072d0, 0xc1a81d8e, 0x8da72a7b, + 0x7f79f58d, 0x53f5af85, 0x49a87410, 0x22fe2f33, 0x0801138d, 0x6868d90f, 0xdcd8b272, 0xb1d1d662, + 0x09790eb3, 0x0003ee76, 0x9c2da52e, 0xe93c35d4, 0x8e2cd079, 0xf52f6fdc, 0x7024e06c, 0x71d360c5, + 0x89ced0d6, 0xd2bc4da5, 0x0f85368b, 0x6fd5d679, 0x5f3a9243, 0x57735a00, 0x6f279dc2, 0xebc6a8b0, + 0x25f89177, 0x4fa240d0, 0xfa1289af, 0xb430dc54, 0xa4ee5805, 0x37a37f18, 0x4a0b1a68, 0x3a65c421, + 0x0384afb5, 0x9255a4fc, 0x190b1fe1, 0x632913e6, 0x0df096c2, 0x4c0eeaff, 0x861faf25, 0x04978dc9, + 0x2d3972f2, 0xc669648a, 0xc7b46f30, 0x59258369, 0x5cac4d8f, 0xa4108e5e, 0x17d4efa5, 0x2761e224, + 0xc7768356, 0xa957c19e, 0x4b138ef4, 0xe9defa7f, 0xc181baef, 0x09a09db3, 0x68e3259e, 0xee18cc26, + 0xd9a87839, 0x09963166, 0x79336e0b, 0xb8a050d3, 0x257cd6e9, 0x89afeaa0, 0x20aad2ef, 0xf9092649, + 0x49bebcfa, 0x145f9891, 0xa21713f9, 0xcc1faa72, 0xfe5cf74a, 0x3d3c3990, 0x021f6b96, 0x7f497429, + 0xa2c8f943, 0x9adbb8ee, 0x91759d09, 0xdd5950c0, 0xf14a3dec, 0x67ac63bd, 0xd560ef53, 0x9b3bed63, + 0xca499c00, 0xb200491b, 0x9859fedd, 0x1316f213, 0x6055764d, 0xfb37d1d5, 0xe4cffdae, 0xc8fb53e9, + 0xbb61e453, 0x72f9f1be, 0x10e3464c, 0x5811ceba, 0xd2f85fb3, 0x7bc1a1d5, 0x40f9e15b, 0x1d0f2941, + 0xcf0f1a34, 0xbf7d0ef9, 0x10023781, 0x5654f116, 0x65caafa0, 0x1a48e442, 0x3772a7fd, 0x06fe3601, + 0xe024f83a, 0x9793a5a5, 0x6900e93e, 0x4138af89, 0x3abb869e, 0xabddbe2e, 0x07f5dffe, 0x31af40af, + 0x7c724100, 0xe3091a03, 0xda03790b, 0xfecdec74, 0x9e2890c8, 0x71acb46e, 0x83161129, 0x027c6866, + 0xd6888725, 0x59c6f87f, 0x282190aa, 0x03663538, 0xcafadfbb, 0x39904aa3, 0xdc4d9e89, 0xe60f7fa9, + 0x81a49dcf, 0x4b729fc5, 0xf314352b, 0xfc999633, 0x9d54d053, 0xb0a9c1d7, 0x2c2a3740, 0xfff2a572, + 0x3f977c20, 0x540520df, 0x54abbcd6, 0xcf5af1de, 0x9db826f3, 0x9b0d0a0a, 0x9fee8197, 0xece5c34f, + 0x95267b0c, 0x9d4d2cf6, 0xaf99195f, 0x6736946b, 0xd5e98f85, 0x1f806ac8, 0x3578c076, 0xb4125ede, + 0xabd9ab6c, 0x6b244c26, 0xc7db7f19, 0xe7ee066a, 0x5ac79ca9, 0xbb9429a6, 0x15047d01, 0xd24f9ca0, + 0x1152e608, 0x387d2827, 0x45054522, 0x0de0a57e, 0xa8faaafc, 0x508fe773, 0xfe27ffab, 0xf3afe272, + 0xe7b94fcb, 0x10596f91, 0x760bc08b, 0x29890d91, 0x802b1ed2, 0xcce5882b, 0x1343997d, 0x376d43eb, + 0x1b6ae6ca, 0x59f1c0ca, 0x076ded51, 0xe7ad6170, 0x33d46343, 0x16500d81, 0xe73c67a5, 0x7f1d32ed, + 0xe22ed6bf, 0x152fd4df, 0xc0aca327, 0x0bb22925, 0xd0b44f1e, 0xba88e42a, 0x614112f8, 0x1c959b35, + 0x2103bce7, 0x1d8fd839, 0xe2119cda, 0xe1e8f5c3, 0xf97a8111, 0xd227413c, 0xbb5a260b, 0x825abafe, + 0xf6a47a6c, 0x9de2024f, 0x50b5e2c5, 0xd4d05e75, 0xf46568a2, 0x94746e90, 0x1a3eddfd, 0x95dcabdb, + 0x601e5b3a, 0xecfab16a, 0x60925a4b, 0x6c4abf4b, 0x79d4ee59, 0x7a5e1cc5, 0x84d1cb45, 0x843e11df, + 0x7abc8edc, 0x9c42fc2f, 0xf74fabab, 0x09361d5c, 0x4ecaf6b6, 0xffa85242, 0xee4da99f, 0x5c61b217, + 0xe9ed0b21, 0x87886f98, 0x7f224b77, 0xdb7bd54e, 0x96f64d40, 0xb4b15d3b, 0x1612ebc3, 0xb629fb89, + 0xff1a7a22, 0xbf52cf31, 0x73658e45, 0xc8565788, 0x9602f9ab, 0x7c70c589, 0x27df94ac, 0xf171c279, + 0xf4a5eb2c, 0x49af4fbd, 0x6fa6c83c, 0xb1946c4a, 0xe0d89089, 0xe323b332, 0xc5ee6a2f, 0x495e9329, + 0x32dcfed4, 0xef3747d3, 0x71a87c12, 0xa859d5ce, 0x343db0b4, 0x8d4d582d, 0x9373d573, 0x9c0a91fb, + 0xccc1e48e, 0x6cb64db4, 0x2d188bd0, 0x211ff639, 0x2aec54e8, 0xafacef3d, 0xc4c6933e, 0x3237b096, + 0x153ba450, 0x189c54fe, 0xd76c1d5d, 0xe4795d8d, 0x99f23b3c, 0x56eacb75, 0x31491fc2, 0x222ec950, + 0x8ad8ce02, 0x779442bc, 0x53aac1f3, 0xd8f8338c, 0x5af31bc2, 0xbf7080cd, 0xe8aa44cd, 0x24bef1c0, + 0xa56bb19f, 0x6e16d60f, 0xd3c56836, 0x815113c7, 0x56895d3f, 0xfcdf215d, 0x32a14876, 0x69734da1, + 0xa742d578, 0xd4bc9234, 0x0a2848c3, 0x2ff7f213, 0x16acbd83, 0x0105c92f, 0xc4566215, 0xe86515b1, + 0x694658ae, 0x9c12e5b2, 0xe94963b2, 0x5f4efafb, 0x2fe1c70f, 0x38d7a9ab, 0xace69f01, 0x6475156d, + 0xb4e84c73, 0x50b9d9a7, 0xc3d58958, 0x9f34741f, 0x9dabb44f, 0xad1872d9, 0xe33b437a, 0xc150404e, + 0x71365bdf, 0xef244018, 0xca42875c, 0xaf935d10, 0x97911ba8, 0x5eb0ba1d, 0x80b6427e, 0xa2033a1e, + 0x52df9cb9, 0x14d52656, 0x255489fa, 0xb093c5d7, 0x980f5ef3, 0x5bcd6c73, 0xa7edab69, 0x409a1a0d, + 0xa3a31bb1, 0x908b0eb1, 0x902a0176, 0x743c6b5b, 0x5c0546b0, 0xf4fb48c9, 0xfbcca187, 0xc9350d34, + 0x2999ffea, 0x27e8c754, 0xa831c122, 0x1bc6ec3a, 0xb1efa86d, 0xfc2a070d, 0xadec481b, 0x1b1ee2e6, + 0x71a1f8cd, 0xff3a71c1, 0xebf8a150, 0x6df5bbd9, 0x83dfca7b, 0xbe8b182f, 0x5d0c936e, 0x50e0cb2a, + 0x5d48d385, 0x9d8b217b, 0x14150bff, 0xacd68588, 0xfb533790, 0x753250a0, 0x8cc71f15, 0xd491ae84, + 0x87e84d00, 0x5dcb840f, 0x497122cf, 0x673ca8de, 0xb8b27f44, 0xec8991fa, 0x602534bd, 0xd9051b76, + 0x9654ae54, 0xce8c739e, 0x4ad33722, 0xf19e234d, 0x526fccac, 0x8cd247fb, 0xf1ade9a2, 0xe9c1ee5b, + 0x6f8d740b, 0x10f054dc, 0xc965e058, 0x3b0d08d6, 0xc200f35b, 0xc13866c1, 0x20930758, 0x1d92cd28, + 0xae29e61d, 0xeda9a8aa, 0xbfc0cf30, 0xef1117e8, 0x65e3af2a, 0xaeebcac9, 0xfe91b492, 0x6e3faba6, + 0x769c0ae9, 0x4a54f22b, 0x374f9899, 0x43db74d1, 0x5191d2f6, 0x2e52c0d0, 0x7b70ec21, 0x3b3ddcaa, + 0x7b8de586, 0x8ee3c94d, 0x6b376b06, 0x871154fa, 0x3bf400a4, 0xc41d645b, 0x300ee6d7, 0xe1924232, + 0xe8870d80, 0x493f1a9e, 0x954e2ed0, 0x50f44076, 0xba1b7e32, 0xb6379a2c, 0x0166cc82, 0x5acd3527, + 0x99b4c0cc, 0xbfee8aa5, 0x9956ca76, 0x634cc1ba, 0x24ba3771, 0x11680313, 0x34e42b00, 0xaa5e79f9, + 0x0eab6bdf, 0x31e33580, 0x36223004, 0x69def896, 0xc29b142f, 0x50a89c91, 0xc1882964, 0x0d24e45c, + 0xcd655058, 0x9c43533c, 0x2ee5f2e0, 0x535be541, 0xbc02a836, 0x309f75e7, 0xf280279d, 0xfa8cfbad, + 0x7d255a89, 0xf3364fed, 0x691e1ee8, 0x9e9dc0d1, 0x15338802, 0xc9ec6e31, 0xb1152933, 0x7c3096b6, + 0xf3e09061, 0xf1bd88db, 0xb4f85461, 0x8a347d9c, 0x9032128c, 0x89cc83fa, 0x3c9ed8ce, 0x8246f258, + 0x0aea945a, 0x92d905d8, 0x46dd4037, 0xb3e73878, 0xcfca50c9, 0xd4a3d79c, 0x998d9c05, 0xb08f2d0d, + 0x3120acce, 0x36a91899, 0x520874b4, 0xc42ff081, 0xb5fb532d, 0x33285bee, 0x606282fb, 0x5201ea17, + 0x82321ad6, 0xcb378631, 0x39bf7efc, 0x8ae5d62e, 0x447abafa, 0x7d674f34, 0x54264a4f, 0xe78d1366, + 0x2c1f387f, 0x777a5318, 0xf8398912, 0x3b8b200c, 0xd7809819, 0xfd95b179, 0x6ded1ab8, 0x5b8314ba, + 0xf056adfa, 0xa87eb84d, 0x504375f5, 0xc1829b82, 0x4108d2b4, 0xe7f9b1cd, 0xd319dd71, 0xf648680e, + 0xc2740f60, 0x6d4acd21, 0x17a78222, 0x7db17785, 0x7111685b, 0xacdc87d7, 0x583c1a78, 0xd358dff0, + 0x67d7f295, 0x96bd8aee, 0x82614be2, 0x8eab06a0, 0x22e45dff, 0xdbc8f8e5, 0xe015893d, 0x25ab1198, + 0x62557508, 0x824f897d, 0x4be5b204, 0xbf0ea842, 0x6b935b83, 0x7f9782e8, 0x65e6ac0f, 0x0c46970f, + 0x0e9fa0d0, 0xdb124e93, 0x563b9679, 0xd1dcabf4, 0xd3ce1b22, 0x2d0575b1, 0xc8665b5e, 0xbba48d3e, + 0x98c07dd7, 0xd0b6821e, 0xb9e86ba5, 0x149e11aa, 0x05f7ad80, 0x957c04bf, 0xb11cafab, 0xd94c4ec4, + 0x06f4c0ce, 0xc9878cfa, 0xfc21b552, 0x65c5b2a8, 0x968960b6, 0x5c2b9eda, 0x6e161dd5, 0x99fec926, + 0x348866e7, 0x140d9d64, 0xfbd8f65f, 0xfd5cb6d4, 0x93b748ca, 0x5b6e1da2, 0xb629fea2, 0x6b4dd9f4, + 0x3a386d6b, 0xb874f8c0, 0x0b60a069, 0x8838def0, 0x9836f0ab, 0xe9f120d7, 0xdc8093d3, 0xc3e395a8, + 0xbb5a2dea, 0x1a30c1a1, 0xe2c19746, 0xf88e58c4, 0xe4d006e7, 0xe82a3006, 0x030320ce, 0xf4766148, + 0x9111adf1, 0x93a22aa1, 0x286d74ee, 0x95bba5fe, 0x9f1e6a0c, 0x6f89466b, 0xf3a778f8, 0x56081cf9, + 0x21050cfa, 0x30df45ff, 0x2a7fe6d9, 0xfab17961, 0x133522bf, 0x70ad1298, 0x19d8133f, 0x899f4583, + 0x1b726a8e, 0x9e72d799, 0xb5fb4832, 0xf85d1ed7, 0x3c88434b, 0x14aa7105, 0xe00cbb49, 0xd6231d78, + 0x8e0306d6, 0x5dd0a8e5, 0x9bf305a0, 0x170f2b2c, 0x8d580e07, 0xadb316f8, 0x0ef084ba, 0xef8f8b93, + 0xc7f40205, 0x15d7110b, 0x0ef661c8, 0x71b94da1, 0x9e14d4ae, 0xef265d4b, 0xa719e0d8, 0x30b7c627, + 0xfec8ad38, 0xfb0e2a14, 0x72a2776b, 0x08a5e735, 0x0f853df9, 0x34c3e9d9, 0xc070f670, 0x918be3f3, + 0x4b1578f0, 0x8f86ed26, 0x8593a99e, 0x9845aed1, 0xd123652d, 0xbc5bf7bc, 0x4d24c4c9, 0x9732234f, + 0xdb63cc81, 0x7f08c5fa, 0x32286a4b, 0xe0475fed, 0xbb327adf, 0xff61e77d, 0x8bac326f, 0x20380ef2, + 0x50c22325, 0xec818868, 0xfb625591, 0x2ef2e1af, 0xcb1be22a, 0x10beaa9d, 0x6d0df6c9, 0xb3acdc38, + 0x6102437b, 0xfbf50251, 0x441f37a2, 0x5a29d56a, 0x04086a7d, 0xb77f3ea7, 0x31519e84, 0x62b99999, + 0xf7a6a4aa, 0xabf6f204, 0x58300bed, 0x2c01cfa7, 0x297e21e0, 0xfe44e81f, 0x12bc8ea4, 0x343e0f93, + 0xdad78d15, 0xf2cf8e43, 0x46855fe9, 0x4ad5033f, 0x93f4dba7, 0x15d8b40e, 0xac8d727d, 0x6d20f40e, + 0x68ef6a06, 0x19d7e60e, 0xd20f2dc9, 0x9f3b99b0, 0x13584833, 0x0e2728f8, 0x133f1197, 0x7d5c80fd, + 0x36c5933e, 0xf396c210, 0xdc812a67, 0x72f4bb65, 0x53adf91f, 0x7d958af3, 0xdc6695eb, 0x72eeaa53, + 0x7eb8ece8, 0xfa510124, 0x655a7d64, 0xe689e09a, 0x46077f10, 0x0d6047d1, 0x38727918, 0xf149cbdf, + 0x026c8539, 0xe84065cf, 0xbb312a65, 0xbc946396, 0xcf32f4d5, 0x6384619b, 0xba959dd0, 0xd534b277, + 0x9f9572ff, 0x135446c6, 0x9df2fd6f, 0xf859ffa6, 0x0a1dab7b, 0x86323f56, 0x6a2db57d, 0xb5910461, + 0xcebd4f79, 0x307ccf62, 0xd4ae116f, 0x26d76e11, 0xf0a4d7ce, 0xc698ded4, 0xd741c954, 0x3f40ec70, + 0x8f6ffdb9, 0xf02983b9, 0x179782d4, 0x8cc80c9c, 0xc9143d63, 0x5ae1e5c3, 0xd0ff782e, 0xd7002350, + 0x79a100a7, 0xf33c2575, 0x68713bda, 0x26b9b9b7, 0x3cf9c259, 0x8bd7d1de, 0xedf4b6a3, 0xe7cf1b8b, + 0x381f6041, 0x9428854e, 0xdcfdc5c5, 0x5a9bc6a8, 0xa2fe61d0, 0x300f1bda, 0xc2df66dc, 0x0c7588fc, + 0xdcb4a22d, 0x9ac69e0f, 0xa44c43ec, 0x4851379a, 0x47b5227f, 0x5b934e54, 0x311afbfc, 0x55690c00, + 0xa7c44af6, 0x99546cfc, 0x9e070771, 0xdc9e79f6, 0xe1cc1727, 0xa20c0c97, 0x3d22ed44, 0xc0a2a210, + 0x035b6801, 0x2d7df2ad, 0x514d55c2, 0x187c4bd5, 0x2188965a, 0x2cdeb781, 0x5179c0a1, 0x17a18c26, + 0xf0c2cbcd, 0x9f2bba7b, 0x5a089bde, 0x2df10a69, 0x8ecefcd2, 0x5cb76ded, 0x1e728b27, 0x9e2f0694, + 0xe3c6a43c, 0x7336386f, 0x49f41f03, 0x13348b44, 0xa19faa0c, 0x9581a9b5, 0xce23bf0a, 0x993dd210, + 0x05ee20a7, 0x08868351, 0x8af774e1, 0x66f0ba05, 0xefa2fdcf, 0xf1841f0d, 0x6f8d59f3, 0xcbc2afb1, + 0x5415a3f5, 0x01b72320, 0xa56bbedd, 0xf7c4ab46, 0x23f83e62, 0x5ccc0057, 0xb2789775, 0xd616c60d, + 0x3cac11fc, 0x69457896, 0x19e0b853, 0xd72c0ff0, 0x122edd51, 0xd5317686, 0x850aed02, 0xd7d6667b, + 0x0a4149c9, 0x6e8a371a, 0x4e892e69, 0x7d6901b1, 0x07a3c4a8, 0x4291884e, 0x55525885, 0xa36f7d13, + 0xd3524155, 0xe915bece, 0xfcef4100, 0xeef1b1ce, 0x06c6c5ce, 0x335eb91e, 0x86650261, 0x59d23353, + 0x3d4f4ebd, 0xf1e15e0a, 0xfe63a0a4, 0x23eb6df3, 0xdffb3bf8, 0x6fad6374, 0x33c6201b, 0x42ec56fc, + 0x08d20ae4, 0x240af6d7, 0x3ac5060a, 0xa8cab650, 0xf8bb480f, 0x657d64ea, 0x845cc773, 0xf0424bf7, + 0xd74bbff9, 0x58b156f5, 0xf1dfad65, 0xabc7da63, 0x0e9131dc, 0x5fcff617, 0x0f53080c, 0x2b7591d3, + 0xb4f6707f, 0xa1a72e1d, 0x8fedf2f6, 0x6d1844a6, 0xe5504779, 0xc23b1f95, 0x7845d392, 0x304eee95, + 0xff319c51, 0xf38d5e0f, 0xe8bbea4a, 0x2a281afc, 0x369cbcb1, 0xbb97301f, 0x35dd4498, 0x668b54bf, + 0x396086f5, 0x901b10bb, 0x0a848dd3, 0xa92ef59b, 0xb2841d85, 0x9629e8d8, 0xe6328f63, 0x348a30b1, + 0xa9942beb, 0x83513e9e, 0x84c3dcd8, 0xe2964ef6, 0x7f8b146d, 0x4d9cd842, 0x3340eb4d, 0xfad7eddc, + 0x7a31f964, 0xee284e0f, 0xf6779678, 0xb81d6508, 0xf3e5f5f7, 0x919c37e7, 0x62201cf2, 0x86d13c0b, + 0xa1d971e2, 0x5e025f7a, 0x9daebed4, 0x3ad8bd34, 0x08c41ccd, 0x677f9ce3, 0xf25bee4c, 0xb0b9d2b1, + 0x1c56564d, 0x0a5bd131, 0xbd792401, 0xb165a14a, 0xf2f169ba, 0x9f4dd9ea, 0xc5139d16, 0x55a5f65c, + 0x11e0131a, 0xa0e76e90, 0x54fac28b, 0xc2bd2544, 0xfb20f1b4, 0x072f7ee5, 0xbfa8c8b4, 0x2e2acec9, + 0xc4d8e9f9, 0x06019aef, 0xc0c0dfd2, 0x04bb1338, 0x4ea622e2, 0x63ea4781, 0x6800ca61, 0x31416aea, + 0x76888ceb, 0xdd1731fc, 0x3d7183ad, 0xbf828d73, 0x93c96267, 0xb5b59021, 0xfe2037bd, 0xf9152ceb, + 0x9b7f8283, 0xc02a11ef, 0x298a9975, 0x53b0f356, 0x46b32e45, 0x40bb9852, 0x25134e0d, 0x34a34fe2, + 0x94fadb7c, 0x5e35a4c9, 0xb9def0c2, 0xcbbf5444, 0x352312b9, 0x83f449bf, 0x8b80fc1b, 0x78d95835, + 0xee70e922, 0xc35aec6c, 0x8d582cad, 0x5274a700, 0x9ff10b07, 0xce6a4a46, 0xedc74b99, 0xddf73ff2, + 0xc9421199, 0x0a1edda9, 0x3818fed2, 0x0477ad7c, 0x9ecaa367, 0x32ca7a21, 0xcd1b663f, 0x8f60c36c, + 0x744eae76, 0x9d1ebe0d, 0x16168382, 0x4279ce4a, 0x632eaaff, 0x9d74fc3b, 0x5f63d008, 0xf216d64e, + 0x3e55b8d4, 0xc24c8aa9, 0xc07dea87, 0x712bcb9f, 0x8a272cd5, 0x05527f80, 0x2c551fc8, 0x3f0062c2, + 0xbacbf752, 0x4958cdea, 0x84ab4783, 0x542639ef, 0x80b23a21, 0x10a5d518, 0x67ba6d9f, 0x0be46749, + 0x7fc4218a, 0x4f93bf49, 0x9041f04e, 0x71b6d6c5, 0xe8dba171, 0xdd38df6b, 0x4fc7fe7e, 0x142f7060, + 0xfee97fa8, 0x05089174, 0xd3cfab02, 0x0034a6de, 0x964b2f12, 0x8f5a9641, 0x0d98e8fa, 0x5c4f2eeb, + 0x34865f17, 0x9b3a85ed, 0x7cac7d97, 0xc9550e1c, 0x20b4b122, 0xdb6a1362, 0x8d242c0d, 0x7fc8f035, + 0xa834d0fc, 0x931d3c47, 0x056f524d, 0xc5606237, 0x31246223, 0x8c9c602f, 0xd502386e, 0xa52b9b17, + 0x35474dbc, 0x91c68dc7, 0x9a663865, 0xa4dec2b6, 0x06b1cf67, 0xcf23c80b, 0xc262a1e8, 0x298bd7dd, + 0x5df4d889, 0x64b92523, 0xb89eb78c, 0xb8f9420d, 0x8e09de63, 0x8c030916, 0x7b81a764, 0xc9be0f3b, + 0xdbaaa01f, 0xfc45c169, 0x2ce4c165, 0xd04b3eae, 0xee64bae6, 0x0d549df7, 0x516b28dd, 0xa297363d, + 0x5f08e4b9, 0x618a0668, 0xe2e020d7, 0x4378a9e7, 0xe8b552ed, 0xde31315b, 0xba6eb857, 0xda3733f5, + 0x82379079, 0x6ff2eb4b, 0xb6a62862, 0x3887255e, 0x885b03c7, 0xb0a39f25, 0xb8314249, 0x7d3a6fea, + 0xcacc2742, 0x92ebd811, 0xe7058ed4, 0xd2e98894, 0xef5eaa73, 0x0b66fa6b, 0xc9e44261, 0xab9a4b97, + 0xc8d9211f, 0xf1d43bf1, 0x3caa98d4, 0xc07e1e0d, 0x388ff90a, 0x60b05914, 0x80f6f2d1, 0xf6201bf0, + 0xabc257c4, 0x15031bc5, 0xbded967d, 0xf691b254, 0x7c0f898f, 0x7f1649d5, 0x6b3f857d, 0x41edd676, + 0xab6a645e, 0x31f7ec9e, 0xb5a80fec, 0x04685b14, 0x28bf9c81, 0x22eb783c, 0x017071d4, 0x14a2da95, + 0xbb04b7d9, 0xcb3fd423, 0xbf4f8a3f, 0x36a86cf1, 0xb8cb7358, 0xeceb7c3d, 0x1179e877, 0x46818b21, + 0x71c807ba, 0xa73a86c8, 0x660a5db7, 0xfcaa8107, 0x08de8bd1, 0x773b345f, 0xf4e0238e, 0x0bb65908, + 0x36d1d83c, 0x1d9acfc6, 0x9c281e26, 0x737dc435, 0xb0a1a885, 0x4028d52b, 0x5ee66ff2, 0x72c0cbd7, + 0xc98cda75, 0x8a662db9, 0xcb67ae55, 0xe14de6fe, 0x544cc3be, 0xe7918464, 0x8023ff84, 0x5badd7a6, + 0xf8d6ee4f, 0xc716f96a, 0x3d81e62d, 0xdbfea12b, 0xdf002c60, 0xc79790ff, 0xf33a165e, 0x6efa6ce7, + 0x2fbda3a3, 0x90351e59, 0x2bdcaecf, 0x82e02816, 0x935bb053, 0xd68e3c32, 0x9dd41ae5, 0x11f2993e, + 0x49aa777c, 0xaaf9de04, 0x64cc8b38, 0x8dde0528, 0x3f82f8cd, 0xfebbb90c, 0xff17d890, 0xdbede996, + 0xd801a3d1, 0x9d31a4bf, 0x9cddb23a, 0x4eb54c51, 0x16fe747b, 0x8593e2ed, 0x362ee3b7, 0x708a224a, + 0x3f88c142, 0x3e086b18, 0x13516182, 0x07981b18, 0x1d8db035, 0xe5dfe618, 0xd538c1c3, 0x44d6a585, + 0x46e2c2ba, 0xaebc961c, 0x44c6e775, 0x27dd60b3, 0xe4050adf, 0x66616b27, 0x9af28fe2, 0xcbc7d4dc, + 0x0fcc181f, 0x4e9a4be8, 0xf95a9de7, 0x628022d0, 0x5695f049, 0x4d375de5, 0x703952bd, 0x373604e2, + 0x854d2c4a, 0x088f91af, 0x6a266c6e, 0x76a1c6aa, 0xb26ea269, 0xd490c64a, 0xae93b56e, 0x5d9664c2, + 0xed3c0cf9, 0x4ba58c15, 0x3f52baee, 0x341ce029, 0xd98f0b43, 0xd1bdc0bf, 0x9d0303ce, 0x1c11885b, + 0x2626dab9, 0xfc6a3de2, 0xd2957c1a, 0xa4b0b389, 0x87ff3db7, 0xf1d80fa8, 0xc722bec7, 0x9d907e23, + 0x5636fa09, 0x65734788, 0x43a45622, 0xca06bd52, 0x9e183370, 0xea250058, 0x4cab5e39, 0x45a5efc9, + 0xd7b4295a, 0x3294ae98, 0x8dc7a2bc, 0xe03c349f, 0x4dd20897, 0xf179f969, 0x27ee62bf, 0x4414dc8f, + 0xde178f58, 0xceee7dff, 0x27a15f90, 0x0a233599, 0xc477ae9d, 0x8c26cafd, 0xa52e2664, 0x1c33d0ba, + 0x903adce1, 0x007848ae, 0xcf1d9ad4, 0xefbf2b98, 0x82dcc49e, 0xe8ad901a, 0x9d70c899, 0x918fc4fa, + 0x6b03f232, 0xe88b715e, 0x7f4acadc, 0xb0851ccf, 0x3edc3119, 0x2336f1e2, 0xbd64299d, 0x93b607ef, + 0xc633700a, 0x44a58952, 0x6ebd950e, 0x450a7001, 0x3d022e39, 0x7950ff04, 0x7b8b212d, 0x41e6ac79, + 0x8a634444, 0x2c20e933, 0x852ad6f2, 0xd28c5df4, 0x485072c8, 0x2159ea1d, 0x71164552, 0xba557456, + 0xbed6921f, 0xacc12c80, 0x545ca1f8, 0x4f36dfa4, 0x4eec08a7, 0x81967866, 0xb2d78845, 0x46fdefa7, + 0x39b94edf, 0xb1518894, 0x166cf4de, 0xca2e6fb6, 0x21042e92, 0x08477a8d, 0x02e6133f, 0xd03a9517, + 0x5a8dcb1e, 0x65351dd4, 0x56a66010, 0xff2fae36, 0xe8fb07df, 0x727e523e, 0x57e87c71, 0x5777aaa3, + 0x04549940, 0x1bf31f25, 0x18687d58, 0xf04e143d, 0x229e291a, 0xcb10efa2, 0x2187880f, 0x2a08aa07, + 0x39995226, 0xe57ae7a1, 0x24c71692, 0x25e67f52, 0xf5dfe8f0, 0x4c8e65d7, 0x801a30e1, 0xbd1a98fe, + 0x70f68815, 0x311b9227, 0xa6aa496b, 0x3a25c5ac, 0x2d005523, 0x3d415fda, 0xe610e51e, 0x0601e7b9, + 0x628e719b, 0x8154915e, 0x8848c79f, 0x10afe530, 0xb5f2be3a, 0xd042b2ca, 0x232e341a, 0x7a8eab7f, + 0xc7b996d1, 0x4d5f1ff1, 0x5eb46323, 0x6c86e7a1, 0x552f3207, 0x645e911c, 0xa919bf1c, 0x4f1d753a, + 0x0b381d4c, 0xabf20eaa, 0x387fe212, 0x495b7151, 0x9e830a64, 0xb7802100, 0x9d3bc64b, 0xf9c523e5, + 0xf2e9a16d, 0x8a428ec4, 0xe0b8222c, 0x4e6309bf, 0x232142df, 0x5933fc1f, 0x946ecf6f, 0x25464141, + 0x6ff0a924, 0xed20c49b, 0x84394a6d, 0x0fc789fc, 0x0b4e29f0, 0xcd8d3c80, 0x2be4601c, 0xf2930fee, + 0xa2de7bf4, 0xc378c007, 0xd8b88e27, 0x997502e0, 0x11407247, 0xb0506c4d, 0xe76e140e, 0x93aa0388, + 0xd9d25ddb, 0x59a9e01c, 0xdc733c9b, 0xa25f2844, 0xb919e435, 0xf1ac1a54, 0xc1733ead, 0xf0461626, + 0x1e17888e, 0x0439389d, 0xc86fc708, 0x47401fba, 0x2ccea47e, 0x99d09eec, 0x2807614d, 0xd4e20b08, + 0x61629f02, 0xdc3d8c04, 0xe36059e3, 0x21a65b2c, 0xf5bb398f, 0x69b3c00d, 0x98c42df5, 0xfaeea002, + 0x213cf14b, 0xa4f9810c, 0x263e7ee3, 0x9f3b7f00, 0xa7360bc1, 0xe3d480a3, 0x21e9cee5, 0x7bf268a9, + 0x8043b41a, 0xb5d20cd5, 0x5342a7a2, 0xc16e47ac, 0xe9a9df11, 0x7b020e68, 0x78707673, 0xcf8cbfb9, + 0xcc1e4122, 0x97c3bdd2, 0x479d9f44, 0x56d347b3, 0x4f14bca3, 0x5fc2bb27, 0x680b7c72, 0x4dfbde99, + 0x4ca81be5, 0x554996ea, 0x2f9e3d96, 0x94ec78fe, 0xfccafd84, 0xeedaeb8a, 0xe4c52eae, 0xee214aef, + 0x3f536f8a, 0xf944d200, 0xbcacd975, 0x14a04526, 0xbb460aa3, 0x119e1e2e, 0x1d95e264, 0x8b4f52d3, + 0x2b585f39, 0xf107dfb8, 0x09c573cd, 0xcf8ecdb9, 0x8420aa87, 0xcbb669e6, 0xf292d38a, 0x815cb622, + 0x016cdc06, 0xdd51ac7d, 0x9bff65c7, 0x91b2ce9a, 0xcf871316, 0xd41d4bab, 0x2fc44632, 0x798f7a24, + 0x4c9e450d, 0xbb5ea95a, 0x38ceccc5, 0x1fad1059, 0xb0adc6f1, 0xc552d7e3, 0x9b86b169, 0x9aee2f88, + 0x00410638, 0x1d8a4a21, 0xce845d48, 0xa5effb2b, 0x7f986b11, 0xa26052b6, 0x6494325d, 0x6bb0749c, + 0x6119d66c, 0x27ba6df9, 0xa5e317d1, 0x940da630, 0xdc5be9c4, 0xa21cee2f, 0x60f20ea9, 0x5008a718, + 0xa0e6fd9a, 0x5de34445, 0x5acf320d, 0x2bc6233e, 0x51d07ac7, 0x59c11e72, 0x2880a601, 0xa284eb9c, + 0xe3dcdc40, 0xd82c4c1a, 0xaca04116, 0x83a58ac3, 0xb2901c36, 0x84d906a2, 0x34c6e254, 0xa9a3b3a2, + 0x0f1fc54d, 0x561710ce, 0x7ab1250b, 0x35114e00, 0x3f8147de, 0x88b852e4, 0xb6bfcbe9, 0x1c8cb6fe, + 0xa842d78c, 0x7f2e5c6e, 0xd5985750, 0xa189861b, 0xc0524c01, 0x3ce6a7fd, 0x1ed0485d, 0xba42c22c, + 0x88689936, 0x57975e1d, 0x6dc413c4, 0x758449f4, 0x87094dd7, 0x1499aaca, 0xeec56aa4, 0xdc7dcd70, + 0xc114a6e6, 0xeb944079, 0x3f180f7d, 0x93a95b1b, 0x0fcfd3f7, 0x403774ed, 0x3b29e943, 0xba70e680, + 0xa69fe9d6, 0x4ec25420, 0x7b33c20e, 0xa02262f9, 0x2e073915, 0x334daf14, 0x44e867b1, 0x1d3359e3, + 0xcf7553e8, 0xce10ce62, 0xe356fbd5, 0x96eaa05d, 0x0b09311a, 0x8b3e2b45, 0x3a2afbfc, 0x5d19c14d, + 0xd02532e9, 0x2a1d02e0, 0x252d30d3, 0xeb5b1e97, 0xbf08bcaa, 0x052038f9, 0xda7850d7, 0x94f7a745, + 0xbdcf042a, 0x37d08110, 0x67d1c008, 0xcc63ff4d, 0xb2a36586, 0xb1573ba9, 0x9f302f52, 0x97edec5a, + 0x7b863f75, 0xfbea458d, 0x935bbe2e, 0x022d260e, 0x78183714, 0x7a640b75, 0xc940707e, 0xadd8f6ce, + 0xbe7899a6, 0xa8f980c7, 0x18bd679c, 0xced32616, 0x2e256f94, 0x664f0ca9, 0x384232e9, 0xb8e6bc48, + 0xeda853c0, 0x5d3e81cc, 0xc80439da, 0x9d9da32c, 0x503c4afc, 0xe619806c, 0x187a0111, 0x9f4eb8a6, + 0x839bfa8c, 0x58a83598, 0x8f063edf, 0xe9d72256, 0x3db7eb5b, 0x357a305d, 0xfe6c9a6f, 0xea40b918, + 0xce5c7e2a, 0xa9b920f5, 0x545d5418, 0xad489e8a, 0x870be42a, 0x510e8a6b, 0xda8a7d69, 0xbdea1ead, + 0x9f3ff065, 0x1364b84f, 0x53550393, 0x45bbde72, 0x90983039, 0x2d29cd36, 0xc0e76592, 0x510b5caa, + 0x2e4a0b6b, 0xa3471966, 0x1ae787ea, 0x0ffb5941, 0x258ce9c7, 0x7e2611b5, 0xbda6cad4, 0xb82438cf, + 0xd6f00605, 0x0b5fa0b7, 0x25ffcda2, 0xbfec2ae7, 0x84e9b639, 0x6b340ffe, 0xcc8e4ec4, 0x5dd4daaa, + 0x589c4860, 0xbfec6b47, 0x87c1be66, 0x3401860f, 0xff7b5fa0, 0x5d9fd0a6, 0xf4e97a10, 0x796ee98a, + 0x1f53c177, 0xd635cbdd, 0xafe1501e, 0xba85e915, 0xfae6c3f1, 0x99e6098d, 0x9ecabd0a, 0xd89cbabc, + 0xb53735fd, 0xb1f97b9c, 0x72d4f08d, 0x7087aa1f, 0x40faa90a, 0xf23e5da8, 0x0d59b2c1, 0x1f363e08, + 0x78d93f84, 0xc4c224ec, 0x9598e1fe, 0x72f1f752, 0xc63672f4, 0x3beb0089, 0x34852d5a, 0xc69bc77d, + 0x423b7e28, 0xfddbe4cf, 0x91781052, 0xc510e2cc, 0xe019bfe5, 0x1ce4d3af, 0xbe49a971, 0x8e8f31c6, + 0x707521ca, 0xda4b3b15, 0x02e04718, 0xfa841281, 0x41d2e13e, 0x50413caa, 0xd6e3b96c, 0x40941970, + 0x83dcf5f8, 0x3f8c0fcb, 0x1ba17568, 0x6d79ef18, 0x16c61386, 0xf92a45d3, 0x05d22816, 0xa59dfa8e, + 0x284907e2, 0xf03ee692, 0x9f3655aa, 0x8cd404de, 0xb7cbe4dc, 0x6f880244, 0xa377bf2e, 0x0d2b4680, + 0x2268025e, 0x44265843, 0x97bd3012, 0x42eb05de, 0xec4cb803, 0xb315c647, 0x3fa27f1b, 0x79e44232, + 0x53c279da, 0xa310d122, 0x4cab5ee7, 0xb1f5fd32, 0x28488724, 0xf2c4d54e, 0x8f4d4e88, 0x278937c2, + 0x413c2b77, 0x54033121, 0x6fa929c4, 0x29f416f8, 0x92c20f2a, 0x8b489488, 0xb3411a3d, 0x4d2dfeb7, + 0xa74043cd, 0xe6f410a8, 0xd8a8fa7f, 0x7eab0462, 0x5930dc92, 0x8d84664a, 0xf1a9301b, 0xe29c597e, + 0x19461556, 0xdafaee03, 0x4c7cf09a, 0x12325a98, 0xb77e9baa, 0x0ffec0e1, 0x819398e8, 0xadaa9702, + 0xb58c29b1, 0x2c88414c, 0x3a339e15, 0x37964ca7, 0xb1ec76b5, 0xc0446abc, 0x454ec3e1, 0xe32faec6, + 0x4c35b431, 0xe2ce2281, 0x8340f6a6, 0x80ca8f77, 0x359bcb81, 0xa4e482ef, 0xa89d27d3, 0x13aa440b, + 0x1e931a7c, 0xa7a5aaaf, 0x832a9915, 0x8ec9f759, 0x8d6f1927, 0xe701faaa, 0x1a519575, 0x9bf8782b, + 0x50e28465, 0xa2ffb3b4, 0xe685014a, 0x494cc6ad, 0x6963cb1a, 0x294fa4d9, 0xff1287ee, 0xb5b30db1, + 0x704cd447, 0x30853722, 0x7f8b97f1, 0x20e0690f, 0x7e367825, 0xe1587312, 0x14423091, 0x1f32faa4, + 0x0eed07d8, 0x2dee9d22, 0xe6c46996, 0xb8c3d131, 0x79f129cd, 0x3dd96dda, 0x0edf31b5, 0xbeca3cdd, + 0xab48768d, 0x6258c8fc, 0x62936583, 0x078b7690, 0x40ac1069, 0xaa0ffc68, 0x86d382f4, 0x130296d5, + 0x5bb38d84, 0xd8ca70aa, 0x05e0f77e, 0x92019f77, 0x6efbcfdf, 0x47d4c696, 0x381f720f, 0xa9f49988, + 0xeb1e55c4, 0x3b17e694, 0x1d680c7b, 0x328667e1, 0xef2a9e5f, 0x8dbbac11, 0x307604b8, 0x4038a50f, + 0x1b39ea28, 0x9f6dbb2a, 0x4a5faf69, 0x3acbe866, 0xa1b969da, 0xacaf5714, 0xf21e6bbc, 0xf99ef7b4, + 0xe8ebb48d, 0x5696e527, 0x6e9c74b3, 0x532a7712, 0xac2e8838, 0x57a85299, 0x94558c0f, 0x8e4fd53e, + 0x0a744a73, 0x4a1a6ac1, 0xb0ec3abf, 0xc3403c6b, 0x2896931c, 0x3ea2ff34, 0x803bf3e1, 0xb86a3a5a, + 0x0d0e2b05, 0x361667f0, 0x97e9b2d7, 0x66ecb961, 0xe5f29c2b, 0xf9b845ed, 0x0d0179c1, 0xe63e5359, + 0xefe32f2e, 0x2b93aeb2, 0xc0a14658, 0x5e2b3730, 0xfe9beb4d, 0x13af459e, 0xe34238b9, 0xfdd08844, + 0x5d2e20d8, 0x2ba0fce7, 0x98531dbe, 0xbf2c4d99, 0x6456aca2, 0x33be462f, 0xc3214353, 0x5907ce4d, + 0xcf947b47, 0x3b6252aa, 0x9ebff6a7, 0xf0aea551, 0x1c5c3c3b, 0xd9b7c797, 0x1318396b, 0x4c27cd72, + 0x49e069c8, 0xe0d6f417, 0xce3f3f3c, 0xbf4585ea, 0x77471e76, 0x67210ad1, 0x8e9333ed, 0xb337e7d4, + 0x7e8a0287, 0xf6439027, 0x6454658e, 0xd86025c2, 0x62596608, 0xd92792a5, 0xf3f29677, 0x52816ae4, + 0xa54b6e13, 0x0a3903a6, 0x78428e67, 0x0ee4ceb3, 0x936105c3, 0x7a63fa2d, 0xa1d0965a, 0x53a92157, + 0x1ae0d916, 0x7f6ed97b, 0x0984c953, 0x3588e3bb, 0x1dd97a18, 0x6a110219, 0x33fb2b8b, 0x798cbc56, + 0xab627498, 0xf2d7dda2, 0x147b7d63, 0x5fc2f39f, 0x98815ddf, 0x97055078, 0xf1491978, 0xaa57c046, + 0xa594de80, 0xb674aa87, 0xda2ec24b, 0xcea1bb39, 0x2ba3221c, 0xd4376562, 0xe955e9b1, 0x8252d4d0, + 0x9f00a976, 0x6d7ab000, 0x81c08d2d, 0x54103c26, 0x543f516b, 0x73b4b08c, 0x0c2d35b9, 0x0e39e2ec, + 0xa46c8cc1, 0x980cb37c, 0x5b6ce2eb, 0x50645554, 0x5c4dc765, 0xd38ace82, 0xa489c0d4, 0x26f96a2b, + 0x6f007bfa, 0xafe80248, 0xb15d7d70, 0x46e66664, 0x11e98149, 0x70232365, 0x5c4c6dbf, 0xc1688d96, + 0xa6481f58, 0x6dc70948, 0xa410d9cf, 0x306bdf20, 0x936413a6, 0x0784bae7, 0xe08f4097, 0x69788fb2, + 0xe505e32d, 0xfff12d31, 0x0742f205, 0x42bfb4c2, 0xd1108362, 0xc38f46e5, 0xea36d252, 0x56bf4934, + 0x1b5cb3be, 0x19bf9327, 0xd2cb6436, 0x8d8498a0, 0x4c3d33c0, 0x12672fb8, 0x33478eff, 0x17e82108, + 0xcf0a31d7, 0x3c79fbba, 0x5910f064, 0xf2969e12, 0xe32b4786, 0x6aedfc64, 0x4cba2204, 0x4f7c385b, + 0xcdf11eb6, 0xf44cf66d, 0xc7b87eea, 0xcc915a84, 0xc7bdbbeb, 0xeb1f6a3c, 0xbfbbd11e, 0xaa896f83, + 0xffb601c0, 0xc4ac5d28, 0x5e639ef3, 0x9103d2d0, 0x70588ef1, 0x5ade20b5, 0xb7e9526d, 0xf365714b, + 0xd89c0569, 0xe68bde18, 0x50bd2866, 0x6717ec2a, 0xae2293b6, 0xe2d86c69, 0x48f899dd, 0xe1cc7b9b, + 0x5db4cad7, 0x0ac6a786, 0xbbf6c3f8, 0x8f096b9a, 0x86f537da, 0x78a5569f, 0xa4f2d738, 0x6defcf95, + 0x35e97de2, 0x24c9a95c, 0xc6859bfd, 0x638ded22, 0xf24936c3, 0xba0fcc55, 0x7b8ba69f, 0x8627c868, + 0x7d2b4ffe, 0x36702ce0, 0x118a5f91, 0x590c3760, 0xbdca8daa, 0xfcd1eb9e, 0x1a0ff50b, 0x591f0cb2, + 0xbd808324, 0xcb003cb0, 0xb81ebfa7, 0xe5d5351a, 0x33d836c6, 0x3e411346, 0x0513381c, 0xe44f63c7, + 0x4f327b47, 0xae283abe, 0xca451d79, 0x82f61dc2, 0xc48c3de1, 0x7b900e06, 0x9adec741, 0xbebf5365, + 0xe5b4b690, 0xfe6d17f7, 0x6937e8f3, 0xcab14916, 0xe57c4239, 0x2b0cd14d, 0xb0d2687e, 0xe3b7ff9c, + 0xc9292218, 0x9ba71a9e, 0x89cfa302, 0x8044f28e, 0xfd28e66d, 0x0f8a05be, 0xc0d31045, 0xbb175031, + 0x50b6103d, 0x26f327b1, 0xa6e27f42, 0x47ff1112, 0x7063b674, 0x9c09962a, 0xbf549f48, 0x0c7566ea, + 0x954daabd, 0x2dc67e7e, 0xce5bcf56, 0x1b7033a5, 0x945d890b, 0x6aaed82f, 0x90920c57, 0xbf2c0269, + 0x82237f2d, 0x071aac49, 0xb42bd8dc, 0xcae993dd, 0xa5c5331c, 0xde2b2ce5, 0x7f4e9e87, 0x9ab76b84, + 0xaef6a4c2, 0x1c35b997, 0x14e8f728, 0x572ac04e, 0xb1e55721, 0x6e77db4e, 0x16ce8485, 0xa4b41439, + 0xcf400feb, 0x7ff226f0, 0xdc22ca84, 0xd2bc5f4f, 0x8bd7dbc5, 0x1d0278ee, 0x0530763a, 0x7c59a752, + 0xa22afea8, 0xc7a2571a, 0xdd823b07, 0x655afb9b, 0x4d89a381, 0xf9ce7339, 0xc347e7e0, 0x21e5ba63, + 0x68330849, 0xadd5032d, 0x7bcd3da4, 0x3328918d, 0x2790a38d, 0xe2a620cd, 0x062e8106, 0x25428d51, + 0x5c58d4ed, 0x16f9ef0e, 0x8185d6bb, 0xf9a56b53, 0x9b3d8825, 0x051d553b, 0xe6617d47, 0x88ea8b86, + 0x9216ca4f, 0x438f86ce, 0xec0485a1, 0xf60329ee, 0x84e660b3, 0x1ded490d, 0xf16facca, 0x0a3f0b07, + 0x49b91b27, 0xceeeba74, 0x279ef3bd, 0x08dda561, 0x8560cbd6, 0xed694ebb, 0x181a6232, 0xf7561713, + 0x57dbca30, 0x8c14ec03, 0x0d96ef90, 0x9d825058, 0xa4f1d083, 0x8c8ceb3b, 0x05be01ab, 0x18767803, + 0xd801790e, 0xfbedfc61, 0x7354c911, 0x38c6a4d6, 0x7576689d, 0xf7b844c7, 0x934dbe35, 0x93166877, + 0x94949d3f, 0x88c814ca, 0x77400263, 0xc39f91aa, 0xf25d7705, 0xeaf8af3b, 0x27e108c8, 0x62df3635, + 0x245ff66a, 0x0c992931, 0xa37c7fe2, 0x95ff128a, 0x62380374, 0xbb65e015, 0x3054f86e, 0x22deef92, + 0x5b1a55e5, 0x5a98fec1, 0x78ffc766, 0x70769d7c, 0x2cfc9b44, 0x20290f90, 0x40156695, 0x038fd4d2, + 0x32355473, 0xce84e00e, 0x142ba27c, 0x44a17fc5, 0xfa5bb6f0, 0x1705245e, 0xa9cdc464, 0x9f7da369, + 0x345fb81d, 0x54b7ce5b, 0x826a4b1a, 0xbf28617c, 0x4d5e54ff, 0xb6578018, 0x399fff48, 0xb29fb030, + 0xd5a75322, 0xb4e23a59, 0x7ce1525d, 0x404a2634, 0xdbbd0d5b, 0x17d57447, 0x143db643, 0xe96183c9, + 0xa37203c2, 0xb5470e2d, 0x991daf4f, 0xd2391f9d, 0x08d0d2be, 0xb102bb89, 0xf5f22bdb, 0x81bf8076, + 0xcc2f0f79, 0x265abe23, 0x0710f5b3, 0x16256a7d, 0xbd32835f, 0x9a7b02f1, 0xf7f2a792, 0x41dddfde, + 0xd8b7481c, 0x75d244fe, 0x02510b20, 0xdfb81404, 0xde49f0d4, 0xdda00362, 0xe3edecd7, 0xfed35873, + 0x02da6c76, 0xc4b2963e, 0x249a6d20, 0x27400731, 0xb6d40070, 0x22c9525a, 0x75c5751c, 0x0a97db4e, + 0x14f9b788, 0xd5bbe951, 0x95fb652f, 0x75df4d19, 0x4184e767, 0xd0c07fc9, 0x13643af1, 0xe9920753, + 0x9558fe1d, 0x5c6da50c, 0xcd32dc52, 0xd89c9441, 0xfd35fea4, 0x10f109ee, 0xa6975feb, 0xd299d0e1, + 0xa2d2b170, 0x78cb0830, 0xe27f7124, 0xe9d0ad50, 0xd6becdc0, 0xa158b547, 0xe0db9749, 0x4a645520, + 0x745de2d7, 0x16e3b4e8, 0x93d51434, 0x0a9879e8, 0x87308feb, 0x65ba430b, 0x8f3bb8e0, 0x67a5f314, + 0xc6c49b9c, 0x6268455b, 0x282f9648, 0x8e5d59e3, 0x8ba30d32, 0x8813e27e, 0x27842b33, 0x11443ba8, + 0x01fba412, 0xf4cc60cb, 0x60324be5, 0x49e95abc, 0xe049cb24, 0x7f0e7584, 0x52aadf92, 0x4a52f289, + 0x522668f9, 0xb6827d8f, 0x5c2ee24f, 0x35ed3cf9, 0x2270fdb5, 0xf7884112, 0x47e75fd0, 0x780175a1, + 0x22ccd038, 0x0e970e34, 0x3f737376, 0x73ab50f7, 0x919b0846, 0x8ad3442f, 0x9a606d50, 0x26a23dbf, + 0xd09544d8, 0x837ce84e, 0xb31168b8, 0x76b710cf, 0xbaeef4b5, 0x41d31dd8, 0x3395bc13, 0xd1c20efe, + 0x0e4f486d, 0x5c6b3870, 0xc3edf1d9, 0x4828a7d8, 0x3fcd3c2d, 0xed011fbb, 0x6ba92987, 0x54e66197, + 0x1b9fef9b, 0xe67bdaeb, 0xbb95dbf7, 0x717ea072, 0x1fc53303, 0x38837c6c, 0xa8ffb67f, 0xc204c5e2, + 0x99c95a08, 0xbc4f8d90, 0xf4fbcc6c, 0xbe29ba5e, 0xfeaef0a9, 0x42461c9d, 0xe06ccfe6, 0x1443ed1d, + 0x5d42da19, 0xa5834295, 0x23b0a29b, 0xa80edb0e, 0x04f080c3, 0x2c4709d1, 0x42a3c4f2, 0x1e9d4b77, + 0x0792ffad, 0x0d6c8d84, 0xadb0de57, 0x6c570758, 0x7c905f21, 0x3c602deb, 0xe590c0b6, 0x79dc7d26, + 0x493700fa, 0xad27b32f, 0x5efab18a, 0xf7419f93, 0x869f89eb, 0xc1545996, 0xe998e2a6, 0x6e208abf, + 0x7d63d74d, 0xf1aa7f38, 0x993ee5b9, 0xdef01926, 0x75161954, 0x8ee6bc05, 0x1082a8ae, 0xf042e5b0, + 0x64e90002, 0xec6436f8, 0xe2818e6e, 0x26ecc23c, 0x7447a097, 0xf0b5390d, 0xeee58e23, 0x38e6fae7, + 0xb0969795, 0xb15f68a3, 0xb8c2427e, 0xe8786f7d, 0x32c20a65, 0x548512af, 0x1c4bdae2, 0x906b25a1, + 0xf720af41, 0x4a42fe10, 0x0a5e7671, 0x0261b1f5, 0x7302b53d, 0x44da05d5, 0x556974ab, 0x22ca30b3, + 0xde096047, 0x0f4cc91d, 0x8dd99d23, 0xdb52dcd6, 0xcd188364, 0x07ba10be, 0x566c1acd, 0x062011df, + 0x314c002a, 0xd1f0f54e, 0x96a798f6, 0x423f0e4f, 0xea06447e, 0x981f74ae, 0xc36d6941, 0x0c86a0fa, + 0x739f5713, 0x5c773cff, 0x8c15105a, 0x1346d1fe, 0xd704413a, 0x168e9559, 0xd3ba43ae, 0xc674a744, + 0x4bbcc24e, 0x7993f85b, 0x9d3ec86b, 0xee831a4e, 0xc23c1586, 0x482a2738, 0x9f9c0878, 0x00ea479f, + 0x3246142d, 0xd9df3940, 0x18a67788, 0xed5a5646, 0xbd199a81, 0xc5d2e0ca, 0x972516c9, 0x6cfa0f65, + 0x6678cd33, 0xb6ca2de5, 0x5f6de051, 0x5d7f2470, 0x397b46e8, 0xe71294cb, 0x37f53594, 0x56b17df1, + 0x7b4cc794, 0x0a149d8a, 0x20a16f2f, 0xa8417117, 0x6916cccd, 0x89d8bd33, 0x6fa76295, 0x0575522c, + 0x1cab4713, 0x287d21a8, 0x03e63a8f, 0x5b90e24e, 0xd9546326, 0xbf521973, 0xa4e2b59a, 0xdfdb8e29, + 0x4733f27e, 0x6bd716db, 0xbc074789, 0xc1a95c90, 0x690255e5, 0x740b9fb0, 0xde01c19f, 0x6f35baa1, + 0xd530f88a, 0x18eea73d, 0x5fe3a146, 0x4dc9afb7, 0x0eac5a40, 0x5468aaa6, 0xda8fb30b, 0xa37208fc, + 0x631afc99, 0x5c98f3e9, 0x5e74d8b8, 0x744a5e02, 0x19043128, 0xcd2b09f1, 0xadd1bf45, 0x95433362, + 0xc5e0bdcb, 0x340b6436, 0xf6f4ea63, 0x07820832, 0x0d2f067b, 0x489381b7, 0xd5133dc2, 0x1f11060c, + 0x76e66ea0, 0xefd90f01, 0x9ba1ea03, 0x6d44f47d, 0x6f16ec54, 0xcfc00f38, 0x2e702752, 0xa3ad9e91, + 0x00a66a0b, 0xefeacd45, 0x312ce213, 0x52b46e37, 0x65d019b6, 0xef1d019f, 0x772dd3c4, 0x5208df06, + 0xde8c4a7b, 0xfb56c6a9, 0x2a434489, 0x0999f446, 0x4844cd7e, 0x78d218f4, 0xd1202f3e, 0x64d6f8ef, + 0xe199f06e, 0xdc6882e5, 0x1970a869, 0xc7ed3069, 0x6816e4f7, 0x2dd2a0bf, 0x231e885e, 0x2c24442b, + 0x7fd5393d, 0xa1166ae7, 0x9c67d48f, 0x99a584d5, 0x0d4f86a6, 0xedf4e496, 0x8d70cf7b, 0xd6010b5c, + 0x81117fd5, 0xdcd38d8e, 0x6ec6265c, 0x3fd4458b, 0x4cfedd27, 0xcc5a1f3e, 0xd901114c, 0x4e35f7c7, + 0xfdba3d9d, 0x81e5b305, 0x3caf8ef3, 0xffda1650, 0xf096c8a0, 0x019740c2, 0x253c4e08, 0x34a935e3, + 0xebf97a1d, 0xb5351c26, 0x0878c41b, 0x7c506735, 0xf2333241, 0xac86d4cf, 0x69f866c7, 0x7ea7689a, + 0x8f397997, 0x5a65c392, 0x18b0aa8c, 0xdb42deb8, 0x53d5c224, 0xf866a6ff, 0xadeeaf2e, 0x8b64c0d1, + 0x4ea407da, 0xe3fe115a, 0x4c673451, 0x8aafa737, 0x86e4f19c, 0xf62d28e5, 0x2c5a5901, 0xcfabc4ad, + 0x0d40d350, 0x4ea5ff3c, 0x65c8cb10, 0xc6fd1fd5, 0x72702cf6, 0x760132d2, 0x543aef13, 0x5a1cd3d5, + 0xf0c5e38f, 0x535a1842, 0x8f25dffc, 0xdc6ae04a, 0xbead2121, 0x55197eba, 0x6894d0b6, 0x8ee21f03, + 0x2b52d3e8, 0x16317d8b, 0x83f455bf, 0xd413fcd1, 0x7c3d8566, 0xab2ea376, 0x4c0d8714, 0x46a32bf9, + 0xe027f72e, 0x53b6ae99, 0xc60165e9, 0xc3c51825, 0xce61de69, 0xccf97d16, 0x59f89f1c, 0x6ca48ef4, + 0xb4854162, 0x120bd5ea, 0xb18987ab, 0x995f7b8d, 0x7c11e4bc, 0x0790617c, 0x0e6be392, 0x01338695, + 0x78db6e73, 0x599758f8, 0xf63bcf4a, 0xcd0cef53, 0xf4e4d618, 0x19c946f4, 0x45981110, 0xe868904f, + 0x30e4d700, 0x3d7773a4, 0xa5d566e3, 0x49ea0e3d, 0xb2984ed8, 0x732db7ce, 0x6ab0f76f, 0x106ddf9e, + 0x5c5a8970, 0xd5f5d606, 0x549585de, 0x67847116, 0xee7c76b1, 0xd3c93219, 0x2cf9be24, 0xb6a16f26, + 0x002af305, 0x4d0620dc, 0xb3ba658f, 0x0a42b829, 0xe29a6891, 0x8d5f8623, 0x2aafa71d, 0xe243b986, + 0xd157ad7e, 0x4e1c7904, 0xd9d9b92c, 0x049b572d, 0x337dbaca, 0x2a54492a, 0x42c9a66b, 0x1785724d, + 0xec2fda76, 0x11940f00, 0xdf0f3407, 0x000fe269, 0xbc8f5324, 0x51d8c175, 0x80f17ad8, 0x0a3514e1, + 0x16b3c791, 0xbd670aa9, 0x50dfa369, 0x17415f80, 0x8ffbfe4d, 0x1c3da99a, 0x0957252d, 0xb539e6a5, + 0x5b450b8e, 0x2ae6124d, 0xfc06fd2d, 0x7d931ac9, 0xc595ab64, 0xff99b2e8, 0x0fd0ce0e, 0xba5205e1, + 0xdae3dc45, 0xf056c921, 0xb9a10fb4, 0x32fc3349, 0x35e1c60e, 0x3a960c93, 0xad75ce0d, 0x66ae0a21, + 0x053c331b, 0x4d3e11fc, 0x456b065c, 0xe025b3f3, 0x3c9de797, 0x1f595d48, 0x65ac031c, 0x1d045837, + 0x69c9803e, 0xe2f8a1e8, 0xbc84114a, 0xe304bac1, 0xd9413349, 0xbb48f67e, 0x3645bb31, 0x162c25c5, + 0x70b62850, 0xfbfd42b3, 0x965441ea, 0xa79676be, 0xe2f84d26, 0xaa781c2c, 0x88deb530, 0x43a5630e, + 0xb8f00da8, 0x92933943, 0x3ba3d7f9, 0xf96f6543, 0x8b6140db, 0x79bf673a, 0x2a7f1f7f, 0x6e755212, + 0x3c6fdc48, 0x04635a91, 0x3b950237, 0x22e668ba, 0x2a4cacd0, 0x670a8a03, 0x36960591, 0xae10c9a5, + 0x4ef9ab56, 0x8466d428, 0xa6d0abb5, 0x77e60aa4, 0xf57b612b, 0x71e59407, 0x564a8558, 0x8eb5c1f0, + 0xb3184422, 0xbecf993b, 0x00cb77a7, 0xe1749df7, 0xf665cce0, 0x27e8b2f7, 0xff762b11, 0xa2477941, + 0x0c7abbed, 0x887cdc43, 0x45e95731, 0x3ed1b1ac, 0xf189a978, 0xf5b588f5, 0x2f9fafee, 0x136e8eda, + 0x7f032d83, 0x5ba8498c, 0xe5acfb3f, 0x297d5cc3, 0x3dd861f8, 0x5dd7f86a, 0x6b46eddf, 0xd639a2a5, + 0x92218dac, 0xca3544e7, 0x7130da33, 0x9667e3b4, 0xf0975047, 0x85d3fe3e, 0x4e4cb797, 0xf7690e64, + 0x4559c194, 0xb9e738a6, 0x10e73104, 0xd7c9fca2, 0x6e4f8555, 0x0e02a15a, 0x9627cb90, 0x5b1972cb, + 0xd98a740f, 0xbbb18f14, 0x5cc6cea6, 0x0ca32e4e, 0x9f15194f, 0xaac00666, 0x0b731cba, 0x69fc9464, + 0xe9e14d81, 0xedfb4f75, 0x4b214dc0, 0xb3f00a1d, 0xdf92281e, 0xe18150ce, 0x91a285bc, 0x96efe944, + 0xfdcf8f33, 0x18f4a6e6, 0xa704f2b1, 0x77b003de, 0x11ee6319, 0x95401593, 0x50b962d7, 0xafcc50af, + 0x89f513ba, 0x5a3a561b, 0x11e12b32, 0xa510391a, 0x33ae184c, 0xa0073802, 0x698eb929, 0x0172a04c, + 0x913006d0, 0x99e7c48e, 0x1e8fd6a5, 0x70292aed, 0xf046cf88, 0x52bc0800, 0x4c2e8a76, 0xd1c6ab26, + 0x646c0279, 0x3b7b5f57, 0x92444b8b, 0x75601546, 0xe6f3845f, 0x8394aa1e, 0x69ec82c5, 0x5670f149, + 0xfcce9055, 0x8307b510, 0x457b9a99, 0x85fe367e, 0xd7c6b50a, 0x1b13defa, 0xcafd3f02, 0x7962e5d9, + 0xd96fecbc, 0xeb402d6f, 0x88396cc2, 0x2ac5abcb, 0x176e76c1, 0x1dd1da91, 0x5e92df86, 0xa6aeb584, + 0x0bcb8040, 0xd881dced, 0x5734e90a, 0xceb07a2f, 0xb1e9c794, 0x8803ae3e, 0x4bc686bc, 0xa1f01f54, + 0xfd893e87, 0xf289e43e, 0x1026f5f0, 0xc468abed, 0xd440e995, 0xcee10f40, 0xff69f0a1, 0xac6e4e14, + 0xe3367bf6, 0x54ea5220, 0x822cdbe5, 0x7811372c, 0x8a4a2c70, 0x66c88b42, 0x5f6bc6de, 0x33bdbf59, + 0xfe34652c, 0xc2877857, 0x1ebcb4b0, 0x1c37c19b, 0xa4acb3b7, 0x96048d55, 0x8b1380fa, 0x9ed16ced, + 0x8a1eb4d2, 0xcf5fcfb4, 0x404ab291, 0xa1bca4f2, 0x5ebe2d42, 0x4210603f, 0x6282ea83, 0xd7d8ff53, + 0xe8f680a8, 0x2c8a1beb, 0x327b43ee, 0xe1866f8e, 0x0e0b3e4e, 0x01d2fc02, 0x6a416a9e, 0x87dd9ae0, + 0x603bb04b, 0xbd55dbc0, 0x0047b9d4, 0x239adf79, 0xddc709f2, 0x861b37fe, 0x5bc89a99, 0xd3ccb48f, + 0xb9e9197e, 0x4e084ca8, 0x4f8911d4, 0x3d455244, 0x2ae40fb8, 0x81e4e9fd, 0x3fe231cd, 0xc3bc1c76, + 0xd6aca8f7, 0xefeec08d, 0xba30de06, 0xed45c7c5, 0x3c345c43, 0xb3e16de9, 0x11a85c7d, 0xfe8e9dc7, + 0xa1f0a74a, 0xd5629af4, 0xe148a467, 0x9f028aa4, 0xd0711f1e, 0x6d13026e, 0xad3060bf, 0x20a70e36, + 0xf27b0f59, 0xd801094e, 0xf6dcc8b3, 0x69861707, 0x0e19c6a7, 0xdb03cdb6, 0x29242ff3, 0x653ac8a7, + 0x7afdfbf7, 0x202a958c, 0x5f0d795c, 0x20a7d314, 0x3538724c, 0xfe3e5c7f, 0x0e075cc0, 0x801d9cc2, + 0x389cc15c, 0xf1e756cf, 0x59639f39, 0xae35cf35, 0x6de52d30, 0x5c2f919c, 0xd6810b1a, 0xc9055244, + 0xa5192870, 0x66bb25e0, 0xbfc03323, 0x5d12879c, 0xf82cb656, 0x78dfbd27, 0x382a6f56, 0x3f2ade16, + 0x22042856, 0x64e67250, 0x7a7d9c9c, 0x4e8e1878, 0x4fc508ba, 0x80b5bd1d, 0xcc6f1a21, 0x0782e1fa, + 0xa45c6817, 0xd305d325, 0x36424d33, 0xf7d0b31a, 0x261b3d31, 0xd3fd4526, 0x03106637, 0x4bf243ce, + 0xd478a834, 0xfc120c9a, 0x3509f037, 0xebe6a7b7, 0xd723bc46, 0xad4d1937, 0x7c126884, 0x6808939d, + 0xa8524b98, 0xb2e7a3c0, 0x2a5e7bef, 0x38f02c45, 0xa06c14cc, 0x63ed5353, 0x2e7957df, 0x290601d9, + 0x9930a908, 0xc3b25ab3, 0x4cefe4b7, 0xdf737d01, 0x00fc2567, 0xa55190e0, 0xf35a827c, 0x7a4ac655, + 0x05f7806a, 0x2b53378f, 0x0378e369, 0xfce48ef0, 0xb7c068a3, 0x0a6127c3, 0xed9420da, 0xa8f0c336, + 0x7a26b465, 0xeeb4114b, 0x628ab19f, 0xecc01460, 0xdedf9b0d, 0xf4ddc3a2, 0x99789961, 0x0a5c20c7, + 0x79ab55db, 0x076cbbd9, 0x39bbc7c4, 0x58a9c6e6, 0x5c82fbb6, 0x76d0fcba, 0x9f1a7302, 0x49df973b, + 0xf2530cef, 0x4da35ed4, 0xbca057bb, 0x670481d5, 0xbf397fc9, 0x1da7a366, 0x6845dfa6, 0x69fa9e9f, + 0xec5bc192, 0x399683b4, 0xc80c51eb, 0xf1c094b5, 0x04e67a80, 0x22cac260, 0x9d20606d, 0x2de081ad, + 0x5b02bf32, 0xc47d8859, 0x2fae7645, 0xe5dd82f1, 0x92c1eced, 0xda17ef73, 0x7037cbfc, 0x70b9f61d, + 0xe1a642e8, 0xfdc34bdf, 0xda6e7c95, 0xe6ae23fe, 0x6251cfdb, 0x23382c34, 0x089be883, 0x81f93ea8, + 0x470840aa, 0x0a60609d, 0x75f5f465, 0xc0e40479, 0xbb044e60, 0x2c1f3f29, 0xff3e8dcb, 0x33dab8f0, + 0x34fa3d0d, 0xf28798bc, 0xf29a9865, 0xdbf89108, 0x414394f2, 0xc152e457, 0xf3b61ad9, 0xe925adfe, + 0x52c443bd, 0x8b240cf9, 0xfba971d4, 0xda00b535, 0x2004d043, 0x88a4b159, 0x3d08045c, 0xe8ddc483, + 0xde46793b, 0x5263ffa3, 0x31e23e4c, 0x9022343e, 0xa11a71dd, 0xd2c148b9, 0x1498d447, 0xa83a559c, + 0x2202e90b, 0x031d5954, 0xf47e39e9, 0xdb6d6091, 0xd4d47ccb, 0xe26034a2, 0xd1afc4dd, 0xad75ae92, + 0xdd06342b, 0x4dbb7b38, 0xc326ee9a, 0x694a5bea, 0x8b6c177c, 0x62dde297, 0xd6abc9ed, 0x6a6dd5fb, + 0xcfb11b72, 0xa0b1cb8e, 0x4d1d4580, 0x421d775f, 0x510246ff, 0xc3160e2a, 0x2f06c988, 0x9536c37b, + 0x619e2313, 0x39ef5585, 0x357368b7, 0x76f27361, 0x66de04e0, 0x9c4e7604, 0xeb67d71a, 0xce2fa90a, + 0x80392dec, 0x72842929, 0xc0680ca4, 0x9572d66e, 0xdc94cd73, 0xb2b3c0dc, 0xad0339ae, 0xae6e8017, + 0xb4e08465, 0x4fcb376e, 0xf35ced66, 0xddf40dd5, 0xd9ddd0a9, 0xccdf36cf, 0x3fe39003, 0xb461df65, + 0x2dad8d7b, 0x81ed8eab, 0x4e02fe34, 0x3e630fc2, 0x68408e51, 0xd8f45c44, 0xb731a48b, 0xf09f6ac3, + 0xc53110c3, 0xf3575dc9, 0xe603bd46, 0xf889c6f9, 0x192bb804, 0x4d60e418, 0xb3060145, 0x6ed13ab9, + 0xc6742e23, 0xd27b9a47, 0xb8f2c0e3, 0xf3129d02, 0xf2a9c2b7, 0x5baa4d93, 0x8562bbde, 0x20b5f74e, + 0x8bb99243, 0x64662d70, 0xc4461822, 0xb6bad410, 0xe35efb6b, 0x01da37cc, 0x9cc30e8b, 0xd68695ce, + 0x4fa030f4, 0x20a54b2e, 0x300ecae7, 0x2779c1b2, 0x6596cc37, 0xd3ac8415, 0x32e85597, 0x9088633a, + 0x1ee16fa1, 0x07414bad, 0xa7a0130b, 0xf59d3dd3, 0xb7fc2aa0, 0x7c864921, 0xa4059049, 0x18a01901, + 0x69463001, 0x89b01fd2, 0x92a3274e, 0xef0d0f7f, 0x9230360d, 0xb3a06c5c, 0x57315e0e, 0x044d41af, + 0xfad29251, 0x4dcde80a, 0x1cf43dc5, 0xb6b3b86c, 0x64819401, 0xe7c60ef0, 0x1da796b2, 0x7076c267, + 0xf138a445, 0xb0963bdc, 0xd97af2f8, 0x7448e807, 0xbf074f36, 0x188ae37b, 0x11147463, 0x201e2291, + 0x042c7461, 0xbc814d9e, 0xd18ba321, 0x92bb9189, 0x831d588b, 0x7639cb52, 0xee7a0bdb, 0xe613a30f, + 0x277b89f2, 0xcfddc592, 0xb3ba79cb, 0xa46799e4, 0xee66bd81, 0xeaca2d01, 0x04ed1250, 0xba8e477e, + 0xfcd1be95, 0xf325e8a5, 0x4854888a, 0x87ffa69a, 0x36a5f1f6, 0x3e697c77, 0xa1bf69f2, 0xf67d3363, + 0x7109cd85, 0xede86c44, 0x17c26180, 0x3d601b94, 0x2f85855a, 0x8e9bb461, 0x9c9ca807, 0x587cf890, + 0x37188fdd, 0x92be3b26, 0x9b5af781, 0xf58b56b9, 0xe2f655ef, 0x9b32d420, 0x98298da1, 0xe5a69c71, + 0x2e77d820, 0x12d8083f, 0xee7053ab, 0xc02e1958, 0xd5f9ca14, 0xf3ddce05, 0xd5344155, 0x4d302db9, + 0x6f22a79d, 0x13fbe632, 0xd6b37ef7, 0x41ba9ece, 0x74db6a8c, 0xd2cdf087, 0x84bdc1d4, 0x3f10217e, + 0x9840af84, 0x8c96dc06, 0x3cb79280, 0x77043b47, 0x1d541c14, 0x384be80f, 0xec6ea888, 0x17ca8df2, + 0x553728e0, 0xa6f82659, 0x23cad615, 0xb3366bc2, 0x951fcda6, 0x27acf08d, 0xaebf2ea1, 0x6fd7e23e, + 0xb8b6c000, 0xdf71b3ba, 0x8da51485, 0xff1ab4c7, 0xd40136de, 0x9002f67a, 0xe0b3c889, 0x04b1381f, + 0x0b38ca89, 0x68debf64, 0x9708fb36, 0x8a47ed8b, 0x57e84e09, 0x78f630b1, 0x22ee062e, 0x184a3aa8, + 0xa1abfd56, 0x4d7b3b37, 0xf4fe8f32, 0xf9b7f864, 0xb8a08d43, 0x0fc4555c, 0x9866fb62, 0x75dbc14b, + 0xc862e813, 0x8e191f79, 0xe38ca95b, 0xff93ca46, 0xd5f8e172, 0x6c47c4be, 0xb985d005, 0x32fc6884, + 0x16bd2246, 0x3bf5af89, 0xe4c85610, 0xde097f9a, 0xf1ff82b3, 0x3c9a063b, 0x60f49d84, 0x8dc39d4a, + 0x66afad72, 0x8a2eb1d3, 0x0d0f7efe, 0xeda3e57e, 0xa0d66af1, 0x2a52ddef, 0x88d1038e, 0x8dbb75be, + 0x1037bcdf, 0x5a108048, 0xfb78199c, 0x8a01ddf5, 0x4e87603f, 0x6e3b0c12, 0xaff7e3e9, 0xe4b1af5a, + 0xafb4465c, 0x3cc7d790, 0xc5a1baf8, 0x9796afe0, 0x71641864, 0x79ec7a89, 0x6d809644, 0x7afc2a65, + 0x288ce27a, 0x5be50125, 0x3be44080, 0x7bcb8e02, 0xcdc5a470, 0x9cd127b1, 0x9933480f, 0x23242583, + 0xec338475, 0x944fe93d, 0x0cb73510, 0x8a7f7ba6, 0x21bf6ba1, 0xd8a688a9, 0x306330d2, 0xe6098686, + 0xa8989890, 0xfcf0afba, 0x940bc2b1, 0x3d4fc4f6, 0x6eafc41a, 0x8c4d49d3, 0x3739da62, 0xf028c65e, + 0xeaaee8ac, 0xe0981267, 0xc5076185, 0x24634294, 0x14b8be3f, 0x5e8b2417, 0x02fee8bc, 0x0d407c05, + 0x1730a1fe, 0xfeedb77b, 0x9d79ce78, 0x260c99dc, 0xac3ee923, 0xb0477387, 0xb99cc3d1, 0xcb2912c4, + 0xae77ae1d, 0xea0dc5cb, 0x5806bc23, 0x2e1940b9, 0x35c0e8d5, 0xee6a31ff, 0x005d86e9, 0x8661a541, + 0xe6747b12, 0x23d5d943, 0xdefa6c1c, 0x6638f200, 0xfe6e08a3, 0x74c82691, 0x7b303d1b, 0x0e0dc5f0, + 0x393a98a3, 0x42b846b8, 0x1d6557a4, 0x4c43f2dd, 0xd9edeb14, 0x850dacd9, 0xfc99c42d, 0xa57133b6, + 0x8e9c7dd6, 0x3a8e3f57, 0x6521e3b5, 0xa015a07d, 0x4ed5f568, 0xe77b40e8, 0xd1dbd6bb, 0x6106680c, + 0xa97cb937, 0x138384a8, 0x075cc976, 0x048365f4, 0xdcfa629b, 0x06d769b5, 0x71c81db7, 0xd4afe8d3, + 0xf6204a86, 0x2204dcdf, 0x42d78735, 0x939cc963, 0xeb6b34db, 0xc511b152, 0x24d2afbd, 0xaac51f69, + 0x4b7ee24d, 0x5f5a510e, 0xac035117, 0x5e1d441f, 0x9dc3492d, 0x79f4b928, 0xfa8f5735, 0x17c86279, + 0x8148d684, 0xdcf91914, 0x27ee3278, 0xeff9295b, 0x78495226, 0x1cf95b8f, 0x3314967d, 0x5f8596e2, + 0x5b669c31, 0xb7cfa646, 0x225f9b1f, 0x0c1e5f72, 0xaaad8db3, 0xf918b02c, 0x479cb7be, 0x7240841d, + 0xbdadf184, 0x924ffcde, 0x04fd46dd, 0xfdac9551, 0x37761622, 0x82529215, 0x0fab2b5b, 0xe4032c25, + 0x6e1b88e0, 0xecd51edb, 0x3c419b25, 0x9f686af3, 0xd4226d01, 0x3e9d7645, 0x4e6334c6, 0x19d5c587, + 0xa82530e1, 0x6e1071ab, 0xf9ea44fd, 0x38d68a24, 0x12612821, 0x52c4b9fa, 0x204197f4, 0x25b70198, + 0x8034b3cc, 0x9109427b, 0xa3bead7a, 0xdee1f23f, 0x23559f01, 0x49a1f595, 0x98853c5d, 0x2210fb60, + 0x961046ca, 0x3c7d8090, 0xc281c4aa, 0xb16f68d9, 0x5ed748ed, 0xb6f82ca1, 0xbaaf8801, 0xb0e2ed02, + 0x35b24e44, 0xbc967fdc, 0xe8b5a0e6, 0x91f95f82, 0xc505b82f, 0x22391bc7, 0xdb255eab, 0xed3485ae, + 0xa9b47136, 0xdb79e5d6, 0x74fe1bed, 0x7eab7a41, 0xa6998859, 0xbed5abe8, 0x47dae7ed, 0x06fc232f, + 0xf495a2ab, 0x443da2dd, 0x7d7b7c11, 0xc250af4d, 0xd5bd3756, 0x1bf42f13, 0xbce6ac5b, 0xafa38ad0, + 0x3b8724d1, 0xc01a5eeb, 0x2f153a95, 0xb094fe6f, 0x29585f7f, 0xc0354fa7, 0x78289c06, 0xad64d7df, + 0x6deefd8f, 0x94b89168, 0x4e56a1b8, 0xa5a65466, 0xbbc0313e, 0x0ce2cbca, 0x420014a3, 0x4dd14544, + 0x547fed2b, 0x340711a8, 0x8322efd6, 0x6649b756, 0x92d25286, 0x452ae450, 0x604dc15f, 0xc2daa9f5, + 0x22cf3046, 0xcabc5889, 0x261b4fa3, 0x142bd295, 0x0f98a7fb, 0xb74ae020, 0x0b9d35bd, 0x72c387c1, + 0xc82c10f8, 0x7d58f45f, 0xf2944301, 0x4f2a855d, 0xf7af3388, 0x68d3f139, 0xf529b284, 0x8f126f67, + 0x7cc4e544, 0x394f1e40, 0xa76120cd, 0x924d39a6, 0x6c193c6a, 0x27e62f0c, 0xc24ce652, 0x8a55a5b6, + 0xda72e8b0, 0xbd3901a9, 0x0465c657, 0x136c2db3, 0x8c1f2a02, 0x477a8820, 0xffdcbf9f, 0x2f42327e, + 0x70512966, 0xece56b5e, 0xdb2c1c59, 0x4d5ea84a, 0x985462b6, 0x78e7f9f2, 0xb47fbfc0, 0xa81dc2ce, + 0x27b580d5, 0x354b0f0d, 0x8a1359ea, 0x1bf12ffc, 0x3e0b0a95, 0x1a07d345, 0xcd19d2c8, 0xcdc76d4f, + 0xb7d1ad85, 0xc5407476, 0x9bacf83b, 0xb7abd0f9, 0xbe87d33c, 0x96bc8106, 0xd5fd1c67, 0xf7f74bb7, + 0x16fb3252, 0x143dd6c0, 0x079141e4, 0xeac54dcc, 0x20573c86, 0x946c1eee, 0x1602d97b, 0xfff723ed, + 0xf5c8a9c6, 0x3f6bddff, 0x9d682e77, 0x4b17c680, 0x88298116, 0x72013b6c, 0x2d12bce5, 0x68620402, + 0x3675d021, 0x64668d46, 0x0b157883, 0x0d115dc6, 0x93bae19d, 0xe33aefdc, 0x53622ef1, 0xa157ad62, + 0x31d1b1b3, 0xf50b76c6, 0x230c6474, 0xef45b9a5, 0x6d363f59, 0xb38aef3b, 0x04b5ca34, 0x5837d498, + 0xdf1470d6, 0xd5748ed0, 0x1d3692d1, 0x57f9f183, 0x2386289b, 0x43a289ef, 0x51c68225, 0x47c39b90, + 0x1be407b6, 0x26ba4b1f, 0x30113878, 0x13e9c33e, 0xe1bd3967, 0x7070c0f5, 0x4cd97e21, 0x36c9107f, + 0x5bc1da98, 0x235dfcbd, 0x7f162115, 0xccf060a2, 0xac8702d2, 0x6f7b2bfe, 0xad2a495c, 0x6b1b388f, + 0xc8052f57, 0x3f7eb3cd, 0xbf44c365, 0xcd4d4b88, 0x06203010, 0xca317727, 0xd4ddf768, 0x073a50fe, + 0x3697cdd3, 0x7f05681f, 0xb5177744, 0x30b6deb2, 0x4a8f284e, 0x90c3222c, 0x18fa1b2a, 0x54d1162b, + 0x38b9d193, 0x15e35b39, 0x5765a499, 0xd06835a1, 0x9e753cbd, 0x1749cd6f, 0x860e7600, 0xe2d9398f, + 0x5f78f1e9, 0x48fff988, 0x1409e604, 0x9887dc74, 0x07ccf2bc, 0xf21908b2, 0x5e25a19b, 0x4c144191, + 0x4adb536c, 0x4d44d8d8, 0x90cdfed1, 0x1ecbdaf1, 0xc7ffdb93, 0xf8a67d78, 0x23dc9ef2, 0xc0beeb5e, + 0xa6496b21, 0x6d74b97f, 0x27a23ded, 0xbb0fd408, 0x823ee38c, 0x35b0a022, 0x4d5e755c, 0x5dbabee7, + 0xd8a12484, 0x6f8e4b75, 0x432b9f69, 0x532bd229, 0xa37de6e7, 0xf9e1c383, 0x3f32238a, 0x6be45385, + 0x8647b059, 0x610fcdb2, 0x50c8e7bf, 0x7f76811c, 0xdf75d06a, 0xe003912c, 0x2dde3173, 0x83d33fcb, + 0x7d17885a, 0x3e260580, 0xc1386f30, 0x49f3cf31, 0x5e88fc5d, 0xccea85fa, 0xd9074edd, 0x99ef434a, + 0xf69ba176, 0x94ac1b89, 0x38d8f6b1, 0xb7987fef, 0x63b71109, 0x7a33db37, 0x01509c2d, 0xa6618f52, + 0x9a5d527f, 0x860ea3b8, 0x9e21662c, 0xbcc3a554, 0xa4f90b93, 0xfc64f1b0, 0xaa368584, 0x2caa86ac, + 0x5b238541, 0x17d91e6a, 0xdef02401, 0x6d13cf05, 0xb968c918, 0x3c9f47f4, 0x34cb1119, 0x07723436, + 0xc18bb429, 0xbcb7bb90, 0xf7c99ffe, 0xb9e5a4e2, 0x060db9bd, 0x126670d3, 0xedb567f3, 0x0697bbcb, + 0xe0b454c6, 0xf6fb58e7, 0xc43eb841, 0x3937fe8b, 0xa86e8abe, 0xc068cbf8, 0xb047162e, 0xec7a9798, + 0x95d70cd3, 0x53bb04c7, 0xb00abb42, 0x2235b572, 0x4f156b6d, 0x3104d3e3, 0x64334471, 0x8d59ff17, + 0xa35947bc, 0xb1dedcfd, 0x885bae1e, 0x8d14ef2b, 0xd5d70ff5, 0x005b1132, 0x32288c82, 0xf6c671db, + 0x115849a9, 0xfc43edcd, 0xbb0ae0e1, 0x594144ff, 0x1a6dd967, 0x6ee5b4ad, 0xfbbe0fde, 0x8fae5a7f, + 0x20e03f74, 0x2c183bea, 0xd4a01f74, 0x7801ade7, 0x06bd02aa, 0xee1c8c7f, 0x67b71a46, 0x8a1d1646, + 0x450df106, 0xece84983, 0xc2d17d8c, 0xe573d712, 0x251ccaa3, 0x4238f744, 0x69ed6cc8, 0xf2b9e543, + 0xc24acfff, 0x918515f4, 0x65c1c8dc, 0x1f49c150, 0x7053a9af, 0xd3378cc6, 0x24f566fc, 0x8324f491, + 0xb9228a0a, 0xad75a19d, 0x8bcaaee8, 0x3b27bbeb, 0x3a54a745, 0x82f29baf, 0x9beb5dc9, 0xd32946d6, + 0x7ab4598e, 0xf716ef30, 0xd3903bab, 0x2763a0c2, 0xafa8bcaa, 0xe5c100b1, 0xef2dbcdc, 0x757fc76c, + 0x7559baf1, 0xd8ae1604, 0xfef3470e, 0xfcb30c3e, 0x635bc26f, 0x1b6acadd, 0x7b4c248b, 0xe891b658, + 0x4501b7e0, 0xa1a88944, 0x5b22931b, 0x86a01d3f, 0xd4f455d9, 0xa6d7982e, 0x01336ff1, 0xac548a6e, + 0xba4e6edf, 0x6d2c1909, 0xef7836aa, 0x2bdac515, 0x47ec9d7d, 0xbb6f1d27, 0x2a93a33d, 0xcfe8c1a6, + 0xcbb33fc2, 0xe5b3e8e6, 0x59bae671, 0x701323ab, 0xca424881, 0xa788a89c, 0xf10466cc, 0x11c98b95, + 0x3a896eaa, 0x7dfb0191, 0xf2b2eeed, 0x66f133ed, 0x3bd9fc4a, 0xc5c9d34c, 0x4fc48723, 0x720ec6f9, + 0xd7414e49, 0x383994b1, 0xe5591c97, 0x2db7cfb6, 0x2b6520bd, 0x32f659aa, 0x6c416d84, 0x65509b5f, + 0xae84b862, 0xa998b317, 0x63a42540, 0xb9295b7e, 0x9f128a18, 0x53432a09, 0x43d69390, 0x30e2bb82, + 0xc8561cb6, 0xb8a1cf75, 0x707b68d0, 0xeec522b5, 0xdc002942, 0x5433c2ac, 0xaa049a63, 0xa41af5e7, + 0x2271057d, 0x8210e0b9, 0xd28f1e20, 0x26585241, 0x799cddee, 0x22955af2, 0x415129eb, 0x06332561, + 0x675af1ee, 0x231e6c03, 0x63dbd7ce, 0xa6778cbf, 0xb5a8c394, 0xa3d11e59, 0xa58c9853, 0x7bf894ef, + 0x0497d0a6, 0xa38c0db2, 0xb33059c6, 0xbf428444, 0x79a24f37, 0x53608262, 0x92709790, 0x79e21927, + 0xeb9b71ef, 0x642ac076, 0x691b28e2, 0x23d7cf6a, 0x96cd5f0f, 0xbe766076, 0xbe689d02, 0x8c08f417, + 0xb9f3d4c7, 0x4e8201bb, 0xd0e09054, 0xe30bafbd, 0x3a627f7d, 0x5206c50b, 0xd9c38e13, 0x8bde0ef3, + 0x0ab0b8ef, 0x039911fb, 0xe6f1a800, 0x2cef47d3, 0xcc93eddf, 0x386381ce, 0xbfaa0858, 0x28d86b51, + 0xbdf0541f, 0xec0d9fdf, 0x1dffc434, 0xb7f836bc, 0x1606c2cf, 0x11d05c31, 0x2e2eca8d, 0xa0443ca9, + 0xf4f70a84, 0xb0d79ce9, 0xb72f622a, 0x8a98274e, 0x08883cc3, 0x4c604ad8, 0xbe5d9cca, 0xdbf78f07, + 0x27dda585, 0x397013d7, 0xee469114, 0xd35535bc, 0xb516ff39, 0xc607c597, 0x6110df29, 0x62bc2223, + 0x057ea0e3, 0xd6b1d862, 0x31f702b0, 0xac89550d, 0x1b4b5d8c, 0x55839d7b, 0x6dd8bad1, 0xe8082508, + 0x264dc119, 0xf9f51ebd, 0x54113018, 0xd9580ae3, 0x3b48b8b3, 0x88f95001, 0x1c3e8ef0, 0x15dfe896, + 0xf3a2c526, 0x6c860818, 0x91c7c058, 0xf211ec39, 0xceed0049, 0xa896f51f, 0x0a95eadf, 0x5c2768d9, + 0xc4a4e9cc, 0x5c5f6506, 0x1a4b7f5a, 0xd16a2d1b, 0x801e2283, 0x069cffc2, 0x9c690ea7, 0x95caa945, + 0xd896a68a, 0x32c9ac3a, 0xf09bdf1a, 0x8ebb5b4b, 0x501c8c3c, 0xa0f352bf, 0xe75d5123, 0x21be3817, + 0x66155fbc, 0x7260bcde, 0x1dfa8e58, 0x757acd3f, 0x20371255, 0x69f45dcb, 0x5d7f255b, 0x2ecc4123, + 0x1b126610, 0x1933aa5f, 0x82bc5021, 0xd897d987, 0x39c73992, 0x4b8d5b3c, 0x3adf4420, 0xf3703015, + 0xadcd4146, 0xd76fc73a, 0x64c47fc9, 0xf3e771b6, 0xc3e8b752, 0x39544065, 0x05985c7c, 0xfcf686d6, + 0xb51a87f6, 0xb21d23a8, 0xcd5e5e1d, 0xd6d5087d, 0xfb18e0ff, 0x676bb412, 0xf470bf94, 0xde1db0d4, + 0xa2d1055d, 0xc18ff4c1, 0xbb0cb56a, 0xd5503517, 0xbe17d551, 0xbed41033, 0x82a8b7f1, 0x370d9fd8, + 0xfa62fc7d, 0x3c897212, 0xe9b2bed7, 0x8e518703, 0x31fe332e, 0x8f3244a8, 0x0fc1f849, 0x01025f8d, + 0x2e7b1746, 0xe2b4e281, 0x9230e75d, 0x9748f57b, 0xee2f7db3, 0xd3d33b9f, 0x0ae88d70, 0x24db93a3, + 0x34ab5794, 0x5a57b963, 0x4522aa6f, 0x4a56223f, 0x73e61836, 0x6f8ad1b3, 0xc771d2b2, 0x97f5c250, + 0xbfbc9eed, 0x7b6e8c04, 0xac7ffc53, 0x64723f5b, 0x90555148, 0xe2858ac7, 0x88ce2079, 0x9a168006, + 0x0b68321d, 0x2c81d32d, 0x4dfebd4f, 0xb4a327d8, 0x668dbf95, 0x2658d2c0, 0xb7f8edbd, 0xcf346e49, + 0x49a89145, 0x83e0749e, 0x79b27c22, 0xdfdb5f8b, 0xb995e2c0, 0xaf062629, 0x23218665, 0x4283a0a9, + 0xcc01c010, 0xf0e4dc35, 0x8b3b8393, 0xa13130e9, 0xe097a13c, 0xdb77bddc, 0xb66b5104, 0x5501de46, + 0xdb551831, 0x4e843502, 0x777a9cab, 0x16da75b2, 0x36a67679, 0x96d273be, 0x81fb49b5, 0xac1956ab, + 0x8ce9187e, 0x72a3ad85, 0x7a60b0af, 0xe443b610, 0x317edd2d, 0x3e9b7c96, 0xc1d3ff49, 0xcace4426, + 0x257ee4a3, 0x2e6f7c21, 0x3f94883d, 0x58e18feb, 0x30ad3eaa, 0x82748be5, 0x9b83dbdf, 0xdb72a8e6, + 0x3a91adbd, 0x6dcb1e3b, 0x7febc444, 0x3beaac92, 0x87aebf03, 0x00722263, 0x94e08b03, 0x9bc5333e, + 0x85d51ff7, 0xda56f18d, 0xe70e657d, 0x80146656, 0x806d2300, 0x25628058, 0xb34be852, 0xbc7c3b82, + 0x06c6052d, 0xa36c8ef3, 0xd59a7fff, 0x924f9eb9, 0x8d08ecc0, 0x1bcaed44, 0xeb40f94b, 0x2dcb1a9a, + 0x5643d7d9, 0xbd7e8e73, 0xaaee6508, 0xc78d9232, 0x076295ca, 0x1fe8eb43, 0xd3e54485, 0xa177b581, + 0x723f9a16, 0x8c140db0, 0x51ed84d8, 0xad32d1c1, 0x3c7d5c62, 0x6c515aa1, 0xc6fbbfa0, 0x6f7f8910, + 0xefca3591, 0xbe9c0ff1, 0xdcda6a2f, 0x2aa77802, 0x35395bef, 0x1621dab0, 0x0cc462cf, 0x5af1a4f1, + 0x1a8fbcf4, 0x76768165, 0x750ce033, 0x5e2533d1, 0x9bf40d3f, 0x79b3481f, 0x00bae26b, 0x6334f7a8, + 0xfe61e251, 0x6959a964, 0xc07e7b11, 0x6db66fb4, 0xf0a6dc6a, 0x234e1c6c, 0xfc9674fb, 0x67e82840, + 0xe214f271, 0x83d5c8ae, 0x365fc8e0, 0x995a1414, 0x66df540d, 0xbd63397a, 0x8cc5eeab, 0x2e387b11, + 0xbedc9253, 0xd72acee6, 0x0255a219, 0x15b712d4, 0x54c469ab, 0xdbdee032, 0x8bd0394b, 0xf9738c46, + 0x47ca91a9, 0x4c8764ee, 0xa244e2e7, 0xc6f8b467, 0xf64f7c87, 0xbd455a3e, 0x53c50b0a, 0x3179cd30, + 0xbb6e6133, 0x7789a103, 0x2c5bdfa0, 0xd5b8b38e, 0x0df15e69, 0x2f084f00, 0xe1409dbd, 0xd226aa4f, + 0x5858d722, 0x7d3d57de, 0x730b7911, 0xe282d6e6, 0x4e7f57a7, 0x64406d66, 0xbd64cecc, 0x6051ef17, + 0xe7dbeedd, 0xbcf7a054, 0xf35e1d7e, 0xc5b8913c, 0x85ca3c7e, 0xf6b13004, 0x7727b22b, 0xdee14e13, + 0x56bea25e, 0x692d44fa, 0x6c93e0dc, 0x6c48042d, 0xdbc51492, 0x453a2335, 0x9304db0c, 0x051ddab4, + 0xf78baef0, 0x9798ec42, 0x1d1c1ae4, 0x180db976, 0xe282af57, 0x6491ad2b, 0xcf9f7c96, 0x2036a5ce, + 0x80b6dfd9, 0x0998098f, 0x88797a17, 0xdbd364a6, 0x4b819c9c, 0x901a97b3, 0xddfcc56b, 0x6b71ff91, + 0x88157860, 0x82bd3ec4, 0x39e2a312, 0x83aafdb1, 0xad804ec4, 0x09ad2a26, 0x8a613d6a, 0xa55fe028, + 0xb3d02591, 0x2517c44e, 0x1de3577b, 0x01c23d7c, 0xdb45226f, 0x84583e85, 0x35ab38a4, 0x4907476b, + 0xa389f013, 0x2570dbaa, 0x23d890b7, 0x912f7525, 0x8fdbf8b1, 0xd2b45fa7, 0xcc4c6fe6, 0x3a2fc6d8, + 0x234ba13b, 0x00d0eb82, 0xb5ef6160, 0x14c1fae3, 0x2c17e8e4, 0x062a67df, 0x58992d06, 0xb0167c9b, + 0x99c775e4, 0xa73c0a91, 0x8b503d41, 0x581e6335, 0xbf3e4988, 0x96dcd41d, 0x60abff56, 0xd1a22abf, + 0x23e8b2ae, 0xf864b14d, 0x14771a84, 0xe8c892ef, 0x327cfe5d, 0xbff519a5, 0x19c59edd, 0x631aa6a7, + 0xb1bffa65, 0xdc6e4c02, 0xa9c18256, 0x9dce995e, 0xaf22c0f6, 0x2bed433b, 0x0f101e4e, 0xed0e425c, + 0x0f659e52, 0x6d88e466, 0xefca12b6, 0xcd63e004, 0x6b56d237, 0x0ac345f5, 0x3505581e, 0x0782d856, + 0x6a268967, 0xaeebb35b, 0x12dc2b11, 0x91ba1d29, 0x5e4f0ee3, 0x373fd826, 0x46ed8677, 0x6f2ac6f3, + 0x4bf1dcdb, 0x80680f0d, 0x6989af6a, 0xe11ad449, 0xaa2c1635, 0x33dde818, 0x9c930c25, 0x79b3a173, + 0xf958d10b, 0x830d3be9, 0xdeb9e082, 0x774d77af, 0xd2fae014, 0x5733f1c9, 0x38bafecb, 0xe546d494, + 0xc8dc9c88, 0xd09e460f, 0x9f9588d5, 0x629d8c03, 0x5d8c2f46, 0x38954388, 0xa2f35458, 0x152aa5d6, + 0x75ef8f2c, 0x6faa06ab, 0x35d52655, 0x5db21682, 0x1b7fb2fa, 0x0e1f94fe, 0xc2a48e23, 0x8ed385ee, + 0x8ffaf4d9, 0xb996891c, 0x19ced8f0, 0xbb25a535, 0x58ae0bc6, 0x4437e80f, 0xf4e63cbc, 0x8a24ec61, + 0x361bc131, 0x6b071b5d, 0x5ac05ca6, 0x54f3b769, 0x467e286a, 0x7c18c6f7, 0x96390d7e, 0xc8d25d5d, + 0x5477c98f, 0x7388709c, 0x016980e8, 0x378f58da, 0x1308668d, 0x5cd3c900, 0xf7014b70, 0x5d682990, + 0xf12765d9, 0x4ee534c6, 0x30d63d49, 0xae613c12, 0xa23b98c7, 0xd09a1f7c, 0xa745d8af, 0x16f70c0c, + 0x4cffc1b6, 0x3895d151, 0xf356f109, 0xce4d5cf8, 0x9fc5b973, 0x59e83936, 0x3d159f47, 0xc744185d, + 0x0b6cca2b, 0xb5ddad70, 0x0463e0f6, 0x534d7d1f, 0x02a225b3, 0x0a18b8cb, 0x31d635d6, 0xaa8892b3, + 0x3e7dda3e, 0xd4c1391f, 0x0fb37d55, 0x55a05c6d, 0xba72487b, 0x27866729, 0xe1196ee4, 0xfa069b00, + 0xf644c5bd, 0xd93b788c, 0x2ce6eea5, 0xfa9b8c8b, 0x48dabe48, 0x79b28dcd, 0x44495d04, 0x8283af37, + 0xa4dc8cc8, 0xd0d6d56b, 0x083fb596, 0x79f45d6d, 0x8bba222c, 0xbc2953f2, 0xf20031c0, 0x5350c8eb, + 0x40f93f5c, 0x104b80dc, 0xcff8c26c, 0xc1cc443e, 0x2316a966, 0xcf50aae3, 0x21071c93, 0x1f69f65d, + 0x7d33385d, 0x0c926b1c, 0x47a0bb91, 0x2ac22ec3, 0xa6aaa8c4, 0xb43fcafc, 0x94bc57d2, 0xfd0585c3, + 0x91af5ac9, 0x6aa32438, 0x531278d8, 0x89ed356c, 0x6b454fc7, 0xcee2dcfe, 0x9473c727, 0xbf7f795d, + 0x177376b2, 0xb897c495, 0xd09b3cbb, 0xc8dfb493, 0x1c9c930b, 0xa8d92293, 0xe8a583b9, 0x37121013, + 0xa89bb57d, 0x4b882cc9, 0xec83fdc1, 0xc3836386, 0x66174b32, 0x61582fd5, 0xc95af5dc, 0xd6d24c04, + 0x68b331cb, 0x14e9306b, 0x68e221bd, 0xa50c2723, 0x2a41591b, 0x53b6196f, 0x6ecdd21c, 0xd6dd4940, + 0x3ef3f536, 0x64137986, 0x53f4f1c6, 0xbc762717, 0x94c795f7, 0x0cf44a39, 0xda0dd9c1, 0x3b8f7c26, + 0x2859be2b, 0x78daabcd, 0x88ab46a0, 0x947c6642, 0x35467704, 0xdf287b96, 0x2e12beb4, 0x3e2c635b, + 0x7b6de39c, 0xb89b8120, 0x07c86349, 0x84c1bd51, 0x30516d0d, 0xe66e6704, 0xda4f119d, 0x1b14330f, + 0xca28d7b8, 0xb4a7db08, 0x63351adb, 0xf045fc96, 0x9f999acb, 0x9eaa373f, 0xac45a70c, 0x938142aa, + 0xcb0d48bd, 0x4553116f, 0xe0b2cd42, 0xf556351a, 0x62e91c4a, 0x63c4e1dc, 0xd799ebab, 0x7964eaa5, + 0x19371527, 0xa7ff56c3, 0xded3e051, 0x12a84155, 0xc74136ce, 0x63347511, 0x30a213ca, 0x98f0b816, + 0xfe67e717, 0x00de13a7, 0x861dc246, 0x2dbefa42, 0x0785ebaa, 0xc28d23ff, 0xfca9fd09, 0xae5ccffa, + 0x8911eb49, 0xa31e4355, 0x6ca68246, 0x42e45925, 0xf6f0a6ff, 0x16baa095, 0x06ed41bf, 0x0d067d5c, + 0xdab3fda8, 0x9e6029cb, 0xdef7af00, 0x987c7669, 0xf2a4ccbb, 0x535bbe7f, 0x4fe84c15, 0xb849a045, + 0xf15a8772, 0xc8e5912a, 0xc55d66bf, 0x711c454b, 0xf5eb867a, 0x2ef7b085, 0x3accdf11, 0xf4137770, + 0x1b6a2dfb, 0x61852a2d, 0x352203d4, 0x84fb90d4, 0x750ede89, 0x83134529, 0x1a9e197e, 0xff3deddc, + 0xe93240d1, 0x30609eb6, 0xa32b59c1, 0xec31e8b0, 0xa7ec7adf, 0xb6a4f906, 0x1f9db0c2, 0xd571b0dd, + 0x7935c73d, 0x8815db92, 0xd3990757, 0x5ccca62a, 0x3e2ed995, 0x6f1b38ab, 0x5ed5a294, 0x50a9bf5a, + 0x43fc66e5, 0x108c370c, 0x51f79adf, 0xd9a37145, 0x25de57a8, 0xc6291262, 0x455f6a9f, 0x88f2e5e9, + 0x450883e4, 0x020a50b5, 0x2418ba38, 0xa4ff5caf, 0x234a7cca, 0xdd5ef84b, 0x8251d03d, 0x7a02d1c9, + 0xa372b068, 0xb1bd4523, 0x0867cf24, 0xc6f256bb, 0xa242f7ac, 0x7acfbe4a, 0xf46f9017, 0x72883ce9, + 0x88085187, 0x9738e9e1, 0xe224ff8a, 0xc50b0501, 0xecabd5ef, 0x86b6daca, 0x7e003f15, 0x96ae8ce2, + 0x5ca19b46, 0x6d6c259c, 0x7cb77514, 0x33f12535, 0x683d14f8, 0x994e7cc3, 0x92e83c6f, 0x86779e75, + 0x8c15c9f0, 0xef3838fb, 0xa90f16da, 0x6ee8633a, 0x5b896e53, 0x169c8b21, 0xff7a6cc7, 0xfd8a7ee8, + 0x2b077ee7, 0x6b38782f, 0x60384fb4, 0xc0419541, 0x88faf1de, 0x525e5edb, 0x2d50bba1, 0xfba88ccc, + 0xebb676b7, 0x8f9235a6, 0x7920715a, 0x9d6be8d7, 0x80f2ef06, 0x5b5be396, 0x6dd467d0, 0x2e17a8df, + 0x13973b7f, 0x6c6fd931, 0x24dde33f, 0x230266b2, 0x0dec186a, 0x1a931ade, 0x9198c993, 0x24d3cbb7, + 0x8dc033d0, 0x3bd496eb, 0xa974ec5d, 0xa31a9c5f, 0x7b1cb80c, 0xb23c1c36, 0x8cb01322, 0xf672bb3c, + 0x4bbd07b2, 0xd7de6720, 0x1fa8096c, 0x90a55f5e, 0x43121f2e, 0x8f9cc4a1, 0xae1ffc4c, 0x83e95f45, + 0xc2d9a30e, 0x215da155, 0xf4878a98, 0xb524ae72, 0xbee3b774, 0xa4cf8fd7, 0xf0b1a5d6, 0xfe76bfb0, + 0x57bd4e95, 0x4fedd3b2, 0xe319fc3c, 0xa9fcde2d, 0x8fcfc207, 0x0182e962, 0x561410fc, 0x8729a13b, + 0x84638b3a, 0xe01fa98a, 0x281699bb, 0x80c47470, 0x937b76eb, 0xe421b5e5, 0x465cd3dd, 0x6cb742ee, + 0xb777c363, 0xdcfd0458, 0xd0effe47, 0x4405571f, 0xaaa426a5, 0xde36a4b5, 0xc41599f5, 0x4cdab802, + 0xb276422d, 0x38e1dd56, 0x825986a1, 0x67cbd8ca, 0x0ecee594, 0x1b7c92f7, 0xea43c7ff, 0xa911ff42, + 0x32011dc4, 0x6e648b9b, 0x15f05e3f, 0x70461513, 0xf8f3ac16, 0x6b134d82, 0xd5a7705f, 0xd3aa0e3c, + 0x5b6e96fc, 0x1a3a4950, 0x177c078b, 0x0938b280, 0x20dbb356, 0x376e9058, 0xa73709c9, 0xf9af5fa8, + 0xdc04ac27, 0x7d78c501, 0xd1e6c5de, 0xed5c4dc5, 0x9ea7a511, 0xd9577b6c, 0xd362a004, 0x7767d668, + 0x98a09d91, 0xafe20736, 0xefa31c15, 0x5069041a, 0x26d28cef, 0x31a25a85, 0x021ae113, 0x26a3ae51, + 0x9938542f, 0x26e7d9b0, 0x429e5d0c, 0xafd8c0c8, 0x49db7872, 0x1572aae1, 0x646f2a1b, 0x6ce95134, + 0xc39088f6, 0xe9285b7f, 0x487434b4, 0x1fc38994, 0x898df2f6, 0x0e8a4123, 0xcf920621, 0xa1076cdc, + 0xd7d4beee, 0x84d0af4f, 0x4a64b478, 0xc3e5ed73, 0xdf26cb20, 0x0c3c8d29, 0x80e09517, 0x3baa97ee, + 0x9c034a19, 0x317d4dd3, 0x5fb5c5cd, 0x0fc273d1, 0x6956353c, 0x64910224, 0x28b34513, 0xc7d2e161, + 0xf7d46798, 0xd8b3cd35, 0x09e6a6bf, 0x71f2ad2a, 0x2b720516, 0x0772b1f2, 0xbe18cb06, 0xc288a068, + 0xe189a2ea, 0x9adce6c2, 0xfc7481d0, 0x1dc4aeea, 0x210a81f7, 0x0993a36e, 0xf359a36a, 0x1a1bec56, + 0x797f2a93, 0x0594757a, 0x23687078, 0x153cacd4, 0x8ec6ee8b, 0x4d875f27, 0x3d480ff2, 0x81b9bdaf, + 0x81e019c2, 0x9d12434c, 0x23c23f7b, 0x87e37df9, 0xa8e676cb, 0xb657b3a0, 0x33669b39, 0x9862981b, + 0xf5b58c00, 0x681a8a4b, 0x70fd8396, 0xc077378f, 0x4f9a4600, 0xbc2bb08c, 0x761f3eeb, 0x13a1417d, + 0x0a79bd30, 0xcf0b89a6, 0xa027aec3, 0x73438c2c, 0x430bf484, 0xf63793c4, 0x990d8301, 0x6c0f9205, + 0x821a202b, 0xae41042c, 0x1f71056a, 0x00b4b56a, 0x43215c99, 0x2d750530, 0xf2a576d5, 0xc0ee7052, + 0xfb414785, 0x5565169b, 0x995ce49f, 0xbe109213, 0xd6a80dbf, 0xeb8b7255, 0x1e6f75df, 0xcb2c4b0b, + 0x3dcf0493, 0x429adae7, 0xc7cdf1da, 0xcb37e43a, 0xa52a1216, 0x4925e796, 0x6eebaec4, 0x6ff3cc9c, + 0xacb89935, 0xead1ba28, 0x98b157be, 0xdd846dde, 0x9324d5a6, 0x5285b684, 0x3663bb2a, 0xd2e025ec, + 0xbc055fa0, 0x8c6f1bc7, 0x2dea3ae1, 0x58e6b221, 0xde23882f, 0xfd53719b, 0xee03ba5d, 0xe36b7527, + 0xd33f0254, 0xa55c30d3, 0xde02966d, 0x3df26635, 0x2e57575b, 0x884c5dc8, 0xd028df21, 0xa29ac0c3, + 0xbb577bd6, 0x33ff271d, 0xff43ba4e, 0x1eca9ad4, 0x2cacf6c6, 0xb4822094, 0xe1e894c0, 0x156838ea, + 0x5ddda3a4, 0xfb45dff0, 0x23da996f, 0x636feab7, 0xd8a323de, 0xe54019e2, 0x6eaeebfc, 0x62787de2, + 0x11fb4eea, 0x6574126c, 0x30ed1189, 0x0c9411d8, 0xd7229dcf, 0xb1a64cf3, 0xc1f5f808, 0xa1789011, + 0x72ee5e30, 0x58c37eb6, 0x63dec3fb, 0x5da0e9e5, 0x9b8154b0, 0xe12b5b83, 0x4f98d7c2, 0x2583addb, + 0x45c9d19a, 0x74ee0d53, 0x607433f9, 0xfe99ba1e, 0xfa9b4f14, 0x03e6ab23, 0x477802e7, 0x57cad6c8, + 0xad566cf8, 0xdb367990, 0x65220266, 0xf1915230, 0xaf7eeda4, 0xdad2b055, 0x78c617ea, 0x5371da20, + 0x4687338b, 0xc24790bc, 0x9b09438f, 0x2b1b7c0a, 0x013e9ef7, 0xd1cd8bc4, 0xda3f612c, 0x3dcc07f0, + 0x3589049f, 0x21e1e685, 0xd3c6a313, 0x7e25ebb1, 0xdec33560, 0x72208cf3, 0x8e425404, 0x61cfe6e1, + 0x85fc6231, 0x6d5901e0, 0x37b9202c, 0xf2146264, 0xd972773c, 0x74b140b6, 0xbf961c99, 0x268985d4, + 0x6c8f37b5, 0x46db08b2, 0x9e4f4aef, 0x8c526ab5, 0xafcd2dd3, 0x10c816c9, 0xb3594ee9, 0x94521a26, + 0x118bfed1, 0x4fe4eadd, 0xc9ab321f, 0xbfe2ef75, 0xfe7a3fc8, 0xab088fa0, 0xa41b3d6c, 0xce0acda4, + 0x5b3c230a, 0x366280bd, 0xb2397bf0, 0x0ea2003e, 0x98c52e49, 0xe625e29f, 0xcc0c496a, 0x5bcd3838, + 0x359e4021, 0x731f4f48, 0x48765d4f, 0x77444b6d, 0xb77e7227, 0x5242bc31, 0xb4edb621, 0x596a4f9d, + 0x5c0f8662, 0xb0a80049, 0x93832e65, 0x2dc69e45, 0x8a46a307, 0x256cd884, 0x2bdbb3a9, 0xaecd2235, + 0xefa277b3, 0x7d66d39f, 0x80e5260e, 0x4b3d427a, 0xe038c21a, 0x1c2104ac, 0xbb75a2b8, 0x4397e3d1, + 0x2ec5d316, 0x4947ad01, 0x3fbd13ca, 0xcc3c5d60, 0xaf3befa0, 0xb77fcadc, 0xf84712dd, 0x829ad701, + 0x0d760cb8, 0x16a12ff4, 0x94682d9b, 0xd7480a8f, 0xa6143a08, 0x6e0f85d0, 0xc7d8298b, 0xa78fb93b, + 0x87922e39, 0x9f364ea7, 0x887d2a24, 0xad3f5cb1, 0xc44a11b3, 0x57f2e6d0, 0xcd10d436, 0xa222e6aa, + 0x73bb47a0, 0x71410b91, 0x79dacdc6, 0x5322a37b, 0x62ed814e, 0x32ea8894, 0x0b7561c6, 0x561fb88a, + 0xd49aea2d, 0x978a65a3, 0xd00fef45, 0x10238b9f, 0xdf9e8473, 0x8c5f70af, 0xd9111897, 0x7a408bf8, + 0x85e4e2cc, 0xd93be34d, 0xc3add008, 0xcb14f826, 0xd475d7a1, 0xc986631e, 0x3e024a72, 0x4e26f72d, + 0x0a3a13ef, 0x41259eae, 0x548f1e8c, 0x2db9b54d, 0xc02050ad, 0x03bfb2d0, 0xf5e20640, 0x2055cbaa, + 0x6587bc38, 0x63db5ace, 0x723b152d, 0x04263c65, 0xc27ecfe7, 0xdbd8f02e, 0x099fc2d3, 0x0b26e500, + 0x2f0940bb, 0x766186f8, 0xad7a97c0, 0x8c0e5d5b, 0x7154523f, 0x9263b213, 0x01f9805f, 0xaa19fc53, + 0x0207f09e, 0x07943820, 0xd04ff483, 0x7dcf8ad5, 0x71cf34ed, 0x8ad0925b, 0x8ef3aa57, 0xd794f690, + 0x49f8700e, 0x0875e3ee, 0x8a185df6, 0x0c3110b9, 0x9143b8da, 0x2806224e, 0x505cb18a, 0xf95dbe7b, + 0xd8d58a11, 0x902a898e, 0x017ee10e, 0x9ddcffa7, 0xc7bb1e0f, 0xddf5b603, 0x79ea9458, 0x672bf6ab, + 0xbaef1869, 0xe518f43e, 0x3d35e0a0, 0x2a443940, 0xf0d937ec, 0xff2d0eae, 0x87910058, 0xc54bf209, + 0x50e1c0cb, 0xe5fe9a61, 0x849a301c, 0xe10f445b, 0xa1aee08b, 0x9257232f, 0xf2f2e5ed, 0xd02253a3, + 0x25be6288, 0x2cde1852, 0xa78d6568, 0x90dab40d, 0x0077bf3d, 0xe66d4211, 0xb7e35a4c, 0xf275a881, + 0x00b7709e, 0x41a544f6, 0xc2cee653, 0xde2e84ca, 0x30921c8f, 0xba9ce7fa, 0xda7b6e73, 0x8b4995f9, + 0x586cfe27, 0x924e6767, 0xbc953fde, 0x973189b2, 0x105a1bdf, 0xa40fb19e, 0x3541a7b9, 0xed898ddb, + 0xf60f3ff9, 0x4916f277, 0x910b7d80, 0x30891d17, 0x8008e67b, 0x9e2e74c8, 0x016c5b53, 0xcbbe6a9e, + 0x4aca7c97, 0xc2fdb69d, 0xa8cd49c1, 0xa120a4b4, 0x1fcfa235, 0xfa408a88, 0xc19d0474, 0x05852cc1, + 0x6f1cb2e0, 0x0ce809c8, 0x9bcd32c9, 0xfcf13f83, 0xd963ef6c, 0x50ac29d4, 0x5f3fbcf9, 0x068355a0, + 0xf4f89a96, 0x6e595d13, 0x0f55b46a, 0xb82a1f10, 0x8f4647ce, 0x36a3cee1, 0xe6d4dc2c, 0xb7dd0a25, + 0xe4e49770, 0x3927a27e, 0x54f50d01, 0xfc6c94c2, 0x5feacfe7, 0xd95eadfe, 0xe3747a40, 0x61249c08, + 0xf1143dd1, 0x2b491a80, 0x94054a90, 0xca5780f8, 0x53e6f833, 0x0d9c87f4, 0x8630f7c9, 0xf00d3a79, + 0x13386e8f, 0x7f59c60a, 0x4208d1d8, 0xa7fdeaed, 0x1a66a440, 0xc2216d79, 0xac4b6f6f, 0x79fb626c, + 0xf3bdda7d, 0x9dd0b905, 0x8d01d14a, 0xc847bd15, 0x8ecde345, 0x564b1a87, 0x13a7d11c, 0xc5df2489, + 0x646bf35c, 0xa2fff5cc, 0x9e83cffa, 0xce4ca8a1, 0x2fefcbb4, 0x82e0bfbe, 0xffe5c693, 0x92a3893a, + 0x7178323c, 0x890fc02d, 0xb9403c06, 0x5aacf7a7, 0xfc694821, 0xccb11fef, 0x9d91e9c6, 0x9e5f3435, + 0x25e68d5c, 0x887f72b1, 0xd440b945, 0xa510f57e, 0x7dffb837, 0x538567f3, 0x03f8a1e8, 0xf0f5067e, + 0xf24bb4e2, 0x23002951, 0xdea17619, 0x00229938, 0x697cec70, 0x324509f8, 0x0a8434dd, 0x0084293a, + 0x88d4e3f0, 0x094b062a, 0x244d8027, 0xc6d661f1, 0x7384713e, 0x847d9aea, 0x5cf81146, 0x7e8769b6, + 0x9388d6d4, 0x8de4fb83, 0x19595864, 0xfde23c53, 0x3f896908, 0x20cfdb53, 0x3d53d4f3, 0x1ee48a4f, + 0x6364f945, 0x034c45c7, 0x5b3f800d, 0x3b82fead, 0x1c50337f, 0xf550b1d0, 0x696d4286, 0x3a75d032, + 0x8caca6f1, 0x328d84a1, 0x540b95c3, 0x6a845ee4, 0x9e6f4ec4, 0x73bcb3d3, 0xc56344a8, 0xf1f567c6, + 0x01e2982a, 0xb2f25620, 0x3d9b42da, 0x626c176d, 0xad0a9a90, 0x85051e15, 0xeeb4a005, 0x90e68218, + 0x4503a022, 0xf9c45542, 0xe397f819, 0x97ea328c, 0xa18bcc17, 0xee857a0d, 0x4949f980, 0xcc95b26d, + 0x11a397e3, 0x02bac247, 0x57e035d9, 0x80380005, 0xe882a717, 0x428b9fcd, 0xe037911a, 0x25a58814, + 0x7db2bcd8, 0x8530cfb8, 0x2569809b, 0xd2f8dc18, 0x643f2a26, 0xdccdfb46, 0x2ff412cc, 0xc39dc2a0, + 0x97e565c2, 0xf5307d78, 0xf756350f, 0x1a18a496, 0x93726205, 0x95275275, 0x948a277d, 0x2a2718d2, + 0x37c8b4b3, 0x07ae6b4d, 0x3b495dad, 0xf01a2ae0, 0x02f4c1c3, 0xee0ca34e, 0x4099ac88, 0x66bd79bd, + 0xf6fd0c09, 0x5d0f3932, 0x221eab50, 0x7e3c483b, 0x418f97f5, 0x24373c42, 0xe82f04dd, 0xc78ce9ba, + 0x93d8838c, 0x7e1073e1, 0x2cac34e0, 0x4d467fdf, 0x380b1d57, 0xc850c6b8, 0x0d37cba3, 0xc5421611, + 0x0d39cf49, 0x71d197bd, 0xe1ab919b, 0x559b9af3, 0xed078662, 0xf33c8c36, 0x9baa17bd, 0x0f6b1625, + 0x4e2208dc, 0xebc715eb, 0x97ccb285, 0x079c8c98, 0x931157f4, 0xb2bc579a, 0x2d453e38, 0x64f5e5e6, + 0xcaf044f0, 0x2a555087, 0xc849349e, 0x66f2771b, 0x5d850a1b, 0x670e9fe2, 0xf99804a2, 0x859f5d15, + 0xd8be36de, 0x34944477, 0x50bd3699, 0x590b83fc, 0xcd3f6ab3, 0x611900c9, 0x30411d5f, 0x02762247, + 0x0639e65e, 0xbdbbbf8c, 0x246fd793, 0x57df0b23, 0x5d440433, 0x425d7416, 0x775022e8, 0xee70a2cd, + 0x3ddc5be3, 0xb3afb312, 0x0d6f8a7a, 0x7b311880, 0xb34aa6d8, 0x048921af, 0xf5874f59, 0xcf5cae77, + 0x3275a354, 0x73d24600, 0x286f5a7b, 0x526f7c00, 0x60198baf, 0xb433e0dc, 0x8285724a, 0xe611801c, + 0x91dba022, 0xd7a29b9e, 0x2148367a, 0xd800091e, 0xd4c1b932, 0x0222493c, 0x631a7cf9, 0xf89bcbf7, + 0x34f65a1c, 0xf6ff7e42, 0x142c2d0e, 0xdcb3d3b9, 0x607a5311, 0x6b34d5e4, 0xe16a7478, 0x50c8f3d6, + 0x84c58258, 0x1c3b0a6d, 0x45a4102c, 0x03197006, 0xc9006ad2, 0x7c7f5771, 0xcec59321, 0xdf9bdc20, + 0xa59f6f8a, 0x2b77733d, 0xbec9fbf9, 0x2a720730, 0x414b8900, 0xdd822601, 0xadece41e, 0xf8ea2c82, + 0xfe7eddd8, 0x2018c093, 0x5688766c, 0xfadfb00f, 0x7f56d7a5, 0x764dd5e3, 0x424803cf, 0x47968aee, + 0x344e928d, 0x0d8e4e8e, 0x587a3c89, 0xdd2dd322, 0xc3b7ea30, 0xb29eaa94, 0x390b75d9, 0xd4021110, + 0x52b96942, 0xc1a41671, 0xeaea2ad2, 0x7e0f39c5, 0xa136675a, 0xf2d72101, 0xb8cd53e6, 0x6c8f8275, + 0x33bd3e08, 0xe9d5021f, 0x86c2b4ce, 0xc392ea0d, 0xa8f815ea, 0x415753bb, 0xc7a68e4f, 0x33bf9937, + 0x8c43347d, 0xbec34f28, 0xd8c024fb, 0x5185a058, 0x8e49c123, 0x66ae36dc, 0xae0d9d9a, 0xda5318b1, + 0x292dcfed, 0x285b8ed7, 0x4bb03091, 0x1fa61b8c, 0xfc8d0d6e, 0xb3b8a294, 0xcb7bb27f, 0x41c2d932, + 0x57163bcd, 0x9cf62e54, 0x5844db25, 0xb2473da8, 0xb047b9dd, 0xa04544ef, 0x0ef038af, 0xc157033a, + 0x90c2cd58, 0x67b2a7cd, 0x585a2e1a, 0x86a09e2f, 0xeb2c0849, 0xd9fec81a, 0xcd0e62cf, 0xd5c8b59f, + 0x739e6c7f, 0x272b818b, 0x282f36a8, 0x22b80147, 0x8db88961, 0x40663a33, 0x0103ca47, 0xd81eb994, + 0x780a04d3, 0xe2d995d7, 0x82ddd5b3, 0x0364da1b, 0xa305e7f2, 0xff1480dd, 0xb57f45a9, 0x2997cbc5, + 0xf733caf5, 0x52dded75, 0xf3536f8a, 0xed6d4dfa, 0x2781aa36, 0x085252ba, 0xdb9ed232, 0x82790e4a, + 0xc249f283, 0x310f96e4, 0xd54da59b, 0x8528adce, 0x6166bf1d, 0x0f72c222, 0xab6dc554, 0x1f95ed8e, + 0x9c303266, 0x0cb8bd0b, 0x30f7ee47, 0x2921f6a5, 0xf9f899f6, 0xf1e6af60, 0x7382bcc0, 0x22b65cdc, + 0x91ac97bc, 0x28cbd5dd, 0x240216fb, 0xd1bb1ccd, 0xa5c50166, 0xe2b3faa9, 0xafaadcb3, 0x43c240f4, + 0x8f7d26a8, 0x412a0d44, 0xf66f4b1c, 0x0a5d4c68, 0x52a09494, 0x7640fe83, 0x04b9c185, 0x42682406, + 0x01122b3d, 0x5d34fd80, 0xc8b8f29a, 0xf2653945, 0x61c32d48, 0xe6d66dfd, 0x5a0e3183, 0x79f21002, + 0x1ecc9f79, 0xabb4d7e2, 0xf5284a79, 0x059ceab3, 0x55bcebd9, 0xcb954056, 0x6c3e42f7, 0x0a45a93a, + 0xf95cf392, 0xac4042bf, 0x05da0b74, 0xb8dcb4da, 0xdc6413e2, 0xe506c492, 0xfe74d994, 0x49565a7d, + 0xcadcbd37, 0xc4021bc8, 0xef9aa08d, 0xb19b9943, 0x006916e4, 0xf1797ded, 0xfc59017f, 0x79f39d86, + 0xea4ff1ff, 0x93319dee, 0x26868e7d, 0x96335b43, 0xce017a6b, 0xcc6a6845, 0x0cb1dd35, 0x5b3d0a3e, + 0xfe9610e6, 0x8ff9c3d5, 0x0f78c455, 0x2a1718ba, 0x4053f143, 0xb1b5678c, 0x41d42dcb, 0xad1a9a73, + 0x6470225b, 0x5f0afda2, 0xc7cd1400, 0x9f0eac20, 0x30fc4aa8, 0x038d95ab, 0xa8155424, 0xf5719cff, + 0x8c0b45a0, 0xbb290a03, 0x5fa7f2cf, 0x0b938948, 0xcc3e04cd, 0x9096083f, 0xb15f7d0c, 0xea698e51, + 0x9572a982, 0x8e34a818, 0x973cced6, 0xb99b20a0, 0x19dc2ae5, 0x408375c9, 0x90592514, 0xf8183374, + 0xf1a716de, 0x1b858fa1, 0x38805ca8, 0x727dc375, 0x5380d3b2, 0x12d63efc, 0x281043e8, 0x97d71e22, + 0xf3e6a97b, 0xacab6425, 0x5cfccfe6, 0xdc6c7577, 0x47021ed5, 0xc187025e, 0xbd26e090, 0x978b5c44, + 0x865e8c8d, 0x44a8c1cc, 0xa0a5d139, 0x1f50430e, 0x80c07073, 0x8b79c876, 0x6509dce9, 0x8f94c524, + 0x9e95d6d5, 0x63265f28, 0x8e232209, 0x1d698a1b, 0x54dc7dfb, 0x2bfa577e, 0x2b53a946, 0xcb96eba2, + 0xf779ce6a, 0xefea4466, 0x914b0e7f, 0x6bfbfbf3, 0x3206e349, 0x509c0579, 0xcc492fcf, 0x47430956, + 0x040dbc09, 0x4fd417a9, 0xc5e334b4, 0xd54d8047, 0x61525930, 0x90603c92, 0x686cf6eb, 0xb79ee157, + 0xfa40197b, 0xbf463ffc, 0x2f041387, 0x9f790cea, 0x43d4f548, 0x1cdabc12, 0x7fb95d21, 0x1dde04dc, + 0x58cd9086, 0x0b0bc761, 0x38becaf6, 0xe9c9c06d, 0x0080d3d9, 0x83565511, 0xe0db99d3, 0x40d72dd7, + 0x283db549, 0x30d56f13, 0x6ae907bf, 0xa4c9cda3, 0xa6b65e87, 0x66bf8624, 0xb3c2dd19, 0x1b9dec5b, + 0x72a521b1, 0x73bebc0e, 0x5f700c24, 0x51b5f2c2, 0x80f14321, 0x8936c9a0, 0xd1e72009, 0xb16417f3, + 0xcea16ba1, 0x5f380d50, 0xb3ccc7c9, 0x39d934bd, 0x9574a011, 0x8421f622, 0x1590e784, 0x73df7c03, + 0xd019201c, 0xf9ef6fe2, 0xe0c9bb9a, 0xddbcad10, 0x264dcd58, 0x07118ab4, 0x958d13e7, 0xc0608f60, + 0x79cf8da4, 0xa0f6fd1b, 0x7aff816d, 0x71a40cad, 0x9930fb44, 0xd4aa3952, 0xe4d713a3, 0x2d23872c, + 0x7be76a35, 0xed5fe8a7, 0x64fbd347, 0x1b69bc41, 0x6c599d51, 0xab8fd385, 0x2dbc8500, 0x31060510, + 0x2bd4496e, 0x9079532d, 0x9fecf65f, 0xced93a76, 0x72d80b1e, 0x9be02959, 0x18ab2b52, 0xd4746919, + 0x0dd29579, 0x62f978be, 0x7b3b8fd7, 0x6bd0abdb, 0x4e108c45, 0x59d9fce4, 0x88de28ec, 0x5be5f29a, + 0x0a048f7e, 0x7d2aa348, 0x0fdbdbfe, 0x0b55257e, 0xe3def290, 0x001fb6c4, 0x4a2232c0, 0xfefeeccc, + 0x40988a01, 0xcf77dae9, 0x2ccdc019, 0x393258c0, 0x283e55ab, 0x4c9ba1b3, 0x01d8f78e, 0x0ecea64a, + 0x9259d60d, 0xe3b962a5, 0x5339dc1a, 0x48a24526, 0x53acfe08, 0x6cc23110, 0x343dc5f6, 0xbb8398d7, + 0xa45541d2, 0x9c557a6e, 0x742ccfef, 0xe766e7bf, 0xdf981ec3, 0x88e3cc13, 0xabfd32ea, 0x2f1431f6, + 0x7eab4eb5, 0x1471580c, 0xb45999f4, 0xd4552180, 0x5d4de259, 0xc28d5182, 0xc0ec29e7, 0x58e892ed, + 0x8efc965c, 0x74623338, 0x6d2989a9, 0xfffd42ff, 0x5799dee9, 0x59bf77a0, 0xbf9ff71e, 0x8988639e, + 0x3e839685, 0x8bbc067d, 0xeb389c34, 0x4a56e1e4, 0xfb640445, 0x751733bd, 0xd6686ac9, 0x6f3bab04, + 0xbc41eae5, 0xa9d1c62d, 0x6fb1d7c0, 0xaf410dbf, 0xa64a14c9, 0x91d6cafa, 0x75efa91d, 0x726f462e, + 0x6537ffea, 0x0517d18b, 0x193f393a, 0x9308a48a, 0x97942371, 0x3ee7024a, 0xbbb91086, 0x2243f329, + 0x279cd8f9, 0xcf9040db, 0x3b204fba, 0x1a7ea1fb, 0xdb332eac, 0x1f13bc00, 0x784ae501, 0x68022985, + 0x780af9e9, 0xea7bcd8c, 0xfbef52b0, 0x4180391d, 0xa82c3626, 0x77bf86fc, 0xa4621c5c, 0xe2766d89, + 0xd769e596, 0xfa6b17bc, 0x85a45d2e, 0x1e27c2a7, 0x63864e43, 0x06b3361e, 0xae7d24fd, 0x4f304ea1, + 0x3abb647d, 0xcdbafa92, 0x7d7304e0, 0x83162c89, 0xb119446c, 0x57da7064, 0xe2655258, 0x12f1fdb2, + 0x4bf932cf, 0x9f81db62, 0x49729679, 0x8005347d, 0xac53efaa, 0x9d1e954f, 0x04558317, 0xe53e287c, + 0x4d661dd7, 0xc3b9d58b, 0x83c147b9, 0x44abe0a0, 0x14ffeb55, 0xeab9d13d, 0x9d1076b7, 0xbaf3355e, + 0x0bd06f7c, 0x852a677e, 0xed3900f0, 0x7727df50, 0xcb505514, 0x289f3de1, 0x2a4e5140, 0x25b7b184, + 0xf03ae866, 0x4597a69b, 0xb2f3d489, 0x4e3b6de1, 0x3c7b43d0, 0x84adfff3, 0x7ec8ac10, 0x28f8dfdd, + 0xaedfa930, 0xb2c8962c, 0xe4fbbf6b, 0xb88b1ec4, 0x1aa2016e, 0x44f69417, 0x71df84ec, 0x6d447395, + 0xb1d4cfb2, 0x4a714b4d, 0xbe5d26e4, 0x3b231585, 0xebc143c3, 0x00fb5cfc, 0xc486fbad, 0xc3483a64, + 0xa8a95ee7, 0x428e0e91, 0xba60b596, 0x7fc9e5fb, 0xee6fb309, 0x80a49e75, 0x74f751a9, 0x7dbed191, + 0xb787c0d3, 0xa93ee23a, 0x37b14b3f, 0x9afa3740, 0x48092179, 0xd3dd21b5, 0x48d3dc8e, 0xed0e5a14, + 0x8ab90415, 0x9acb270e, 0x9e28cd74, 0x6680006b, 0x21ea0d9e, 0xd97ce2f3, 0xdf3fd04a, 0x292541bb, + 0xbab690ea, 0x2d02aee9, 0x0845dd42, 0x30d5f118, 0x06d819c2, 0x6a51a80c, 0x691028d4, 0xb0ce9e6c, + 0xc022a3c2, 0xf36774c7, 0xaa73e6b1, 0x781205ee, 0x54ddd3e1, 0x2f4bf2c9, 0x6b7fca6f, 0x1c6ef7be, + 0xdc088c46, 0x3336b647, 0x36c4c2e1, 0x690f8eae, 0x5f8aaa3d, 0x998da8b2, 0xe13e7ecf, 0x6fb27edf, + 0x5937a683, 0x06a0c371, 0x5651a0ed, 0x55d12d5a, 0x19540fe4, 0xebf0d9b4, 0x36a05207, 0x7dd442f6, + 0xc8c9bd8c, 0xac134ee7, 0x7e49e5a8, 0x469d5e52, 0x3193b8ec, 0x8ed70dc6, 0xf0f19dab, 0x9fd59ccf, + 0xe7745e7d, 0xf913d9f8, 0x8a4bce67, 0xa1aa1cd5, 0xeed251e5, 0xd980817d, 0xa74a972a, 0x7eb9aa9a, + 0xa7025d80, 0x1a796bbc, 0xebfc5186, 0xc4eaa2cc, 0xfe1e3ee9, 0xbacef435, 0xf0eaf8d5, 0x949ab206, + 0x54055e9f, 0x19e70a45, 0x8a4e657b, 0x3fc561d1, 0x98e17dc9, 0x366853ac, 0x641eedae, 0x60c03d17, + 0xeb006ee3, 0x603063a0, 0xc001030c, 0x2b656c4d, 0x6f9c97d1, 0xfd2d98f2, 0x55aa7efd, 0x74c74979, + 0x2ae2f435, 0xa8a54c70, 0x6ca8b074, 0x77952ce0, 0xc006b0c4, 0xb731909b, 0x09528ace, 0x3bde74b0, + 0xf78d4409, 0xe0b9b714, 0x3ebed1e9, 0xaa6e46b4, 0x7b36d82b, 0x250238de, 0xd25edc2a, 0x7b3954fe, + 0xf5fdc787, 0x6a64f9f8, 0x1db578ff, 0x8d910628, 0xd05d3f7b, 0x6745c11c, 0x86081a16, 0xac5ff5d4, + 0x3b609bc3, 0x322df0fd, 0x7f2162ff, 0xf011253c, 0xa90288c5, 0xdcb1ad13, 0xf546233c, 0x66777551, + 0x7727b7cc, 0x78789e3a, 0x0fdb6c26, 0xcb03bd38, 0xbdae0cb2, 0xd8a67842, 0x9fff2f50, 0xf8b827e4, + 0xcd507e1e, 0x61d878fe, 0x8e8ed169, 0xf0c1425a, 0x318ae098, 0x25391401, 0x4d6c4b0b, 0x61a7d0e7, + 0x3b1ccda2, 0xc10daa96, 0x8e55a079, 0x287f2c6f, 0x63a36816, 0xe1f028da, 0x9b6ea1b5, 0x0144b2bb, + 0x4201a62b, 0xb17f0bb1, 0xfbe0adbe, 0xeb55254f, 0x2215b6a1, 0xbe9ee69b, 0xdfcd1594, 0x2cfceed4, + 0x8f9f35fd, 0x8c5866c0, 0xcf3b0431, 0xace9c6d8, 0x2c10c771, 0xac32b72a, 0x04f3b8e2, 0xc1ce15af, + 0x84e32071, 0xcd071b47, 0xa452b776, 0xe6e96e44, 0x8b4e07df, 0x5bda36f3, 0x2d31c6d2, 0x58a0fb76, + 0x4c6f206d, 0x34ba6eb3, 0x0a588d13, 0xfb2ef77b, 0xce851d8b, 0xe0134405, 0x22b765a3, 0xb94654ff, + 0x45097011, 0x187f97ed, 0xc735dd45, 0x5988a2bc, 0x3dde1b0d, 0x849e3c15, 0x80c702a0, 0x0ba9dc62, + 0x5d57ce92, 0x01154d1f, 0x2cec9269, 0x2d82be9c, 0x7d1f303f, 0x8de11cac, 0xece0e395, 0x86962d5e, + 0xbac5e73c, 0xc02e1ce3, 0x79a3ce02, 0xe973e3f2, 0x025bfda9, 0x755c5564, 0x85300bd5, 0x2f3e6958, + 0x6a808c7c, 0xb1cda013, 0x23041b83, 0x728d3504, 0x86081d7e, 0x1092d4ce, 0x40920bdc, 0x101f3973, + 0xbc1efb28, 0x18a6d96a, 0x5bc03988, 0xea568d04, 0x6d47484d, 0x25798696, 0x2ef97de4, 0xd154c730, + 0x1248e0ed, 0x3f507890, 0xfe5f6142, 0x3b682f32, 0x9cfa1377, 0xc713eec2, 0x598b31b1, 0xa088faed, + 0x6a1cf4c3, 0xb6d224db, 0x01f4c09d, 0xcb900f6d, 0x17dbe60d, 0xb750c92a, 0x040ff29b, 0x3ada5b6b, + 0x284a308d, 0xfdcde80c, 0x6030f135, 0xb70d405b, 0xfe079d7f, 0x9b3c1f13, 0xa3f838cf, 0x7c718d45, + 0x8f2ff2d7, 0x77cdf987, 0xf34d9d45, 0x2fd8498b, 0x3c4a1a11, 0xe2f9dbb7, 0x31d062bb, 0x3e9a4491, + 0xab6c107f, 0x7140dceb, 0x48384043, 0x03807be2, 0xa355333d, 0x2cf338ec, 0x8a0c865a, 0xe7074d74, + 0x5973f098, 0xaf7d0c03, 0x428f5924, 0x073bdd34, 0x5c47da8f, 0x27ecd695, 0xf865677d, 0xdd53c123, + 0xb310a559, 0x0fe6aec8, 0x30ecd92a, 0x7df467e0, 0x0511df08, 0x1c8babb2, 0xd8943964, 0x579cd23c, + 0x480067f3, 0x67b3fb06, 0xc2c840c6, 0xb89f8a88, 0xdb650bb1, 0x84ea6f5e, 0x18bd8fde, 0x8855ee21, + 0x1dd1fa10, 0x015540e0, 0x23fc2092, 0xacaaa168, 0x3f8b419a, 0xaa69f599, 0xa044c2f8, 0xb21fe356, + 0xbf5d7348, 0x3b42e960, 0x45d59777, 0x41043d68, 0x79bd44cf, 0xdb8dc6b0, 0xe717938d, 0x46c20eb6, + 0x46e64dc9, 0x484f3166, 0xa1ae8db9, 0xf9076e74, 0x57812309, 0x91c0dddb, 0x866e923f, 0xd1efc75e, + 0x7bda64ea, 0x58df77b8, 0x5358f8ed, 0xe9a2e551, 0xedfd4326, 0xb8bfbe93, 0x0a63201a, 0x9168fb83, + 0x7bed96a3, 0xe124b811, 0xac87a607, 0xbbf4d7eb, 0x3765182e, 0xfd54bb6e, 0x8d63225c, 0x15837c6f, + 0x5df4e621, 0x68d5676d, 0x1fb7ef66, 0xe346dfd2, 0xf5c8d780, 0xe122e37b, 0x50476cd2, 0x6508e2bb, + 0x38da351a, 0x98a47104, 0xcc1e84a7, 0xfff5a04e, 0x29154b5b, 0x003f666a, 0x0962a248, 0x677a1d6d, + 0xd4d1edbe, 0x2e4f3227, 0x8d9e8fec, 0xd32d39b1, 0x8922baa7, 0x3f830a50, 0x4a263b70, 0xac250a12, + 0xbf9e97df, 0x70ddace4, 0x3164036b, 0x8c627a36, 0x74a05d0f, 0xa3dca893, 0x2abfe0ee, 0x9653b624, + 0x5f4c2b01, 0x96474ed1, 0x9f82f580, 0x788039a7, 0x4dd012f5, 0x84798fe4, 0xe1293c19, 0x246f784d, + 0xcc29421e, 0x0a84611d, 0x4d9c9efc, 0x4f3b12c2, 0x3bd2f115, 0x7cd36373, 0x333ebccc, 0xec7d670d, + 0x071b57a6, 0x60c99f25, 0x891ec4db, 0x021bc243, 0x7374bdd6, 0x73165831, 0x957ffe8e, 0xbd38edd4, + 0x8cfca956, 0x0bc6ce7d, 0x4562fa1c, 0x9c2c121b, 0x97bd314f, 0xe7300a38, 0x44913b32, 0x745f2b21, + 0x2f898b2d, 0xdcf8e279, 0xf6038159, 0x4f4ace65, 0xf97e187d, 0xdffb9927, 0x09b5caa7, 0x7ca283b7, + 0x32595c46, 0xbd467cec, 0x90777f17, 0x8ace94a8, 0x9b41231a, 0x68efc323, 0xbc705789, 0xcf737930, + 0xbbb6f84f, 0xfe997988, 0x2e874ea4, 0x2e3d0329, 0x6e3e979e, 0x4149b1eb, 0x4ac8216e, 0xd3689ced, + 0x1b8b0388, 0x95c56564, 0x3177be2f, 0x2f67279f, 0xcc5994b9, 0x004c3741, 0x01c2a8c1, 0x28d57e85, + 0xd0d1e2b6, 0x544104da, 0x1fd64f43, 0x399eab49, 0x41263739, 0x95b69a0e, 0x65398429, 0x5990780f, + 0xff051642, 0x7091ae90, 0x03d3200c, 0xbc12a476, 0xdbc56e0e, 0xc064152d, 0x305f1ba1, 0x7204bd40, + 0x9de8bcbb, 0x82567238, 0x1177d6d9, 0xdf8ebeaf, 0x5ffa7c39, 0xac4e72c4, 0x457906e3, 0xe4de0181, + 0xaf82212b, 0x40efb76d, 0xe9998b04, 0x9e842fb1, 0x8c7925ed, 0xfe1fb70d, 0x92648592, 0x51430e98, + 0x53367fe4, 0x2e76c38b, 0xb6a9137e, 0xbb200cc2, 0xb4666422, 0x22e25dc2, 0xefd5265e, 0xcd50a2da, + 0x5f84c58b, 0xc36e4cb5, 0x64e77e40, 0xee33028b, 0x9769a5b1, 0x6e5e62d2, 0xc0fd98af, 0xd06af43c, + 0x2867efa1, 0xf36da3a9, 0x7b692948, 0x4715de09, 0xd7fa0608, 0xb760a076, 0x78a0d97e, 0x9b429622, + 0x066b3215, 0xcf502457, 0x0af7bea6, 0x82d384d1, 0xfca8bbbe, 0xe38c8a80, 0x3b7209b8, 0x586c1715, + 0x45882ef4, 0xc9f3cd19, 0x901475ac, 0xf99ee53f, 0x92b645f9, 0xd15653b8, 0x3facb419, 0x378f6009, + 0x34c66fc3, 0xb34565c2, 0xdff5b234, 0xbe92f585, 0x3651c3bd, 0x6443000a, 0xae692198, 0xc3b5c604, + 0x71b07a58, 0xe596464f, 0x8fc372a1, 0xa79e470f, 0x008e7da6, 0x6c9e1b18, 0xb90792db, 0x4029bb80, + 0x23dc0f87, 0x2bf26c1a, 0x2ae042fd, 0x73aff0df, 0x5530125c, 0xafba6c7c, 0x167cece1, 0x88e74f2a, + 0xff9aa231, 0x7e0fac9d, 0x5643f3d5, 0x5fc6c111, 0xbdb93ed8, 0x7e6fa866, 0xe7321eb7, 0x9b845b0a, + 0x61de2f86, 0xd394b603, 0x715518c2, 0x7d568091, 0xd8396b16, 0xc4d7ea06, 0xa6d0f8f8, 0x0110aae6, + 0x36221c6b, 0x99077d9a, 0x481e9483, 0xdb0a7890, 0x8e3ffd42, 0x64d54704, 0x09ee3519, 0x45a2c820, + 0xb6e25b8f, 0x1a6468b4, 0x8de06937, 0xd2d9455b, 0xf509887e, 0xa311aa13, 0x46e85e6d, 0x094d10f0, + 0x90c53895, 0xecf1b251, 0x4a8c3e2b, 0xc07b27d8, 0x9f9ffb9c, 0x199d6bb5, 0x3c1d42ff, 0xd8f2efd1, + 0x7ca9dcb8, 0xba938ffe, 0xf84725e5, 0x442fe87e, 0x9ff216a8, 0x1101d972, 0x2492847a, 0xd620c50a, + 0xb0e97116, 0xfa50ac8e, 0xad229f36, 0xcd744ba5, 0xecf16daa, 0x36aa310d, 0x436105fb, 0x86328735, + 0x4627c182, 0xfa829d44, 0xd30432ac, 0x67174afd, 0x5d67a615, 0xff3538af, 0xb5cfe222, 0xba82b16c, + 0x1ac9ca29, 0xba579af2, 0x5401135c, 0x77b0dcce, 0xc78483db, 0xc2f9e109, 0x77da4faf, 0x3c0599ed, + 0x2682924a, 0x842b2904, 0x80b503b4, 0xcceaacd4, 0x3f046cae, 0xc3906435, 0x90196718, 0xd3ccafd0, + 0x4c1fdee0, 0x5eb3eac8, 0xd8ec7bd7, 0x6798d3b7, 0x8913a81b, 0x1ddaba91, 0x7f7a1fae, 0xaf93b5a4, + 0xf9490be8, 0x37e337e5, 0xb241aa94, 0x64662352, 0x22bccc67, 0x678cde0e, 0x6138a223, 0x7ceca378, + 0xac8079f1, 0xa31cf2a9, 0x89a3fdd4, 0x5f890c34, 0x14ae5763, 0x2a201daf, 0xc64739c8, 0x45131780, + 0xc719e1da, 0x9a507d98, 0xc523838d, 0x98a714ae, 0x702cb864, 0xda3b67a7, 0x2421c4cd, 0xfc855bc7, + 0xd2df0d33, 0x7d0ff15d, 0xd12f52ac, 0x72e37e04, 0x4eefe847, 0x44436607, 0x30700d27, 0x3c281cbc, + 0x349e1f2a, 0x3d511c64, 0x53f19806, 0xf03926ed, 0x7324a591, 0x9be2c3e8, 0xb3a9352c, 0xcd237c95, + 0x5322286a, 0xeebc75e5, 0xfcb9b428, 0x166e1b82, 0xc0c32810, 0xd1363ffa, 0xb425b9f4, 0xf43f779c, + 0xc3e2a34e, 0xe03fe9a4, 0x62efa16e, 0x358bab59, 0x5d7e0fcb, 0xc29e9d8a, 0x55b64f28, 0xb38c1645, + 0x2587f653, 0xc8b13a6b, 0xe7a093c8, 0xaa8c9814, 0x995f0bbb, 0xc778e734, 0xfc3be643, 0x828adc65, + 0x9cc76abd, 0x6d947e4e, 0x3af1492e, 0xc006e3a6, 0xd84592bd, 0x456cafc8, 0x704663af, 0xc13920b5, + 0x85f65fc8, 0x2eaf74ae, 0x4c09d709, 0xa0e1c580, 0xd5588e26, 0xf53ec87f, 0x601dc647, 0x349c66c7, + 0x5b4eabe4, 0x668e7890, 0x78fcc93b, 0x77d3a5f6, 0xd7159434, 0x46ca48c0, 0x72d9bc20, 0x55e0519d, + 0x19cb5a52, 0x5529ebc0, 0x5262c524, 0xa98c9b90, 0x74add16d, 0xcbd4c712, 0x93a95670, 0x3d45779d, + 0x70bb70c9, 0x0a8770b9, 0x939eaa7f, 0xde3bff63, 0x15006ebe, 0x4eb7493c, 0x851a2995, 0x830815da, + 0x076aa431, 0xb4f8eb2b, 0x3e587913, 0x6c481470, 0x04c1e8d6, 0xc4cd862c, 0x9b024192, 0xd6418559, + 0x8b783aa3, 0xff5ac82d, 0x799d4c87, 0x25e1044c, 0xd6a33c72, 0x7dae134a, 0x70e2e36c, 0x8f17a6bf, + 0x9d9305db, 0x43d215a1, 0x0789c5e5, 0xaa4c072d, 0x205e1e64, 0xc076f56d, 0x07bab38a, 0x3f50a26c, + 0x4ffaddbd, 0xd9c6cc16, 0xdd6291da, 0x5fc3953e, 0x99054324, 0x9e181f86, 0xe17a98e2, 0xb3363337, + 0xf5ed740e, 0xf84caddb, 0xc109beee, 0xbf6065bd, 0x6013113f, 0xfce1d595, 0x916a1c08, 0x838df94d, + 0xd404d7e6, 0xcbad606e, 0x66b185bf, 0xf5aa43f2, 0x3efed499, 0x86551c62, 0xbddd8902, 0x2123fe62, + 0x47db9cd4, 0x82fc2576, 0x399b34ae, 0xc5acdd2d, 0xb38cc79f, 0xe57e6a8b, 0x4cdbd537, 0xf825632f, + 0xfd10cd78, 0x4248abb5, 0x77d64d21, 0xa66a7066, 0xd6c6e4a0, 0x6cf2d1f9, 0xed40ef76, 0x16f69117, + 0xe32fe9fc, 0x3803b677, 0x79349432, 0xe85416b8, 0x1de73e4d, 0xd05f84fc, 0x23890985, 0xc681a6c2, + 0x9b1a3a86, 0x1c3dfd31, 0x542e2464, 0x6f1ddac4, 0x1d5b4bfb, 0xfbf2f495, 0xabfd11ac, 0x6d58d048, + 0x2bee0e6e, 0x7d3ab971, 0xf2d78e3c, 0x067cfd8f, 0x1bd4fd30, 0xa2aa0d65, 0x78e45a1c, 0x9b7748ad, + 0xfe61ea51, 0x947f35f9, 0xe2d287c9, 0x7eebedd4, 0x7b8075d3, 0xa762767e, 0xf2b70238, 0xfa0d7199, + 0x14e94a37, 0xbcb0ba2b, 0xde0e5e84, 0xa64d2ee0, 0x558bb952, 0x369a0632, 0x1fb55c69, 0xf6530cba, + 0x25da4999, 0x38705941, 0x9c36870a, 0x49ced48d, 0x5bf9a769, 0x8cdf2dbe, 0xbeca1a78, 0x0822e3e7, + 0xa2a4f159, 0x797d686d, 0x1b7a063a, 0xfa29fb10, 0x2250382f, 0x107ec8ba, 0x1e97c396, 0x73a85d23, + 0x517ceee1, 0xe13d961e, 0xa5905325, 0xadd380f0, 0x41147033, 0xd9750025, 0xece7fe8d, 0x2862e15c, + 0xeb25546b, 0xcbf847bd, 0xca3d3009, 0xef0dbb82, 0x124933a9, 0x75f7153f, 0xd562dba1, 0x82de15d2, + 0x21105ed6, 0x9f5d8eaf, 0x47705a4e, 0x0a881d11, 0x08dac176, 0xe9a1a2ed, 0x808b5bbd, 0x06f8dad4, + 0x39361dc9, 0x6d915890, 0x1f15b8c4, 0x6623dc8f, 0x47678950, 0x276a7fb7, 0xed1a1836, 0x2f2879e4, + 0xedf84b91, 0x429eabd0, 0x0e632fc6, 0x57d508cf, 0xcbe7585d, 0xc5ec759a, 0xe53ef898, 0xb9b70579, + 0x4add73ee, 0x06e19daa, 0xd2ae8a66, 0xa09d4efa, 0x3f1680a3, 0xac402ab1, 0xee05f58c, 0x3a3d5399, + 0x828ab291, 0xdea43ce6, 0x26d488ea, 0x359d6b84, 0xf46bef09, 0x11883568, 0xb7702a24, 0x59bfe252, + 0xab8eb57c, 0x0f8e51aa, 0x854ddbee, 0xf918eb19, 0xeffb0e5f, 0xa3469d9e, 0x4a157c39, 0x8d4b01c8, + 0x42213d74, 0x380bc966, 0x0546e823, 0xf2001937, 0xcb003080, 0x3e00da93, 0x59ece762, 0xb45213d8, + 0x6980469e, 0xdf9a8cb8, 0xb41b4fa0, 0xcbf3c48c, 0xb0d0c9e6, 0x880ad687, 0xf5fdb530, 0x85b33e52, + 0xdb23fd97, 0x593df844, 0xad688a77, 0xee8cc6f1, 0x949113f7, 0x36f835dc, 0x8ff5241e, 0x8d068073, + 0x2df411bc, 0x89fe1414, 0xaaa8e6d9, 0xf22257fa, 0xeca51cea, 0xaa173725, 0xd972b5ca, 0x0fcb0e0a, + 0x79ebeb7c, 0xb7e20dd4, 0x52e2abda, 0xb04a58f4, 0x2bb33f89, 0x571428fa, 0x651f4da7, 0xa9ba6351, + 0xc0dd0b00, 0x2eac07cb, 0xe839cc75, 0x8f0521b8, 0x4860361d, 0x00c523da, 0xec2958f7, 0x3139c55e, + 0xb56e01f6, 0x069911b2, 0x1b31da72, 0xb905aa70, 0x4e66575e, 0xd7353d61, 0x12511aed, 0x5aa18189, + 0x30bb9bbc, 0x356fcc76, 0xbf7559ba, 0x72da520a, 0x390991a4, 0xd1e746d0, 0x3be4fc49, 0x53b204b0, + 0x46eca7a3, 0x35e7ce06, 0x9c805f27, 0x77d3b63a, 0x8ef3a349, 0xe6ca1cb5, 0x135bca74, 0xa1f04259, + 0x0eafcefe, 0x91936545, 0xf23559a0, 0x0bf989f2, 0x13787541, 0x960bf4b7, 0x564ba175, 0x78288465, + 0x63ce0369, 0x9526c651, 0x165e2e31, 0xd6292185, 0x52d96e59, 0x431b4852, 0xbb8742fd, 0xa3e274b3, + 0x0e0bba29, 0xda3e7eb2, 0x5e1fcef0, 0xf36d6c03, 0x12a8a363, 0x0d09edf5, 0x521378e4, 0x80051c4a, + 0x3d56259d, 0x9acf67a5, 0xd32c4ad6, 0x65951461, 0x83a76613, 0x085fd3eb, 0xd6bde506, 0xc6d69050, + 0x4c77c8cd, 0xeb85a53b, 0xbacb002c, 0xe9ad4197, 0xa9c41c7e, 0xacce6570, 0x70fd0f21, 0x307f50d2, + 0x4215e6bb, 0x94727283, 0x2200cfc1, 0x85864e5e, 0xc77efd4b, 0x63a0ca94, 0x64a4a14b, 0x65d68ca5, + 0x96602c01, 0x2af3559f, 0x8d969c0c, 0x3e90e570, 0x32b959a0, 0xaddb207f, 0x5d6a3dfc, 0x01e2c6b6, + 0xeacb8151, 0x32897507, 0xf89bb120, 0xa673405a, 0x6f83d630, 0x7ad73cca, 0x497378dd, 0x75710f10, + 0xb0eba385, 0x3f521fd3, 0xf94a0433, 0xd82efcca, 0x7ca08497, 0x6d4be483, 0x5772de0b, 0x15cdf4ac, + 0x3c498a0a, 0xa13a0cc5, 0x929da6ef, 0xe6c05583, 0xbce1716a, 0xfff74b3b, 0x5bc84f4d, 0x1f3bb814, + 0x43427ac7, 0xd80706fc, 0x1b02e31c, 0x8268e9c2, 0x94c2af9e, 0x0cf48f26, 0x81eff8df, 0x5aa82ab5, + 0x6fc07033, 0x67250d06, 0x779afec4, 0x713b5479, 0x169e6e89, 0x0da5d6b9, 0x165956c2, 0xdf8f1e58, + 0x54ae3728, 0xe6e42ab4, 0x0a4fde19, 0x3a5d9830, 0xd1db0d4a, 0xb131f40c, 0xad0e5d4a, 0xbcb6fe04, + 0x29b4b1d3, 0xc95cf0df, 0xf62d1508, 0xf1f5e8a8, 0x6e527f76, 0x7b3afafc, 0x6b2902af, 0x2c9df233, + 0xf201dc25, 0x87d91cc3, 0xd1063a5e, 0xfb99807f, 0x3275543f, 0x730250eb, 0xeb458388, 0x38bf0794, + 0x74ebf23c, 0xf14c1265, 0xae2a7e64, 0xf7ac0290, 0xa4ffca4c, 0x73a956ad, 0xd49df4d0, 0xc5404c81, + 0xfbbe63a9, 0x0ad02108, 0x68508d92, 0x7f4c6806, 0x0a1b6a43, 0x47e82540, 0xa3ce39a0, 0xb788afd4, + 0xb007e68a, 0x91f63730, 0xbf04b0b9, 0xbe2bada3, 0x1b89452d, 0x2d09cbb9, 0x2dee4ba4, 0x2c92022b, + 0xc66f0177, 0xc8bf4c98, 0xd1981cda, 0xb3a9bc6b, 0x94c6ee1d, 0xdbd238bd, 0x5b38c5ab, 0xb6cc9720, + 0x979f07d6, 0xbfd78bb5, 0x547abda6, 0xc7c52f2c, 0xaa787dba, 0xec12287d, 0x6479cee0, 0x980c685a, + 0x7ccb2dfe, 0xe2d34858, 0x2d665864, 0x02c785da, 0xe0872ccf, 0x261579ac, 0x4c7dfe41, 0x0994494d, + 0x45a319b0, 0x7c99062e, 0x46f5ec72, 0x579064e0, 0x7ab65c64, 0x0c457ff8, 0x4308f3df, 0xf2146a99, + 0x0bc77c9f, 0x40a8d825, 0x21473dab, 0x82594627, 0x436b4923, 0xf667152a, 0x7790ef34, 0xd4eff6be, + 0x3ad38faf, 0x5a044bb3, 0xdb82a910, 0x4148ac5e, 0xf369a629, 0x83d3b836, 0xbd8f6598, 0x5fdba0d9, + 0xe0814e66, 0xebdd4c99, 0x672b9331, 0x0539626c, 0xba6b6433, 0x74723d3a, 0x336858fc, 0x074e4fb2, + 0x3949e21a, 0x896920aa, 0x71c4e70a, 0xdc986752, 0xa0374ba4, 0x2acc65d5, 0x04a5e826, 0x043d2ca3, + 0xb949d899, 0x57e05606, 0xe1ab09c7, 0xa8ef0e74, 0x8f8c6797, 0xa75ff713, 0x41f80e56, 0xf2e35785, + 0x5326a3ac, 0x75eeac9d, 0x7b4ea6a4, 0xbc9d3d50, 0xde60d641, 0xfe366dff, 0xcc0fcb7b, 0xa2685772, + 0xc718387a, 0x8ff00566, 0x5dde5164, 0x82c645d4, 0xf7057b0b, 0x4920d61c, 0xdfe72b55, 0x5e679c1d, + 0xd0444918, 0x836590f1, 0x69235822, 0xa3f9dfab, 0x4885a7f0, 0xe625ddb5, 0x33c20ad5, 0x0b9f0292, + 0x12d5612d, 0x6d1dac35, 0xc6cc3d27, 0x1b54d356, 0x3589f557, 0x7ac9e2bd, 0x8021156c, 0x9eab10af, + 0x68df6a02, 0x0ab205b4, 0x24b5a3c2, 0x3325bbd9, 0xf1e2b1c4, 0x6148aaf1, 0x92624d0c, 0xe38420d7, + 0x79108948, 0x4d6410bb, 0xf7485680, 0x7e7ab72c, 0xf9b50dd5, 0xe2c76945, 0x3b644afd, 0x3ad40364, + 0xb1415703, 0xb161dfed, 0xb80222f6, 0xd17d48cf, 0xc8e2e7ea, 0xeb988805, 0xce438bd1, 0x9630ab28, + 0x9a658145, 0xb7125a1d, 0x8f3e5f3e, 0xb8603fd4, 0x2392a1c8, 0x80075d90, 0x4203ce0a, 0x8e84a84f, + 0x25b77f4d, 0xfb6b757e, 0xaa645762, 0x5a12971b, 0x219a0dc7, 0x3e474784, 0x643314c1, 0x65169280, + 0xf86672fc, 0xc5a5da9a, 0x3c360b1d, 0xa198710c, 0x554d9056, 0xc85f6429, 0xad02609f, 0xa9014d0b, + 0x546f5edc, 0x44b99d58, 0x092866bb, 0x2a888326, 0xa230d5ab, 0x2298d78f, 0x5931d3be, 0x1985fefb, + 0xdc312d39, 0xbebea343, 0x6c131071, 0x384d66b2, 0xbd3db6a7, 0x215f6539, 0xd212451e, 0xa0ee5728, + 0xe8f2f648, 0x14e5654c, 0x6e619704, 0xc2826771, 0xf884498d, 0x3293872f, 0x9dd9ea0e, 0xf4faaf36, + 0xf796bf8e, 0x546a170d, 0x89771fbd, 0x7ae46c30, 0x22119b5c, 0x4d1977f1, 0xdc9b55a1, 0xe15d64b9, + 0x51144acf, 0xa5f4fba3, 0x5c54f279, 0x7af9691c, 0xf4583f25, 0x112fc341, 0x19acca7a, 0x7f3d5583, + 0x81474b0e, 0x9377e3b4, 0x66d67c04, 0x4c8f3bdc, 0xa7da156a, 0xd716b938, 0xbb37ca52, 0xe64b3678, + 0xfdddfdcb, 0x5f91d610, 0x8b9404e9, 0x8def46d4, 0x02fff701, 0x24bade9a, 0x9f6a376d, 0x7f6b2d13, + 0x733f8348, 0xbf6b8cc5, 0xa116f2f7, 0x9e0c886a, 0xafb0ab37, 0x7c8fb3a0, 0xaf493414, 0xe397ad39, + 0xa266a440, 0x61ce97e4, 0xe295b02a, 0xd22f0344, 0xd8d21f10, 0x81068710, 0x4e42d698, 0xa3a2b62b, + 0x1ab6cd87, 0x86bf27a3, 0xf15bc23d, 0xfd6be650, 0xc4b32b52, 0x7b4a1fcd, 0x17a74ca4, 0x57cbf268, + 0x9f20c46e, 0x076435d3, 0x03d56eff, 0xa7ba8db6, 0xdd0defaf, 0x1e3e945a, 0xfec28793, 0xd4fca899, + 0x65513671, 0x0ee12e19, 0x3d602097, 0x915c28a4, 0x6584b4de, 0x50abe92f, 0xf3996011, 0x7b7b0896, + 0x748b3756, 0x761f525c, 0x9b966697, 0x7b8dbfba, 0xb3865905, 0xfa333a54, 0x88963dba, 0x7b8bdc52, + 0x3ed86552, 0x21744167, 0x24000777, 0x6ee06f10, 0x799e8f97, 0xfd0926a8, 0x5b46f9cc, 0xa1336d46, + 0x0c4647f1, 0x7e00ed79, 0x74da30a0, 0xbc15c75f, 0xcb66796c, 0x5cd3121a, 0xc191efe4, 0xd5af7268, + 0x42bcf202, 0x258ab1cf, 0x10602970, 0xa0188f2f, 0x082d7632, 0x30395ea5, 0x3cea7c82, 0xaff6d7c7, + 0xa538e90d, 0x054228db, 0x6e411a47, 0x03fee0f9, 0xce3a4c96, 0x37a17750, 0x5204bf94, 0xee690480, + 0xacfa0c15, 0xff6d2893, 0x26ae1cf8, 0xaa65dcb2, 0x8c993b5c, 0x3760f849, 0x3ac7d976, 0xd0d0c2c2, + 0xf4f5818a, 0x47bb8e59, 0x724e92d7, 0xaebc5a57, 0xa3fb92d0, 0x4afeafb4, 0xeb5815ba, 0x8029bd38, + 0xb47224e5, 0xf7fcfa49, 0x7b14f0a4, 0x3bac171b, 0x38de2c54, 0x7d35ab61, 0xeaad40c0, 0xc675b15d, + 0x3c247040, 0xd915f6df, 0x1e83af0b, 0x8d95f0b6, 0x39c86a1a, 0xd5eaa176, 0x599865bb, 0xa696bd1d, + 0x75c6c941, 0xdf6df747, 0x67db4c9b, 0x553fd219, 0x09b3d56b, 0x34abfc09, 0x8a16901c, 0xa48e76cd, + 0x7aa6eddc, 0xba96b3e0, 0xb352df77, 0x53110753, 0x9b8f02a7, 0xedfe3458, 0xcf079522, 0x7b4caf99, + 0xe797e2e0, 0xcc4e99a5, 0x548059ec, 0xf95be1df, 0xa2009a19, 0x0202c9db, 0x1bd5b690, 0xd8a24d94, + 0x69ae4234, 0x238bcda4, 0x135da0fc, 0x0a4fe177, 0xdeed8c05, 0x3a075c6e, 0xe4336f58, 0x31df9114, + 0x3ed2da01, 0x8c97c460, 0x93e57522, 0xf86f4090, 0xa6e1b585, 0x6a44dde4, 0xf276d38e, 0x971103b3, + 0x992317d4, 0x566a1a81, 0x5e9c6099, 0xded666d0, 0xd471854d, 0xc514516f, 0xf8102f60, 0xb06cb139, + 0x60b3bb0e, 0x536c3632, 0x78cf132e, 0xa7496af7, 0xc8538cac, 0xbb2d8b78, 0x9e53b7da, 0xff541001, + 0xaadfd702, 0xe0e10c4d, 0x65d07735, 0x9f3648b5, 0xb3dd72e3, 0x8066628f, 0x18a3f696, 0x50d750e8, + 0x4f67feb5, 0x40007260, 0x11ae697c, 0x13a22e43, 0x11865851, 0xa45fdb54, 0x81f64035, 0x0254b3a0, + 0x380b93d0, 0xf1970c7f, 0x14c8bd5c, 0x579f9dda, 0xe5a43f20, 0x739a6d42, 0x5eba8870, 0xc9731326, + 0x27b96b16, 0xcddc4033, 0xc2a857ba, 0xc3a064aa, 0x0d36739e, 0xdf8cacf8, 0x896282ec, 0xcb5e06d9, + 0xb98c8a65, 0x27125e91, 0x380a8ca0, 0x9e722ab5, 0x4dc05ea5, 0xe347663d, 0x18b53f9d, 0xe7ab69b7, + 0x34501ecc, 0x99a9bf27, 0x125ae956, 0x735c5f2b, 0x01b59cfc, 0x79146678, 0x383e793d, 0xb8ca0cef, + 0x542bbb4c, 0xca7cd28e, 0xde35c2df, 0x733a1b51, 0x540e9068, 0x787e426b, 0xf1dc5c22, 0x48a809d0, + 0xc2e967ab, 0x71477227, 0x1169476f, 0x60506ba7, 0x823b689a, 0x88ba4007, 0x2d3aa81e, 0xa7c36d8d, + 0x22839ea5, 0x7ea8dc35, 0xafd3e552, 0x3bde9948, 0x810385ec, 0x9252580f, 0x4ca4eb39, 0x29b10abc, + 0xef7ccf33, 0x23477916, 0xebb0be38, 0x7d89f5a8, 0x38e425f3, 0x3622d3b4, 0xb9500aa8, 0x5708c754, + 0xd70422e9, 0x9d83491f, 0xa2dad8c6, 0xc5e7dce4, 0xa34d90bf, 0x8092e730, 0x97172749, 0xb7171ebf, + 0x0ec73001, 0x9e31a65b, 0xe5795dc1, 0xd099fa46, 0x930f59d2, 0xba942071, 0x5a982d96, 0x2edeaa5e, + 0xb39ea31c, 0xcc762e46, 0x776da772, 0xd20a1b39, 0x24c0b952, 0x993d4988, 0x2087d9ae, 0xba78019e, + 0x7da6d505, 0x189423d3, 0x9cda61c6, 0xfe464b32, 0xcc4dafa3, 0xb4f11746, 0x1a2e532f, 0xf0644c58, + 0xcf35a2d9, 0xa76bd413, 0xa00c8e83, 0x3a882159, 0x24e9a786, 0xd12a21c5, 0x628ad596, 0x14ab5dcd, + 0x3aadd310, 0x4fdda82b, 0x6352240a, 0xd4bbc7cc, 0x18121d8c, 0xc4863bdb, 0xf8a206f4, 0x257bc0f9, + 0x228e22d7, 0x51cd6dc5, 0x941954a4, 0x98af11ad, 0x48303103, 0xd8258ad9, 0x960e7553, 0x7d3ef0ae, + 0x84e6c7ef, 0xb1e8c029, 0x2895cecb, 0xed8e76da, 0xbf88428d, 0xe71e1c45, 0x86b54ef2, 0xf3bdb136, + 0xe1596595, 0x78235612, 0x3a6a510f, 0xb922e88f, 0x93a18ead, 0x41133882, 0x5ebf7622, 0xf7cdb7e9, + 0xe66b69a5, 0x915e233c, 0x6b680916, 0x8a13f25c, 0x96ed658f, 0xd8f68886, 0x507b40c2, 0xfa65f1f2, + 0xd1d73fce, 0x281e37bd, 0x1ebab676, 0xd295ca06, 0xb737318f, 0x9fb43dea, 0x5fcee851, 0xf204c0a5, + 0xe2c292aa, 0x57b8d98c, 0x0c47fb74, 0x645468da, 0xf0fb4356, 0x3f628708, 0x0cfb411f, 0x3cd880eb, + 0xfc9de2e2, 0xd002594e, 0xec0acdbe, 0xa650d226, 0x66c999e1, 0x4cf3220c, 0x06fccbd2, 0x250406a6, + 0xc229e3fd, 0xf116492b, 0x0d7d0e0b, 0xbdfbca9c, 0x17c97992, 0x6b2448d5, 0x174ec543, 0x28c19432, + 0x15b50e8b, 0x216d18bd, 0xdb9a5a95, 0xb5a4a2fe, 0x5a873a0b, 0x1f00a668, 0xb1c7eb78, 0xff6e8d20, + 0x7d951d0d, 0x8961eba3, 0x1a6df6c0, 0xce34bf75, 0x95c952fb, 0x9c2e91db, 0x73cb419d, 0xf9577d6b, + 0x7db144c2, 0x01ec5236, 0xf218d98d, 0x8a267256, 0x88680a07, 0xa5c6cdf8, 0x7853df01, 0x4ea61c46, + 0xbaa3b4dd, 0x7eaf2552, 0xf8d6c5b8, 0xea20af58, 0xa37b8da9, 0x36ad9a07, 0x03841c06, 0xc1b7ca6a, + 0x5acf49a3, 0x3fe5c1f1, 0xa75bd5e7, 0xf1aa8a3c, 0xea0285f8, 0x8971b16f, 0x967f4a0e, 0x096431f0, + 0x7def7e6c, 0xac2e59bc, 0x2e1e7daf, 0xdd64a3c6, 0xcf8be39c, 0xb223531a, 0x501af305, 0x2cae36e7, + 0xec884247, 0x12d6d3a2, 0xd2b53608, 0x52c6b34a, 0x3fb12447, 0x0ca4b591, 0xa7135022, 0xde3124b1, + 0xead65eac, 0xf66984b9, 0x7c706d9f, 0x60d8a631, 0xb1500ade, 0x0d3c1d44, 0x9e10a058, 0xa92dbc0f, + 0x505252fb, 0x367e27be, 0x94653571, 0xbbd77424, 0x5e9848ac, 0x7b5b50de, 0x505c0259, 0xa3f8b3d6, + 0xb0f00acb, 0x2ff996e0, 0xef48c6fc, 0xbb110e93, 0x4f328dd3, 0x5e2e6592, 0xde6c8d16, 0x220d6c3e, + 0x71e6904c, 0x56320a75, 0x8f667e87, 0x98d3e301, 0x63a9a59e, 0x0ae749c2, 0xdd211bd7, 0xca880c09, + 0x6980706e, 0xfed277f1, 0x2c66beb8, 0x18289a3b, 0xa4d6101a, 0xacb3c89c, 0x620d88ef, 0x244b00db, + 0x51689777, 0x7d9e2378, 0x8e8c588c, 0x1aab3741, 0xf1620ec9, 0x1e127f73, 0x19993739, 0xc27a3aab, + 0xfdbc26c2, 0xc10e0eb1, 0xa33462b5, 0xff74b99d, 0x36b1a56d, 0x47664faf, 0xebe4f3be, 0x670a370c, + 0x00d84ad9, 0x66a32afa, 0x51647924, 0xed9756e8, 0x7e5fa7ee, 0xca1b6fbc, 0xacf9a605, 0x0a2b7b62, + 0x4948397b, 0x5e6cf327, 0x4dae69b4, 0x6d1baaac, 0x75cce883, 0x7bf679aa, 0x5fd5e36e, 0x14dcc64a, + 0x940f0507, 0x60ad224a, 0xcfac0dbf, 0x381b3205, 0xf17d8dc7, 0x20f1177d, 0x5fde4883, 0xa7ec3cff, + 0x3071bb32, 0xc155ae55, 0x51fcaa45, 0xcca02843, 0xaf70bb11, 0xcdaf35bd, 0x4c80b990, 0xfe7abea9, + 0x81447262, 0x2e13178b, 0x13826912, 0xe3b587fb, 0x9f0462cc, 0xb1a8d57a, 0x1a9d32de, 0x94b91bcf, + 0xd260066e, 0x6dcf7872, 0x6c8342f1, 0x4f33b02e, 0x64bdea5e, 0x208ae621, 0x574f6523, 0x7af4561e, + 0xc832d43f, 0x3fa3418e, 0x7436b12f, 0xc99b0321, 0xc809ae58, 0x3192454f, 0x0090fd49, 0xd4dc2277, + 0xc58a07a0, 0xb60581c4, 0xad3a9cb3, 0xf64c0a85, 0x036dd726, 0xc459821d, 0x2ad0f85b, 0x48ff60cf, + 0x0b584564, 0x6dd8ca8b, 0x74ddc741, 0xa7fe3f05, 0x04f20877, 0x9161089a, 0xbf13ca0b, 0xb14e6b79, + 0xdfe7ff30, 0xdd0bc550, 0x68b95a1c, 0xe6a3c082, 0x2fce969f, 0x628ad763, 0x66ad47a3, 0x9bccae2d, + 0xa56a0793, 0x40015c08, 0x1cacc4eb, 0x3f24f517, 0x690c9e13, 0x3afd1cd7, 0x3cfaabf9, 0x8f256893, + 0x18357444, 0xaa0ddba6, 0xfa350899, 0x1907cad7, 0xb2dba68a, 0x384bf016, 0xa93754e5, 0xbb3c5063, + 0x3d3e83fc, 0xc8ceb826, 0xd9163a64, 0x27a8440b, 0x038cb542, 0x1b48be38, 0xe5ee6915, 0xf1f20b96, + 0x86593ec4, 0xdc1f890a, 0x1d74f22a, 0x701b9ac2, 0x5bc4b471, 0xc50514e2, 0xd3ac9e2c, 0x11601af4, + 0x7cc6ddcf, 0xa2d110be, 0xbe69a4e9, 0x2c94d951, 0x99789da2, 0x44fcda71, 0xe2798ef9, 0xc3923173, + 0xe092fb67, 0xf6511691, 0x6b1d3276, 0xb29fc201, 0xa6ca1d3d, 0x1d7361bc, 0x9cc96bd7, 0x90b845ef, + 0xd4351258, 0xad1d7a6f, 0x8edbb2c8, 0x708fae13, 0x9e0c561a, 0xca1cb834, 0x5db8b9ef, 0xa65baea4, + 0x8b0fdaa7, 0x56862116, 0xbd14d846, 0x962b0ba5, 0xaa515d8c, 0xf52b0e77, 0xd0d3248f, 0x386724fd, + 0xec8edc5a, 0x0f9734e0, 0xf013d8cd, 0x035c4c92, 0xb29e4f6f, 0x6f7f7d98, 0x06cd25bd, 0xfd2635ea, + 0xba2315b5, 0x8bca9646, 0xa900a80b, 0x37ce0f94, 0x7a74d0b5, 0x45967fa3, 0x7a1b5ecb, 0x747bae7d, + 0x3d943efd, 0xea9b58a9, 0x5abeb45e, 0x1d2bef3d, 0xaa9fe854, 0xffeaa678, 0x621e5950, 0x1cc54240, + 0xd66e44a6, 0x096d10f3, 0x14cb1fb5, 0xa70fcf51, 0x12299da2, 0xeefe9d16, 0xaf6e4014, 0xabc44865, + 0xa4abde89, 0x7e593cea, 0x68b3f55f, 0x01367637, 0x5293441a, 0x3a030bfc, 0x70ee0001, 0x32d306a7, + 0x18681987, 0x1fc448b2, 0x852dec5c, 0x0437cd4c, 0x6d62c098, 0xd13f108e, 0x09ba88de, 0x24ea4221, + 0xc925cfdd, 0xc57db2da, 0xea22834b, 0xc5b6f36c, 0x46be5842, 0x4044ee11, 0x1478ba57, 0x23847a84, + 0xa613efe1, 0x5d6b6cf1, 0x52287c81, 0x15742ec0, 0x1881de88, 0x66c23ffe, 0xee68ff06, 0xfe0de47d, + 0xa6b2516d, 0xc94684b1, 0xd2686635, 0x720b1a70, 0xbccfa79b, 0x7c9ba45e, 0xc746ae33, 0x70e085c7, + 0xc5395aa6, 0x40855ff8, 0x0edb4d01, 0x1cf3ed9c, 0xcfb031c4, 0x5e7fa374, 0xb8586ac9, 0x44919971, + 0x1fc1420a, 0x7b82cdd7, 0x74e22b2c, 0x95e706b6, 0xcc2af9ed, 0x01c187fc, 0xbaf81a8c, 0x20c453be, + 0x37529053, 0x971264e3, 0x8bcf4458, 0xb43265f6, 0x9de7a01e, 0x1b965eaf, 0x61936125, 0xe72e8284, + 0xfd20f213, 0x5a01df1b, 0x1384e92e, 0xcdadf107, 0xc5dfb66f, 0x56680317, 0xa6c44e80, 0x86876c9e, + 0xd8256679, 0x200caba0, 0x54c7a8e8, 0x42a15ed3, 0x5fec34af, 0x81517fb7, 0x098b6d94, 0xe11a8759, + 0xde20eadb, 0x4b550922, 0xcb6cdcdd, 0x9044f6c9, 0x0a1ffc4c, 0xce73f7b3, 0x2e1a795d, 0x4fac3ad0, + 0xa33ff00e, 0x33e36aee, 0x9393b29a, 0xe923f4c9, 0x33922dad, 0x3c325060, 0x6aef5797, 0xc04b0ca8, + 0xcf192a46, 0xac711692, 0x5e2f0225, 0xfc7aca57, 0x61888b41, 0x74831a7b, 0x5179d10c, 0x6650d4aa, + 0xcf0d2806, 0x9e9ce023, 0x88768a53, 0x9966de71, 0xa84e1cff, 0x3460c1e3, 0x8db2202a, 0x81753500, + 0x75458c70, 0x567f15fc, 0xbb347865, 0x404f0b43, 0xfdf39744, 0x6eb46edb, 0xcf3a4b64, 0xb7a08e03, + 0x8b9a9466, 0x028edd10, 0x8d9b203f, 0xd71534ed, 0x101a4132, 0xee0ee95d, 0x39eaa7d9, 0x6a3eb5a6, + 0x03449b20, 0xbbf7a9a8, 0xf094370a, 0x89cc51a2, 0x5e41dafa, 0x7205521b, 0xf3d81460, 0xb5244eea, + 0x62efa713, 0x34b9ab75, 0xcbd4ede8, 0xc4b3b0dd, 0x1be61cc2, 0xcfc12458, 0x36a87fce, 0x7cd8d299, + 0x4f3b944a, 0xdcc9bea4, 0x31d123d3, 0x5716bf43, 0x4828435c, 0x58ace8ad, 0x2d7853f3, 0xed291f71, + 0xae8f721a, 0xfd8d9096, 0xf138748f, 0x872e128b, 0x2bdb1862, 0x9cdb304c, 0xe58795aa, 0x175ec601, + 0xdf98a43f, 0x933f33e6, 0x3804ebb2, 0x8c3a0406, 0xfd97a4b6, 0x7deea466, 0x2d576e9c, 0xb6acfee7, + 0xebb37ace, 0x75f461d5, 0xbebd8873, 0xfb59276c, 0x2bb23f77, 0x51e31c5a, 0x77ebfa11, 0x506aaa94, + 0x659e5a1d, 0xfeda2c1a, 0x1c09e964, 0x81dfef7e, 0x30dba89a, 0x81c40152, 0xa0253b25, 0x97b6cd30, + 0xf9bd8074, 0x81f8e365, 0x008a8853, 0x9692bcc8, 0x9ffdb99a, 0x1842375f, 0x73667d3e, 0x285f9602, + 0x11bed8da, 0x6315b955, 0xff9a4304, 0x72d4d9e4, 0xe8b155ea, 0xb811838f, 0xd26bb2bd, 0x99693a1e, + 0x6aec1134, 0x3839e98d, 0xfdf0b75f, 0xe83add77, 0xbdcfea92, 0x4229c01c, 0xb67bf706, 0x9655fada, + 0x610160ab, 0x9619f3ad, 0x6707433a, 0x6c2c73ae, 0x86d49a9f, 0xd99b5485, 0x9686e4f6, 0xaaaccf4c, + 0x7b5af469, 0x1dc23cc2, 0x3f2c063b, 0x88a5204f, 0x0e9370c4, 0xb67b9ca8, 0x9fd283ad, 0x2c7314a7, + 0xd4ba2bfc, 0xae7bff12, 0x820201cb, 0x570b09dc, 0x465ac7f6, 0xcb46e964, 0x356e32fa, 0xa0f4e94b, + 0xc81b71eb, 0x24c0e000, 0x795cca43, 0xe0b214be, 0xbdf2b1fc, 0xf33eda63, 0x6baa224a, 0xb594e19d, + 0xe962f6c2, 0x320b93f5, 0x1bd1a663, 0x66d98343, 0xe27421a1, 0x2d84e38a, 0x57af24d4, 0x7608acb8, + 0x85eee088, 0x82cc630c, 0xc27f2403, 0x59847069, 0xcd457321, 0x95b69b9c, 0x8a60ee1a, 0x543a7774, + 0x72988a0c, 0xbe7ce055, 0x798a3a24, 0x3e648d17, 0x575f1852, 0xe5e94996, 0xd9bc4a9f, 0xc7747525, + 0xa25dc3db, 0x612e49c4, 0x732ddb48, 0x0950859b, 0xcde0cb42, 0x8296c58d, 0x37795eba, 0x54fc024f, + 0x9517d5b8, 0x2e65dbeb, 0x7da5804c, 0x3c13f0bd, 0x8c8953b4, 0x6b4521e6, 0xc91af23d, 0x4cfbe940, + 0x3665998e, 0xf491e7cf, 0x63c4c2f9, 0xd18e24cb, 0x7af794c5, 0x040a898a, 0xec1503d4, 0x004721b8, + 0xf8c9ba7f, 0xbc406d7c, 0x413418b6, 0xdd2dfc6a, 0xf26d1e91, 0x91bdd83e, 0xacfeee40, 0x6229d2c9, + 0xd6dabde5, 0xd0d8ff75, 0xef5cfcf7, 0xd704d0b9, 0x3640b40c, 0xb55612c2, 0xf1ad7508, 0xaf4e86c2, + 0xfc6ece05, 0xbd72f545, 0xad76bf8e, 0x60bc3092, 0x5d3d5442, 0x2c097855, 0x4087f9b4, 0xefbb98d9, + 0x0a5151ff, 0x19cd9cd3, 0x92dee50b, 0x111516ad, 0xd6faa90f, 0xc011d399, 0x9fd81069, 0x72e174bd, + 0x213cfa71, 0xffb0e3b8, 0x8ad767d5, 0x57fe8971, 0x284796ab, 0x69fa75aa, 0xaa3737fb, 0xa5010cb2, + 0x76a3edd3, 0xf548e31d, 0x6e89ea3e, 0xc018664d, 0x901285ac, 0x73229bef, 0x0a3e823c, 0x577e3cf1, + 0xe1b098d7, 0xa0d2a3da, 0x6e15233f, 0xa7ecd422, 0x81dde79d, 0x16309552, 0x8adc9b6a, 0xd49aec1a, + 0x6ba3d732, 0x4583ab3e, 0xf5d2006c, 0xb193802d, 0x635f036a, 0x1ce8af49, 0xdf192193, 0x73aef94c, + 0xc04c1af1, 0x098857cc, 0x046e10b8, 0x36eaf406, 0x78cc31ea, 0x68ecd0dc, 0xd80dfb5e, 0x72dd5649, + 0xc2b108a9, 0xc256115f, 0x94c81424, 0xba457548, 0x826ef0dc, 0x8cea3145, 0x0fb70c5e, 0x54dd79ca, + 0x52c28d50, 0x268339a9, 0x99c31a00, 0x2d37c05d, 0xe9d34160, 0x8ad40e31, 0x79eb9e1e, 0xcde835c0, + 0xaf9f4a73, 0x7d3a2f6e, 0xd655b951, 0x9f76c0f2, 0x0fbdd5f9, 0xbf52a61a, 0xe633cdee, 0x163d6bee, + 0x622d30ac, 0x77a15f01, 0x320af30c, 0x5a5ce422, 0x894e963f, 0xe69bf584, 0x71c3ff58, 0x29804ed8, + 0xa0a2202d, 0x6262e13a, 0xe88ee986, 0x02dfcae5, 0xf89397bb, 0xc97e2d1d, 0x97338cb1, 0xadb7caac, + 0x29b6ae05, 0x6971d98d, 0x347ba128, 0xdc1b5fef, 0x9f28b0ed, 0xb4b20392, 0x495f4a1c, 0x9b1f5f13, + 0x861110c1, 0xe2684f6c, 0x460dbb62, 0xd2a3d034, 0x1915b631, 0xd91ba3f1, 0x155a88da, 0xe91f7b9b, + 0xa36f2dd5, 0x21fd4be5, 0xb4af41d7, 0x20851b9d, 0x6a20a5d2, 0x322ad4bd, 0x9dbb9e9f, 0x957d5f40, + 0x8d88f32c, 0x0b721267, 0x80ca6f70, 0x39ea7fe0, 0xa714b56b, 0x567e6d6e, 0x3f47d2ee, 0x286b2332, + 0x1d857928, 0x97e4e89b, 0x97f34c3f, 0xa0b00897, 0x7064eecc, 0x48d20b6f, 0x41a79473, 0xf5f57f0c, + 0x48424aa2, 0x4e3e5678, 0x02e1c2d4, 0xccb9f736, 0x8cea2599, 0xf50ce8e7, 0x9f5d7569, 0x95161abe, + 0x693ed846, 0x11ae7b33, 0x59ba33d0, 0xe850777f, 0x79bd0ca5, 0xb6d90201, 0xbd3e3c47, 0x570bff1d, + 0x3d10ad6d, 0x5bdd4df5, 0x5bdb8fb5, 0x33f6ca43, 0x6efccb77, 0xd0c5cf29, 0x8e29828a, 0x8b9db5ee, + 0x2272b3fd, 0xc47a4341, 0xad6de0d8, 0x94ec9de4, 0x882be06e, 0x762458f5, 0x79fba007, 0xd5305352, + 0xeb962c98, 0xce16a3ef, 0xa9340b9b, 0xf4213750, 0x2b35d3fb, 0xc69db854, 0x2c548296, 0x0fe9acf6, + 0x75830ce7, 0x78bded66, 0x6122a0ea, 0x0638b5e1, 0xb89a01e5, 0x197ba079, 0xd9cd4a58, 0x0b9394d5, + 0x30537be2, 0x172fc43e, 0xb1a41ebf, 0x9d1b6726, 0x0e5a3794, 0x1ba0f6b8, 0xf09bfbd9, 0x3c44dddc, + 0x83a2139a, 0x0cd90d72, 0xd554fdec, 0xceb99d20, 0xfff63186, 0xe5af1adf, 0xedf81c02, 0xd8157668, + 0x359067ef, 0x20a97382, 0x2c34dccc, 0x25f371b2, 0x6fc4a5f3, 0x626235c0, 0x5ef2ec80, 0x5b813341, + 0x8aa7d58d, 0x70b85fe6, 0xda493625, 0xf8d556ae, 0xb1684cbe, 0x3441143a, 0x9960d42f, 0x1f2aa630, + 0x237ef5cb, 0x15609924, 0x6ce3027d, 0xce75f813, 0x3199443e, 0x13f19460, 0x8222d29e, 0x2f37de0d, + 0x9a0333ce, 0x9428e82b, 0x4173e996, 0x1ab7bd8c, 0x696bded3, 0x3e8a538a, 0x1c749135, 0x7154814a, + 0x3edc3433, 0x4180cfd4, 0x7c20517b, 0xd32099d6, 0xaa2aea98, 0xb4dbeff2, 0x19542d66, 0x7270e56b, + 0xddc633eb, 0x68bc518c, 0xd8609aad, 0x3fa459ce, 0x29966fea, 0xe47f6252, 0x32816af6, 0x47f320a2, + 0x3e47b315, 0x51e7c887, 0x41acf82e, 0x58078407, 0x52c27452, 0xadb448c1, 0x7448a145, 0x7c1e945b, + 0x72167e31, 0xdac76d0e, 0x9387bda0, 0x1be7e55f, 0x580a46d2, 0x4a7e61d5, 0x11f93eb3, 0x0bc6ee58, + 0xeda817c5, 0x7f29a472, 0x04c5d7c3, 0xb376cacf, 0x22b909d7, 0x2c6e9bd9, 0xc29c72d8, 0x84167dfb, + 0x018c9973, 0x90a3122c, 0x8c507075, 0xd07fab32, 0x02ee75b6, 0x4e1dd521, 0x2230ac7f, 0x2bb32427, + 0x0a71f7e3, 0xaba4f872, 0x17de7746, 0xfa78709d, 0x7f7565d8, 0x54eebbd2, 0xf9c2639a, 0x0064aa91, + 0x65b54ff0, 0xea1795ff, 0xb127f9ec, 0x058dbe01, 0xc4faf108, 0x71e7b226, 0x59371538, 0xec51e189, + 0xb0e56e2a, 0x6c573a24, 0xde8a4a76, 0x3f7d5c88, 0xc41aa7f7, 0xec7873aa, 0xc9e81630, 0x61db59ed, + 0x8842f149, 0xebd61e9d, 0x4924add9, 0x52386146, 0x14425452, 0x1326b9d7, 0x6fb0b90d, 0x9112891f, + 0xc7182660, 0xc6d59820, 0x930e8d06, 0x3a072ea7, 0xa69238dd, 0xc95c7021, 0x613311ce, 0x2c917a62, + 0x6f42a84e, 0xc3f713ee, 0x1433a284, 0xc9009eb9, 0x5ad081c9, 0x98329a28, 0xf2023d9b, 0x8c5b2949, + 0x0e3e4d92, 0x51e54ec9, 0x6056cb91, 0x833287c8, 0x21a2e3f9, 0x936faee2, 0xe7b60c56, 0xb6d3f139, + 0x4c45dc59, 0x77c9b9ac, 0x9786f16b, 0x4ac4f602, 0xdb719c43, 0xf98e467c, 0x4a42e19e, 0xbb3c5899, + 0x26e68667, 0x8c6fed8b, 0xb7a3cb33, 0x4dca3a03, 0x663effa1, 0x90a14a5b, 0x6353c1f8, 0x9d231ac3, + 0x0266727b, 0x25e0188d, 0xe64b6a28, 0xd9dbe09e, 0x41576756, 0xb9e6a42e, 0xca2b2b1b, 0x025e72ce, + 0x8dca267a, 0x9da9ed81, 0x99d90e1e, 0x80bcd69c, 0x40cd2891, 0xf7ecaa8f, 0x71792a47, 0xb6282d35, + 0xa6eadfdf, 0x6567d839, 0xa19a07f5, 0x245168e0, 0xded18da1, 0x592f2358, 0xf1077961, 0xd0f2fb17, + 0x8801ac7c, 0x47af1101, 0x017492bc, 0xacb73254, 0x9d2c47c7, 0xc990b3d5, 0x04a37faf, 0x027268d0, + 0x07fd6c59, 0x8ede3b43, 0x34f30f55, 0xe0fe9e23, 0xb141b19d, 0x72c1623a, 0xc4fc751f, 0x917b8a43, + 0xd6e38bea, 0x283f09b8, 0xe4bfaf68, 0xe425d89a, 0x2c7dfdea, 0x53e02814, 0x107e998d, 0x799d3982, + 0x6ac271e1, 0x444cd8aa, 0xde6f2a6b, 0x3e0b0195, 0xe630b9b3, 0xe46226c1, 0x9c202eef, 0x3871f2f0, + 0x299be047, 0x75629e54, 0x145b0dcc, 0xa36253cc, 0x61cf8579, 0x2cc7e301, 0x92715873, 0x0507ce57, + 0xb6e29420, 0x5c625e26, 0x714b060d, 0x46b083dc, 0x00a16405, 0x1734dca3, 0x1dedffb1, 0x20bad7cb, + 0x3b33e8dc, 0x55a82f31, 0x355d9818, 0x711ec56c, 0x37252a98, 0x01d67be7, 0x5ed856c0, 0x367190b7, + 0x8ca7b35f, 0xfc928132, 0x4d42a7a6, 0x042f8e8c, 0xa61c653a, 0x30cd617b, 0x048387ef, 0x07bf0357, + 0xb5d42d95, 0xefc8e2a7, 0xd9d00153, 0xfbc47922, 0xcb326b8d, 0xb22d55ce, 0xf7347bf4, 0x9ef07b85, + 0x64c6fc15, 0xe4c4eb99, 0xb7976c9f, 0x562410c6, 0xd744a001, 0xb8e0e49e, 0x2caa2df2, 0x0afa1fd4, + 0x5d172106, 0x93de8c69, 0x7def76c3, 0x2ce4bca8, 0x8617bda2, 0x77cf9b0f, 0xaba64ee1, 0xa5d32606, + 0xfd124060, 0x7590eec9, 0x9ca5a9b0, 0x35d5ca4d, 0x6fcc3130, 0xc1c16c0b, 0x75c3c28a, 0x162d9dcc, + 0x07ff8633, 0x946c097b, 0xda10b35e, 0xf5163763, 0xd6e03588, 0xf02ea71a, 0x72b33717, 0xf91b53d4, + 0x46923efd, 0xecc22135, 0x581995f4, 0xc7046e00, 0x8bb3b2a7, 0x7f08b5e2, 0x3544ac6c, 0x9e01a55c, + 0xc2287720, 0x598c947b, 0x7d19a8ab, 0x8639db90, 0xf3bca9c2, 0x1508861e, 0xc1020268, 0x3f9de529, + 0x273078c6, 0x5f07dd35, 0x8d4e5f56, 0x793a0cfc, 0x3fa4dba0, 0x79b6ec2e, 0xe0f9a174, 0x0c531754, + 0x07109a9e, 0x14cbed6d, 0x43665396, 0x0fb21bbf, 0x9a05c8c9, 0x1da55152, 0x9c2090f4, 0x47d57756, + 0x7e58809c, 0xf92023d9, 0x1c7603ee, 0x00c3c14a, 0xe48b06f6, 0x8bc784ed, 0x23871803, 0x29ce80c4, + 0x8de5421a, 0x404115cc, 0x92486f32, 0x3d0052f3, 0xdd78ad76, 0x7c2bce4f, 0xed061ecd, 0xa64bc441, + 0x12f88316, 0xa0c22aca, 0x39f61c33, 0x7edfcc58, 0xa67febe7, 0xe54cfd3b, 0xbdfc4e77, 0xc0e79eeb, + 0xcb2467fd, 0x8d11d7a6, 0xbceb1fe4, 0xceeca079, 0x2c2bd9de, 0xd44425bb, 0xa1c78e95, 0x22fe2ee6, + 0xc69ffb4b, 0x06efc392, 0xac2b8706, 0xaf5727e1, 0x42132bf4, 0xfe9739e1, 0x39683964, 0x88b99ec7, + 0xb1a33b9e, 0x17ac99d4, 0xed34f9cb, 0xdf5dcf7e, 0x623d4c08, 0x365c38c5, 0x61438a3e, 0x2b1f598a, + 0x39fac3cb, 0x696874b9, 0x17e428b4, 0x0eee12fd, 0x29ad8c5b, 0x0472d26b, 0x38b11172, 0xd2af4dfe, + 0xc4dafac9, 0x9da1c50e, 0xff54e76e, 0x41da108e, 0x276fd95d, 0x3131f132, 0x5478cc4c, 0x65d0e512, + 0xd128542a, 0xdac39957, 0x0e2f1e59, 0x00ef8898, 0xa7b40cfa, 0x4ae60ecf, 0x49e552f5, 0xa3a9d48a, + 0xbab69b2f, 0xada027ae, 0xbc97a344, 0x90a219bd, 0x98745815, 0xd964aa66, 0xcf015bb4, 0xb32a9701, + 0x3d556047, 0xf8bd8c72, 0x11656115, 0xda83e637, 0xb8f8dcb2, 0xe507d9db, 0x5f6b2597, 0x7c3e5e28, + 0x0e32e1f1, 0xedb56b3c, 0xe3fea5b2, 0x9a6694c6, 0x27a074a2, 0x3ca6af87, 0x403e218c, 0x97c1a842, + 0xadc8c4cb, 0x41964311, 0x70428766, 0xd0312f0a, 0xf4093291, 0x554dfd71, 0x5a3560c7, 0xa977196f, + 0x265b5e9c, 0x9a732ea5, 0x9291f811, 0xf1330d16, 0x981781c3, 0xd15abb59, 0x60212c4a, 0x23b8010d, + 0x36e978c3, 0xbef6c900, 0x05d48fb2, 0x0e506767, 0x71e9750e, 0x9c111156, 0xadf302a2, 0x21609caf, + 0xc289919e, 0xb27921a9, 0x6aff13d7, 0xe1a685f5, 0xc0a2eb35, 0x608940ed, 0x52adb932, 0xab67981c, + 0xeab602d1, 0xf043d90d, 0x90d86cf5, 0x0720a22a, 0x785cc6d7, 0x0863a5cd, 0xf1178ba0, 0xd2601c4c, + 0xe060778d, 0x32095bd9, 0xc4609787, 0x40cdf6cf, 0xb5f01aa2, 0x2dcbafaf, 0x23917540, 0x256663ef, + 0xf90b016a, 0xa5e479f7, 0xbb30a794, 0xb88003a3, 0xb288575e, 0x31585209, 0xe71c7de8, 0x91b8aa80, + 0xcbf8a36e, 0xe5e58da5, 0x429af6a2, 0x2881352b, 0x864ed015, 0x4de1a684, 0xaa8b280e, 0xc74bf04b, + 0xce6d476e, 0xaba96966, 0x559e6c79, 0x80935b42, 0x51b74252, 0xcac6c490, 0x5b1a0f03, 0x8c1fd348, + 0x930d9396, 0x545241e7, 0xc42e8d0b, 0xb5940457, 0x0aa6c721, 0x4edfa299, 0xa2a490b1, 0x6ee61a5d, + 0xc00c2f25, 0x9af41f6a, 0xd28f6994, 0x38929505, 0xdc20809c, 0xd9d03790, 0x306bf56e, 0xcfe0ae06, + 0x3441cd4e, 0x5f364550, 0x0927fe91, 0x3dd5deb3, 0x95f71217, 0xfe7f5750, 0xd579385c, 0x969e43bd, + 0x75c56a1c, 0x73517c03, 0xc905d41e, 0x404d809b, 0x0318b5e4, 0x165b8882, 0x72b41a1c, 0xaf4d95c5, + 0x330f37f9, 0x0f140773, 0x2e30e13f, 0x3cd8ab19, 0x40b4c9b3, 0xa7fda22d, 0xc7e952c4, 0xc30990ca, + 0x4e859264, 0xbdf46075, 0xf80b4fc8, 0xabd72b1c, 0xe33ba658, 0x14cf2a69, 0x71e1607e, 0xfc5f75b2, + 0x0d907e3e, 0xf46c0e6e, 0xced011eb, 0x6f8a1810, 0x0a940714, 0xa561401e, 0x31b8c85c, 0xbe0bb9dc, + 0x41adf532, 0xbfd0d933, 0x3b4b5431, 0x35748baf, 0x33a6f9bb, 0xa831812b, 0xf40a3292, 0xbfe2c418, + 0xc5c2ab93, 0x411a85bf, 0xdc0fc76d, 0x028909c1, 0xdd533f75, 0xe006d093, 0xef526997, 0x69c16ae2, + 0x8ca7b67a, 0xaff417bf, 0xc1c5cc28, 0xfc6fd851, 0x1bbe3885, 0xb77f3139, 0xa8079bd1, 0x47c39aaa, + 0x86820c45, 0x0de3b9c3, 0xe7b80c0f, 0xf7998472, 0x4437c205, 0x0b9c783e, 0x3565d50f, 0x6c354df4, + 0x7206ae2c, 0xcfa39257, 0x5a76615e, 0x85e58078, 0xd09ebe62, 0xc6725ee2, 0x5ec332c4, 0x00e5fbc5, + 0xe58e9dff, 0xa2d791d4, 0x0ef62664, 0xcb83374d, 0x22296ec9, 0x2bf60da0, 0x2322c0fc, 0x1f7494cb, + 0x2095c24b, 0x7ad02703, 0x2cb1b0d4, 0x07a0ffa6, 0x6baad211, 0xb5bd9d34, 0x2b02ae27, 0x776d0510, + 0x4db0e84a, 0x908ea803, 0x1bccf9a9, 0xa6c31afc, 0xb53d124c, 0x9fb2e1b5, 0x613c149a, 0xa9d42bee, + 0xc2289dac, 0xacbf9502, 0xfea09375, 0xd5b1b854, 0x67de2158, 0x265391ff, 0xe4465ff3, 0x98abcb3a, + 0x30a9e5c9, 0x5d6406a8, 0xefc5ce84, 0x61f6edae, 0x57fb6316, 0x8fe73fc5, 0x366d9f9a, 0xaa490301, + 0xe332c534, 0x044db87b, 0xe4603053, 0xa05a00f8, 0x223233f0, 0xb862976f, 0xa87f500d, 0x76c131f1, + 0xfd884e7e, 0x87130b70, 0xbe2a1cc4, 0xd943125e, 0x81bca21f, 0x31bf7fd8, 0x88efe4ff, 0xcfa556cc, + 0x76760b34, 0xf237c316, 0xbcaabd0c, 0x0a692e35, 0x00342071, 0xcca280d1, 0x0daaa20b, 0x27a876b0, + 0x08ff242f, 0xd44bc221, 0x1ef5db5c, 0x2bd2c78f, 0x25e2a8b1, 0x22355283, 0x7ad03a9d, 0x6405a9b7, + 0xe6d9fe05, 0xd19637e9, 0xcb4ac3a5, 0xf2c959de, 0x65adf2b8, 0xd0dad37d, 0xafa1a877, 0xd809e417, + 0x0a0757ec, 0x21a2b2dd, 0xce15c5d9, 0x20b5389c, 0x7888357d, 0x68e6a14a, 0xaf0489d5, 0x3d62d6cc, + 0xa20fb609, 0x6e69679b, 0xee3d175f, 0x30a7f901, 0x945f21f3, 0xda72978f, 0xda0a9c32, 0xd7c0d8b1, + 0x3a082dc0, 0x56829fe2, 0x7a1a3277, 0xa6db4294, 0x2f5c4c93, 0x64d26103, 0x40dc3762, 0x7373e9fb, + 0xf78bec21, 0x6696478c, 0x8b1fb1af, 0xe629517e, 0xf8a026fa, 0x838861c7, 0xbcfd6f6a, 0x877b4963, + 0xfeb279d0, 0xf0bc921f, 0x9880ba57, 0x4d9dba6c, 0x53cd6974, 0xe787be07, 0x80fbf442, 0xae5728d2, + 0x8c12a7d4, 0xbb314733, 0xa8daaae9, 0x227bbf73, 0xa3280585, 0x6a80f7ac, 0x4f56c7b5, 0x219a3cb5, + 0x5ef17208, 0x8f17ef5c, 0xa173d841, 0xe7c5bfd0, 0x420748dd, 0xc190fb0d, 0x4b841ccd, 0x33783c86, + 0x698bbcf2, 0x3c821552, 0x5867583e, 0x7d02521b, 0x6ad588fb, 0x710901df, 0xcf018f1e, 0x973522f1, + 0xdcd8b77b, 0xd7e3c22f, 0x5c92864c, 0x0b4ad9c2, 0x3de2ad83, 0xd6f2a0c6, 0xaf01e5e2, 0x30df6f69, + 0x354e6d65, 0x0d8cce61, 0x05c307aa, 0xb5f82457, 0x1019d1c0, 0xf361f354, 0xfe07047a, 0x39d57ae5, + 0x3218f220, 0x307d83a8, 0x82cb5131, 0x15c8d739, 0x574fdd25, 0x8372848d, 0x15007746, 0x53ba5177, + 0xb1889f83, 0xd5bbde48, 0x07b974ef, 0xfa0db9ae, 0x1a6bd396, 0x9c566758, 0xf5f340ec, 0xf146581b, + 0x7370d394, 0x0fea65f8, 0x11b54e6e, 0xf5b5ad5f, 0xcc4df8d3, 0x9af7ebdd, 0x93a27061, 0x318073b0, + 0x04373a71, 0xdc19bcad, 0xe70ff276, 0x1381f8e8, 0xd6a63e0b, 0x2a65fef4, 0x86ff6973, 0x7dd8a0b8, + 0x4c34d694, 0x11ae64bb, 0x839db200, 0xc3e20c97, 0x8721cd0c, 0x8be021a2, 0x40665415, 0xb75c30e6, + 0x33592e3b, 0xf93dae0b, 0xdfac228a, 0xe3294df9, 0xfa8a2781, 0x7c6791dd, 0xcf943448, 0x6d85ccb9, + 0x05e5ee19, 0x382d6ac4, 0x52f707d3, 0xcc84babb, 0xa021b1a5, 0x215f55b2, 0x57fbe905, 0x2b4b72b3, + 0x5387fb6f, 0x85e28baa, 0x9fb8b3a1, 0x930c0c64, 0x443c9f24, 0x581e46b0, 0xe08d318f, 0x6d871c4c, + 0x8d7dfe6c, 0x6566cfbc, 0x9b38cb9c, 0x8fc58857, 0xea17c509, 0xd4938dfe, 0xb1d1ce80, 0x72c0f40c, + 0x4ed145a4, 0xdef3019d, 0xd421e747, 0x803d4a00, 0xcce6b905, 0xa65aedc0, 0x123b331e, 0xea51069a, + 0xee08fc6d, 0xd9e3cfaa, 0x5d7cc3e3, 0xd14e3ef9, 0x2e2c539f, 0xe490beac, 0x29a484dd, 0x969d7fda, + 0x3f56c410, 0x525c88fd, 0xa87eb903, 0x6a5eb779, 0x61ce81fc, 0x395788f6, 0xd60e01eb, 0xf10512d1, + 0x0238c967, 0x2715d44f, 0x2ed2f242, 0x56833dfb, 0x6bc4d36a, 0x35cf0f15, 0xc9d5286f, 0xa48f7e76, + 0x2a018ca9, 0xed439a35, 0xcf3eca9d, 0xe81faa27, 0x4a20e01f, 0x79144495, 0xead4dded, 0x0039f365, + 0x1271d57a, 0xa6a2dea6, 0x16d217aa, 0x80e33cff, 0x27dd9277, 0x98db126f, 0xc854f468, 0x8940a625, + 0xd27a1697, 0xdb31468b, 0x533d5476, 0x3d5b81cc, 0xa9f513df, 0xef36b33f, 0x851ed06f, 0x09ae796b, + 0x61ad99e3, 0xff25bfec, 0x3c4c3ac5, 0x966a3160, 0x5fab6042, 0x98b41f89, 0xa3664d35, 0x9cd38fe2, + 0x42813efc, 0xb8e69528, 0x23f01030, 0x83dc15e3, 0x1c51090c, 0x080dde8b, 0x7dcff8c3, 0x5debc0b9, + 0x6e685c77, 0xdd7eb135, 0x7b9be013, 0x927e039e, 0xdb5f03e1, 0xe64bf1cc, 0x2bf16a56, 0x9f31aaf7, + 0xbfc050cd, 0xa59fe256, 0x0f18b3a9, 0xac951534, 0x4ab25383, 0xbe42912a, 0x686fd6bd, 0xa22d9c9f, + 0xa7b2f4f3, 0x8121c2f7, 0xa5d7d70b, 0x83eb922f, 0x506cb61e, 0x920936c3, 0x6a57e7ac, 0x39983533, + 0xd7a87603, 0x5e0a2a06, 0x36e1a502, 0x875f4a62, 0xc972eea4, 0x0b977543, 0xea6faa87, 0x75047722, + 0x6a6d18c5, 0xea824b24, 0x21ed508d, 0x982f0710, 0xaf0b1c1a, 0x261a76e3, 0x29a74033, 0xa920240c, + 0x878ae11f, 0x2ec0e576, 0xa7663234, 0xc357d1de, 0xc4e90a2e, 0xc15728e7, 0x74aa8a44, 0x1b0bb67a, + 0xd1895e68, 0xd38c9de6, 0xe0ef3de5, 0xb1180fb3, 0x0a75ec2b, 0x6bbd4076, 0xd5a0d1bb, 0x6756427f, + 0xf599adb4, 0xc77513e4, 0x89ffb036, 0x6c8d60fb, 0x29640247, 0xdb217402, 0xd66d476e, 0x3203cc91, + 0x877a449a, 0xf45f6b73, 0x3e0195fb, 0xc946acd3, 0x9ff44e23, 0xd127189e, 0xffea3770, 0x4023f569, + 0xe441b3d5, 0x78b791cd, 0x428a1457, 0xf97587f0, 0xfe21b3c6, 0x293aafed, 0x0295c24f, 0xf4c3a172, + 0x14926e6c, 0x38be3d05, 0x8a259084, 0x009e573b, 0x81446281, 0x80b3e7fc, 0xc318d899, 0x430dbce2, + 0x30ece5c7, 0x69d836c4, 0xa22e3161, 0xf6ab4745, 0x8d97a359, 0x80b033f6, 0xee25098c, 0x215a3d6d, + 0x1dc00cac, 0x99f68c1c, 0xd4884d5e, 0x020c32a3, 0xce8f4836, 0x8468b9d3, 0x82f9cb1a, 0xdee0da2a, + 0xea11df5a, 0x0b8277a3, 0x2c102d43, 0xe11f0568, 0xbf97c21c, 0x1df711df, 0x3c418ca2, 0x581ab7a7, + 0xe4ec4763, 0x0a479eb3, 0x7ef52fd6, 0xd4f61c6c, 0x721c6b51, 0xff78ec95, 0x133dc6ad, 0xe20e3d69, + 0xfd241228, 0x8259271a, 0x2ae29d7c, 0x7e961c5c, 0xbd6c01fd, 0x2a4eb9e9, 0x3914325b, 0x6d9359d0, + 0xad014614, 0x22adaea0, 0x26c36224, 0xd5eb25a3, 0xb9416bf3, 0xa00b7be4, 0x107c519a, 0xf1b41e75, + 0xbfb8150f, 0x1f62419c, 0x964ab2b0, 0xea2c0ce8, 0x143acafc, 0x281ff437, 0x011543c5, 0xd11b7b43, + 0x716e027a, 0x639b0bb5, 0xad442f0f, 0x24f12dd4, 0x062a975b, 0x94722898, 0xa9af8bb7, 0x1546fc33, + 0xd38bbca3, 0x0be799a5, 0x89f0ec84, 0x21fb0c95, 0xc296b4ea, 0xa5b886be, 0xfbb52ef9, 0x1eef6459, + 0xba4cb27e, 0x954cf0f2, 0x5e649f9b, 0xc2eed7bc, 0xb6cce27b, 0x8d3cc5cc, 0xd6996a1b, 0xdebd16f6, + 0xd0f57e62, 0x2845bb3d, 0x9809f5a0, 0x1b9ae655, 0xc246b6e7, 0x8ff9cf9f, 0xe3fed6c9, 0x7f5024ca, + 0xa42d8ba1, 0x3b8ed275, 0x38525376, 0x50fba58c, 0x16368ffe, 0x6d993847, 0xa8a844e0, 0x0a9047ec, + 0x81f09227, 0x5a086689, 0x86cbf0f9, 0xaa5eb56a, 0xa7ee675c, 0x98ffd58f, 0x12e22719, 0x07a5e544, + 0xbb6952ae, 0x8ee693e3, 0xa78c730f, 0xe0d59fd4, 0x5768e5b2, 0x2713b7f7, 0x807b00cf, 0xf738b508, + 0xf5074084, 0x8d379b00, 0x09fb33a7, 0xee1c835d, 0x363e95de, 0xcd43a62e, 0x4a8a7fa8, 0x3c541f95, + 0x7bba565e, 0xa75bafdb, 0xe8e9e2be, 0xc32d22b4, 0x58ccaab4, 0xb7b438c8, 0xebaa4ff1, 0x95602414, + 0xee0f2778, 0x6667505f, 0xbecd0871, 0x4cd2b4ac, 0x60487a45, 0x2f971611, 0x10fd774b, 0x00af4ef4, + 0xef1c5f25, 0x08c80f18, 0x4aeb7619, 0x52781ba6, 0x3d82af63, 0xd873c8ac, 0x25d7e90a, 0xdeda1b45, + 0xf9bd1760, 0xf8a5b9e2, 0x0fbf1c42, 0xe9f84cfb, 0x09566c9d, 0xd06c3d6d, 0xc8b0a41e, 0x8c067617, + 0x92921a8d, 0x19025bd2, 0x19a83c1d, 0x24894a5c, 0x2b121dba, 0x0fe0fc97, 0xbee961d9, 0xa43de632, + 0xded2505f, 0x80704008, 0xa2438be6, 0x8ee7e3dd, 0x9abd6905, 0x21331ae8, 0x636c5f69, 0xd88b777c, + 0x11d29abc, 0xfb813381, 0xfd379cb4, 0x8bdfa5b5, 0xb0d55d8a, 0x6dedd0ca, 0xcd23da53, 0x828ae1ee, + 0xbdfaa2dc, 0x0a0fc9b5, 0xf9fe303f, 0xd2d7fc61, 0x17fd1dda, 0xa646e2f2, 0x9afe4279, 0x0af72e6e, + 0xc17f8449, 0xf9d49f66, 0x9f3922aa, 0x79231c76, 0x8206b97a, 0x2e88e740, 0x7b3ce7d2, 0x077a9d6b, + 0xa8ab59f3, 0x3b30fe80, 0x124ba6b9, 0xf0e305dc, 0x21901d1c, 0x3af0b0ee, 0x10a7fe7d, 0xe37af6d8, + 0xef83c90f, 0xab728559, 0xcb6f0903, 0x9050fe6c, 0xdfca54e6, 0xf2543d5e, 0x8748fa4d, 0xb77bb4d2, + 0x0c96f6b4, 0x2b03cffc, 0x6735b3bd, 0xc573d392, 0xa13a880d, 0xbee552c4, 0x771e0d1d, 0xf22ad99e, + 0x1fbfa88c, 0xce8cc56e, 0xdd1fdc03, 0xd724decb, 0xff33efb6, 0x4adcc4b7, 0x216d8836, 0xf1e7ac33, + 0xf02320e7, 0x2f3dc950, 0x56447a1f, 0x5ef58b17, 0xa1864af7, 0x9f4bb7ba, 0x2f644b9e, 0x42310c74, + 0x4cf68b0b, 0x528574d9, 0x1a8f853e, 0xe9e208bf, 0x877271ad, 0xe6c8fdeb, 0xd16dfa69, 0x910d9f63, + 0x24272742, 0x69e60ed2, 0x8eaf82b0, 0xfcce376e, 0xfe1e3f57, 0xa9bbe137, 0x37012070, 0xedf99334, + 0x98806414, 0xbff6261d, 0x0ad06e36, 0x0a601bda, 0x770fd89e, 0x40a53f47, 0xea2c7976, 0xa7ef21a3, + 0x1b855a9b, 0x807b1f32, 0x07f8a434, 0xba641612, 0xdff49170, 0x12f3254a, 0xb23db57e, 0x907a72db, + 0x920e6f05, 0x5a444806, 0x4dbdbb97, 0x7c3fc341, 0x69150b22, 0xa699649e, 0x5cc6f031, 0x7346fac7, + 0xd821c845, 0xc8d0b9b6, 0xfdbfda28, 0xed8ed965, 0xdd2b094f, 0x6d319481, 0xee2a3585, 0x620253f1, + 0x5bd8e8e4, 0x14824660, 0x4d0a06f9, 0xab7ba3f5, 0xb30682b9, 0x47672241, 0x9b8c0718, 0xa02d61a0, + 0x77e66dfc, 0x49ef5ebf, 0x279cb863, 0xae82af2a, 0xa9ce6234, 0x1e835bcc, 0x798f4b9b, 0x031e67a9, + 0x37010af4, 0x6c2972b2, 0x6336be55, 0xe3e3298e, 0xc69e4193, 0xf9d8f18d, 0x0494fc69, 0x4aa53ce1, + 0x744f2e3c, 0x4787b127, 0x0749e4fc, 0xc57b0d82, 0xe238054f, 0x86394792, 0x79cb5757, 0x14379823, + 0x63f6edaf, 0x25ed8c47, 0x15afa445, 0xce31acbf, 0x30ec2913, 0xc7e1f4cc, 0xdece16de, 0x1f5a877b, + 0xe39c3169, 0x2ddb0e63, 0xa72434d0, 0x125d1253, 0x4c2d956c, 0x88110902, 0xfa3dfcb2, 0x5fe6c73b, + 0x662037c4, 0x80d5622d, 0xea9ffc85, 0x6300dbc0, 0x0bbf9504, 0x61874602, 0x4c5ae2a5, 0x1d50cb0c, + 0x73f2aea7, 0x46e06351, 0x8d4cbf5d, 0x07a7c3ad, 0xe9950b58, 0xe0f4bffa, 0xf8e6236b, 0xa088d837, + 0x89097141, 0xfbf11a2c, 0x39878085, 0xa35ce0c3, 0xe08e1e94, 0x3f96d2e9, 0xc985940a, 0xb5b1c995, + 0xbad3408c, 0xc9d5d57a, 0x371efa82, 0xac7bea83, 0xdd901416, 0xc96fb41f, 0x61968394, 0x59895225, + 0xe92ccbd4, 0x1f898e4e, 0x67c46c1c, 0x43b5da72, 0xe74d44b3, 0x842acbbe, 0x5d14f41c, 0xf6bbf730, + 0x034b2b00, 0x12dc03d4, 0x69408e88, 0x1d318625, 0x4d414e3b, 0x1751a2ec, 0x6bde6cb8, 0x3186e118, + 0x5b5530a5, 0xde6499ca, 0xec5821a1, 0x8f793e54, 0xb5ce9b30, 0x79bb950e, 0xb1108d0f, 0x0d435976, + 0x00e2db9d, 0x8df1b6f1, 0x0dcdc94c, 0x3a942e5a, 0x0afb2196, 0x08247282, 0xbecccab6, 0xfcc636ab, + 0xc3f5ed95, 0x106784e5, 0xbec70ecd, 0x80f8d19e, 0x8260b11c, 0x48dd9d7e, 0xfcf9cc51, 0xb941c97c, + 0x2ca34d86, 0xd2cc2f10, 0x6f2c172e, 0x72b964e6, 0x51f963c2, 0x77dca6bb, 0xc9661e6f, 0xb1216bac, + 0x6d1dcbc9, 0xf6e84751, 0xbdb91aea, 0x323afc6b, 0x3fe86cb9, 0xb56180c0, 0x7081d720, 0xb410bb5a, + 0x178caf40, 0xc1c3d249, 0x3d459624, 0xdb8a4214, 0x1a09bf7d, 0x62961a66, 0x1f28a224, 0xff961fcd, + 0xd40c9d06, 0xd96efee3, 0x4ac4880e, 0x791165a9, 0xae489a31, 0xb2ddeb5b, 0x29b56b76, 0x1c48407f, + 0xd967c4fa, 0xf75bc866, 0x7d147d4b, 0x69176d2a, 0x291146d6, 0xd07b2a38, 0xc335c0b2, 0xecaa5ddf, + 0x09665960, 0x80bd6fef, 0x236eb023, 0xe9afad23, 0x7a848150, 0x7905c688, 0x137543ba, 0x27f13137, + 0xb4c91532, 0xb3355a77, 0xc71157fe, 0x5b3ab19a, 0xaffce6f2, 0x6af6c9e5, 0x15c1689b, 0x92c091fd, + 0xe8dad464, 0x4819e87c, 0x6458acf4, 0x58ebbbc1, 0xd0e740b0, 0xbabde8e5, 0x405ae1d8, 0x564e7d94, + 0x2f768ac6, 0x2848d997, 0x1e33400a, 0x1b158051, 0xb499216d, 0x7acdd710, 0xd4586ba8, 0xa6858cfe, + 0x4e7eb834, 0xebf26dbf, 0x4853c495, 0x8f0f76f8, 0x67382b6b, 0x3dbf0db4, 0x709a9784, 0x9defe725, + 0x17c6402e, 0x59df1ce1, 0x34bf1473, 0x45c24b7e, 0x36dc24d7, 0x963d4162, 0xd4d1f1ee, 0xd9012504, + 0x9bd5345c, 0x4c13f296, 0x85c6f6ec, 0xf2760442, 0x7db9b82f, 0x2c11d753, 0x7f35ffa4, 0x4ff9928c, + 0x0ef697b1, 0xe49a6208, 0x684ef1fc, 0xd9b8fb69, 0x8b2d6519, 0x266d5f6a, 0xfc2b899d, 0xf2b0ab27, + 0xf6f86149, 0xddb666ce, 0x40f20960, 0x2fede7ca, 0xe2fdc0d0, 0xde857203, 0xb8aed30a, 0x2058243f, + 0x3f72e0a0, 0x7ee2e6b0, 0xd70b2aea, 0x8032c242, 0x031cc06a, 0xcb0ee9d1, 0x02eff206, 0xa3b7784a, + 0xc4be596d, 0x31b221e6, 0x93d992c6, 0xbb01c680, 0x33ed2d13, 0x22ec9a7d, 0x0c0460f0, 0xcd5ff0ad, + 0x0e59729e, 0x3e8cd300, 0x4d17c389, 0xc9f16429, 0xcd6cd68a, 0x300b9e09, 0x45640ab5, 0xce15808c, + 0x232114ba, 0x5bc4b2a6, 0xfb4ef95d, 0xccb8bc01, 0x3d0234e2, 0xd568023a, 0x19f0be25, 0x004b0a85, + 0xd82479cd, 0x2d456cdb, 0x62110d88, 0x6bcafc1e, 0x67056249, 0x02e27083, 0x79980ab9, 0x5577903d, + 0x4ddc8676, 0x9191a82b, 0x12722feb, 0x1d8d10b3, 0x4b7f4929, 0x16003a79, 0x6a65ea85, 0xcb6b5112, + 0xf01e6462, 0xd1b6dd1a, 0x015c8b73, 0x1d0e1f91, 0x696caced, 0xba1b7f81, 0x503a43f8, 0xdb6d0c5f, + 0x779b3747, 0xaac6e8ac, 0xd22f9539, 0xa7bdcc59, 0x2a678872, 0x4e964fa2, 0x32c3aa3c, 0x86471b98, + 0x139e1fe5, 0x34857034, 0xbcc9556c, 0x7b91277f, 0xedc6057e, 0x62472564, 0x8e264117, 0xfa88af90, + 0xdd3e4887, 0x88642e4f, 0xe1510a08, 0x0463d9d8, 0x6cd92917, 0xf1744d5a, 0x706e2eff, 0x66003626, + 0x6dd4f21c, 0xd924a149, 0x0bfd4a6c, 0xdf8f923b, 0x871cc0db, 0xe36f8d33, 0x185ed8a6, 0x358a29be, + 0x46cbbfa5, 0xf6b3a8e9, 0xb2ff13d5, 0xf6ed31d5, 0xa8e06efc, 0x1b143073, 0x14bf592b, 0x6223d3cf, + 0xb2923d9d, 0xf4e71291, 0xafc89fe8, 0x0ead1e7f, 0xd86cd01e, 0xb723418c, 0xee901f25, 0x6c7a76dc, + 0x9cbabf43, 0x5b26d7dc, 0x4b668b18, 0x5aa8a18e, 0xee84d6f9, 0xc395952c, 0xae246a07, 0xe89fa477, + 0xd4eb3223, 0xe18a99c0, 0x76aa153e, 0x422cbafb, 0x749a2f84, 0x625c1eb3, 0x7158fdf6, 0xb8f7458d, + 0x1b146764, 0x90773921, 0x8256d96c, 0xea280a44, 0x9a7b986a, 0x82048368, 0x2466d645, 0x73646197, + 0x23b71c36, 0x37ff9024, 0x1bdf41b3, 0xc4cca4d8, 0x5b8746ef, 0xb98498a3, 0x5464ce0f, 0xb7c0b99c, + 0xaebb32ab, 0xa820aba4, 0x1cc5d720, 0x64eda7da, 0x9d61306b, 0xfef90957, 0x4318210f, 0xa78ec676, + 0x39b1301f, 0x18b2bd77, 0x2aa57d48, 0x9d2054b7, 0x9304946a, 0x04158fe8, 0x8d5c2492, 0x8ddc1dc3, + 0x4b447645, 0x9da00842, 0x549fdf92, 0xcec310b9, 0x8a5e2363, 0xb9ba4120, 0x1151d2dd, 0x9fbda159, + 0x071a882c, 0x7a9d05f1, 0x2e8ea2a6, 0x7fe51774, 0x93a911ee, 0x68bca72e, 0xee58cb5c, 0xb152d22e, + 0xb8fa1fc8, 0x7d2a39a2, 0x2dbcd873, 0xb4d74f07, 0x8f504122, 0xa666adc9, 0xed202b33, 0xc7e40714, + 0x830e8d7d, 0x11452803, 0x8bd3a429, 0x1dbd0483, 0x06eebe2b, 0xc12fae19, 0xcf0b074e, 0x1e804282, + 0xfd1996c4, 0xf93b1aa6, 0xe99681d3, 0xcb56f3cf, 0x83a5fb58, 0xea8a7709, 0x4bb94f66, 0x5651749f, + 0x8595064a, 0xc659dd08, 0x772b3384, 0xe3f1711f, 0xd5f43368, 0x678be3e9, 0x96d6d1af, 0x915baceb, + 0xd2dcb2f5, 0x12e74f76, 0x7fd9f3d9, 0xaeba1720, 0xfb7eb2e0, 0xbaf69189, 0xc26cca1c, 0x749ed8b9, + 0x17a460cf, 0x6a7e7a83, 0xe439eac4, 0x0fcf67d9, 0x3a1113a4, 0xe0d96994, 0xe8336288, 0xdc1ddbc8, + 0x0cb9c729, 0xad642ecd, 0x537441ca, 0x604a8554, 0x84da2463, 0xea5f9f33, 0x9e1b6414, 0x5a6f2315, + 0xda368937, 0x3dd4b327, 0x955cae47, 0x3305306b, 0xc11720a7, 0x736ac6a9, 0xfa48a03b, 0x3afb698f, + 0xeef7926a, 0x5280a6ee, 0x435aeb76, 0xf1144d92, 0x512c0a67, 0xd2803469, 0x5b26b0ba, 0x65bc1d99, + 0x0775209a, 0x1e8fd076, 0x28d219c9, 0xdcc354ac, 0x099c9b11, 0x024dea07, 0x5907e574, 0xbdffe9a8, + 0x289f707c, 0xda2bd0c4, 0x36fbbed0, 0xf6aa07ad, 0x64fe7258, 0x5495daaf, 0xa2f2d14e, 0x967e9c17, + 0x4e0cbcec, 0x23591f60, 0x3edbce45, 0x233e8e6d, 0x872d22c0, 0x68865051, 0xae4b52a4, 0x006897da, + 0x840f8720, 0x67147d07, 0x627e7f9c, 0xad2767f7, 0x04fc33d3, 0xe54d147a, 0x12aa7fb2, 0x357a23df, + 0x4513d958, 0x5411d276, 0x1b9269b3, 0xf135c702, 0x9a7dfc46, 0xaa1f76be, 0x2f59de95, 0x0754921f, + 0x2f7fddd7, 0x26481fd5, 0xd4cce081, 0xec156440, 0x093eefc0, 0x2158b319, 0x435bf976, 0xcfe10202, + 0x25aac2e3, 0x3e3d45b7, 0xa479da31, 0x33071039, 0xe0d8760b, 0x74970efe, 0x6a7de4ae, 0x790f49cf, + 0xc8b8ea87, 0x1c8b4e3b, 0x1519935e, 0x97d60d43, 0x9b9f2d19, 0xec813cca, 0x23c3b54f, 0x6e36c785, + 0x32d5a814, 0x98c13e77, 0xe2222cd7, 0x0e6f73e2, 0x539dfa52, 0x8954e235, 0xcf30c262, 0x6435b47c, + 0xbe4c1195, 0xea323b7d, 0x71f45709, 0x1abdf0ba, 0xeed3da42, 0xc23f12a2, 0xc15b802a, 0xf45ebcfa, + 0xfa610ad3, 0x0c904bfd, 0xf940f76c, 0x3e217063, 0x203bbf7b, 0x16033efd, 0x8ae9c8ea, 0x85c23984, + 0x1d4f1705, 0x910f80fb, 0xa8903489, 0x7d3be2ec, 0x0d2c9c9f, 0xc26bc7f2, 0x2d4d6d96, 0x3f59e700, + 0x9a0a7aab, 0xc1b32103, 0x6fa238db, 0xf60ac3a6, 0x5737105e, 0xdf1e4f2e, 0x3ebbf047, 0x79047d90, + 0x31790ab4, 0x3abd501c, 0x98312c07, 0x283c2053, 0x4b09e111, 0x52211c36, 0x0ab0c9f1, 0x0a6f6251, + 0x534049ae, 0x1d32dae0, 0x0aec95c4, 0xd35cfe43, 0xe2f63991, 0xc10295e5, 0xda10c2d7, 0xffac39b3, + 0x16985813, 0x1f0be4fd, 0x706b01e2, 0x16d2dbe0, 0x3e8d8d47, 0x6ee06d59, 0x23c3fbb5, 0x4c24c253, + 0x259d0b18, 0xeeaccd2b, 0xa11771ac, 0x695bc145, 0xc90a7296, 0xe5d4da60, 0x7547529f, 0x0af183e0, + 0x83d565c8, 0x92695a07, 0x607404de, 0x6ad3fbb1, 0xc4128a82, 0xc94a0d86, 0x081baa9e, 0x6e9bec3b, + 0x2829915f, 0x7a4d72fa, 0xf817b3b1, 0xa1dc40ca, 0x1c6d22da, 0x9cdede22, 0x78ae6d8f, 0xe53c7eef, + 0xb89abed0, 0x62e0c1c2, 0xf25e6a33, 0xcabe5726, 0x96414ec7, 0xd3f58377, 0xcd45e97b, 0x3885ae15, + 0x56c01c07, 0x2f4b974f, 0xce2b04e4, 0xbcf735cf, 0x5f452914, 0xd857ef8f, 0x29639b18, 0x04979cfb, + 0x36029d22, 0x493c215f, 0xafa134e0, 0xf60a12ae, 0xc96d5065, 0x208d75d2, 0xa9219731, 0xd9476205, + 0x38575f56, 0x9473b7f2, 0x7cfe3f28, 0x99ce66bb, 0xb0c64772, 0x5f9fc112, 0x728544a0, 0x23b49714, + 0x80b5dc74, 0x51b972ad, 0xc4dcd247, 0x11fdf03d, 0xd59ca5c6, 0xbb57d2b4, 0x219b5a9b, 0x9a3ebd29, + 0x996147ea, 0xb8339e99, 0x027dbd72, 0x72135635, 0xeef6f72a, 0x97c18b35, 0xb4bfdad9, 0xb9f85128, + 0x1dab9872, 0xee46bb23, 0xef100fb1, 0x9bb38ed4, 0x51e6c0c6, 0xfce4a00b, 0x90cdbc0a, 0x69d334a6, + 0x190e760f, 0x5f66b8aa, 0x3e016a7b, 0x7a040404, 0x7e875575, 0x6d00b50d, 0x62f2fac9, 0x3bc52618, + 0xbca129d2, 0x349228af, 0xadcd88c6, 0x459550cf, 0xa9152fd5, 0xb2e63695, 0x66a93167, 0xe996a7ba, + 0xdf6f6f5d, 0x30493e47, 0x5610bef2, 0xd9be0cdc, 0xfbb20ac0, 0xb8976e1a, 0x1257279b, 0xf056f29b, + 0x60dd4885, 0x7027c8d4, 0x865e02fd, 0x6547d0a0, 0xccf0295a, 0xd659de41, 0xcc58e4c5, 0xcae509e4, + 0xdf189aaf, 0xdc9f42b3, 0xbb4b22ed, 0x569c632e, 0xb6a0c473, 0x5abadbc7, 0xfa135fd1, 0xc3392f6d, + 0xe097a349, 0x8900b6c5, 0xcd0e0841, 0xa4929fbf, 0xf6310fd6, 0xe3a82708, 0xc3b3d7db, 0x38b6de6d, + 0xcadf0eed, 0x318fa55e, 0x5cd882b9, 0x04f86bd4, 0xd6565641, 0xb8ecdf87, 0x677e50f0, 0x23668e8c, + 0x57d3b982, 0xcd47641a, 0x7330856e, 0x09ab6f6a, 0x07b53f65, 0x20884c8d, 0xf10ae5eb, 0x37cc282d, + 0x9d65a165, 0x8750c8e8, 0x4b2c90ad, 0xea1b1dcf, 0x6ccfd58f, 0x3d76b312, 0xc6b2960f, 0x0bf318fa, + 0x231edd49, 0xd43e6db5, 0x3417569d, 0xc1084144, 0xfc089534, 0xc9ba9534, 0x631d96da, 0xc1ae09ab, + 0xf7ff5470, 0x19a12f5a, 0x029221ee, 0xf8bf81a6, 0x37f7d18b, 0x7ffd33ee, 0xc38cb8bb, 0xf6d02f07, + 0x86917359, 0x76b1c319, 0x6b305b9f, 0x8fac2f0d, 0x14d88b6c, 0xf2467b17, 0xaab1a742, 0x5e9fb62e, + 0x06c223ff, 0xf426e65e, 0xfc1e2862, 0xb112a984, 0x05d08c67, 0x8e46d6d2, 0x83667322, 0xcf567bd9, + 0x95d7d5ad, 0x31b14452, 0xf6d396e6, 0x861bf2e0, 0xf1143c8c, 0x1254117e, 0x96dc650a, 0xdbdcc726, + 0x3bf3b704, 0x974167c6, 0x040065c9, 0x789ad8fd, 0x06b32bdf, 0xda1ddd80, 0xa20d57df, 0xb4fb8d34, + 0x6b40a63d, 0x34989ab6, 0x900cfabc, 0x4293db82, 0x5b1ee1f3, 0xa4ee269b, 0x4d437c28, 0x2fea6fa2, + 0xde745e05, 0x4e4350db, 0x34852ae8, 0x6648298e, 0xd08f686b, 0x03a78860, 0x00b613cc, 0x7a3fc50b, + 0x70eece38, 0x279a39f7, 0x076b26c5, 0x801d203d, 0x35438de7, 0xffad7c96, 0x074808f6, 0xa46207d7, + 0x84fbcedd, 0x553f1803, 0x1f1ebdd8, 0x0094ef36, 0x65423103, 0x1165404d, 0x376688cb, 0x5bfb6c73, + 0x59099fce, 0xc1d7b94a, 0x48405c21, 0x5d9a3edf, 0x9575a432, 0x5f4a5289, 0x46d314f5, 0xdc029f56, + 0x21fad65d, 0x23616ecb, 0xbf37821c, 0xb5f1e693, 0x9060b2dd, 0x90da209b, 0xec7c5ff8, 0x829a6358, + 0x2ee4b68f, 0x701a297e, 0xfaffd294, 0xcb61dcb6, 0xd0dc929b, 0x98d87ff7, 0x08d59c92, 0xc270b2a4, + 0x94662aa4, 0xffab2aa1, 0xf9dcfbce, 0x8aa82a67, 0x4cfe99ce, 0xc07a624c, 0x5eec1fda, 0x77eef984, + 0xbaa7adfb, 0x9c154b29, 0x6efbb94f, 0xa60a0fdc, 0x98e49dae, 0x28e3eaff, 0x1ac825f9, 0x7fbc42e6, + 0x4aac40c2, 0x2a52adfe, 0x50db1037, 0xc1e3424f, 0x013d336e, 0x24c11459, 0x62c97d6e, 0x3535651d, + 0x90e65a2f, 0x1a8dfd58, 0x7a5237f0, 0xe9c1759c, 0xa8f40667, 0xb662d7c4, 0x1dc92949, 0xec603397, + 0x663770d8, 0xfa0a7fe7, 0xffb7fa4d, 0xf14dc993, 0x15cf5d8e, 0x083a6505, 0x3f0f4d7a, 0xf3f8a6e7, + 0xa83b72e3, 0x72d44c79, 0xcfa9dc97, 0xd6f22b8d, 0xdd08f6ec, 0x83be842c, 0x2df57d4f, 0x91241722, + 0xdf6fff8d, 0x12ee3cba, 0x53297ce4, 0x1a94af61, 0xd4783618, 0xb1c83137, 0xd8e00782, 0x2025f5a0, + 0xa3d8efd5, 0xa771dc4f, 0x33cb25c1, 0xba7af433, 0xb3598af1, 0x3e4935ec, 0x6651d973, 0xb1e70d60, + 0x00307bb3, 0x05d375ac, 0xe50f4550, 0xfa8c1c6d, 0x0509b5d6, 0xb016c0e6, 0x9ac33da6, 0xe15ce193, + 0xe60d49ad, 0x5ab774aa, 0x236be4c8, 0xe50d5ad2, 0xf3efd687, 0x1b8e7521, 0xaa7a22f7, 0xe1c98c57, + 0xf77c770f, 0xd979e798, 0xe3716f67, 0x285ac72d, 0xbded8bd3, 0xcce2f4c1, 0x7a072ad3, 0x0070fbec, + 0x3497c4db, 0xb7714efa, 0x86ad9e81, 0x2bedf127, 0xbe10d3f7, 0xb11453d6, 0xc7a286ae, 0x0509297a, + 0x3ba6d8c9, 0x5219bf6d, 0x0eb81198, 0xaf0f65d5, 0x42f7f8a8, 0x9f75d5d6, 0x6a905ccf, 0x87d63028, + 0xc326e1d4, 0x858adf4d, 0x1f7f8209, 0x44b16496, 0xd16e9e61, 0x762e481f, 0x909d04a6, 0x68abba43, + 0x0bdeb922, 0x5c37428f, 0xab57d40c, 0x750c2199, 0x38ecf216, 0x605e08ea, 0x48fd5037, 0x30409c70, + 0x4676dfaa, 0x8ab2dd76, 0xea550cc7, 0x08cf68bf, 0xf7de1343, 0x3a447002, 0xb5c9c4a4, 0x7ea1b601, + 0xcb83bbee, 0x1b14ced5, 0xca882bf2, 0x9a95519b, 0x38003869, 0x6e391489, 0xbe209eb9, 0x38f08c7d, + 0xf66043af, 0x2067402d, 0x07faa4d8, 0xfd0b8ba8, 0xc1e1e2f2, 0xf6be9d55, 0x3ed5764a, 0xfe0bccf8, + 0x6e5e6988, 0xfce8c564, 0xece7e18e, 0xa5e6da69, 0x36cb40b5, 0x4a08ff7f, 0x3ee1e9d0, 0xae22a06b, + 0xe36aad99, 0xc6bdfa32, 0xce4809e5, 0x22c683c5, 0x415863a8, 0x6da749db, 0x1596eb19, 0x598aa38f, + 0x5f0461b6, 0xad60b8f3, 0x3d522789, 0x05da291e, 0xaf7e5053, 0xbbebca07, 0xa7d05878, 0x96334668, + 0xce2961db, 0x3ee5e6ab, 0xe284fe06, 0xb977db8a, 0x6ce5c51d, 0x871e63a4, 0x269b72c9, 0x2fb82205, + 0x784c551a, 0xc2a735a0, 0x2c3e6a25, 0x51872411, 0x0fd14459, 0xb203c536, 0x0ace2779, 0x7598ff64, + 0x2ad14cbf, 0xfa9aa15e, 0x643e2d08, 0x808532b9, 0xa6ffc174, 0xf7d1bb76, 0x48ee7b3e, 0x4f3a4495, + 0xeaf865ed, 0x735db80a, 0xc0b6ed16, 0xea73d40d, 0xe2962a2b, 0x8c9b5fd4, 0xe49edeca, 0xd19a7e02, + 0x5df7975e, 0x95562910, 0x9dfb5882, 0x4862d137, 0x09d080ea, 0xed83b774, 0x86ce6b0e, 0xc972d907, + 0x11c09d07, 0x04b4cd39, 0x5db7a996, 0x3670fd66, 0x8eb6b383, 0xc5314344, 0xfd980a3e, 0x19ac557b, + 0xe86f2224, 0xa2aef6fd, 0x90e9fa35, 0x02761803, 0x4035f097, 0x9df47cb7, 0x1574b654, 0x78779549, + 0x58c177ca, 0xb5f8d93b, 0x402cb41d, 0x2572ba2b, 0xe86ba9cb, 0x96cb4437, 0x5ff803f5, 0x8bc6c8f3, + 0x5ebed083, 0x4a716933, 0x9ce4447d, 0x76389514, 0xc7f69fe0, 0x4a050bf2, 0xb79c3d4b, 0x8878c2b1, + 0xb37352f8, 0x50ff69f1, 0x80446f80, 0xff93687a, 0x95b65ae9, 0xa5dc7678, 0x5fe9d94d, 0xff37e020, + 0x534d20aa, 0xcfaa4b98, 0x45b54e48, 0xdba3ab41, 0xef68f997, 0x12520897, 0x35e1e012, 0xbb43caac, + 0x10abafb8, 0xf0290fcd, 0x7ddb0d7b, 0x05f9a798, 0x9125a71f, 0x5d50239b, 0xa9823c6c, 0xc9c6514e, + 0xd16020db, 0x96dc0ab9, 0x428a8e17, 0x4df9d31e, 0x831365a8, 0x9bbee066, 0x62e4f45d, 0x75b0cf44, + 0x72808ee3, 0x7c89efc9, 0xeec0bd13, 0xd47113dd, 0x26f80e2b, 0x0c7fab55, 0x09b5fe13, 0x3c27c1c7, + 0xc77aaa87, 0xd35588f2, 0xb13519c9, 0x7178fd95, 0x4b3de99f, 0xcb77f9d1, 0x22c8ccdb, 0x7948ad47, + 0x27a480fd, 0x2e5aa0f7, 0x1b88a4bb, 0x88c5b6ce, 0x46265a8f, 0xe2128281, 0xfb3c313a, 0xc0185960, + 0x3b26d39a, 0xf6f95388, 0x8ae578b1, 0x54e82e61, 0xdee8efc8, 0x36414840, 0x13fb12a4, 0x4aefb244, + 0x110e34d3, 0xea50bb5f, 0xb05a557f, 0x91a813df, 0x36954166, 0x48848ac9, 0x552318ff, 0xaed710d5, + 0xaa44653f, 0x78708e6a, 0xbeeff58f, 0x65906d66, 0xba94d9a8, 0x753a79b0, 0x43dfe7c0, 0x2a0ca09c, + 0x57535191, 0x86a4a8af, 0xdd2c8bb4, 0x5d9d5515, 0x0a773672, 0xb975283f, 0x7ba6682e, 0x6b23a7b3, + 0x6df9b073, 0x62f2a96c, 0x9d570c61, 0x70f22288, 0x4c9f1262, 0xdc01bd75, 0x33e09e8b, 0xdeee287d, + 0x2d546492, 0xe002e3e1, 0xf6441403, 0xc121c781, 0x59fb67a5, 0x1dfe30ec, 0xad3e73a5, 0x06061340, + 0xa8719a10, 0x7b6d8b07, 0x79e0fd28, 0xdee801cc, 0x4391d234, 0xc2a71983, 0x63f3aa5a, 0xd8434653, + 0x670e7ef5, 0xff6f4e2e, 0xc0308aae, 0x36bb6584, 0xfd94fe21, 0xb4a35442, 0xa62c48da, 0xa36159b2, + 0x3b321ba7, 0x9fa35588, 0x61a87220, 0x86611244, 0xd13262fb, 0x0c188d53, 0x7dfffbad, 0xa179fc7d, + 0xf4e32ef6, 0x44a67154, 0x9df4bfb1, 0xa843fe04, 0x17742aa3, 0x2808e2c5, 0xd8d3fe3d, 0x6c6cf800, + 0xfac58246, 0x9214e857, 0xa19822f1, 0xc0add9a3, 0x360bc8e7, 0x6c8fabd6, 0xb8267267, 0x990dcc71, + 0xf38a0b8a, 0xbfdd6f2e, 0xdb35d402, 0x0736b1e1, 0x67740a87, 0xee2e6dd8, 0x39f1cbf4, 0xd0ea22f9, + 0xadcb7aae, 0x7f72c8e7, 0xc4896d56, 0x85da68aa, 0x3a2c6174, 0x73df378f, 0x81b85781, 0x6bdea488, + 0xe1ad8efe, 0x9e852898, 0x973dc532, 0xa2df76a2, 0x994a73e4, 0x15fb20a8, 0x1e69893a, 0x269bd77a, + 0xdcf66b73, 0x25be7c75, 0x09160bff, 0xe6a3decc, 0x46c6d99b, 0xb74488f2, 0x9733355b, 0x83d696fe, + 0x9db7e747, 0x1a208e6a, 0xcdf785b9, 0x8f71bcd4, 0xce898b5f, 0xfda1c80e, 0x604ccbb5, 0x948d80ca, + 0x6ebc7075, 0x324fecd0, 0x445d4714, 0x0099653f, 0x40e5a30b, 0xad34a0f4, 0x6ff75a06, 0x0d748b75, + 0x4a238c23, 0x9f77d021, 0x20d83a92, 0x70579c8e, 0xc8166b8d, 0x73fff21e, 0xc24de6f6, 0x8daaa819, + 0x46645fdd, 0x9cc01216, 0x052df129, 0xfe5a6647, 0xd9adea9b, 0xb79d74a8, 0xbe7d81cf, 0x14ff8888, + 0x081e12c7, 0x979c4db0, 0xcda61c63, 0xa29f128f, 0xb756e497, 0xff4bca24, 0x97e901d6, 0x46dc5a41, + 0x2845c712, 0xde5ef5ae, 0x09e623fe, 0x2aa435e3, 0x7735950b, 0x1936bfd9, 0x758d5ee8, 0x661c56b1, + 0x5d0a6c2b, 0x516e30cf, 0x26e4f617, 0x518440a4, 0x49497f63, 0x55016703, 0xb21beb95, 0xea0951b3, + 0xe0677988, 0x9cefbd54, 0xf112167f, 0x1dea686a, 0x340baf04, 0x7d311d7e, 0xe45a9b12, 0xe9e7a430, + 0xd08c650a, 0x59a4bce1, 0xdd1b3726, 0x78ee970f, 0xbe3a31dd, 0x590a5171, 0x6672aff3, 0xe43e1fa2, + 0x26d2c834, 0x7e63e429, 0x557000f4, 0x7f3b38f8, 0x06501665, 0xb436d8d4, 0xbb9e41bc, 0x7096e362, + 0xec075865, 0x0ff208ec, 0x680fcfd0, 0xf8876645, 0xdb3df728, 0x78d6893b, 0xc7149ded, 0x891f83e6, + 0x42e9e504, 0x1ab42375, 0xe30e11e8, 0xe51cb3dc, 0xefd669f8, 0x5b72023d, 0xa5b753b8, 0x5a29510e, + 0xa69f4973, 0xb8c0fb5e, 0x4113862d, 0xa74d04a5, 0x8e0d0583, 0xf9304138, 0xbb259873, 0x53d9fcf0, + 0x1f1fdc9a, 0x710266d3, 0x3e8fc5b8, 0x333269a3, 0x14a31d19, 0xe894db43, 0xa6aa3002, 0x08905ff2, + 0x1a260aab, 0x8042ef19, 0xf3e25a28, 0xc948c909, 0x4dcd60cc, 0x447ece3f, 0x40619ce6, 0x671ce31b, + 0xfb87e6bc, 0xb20464d4, 0xf3e6b9e6, 0x43b34e1b, 0xd4216c95, 0x4b9bf27d, 0xb09d1748, 0xf4c2611c, + 0xfd174026, 0xea0de3ad, 0x78308b7b, 0x1670f423, 0x8a4543be, 0x01042609, 0xb079ccfc, 0xf957937e, + 0x9ff493d8, 0x25348736, 0x7f3e4d2b, 0xd06d8452, 0xa7fc9b55, 0x357e81d7, 0xae35f16e, 0xf13a4c75, + 0x0c3eafff, 0x15111532, 0xbd07c92e, 0xb5a32d71, 0x2ea0fe04, 0x205ad43e, 0x2a3641a8, 0x3c920722, + 0x914aedf4, 0xcd80d3bb, 0xf9a73b08, 0x11107d75, 0xfadc7563, 0x662678bb, 0xfdc523ae, 0xc5d2acde, + 0x33ae6bb1, 0x04874867, 0x8864078d, 0x32ce73d1, 0x0b246ead, 0xb8fc3407, 0x06d3cff7, 0xc659f81b, + 0x8d61bc8f, 0x8f6bec0f, 0x6fdefb8e, 0xee14ccf3, 0x878ac560, 0xb79008a6, 0xc5a71487, 0x8801cd79, + 0xdd25558f, 0x13974e74, 0xb8660885, 0x42921318, 0x8765504c, 0xd9fb489b, 0x48bc0b20, 0x63c011c5, + 0x492e1b8e, 0xe8a80664, 0x99d83444, 0x93c750d6, 0x07d561c4, 0x97734d97, 0xcbe06402, 0xd22017fc, + 0xa4bae442, 0x5b250fa7, 0x09507749, 0xf7134d6e, 0xcded8884, 0x742d8fcb, 0xa107fd28, 0x1f114196, + 0x59d77daa, 0xd090e0fa, 0x03fcc739, 0x233ae09d, 0xe9838268, 0x34acbf8c, 0xa0c8f3ad, 0x873dbdbd, + 0x6e462363, 0xc9893e11, 0x7120bc66, 0xf04aeb19, 0x91124bcc, 0x4f850842, 0xed204f7f, 0x3ca8f384, + 0x679b86f5, 0x12203115, 0x2ff18350, 0x72ea5e5a, 0x78a0fc87, 0x067ce1cb, 0x9b48b718, 0x7dc968cf, + 0x26e34051, 0x3d2084f1, 0x80fb2b2c, 0x3a72ce19, 0x196ce1e4, 0x4b4f8f7b, 0x9d93ffc6, 0x0e38ada9, + 0x9caf5cd8, 0x5e286a6f, 0x12ba6cce, 0x46f8b81e, 0xf232db98, 0xeacc111b, 0x17d26b7d, 0x7df2665a, + 0xbec4b150, 0x7f1e0a35, 0x9d464dd9, 0x942ae309, 0xef33a6ba, 0xe71de527, 0xadc9f7ae, 0x9a84ce3d, + 0xf1cd6df9, 0x60b208f8, 0x82e67654, 0xe2a666e5, 0x1266e118, 0xfc295df0, 0x594cdf42, 0x06b4bfe4, + 0x733b65a4, 0x6abe8594, 0xa55e3de9, 0x01bc27d0, 0x8cf985e0, 0x609104c0, 0x46870be3, 0xa2d259fb, + 0x78368bbc, 0x795634d5, 0x7804bbc0, 0x6aafa3fe, 0xc3e0ccd4, 0x59fa8d3c, 0x8036e532, 0x19faf081, + 0x8fe0807c, 0x6d0510e8, 0x1ccc1a37, 0x1c27a948, 0xfa4ae512, 0x9dbf80b5, 0xeeb064f7, 0x93e2e093, + 0x28ccee8e, 0xfc5644db, 0x9bc7bf88, 0x61096dba, 0xc0080aab, 0x04a0c5ea, 0x576684b1, 0x843835d0, + 0xd893ce4a, 0x10a2c76e, 0xa034a5ac, 0x4f4ce9c4, 0x0471cb66, 0x8a63fb8c, 0xabd0186b, 0x527cf2c7, + 0xda378608, 0x29651a51, 0x85a96738, 0x43036175, 0xe9969b2a, 0xecf8c730, 0xaf7bf980, 0xfdf322eb, + 0x41b05462, 0x4851c608, 0xb811931b, 0x4816ed66, 0x7247aa67, 0xc67c3f8d, 0x3da40975, 0x38f9720d, + 0x0620101f, 0x53abd603, 0xc9c8db46, 0x5414fc14, 0x5da6a22e, 0xe915ee80, 0x2f0ff4e6, 0xce0be67a, + 0x71573766, 0x2299a7cc, 0x41900ea5, 0x56e43ac9, 0xc5b92db6, 0x7e14bca5, 0xa344a76b, 0x99642595, + 0xbf69a53f, 0xb7350e62, 0x806eac7a, 0x5f41dbe0, 0xda1bc23e, 0xcf7af4dd, 0x83f4c24f, 0x1b77ff63, + 0xfce4d24b, 0xe307d657, 0x8c3925a4, 0x6017ced7, 0xbb6cecc5, 0xb4daeee7, 0x689254b3, 0x5443c06c, + 0xc221aa1b, 0xcd5965b4, 0xaf23636f, 0x6bebe4aa, 0xea7e1db6, 0x41bff7dc, 0xb4462ef8, 0xc7a6a2d9, + 0x5bd47a79, 0x3a585b80, 0x515dd608, 0x8a6891f6, 0xf090d226, 0xf476bb57, 0x187da135, 0xc73c997d, + 0xde709f65, 0xc4def0ea, 0xf9f6fc3a, 0xe5656439, 0x1eeffb36, 0xd9a77e8a, 0xbbd6fe48, 0xddf0e7df, + 0x521f1a3c, 0x7085a95e, 0xd8875859, 0xed2771e9, 0x15debca5, 0xcc5419df, 0x164a9b38, 0xfc6c4702, + 0x5fbdcc69, 0x0a8e1549, 0x3859a5d2, 0x566d0aa3, 0x9fc6b7a6, 0x238f76d1, 0x522fa536, 0xbb196eff, + 0xa41825e0, 0x39c4208c, 0xb4108a28, 0x2a5b91e2, 0x2d89f739, 0x6f436cdd, 0x01d83f36, 0x1187d74d, + 0xbe5f73a3, 0xc1eb60a2, 0x86d55e4f, 0x05f49e2d, 0x6f4368c1, 0x6cfafaaf, 0x02ba35f7, 0x89984682, + 0x5dc509cb, 0xb66ed66d, 0x23342438, 0x72e271e8, 0xc11bc922, 0x81cab821, 0xb58bcb8a, 0x7e20da04, + 0x28747185, 0xa0a7e368, 0x68596097, 0xf5904500, 0xd88958cd, 0x69a52f97, 0x10d5d97a, 0x79c0070d, + 0xec7724b0, 0xda78c210, 0x5670d973, 0xce24ad25, 0xc9160342, 0xc11a0653, 0xe43452de, 0xe7491028, + 0xc0491548, 0x0c2e79ec, 0xcc0f772a, 0x8f58fe21, 0x6c3f74aa, 0x122d8f4b, 0x9ca0b146, 0x0cd0570e, + 0x9c32f3b1, 0x3f15ae68, 0x785718cd, 0xd1224b3d, 0x7e1a1572, 0xc6d94272, 0x61f9d708, 0x4383f329, + 0xa68dc449, 0xa5a42f40, 0x2b669f5d, 0xe81ed442, 0xed38bc82, 0xa1fd9ea9, 0xbb26ce85, 0x2580a84f, + 0xf14b865a, 0xe9033811, 0x1ff7c29b, 0x1c5f4812, 0x0d4f74b2, 0xa8db00de, 0x88074853, 0x10a3031b, + 0x6b6ddff2, 0x9553451e, 0xcdffc0f6, 0x5071c066, 0xaf19739b, 0x1d2ac869, 0x9fb65e09, 0x5ca259dd, + 0xd04fe883, 0x4a83c1bc, 0xac4eb3f3, 0xe6920562, 0x9721f11e, 0xc1a1576b, 0x474da758, 0x53b00aab, + 0x3f2c14db, 0x3c1e9cc0, 0xbbcba2b7, 0x66b942d7, 0x8987a45f, 0x964b6cae, 0x550cb9ff, 0x794a8bd6, + 0x28cc0916, 0xe50a15a8, 0x3944da04, 0x610d5a95, 0xb9e139da, 0xbfa0d327, 0xa037d8d0, 0xa1d5d29d, + 0x53a3d8a5, 0x2dc1a6d9, 0xa4c31c06, 0x2e6f3497, 0x9f7212f4, 0xd1d0b141, 0x4e44dd82, 0xeaa779fe, + 0x6e49a8e4, 0x3981a097, 0x4a2505d2, 0xc2f16e25, 0x74d88bc1, 0x00d0ee79, 0xcf0a0d01, 0x1cd40b45, + 0x9ca21f48, 0x6adf52f2, 0xebde7125, 0xc04abbe7, 0x5e50a4cb, 0xee5a6cd1, 0xcc08138b, 0x99fe31d4, + 0x26e231ea, 0x52c204e5, 0xdc771c48, 0xb17ce67d, 0x7dfd075b, 0xcce6a40f, 0x2fd7cb19, 0x988aa304, + 0x715203ff, 0x0884ce3d, 0xffc80637, 0xece929f8, 0x15f9b184, 0x0ab4a2d4, 0x34b62807, 0x082b1338, + 0x648c473e, 0x5afa7288, 0xbe2c3c48, 0x7213e702, 0xa22d2742, 0x5145481d, 0xc2770e73, 0xfb688a35, + 0x5af4ef70, 0x5c6035b0, 0x082e4646, 0xfa4cfa99, 0xfe5a1c31, 0xdd4c5ec6, 0x8aa52adc, 0x73051da9, + 0x9a7d8cc1, 0x4c6fa673, 0x42b93f26, 0x1ac5097d, 0xd1a91fe3, 0x6c6f3f6f, 0xce551532, 0x94fccf8f, + 0x2bbbb47a, 0xe92fefa4, 0x2d98e47b, 0x68042829, 0x6060a1c1, 0x11aad587, 0xca24f4c2, 0x59099f3a, + 0x979b8e7f, 0xe55a1eef, 0x290a9c99, 0x41d8604f, 0x5620f7ee, 0x9d0ca6ff, 0x17202707, 0xef665982, + 0xfb202c1d, 0xa3b3db9d, 0xb2ea125a, 0x7999c408, 0x095aedc1, 0x6296bfc1, 0x4593a740, 0xeee72cb7, + 0xbccb7de2, 0xde771c40, 0xd90a1b22, 0xef15e570, 0xd237cc51, 0x76aba08a, 0xf6609e3b, 0x4ccf713b, + 0xa56d3ff0, 0x2503adb4, 0xf0f20f38, 0x69331071, 0xd307dacc, 0xa59ae223, 0x72fb6616, 0x48d90c7e, + 0x13446acc, 0xc97d1585, 0x7991406d, 0x82a62a88, 0x32b9c4e5, 0xfed2dd32, 0xbf18afab, 0xea3f2a94, + 0x075f7df7, 0xd45b241f, 0x7dc0d974, 0x094c720e, 0x6d8056c8, 0xa77a931a, 0x5264e542, 0x5cbe091a, + 0x33828651, 0xef1041bb, 0xacce887f, 0x8ef47d4c, 0xe2a0cf29, 0x36f9edc6, 0xca51a82a, 0xe2ee01f0, + 0x80b9a55d, 0x2bee0e2a, 0x2d409380, 0xb9a3c1c6, 0x7aef3ed1, 0x76ade345, 0x3aee9bb9, 0x69ea1ecb, + 0x57b3e9f5, 0x1dbe0ab8, 0xcaba6335, 0xc46392b8, 0xff1d021a, 0xcbc2d5ca, 0x62efe6a6, 0x60d6067f, + 0x01fe292f, 0xd78d3214, 0x407d0a57, 0xe3712935, 0xa29145d5, 0x4cd40ddc, 0x159ed283, 0x5502cf50, + 0x8452b3f4, 0x9d9511ab, 0x38dfc307, 0x97d9b097, 0x0e612678, 0x54f6f8c4, 0x80088e70, 0xbc13cda7, + 0x1a141a25, 0x99b33b18, 0x45c206b7, 0x683ad0f4, 0x30d445a8, 0x78c39a16, 0xa0e06b38, 0x9d454c8f, + 0x322b8d8c, 0x209c0019, 0xea64bc83, 0x1fa1ab0a, 0x0025af88, 0x906ec1f5, 0x14c97e16, 0xa0f3d231, + 0xcf824a69, 0xaabd36e6, 0x96f61dee, 0x337fc56f, 0xf08d334c, 0xea72c1a7, 0x5534b1cb, 0xc82f653a, + 0x712f6ebb, 0xbfe066d9, 0xd6f177b9, 0xb9c57231, 0x4700f65f, 0x51f8d9e0, 0x6bed97f4, 0xe7323e2d, + 0x0ec8b90d, 0x37bfdb9a, 0x17d3449d, 0x78f91d6a, 0xea532752, 0x3b949c3e, 0x74953c29, 0xde5c4367, + 0x2288f349, 0x9092ae6b, 0x7596568e, 0x996102fa, 0x1f38e062, 0xca18fd2a, 0xa1c14d30, 0xefcf6342, + 0x7be88f20, 0xe055da3a, 0x705378a8, 0xef8f45a0, 0x2078540f, 0x229a8fc8, 0x1e5412e3, 0xc2fff048, + 0xda3babbd, 0xfa738e99, 0xb8849429, 0x77644c49, 0x549d1b04, 0x8f84835e, 0x42f2db4d, 0x31296239, + 0xb1f74d52, 0xbcda0fd5, 0x925e4d29, 0x8e8d1f99, 0xbf1959f4, 0x2431cdab, 0x28229e97, 0x7f675953, + 0xc3ccd3bf, 0x182cab85, 0x45e60116, 0xcb05408b, 0x5affe37e, 0x1179e4f9, 0x9939107d, 0x7f3eafed, + 0xf73b0714, 0x9eba430e, 0x8c34a881, 0x1559d5bb, 0xbefc0e95, 0xabc3f506, 0x38788cce, 0xdb409843, + 0x09d2b95e, 0xc623b119, 0x8404f82f, 0x3d05fffa, 0x400e14a0, 0xa2e308f1, 0x99d4ccc3, 0x5836179d, + 0x0d1046dc, 0x93c479ed, 0x9dfb6933, 0x3e59ad2c, 0xf0d1254b, 0x4a478d31, 0xbca40b7a, 0x751f2dcb, + 0x07705bd0, 0x98e0082f, 0x2b0fecfa, 0x54170858, 0x495ede2f, 0x9fd3ed86, 0xf2c94e0a, 0x55703149, + 0xb439ed7b, 0xfbd46ecd, 0x0bb91972, 0x5a7a5ac5, 0xf4dcb02f, 0x63a12ca6, 0x6d906436, 0xeebf9780, + 0x8a1f164e, 0x913b45ba, 0x07cf816b, 0x466a33f4, 0xd30ae8ae, 0x2d8bb8f8, 0x93ba1600, 0x0ffaf9d8, + 0x08a63650, 0x1d51c4af, 0xecb2b75c, 0x4175503f, 0x3da5b150, 0x0ba5df1d, 0x396155ae, 0xb0e3bcd0, + 0xe9b5d6e6, 0x5712e7af, 0xd46d0b56, 0x9d877304, 0x5e713059, 0xda9cb336, 0x7d34ff51, 0x09b4e23d, + 0x37a54e00, 0x67912ef7, 0x51dad3a3, 0xd9f2e722, 0xb0f71799, 0x9df5532f, 0xe819ddf0, 0x05e13936, + 0xcb35470f, 0x0c471323, 0x51eeca51, 0x154ac859, 0xc118d4f2, 0x4302601f, 0x5260448f, 0x3d419cb2, + 0xd3ac278b, 0xded84b5f, 0xbd4f91fb, 0xc0a955ad, 0x21fa381c, 0xeb90d8e8, 0x49137916, 0xa318a656, + 0xc6a8fa7f, 0x5c17a263, 0x32bd17f3, 0x78bf5c84, 0x2d5d582b, 0x47a9d68b, 0x1bc68edc, 0xba74bbf1, + 0x8b93d305, 0x0c91aece, 0xd4435bdd, 0x7578223e, 0xd91265de, 0x7f9ae885, 0x765bfaab, 0xfa9ecb15, + 0x1324154d, 0x18990d9a, 0x9fcecf9b, 0x7fc90f1b, 0x9308383e, 0xfae74a0a, 0xbd9edf0b, 0x291acff7, + 0xc8f9d77d, 0xb9e49285, 0x1c425e9a, 0x455f1ecf, 0xa5fe0072, 0xa8387bb6, 0x0bf818c7, 0xaaef88a7, + 0xe8fa1ec9, 0xd49c6fbb, 0xd901bd0b, 0x73e13151, 0x2e42fc19, 0x003cc75e, 0x49077e20, 0x2e5a0b3c, + 0x130407b9, 0x8e75e638, 0x784f6f99, 0x40e09a02, 0x7ed0b545, 0xde2526c1, 0xff4bd95b, 0xa1bdc212, + 0x50453ad8, 0xc358f89b, 0x71cee706, 0x09217096, 0xf3da1db8, 0x1e0534e4, 0xa6f747e0, 0xcff4a84e, + 0x65b535f7, 0x8d6ac2c4, 0x8dc429b3, 0xb88750b4, 0x01a0c34c, 0xe0d0cf56, 0x31ded423, 0x409d7710, + 0xce6fdfce, 0xac2c7989, 0x5cad2867, 0x9ddf8e5e, 0x541d7c87, 0xfb067b3a, 0x78396f1d, 0xe437e3c5, + 0xab50f20f, 0x8a9b4232, 0xe866ace8, 0x7a622c4a, 0x62dded8d, 0xbff4d16c, 0xd2ed309d, 0x07c83a88, + 0xe707ea31, 0xf496e774, 0xa2eb8489, 0x9ac87ac5, 0x0b9db121, 0x811c880c, 0xceca9d20, 0x9ce796c3, + 0x3172ba3c, 0xf9874f49, 0x39310e5c, 0x55583ea6, 0xb15ab3f6, 0xb442b32c, 0xd5356053, 0xe4cb5b86, + 0xabb73c9f, 0x4818f9f2, 0x3e36314a, 0x978b6506, 0xe3d8b504, 0xb4f317a8, 0xf4e37a3a, 0x9b798fda, + 0x9e63d41a, 0xbc564b45, 0xcb0a9056, 0x2d8652ff, 0xf9761e7b, 0x4baed26e, 0xe2d6fd6c, 0xf5a1d04a, + 0xab142146, 0x1ad7082d, 0x69e13c86, 0x3e7228d8, 0x253f3820, 0x863f6eec, 0x21485e6b, 0xf23919de, + 0x4ec615b3, 0x12d18d1a, 0xc1e3f9c2, 0xbd7fa9f6, 0xe7240d0c, 0xbfed9fd8, 0x83e32f21, 0xe2ec67c3, + 0xe7da9e17, 0x87796d7c, 0x2cf13756, 0x3bdd892b, 0xecd02976, 0x3658b74a, 0x28de5436, 0xce6e67ae, + 0xcabe613c, 0x2ffc231c, 0x67e2a4d2, 0xf237ef3f, 0x0ab0d1a4, 0x433685e6, 0xb939a37b, 0x6acb87cb, + 0xb1716bac, 0x5f49466c, 0x947ef66d, 0xe093207e, 0x70741730, 0x8f800bb0, 0xbd7f74eb, 0xe6adc86d, + 0xd20a1c6a, 0x77c010c7, 0x455bd4c5, 0xeca04c82, 0xa18287a7, 0x788cdf21, 0x46426fe3, 0x229e6356, + 0x1ec436b9, 0x8e95bec3, 0xf4129cba, 0x97e4f9bd, 0x5bf54845, 0x6071a51c, 0x4a902a10, 0x27b40492, + 0xd70f5145, 0x1e4927c7, 0x1994ea45, 0x90aa6d81, 0x5ffe971c, 0xf018817b, 0x78dddf48, 0xb8bae009, + 0x98834b7e, 0x75eb65b5, 0x3a2530bc, 0x9da66111, 0x27ea8091, 0x43cc89ad, 0x1cbbff56, 0x44ed5cf5, + 0x9707cc34, 0x99572b0c, 0x2d6bf18e, 0x3070f404, 0x946012a0, 0x2be560c6, 0x378a5891, 0x2c3ae64c, + 0x7721b1ea, 0xed872bb7, 0xf137fffd, 0xf4bc22b4, 0xa47d54ba, 0xc83c4666, 0x0e7bc809, 0xd828528d, + 0x982ec3ad, 0x3db646ed, 0xd3ab0b24, 0x7db3c7f0, 0x56e5041f, 0x4fbd34eb, 0xeed3f066, 0x5cb409e7, + 0x8d90ef75, 0x00477b03, 0x95b46ead, 0xd4d35eb2, 0x8c48fe22, 0xf746472a, 0xd3f39926, 0x4a72104f, + 0xbaa4187c, 0x34605228, 0x25abbc01, 0x4265e466, 0x31f58b15, 0x06b9482d, 0xc7822d54, 0x5de116ec, + 0x0ea9e4ca, 0xe9982654, 0x7f70e303, 0x68ae78a9, 0xd7808cde, 0xef169a08, 0x67e75c32, 0xef17021a, + 0x9d8d3390, 0x76f56f9c, 0xd0cfe2f1, 0x823be019, 0x52323294, 0xd24815f2, 0xd1c689ad, 0xbf13e665, + 0xea9cc930, 0x0bca945f, 0x92f6a2d4, 0xa5d7084e, 0xd07dbbbc, 0x7242673c, 0xb3d036e2, 0xda87edb2, + 0x9abce44f, 0x3534123c, 0x1991af80, 0x531a69f7, 0x01c91e6a, 0xcd526606, 0x2772fd65, 0xdfb17a2a, + 0x5a09c8fd, 0x7262168f, 0x22f6f5c3, 0x6bb200bf, 0x773838a1, 0xea9c4ff0, 0x8cb06242, 0xef590eb7, + 0xe23ea5d8, 0x4adf46a2, 0x6afc6a84, 0xc04f15ce, 0xaf1073f8, 0x8decbe17, 0x2ebe7031, 0xb5072e82, + 0x2d8e648e, 0xb9a776e5, 0xab8ba0e1, 0xe3765da5, 0x7eef96de, 0xe51272fb, 0x7775bfdf, 0xc3968b04, + 0x03358596, 0x287ada86, 0x92100464, 0xb510a0dc, 0xe63557e7, 0x10a465b1, 0x3f09f314, 0x2e9326d2, + 0x5c13cd95, 0xc33599cd, 0x74ecd4dd, 0x8fd5bac4, 0x294c56d3, 0x0d87fe2b, 0xfb5235de, 0x734d9752, + 0xff411d4c, 0x134917c1, 0x169d201c, 0x45e7453f, 0x2f6e12e1, 0xeedfe70c, 0x76730ac0, 0x863370e3, + 0x7397c29e, 0x7f783bbf, 0xe540266b, 0x0a671470, 0x5f3319e2, 0xaa914166, 0x55bdb884, 0xe152891b, + 0xf32d3892, 0x1c66f758, 0x97aa59f9, 0x52222504, 0xf890f3c3, 0x6240ce01, 0xe5293fdd, 0x8312260f, + 0x733d3d25, 0xa43bb964, 0x8df60975, 0x37f80ee2, 0x2da8e36f, 0x805e323e, 0x0fd4c17c, 0x7ff6c3fb, + 0x82d3007f, 0xd533116c, 0xd60b86c2, 0xa7ba3a4e, 0x1afa3020, 0x0f0dd7f2, 0xa7fdfa8d, 0xd8987c48, + 0xc9df2371, 0x17e8ad91, 0xd1e94608, 0x4d34d4d6, 0x66811cdb, 0x305e8732, 0xf86b3694, 0x157f8ab0, + 0xb9d67c21, 0x2a0ec1fb, 0x6135bbcf, 0x7aece38f, 0x62424073, 0xdc7ec496, 0x603a02c0, 0x7f3dcf09, + 0x2d9f5578, 0x91e7c00b, 0xc5619507, 0xb63fe537, 0xae87eeac, 0xeefc2563, 0x9de358fa, 0x07862997, + 0x609d183f, 0xb95dc334, 0x4375061d, 0xcee03653, 0xccaa3e57, 0x18b1a5df, 0x97849d12, 0x72af02ad, + 0x0c0f65eb, 0xd9cc6163, 0xc17d4627, 0xfe0ea1d9, 0xaa94d2f3, 0xd69e2071, 0x161170fe, 0x03773082, + 0xe3815abe, 0xbd516a15, 0xa355be6f, 0xa98e576f, 0x57e3e359, 0x9da05a94, 0xb395ec66, 0xce50164a, + 0xd1eb3928, 0xce9ed320, 0x422273c4, 0xb4c339da, 0x25952abf, 0x0e850f7f, 0x9ab5bca8, 0x2ec85d38, + 0xeedfe839, 0x06a2f022, 0x0c3112f9, 0xa2dcc472, 0x5c7a2604, 0x6e555f5a, 0xf29d8145, 0x5c9ad712, + 0x25bde493, 0xa06d7c6b, 0x706d8c2c, 0xc48eb960, 0xf8829209, 0xc1185c5c, 0xcbebd5ec, 0xc41e3f7c, + 0x736f056b, 0x7f8ff44b, 0x5835fbda, 0x81fa94b0, 0x27941ccd, 0x42d32a71, 0x190c8485, 0x0b924f67, + 0x320f2029, 0x3a07fbb1, 0xcf49c180, 0x411e7cde, 0x9d583a98, 0xdf38ef71, 0xdf2e70d2, 0x32f42251, + 0xeb9c0949, 0x0c4a2470, 0xe5f7cb89, 0x2bb64f6d, 0xf6f09894, 0x2da3d35b, 0xf5ec15a4, 0x523cb7d5, + 0x18e7c6d6, 0x1171da5c, 0xa4a58404, 0xf703bf2c, 0x8c316235, 0xb71d6962, 0xe617d535, 0xfb21abbd, + 0x31f50fc3, 0xaaa1920a, 0x142bea52, 0x14477bc2, 0x0dd1ce02, 0xe436f69d, 0x2b3b06f9, 0x2f433e56, + 0x84b5d34b, 0x72d869c9, 0xf33757b8, 0xa03d3206, 0x9f09be7f, 0x97a1c08d, 0xe443b2c7, 0x71c254c9, + 0x97eb5bd2, 0xcedf9c9c, 0x5a679c14, 0x945da5fa, 0x64f76824, 0x763d670e, 0x1b4d335b, 0xe7b5c9da, + 0x07fbdb79, 0x21178673, 0xe91794d9, 0x3d549b58, 0x8bea5298, 0x302193ff, 0x941dfa5e, 0x4bb6a617, + 0x93060f36, 0xbc97548a, 0xfc576f8b, 0x8a646d2c, 0x1eafc738, 0xfa0e95c0, 0xf03f1b6b, 0x19a00eef, + 0xbc44fd4e, 0x20a388a0, 0x920b14af, 0x4a35ffa0, 0xe5f6d6bc, 0x06acc293, 0xe75cc754, 0x4e937329, + 0x7e87354c, 0x69682de1, 0x43864d7b, 0xec6f9afa, 0x75ecc685, 0x2f555af1, 0x8f52e9b2, 0x6dae4d26, + 0x748a7e0a, 0xbfe37bae, 0x775e7a03, 0x1ad778ba, 0x9ef47f22, 0x3d6201a5, 0x64e7d146, 0x29a205cd, + 0x25e9a0af, 0x658fd1d2, 0x5820a82c, 0x881c6452, 0x4a6c89fc, 0x76347739, 0xf45f4d1b, 0xda04a6f2, + 0xe9efb2d7, 0x8f83d3a5, 0xfdc18db7, 0x3c104c81, 0x4ddb0491, 0x2d05b163, 0xb8f92576, 0x64119fed, + 0x951eb1af, 0x6664fd82, 0xcc3b7cda, 0x5f259e25, 0x2021eb6a, 0x8e96741b, 0xd2b74916, 0x4b535f8d, + 0x8690b18f, 0x296a2a62, 0xc1979d4b, 0xf1fbe82d, 0xb1b409b4, 0xc926fe38, 0xe7961ef1, 0xf7cc997c, + 0xdf62dae2, 0x1b4ac093, 0x34f2ab57, 0xa3d8188f, 0xa2552553, 0x9346d9bc, 0x80af39b7, 0x9a61d68a, + 0x9e5e4f42, 0x0efbba00, 0x5f2179d4, 0xd4edd0c9, 0xd1db10ca, 0x60b291b0, 0x9e533cd3, 0xde6577ed, + 0xcb24f7b5, 0x7b073819, 0x3d5453bd, 0x3c7b55d6, 0xc9880008, 0xc8ab85fc, 0x75f833da, 0x83c26cb6, + 0xb3a77f96, 0xc0e3d881, 0xb002faf2, 0xe77b3fb1, 0x0ebff428, 0xbda6acbc, 0x8c25be3d, 0x55104beb, + 0x9e4dc1ea, 0xca01d2c7, 0x339f29a9, 0xdf5a7995, 0xbb3c3912, 0x35b113e0, 0xe52ae7da, 0x57c3d243, + 0x15ba467a, 0x8eeb6050, 0x583df4e8, 0x10b0bb16, 0x56596003, 0x24f83499, 0x7b9c48b4, 0x6ec4e999, + 0x5acf46b1, 0x57348c3b, 0x77436a90, 0xc7ee99ed, 0x0fb96f1d, 0x5fcaee00, 0xd8984da0, 0xb9b8204e, + 0xf91edc33, 0x30d4888a, 0x30bad49f, 0x38559836, 0x9b9bd383, 0xc9378718, 0x9194c37d, 0xb66eb4b9, + 0x5fbba198, 0x58387315, 0x84b45f4e, 0x98ab8cab, 0x423f4645, 0x34e363f2, 0x93154b36, 0x4e038c11, + 0xf9d425a9, 0x0859c2cd, 0x2b759abb, 0x2a0ce651, 0x03c1a808, 0xe8c55edc, 0x89a5cbf3, 0x4b124dae, + 0x804ea623, 0xcf3e7794, 0xcb6cbef8, 0x687d3651, 0xc627a1eb, 0xf00c5d97, 0xc429dfc7, 0x7fa22261, + 0x708c89e9, 0x8f91399f, 0x0039f804, 0x02c937a9, 0x6575c4aa, 0x8f71d26c, 0xaf9a1aa5, 0xd186525d, + 0xead28b77, 0xdc76f3c0, 0xec1c430e, 0xd86df4a3, 0x45a2a9d1, 0x4e70ecaa, 0x754977a6, 0x65f6be06, + 0xebc79993, 0x77cf2a49, 0xc1d6e58b, 0xe8f9cc4c, 0x4da1aa4f, 0x10e1a21c, 0x5820e43e, 0x15646165, + 0x007bc6e0, 0x2e81f62c, 0x6f71218d, 0xbcddf084, 0xabf748cc, 0xd5c5dd7f, 0xecd9079c, 0x0c8afb18, + 0x2b9ba39a, 0x54247ec2, 0xc67c753e, 0xea43a9be, 0x975a036a, 0x720c0107, 0xda5eb2b1, 0xf102a632, + 0x97a8eb94, 0xe006f8cd, 0x28a20076, 0x1eca99ff, 0x0f83925f, 0x522bbfc9, 0x4561516b, 0xa8909ffc, + 0x3ee17625, 0x50c45daf, 0xbbd82dc7, 0xecc3cc9b, 0xc1d7a604, 0xd2bae17a, 0xffcd84e1, 0x8b2eb542, + 0xb48fc2b3, 0x77302824, 0x72783b57, 0xd8409073, 0x3d5c8326, 0xc4c66fff, 0xe5575d05, 0xeb2820aa, + 0x90a14f88, 0x1555cff7, 0x1fbb0916, 0x13d511a8, 0x293af4e1, 0x14a9d038, 0xfbe72283, 0x7fb4614e, + 0x531293f6, 0x7895dac1, 0x7fd3f65f, 0x3487084e, 0x34657d15, 0x4e4e76b1, 0xd747da0b, 0xd5a9c075, + 0x0f11546e, 0x55483732, 0x9b7683fc, 0x5cd028c4, 0x9267778d, 0x7e05c957, 0x7f0144e5, 0x8214134e, + 0x57004388, 0x42fd6621, 0xdcde3745, 0xe19a0ffe, 0x81b5ca8b, 0xa7c85150, 0x55aa49b3, 0xee137d8e, + 0x7e4cb28a, 0x347b193b, 0x28748aae, 0x06ab43b2, 0x11c1bf0b, 0x584152f3, 0x4133adea, 0xcc77a87b, + 0xb2fd5ae9, 0x798628e5, 0xbb19fa84, 0x5b033ec3, 0xffac9455, 0xd0d8b193, 0x753cb383, 0x4c4ea3b1, + 0xf29d11d9, 0x4d823585, 0x4158bb5a, 0x2c7759d7, 0x99f3d827, 0xa2a36efc, 0xff2a0124, 0x8581828c, + 0xb5b62889, 0x0b63e0f7, 0xc3db0050, 0x8d2a098a, 0xbc8710d4, 0x5a847e67, 0x3b74994b, 0x5e10ae03, + 0xcdf3d897, 0x604f8478, 0x2e51e3af, 0x3bcf40ac, 0x777d4db1, 0x2cf19535, 0x5fa86f23, 0xe354188d, + 0x3d407f85, 0xd48cf589, 0xee47b3c5, 0x0fe7fe04, 0xe41b4838, 0x50beaf08, 0xd47d56f4, 0xd44546f6, + 0x5b7a1e0e, 0xfa9b03d9, 0x4f26f720, 0xd137ba6c, 0x0189d8bb, 0x047c68d0, 0x9b2ba709, 0x5d3a056d, + 0x1efe7852, 0x31284c13, 0x08a39f59, 0x271d3585, 0xa72a654b, 0x8dd625bf, 0xb5b4a419, 0xa44892ff, + 0xa3271acb, 0x27fd144a, 0x551df23b, 0xda583ea3, 0x0737edf1, 0x4dd0c119, 0xa60689aa, 0xb35a76b8, + 0x224ad5bf, 0xb19ac549, 0x11f12bf0, 0x1bea75cf, 0x409d8a8f, 0x600d04af, 0xde65464f, 0x0c5b4f24, + 0x2d68b2f8, 0x91283e60, 0xfa530e2b, 0x9d96da84, 0x15275f5e, 0x6eeb289b, 0xf2ed0e82, 0x859ac3bc, + 0xb5f232e1, 0x55583f90, 0x6e2befef, 0x7df72e69, 0x6d775075, 0xc07ed1f8, 0xca892157, 0x43eb8901, + 0x7ff35d0d, 0x7e381b60, 0xcd48af69, 0x6ed5285b, 0xe5e4f52e, 0x37e56934, 0x65466bf7, 0x8981263f, + 0xdb036e23, 0x15ed8dcf, 0xbdae20e9, 0x36eee12f, 0x558fe769, 0xf97354e8, 0x9d261003, 0x6c8a2287, + 0x22841473, 0x75410223, 0xd3c28a84, 0x1207b549, 0x9eecbd2a, 0xbcaf4951, 0x0e2682dc, 0xe13a48fa, + 0x898bdcc7, 0x4b56b7bc, 0xc2f94612, 0xc82e9e7b, 0x97302451, 0x04b5a7bc, 0x546f768d, 0x2a5a5216, + 0x1e6bf18f, 0x14659edb, 0x0a4b22fa, 0x9ef21be0, 0x87e90e40, 0x1fd5f5dc, 0x5bfc6908, 0x59eedd05, + 0x8373adee, 0xfe2228b0, 0x2b61e8cf, 0x3aa886e8, 0xcf300753, 0xd06027d1, 0x93834ddb, 0xf5c5fb28, + 0xee275a8d, 0x6df9ae36, 0x46ebdfe1, 0xb425d9c4, 0xd12e733d, 0x04053773, 0x427c2523, 0xf36f4787, + 0x7d8d2ecc, 0x57ced52c, 0x5718d3cb, 0x55225be0, 0x8a5dd2e6, 0xfe93d7df, 0x4d186816, 0x95d10ba8, + 0xbbc92266, 0x6cc6d30e, 0x97c8fb94, 0xd6984506, 0xfaf5a844, 0x91f9d106, 0xa548be15, 0x7de7cc79, + 0x1f18cdbd, 0x1fa0fa65, 0x503ed8be, 0xcc0d7619, 0x6588d9f3, 0x3bc000f8, 0x513753fa, 0x33a28430, + 0xff45f183, 0xf03fa068, 0x7e878c7f, 0x868ee0ad, 0xc944dbc9, 0x71c51cb1, 0xd2a37bcf, 0xfb995289, + 0x7d69af4c, 0x0b1c808d, 0xc50e2564, 0xb20fcc8d, 0x9bdb4f2f, 0x149fe264, 0x4439e5cc, 0xf104b557, + 0x09261aa3, 0x026c7840, 0x72c9b31d, 0x3101a40b, 0x48d01500, 0x18dd6f97, 0x2fc36a17, 0x24010704, + 0x39f23b11, 0x23641bf6, 0x57892935, 0xa04aa78e, 0x61ac13aa, 0xde3aa082, 0xb862dbb5, 0x099adda2, + 0xc2b06d17, 0xace77c0e, 0x9df14ad0, 0x62e9e558, 0xc85a1642, 0xf3745bc8, 0x95780b09, 0x3f620e64, + 0xd0b88dd5, 0x7f57e70e, 0xe70fed74, 0xb5919f2a, 0xcbce8ba5, 0xffa689ab, 0x0d4c580d, 0x78860a65, + 0xd23fbb89, 0xf6ae50d1, 0x18247fa5, 0x3f626814, 0x502bdd76, 0x2fbac7a2, 0x955dfab2, 0x88866d5e, + 0x4352f4e1, 0xf50b0632, 0xc94da7f0, 0xad051e67, 0x33e49c31, 0x978881ef, 0xb4fd070a, 0x441bd912, + 0x409913fe, 0xa8565699, 0x8a366501, 0xacbd26b9, 0xf79ee47a, 0x9923e259, 0x37d83308, 0x84831de6, + 0x9984f109, 0xca1b7a27, 0xa97f3ade, 0x0c8a36b8, 0xfcdd8ea4, 0x7738ce9e, 0xa7a68c50, 0x490ee216, + 0xd237894f, 0x3c27369b, 0x3778e87f, 0xdea41c67, 0x2f711441, 0x857d62bf, 0xc6b09cec, 0xe44d093c, + 0x930cdb18, 0xdcb1e98e, 0xc1bc518b, 0xe607cbf8, 0x185396c0, 0x4e58f586, 0x967f8c45, 0xf148d5c8, + 0x17d49963, 0x199d8979, 0xb73a5739, 0x93723802, 0x8aaa2a05, 0x1ab877ee, 0xe41db53e, 0x0d448f4d, + 0x0618003f, 0x6760554f, 0xea76dd37, 0xf16fb1ff, 0x6957bbe8, 0xaf2b796a, 0x979cef23, 0x7fed06af, + 0x3aeebba2, 0x837f2de0, 0xe12722c1, 0x7707da34, 0x1bfe2e64, 0xe5d5c8c4, 0xa66f0ed4, 0xca4eaa5a, + 0xbf86b00c, 0xc7cc0c9b, 0x1f53a612, 0x8ce2523e, 0xbe0ed7ee, 0xc0167fd8, 0xc1f9e328, 0xa88da0ac, + 0x3bea4050, 0x7b47997e, 0x2ca83f8e, 0x35e4731a, 0x1cb70b37, 0x23c919ed, 0x939f0091, 0x899d83b9, + 0xe093f033, 0x2388481d, 0xfe34a7c8, 0x7ed1591a, 0x1ca6df92, 0xdb33ea05, 0x22df439d, 0x8eb0065a, + 0x004d3399, 0xa72c07cf, 0xa812a93f, 0x6f37816a, 0x9fe8a556, 0xc162ea62, 0x42e7178e, 0x09c899ef, + 0xd275739c, 0xeefec834, 0x70e9a327, 0x23ef52c2, 0x7e112be2, 0xf11cde78, 0x212c7765, 0x09d8a1ef, + 0xfc168bfb, 0x74849263, 0x9460b68c, 0xcbda5962, 0xe5995e9f, 0x3a279dff, 0x75c7497e, 0x2f672123, + 0xb679db4a, 0xf9485a9b, 0x1a1d3e0c, 0xa19fd570, 0xe9da05f3, 0x756bd45a, 0xb720e99f, 0x07c870aa, + 0x68c8e263, 0xe39880bf, 0x59827ef1, 0x66b13d0e, 0xc5d32d85, 0xaa4e5cd7, 0x20c21368, 0xba8d05b8, + 0xf7ef45b2, 0x13568e0d, 0x7c9235d5, 0xd51d71f9, 0x1a32d79f, 0xdfa61aab, 0x9f96aa4b, 0x2e05ea2b, + 0x63c7c761, 0xefbaf53c, 0xbfeeb772, 0x4db15698, 0xcd7ef6aa, 0xf05b1d7e, 0x95dcd0b6, 0x506d1555, + 0x90a18f6f, 0xc231def4, 0xd93312aa, 0xfb336de9, 0x9981e8ce, 0xd96627fc, 0x508d246d, 0x4e70c321, + 0xc5dd0196, 0x43bd1851, 0x842b611e, 0x69c447df, 0x0b9a099b, 0xf6f92db0, 0xa4e70b85, 0x63bb12f8, + 0xc47ba03c, 0x4ac05b1c, 0x22bbd2a9, 0x836db01b, 0xc01d95cd, 0xfc509995, 0x90835919, 0x41207345, + 0x18147b10, 0xe28d8270, 0x376bd38b, 0xbe42f31b, 0x91a79cf7, 0x6d3180e8, 0xa7638322, 0xd2bfe9b3, + 0x4a2c3ba3, 0xd07c5e74, 0xe9fb94f4, 0xb5aa3a10, 0xf52f6be0, 0xbac4912e, 0xdb727f29, 0x0beecc73, + 0xbda9eee5, 0xe6809994, 0x0c34ff86, 0xe0d78faf, 0xe074569b, 0x6628b975, 0x65c7d577, 0x883f6080, + 0x5b76c5c2, 0xe14a8ce6, 0xd9f58b40, 0xed988975, 0xed6199a4, 0x9533ac7e, 0xbb306b96, 0x21dc7a7b, + 0x82aa1880, 0x17a84cc4, 0x1480e304, 0x1a3ee1e1, 0xd160412e, 0x02c8a2db, 0x229aef22, 0x0c65cf3d, + 0xdb5b7795, 0x98cd4561, 0x66e9eb3f, 0x2126179b, 0x79af3451, 0xfee89856, 0x1c8b9f28, 0x5a2ebb43, + 0x91156d44, 0x8bb9652f, 0xd3655a6b, 0x03b0b2d8, 0x1a19421f, 0xdc8d512a, 0x2e41da74, 0x215def3f, + 0x4f7fdec9, 0x3d40e5f0, 0x19ffd11f, 0x464ef9f8, 0xd3a9f9da, 0x39f9c86e, 0xc3f4beec, 0xe0fa7822, + 0x5a737081, 0x4ae84952, 0xf74749a4, 0x3bdfcb4b, 0xe8414aaf, 0x580a7360, 0x91726b98, 0xde14c721, + 0x3d75016a, 0x45cea84b, 0x74850c26, 0xa1d7fac2, 0x1e30d60e, 0x03706335, 0x9f4e426b, 0xec49b2c7, + 0x1b4bf035, 0x3c6e5478, 0xbcc7c36e, 0x7923e562, 0xfdd267fc, 0x5cb64e86, 0xba9542a6, 0x5304e321, + 0xe32ba3f4, 0xb075525d, 0xba6e5c6c, 0x61ddf598, 0x4002d85f, 0x0861c258, 0x6d23485f, 0x779f61c5, + 0x8857c3cb, 0x409f4155, 0xb06261d3, 0x51318543, 0x0657b0ce, 0x43256844, 0x5e5b623c, 0x4671bcd1, + 0x82aa39d2, 0x7aeedd22, 0xbf3c8f5b, 0xc5bb790b, 0x35c27ba2, 0x37573906, 0x70753a34, 0xe52744f1, + 0xe6395286, 0x377ff25a, 0xbccdda23, 0xa059f564, 0x61d696a1, 0xcf92e9d7, 0xcfd2437b, 0x1da2ea9d, + 0x2346aa7c, 0xd54aa0d0, 0x0cf3d940, 0x6d13c8bb, 0x61ec5aed, 0xaf6ec2d7, 0x94517300, 0xb9d0d3e6, + 0xbc3b463b, 0x767da39f, 0xbede3f7c, 0x3202dae9, 0x53b52940, 0x9c1cc8cf, 0x902677d2, 0x349686d0, + 0x5c01fe98, 0x03a70f57, 0x4fd05665, 0x34839c5d, 0x5cb05a11, 0x1baf1141, 0x1dfd6a07, 0x87151c1c, + 0x33e0817b, 0xf313072f, 0x60bdcb5d, 0xcb92b935, 0x152b8ffd, 0x5729aba4, 0xc761d098, 0xb6bd8391, + 0x9dc9736d, 0xc5d2ce1a, 0x6e1ce2a2, 0xe51014c7, 0xb12b17ba, 0xaf9c8193, 0x567bbf20, 0xafa4a02f, + 0x3515f113, 0xb29f331f, 0xfdc190fd, 0x8bceca14, 0x842cc277, 0xa20b022b, 0x3d38a7b3, 0x1bc65744, + 0x02da5308, 0xd7f1a468, 0xac077eab, 0xaedfd306, 0x705163ea, 0x276403b1, 0xf94f4ec4, 0xd18b8c0d, + 0x867649ee, 0x632f5b9e, 0xd412275a, 0x79ebc7d3, 0xfdcb965a, 0x65dd5143, 0xedbcac4c, 0x469302c6, + 0xe723a2a3, 0xccb0a0f7, 0xb7275e6f, 0x997f81f3, 0xc3175489, 0xb1276d1d, 0x4a90f0e3, 0x271af2e3, + 0x4baed99a, 0xc9b3641e, 0xf291ee1f, 0x193b4f68, 0x62913ccc, 0x67034bb1, 0x46d80df3, 0x0b0d1ba6, + 0xba6ae2eb, 0x1cc5e54f, 0xa469b187, 0xd6dd0c8d, 0x3a660cc2, 0xb17b5597, 0x49b6595e, 0x342fc7c9, + 0x22b60fdf, 0x6015ca72, 0x784bdbe0, 0x15583187, 0xfbc25eda, 0x324339ac, 0x4698ce07, 0x0e547311, + 0x4c4a8aaa, 0xccf237fa, 0x1b9ae056, 0xde96acca, 0xf36c4f64, 0xffdd3bcf, 0x5973609f, 0x46afef65, + 0x8b1a542c, 0x969d5dbc, 0x46c954db, 0xe5e7d91c, 0x28e93f01, 0x88681751, 0xc671b340, 0x64dadbeb, + 0x123db5f9, 0x494bc290, 0xa42c64e0, 0xfb37fd12, 0x9e4ac0a2, 0x53620a29, 0xe4c6d121, 0xf0c0e81f, + 0x3e79d39c, 0xf042601a, 0x84a2a039, 0x67d53d81, 0x98c0c6e5, 0x1fed0b7d, 0x9130ba5f, 0x180571ab, + 0x7f484a92, 0xed321ce0, 0x03671d89, 0x9104de2a, 0x926a60fb, 0x833b205a, 0xcea4cde0, 0x94175367, + 0x55615727, 0x0e92d24b, 0xf01a16cc, 0x908e3af9, 0xef239fe8, 0x4f118bb5, 0xa3b82f69, 0xff45d97a, + 0x2bce5d82, 0x39a87ccb, 0xd3325853, 0x93796b7f, 0x834fc032, 0x0f0a3766, 0xc5d16af9, 0xb61b4971, + 0xf82f658f, 0x55ff703b, 0x8934047f, 0xdea617be, 0x467d61fb, 0x945c2ee0, 0xae9ae79f, 0x5f6aef33, + 0x8d1a6fcc, 0xa69b270c, 0x99c1e826, 0x64d2dddd, 0x7d15a265, 0xfb75ddbc, 0xdd876581, 0x25ce7573, + 0x936bc250, 0xe1e2be94, 0xd58b692d, 0x048fd167, 0xb535e11f, 0xf330cf20, 0xfbd1d154, 0xee3e2300, + 0x65915510, 0x9006e0da, 0xc0326ae9, 0x29a3883a, 0x66376729, 0x537a83ec, 0x7100f1d2, 0x27c3cb14, + 0xb153d8df, 0x09a020ee, 0xf92dcc9a, 0x39d96929, 0x77a232e9, 0xeabee87e, 0xf05a7143, 0x7623f882, + 0x48b7d387, 0x314e0331, 0x07a102bd, 0x11a64482, 0x788ab284, 0xeb498feb, 0x457a934b, 0xeb819f58, + 0xca4e9ba1, 0xe06e8430, 0x68f12332, 0x7cca10a5, 0xf4e6f790, 0xa626a79d, 0xdb72655f, 0x5e6b9094, + 0x9e004b50, 0xde453d36, 0x51cf88e8, 0x1c596a62, 0x1a75d201, 0x6fd97deb, 0x1efb3825, 0x0d9d728c, + 0xb08251fb, 0x80f34220, 0x2eb6b71c, 0xba8e9d96, 0x0b818e04, 0xbc3058a7, 0xf1785f5a, 0x9837d2de, + 0xfd8eff97, 0xbbe6a1ec, 0x79d5d149, 0xc425fa0e, 0x5e92d836, 0x7dc96794, 0x06d2cd2e, 0x54b52861, + 0x1f9ad6d7, 0xabbb9db1, 0xcecc69b9, 0x58a27028, 0x9958937f, 0x3232f135, 0x1cc0c463, 0x0e69caee, + 0x7e0aec33, 0x5e7addb8, 0xfa0bbe98, 0xca0527df, 0x54b2a16d, 0xcf9d33c7, 0xec8493d0, 0x2611a93d, + 0x180d2b14, 0x86c95ff7, 0x8f0a5b81, 0x7a96ec38, 0xb1f2c415, 0x261d8f8b, 0x9ab57cf6, 0x7b8878f1, + 0xf850fa23, 0x6f7cb763, 0xd7d05cfc, 0xe49e202f, 0xbf77d037, 0xa9616e60, 0x6a96383f, 0x32d8454a, + 0xed4ccfa8, 0xcdbd626f, 0xde5e0997, 0x9822c685, 0x8fd0c3a2, 0xf145494a, 0x5e707c00, 0xe0aac1b9, + 0xde983837, 0xd635061c, 0xb3d8e95e, 0x9089bc6b, 0xfe356105, 0xbe238d09, 0xbad66df0, 0x45dc7dd9, + 0xa8b74de1, 0x83bc723c, 0x463c45b0, 0x8562ab8d, 0x4ca6cd00, 0xa5b04713, 0x84296e97, 0x1da35913, + 0x0bc0e8c3, 0xc5655f60, 0xfdf247ef, 0xfc98d1b9, 0xb2187a7b, 0xf8db5514, 0x93b618e2, 0x1c4fbbab, + 0x6b4c78d3, 0x766fd55e, 0x5479a766, 0xde4ed5f3, 0x64052ac6, 0x4de5c262, 0x73d0b010, 0xfa12d70c, + 0xa33a9384, 0xf33de3c4, 0xb6e5fbd7, 0x6088c136, 0xdec76def, 0x48f5b679, 0xc83e9627, 0xfe4cb9d2, + 0x42d77c1f, 0xe6fb2a29, 0x5e7577f5, 0x7078e725, 0xd013561e, 0xbf63f52d, 0x695025ba, 0x601b31e3, + 0x000d5146, 0x6ed29172, 0xb5336741, 0x6c3c9777, 0xcd2904e2, 0xf4e58ef5, 0x5e1483b1, 0x94cf88f8, + 0x40a531c2, 0x3f71bd8d, 0x574264ae, 0xd6c2a677, 0x08727fee, 0xd36505a8, 0x574b724e, 0x4f6be2f7, + 0xb4e93ed2, 0xe27092a1, 0x700455a0, 0xb59c1ba5, 0x27cb3116, 0x5c48e7a8, 0xcf7f524d, 0xa07d3863, + 0xacd1f41a, 0xd7ba1f5e, 0x6fb2bebc, 0xb80b76c5, 0xbb65432e, 0xb2039611, 0x9448c11f, 0xddc5e96c, + 0x41c5951b, 0x2af3156e, 0xf1df9f69, 0xad93dfc0, 0x616a1032, 0x1796aac1, 0xed93289e, 0x12393d43, + 0xc43ab06c, 0x07654e44, 0x228e8ea5, 0xe97aeed8, 0x4f915fa0, 0x9a157b85, 0xbe987021, 0x5aa682e8, + 0xa591c08a, 0x1f44e9f0, 0x0ee189d8, 0x39036384, 0x415eb521, 0xaf91e3ba, 0xc29b3713, 0x3a122843, + 0x1ff025dd, 0x1a433cae, 0xd0a53368, 0x98b44e6a, 0xf9c9bc89, 0x5b6e2560, 0x05ab2f4b, 0xbd70e511, + 0xda6a6fe0, 0x9a854bc2, 0x2f993c9d, 0xda035e87, 0x97f6c34a, 0x9395756d, 0x73df3889, 0x82c11f78, + 0x37fcbec1, 0xec4f7664, 0x7bfdf688, 0x1eaf3efe, 0x3293fbb9, 0x17d0a1a8, 0x114b5075, 0x5b9c493b, + 0xcbf94407, 0x966f67b7, 0x4395f3dc, 0x684032ac, 0xdf43eb47, 0x2181eb2b, 0x7209aeed, 0x96a57a65, + 0xfc1821f7, 0xf0ec6458, 0xbd3ed48c, 0x749724e7, 0x51a5d42c, 0xb55083ee, 0x09abb272, 0x8f4a5928, + 0x57b59ebc, 0xb32cd09f, 0x83c9200f, 0x83631464, 0xadd903db, 0xffd4c9ef, 0xd79ef793, 0x6f21cc24, + 0x74395497, 0xbf8c2b40, 0x65226b79, 0x1d202444, 0xd145bd0a, 0x24559b47, 0x801f8e36, 0x38e2fb39, + 0x3514299a, 0x73365dcb, 0x18ff1e19, 0xb789dd39, 0xcc80e51f, 0x0e0e300a, 0x2a88cf5d, 0x16a63f92, + 0x8364ad93, 0x7a5cd2e4, 0x5983dd4e, 0x67bed846, 0x351a969f, 0xe7830e05, 0xe4f21e32, 0x4222e71e, + 0x9b84213e, 0x03b33d0e, 0x5ed985ab, 0xca91b256, 0x5e1ef0d7, 0x1d67288c, 0x62fabc6c, 0xf9e54a2b, + 0x3365f7e1, 0xfbea007f, 0x7895a792, 0xe7d2691e, 0x9c99cc67, 0xb05b3188, 0xd61a8157, 0xfb544514, + 0x19087dd3, 0x31235dd9, 0x4337d3b1, 0x997d5406, 0xf1e049ad, 0xc7d6f59b, 0xbb5d14fc, 0x7811cb94, + 0x654cf4b1, 0xd3a6661d, 0x9c6e076f, 0x430b6b76, 0x1b85b4b2, 0x3891bcde, 0x8d71ef14, 0xc544ea03, + 0xd584e187, 0xe8d6793b, 0x238bf7bd, 0x1e349065, 0x97e92769, 0x2c0cb65b, 0xc8de14ba, 0xd2bcb080, + 0xa5565251, 0x049bd686, 0x9680d79d, 0xe4a4d2d3, 0x3623627c, 0x803b4695, 0xf2a8927b, 0x363ce2ca, + 0x224588e1, 0x76401269, 0xfd572866, 0x7fe26018, 0xee57a37a, 0x793a48eb, 0xa88c48b9, 0x0a9e290b, + 0xcf4517a2, 0xa84ccb69, 0x40dd81f8, 0xebd6eb51, 0xa9321913, 0xb4a584c3, 0xb1170dc6, 0x89cdf079, + 0x80ded362, 0xb5b92a71, 0x15a21cbc, 0x28a1bd19, 0x5eb659a9, 0x289872ab, 0xd8f5ec8d, 0xcfbb97cf, + 0xd7a77436, 0xddd96717, 0x50d0b0f3, 0x6ba682f1, 0xb3b78fb5, 0xcd984285, 0x789b79eb, 0xee3dabf9, + 0xf14886ac, 0x967b5dfb, 0x842a3e1a, 0xe01bc8a4, 0x9bc61442, 0x3bfd0abf, 0x7e64b3a4, 0xf3b395bf, + 0x7fa7efc4, 0x8241fb82, 0x6e8664d4, 0x7e809921, 0x750a7695, 0x9e4c4b43, 0x4c8d4496, 0xab8441da, + 0x7a2725d3, 0x4ddc2004, 0x70c16bae, 0xc46a794f, 0xd8ab4856, 0x93a279b4, 0x6efaa491, 0x56f4f8db, + 0xc9164be1, 0x4b862080, 0x450cfcf4, 0x777aecb7, 0xb8070d80, 0xc14c09b7, 0xf4d8fcff, 0x9fd0d22e, + 0xf30af24f, 0xe4d3dc91, 0xaea25a3c, 0xf5b76729, 0x68b9c981, 0xad42cf45, 0xbfff8c09, 0x4af38601, + 0x73e2cd2b, 0x60811a99, 0x0f1af700, 0x13bdd6ae, 0x1bab5d43, 0x241b6d1f, 0x40756d2d, 0x2596c74f, + 0xed4fd5f1, 0x0a202048, 0x8e3d31e0, 0x6b9c6d43, 0x74d55a13, 0x76a47583, 0xce9e95b2, 0xa1f7f9fe, + 0xab907dd0, 0xa72e99a2, 0xadf51823, 0x0cb87b50, 0x60f06158, 0x24f3f84e, 0xf52504fd, 0x3af24dc7, + 0x5bb298be, 0x618049ae, 0x1e4e5c52, 0xd90e94d1, 0x32ed8a45, 0xab511177, 0xccd39aa7, 0xca85dbf2, + 0x32c8db77, 0x3c436835, 0xe4dfe182, 0x2118b133, 0x8904436b, 0xc568b32e, 0x5f99670c, 0xc7c1f05e, + 0x5dfbd60c, 0x4fbef4f8, 0x514a4cac, 0xba208c9a, 0x96a488cd, 0xf78f4fb8, 0x78dfc50c, 0x45e8b876, + 0x7d60e363, 0x2998e084, 0xf993283b, 0x3b1f7308, 0x16aaa1ed, 0x15d41ed9, 0x888d6e13, 0x74e0af4a, + 0xe9dd45ee, 0x4bcd24b0, 0x54027008, 0x24b4b2a5, 0xde092c2f, 0x2ca6f209, 0xf3e34ae3, 0xc37dc5db, + 0x44686a17, 0x927b3eae, 0x19eb399e, 0xb666afe8, 0x3dd58288, 0x55d69d71, 0x3a5c609c, 0x937f0988, + 0x7f5f1612, 0x4ddcbb90, 0xaf83583c, 0x13860b93, 0x1bfe29f1, 0x9e9e88e0, 0x48d7db00, 0x5d62e0fe, + 0x446e12ff, 0x310c59f5, 0x8341a966, 0x10f601f3, 0xb12d14b4, 0xdcd0307d, 0xc589c92c, 0x6ce3f055, + 0xb889816d, 0xb3c00d65, 0x13f249a7, 0xddc4dec7, 0xd8d472a9, 0x0a1932d7, 0xde6b1883, 0xa38a2a0f, + 0x81d0dcff, 0xd8c994c2, 0x8b05de95, 0xa00eb736, 0xe502b03d, 0xae01ff89, 0x9e3f70ef, 0x4deb1c7e, + 0xc8bc8641, 0xbbe7dc8e, 0x129af587, 0xf8cbc838, 0x2412a344, 0xe851fe66, 0x6bc83ceb, 0x60113e55, + 0x609197f9, 0x42864aea, 0xd00861ab, 0x414ca918, 0x0a904d01, 0x91e05402, 0xfcbc4569, 0xa81ebf96, + 0xdf314b25, 0x38d72d2c, 0x3418488a, 0xd9024644, 0x942db4bd, 0x2195e5e4, 0x1c6233f8, 0x3181908e, + 0x09b5fe3c, 0xba4aa7d7, 0x943ca338, 0xcc709ef8, 0xbbc4c48c, 0x57c2d5c8, 0x6823f38d, 0xae8cc6e6, + 0xeea7cf1f, 0xb0e676c2, 0x53adeec9, 0xec2b40dc, 0x314d0ae5, 0xba2d667c, 0xadf7ae7d, 0x48983eaa, + 0x08502d0f, 0xee71c2a6, 0xc39fc0d4, 0xfe9a5a58, 0x04c06638, 0xcb22c9e2, 0xb678b389, 0x6fc790f8, + 0x55b035cf, 0x6f966b6f, 0x49cc65ea, 0x826cc842, 0x3d7a14e7, 0x19c64760, 0x27daf341, 0xba63667a, + 0x88a7198e, 0x2b0dd089, 0xed6131a0, 0xd98c41f8, 0xddf86019, 0x9da8c446, 0x23e48507, 0x06437419, + 0x3ef84975, 0x33cc4212, 0xd4efc047, 0x79546688, 0x4bf1bba6, 0xdc9ec165, 0x0ddf945d, 0xc412b4f0, + 0x2bb30620, 0x8768fced, 0x3f62d7d8, 0x31747544, 0xd59875a3, 0x9589d3dd, 0xc9bc5ed4, 0x7a1eb1b6, + 0x7cc82bc3, 0x3b72ec24, 0xb509d82e, 0x6d9db0c1, 0xc813505d, 0x94a26a13, 0xd7b93e2b, 0xeee958c0, + 0xb0254d56, 0xafbe536b, 0xed9f4bc8, 0xe89fdbb7, 0xa0592393, 0x11cf2712, 0x3206c4af, 0x3d4a8cb4, + 0xe42b1b2b, 0x36a7e736, 0x23b231de, 0x5dd3fb0d, 0x7ef2e3d0, 0x9c74e545, 0x1a85ed41, 0xbf19ef4a, + 0x7e315f5c, 0x58676bf4, 0xed37b974, 0x7d6254fd, 0x7baf6081, 0x1b4370e3, 0x4fbd413e, 0x34c9e6a3, + 0xabaa3178, 0x6453407a, 0x8ae2d00f, 0xb7ad9aa0, 0x1a0c4205, 0x2c3d8465, 0x73799ae6, 0x15a504c0, + 0x67d9bab9, 0xb424dc8b, 0xbc4cd11e, 0x1a477439, 0xefee6d58, 0xc2017250, 0x9916e48e, 0x0c4c2955, + 0x06be0dc7, 0xb148df1c, 0xa6f5c4df, 0x158ad58f, 0xfcb2e30b, 0xed6e9a0a, 0x4a44fb49, 0x8336d2d0, + 0xd9ddd61d, 0x46764d6a, 0x1be5d176, 0xd3b27b88, 0xb3b1575a, 0xda31566b, 0x8a115712, 0xa32bac5d, + 0x49c7e899, 0x4a6cfd5e, 0x79a34dee, 0xf8dc1e33, 0x999e56f1, 0xd14f0df3, 0x4197993a, 0xb39f5c8f, + 0xd27ef21e, 0xf8955a6f, 0x7cff4ea8, 0xb2f9f0eb, 0xb5a2de97, 0x5c69dbf4, 0x99c6c577, 0x4eebbf15, + 0x472c4496, 0x65de494f, 0xb11cb1b6, 0xd02cf91d, 0xf3218e0f, 0xc201e799, 0x1f930c2b, 0xf68d7b18, + 0x8bd2d2b9, 0x294f8926, 0xfdcaf0a3, 0x42931fc0, 0xa45d4de3, 0xf6db2b94, 0x79621a43, 0xc6b2e946, + 0x003aab01, 0xfd8beb57, 0xcd7d61a1, 0xbc3622e2, 0x70e2a235, 0x5d112a0b, 0x00347f7c, 0x18179b19, + 0xa8e18268, 0xeadf41fd, 0xa4a8940e, 0x6843a9ba, 0x5764db84, 0xe4547cd5, 0x3347bae7, 0xcf914e56, + 0x79e5a32c, 0xa33b6183, 0xbf63f1e8, 0xbf29641d, 0x4ff02548, 0xeb514a35, 0x70bfbcf1, 0x790f67b7, + 0xcc5c5bdc, 0x19ae4141, 0xfbb0a794, 0x7ef54dba, 0x81580d9c, 0x94350358, 0xa49e3c43, 0xb87b2192, + 0x6b47b98e, 0x45adf418, 0x987c6cda, 0xda659202, 0xde27f10c, 0x144f7d33, 0xfbdfb312, 0xcde254a8, + 0x75017175, 0x72bec2ae, 0xa5bbeb71, 0x84865310, 0x0502895a, 0xe10a6f32, 0x49d9b54f, 0x26be6c98, + 0xb0b860b4, 0x34186ab7, 0xa2bba1e0, 0xeef6d927, 0x41bd0004, 0x7bf046c9, 0xad81b9f7, 0x894ad1dd, + 0xef445b09, 0x9f3d1fd7, 0xb9a77e65, 0xa4e96d5b, 0x152789df, 0xbee77ae3, 0x37558079, 0x258db0cd, + 0xd3c4f0b2, 0xa2db1594, 0x81404c2a, 0x79c14193, 0x742a2a9e, 0x1267e6a3, 0xe45c5799, 0xe7169162, + 0xb89a0952, 0xc4e026d4, 0x25d65ed4, 0xd06db62c, 0x637c743b, 0x0063ed44, 0xd682f0f1, 0xb911c88f, + 0xdcb4d37a, 0xafbbee83, 0x41777517, 0x46b91443, 0x78d21ca4, 0x69ce8887, 0x95f17d95, 0xab05bb1f, + 0x02874f36, 0xe22bb9e4, 0xab96f717, 0x5e09ee68, 0xfae21a81, 0xea14b855, 0xa1a88d46, 0x547ad758, + 0xe1a51568, 0x971a2ef7, 0xb9fca511, 0x75f4c97a, 0xc35d58e8, 0xd2cb3244, 0xa57688f7, 0xae51a171, + 0x2fe98c9c, 0x3110c625, 0xb40a2ee5, 0xc430472c, 0x95cdf844, 0xda565900, 0x6c994501, 0x1ed20a47, + 0x8629fd0c, 0xe918a2d5, 0x1971c2bc, 0x47fdd74c, 0x4b1dd58e, 0x2d969d87, 0xae4839b7, 0x440b7089, + 0x4751ed1f, 0xbb2b738d, 0xe2739c46, 0x0fae3639, 0x8e4aeaa3, 0x2b51af1a, 0xd5dc050a, 0x3d0bbc59, + 0xde18dfc7, 0xfb52495e, 0xa5ac9872, 0x2acac249, 0xa4a909be, 0xa2a7d933, 0x45ed215a, 0x97755a0c, + 0x72710a98, 0x2dfd533c, 0x3528bbff, 0x5f3eca74, 0x347becff, 0x12e585e8, 0x6f88ed3a, 0x30e9b705, + 0x6d67e842, 0xd5657292, 0x4571df71, 0xe7538ae3, 0xf69ce26b, 0x96c773d5, 0xe502e6fb, 0x53045136, + 0xc731b4bd, 0xfe559019, 0xa5ddcb1e, 0x87e4740e, 0xb049beb5, 0x1d8e7f2c, 0xc2708141, 0x76ee981d, + 0x6231d701, 0x3d786e3f, 0x79a6c995, 0xd99f61d0, 0x6ed64d07, 0xdfc386cb, 0x7469d0d0, 0x0da17990, + 0x83d8f115, 0xc0c65395, 0xdcf0553f, 0x14c999ab, 0x56490f36, 0x9451b251, 0xefe0fd49, 0xfecad78e, + 0x88870982, 0xf184bfe7, 0xc129b3a7, 0xc86621da, 0x6f6ebe50, 0xba9a7d89, 0x4f7e0153, 0x875d134d, + 0xfb9582e3, 0x03b15ef8, 0x93d9739e, 0x23146b28, 0x180a915e, 0x9336b865, 0x57dd3cd3, 0x0f14ac7d, + 0xe3d1c984, 0x517c26ad, 0x0133ba3c, 0x09d58899, 0x04aac187, 0xaa538eeb, 0xfb7d1b46, 0xabf374e7, + 0xc17f6170, 0xa63177a5, 0x212803fc, 0x25f3850f, 0xe0cc5517, 0xf652f5d3, 0x01830d07, 0x987436f7, + 0x8f521f15, 0x8b962bfb, 0xd237c029, 0xa225a602, 0xd26a2c73, 0xea9b4d32, 0xcef03959, 0x5ab1ac5f, + 0xc1cd09ef, 0x04227995, 0x7da0ca4e, 0x1145f431, 0xedd1a559, 0x3175aa83, 0x5b26e8f7, 0x230325cf, + 0xca3ba039, 0x772c470f, 0x39cb7eb8, 0x4245a4e4, 0x121e88e4, 0xa18557ef, 0x94d101ae, 0xbd01369a, + 0x6c1af058, 0x67369219, 0x14aad88a, 0xd37e2138, 0x56bfcb2d, 0x9cc18912, 0x7dd72508, 0xd67fb7d5, + 0x84c1c932, 0xdb85ef5b, 0x3d20bf34, 0x38a91b2a, 0x1c0343f0, 0xb802e7e6, 0xd79b386f, 0x7b2b4ff0, + 0x8460cd27, 0xea70492c, 0x7818f356, 0x6ea8defa, 0x7918f4b2, 0xa182e2df, 0xcb4b314e, 0x21287167, + 0x3b133952, 0x82d27998, 0xa80776c0, 0x5babd988, 0x6343301e, 0x2a8d64f8, 0xb28fd87b, 0x36b5abe2, + 0xc0fb4cda, 0x55eb0985, 0xbbc1ed1f, 0x55cb2e49, 0xaf1276f3, 0x314875d2, 0x340811fd, 0x96ff1ba0, + 0x9c0c48e8, 0x4df1b7ca, 0x7b735faf, 0x1bdb0043, 0x8a61f6be, 0xd08257cc, 0xe2829923, 0x8c2e9739, + 0x8b87adab, 0x0348bad8, 0xc6bb401e, 0x0693028c, 0x5a34bf7b, 0xf5b3b130, 0x4b8f8f67, 0x2244ce8e, + 0x3709ad43, 0x2baddf6c, 0xeabcf2cb, 0x63549ecd, 0x8708079b, 0xb0a72ff4, 0x3cf6ff91, 0x121a8f93, + 0xfdc61004, 0x22939e66, 0x4ddd91cb, 0x6d4883ce, 0xc716f57f, 0x76296f5f, 0x9b2b9b4d, 0x43b587c7, + 0x96a7a2bc, 0xcfcded3c, 0x2ff3e057, 0xd4ca559f, 0xaf2f51bd, 0xc443fef5, 0x2d4f6f02, 0xc30f6981, + 0x6d407741, 0x53c546dc, 0x9b92fb47, 0x6223f71e, 0x33edbcc4, 0x61e66fe5, 0x328b12c0, 0x8442eec4, + 0x59701460, 0xfafb46de, 0x5fb5166a, 0xffa6b526, 0x3528c839, 0xb2c78022, 0xefecba9f, 0xe57a4aa8, + 0x5df20656, 0x8bf49bb1, 0x9e8037f8, 0x8abed8d6, 0x3a872cfd, 0xc46db3b9, 0x9d8f13c5, 0x9b905a5b, + 0x944d05fd, 0x7eac3936, 0x6a2788fb, 0x34b338c1, 0x50c719a3, 0x59e18f84, 0xdecc2d5d, 0x08b6bebb, + 0xb978d6da, 0x3627a368, 0xbc4fc82e, 0x30e16070, 0x51f896da, 0x0f4d7b9c, 0xd5f193c6, 0x5fb03199, + 0x456275fb, 0x3cba4620, 0x9638cfe1, 0x93306a25, 0xa9dca541, 0x93a4e712, 0x13af648b, 0x7fdd39c4, + 0xee83f0d2, 0x4b492d9d, 0x42b1ffe4, 0x48fcc71a, 0x8653da78, 0x63e21d41, 0xfd25c635, 0xc9572d4d, + 0xb4d0b51a, 0x5cd0ef46, 0x380c4b14, 0x25cefee7, 0x6ff518c2, 0x886d5b7b, 0xaa4c1265, 0x4a8d3c47, + 0xcfe577dd, 0xc0a5cbda, 0xca7a1022, 0x44b0bb2b, 0x33bb52fb, 0xd3313a2c, 0x368d339c, 0x52e68bcc, + 0x8a7c8512, 0x60718a35, 0xd40fcb94, 0x0ba82851, 0xbf19d49a, 0xbcd28aa8, 0x1b8a5cd9, 0x64aeb0ad, + 0xf78010f2, 0xbcb1aba0, 0xcb8ce6f6, 0x647b9ddd, 0x098f1d59, 0xb62b1842, 0xaa9372f5, 0x04a67f2a, + 0x73ef89a1, 0x047a80c7, 0x76f7a2fd, 0x8fb8f262, 0x99a9dcac, 0xe07ddaf9, 0x43fe0e94, 0x0aa30af4, + 0x28f2b341, 0xa4ea4764, 0x51efa99b, 0x70385f9d, 0xf76a84e2, 0xf64dd4fa, 0xf95b7f93, 0x87db5d4d, + 0x1232fe37, 0x9507dd42, 0x1813c951, 0xb2dc5ff0, 0x7053b9b6, 0x64d9a9f7, 0xadf1e909, 0x7e2f69f2, + 0x14bb72ee, 0xecdfaf1b, 0xcdd47ea2, 0x975ca3aa, 0x967b2cb0, 0x030424a4, 0x5c8671e4, 0xcf79889b, + 0x8469f3f5, 0x92357938, 0x754e3247, 0xab1e7c8b, 0x29746804, 0x41fc8c78, 0xa383be47, 0x76fbc30f, + 0xbe1663ba, 0x37b8e0a2, 0xe41f6d93, 0x24949c48, 0xd9a79e9c, 0x3ba53250, 0x096bbbbd, 0x6cb7a330, + 0x13634146, 0xffc80133, 0x76d13bfe, 0xb78eadcd, 0x9567aeef, 0x27f08d71, 0xbf421c92, 0x61c94d24, + 0xe42432ba, 0xc8b83331, 0x42d7996f, 0x71ff6968, 0x858bc1db, 0xe4a19c60, 0x7029c931, 0x448f8ef6, + 0xf456c6b1, 0xe0d151aa, 0xdedd42ca, 0x12a77948, 0xf996cd50, 0xb627b57c, 0xa91f2d3a, 0xf8cba3a4, + 0x5e544a5c, 0xd1426447, 0x0093f4f0, 0x0b64b0d6, 0x80be4c45, 0xf315568c, 0x1e363a17, 0x550ea6ff, + 0xbdd749bc, 0x77eea674, 0xeeed46bb, 0x29d5ebc1, 0x0d2eac86, 0x6abf06d4, 0xb2ec5c93, 0xf7087be2, + 0x240dad0b, 0x0dd9e215, 0x6469ecb7, 0xc1464881, 0xd1f9147a, 0x74fb0062, 0x147dcb82, 0xcf7266d7, + 0xb81aa9ef, 0x667ab067, 0xbdae666a, 0x21179a93, 0x9affa353, 0xaad487c0, 0xfe1023d7, 0xc6c0fcf2, + 0xd163423e, 0x052eb0ff, 0xec2535e1, 0x86affaeb, 0x959dff8b, 0x43aa9433, 0x6cec2c87, 0x61a2922d, + 0x26517963, 0xf8f73a64, 0x2fe14c77, 0x111bf6d2, 0x7efbe813, 0xcb77d4ad, 0xe69f645a, 0x0c11dad4, + 0x252db929, 0xdbfe59e6, 0x41e36c88, 0xf085257a, 0x87d77345, 0xc5d3e546, 0x4d56a798, 0x3c9e4a5c, + 0x647c81a1, 0xe3fa793c, 0x5cf917c7, 0x042e2554, 0x7a987922, 0xbab536ea, 0x8dc94285, 0xf98959d0, + 0x5043ca5d, 0x07f91fb0, 0xefd33c4e, 0xfe300ba7, 0x67164873, 0x633797bf, 0x54cb9a65, 0x5f71181d, + 0x6e388149, 0xe6958208, 0x3952dff9, 0xa29bed40, 0x12455c85, 0x30d206f8, 0x4108b4fb, 0xe3e00692, + 0x13278109, 0x190db82d, 0xc09862e9, 0x9b1d2ca3, 0xeb470cd1, 0xe7cd4610, 0x92959583, 0x7ad3b320, + 0x9361e4c1, 0x6dd22923, 0x06f95e0f, 0xe23dc2df, 0x0a89647e, 0x2cbeefff, 0x0630d4f6, 0xad4682d4, + 0x3e468618, 0x8ec3c165, 0x98f3087e, 0x095413cc, 0xa44cc2af, 0x2210becd, 0x040fd9a2, 0x82eab097, + 0x33c8e2ed, 0xabc161a7, 0x7439c88f, 0x2b9f1392, 0x81ec1abf, 0xb51f9efa, 0x6d0c4ce5, 0x56fa0c6e, + 0xce7790de, 0x1ac01941, 0x188b72c8, 0x82826d39, 0xd12cac99, 0xc4e58ed7, 0x8bc5751b, 0xa397bb19, + 0x4cc5367a, 0x6dabe53e, 0x4d704432, 0xe8955486, 0xeb9281ba, 0xc357158d, 0x9f206476, 0x95b8ffd6, + 0xe9cdab5f, 0xdfd88924, 0x0347862c, 0x0511aab4, 0xabdf576d, 0x8483acf0, 0xb61aaa0c, 0xce9d8887, + 0x83e12b18, 0x5f3e1b48, 0xacb19e82, 0xd9268263, 0x9203a1b6, 0x1eeb9ca6, 0x92a3009c, 0x8a8f318e, + 0x78d41ee8, 0x7238fecc, 0xe4223088, 0xf4701b46, 0x2d38b73e, 0xa8adfbb1, 0x2960bd07, 0x7b66db7d, + 0x0a147a66, 0x532e8530, 0x1f571e44, 0x1140feb9, 0xb379d114, 0x936812ab, 0x9a077623, 0x952a73d9, + 0x72afa0af, 0xd1c1589e, 0xe47a6211, 0x9c09896a, 0x486a824b, 0x12538d64, 0x4c19f7d1, 0xc8d4fee5, + 0x81e812fb, 0xc211d968, 0x572d42a1, 0xdf58f02e, 0xc3245163, 0x4fb3e129, 0x026d4985, 0x59215026, + 0x2ba09c00, 0xe623247d, 0x64177ee8, 0xa67b07b4, 0x576f4dcd, 0x63dd6767, 0x3ef5d77c, 0x2d7dee45, + 0x9c8dc513, 0xaa3edeb2, 0x6861f1f0, 0x92c44468, 0x64bc9674, 0x86b9e8b5, 0x63a0f613, 0xd886e6a8, + 0x2ba5ec73, 0x7368619f, 0x6cd084e3, 0xa2255624, 0xb2c44c9d, 0xa82b477d, 0x6039a656, 0xc180dbc5, + 0x5fc56135, 0x45869893, 0x49feafe8, 0xf8f63c31, 0x5e8c11cf, 0xe01e6ab5, 0x94d8263a, 0xbc5b25f6, + 0x7e56c2a5, 0x5b10e94c, 0x69909297, 0x31831dd1, 0x14bcda88, 0x0ef06817, 0xb0615f77, 0x3f523230, + 0xb03900ee, 0x2ca5ceb8, 0x33e88962, 0x2ca8aa52, 0x837c2a55, 0xb341c7b0, 0x2ceabba8, 0xa55998a6, + 0xbe1a7406, 0x0e6edc67, 0xcdaf9747, 0x5d32fc98, 0x53c5608f, 0xd04ed558, 0x6bc3999b, 0x9048f7c0, + 0x1b903678, 0xed43d66d, 0x46f1afc2, 0x2ec3aaa1, 0x8b5d85ca, 0xd4d8496a, 0x69488084, 0xd62ebc6e, + 0x9cd4df50, 0x08aef82d, 0xdac88a14, 0x8ac03218, 0xa45df744, 0x1cd9e5e0, 0x485456bb, 0x39331ea7, + 0x314df765, 0x81fef72e, 0x1da7495d, 0xd3a3fdef, 0x0372f746, 0xb9299fbe, 0x97249737, 0xf757d230, + 0x26ee47f2, 0xe516171c, 0xbd5e31f2, 0x18fb170e, 0x021197a3, 0xc2034124, 0x6cd8e436, 0x2e25178f, + 0xad70d445, 0x1cc96adc, 0xf776efeb, 0xf45717af, 0x133b911b, 0xd0fdc83c, 0xbbc55ee8, 0xacb2a80c, + 0xdfca63db, 0xe4db1c6d, 0x280c17f9, 0x6efee676, 0x005e4131, 0x7cd9675f, 0xf075813b, 0xb1ab3440, + 0x3edacae6, 0x308ab075, 0x3092e812, 0x09ecd82b, 0x9ad43f8c, 0x7d6357f3, 0xd20cebcf, 0x93de998b, + 0xd59bb139, 0xbcdba7e9, 0x834230ce, 0x0d592aae, 0x5023f59a, 0xb6651a7a, 0x91357894, 0xdb384632, + 0x74ba27b4, 0x8ac16302, 0xd352b716, 0x246fb066, 0xfb092829, 0x64cab9c9, 0xfac95505, 0x3cddf12e, + 0xaa49d7b0, 0x8d1f295c, 0x72194b46, 0x14618702, 0xdcdde6d1, 0x2739c05a, 0xaafc4bd0, 0xa90247ed, + 0x9bda5017, 0x8facde27, 0x048d053e, 0x9cddcb06, 0x9be6de41, 0xd0a325c0, 0x9e197d56, 0x1f0a8ae4, + 0xaf9e5269, 0xea66bd48, 0x606a3ef8, 0x0967fb3c, 0xe50acefd, 0xebda276c, 0x6a0dbc79, 0x6f902a0f, + 0x0904107c, 0xd7e4eae8, 0x8ed5e960, 0xc5826970, 0x69f19e32, 0xe2db5bff, 0x661e8dec, 0x19dab306, + 0xad4930a7, 0xa6d5218d, 0xe9e724e3, 0x1bac65c5, 0x85b7491f, 0xc62c8f06, 0x91941c0f, 0xe3b8dca5, + 0xb95ec78d, 0xd6ab8b13, 0xff191592, 0xbd5cbe1c, 0x6621489d, 0x53187984, 0x537bdaca, 0x141ea9f0, + 0xd68eceb9, 0xdcd870de, 0x2487f7e9, 0x98b55182, 0x91e3e337, 0x57aeb3cb, 0x962c803e, 0x1ef8d4ab, + 0x2a57aa0f, 0xf29fc78e, 0x150e3bca, 0x5012a7c4, 0xe229fa86, 0xa1f3ad3a, 0x6df8b510, 0x3bbce9f2, + 0x70ebe5b0, 0xac354483, 0x15db421a, 0xfddfbb74, 0x998a309f, 0xeb8f1ec2, 0x007d7387, 0x821c8abe, + 0x56f411dc, 0xb95fa8f3, 0x2b760cdc, 0xbb139a8d, 0x00576ffd, 0xa9bc77dc, 0x08952910, 0xe46e9405, + 0xf0c0af01, 0x93b4d311, 0xec82781e, 0x7fce6a2e, 0xcfda8da9, 0x82e7560c, 0xabc81568, 0xb31140da, + 0xb5c5a24d, 0x3c975723, 0xf2abca3d, 0x6d8dd010, 0xb88609e2, 0x7391ff2f, 0xec10e5ab, 0x2350d2ab, + 0xe588babf, 0x155669f9, 0xd9ee2473, 0xf62c2439, 0xe18f0ce5, 0xff5637f4, 0xdd2b242c, 0x24063b37, + 0xe6943e42, 0xae7a2720, 0xb7cce9da, 0xff650b7d, 0x781f11ed, 0x43ca995f, 0xab22e7a3, 0x21844987, + 0x12ee6ef2, 0x0fc88d49, 0x32f5ce6b, 0xd81ab931, 0x0ea2f571, 0x668028f4, 0x1886b436, 0xc96f4ee6, + 0xe6d5b087, 0x79791ba2, 0x785aadf4, 0xdb95e99c, 0x55383f6e, 0x2d0a998e, 0x5ff547ea, 0xba98ed7b, + 0x65c43a12, 0xd4649292, 0x4a21afe6, 0x20687faa, 0xd00a4edb, 0xcbb161c4, 0xbfe4694d, 0x8e1b61c4, + 0x6944e802, 0xdbe2778a, 0xf9366ea9, 0xc877fd53, 0x9a981511, 0x8b91bca8, 0x3f3cddb9, 0x39472104, + 0xf55347aa, 0x00165142, 0xd7ef8519, 0xa411e92a, 0xac75d2a3, 0x01c27e7f, 0x439cc66c, 0x5d57d742, + 0xf757c521, 0xa7ecd2d1, 0x71c14563, 0xf61ff57c, 0x3e440378, 0x8f05f6ee, 0xe218335f, 0x25423ac5, + 0xb5ad9552, 0x85384859, 0x9118891f, 0x65980a38, 0xe8d06fee, 0xf91cebba, 0xeb91ff6b, 0x95230dfa, + 0x28d94baf, 0x740346e3, 0x9de4aa95, 0x1f49350e, 0x6ece88a9, 0xce280f1d, 0xfbdba060, 0x56031bda, + 0x79ecfdcf, 0x8d8d05b5, 0xe1b7d7f3, 0x90f2d86e, 0xfb0526aa, 0x8417aa92, 0xed8e1866, 0x27427691, + 0xceaea69e, 0x13013c64, 0x434b4da0, 0x7bfece68, 0xe52daa3d, 0x93b46f6d, 0x7fb58f0b, 0x2bd8ff91, + 0x409c3949, 0x81170f42, 0x925479aa, 0x5f2d0ad3, 0xf9d6cfd7, 0x1a97117f, 0x5940b6e6, 0x74299859, + 0xdb740821, 0x6c071797, 0xe3224c26, 0x323bd65e, 0x82f7ed67, 0x94b3eee0, 0x852d688f, 0xdf72f018, + 0x9daebb26, 0x4169aa95, 0x4219683f, 0x2af370dd, 0x24e89fdf, 0xd2f4ff6d, 0x876106e3, 0x9fd26e70, + 0xc0ad94e6, 0x17d0c4ff, 0x60432348, 0x4d86ec3c, 0x99582649, 0xe3bff7f2, 0x46d3446b, 0xe0fc85d6, + 0xdede067d, 0x8713c7b9, 0x5581adaf, 0x0fe03325, 0x71936b97, 0x61f9fec5, 0xbb4efe34, 0xbab2a3f9, + 0xda971487, 0xda3ff2a7, 0xb58b8b58, 0x6003fac7, 0xfe7ed200, 0x08104f8c, 0x1b922095, 0x18017a89, + 0xb958bd3f, 0xb6a1dcf3, 0x10a40d45, 0xd7ce429c, 0xd3692400, 0x4f2ac570, 0xe36be403, 0xa6812efb, + 0xef6581ca, 0xec3a2642, 0x2ff4b49c, 0xba4f60e0, 0x2137bdf5, 0xe3ba15a7, 0xb4f122dd, 0xf9fe52e0, + 0x7d44b071, 0x85cb4c6b, 0xc8130ec6, 0x423be6fb, 0x1ed0d371, 0x8750d5a0, 0x91574dd9, 0xdc035c78, + 0xb4e68cf1, 0x6c18db33, 0x97a45299, 0xe5a75817, 0x45da6d4a, 0xf7c9a82a, 0xc4a2a964, 0x76fa6138, + 0x83a8b3ac, 0xd44dcdc3, 0x626894dd, 0x54ff5be8, 0x1075c0e3, 0xd5ced2ff, 0x868f4e98, 0xf7a76829, + 0x73f35464, 0xb788a964, 0x0ea2fb8e, 0x0290cf14, 0x7df28062, 0x388b5afc, 0xc5189c3f, 0x68472876, + 0xd4611931, 0x17f7c67c, 0xff214dc0, 0xd2b80fd3, 0x7bac47be, 0xa7da41f1, 0x38e560ce, 0x603ad6e9, + 0x28085d2d, 0x5bbe5656, 0x32aa4532, 0xf44222eb, 0x456b0392, 0xe4204031, 0x55a86c25, 0x991ee25e, + 0x22771ada, 0x744645b8, 0x169256a5, 0x20ea7647, 0x7cd9c90f, 0x7e7eedf9, 0xed080f2d, 0xed44b27b, + 0x62c6f26c, 0x43938fda, 0x8d675967, 0xba8a6623, 0x17cb06b0, 0xa52ecbf7, 0xd1bd933b, 0x0a6de6f7, + 0xc429445c, 0x45770f32, 0xfed51c28, 0xa364d7c6, 0x188d9720, 0x8b8bee62, 0x132e4db9, 0x214f0f32, + 0x0ff2dfba, 0xf9b8fde5, 0xd1bdd617, 0x813da1a6, 0xf8ffd1e0, 0xf8cc888e, 0x27b5e312, 0xfbbeaf70, + 0x0481ac95, 0x8cf9cc97, 0xe9be3e36, 0xba588a80, 0x2261249a, 0xc55ca21b, 0x74c690dd, 0x08fccf1c, + 0x178f816a, 0x3e37ac21, 0xd75e1460, 0xb00c2486, 0xb743b67b, 0x3b506f8d, 0x878a2173, 0xa7748ebd, + 0xc465c1af, 0x92a464d3, 0x329773d2, 0xc8fa99c1, 0xead88541, 0x917d22b4, 0xc46b22b6, 0x3a8fb7a5, + 0xc772f994, 0x0ff73e90, 0x4222433f, 0x35c9a417, 0x628cac19, 0xc9e56a88, 0x95fd010f, 0xa6921d92, + 0x57a6ea75, 0x5a7d70c7, 0xdd0a6658, 0x7acaaad3, 0x9d0f2e8e, 0x50b87b8e, 0xb05afcdb, 0x4644ac9f, + 0xda544039, 0x7cdc83b7, 0x497ca480, 0x8be75c0f, 0xba23f82a, 0xebf42c14, 0x1a3f7060, 0x28197fc2, + 0x8da882ea, 0xb9e46fc0, 0x5dfa36d4, 0xe63d12d4, 0x60b7329e, 0x7b17b8c3, 0x2c87d6ac, 0x719c3c58, + 0x19925e7d, 0x781dc32e, 0x05d79e4b, 0x247b5a0b, 0xa2241020, 0xd49a8233, 0xf5b7cf5e, 0x1057a290, + 0xbeb6e44d, 0x280234e3, 0x8bd26411, 0x39a427cd, 0x2ec50ee7, 0x9981ea74, 0x4c37fbd7, 0xeb89cef5, + 0x33eb9794, 0xc41e50cf, 0xe2654036, 0xcf1e4680, 0x3ee78e16, 0xeb73b23d, 0x7d243a6b, 0x5534a515, + 0x1fa5db59, 0x77111b36, 0xb9319db5, 0x39f02441, 0x14892668, 0xae000782, 0xd01b4cbe, 0xac661616, + 0xe26cba47, 0x8399a5e8, 0x29360fdb, 0x3e3d001f, 0x105ca9a1, 0x58500e53, 0xe2b37166, 0xdd130a73, + 0x9c1e7cf7, 0xf589123d, 0xfdd68e44, 0xdec799f9, 0x1ed2fde2, 0x06822858, 0xe529b8e3, 0xe79b83c5, + 0x9d624d36, 0x7cb0a2b7, 0xb2d95e01, 0x2bd5fd51, 0x8c024d37, 0x07f48696, 0xde7c9817, 0x7f4163d1, + 0x08a198ba, 0xaabdedab, 0x345cd01f, 0xdad7094e, 0xc78c59f9, 0xc2141564, 0x4baadcc5, 0xb99b58f2, + 0x1bba76ff, 0x04bff8cb, 0x8e4c4e2b, 0xbea964e7, 0x68edbc29, 0x7f607b62, 0xe6be072c, 0x5dbd03dc, + 0x426eeb50, 0x456473f6, 0xa222e68c, 0x2e839c44, 0x6b1533c4, 0x411df19b, 0x92ea549c, 0x6c0eeb33, + 0xa2d5a5b4, 0xdff49bb4, 0x26a29f8e, 0xb7e01ca6, 0x540f908d, 0xe51c8b72, 0x54344f95, 0x5b4e73dc, + 0x9f325f1a, 0x4b70fa1d, 0x27149284, 0x2e8c64f5, 0xc372b70d, 0x53f55aec, 0x61bba3cd, 0x9e230538, + 0x9c1074b3, 0x5318c886, 0x37ace3e0, 0x0b6574c8, 0x43414f7f, 0x7357ebb4, 0x4769073c, 0x8baf1921, + 0xa7058bfa, 0xfb856cad, 0x982db971, 0xb52b3d07, 0x7c24548a, 0x9ef01239, 0xdcd3ae35, 0xb161d473, + 0xd1d16d6f, 0xa554100a, 0x7135e1b5, 0xd9a82449, 0x39cac620, 0x82a9c409, 0x86a6ad73, 0x944e85f5, + 0x5570ad95, 0x82ca4b2a, 0xa48600a7, 0x58bf797f, 0x8033dea1, 0x49c7fb42, 0x88b4476c, 0x892e9657, + 0x16d1983d, 0xcb43a31b, 0x1ceecdb2, 0xc4dcefdb, 0x30ffb243, 0x936babe5, 0x9ee2d690, 0x48aa420d, + 0xa0858410, 0x1802e1a6, 0xf2340d54, 0x37323e97, 0x509c4bbf, 0x60bcfba6, 0x95a91cb1, 0x5415867c, + 0xb9f105ed, 0x5b59c8cd, 0x2aa8c8c6, 0x49f1d305, 0x6e532955, 0x019ef6bb, 0x908dafbc, 0xf137f8b9, + 0xf4fcdbd4, 0x4a33e9bf, 0x31f46a19, 0x2116b958, 0xbc8f591e, 0x243d31d6, 0x7078900f, 0xd1f722b9, + 0xe3f11be7, 0x86d0b17e, 0x522ed7dc, 0xd1c1f156, 0x2968c5c3, 0xaab6692c, 0x1ad05a13, 0x8d6e48c3, + 0x7523a055, 0xd13aca36, 0x1fadc73e, 0x0bab4115, 0x02f0641e, 0xcb9578ba, 0xbeee3ccf, 0x4e679e3a, + 0x491032ad, 0x44722b6d, 0x625afeb3, 0x6138383f, 0x1d66136a, 0x48a01a1f, 0x347e965a, 0x1e76ec33, + 0x4a56526b, 0x305cfa35, 0x059badc1, 0xad87d0d3, 0x860b4360, 0x8e429a17, 0xb5e58a08, 0x9c14ddde, + 0xdb07339a, 0x23bfce3c, 0xd32ad27a, 0x0c098c64, 0x033005ee, 0x60a212d8, 0x4ddfc91c, 0x2c0319ad, + 0xaa5379b9, 0xc3299f3e, 0x4633faba, 0xc9e5a61f, 0xa8820757, 0xa97cdeaf, 0xa0348ec0, 0x1a5fa201, + 0xb20b46bb, 0x240f4382, 0x19ab7d02, 0xbd8b0a32, 0x5fb4c0eb, 0x3a8948dc, 0x628dad64, 0x75d19cb2, + 0x13b97a9c, 0xbac658bf, 0xb9a8f948, 0x076a93cd, 0x5725df7c, 0x9fa52d10, 0x33796b92, 0x849ebb89, + 0xf638f60b, 0xb3437719, 0x93d6bd67, 0x175f4bc4, 0x7d00a009, 0x41620a4a, 0x5e7b5f7b, 0x96e488f0, + 0x2c1d1ce2, 0x0b6ca94d, 0x16ce971c, 0x28efe47c, 0x75a1a4e8, 0x6832948e, 0x1fd04162, 0x83a862b0, + 0x2203173d, 0x3f7a516c, 0x299d5aa3, 0x8060bfd4, 0x77d2574f, 0x86206679, 0xfd393908, 0xd6e510fd, + 0xd7e8aef5, 0x2b36e541, 0xa8c06294, 0xc9472de9, 0xa6cb28fa, 0xa41deaf1, 0x6b3c5b5c, 0x0dcfa747, + 0x1c0038ed, 0x8dcc36f8, 0x2cf99ed2, 0x2521b3ca, 0x183d6368, 0x9841166a, 0x8336a1f8, 0x4a9cc096, + 0x71b87f79, 0xec90a4db, 0x03421c98, 0x931048fd, 0xec4581c2, 0xd5163086, 0xa2b0d5d4, 0xc8ac21a0, + 0x019b88eb, 0x796a5320, 0x27697851, 0x2650ddbf, 0xf98b87b3, 0xaf91095b, 0xc943ad25, 0x687f2bef, + 0x3cb1fb24, 0xb29496b0, 0xbc071b72, 0xecceb4f6, 0xc4efce3c, 0x809af742, 0x776bc7c8, 0xb7ccdda5, + 0xce4b2c7c, 0x1eb1c664, 0x93774744, 0xe6abba22, 0xec1fe907, 0x3e24502a, 0xd2a48e59, 0xe6099b23, + 0xc73b1272, 0x10e6bfb7, 0x8eb07a45, 0x3c1d5dfa, 0xcb68c00f, 0x3ddb1577, 0xb33d4207, 0x9b6d213e, + 0x11750e82, 0x393938a5, 0xe4a30927, 0x9972514a, 0x7ab9d68c, 0xae1300e1, 0x990378b2, 0x33158916, + 0xb04febfe, 0xaeda9c74, 0x229c749f, 0x1a69c083, 0xe6ad65f8, 0x6156227a, 0x07e4bf6c, 0xe9f8b296, + 0x261ff890, 0xe73a35e7, 0xf3dc29f2, 0x34ef55b2, 0x2fa27a4d, 0x5a966935, 0x4699141d, 0xda1534bb, + 0xa5e5531a, 0x14db85cc, 0xac573676, 0x2faabf10, 0x8e59f8b3, 0x00b0abc0, 0xd6f7f07a, 0x56b29a91, + 0x4e8fedc1, 0xd9aaa509, 0x5da28c54, 0xd1b529ed, 0x3dded97d, 0xd3e081b6, 0xda50744e, 0x565d47b1, + 0x892e93de, 0x49c54f4d, 0x85c51828, 0x0b6dbe35, 0x0d35eafc, 0x49970638, 0x22d62d34, 0x373c5e1c, + 0x89662be3, 0x095ab6bf, 0xb3f6cde5, 0x8a07b9d0, 0x7d973a62, 0x2eece564, 0xa9b2574e, 0x81ac5578, + 0x77baad8a, 0x14c50187, 0x153cb1ee, 0x878d19cb, 0x0a741920, 0xce489a65, 0x2a132d82, 0x30c33b8f, + 0xddf12828, 0x4ec85bbc, 0xb297a41a, 0x3cb851b1, 0x7ad31a16, 0x676d4d85, 0x3b559807, 0x34fb1c9c, + 0x3ef59fdf, 0x7fe9a2f2, 0x7421aa9f, 0xbf037c68, 0xf4bf0cb7, 0x2a932580, 0xe2059783, 0x7d3f44d7, + 0xd44d3666, 0x41a58b47, 0x661dc7a7, 0x8380f1d0, 0xc0a8093b, 0xa3a67f35, 0xbdf69598, 0xa5df5c87, + 0x6552999b, 0x4b96bf8b, 0xd5156172, 0x8e934f38, 0x4ebfe23f, 0xbc581d13, 0x9f946502, 0xdaf4bdbb, + 0x93ce3ce5, 0x2936fa3f, 0xfaa0b44b, 0x9fe51563, 0x66918fea, 0xb6f00ccc, 0xce339f19, 0xd3a272ec, + 0x62fbc66a, 0x6026c8c8, 0x11b9c2af, 0x7a62849f, 0xebb49896, 0x31b4ac01, 0xfafed3f3, 0xf8a83797, + 0x0994cd65, 0x19c75e6d, 0x90984a1e, 0x00e5c4aa, 0xeb1f7197, 0xe63c72b8, 0x9df8ae3b, 0x40e84764, + 0x32abda8e, 0x4e483303, 0x5e33671e, 0x35debda7, 0x3ca99413, 0x898b7066, 0xac414bcd, 0xde2bac25, + 0x6290bb94, 0x91dc1617, 0x48ece135, 0x27059ac5, 0xfec8a455, 0x6f277172, 0x4fe6abe1, 0xf069bf45, + 0x0661e4f2, 0x70b55fd4, 0xa8c7d2c0, 0xe7c96297, 0xea027232, 0xb6e9f25c, 0x46d99d23, 0x7efd9261, + 0x4fd433de, 0x2f362587, 0x15f6fdc3, 0x912e7103, 0x007f30a9, 0x4cd30779, 0xb2e15a72, 0xd20f892b, + 0x43a46d95, 0x3cb09e93, 0x0a0f3f46, 0x78c81dfe, 0xc66d7713, 0x4402315b, 0x18ae343a, 0xcdf681f5, + 0xc24f17df, 0x3edd99f8, 0x942c08e9, 0xafc01a87, 0xf9b97d12, 0xffdda507, 0x3a716584, 0x84d9fa0d, + 0xb70dfd4a, 0xba30d0ea, 0x6ce6372f, 0xac68756d, 0x510bee6b, 0x8b1c9141, 0x72fa3012, 0x7e14eec6, + 0xfe1bd909, 0xb5fd9d15, 0xee667b6c, 0x7f4714eb, 0x90ea9591, 0x4117d18c, 0xefef2acf, 0x9b37a45e, + 0x2462961c, 0xbdc94c91, 0x6aa44840, 0x18543a5b, 0x46edb683, 0xbd3434cb, 0xc2c8b438, 0x58e13697, + 0x28d3504c, 0x5a593dc6, 0x05a58566, 0x2a4d7f82, 0x29358f2f, 0xccbb93ce, 0x3edec700, 0xdc4dbe37, + 0xee883652, 0x5c506456, 0xab0d5002, 0x9f786e89, 0xaff399cf, 0x9991b657, 0x1157bd4f, 0x0b1aecce, + 0x06499ceb, 0x4a49c0fe, 0x07fc0f8c, 0xccd72df0, 0x62d4e23b, 0xb78f2572, 0x835b9f3e, 0x9ac3e7aa, + 0xb7e3de88, 0xb006c747, 0x2bf78cd0, 0x1a9fc866, 0x188d9cdd, 0x8a1f0ade, 0x09b89ea7, 0x3b5e63c4, + 0x4cd0cf57, 0x2d7e4d38, 0xae05257f, 0xd4c93756, 0x41916448, 0x6804d0a8, 0xf0605986, 0x47dd0a04, + 0x2af9d536, 0x7b3bfe1d, 0x31632d24, 0xc68fcdc1, 0x49b978d1, 0x193f361b, 0x4cd983ad, 0xb12e0858, + 0xdd0270d2, 0x052c9f06, 0xc9deebbf, 0x9fcc9c4f, 0x6128d003, 0x25663aa2, 0xdf0f5530, 0xabd8213c, + 0x940263fd, 0x92cef14d, 0xda8d4609, 0x95a74419, 0x1fdd2601, 0x7888dd1a, 0x4fedbd35, 0x89c64260, + 0x414027b8, 0x2e574ef2, 0xc1339ee4, 0x77041d25, 0x1efd5941, 0xa613f100, 0x74c35baf, 0x93db9811, + 0xfbb984a4, 0x7734ddc7, 0x6e1a05e9, 0xdac37842, 0x1bc9ff8a, 0x6b9f765b, 0x56722354, 0x0c11f892, + 0xa7d8b732, 0x051fc3b9, 0xb560a623, 0x41591413, 0x3da0e466, 0x03e47d9a, 0xb8737205, 0x421d894c, + 0x85a75fbf, 0x5d871ba5, 0x6ad3c7d1, 0xc8799197, 0x60bb208e, 0x6770234d, 0xacb297c6, 0xcb21c807, + 0x748fbccf, 0x3c4d6198, 0x0cc2ad1d, 0xf1c0cb8c, 0x149e2d73, 0xd8bc214c, 0x3cd308a0, 0x0d569c30, + 0x4fb004ba, 0x4f35a189, 0x6d9d07bf, 0xbcf6e2e0, 0xf459e0ae, 0x3f6458ce, 0x09cc4c27, 0x76ac7839, + 0x59b00481, 0x89d3a59a, 0x6943311f, 0x6c564082, 0x160188f6, 0xf42bcc0f, 0x2a8e1f0c, 0xe760987b, + 0x21c8a32a, 0x5b1b7ea2, 0xcf297a37, 0x867ba077, 0xf3561d9c, 0x0fdfcc20, 0xad95ade7, 0x058ae388, + 0x830e30b1, 0x4a02d61a, 0x909e2bfb, 0x948c8055, 0x2f3418e2, 0x5136fa71, 0xa402362d, 0xe5d11e85, + 0x37b29aa2, 0x4e285c6f, 0xf821713f, 0x38268d55, 0x7f3ceaf0, 0xeb39fcb1, 0x2631654f, 0x7fe1c146, + 0x9d935b1f, 0x125190b0, 0x03e06c96, 0xbd8e43b4, 0x9741f022, 0x7b049317, 0x36ad468d, 0x1f45f950, + 0x8b584cbf, 0xfb20b188, 0x95f31660, 0xac2319d3, 0x7621bedc, 0xb7fc56f3, 0x84afdd0e, 0x7ae3015e, + 0xb2ed3aad, 0xb8cb0e6d, 0x4b13d946, 0x0b000797, 0x9fd76db5, 0x6210eff5, 0x5cdc46ea, 0xfe0971b7, + 0x6f9741a7, 0xd5a5d024, 0x86118552, 0xe3b411b9, 0x9c98082a, 0xe899389b, 0xcf0c3a55, 0xfcf16665, + 0xf7daa047, 0x8467e99a, 0x49fef549, 0x7781ec97, 0xa3df2914, 0x6813693b, 0x38379290, 0xf4c5289c, + 0x4ce553ac, 0x42e7a684, 0x866eb284, 0xb2dcf856, 0x7220c12d, 0xcee107a8, 0x673ebc2b, 0x22a89a1c, + 0x597676ea, 0xce66049c, 0x3f619d35, 0x1128df2f, 0xaf421f62, 0x5651c5e0, 0xc0dc0068, 0xdc84d9a4, + 0x641e6590, 0x3d124c7f, 0x78fe67e3, 0xdeac855f, 0x664f2f8a, 0x5e471082, 0xaec489bb, 0x8d48b402, + 0x916e11ae, 0x7d997e33, 0xd7a4b6ca, 0x252172ff, 0x8233b3f0, 0x828ff0e0, 0x82350b3a, 0x2a884b6a, + 0x542b569a, 0x7fd7c691, 0xbce8c30a, 0x497aa9cd, 0x3ed299c1, 0xb712a4b7, 0x1f753c5c, 0xf9d4262e, + 0xc8f60a7b, 0x6c82fb5b, 0xe180072d, 0xa0436892, 0x15f59016, 0xdec6ed95, 0x045aa157, 0x9ad2fb7f, + 0x13eb4dd7, 0xa234d5a9, 0xad0c7d4c, 0xa8c65911, 0x4c08f905, 0xf19ab1b5, 0x422bd017, 0x68ba8565, + 0x27106f8e, 0x6856dda0, 0xfa444b41, 0xd42334c3, 0x79685677, 0xd4433283, 0x5bbacbdc, 0x60c79d6c, + 0x8b465c90, 0x63a8312f, 0x8c7cf445, 0xed3b12c4, 0x7a79a732, 0x84bd6662, 0x8895986b, 0x3a28e2dd, + 0xdfcdd67c, 0xfde1d983, 0x73fbfcb7, 0x47400f43, 0x8ce93c0e, 0x58c78ce0, 0xbce7bdaf, 0x6f9827ae, + 0x541381f0, 0x7cd0df8d, 0xfc533692, 0x1f8dd9ab, 0x30037517, 0x451a42c1, 0x5f71958d, 0x36c12560, + 0x1204d537, 0x81ee300c, 0x010e28bc, 0x0775acd2, 0xa7d8dec0, 0x8dd5b453, 0xb8bfedf9, 0x2ee3b70e, + 0x15f53789, 0x11f2e31a, 0x85df1082, 0xcdbcc645, 0x038ccc47, 0x3af4b463, 0xa832cd36, 0x4ff11e85, + 0xad8c795e, 0xe631aafe, 0x012de440, 0x200a33be, 0xb9a802b5, 0x1ac506de, 0x833418b5, 0x2bea94b2, + 0x658ce0d0, 0x87687ef8, 0x4698f6f1, 0x19d4867a, 0xa3fa76cd, 0xe18d20a6, 0x125a3b39, 0x5bd72887, + 0x3588ba14, 0xe0327bb4, 0x3536ab64, 0xf65d6d30, 0x2f860575, 0xff1da230, 0xd079b4a5, 0xcfac7dbf, + 0xcdc468ad, 0x73c13587, 0xa6c4bf37, 0x4d38fa62, 0x1c01cf7a, 0x37f9b524, 0xce7cb3a5, 0x9dd222c4, + 0x020203b1, 0x7dc36066, 0xd3f96d6b, 0xad564a8c, 0xc0d19e3c, 0x31314805, 0x660d0285, 0x96dbfbec, + 0x8b23e1a2, 0x597036ca, 0x590b9a0d, 0x04634b21, 0xfc8d8100, 0xf8e63a0a, 0x868eaad0, 0x39f34205, + 0x34934a4a, 0x5be4ec33, 0x9ae7ac84, 0x2c1f2431, 0xfb1d977e, 0x8986b6e1, 0x4f0b2b96, 0xa54636b4, + 0x4820b0f3, 0xfaf76a7c, 0x84a021ad, 0xe84af2df, 0x89c3b0da, 0x4c62bbe6, 0x0f28fc68, 0xe8127bea, + 0x0bb97857, 0x2cf8f639, 0x7ab9dc57, 0xf52464e0, 0x7efb4d3f, 0x5de2035c, 0x01c954dd, 0xeb0ad3dc, + 0x38f6d4c3, 0x1345047c, 0xa9d0adcc, 0x0210b65a, 0x279f51a5, 0x9abbd217, 0x7a341096, 0x8c67f7d7, + 0x426c9872, 0x5c45400f, 0xc3b67b04, 0xec670f9b, 0x71492cec, 0x883caeba, 0x7bc4d574, 0xfa2ad28a, + 0x2521445f, 0xd4a66432, 0x7a56d735, 0x824b5069, 0xec6d464d, 0x2e091c12, 0x583c98e1, 0xb1389c5e, + 0xb68259e0, 0xfd267b2f, 0x0ea4867e, 0x0f00d43f, 0x5cafd846, 0xb2f94e61, 0xd6e95c49, 0x1fdae367, + 0xee8d9d32, 0x595b06d8, 0xfe07ab44, 0xa0f3346d, 0x398afc08, 0xdb58d249, 0x4f124253, 0x2410de5c, + 0x0e0cc6a7, 0x6b50fba0, 0xd69d2e5b, 0x2fdcf875, 0x720b3b39, 0x9e2051c3, 0x0c262343, 0x2cd1f472, + 0x6036711d, 0xe39e3ac3, 0x65cae695, 0x3ab57be2, 0x322d31dc, 0xaaddcb8d, 0x18c3fc65, 0x42c3bc4f, + 0xd194d527, 0x3824d3d6, 0x3f2df5ec, 0xbb1a678b, 0x13a817db, 0x4b68b519, 0xb1d12fa2, 0xb4762b6a, + 0x230e1a1c, 0xdc96ff03, 0x246403d7, 0x264b4b8b, 0x723bdf8b, 0xeefa8044, 0x982df5db, 0x5c03edd3, + 0x5af95144, 0xf6f9207d, 0x9c0bdc9d, 0x501fbed2, 0xcda52069, 0xd7cdf9ec, 0x5d4feb80, 0xca1fbe61, + 0x3661b07c, 0xc2be7246, 0xabd318e7, 0x22dd98e2, 0x877a7566, 0x5c56a494, 0x566356d5, 0xb218838c, + 0x05dc83f5, 0xeb9a6368, 0x062ce712, 0xc359348d, 0x9d88080d, 0x83ad2a6c, 0x0db8a3d1, 0xde1799cf, + 0xf4636807, 0xac3f290f, 0x47c3e24d, 0x225023a6, 0x79518e5a, 0xf425d35e, 0x948d8bac, 0x286ca45d, + 0x5f36c97c, 0x0d585529, 0x7be33a30, 0x3aa703e7, 0xa86065d6, 0xc9b6320a, 0xe7e6d657, 0x4162c1b1, + 0x674c0fb6, 0xeac5beab, 0x292ca620, 0xbfd95bb0, 0x5e2d56a1, 0xe0056a27, 0x8c4a4305, 0x282d13a8, + 0xd085fa8d, 0x3db99228, 0x3a0ef8db, 0x35b226b1, 0xe49bd0c5, 0x739f41ca, 0x793c5762, 0xec395265, + 0xed366069, 0x6dd7a56e, 0xad51da72, 0x896467d4, 0x31febbd5, 0x339d573b, 0x13850da9, 0x91871c52, + 0x43808c75, 0xedc7e141, 0xa060a6cc, 0xbf4d7600, 0x781ca502, 0xa49ef33e, 0x78bf43e6, 0x416b7f0d, + 0x6f545ea2, 0x6fe989a8, 0xa2b99aa7, 0x101b2b91, 0x82e09a2e, 0x72deb67d, 0xf035621d, 0x9dd5aef8, + 0x5ef617ad, 0xbeecbaa0, 0x0ab16e1f, 0x1caae972, 0x35885fd9, 0xab7010f1, 0x3f141653, 0x252412c7, + 0x98a289a5, 0x32ebea8a, 0x338803c4, 0x29a266a3, 0x93f69d27, 0x81dd1d75, 0x7c89ba0f, 0xe13951e0, + 0x89fc406e, 0xb808ba24, 0x29f0b1f0, 0xc9140e96, 0xc2f77d53, 0x2b5cbd22, 0xc66a51de, 0x733f51c7, + 0xa21c43d0, 0x1e32d41b, 0xf5ba84f7, 0x7f9e8d5c, 0x990ed5c1, 0xf9ef9545, 0xb601bee9, 0xa876d17f, + 0x1c7df1f5, 0x5f46bab8, 0x46a1801e, 0x76b173ed, 0x39959fa5, 0x8f13e88a, 0x6ffaf8c6, 0x9c4c329b, + 0xb0fc7298, 0xaf2a1749, 0xf85e600f, 0x1368789f, 0xc0c6029e, 0x7bc90374, 0x95184e9b, 0xb46f956a, + 0x368455d4, 0x8c52f383, 0x9b94a01f, 0x80a656db, 0x08de916a, 0xb9722ee0, 0x0dec4ded, 0x1e25eac6, + 0x92eee81a, 0x6920ed45, 0x18fae44c, 0x4c139139, 0x22fbbb86, 0x56d577ac, 0x595468de, 0x5d31633e, + 0xaebdc5a4, 0x4c417f00, 0x611ef74d, 0xbaaaebf4, 0xb77d0c2a, 0x9f642799, 0xe6785e4f, 0x4b6573a0, + 0x89dee499, 0x7ad4b0ae, 0xf098f499, 0x8507bee5, 0xeeba19cc, 0x923e601f, 0xa6c23f63, 0x2feeec78, + 0xf77352fa, 0xcc70f097, 0xdda17167, 0x5574b9ca, 0x33d301e5, 0xd6c99707, 0xb1512cf7, 0x4f713467, + 0x764efe3a, 0x26d09aa1, 0xd1330565, 0x402f3d8c, 0x070701e2, 0xff262784, 0xd740078f, 0xa1e0d72c, + 0xd0fbfa75, 0x027b1e25, 0x61444f3b, 0x5e02e963, 0x98f9b9e4, 0x5a0031cf, 0x833b1acd, 0xda3ddf0e, + 0xe4bf33ce, 0x01190807, 0xf1759e7e, 0x45f6ac33, 0x56d7cbc7, 0xb6e54c19, 0x7e631fe6, 0x69530d6d, + 0x6bb75237, 0x1c1cd1f0, 0xd6ed6ade, 0x1a242baa, 0x761f6dc6, 0x8eb44129, 0x25e7511c, 0x482e1fb8, + 0xb041e668, 0x8b3943fd, 0x7a805175, 0xec51cdd2, 0xe9ec3cfa, 0x998813b0, 0x8afd7fb2, 0x29e84097, + 0xe63692d7, 0x09a714cc, 0x2599f28d, 0xec619e68, 0x0e164611, 0x85f30962, 0xada7f894, 0xa7b341fc, + 0xbb2baa75, 0x773dad46, 0x03dbe4e0, 0x50b0c5d6, 0x832b3cf4, 0x644d86c9, 0x32c6c512, 0xf4d16c61, + 0xa20748ea, 0xb35ed66f, 0xbd1b8600, 0xc4d26d83, 0x6d34aed4, 0xcdbdee0a, 0x2a594957, 0xd2eeb363, + 0xcc2759ec, 0x235b223e, 0xca9266c8, 0x9e57ee79, 0xdd3744c5, 0xd99a84ac, 0xce0b57fa, 0xd60dce45, + 0xb1643552, 0x1f4ebc34, 0x47fad986, 0x059e4c75, 0x345710b7, 0x07960451, 0xe4db2e51, 0x35f6ee87, + 0x210c742a, 0xd4fc3bfa, 0x6dffdb3f, 0x21819ed4, 0xbd7c7212, 0x453ad12c, 0x0008d660, 0xaa6dcb4c, + 0xb5861fda, 0x92ecde5a, 0x8a573b81, 0x00b76df0, 0x152827dd, 0xe64dd382, 0xeb87bef1, 0x145d63e0, + 0x7a278082, 0x67d1c21f, 0xc4259159, 0x83d0b54a, 0x60d33d9c, 0x7235d812, 0x2d0deb69, 0xe528b738, + 0xac9a8180, 0xd08f5323, 0x5af03546, 0x49060dc1, 0xa4162170, 0x2682b846, 0xd089d5aa, 0x354e0fa4, + 0x83f41807, 0x575ea181, 0x3edd7512, 0x37b18ecd, 0x6074f002, 0x8f650bc1, 0xa5d0a3e8, 0x39c0efed, + 0x1c2dc659, 0xaabb4130, 0x12ac234f, 0xfbdef88c, 0xb0fc7d13, 0x9e5f916c, 0xb36cfc24, 0xb7afea31, + 0xaf048eb3, 0x0866a7d3, 0x2c2d4a4d, 0x2180a3b5, 0xf14b088c, 0x7f47d541, 0xcaac007f, 0x01e16893, + 0x430325a5, 0x4bd27899, 0xca86c60d, 0x0a071edf, 0x6d777463, 0xd2e0634d, 0xd8db115b, 0xfe10f586, + 0x2945beae, 0x12ed0476, 0x44cb59db, 0x03719432, 0x90916bd8, 0x4b9ae1a4, 0x9a62d8ba, 0x8d97ec6c, + 0x794f39f6, 0xc9672ac5, 0xbab856c1, 0x2d36a757, 0x141fb688, 0x60cfae0e, 0x51576dcb, 0xeb700a4f, + 0xb20135e9, 0x05b4a70e, 0x2c223a8c, 0xb7d36e7e, 0x88f769f0, 0x6c3827f8, 0xe1eb52a1, 0x390541c5, + 0x827d2430, 0x902d3619, 0x3c6d9eac, 0x2722d894, 0x66a493c8, 0x8550775d, 0xb0769e2a, 0xbf41a172, + 0x6142d6fa, 0x388e2cc2, 0xcaf86015, 0xe098f3ff, 0x384e714c, 0xfab2adb6, 0x437b67f0, 0x42a071ab, + 0x66a9c159, 0x203d1e22, 0x5b6edb31, 0xa6d1c7b7, 0x9aea1de0, 0xc7183d6b, 0xd15a39b0, 0xb8f45668, + 0x46d95993, 0xefd11513, 0xb491d2ae, 0xe69c61b2, 0x39863b63, 0x573b6bff, 0xa62ac92f, 0xa1b8631f, + 0xf7f64a91, 0x398ef155, 0xc378bd75, 0x5987b125, 0x09de7920, 0x92294261, 0xe6075c5d, 0xa9fc1d8f, + 0xfb64e7ae, 0xa3161c02, 0xce605f33, 0x7e58d606, 0x0f265956, 0xdc4ded83, 0x9c5be84a, 0x93018ea5, + 0x7e735760, 0xa870e37b, 0xb3ca94ad, 0x79e559e0, 0x55d5d351, 0x88a4aa4a, 0xca7fd3d3, 0x7149f79d, + 0x79b1b237, 0xb80fa078, 0x3913dd8f, 0x4e81a4fe, 0x86ce9b49, 0x015c893a, 0xe759f92e, 0xaf16f2ab, + 0xc27284d9, 0x25b0a9f6, 0xd0366463, 0xe9169d92, 0xea78e6e0, 0x8c69cba8, 0x422c229c, 0xddf370b8, + 0x7ffc1e5b, 0xd97eb8f5, 0x4ee8a78e, 0xf7863ae4, 0xe5f4e9bd, 0x806c3821, 0xd18b80d7, 0x934353c9, + 0x91063859, 0x783fd86f, 0x02b294f8, 0xd2caee3a, 0xa6ae3111, 0x5d436f20, 0x18c19ce2, 0x13a53417, + 0x768c2fbb, 0x1c69224c, 0x785f8709, 0xed2c587c, 0x6420602e, 0x64b7c15e, 0x8d3ba83a, 0x099aa7a6, + 0x2031a77c, 0xc0b99ac4, 0xa42cb844, 0x61593c25, 0x412aaf8a, 0x72d2988b, 0x06fe31d3, 0x5537266f, + 0x01f0f2eb, 0x59eaf51e, 0x970620ff, 0x125aac8d, 0x70a9d398, 0x065488b4, 0x76f70dc7, 0x0d6dbb21, + 0xf385e04c, 0x2d3d9787, 0x3221b311, 0xd919f34a, 0x2f64765a, 0x4b3d4ebd, 0xf85349a8, 0x06a6fb1f, + 0x7a03c3cc, 0xf4d64c23, 0x5f2b6872, 0x01855e26, 0x67f193ac, 0x53f85981, 0xa1706b40, 0x2ccbb226, + 0xf99cd736, 0xa4ff1ab5, 0xb0f8b0e1, 0x0c98ffcb, 0xa343e6ee, 0x99b7c405, 0x191f117a, 0xb0699f8f, + 0x937b764d, 0xb70946c4, 0xdddd989f, 0x66ec06dc, 0xaabf34b2, 0xdfb9dfbc, 0x1269d49b, 0x6d6f09b3, + 0x5e90a68e, 0x9e14b8ee, 0x230b9c01, 0xfde1eb6e, 0x2b1474ab, 0x02168160, 0xcbc2b290, 0x38188a2e, + 0x67a367c5, 0x8d527df3, 0xbde280fe, 0x52e6b27c, 0x2706ac8c, 0xb87012d8, 0x78c05f11, 0x94e8c22b, + 0xe1dfb7b2, 0x58c6a8b2, 0x068c7324, 0xc4b5fa56, 0xfc598a84, 0x360326ee, 0x1c1d2727, 0x3b9bbf78, + 0xfcab3792, 0x83a09d7f, 0xd9a697c6, 0x09d1527d, 0x68321fa4, 0x07de4151, 0x1f60ded3, 0x62a18876, + 0x0138531d, 0x838f8e7b, 0x48571dc0, 0xe974ae37, 0x28858d54, 0x991f26e6, 0x31b7b5d9, 0xb758208f, + 0x3bf8f5a5, 0x1bd134ec, 0x62bece1b, 0x8dddfae0, 0x0ed08915, 0xd0f85e17, 0xdc45da9c, 0xf732ba9b, + 0x103bd817, 0x6725d348, 0xd6c4841d, 0x0de1ed4c, 0x59bc1060, 0x69a7df93, 0x4a28a446, 0xb1db3bf9, + 0x165ec294, 0x1fb357c0, 0xc4706926, 0x4af49a66, 0xf105db4b, 0xf81c2fa6, 0xac8a627f, 0xcdad5f53, + 0xe2dd358f, 0x242b5dc9, 0x3f7ab27d, 0xff3580cd, 0x703e8a39, 0x13ac125d, 0x10373089, 0x7f7b900d, + 0xdbd1892b, 0x6925f816, 0x88411c87, 0x48d5737a, 0x94bbef1b, 0x93146d3e, 0xed888997, 0x65bac72a, + 0xe87b7bc6, 0xd4491be0, 0x1ba5f4ab, 0xe9a7a1ca, 0xe1062012, 0x703cfc7e, 0x557484a1, 0x88607b48, + 0x6e9b4d47, 0xe4e619cd, 0x12d2ee48, 0xada3b75f, 0x0334b571, 0xf91ad36a, 0x5b70d3f0, 0xe1e353c5, + 0xad7aab33, 0xa92087eb, 0xccd490b9, 0xf6585ab2, 0x2594575a, 0x0ae2581b, 0x6add9200, 0xf8c51549, + 0x86b6f01f, 0x0c15e996, 0xb7f18c01, 0x9fa74f07, 0x8eae627b, 0x3f40d229, 0x7ae6b07b, 0x17d7ca94, + 0xa10aaf64, 0x11fe7ea7, 0xbf13b20f, 0x2758e45c, 0xcdb31aa1, 0x5320ef37, 0xec1f2a6b, 0xa1820463, + 0x398724c3, 0x35aa3c1d, 0x9a4605bd, 0xbb30f11c, 0x92682151, 0x09e52d93, 0xae1a589d, 0xa8bab5bf, + 0x50f5d787, 0x3ff07360, 0xd155c6ff, 0x9f486ca6, 0x87ade7bc, 0x1158c48d, 0x326a0264, 0x356faa04, + 0xb22772a4, 0x08aa1dc3, 0xb222867f, 0xdcb541f5, 0xe1fcd586, 0xb13da91e, 0xad20d114, 0x183fc79b, + 0xad7236fe, 0x5562a540, 0x66146d20, 0x5a6fefce, 0xcd329b61, 0x96ff1d18, 0x8320f034, 0xa60e631a, + 0x3f5d60b9, 0x619b4ed2, 0x891c25ea, 0x734f6d8f, 0xcd6d8cb7, 0xfbff8d83, 0x3eb771fd, 0xf9c98d26, + 0x040d6a6f, 0x4b416014, 0xe4fbba56, 0x0f3cc43c, 0x055c6112, 0xa343e9f4, 0xd27b3568, 0x93186d61, + 0xa4bb6bdf, 0x829e5229, 0x4d0756c0, 0x7c164652, 0x11f5f5fd, 0x8ef813a2, 0xf4694594, 0x7d2c3b74, + 0xdc16c4aa, 0x9c6441e4, 0x05911d01, 0x345363e0, 0x4d1a20d3, 0xdec766ad, 0x7875f7de, 0xceda12b1, + 0x5ae86f5a, 0xc0d2e6ed, 0x52c79a7d, 0x0a14f396, 0x918418f8, 0xe5b80782, 0x1d4ca70e, 0x7f43445c, + 0xed4a565c, 0x3d971d00, 0xfe7b5f8e, 0x8e41765a, 0x493fa8b8, 0xddb5d0e6, 0x1f16f3b1, 0x2dbbc98c, + 0x88bbcee7, 0x0e9f6659, 0x63bde5f7, 0xc964aa51, 0xbc5bada5, 0xebd2cb0d, 0x1b610442, 0xce7f2501, + 0x5a86131f, 0x1ad8e96d, 0xf2a45223, 0xb83a7141, 0x38bfde94, 0x270ef708, 0xb2aebe1f, 0x03a02a38, + 0x32f1b9b3, 0xc97e5e26, 0x0411504f, 0x2959fe94, 0xd0e23dc7, 0x3033a36a, 0x9b8c896e, 0x359551b8, + 0x6bba0b11, 0x0cc94b98, 0x340e6dd8, 0xc87cee85, 0x40b6f331, 0x7033c3cf, 0x2dca40c0, 0x6781989e, + 0x23e96608, 0xbd8720c4, 0x21e2347d, 0x5a65e9d9, 0x0f561cbf, 0x409b3860, 0xb00ceb18, 0x5da07f65, + 0x8aa2c653, 0x1ae66227, 0x85ac5b59, 0x491d4bb9, 0x0eeef5c4, 0x5bcef7f6, 0xd1450d14, 0x9e356135, + 0x1816fcde, 0x6cb8e73c, 0xefac8401, 0x1a6be403, 0x791df122, 0xde9d9b19, 0x42965b4a, 0x27677d7e, + 0x2e002ebe, 0x0e6ca6f7, 0xce2bc7fd, 0xa0a52243, 0x81f8e090, 0xb5da6986, 0x239db68a, 0x8d2ca163, + 0x95e76ebc, 0x4a661d35, 0xdf0870ad, 0x8baf99ef, 0xed155111, 0x87bb42e7, 0xf30df12f, 0xa95f4e91, + 0x9a36231b, 0xa9e326a0, 0xf16c5825, 0x87c35ad6, 0xaf03a13d, 0xe30345f6, 0x08d7bfbc, 0xba390735, + 0x0aec82c6, 0xc6ecfb13, 0x2aac6c33, 0x67148671, 0x864cefea, 0x6195af42, 0xd5c64f16, 0x2cf38495, + 0xe8e4ff52, 0xe3ace6ae, 0x32f38569, 0x7ba0e5e6, 0x24c4d5b5, 0x162f5d92, 0x5217424b, 0xcf6742c4, + 0xa9e9664c, 0x3d6a6691, 0x0694abc3, 0x3e3b2d81, 0x69fbe73e, 0xe1fd6e65, 0xed47285b, 0xfa44967b, + 0xe7886f13, 0x001387be, 0xc6b813c7, 0x51a2034c, 0xf915698b, 0xc2e39a2f, 0xa74ee19c, 0x694ff3c9, + 0x93f1ba76, 0x4d48a4af, 0xf88ce7ea, 0xd932e1ba, 0xd09e3a68, 0xf89f7700, 0xfb087061, 0x90b0e95a, + 0xf178a8be, 0x7688a684, 0xd8a6f0ba, 0xaa403f45, 0x2f3d627a, 0xc792d184, 0x6e0542d7, 0x454d615d, + 0xb579807a, 0x6e6c2a49, 0xde3747a0, 0x5fefa678, 0xceec61f1, 0x5acc748b, 0x75148841, 0x0581d219, + 0x1d31bde5, 0x2930fd5f, 0xde18e04d, 0x5b9f4ba5, 0xab748c3d, 0x40684723, 0xab6c442a, 0x7553c1bf, + 0x405b52af, 0x9eb6e7e5, 0x0c22bfe9, 0xd6a9cb20, 0x0258bf6e, 0xcc9f68e4, 0xc21e0c57, 0x7eaad39a, + 0x78b5b5c0, 0xe06d3c02, 0xc38ea8c6, 0x92d1b251, 0x23c58666, 0x4d8f586b, 0xb621d488, 0x7f87e225, + 0xc00f6106, 0x96602ca4, 0x2a8275cd, 0xf4a9ea3c, 0xdf37e6e5, 0xc64d746e, 0x722a601a, 0x50a1545e, + 0xf4b68b5d, 0x8d6cfb6d, 0x75e49824, 0x81a51631, 0x96e6f6ef, 0x4edf0d01, 0xbfadd056, 0xcf8e73cd, + 0x59c25a9e, 0x4cf5fc8d, 0xc2bd7dc7, 0x207437f2, 0x4a1d019f, 0x91fd1c86, 0xd482ff55, 0xab625d01, + 0xe10cc024, 0x43249bf1, 0xf520588b, 0x05c90d5d, 0xec4d3a00, 0x1bb44fdd, 0x8f8dd0b2, 0xd17487c5, + 0x7fbc2344, 0x025e65e4, 0xacfb4be5, 0x3cc0fb33, 0xc7ed041c, 0x6bc0d7a8, 0x0a9d5686, 0x3c14e70b, + 0xe6e15bde, 0xccfbae64, 0x57c3a7d1, 0x67abe7ac, 0xbfcc84a6, 0xda1b68b7, 0xc766d8e0, 0xb7c15008, + 0x6d4ea6ca, 0x16a57ac7, 0xe0844a9b, 0x8ad1dd41, 0x7e61c9ed, 0x50699adc, 0x107bc4af, 0x053889ff, + 0x83b3c852, 0x38169b99, 0x495e3d59, 0xf4e407c2, 0x85f276bb, 0xd09aa1bb, 0x6e054a97, 0xaefe045e, + 0x0b7d9796, 0x69b40027, 0x11df5474, 0x037ea164, 0xea2573a2, 0x9de345ee, 0x0933c6cd, 0x4f8b1728, + 0xee7b8060, 0xd8432865, 0x074da511, 0x3f2d4682, 0xefb40ebc, 0xa9832329, 0xa9ffec1e, 0x6372a15a, + 0xd7c12f6a, 0x3c712df1, 0xfa8b7f3d, 0x538e2cb7, 0x1d3a4eeb, 0x51323a83, 0xcd4cdd9b, 0x4e69a69f, + 0x06d91bcb, 0x8fae2960, 0x9cdd6572, 0x1cc71c5d, 0x8b6ca921, 0xc3cae98f, 0xcecdfe06, 0x5905c665, + 0x282f4430, 0x6b974b75, 0x567e633e, 0x4608fb4e, 0xa9ba5bac, 0x0857fb84, 0x30c00944, 0xb2744391, + 0x58dcef3e, 0xbd5f78d5, 0x7a659e26, 0x2c530339, 0xeb54cc21, 0x87816323, 0xdc2a4f83, 0xd8cb4a76, + 0xaa9d5b3b, 0x031d5fd7, 0x64819be9, 0x89334299, 0xd053a415, 0x56fb83d6, 0x2bdb35c7, 0xb5610019, + 0xd8552e21, 0x133bed13, 0x10e3612e, 0xe98006f7, 0xf5282809, 0xfbb51616, 0x1203a63b, 0x00dcd5c6, + 0xee727c9d, 0xdbdfc765, 0x1375e268, 0x689a012a, 0xcb80a02a, 0xd2b80a07, 0xc622f80f, 0xdd8f9fbc, + 0x5a349f44, 0xc2cb740a, 0xd6475fc2, 0x0456fb8b, 0x92d99ee5, 0xcb99cb4c, 0x7e74a2da, 0xb16b1dab, + 0xf0156f61, 0xd56b6a7d, 0xe750d281, 0xe3ec007d, 0x8f9e059d, 0x48394f17, 0x3bbb6209, 0x8a67b54f, + 0x72981bec, 0x94e91cff, 0x35b402ec, 0x0eaa2ac3, 0x3e79527a, 0x30d530e8, 0xa55285f8, 0x11004106, + 0x193b4a8d, 0x2d754385, 0x5047c936, 0x3a697b33, 0xb94dfae2, 0xc9101aa0, 0x9fe13099, 0xb56b432a, + 0xd2a0a18e, 0x007f5d5b, 0x4310334f, 0x3cdff30e, 0xf21a5172, 0x617d2b9f, 0x2df958d6, 0x3442c901, + 0x63a62627, 0x50b9dbab, 0x4783aca5, 0xab9522cd, 0xeb4a5e82, 0x174d9e86, 0x31694d5f, 0x6234f33e, + 0xf20221b5, 0x0d7954e7, 0x521aeda1, 0x4c6f6a7d, 0x6a3392ff, 0x71ac386a, 0x00bb1e8a, 0x473d9758, + 0x0cd6af99, 0xe491da3e, 0xba28601b, 0xd4fb78eb, 0x904c56cf, 0x37c658d2, 0xdd6e1f99, 0xf3463872, + 0xe180a892, 0x566d3800, 0xb99c7564, 0x0b0424c5, 0x39f6df3b, 0x917e4f06, 0x8804d8af, 0x0e6c1de4, + 0xd3510546, 0xa66d81fd, 0xc9f20f4e, 0x27c04d39, 0x0f29c169, 0xe5c68efd, 0xf4f6940c, 0x52ab41de, + 0x033e560c, 0x7a7743df, 0x21c3c768, 0x9bd10981, 0x7911ad37, 0xcb5802e4, 0xc2b9567c, 0xb0d4c90a, + 0x679f6ca9, 0xdb5390a1, 0x60e40d4e, 0x0b3b6484, 0xd9b55b48, 0xe89e3dc3, 0x28ce47c3, 0xe6d6394a, + 0x6fd21741, 0xcf842595, 0x4152ad03, 0x41c310e1, 0x36d7b968, 0x9f407b0e, 0xb6c8aea0, 0x36c86ff1, + 0x3aa8b88c, 0x813c8ecb, 0xb626797b, 0xea23334b, 0x36f80aca, 0x67eebe61, 0x3c2a2d30, 0x675591a5, + 0x70fe038a, 0x24008ebd, 0x378bd541, 0x5c8de11b, 0xb7e47864, 0xb8f599fb, 0xdb3e328c, 0x67e9eaea, + 0xab1bf838, 0x32367536, 0xa852e209, 0xb654a09d, 0xd12ad393, 0xfe230858, 0xa38dc725, 0xe9706840, + 0xd277032e, 0xb3af1b94, 0x55246d1b, 0xa6b869bf, 0x794682a6, 0x3b52b5c6, 0x9d526e9f, 0xd2d3b401, + 0x8f1fd9fb, 0xc72bb419, 0xb4de1345, 0xc3c5e1df, 0x168f6fd1, 0x011b63e1, 0x9816f6c9, 0xb46329ed, + 0xb62281a9, 0x1d8b4340, 0x3b9631c7, 0x6740ad7e, 0x4b6148c8, 0x5838327b, 0xf20707fc, 0xd52c44ea, + 0x93e3c8db, 0x2b401fe3, 0xbc86af13, 0xcc0ab427, 0xf2cfde86, 0xc314183b, 0xa3851c3e, 0xa86d4590, + 0xa373104b, 0xd8ced9dd, 0x9e6ee055, 0x05e1580e, 0xfae07455, 0x2e83f202, 0xc3e648f5, 0xb838f427, + 0x20a4664a, 0xd6c18ce8, 0x3c9c973a, 0xd86f7e32, 0x16273d98, 0xb371b320, 0x7306f3ee, 0x4923c3ac, + 0x643ae305, 0x687253f7, 0x4d1b8929, 0x91b4b957, 0xb2d12edf, 0x93d5c30a, 0x206c9431, 0x38b90bf9, + 0xbba6e5fc, 0xe923429e, 0xb4e5879a, 0x27d252b7, 0x8b157d80, 0xe9692c46, 0xdbfa7577, 0xc723ac12, + 0xf4a34683, 0xd905d99e, 0x59195bab, 0x13fa684c, 0x2bf63036, 0xdb0274b1, 0xd4d7a713, 0xbc59806c, + 0x4fa412f5, 0x972bc22d, 0xdbe4e80e, 0x6aa8ce76, 0xc73938a6, 0xefa4dbe4, 0x5cab1598, 0x5bad05ca, + 0x4a1fde5f, 0x50a87be9, 0x96e4bd2f, 0x01c83cfd, 0xb24feecd, 0x6a6ebc38, 0xe1bde06b, 0x964355f3, + 0x779799ca, 0xc3a278a3, 0x5f46d681, 0xc15a8c4c, 0xf59d37f6, 0xe9b1c8da, 0x8f2e957a, 0xfda53d1c, + 0x6bbe2f08, 0xd9367b22, 0xb014a3f1, 0x944eec27, 0x435880c2, 0x1c6bcaaf, 0xa9404e9d, 0xb461ca56, + 0x6b99346c, 0xf83847f1, 0xc617d40e, 0x99c639c9, 0x81414c16, 0x6f54b22e, 0xac1e0d1b, 0x9dd99697, + 0x7ce8f44b, 0x04188261, 0x4e9963dd, 0xab08d795, 0xac208d6d, 0x19fa1abf, 0xde2307f0, 0xbffb65bf, + 0x9cb72932, 0xfe994e95, 0xb26a866b, 0x46aae01f, 0xc260741b, 0x05354ac3, 0x6fbe4a27, 0xb49c813f, + 0xc750278a, 0xd90c6845, 0xb34b2cfd, 0x1f3e6e90, 0x6ec38fe4, 0x6ca72726, 0x6643eadb, 0x3a5900fa, + 0x8053b7f0, 0xe0c95959, 0xd143df35, 0x6dbecab0, 0x88038208, 0x5e140ac6, 0xdeb0ad48, 0x15d1f160, + 0x2a655ba8, 0x6c980bd4, 0x38a042c3, 0x1a6c8cc0, 0x36f5830d, 0x6af72bd8, 0xb71dd4c3, 0xe9e593f7, + 0x6b2446fc, 0x65f1dab7, 0x93411973, 0xa9631e2d, 0xa75c0fbf, 0x7aa5e208, 0x1482885f, 0xe0d7580f, + 0x836913b0, 0xe264452d, 0xec722a6f, 0x411f997d, 0x93c0712c, 0x45512b26, 0x16bce154, 0xe08d9ff7, + 0xed46f21c, 0xd4ccfffa, 0xedc854d4, 0x70e789b5, 0x54add31e, 0xacf2ea06, 0x0b416b09, 0x330c243d, + 0x8c4ed303, 0x6062a751, 0xb0360c5b, 0xb71a9277, 0x6665f42c, 0x4999f33b, 0x6666c670, 0x4290e8aa, + 0xf6b94068, 0x3267d3c6, 0x4bd60a28, 0x5096ba89, 0x45a7cf21, 0xf53e46d5, 0xd3a384b2, 0x73818cf3, + 0xbf8392fa, 0x6a9e9b35, 0x7d8212c8, 0x450c198b, 0xa8d4d2ad, 0xd8e1a44b, 0xdc239578, 0xea621de9, + 0x0c4fc161, 0x35e2c6ca, 0x28c5816a, 0x06f27c81, 0xa652adfc, 0x31fcc9b5, 0x848efba1, 0xe66c2066, + 0xcc2d7803, 0x3d18dd6c, 0x8ed8609b, 0xe449a55d, 0xf3642782, 0xedeab3b9, 0xf2c0e177, 0xa38650b5, + 0x6a025e92, 0x0c76991f, 0xde62b7b8, 0x4d6da3ad, 0x24018481, 0xa19790b4, 0x0baf37ec, 0x1aa922ed, + 0x399c57d9, 0xbd0e3ea4, 0x9a0d8ac7, 0x1d1525b3, 0x28cfe2a8, 0xa9d3df2c, 0x9f03dd32, 0x633ce94e, + 0x05ec1c40, 0xc21ad8c4, 0xedbffcf5, 0x3b64267a, 0x0c4039e8, 0x78b4840e, 0x5cab7c5c, 0x86f33e7d, + 0xd0d4152e, 0x29515694, 0x53279393, 0xd55b27db, 0x97f5e47d, 0xa0e6d0c5, 0x4004ae88, 0xab16973e, + 0x4a3d6b34, 0xced40385, 0x7fac3635, 0xae246769, 0xb785bb6a, 0x0e77dc2e, 0xafc4554b, 0x74bd9a9b, + 0xe09cb8b2, 0xa6e0da53, 0x8d20fd61, 0x7e008704, 0x611b9b61, 0x045f9f86, 0x0eaeefd2, 0x72b5dd6d, + 0x80257776, 0x0f9b7292, 0xce3c5eed, 0xa42cb956, 0x447193fc, 0x789725e8, 0x9dbed1a1, 0xfb10265d, + 0xc4b4262f, 0xb29b2579, 0xb2836e53, 0xa59dd050, 0x18ed7a58, 0x734eb0c7, 0x041662f8, 0x4401a1e0, + 0x96d3d569, 0xe7a7c626, 0x414510bc, 0x19d17312, 0xacfae5d0, 0x9c48f274, 0xf8e89649, 0xbbadddcf, + 0x781c8274, 0x0c877f1d, 0xa6a1389f, 0x4811fb8f, 0x69323b99, 0xd76aa1bb, 0x0bca6b7d, 0xca47ad1e, + 0x70c1dd57, 0xefab0d4e, 0xf55b6ab7, 0x2782cca1, 0xee140001, 0x7271ecf8, 0xa02fe89a, 0x3f75615f, + 0xe428c056, 0x9bd5d06b, 0xe66e2fd9, 0x470a1971, 0x2f93e259, 0x8b5bdc0f, 0x2c0cc42d, 0x34919745, + 0x5769b4a9, 0xad633610, 0x1e6dd1f9, 0x56861dde, 0xafd3f84d, 0x2a6e8340, 0x901c53fe, 0xb48c5bf1, + 0x68eb8172, 0x651a6574, 0x437f3b4e, 0xfa4c79c1, 0x476e74bf, 0x21f44987, 0x69b9731e, 0x7837eb91, + 0x51f88a5b, 0x2a660bb1, 0x23857c85, 0x6d08fa47, 0x3239574e, 0x8d2054c9, 0xb31189e6, 0xb4beeb61, + 0x1152209c, 0x515655fe, 0x02e4c968, 0x4a0fc932, 0x68efda12, 0x297fa466, 0x7d28b487, 0x41f868f2, + 0x4a7d333e, 0x3eda6b0c, 0xbd645761, 0x89734ceb, 0xf95b03ac, 0xa54e02dd, 0xa3302f7a, 0xac5ba57a, + 0xb9bbee14, 0xb1675fcb, 0x3802d18a, 0xb99acef2, 0xf14cc76b, 0x79da614f, 0xfeaf1f36, 0xddc833c9, + 0x1f8e18f7, 0x351fb80a, 0xfe2cde4a, 0xbda58643, 0xc354167b, 0x9c529e5a, 0xa917c568, 0xc3493b4b, + 0xd8826bf7, 0x7a2466f4, 0x9813c48c, 0x7369db81, 0xaf2812a2, 0x03b6299b, 0x24080c32, 0xad657aa8, + 0x7331c011, 0x2ad6e925, 0x14c7a723, 0x5f307668, 0x7be2dda1, 0x165c2471, 0x1b716417, 0x1edee9fd, + 0xda893237, 0x75cbcd1a, 0x7a9d67b5, 0xe104b1af, 0x59cf4666, 0xb8ada588, 0x87f515eb, 0xb79d4467, + 0x34c0b7bf, 0xf12f3843, 0x3dfc6eda, 0xce67023f, 0x7b92b91b, 0x11848033, 0xd05908ca, 0x95ca39f0, + 0xa4c2541e, 0x7cdd5b32, 0xa0120435, 0x2460b060, 0x1580f649, 0x1eb2835c, 0xaa4144da, 0xb75d6907, + 0xe67fcf3e, 0x4541d7a7, 0x92730fe9, 0xb8902bf3, 0x2959d80d, 0xe7b3901c, 0x6423fd59, 0xb9be040b, + 0x9a054f1d, 0x759ebdbf, 0x6457d62b, 0x6b267cfd, 0x5b8a9ec9, 0x9fefa455, 0x4150d0ae, 0x3b579930, + 0xe977d8ef, 0x5c92c494, 0xb1fb08ac, 0xe096602e, 0xe609d3c3, 0x94d93f1e, 0x8a029e85, 0x41627ef3, + 0xc506d1ba, 0x77c83d77, 0x41ebab21, 0x02750240, 0x75b8103e, 0x63207b93, 0xfb161dfa, 0x6679ab05, + 0x6e249a96, 0x16682084, 0xb697fc61, 0x10ad230c, 0xda87f379, 0xcc25255f, 0x4c2bc972, 0x062a9c53, + 0xa94e26b7, 0x23197878, 0xb9c10ac6, 0xe3b8b10c, 0xd50e2ac5, 0x603497a9, 0x536cf9c7, 0x5ba46cc0, + 0x866f222d, 0x607f6e4b, 0x5f7fe0d0, 0x2f2e8777, 0x3e843920, 0xcd64317f, 0x8f3ca429, 0x78f344d9, + 0xc5f970f9, 0x451bf3eb, 0xa9e7e008, 0x09591159, 0x271483dd, 0x85b5f7d6, 0xbe130a91, 0x464d3541, + 0xdbf6b7ff, 0x38c4145f, 0xf0cfaffb, 0xb23ea040, 0xe04c53ae, 0xc1c17cd5, 0x17ae6c87, 0x5debd873, + 0x2e81c2ca, 0x2bcb50a0, 0x1366a48f, 0xf86bd375, 0x29d7ad5f, 0x4469db74, 0x8944d318, 0x5f6f38cc, + 0xdd8558c9, 0x41b3955c, 0xa7a1a7a9, 0x764364df, 0xf2e8b102, 0xb43cdb42, 0xbbcdb632, 0x12ebc820, + 0xe7bd2755, 0xed3f9ff3, 0xd5590e9b, 0x777f1905, 0x9a18d695, 0xbc6d7aa7, 0x738ba453, 0xde400c42, + 0x2a0d3c3f, 0x2c90cd8f, 0xc63ffd90, 0x1865d362, 0x7dee26fe, 0x4c920a0a, 0xc949fca8, 0xf68402d5, + 0x474dc60f, 0x6f4179a3, 0x2b3e15a7, 0x61e28b5e, 0xb6b5cf1c, 0xee446d30, 0x7f02c49f, 0x823a5121, + 0x07ec049b, 0xddc608c7, 0xd1d1066d, 0xc8024a5c, 0xd22d3008, 0x19a563bc, 0x4027d29e, 0x8ef28e4a, + 0x6fd7c1d7, 0x255fb109, 0xe6bb504c, 0x09af4016, 0x523152db, 0x088bb7a4, 0xfd79b390, 0xfc983f1e, + 0x54823cc8, 0xda144e71, 0xe081446f, 0xc9c34f58, 0x46179517, 0xd99d6a0c, 0x7e236182, 0x951d16cb, + 0x75812100, 0xf34cab63, 0xbde20e5e, 0x488ad813, 0x76158afe, 0xa1b16356, 0xbd18eaea, 0x77d2da9b, + 0xed1f5710, 0x9e07e0ca, 0x27130277, 0x7b565d50, 0x8f2136a7, 0xba7dc282, 0x736fa20c, 0x5c70d70b, + 0x8e938c0b, 0x982c5d3b, 0xdafee9f7, 0x9d8beb9d, 0xd9a0e512, 0xea206828, 0x5e12c632, 0x6a7775c2, + 0x4619138f, 0xcc12a3b4, 0xc10d7ba0, 0x6e3258c0, 0xfbe588ee, 0xafbf44d4, 0xd1e91870, 0xe51c6ec7, + 0x15972b0a, 0xbb40b62c, 0xaaf87fcf, 0xc99dfe13, 0xea2d046e, 0xc487b361, 0x27795602, 0xbf91e9d2, + 0xa4e3451d, 0x1d037d4e, 0x7cb1c3bc, 0xe800a190, 0xb6f5c8f2, 0xdfdac18c, 0x8ac71375, 0xa2a66844, + 0x68cbcb00, 0x52278c47, 0xa31e7425, 0x49d483e3, 0x7b351834, 0xfac76437, 0xa9cd6808, 0xd6fcab73, + 0xa88c6b5e, 0x84e80b16, 0x376c198c, 0x2159a244, 0x1e1ff850, 0xc7f1d25a, 0xcb4eff31, 0xda728a4e, + 0xacac38cf, 0xe3e7e20e, 0xd2226df4, 0xe27ec887, 0xec2a3923, 0x8c7a684b, 0x79a531f9, 0xbad9fc0d, + 0xa0fcd19c, 0x314b4f20, 0x3c2bf3b2, 0xf5c1e3f2, 0xbfc15d7d, 0xe58fa5e5, 0x986b5ba9, 0x991c8810, + 0x9de63ca0, 0xee0483d9, 0x4f6682e2, 0xfd363788, 0x6d92b85f, 0x3c602702, 0x3bf343a6, 0xf125975e, + 0x22320f23, 0xa8d0e147, 0x31dac0d0, 0x65efdca7, 0x0e695eae, 0xb452200b, 0xe8dcacf2, 0xec07824f, + 0x0b0a7a52, 0x5bf07cca, 0xe0c16672, 0x2b2e063c, 0x5ef92fa7, 0x2ae7fcec, 0x193f461e, 0xda60b564, + 0x7ce022bc, 0x39e7ce89, 0x5ce0886c, 0x983c382c, 0xa94bf6a3, 0x91e628c1, 0x096a9a5c, 0x82f53e68, + 0x6aec28d2, 0x6b0bff84, 0xfdd8c495, 0xbd7b6489, 0x065ec42b, 0x30272d3a, 0x3668b603, 0x7807a666, + 0xa856e94a, 0x15596f5e, 0xc0b422bf, 0x1b323e98, 0x8b0c1bc0, 0x83db9f1c, 0x17b35c56, 0xb6991332, + 0x707354ac, 0xa2dc01a8, 0x3bd84f27, 0xc618a141, 0x831771a7, 0xab0f58a4, 0x8d0a3db5, 0xa1086834, + 0x43b41f70, 0x51c474a0, 0x9dfd9325, 0x3f42d42e, 0x1e539b87, 0xd6ff0915, 0x0da3ae3e, 0x8a3d4e6b, + 0x844bf2e1, 0xb7f4a708, 0x4641df34, 0x5f7adb0d, 0x23349eb7, 0x9f4be522, 0x947d355b, 0x7b997237, + 0x96646b37, 0x94d821ca, 0xf600d230, 0x7a462b9d, 0xcff2e709, 0xea4835e1, 0x826e5d12, 0x17867e8e, + 0x9afe35ee, 0x5900aebd, 0x145a3637, 0xf550015b, 0xb106c24b, 0xd594c310, 0x5cbd6b84, 0x80153b7e, + 0x86088ea3, 0x8f2f4b49, 0x63edbdd3, 0xfd064252, 0x8d187ce2, 0x87e2eed1, 0x9a9b03f0, 0x87606a4d, + 0x1162c94b, 0x5cd1ee04, 0x66f4b6ce, 0x624a4d09, 0x98e51652, 0x03064723, 0x61640de3, 0xd6f84535, + 0x7e5b5c44, 0xc40d9b09, 0x459a1198, 0x7ef534d5, 0xf0454726, 0xf760e220, 0xf07076f9, 0x9b0c3cce, + 0x239ebfa8, 0x7d7a83cf, 0xe6c99227, 0x080bce7d, 0x87b73fe5, 0xf1754693, 0x521f48be, 0xbf03845d, + 0xa264d498, 0xa3399488, 0x218005d6, 0xc1c34684, 0x440538ac, 0xe05a0205, 0x7847923f, 0x70f63a94, + 0x0816eb39, 0x5786c55f, 0x77f57bed, 0x324c4a34, 0x629f3601, 0x66d4b0eb, 0x5d91be8a, 0x1c5fc370, + 0xb8191c79, 0xd22190b3, 0xb2d08949, 0xabb61983, 0x69a2d349, 0xec78f480, 0xd57862a9, 0x2d20ac73, + 0xf197a4ff, 0x37047406, 0xd1ede1e0, 0xd702a745, 0x92311c73, 0xe1e05079, 0x60f1ee63, 0x1e787928, + 0x854cfac2, 0xf7776e51, 0x26de0038, 0xe2a417a6, 0xe8e79fda, 0x3e0c1d64, 0x9b57bf26, 0xc59bd447, + 0xaaddb828, 0xf269c465, 0xe339ad1c, 0x44cc5cfd, 0x949b8aab, 0x78bb5ba9, 0xdd185db2, 0x47a65406, + 0x8a02d9cc, 0xe831be40, 0xc11ec24a, 0x3f8da4b3, 0x02c738ed, 0x383c08d0, 0xb37ac0fa, 0xa13295fa, + 0xd9103792, 0x4f453ef9, 0x61f6c095, 0x38746ab6, 0x78239b66, 0xa541d796, 0xd1310b04, 0x5a57a9d3, + 0xf8fb6405, 0xf9136d48, 0x503d8530, 0xda4903b7, 0x8775886d, 0xc852b76a, 0xf7c73223, 0xc3bb9f12, + 0xa2bfd547, 0xfe226e6c, 0x863c9775, 0x9108df3a, 0xa2bbd52c, 0x3cfd573a, 0x64beed92, 0xde25eba9, + 0x96bf33c7, 0x2cc787ee, 0xb7c0583f, 0xfeae9bc5, 0x655b3376, 0xc28b7429, 0x332c4d29, 0x41d409a0, + 0x196307fc, 0xa6448cde, 0x713d60bf, 0x837c5c0c, 0x469a2187, 0x0ffebbd0, 0xb1bb6817, 0xa2acb8a7, + 0x7ac75e66, 0xa525fd75, 0xa642f6f2, 0xb6ae9118, 0x63fa1f86, 0xcba39c99, 0x71db52b2, 0x634a805d, + 0xc839780b, 0xd04db776, 0xd071809f, 0x87540bec, 0xbb8d5812, 0x762ba23d, 0x1892f496, 0x69c9ec92, + 0x9d386b89, 0x134cc0c9, 0x9c9870dd, 0xae693643, 0x5cde09e3, 0x7052e91b, 0x37f1fa59, 0x783468fb, + 0x231b6055, 0x392ed8a0, 0x03d1c81c, 0xb2201af5, 0x38d250a3, 0x055d664f, 0x12c42669, 0xf78ba427, + 0x485becb5, 0xd53da2f7, 0xd3ebe7d6, 0x7db71f15, 0x497f8550, 0xee855bdb, 0x6ed55458, 0xdb476ee8, + 0x6b32e2ab, 0xe29a8805, 0x5b753971, 0x0fe6b82b, 0xf005ca0b, 0x580e444e, 0xb34a310d, 0x1fcac085, + 0xcf7ed8b0, 0xaac1df55, 0x3f6095cd, 0xd1f680eb, 0x9c3447a0, 0x8ae53106, 0x95ad9b9d, 0xc0bfa7a1, + 0x982b5689, 0x1ae45394, 0xfa8c9903, 0x852be839, 0x2d92283c, 0x0b98fece, 0x87b40e92, 0xd06c691a, + 0x8ae4e0c9, 0x0baf9d42, 0x4d6b7434, 0x5dc3a565, 0xb8418c8c, 0xcd6574d7, 0x3aca2a87, 0x8a97696e, + 0x96853990, 0xcd01e840, 0xb7487f83, 0x03281357, 0x926b4fb2, 0xd3ef934c, 0x6f7d732e, 0x28c80f15, + 0xdc4cc70d, 0xce344da9, 0x525cb2af, 0x8656f863, 0x7d2a3231, 0xf51b70a0, 0x74bfc31b, 0xa5b56073, + 0xa3a76ae3, 0xdfc9640d, 0x6e7122f0, 0xf66dad9c, 0x9a97f41a, 0xb127d42c, 0xd08fda81, 0xbd3733ce, + 0x2766e1f4, 0x915e08af, 0x5a2e0912, 0x1680e0ef, 0xd7d380f5, 0xa092be0a, 0x4e609d00, 0x75c13c72, + 0x26c6b4aa, 0xcc37b1b7, 0x14dc7e0d, 0xfac3bd26, 0xf083ed81, 0xf7ea4894, 0x3dd8e9f4, 0xb577ef16, + 0x95d4edee, 0x6b2aa12a, 0x126c027a, 0x8f575d89, 0x7cad75f8, 0xfa59599e, 0x3ea65731, 0x526a6262, + 0xb209fd9f, 0xc7f3b4cf, 0x98db5005, 0x79a1a77f, 0x94587d3d, 0xe0decac3, 0x1ea4bcf1, 0x1e9a9551, + 0x4d6bce4f, 0x6af8e070, 0x179543ef, 0x95c42832, 0x88031881, 0x950789eb, 0x9fa1be2f, 0xdefeca55, + 0x06342f32, 0x9e6a22b4, 0xeca91d80, 0x59e4665d, 0xabd96481, 0xe7b94e19, 0x8434cb34, 0xa1ee4cd3, + 0x3ebd85e2, 0x9d22ef41, 0x86958b16, 0xb385d730, 0x9b69212e, 0x5b595194, 0x002359f0, 0x6e28f913, + 0xc6550d2f, 0x3bdcd959, 0x2d97b43e, 0x97483ec2, 0x4b702934, 0x06a1a48c, 0x9c60b448, 0xf63ba60c, + 0x15e33fcc, 0xe4e5e131, 0x876bf16a, 0x7971408d, 0x9e2fc195, 0x96ac2cf6, 0xbd258380, 0xe891cccb, + 0xb1e8c50d, 0x68892f5e, 0xe848b7c6, 0xddccc9ef, 0x81b77fd6, 0x59586749, 0xad6a240f, 0x8c0cf087, + 0x77989ada, 0xc79c8638, 0x1ff086e5, 0xbfdc1b05, 0xdfb3eeef, 0x7680930a, 0xceebebe7, 0x7d96ff4c, + 0x8fed690b, 0x8c915323, 0x91827932, 0xafa89429, 0x471aef28, 0x0d0e271a, 0xa8061032, 0x419dfab4, + 0xa4b265c9, 0x1377b993, 0xa5e8af60, 0x3623300f, 0x7a74fa34, 0x70785579, 0x21c80c6a, 0xcef0f09b, + 0x7c46dcce, 0xf639ef8d, 0xdebdecc0, 0x87eb328f, 0xa2d82feb, 0xa1475194, 0x98d55142, 0x3eb4827d, + 0x995cd697, 0x7e33ee6e, 0xabeb5205, 0x504a5eca, 0xf8abe5a3, 0x81bc5902, 0xb04f9441, 0x9c403d10, + 0xbcf8f2ea, 0xd5e25dcf, 0x8de0ba0e, 0xcbdc44ed, 0xb43cd739, 0x7e1b7c9f, 0xd2e3cc5e, 0x024191de, + 0x3eb7de58, 0xe15c963c, 0xedcc5bc0, 0x4c0335a8, 0xa9472050, 0xdb8aa986, 0xb40b7b54, 0x92295cf1, + 0xa4cb9f5a, 0xcdf7f1d2, 0x407cb43f, 0xe14bad5f, 0x7ed97f0b, 0xa6cd9837, 0x009e7468, 0x16471ab7, + 0x4b28c5b8, 0x72d470cf, 0x3dd60c15, 0xdc3fe522, 0xfeb7c592, 0x2894e002, 0xe89eb6f7, 0xfa9e8a6d, + 0xd6ac5864, 0x9b2aa05a, 0x464d0f7d, 0xc599bd3f, 0x569453d4, 0x1426012e, 0xd9564df4, 0x4b30e561, + 0xeb893771, 0x3037e09b, 0xd33de0df, 0x0277c46e, 0x22044ea1, 0xcfda382e, 0x8580a7a2, 0x42c12a29, + 0xfe279fee, 0x4c924113, 0x5c47a3c3, 0xc2d09970, 0xcfa22c07, 0xeb0371f9, 0xd7b02a9e, 0x1fd72c71, + 0xb9d35927, 0x310477ad, 0xf43f5918, 0x8e383584, 0x169da4b2, 0x1b21cec7, 0x149fca04, 0x2f42a6fe, + 0x6f13a3c3, 0xddcc087a, 0x626e8056, 0xa2f8062e, 0x1948367a, 0x8f3e4454, 0xaa78fc63, 0x45688e75, + 0xf8fd3cbd, 0x3f123822, 0xef77ee7e, 0xaadc7403, 0x457c24bb, 0xb2a8a1fd, 0x80c68243, 0xebfa4c75, + 0xbeda23f1, 0x08099d6c, 0x4d31ea77, 0x4c6adbd5, 0x4ad1e291, 0xc2003c06, 0x81a3624d, 0x341210ad, + 0xd77c6195, 0x0b3caca7, 0x866577ed, 0x9c0dc558, 0x7f20278f, 0x006e5e79, 0xade95f3a, 0xf8aafd5a, + 0x10de52b3, 0x0aec9d81, 0x711babd5, 0xbc3af8f7, 0xb45df72d, 0xeafc167e, 0x809aaa90, 0x9e72595f, + 0x5c534eca, 0x652d4d4f, 0x0b1669ee, 0x7cbf0999, 0xc7ffe02e, 0x6b4ca88f, 0xde9fd424, 0xd4b2f31d, + 0x3241f45b, 0xa67f4031, 0x13aad169, 0x4b5a7ed0, 0x9f4479ac, 0xbc0a9653, 0x8018d7c7, 0x3f7cb0ad, + 0x704c79c5, 0xe0daeec8, 0x795c7f30, 0xd112693f, 0xfa26863f, 0x5789c524, 0xb04e99c8, 0x67766430, + 0x6b8c2d3b, 0x73c3ba8c, 0x0d8acc21, 0xd674fb48, 0x982488fc, 0x8fa896eb, 0xed89c44d, 0xb87b3031, + 0x73e5911a, 0xb72df0c1, 0x50fb88ed, 0xf4f9035b, 0x844248c3, 0x3ed3ad3d, 0x128dab10, 0x5d3b6d5b, + 0x3ffb3b7d, 0xc5ff0dc8, 0x076f18c7, 0x65d8e214, 0x3ca3a740, 0x5e28fb4f, 0x026e752b, 0xfd7a55f8, + 0xc75dc774, 0x1d112fd9, 0xa79a9e4a, 0xb7e959f1, 0x1d24db0c, 0x9db65c6c, 0x231d6b51, 0xf06377ff, + 0x428f2643, 0x0869b010, 0x66718a3a, 0x1d85adc7, 0x6d1e0aa7, 0x040e305a, 0x6243063e, 0xcb9572b1, + 0xde1f58ae, 0x4fd91260, 0xefa4260c, 0x9fb9fa33, 0xba55eb83, 0x4424eba1, 0x80bba2c5, 0xb0be75d4, + 0x765f85c5, 0x293ded7c, 0x50b70f01, 0x8b2900e7, 0xe1c29d07, 0xa88b70f2, 0xcfd9e473, 0x6105ade1, + 0xbd20b49a, 0xf3434f43, 0xe0280086, 0x1748ec07, 0xfceb882e, 0x96cb4002, 0x390d11a1, 0xbfecdb81, + 0xb6980436, 0x25a5ac87, 0xcf0f150a, 0xedb7a4f7, 0x92a52d12, 0x3d0f86ac, 0x4bedb567, 0x2bdbce2c, + 0x0af44045, 0x7951f3ae, 0x2b11d3be, 0xa9cb86a9, 0x7f89a4de, 0xf1aedb1c, 0x51f7badc, 0x3d5a2d2f, + 0x8161fdef, 0x2ee72a6e, 0x5a22867e, 0x1c5299ab, 0xda1f0569, 0xbe6d1e6d, 0x98f768d4, 0x6a4c86bd, + 0x4a828e1f, 0x517cb925, 0x8146cc5e, 0xe9820867, 0x91809a14, 0xb2a8d437, 0x7b8ec573, 0x8189d22d, + 0x4c4a249b, 0x0338e8cf, 0x077c8834, 0x62fe39fb, 0xb3203a11, 0x4c65bbc5, 0x504233df, 0x136b3e8a, + 0xdc6b0aa1, 0xd5ce9f98, 0x9752cdde, 0x9ed90964, 0x82a688f5, 0xb714c1c7, 0xfebcdd2b, 0x2a133263, + 0x5e0adc6a, 0x674165fa, 0x3a11131e, 0x21b12e0b, 0xd5c8ea86, 0xc3070753, 0x1c1c3c1d, 0xe43a83e0, + 0xb9fe824d, 0x4926536d, 0x911fd945, 0x442511a9, 0x02e0c518, 0x064213ca, 0x1ea679f2, 0x1a2f0d8f, + 0x3f83debd, 0x8ebb85d1, 0x7143b2ec, 0x4f628ec4, 0x18e03b13, 0x831035f0, 0x4a58c90c, 0x41387585, + 0x42ef3fe6, 0x306f7487, 0x38057959, 0x52b7b0e6, 0x6bb89296, 0xfb2ba1a4, 0xbc38597b, 0x26e4eef1, + 0x521b262a, 0xc5fd0ccc, 0x0b97e5fc, 0x16d386a5, 0x63baca40, 0x81bcb1ab, 0xb56a5615, 0x05dc98e8, + 0xfd005bbd, 0x9a747b6d, 0x4f45cc98, 0x3f51d283, 0x8386a4af, 0x37fd124f, 0xe74b4e3c, 0x87853208, + 0x9b3007fc, 0xca92ae27, 0x58d67d1c, 0xf532fea3, 0xe9edfcc4, 0xbf31a18f, 0x98bfcbaf, 0x1db07989, + 0xbd6c34ef, 0x356b949b, 0xe34796eb, 0x25fbd682, 0x178fa704, 0x2d97e75d, 0xe50cf9db, 0xdfc28f75, + 0x8d2d85a6, 0xa2c953a6, 0xebaee0a1, 0x6aabdba1, 0xc0df967f, 0x72dffb3e, 0xc5f8750d, 0x39d46ef4, + 0x8e3b7097, 0x06c5d9a6, 0x76cee949, 0x2d76779f, 0x1a881c30, 0xa240cc74, 0x9169b02f, 0x9ac30246, + 0x9568350a, 0xee905e49, 0x64b250f2, 0xc6ef6e3b, 0x8a300b19, 0x9072d99c, 0x1a86f29b, 0x495e8e25, + 0xd88cf852, 0x192395d3, 0x64f256ba, 0xfd726f10, 0x794338e9, 0x94f551e8, 0xe7c690c9, 0xe1a4ff6c, + 0xe44b9dd5, 0x27d41288, 0xf89fff9b, 0x320e2dc2, 0xe94ed4dd, 0xa8452d44, 0x5cedf823, 0x09581e11, + 0xd95cb323, 0x1a2164ae, 0x894c4f85, 0x77ed3fe5, 0x0f552289, 0x4584e7c2, 0x7d8519f2, 0xe532d024, + 0x7271a30c, 0x6be9a9df, 0x819b442f, 0x313dcb29, 0x9dea0c4d, 0x47d10567, 0xbc96748d, 0xced65033, + 0x6cea0303, 0xeee6778b, 0x07719eda, 0xfdeb6d58, 0x806fe2c5, 0x54abec60, 0x3d68fb50, 0x1db60aad, + 0xfc86e512, 0x6b20c0ae, 0x784f6523, 0xe2ea9a60, 0xf4e348f8, 0x6ded4a33, 0x30591822, 0xe5a00094, + 0x6e6d3f50, 0x0f11bae4, 0xf282ac9c, 0x8e7ff5ab, 0x5f732d42, 0xf56af9fe, 0xcc6fb3e2, 0x7a3d6986, + 0x318c19cc, 0x61b0f480, 0x4bfc569c, 0xa58b852b, 0x1706b545, 0x864862c3, 0x4e49267f, 0x7ac26a36, + 0x0dbe449b, 0xffea2913, 0x406a98be, 0x5432ed3b, 0x9a1c87bd, 0x762b6a43, 0xdb05ad73, 0x77f6fcec, + 0xfad08f1f, 0x804a6a75, 0x0edd908e, 0x59006ae2, 0x5d81287a, 0x09ded2eb, 0xf8352a87, 0xee2b7d9d, + 0x9dbd0c55, 0x27185369, 0xaca1ed87, 0xa9785cfc, 0x928c1f4b, 0x5e89fa10, 0x86875b72, 0x6f4b5967, + 0x57cb0f5d, 0x685d6b96, 0x9ddef391, 0x71c12ceb, 0xfa810ee0, 0x3270a9b5, 0xf5155a61, 0x2a4e5830, + 0x0c1d188d, 0x5436a97a, 0x201dd760, 0x694afcbb, 0xce02fd27, 0x05ce615f, 0x01239d30, 0xbd5a476c, + 0x1d92d98c, 0xc8a9b51d, 0xfd3fab73, 0x15ec4698, 0xc57c8a69, 0x7cc217c5, 0x3e7a4294, 0x32b7f82c, + 0x7f222971, 0xc20356e4, 0xe5575dc9, 0x5f1590f5, 0x33321fc7, 0x211cb866, 0x2015a608, 0xf59a8f48, + 0x1cf1b98e, 0x438f1814, 0x9cd27d74, 0xc1f892e3, 0xb7bbe64a, 0x82628390, 0x5404c77b, 0xfff36e2b, + 0x7168768b, 0x20c43e0c, 0xbd0c0dbd, 0x126bb5ca, 0x6e4a647f, 0x7e8140ab, 0x3373536b, 0xf86742cd, + 0xbc1d996b, 0xe9a6cf2d, 0x6ff41047, 0x1240e648, 0xce3caa31, 0xe2d9d286, 0x7e6aa887, 0xf5a9b577, + 0xdae19115, 0x043df34c, 0x8d806844, 0x2beb1681, 0xd0c14261, 0x07451e7b, 0x50060a71, 0x0426fc22, + 0x934fe60b, 0x67584854, 0x31fe97f3, 0x2366ecea, 0xef04c967, 0xf200d219, 0x429ea96d, 0x1986cf79, + 0x8b63bf52, 0x6ee2ce4f, 0x04f3e565, 0x2293dc3d, 0xf006f44c, 0x19c443ba, 0x3778d36e, 0x0cb2e10d, + 0x1a150070, 0x62c1aceb, 0xa0395e28, 0x2a102c5f, 0xda0da80a, 0xa24ca669, 0x64598616, 0x04bf468f, + 0x312b9600, 0xdbd258f8, 0xac50fef1, 0x5fd6b44a, 0x482ea8ac, 0x09992180, 0xf2754eab, 0x776ce022, + 0x844bed7e, 0x189f60fd, 0xad27a09b, 0x3f862bb7, 0x715c52cf, 0xf84fa212, 0x9d8a0d8a, 0x965884ca, + 0x0094f9ab, 0x34fa2bca, 0x8b8b563d, 0xbcc98601, 0xa2b8e884, 0xc8f9634b, 0xc2ee9fe4, 0x381e6ac5, + 0x8b75a738, 0xa2f325c0, 0x81c17611, 0x66928caf, 0xf08763c1, 0xfef6d4dd, 0xe4ddb4e3, 0x8898b08d, + 0xfc6c5d15, 0x2d094449, 0x9d368046, 0xf2dbed53, 0xef2e6cea, 0x109aad61, 0xc1b88e02, 0xea9360ba, + 0x42808344, 0x17f6d694, 0xe5f1afae, 0x906881a6, 0x2d6c5bcb, 0x400c00f1, 0xbab4d448, 0x2aee13c9, + 0x2f7ee0c8, 0x2860e7df, 0x4af72c21, 0x84e9a6d2, 0x62f809c2, 0x0ccf45b4, 0xe55a10e6, 0x29d9e15f, + 0x5a780c98, 0xbabac121, 0x4b19fae3, 0x334b347e, 0x6bb2a9ea, 0xa6a44e66, 0xc1a0a6eb, 0x169b64a5, + 0x737d1186, 0x0e1c222c, 0x118d5dfa, 0xd9123722, 0x86777240, 0xb99d9b05, 0xa5787a19, 0x3cf08cad, + 0x84d28e3f, 0x7495c342, 0x835e7452, 0x982d9a48, 0x0a4fe45d, 0x5b868887, 0x8a87ec66, 0x1e310219, + 0xa757662d, 0xde935f4d, 0xa1934d9e, 0x2c1a0150, 0x8811d139, 0x718c70d4, 0x85feb983, 0x3e88c03e, + 0xa8c42b5b, 0xf0bfde88, 0x318a03ca, 0xbd44aaeb, 0xbb63b885, 0x02f41d96, 0x3ad34b6a, 0x5bc59252, + 0x7b622046, 0xe013b37d, 0x380d6833, 0xeb915442, 0x7e44d30c, 0xcb91530b, 0xf99574d2, 0x51392b9f, + 0x8d81bcb9, 0x62d25eb9, 0xd1e6d17b, 0x01f7692b, 0x1c706c00, 0x17e8c984, 0xfece8087, 0x6e1f2892, + 0x7091495c, 0xba332980, 0xeca49616, 0x9dde7d9e, 0x32cf4303, 0xc6a4614b, 0x79a51b4b, 0x38cde5c9, + 0xa875bda7, 0x4347d4af, 0xfae2b255, 0xbf2b2fd1, 0x38f1fff0, 0xfa517ef4, 0x361a70d7, 0xe9f335fa, + 0x5bc9f667, 0xa6c6dc05, 0x0be7ad1f, 0x0f478538, 0x455d8f9a, 0x9f0539d8, 0x679fadb1, 0x3a81e808, + 0x4847b82c, 0x26677a9c, 0x48d84f94, 0x306d3468, 0xd6e1a4c6, 0x38c42c0a, 0x05d539bf, 0x90b0d316, + 0xf82287b7, 0x425aa90f, 0xf92c96dc, 0xaac6c8f4, 0xf13b9f47, 0x87631102, 0x41bc56ee, 0x55013c02, + 0x1b36fb32, 0x9c70f2dc, 0x83be8b1d, 0x51313014, 0xa8aa0a1f, 0x87a5a9d7, 0xf4479707, 0xdaa56b0e, + 0x37d0a9b2, 0x193861a6, 0xe78e5955, 0x7f78dd55, 0xecc60e42, 0xad291c7d, 0x63bdc45b, 0x78fda681, + 0xf8b97e08, 0xde5da045, 0x219da8fd, 0xa015d755, 0xdb056522, 0xbd40e742, 0x0a030ab2, 0x60b177c8, + 0x293e2165, 0xb2fc365a, 0x771f8fe3, 0xe209dbfa, 0x374264fc, 0x51a09158, 0x76fe6750, 0x51818ed8, + 0x36f9c2be, 0x4fd27967, 0x0ccec1bb, 0x6388cd1e, 0x8676b4b7, 0x4d24098d, 0x30edd55e, 0x39a29bd3, + 0xcecdc167, 0x24a81381, 0x5de11c46, 0x0c1db235, 0x59d8f65c, 0xdeb8dc3b, 0x04ab7e09, 0x19b6e8a8, + 0x261c932c, 0x199d91a4, 0xeee92de8, 0xd27298fb, 0x8ec6233b, 0x77d242ff, 0x7b5e8f29, 0xe8ced3ef, + 0x22cd1e6d, 0x8c0cb095, 0xcda56e5b, 0x129ab587, 0x72890e05, 0xb4714048, 0x2d7cee01, 0x5b9ddb2c, + 0x13559be2, 0xe41dbab8, 0x9fef5e4a, 0xd3a6e24e, 0x280a2859, 0x51fd3c8b, 0x5126ab08, 0x59c3e8cb, + 0xa065298d, 0xe362692b, 0x19be4761, 0xad0c3cb7, 0x2deb0b7c, 0x2dccb96f, 0xa4635e8e, 0x399f9048, + 0xb0ab166c, 0x6af86654, 0x9a358b2f, 0xaabf54ce, 0x09022042, 0x500b3e42, 0xfad37379, 0x499b8ca6, + 0x31255be9, 0xa8b103fc, 0x30329d5e, 0xc8545a2a, 0x238e4821, 0xe2c44387, 0x4c2e5618, 0x04126a69, + 0x46142466, 0x74a2c00a, 0x5b088fee, 0x0ad406d7, 0xe6d1c2ea, 0x45eddef3, 0xf11896b7, 0x5c0c7f3a, + 0x1c2d083d, 0x8282f699, 0x11aaa726, 0x03ed7903, 0x12328271, 0x34b56d6b, 0x09006a77, 0x68207bff, + 0x1c1d8852, 0x1227cf41, 0x83f6a8f9, 0xf1b3ee9f, 0xa93d42cc, 0x9a12b3e4, 0x33de6321, 0xc17b51b7, + 0x76f4b9d0, 0xe7c72026, 0xd74a0460, 0x0c56beb6, 0x9d8dab6e, 0x7fe8f3b5, 0x710de518, 0x8d140c31, + 0xd72b8149, 0x9c82ebe2, 0xd90908ca, 0xb9e6ad65, 0x5814597f, 0x88c4ffe1, 0xebf96fba, 0x6362ab87, + 0xf13e8fa5, 0x3f96952a, 0x38869aa7, 0xce9125d4, 0x1b0eb8fd, 0x7707f3ea, 0xafd9b212, 0x4d9aa604, + 0xd9020a84, 0x135b1c71, 0x058992b0, 0xfa636953, 0x7f0d324b, 0x6f7e9769, 0xdef99280, 0x7d6957a8, + 0xc6b0b2ed, 0x05019c40, 0x5da6b19d, 0x0fdf9c65, 0xe2fab8cf, 0xfb2d3025, 0xaf7c1760, 0xe66c7f6a, + 0xdb2382e1, 0x250c6480, 0x4770acce, 0xf0291009, 0x68498dc8, 0x8a9a1e79, 0xdb1a5d42, 0x543076dc, + 0x6ca41ecb, 0x452d4ed8, 0xb0c8ac2a, 0x8a865df1, 0xba5232ea, 0xd22d10ca, 0x69e2b91d, 0x0aa12c60, + 0xaa094660, 0x85019c83, 0x78b2d889, 0x07ce516d, 0xdd09a55a, 0x0a030707, 0xb2a4bf80, 0x986fa017, + 0xb5e660f7, 0x925c47f0, 0x3f308600, 0xadd2bada, 0x73f4a6c2, 0x448b15ca, 0x8d782eeb, 0x73dd2d28, + 0x85bbff01, 0x8ab107ef, 0x151c7fe0, 0x3983b6c9, 0xf335f2e1, 0xcccea0db, 0x7e770c77, 0xfc7a2de0, + 0x0736eacb, 0x6020fd77, 0xfbcf493b, 0xce97c9de, 0x0ff35264, 0x7eaaadb5, 0xcf5310ce, 0xb7444085, + 0xcc1a51d1, 0xf19f2b97, 0xcc7f1547, 0xa0417f57, 0x04e272ee, 0x90f1da3a, 0xd1206438, 0xcaf723ca, + 0xfdcdf178, 0x3739c727, 0x06130caf, 0x1c14c462, 0xd85a4e99, 0xc41fc27a, 0x15a6cadd, 0x160f716e, + 0x9cb35c77, 0xb2a4af67, 0x562c69b8, 0xe04e9f9c, 0x6e28aecd, 0xd790fbad, 0x0e94fe4b, 0x34e58ece, + 0xdaf8206c, 0x505a8c3c, 0xf1c0680c, 0x235c9b3f, 0x6afbcd65, 0x52c5b4c2, 0xbc5eec40, 0xa51b535f, + 0x26e28ca5, 0x569ebf9e, 0x607bba82, 0x521c9649, 0x8b75ec43, 0x4792b6db, 0xa182cf0b, 0xaaee42d9, + 0xd08bfb8f, 0xf6165b94, 0x53812086, 0x0bc64fc6, 0x8bd7811b, 0xeef30c3b, 0x0e005b73, 0x364e39b0, + 0x55e0dbf8, 0xa17a46fd, 0x906c8a9a, 0x08020433, 0xbdb9b5c2, 0x22b60900, 0x44846ef5, 0xa6b4b639, + 0xe6c5aee3, 0x22f5746f, 0xc1f20e15, 0xd0065380, 0x75fe9e50, 0xe46a9019, 0xae7554ef, 0xa0ea420d, + 0x9de55ff0, 0xe4790feb, 0x9e0ac44e, 0x677fceee, 0x3f9a0213, 0x8256d2fa, 0xa3a65ecf, 0x3443c1c6, + 0xe5b49571, 0xa6fa5d63, 0xcf0388f0, 0x1615c2fa, 0x49db1ccc, 0x7b09d114, 0x4a124ebc, 0xeb731fc3, + 0xee484938, 0x2f2cfc37, 0xfae2c293, 0xdd48e2dd, 0xdb3adcf2, 0x31c347ec, 0x99b64813, 0x45540475, + 0x3143e908, 0xbab653fc, 0x678b6a39, 0x4fae05af, 0x6b0fa6fe, 0xcac22e94, 0x7017ece4, 0x471a28a5, + 0x5bb0f2f1, 0x8989080a, 0x78cb1773, 0xcfb23534, 0x81f913f9, 0x99805e92, 0x72fc83de, 0xc43e5c10, + 0x5caad0c4, 0xa801ae35, 0x56799b4c, 0xf2c3d08b, 0x96f33844, 0xff472b32, 0xab31543f, 0x7853929c, + 0x91cb8402, 0xdde21129, 0x2f0999ad, 0xb34300c4, 0x1cda7f5a, 0x9e5680b8, 0x19be8f87, 0xc90e5a02, + 0xbfcf7eb5, 0xdc4acdda, 0x21d9b246, 0x2e8eb3e9, 0xae3bf20b, 0x221f770e, 0xbef19ba0, 0x7c3fed05, + 0x562fb479, 0xd8e73d98, 0x0a62405c, 0xfd03c930, 0x6566d131, 0x9b845a45, 0x7722252e, 0xc8364adf, + 0x43a1f2cb, 0x6c2d4f07, 0xa4fb9916, 0x150c1cf9, 0xe09a504e, 0xde1e85ed, 0xe0134d5a, 0x75a91af9, + 0xc8ae17c3, 0x41e6f64d, 0xc74c79ae, 0x52e79c43, 0x6b6b3526, 0x3fc819fc, 0x94e82132, 0x10354f3d, + 0xb9da20ac, 0x851f6f33, 0xc393fe0e, 0x3b1e5a28, 0x17b3f65e, 0xfa2f6b45, 0x8daab2f8, 0xf94cd217, + 0x69856430, 0xddb99fb8, 0xe0d31cd8, 0xddda2dd5, 0x63e03131, 0x0f04b8a9, 0xd7a97715, 0xd35897e8, + 0xc1a4d566, 0xa714e6a0, 0x51fa6ad8, 0x6e1304f6, 0x1f1233ab, 0xd182cd1b, 0x30ea491d, 0x1757ff82, + 0x70079191, 0x5d7c7087, 0x4bfa8aea, 0x5b490f32, 0x3c9db81a, 0xb98476f3, 0xb4c7032e, 0x0359831b, + 0x783c0459, 0xb8219039, 0xceb5682c, 0xe820aff6, 0xe73fdaa0, 0x02278559, 0x06bcdba5, 0x278e9361, + 0xab4f59a9, 0x78b6e3d7, 0xb5f06589, 0x888e17ed, 0x6a7e1e0a, 0xdec289aa, 0xb73e47df, 0xda7be4ec, + 0x7d382302, 0x865c547a, 0x920de44a, 0x786da59e, 0x7a507208, 0xb87cfeaf, 0x089b8d11, 0x89beaec0, + 0x3bc4920d, 0x3b9a4e5b, 0x8aa3e592, 0x2250a426, 0x17523bd1, 0xd88e0466, 0xa32b3807, 0xd9272c96, + 0xcf7028c1, 0xb51a5053, 0xb93f387e, 0x8e29e75e, 0xb4a0f51d, 0x51925648, 0xe7040506, 0xb3b62bf4, + 0xc1e9d205, 0x85019f35, 0x12f1781a, 0xce3c8302, 0x02e08272, 0x38ce83f9, 0x066158c8, 0x2e732fae, + 0xc9370121, 0x93a88860, 0x42456972, 0x4d4975c6, 0xe48daf99, 0x4b0073e3, 0x87b3371f, 0xbabe33ad, + 0x06add468, 0xe27394e3, 0xeb862501, 0x12b8a5c2, 0xc7a81e13, 0xb7dee781, 0xcd4c6320, 0x2c4e3653, + 0xad56c7f7, 0x3d7b1636, 0xdb1dff70, 0x0152478c, 0x57678c82, 0x5ba1e90e, 0x0c25c626, 0x9484a5d9, + 0xdef096be, 0x2e2ae264, 0xcb73474c, 0x8e41e450, 0x3266e454, 0x443d94aa, 0x0f466cbb, 0x5892fcdf, + 0xbe48d0b6, 0x0c08aef1, 0xbda1a7d9, 0x2167cd39, 0x477a065e, 0x69a5640e, 0x45e1b8e2, 0x662d08f4, + 0x54e5648f, 0xe92ccb9e, 0xd6d0cc63, 0xc3d801d1, 0xc26055ac, 0xc8b2ec46, 0x18340c8d, 0x87fd8395, + 0x575bebe1, 0xedbb42ae, 0xaf220ce2, 0xcebc9d20, 0x24139591, 0x162a4696, 0xb5e1d4ce, 0xa6ead4f8, + 0x4ca147eb, 0xaefd529d, 0x8378b8bd, 0xe5e618f0, 0x50dd51d5, 0xbd7f4d70, 0x1f23a255, 0x1b2ea940, + 0x65669d80, 0xc50aec25, 0x8f2a8ac7, 0x7b02cf2c, 0x5583fd7e, 0x2e01ce75, 0xd1053183, 0x80a22185, + 0xfafd3aa2, 0x9941270e, 0x9d41e508, 0xb296704d, 0x424b082e, 0xac86f10c, 0x78599df1, 0xe40105c8, + 0x19385a99, 0xc32f3f45, 0x73e4c83b, 0x21a100f3, 0x7af534c6, 0x4fdfdf5e, 0xb090f916, 0x615b14ad, + 0x47e773a6, 0x4dd8f415, 0xed3f3ea3, 0xf843c719, 0xfab65704, 0x8f9abafc, 0x8cae2a1b, 0xcc42dc3c, + 0x3eb38b7d, 0x37c1ad19, 0xfe84b1a2, 0x430b0f3c, 0x97918c3e, 0x685bfe4d, 0x4d5484e2, 0x08307bfb, + 0xc08854e2, 0x0fde7e87, 0x82d4e007, 0x52b419ab, 0xec186edc, 0x342d57e6, 0x4e648b51, 0x6a880fdf, + 0xa203abd7, 0x1f0b66a3, 0x8315f8d4, 0xac9806fa, 0x1b145f0d, 0x021c3b5f, 0xc3c8c9b8, 0x55bc5919, + 0xddbe64ec, 0xacba8798, 0xc600dcea, 0xb51f2769, 0xfce04255, 0xb0a02496, 0xa4979b83, 0xe2437d15, + 0x9b6486be, 0xdf2370e8, 0x6d4673f0, 0xce33a28f, 0xb0bcab09, 0x174a380a, 0xadff90cb, 0x4d2e5bb2, + 0xd4574a21, 0x0f508771, 0x469ca194, 0xae59ad60, 0x038d3ce6, 0x215e0da3, 0xc2ecbe97, 0x8b53f7f7, + 0x5fc51577, 0x0fb59a1f, 0xc16fb18c, 0x5544c4a1, 0x90affb97, 0x84f72a17, 0xfe1b2731, 0xc25afe29, + 0xc5ebea24, 0x4fb47e03, 0xf98e1e71, 0x80da9204, 0x2f6d71bf, 0x0a4b4608, 0x56aa7817, 0x545134be, + 0xfc083f7d, 0xd7046f2a, 0x12ab8c29, 0x60c77e3f, 0xd349e680, 0x42251922, 0xf927b604, 0x4479be3a, + 0x3fdc40d7, 0x32b8664d, 0xaeef3c7e, 0xc84f65e4, 0xeb6a47bb, 0xd393962a, 0x871b85f0, 0xb4976b02, + 0x7249c355, 0xf1e02d67, 0x9dbdd0da, 0xba6f5f91, 0x209b6b01, 0x71ca5039, 0x45f8c3ca, 0x5381d683, + 0x0f800558, 0x851a0694, 0xf4d35858, 0x558428e5, 0xf4616d2b, 0x3dad9fe3, 0x1f1a0737, 0xb5d76cbe, + 0xa9d5c2a1, 0x6e8b144c, 0xd8e776f7, 0x3ccf6d45, 0xd89d3be7, 0xcc8d4e11, 0x96425605, 0xa7735b65, + 0x4a0545bc, 0x2335a57d, 0xd24ee107, 0xe34b0730, 0xda9e7f46, 0x4a41e305, 0x3851ace1, 0xeb83678e, + 0x7c5a189c, 0x7f96e7c7, 0x4c5bba58, 0xf879cd9c, 0x773889c7, 0x8e895da9, 0x1a7d23ec, 0xeee6b50f, + 0x74a9bcf5, 0xdd799eb4, 0x2596d282, 0xb79f18a4, 0x5a167448, 0xb1946dad, 0x31bcf79c, 0xc9fa7475, + 0x9d4a19a5, 0x08f88bde, 0xb7201a22, 0x02037117, 0xdb2e8405, 0x0301eb6c, 0x53bf1e46, 0xb4b351cf, + 0xc02db365, 0x794677e2, 0x3c8c3883, 0x0e33ae07, 0xe447928b, 0x44a688fc, 0xa511266d, 0xb1ea8a7f, + 0x1bbfc947, 0x7248e27c, 0xe427804f, 0x943cd244, 0xe5c4eea7, 0x0ecd2d27, 0x26912681, 0x1b7d4582, + 0x85b59010, 0xe96f06f8, 0xdfa516f8, 0xafaa6fd9, 0x02b33904, 0xdac1f70f, 0xccb9e3ec, 0x8af6e5bb, + 0x2e0b9490, 0xf0c4c190, 0xabf293ba, 0x02b23280, 0x31c8456d, 0x539d0603, 0x17822935, 0xab1e82d6, + 0x9c537329, 0x8a0f5d85, 0x7f46dc30, 0x605bc0bd, 0x4870169c, 0xa6c2821f, 0x6f866c19, 0xcc64662b, + 0x53d08d0d, 0x911e43b4, 0x5c5ebf40, 0x21808dcf, 0xbe5989cd, 0x97b738ed, 0x7838e7a7, 0xc27a0a14, + 0x0e326d51, 0xe7e9e8b4, 0x2b47ed13, 0x49e0fcb3, 0x8957921b, 0x2b8393a9, 0xa24b0448, 0xa54daaf0, + 0x54d3a35e, 0x1752bc49, 0x97249235, 0xfb9f807d, 0x511e6334, 0x0d3d883e, 0x26ac73b1, 0xc055433b, + 0xe55d9ccd, 0x2bff1f77, 0x5a75af46, 0x13907cbb, 0x912dca51, 0xd0d25990, 0xf541ca1e, 0xa3f1d20b, + 0x2784c838, 0x124811c1, 0x1cf4e2ea, 0x228fa274, 0xe5449f84, 0xe0f60708, 0x26b77a49, 0x73fc8c9a, + 0xe39d6ee7, 0x3a3a040a, 0xacb2bc7d, 0x9411dde6, 0x8dc5534d, 0xe05e2641, 0x6c75f82a, 0x84c4a31d, + 0x574047a9, 0x7ab1a9c4, 0x303e2878, 0x5c610ebf, 0x5df32e33, 0x0828329b, 0x0eb8b3cb, 0xac6cbbc5, + 0xb6009851, 0xfa2d6046, 0x4adf4270, 0x4a575526, 0xf955dfdb, 0x172ff948, 0x44cb96d6, 0x3db7c0d1, + 0x87c3d961, 0xf4a73393, 0x8b5514a8, 0xb9902d46, 0xc4b9268d, 0x62f9cf93, 0x11cc12ba, 0x368b69bc, + 0x69907080, 0x770f025f, 0x103e705c, 0xe8514830, 0xa5b4d1a8, 0xf4e7263f, 0xcbecc9a9, 0xe782a5d2, + 0x7448f502, 0x8fc176cd, 0x1cc0cdb2, 0x94f39606, 0x87dcba49, 0xa3cca083, 0x089e4881, 0xa52ce3da, + 0x9cd73357, 0xe07ecb4c, 0x7ceb98eb, 0x59a9f85f, 0x9fc0b048, 0xb9353484, 0xaa7869cf, 0xd0bad68f, + 0x90ffea1b, 0xc9addf86, 0x727e85b9, 0x2a6e41d3, 0xdbdd28f8, 0x4c5a92f1, 0xeda2955e, 0xabe15c39, + 0x3a62326d, 0x3526b9fd, 0x70f04c0a, 0x40fecb2a, 0xd31a3630, 0xf45b54f0, 0x4f212aad, 0x952f608c, + 0xc45214ee, 0x36253dd8, 0xc5828223, 0x869b3876, 0xdf6c7747, 0xb381d8ce, 0x1bbcf791, 0x393ab11c, + 0x9fa66f4a, 0x22fd7118, 0x6bbe38ce, 0x6321cd98, 0xfef4c550, 0x87104bd6, 0x31831400, 0x884b9072, + 0x996ebbc2, 0x95974a23, 0x8c79e328, 0xbd03e85b, 0x7053ef4c, 0x3021b2ed, 0x055e0384, 0x281e3403, + 0x4dd337ff, 0xd5c16136, 0x9d7fdb2c, 0x3d3d9371, 0x2faf0556, 0xaf280849, 0x419fbd92, 0x75e8d673, + 0xf58d2076, 0xc7749dfc, 0x7a106c78, 0xdda97e98, 0xaa727a21, 0x5b0fecf9, 0xf57de63a, 0x8da492e0, + 0xe42adc21, 0x940475df, 0x3dc2fd61, 0x18828384, 0xb31cbf40, 0xdac1b738, 0xeca70dc0, 0x0175e1f4, + 0xe47f30b0, 0x350ae606, 0x6072ad72, 0xf01ce58f, 0x59364100, 0xe471b841, 0x6911d841, 0xf8aa3040, + 0xc63a7dd6, 0x4c01bade, 0xe88fabd1, 0xfdc07c79, 0xd89c02df, 0x0e112eb8, 0xc916ea36, 0x53078a92, + 0x44781527, 0x5dc0c1c2, 0xfe2258b2, 0x42d7f6b3, 0xdfeb6722, 0x3ae55cd7, 0x1db24acd, 0x47337cd4, + 0x9a467a92, 0xb58245b7, 0xccc57199, 0x49c6c25c, 0xa4d114cc, 0xc4b368d9, 0x558d9339, 0x72520a09, + 0x3a125fba, 0xf29591a8, 0x10ad113d, 0x0b49363a, 0x1c94cc68, 0x6eeb8941, 0xfef39d3c, 0xc0e9725d, + 0xca09b86f, 0xf712eac6, 0xa93ff0d6, 0xf5d2de0f, 0xf5cc453c, 0x0ee6d6b2, 0x714efc5a, 0xde38edee, + 0x9effdc43, 0x72c84a14, 0x8e3f44f7, 0x694ef4b6, 0x4fa58142, 0xb9158860, 0x6aaafe7e, 0xac5739dc, + 0x739bb485, 0x96421e57, 0x07ca328e, 0x8a6bba95, 0x9af65640, 0x6eea9244, 0x414a1dbf, 0xc9a2b941, + 0x1c77cd91, 0xab6436b3, 0xea5e7cbe, 0xfa7ebe9f, 0x7dcb8c5d, 0x01eb6130, 0x4d7aac32, 0x65522743, + 0xeff8fe2b, 0x257fccd9, 0x7095879c, 0x6d34c1c7, 0x792d9fda, 0xe2e32ecf, 0xa76803a8, 0x4bf2a89d, + 0x160ad04c, 0xf5a5127f, 0x38986962, 0x3df7ba85, 0xa0ab380f, 0x8c9080ec, 0xc0b56b5e, 0x175064ff, + 0xe1327c45, 0xf8797c53, 0x4ae36fb9, 0x9f42756d, 0x8190abb0, 0x4f30fe10, 0xca956485, 0x41f7878c, + 0x47e21865, 0x74acc108, 0xafd7a862, 0xe4d5c089, 0x588fabdf, 0x18a168e3, 0x6d46a6a4, 0x7f55ae51, + 0x63f1100b, 0x716ab2e9, 0xd37af3c6, 0x975d6888, 0x52a18afd, 0x325e43f6, 0x9c2c1403, 0x2c10c929, + 0x77080931, 0xbc645a22, 0x60890a13, 0x3f098a4a, 0x307d20f7, 0x7d2db4ef, 0x0e2a1f6d, 0xcc79dda7, + 0x6c918ef6, 0x2242443f, 0x7f8b4a7b, 0xa52944f6, 0x845bc936, 0x47e6df24, 0xc19d0740, 0x852dce9a, + 0xac2aaf73, 0x77848b79, 0x9fbf034e, 0x4798e736, 0x2b11ad2e, 0x799709ee, 0x5445e9da, 0xd90c1031, + 0xaecf909a, 0xcb76304b, 0xf8bdb607, 0x17fe03cc, 0xd2fb693c, 0xde0b4b30, 0x80cf6f30, 0xde703f38, + 0x4466f2d1, 0xb6d93b55, 0x05c4ecfd, 0xe74f9928, 0x61add1a2, 0x8cf23588, 0xc36a13f2, 0x8d9032d9, + 0x29f9f2ef, 0x25712031, 0x43fe6bdf, 0xe6520ea4, 0x12752532, 0x15b51701, 0x01599121, 0x20f4e4c7, + 0x7f327d94, 0xbf6c8e41, 0xfb89a119, 0xbb3f4f22, 0x1b045633, 0x423d1179, 0xcdec7c02, 0xd00cada9, + 0x4c4f435a, 0x34f12ae4, 0x2b453f00, 0x844f9ed2, 0x404ed2c1, 0x8207e631, 0xdf713feb, 0x6c2ea443, + 0xa3f10772, 0x06002fb0, 0x190e9fe7, 0x4835f316, 0x8cc7d467, 0xbb63b3de, 0x59c9e85a, 0x7cbce96d, + 0xa32d7511, 0xa05f49a8, 0x18e44738, 0x99e2881a, 0x1a1c65ba, 0x52a074b2, 0xc66214b8, 0x0a23f1e4, + 0x43ee977f, 0x793268db, 0xcb60b468, 0xc396580e, 0x8fbc86a9, 0x52b64217, 0xe07258af, 0xea45046f, + 0xc28f4249, 0x0243ae45, 0x781b350c, 0x3c8db5de, 0xe02a6744, 0xf16fb287, 0xebba8146, 0xa12c2c46, + 0x0118f35f, 0x5ab07478, 0x79d10ae3, 0x4d2f8433, 0xecee9504, 0xa8a56b42, 0x2c89dcdc, 0xf132f3ca, + 0x5be4738a, 0xfd682d03, 0x1558c510, 0x10c29cec, 0x648327aa, 0x42d99ff5, 0x16d9aaec, 0x16edc57b, + 0x1c9e002d, 0xdf964b20, 0xaa26878d, 0xa180f8ac, 0x5b7a6452, 0x4e7a91ad, 0x3c4e8b41, 0xf589653a, + 0xb845336f, 0xfc7f6900, 0x375ae30e, 0x72c816d3, 0x2a019e9d, 0x86050417, 0x538d30ab, 0x4dfe4768, + 0xe1203d22, 0x87aa4bb6, 0xa1d5b5a8, 0x1d3a5a2b, 0xcf162c49, 0xb5754201, 0xc078bc45, 0x2eb8bc17, + 0xf3a8c9ab, 0x44d0bfd3, 0xe54e9034, 0x8ad26cb2, 0x3a601b6c, 0x74350b59, 0x4d60dba0, 0xeaf657be, + 0xeaa9a290, 0x97631b2c, 0xae957122, 0xe2d734ea, 0x243334e2, 0xc4e5344b, 0x71045cc3, 0x0ac8fe88, + 0xccaba58e, 0xe926d978, 0x8f8bb800, 0x729b7de8, 0x16ddb088, 0x3276a59e, 0x64b7b100, 0x397b99ce, + 0xed42f9f2, 0xc97371e4, 0x0365758b, 0xd09c79d6, 0x779cef6b, 0x325d6031, 0xf92fb2e4, 0x4a7c3708, + 0xcecf7eb1, 0x28af05f7, 0x7638d9f0, 0xbce7d5d0, 0x8bcd7934, 0x7f8b008b, 0x096092cc, 0xbefc715c, + 0x6b7fb44a, 0x666c680f, 0x923c6ae6, 0x9e62b68c, 0x45b0765e, 0x058f4f7d, 0x99479a52, 0xf77e3ca7, + 0x5c8147f3, 0xe1fd6e71, 0x329c2424, 0x4d8b1439, 0x391c4157, 0x2f81ea05, 0x4f258913, 0xbee81117, + 0x9c6cead7, 0xdccdc450, 0x82783edb, 0xf7a90950, 0xc0b38a63, 0xe2ff0857, 0x2d8ae8bb, 0xa3914280, + 0x85c696f1, 0xff78d177, 0xfe4234c8, 0x7a2a3360, 0xbf8b9050, 0x6bb8c17d, 0xedab5be2, 0x751403dd, + 0xb937358c, 0x02351782, 0x2ffaf806, 0xd04efdd1, 0xc963cdd6, 0x806bca25, 0x22598d36, 0xf4bd965f, + 0x5fb1bdd6, 0x206698f0, 0xe3f19cea, 0x6da7524a, 0x78686a54, 0xb83d320f, 0x0cbbace2, 0xaf196879, + 0x00d735aa, 0xfea1b8a3, 0xf7ddf942, 0x2dca3d2e, 0x231f3f13, 0xbb268623, 0x51dc2a20, 0xf96cdf4d, + 0x3b69cf2c, 0xddc0d16b, 0xa78b78ce, 0xb0aec46f, 0x14e08dab, 0x2c685ca8, 0x2c5d71fd, 0x7e976879, + 0xf9df0162, 0xf12a3bbf, 0xf95f7185, 0x9a65b4fb, 0x00991b64, 0xe21dfae3, 0x70feca9a, 0x4113fa67, + 0xabfa90e6, 0x22527475, 0xb0987ba4, 0x5a0fa416, 0xa9678934, 0xbc5bd5ba, 0x0b8ad9a9, 0x2ea851d5, + 0xf808dba2, 0xc87f523d, 0xe9965f29, 0x8c22c7e8, 0x50c99652, 0x14d359d6, 0x3c2c5256, 0x02009120, + 0x83f29918, 0x958b49a7, 0x2879ba7a, 0x1272adc1, 0xc4297138, 0x269ec070, 0x8e1a0b1a, 0x96e36825, + 0x7982d0ad, 0x8c26982e, 0x17cdb306, 0xb0f1bd15, 0x342d9bea, 0xc3df069d, 0x3fa00e03, 0x30c1474e, + 0x1eded34e, 0x0ee1e922, 0xcc614d34, 0xf83a82cd, 0x22da54ee, 0x70caf6d5, 0x073e4638, 0x27af5e2d, + 0x88ba40b6, 0xcf7e2ed4, 0xca3abd9a, 0x18cfc05d, 0xbf0e31b4, 0x9b8051af, 0x39380f7e, 0xc22c5017, + 0x476c9453, 0x6b3ad286, 0x3d7b95b9, 0x7b8835e6, 0x49ce6275, 0x3ca0d808, 0x116bbb60, 0x63a9f946, + 0x37800138, 0xc90bc393, 0x4718b647, 0x182582ab, 0x3a464a47, 0xa70f052f, 0x2bc70b64, 0xf3623b9a, + 0x2bc2a880, 0x4682fdeb, 0xca05fdee, 0x7430c3cf, 0x9eee1a27, 0x7685ee2e, 0x581f5ac1, 0x9a6e47c5, + 0xf0c1ca36, 0x838e938c, 0xa00fe931, 0xc42324fc, 0xbea8dba3, 0x746c8b19, 0xe41bea33, 0xf7bb2068, + 0xcf66f676, 0x9910c1dd, 0x2ca15bd0, 0x99841d97, 0x2078aa90, 0xf38edc5d, 0x5aff9786, 0x38f411d9, + 0x4d94165c, 0xedecd4bd, 0xff331998, 0xcbc34e48, 0xb96c660d, 0x8d2b2eab, 0x197f07c1, 0x3e902717, + 0x15d2e873, 0x26d00256, 0xd5ee6ed6, 0xc9f5b9ea, 0x263bb67a, 0x35bc4404, 0xd56e56fa, 0x45a36df6, + 0x4b77ab19, 0x55e6d7a1, 0x802a9c09, 0x3c709f10, 0xce825e32, 0x75b1b742, 0xba4f5102, 0x9851bd12, + 0xfb3b2805, 0x8540e869, 0x6f29bf1f, 0x65691ab7, 0x20adacfb, 0x9ecc6000, 0xdf1e6f81, 0xd93a116b, + 0x7f7b896f, 0x58d97c46, 0x71170473, 0xe78b7cd2, 0xc131186b, 0xa9bb7274, 0x8bf5b1c2, 0x0adc9703, + 0xef46f110, 0x194127b0, 0x1fc66fb6, 0x50ef386d, 0x0edc04dc, 0x8a916064, 0x3e175b0d, 0xad0d08de, + 0x6fe0f8ea, 0x7b3a3066, 0x494b4a57, 0x6f333e90, 0xa4d6d464, 0xa72da6c1, 0x39a33310, 0x6a690e8b, + 0x572e6ed6, 0x612bc5f2, 0x58985c1b, 0x1967d4ec, 0x6a57a70c, 0xeda4024c, 0x640908ac, 0x761a470d, + 0xc5fa951a, 0xd4f74561, 0x2d6d1c55, 0x2a893dc4, 0xa9f87e79, 0x2a406da7, 0x383b366f, 0x4b0830de, + 0x31d1603b, 0xd1926218, 0xecc199c8, 0xced77f75, 0x7e2c84ea, 0xf6ddd66d, 0x37d653ec, 0x72c6aa82, + 0x9a89bc87, 0x335740ed, 0x72a013af, 0xabb848ec, 0x7cf31747, 0x973026c6, 0x687b4a80, 0xe10ba693, + 0x453e4236, 0xbf50de1c, 0x6270d1f8, 0x2f08a982, 0xc2d6d715, 0x818ab232, 0x3c709e1f, 0xe7bc0ae1, + 0xee5d6563, 0x56dd6888, 0x74ec8db9, 0x8d7141bb, 0x1ac228a1, 0x79843ea1, 0x6d04b06a, 0x6496c52a, + 0x99e22461, 0xa6f18d84, 0xb7e7cae2, 0xa330564a, 0x766bf641, 0x9753bea0, 0x31220671, 0xcf622623, + 0x959ddf2d, 0xf58aca26, 0xabf8cb05, 0x87b9451e, 0x7311d519, 0xbbe1e939, 0xcfab4900, 0x956db601, + 0xde7bf6a9, 0x79afcf3a, 0xf10ac173, 0xb2a90f8e, 0x7bb189e7, 0xec858fc4, 0x83967908, 0xe8923d4c, + 0x41ac10d9, 0x0be44f11, 0x258b7713, 0xed624685, 0x808a301b, 0x768d50b4, 0x1bc75161, 0xf65b1663, + 0x8c791701, 0xc7f4e495, 0x5fef1db6, 0x6a83270c, 0x01b8b97d, 0xa10e5522, 0x8d678257, 0xe0e15027, + 0x5cc63177, 0x30408197, 0xe873ceee, 0x7a4dfa06, 0x7679b42e, 0xd0f6461b, 0x1cc433a6, 0x3c6540bc, + 0xa2cb9043, 0xc1b2bfa3, 0xea92f7eb, 0x1525f9a0, 0x899e16e5, 0xbe36ee35, 0x2da113ae, 0x651f579a, + 0x45dbcbed, 0x74e7c6aa, 0x9f5242b4, 0xf09328ec, 0x5a414186, 0x1cd471b7, 0x83af36ed, 0x81cf749c, + 0x4f877026, 0x976535b9, 0x0ae740ee, 0x9a86e52e, 0xcb4d414d, 0x293ca9d0, 0xa9816338, 0x2c0b9618, + 0x026bf710, 0x22e4fe81, 0x943c9bab, 0xfeabb50a, 0x9ae26872, 0x3f52f679, 0x147b6443, 0x9079e512, + 0xb258ee5f, 0x92bddf88, 0xfb25c6b0, 0x43767174, 0xca73633f, 0xe37b6895, 0xeb6ab54a, 0x64d25cbc, + 0x5390bee0, 0x74da549f, 0x94321d77, 0x1f84001f, 0x8870dfae, 0x9e79a0ba, 0x41c730f2, 0x6e5c557e, + 0xe31749d1, 0xbb7adf80, 0x01e34bac, 0xdcf0bb9c, 0x074426f6, 0x563aebc0, 0x687e34df, 0x3dd549b5, + 0x6d4290c9, 0x0b5eac08, 0x016c4beb, 0x296ca22d, 0xb061b943, 0xf5811b48, 0xd54bb20e, 0x7c9b1fb3, + 0x5065ff74, 0xdc97b07c, 0x182a480d, 0x76b8da06, 0xa5950daf, 0xea41a64a, 0x025cd399, 0xfd996dcb, + 0xcbbeeab9, 0x439a5666, 0x189c011d, 0x037df3da, 0xd52c7156, 0x9c3511f1, 0x389bc660, 0x626e697f, + 0xf6c8cd20, 0x6ef8a245, 0x034b034a, 0x62c2c9a4, 0xa820b2af, 0x763df675, 0xc6aa2d30, 0xeb888d6c, + 0xd982b7bd, 0x34462715, 0x19ac4c3b, 0x609c9bb2, 0x88de940a, 0x1c0ed1df, 0x668dfd4c, 0x01a09331, + 0x22b94b5b, 0xe40e67bd, 0x0a3a0a90, 0x5272ccbc, 0xb41029ad, 0x291ca3ec, 0xa78b375f, 0x5081fb5b, + 0x4788f238, 0x6a779b13, 0xf4ae5881, 0x3122e7e8, 0xd636dff7, 0x1a01b13e, 0xf98171ff, 0xca3c95a7, + 0x8fe47d91, 0x2980ad7f, 0x2b57e214, 0x23f7c638, 0xb6d4ce05, 0xe517994b, 0x833f5d98, 0x1bcbac42, + 0xfc8199c3, 0x5126875f, 0x84660fe9, 0xae4081fa, 0xaadfaf4c, 0x8d73848b, 0xb9811d9c, 0x296d0cd7, + 0x1e9f5b03, 0x01955609, 0xde6fc654, 0x6a1a4f8a, 0x8b890eda, 0xdfc1c2d7, 0xfcc94329, 0x7ede3202, + 0xc58bd63d, 0xa08ee996, 0x926dcb34, 0xf9172753, 0xdf3f074a, 0x6fed7d04, 0xcefd088b, 0x07e2379d, + 0x939f3845, 0xad2324ab, 0x67f8f588, 0xca46b6a9, 0xc1a3f0ea, 0xb7b3996b, 0xaa30035e, 0xbaa7bee3, + 0x7f2a7eb3, 0xbcc9ab10, 0x3100a8b5, 0x47c2a16c, 0x4daf20f4, 0xadcb6564, 0xcbbb8b0a, 0xb3523780, + 0x7620fc53, 0xff1ea9d3, 0xc31af601, 0x372a6810, 0x4bd9819c, 0xd3c6ac88, 0xd39d52e3, 0xbabfde0f, + 0x5ee0c727, 0x67379d27, 0xad23f878, 0xd9c3e59c, 0xd038961d, 0xbeda9e5d, 0xf2b42192, 0x93a0fec6, + 0x1f36329d, 0xcdade6c0, 0x4900b990, 0x4bdb9e93, 0x3fac022e, 0x82cdbaf2, 0x20f7891b, 0xfbcf2306, + 0x7a877c15, 0x1f123df2, 0x52ac62ba, 0x9e04fd76, 0xe80c2f53, 0x060e1a6e, 0x7f33e49b, 0xae9eaf96, + 0x1cd01c7a, 0x4da224b5, 0xb2e8d047, 0x2686e83a, 0xbb1b774b, 0xda8c1399, 0x5acc3d8e, 0xe20045a6, + 0xf5e6806c, 0x2d590430, 0xca86c798, 0x1812b4fa, 0xabed7900, 0x4f33209e, 0x051d7bcb, 0xd21443a8, + 0x322eb0ca, 0xd9c1981d, 0x5f782c42, 0x18bc8420, 0x424113f3, 0x8954546e, 0x0276268a, 0x46e8b452, + 0x29ed90bd, 0x3d2dfb45, 0x41969ef0, 0xcfe57f6b, 0x62f71b2a, 0x12e4e0a2, 0x6171d013, 0x5dee7e57, + 0x3fd9255c, 0xc5b322c2, 0x42fe4be2, 0x2d9b8c52, 0x4b495e84, 0xf93ddd63, 0xace32008, 0x1a72b486, + 0x96c33e12, 0xae77f964, 0xb505dd27, 0x95f10365, 0xcdb17874, 0x34379f37, 0x164dec4f, 0x030c54ee, + 0xa7510042, 0x334cd1bc, 0x65fc0d4a, 0x174193de, 0x130832aa, 0xa815128c, 0x20b6f220, 0x9f5f7431, + 0x359ff152, 0x9141db46, 0x7c9b9cdd, 0x054ca882, 0x402f67cf, 0x8b926dc1, 0x3b691f44, 0xb50181db, + 0xa7b89278, 0x7acd6484, 0x217b004e, 0xce1b2a1a, 0xbdaae6cd, 0x81921232, 0x8ecf45a0, 0x63c1574e, + 0xb5643ff5, 0x170b2bb8, 0x109838fe, 0xb89113ca, 0x73247ff6, 0x5a8e9035, 0x3e6d0861, 0xe8d2c820, + 0xbfe9f5a9, 0xee472775, 0x0d78cc7a, 0x596649a7, 0xa9b7bfd3, 0xa85975c9, 0x6dddc6d6, 0xeb659cef, + 0x53585cd0, 0xa5eccfb8, 0x92c773af, 0xb54090a1, 0x0c6af1e5, 0x1235d1ff, 0xa7576147, 0xcd767ce0, + 0x3c3216f5, 0xdb2f6f11, 0xf340ee76, 0xcba34c91, 0x250324c7, 0x1107dd3a, 0x72ba2185, 0x34cc9ebd, + 0x693a8257, 0x39172a93, 0x7f2eff28, 0xdd50cd7d, 0x8714505b, 0x686546c9, 0x90837af3, 0x0ad44adc, + 0x0897528b, 0x08d19249, 0x046da413, 0x2d3b282f, 0xa596c51c, 0x62740bea, 0x4436abbc, 0x170e80bb, + 0x911b1327, 0xab629b10, 0x3d64edcb, 0x7cc48a01, 0x7ec061dd, 0xc88178de, 0x4bbef217, 0x65be69ce, + 0x30392624, 0xaca7a50a, 0xa7f3597a, 0xd58b121a, 0x1a7bf146, 0x8ef9bfa4, 0x1be18162, 0x2e9cb785, + 0xec513386, 0x87004eeb, 0x9513b6b9, 0xfdf9e86a, 0x1029c6d5, 0x72f08b50, 0xbc12d58b, 0xfe61f088, + 0xf3b036f6, 0x4010e16a, 0x78749387, 0x26bb8f10, 0x64c1c8b2, 0x84da5218, 0x2f31bd24, 0xfc83ed85, + 0xc79a4e0e, 0x8e9f397a, 0xa59623c0, 0x8f07867f, 0x06a1cd51, 0xb890e4bc, 0xbc1da231, 0xe4bf1ba1, + 0x523540fd, 0xffd17d7e, 0x8697439d, 0x232f7b89, 0x13908b24, 0xaafa4931, 0x31df5d7c, 0x0dfd4858, + 0xf934d029, 0x5e1467d7, 0x58d0dfc1, 0x74964974, 0x5a736ac5, 0x0ac59dd1, 0x1f6ca68c, 0xf30f1bbb, + 0x61dcebf4, 0x21ba6488, 0x17fe90f5, 0x9bf5892f, 0x237b43fa, 0xf5600cc4, 0xac813103, 0xa94d8c0d, + 0x2b6d426e, 0xb8537686, 0xa61e9d79, 0x47850ffb, 0xf7a7307b, 0xa2efbc08, 0x419e3a87, 0x12a65e50, + 0xeb8b3afd, 0xb0259c0e, 0xc2118de8, 0x37006c49, 0x54bb7f55, 0x78622c76, 0x0c666bda, 0x73422524, + 0xfb79c5a3, 0xfabeab6e, 0x98ee994e, 0x243f5499, 0x2f0301ee, 0x86075364, 0x37040d85, 0x15bf27f5, + 0x91a38da6, 0x11f616d6, 0x3dc8dc5b, 0x7a28336a, 0x63f0b59e, 0xd420f11c, 0x74da29a6, 0x43dfe625, + 0x8640c086, 0x2abe7f42, 0x7cef626c, 0xb06e6c06, 0x0d9cff63, 0xa710f538, 0xfce5573e, 0x450f8d22, + 0xe9669af8, 0x4eea4530, 0xadfe3c37, 0x0b110006, 0x91103d2b, 0xaa6fe50e, 0x20965146, 0xf89a57e4, + 0xc56984c9, 0xd9f305c4, 0xb86d0c82, 0x944e7413, 0x91504b78, 0x75d4acd4, 0x612c4095, 0xf1105000, + 0xccdded26, 0x3df149f3, 0x20386691, 0x9509f553, 0xc970b7e6, 0x41ddf428, 0x46353a6f, 0x4bd3f50a, + 0x98b74e12, 0x9ec0e763, 0xd3caf56f, 0xa47438d6, 0x2b4fde40, 0x3517f2bb, 0xe1c1e504, 0x90b482ce, + 0x1bc3be93, 0xc6fa539b, 0xcaa8036d, 0x2538cb3c, 0x30e1cc31, 0x9f437294, 0x48271e29, 0x0a5622fc, + 0x955067b3, 0xf5402398, 0x707eb70c, 0x67d916d0, 0x0ed73eca, 0x61fc8a7f, 0xd6085ea5, 0x57311096, + 0x83392bea, 0x07e942da, 0x3fdf5b2d, 0x3e3636e2, 0x3175ca1d, 0x57e1d1b7, 0xdbcc1799, 0xcbe076d4, + 0xfc8a0a10, 0xe4b6a828, 0x03b29df5, 0x4c145955, 0x79cccc4a, 0x30fb311f, 0x4401b7e3, 0x5119d628, + 0x7a7444f7, 0xa0604eff, 0x3314bbfc, 0x02763a78, 0x0158ddad, 0xe4a5b758, 0xfe39a8f2, 0x8e8e1696, + 0x3f1d50fa, 0x806ccca3, 0xe621fc73, 0x49997e53, 0xec235711, 0x998d7619, 0xeec6621f, 0xd8f079fe, + 0xbeb42a63, 0x8862ae34, 0x143b6a9e, 0x255d71ba, 0x7e292b9e, 0xdb7d0a7a, 0x41c5af86, 0xcef5e439, + 0x58498581, 0x0a283ada, 0xe06d99cd, 0xb8011c9c, 0xa28cb53e, 0xfb5d8a17, 0x590f7953, 0x455e5c02, + 0x7ee51360, 0xd255ad65, 0x851d8f27, 0x8ce3a71a, 0xd3923117, 0x5eaf189e, 0x247fd82e, 0x9f205ae9, + 0xb452bd39, 0xfc56fd01, 0xa0996194, 0x8fb66d0e, 0x9e477ceb, 0xdffe1ab8, 0xbde3f1ae, 0x8e0aaea6, + 0xd98bbff9, 0xa256a5a1, 0xf3fb6649, 0xadd60630, 0x424672a8, 0xeb06b136, 0xc952c611, 0x7f4f50d6, + 0xfa3d559c, 0xfd016f57, 0x6394e714, 0x3c887650, 0x6199a16a, 0x252be956, 0x4fdc8ebe, 0x70a62fb3, + 0x3ec2d00e, 0xb7571b04, 0xe2f52eb0, 0x88951dab, 0x7638c3c8, 0x8ded375d, 0x706147d3, 0xa55cc5bd, + 0xb4bc73d5, 0xa58af897, 0x45d47675, 0x500cbee4, 0x1639b989, 0x35a220e9, 0x40413dd1, 0xe627fd00, + 0x138b70e1, 0x8a654322, 0x3b8b3494, 0x3819a57e, 0x3065a80c, 0x1ce8172a, 0x318680a1, 0x08c26a68, + 0x8f8a0e71, 0xb7243e86, 0x08ade837, 0x5378dc63, 0x917f4886, 0x207b4c21, 0xe774da98, 0xf959a91f, + 0x34896d05, 0xc7274ee1, 0x107b216d, 0xfa13c355, 0xee494f97, 0x7db8cfbc, 0x5ffc3eb0, 0xfb466703, + 0x596917c1, 0x2ba8801d, 0x774b2843, 0x5b0d30fc, 0x9f3a6c81, 0x3dea3174, 0x2c41eb5f, 0xb8b372e5, + 0xf989ea8a, 0x0426b6e5, 0x0f56482e, 0x0577209b, 0xf23e0d58, 0xc6e3daf2, 0x68070a9a, 0xbddb901d, + 0xd00be683, 0xa67bfaed, 0x53e5eaf7, 0xe169f43b, 0xaefd0393, 0x310ce163, 0xb75d7423, 0x1bb4fecc, + 0x4adac113, 0x8ad22119, 0x91cc9b57, 0x4f8f3304, 0x786e83a7, 0xa12dda80, 0xdddb8331, 0x552f51f1, + 0x5f0f85e9, 0xc8afee81, 0xdca7d7cf, 0xebd15aeb, 0x29530660, 0x14d9c903, 0x55697ea9, 0x9692bda9, + 0xde2e531f, 0x87d11d89, 0x0b95ca26, 0x06959329, 0x44490888, 0xf4922c0c, 0x7dbca57c, 0x145cd0fe, + 0x4405a6a3, 0x4f43fdf6, 0x7678e3b4, 0x2ed5b251, 0x2dcdf201, 0x04aa68d6, 0x02af37eb, 0x46e533ea, + 0xde4dd270, 0x4ddcc706, 0xfeda8870, 0x26c4af69, 0x725ad0b0, 0x1a05f5ed, 0x7bd8462f, 0xb9a96c20, + 0x84dba9d7, 0x6eb8daea, 0x9484587f, 0x639aec37, 0x650cdbe1, 0xfe8df74b, 0x90c1a55b, 0x0a51041a, + 0xd4e36a13, 0xae288abf, 0xccb4b824, 0x9a4aeb5a, 0x295719fc, 0x58a792db, 0xb7a054d2, 0xc3327b84, + 0xafad4b88, 0x41953504, 0x96a8fbfd, 0x696dff8b, 0x8113d892, 0x9afb728f, 0xd5adb8db, 0xe4bb12dd, + 0x46f17402, 0x7aed3844, 0xc8198430, 0x91dbbeff, 0x0a944aed, 0x3cdeafbb, 0x49d7d7d3, 0x8d3aeef3, + 0x23fb5363, 0xe385f3ef, 0xc882b99b, 0xa1ebf063, 0x169550eb, 0xad10fae3, 0xacb7d185, 0x51886070, + 0x9e945e3e, 0x631295a0, 0x3c828221, 0x65adfd3f, 0x7995604a, 0x087b307a, 0x1f9a7a38, 0x2ac46201, + 0xf3ee3ff3, 0xab491225, 0x2ff994a9, 0xc0290dfe, 0xe21748d7, 0x46fe37f8, 0x926a05af, 0x373235bc, + 0x759a41fe, 0x586598a7, 0x7ab3f119, 0x8bd0cf43, 0xc886a3b1, 0x419b9596, 0xd573f322, 0xb66e1e3a, + 0xaf7281e2, 0x53bcca04, 0x8efb897a, 0x8a35d08f, 0x4b5de967, 0xef93d10a, 0x93f14c7e, 0x5e3718e1, + 0x171d6451, 0xf4aa3b2e, 0xec778981, 0x70cb717a, 0xf13c85e3, 0xc01dd577, 0x29503357, 0xd763fc7e, + 0xff76d5ea, 0x2844f819, 0xa72adf5c, 0x1bde6b66, 0xe476b0e2, 0xb14c0816, 0x87b40d23, 0x20a79714, + 0x5d3dd29b, 0x1a7970ae, 0x2abe1c5f, 0xfa5625f5, 0x0a7c5905, 0xed2dc55e, 0x631d3a18, 0x9f3d37ce, + 0xbc95fd64, 0x4be5519a, 0x520c4be4, 0xd56cec1a, 0x08c58d61, 0x4f509a55, 0x272d5874, 0x7ea10267, + 0x239ff811, 0x188f5c71, 0xcd30640e, 0xb8a0e4fb, 0xe6e5a7cb, 0x9e9937ab, 0xc5f8220b, 0x702382b4, + 0xcf9abf89, 0x60223b2a, 0x88526369, 0xc6d56b30, 0x28d6fd02, 0xa7ed122f, 0x02ad5651, 0xc68458a8, + 0x51a0d347, 0xaa124954, 0x0416edba, 0xc661f8f9, 0xbd142ca4, 0xbdaa5c52, 0x683351b2, 0x2659a125, + 0x004e9458, 0xc416acf0, 0xa7e63946, 0xdc139269, 0xdeaa2b63, 0x7c631563, 0x8aec240a, 0xcf6020f5, + 0x98c4dcd9, 0xd8af2160, 0xd80f7855, 0x9c92aa93, 0x9679bd9f, 0xff447660, 0x07592947, 0x1177a7cc, + 0xcaefe11a, 0x2aacd6fb, 0xc35d871d, 0x775c70bb, 0xa47a6572, 0x84fc29d6, 0xf4362e37, 0x5c2d9c8e, + 0x741384aa, 0x3d24c765, 0x7edce93f, 0x223aa54e, 0xf5b4239e, 0x5c2d82ab, 0x9458fe58, 0x2a89a92f, + 0xe2efe728, 0x8c0bc6e1, 0x1279ce66, 0xa6459825, 0x76d01c39, 0xb96cc31f, 0x1c2a4b06, 0xaea24241, + 0x33e443aa, 0xd5490050, 0x28336ec0, 0x705a1c33, 0x0ca4fa51, 0x1fe16eb0, 0x52952fae, 0x165ff0e3, + 0xfbcfae7d, 0x704cb073, 0x91d9104c, 0x7a90ae91, 0xb0b80eea, 0x4ccac1bb, 0x202aee43, 0x94057de8, + 0x9ff8e683, 0xffdca252, 0xc47497ef, 0x601f08a6, 0x36079b79, 0x99351ccf, 0xb92ca8f0, 0xf5793003, + 0xf0605179, 0xc6baa183, 0x4ed4a51d, 0xf2d0bbd4, 0xa160d793, 0x4aff02c6, 0x1433ab3e, 0x193f251f, + 0xc74fd811, 0x4fb7a04d, 0xe9281c4e, 0xa319dcca, 0xde365f04, 0x4d570586, 0x97c73301, 0xf3e8a32c, + 0x89d746e2, 0xc2a8b50f, 0x69bb4fc1, 0xaa2331f8, 0xed1b0f7d, 0x45c90e70, 0x2723933f, 0xba1a6d5b, + 0x99942c38, 0x7c922b2d, 0xfc1338af, 0x1fccbaab, 0xbcdc0bb1, 0x80865009, 0x35ceed72, 0x7af5e495, + 0x3798d6a4, 0xd36f04f7, 0x9e750ded, 0x0a6e65df, 0xb60a77c9, 0xff2b0f27, 0xc6c9d593, 0x600c12cd, + 0xdd89717c, 0x8adb4259, 0x2973f78a, 0x64993c6a, 0x10e10777, 0xe7243271, 0x8f575faf, 0xfcea1b43, + 0xb0187c99, 0x730ca0e1, 0xfde3df80, 0x36201442, 0xd649423b, 0x54761788, 0xfa7d63dc, 0x3e5f8564, + 0xf05f34cc, 0x62a89488, 0x591f664e, 0x8c277db5, 0x199d2afc, 0x851f32e5, 0xe0b169e4, 0x815d843e, + 0x034fd3c1, 0xce20657f, 0x9a019f3f, 0x1eb44edd, 0xc046edcc, 0xc55ebfbe, 0x3019b38d, 0x02d887a4, + 0xaa73269e, 0xb2e27c35, 0x0770bb7b, 0x8e44e67f, 0xc3a90e25, 0x20628f16, 0xa8603126, 0x7947ccfe, + 0xd82dc350, 0x74bbcba4, 0x002052e5, 0x28b57977, 0x924d3ae7, 0x480a6596, 0xe7769a90, 0x75dd8cfd, + 0xfb355122, 0x7c24f873, 0x68bbdd60, 0xe7148c4e, 0xe7a369a0, 0x3ba673f0, 0x33527ac3, 0x003bed62, + 0xb3941ea1, 0x2999ce5f, 0x05f36c8a, 0x319e0c73, 0xf0dd69c1, 0xe141389a, 0x8e37c060, 0x6f1ebc41, + 0xb7845791, 0xa0156640, 0xddef5402, 0x12d237de, 0x7938ded7, 0x55b96f2e, 0x18cf31a0, 0x2e7ef791, + 0xdaa0ef4e, 0x61f19dee, 0x255f3fb2, 0x6f0b12ca, 0xc276d8b3, 0x473b693c, 0xb32b04bd, 0x419d39fc, + 0x5accce14, 0x8e7362f1, 0x80901a49, 0x1e96df99, 0x9714168d, 0xa11904c4, 0xe469ab09, 0x5bee5b43, + 0xe41cfb59, 0x8ba0a577, 0x14707daf, 0xe7c8232a, 0x86d89a3d, 0x35fceac1, 0x55440570, 0xa1484565, + 0x453a5a79, 0x5f190c6b, 0xfa9387fc, 0xe613990d, 0xa483a243, 0x88d8a061, 0xd045fe67, 0xe460b672, + 0xdbefafe0, 0x69acd6bc, 0xa2386bc1, 0x282b4ddb, 0x2bd0bc33, 0xb0ea3565, 0x84a1d4a1, 0x5027d260, + 0xad9421e2, 0x8b6194c7, 0xddae14a2, 0xd6d18b75, 0xc034e21f, 0x72479994, 0xe0ea8de8, 0x9374f0ef, + 0x866d1c30, 0xef75707d, 0x8da761fb, 0x8ae767b9, 0x832aecfa, 0xeb05ee91, 0x893dde7c, 0x9a09ab16, + 0x5bac8032, 0x46654054, 0xd6562dd2, 0x43e7a12e, 0xbd49b460, 0x407891ea, 0x4c436e83, 0x816b5b2c, + 0x2d454cf7, 0x5c66e626, 0x627b1ce1, 0x4a60c5c9, 0x85acd360, 0xda669682, 0xb10ec9b4, 0x442eca13, + 0x1a5a3d89, 0x3d2d4ed5, 0xbf3e35e0, 0xcdf10b76, 0xde05143e, 0x97ab107f, 0x74a70435, 0xdf710a58, + 0x52ca2206, 0xc9b6c424, 0xccb76ab0, 0x4c1a1bf1, 0xed584d65, 0xb10ac389, 0x86614cde, 0x87bd7836, + 0x5a885bc3, 0x0c2426ec, 0x856a1729, 0xef9ae37f, 0xc9fd4398, 0xe6fa8f22, 0xd4c84241, 0x0f9f7032, + 0x9a3b9bc0, 0x3af2581b, 0x13962688, 0x50077eea, 0x64b5485d, 0x08d0f812, 0xf5eb589a, 0xd90fd65e, + 0x9186196d, 0x5c580d82, 0x46544cf5, 0xd9566149, 0x5b97288c, 0xe1c8b883, 0x41e91760, 0x3eef8309, + 0xb792cd2e, 0xa5b9fa11, 0xc6545668, 0xde16c150, 0x1808f3e3, 0x0789d6f7, 0x4c54f3b5, 0xe86af861, + 0x434a7b7b, 0x6bd8f4fe, 0xd2e4934c, 0x0589c42b, 0x3a19c459, 0x72aaf903, 0xfd121639, 0x0469c1d0, + 0x48cb04bf, 0x79ffaf2d, 0x3bc3430b, 0x273378c2, 0x1a731559, 0x81e042c8, 0x4a99bb14, 0x5bcac4f5, + 0x65e6d931, 0x02b0f3ad, 0x6ad4214d, 0x36276812, 0x38758653, 0x9d046994, 0xb6c2da99, 0x3464d675, + 0x7919fe1c, 0x0a4a5917, 0x20bad64b, 0x3e05b813, 0xef491f72, 0xbcee18d1, 0xa17d5a2f, 0xccb44689, + 0x451181c4, 0xc9f5592c, 0x401f1c98, 0x4b78a77d, 0x44e3a970, 0xdb7b1b44, 0x3264dfba, 0xa62ae1b3, + 0x487edd83, 0x74ca2e3d, 0x24cacdde, 0x3ff31eb8, 0x12f31dc0, 0x8f90e5de, 0xd05d63f0, 0x1293c2f4, + 0xeadb75e1, 0x1f05550a, 0x010320be, 0x1b98c271, 0xe0bd0497, 0xbf8135e2, 0x268ea33e, 0xddbb4fe9, + 0xed60f925, 0x4c041d5e, 0xe12de1e2, 0xfd270e24, 0x7e80ccc6, 0x8f018f11, 0xcd48dbe5, 0xd75f4992, + 0x38862ecd, 0x1ca96397, 0x1047caa5, 0x1fbdab53, 0x9eed6d30, 0x581608d8, 0xa0964913, 0x3e2fcc4b, + 0x6e30c487, 0x60a03646, 0x1a22add9, 0x87c49655, 0x9fcae4d8, 0x0a233936, 0x873aa94c, 0xeeb92621, + 0x444146f4, 0x8efc7f01, 0x47fb7942, 0x98bfc2a2, 0xe3c0693e, 0xbce93ec0, 0x85eeb89b, 0x97eb63bc, + 0x69d48b55, 0x1d7168ff, 0x755dc73c, 0xe1d76c71, 0xd49e0f8f, 0x74adc27c, 0x100624cb, 0x123bb176, + 0xce76e1ec, 0x5df70cb2, 0x40144a5e, 0xaf84e953, 0x97402c74, 0x05400430, 0xbfa874f0, 0x4a79b5f7, + 0x638e6f09, 0xd07e907e, 0x08102434, 0x7356556a, 0xe86c411c, 0x67e156db, 0x4831535d, 0x14375701, + 0x498cc138, 0xed838d34, 0x76febfce, 0x5362a5f0, 0xbd0f7a78, 0x68ee60fe, 0x1c77ae17, 0x82339034, + 0x0f79290f, 0x0ae8c7f4, 0x4d6b535c, 0x83d2a103, 0xbd880866, 0x2eeadd2e, 0x9bcc9542, 0xea390f0c, + 0xb8cb587d, 0xa98cfbe7, 0xba27de02, 0x466446fe, 0x888120ce, 0x9dc41b73, 0x0f93363e, 0xbfe1ccc4, + 0xce3eebcc, 0x02a2f44f, 0x6eda187b, 0xa45a773d, 0xdd980b7f, 0xb18e8d98, 0xc9b14489, 0xcdf48600, + 0xcbee92f9, 0x102a9a54, 0xd5072c08, 0xd20af64d, 0x6cf3b8fe, 0x1e6a97d0, 0x7420072f, 0xa1012d50, + 0xa2b11196, 0xb3b8abe7, 0x33cbb9bc, 0xbfa1fe61, 0xac24cae9, 0xc218bbc5, 0x49df0154, 0x96d76a7a, + 0x4f2f41a3, 0x6115a328, 0x4793d84c, 0xadda9ac3, 0x72b38ac6, 0x3dfbf5e7, 0x3dac57ed, 0x874ebb4e, + 0xecc7f057, 0xe4c9fc9a, 0x4913d19a, 0x370d6079, 0xfd6ee6c1, 0x970a15ee, 0x8ef5a2cd, 0xa1b7df1a, + 0x5ddaccb3, 0xbee47e41, 0x74a08f36, 0x8968464e, 0xfe466e42, 0xb1b8e60a, 0xbc1a71fb, 0x0b41b81d, + 0x29529b08, 0xae5f9333, 0x473559c2, 0xc27a67f0, 0x45d363f6, 0xc870f05c, 0x732f579a, 0xc755a13a, + 0x74bfa16b, 0x99900c28, 0x74a1a385, 0xf82c7722, 0x08db29b8, 0xe1952f3c, 0x5504b63a, 0x03acac65, + 0x32105a2d, 0xf6d1983f, 0x00df94f8, 0xd76e32f2, 0xc67fdb38, 0xa8c53144, 0xb7316a7e, 0xc7490c3d, + 0x8b8efcdf, 0xb2fa544b, 0xfd075c33, 0x103b936a, 0x71222244, 0x804b9d17, 0xaf341d21, 0xd6162f4a, + 0xb4c6ef7e, 0xc9517d3d, 0xb9030dde, 0x908b2331, 0xea9f48a8, 0x71e38531, 0x9fe195ae, 0xfc71b2f4, + 0xedabcb6e, 0x15b7a9bb, 0xefbbf408, 0x05697e0b, 0xc813ea3a, 0xd0f0d42d, 0xf88ab082, 0x24c4c654, + 0x3976b54a, 0xde681c5c, 0x33bcb7af, 0x34f07632, 0x87d579c9, 0x3f31d8f8, 0x2a831721, 0xd8bf4a51, + 0xfeb809fa, 0x0c3f08ed, 0xc99709be, 0x4ff39da2, 0xa3cf5118, 0x28deb629, 0x3dbda075, 0x5fcb615a, + 0x0d255252, 0x9ca3a123, 0x7dbdb327, 0xd9ff5f68, 0x18e57fc5, 0x93300d5e, 0x516a4c95, 0x06b0d935, + 0xcb672125, 0x4f0f8874, 0xff7022c3, 0x25fa97ee, 0xa1b568e3, 0xa56f3cac, 0xb4dbbdc6, 0x1b5e8db0, + 0x80fe5433, 0x1ed236c7, 0xb5eda829, 0x796dedd2, 0xe51d9bb7, 0xd3f72e85, 0xc6a11723, 0x12216b80, + 0xe06bc9a0, 0x84dd7f91, 0x2ac61f49, 0x9b84ebaa, 0x5127c185, 0x82f9f358, 0x4f481ccb, 0xe1a5f991, + 0x2e9da95a, 0x26885b29, 0xc7b5c718, 0xf9c82d3d, 0x64287a3b, 0xe02a12f9, 0x8cf8675f, 0xc594d0b2, + 0x69391934, 0x60f8d572, 0x347ec51e, 0xb1066a48, 0x51e06a4a, 0x08191584, 0x135ff6d1, 0xa8aa5227, + 0xde9686c8, 0x325d7fa8, 0x9af701d8, 0x812464cf, 0xf51e4f4e, 0xc38ac60a, 0x27ad8e07, 0x78b303bc, + 0x6c5b805a, 0x63f245f4, 0xf238c461, 0x9702d913, 0xc294fb69, 0x747673cc, 0xd3e253de, 0x845e833b, + 0x3a933f10, 0x85648a5d, 0xd838bbf0, 0xcfcf1a3a, 0x0280c8a4, 0x14aad5b7, 0xbc0cb4ef, 0x5ffce205, + 0xfe5746aa, 0xc0c53e2e, 0x55e8cbca, 0xe6fcca01, 0xdcd5c790, 0xe92c91a5, 0x7bb323c4, 0x396e207a, + 0xee35cdfe, 0x08d0bbfb, 0xbd721e18, 0xc60b4332, 0x24517ba2, 0x207f0476, 0x2453a695, 0x9ea9b61e, + 0x57ea1dd1, 0xac58c3c2, 0x647452d2, 0x270291aa, 0x2ca0f06e, 0xe2f108c1, 0x17edb9be, 0xcc9d5db0, + 0x09b677e4, 0x884d3836, 0x9c72863d, 0x2b470947, 0xeee7846d, 0x993f5b74, 0x14f804af, 0x5d3c6c9e, + 0xb3b2898b, 0x607ef389, 0x5c48430c, 0x0190adab, 0xb2032238, 0x2346dafd, 0x0dbc64fa, 0x662ba84d, + 0x6fd56d12, 0x87170e4c, 0xb02ecceb, 0x74488cf2, 0x97040938, 0x7049fd09, 0xc6d9cd29, 0xa0d05735, + 0x0fe9e2c6, 0x31c40c6a, 0x27ac40c3, 0xa8e8b53a, 0xaecac338, 0x912d3252, 0xef40f3e7, 0xc0cf9a9c, + 0xe939baad, 0x8bf9ffea, 0xfaf5557c, 0x1ba06feb, 0xe0906edf, 0x866d6586, 0xaabe12c3, 0x49d34e0c, + 0x1fd9b83d, 0x660d6aea, 0x5b66223d, 0x5ae70286, 0xd95257ce, 0xebc9cf2e, 0xe3d536ee, 0xaa4e393d, + 0x2a605e40, 0xf2842c7e, 0x8d2bd491, 0xcec062ed, 0xbf8497e6, 0x39dbae83, 0xfaa64865, 0x588e8042, + 0x7796b041, 0xc5c6aa3b, 0x7394b903, 0xd3426139, 0x8b6557a8, 0x45a09da4, 0x2fce6852, 0x27ee6b3b, + 0x64ed9772, 0xb34b99bd, 0xc1a268d9, 0x359fc8d9, 0x64f4e756, 0x873c11ef, 0x0450f2e9, 0xf33553cc, + 0xbfa33d0f, 0xc3d04978, 0xed03e621, 0xa3b84afc, 0xcf069cca, 0x061db69e, 0x7754600b, 0x7c78c454, + 0xe7465282, 0xf39bd031, 0x23dd39f1, 0x971c5d81, 0x3e95f9e1, 0x50bc36cc, 0x4403a560, 0xdfa1aea7, + 0xa564575d, 0xccbeec38, 0xc8e5b688, 0xdaf5250e, 0x07b918ba, 0xf5cd8279, 0x3392649c, 0x9fc82489, + 0xd3b651f3, 0x2381aeda, 0x9f5f734e, 0x59e639cd, 0x3376ed75, 0x2d17718f, 0x90aaf41a, 0xfb8c850d, + 0x54999fce, 0x05bd0686, 0x84f7bf26, 0x3089991d, 0x35060694, 0x2dc2a85f, 0x72bbf179, 0x16e4dab2, + 0xc4281c02, 0xa0e16223, 0x58d0861e, 0x48b65474, 0xaa5b760b, 0x64a390ed, 0x546a982c, 0xb6cfdc74, + 0x43a8a7d9, 0xc9d9b8db, 0x5a9e58a2, 0x398220a0, 0xa433647a, 0x8dbf815d, 0x8b122a4b, 0xdd1b1450, + 0x9c535d84, 0xdf861016, 0x181dab4a, 0xbea22012, 0x4ea457a0, 0x02df8ab2, 0xdec6dadc, 0x899c233e, + 0x10c01029, 0xb9ca6373, 0x4233cd27, 0x81bdf75b, 0xb84625d0, 0x233acde4, 0x0e4e6474, 0x61912a70, + 0x3030024a, 0xa8c64e99, 0xf09d1bba, 0x26cfba62, 0x5f9e5f29, 0x557011b3, 0xcfb1e4a4, 0x734cf7b9, + 0x5deb9124, 0x8e6f4451, 0x5cc1d570, 0xaa80a69a, 0xe5e94b54, 0x7fe22f8c, 0x3f2a1002, 0x0055e5c5, + 0x7a7ed27d, 0x0e76da4e, 0xa3429cf2, 0x52d99a2f, 0xc6d0012c, 0xbc47e6b0, 0x79cce4d3, 0x85f3ef2e, + 0x731136b3, 0x43d20798, 0x94d378ff, 0xf68bebd9, 0x341f457f, 0x341810b1, 0xae415195, 0xe7b29826, + 0xa0928f04, 0x5df4086f, 0x5da7fb9c, 0x14aa0437, 0x2dd50fa7, 0xaee2a3a3, 0x5ba8a61c, 0x8017ae24, + 0x45c0f2b5, 0xe25fe288, 0x7c726b6e, 0x7dee70ee, 0x460c85e1, 0xe5230190, 0x861fd2d0, 0x16b59af2, + 0x4f743ff8, 0x0d6775d8, 0xd1614891, 0xce4f987e, 0x7fcb2198, 0x2d3bb27a, 0xc2c4b0d9, 0xd5ca67ec, + 0xae3c55f2, 0xa19b1e22, 0xb12e02bd, 0x9f498922, 0xcaefe7bd, 0x739b9378, 0xc410e17c, 0xc635a516, + 0x378ff7a1, 0xd5411f78, 0x1a06ebf6, 0x02c00afa, 0x04658ffd, 0xc711e98e, 0xe43f3158, 0xfa37020a, + 0x3e8b0e84, 0x6a365cda, 0xa121d0ff, 0xbcb3b2c8, 0x2998b514, 0x03b1613c, 0xe046fc51, 0xbbbb0ff8, + 0xb9457070, 0x30937b26, 0xa1a0464a, 0x748bbe1e, 0xb4af20b6, 0xa6446f3c, 0x73c1f38d, 0xb00808ce, + 0x1d3d290a, 0xd0ae8050, 0x909293b0, 0xe48b2c32, 0x4e425ab5, 0xe9b4cf9e, 0x0d4e24a4, 0x65dbf0c2, + 0xf3ae4162, 0x31074868, 0x145b4419, 0x25cf5eda, 0x7e7748ea, 0x1154e2a9, 0x57a37f35, 0xa5abd7d5, + 0x0612bd78, 0x12d4a5dd, 0x7221510e, 0x9adb7953, 0xff6dd545, 0xbffaffda, 0xffde1883, 0x95b43f65, + 0x772b03ec, 0x927eb46b, 0x7151d962, 0x82aa503c, 0x419ca7d4, 0x452af90d, 0x7051f869, 0x3909fee4, + 0x3a0e57cb, 0x9cfca299, 0x604764bd, 0xa7064a48, 0xb297304f, 0xc72147a6, 0x727904f2, 0x359dabe5, + 0x19783309, 0xbbcab5f3, 0x1ecb619d, 0x2c2c4def, 0x9ce06905, 0xb197147a, 0x8797f997, 0x26c985ef, + 0x4468292d, 0x580b3159, 0xc89151c4, 0xce016e83, 0xa30bc805, 0xcc2d8b2c, 0x0518e705, 0x1b44295f, + 0xec470485, 0xfe000ddf, 0x0b22c9a0, 0xea16d043, 0x34c4f599, 0xfe48e6ef, 0x4d9a806f, 0x27b4a8ba, + 0x764bae09, 0x0779b11d, 0xeb3bb6a4, 0xe090f8ff, 0xe00d19c5, 0x2249f28c, 0x4474f03f, 0x73a05e9e, + 0x30b3bd08, 0x2ff6c5dc, 0xfc2e3c9e, 0xd40ca297, 0x1c41110a, 0x54c80a84, 0xee512bdd, 0xc185a6d9, + 0xe31fcaba, 0x93735921, 0xa4743612, 0x9608ec24, 0xb168fb14, 0xfed8b9ab, 0xc0dfd40e, 0xa5a0a6f3, + 0x92b99385, 0x53ccf3cd, 0xcdd20e17, 0xea9b6ebf, 0x1ec88b3b, 0xe0ed8651, 0x59dec273, 0x38a20618, + 0x5ce7171f, 0x6416f7a4, 0xb811ba92, 0x7b7af8d1, 0xa542058c, 0x303b995d, 0xf3ae9c1a, 0x8d26311d, + 0xfa7df2f2, 0x68cbefbd, 0xa76ca50c, 0x13aa527c, 0x7d3ee8fc, 0x1cf263b0, 0xe49c19ee, 0x69f314b6, + 0x9bb1b0b7, 0x4d7792de, 0xf683612f, 0x00860279, 0x21e49e02, 0x91235b40, 0x80da2607, 0x409edcd2, + 0x060b3af3, 0xcbbe32a3, 0x495b2b27, 0xcb76a5fc, 0x7ed4d5c9, 0x88327f57, 0x51401cbe, 0x12374c29, + 0x7a0d6084, 0xce17b8ce, 0x6147e5a9, 0xa3e72ea0, 0x01410786, 0xf09e5dd8, 0xfa6034e2, 0x353b0509, + 0x90004903, 0x144faacb, 0x2808868b, 0x1ae2de3c, 0x7a484f35, 0x7fae092c, 0x1793cecf, 0xf85d889f, + 0x0909f075, 0x9be466a7, 0x61d364e4, 0x3d595df8, 0x078e2c85, 0x66967b95, 0x950abfe4, 0x572b8c58, + 0x06877781, 0x2ab42f32, 0xc0adb335, 0xa609855a, 0x8ed0bf4b, 0x93ce0f21, 0x749e2dbd, 0x403b8608, + 0x7b369535, 0xca9ab92e, 0xe9cf7c99, 0x075a7ff9, 0x179ca235, 0x7b34c874, 0x78190a9c, 0x12d0b04b, + 0xfcf0168c, 0x6c275b26, 0xad679ff6, 0xb99c6cc7, 0xc587db09, 0x827346f9, 0x904c41ee, 0xb66349da, + 0xb1d48f75, 0x094f5cf1, 0x6c526fda, 0x64fe07be, 0xc319cdf4, 0x01b7643d, 0x9aba6339, 0x53387e36, + 0xf6553335, 0xbf1e48ef, 0xc82e37c1, 0x865c78c4, 0x835e73ee, 0x7d5e6382, 0x990407dc, 0x2e42acc9, + 0x74442ee1, 0xc553b955, 0xbadbc1ea, 0x8660a0ad, 0xf91b0bc3, 0xd689d416, 0xdd1b4a49, 0x08000128, + 0x8f9b1f15, 0xba964777, 0xa1f678dd, 0xeb489c63, 0xe9d8549d, 0x6378f6f8, 0x445acb6d, 0xa772c1d4, + 0x6228f67b, 0x85d90eb4, 0x7b93dd9f, 0x8e24f1e1, 0xf78c2456, 0xa12e17df, 0x8aeb713a, 0xa58ebab1, + 0x8cdbad9a, 0x4e9cb624, 0x19fa314e, 0x51a43f9a, 0x291d78cb, 0x757354ba, 0x74e4f1fc, 0xea7d0497, + 0xa170ab78, 0x363796e8, 0x741a06eb, 0xf8f506a8, 0xde73a45e, 0x4a409f39, 0x395be511, 0x5094ce6a, + 0xc9072c7e, 0x49d3cf83, 0x05bfbb97, 0x73789abb, 0x0aefe2e1, 0x84e0bc6a, 0x72705d13, 0xca953b04, + 0x8882f27a, 0xe7397097, 0x39c84e0b, 0x9a78ba59, 0x6768a4af, 0x2057e592, 0xda745a9d, 0x906c9ef6, + 0xc3c687f4, 0x9968b3df, 0xda5a4d76, 0x31008da6, 0xa36608ce, 0xdcc110b8, 0xd231f4c2, 0x4b6742bb, + 0xe93d137a, 0x6ac3bb3f, 0xee7e68e7, 0x1981e64e, 0x7e405a45, 0x2b771e3c, 0x344bae3c, 0x4f247088, + 0xa68ef204, 0x6b6ca655, 0x7b28af2e, 0x2f901c4a, 0x9039cd21, 0x7b7a5bd4, 0xe96804a6, 0xb0811814, + 0xb517d0de, 0x8a7b29ca, 0x7009b6af, 0x4352035f, 0xacb8260e, 0x1301b478, 0x18bcb6dd, 0xf30890dd, + 0x9d48ccbb, 0xd4369ecb, 0x3ca846fc, 0xea4968b2, 0x587b0100, 0xd035a6ef, 0x2cde12f4, 0x0c8bb280, + 0x4190d63c, 0x8e307ebe, 0xb9deb640, 0xc33f5f8e, 0x61627ee4, 0x5776b915, 0x6fabf809, 0xca09036b, + 0xc90bc251, 0xdffd7518, 0x14846926, 0x45b37d0f, 0x2c5f89c9, 0xc6d66322, 0xaacee8aa, 0x02424212, + 0x09549e89, 0xcf6dc521, 0xae9c16aa, 0xdb21d943, 0x0a1c3685, 0xa0e7dce1, 0x34ee3cea, 0xcec18b17, + 0xd8f17e65, 0x814add85, 0x12475424, 0x1dba2d2a, 0x73afa018, 0x118a1f11, 0x7682dacc, 0x13df0c12, + 0xafe56fb0, 0x9f9eba58, 0x645bb7f1, 0x447e23fb, 0x2d013b94, 0x542f6ba4, 0x03b81532, 0x82583b70, + 0xcdaaf5bc, 0x42adf47b, 0x4403221c, 0x91f09660, 0x18d087ed, 0x53080919, 0x189bc32a, 0x4272779e, + 0x4c2940bf, 0x62027c04, 0x57d753bc, 0x34e2e131, 0x9ea660d3, 0x8b2a876c, 0x1539ad45, 0x03b10f1e, + 0xb4c2d93a, 0x653ab8f8, 0x4512637c, 0x65c32d15, 0x4e8bf426, 0xe2da28e1, 0xc9a8690f, 0xa0714932, + 0xb621ce07, 0x4d57d10f, 0xa24ed52e, 0x5f6463fe, 0x0acb417a, 0xde26fb8f, 0xb570aadb, 0xcc7754ac, + 0xb0e7da37, 0xabfba9db, 0xef0797a3, 0x12fbc4c7, 0xe8204988, 0xbd7e31f9, 0x7f30039b, 0x3574327b, + 0xed538671, 0xb264976c, 0xa191cecc, 0x6b9ba238, 0x2aec3823, 0xe2c8b3ee, 0xdf87cf22, 0xc05315bf, + 0xc8cea070, 0x9ba6c25e, 0x5006eab0, 0x6b5f0691, 0xdc7731af, 0x011bfb60, 0x0dc03094, 0x83fc4250, + 0x572b81a8, 0x00fd9996, 0x0ab8257e, 0x3f235318, 0xdc8eb3fd, 0xf96fb3e0, 0xbbcf0a9d, 0x1ddb6a80, + 0xc3f0f08b, 0x5b0c31cc, 0x0b3337fb, 0xb19c90d0, 0x7b838be1, 0x5729f5b0, 0x6b748bb4, 0xe34c515e, + 0x220eaa7f, 0x3957725f, 0x1562c653, 0x8de09ed2, 0x2f949c1f, 0xb8256021, 0x88e80f78, 0xc25416a5, + 0xe1639ec0, 0xbddf8763, 0xeb9f5bfd, 0xd1473d0c, 0x31ff7caf, 0xd53c2548, 0x5fbea17e, 0xe4d14cac, + 0x706947a2, 0x7425b32f, 0x10065f67, 0x4054e364, 0x977f67c4, 0x10f28f54, 0x6c30b1c8, 0x7ff94657, + 0xbeb2e526, 0x51d1c65a, 0x1593f23b, 0x795e0a7f, 0xa8d2c56d, 0xe36cde9d, 0xb100d8a6, 0x5f4c9233, + 0x253f2b6f, 0x2c1020e5, 0x37d8a71e, 0x632d791e, 0x859c5dd8, 0x7a952396, 0x386b64ea, 0xd4353188, + 0xc49a3ae0, 0xf7f9b652, 0xd01d7693, 0xa804705f, 0xab582034, 0xc8cb4581, 0x791a6288, 0xdcc99e20, + 0x6696dde9, 0x8d668a7c, 0xf3d641e2, 0x7bad77cd, 0x1e045703, 0x810ddf95, 0x90c0056c, 0x0a2535a3, + 0x83aa65f2, 0xa39d1f1b, 0xf681e44e, 0x204ce3ab, 0xb08ebe3c, 0x8a8457f6, 0x5c69f21f, 0xdb1b1c9f, + 0xb052b449, 0xcfa3074c, 0xec5ac82d, 0x6fd5abe1, 0x277e4291, 0x593ae0cf, 0x7fdc7c83, 0xf67d4808, + 0x6e4534f3, 0x47da4f97, 0xe22a581d, 0xa956973e, 0x7c7f4487, 0x7a6c8ba0, 0x0c36eff3, 0x8a679b70, + 0x64f35228, 0x70615eb8, 0x138f9485, 0x37f9c197, 0xea80695a, 0x79acf313, 0xa9e422a9, 0x2407b02e, + 0x47f57ac8, 0x91176117, 0x30994407, 0x49dd7c18, 0x0e05fae0, 0x5a00310a, 0xc33b74f9, 0x77d6d016, + 0x867b259e, 0x8edf39c4, 0x0021fe76, 0x60390c00, 0x393b68d1, 0x5c93e55b, 0x9253a95b, 0x8e72b72f, + 0x57c06fca, 0xc7f6093f, 0xa169c8d3, 0x06e655aa, 0xc261a06b, 0x92c90fec, 0xf32243c4, 0xe39fe4f6, + 0x3b01f2bc, 0x7dea0695, 0x5a426e2b, 0x553d23ba, 0x6a30e06d, 0xb37b1f67, 0xe5eb50ac, 0x15b398e9, + 0xafd1f677, 0x684f06d2, 0x72c016b0, 0xf1649c8d, 0x65676d5a, 0x3c445992, 0x827dc458, 0xc6a246d5, + 0xaf47a0b0, 0x0d9647b3, 0xd85e038e, 0x52231292, 0xa2ba2227, 0x280a8fed, 0xbc7de7aa, 0x525055a6, + 0xfcf7992c, 0xbf75fad6, 0x9581376d, 0xb91e6ce1, 0xbc021c69, 0x6b79f6f8, 0x5feea24b, 0x0c2bcdb1, + 0x71d5e12f, 0xa9a42be5, 0x02df3520, 0x8c95871c, 0x83294b71, 0x455cc87e, 0x13b79e7e, 0x3ed54048, + 0x8ec8cef4, 0xc66f3b4c, 0xa721c895, 0x845e4e87, 0xdec592b5, 0x0670be6a, 0x0eb73ed0, 0x7697f11b, + 0xf6d88a97, 0xd6d92269, 0x11a16305, 0x52e9cdb1, 0x52806adc, 0x23f11b29, 0x7abd2fc5, 0x145132d2, + 0x4de54902, 0x0ca48438, 0x26fa523f, 0xe93b5695, 0x892f4677, 0x13f2977d, 0x823e8395, 0xc0b515f9, + 0x97edb867, 0x10def9be, 0x50ebf86d, 0xfbc0e63a, 0x08ff343a, 0x61395a21, 0x16f9eb2f, 0x69330f1e, + 0x933a764d, 0x2b1cd4a5, 0xf841d013, 0x489c01d6, 0xf2e051fa, 0x1373012e, 0x91cd8017, 0x828b782e, + 0x419ad9ef, 0x4e9216cc, 0x2de0dc30, 0x7b6e68e1, 0x5138cc47, 0x86c1db1e, 0x4157d052, 0x03478d4f, + 0x63d20cbd, 0x8537aa7e, 0x2493e918, 0x43ec41e0, 0x47c2cb08, 0xcad9ac8c, 0x782c6744, 0x3877f539, + 0x667cb0a1, 0x6a5acdea, 0xaba22134, 0x595bef53, 0xd7baed1e, 0x7106611d, 0x64695ba9, 0xc04a4ba6, + 0x9a1f703f, 0x2fcb588a, 0xe234b254, 0x1ab435b8, 0x03a621dc, 0xb0810426, 0xbdcf07ca, 0xa998b6ab, + 0x2198130d, 0x37c333ba, 0x7574853a, 0x6dd58d90, 0x77ec2f98, 0x46988a4c, 0x3e362657, 0x6b636ab3, + 0x1d141092, 0xc53f826c, 0x3c03a51b, 0x54cfb3e3, 0x26f93616, 0xf3707c31, 0xcb7fad3a, 0x85ee6d49, + 0x2b0b7f7e, 0x5bc40ca6, 0xc2cd39c2, 0x6a37f940, 0x01d832ca, 0xc1bd25ed, 0x9b89edc5, 0xed4cf33f, + 0x55c73a9b, 0x3827ae09, 0xbdfe4ad1, 0x7f9b9f73, 0x4a661cf7, 0xbf569a25, 0xd08ca89e, 0x812a9f49, + 0x95bd1a39, 0x1470aa96, 0xbdbecd2b, 0xad2eef9b, 0x16761df6, 0x76c1a954, 0x1294f89d, 0xc73403b9, + 0x3f3560b2, 0x7e1fa6d1, 0xfbd6f318, 0x3de479a9, 0xcdbbf315, 0x90f5bda4, 0x33fcab0d, 0xf0649251, + 0xdfc5946c, 0x5f5d3d4c, 0xbaf2d4f2, 0xb154f189, 0x722a6e83, 0xfc731c6f, 0xca0368ff, 0x353c7117, + 0xe5e4ee3c, 0xd64a6a9f, 0xa95037e5, 0x5b69b5a1, 0x48046cac, 0xe17fe534, 0x549debef, 0x4b8a714e, + 0x7cfb0470, 0x9e00a9d6, 0xae660492, 0x11326b62, 0xf7fd08be, 0x5bfa307f, 0x50f2881b, 0xbb26ebfd, + 0x9e9b18e7, 0xb99b3ced, 0xb8bbc263, 0xda39d64c, 0x461786d1, 0x95d0cc39, 0x83a37363, 0xc278f8bc, + 0xc995dddd, 0x261f96a9, 0x53addc5e, 0xe173add1, 0x07a7f01a, 0x4ecadb2f, 0xe5c5ae81, 0xf2737182, + 0x352100d1, 0xbe08f46e, 0xda07d6ec, 0xb5f5a707, 0x77abffd2, 0x69ab1e52, 0x44c30b11, 0x065285e8, + 0xe2adb364, 0x8fb2fe74, 0x6ee6abb2, 0xfca5ae74, 0x629fe2da, 0x4643ec14, 0x156450dc, 0xb2c3e872, + 0x99fa04d4, 0x759f3f66, 0xe84d4df1, 0xeea09525, 0x6ca7ffac, 0x6acf9edd, 0x02d15603, 0x09635739, + 0xaa090ac4, 0xf6ccc439, 0x7014f157, 0x0e8057f7, 0x1817aee3, 0x9d6b549d, 0x5c9bf179, 0xdb6f4248, + 0x0df4e69c, 0xd4d19dab, 0x2e1166d1, 0x33c36fc8, 0xc1aee33c, 0x5484040a, 0x5bca5358, 0x1dfe2bf8, + 0xa933add4, 0x3555e99b, 0x4833be2c, 0x23d67a98, 0x510574ba, 0x89cbab58, 0x069d2d72, 0xfce82937, + 0x2963397e, 0x425c1a6c, 0x6eb697ac, 0x628ea4ac, 0xf2ee273e, 0x38573a70, 0xe9806a20, 0xbf5f341d, + 0x0e639f0b, 0xd2cdb5c8, 0x1a708314, 0x154e1789, 0x6bf570d3, 0x273c1079, 0x8eb92e0c, 0x39ae624d, + 0xff55bb24, 0xd18c1f72, 0xa360acab, 0x32eb9fea, 0x5c5e55a4, 0x6e2fd184, 0xbf6e55af, 0xe87182e9, + 0x8e0b687d, 0x06e8cfea, 0xae0a1fba, 0xdc0e7035, 0xbc94bd31, 0x96e62838, 0x58e6643c, 0x84b3ef7b, + 0x2ed3e83d, 0xa976b920, 0x08046880, 0x4f7f670e, 0x8cca14ad, 0x81c83a90, 0xb32c0d67, 0x197e3566, + 0xa7194a7e, 0xf79f70e4, 0xc1222224, 0xcc80585c, 0x2a828598, 0x705ad8f0, 0xb5dbbcc3, 0x7539b73d, + 0xecf2aa23, 0x3d91f883, 0xba39696f, 0x5ac5cbdc, 0x5b6af711, 0xde6fe3d6, 0x96367350, 0x55bc0e2a, + 0xa7c30129, 0x6709b46d, 0x9ce16c00, 0xdea4aa70, 0xa9c10414, 0x89b6d8a0, 0xacfa985d, 0xbd6f0693, + 0xda69543d, 0xfcdc5dcd, 0xe02541eb, 0x0069b975, 0x933d780b, 0x5d503403, 0x8b51e764, 0x2b28454d, + 0x2b0d5cf8, 0x11aa35d9, 0xa287b544, 0xd4361fc4, 0xa55320f6, 0x5047af8b, 0xc8e48e71, 0x1a3f6589, + 0x151a496d, 0xa09350d9, 0x2e0b1208, 0x29971c5e, 0x87281688, 0x1e3a54f3, 0x0069006c, 0xa7d130bd, + 0x7623a18c, 0x5450428a, 0xea84c221, 0xabd373d6, 0x875fc5ed, 0xe498f64f, 0xee16f435, 0x65dc2674, + 0xf30fd67d, 0x8ad7ccc4, 0xbca1af80, 0x9ee8e386, 0x8ebd3d48, 0xee28886c, 0x00f3ba83, 0x3a19b90e, + 0xeec184cb, 0xac1edbac, 0x73e1a9b0, 0x26f8d571, 0x69d431ff, 0x0d77eaa3, 0x5a6a8d26, 0xd285e69d, + 0x44aca4f0, 0x085e96e4, 0xa8aafaea, 0x53abf431, 0xa8cec312, 0xd627f5c3, 0x7c88fd46, 0x6bacf143, + 0xd842b7b5, 0x0c65af32, 0xe6542659, 0x3d91e4fd, 0xe2a3c013, 0xfd8259b5, 0x692af900, 0x275b093d, + 0x9afba6cc, 0xd4070783, 0x0ce69435, 0x16a1d7d7, 0x6b90e1a3, 0x415138ad, 0x4718fbc4, 0xe3d83a8e, + 0xfd914869, 0x9d204ec1, 0xfe57146f, 0x065fcde2, 0xbc6441c4, 0xd17802d7, 0x034e034d, 0x784ebec5, + 0x8bb98dc3, 0x6b1895b8, 0x64142d95, 0xf980887a, 0x6f35b927, 0x15fba0ee, 0x41cb262b, 0xaaaa8724, + 0xc655a375, 0x4d33b37b, 0xfa9e4933, 0x5fb778b7, 0xb4211a8a, 0x065cbd60, 0x3fcf8c6c, 0x155649fc, + 0x19ddb91f, 0xf05e1a76, 0x5723d844, 0xb8b3c00b, 0x5cf4e7fb, 0x3ab9040f, 0xa8d0673d, 0x0e9a9d0e, + 0xd1c7c3b1, 0xa5f9e76f, 0xdf13de66, 0x0053f306, 0xd44858cc, 0xb426b9d8, 0x8cceed59, 0x04e1e89c, + 0xd1558360, 0xbf54aba7, 0x75867791, 0x62f0a8ed, 0xeb851eb6, 0x3150fc76, 0x1d381294, 0x4672f854, + 0x5912bf64, 0xb63e099e, 0x40dc85ce, 0x2316278e, 0xeacb678c, 0xf1421c52, 0x3fd669c2, 0x3a765ff6, + 0xbc108851, 0x2fc9241f, 0xb6979972, 0x89444108, 0xcaca2fb6, 0x76dda24d, 0x065384c9, 0xbdec2306, + 0x3b12c757, 0xab22021c, 0xd3919a18, 0x9a7a2d58, 0x4a041ae6, 0x04abeddb, 0xce35fa8e, 0x96a3fcea, + 0x69858c87, 0x94c3aa53, 0x11890661, 0xb3ecb87b, 0x25764542, 0xe810debf, 0x8d08a6fd, 0x4edfa270, + 0x59c7c9ab, 0xada17146, 0x0f4e22a9, 0x0e5d3b6a, 0x38d34ccd, 0x51a20462, 0x6e58dd42, 0x26d05d96, + 0xdd79d1e3, 0xa3e4eca5, 0x5c89973a, 0xb5227068, 0xf574b90f, 0x5f353e9e, 0xdd2caf7f, 0xe6ff0d8c, + 0x914f1be8, 0x87e573c3, 0x0e0dca61, 0xf513ecd9, 0x7ebfcb5a, 0xdf5b087e, 0x84e8012d, 0xe099b285, + 0xbbe22294, 0x02049ea5, 0x664cfcb5, 0xcef9b02f, 0x9619e97b, 0x9142173a, 0x8caabffc, 0xd3110316, + 0x37af09d4, 0xa630ac93, 0xba9661c0, 0x5361cd45, 0x7edecd91, 0xd286453e, 0x501b6756, 0xcaa18160, + 0x216f5aeb, 0x05bd8717, 0x5755262f, 0xf0ed99e6, 0xf190646f, 0xc6cabd07, 0xcd5c75f1, 0x28badb48, + 0x9bbdb5bb, 0xb645c203, 0x9ab0747e, 0x3933ec4e, 0xd8b18ae6, 0x6b5e4f32, 0x5ff42499, 0xd09057fe, + 0x1b70a382, 0x807d54a0, 0x008edb2d, 0xc631c48b, 0xf7afa28f, 0xcbcef3d9, 0x8de278e6, 0x9500ce73, + 0x27f4575c, 0x4d979339, 0xa69f8e58, 0xe92b28d7, 0x10c776e2, 0x3645d1a8, 0x4809e1f9, 0x165b8753, + 0x6ac6669c, 0x8d9ba7c1, 0x022ed894, 0xd5eff6fa, 0x25376943, 0x1c06c941, 0x7cb7e808, 0x0bfc9f6a, + 0xa3382c07, 0x639efb0c, 0xf6ad004b, 0x3c1f8ac3, 0x1d2d3f6e, 0xbab4ea3c, 0x9f63faf6, 0xa21ea36f, + 0x92adc2ac, 0xc903fee2, 0x838ff78d, 0xd404af54, 0x1a93de4f, 0x553fff0d, 0x866b800a, 0xc9b673ff, + 0x890d666c, 0x55d60058, 0xd663fc23, 0x53505d7d, 0x0e2e6f37, 0x85f30d89, 0x30a9758a, 0x94d232e2, + 0x3311ec03, 0x968644b2, 0x148b78af, 0x9a167b68, 0x439b4710, 0x05e736c2, 0x22cda9cc, 0x878437f8, + 0x73d126ca, 0x6e3ae41a, 0x81adf35d, 0x654105d7, 0xf45c20b2, 0xe2870753, 0xe201df81, 0x91099dda, + 0x1549971c, 0x3b001dfe, 0x1154707e, 0xbaaa1899, 0xa73d1a21, 0xe7768996, 0x118f0859, 0x00050017, + 0x165dd33a, 0xd119d10f, 0xa1cdd11e, 0x06bf61a9, 0x70a91923, 0x9d95e34a, 0x86943633, 0xdaa25b18, + 0xd2e5babf, 0xda8a94cb, 0xc059197a, 0xaa82a0a6, 0x63d15023, 0x20e96dfc, 0x7c61f05e, 0xacfa707d, + 0xbcd84257, 0xb9052e3f, 0x49b9a188, 0x4e0bb401, 0xb02c9950, 0xd20048e3, 0xa6ba2593, 0x944f2e04, + 0xe3976cac, 0x03eb7a71, 0xfd0b5944, 0xfd69a354, 0xa930a437, 0x1e587461, 0x50435dae, 0x5afb7811, + 0xe75fb66a, 0xf76a8492, 0x5712145d, 0x85581139, 0xb778a11e, 0xf4630f46, 0x7230a0ea, 0xfc88c44e, + 0xaad94efe, 0x58d1d323, 0xeb285aad, 0xe0a6ace8, 0x0bafd414, 0x01f05b0b, 0xdb043103, 0x269ce2c2, + 0x7a64d65e, 0x49df36fd, 0xb2ed7b4c, 0xd4d97fe7, 0x01ab90d2, 0x2caa9f25, 0x4f194b6e, 0x68c70139, + 0x7e278e31, 0x590c420c, 0xa3203708, 0x90502ab1, 0xe4a37b78, 0x74121b7a, 0x7e1dc159, 0x486283bc, + 0xc96309eb, 0x655f9c8e, 0x23e616de, 0x4b03efbf, 0x7001a3a3, 0x9fbeaea1, 0x61b07f9e, 0xfa019bbf, + 0x11be6d3d, 0x3af5906f, 0x3ce41be9, 0x277d7c59, 0x53b4a75a, 0xf4635b76, 0x55ddcb20, 0x6df63cc6, + 0x00a44a8a, 0xe4ba2f6e, 0x1c9a5d08, 0x95bb8748, 0x43d8eb2a, 0x85b66227, 0x340e4a11, 0xb8bdc2ca, + 0x787a6355, 0x3a3b5d4f, 0xf4fa424e, 0xb5ad0565, 0x16172bf7, 0x5c8fedfc, 0x9477b86b, 0x5c428a3b, + 0x68575a17, 0xdac974af, 0x427e0b4b, 0xa93aca87, 0x25f5bcbf, 0x5b202fcd, 0x1cbe69f5, 0xc8044f3b, + 0xaf7837cc, 0x61e1085a, 0x526f2a1a, 0xcba68a5a, 0xaf5acc89, 0x03a6caee, 0x661b2178, 0x96133bb2, + 0x1c51bf00, 0x7e1e46db, 0xc9154591, 0x8e1f8c56, 0x586a49ad, 0x48cf6a0a, 0x58c4a27f, 0x0e9c76a3, + 0xdaa6fb5f, 0x73fe7efe, 0xf479957a, 0x34f3d3a5, 0xd127f181, 0x1d7e17b1, 0x8b2cddbb, 0xc0c37d18, + 0xdbf7c8ce, 0xb1edf1fc, 0xd6134868, 0x634a8742, 0xea0eced0, 0xa10ca763, 0xbec09d4b, 0xd09c5f07, + 0x67950319, 0x5de18bdc, 0x98a30f0f, 0xe37212b1, 0xe2be0c00, 0xbc008c68, 0x0c6f6aa5, 0x80c7990c, + 0xdf3d5896, 0x6bbb0714, 0x075e47c1, 0x4e7ad165, 0x6c44df7a, 0xdef43443, 0x23f42d07, 0x124016a9, + 0xd1bdefce, 0x07eca4ce, 0x3e6df943, 0xef5e89d7, 0xdd19a770, 0x08df36bf, 0x20903816, 0x5029603a, + 0xd0e7257e, 0x1206a117, 0x844e1b9f, 0x13a834b6, 0x1d98293f, 0x0c6fd988, 0xc287e47e, 0x988c3e80, + 0x90337562, 0xb90e71e8, 0xe51aaf82, 0x0112ed62, 0xd36353d3, 0x60513770, 0xef525241, 0x267d07a3, + 0x75928aab, 0xec13844b, 0x2feff8a6, 0x5e9ba6bd, 0xf188275a, 0xae91e8ec, 0xd9a9f89e, 0xd45f08b5, + 0x91ca86c3, 0xc7a5b82f, 0x62dd0edd, 0xdd359e5a, 0xe1a6b301, 0xbe8d9d8b, 0x6fcfd01d, 0x7bc57d05, + 0xe60749ea, 0x8c7cd4b7, 0xc51c5396, 0x55a5d7f5, 0x5ba6f17a, 0x57108080, 0x84eef65e, 0x68bd4fa6, + 0xc27e7d13, 0xc0c2f06d, 0xc86c789d, 0x89303490, 0xd68491b6, 0x54549d42, 0xabdf70b3, 0xac95d288, + 0xb4dcb609, 0x7183c8ff, 0x12cc3d05, 0x4ac56dd8, 0x9a8140ec, 0x8f047417, 0x8f68d123, 0x366131cb, + 0xc3a56e89, 0x719e06b6, 0xcb4183c0, 0x78c8026f, 0xcc7014e3, 0xae2c6798, 0xc85cdb04, 0x7f6212b4, + 0xd262e9ae, 0x3de1a43a, 0xa4ca98b9, 0xddf3405c, 0xea4fa258, 0xa6519f7e, 0xaddb7c8c, 0xfdfd9cd3, + 0x42c941a0, 0x979cdc72, 0x144d2a24, 0x8bc96737, 0xd62048ab, 0x3157787f, 0x2fe46328, 0x01383ed7, + 0xf356c22f, 0x9f1784ef, 0x5ce746ef, 0x7694413a, 0x9f7540f5, 0x769ee671, 0x0df2eb8b, 0xa3a88cd9, + 0xf9660194, 0x4a37b69f, 0x17cd7a33, 0x15cddbd9, 0x2ea765a5, 0xbae8c54d, 0x7e75fffe, 0xe6f97bff, + 0xbe1223cc, 0xc4ba43da, 0xa51fe46d, 0xaef85f79, 0x44220a2e, 0xfee4a3f7, 0xa2e2cb42, 0x40dbed6c, + 0x2d6443d1, 0x3f26b607, 0x3dc530eb, 0xc6d92da8, 0x525f3825, 0x2b32769c, 0xfcd53d08, 0xdfa44671, + 0xf8b1dfb7, 0x520234e5, 0xa9419b72, 0x2239edec, 0xf8e54833, 0x4192a755, 0x9af5e16f, 0x397e1554, + 0x2da9c707, 0x095df26e, 0x5cc66392, 0xbcae7a00, 0xaab3eee1, 0xb493c1d2, 0x6cfe4e7c, 0xdf88f078, + 0x44550ea7, 0xdc3cffe8, 0xface5523, 0x90f8eadb, 0x030eda80, 0xd43d787f, 0xbebfda9b, 0x7cc345ab, + 0xbc5b80a0, 0x4b313616, 0x638c03f5, 0xd624af12, 0x09b8db55, 0xc61ef342, 0x8bd15dcf, 0x9104f61a, + 0xb3dcc205, 0xf3ca8a5a, 0x7522f0c6, 0xc35b6e3a, 0x5735098e, 0x2e87daf1, 0xd9e1bca5, 0xaeb80658, + 0xdb5b9fd3, 0x654466c6, 0xa4a8098c, 0x4435cfb2, 0xffa8ac9e, 0x52845607, 0xd02c6150, 0xc68e8a16, + 0x5d62c350, 0xa6e9efd3, 0x3e43b30f, 0x8bff84ed, 0x55663d7d, 0x4b3bf7a4, 0x52ee6778, 0x36267f56, + 0xec29ff86, 0xe78945a8, 0x9c74c85f, 0x12f7db16, 0x69d5ac23, 0xe30effd4, 0xb4480000, 0x6f7ef61d, + 0x958b03a0, 0x7e447c40, 0xaff2a6ca, 0x6b62fbf0, 0x07e0284b, 0x5ab286b7, 0x1a330eb6, 0x77c6fdf4, + 0x36ae38ce, 0x034c2479, 0x5259cddf, 0xad7d7e82, 0x6212ca2b, 0xefeb07b3, 0xf7e3aacb, 0x57c28b29, + 0xb8713235, 0x847cabf1, 0x43cdce4b, 0x04f6b1be, 0x80b033fb, 0x78fb0369, 0x60ccd428, 0xdde0a422, + 0x975c8f69, 0x53ce7770, 0x4d994732, 0x8c34500f, 0xd72c69af, 0xfbc80f8c, 0x9f278170, 0xd9f85a5b, + 0xcfda513a, 0x9489bbf0, 0xfab2dedf, 0xabc295e1, 0xbab1b773, 0xa8830b4c, 0xc8d450eb, 0x33d4f148, + 0x6c82e7fb, 0x4cd8be82, 0xe6462324, 0xdb7e64e1, 0xfe0dea5e, 0xae36d8e6, 0x6a2a9490, 0xcf1e2f44, + 0x379f7837, 0xd7ede76f, 0x246ee175, 0xdee15826, 0xeda4d525, 0xf55764d5, 0xd1beda3f, 0xfee8b8f7, + 0x3deacb9e, 0x877deda6, 0x916ffbce, 0x40af4a23, 0xbba29a02, 0xae176bbd, 0x807f86e3, 0xabb8b612, + 0x3d33d0b1, 0x216c7a47, 0xe5b71e18, 0xfd6eaf4c, 0x4b134f3a, 0x4182408d, 0x73ead278, 0xdf9bc5d5, + 0xef24577c, 0x30e5ca7f, 0x856df358, 0xe5603554, 0xa2c76558, 0xb68e87cb, 0x3a0ec37c, 0xfa033bc0, + 0x364dc183, 0xc534c5eb, 0x5af704c7, 0x6662c6ce, 0xfac2ad0d, 0xa81ab1c7, 0x1c4e60a3, 0x1a34b33d, + 0x4529a4a8, 0x935fb6ac, 0x716615e6, 0x319e12e7, 0x70589438, 0x60edf2a0, 0x7bb74a9a, 0xf5c0d16b, + 0x4607e1e0, 0xe6d60c4b, 0x339aad12, 0x4438579a, 0x12b413cd, 0x2dc75fe6, 0x97cc8a6d, 0x1a0b7ae2, + 0xcdf1374c, 0xf4fe97e0, 0x9dd4cac1, 0xa3a52d34, 0x6fee5a3f, 0x9afe4050, 0x2e23fd25, 0xb29569f3, + 0xed802abd, 0x14ad4733, 0x76589765, 0x7a94fa10, 0x2855c657, 0x7fe85c6c, 0x7e082c7a, 0x9c5594dd, + 0x6dc4bc5a, 0x64cd53cf, 0xec9775a7, 0x43441007, 0xe8074dd8, 0xd925aec4, 0x3406c255, 0xe8071808, + 0xb929fc57, 0x79c1d37a, 0xc7fb2fd6, 0xfa314afc, 0x56d9bd5a, 0x6e3f9f8a, 0x82c21904, 0x0741c807, + 0x711d068d, 0x8f5cd542, 0xcb3d105f, 0x91e5894d, 0x7961223a, 0x097f8189, 0xb7ed2a88, 0xba50ecd9, + 0x8edafc65, 0x960e9360, 0x0eaa347b, 0x397b98e7, 0x8f6f3041, 0xda1ae861, 0xb798a94f, 0x8695745a, + 0x867cfbfb, 0xe180ce60, 0x469c35dd, 0x79837673, 0x90eaf87a, 0x803a7126, 0xce11aa85, 0xbcac0f28, + 0x914daadf, 0x0a666080, 0x36826cee, 0x54e3c9d6, 0xfaf9cab7, 0x3e9753dc, 0xb8e4b62c, 0x1cc3c35b, + 0x45c3b08d, 0xb731061e, 0x244b088c, 0x77e8f079, 0x20200a2a, 0xd4efa3fc, 0x32e4e6be, 0xf43d2ca1, + 0x9264d0e9, 0x96a757e4, 0x68d1299d, 0xf91f3ac0, 0x2bb3d5bb, 0xa8a6bfbb, 0x90c34fde, 0xdcad1ff4, + 0x09063fd5, 0xf5206023, 0x4352cf65, 0x6a2ca989, 0xb6c20036, 0x03e4afcf, 0xfec82a40, 0x94c2712a, + 0x035e367e, 0x7696dc65, 0xb55b442c, 0xcbfc77fe, 0x6d5fdf8e, 0x75d87b33, 0x274f426c, 0x5778433d, + 0xdccd3100, 0xaffcc114, 0xb7ffb94c, 0x384525d8, 0x27d25b6d, 0x3de3acda, 0xcbdcc2c4, 0x12793e5f, + 0xb83944bb, 0x8d364401, 0x7cb2a4fb, 0x97af34d4, 0xfd7523dc, 0x37848a19, 0xda0b1886, 0x08ddf9b1, + 0xcc100bdb, 0x8a147300, 0xa383a7b9, 0xd88bb901, 0xb8bfd63f, 0xda669d76, 0x4905b55c, 0x1464592f, + 0xdb855e9e, 0x59aee2bf, 0x7d7cd6aa, 0x8ed10a37, 0x7d93a185, 0x399b235e, 0xa7b2fbf0, 0x92168795, + 0x1569d533, 0xf337af65, 0x9e82ba98, 0x52683cfd, 0xbd28a711, 0x55efd1c2, 0x0ab44aea, 0x242c86ec, + 0x63de6822, 0xc63de2c4, 0xf7da1cf5, 0x1da98b34, 0xf9b205dd, 0x5f7edd7f, 0xec1de0aa, 0x1891d2bf, + 0x4aac0cf2, 0xee48da2f, 0x4522a731, 0x6b0adc37, 0x30b71d12, 0x169dd70f, 0x800d4538, 0x1578facb, + 0x6ca74e77, 0xa08dea95, 0x17c304f5, 0x95580a7d, 0xc143ca5a, 0xb7fef39a, 0x6f20cf32, 0x8472eb2a, + 0x5c5d4acb, 0x8232aee1, 0xd80d9964, 0xf468b258, 0x2170f67b, 0xd561c7ed, 0xbb2d812a, 0xb0411128, + 0x14617052, 0xed7a6eaa, 0x096fdf94, 0x6e3ce131, 0xffb6d4d3, 0x1f503112, 0xa33b2201, 0x560eac09, + 0x72b415f1, 0x2a85c478, 0x655925e3, 0x6c155c70, 0x6542ba81, 0x2753f325, 0x3bbd1f5b, 0x444ebc1c, + 0x7e515541, 0xccb13b7a, 0x9e1de189, 0x89a1c0a7, 0xa96340cf, 0x62baaa1e, 0xc4950bea, 0x461520bb, + 0x24028a16, 0xe0eb161f, 0x2c1a71bb, 0x228c3b02, 0x91e6ca1f, 0x9748a756, 0x7e78c9f2, 0x05ffadef, + 0x9de7c501, 0xd6d0e72c, 0x5dc31324, 0x99aa2528, 0xda0da7c9, 0xa89a9030, 0x64cc7ef2, 0x00bcce8a, + 0x6c0636d5, 0x36457121, 0x7cf1f208, 0x06aa6ffc, 0xb4fbd324, 0xcb16d457, 0x12506f44, 0xfe05c546, + 0x2b98b8c9, 0x6006dcb9, 0x1dd3ddbb, 0x01d0ac22, 0xe245bbbb, 0xdcdc3832, 0x6262d739, 0xcb9e09c1, + 0x25fb701c, 0xe6209d2e, 0xdd7aa5bb, 0x8deef78a, 0x336d4ebb, 0xab7cad3b, 0x196f917e, 0xc79c1130, + 0xe42591a0, 0x016df040, 0x1bd5ee31, 0x73cf10b7, 0x0681ec98, 0xd59f918c, 0xe31a0dda, 0x7a38de3e, + 0x515dc680, 0x5b455cbc, 0x4923e780, 0x9dc681dc, 0x09cb2d4a, 0x11e19e69, 0xc51b464b, 0x945fbc54, + 0x28c7cf21, 0xa3c95f85, 0xa0c3eeca, 0xd0ee2e25, 0xe6ec9ecf, 0xac1fe005, 0x1e582574, 0x6a703a60, + 0x87c7b5be, 0xc1e0e23f, 0xa22831a3, 0x569a5cce, 0x7adf1fbf, 0x5e2e3db2, 0xa25877aa, 0xaacf4746, + 0xfe1f6173, 0x73477122, 0xc6c4a008, 0xa60f74ad, 0x1f85f860, 0x9f9c9e36, 0xa55cc80e, 0x7f8b6007, + 0xa9d9b6ca, 0x8c062557, 0x28db199f, 0xd7ca692f, 0xf85d6760, 0xa1614901, 0xbb83d07c, 0x96ccb35d, + 0x912fad09, 0xb0a0510c, 0x58f763f5, 0x51dc5fa2, 0xc01e2527, 0x05075dbb, 0x0f178bba, 0x56daa7c0, + 0x233c3b8b, 0x2bcdbce7, 0x8fbbe134, 0xb81526e0, 0x0a3595c8, 0x78fa7682, 0x68ef640f, 0xd8003111, + 0x186e2a00, 0xa4d5f7de, 0xf912f228, 0xbfdbf151, 0x0f2fe500, 0x055414d4, 0xb29493b1, 0x19413997, + 0xb823c104, 0x6ac29275, 0x496a6f3f, 0xf3fe1c50, 0xa23838ea, 0x03af71b3, 0xf4d417e1, 0x525ab4ff, + 0xab87aca0, 0xddaad3c4, 0x751390b8, 0x665853ff, 0xa9efa169, 0x72033537, 0x57df1d86, 0x93f41d68, + 0xc48d2454, 0x0b46f4cc, 0x4dba581e, 0x3b1d453e, 0x4499530b, 0x78fc0ffb, 0x0f24ca14, 0x41e60293, + 0x4ff6f815, 0xdb3b906e, 0x23194e38, 0x6769c0f4, 0xcf543c87, 0xc0314dbe, 0x25463e1d, 0x0eecfcbe, + 0xcf46e679, 0x97bcca7c, 0x4c182671, 0x8d10b2a9, 0xc07fa086, 0xd027dbc9, 0x6602ae67, 0x01e05351, + 0x0aa15437, 0x27c67458, 0xf00048a4, 0x03cfe4ba, 0x3b658b6f, 0x20366366, 0x857dc22d, 0x3d1850df, + 0xc4d8240d, 0x932392f8, 0xb869a7cf, 0xee216b3a, 0x4be26e45, 0x0ba8fa6f, 0xc22c709f, 0xf1acd29f, + 0xf660dc3a, 0x8fc5170c, 0xbe821faa, 0x3bcb4aee, 0xdee44b03, 0x5d54f2d1, 0x9338ee83, 0x15f4a36a, + 0xe7d90b43, 0x5ce5c224, 0x8c3236bf, 0x61e152b6, 0x3dadf5e3, 0xd9062d09, 0xf99795e2, 0xa0e64e53, + 0xd27e8994, 0x53737427, 0xc1db448f, 0xc840dd2c, 0x37b1dbbe, 0x5a542a49, 0x098705d2, 0x54aa2d46, + 0x40dac555, 0x23285046, 0xbac91581, 0x673258f0, 0x0b15a3bf, 0xa86cb66d, 0x1f32cb89, 0x3b116abc, + 0xa7dd1da7, 0xce9257ac, 0x6ee521a6, 0x943d451a, 0xcdcbb447, 0xde41cab8, 0x500308cf, 0x1ae9ff1e, + 0x8a71645b, 0x8e328e0e, 0xd29594cc, 0x480c6a42, 0xb43d8408, 0x4b640285, 0x90548134, 0xb3e3decf, + 0xd2fdfa10, 0xeb8d8352, 0x573fd4a3, 0xebcc93ab, 0x4080b77e, 0x1a62276c, 0x3b370905, 0xde10d007, + 0xd6c94e63, 0xa7e4a36f, 0x4b7f2988, 0x711935d2, 0x00d3d232, 0x056e5401, 0x7768d21a, 0xa382caf6, + 0x5d2842ae, 0x404fcd2c, 0x5a46e739, 0x4967dafa, 0xd020ebba, 0x2c6647eb, 0xaf265f1e, 0x5738945b, + 0x7d050adf, 0x5c136374, 0x38234a94, 0x20882025, 0x1aa58619, 0x000b6281, 0xf15104cf, 0xa61bd7f2, + 0x65534aac, 0x73e9882b, 0xb451eb86, 0xa58977ac, 0x07c5486f, 0x1b1aa5e5, 0xfcb94706, 0x98b68ec8, + 0x12beca5c, 0xacb79643, 0xcb15802f, 0x38aafb2d, 0x400dd91f, 0xe587c38c, 0x761bdc74, 0x1c584f7a, + 0x448e9e0d, 0xa752d4f0, 0xeae2418e, 0x080efcd7, 0x86c364ff, 0xaa88a656, 0x861947c4, 0xeee2d0ae, + 0xc5a3d7d6, 0xd173ea3f, 0xedcf8919, 0xf680a52c, 0xf7a2e072, 0xc237b41f, 0x3846ab79, 0x387a6087, + 0x8c12d736, 0xcefda7e7, 0xca117bec, 0xbf5567c9, 0x51636739, 0x129a33e6, 0x87edc9a4, 0xfb54471e, + 0x31cfd7b0, 0x53426a11, 0xedfdfa35, 0x5605b2fc, 0x1e18a841, 0xfd1d786c, 0x01494cc6, 0xdcec75ca, + 0xd91f0b5b, 0xb46f8992, 0x375a29ce, 0x41dc63f3, 0x902ba4e9, 0x0ffea7a7, 0x128f7a0f, 0xbc47a305, + 0x3067dafe, 0xbd8d5fb8, 0x97295689, 0xbbe7e7af, 0x725d3c68, 0x24021e85, 0x79f7417f, 0xfa5dcdc7, + 0x36b4c747, 0xb1f09e6d, 0x7f8c8146, 0xf00da06f, 0x61fabc7b, 0x91d6586e, 0x7d6096d6, 0x72bd9437, + 0xbf3dcff8, 0x07af8ec1, 0x6343897f, 0xc4f91123, 0x2024a7c0, 0x1777d143, 0x94343012, 0x52055d51, + 0x9bae5245, 0xa6992f9e, 0x618e75fb, 0xb1a2e11a, 0x9302df76, 0xd405745f, 0xaa8cf361, 0x68211721, + 0xf23380d3, 0x157dadd5, 0xee1ccbd6, 0xe40f80e2, 0x4e575ff7, 0xe0d18cd7, 0x1c19daa0, 0x52596610, + 0xe8c1ad5d, 0xbf215e56, 0x4eab1aeb, 0xca9fdb8b, 0xf9493493, 0xe45f39af, 0x4371b158, 0xd02cd0ea, + 0xafdcf3b0, 0xaa36ac99, 0xf47756c1, 0x5e12de78, 0xb68292d5, 0x165c5755, 0x91a3ed94, 0x92ba0edf, + 0x6fe6103e, 0x70625e53, 0x8da149e4, 0xd093bb8a, 0x40bb8709, 0xa653e1ab, 0x00df2502, 0xdb371cb7, + 0xff47fc06, 0xac922108, 0x1147a87c, 0x16161d53, 0xcf425c15, 0x7070c1cd, 0x47fefedb, 0xb4652b43, + 0x12eacaf0, 0x5511a7e4, 0x6024a0f2, 0x982f2918, 0x860736b4, 0x1fa17bcd, 0x611b4350, 0x71a7cab0, + 0xd090ff47, 0xe2c077fb, 0xb0a8139c, 0x42164da3, 0xf132ea0d, 0x46ebbb11, 0xb981718a, 0x1403b9d4, + 0x1b592bba, 0xaf626a8f, 0x3a1eba0f, 0x023bd794, 0x66837e45, 0xa6cafcaa, 0x45e8d906, 0xb0c8c345, + 0xe3f207d6, 0xf4aeb802, 0x92c6f52a, 0x8b3ffddc, 0x3098b8fa, 0x1c12f398, 0xbb32d766, 0xe2ccdb28, + 0xd1b684ed, 0xab3be6e9, 0xd1c3939f, 0xd8bbf06b, 0x091dfe58, 0xb837f413, 0xd7c40e0b, 0x32854cb5, + 0x14476701, 0xbc8c4cb5, 0x9c4b41a1, 0x11dac87d, 0x625482bd, 0x190e7ef6, 0xd1c414fa, 0xb79f5c71, + 0x47e71eeb, 0x12f3bec9, 0x79c4910c, 0x29100c56, 0x37860919, 0x5dcfc018, 0x155e26c4, 0xaddcbb5d, + 0xae76cf98, 0x2ae2e06a, 0x1b81bea2, 0xb5b97060, 0xa0ab505e, 0x9cfea10e, 0x2e8c4b90, 0x9d94f66d, + 0xd7810939, 0x3fd445ae, 0x501f98f8, 0xff84fdd9, 0x669145a5, 0x0eb058db, 0x021d8d87, 0xdcb286c0, + 0x1ac6ebed, 0x4e5345e2, 0x743e67e4, 0x8e816596, 0xa66e153a, 0x3149a659, 0x265d7fd1, 0xab2f0ec2, + 0x1f2cbee8, 0xbfa6ba1f, 0xe15767a1, 0xb653c61f, 0xe26b87ae, 0x9eae7edf, 0x07994400, 0xb07f801e, + 0xfb98f287, 0x0d951cdd, 0x45242ac7, 0xbb7ae7be, 0x9275e549, 0x8c17bbad, 0xb2a7276d, 0x70c217da, + 0x26ec2747, 0x75a50033, 0xfcf736ef, 0xeaace435, 0x53caa1f6, 0xbeb6097e, 0xa9b4c942, 0xfa663f68, + 0x51178671, 0x13ef534a, 0xb214df25, 0x92f43779, 0x55e4ac92, 0xb66212d4, 0x4714a71b, 0xed8e6bf1, + 0x7b4cf46e, 0x6dff668e, 0xa5ff51a5, 0x7bed5a1f, 0xa8688ba5, 0xc1fc9c93, 0x7d645c85, 0xd967fd23, + 0xa4a2c988, 0x4cb4a131, 0x9f64dcb3, 0xb6dfee06, 0x16971b6e, 0x24c1ced2, 0xbd7aa6ee, 0x9a53165c, + 0xbefbdee2, 0xb3854b5e, 0x9a168433, 0xd68d5eb4, 0x2d3b3150, 0x09d71682, 0x92d687eb, 0x95ed0c1f, + 0xa9591400, 0xc4822337, 0x58cb51c2, 0x21529ebc, 0xbadec3b3, 0x9730543e, 0x1e7c12a0, 0x2940ea70, + 0x30c094aa, 0x00d82dea, 0x27f3023c, 0x486710e6, 0xbd410a9f, 0x7acbfec2, 0x4a59a7f5, 0x16f4e096, + 0x961012f4, 0xdf16f9b4, 0x12c21f7c, 0xc1bc4890, 0x2ef13aa4, 0x88fef5cc, 0x9775642d, 0xae10a976, + 0x133bc604, 0x0922fda1, 0x7950ec08, 0x74b3cdc9, 0xaaa7b260, 0x414775b5, 0x290c216a, 0xf392a5e0, + 0x9d1551a1, 0x0a87c3e8, 0xf0e802d3, 0xd26c5dd9, 0x17097e6a, 0x795f6f03, 0x5b487c41, 0x0d7c0ae2, + 0x3c4ce451, 0xc4922923, 0xf2066266, 0x788ac14e, 0x2b92c5f5, 0x16f4bdab, 0x42e2e758, 0xb1b59242, + 0x9c5fcf1f, 0x1c4fd2a3, 0xdb35ceb8, 0x11937254, 0x4013c5bb, 0x2b70f083, 0xdfcc49a7, 0x30863bb4, + 0x31ffe3e9, 0xbbde264e, 0xc321807b, 0x505b572f, 0x093f0a1a, 0xdb6952dc, 0xa506ff4a, 0x0a5c0578, + 0x4d0f8e58, 0x7a6282e2, 0xb52a49da, 0x16572343, 0xa665c36f, 0xf250be05, 0xe7b42384, 0xa4451484, + 0xc5457252, 0x9ec9df66, 0x1423eb5d, 0x63f4a38e, 0xa0ff4b4e, 0x3e189088, 0x48e492f0, 0x294daf97, + 0x33f4e6b9, 0x6bed6cfa, 0x25dee303, 0x271c279b, 0x0a6953fe, 0x55317a9f, 0x92c4ea13, 0x7b5ba95c, + 0xbfc11db1, 0x84cca65c, 0xbddeecb1, 0x6e387ed9, 0x1793335d, 0xab04a412, 0xea84af07, 0x47c9059b, + 0xa79d1060, 0x06de43be, 0xe3cd9586, 0x63974530, 0x1c21a31c, 0xb7d47be3, 0x51d06b21, 0x4fe499b2, + 0x100abdf9, 0x6058b5a9, 0x94d96714, 0xc0869dc5, 0x21fe650b, 0xd7ec7122, 0x903f5f4e, 0x2cf7fb71, + 0xe197d892, 0xa13e3a90, 0x6a8b8575, 0xf65abfb8, 0x8624a3fe, 0x7e048e70, 0x7c19e9e0, 0x54096210, + 0xb4746605, 0x2e04b04c, 0x1347bc56, 0x5eb38f49, 0xe9541a21, 0xa0378a68, 0x83dc93a1, 0x1ab4bbd1, + 0x35c12f55, 0x9ef3510c, 0x9a545e94, 0xfaface93, 0x7c03369e, 0xb85265e9, 0x28c98a61, 0x851834c7, + 0x053d8877, 0xaeca375d, 0xbd12bb08, 0xa41b6714, 0x6465fe68, 0x6375aa25, 0x5a7a22ad, 0xb36bb606, + 0x4611a66e, 0x50d59447, 0xceb4a0e2, 0x0cbdb3b0, 0x7e45832c, 0x113cd190, 0x3000fce2, 0x73747820, + 0x18a4d8b1, 0xc6982004, 0x7d855f4b, 0xbcef72e1, 0xcf118a49, 0xd63a1c84, 0x33f803c3, 0xe8bcf818, + 0xab2109d5, 0x2f68583c, 0xef2f9546, 0xdfbf348c, 0xf19f1d6d, 0x44fe6a47, 0xa4adcf16, 0x03f674ed, + 0xdaaf99b1, 0x279c21c0, 0xa83813ab, 0xbfb68220, 0x8783de6c, 0x6dfe00df, 0x684f1700, 0xa3b20e2a, + 0x3d9bd891, 0x64d1f264, 0x13764194, 0x9ef78b5e, 0xf25bb72f, 0xf12f06c3, 0x85775f1b, 0xe53c1a01, + 0xd0ed0b4b, 0x0814d6aa, 0x5d41d8f0, 0x9e8724f1, 0x7efb1b58, 0xb08b37f7, 0x2f6182be, 0x92a894e2, + 0xa7de38b9, 0xc79ce221, 0x8e370da2, 0x3ce5d714, 0x4fe510a4, 0x74c8af40, 0x36879ba8, 0x166d7534, + 0x7f9e710f, 0xa3414436, 0xc32a751e, 0x0882de99, 0xee1ee86f, 0x0658d073, 0x8c430beb, 0x7f7bb695, + 0x322c6a05, 0x4a6f9c1f, 0xfe1b9ff4, 0x5b5ac095, 0xe049ae02, 0xfd6a66f3, 0xc02ebf6d, 0x48706bb5, + 0x98d51b39, 0x83720db5, 0x34024d83, 0x1938c84e, 0x8ae8d1ad, 0xc49f1140, 0xf85e6227, 0x5f631249, + 0xc203dcda, 0xe53a9de0, 0x8a260893, 0x0aec6cbb, 0xd1e44136, 0x3e901ff0, 0xd4e2978c, 0xeb7f5600, + 0xcc5cd914, 0x05d0ae19, 0x5147c28f, 0xed2db101, 0xfcb68764, 0x88a96f02, 0x6f822bb0, 0x3d6889ae, + 0x329d647c, 0xc07dcfc5, 0x3f13f074, 0x117d9b76, 0x2df17ed3, 0x4427700f, 0xbfe20645, 0x7dd57285, + 0x0bd95a42, 0xcec9b626, 0xdbaf6af8, 0x95cd4241, 0xd675cad5, 0x999aaf4f, 0xe7004338, 0x3c2781a7, + 0x926d8569, 0x69b8501b, 0x1eb8d4be, 0xa3c1138f, 0x9c751b23, 0x3247da5c, 0xdafa3a0c, 0x52e39cd6, + 0x4fa2ccb9, 0x2ed11fb9, 0x3f764ff8, 0x442e6e00, 0x345300d1, 0x5dff8b01, 0xa5a38b27, 0xc7150aad, + 0x1174b173, 0xe6e4f5f8, 0xcfb12fb5, 0x66584ee0, 0x204e4c8d, 0x119f3c17, 0x8cf62c85, 0xd7084e76, + 0xa4daff48, 0xf2f3a0b8, 0xd2ab2987, 0x5a2c3dd0, 0x3a1a7226, 0x64f47359, 0x59de0a5c, 0x3359d829, + 0x0d41ed6f, 0x918e0f50, 0x7c0fba95, 0xaf34a9d5, 0x8a5fe55a, 0xe22472d1, 0x48fcefdf, 0x65ab3a0f, + 0x54dd707b, 0xd92dfba1, 0xf88a7a5a, 0x2b046b98, 0xc185b800, 0xf346089c, 0x1ab4be0f, 0x1bdf9d7e, + 0xd4f88e7c, 0x97793478, 0x48edb7f9, 0xdc8f0ad0, 0x8c1e7b74, 0xb295656e, 0x0c017c18, 0x0d2833bf, + 0xe6ae7c01, 0xb0f86c2f, 0xafec013c, 0x08d9032b, 0x9c3b4316, 0xdb4aca2d, 0x755bd452, 0xbad50179, + 0x316ba6cb, 0x14ac0bc3, 0x5750a837, 0x707a3ada, 0xd3cf75ed, 0x1041f79c, 0xcb8b91d4, 0x4ff6a4d6, + 0xda0636be, 0xbd60fa88, 0xac4978e2, 0x501d30dd, 0xec698bda, 0x049e0bbd, 0x88a30668, 0x70d964d2, + 0x74268097, 0x6a9e0cc4, 0xd883796d, 0x4ac41abd, 0xfdfe36c4, 0x90757c4b, 0x5767c8b0, 0x9f6a8de2, + 0x6d6f2099, 0xa652ea0f, 0x81684036, 0x2fa082de, 0x86d50ec0, 0x2c6c934e, 0x3e722fd1, 0x499ff3ad, + 0x2606cbe9, 0xf870425d, 0x678d836e, 0xfec88acb, 0xedf8242d, 0xea5f0d2b, 0x9959b512, 0x9ad50d1e, + 0x664802c7, 0x5bcad404, 0x1885bc6e, 0x28235b51, 0xc246bb04, 0x2dedf5c9, 0xa9851d50, 0xc549bc5d, + 0xc64f6575, 0xa72db0ab, 0x9a9d16bb, 0x7376f18b, 0x1dae7922, 0x0a760f6d, 0x9da036f2, 0x7f4a0ade, + 0x0ec3f473, 0x226e8ab9, 0x70ac9b1d, 0x55bbf72e, 0x96d2769c, 0x5afc53dc, 0xca9b6c85, 0x85218e43, + 0x86ac0955, 0x425afab1, 0xf7644563, 0x207ee2e0, 0x3cd63b41, 0x6b7bf8ee, 0x9713bda6, 0x228551e0, + 0x95b47466, 0x0b3ffd35, 0x03f7f8eb, 0x33be59fb, 0xba70c235, 0x5f183b90, 0xe18f57c9, 0xbc138f21, + 0x4517681f, 0xa404c35e, 0xfbb219b6, 0xe37a367f, 0x18c7105d, 0xc12150ae, 0x61e8cab9, 0x6a97d0db, + 0x47b4c66b, 0x8493af43, 0x4aeda844, 0xb0a6ba95, 0xaa694c5e, 0x44132409, 0xf851a644, 0xf5a0a58f, + 0x10f5ab57, 0x7526ff79, 0x249068fd, 0x8e065bd0, 0x5b7d62b2, 0x0cc1b264, 0x062cfe30, 0xa92074ba, + 0x85677fe7, 0xbde0270f, 0xb062077d, 0xe503d15f, 0x7cf30d67, 0x0d0c316e, 0xe0370030, 0xfce49a51, + 0x193d2a01, 0x60d2ff06, 0x6d2f65c9, 0xd12f3246, 0xbd031c60, 0x519104ff, 0x82617be8, 0x89e04dbc, + 0x60872874, 0x074dd047, 0x7ac69988, 0x55f60e76, 0xfa08ac4f, 0xd758b559, 0x136154cc, 0xe8cf1469, + 0xb7b87445, 0xc50fef6f, 0x4d2b2d56, 0x018cbbd3, 0x07d1fc2b, 0xa679eccb, 0xa576dbd0, 0x73f660f4, + 0x234824bc, 0xa9b44bc5, 0x6dc8485d, 0xa29ac278, 0x8f12325c, 0x1c134008, 0x9aed64a1, 0x62d14cfa, + 0xa05117c3, 0x8e7ce627, 0xa857bb68, 0x96d99548, 0x16692ad5, 0xdbc37d2a, 0xf430c0a5, 0xf51094a6, + 0x43417f64, 0xcedf0abc, 0x64e9cf09, 0xb7869092, 0x76b26c68, 0xdb4721cc, 0x26f0d6d0, 0x6c02ae98, + 0x9328f958, 0xa4121f68, 0x40a5f6e8, 0xa8703512, 0x88ab3574, 0x49dcbf2d, 0x9d915bdc, 0x4025ca76, + 0xb37db0e0, 0x70349b11, 0x41ab811a, 0xec06a63e, 0xd1088455, 0xa310859c, 0x37f2aef7, 0x5c48b1ba, + 0xf0804f1c, 0x9e5e9a56, 0x122ad067, 0x671a1171, 0x66f90002, 0xd38cd795, 0x4d67cc2c, 0x1f5866eb, + 0x6bfff2c9, 0x0dc1a06f, 0x6a4e5012, 0xe662c4d0, 0x098561ce, 0x94920426, 0xfc1ab135, 0x7729039a, + 0xd5db8b41, 0xa93482d1, 0x53002f46, 0x9440bd87, 0x4c2157f2, 0xa6721802, 0x999e4709, 0xfa441dcf, + 0x9ac3f1b4, 0x391ef69e, 0x4e75d817, 0x5bfa0782, 0xd9a0a28d, 0x2c976075, 0x7126ce2d, 0xe5299a50, + 0x74166b41, 0xaf2f7d00, 0x6f135f90, 0x946b93e4, 0x7b732a79, 0x73a25519, 0xd259e539, 0x5ff472e9, + 0x74a38210, 0xda827d7a, 0xe7c3d857, 0xe1bdd6a8, 0x6f35fbe8, 0x717ba184, 0xe47b70ef, 0xd078ef1a, + 0x5068dcde, 0xfc494190, 0x316f86a0, 0xbc09a609, 0xf76f7300, 0x5e67c9ce, 0x74ca74a8, 0xe82d4d8e, + 0x5a01c348, 0x309849ba, 0xdd388bac, 0x161aa57f, 0xf82d4fe0, 0xd30f4c4e, 0x107889cb, 0xfff635fa, + 0x7735bcad, 0x57065ed5, 0xa4cabe80, 0x6841ccbe, 0x3ad6f14f, 0x25139a50, 0xba4a5768, 0x9121869f, + 0x7b107785, 0xeb2e21a2, 0x5351cbd9, 0xa599a5ab, 0x4fe3b737, 0x66e60160, 0xfdf62314, 0xb2e96b01, + 0x5c40d76c, 0xf8dd216e, 0x2960cb8b, 0xe972a384, 0x2ed3b2b1, 0x78e8491e, 0x01d3feda, 0xee024fda, + 0xad0224b4, 0xde944422, 0xdc83525d, 0xade59f11, 0xd8d068a9, 0xf8941bbf, 0xaad5c4a7, 0x3e6bf0a4, + 0x4ead3480, 0x858b7f56, 0xee1508cd, 0x23ac2587, 0xb077328a, 0x6e40a997, 0x3e84c7d5, 0x28456463, + 0x879147ee, 0xf558244a, 0xd9a57f07, 0xd2260a3b, 0xb0e6a813, 0x6860bc6c, 0xad52b8f0, 0xe6383bc2, + 0x4d2c57f1, 0x56dc7988, 0x799a56fb, 0xaf86bcb3, 0xb90c6267, 0xa184ca1b, 0xecbeb8b7, 0x8241f320, + 0xf158c000, 0xe8762d75, 0x0fa8f868, 0x25d8ceae, 0xbc03c977, 0xe5eb9f8b, 0xbd80f641, 0x1e8fa840, + 0x63c2c50d, 0x33672844, 0x11ef6a93, 0x76587d82, 0xae51f557, 0xe5b47ff3, 0x7eddd6f2, 0xffd66f1e, + 0x60dc5de4, 0x141a858b, 0x761a0b48, 0x9d2ff113, 0x895da8be, 0xb0a00299, 0x56d7166c, 0x53f3a329, + 0xc960d18a, 0x66988089, 0xb66e449f, 0x66af456e, 0x28dd3fb0, 0x2981cf98, 0x0a44c0f4, 0x271b692e, + 0x3f2a3a4e, 0x91c293e1, 0xc7521326, 0xaea733ef, 0x50c4ba58, 0xc4657130, 0x8fb7148a, 0x7c24efc7, + 0x4c142e85, 0x5799678a, 0xa985a559, 0x0b120186, 0xf8762e1d, 0x9419bfe9, 0xda3ee6cc, 0x01febffc, + 0xb8fb823a, 0x00e95ae6, 0xb95af0dc, 0x69654918, 0xacaab8bb, 0xfadd4388, 0xd578a5d5, 0x7d1a7985, + 0xbdc0ab90, 0xcd1dd8aa, 0x6351e5a7, 0x256ea3e9, 0xfda46c8a, 0x6ad6d0b6, 0x4df5f96f, 0xa47600ae, + 0x17c9aaeb, 0xa574500e, 0x279164e3, 0x2dc9ddeb, 0xc3b2427d, 0x5bc36ad0, 0x39b9fede, 0x25c42f8a, + 0x4b73e43f, 0xfd85107c, 0xec06a35c, 0xe6c780fc, 0x58755e06, 0x6e3c2731, 0xe3a1b145, 0x18394d4a, + 0x837210d8, 0x6eac39bc, 0xaefee1e2, 0x8add0e56, 0x0039f035, 0x137f0bd8, 0xe9dc40fd, 0x5066a7e5, + 0x9d5e451e, 0x69ca7be6, 0x00fa8e64, 0x46fa6b32, 0x1b837b54, 0xabae78de, 0xe8e05bbc, 0x87e2542e, + 0xc5549e7b, 0x76fd761c, 0x1a998614, 0xf0c84f25, 0x940f6445, 0xff31d6f8, 0x6ffd04a8, 0x638960c0, + 0xc8cfd835, 0xd5943d2a, 0x9a37b1ab, 0xc1e1b2c2, 0xf2012416, 0x7b75ceb2, 0x7a4a7020, 0x1d97c947, + 0xb4556886, 0xf9a62e29, 0xc39c69bd, 0x7b823f18, 0x25ef7731, 0x14d6f400, 0x62a7bae9, 0x58ae4a4c, + 0x40dac60f, 0xa3d8bc4e, 0x47518ea5, 0x336f3587, 0x39972edb, 0x9db31ea6, 0xb4fc5abf, 0x053ce20e, + 0x756f5fcc, 0xf868c3f1, 0x4ef13d00, 0x62f8380c, 0xc541eea9, 0xe97b1d9e, 0x2f3e293f, 0xc33ae1f5, + 0xbe1201ba, 0x947a40d1, 0x1de349cf, 0x7ca510da, 0x463f2327, 0xd54778ee, 0x689ef156, 0x4a598329, + 0x6e9a4507, 0x8d2d101f, 0x304a6891, 0xd7d02827, 0x8734909e, 0x436f8356, 0xc6e6ea95, 0xe9436307, + 0xde653792, 0xedcb4f14, 0x6f5222ad, 0x1cf72425, 0x30ac605e, 0x3d47bb21, 0xe3a3d084, 0xa5d2d6e3, + 0x91798418, 0x68a191cd, 0xe604fb5d, 0x6ce9f87b, 0xb8997417, 0x0115e918, 0x78e7cbe7, 0x88ac5237, + 0x8c35708f, 0xd95b2943, 0x7ffd2a64, 0xecb431a6, 0x12118ada, 0x3a18c2a6, 0x3d53b1ed, 0x724878f7, + 0x26b3b576, 0x8b048f31, 0xf407eb67, 0x17eceaa5, 0x2a91f6b4, 0xf75103b8, 0xa880ee24, 0xbc0f524f, + 0xc53c5068, 0x6d7279dd, 0x94678bea, 0xa54fc9dd, 0x64d17bf5, 0x2b87b279, 0x1e8f63d1, 0x8e184118, + 0xc6669f54, 0x933575a9, 0x0a78de51, 0xf9513a9f, 0xbea185a6, 0x3f83a571, 0x65185839, 0xea806080, + 0x075a0a20, 0x8d993165, 0xc87ab62e, 0x70fe33eb, 0xc53498dd, 0x72f3d4ae, 0xc65e6fdf, 0x625ccc7b, + 0xab021037, 0xbc1c570e, 0x5ca3612a, 0xf8e2baf7, 0x06c83bfa, 0xeb849414, 0xf88db475, 0xff49acd2, + 0xad476b72, 0x88302764, 0x02970f41, 0x2540c875, 0x112ebcda, 0x32757f51, 0xf01c05e0, 0x23d4ed2b, + 0xbe304040, 0x1a5690f7, 0xa4c523c9, 0x3a62ee0d, 0xfc554c9c, 0x77f73754, 0xc93b2de0, 0x72cbf1f2, + 0x8bc1c56b, 0x17fa2f8e, 0x4156a78d, 0x8b5ba102, 0x1a60bcea, 0x291c4b0e, 0x864c6baf, 0x36d89568, + 0xf0a750b9, 0x2f887395, 0x6a87ea37, 0xa1f5275e, 0x85f4b813, 0x900851f4, 0x516c9dee, 0xb6be3fd9, + 0x76a6d26d, 0x9904b2e5, 0x4d15379b, 0xff8e932f, 0x01415ec4, 0x560334a3, 0xdd78e849, 0xceadb8ec, + 0xb229a623, 0x49878528, 0x7a3b0703, 0xe34354cf, 0x8a72ade9, 0x2ca14ef0, 0x93c0e100, 0x81902244, + 0xc5de877b, 0x2b2ce66a, 0x0a787e7a, 0xd072312c, 0x18f083a5, 0x73563a24, 0x6cbaafab, 0x424081f9, + 0xeaf2345f, 0xb6ae1428, 0x26b80339, 0x6aed608f, 0xfbacee43, 0x600d77b4, 0x104591ef, 0xa4b7963a, + 0xf2304f29, 0x48dcb600, 0xcbde9086, 0xdfe0aa7a, 0x647ad6f5, 0x60d29da6, 0x172be30f, 0xbb2b7c81, + 0x1e9a64fd, 0x456ed6ec, 0x92783913, 0x3d0d1ddd, 0x9c85b8df, 0x9da88003, 0x5ca55659, 0x4edca096, + 0x6c9a3e59, 0xea1c65f8, 0x994c4109, 0x239f52ab, 0x2d5a36bb, 0x25407210, 0x223f0a63, 0xa968016a, + 0x501d3026, 0xc5494498, 0xb3bdf306, 0x1f9d8345, 0x1dad7f1e, 0xa6c9fc55, 0xdbaf6118, 0x0d3b6512, + 0xdd3a498c, 0x134b2ce3, 0x031c9bee, 0x13a052f3, 0xfeddc82f, 0x9a2b8b4c, 0x8b104ec5, 0x0168cb5f, + 0xb033f4bc, 0x2b803f76, 0x2d8df076, 0xd81dc89c, 0x2aa800d6, 0x7149e176, 0x75340db1, 0xe9d8f422, + 0x6fac24cf, 0xe295effc, 0xc94e64eb, 0x7e938e62, 0xc6f76310, 0x59520a6e, 0x53243a3c, 0xc0bf2305, + 0xd7848a8b, 0x343393fd, 0x4d86d0ed, 0x8631ff88, 0x5ef88a41, 0xae26d060, 0xfa192e44, 0x3d3a9a1c, + 0x24e10364, 0x0edfa3ca, 0xea25d992, 0x41ff2daf, 0x7174d644, 0x0675559d, 0xf8f9e2c5, 0xed11954e, + 0xa9974c9b, 0xd4cedec8, 0xc82b7801, 0xa99dede4, 0xc0bb88d0, 0xa2d24f09, 0x59c86037, 0xf6d7f1bb, + 0x65661260, 0x319c3de8, 0x3bdf0062, 0xd976ae51, 0x99bf089d, 0xd1fd93b1, 0xb273d780, 0x5ee2604e, + 0x9d8c92ce, 0x6ea28747, 0x0ea013ad, 0xc00045df, 0xf28d5a42, 0xdc04197a, 0x263c842e, 0xac99e33a, + 0xb3347304, 0x37505052, 0x32584de1, 0x8eabbaa4, 0xf3790f43, 0xfe8d259d, 0xe4ada227, 0x8f76cd52, + 0xde372b83, 0x449cf804, 0x1526f27e, 0x0eb133d2, 0x13146692, 0x3c55c98e, 0x0b12bbe8, 0x0c20263d, + 0xd892073c, 0x31d62859, 0xb9aa36d1, 0x6501a20a, 0x015e2246, 0x1292276e, 0x1b88a4e5, 0xfd5ee00d, + 0xfb7edcd2, 0x967930e7, 0xb3fab382, 0xa521a841, 0x974fdcc6, 0xc5f3d40f, 0x9bf0505a, 0xe6c032e6, + 0x102131f7, 0xbce590d2, 0x80aa29a4, 0x2975451c, 0xe0978ec4, 0x02a926c9, 0x26712fc5, 0x0b1143e0, + 0x94a1885e, 0x29b27c5b, 0xe5fc4de4, 0xa780b666, 0x5b3e971a, 0x43115384, 0x7ba259e5, 0x858bc74e, + 0xdf4c5b89, 0x8e106335, 0x3077ebcf, 0x21690454, 0x93a66eb7, 0x9c2b84e7, 0x11bd1286, 0xb5d7fee8, + 0x1901d27e, 0x26fa197d, 0x2714e386, 0x633e3fa9, 0x2e7c4ff5, 0xd6021a22, 0x63e6f39d, 0x10923c98, + 0xac6909cc, 0xdf9aaf0a, 0x702632a2, 0x9e64db4f, 0x5e69b716, 0x088699ff, 0xaf272927, 0xd7b509ca, + 0x964406da, 0x762a30c5, 0x8a77d5fb, 0x6b46c969, 0xed353bc7, 0xc2dbbd90, 0xb3785ab5, 0xc075b9a2, + 0x63dde0d8, 0x29e92590, 0x7182137d, 0xcdd12d0f, 0x086425f0, 0x5e4c33f1, 0x6c01298b, 0xc8a963d5, + 0x1563eeef, 0x325b8a1d, 0x8154c8d8, 0xc8251ae0, 0x2280b281, 0xd70b0c6e, 0xc51a85d0, 0x80e177ea, + 0xf2e3802d, 0x53560193, 0x8093cfe2, 0x5165cb9e, 0x0ec59357, 0xd166cd65, 0x15576af3, 0x0841fb06, + 0x30c3e0e9, 0xf51a8af0, 0x8c6c366d, 0xc4babdb9, 0xff77f2de, 0xf68a3160, 0x7e5fcb08, 0xe08c473e, + 0xbfa6dc05, 0xf0dfb226, 0x04160c10, 0x3e59ddc7, 0x30ba881d, 0x72fc5cc6, 0xf7ea8950, 0xb9f4beb8, + 0x85533828, 0x2bbd4775, 0x36044d78, 0xa67fa564, 0x86ecbaee, 0x81954d93, 0xeb81903d, 0xb8f70235, + 0x1c92a433, 0x54ad34ea, 0x4dc493cb, 0xc6e81551, 0x97945bf7, 0xe22e3b46, 0x6bdf55df, 0x0c2d85b3, + 0x9f25de37, 0xc1b6a4e5, 0x4597a8d5, 0x64e646bf, 0x53dd4451, 0xaf53cae3, 0xb770b362, 0x7d38a41d, + 0x822b941d, 0xb4f9c6b7, 0xc9851fa8, 0x98acd4cf, 0x1410904b, 0x33a1919b, 0xe310b983, 0x79e5f6fa, + 0x9beecd16, 0x72a41135, 0x78010d75, 0x2769d012, 0x49b96425, 0x5bcbec3c, 0x24b83639, 0x23f3eb6b, + 0x7d300d6d, 0x5582b528, 0x86191a51, 0xd05271f0, 0x6db08954, 0x8d43828d, 0xad78c937, 0x3eccf498, + 0xd734987c, 0x39541fef, 0x9ae2dbf0, 0xdf55b167, 0x2639e386, 0x8d001317, 0x1c5f3274, 0xe4919dc9, + 0x78317298, 0x50b67a28, 0x2c837f04, 0xa79794ee, 0xfa7246af, 0x6acf3d6b, 0x1463e0fb, 0xf58f0091, + 0x3cab04cd, 0xf573e3cb, 0x1e432b45, 0x92def9f0, 0xbcec1a03, 0x5018dd75, 0xcd414968, 0x0882dd34, + 0x89f1bed6, 0xe21adf04, 0x97fd0051, 0xde349cae, 0x45da6039, 0x71649047, 0xe58d4950, 0xfaf36b13, + 0x917d4cfa, 0x83b79c30, 0x0f9cffec, 0x98ed9b09, 0x6dc2e108, 0xfecd6ed3, 0xb96703f2, 0x89025f4e, + 0x64198b70, 0x12669d4e, 0x9f4e60b2, 0x03aa7956, 0x6e7efb4a, 0xd8ac3e36, 0xb6d83abb, 0x6447f3dd, + 0x72253b94, 0x33002ec5, 0xa31beb68, 0xd169a683, 0xe30054a3, 0x52639223, 0x303f5c68, 0x4abdc74c, + 0x40673ba3, 0x296a0473, 0x9a7e846d, 0xf11e7a19, 0x27a472e8, 0x96e6b594, 0xc2c0a024, 0x503b82ab, + 0x78932f85, 0x0ce55db0, 0xb4ac0289, 0xc5d475e9, 0x3a6e97c8, 0x3c169f5c, 0x8310c776, 0x78d68c3d, + 0x2f4bce56, 0xbd72764f, 0x0b525e62, 0xe1d3d176, 0x6ee930b0, 0x198bae19, 0x70e0c4c3, 0x4cdbc398, + 0x943403ca, 0x5c145179, 0x5b880a2e, 0xafa5518c, 0xc8f43918, 0xeea31885, 0x43fc51ce, 0xa4d990c0, + 0xdad33628, 0x85734dd7, 0x51514806, 0xb3514570, 0xc5bcb6aa, 0xabeeab4a, 0x70c8d14d, 0x4083728e, + 0x666e4842, 0xdf96f80b, 0x1b37aadc, 0x288fdae3, 0xcd2ed67e, 0x437ab34f, 0xae291728, 0xe12c77c4, + 0x13a408fb, 0x40fd1eae, 0xa773d67b, 0x5ec34bca, 0x58da53a0, 0x4a88e39d, 0xf16f6c16, 0x246ad693, + 0xfc974b25, 0xfe76b00c, 0x09daf1a0, 0xcc1c7bc3, 0xd4a7aa09, 0x7c860ff4, 0xfb5791ee, 0xb1d3e882, + 0x4ce5b6c0, 0x62a3ef67, 0x9b0ce420, 0x8ea2d4f7, 0xcf035b2b, 0x85503691, 0xe1159e28, 0x5679bf53, + 0x19b6bb6d, 0x8ae7ae93, 0x438457c4, 0x24be62de, 0x8b45a163, 0xfd3b4030, 0x73ee306f, 0xbef37c55, + 0x0e77e2cc, 0x1ce20ca9, 0x1ca4e8bd, 0x4588789e, 0x40452dbc, 0xa2a474bb, 0xfb8ec142, 0xfd89013e, + 0x13d40ca0, 0x5902c386, 0x250b5966, 0x7ff7d310, 0xd3854269, 0xaec11b2b, 0x3618af6b, 0x6903feaf, + 0x03209698, 0x892e20f0, 0xae8d4c79, 0x3613b9ba, 0x2e0e43a7, 0x74668ed8, 0x546f6501, 0x1846b11f, + 0x7b87dcf8, 0xee34c49f, 0x5cbc3b30, 0xcba0c0d8, 0x49694656, 0xc935797f, 0x5780c42a, 0x3eb3d908, + 0xdfb44aa1, 0xf6ac0f25, 0xda22e8cf, 0xc7535fff, 0xd3409568, 0x0edf8899, 0x4728dc5f, 0xee6ca450, + 0x54e425f8, 0xf4ffc8b0, 0x08ba3160, 0xfb1d2307, 0x9ed5aea7, 0xcd485105, 0x83818de0, 0x1d47e6c6, + 0x8a38d729, 0xbb2c507c, 0x8a12de0a, 0x838bbd5f, 0x7ce8854a, 0xa8f0600b, 0x252d1b70, 0x12b92765, + 0xbae269b8, 0xbc8bc50e, 0xf45e9d60, 0xb5b1f96f, 0x964339a2, 0xe682d5ce, 0x8b3679e6, 0xbe86f5e8, + 0x04350159, 0x2b4a7831, 0x2838272d, 0x7fd04fdf, 0x25f52f63, 0xf9b6ee7c, 0xd25fb91c, 0x2743c579, + 0xe9555299, 0xa52e2307, 0xcc09632d, 0x7a3901b1, 0x897192b1, 0xf4372654, 0xf52e0e98, 0x7a463296, + 0x1eac6b67, 0x72af94bd, 0x478edd48, 0xca6c4d4d, 0x02377d35, 0x9edb40c1, 0x88b1e585, 0x2abcc9f7, + 0x8a7540c2, 0x41674c5e, 0xc77fff22, 0xfc00c2d1, 0xcdeb2fe1, 0x616750aa, 0xf6088fc1, 0x1b7762a4, + 0x45182f8b, 0x41834f58, 0x5c73156c, 0xfab66ac7, 0x51da0868, 0xbdb33ca4, 0x3a1e6384, 0x0fc6c0a0, + 0x0b13c8b8, 0x36e174af, 0xd3655e9d, 0x0aeb6e15, 0xc5df2e6f, 0x568cabc3, 0x3c47d61c, 0x14b6da01, + 0xed3d7a53, 0x3e6ffcd2, 0x7409eb33, 0xd037ec4b, 0x92edc06f, 0xb7e754b6, 0xc5049028, 0x8aa27b8c, + 0x424bf931, 0x1c77bc59, 0xbcf378c4, 0xec9fcf50, 0x20b45d69, 0x9a9659f8, 0x02d56f9f, 0x83f39982, + 0xb38e4327, 0xc770d406, 0x4b8ae95c, 0x09b9dbe4, 0x4f6b90b0, 0x980f8992, 0x4b9db91d, 0x4eac2f84, + 0x40701300, 0xd93045da, 0x2e0f1d19, 0xe5a8f3f6, 0x64d5d77c, 0x5e1f8a55, 0xe2cf7124, 0xa2da1fd2, + 0xf7427e35, 0x64d53b4b, 0xd9dea584, 0xbabf29ac, 0x38280112, 0x6abdd308, 0xb3bfe532, 0x443afc16, + 0x392549ce, 0x12889056, 0xfdb813a8, 0xa9d2640a, 0x814b3f9b, 0x3f13b437, 0xc8d6f118, 0xb0442dd7, + 0x0e05159f, 0x05bdb172, 0xb9c0b8ee, 0x81f14fa0, 0xb00f6c6f, 0x3f070df0, 0x36c2463e, 0xdbf9c583, + 0xfb30ff46, 0xaabc83dd, 0xff6de6dc, 0x6e1c52e7, 0x2ab8ec75, 0x8d9b9026, 0xc7672723, 0xaabc363e, + 0x1012d391, 0xa98b3930, 0x6eeaec39, 0xbc51059d, 0x4b5ded95, 0x25b8a234, 0x55b1f743, 0xbd4936f7, + 0x9b00cf17, 0x7551a68d, 0x9c26777c, 0x567ccc94, 0xd26feeb6, 0x7988cd35, 0x90532aa2, 0x5995133c, + 0x88d30c68, 0x041126d9, 0x2a0e8c91, 0x40295b9d, 0xfc9fd493, 0xaa1a4cc2, 0xd39b373c, 0xe26d3032, + 0xc73bbc15, 0xbd6fbbed, 0xe7358e3c, 0x1d7d1964, 0x70b1dddf, 0x1d8523f7, 0x17ff282b, 0xe2f6b269, + 0x5125454a, 0x153f82c9, 0x143f55b4, 0x2ed04b77, 0xfdeb41b8, 0xeb6ed912, 0x45448a1d, 0x616af3c1, + 0xf055a860, 0x994b628e, 0x560c5ac2, 0x77717e1b, 0x2c7d9fc3, 0x6bbedd12, 0x985f0934, 0xa1d6d04b, + 0x3da01f6a, 0x5dacfe2c, 0x9b8a52c1, 0x94487a03, 0x849b9792, 0x97854c51, 0x17b37346, 0xc25e27de, + 0x9aa6e0b8, 0xc297fbff, 0xf9001f35, 0xd6a72076, 0xde8c26bf, 0xe69eb77c, 0xcd8a31f5, 0x652b2489, + 0xbcdc3c7d, 0x470084d9, 0x108a45e3, 0x11580858, 0x3c113e38, 0xf1d4f97a, 0x9faf0162, 0xa7b066c9, + 0xa04aabaa, 0xfe82cca3, 0xa969b50e, 0x015e92e2, 0x54fd462e, 0xc0078815, 0x70cbd962, 0x160adcf8, + 0x1890c6c6, 0x2b1ed1d6, 0xbec68220, 0x49ef868d, 0x27d717a7, 0x04e4b54e, 0xb180a77a, 0x3d9cce33, + 0x61fd6b8b, 0xf8b908c9, 0x057b633d, 0x887fceec, 0xc6c7e657, 0xe361b53d, 0xad5000f6, 0x6fbfa669, + 0x7bcace71, 0x3323aebc, 0x45e764c3, 0x3de935eb, 0xfd027100, 0x7e2eff0f, 0xbb6fd9d4, 0xd460f00c, + 0xfd9acd9a, 0xd69d0f6b, 0x8323ad26, 0x4d7274c1, 0x51245b7d, 0xf364bfa0, 0x23ea0fee, 0x2fd26ae3, + 0x5357fcbd, 0xad2ba144, 0xeb847230, 0xcd96422f, 0x175c291f, 0x61c3a1bb, 0xde820c04, 0x1256595c, + 0x4dc412f2, 0x116bd7c5, 0x3eb22366, 0xe070138b, 0x2ab8b800, 0xc6a95885, 0x846f7e29, 0x37eebcd8, + 0x9e883fe7, 0xfbe67952, 0xe698033d, 0x195f9507, 0xf695c2aa, 0x749f8d25, 0xebf65998, 0x98a93dfe, + 0x7500819d, 0x00b75bc5, 0xcc56506d, 0x253793d3, 0x233a4dbb, 0x9cfd9a33, 0x26c6bc90, 0x3b8cf9f5, + 0x152cb8a8, 0x6101ad92, 0xd0420b22, 0x6881b35b, 0xc7931bbb, 0x04b41fc9, 0x13a9e00b, 0x31bb23be, + 0xef27a022, 0x6d4bfc56, 0x853063a2, 0x0ae1c27d, 0x3a32a624, 0x0f26e30d, 0x2541dc65, 0xd7a21c00, + 0xc0a2b3b4, 0x4f8eac51, 0x30f55147, 0x700e86ff, 0xebd8dbe6, 0x0eb36ca4, 0xf660a8fa, 0x235935f7, + 0xa38090af, 0xa188c087, 0x6fe7199b, 0xa1be490b, 0x59585b55, 0x732fb4aa, 0xda664685, 0x1b4eb437, + 0x1b644687, 0x69b9b524, 0xf147d846, 0xabcf3b9c, 0x440c7957, 0x8a43b74f, 0x9557cae9, 0x9ca33706, + 0xe3796aef, 0x3dcf3a29, 0x7d2cdb5f, 0xf85bc194, 0x189905f8, 0xf31e826d, 0x8ade5ebe, 0x15e2eae9, + 0xfd334405, 0x9201bbe5, 0x46302542, 0x0e3ab552, 0x1326be3c, 0xa82f6036, 0xf0d3e9f9, 0xa0f73643, + 0x5a9923b8, 0xc9581fa7, 0x3033e4b3, 0x7770beed, 0x12cf899c, 0xfb1b8b6d, 0xb5997658, 0x98f7ce5b, + 0x03ca10b0, 0xe9de0b8c, 0x85c1c07b, 0x3b1ffbc3, 0xf9c74aea, 0xde43ed1f, 0xe9c7f56f, 0x3b39a676, + 0x9573a133, 0x6b75f601, 0xeb8b5711, 0xad3c18b3, 0xab9b26cd, 0x56c22f4a, 0x692fd52f, 0x9b7156e6, + 0xa644567c, 0xbec0c42b, 0xb0e8c64d, 0x2da72feb, 0x3a5c760c, 0x8418c714, 0xa2ed6bae, 0xd7b5cf6a, + 0x3666a3e1, 0xa41c1ab7, 0x7dc4b9f0, 0xcc6804d8, 0xf30acd6c, 0x3d3df9a1, 0xd11f4d63, 0xe8da901d, + 0x3dcaff67, 0x59f1acff, 0x8f24ea76, 0xe232a980, 0xe95fd479, 0x422ad0b3, 0x07a124ad, 0xfdbb02a7, + 0x944fbe79, 0xe1529c3d, 0x34e8e54d, 0x0044469b, 0x4e51742e, 0x47d1de34, 0x0524ece1, 0x61443d45, + 0x4e113c49, 0x20af3c24, 0x294e7d89, 0x2f39122b, 0x8726b9ec, 0x50b1fb9f, 0xd8d6a226, 0xc559c2bc, + 0xe1d2ab66, 0x35947917, 0x3993dc64, 0x20bea259, 0x95ac2558, 0xf0a45c55, 0xa0e33e7d, 0xe7cbbb9d, + 0x031711a6, 0x758a15f0, 0x061a637b, 0x07c6ca70, 0xc0cfc21e, 0x27b16891, 0x915ebceb, 0x0586e4ed, + 0xfcbb3adc, 0xd2c51cb0, 0x83ec1134, 0x1b5c179b, 0x5a5a636e, 0xe27cd4bf, 0x2c9ebaba, 0xb35d48f7, + 0x21e847b7, 0x2372e838, 0x7b60353d, 0x5aeb334e, 0x49962a0d, 0xe1f98c80, 0x4a225c41, 0x913bdf1e, + 0xa34fda11, 0xd0b30904, 0xe62e0c37, 0x66670fd4, 0xe9d445dc, 0x94cf873b, 0x925f54d0, 0x1113a876, + 0xd5e26c28, 0xc692cd7c, 0xd787c348, 0xd3b3474e, 0x22c428e9, 0xf3639f62, 0x7f6b2e8f, 0xc725a349, + 0xca7d7dca, 0xc6e655a5, 0x2dace1e9, 0xba375485, 0xdb1854d2, 0xbb80b027, 0x6985a81b, 0xe1f82c80, + 0x5b7d0460, 0x55691625, 0xe9efa6d7, 0x5c57b3f6, 0x5c5fa37c, 0x0af72156, 0x0a53806a, 0xff08cc4e, + 0xa9b4349e, 0x3f027f11, 0xf44a50b2, 0xa6bd45aa, 0xb01b19d8, 0xee150e5f, 0x132f507c, 0x32c1949c, + 0xcd3b22ef, 0x3ed8526a, 0xd71c92b5, 0x005557fd, 0x55d0d651, 0x8dc12924, 0xf22435d8, 0x593023ac, + 0x4b6a1e84, 0x2801597c, 0xb485261d, 0x835203a0, 0xda1eede9, 0xfe60d582, 0xfcc4cc4f, 0x375487a2, + 0xd2594f24, 0x7f71bcf5, 0x69be7ad8, 0xfcc9244a, 0xe123487e, 0x5d609dd5, 0xec455d36, 0xf192b3e1, + 0xc4876a66, 0xf58fbd48, 0xa80cf9bb, 0xcd8f9746, 0xcbab0587, 0xf24a1db1, 0xe0c2c915, 0xc9984cd1, + 0x29dd3e48, 0x720a527c, 0x9b1728d5, 0x399e5e23, 0x44cca6e9, 0x06909643, 0xc114ceef, 0xf9d45d7a, + 0x25c02e99, 0xa9912575, 0xc827aa73, 0xdabcab73, 0xcb7a6cae, 0xaa226506, 0x69006a54, 0xaff48ba8, + 0x2886409e, 0x2bfda27b, 0x3ee037a6, 0x6d5f6bbc, 0x01766074, 0xa466ec0b, 0xe1e5bdfc, 0xa5aec025, + 0xa462e2f2, 0xd25f74f5, 0xda3ba573, 0x17bd408f, 0xa3f90232, 0x943f5229, 0xc2011034, 0x26820282, + 0x82252753, 0x5aec2652, 0xb8d936dc, 0x521c1f6d, 0x93e120da, 0x472b5b39, 0x56739e5c, 0xa0df979f, + 0xbb5c8caa, 0x017d5e0b, 0x994cc574, 0x7dedd4a1, 0x17b1dc3d, 0x3a2efb82, 0xfb5887e2, 0x84050a67, + 0x365965d6, 0x8da33f8c, 0xb2aeb887, 0xf2d11f63, 0x223884b9, 0x939c56fc, 0x5c534057, 0x15f3eae6, + 0xf37ef961, 0xfdcbea28, 0x16a753ac, 0xc87e75ef, 0x4569e8b0, 0x39855b53, 0xe7b8eb46, 0xe54cd1c0, + 0xbab762d2, 0xa3a9b0f6, 0xd67a5ca6, 0x3064bfbe, 0xc5681fce, 0xdf2d2bf7, 0x585fafa5, 0xc8c911d9, + 0x074e6428, 0x520b503d, 0xad9482e0, 0xed92a492, 0x642f3088, 0x0933583b, 0x757374e0, 0x904ef293, + 0x3dddbc09, 0x47e70a65, 0x0620dca9, 0x3dc4836b, 0xa0f0476f, 0x49ea4d98, 0x59400efd, 0xf2b9611c, + 0xf7fd0347, 0xa264741f, 0x876bb0c5, 0x58a6a876, 0x6e674e6b, 0xdc38e552, 0x7f36c99c, 0xfefa823b, + 0x8cf2bed1, 0x4295ea65, 0xbdaf6b9d, 0x3629db85, 0x6d8eeb00, 0x17a0a4de, 0x612eeb59, 0xe5e7f3db, + 0xe0cd42f3, 0x2350fe33, 0xa5fefd19, 0x0f1c31a8, 0x2138ed6e, 0x17bd6e4f, 0x4c3732f4, 0x6731e959, + 0x4232d685, 0xfd77a588, 0xd313b271, 0xb4e47d59, 0xef5ee342, 0x55c46550, 0x4b9fa67e, 0x2b909dc8, + 0x810a87e3, 0x0a520707, 0x1a0e978d, 0xfcee8f18, 0xe462c3c9, 0x36981f54, 0x615c89b9, 0x5308bba3, + 0x4ed03248, 0xcac39a11, 0x92d78805, 0x857df757, 0xca72604e, 0x940575bf, 0xdecadc41, 0xc19ccece, + 0x9a16f072, 0x9f426f96, 0xb290a2cc, 0x7bfb58f6, 0x53c747f8, 0x9007a98a, 0xf33e0009, 0xbff29d53, + 0x7136083e, 0x28e9858f, 0x815b913c, 0x1ac8bd15, 0xcb4a12d4, 0xdd0099ef, 0xa922f31c, 0x56d7b2e2, + 0x391dfaf4, 0xdbb34108, 0x67335f86, 0xdd8c457b, 0x9a8e579d, 0x4b481d29, 0x3f084b3c, 0x2c255459, + 0xdb92c135, 0x6018df32, 0xa7d1d77e, 0xde7cea4f, 0xb55aebe4, 0xebdf241f, 0x55ff3169, 0x0e0fbbc0, + 0x2e222ecd, 0x7af2eaec, 0xc2d31c7b, 0x64111d39, 0x00396d99, 0x8e0145e2, 0x1312d5cc, 0x86e15aaf, + 0x85b6b826, 0x87f4eca8, 0x68c5aa77, 0x363e74f1, 0x1a4caa44, 0xd41146f1, 0xd940b325, 0x4e9eb514, + 0x2384c313, 0xd4f98c3e, 0x76e6eb4d, 0x882caa29, 0xb3ec8d81, 0x97800a48, 0x1d812404, 0x8cd8c0c6, + 0xb416010f, 0x87da34ff, 0xfc1df441, 0xf6e962b5, 0x9bba2179, 0x11cfdbc8, 0x4d05793e, 0xe8590e11, + 0xb4e3822b, 0x4a0cd274, 0xa5e97946, 0x73bb08ec, 0xa352d77f, 0xf82df2c9, 0xbe30f725, 0x821cea7f, + 0x3542907b, 0x7e46dacc, 0x2840b136, 0xa4337e91, 0x29f69db0, 0x49b6b8ff, 0x760668d2, 0xdc97dfb4, + 0x92831756, 0x816f149a, 0x6c3b3f8e, 0xc2c50eeb, 0xbecc627a, 0x2eed1ef1, 0xcbc86c60, 0xa5b0c5ef, + 0x84a86610, 0x361d0242, 0x923e7ca5, 0x9809c5ed, 0x63c3d59b, 0x20bdb1c1, 0x807c93a2, 0xfed0d749, + 0xd24eacf0, 0xce784617, 0x0fbeae7a, 0x2ff95da4, 0xc41714de, 0xc4ddf702, 0x946f90a1, 0x75803bee, + 0xdfe3291d, 0x29dca811, 0xb81deaaf, 0xd9174f06, 0xfc489f04, 0xd29ca211, 0xff86dc9c, 0xe5d6852c, + 0x7ebb4204, 0xff413120, 0x792cb52c, 0xe20fe991, 0xda421002, 0x4f3fd662, 0x82583eae, 0x4172a5ab, + 0x6e0afbb3, 0xedcb27b3, 0x46987ad8, 0x97a3deb8, 0x90551a1f, 0xc652bd8c, 0x85050f58, 0x8147d32f, + 0x28d675ed, 0x76cb3205, 0x2c891f05, 0xd98d53aa, 0xf21973c7, 0x1bd80f18, 0x23ddabe4, 0x0a0599e6, + 0x2a498e9e, 0xff3ddbc5, 0x3e0b1840, 0xa8624f9a, 0xd723b00d, 0x18fb3843, 0x62dd7f8a, 0xa9a82a73, + 0x97dc58cc, 0x77f10c1d, 0x893d7620, 0x36f2f86d, 0x78323f49, 0xf79d329f, 0x6bebb722, 0x4c2ca682, + 0x7c1454c1, 0xad5f3c34, 0x6f7b9d9c, 0x8a91108f, 0x1a377494, 0xd9be25de, 0x8d2d3b31, 0xd1ec70f9, + 0x756ba1ad, 0xa4972e3d, 0xb44a137a, 0xff8adb2a, 0x663902a9, 0x829c930f, 0x1a321a47, 0xb394722d, + 0xae4c14cc, 0x2454c4d6, 0x548c2fe0, 0x8d92b5c6, 0x84c5b0a8, 0x15185127, 0x772c5b7d, 0x031a804f, + 0x53579e20, 0x37f1dc3d, 0x9b3629d4, 0x9f5d5abc, 0x21cc2024, 0xe7896ab6, 0xc670b0a4, 0x68fc66e8, + 0xba9e6270, 0xbd0cf0d4, 0x8d26f726, 0x163c3506, 0x37d5b17c, 0x7f9f811f, 0xb5f140f8, 0x42a34a48, + 0x9cb4ded1, 0xc02cd1e9, 0xdb6d757a, 0x7202d75d, 0x60cb3440, 0x78f52467, 0xe2f32506, 0x2dc8009b, + 0xfc881c63, 0xb7c9cc22, 0xd81ef967, 0xcc09cf50, 0x240c8e38, 0xf01d7a9b, 0xd7fc410f, 0x43252279, + 0x84bef78f, 0x7e857079, 0xf5df5f9d, 0x5d7a2095, 0x14dfb678, 0x4a07f1b4, 0x69e56675, 0x655785e5, + 0x37e2c3c2, 0xa6e56ed6, 0x27e0b909, 0x1735c5f9, 0x21b9a1b5, 0x8b02feab, 0x1150f65f, 0xbaf634b2, + 0x561e13f6, 0x6e1ec5cb, 0x2113bcac, 0x7136a95e, 0x1279d8a9, 0xa7871f01, 0x4a79fdc6, 0x2cb01968, + 0x44458d6c, 0x520b6b5a, 0xeeea82af, 0x546b57e1, 0xa42874be, 0xe2816c44, 0xe8c23b81, 0x596948f3, + 0x2dc8703f, 0xefae8d47, 0x616c4965, 0x7cbc0774, 0xcf7cf715, 0x92ac42ba, 0x3545ebb9, 0x5b59f8e8, + 0x21fa02b1, 0xa739d502, 0xd8c1d815, 0xec13f725, 0x0c245df3, 0x4108b8bf, 0x63b0c20c, 0x88fcf386, + 0x38b53365, 0x15e3ee76, 0xfee04fce, 0xed3ce09f, 0x7dd4cf30, 0xeede17e9, 0x325c458c, 0xc81bcb26, + 0x4dea39ff, 0x44437aaa, 0x42c73f32, 0xe81c8c85, 0x4acfdc91, 0x919d5f72, 0xebfc2dfc, 0x981de2ba, + 0xab7ed45d, 0xfdbf06ae, 0x749fa0a6, 0x3a3d729b, 0xb609d64a, 0x2ac0193f, 0x5cb87071, 0xc3d0a113, + 0xf722abda, 0x6073b60a, 0x6988922f, 0x10a2675b, 0xf9d2dbf7, 0x7857e531, 0xf4df8619, 0xef2672ff, + 0xbfcd6361, 0x7c49e687, 0xc27bec25, 0x252414f7, 0xc14fdbce, 0xe6ba7ef4, 0xd66d2a43, 0x96e3380d, + 0xe3465ee4, 0x9255b1e8, 0x2f6f315d, 0x5217cf96, 0xfb8e2e08, 0x8153659b, 0x3eb07330, 0x417c5344, + 0x78a52e37, 0xde947149, 0xee1f908e, 0x263c16d3, 0x553223df, 0xeb48457f, 0xa255d19d, 0xa67bfc2d, + 0xbb73e271, 0xdfb2a043, 0x85a999b8, 0xcb72fadd, 0x788af155, 0x308ce14b, 0xf00d04f8, 0x3eed67d1, + 0x7848a99b, 0x56f2fee3, 0x69b16985, 0xe904794e, 0x3e09ecc0, 0xf20e85ea, 0x93a23d2f, 0x66ab2253, + 0x03482d73, 0xc0f02837, 0x5e0fdc4d, 0x45b495c5, 0x91cadb1d, 0x739640c6, 0x655b765b, 0x5f30c3a5, + 0x8479c23e, 0x53fdf76c, 0xd188efc9, 0x8e3004af, 0xc9070555, 0x1820aafb, 0x7aef08eb, 0xab370604, + 0xa07ac908, 0x0f924da2, 0xfea1d411, 0x4c33f315, 0xccca4dba, 0x8f2f3296, 0xe333734d, 0xb209f236, + 0xb47c3af6, 0x1178eec0, 0x487f0e56, 0xe1df3b31, 0x649f6be0, 0xee62043c, 0x8efadbef, 0xe4369552, + 0x59ee5e06, 0x5d7ee8c8, 0x8e171cfe, 0x5e78f81e, 0xa0fc95ce, 0x04223f91, 0x2dbf02cb, 0x8000a00d, + 0xc80b72df, 0x8e4e04f2, 0x0fe755e1, 0x7ca12d51, 0x205c77cb, 0x497376d0, 0xb30c824e, 0x2df9cabc, + 0xc54cbeb3, 0x8581e2c0, 0x04116c6f, 0xb27691e2, 0x30612d71, 0x10da5154, 0xaeefa9ad, 0x5f840ba9, + 0x0358acb8, 0x9900a21f, 0x251783c4, 0x39a79118, 0xdbfd2aa1, 0x7b5926c4, 0xdc2c66d9, 0x06a2bb29, + 0x8779416f, 0x96d4bf9e, 0x77958f11, 0x0e591fbb, 0x32061282, 0xb9d6ffdc, 0x8e822217, 0xcf4533c5, + 0x9ddbe243, 0xf3028562, 0xd2a59724, 0x99d8fc8c, 0x3b4a5c5c, 0xe5e73db2, 0x6760dd41, 0xc8894674, + 0x66517064, 0xd20a4306, 0xf8b7a2b3, 0xfa8e44b8, 0x11f24481, 0x4f326845, 0xf0231dff, 0x32f14b17, + 0xee38621f, 0x8c25d70e, 0xaf42bc37, 0x3b243721, 0x6f0478c0, 0xf4f8b07a, 0x406d9d51, 0x0e3c274e, + 0x70fbdca7, 0x6aeed56b, 0x3ed9bffb, 0x8630b49e, 0x6d25f5f9, 0xa6a59311, 0xfeaa3073, 0xe39526aa, + 0x12be48a8, 0x4f763a66, 0x5972fdf6, 0x04e25f10, 0xa9f2f411, 0x5e1a7322, 0x7d44eec6, 0x526f4744, + 0x36febfa0, 0x0a99bc9e, 0x11579eaa, 0xfe3e5c1c, 0x48698e18, 0xb90484bd, 0xeb922cfc, 0xbd1655ec, + 0x7e70a7b9, 0x715bf154, 0x0a069d92, 0x08ec24bf, 0xb9f5d1e8, 0x0e79288b, 0x27f492fa, 0xf397e5aa, + 0x8a0fa97a, 0xff64fb36, 0x005f0a24, 0x02e23c0e, 0x6f10267e, 0x953f2606, 0x28f826fd, 0x4318bfd2, + 0x7eda6bd5, 0x9810611c, 0xf75ed0e3, 0x963e6b6a, 0x28b8e4d5, 0x7d3ac600, 0xb4241985, 0xbe9fe148, + 0x72411827, 0x8f48788d, 0x150f70a0, 0x18a7398a, 0x55e56cc1, 0xa38d5f33, 0x0e3224a8, 0xf84a1dc7, + 0x28c5153a, 0xb9c3b169, 0x271c6184, 0xdfa5f0d4, 0x428ee1ff, 0x0d64d213, 0xf009943b, 0x8700d261, + 0x89c4b1f7, 0x507f4757, 0x0c7c9690, 0xc56b2297, 0x8f9cfb83, 0x48c12719, 0x1bf19e0f, 0x510644bb, + 0x0bbdf2a6, 0x5f82b21e, 0xbc7f4b65, 0x6ea7e523, 0x25867a7b, 0xda74f72f, 0x27bd7486, 0x3731bca3, + 0x55d91ad1, 0x115a8233, 0x2f7498d4, 0x577babbc, 0x82b27d2b, 0x6f9cafec, 0x1537412e, 0xeecbaed7, + 0x04fa5237, 0x28ee3dd8, 0x3acbf818, 0x2825c3ba, 0x28aa6b3e, 0xa668dbbe, 0x8771eb52, 0xe8a5646e, + 0xf2c7e5b9, 0x12ee9cce, 0xc3dbf560, 0x31abf132, 0xe256e67c, 0x39fa5df8, 0x3e5e524c, 0xed8201f9, + 0xc5504e39, 0x6fd57558, 0xb6b23973, 0x324d0f1a, 0x6e067fcb, 0x550af213, 0x73516335, 0x46645267, + 0xac050fa1, 0x985cfc6f, 0x56b28b7e, 0xf999903a, 0x82f8bd06, 0xcd39155b, 0xc5c9a2f3, 0x1173298c, + 0x89314830, 0x4e5d37cf, 0xaa4d2ef1, 0x06cd5c47, 0xf1d68f14, 0x67815f6e, 0x66021129, 0x0d021332, + 0x7214afa4, 0xc6045f41, 0xd209f5e5, 0x6bd741b3, 0xc5a007aa, 0x515b4cd8, 0x6f94b542, 0x56043b46, + 0x1af07dd7, 0x9b4644bc, 0xf3644549, 0xe803e367, 0x47bf9b78, 0x6ca2ae4a, 0xc5147a5c, 0xf5173536, + 0x2e4c7831, 0x0fa44527, 0x9973509b, 0x958ee744, 0x4930c27f, 0xebcbb2f4, 0x5983ca5f, 0x2c881bbc, + 0xb7a6ea65, 0x3453cb13, 0x77980bbe, 0x26c39e8c, 0x96070554, 0x60014b6d, 0x173e8306, 0xa527ff88, + 0xace28735, 0x8c2ae622, 0x4a967212, 0x1302db8b, 0x0683d1d8, 0x70f198da, 0x66723cf8, 0x57fe8fe8, + 0x7ea3003f, 0xac9cf5ca, 0xb940394f, 0x17c39229, 0xad33f447, 0xf0a71c88, 0x1489b1c9, 0xf1f9bfb6, + 0x31bc1ff3, 0x4b4f6f22, 0x194b993a, 0x330926c3, 0x5e3c8be0, 0x703ec497, 0xa927a9bb, 0x87011f2f, + 0xee147430, 0x7d3b4e0b, 0x82f8b894, 0x4cbefb57, 0x770d9482, 0x04a975a5, 0x18d7290f, 0xc9c67b04, + 0x574f7825, 0x77d2c8f5, 0x1cb19da5, 0xd3e4bddd, 0x9797acb3, 0x387ecae6, 0xc5beb341, 0x493c9ccc, + 0xbf5c765b, 0x860ee9a4, 0xaf7d5415, 0xe775c0b0, 0x5b19220a, 0xcc6a47b1, 0x1eb8fc58, 0xdd7b555a, + 0xb243e980, 0x99cf6d05, 0xc233511d, 0xdf029f31, 0x997a8ad2, 0xc7fd851c, 0x145f9227, 0xc0a8a3ae, + 0xc5d047e8, 0x820f074f, 0xb0c6f21d, 0x62499d3a, 0xdec3dbdf, 0x331f3af7, 0x7cb83044, 0x35bb38d3, + 0x203e877a, 0xb89caba1, 0x8c483894, 0x6a199003, 0x1491b511, 0x22ed27b1, 0x0bd3f8d5, 0x792cfe31, + 0xe7978420, 0x76a1a186, 0xd70b593b, 0x1bf40f42, 0x73678fd7, 0x6ecd3f5c, 0x72c61e35, 0x7ec3fe75, + 0xd0364861, 0xcc82a373, 0x3f71d2a2, 0xc90aa9c4, 0xde77e029, 0x45572ded, 0x44071722, 0xeb74bf1a, + 0x4d543801, 0x1cdd5e52, 0x2457e3ff, 0x2243f1dd, 0x0e7574c2, 0x8e3cb564, 0x8fd2a8f6, 0x9936d05a, + 0x618b2632, 0x26ef23a7, 0xd60e54bd, 0x447ae2a4, 0x28453ce8, 0x47d2396e, 0x98e9daa4, 0xaf44c505, + 0x81063668, 0x28972d06, 0x8f6ec43a, 0x43c74ed1, 0xb4eb6780, 0xff80371f, 0xd1c68d7a, 0x21ea54e6, + 0x4bfe186e, 0xe88c2cd5, 0xbdc673a9, 0xf8575c21, 0x46d60e2e, 0x893d8872, 0xf91a7b72, 0x015c0f8a, + 0x489e36b8, 0xd592cd12, 0x25586698, 0xf153ac14, 0xa45ce5ac, 0x1008f541, 0xf4aa3f5e, 0xe56344d7, + 0x6b7471ec, 0x64a45964, 0x82acaf88, 0x8dbf0cc0, 0xd7ecaf7c, 0x59dda290, 0x238f97a3, 0x767c92f9, + 0x35673366, 0x88a8a016, 0x7abfa6fb, 0xc238e409, 0xaff1aa37, 0x8e6de8aa, 0xf1206f40, 0x0452282f, + 0x6e7b70a3, 0x0233d080, 0x76ef070b, 0x887ad823, 0xa2465a15, 0x7a2fd263, 0x87651217, 0x74a7d7d1, + 0x082a3cf3, 0xc4d1e870, 0x4ca89bce, 0xf2e44c61, 0x1b70e678, 0xf3983652, 0x4d7f04f0, 0x88e12459, + 0xc15648aa, 0xdca40f92, 0xffd26eb6, 0xa0b4eb79, 0x5ceae5dd, 0xbc42c31b, 0x1dcdecb8, 0x9fe09178, + 0x5467cd65, 0x631eda63, 0x56b82861, 0x283cd0f7, 0xf1f796cd, 0x042069a4, 0x0838038a, 0x8ebbeb0e, + 0x7ca7e7c5, 0x4b93a755, 0x35b6cf14, 0xc7580d61, 0x08c7d78f, 0x64499dfa, 0xf4c5d1b6, 0xd56eccba, + 0xfda1237a, 0x18959678, 0xea066ed2, 0x00ada635, 0xb4656557, 0xf18a67c1, 0xa3b6b0ae, 0x00659151, + 0x6fcbaf2a, 0x3e9732d0, 0xd7a863a2, 0x2879ebd8, 0x9e75d44e, 0x00787f54, 0x7ce9deba, 0x51461733, + 0x701e0229, 0x53d866e3, 0x7b5cea7a, 0xef2d75aa, 0x06c39896, 0x915a8f56, 0xb9e1cf88, 0x379555c5, + 0xc60df0c5, 0xbbdbe68d, 0x9e1c0bf4, 0x28eb6952, 0xd6e50c14, 0xe81ab5ea, 0xb61f0af0, 0x6d3f2fc5, + 0xee588ce2, 0x7d4600c6, 0x8e56667b, 0x4839391d, 0xb58f544f, 0x0b0f6c25, 0xa4ac3e4e, 0x8c73ee43, + 0x899efed2, 0x851e3b41, 0xe8bb576e, 0x3d0e5035, 0x0946acfd, 0x42d320ca, 0x6d16092f, 0xc98b6efa, + 0x9acaa342, 0xd9049729, 0x39c64850, 0x1536616e, 0xe2a4650c, 0xf4079df1, 0xdfb1ff7b, 0xa49930bd, + 0x14ba5730, 0xafe80c6d, 0x5733302f, 0x0e99ea7b, 0xf149e2b5, 0x1c75dc61, 0x8823f731, 0xd4129838, + 0xc42e9c1d, 0x1ba0ef0d, 0x5930f6c3, 0x06fd8084, 0x4371c99e, 0x8828770a, 0x908a0e4a, 0x33fb96d7, + 0x2c5c15c0, 0x89814ffb, 0x1f59fd09, 0x842f4159, 0xae699152, 0xe1efdc16, 0x997b18e7, 0x466518a5, + 0xa6e359ed, 0x8ec8a364, 0x67d22cbd, 0x8811855e, 0xe22a33bb, 0x6e649d4f, 0xfb8ac9b3, 0x27a08372, + 0xbd7b6496, 0x7c385c0e, 0x30aa5b8a, 0x1c2c647e, 0x41ae6391, 0x5bff4e8a, 0x39e5012d, 0x6d9b898d, + 0xdb46a9f7, 0x481be273, 0xa2a5402b, 0x00734a84, 0xb56bce88, 0x304a011c, 0x70603d4e, 0x3e75de65, + 0x67a064b2, 0xaf980045, 0x02275485, 0x16dfce9d, 0x76310e7d, 0x78a01115, 0xda9d01b9, 0x69e8029e, + 0x00e97db6, 0xa687eff9, 0x0850bf37, 0xf2fcd94e, 0x22e18a36, 0xd208cce5, 0x9fb79d03, 0xd29e5dfe, + 0xeae8fce2, 0x4b9d7be6, 0x9940086d, 0xa63d9eb3, 0xb04e6fcb, 0x8e726a65, 0xc0ae3be3, 0x1c008e67, + 0x7a9d9f81, 0x3ad7a875, 0x81ae0088, 0x72805488, 0x38d5f751, 0xc9f59f60, 0xfe0c2940, 0xfb0282d1, + 0xaf9d4fc8, 0xbfe75b23, 0xee2580d1, 0x4c719405, 0x29dd8af9, 0xee5c601a, 0x220dcd99, 0x616b8039, + 0x1b6fc476, 0x4fa23620, 0xf704f57e, 0x97e917b0, 0xa83d58a2, 0xf44ac55a, 0x546a5158, 0x5a99b77f, + 0xe95bcb5b, 0x52a4d535, 0x0d521406, 0xdee012fe, 0x382aceec, 0xa8d5c837, 0x69923863, 0xce96aac0, + 0xfcfa2da2, 0x963c0c7d, 0xf6ae712b, 0xcecce3a8, 0x8be09cd0, 0x5c3f8084, 0x9add0571, 0xd63b36ef, + 0x2ed5ad02, 0x2940637a, 0x4b7d8fce, 0x1261f57d, 0x56ba937a, 0x363b362e, 0xcdccbf69, 0xe0ff8807, + 0x3ace6531, 0xa33ec57f, 0x161dfa01, 0xc107c94b, 0xef80146d, 0x06747939, 0x8d9d72e6, 0xef109bf0, + 0xdb52a0b9, 0xc9a3f5c1, 0xef2d224a, 0x2005a0f4, 0xed9de7d1, 0xd9c9cdb6, 0x20d27aac, 0x271f6833, + 0xadff7e65, 0x5929c2e8, 0x38db2018, 0x517eef41, 0xaf31c29c, 0xac6d6a4a, 0x29eaa995, 0xb11d51c3, + 0xa32f4f50, 0x87473d3c, 0x15e3fda7, 0xc3705553, 0x133c2c31, 0x395fafea, 0xfd760273, 0xa1f22cef, + 0x8a6a791b, 0x9665724d, 0xfdda79a8, 0x50b26405, 0x52a07364, 0x67976228, 0x611e42ce, 0xd59f6eb2, + 0xb797e368, 0xdd66841f, 0x64b90080, 0xcb03d154, 0x82c0858b, 0xe148c54b, 0x811f9a11, 0xfa58c722, + 0x334d0991, 0x7ed81771, 0x1f9eb835, 0xf53d1c28, 0x6175d541, 0xcf9d9512, 0xeab36bd6, 0xf7f40796, + 0x6cd26544, 0xc1621008, 0x0c9fe236, 0x427379cc, 0xa2048901, 0x43f35612, 0xaab30b56, 0xe5eeb26c, + 0x3814a8ff, 0xbb63834e, 0x07dc2fbe, 0x76846918, 0x3620d1bf, 0xb0452dac, 0xcc277f8e, 0x684c8683, + 0x4bd22303, 0x70368dbf, 0xc1ae319e, 0xb34ded7e, 0x15fdcbb3, 0x86d18c11, 0x6162d219, 0x4be8131d, + 0xced858a5, 0x470933ba, 0x8def979a, 0x270e2a9d, 0x05496213, 0xbde5bb5d, 0x4322ec9a, 0x7713df12, + 0x9ce1d2be, 0x50379315, 0x3ef0eac3, 0xd0b7ffaa, 0x022cf2bb, 0xe9d6142f, 0x87600837, 0xb35e53b6, + 0x68a844a3, 0x9da7e3c0, 0x867c8bef, 0x207d62db, 0xd57c05a4, 0x386d8c38, 0xc34438bd, 0xa85f99a4, + 0x94e57d2d, 0x5cfc1e0c, 0xf3c39d96, 0x84fb3932, 0x3d33ba11, 0x1d60e69d, 0xb872e8e6, 0xcabfc655, + 0xa0ebc6f5, 0x99ecff0a, 0x3c7a3af4, 0x4a684a8b, 0xd83a6041, 0x4a7f97b1, 0xf6d7688f, 0x2b1da029, + 0x4c0c255e, 0x941069a3, 0xd8c4bc75, 0xb7401e04, 0xb66071a5, 0x0591d62c, 0xf0367bde, 0x577b15fc, + 0xc9a363d3, 0xf2d06fe8, 0xdb196e8b, 0x2f11b5d6, 0xad30a525, 0xa8e8e5d1, 0x0544d527, 0xe8c5864c, + 0x427024b0, 0xfc6431fc, 0x54e30496, 0x516c6fa4, 0x3541cba0, 0x507e18be, 0x2e072c4c, 0x8ed7251a, + 0x3871e580, 0x6aaec05f, 0x57d0a327, 0xa94645c4, 0xae7b9428, 0xa50e8fbf, 0x0d53270c, 0xdd383d85, + 0xb25287e5, 0xf6c7d64c, 0xfbe2c740, 0xcebd9913, 0x0660787f, 0x94a5423c, 0xfb08a49c, 0xd6c9fa74, + 0xd64359fb, 0x498ec5d3, 0xe5b7e2c4, 0xbc859b4e, 0x927d9026, 0x7ba2c3f2, 0x26283b59, 0x2d839cfb, + 0xfa021232, 0xd76233ae, 0x95df2783, 0x2cfcb9c0, 0xd3481cd8, 0x4499f982, 0x59240015, 0xb374ce04, + 0x7fed0458, 0x07791623, 0xb33df75a, 0x4e807476, 0xc82e02a0, 0xede3bdee, 0xcef984c6, 0xfb69d2bf, + 0xbf046b78, 0xf92bdb42, 0x06e4e064, 0x8e0a9dfa, 0xd33a61bc, 0x4586b836, 0x549e8596, 0xa482536f, + 0x5ee573bd, 0xb52cafcb, 0x16a694e3, 0x186995df, 0x2fba74ac, 0x20adefbe, 0xa2e00297, 0xf28c7c8e, + 0xee7cefaf, 0x95b9bb9a, 0xd7ff1ea1, 0x20116232, 0xf815e0b8, 0xebf76d0e, 0xd49bbe56, 0xa9f6ba63, + 0x364c3597, 0x2f9b9aaa, 0x502a9aab, 0x8ea42efa, 0x55229d51, 0x76f9f2d4, 0x18667824, 0xb170e194, + 0x06c11336, 0x2751225d, 0x7a5a6dac, 0x5f097178, 0x8169850c, 0x988e30dc, 0x84dece0b, 0x60ec6241, + 0xa4893205, 0xf45bd791, 0x25decbb5, 0x843f6abd, 0xe8af7deb, 0x023c29cf, 0x3ed31974, 0xbe00f61b, + 0x769e165e, 0xfebd6987, 0x72321d7f, 0xc0bab3ca, 0x8597b362, 0xe8ea7a28, 0x22932c26, 0xf54bb453, + 0xffc22380, 0xbb941766, 0x82b73887, 0x39c6174b, 0x049302b8, 0xfd8d4445, 0x1e15e88b, 0xa5de42ed, + 0x9ec059df, 0x4b0a635d, 0x04e49408, 0x8ebeff57, 0x1bc8fa96, 0x5166144e, 0xdee302ca, 0x01cf8e14, + 0xabdacfb8, 0x756e25cd, 0x80898943, 0xcb02f5f9, 0xcfd58cfd, 0xc78da3ff, 0xf42ecab2, 0x4c795c82, + 0x9718fa61, 0x650cd802, 0xda683807, 0x043fd3c3, 0x5f27d608, 0xe87c77d4, 0x2d5808e3, 0xd017411c, + 0xc56c489c, 0x5bbac0cc, 0x67bd64f1, 0xfce55f2b, 0xd107af13, 0x05de9e97, 0xd5962f0e, 0xf9778ea6, + 0x9a278d5d, 0xcac9c800, 0xf1b60918, 0x7edca1db, 0x22b03d98, 0xb158ec6b, 0x881162f7, 0x82a79f04, + 0x11f98380, 0x735ddfa5, 0x2b972145, 0x357220a5, 0x1d5e5462, 0x6982a95c, 0xd9d1ddee, 0x4781585d, + 0xf0c28f8e, 0xacc38bed, 0x1dfa23c8, 0x379ccb54, 0x571bb7bd, 0xc9c83f77, 0x817a9e60, 0xa275052d, + 0xbf3b9197, 0x3c476548, 0x595ccbe5, 0x1b145b3a, 0xe7d3cc15, 0x89df588d, 0x1ab0621f, 0x63c99125, + 0x27ccb7ac, 0xb9a1ba68, 0x8023f7ed, 0x452937c6, 0x5853f390, 0x6fa7c32e, 0xe70a127a, 0x875723d5, + 0x76be3e2a, 0xc67daaf2, 0x81565db6, 0x091f4e3b, 0x1351c2b6, 0x10294662, 0xb8bddf84, 0xcb25830d, + 0xdbdbb087, 0xdc357d46, 0x624a8b37, 0x1685ae07, 0x00447947, 0xe5f13902, 0x48e50714, 0xee3bb828, + 0x9b86d0fa, 0x8948816a, 0x5ee9235e, 0xfae97cd3, 0x7ab76388, 0x618b4932, 0x7399c02f, 0xb0d129db, + 0xa64dbe47, 0x062d8bc2, 0x10eb8478, 0x7eeb4556, 0x266f3cfe, 0x9ddf98d2, 0x40efcef7, 0x6f495dfd, + 0x3b6ba5a3, 0xe3b3bae5, 0x9bfb7f8e, 0x04d3f60f, 0x337e89d9, 0x6e11afc8, 0x7e36a1ef, 0xcee21386, + 0x6cab44e7, 0x760678ba, 0x27ce0930, 0xfd92af5f, 0x580cee85, 0x3c3573a8, 0xb36060e3, 0x4b252327, + 0xc8b3cc48, 0x42673954, 0x895cc60d, 0x3ba2f627, 0x9201f4e6, 0xf8f601e5, 0x6bc713bf, 0xc1beba1e, + 0x0ac9472d, 0xa6f4dfb8, 0x04bd107a, 0xc98a8bd3, 0xf7332db5, 0x8d22bbb1, 0xdd396817, 0x96813bf0, + 0x4ef9e9c5, 0x17050817, 0x332a6886, 0x7c9b4a50, 0x530ad718, 0xbbf8a98a, 0x5f8dbfd3, 0xa4bf8b8c, + 0x1f71ce61, 0x458d3057, 0x9130d32b, 0x6c775eb5, 0xbabdd316, 0x9025ff12, 0xf8fa5e18, 0xe25714c0, + 0xf437f9a6, 0x045ae869, 0x52691b4d, 0xefda0582, 0x85e8a478, 0xf520e2ae, 0xa85a8a9d, 0xb5fcbcda, + 0x072bf936, 0x21fdaeeb, 0xf8c37ded, 0x4d702342, 0x96e517bf, 0x7e8689b8, 0x5b3f9ac0, 0x8955110e, + 0x7a631391, 0xf111a339, 0x90afca57, 0xc930cc65, 0x9f684950, 0x27e8a4e2, 0x031c9a04, 0x05fddb68, + 0x27fc9038, 0x9443b881, 0x1e7f1d1f, 0xe4f7bf0d, 0xfb050cec, 0x09dea080, 0x46c586ba, 0x70b7fa97, + 0xadb3de8e, 0x0c7e6bc8, 0x4c5b3434, 0x4cef8ed6, 0x00946ee9, 0x6bc54c81, 0x39757141, 0x3d42cbf7, + 0x442b9f94, 0x27f176cb, 0x50bb6604, 0x1c13e7bf, 0xcf840723, 0xb13d59ae, 0xc19186d5, 0x93db1ac8, + 0x4f72828c, 0x82c93b2c, 0x1ae46773, 0x49676d58, 0x4d31a972, 0x6d2b98e8, 0xc7f01ef9, 0x54e46f3d, + 0xa7005432, 0x241cc887, 0x614332a2, 0xe6f3d545, 0x8690c5ec, 0x2abfc81d, 0x47ebbe3f, 0xcb393ca3, + 0xd6196156, 0xe58d24bf, 0x3740557d, 0x0d86ee9f, 0x7fdbc18e, 0x8d73a85e, 0x733ea7cf, 0x351bc49f, + 0xeab90569, 0x479cd57e, 0x80c22622, 0x3ccd90cd, 0x07620ba1, 0x22fd411d, 0xd6a0d6f5, 0x84cf9716, + 0x4e093ba1, 0x12a00dfe, 0x6bb76913, 0xb53b32ee, 0x9fe07bbf, 0x4bd96978, 0x7a253a0d, 0x5609f9f6, + 0xda74601c, 0xdfe2b880, 0x7931d17c, 0xac50aa08, 0x694a220b, 0xe5b48b91, 0x51d53a8f, 0xc2a3ba5f, + 0xde195857, 0xf5f34c08, 0xd1f05239, 0x07c98585, 0x9fdf7495, 0x3c48bb2d, 0xab226333, 0x947aa5d0, + 0x5f49d861, 0x8393ad3f, 0xc6d5f57f, 0xeb319c9c, 0xc93db822, 0x0efff3b2, 0xc11af944, 0x9b743107, + 0xd7bb9158, 0x77d4bcdf, 0xfb3d1a6b, 0x8879ee2c, 0xaf3dd280, 0x6bc20f31, 0xbfa8ae1d, 0x8af06d1a, + 0xd63e855e, 0x8a94027a, 0xeee0a649, 0xe23c2a48, 0x5d2cbfc2, 0x47aa8e5f, 0x9074ea00, 0xd5b5719e, + 0xa09b34eb, 0x38e45c81, 0xbfd99569, 0xf3cf4af5, 0x2ce66638, 0x1f2523a5, 0xa67ff819, 0xed5dc8f5, + 0x97ba7ba1, 0xb20f102d, 0xff8b4e3f, 0xd46c1882, 0x330a2c90, 0x6567b602, 0xfbd2bcb7, 0x6991d82f, + 0x6aa64129, 0xe34df276, 0xccd71409, 0xcb4a8115, 0x3b5648ee, 0xe9e79633, 0xc2c38528, 0x6e79357d, + 0xf31f5a0c, 0xada82507, 0x87233a58, 0xa3bf1138, 0x56fc1927, 0x96faab79, 0xeedc8e60, 0x5f3c19a5, + 0xd6478720, 0xd5179026, 0x172978f6, 0xbc0be62b, 0x7755c458, 0xbf9889ae, 0x81aa9130, 0x9f5ca90f, + 0xb30eeab1, 0xbb148378, 0x243aa4c8, 0xf0cf6a7e, 0x8f703ba4, 0x2a67d525, 0x856fff05, 0xf94939d8, + 0x625f25a3, 0x62fa833d, 0x82dc5502, 0x836614fe, 0x55377689, 0xa5db0b1e, 0x29c66584, 0xc2ccf420, + 0xa951ea92, 0x2761a33e, 0xb3512c77, 0x74b9ea79, 0x6b5c6d2f, 0xdc49beb4, 0x7e8cab36, 0xe38d1649, + 0xe373266c, 0x141bf3c4, 0x7d00d5d4, 0x44b6adb3, 0x444e3bac, 0x20bca0df, 0x0af99ad5, 0xe95aa73a, + 0x3cedd5e3, 0x1d86a02d, 0xae3e6891, 0x05231834, 0xb744159c, 0xf4493509, 0xeaa70b03, 0x59ce6bc8, + 0xcedd063d, 0x0d436a45, 0x4bb026c0, 0xedc574ec, 0x9d04b0d3, 0x3c8ad93d, 0x5756be74, 0x20ef663b, + 0xf3713fa9, 0xcf18aca2, 0x557d109c, 0x34401be2, 0xbcd4b924, 0xee144960, 0x232d6f92, 0xbbe913e4, + 0x9bf35f1d, 0xb38aa301, 0x760b3f32, 0x5e38e4ff, 0xcb608eeb, 0x78d96ca6, 0x589b9987, 0xea832128, + 0x02165db5, 0xf23c67b8, 0x54be01f6, 0x7fbaa7c2, 0x716d39b3, 0xe2d51a42, 0x2aa31d03, 0xda5c2d25, + 0xc5c9dd1a, 0x327c2db8, 0xa73bd217, 0x5e8073b4, 0xbd77c45e, 0xfcf5edd0, 0x8ceff488, 0xf924863b, + 0xd5ae2c88, 0x2653e01f, 0xd8c3ae73, 0x131a5c47, 0x71d40ab2, 0xc09eb335, 0x099ae801, 0x854e5d8d, + 0x758fb301, 0xcf228821, 0x52495208, 0x303b281f, 0x244bbc00, 0x5f8ce9e8, 0xf483bfac, 0x672393a6, + 0xea17d69a, 0xb538a66f, 0x976c83d5, 0x97187fdb, 0xf5fd93ca, 0x48af0b67, 0x4a08f26d, 0x864b69a0, + 0xc9908a9f, 0x1f1662f5, 0x7f543f40, 0x7d76a4bc, 0x9afc0983, 0x5036d4fb, 0x590d2198, 0xd2ba3886, + 0x18e35220, 0x3e263f8a, 0xe88d68ff, 0xb57eb397, 0x424333a5, 0x14a3b158, 0x04dc82a7, 0x211fa7fa, + 0xdbde5281, 0xd8f0f656, 0xedb656a8, 0x18d8f9d8, 0x307065f1, 0x81ddc814, 0xc041cec7, 0x7baeb9ba, + 0x2fe0cbfc, 0x650d3279, 0xfe25d478, 0x29d7c12c, 0x1fe1c275, 0x44420bad, 0x7bbb8bba, 0xcc72b624, + 0x40ac524a, 0xea1c4491, 0xa414e69f, 0x10e570d9, 0x6bc65f81, 0xd84befe8, 0xcd39b0f6, 0xce41c05e, + 0x5e9d191b, 0xacb52d65, 0xa30541d3, 0xa37e34b1, 0x2fd3ef48, 0xbcfad43c, 0xb423811e, 0x0a8abb96, + 0xec1cde2b, 0xf94c7461, 0x211be047, 0xdee5b940, 0x014e6e7e, 0xaefe4062, 0xec4c5a8c, 0x1ce455bb, + 0x051702a1, 0x3b87c679, 0x6a56c785, 0x95b65033, 0x41e984b1, 0xc02f4a9c, 0xc1c649e4, 0x5895c48c, + 0xbf358426, 0x06dee43a, 0xabb13693, 0x654d5b0d, 0xcdef4ef4, 0x853ea134, 0xbf7f21de, 0x1a361b67, + 0x75400964, 0x1d53cd72, 0x2b43303d, 0x3ab62741, 0x64f54523, 0xe35b00d7, 0x8ef727cb, 0xc2cd756c, + 0x1fe8f8e3, 0x41fda376, 0x12f953ae, 0x00e7cde0, 0x69792be2, 0x86573aba, 0x7292a49f, 0xb556deed, + 0x8e43ed4c, 0xcbf59101, 0xb785bae8, 0x8310dddb, 0x7d1e2de7, 0x92db62ed, 0xe238de31, 0xc33c5bcd, + 0x2bcc3a6f, 0xd52a30ef, 0x842e6dcb, 0x24041832, 0x42ef74ac, 0xa13f222e, 0x57ac0cfe, 0x1aba058c, + 0x0132d933, 0x34681f9f, 0x1259d81e, 0xb26adeda, 0xae4a3c52, 0x3c88fac8, 0xbfac5cf1, 0x76b0c680, + 0xdbf460cf, 0x11cae795, 0x59b2911d, 0x0ffb6c81, 0x41541473, 0x7afc2b43, 0xfa9f7668, 0x1f77f80c, + 0x722efd29, 0xd6fbc9b7, 0xfe57c3a5, 0xea9c7328, 0xc52c186a, 0xf8e59b79, 0xe41f0695, 0x12b34f5c, + 0x80d8f543, 0xad0136e5, 0x6ab7bf9e, 0x3e68f418, 0x7386962e, 0x234d3a3d, 0xcc337f4d, 0x50b8bd52, + 0x948e1bed, 0x5400c7e1, 0x9fb57e81, 0x70698266, 0xca03e1df, 0x4503d96c, 0x3fee2837, 0x1dec2289, + 0x366abf08, 0x35e7d7b6, 0xe099bcaf, 0x8ad9ef34, 0x00f357f1, 0xd8dc425a, 0xb6149e2f, 0x9afb8a72, + 0xa5732e72, 0xf677a0a1, 0x0e389c87, 0xa74475cc, 0x910ef1be, 0x0cdcbd57, 0xd6f7811e, 0xd8e9395f, + 0x6d3452d6, 0x2635b31c, 0xeb81ccd6, 0x52e2659f, 0x77644444, 0xd522b6ab, 0x204c0f54, 0xf419d487, + 0xeb643db3, 0x9a64a9e2, 0x1cc06eef, 0xcb8b8f93, 0x5bbbe18f, 0x309f7b00, 0x93ce8627, 0x902e6d1c, + 0x432468c1, 0xb65d248c, 0x281c45b5, 0x2585941b, 0x323857c7, 0x781ecbce, 0xbbe7564e, 0xeb7b9048, + 0x127b001d, 0x0eb6f1f1, 0xff5de5a6, 0xb0bd70bd, 0xf5781678, 0x1618aade, 0x7d47129a, 0x458d77a9, + 0xa306e97d, 0xfe1345d8, 0x2738dd2b, 0x2502d053, 0x80e27f8f, 0x339d6488, 0xa6052903, 0x3af13ea0, + 0xe7f0985f, 0x78d4aaab, 0x56b2c505, 0x87b6e143, 0x4f5a466e, 0x7ec06f5d, 0x652eca15, 0x27d8bb88, + 0xcebd6152, 0xe1280567, 0x87c481d1, 0x6fcb3093, 0x4f346f12, 0x62078ece, 0x05ff8d30, 0xada0e48b, + 0xe16291da, 0xfb2c2fef, 0x2ef31a82, 0x5588f72a, 0x55c220a7, 0x585948d5, 0xf4778456, 0xa55c9acd, + 0xeb74e056, 0xf700a183, 0x285fd2ec, 0x49112a78, 0x999dcec3, 0x377be8e2, 0x3018d15d, 0xe5a88154, + 0x10e61e1b, 0xf1edbb57, 0x4e9b96f1, 0xf7c0eb81, 0xcb86e6a9, 0xa4675209, 0x4c09a456, 0xef8ae15a, + 0xec7535b5, 0x96b5fb01, 0xf44f5c81, 0x8af8a3a8, 0x9d4d72d3, 0xa9495916, 0xc51b7e2f, 0x627bc3b7, + 0xd53e12bd, 0x3472682d, 0xfd60961e, 0x10fda304, 0x77b6653c, 0x4cadf48b, 0x20e4a11e, 0x9c452756, + 0x515773fb, 0x507b8787, 0xe9c72356, 0xd8b939eb, 0x6890b7ac, 0x6d0ae625, 0x47d572cc, 0x5c28baa0, + 0x4aa819e2, 0x8dece63b, 0x43a7869a, 0x61405bdf, 0xa1897cf1, 0xea969460, 0x756ed0b9, 0xb7a05690, + 0xc2597bb6, 0x7d6ea973, 0x71b93c65, 0x34e2e118, 0x1d8ea4f8, 0x1c6ae00a, 0xf846c8c4, 0xa964106e, + 0xc042bb6b, 0x190bdb58, 0x9c463c16, 0xf1306520, 0xb7ddf798, 0xa14c37ea, 0x777abb3e, 0x872e08c8, + 0x38c61fe5, 0xe669b2f6, 0x3db5d797, 0x90fe6573, 0x98af2713, 0x45e26931, 0x00667924, 0xa5479bbd, + 0xaa8acaec, 0xaaf32f15, 0x70d81ac5, 0xa76ab042, 0x79e4b78c, 0xa12d5d89, 0x9861c011, 0x203a26c3, + 0xd5c2f52b, 0xbb74d9ea, 0x3df624b2, 0x24427716, 0x2ed230d3, 0xbc8af6d0, 0xf2dafd99, 0xe4876dec, + 0x59147fbd, 0x5574a3e7, 0xc2a4e20a, 0xa33b024c, 0xbc78055b, 0xc43ab7cb, 0x9523c2fb, 0x3f1c3393, + 0x7484bd15, 0x76c8d7d3, 0xb17558c5, 0x3a26dcc7, 0xa63eff14, 0x2fa30044, 0x8f4841e5, 0x6c39b41f, + 0x18799df1, 0xc78c54e5, 0x2e0f910b, 0x16cb4848, 0x69df91e6, 0x1a00e9d4, 0x3713e9c2, 0x648e7bfe, + 0x02342fc4, 0x93aff6de, 0xa76b02a1, 0xeb956cbc, 0xf8798849, 0xcecbf8fd, 0x591cad30, 0x864b5582, + 0x00e430ab, 0xdaacf3a9, 0x75cd3862, 0x1cd4e53c, 0xae789fd7, 0x0bda38d3, 0x6803581a, 0x8ee98776, + 0xcb70f2be, 0x1f0b8678, 0x939ea3fd, 0x1731823a, 0x025f2ff2, 0x1ac7412e, 0x2c9c05fe, 0xe313b161, + 0x602773e4, 0x322d9529, 0x1d75b9a1, 0x1c4fff63, 0x2e61de5e, 0x46f93387, 0xea44600b, 0x2ec1ffb8, + 0xd4efec18, 0x32b3c733, 0xdfe899d4, 0x17772898, 0x80371529, 0x943d5439, 0x8d2b1cd9, 0x7f1a5279, + 0xa21053d5, 0xbe8c298d, 0x17c235d8, 0x49ff607e, 0x72ff4701, 0x83015c63, 0x7b79eb52, 0x2c3a00ab, + 0x64afc96e, 0x597286c0, 0x4a58a80c, 0x088b58ff, 0xf7bf20dc, 0x350ba00d, 0xa77f35db, 0x50c00dff, + 0xf4b8e661, 0xe586b41c, 0x96e3de26, 0xb9b23db0, 0xdadfd634, 0x5bd0183b, 0x5673c15e, 0x1b894ba4, + 0x614d1c22, 0x581a0530, 0xef47e2e7, 0x6b067831, 0xe5e646f9, 0x4ca7722d, 0xecd9328b, 0x8e5cb42f, + 0x46ae115b, 0xe84fdd60, 0xf5e05365, 0xb1398b73, 0x6ec30e1e, 0x0548d114, 0x70fa1c06, 0x84c78db9, + 0xaf4ae219, 0xe3b519d1, 0x6da728fa, 0xf27a771d, 0xb20ea109, 0x45aa0eb8, 0xfdb4e8ee, 0x0bc4eb7f, + 0x55ad4af6, 0x4d8a996b, 0x2d882139, 0x31ee3e4e, 0x7c060c69, 0x68cfdbf3, 0x45a7a482, 0xed5f869e, + 0x82a1b2f4, 0xf45c99aa, 0x544c77f1, 0x964dfcb3, 0x614d146a, 0x1efb4a31, 0x0ca746fb, 0xbceb639f, + 0x1f149709, 0x2e9e80eb, 0xc605ebe5, 0xa33b560e, 0xad27e840, 0x4d46cc9c, 0xe44417f0, 0x72b59e22, + 0xc67f2224, 0x00df5ff1, 0xfdd0ba25, 0x72cfcd7d, 0x44962a85, 0xfe16c0bf, 0xdb750801, 0x7d049a89, + 0xcd9311d7, 0xc9459a64, 0x7547747e, 0xc6070ad6, 0xf96803ae, 0x5f612bca, 0x43f44c60, 0x050e5e02, + 0x10d27da1, 0xb6bf1771, 0xdd06833a, 0x781c8d75, 0x97b5e271, 0xca16b62f, 0xa9dbc451, 0x094184f1, + 0x7ae847d8, 0xee0ef70e, 0x3f9a4caf, 0x8635b070, 0x77963422, 0xb216a6ff, 0xa1154c4b, 0x268108d4, + 0xffa45198, 0x56a5ffa5, 0xd1256aea, 0x55f389b6, 0x6f5bb960, 0x9de2cce0, 0x42ded5f1, 0x289042ed, + 0x35d831d5, 0x15ecee57, 0xced9cd73, 0xa0765b50, 0x53515651, 0x24e4395f, 0x50c37b4c, 0xbfb648ee, + 0xdfb96a32, 0x6c981085, 0x4f747b1b, 0x0cd606d0, 0x4b0d5579, 0xa123b4e5, 0x61dcb416, 0xe6ab3f61, + 0xc081ce5f, 0x38b01cb8, 0xea176a1d, 0xf7ebc00f, 0x1446d8b2, 0x7daacd2f, 0x6b44abad, 0xc8abc207, + 0x5d6c30fb, 0x28e9beed, 0xa92ff36b, 0x3bec0bed, 0xe864901e, 0xdc29f1a3, 0x640c100e, 0xd55801ee, + 0xf072bc9b, 0x8165e0d5, 0x0af9e327, 0xf5b8c1bf, 0xef43ee75, 0x332e0fb5, 0xd8a425a9, 0x57ba34af, + 0xe2b677a1, 0x85067154, 0xbde9e48d, 0xae25f934, 0x88a9b47c, 0x8a87482d, 0x16b42f3e, 0x98c1f718, + 0xdddc5e57, 0x85e50118, 0x1a17044b, 0x20d9feb5, 0x01c6c666, 0x03edcb78, 0xc6216dfd, 0x7954db6d, + 0x02ee2f35, 0x763e3e5a, 0x2d6c03dd, 0xc9360b3f, 0x7ebbc27d, 0xb3016e97, 0xa7da8731, 0x1225a4c8, + 0xee1c25db, 0x61f3ac37, 0x149894cc, 0x9d9697a9, 0xb35eef36, 0x75c642eb, 0x35c7ccc6, 0x796eee39, + 0xb04ed708, 0x673b8b53, 0xa83d742e, 0x438fbd61, 0x4dfe023b, 0x739d3eff, 0x344c9674, 0x821efd93, + 0x918dfd76, 0x48eb05d3, 0x53143ff0, 0x9cabdd95, 0xc92aa455, 0x8d30cf84, 0x3b728479, 0x3e68d244, + 0xbdd44aa6, 0x6d534217, 0xb25e1311, 0xbd7bf819, 0x539398b0, 0xc0e443c5, 0x978836de, 0x8861be09, + 0x8bbe2762, 0x05d7cfae, 0xc7a66e17, 0x9677015b, 0xe0f91624, 0xdddcfad7, 0xe4eb82ac, 0x50250bc2, + 0x642c0c70, 0xce36754c, 0xd7652834, 0xcb0888f7, 0xc136d972, 0xdec8c909, 0xae8015a9, 0x873601a0, + 0x16952f6b, 0xd6fc19f6, 0x6398edc6, 0xd9a369dd, 0x47af345f, 0xefc36067, 0xc286ba4b, 0xf565eea0, + 0x1562582b, 0x51880271, 0x15194f56, 0xe310bd8c, 0x4c1090a6, 0x2e84d0b1, 0xd024d224, 0x5943761d, + 0xb810c096, 0x50bfcfce, 0x31515b26, 0x163203af, 0x17f20c07, 0x11595987, 0x0ad848e2, 0xc13d9649, + 0xc2d50ed0, 0x7803e20e, 0x7cdfa98c, 0x7cc4a471, 0x20ee3dbd, 0x842c50ee, 0x2cbc303c, 0x172f06cc, + 0xa47fb3bc, 0x1d0dc753, 0x913682cd, 0x19cdb47e, 0x53e9e887, 0xc2d72978, 0x898174c8, 0x44f8f178, + 0xc473eb7e, 0xeb3a53de, 0x38ed7f20, 0xf0fde830, 0xbfaa1275, 0xd10187db, 0xb9e41b4e, 0xb2dac22c, + 0xc9b76d55, 0x8efd95b7, 0xcf9542e6, 0x254a1dff, 0x30bdb5ea, 0x06fa79ef, 0xd4108cda, 0x8a47df96, + 0x39f7fc70, 0x52028b21, 0xdc682d9c, 0x28c32f88, 0x059f75bf, 0xce7b7c26, 0x65d8c264, 0x5efecc0d, + 0x7c0b5acb, 0xc22bd65c, 0xf50839f8, 0xb71bf2b9, 0x45adb649, 0x78e7d00e, 0x6af4fca6, 0xfc4899ef, + 0xfc9e4726, 0x3b7074cf, 0xfcf12895, 0x28b420cd, 0x9374ce05, 0x1b22f9f0, 0x411e3836, 0xc7663a9e, + 0x00a45b22, 0x0e8dc429, 0x52d5ba0e, 0xafa5c001, 0xd4886eaa, 0x79a8aea5, 0x71b71895, 0x6e12b2cb, + 0xe35e8d5b, 0x8830af30, 0xc7e8625d, 0x8d98a4b5, 0xca6e99c1, 0x5f94686e, 0xa6a37650, 0x65ab7806, + 0x52030f82, 0xafe1e7d7, 0x7d2f220f, 0xd02cccc6, 0x7913633d, 0xf3406a5a, 0x40fe2548, 0x69ce323a, + 0x15a3edfc, 0x10725161, 0xa076462d, 0x01186085, 0x3a74fa89, 0x42e4425f, 0x97aecc07, 0x343198bc, + 0xb01b6804, 0xaa43beb5, 0xca84702e, 0x6cb694dd, 0x3251ef36, 0x68931f43, 0x164f0d05, 0x00f7b39d, + 0x62400e86, 0x36cff1e1, 0xe9c63b1a, 0xb8dbce8c, 0x76be87ce, 0xe6f12404, 0xfddae36a, 0x8da676ca, + 0xe263f65d, 0x1c1edb59, 0xd9985f42, 0xc800c1e1, 0x05d36cda, 0x71581f76, 0xbc87bc67, 0x5093fd0d, + 0xa704ab26, 0xe84e051b, 0x36cb8a4c, 0xb8e18b1a, 0xa40816cd, 0x79710c81, 0x9575e83f, 0x8a14da22, + 0x6c45bd3e, 0x08fdc95a, 0xf83d57db, 0xa7529e0a, 0xe4d9c768, 0xab84ac31, 0xfe8b727e, 0x409cee51, + 0xc528c67b, 0x56b396d0, 0x8b70f518, 0x8288ec0f, 0xfe7b7603, 0xa572a5c5, 0x215e7b78, 0x98e282d1, + 0xd3799ded, 0x67d6a89a, 0x54313406, 0xf88478b0, 0xc986ec02, 0x118430bd, 0x4f2078b8, 0x11a69cd8, + 0x8144faf0, 0x25f827ea, 0x63b16a39, 0xf4b759f1, 0x1c560136, 0x58bf5087, 0x2c239870, 0x5722f768, + 0x59e60b5a, 0x26d38039, 0x61af8906, 0xca6660f7, 0xcc0f5a85, 0x9f8828a2, 0xbccc654b, 0x49f23975, + 0x8328a14c, 0x322c578e, 0xbdb94872, 0x4b338ca4, 0xff413968, 0x736308cd, 0xc9e92589, 0x43dd731b, + 0x1892965e, 0xbd2a9c4c, 0xb5c74bb3, 0xdc2c3ba9, 0x2dcc0149, 0x8f3dbf06, 0x8b8c20fd, 0x5c4f5cd9, + 0x86708a32, 0x7a980186, 0xe67e4dad, 0x6ee9575d, 0x95bc3fbc, 0xc0976124, 0xef3c30d9, 0x2fe1bdf1, + 0xabf2bd1e, 0x76872d71, 0x9ec99bc7, 0x2ccdbdf2, 0x9103161f, 0x6fb36067, 0x9df71012, 0xf85568a4, + 0xe92c4e77, 0x656d1da9, 0x317febee, 0xfe05d989, 0xb8332d95, 0xbd5ea9d6, 0x6a5dc60f, 0x1e385f2a, + 0xb0e03d6f, 0x511edc22, 0xe6997f52, 0x13c6ce5f, 0x4b8ed727, 0xce5e9cd4, 0x35ce7468, 0x9b299a4b, + 0x71f7b1df, 0x445353cd, 0x97b0e649, 0xdd579024, 0xb35eafec, 0x5aabeb92, 0x79fc11ec, 0x07f577e8, + 0x4c138124, 0xd9bb0e7f, 0x1d61c61f, 0x8abcc198, 0x6d76d30c, 0x4c085751, 0xb2efb633, 0x9009f4c4, + 0xc217acdd, 0x234d8144, 0x90388bb8, 0x1c374670, 0x2272722d, 0x70ab1ad2, 0x3cffb06c, 0x579a77d7, + 0xd7e07bf5, 0xd1cc20f3, 0x98f893a9, 0x8074cf5d, 0xccfbe951, 0x5fffa63d, 0xe2ab53c9, 0xc0940b25, + 0xad4d89ad, 0x4fbf9776, 0x41cee2a5, 0x25562200, 0x85df642a, 0x760611f6, 0x50e9d5a2, 0xddcaa3d2, + 0xb96fa67b, 0xaf3d1292, 0xf9c11070, 0x919a749d, 0x7973d3e4, 0xae7d0761, 0x16625379, 0x474ffc85, + 0x821e3870, 0x2bfdcf98, 0xb80f8790, 0x5db63f2a, 0xb2e5e5fa, 0xe8e214ae, 0x568ed134, 0xd956b337, + 0x76a60a69, 0xd5d3c011, 0xe92b717e, 0x22d49fbf, 0x7aa725c1, 0x189e7dab, 0x9bdcdd04, 0x3f0a9ed1, + 0x3cbb79df, 0x96582920, 0x3b20925b, 0xa7e246d3, 0xe79548d3, 0x61925dff, 0x12b79d8f, 0x9b79fdc4, + 0x7bb58d1d, 0x9b3248af, 0x26304bec, 0xfb681575, 0x403064d8, 0xd21f52fb, 0x709ede93, 0xadc8b8b0, + 0x75d7dbd7, 0x24b769ce, 0x0608797f, 0x31093f7e, 0xe32047fc, 0xa626a85b, 0x489eb40f, 0x73ecf062, + 0x82634b59, 0xed700342, 0xa3664f23, 0x75188f7f, 0x7f0dfb8c, 0xff998288, 0x818d0d05, 0x76f00fca, + 0x416c41a5, 0x1aee25c4, 0x8cdfa468, 0xcc84eefc, 0x37e1752c, 0xcbd9b676, 0x61deb096, 0x35d263bd, + 0x6bd33047, 0x5a277217, 0x96662092, 0x450d70f1, 0xbbdeb7e3, 0xecda6767, 0xecafca95, 0x6619becb, + 0x319c46ab, 0x304f54ef, 0x9878c003, 0x1b0d0da7, 0x02e81dd3, 0x5549dca0, 0x2d45db8f, 0xaa15877b, + 0x3555c919, 0x9157f4fd, 0x22ff8d85, 0x9d131c58, 0xd2e0c475, 0xde48a3e8, 0xd2f97305, 0x1b631356, + 0x3ae1193c, 0xa0bc579f, 0xcb7f8571, 0x55f3352c, 0xbc7307c2, 0xd8fa3690, 0xe552bc59, 0x8dfe457b, + 0xd1734d7a, 0x96ce61a1, 0x655860da, 0x6c80e314, 0x3bd34e01, 0xefc751ec, 0x671164ec, 0xc237acb5, + 0xcce6b17c, 0x138158c7, 0x717935b1, 0x0731e439, 0x2c9beca6, 0xd90199fe, 0x2dba4e21, 0x781788a2, + 0xe26a1bf4, 0x6e802625, 0x4a9b5da3, 0x77bfe1e1, 0x71e2db33, 0x803d60e5, 0x67959999, 0x7aea37f2, + 0x303678a7, 0x3e424da4, 0x3b788d09, 0x11562a48, 0xcb624f54, 0xfa0ba1af, 0x00e5966a, 0x3554c577, + 0x27188aa2, 0xee60440e, 0xd4cd3974, 0xbea19c93, 0x631815fe, 0xbd876bcf, 0xe662ae9f, 0x085fbed0, + 0x2bbd58b5, 0x2991faec, 0x6703f56a, 0x3a06f591, 0x9d59abc6, 0xa94eda2f, 0x5da367a8, 0x2e2fe90f, + 0x65231754, 0x1738ce4e, 0x09a2d631, 0x3e58305b, 0x2ef06d79, 0xde97b66f, 0xd3466eac, 0xdcb9a554, + 0x24020a0b, 0xaa36a157, 0xddb390ab, 0x6da41464, 0x290ae571, 0x7064c276, 0x2ef4553a, 0xea2ee421, + 0xf41a92b1, 0xb1be11a9, 0xdc819ef1, 0x0894cc1e, 0x69948206, 0x62ef6df5, 0x06c52d39, 0xb6aca0ad, + 0xdb5714d2, 0x3ed0b52c, 0xe56b4724, 0xdf7137f0, 0x25b7bc91, 0x160f7daa, 0x8147be08, 0x253a5f1c, + 0xaccc73a8, 0x08c2c7aa, 0x3a968729, 0x7392991d, 0xa4150be9, 0x60333787, 0xbd3d6bd3, 0xea01b592, + 0x8fdeb61d, 0xcfdd9094, 0xf247b107, 0x0f1a49c7, 0x93a426c9, 0x58d2f80e, 0xcf405630, 0x5053c43a, + 0xb91f70c4, 0x4d3be1d8, 0x7e0edcf1, 0x1a1c236c, 0xd4bc09ad, 0x275335a0, 0x8e6cd35e, 0x5fefda8e, + 0x3dc0f93a, 0x490d05a5, 0x336334a7, 0xb546ff92, 0xfdcd413f, 0x0da99587, 0xe28d1153, 0x77efa71c, + 0xaedaa4c7, 0x37cb781d, 0xbc9d79a6, 0x61f515c7, 0x0dbefbb9, 0x0b37778f, 0xbcd9cb43, 0xfb5f22cb, + 0xc1598cd2, 0x085fad6f, 0x34805734, 0xa45de80a, 0xf9fc130d, 0x2418c964, 0x809d18be, 0xdca0a555, + 0xf945e18a, 0xea0989e6, 0x2b7ac819, 0x46d3521b, 0x915efbb5, 0xd8c78e4e, 0x542e41a7, 0xd356448b, + 0xdb16de3a, 0xf3a46b2a, 0x7aed996d, 0x45db9011, 0xae2de3a9, 0x8b2579bd, 0x6c1108ae, 0x7b46b156, + 0x25d5ad4e, 0xecfe888f, 0x983bbbca, 0x9cde0859, 0x4444de52, 0x931edc62, 0xb68f26f4, 0x299b8fd3, + 0x11a957ff, 0x041ff16d, 0x21a73d6d, 0x9a331c19, 0x9074b069, 0xa5abca10, 0x321520ed, 0xff99e5b8, + 0xef1d0f97, 0x6e911e70, 0xf804f4c5, 0x4a79e3ff, 0xd31a6986, 0x74f2df38, 0x33c8c64d, 0x1e357a76, + 0x60ee5af4, 0x149f5ad2, 0x695f1bf0, 0x3962201c, 0xe5930dc2, 0x0fd9f877, 0xfc779e64, 0xc5d782ac, + 0xcd09f9c2, 0x7de9607e, 0x76da6c24, 0xae14cabf, 0x55893be4, 0x562d2344, 0x6eb8bb39, 0xb5da8750, + 0x15685b50, 0x05db1411, 0x99f54e3c, 0x9f0790f7, 0x2d79b377, 0x7b253e0c, 0x8f032ebf, 0x50338df8, + 0x0b750326, 0x9721f518, 0xd4de765c, 0x99adc5f1, 0xc78fce50, 0xcb30c981, 0xb5aecc9f, 0xdc775a51, + 0x81a5d959, 0x99c2837b, 0x8fbea31c, 0x165b298f, 0x67dc3547, 0x8b7accd1, 0x29da0c17, 0xd60767e4, + 0x5054380c, 0x6d598ad2, 0x61bdab38, 0x2f248f8f, 0x7a87d473, 0x7aad6f63, 0xf655460b, 0xeaf86861, + 0xe423adf1, 0x17562568, 0x6ecfa7d3, 0xfd080d30, 0x9bd5a2a3, 0xd3b9a3fb, 0x4d4d3b21, 0x561ce30c, + 0xe22ff5f6, 0x40051f8b, 0xe9ee21d3, 0x43ecabc5, 0xad6bd578, 0x1de2100e, 0x509d6d7d, 0xe0e353c8, + 0xefc75ebc, 0x64172275, 0xdc31dbec, 0x04f7ec9a, 0x715ac2ac, 0xccc8b7aa, 0xc70210be, 0x2bd04d32, + 0xc3f072f4, 0x0412dec0, 0xdc30c21e, 0x3f037cdf, 0x46768833, 0xa27707d9, 0x50ddc532, 0x8681a324, + 0x00447676, 0x6d5fc9b8, 0x1a59ebe2, 0x877b39a1, 0x736c2832, 0x8d533ed6, 0x93b5c396, 0x8582d436, + 0xdd75528d, 0xf834f98d, 0xa5b8ffa7, 0x6d816289, 0x2c76b871, 0x4794ffba, 0xf1609c1f, 0x49419a08, + 0x14385805, 0x81a27f0c, 0xa274aabe, 0x4336c95f, 0xf1009d92, 0x14cd691a, 0x76715f7b, 0x219f780c, + 0x060ca24c, 0x7f55ef08, 0xd57f6fbd, 0x5d4be898, 0x158f3c64, 0x1f8b08e9, 0x8bdcafae, 0x6895a5f7, + 0x80c9315e, 0x7e991b31, 0x8aad4d20, 0x1406a30a, 0xe12e3dcd, 0xd99b5acf, 0x3ea6a936, 0x73301187, + 0x63a9517a, 0xbf070e52, 0xfaa46eaf, 0xb8d79b3d, 0x270311ee, 0x9eec7455, 0x9160fd21, 0x4fbbf33e, + 0x8bb80cbb, 0x1e842c3d, 0x59b9bb04, 0xe06cee1b, 0xc57cfff0, 0xdf7a9934, 0x70125c26, 0x17cfffa6, + 0xddffd6f8, 0x61a488aa, 0xc87cd1d2, 0x43bdeaf4, 0x38d6768c, 0x6fb901b1, 0xdf570fcb, 0x007a5820, + 0xb273a247, 0xd1512047, 0x6ee21060, 0xb430ad31, 0x4afbe7aa, 0x4e6dcc98, 0xf37a261e, 0x5ad21d5d, + 0x0e90915d, 0x2c6411f2, 0xa22cbc33, 0x979180cf, 0xf771c232, 0xc3af6bbe, 0x86037b5f, 0xe0dbcf4d, + 0xc8a4cae6, 0xaf92326c, 0x0fce6aed, 0xa654c4fd, 0xa23a26f3, 0xac088b26, 0xded8c48e, 0xf94455c5, + 0x739aff1d, 0xed00e0fd, 0x91c0c837, 0x6d2f9307, 0xe772dd32, 0xb69f67c1, 0x6124dc49, 0xf2a969d2, + 0xd9ca6a30, 0x3bb78612, 0x79291d1e, 0x9e419f99, 0xa3f81169, 0x549ef83d, 0xdf73a81d, 0xe3952095, + 0x02829f6d, 0x8d056a90, 0x10fdc58a, 0x2ee8b1fc, 0x139ba34c, 0xe6528f3c, 0x95ecfa7e, 0x81bf10f7, + 0x064fe0c0, 0xd0dda336, 0x4239c7c7, 0x1f096a3f, 0x7db44a05, 0x99b396f1, 0x4431c009, 0xd3353e44, + 0xd872c3b4, 0x1e07da32, 0x9bc42d43, 0xd4830dc8, 0x0dfbb0b8, 0x4eb8147a, 0x9adaae1f, 0x97942370, + 0x2e526a4a, 0x07691f5d, 0x0cf31f69, 0x7f562548, 0xa030b2bc, 0x38504bb9, 0x0aa72c9e, 0x5246642b, + 0xcf44f3f9, 0xcc149d06, 0x05368a2e, 0x0f517d4b, 0x0f2b1fb8, 0xa065a570, 0x7825cdbe, 0x19a21573, + 0x5beafbef, 0x88ce14ee, 0x6a4f2fdd, 0xfbc22091, 0xd4f4e61f, 0xe86509d4, 0x1e41f692, 0xb208021b, + 0xaa607e4e, 0xd4583973, 0x0099e2ae, 0x8c21cc31, 0xcc8f9bfc, 0xd7ed470b, 0x26e24a30, 0x3d1472e5, + 0xa8b85055, 0x7ff03e49, 0x28674880, 0x74efb981, 0x2c3245f4, 0x5ece8e9e, 0x0688e0b5, 0x70b45589, + 0xa32dc06f, 0xab7a2269, 0xb867db20, 0x3ad4315a, 0xf5a1def3, 0x00856e45, 0x70ce1466, 0xeab8bca9, + 0xdc42012a, 0xeec06983, 0x22c7c9c9, 0xc4ccd0ac, 0xe54ec9a1, 0xce2ef50c, 0x8032a847, 0x5aab8a1d, + 0x9a8a5b31, 0x21fe7281, 0xef83ba70, 0x88fe2f7d, 0x2e23f46b, 0xd5bf44eb, 0x27e374f1, 0xf7ba4c6b, + 0x470201dd, 0x8f1389a8, 0xf83ec693, 0xe680b666, 0x8a70385b, 0x7982c549, 0x72ee50ba, 0xe05812d7, + 0x9930657c, 0xd7eccc93, 0x897e341d, 0x59ab5c5c, 0x3a106334, 0x8c5dedd8, 0xe7333318, 0x41cf0ed9, + 0x88c88a58, 0x0f9111ef, 0xfa987a49, 0x1af56b00, 0x6f1266cb, 0x21ade7c9, 0x8e0bcf92, 0x5e96a3bc, + 0xe40aec46, 0xdf4f7d91, 0x92f7aac3, 0xd147b9ee, 0xd02d8908, 0x86eac934, 0x5de88388, 0x1432215c, + 0x3c3ec193, 0x885fdc2a, 0x3882f20f, 0xd59a21dd, 0x84717bf8, 0x68784513, 0xe1746f4f, 0x5ca0a94b, + 0xa074f908, 0xf05be2da, 0x2c9f7b0c, 0xe06f6b2e, 0xafcdc44d, 0xc744bce9, 0x94fd3a09, 0x0e52676f, + 0xadba6a06, 0xd2b179b0, 0x87eba072, 0x9343e940, 0xbb8f5c2d, 0xf6402c9d, 0xd64f22bb, 0x98ac2c62, + 0x19bed524, 0xf34eb446, 0x4385d121, 0xc00ec3e2, 0xca566232, 0xf33930af, 0x86641252, 0xe3c8a9fe, + 0xccb833b6, 0x192dded5, 0x7e1d1c9f, 0x91c62627, 0x2e9673a3, 0xab436926, 0x0a613e01, 0xc669325d, + 0x074ff14f, 0xde65cbde, 0x324e42c8, 0x726608ea, 0x74ec2f0c, 0xedfe987b, 0x43104ac4, 0xdd363f9a, + 0x7827e3be, 0x5e8bb021, 0x951eee1a, 0xcc2baaba, 0xcf34ec17, 0x89ce6b9d, 0x473ec9e6, 0x228dd67e, + 0x8058b58a, 0x8acbc568, 0x84bd6af3, 0x76ff5c77, 0x213f9d62, 0x3ef3ce61, 0xf439fbb1, 0x80c58888, + 0x7141ca77, 0x1f2f905b, 0x8a6ea1e8, 0x881ae994, 0xc2da2c53, 0x9d397798, 0x028c429e, 0x7b64af75, + 0x995df0a7, 0x2d16f9bc, 0x626710b7, 0x795ece1b, 0x47c8b861, 0xb323aca7, 0x0d62290c, 0xed1a7cee, + 0x16caabbf, 0x2ad440ed, 0xe589d979, 0x7d1f94b2, 0xb795a78c, 0xa07c8bdd, 0x7f1b5064, 0x25f1aa59, + 0xab1bfe84, 0x0541892b, 0x845c6ead, 0xdce5cc84, 0x266f9273, 0x77435c2a, 0xad012819, 0xf26289a1, + 0x839e4b9a, 0x055c24a6, 0xc70fbdda, 0x4001d652, 0x0c159e2b, 0x02e616b8, 0xa4602321, 0x3bf85c95, + 0x55b1b173, 0x342314e1, 0xfbdcac0b, 0xb255a45a, 0xfbbcbde7, 0x096644bb, 0x623ba653, 0x199ebfe5, + 0x01ce3c90, 0x60e85fb6, 0x9ac3c56c, 0x08c07dad, 0xbf3f479c, 0x1848818d, 0xd239fcf0, 0xf82dbe6a, + 0x41d71396, 0xc20b2c4c, 0xf0a054ee, 0x83b629fe, 0x8fce9ff2, 0x4a385042, 0x407c65fb, 0x6c66f6b2, + 0xb0a401d3, 0x56a331b8, 0xbf7f1db8, 0x40bcb152, 0xd5733aac, 0xae6f214c, 0xc35857c9, 0xd23bf3a6, + 0xdad143bb, 0x5869598a, 0xa49e97f7, 0x3c20aac6, 0xdafe010d, 0x05ff29c5, 0xadae4e21, 0xd2e19871, + 0x214499b0, 0x53752137, 0xa3ea46aa, 0xf6ed2069, 0x36bcdd66, 0xa08010ad, 0x7c881fa7, 0xf5cdbbd1, + 0x75202de0, 0x19fa5c4c, 0x8c4f6356, 0x311465d7, 0x2e088e9e, 0x5ffc47ea, 0x9a18647a, 0xb36e0a69, + 0xab0b579e, 0x98f8693a, 0x7d8fe2a0, 0xd5e96cdc, 0xbc70b871, 0x2530d8f1, 0xe113fcaf, 0x46eccde8, + 0xb16284d6, 0xbaadca5d, 0x6bab590f, 0xdb334c29, 0xd916f9d3, 0x015b250f, 0xa60d8f53, 0x1fb83842, + 0x0ddd442e, 0x3a19501d, 0x9af33a4b, 0xb94c0a78, 0xc10b73ba, 0x129c3a93, 0x4dacd5f5, 0x0226a887, + 0x69b45ccc, 0x40e8325c, 0x5a0fb3b4, 0xfcd93c93, 0x572c9541, 0x27084441, 0x12cafa67, 0x8538617c, + 0x0b57d51b, 0x3ad8a310, 0xee6993be, 0x71c3933c, 0xc1a9f32a, 0x5c34affc, 0xeec5f2c7, 0x66cd843b, + 0x62f33d59, 0xd585472f, 0x816d518c, 0xd97262d6, 0x5d3af753, 0x476e3e71, 0x552bc93b, 0x81bad9e2, + 0x0be58638, 0x1f6cd97f, 0x981ef129, 0x14a51b2f, 0xe393ddc7, 0x23d6b885, 0x2521b217, 0x2b57cadc, + 0x97334ace, 0x6db863d4, 0x5fc36421, 0xd52c023c, 0x196a3743, 0x915a7d9a, 0x7be20675, 0x5e0251a9, + 0x5e5e4d6d, 0x3bc48e0d, 0xa35dcb7d, 0xe76d0c57, 0xe9925f67, 0x2e68048c, 0xe6c1d44e, 0x11e78d47, + 0x70123057, 0x7e699193, 0xbab0890a, 0x4fa0adb2, 0x8df114f7, 0xddbdc16c, 0x1002479b, 0x34271d5a, + 0xa0f589f5, 0xd8d378f6, 0x42e72101, 0x5ded887b, 0xbe6a2eb5, 0xefabe82a, 0x83065d34, 0x3b3a9e77, + 0x1a92851d, 0x4ff68f41, 0xe545c1a8, 0x461a4801, 0x47427877, 0x284d92ce, 0x2af1c5db, 0x0422c081, + 0x3ffd5444, 0x88dae012, 0x9288613f, 0xacbf92e6, 0x8af58ae7, 0xa3e412d8, 0x1e584ae7, 0xde8f020d, + 0x3b1cf6c5, 0xc5f93d2d, 0x522da810, 0x67ca30bc, 0x9bd44ff1, 0x3d95b68d, 0xd2860e16, 0x40d223e2, + 0xbdf986d8, 0x393b0017, 0x4f0afca2, 0x892d7a9a, 0xedc9b3d9, 0xeb14d463, 0x8af8cabb, 0x00beecec, + 0xd039339d, 0xe8bd1153, 0x0276ebd0, 0xf9eee808, 0xe0683dbd, 0xd9a75b6d, 0x9f5f5071, 0x04ea387b, + 0xad65634a, 0xb6d7f19f, 0xfccb9d64, 0x89c4c73a, 0x455a02ff, 0x1f53011d, 0x757a1bf7, 0xdf793c50, + 0xdcf65e30, 0xbcf15f4e, 0xa5a3d7a9, 0xce02bacd, 0x0f9aa380, 0x1190c0bf, 0xfbedc1e6, 0x31fee7ec, + 0x797baae0, 0x2dcda185, 0x7b1dcc71, 0x19e1cac2, 0x2fb950c8, 0xed0f0382, 0xf6ff1e2d, 0x4a826ae4, + 0xa6ff6bcf, 0xfeb4af23, 0xecb640cc, 0x5ab919f6, 0x6d1fbdea, 0x612b38fd, 0x3f1c159c, 0xb5a6c0c9, + 0xacd78c61, 0x5cfb5247, 0x587c7cd4, 0xa7132d55, 0x9d74f104, 0x7873ffeb, 0xc91c1953, 0xd6576e66, + 0x22ab9852, 0xadaba095, 0x1c189253, 0x61c2f39f, 0x39db579d, 0x717ac8f1, 0x6f13e486, 0x52bad3f9, + 0x3fb3960c, 0x5b5f20d7, 0x76f8f257, 0x6592dd73, 0x44091adb, 0xbe83e0d0, 0x86172fd5, 0x0b0e8410, + 0x96ce41bf, 0xef739f16, 0x7f2f5941, 0xb4d7f144, 0xb2d62761, 0x3f9d77cd, 0x3493f3c1, 0x2affa7f0, + 0x2b13ca4d, 0xab0c05fb, 0xe2c2828c, 0x23c811be, 0x4b4d9bd4, 0x58cb611a, 0xed33baf7, 0x5e95fb82, + 0x33c50e4b, 0x24bd72ea, 0xca6322fb, 0x9277d356, 0x1ae05017, 0xb4a3f05d, 0xa2919546, 0xab926844, + 0xec011f7d, 0x3ec573a4, 0x3128906f, 0xf939da94, 0x3231e844, 0x01aa4ec0, 0x6f07583a, 0xe03719eb, + 0x57334e17, 0x8d4bcda8, 0x3af08ef7, 0x2a7a2c87, 0x556e0001, 0x395b37cf, 0xcb2ea562, 0x426cb6c5, + 0xb34079ad, 0xa4dd8f47, 0x08c8a52b, 0xe7c7be00, 0x43a81b7a, 0x89993323, 0x40d14fc7, 0xef2bc2c9, + 0x4bd0ccff, 0x5e355d04, 0x7759aeb5, 0xe2828cbf, 0xabe6b5dd, 0xdef9fd45, 0xcabc2187, 0x70c4d6cb, + 0x58e9833e, 0x93191b38, 0x118e5332, 0xcf71e5ae, 0x80dee23c, 0x68c12cef, 0x2da1c59c, 0x9366e31d, + 0xf6c6928c, 0xd107df42, 0xa2787819, 0x4f9b772a, 0x3ba11c65, 0x4af15ad1, 0x8eb200df, 0xf033354f, + 0xf1fbf48a, 0x961151d0, 0x412a02e8, 0x7c0faa46, 0x156e3599, 0x451a0366, 0x734a0fc1, 0x0c46f4a7, + 0x62985728, 0xf7d1d503, 0x51c63e63, 0x2699eb3c, 0x0bffc484, 0x52b2d1b4, 0x24dd1df7, 0xff849557, + 0x7fd97725, 0x5fab6146, 0xa92242f1, 0xa58ea319, 0x65896aed, 0x3634684e, 0x667b9078, 0xd4859e99, + 0x3b8f5afb, 0x095ddca7, 0xbea6ac76, 0x328aa027, 0x98e761f5, 0x45148542, 0xcca28eb8, 0xa97ab4e5, + 0x07288f7f, 0x30745493, 0x11c473c2, 0xd6719ae0, 0x95c17f00, 0x036511ad, 0x76f84f47, 0xc0e46d3a, + 0xcd579e7d, 0x5f3fe623, 0xa852e23c, 0xecefff7c, 0xd6cdf5c8, 0x793110f1, 0xc21ba788, 0x331a7a63, + 0xf107d5fc, 0x42efee2e, 0x9969b7aa, 0x980b21d3, 0x40114003, 0x5e8ce5a5, 0x9733448c, 0x36a40053, + 0x7a74e12f, 0xdd155bdf, 0x45c297e5, 0x6d1a4a03, 0x272d0db2, 0x6ccb54eb, 0x13e700e2, 0xfe7f66cd, + 0xfcb6e67f, 0x4a9e4c65, 0xc1676178, 0x3ba7c22a, 0xa1737f1e, 0xa7f4ee52, 0xfad03425, 0x1e1ba0c1, + 0x480238d3, 0x6dc2559d, 0x33003291, 0x2ed8e47d, 0x98e09ebd, 0x6c22f773, 0x9f89d747, 0xa3639bfb, + 0xcec61043, 0x4501ee20, 0xcc0361da, 0x1fd175f3, 0xe1252d5f, 0x3666c791, 0x7866e40c, 0x635e475f, + 0x5e80cd61, 0x629b8dff, 0x31525dd8, 0x86ad2168, 0x5c1ad502, 0xf24c7c1c, 0x0d88311a, 0xb68d4b18, + 0xb26bc963, 0x4386c88d, 0x7ddbdab7, 0x406e1b2b, 0xe6d62490, 0x25b77340, 0xc39ef450, 0x693c556b, + 0xc83ea1f1, 0x1e962da6, 0x8e3b5caa, 0x76518cc5, 0x980b0c18, 0x66d9a09e, 0x575acd53, 0xe701cca3, + 0xec2d9d2d, 0x6a64c9bb, 0x86aa4e9a, 0x7bbcc74f, 0x487ba026, 0x1d81e93b, 0xaad8288a, 0x79d76f1b, + 0x75015559, 0xe4a1befb, 0x17b0621c, 0x76550855, 0xc50e0d75, 0x3947e7fb, 0x8fe63422, 0x14c4cf78, + 0x61e8f824, 0x7e61f685, 0xb02a1bba, 0x7d76c00a, 0x3ab2adb3, 0xb3eb3191, 0x480746e1, 0xc1078145, + 0x8d2df6e1, 0x631897a7, 0xbd3d83ed, 0x6ff8ee9d, 0x7abc06d4, 0x96a89a09, 0x06b41c1c, 0xb015650f, + 0xf6f721e0, 0xadf69827, 0xc74075bb, 0x7fb1c111, 0xb6a98f57, 0xba6f9d7e, 0x9199ec5f, 0x9f92f2c6, + 0x08e59443, 0x31688656, 0xa9f37c01, 0xb51c22f1, 0x5f5de2c7, 0x3ea63c9c, 0xdbb94d12, 0x2ae1a3d6, + 0x3317cf21, 0x22a4b1f7, 0xe377be6c, 0x1e98dcf8, 0x194f8629, 0xe65fc0c8, 0xbd0706db, 0xde7b56a5, + 0x150d4dfa, 0x50cd7fb9, 0xe77901c2, 0x370991ee, 0xc23b4b5d, 0xe824d7ca, 0x98be4542, 0xca1f04cd, + 0x8c995b61, 0xd97d7835, 0x839189e1, 0xf41ff215, 0x99d59583, 0x0467a3d1, 0xaf3da310, 0xebcefed2, + 0xd91aad9f, 0xe3ebb282, 0xc96107ef, 0xc10e8560, 0xe5b1da72, 0xdc889da8, 0xd35f3e0f, 0x10b418cc, + 0x74072ec3, 0x182ed8e2, 0xda8e5d22, 0x41df4b2b, 0x55e4d003, 0x3c17a1ee, 0xf63b1d86, 0x3f26b25b, + 0x2b28410d, 0xe0f0964a, 0x911e5793, 0x63575b93, 0x19bea982, 0x9e16c752, 0xd10fc179, 0xe6e88147, + 0x4c89e52a, 0xb1347f2d, 0xe49f34b5, 0x7fa38361, 0x744c296a, 0xf852c9d1, 0xe6c4d356, 0x3c29c5c4, + 0x7601f875, 0x3e1ebb69, 0xc0fee643, 0x15a1926a, 0x9b63a2a3, 0x46e195d6, 0x6d0b0512, 0x29920dcb, + 0x6df2b2bc, 0x3d1061bc, 0x62094121, 0xfca8d7cf, 0xac390727, 0x3c93c05d, 0xbf43f045, 0xe51b3fc5, + 0xf2e1bcf3, 0x2ffaea1e, 0xdaed23c6, 0x495f3b3c, 0x405f3d14, 0xb285fe39, 0xd616f4a4, 0xb833b433, + 0xbd534840, 0xf2448b03, 0xacdfd86f, 0x5e6a31c0, 0xce20fecc, 0x5727d8e6, 0x0f8f4635, 0x396e0f23, + 0x6bac9e11, 0xeb9ccf32, 0xf95e2efe, 0xeb14627b, 0x0d88976f, 0x45223166, 0x61e00cf6, 0x79b8b642, + 0xf27625e6, 0x2cae88a9, 0xbcb419d7, 0x866cc9e6, 0x26e50256, 0xa2c9209f, 0x62fe1630, 0xd27d054e, + 0xa19839da, 0x719db85e, 0x4e98b8d7, 0x078c9de3, 0xc054f8a4, 0xf150b4eb, 0x22d576d8, 0x85df5fe3, + 0xb1ef03f3, 0x7562cfdd, 0xc81df021, 0x40accab6, 0xf5e61c86, 0x1a001555, 0x5d6cbd57, 0x1c8bf550, + 0x114af6b4, 0x3795e3f9, 0xd3a4456b, 0xc39644a5, 0xb4ae0db0, 0x9161d36b, 0x52258466, 0x6ac3188b, + 0x1da4cddd, 0x31839ca2, 0xce6e8b94, 0x92a72e00, 0x54def847, 0xbcf6ac82, 0xa32f70a1, 0xfd74eb6f, + 0xdbb9752a, 0xa660ad9d, 0xfef233aa, 0x301c13ea, 0x9bb28f15, 0x680bcb87, 0x1e679bb6, 0xcbcf26b6, + 0x4403b451, 0x2f6bb5ba, 0x9ed6eb50, 0x6c87fc8d, 0x826cf742, 0x61454725, 0x594d2512, 0x9f8d4382, + 0x1dd55c84, 0x1c1b9927, 0xf4c5c57c, 0x80e8445d, 0x6d057528, 0x16b871e3, 0xac502aa3, 0x95501c18, + 0x47d4207d, 0x9335542c, 0xe584864f, 0x909a94ce, 0xceaf718f, 0xa70f9cb2, 0x21d79c89, 0xc85aadb5, + 0x8db28791, 0x7b1c87ac, 0x157a0d58, 0x1473e076, 0x82a89ba1, 0xdb752771, 0xb342ee62, 0x58ef1dc1, + 0x1161bc03, 0x11903c16, 0xea5d250b, 0x485e5db2, 0x457237cd, 0x31ea6d29, 0x49484121, 0x7f718fc4, + 0x8d784c12, 0x2737b2f1, 0xb18e8a22, 0x856a6cc2, 0x0f70d317, 0x1c401646, 0x2b0491a9, 0x7cf9cb4c, + 0x3273d49d, 0x1eb93088, 0x24b21385, 0x4e70d153, 0x006c4029, 0xdb2cada3, 0x42bea7b7, 0x5a4fa14f, + 0x07c79aa1, 0x4baf20ce, 0xce48f1f3, 0xce746aa0, 0xd7dec518, 0x75585595, 0xe4c22f1e, 0x2dc38d42, + 0xeb32807f, 0x650fec55, 0x5a6f9ba7, 0x0e08b886, 0x6879b6d2, 0x61c222b0, 0x238e9aa8, 0xd13be8c2, + 0x2aaf708f, 0x60917736, 0x86a9bff2, 0x6ce01295, 0x91fb5421, 0x08b33295, 0x8695c546, 0xb072546a, + 0x812538d6, 0x9787ac84, 0xdd18787a, 0xa1cc937d, 0xff877770, 0x194474b2, 0xab54fd00, 0x980b96f1, + 0xeb444435, 0x04f522d9, 0x6bb6bec1, 0x37f96313, 0x9ae8a825, 0xfcb4aa55, 0x0d419b7a, 0x5444ba32, + 0xc6cbbae7, 0x5a93e91c, 0xae758b39, 0x8264dcdd, 0x325a4e77, 0x1662b200, 0x8aff1c5d, 0x5efa7894, + 0x3f5d6ec8, 0xd138d7f3, 0x8a9f2451, 0x61caebc9, 0x6d3d549e, 0x6f80910c, 0x8c4674c7, 0x3936e8f9, + 0xe735e726, 0x5e7f381d, 0x1fe447de, 0x4b93c6eb, 0xd18951cf, 0x1f4e81ce, 0xc4e4326a, 0x37f120d2, + 0xd4fbbdab, 0xa3377f42, 0xcc29039b, 0x7bacef94, 0xc08036db, 0xe2b463da, 0x0235da19, 0xceaceec7, + 0x733105b8, 0x85ece903, 0x3ab73c8e, 0x87300a83, 0x98706087, 0x7b43ae89, 0xb83a5753, 0xaeaedec8, + 0x2de69059, 0x8a698a78, 0xe8da76d4, 0x071e1640, 0xb06470f5, 0x74959627, 0xa0f4fc71, 0xf7b2f4ea, + 0x7c6cb25b, 0xc1c2a105, 0x2f533940, 0xafd030bb, 0x3cc2eb66, 0xa2f8c023, 0xdac95c03, 0x3fe2839a, + 0xe23916fc, 0xd94edff2, 0x5f525d55, 0xbc6391cb, 0xfbd5b1d0, 0x32a22ab7, 0x3d8c3bc0, 0x4a961324, + 0x47177af8, 0xe74e3c42, 0xde37be46, 0x9cd77f45, 0x9f641c78, 0x9bcc138d, 0xc47f5d85, 0x5667dc47, + 0x0210c9b2, 0xd5ff06e7, 0x0b2f1a68, 0x1f76167b, 0x56b770c7, 0xcb7f7b3a, 0x7ddd21b3, 0x982845e6, + 0xa86adb8d, 0x312564de, 0xd1b3c67a, 0xc061759d, 0x2f956c32, 0x93c2e834, 0xb17929da, 0x9830bdda, + 0x9a3b368c, 0xdf3fcfa4, 0xebf381c6, 0x2c10aecb, 0x62c14053, 0x202622a4, 0x9606f7b8, 0x318798e5, + 0xab297952, 0x50705520, 0x6577f513, 0xf8fb0a12, 0x8f15c7b1, 0xcbee306f, 0xdf96f107, 0x9259821b, + 0x3b26b28f, 0x82208e44, 0xa136db95, 0x98c18740, 0x22cabd1e, 0xf99c10fe, 0x86db2a54, 0x2a4f83bf, + 0xd3675566, 0x1d021058, 0xf780f0ff, 0x70af3f07, 0x3c6f1140, 0x7a5cedf8, 0xcafe259c, 0xddbd7441, + 0x555565b7, 0x97ec4386, 0xc7af6155, 0x27b3306d, 0x60e4d967, 0xfd5a2424, 0xd570196e, 0x26b9eb5b, + 0x4f466700, 0x2ac4709a, 0xc64f4dd5, 0x90b747e1, 0x20e64425, 0x11e0e4c2, 0xe3f7e89d, 0x9b955998, + 0xecb1dd01, 0xbb5cb6fb, 0x4bdc0ba9, 0xca20b11d, 0x22a474f9, 0x55d727a9, 0x77537ae1, 0xad564b87, + 0xe6871b8f, 0x0c9796e0, 0x8a118464, 0xa82a5cbf, 0xf4953bd2, 0x490e1df1, 0x460ef456, 0x319ecffb, + 0x88b5b401, 0x8d890532, 0xdd301d06, 0xcb8382f0, 0x0d6e7996, 0x0d0759ab, 0x37eb20b1, 0xe038af62, + 0x48b7aea4, 0x788fd72b, 0xa90aa60e, 0xab90ea77, 0x9e10e83a, 0xf2645ff2, 0x2f38c311, 0x73148081, + 0xc2f55b32, 0x78b51d61, 0xff180cd8, 0xc42667d7, 0xff82f74f, 0xf8d149b8, 0xe13160f4, 0x5d8e8a53, + 0x33d74b53, 0x462d9b54, 0x349f8f38, 0xd60d9758, 0x324341a7, 0x960a97a9, 0xc7c18ab8, 0x1fec9862, + 0x7f1c5fc0, 0xc0870f37, 0x9326e6c1, 0xb4733c44, 0x92404316, 0x697a0ef2, 0xaa5e3dc4, 0x1cfa92f3, + 0xbe87f926, 0x6ab898ac, 0x130f0132, 0xf1294363, 0xb5a52ebc, 0xd3f8470b, 0xf3eb5d0b, 0x79304847, + 0xb487e821, 0xf4f56528, 0xb35b7f94, 0x0c750b73, 0x289a2bd3, 0x190912e0, 0xd4e4b06f, 0xb68c9d67, + 0x65b23c68, 0x634e95b0, 0xd1ee1043, 0x881fe28e, 0xaede9b05, 0x4a638405, 0x127d2cf1, 0xcb5c99e1, + 0x37ec0579, 0x50228101, 0xb1c8006f, 0x35aea92c, 0x6a29abec, 0xef49ebf3, 0x0de3cd43, 0xd04fdbc8, + 0x2e1ff219, 0x641bc484, 0xc0801941, 0x818801b3, 0xdfcfaad3, 0xc70bfc1d, 0x39d30fb3, 0x67670cd7, + 0x540dd07f, 0x2e5182b1, 0x8b2ffda1, 0xabea2eae, 0x2633fa07, 0xb120b060, 0x045dce24, 0xacf98101, + 0x50ceebd9, 0x91672c47, 0xd1072cbe, 0x3bb4be2b, 0xf27bc857, 0xd5dc0d41, 0x098b713b, 0xfc679513, + 0x0d388bd2, 0xd762ecb9, 0xf142676d, 0x0278f8fe, 0xdad6ffa8, 0xbdb57cf7, 0xe68f7c7e, 0xc6f0b75d, + 0xcbee1425, 0x8ef2706b, 0x6139f79e, 0x17d7415d, 0xc8f2b738, 0x4023f573, 0x6638bcde, 0x8297d1a4, + 0xfc98269c, 0xd431a340, 0xf3f12232, 0x2978e872, 0xf12de076, 0xb16021b1, 0x0bb6d1b4, 0x9e6479e3, + 0x3e76e9ee, 0xfc9954cb, 0xbba5894f, 0x0f616aac, 0x680f16ab, 0x4df6f85d, 0xaa22390b, 0xb49f3001, + 0xee0c9973, 0xd5732652, 0xbfab5d30, 0xb07a144c, 0xc4da2aab, 0x47f2c3e2, 0xde4a470e, 0x097fb42a, + 0x134865aa, 0x0e499690, 0xdc0a7841, 0x7ffe0f79, 0xcace4193, 0xdbf596b5, 0x41f016f0, 0x829c6df4, + 0x4152bdae, 0x5bbeb812, 0xd6ce8dfd, 0x5b76f537, 0xc0b73196, 0xf82ff1e3, 0x419c6c39, 0x06f186c8, + 0x60a9e1f4, 0xae826581, 0x5178dc19, 0xf780110f, 0x1d485eb8, 0x3351b25a, 0xd38937b6, 0x4f075a9a, + 0xdf046604, 0xd74e9659, 0xe5edd27e, 0x2db4a59d, 0xe96187f7, 0xb6ec8793, 0xadb49256, 0xd6f83346, + 0x8f59237a, 0x037d9267, 0xfe88e139, 0x5e5a4950, 0xab84cc52, 0x865feaeb, 0x53e12773, 0x8a1ff409, + 0xc9afc89f, 0xf3b0427a, 0x27874f07, 0xba1c3e6a, 0x0f85607f, 0x9cfb17f8, 0xe52e6086, 0xd0f796e5, + 0x7b91ae43, 0x11b8fd3f, 0x79c56b21, 0x38d6b5dc, 0x64c7cb6d, 0xaa5c201a, 0x2fcda68d, 0x1ae87f98, + 0x47ba3e07, 0xbabc0a22, 0xd9dc67e1, 0x3d30a4dd, 0x15a7aad0, 0xb84731cf, 0xef01c533, 0xea652842, + 0x1329b493, 0x0c6a3a79, 0xf65ce10d, 0x5b455c77, 0x668dd1f9, 0xc1cd735f, 0x6f0cc6e0, 0xa32c1b1e, + 0xfe547d24, 0xbfddf62b, 0x08d73db0, 0xe57bdc57, 0xab51110f, 0xa2f5c571, 0x8f554db5, 0xb661086d, + 0x88991e5d, 0x4e5796bb, 0x73c58019, 0xc1da0459, 0x8957073e, 0x867f8261, 0xfc3264cc, 0x4b841483, + 0x1e5087da, 0xc4314b8e, 0xdf3a5577, 0x1a9aaf28, 0xacb85737, 0x5e9c9e79, 0x2a55a586, 0x5486bf92, + 0x911032f8, 0x9c237884, 0x9c45a7ed, 0xe18d33b4, 0x510df8c0, 0x7f2c86d4, 0xdf662c57, 0x93e73627, + 0x224388ef, 0x10c2929c, 0x80a87384, 0x7f091655, 0x497793a4, 0xc23864b8, 0x77256c3e, 0xc43ee1ff, + 0x75563ecc, 0x0ddb9a3b, 0xcb84cc22, 0x42016047, 0x102c0085, 0x80958e99, 0x1da2ce8a, 0xf8b26d60, + 0x184637c2, 0x6313e88b, 0xec51792a, 0x6d078645, 0x65381e9a, 0xc6c67b57, 0xcae78db7, 0x6c56fbb6, + 0xfb154038, 0xa3f42182, 0x61b4e6f9, 0x8f171f4b, 0x0e364ba8, 0xd8f35867, 0xe246dfdc, 0xef3cdd8e, + 0x03ba23ea, 0xa64ceda9, 0x4a01b90b, 0xd9887768, 0xb29b4434, 0x9d1096b7, 0x2ee75757, 0x5393744e, + 0x39fe2830, 0x130eb093, 0x6ee93623, 0x3d5de04f, 0x8c21cbfd, 0xe8566b2e, 0x93bbe755, 0x6de1c661, + 0xdc844f01, 0xe13ed456, 0x09bafdea, 0x646749b0, 0x3cf07990, 0x100a898c, 0xa23adb1c, 0x7fdf5415, + 0xc3566018, 0x09830763, 0x85dace50, 0x7dbb8bed, 0x742b08cf, 0xb00e34d9, 0xdc238c9e, 0xae24691f, + 0x12c7b8e3, 0x0948604a, 0x39940e5e, 0x7db384cf, 0x928a6f58, 0xf9f8d100, 0xda8a2cf5, 0x4d2bc25f, + 0x8e528c26, 0xa926affa, 0xe5dacb0d, 0x8b07428c, 0x8ab491ee, 0xce469318, 0xde439c87, 0xed3cfc57, + 0x9ebbf195, 0xcf8e8ce4, 0x06523ec4, 0xb089bfc0, 0x3a05b138, 0xde043e1d, 0xfe79971f, 0x5a3aa826, + 0xfdc7d233, 0xdac621f4, 0x3fcea95d, 0x29333eab, 0xc092ff0d, 0xe3125db4, 0x5482f1e6, 0x2dd1a7a5, + 0xcc9fd7f4, 0x9107e3d4, 0x5483deca, 0x02fc1026, 0x7da5f934, 0x588f278a, 0xa302d263, 0xbf7eefeb, + 0xb74bcdb6, 0x39bca6ec, 0x803c39b8, 0xe08bce51, 0x2fbfb3cf, 0x3324c315, 0xd912d25a, 0x14973d9c, + 0x19e9a2bf, 0xf24e80bf, 0x9662294e, 0x1ff01306, 0xcbab7807, 0xcddd1ee8, 0x880e1cde, 0x0bd6a36d, + 0x22b61d10, 0xbaae1d85, 0x9026e9e8, 0x3851f1df, 0xedbdb05d, 0x9278d3ef, 0xed3c6d15, 0xcc9d96dc, + 0xe55b2877, 0x0807d012, 0xe15c50fa, 0xe636f803, 0xd72cdd01, 0xcf2f1beb, 0x012d5a16, 0x8601aca1, + 0xc12dec60, 0x8a1b16eb, 0xd771321e, 0x525eed0f, 0x841227b7, 0x68da2be1, 0x1d5b86c8, 0xe8f33b99, + 0x573d5636, 0x956419c3, 0x86e90ea9, 0x2c284962, 0x3a90f4f3, 0xaf547360, 0x074e64fa, 0xd511b3ba, + 0xa53568b7, 0x3f28c1e3, 0xe07112f7, 0x0d535d65, 0xc281fe18, 0x1e815f60, 0xd93ddfab, 0xe55b13ec, + 0xaeb8bde8, 0xd649a6b9, 0x0b182578, 0x15efb051, 0x8facc0a1, 0x476fe584, 0x23d43f93, 0xd5971746, + 0xdb4676cf, 0x016db207, 0x5411baf4, 0x5e18f1dd, 0x2c46333f, 0x07338a52, 0x8ba1c69d, 0x17d9540f, + 0x84dd0136, 0xaa84eaf3, 0x210092ae, 0x67fd4f12, 0x64cde364, 0x2b833676, 0xc8183c98, 0x06a2a679, + 0xbff38cf2, 0xf323499b, 0xb49a2c73, 0x99f9f511, 0x0ea0191f, 0x12fde2c3, 0x493d5dc9, 0xe18e3b0d, + 0x9783d90e, 0xa394f3a1, 0x8eb75279, 0x1144c69a, 0x38a7fc18, 0x0a37c52f, 0x3d7d16ee, 0xd7994d52, + 0x9d1bb94e, 0x33882f4e, 0x2f316a0e, 0x8ba2aa5f, 0x08f42a55, 0xcab27003, 0x8398ddde, 0x35e11ef8, + 0xabda0126, 0x49ab6b9a, 0x1e8e58e7, 0xb28dbfc0, 0xe23bb499, 0x1fe84c7a, 0xbe5ff6b2, 0xc3d7273e, + 0x59ec6e7a, 0x1daa6e6e, 0x5fdc80b9, 0x471f0d30, 0x0f6abcda, 0x3b56eb55, 0x56d7589e, 0x0094f09f, + 0xaeefb192, 0x257db36f, 0x8d21776f, 0x7e88e74d, 0xa6ec159f, 0xbe7f6f3e, 0xefdaa5a8, 0x6ec45f10, + 0x9527900f, 0x7dd19092, 0x4302d093, 0x5c5c6122, 0x945e3207, 0x0e5e0560, 0x5b9b9837, 0xd78262ff, + 0xab648675, 0xc649e3a9, 0xd1d09f08, 0x6ac7f536, 0x718b67a5, 0x3449ae43, 0x0ff597fa, 0x6b3ef065, + 0x90451a5e, 0x5edd2a6f, 0x558aff3a, 0x61cf0521, 0x97b1d957, 0xa7ba72a1, 0x36d8eaa3, 0x75dae618, + 0xc57aaae1, 0x3a1b32f7, 0xa9c0d1be, 0x2518f26b, 0x468b3abc, 0x7d017c8e, 0x2d9231b2, 0x88eb8202, + 0x55101d88, 0xf5afd3dc, 0x04364431, 0xbebae242, 0x00d3179b, 0xbdf34670, 0x0d944e4f, 0xa1424c06, + 0x051f1b24, 0x5a7f3c7b, 0x27a655e3, 0xfa182cfe, 0x62d09d7b, 0xea215b61, 0xb2294bd8, 0x4c60288a, + 0xd8d85a2f, 0x11147e1c, 0x0e004ba6, 0x9b740ebd, 0xb3e9f56b, 0xce331cc4, 0x927763c1, 0x953fbf57, + 0x93be2fc8, 0x9cc4195e, 0x736557be, 0x6993aacb, 0x4236abd6, 0x3bbf5c9d, 0xd94484de, 0x0520a7c0, + 0x353215ad, 0x5add962f, 0xd48c06d8, 0x9b4f2520, 0x677754ff, 0x45345199, 0x4dd22e63, 0xc0ae0a74, + 0xe24468b9, 0x7d3838be, 0xbfb43985, 0xf553f80c, 0xdc61e406, 0x76be970c, 0xaae7ce84, 0xd18c877a, + 0xb03bb09a, 0xa714cd33, 0xa6fb8412, 0xa9f1d916, 0x375138eb, 0xa6ac48a1, 0x89ddafb8, 0x04c14d1a, + 0x8378eef4, 0x28445155, 0x9f1c1cb4, 0xada90113, 0x12d59049, 0xdaab7215, 0x1eb9a079, 0xfa85d546, + 0x1fd6be44, 0xdd3ae889, 0x70f0d6b3, 0x42141685, 0x0278b9d0, 0x2c4dfdcd, 0xe33f4621, 0x8cfaf4af, + 0x9c44f166, 0xf0d08925, 0x484f1d4a, 0xcd798298, 0xf970cb9f, 0x7423f021, 0xa5b0c14c, 0x99ed1399, + 0x9cdf6724, 0xe6e0d724, 0x79bc52b1, 0x472bf633, 0xdf27073e, 0x08c99154, 0x07a91937, 0xddbf85e9, + 0x04a5de82, 0xd8dda6e5, 0x18b5990c, 0x8a78b78c, 0x60a54f54, 0x5c399ad9, 0x43141be5, 0x10992eb6, + 0xfaf2980d, 0xfad6d788, 0x5718c9c3, 0x47ef7e97, 0x46f1ccb0, 0x52e10c6a, 0xa0ef431c, 0x315fdf7d, + 0x91cf518c, 0xe9aa518a, 0xbc39dc8e, 0x429f27d8, 0xa3a3318a, 0xe5db5d5a, 0x5754a451, 0x14c7db1e, + 0x00d2b59e, 0xa58648ee, 0xf4bcade2, 0x18c37444, 0x3d422dab, 0xb5a55e24, 0xd71cc077, 0xeaf0a633, + 0xe532729a, 0x4f44dbf6, 0xdc028e3d, 0x21ba8af7, 0xe91a1304, 0x9a3d48e5, 0x4c5fe7b8, 0xd7e6542d, + 0xd15b53fc, 0x1296d78b, 0x6c9b81fb, 0x01850931, 0xc9578593, 0xeb6f2295, 0x4f567f4c, 0x393e768f, + 0x2b6850af, 0x099f3ee6, 0x36127429, 0x214fa5f9, 0x8210b456, 0x6c1725f9, 0xd022b5b6, 0x12f2a3e5, + 0xf59d2f9c, 0xbdd6cca5, 0x85f4690d, 0xe37a69d7, 0x1513ff55, 0x0f849541, 0x8ad26803, 0x9d09d84e, + 0x37a06924, 0xf29f33a9, 0xc3114722, 0xe7b9aef9, 0x8d91cb2a, 0xb3affcfe, 0x8f998c1e, 0x76e63b0e, + 0xf707dd8d, 0x4693c14d, 0x4cdf9ab7, 0x210d19a0, 0x3577eb41, 0x61eb2092, 0x00af2324, 0xa9c5a799, + 0x82cb447f, 0x86f399f0, 0xef4cc89c, 0x88ba616c, 0x07b9bcf7, 0xcee354b7, 0x4ff28c8a, 0x2c957b95, + 0x7cdf4d19, 0xc21bf6d1, 0xdb53fef9, 0xf1bf4fa5, 0xcfd5e882, 0x763f7d53, 0x4f1ca36f, 0xc1e56ba5, + 0xa806bab7, 0x1f82c45f, 0x3c57b4f2, 0x89d09dc5, 0x12c618f9, 0x250fa1c9, 0x00d351e7, 0x890f1100, + 0x047b06e3, 0xb86b791e, 0x60b0f63c, 0xf22eb3a8, 0x64f1dda6, 0x944c3d41, 0x1e222415, 0xddbb7f20, + 0x4d06aac5, 0xc5a283cf, 0x8d757009, 0x6cdcbb8c, 0x32f102e2, 0x36b9d990, 0xffc9d715, 0x91d6b8d2, + 0x68071cfe, 0x0f671859, 0xfd46f914, 0xd200e644, 0x445b6871, 0xa3717923, 0x86346d8a, 0xda98f5de, + 0x4a5da66a, 0xbc889f3c, 0x1e0f7b42, 0xa8eebc87, 0x01810b95, 0x19fdf485, 0xedee241e, 0xe433e088, + 0x8ab80802, 0xcacfc46a, 0x642301e0, 0x67d56f7e, 0xca3c2137, 0xec6e2f2d, 0xad6e8e40, 0x18eebd79, + 0x6f3342cd, 0xd6900dd0, 0x9852965e, 0xb11a117a, 0xab82a639, 0x41ff7e1e, 0x9aa818fc, 0x64578413, + 0x439b00fc, 0xa2b51ea8, 0x7bfb849a, 0xef5357aa, 0x07bde7c7, 0xbc3d4c56, 0x9a5b4aa6, 0xdc89593d, + 0xdaa4cfbf, 0x26fe5586, 0x4b6d4310, 0x243f4b5b, 0x5fd0a32a, 0xd9a70bd7, 0xd7554361, 0x763b0dfe, + 0x118486b0, 0xc2fbed8d, 0xb1532936, 0x9041c6e5, 0x326a6204, 0x5777958c, 0x324fd032, 0x1813fe2b, + 0x45fe1900, 0x559677af, 0x25ad8c65, 0x091872b9, 0x24dda3e1, 0x0ef5602d, 0xae8daf3c, 0x00dd4c54, + 0x246fde59, 0x397f000c, 0x8ba50083, 0x9b425d6c, 0xc2bea6dd, 0x9fd2ee1d, 0xc206ca2b, 0x10d2aef3, + 0x2e0a4fdb, 0x61004835, 0x33556a48, 0xcc9a3e32, 0x919bab08, 0x09367204, 0x3a172841, 0x81366e64, + 0x8380e507, 0x9f4a701e, 0x6d7c8ab6, 0x560c9b6d, 0xf4db65c2, 0x7bf33f71, 0xec873ce9, 0xee707e27, + 0x64b711a4, 0xe7888145, 0xc4e0fe49, 0x16911651, 0x2985e6dc, 0xc6ed4279, 0x4d4b200f, 0xf0ff5dfe, + 0xe40d1b05, 0x42b86da3, 0x4dfc0591, 0x75508436, 0x8f7b6cb6, 0x4e66488c, 0xac769d0e, 0x9f9773fc, + 0x5ac91aca, 0x863c41d4, 0xbff1e151, 0x0c0b754f, 0xa1e95ab0, 0xee58ae78, 0xcd1b41ca, 0x85e6d07b, + 0xe0d967dc, 0x2cfb90ca, 0x4cc5b73d, 0x3e3a9e3b, 0xf87ab4b6, 0xd7f28d21, 0x9b2bc731, 0x425dbadf, + 0xb0075a26, 0x742a4617, 0xe115329b, 0xdd8d3df9, 0x880b228c, 0x94fb4bed, 0xac865501, 0xc743605c, + 0xe8dc20a5, 0x55316a92, 0x1f598140, 0x61d4b617, 0x933a7d10, 0x5eb08390, 0x541db5ef, 0x95e8c138, + 0x921f4c4f, 0xb0924fba, 0xc73f15f7, 0x5ea6b966, 0x47f3e02a, 0xda495d0d, 0xd4f063cb, 0x6a926c09, + 0x4cf19900, 0xcb3273ca, 0x79bde263, 0x2c6c55f5, 0xd8dd55be, 0xde49d737, 0x06161357, 0x03f5c0df, + 0x77097016, 0x56598431, 0x1d6f0266, 0x1732745b, 0x6478f27e, 0xec158844, 0xc35ee025, 0xfeef21e2, + 0xb9382089, 0xfa37e458, 0x681f0c69, 0x0a3bf684, 0xa8a33150, 0x023c4b5c, 0x0dedd906, 0xd517730e, + 0x261df267, 0x15831471, 0x119c09fe, 0x18004d51, 0xed43469c, 0x42a6ebe3, 0x4757b0cd, 0x9090ebde, + 0xbf8c7384, 0xdb799cbb, 0x11577b62, 0xd8ca301e, 0xc266f0d3, 0xf4e1445c, 0xc5fbc988, 0x8d6f629d, + 0x9d9235bc, 0xd6688438, 0x9d1dddf8, 0x689c33ee, 0x38cd72e8, 0x844abaf9, 0x3ebcd508, 0x8d86b26d, + 0x6cacb2eb, 0xcd327381, 0x88627cf3, 0x6806b018, 0x257be97e, 0xc9b4e3c4, 0xd0b84640, 0x8c5ccbd2, + 0x5bbc2945, 0xd5b59788, 0x7e55023d, 0x970bafc9, 0x2305ae98, 0xb646b0fc, 0xe8fa62ef, 0xe5da77e7, + 0x01dedd5f, 0x84a20955, 0x7fc3ee94, 0xf9403830, 0x63e5f4e1, 0x9e06391a, 0xba4c3b92, 0xa79d4daa, + 0x39220069, 0x3b4a9fc7, 0x31208c03, 0xad0b3bad, 0x71e3f353, 0x6f242a9c, 0x61cbb083, 0xb12f3ed6, + 0xfd7fee58, 0xf6cdc91e, 0xe90f3f9a, 0x9a22b153, 0x3f705f79, 0x7e1d2165, 0xc7ea3be2, 0xc6eb47c8, + 0x199eaeb2, 0x67cac249, 0x7ca3f274, 0xe448da05, 0x5d637172, 0xa94bc2cb, 0xaadb15fb, 0xe19d8401, + 0x57afc046, 0xe5dea221, 0x9dbb7b3b, 0x2e39dd91, 0x7bdb8394, 0x92a9a229, 0xccb9686d, 0x2e196371, + 0xf405844a, 0x3dedf4ff, 0x90033a47, 0x3ec211f5, 0xfd9a178a, 0xdffb3981, 0xbd168ecf, 0x111fbe78, + 0x69587270, 0xb01a3348, 0x95178fde, 0x5f045277, 0x50e5c97c, 0xeb60309b, 0x2a5d359c, 0x057c3c10, + 0x1b3c32e4, 0x167afbe2, 0x7aa5428f, 0x3e731e10, 0x8b72a9e4, 0x627a7927, 0x3375ef9c, 0xea6f4ecb, + 0x2c02b2c0, 0x3e910fac, 0xe0958282, 0xa555286a, 0x30c41c16, 0xc8b8266f, 0xd4ac6c71, 0x3fe0730f, + 0x4ec71841, 0x8d6877b5, 0x8d17a39c, 0x80a04a17, 0x6884db68, 0x4613c594, 0xffcbaae4, 0x34ef828d, + 0xaf66c036, 0x02e11cff, 0x1956e1cb, 0xfd14c480, 0x1021b715, 0x2cd0b342, 0x4ca08c1e, 0xc43fbb31, + 0x7d192196, 0x224edda6, 0x3423e380, 0xdc9ef212, 0x185ba806, 0x3e7daad2, 0x65781dba, 0xb5f17b6d, + 0xe155e6d8, 0x05937cf1, 0x311d9e60, 0x3e0fc182, 0xc94b09e7, 0x5fdd2cf6, 0x90af1587, 0x1f24f3f7, + 0x828eafb1, 0x8d05ed6b, 0x5399adc8, 0xa66444f6, 0x26926e61, 0xe2573260, 0xebde3e2b, 0x72960040, + 0x48340748, 0xc523d1e1, 0xc14708f5, 0x611c939a, 0xd565403a, 0xfa19aa43, 0xea09a850, 0x4ba77112, + 0xc2170ef2, 0x245e1b0d, 0x4c88d2b5, 0x1a9b5467, 0xb2132a3e, 0xa41d8085, 0x1cf0fdd2, 0xe2a493e2, + 0x5e1c480b, 0x06b35ee3, 0x05c77887, 0x2b5c5f04, 0x9fbf44fd, 0x63a3d25f, 0x6f1f7221, 0x5ee162cb, + 0x490e0d8a, 0x1091697e, 0xee3c8a18, 0x35c30a44, 0x2c822292, 0x17da9f23, 0x7268d301, 0x3508f84d, + 0x9d5f6c56, 0x2a644aa2, 0x70534375, 0xa2d509ba, 0x2ee829ec, 0x4e8f36e7, 0xedd8e101, 0xfbc75a1b, + 0x3c526f98, 0x479ef580, 0xe5edbc06, 0x73e43176, 0xff776605, 0x4485eb45, 0x78410623, 0x0e73d91a, + 0x3e200df1, 0x99f766ab, 0xaf582658, 0x6e77e7ec, 0xc0c69b1c, 0x9ec4996b, 0x942b584e, 0x7b4caa0b, + 0xacd47213, 0x8f953931, 0xdba9235c, 0xf883f9e7, 0xb91ccabb, 0xb579f0ae, 0x34a0ea28, 0xac01d39f, + 0xfc47e71e, 0xffb654f1, 0xc67381c2, 0xabe11357, 0x41275435, 0xce153ba9, 0xaa906e92, 0x7452f120, + 0xeee0f651, 0x417e4c8b, 0x0966579f, 0xc4224b97, 0xa7826c3a, 0x853a23de, 0xf4e9dde1, 0xaccb1721, + 0x6e0e16d6, 0xa0b9cca6, 0xc48d9e67, 0x1e4fd503, 0x92160356, 0xcdbae74c, 0xf31a333f, 0x5a9bda7b, + 0x052ffee4, 0xf4a18351, 0x61119964, 0xd3843e30, 0xf6f36c9d, 0x791f324e, 0x7e49ff28, 0x72502d99, + 0xdb910fa1, 0x6e725281, 0xafdf1900, 0x4773602a, 0x2cfcc98e, 0xb1944412, 0xc64a521a, 0x16ae44ca, + 0xb8b0cbfe, 0x56948d74, 0x79f65479, 0x2780eacb, 0xe4b15acc, 0x1e63c586, 0x48d6221b, 0x6c122f27, + 0xd7820a2d, 0x7753e620, 0xfdc1a6f9, 0xc9bfc13c, 0xeae02bd8, 0xb7f50af3, 0xe4261df0, 0xa2dd8d6d, + 0xc5a55b90, 0xf60c3b9d, 0x339f6018, 0x4bf919c2, 0x00ebde17, 0x30ea6673, 0x68f7d0b4, 0xc67b2550, + 0x7a478f82, 0x3ca503b6, 0x10844c8a, 0x26333ef4, 0x3c6f704d, 0xd15cb29f, 0x4b156f8c, 0x5b495b83, + 0xd99d12d2, 0x7a1fb410, 0xa47fc8dc, 0xe48d7096, 0xa338999d, 0xc1a23b85, 0xc09fa2a1, 0xb62130f9, + 0xbe8c5c15, 0x8a005c07, 0x5f63b5ac, 0x44cec651, 0x910c53aa, 0x3c75759f, 0x68ea25b4, 0xd9af1100, + 0x48419bf3, 0xa8979ceb, 0x6e1832e1, 0x104de665, 0x758a5504, 0x25ab0b2a, 0x45e2bf8a, 0x035014cf, + 0x3b60f840, 0x63456ccd, 0x1377f045, 0xf986e022, 0x9c234434, 0x2432a34b, 0xba89d4a4, 0x861579a8, + 0x79f309a4, 0x6481a300, 0x219ba839, 0x40d836c2, 0xb63ee94d, 0x87bb7491, 0x653acaf9, 0xff31367a, + 0x564c3c66, 0xdb123658, 0xf1288144, 0xfdcc614b, 0x2d514234, 0xb9b6ecff, 0xb9a9ce78, 0x8250e2a1, + 0x35d7725d, 0x3f2d4d98, 0x2210927b, 0xe0a5e4f8, 0x33361958, 0xcbe1bc10, 0x9db695a5, 0x27dc5708, + 0xbbead6c3, 0x08900e4e, 0x12abc81c, 0x05977bd3, 0x2c840573, 0x47970e96, 0xcae00527, 0x1516f3db, + 0xc2942740, 0x9f755ab4, 0xde7f7f4b, 0x789e1975, 0x8b5f1c8f, 0x214913af, 0x3c12d87e, 0xe0f66573, + 0xc49b5ea7, 0xa3c29360, 0xea284bd9, 0x2d6fc47a, 0x33ae97a4, 0x37aa05c0, 0x0450f5ca, 0xaaf64f9a, + 0x4ffc6fc1, 0x6b8c3138, 0xf9e8dc8a, 0x9afe2573, 0xd1965644, 0x1f6f1e56, 0x8ef42190, 0x8a4665fc, + 0x13e71035, 0xe519d73b, 0x76c943d7, 0x71cc143e, 0x6e58d2da, 0xe6254d86, 0x56d937eb, 0xba373356, + 0xef903858, 0xa6afd9b8, 0x7aad337b, 0x01da2982, 0xe0987bfe, 0xe65402a3, 0xeea5c357, 0x10719e7c, + 0x431f80d6, 0x95fb980f, 0xd4df2353, 0x30e245f9, 0xc628b239, 0x35961c97, 0x4d095b4c, 0x78086aca, + 0x57c05fcb, 0x24b8f82a, 0xa9733b02, 0x212a0bb0, 0x7b788913, 0xdc4e0d63, 0xe33f5de8, 0xd6329f8b, + 0x070f8bac, 0xc5f2282a, 0x2257c306, 0x33d41d01, 0x14ee48a1, 0x205a7d5f, 0x6c1c34e8, 0x3ab4ccf3, + 0x480a403c, 0x9c5a5145, 0xa69013ac, 0xb5f9041d, 0xde8a6597, 0xe1e492d4, 0x30d71887, 0xe05b48e4, + 0xe65eb443, 0x243fcbd2, 0x2cb052cf, 0xfd745e1e, 0xd823e1b7, 0x62ad7123, 0xf1b5bcf7, 0x33435981, + 0x7283f133, 0xf1cb1fd4, 0xe25ea7bb, 0xf5e7c9b1, 0x607f3aef, 0x33caa035, 0x241e73e5, 0x299f81cb, + 0xd257909a, 0xcf89a258, 0xf4c760ab, 0x0352597f, 0x1793e020, 0x3b648254, 0x16906255, 0x38d9cdfb, + 0x25e94ea3, 0x190d9110, 0x1a5b44fb, 0x405825ef, 0xd559974a, 0x064c7706, 0x549d9cee, 0x94e5db21, + 0x961134bc, 0x0946464b, 0x19914e7c, 0xbc0f1aa9, 0x680e2c0e, 0xe324719a, 0x4d87fe38, 0x4ede74c7, + 0x31061f98, 0xd40a36bc, 0x1b6ecae4, 0x421e69ea, 0xe5cc69dc, 0xda4fdfae, 0x66e2c0ec, 0xe10d7a20, + 0xbd2e9495, 0xd31b4e0a, 0x1e617a7c, 0x1da02c4e, 0xc5de4ad6, 0xd8d5b7ef, 0x52c04635, 0xf5d28e6b, + 0x048074fe, 0xceb13809, 0x2cd6b5e8, 0xa8ec2fb6, 0xa3302db3, 0xd5ed753b, 0xc618ffe5, 0xafb014b9, + 0x7598ae13, 0xe58c96af, 0x2c75f4ca, 0x3a785d17, 0x8c8f082e, 0x4691344f, 0x01b377ab, 0x4c75f4ca, + 0xe8550d12, 0x3a6fd4a6, 0x3a3ede4b, 0x346da1fb, 0x81f7cf96, 0xec628ac7, 0x07d8b9c4, 0xbde393e1, + 0x8d36c8a0, 0x831db0cc, 0xc4bca32f, 0x558a48e0, 0x8efe2553, 0x0038d156, 0xf1607f8e, 0x8eecefee, + 0xb1888522, 0x50751932, 0x5e0deb0e, 0x0b9270b8, 0x3e019797, 0x618e73bf, 0x26e50523, 0x5ab09b20, + 0x241031da, 0x46877916, 0x083fb894, 0xed194590, 0x5101e29b, 0x4dc08d32, 0xd6702a52, 0x153f3b4d, + 0xd2e96914, 0xb7617515, 0x1b196e20, 0x302e7d07, 0x19e420af, 0x32402210, 0xc9587dbf, 0x881573a3, + 0x837ee7e5, 0xe8722c43, 0xd9e56bb2, 0xd14623d4, 0x443a7295, 0x975732f0, 0x37575ea2, 0x2d528d29, + 0x150209eb, 0xef7fda67, 0x3495accf, 0x66633fa9, 0x54093bce, 0x6eecc05a, 0x5f03708b, 0xd4a3e430, + 0x225bfdf0, 0x75cafba3, 0xc1cfcfc0, 0xc9db150b, 0x407d9fa9, 0xebc3ecdd, 0xdffc8317, 0x16b489c0, + 0x2b71cd9e, 0x18385caa, 0x88e04d4a, 0x89097873, 0x4432abe2, 0x3563b821, 0x550fab68, 0x48ff9cbb, + 0x8a8d1f7b, 0x835624f6, 0xa8f196d6, 0xb041681b, 0x07df24e5, 0x69a09e0a, 0xfc1d30b7, 0xb632863a, + 0x0993292c, 0x8998822b, 0x7105ce85, 0x9815b9b4, 0xbb4a030d, 0xa7fa2eda, 0x33b20840, 0x25f53b95, + 0x004732bc, 0x11c9a5c6, 0x66a2aca6, 0x16aabffe, 0x888f64cc, 0x46d534df, 0xd073019c, 0xa54675a2, + 0x3f69bfed, 0x24aca970, 0x646951fe, 0x1b935d5c, 0xa027c052, 0x6cfba72c, 0x2c98b42f, 0x4316d856, + 0x96f42152, 0x9a0ccfb4, 0x067364d0, 0x9577c90c, 0xc0f3f8a3, 0xc85b70d9, 0x64e4ed7b, 0x3d456afc, + 0x2a3badd3, 0xe4652ca7, 0x5a235b44, 0x57214908, 0x3841e9fb, 0x1cceb139, 0x5a1ed443, 0xc1165a07, + 0xecde9d8e, 0xb8fb997a, 0x8286bb9d, 0x9e2a0939, 0x8472a1f3, 0x752a381b, 0x9ff25aee, 0xa3f332bb, + 0x18521817, 0x497df60d, 0x102a6986, 0x9171c3b7, 0x8a86019f, 0x28a69ba3, 0xc496797b, 0x7960ff49, + 0x264bb1a8, 0x9d0e6574, 0x12dadacf, 0x53f8d6c0, 0x2f85a848, 0x4ab2d7a8, 0xe3ede56a, 0xced022ac, + 0xc4429716, 0xedbe65e6, 0x8f1b804e, 0x124570b8, 0xe8672f5e, 0x634068f7, 0x4d904994, 0x195302d8, + 0xa0291251, 0x853f6e61, 0xbac37ae1, 0x1b500bb5, 0x76a5897e, 0x9da071ee, 0x4a040005, 0xcdf681d4, + 0xa2a587c4, 0x0b9a5a09, 0x7e689ee8, 0xa82e15c0, 0xa945ec3e, 0x5ecff26a, 0x57353ade, 0xaff58907, + 0x8dd2b86e, 0xf933c538, 0x7e71996c, 0xb55658c5, 0x3d5f2c0c, 0x6ac53e4b, 0xf52d3ba2, 0x1e657891, + 0xa5ad7cb0, 0x82277e54, 0xf2b4814f, 0xc8075e3d, 0x7ee94432, 0xe973269d, 0xd5c38379, 0x480c6da0, + 0xb4688153, 0xa9317f26, 0x35ee81cf, 0xa461b299, 0xabf150bd, 0x9deaaf11, 0xa1f2f76b, 0x968d9624, + 0x7c16ed66, 0xed6fef97, 0xf4da49d3, 0x98b3f5d7, 0x915bb317, 0xd2cee07b, 0x0fc83776, 0xab6c7a13, + 0xbc8f3d3a, 0xd345e347, 0xa48486f6, 0xe28647e0, 0xc08c0de8, 0xd450301d, 0x9b4ee503, 0xa97ca9ba, + 0x6ceaa9ae, 0x1682d0e1, 0x591e2b74, 0x916cf5ec, 0x6a5ce801, 0x77017ca6, 0x5dd108d2, 0x36256c3a, + 0x5fe8aed4, 0x4f9eee51, 0xfc6fe0d5, 0x82a50b55, 0x7c7bfe8a, 0x2ff1d5a9, 0x961c0a3b, 0xbccf9dd8, + 0xfa8490a4, 0x2317bf63, 0x070f3ab5, 0xa042abc4, 0xe78c3a22, 0x52ba3d56, 0x8d4fbda7, 0x1d99ab7a, + 0x7afc0a35, 0x28b9350c, 0x51d141a6, 0xcfa8d5bf, 0x19bd7658, 0xc8421a2e, 0xd52f629b, 0x000a3411, + 0x75d05b37, 0xa795855b, 0x41510cd6, 0x1f40c014, 0xebea1b77, 0xa0719a9f, 0xb7f8ac90, 0x2050a942, + 0x9a788c58, 0xe59c4147, 0xd17fae72, 0xa2cade36, 0x41417be8, 0x2e7a897c, 0xd748078d, 0x9f5ff033, + 0x2ad5160b, 0xb8325581, 0x1c4ae855, 0x3fdb5e52, 0xfd3d4b55, 0xbb374a8d, 0x770a70bd, 0xd0c323fc, + 0x2659e977, 0x7a2e4462, 0x09a2da74, 0x7cec044a, 0x83cf2f71, 0x3b6b65db, 0xd46d028c, 0x6eda59cc, + 0x950fda95, 0x39977ac8, 0xce6cf805, 0xbc19713a, 0xdeba41d9, 0xc87e0ada, 0xfc010f11, 0x2c57a837, + 0xc4875009, 0x3c6afce7, 0x1e2f50fe, 0xf9dd1c1e, 0x60408002, 0x4feb748a, 0xa2226c66, 0xb74e2530, + 0x86253ef2, 0xe4f32e3b, 0x9d4eef04, 0xbfc6fe7a, 0x321dba39, 0x72efde7b, 0x9c1227a0, 0xe89c9523, + 0xdb38508d, 0x29993977, 0xb62ddb22, 0x77e5c449, 0x12a6e863, 0x7893bf56, 0x6f6cf001, 0x5b7388ed, + 0x669274ec, 0x709d50df, 0x6c4b9731, 0x78a4f40b, 0x027393de, 0xafe29341, 0x71085474, 0x89b1c4b2, + 0xd43eccff, 0x4a538780, 0x35f1427a, 0xf96a033c, 0xab0b5ca1, 0xaebb97c4, 0xba03b95f, 0x55ee3e96, + 0x3dd1737e, 0xf41ce965, 0xb078a8a6, 0x63b5810b, 0xe95652a4, 0x0ea041c3, 0xfcc9193c, 0x6e9b1cee, + 0xd0928f65, 0x6c600986, 0xc705c24b, 0x839a5f44, 0x165fb3df, 0x57146b4c, 0x85b0a574, 0x8f423fbd, + 0x6d0831f3, 0xf5cf59b2, 0x75c01a40, 0x4a617ce4, 0xb5b77010, 0x6364f4ec, 0xa824452a, 0xb1792a97, + 0x33fa91df, 0x863f8e96, 0xaded72c6, 0x9695267c, 0xccf90782, 0xcf09e197, 0x8e3869b1, 0xb549905e, + 0x1711395c, 0x6e1d0e2f, 0x98958e5a, 0x40911c24, 0x0bb0f066, 0x13927b0b, 0x1a0fb240, 0xd6f92d54, + 0x53d7804e, 0x8dbc60c1, 0x98f7b1a4, 0x07e5e6b0, 0xaf1dbe4c, 0xba68553b, 0x5293366a, 0x786bedc2, + 0x311cb7e9, 0xb6462af8, 0xdfd00181, 0x6e553901, 0x8af45841, 0x70a8475a, 0xd1b3938f, 0x96622c10, + 0x4603a087, 0x12686935, 0xab225999, 0x8d9f1e2d, 0x57d72910, 0x52cd20fa, 0x01571c69, 0xc6abbf29, + 0x074e3a9e, 0x94dc2f66, 0x1b413c21, 0x716f7712, 0xb9b233db, 0xa2d51209, 0x85da319d, 0xaa92cb9b, + 0xff02bbf0, 0xb269ff9e, 0x42bbc348, 0xeb1618e5, 0xf9ec39d0, 0xbf396ed7, 0xf4bd66be, 0x9a8bcfaa, + 0x05ca193f, 0xd2013a04, 0x19199b30, 0x201047cd, 0x7bb5fd18, 0xc738f6d6, 0x838a0588, 0xb8a7c133, + 0xfa50e965, 0xedc1b5b5, 0xe5b560c5, 0xc96696ec, 0xef91f906, 0x88815f01, 0xa41832cd, 0xc8014122, + 0xdfcdc17c, 0xd24ca5b4, 0x7e7b01ba, 0xada5c785, 0xf5c65d08, 0x0a010c71, 0x1d2a73ef, 0x2204db09, + 0xc47d2594, 0x3d4c601a, 0xc7ead538, 0xe4e8e8d8, 0xc79ca9c4, 0x574bffe0, 0xabf93c14, 0x6baf0b87, + 0x63871520, 0x9a1a23e0, 0x8061c6ee, 0xecc95e93, 0x72cb4bb3, 0xdd828222, 0x5f4ac9f3, 0xa62f6821, + 0x054a9ca2, 0xfef102da, 0x8af7a723, 0x03d4a183, 0x39da1b47, 0x04ec32df, 0x9db123d0, 0xd241f7a5, + 0x213e1433, 0x0c68758d, 0x893341dc, 0xe955406a, 0xff5676f8, 0x7d37ff30, 0xf0e6500b, 0x10caa677, + 0xf42c9627, 0x22a49eee, 0x764859a4, 0x3fa671c9, 0x394b83e1, 0x71823194, 0xbea05ec0, 0xa23512f9, + 0x7dc99f55, 0xed591476, 0x9a125377, 0x542843fb, 0x20c5f7bf, 0x0c7c44d7, 0x12fa20b8, 0xcb306d1a, + 0x8b8decd0, 0x8e7e87b3, 0x49391889, 0x7bae0247, 0x00a05aec, 0x83246358, 0x63ad52f0, 0x1608fc6e, + 0xa34820e5, 0xe4019070, 0xda24d9b5, 0x91e1b7bb, 0xa36221a6, 0x6d39c72b, 0x236d2f29, 0x7e13ca88, + 0x367e9517, 0xa672eb3b, 0xf53267c7, 0xbd3fefe0, 0xe53e97d8, 0x07f352aa, 0x4d80901d, 0x492dd6af, + 0x9ed29a73, 0xff49f2d6, 0xe5fafc36, 0x4e75786d, 0xe9fbe57b, 0xf20b4a8e, 0x3992f4c6, 0x348a4c17, + 0xa4b8c3f5, 0x70775e72, 0x6666a0a3, 0x9c4ad813, 0xbde5f638, 0xeb509458, 0x7d68db56, 0xd51b24ca, + 0x93d6eb01, 0xe813d1c0, 0x37810301, 0xb8ec3699, 0x0f2f07fc, 0x1f786de9, 0x066d1f59, 0x4f3a4fba, + 0x4b6fb00d, 0x85794d1e, 0xdd3fc9c6, 0xd865f0f4, 0x5393fc47, 0x2bbda5c8, 0x5045e671, 0xe04c426b, + 0x0ed86b7d, 0x6b509270, 0x710368d8, 0x69e9fe59, 0x1f4caaca, 0xfd33ffa6, 0x8463d492, 0xfd94875d, + 0xd130611f, 0xbfb00bee, 0xbef27a6a, 0xa5221aa0, 0x06f8df27, 0x3bfab35f, 0x314c2376, 0x951affe3, + 0xd0485d58, 0x2984ce84, 0xdfd72fd8, 0xc7097fc5, 0xb8d4b6b6, 0xeec08694, 0xce9b866f, 0x0c1418fb, + 0x43683c77, 0x2e55f51c, 0x2b9146b2, 0xaeff4ebc, 0xb4411e03, 0x221cb89c, 0x1bf64f6a, 0x5de0a981, + 0xa4f2d42b, 0xd2c6f9a9, 0x3fbd346c, 0x9fbd0274, 0xd3bb6382, 0x3ba2a9b9, 0x5e703ca0, 0x5eeb8830, + 0x78291219, 0xccc2efa3, 0x25e8ed83, 0x9a0840f4, 0xcc4fe8dd, 0x25f7bec6, 0xc0bdd524, 0xb91ee7c6, + 0xcadcd084, 0x72f378c4, 0x02dc474c, 0x8127e7a8, 0xeb930d22, 0x7c670da5, 0x1a40695d, 0xb8970665, + 0xeb767825, 0x7f4a2737, 0xd729a735, 0xdb21fd28, 0x3f52cc06, 0xe60c5a9e, 0x59dfb251, 0xdaabfc9b, + 0x7dc41896, 0x3d752d29, 0xd1ad0f02, 0x0edad926, 0x6188c8a1, 0x4f809b09, 0xc7acd439, 0xfc9f8047, + 0x00807a7c, 0x2cbace5e, 0x8ad634fd, 0x5f23f118, 0x2275f71a, 0x37fc8fcb, 0x57155119, 0x2e9b1a48, + 0x41943b26, 0x518b3746, 0x8617e6e7, 0x89388fd7, 0x3b15debf, 0x89df96ae, 0xc7af6a4f, 0xe49bde37, + 0xb9cf943e, 0x382e7c9f, 0xcef42399, 0x45fbbe68, 0xbf0249ff, 0x2e8ae5dd, 0x5f12c263, 0x97db50b9, + 0x330e682f, 0x8cb2ac02, 0x4b2746e4, 0x80858d04, 0x3c930d5b, 0xa36a380e, 0xe2b9f16e, 0x618ab426, + 0x02249b41, 0xcbd18ecd, 0xff3aa629, 0x74d1856f, 0x4420b21c, 0x47dfa9b6, 0xfd5b5772, 0xc73ff967, + 0x3334f862, 0x1480dcf1, 0xd6938291, 0x3925fdba, 0x426e8b02, 0xd671b269, 0x4c3b0a01, 0x4444257e, + 0x865fa6d5, 0x4b628d72, 0x7d628f39, 0x09c382e7, 0x6e714369, 0x1fd51a22, 0x742f1d9c, 0x447a6279, + 0x15ed76ea, 0x0a95aa8b, 0x54b3826c, 0xcaedbb1b, 0x6250a154, 0xafd1a416, 0x9110e078, 0x9d41c98a, + 0x9c7a9148, 0xc32d6c3c, 0xf22de590, 0xa1c5a21e, 0xec9a6958, 0x488c200f, 0x048cd011, 0xb49371d8, + 0x0a0566fb, 0xba1939cf, 0xc298853c, 0x3a0f7663, 0x304d0fb7, 0x4471f76e, 0x459b53e3, 0x68411f22, + 0x49070f39, 0x545b5a94, 0x3af7a99c, 0x89084c41, 0x6041f723, 0x8b52a88e, 0xeb185745, 0x7ecebdb4, + 0x61cba4f3, 0x244a8521, 0xc1c8f88a, 0xc3004d2b, 0x84795433, 0xd36f94d9, 0x68d31d22, 0x6acc0295, + 0xcca19df0, 0xfc12bcb9, 0x88c66f19, 0xcdc02b9a, 0x71a560ce, 0x599bdd3d, 0x75f6e064, 0xcac70003, + 0x4c11fee4, 0xb6c48d0c, 0x2357a8c9, 0xd6d5dd96, 0x2ba04a0c, 0xc57996d9, 0x79ccef92, 0x515868ff, + 0x8c5257a8, 0x1e974475, 0xbca63369, 0x570a947f, 0x91d9c254, 0xd5806f82, 0x6b9bc238, 0xa915dd57, + 0x756ee2ac, 0x2f43c749, 0x7de983c8, 0x6d691e2b, 0xe7f7f31c, 0xcf397e19, 0xa9557354, 0xe1390978, + 0xc3690464, 0x6244973e, 0xaf440ec6, 0x4664a17a, 0xd6008c97, 0xe2ca7758, 0x3fff6b4a, 0xff14dc31, + 0x6c2163ce, 0xabf3881c, 0x6df57d3b, 0x80d334c0, 0xf436d8f2, 0xe7d6e460, 0xea192e2f, 0xbe7af855, + 0xd4bc0abe, 0x07b79cde, 0x9ea72363, 0x0664806b, 0x1c721f64, 0x2dd4ff65, 0x66c05fb8, 0xc8fdf8f1, + 0xeab71ef3, 0xbaad1e60, 0x01583ee8, 0xc6ef63fd, 0xe8125e0a, 0xbf247a64, 0x904eea1d, 0x66c958c5, + 0x003b47a9, 0xb027a732, 0xa9d2648f, 0x26e7801e, 0xf261d20b, 0xfc376c55, 0x7fc67024, 0x1ab337d1, + 0x065e3404, 0x8d1abb37, 0xac480734, 0xa8604e78, 0xf3692cab, 0x01963bfc, 0x8e2b8ed1, 0x748dd6ae, + 0x0aadb63d, 0x0cd76f7d, 0x37afed2a, 0xf3125b98, 0xb71d07b8, 0x6e80cff4, 0xe8b9b466, 0x574d21b8, + 0x820d43f5, 0x3fdd2e00, 0x98fbac7b, 0x3d1d90c0, 0x19ac4384, 0x74152ac8, 0xbf46ea65, 0xa120dd4d, + 0x11856c6a, 0xc91c97db, 0xf1fef111, 0x723c62d7, 0x4bcdd999, 0xb1e95435, 0x2f9a5e15, 0xea928443, + 0xc5f00223, 0x3c9112a6, 0x54a21957, 0x1f1e2514, 0x864e12c2, 0xb24a9cf4, 0x7f47771a, 0x78ba4a4c, + 0x773c760c, 0x068a0c5b, 0x2f89bab9, 0x777cb51f, 0xb003fffc, 0xe4839650, 0xaddcfc19, 0x0389c6e1, + 0x6dbb1b21, 0x84ab0d23, 0x415803fb, 0xd824da7d, 0xc9f65ad7, 0xf2f10d1e, 0xce95f279, 0x764078fc, + 0xcc7bba83, 0xad04a6de, 0xbc3bdd1a, 0x9dbe8bbc, 0x79c898cf, 0x32fa2778, 0xcf82c572, 0x4caaa083, + 0xc0ef7c75, 0xbe810f26, 0x8ad739a1, 0xc0b3409d, 0xeed28db2, 0x800b92cf, 0xc334cdfd, 0xb6d354f4, + 0xf1305c75, 0x8ab6f6e9, 0xd2242ec6, 0xb537e577, 0xd02fe587, 0xe0fc56c5, 0xbfc2ab9c, 0x4cd819a9, + 0xff7bda27, 0x08e9ef14, 0x30797e64, 0xe31d3524, 0x8979b375, 0x6a371661, 0x0e53cb6d, 0xd5a2279c, + 0x5ed1f3f1, 0x9c4ff3fc, 0xdce8af4a, 0x04fb79a8, 0x6a4717e7, 0x0474ee04, 0x410efede, 0x0b2d45f2, + 0x447fdbdc, 0x4bf2c561, 0x452b37f3, 0x348741b1, 0x2cdaca38, 0x50fc2da1, 0xa681d0fa, 0xa06887a8, + 0x133f8c46, 0xf6e8af2a, 0xfe5147f4, 0x99ce2675, 0xd6897483, 0xd4c1694f, 0x6e3f5a7f, 0xffafbc12, + 0x4a1da34f, 0x727ba7e1, 0x75945c92, 0x1f50a157, 0x72f12bcf, 0x1cdbdfd9, 0x76475c5f, 0xa0491ba1, + 0xc55aad00, 0x28a35860, 0x11e195fc, 0x3fb644d7, 0x5fcf8925, 0xcd1844f7, 0xa0b17207, 0xab6420a2, + 0x8cfcfb65, 0xb687c9e7, 0x7cb7942e, 0x0c5dc405, 0x7a24e6cf, 0x88baa105, 0x65027d7a, 0x95483d23, + 0x1b4e0ba3, 0x53f778d3, 0x84be332c, 0x32eed212, 0xf5f21681, 0x8f6b16a7, 0xd594b2ea, 0xdef61783, + 0x20205dca, 0x79e56ca2, 0x78d1be6c, 0x3fc766a2, 0xe554bb37, 0x75d86900, 0x4d4a4fbb, 0x00a762df, + 0xdb245f0f, 0xb5f51ddb, 0xb38220e8, 0x3ecfdb77, 0xbc80e6bc, 0xae6bbf91, 0x5a1dd126, 0xc4d97449, + 0xa5aa112a, 0xa3db5ded, 0xd52a7f23, 0x00190917, 0x433dd6cc, 0xe44fcd49, 0xaae906e0, 0x7cf6f4b2, + 0x6718f903, 0x4c2f354a, 0x2238d9c9, 0x82714943, 0x8c8fb679, 0x016f1742, 0xa484f4a0, 0xa0c2d54a, + 0xb52476ba, 0xda427252, 0x1bbe0145, 0xdbc700f5, 0x8381721b, 0x5b0da404, 0x1fa47418, 0xd69ba562, + 0x40bd4041, 0xae7a70f5, 0x63cdc7ee, 0x9d2fc9eb, 0x463be839, 0xcb671af3, 0x499f9db1, 0x86ffb47d, + 0xa1dddc9c, 0x8d8c8d66, 0x966af3c4, 0x7abc905e, 0x6a11f4b5, 0xa268bd0c, 0x2c4540fe, 0xc9a746e9, + 0x78ae48b3, 0xb61a63a6, 0x6874eb60, 0x519fe7d4, 0x583fd619, 0x046d806a, 0x2e2f964a, 0xfc77d2b6, + 0xc5696c42, 0x544482d0, 0xaf4d7ac2, 0xb079df2d, 0x0e2ff9d6, 0x3c299021, 0x17e67c5a, 0xc9cb2cca, + 0xb0877903, 0xcfb9fd8a, 0xa5125f6e, 0x1ac8bc52, 0x03fb8a2b, 0xe8db5b72, 0x2906b0aa, 0xea1356a4, + 0xe552a577, 0xd5a826c9, 0x72437a9d, 0x40df08fc, 0x473d44e3, 0x7999c14f, 0x3e6eb61d, 0x1dd59255, + 0x153586ee, 0x8e52ef3d, 0x6b879c15, 0x68044c6c, 0x18b9a6e2, 0xa46c783d, 0xdf557db5, 0xfa1e2532, + 0xdc0901ec, 0x869b2e6d, 0x5bd465f5, 0xaebfa9fd, 0x9f2f24c3, 0x17df0220, 0x737bc7e8, 0x5bbacd0e, + 0x94abdaff, 0x264099fd, 0x71d7813e, 0x026e81f0, 0x5bf65ae7, 0x9ec7630d, 0xb5beea33, 0x033d6119, + 0xceff0c73, 0xd882f43e, 0x4af039e9, 0x36649e6e, 0x6df3da33, 0x2d309459, 0xb0ae5aa0, 0x321c28db, + 0xf752b3dc, 0x06bd2c0f, 0x325ae487, 0x399ccb8a, 0x134366d7, 0xa9846fc6, 0xb861e244, 0x845eaec3, + 0x1f474a89, 0xa7cee284, 0xf1b8bd31, 0x91d323d1, 0xe83ef38a, 0xeb55a617, 0x34f45f1d, 0x0e6cfb99, + 0xe8f6e50d, 0x17374bd4, 0x695452e1, 0x7c8da230, 0xbc782642, 0x26615c91, 0x176a055a, 0x36999734, + 0xbd652ea3, 0x434cdf04, 0x21df2698, 0x3e1d2beb, 0x76b47bbc, 0xf0539d2a, 0xea226178, 0x135acba5, + 0xe84efe7d, 0x42fc1be1, 0x246d6d62, 0x16af09c1, 0x9634d175, 0xac2a5357, 0xd5f5f238, 0x63ed9afc, + 0x2ad5bafc, 0xbc22b4ea, 0xa5906ac3, 0x3d78e717, 0xee331aab, 0x6795b011, 0xee8b1bd9, 0x14b82750, + 0x59c0af6b, 0xe93926ae, 0x368cae62, 0x36a2edf6, 0x142c5fa1, 0x1a2be46b, 0xbb62b224, 0x4468971b, + 0x33c5d731, 0xe4d1f902, 0x452c4507, 0xb6d1c02f, 0x56e8aa9b, 0xa0abe2f4, 0xe87a4190, 0x011e5dc6, + 0xa2780059, 0x8c72fa06, 0x10522619, 0xff9519d3, 0xd27f802f, 0x82154ba7, 0xcfa00dbd, 0xb9d6c36a, + 0xccc99fe5, 0x57aa8b05, 0x263bca8a, 0xc0b10ee6, 0xb9e0ae83, 0xefca3a32, 0x3255ceaa, 0x54bf5c11, + 0x6d9fe506, 0xc9961b74, 0xd458e41b, 0x244be784, 0xe0c61e2c, 0x0cae436f, 0xd5b7571d, 0x62d79efe, + 0x916e4e7c, 0xce248a3b, 0xc8901646, 0x2fa64889, 0xd3e4ab74, 0x52926ad9, 0xa3c21ec8, 0x9c373525, + 0xafc5405c, 0xd3918b71, 0x176104c1, 0x61e49cad, 0x8b1dfbfa, 0x9effafc3, 0x69145803, 0xb58fd42b, + 0x1df6c509, 0xee25ab28, 0x4a3d005a, 0x8cbb6b80, 0xe3386f59, 0x98605130, 0x3b748546, 0x6d68b1d9, + 0xe27a18f9, 0x15d90d39, 0x61cce1be, 0xe69548ed, 0x9ce29b4f, 0xc3de1c6f, 0x22eb2607, 0x4c4cdaf0, + 0x001d9b68, 0x9c044861, 0x7816e4d7, 0x0e57c738, 0x5a51d329, 0xf731d75d, 0x565f4686, 0x95ee0890, + 0x604f63f9, 0xd77587c1, 0x5caf9748, 0x64a74ce3, 0x5ae858c6, 0x35e921b6, 0x54fe8d06, 0xb5b41542, + 0x286d4013, 0x6006e319, 0xac8150d0, 0xe5c2e648, 0x4d5f4408, 0xeb19e443, 0x81178631, 0xe8c8e34d, + 0xb6c8b291, 0x85dcde1b, 0xb388b554, 0x7eb9fac6, 0xc127f3ec, 0x9a4cc33e, 0x8922ce5c, 0xe6d3d8fd, + 0x93ddef2d, 0xb594941b, 0x76e32865, 0x1ce5c9cc, 0xe159997d, 0xdc914a0b, 0xcd0c193c, 0xf99befed, + 0x50b6196f, 0xce33c424, 0x09a75641, 0xceb4acc7, 0xff57002c, 0xb0e57e1c, 0x40546b4f, 0x61a4d43b, + 0x56a918f5, 0xbc5cfed6, 0x9b5bd813, 0xcaede8c2, 0xedc5d5e6, 0x61ac8e2a, 0xe6af1916, 0x73a8cf78, + 0x6fcb57db, 0xd44d83d9, 0x6da04ead, 0xbe8a17b3, 0xa8c38ce8, 0x86af84b5, 0x890621ec, 0xdbe97ab0, + 0x396b39e4, 0xd1437f64, 0xd7e65196, 0xfc90cd4b, 0x27c5e62f, 0xe5b8e50f, 0x02a2e2af, 0xb226c34d, + 0x7107c314, 0x3a9c7bf8, 0x4a6d8092, 0xd399c9d2, 0xf5fba5eb, 0xb81b8142, 0x38fa3ff8, 0xfa76150b, + 0x7e046d1b, 0x3c241344, 0x4d365353, 0x26421605, 0x5c44cfe0, 0xaaa6919b, 0x226a2c64, 0xade3348b, + 0x3505bda5, 0x9c4a672a, 0xc3ece42f, 0xf369e025, 0x0ad24c82, 0x406a7063, 0x5a1a8aa0, 0xae0ae509, + 0xc765b2eb, 0x84ab9ca5, 0x9ea359b4, 0x18f813d8, 0x181f99c1, 0x67f22493, 0xc71a50bc, 0x209ccc31, + 0x245b6ea6, 0x74f84c08, 0x4d58c8ed, 0x6d77d484, 0x298331bd, 0xa26b7732, 0x81c3eac2, 0x7d549421, + 0x9c4b76ad, 0xe813d84b, 0xb9b58b6c, 0xe912c152, 0xc046afd4, 0x7ebebe8b, 0x3ed6bd7d, 0x6276354a, + 0xcf7b28b5, 0x4ee94fb1, 0xd15517c4, 0x6ec36b4b, 0x45e61849, 0x51405aa2, 0xc37a394d, 0x9bf970de, + 0x4a92728f, 0x726064d5, 0xef2c19f1, 0x9612ba11, 0xafc59fb2, 0x224ae7db, 0x6c646ef4, 0xef66e6da, + 0x44afca54, 0x0bbee791, 0x2f0b2967, 0x6ced4cb2, 0xa76478e2, 0x0fe20e76, 0x9acdb446, 0xb746e67e, + 0x49e54124, 0x203cd97e, 0x565ecbf3, 0x6ab44b0f, 0xe0537d37, 0xf8c39a0e, 0x863eb4ff, 0xbc413607, + 0xfcc87199, 0xc3b69ba3, 0x19c3f7d0, 0x6704fb05, 0x60d1ca86, 0x940a6fd4, 0x6087732d, 0x7806f663, + 0x08c1d2e3, 0x70278d2c, 0x65dbd740, 0xd1b141c3, 0x0a4e67d5, 0x84bb60e4, 0x94b8d544, 0x4e74dec4, + 0xf355fb55, 0x80ffc2e8, 0x797a1a54, 0x16ce0023, 0xae11d9b6, 0x8a78b0bb, 0x928184c3, 0x7ca45cab, + 0x3a38550b, 0x671becd5, 0xdfb72cc7, 0x155bd14b, 0x3ae3708a, 0x438e8b60, 0xc02fc8ba, 0x65167bc9, + 0x9aa139c2, 0xb927b49e, 0xb4ba59dc, 0x1a804a3b, 0xbcc73611, 0x07ab5d7a, 0x2a2d82e3, 0x706f2744, + 0xb507a697, 0x2a1fc2e5, 0x2d039958, 0x871b0f25, 0x4f2f98d4, 0x3929af56, 0x04cd19c1, 0x2d05631e, + 0xa71e0149, 0x7cd7f1c6, 0x5af7ff03, 0xb5a29b1d, 0x0ead37bf, 0x83dc73d5, 0xfc938f1b, 0x4c7cd620, + 0xd9717c4c, 0x1ee13f8c, 0x668e2f93, 0x60e9d48c, 0xfd7bf7d7, 0x3589fce0, 0xfc04639e, 0x0bb8d187, + 0xe68b8857, 0xeaff80aa, 0xd5fcb22f, 0x0427c8ef, 0xfd57eeb1, 0xe13c537a, 0x36b8d835, 0x5366cf4d, + 0x4b8c2f53, 0x49faade7, 0x6cfb3085, 0xc31b7cfc, 0x31efebee, 0xf955eada, 0x873baa46, 0xe83a4fc1, + 0x48c0cccc, 0x96d47216, 0x876a365c, 0x9f49d03c, 0x1de4c6b6, 0x060e5041, 0x5dbdbd3a, 0xf7a60a45, + 0x079da6f5, 0xfd4e2369, 0x7fdcaa57, 0x9860ed51, 0xe83bcc5a, 0xe11006a9, 0xba54e55f, 0xb6eca477, + 0x3fb0900f, 0x646794ff, 0xaadb2730, 0xbfb3eb71, 0x4db51b1a, 0xe65f642c, 0xe27dc13d, 0x26c25599, + 0x4468c736, 0xd73bdb13, 0x4bebb7c8, 0x03af0b52, 0xa160eb0f, 0x8628fa4d, 0xf30fb609, 0xda396845, + 0x35c44eb9, 0x748c3344, 0x6b81cb92, 0x034fe277, 0x6c10e23c, 0x372b24a7, 0xab9d9a49, 0xb1a776c2, + 0x82ba375c, 0xc25e8332, 0xb00ba478, 0x849d8457, 0xdee7c51e, 0xb5819e50, 0x04a74804, 0xf1c7e08c, + 0x1aa5181b, 0x9ffe13e0, 0x80663ad4, 0x9a03b21d, 0xc11af956, 0x5d7d1c61, 0xe94544d5, 0x30c471ac, + 0x29190cdd, 0x8b0263cb, 0xa1d8e66a, 0x3036d43a, 0x6b08a2e5, 0xea18325d, 0xe4877fa0, 0x0a560873, + 0x9225afd9, 0x149f2815, 0xeabdd861, 0xc6b94aca, 0x1c2aee9a, 0x1489015b, 0xd9111b8f, 0x91a33289, + 0x16d966bd, 0x35d4f368, 0x25adca9b, 0x1cbde0c7, 0x3468cd98, 0x707f2823, 0xca940c56, 0x31563003, + 0xbba0e036, 0xcdd6632a, 0x81539681, 0x2be29405, 0xb9b173b5, 0x9e770827, 0x07328b95, 0x2f1e572d, + 0x9836af48, 0x65c03e00, 0xa64de6b8, 0x9b50e535, 0xb4444f77, 0xed349588, 0xc08c4195, 0x4b6aa269, + 0x76c42958, 0x6d484f66, 0x5b11aff1, 0x46a0cd5c, 0x883ca511, 0x0174f429, 0xf92434c8, 0x1a02c26b, + 0xbad24c68, 0x30d13daf, 0x8de5f824, 0xb8f7461b, 0xfa7cba41, 0x913c2f11, 0x81cd7fe9, 0x058d1a3d, + 0x984f52ea, 0x2357ca54, 0x83e30462, 0xae22763b, 0xe030ef32, 0xa4898aa6, 0xecb0f4aa, 0xd491b02f, + 0x3e388bc6, 0x73710f07, 0x243d7fa9, 0x2e4ef084, 0x02b35181, 0xf866e084, 0x7b6c0986, 0x63612d73, + 0xa4bc1832, 0xa95fc77c, 0xd098546e, 0xaa4414e5, 0x8fcfe7f6, 0x8d35a453, 0x66800578, 0xf9108074, + 0xbf43a311, 0xc02f12a4, 0xdc88b063, 0xc7ac0dac, 0x95a8eddd, 0xe1c267ea, 0xf71ef85d, 0x83fbd812, + 0xf5666959, 0x58a1288e, 0xf39e0d77, 0x2aceec56, 0x7bce0f15, 0x879889e4, 0xe2240605, 0x4a4c2bfc, + 0x7e146886, 0xedfaba90, 0x3d4cb861, 0x55c4d5a1, 0x7263e089, 0x937c71fc, 0x12cb3a7a, 0x80b9df21, + 0x981b039b, 0x5ee9238c, 0x04ae32c5, 0x5218f402, 0x30f33d95, 0xbc4f58bb, 0x7030fc69, 0xd1914b8c, + 0x87be2c58, 0x841a8a91, 0x7d245d68, 0xa121ee39, 0xab73fed3, 0x31d52af1, 0x3fe177e1, 0x889ed816, + 0xa042f44c, 0xdb48029c, 0x26cae80b, 0x42803a27, 0x76b1d663, 0x8655648d, 0xd8aa0858, 0x49604e37, + 0x5aba0253, 0x012c2d1f, 0x8d7ddf2a, 0xf2172a4f, 0x1d08ea34, 0x1087e9f7, 0x0a84d10d, 0x3bcd19d9, + 0xa574e2a6, 0x69a4b077, 0x25c66dbd, 0xa5c2edf9, 0x75974fac, 0x5e6f41d8, 0x8fdbc2fb, 0x184e5b85, + 0xcbaacb94, 0xa371e7e8, 0x4533c05b, 0xe435e36b, 0x091f86fe, 0xe4e0543f, 0xc3f92162, 0x17d9136d, + 0xcd91d5eb, 0x061d569c, 0x01024be4, 0x6b2f6d87, 0xd75f4efb, 0x985ccd47, 0x1becdbfb, 0x9944df09, + 0x5ed6af57, 0xfe4144cc, 0x575864cf, 0x48d658cc, 0xbb4372d6, 0xd7bd0d79, 0x6b89c1e2, 0x488351e0, + 0x1e4a677b, 0x3f0fecee, 0x38384010, 0x8ec359d8, 0x84b6c6c5, 0x4d6ef0b6, 0xcf98aad4, 0x37c631fe, + 0x63642742, 0x74ca90e6, 0xc64b2967, 0x978436e7, 0x38ed1aea, 0x4878839d, 0x4842ff2c, 0xaf76db8e, + 0xb0e5147d, 0xb3d7c2a5, 0xb830250f, 0x1699b954, 0xb8ba2ce9, 0xaa9f27c0, 0x42f43ba6, 0x8fbffc80, + 0x872a0467, 0xcd3b47d1, 0xfd153904, 0xd531d2b4, 0xdc206445, 0x604f9fe0, 0xf104c05d, 0x05c238a3, + 0xceffd7ae, 0x9b6ce08b, 0xa6e48b0d, 0x88c31f0e, 0x36dc556e, 0x1cf6f65e, 0x20e031f6, 0x699b5a2e, + 0xe98a6d67, 0x7ae8b101, 0xb87937da, 0x9e29500a, 0xc0da7e84, 0x4f19a4cd, 0xe52ac0e3, 0xb4da4f35, + 0x54d17209, 0x3580d2d7, 0x76c0d19a, 0x0cbcfb5f, 0x71340e72, 0x4809d5d2, 0xd93496ed, 0x7f456a81, + 0x7846289d, 0x1796d803, 0xf61a212b, 0x469a0695, 0x23af1646, 0xddecbd39, 0x87d90adf, 0x6a0c11c8, + 0xb1aad413, 0xa5d2fe7b, 0x8af66fa5, 0xfa31cc8d, 0x02161311, 0x24f2fcd6, 0x562c2709, 0x16c43905, + 0x9d6f008c, 0x0a807913, 0xb7471e1f, 0x85736113, 0xc8c3f610, 0xb084d5dd, 0xf474e211, 0xf6fdfe15, + 0x74b79357, 0xae597aee, 0xf11f93b6, 0xa83be799, 0x5d21143d, 0xfca2549a, 0x006d9905, 0x9eb59bc9, + 0x2b109f9c, 0xb35cfa65, 0x10ab91ff, 0xf12afd22, 0x5c37b05f, 0x1c8e75d8, 0x62112c12, 0x48f5fc10, + 0xe88397da, 0xd4d4aa99, 0x9075c9dd, 0xd5f18f16, 0xa3e09125, 0x740dc093, 0x77922523, 0xc760c768, + 0x25dc91db, 0x5c4c2908, 0xdced0ab7, 0x311e0361, 0xc81722cd, 0x9118014f, 0xe769e54e, 0x53c478c4, + 0x5d1398bb, 0x5d68b6ac, 0xb07674a5, 0x1a991272, 0x7c5ece2d, 0xda38b93d, 0xb1fd08d4, 0x8d1b6994, + 0x526d4d74, 0xeb84c80c, 0xad2d4772, 0x3f7ae3a7, 0x5797ae5f, 0x5dd1dbbc, 0x752f0da8, 0xe7473f25, + 0x97377dc4, 0x19094083, 0x32694e43, 0xfbbf8f23, 0xc5fbdb8d, 0x4ce1f8cb, 0xc506e465, 0x49a24e16, + 0xe7e4191b, 0x8a755daa, 0x19582865, 0xe0749ade, 0x19a44027, 0xd796989f, 0x9ac75606, 0x93a9e148, + 0x1ce32d85, 0x868e0371, 0xc44d7c4d, 0x715faaac, 0x772dc27d, 0xfa5a059e, 0xffed114c, 0x268ab0d9, + 0xddd33bb6, 0x2145060f, 0x37c41f8a, 0x1168a04d, 0x49f58999, 0x9c6ef167, 0xe4a13ffc, 0xfea71e46, + 0x53c8510c, 0x02a74502, 0x08607bbf, 0x39f8456a, 0xd69a6fe5, 0x7bc4b879, 0x8dd06abb, 0x0cf29480, + 0x300d6774, 0xbf8d96f6, 0x96473bb5, 0x3c90a048, 0xfb37986f, 0xc5a00c2e, 0x2a05e297, 0x274a92ba, + 0x354b379c, 0x9f9db554, 0x2f72ccb6, 0x0058cdc9, 0xa1a1c38d, 0x3e37b6f7, 0x79a2d228, 0x4f2369e9, + 0x86258f26, 0x9a9c6820, 0xeb69f856, 0xa9298812, 0xce4012f0, 0x9aded287, 0xf85529f3, 0x8af89dda, + 0x00a6ba0e, 0xf9562fcf, 0xd2a48e3c, 0x77d734f3, 0x323dc4ad, 0xbdb24bfa, 0x0ce6c798, 0xfd9d8a43, + 0x21d9811b, 0x6e17278a, 0xb5ef616e, 0x73e423b5, 0xae74a04b, 0x0846dfd4, 0x56f0d929, 0xc7a521e1, + 0xd0027487, 0xd5843a70, 0xc27dde61, 0x2396d9d0, 0x308f0bb5, 0x880515a5, 0x5cdcb629, 0x2fa4c630, + 0x5df86719, 0xf5a4811b, 0x1773eb07, 0xffce6253, 0x7f48f8fa, 0xaa488c1b, 0x87e4923b, 0xecb34e8f, + 0x0640d799, 0xb64323c1, 0x9169090b, 0x67ff6068, 0x30527bf5, 0x3ce34a81, 0xcbbdb0cb, 0xac293d64, + 0x913e7111, 0x8bbcc80d, 0x460c6d1f, 0xd960fcfb, 0xb04cbfde, 0x825a65b9, 0x11fbdde9, 0xcc2b7fa6, + 0xfcfb0dd9, 0x324a286f, 0xca16a16a, 0xdb0b3091, 0x6685ff1e, 0xfb88d5ad, 0x8babbead, 0xfd2a20c7, + 0x3adee043, 0x566980b9, 0xbaa80b48, 0x5c75e5a4, 0xa093c906, 0xbac7a3a5, 0xd3f89f9f, 0xfbfcea1e, + 0x8d0c8a0d, 0xbd5552b6, 0xbeb3c8cc, 0x6d577bea, 0xc0d992af, 0x8d633eee, 0xed91eb55, 0xecf7bc04, + 0xaf789dbb, 0xe97d07a3, 0x2c52ac7e, 0x4a5e4888, 0xe2853b2f, 0x6416cead, 0x0c2ed4e7, 0xac27977c, + 0x1995109a, 0x47d94907, 0x03c136fc, 0xb3bb2078, 0x46544150, 0xd7ff0d67, 0x33378ead, 0xe40c8705, + 0x18856aa0, 0xd1a96af9, 0x43869fa1, 0x3ef06176, 0x9b83049d, 0x868ffbae, 0x6e4499b1, 0x94809708, + 0xb2863963, 0xa8e30318, 0xc2da130a, 0xbd0fbe6d, 0x0dc94c94, 0x37803aa3, 0xda6b4197, 0xe7306404, + 0x7b795ff9, 0xa48c21e5, 0x884d22b3, 0xe9761bc9, 0x00fbd5ff, 0x20e61060, 0xe0161322, 0x5ca5a28b, + 0xbbd7b892, 0x6759a99f, 0x4c12a60f, 0x47c15d2a, 0x8f3166dc, 0xee41e497, 0xf07fc009, 0xedeeef82, + 0x0b33acae, 0x7852bf30, 0xd6ef7ab2, 0x16d1e497, 0x7430c5df, 0xeae80f51, 0xfbc230b6, 0x67dcafdd, + 0x1d5f2ed8, 0xbeb30dc2, 0xe00f2e0e, 0x5ca08dbe, 0xd0ac82eb, 0x3e3b2caa, 0x4b70693a, 0xf6a57f25, + 0x342e3fe4, 0xa5076e36, 0x9642a244, 0x9b6b6c3e, 0x5e9a73fc, 0x6d859b80, 0x0f17289a, 0xbea9b21c, + 0xc115a11f, 0xa29b6bde, 0xed2e3d21, 0x1559bd25, 0x82b59b78, 0x981bb163, 0xea83fabf, 0x6b7d919e, + 0x4cafedb6, 0xfcad030d, 0x69e2b586, 0x70544161, 0x6d1d71ab, 0xb080fa69, 0x21497536, 0x12f94734, + 0xf6bafbb5, 0xb6540b4d, 0x151618ad, 0x6c9bf075, 0xc805e31c, 0xae8bdd1f, 0xb3062090, 0xae6b9d32, + 0x839bc1bd, 0xf200e546, 0xc1756b96, 0x1930dd1c, 0x7560a319, 0x91b01f2e, 0xb588e68d, 0xd89cc3e2, + 0x41e9a640, 0x1fa5b909, 0xbee7f5ab, 0x996da492, 0xa2d1db59, 0x70977280, 0xe2a8e345, 0x1346ae37, + 0x36f5d516, 0x0ed4df07, 0xe70ab159, 0x58d933e1, 0x7b40e537, 0x99453bb0, 0x5c19b434, 0x09433361, + 0xd7526b54, 0xde4bda51, 0xb89a9253, 0x8b79482f, 0x59051e3a, 0xe531527a, 0xe91dd1ab, 0xc059c00a, + 0xbd410959, 0x0c75aa84, 0xb190c110, 0x1c779a81, 0xb065f6c4, 0x0f465437, 0xcf991010, 0x036f1daa, + 0xf672d881, 0x0fd26cfb, 0xa1d91c53, 0xd12338cc, 0x06ffc608, 0x945fd7e1, 0xd00c08e1, 0x30c5caff, + 0x81994162, 0x63136fb8, 0x2a1d1b4f, 0x6299e37a, 0x2e692564, 0x25feb321, 0xfd0951e7, 0x02f410bb, + 0x9659f067, 0x40f3a663, 0x922aedca, 0x18b9505d, 0xac820077, 0xbcf7a072, 0xa7216a10, 0x8bcf1c46, + 0xe2a3463f, 0x68f411ba, 0xe8053f35, 0xd84a4d2a, 0x75596b0b, 0xbd21b174, 0x8b484557, 0x55d02fe9, + 0x1fdf560a, 0x0f3b7c9f, 0x2d172ab7, 0x97998123, 0xceb647b2, 0x30102c9d, 0xe76e12be, 0x94232f2b, + 0xed230809, 0xad50bb5a, 0x596ef1f3, 0x2b23823e, 0xb98ff8e8, 0xe916a575, 0x8f673b8a, 0x36498fd3, + 0xdef52ce3, 0x5f830402, 0x190f3351, 0xb7722991, 0x9b97ebb6, 0xb8663a98, 0x80a256c9, 0x4b79519b, + 0x58617299, 0x33c2fc1a, 0x79109bfc, 0x6355d8ec, 0x45df76fc, 0x012e7fc9, 0xa3f06690, 0x989844b4, + 0x7907f8ae, 0x6786ce9a, 0xa69e26c1, 0x4a162127, 0xc98e0b64, 0x1a05a156, 0x56309f85, 0x758d023b, + 0xc932c053, 0x99b4c218, 0x513cb28a, 0x2e38e902, 0x77d3e8e4, 0x1e99d56a, 0xaa6955c6, 0x4db388f1, + 0x02d90614, 0x36e0c289, 0xd9e65c60, 0xe77f8edd, 0x8946e5eb, 0x1f66bed8, 0xed58a351, 0x9905c461, + 0x66564451, 0x7d14d441, 0xef1339a0, 0xb7ca4116, 0x71abe36f, 0xb60e033f, 0xd2152625, 0xbf9cbbec, + 0x998ea373, 0x941d7c3d, 0x5ff8e48f, 0x863db54e, 0xbbb11984, 0xdd1356b6, 0xab641719, 0x2ab7ef2f, + 0xa3d0c48f, 0x4bf1242a, 0xe5b97c76, 0x32a002e0, 0xbd62d919, 0xfe975133, 0x216cf7ef, 0x45fbe521, + 0xf98e23db, 0x3203f14f, 0x8abb9ea7, 0x4b78a1e0, 0xf0d7bc39, 0x155cfd13, 0x1c44cac2, 0x95369cb1, + 0x39cd9fc0, 0x5282e992, 0xffa0bbed, 0xe240f874, 0x3b09b802, 0x12cb5adc, 0xe9423d7a, 0x403b3b99, + 0xada092a7, 0x851c9b3b, 0xa625666e, 0x4d0e4f20, 0x49264c96, 0xa9c8500e, 0xd37d3b86, 0x2097eb9c, + 0xf32f1257, 0xc0192de0, 0x19dabed1, 0xdfb4bf06, 0x0b48ee2d, 0x1c835ac4, 0x4dec0b93, 0x7cba2caf, + 0xf549869c, 0x56c583be, 0x3945fff3, 0x001326b2, 0x378e14e6, 0xb3e69f2c, 0xfdc779ec, 0xe5be49ae, + 0xaf038b61, 0x5c0e7601, 0x015e2fb9, 0x6d185718, 0x363fe840, 0x3729c985, 0xa9b7f3aa, 0xa41de646, + 0x63304b95, 0x0e6f2f2a, 0x9bd59621, 0xc727cf4d, 0x447b0668, 0x751b0274, 0xc471a558, 0xec36f7b2, + 0x7197547e, 0x64ce56c0, 0x8a427870, 0xb7ae9c1c, 0x668abd5c, 0x8e4547c6, 0x9314c4fc, 0x31f3d18f, + 0xd79c70ac, 0x4a9964bd, 0x45b622c2, 0x194900d2, 0xb4cec415, 0x0f1a06e9, 0x11ab7e81, 0xc1aa577a, + 0x435c0123, 0xb69be672, 0xc0dd624a, 0xb19ba18b, 0x7b2c886e, 0xe9c03883, 0x18672c52, 0xbf1d36bb, + 0xca9eca65, 0x38d962e8, 0xbc868257, 0x3850610a, 0x1c61bb26, 0x2a43e991, 0x190c204a, 0x3da50b3c, + 0x532ac88e, 0x70d92dd1, 0x7e996aac, 0x48340e35, 0x23c40874, 0x53f80b08, 0x13aac22a, 0xb0e5104e, + 0x0841aa35, 0x08c604f0, 0xb868f069, 0x44354236, 0x17d599fe, 0x96f09d81, 0xad9c877f, 0x0b07e5f1, + 0x15863e3c, 0x93098f25, 0xefd8b0d0, 0xdbc8bcf6, 0x7d29dab3, 0xb6e320c5, 0x9bab36a4, 0x090b7288, + 0x4073b1c3, 0x816a84c0, 0xe5c09250, 0x0e393eac, 0xd0046c40, 0xae8195c4, 0xd95739a3, 0xcdd14bbc, + 0xb8ca0d4c, 0xcb53351c, 0xef7e8c65, 0x7ad1fa05, 0xa7f1bd6a, 0xece7d46a, 0xfd04c54d, 0xfd06781f, + 0xd00d36fa, 0x0123f7c1, 0x57ced070, 0x9b81695f, 0x0253d88a, 0x43140383, 0x90683d04, 0x1e96a371, + 0xb6b0de28, 0xbcf4bde3, 0x2c820ee0, 0x60607660, 0x9c45ec04, 0x5197ff12, 0xac0123ce, 0xc878bf39, + 0x10d53fb0, 0x6a10a03d, 0x5f8a3c6f, 0xd51f1d29, 0xfe1aa78d, 0xd8511674, 0x1870d3f9, 0xb34852aa, + 0x588b753b, 0x04deb5b6, 0x644f0241, 0x96b860db, 0xbb021b4f, 0xdc367d73, 0x3f728e73, 0xfd32476e, + 0xf80b6c86, 0xe9ad667e, 0x6440d5cf, 0x6310eb93, 0x255b65c0, 0x8be87382, 0x0ef9ccff, 0xd2d04ed2, + 0xe176ad60, 0x72a3e7d5, 0x6a67199e, 0x0468f2f1, 0xb464a605, 0xe4a59db8, 0x16ffafe7, 0xaa4fc1e5, + 0xcbbe2a8f, 0xb8eeeed1, 0xd8fe9496, 0xe901bd5f, 0x592d67e1, 0x24b42f4d, 0x71236485, 0x15737190, + 0x17c78dde, 0x26bcfcdc, 0x29db3082, 0xf5b56154, 0x0bfecb75, 0x075c6ff0, 0x78df3c11, 0x06b057e2, + 0x3f56ec9c, 0xeb098e9f, 0xbd4a6deb, 0xa1a6219a, 0x015b1f52, 0x077f7b16, 0xbce1b1f7, 0x148dc062, + 0xbd09592e, 0x3caa6596, 0x6eddca97, 0x8f6ea1fa, 0xd2744d88, 0x8c6ee33d, 0x604f5e73, 0x721601c7, + 0x72429731, 0x7d461b8b, 0x399d9e56, 0xb9012dfa, 0x19592b10, 0xba8df0f8, 0x5d1e18ef, 0xe71c4f18, + 0x59dec154, 0x97a42b03, 0xafcab452, 0xbbca6af3, 0xf159abf6, 0x1a948446, 0x7b79f199, 0x0595d7c3, + 0x17223885, 0x44299253, 0x0f10334a, 0x0c509d86, 0x2ea282a5, 0xfa13aca6, 0x0353fdbd, 0xbd1905b7, + 0xf63f502f, 0x688b8339, 0x6905d4b8, 0x494eff1b, 0x71e8bf01, 0xafce7257, 0xf7856e39, 0xf20a09b0, + 0x2c6b4cc8, 0x189ad723, 0x3cd16805, 0xac98696c, 0xf79d0bb9, 0xbab37f8c, 0x4b727868, 0xd5f9d2ca, + 0xd7ddc349, 0xcbe339f9, 0x98b645dc, 0x9f2535eb, 0x1b236709, 0x1874620b, 0x00265fc6, 0xffe28865, + 0x237fdc88, 0x9f7d2108, 0x74a57286, 0xd5eaba94, 0x05f0af4a, 0xf0a47254, 0x6714089f, 0x3cbb5406, + 0xf5d7b491, 0xcd885d5b, 0x7e48fc43, 0x51bd8468, 0x2c8b0729, 0xfea85ca2, 0x3ebc36c6, 0x14cf65b4, + 0x6985e6e3, 0x05cf1e8c, 0x63bae428, 0x2701ae24, 0x78b410c7, 0xb542df9b, 0x64b4ceea, 0x4658ff6d, + 0x8c9e84a8, 0xe20b8385, 0xdec337fc, 0xb8256f7f, 0xa8dd042b, 0xe9acaa94, 0x1c40a0bd, 0x61ee5a30, + 0x89e045e1, 0x417a52cc, 0x269c40a2, 0x56e715c7, 0xd0d3f48f, 0x2e03266a, 0x4871e428, 0xc7bb2b44, + 0x1744cd72, 0xa6106205, 0x327686bb, 0x2bb8c03d, 0x54a0df98, 0x725aa032, 0xb4b9e61c, 0xb164fb57, + 0xeaed6e4c, 0x11cf1c4c, 0xf2e4b02c, 0x5578b729, 0xe45a0396, 0x03c6b2bc, 0x39e2f648, 0x25aaa0d3, + 0xbcf11a41, 0x2193258e, 0x07a3411a, 0xa88a4782, 0xa0302e0f, 0x4d9311fc, 0xaf42bf7b, 0x6eb7a1de, + 0x48a6549b, 0x5abaead6, 0x0a9970c0, 0x8a60ed7a, 0xd3af3fa1, 0x290ea2ca, 0xa7e83016, 0x8052ff1b, + 0x89c67075, 0xe0ced1bc, 0x800e4cf3, 0x98c12258, 0x3919a7e8, 0x18ace016, 0xee06d8ed, 0x9a4c029b, + 0x6e7c8c28, 0xb5ae8ce6, 0x90710505, 0xcf5b562d, 0x57bf7493, 0x31bffaff, 0xd60cc976, 0x5e7902d8, + 0xf18da021, 0xf05fcbe6, 0x1fb0141b, 0x084068a6, 0x04325cf1, 0xadc95576, 0xb3ca876f, 0x031e1500, + 0x5f0f4d4c, 0x375a1508, 0xacda134f, 0x59112add, 0x7ac89fb3, 0xb8567c7b, 0xfc765231, 0x96a9c25f, + 0xa905725c, 0x92750e4c, 0xa425d2cf, 0xa3c4d821, 0x79fed15d, 0x727e9995, 0xe3440b98, 0x285c5887, + 0xf12a8bce, 0x2e0318d9, 0x3990138f, 0xcc991159, 0xac09f7d3, 0x698a02eb, 0x6430ffba, 0xcc20379a, + 0xf270826e, 0x938e9f53, 0x22b35d05, 0x91f7d6c7, 0x6c29bd04, 0x97a90ced, 0xc1211089, 0xc8c4c60b, + 0x33a881fa, 0x531e064a, 0x333ea523, 0x5276addf, 0x112f910a, 0xc091b9c5, 0x99c79098, 0xf355f783, + 0xc793734a, 0xe1ca2c33, 0x51a1d4bb, 0x0fbee536, 0xbaab5ebf, 0x8fba7084, 0x102d5451, 0x4ee0dfbb, + 0xbb6067a2, 0x3d577826, 0x35202e72, 0x0ca36cec, 0x14929b58, 0xcbc97a6c, 0x6ee5a4a8, 0x284908c3, + 0x2fac001a, 0x2203ca15, 0x10b7fc5b, 0x773b6032, 0x07bce5a4, 0x81ce1667, 0xe55f08bd, 0x7c054e7a, + 0x36f8fad8, 0xaeda472f, 0x69c9314e, 0xe5146b6e, 0x618148a7, 0xab2ce6e7, 0x7a3fb7d7, 0x13a4ba02, + 0xaa160536, 0xbee27c29, 0xbb64afe1, 0xff31a2c9, 0x01f024e2, 0xf251ffe7, 0x401a3d08, 0x40d679c0, + 0x93355921, 0xfbbfb60d, 0xa97bab4b, 0x8ca871a3, 0x579e82ad, 0x7cf9c86e, 0xfc954fea, 0xee84ecfc, + 0xa0bc44d5, 0xdb4428ec, 0x761dff09, 0x3f06a897, 0xf54f13ca, 0x996b93db, 0x737fb1f8, 0x3bdbfd41, + 0xafeab556, 0x29130e96, 0x2b7a0129, 0x55069b54, 0x7679e428, 0xc04b2a4b, 0x1c30aa51, 0xdf15e86c, + 0xbe4b9448, 0x4bf71e5f, 0x73affb9d, 0x1e9fef4b, 0xda87c876, 0x9de2682d, 0xec1bf1ba, 0x60de347d, + 0xc77d1f6b, 0x1ee048fb, 0xfd180647, 0x3e2feb9e, 0x925e0b30, 0xbc199f7f, 0xe04b61e1, 0x1774dc33, + 0xe9ae8262, 0x21912645, 0x26f407f0, 0xd3fcda0f, 0xb71a01f7, 0x31f4ae1e, 0x1d2c7e34, 0x20b674d4, + 0x058b0c35, 0x89371c23, 0x13a0b85e, 0xfcde095b, 0x547044ce, 0x9e0a2759, 0x39dd19b1, 0xcc6bccae, + 0x78e70319, 0x4953bdc9, 0x6ec53351, 0x2d90195d, 0x9251b28b, 0x88d9c309, 0x436fcf10, 0xf64f2806, + 0x162bcfb5, 0x3e2fbf02, 0x73a2fe20, 0x305f4d39, 0x7b11dfd1, 0xc2d5ce6a, 0x66055447, 0x88f45ca7, + 0x385075f0, 0x74f305ae, 0x372d6f8a, 0xcebbc867, 0x1caa68ad, 0xe6449057, 0xb72dd6ed, 0x370ef604, + 0x590534c0, 0xa22b8120, 0x8c25c3e0, 0x3a8de418, 0xae692b81, 0x3e6e83b4, 0x37b1f5d4, 0x29109808, + 0x558a904c, 0xf6d8b81a, 0xa539ecba, 0x23202284, 0x76520938, 0x4260c067, 0xc86c68c7, 0x27b21955, + 0x620cec16, 0x43e91c14, 0x6cad20ab, 0xb7ca3d36, 0x56416a90, 0xe7dd281b, 0x538ed522, 0x61c12c64, + 0x99f180ba, 0x424c1af8, 0x7c5c8a7e, 0x2d668d73, 0xacadb4d1, 0xb237eb7d, 0x064870a3, 0xaf5ab454, + 0x2a6fbab1, 0x258f7046, 0x10b3e723, 0x424659e5, 0x9977e1bd, 0x0621a1cb, 0x60798fbf, 0x5f457411, + 0x335287c3, 0x22157c2d, 0x28214eeb, 0x43a4a80e, 0x613df838, 0x461023d2, 0x4fe639d5, 0x6301355a, + 0xc70df1f0, 0x12411816, 0xa505767f, 0xa4804f3a, 0xab5def5b, 0x823ce3c2, 0x9b912b8c, 0x03de64e7, + 0x769435c6, 0x58a336c0, 0x2b70d4dc, 0x1496aaff, 0xf214662c, 0x5b8179e9, 0xbf6012e2, 0x67916a14, + 0xbc2ee5ca, 0xc75a6e69, 0x9449f0db, 0x54315237, 0x26a119ae, 0x27732b7a, 0x8ac17d81, 0x22a3fab5, + 0x213d433a, 0x12dbd6f5, 0xfb32471e, 0xd4c3f688, 0xd26deeac, 0xf4053e98, 0x9ce54467, 0x827d5f2c, + 0xfd8fba78, 0x56247930, 0xf8d706ae, 0xf359d27f, 0x46ec7cb4, 0x51da3c35, 0x2b8de673, 0xcf17d98a, + 0x3666fc4e, 0xcde7e162, 0x08bb8bca, 0xcc958025, 0xc350020a, 0xd0b7e1c0, 0x30da4055, 0xbfbb6d76, + 0xc15a79d3, 0x902c55a7, 0x0c033ba6, 0xc1512a87, 0x04a374fb, 0x20ea932f, 0x725d0ed8, 0x927b72c8, + 0xadeb5fea, 0x39628d1e, 0x6e3b5307, 0xc7ac3dc9, 0x1197b084, 0xda33a5ec, 0x05a2cc03, 0x9fa0b116, + 0xa8b6c18f, 0x5bc056c8, 0x33e6bbb6, 0x2dd412c3, 0x414d51a1, 0xa003faf4, 0x84d7392d, 0xd4ffd417, + 0x1ec166c0, 0x773098c3, 0x7ac864e7, 0x962aefe9, 0x545ec08e, 0x7ee9e0f2, 0x8a4d6af4, 0xdcd9f25b, + 0xa8d51253, 0x279d5125, 0xa9769d76, 0x45ad9a25, 0x52d5ade5, 0xb077cab6, 0x95016b0b, 0xa11693bd, + 0x2b5f7622, 0xb6c4dbcb, 0x039ea56a, 0xe9f5766d, 0xd9e4634f, 0x4ec2f4b9, 0xcc09b2ad, 0xf93098c0, + 0x6d81fe59, 0xca9abec1, 0xfed94b9a, 0x73524065, 0x8087a24b, 0x81c9e85a, 0x8214dfee, 0x7f4312b1, + 0xf1e00dcb, 0x60abc8e1, 0xea8851ef, 0x05c1ad94, 0x34da8283, 0xbaee3965, 0xc77f9068, 0x42e85eb6, + 0x7b6527d7, 0xb9abc0dd, 0x271d7337, 0x677ab0f1, 0xfdacac78, 0x6fafb992, 0x95e70bc9, 0xd3b50542, + 0xbe587458, 0xa54d5cce, 0x9892609a, 0x61365d08, 0x17593e28, 0x3ffc96fc, 0x1b9c09a3, 0x917a4acb, + 0x8e62e59a, 0x38d6d1d3, 0xea736a2b, 0x7716ddb0, 0xd01f66ef, 0x9dab5ea3, 0xf1e96d20, 0x9809780c, + 0xa911de76, 0x9d097da7, 0x211ad471, 0x70e389cb, 0x735fdd25, 0x185bce24, 0x344bdf66, 0x94c72517, + 0x66ba1400, 0x64857920, 0x012b939f, 0xc1c8d4e3, 0x91693b9c, 0x281db2c4, 0x2c8769dd, 0xdb39c6cd, + 0xefd6de68, 0x9feec55c, 0x9a4ee243, 0x36668dd1, 0x7853ea27, 0x21bc55fb, 0x5462b24b, 0xce56e386, + 0x8db50c68, 0x4a78d3f7, 0x88254022, 0x3875822c, 0xcb3bbf2f, 0x69238e44, 0x9b4181af, 0x910a8062, + 0x6935c751, 0x1d78e8fe, 0x1fd086a6, 0x0bb972c1, 0xaede087f, 0x451eed0c, 0xa8d84ea4, 0x6a6b7b29, + 0x060bb322, 0xd5216020, 0x2a69802e, 0x78571e45, 0xc487a077, 0xbdde346c, 0xde93ee33, 0x5007fb9a, + 0xeef8aeb3, 0x1bde44cc, 0x38647f83, 0xedebbe63, 0x34548643, 0x19f5daf3, 0x2a50b3db, 0x1916a3c4, + 0xd885c0ab, 0xd5fde2db, 0x79630c04, 0x2ee81ee9, 0x1035ea68, 0xe13a4969, 0x6eafb57e, 0x50933ce1, + 0xfd87f15f, 0x9b0dc143, 0x3cc09fad, 0xe9154500, 0xae617d7c, 0xcc3a6090, 0x43ae99a1, 0x0ac982cd, + 0xf30e31df, 0x41df8768, 0x63709964, 0x2243b968, 0xf9cf7672, 0x907190ea, 0xffbaf4c2, 0xa632f63e, + 0x2ba21921, 0x1f9e9518, 0xeba592bf, 0x88024f94, 0x2f16e929, 0x1fd924b5, 0x6af843c1, 0x662dcd3a, + 0xeb7ba6eb, 0x477902f9, 0x25ee8b1e, 0xf2dcc22e, 0xda31dfbe, 0xbd7cb410, 0x8513e6bc, 0xdd9b0800, + 0x5f1968ae, 0x1201b1ff, 0xbef73f97, 0xda598fbd, 0xf69d52fd, 0xcf6ac45f, 0x226fef8d, 0xc32d5b36, + 0xab97abcc, 0x229e243e, 0x69cda4e6, 0x1aa28851, 0xa30c0471, 0xdd90562d, 0xfb8ecfb9, 0x565c1b3f, + 0x005b3873, 0x4125ca0e, 0xb53ce23c, 0x991f118b, 0xd1ba2b72, 0x7944deda, 0xcef469f5, 0xc32b7f80, + 0xae31f801, 0x54b6105a, 0x2cf98541, 0x536ccf18, 0xb9608cc5, 0xf58bdb2d, 0x635653dd, 0x6c4627a7, + 0x57164b2e, 0xfed59fec, 0xde2a243a, 0x4e67a975, 0xce533eed, 0x8cfb642d, 0xfa672758, 0x93726bca, + 0x6ee5fef4, 0x0ee54dee, 0x57935f77, 0xe78ceab3, 0x0d39e9c2, 0x979995fb, 0x714f9427, 0x25722784, + 0x21cde9c2, 0x71212d3f, 0x543b0ec5, 0xc031f8c9, 0x5e6ec7a0, 0xdd1d5cb3, 0xed5d3c76, 0xb4576288, + 0x92dde484, 0x12647d00, 0x69703757, 0x2d3becfe, 0xbe1a5859, 0xe4e2542d, 0x3e3745c2, 0x6c94788a, + 0xb48965b9, 0x487f5ce4, 0x77ec72d1, 0x5d5276c0, 0x8709fff1, 0x04727498, 0x9b6e1bd5, 0x0eabac10, + 0x71672595, 0x3474f592, 0x119919a2, 0x6cae686f, 0xa93a1926, 0x2dea7bff, 0x6d26271a, 0xd21827b6, + 0x24019274, 0x1873c0d1, 0xb797eed6, 0x6ec828cb, 0xd221926c, 0xf6002965, 0xef00594b, 0x56ac7f44, + 0xf5736891, 0xc44c0714, 0x7e850254, 0xaf29b64f, 0x933c587d, 0x94176c70, 0x047d7734, 0x4f35258b, + 0x5eb37f54, 0x899309d5, 0x3236076e, 0xe71072f6, 0xfe69f9a3, 0x786ee5e2, 0xc7b613f4, 0xcd7a541b, + 0xb1f9590c, 0x800b89c4, 0x32ba6ea6, 0xb77960ff, 0x9e2621d2, 0xed38b08b, 0xd8405feb, 0xd0f53f9e, + 0x0ca18bde, 0x2f72ad55, 0xc147e704, 0x3acd5258, 0x270b9d0f, 0xbdaf9621, 0x1e2ed9b8, 0xad3cf805, + 0x29b2c3fa, 0x9febf731, 0x06805caa, 0xd8a53b3d, 0x79a1e5b8, 0xeed428f0, 0xcccb9b9b, 0x265020a7, + 0x33fed2d6, 0xfc2bc1bc, 0xc992a4bf, 0x68db28d5, 0x1ba3bc33, 0x7debd820, 0x7ff9f6d4, 0x32965235, + 0x8532a246, 0x1f83939b, 0xd75f83d4, 0xca8a754c, 0x1bc0ea4d, 0x099c6cbb, 0x75988e0c, 0xa2db8f5b, + 0x46160677, 0xdff8ad30, 0x0e681c83, 0xbe08128a, 0x02fe0461, 0xe53910f7, 0x7f29ccdf, 0x1724a1fd, + 0xd7385cb3, 0xafb42bf2, 0x805115c1, 0x572258d8, 0xba833ed2, 0x99b35143, 0x24ac7c59, 0x59f4585f, + 0x40574875, 0xd39f48f6, 0x71848639, 0xfc27b910, 0x14463b4e, 0x917feb18, 0xb0d18c33, 0xfa3f012d, + 0x7dfedca5, 0xd0084508, 0xff0c4065, 0x5357ec18, 0x97c640bf, 0x4eca36c1, 0xccc5ea65, 0x20a9a9e1, + 0xd50e12dc, 0x8333da38, 0x8964afcf, 0x7d12c525, 0xd16e4814, 0x60a4b926, 0x6601260f, 0x82260bf9, + 0xd3f3c7ba, 0x616ac6b3, 0x0f9473f8, 0x68e8587a, 0x84ee9ed2, 0x2fb84fc9, 0x95700b96, 0x9fcfcd33, + 0xb4610b5d, 0x2ab89618, 0x31675a1f, 0x5b7b0ac9, 0xd199dff6, 0x137247de, 0x8ddb7035, 0x44222404, + 0x847b9dfc, 0xb84c7128, 0x1676423a, 0x275200e3, 0x3d25290d, 0xa1fd2db3, 0x4c37a6db, 0xb64abbb1, + 0x11ebc3ca, 0xe07c6067, 0xcb66535d, 0x14fb2c53, 0x671d6ccc, 0x680eb8b8, 0x514e718a, 0xdd716f1a, + 0x5b66ae71, 0xe4736136, 0xff5c4f24, 0x00275a2f, 0x13172a95, 0x4bba9efd, 0x6c174325, 0x0e53b106, + 0x41fc4bc8, 0x6b399108, 0x7db57c3c, 0x714cb5f7, 0x5e216c00, 0x6174ca72, 0xc2003f6a, 0x6573b284, + 0x3427eb77, 0xebdd7f32, 0x0ec979e2, 0x1727b25b, 0xb36e9376, 0xb958c994, 0x046d7e00, 0xf91f3f85, + 0xd8d9657e, 0x39fbc0b7, 0x4f0d8069, 0x555809f0, 0x33c4263a, 0x2b677b11, 0x5362e5ab, 0xa042586c, + 0x10319cbc, 0x7c2d6fa7, 0x0f28a300, 0x27438166, 0xad9ea15a, 0xd69886f2, 0xc3e8e489, 0xa30eedb9, + 0xd6a75466, 0x248979fd, 0xfaed98f0, 0xb93f4a0e, 0xc497b767, 0x77858f37, 0xbb20f169, 0xb6df4fbe, + 0xaf4e226d, 0x75ad6ff4, 0x45b0fa6a, 0xa3b804d6, 0x92262757, 0x46094757, 0x05f517aa, 0xe515680b, + 0x76c86ade, 0x4fc2cfb4, 0x2c0a44e2, 0xcc384dd4, 0x33e0daa9, 0xe002e9c1, 0x2cddab23, 0x64e55051, + 0x5f1b964e, 0x643c542b, 0xc44332ff, 0xaaaf3d0e, 0x3108a53f, 0x6222d4e7, 0x5527cf0a, 0xb00a49ad, + 0x4bb5b608, 0x1262c46b, 0x101246b4, 0xb0633c90, 0x3963a57d, 0xff81bbf9, 0x74f7dd38, 0x4a302162, + 0x9720ce2b, 0xf41222e1, 0x0e7bbc6e, 0xd541c986, 0x6e09300c, 0x025d9b11, 0x769077bf, 0x7a03335c, + 0x2ba8cf02, 0x6d3b8e4f, 0x99d097d9, 0x4a77fd92, 0xa91d723d, 0x3bf77fe2, 0xad8b98f9, 0x38a023ec, + 0x94c64813, 0xfbb63aa6, 0x1a0c5cdc, 0x31653503, 0x6c9f8330, 0x289dab67, 0xf16b8ee7, 0x2c151b4c, + 0xae7cceb8, 0xfa6c5cd8, 0x89d11b85, 0xbdca2830, 0x3a570de1, 0xe23c2dd2, 0xdcd86384, 0x6cc1b494, + 0x6d42b582, 0x17af6240, 0xa8ac6091, 0x546465c6, 0x5b2ba2c1, 0x779229fd, 0x952ad2a4, 0x7ffb6333, + 0x1cef62fb, 0x76347a11, 0x7a19f040, 0x529dd1ed, 0xdf2adf71, 0xef6839e3, 0x0cc39c76, 0x0c304dac, + 0xebfd6989, 0xc01feaed, 0x15fe10fb, 0x5c9eee46, 0x7a1ce43a, 0x735b2554, 0x11e052a5, 0x7c44e343, + 0x28f9fb56, 0xccd5cbc4, 0xbae93ef6, 0x3355047c, 0xee3735d9, 0xfff1a05a, 0xcee85acf, 0xfe6880d6, + 0xd36b3c03, 0xa0993162, 0x26a19376, 0x794b5fe8, 0x1965a507, 0xdbe0aec5, 0x7d4fd30c, 0x21af936a, + 0xe26776a5, 0xc66ed883, 0xf9ecd8ea, 0xe92dc606, 0x018ecb40, 0x0afc98c2, 0x33de605b, 0x7cd73ac6, + 0xfa36271a, 0xfd1358c2, 0xb0ba1706, 0xc2a27899, 0x6a3970fa, 0xd420cddb, 0x785aea1b, 0xf69a5850, + 0x10cb44b7, 0xbb6c1356, 0xf945e9b5, 0x6b916a2e, 0x9fff43cf, 0xdd24aae9, 0xe69dcdb4, 0x44a2b140, + 0xad76f307, 0x6b288d5f, 0xd2a959f9, 0xc40ec7d5, 0xeef525d3, 0x6703a294, 0xce8b9278, 0x54cb7403, + 0x456e176d, 0xb40a305f, 0x3d1c57ee, 0x6e9779b8, 0xb20d299c, 0x2f9931a8, 0xdb8d7241, 0x7b072093, + 0xdadf4762, 0x19109741, 0x6e62aeee, 0x861a27bf, 0xdc01854a, 0x6fc06370, 0xfa89b2c5, 0xa02aaefe, + 0x8fe55d96, 0x2cd37d43, 0x9ce2f242, 0x33937ff1, 0x532d37fa, 0x84f06a19, 0xa536d1dc, 0x112597fe, + 0x892aef33, 0x1d21d30f, 0x603c4524, 0x35cc167a, 0x6bfbdcf6, 0x42377e20, 0xc5464dc0, 0x10539c0d, + 0xde4a09e8, 0xb5ee19b3, 0x287f36f0, 0x8932e809, 0xced3e69e, 0x4c5da28f, 0x17c679dd, 0x8628c236, + 0x5fd9d1bd, 0x1fa89ba1, 0xd948cb50, 0x5cd51c70, 0x47427607, 0x198db9d2, 0x1e0601ed, 0x3ecf997f, + 0x21ae1fe7, 0x2f934950, 0x8ec88643, 0x79e1b51d, 0x69d18be0, 0x7dca9fd6, 0x22459b95, 0xfbab836b, + 0x0e649a85, 0xee412b1f, 0x2c47db81, 0xbc8f2e89, 0xcc9b0f77, 0xd01537f0, 0x474a004f, 0xc3e3c464, + 0xc6215e7a, 0x06c96520, 0xe9e50b59, 0x18679477, 0x8547ada3, 0xdb49b953, 0x31183352, 0xad823b9e, + 0xec6fddc2, 0xecf4610e, 0x7f6b37a1, 0x3c25a985, 0xe464173c, 0xb60a6062, 0xb93a0a4c, 0x85c3e9e7, + 0xcd232e64, 0xe76f9825, 0xb22dcf00, 0x40b5b2b0, 0x8fd1620d, 0x9af0d795, 0x3196dc85, 0x1726a21e, + 0xde9cd567, 0xd65f1dab, 0x8516a172, 0xaa83204a, 0x6985c275, 0x0e455b13, 0x5f6f03d6, 0x2149c23b, + 0x55fddedf, 0xcb31e47c, 0xcc8b0a71, 0x66c0104b, 0xb94f17b0, 0xf32ca575, 0x910cb0e8, 0xd730b671, + 0xd7ea8045, 0xa3cea49c, 0x0ed93013, 0x891bb31b, 0xa531b609, 0xaee2c75e, 0x0e25e04e, 0x51e3509c, + 0xdef3f65d, 0x88540c34, 0xcd5bd09a, 0x099652c7, 0x7973b3a1, 0xc28ad4fe, 0x3350c546, 0x63511bb9, + 0x61ddbc9f, 0x33b2e6f1, 0x77e1bc7b, 0x9b0f7731, 0xec37f475, 0x38ff8b93, 0xcbe63ece, 0x3c4f8876, + 0x864bffa7, 0xf24099aa, 0xcbec496c, 0x16ccbf23, 0xeca5e069, 0x0974f316, 0xa1862ab7, 0xd1dcb52d, + 0x3df22237, 0x2395fab8, 0x51d98608, 0x99df6ec6, 0x09278a60, 0xea3ff5c4, 0xfc5a1ece, 0x8ae841cf, + 0x23355fcc, 0x4a0e1dba, 0x03170717, 0x08c0b570, 0xbf7375e7, 0x76f3e12a, 0x985fd983, 0x43f30e43, + 0x19a3c0ba, 0xe73c9ce6, 0x2d6a2ab2, 0x46115279, 0x996a1679, 0x1f4cd61b, 0x1dbd2978, 0xb792cf64, + 0x9934157e, 0xaf349f91, 0xe7d71675, 0x71e5bf53, 0xa3e13934, 0xaa0a2d5b, 0xcb3fed47, 0x05ecc569, + 0x23eaf281, 0x118e9657, 0x68fdc7fe, 0x2cfdd9a8, 0x016c5bad, 0x1c72e47e, 0xf929febb, 0x5b0ce71e, + 0x8a3f8704, 0x2ec7158f, 0x6597a3fc, 0xb45e0a93, 0x31acb975, 0x9becae69, 0x30ac2c53, 0x2f0a559b, + 0x561dc69f, 0x1855f1f4, 0x964af187, 0x9728c1ce, 0x87a6fb02, 0x3c719dc7, 0xa4d6838f, 0xc7e248ca, + 0x24d19f23, 0x81513be5, 0x6799a2e9, 0xc4dda870, 0x28a822d5, 0x0ab3d89f, 0xb7385d36, 0x539475a9, + 0xa851ee53, 0xbb90021f, 0x47ec6c57, 0xa2ff7604, 0xcc469c71, 0x9fcdc29c, 0x69dc4c9b, 0x6f2268ad, + 0xacfa7d9d, 0xc2119b79, 0x063fb308, 0x3c754141, 0xcaf3d6a5, 0xfd8f3bb4, 0xa0cca528, 0xbd8a22b0, + 0xa5f7b701, 0xbdfe19c9, 0xa09eca5c, 0x11171fad, 0xe9729f48, 0xff36691d, 0xd240d57d, 0xbbeff23e, + 0x72fd2754, 0x8b11f348, 0xa3f494d3, 0x650ce7cd, 0x742db53d, 0xa8cac854, 0xd9fb00a5, 0x861486c6, + 0xbd1ab6f3, 0xf71e6def, 0xcb4ec151, 0xe2b3d989, 0xccc778be, 0xd096b98b, 0x9701a8a0, 0xd84b337b, + 0x9c009d9a, 0xd0c06804, 0x000393c0, 0x000fc0cb, 0xb268c9e1, 0x85c8b015, 0xef82b71f, 0xba11045d, + 0xaffc0f4e, 0x3dad5c65, 0x3a4390e4, 0xc7340816, 0x647009a9, 0x0fb95f25, 0xe392ca19, 0xfb81c6b7, + 0x43d5edc5, 0x937e0bc1, 0x63eb58ab, 0x23c2024a, 0x0dc4e75e, 0xf6b3f370, 0x76a92e51, 0x9895d410, + 0x375b5bb5, 0x924cb178, 0xd33ed5df, 0x870e1bbd, 0xf77b2254, 0x1a2fa233, 0xefbeb301, 0x01bc5c08, + 0xa4b67edc, 0xd85d43af, 0xeff1f973, 0xb5832bc9, 0x99211018, 0x8ceffc2d, 0x22b7d131, 0xa6941338, + 0xd51b3c88, 0xdbf21478, 0x82e3e412, 0x6baf1b54, 0x5b66c50e, 0x73b7a871, 0xce0a0e14, 0x3ffda492, + 0xb42cf84b, 0x688fdc0b, 0xd350f67e, 0x6034e584, 0x30b0c491, 0x821df07d, 0x33869343, 0xa3e77262, + 0xeec6898b, 0x85fc3361, 0xfaa4eb6f, 0x476c3c8b, 0xf83646d1, 0x3a2cb4bd, 0x15a79c88, 0x4a8e197c, + 0x640c9874, 0xb3884cc7, 0xecc79a75, 0xc8ce5414, 0x94b78666, 0x32d9b690, 0x6d94e6a1, 0x2b1fe24b, + 0x4fad6add, 0xd5f0d663, 0xca1673df, 0x98aa529d, 0x3c040728, 0x242d1dcb, 0x1d0205b8, 0xd344e95c, + 0x4803ab12, 0x488043f8, 0x6ea9bb7b, 0x9b2d8c4c, 0xe67cd8d2, 0x04384ae6, 0x93701695, 0xf892e1d2, + 0x835623f4, 0xd90cae45, 0xa9bcaaf2, 0x2baaa39f, 0xf98a9c86, 0x28296bc2, 0xba881b8d, 0xd2758490, + 0x2739df3f, 0x9216c708, 0xa9d2c417, 0x52a6ba32, 0x4339ce15, 0x546533a3, 0x737ceee2, 0xd41f70ce, + 0x0f7ec7f3, 0x9adf111d, 0x453633c8, 0xc7dddfdd, 0x4d50f372, 0x7a215d39, 0x0744c502, 0x755e903a, + 0xd9cf812a, 0x5b3c4fbf, 0x92537ed2, 0xce229717, 0x7e0fedf7, 0x9556e4fe, 0x69581b9c, 0xf1ad58c5, + 0x26d98d64, 0xa64d7680, 0xa2fd47a5, 0x2f6cac7c, 0x73e65abd, 0x0ec79750, 0x99484a19, 0x9a1e6cb8, + 0x6b2a4eb8, 0xa19014a9, 0x6c6e1869, 0x8832e363, 0x48a54052, 0x5c0b6961, 0x01f776ea, 0xd5c47ad0, + 0x6fed80aa, 0xa6ab303b, 0x23cd1efc, 0x839643b1, 0xc8f03bce, 0x6320e9ff, 0x93eec109, 0xe8ba9701, + 0x04d7768c, 0x01267a78, 0x71fa0978, 0x78a56ed4, 0x83f89ed4, 0x55051762, 0xf6071e7d, 0x205f3f97, + 0xa8eac4e7, 0xb458eef4, 0xc1e1f9a6, 0x9ea93bf0, 0x0a46a798, 0x6b7822cd, 0x0cf2ab85, 0xe5a6dc06, + 0xe317ccfa, 0x5416b7ee, 0xf934ae6e, 0x2b5c057b, 0xc16b8e69, 0x3ea7fbd7, 0x81d57c17, 0x5274a7e1, + 0x083a8001, 0xde244d7a, 0x244a642c, 0xbdd032e7, 0xa6f8a116, 0x4d4a9479, 0x6a7ab145, 0xd14512b3, + 0xda97f066, 0xa71535cc, 0x00ae08ab, 0x95708123, 0x5e4d3143, 0x15931008, 0xbe198b16, 0x71989e75, + 0x13aea508, 0x1f570f2b, 0x38a8fac0, 0x58c0339a, 0x9321bda0, 0x56d1a4e5, 0xfd783d9f, 0x111108c0, + 0x20927806, 0xc0167d92, 0x6b9cacc9, 0x5275d540, 0xf31e3af0, 0x20facc8b, 0x7d708d50, 0xf8f02f55, + 0xbe1df197, 0x7263cf37, 0x4dbb5543, 0x15edd551, 0x3ebf1c65, 0xcc3abda4, 0xa09c9554, 0x81f09270, + 0x7518d282, 0xc16c1e18, 0x1b600dd5, 0x4509f892, 0x7e2955c6, 0x0a122a3c, 0xcdbd5426, 0x3e329f2d, + 0xb5d4d1d0, 0xbe9a3a17, 0xc48a4a77, 0x1e45605a, 0xc5fcdf3c, 0xc67cf5bb, 0x4e387d6c, 0x6a9bf867, + 0x235018c8, 0xedf63e83, 0x6db027f5, 0x68537204, 0xf1cd88ba, 0x8a706d68, 0xe41c85a7, 0xe5a92a58, + 0x7f2d8260, 0x9ea1315f, 0xe58f2627, 0x756d017f, 0xc1ba198d, 0x7b9962e0, 0xd4e31681, 0x2a5727f8, + 0xc2b5e24f, 0x9146272a, 0xff6df454, 0xc78f8a19, 0x94b176be, 0xfc432a76, 0x27842cc6, 0x65839af5, + 0x54a34567, 0x8c41b69a, 0x5ebe51a0, 0xe930d933, 0x0ceb7396, 0x35074ad2, 0x4e807d3b, 0x5d1a9c05, + 0xf586edc9, 0x91b29e49, 0x79bd6b15, 0x69e4f000, 0xd581be8c, 0x3f628e22, 0x2344aef0, 0xbe96c2cd, + 0x1beed762, 0x4db9e849, 0x3ac17e4b, 0xc76dc4ec, 0x8cd36633, 0xa2293d2c, 0xf4e68c18, 0xe61a9ea7, + 0xeabb1d60, 0x3fa3a01f, 0x02e6e0e1, 0x989c55a8, 0x221c69dd, 0x955464a1, 0x561572e2, 0x03f6837a, + 0x75cc39a0, 0x1954bf4c, 0x6d041349, 0x6fb1c171, 0xd74db1f8, 0xa7eb0101, 0xab9e55c9, 0xcacc7039, + 0xf0e27529, 0xfd4c1913, 0x8b6aa1ab, 0x49a62564, 0xec2e4d68, 0x308c0a29, 0x6b6ace13, 0xd4a479f1, + 0x5a43fe58, 0x96286973, 0xe98ddda1, 0x2c20335b, 0xa7c1939b, 0xaed027e5, 0x0784ea01, 0x3e9a76ef, + 0xa7136b57, 0x25b5c71f, 0x70ea9a37, 0x1151323e, 0x421d95fa, 0x64a6fb33, 0x6a391139, 0x79f82188, + 0xd370e2ca, 0x97e1248d, 0xdfb322cd, 0x731025a1, 0xdf79bb57, 0x6dbad0cc, 0x03d1ab8d, 0x3fe1c9c5, + 0x28dc7164, 0x78a35dc8, 0x1260539d, 0x31fa1455, 0x7cffa131, 0xea38859c, 0x247674ba, 0xa590cabb, + 0xc15689b7, 0xb832e662, 0x76227e69, 0xc845a6b7, 0x77c30483, 0x15a01e9a, 0x36cc2101, 0x34b9409f, + 0x50e5c32f, 0x02161015, 0xcc257629, 0xa130f02b, 0x9ac2b55b, 0xe26efdaf, 0x006dd960, 0x90177793, + 0x74553260, 0x6e9b938f, 0x134859b8, 0xbc7e7da7, 0xa6ca1091, 0xadf9f48b, 0x5ccd63b9, 0x1468ab72, + 0x88844417, 0x40bec51a, 0x3e756d95, 0xca77e7d4, 0x03973409, 0x5d8ee09a, 0xac3a75c6, 0x1fbc06e7, + 0xdc8d1dd6, 0x034a2895, 0x4698776c, 0x2ab0a40a, 0x5510c05a, 0x7f3433b3, 0x1951f923, 0xa19f8d0e, + 0xe100dc98, 0x0431c630, 0xf3373db9, 0xe92a273d, 0x75a45b3e, 0xc7c340cd, 0x23958a28, 0x7cb95128, + 0x17ed0130, 0xc83a3e8c, 0x4e613bb9, 0x3c1e4d98, 0xd7d2c74b, 0xce351f42, 0x9c1abb74, 0x2aea9c4b, + 0xa269464e, 0x8c194321, 0xed955963, 0xd4befdde, 0xd9d0fb6b, 0x8d3302d2, 0x2bb73187, 0x8cf15ac7, + 0xf95117dd, 0xbef5441d, 0xc148d70b, 0xadcd902f, 0xfa0ff574, 0x891d6d30, 0x26d0d756, 0x31071510, + 0x1b6ce024, 0xecf79c40, 0x65227e59, 0x0ec107a3, 0xfba5a60d, 0x35718326, 0x5751efce, 0x6f7ce3e5, + 0x888a8f7e, 0x87628375, 0x1da0e23a, 0xfddb00cd, 0xb039c2e3, 0x70f02ba3, 0x7def2fe7, 0x94a55406, + 0x7860d603, 0xd7c0c0d8, 0x12ea029c, 0xcae9da95, 0xdeef67ac, 0x82a0e8d8, 0xbe484ab8, 0xaa64fb1e, + 0x0b10d28c, 0x22776651, 0x1782edd8, 0x1f87a58d, 0x8cfb1db0, 0x7be8f149, 0x6133bebe, 0x315a7beb, + 0x89584ea0, 0x59fdda42, 0x33a49506, 0x44ec2641, 0x75fb4d7c, 0x4cfec5f4, 0xecede465, 0x955f4d2c, + 0x29936dfc, 0x06a3975c, 0x60dca0ec, 0x1f4c8367, 0x9013274d, 0x5a0a0857, 0x5beaabf9, 0x761428ae, + 0x29a3a5f2, 0x1ff2db1e, 0xed0d912b, 0x36ba2690, 0xdb5913f4, 0x7502a66b, 0xd2f33734, 0x9dc1e125, + 0x5efcd9a5, 0xb1aa046a, 0x7e7e03e9, 0x6ea4967d, 0x5e67d240, 0x05359594, 0x94dbdf70, 0xcf55377a, + 0xa263dbb2, 0x72ffe269, 0x50b8fc99, 0xde4f30d8, 0x41b50dd8, 0xbfec2aba, 0x57ef5607, 0x1dab12ba, + 0xf25ab4c8, 0x4dc35652, 0x0a6bd42c, 0xa8d17963, 0x72502621, 0x3ba4a5ca, 0xdeda2eec, 0x830c4fa9, + 0x35f1bfb8, 0xa1070e35, 0x9a798dc7, 0xf1ddce58, 0x390f0bc0, 0x7146d573, 0x92be6480, 0x500cf05e, + 0xff69f675, 0xab229030, 0x1d3835f3, 0x8a100d6e, 0xc53683c9, 0xe80903f4, 0xc537c66a, 0x4109bfc0, + 0x6a79b36c, 0x14c6041c, 0x0d4eedd4, 0x8140b422, 0xb8fc464c, 0xd6e783ed, 0x67e29966, 0xeab31abe, + 0x63604fbd, 0xf703d432, 0x840f4288, 0xb3fc1923, 0xb837631b, 0x3589c626, 0xd79dd77e, 0xfec57067, + 0xb17769fd, 0x3e0666b3, 0x03e250eb, 0x9b6db3cc, 0xbeda7d45, 0x498e0e98, 0xa371d02c, 0x27b87951, + 0x630c4619, 0x26f5c2ab, 0x5adf8efe, 0xfa771b9c, 0x9a7fc806, 0x98fb0767, 0x8efca6c0, 0x4a5041d4, + 0x69f76f8c, 0xb952b986, 0x39cea558, 0x2a30f568, 0x98387474, 0x8aa54fa3, 0x04221608, 0x25902157, + 0xce50f3b5, 0x2487e4d8, 0xedc450c7, 0x708ed75e, 0x7ac503cf, 0x68447254, 0xad0f2d66, 0x18d7b92b, + 0xc2929b5e, 0xd8f7dd64, 0xdc483304, 0x742b7b98, 0xe7e172db, 0x29fa8eda, 0x366c298c, 0xa4cd0eb5, + 0x7596cfbe, 0xcf05768f, 0x29d94469, 0x864e992a, 0x14c9d61b, 0xb3ced04a, 0x753d4f73, 0x0d39aac3, + 0x05a1adbf, 0x1980aedf, 0xd1c6b99c, 0xb807a58d, 0x4a97b439, 0xeb2a56b2, 0xd77f400f, 0xa61bee55, + 0xeef39233, 0x696c2a49, 0x9336ebb8, 0x5671cbf8, 0x1c62a327, 0xf3f4df96, 0xc65a6c40, 0x55d2001d, + 0xe8085550, 0x1ec23a10, 0x0db885bb, 0x9c665197, 0x5813093d, 0xce38be81, 0xf521f4e8, 0x983d24c4, + 0x941b33af, 0x7b9f4853, 0xc6185a1a, 0x7ca566a5, 0x2ca7ad59, 0xb2c6126a, 0x6fd84571, 0xfe90b787, + 0xa0cf878f, 0xd396fe81, 0xabb2ac85, 0x19bb2f52, 0x1647dccb, 0x619e0604, 0x63f1ec95, 0x762f5a50, + 0x403da40b, 0xbabc45de, 0xaa23dfef, 0xf05f5d79, 0x2c670774, 0xb21d30d5, 0xbf4b5b20, 0x3877b5cb, + 0x4da81444, 0xb0e06529, 0x8ac0350d, 0xa01411f3, 0x0910f732, 0xf20d9b91, 0xd2e41f5d, 0x6fc8dc86, + 0x8d5acb1b, 0x8298e305, 0x90e03d26, 0x4972672f, 0xa1d2bd8b, 0x924118a2, 0xc617f501, 0xf795b180, + 0x98ab8973, 0x1f23c5fd, 0x53c6e0e6, 0xd087b5ea, 0x68333aa8, 0x7f71a2a3, 0xbdc92e9c, 0x2c0ad17e, + 0x2ebdb06b, 0xc2db7bbc, 0xeb53471e, 0x962aa771, 0x2087d5f4, 0xdebd3248, 0x8b930574, 0xc719cafe, + 0xb5e48aef, 0x9f2eceb2, 0x4650f663, 0xb20cd6cf, 0xdac7c4f2, 0x708f10d7, 0x6c6a761e, 0xcf0db7c3, + 0x0197152c, 0x72b9c77c, 0x5d952843, 0xd463beb1, 0x021ec51c, 0x7e9fac7f, 0x9b77bf0c, 0x774deb67, + 0x34bbe584, 0x9730a337, 0x6d4bc1d1, 0xaf39b736, 0xdb16f141, 0xddcc75f7, 0x7674585c, 0x3055ad6c, + 0xfbc32403, 0xc0f32269, 0x79278f9f, 0xa97ef997, 0x7787c053, 0x942a8986, 0x18b983e5, 0xcf5645d1, + 0xda190561, 0x8749c79d, 0x7d116f9d, 0x5e98e576, 0xfa7f89b0, 0x82fa19a4, 0x861aace9, 0x2594d721, + 0xe3888be8, 0xfa0f2740, 0x9ac3011f, 0xc1c95050, 0x85b3cbf6, 0x7becda69, 0x1403e34e, 0xbce409dd, + 0x13a179c5, 0x0f0cf095, 0xb8823e04, 0xf7b10152, 0x3f80a7eb, 0xc5ed28ca, 0x83af2216, 0x22446f41, + 0x3ad2a515, 0xf9f30e3b, 0x6ebd1bed, 0x948e0e5f, 0xa7241f49, 0xf9413fc7, 0x59d1fa6e, 0x42dfd728, + 0x35358b60, 0x64d96446, 0x972bd4e3, 0x6ce74188, 0xfaa4c285, 0x553acb89, 0x0765dc29, 0x0b84b517, + 0xcbba2d08, 0x83e6764e, 0x3b652ad8, 0x37d942ea, 0x2c155fa4, 0xbb844293, 0x5036a412, 0x0236fd8b, + 0x4beb28f0, 0xc8a8510a, 0xa1df8ba9, 0x2685fe3e, 0x33f3fb90, 0x238af25c, 0x506c485e, 0x3331519d, + 0x7cdce04c, 0xb6ed249c, 0x7b4737d3, 0x8d4d4ef2, 0xcc776bea, 0xf8b52de9, 0x16c77cd6, 0xfcb69f09, + 0x03c0afc3, 0xea204e50, 0x6a8cc7c5, 0x1153aa0d, 0x264f128f, 0xaa9991e8, 0x32bc1d50, 0x974df95d, + 0x561d324f, 0x06876be3, 0x691c49a7, 0xede30d19, 0xee97883c, 0x2ccb1939, 0xc618637e, 0x19e45f80, + 0x973bd5ff, 0x5ff67eae, 0xe4110d8b, 0x39f1b836, 0x3e89db57, 0x2d9fff77, 0xd54c7d5e, 0x69b8cab3, + 0x7b183ebc, 0xaffeb241, 0x48cd4864, 0x2873889a, 0xca866b2f, 0x9b6dbe48, 0x3834d5d3, 0xdd90d0b5, + 0x6a905431, 0xce866e9f, 0x26085295, 0x2dfe172d, 0xccf4a717, 0x854d2053, 0x1dc5ddfa, 0x97154728, + 0xe9678ded, 0xd29c4ba5, 0x71c28ccf, 0xd3edc759, 0x9fe3b08b, 0xd1decea7, 0x92c025dd, 0xe2ce1d56, + 0xc6383d03, 0xb6af6526, 0xb980519e, 0xe2e6f02a, 0x14cd0b0e, 0xd87c73e3, 0x9671364e, 0x89f4f42e, + 0x695df6fd, 0xcb1415c8, 0xf269d83f, 0x2b5d793f, 0x3120d519, 0x71c34ed4, 0x464082f0, 0x231d4a68, + 0x28f6647e, 0x18b76e18, 0x8a7c9d5d, 0x7c36f1b8, 0x35201640, 0x41c66f61, 0xc98a2c72, 0x4163d5d0, + 0xa24e664a, 0x74d24250, 0x8041484d, 0xa565473e, 0xbc7e62f0, 0x4bd6cb61, 0x78bcae51, 0x3b4ea36c, + 0x1611212a, 0x020742eb, 0x857afb26, 0xb0e6afee, 0xff6046c7, 0xcdbc50ef, 0x6e54cc29, 0x4e597671, + 0x73a7e851, 0x1b283b09, 0x2fb69f2f, 0x86bf1954, 0x72b13ffa, 0x564ed2bb, 0xcaafbd13, 0xf07ddfd8, + 0xba74b8cf, 0x9ff3fcff, 0xc9c88e09, 0x2ec50c39, 0xdcfe7afc, 0xff26a7f6, 0xcc545574, 0xa1bb3cfa, + 0xd6ccd75a, 0x0d885e75, 0x1740dff5, 0xaa84d160, 0xb20f2695, 0x8017c37b, 0xfe28288b, 0x4bc0ef3a, + 0x055b416b, 0xbdc733eb, 0x8d8cc80d, 0x9d4a9640, 0xe25fee25, 0xaf9fdedf, 0x51e982fd, 0x036a55e5, + 0x5ddfb21d, 0xa60f0f8d, 0x4a858416, 0x6476768b, 0xfdbff7d8, 0x3d199227, 0x84776e4f, 0xd0673073, + 0x81a53bb5, 0x7fbccf9b, 0x39e0c368, 0x59dd3897, 0x7c29e0ed, 0xab017189, 0x55663c7a, 0xe0b796ab, + 0x2d42c66e, 0xad15320d, 0x83f25103, 0x148ca637, 0x8eb572b9, 0x78cb5ca5, 0x9239ae67, 0xb20fee27, + 0x8c717e49, 0xe01b4cc7, 0x84a546eb, 0x2ceb1188, 0x25584180, 0x00655d5e, 0xb2e61541, 0xe480bf29, + 0xcc52f2db, 0x6fc8ee6b, 0x31d59d59, 0x717fe93a, 0x92751911, 0x03d7f8e1, 0x4fcd714c, 0x7a54cbe3, + 0x92ccc143, 0x62483495, 0x39993f9a, 0x6bf0ed67, 0xb509fc47, 0xf0d85c77, 0xbdccac1e, 0xef7092d5, + 0x377e580d, 0x14d29f5d, 0xe0df2b2f, 0x34974fe6, 0x1f791539, 0x869c556d, 0x3653c541, 0x643752ee, + 0xcb4a5adb, 0xd148c6b1, 0xea554bcb, 0x0c93eae4, 0x362d4e6d, 0xc41adc28, 0x057d8969, 0x6fcb52b3, + 0x169f5602, 0xe460ec58, 0xf76d866d, 0x063ec714, 0xc82c66f4, 0x68e56c35, 0x291b08fb, 0x7cb99a21, + 0xb5f6f11a, 0xf474f59b, 0x9bf0b73d, 0x7ae9b66a, 0x434b215a, 0x565808b3, 0x082fbfa9, 0xb9f159fe, + 0x7d3a86b4, 0xbf7be3c1, 0xcd2a4ad0, 0xe36f7889, 0xb3270676, 0x54290af5, 0xd90dff13, 0xb375f1db, + 0x01f3425c, 0x5c2acf7f, 0x0e7bf546, 0x0f00e862, 0x53e5e759, 0x41d5b3bf, 0x9fcd06e0, 0x70758ebe, + 0x0478792a, 0x9e1c1f99, 0xe4706b29, 0xd5f16811, 0xd5991551, 0xddd66554, 0x8ca6a661, 0x40947195, + 0x5b3315a6, 0x72b3db01, 0x53873d07, 0x1dcbf8e3, 0x43ac048f, 0x29edb51f, 0xa62d4dc6, 0x6a100315, + 0x26dbffb8, 0xf6d7356f, 0x1d4c596d, 0x7e19ace2, 0x0b2f9fe6, 0x27c753b8, 0xcb20706b, 0x68e253e8, + 0xa3de2ece, 0x963d5033, 0x9c06604d, 0xd7b25f0a, 0xc975cf37, 0x2aa8b464, 0x3b088e7b, 0xeb12a435, + 0x98a8ce35, 0xe506b86b, 0xeb1783fe, 0x620f3dd0, 0x1df3ce21, 0x7bb0fa8e, 0x147a57a3, 0xb25ef3f5, + 0x6bbcafe7, 0x7503f7ed, 0xf8ab19db, 0xe462f6d5, 0x27b2855f, 0x6c97b13d, 0xa85ab122, 0x465ed81e, + 0x9d0f5a0e, 0x14dbcfd9, 0x1ff12788, 0xbb241c6b, 0x71724b04, 0xb7b2c717, 0xb6ffd04f, 0xa7095b96, + 0x0f5bc791, 0x9fed708f, 0x068f0869, 0xb7032fad, 0xcaa223ce, 0x239a2c9a, 0x900b09c8, 0x67712709, + 0xf5f205ff, 0x30d84f20, 0xbcda3ee1, 0x536fbb5a, 0x1b7377be, 0x29cd330c, 0x6f671992, 0xf2a81a52, + 0x5a81ceda, 0x574d1b8b, 0xadd19a03, 0x9126038b, 0xb065064c, 0x8dd6ae84, 0xa75a36ee, 0x3261d885, + 0x7a4d1f94, 0xfc29d2c4, 0xb47ebd88, 0x5423079e, 0x3971fffa, 0x0a8ffc97, 0xc2daac6d, 0x531a5163, + 0xf3cebbe9, 0x8c83fedd, 0xd11ddec3, 0xeab9a28d, 0x2a6a19d5, 0xb31c018e, 0x685a9fd3, 0x5bcba15c, + 0xca68d72a, 0xb95a856f, 0xc978a6de, 0x5c9e6065, 0x7519a378, 0xf21fb939, 0xbf511065, 0x4712c392, + 0x8cb04861, 0xc9ed9a80, 0x4b7d8fae, 0x80899721, 0xdfd39d4a, 0xa0314f50, 0x382bfe08, 0xa93317d5, + 0x1c18b644, 0x133984ab, 0xf788a652, 0x9bab727f, 0xf2ea5762, 0x7630b69d, 0x06cceba7, 0xab6c9700, + 0x4ed5bfeb, 0xa423ca0d, 0x8a0c4b61, 0x70f3a4d7, 0x4f3c6bd5, 0x644c8fba, 0xaf8f9e61, 0xb0c55cfd, + 0x5ed301d7, 0xff820899, 0xb22f92a2, 0xae8f8ed8, 0x8ebd3b90, 0x02c974a0, 0xed6396d1, 0x0b08c816, + 0x32469aa1, 0xdef829c9, 0xfacd4364, 0xb68c88dd, 0x4716f7d4, 0x641409c1, 0xe896d382, 0x6a24949a, + 0xe1094956, 0x6ad76fc6, 0x2c22cde9, 0xdc122ac5, 0xa43c5c6c, 0x3febcd1a, 0x2726bc4f, 0x330a1352, + 0xbe0f2796, 0x3f9f2bbe, 0x1dbef733, 0xf26c425b, 0xe643f340, 0xe2d9421e, 0xcf1e4605, 0x369c8198, + 0xb1b3f1dc, 0x16e3dc24, 0x74ff22a3, 0xb5ef0eb9, 0x208eb731, 0xad146c17, 0xbe908e18, 0x6ad90d65, + 0x3f0360ca, 0xff7cb960, 0x7e237b69, 0xa5993381, 0x40dc3378, 0xa9f926bc, 0xe9a08592, 0xb6d67454, + 0x12f34cee, 0xd3dbd2e9, 0xce4fc54e, 0x717f8017, 0x3dc897df, 0x44726a0e, 0x4623e9c2, 0xcc34a551, + 0x1a5ac8a6, 0xdd826ece, 0x89d96dee, 0xfd22ec01, 0xd5029daa, 0x651d28d4, 0x773c4120, 0x6815acc2, + 0x74e54091, 0xa07bcb07, 0x9b85ff66, 0xc98d9038, 0xa66021d7, 0xffacb64c, 0x400ab073, 0x32c8481e, + 0x61ceba25, 0x888ba41e, 0x3403fe14, 0x427ef930, 0x7189018b, 0xa6c4b9b9, 0x6bc558d4, 0x8955d36a, + 0x8b87f4c7, 0x05f685f4, 0x0a51fc53, 0xef258c60, 0x67375241, 0xd98370c1, 0x4df15cce, 0xba259249, + 0x38526373, 0x0c0c3420, 0x88a6fc21, 0xf5a90ddf, 0x89c598d7, 0x9887760b, 0xc30213a7, 0x0452f882, + 0x5018414a, 0x5b64258e, 0xaecabb82, 0x23753834, 0xcff0bfb3, 0xb0043146, 0x28655029, 0x3f5cf8eb, + 0x158a4cec, 0x9577ed02, 0x8eb772f2, 0x63c9bde4, 0x56e48130, 0x14cc7b50, 0x57332604, 0x69605ae9, + 0x02c2313d, 0xbb722ee6, 0x27cd4318, 0x34d668a0, 0xdec8b795, 0x10a311a9, 0x3ccc3a43, 0xab6fa4ad, + 0x102286fb, 0x94657c32, 0x3f6bb6d6, 0x751527d9, 0xd110b38d, 0x95b3337a, 0x79723903, 0x9d39d963, + 0xbb0d8eed, 0x650356c7, 0x64e30e72, 0x5be7fd20, 0x05b6acfa, 0x06d6e819, 0x852e1d1d, 0xcab58beb, + 0x28f0c491, 0x3b8b792e, 0x0cf39c5d, 0x6099e243, 0x0b4bbd32, 0xa6954d50, 0x2b526e8e, 0x0ca8ace9, + 0x9b566e3c, 0x50e8ad6d, 0x00115c02, 0xcaf6deac, 0xcbc5be23, 0x21d54555, 0x121fb8ff, 0x7f093fcb, + 0x63e62027, 0xe8e178ab, 0x2dccb008, 0x996a0993, 0x84cfdaa6, 0xd591875f, 0x68c8ca94, 0x085660a2, + 0xd93a97f9, 0x21d9c16e, 0x1c17eab9, 0x2095f8b9, 0xbf737281, 0xc2368d28, 0x93d66a8e, 0x7a45a734, + 0x35cc1cae, 0xb45750f0, 0xd5a0851b, 0xe65acc15, 0x5c5a0a80, 0xd8fb0564, 0x48cd4ab7, 0x2aa5d018, + 0x3db6dd13, 0x0a2c18c5, 0x752bef1b, 0x9c4b722d, 0x84d6cb7c, 0x97cdba0c, 0x0a097f80, 0x98ce4f30, + 0xa6fb4bfa, 0x37d3a580, 0x8e7dcfb9, 0xfb69b496, 0x18096a8a, 0x2dbec39c, 0x6cc6dcd5, 0x90ac7c40, + 0x8efed80b, 0xa52fe1c7, 0x1e5f598c, 0xbc4a8679, 0xebe3211a, 0x58f33779, 0x416ddc30, 0x9917ba43, + 0xe55cec88, 0x2fe794df, 0xb6aa34da, 0xba8f112e, 0x30190deb, 0xa7e7e131, 0x171a84b3, 0x82a066ce, + 0xa0d1e4d9, 0x438bcb10, 0xb4583015, 0xfdecdd0b, 0x196086c3, 0x7675cec8, 0xc43cfdbd, 0x04f059bf, + 0x840ff561, 0x73b064c3, 0xb22ea0ca, 0x965f12c9, 0x2b0fd40e, 0x29aa70b3, 0x17d8f1ee, 0x47a40e38, + 0x9cddc307, 0x818cd323, 0x907a56e7, 0x764e80aa, 0xeb8e3b1c, 0xc0c7b6f9, 0x0a06963e, 0x9720c912, + 0xe09fd11d, 0x8b2ca503, 0x9e24cb01, 0x1b3ff549, 0xebdae0f4, 0x0094a44b, 0x21c42a2a, 0x07055bde, + 0x6c2b4b8d, 0xb2211186, 0x511fc6ca, 0xad4a153f, 0x56bbb723, 0xb0b3d05c, 0xef93cb5c, 0xf9d53772, + 0x0d01ca81, 0x94081e15, 0xe670339a, 0x904f0d81, 0xb16b16cd, 0x03314aee, 0xd32845cc, 0x4d64a1a1, + 0xa1d63b7d, 0xdc139d29, 0x456bdded, 0xab061bab, 0xd4539ea7, 0xe623c5d2, 0xd5c213d0, 0x70c3534a, + 0xc4158767, 0x84465436, 0x5e8637c7, 0x688231e7, 0x91010983, 0xbfdd9ea9, 0x3cb2a779, 0x8ce708cc, + 0x6965b801, 0xe7b03ffc, 0xfe2834bb, 0xbc178a03, 0x1a2018a5, 0x5157549b, 0xa4be32d9, 0x53eac863, + 0x33311917, 0x6b198a92, 0xf6b79601, 0xe8041b84, 0x64414719, 0x31289fc6, 0xe8aef24b, 0x9a5d0a58, + 0xac774136, 0x87d91e1b, 0xf91d9079, 0xdbf6c120, 0x0517b9c9, 0x1eda8bd2, 0xbc7efa70, 0xe4dc1276, + 0x3455bfac, 0x9d4b24b9, 0x5fbec86b, 0x086460ea, 0x516d7d1f, 0xe334ab38, 0xbdeffbf7, 0x7a445e92, +}; + +/*! +* \brief Size in words of the firmware image +*/ +#define LR11XX_FIRMWARE_IMAGE_SIZE 61320 + +#endif /* LR11XX_FW_H */ diff --git a/src/modules/LR11x0/firmware/lr1121_transceiver_0102.h b/src/modules/LR11x0/firmware/lr1121_transceiver_0102.h new file mode 100644 index 0000000000..49d0acd60d --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1121_transceiver_0102.h @@ -0,0 +1,1921 @@ +/*! + * \file lr1121_trx_0102.h + * + * \brief Firmware transceiver version 0x0102 for LR1121 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0102 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1121_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Size in words of the firmware image + */ +#define LR11XX_FIRMWARE_IMAGE_SIZE 16604 + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x2ea0c276, 0x6e4de0c5, 0x4cf2c81d, 0xaa275f96, 0x32bb1d34, 0x47de48e6, 0x096992ab, 0x108c537b, 0x45dd8779, + 0x0f5cc4e9, 0x4b855f75, 0x23ded455, 0x01ea9bb6, 0xf856934e, 0x09ce13fb, 0x4c2e5654, 0x39e7c3e8, 0x167f57a3, + 0x5ae8cd9e, 0xd9563336, 0xd166f3c8, 0x298c2f9e, 0xe2193bd7, 0xa5eeaf2b, 0x4a0e0c2f, 0xf67ae104, 0x17d15ac6, + 0x2ba5b843, 0x462c0ef7, 0xe78f0ac4, 0xec8f7e71, 0xfbf8df16, 0x591f1ec9, 0xe1554f48, 0x31d40bc5, 0x88818f7e, + 0xcdb57711, 0x940e2a16, 0x9917571c, 0x0d9fbb1a, 0xa5971749, 0x8e5d8e0c, 0xde3c1ab7, 0x781cfb70, 0x2961a2b5, + 0x95079ca0, 0x10bb9d6a, 0x7684d3dd, 0x304f5912, 0xd09f24cb, 0x4c565c53, 0x1e0c41e6, 0x8becd6e9, 0xeff49ef5, + 0xc2a0cc94, 0x51126518, 0x370efd80, 0xc8f723ec, 0xb83b9112, 0x46544f32, 0x469f7af9, 0x9de10b2a, 0xd6ea91c9, + 0x6ba18d66, 0xda8ba45a, 0xe6fee752, 0x1d606d33, 0x19148a52, 0x77ee58ec, 0x90253804, 0x44ad4ce4, 0xe566bff7, + 0x78cbbcd9, 0x60e940bf, 0xdf5ec03f, 0x12d77bc7, 0x7eda6d6c, 0x136fc2f7, 0x183c9701, 0x52d410ba, 0xc0fe0796, + 0xa64e31d6, 0xd5033efb, 0x812d9437, 0x81438a12, 0x7194f237, 0xd1b11f70, 0x3067cea0, 0xeaa6f7fb, 0x9f006380, + 0xa6738d12, 0xd55ceaa1, 0xff951068, 0x1a999c21, 0x10a5e28e, 0x20b57be5, 0x37812f04, 0xa3697e43, 0xdf027f9b, + 0x6e88e460, 0x327370d6, 0xa460bb59, 0x062c9c6a, 0x898ed7a7, 0x4726ad33, 0xb666c8e3, 0xb7dec6e0, 0x9170cd9a, + 0x7a6d8a92, 0x5798553b, 0xacc01f1b, 0x3faf2e48, 0x4a2e6f7a, 0x118c4153, 0x125c2ad6, 0x4ae18f0c, 0x3ca98d51, + 0x9a8f9cda, 0x1a4e0866, 0x5ae8d35a, 0x62f20ad7, 0x5291b8d7, 0x483b43be, 0x0ba409fc, 0x49ed36fe, 0xdf3f5e18, + 0x80cd0f10, 0xfda2c6a0, 0xe672b3ce, 0x759ef3ac, 0x4d1e615c, 0x667af315, 0x311be689, 0x6a2c1481, 0x46e89400, + 0x947be405, 0x4d3d3bcb, 0x02643631, 0x79f6df2a, 0xd4696a13, 0xef40a9cd, 0x0638982f, 0x5d44fccd, 0xeb2ea585, + 0x01a0a81c, 0x311d26ab, 0xe2583baa, 0x9586e18c, 0x7a51f3e0, 0xfc00a1a0, 0xf46cf767, 0x238b1d7d, 0x976857b0, + 0xdd6079fd, 0x06f93838, 0x9c95948f, 0x0e3016c7, 0x6d82de0c, 0x6dc55b10, 0x8bf6296f, 0xbb7916e8, 0xf0d3c462, + 0x49c19535, 0x08cc100f, 0x9ba49b44, 0xbe19707b, 0x57dcec97, 0x5034195b, 0xc0908ccf, 0x5d0cc1f1, 0x4c75c544, + 0x08c65163, 0x5ff134b1, 0xbfb3f8ec, 0xb349fa38, 0xb47d6be5, 0xdb87b51e, 0x3b38a63a, 0x68e21481, 0x21dff7c0, + 0xfd1423ef, 0xbed4013d, 0x38b9be03, 0x4ddd792e, 0x2d4011e7, 0xcf962084, 0x402ee6a2, 0x532110d5, 0x65c0ce32, + 0xb8bdf162, 0x4c74dd6c, 0x8d77c2f0, 0x852b0aff, 0xe83c0f99, 0xb6ae4edc, 0x9a9dd506, 0x2b270d19, 0xc68a4615, + 0xd27b0920, 0x324398f6, 0xd5b26156, 0xebc857d1, 0x76b0383c, 0x20e4e3a8, 0x676403ca, 0x6f814ea9, 0x60bd6f81, + 0xf59410ce, 0x8b73d2a9, 0x9dc18ffb, 0xac2c84e7, 0x7778eced, 0x750395fe, 0x59fd8a3a, 0x2ffe807e, 0xa89b527a, + 0x10578b20, 0xe0673b9d, 0x3af57e3e, 0x5d61be31, 0x1397df0f, 0x6977c83f, 0xeeea75db, 0x50ac8878, 0x55ee7df2, + 0x052b5b93, 0x19f10f97, 0xe71dd1f1, 0x9a25dc23, 0x4c1144dd, 0x340b1bda, 0xfe776430, 0x9abc9e44, 0x90ce5dc5, + 0x0e44a9e9, 0x158284c9, 0x9768d0b1, 0xc0e365be, 0x8db02a38, 0xaaf8c3a7, 0x0e1e835c, 0x006a04b4, 0xacfd4d81, + 0x1e41e5b5, 0x48ae30a2, 0x2b9da3c3, 0x23985f10, 0x161f2b7a, 0xe1191020, 0xc3c332c0, 0x1941934b, 0x3041f337, + 0x1935d573, 0xd5432bd3, 0xec44b3c8, 0x5eeb7605, 0x8fe14990, 0xfc24966d, 0xb1416286, 0xb48f1346, 0x89fadabe, + 0x620db1f5, 0x8b440db1, 0x1b213b87, 0xb78c6780, 0xc59dcc11, 0x9b6692ae, 0xad752b67, 0x9f2aff84, 0x1133de87, + 0x75382786, 0x105f7c05, 0x7b47fd32, 0x78dce915, 0xf547ddc5, 0xe8b29aca, 0xbf724c95, 0x58f2415a, 0x72244179, + 0x167dae95, 0x87b56c41, 0x9264e515, 0xb84afaa4, 0xf9acb2bd, 0x4e11b4fa, 0x909d30fb, 0x12669ff0, 0x028bbc26, + 0x355b43af, 0x61215f09, 0x60e6fee1, 0x42f1d535, 0xcdd04c63, 0x88a0419e, 0xc803a41a, 0xac048ce4, 0xabe9adff, + 0x148890b8, 0x69e06ebc, 0x4de9bfdf, 0xca1daa7d, 0xdc89ed1e, 0xa508646a, 0xcf0ef96d, 0x05c00e73, 0xfd8d04a2, + 0x670bd5db, 0x2877f8af, 0xbceeab7b, 0xd3c4419b, 0x563cf6f5, 0x76f1a47c, 0x9822433b, 0x2ef857ef, 0xb360de7f, + 0x598b7108, 0x1b7413fb, 0x20f76b04, 0x6a938b75, 0x89944650, 0xc22c73c4, 0xdc28be20, 0x450a4384, 0x2a843dec, + 0xc261827d, 0xb4882b2a, 0xc8e86dcb, 0xa0d69f4a, 0x953d2ffb, 0x28402c11, 0x306f2699, 0x189aa532, 0x15341c98, + 0x562b4959, 0x1b73f7cb, 0x81ab5be4, 0xd4a2276f, 0x01eacba8, 0x27f01970, 0x74e69046, 0xec0540ca, 0x39582b21, + 0x79cb991d, 0xfac1678f, 0x9c665761, 0x3cef9e2d, 0x6208bd81, 0x50e0a87d, 0x7c9a868e, 0xcdfb5dc1, 0xffcca57b, + 0x7384b92e, 0x5b6d22ca, 0xbfccf810, 0xac14d037, 0x6090dd1a, 0xf029da9b, 0x7b35c283, 0x01f606bf, 0xc27a72af, + 0x34c68252, 0x55d23bd3, 0xf4468c8e, 0xff510339, 0xf072e67e, 0x512410df, 0xceaba164, 0xf657c6a9, 0xaccfae18, + 0x3ac4f3f0, 0x26f27ba5, 0x25693019, 0xc8f3365a, 0x04a34a1f, 0xf55711ec, 0x019cc412, 0xce8b5ee3, 0xfb921f4b, + 0x29f6a5b0, 0xf55d4897, 0x970006cc, 0x99147ae3, 0x859ab5fc, 0x449e3ca1, 0xe6479bbb, 0xe3364d50, 0x75abc7ee, + 0xa79063d4, 0xc76a7720, 0xc61c19d4, 0xdf912c9c, 0xca622bd6, 0xd54e8ddc, 0xba0071e1, 0x1555a9c3, 0xe5ea0ef0, + 0x33acf21d, 0xd5993a01, 0x25e4825d, 0x80faf8e5, 0x27df56c8, 0xdd089a6f, 0xbac1d557, 0xc10c5346, 0x0dd2978e, + 0x782f2478, 0x8376ba46, 0x2c57c30b, 0x41fe72b9, 0x6346c84f, 0x1c35da33, 0xf958d5f1, 0xcadc9aa2, 0x9980a9b1, + 0x98a8de8e, 0x28c8ad37, 0x448f90c8, 0xe696152a, 0x8f6a717d, 0xf454fe4e, 0x7fbba82c, 0x456695cd, 0x008e609b, + 0x326e1591, 0x6169399a, 0xd78d918c, 0x133cd60c, 0x67d68595, 0x40a37633, 0x55a87c66, 0xf5e35128, 0xe2d4d9c0, + 0xf466642c, 0xe59e6422, 0x00c97eb8, 0x5836b698, 0x54840d94, 0xdfc81740, 0x74abbbf5, 0x3acf0974, 0x5f070e84, + 0xeed5f5ab, 0xc199a700, 0x9afc264b, 0x04433ee2, 0x2e45f167, 0xf6f4373c, 0xa336121d, 0x938048cb, 0x37ea0cc2, + 0x2db67d7c, 0x1d8a4fb5, 0xe15a564c, 0xe4222dd2, 0xaf47c73d, 0x6a7a6185, 0x1059e1a1, 0x10945bbb, 0x5b3e2695, + 0xaef27a38, 0x8a9c831e, 0xf3deb6ce, 0x769db12f, 0x6f792574, 0x9289787b, 0x144c603f, 0xe60bca75, 0x716d2ded, + 0xe5b5843c, 0x52efcc04, 0x1532e238, 0x9843ef54, 0x94e4fb8e, 0x588f4305, 0xf796f4ec, 0xf413e910, 0xa193ed14, + 0xa9084a37, 0x2db5271f, 0x41bea322, 0xffb528b7, 0x8f6e9f5f, 0x6b8fdcf0, 0x5c853cff, 0x0ee0ae99, 0x473ce598, + 0xea491e04, 0x6c495244, 0x1be66c90, 0xd747b1e5, 0x01dab1e1, 0xe4439a27, 0xa0b4b76d, 0xa86f98fd, 0x5d947a71, + 0x2d385faf, 0xfeaa3ed5, 0x47fb4c5a, 0xe3a67f15, 0x434569b1, 0xe0e46b05, 0x34fe31ac, 0x386f77dd, 0xa9c918c1, + 0x04441f48, 0xfe08456d, 0xcef31b7a, 0xfb3d85a8, 0x6f94cb9d, 0xc085b6b1, 0x82653ba2, 0x3cbb2798, 0x70a85aca, + 0xf69e8d10, 0xd05fc0c4, 0x8743b18c, 0xa4fa20fc, 0x8ed715e3, 0xf4a17002, 0x7a215abf, 0x5b5afb41, 0x986a11b0, + 0x08cd1a9e, 0x07c3e6b1, 0xa8803817, 0x1043cc5c, 0x6e572d75, 0x8ff7fceb, 0x5f93c07e, 0x83b83c54, 0x498a6277, + 0x953f5758, 0x995045dc, 0xe0c874f4, 0xbfb238ec, 0x90461a16, 0x05df4b8d, 0x317275c8, 0x650f44f3, 0x9df2122c, + 0xb82a276b, 0x46c1e38b, 0x012664c1, 0x3d581c2e, 0xb4fc99c2, 0xf2c1309a, 0xe14d6e7f, 0xd11eb55f, 0x05b0e194, + 0x9672e0ab, 0x374b0385, 0x7adaf5ac, 0x6da8ed5d, 0xe8846df3, 0x3c850b3d, 0x55782351, 0xecab569e, 0x933b8782, + 0xec2cc555, 0xc10f9657, 0x5f2cb53f, 0x47bdc6f8, 0x611e63ca, 0x5d69380d, 0x78a526e6, 0x6496c1ea, 0xf478361c, + 0xea61b0e3, 0x28b94f58, 0x4a29438b, 0x7dcbba36, 0x3256fe17, 0x260f5448, 0xbd9ab746, 0x1593eea8, 0x2ed778f9, + 0x96c95c3b, 0xa94eb9ca, 0xe03b81aa, 0x812ddc20, 0x81139c9e, 0x7872034d, 0x9d3d4323, 0xe5770d21, 0x7971bfdf, + 0xa97d2b90, 0x01821599, 0xa50ecbe1, 0x8b4aeeff, 0x99b04f63, 0x3e312696, 0x88fbcb38, 0xe76308b4, 0x4f2cd5ea, + 0x40975b18, 0x49533d45, 0x0c2eb719, 0xb0240f9f, 0x9b28d3ea, 0x6901039e, 0x0cab54b5, 0x1b0d7e6e, 0x5c4895b7, + 0xbe17ed9d, 0xf4acaa27, 0x8131078a, 0xa22fe07c, 0x1f6a413f, 0x0d3d7c1c, 0xc3c8e756, 0x12f816cf, 0x1139a259, + 0x27653853, 0xe540c86a, 0x156282d7, 0xc8040062, 0xecf64df1, 0xe9bd1e06, 0x78a5a636, 0x0b60263f, 0x121dec83, + 0x028b0a77, 0xc7d29394, 0xbaa2013a, 0xec4a292a, 0x16da6482, 0x169c994b, 0xf89724ae, 0xc62c0c04, 0x4349e0dd, + 0x5d4f0d62, 0xb8375941, 0xcb251c97, 0xa6dd61ef, 0x3a1b4d53, 0x64993b03, 0xf8d0aac8, 0x951549f6, 0x466ca869, + 0x571dcf1a, 0x273337cc, 0x9ebef1d7, 0xa589a101, 0xf0655d59, 0x4b186aa7, 0x232150a4, 0xd216e796, 0x18e37df9, + 0xb0954a45, 0x1a1f0bb9, 0x07726751, 0x70bcc01b, 0xdbd408ce, 0x4ac74629, 0x008db40c, 0x5384107b, 0x10c14cc1, + 0xbe16e269, 0x09b5419a, 0xc8e9d041, 0x82bc336b, 0x35c62c8f, 0x6ddbdc78, 0xed311d6d, 0x920e9cb7, 0xb13640eb, + 0x5b47c593, 0x7dc48503, 0x79c1db87, 0x691d5395, 0x126d0425, 0xd402a7bf, 0x0c51d518, 0x8457cea9, 0x25e53db3, + 0x4953fad6, 0x18da2a4e, 0x039daf3f, 0xc03673a5, 0xfb05623a, 0x62dccc7f, 0x9626d9d7, 0xe34899ef, 0xd5f9c230, + 0x5b5a97a7, 0xfb0f451f, 0x3d509154, 0xf4104446, 0xd2c3e534, 0xcab6ca77, 0x49f5512c, 0xe55d95e6, 0x4bbc6780, + 0x486e6735, 0x2f951337, 0x15955a30, 0xfd7cdd13, 0x8ff094d8, 0x3ebb366f, 0x919ab040, 0x2372e5df, 0xaf840d18, + 0x9ba06076, 0xd9955adc, 0x7dedf8cb, 0x610fb1b0, 0xebf6e8a0, 0x504fecd8, 0xb4d664ea, 0xb7b0f295, 0x0ec6a182, + 0x55e63f93, 0x6e58619a, 0xb4e58826, 0x28903ab6, 0x6a144499, 0xec53d99f, 0xeb60069c, 0x3bb8507a, 0xb5cf4ba6, + 0x959c6bb3, 0x6c5d2835, 0xe54d35a4, 0x8ce92e37, 0x8a8e4207, 0x6e7ddbff, 0xe079f01c, 0x85f13d2c, 0x35d7b581, + 0x6b830bc7, 0x2754d7b2, 0xd843eba1, 0x2899ea93, 0x41aacdbf, 0x48bd0830, 0x7a411f30, 0xa050daeb, 0xc2252413, + 0xa6c0c68f, 0x86624499, 0xd91424eb, 0x01fa540c, 0x1209082c, 0x2beb5e27, 0xbc1942bc, 0x277bc2b1, 0x67d62300, + 0x84f95cdb, 0xccad6491, 0xe640ec16, 0x0c61b810, 0xe0533837, 0xb3f1a882, 0x143d5a7b, 0x2242a2fd, 0x1f8a660c, + 0x20cd8e16, 0xdc63eb3c, 0x5bcacdc6, 0x513137d9, 0xfe1539bc, 0x5534b9f7, 0xcf0cbe22, 0xa6a9660a, 0xedb1cb60, + 0x78662fac, 0x2a1ebb3b, 0xf9103897, 0x78631f9c, 0x81b084b0, 0x94fff1d0, 0x05b2f7bc, 0xf38e13d2, 0xe663018d, + 0x2aec71d0, 0xfe88ca59, 0xedc67eb6, 0x7e1c27e8, 0x31527b0c, 0x250d3e7b, 0x0d54c91c, 0xb0e4b535, 0x530a3d47, + 0x487237ac, 0x13ffa347, 0x6111c0d6, 0x8f6d2400, 0xf7a66783, 0xaee1939e, 0x8e4c802c, 0x68ab0bdb, 0x9997fbaf, + 0x12080868, 0x03c1c6d1, 0xf05b7afa, 0xa39c88f7, 0x8c67e588, 0x720e8437, 0x45b869e8, 0x167fd164, 0x50ab3495, + 0x1c223dd9, 0x229dfff1, 0x0ad0eab9, 0x59c8da20, 0xce935ad6, 0x6332f91f, 0x39f62538, 0xa49c029e, 0x233ff99f, + 0xa1528215, 0xe2797b7c, 0x86cabff1, 0x5df21fd8, 0x3e18deed, 0x317a8ad4, 0x048ec35f, 0x514f302b, 0xcefa4cf8, + 0xc6c8f588, 0xe4efb6f8, 0x855e70fe, 0x3beccb98, 0x668645e2, 0xfc418622, 0xaf1b3960, 0xd58a9a71, 0xd5ead730, + 0xd0173395, 0xc9015665, 0xe2d6edd2, 0xbf7d4af6, 0x5b4a15ef, 0xda35bac4, 0x1cc87d2a, 0x99bc2ace, 0x0012a958, + 0x3e043788, 0x9b02ac8e, 0x5de22a56, 0x39a98c5a, 0x94f2b977, 0xd583d740, 0x64dba4a3, 0xa02beea8, 0x80633a39, + 0xbed9d176, 0x744ecca2, 0xb22e1d3a, 0xa5e5f7a7, 0xa1f987a5, 0x3852a2d5, 0x91be1191, 0x38b07aed, 0x628715df, + 0x19e6abdf, 0xf70c891b, 0x0ad380df, 0xa7f08d5d, 0xc7e2bc92, 0xa0328b0e, 0x2bd615ae, 0xe164a7e5, 0x187e56fa, + 0x8e8619e4, 0x8353968f, 0xf39dc3ad, 0xbb8b706d, 0x270044fb, 0xdea6bcb3, 0xfe5fe18d, 0x9e584e4a, 0xd4002aaa, + 0xd116a794, 0x01bd30ed, 0xf4709509, 0x1cf35643, 0x90d74fac, 0xb1203378, 0x593eab56, 0x8abc5a29, 0x8b4509bb, + 0x0b576a21, 0x3f470859, 0xd0516523, 0xc6da69de, 0xfb69730d, 0x8a476e1a, 0xa5f75b20, 0x8c956308, 0xf555bf49, + 0xe74278a6, 0xdce73674, 0x2953fa76, 0x71495108, 0x578a4aa9, 0x6ecfd365, 0x7a0083ca, 0x5b5575cb, 0x8df7068f, + 0xb36319d0, 0xd0b6d2ab, 0x327ecd08, 0x1cb3cb2a, 0x4e56b862, 0x25e5b7ce, 0x40e53b90, 0x13af46f1, 0xccda7d40, + 0x2ce7d6b2, 0x8839bb4b, 0xda40b71b, 0x63c640bf, 0x679c790e, 0x2b214e90, 0x7f6635f5, 0x8c155daa, 0x0ab93a06, + 0x3e12ca98, 0x3f5a04ff, 0x0862fe0e, 0x64f50dd9, 0x02d4aa1e, 0xc0260b68, 0x5489dfe9, 0xf3cdbd2e, 0x76575934, + 0x79546997, 0xe65ba2fd, 0x601cfc7d, 0xd05c653e, 0xd6bb58f1, 0xe8e5db22, 0xc639acaa, 0x6325174c, 0x6dd2c75c, + 0x8ad68aa0, 0x140e9f14, 0xf9c05f73, 0xe393b2be, 0x3135b034, 0xbdfde8d3, 0xe92d628c, 0x8987e097, 0x0acd6a92, + 0x18ad03e6, 0x9beb43ed, 0xd10abc8c, 0xb0b5f891, 0xf12e3c00, 0x94cadd1c, 0x62e001e1, 0x16595c02, 0x133f5c53, + 0x484b79a9, 0xf085d7d5, 0x4460b47b, 0xb3bfd531, 0x69678bc0, 0x804ca87d, 0xb0f75cb8, 0x3d8e0b80, 0x67a60b2a, + 0x62ed01e9, 0xec6728a7, 0xc0e1563e, 0xe2793d2f, 0x22f09861, 0x53f0c782, 0x068eeee2, 0xd8d4fb1c, 0xa3016ade, + 0xe61c6c93, 0x6a30d8c9, 0x20957875, 0xa3463b4e, 0xe481b5c8, 0x53f718f4, 0x8f2d0489, 0x4d511454, 0xb4682c08, + 0x4b0202f9, 0xa0701ea4, 0xea7a4742, 0xb3439ab7, 0xda6c873d, 0xa41d1041, 0xa4c1bc2c, 0x1c7f4f3a, 0xfbdb1fa0, + 0xc8b94ebf, 0xcaa44f9c, 0x6fe50908, 0xab9243d2, 0x66236ef9, 0x7a4f8d3d, 0x812b4ab7, 0xeaf26a33, 0x70427175, + 0x32a30cd2, 0xe7c62bd9, 0x0f343884, 0xc69879a8, 0x416520ba, 0x8ad70de3, 0x167ecd4b, 0x313bab31, 0x8315b092, + 0xa8c2e93b, 0x558be0b3, 0x22b54936, 0x3766b492, 0x531650e9, 0xe6b28f1f, 0xe9027ef0, 0x678c1a4d, 0xf6009944, + 0x7ff2ea04, 0xffcc1ad2, 0xff518d27, 0x90fabd75, 0xe8fee8ae, 0x27197b90, 0x8d6f3e2a, 0x563330f9, 0xe0f9ab11, + 0xa3bb32f4, 0xd512f721, 0x965bf591, 0xfbb7f0e8, 0x9cdbb91e, 0xab477071, 0x74ffe8e8, 0xef0a8de1, 0x4b46bf6a, + 0x213d175f, 0xdf8b998a, 0x6a211a8b, 0xd4c1e7d9, 0x8eddb4c9, 0x6d6c3cb2, 0xc58f6d12, 0xc94677ff, 0xc0e1c8c6, + 0xbb845f97, 0x47eae714, 0xa6e592be, 0x62d14bd1, 0x3f04d865, 0x864beae2, 0x5e838f35, 0x8e29307f, 0x82a70ca9, + 0x5605dc7a, 0x303bcdeb, 0x81f770b7, 0xf275585a, 0x410b4555, 0x04d66e7e, 0x2a2eea0c, 0xe11b8740, 0x24c58d7c, + 0x94817651, 0x66974a67, 0xe3d8304d, 0x4de59561, 0x6b8faf44, 0x6f9bb66a, 0x590ce562, 0x8698ca8e, 0x12fd3a4a, + 0x8441985c, 0x4180ef71, 0xaf8215ad, 0x39485506, 0x8a042601, 0x1e5ffb40, 0x45d64a6e, 0xaf94e801, 0x55d97b19, + 0x19c8146d, 0x96550bf0, 0xe852f596, 0x697bf9d5, 0x268220ac, 0xcdb0b5ee, 0x0e07bfe5, 0x83d9e571, 0x42d08408, + 0x33ccbfb2, 0x0b6c5ba0, 0x6652bdf3, 0x17a676a4, 0x4d84d94f, 0xc72357cf, 0x0789758e, 0x5100dd5d, 0x3df52b10, + 0x4c44b70b, 0x8dc24b72, 0xfc1a07e6, 0x928ab35f, 0xe492606b, 0x8fd1a9ba, 0xbbc2f016, 0x2769231a, 0x92a065cb, + 0xc27f3a0a, 0x7051336d, 0xbcf3ec19, 0x4733a0df, 0xc23211fb, 0x0df40450, 0x55aa426f, 0x388e29ac, 0x23df95d4, + 0xf4011be1, 0xab5018ef, 0x7215dc81, 0xde0f9727, 0x3a07f6b5, 0xc61ba482, 0xa839e562, 0xb4b4d983, 0xff13ff8e, + 0x84809a01, 0x79164d69, 0x8656aeba, 0x61a528f7, 0xeb3a5052, 0x59b10bcb, 0x4fc40328, 0xd2d215d2, 0x4f03ce7a, + 0x471b3523, 0x888cd03d, 0x957bd7f5, 0x1f90a750, 0x4499e27b, 0x6d476dde, 0xc222db85, 0x1433b387, 0xc3eb4311, + 0xff937d46, 0xf05f66f6, 0x45c76753, 0x659b0e9d, 0x0a057ec8, 0x394d0cda, 0x4904dedf, 0xc77d9fe3, 0x9274d0f6, + 0x690b9f3e, 0xf31c5365, 0xb82591e7, 0xa38a1876, 0xdcd52fc2, 0xa65ee824, 0x70a8603a, 0x6dfcf93e, 0xdeafb0a7, + 0xa884e602, 0xd8d51127, 0xf5d91678, 0x11b1ddbe, 0x89de912c, 0x0d260661, 0xb953df22, 0x979c3981, 0x973c9809, + 0x98b5cb11, 0x22631ce2, 0x735c4801, 0x3d568abe, 0xdcc049d1, 0x9f705b7a, 0x9d65d720, 0x7363be5d, 0x17662de2, + 0xa840cf8b, 0x0ec4ced2, 0x611923ed, 0xa5918b1b, 0x3125275e, 0x06a29618, 0xff672572, 0xcf6c86a6, 0xe877e7a5, + 0x824d194c, 0x9d39b6d9, 0x1abe905b, 0x52daeafb, 0x863831da, 0xd56e0620, 0x8c9133e7, 0xffd9f8ab, 0xe9f0121a, + 0x8942efff, 0x03a7d8dc, 0xc35e038a, 0xd9a73741, 0x6843bcf8, 0x8061d3d3, 0xa85eb679, 0x78c8f79d, 0x1403a632, + 0x23149508, 0x20c54c25, 0x8748cfeb, 0x947a5f12, 0x6ae32934, 0xd68bb6f9, 0x049d8b22, 0x7ca8318d, 0x0c4d7946, + 0x057eb1aa, 0x404c1757, 0xa60edd60, 0xd24860e9, 0xaa6a306c, 0x22e765ab, 0x28df63cc, 0xa4d43557, 0xf3dc0113, + 0x0a190c11, 0xdd622e09, 0x7d22a1b1, 0x663f6e72, 0x09078383, 0xee680e24, 0x3ee956b1, 0xbd009c48, 0x251a108b, + 0x31ae1a85, 0xde3297f5, 0x30168fd2, 0x17ed22a1, 0x354c04d6, 0x6671590c, 0x27d7364f, 0xde51faee, 0x8faa7e3a, + 0x707f4b9e, 0x41bc08cc, 0xc0329610, 0x94a0525b, 0x29291684, 0x4ec32831, 0xba61bd3f, 0x6be4f6fe, 0xe575fd8e, + 0x9ac412b7, 0x010d081b, 0x578515bc, 0x7907c379, 0x2e1e9d14, 0x6d8a57b5, 0x288d27ba, 0x3edb1578, 0xf16c153d, + 0x9dfa545a, 0x73f132ac, 0xf98b0aab, 0xc483d202, 0x425fbd5b, 0x7c240919, 0x0e148a75, 0x972a02a6, 0xa8bb8ac2, + 0x8abc3b0d, 0x5b911c78, 0x1751585a, 0xb987ee24, 0xb6c7e9b0, 0x7848e393, 0xafa0f810, 0xd74c4c54, 0xa1e156b2, + 0x0293ebdd, 0x66bad1e9, 0xee86bd28, 0x8c928007, 0xbdb37038, 0x660d8054, 0xb35f9b66, 0x9668315b, 0x3944cbf7, + 0xda224139, 0x605af7c5, 0xeedca516, 0xfe40f443, 0x2bc392c5, 0xed1dacb3, 0xcb9e5802, 0x8a14f1d4, 0x621b6c8f, + 0xfc9343cd, 0xdc02fcba, 0x9eb64778, 0x210d31fb, 0x6152b066, 0x768acb37, 0x1e31a4cf, 0x15a0710a, 0x3e2e0a02, + 0x48d80ba6, 0xbe5f0f81, 0xbae72df1, 0x039924c0, 0x0da67edb, 0xb3beacbe, 0x24aebeff, 0x592f1f48, 0xd714a7bf, + 0xfab7c364, 0xab86e291, 0x0fa8e2a4, 0x0ea46863, 0x10813871, 0x6e367196, 0x740288df, 0x17f63a19, 0xd58175da, + 0xb1759936, 0x18e386b4, 0x48b3bfae, 0xbb7a677a, 0x2abf1bc0, 0x57e532ae, 0x78a2d166, 0xeea8cb2d, 0xb290933a, + 0xa6a973aa, 0xd30879f4, 0xf793830e, 0xf4d11bb4, 0xf899eec5, 0x787303d3, 0xec80e58f, 0x8427be19, 0xa6fb0120, + 0x6ac4d7b5, 0x60aa239a, 0x7b6436ba, 0x81ffe3c3, 0x8d40c865, 0x510ac0c3, 0x90a89b64, 0xc491d71e, 0x919ed88e, + 0x67e310c3, 0x37fd9ff2, 0xe9d91714, 0x81fd6582, 0x614d6b80, 0x30767104, 0xea48cdf8, 0xf8be9b10, 0x6b60c2a7, + 0xb1f649d6, 0x69a05418, 0xdb5c70d7, 0xad2d5521, 0xd7e80a20, 0xa6e3b306, 0x263c90cf, 0xbfd30910, 0x6c903798, + 0x5349ac17, 0x3a1d3bb8, 0x7888c98c, 0x357431ad, 0x29cb83bb, 0x8159513b, 0x9315eea8, 0x1706c2ac, 0x240cddad, + 0xfc9ea962, 0x217ec572, 0x429bf78f, 0x836a3aaf, 0x5225163c, 0xf4dada31, 0x8b0985e3, 0x86f4c289, 0x937217a4, + 0xdbf172ac, 0xb1110ab7, 0xba39c3c4, 0x0622b3aa, 0x8d6b94bb, 0xf07a3c68, 0x97a4b4fd, 0x0324ffd7, 0x207c500d, + 0xe8c1a355, 0x561d82b1, 0x06cd2598, 0x4c4dde0c, 0xf65e9f95, 0xb23d6706, 0x50a504b7, 0x45ade60d, 0x74d2a8cf, + 0x123f0fbc, 0xd3a81111, 0x911f1dbd, 0xb32d99d8, 0xdb343783, 0x6a383887, 0x712c9044, 0xa208f391, 0x40bb9a80, + 0x8f58f15f, 0xb67379b2, 0x434716c3, 0xeb0ab89f, 0xdbbeef9b, 0x253ec6e2, 0x5f175e40, 0x3cb6c039, 0x60d3c626, + 0xc43510a3, 0x7579a7d3, 0x3b1e10e1, 0x10e1ea72, 0x6e78176e, 0x110a6471, 0x24989c51, 0x6b0bc3b5, 0x9206611c, + 0x343c01d2, 0xcdd6ed7f, 0x34ac91f0, 0x1569f5b7, 0x49d47b08, 0x4472f423, 0x08c80925, 0xc3d6c55b, 0x6ec7eeaf, + 0x79fe6f90, 0x42ab435a, 0x6663e106, 0xf389bdb4, 0x848b17bd, 0xf28f9fd2, 0x33e24176, 0x69db3abf, 0x1b109a73, + 0x85f2e72e, 0xf157f9ad, 0xf09eff8e, 0xe0198974, 0x6792e5ef, 0x5887db67, 0xfb1bd71d, 0xc0b6cc47, 0x70f259ae, + 0x38dbc05e, 0x44a5dbc3, 0x1bcb6dfb, 0x11f51637, 0xb7075baa, 0x570b95d0, 0x81183034, 0x462d10db, 0xa266c85f, + 0x7b026faf, 0x75ac8542, 0x6971c732, 0x8c308ea7, 0x8d244bae, 0xb9642297, 0x02a8445b, 0xd1effa98, 0xba6ba2c9, + 0xa2ad0095, 0x3717b731, 0x6d4ef7d3, 0xea737716, 0x3e0d5595, 0x5cd4b1dc, 0x99903266, 0x24650fe3, 0xb3ebe723, + 0x7581c71f, 0x4e6971e9, 0x897f0c70, 0x49447e44, 0x41f483ec, 0x5bfe0b2b, 0x35186e56, 0x4b08e072, 0x831b91ef, + 0xdce69fcc, 0x33136ade, 0xe68bd868, 0x44bf3870, 0x8032dc85, 0x75bed710, 0x5892600c, 0x9759a135, 0xb9a1103e, + 0x5ce2121f, 0x5fb00d7f, 0x703ea6a8, 0x31099d7d, 0xfd387fba, 0x61eef1f4, 0x3179f9e5, 0xe5980cb9, 0x22afc8c8, + 0x7a58468a, 0x183d8fd3, 0xbda6413e, 0xf42ba06c, 0x25e7bfab, 0xe8da9226, 0x58e8af9b, 0x34373d6e, 0x47fd4624, + 0x9e5c3342, 0x4eb45dd7, 0xc2f9ea3b, 0x81397a45, 0x2265063a, 0x73b69e0f, 0xe78e9b46, 0xa66ee35e, 0x321799ea, + 0x9d80057a, 0x9b1ccd84, 0x0b98ba50, 0x3c26c9dd, 0x7dd3d40e, 0x97b093e3, 0x7eef8a9e, 0x82fb2bb2, 0x745c75eb, + 0xe0edceb2, 0x499064e2, 0xfa483635, 0x383c166c, 0xdb7b5eb0, 0x44799e1b, 0xa3604985, 0x645fe667, 0x70405746, + 0x56148378, 0x695e28d7, 0x5c592227, 0x5c352420, 0x140e03f0, 0xbe51eff4, 0x7f617b60, 0xb005b456, 0x9a56877f, + 0x2d941c2f, 0x75f138f9, 0x9ee05377, 0x1bef5d65, 0x6db1facc, 0x06870c3f, 0xd224e181, 0x3165d53e, 0xa97e5b51, + 0xd7de9ef2, 0xacaafe1c, 0x2182ecb5, 0xbcaf24ff, 0xde6dc72b, 0xe58598ad, 0x05f8a4a5, 0xff2bea0e, 0x07f21fbe, + 0xd149a0c0, 0xaf8f6cf8, 0xaf90face, 0xdf9d0cd6, 0x68a1c0ce, 0xb27aec49, 0x534b4de5, 0x6c4802c7, 0xb3b61af8, + 0x377719d7, 0xcb863931, 0x73fc23f8, 0x5573320c, 0x44d443bf, 0x91265d36, 0x47990833, 0x27691524, 0x77a9309b, + 0xedd82e07, 0x46b232bd, 0x1b72b52a, 0x183183b0, 0x2398aac0, 0xa1f13ae6, 0x596bf5b8, 0xcf55822e, 0xff3fb9a7, + 0x962b8a1a, 0x6e5f8fc3, 0xcc1d5ea9, 0xd0fb0bf6, 0x592c314f, 0xf2ac0cb7, 0x97e4b0f4, 0x5219537b, 0x8074b167, + 0xaf495c81, 0x77f44f0d, 0x0698ec3e, 0x4429d908, 0xec357920, 0xdd8ccbb5, 0xfeb35f96, 0x32ca4c93, 0x5a678869, + 0xa5f2ca87, 0x9bea2d72, 0xfe350691, 0x365f38d6, 0x67ac19bd, 0x0a1c536a, 0xf1e6f098, 0x68a47b21, 0xb1953a97, + 0x4c653551, 0x0e138255, 0x12488c15, 0xf276fcd9, 0x70558656, 0x1a891032, 0x76e06d94, 0x224f0fc3, 0x446e7fd2, + 0x2c2dd564, 0x5c5b8fd7, 0xe495d496, 0xc89acacc, 0x5c8865c7, 0xe5ba3842, 0x2c753d9c, 0xd62096e2, 0x3c450737, + 0xc74d33e1, 0x18465cf1, 0x52aca5a5, 0xcf2916ce, 0x766f762e, 0x6d4097ad, 0xe20c951e, 0xea842399, 0x8460d97c, + 0x92a31835, 0xe6beb644, 0x259c8ab4, 0xa33284df, 0x2798fde3, 0x95468abe, 0x44c6387d, 0xca257637, 0x943f7e79, + 0x8165313d, 0xdc741313, 0x858e7424, 0xca81e5ec, 0x70ccc9cf, 0x13f0614a, 0x55492547, 0x02d85a34, 0x47c20df1, + 0x09b932c5, 0xa1deebcc, 0x1dd2b893, 0xae106e29, 0xd7f7c9e9, 0xe91a57d6, 0x0cf4fffc, 0x334851ce, 0xcb4cfffd, + 0x7b13cd00, 0xfa015e6e, 0xbf6e1afc, 0x2e82ea62, 0xecf95355, 0x320a305b, 0xdcda5c4a, 0x4335bc59, 0x0df6b26c, + 0xaa11871e, 0xd801d740, 0xf4e04674, 0x128f26c3, 0x9d922476, 0xa9918059, 0xc7d36f55, 0x54c9625f, 0x6f70cf7b, + 0xffe640e5, 0x3e585ce7, 0x3db7be58, 0x7a59ceff, 0xbf7745ac, 0xeef13c50, 0x46435a5d, 0x9e7aa1db, 0x614835db, + 0x3a070f7a, 0xe67b6851, 0xa6b0bb83, 0xf5aeb836, 0x902e56c7, 0xaef2adb1, 0xccc9d766, 0x8861ba32, 0x712baf6b, + 0xdd447c62, 0x844d18a9, 0x2eba6a7e, 0xa931f2ba, 0xa251dffd, 0x09f0f8f8, 0x7fbfc099, 0x26c067b9, 0x291eddc2, + 0xadb1485c, 0x819e8f7a, 0x29269a79, 0x4bd4ce66, 0xdd0de4e2, 0xd0b3bfbb, 0x761f7d41, 0xcc83e19f, 0xcf7ac2d7, + 0x024004f2, 0x7bc280c8, 0x07bf49ae, 0xba4306f5, 0xc3664c63, 0x584f8e8e, 0x86f50da0, 0x008d9da9, 0xa362c0d9, + 0x32e7c9bf, 0x6f74b074, 0xd3afe655, 0x9379a0db, 0x6f8aa6ec, 0xf80e9047, 0x6d7d1ef8, 0x235b94fb, 0x4717897c, + 0xa4b382fb, 0x6df55af6, 0xa967e85d, 0xb586a4e3, 0x26235225, 0x09e51e42, 0x96b707e4, 0xb3cc5c10, 0x0ab1792b, + 0xe3cc47a8, 0x2e1af8d1, 0x839dcb42, 0x3bd07220, 0x7d9be355, 0x74dcf19c, 0x5e390197, 0xa2809ff8, 0x05c8e785, + 0x89df1142, 0x19876fb6, 0xd991d13a, 0xee0ce184, 0x58b70d47, 0x926a3675, 0xa4d9aa3c, 0xb957f269, 0x332327b4, + 0x1c981f2c, 0xc9ffa084, 0x4a2f73f2, 0xc10823ca, 0x9911870d, 0x0e5f2404, 0x6caa8bba, 0x50d1f654, 0x95203200, + 0x22bafd7b, 0x954c27ee, 0xa30a2d42, 0xa7a44f93, 0x6d0ec2f3, 0x6df38a5a, 0xb7e30e7a, 0xa5a29696, 0x58604f3c, + 0xa2d0a5d5, 0x583e280a, 0x1519f382, 0x27d4ed21, 0xfd3081a0, 0x28d7a662, 0x8feabc5a, 0x729c0167, 0x41767116, + 0x00966187, 0xe05e39db, 0x77202e4d, 0x4fdbfe0b, 0x91df2c0d, 0x26399cf3, 0x38ee3ada, 0x4e9a947b, 0x2abf8616, + 0x4986164c, 0x2fd2d276, 0x724a7e87, 0x711adf68, 0xb653106b, 0xdb34ceba, 0xa410cffe, 0x43eb524f, 0x55ed5817, + 0x5469ca65, 0x58eaef87, 0x6c566444, 0x9ad7e801, 0xda046697, 0xd8fa58a2, 0x10de37b4, 0x763189ec, 0x2953a014, + 0xefbf10a7, 0xec5982d3, 0x99847aea, 0x4288379d, 0x4a4d3340, 0x98f00e71, 0x3f9c53f3, 0x0647681b, 0xa71c7eb5, + 0xa671812d, 0x88e2c97e, 0xc0c8108c, 0xcfc092e9, 0x9d99e947, 0xefd94c74, 0xa682b24e, 0x5a59540e, 0x44797000, + 0xb5a0cbdc, 0x27b8c427, 0x126cd482, 0xb5dacb52, 0x44d341bc, 0xdcd9c943, 0x3fe60473, 0x3e5a6f06, 0x565cf39d, + 0xcf1ce4ed, 0x09b1c942, 0xb646b750, 0x217d90ff, 0x49d5b8df, 0x479849e8, 0x660c1d07, 0xae06ee62, 0x187a7bc4, + 0x6795eb1b, 0x5246af0f, 0x45f2f018, 0xfc713adf, 0x59bc11ea, 0x510cf363, 0x2ad035df, 0x112763a2, 0x711e6a34, + 0xc23384db, 0x76d12155, 0xc721d58f, 0xed8fe104, 0x58336164, 0x503c40ba, 0xa2b0b1f5, 0xc0e72038, 0xa411d2d1, + 0x664ec444, 0x01d1d682, 0xc560a374, 0xc6f4a396, 0x692a98d0, 0x710d5d09, 0xb97fe98c, 0xf4fd116e, 0x2b73229a, + 0x6ae4b2f0, 0x718cfb63, 0xfe346b41, 0x0cd66a52, 0xdde185fb, 0xdb38d34a, 0xbac48890, 0x783123a4, 0xd39fd0d2, + 0x04904df1, 0x4a235340, 0xc5490f29, 0x61b8d633, 0xd82173a0, 0x6bb7ba6a, 0xa31017e8, 0x7bd21e40, 0x1590bb09, + 0x6a75be4b, 0xef66fea9, 0x870d4f98, 0x9e13bdec, 0xd5f83b47, 0xae3a5180, 0xc0959fb6, 0x1b38b6cd, 0xc3cbe90b, + 0x16ce9349, 0x3e7571cb, 0xe34b2d07, 0x54c24c67, 0xaa3afaf0, 0x5ce57178, 0x12168763, 0x1eb8c07f, 0x1b16697b, + 0x99491c90, 0x0e884256, 0xa8e8b634, 0xddaf83ec, 0x7db8f784, 0x06ca877b, 0x54714443, 0x8d898931, 0x8c74d1fb, + 0x00842d1a, 0x85fc3cfa, 0x1e49221d, 0x1777f857, 0xaaec2162, 0xb0f5a951, 0x78473f76, 0x9a4ba096, 0x461c2c72, + 0xbe20d047, 0x6f0b7b2c, 0x3f5a9536, 0x1a0ba9c0, 0x6e571264, 0x18eb9be4, 0x00ea7aa4, 0xf5603c36, 0xfb85d2c6, + 0xa21a0d08, 0xb415d46e, 0x457d68f4, 0xe0c99aab, 0x11834832, 0xa07c1c8b, 0x66fd5f4f, 0x3cd66b70, 0x27b02f79, + 0x066ebb9d, 0xd8e34a62, 0xa12dcd0c, 0xbeefe53d, 0xde0a8800, 0x97d599ff, 0x54b6748a, 0xb647c1e7, 0x5ec7aa79, + 0xf63ece16, 0x0bae55c2, 0x40fd2d22, 0x86fd0a0a, 0x37afeed7, 0x5bf29568, 0x657185ba, 0xd9b79a7e, 0x9dabf3a6, + 0x4edb1589, 0x8d854d1d, 0x7383182f, 0x2a03878b, 0xdfe13cbb, 0xe97ae6b4, 0xedafb219, 0xcfb5d549, 0x0c79d497, + 0x75145a50, 0x5748128c, 0x23461990, 0x7825009e, 0xa15df821, 0x2257611f, 0x14d837a9, 0xf4902963, 0x37510324, + 0xa494e8ec, 0xb77f3faa, 0x8a1e9c73, 0xff451cd5, 0x9757808c, 0xa0f05643, 0xeaa817d7, 0x58784a0d, 0xfc1270bc, + 0x6be869c7, 0xd6c857d8, 0xb6fa6f5e, 0xd9eddec0, 0x44aa0f00, 0xe072e064, 0x697beb4f, 0x7e8929a8, 0x21ff8176, + 0xd7bf22b1, 0xc76254f3, 0x28f18c4c, 0xbfc43dd7, 0xc75836c6, 0x6f340b8e, 0x317fbf1d, 0x6cab45f4, 0x877409b9, + 0xd9852575, 0x97137b7f, 0x25d3105e, 0x93e71248, 0x97066466, 0x54ae00f1, 0xf87af556, 0x29012e0f, 0x12b201cb, + 0x8aaafd30, 0x57d81a86, 0xa93b5c7e, 0x728dab0a, 0xdf67c189, 0x6b692cfa, 0xe2095a4c, 0x3dfe6784, 0xc686df93, + 0xeec00834, 0x7b46decb, 0x8ad30a87, 0xb839b168, 0xfbcf4eec, 0x1496b53e, 0x098f87e9, 0xea65ef10, 0x998cc195, + 0x282da607, 0x56fd7dc4, 0x9561db0e, 0x0f016f72, 0xe329dd20, 0x8bbf01dd, 0x67cecdc2, 0x0094c1b5, 0x4dcf02fb, + 0x22fc7194, 0x128414ed, 0x608e3575, 0x060ca053, 0x70e3e2fe, 0xb66025be, 0x8c221434, 0x214bccb2, 0x2b3f17f5, + 0x47135030, 0x9a14cb7a, 0xfb4f385d, 0x5095b3ff, 0x58c022ad, 0x1d615477, 0x1d4bc506, 0x85b03373, 0xc4bc5a18, + 0x3efa6207, 0xcc3169d7, 0x19fec5b1, 0x2927d88a, 0x96bcb536, 0xdc1aa4f3, 0xa3a35872, 0x5d494193, 0x7d434ce9, + 0xc3078528, 0x9f12fe4d, 0x0bf2f43a, 0xe94d765f, 0x7d41783a, 0x436314cf, 0x6e8c6eb2, 0x992adc0b, 0xb05a5c84, + 0x457c0575, 0xeb6d7ec8, 0xe27eccc9, 0x9e378791, 0x968943d3, 0x65af67af, 0xd369e408, 0xd01d28cb, 0xe9c6693e, + 0x4444d2b9, 0xddeb63bf, 0xf613f9fc, 0x29b7732f, 0x08bc2754, 0xc12d6b7f, 0xf7bb0d2d, 0xb9ae4344, 0x0d3f82fd, + 0x431d76d0, 0xf01798fb, 0xd3aa6ba4, 0x2dcdd21e, 0xd5b85b8c, 0x0f5ff7e9, 0x6861a6fe, 0x7c212559, 0xfcf02817, + 0xda20e666, 0x72b356c6, 0x52540ea0, 0xac3df7c4, 0x8fbc6766, 0x04e794b7, 0x7823e419, 0x6c9ca366, 0x2bb2a1a9, + 0x58e28f69, 0x857effe8, 0x004013fd, 0xe76b9172, 0x17d051ae, 0x7668cc5a, 0xbad231bc, 0xdb8925f2, 0x63badf84, + 0x545daa4c, 0x07d6dbcb, 0x5ffad74f, 0x8822f8a5, 0x3192e5fa, 0xb2ac4e1d, 0xebc0136a, 0xdadc34d2, 0x217ea6a9, + 0x54911dff, 0xfbcc29bc, 0x2b42f167, 0x0d5b9dcd, 0x26de4c92, 0x739d08ce, 0xf16e8269, 0x712315eb, 0x6790201b, + 0x96751aa0, 0xe19de737, 0x816492e6, 0xc967e4bf, 0x42dfe46b, 0x2eb2723c, 0x103ecacc, 0xa6875f97, 0x0f28e666, + 0xf3e4464e, 0xe9b3562b, 0x403ea3fd, 0x328e9aff, 0xa7edbb71, 0x13dee5e3, 0xcd63df64, 0x2222077c, 0xcdca4b4f, + 0x0e98121a, 0x7400e267, 0x0a31868b, 0xf217fec9, 0x426a7a58, 0x9ac8a1b4, 0x3681e695, 0xfffe9035, 0xba6eb172, + 0x1e0f6f88, 0xbd646836, 0x7499437b, 0x3c75b20e, 0x2a8cc814, 0x92b10789, 0x2cdc6a1b, 0x411c6803, 0x061c5f52, + 0xa0970e07, 0xa86dcd53, 0x2e1c56e7, 0x69d115ee, 0xdd2a18f8, 0x737d7486, 0x6e59b827, 0x443fbda9, 0x8d61ad31, + 0x6939847e, 0x354c2024, 0x1e0bb78d, 0xc0d744a9, 0xb5278e9d, 0x09ebd3bb, 0x9e6cd06e, 0xb6bcc741, 0x227c6ca1, + 0x263346b8, 0x6952e4cb, 0x506185ef, 0x0dd7dd50, 0x1297784a, 0xb77eb888, 0xb804101d, 0xae4d1c85, 0x0242a328, + 0x2ad039ba, 0xaff749a0, 0x80568bc6, 0x1acb05bc, 0x66590703, 0x31e67a9b, 0x02737ea8, 0x1d384a70, 0x425cbeed, + 0xb528b2a7, 0xa0db29f5, 0x46a74eb2, 0x63648db1, 0x8d77f376, 0x15ced6f1, 0x78b87f76, 0xceeb1f4d, 0xb914649f, + 0x1d6c43ea, 0xaf159d66, 0x3b412b8e, 0x5c5bf1c2, 0xd09ac5d0, 0xc802d24c, 0x154072a5, 0x23c3ced1, 0xf48175a2, + 0x0e605e50, 0xa73888e0, 0x6ab18031, 0x3294cddb, 0xfcbf74d0, 0x875b2733, 0x80e41310, 0x29837915, 0x92307600, + 0x7e96a93d, 0x2d4dbab4, 0x7b2bc70b, 0x1af9149a, 0x21efdf25, 0xa1ed4863, 0x38b49efc, 0x4b4abaf2, 0xe18b7ede, + 0x991e8813, 0x6aaf3a27, 0xdc59ec89, 0xeff02938, 0x5efc8a5a, 0xcbe36852, 0x8c8138af, 0xf8381fc6, 0x67a71002, + 0x135d3db0, 0x669c03ed, 0x567ae939, 0xc98e0805, 0xa7b0c269, 0x6c71c44d, 0x6d0082a6, 0x85f7576f, 0xf2b560e4, + 0xe5b26d8a, 0xf2bbe632, 0xc5343b26, 0xcd8c75c2, 0x38f5afa1, 0x136ddcf9, 0x02671870, 0x0d2f5198, 0xe0c2e67b, + 0x1c43cb69, 0x1a8ebbdd, 0x501ec3e6, 0xe5bda01b, 0xa2c0da73, 0xcdcc98a3, 0x1ba1fbf6, 0xf0c144cc, 0xe4932421, + 0xc67b8793, 0x8a8cf02e, 0xcd90745d, 0xa9e760a8, 0x92ac4793, 0xfb955d20, 0xea4c2afa, 0xd5ec961c, 0x280e6885, + 0x2bbd6d25, 0x7f626706, 0xa111a024, 0x6f240231, 0x244acb5d, 0x06126a94, 0x19e0b792, 0xfc8d2a62, 0xab9294a4, + 0x95fa171c, 0x21ab5347, 0x4b3d31ea, 0xce37b7ef, 0x1ad4fd33, 0x042ea6a3, 0x048c8136, 0x6b313d1f, 0x7033d92a, + 0xf22fd338, 0x0aeb301c, 0xc904fc38, 0xffc11c36, 0xf1e4b3a8, 0x169291cf, 0x9d695e0e, 0xa52153f6, 0xc26b86d0, + 0x2af494e6, 0xa988aa69, 0x58b9b89c, 0x6786632c, 0xa05dfb80, 0x69452d42, 0x235fe80c, 0x5e7e5888, 0xe5a7e3de, + 0xa1c7089b, 0x98ef1171, 0x57032f1c, 0x6719474f, 0x54a472e4, 0x94fc5acc, 0xfe291594, 0x4adaf770, 0x41bb1d80, + 0x366b47ac, 0xab3a5ca5, 0xffa2b758, 0xc0a3ffa3, 0xafc3f49e, 0x4069790c, 0x49847b30, 0xf4927491, 0x612b6cdd, + 0x72cc5db8, 0xaabac680, 0x8f0560b6, 0xd1398a59, 0xaee5135a, 0xcc8f6e56, 0x6c58fd51, 0x79a93e4b, 0x26c952aa, + 0x23c2e2e9, 0x510ede5d, 0x022ad2fd, 0x3a593928, 0x1a6b847c, 0xb261475c, 0xa730a3be, 0xe81e2670, 0xebc0cdf9, + 0xbd8f07ca, 0x773e5c7c, 0x62f769f1, 0x08c29d36, 0x080f461e, 0x124b3184, 0x2903303d, 0xdea1bccc, 0xc268e681, + 0xc1f375a0, 0x6f8d2ad0, 0xbe64db01, 0x8a6f7412, 0xde0f62c5, 0xdf4169d9, 0x9ece171f, 0xe60698c2, 0x4745df4e, + 0x26d328b2, 0xeb11a13a, 0xfdc2c15a, 0xac53d6df, 0x9b728dd4, 0x4fa02410, 0xcee4cc55, 0x18237d9a, 0x691e65aa, + 0x9229fca6, 0xd3150325, 0x36622228, 0x335ac89e, 0x10805eae, 0x1ec2b727, 0xfb6ab26f, 0x3720f6a6, 0x6f502156, + 0x777e5195, 0xb1056d59, 0x0636fae6, 0x9c6da135, 0x7d4c686f, 0x6794fa69, 0xcb91d553, 0x4cd2763f, 0xc9207b81, + 0xfbe900c0, 0xd552b8b0, 0xcd8da147, 0x7cbde41d, 0x3dace902, 0x7f5ff0c8, 0x53efd4c6, 0xc2b5f085, 0x1c1d0d25, + 0x5cd44639, 0x9c287aad, 0xe4f306f5, 0xfbd55122, 0x8342faf7, 0xdfd17b9a, 0x8ea6aaed, 0x574917ae, 0x24d69055, + 0xd012a15f, 0x2f88a7e3, 0x1b7cfbd8, 0x047cc00a, 0xf39b4b92, 0x069b188d, 0x6f220ada, 0x89798cb2, 0x00752e6c, + 0xbb34a7fd, 0x2c8f4bf3, 0x4a84fc51, 0x9298942d, 0xa994052e, 0x2bd349ee, 0x0482118f, 0x797e814f, 0x497bb7a4, + 0x3dc4764c, 0xec52d7d5, 0x38d943f2, 0xcde8f07b, 0x1bf33cbf, 0x572b4fab, 0x6ca65bde, 0x597226a4, 0x87f84550, + 0xa1ad2881, 0x8942ece8, 0x8e23778d, 0xd952ce73, 0xf04aef8c, 0x6d66f444, 0x066b9516, 0xbf36fd93, 0x24ca646d, + 0x39a55404, 0x4378d9d9, 0x3c92de0c, 0x1e387b2f, 0x7f1d884a, 0x9e1e43c4, 0x1eed3aed, 0xa41a8ce5, 0x9c31ffe1, + 0xd23e1618, 0xe7c42820, 0x6ee0d615, 0x98c0511e, 0xab37552f, 0x76be5c26, 0x270fd855, 0x7fa873ea, 0xca3e0f50, + 0x87861fbc, 0x4428a7f4, 0xe96515d7, 0xf1ec8c31, 0xfa70be80, 0x730c9afe, 0x43ecddba, 0xbe4adcf4, 0x0d6e6b05, + 0x22ddc973, 0x2d2993ac, 0xcf09815c, 0xb1c87cec, 0xc4f9df79, 0x9f9bd9b2, 0xa232afd4, 0x21194c96, 0x9c9fe97f, + 0xa9cd447b, 0x2e3a5541, 0xd9d447e1, 0xc815d6e8, 0x424d594c, 0x03061a4a, 0x76141448, 0x0ff586bc, 0x15b85473, + 0xf1da50c6, 0xd56acd11, 0xf6fadf0e, 0x8a93425a, 0x19675ba0, 0x1376e997, 0x7305e40b, 0x2013e91d, 0x99d26f61, + 0x75a0bc35, 0xdf2d7c46, 0x5e5eb5ec, 0x75970f03, 0x70cc686c, 0x61e9759f, 0x1ba4d95e, 0x428bcf7c, 0xd5ab5e73, + 0xc8eed94b, 0x88d85cb3, 0x468868e8, 0xe675bc47, 0x030b453d, 0x403636ae, 0x857a7ad4, 0x5349468c, 0xa5388dd1, + 0x6518e7c9, 0x2c2d2643, 0xd5bd8b08, 0x30f3af4b, 0xbdf857ef, 0x2a6ced4e, 0x8c5206e0, 0xe4df6b5c, 0xaa3e5811, + 0x95dd2d0e, 0x9972b30d, 0xf46b4da6, 0x94239151, 0xeb88a58d, 0xd0f1a226, 0xe3866a67, 0xfbb30827, 0x8ef324c4, + 0x0e1c0b78, 0x17829990, 0xfb120378, 0x5fe91d93, 0xa6d0051d, 0xacf197e3, 0x44d10221, 0xbc1ca4cd, 0x6b653932, + 0xdb0c36f3, 0xa6115fc0, 0xaf1287d1, 0xbfedd01c, 0x8eebc47b, 0xa0d0fa39, 0x96823fca, 0x5ce147e0, 0xed2e0b18, + 0xbbc60aff, 0x824eea54, 0xc7833ada, 0x691f67a8, 0xc0624201, 0x7c68e66d, 0xd9b0e0f4, 0xc86a625d, 0xaa7d7ba1, + 0x253d2327, 0x4bf81aa7, 0xfbaf3177, 0xca5180ff, 0xaf142351, 0x12015bb0, 0xc4b60b04, 0x8b8d3bcd, 0x97d11497, + 0x3c00d9c2, 0x8c1dbe9f, 0xa62a2c05, 0xa3ecb266, 0xe4b909ca, 0xf30faf39, 0xcb40f5c1, 0x2e4b541b, 0xeb07f76f, + 0x59ae5847, 0x2494a7c7, 0x69ad812e, 0x23b88172, 0xe0b3a463, 0x4b451696, 0x22c61146, 0xca7e0d1e, 0xd22b4123, + 0x7cfc8797, 0x216c8f5e, 0x8743b157, 0xdc687020, 0x974d5fe4, 0xe7f821cf, 0xb97fa9cd, 0x6a333efe, 0x6b7daee2, + 0xadf542d7, 0xf1b508a1, 0x62542be8, 0xae1deb77, 0xde11ad41, 0x815bf01d, 0xc2c593be, 0x45a4179e, 0x0a8e1c9a, + 0x78f5cc7b, 0x9ed52cc5, 0x14b560f0, 0x077ee858, 0x774e4ea3, 0xe550bd28, 0x9bbff9b3, 0x01f883e7, 0xe4852c28, + 0x1c6866f5, 0x1aa95b97, 0x4e1c7c9e, 0x6f1fbedd, 0xb9968ec3, 0xec9380b7, 0x686f9a6a, 0xec080c4e, 0x4f9ee1b2, + 0x62413b06, 0x9acf8eb0, 0x9ab30641, 0x1646003b, 0x9233eba1, 0xb4bd89bb, 0x6030b843, 0x8f3e877f, 0x3cde7158, + 0x0a6b7092, 0xec70d255, 0xed510ab9, 0x35cf3dad, 0x1021f0e6, 0x8f8d5dfd, 0x111478b9, 0xc2362f02, 0x298faa5a, + 0x1e449b77, 0x3160a939, 0xb1f4422e, 0x33b6637c, 0x21953a8d, 0xb7170d5b, 0xeb111dd0, 0xd4ca7dc6, 0xb28fbe23, + 0xe17aaa24, 0xae4711be, 0x570a0d1b, 0xc6224124, 0x2735f870, 0x0fe97782, 0x460f1b43, 0xfc4981f9, 0x7262bc6a, + 0xa44a976c, 0xb1229622, 0xadac7090, 0xe739e73f, 0x3e462359, 0x7edcf90f, 0x0ae60a26, 0x64ea73e8, 0x15458602, + 0x95726f6c, 0x302d2f29, 0x8703ff00, 0x59ceedbb, 0x3598c2cc, 0x039d95c6, 0x0f1dd14d, 0xa0517f78, 0xc18de78b, + 0x8ab3e10e, 0xe65aad5f, 0x997a92dd, 0x47111005, 0x89ec4fb7, 0xe21ea99b, 0xb9580af5, 0xf23ed178, 0xf0d17b8b, + 0x99f1f876, 0x019ea8bb, 0x5c8271de, 0x30356206, 0x0387761e, 0x257215a0, 0x0d408035, 0x697b8f03, 0xaa05bb7f, + 0x7942249e, 0xade0e238, 0x6ad480f7, 0xf9a78fbf, 0xb8c52e4b, 0x1ba54cdb, 0xef30db5b, 0x90980332, 0xdf92e397, + 0x3d2649f0, 0xa57d2e88, 0xe9bc181e, 0xcf93cc99, 0x2c91479c, 0x5aa4f77a, 0x7b3df531, 0x0aef9b8c, 0xb1db5287, + 0x2b3cc0bb, 0x96f736fa, 0x7946531f, 0x4060e5fe, 0x9e4cef52, 0x1d40382e, 0xe5a4cfb8, 0x665318a2, 0x85eec80d, + 0xc24b324a, 0xca58b07b, 0x8e9c2728, 0x8149a074, 0xf26b0144, 0x7cf44366, 0xa498fd1e, 0x8afd179b, 0x6da540e5, + 0x21b0ace3, 0xfd5b8ee1, 0x9a6e5ab2, 0xf609a586, 0xed9f0851, 0x543f3fec, 0xc4a5d1f7, 0x4c17dfa2, 0xc2efbb35, + 0x84746644, 0x706a17bb, 0x44232298, 0x1df82aad, 0xf6b460d0, 0x91ed8604, 0x8a8b287b, 0x7d515777, 0x88efc69e, + 0x73647907, 0x2871362d, 0x07aa2b83, 0xf2404d4b, 0xf4127956, 0x73755947, 0xd6ec566f, 0x9cceccad, 0xe1016c4f, + 0x22f503c3, 0x0cb57fa3, 0x5a91d3f7, 0x2f6ad69a, 0xf9fb0f5e, 0xbc34281f, 0xe07a4c51, 0x195ad096, 0x33484afd, + 0x4531a512, 0xded259ff, 0xaeaae3fd, 0xa04b0da3, 0x3bb16777, 0xf653048d, 0x453e87dd, 0x40e50b18, 0xff6ade26, + 0xfb6fe5b9, 0x3eedb16f, 0xcac6dc6d, 0x67029a26, 0xdecb93f1, 0xe50417f9, 0xc4e4e892, 0xa22999b5, 0x884566a5, + 0x749f3b19, 0x36801953, 0xf0ff7a44, 0x673ab7cb, 0x2005d8af, 0x96bd889b, 0xf9cca6b5, 0xed417a0f, 0x74ba8bdf, + 0xd3262633, 0x006f3006, 0x2aa74e60, 0x655af45d, 0xd37fbe4b, 0x3b289edf, 0x47739679, 0x6b4ec771, 0x4ace3f02, + 0xec47da48, 0x753f608f, 0x74db879c, 0x87b41daa, 0x7c65e038, 0xb13631e9, 0xfd9410d4, 0x22bbb90b, 0x7d48c7fe, + 0x381a1bfb, 0x8f79bb9f, 0xe230da81, 0xcdb2da78, 0x3f8fbc86, 0x65ad360e, 0x9685f8a5, 0xed1b5f67, 0x41558b2c, + 0x82ffa9e1, 0x84b89305, 0x1287a6bb, 0x02c6db4d, 0x1b1096ec, 0x8970eaf1, 0x1e260f95, 0xd028e348, 0xa972324e, + 0xa881b091, 0x6a34a894, 0x81b3f9ec, 0x0a073af7, 0xb21eebcb, 0x39b5e52d, 0x0e33550e, 0x3ffbd47e, 0x0dbff12d, + 0xe03fdaca, 0xdfa24f7b, 0x1b2551df, 0x793ff758, 0x778af4be, 0xcb6236d4, 0x03b8f3f4, 0x43514e0a, 0xcc248017, + 0xcaa70632, 0xb7f90632, 0xbcf359fb, 0x19884991, 0x78be79c3, 0xa3e43d58, 0xd4b9ddde, 0x74a94dfc, 0x0e08b8cb, + 0xeebd9525, 0x6595a53e, 0x16e189fc, 0xc6ad2e3c, 0x6222c3cf, 0x272d03ee, 0xcb065eac, 0x588438d6, 0x3a319897, + 0x2ef8659a, 0x0161ab99, 0x1e2e5a97, 0x1c5b2ec6, 0x6d43133d, 0x4f3f33e7, 0x462c8ff9, 0x822921fc, 0xcf81eab4, + 0xa82c5947, 0x22aa9d9f, 0xc70b564e, 0x3009181f, 0xc23b6baf, 0x2bb4b351, 0x057db62e, 0xd493fc8a, 0xc9452fa3, + 0x0bffe0fc, 0x4e268668, 0x92d1059b, 0xeb835d86, 0x6872f7d5, 0x0cc7d4a6, 0xe662941e, 0x0f0901a1, 0x71711437, + 0xb6d13b9d, 0x45d1f06f, 0x3f7fdf95, 0xe9bcf17b, 0xa0ec795c, 0x6b307242, 0xc629c666, 0x09c6bb59, 0x743f7bd8, + 0x7671fcfd, 0x6a1693be, 0xd6230a1a, 0xcddcf870, 0xb3d53efa, 0xbaa5ca66, 0x1e70a8c6, 0xad53e6f1, 0x30fe16a8, + 0x51c821dc, 0x036010c5, 0x812d8375, 0xacab0d1f, 0x8b8b4ef0, 0xcf3a095d, 0x395b09f8, 0x36749b65, 0x3a4b2a2f, + 0xa13ea3ca, 0xc0da7f95, 0x1066f789, 0x71fd019d, 0x2fc559b7, 0x40ed50a7, 0x4fd557ec, 0xa984554e, 0x3a3baec2, + 0x0ae80c65, 0xcaacec03, 0x96882d6c, 0x1e2e7207, 0x3700e0b4, 0x9945663e, 0x04e62368, 0xa70618b6, 0xfd627879, + 0xb1707e73, 0xc60a53ce, 0xda6580dd, 0x788d49b3, 0xf10bcdd3, 0x525e7bf3, 0x26ed96bb, 0xb84e7e66, 0x1c1f5a02, + 0x1b681116, 0x48db1ac2, 0x79d04085, 0x2770bdac, 0x78c2e295, 0x8f24fa82, 0xdcd5ad96, 0x0a425d38, 0x3cf7ce26, + 0xe0da2609, 0x76bcf687, 0xee481909, 0x13bcfbac, 0x83e80f67, 0xfe564eab, 0xb09ce418, 0x027d2fb4, 0xbfa9a88e, + 0xa5efb9b8, 0xbd54345d, 0x2a40ad7b, 0x4492be28, 0xc2665ea2, 0x7c10a815, 0x55cfd761, 0x6d277b7c, 0x3ffd5811, + 0xc534bdf5, 0xfe3d4a2c, 0x170ae3e4, 0x5db93b1e, 0xb6b19783, 0xc914fae7, 0x49f36146, 0x6d791397, 0xabcdb717, + 0x64b3b1ae, 0xbc333521, 0xe1d83c5e, 0xd20ed496, 0x354781a5, 0x635dfc15, 0x51fdffd7, 0xe78055df, 0x95285b4e, + 0x8518b6b4, 0xb23a08cc, 0xf98f619d, 0x983f8ddd, 0x0abf9f97, 0xc3f8355d, 0x95f69bd4, 0xe33f7db5, 0xc9f0c8ce, + 0x24b6050c, 0xa9c21f9c, 0x252ff137, 0x53de5be8, 0x57307a87, 0xef68279e, 0xdefe663f, 0xcbe9e4ed, 0xb72d4b47, + 0x060f8e0f, 0xaad9da0a, 0xfa87efe8, 0xb49ae495, 0x23335e2c, 0x7e8430d4, 0x8d3fb824, 0xace7cf72, 0x2a67ef87, + 0x4ca69be1, 0x5fccaa9f, 0xb4c17d88, 0x98702dcf, 0x8cd2e58e, 0xba62d938, 0xcaed59e1, 0x74eaff13, 0x27691bd7, + 0x4ebe3bcf, 0x77bb9ae2, 0xfa9d254e, 0xb39e5e39, 0xa9d21682, 0x75676c3b, 0xb3508521, 0xa023214e, 0xb6f43c04, + 0xefeb3d04, 0x613cef79, 0x19e79214, 0x11201da8, 0x3cd4705a, 0x03e86443, 0x64052249, 0xd03c39ef, 0x6bcf95ab, + 0x38b85f51, 0x1f5aa0ad, 0xf5f83ecf, 0x43c70f78, 0x073c6c5d, 0x44dab9c9, 0x7f458740, 0xb723fac6, 0x3a5468ad, + 0x49ee9e17, 0xefec139d, 0x5eb2972e, 0x15c95d26, 0xb9308f8b, 0xd7f16445, 0xce0e7a1b, 0x45a8c889, 0xe35c9ed9, + 0x8fa80af8, 0x29c2b686, 0x4fb649b7, 0xcc655977, 0x312b0ecc, 0x63ed8de8, 0x5ac57e4e, 0x6b23d817, 0x48be5a98, + 0xf9efddd2, 0x7b67ee8f, 0xae97d29e, 0xc88165b6, 0x99ee8dac, 0x4884c4c6, 0xac320886, 0xa3f1d02c, 0x7bb62d4c, + 0x1bbb4d87, 0xeb73b019, 0xcf225fca, 0x71fbe60e, 0xc051c565, 0xad56b430, 0x6a13dcc3, 0xd6f1a094, 0xfbcdcd7d, + 0x6330e7e5, 0x9ace1ab5, 0xac5d9983, 0x002dff8c, 0x75821ab4, 0x1c0a910d, 0xb785b2e8, 0x31b4ea54, 0x43ced495, + 0xf309329a, 0x81c7a95c, 0xa7e3eb86, 0xca38183e, 0xc8704f1b, 0x06b930f9, 0xc12805ac, 0xb25f681d, 0xfce3b448, + 0xd3d769e3, 0x8161265d, 0x796167a0, 0xd9957fd6, 0x515274f0, 0xb34cfd71, 0x7f57dc70, 0xbc5772be, 0x33c90634, + 0xe5b27f61, 0xb4f728eb, 0x13ef1837, 0xb423b65f, 0x8a271321, 0x89dc1df6, 0x53a7df4f, 0x38c87822, 0xf00d3230, + 0x178ffc12, 0x70999aaa, 0x47ce17e0, 0x59d6bbb7, 0xa5dbb2a7, 0x68375131, 0x90e8c13a, 0xf8d1e347, 0xaf6c3ae4, + 0xae735eb7, 0xfa808c4c, 0xe41cf2a1, 0xf79687cd, 0x868e0c78, 0x847efe9c, 0x1d85a17b, 0x9461af39, 0x245a989d, + 0x8bae3647, 0x14aafccd, 0xa9bd0253, 0xf5811a64, 0x229e3fa6, 0xc877fbf7, 0x9885ec9c, 0x1752e2f0, 0xb500558b, + 0x6226c73e, 0x40989a31, 0xeca5253f, 0xa68885ac, 0xc6e33a6b, 0x3b433ebd, 0x09c1037f, 0x734f2390, 0x34487425, + 0x10ad4f9a, 0x1d47ecce, 0x4d5f3a00, 0x2221c41e, 0x3af67227, 0x13c3de9e, 0xf635c7f7, 0xf9413c64, 0xd895f812, + 0xa66e9400, 0xc438c6c4, 0xfe67aff6, 0x4d34fc23, 0x2ec13047, 0x061a1b75, 0x3e2eec9f, 0xd9e857f6, 0x8286e58e, + 0xc91f3687, 0x29261d69, 0x9232eef4, 0x6e568c81, 0xedf5c371, 0xbc3aa0d2, 0x360ce36c, 0x0b56ba3d, 0x188fc1e1, + 0x823ceaa0, 0x1034a54f, 0x656edef0, 0x3fca810b, 0xec4fcbc1, 0x414f949c, 0xa8847354, 0x29ecadf1, 0x61da530e, + 0x97866979, 0x6af86a22, 0x655b92b6, 0x3ce56d6e, 0x7a57a955, 0x74d2fa50, 0xb9099e3e, 0xd7d081bb, 0xb80c579a, + 0x6a52689f, 0xf5a10380, 0x0326921a, 0x5bf99f85, 0xfbfb3c80, 0xa31b3aa2, 0x971d82b0, 0x0735f783, 0x1f27915f, + 0x2c2bc128, 0x5cd8e63e, 0x81d282b5, 0xbe02abea, 0x3106a09d, 0x06ecc03a, 0xf3525a25, 0xfe360862, 0xeaa44600, + 0xcf0b9f3a, 0x9757b72f, 0x7e2f7186, 0xdb366694, 0xa8ef3aa8, 0x19b0e5bc, 0x6fde6d1e, 0xb45eb95a, 0x6ada5d63, + 0x9b1b2c6f, 0x964583a9, 0xa77077ce, 0xfda0bb36, 0xb8d3c6ff, 0x96c6ff59, 0xc44027f0, 0xe9d4801a, 0x61f58508, + 0x44d704e6, 0x028f8370, 0x69025f0a, 0x6963e4d2, 0x9633661a, 0xeb94e25e, 0xb75a790d, 0x839af3c4, 0xe16270e0, + 0x72db1361, 0x18e191bd, 0x54795aa0, 0xb8c4dc99, 0x677c59a5, 0x9617efff, 0xe24c1b14, 0x4d217602, 0xa6643d85, + 0xd3bbbbe8, 0xb12e98c1, 0x99fc5741, 0xfbb6ca9c, 0x2f798537, 0xbf8dc1e8, 0xdeafde26, 0x72387fae, 0xac2a6dac, + 0x5b288eab, 0x5f613c3b, 0xe4ec1e9c, 0x16f87795, 0xd5a40b27, 0x0dbb57ab, 0x2b6b2d2e, 0x8d402ea0, 0xdd12bb57, + 0xf964b399, 0x593b16c7, 0x7f50a542, 0x798fc74f, 0x9985fa57, 0x54ad6ebd, 0x2752765b, 0x09300295, 0xae11e14e, + 0xd9bd12bb, 0x7726e935, 0x0875b484, 0x1022a841, 0xf9433829, 0xc7e41a93, 0xd95d5208, 0x343694e5, 0x20031b89, + 0x4770103d, 0x9742e076, 0x1687cc18, 0xdaa5af22, 0xfce4b859, 0xd157946c, 0xe2922faa, 0x0f7babe2, 0x00fdbcea, + 0xbf63eb38, 0x3e6fc7ef, 0xced0b227, 0xacb34589, 0xdb84fdd3, 0xb0c28e86, 0xe4e6516d, 0x5e5321bc, 0xb7dce1d2, + 0xfcacf93b, 0x3ad192e7, 0xfd6945cd, 0xfc18f186, 0x8a462ae9, 0xfa9e7cb5, 0xcef68077, 0x7aeca954, 0x730434bc, + 0x5e191b3a, 0x535f3dd2, 0x4403db26, 0xa0faa7e3, 0xd1fa0538, 0x34822110, 0x8ebbf550, 0xcab7e4dc, 0x32ab0b7f, + 0x1b5951ae, 0x3cbbad30, 0x329f2955, 0xe4f9a0fe, 0xe2e7bcaa, 0x34fb69e4, 0x7f25ed51, 0x8f39753c, 0x54a8595b, + 0x53f2315a, 0x1969f661, 0xee8941dc, 0x691ee4fb, 0x9539eefc, 0x4b68c4ef, 0x72eecf70, 0x91f2d0b6, 0xc8a3617c, + 0x894b1c7a, 0x7cfec0d0, 0x2e5c410e, 0x7ed26efe, 0x4b19a6df, 0x07321dcd, 0x425bd8e4, 0xd7de243d, 0x581afe8b, + 0x721ac467, 0x13747e25, 0x2f5ea7c3, 0x30588a19, 0xfff20a08, 0x8d288ee7, 0xf974794d, 0xe765c4da, 0x86e16d47, + 0x47d4fa50, 0x8925cf3c, 0xbe313b27, 0x37bddc76, 0xc0b94d32, 0x4f2b031b, 0xa3383b25, 0xb327604b, 0xeabb4b42, + 0x267eb9e0, 0x3765782e, 0x39f32bd9, 0x3af2612b, 0x4be451ab, 0x55b0ff91, 0xb712b875, 0xd2102a94, 0xc4369a20, + 0xe57605c8, 0x4d4b5194, 0xd9fda760, 0x295cb6cd, 0xe6ea893a, 0x10f3d7d2, 0x7af78c53, 0x6e97a14a, 0xe252e8a7, + 0x7757fbed, 0x3ee9cfe6, 0xf6a789aa, 0x3e41e062, 0xe0749544, 0x72f959a6, 0xa7f08458, 0xb053f42c, 0x764bf996, + 0xc058ed5c, 0x992605f6, 0x7b1d6f21, 0x99cbce0d, 0x9cb98b20, 0x2bbbcd45, 0xd02d0f04, 0x545c0cc3, 0xf055e7ce, + 0xd881a42a, 0xcff7bb41, 0x247bcf68, 0x6e119f54, 0xf30ea920, 0x0f7ce4d2, 0x6b54fe40, 0x797515bc, 0x84fbfb3c, + 0xd8c6613d, 0xba00ac2a, 0x56e224a5, 0xed3fcd3c, 0xce8493e5, 0x1522005a, 0xf9e637c6, 0x7ad0a0cf, 0x4ca86889, + 0xd919f8e2, 0x76af35a6, 0xf033f28d, 0x3848fdbf, 0x29e28cf3, 0xdb049ffd, 0x6f93a89c, 0x55f8c112, 0x1a0759ab, + 0x9650fb3a, 0x2ff05e36, 0x81ba11f4, 0xfe7c19d1, 0x999d504c, 0x62f835da, 0x785fbc17, 0xb41aa072, 0x801592c2, + 0x3bd3f891, 0x87e035e2, 0x7d6a8d5a, 0x033fe153, 0xf73bf9da, 0xf3215e24, 0x027f90af, 0xcdc9ccc6, 0x68e4c0e6, + 0xd0db706a, 0x79805193, 0x99f91cd5, 0xffe72c7d, 0xedf30dc3, 0xbbf3fe47, 0xba73d270, 0xe8cc5511, 0x29405f2f, + 0xa96eeb75, 0xc604c79b, 0x9474e7ab, 0xcc205afa, 0xee6550a6, 0x126bee97, 0x3c56e7ad, 0x5f574886, 0xfe73103c, + 0xf51b1374, 0x532396a5, 0x598a713a, 0x336ce841, 0x8221f7ee, 0x8531a6ff, 0x0f566898, 0x2eb80887, 0xb87bcd6d, + 0xfe295706, 0x10fc51f5, 0xf831dfa2, 0x90c92029, 0x67a40a55, 0x1ad01d57, 0x46703b1c, 0x57d8ce39, 0xc86615e6, + 0xee29c8af, 0x99eed6aa, 0x3b6fd051, 0xad73d5fc, 0xd1700c64, 0x2c62be7e, 0x508e796a, 0x64c7c637, 0x7c816848, + 0x553abda9, 0x45675baa, 0x7dba4ede, 0xa2b72db6, 0xc6c40681, 0x50665a34, 0x6f2e5827, 0x0ab462bb, 0xb934b156, + 0xdab1907f, 0x3c7ac62a, 0xb97f904e, 0xfd1048fd, 0xbc7f62b1, 0xa0f1c5e8, 0xb60662f0, 0xdcf70cbd, 0x13485fa3, + 0xaf465b30, 0xb50300b7, 0x4b7e4c9e, 0xa00eb7e0, 0x77571f61, 0xeb7b74d9, 0x05e9684c, 0x0a889f6a, 0x12440fc1, + 0x239f70c0, 0xb4d09d2a, 0xef3aa69d, 0x5db2da95, 0xaaa8f986, 0x20235bd2, 0x4964f53f, 0x88d6bebf, 0x90da953a, + 0xaeabf118, 0x50f4a07c, 0x96925997, 0x7169339b, 0x8c2b3313, 0xceac58f4, 0x4771f8ad, 0xcf91d273, 0xf90c95cf, + 0xce5bbeb1, 0xc1130bd9, 0xa0fa36ac, 0xe7bec43d, 0xcecc1a6c, 0x8f941f0c, 0x397b8703, 0x5fc79fc3, 0x27dfd7a8, + 0x4196da16, 0xa1e53576, 0xd39d5af9, 0x8c646621, 0xbeab0174, 0x1c7d8cca, 0xc0d96ab9, 0x7da0c4a5, 0xa09fdaa0, + 0x254b312b, 0x7e8759db, 0x9392a665, 0xf9b77ff2, 0xae712a44, 0xbac48c57, 0x2c2dd048, 0x3dc0852b, 0x6dc5f4fd, + 0x40c13952, 0x94125dde, 0x34e08754, 0x6a7cc7d8, 0x304f5960, 0xb8ed728f, 0x45d51ba3, 0xb56b2957, 0xe5a2f2ea, + 0x05ef3f58, 0x48f095f5, 0xa292abf6, 0x13489237, 0xca2af1f9, 0xe043c3d8, 0x40801e8b, 0x01ebfa34, 0xcedd8b11, + 0xa8987055, 0x1fb12a3f, 0xcb7b5f0f, 0x0634e9a4, 0xf823f63c, 0x807158bb, 0x05deb40d, 0x9694b5f2, 0x8ce134ec, + 0x2f8cfdea, 0x0c2b6ebb, 0x0954615e, 0x7549d322, 0xdb8d263c, 0xcd02c043, 0xa7716565, 0x1d3f3748, 0x941f5b21, + 0xed584904, 0x729b7b0e, 0x38808fd9, 0x486fca62, 0x7260f8f7, 0x0c12f6fe, 0xe85c6e9e, 0x13b8655f, 0x9e4072df, + 0x645498ba, 0x1730c9c8, 0xf6e69212, 0x870f76e9, 0x7b8dbeb6, 0x63aba39e, 0x4ef8f8ef, 0xb3ad6188, 0xcfe98529, + 0x92009d34, 0xbb4062f3, 0xb664cf49, 0x3b4bea86, 0x97a52d85, 0x70b80ce3, 0x22c424eb, 0x191ec236, 0x0235e1a9, + 0x41caf36a, 0x8d6ada24, 0x63b2769f, 0x17141683, 0xf1032478, 0x77e5c653, 0x5b8127b1, 0x427cf540, 0x0d90b37c, + 0xcffdf303, 0x41df7e9e, 0x7d62fede, 0xf4de5547, 0xd77983ad, 0x0b90017b, 0x6e8dceec, 0xdb8d145e, 0x7d8b7ea8, + 0x1969e65a, 0x0e7e6912, 0x41a84d6f, 0xe415b0d9, 0x98396cca, 0x12cf49c6, 0xe67dea6f, 0xbc4a7e2a, 0x7b6565d4, + 0x99c39186, 0xc428453d, 0xa524aabd, 0xccb3f5de, 0xc713dd65, 0x526af90e, 0xd1033b86, 0xcda1d049, 0x0371d4ab, + 0xf80c4f02, 0xa55315ab, 0xcdcf22a5, 0xe1fe54db, 0x9686d86e, 0x9caf2b9e, 0x8e6be3c7, 0xf5ecb92a, 0x6dd5c655, + 0x4921aed8, 0xf9c16114, 0x0b9cd741, 0x853f4395, 0xd0ecaf99, 0x56d0774e, 0x1d68a1e5, 0xf7b95bf9, 0xb333d12b, + 0xf7b7859a, 0x99f040d0, 0x55e73afa, 0x242e6c90, 0x3540968a, 0x1eea0ee1, 0xf2485eb0, 0x06940263, 0x17ec1b3a, + 0xf2277fa9, 0xc8db4d25, 0x1daac821, 0x94dec778, 0x66cd2cca, 0x72b33a8d, 0x013e10bc, 0xdd786c05, 0x3f1c870f, + 0x7e74855e, 0xb876cff6, 0xf0fa0aa6, 0x0b82a9cf, 0x967d64e2, 0x97450e8f, 0x94d3e538, 0xcd364edc, 0x7a8c0829, + 0x3dde4484, 0x240e1f96, 0x0b7332a2, 0xc05cfa32, 0x7c13e6ea, 0xd058b4f6, 0xbf074236, 0x356dc04c, 0xb16b94d7, + 0xbbb39f2a, 0xf737fe94, 0x5cf2c964, 0xce807013, 0x57fdeeb5, 0xe240985f, 0xfd0cb8ae, 0xdc049e80, 0x239b7499, + 0xfb99ab35, 0xde30795e, 0x99b05255, 0x896c0661, 0x4c9f7f74, 0xa949463c, 0x2fc46189, 0x90df0d6d, 0x604b3af6, + 0x19d53be0, 0xb2acb799, 0x5ae12f3d, 0xb3f52f78, 0x6981b3db, 0x1a57a11b, 0x519f6a0f, 0x5803530b, 0x36a7ad0c, + 0xb054eeeb, 0x24c163c4, 0x7b9d1928, 0xe3ed91f7, 0xae690562, 0x81893460, 0xb9a421cc, 0x7c50c379, 0x5994a340, + 0x51bdfb07, 0xd84cd644, 0xb00cb155, 0xeffb1d6e, 0x7a753dcf, 0x4d7fa9b2, 0xcc4e5eee, 0x71dda4b8, 0x93740e65, + 0x0fa0a377, 0x1a094d91, 0x9d4ed955, 0xd24a656b, 0xdfe948d8, 0xa2cc558b, 0x416f1b5e, 0x421ef54b, 0x47bc209f, + 0x686c4418, 0x961e8571, 0x2f7c6149, 0x74ce675a, 0xa2708ea2, 0xbedcb80f, 0x2701f519, 0x974f02f7, 0x0b9e2110, + 0x4688289b, 0x903f7a62, 0x29af9bfd, 0x4e73c937, 0xf6c4ecc6, 0xef493cb6, 0xc9206431, 0xc99f53ce, 0x0e68819b, + 0x1e34efe9, 0xde8059ed, 0x1b38e80e, 0x853014c5, 0x479e2a42, 0x43f48672, 0xd8674af2, 0xd55d5e8b, 0x4f4d0045, + 0x69c08e35, 0xc14904df, 0xf68478d6, 0xcf1c5739, 0x898e6e45, 0x963b487a, 0x3fbda334, 0x0bd65135, 0x72a947bf, + 0xa95f0607, 0xc56589a2, 0x9ebfd80f, 0x6c3c53fd, 0x1e856b4c, 0x965a0765, 0x60e9ba68, 0x1677eb94, 0x20124ef5, + 0x91dccdef, 0xd9ef101a, 0x95cae087, 0x8064ec80, 0xf4d52b6e, 0xb1964301, 0x5bea9f00, 0x468c23db, 0x54520f3b, + 0xdcbaafe2, 0x62b325b3, 0x712db7b8, 0xfa3cbe13, 0xc7ce85d0, 0x52160868, 0xe936c3e9, 0x89cf2a38, 0xb555be47, + 0x514866bf, 0xbc5f213a, 0x78044864, 0xf031ebdf, 0x0fa0e851, 0x42fdacab, 0x7837423e, 0xb12be572, 0x7f1bb898, + 0x8f393a84, 0x9c4b4419, 0xd8fa9364, 0x34643531, 0xa258d9c7, 0xe8952081, 0xf526a2c4, 0x7d1d50ba, 0xa5ce8860, + 0xb38184f3, 0xdb967800, 0xed7c4402, 0x2269ec6d, 0x3d2f3771, 0x62cf4df4, 0x9b80a7c5, 0x013f21b0, 0x00120d04, + 0x8451b53c, 0x273b299a, 0x38d0ee51, 0x4acbbe7c, 0xe7f5d82c, 0x2e5278f5, 0x291baed3, 0x1ed15470, 0xe211cf4e, + 0x3ee70f65, 0x1f12e006, 0x68a5ac64, 0xce6b8edf, 0x3a2e3093, 0x1cac1abf, 0xb63b851f, 0xaf158eac, 0xadc07070, + 0x685e2144, 0xe38d42a8, 0x92359b43, 0x73755ddb, 0xcc1eeb75, 0xa148d9d1, 0xb41ae21d, 0x253899b3, 0x0a3a3836, + 0xc87ed52a, 0xafc7fd9b, 0xeb5b8466, 0xccbfb770, 0x5dcf9464, 0x5e19eb7d, 0x661cc792, 0x5a3d81c0, 0x3e808f9f, + 0xcb5ff3e3, 0x689a3521, 0x032696e3, 0x4c6f9f21, 0xae090535, 0xd800041b, 0xcec75596, 0xb3d29ef5, 0x471fe264, + 0xcb52c854, 0x3cf0e4c5, 0x98726363, 0x0e54a886, 0xb030599a, 0x33d6b2b0, 0x5b3a3b7d, 0x190f5c47, 0x9c3551ab, + 0x92857c67, 0x66e5a3ff, 0x6003db76, 0x200e60fe, 0xc84684d0, 0xd348e69b, 0xd082821a, 0xdb9bce71, 0x0a56f065, + 0x27797b9a, 0x0528b514, 0x8ae64013, 0x83637324, 0xdab22c2a, 0x8856ba11, 0x4cb93494, 0x728dde1b, 0x4f027926, + 0x57abc599, 0x31461b4e, 0x685f2baa, 0x9cc704fb, 0xedaae235, 0x0baf3572, 0x0b6e0af3, 0xf6dad2a5, 0x27f155aa, + 0x9e49b08d, 0x28b66acf, 0xad0485e0, 0xd4313f6b, 0x8cc5b369, 0x1538ecc3, 0xcee2f4b5, 0xb131e3f5, 0x6926ceb4, + 0xb037fa31, 0xee026b8f, 0x7135b21f, 0x65f837f5, 0xe78479a0, 0xcad669ce, 0xaffe35f2, 0xe2cba436, 0x23b33a56, + 0x34072e9a, 0xf6223ad5, 0xb226aad7, 0xffe91ab2, 0x60570a11, 0x99c8a9fd, 0xe2b2f153, 0x7b3c2f50, 0xbe06e504, + 0x22fe5767, 0x5799a163, 0x1d6bf12f, 0xc8fbdca8, 0x98c534d0, 0x6d597aa1, 0x6e57d279, 0x7ec9b492, 0x953d13b9, + 0x2892d1a2, 0x1d3b3c35, 0x8bc35c1b, 0xc790cc0e, 0xf27f54c6, 0xb54af2a3, 0xdf304ec2, 0xa3c02d25, 0x622cf5b5, + 0xebe3551f, 0x704e2805, 0xd8cb5874, 0xf2631a17, 0x63a7b69c, 0xa8c41d3d, 0xab94fcbe, 0x0d4a524a, 0x6786d1d0, + 0x495d888a, 0xa6bd0279, 0x1cc0554a, 0x273cfc05, 0x591f8460, 0x98305d13, 0x7e979d80, 0x4d27a46a, 0xeb989bb4, + 0x05037a45, 0x2f5bb4cd, 0x4415363a, 0xd3b92270, 0x5e70d6b8, 0x4e54a7ef, 0x0ee5e11e, 0x8f118291, 0x1454ec2f, + 0xef03437e, 0xc012a258, 0x9449e466, 0x9fa7712b, 0x28b7ae4e, 0x147a1fcf, 0xd7d656cb, 0x1cdcc99c, 0x23d1059c, + 0xda5bc6f7, 0x8b90c4b8, 0x9d3acac7, 0xc94f2a87, 0x3c54b413, 0x245f76a4, 0x148311de, 0xbc64555f, 0x78485a46, + 0x7c9f64c5, 0x19ce1b6d, 0x44219bad, 0x8a40e670, 0xe423de31, 0xf1f3c727, 0xc4d091be, 0xe4cbdb5b, 0x94e53517, + 0x686d85a3, 0x6dd9499d, 0xcc45cf99, 0xe54d3218, 0x6c105d86, 0xc3152cfe, 0x60dfdee4, 0x90aea17b, 0xee53ceb0, + 0x3805e907, 0x09e50dbc, 0x3045987e, 0x213be311, 0xf00ed7ce, 0x56abf633, 0xe63af221, 0x42ef967b, 0x4709977f, + 0x394e2455, 0xed2e0d07, 0x498c0693, 0x69ef212f, 0xd9cfed8c, 0x9cd3ce3f, 0x2f314687, 0x65b2490d, 0xe2bfb7a5, + 0x413b5b68, 0xd7c67472, 0x7d859961, 0x4e2f2884, 0xbbf9c3f4, 0xbf350657, 0xdf17fba6, 0x3a455fa7, 0x672a2ab8, + 0x0b0786c9, 0xab22b5c0, 0xa0c36ba4, 0x3c5ee050, 0xd443e664, 0xd1eac78a, 0x20c32a69, 0xb9fcec5f, 0x4400bd61, + 0xa7d9dc15, 0x83a19049, 0x8ec98be9, 0x18df38a1, 0x47f317c9, 0x2ff86770, 0x4f8a3d08, 0x867a338a, 0x19f97617, + 0xef2e82f6, 0x346843ea, 0x92c70675, 0x26821ea3, 0x281f94aa, 0x786e2021, 0xc4733e71, 0x51683a26, 0x7497c772, + 0x13792534, 0x14305f47, 0x0afde914, 0x62ca69f9, 0x75d6a66f, 0xab7e027f, 0x0b717498, 0x3904a2ba, 0xc784a276, + 0x17154863, 0x6142960e, 0x4ae60320, 0xe2d21b60, 0xbdfc246c, 0xdce0747d, 0x20b8aa05, 0x2c06fd84, 0xb2cc078d, + 0x7f681959, 0x8feaad9d, 0x438cfc88, 0xe82c4779, 0xab1e86c6, 0xbc484969, 0xfab90079, 0x6f47edee, 0x54b6e379, + 0x8343e443, 0x0c8fe07c, 0x0cc24480, 0x837f1cba, 0xeb97e571, 0xca4e2292, 0x9ef93bb8, 0xc46350d7, 0xf9ff77ac, + 0x610d2eec, 0x6bb3d6d8, 0x1126c6a7, 0x13ac9ff5, 0x8b512ae2, 0xd7d440b2, 0x94c72188, 0x2f714535, 0x68257b54, + 0x02b48ada, 0x3a75567e, 0x4467d62f, 0x7d6a658b, 0xef0a617d, 0x7063a799, 0xf33ff58f, 0x688789fd, 0xc66e475a, + 0x076f67d5, 0x42e9be1a, 0xb4049ffd, 0x498fb095, 0x5de92ca0, 0xc74fcd5e, 0x3c894ae3, 0x69e9e4d9, 0x92b27c72, + 0x4c547d30, 0x9abc65c4, 0x58b95b41, 0xd4e6fe77, 0x90e9abe6, 0xa675f28d, 0xc01ed523, 0x7864f451, 0xe585cdff, + 0xd2dd8d87, 0xc1ac78b6, 0xc87fabe9, 0x4b78e91a, 0xc420cecb, 0x675f805f, 0x42044070, 0x2fbdd071, 0xf664502b, + 0x35802c96, 0xae8102e4, 0x920f5e9d, 0x4f72d587, 0x61a07aab, 0x067a8e48, 0xe4cfe382, 0xd4b86f3c, 0x6f6a15ed, + 0x5feb79d9, 0x8b7ac9c7, 0x9d133e4e, 0x722f84a8, 0x4d9a37b6, 0xd764300c, 0x36f82351, 0x86153cc9, 0xe0f35eec, + 0xc077698d, 0x86bef3f1, 0x704cd7bc, 0xf7eb4f56, 0xe5d0908b, 0x8d366980, 0xf2bde99a, 0xf29e8d7e, 0x5a851e18, + 0xfa0eb163, 0x5c63f1bc, 0x56edffe1, 0xe87ee5df, 0xd8923b98, 0x2e53110b, 0xde504ef9, 0x19560f47, 0x10125698, + 0x17ac2a11, 0x1934e006, 0x90518a88, 0xede45bbd, 0x0ece1a1c, 0x69ab861f, 0x0b2579d6, 0x061f2ad5, 0x3e7d0a9a, + 0x951cf7a9, 0xa89ce21b, 0x308ac1f2, 0xb378baa4, 0xefde233e, 0x4d50f46c, 0xdc906945, 0xfb1011c9, 0x1d950396, + 0x66283874, 0xd86023ff, 0x91fcc14f, 0x98255503, 0xc7fd9af7, 0xe3805e1b, 0x1db9ad57, 0xfc182d5f, 0x706473d0, + 0x3e25a733, 0x5ff2eb42, 0xdd2232cb, 0x8bbf90f9, 0x477c01b8, 0xb657135b, 0xfb4e494e, 0x0a553a35, 0x12e0570e, + 0xb0e53f30, 0xaef3a233, 0xbd2eccf0, 0xdbacc749, 0x1fd5e7fb, 0x2d2eddfd, 0xe6246b92, 0xa498954f, 0xd77284ec, + 0xe1955ac9, 0x1d90d96b, 0x861b99d7, 0x34281cbd, 0x5301ceac, 0xe7dfde82, 0xf64bdd48, 0xe5913a7a, 0x793cc9fe, + 0x5a28e0b4, 0xdabd231b, 0x704cc7bf, 0x75470fe0, 0x070ef5e1, 0xccfb0669, 0xcd5a55f3, 0x1efc173b, 0xa51a25f2, + 0x03ca507d, 0x6ab354be, 0x8efb880b, 0xb3113c44, 0xd37426be, 0x3e9c65ee, 0xd05d02d0, 0xa2c4227e, 0xa37e94b8, + 0x4e43f3fb, 0xc0f394d8, 0x1ab3502b, 0xcb4259ec, 0x4091185e, 0xdda21ec6, 0xdd12608e, 0xe8b136dc, 0xaed03541, + 0xfa27018c, 0xd4400e7b, 0xd45d0d4a, 0x549ad089, 0x2646d075, 0x29d19bb0, 0xbeb587e1, 0xdd925fb4, 0x4453bcd1, + 0x392feb3a, 0x56bd025f, 0x431107ae, 0x4239596c, 0xca852528, 0xd4f447cc, 0x974b8ec4, 0x36de40bc, 0x391ed86b, + 0xdf1e0866, 0x8023c6ff, 0x051ddc68, 0xcb4eb9c5, 0x0f807496, 0xa1906bdf, 0x361f243d, 0xbb3c3271, 0xb05b2bb9, + 0xb0fed6f2, 0x1117e054, 0x73a6f610, 0x77dbcbef, 0x95e2dc9a, 0x3627a2f8, 0x3e4ef898, 0x0906a60b, 0x84ee47d2, + 0x7514474a, 0x5ec49374, 0x526612f5, 0x3132b7d5, 0xbc21d4ff, 0xfd04d632, 0x3c199f85, 0xe2d231f9, 0xe0fde7c1, + 0x94fa2faa, 0x28667d85, 0x4e88173c, 0x01caa5ec, 0x5a4ec55d, 0xff51abc5, 0x01621db1, 0x700e5bc7, 0x4f6374ae, + 0x4162c6d8, 0xcddff73c, 0x6473081c, 0x2f3044f8, 0xa8e39af9, 0x9d595711, 0x44896e0b, 0xb41ef46e, 0x78a25f26, + 0x982cfcbe, 0xeeb32a39, 0x0ad4665e, 0x3edf7c5c, 0xdf03f43a, 0xd7fa2ccc, 0x8f7ae131, 0x611ba6e2, 0x966a3d7f, + 0x8dbde81b, 0x844b37a1, 0x84812687, 0xa288e6f7, 0x22f8a686, 0x3017801f, 0x55b1c0f2, 0xe6723728, 0x314cf6a5, + 0xffc4c049, 0xf0e3a7b2, 0x0b8155aa, 0xbc75a1e0, 0x114d6bae, 0xa78169cc, 0x3aa77f4f, 0x8c235e06, 0xaefd81b8, + 0xf70d38a1, 0x3998be30, 0x56071e0d, 0xb170bf19, 0xcb8c1c63, 0x1a354b9f, 0x7a999357, 0x265dd160, 0x8f49a98e, + 0xf3bef590, 0xeae28455, 0x187113e8, 0x51c08634, 0xee8ab9f7, 0x5de94514, 0x1b0c7fd7, 0x8bb5aa11, 0x18ff990a, + 0x4b32bf4e, 0xa80155e6, 0x00743660, 0xc63b9e25, 0x07f55329, 0x86f07449, 0x7a26beb3, 0xa1abd9a9, 0x028b5073, + 0xf679862a, 0x56b026e1, 0x4638cf6e, 0x56b25f76, 0x2826eea7, 0x13ec0401, 0x61a3e545, 0xd0a07ea7, 0x8eb03035, + 0x700f9e6b, 0xb7d2225a, 0x6265206b, 0xbeca73a5, 0x2d106b98, 0x401968d9, 0x59fefd99, 0x49996ea5, 0x521cc181, + 0xf128b3f9, 0x6f3db4a7, 0xda0c3887, 0x195684c7, 0x1493d6cd, 0x564cb492, 0xd6e65b07, 0x4ca51e81, 0x07cd0f30, + 0x85ad9ae7, 0xdc001090, 0x58207561, 0x93697731, 0x9afae558, 0x6efccc2b, 0xfba536a2, 0x066e35e5, 0x6df910f0, + 0xf7e8a2f4, 0x3929674e, 0x510d1473, 0xc7d60f1c, 0xf87d4266, 0x37edc0b2, 0xc07cf968, 0xbd924267, 0x831807eb, + 0xc8a7c350, 0x8bbf7403, 0x4a119ce8, 0x6eed9cfa, 0xf3ab6725, 0x6d6203b1, 0x6612ea95, 0x604c6772, 0xd941d589, + 0x18028482, 0x7541341b, 0x3afc74db, 0x15fc8f2a, 0x3e2fd562, 0xea87cc2f, 0xd05bc5e6, 0x534a1459, 0xcc5fb620, + 0xfe03cebb, 0xd691360b, 0xf0fe8e6a, 0x09f43826, 0x0df148bf, 0xdcf7f4fd, 0x362d02b5, 0x37a30027, 0x1c73c911, + 0xac2e1130, 0x55339bb9, 0x614d211a, 0x367dd0f2, 0x7e4380d9, 0x67df4229, 0x38052ced, 0xf667cb73, 0x2d6189a2, + 0x57334458, 0x07d818d7, 0x2cd81c03, 0xb6178ff9, 0x5afcd318, 0x6c175028, 0x9c45883b, 0x107e2927, 0x1d5948ca, + 0x468f86f8, 0x087a7197, 0x7d29319b, 0x2dd7b8b7, 0x37648ce9, 0x99cd0ae9, 0x7c262616, 0xc7ca6159, 0x6c7aad83, + 0x1425b399, 0xe3665afb, 0x64d96484, 0x3bde4b09, 0x9cde5b74, 0x04997576, 0x703a5b95, 0xa28ea3b4, 0x77c61203, + 0x3eb40786, 0xf7728480, 0x4bf23263, 0x948490fd, 0x19d70b4f, 0xe4842879, 0xbbb8e74f, 0x01f42c74, 0xd1b46d0e, + 0xcc835dd4, 0x7e250291, 0x73fbb7a9, 0x7b738ef9, 0xb6294047, 0x1dcc8aa2, 0xec9e2305, 0x102b956d, 0xe55c573a, + 0x0bf6063e, 0x26022b9a, 0xc11419c3, 0x78149855, 0x44ad4a5b, 0xc03edf1c, 0x1b772969, 0x2f833a42, 0xcf6712dd, + 0x647b02c0, 0xedfee07c, 0x8a2d85d0, 0x879665e3, 0x286e26e1, 0x3a924595, 0xab9c7107, 0xdd1ef071, 0xbde873b3, + 0x689d3aa9, 0xadc03d2d, 0x8f0f00c6, 0x324afa0f, 0xd88b8d4c, 0x7af73eb6, 0xd4601f24, 0xcbc244d9, 0xb1863e86, + 0xf269f823, 0x25c198dd, 0xd0178e95, 0x0aaba90e, 0x65a34611, 0xfa048408, 0x20308b14, 0x359d667d, 0x687cb152, + 0x480f056a, 0xfdcf7b7b, 0xbeb9f0f3, 0x5fed0254, 0x47a88a35, 0x43c71032, 0x5b386357, 0x574e8fb4, 0x26674cbe, + 0x1a18686d, 0x73ce0440, 0x5957edfd, 0x74b60429, 0xecaf7df2, 0xfb71abd6, 0x804fdfec, 0x997130da, 0x2d78786a, + 0xcf2bfb26, 0xc7bae414, 0x33e3570a, 0x229b19ac, 0x0e5c17ce, 0x3f36c7e4, 0x6c49c4b3, 0xde80dc1f, 0xf036ff9c, + 0x9c466a22, 0x7bd34cbf, 0xbb0de394, 0xcfb39909, 0x3370273d, 0xae67a0bb, 0x6c0834ca, 0x8d90ce7a, 0xd95e35f8, + 0x92670ae4, 0x88b10923, 0x6b4c6e95, 0x8cd6a984, 0x1be4b035, 0x2905f702, 0x9db68f44, 0xc8199137, 0xf25eeaa0, + 0x8122339f, 0x5c0aee6e, 0x5308488b, 0xc398063a, 0xaa461caf, 0xa763d64c, 0x5d827fce, 0x56de43b7, 0x3504034e, + 0x61e6e6aa, 0xdc93fb35, 0x2e612f56, 0xb1082bd3, 0xb6e5f767, 0xe4aa88bb, 0x922f526a, 0x915b42ac, 0x7e59609f, + 0x90f683d4, 0x38624992, 0x5b92b8ee, 0x0a8bc0ab, 0xf014030a, 0xe99fbf87, 0xdcc8208b, 0x8ae234e2, 0x3d8f0e0b, + 0x71a65758, 0x3c8b1c01, 0x20acd33c, 0x339b12d9, 0xf1e346ef, 0x66840fe4, 0x981c5353, 0x757d86fe, 0xa09c3950, + 0x38e8f071, 0xc8deb16e, 0xf20fffa9, 0x0db547c6, 0x43c47fbb, 0x2b94f98a, 0x6928fafb, 0x500e6647, 0xa704b495, + 0x3c897594, 0x3d2c12de, 0x20f2e5d5, 0x9fe2610f, 0x5a1bb728, 0x112e361a, 0x026d7aa8, 0xcf8e3047, 0xabe00d3d, + 0x57393b8d, 0x28f0d4b9, 0x9621c314, 0xb7ea975c, 0xaeeaba1f, 0xf9e5d7a2, 0x6835d81e, 0xa42253ef, 0x1d08a235, + 0x404939d7, 0x656a5a59, 0xbf9399e6, 0x0fa35f7c, 0x6896ca2b, 0x2e3b97aa, 0x0b4eb373, 0x3e0496ed, 0xc091d80a, + 0x0ebc5d44, 0xe9ce0025, 0xeeda30a4, 0x2ab3e9d4, 0x59404945, 0x57302894, 0xe865c801, 0xf89ca772, 0x21ba6427, + 0x9596fa77, 0x6d6862fa, 0x7e80fb27, 0xab561cad, 0x01a1e0a5, 0xf98ad068, 0xc1f870c2, 0x5089f189, 0x3ae06f3c, + 0x207292f5, 0x05c1d309, 0x9638bd4c, 0x238a59cd, 0x95e07a62, 0x7aa68a76, 0x1bba6d49, 0xd079b2c1, 0x7a32c6db, + 0x58ca05cb, 0xd074b5ad, 0xb7bafcda, 0x439411fa, 0xf9219ef6, 0x042bced5, 0xa9266700, 0x3ee7dfad, 0x2d0b8a0e, + 0xf06eeb17, 0xd9ca7df8, 0x782e07a9, 0xdb7e0bae, 0xc5670b4b, 0x8132656c, 0x585344ba, 0x5a1c2423, 0x783f9f23, + 0xbdeb2943, 0x7b4e5ec6, 0x54d6b1b0, 0x6df7398d, 0xbbb67914, 0x83192d09, 0x43950452, 0x5d3968a5, 0x2a7425e7, + 0xa5ded392, 0x0055764a, 0x0a6c5c49, 0x039822c5, 0x041ce545, 0xfad314c0, 0xaa3e27d9, 0xe3ac6850, 0x99951410, + 0x609611d2, 0x87c6f618, 0x80d4bc00, 0x7efb7e58, 0x16b7d666, 0xc86d7ea6, 0x6c538ab0, 0xd77a4b9e, 0xd057b3df, + 0x67db353e, 0x60635517, 0x46182708, 0xa6169da4, 0x5da47b73, 0xdcdd57f3, 0x2ea6cba8, 0xb0017977, 0x6f96e3ad, + 0x24a99054, 0x43a7775e, 0x79025d11, 0x823461f6, 0x659ee616, 0xe3b852a0, 0x65dad298, 0x6afc7310, 0x99b19bde, + 0xac37af30, 0x755f6de8, 0x81c2413b, 0x9543dba5, 0x48677e76, 0x1020dc50, 0x224140ba, 0x26aa58c4, 0x026cc902, + 0x0497246e, 0x185f94a5, 0x6695b1e4, 0x4043ddc3, 0x00d33b66, 0x99b96056, 0x576cabea, 0x8710e875, 0xec277d07, + 0x596c3d89, 0x0ed1d42e, 0x0aec7781, 0x2e9251cf, 0x9da1535b, 0x6656567c, 0x07020da1, 0x866a67e0, 0x074f65e2, + 0xd56fe857, 0x8b86e7ee, 0x64043286, 0x653e19eb, 0xed72a1f7, 0xae77b001, 0x0a48b02a, 0x7529cc27, 0xfc5cda7e, + 0xdf0119ba, 0x4e3c2c2f, 0x23ef9536, 0xf3a8b419, 0xf2ee29ed, 0x75011f4f, 0x87d97ccc, 0x74359e18, 0x87e249af, + 0x964f3edf, 0xb2aa3b1e, 0xe7d060d7, 0x79b16329, 0xcbae5be2, 0x769ef930, 0xeb0f491e, 0x80288816, 0xfff66a3d, + 0x245a997e, 0xf7e62331, 0xb51f84e4, 0xdde2d926, 0x23b4df9c, 0xbb8e2d14, 0xbbd29fa0, 0xf71929de, 0xf339d633, + 0x55f62d60, 0xee09c452, 0x6fac6258, 0x65fe4f4a, 0xaec51b8e, 0xc1b5181a, 0xeaa9c1d0, 0xda717bbd, 0x57e854b8, + 0x6604d2bf, 0xe93bd61b, 0x3e0907fc, 0x79eb9b76, 0x5f6ce484, 0xc79394ad, 0xb38c142c, 0x4643057d, 0xfec45180, + 0x42aed6ce, 0x5062d34a, 0x6dd95a3b, 0x4ed57d3e, 0x7ecf8678, 0x19cfea28, 0x78b7b5f3, 0xe8f459c1, 0xd53a3dd5, + 0x89b23704, 0x29806966, 0x5925f819, 0xe976e0e5, 0x8bf8671d, 0x2f2e32a6, 0x696c92af, 0xfb02a953, 0x4e029f71, + 0xc99a9165, 0xcc04c079, 0x3e9dd191, 0xa6e8af2f, 0x155e8832, 0xfd5bef0e, 0xc91d0838, 0x2fbbe935, 0x0997ce06, + 0xc125f943, 0x987810b1, 0x8f746e3b, 0xfab5b2e6, 0xb43feee3, 0x5815d5d6, 0x66d7316b, 0x9b8c7cd9, 0x0e2c59f0, + 0xbdaeb71a, 0xc8f0ccdb, 0x197eeec7, 0x63b363fe, 0xb0958a4f, 0xed98d603, 0x79e9253e, 0xb557b22c, 0x6e368959, + 0xf79f4df1, 0x5c437e8e, 0xb9f7a85e, 0xaec0442e, 0x25421938, 0x99dfc8a2, 0x4ab7dd4b, 0x65c9e2a1, 0x32a1fbd7, + 0xb6922012, 0x6bc40fa5, 0x3cd6ad89, 0x1599edb9, 0xd78b4c52, 0xde1bff2e, 0x5d928967, 0x45c448a3, 0xa22dd77a, + 0x97449f49, 0x69646ab1, 0x0f744a03, 0x07dfbbe7, 0xdf159502, 0x9f01fa29, 0x7837c7bb, 0x08c0a094, 0xb9144bd3, + 0x9b953532, 0x64945b10, 0xe233028a, 0x1221465d, 0x8c84e66d, 0x08a2765e, 0x58551b69, 0x454a351e, 0xb14bb341, + 0xecaa5f82, 0x2cb24ece, 0xf696fbab, 0xb247cc3b, 0xe3d63a76, 0x4cefa987, 0x617768cb, 0xec6ea506, 0x6bdb3ae3, + 0x3a7675b8, 0x17ebd3ac, 0x6eddeabd, 0xed6e5908, 0x8a3e4281, 0x62169a4c, 0xcb153753, 0xd2f901b0, 0x57bb759b, + 0x53ed8c83, 0xce6b084c, 0x1edf365a, 0x9bdc87c0, 0x4eeea087, 0x2c159923, 0x836a5cc6, 0x096c3c29, 0x282a4ffd, + 0x7a4814ab, 0xebf2b8ed, 0x0d23faf6, 0xd9cb77b4, 0xbf2df962, 0x28917c15, 0x65affa0f, 0x70dc4591, 0xc7887b06, + 0xd16e4fe6, 0xebb1703b, 0x4f0b3fe8, 0xb77d7708, 0x0de83f43, 0x60a1924c, 0xdce825d4, 0x6d4909e8, 0xc7e1ca1f, + 0x3294b588, 0x96f5812c, 0x9f10764b, 0xc4a7166e, 0xd4526348, 0xdd2631dd, 0x0a031366, 0x91569de3, 0xd811f571, + 0x0b6a6b95, 0x85255275, 0xc90ce7df, 0xc39cba2c, 0x351380b0, 0x6869aeb0, 0x1ba2ab87, 0xb7713e44, 0x6b437b45, + 0xcb5d1c4f, 0x8e9cb4a1, 0x1d28e473, 0x14b93fbf, 0x66441b5b, 0x0f4eb566, 0xfe23eae4, 0x3c1d9fcc, 0x52b82381, + 0xd4a9658e, 0x583f5c48, 0x08cb9c2c, 0x140ed234, 0xe01990b1, 0x71f7782d, 0xea1017bb, 0xd7ff9771, 0x4aeddded, + 0x8ef1ea4f, 0x03a41b13, 0xa4768786, 0x044b6611, 0x399bda0f, 0x587d3029, 0x27d1b0e2, 0x6bf0c39c, 0x6d38fc9b, + 0x60ecd906, 0xd522cc0b, 0x06899559, 0xfad4c393, 0x64771eae, 0x9fd6c568, 0x82a2c517, 0xd67797f0, 0xc8ed8c0c, + 0xd9526426, 0x5b5ef2df, 0xe3ab3dbe, 0xb4b4ea6f, 0x1d49085b, 0x302605a7, 0x7206cd95, 0x6290cd60, 0x48a58ad1, + 0x1774c890, 0xfd0faa0d, 0xe4d225a6, 0xd7905541, 0xf605808c, 0x377e3be9, 0x24a854d3, 0x606e7e68, 0xb7635a2e, + 0x51bbe2fb, 0x96171ed3, 0x7e17a774, 0xeee99b8d, 0xea0faacc, 0x2c0c8ab3, 0x185ece91, 0x5db50b3b, 0xcfa8ebcb, + 0x1c6635ab, 0xcd1c3bd5, 0xfcb6d5db, 0x34d9b1c9, 0x8c512e52, 0x93833e12, 0x9b4239cb, 0x99a84005, 0xbaf7d7e0, + 0x08c6ce3b, 0x510e60b5, 0x370d8471, 0xf7640ceb, 0x79f9c314, 0xfe43d758, 0x80659070, 0x91349105, 0xac9171ba, + 0x7c3a1349, 0x55ebf0e9, 0x9c31a985, 0xf0118a75, 0x49d15d19, 0x57aa246b, 0x7db9f0de, 0xad2bec8e, 0xcae8c357, + 0xe69070d7, 0x3b626cf0, 0x1cb8b284, 0xfb656f57, 0xb891c22a, 0x4e6d77c6, 0xbcedc5a8, 0xc29cb4a9, 0xc3d4ce0b, + 0x18cfd0b5, 0x6909404f, 0xb8eb24ca, 0x78845ae6, 0xef441b1a, 0x91ebbc62, 0xadf458b7, 0x89e64f1c, 0xdf95543b, + 0xd19161b5, 0x503f7bc3, 0xf9cc152d, 0x4debe1f9, 0xb8b3f408, 0x78db0015, 0x636835e7, 0x4a74f868, 0x9f450922, + 0xe9a77dca, 0x480073b8, 0xf98220c6, 0x0164c85b, 0x882a318b, 0x7c0c6e85, 0xe7553f1a, 0x71d06c10, 0xae23d329, + 0x9991728a, 0x0a2f76fe, 0xb73765e4, 0x2eec9fab, 0xd7c1aae7, 0xfc449aa5, 0x1b7c2609, 0xa3308507, 0x9f0a3e9c, + 0xd31be706, 0x6b02db3d, 0x6b96e3e9, 0x9d8c134e, 0xfa9e6b33, 0xaf09852c, 0x359f28d0, 0x7112123f, 0xc880bac4, + 0x7790c6fb, 0xef037250, 0x50d61736, 0x5ac24e62, 0x28f7b37a, 0xf6982478, 0x345c9cf0, 0x8584d753, 0x98a36eec, + 0xfeeb1aa3, 0xfae98e70, 0x071cce20, 0xb0b684f3, 0xfa0f8fc0, 0x0b77bd8f, 0x726cd1b8, 0x7584c083, 0xbcb15a5d, + 0x49213326, 0x29b0a32c, 0x2173227d, 0xd7b2fd84, 0x348d2d9b, 0x0ffec20c, 0x1c54e674, 0x2aacf70c, 0x711c9f16, + 0xb56c6df0, 0xae534f4f, 0xf1a94666, 0xaea7edf7, 0x49b84f6a, 0x0ab3a16f, 0xeb7d4a6f, 0xed841d64, 0x070ecc8c, + 0xe8f5d9fd, 0x70b659c3, 0xa32b8436, 0x20facac8, 0x50a857a8, 0xfda8db82, 0x31be72d3, 0x7d5ae491, 0xd55678fe, + 0x7ad35702, 0xf0f9014e, 0xca9fc2e2, 0x5b39a460, 0xd7535353, 0x13df22e9, 0x5ad1e5b3, 0x39504c8a, 0x1fdc240c, + 0x60f551e8, 0x81ccaffb, 0x09ecb098, 0xeba940c3, 0x2e12ae35, 0x8b893a37, 0xa5ced6c1, 0x4db05c16, 0xa3de677f, + 0x90e2e010, 0x3ca96521, 0xd56bdd07, 0xc2fd1b4b, 0x3099d328, 0xea5812fb, 0x4e2d873b, 0x2d929b67, 0x27ae2196, + 0x1d6d3a6a, 0x445ae35c, 0xf5c17a1a, 0xf6330e25, 0x2ff08785, 0x2baecb3f, 0xc36392bc, 0x1bc78559, 0x4ace4333, + 0xbd8affec, 0x63a1db18, 0x12841038, 0xae1322ee, 0xc53287c9, 0xd6413769, 0x15a4fb11, 0x6dfcc04d, 0x325a9df8, + 0xf0930952, 0x0dc4da6a, 0x56bb4d1f, 0xc1a616a7, 0xfacbd535, 0x806963a1, 0x8721328f, 0xab521bcb, 0x461028ba, + 0xd1404653, 0xed2ec4c4, 0x8456e9a8, 0x288b02de, 0xe74f6b57, 0x15ba1267, 0xcdea079e, 0x647071d8, 0x93b061b2, + 0x935d6985, 0x766c45b7, 0x685ae1dd, 0x4a46f6a3, 0xfb9a0644, 0xcf4e6c55, 0x9ccee18a, 0x816bc1bb, 0x616b3118, + 0x5bda7e6f, 0xca46873e, 0x4decf8fe, 0xcc330559, 0x4065c9b3, 0x5c2c7be2, 0xa437725f, 0xe74065f3, 0xc4921622, + 0x7efea911, 0xc6c0b1ef, 0xbddf109d, 0x4a24520f, 0x47016950, 0x19ec01da, 0x3dd55d76, 0xfbbf6107, 0xa0457fad, + 0x89aed75f, 0xc5b41c30, 0x6778265c, 0xd4380dfd, 0xb2efc0ca, 0xa5b42ca0, 0xfa0040df, 0x1b1d1fdf, 0xea397cca, + 0x21617b95, 0x1018fb1d, 0x8fb9487d, 0xc077bab6, 0xdc9dbdbd, 0xff2919d2, 0x680193ce, 0xa8453dda, 0x2ef76415, + 0x01553253, 0x8cf36d71, 0x1c8ab4c0, 0x6707bcf9, 0x2ef29006, 0xa10607c9, 0x0322e371, 0xa52e2e6e, 0x56f7da79, + 0xa4acb05f, 0x5e4abffc, 0x23eb42a9, 0xe8d480a2, 0x2e041b8d, 0x0f2de73f, 0xaf003408, 0x852e4846, 0x2e193de6, + 0x01950c6d, 0x0745a6da, 0xf88c2d66, 0x911421e5, 0xdd482551, 0xd32f0fa9, 0xc776005d, 0x725a68c0, 0x88ed0f95, + 0x3d6a3146, 0xff9908cb, 0xe0b74cf9, 0x467b20a5, 0x434147ad, 0x1d48eb96, 0x707cc21a, 0xf1496075, 0xdd4d79d8, + 0xdbd2f5ae, 0xc7e81b6d, 0x2e37219d, 0x4c7b6fa7, 0xc69b4419, 0xd53a3d95, 0x903f5020, 0x043b2e03, 0x6c22c447, + 0x94fc0947, 0x035ffad6, 0x8bdc88d7, 0x76c1c023, 0xeff16874, 0x8611ab6a, 0x85b608a7, 0x32168d8f, 0x25fa1aef, + 0x253f7f21, 0x29844fe5, 0xfc927834, 0x3cb35219, 0x9b199995, 0x322d12c1, 0xc06e5579, 0xe13f7606, 0x8dbfc059, + 0x899646b5, 0xf0f2a64d, 0xba644b35, 0xaa387cfb, 0x443034a2, 0xebdd3a8e, 0xe4a91f98, 0xc306ca47, 0x56e6de31, + 0x8e9c950f, 0x41d5ac3f, 0xfce7628a, 0x2d34b704, 0x198301f9, 0xdb950db6, 0xb3203518, 0xe182fd83, 0x4ef53306, + 0x6ed8cddf, 0xef9f1c57, 0xa1a56573, 0x23bc4e9c, 0xd0c1b08e, 0x7ab8e923, 0x3ce6c42d, 0x2e6c4fdd, 0x3bfc7989, + 0xbfcc8e53, 0x961780b4, 0x822da396, 0xa0a5c72e, 0xbfa232c7, 0x10523e7e, 0x83445d06, 0xbf061db7, 0xcf5ce764, + 0x1818a3e5, 0x801895d2, 0x2ba6be36, 0x280bc242, 0x9792d5f5, 0x59bd642f, 0x23f576a9, 0x787dd5b3, 0x7464366f, + 0x6359af1c, 0x1b1fef8e, 0x287f7417, 0xd452b765, 0x9e6440d9, 0xec28cf95, 0x612c8b57, 0x324ab689, 0xb9cd7630, + 0x0772d583, 0xb0138f3b, 0x0703b95e, 0x25da5618, 0x74ff9dd7, 0xe1fdf07a, 0x1d239223, 0x78a31e89, 0x50ed61f5, + 0x1c5c76a7, 0x011aa72d, 0x70fe9ac1, 0x6c390e97, 0x3095f339, 0x26c055f6, 0x8776c136, 0x4deed7c7, 0xd2241eb8, + 0x2040543e, 0xfc5bb9e0, 0x9e351476, 0xf3e1174d, 0x89dc36a7, 0x091ee15f, 0x188ab77b, 0x4758857a, 0x349b4326, + 0xbbe809cf, 0xfb715fb4, 0xa51b69ec, 0x913e5487, 0x83fbec32, 0x0264267e, 0xef3b9a29, 0x55bb87e1, 0x960cd8b0, + 0xb8becca3, 0x686ffaa8, 0xc3fb9f1c, 0xd6ef0563, 0xfb897efa, 0x6c8efe23, 0x4718f44f, 0x79ceabe5, 0xb405fe55, + 0x2e3fb4fd, 0xf1742701, 0x357562ab, 0xc8c06f25, 0x13a140fa, 0x797c5374, 0x42eae636, 0xa1a6efa2, 0x1ab162aa, + 0x36aca560, 0x85f0c95a, 0xd70c883f, 0xf378958c, 0x0fb81831, 0xdad0069b, 0x9df483ee, 0xac106ca3, 0x277327fa, + 0x093e95e8, 0x5833264c, 0x21d14258, 0x4c0666c8, 0x88cf8870, 0x5228522a, 0x3ca4cae7, 0xd856aa61, 0xc4d7a6f1, + 0x0b748b10, 0xadd096fc, 0x881ae19e, 0x7c1fa6b3, 0x18f72fd0, 0x0f7b357c, 0x2bef8ffa, 0x525e9e60, 0xc9c7c0b0, + 0x69ab27cd, 0x1bdf5967, 0x1924595e, 0x369b7bc7, 0x18aff0ef, 0xca9ab58d, 0x3f50c042, 0x0f1b275d, 0x934bfed6, + 0x26022a0d, 0x635a8ff1, 0xad236565, 0x10fa84be, 0x35320a98, 0xc53327d5, 0x40240df8, 0xe28cf42b, 0x82a9bb07, + 0xa933d3c7, 0x5d004a65, 0x27401aed, 0x527b9eee, 0xcac0ae33, 0x953ad816, 0x2e1e18e9, 0xa8e4f1c5, 0x97b3bc47, + 0xffede808, 0x622a3342, 0x741eafe8, 0xa1eb3d72, 0x24121c5e, 0x3ea3548f, 0x8c05c61c, 0x4ef03d0c, 0x77135e62, + 0x42a0afe5, 0x19471dba, 0xf0fc80ba, 0x4d95edfb, 0x48655b7d, 0xf1019413, 0xb36b9747, 0xd6e9fe91, 0xc2809a6e, + 0xd27ab578, 0x9ecd6107, 0xe3695c31, 0x6e166fde, 0x73d341e7, 0x702269a0, 0x33e45ceb, 0xf7153e22, 0xceab928e, + 0x6c7b5390, 0x38ae66d8, 0x71a1d8bb, 0x000591ab, 0x0db16721, 0xf844fc36, 0xb74dbead, 0xe0c71a17, 0x6f158793, + 0xa444d529, 0xe90886cc, 0xb9de3bd8, 0x346ee259, 0xe9dc00b1, 0x2de0a88f, 0x57c06bbe, 0xb74391af, 0xbe39c7a0, + 0xf17ba529, 0xb0c5784f, 0x83ca2772, 0xce02764a, 0xa11bc2ea, 0x336eaaa6, 0xa6a2192f, 0xea8476c9, 0x09469837, + 0xf3cb8645, 0x0c6ff0f5, 0xbdcfd8e1, 0x2e1cd4ee, 0x21219ffe, 0x13137ba7, 0xf1762e76, 0x9f0e2490, 0xbfd2dabc, + 0x35524a37, 0xb0424bd0, 0x608e06d5, 0x0cd05d9a, 0xb7d7712a, 0x4585fcd3, 0x0c81e901, 0xd7787f60, 0xe5303313, + 0x3ff22125, 0xd9ab528f, 0x199a6fa7, 0xa0433ff6, 0xeaf67d0a, 0xad8eae5b, 0xb9baf3b2, 0x8bf10871, 0xba439a47, + 0xed7f434f, 0xcbcf6926, 0x9488544c, 0x9b4ea2cb, 0x757cf4da, 0xad932440, 0x10c64315, 0x3b8f1456, 0xdeec9119, + 0x0d0541dd, 0x3a0949dc, 0x0047f87a, 0xa01723af, 0x3cf01b7f, 0x4d44643e, 0x3d2492ad, 0x7cbb91bc, 0xa0b6dc58, + 0x49a2c522, 0xd27e2577, 0x78fcf879, 0xa4a2f303, 0x197c0caa, 0x13ac9180, 0x39ac18b6, 0x80e50fa9, 0x93dd9652, + 0xf414252e, 0x4ba93830, 0x28b46cd3, 0x64370d1e, 0x0d244294, 0xc5581c9a, 0xa723ad7b, 0x23f27717, 0x7af5d9ff, + 0x1044f4a7, 0xb8ca58ee, 0x552426a2, 0x29ada1c7, 0x18b307e9, 0x528ca545, 0xc0265dad, 0xf0e0bd68, 0x4de3a2d3, + 0x4532ad65, 0x8754a298, 0x15a1f161, 0x70dd7ad0, 0x354b54be, 0xbbe6e2cb, 0x042838ba, 0x05ec64ea, 0xbebc02e1, + 0xd3fa95b5, 0xabd0bf2c, 0xb7f8e734, 0x206fa0db, 0x5bbc4614, 0xc57af0b6, 0x217a537f, 0x9911d7c2, 0x3aed8dd1, + 0x3b839c2f, 0x21f0d430, 0x3f86df65, 0x317f0c14, 0xadca50f3, 0x08dd48d1, 0xb908ff8d, 0x82c78170, 0x99b9cf0a, + 0xcc0cb95a, 0x17ca1b33, 0x68b4acf0, 0x1639a5bb, 0xd558447e, 0xc0e49974, 0x6eea88ed, 0x37e82348, 0xca3d3a8d, + 0xfa214b41, 0x1175db6b, 0xdbdc05a6, 0xfd5f06e2, 0x8fb59e17, 0x5ecd15ef, 0xf5f89820, 0xfc08c63f, 0x093c4b6e, + 0x7c9fe492, 0x07be602f, 0xe3b3b7cc, 0x6ac536f3, 0x01aa5f9d, 0x98449b11, 0x0d3ff557, 0x6feb3955, 0x1a5fbf35, + 0x5436ff44, 0x6008a3da, 0x7ceaa5ae, 0x498abab8, 0xfeda84cd, 0xc895e186, 0x11bd88dd, 0xf372c2f0, 0x9f1f8280, + 0xd13854fc, 0xa546adc0, 0xadef0bc9, 0xc9e35bc7, 0xddaee329, 0x19eec89f, 0x332ca259, 0x92a4c838, 0x78ab432d, + 0xbddee665, 0x59888212, 0x40c91bb8, 0xa5f9b14a, 0x4f27452e, 0xff948a87, 0xc04a25f0, 0x901b1d6c, 0x0ef52329, + 0x051e3aa3, 0xded5ef16, 0xe17b5440, 0x56a785a2, 0x6c913ec2, 0x264fe160, 0xeaad10aa, 0x1bd19e00, 0xa4b0795a, + 0xecaa77b0, 0xfc3f9944, 0xee67efeb, 0x81ead54c, 0x6448f057, 0xc28c2c74, 0xa0a83e3c, 0xf7addea3, 0xa23a3b4b, + 0xda5b168e, 0x5e3e8a34, 0x029d544e, 0x60f2ae8c, 0x99048350, 0x910db89f, 0xcaed7135, 0x83879a6c, 0xb9a25bcb, + 0x604aa1e0, 0x5487c3f0, 0xe53c0f8e, 0x398e2791, 0x4d4eee26, 0x8127fcca, 0x3e2e567c, 0xccc7bcf0, 0x93f34b30, + 0x9498aa7e, 0xefc22e36, 0x0a7af718, 0x14fb15e5, 0xde4bec52, 0x823ee3cc, 0x6d73351e, 0x8ef60e5d, 0xd6ad249e, + 0x36aa32f9, 0x585f7230, 0x894841a8, 0x4561f61b, 0xef40d265, 0x7b576678, 0xb163d72b, 0x1991cc22, 0x5945703f, + 0x81f19fc5, 0x30037d99, 0x20960b52, 0xc67cc35c, 0xf6ea82d2, 0x9f806a41, 0x3a95a10f, 0xbcc84e72, 0x0ac82b3f, + 0x22bcf234, 0xbf574cec, 0xefb1812d, 0x65b809b9, 0x72e5dd6c, 0xff3e749a, 0xc86a4798, 0x9d6bdf26, 0xae1f45e4, + 0xf1ee8a77, 0x41e557fb, 0xa5073b28, 0x30baf9b0, 0xa48d9112, 0x936833cd, 0x478baace, 0x3e09ff30, 0x9f041322, + 0xc2f05e5d, 0x4c114e8b, 0x63d8d495, 0x49d3e0d7, 0xebc3c9ed, 0xb6368ed0, 0x3f4322bb, 0x321edc76, 0x4af918c4, + 0xe4d77212, 0xeda622e4, 0xdba114bb, 0xcb9785ca, 0xa6f97cfc, 0x164d813d, 0x7abbd335, 0x211bbb05, 0xbeff9eb9, + 0x265de5ad, 0x2c91f864, 0xdd3169d5, 0x8d565cad, 0x93da41fe, 0x8ee84098, 0x17ced890, 0x583f3021, 0x78661298, + 0x5ef86e7a, 0xf55cd574, 0x2c491eac, 0xc1addbcb, 0x7afd7e3d, 0xe8a1db6f, 0x02ae648d, 0x9c3d107a, 0x7d604b55, + 0xe31cfa93, 0x7513a219, 0x54864f62, 0xa66f9c42, 0x908730f7, 0xb3eb6329, 0xeb097afc, 0xa36c9a8b, 0xe28d40a6, + 0xea694708, 0x93457fd4, 0x0ad926be, 0x32e3663e, 0x475af337, 0x6a23ce01, 0x63d560ce, 0x0d556f70, 0x14d85c2e, + 0x0ac017aa, 0x61fe2e93, 0x7791a8f9, 0x6cab7591, 0x2845517a, 0xd14a40a3, 0x933c46e6, 0x84069768, 0x9034b35b, + 0x375a42e6, 0x3d515ec4, 0x67e7c441, 0x267be921, 0xa10eded3, 0x63c66021, 0x5616a57c, 0x47254546, 0x9e0319b5, + 0x2f9d3315, 0xa67a0176, 0xe8d7a2d3, 0xcf7b2909, 0x950d2437, 0x90a9e662, 0x140358b8, 0x1d4c84ff, 0xa32e9843, + 0xfd4e81c4, 0x91f02e23, 0x8daa45d6, 0x836b4894, 0x2b107e93, 0x65651486, 0xabe81bce, 0x65b18532, 0x892f384c, + 0x7d44f7d1, 0xbafdb361, 0x5680aa31, 0x6d81b8ba, 0x0c1fa391, 0xf90071fc, 0xacdb9a1f, 0x0bc955f4, 0x41fb638a, + 0x0d0ffa2c, 0x82d9663c, 0x931c31ce, 0xef256ea2, 0x607cea69, 0x0b0f0d0a, 0x1a02471b, 0x9633288d, 0xbb5a5e56, + 0x5ff9e849, 0x1bf13fd2, 0x555eb5d4, 0x17f9f426, 0x90a7d17b, 0x30122614, 0xdc3f0e99, 0x6ad2f666, 0xf6114466, + 0x042dda88, 0x936f9793, 0xe42f0d6c, 0x11f2a36e, 0xa8c049b5, 0xa8aeccaf, 0x675073ee, 0x1bc4790e, 0x9875fbb9, + 0x5cc85f90, 0xde0a73c1, 0x7332233b, 0xa7a3c325, 0x23466169, 0xd9dd99fc, 0xc7b3589d, 0x9b285b31, 0x15627f87, + 0x65115420, 0x7f047465, 0x64b94290, 0x356caa58, 0x400cb0b6, 0x7a90c0b5, 0xca1ea90a, 0xaef81e80, 0xf25aef77, + 0x0d4634e5, 0x2e63ad25, 0xf5eedab6, 0x48524cb6, 0xf7de49d9, 0xa71e4a3d, 0x5ad6469f, 0x8bcbf70a, 0x132c3a17, + 0x6c1913a3, 0x5c27a36c, 0x67bc699a, 0x0753c21a, 0x9c03bbfc, 0x314e5b66, 0xe690d572, 0x6e24bb12, 0x7eae7dbe, + 0xb0c139c6, 0x22a20179, 0xe2af9167, 0xcdd899b2, 0x84690317, 0x547edba9, 0xe157d37b, 0x5d216b22, 0x534c420a, + 0xc3085cf9, 0xc5f5a23c, 0x8a6cc983, 0x676260f4, 0x80490c26, 0x74bd0f0e, 0x0e6060f9, 0x8441c04d, 0xaa555e6f, + 0x35047e31, 0x7450cdb5, 0xa4008db9, 0xf55e38d1, 0x69f7ceac, 0x877dc026, 0x3551c469, 0x3731fe46, 0xa223f618, + 0x284a1750, 0x4004f2b6, 0x7bc67a66, 0x32a7a9c3, 0x1fc462b7, 0x5b2c4eea, 0x4b89c9c5, 0xbc28ac26, 0x6111159e, + 0xaa8ced5f, 0xd7d87041, 0x3757e4e3, 0xcee6bdfb, 0x42b20d56, 0xb024cc42, 0xbcd2a4ea, 0xf5d9730f, 0x667f76de, + 0x39295c20, 0xf3e2ea2c, 0xcb33cb24, 0x2153f6c2, 0xe7132235, 0x317348a9, 0x7735bb32, 0x5b8dd214, 0x2902bf0c, + 0x95921b2e, 0x5dbb32ef, 0xa6796e26, 0x5ca75e17, 0x3f7333f5, 0xd1b51209, 0xe2e844a5, 0xe68f9874, 0x115554b0, + 0xdc343c7c, 0xab8ed4a2, 0xf7988c60, 0x8325ccca, 0x3cd2b186, 0x25267280, 0x62822d65, 0x7892f22d, 0x4963b958, + 0x5d5be217, 0x0cd05e79, 0x43d065d9, 0x6ba6ee20, 0x308a3a57, 0x1048a92f, 0x0698a513, 0xd068b583, 0xffe3d6fa, + 0x94d550cc, 0x21e38c3c, 0x9778d84e, 0x06f35fa2, 0x2abdb10e, 0xd585a7d5, 0x5cd8ce6a, 0xa7a79813, 0x49b5883f, + 0xd49b37a1, 0xf6d7b268, 0x7402a8d3, 0x26f7536b, 0x7d8364a8, 0xf564a18c, 0xae2fbea4, 0x5d6563d2, 0x33abc15b, + 0xad15b239, 0x97d422e9, 0xad9fa47d, 0xb5425d34, 0xc4a14dbd, 0x60b1f163, 0xb4572a24, 0xc8872196, 0x0eae5844, + 0x6b4035ca, 0xa8bff99e, 0x91bd6810, 0x31d37413, 0x9f40afdd, 0x8d577fa7, 0xe82bcb78, 0xc9be82e1, 0x4df0edde, + 0xc03d1102, 0xeb0f2333, 0x69b5c34b, 0x70c83ead, 0xb4fab489, 0x5404db42, 0x0baae87c, 0x1434d49b, 0xf157f594, + 0x4e3aa4ce, 0x35458443, 0x95465d2b, 0xa51ee32d, 0x884e3c9a, 0x70160cc5, 0x7c9810ec, 0x5e06a35e, 0x075b88f2, + 0x825644e7, 0x22e7bac1, 0xd4855032, 0x41352500, 0x8839e5d4, 0xc1196d9d, 0x9c5d35ce, 0x78558f4a, 0x160e44f5, + 0xdc0f52b8, 0x8b65ccbe, 0x962cc8c0, 0xf16a5a7e, 0xbe42c3d5, 0x53fc7ba6, 0x407584e2, 0x84ec5286, 0x23b149c1, + 0x1adaf1bc, 0x69a6540b, 0xb7dcc02a, 0x64886987, 0x5b649d43, 0x8eb66d66, 0x7e92d871, 0x74cf3b17, 0x3baa95c1, + 0x6c505219, 0xdad034aa, 0x3f602ddd, 0x7e91c202, 0x8407d4ea, 0xcb1b6030, 0xff0c412d, 0xb53eaf9f, 0xaf7daa50, + 0xe29dc4ee, 0xf805c7c2, 0x2d3f49fa, 0xbe5e4e71, 0x9fc6038e, 0x9d050478, 0xb48e4a40, 0x323da799, 0x9badca8f, + 0xbf02f907, 0xfa69e3b6, 0x803f7a6d, 0xdf4ad35a, 0xbf3db325, 0xe4df75bf, 0x393d909c, 0x5bbc1c26, 0x35370439, + 0x9cbcf551, 0x5bdb8b88, 0xd33bb9d2, 0x56fc2293, 0xde658060, 0xfd140da0, 0x9d825901, 0x566adb27, 0xeda908e1, + 0x5ebcb187, 0xb83c6d62, 0x47723848, 0x5e5519f9, 0x7a177c24, 0x6f8561ae, 0x1ef8f598, 0x268a4704, 0x19ecf9eb, + 0x2a84c709, 0xcde43366, 0xea627ee4, 0x30f8368e, 0x4cee4e2e, 0xf97cb149, 0x6326a79b, 0x73a7c6bc, 0xc25c64ab, + 0x67ccef3e, 0x9e30da4f, 0x027d2ee7, 0x58ed86ed, 0x363a12e6, 0x3c42896e, 0x2753b498, 0x8b340593, 0x53e13153, + 0x8f4534e9, 0x87ba77ef, 0xeb39b71d, 0x2f3f113f, 0x30d07879, 0x9bed606a, 0x477aa0e7, 0x9d3e04f4, 0x8123fa84, + 0x2c60c4e4, 0xe8058364, 0x50be9ea7, 0x1687e5a1, 0x3e9e7832, 0xb5417491, 0x581785ee, 0x8da51964, 0x88ae5d90, + 0xc0752ec2, 0x4ce9ca3a, 0x76a59948, 0x47f80c34, 0x02e4b6e0, 0xf2a1cfb7, 0xd2292a03, 0xdb267db4, 0xf10354ef, + 0xb240da1f, 0xc4e47f08, 0x7bf70c10, 0x0f3f477b, 0x4b9e3911, 0x8d175bdc, 0x53fec89e, 0x956cc2d6, 0x31c497c1, + 0xfdcb6b65, 0x036a3f62, 0x3ce1eced, 0x4c74be6d, 0x32bf1979, 0xb477ebbd, 0x2f1e919e, 0x00732196, 0x2f62cf63, + 0x5a64616f, 0x9a57e296, 0x6f6ac705, 0xdf92eb9f, 0x30342028, 0x49f14ca8, 0x329a26f1, 0xb1d54f6a, 0x608ea4ab, + 0xda377d27, 0xcf4cd092, 0x03a6e6ec, 0x7dcbf703, 0xe6f3b7f3, 0x618b1bcb, 0xfcb55d9b, 0x5b1a6653, 0xb433902a, + 0xbcc6c46c, 0xbcf0755b, 0xcf2e1219, 0x49647033, 0xdf810459, 0x0a78eabe, 0x54db295b, 0xa4d2e405, 0x4332b6ea, + 0x6ae2da2c, 0x341c047e, 0x4a539a0b, 0x5a105c26, 0x4fa94c14, 0xe1f0fd00, 0xa3beb1dc, 0x5436deaa, 0xd352e1b7, + 0xd0c99d35, 0xafe9cf4d, 0x4d72363e, 0xaadc29cc, 0x490c4531, 0x2042363b, 0xea06ee86, 0xefc37592, 0x9bf19d31, + 0xfaeea22e, 0x37adf412, 0x06427676, 0xb37f6758, 0x4834618b, 0x23c7d9a1, 0x21b4a4f2, 0xc7c332f5, 0x05409f3c, + 0xc0f9eb2b, 0x70005a65, 0x0de87249, 0xd7d49b8e, 0x569859ab, 0xf3c4b800, 0x1cea1d46, 0xa4516bad, 0xb765eb80, + 0x9b7535be, 0xcb7b2e50, 0x6d9d710d, 0x2c954b82, 0xca2c76aa, 0x45715845, 0x952d5be4, 0x346063b1, 0x4f19dfae, + 0x529c0a0a, 0x6e3f3e25, 0xd32a952f, 0xb7b82efd, 0xb2283180, 0x20b6b5b3, 0xb158ce10, 0x3c7487e3, 0x8b131fa2, + 0xef97bce7, 0xfb01a669, 0xa8b0fb0f, 0x10319264, 0x585c6821, 0x67ddf82f, 0x2ed461df, 0x81fe667d, 0x4261acd9, + 0x512d4023, 0xa93ce498, 0xf200df02, 0x55941130, 0x79001149, 0xece774d7, 0x7d226da3, 0xc9b75b70, 0x07f08606, + 0x64bdc2eb, 0x7d26303b, 0x38a13e3e, 0xd97820ef, 0x5a435b88, 0xb7d4b9a4, 0xe6ca57c7, 0xcca3eb1b, 0x43b8727a, + 0xac70aee6, 0x6108c31e, 0x663873f6, 0x911057dc, 0xcaae7369, 0x362905c0, 0xbd7cd7e2, 0x7b18f6d3, 0x2918736d, + 0xdec38ddf, 0xaf1bea34, 0x531a6de5, 0x4ecf3f10, 0x6e59139f, 0x6de153e2, 0x1b467939, 0x5b2527ad, 0xe37f9a1e, + 0x1444780b, 0x56984dbd, 0xce6125a1, 0x5ba00809, 0x6e2998a8, 0xefd43dda, 0x53aa8efa, 0x3e270b55, 0x434a4ce3, + 0x97613503, 0x5edd4bd7, 0x1d4e0bc4, 0x2543fa49, 0xb7e22208, 0xa11546ba, 0x01280cbc, 0x14d2c6ca, 0x030114f5, + 0x75a443b7, 0xef71b86a, 0x33443116, 0x5d05cfab, 0x5ae87b27, 0xa700ba9d, 0x54f6b1f9, 0xf8076350, 0xbc4ec6d5, + 0xc0a6c286, 0xb5956c02, 0x793f950a, 0x28a7a5ce, 0x41c97276, 0xb89be1a7, 0x1a590791, 0x3a59b9cd, 0x13a6382f, + 0xac0a7dd1, 0xe2f77bd6, 0x6ac00825, 0xea22785c, 0x8f60d10e, 0x59a87bcf, 0x067bab24, 0x87a6c6e8, 0x6340967b, + 0xb630d39c, 0xa1ddc765, 0x16c88524, 0xc16b73bf, 0x16ed3808, 0xcd3839b6, 0xf13a07bc, 0x9ab33642, 0x0cd97a07, + 0x3fd75c60, 0x8ef21997, 0x98de71f9, 0x8e85a255, 0xcaba76d5, 0xdb20ae34, 0xf8c95a02, 0x57ff3ccc, 0x857328a8, + 0x990eb07f, 0x0857e355, 0x79e95d75, 0x1dedde47, 0x37f98ac9, 0x4386da85, 0x97934af4, 0x80c6481b, 0x028ce833, + 0x410c7797, 0x425d4c00, 0x9bc5c281, 0x238773d0, 0x2527ef96, 0xaf13e81a, 0x0cfad1c5, 0xd4b546fa, 0xb4a1eb34, + 0xbc06fc7a, 0x6abdf2f2, 0x7dd8a7db, 0x4ec21e96, 0x49d71aa5, 0x581dbc45, 0x5b6c4bf5, 0xce3f7e6e, 0xa037f1b5, + 0x3cff148e, 0xb69b2c93, 0x746f12f7, 0x603ca80d, 0xa69c0fd8, 0x4ba56bf4, 0x1190a837, 0x60aa6a9f, 0xe5f8c607, + 0x51baf95f, 0xb2bb4e11, 0x62f202d9, 0x435aefee, 0x0f42a3f2, 0x6d50d36b, 0x127dc27e, 0x672257bc, 0xa1e6cf00, + 0xd4e1f8cd, 0xbc8e566f, 0x7b6563c8, 0xf728226f, 0x349c3b7d, 0xa05fc152, 0x4d71e033, 0x85f33f56, 0xced64d95, + 0x8a991f5e, 0xcaca719b, 0x8b52e421, 0x953570f6, 0x639de297, 0x9966e258, 0x111c5b12, 0x410d8901, 0x2b183899, + 0x7cfa99d8, 0xa02fe9eb, 0xbbe46c91, 0x4b3585aa, 0x95cec575, 0xa3f73f6b, 0x3594f706, 0xf9ca0d0f, 0xc20f27b1, + 0x3e4eed71, 0xb5849877, 0x1eeb7a3f, 0x06aec493, 0x76f9131e, 0x23bdbbd9, 0xb437875b, 0x5c273af3, 0xa9cc7e71, + 0x8d078da3, 0xf646b314, 0x1f0106eb, 0xffd3a6b9, 0x582e56f7, 0x1af6ce8f, 0xea2888c9, 0xdfae758d, 0xeebc0f89, + 0x499df944, 0xcae84dd5, 0x4be6439e, 0x61e2ecd6, 0x3df5549b, 0xaec117e8, 0x67107c64, 0xbd00db9b, 0x7aafae03, + 0x7487bd5b, 0x0021e997, 0x4216325b, 0x15e1b863, 0x42c896dd, 0xce7655de, 0xcb2b36d5, 0x786a0aef, 0xcc893810, + 0xb388096e, 0x30fd6973, 0xe7febd9e, 0x351062f2, 0xfe31057e, 0xf21e7ce9, 0xecfe2be3, 0x899265e9, 0x8377f38f, + 0xde89dcfb, 0x9dcd1f70, 0x790d6376, 0x4feb1b52, 0x20d10247, 0x76a25da6, 0xdf579044, 0xff3e445a, 0xf3107685, + 0x16969538, 0xf02a5f3c, 0x60a5e278, 0x4d58e7d2, 0xa44ac5d4, 0x0c692219, 0x00622cb6, 0x04e59ee1, 0x871e46a6, + 0x28c2d625, 0xbdb4e468, 0xd3fe3a7f, 0x58661034, 0x975a15ce, 0xc9f8c196, 0x2283bcab, 0x5028b149, 0xba519cf5, + 0x14c05ca2, 0x0becf461, 0xb023784f, 0x20e30639, 0xeca90705, 0x4375506e, 0x9d2bd850, 0x8e02efc5, 0xc5b56499, + 0xfcb1f81c, 0x922c828f, 0x396ad293, 0xa0468cc4, 0x49f036f6, 0x55b81234, 0x39d8041b, 0x3f91109d, 0x0a69c544, + 0xf06fb844, 0x09159138, 0xf9a70789, 0x59aa96ea, 0x17558813, 0x8e621355, 0xf202ac2c, 0xf4c8b678, 0xcb0e3be7, + 0xc05ddb93, 0x25aa1ac9, 0xe1650698, 0x508d91d8, 0xf9b5a1c0, 0xe80e0dcf, 0x96b3c7e0, 0x7a6c663f, 0x8b64c486, + 0xc2049d5c, 0x1aef4c15, 0x40d8560e, 0x35721742, 0x7211b9a8, 0xfb1729df, 0x3a9ab5ae, 0xe219c03f, 0x92b09fb9, + 0xb405fb4a, 0x7b7a8c6e, 0x7b2f6be1, 0x9af4ab7b, 0x49b12a58, 0x31f85733, 0x589b5249, 0xf0cedf86, 0x226d220f, + 0x90be6ee9, 0x1ac31cc8, 0xaa628527, 0x01949066, 0x4c8654a9, 0xe9755e29, 0xd856668f, 0x882b222a, 0xcaeb6384, + 0xb1c047a4, 0xa9bbfb78, 0x7e28ff6c, 0xc0e22504, 0x88640a39, 0xaf0c46d7, 0x967a8487, 0xde00cd7f, 0xb7d9379e, + 0x8481fde9, 0xff6ea882, 0x32c5232e, 0x5a86c37a, 0xb8e0f696, 0x28439463, 0xe6b78d43, 0xda72eb05, 0x236da76a, + 0x975dcf66, 0x0eb888b0, 0xf8eabdc8, 0x0518a363, 0x0373d479, 0x7112da7f, 0xa8af6d91, 0xacd8976c, 0x58a5ba74, + 0xda87390b, 0x3a96d653, 0x2241e088, 0x330f5df0, 0x9ff27b4d, 0xf036e70d, 0x17872f35, 0x77156e14, 0x17e77bd0, + 0xaccaf76f, 0x27359498, 0xbdd7c71e, 0xa437c14f, 0x45d7f979, 0x218cd6d5, 0x68bce281, 0xb183a7a6, 0xd5d687ad, + 0x30859edd, 0x7d6d4083, 0xb067605f, 0x2e23ef7f, 0xd23c5479, 0x111e5c08, 0x7bb2912c, 0x930b8a74, 0x3b94186d, + 0x70e5bc7e, 0x856cbd16, 0x2ab1f055, 0xa92a1b83, 0xa7b0dbf8, 0x597b2158, 0x81bef286, 0x545df8f0, 0x5463afb5, + 0x64e4f4ea, 0xe6ce3019, 0xf536610f, 0x8db23d13, 0xa8124614, 0x94016eba, 0xbb3646ff, 0x3ff3bc1f, 0xdd2e849e, + 0x724a0776, 0x6569f0dc, 0xd914127a, 0x75289927, 0x14d7bbed, 0x2a7f3624, 0x12cd001d, 0x3bf85550, 0x36dc12cc, + 0xa38b26be, 0xd6c1de7d, 0xbb9a017d, 0x9c2a54b4, 0xa42d7cf4, 0x81adfd1c, 0x82e3bb4f, 0x9f3fca7b, 0x55f14501, + 0x8258ae1a, 0x34bdfc68, 0xbae32498, 0x31958d06, 0x32790d14, 0x520533a0, 0x54fcf483, 0xd238cbb7, 0xe245f05b, + 0x810b8a0b, 0xd9ff83b7, 0x1078a72d, 0xc8235e1c, 0x2534bd7f, 0xe6ff56ee, 0x298d1bc2, 0x14945c9d, 0x32398305, + 0xd21924ee, 0x1447e908, 0x26514887, 0x4d7ca5d3, 0x6640afe6, 0x058f223d, 0x1d741182, 0x1e20bd7f, 0xd64885fb, + 0xec51f8eb, 0x642d8ab0, 0xc88a32da, 0xa13bdff2, 0x7bf33f61, 0xfc1c1a05, 0xeacddbc6, 0x7f55788a, 0x2ac6a969, + 0x9a131899, 0xa729d23c, 0x219936a9, 0xbddc6a7b, 0xee7e3f09, 0xa128463e, 0x9ab7e720, 0xfc63f6ea, 0x8ba054c3, + 0xbed76d20, 0xcdad1e9b, 0x46a41e30, 0xfd88b447, 0xee0ec7af, 0xbbb1073f, 0xed877217, 0x12800971, 0x74735b1b, + 0xfb2287d3, 0xdef754e8, 0xa651c5f6, 0xbb2c3bc7, 0x2df7c4d2, 0xdc07b491, 0xc42fbd96, 0x685ca0d5, 0xb19293aa, + 0xf98635ac, 0xd9ba1b5c, 0x5e5bce1b, 0x84ab2f01, 0x6320d08d, 0x7b6c743d, 0x56ff9d00, 0xb5180304, 0x844aca42, + 0xd8880160, 0xda818ce5, 0xe0e4347b, 0x585f6ae7, 0x20b8269a, 0x0db960a7, 0x4cb1bd73, 0xcc1f6321, 0x30eb0a8f, + 0x8ceb0e2f, 0x32ec8e65, 0xb7e4f390, 0xdc29bac8, 0xcdb89974, 0xab541b93, 0x46560f6f, 0x55fe9c74, 0x33822f0c, + 0x6e3be55d, 0xffa96b0e, 0xf39d9c12, 0x8b33bc83, 0x5b6e8a4f, 0x7f47ca0d, 0x85bba8b9, 0xf352438d, 0xa4a50e14, + 0xc65c109a, 0xed5f7923, 0xde8fe9fa, 0x5627ed5a, 0x7488ff56, 0xd30595b2, 0x4c0e218b, 0xbff846f3, 0xe937a01b, + 0x8030a3ee, 0x0c900ba6, 0xb6cb3123, 0x7f82314c, 0xa912c183, 0xeec45761, 0x93f45489, 0xe84f99e3, 0x73b052f0, + 0x46a3676a, 0xf4df8ac8, 0xd5581f45, 0xde9b2c93, 0xb83fd647, 0x6e7b88ce, 0xf4841a2e, 0xbea8d1d7, 0xfcf300ca, + 0x9cc45770, 0x33897e51, 0xde836f49, 0xafe78497, 0x7f97398f, 0x4f146a51, 0x0e2fce8e, 0xebb30b57, 0x4236d104, + 0xb2217b65, 0x8cda93b5, 0xef169368, 0x882c2440, 0x61c911d0, 0x873e8de7, 0x068544f8, 0x663b0280, 0x9ae08337, + 0x2284bc9d, 0xcc4afa80, 0x4e121c3e, 0x517a4321, 0x0602a5db, 0x841ceaf7, 0x25494025, 0xcece5d0d, 0x98385826, + 0x22622be9, 0x0868566a, 0x42f67648, 0xd7cbd617, 0x75b43c56, 0x5d11f430, 0x04196e0d, 0xdde01831, 0x77e7c74c, + 0xd0a05ca6, 0x74b91c35, 0x397ab777, 0xfeab423c, 0x92a60929, 0xa487960d, 0xb8a5ad21, 0xfc342e4c, 0x74ab2378, + 0xe5e8ff5d, 0x988e150f, 0xd559e3c8, 0xd805dc62, 0x63356e75, 0xc279dd10, 0xd2442c89, 0x84fca8cb, 0x1f56fbe6, + 0xfb91db4b, 0xdb8b2916, 0x98492ad4, 0x2c65535e, 0xa2fe1b82, 0x5f84acf3, 0x18af14b9, 0xf5d50dcb, 0xb320598f, + 0x0740cf2c, 0x65dccf25, 0xfff2699e, 0x64fc383f, 0x46d1869f, 0x0c2274f6, 0xb9803c62, 0x795b3873, 0xead5dc8f, + 0xacdf05e8, 0x535e9fd6, 0x7336c869, 0x83093f73, 0xd7cbd668, 0xe7203e82, 0x2a243d46, 0x98a104e3, 0x29b3a2d2, + 0x06c68de2, 0x44b2d974, 0xd7c98024, 0xa314b2da, 0x91acda9e, 0x64867a57, 0x2715ac20, 0x64a9fbf2, 0x40a808a3, + 0x476c4f87, 0x98c00204, 0x9bcc50e4, 0x1f8618b8, 0xf5e5359a, 0xcdfe4caf, 0x4bcc7835, 0xd4c24ea2, 0xf845038c, + 0xfa43ce9f, 0x8018b281, 0x3ec4b52b, 0x42eb01b6, 0xf71727b3, 0xda2d95fb, 0xb4c788bd, 0x927fc1e7, 0xea0ed0df, + 0x281bd6bd, 0x1acbb64a, 0xfbd2c6f4, 0x93ed221e, 0xf661f02d, 0xd5483c88, 0xe8d932f1, 0x49b8e754, 0x3e97d62e, + 0x841749ce, 0x0f2ec078, 0x64cc7320, 0x764a63ac, 0x5e44593a, 0xdd4ce58b, 0xc0111e5a, 0xbea6ba70, 0x26a548a4, + 0xa8654cb4, 0x6954abee, 0x70b80797, 0x20125887, 0x091eac64, 0x24e66a2b, 0x404c4f5b, 0xd9200746, 0x70164b62, + 0xc524f811, 0xbf9bbea8, 0x918619c4, 0x78c6f6a4, 0xc04c68fb, 0x78d62083, 0x0dc96b69, 0xa68cf0bd, 0x71d7987a, + 0xe42d7eca, 0xd1035ac6, 0xe3273c03, 0xbafaa98c, 0x18453415, 0xc7400b83, 0x8a97627b, 0x9f294862, 0x597d510a, + 0x988c3b16, 0xa6a56ed2, 0x72c84b67, 0x1d7fc354, 0x1bb2ea2b, 0x65059656, 0xa6beae88, 0xf88c16bd, 0x5357f34f, + 0x8a3cc4b7, 0x4f105cf3, 0x91bec0f5, 0x929f2d28, 0x4bf3ce23, 0x3ff0c6eb, 0x5abe63e0, 0xe2d3693b, 0xe17526e9, + 0x6138362b, 0xba787a51, 0x505a37b7, 0xec072c9c, 0xfa327229, 0x4712e57d, 0x5f824f7d, 0x7220da5d, 0xb92d0f1f, + 0x7de337c9, 0xd4ddd97e, 0x6a38be3b, 0x11ca44d3, 0x35d6fb90, 0x048483d8, 0x28439f80, 0xf3e5f79d, 0x7c4b0c4b, + 0x7f89b00a, 0x527d9489, 0x26fe2c48, 0x71d6f42b, 0x4ed2ee98, 0x52106299, 0xfd2e5dc1, 0xed0bc2f2, 0x89545617, + 0x08d363e1, 0x82a3c651, 0x8905c01d, 0x32a26d1e, 0x6b16cd17, 0xda39587d, 0x4e25776c, 0xf715aea5, 0x79d1c794, + 0xe4dde08b, 0x23c37b04, 0xa8038b4d, 0x9f7f75b1, 0x692e1603, 0x73bda3bd, 0x3b562357, 0xeab13598, 0xa62fbb14, + 0xaeba4428, 0xdb5e0da9, 0x59684eb9, 0x941e4cbd, 0xedb35ce3, 0x400ac4eb, 0x8dce6a86, 0xf66ae65a, 0x842bfcfd, + 0x1e22e2db, 0x8a5f8da6, 0x5c876637, 0xedc73b69, 0x18ea2c86, 0x7d9ca069, 0x542a6f1e, 0xfc03be6a, 0x6d9da799, + 0x64efc55f, 0x4833e6a1, 0xda0fa667, 0xf96cca95, 0x5157ee5c, 0x28664184, 0x4b37bec9, 0xc8b54d15, 0xe871e9b3, + 0x89cd0f17, 0x669528e2, 0x297b302b, 0xdafb3640, 0x48651cfc, 0xe6717424, 0x1d5bdba6, 0xaae40d3d, 0xf720f51a, + 0x6c8b5f0b, 0x06a2cc65, 0x36b39afa, 0x579029b8, 0xaf3c6527, 0xefecb58b, 0x4602bb79, 0xd14ce0f8, 0x6f572325, + 0x4ed5bda7, 0x4df284c6, 0xd61d54b9, 0xfb42db5b, 0xe124daee, 0xd14b98f6, 0x2bc399c3, 0x63f1b334, 0xd0f1af19, + 0xba1d67cf, 0xd0d7e5f8, 0x39de5620, 0xb31b2513, 0x25ab661f, 0xfb12a454, 0x4e26b0c0, 0xe028f125, 0xeee523ed, + 0x6de6cbfa, 0xd307738b, 0xc558aa73, 0xf0a41233, 0x4457b5ec, 0x2e029262, 0x35fc6831, 0x93de5128, 0x2415da94, + 0x1d04480b, 0x1bdbac55, 0x34ade442, 0x8ccf9abd, 0xabf5a8e6, 0x6af94b71, 0xd87d8bd4, 0xe13ceafe, 0xf5d2b6f5, + 0x465576aa, 0x207cf866, 0x5da43727, 0x6c295543, 0x08b86000, 0x73d9c253, 0x76a557e1, 0xfe9df9b5, 0x66ba99bf, + 0xfaf05af0, 0x19155c2a, 0x5aafd134, 0x5462953b, 0x40b04e2f, 0x3e91085d, 0x2c9c57c3, 0xb262aa8d, 0x200eee50, + 0xa1ba9997, 0xbd90d1c4, 0xc1d913f3, 0xc7fc9758, 0xef3b82de, 0xd201b1b4, 0x12a1e5d7, 0xee2594fd, 0xf4313e58, + 0x6b2be82f, 0x41a5c159, 0x1bf2966a, 0x4744e966, 0xaddd8685, 0xb2aa2015, 0x2eb72c46, 0x10a8b412, 0x359b9ba6, + 0x05df85d4, 0x0889ce77, 0x7b984933, 0x95af6001, 0x738bf600, 0xa2ffa823, 0x0e743ab1, 0x4367256d, 0xec86544e, + 0x63a9950c, 0x79126cd9, 0xce537d71, 0x79313579, 0x8be801d1, 0xc784641a, 0x3082b221, 0x75493c86, 0xc714ed72, + 0x3713f3a1, 0xed576bc6, 0xc957b27b, 0x789f1468, 0xa497f3b8, 0xae01aae3, 0xe8cf68e6, 0xfd7ed70b, 0x6ef35d78, + 0x141f9bfb, 0x0522177d, 0xce6d740e, 0xde94ed56, 0x736be3d2, 0xadbaee90, 0x0e6a6d9a, 0x046ea6dc, 0x5289c7fb, + 0x04fc0ebc, 0x7bd1bd29, 0xdf702e07, 0xdec76f69, 0x5cee66c2, 0x1b61b6c6, 0x84c180bf, 0x09645444, 0xea327c0a, + 0x5d235f9d, 0x9e412211, 0xf34c3ca0, 0x73078ddf, 0x40eb8c02, 0xa69f8470, 0x51cabc8b, 0x82f39c73, 0x38fa73f8, + 0xf4528b12, 0xdac91e62, 0x02836867, 0x6fdf49ae, 0xe90f911b, 0x87613c7d, 0xb726da10, 0xed5b47cd, 0xeffedc70, + 0x7c667a9e, 0x360a9312, 0x0ec86322, 0x724d0402, 0x02aef783, 0xf625c7e0, 0x9e947e28, 0xabe42420, 0x61258c66, + 0x0a24264c, 0xb30c9257, 0x8af5c9da, 0x7774c7f6, 0xc76390ef, 0x558db791, 0x574c6b2b, 0x91d0f426, 0xdec38669, + 0x2f5fa447, 0x241374d6, 0x41b99ee8, 0xc9192120, 0x4fc5ab61, 0x4e08ade4, 0x6aee878b, 0xf516bbb3, 0xd09563b9, + 0xe43df09c, 0x94b17118, 0x45b77e1e, 0x3e30dbe5, 0x5033395e, 0xfc6531a8, 0xd63715d6, 0x44309468, 0xcda42bca, + 0xb0f91133, 0xfd74ad4b, 0x055b617b, 0x0f52c4b3, 0x1988fbec, 0x7a7611a1, 0xa4d8cafc, 0x8c4eee9a, 0xaa51aeb3, + 0x17dfa904, 0xf82affd8, 0x5e5c71f5, 0x20932a38, 0x8124e209, 0xc877cfb0, 0x116cb184, 0x0ef6225f, 0xd6d6461c, + 0x9b0d2245, 0xc6d93746, 0x30184821, 0xa417e9b7, 0x02964db4, 0xba90c030, 0xab2f42a4, 0xb685acc9, 0xa792d017, + 0x8af7e891, 0x846902a8, 0x149fa155, 0xf0af802f, 0x45fa8d41, 0x3a8c4da1, 0xf718ad08, 0x4fd4a9ca, 0xdcada5b1, + 0xe8d3ecc5, 0x9c993f09, 0xda7350a9, 0x1f466cd1, 0xad933222, 0x9daf6fa7, 0xe93d035c, 0xfe65ba6f, 0xe4379396, + 0xad26fbb4, 0x54951f8b, 0x003f2557, 0x3b92aa5e, 0xcc5963dc, 0xf748eef0, 0xfb010eaf, 0xd46fdd10, 0x58e7686b, + 0xe67d2a63, 0x0b2a2a1e, 0xb85550ae, 0xc0bd2ed4, 0x18e6cce8, 0xaee30a5e, 0x0f42d50b, 0x637dba28, 0x3f00d454, + 0x42436039, 0xc946d146, 0x9f7e1ba3, 0xb5c9169e, 0x58ec3e68, 0x2801489e, 0xb1bd3078, 0x33127fde, 0x65628c55, + 0x3ecf3c5c, 0xb12fc0e0, 0xca27d6d8, 0xd28fbb9d, 0x175e5eae, 0xe8f5cdc0, 0x600f4b28, 0xdf0ec6e8, 0x5e2b9562, + 0x468bcb1e, 0xdf21d287, 0xfe2b34fb, 0x1a125902, 0x911241f7, 0x1634c50a, 0x113cc81c, 0xba5a5acc, 0xda980e1c, + 0x1f987a06, 0x5e70b7b3, 0x46689ded, 0x234f871a, 0x9e0c4842, 0xb0f54124, 0x48b074b2, 0xb4a5a112, 0xc463243e, + 0x05b75c7c, 0x08993f78, 0x4fb24bdd, 0x7229e3f8, 0x157aee62, 0xbca2e941, 0x951b2b7e, 0x80599df1, 0x852734b6, + 0xa8ede591, 0x35c8d635, 0xd1c09aa2, 0x94bd5185, 0xcb642545, 0xeb18c020, 0x6d434f74, 0x5fb25419, 0xfbc93364, + 0xc41ae40a, 0x9a4c715f, 0xb8a79d11, 0xfd5f9a2a, 0x7fe34d37, 0xf6352ded, 0x2fb9d5bd, 0xb1d84aad, 0xd27eef95, + 0xcddc7c6f, 0xfb2e69b1, 0xe6437d84, 0xb2252a8d, 0xb345c5e0, 0x6a94e519, 0x9acb6bac, 0xb74a9402, 0xf635b4c2, + 0xfb56f44d, 0x859cbaad, 0xa31247f3, 0x35ee9716, 0x1c1ce153, 0xeb1b3681, 0x98dade5b, 0x84798798, 0x934cb039, + 0x5c42fc8e, 0xd0dde6de, 0x5291b011, 0x2aa2d504, 0x0adfafdb, 0x0c1f7e05, 0x6cb2e7d3, 0xf1e8fec3, 0x6b0c350b, + 0x13134a7a, 0xf5c08221, 0xdfe42832, 0x271753ee, 0x040b9617, 0xbd6ce77f, 0x4dd92fb2, 0xcc5fe7a1, 0x125d3e59, + 0x05bc7ad4, 0x0cd2813d, 0x342fd209, 0xc476a959, 0x4b53d655, 0xba8b7bea, 0xca81b90d, 0x97d205be, 0x9569c5e5, + 0x0a9c5b33, 0x032f7048, 0x9641c0e7, 0xed460f2e, 0x12b1200e, 0xcb245671, 0x30cc7f83, 0x2cc9c547, 0xb6d5fbb6, + 0x854077fc, 0x2d38dbbd, 0xda4651a8, 0xe9732974, 0x7dd09b15, 0x187f9b45, 0x1727c7c2, 0x30fcfa6e, 0x09f9f9d9, + 0xf61ff848, 0x410ea73e, 0xb5a25905, 0x9800a259, 0x4465abed, 0xc72a9de6, 0x3ffb59e2, 0xf52888df, 0x98e228c0, + 0x4ebb6d2b, 0xf689fba2, 0x096a0551, 0x1442b8d6, 0xa7742ffb, 0x1e36dacd, 0x7827aced, 0x65eaed8d, 0xd678bc6c, + 0xe82d97c3, 0x28630d84, 0xd2e85279, 0x481e0dc7, 0x2a30ffca, 0x1798ff16, 0xa74943e1, 0xa7ea4c78, 0x04c05691, + 0xd6e3545c, 0x5356592c, 0xd282ef30, 0xdc213b96, 0x8c271789, 0x8cc32fc0, 0x89b58380, 0xd1b117da, 0x8c8124f0, + 0x9d28b727, 0x0c336183, 0x418dcd82, 0xa4ac80eb, 0x5c2c5696, 0x506bd507, 0x1f750657, 0x2b77b9fb, 0x06d86dcf, + 0x22fdf164, 0x3f736bf1, 0xef8f5e71, 0x4c976134, 0x150d539d, 0xb4582698, 0x7b1924af, 0x4fa013fe, 0x2463f5c7, + 0xf90e6cd9, 0xff7b30f1, 0xe9ff7386, 0x477aba73, 0xdae6e9e6, 0x541923d2, 0x64046f89, 0x903b6a33, 0xedacaf9d, + 0x7f0943bc, 0x9cfe635d, 0xb489a494, 0x7a9171bf, 0x02ffcca4, 0xcf61ea8a, 0xe9de5a1b, 0x968f4e8b, 0xe1a4d20a, + 0xb1396c10, 0xa6671a17, 0x86db28f0, 0x63668422, 0x6421467b, 0xec7bf608, 0x422e02d6, 0x6fd1b9ec, 0x724e3c6b, + 0xb292b18e, 0x8f5f12f6, 0xd6119835, 0xf153e548, 0x28619442, 0xd5138799, 0x57b40d3d, 0x79377661, 0xc05432a4, + 0x2ac497ea, 0x45106b71, 0xc05beae4, 0x02f964bf, 0xf3da674b, 0x47a92d38, 0x417ba24d, 0x0d80c874, 0xc2ffef51, + 0x41cc9a2f, 0x49cd2006, 0x1116c3db, 0xe40fcf87, 0xa8d24698, 0x2b857e9c, 0xe6dc96c5, 0xdbd93ee5, 0x39ecb559, + 0x5a01cbda, 0xffce09d0, 0x74ea191d, 0x6783e14e, 0x4276889b, 0xd2013dc5, 0xd75224a9, 0x823b2aa6, 0xa0fc9ebd, + 0xd896aa47, 0x0ab243bb, 0xd3f15134, 0x97b244e5, 0x453efc8d, 0x24c1f64a, 0xb86837c1, 0xd7364684, 0x2b5b019a, + 0xd70a19bf, 0x7a85de81, 0xc62d5b46, 0x92ecbef6, 0x67f593f0, 0xd066b718, 0x78ebe494, 0x2c815525, 0x46152ac1, + 0x386aa6c7, 0x24c0e893, 0x2665b356, 0x24b8e1d9, 0xd8521cb1, 0xa6be351a, 0xdaae2015, 0xdcdedafb, 0x54d09f33, + 0x6552acd9, 0xbbd5c45b, 0x5c3b169e, 0xb34ef7e9, 0x80d95b52, 0x05477cb7, 0xbe1518a0, 0xd85cd109, 0x69b7cf45, + 0x9358d570, 0xde6dce04, 0xda4a51be, 0xd3c2399c, 0x5e9ce616, 0xa76cb234, 0x457254d1, 0x87fce434, 0xc229a139, + 0x4493f910, 0x8d546445, 0x3c4fdd32, 0xf4bb6166, 0x7f21bd0a, 0xe41c50c0, 0x62aef3f9, 0x2062b778, 0xa826f612, + 0x7fb0d366, 0xc9408d49, 0x5fc37621, 0xb779ee6b, 0xdae5bcdb, 0x9698a5a3, 0x44ba2841, 0xfaefc509, 0xbb11fc1b, + 0x27b5c81c, 0x5b4c1481, 0x2cfaa6cc, 0xc69d8f30, 0x946ff83b, 0x61a6ad46, 0x0177081d, 0xc0a0b0f3, 0x27e967e0, + 0xffa2610d, 0x93840818, 0x78abc1ce, 0x26510fcf, 0x27ace2e0, 0x8555242f, 0x81e54fdc, 0xca3ddf66, 0xf4f6780c, + 0xc464ea6a, 0xf2eafd72, 0x0dc619cd, 0x1d0a4335, 0x574188cf, 0x71933ada, 0xf9bcb1c7, 0xa9a76708, 0x89c245a8, + 0x92ba5ade, 0xb9140630, 0xbbe71e8f, 0xb6615b31, 0x9c3eb405, 0x3818c1bb, 0xcbf85147, 0xad999118, 0xc40cb742, + 0x71d291de, 0x4892f146, 0x8ab76715, 0x338e5e39, 0xd6453a61, 0x8b339c45, 0x3a4359c4, 0x02b0cd6a, 0x0f2d907a, + 0xbdd06883, 0xc6361b38, 0x706a9ae5, 0x2e7d042e, 0x8c6b8e53, 0xab9b6409, 0x11b32de8, 0x764b7de2, 0xcafc81c4, + 0x6741f42b, 0x209aa2c4, 0x1a51ee7f, 0x3dabbe27, 0xc1898a73, 0xd4eff748, 0xb579aad5, 0xfedb717a, 0xf5cc03e4, + 0xf715d969, 0x690b5ef7, 0x0990b21f, 0x1ce0e79e, 0xf07af07b, 0x01763799, 0x5935f253, 0xf256a5c7, 0x489e2d72, + 0xb0fb80fb, 0x0d703bc6, 0xdb168049, 0x1b86ea4a, 0x8e8864c2, 0xa0ce9151, 0xa9ac69ea, 0x8dfcd029, 0x78c6ed06, + 0x92cd356e, 0xfb538afd, 0x80ef6562, 0x66bb9ed3, 0x84f69f71, 0xe4ac74bc, 0x06aad1f8, 0x05c6984a, 0xfd72865d, + 0x9330f37e, 0xc138c9ec, 0xca8ed7ca, 0x3aa1267e, 0x704dd681, 0xe888a960, 0xd11a84a5, 0x8b8eb76b, 0x699c161b, + 0x38dfb37b, 0x36cf18be, 0x23518279, 0xb3f29001, 0x87245abd, 0xe74386f5, 0x4211a907, 0x3ae4dc79, 0xdcfc4888, + 0x80c9737c, 0xb6ba4ac2, 0xf50ed166, 0xf136c1ef, 0x35d5c7aa, 0x20f1dc17, 0xa07f803f, 0x148d16db, 0xb865767b, + 0x74f6abe7, 0xdb32d2c8, 0x486ccc5a, 0xa03bdb69, 0x1aaaa646, 0x2fb5d782, 0x43f28d0c, 0x4386e60f, 0x80128d7b, + 0x91ce7eb2, 0x38827431, 0x39b71694, 0x9c4c73d4, 0xfea1ae91, 0xb8e39325, 0x0ae4c708, 0x0f36386c, 0x16ae10da, + 0x00db964b, 0x6d34d3d7, 0x32f97d69, 0xfd56ded0, 0xd2caae72, 0x9b52be65, 0xbfacb5fc, 0x28ae8578, 0x717ffbd1, + 0x03e14e75, 0x76799649, 0x4ec5b25c, 0xa3ef1104, 0xf304a0a3, 0xc4aa13d2, 0xb8dee790, 0xbf0db44f, 0x365a632d, + 0xd091c656, 0x8e07730f, 0xcc7e8ce1, 0x94a278bd, 0xcbedda05, 0xca1742cc, 0xc63970b4, 0xfbde3e3f, 0x931f88a9, + 0x1305ff1f, 0x3acd8c2d, 0xc7f20866, 0x1e2249bf, 0x59ebb763, 0xc7c04cb7, 0x0ca147ae, 0x90ff0efb, 0x9c3da85e, + 0xfcc97121, 0x7eb01592, 0xceee70f8, 0x78b65e20, 0x36209fab, 0x359a3f0a, 0x734b2b47, 0x9071909d, 0xbc042b4f, + 0xf946cfbf, 0x81b5b328, 0x3046e487, 0x96e91f8c, 0xb141ce3b, 0xe31844c6, 0x7f54134c, 0x1b666d1a, 0x0f95e1ae, + 0x93372abf, 0xeffe21a7, 0xd6cb526d, 0x07e60422, 0x05f4b2b7, 0x24b98afd, 0xc0b1facd, 0x53f1f8c9, 0x7ff0dbc1, + 0xdec49832, 0xe485e7a5, 0x722d9a2e, 0x59208053, 0x7a64c958, 0x5e05dea2, 0x33a950f2, 0xba8c8665, 0x36aeb1b9, + 0x1213fc37, 0xf56b3847, 0x5a3381b1, 0xd6de2958, 0x738bc644, 0xee384175, 0xd8a56e8b, 0x22f8372d, 0x77354c08, + 0xebb52cc7, 0xb77473d8, 0xc9ac2910, 0xfae17fa4, 0x9697a801, 0xede27455, 0x2760c40d, 0x18c3c623, 0x2cdf98ae, + 0x5c22096d, 0x4745bf9a, 0x5fa33a04, 0x4e19b280, 0x0bf71bb6, 0x7c9bdf28, 0x9ce6f65f, 0x58afbf43, 0xaaec02a1, + 0x4ccfe242, 0xaffab91f, 0xc47b6ca3, 0xaac6d978, 0x1bfbcfe8, 0x8778a6eb, 0xcd87f6db, 0x9d0d1c51, 0x474e0038, + 0xd9ea4c41, 0x3837c993, 0x91da419e, 0xda85d867, 0x4bdfe996, 0x7918cf16, 0x7a3781ac, 0x267e0009, 0x7e1fcbd8, + 0x8c0bdcce, 0xa85d08ab, 0xde97db67, 0x6852c198, 0x1d565900, 0x182df8b9, 0x9e621519, 0xfb7a7c7e, 0x15a4d93a, + 0xaaf9fb3c, 0x45561bf3, 0x169beab9, 0x0d120fcc, 0x5e639616, 0xe53d2c76, 0x952254f1, 0x1316e1e0, 0xdddb5676, + 0x2cbb19fb, 0xd03ac1c4, 0x4ee8130f, 0x749c89a2, 0x8358d0f8, 0xec469f5e, 0x397c6fa6, 0x625c8a41, 0x4a0ab8e7, + 0xd2d2dc57, 0xf3aa653a, 0x38b5f560, 0x69e77d78, 0x993d41d3, 0x9a0709ba, 0xd60d3720, 0x577add03, 0x7753a3ad, + 0x9482ca7c, 0xab707ab3, 0x5e43700b, 0xc88e060e, 0x699223bc, 0xaf3827be, 0x583c62fd, 0xc5c27e47, 0x20bbfd10, + 0xe45ba417, 0xcfd39795, 0x5b37219f, 0x5eca9a6b, 0x32565cfd, 0xa557ec74, 0x1937dbc1, 0x93fc1aa5, 0x1c478ea6, + 0x859c3d49, 0xec48349a, 0x850b34ce, 0x8f935091, 0xd020ad68, 0x499b762b, 0x64e87a21, 0xed18e243, 0xf4948e55, + 0x2b697f3e, 0x8d648f0c, 0x1ee6302a, 0x1570a79b, 0x0947315a, 0x2902c3d2, 0x7257c554, 0x1aabdcf1, 0xe4c02d74, + 0x2b1555f6, 0x7161c651, 0x7f184d61, 0x25e216ec, 0x2d01420b, 0x3c08bf55, 0x278d0f7a, 0xeefb0915, 0x07f77e54, + 0xf8a8eb22, 0x704f8e88, 0x9622a928, 0x1f8b8d19, 0x504e3762, 0x9adf41ae, 0xcd91996e, 0x6f2f1684, 0x92318368, + 0x63cf9b9f, 0x09821e2a, 0x83c4e0d0, 0xa58c8597, 0xae14005f, 0xfce6d263, 0x20e35038, 0x9cdf9a94, 0x44152d1c, + 0x2d88b738, 0x419318dc, 0x5c2e1f60, 0x6dc73e9a, 0x17dc6900, 0xa22bccd7, 0x23f7136a, 0x0ab785b1, 0x37ad0763, + 0xd1d2d908, 0xce4c4bec, 0xd09605c1, 0xc1c950f0, 0xf09126fe, 0x8859b1fd, 0x93ba6b76, 0x8cdf4e6d, 0x2e254239, + 0x76fdd46d, 0x5962cf23, 0x34d5d388, 0x1a1a7c2b, 0xfd4cabde, 0xc8abecdf, 0x45262c9e, 0xadc1b382, 0xf62a5525, + 0xf906e8df, 0xcf66abaa, 0x557a71de, 0x5b641c04, 0xad757f6e, 0x298fd4ea, 0xf377d2c8, 0xefe759eb, 0xa23b1961, + 0x9436ef2e, 0xaf01c6eb, 0x1e29cdd7, 0x37a0c39e, 0x9f62802d, 0xdbb2184b, 0x0f806b06, 0x941eb7a1, 0x55bc28bd, + 0xa6f2b6a8, 0xc7485963, 0x26194662, 0x3a58f54b, 0x721dcec6, 0x16c3eb9e, 0x6a076ae2, 0xda7951e9, 0xc608c3ec, + 0xc281c256, 0x8bd8e226, 0xcf57da37, 0x7b7ed2c9, 0x4e9a91ed, 0xca2c8301, 0x5751e1c5, 0xbae9cb7d, 0x21346fe5, + 0xa2767aef, 0x0dbd5ab0, 0xd0ab67de, 0x23e93032, 0x68e3b72d, 0x316ddb25, 0xa6c32e13, 0xdf06e6d0, 0x7f37e2c6, + 0x8eae779c, 0x183cd30f, 0x4b882dfa, 0xbe6c4a67, 0x475dab48, 0xaedfca39, 0xab08ee80, 0x54729084, 0x008675de, + 0x0e472d12, 0xdd9b7375, 0x0ada62a8, 0xed311a31, 0xf444751e, 0xee9d9712, 0xc33108d3, 0x30dee869, 0x09ae190a, + 0x355a085c, 0xe06154d1, 0xc181188b, 0x8703c66a, 0x2479df18, 0x157a0edf, 0x9e3b415a, 0x0b82e377, 0x0c65b3ce, + 0x6690b95d, 0xdf24dca6, 0xf195a27d, 0x44d80c8f, 0xf5b6d00c, 0x8cfed285, 0xe7b59c42, 0x8adec843, 0x830460fe, + 0xb7413b42, 0x91e2524d, 0x03ad3d5f, 0x0a5568db, 0x82909d00, 0xf96fff6b, 0xb0e603e9, 0x89f4d1fb, 0x013e79b5, + 0x49bcda63, 0xc701bac9, 0x0058fcb4, 0x7c1c7599, 0xfdf2e11c, 0xcbbdb8aa, 0x8befbc65, 0x8fa34748, 0x157fe25b, + 0x9ed718fe, 0x8bb8ebf0, 0xf944d906, 0xdf22e761, 0xd66e9e4a, 0xf6c11bab, 0xc8a426c9, 0x5b144996, 0xf7d32738, + 0xab70f46a, 0xb1e4293f, 0x64e3835f, 0xfa450fa9, 0xeca35f9c, 0x448040a7, 0x19e7ada1, 0x138a15b5, 0x69185569, + 0xbd6f857f, 0xea8e1a37, 0xae80735b, 0xd2fed0ff, 0x7dac1db8, 0xf3d29b10, 0x97fe55f1, 0xa7b4df57, 0xc59208c7, + 0x9f33a5e0, 0x2126a1c8, 0x62340224, 0x2ca7841b, 0x677b165b, 0x5aef7434, 0xe69674de, 0x83690bda, 0x46b212cc, + 0xaff4e00f, 0x81c19e97, 0xc6452598, 0xcab354b3, 0xfcbe8113, 0x05f5e996, 0xa63df4c7, 0x958aa193, 0xd134566a, + 0x267c8cad, 0xcc8d45ba, 0x9d13f165, 0x7b91fdd3, 0xac09aa50, 0xf87ac30c, 0x7ebf9c6e, 0x716db044, 0x8723dfc0, + 0x2de10b9c, 0x77a57acb, 0x9dd3fe23, 0x4e018264, 0xcc9a5771, 0x1257f58c, 0x40c77a0f, 0xc13c21af, 0x07087805, + 0x6825fb66, 0x417c204a, 0x345a1402, 0x687560a3, 0x89aaf1ea, 0xf56b2232, 0xc81d8b8e, 0x6240c4af, 0x835a6785, + 0x168f3b22, 0xa9a3a6bd, 0x65881ec9, 0xa70c4833, 0xff00bdbb, 0x846a20be, 0xcb306f3d, 0xbbe15da0, 0x4fb5f424, + 0xa8492500, 0x0c325432, 0x84c7e130, 0x0fb690ff, 0x19be9e31, 0xc2940bcf, 0x831f2e55, 0x17d3d7ed, 0xcde41e0f, + 0xf2d2e272, 0x0e47256f, 0x245c1f42, 0x35857bcd, 0x322a6381, 0x8a01b6e7, 0x404d06a9, 0xc73d6c8c, 0x26a03f87, + 0xc03bed9b, 0x819048ad, 0xbbaed3d9, 0x8bc7e0cb, 0xa738c68e, 0x4e721f00, 0xf948cc21, 0x0dcca26f, 0x7abdce19, + 0x7e96c2a9, 0xeeaecb99, 0xa24035da, 0x3caf8c2f, 0xd5adcec1, 0xae37b604, 0x5854096d, 0xa5ad1c0d, 0xb5059af0, + 0xadaf7efa, 0x5087e991, 0x1932d9fe, 0x4a6fe3c4, 0xbcf329d7, 0x994789c2, 0x13b5955a, 0x9ea82b18, 0xc35e82c9, + 0x20b50f11, 0x2b702ac4, 0x6e397bdf, 0xc6f8bfc8, 0x845e1980, 0xaaf8e2e6, 0xcc62c26c, 0xe75874c1, 0x9b6234ac, + 0xcb9030e4, 0x3c9e8685, 0x3090beec, 0x77029fad, 0xfef325ca, 0x420c0abc, 0xdc428599, 0xc784cfbd, 0x1e884dad, + 0x1363c3c7, 0x5e758322, 0x842d36a1, 0x5da13df3, 0x4c4098f6, 0x475ff5aa, 0x71e0fc4d, 0x4ebc04ed, 0x20e695dc, + 0x6f4f9637, 0x41f4f796, 0x5c47d771, 0xb4e22701, 0x214d3f38, 0x5b7f40da, 0x6fc13afe, 0x6210f11f, 0x8bc0240c, + 0x269ce26d, 0xd4db3dbd, 0xb98dacfb, 0x72f30aab, 0x4bf1d5aa, 0xd721bd90, 0xcfda4bc9, 0x07a094d7, 0x0f969d6d, + 0x390bc5d3, 0xe32cfe00, 0xa6364364, 0x2271f7a6, 0x5351c80c, 0x7d15fe5c, 0xd5b96905, 0x56a8710c, 0x73a75cd0, + 0x1fa393d8, 0x87692687, 0x423d1d10, 0x285ff7cc, 0x5d403e8e, 0x1637429c, 0x7fd383d9, 0xf634ebd4, 0xc5151b16, + 0x1bcce3d8, 0x2c86f309, 0x83e84da9, 0x12a16998, 0x0fa9e07f, 0xa35bba36, 0xe486d32e, 0x09ed92ea, 0x0d3784d3, + 0xeae918b1, 0xb3e3926c, 0xbd544dab, 0xd1b2e419, 0x302e7c1c, 0x34533591, 0xd2f4da45, 0x02d7ae6d, 0xad0da806, + 0x1edc4039, 0x81888678, 0xcd38c8d0, 0x9854f11b, 0x2b033c75, 0x22790a17, 0x94438b23, 0x8df93788, 0x713a577a, + 0x3119beed, 0x415db2f5, 0xa58e2d76, 0xc5bbc066, 0x5b9dae26, 0x775a317e, 0xfdf3b991, 0x97f68cfc, 0x89e2c973, + 0x480a2ba0, 0x850dfdd9, 0xf8c48864, 0x7204a692, 0x77f80c85, 0x444fe226, 0x461119c1, 0x0c71bcfa, 0x86355862, + 0x0cab8b5b, 0xed9084e1, 0x8b39cafd, 0x73e68d1c, 0xf2dcccb9, 0xb049472d, 0x4fc2dc77, 0x3833ec12, 0x7dc19f23, + 0xdb7d177a, 0x63dc75d2, 0x1f5dc00b, 0x1cc37933, 0x23259f2d, 0x5391b436, 0xcb3a1368, 0x28ad9d4a, 0xb374c2fe, + 0xd760108f, 0x4f800e1c, 0x4ea9f93c, 0x6b6d335a, 0x277afd17, 0x3082e8f7, 0xf43ded9b, 0x3cb2af08, 0x9f48f1af, + 0x57ee161b, 0x54d99447, 0x394dd306, 0x9a5975fa, 0x19b239f9, 0x57861db6, 0xce51a4f7, 0x8571c274, 0x0278d311, + 0x87402b8e, 0xdd4c4936, 0x1c29c92a, 0xfa83e5bd, 0x3186cfeb, 0xc59b8b00, 0xcbf11235, 0xfd4442f3, 0x143bcac1, + 0x9bef0ab3, 0x4b1c97fc, 0xb560ce7d, 0x304e76cb, 0xe7e42b3b, 0x99f51a7f, 0xca258bde, 0x0ab09d82, 0xb4b1adfb, + 0x4c927383, 0x8b0f829e, 0x85b94ab2, 0xbd7fab31, 0xf3ffb341, 0x42494d5b, 0x3a0f6bc1, 0x2ab95624, 0xca656b49, + 0x30492cdf, 0xd200ecba, 0xdf501248, 0x310f616d, 0x6b2ab81e, 0x4edc3105, 0x12cccad1, 0x99a0855a, 0x5adad10c, + 0x0608a9fc, 0x5625610f, 0x4f591640, 0x14db733d, 0xdda2529a, 0x1820bb9b, 0x04825c46, 0xe5e6cab4, 0x9d4ca81f, + 0xbc37f391, 0xd931104e, 0x86d9149b, 0x7e1a981f, 0xa9607578, 0xdeecdafb, 0x17fd898c, 0xa30b2be9, 0xb00136ef, + 0x7d4446dd, 0x6085aab2, 0x47f67655, 0x76942d45, 0xfd1ccb01, 0xd19498e3, 0x1c1f93c7, 0xf3560960, 0x9158eb46, + 0xd34a06fe, 0xb14f543f, 0x06c67706, 0xc72355eb, 0x0bd2ad57, 0xcecc0c75, 0x1fab9c3e, 0x45b3d689, 0xff424cab, + 0xcaa78a9d, 0x14b62cb8, 0xe84f4aa1, 0xdffb173a, 0x7e7dadb4, 0xd715cf7f, 0x7f64d010, 0xa421f156, 0x7e9cea36, + 0x4b1360a8, 0x104de91e, 0x821d68d5, 0x7369b9ab, 0x8249357f, 0xb68adf1b, 0x217daba5, 0x998cab76, 0xc122ffe8, + 0x0d458961, 0x4c785146, 0x2203a706, 0xe7887d68, 0xf722cd2f, 0x0c17fa2b, 0x6030f6cf, 0x28a35074, 0xee9de8c4, + 0x1c3ad782, 0xedfbf51a, 0x2f51cb65, 0x60ce6557, 0xbe0e48c5, 0x43b22971, 0x190eaae3, 0x0a00c06f, 0x8239e923, + 0x83ea308d, 0x2b40ef32, 0x30d39269, 0x34663ed9, 0xb448bd11, 0xaaa0d5b1, 0xedd5d6e0, 0xa0aa808a, 0x39897c0b, + 0xaa858478, 0xa7ebaa14, 0x43c491ed, 0xb3d73aac, 0xcddf0e22, 0x7ad0c804, 0xf00364de, 0x72b0bac7, 0x696cee8f, + 0x5afb2046, 0x241abfd7, 0x65ee2252, 0x6f72cee4, 0x72fee518, 0x479f9116, 0x62ab8c27, 0x4993b59b, 0x0ced15b3, + 0x12f380c4, 0xb805a151, 0x90c9fbb5, 0x6491451e, 0x392e6cb6, 0x9513ea8b, 0x9aaaceab, 0x0af39eeb, 0x751d3cb5, + 0x262b1a40, 0x1739b4f6, 0xc85cfbd5, 0x3d4ed709, 0x881209b8, 0x64b441a3, 0x9fa5e85b, 0x4848c63d, 0x3560cf33, + 0x8cd9b726, 0xdd7f2c2e, 0x6ee4e656, 0xa8d21ceb, 0x358bab1c, 0xc0ae6f21, 0xc108022c, 0xa1fb9fb8, 0x5616f2e9, + 0x09cd9893, 0x42712c59, 0xcbc83660, 0xb2b15c89, 0x0e31a7b4, 0x50d891de, 0xea0498b1, 0xca54ddc1, 0x49242e18, + 0x3383be99, 0xbba7c374, 0xe310fa52, 0x5703ab01, 0xf238c66d, 0xf9d9568a, 0x57a6fd84, 0x9d89d274, 0xe57d88a3, + 0x5cf8f7c5, 0x7ff54dbf, 0x1b9e0b13, 0xa286381b, 0x1cd50a04, 0x4dbbf3d1, 0x1be74969, 0x327a9503, 0x87d6e304, + 0xe72e2529, 0xc6f4ca61, 0x7bd90c30, 0x93d8983c, 0x76afa2d9, 0x1381f72e, 0xdf3f69a8, 0x4c8f037c, 0x0a593673, + 0x3e8caf4a, 0xf280befb, 0x707609d9, 0x0937c564, 0x7db8705d, 0xcb2d0061, 0x2d2c8a31, 0x840d3ab2, 0xa2994aa9, + 0x80af1018, 0xf320c7a6, 0x91ac1a48, 0xe8993762, 0x23283633, 0x728b76cb, 0x7495f77c, 0x67ab1da5, 0x2de58a75, + 0x911cf78a, 0x7c18aef7, 0xf851585a, 0xd2204f6d, 0xf3da734f, 0x71b71b6e, 0x020d1b4e, 0x920874a4, 0x863ce0fb, + 0x02eee1a4, 0x88e4d1b1, 0x6a423485, 0x0c83da21, 0x3a800d73, 0x65a77224, 0x4683e4d7, 0x2ee99329, 0x6fda7ebd, + 0x1c21229f, 0xb0758ded, 0x215fb7e7, 0x8519d73e, 0x0d66b004, 0x4dadf053, 0xd43bf2d4, 0x0ac96fa8, 0x22f46a18, + 0x6da43aa9, 0x63f2e015, 0x46fb447a, 0x47cccfd1, 0x1d3b01bd, 0xb139586b, 0xef630499, 0x85fe1d2c, 0xd1807556, + 0x8d5bc9aa, 0xe6a686f9, 0x70a2cbb8, 0xa1b427cb, 0x359f4064, 0x10e81405, 0x01ff56f9, 0x32d55771, 0x164839e0, + 0xd3dc9bfa, 0xba55180f, 0xa3c87b63, 0xf10029cb, 0xc7a94a4e, 0x58507e36, 0x29bcfb02, 0x12c84da2, 0xfffd1ca9, + 0xaf93e406, 0x410a5282, 0x58142ec2, 0xe14b4751, 0xb2eb4ef6, 0x3d2e3407, 0xe01e5595, 0x2cb305c0, 0x228dfab6, + 0xba06b9f2, 0x99066673, 0xb1db6e65, 0xb512aca0, 0x256aadd7, 0xd5aa7aa0, 0x459bc384, 0x797374bc, 0x08ac4809, + 0x138d46df, 0xad3b68d2, 0x4b578890, 0xffd851d4, 0xe93909e3, 0x59e02f00, 0x54eed132, 0xd31fd8bc, 0x2cc1253e, + 0x661896da, 0xf1e4c45c, 0x18347d5f, 0xd217c72d, 0xba514125, 0x15ec4a0a, 0x67fed745, 0xefdbf0a0, 0x8f8c974a, + 0xb5ce8b17, 0x4a416b1a, 0x743f2167, 0x8466980d, 0xd32a86da, 0x67701e5d, 0x8a9a0f18, 0x5458e266, 0xe8a5bfb4, + 0x44636399, 0xee48b31b, 0x77ab8373, 0xab316178, 0x4fe435e7, 0x6b1f0483, 0x766e7883, 0xfca7550d, 0x23b31908, + 0xb739d80c, 0x4c615c85, 0xfc0f3f2a, 0x52db12f2, 0x477d44a8, 0xaa1969db, 0x2a10b581, 0xe3ef8e5b, 0x3f98229a, + 0xeb5f159c, 0xaa950155, 0xb01e7e84, 0xf6e1a79b, 0xd8b86623, 0x8184098d, 0x7d4c5120, 0x066977ad, 0x42fa8c4e, + 0x55161871, 0x945e4381, 0xc40f25af, 0x07f1a27f, 0x8637aa9b, 0xfbc42919, 0x8a613a86, 0x5ee4ec05, 0x30e737d8, + 0x4bd1983e, 0xcca8ff14, 0x718522d7, 0xbb3d0b91, 0x16d39d36, 0xae5ab3f2, 0x4286ad35, 0xec3228be, 0xac4ac6ad, + 0x0d9e6812, 0x74f0e0d1, 0x45d1387b, 0x15416819, 0x2390b305, 0x27e46c8f, 0x43f08436, 0xd527737d, 0xebb03ade, + 0xaccc093a, 0x219f1d95, 0x6a27f8eb, 0x7ff1765b, 0x1434ca0a, 0x3b296cd7, 0x731d01f8, 0x8254396e, 0x176d0b91, + 0x8f190822, 0x679ec385, 0xecc7ff21, 0x3e9bd325, 0xd9ee5800, 0x14138e99, 0x1bbffa7a, 0x277703cd, 0x3915a3bf, + 0x1fce193f, 0x2c02d6b2, 0x4701f5da, 0xf7e7cf8f, 0x141ef5e8, 0xf289d634, 0x714a2a99, 0x42efef00, 0x8d28a15b, + 0x80b3e3e5, 0x8505a980, 0x3fd4ca59, 0x8ed87cf5, 0x2984eaad, 0x11d80647, 0x8d126e3f, 0x062ad9c9, 0x035bca25, + 0x9e8e0081, 0x87d6b2b2, 0x3f22275f, 0xfcb835dd, 0xc3f1fa1d, 0x0e9f0170, 0xa4600677, 0x814467b0, 0x7bd79cf7, + 0x34dea416, 0x4f067091, 0xfc25503d, 0x8871b447, 0x3fbc6daa, 0x1b33fb52, 0x93375c44, 0x989df9b7, 0xc8f80241, + 0xbf8915bd, 0x46c4cb5b, 0x95a33af6, 0xee68d786, 0xf7e3d33d, 0xade32492, 0x56220956, 0x5d62551c, 0xee60f791, + 0x45dd8afe, 0x995df4a1, 0x85461629, 0xbefd6911, 0x3e75bf68, 0x07e42489, 0xa5e8f48d, 0x243ffc33, 0x748ce810, + 0x83832d0a, 0x3c58e864, 0x791da38e, 0x74d234c3, 0xd819e2c6, 0xd3f4da52, 0x28a7c286, 0x9bf8be61, 0x60344118, + 0xc2f8a5e5, 0x33512629, 0xd7a25813, 0xa0f17f10, 0xdd47802e, 0xd83616d0, 0x10dd1b0f, 0x17fea569, 0x17bd57d0, + 0xd0c219ac, 0x692b579c, 0xc7dd5b33, 0x248d5078, 0x4058445d, 0xd9cbf640, 0x5f373621, 0x86738912, 0x40fd657d, + 0xc09393f8, 0x3c89e35a, 0x74bd54fc, 0xfcf06f20, 0xd84356b8, 0x0c7c85e2, 0x4ad39548, 0xd1da4a73, 0x6c017218, + 0x767a9464, 0xb761aaa9, 0x55a76048, 0xa3c2aedb, 0x5ba76b29, 0xb71f868d, 0x4ab8f773, 0x5272b56e, 0x7d4dbe59, + 0xd37968aa, 0x2c1845f6, 0xf2c461ec, 0x8afcb48c, 0x2e0f1caf, 0x4a192e83, 0xb1cdfa9e, 0xf9e7095c, 0x30137027, + 0xd42f1a1c, 0x40aaa7aa, 0xf57f7748, 0xcd6dbddb, 0x85608ab3, 0x97773701, 0x8356cfb6, 0x46e20bef, 0xf422d319, + 0xc5c45cfb, 0xf90db52b, 0xbfd8ea8f, 0x2402a0ed, 0xe48d725d, 0xd6073b27, 0x4e85760d, 0xaff489b2, 0x70dc2eee, + 0x44460819, 0x84bf9f54, 0x7d10e536, 0xd9683c4a, 0x46a2bd42, 0x4e400b66, 0x2238b92a, 0xbf4b810c, 0xbc6dcd69, + 0x566a14e3, 0xeb0141e0, 0x5c33b7bd, 0x168bd821, 0xfe1c0c0d, 0xf33ec6a9, 0xf923b69a, 0x227814b7, 0x248e06da, + 0xca129d8b, 0xb2e08058, 0x2e4d7e2e, 0xad7056b6, 0x9bd333d5, 0x114e0e64, 0xe0601d24, 0x2efc80ed, 0x5556f03e, + 0xc4892863, 0x2f6c9883, 0x481dad01, 0x4f499641, 0xe71b4460, 0xdb4c2cea, 0xcc92b7e8, 0xc7da475f, 0xc5fcf218, + 0x552fa380, 0xaf94dabf, 0xc5b6d25b, 0x5b65ece2, 0x7a07ec0b, 0x3f2c181b, 0x0945e940, 0x7e961df7, 0xae2ec67a, + 0x5c39be42, 0x4c55417f, 0x3c065c60, 0xb4ef14d3, 0x314dde06, 0xe3d5a4f7, 0x5a382283, 0xf6c70ab3, 0x86a3a169, + 0x6ad2bda5, 0xb9ae66f7, 0x28693407, 0xde304911, 0x52f7eecb, 0x222afa31, 0xf2398e16, 0x18751be5, 0x60ed8243, + 0xad23785d, 0x1b334157, 0x9df1a140, 0xabe00bbd, 0xf8867289, 0x10fe247c, 0x8181ded1, 0xfabd0560, 0x49e6129a, + 0xb9c0f803, 0x324aa6bb, 0x3defbca3, 0x4c8eb149, 0xab562e3c, 0x1983c96c, 0x40377f90, 0x902bd34e, 0x10941252, + 0x267eef51, 0x1d948dc7, 0xe3418e0b, 0xce78b85b, 0x0ba59865, 0x2cf4db10, 0xc8d873eb, 0xc5777756, 0x84f22f01, + 0x6b817125, 0xfa2edc3d, 0x25b3d109, 0x5ee113fc, 0x4837f3d9, 0x4eebfb02, 0x3fffd262, 0x0c625cbc, 0x11519f84, + 0x0946098b, 0x141b4beb, 0x1b887219, 0xb7cf8c1f, 0xda27ef0e, 0x85d7f731, 0x6afe6b37, 0x13996c86, 0x25399e87, + 0xcc12a777, 0x0a53d2ce, 0xddfea177, 0xd751cba6, 0xf59db947, 0x4e0966c6, 0xb10e0447, 0xd4c5d179, 0x5d3ae9e8, + 0xa0da5f7e, 0x104a4b93, 0x83b014c9, 0x87717e75, 0x7d57a7b4, 0x4a999aa2, 0x058a4f32, 0x2b725b7a, 0x4bcd5b89, + 0x9b7b9f96, 0xe420ecc0, 0x90761953, 0x12c0cbab, 0x88343b5d, 0x8db1b1f9, 0xf101c072, 0x68b800d3, 0x562d2671, + 0xbd0e8318, 0x8a51e34c, 0x80ee6318, 0xe7ee0f36, 0xc378f1ed, 0x84c299e9, 0x6aab803c, 0x30b3d352, 0x89258a38, + 0xcae0d4f8, 0xefaa3984, 0xa527d28c, 0x45a8b47e, 0x458b8b61, 0x4693e514, 0x84fbb476, 0x61bb6c34, 0x42e8c772, + 0x40671192, 0x795b61bb, 0x4a3628a4, 0x45c87413, 0x47852ffc, 0x99934c03, 0xb905658d, 0xbced7a39, 0x702c5cab, + 0x401faba1, 0x5413c08e, 0x5e721b7e, 0x0522f3d3, 0xd8189d6b, 0x906c9e40, 0xb90f630c, 0xbbc549e6, 0xc6646338, + 0x510e06bb, 0xd5bf0a98, 0x0ee7e143, 0x09efe5fd, 0x30e486f5, 0x6581e20e, 0xb1de5d06, 0x7ac1976f, 0x2f316848, + 0x819c718f, 0x6861e16e, 0xa753cad1, 0x40a6b03d, 0x8dd17ffe, 0x242f95be, 0x364a6e36, 0xf440cd5d, 0x9f8cabbd, + 0x41f2ca1b, 0x2a914637, 0x8777ed1c, 0xb491358e, 0xa066bfa7, 0x44517a2e, 0xe1a2d05b, 0x98f2b71a, 0x1331a40d, + 0x38423bd3, 0x16a54362, 0xc589dad1, 0x15c889ac, 0xc7265b9d, 0x50652628, 0x218a0d44, 0x69cef47e, 0x65f224e2, + 0xfb7b399b, 0x4242d0ed, 0x19a30205, 0x60fa1d46, 0x0438940c, 0x3852da4e, 0x2f350a09, 0x3a44281e, 0xc59a2fa4, + 0x5ac295c1, 0xf4f572cf, 0x8270031c, 0x7bee28a7, 0xae3844ac, 0x2ce54941, 0x5612d84a, 0x4a7232fe, 0x258c26b6, + 0xa174c883, 0x542b2867, 0xf344b7c0, 0xac546490, 0xce962ccd, 0xaf94f429, 0xda3eecd9, 0x72e5d488, 0xef5f44dd, + 0xcb148e34, 0x94c60f65, 0x2ff67228, 0x68f17c5b, 0x778b0172, 0x97c2ead8, 0xff99dc1e, 0x49e90647, 0x3534c53b, + 0x74a18f33, 0x53055a6f, 0x3d91cabb, 0x950d76aa, 0x78313cc0, 0x225ab3ec, 0x920c52d5, 0xbfa8e421, 0x818316ad, + 0x5b093283, 0xf005765f, 0x3e63b449, 0x9f6532a4, 0xb0f97c74, 0xb8b89ac2, 0x1c1724c8, 0x9808fbb7, 0xef0ccb10, + 0x4e5d96f8, 0xa17e3470, 0x790f2132, 0x857d0856, 0x2b8bc21a, 0x92d6c115, 0x81611153, 0x053c05d9, 0xc0bf3d18, + 0xc2eefe57, 0xc5bdcd57, 0x27b0d4e0, 0xda14496c, 0x45c5a7e9, 0xd1b017ca, 0x69863c8c, 0x875bfb9a, 0x837b26ec, + 0x34f2b4a8, 0x257ca7b3, 0xaa62e6cd, 0x78393b9d, 0xa92e2da6, 0x6a80f78a, 0x4db59cf1, 0x97a44450, 0x7bcecd19, + 0x6672f189, 0xdae3380d, 0x57d36bf2, 0xc230cee4, 0xffad8aab, 0xb84665a8, 0x5cdac5cc, 0x30b9b331, 0x89450841, + 0x6589a426, 0x8d145622, 0xb9142fcc, 0xc47dc1f0, 0x28ee8854, 0x6cacfc38, 0xf95e82f9, 0x350f5f31, 0xd111313f, + 0x1a47c67b, 0x5aa568ec, 0x41b41790, 0x2c29336d, 0xf5fec740, 0xc1325869, 0x515bec2c, 0xe2a4f498, 0x10612f88, + 0x188e3ffb, 0xbf337e19, 0x99f95747, 0x511ad026, 0xff773ba2, 0xda24ea77, 0xace85214, 0x166cb7da, 0x78dace6d, + 0xe87cf244, 0x0f135e70, 0xe7b5d598, 0x2600961d, 0x21aa3c71, 0x50612aa7, 0xf60d5836, 0xbdb1d797, 0x94642ff6, + 0x06c45ec1, 0x2c13f134, 0x03f714ae, 0xe05de9f5, 0x730d3681, 0x47b40ed8, 0xdc09a578, 0x4efb6026, 0x193810c2, + 0x673df4e7, 0x5c2d1031, 0x9003ef7a, 0x0ddcb6da, 0x4a84338e, 0x68d0d0b8, 0x66a4c621, 0x7aee54cd, 0xa09cbb03, + 0x327c38c9, 0x68f72922, 0x5b6de73b, 0x83410ca7, 0x113fe9c2, 0xcfe9b565, 0xc57c3aab, 0xa754081a, 0x4e3b27b1, + 0x0e80685e, 0xd7dc85cd, 0xe8cd855f, 0xecd9b632, 0x97326254, 0x3fa413a0, 0x92e8cd9f, 0xe96bae4e, 0x85c480ea, + 0xfba212cb, 0x6ff5641d, 0xde3d3290, 0xcf839274, 0x93262ac6, 0x9a972ea2, 0xa606b30b, 0x24dcf09f, 0x2f8c4105, + 0xe39531c0, 0x14910212, 0x8ffef784, 0x971cfc09, 0x3d847e52, 0x7fed6965, 0xad075d59, 0x9453dc6e, 0x10c2b5d7, + 0x4de481bb, 0xd6420958, 0x669888b3, 0x990c1bc1, 0x5e0fe13d, 0x788216cc, 0xf1554243, 0x8f530522, 0x2dde62ae, + 0x0e638daf, 0x392f0bf4, 0xc048d5d2, 0x5f29a6be, 0x6071478e, 0x835aaf3b, 0xca3c1a00, 0x7b961636, 0xd0feb24e, + 0x63a7fcca, 0xa3ffe1e3, 0x69e3788c, 0x96d600ea, 0x6056b21a, 0xd7fe147e, 0x4050d9e4, 0x7c28999f, 0xdccfa4ee, + 0x91912429, 0x5fc11254, 0x0663b174, 0xe063ffae, 0x036c8ee2, 0xf2ae2788, 0x2ad6d052, 0x95dc557a, 0x91798237, + 0x638d8e15, 0x92913ce2, 0x7d7e246c, 0xc8da959d, 0x3f11af57, 0xe87f46cf, 0xf0b0ab3f, 0x87b0aa42, 0x1d0f8bda, + 0xd2a3da99, 0x02a73dbc, 0x28046201, 0x27a9020c, 0x4edb63f3, 0x25764d7b, 0x82cd0222, 0x8ba28903, 0x7eeea5a9, + 0x28bbb3fe, 0x95b685ec, 0xde525052, 0x5cc23461, 0xfd3e6eea, 0xdcb2794d, 0x2989e3f8, 0xffd5a0fc, 0x7ab6018b, + 0xd3a9f45e, 0x8c6f242b, 0xdec1c03f, 0xc46af3d2, 0xad846170, 0xd0b01209, 0xf567e2dc, 0xd148d9c2, 0x8cea189e, + 0xecad4da2, 0x0262b2ee, 0x7781007c, 0x7407208f, 0x6f28f291, 0x0ad17b75, 0xeb6b7d08, 0x8483eb0a, 0x98784d1e, + 0x5bcfff6b, 0x6395c44f, 0x9f5fd759, 0x6fd01a86, 0xbef4bceb, 0xabb81cce, 0x62d5e87b, 0xbea018b3, 0xd110fba9, + 0xe800a14b, 0x71e97766, 0xf704279c, 0x653c4732, 0x5eb51a88, 0xb55e8877, 0xaa7f87d1, 0xf972e01e, 0x00b996c4, + 0x1e019b07, 0xaee443e7, 0x87ce5cd7, 0xaf65f6f6, 0xcc10690b, 0x92269956, 0x44a8f9b9, 0x1add631e, 0xb78ff7ed, + 0x24b3c22c, 0x73812b41, 0x30fbc371, 0xddee2249, 0x05561bb1, 0x97cd9730, 0x177eef62, 0x23b1ffe5, 0x70b4340a, + 0xd3e5e365, 0x10b5440a, 0x10e88559, 0x89e53314, 0x0524a24a, 0xe3edfec6, 0x1b9de6ff, 0x35f7df00, 0x3318583f, + 0xc45ffdcc, 0xb17e637e, 0x354a9e97, 0xad82a0a7, 0x60040e7c, 0x204d6d02, 0x2a573465, 0xd21d008a, 0xf2613a1b, + 0x1061511f, 0x2fc6237e, 0x9f4edb85, 0x40d8dafc, 0xf8a86d4e, 0x9703c1b2, 0xbdf7418e, 0x65923431, 0x229acc5e, + 0xcddb5998, 0xaf280877, 0xac5a535d, 0x45a24317, 0xb0311652, 0xe5c3a1e2, 0xc271312d, 0xa52d85e3, 0x7d983028, + 0x6be5143d, 0x0b147a87, 0x495c69f3, 0xf3826656, 0xc81a7545, 0x213d7b19, 0xe337c4f4, 0xedbd6c52, 0xf98e0efc, + 0x73b980c9, 0x962e2572, 0x14708eeb, 0x677da513, 0xca77145d, 0x158413fb, 0x8ce3045f, 0x729fc79c, 0x5bcea36b, + 0xa5025b68, 0x78113cfb, 0x67067f11, 0xae682edf, 0xd3dec48c, 0x6ad35fab, 0xb3ef0bf7, 0xa1a66def, 0x5a18e13d, + 0x3b3f3528, 0x1af3d9cf, 0xde5ff8bd, 0x74c2b5ac, 0xef8fecb9, 0xf5364d1e, 0xdd435523, 0x29c8b95b, 0xf2df44ab, + 0xbde08857, 0x6cc2a10d, 0x10a2f7c1, 0x4e8c6454, 0x55aebecc, 0x2b213851, 0x31702e20, 0x99092718, 0xa359bc50, + 0xa5ea4922, 0x56de8fe5, 0x5138974e, 0xe9ce120c, 0x4def83f7, 0xfe0ffcf2, 0x6c5a85d3, 0x9ddb3621, 0x36d6117d, + 0xc99c58cb, 0xc37a8357, 0x61f09051, 0x193266c4, 0x88546f3b, 0xa6544e3a, 0x47827a0c, 0xc79a00c0, 0xcbebd54b, + 0x2c773a73, 0x18002784, 0x5dd9ed39, 0xcbd4237a, 0xbd9d4431, 0x17719a32, 0x22d8b0f1, 0x8975713a, 0x997d995d, + 0x2542d734, 0x29b70b19, 0x0046ab3b, 0xc8357537, 0xb5e37ee0, 0xf4c5881d, 0xfbe45c4f, 0x9d4ea91e, 0xfd71fdbd, + 0xa6bb3d9a, 0xa689000b, 0xf4df0350, 0xb8499262, 0x4883dfcf, 0xe6d013de, 0xfb7e9d39, 0x710a665b, 0xbe7a2fb3, + 0xbe4b4b4f, 0xf097210d, 0x989a26ae, 0x7e30b0dc, 0x1607433c, 0x16ceab38, 0x847b924d, 0x146829b6, 0x4a138654, + 0xf7dbfccb, 0x9e45dbdf, 0xd8f07419, 0xf51c26ba, 0x415b44e4, 0x22171b32, 0xf8b6279f, 0xc8e0fc16, 0x6678ca1d, + 0x5c572c47, 0x63d71601, 0xab731be0, 0x35b88a24, 0x5292c7b2, 0x820b834c, 0xeeee39fa, 0xf4a28629, 0x11985228, + 0xfa848d01, 0x1b1eef19, 0xefa66956, 0x6d6e8843, 0xf08e4a6a, 0x596a0a8a, 0x27cacead, 0x3945e245, 0x7f253b45, + 0xab962fb4, 0xb4714f5f, 0x2a2006f4, 0x54358ad1, 0x04328b31, 0xf4af2bf7, 0x00ef03c3, 0xc8adf3a5, 0xaf4dc611, + 0x578bbc26, 0x21d7bc74, 0xa2b4ae49, 0x0ddd25d0, 0x22fe1809, 0xf27940d6, 0xfb13a341, 0x79029723, 0x7be31bd5, + 0x56b3b0eb, 0xdfae697e, 0x9b58efae, 0xd172c1df, 0xb3818cf0, 0x4013d4b3, 0x8a33d5bd, 0x22d4169b, 0x4996dc3e, + 0x062e144f, 0x4375e10e, 0x62b39cbc, 0xb68ab41d, 0x8b87fcca, 0x54328a84, 0x68c945b3, 0x18f7bede, 0xe8f751c2, + 0x03f538cf, 0xd6d7d6e3, 0x319f7a19, 0x52ad123b, 0xecdb22ae, 0x5e2388c5, 0x49ac7dbc, 0x278ddccc, 0x12fab7df, + 0x9d69c08c, 0x49e3fbc9, 0x63d2fb8c, 0x74c30c5a, 0xf4ee8482, 0x3ee9b169, 0xdcdc1b5e, 0xc791db0e, 0x144a63ba, + 0xfc8c3752, 0x4b2b6e92, 0xf10349e0, 0x66cb9e28, 0xc3b4fbf5, 0x7e06a755, 0xf07ad41d, 0x385ad502, 0x057005dc, + 0x6010f09e, 0xb7302d99, 0x779b7bf4, 0xbdeb539c, 0xd4faa1e9, 0x3f0ee15e, 0xe0898004, 0x6b25d5fc, 0x18b5b6ea, + 0xbf2b5565, 0x131d845c, 0x7ae53de3, 0x7b9b1321, 0x2570347c, 0x5567b452, 0xcf04a23f, 0x95524725, 0xe17e99f8, + 0xb1ef1e65, 0x6ea508c6, 0x9c666d03, 0x822104be, 0xff3f25a8, 0x6a8fed5b, 0xcceac528, 0x82de29f8, 0x117cf8ba, + 0x996ae7a5, 0x038c6dc6, 0xf3e916e3, 0xe7e38e1c, 0xbec49137, 0x1e4d9461, 0x23286d5f, 0xad54ee51, 0xb17ff2b5, + 0x93bda2e6, 0x66826f07, 0x650efc95, 0x3550bfa1, 0x3158ad93, 0x06f0fc8c, 0xcb5af5dd, 0x68a66547, 0x607eafb9, + 0x145d1bc5, 0x8c1672f6, 0xb441479e, 0x681a9ce8, 0xb73169ba, 0x311c8d0f, 0x2cde25c7, 0x05453032, 0x96279d1d, + 0x9e06fc82, 0xd10195c1, 0x60cdbdce, 0x48bb9e55, 0x7d1341c8, 0xd7cff135, 0x5080c4e9, 0x3abf847e, 0x5132ce0f, + 0x1d27ee1b, 0xed29b659, 0x5c51ac15, 0xd13a329f, 0x74819cfa, 0xd24daaef, 0x94dbae3e, 0xc56648eb, 0xd9f40f3a, + 0xc4d7a811, 0x727c6e7a, 0x1620e2ce, 0x529e9842, 0xe4dee6df, 0x5ea2cc34, 0xea0d46c5, 0x62ac6706, 0xada4beee, + 0x8474360d, 0x4fce7ef2, 0x7afe32ec, 0xf1eaa299, 0x1640332f, 0x6502e0f2, 0x1d3d8625, 0x4090ab68, 0xc83e6440, + 0x59e547be, 0x40c69367, 0xdca5fcd0, 0xad50a393, 0x2a08cf12, 0x088fe400, 0x1b615cae, 0x6f3ada6f, 0xc827d97c, + 0xdfd9f8c5, 0xcf075889, 0xfd42c754, 0x3d01a770, 0xb876be86, 0x2111e84f, 0x7e790292, 0xc4b06df1, 0x3774bb48, + 0x2ed4ae24, 0xccdffde0, 0x934d43ea, 0x7ee5d0c8, 0x85aa0041, 0x36277fc2, 0x6d0bf876, 0xef122cb6, 0xc42b9766, + 0x71a52b08, 0x9d37bb43, 0xece35ba7, 0x16b81914, 0xcf39e58a, 0xbdcb4bdc, 0x11f0829e, 0x80c9e42b, 0x709e1c3c, + 0x7d800a90, 0x98db1d0d, 0x025bf3a2, 0xaf151a24, 0x55440d80, 0x84b5bf41, 0x43a3b37f, 0x026c07a4, 0x09911250, + 0x745761aa, 0xcbeb70e2, 0xcbb0cd52, 0x5459c460, 0x31ca813e, 0x59632cec, 0x6ff89de5, 0x6cc015eb, 0xdd971815, + 0xc8d3cbf6, 0x4d73d276, 0xca5b7074, 0x4f1c547a, 0x6ebc24fd, 0x2644b9d6, 0x2e7e357e, 0x0c2b7292, 0x6102b3c5, + 0xc861b94d, 0xd2e4584e, 0xc5518771, 0x79eb0dd8, 0x778e56ad, 0x7b22ca01, 0x995c9839, 0xf09b2979, 0xa5cc7534, + 0x06451ad8, 0x47573c61, 0xe74ea004, 0x39765d44, 0x2d66639a, 0x0f8a21de, 0xf0c73687, 0xd7a6a9dd, 0xf79993b3, + 0xd46fc340, 0xeebdf84a, 0x32d13544, 0x32468186, 0xc7c31ca1, 0x311b9776, 0x4aceded5, 0xf51408dc, 0x2e4a59a7, + 0xb20adbb5, 0xc2b9863a, 0xbc11b585, 0x6770d2d5, 0x56aa565b, 0x424db975, 0x2cadfb61, 0x2d801a6f, 0x2e60b385, + 0x84bdc859, 0x39c50fba, 0x9efacfa6, 0x246e12b4, 0xcc777793, 0x913e6a19, 0x340e8c96, 0x9efa3c51, 0x38970b38, + 0x89e0d467, 0x743f6d3f, 0x5523332f, 0x61c4139f, 0x2dc29e13, 0xbe72fc45, 0xc2a455ed, 0x2b1a5691, 0xf8ff242b, + 0xc5efa722, 0xbb584f8e, 0xb222d130, 0xb01ef586, 0xa498771d, 0x77f814e6, 0xc6793443, 0x47eb7dff, 0x53524003, + 0xce757279, 0x5e896e22, 0x1e914c8a, 0xbf062ff2, 0xa6802238, 0xeeb71ea1, 0x8c8e5d48, 0xf2e77637, 0x3fdf6362, + 0x94f647df, 0xa8ebef23, 0xc8e7a86c, 0x1b8231a0, 0xc776ec9d, 0x1eafad6e, 0xbf220124, 0x668478ba, 0x78cedf2d, + 0xe52555bf, 0x64667334, 0xc50eef43, 0xc33a5809, 0x4ad8f995, 0xeff628f2, 0x2429245a, 0x93ab3090, 0x71e57671, + 0xd3fff84e, 0xf30773fe, 0xe17562ba, 0x623f7e98, 0xfbc99f08, 0x39b004cc, 0xf969f11a, 0x191b29c2, 0xa2196590, + 0xa0367bef, 0xb401a4d9, 0x4652fb66, 0x31288a8a, 0x4071e16f, 0xab53d038, 0xa42529d9, 0x4e785177, 0x82ba8495, + 0x60664271, 0xa9a9167b, 0xefc7324d, 0x443bbc56, 0x3d6667b9, 0x3d04ef8d, 0x74ac7a41, 0x7fa92b41, 0x6dd8e330, + 0x4f852c37, 0x79855111, 0x5ecaa260, 0xde4e6012, 0x6ae9b9d2, 0x113f09e7, 0x20de506b, 0x51108fb0, 0x0e41c302, + 0xccb7e0f8, 0x091eea01, 0x01f8bb24, 0xe78b1154, 0x8d2c1de6, 0xcd8aaf82, 0x9c2b84c5, 0x9fd7b3a1, 0xe5a74715, + 0x9a138b86, 0x8528bd67, 0x2ed09f04, 0x46e37dd5, 0x7c36523a, 0xd7f477ea, 0x4c7a1212, 0x69f92744, 0xca59f84c, + 0x307405fb, 0xe41d0b01, 0xd6dec49d, 0x0e15e058, 0xdf44d103, 0xce3f00ea, 0x1670cde0, 0xefe63075, 0x184040a5, + 0x923e5243, 0xfee009be, 0xfdf1a6ac, 0xd825558c, 0x4faba4e9, 0xad84c113, 0x10a9d32e, 0x43de7ef1, 0x7912f4ac, + 0xf0d8f1b2, 0xa5abdd4c, 0x81320222, 0x215ba0da, 0x4009b3bb, 0xa294de92, 0x807e3189, 0x87f9c620, 0x6a429b44, + 0x291983aa, 0x1bb64f63, 0x5275ae78, 0xab792c73, 0x9892ed44, 0xc90d35e1, 0xf747070e, 0x9f687a4a, 0x1581f3af, + 0x56c5b2a5, 0x61158d37, 0xffff0082, 0xa2759479, 0x6274dad7, 0x62f58278, 0x01910d93, 0xc0848936, 0x597e3bbb, + 0x2efe39ca, 0xaf500c09, 0x2a63d343, 0x24033a85, 0xa6ddc5bb, 0x8968742a, 0xeccef3a3, 0xcb353e15, 0xabfeb645, + 0xe9b69967, 0x88c4fae4, 0xba487490, 0x8f7155e4, 0xc711403d, 0x6b35c1b2, 0xe3422cb1, 0xdc847998, 0xfe7c2971, + 0xbf976d40, 0xb888dadc, 0xe8ca64ea, 0xe5e0e59b, 0xb2cb1b41, 0xae95bf1c, 0xcadbbd24, 0x02c027fa, 0x619a4e2d, + 0xb03f197b, 0xead29dcc, 0xab7c0775, 0xb3e8d4e6, 0x2162e94a, 0x4420f3fb, 0xa801183b, 0xf02c7aee, 0x5f0b85eb, + 0x002b5959, 0xfd907f8d, 0xf087407a, 0xc41c7da7, 0xe2657b76, 0xcb0ba8aa, 0x278d147f, 0x22c5aa2b, 0xf5e738d4, + 0xb91e3724, 0xa6646aac, 0xb9063c0d, 0x5d411872, 0xcbf112be, 0xd07cd879, 0x6326acfd, 0x24be1776, 0xe41c8584, + 0xd3bc2afb, 0xfb01c49c, 0x053724c1, 0x0f3a030f, 0x6c31c968, 0xdd9f78a5, 0x65f795ed, 0x9387d601, 0xe21c5f23, + 0x0d36c5a7, 0x4452a110, 0xd8356125, 0x7568a8a7, 0xc9207df9, 0xdc9debc0, 0xc625513b, 0xc27ea241, 0x3a3f02a0, + 0xe3c10d06, 0xa486c724, 0xcd7ea9b7, 0xe58e5928, 0x1094164a, 0xd5b0ce5d, 0x07d679c7, 0xe66ce27b, 0xc4a2e407, + 0x89723e89, 0x7584084d, 0x68c91718, 0x49d5010c, 0x05e6fc5b, 0x2da6000f, 0x199efd1d, 0x2ee9ac22, 0xbd22a4b3, + 0x07d698e4, 0x0de64116, 0x5a72d8c6, 0x61c38ac6, 0xdad4cac0, 0x45ca5b21, 0x77092f12, 0xf348f069, 0xd14b9671, + 0xd5f20c27, 0x07fb9f9d, 0xd606bae3, 0x3bfad9dd, 0xe1376182, 0xbb13496f, 0x65679a3f, 0xde1b6c67, 0xb3276301, + 0x8ffcb299, 0x1dd13220, 0x08b9b300, 0x057fc5f7, 0x2e9934b9, 0x26562103, 0xa23975a0, 0xebc5adca, 0xb7812ad6, + 0xa123d2d3, 0xf5694b9d, 0xf72a1214, 0x2150f13f, 0xe35d32b9, 0xb1d76e27, 0xef18b11b, 0x4b844917, 0x7654e0f8, + 0xafd0767c, 0x52db144c, 0x08076a61, 0x7362b285, 0x159ef96c, 0xc3892fed, 0xf8271eee, 0xed334ae9, 0x97021f95, + 0x39559117, 0x41f7d3cf, 0xe771e8d1, 0xcd92ab0b, 0xb80945d3, 0x129a5ff6, 0xc130c49b, 0xf9db7e01, 0x0b45830f, + 0x43014984, 0xef65cf16, 0x62cf0375, 0xcb599d28, 0x72cfc5e3, 0xea229526, 0x2239c222, 0xc549a2ca, 0x0eac12b2, + 0x9c818c4d, 0x93f968cf, 0x15c9cf47, 0x21121609, 0x46dfcd34, 0xbb8d2154, 0x9d332ddf, 0x65fa4641, 0x0d32e57a, + 0x05e0f72b, 0x15cbd4ce, 0x52f71f3e, 0xff21576b, 0xddef5392, 0x6f7a7626, 0x8c877140, 0x04cd3ed7, 0xadf351a6, + 0x34fdfca3, 0x4bf70c1e, 0xc1190adf, 0xcc59dabf, 0xefee7920, 0x3b3e206a, 0xa9dd5d0c, 0x7e655f1e, 0xde7a468c, + 0x1d72879e, 0x24ef7917, 0x986efd4b, 0x385aca35, 0x6a9228af, 0x8520f327, 0xce919742, 0x0877a7bd, 0x0cc6a0ce, + 0xfe082660, 0x357a020d, 0x646fab39, 0x94415532, 0xe2f473bc, 0xc62c793e, 0x1d7c2407, 0x53160a1f, 0xe16cc161, + 0x175de925, 0x754e7075, 0xbc2bb411, 0x7db5a9fb, 0x3006877e, 0x53c99c18, 0x32aea527, 0x31449489, 0xabce31d9, + 0xcbc8b21e, 0xf5718bff, 0x47af1b11, 0x04ea3ffe, 0x53de6328, 0xe5229856, 0xdd1fb3c0, 0x72c6cf08, 0x250a4542, + 0xcfd087d4, 0x3a8ecfdc, 0xa570c760, 0x4432efbd, 0x19ffab73, 0x0ac4475e, 0x15db2048, 0x55109868, 0x4124c3e9, + 0x85127dfa, 0xecb6d41f, 0x7a0c7cb7, 0x9123214f, 0xe9d376d4, 0x596783e5, 0xd9dd8b06, 0xdd14c790, 0xf1a30b2b, + 0x544e4cce, 0x0e01fba1, 0xb78ae9b2, 0x4efe6506, 0x9fd3dd3b, 0x39cad9c5, 0x14d95a2d, 0x5780b269, 0xd17f408d, + 0x0d3916a4, 0xf5e63c46, 0xd7d48cdd, 0x536a477e, 0x1a9d3c90, 0xadb12f06, 0xb8c316c4, 0x92fb8bb2, 0xf29035b2, + 0x56e03bd0, 0x06966316, 0xea2fc9ca, 0x3b457fdf, 0xa2bb7051, 0xef74b317, 0x7ac3dece, 0xbd0af05b, 0x32e08d27, + 0x3344a102, 0xe15bcb48, 0x146cbfb4, 0x1c364de9, 0x4e6e1da5, 0xcf7a35bc, 0xf8a246e3, 0x364735fa, 0xf60af2be, + 0xcbea0bde, 0x49a6a169, 0x7ca93291, 0x39ec4de8, 0xef349c5e, 0x6adb512f, 0xf8198dd4, 0x9c5b69bb, 0x04506545, + 0x0639b3d5, 0x349ee0a5, 0x49daab17, 0x61a99aa8, 0x47f7a8e7, 0xee5ae76f, 0xd34a43aa, 0xc048dd77, 0xbcca3396, + 0xe7af871d, 0x9d35eeea, 0xce405800, 0x58ee6340, 0xbc6b48c8, 0x25eaa0a1, 0x109077c8, 0x6d598988, 0xc714a525, + 0x41786dce, 0xd0fb7784, 0x09c5df42, 0x93751a23, 0xa133d31e, 0x890d3893, 0x2113e9bf, 0xf2163042, 0x31e1c980, + 0x537a473f, 0x62d51790, 0x37aacd3f, 0x7db98e6b, 0xa20bee6d, 0xccd4d354, 0xacde1fdc, 0x35d2d8ae, 0xb353bf8c, + 0x8a6449de, 0xfa50c9b5, 0x5288ac98, 0x916ba3d4, 0xdcd97440, 0xb492a705, 0x31366271, 0x082bb1ce, 0x1d0a16c0, + 0xdef1938b, 0xd4b40edf, 0xb0f77748, 0x6eabbdc0, 0x278c98d5, 0x0c4637d1, 0x2e43fa68, 0xcf7019b1, 0x7e301c9f, + 0x298a14de, 0x043f686f, 0x804182ef, 0xb0c1f257, 0x20d9371c, 0x4b0325a2, 0xa7903482, 0xde3164ae, 0xe8795439, + 0x6a500050, 0x141564ec, 0x95f25a60, 0x0fa75486, 0xea732765, 0x09fd7cf7, 0xead76ec0, 0x5109fa8b, 0x563cc3b4, + 0x6deabc15, 0x3214f961, 0xb1d67b0a, 0x30b54aab, 0xa72cb2e5, 0x67d58872, 0x12d1cb7a, 0x52c7851a, 0xe15a5f04, + 0x6ccd2525, 0x968a1abd, 0xf7f3213b, 0x0a76559b, 0x1a93c5d0, 0x2a220656, 0x9e1fb05c, 0xd83fe512, 0x727c6d19, + 0x4df4b078, 0x33115204, 0x06745dd1, 0x2bc985b6, 0x4b1a8d16, 0x65e6cb70, 0xb359d4cb, 0x71fdebe8, 0x96659bfc, + 0x8c0d3225, 0xa252e82d, 0x7802949b, 0xd6c3b750, 0x1aadff2c, 0x85153649, 0x708a2c35, 0xd2a16315, 0x0762000c, + 0xa7106337, 0xf2e2d939, 0x63e61dc6, 0xf577aedb, 0xe8a70dcb, 0xecfe6ff8, 0x6a163471, 0x4bb901b9, 0xf05e5793, + 0x2b8169b1, 0xfa079063, 0x9289d6d1, 0xa04fad9b, 0x7b821f8e, 0x50ac5c0a, 0x092c6d36, 0xfaa13651, 0x11649adf, + 0x8cffb36c, 0x067d06e6, 0x1d3a6fd5, 0x270abe12, 0x34ecdde6, 0xd763136e, 0xd38c80bd, 0x88a9f4ae, 0xa1ea068f, + 0x756a395b, 0xa21d627f, 0xec1be1be, 0xa88b79dd, 0x08d1f984, 0x4105ee4a, 0xa1b7c442, 0x7c1e9e52, 0xb3e5f78c, + 0x4dad4f39, 0x1d2017f0, 0xdb124129, 0x8b6e7ffb, 0x03999f72, 0xaf7c1846, 0xbba5cd7c, 0x49e7275a, 0x2f0fed77, + 0x1536006b, 0x1bc6b33b, 0xb9200669, 0x8b714320, 0x52f1aba4, 0xc41288f7, 0x61eb0e17, 0x5fbf60b2, 0x0b616491, + 0xfee6032d, 0x4c90e78c, 0x9c586efa, 0xa1e47597, 0x26f2964c, 0x2ff68ba5, 0x80e0e42f, 0x655d2c22, 0x0380b99c, + 0x210121fe, 0x0d6d798e, 0x31835660, 0x0aefc82c, 0x6aa43160, 0x9d1c3849, 0xb8c319f5, 0x540aa3d2, 0xbe83472d, + 0x1e345eee, 0x074339fb, 0x7807a63f, 0x9f96ccfe, 0x6574e4e8, 0x3e25c22f, 0x13f39a8f, 0xa731c50e, 0xb922bf97, + 0x63727a67, 0xf6722835, 0xd734571f, 0x7aa9af09, 0x42b55a8e, 0x9da11fe4, 0xde97e550, 0xb7bdc80a, 0x4314b821, + 0xe7cd5bbb, 0x796a40b4, 0x56ade1d8, 0x60baf4d7, 0x51fc5930, 0x0d88268a, 0xe00e950c, 0x2df90cfb, 0x66c3aa3c, + 0x580be155, 0x6d5b9a7f, 0xe0de2b53, 0xf770bc8d, 0xc1818339, 0x06e0553a, 0xe693c774, 0xbe1d9fca, 0x00432eeb, + 0xeb3c0958, 0x7ad213d5, 0x88d9d100, 0x1a0fc0e0, 0x6594abe4, 0x39721f50, 0xc8e05f13, 0x3d5d19ae, 0xf0c74ab8, + 0x47bbbe54, 0x3cd35edc, 0x2dd06dcf, 0x016ea97d, 0xc4100bfa, 0x16074eb3, 0x57d531bd, 0x7fa97e2b, 0x1a0e67f6, + 0x109a3aa5, 0x7a473d6b, 0xca5ee386, 0x8d20ecf2, 0x860a1120, 0x7f2a33ce, 0x9ced1f04, 0x9e5700b1, 0xf508818b, + 0x11d34c96, 0x2b1c4f78, 0xa23d2c15, 0x0f7b3796, 0x3cede6b2, 0xda88a964, 0xbc362bfd, 0x26963be8, 0x2e998c4d, + 0xa0094c74, 0xc8644119, 0xc9ac42b0, 0xa2afd86f, 0x277daa1c, 0xaca96513, 0x56ac20c5, 0xb5b4d5ee, 0x588888e6, + 0x8a9886f1, 0xc63aff1a, 0x392f2e05, 0xab700272, 0x334bef10, 0xa2840714, 0x61b51641, 0xdd2b74b6, 0x0f58d6de, + 0xb923f6ec, 0x807a710c, 0xc52ddd61, 0x478e5368, 0xf2ee8fbd, 0xb6eb26cb, 0x9bb5403c, 0x6bab309a, 0x0311c935, + 0x25e2ddab, 0xcfb3c108, 0xc87d1b36, 0x619ac660, 0xf10eb32f, 0xb35438c5, 0x973aac2e, 0xd15883f7, 0x7e5d8ce7, + 0x16eee1ac, 0x1ef75879, 0x2a67d979, 0xdcb0ed7f, 0x2d55759b, 0x5ef789a7, 0x6fd48a19, 0xafb3526f, 0x6afc5da6, + 0xb7e23a36, 0x200fc47a, 0xdbac22a1, 0x29d4a9c6, 0x53b3162c, 0xa8b45d5e, 0x82bf0604, 0xbc449667, 0xff28f25e, + 0xb3dd261e, 0x0505f9bb, 0xbacee6a8, 0x2396c2d4, 0xfcb16486, 0xc2e942dc, 0x3151181d, 0x4b780554, 0xa5af8905, + 0xf8102768, 0x027283c5, 0x78cb719a, 0xfad1ec01, 0xcf7b845d, 0x13b94a5a, 0x3e1658b3, 0x55f9785a, 0x748fa885, + 0x04d8ddf9, 0xb805f62b, 0xb35365f5, 0xea608914, 0xcb8361f6, 0xa32c1f4a, 0x78e77145, 0xdff73647, 0xa7379761, + 0xc1f3af32, 0x5c9e8224, 0xec31987e, 0x14294d92, 0xb6aeb5bc, 0xe928224b, 0xd44dd0c8, 0x6523c4fc, 0x3ac69ee0, + 0x5876e470, 0x7c7fe9a9, 0x8623aac0, 0x589ce268, 0x54b9402f, 0x124b2f74, 0xfb56e266, 0xdd6b9bf7, 0xf6586eb3, + 0xbe0e7e97, 0x769267f7, 0x80bc1d21, 0xd07a9310, 0x4e790747, 0x059f7245, 0x8f540310, 0xe2d11a06, 0xbb98a6bf, + 0xe4236ba3, 0x99c2dce8, 0xae2dab2d, 0x09743acf, 0x032a9d5d, 0x4fb30334, 0xc562f01f, 0x496fe2af, 0x86a3c493, + 0xd21bb8c8, 0x5d0455cb, 0xd316e407, 0x6866eeac, 0x0316a4b4, 0x0cee0915, 0x6b0389db, 0x65d58ea8, 0xfd661c2e, + 0x2d52b2ac, 0x6e8ca1e8, 0x7a00946d, 0xc1d474ed, 0x248f00a0, 0xbe5d19a6, 0x05f0995a, 0x22f30d0c, 0x5d632797, + 0x74112112, 0x0cd083ca, 0x973d6240, 0x12dcf22e, 0xb8ed3535, 0x13e90c4b, 0x3f6020f7, 0x45ac8923, 0x1385e84f, + 0xa8bacd0c, 0x8221cb13, 0xfb074f0a, 0x0b21bd61, 0x0283c69a, 0x37d85e72, 0xd9880bb2, 0x6ef994b7, 0xf677d499, + 0xe668e795, 0x5e1f9a2f, 0x9188f729, 0x987f8759, 0x10406b57, 0x5f4b6fbc, 0xca7dc74a, 0x780ffdc2, 0xfec9d4be, + 0xa5beee6e, 0xa5c3d606, 0x4a94311a, 0x069d575c, 0xbfb61233, 0xc11edf5e, 0xfbb9cad1, 0x5985e1c7, 0x521d8f40, + 0x56eb8cae, 0x13dc3d00, 0x16871d02, 0x9ce8f44b, 0xdd8e409b, 0x008c9fc4, 0xfba3d746, 0x9cc6e1b3, 0x9244063c, + 0x6f4097a7, 0xf35f943f, 0xdb09eacd, 0x540bf947, 0x27e5ff35, 0x6ba6b1c1, 0xc468d772, 0x9766bf30, 0x32a58596, + 0xd02e4bcb, 0x24ce1c51, 0x36528500, 0x30594cdd, 0x3eb3aab4, 0x8bc406c6, 0xa90531f6, 0xf5006d7e, 0x17843557, + 0x8e265289, 0x09bae7e7, 0x335ae155, 0xf022fce8, 0x7c2e4797, 0x9eef23a1, 0xe12a6f74, 0xc361c4d7, 0x24532034, + 0x9e1797ea, 0xb0d7af0b, 0xbd70db40, 0x143d1b61, 0x25e5ef20, 0xca51391d, 0xf3659697, 0xe303ee4e, 0xef6d65d0, + 0xe52b4be3, 0x4e937840, 0xe37b82d5, 0xa13cf089, 0xe6b52776, 0x71df722c, 0xe5cc2c03, 0xa414640e, 0x17fa83ad, + 0xd4f0d965, 0xbaaa3bf3, 0xe90bf6f5, 0x40dfb112, 0x86fab584, 0xf86821d3, 0x9fffbdc3, 0x0cd89c86, 0x5bd3e715, + 0x250398ab, 0x91b91f5f, 0xa67c853e, 0x285d6611, 0xa7093227, 0x8dd3d21a, 0xc030cb56, 0x3c0eaa5a, 0xa1ba26b0, + 0x08b5916e, 0x9e6b92b7, 0x0928c1c8, 0x19c25571, 0x0d370bdd, 0x09daad62, 0x92e96cf5, 0xe9299204, 0xedafb826, + 0xadda5a01, 0xcd0758e9, 0x5409a9bc, 0x4a2caae8, 0x1c6a51ea, 0x61bf84af, 0xd6166bba, 0x9945ded4, 0xbb2b960f, + 0x74dcb6ea, 0x0ad0b8fa, 0x2d3cf9c2, 0xa87e5902, 0x154b61bb, 0x7365234b, 0xa113347a, 0x4ce4cee6, 0x9e262f15, + 0x9e250d39, 0xe6e8e461, 0xd6a93f49, 0x5961efb2, 0xf85ebf59, 0x8283a7e7, 0xa6de4f70, 0x19822ce9, 0xfd6bc877, + 0xa01a8de1, 0xf4aa81fc, 0x5d14ff4b, 0xa001d2fa, 0x7d804e0d, 0x4fe62fbd, 0x2f986537, 0x5247ce97, 0x26fe292e, + 0x2e68250c, 0x6fe61836, 0xbfdddc0c, 0xf376ee05, 0xfd76ca5e, 0x26188344, 0x7129f3cf, 0x450c4311, 0x70d62380, + 0x2f46d59d, 0x57eff741, 0x794de1f5, 0x86065a66, 0x3207d1f4, 0x91fbba87, 0x0b787aec, 0x0ac854b7, 0x772fdbf1, + 0x7a6d21d8, 0x55a3dd06, 0xde81e3f1, 0x4ab29061, 0xc9b5859c, 0x7dd09925, 0xf206ba63, 0xfc692bcb, 0xf77bec88, + 0xa3504768, 0x9cd33eb0, 0x22162da6, 0xf8217a84, 0x4d4e2aab, 0x02965279, 0x8e6f8a36, 0x7d758e16, 0x52143941, + 0x25d163a8, 0x2748ce5e, 0x91e48ad2, 0x118cf705, 0x5a510b83, 0x4ab4f5a9, 0xbfadcdee, 0x6ee1f8e1, 0xe983f85d, + 0xc1d1048e, 0xb7dbb5f3, 0x7e8d92ed, 0x90f308bd, 0x47c6e24f, 0x61e499aa, 0xf11998b7, 0x14b5edc5, 0xc464ca35, + 0x8056f22a, 0xde426680, 0xacc0adae, 0x11f2e96a, 0x71997be7, 0x88dabf2b, 0xe9ac0dd9, 0x750efd22, 0xbcf0acfb, + 0x320019d9, 0x73ed8fe9, 0xafb3a335, 0xe94f483b, 0x2fba04cb, 0x65d6dfb9, 0x38900e93, 0xde2773a0, 0x01bc7ab7, + 0x041ef9e8, 0xbcd02573, 0x7e0052e6, 0x2787dd07, 0x7d99f188, 0xc2608a97, 0xbac3276f, 0x7b11e9f2, 0xe858f156, + 0x418ff94a, 0x72d43ff0, 0x7ea7aa01, 0xc1cc8f3e, 0x669be42f, 0xab5cd48d, 0x2eee05d9, 0xb2c28ef1, 0xf0bf984e, + 0x4b216ae4, 0x8db03d80, 0x7462a019, 0xe80c489a, 0x47a27f65, 0xc5530661, 0x77bea6ad, 0xc444326e, 0x8496de66, + 0x7b5bde6d, 0x4bed4d3b, 0x485565c3, 0xa75cfd38, 0xdc6486c0, 0x886de9fc, 0xdc3bba03, 0x7572e741, 0xf164d10e, + 0xd586fdb6, 0x7723ab54, 0x14efe46a, 0x3bdb8218, 0xa50090b6, 0x9b9c9cdb, 0x74b94992, 0xefdf6f56, 0x32c455da, + 0x1278739b, 0xc17051ae, 0xbe350c9d, 0xdbd1dad4, 0x04dbb4ff, 0xe9ee85b3, 0xa470358a, 0x76a7acb8, 0xc9bd0f66, + 0xa4c47ddc, 0x68d86367, 0xa1c8ae96, 0xa5c19b7d, 0x071f3423, 0xc9eb64d9, 0x8934ded9, 0x36ac8429, 0xc461cbc3, + 0x7cb54206, 0x6670e030, 0x5fdcf743, 0x4bf68497, 0xc1927b2c, 0xa947d7a2, 0xec6352e5, 0x32a8f68d, 0x8a06776e, + 0xe000ab93, 0xe971de19, 0xd16c129e, 0xe0079a03, 0xcd5aacc2, 0x86ce8c31, 0x369c8db5, 0x962a8b45, 0xd00a6f4e, + 0x46fe3873, 0x0e7acd63, 0xc7bafe2e, 0x4a7df3dc, 0xbcb5e1a5, 0xed6d9747, 0xce8368ff, 0xdbfd8c57, 0x233a7a18, + 0x8bcc1666, 0xaa3174df, 0xaf4fdf6b, 0xe221c6fc, 0x5ee3c915, 0x4a07c071, 0x1c1d426f, 0xc86851fa, 0xb7db4853, + 0x06f70ca3, 0x08e8150a, 0xd494b562, 0x96b27392, 0x1fe9e8c4, 0x47501d9c, 0xfceb3d3f, 0xa6ac6027, 0xcfe8fa6b, + 0x8c9fd89b, 0x84d1425f, 0xbbdd917f, 0xa4880235, 0x89faa482, 0xd41b403d, 0x26c8cce6, 0x848e998b, 0x76220724, + 0xa4084553, 0x5bbbfe88, 0x512d8d98, 0xaedeef63, 0xee2dba42, 0x9045f4a2, 0x03e4fde9, 0x9ea4d75e, 0xf021134e, + 0x8837e307, 0xd77a7bd2, 0xc94929d0, 0xd952ef0c, 0x2941236f, 0x5ac3cc1d, 0xc13f6fbd, 0xb6932ab0, 0x85064a4c, + 0xc05df4ed, 0x28e55016, 0xbb3cfb4f, 0x1c38d79f, 0x72f781fc, 0x8c01672c, 0xa869cb78, 0x54c1de39, 0x545f81c0, + 0xc7bfcc30, 0xdc6e5f50, 0x59f4b7ca, 0xed3f152c, 0x02e3d548, 0xc5f3254a, 0x655a435d, 0xdb60016b, 0x07c7e3ee, + 0x9b34ec8e, 0xd2a2d82f, 0x8789736e, 0x2f5cb89c, 0x20b8756a, 0x827bf7ec, 0x0783f85b, 0x6f0a3c96, 0x4ee55bd3, + 0xd1c95671, 0xb70a5da3, 0x3d7114af, 0xe3a5d604, 0xc88f069f, 0x43d97d76, 0x0923d70d, 0x76b86efb, 0xb7b44fc1, + 0xd1021029, 0x5a7a7124, 0x2752ff5b, 0x80438753, 0x51c04161, 0x9be2c9e9, 0xbe09138a, 0xcf188e21, 0x0cb8735f, + 0x7d48bbb0, 0x252e92b5, 0x88cbdbd6, 0xb51f1b46, 0xe291b933, 0xbd020668, 0xe81339b5, 0x11279836, 0xd276af62, + 0x8a1f7f83, 0x29f8bd01, 0xf364820c, 0x0dde5a8c, 0x74e3dd09, 0xdf5347d7, 0xb092b81d, 0xe531d68e, 0x3b2977ab, + 0x1f954012, 0x13d609fd, 0xaa1b3e69, 0xda1d6548, 0x6acb5e40, 0xfae72889, 0x02b9761b, 0x08db63ef, 0xcb7c0a2e, + 0x6bda8302, 0xa62ded6c, 0x933b1e58, 0xd60271f2, 0x99fe63a5, 0xd604d2a8, 0x87916458, 0x18d2e657, 0xae4b8da3, + 0x7d98fe9b, 0x9421acef, 0xf2502d15, 0xccdbc036, 0x2d97a40d, 0x0c750f24, 0x97c3f43e, 0x69f4690b, 0x98908e39, + 0x8345f37e, 0x6e3b2bee, 0x2641eb83, 0x4a685683, 0x73c93843, 0x4fc00a99, 0x79145231, 0x4eaacecf, 0xb757fae9, + 0x9df6d2cc, 0x91bb67a0, 0x1ca954e2, 0xbb80e8a2, 0x9c89a1d7, 0x4e37b0c0, 0x48788da7, 0x162987a5, 0x61224da9, + 0xb306ce7c, 0xe700921b, 0xb499a644, 0x032cdd30, 0xd550725d, 0xb6a8a69b, 0x487e36e3, 0x7660d022, 0x751fae8c, + 0x1b685d86, 0x41496455, 0x60c8bd9a, 0xadd02268, 0x02964e26, 0x9191f2be, 0xe5ff5916, 0x5c40e817, 0x95ab2e47, + 0x794c125e, 0x97bf9b88, 0x0b16c113, 0x3dd03433, 0x20780e9a, 0x1ee68928, 0x84d4fb3e, 0xd5d8ed18, 0x00fdc802, + 0x87134d13, 0x4df30b5f, 0xf9d81fb1, 0x0e181997, 0xbb0e9322, 0x083c465d, 0x6a4a2b67, 0xa7a39034, 0x673c3a73, + 0xd5f4a309, 0xe04de0ef, 0xfc68238f, 0x358e5d9a, 0x82916db1, 0x688a8175, 0xac5f2df8, 0x1d81bfbb, 0xc189d1b9, + 0x15990884, 0x237bd5c4, 0x5079b872, 0x4bf59738, 0x8f154af0, 0x52109a9c, 0x6332c26d, 0x8a06ed0a, 0x3c7b8caf, + 0x01d76b29, 0xbc7f7e35, 0xbb11ffb5, 0xfe517ab1, 0xdefdba8d, 0xd870e957, 0x7fd0c14f, 0x6cf7a955, 0x1bc4842c, + 0x688d8904, 0x3568f894, 0xc77c12be, 0x7c5da154, 0xad6b907e, 0x7db25dfd, 0x8c4c0080, 0xdbb8314d, 0xcca122b6, + 0xfc6c9542, 0x34a1800c, 0xea31a0f3, 0xeddefecf, 0xe298e0ca, 0x78a4e58a, 0x103e9be5, 0x233314de, 0x5732ccf4, + 0x0a20d424, 0xcaa28bd7, 0x3f42688e, 0x829bb31d, 0xf493d9f9, 0x4c1fa98b, 0xab43d87a, 0x35f0d7db, 0x3e04931b, + 0x6ff6dead, 0x59a4fa60, 0x0a17d91c, 0xd272c249, 0xa104bb13, 0x85599f6a, 0x73f7bbb0, 0x0206e42c, 0x86054f10, + 0x45a5ddf8, 0x51931573, 0x0a80c9b2, 0xadffd502, 0x8d1dbe55, 0x57fa3a4c, 0x80935736, 0x717660f7, 0x93727c9e, + 0x540fea01, 0x942eef84, 0xbf7653d4, 0xaeda7be0, 0x4520f55f, 0xfc47a355, 0xf103e8d7, 0x894e4382, 0xd71d51f3, + 0x27a18515, 0x9e901d0a, 0xac8720c3, 0x43999dac, 0xa7631750, 0xdef4961d, 0xd9c5f43a, 0x0b82c565, 0x9f5b09b2, + 0x60a3c36f, 0x17fe63a1, 0x4a33d316, 0x623d770d, 0x5c3a52a1, 0xb06860b5, 0xb8479cdf, 0xa3bf1737, 0xeb321424, + 0x130f0876, 0x815e7217, 0xf61a9795, 0x4004071c, 0x91a1cb06, 0x3bfb353f, 0xf1d6bbce, 0x98926c59, 0xfed57bab, + 0xe942650b, 0x991241db, 0xfedbacd2, 0xc07b0860, 0x941ded28, 0xdef1ba7e, 0x1aef716a, 0xefebe4df, 0xe5ef9cf4, + 0x09c7a484, 0xca1894e0, 0x69483554, 0x91e01bd0, 0xbf9c9bd6, 0x49258580, 0x4a7bc089, 0xdddbe220, 0x2924d3bf, + 0x4baa253c, 0xfdfa248d, 0xf135d319, 0xfaecd563, 0x2135540c, 0xa8278c8a, 0xf6233873, 0x5251ceea, 0xfe3b87cf, + 0xb6ef2af1, 0xeb67b372, 0xdbd0f9a8, 0x62259c06, 0xefe63b95, 0xce523582, 0xd503a650, 0xfac49626, 0xd35dfb2d, + 0x1d2995d9, 0x6f3ab742, 0xf46298fe, 0x199521f3, 0xabbb61a4, 0x047f64aa, 0x7bf27454, 0x901adae0, 0x892db29e, + 0xce907af7, 0x2b40111e, 0x10e6345f, 0x5be6b5d3, 0xc8a8ba22, 0x91ffce3b, 0x92d56c9a, 0xcdc4b44d, 0x96aa3ed6, + 0x583839c2, 0x05e8a587, 0xeb06831f, 0xffdc542d, 0xdf92bc04, 0x57df396a, 0xa5c143fd, 0x774a7f3c, 0xa0542f7a, + 0xaef79c37, 0x1939eb24, 0x03400be1, 0x2310ce21, 0xeb1eaa2e, 0x386fd6e9, 0xc53921d4, 0x311261d0, 0x47b4bbb7, + 0x3695b80a, 0x8b133c0d, 0xf42bf851, 0xe7f1e5ee, 0x021a53e6, 0xf68a0501, 0x695578ac, 0xcf70d859, 0x94e524f7, + 0x23f49de2, 0x484c0c09, 0xa0459ea5, 0x53a75120, 0xdc756962, 0x2f198041, 0x87cc4481, 0xe7c1e6fb, 0x527e973f, + 0xf9114109, 0xeb9ff2fb, 0x3ff83a2c, 0x2a22f8c1, 0x02a2af84, 0x4eabde06, 0x97c8c565, 0x944b6996, 0x3ba7a92f, + 0x6b8f2b2b, 0x22ada190, 0x4cc78164, 0x7c117338, 0x38d548d6, 0xcbdacf5c, 0x3dd2f81e, 0x8a1c70a7, 0xf80e9dd4, + 0x494d737f, 0xd3c30f23, 0xdff540af, 0x42f5692b, 0xcbb68212, 0xf9971674, 0x810aa485, 0x35798e5d, 0xc4707719, + 0xe2495ec1, 0xc0ab7a28, 0x17045602, 0xbf3e98f4, 0xa2627e50, 0xc89c7652, 0x206137b7, 0xa0bf79f8, 0x019dcbc7, + 0x7039816e, 0xfe6ed8ca, 0x24f5aeaf, 0x2dbbce3f, 0x22442c48, 0xde866420, 0xc9bd9d1f, 0x13101e30, 0xd90a1673, + 0xed0840ae, 0x6e955cf2, 0x279dd344, 0x2ee26b52, 0xed6f25d7, 0x6b0f9f01, 0x26dee42f, 0x544574cb, 0x990c99df, + 0x29f04d6f, 0xdc8b0228, 0x3ed8129a, 0x75b27de5, 0xfa8529e5, 0x35988d60, 0x776bb518, 0x3539d35a, 0x415d23ee, + 0xb748ff3a, 0xf4a03f11, 0x60be0c26, 0x2e61f68b, 0x7fab9f09, 0x97c22274, 0x8d210e31, 0x0c6b602b, 0xee574860, + 0x9ac294a2, 0x566048d9, 0xdd09d8f9, 0xf8d6d65c, 0x71b29228, 0x40bf989a, 0xd99b5800, 0x6d1eb6ce, 0xefa64ce8, + 0xc4fd3ac5, 0x0ff40a6c, 0x32599632, 0xcfa9546c, 0xd879fceb, 0xd5272425, 0x5eb57bda, 0xa7daf473, 0x2715b0f4, + 0x59f8ae62, 0x7f4a16b8, 0x01556a19, 0xe381328a, 0x273c4b72, 0x43d4875c, 0x28286d93, 0xcb6db7d9, 0x7d79b749, + 0x8a793e0d, 0xdc4c83a6, 0x5554326f, 0x1a113800, 0x198871a6, 0x04ca8ed7, 0xee0e564d, 0x372774ad, 0xea166766, + 0xe1bfd446, 0x959075aa, 0xc5de5ca2, 0x46cc3362, 0x96faf513, 0xd33d0119, 0xaa33761c, 0xd9283bff, 0xbfc7e58b, + 0xc77e62d0, 0x91d59918, 0x2ccf27f1, 0x9e5986cb, 0x65e944ee, 0xc7a34039, 0xeebb6880, 0xf35fca51, 0x6eb075e1, + 0x6fad3aaf, 0x7c21bc3a, 0x8c734a18, 0xe54aa24a, 0xe16b1dca, 0xf2169ac6, 0xad366e8a, 0xda3e395d, 0xd5c11bcf, + 0x6ccc2718, 0xcfc794da, 0x10dfee7e, 0xc531385f, 0x59bc93f9, 0xb24b8a9f, 0x01bc3882, 0x67adf4f9, 0xf47157fc, + 0xb67a56ba, 0x1c7c0234, 0x80bc94d2, 0xbe464285, 0x46db8b26, 0xdceadc17, 0xc2d7b3e8, 0xdf43e946, 0x43b584f5, + 0xa9cc4d81, 0x39f1c90d, 0x49fcef5f, 0x44f08048, 0xaa000005, 0x574d2ff4, 0xc4acca74, 0x38c4aa1d, 0x5e1ac9d7, + 0x628fdaee, 0x71870726, 0xa8f6a84f, 0xc356cc98, 0x27828b51, 0xd24f6552, 0x87a46ef2, 0xa95326ff, 0x65e911ef, + 0x1a85bd99, 0x7a1e1fac, 0xddcd1592, 0x9aa5a6e2, 0x546d6fc2, 0x71f7184a, 0x69b508c2, 0x5d323f4e, 0x3ca2b3f8, + 0xf92edc20, 0xac6d9629, 0x11bb38ec, 0xc287310c, 0x76de1eb1, 0x8c29292f, 0x54b82bbb, 0x8d28c9c3, 0x05f780bd, + 0xeb638b8a, 0x942c6df1, 0xb1264cc2, 0xf3ddae0b, 0x9f1e0335, 0xe2786fdd, 0xcb4f08bc, 0x1a1517e8, 0x4cc75146, + 0xd36e55b5, 0xb6d9ca0e, 0x967b2b69, 0x0bb74ce7, 0x35146571, 0x79709567, 0x7fd06920, 0xc40da366, 0x0a563960, + 0xd3dd60b9, 0xa8a60c9a, 0xc3945207, 0xdfebb07f, 0xb2e26035, 0xc35d1f69, 0x903f751b, 0x55487f78, 0x46f50b16, + 0x7f6c5e31, 0x66bbb886, 0xcda81dd5, 0x1d52b746, 0x0ff97c15, 0x58f94d0b, 0xe6f3ffdc, 0x29052282, 0xee07c5c7, + 0x3873cc36, 0x36c4ca43, 0xd4b1bfb9, 0xfc88eb78, 0xd0d29e49, 0x1b675d8c, 0x59d08928, 0x3b7847be, 0x33d56b6a, + 0x52cc4028, 0x08973905, 0x7064a20b, 0x8716c007, 0xfd39e88c, 0x96e6b02d, 0xf41563f7, 0xefa27c9b, 0xdeea8fec, + 0x61d1003f, 0x38a39d33, 0xa4000798, 0x61c2d4b4, 0x7c7e4957, 0x2b31ccbf, 0xa0262333, 0x026b18ef, 0xc53f2fac, + 0xd42187e6, 0x2d5e3d78, 0xb6b4a4ec, 0x8cb319be, 0xc6246e74, 0xfcb6ea8e, 0x9125b0df, 0x4d0ee969, 0x9c877520, + 0x08f3e8ee, 0x2b433abe, 0x4fb55d02, 0xeeb74b77, 0x4827f357, 0xfbc56d83, 0xf03be8b5, 0xfdd21543, 0xe05db03a, + 0xda6b9f4d, 0x582693ed, 0x3cc3a7d3, 0xe465eb28, 0xdb1ceec9, 0x8a8e6d22, 0xbd38d3ce, 0x33563cdc, 0xbfa68db9, + 0x9307d8eb, 0xc60c280a, 0xdfd1a611, 0x31fad6d7, 0x87a4a0b9, 0x2d5ffd1c, 0xe6b9e177, 0x52ea0d02, 0xbb9adbdb, + 0x6f5c9b77, 0xfbe68d83, 0x2b36fb7d, 0x3de289ea, 0xba8532f2, 0x87ca8e3e, 0xa2224152, 0xe08b28f0, 0xb239cb1b, + 0x862514c8, 0xc9d2fbd9, 0x56491bcb, 0xbf008e33, 0x1ed04405, 0xe48d1594, 0x77d5c970, 0x57979398, 0x7c3f61a7, + 0xf880a8ce, 0x46054cbf, 0xebbe705e, 0xf40f0280, 0xce7c097b, 0xfc64dee1, 0x9b86be6b, 0x9a6f0857, 0xaf16b04d, + 0x58eed43a, 0x3244e0e6, 0x991ce501, 0xa37edb55, 0x77be6b77, 0x9c415ab8, 0xa9057311, 0x46e284e8, 0xc38e21b8, + 0x4da3ee8c, 0x7864d8db, 0xc50a3380, 0x1d6cae80, 0x350d324b, 0xc9ae318b, 0x692ffe0d, 0x7f481fdf, 0xb5f82c07, + 0x1150cea0, 0x4feb56e6, 0xba4cfe92, 0x9f1a8f4f, 0xdc6a6d18, 0xc4249e1b, 0xcc4f4aaa, 0x9f53b04e, 0x1700ce65, + 0x7f097bff, 0x6618a70b, 0x0c461dfa, 0x0c367a76, 0xe2f57807, 0x6cf01aed, 0x923b16e3, 0x1e6dabd3, 0x8e80454f, + 0x9293ecd8, 0xfb1fc670, 0x2c3546c2, 0xb363a05b, 0x3eb489f9, 0xcca4d866, 0x283c4b13, 0x7c5d422e, 0xba3b8730, + 0x9d8627ac, 0xb84c625b, 0x4fff9091, 0x3b5f3903, 0x755bc48c, 0xfd3849f2, 0x3f5e1621, 0x2c1bd00f, 0xa21d7dd4, + 0xade92e01, 0x440588ab, 0xda9220fb, 0x5e36dbc2, 0x90fbc028, 0x97e31b57, 0xda3c53f7, 0x0e9768bf, 0x53052be5, + 0x47882206, 0x4ad59013, 0xf285fdfb, 0x871b7db8, 0x4d5ddf35, 0x8b4a33bc, 0xea0c6ae0, 0xed38e3e0, 0x588fe260, + 0xa88c1d71, 0xc0d0d913, 0x34fadc24, 0x63b16683, 0x3739ff85, 0x4c9503d3, 0x7d69b280, 0x44d74d52, 0x7ef949ca, + 0xf689b948, 0x87e4209d, 0x865fe908, 0xc5e8aae8, 0xf0be91f1, 0xd7fa2b85, 0x10d7a644, 0x51b967da, 0xad668448, + 0x0223559c, 0x43fafb4a, 0x53229d19, 0x3f5ff15a, 0x8d8c4084, 0xd811a876, 0xad91363e, 0x8bd0fe0a, 0x6ce2c015, + 0x9b234855, 0x5de8995e, 0x7c78bd58, 0xb6ecf906, 0xd696a503, 0x0d01e735, 0x44fbd5b1, 0x0493f3f1, 0x17851988, + 0xadb0b43d, 0xfccb0272, 0xcc63065d, 0xcd5b3247, 0x25402bff, 0x8a58414c, 0x88e000e4, 0xeab1ce31, 0x9bff0bd0, + 0x39d2fb13, 0x0196fe04, 0xe0c405a8, 0x71ce34d5, 0x3d1581d4, 0x153a89df, 0x99977245, 0x47ba0abf, 0x6b03b179, + 0x153f2853, 0xeecd2d2b, 0x08245601, 0x4a628e25, 0xc15fae37, 0xa60e4e36, 0xa2189c00, 0xc5b4e6de, 0xcacc37af, + 0x35d13ca4, 0xf5106d28, 0xc2e014ac, 0x2be40b9e, 0x3c5671e2, 0xb2bce0e3, 0xdb3935b1, 0xa9f831f3, 0x2e179d13, + 0xfc94ebbb, 0x7cb728d1, 0xda828b47, 0xc9f65070, 0x0164bce9, 0x2b1ab6a4, 0x7ff31a47, 0x1449eb1b, 0x80d8dd67, + 0x61282a80, 0xb6f7bd83, 0x49dc5278, 0xd506b470, 0x19ef972b, 0xb2eb593c, 0x73776a49, 0x06c8d4c9, 0xd9012135, + 0x6e30df17, 0x7386af56, 0xecc7bed5, 0xbf4abdbd, 0x4f104b0c, 0x68b0eb5d, 0x5d972648, 0x82a77059, 0x2d42bfef, + 0x128f6b6d, 0xaeec4217, 0xa19433f7, 0x062878fe, 0x9a6854d7, 0x02d1dd77, 0x4583abc6, 0x23471039, 0x2bc9432b, + 0x5218be6c, 0xe2c7cb32, 0xfc0d31b2, 0x12310b3b, 0x76b95bc3, 0x5acea766, 0x1666d837, 0xac6e4d9b, 0xabc8b7b2, + 0x1e2dbe3d, 0xa46dfc66, 0xed65ba57, 0xf82093dc, 0x0cb579bc, 0x0c53685f, 0x605fa2e6, 0x3d6fb2a9, 0x683d6162, + 0xd28fea56, 0x07dc7828, 0x79f1ecb5, 0xd845b3ec, 0x92125b4a, 0xbd4a9b60, 0xbda83d8a, 0x285d5d64, 0xc2a1978f, + 0xbcac7beb, 0xdc1cbf78, 0x703d683b, 0x81ec6127, 0x1483c7ef, 0x2eba9383, 0x32e81dc3, 0xc1eccd79, 0xecf4cee3, + 0xa3acd342, 0xebada454, 0xba4cc4d9, 0x72b3fcfc, 0x89016571, 0x247128fb, 0x70514180, 0x86128009, 0x381204cd, + 0xd65bb9f8, 0x5ccc6147, 0xa4159178, 0x0ab93ab0, 0x91c0175b, 0xc45697ac, 0x6f062063, 0x17486905, 0xf1034314, + 0x91ce0462, 0x09fa7de5, 0x5bf03a40, 0xe834dd36, 0x27b485a2, 0x965856a0, 0xe4328f34, 0xefd271e2, 0x4010923e, + 0x098ece14, 0xc9c0d14d, 0xe7ae30cc, 0x1d8c2301, 0x8ffc7bb9, 0xd3bbdd95, 0xa5560103, 0xdb5b4205, 0x8afeaea0, + 0x6af6664f, 0x04bfcd85, 0x7d8316f4, 0xe2a55fd1, 0xf54b8e9e, 0x64209710, 0x30cf2c94, 0x268063dd, 0xf618ec9a, + 0x1076b85e, 0x4a9bd19c, 0xc837c601, 0x1a0f22d3, 0x216ad49f, 0x907dcf55, 0x1364f235, 0x742e1447, 0x9b5b0a91, + 0xb61a890f, 0x911a75f4, 0x69671ba9, 0x5ff2126c, 0xdec68beb, 0x333cce77, 0x01903caf, 0x4e81412f, 0xe7a6c814, + 0x426638b9, 0xe2433a57, 0xb296717f, 0xef76e00d, 0x22b67aea, 0x1680caf4, 0x87d7d12c, 0xcd4cf8b7, 0x1b2647ff, + 0x3d32d294, 0x10aad7f1, 0x23ca786e, 0x685d608a, 0xcd369ecc, 0xb0600bb1, 0xe7096e2b, 0x5ec9c6a3, 0xe02c152a, + 0x469be139, 0x4dd03a6d, 0x2d1e4801, 0xff585739, 0xe50cf028, 0x5680fba5, 0xb4fb945f, 0x6065c5e0, 0x7b576952, + 0xdd38dcca, 0xa1605eb1, 0x30fba64f, 0x4f333701, 0xda809644, 0x2b3c5aef, 0x4d7b3d0d, 0xc309b7da, 0x6578047b, + 0x4a875056, 0x9f2e8005, 0x6202fbaa, 0x2505eaaf, 0x9e7547a3, 0xe625c103, 0xb5b0b3eb, 0x791098b7, 0x55818f30, + 0xe3507fd7, 0x6060ea8e, 0xa688da3b, 0x26b4e175, 0xef1ef174, 0xe4f78f4e, 0xa9f57c91, 0x080504f4, 0x99ea074d, + 0xf0132606, 0x54bfba33, 0x4429d8a4, 0x9d84ab0e, 0x11f35d11, 0x46a805a6, 0x448e16ed, 0x19668328, 0x421d8db7, + 0x5bcb20a7, 0xe8e65eaa, 0x6a65873f, 0x4f86411b, 0x87dd0573, 0xa23ecde1, 0x712861cf, 0xd8215a6d, 0x491edd21, + 0x8e67c64c, 0x542b4939, 0x1078b189, 0x828112ec, 0xdea6367d, 0x7f0b761e, 0x6fd17003, 0x86335bb6, 0xb2a0571d, + 0x2134138e, 0x33229266, 0xb489ba00, 0x650cbe3c, 0x12fced9e, 0x3cc9091a, 0x0b61fd45, 0x6a999371, 0x72722cfb, + 0xc8689497, 0x67e9034c, 0x2e83d919, 0x4e71fec9, 0x8adf9122, 0x07d2bb0d, 0x036f940b, 0x2c5ac35d, 0x1e34a213, + 0x632937b5, 0xf10be63f, 0x47ca5489, 0x55456807, 0x31a70f42, 0xe2ddd560, 0x0b748d55, 0x0b3d8c03, 0x0058045e, + 0x9a24e0d5, 0xf40fb3e4, 0x14922044, 0x404278c2, 0x3969c99a, 0xa004607b, 0xfe494c8c, 0x7cca9d8b, 0xc636f23b, + 0x0846ba3b, 0xadde8f2b, 0x9f15e76a, 0x8e465c89, 0x349b3d62, 0x8a9ce74c, 0x39e44655, 0xf8886f3f, 0xca7839c4, + 0x60f4938b, 0x027305bf, 0x48366ffd, 0x5304f96b, 0xabf88f51, 0x6f0aa3c0, 0x063cff66, 0xc37ac140, 0x598044ee, + 0x8f27b75e, 0xb6fce04e, 0xf3cfebae, 0xeab2c204, 0xb93df5b4, 0x0d33a2e1, 0x00adc955, 0x905948d1, 0x6bef128b, + 0x5a111592, 0x99f1f55f, 0x3edd925a, 0x22964842, 0xbe75ea53, 0x526ade15, 0x214e33fa, 0x3f2b25f5, 0x474c802b, + 0x6d9e41cf, 0x938132fa, 0x7f5bb5d9, 0x64f6e871, 0x041cedd3, 0xc9782112, 0x5da1869f, 0x048b8fd4, 0x3fae8105, + 0xd6de525b, 0x4d0d9934, 0xfc76e974, 0xc44f8839, 0x37e86500, 0x9f58d865, 0x1020a026, 0x6c922096, 0xce60eac5, + 0xa32fdd17, 0x92e91f92, 0xe27924e3, 0xe8daf02a, 0xa456fd59, 0x37e236d4, 0xe91448bd, 0x393c920d, 0x008ed099, + 0x0780ee7c, 0xde25ae27, 0x04d05a83, 0x1a8b8716, 0x5cbeff1e, 0x6d5f4db3, 0x4f8a033e, 0x79b71ccc, 0x52f98c5c, + 0x59c8b35c, 0xef5b038e, 0x8e5095d3, 0x24177ed3, 0x4310db9a, 0xbb96b3b5, 0x570ef7b5, 0x903f7e54, 0x09005a28, + 0x32ef6cdd, 0x71909399, 0xa2385b31, 0x23ee1b94, 0x1b58d3da, 0x1d5d7670, 0xdd939dcb, 0x5deedefc, 0x459de6bb, + 0x5973e4b8, 0x120fabf2, 0xd6c32f4e, 0xdae378cc, 0x94f51e14, 0x5c9ee5af, 0x175ceab5, 0xab6a9877, 0x2adcfd0b, + 0x68319ee8, 0x6b6da38c, 0x002e93e7, 0xc14961c6, 0xc291b574, 0xf0be4b5e, 0xc303da81, 0x21852ca2, 0xea5d40bb, + 0x45365d0f, 0x63808b99, 0x8c39d9c3, 0xe42f80c9, 0x097d8a01, 0xf10e92c4, 0x88f505e0, 0x95e8c2a2, 0x7e09e38f, + 0x30f5188c, 0xab3ca69d, 0x9c65c4be, 0xa54daec9, 0x8003f5b1, 0x69c0e943, 0xbfce4834, 0x66215075, 0x26948097, + 0xa3fc099f, 0xed269992, 0x1fb70d6c, 0xd2f37299, 0x946e87f9, 0xd668dee5, 0xf19a8f55, 0x5a5c3a5c, 0xfeb34b70, + 0x19f0c794, 0x0f769cd6, 0xf02b94e5, 0x8f265d3a, 0x80ab7f4e, 0x43634a92, 0x3a0c9cf5, 0xcbc7e8be, 0x81212d2b, + 0x1daa708a, 0xcc619bbc, 0xbcd0fe48, 0x623e2d82, 0x86305e9f, 0x26554f04, 0x2d89783c, 0xb7225271, 0xb1ce9cef, + 0x99d02ca5, 0x95f1a190, 0xcf427869, 0xa3af13d8, 0x505ad1bf, 0x073a0d65, 0x8b1900e7, 0x4891a08a, 0x10508f32, + 0x0e59908a, 0x556e2f40, 0xc2a251a9, 0x3fd567bf, 0x275607b9, 0xfbea926c, 0xaa3bf841, 0x47c03a06, 0xbe6e318b, + 0xa68b092d, 0x24ba6f9d, 0xec867089, 0xdda0037d, 0x6fcdff32, 0xb49a94af, 0x38ece5cf, 0x0a7833e2, 0x6bf07ed1, + 0x0da4ad49, 0x33bb16fd, 0x4e9fdae8, 0x3dc86f97, 0x45da9e26, 0xcda118e9, 0xefadefb9, 0x93d2c1b4, 0x528e2162, + 0xb9b0571b, 0x0aebbc48, 0x115e418f, 0xe8a031be, 0xdb6e285a, 0xbc0fcb4b, 0x7edafd65, 0xf4ad69a3, 0x47a9495f, + 0x2adf04a1, 0x092208e1, 0x6e75b3b6, 0x2528d71a, 0x62bfe300, 0x182f9309, 0xdbf66857, 0xf40bcfd0, 0xa6048eaa, + 0x57d7495b, 0x14209968, 0xdf7e6564, 0xc932c6cf, 0xd194ffac, 0x37f9109c, 0x56404705, 0xbada3c76, 0x3ea22ed6, + 0x69224fb4, 0xe25ffdab, 0x60820e92, 0xbc96b556, 0x469121d7, 0x175f47c6, 0xc055ecb7, 0x2f272164, 0xdaa3670e, + 0x3038de05, 0xddc575b1, 0xebe1da2c, 0x177e1584, 0x8bdbad06, 0xf3358f3e, 0x43e2ba0d, 0x0b7a08ee, 0x892e79a5, + 0xa6a563b1, 0xb7f56738, 0x05fcbc9d, 0x978c3896, 0x33c7972a, 0x2722c0fb, 0x1a02fd7e, 0xe279d407, 0x955bdc55, + 0x48bc2c64, 0x2b8a5c04, 0x8de19d30, 0x83db014b, 0x41f47212, 0x0253c047, 0x04ffd7d8, 0xce6152a7, 0x54401ec4, + 0xe7034994, 0xe2e76b0d, 0x7fffe072, 0x51e6514c, 0x61868bde, 0xed854d04, 0x98ed6a4a, 0x13a050ef, 0x81d5b0a0, + 0xfdf847c1, 0x90b3f8ed, 0x9a752212, 0x4131a329, 0x907449b6, 0x71757e66, 0x6205996f, 0xc60e05a6, 0xadbff0df, + 0xc3568ef7, 0xc6ceda07, 0xd0a527ca, 0x497e607b, 0x3733d498, 0x6e40bca4, 0x36169f1e, 0x9aac75a3, 0x8ea5ffec, + 0x3f0f8dcb, 0x2b8e1c8d, 0x3902b210, 0xd6a0c9e2, 0xcee39db5, 0x530d3702, 0xde6de029, 0xf01be51e, 0x4b342c1a, + 0xecb5b5d8, 0x601fbf59, 0x4a377dad, 0x98dba8d0, 0xd9c6297a, 0x37d20016, 0x3f5def8d, 0xbbe71153, 0x4d8023fb, + 0xfe2bc446, 0xd729ec64, 0xfca88d40, 0xdcb0188e, 0xa331c0b3, 0x81cffea5, 0x60240846, 0x033541b4, 0x560c8daa, + 0x9cde1a12, 0x3d46a462, 0x39ecaf3c, 0x201167e6, 0x0e26f58a, 0x8ed185dc, 0x84eccc8c, 0x413d4da6, 0xcc064971, + 0x4a564884, 0xc3d4528c, 0xac139582, 0x7c3291d5, 0xbad773e0, 0x53602aee, 0x3ea6439f, 0x64b2a63e, 0xab16dae9, + 0xed030d36, 0x74d4d25e, 0xa1a0962e, 0x7213df5e, 0x9bb8482f, 0x380108c0, 0xc27278e2, 0xe571093e, 0xce7556c5, + 0xe36f78da, 0x105f1551, 0x22049adc, 0xf59d43b2, 0x17ffd809, 0x824987b5, 0x3a159a8c, 0xb3363d6b, 0x0e93cef7, + 0x6a5651e2, 0x38d11719, 0xd230874e, 0x7f8b9d29, 0x7a52c233, 0xee8fff6d, 0x88f3a868, 0xa6149a79, 0x64f6751f, + 0xeda9504f, 0x54bd1215, 0x2274ebef, 0x7e05f2c4, 0xc39ae26b, 0x57b0e1f8, 0xf87683c4, 0x6b7dd76f, 0x41ae7a13, + 0x26c972cb, 0x3bfada75, 0xb2d8bccf, 0x5fea6a6d, 0xd33b8d91, 0x277a65ac, 0x119b52b6, 0x8ee287a1, 0xf1df9c07, + 0x1fa96209, 0x8cda02c3, 0x53f6d156, 0x5f3a3d2a, 0x69ecb361, 0x571e547f, 0x313000bb, 0xa2d72c38, 0x4192b702, + 0x9fce34a1, 0x792b85f4, 0xb311f244, 0xdc5251e1, 0xb2415377, 0x3f48bc68, 0xb1687a77, 0xe2bdd6b0, 0x2d4f020b, + 0x1a777ff4, 0x922366ae, 0xb4f790e8, 0x0c802c39, 0x8a2e2fc6, 0xe6a11930, 0x5c672b41, 0x81488aa7, 0x979c1617, + 0x0d8c1b3a, 0x16c364d9, 0x2b850e78, 0xe3d1a0d9, 0xe7c9cdd0, 0x7db1ea32, 0x388fe914, 0xc3c7cd46, 0x033a7b37, + 0x892a4dc7, 0x71fbc72c, 0xd7454867, 0xcb5f3578, 0x4fa1eef6, 0x16499f51, 0x1a065575, 0x7912ebaa, 0x0c7b8620, + 0xfcd54788, 0xd2f19f7d, 0x96cb701f, 0x314c78a5, 0x72cdee52, 0xa79c87ab, 0x98fa5886, 0x1c814879, 0x9ffb2233, + 0x0bdd91a5, 0xfe055de3, 0xa67896d6, 0xc8ceb2a6, 0x61079bfc, 0xa90b6043, 0x09ab56c0, 0xa0b8c7ee, 0xb7a1ef7b, + 0x521cf670, 0x39f0043e, 0x61862131, 0x2df4cee7, 0xa8c6bf51, 0x2acbfb09, 0x7108d19f, 0x28b487f5, 0x697143d8, + 0x0d30ebb3, 0x3f753705, 0x718f6af2, 0x7d2e3ca9, 0xd2afece7, 0xcec22826, 0xd5611ba9, 0x89ec4d57, 0x2a49fa90, + 0x2610887a, 0x5fabd5f5, 0x79c9db2d, 0xe3dec300, 0xc2fdf2db, 0xd0fb87e3, 0x904c32bf, 0x0544cf93, 0x22b9f0a5, + 0x2a8d7050, 0xe4111236, 0x9f1a6f5e, 0x7a55bfd3, 0xb1e877eb, 0xb5a7486e, 0xda9ffa1a, 0x96e097c3, 0xd84e8d3e, + 0xea2361c1, 0x8ed65b43, 0x0a226956, 0x80bd3c76, 0x8e60be61, 0xdcac1f9a, 0x2cc14355, 0x8791b7dd, 0x9a83f5ec, + 0xe6a86b4a, 0x56c31aba, 0x81bbb4bd, 0xa8b16a62, 0x80667602, 0x5b17c119, 0xde1ba38e, 0xe14df593, 0x660d29a2, + 0xeda5a540, 0x179cb507, 0xe7771e7d, 0x1af13cee, 0xa7a18e49, 0x6184638d, 0xf31c5e68, 0x9562c0e5, 0xcacb008e, + 0x8f933965, 0x27aba69d, 0x9ccd4338, 0xd04382f6, 0xf86652cf, 0xce843e93, 0x16a2943b, 0x378a0990, 0x1ffaf2a0, + 0x6d55d72c, 0xca7bb018, 0x138b0cbf, 0x49ca2460, 0xe1d9e0fa, 0xd3141c59, 0xa412f83e, 0xe4ee4cb4, 0x0b09f00d, + 0xb9b835c9, 0x0b06daf7, 0xbdba4d20, 0xefdcfc69, 0xcbc9e9d5, 0x8561a646, 0xea7a2cee, 0xbbe4ed66, 0xe0d44121, + 0xc105b622, 0xb86e83e7, 0x7f935e71, 0x3309f51d, 0x3ddec126, 0xb5d607de, 0x5fef801c, 0x09c40629, 0x948df952, + 0x63572e40, 0x701185a0, 0x669f9035, 0xe351bc29, 0xe004e8b5, 0xe7f8559c, 0x2cbaf528, 0x43c1f3ed, 0x92f7f336, + 0x39e627af, 0x7e7a8422, 0xc108861d, 0x4da407c1, 0xdc19e290, 0xac7e1ef9, 0x5a78b534, 0x0e86eea0, 0xb31e5a16, + 0x9d7b4326, 0xb37fd561, 0x194531f5, 0x66ae730c, 0x784a63c9, 0xd6d83d53, 0x57227b88, 0xeb8633c0, 0xbb5d1760, + 0xe4100859, 0x28615218, 0x324df218, 0x29283197, 0x5109104e, 0x0adbd0ce, 0x3cacf797, 0xd7484c51, 0x30491c09, + 0x936ac562, 0x191ffa43, 0xae7e2085, 0x435e0188, 0x3afa7fad, 0x9b9e5640, 0x72f961ae, 0x36e20886, 0x9e486527, + 0xfa73f455, 0xca4f51f7, 0xe033d6a6, 0xee02fc72, 0x8c6c44bb, 0x47a7a5f9, 0x7d84a0bb, 0x7f5b434b, 0x34e9944e, + 0x9f4ca9aa, 0x35b672bd, 0xf8ed095b, 0x46e27710, 0xebaa8772, 0x2186c9a5, 0x3516775c, 0xe9e8003a, 0xf35d28ea, + 0x1b5bb130, 0x823233a8, 0x006e4a6e, 0xb3de1bb3, 0x16ca9f11, 0x1010b13d, 0x147be80a, 0x3f317bf7, 0xa0f196e5, + 0x8b6174bd, 0xa18a6900, 0x0c006e55, 0xe869592d, 0x3ac1db45, 0x569dcd28, 0x8082ce83, 0xa1f2ef36, 0x7ae378ad, + 0x526a3c0d, 0x30e6f1c8, 0x4697f9d9, 0xdd67751a, 0x4205d4e1, 0x0331361d, 0xb0f98a95, 0xf34051da, 0xd4da48b9, + 0xe368dd75, 0x64a8067b, 0x46602632, 0x674efd97, 0xa3687602, 0x4e36eefd, 0x854856ec, 0xc968aaaf, 0x10e6b028, + 0x0138e373, 0x1488f8a9, 0x3b8c8a64, 0xdf080b37, 0x60d306e4, 0xa5f1ffab, 0x1a2b5798, 0xafd782e9, 0xb77f6fde, + 0xbf3eb5de, 0x1c824bbe, 0xb5976857, 0x0a3489ab, 0x551ed030, 0xb15cd92a, 0xa8b94502, 0x380358fb, 0x88afbe84, + 0xaf735f36, 0xb64641f6, 0x7bac0855, 0x8c003d2f, 0x6f1ff39f, 0xcef9551b, 0x3ccec097, 0x8ddedb40, 0x25407842, + 0x3a75a0c3, 0xe689b486, 0x66868c7d, 0x610a027e, 0xf2c7be19, 0x34561c0d, 0xeb286989, 0x1f0f4a8a, 0xb427d40c, + 0x36827bde, 0x39991598, 0xf8d2080f, 0xd93f1b77, 0x062400ac, 0x58aaf6e3, 0xa08c5982, 0x80521311, 0x00e53621, + 0xea01248b, 0x82d283a7, 0xbca601c2, 0x601b6cd7, 0x0dfc08b6, 0x201f78f2, 0xb43299ac, 0xb1239c9e, 0x1df04e0f, + 0x5019c81a, 0x83933676, 0x914ebcab, 0x84ebd81e, 0xba73eb0b, 0x11d58d49, 0xc3130fd7, 0xcbec2920, 0x15d0adf4, + 0x0874440f, 0x1ef60efe, 0xb4801ab0, 0x0c4586c4, 0x6d48af3d, 0x0f6610e7, 0x57a6f635, 0xf3f9e4f4, 0x2cb7091f, + 0x446fe0eb, 0x91c1f437, 0x92328934, 0xe0b51c75, 0xd3982aac, 0x601e65d0, 0x0b67ec42, 0xaa1a1f94, 0xf4a618b8, + 0x2fb11ead, 0xaef5d9d5, 0xd20e1a32, 0x370bef95, 0x560d64f0, 0x822adf75, 0x9034b59e, 0x8a3e40ed, 0xa1169887, + 0x4bd129bf, 0xa55f9fc0, 0x28b35a51, 0x2121b8e8, 0x6a4f83e6, 0xb8d1fe74, 0x5a998399, 0x1cd13edc, 0xd6457652, + 0xab62b9fe, 0x20c031f6, 0xfa65ecc6, 0x856c53a1, 0x604acd30, 0x0158f1cc, 0x0791a9a3, 0x86e0ce0c, 0xd3630614, + 0x7af779cc, 0x4f88fefd, 0x06f60073, 0x1d530463, 0x04f7d08b, 0x4573e350, 0xb4d43717, 0x839d3456, 0xdb292609, + 0xdfa0df54, 0x5a36906d, 0x73e4bb02, 0x12056c29, 0xaa4a2f76, 0x169b8fa3, 0x4a79f27f, 0xdd2bd201, 0xa61db1d3, + 0x146379e5, 0xd3865943, 0xb1197458, 0x1ece3e77, 0xd4bd2f36, 0xaa24c54e, 0x741d3424, 0x34614a5b, 0x50de7b00, + 0x32f3ff2d, 0x3f55c2f3, 0x6c9a9442, 0xa999ca91, 0x83ef7136, 0xc09423e0, 0x7926c465, 0xcc79c4fd, 0x25803a39, + 0x4e847258, 0x6ba4d388, 0x26480e46, 0x450d2de7, 0xfab722e5, 0x45532754, 0x47bd4370, 0x0368f598, 0xcc285741, + 0xf5c2a103, 0x356ba14a, 0x93ec9bda, 0x11254455, 0xbc644353, 0x27f8a856, 0x49f4b58e, 0xcc3a975a, 0x3ef2a22e, + 0x324a9ec4, 0x54f3aa55, 0x2d24f6d0, 0x01cf40b7, 0x13ebd1a4, 0x5fc4d31e, 0x311a4e73, 0x61e38494, 0x9eb874b3, + 0x41a4624d, 0x057a089e, 0x04bd8d24, 0x2729c8cb, 0x0e05f149, 0xaf4ac150, 0x4bd14deb, 0x5fe5335a, 0xca8000d0, + 0x4e71306f, 0xfc71b181, 0x715b8a15, 0x82ec34c4, 0xbe33ff30, 0x0c498c78, 0x8b60b3eb, 0xce3e8454, 0xffe53395, + 0x2be88a84, 0x62e47f99, 0x3acfafd4, 0xb62cc9d1, 0x2d083c68, 0x9feb789d, 0x15512c8a, 0x50bc437c, 0x304315cb, + 0x2f486bb9, 0x095a97b6, 0xb073a67b, 0x3cb58873, 0x0464c863, 0x6f98675c, 0x45b974c1, 0xa84df183, 0xd255fa1a, + 0x8d54d42f, 0x51521e83, 0xc71d9442, 0xd4d78f3f, 0x872e7c65, 0xb8d78d5c, 0xbecd15ef, 0x993a9d69, 0xf7ee281e, + 0x3d0b1714, 0x94c20ab5, 0xd5b3e30f, 0xb4f6dfd2, 0x7f84f591, 0xd337208d, 0xe9581409, 0xad20e9d1, 0x957b8d8f, + 0x8709dfc2, 0x2bf95eea, 0xed188796, 0xc80be35a, 0xe8270aed, 0x0a6e10fc, 0xd612650e, 0x4a7ed2be, 0xe4a1f5d5, + 0xeee16bcc, 0xfa81607f, 0x23eba027, 0xff2a3051, 0xbaf6ca6b, 0xe3e17126, 0xcf63819e, 0x56de5cc3, 0x6d0d582e, + 0xc6039d38, 0x298b4923, 0x79fdcbe0, 0xb9b1eeba, 0x742c8dbd, 0x8944b447, 0xe2d7390c, 0x489fd869, 0x4b1de55d, + 0x397f0228, 0x83385ff7, 0x84345148, 0x3daa57e3, 0xca97db55, 0xb03ba5a4, 0x98714064, 0xf57dea18, 0x3ee71c8c, + 0x55388c4d, 0x3d56c0e4, 0x4ba9d644, 0x5cdd0d4e, 0x1edf6bc9, 0xc6eba0f1, 0xd6f3dc6e, 0x94784fc4, 0x5dde47c4, + 0x0c72ad0f, 0xece9d696, 0xd542592b, 0xa4525997, 0xef319caa, 0x8fe4686e, 0x2ceafd99, 0x0969f983, 0xf9941d1e, + 0xbf552d41, 0x04615906, 0xdc8b3f2f, 0x884728ae, 0xb485d406, 0x44dc34fb, 0x17576900, 0xd33d0c48, 0xeeed79c4, + 0x23a3f4af, 0xb68b0bf8, 0x8003c4fa, 0x35c87612, 0x23bf7022, 0x21ed84e5, 0x0d85985d, 0x774bbe28, 0xa7667f12, + 0x1689194e, 0x4b70cb7a, 0x623b1744, 0x23393a73, 0xaa604078, 0x7d71f237, 0x945984c3, 0x666b758d, 0xcd061b81, + 0xcc06ffa9, 0x71c158c1, 0xf4342754, 0x5d53773a, 0x1c0b0b6a, 0x4cd5b60c, 0x881c0836, 0x4b9ec430, 0x0099cf5d, + 0x217773c7, 0xd6ed09dc, 0xdf58ab71, 0x6dfaf873, 0xf1ad2a3d, 0xb3638699, 0x2bbfdd2c, 0x50ee5035, 0x6a3b22fe, + 0xddc981b7, 0x232aec97, 0x469078d1, 0xb5aa25f4, 0x257fd683, 0x6eaf47ea, 0x85a4d544, 0x955b3047, 0x9a00ae31, + 0x52410a41, 0x4bb0db3e, 0x6fa6d5b1, 0x3ec110b5, 0xe729e4db, 0xdd8798db, 0xe65989c8, 0x3a2e55c8, 0xb89d9b89, + 0xfe75fd55, 0x3238a201, 0xb259b08c, 0x6e502f87, 0x9775b5b8, 0x4e6a53b5, 0xc266b10f, 0xa885b0d4, 0xf7e0968c, + 0xfcfb8fb7, 0x9171cce1, 0x20ce0f71, 0xb0d90b2a, 0x99752864, 0x1d4e0082, 0xa5e3f99c, 0x973a9bec, 0x9934774c, + 0x2748a25d, 0xf54a8edc, 0xa8624229, 0xb6017711, 0x35387aae, 0x8c0f65ad, 0x5ab5ae94, 0xeb1e0f46, 0x7adf65c6, + 0xc7a81ff1, 0xaffdb249, 0x38393f32, 0x0b4657ea, 0xb6931157, 0x5894e307, 0xf4ceb0e6, 0x4a68dcb0, 0x0889085c, + 0x239cec98, 0x29bb1271, 0x5dcb280f, 0x5783dae6, 0xc37c28d6, 0x3bbb74f8, 0x87c3d45b, 0x08e58f03, 0xf9d20979, + 0xe1e62b45, 0x400f0abe, 0xb3fbb042, 0xaacb8b04, 0x8245ad11, 0x353e4ff3, 0x6e9860f6, 0xa011bfba, 0x4bb452bf, + 0xdebbdc54, 0x01740178, 0x8dcd78af, 0x468b9167, 0xe564907e, 0x182c7653, 0xc3e235ae, 0x7a11f83f, 0xdf3ec004, + 0x07b04bef, 0xfb45d138, 0x5f382329, 0xd606d691, 0xbf139251, 0xadeb6ec3, 0x10f1e3dc, 0xa5e21a54, 0x336a4a95, + 0xa3537c9e, 0xc513888b, 0xb136e867, 0xdf2b9fc0, 0x41e14f8a, 0x65225be1, 0x890b98f9, 0x4090b3e8, 0x22f20090, + 0x9b96d305, 0x080066ea, 0x8f039ff2, 0x79575865, 0x15096ebb, 0xe6b8dd22, 0xd40fd3a3, 0x984cc50a, 0xeda9100e, + 0x8961f2e4, 0x74dd413e, 0x11219690, 0xe8e6c911, 0x1ec5d683, 0xfe5ebb9f, 0xb4432a75, 0x887077bd, 0x7b8c32e3, + 0xfa5380dc, 0xab556c7a, 0x762c4fd1, 0x3321c5b2, 0x23bfab8e, 0x431025d6, 0xa5bff456, 0x28aeea93, 0x5faef434, + 0xd33effb0, 0x924bc9e6, 0xa337631d, 0x61259e76, 0x9c1ab386, 0xdca14318, 0x7d44dfef, 0x548f58dd, 0xe63364c6, + 0x6ee8c4bf, 0xd75145c8, 0x9e4775ad, 0x7790b24f, 0x60645ff0, 0xaad6037c, 0xeb03f79c, 0x0cc414ce, 0x2304bd20, + 0x44585657, 0x8ef4b271, 0x15c2b00e, 0x6be8e7e4, 0xd925375b, 0x3ef6913f, 0x441a966a, 0x2393a779, 0xa73f3faf, + 0x17f853eb, 0x62aead02, 0x0494d69e, 0x15034d88, 0x4ea5e91b, 0x81f6e63b, 0xba7a09c2, 0x6acd313f, 0x615a8bd3, + 0x3e7cf85f, 0xf187c718, 0xf05864bc, 0x5ca32ab9, 0x80e5e9e9, 0x43bcbec7, 0x718858d7, 0xc799c181, 0xd0a5d173, + 0x6d67d701, 0xcc7d9351, 0x46a28d3f, 0x243cb882, 0xb4d6cd08, 0xf84bd949, 0x5f046335, 0xd8000363, 0x3e7f7362, + 0xb879c88e, 0x57c6b92e, 0x7bb7e940, 0x8719e9ca, 0xfe548683, 0x052d43d6, 0xe943bc48, 0x1a53f208, 0x9ea15e09, + 0x2330e84f, 0xe08ae6fe, 0x2c07e05c, 0x283d3cd9, 0xcd6aa267, 0x39fef78d, 0x80556f4a, 0xa8be433b, 0xb24751a6, + 0xf43f7932, 0x038f3866, 0x0fdf0d04, 0x13a9d3c1, 0xa904b4b2, 0xa2810a7a, 0x82d0565a, 0x9ca64169, 0x2dc2a9ed, + 0x794ca2d5, 0xe3ea762e, 0xe02b91d0, 0x6b446b4a, 0x87a0a546, 0x8ed35719, 0x6bd81838, 0xb4b83ade, 0x97db5f5f, + 0xa5a7b89e, 0xd69221af, 0xd6851042, 0xe6d49412, 0x44def605, 0xd05e3b12, 0x7ca65f33, 0x7903768f, 0x0a54d75f, + 0x4456dba5, 0x8c137845, 0x6eae1acb, 0xc797ed3f, 0x8d7e6020, 0x585c0de0, 0x4e6da15b, 0x8b987620, 0x81c1fb3d, + 0xdb1046f4, 0x79e206e4, 0xc7a54a87, 0xa2ccc9b9, 0xab5ca778, 0x38455ee6, 0xbce17f41, 0x3725b9ab, 0x1bb34677, + 0x9beece84, 0xcc24a0aa, 0x596e27f7, 0x55b31b3d, 0x06a029f9, 0xab7932cc, 0xfb3f9a7c, 0xfc66823c, 0xa80481bf, + 0xfdb1b3b7, 0x685d063a, 0xa1ba14f9, 0x70b96d41, 0x8a742e35, 0x9c4c9b66, 0x9af350f8, 0x949faa7c, 0xf41d4e78, + 0xa6f12a12, 0x124d7353, 0x160620fc, 0x139567a0, 0xb2d4c901, 0x5450c2b3, 0x0bb5780b, 0x4a7ff01f, 0x28f38f4a, + 0x1d246067, 0x197be9f7, 0xf0632b59, 0x8ebd179b, 0x4ebfe116, 0x5bb8184a, 0xaa57bc72, 0x3852300d, 0x42a76203, + 0x158b4bac, 0xf43f1ff7, 0x8aeb116b, 0x0157d541, 0xfc506d09, 0x7a551d07, 0xc15b8bea, 0xf4321318, 0x5ce487b9, + 0x639e782d, 0x1a3c3c27, 0x09b6e864, 0xd2b403a8, 0x88db3d42, 0x20aad341, 0xbb49f38b, 0x6c15670b, 0xd50a1533, + 0x6be22a86, 0xbcecb876, 0xb659ec56, 0x851bc75d, 0xf9732b6a, 0xbf0d53d4, 0xa1362723, 0x1563ab0c, 0x08410984, + 0x6b42d659, 0xf75da53d, 0xfcc37d0f, 0x099d1722, 0x9aff8ac3, 0x6633c145, 0xb453b3aa, 0x779a1d39, 0x750488ad, + 0xc2de2166, 0x2e56333b, 0xae64c7d4, 0x4444a4a5, 0xd3e72b3a, 0xbb32e737, 0xa2c14428, 0x09650932, 0xee9031ef, + 0x47109f3d, 0xa43a472f, 0x237133ea, 0xaea36cd8, 0xfb56df02, 0x174f2470, 0xcaceabce, 0x7a94318e, 0xe8d15157, + 0x5b25375f, 0x52ed3bbb, 0xeaad596f, 0xa51b7bf6, 0xc50ab940, 0xe25f779e, 0xcd72a998, 0x0a1db786, 0xdab749fa, + 0x475b6dc4, 0x4de91623, 0xfe785c5d, 0x5b49bcb3, 0x5fddb304, 0x1b3f8c93, 0xd82e94ae, 0x96edfe55, 0x8f1c2cc8, + 0x171bef64, 0xbac3e625, 0xa73027ae, 0x9b16e819, 0xdcea4489, 0xd7f14999, 0x7abfa1d8, 0x8409f484, 0xce0000d0, + 0xaa1c1287, 0xbdbefd01, 0xbdeae502, 0xfb989f2c, 0xefc00efd, 0x52c4ca0a, 0x87cbf965, 0xff6ca10c, 0xe9404d86, + 0x9e8dfc5d, 0x394539c2, 0xa4d08644, 0xbef4c156, 0x04fe7820, 0xb19ee216, 0x108ec7db, 0x701ebc70, 0x37a9219e, + 0x701279e5, 0x8df1f1b5, 0xa7cfcfe5, 0x9dfa2815, 0x8af2986a, 0x7f1a8546, 0x52f479af, 0x548f17e2, 0xbd1e6936, + 0x5df0d7c5, 0x25c77f7b, 0x8e04f88f, 0xe25551c1, 0xf75cbb19, 0xcc69bb45, 0xc1223fe3, 0x1f2e25bf, 0x0a69ddb1, + 0x9a58ef07, 0x9227cac0, 0x8832262c, 0xefe3ceba, 0xdfe4d553, 0x4ee84f92, 0x6b8d3233, 0x9702940e, 0x86743903, + 0x9e01d6a6, 0x9a44cd37, 0x61e98ead, 0xeeca2e0d, 0x7b7731f1, 0xecc1cb38, 0xf1a9d7bd, 0x62d55b2f, 0x43daa4a4, + 0xcd903ba4, 0xcf1a9d85, 0xa2af2852, 0x6f3d116d, 0x257a87bd, 0xf5daf9e3, 0xfae5473f, 0x5ab0d7bf, 0xda21e48a, + 0xc2e591fb, 0x1a55486f, 0xc184dfe4, 0x3b2850e7, 0x5f0a6660, 0x27cbc3da, 0x321b0d3f, 0x32c7366e, 0x8a9d5809, + 0xb42714df, 0x0204a26e, 0x2871812e, 0x6462a7fb, 0xd5f289ee, 0x8dbc7dd3, 0xb76a0af5, 0x94095f25, 0xb95adfcb, + 0xcb8f18ae, 0xf17cbac0, 0x2ea3eb39, 0xb135595b, 0x5290badd, 0x23f6d142, 0xaf7eca9d, 0x591deaba, 0x6985b51f, + 0x112573c4, 0xaf3bd6ed, 0x86faa5b2, 0x4af09975, 0x05311077, 0x68f16e92, 0x9832f7ab, 0xbfd9e6c6, 0xa2518ca0, + 0x12a3e92f, 0x1616ddf8, 0xaa5004de, 0x3ea6f276, 0x995a346a, 0x8b6cc787, 0x6d6c4b53, 0x8fb78e2c, 0xe39e6a76, + 0x96c70d5a, 0x8e0aaf97, 0x28c6f5ca, 0x9db882f8, 0xf18c0e86, 0x9fbbeeaf, 0x60d5b895, 0xb2a95260, 0x83aeaa51, + 0xce44613f, 0xa1d6e82a, 0x95a6413b, 0x693e1b08, 0x1363c72c, 0xff2d78d0, 0xc56f3707, 0x073388e6, 0x699f5e69, + 0x03212b11, 0x40f60312, 0x619f5f28, 0xcecbe252, 0x44696d25, 0xec1b29a2, 0xd7cafdb8, 0x4a176751, 0xa2538f52, + 0x0ee58c53, 0x7aa235f4, 0xef3168bb, 0xccfaaa71, 0x1d090f0c, 0x314641e8, 0x7de02656, 0x2e40e6b2, 0x885eb162, + 0x57fd8f68, 0xa37a878c, 0x8ab83ee8, 0xe9eaf1f8, 0xf1c1837e, 0x9bb724b4, 0x955f62cc, 0xc15902cc, 0x2e679806, + 0xcda0758e, 0xfdf6ef95, 0x53f107dd, 0x728cea31, 0x28499d1c, 0xb102a5e9, 0xdc7fa3d1, 0x07cda2dc, 0xebdd885b, + 0xe0b447f3, 0x5a37346b, 0x136e1a01, 0xe32f3ce8, 0x1ef46c77, 0xbc7f3857, 0x40734050, 0xa39bebf6, 0x2777aef6, + 0x30da576d, 0x9527c184, 0x2f9128a2, 0x14c57c3f, 0xdc607ff0, 0x8f84f51d, 0x6277adbb, 0xb1ee5e28, 0xab4612c3, + 0x086b7e96, 0x4016e208, 0x98a69bcd, 0x98afc28a, 0xfe639513, 0xb9aee9f7, 0xd28c3b1c, 0xb0879691, 0xc2300399, + 0x9c3fb7e5, 0xe18bcf2d, 0xf86e4274, 0x1251c13b, 0xd2960cfc, 0x23a332af, 0x602fcc39, 0xeec192cc, 0x80219ea7, + 0xdcee4903, 0xa57066d1, 0x7e5b4b24, 0x2fc10eea, 0x27ccc0e5, 0xdd752b64, 0x0d2dc5b2, 0x91a65809, 0xf5a40f43, + 0xff17162f, 0x62efb375, 0x86eff5bd, 0xdde27ca8, 0x3dbb729a, 0xe75468ef, 0x875b83de, 0x368a9d58, 0xcf895ba1, + 0x51a4e52a, 0x0743eb18, 0x6d906790, 0xcdc1eec4, 0x9faafa46, 0xddef95ec, 0x4a40e1de, 0x0ecd62cd, 0x1270c313, + 0x1b709fa7, 0xe55654de, 0x025a3c71, 0xe3513d0b, 0xb75d960f, 0xbe151d1f, 0x3d691a59, 0x1fe38602, 0x8ec84662, + 0x7c5a68e6, 0x569c18a1, 0x027c1be1, 0x81a294f8, 0xebff9f2a, 0x25a0863e, 0xc0da6a68, 0x4237ed75, 0x4e018d92, + 0xe4cea25f, 0x413f201e, 0x34b9c382, 0xa29b339f, 0x94b52dc4, 0xb07b7aa9, 0x0924cf22, 0x3a869fb0, 0x6ec5a5c6, + 0xe1f9b6f7, 0xa81e91b3, 0x8b1402c7, 0x7d225486, 0xd718059d, 0xfe9d1f8b, 0xb8608e81, 0xc72f723e, 0x1e46203d, + 0xc8770250, 0x12702dd4, 0x360ef6f0, 0x1b17e40f, 0xc9988ded, 0xbdc68b0e, 0x6327da57, 0x5232f51d, 0x6212d859, + 0x09bba1e5, 0xebde6059, 0xb7ff7a9b, 0x0b2aec73, 0x29d97371, 0x16bfad51, 0xaf4573b9, 0xf0658e28, 0x24a56ff9, + 0xecd2f7cd, 0xf57907fe, 0xbe10b254, 0x32d1b08a, 0x9bcb2594, 0x5c5a536d, 0x6266d65e, 0x6265c51c, 0x7209a7f9, + 0xb2425e14, 0xcb43f883, 0x0e813411, 0xb55654b5, 0xa835d411, 0x3ebed4ff, 0xe0c5157d, 0x13189552, 0x7ceb2fa6, + 0xe7bf8242, 0x1e2414e4, 0xd8b7f6bf, 0x89960436, 0x201a18d4, 0x258ad2ee, 0x0e398afb, 0xca6ff069, 0x9d8fa64f, + 0xa98c1853, 0x83fba8c4, 0xfd5bfb43, 0x1fcc54eb, 0x3a056d17, 0xbaf01887, 0xb4137adf, 0xa5c94dd7, 0xd5154bfe, + 0x39b15db4, 0x6f187453, 0x3833c440, 0x7b23df46, 0x8692ef3f, 0x56d52d1e, 0x4e772112, 0x23e91db5, 0xbeb1be6e, + 0xe9b8cc01, 0x6bfc2d87, 0x3ddcc98e, 0xb0bcc6ee, 0xe6e3f094, 0xd64534af, 0xada42a99, 0xf36b1a22, 0xf95fa421, + 0x0d86df29, 0x18e86489, 0xbdee25fc, 0xa4264540, 0x40f2efa2, 0xffcd14d5, 0x1d94a4be, 0xb321f10b, 0x6df7ddfb, + 0x68744902, 0x7b5b518e, 0x02262b43, 0x18a8d8ea, 0xafb97733, 0xfea93041, 0x83834181, 0xaa2418be, 0xee933001, + 0xda5695eb, 0x9d57d082, 0xfae3d604, 0x3221cc2c, 0xa614d7fa, 0xc64d6915, 0xc10263eb, 0x30a55e4b, 0x73610bd7, + 0x1c37734e, 0x5a421298, 0x4ee32f05, 0xb55da11b, 0xbd154902, 0xfe331368, 0x9f511397, 0x77fb7173, 0x548b46c7, + 0xac9f5d48, 0xd6b330f2, 0xc412b38e, 0xc0f5366d, 0xb8fb0219, 0x8acff3b1, 0x7bff4b20, 0x98432020, 0xf21e23d1, + 0x0a7aec2e, 0xd940dab4, 0xc39d6584, 0x3158811c, 0x15498ac3, 0x5726dfab, 0x631af8b2, 0xaa6e38ae, 0xf1c9566d, + 0x8521e049, 0x9adaa34b, 0x2f0a0c16, 0x18a14242, 0x0b33d7e0, 0x56f75253, 0x26dd4745, 0xf6e5f32d, 0xd7bfda14, + 0x1f6bd1a6, 0x9708f38b, 0xb0b4330d, 0xb638fd67, 0xe179bc6d, 0x9261a994, 0x1dd8dba8, 0x057076f0, 0xfac3423a, + 0x5b71a409, 0xcb4e03da, 0x76a0cc6d, 0x174b42d9, 0xdc7061e9, 0x55015589, 0x6313b8f2, 0x7f24cc57, 0x9d235907, + 0xcd9bab66, 0x0f28a725, 0x2bc891b8, 0x09747a05, 0x39ad82c2, 0x3e4e9a68, 0x6e031ac6, 0xff74ac30, 0x0fc6ed79, + 0x286cd3de, 0x381a17da, 0xff88bfab, 0xadda776a, 0xfecb1b49, 0x90fd5871, 0x0fe20cdc, 0x945122b1, 0xf7f74c55, + 0xa9064b4e, 0xca794c86, 0x0c0d7ffd, 0x1cc764b7, 0x864f9781, 0x887617f2, 0x5a0d4865, 0x3c22acd3, 0xf0db5797, + 0xbcfabb1a, 0x0c6f1ec4, 0xe0ad049c, 0x31c871ef, 0x34b221e5, 0x57f3bad3, 0xd381946b, 0xa4ccd262, 0xa9700ab8, + 0x484803c9, 0x15c466da, 0xbd29ec72, 0xc15287fd, 0xefea4dc6, 0xa833c45a, 0xaa41cc1a, 0x270df978, 0x9119c377, + 0x83dcac64, 0x5456afc1, 0xe080498a, 0xc90c9ce8, 0xea2f6bca, 0xf9c748bc, 0x8d7c3aa0, 0x9e27125c, 0xcbf3699c, + 0x47f07277, 0x2d649791, 0xc0fc8f6b, 0x14d1d5cf, 0x706cf140, 0xfb361b66, 0x96eb4de1, 0x15c1eb75, 0xcb6c90bd, + 0xd2d491e8, 0xafbe8a6f, 0x669057d7, 0xaf60d6ba, 0x54641c96, 0xb294f470, 0x3637464b, 0x9dea6fd2, 0x51133259, + 0xc749c5d2, 0xb7afe84d, 0xcc086c74, 0x84890b73, 0x91985fd0, 0x12ec76fe, 0x908a8830, 0x41859327, 0x1f5b96c9, + 0xc4ff2e43, 0xf219cf7b, 0x4c51fa3d, 0xe3011aed, 0xc3a73f62, 0xe5ed0189, 0x439f3dc3, 0xab412f3b, 0x75e92b98, + 0x7ff7c2e3, 0x57bec9ce, 0x5abd2c18, 0x1106abaa, 0xe8d6b3e4, 0x71647a57, 0xa22611bb, 0xe38caef8, 0xdb130372, + 0x8cc21a40, 0x14ae89c4, 0x8044f622, 0xe8ca1eb9, 0x1f52814b, 0xe1c68604, 0xd614309f, 0x13ead90c, 0x99bd7595, + 0x628d68f8, 0x885a2e59, 0x5bba9b74, 0x5edc4528, 0x68d4aaa5, 0x32890f93, 0x1d358d8f, 0x48724266, 0xc2fd6bbc, + 0x8424c91a, 0xc3fb7cec, 0x39c70e70, 0x0c1a566e, 0x9b1b377d, 0x0d3bf3a0, 0xcfd0c986, 0x9e7d0900, 0x712b7b13, + 0xdcc62ec0, 0x80810b1b, 0xdc7fdae2, 0xec7a6810, 0xd8c97db6, 0xc3861dc1, 0xff6121c0, 0x58553e19, 0xfabc9c7c, + 0xa2f05b92, 0xf1f38790, 0x7196be28, 0xeec4d229, 0x3826d6d4, 0xc2cedf24, 0x9ae1e1e5, 0xec4b5d7e, 0xb0f8368a, + 0x04c6a9ab, 0xc9cb3688, 0x5e4a6d22, 0x9a7ad394, 0xb54bf006, 0x046da977, 0x19274358, 0x8079ec78, 0xb8adb71d, + 0x05e1b7be, 0xc4201bef, 0x0c18f717, 0x972f3228, 0xd86cd658, 0x58b2930a, 0x15d9d923, 0xaca8b755, 0x44ca975f, + 0x43860866, 0x16edf188, 0xb31a2d34, 0xbee66e88, 0x1bc46a1d, 0x9514b620, 0xc3754e8b, 0x54bf88a8, 0x270c1122, + 0x76b253e2, 0x134e2477, 0xc0b5aa88, 0x3a5a9278, 0x15f1afb1, 0x6c59eaf6, 0xa7caa321, 0xe0753a63, 0xe4aea334, + 0xce4693a4, 0xe57748f9, 0x720aff3e, 0xe7b04ddb, 0x78dd7aa1, 0x0b1e5727, 0xe0edfe74, 0xb315298a, 0x943ea693, + 0xe6b9acbb, 0x024f677a, 0x07b9f42d, 0x17f3becc, 0x25273ea0, 0x95938856, 0x674e2cb3, 0xf071e120, 0x6baca83d, + 0xb44084c7, 0x3fdfd5be, 0x70748b1e, 0x740b2f52, 0xf65e5329, 0xde5de51b, 0x834bae5d, 0x251f0006, 0xd64a4a3b, + 0x7bb95258, 0x1a3a1ab9, 0x7382f5a2, 0x10c7e807, 0xb5ae7fab, 0x2d866c3f, 0x5ebd4bdc, 0x689f6c5b, 0x0cd07feb, + 0x75b430b7, 0x890d653c, 0xca72086e, 0x7f2cd784, 0x9a513bd5, 0xc26bc36a, 0x3f71ba7e, 0x648af606, 0xda5338b5, + 0xdaae3d34, 0xc9c5fd90, 0xcf08eb96, 0x9cf6fe11, 0xa75268f5, 0x6da767f8, 0xad771b4a, 0xa9544867, 0x52f2dda1, + 0xbcd684cd, 0xd761f1e3, 0x5e5fccc3, 0xff869a2c, 0xa030474b, 0x774a2aa8, 0xec59315a, 0x5572589b, 0xf5be54ae, + 0x0196eb33, 0xfd1eceaa, 0x84700cde, 0xe29ce0b8, 0x66866633, 0x63af8358, 0x3bcd2b9e, 0x80ccbd19, 0x8c07208e, + 0xe6a5b1d6, 0xa9de315e, 0x803e7f19, 0x8f436a1c, 0xc9f04f5e, 0x0c44e7f9, 0x910eac20, 0xb535f668, 0x89aaee3e, + 0x31d29f30, 0x299637c6, 0xdda8897f, 0xb85da1ef, 0x22c93684, 0x4b73ddb3, 0x931b9ac9, 0xbd3d7239, 0x87dcfaea, + 0x63098cc1, 0x27e0b0a9, 0x7c767a23, 0x16d08e50, 0xf68227f9, 0xdb3a9659, 0xc41a817f, 0xa5868fb4, 0x03a957b5, + 0xdc012e4f, 0x39017fea, 0xe8b41178, 0xd72d8a1e, 0xc97c0016, 0x6f6b9c65, 0x01928275, 0x33a813dd, 0x166c31e0, + 0x578ba6cf, 0xf293cbff, 0x62124f02, 0x16053a45, 0xf66fdb8e, 0x335fb9aa, 0xc71c65a6, 0xf07fd79c, 0xdc46e080, + 0x2e0be6f5, 0x712ecf9d, 0x6eb8d768, 0x25deab05, 0xa46ec5b5, 0x36a0ba63, 0xe2ca3975, 0xfdf3f5f0, 0x200cf178, + 0x2bd10ce8, 0xa9b8b2d8, 0x3f4f9096, 0x11b2151c, 0x46ee9542, 0xcba26066, 0xc7a68570, 0xc6e4e1df, 0x9ace63dc, + 0x0e60c576, 0xfed73570, 0x58093e44, 0x1d9aa6e7, 0xd8cecabe, 0x650c7663, 0x99e31ada, 0x352ee248, 0xc699e3fe, + 0x54144411, 0x12d22cb5, 0x22b0a52d, 0xa5ef5a3e, 0x9b8be984, 0x3eaa88e8, 0x65facef1, 0x8eb1404c, 0x15728b4c, + 0x5a78a542, 0xf5cbd615, 0xa2882943, 0x61982e60, 0x832c3a7a, 0x4e62c1b5, 0x098f9d65, 0x4037f884, 0xf2400253, + 0xfdb8176b, 0x08a273b8, 0xe6d0ea72, 0xb78c1a42, 0x22256dd3, 0x6a7015f9, 0x84957b90, 0xc0fde152, 0x43cccf02, + 0x4e631d9f, 0xcb265c61, 0xef96345e, 0x27d5bf4c, 0xde76622a, 0xf6fe769a, 0x1979ce13, 0x63645712, 0xe1ad68c3, + 0x10654676, 0xc7b9e967, 0x75181b42, 0xd2cf7a34, 0x4d513b66, 0xe42cd5dc, 0x01933ecb, 0x2594ec62, 0xdbe13021, + 0x69c4ea5d, 0xde50b85b, 0xf0bd554e, 0x46f2bb65, 0x9af6fb69, 0x3c844297, 0xe97dcd35, 0x7896081c, 0xb59002ea, + 0x9fec7388, 0x7d47247d, 0x110c9b66, 0x91fa92d8, 0xddedc216, 0x3c727eaa, 0xe314c345, 0x7d864b6e, 0xb658cc63, + 0x89fa5d6b, 0x6fc6f08c, 0x3b028a82, 0x63539f7c, 0x124f3164, 0x69d47f78, 0x81096f01, 0xa0ba2097, 0xd66d56d8, + 0x768a5e93, 0x84a6800e, 0x52325f33, 0x36bc8d0f, 0x04ca33f7, 0x1201ee5c, 0xa6d5f14f, 0x903c0cc6, 0x300c406d, + 0xfae8e7ec, 0xc428252e, 0x4f08617f, 0xefc06c42, 0x9c0f8ef4, 0xe02326e0, 0x1fa6c46e, 0x12e54dd0, 0xc3f2e222, + 0x36433755, 0x19939795, 0xe89ade4f, 0xd8b01d0c, 0xfe9cfc9d, 0x16d1aad6, 0x3b7dc3bf, 0xcdc84ac3, 0x57042615, + 0xd5d2e34a, 0xd597ee92, 0x3102bfe3, 0x739bd1f0, 0x67cf510f, 0xa191e57d, 0xfdde5c00, 0x0a9333a7, 0x9b7cc629, + 0x8b480e07, 0xac109835, 0xb30747cc, 0xbf12e377, 0x19cf5351, 0x6fe6cf6a, 0x06cdadb6, 0xb4feb6a9, 0x61246179, + 0xa302d0ba, 0x4bb9170f, 0x9fa8d84f, 0x216b8c3e, 0xe594261e, 0x96184581, 0xddbb20f2, 0x2ede3726, 0x1519205c, + 0xfed8a34a, 0xe4cb2969, 0x8b59a716, 0xa28e3d30, 0x0b2a5ecd, 0x82b2fdad, 0x0f63a6c7, 0xdba6987a, 0x959a3935, + 0x2447b2e9, 0x14d6dc61, 0xe6ab7ee7, 0x0e5c4c71, 0x017b9c30, 0xbeb3e9d0, 0x5aa044bb, 0xb1a677ed, 0xb6b82d93, + 0x75dd6b5e, 0x4b882866, 0x9cacda94, 0x5768c60f, 0x61b59460, 0x9ab45293, 0xc43afebf, 0x09b8da8e, 0x0c1a857c, + 0x47ced341, 0xc65ac052, 0xc01bbbf9, 0x232d2e62, 0x6a0f1a2a, 0xc5568f8c, 0xfd3e435f, 0x5b20897f, 0xa0f9fb53, + 0x403fc089, 0x6117332b, 0x5442ef28, 0x8b5dcd5f, 0x560ee1c8, 0x07c88d40, 0x0934dd9a, 0x35be3e77, 0x3445ea2a, + 0x560ceb58, 0x13e9734c, 0xdaf42afe, 0x56918622, 0xbb888c21, 0xb771c665, 0x383eacdc, 0xde5c8049, 0xcf8f6397, + 0xe19898a6, 0x659e3a23, 0x06eccabf, 0x6452159f, 0x56472c3b, 0x9003eeeb, 0x00862628, 0x973bc07b, 0xa338bd20, + 0x6acfc89a, 0x4d803730, 0x80dca456, 0xaed7ed86, 0xea176f30, 0xe143aa8f, 0x0e14abb4, 0x1c13fb96, 0xedb44ba2, + 0x2d61dc6e, 0x2af0dce3, 0x3d8c7b77, 0xc2d30241, 0x8717629e, 0x32e39dd6, 0xf4c28854, 0x0671bd69, 0x5ba88bf9, + 0x8f938d1c, 0x587bf470, 0x34747d93, 0x6b708fc4, 0x05859b45, 0xf2181e05, 0xab765e62, 0xf62e48a5, 0xef9bcb00, + 0x27fe7edc, 0x815c83ea, 0x20badb42, 0x9e6405ef, 0x7a69cab3, 0x716a0fb7, 0x71d2a407, 0x6f973e28, 0x10bfb2b6, + 0x85f6ab80, 0xd238d717, 0x3a3b7761, 0x250efaf6, 0xaef73ac7, 0xc03a6d42, 0x0072a595, 0xaaaf7555, 0x5fdb16d7, + 0x52cbef2a, 0xf5ad4811, 0x8d607a6b, 0x230a707e, 0x5de9be57, 0x6dac6d4e, 0xc96ad841, 0xf3a3398c, 0x4094840e, + 0x9cf9a631, 0xbfae88bb, 0xd1d0facc, 0x5372d663, 0x3be4ef7c, 0x69a4b830, 0xa99ef217, 0x10b4a300, 0x8e7c9a63, + 0x46b902dc, 0x36420303, 0xc1bcd663, 0xc6e2af09, 0xff41f045, 0x1b7bb680, 0xa133cc95, 0x20ab9f5c, 0x70f9b7cc, + 0xfdd95232, 0x7bc67559, 0x3a9170bf, 0x8b468f82, 0xb5f59c67, 0x7f35fcef, 0x7266c376, 0x3fa67c46, 0x505fe268, + 0x4e12b6a0, 0x46bfa4ec, 0xb5c841fb, 0xaece4d65, 0x87ad2eb5, 0x0ec49cdc, 0x7258b67f, 0x57a268ad, 0xf3bf41a0, + 0xec45044b, 0x20549db9, 0x9f8744a2, 0x88897d70, 0x20507d3f, 0xf9b7410e, 0xef393818, 0xb010cf3f, 0x1b29d2e8, + 0x9b4b7510, 0x3ba77e52, 0x3fb28311, 0x3f064798, 0x485f8bf5, 0x0a18a13f, 0xfdf3ef31, 0x6bc9a5b4, 0x56003b52, + 0x93f1c171, 0xfc2c8a39, 0xedf4e6b2, 0x3d218167, 0xa7a7488a, 0x99004550, 0x321fcd6b, 0xfdbd6a3e, 0xedb05b84, + 0x2b69cdd1, 0x053770f3, 0x65ddb569, 0x5689ced2, 0xf82698c5, 0x8b3b220d, 0x4426b84f, 0xb93e3e83, 0xe42e6562, + 0xcf3e9581, 0x55cc4557, 0xa94b5510, 0x4830a165, 0xb02518a7, 0x575bba7a, 0xb57e05eb, 0xbdc0611f, 0x90a64de0, + 0x6f82232b, 0xa2cee8bf, 0xc016e45e, 0x61f3e299, 0xe06e6499, 0x976db162, 0xa29b725e, 0x16991016, 0x0224a38d, + 0xad596f3c, 0x2994b3ad, 0xdd835358, 0xf1cdcbf8, 0xa9764f5c, 0xffd08d21, 0x05632cd1, 0xc0233880, 0xa0d15a10, + 0x5955d7ca, 0x34d37f6c, 0x0a08cb23, 0x75a9135c, 0xa3c7e0b8, 0x2a03c974, 0xbd5d90dd, 0xc1d11ed7, 0x5bf59cd0, + 0x7ec0ef37, 0x455e81c5, 0x0359526f, 0x66862286, 0xb704eceb, 0xca3c7cc2, 0x99068844, 0xd77342f3, 0xd6688cc7, + 0xd6aeb276, 0x0395b142, 0x1866c388, 0xd7319e1a, 0xd42ea2db, 0x65f4b297, 0x34866bf4, 0xb0015598, 0xb6feb624, + 0x350e382d, 0x28c18325, 0xab75ff67, 0x7bba4682, 0x43f54ca3, 0x1de2892a, 0xea71d71a, 0x869d9205, 0x713f758b, + 0x03b60727, 0x0823cb2f, 0xda2ad279, 0xb4654f62, 0x50e5fca3, 0x1cf3d7d6, 0x27a36693, 0x02fa29d0, 0x29a21ebe, + 0xd84ab9f3, 0xf04283b6, 0x15e85da2, 0x8a8b62fd, 0x34f949af, 0xcbd92320, 0xdae7f2c2, 0x34081e7b, 0x2d581e06, + 0x979d319d, 0xa079a0b9, 0x46011f1f, 0x17bd7a82, 0x1b20bc16, 0x5319f2cf, 0x83a237ba, 0x885ace29, 0xa57ad4e3, + 0xac0e3e0a, 0xab06f7d7, 0xb81230a7, 0xbb69da2d, 0x4679fcd5, 0x29dea619, 0xd487370d, 0x86828011, 0x2319c359, + 0xd884ac9b, 0x4c93bb17, 0x66fbeca8, 0xed76a78c, 0xfefdf306, 0x3f4adf84, 0x396d931a, 0x506d0122, 0x126f914a, + 0x410738d8, 0xb9c448b1, 0xb5f6282e, 0xbc17e3ca, 0x99f4aac2, 0xca98564b, 0xa24460c6, 0x87e51edd, 0x656f8b84, + 0x1522a0a0, 0xce60e63d, 0x65b23e81, 0xd85d652f, 0x1ec9b8fa, 0x14ef6b15, 0x426e119f, 0x8d810d54, 0x19da8d78, + 0x60856da7, 0x5925ee0d, 0x2ed10586, 0x51673b2d, 0xab986912, 0x1121c5f7, 0xa1ec71c9, 0x751c7fb1, 0x5f8f7fc8, + 0x70058bf7, 0xcc71d969, 0xb8bebc9b, 0x7cee6de2, 0x9e093ffa, 0x3c692046, 0x0ff5fd43, 0x080f8687, 0x84125f94, + 0x844ca693, 0x299d27d6, 0x0b1de51c, 0x002951a7, 0xe09241e6, 0x5d2e4722, 0x8a69190c, 0x384735ff, 0x755fd48e, + 0xe46964d6, 0x8d4a80ac, 0x5c16a36f, 0xcee49e0a, 0xdebc4e77, 0x2c9a21a6, 0x2215946e, 0x05ff049c, 0x887a1dfc, + 0xc6c08831, 0x8230001b, 0x164fee31, 0xf13b1cae, 0x17ec7ddc, 0xdffd562d, 0x6d86276c, 0x2942d7f0, 0xb5db0622, + 0x230a6974, 0x7afecd1a, 0x393dab47, 0x1c81942c, 0xe1c85753, 0x23662798, 0x431a7bce, 0xe699d6fc, 0xdabe51f3, + 0x2bc14d42, 0x934a614b, 0x59b289b5, 0x55710cdd, 0xfce67b72, 0xae7aac74, 0xa1c8dce9, 0x7366de34, 0x2ad908b8, + 0xc3c83c85, 0x6948edc8, 0x4d0d276a, 0x5bb7dbaf, 0xfdf321ca, 0xb134ceda, 0xe4acffcf, 0xe3f3117d, 0x467a3000, + 0xba80a324, 0xffb9a7ad, 0xcdf4af0c, 0x37070bb6, 0x5ca1033d, 0x6eeff462, 0x8040d219, 0x63d4bee5, 0xee9ff1f1, + 0x05888b07, 0x47bc3305, 0x6caa7961, 0x60c71274, 0x8dd608b1, 0xf9849801, 0xdb75e8ca, 0x038a6bce, 0xe151c9e2, + 0x16eeaf8c, 0xdcc1edcb, 0x05dd580c, 0xe4ac7b9d, 0x09370a79, 0xdeff6e8b, 0xc3847e73, 0x6a71ab20, 0x0f7e9abe, + 0x8b65d008, 0xdc9158b0, 0x0ab3b074, 0xcf593482, 0x3b5b7035, 0x23925155, 0x50ee72ea, 0x20b598f5, 0xfb0f96d6, + 0x5ab409b2, 0xf70f5b59, 0x9d099463, 0x6db3d0b6, 0x7c08ac8d, 0x0e3b7071, 0xca3275ac, 0xc3be89c3, 0xdee59744, + 0x470d499f, 0x76b6912d, 0xbd80d7ed, 0x89a05df0, 0x770bb979, 0xd7bc4eff, 0xde38094f, 0x313a1d12, 0x57c19ca5, + 0x608ce9ae, 0xfd8869a9, 0xb95c2f26, 0xeb42577b, 0x36327fe4, 0x16b6969a, 0x7b9b4eed, 0xc69b5841, 0xa1314e03, + 0x1fdc3dfa, 0x78cfe1e6, 0x5f0d47fd, 0xe4286e00, 0xe6e21422, 0x977fe0ab, 0xbb0a86b8, 0x3c23d00d, 0x3b846130, + 0xf22ac287, 0x06df0062, 0x2558a31a, 0xb5b6ebac, 0x5820e6c6, 0x7d706123, 0x6760a6d3, 0xf4aaf596, 0x430a6041, + 0xf20c910a, 0x43f1ae7c, 0x340492e2, 0x468a8ee8, 0x3ba0ba56, 0x942ff18e, 0xe504ee5d, 0x22a5e684, 0x0a5dade7, + 0x797c21aa, 0xd73d5602, 0x904b44ce, 0xd696a936, 0x6b5ffa07, 0xd40cfba2, 0x131fd31b, 0x3d281a28, 0xd001c6b4, + 0x5153d773, 0xde4084a6, 0x3c75d0e2, 0x30dbee0d, 0xddda1ff8, 0x4797b057, 0xa6bc72b8, 0x75dfe012, 0x06ddd330, + 0x27c8bef9, 0x3bb93bfb, 0x43dd7e0f, 0x0738c0c7, 0x7f84a972, 0x9f0b0832, 0x09f30a26, 0x6ced418a, 0x870772a7, + 0x8d5ff7b0, 0xa1c6ed4d, 0xa541cb09, 0xc8842490, 0x705b1253, 0xdbe1dcab, 0xb1a7ce60, 0x11f46bef, 0x07963439, + 0x65a9fb68, 0x436dbcb0, 0x25c821ac, 0x2b69497b, 0x3e3b7d7d, 0x4e9a3b6b, 0xea4f62cd, 0x2f2c5f92, 0x55c13c0f, + 0x5e4db57e, 0x4a9fb75c, 0xbf064b5e, 0x8bfa3eab, 0x2eee3ef5, 0x603ec16d, 0xfafded74, 0x32a7a749, 0x356a96ef, + 0x1b467d2c, 0x7f2bde49, 0xc9cdc20f, 0x74f4e29e, 0x35a77f88, 0x0c2fa2d1, 0x8450eff2, 0xf509bd8e, 0x93c60de1, + 0x41e4964a, 0xbd402f36, 0x3bb1c665, 0x38a98f4b, 0x096e3c05, 0x0323310b, 0x99d5a1fc, 0x2a570e46, 0x2a5777d5, + 0xf6ab66c7, 0x7bf8eea6, 0xaa7d4943, 0x72302642, 0x08cb7236, 0x76bd9cc5, 0x5bbf3034, 0x8e3eac02, 0x0e285570, + 0xd06af4fe, 0x9ca1ea8a, 0x317078a8, 0x2d36fc84, 0xaa01c013, 0x5045269c, 0xb1c982f4, 0x2b5581b5, 0xc90e141b, + 0x72cd6326, 0x39da9fb1, 0x394d063e, 0x9e5c7736, 0x07243ea3, 0x5fcbc04f, 0x66c4f25e, 0x07c8b700, 0x3b116150, + 0x8ba3dc7e, 0x6f777e63, 0x1d3b4773, 0xc8e99002, 0xe4c18796, 0x545c5c12, 0xb8e67f65, 0x83d08541, 0xc4c6c98a, + 0x8e253209, 0x5f66345c, 0xf6b5b566, 0xe618cb0d, 0xaaf3085e, 0x795a3ced, 0xe600b7c5, 0x5903cce1, 0x59c90d3b, + 0xf7f04a97, 0xa1ba75ea, 0xb1a389e0, 0xd630563a, 0x7d12f43e, 0x05d13924, 0x93dd21eb, 0xfcf3a7ae, 0xaeb5b508, + 0xe77abb42, 0xb1e633fe, 0x0f76b794, 0xc1026d64, 0x22b928a5, 0x6fc2037e, 0x61d0667a, 0xcfc8a54f, 0x3a921f7f, + 0xa6c6c8a6, 0x8d9f2c51, 0x613ffb60, 0x89515a55, 0x9eb5e71b, 0xdc9b597d, 0x4784e058, 0x542cc6ba, 0xd550ac8f, + 0xa6fbf5f3, 0x1f0c1413, 0xdabc6116, 0x82bead86, 0x1f3773f8, 0xe5b888a6, 0x50162453, 0xf1dc1fae, 0xa7eb5c5f, + 0x8cf52602, 0x8c50e408, 0x4bd83114, 0xbded21c0, 0xf8981e36, 0x5a975c98, 0x9700680e, 0x3786ad4a, 0x5a80f1ce, + 0x9257b051, 0x7878cd01, 0x0eb50ac6, 0x1ddd220b, 0x9d1c3874, 0xf4d7ba1d, 0xdbdd935a, 0x57e090c6, 0xe4699cc7, + 0xea0314dc, 0xee76093f, 0xd95e4e4c, 0xe0fcab34, 0xd3409112, 0xe763cce5, 0x500ff94a, 0x5a6ed906, 0x9efc581d, + 0x5fde224d, 0xe5f99654, 0x490c2513, 0xcf958e35, 0x7f2dd03e, 0x953b7f32, 0xc78ce2e6, 0x4646924f, 0x34b0082a, + 0x503e9d2a, 0x0b3541b9, 0xa6ecd071, 0x5aed2cdb, 0xa13c9105, 0x23dc63f4, 0xc242b597, 0x27d0f595, 0xa63abba0, + 0xb1cf357e, 0xac69b44e, 0x6a0da772, 0xc38b3440, 0xe4ac16e5, 0xf3e9b730, 0x5ccb3038, 0xf13832f8, 0x5b3e5b29, + 0x1213183a, 0x2347525a, 0xc7ec11da, 0x8c1f4639, 0xa6b1b3d9, 0xa748bc0d, 0x371b54ae, 0x9cf41e13, 0x6b8b1fc6, + 0x1fa3803f, 0xc57c3348, 0x9529392e, 0x19b519ce, 0x4e3e2e25, 0x633c02da, 0xeb01f3f0, 0xa3145509, 0x948f5b29, + 0x43dd37e0, 0x52824854, 0x22445e0d, 0xb1804bdf, 0xb26643d0, 0x5a53ae43, 0xb8e79109, 0xb8c4b78f, 0x08e256eb, + 0x690ffb9b, 0xc2a40d3d, 0x44fa38c4, 0xdd2142dc, 0x4eb41f6c, 0x46d95612, 0xb7ab5954, 0x04fd1d91, 0x377e2f82, + 0x8ebcdaa0, 0x59a66920, 0x350901bf, 0xa1c35a62, 0x667d72fc, 0xc94d23ba, 0x4414236a, 0xa71c2ff5, 0x4bd32b7f, + 0x5c4c144a, 0x7cecb0b5, 0x6c870470, 0x7eaf9457, 0x774e95c3, 0x5d60746a, 0xb5452c72, 0xb1ae16ad, 0xe33ab9a8, + 0x3cd2f8c0, 0xc16d16ac, 0xb952a46b, 0xb7e2911c, 0xaee4f5c4, 0x848233fa, 0x6f936f43, 0x8c5ea716, 0xc5f8a76b, + 0x0d58966b, 0xdd7d2085, 0x3439871f, 0xea928188, 0xafb0c068, 0x321de26d, 0xe9ee845e, 0xba54d356, 0x23c05b5f, + 0xeee62204, 0x440a95e9, 0x056bc073, 0x61b67642, 0x3d459c8f, 0xf16653be, 0xa75ae2fa, 0x509b0878, 0xa27a5321, + 0xa8f47186, 0xfa47b51b, 0x8d5aec04, 0xa936cc95, 0x6156568d, 0x440e0f23, 0xb4833c6f, 0xcaeae1d5, 0xb298f0ef, + 0x03edc11b, 0x99be01f7, 0x484999e4, 0xa7bfba75, 0x2fff9202, 0xd2c1d4b0, 0x83943dca, 0xc226c071, 0x20998bc1, + 0x32d699a1, 0x9dcbc197, 0xaf58c25a, 0xfe735709, 0x017ddc35, 0xeb06656b, 0x7233cf08, 0x31a9e2ea, 0x0d7084da, + 0xd693d335, 0xcdab2075, 0x8be04f06, 0x0696cf40, 0x2446c725, 0xdf5ee6e2, 0xd591bdf5, 0x76e97b76, 0x7a227ab6, + 0x19bf4958, 0x1add9be8, 0x59295188, 0x6a98dd17, 0x944868dd, 0x8673c8d6, 0x2cd1fa52, 0x89e29e94, 0x5a2460e1, + 0xfb1e24dc, 0x780fa107, 0xb0cb95aa, 0xee6b8352, 0x5d386848, 0x250c3fa7, 0xf9316403, 0x57c9cf34, 0x97ffe193, + 0xbe85eea9, 0xc13a11ee, 0x749d1237, 0xd563cd1d, 0xe6904944, 0x2d571d5c, 0xf5aa276b, 0x00787bec, 0xdc899238, + 0xb3fe457a, 0xd9bb410e, 0xa2be3d2f, 0xe3c8eea2, 0x0ff39bf4, 0x279a9481, 0x9a47127d, 0xe2692ee9, 0x0e7ca2b4, + 0x01c3994e, 0xd594f1de, 0xde0e4dd7, 0xf03d128c, 0x8e413725, 0xffafa9d7, 0x6945171f, 0x823c08c1, 0x960ef739, + 0x0896130f, 0xa9f597a3, 0xe184c281, 0xc40f40b3, 0x0f333714, 0x76a401e6, 0x54d8bd0d, 0x372fd6c6, 0xf1281100, + 0x970c8797, 0x4f00f6d8, 0x13f4dc35, 0xc3afcf11, 0x333d6854, 0x8e69d9c5, 0x29e343c7, 0x12b33a02, 0x61ac988a, + 0xc1d08452, 0x343c6e04, 0xca78bc6b, 0x109ffbe1, 0x99dcc1c3, 0xb88ba541, 0x55a1a029, 0x58fde4f3, 0x1ba09a52, + 0x4c94975d, 0xe5cf5e8f, 0xf13f9f6e, 0x47c87013, 0x32722b75, 0xb0dc35cc, 0x0b87d6f0, 0x91877c53, 0x319b04f0, + 0x5dbb480b, 0x73802b72, 0x5e9d1a34, 0x212d5fb1, 0x069de1fe, 0xb1f257d7, 0x8e438d8a, 0x3d2ed0fc, 0x8c3062fe, + 0x4c32732b, 0x621d00bf, 0x2d35373c, 0x559e5abe, 0xb8e2e57f, 0x4909c9ff, 0xd2af7130, 0x0d63d33d, 0x597d3e4a, + 0xbbf73d63, 0x06f5f846, 0x5cdffe6e, 0x4028f71d, 0x1d069006, 0xeaf640d6, 0xb47d5af2, 0x1971bb4d, 0xa8d55708, + 0x93ca500f, 0x7a0b7a3f, 0x8aa5ed8e, 0xdb8c588a, 0x72a6bfca, 0xb70c0cce, 0x56787d16, 0xc3245f72, 0x1584404b, + 0x3dbbe121, 0xddb32e4e, 0x2e5ae801, 0x4b699d6d, 0x46d6fa82, 0xfce94f3c, 0xd4d546b4, 0x057ed683, 0x7d2907e9, + 0x6e913e38, 0x51d0a241, 0x3dfb7bf0, 0x03e236b7, 0x41ad2e5b, 0x36b65c10, 0xc09959f2, 0xf8dc9f12, 0xc69dd5fb, + 0xf923a8f1, 0xb0d758c8, 0x15771228, 0xfb1d0cd7, 0x7b5fc481, 0x659c01c7, 0x8b1ee283, 0x0c20d886, 0x86afb1fa, + 0x836f2c7e, 0x550858fa, 0x951b7741, 0x0e6e4903, 0x543054d6, 0xa5bf3ba2, 0x696b3f7e, 0xd02b1aaa, 0xed6fafe1, + 0x104ac160, 0xffd3a57c, 0xd890962c, 0x7502d68d, 0x800b839c, 0x51691bb0, 0x33fc42ce, 0x447fe754, 0xb8add29f, + 0xf1d65772, 0x4373357b, 0x42f10ff7, 0x2149bddd, 0x90e6b3aa, 0xfdd98104, 0xed23d624, 0x21c59b87, 0x62ba00ee, + 0x1e2ef407, 0x8d1d3465, 0x8d042f52, 0xf7d1a833, 0x3307f146, 0xb7f699e6, 0x3074b2d5, 0x534e982f, 0xf709f442, + 0x3b0b9025, 0x5c264de0, 0x471f4399, 0x273268f2, 0x08aa31ad, 0xd5b9c71a, 0xcb3fdb4d, 0xe47275b9, 0xa1aa69ed, + 0x47c50484, 0x925e267c, 0xd6223f23, 0x8c2f1242, 0xac3d6512, 0x670fd9f5, 0x46bb7443, 0xb151e2bb, 0xc44ebf48, + 0x4411dfe2, 0xb298848c, 0x245e4f68, 0xf97c6785, 0xa1c8eaf0, 0x5b985be3, 0xf20cf907, 0xc98a770f, 0xb681ed9c, + 0x60d147e8, 0x8fff6b29, 0x837017d1, 0xfd1955c1, 0xf9422c78, 0xa8becb96, 0x36c24161, 0x6ffa421e, 0xc479d2de, + 0xbd10984f, 0x6dfc647d, 0xc2f2c319, 0x87f25f63, 0xca00e2e2, 0xa90977f9, 0x2349c70b, 0xc2fb0504, 0x9e916c33, + 0xdecdc396, 0xb02b56cc, 0xebb75ad1, 0x182bce06, 0xd83df717, 0x5f105ce1, 0x4732b8db, 0xff9e4131, 0x3c0d16c8, + 0x367974c9, 0xb01ea711, 0xc1eb4835, 0xd31ca779, 0xb3a5a678, 0xed846e11, 0x78d543ea, 0xa622fb15, 0x77a6c186, + 0xca094336, 0x7a3167c0, 0x92000276, 0x1e099fea, 0x34c47487, 0x339aa209, 0xc89cbd3f, 0x82128a99, 0x32ccef1a, + 0x2ab82b86, 0x2b536256, 0x5d4b4e49, 0x67c66405, 0xa3a525c8, 0x45698552, 0x3445c6c8, 0x77e24e57, 0x62902c4e, + 0xff5058af, 0xc29c8b2a, 0x2a09c844, 0x4b2b86fe, 0x540f83d4, 0xb378851f, 0xe41518a7, 0xcd5b26e7, 0xe7a2ccbe, + 0x8c4f7654, 0x76cb72b7, 0xa21b9b73, 0x4bacc205, 0x96bb980e, 0x989fd6dc, 0x8c19813f, 0x65af7fe1, 0x14b55b31, + 0x81a974a1, 0x48d1ea30, 0x3444639e, 0xb2780de8, 0xb388a07f, 0x31211971, 0x2680b833, 0x762ca9cc, 0x27124b98, + 0xda06798c, 0x28607707, 0x6a3c3dac, 0xf2f2a7b1, 0xe56aedb0, 0x5d6f4e01, 0xcb6980df, 0xd1281cde, 0xf9a29421, + 0xba8e42e7, 0x565762cf, 0xbef0298e, 0x4ab8935d, 0xe4d0e7cb, 0x332d86d8, 0xaa3133a7, 0xe8c4835c, 0x525da246, + 0x75b0b221, 0x0c905ce4, 0x9d91dd88, 0x84b504d3, 0x0d561f8e, 0x1e3ceb2c, 0xdab52381, 0x3e40e434, 0xd371eba6, + 0x7dd88928, 0x6467889a, 0x9a1de0b3, 0x6ec085a5, 0xe52c3e11, 0xf0d07479, 0x9f444f2c, 0xaeb00950, 0xc5cc82bf, + 0xabb7b8b3, 0x0da850de, 0xdd123bf3, 0x93740975, 0x3bb9cbcb, 0xcfcbb40e, 0xac78f17f, 0xe200f67a, 0xb6d70d12, + 0x9318b54a, 0x24a614c1, 0xa2f92b98, 0x33f8ee9e, 0x96348ad7, 0x5dd4f41a, 0x0902909c, 0x7fed9e8e, 0x91bc6b90, + 0x287c3417, 0x185c5681, 0x193850a2, 0xdfe540f9, 0x391fe3ef, 0x6420ba64, 0xa101f556, 0x6f030305, 0x04e447c7, + 0xfaae83e6, 0x812266bc, 0x8fc21829, 0xc63312c5, 0xb66466ce, 0x8492a736, 0xe018a67c, 0x384c6427, 0xea3685a1, + 0x2622e59b, 0xc6116972, 0x052f2228, 0xa722ddba, 0xa3709625, 0x71a14d19, 0xd915051d, 0xf72301fe, 0xabbdc518, + 0x99cf1469, 0x406dbddb, 0x47dc3d86, 0xf26f332f, 0xd880fca1, 0x37dafc23, 0x6fd8205a, 0xcf470ff6, 0x86cb67ee, + 0xed0d2d4c, 0xef11c51d, 0x0b6ca1ef, 0xcfed9d84, 0x2297df28, 0x210dd62a, 0xfdd3d21e, 0x4db658e9, 0xcafe12d4, + 0x81762943, 0x19373184, 0xc1f562e5, 0x9e9177ce, 0x741aadfb, 0x1f1e2421, 0x4e8906a0, 0xabe0ed9f, 0xe3c3581d, + 0x4f6f470f, 0x777b78fd, 0xcdc2db13, 0x8c929bfd, 0xa05a639f, 0x42d16e51, 0x5169cbce, 0xcf76d250, 0xa635e237, + 0xb802055b, 0x97927446, 0xffd2df7b, 0xb48d3558, 0x7f0ae5fe, 0xbf77d228, 0x10bfad80, 0x7c1cbade, 0x36bc9746, + 0x57acf380, 0x92990554, 0xa5b7b27b, 0xfed8fdc5, 0xa7a9659e, 0xa4db486a, 0x2e2b63c6, 0x295f1657, 0x81503fd4, + 0x0a5283bd, 0xccb0ef2e, 0x80417236, 0x12373455, 0xfb8f43e8, 0xcb027aae, 0x65ba145d, 0x2576e3a5, 0xee63377c, + 0xb3a02499, 0x00645dd0, 0xbee4e6f0, 0x48b93f66, 0xd22cb28f, 0xb268314e, 0xd9d9f586, 0xd322efa6, 0x57d2c84b, + 0xb282595b, 0xb68933d1, 0x0bd5024d, 0x6bf2ce88, 0xd2a0ea9e, 0x054d7afa, 0xe29baf4b, 0xb8b5ec44, 0x1f0ed15a, + 0x3e09f5ae, 0x2f4d6611, 0x2938bf8d, 0xf7622256, 0x615fb101, 0xccd2a269, 0x01aadcfb, 0x80395beb, 0xe40a086c, + 0x5221311a, 0xa8cbaeea, 0x168912ba, 0x9e030b86, 0x0f5603f2, 0xda9c7f15, 0x062d53de, 0x29c213f1, 0x18203717, + 0x7a3aa08f, 0x3e785951, 0x59b5b01c, 0xeb90b0ed, 0x07a4cbd8, 0x3768437f, 0xefe98843, 0xdbe61621, 0xaddc29a5, + 0x218f95a8, 0x293b3568, 0x5d1ede1a, 0xddf3087e, 0x7e431148, 0x1b4ad324, 0x5c787990, 0x4ed372bb, 0x9f903545, + 0x61f9a40c, 0x4327fb68, 0x74a8c399, 0xff6f050c, 0x204b635e, 0x725e71c9, 0x2da22541, 0x5c947af8, 0xf9fa4bc7, + 0x027a92d6, 0x84e7732d, 0x5d5ca777, 0x19da5ba2, 0xae0d91ff, 0x2affd4ca, 0xa4c960be, 0xf8dc9010, 0x795b4abd, + 0xdf7b64e7, 0x7eb9d0ed, 0xc0bd0454, 0x908a3485, 0x60358806, 0x08bf1353, 0x231bdf36, 0x7cd93444, 0x31cc179b, + 0x16454472, 0x656713c2, 0x063efc38, 0x278b4bb1, 0xa5f2e6d9, 0x38314f74, 0xaa09fc8f, 0xc43ce0e2, 0xd8bd9288, + 0xa4d2ae75, 0x95b8c889, 0xbab17234, 0x9fdefc19, 0x11b51d2a, 0xfefb2e40, 0xca6bbd24, 0x50e2394f, 0x0372b64d, + 0x48e84388, 0xb6aee122, 0xb41d096d, 0x7f6833e9, 0x573923e0, 0xe851fe56, 0xb03691a0, 0x4580fc91, 0x7473f011, + 0x8af0c2b9, 0xb9ddbc01, 0x1e9de4b0, 0x0fbdde60, 0x98c10dcd, 0xd220af8e, 0xcad255e6, 0x338f981b, 0x6c1ca7aa, + 0x1bd0446e, 0x5687afd0, 0xf008ff14, 0x25c1dc2f, 0x803d5825, 0x3c7faf2a, 0xc22e30b1, 0xf880e3ff, 0x9b2f51de, + 0x8f365f9b, 0xbe23cdde, 0x2e4f659a, 0xc8058716, 0x22e0df0b, 0xb13ac348, 0xad964836, 0xe8189421, 0x2d0875b0, + 0x63e99835, 0x095bbc10, 0xb1798d9c, 0xc996e435, 0x0b887823, 0x725b6ae0, 0x8f73c78e, 0xf5723e86, 0xca1bebd8, + 0xf49ca41e, 0x1dbf2fdd, 0x12b4dcf6, 0xed98a853, 0xafa831c6, 0xac9e0012, 0x21cbe6c6, 0xc26a8fd4, 0x3e8b400e, + 0xcafbd2e3, 0xbf006f94, 0x335dd5f5, 0x7542ca9b, 0x700223ae, 0x4c73ed09, 0xf6d00271, 0xf42371b4, 0xb41e9723, + 0x6fa8f449, 0x0f273b10, 0xb4df304b, 0x69f6cbb9, 0xffc43a12, 0xd9e2c152, 0xbc2a2833, 0xe51ed898, 0x1738250c, + 0x9b3dce7d, 0xd136d098, 0x16748c46, 0xf5d13403, 0xdc9d3bf5, 0xe7ecb057, 0x6644236f, 0xad30de0a, 0xd0d5bb6d, + 0xb46e73fb, 0xc5c09bc4, 0x6b6e8472, 0x353d2a8b, 0xfa739e90, 0x45887cbd, 0x7233f9fa, 0x836c99c0, 0x55147bd7, + 0x6027c956, 0xf27adc82, 0x9b9149e2, 0x482fe9b3, 0xa7e9673d, 0x2f5b576d, 0xfa0461b2, 0x8a51dacf, 0xbf99147c, + 0x7702a182, 0x439039a6, 0x2ee2594f, 0xa73e6b5e, 0xb112c13f, 0x56d89890, 0xe11a7464, 0x744881ec, 0x09c730d8, + 0x4765371f, 0xbe5608a8, 0x89ce1f94, 0xa739162e, 0x995d24a7, 0x1b5140cd, 0x14e5fbc9, 0x3ee7d016, 0x60441441, + 0xa9db4196, 0x2aeeab2e, 0x6656371f, 0x47921c1c, 0xa52dc650, 0x658e12bb, 0x1226e923, 0x78e02f89, 0x934e8798, + 0x0de7ff5d, 0xca88bcc0, 0x9146d43e, 0x8f9bedb8, 0x6172e9ee, 0x3cb70fe3, 0x7b2f0ea5, 0x3004625b, 0x24741b5f, + 0xa55dc210, 0xec363801, 0xaf32339a, 0x9acb44f2, 0x4e311d9c, 0x4e1d8efc, 0x3250beab, 0xf7b3ca07, 0x82a81134, + 0x3e055a98, 0x8cf8aee3, 0xafee8c40, 0x9f77fa45, 0xf61bc5e5, 0x601d2638, 0x8331fe0f, 0xa064ab1c, 0xf8f471b3, + 0x9dc3ff05, 0x8c3aeffb, 0x0e38fe38, 0x9fa5b7ee, 0x0f51c2ba, 0xaf1dde0c, 0x53dcb531, 0x91bbd8b2, 0x14370642, + 0x05d64ed3, 0xc94ed203, 0x457158c7, 0x009efa34, 0xc238c3e9, 0x70f7e349, 0xbc3c4e47, 0x43faed23, 0x68a6ca65, + 0xd74fd593, 0xc8df0a48, 0x5f43351f, 0x0296a2ae, 0x7503379c, 0x68dbc890, 0x37651b24, 0xaddb1660, 0x5663842a, + 0x55c7828a, 0xe366b29b, 0x4265949b, 0xfb6e0fcd, 0xf15d32f1, 0x64f2df97, 0xbfbf5efc, 0x1b1c156a, 0x47f51b76, + 0x6c83c597, 0xbe4f4c3d, 0x893cca8b, 0xe0a79c7b, 0xc95cb80e, 0xa4c16c29, 0x045bf979, 0x25313c57, 0x83461b4a, + 0xf6a1bce5, 0xd618ba52, 0x3f598f5d, 0x3a6512bd, 0x7c3178fa, 0x7a24ebc1, 0x297aaecb, 0x50cb57fd, 0xe77e84da, + 0x722c2712, 0x13b2cb59, 0x40f50abf, 0xdde22243, 0x9f340860, 0xa22204a9, 0xcfbe7ba0, 0x40a336f6, 0x638cd32d, + 0xd93c959a, 0x92a91fd6, 0x059dba32, 0x0aa42a67, 0x3d2b42f6, 0x9dcbd79e, 0x4e32a5e7, 0x90d875bd, 0xb32c7d49, + 0xadb9eecf, 0xa1f4f6da, 0x4417759e, 0xfa924935, 0xf2243abe, 0xfe760083, 0x51f71e83, 0x6f41bbd0, 0xb627dd6b, + 0xe833c2a5, 0x72062be8, 0x9884de4e, 0x7bff8133, 0x52c4d62c, 0x49dc97dd, 0x3188397e, 0x5ef39369, 0x7df9aa53, + 0xe7a47124, 0x016214c5, 0xc2ea50be, 0xdbe70c1e, 0xc9091a6c, 0x900e7605, 0x470502e2, 0xaf48365e, 0x90c7e34f, + 0x375ee38a, 0xd8c886d0, 0x759f3a12, 0xa6757b0f, 0x01274e46, 0x5fc7464f, 0xb9dc3744, 0x072e83aa, 0x94065a6a, + 0x8380b017, 0x86a1b104, 0x83a4e18c, 0x51363484, 0x7ca97a0e, 0x2d3c69b8, 0x80e4d71f, 0xc5c3d65c, 0xcc74f900, + 0xce77f21b, 0xdfd31c48, 0xe2e84a4d, 0x2c7bb8a4, 0xd02af0ee, 0x06774c1f, 0x1f3da3d0, 0xd5881164, 0x6d89494b, + 0xd3d4b851, 0x6b01c7b3, 0xcf4fb380, 0x9375c61e, 0xb748d1da, 0x8f3f645e, 0x5113b971, 0x61fa3008, 0x6780c0a9, + 0xc09b77b4, 0x8ef5530b, 0x366738b6, 0xba4d372c, 0xb6e65b6e, 0x36167731, 0x51d7f44d, 0x49627890, 0xe7de08ae, + 0x0b4f1748, 0xc7f715bf, 0x06821883, 0xa7652ef0, 0x9f18332d, 0x7a9c8e61, 0x382d7f3f, 0xcc9534d1, 0xc73216ea, + 0xde1d41fb, 0x2e81cbc6, 0x61d8401a, 0x08917557, 0x8f0b3f18, 0x0c882c07, 0x9e705b4d, 0xfbed6812, 0xf5410fc4, + 0x9f9ecce2, 0xa11a0c02, 0x6b3847bd, 0xea824bb0, 0x97dc4832, 0x59b0ee87, 0xc9dfe392, 0xd09019e7, 0x6a8d87a6, + 0x9c0133ba, 0xc6fcec26, 0xf555402b, 0xd091afdd, 0x349d3d15, 0x73cc1bc1, 0xa6680d12, 0x8a0bda6d, 0xc1bd717b, + 0x58f718a9, 0x300d7732, 0xfec2fc87, 0xc85fa0f6, 0x621efd34, 0x85819854, 0x0e241fcf, 0x45de1cde, 0xe08074f0, + 0xd18ec6b6, 0xdc1bcc9b, 0x95847175, 0x477d7724, 0x204f29bc, 0x8ac543cc, 0xc68dd1c7, 0x791efca3, 0x8fae2eb5, + 0xb60675ab, 0x5139511c, 0xfb50e830, 0xd5c98948, 0xc930b78d, 0x2565f082, 0x4b4e03f4, 0xe4a765a6, 0x86d1fc8e, + 0x263a6aa5, 0xa3e2fa1b, 0xcc607c88, 0x861afcea, 0x20da4974, 0xabafb613, 0xc5370236, 0x65a06215, 0x0388ca13, + 0x0d793888, 0x524dfc4e, 0x9a9d66a1, 0x31947655, 0x5032129a, 0x03b965fb, 0x18b2f5c9, 0x9250a5fc, 0xb0b3d695, + 0x2e4bf4cb, 0xb283941a, 0x1512edcb, 0xd7c003ea, 0xcca5f52b, 0x840e59a7, 0xe55487b4, 0xc2559380, 0x7d203a7c, + 0xca80e453, 0xd6f6abed, 0x7814d777, 0xba062fc4, 0xd2ea5939, 0x69c88bee, 0xc40c04db, 0x31967080, 0x89f00e04, + 0x3ec708ae, 0x0dcce02a, 0x0dc0ac2f, 0x8dbd8979, 0xddad1fff, 0x91b1895e, 0x5fa7022b, 0xb38f7f5f, 0x08c86f13, + 0x086ec9e1, 0x45583911, 0xe588af5f, 0xba4b57d1, 0x6490c8e3, 0x174a2ed3, 0x6f4dc6b7, 0x60251811, 0xa4b0d5a6, + 0xd2f6fecc, 0xd52324fc, 0x356e3fa2, 0xbb6175a8, 0x7b11fcba, 0xce7848fa, 0x1ad30493, 0x9e633e32, 0xec44fffb, + 0xed620138, 0x50deb6bc, 0xdde0e613, 0x68d190db, 0xae4f1298, 0xd6f40f27, 0x2cec4826, 0x4500d589, 0x8da0b3b5, + 0x6a35e61d, 0xdddf6fbd, 0x18a46e20, 0x9f2dde7e, 0xe5d78142, 0x50b81950, 0x1114fb67, 0x2539a362, 0xf9a61e27, + 0xb700a1e5, 0x05269316, 0x88231f22, 0x3f9adf63, 0x4b3ed1ff, 0xa7be39d6, 0x5e7273e6, 0x372fa6d6, 0x40841768, + 0x53b29d59, 0xdcd024c2, 0x0ee6bf6f, 0xc82bd894, 0x7fe0797b, 0xf0165f86, 0x1f344b53, 0xefffd86d, 0x20031b4b, + 0x154038f5, 0x55e772e3, 0x7b92ed50, 0xa614db3c, 0x53d2cd0c, 0xc5201468, 0x6f9e4278, 0x3ac58218, 0x8ee77010, + 0xa1e11151, 0x377eab8d, 0x5fbcc204, 0xc5ade5a3, 0x27b23508, 0xab976ff8, 0xacb0adf7, 0xe1613690, 0xd0c72c57, + 0x84e67238, 0x4c03a2bc, 0x2126000f, 0xf4ebcb6d, 0xd988ee69, 0x8400066c, 0x8801e985, 0x4a673952, 0x72752eaf, + 0x1f0d2169, 0x0c8d06d5, 0xb3c11263, 0x5195debc, 0x20faa6af, 0xa096b12f, 0x4d0d017c, 0xec62b65e, 0x5f642425, + 0x02a9d98b, 0x7c353e52, 0xf2873bff, 0x3e01f1f6, 0xe0f53b61, 0x22fc9cfc, 0xbf0fa194, 0x3a96c6bb, 0xfca66a6f, + 0x3d7538f8, 0x93b597b8, 0x29ad5c33, 0x452b400d, 0xd1452198, 0x632ff8e3, 0xd4b248ae, 0x39961f55, 0x191ffa59, + 0x6379e4a5, 0xb3f8232e, 0x4f845968, 0xac3fc1c0, 0x47ed4802, 0x8d0d21fa, 0x9e2304af, 0xf375e8d8, 0xe2b2a0cc, + 0x61992448, 0x4874d55d, 0x7076ec5a, 0x27f7adbb, 0x0b8e50ec, 0x0eecc112, 0x7acb44b4, 0x9d2daa4f, 0x46949f96, + 0xe71337d4, 0x681889c1, 0x8688b1b8, 0x25414cc4, 0xebf379ef, 0x1873de90, 0xda03a712, 0x9dffbafb, 0x3339fd0d, + 0x442bf360, 0xd10c4c0a, 0x3639b5ff, 0xe5011d2e, 0x96b82439, 0x7d6683fb, 0x67a501d4, 0x1688da10, 0xbe749132, + 0x14a495ee, 0xa0a6271e, 0xe0351a07, 0x4d79bf75, 0x8d608550, 0x88c5ab73, 0x85e6f068, 0x7a757797, 0xd900c690, + 0x25965f6b, 0x087b196f, 0x2670f4cb, 0xc08b3249, 0x01ad2da9, 0x2302a6f7, 0xddce8e90, 0xf97ae02f, 0x7fa72828, + 0x43403652, 0xd599a1cc, 0x9f0a12e1, 0xd346066a, 0xea8eec45, 0xea2b7045, 0x678a924e, 0x820a344a, 0xd7ca1e7b, + 0xc2a01011, 0xdce3feea, 0xabf30c27, 0x6e727cc3, 0x2af70e11, 0xfa0731c7, 0xff73af5c, 0xe599bf11, 0xdc531435, + 0x53c3ef9c, 0xd0666e83, 0x8b7ab077, 0x1ffb8ca1, 0xe1585eb5, 0xed8f97b2, 0xc7258d8f, 0xf008060d, 0x86e32b6e, + 0x278dd366, 0x027dd726, 0xa9052de4, 0xc56ceb56, 0x1de3ff0b, 0xc55e372c, 0x2c5b3a05, 0xc383bf0e, 0xdf0f5970, + 0x728e977c, 0xa2559e68, 0x1e1547d7, 0xddc2c58b, 0x1fcdc874, 0xdcd1072a, 0x7a96dfd9, 0xa6987258, 0x9ed95a95, + 0x9cfa510f, 0x83102f8b, 0xba316c85, 0xbf6b774a, 0xfb3e7546, 0xcc2a96a2, 0x6677abe3, 0x9fc200f6, 0x622778a1, + 0xcc1e14d7, 0x37b25ec6, 0x2d5a19c6, 0x656932a1, 0x78b2999b, 0x6093162a, 0x7fe924be, 0xde5f1cc0, 0x35620cd6, + 0x61154885, 0xc3992633, 0x77a3fb59, 0xcdfb7c98, 0x5c2c9c10, 0x525d30ab, 0x849d9feb, 0xaff4e616, 0x41b6c23c, + 0xf8189846, 0x3f888cbe, 0x68073de1, 0x146554a1, 0x737d0310, 0x751e5bf0, 0x36a539e2, 0x5da3323c, 0x78008d7c, + 0x3b69b98b, 0xefaed7bb, 0x1e0ac403, 0x63718151, 0x13bb1332, 0x59d45eae, 0x4147b0b9, 0xd00ed23a, 0x7c9a2d49, + 0xbd84e064, 0x3d95278e, 0xff5d0a69, 0xa618808f, 0x908e2ae7, 0xf2565f58, 0xc426cdff, 0x64ff63fc, 0x5d1599d2, + 0x67b2c025, 0x9ed01e9f, 0x74d61051, 0x6d5a11df, 0x0ab21162, 0x524cba0c, 0x87a4adc8, 0xbdc695e2, 0xadb2dd01, + 0xb392d471, 0xc6803339, 0x73f8a28c, 0x85b347dc, 0x51b2c605, 0x54fd2d9b, 0x6d223a8a, 0x15af71d3, 0x5b1fa5e9, + 0x902b5742, 0x81645113, 0x86e30868, 0xe144dacd, 0x439e8e33, 0x6591426a, 0x2c1abc63, 0x1ee60d3e, 0xbfc4cb8c, + 0x2d14d7de, 0x95ee3018, 0x426b4da7, 0x98c9f7df, 0xcbefca8f, 0x17ddcc69, 0xe0a89897, 0x85002505, 0xcc35574a, + 0x0c95ea10, 0x76793d2f, 0xacdeeb6c, 0x3078559b, 0xfb7f39fc, 0x38b6af38, 0xfbe4bda0, 0xcf2541ef, 0x7971f256, + 0x9f3dd224, 0x4ed801ba, 0x9fd650c8, 0x00b0bc1a, 0x857cc4b6, 0x65be0cfe, 0x70ad5f94, 0x291669f0, 0x2ebd9b3c, + 0x505d0861, 0x741a25fe, 0xaaa5bcad, 0xca122b0a, 0x33cf0cb1, 0x7c3ad271, 0x6879258a, 0xbb77be20, 0x30418bd9, + 0x73ce7f37, 0xb7fc7f36, 0x55ca86e0, 0x2e4f1d74, 0x4d298129, 0x8496f820, 0xd0d787a1, 0x00c2e4ae, 0x132d2181, + 0x2008d65c, 0x5d20c31c, 0xce5c92c5, 0x91f9803a, 0x96dce948, 0x85afc8de, 0x72dd4adb, 0xbc6993b7, 0x8ef106dc, + 0xe8f729ce, 0x2ad6a6c4, 0xc6be1984, 0xc47b2886, 0xf9245d31, 0x34b87a97, 0xbf129246, 0x1638c492, 0x72c74646, + 0x5164a477, 0x02a1f134, 0x5c2d2927, 0x2ae374ce, 0xdc634027, 0x6058b2af, 0x92f2eb03, 0xe9af747a, 0x22b52452, + 0xf6dad1a9, 0xc219e523, 0x999db1b6, 0xe868e61e, 0x229c948b, 0x47951631, 0xc45979b4, 0xd5b01d12, 0x6c8a8390, + 0x027f8ed4, 0xa78ec433, 0x192ebe50, 0x5660c1aa, 0xd89cc3f6, 0x258b53b8, 0xef4c75e8, 0xdc80e7d3, 0xa0a0c320, + 0xc89a78f0, 0x96a4e2bb, 0x3a1cb7fe, 0xdb9a9b1e, 0x4edf516f, 0x2ff91f5b, 0x02cb382c, 0xef882dfe, 0x7b7acc66, + 0xab8aa803, 0x1ebfe19e, 0xef148367, 0x8e97bd0b, 0x181347e4, 0x118d8f6f, 0x6ea5f5bc, 0x3ac993a8, 0xaf2f7e60, + 0x84d8b28f, 0xbda10567, 0x937f14ef, 0x95cc900f, 0xb08a69ba, 0x71a16b81, 0x711e2e83, 0x8f0909d8, 0x34889f3c, + 0x1a4368aa, 0xef3309db, 0xc95d9ba5, 0x51ce9010, 0x0c7f9940, 0xd992558c, 0xb893e2e2, 0xf5a44e97, 0xc5b2274f, + 0x04361b95, 0x48bd488f, 0xf9ba422c, 0x1b01d5cb, 0x7e24c698, 0x3bf4371f, 0x987f340e, 0xa87a4bea, 0x8cd307f3, + 0x489484ee, 0x45fca205, 0x138eb6db, 0x54dcb281, 0x23195c06, 0x3535ee44, 0xa10b8ef5, 0xf9ebcd18, 0xa7b1901b, + 0xa857a539, 0x076fad41, 0x000eef29, 0x99683e84, 0xd0f8293f, 0x010260f8, 0x112af12d, 0x62ca2b55, 0x5023b9f5, + 0x7f5b897a, 0x49837200, 0xbd265188, 0x8f6c3d82, 0x9477632d, 0x164ee6d2, 0x1ed424b4, 0xf2c8417e, 0x57198ee0, + 0x528cdb12, 0x3e5a0087, 0x58023ade, 0x330cc6fb, 0xf7976b02, 0xe38cb73a, 0xa9c462d9, 0x32bad7ba, 0xfa5eeea3, + 0x637fedb8, 0x76588782, 0xc29811ee, 0x6a014343, 0x7dbfbb7a, 0xb40e945b, 0x5f92f1d3, 0x77cbd65a, 0x012af51b, + 0x0629034c, 0xe421ebc6, 0xa30ecb10, 0x2ee9f8c0, 0xb9118658, 0xd3a99902, 0x096ff689, 0x7a66c57c, 0x22c2d3fa, + 0xf42fdc6a, 0x84b5a645, 0x333d7d55, 0xf82a333e, 0xe41d8461, 0x4dea543a, 0x488b96a8, 0x823866b7, 0x47d1b629, + 0x75e90304, 0x49edcaae, 0xee3855bb, 0x8591078a, 0x39133114, 0x10635ddd, 0xf99d98e1, 0x68f5aff6, 0x9179e3b5, + 0x9e0371b9, 0xf0a8b9c3, 0xfbd04446, 0xa4054866, 0xf2023c5b, 0x8c1bc95e, 0x0d514278, 0xe583aa33, 0x95e46db7, + 0x192fc47d, 0x4a63c73f, 0x5a80de90, 0xcd044f94, 0x96a72f73, 0x6c65556f, 0x453c1b54, 0x6e29067d, 0x1030e6bd, + 0x92f642cd, 0x08134e8d, 0x1ec16ea6, 0x49e74a87, 0x3f7bba07, 0x691606f8, 0xaac5bfd2, 0x28ab8575, 0xbc94dc40, + 0x2b851466, 0xac9baf49, 0x165aa8f5, 0xe295035c, 0x10919b95, 0x6bc8d673, 0x257798a1, 0xc9bcfccb, 0x3206f5d9, + 0x35f03f21, 0x2d1074ab, 0xff5c4d3a, 0x01fb31fa, 0xdc0985e3, 0xe392025b, 0x2742ffde, 0xa748259d, 0x7e23ebb0, + 0xa4ac7b57, 0x58bcd855, 0xbd4d012f, 0x4668ff35, 0x80a45e12, 0xa857040f, 0x73725d69, 0xa25a422a, +}; + +#endif diff --git a/src/modules/LR11x0/firmware/lr1121_transceiver_0103.h b/src/modules/LR11x0/firmware/lr1121_transceiver_0103.h new file mode 100644 index 0000000000..0d2070cd7c --- /dev/null +++ b/src/modules/LR11x0/firmware/lr1121_transceiver_0103.h @@ -0,0 +1,2157 @@ +/*! + * \file lr1121_transceiver_0103.h + * + * \brief Firmware transceiver version 0x0103 for LR1121 radio + * + * The Clear BSD License + * Copyright Semtech Corporation 2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted (subject to the limitations in the disclaimer + * below) provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Semtech corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LR11XX_FW_H +#define LR11XX_FW_H + +/* + * ----------------------------------------------------------------------------- + * --- DEPENDENCIES ------------------------------------------------------------ + */ + +#include + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC MACROS ----------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------------------- + * --- PUBLIC CONSTANTS -------------------------------------------------------- + */ + +/*! + * \brief Firmware version + */ +#define LR11XX_FIRMWARE_VERSION 0x0103 + +/*! + * \brief Firmware type + */ +#define LR11XX_FIRMWARE_UPDATE_TO LR1110_FIRMWARE_UPDATE_TO_TRX + +/*! + * \brief Array containing the firmware image + */ +const uint32_t lr11xx_firmware_image[] RADIOLIB_LR1110_FIRMWARE_ATTR = { + 0x5344cf82, 0x911b2526, 0x64873578, 0xd78f89a2, 0xff6fb7b5, 0x2a232f0e, 0x82223dbd, 0xc2a80c47, + 0x27869379, 0x1a9e71dd, 0x95c0e8a6, 0x840a2fe6, 0xbf76db44, 0xe9a65a38, 0x0890ea4e, 0xdc58bc3c, + 0xda2b66d8, 0x53ca71dc, 0xb53ae953, 0x3c5d0083, 0xc28af844, 0xebc443b9, 0x1912a6a2, 0xd4879700, + 0xdb072816, 0x99018cb5, 0xb4be1e5a, 0xce20d499, 0x4f46e7cf, 0xca4ed7d7, 0x6eb239b3, 0xb2aa5797, + 0xf644d94a, 0x0e42f1eb, 0x0ad62751, 0x1d95ce55, 0xaddc0300, 0xb26f4c1b, 0xfe90164f, 0x315d5167, + 0x153aefe0, 0x418267ef, 0x4c22158f, 0xbac22c11, 0xb3d8f639, 0x6edb6593, 0x889b8faf, 0xa62c91ea, + 0xb2786be3, 0x3c5d88a5, 0x118522c3, 0xce08b8f2, 0xefd420e9, 0xb634cb3a, 0xe5dbce02, 0x9e3e4048, + 0x11326bbd, 0x4f2ff14c, 0x3ec1ed38, 0x1b2eb4b4, 0xc95b972f, 0x070715fa, 0xd9922aee, 0xf0b15eee, + 0xda8ba45a, 0xe6fee752, 0x1d606d33, 0x19148a52, 0x3a26a5c3, 0x1b491bfa, 0x50fba80b, 0x5a0e8170, + 0xa2d009ae, 0x8af4f846, 0x883ab07d, 0x89738279, 0x32d0ab69, 0x1909da6e, 0xbf2a09a6, 0x63ef0f69, + 0xa6a10b2f, 0xf7da0d59, 0x00b66b16, 0x91681f7b, 0x68afcd2c, 0x35c52712, 0x93bfaf1b, 0x188de081, + 0x609c1e2c, 0xc793392a, 0xa91b8751, 0x08b6e3b8, 0x0c9c05a8, 0xd833a16b, 0x404d7336, 0xf8ea8097, + 0xa6c58ba4, 0x62d10e9f, 0x99b4c314, 0x87323969, 0xbd17aed3, 0x9474833a, 0xf308a22d, 0xcdeb15f6, + 0xb67a66c9, 0x8c6189a3, 0x8c7b15eb, 0xbe95a249, 0x9a936327, 0xc105ca58, 0xffeeda30, 0xf506b362, + 0xefb8d0e3, 0x35512008, 0x7f0e22bf, 0xc73547e6, 0x1e0d2017, 0x13aded75, 0x447a6377, 0x5073a357, + 0x0fb3fd99, 0x14ce5c86, 0xf00f83ee, 0xe5b551ae, 0xc964c8dd, 0xcbef9c5d, 0x59d2d8cf, 0x475353e1, + 0xe672b3ce, 0x759ef3ac, 0x4d1e615c, 0x667af315, 0x311be689, 0x6a2c1481, 0x46e89400, 0x947be405, + 0x4d3d3bcb, 0x02643631, 0x79f6df2a, 0xd4696a13, 0xef40a9cd, 0x0638982f, 0x5d44fccd, 0xeb2ea585, + 0x01a0a81c, 0x311d26ab, 0xe2583baa, 0x9586e18c, 0x7a51f3e0, 0xfc00a1a0, 0xf46cf767, 0x238b1d7d, + 0x976857b0, 0xdd6079fd, 0x06f93838, 0x9c95948f, 0x0e3016c7, 0x6d82de0c, 0x6dc55b10, 0x8bf6296f, + 0xbb7916e8, 0xf0d3c462, 0x49c19535, 0x08cc100f, 0x9ba49b44, 0xbe19707b, 0x57dcec97, 0x5034195b, + 0xc0908ccf, 0x5d0cc1f1, 0x4c75c544, 0x08c65163, 0x5ff134b1, 0xbfb3f8ec, 0xb349fa38, 0xb47d6be5, + 0xdb87b51e, 0x3b38a63a, 0x68e21481, 0x21dff7c0, 0xfd1423ef, 0xbed4013d, 0x38b9be03, 0x4ddd792e, + 0x2d4011e7, 0xcf962084, 0x402ee6a2, 0x532110d5, 0x65c0ce32, 0xb8bdf162, 0x4c74dd6c, 0x8d77c2f0, + 0x852b0aff, 0xe83c0f99, 0xb6ae4edc, 0x9a9dd506, 0x2b270d19, 0xc68a4615, 0xd27b0920, 0x324398f6, + 0xd5b26156, 0xebc857d1, 0x76b0383c, 0x20e4e3a8, 0x676403ca, 0x6f814ea9, 0x60bd6f81, 0xf59410ce, + 0x8b73d2a9, 0x9dc18ffb, 0xac2c84e7, 0x7778eced, 0x750395fe, 0x59fd8a3a, 0x2ffe807e, 0xa89b527a, + 0x10578b20, 0xe0673b9d, 0x3af57e3e, 0x5d61be31, 0x1397df0f, 0x6977c83f, 0xeeea75db, 0x50ac8878, + 0x55ee7df2, 0x052b5b93, 0x19f10f97, 0xe71dd1f1, 0x9a25dc23, 0x4c1144dd, 0x340b1bda, 0xfe776430, + 0x9abc9e44, 0x90ce5dc5, 0x0e44a9e9, 0x158284c9, 0x9768d0b1, 0xc0e365be, 0x8db02a38, 0xaaf8c3a7, + 0x0e1e835c, 0x006a04b4, 0xacfd4d81, 0x1e41e5b5, 0x48ae30a2, 0x2b9da3c3, 0x23985f10, 0x161f2b7a, + 0xe1191020, 0xc3c332c0, 0x1941934b, 0x3041f337, 0x1935d573, 0xd5432bd3, 0xec44b3c8, 0x5eeb7605, + 0x8fe14990, 0xfc24966d, 0xb1416286, 0xb48f1346, 0x89fadabe, 0x620db1f5, 0x8b440db1, 0x1b213b87, + 0xb78c6780, 0xc59dcc11, 0x9b6692ae, 0xad752b67, 0x9f2aff84, 0x1133de87, 0x75382786, 0x105f7c05, + 0x7b47fd32, 0x78dce915, 0xf547ddc5, 0xe8b29aca, 0xbf724c95, 0x58f2415a, 0x72244179, 0x167dae95, + 0x87b56c41, 0x9264e515, 0xb84afaa4, 0xf9acb2bd, 0x4e11b4fa, 0x909d30fb, 0x12669ff0, 0x028bbc26, + 0x355b43af, 0x61215f09, 0x60e6fee1, 0x42f1d535, 0xcdd04c63, 0x88a0419e, 0xc803a41a, 0xac048ce4, + 0xabe9adff, 0x148890b8, 0x69e06ebc, 0x4de9bfdf, 0xca1daa7d, 0xdc89ed1e, 0xa508646a, 0xcf0ef96d, + 0x05c00e73, 0xfd8d04a2, 0x670bd5db, 0x2877f8af, 0xbceeab7b, 0xd3c4419b, 0x563cf6f5, 0x76f1a47c, + 0x9822433b, 0x2ef857ef, 0xb360de7f, 0x598b7108, 0x1b7413fb, 0x20f76b04, 0x6a938b75, 0x89944650, + 0xc22c73c4, 0xdc28be20, 0x450a4384, 0x2a843dec, 0xc261827d, 0xb4882b2a, 0xc8e86dcb, 0xa0d69f4a, + 0x953d2ffb, 0x28402c11, 0x306f2699, 0x189aa532, 0x15341c98, 0x562b4959, 0x1b73f7cb, 0x81ab5be4, + 0xd4a2276f, 0x01eacba8, 0x27f01970, 0x74e69046, 0xec0540ca, 0x39582b21, 0x79cb991d, 0xfac1678f, + 0x9c665761, 0x3cef9e2d, 0x6208bd81, 0x50e0a87d, 0x7c9a868e, 0xcdfb5dc1, 0xffcca57b, 0x7384b92e, + 0x5b6d22ca, 0xbfccf810, 0xac14d037, 0x6090dd1a, 0xf029da9b, 0x7b35c283, 0x01f606bf, 0xc27a72af, + 0x34c68252, 0x55d23bd3, 0xf4468c8e, 0xff510339, 0xf072e67e, 0x512410df, 0xceaba164, 0xf657c6a9, + 0xaccfae18, 0x3ac4f3f0, 0x26f27ba5, 0x25693019, 0xe0510e0a, 0x77155df0, 0xd7bd676e, 0x0ffe81fe, + 0x1abd786f, 0x030fd48e, 0x96e77900, 0xd6ca457d, 0x56b85760, 0x772bbc5a, 0xbfb67dbe, 0x8961342d, + 0xe6479bbb, 0xe3364d50, 0x75abc7ee, 0xa79063d4, 0xdafb1139, 0x502d8935, 0x990c1282, 0xc774348a, + 0xdd94f27b, 0xb4b3ebee, 0xcf29128e, 0x210c5dba, 0x1a90e9ca, 0xa1d242ce, 0x422bf1a6, 0x71307dae, + 0x6ac58155, 0xa0a9a775, 0x92c45459, 0x02dd0633, 0x600a30f5, 0x0a5b36a7, 0x41146625, 0xc00a0a23, + 0xf98a355c, 0x6e3d207e, 0xa7705537, 0xa5f0ee94, 0x962eb7e2, 0x641482e2, 0x5631ee92, 0x83688926, + 0x377d3974, 0x2180e743, 0x8e2b8590, 0x36dc6589, 0x4ae494ef, 0xb0ffbcce, 0x45781529, 0xa2b92fe9, + 0xbf8c3291, 0xd92ce914, 0x9cdf7e8c, 0x933d0d89, 0x2e0f619b, 0x2e68c846, 0x17d961b6, 0x108bb773, + 0x5d5088b0, 0x565be7bb, 0x5371a9ac, 0xcbe9072d, 0x28ceb54b, 0xa7c7edec, 0xc2b4bee5, 0xbfab73f6, + 0x176ebc63, 0xa1205b4a, 0xe3fdb4c0, 0x27f73c5f, 0xdf100378, 0x76e3bb2e, 0xab2f4c82, 0xfa349044, + 0x938048cb, 0x37ea0cc2, 0x2db67d7c, 0x1d8a4fb5, 0xe15a564c, 0xe4222dd2, 0xaf47c73d, 0x6a7a6185, + 0x1059e1a1, 0x10945bbb, 0x5b3e2695, 0xaef27a38, 0x8a9c831e, 0xf3deb6ce, 0x769db12f, 0x6f792574, + 0x9289787b, 0x144c603f, 0xe60bca75, 0x716d2ded, 0xe5b5843c, 0x52efcc04, 0x1532e238, 0x9843ef54, + 0x94e4fb8e, 0x588f4305, 0xf796f4ec, 0xf413e910, 0xa193ed14, 0xa9084a37, 0x2db5271f, 0x41bea322, + 0xffb528b7, 0x8f6e9f5f, 0x6b8fdcf0, 0x5c853cff, 0x0ee0ae99, 0x473ce598, 0xea491e04, 0x6c495244, + 0x1be66c90, 0xd747b1e5, 0x01dab1e1, 0xe4439a27, 0xa0b4b76d, 0xa86f98fd, 0x5d947a71, 0x2d385faf, + 0xfeaa3ed5, 0x47fb4c5a, 0xe3a67f15, 0x434569b1, 0xe0e46b05, 0x34fe31ac, 0x386f77dd, 0xa9c918c1, + 0x04441f48, 0xfe08456d, 0xcef31b7a, 0xfb3d85a8, 0x6f94cb9d, 0xc085b6b1, 0x82653ba2, 0x3cbb2798, + 0x70a85aca, 0xf69e8d10, 0xd05fc0c4, 0x8743b18c, 0xc993f077, 0xec0323d5, 0x6d56fd9c, 0xf67711c3, + 0x3a42d332, 0x99ae8889, 0x2b6e896e, 0xd7937343, 0x6cb07572, 0x8d300f05, 0x8671832a, 0x03a1b773, + 0xaafcf414, 0x3987965a, 0xf3e20eb4, 0x8a87a4c0, 0x27f46504, 0xfc84532f, 0xbb590e07, 0xed5af822, + 0xd68fd6b8, 0x6420cb2b, 0x7ce30872, 0xf2eb6df3, 0xe2759533, 0x896aeee3, 0xc3e8eaee, 0x3640cf10, + 0xa941cccd, 0x36512530, 0x1896c194, 0xf77eeff2, 0x72e79db4, 0xd6445a5f, 0x7298fa36, 0x508161db, + 0x5ade65b9, 0x0182183d, 0x9bf47782, 0xdc2037ff, 0xd44b3601, 0xcb53434e, 0x04d242cc, 0xb5145c95, + 0x531b4474, 0xec8e1b2a, 0xa39d287e, 0x18e410a8, 0xb77e0475, 0xa89c6c0c, 0xf4601569, 0xe5776e2e, + 0x4dbc2447, 0xa5de958c, 0xea41a251, 0xc5944ba9, 0xafd4335c, 0x8efaee58, 0xd5bb4570, 0x94056402, + 0x96c95c3b, 0xa94eb9ca, 0xe03b81aa, 0x812ddc20, 0x81139c9e, 0x7872034d, 0x9d3d4323, 0xe5770d21, + 0x7971bfdf, 0xa97d2b90, 0x01821599, 0xa50ecbe1, 0x68ec4e76, 0xdf5b179b, 0xeebdbe40, 0x3a7585e0, + 0x542be718, 0x94b13340, 0xa1c3a84e, 0x5d2f0fba, 0x253e9988, 0xc78c8b0e, 0xe0b481ec, 0x28ccce15, + 0x7cc9a4ae, 0x25654986, 0x63e487a8, 0xdb210b65, 0x25f96b07, 0x7b66532a, 0x7f28c722, 0xeaab0e11, + 0x41c2c6ac, 0x511b2fae, 0x34157ade, 0xa0abf4bd, 0x79f37d0b, 0xbd94376e, 0x8bf8d4b0, 0x06044f10, + 0xae2353a9, 0xc32e79bb, 0xc657448e, 0xb4ba2a35, 0x57c1e2d4, 0x8c4537de, 0x74c5bc4a, 0x57604b57, + 0x764e2cb8, 0x6ad472d3, 0xde41af33, 0x30cde4f5, 0xc5eae912, 0xfb9134a5, 0x3046e91d, 0xed7a2df4, + 0x78fa11c6, 0xb95c347a, 0x870ed551, 0x2a1e230d, 0x4eb9c93b, 0xca102ed7, 0xb34023b3, 0x075a7306, + 0x273337cc, 0x9ebef1d7, 0xa589a101, 0xf0655d59, 0xb8f5ea0f, 0x46aafc42, 0x6e5d51b9, 0x2928f6e4, + 0x9bc7476f, 0x49193175, 0x3600214c, 0xa9d31344, 0xfadbb3cf, 0x6a3c5eaa, 0x4f1e15f7, 0xf7263c2c, + 0xc26809cb, 0x81852159, 0xf5dc1325, 0x46854416, 0x685861d5, 0xbb9f21dd, 0xddb299a1, 0x586effb1, + 0x537f6365, 0xdd07507e, 0x66306f20, 0xe8e1d218, 0x6ba0429f, 0xf28be742, 0xaa126107, 0xc25e2906, + 0x9070825a, 0xe148ff86, 0x9b340918, 0x2b198c4e, 0x6eb4667e, 0xeb247132, 0x1078e376, 0xdaf09be9, + 0x1b395c1c, 0x6629c6a1, 0xfa337115, 0xb88ad8fc, 0x15628cd4, 0x2b05b1d1, 0x3584b81e, 0x93c23ea4, + 0x9abc21b3, 0x082a51ff, 0xc3abee4f, 0x3612922f, 0xdcee92c9, 0x27fb9750, 0xeb6994a6, 0x3861c511, + 0x833d4378, 0xf84e214b, 0x08f2ca2c, 0xe95c4dcf, 0x86633471, 0xfb0fc3c2, 0xd8c6d223, 0x88e18bb0, + 0x7dedf8cb, 0x610fb1b0, 0xebf6e8a0, 0x504fecd8, 0xb4d664ea, 0xb7b0f295, 0x0ec6a182, 0x55e63f93, + 0x6e58619a, 0xb4e58826, 0x28903ab6, 0x6a144499, 0xec53d99f, 0xeb60069c, 0x3bb8507a, 0xb5cf4ba6, + 0x959c6bb3, 0x6c5d2835, 0xe54d35a4, 0x8ce92e37, 0x8a8e4207, 0x6e7ddbff, 0xe079f01c, 0x85f13d2c, + 0x35d7b581, 0x6b830bc7, 0x2754d7b2, 0xd843eba1, 0x2899ea93, 0x41aacdbf, 0x48bd0830, 0x7a411f30, + 0xa050daeb, 0xc2252413, 0xa6c0c68f, 0x86624499, 0xd91424eb, 0x01fa540c, 0x1209082c, 0x2beb5e27, + 0xbc1942bc, 0x277bc2b1, 0x67d62300, 0x84f95cdb, 0x2c660272, 0x3c24b9ed, 0x0f9508fe, 0xce7e883d, + 0x3f479f50, 0xb21063f5, 0xc88bb3af, 0xf7decb4e, 0xba6194c4, 0x1dd2da49, 0x7d550d06, 0x37d865eb, + 0x9e5b4073, 0x3cc7e24d, 0xd3fdcabb, 0x15137cd9, 0x9391cd7b, 0x9530fc40, 0xa2f32773, 0x26414307, + 0x78631f9c, 0x81b084b0, 0x94fff1d0, 0x05b2f7bc, 0xf38e13d2, 0xe663018d, 0x2aec71d0, 0xfe88ca59, + 0xedc67eb6, 0x7e1c27e8, 0x31527b0c, 0x250d3e7b, 0x0d54c91c, 0xb0e4b535, 0x530a3d47, 0x487237ac, + 0x13ffa347, 0x6111c0d6, 0x8f6d2400, 0xf7a66783, 0xaee1939e, 0x8e4c802c, 0x68ab0bdb, 0x9997fbaf, + 0x12080868, 0x03c1c6d1, 0xf05b7afa, 0xa39c88f7, 0x8c67e588, 0x720e8437, 0x45b869e8, 0x167fd164, + 0x50ab3495, 0x1c223dd9, 0x229dfff1, 0x0ad0eab9, 0x59c8da20, 0xce935ad6, 0x6332f91f, 0x39f62538, + 0xa49c029e, 0x233ff99f, 0xa1528215, 0xe2797b7c, 0x86cabff1, 0x5df21fd8, 0x3e18deed, 0x317a8ad4, + 0x048ec35f, 0x514f302b, 0xcefa4cf8, 0xc6c8f588, 0xe4efb6f8, 0x855e70fe, 0x3beccb98, 0x668645e2, + 0xfc418622, 0xaf1b3960, 0xd58a9a71, 0xd5ead730, 0x83b795df, 0x3466713b, 0x1be417b9, 0x2efe4b91, + 0x5b4a15ef, 0xda35bac4, 0x1cc87d2a, 0x99bc2ace, 0x0012a958, 0x3e043788, 0x9b02ac8e, 0x5de22a56, + 0x39a98c5a, 0x94f2b977, 0xd583d740, 0x64dba4a3, 0xa02beea8, 0x80633a39, 0xbed9d176, 0x744ecca2, + 0xb22e1d3a, 0xa5e5f7a7, 0xa1f987a5, 0x3852a2d5, 0x91be1191, 0x38b07aed, 0x628715df, 0x19e6abdf, + 0xf70c891b, 0x0ad380df, 0xa7f08d5d, 0xc7e2bc92, 0xa0328b0e, 0x2bd615ae, 0xe164a7e5, 0x187e56fa, + 0x8e8619e4, 0x8353968f, 0xf39dc3ad, 0xbb8b706d, 0x270044fb, 0xdea6bcb3, 0xfe5fe18d, 0x9e584e4a, + 0xd4002aaa, 0xd116a794, 0x01bd30ed, 0xf4709509, 0x1cf35643, 0x90d74fac, 0xb1203378, 0x593eab56, + 0x8abc5a29, 0x8b4509bb, 0x0b576a21, 0x3f470859, 0xd0516523, 0xc6da69de, 0xfb69730d, 0x8a476e1a, + 0xa5f75b20, 0x8c956308, 0xf555bf49, 0xe74278a6, 0xdce73674, 0x2953fa76, 0x71495108, 0x578a4aa9, + 0x6ecfd365, 0x7a0083ca, 0x5b5575cb, 0x8df7068f, 0xb36319d0, 0xd0b6d2ab, 0x327ecd08, 0x1cb3cb2a, + 0x4e56b862, 0x25e5b7ce, 0x40e53b90, 0x13af46f1, 0xccda7d40, 0x2ce7d6b2, 0x8839bb4b, 0xda40b71b, + 0x520c8092, 0x33ac09c3, 0xe536de11, 0x6a6943a5, 0x8619fcd9, 0xb091419a, 0xd8aad57f, 0x0d6506d1, + 0x62636896, 0xe5be0308, 0x42fe6b90, 0x4cf26076, 0xbb7e4bb1, 0x7eb98b1a, 0x125351d8, 0x1be08b72, + 0x04c8b999, 0xe3e4e559, 0x201d4590, 0xaddb625c, 0x2c8e5b41, 0xa9addc42, 0x3e437f44, 0xd1cc6a99, + 0xdae50f7b, 0x147ba131, 0xf2cd883d, 0x5efa3b8a, 0x2078d215, 0xf5e49483, 0x0f9e5664, 0x6c41aa04, + 0x4c78d4a8, 0xcc580552, 0x8862093d, 0x9dc26a6c, 0x6cc63066, 0xb4aba040, 0xc6b059ae, 0x88c668e7, + 0xf094c148, 0x50355068, 0x47ef21f9, 0x216fb854, 0x136de922, 0xcbd2b83b, 0xdbf81dc6, 0x1b281870, + 0xb0f75cb8, 0x3d8e0b80, 0x67a60b2a, 0x62ed01e9, 0xec6728a7, 0xc0e1563e, 0xe2793d2f, 0x22f09861, + 0x53f0c782, 0x068eeee2, 0xd8d4fb1c, 0xa3016ade, 0xe61c6c93, 0x6a30d8c9, 0x20957875, 0xa3463b4e, + 0x01b15821, 0xe165e3a0, 0xd950b3c5, 0xdc635d79, 0xf3c979af, 0xd955130d, 0xccc119e9, 0xbd59c38f, + 0x3fcc9221, 0x57418b56, 0x7a0c0c2d, 0x0758a7c9, 0x60018c86, 0x699806f5, 0x9c864d2e, 0x5de2998e, + 0x9a5422aa, 0x3788894e, 0x0397d3a5, 0x95624318, 0xc09d0287, 0x6e579203, 0x09b017ec, 0x141668cd, + 0x4e59eb0c, 0xe5744721, 0x67afe320, 0xbcb0949f, 0xa91c6128, 0xac1252c7, 0x6d212827, 0x1481e538, + 0x679ca063, 0x617e8a0d, 0xfb0f82c0, 0x8c5f826c, 0x287c5f7e, 0xcfeb0f83, 0x928fdcf1, 0x500ae093, + 0x82343191, 0xb0fd6c34, 0x02d27767, 0xe1e16fd0, 0x64ecf346, 0x866b0773, 0x2d474451, 0x5cc7ef72, + 0x563330f9, 0xe0f9ab11, 0xa3bb32f4, 0xd512f721, 0x965bf591, 0xfbb7f0e8, 0x9cdbb91e, 0xab477071, + 0x74ffe8e8, 0xef0a8de1, 0x4b46bf6a, 0x213d175f, 0xdf8b998a, 0x6a211a8b, 0xd4c1e7d9, 0x8eddb4c9, + 0x292b25ce, 0x2de07da1, 0x3ee157da, 0xdc292b59, 0x45dc012d, 0xc88c40e7, 0x4f39162d, 0xfef5d4a6, + 0x33bcf477, 0x79253ac7, 0x349a6b50, 0xf58007e2, 0x2a4297d0, 0xf09ce56f, 0x08dc7bba, 0x7bc968ce, + 0x1f463610, 0x714e62fb, 0x6d1d9932, 0xbf1bd783, 0xd60ad02e, 0x2596f751, 0xee14e7d2, 0xcc0c6e1e, + 0xf9789b79, 0x3ffbd95f, 0x85fe8a3d, 0x6adb0497, 0xe3903d20, 0x469bdba1, 0x9bc00def, 0xef9f668c, + 0x3f695269, 0xdbfc6f20, 0x0bf7a0b4, 0xaca996aa, 0x52749d80, 0xfbcad677, 0xf2888101, 0xbe09463b, + 0x2c669477, 0xa9ad1a99, 0x8cdc4f57, 0x73f5143d, 0x40dcf61b, 0x6cdc8191, 0x6c364ea3, 0xa50f63b2, + 0x42d08408, 0x33ccbfb2, 0x0b6c5ba0, 0x6652bdf3, 0x17a676a4, 0x4d84d94f, 0xc72357cf, 0x0789758e, + 0x5100dd5d, 0x3df52b10, 0x4c44b70b, 0x8dc24b72, 0xfc1a07e6, 0x928ab35f, 0xe492606b, 0x8fd1a9ba, + 0xbbc2f016, 0x2769231a, 0x92a065cb, 0xc27f3a0a, 0x7051336d, 0xbcf3ec19, 0x4733a0df, 0xc23211fb, + 0x0df40450, 0x55aa426f, 0x388e29ac, 0x23df95d4, 0xf4011be1, 0xab5018ef, 0x7215dc81, 0xde0f9727, + 0x3a07f6b5, 0xc61ba482, 0xa839e562, 0xb4b4d983, 0x75492f47, 0xe260e796, 0x625b7fc9, 0x6f05653e, + 0x5f181d15, 0x54873f00, 0x6b30f316, 0xd5f4cae6, 0x377b1fcb, 0xc8c83907, 0x5db9107c, 0x37a2d790, + 0xa5760fe4, 0xc6df7311, 0x651e9f11, 0x46bfe43b, 0x3f902b3b, 0xe29f57e1, 0xa0038d0b, 0x64dae471, + 0x7b5082cc, 0xf6b0b56d, 0x478edb97, 0xa422efbf, 0xcde39c87, 0x49944eb9, 0x25f5b957, 0xa576310c, + 0x7cabfa92, 0xae0c5e45, 0xac3723f4, 0x9a7ed680, 0x5fd2c073, 0xdd2d7dbe, 0x8f2de9a4, 0x7d856fec, + 0x6ce27cbf, 0xbfdfb801, 0xe509c502, 0x4f849206, 0x0d9c866f, 0xd0aeb42d, 0xf5ac4d85, 0x2ea7d31e, + 0xc369ce8c, 0xf34cac28, 0x2122388d, 0xd71d0ab9, 0x77b860a2, 0x68ac5d26, 0x0575b8c2, 0xd2d6c51a, + 0x8962bc71, 0xb1f4f0d5, 0xbb7c4b8e, 0x9847c0aa, 0x9637cc55, 0x4c2014cc, 0x8122c8f7, 0x699a79ce, + 0x0ecacfb0, 0x136bf119, 0x89608baa, 0xb041e218, 0x1239d2e8, 0xdb34e0d9, 0xf2210bab, 0x28369894, + 0xb780c9a2, 0xe0c8ceed, 0x2909edd2, 0xd1a57c98, 0x36341ecd, 0x917eb654, 0x27aa913f, 0x6e5df1f5, + 0x24a10ade, 0xec4bd958, 0x81dd0127, 0xd65009b7, 0x503bd9fc, 0x164a94df, 0xa0fb108d, 0x26f323aa, + 0x1486a5ed, 0x5b5841ac, 0xdb8415a5, 0x18bca2fd, 0xa38d4fcb, 0xbf61134e, 0x19222f18, 0x4c4b362d, + 0x404c1757, 0xa60edd60, 0xd24860e9, 0xaa6a306c, 0xb1e85b2f, 0x10a9aaef, 0xaa5db9d1, 0xf1f51e4c, + 0x3e801de1, 0x06b79fea, 0x37b99f2e, 0x49319645, 0x609413e5, 0x9ea9e1b7, 0xacb66240, 0xc2056591, + 0xa5c51e6e, 0x06036044, 0x5922c588, 0x3b4a45f1, 0xe0680471, 0x57981ebb, 0x694c77b2, 0x9d683bd3, + 0x4fa9c8fd, 0x9a8011d5, 0x0fcc44e0, 0x1f2ac53f, 0x63bc14f7, 0xf296bedd, 0x0d52ba51, 0xf8042525, + 0xd8e519e9, 0x1570406e, 0xf765c56e, 0xafb19cfb, 0x8892a7e8, 0xe5077d08, 0xff5ab16d, 0xb6ac6d0c, + 0x6696cb61, 0x9a268e88, 0x4d8503e9, 0x671121a8, 0xf37bb714, 0x1d798c84, 0xe147c48b, 0x716ebd06, + 0x70126d24, 0xe4df6378, 0xb67c52c6, 0x6bee37d3, 0x310a36fa, 0x126bc1c1, 0xbf7dbfb8, 0x669adf45, + 0x40b3d35e, 0x5309fd9c, 0xb680ded0, 0x63839ca3, 0x34521bbf, 0xef18d0ca, 0x23a64ed8, 0x19da8920, + 0xee86bd28, 0x8c928007, 0xbdb37038, 0x660d8054, 0xb35f9b66, 0x9668315b, 0x3944cbf7, 0xda224139, + 0x605af7c5, 0xeedca516, 0xfe40f443, 0x2bc392c5, 0xed1dacb3, 0xcb9e5802, 0x8a14f1d4, 0x621b6c8f, + 0xfc9343cd, 0xdc02fcba, 0x9eb64778, 0x210d31fb, 0x6152b066, 0x768acb37, 0x1e31a4cf, 0x15a0710a, + 0x3e2e0a02, 0x48d80ba6, 0xbe5f0f81, 0xbae72df1, 0x039924c0, 0x0da67edb, 0xb3beacbe, 0x24aebeff, + 0x97672fd7, 0xa74ecb0f, 0x5c6558d1, 0xa5084951, 0x5487d2d0, 0xc118a020, 0x7454902c, 0x62f9bee6, + 0x19b7774c, 0x0335038b, 0x1abd414f, 0xc7c5dafc, 0x90791ca1, 0x137e9afc, 0x33696240, 0x98b48534, + 0xcaecdfac, 0xb3080475, 0x27c0a007, 0x7b9a5596, 0x2efb3ba1, 0x76998e2a, 0xae430991, 0x393a95cc, + 0xb035bf95, 0x6ec8458d, 0x4f4c04b0, 0x477c9b43, 0xd970923f, 0x888c838f, 0x15ed8474, 0xf38a4ed4, + 0x81ffe3c3, 0x8d40c865, 0x510ac0c3, 0x90a89b64, 0xc491d71e, 0x919ed88e, 0x67e310c3, 0x37fd9ff2, + 0xe9d91714, 0x81fd6582, 0x614d6b80, 0x30767104, 0xea48cdf8, 0xf8be9b10, 0x6b60c2a7, 0xb1f649d6, + 0x69a05418, 0xdb5c70d7, 0xad2d5521, 0xd7e80a20, 0xa6e3b306, 0x263c90cf, 0xbfd30910, 0x6c903798, + 0x5349ac17, 0x3a1d3bb8, 0x7888c98c, 0x357431ad, 0x29cb83bb, 0x8159513b, 0x9315eea8, 0x1706c2ac, + 0x240cddad, 0xfc9ea962, 0x217ec572, 0x429bf78f, 0x836a3aaf, 0x5225163c, 0xf4dada31, 0x8b0985e3, + 0x86f4c289, 0x937217a4, 0xdbf172ac, 0xb1110ab7, 0xba39c3c4, 0x0622b3aa, 0x8d6b94bb, 0xf07a3c68, + 0x97a4b4fd, 0x0324ffd7, 0x207c500d, 0xe8c1a355, 0x561d82b1, 0x06cd2598, 0x4c4dde0c, 0xf65e9f95, + 0xb23d6706, 0x50a504b7, 0x45ade60d, 0x74d2a8cf, 0x123f0fbc, 0xd3a81111, 0x911f1dbd, 0xb32d99d8, + 0xb6c7a52a, 0x0f44c2cd, 0xbff4d99f, 0x0f3be894, 0x752d18a5, 0xc26a7139, 0xd89a4f7f, 0x1ac3db7b, + 0x4092fcd7, 0xe135cc86, 0xfcf7f77e, 0x0692b03a, 0xcdb23c6b, 0xad922899, 0x34d662c1, 0x5df062fa, + 0xd004f55e, 0x454044c8, 0x0dfd97cc, 0x8972f940, 0xf1c5a0f1, 0x2bd9d3a4, 0x45c8ee1c, 0x4fc49bf4, + 0x68d37389, 0x7c3f229d, 0x1023cb94, 0xeccfb3c3, 0xcd2a9591, 0x29de6999, 0x6d0149c5, 0xf3363dbe, + 0x642e9f42, 0x84fbc90a, 0x87d21a45, 0xac5224b2, 0x4be514ca, 0xd50f6d64, 0x52c15174, 0xb6500665, + 0x83c196e6, 0x60465d20, 0xd919362c, 0x4a5d1088, 0x9e2f620e, 0x28cea280, 0xd5a8b0f9, 0x56645bc5, + 0xf4a76b0d, 0x4f35750a, 0x0b14fd56, 0x0f0b78c9, 0xe7a8a32a, 0xfd7ceb52, 0xcc55e4c2, 0x3889dc3b, + 0x075c13d5, 0x78254aeb, 0xcd400fc3, 0xd1409ed6, 0x30cdef19, 0xd11bab15, 0x23e13c36, 0x8217a037, + 0x88322e3d, 0x9898c305, 0x0bea8dad, 0xc82db305, 0x6c2293a3, 0x3681ce71, 0x20674f46, 0x9451f276, + 0x75b84e5b, 0xf6bb0408, 0x8203723b, 0x50d822ce, 0x1ea99afb, 0x71180c41, 0x0ad26049, 0xa3f34588, + 0x07665443, 0x2c04c65d, 0x902ef91d, 0xc04a0d1a, 0xd31f7e36, 0xa248db82, 0x84dbdb8b, 0xc081831d, + 0x776c5753, 0xf8b8c244, 0x9907bbf0, 0x906414d3, 0x2eb9cb1b, 0x99714a43, 0x20b5fe26, 0x2786b564, + 0x57a09715, 0x4b54c798, 0x0a5f248a, 0xbc47855e, 0x49897469, 0x313c25a6, 0x9f305852, 0x258b7fcc, + 0xee8d2477, 0xd7ac9c6c, 0xe070b498, 0x85b4ea80, 0xec8c0d2e, 0xd3dc0622, 0x8c1481fd, 0x62ebc63b, + 0xdabaa12b, 0x9aa83791, 0x2903dddd, 0x256de6d4, 0xc77b20ee, 0x670cc6a9, 0xb0a27d2b, 0xa5eefc4b, + 0x6037f54a, 0x4487b46f, 0xb9d2a3a6, 0xd7a9253c, 0x16081cf1, 0x73a135f0, 0x53df89c7, 0x8215b7c2, + 0x7eef8a9e, 0x82fb2bb2, 0x745c75eb, 0xe0edceb2, 0x499064e2, 0xfa483635, 0x383c166c, 0xdb7b5eb0, + 0x44799e1b, 0xa3604985, 0x645fe667, 0x70405746, 0x56148378, 0x695e28d7, 0x5c592227, 0x5c352420, + 0x140e03f0, 0xbe51eff4, 0x7f617b60, 0xb005b456, 0x9a56877f, 0x2d941c2f, 0x75f138f9, 0x9ee05377, + 0x1bef5d65, 0x6db1facc, 0x06870c3f, 0xd224e181, 0x3165d53e, 0xa97e5b51, 0xd7de9ef2, 0xacaafe1c, + 0x2182ecb5, 0xbcaf24ff, 0xde6dc72b, 0xe58598ad, 0x05f8a4a5, 0xff2bea0e, 0x07f21fbe, 0xd149a0c0, + 0xaf8f6cf8, 0xaf90face, 0xdf9d0cd6, 0x68a1c0ce, 0xa260e65a, 0xe859ba32, 0xec4d0171, 0xf3f82ee8, + 0xe2bc858a, 0x5b02a722, 0xfa7b4f91, 0x40935489, 0x2ed24424, 0x2d7f8232, 0xd7dd2633, 0x2baf7e2f, + 0xc811f658, 0x15e0d42e, 0x845718b4, 0xda70ced7, 0x0d6af3ea, 0x315551b2, 0xfcec6360, 0x43787b5b, + 0xcf55822e, 0xff3fb9a7, 0x962b8a1a, 0x6e5f8fc3, 0xcc1d5ea9, 0xd0fb0bf6, 0x592c314f, 0xf2ac0cb7, + 0x97e4b0f4, 0x5219537b, 0x8074b167, 0xaf495c81, 0x77f44f0d, 0x0698ec3e, 0x4429d908, 0xec357920, + 0x789428e3, 0xf1ce05cb, 0x525f85c2, 0x789aab86, 0x4a7492a8, 0xc0db168a, 0xecba712d, 0x60f4e893, + 0x4a12d51a, 0x9cabd82a, 0xb83c53e0, 0x284bdbf9, 0xf5ae2e0f, 0xf5f44d2c, 0xa2abf00d, 0x189ded95, + 0xf4ba7471, 0xdf74b71e, 0xbdf30745, 0x14c6bb1a, 0xd47e1fb6, 0x88299417, 0x03888198, 0x595eab77, + 0xc88fde94, 0xc03fa31b, 0x7468de33, 0x13660a39, 0x344271e0, 0x6a11c241, 0xf0c6892f, 0x475a3d50, + 0xafd978c6, 0x48bf87a5, 0x313b909f, 0x987e733a, 0x5abccdde, 0x7edcc9db, 0xfd5d7926, 0xf6aec1ae, + 0xce18862c, 0xdb7dd57d, 0x3d5dd8f8, 0x6d5d178d, 0x2cad1ae5, 0xbfd90b44, 0x01aff37f, 0xd6786aef, + 0x943f7e79, 0x8165313d, 0xdc741313, 0x858e7424, 0xca81e5ec, 0x70ccc9cf, 0x13f0614a, 0x55492547, + 0x02d85a34, 0x47c20df1, 0x09b932c5, 0xa1deebcc, 0x1dd2b893, 0xae106e29, 0xd7f7c9e9, 0xe91a57d6, + 0x0cf4fffc, 0x334851ce, 0xcb4cfffd, 0x7b13cd00, 0xfa015e6e, 0xbf6e1afc, 0x2e82ea62, 0xecf95355, + 0x4d5e1ede, 0xe67beb5b, 0xa20d9671, 0x303d55f1, 0x33ae63d2, 0xab4e78a5, 0xf27bd1fc, 0x5145c540, + 0xa3bc5edf, 0x0a0b49f5, 0xbb6d338d, 0x9f804bcc, 0x3a2570ee, 0x5b56b9a0, 0x0e500486, 0xb3680694, + 0xe805e553, 0x7be1712f, 0x8b70ba5c, 0x0dc88f8e, 0x9f0e8760, 0xe0492db2, 0x27a329b6, 0x6fc5cd4b, + 0x606b3e45, 0x7e5b9080, 0xc4a2190f, 0xcd6b6d0f, 0x0de68fe8, 0x9c27e5dc, 0x26f9692c, 0x3b484cb0, + 0xfc2b57b8, 0x30ec967f, 0x489f6e88, 0x9cc3b439, 0xd9c96eca, 0x0cbc0a9e, 0xe5cac299, 0x2afbc4b4, + 0xadb1485c, 0x819e8f7a, 0x29269a79, 0x4bd4ce66, 0xdd0de4e2, 0xd0b3bfbb, 0x761f7d41, 0xcc83e19f, + 0xcf7ac2d7, 0x024004f2, 0x7bc280c8, 0x07bf49ae, 0xd26dca18, 0xf0e9c930, 0x9190459d, 0x92116976, + 0x49c8cca4, 0xecbe4169, 0xec50e6a5, 0x2808a5a9, 0x7841ab27, 0xd16d8a52, 0x9bef4565, 0xbc3893f4, + 0x24ee907e, 0x4a4df8a5, 0x710840e4, 0x315cc712, 0x3fa32aa9, 0xd23fe3e6, 0x77aa8548, 0xd644128b, + 0x15cb4bb6, 0x5e6e05dd, 0x35b06a9a, 0xbd05a6f2, 0xe153eabb, 0x419d3206, 0x5202a005, 0xdc2f8a15, + 0x89b3f4ea, 0x4f369368, 0x52b98cb1, 0xaa598fc9, 0x1ba7095f, 0x5971be09, 0xae1a3ad6, 0x3870c8aa, + 0x58b44661, 0x37b9d07b, 0xa110bc27, 0xae07e8fc, 0x20acdca6, 0x6e737a8c, 0x0341a92c, 0xdb1410d8, + 0xef892dd8, 0x15719095, 0x26f0c2ab, 0xf61f4ce9, 0x8b293681, 0xbf300edf, 0x916e2b21, 0x78ad2f01, + 0x12bc700d, 0x27171e6f, 0x9d8382dd, 0xfa5ce39a, 0x6cbc690a, 0x7e38af91, 0x77f77da7, 0x3b466cee, + 0x63dfe1cb, 0x2e9716df, 0xe9d690f5, 0x863910ab, 0xec045596, 0x9a3fec42, 0xef4971b1, 0xc10e8b29, + 0x5d51cfbc, 0x16825358, 0x3e411896, 0x66a588be, 0x8620c876, 0xf735fd2e, 0x80adfcde, 0x0b46ff73, + 0xce90fecb, 0x570d92df, 0xf28f7f29, 0xf4adc542, 0xc9b7790f, 0x0cd65c17, 0x9287ff43, 0x237e806b, + 0xe21bd8b5, 0xb880efbd, 0x5a0226f7, 0x476adcd5, 0x5c6f03a7, 0x1691b335, 0xd6757db7, 0x05ec9865, + 0x8be23c7c, 0xe0aa5ead, 0xd0055b91, 0xf9b3b578, 0x991c75d3, 0x0c09ccb9, 0xbea63127, 0x880cf9d0, + 0x0edd8087, 0xd606d5bf, 0x8949c45d, 0x19232da7, 0xee44c924, 0x1837b7c9, 0x7dc0b438, 0x1b786dc1, + 0x2f9c5589, 0xcbc48f76, 0xd935646b, 0xbc0ba874, 0x085b8e84, 0x5510f734, 0x48cde282, 0x1c3af3e8, + 0x126cd482, 0xb5dacb52, 0x44d341bc, 0xdcd9c943, 0x3fe60473, 0x3e5a6f06, 0x565cf39d, 0xcf1ce4ed, + 0x09b1c942, 0xb646b750, 0x217d90ff, 0x49d5b8df, 0x479849e8, 0x660c1d07, 0xae06ee62, 0x187a7bc4, + 0x6795eb1b, 0x5246af0f, 0x45f2f018, 0xfc713adf, 0x59bc11ea, 0x510cf363, 0x2ad035df, 0x112763a2, + 0x711e6a34, 0xc23384db, 0x76d12155, 0xc721d58f, 0xed8fe104, 0x58336164, 0x503c40ba, 0xa2b0b1f5, + 0xc0e72038, 0xa411d2d1, 0x664ec444, 0x01d1d682, 0xc560a374, 0xc6f4a396, 0x692a98d0, 0x710d5d09, + 0xb97fe98c, 0xf4fd116e, 0x2b73229a, 0x6ae4b2f0, 0x718cfb63, 0xfe346b41, 0x0cd66a52, 0xdde185fb, + 0xdb38d34a, 0xbac48890, 0x783123a4, 0xd39fd0d2, 0x04904df1, 0x4a235340, 0xc5490f29, 0x61b8d633, + 0xd82173a0, 0x6bb7ba6a, 0xa31017e8, 0x7bd21e40, 0x1a3fdae9, 0x31a2a271, 0x7a9a8267, 0xca1179e2, + 0x9e13bdec, 0xd5f83b47, 0xae3a5180, 0xc0959fb6, 0x1b38b6cd, 0xc3cbe90b, 0x16ce9349, 0x3e7571cb, + 0xe34b2d07, 0x54c24c67, 0xaa3afaf0, 0x5ce57178, 0x12168763, 0x1eb8c07f, 0x1b16697b, 0x99491c90, + 0x0e632013, 0x7cc11860, 0x014fa705, 0xf6821250, 0xcc4f344f, 0x570f76f7, 0x2be2e88a, 0x16a54c0a, + 0x730de6bc, 0xeab118f2, 0x9c411687, 0xd86104be, 0xd6734764, 0x147ce7bc, 0x73c3d89a, 0x2ad2732a, + 0x91568844, 0x7087434f, 0x2a0c8792, 0x9b72ad49, 0x5137c4fd, 0xad24bae5, 0xa10dc66a, 0xb1fc4c8d, + 0xefca2d39, 0xa2509b12, 0xdfa06883, 0xde6dc76b, 0x7b25f6ed, 0x6531ae9b, 0xdaaa8063, 0x3163cd47, + 0xe0296315, 0x47d13fe1, 0x77eaeae6, 0x9e396b45, 0x20b6543c, 0xbdf40ea4, 0x0a9c02ab, 0x432d9c5e, + 0x4ff30045, 0x22d0957b, 0x1c4dcece, 0xac877b9b, 0xc2de1d4e, 0xc8a5701e, 0xa4540bd4, 0xddfccc5c, + 0x37afeed7, 0x5bf29568, 0x657185ba, 0xd9b79a7e, 0x9dabf3a6, 0x4edb1589, 0x8d854d1d, 0x7383182f, + 0x2a03878b, 0xdfe13cbb, 0xe97ae6b4, 0xedafb219, 0xcfb5d549, 0x0c79d497, 0x75145a50, 0x5748128c, + 0x23461990, 0x7825009e, 0xa15df821, 0x2257611f, 0x14d837a9, 0xf4902963, 0x37510324, 0xa494e8ec, + 0xb77f3faa, 0x8a1e9c73, 0xff451cd5, 0x9757808c, 0xa0f05643, 0xeaa817d7, 0x58784a0d, 0xfc1270bc, + 0x6be869c7, 0xd6c857d8, 0xb6fa6f5e, 0xd9eddec0, 0x44aa0f00, 0xe072e064, 0x697beb4f, 0x7e8929a8, + 0x21ff8176, 0xd7bf22b1, 0xc76254f3, 0x28f18c4c, 0xbfc43dd7, 0xc75836c6, 0x6f340b8e, 0x317fbf1d, + 0x6cab45f4, 0x877409b9, 0xd9852575, 0x97137b7f, 0x25d3105e, 0x93e71248, 0x97066466, 0x54ae00f1, + 0xf87af556, 0x29012e0f, 0x12b201cb, 0x8aaafd30, 0x57d81a86, 0xa93b5c7e, 0x728dab0a, 0xdf67c189, + 0x6b692cfa, 0xe2095a4c, 0x3dfe6784, 0xc686df93, 0xeec00834, 0x7b46decb, 0x8ad30a87, 0xb839b168, + 0xfbcf4eec, 0x1496b53e, 0x098f87e9, 0xea65ef10, 0x998cc195, 0x282da607, 0x56fd7dc4, 0x9561db0e, + 0x0f016f72, 0xe329dd20, 0x8bbf01dd, 0x67cecdc2, 0x0094c1b5, 0x4dcf02fb, 0x22fc7194, 0x128414ed, + 0x608e3575, 0x060ca053, 0x70e3e2fe, 0xb66025be, 0x3476970d, 0xf3e63332, 0xf49d7cca, 0xbc9ba052, + 0x339c306c, 0x4d61b6e5, 0x8cd9b756, 0x3a3ed54a, 0x35d4cf8f, 0xb2c06604, 0xfe588221, 0xf8b03db5, + 0xf2bcbe7c, 0x986dab7c, 0xc7f5ed27, 0x95af8013, 0x984e78d5, 0xc7264542, 0xa03bc9a9, 0x856629c4, + 0x75af6b9b, 0x685f213a, 0xe6894a18, 0x7f19c43d, 0x83365f33, 0xc366c15b, 0x60ca14a7, 0xfd0e074f, + 0x642f5aec, 0x2404d98c, 0x0ef8152d, 0x103313cf, 0x2f17b0fa, 0x5cb38daa, 0x69595231, 0xf8f4fdaa, + 0xd369e408, 0xd01d28cb, 0xe9c6693e, 0x4444d2b9, 0xddeb63bf, 0xf613f9fc, 0x29b7732f, 0x08bc2754, + 0xc12d6b7f, 0xf7bb0d2d, 0xb9ae4344, 0x0d3f82fd, 0x431d76d0, 0xf01798fb, 0xd3aa6ba4, 0x2dcdd21e, + 0x7d7a802e, 0x085f4870, 0x89ac852a, 0x0eb38529, 0x8c361426, 0xc59cc875, 0x4977aa9a, 0xd82b385f, + 0x1a68de11, 0xba67ecda, 0x46ef338e, 0x68873213, 0x73696261, 0x7d94f54b, 0x508a31bb, 0x44f21bd6, + 0x877b11d9, 0x51429a66, 0x68bce5cc, 0x23816d1f, 0x10fb5402, 0xc44e02d5, 0xb2cadee4, 0x3543ace2, + 0x2a0c792f, 0xacc0e58b, 0xaccf027d, 0xe555578f, 0x8b6bd762, 0xe69a815c, 0x33aca861, 0x788dc582, + 0x93a4ffb4, 0x2eba4e05, 0x6f263a77, 0x5e776aa2, 0x18870d0b, 0x95b1eb11, 0xcf734f53, 0xbf682628, + 0x370ae8ca, 0x8f7b6569, 0x37bb92cb, 0x34634f02, 0x482ce248, 0x0b20fe58, 0xeec037a8, 0x5ff8b905, + 0xa6875f97, 0x0f28e666, 0xf3e4464e, 0xe9b3562b, 0x403ea3fd, 0x328e9aff, 0xa7edbb71, 0x13dee5e3, + 0xcd63df64, 0x2222077c, 0xcdca4b4f, 0x0e98121a, 0x7400e267, 0x0a31868b, 0xf217fec9, 0x426a7a58, + 0x9ac8a1b4, 0x3681e695, 0xfffe9035, 0xba6eb172, 0x1e0f6f88, 0xbd646836, 0x7499437b, 0x3c75b20e, + 0x2a8cc814, 0x92b10789, 0x2cdc6a1b, 0x411c6803, 0x061c5f52, 0xa0970e07, 0xa86dcd53, 0x2e1c56e7, + 0x69d115ee, 0xdd2a18f8, 0x737d7486, 0x6e59b827, 0x443fbda9, 0x8d61ad31, 0x6939847e, 0x354c2024, + 0x1e0bb78d, 0xc0d744a9, 0xb5278e9d, 0x09ebd3bb, 0x9e6cd06e, 0xb6bcc741, 0x227c6ca1, 0x263346b8, + 0x6952e4cb, 0x506185ef, 0x0dd7dd50, 0x1297784a, 0xb77eb888, 0xb804101d, 0xae4d1c85, 0x0242a328, + 0x2ad039ba, 0xaff749a0, 0x80568bc6, 0x1acb05bc, 0x66590703, 0x31e67a9b, 0x02737ea8, 0x1d384a70, + 0x425cbeed, 0xb528b2a7, 0xa0db29f5, 0x46a74eb2, 0x63648db1, 0x8d77f376, 0x15ced6f1, 0x78b87f76, + 0xceeb1f4d, 0xb914649f, 0x1d6c43ea, 0xaf159d66, 0x3b412b8e, 0x5c5bf1c2, 0xd09ac5d0, 0xc802d24c, + 0x154072a5, 0x23c3ced1, 0xf48175a2, 0x0e605e50, 0xa73888e0, 0x6ab18031, 0x3294cddb, 0xfcbf74d0, + 0x875b2733, 0x80e41310, 0x29837915, 0x92307600, 0x7e96a93d, 0x2d4dbab4, 0x7b2bc70b, 0x1af9149a, + 0x21efdf25, 0xa1ed4863, 0x38b49efc, 0x4b4abaf2, 0xe18b7ede, 0x991e8813, 0x6aaf3a27, 0xdc59ec89, + 0xeff02938, 0x5efc8a5a, 0xcbe36852, 0x8c8138af, 0xf8381fc6, 0x67a71002, 0x135d3db0, 0x669c03ed, + 0x567ae939, 0xc98e0805, 0xa7b0c269, 0x6c71c44d, 0x493e8bbd, 0x8a60d131, 0x30104381, 0x7e024ffe, + 0x1e9d9ec1, 0x6e100c22, 0xb34942bd, 0xc52fb92e, 0x4e1c2a9b, 0x533a95dd, 0x5c23b600, 0xd3d7c181, + 0x1c43cb69, 0x1a8ebbdd, 0x501ec3e6, 0xe5bda01b, 0xa2c0da73, 0xcdcc98a3, 0x1ba1fbf6, 0xf0c144cc, + 0xe4932421, 0xc67b8793, 0x8a8cf02e, 0xcd90745d, 0xa9e760a8, 0x92ac4793, 0xfb955d20, 0xea4c2afa, + 0xd5ec961c, 0x280e6885, 0x2bbd6d25, 0x7f626706, 0xa111a024, 0x6f240231, 0x244acb5d, 0x06126a94, + 0x19e0b792, 0xfc8d2a62, 0xab9294a4, 0x95fa171c, 0x21ab5347, 0x4b3d31ea, 0xce37b7ef, 0x1ad4fd33, + 0x042ea6a3, 0x048c8136, 0x6b313d1f, 0x7033d92a, 0xf22fd338, 0x0aeb301c, 0xc904fc38, 0xffc11c36, + 0xf1e4b3a8, 0x169291cf, 0x9d695e0e, 0xa52153f6, 0xc26b86d0, 0x2af494e6, 0xa988aa69, 0x58b9b89c, + 0x6786632c, 0xa05dfb80, 0x69452d42, 0x235fe80c, 0x8b49d0ea, 0xcbe56431, 0x4e647238, 0xaa39cadd, + 0xb67270b3, 0x8b1cbfd7, 0x04127894, 0xe77ecc31, 0x3caaebcf, 0x92463d58, 0x6e8fe16d, 0xe49a0814, + 0xab3a5ca5, 0xffa2b758, 0xc0a3ffa3, 0xafc3f49e, 0x4069790c, 0x49847b30, 0xf4927491, 0x612b6cdd, + 0x72cc5db8, 0xaabac680, 0x8f0560b6, 0xd1398a59, 0xaee5135a, 0xcc8f6e56, 0x6c58fd51, 0x79a93e4b, + 0x26c952aa, 0x23c2e2e9, 0x510ede5d, 0x022ad2fd, 0x3a593928, 0x1a6b847c, 0xb261475c, 0xa730a3be, + 0xe81e2670, 0xebc0cdf9, 0xbd8f07ca, 0x773e5c7c, 0xada06fd8, 0xc9b874b1, 0x9e60fc97, 0x31616400, + 0xd36c5992, 0x2cdbe0a2, 0xdd14970e, 0xdbafd9c8, 0xabb610fd, 0x85231d09, 0x9f9bca61, 0x1ef03a80, + 0x95ba0374, 0xa6c11d9a, 0x7e382a06, 0x5412a5d9, 0x7b2de404, 0xd0d523c3, 0xad0edaa6, 0x736efabf, + 0xd843ef8b, 0x2ed25c4b, 0x11ae8501, 0x022cd526, 0x10a0cebc, 0xa6bbf21e, 0xcdb72f11, 0x592ae6bd, + 0x46dc3621, 0x238a02d4, 0x7fa23b59, 0xefa8a176, 0xc046a3d3, 0xcca3982b, 0x24c785a8, 0x3f7fbe39, + 0x0636fae6, 0x9c6da135, 0x7d4c686f, 0x6794fa69, 0xcb91d553, 0x4cd2763f, 0xc9207b81, 0xfbe900c0, + 0xd552b8b0, 0xcd8da147, 0x7cbde41d, 0x3dace902, 0x7f5ff0c8, 0x53efd4c6, 0xc2b5f085, 0x1c1d0d25, + 0x5cd44639, 0x9c287aad, 0xe4f306f5, 0xfbd55122, 0x8342faf7, 0xdfd17b9a, 0x8ea6aaed, 0x574917ae, + 0x24d69055, 0xd012a15f, 0x2f88a7e3, 0x1b7cfbd8, 0x047cc00a, 0xf39b4b92, 0x069b188d, 0x6f220ada, + 0x89798cb2, 0x00752e6c, 0xbb34a7fd, 0x2c8f4bf3, 0x4a84fc51, 0x9298942d, 0xa994052e, 0x2bd349ee, + 0x0482118f, 0x797e814f, 0x497bb7a4, 0x3dc4764c, 0xec52d7d5, 0x38d943f2, 0xcde8f07b, 0x1bf33cbf, + 0x572b4fab, 0x6ca65bde, 0x597226a4, 0x87f84550, 0xa1ad2881, 0x8942ece8, 0x8e23778d, 0xd952ce73, + 0xf04aef8c, 0x6d66f444, 0x066b9516, 0xbf36fd93, 0x24ca646d, 0x39a55404, 0x4378d9d9, 0x3c92de0c, + 0x1e387b2f, 0x7f1d884a, 0x9e1e43c4, 0x1eed3aed, 0xa41a8ce5, 0x9c31ffe1, 0xd23e1618, 0xe7c42820, + 0x6ee0d615, 0x98c0511e, 0xab37552f, 0x76be5c26, 0x270fd855, 0x7fa873ea, 0xca3e0f50, 0x87861fbc, + 0x4428a7f4, 0xe96515d7, 0xf1ec8c31, 0xfa70be80, 0x730c9afe, 0x43ecddba, 0xbe4adcf4, 0x0d6e6b05, + 0x22ddc973, 0x2d2993ac, 0xcf09815c, 0xb1c87cec, 0xc4f9df79, 0x9f9bd9b2, 0xa232afd4, 0x21194c96, + 0x9c9fe97f, 0xa9cd447b, 0x2e3a5541, 0xd9d447e1, 0xc815d6e8, 0x424d594c, 0x03061a4a, 0x76141448, + 0x0ff586bc, 0x15b85473, 0xf1da50c6, 0xd56acd11, 0xf6fadf0e, 0x8a93425a, 0x19675ba0, 0x1376e997, + 0x7305e40b, 0x2013e91d, 0x99d26f61, 0x75a0bc35, 0xdf2d7c46, 0x5e5eb5ec, 0x75970f03, 0x70cc686c, + 0x61e9759f, 0x1ba4d95e, 0x428bcf7c, 0xd5ab5e73, 0xc8eed94b, 0x88d85cb3, 0x468868e8, 0xe675bc47, + 0x030b453d, 0x403636ae, 0x857a7ad4, 0x5349468c, 0xa5388dd1, 0x6518e7c9, 0x2c2d2643, 0xd5bd8b08, + 0x30f3af4b, 0xbdf857ef, 0x2a6ced4e, 0x8c5206e0, 0xe4df6b5c, 0xaa3e5811, 0x95dd2d0e, 0x9972b30d, + 0xf46b4da6, 0x94239151, 0xeb88a58d, 0xd0f1a226, 0xe3866a67, 0xfbb30827, 0x8ef324c4, 0x0e1c0b78, + 0x17829990, 0xfb120378, 0x5fe91d93, 0xa6d0051d, 0xacf197e3, 0x44d10221, 0xbc1ca4cd, 0x6b653932, + 0xdb0c36f3, 0xa6115fc0, 0xaf1287d1, 0xbfedd01c, 0x8eebc47b, 0xa0d0fa39, 0x96823fca, 0x5ce147e0, + 0xed2e0b18, 0xbbc60aff, 0x824eea54, 0xc7833ada, 0x691f67a8, 0xc0624201, 0x7c68e66d, 0xd9b0e0f4, + 0xc86a625d, 0xaa7d7ba1, 0x253d2327, 0x4bf81aa7, 0xfbaf3177, 0xca5180ff, 0xaf142351, 0x12015bb0, + 0xc4b60b04, 0x8b8d3bcd, 0x97d11497, 0x3c00d9c2, 0x8c1dbe9f, 0xa62a2c05, 0xa3ecb266, 0xe4b909ca, + 0xf30faf39, 0xcb40f5c1, 0x2e4b541b, 0xeb07f76f, 0x59ae5847, 0x2494a7c7, 0x69ad812e, 0x23b88172, + 0xe0b3a463, 0x4b451696, 0x22c61146, 0xca7e0d1e, 0xd22b4123, 0x7cfc8797, 0x216c8f5e, 0x8743b157, + 0xdc687020, 0x974d5fe4, 0xe7f821cf, 0xb97fa9cd, 0x6a333efe, 0x6b7daee2, 0xadf542d7, 0xf1b508a1, + 0x62542be8, 0xae1deb77, 0xde11ad41, 0x815bf01d, 0xc2c593be, 0x45a4179e, 0x0a8e1c9a, 0x78f5cc7b, + 0x9ed52cc5, 0x14b560f0, 0x077ee858, 0x774e4ea3, 0xe550bd28, 0x9bbff9b3, 0x01f883e7, 0xe4852c28, + 0x1c6866f5, 0x1aa95b97, 0x4e1c7c9e, 0x6f1fbedd, 0xb9968ec3, 0xec9380b7, 0x686f9a6a, 0xec080c4e, + 0x4f9ee1b2, 0x62413b06, 0x9acf8eb0, 0x9ab30641, 0x1646003b, 0x9233eba1, 0xb4bd89bb, 0x6030b843, + 0x8f3e877f, 0x3cde7158, 0x0a6b7092, 0xec70d255, 0xed510ab9, 0x35cf3dad, 0x1021f0e6, 0x8f8d5dfd, + 0x111478b9, 0xc2362f02, 0x298faa5a, 0x1e449b77, 0x3160a939, 0xb1f4422e, 0x33b6637c, 0x21953a8d, + 0xb7170d5b, 0xeb111dd0, 0xd4ca7dc6, 0xb28fbe23, 0xe17aaa24, 0xae4711be, 0x570a0d1b, 0xc6224124, + 0x2735f870, 0x0fe97782, 0x460f1b43, 0xfc4981f9, 0x80bbe05c, 0xaa711a60, 0x5966382e, 0xc36cf08c, + 0x67b98be6, 0xbfb22ef2, 0xa90ed3d2, 0x62203219, 0x041bafff, 0x3beefef8, 0xc8f61832, 0x4fecc3ff, + 0x58121cc6, 0xe92a6116, 0xe3a205dd, 0xfd21801e, 0x68fcd7df, 0x06db52bf, 0xea848757, 0xbc8226c7, + 0x211eb63e, 0xc68c19c4, 0x01bc6ec7, 0x3fae0a11, 0x992637cb, 0x5d9fefa0, 0xd4901de8, 0x6b1304d6, + 0xd7315bb2, 0xffc203ab, 0x4a7a6723, 0x1ee5e8d9, 0xdf199c2f, 0x77bfbada, 0x430fbf18, 0x1fc0cbeb, + 0x216aaec2, 0x1b54e6f6, 0x002bea52, 0x0b1d74cf, 0x8d56b07f, 0x764f99f7, 0x8fc5dd45, 0xd9a5fc53, + 0x90980332, 0xdf92e397, 0x3d2649f0, 0xa57d2e88, 0xe9bc181e, 0xcf93cc99, 0x2c91479c, 0x5aa4f77a, + 0x7b3df531, 0x0aef9b8c, 0xb1db5287, 0x2b3cc0bb, 0x96f736fa, 0x7946531f, 0x4060e5fe, 0x9e4cef52, + 0x1d40382e, 0xe5a4cfb8, 0x665318a2, 0x85eec80d, 0xc24b324a, 0xca58b07b, 0x8e9c2728, 0x8149a074, + 0xf26b0144, 0x7cf44366, 0xa498fd1e, 0x8afd179b, 0x6da540e5, 0x21b0ace3, 0xfd5b8ee1, 0x9a6e5ab2, + 0xf609a586, 0xed9f0851, 0x543f3fec, 0xc4a5d1f7, 0x4c17dfa2, 0xc2efbb35, 0x84746644, 0x706a17bb, + 0x44232298, 0x1df82aad, 0xf6b460d0, 0x91ed8604, 0x8a8b287b, 0x7d515777, 0x88efc69e, 0x73647907, + 0x2871362d, 0x07aa2b83, 0xf2404d4b, 0xf4127956, 0x73755947, 0xd6ec566f, 0x9cceccad, 0xe1016c4f, + 0x22f503c3, 0x0cb57fa3, 0x5a91d3f7, 0x2f6ad69a, 0xf9fb0f5e, 0xbc34281f, 0xe07a4c51, 0x195ad096, + 0x33484afd, 0x4531a512, 0xded259ff, 0xaeaae3fd, 0xa04b0da3, 0x3bb16777, 0xf653048d, 0x453e87dd, + 0x40e50b18, 0xff6ade26, 0xfb6fe5b9, 0x3eedb16f, 0xcac6dc6d, 0x67029a26, 0xdecb93f1, 0xe50417f9, + 0xc4e4e892, 0xa22999b5, 0x884566a5, 0x749f3b19, 0x36801953, 0xf0ff7a44, 0x673ab7cb, 0x2005d8af, + 0x96bd889b, 0xf9cca6b5, 0xed417a0f, 0x74ba8bdf, 0xd3262633, 0x006f3006, 0x2aa74e60, 0x655af45d, + 0xd37fbe4b, 0x3b289edf, 0x47739679, 0x6b4ec771, 0x4ace3f02, 0xec47da48, 0x753f608f, 0x74db879c, + 0x87b41daa, 0x7c65e038, 0xb13631e9, 0xfd9410d4, 0x22bbb90b, 0x7d48c7fe, 0x381a1bfb, 0x8f79bb9f, + 0xe230da81, 0xcdb2da78, 0x3f8fbc86, 0x65ad360e, 0x9685f8a5, 0xed1b5f67, 0x41558b2c, 0x82ffa9e1, + 0x84b89305, 0x1287a6bb, 0x02c6db4d, 0x1b1096ec, 0x8970eaf1, 0x1e260f95, 0xd028e348, 0xa972324e, + 0xa881b091, 0x6a34a894, 0x81b3f9ec, 0x0a073af7, 0xb21eebcb, 0x39b5e52d, 0x0e33550e, 0x3ffbd47e, + 0x0dbff12d, 0xe03fdaca, 0xdfa24f7b, 0x1b2551df, 0x793ff758, 0x778af4be, 0xcb6236d4, 0x03b8f3f4, + 0x43514e0a, 0xcc248017, 0xcaa70632, 0xb7f90632, 0xbcf359fb, 0x19884991, 0x78be79c3, 0xa3e43d58, + 0xd4b9ddde, 0x74a94dfc, 0x0e08b8cb, 0xeebd9525, 0x6595a53e, 0x16e189fc, 0xc6ad2e3c, 0x6222c3cf, + 0x272d03ee, 0xcb065eac, 0x588438d6, 0x3a319897, 0x2ef8659a, 0x0161ab99, 0x1e2e5a97, 0x1c5b2ec6, + 0x6d43133d, 0x4f3f33e7, 0x462c8ff9, 0x822921fc, 0xcf81eab4, 0xa82c5947, 0x22aa9d9f, 0xc70b564e, + 0x3009181f, 0xc23b6baf, 0x2bb4b351, 0x057db62e, 0xd493fc8a, 0xc9452fa3, 0x0bffe0fc, 0x4e268668, + 0x92d1059b, 0xeb835d86, 0x6872f7d5, 0x0cc7d4a6, 0xe662941e, 0x0f0901a1, 0x71711437, 0xb6d13b9d, + 0x45d1f06f, 0x3f7fdf95, 0xe9bcf17b, 0xa0ec795c, 0x6b307242, 0xc629c666, 0x09c6bb59, 0x743f7bd8, + 0x7671fcfd, 0x6a1693be, 0xd6230a1a, 0xcddcf870, 0xb3d53efa, 0xbaa5ca66, 0x1e70a8c6, 0xad53e6f1, + 0x30fe16a8, 0x51c821dc, 0x036010c5, 0x812d8375, 0xacab0d1f, 0x8b8b4ef0, 0xcf3a095d, 0x395b09f8, + 0x36749b65, 0x3a4b2a2f, 0xa13ea3ca, 0xc0da7f95, 0x1066f789, 0x71fd019d, 0x2fc559b7, 0x40ed50a7, + 0x4fd557ec, 0xa984554e, 0x3a3baec2, 0x0ae80c65, 0xcaacec03, 0x96882d6c, 0x1e2e7207, 0x3700e0b4, + 0x9945663e, 0x04e62368, 0xa70618b6, 0xfd627879, 0xb1707e73, 0xc60a53ce, 0xda6580dd, 0x788d49b3, + 0xf10bcdd3, 0x525e7bf3, 0x26ed96bb, 0xb84e7e66, 0x1c1f5a02, 0x1b681116, 0x48db1ac2, 0x79d04085, + 0x2770bdac, 0x78c2e295, 0x8f24fa82, 0xdcd5ad96, 0x0a425d38, 0x3cf7ce26, 0xe0da2609, 0x76bcf687, + 0xee481909, 0x13bcfbac, 0x83e80f67, 0xfe564eab, 0xb09ce418, 0x027d2fb4, 0xbfa9a88e, 0xa5efb9b8, + 0xbd54345d, 0x2a40ad7b, 0x4492be28, 0xc2665ea2, 0x7c10a815, 0x55cfd761, 0x6d277b7c, 0x3ffd5811, + 0xc534bdf5, 0xfe3d4a2c, 0x170ae3e4, 0x5db93b1e, 0xb6b19783, 0xc914fae7, 0x49f36146, 0x6d791397, + 0xabcdb717, 0x64b3b1ae, 0xbc333521, 0xe1d83c5e, 0xd20ed496, 0x354781a5, 0x635dfc15, 0x51fdffd7, + 0xe78055df, 0x95285b4e, 0x8518b6b4, 0xb23a08cc, 0xf98f619d, 0x983f8ddd, 0x0abf9f97, 0xc3f8355d, + 0x95f69bd4, 0xe33f7db5, 0xc9f0c8ce, 0x24b6050c, 0xa9c21f9c, 0x252ff137, 0x53de5be8, 0x57307a87, + 0xef68279e, 0xdefe663f, 0xcbe9e4ed, 0xb72d4b47, 0x060f8e0f, 0xaad9da0a, 0xfa87efe8, 0xb49ae495, + 0x23335e2c, 0x7e8430d4, 0x8d3fb824, 0xace7cf72, 0x2a67ef87, 0x4ca69be1, 0x5fccaa9f, 0xb4c17d88, + 0x98702dcf, 0x8cd2e58e, 0xba62d938, 0xcaed59e1, 0x74eaff13, 0x27691bd7, 0x4ebe3bcf, 0x77bb9ae2, + 0xfa9d254e, 0xb39e5e39, 0xa9d21682, 0x75676c3b, 0xb3508521, 0xa023214e, 0xb6f43c04, 0xefeb3d04, + 0x613cef79, 0x19e79214, 0x11201da8, 0x3cd4705a, 0x03e86443, 0x64052249, 0xd03c39ef, 0x6bcf95ab, + 0x38b85f51, 0x1f5aa0ad, 0xf5f83ecf, 0x43c70f78, 0x073c6c5d, 0x44dab9c9, 0x7f458740, 0xb723fac6, + 0x3a5468ad, 0x49ee9e17, 0xefec139d, 0x5eb2972e, 0x15c95d26, 0xb9308f8b, 0xd7f16445, 0xce0e7a1b, + 0x45a8c889, 0xe35c9ed9, 0x8fa80af8, 0x29c2b686, 0x4fb649b7, 0xcc655977, 0x312b0ecc, 0x63ed8de8, + 0x5ac57e4e, 0x6b23d817, 0x48be5a98, 0xf9efddd2, 0x7b67ee8f, 0xae97d29e, 0xc88165b6, 0x99ee8dac, + 0x4884c4c6, 0xac320886, 0xa3f1d02c, 0x7bb62d4c, 0x1bbb4d87, 0xeb73b019, 0xcf225fca, 0x71fbe60e, + 0xc051c565, 0xad56b430, 0x6a13dcc3, 0xd6f1a094, 0xfbcdcd7d, 0x6330e7e5, 0x9ace1ab5, 0xac5d9983, + 0x002dff8c, 0x75821ab4, 0x1c0a910d, 0xb785b2e8, 0x31b4ea54, 0x43ced495, 0xf309329a, 0x81c7a95c, + 0xa7e3eb86, 0xca38183e, 0xc8704f1b, 0x06b930f9, 0xc12805ac, 0xb25f681d, 0xfce3b448, 0xd3d769e3, + 0x8161265d, 0x796167a0, 0xd9957fd6, 0x515274f0, 0xb34cfd71, 0x7f57dc70, 0xbc5772be, 0x33c90634, + 0xe5b27f61, 0xb4f728eb, 0x13ef1837, 0xb423b65f, 0x8a271321, 0x89dc1df6, 0x53a7df4f, 0x38c87822, + 0xf00d3230, 0x178ffc12, 0x70999aaa, 0x47ce17e0, 0x59d6bbb7, 0xa5dbb2a7, 0x68375131, 0x90e8c13a, + 0xf8d1e347, 0xaf6c3ae4, 0xae735eb7, 0xfa808c4c, 0xe41cf2a1, 0xf79687cd, 0x868e0c78, 0x847efe9c, + 0x1d85a17b, 0x9461af39, 0x245a989d, 0x8bae3647, 0x14aafccd, 0xa9bd0253, 0xf5811a64, 0x229e3fa6, + 0xc877fbf7, 0x9885ec9c, 0x1752e2f0, 0xb500558b, 0x6226c73e, 0x40989a31, 0xeca5253f, 0xa68885ac, + 0xc6e33a6b, 0x3b433ebd, 0x09c1037f, 0x734f2390, 0x34487425, 0x10ad4f9a, 0x1d47ecce, 0x4d5f3a00, + 0x2221c41e, 0x3af67227, 0x13c3de9e, 0xf635c7f7, 0xf9413c64, 0xd895f812, 0xa66e9400, 0xc438c6c4, + 0xfe67aff6, 0x4d34fc23, 0x2ec13047, 0x061a1b75, 0x3e2eec9f, 0xd9e857f6, 0x8286e58e, 0xc91f3687, + 0x29261d69, 0x9232eef4, 0x6e568c81, 0xedf5c371, 0xbc3aa0d2, 0x360ce36c, 0x0b56ba3d, 0x188fc1e1, + 0x823ceaa0, 0x1034a54f, 0x656edef0, 0x3fca810b, 0xec4fcbc1, 0x414f949c, 0xa8847354, 0x29ecadf1, + 0x61da530e, 0x97866979, 0x6af86a22, 0x655b92b6, 0x3ce56d6e, 0x7a57a955, 0x74d2fa50, 0xb9099e3e, + 0xd7d081bb, 0xb80c579a, 0x6a52689f, 0xf5a10380, 0x0326921a, 0x5bf99f85, 0xfbfb3c80, 0xa31b3aa2, + 0x971d82b0, 0x0735f783, 0x1f27915f, 0x2c2bc128, 0x5cd8e63e, 0x81d282b5, 0xbe02abea, 0x3106a09d, + 0x06ecc03a, 0xf3525a25, 0xfe360862, 0xeaa44600, 0xcf0b9f3a, 0x9757b72f, 0x7e2f7186, 0xdb366694, + 0xa8ef3aa8, 0x19b0e5bc, 0x6fde6d1e, 0xb45eb95a, 0x6ada5d63, 0x9b1b2c6f, 0x964583a9, 0xa77077ce, + 0xfda0bb36, 0xb8d3c6ff, 0x96c6ff59, 0xc44027f0, 0xe9d4801a, 0x61f58508, 0x44d704e6, 0x028f8370, + 0x69025f0a, 0x6963e4d2, 0x9633661a, 0xeb94e25e, 0xb75a790d, 0x839af3c4, 0xe16270e0, 0x72db1361, + 0x18e191bd, 0x54795aa0, 0xb8c4dc99, 0x677c59a5, 0x9617efff, 0xe24c1b14, 0x4d217602, 0xa6643d85, + 0xd3bbbbe8, 0xb12e98c1, 0x99fc5741, 0xfbb6ca9c, 0x2f798537, 0xbf8dc1e8, 0xdeafde26, 0x72387fae, + 0xac2a6dac, 0x5b288eab, 0x5f613c3b, 0xe4ec1e9c, 0x16f87795, 0xd5a40b27, 0x0dbb57ab, 0x2b6b2d2e, + 0x8d402ea0, 0xdd12bb57, 0xf964b399, 0x593b16c7, 0x7f50a542, 0x798fc74f, 0x9985fa57, 0x54ad6ebd, + 0x2752765b, 0x09300295, 0xae11e14e, 0xd9bd12bb, 0x7726e935, 0x0875b484, 0x1022a841, 0xf9433829, + 0xc7e41a93, 0xd95d5208, 0x343694e5, 0x20031b89, 0x4770103d, 0x9742e076, 0x1687cc18, 0xdaa5af22, + 0xfce4b859, 0xd157946c, 0xe2922faa, 0x0f7babe2, 0x00fdbcea, 0xbf63eb38, 0x3e6fc7ef, 0xced0b227, + 0xacb34589, 0xdb84fdd3, 0xb0c28e86, 0xe4e6516d, 0x5e5321bc, 0xb7dce1d2, 0xfcacf93b, 0x3ad192e7, + 0xfd6945cd, 0xfc18f186, 0x8a462ae9, 0xfa9e7cb5, 0xcef68077, 0x7aeca954, 0x730434bc, 0x5e191b3a, + 0x535f3dd2, 0x4403db26, 0xa0faa7e3, 0xd1fa0538, 0x34822110, 0x8ebbf550, 0xcab7e4dc, 0x32ab0b7f, + 0x1b5951ae, 0x3cbbad30, 0x329f2955, 0xe4f9a0fe, 0xe2e7bcaa, 0x34fb69e4, 0x7f25ed51, 0x8f39753c, + 0x54a8595b, 0x53f2315a, 0x1969f661, 0xee8941dc, 0x691ee4fb, 0x9539eefc, 0x4b68c4ef, 0x72eecf70, + 0x91f2d0b6, 0xc8a3617c, 0x894b1c7a, 0x7cfec0d0, 0x2e5c410e, 0x7ed26efe, 0x4b19a6df, 0x07321dcd, + 0x425bd8e4, 0xd7de243d, 0x581afe8b, 0x721ac467, 0x13747e25, 0x2f5ea7c3, 0x30588a19, 0xfff20a08, + 0x8d288ee7, 0xf974794d, 0xe765c4da, 0x86e16d47, 0x47d4fa50, 0x8925cf3c, 0xbe313b27, 0x37bddc76, + 0xc0b94d32, 0x4f2b031b, 0xa3383b25, 0xb327604b, 0xeabb4b42, 0x267eb9e0, 0x3765782e, 0x39f32bd9, + 0x3af2612b, 0x4be451ab, 0x55b0ff91, 0xb712b875, 0xd2102a94, 0xc4369a20, 0xe57605c8, 0x4d4b5194, + 0xd9fda760, 0x295cb6cd, 0xe6ea893a, 0x10f3d7d2, 0x7af78c53, 0x6e97a14a, 0xe252e8a7, 0x7757fbed, + 0x3ee9cfe6, 0xf6a789aa, 0x3e41e062, 0xe0749544, 0x72f959a6, 0xa7f08458, 0xb053f42c, 0x764bf996, + 0xc058ed5c, 0x992605f6, 0x7b1d6f21, 0x99cbce0d, 0x9cb98b20, 0x2bbbcd45, 0xd02d0f04, 0x545c0cc3, + 0xf055e7ce, 0xd881a42a, 0xcff7bb41, 0x247bcf68, 0x6e119f54, 0xf30ea920, 0x0f7ce4d2, 0x6b54fe40, + 0x797515bc, 0x84fbfb3c, 0xd8c6613d, 0xba00ac2a, 0x56e224a5, 0xed3fcd3c, 0xce8493e5, 0x1522005a, + 0xf9e637c6, 0x7ad0a0cf, 0x4ca86889, 0xd919f8e2, 0x76af35a6, 0xf033f28d, 0x3848fdbf, 0x29e28cf3, + 0xdb049ffd, 0x6f93a89c, 0x55f8c112, 0x1a0759ab, 0x9650fb3a, 0x2ff05e36, 0x81ba11f4, 0xfe7c19d1, + 0x999d504c, 0x62f835da, 0x785fbc17, 0xb41aa072, 0x801592c2, 0x3bd3f891, 0x87e035e2, 0x7d6a8d5a, + 0x033fe153, 0xf73bf9da, 0xf3215e24, 0x027f90af, 0xcdc9ccc6, 0x68e4c0e6, 0xd0db706a, 0x79805193, + 0x99f91cd5, 0xffe72c7d, 0xedf30dc3, 0xbbf3fe47, 0xba73d270, 0xe8cc5511, 0x29405f2f, 0xa96eeb75, + 0xc604c79b, 0x9474e7ab, 0xcc205afa, 0xee6550a6, 0x126bee97, 0x3c56e7ad, 0x5f574886, 0xfe73103c, + 0xf51b1374, 0x532396a5, 0x598a713a, 0x336ce841, 0x8221f7ee, 0x8531a6ff, 0x0f566898, 0x2eb80887, + 0xb87bcd6d, 0xfe295706, 0x10fc51f5, 0xf831dfa2, 0x90c92029, 0x67a40a55, 0x1ad01d57, 0x46703b1c, + 0x57d8ce39, 0xc86615e6, 0xee29c8af, 0x99eed6aa, 0x3b6fd051, 0xad73d5fc, 0xd1700c64, 0x2c62be7e, + 0x508e796a, 0x64c7c637, 0x7c816848, 0x553abda9, 0x45675baa, 0x7dba4ede, 0xa2b72db6, 0xc6c40681, + 0x50665a34, 0x6f2e5827, 0x0ab462bb, 0xb934b156, 0xdab1907f, 0x3c7ac62a, 0xb97f904e, 0xfd1048fd, + 0xbc7f62b1, 0xa0f1c5e8, 0xb60662f0, 0xdcf70cbd, 0x13485fa3, 0xaf465b30, 0xb50300b7, 0x4b7e4c9e, + 0xa00eb7e0, 0x77571f61, 0xeb7b74d9, 0x05e9684c, 0x0a889f6a, 0x12440fc1, 0x239f70c0, 0xb4d09d2a, + 0xef3aa69d, 0x5db2da95, 0xaaa8f986, 0x20235bd2, 0x4964f53f, 0x88d6bebf, 0x90da953a, 0xaeabf118, + 0x50f4a07c, 0x96925997, 0x7169339b, 0x8c2b3313, 0xceac58f4, 0x4771f8ad, 0xcf91d273, 0xf90c95cf, + 0xce5bbeb1, 0xc1130bd9, 0xa0fa36ac, 0xe7bec43d, 0xcecc1a6c, 0x8f941f0c, 0x397b8703, 0x5fc79fc3, + 0x27dfd7a8, 0x4196da16, 0xa1e53576, 0xd39d5af9, 0x8c646621, 0xbeab0174, 0x1c7d8cca, 0xc0d96ab9, + 0x7da0c4a5, 0xa09fdaa0, 0x254b312b, 0x7e8759db, 0x9392a665, 0xf9b77ff2, 0xae712a44, 0xbac48c57, + 0x2c2dd048, 0x3dc0852b, 0x6dc5f4fd, 0x40c13952, 0x94125dde, 0x34e08754, 0x6a7cc7d8, 0x304f5960, + 0xb8ed728f, 0x45d51ba3, 0xb56b2957, 0xe5a2f2ea, 0x05ef3f58, 0x48f095f5, 0xa292abf6, 0x13489237, + 0xca2af1f9, 0xe043c3d8, 0x40801e8b, 0x01ebfa34, 0xcedd8b11, 0xa8987055, 0x1fb12a3f, 0xcb7b5f0f, + 0x0634e9a4, 0xf823f63c, 0x807158bb, 0x05deb40d, 0x9694b5f2, 0x8ce134ec, 0x2f8cfdea, 0x0c2b6ebb, + 0x0954615e, 0x7549d322, 0xdb8d263c, 0xcd02c043, 0xa7716565, 0x1d3f3748, 0x941f5b21, 0xed584904, + 0x729b7b0e, 0x38808fd9, 0x486fca62, 0x7260f8f7, 0x0c12f6fe, 0xe85c6e9e, 0x13b8655f, 0x9e4072df, + 0x645498ba, 0x1730c9c8, 0xf6e69212, 0x870f76e9, 0x7b8dbeb6, 0x63aba39e, 0x4ef8f8ef, 0xb3ad6188, + 0xcfe98529, 0x92009d34, 0xbb4062f3, 0xb664cf49, 0x3b4bea86, 0x97a52d85, 0x70b80ce3, 0x22c424eb, + 0x191ec236, 0x0235e1a9, 0x41caf36a, 0x8d6ada24, 0x63b2769f, 0x17141683, 0xf1032478, 0x77e5c653, + 0x5b8127b1, 0x427cf540, 0x0d90b37c, 0xcffdf303, 0x41df7e9e, 0x7d62fede, 0xf4de5547, 0xd77983ad, + 0x0b90017b, 0x6e8dceec, 0xdb8d145e, 0x7d8b7ea8, 0x1969e65a, 0x0e7e6912, 0x41a84d6f, 0xe415b0d9, + 0x98396cca, 0x12cf49c6, 0xe67dea6f, 0xbc4a7e2a, 0x7b6565d4, 0x99c39186, 0xc428453d, 0xa524aabd, + 0xccb3f5de, 0xc713dd65, 0x526af90e, 0xd1033b86, 0xcda1d049, 0x0371d4ab, 0xf80c4f02, 0xa55315ab, + 0xcdcf22a5, 0xe1fe54db, 0x9686d86e, 0x9caf2b9e, 0x8e6be3c7, 0xf5ecb92a, 0x6dd5c655, 0x4921aed8, + 0xf9c16114, 0x0b9cd741, 0x853f4395, 0xd0ecaf99, 0x56d0774e, 0x1d68a1e5, 0xf7b95bf9, 0xb333d12b, + 0xf7b7859a, 0x99f040d0, 0x55e73afa, 0x242e6c90, 0x3540968a, 0x1eea0ee1, 0xf2485eb0, 0x06940263, + 0x4e77c547, 0x3bba4ff1, 0x93a9415b, 0x328fc32b, 0xd043f4bf, 0x5851c31e, 0x095326ee, 0x3e8b6406, + 0x49ccce90, 0xd3a6da8e, 0xf8528d76, 0x6e9ea8a9, 0x82723de7, 0x25f2e863, 0xe4a7ba6d, 0x17ff2cf2, + 0x60ce0878, 0x349e9d2f, 0xb4d38c26, 0x2b1b0b11, 0x937c41f8, 0xdf5f81e6, 0xd5f99e77, 0xb6678816, + 0xd058b4f6, 0xbf074236, 0x356dc04c, 0xb16b94d7, 0xbbb39f2a, 0xf737fe94, 0x5cf2c964, 0xce807013, + 0x57fdeeb5, 0xe240985f, 0xfd0cb8ae, 0xdc049e80, 0x239b7499, 0xfb99ab35, 0xde30795e, 0x99b05255, + 0x896c0661, 0x4c9f7f74, 0xa949463c, 0x2fc46189, 0x90df0d6d, 0x604b3af6, 0x19d53be0, 0xb2acb799, + 0x5ae12f3d, 0xb3f52f78, 0x6981b3db, 0x1a57a11b, 0x519f6a0f, 0x5803530b, 0x36a7ad0c, 0xb054eeeb, + 0x24c163c4, 0x7b9d1928, 0xe3ed91f7, 0xae690562, 0x81893460, 0xb9a421cc, 0x7c50c379, 0x5994a340, + 0x51bdfb07, 0xd84cd644, 0xb00cb155, 0xeffb1d6e, 0x7a753dcf, 0x4d7fa9b2, 0xcc4e5eee, 0x71dda4b8, + 0x93740e65, 0x0fa0a377, 0x1a094d91, 0x9d4ed955, 0xd24a656b, 0xdfe948d8, 0xa2cc558b, 0x416f1b5e, + 0x421ef54b, 0x47bc209f, 0x686c4418, 0x961e8571, 0x2f7c6149, 0x74ce675a, 0xa2708ea2, 0xbedcb80f, + 0x02099522, 0xc2393e92, 0xd37d7940, 0x9383d9e8, 0xf9662340, 0xf68e78b1, 0x1718a13f, 0x1020ee90, + 0xc4aa21e9, 0xe97830d8, 0x2e187a2d, 0xa34b58f3, 0xf4889dd2, 0xc7280bdf, 0x612d5ecc, 0xd08f94ad, + 0x5947880f, 0x1c30206b, 0xac7e6e84, 0x2dbded96, 0x51b68fdf, 0xf08c7e91, 0xbf34b2d7, 0x6839be34, + 0x0531ec1d, 0x9af374b5, 0x71fa5beb, 0xaeb333e7, 0x9c0d688b, 0x3444d4f3, 0x4ebb41be, 0xb9953926, + 0x3850f5ba, 0xe363ef68, 0xca12cdf5, 0x3b00f8d5, 0xdf41e653, 0x193dbea3, 0x01bbcbed, 0x01920cad, + 0x5ccf6111, 0x7bb65408, 0xcc5bf4b3, 0x3b1f73ba, 0x2cce8399, 0x7d3b8480, 0x1e84338b, 0x5be3050e, + 0xc39d2d7f, 0xd87ee549, 0xb19cef0b, 0x908edc20, 0x756f42ab, 0xa2e108c5, 0xefb75207, 0x1074471c, + 0xae15cbb1, 0xbe16fe0a, 0x5b839f92, 0x179786fa, 0xdf041e4a, 0x23791f1d, 0x6315e2f9, 0x5e8b2cc2, + 0xb12be572, 0x7f1bb898, 0x8f393a84, 0x9c4b4419, 0xd8fa9364, 0x34643531, 0xa258d9c7, 0xe8952081, + 0xf526a2c4, 0x7d1d50ba, 0xa5ce8860, 0xb38184f3, 0xdb967800, 0xed7c4402, 0x2269ec6d, 0x3d2f3771, + 0x62cf4df4, 0x9b80a7c5, 0x013f21b0, 0x00120d04, 0x8451b53c, 0x273b299a, 0x38d0ee51, 0x4acbbe7c, + 0xe7f5d82c, 0x2e5278f5, 0x291baed3, 0x1ed15470, 0xe211cf4e, 0x3ee70f65, 0x1f12e006, 0x68a5ac64, + 0xce6b8edf, 0x3a2e3093, 0x1cac1abf, 0xb63b851f, 0xaf158eac, 0xadc07070, 0x685e2144, 0xe38d42a8, + 0x92359b43, 0x73755ddb, 0xcc1eeb75, 0xa148d9d1, 0xb41ae21d, 0x253899b3, 0x0a3a3836, 0xc87ed52a, + 0xafc7fd9b, 0xeb5b8466, 0xccbfb770, 0x5dcf9464, 0x5e19eb7d, 0x661cc792, 0x5a3d81c0, 0x3e808f9f, + 0xcb5ff3e3, 0x689a3521, 0x032696e3, 0x4c6f9f21, 0xae090535, 0xd800041b, 0xcec75596, 0xb3d29ef5, + 0x471fe264, 0xcb52c854, 0x3cf0e4c5, 0x98726363, 0x0e54a886, 0xb030599a, 0x33d6b2b0, 0x5b3a3b7d, + 0x190f5c47, 0x9c3551ab, 0x92857c67, 0x66e5a3ff, 0x6003db76, 0x200e60fe, 0xc84684d0, 0xd348e69b, + 0xd082821a, 0xdb9bce71, 0x0a56f065, 0x27797b9a, 0x0528b514, 0x8ae64013, 0x83637324, 0xdab22c2a, + 0x8856ba11, 0x4cb93494, 0x728dde1b, 0x4f027926, 0x57abc599, 0x31461b4e, 0x685f2baa, 0x9cc704fb, + 0xedaae235, 0x0baf3572, 0x0b6e0af3, 0xf6dad2a5, 0x27f155aa, 0x9e49b08d, 0x28b66acf, 0xad0485e0, + 0xd4313f6b, 0x8cc5b369, 0x1538ecc3, 0xcee2f4b5, 0xb131e3f5, 0x6926ceb4, 0xb037fa31, 0xee026b8f, + 0x7135b21f, 0x65f837f5, 0xe78479a0, 0xcad669ce, 0xaffe35f2, 0xe2cba436, 0x23b33a56, 0x34072e9a, + 0xf6223ad5, 0xb226aad7, 0xffe91ab2, 0x60570a11, 0x99c8a9fd, 0xe2b2f153, 0x7b3c2f50, 0xbe06e504, + 0x22fe5767, 0x5799a163, 0x1d6bf12f, 0xc8fbdca8, 0x98c534d0, 0x6d597aa1, 0x6e57d279, 0x7ec9b492, + 0x953d13b9, 0x2892d1a2, 0x1d3b3c35, 0x8bc35c1b, 0xc790cc0e, 0xf27f54c6, 0xb54af2a3, 0xdf304ec2, + 0xa3c02d25, 0x622cf5b5, 0xebe3551f, 0x704e2805, 0xd8cb5874, 0xf2631a17, 0x63a7b69c, 0xa8c41d3d, + 0xab94fcbe, 0x0d4a524a, 0x6786d1d0, 0x495d888a, 0xa6bd0279, 0x1cc0554a, 0x273cfc05, 0x591f8460, + 0x98305d13, 0x7e979d80, 0x4d27a46a, 0xeb989bb4, 0x05037a45, 0x2f5bb4cd, 0x4415363a, 0xd3b92270, + 0x5e70d6b8, 0x4e54a7ef, 0x0ee5e11e, 0x8f118291, 0x1454ec2f, 0xef03437e, 0xc012a258, 0x9449e466, + 0x9fa7712b, 0x28b7ae4e, 0x147a1fcf, 0xd7d656cb, 0x1cdcc99c, 0x23d1059c, 0xda5bc6f7, 0x8b90c4b8, + 0x9d3acac7, 0xc94f2a87, 0x3c54b413, 0x245f76a4, 0x148311de, 0xbc64555f, 0x78485a46, 0x7c9f64c5, + 0x19ce1b6d, 0x44219bad, 0x8a40e670, 0xe423de31, 0xf1f3c727, 0xc4d091be, 0xe4cbdb5b, 0x94e53517, + 0x686d85a3, 0x6dd9499d, 0xcc45cf99, 0xe54d3218, 0x6c105d86, 0xc3152cfe, 0x60dfdee4, 0x90aea17b, + 0xee53ceb0, 0x3805e907, 0x09e50dbc, 0x3045987e, 0x213be311, 0xf00ed7ce, 0x56abf633, 0xe63af221, + 0x42ef967b, 0x4709977f, 0x394e2455, 0xed2e0d07, 0x498c0693, 0x69ef212f, 0xd9cfed8c, 0x9cd3ce3f, + 0x2f314687, 0x65b2490d, 0xe2bfb7a5, 0x413b5b68, 0xd7c67472, 0x7d859961, 0x4e2f2884, 0xbbf9c3f4, + 0xbf350657, 0xdf17fba6, 0x3a455fa7, 0x672a2ab8, 0x0b0786c9, 0xab22b5c0, 0xa0c36ba4, 0x3c5ee050, + 0xd443e664, 0xd1eac78a, 0x20c32a69, 0xb9fcec5f, 0x4400bd61, 0xa7d9dc15, 0x83a19049, 0x8ec98be9, + 0x18df38a1, 0x47f317c9, 0x2ff86770, 0x4f8a3d08, 0x867a338a, 0x19f97617, 0xef2e82f6, 0x346843ea, + 0x92c70675, 0x26821ea3, 0x281f94aa, 0x786e2021, 0xc4733e71, 0x51683a26, 0x7497c772, 0x13792534, + 0x14305f47, 0x0afde914, 0x62ca69f9, 0x75d6a66f, 0xab7e027f, 0x0b717498, 0x3904a2ba, 0xc784a276, + 0x17154863, 0x6142960e, 0x4ae60320, 0xe2d21b60, 0xbdfc246c, 0xdce0747d, 0x20b8aa05, 0x2c06fd84, + 0xb2cc078d, 0x7f681959, 0x8feaad9d, 0x438cfc88, 0xe82c4779, 0xab1e86c6, 0xbc484969, 0xfab90079, + 0x6f47edee, 0x54b6e379, 0x8343e443, 0x0c8fe07c, 0x0cc24480, 0x837f1cba, 0xeb97e571, 0xca4e2292, + 0x9ef93bb8, 0xc46350d7, 0xf9ff77ac, 0x610d2eec, 0x6bb3d6d8, 0x1126c6a7, 0x13ac9ff5, 0x8b512ae2, + 0xd7d440b2, 0x94c72188, 0x2f714535, 0x68257b54, 0x02b48ada, 0x3a75567e, 0x4467d62f, 0x7d6a658b, + 0xef0a617d, 0x7063a799, 0xf33ff58f, 0x688789fd, 0xc66e475a, 0x076f67d5, 0x42e9be1a, 0xb4049ffd, + 0x498fb095, 0x5de92ca0, 0xc74fcd5e, 0x3c894ae3, 0x69e9e4d9, 0x92b27c72, 0x4c547d30, 0x9abc65c4, + 0x58b95b41, 0xd4e6fe77, 0x90e9abe6, 0xa675f28d, 0xc01ed523, 0x7864f451, 0xe585cdff, 0xd2dd8d87, + 0xc1ac78b6, 0xc87fabe9, 0x4b78e91a, 0xc420cecb, 0x675f805f, 0x42044070, 0x2fbdd071, 0xf664502b, + 0x6e1f0633, 0x7b698ec1, 0x93584c5d, 0x43659ab8, 0x571e8478, 0x7f42b641, 0x401e394b, 0xd5d4ed34, + 0xcbf2c8ca, 0xcb147801, 0x244a39c6, 0x6c49e10b, 0xe00b5361, 0x06fe6de4, 0x24aba5f4, 0x478ae0c0, + 0xf1d8013a, 0xa11e927c, 0xfc217be0, 0xf722c752, 0x81853054, 0x991d756a, 0x61e180c1, 0xf76ac570, + 0x8c9a7c42, 0xde171cc2, 0xa2cd47ff, 0x32d6a092, 0xd464f964, 0x4d595349, 0x6db2bb66, 0x053f0095, + 0x8a6c6380, 0x41ccd561, 0xdf8f5499, 0x8c6071fc, 0xa7ced186, 0x37f64821, 0x7bb30d6f, 0xaaec4de1, + 0x0ece1a1c, 0x69ab861f, 0x0b2579d6, 0x061f2ad5, 0x3e7d0a9a, 0x951cf7a9, 0xa89ce21b, 0x308ac1f2, + 0xb378baa4, 0xefde233e, 0x4d50f46c, 0xdc906945, 0xfb1011c9, 0x1d950396, 0x66283874, 0xd86023ff, + 0x91fcc14f, 0x98255503, 0xc7fd9af7, 0xe3805e1b, 0x1db9ad57, 0xfc182d5f, 0x706473d0, 0x3e25a733, + 0x5ff2eb42, 0xdd2232cb, 0x8bbf90f9, 0x477c01b8, 0xb657135b, 0xfb4e494e, 0x0a553a35, 0x12e0570e, + 0xb0e53f30, 0xaef3a233, 0xbd2eccf0, 0xdbacc749, 0x1fd5e7fb, 0x2d2eddfd, 0xe6246b92, 0xa498954f, + 0xd77284ec, 0xe1955ac9, 0x1d90d96b, 0x861b99d7, 0x34281cbd, 0x5301ceac, 0xe7dfde82, 0xf64bdd48, + 0xe5913a7a, 0x793cc9fe, 0x5a28e0b4, 0xdabd231b, 0x704cc7bf, 0x75470fe0, 0x070ef5e1, 0xccfb0669, + 0xcd5a55f3, 0x1efc173b, 0xa51a25f2, 0x03ca507d, 0x6ab354be, 0x8efb880b, 0xb3113c44, 0xd37426be, + 0x3e9c65ee, 0xd05d02d0, 0xa2c4227e, 0xa37e94b8, 0x4e43f3fb, 0xc0f394d8, 0x1ab3502b, 0xcb4259ec, + 0x4091185e, 0xdda21ec6, 0xdd12608e, 0xe8b136dc, 0xaed03541, 0xfa27018c, 0xd4400e7b, 0xd45d0d4a, + 0x549ad089, 0x2646d075, 0x29d19bb0, 0xbeb587e1, 0xdd925fb4, 0x4453bcd1, 0x392feb3a, 0x56bd025f, + 0x431107ae, 0x4239596c, 0xca852528, 0xd4f447cc, 0x974b8ec4, 0x36de40bc, 0x391ed86b, 0xdf1e0866, + 0x8023c6ff, 0x051ddc68, 0xcb4eb9c5, 0x0f807496, 0xa1906bdf, 0x361f243d, 0xbb3c3271, 0xb05b2bb9, + 0xb0fed6f2, 0x1117e054, 0x73a6f610, 0x77dbcbef, 0x95e2dc9a, 0x3627a2f8, 0x3e4ef898, 0x0906a60b, + 0x84ee47d2, 0x7514474a, 0x5ec49374, 0x526612f5, 0x3132b7d5, 0xbc21d4ff, 0xfd04d632, 0x3c199f85, + 0xe2d231f9, 0xe0fde7c1, 0x94fa2faa, 0x28667d85, 0x4e88173c, 0x01caa5ec, 0x5a4ec55d, 0xff51abc5, + 0x01621db1, 0x700e5bc7, 0x4f6374ae, 0x4162c6d8, 0xcddff73c, 0x6473081c, 0x2f3044f8, 0xa8e39af9, + 0x9d595711, 0x44896e0b, 0xb41ef46e, 0x78a25f26, 0x982cfcbe, 0xeeb32a39, 0x0ad4665e, 0x3edf7c5c, + 0xdf03f43a, 0xd7fa2ccc, 0x8f7ae131, 0x611ba6e2, 0x966a3d7f, 0x8dbde81b, 0x844b37a1, 0x84812687, + 0xa288e6f7, 0x22f8a686, 0x3017801f, 0x55b1c0f2, 0xc1904efb, 0xa4e24545, 0x541235f5, 0x099642a4, + 0xb7a416c3, 0x1cd4aacb, 0x7a0ed2a2, 0x85c10391, 0x2d200eb9, 0x43a2cc2c, 0x38e972a4, 0xd780a42a, + 0x97cf2422, 0x41ff8bfd, 0xc35d1264, 0x0a40d99b, 0xa0d0ddd9, 0x21b70524, 0xaad5d7ec, 0xa17d80f4, + 0x2251bd3b, 0xf75b2bb4, 0xb06f9695, 0xe140798f, 0xf2facdb2, 0x5ea9c4fe, 0x72c39c84, 0x5f7e71e9, + 0x9d776956, 0x4e601f55, 0xe12a7fb2, 0x3d30da3e, 0xdb2fedb5, 0xcf45f184, 0x7aa0caf1, 0x712849a1, + 0xa1abd9a9, 0x028b5073, 0xf679862a, 0x56b026e1, 0xcefa19be, 0xc71606ef, 0x03bf39c3, 0x2ea8b0bc, + 0x6e2db697, 0xa246fa62, 0x493b1734, 0xa40357b4, 0x11cdc967, 0xcb4c7cbc, 0xa84b0977, 0xa1416891, + 0x5d035a6a, 0x3d562ca9, 0x11777013, 0xc4884f2d, 0x1eeea53f, 0xa0dbb58f, 0xea7daec0, 0xade53c6d, + 0xcd904c74, 0xbf09d79f, 0x174bf676, 0x213661c7, 0x09d682a2, 0xc6a8809c, 0x8779702e, 0x7d5bac5c, + 0xb41ef42f, 0x6a79e28e, 0x7cd55184, 0x2197c5d6, 0xba85c05f, 0x8bb8c087, 0x26c22b2f, 0xfa7c329a, + 0xf1c0e21d, 0xc8f1eba2, 0xc1c06609, 0x56040129, 0x9712418d, 0xef72369a, 0x51401505, 0xead47bd0, + 0xa78dd731, 0x7381fde3, 0x3bcabe16, 0x7ea2548c, 0x3750808a, 0xe0459dea, 0x5bc8eccb, 0x1228e202, + 0x41410194, 0x4e7882d2, 0x2782108d, 0x94d0e602, 0x1ac358bc, 0x1cca4b5a, 0x83679ac5, 0xfa41b825, + 0xcc5fb620, 0xfe03cebb, 0xd691360b, 0xf0fe8e6a, 0x09f43826, 0x0df148bf, 0xdcf7f4fd, 0x362d02b5, + 0x37a30027, 0x1c73c911, 0xac2e1130, 0x55339bb9, 0x614d211a, 0x367dd0f2, 0x7e4380d9, 0x67df4229, + 0x38052ced, 0xf667cb73, 0x2d6189a2, 0x57334458, 0x07d818d7, 0x2cd81c03, 0xb6178ff9, 0x5afcd318, + 0x6c175028, 0x9c45883b, 0x107e2927, 0x1d5948ca, 0x468f86f8, 0x087a7197, 0x7d29319b, 0x2dd7b8b7, + 0x37648ce9, 0x99cd0ae9, 0x7c262616, 0xc7ca6159, 0x6c7aad83, 0x1425b399, 0xe3665afb, 0x64d96484, + 0x3bde4b09, 0x9cde5b74, 0x04997576, 0x703a5b95, 0xa28ea3b4, 0x77c61203, 0x3eb40786, 0xf7728480, + 0x4bf23263, 0x948490fd, 0x19d70b4f, 0xe4842879, 0xbbb8e74f, 0x01f42c74, 0xd1b46d0e, 0xcc835dd4, + 0xc8a219ce, 0x8ad3ecef, 0x4565ceea, 0xb4755725, 0x9fbba82b, 0x44f56bf3, 0xb84c47d6, 0xefa2dc3b, + 0x0bf6063e, 0x26022b9a, 0xc11419c3, 0x78149855, 0xd156024f, 0xf96ac9ff, 0xe98a866f, 0x852d6101, + 0xbe4955fd, 0xa6ebd341, 0xccf184ce, 0xb1cb5faa, 0x235d47e2, 0x5dc87d5c, 0xb56d2056, 0xc65f6fcf, + 0xf6a12120, 0x16f3b6ee, 0x8c2d8724, 0x97f5e1ad, 0x27c20cae, 0x7b813e46, 0x409f5620, 0x67d4f5a4, + 0xe7b4ac44, 0xaf653b32, 0x593f0f8b, 0x98bfbd90, 0x44026709, 0x9d20bb12, 0x77f2e8e0, 0x9671bdc7, + 0x2d19f36e, 0x621f128b, 0x60b23a08, 0xfad2867f, 0x8ff4060d, 0x8547c9d8, 0xed99a9ab, 0x2a8cfeee, + 0xf7df981a, 0x0f65b8b2, 0x54def51d, 0xf239184c, 0xb86a5580, 0xeab4791d, 0x64d559e6, 0x131d8df2, + 0xc4f6136e, 0x50bb0929, 0x71b9ac43, 0xc490a8b3, 0x1ab50fcc, 0x0db6fade, 0xd2ef169d, 0xc30cab83, + 0x68f13e97, 0x64ff3b55, 0x43b30579, 0x2757a5d5, 0xdb10b0f2, 0x34b827e5, 0xf11c7a36, 0xd50ebf60, + 0x7bd34cbf, 0xbb0de394, 0xcfb39909, 0x3370273d, 0xae67a0bb, 0x6c0834ca, 0x8d90ce7a, 0xd95e35f8, + 0x92670ae4, 0x88b10923, 0x6b4c6e95, 0x8cd6a984, 0x1be4b035, 0x2905f702, 0x9db68f44, 0xc8199137, + 0xf25eeaa0, 0x8122339f, 0x5c0aee6e, 0x5308488b, 0xc398063a, 0xaa461caf, 0xa763d64c, 0x5d827fce, + 0x56de43b7, 0x3504034e, 0x61e6e6aa, 0xdc93fb35, 0x2e612f56, 0xb1082bd3, 0xb6e5f767, 0xe4aa88bb, + 0x922f526a, 0x915b42ac, 0x7e59609f, 0x90f683d4, 0x38624992, 0x5b92b8ee, 0x0a8bc0ab, 0xf014030a, + 0xe99fbf87, 0xdcc8208b, 0x8ae234e2, 0x3d8f0e0b, 0x71a65758, 0x3c8b1c01, 0x20acd33c, 0x339b12d9, + 0xf1e346ef, 0x66840fe4, 0x981c5353, 0x757d86fe, 0xa09c3950, 0x38e8f071, 0xc8deb16e, 0xf20fffa9, + 0x0db547c6, 0x43c47fbb, 0x2b94f98a, 0x6928fafb, 0x500e6647, 0xa704b495, 0x3c897594, 0x3d2c12de, + 0x20f2e5d5, 0x9fe2610f, 0x5a1bb728, 0x112e361a, 0x026d7aa8, 0xcf8e3047, 0xabe00d3d, 0x57393b8d, + 0x28f0d4b9, 0x9621c314, 0xb7ea975c, 0xaeeaba1f, 0xf9e5d7a2, 0x6835d81e, 0xa42253ef, 0x1d08a235, + 0x404939d7, 0x656a5a59, 0xbf9399e6, 0x0fa35f7c, 0x6896ca2b, 0x2e3b97aa, 0x0b4eb373, 0x3e0496ed, + 0xc091d80a, 0x0ebc5d44, 0xe9ce0025, 0xeeda30a4, 0x2ab3e9d4, 0x59404945, 0x57302894, 0xe865c801, + 0xf89ca772, 0x21ba6427, 0x9596fa77, 0x6d6862fa, 0x7e80fb27, 0xab561cad, 0x01a1e0a5, 0xf98ad068, + 0xc1f870c2, 0x5089f189, 0x3ae06f3c, 0x207292f5, 0x05c1d309, 0x9638bd4c, 0x238a59cd, 0x95e07a62, + 0x7aa68a76, 0x1bba6d49, 0xd079b2c1, 0x7a32c6db, 0x58ca05cb, 0xd074b5ad, 0xb7bafcda, 0x439411fa, + 0xf9219ef6, 0x042bced5, 0xa9266700, 0x3ee7dfad, 0x2d0b8a0e, 0xf06eeb17, 0xd9ca7df8, 0x782e07a9, + 0xdb7e0bae, 0xc5670b4b, 0x8132656c, 0x585344ba, 0x5a1c2423, 0x783f9f23, 0xbdeb2943, 0x7b4e5ec6, + 0x54d6b1b0, 0x6df7398d, 0xbbb67914, 0x83192d09, 0x43950452, 0x5d3968a5, 0x2a7425e7, 0xa5ded392, + 0x0055764a, 0x0a6c5c49, 0x039822c5, 0x041ce545, 0xfad314c0, 0xaa3e27d9, 0xe3ac6850, 0x99951410, + 0x609611d2, 0x87c6f618, 0x80d4bc00, 0x7efb7e58, 0x16b7d666, 0xc86d7ea6, 0x6c538ab0, 0xd77a4b9e, + 0xd057b3df, 0x67db353e, 0x60635517, 0x46182708, 0xa6169da4, 0x5da47b73, 0xdcdd57f3, 0x2ea6cba8, + 0xb0017977, 0x6f96e3ad, 0x24a99054, 0x43a7775e, 0x79025d11, 0x823461f6, 0x659ee616, 0xe3b852a0, + 0x65dad298, 0x6afc7310, 0x99b19bde, 0xac37af30, 0x755f6de8, 0x81c2413b, 0x9543dba5, 0x48677e76, + 0x1020dc50, 0x224140ba, 0x26aa58c4, 0x026cc902, 0x0497246e, 0x185f94a5, 0x6695b1e4, 0x4043ddc3, + 0x00d33b66, 0x99b96056, 0x576cabea, 0x8710e875, 0xec277d07, 0x596c3d89, 0x0ed1d42e, 0x0aec7781, + 0x2e9251cf, 0x9da1535b, 0x6656567c, 0x07020da1, 0x866a67e0, 0x074f65e2, 0xd56fe857, 0x8b86e7ee, + 0x64043286, 0x653e19eb, 0xed72a1f7, 0xae77b001, 0x0a48b02a, 0x7529cc27, 0xfc5cda7e, 0xdf0119ba, + 0x4e3c2c2f, 0x23ef9536, 0xf3a8b419, 0xf2ee29ed, 0x75011f4f, 0x87d97ccc, 0x74359e18, 0x87e249af, + 0x964f3edf, 0xb2aa3b1e, 0xe7d060d7, 0x79b16329, 0xcbae5be2, 0x769ef930, 0xeb0f491e, 0x80288816, + 0xfff66a3d, 0x245a997e, 0xf7e62331, 0xb51f84e4, 0xdde2d926, 0x23b4df9c, 0xbb8e2d14, 0xbbd29fa0, + 0xf71929de, 0xf339d633, 0x55f62d60, 0xee09c452, 0x6fac6258, 0x65fe4f4a, 0xaec51b8e, 0xc1b5181a, + 0xeaa9c1d0, 0xda717bbd, 0x57e854b8, 0x6604d2bf, 0xe93bd61b, 0x3e0907fc, 0x79eb9b76, 0x5f6ce484, + 0xc79394ad, 0xb38c142c, 0x4643057d, 0xfec45180, 0x42aed6ce, 0x5062d34a, 0x6dd95a3b, 0x4ed57d3e, + 0x7ecf8678, 0x19cfea28, 0x78b7b5f3, 0xe8f459c1, 0xd53a3dd5, 0x89b23704, 0x29806966, 0x5925f819, + 0xe976e0e5, 0x8bf8671d, 0x2f2e32a6, 0x696c92af, 0xfb02a953, 0x4e029f71, 0xc99a9165, 0xcc04c079, + 0x3e9dd191, 0xa6e8af2f, 0x155e8832, 0xfd5bef0e, 0xc91d0838, 0x2fbbe935, 0x0997ce06, 0xc125f943, + 0x987810b1, 0x8f746e3b, 0xfab5b2e6, 0xb43feee3, 0x5815d5d6, 0x66d7316b, 0x9b8c7cd9, 0x0e2c59f0, + 0xbdaeb71a, 0xc8f0ccdb, 0x197eeec7, 0x63b363fe, 0xb0958a4f, 0xed98d603, 0x79e9253e, 0xb557b22c, + 0x6e368959, 0xf79f4df1, 0x5c437e8e, 0xb9f7a85e, 0xaec0442e, 0x25421938, 0x99dfc8a2, 0x4ab7dd4b, + 0x65c9e2a1, 0x32a1fbd7, 0xb6922012, 0x6bc40fa5, 0x3cd6ad89, 0x1599edb9, 0xd78b4c52, 0xde1bff2e, + 0x5d928967, 0x45c448a3, 0xa22dd77a, 0x97449f49, 0x69646ab1, 0x0f744a03, 0x07dfbbe7, 0xdf159502, + 0x9f01fa29, 0x7837c7bb, 0x08c0a094, 0xb9144bd3, 0x9b953532, 0x64945b10, 0xe233028a, 0x1221465d, + 0x8c84e66d, 0x08a2765e, 0x58551b69, 0x454a351e, 0xb14bb341, 0xecaa5f82, 0x2cb24ece, 0xf696fbab, + 0xb247cc3b, 0xe3d63a76, 0x4cefa987, 0x617768cb, 0xec6ea506, 0x6bdb3ae3, 0x3a7675b8, 0x17ebd3ac, + 0x6eddeabd, 0xed6e5908, 0x8a3e4281, 0x62169a4c, 0x1076be44, 0xe372bd1d, 0x5a7b3fde, 0xbfedecb5, + 0x74d529c5, 0x3f7328d4, 0x638c8afd, 0x6ae54822, 0x1dd30eaf, 0x08ff46a0, 0x2923b4f8, 0xf608b4e2, + 0x9acad557, 0x77752fe8, 0xa596f968, 0x261fe8af, 0xe07dc4d4, 0xe31a399d, 0xac752954, 0xb4d436f0, + 0x09591209, 0x77d9f518, 0x07fe857b, 0x95ace54a, 0x36da096d, 0x83726f5c, 0x2cba3b47, 0xfa47cace, + 0x6d4909e8, 0xc7e1ca1f, 0x3294b588, 0x96f5812c, 0x9f10764b, 0xc4a7166e, 0xd4526348, 0xdd2631dd, + 0x0a031366, 0x91569de3, 0xd811f571, 0x0b6a6b95, 0x85255275, 0xc90ce7df, 0xc39cba2c, 0x351380b0, + 0x6869aeb0, 0x1ba2ab87, 0xb7713e44, 0x6b437b45, 0xcb5d1c4f, 0x8e9cb4a1, 0x1d28e473, 0x14b93fbf, + 0x66441b5b, 0x0f4eb566, 0xfe23eae4, 0x3c1d9fcc, 0x52b82381, 0xd4a9658e, 0x583f5c48, 0x08cb9c2c, + 0x140ed234, 0xe01990b1, 0x71f7782d, 0xea1017bb, 0xd7ff9771, 0x4aeddded, 0x8ef1ea4f, 0x03a41b13, + 0xa4768786, 0x044b6611, 0x399bda0f, 0x587d3029, 0x27d1b0e2, 0x6bf0c39c, 0x6d38fc9b, 0x60ecd906, + 0xd522cc0b, 0x06899559, 0xfad4c393, 0x64771eae, 0x9fd6c568, 0x82a2c517, 0xd67797f0, 0xc8ed8c0c, + 0xd9526426, 0x5b5ef2df, 0xe3ab3dbe, 0xb4b4ea6f, 0x1d49085b, 0x302605a7, 0x7206cd95, 0x6290cd60, + 0x48a58ad1, 0x1774c890, 0xfd0faa0d, 0xe4d225a6, 0xd7905541, 0xf605808c, 0x377e3be9, 0x24a854d3, + 0x606e7e68, 0xb7635a2e, 0x51bbe2fb, 0x96171ed3, 0x7e17a774, 0xeee99b8d, 0xea0faacc, 0x2c0c8ab3, + 0x185ece91, 0x5db50b3b, 0xcfa8ebcb, 0x1c6635ab, 0xcd1c3bd5, 0xfcb6d5db, 0x34d9b1c9, 0x8c512e52, + 0x93833e12, 0x9b4239cb, 0x99a84005, 0xbaf7d7e0, 0x08c6ce3b, 0x510e60b5, 0x370d8471, 0xf7640ceb, + 0x79f9c314, 0xfe43d758, 0x80659070, 0x91349105, 0xac9171ba, 0x7c3a1349, 0x55ebf0e9, 0x9c31a985, + 0xf0118a75, 0x49d15d19, 0x57aa246b, 0x7db9f0de, 0xad2bec8e, 0xcae8c357, 0xe69070d7, 0x3b626cf0, + 0x1cb8b284, 0xfb656f57, 0xb891c22a, 0x4e6d77c6, 0xbcedc5a8, 0xc29cb4a9, 0xc3d4ce0b, 0x18cfd0b5, + 0x6909404f, 0xb8eb24ca, 0x78845ae6, 0xef441b1a, 0x91ebbc62, 0xadf458b7, 0x89e64f1c, 0xdf95543b, + 0xd19161b5, 0x503f7bc3, 0xf9cc152d, 0x4debe1f9, 0xb8b3f408, 0x78db0015, 0x636835e7, 0x4a74f868, + 0x9f450922, 0xe9a77dca, 0x480073b8, 0xf98220c6, 0x0164c85b, 0x882a318b, 0x7c0c6e85, 0xe7553f1a, + 0x71d06c10, 0xae23d329, 0x9991728a, 0x0a2f76fe, 0xb73765e4, 0x2eec9fab, 0xd7c1aae7, 0xfc449aa5, + 0x1b7c2609, 0xa3308507, 0x9f0a3e9c, 0xd31be706, 0x6b02db3d, 0x6b96e3e9, 0x9d8c134e, 0xfa9e6b33, + 0xaf09852c, 0x359f28d0, 0x7112123f, 0xc880bac4, 0x7790c6fb, 0xef037250, 0x50d61736, 0x5ac24e62, + 0x28f7b37a, 0xf6982478, 0x345c9cf0, 0x8584d753, 0x98a36eec, 0xfeeb1aa3, 0xfae98e70, 0x071cce20, + 0xb0b684f3, 0xfa0f8fc0, 0x0b77bd8f, 0x726cd1b8, 0x7584c083, 0xbcb15a5d, 0x49213326, 0x29b0a32c, + 0x2173227d, 0xd7b2fd84, 0x348d2d9b, 0x0ffec20c, 0x1c54e674, 0x2aacf70c, 0x711c9f16, 0xb56c6df0, + 0xae534f4f, 0xf1a94666, 0xaea7edf7, 0x49b84f6a, 0x0ab3a16f, 0xeb7d4a6f, 0xed841d64, 0x070ecc8c, + 0xe8f5d9fd, 0x70b659c3, 0xa32b8436, 0x20facac8, 0x50a857a8, 0xfda8db82, 0x31be72d3, 0x7d5ae491, + 0xd55678fe, 0x7ad35702, 0xf0f9014e, 0xca9fc2e2, 0x5b39a460, 0xd7535353, 0x13df22e9, 0x5ad1e5b3, + 0x39504c8a, 0x1fdc240c, 0x60f551e8, 0x81ccaffb, 0x09ecb098, 0xeba940c3, 0x2e12ae35, 0x8b893a37, + 0xa5ced6c1, 0x4db05c16, 0xa3de677f, 0x90e2e010, 0x3ca96521, 0xd56bdd07, 0xc2fd1b4b, 0x3099d328, + 0xea5812fb, 0x4e2d873b, 0x2d929b67, 0x27ae2196, 0x1d6d3a6a, 0x445ae35c, 0xf5c17a1a, 0xf6330e25, + 0x2ff08785, 0x2baecb3f, 0xc36392bc, 0x1bc78559, 0x4ace4333, 0xbd8affec, 0x63a1db18, 0x12841038, + 0xae1322ee, 0xc53287c9, 0xd6413769, 0x15a4fb11, 0x6dfcc04d, 0x325a9df8, 0xf0930952, 0x0dc4da6a, + 0x56bb4d1f, 0xc1a616a7, 0xfacbd535, 0x806963a1, 0x8721328f, 0xab521bcb, 0x461028ba, 0xd1404653, + 0xed2ec4c4, 0x8456e9a8, 0x288b02de, 0xe74f6b57, 0x15ba1267, 0xcdea079e, 0x647071d8, 0x93b061b2, + 0x935d6985, 0x766c45b7, 0x685ae1dd, 0x4a46f6a3, 0xfb9a0644, 0xcf4e6c55, 0x9ccee18a, 0x816bc1bb, + 0x616b3118, 0x5bda7e6f, 0xca46873e, 0x4decf8fe, 0xcc330559, 0x4065c9b3, 0x5c2c7be2, 0xa437725f, + 0xe74065f3, 0xc4921622, 0x7efea911, 0xc6c0b1ef, 0xbddf109d, 0x4a24520f, 0x47016950, 0x19ec01da, + 0x3dd55d76, 0xfbbf6107, 0xa0457fad, 0x89aed75f, 0xc5b41c30, 0x6778265c, 0xd4380dfd, 0xb2efc0ca, + 0xa5b42ca0, 0xfa0040df, 0x1b1d1fdf, 0xea397cca, 0x21617b95, 0x1018fb1d, 0x8fb9487d, 0xc077bab6, + 0xdc9dbdbd, 0xff2919d2, 0x680193ce, 0xa8453dda, 0x2ef76415, 0x01553253, 0x8cf36d71, 0x1c8ab4c0, + 0x6707bcf9, 0x2ef29006, 0xa10607c9, 0x0322e371, 0xa52e2e6e, 0x56f7da79, 0xa4acb05f, 0x5e4abffc, + 0x23eb42a9, 0xe8d480a2, 0x2e041b8d, 0x0f2de73f, 0xaf003408, 0x852e4846, 0x2e193de6, 0x01950c6d, + 0xd1e1ea73, 0xec09663b, 0x9338dfd3, 0x98ef6208, 0x9174c454, 0x45ee9552, 0x8d61a6c1, 0x9ac75012, + 0xf25002ea, 0x75d83a4b, 0xafb1c249, 0x90615ffd, 0x15d3d631, 0x3ff96e4b, 0x8669b3dc, 0x015fa8e0, + 0x7b31dd9c, 0xcbee8952, 0x6ad5ef8c, 0xeaeed538, 0x9c3b7bd0, 0xc5c9d402, 0xe4693279, 0x71d31ef5, + 0xac7c0d54, 0x9499ca1a, 0x45999a12, 0x0d7894f3, 0xa66aa26b, 0x07f3c293, 0x6dfaf6fd, 0x6111c8b8, + 0x1f219089, 0xf1beff2f, 0x9863024f, 0xcea2d4cc, 0xd6908729, 0xb249be79, 0xda3bbafd, 0x14413da5, + 0x92165ac9, 0x1b04bcc2, 0xcbd39431, 0x8aa8eb11, 0xac6af5cf, 0x3c960f9e, 0x70015ddd, 0xe71684fa, + 0x443034a2, 0xebdd3a8e, 0xe4a91f98, 0xc306ca47, 0x56e6de31, 0x8e9c950f, 0x41d5ac3f, 0xfce7628a, + 0x2d34b704, 0x198301f9, 0xdb950db6, 0xb3203518, 0xe182fd83, 0x4ef53306, 0x6ed8cddf, 0xef9f1c57, + 0xa1a56573, 0x23bc4e9c, 0xd0c1b08e, 0x7ab8e923, 0xa1946ed7, 0x9840e7fb, 0x90092a13, 0x2adb96fb, + 0x879592df, 0x6d70a7cc, 0x18e5dc14, 0x1efa8477, 0xa70561b5, 0x55369dd6, 0x65e8cdc0, 0xfd5bde7e, + 0x9041a99a, 0xa4a667fb, 0xfc1d5b33, 0x37a36b1b, 0x57bc2419, 0xfc0ae53f, 0xcd5f1ecb, 0xc22d2dc8, + 0x629ad2d7, 0x8227995b, 0x61dea505, 0x5df9cd8b, 0x9909370e, 0x3e1ee058, 0x6a6cb57e, 0xfce460e9, + 0xa98fdbaa, 0xf2429574, 0xc90f1d0c, 0xa81999d3, 0x88e36cd8, 0x4d4a2e16, 0x27e2bcc5, 0x55e7c31f, + 0x674f6247, 0xd06bad61, 0x0316d6ca, 0x2f2c9f19, 0xeef22f8d, 0xfaca836b, 0x097dc0f9, 0xaf53a96d, + 0x31a6acb3, 0x6dd11971, 0x8e78c37f, 0x9c9c1f2c, 0xc9ec7539, 0x13139f44, 0x2186c263, 0xbd7337bc, + 0x4e39d57f, 0x8a609c14, 0xa3fc1a52, 0x866227ac, 0xa8e23751, 0xf16b0dfa, 0xef24aeb9, 0x7a3082fe, + 0x7b156c52, 0xec94a8e0, 0xc9b6f0f9, 0xb3f48237, 0x7e6aec02, 0x3eaff5ce, 0xb544a3c6, 0x249a1e4c, + 0xadb4bd0c, 0x9bc8728c, 0x90acca10, 0x937f5b93, 0xe3fcb57e, 0x048439dc, 0xcc22b619, 0x6d5de6b2, + 0x92fb652a, 0xff49e4af, 0x6f1dabf4, 0x32b8a1f0, 0x05d506a8, 0x6db71c05, 0x37f6cee1, 0x27465f7e, + 0xa7c8dcb9, 0x1a229820, 0x2a2e3879, 0xd2e9dd24, 0xe9e83cae, 0x127dd08b, 0xfe5d62d0, 0x5efc24e9, + 0xdeaac031, 0xb9fe76f8, 0x9230ddbd, 0x177294ea, 0xa5fb0d27, 0x22cf9992, 0xc8e76569, 0xe9b8f574, + 0x92f7fb01, 0xecd676d1, 0xf99c354b, 0x846f2e30, 0x7f18178b, 0x0ad7643a, 0xc8159931, 0x6574ef87, + 0x2bef8ffa, 0x525e9e60, 0xc9c7c0b0, 0x69ab27cd, 0x12c65bdd, 0x39ccb77e, 0xabb6fe6e, 0xd2a0f264, + 0xe1c908b1, 0xde4660dc, 0x3a63887e, 0x684718dc, 0xb9f0869c, 0x0bd128d5, 0xfbc3c6e1, 0x420866c4, + 0xd88c1136, 0x719cf96e, 0x4eda5f2b, 0x1749d212, 0xe32de359, 0x2843d6a6, 0x5a39b4ad, 0x31b8067e, + 0xf333b88a, 0x021275c1, 0xd2bbb178, 0x0b6a75fb, 0x180093b6, 0xbce810e8, 0xf3b33c92, 0xe6bbc4d6, + 0x2a1b782d, 0xb57b9b8f, 0x34bd4a98, 0x408373ae, 0x887c7112, 0xf5a71cdc, 0xf7e70779, 0x49875e8f, + 0xe125316d, 0x0bfc82d7, 0x3b5cb3b3, 0x991d46c4, 0xb3cdc33c, 0xd2abf2cb, 0x43ff4524, 0x1688c791, + 0xcf81cb7e, 0xa829746e, 0xa23f0ebf, 0x431357f2, 0xc89a31aa, 0xffc5d265, 0x6958f724, 0x2bf59265, + 0x53e24f0f, 0xf3e9cf23, 0xefe48509, 0xedb44f72, 0x7e290225, 0x45f94818, 0x32d40a5e, 0x8929c2df, + 0xe0c71a17, 0x6f158793, 0xa444d529, 0xe90886cc, 0xb9de3bd8, 0x346ee259, 0xe9dc00b1, 0x2de0a88f, + 0x8ceb404e, 0x5c95eb65, 0x1ed8c593, 0xb01ad347, 0x020bed23, 0x3db80c32, 0x51eff03c, 0x86ea095b, + 0xc2be33f2, 0xb47b9eb4, 0x920d1cfb, 0xc92a727a, 0xc8efd446, 0xe0cc573d, 0x61516152, 0xcb028623, + 0x420ab8b0, 0xb12c647b, 0xe4d189c5, 0xcfab388a, 0x605276aa, 0x50520692, 0x5483030a, 0x15b2caf8, + 0x5073aabc, 0x9ddde1ab, 0x1fbc85d3, 0x31a29213, 0xa81d48a4, 0x02a636ab, 0xdb99cc7d, 0x18b0068d, + 0x2591ba87, 0x18eefe6d, 0x12a0a8f2, 0x01a59560, 0xe3dc84be, 0xa02d4afa, 0x5425a8d9, 0x2bffb405, + 0xb8e2e3fe, 0xe6cd3834, 0x7c0442f3, 0xd3ecb3fa, 0x7719458c, 0xf7a16151, 0x9b375bf3, 0x55506eba, + 0xc816eb85, 0xaf9b1c2d, 0xb35407dd, 0x140ccdb7, 0x8cad5777, 0xde01f17f, 0x10f67620, 0xa16f9020, + 0xa0b6dc58, 0x49a2c522, 0xd27e2577, 0x78fcf879, 0xa4a2f303, 0x197c0caa, 0x13ac9180, 0x39ac18b6, + 0x80e50fa9, 0x93dd9652, 0xf414252e, 0x4ba93830, 0x28b46cd3, 0x64370d1e, 0x0d244294, 0xc5581c9a, + 0xa723ad7b, 0x23f27717, 0x7af5d9ff, 0x1044f4a7, 0xb8ca58ee, 0x552426a2, 0x29ada1c7, 0x18b307e9, + 0x528ca545, 0xc0265dad, 0xf0e0bd68, 0x4de3a2d3, 0x4532ad65, 0x8754a298, 0x15a1f161, 0x70dd7ad0, + 0x15ac82f5, 0xfd1cf51d, 0x19eb9f7e, 0x0caac20e, 0x59efb867, 0x707c5d51, 0xb440cddd, 0x7ff20755, + 0x731eeb04, 0x26050aa8, 0x1d346d06, 0x3de2f4d7, 0x652ec175, 0xbde5dc47, 0x6c6927b9, 0x58d1e960, + 0xc7c78e93, 0x870f9f1e, 0x179d62f9, 0x94828d62, 0xae7363a0, 0xc0bcbbf8, 0x65e6bda3, 0x3210bf9b, + 0x119f0ba1, 0xb2828732, 0xace129b8, 0x38716c75, 0x05ed076b, 0xcb95f66a, 0x2e4b5c5f, 0xc16502f2, + 0xfa214b41, 0x1175db6b, 0xdbdc05a6, 0xfd5f06e2, 0x668355c5, 0x48eeef80, 0xcf43c034, 0x81f35504, + 0x5c519e92, 0x7ff967e1, 0xd7617f27, 0x0a340e4a, 0xdc632023, 0x3fca42b6, 0xe41a7a2e, 0x734ffbed, + 0x261bf2fa, 0x72915bf4, 0x1d52434f, 0x9cfa8256, 0x41a480b5, 0x1dfc7bde, 0x392d190f, 0x9ff3ac98, + 0xd6212c9d, 0x5b9be820, 0xd07a1118, 0xcef75f28, 0x2397992c, 0xccb0ced8, 0xb12272f0, 0x72a5ca73, + 0xd1ca8706, 0x8f542c94, 0x90ee7b1c, 0x8b9b1c59, 0x6f531cc4, 0x7261e957, 0xc2a5889d, 0x92633e94, + 0xff16e600, 0x6fbd16f6, 0x23b4df8c, 0x6d7745ee, 0xcaf48ed4, 0x80a5e37f, 0x62ca3b3d, 0xc3521cbc, + 0xf9391dc8, 0xdaaf8e37, 0x54af502a, 0x91640344, 0x9a849092, 0x784e699b, 0x7304c222, 0x77f94def, + 0xba799ac3, 0x70d6a48e, 0x4a521b5c, 0xae9ee479, 0x3069f428, 0x1924de82, 0xdaa800c0, 0x6343de14, + 0x5e3e8a34, 0x029d544e, 0x60f2ae8c, 0x99048350, 0x910db89f, 0xcaed7135, 0x83879a6c, 0xb9a25bcb, + 0x604aa1e0, 0x5487c3f0, 0xe53c0f8e, 0x398e2791, 0x4d4eee26, 0x8127fcca, 0x3e2e567c, 0xccc7bcf0, + 0x93f34b30, 0x9498aa7e, 0xefc22e36, 0x0a7af718, 0x84df1994, 0xab489336, 0x272f91af, 0xc595e913, + 0x98b451e1, 0x457c931c, 0xad60033b, 0x9f4a665d, 0xab81c04b, 0xf1d2014b, 0x3e738b06, 0x112fbc87, + 0x264ad049, 0xca30c142, 0x8fdd5e47, 0xe9a5e743, 0x624f6a7a, 0xb47c99a4, 0x772717b9, 0xdb6f26fb, + 0xbddecd9f, 0x2429d57a, 0x05c366b1, 0xb6b6787c, 0x20ff829c, 0x52ec547a, 0x498bae60, 0x801a4751, + 0xb35da2e0, 0x619c32c4, 0x317cabf7, 0xa7f4a57b, 0x06a65411, 0x1175dfd5, 0x863f03a1, 0x3d0ee513, + 0xef7764a5, 0x32798bb8, 0x57b24fd5, 0x3a50e358, 0xe9415702, 0x281e725b, 0x4c443082, 0x5e76260b, + 0x63d8d495, 0x49d3e0d7, 0xebc3c9ed, 0xb6368ed0, 0x5a050164, 0x0d8e96f0, 0x54afe9b5, 0xc4e0b39c, + 0xc30d0544, 0xe904bfd3, 0x0d8aad20, 0xc7ba0fe7, 0xd7c773ca, 0x08126c80, 0x075e9747, 0xeba6dc3d, + 0xff11ce10, 0xa237d2f9, 0x66b0661d, 0x781b3bce, 0xff6b8ee9, 0xe220c4ad, 0xe1183210, 0x3a206522, + 0x3f648417, 0x0e1c45ca, 0x3b848160, 0x206854d3, 0xf9cd68a4, 0xd2d3b69a, 0x99d12769, 0xc29676f8, + 0xebb2cd57, 0x824613c0, 0x9fc4d39c, 0xed6ae04a, 0x27b9e67f, 0xcbca0df1, 0x1992f352, 0xca9f4acc, + 0x4c8688e4, 0xc0498cf2, 0x80b0fd14, 0xfdbd1fb1, 0x98caed92, 0x6402d23d, 0x6d3667e7, 0xcc70fff3, + 0x4a11a18a, 0x33304de6, 0x3a5966b2, 0x37fd692a, 0xaaf00f8d, 0x64ce3603, 0x899d67ea, 0x6df32688, + 0x67b94bbe, 0x92555d15, 0xdb4b825f, 0x6f0a61da, 0x74454384, 0xae804b6d, 0xe7814842, 0x21bf1f2d, + 0x55dcf638, 0x6b48c298, 0x94b645ce, 0x21e25fb8, 0x22e23e60, 0xfbfd718c, 0xd0b85ea4, 0x2153eef7, + 0x684513f8, 0x120cdf87, 0x6c8e3376, 0x3aedf3ab, 0xce155c50, 0xca97832d, 0xce1de0b6, 0x0f55af3c, + 0xd70d855a, 0x57dd7c1a, 0x2304d35a, 0x51c41466, 0x3c372adb, 0xdde3213d, 0xf0cea25f, 0xe71832eb, + 0x77572256, 0x124e7d31, 0xdc8f7dca, 0xf6d545c8, 0x3f4361c0, 0x353acf59, 0x632b18c4, 0x11533496, + 0xc3252bf8, 0xbdfc9f46, 0x12033ab1, 0xcce8c16b, 0x52f3d465, 0x4f30595d, 0x4dd21b26, 0x14285e90, + 0x015987c9, 0x4b6c9963, 0x44579836, 0xcfdbe38b, 0x7f5d2102, 0xfd5ada04, 0x8e9aa49e, 0x07bbf7cd, + 0xc1a3821b, 0xab654dca, 0x51aa2932, 0x702013b7, 0x6b582db8, 0x59843b5d, 0x32800726, 0x3b4ac27c, + 0x199319cf, 0x8c34acf4, 0xcc0545fd, 0x09757414, 0x68169aff, 0x880534ac, 0x5caf4487, 0xab44ee49, + 0x23466169, 0xd9dd99fc, 0xc7b3589d, 0x9b285b31, 0x15627f87, 0x65115420, 0x7f047465, 0x64b94290, + 0x356caa58, 0x400cb0b6, 0x7a90c0b5, 0xca1ea90a, 0xad22512d, 0x8f744da6, 0x1f8a9f16, 0xfed9058e, + 0x34c13ce5, 0x98386194, 0x6ae3dc9d, 0xa3fd6806, 0xaeb25f6f, 0x344a9649, 0xd4682c0f, 0x58b0968c, + 0xc21bba34, 0x085a1a74, 0xc9bcd35b, 0xb5fec7e6, 0xcd0f32b2, 0x719ce23c, 0x71fcd309, 0x88ec5a83, + 0xb5403b18, 0xa610bbb1, 0x848b2208, 0x0f0d9da5, 0x09ef0660, 0xb110c987, 0xe6928c43, 0x101ebe0e, + 0x14c8814b, 0x1b322f40, 0x5b393cd5, 0xfdd903d9, 0x36888136, 0x1176b3d3, 0xe3c2e4be, 0x55d51fda, + 0xb3f9dd78, 0xca77c672, 0xa71a747e, 0x614390e6, 0x08396869, 0x8fbdbc12, 0xa35ee5a5, 0xa5a683f9, + 0xcb7fe7d6, 0x1d5d0d91, 0x2af49188, 0xb1d687ac, 0x60231ad8, 0x617fcbb8, 0x6700be19, 0x2f4d57f2, + 0x5b2c4eea, 0x4b89c9c5, 0xbc28ac26, 0x6111159e, 0xaa8ced5f, 0xd7d87041, 0x3757e4e3, 0xcee6bdfb, + 0x42b20d56, 0xb024cc42, 0xbcd2a4ea, 0xf5d9730f, 0x624d4941, 0xbb5ca622, 0xfdebbfd1, 0xf96ac576, + 0x324430a4, 0xdccdd390, 0xf4ea6b64, 0x961aabd7, 0xf09a9c19, 0x36c3eb4d, 0x90035791, 0xc832be16, + 0x3620c5aa, 0xb9c54e3b, 0x89abb8a7, 0x4fe8e569, 0x72643b61, 0x056785c6, 0x84ccfaad, 0x55169b41, + 0x9338e166, 0xc69fa874, 0x880a137e, 0x987bb58b, 0x484f5ba8, 0xd75de8bf, 0x5399228e, 0xd1196e80, + 0x49071479, 0x7319c289, 0x2b837a30, 0xcc412c9a, 0xda9426ff, 0xaf7db298, 0x9ac562c3, 0x69813f24, + 0x6259b1b7, 0x749f7592, 0x9d5cb566, 0xe13cc77a, 0xfc6e037e, 0xd928f2f5, 0x8721ce46, 0x3f2cf2cb, + 0xf80bd603, 0x30fbf6aa, 0xfc7dacd5, 0xd41eeff2, 0x6800384d, 0x6f22e213, 0x6aa2edf1, 0x4a7dc91d, + 0xae2fbea4, 0x5d6563d2, 0x33abc15b, 0xad15b239, 0x97d422e9, 0xad9fa47d, 0xb5425d34, 0xc4a14dbd, + 0x60b1f163, 0xb4572a24, 0xc8872196, 0x0eae5844, 0x6b4035ca, 0xa8bff99e, 0x91bd6810, 0x31d37413, + 0x9f40afdd, 0x8d577fa7, 0xe82bcb78, 0xc9be82e1, 0x4df0edde, 0xc03d1102, 0xeb0f2333, 0x69b5c34b, + 0x70c83ead, 0xb4fab489, 0x5404db42, 0x0baae87c, 0x1434d49b, 0xf157f594, 0x4e3aa4ce, 0x35458443, + 0x95465d2b, 0xa51ee32d, 0x884e3c9a, 0x70160cc5, 0x7c9810ec, 0x5e06a35e, 0x075b88f2, 0x825644e7, + 0x22e7bac1, 0xd4855032, 0x41352500, 0x8839e5d4, 0xc1196d9d, 0x9c5d35ce, 0x78558f4a, 0x160e44f5, + 0xdc0f52b8, 0x8b65ccbe, 0x962cc8c0, 0xf16a5a7e, 0xbe42c3d5, 0x53fc7ba6, 0x407584e2, 0x84ec5286, + 0x23b149c1, 0x1adaf1bc, 0x69a6540b, 0xb7dcc02a, 0x64886987, 0x5b649d43, 0x8eb66d66, 0x7e92d871, + 0x74cf3b17, 0x3baa95c1, 0x6c505219, 0xdad034aa, 0x3f602ddd, 0x7e91c202, 0x8407d4ea, 0xcb1b6030, + 0xff0c412d, 0xb53eaf9f, 0xaf7daa50, 0xe29dc4ee, 0xf805c7c2, 0x2d3f49fa, 0xbe5e4e71, 0x9fc6038e, + 0x9d050478, 0xb48e4a40, 0x323da799, 0x9badca8f, 0xbf02f907, 0xfa69e3b6, 0x803f7a6d, 0xdf4ad35a, + 0xbf3db325, 0xe4df75bf, 0x393d909c, 0x5bbc1c26, 0x35370439, 0x9cbcf551, 0x5bdb8b88, 0xd33bb9d2, + 0x56fc2293, 0xde658060, 0xfd140da0, 0x9d825901, 0x566adb27, 0xeda908e1, 0x5ebcb187, 0xb83c6d62, + 0x47723848, 0x5e5519f9, 0x7a177c24, 0x6f8561ae, 0x1ef8f598, 0x268a4704, 0x19ecf9eb, 0x2a84c709, + 0xcde43366, 0xea627ee4, 0x30f8368e, 0x4cee4e2e, 0xf97cb149, 0x6326a79b, 0x73a7c6bc, 0xc25c64ab, + 0x67ccef3e, 0x9e30da4f, 0x027d2ee7, 0x58ed86ed, 0x363a12e6, 0x3c42896e, 0x2753b498, 0x8b340593, + 0x53e13153, 0x8f4534e9, 0x87ba77ef, 0xeb39b71d, 0x2f3f113f, 0x30d07879, 0x9bed606a, 0x477aa0e7, + 0x9d3e04f4, 0x8123fa84, 0x2c60c4e4, 0xe8058364, 0x50be9ea7, 0x1687e5a1, 0x3e9e7832, 0xb5417491, + 0x581785ee, 0x8da51964, 0x88ae5d90, 0xc0752ec2, 0x4ce9ca3a, 0x76a59948, 0x47f80c34, 0x02e4b6e0, + 0xf2a1cfb7, 0xd2292a03, 0xdb267db4, 0xf10354ef, 0xb240da1f, 0xc4e47f08, 0x7bf70c10, 0x0f3f477b, + 0x4b9e3911, 0x8d175bdc, 0x53fec89e, 0x956cc2d6, 0x31c497c1, 0xfdcb6b65, 0x036a3f62, 0x3ce1eced, + 0x4c74be6d, 0x32bf1979, 0xb477ebbd, 0x2f1e919e, 0x00732196, 0x2f62cf63, 0x5a64616f, 0x9a57e296, + 0x6f6ac705, 0xdf92eb9f, 0x30342028, 0x49f14ca8, 0x329a26f1, 0xb1d54f6a, 0x608ea4ab, 0xda377d27, + 0xcf4cd092, 0x03a6e6ec, 0x7dcbf703, 0xe6f3b7f3, 0x618b1bcb, 0xfcb55d9b, 0x5b1a6653, 0xb433902a, + 0xbcc6c46c, 0xbcf0755b, 0xcf2e1219, 0x49647033, 0xdf810459, 0x0a78eabe, 0x54db295b, 0xa4d2e405, + 0x4332b6ea, 0x6ae2da2c, 0x341c047e, 0x4a539a0b, 0x5a105c26, 0x4fa94c14, 0xe1f0fd00, 0xa3beb1dc, + 0x5436deaa, 0xd352e1b7, 0xd0c99d35, 0xafe9cf4d, 0x4d72363e, 0xaadc29cc, 0x490c4531, 0x2042363b, + 0xea06ee86, 0xefc37592, 0x9bf19d31, 0xfaeea22e, 0x37adf412, 0x06427676, 0xb37f6758, 0x4834618b, + 0x23c7d9a1, 0x21b4a4f2, 0xc7c332f5, 0x05409f3c, 0xc0f9eb2b, 0x70005a65, 0x0de87249, 0xd7d49b8e, + 0x569859ab, 0xf3c4b800, 0x1cea1d46, 0xa4516bad, 0xb765eb80, 0x9b7535be, 0xcb7b2e50, 0x6d9d710d, + 0x2c954b82, 0xca2c76aa, 0x45715845, 0x952d5be4, 0x346063b1, 0x4f19dfae, 0x529c0a0a, 0x6e3f3e25, + 0xd32a952f, 0xb7b82efd, 0xb2283180, 0x20b6b5b3, 0xb158ce10, 0x3c7487e3, 0x8b131fa2, 0xef97bce7, + 0xfb01a669, 0xa8b0fb0f, 0x10319264, 0x585c6821, 0x67ddf82f, 0x2ed461df, 0x81fe667d, 0x4261acd9, + 0x512d4023, 0xa93ce498, 0xf200df02, 0x55941130, 0x79001149, 0xece774d7, 0x7d226da3, 0xc9b75b70, + 0x07f08606, 0x64bdc2eb, 0x7d26303b, 0x38a13e3e, 0xd97820ef, 0x5a435b88, 0xb7d4b9a4, 0xe6ca57c7, + 0xcca3eb1b, 0x43b8727a, 0xac70aee6, 0x6108c31e, 0x663873f6, 0x911057dc, 0xcaae7369, 0x362905c0, + 0x539348b0, 0x6a0283cf, 0xf8a746a5, 0x7ffcd723, 0x1975b779, 0x277eef78, 0x3c9bee64, 0xa4b5bb73, + 0xa0258925, 0x87f6a33e, 0xcaa88e53, 0xc4dec5d2, 0x373df5fc, 0x0c691b31, 0x9f445779, 0xd3ddc1a8, + 0x125d7b67, 0xc6379030, 0x3307ecf7, 0x14a93b3c, 0xfd2ff94c, 0x0e4bb461, 0xd5c179ac, 0x0a46f4b5, + 0x68bb08b6, 0xae3946d1, 0xa9303165, 0xa1b776a5, 0x75753708, 0x0bdbf5e7, 0xb29e9e6d, 0xd04e5727, + 0x33443116, 0x5d05cfab, 0x5ae87b27, 0xa700ba9d, 0x54f6b1f9, 0xf8076350, 0xbc4ec6d5, 0xc0a6c286, + 0xb5956c02, 0x793f950a, 0x28a7a5ce, 0x41c97276, 0xb89be1a7, 0x1a590791, 0x3a59b9cd, 0x13a6382f, + 0xac0a7dd1, 0xe2f77bd6, 0x6ac00825, 0xea22785c, 0x8f60d10e, 0x59a87bcf, 0x067bab24, 0x87a6c6e8, + 0x6340967b, 0xb630d39c, 0xa1ddc765, 0x16c88524, 0xc16b73bf, 0x16ed3808, 0xcd3839b6, 0xf13a07bc, + 0x9ab33642, 0x0cd97a07, 0x3fd75c60, 0x8ef21997, 0x98de71f9, 0x8e85a255, 0xcaba76d5, 0xdb20ae34, + 0xf8c95a02, 0x57ff3ccc, 0x857328a8, 0x990eb07f, 0x0857e355, 0x79e95d75, 0x1dedde47, 0x37f98ac9, + 0x4386da85, 0x97934af4, 0x80c6481b, 0x028ce833, 0x410c7797, 0x425d4c00, 0x9bc5c281, 0x238773d0, + 0x2527ef96, 0xaf13e81a, 0x0cfad1c5, 0xd4b546fa, 0xb4a1eb34, 0xbc06fc7a, 0x6abdf2f2, 0x7dd8a7db, + 0x4ec21e96, 0x49d71aa5, 0x581dbc45, 0x5b6c4bf5, 0xce3f7e6e, 0xa037f1b5, 0x3cff148e, 0xb69b2c93, + 0x746f12f7, 0x603ca80d, 0xa69c0fd8, 0x4ba56bf4, 0x1190a837, 0x60aa6a9f, 0xe5f8c607, 0x51baf95f, + 0xb2bb4e11, 0x62f202d9, 0x435aefee, 0x0f42a3f2, 0x6d50d36b, 0x127dc27e, 0x672257bc, 0xa1e6cf00, + 0xd4e1f8cd, 0xbc8e566f, 0x7b6563c8, 0xf728226f, 0x349c3b7d, 0xa05fc152, 0x4d71e033, 0x85f33f56, + 0xced64d95, 0x8a991f5e, 0xcaca719b, 0x8b52e421, 0x953570f6, 0x639de297, 0x9966e258, 0x111c5b12, + 0x410d8901, 0x2b183899, 0x7cfa99d8, 0xa02fe9eb, 0xbbe46c91, 0x4b3585aa, 0x95cec575, 0xa3f73f6b, + 0x3594f706, 0xf9ca0d0f, 0xc20f27b1, 0x3e4eed71, 0xb5849877, 0x1eeb7a3f, 0x06aec493, 0x76f9131e, + 0x23bdbbd9, 0xb437875b, 0x5c273af3, 0xa9cc7e71, 0x8d078da3, 0xf646b314, 0x1f0106eb, 0xffd3a6b9, + 0x582e56f7, 0x1af6ce8f, 0xea2888c9, 0xdfae758d, 0xeebc0f89, 0x499df944, 0xcae84dd5, 0x4be6439e, + 0x61e2ecd6, 0x3df5549b, 0xaec117e8, 0x67107c64, 0xbd00db9b, 0x7aafae03, 0x7487bd5b, 0x0021e997, + 0x4216325b, 0x15e1b863, 0x42c896dd, 0xce7655de, 0xcb2b36d5, 0x786a0aef, 0xcc893810, 0xb388096e, + 0x30fd6973, 0xe7febd9e, 0x351062f2, 0xfe31057e, 0xf21e7ce9, 0xecfe2be3, 0x899265e9, 0x8377f38f, + 0xde89dcfb, 0x9dcd1f70, 0x790d6376, 0x4feb1b52, 0x20d10247, 0x76a25da6, 0xdf579044, 0xff3e445a, + 0xf3107685, 0x16969538, 0xf02a5f3c, 0x60a5e278, 0x4d58e7d2, 0xa44ac5d4, 0x0c692219, 0x00622cb6, + 0x04e59ee1, 0x871e46a6, 0x28c2d625, 0xbdb4e468, 0xd3fe3a7f, 0x58661034, 0x975a15ce, 0xc9f8c196, + 0x2283bcab, 0x5028b149, 0xba519cf5, 0x14c05ca2, 0x0becf461, 0xb023784f, 0x20e30639, 0xeca90705, + 0x4375506e, 0x9d2bd850, 0x8e02efc5, 0xc5b56499, 0xfcb1f81c, 0x922c828f, 0x396ad293, 0xa0468cc4, + 0x49f036f6, 0x55b81234, 0x39d8041b, 0x3f91109d, 0x0a69c544, 0xf06fb844, 0x09159138, 0xf9a70789, + 0x59aa96ea, 0x17558813, 0x8e621355, 0xf202ac2c, 0xf4c8b678, 0xcb0e3be7, 0xc05ddb93, 0x25aa1ac9, + 0xe1650698, 0x508d91d8, 0xf9b5a1c0, 0xe80e0dcf, 0x96b3c7e0, 0x7a6c663f, 0x8b64c486, 0xc2049d5c, + 0x1aef4c15, 0x40d8560e, 0x35721742, 0x7211b9a8, 0xfb1729df, 0x3a9ab5ae, 0xe219c03f, 0x92b09fb9, + 0xb405fb4a, 0x7b7a8c6e, 0x7b2f6be1, 0x9af4ab7b, 0x49b12a58, 0x31f85733, 0x589b5249, 0xf0cedf86, + 0x226d220f, 0x90be6ee9, 0x1ac31cc8, 0xaa628527, 0x01949066, 0x4c8654a9, 0xe9755e29, 0xd856668f, + 0x882b222a, 0xcaeb6384, 0xb1c047a4, 0xa9bbfb78, 0x7e28ff6c, 0xc0e22504, 0x88640a39, 0xaf0c46d7, + 0x967a8487, 0xde00cd7f, 0xb7d9379e, 0x8481fde9, 0xff6ea882, 0x32c5232e, 0x5a86c37a, 0xb8e0f696, + 0x28439463, 0xe6b78d43, 0xda72eb05, 0x236da76a, 0x975dcf66, 0x0eb888b0, 0xf8eabdc8, 0x0518a363, + 0x0373d479, 0x7112da7f, 0xa8af6d91, 0xacd8976c, 0x58a5ba74, 0xda87390b, 0x3a96d653, 0x2241e088, + 0x330f5df0, 0x9ff27b4d, 0xf036e70d, 0x17872f35, 0x77156e14, 0x17e77bd0, 0xaccaf76f, 0x27359498, + 0xbdd7c71e, 0xa437c14f, 0x45d7f979, 0x218cd6d5, 0x68bce281, 0xb183a7a6, 0xd5d687ad, 0x30859edd, + 0x7d6d4083, 0xb067605f, 0x2e23ef7f, 0xd23c5479, 0x111e5c08, 0x7bb2912c, 0x930b8a74, 0x3b94186d, + 0xbf7b3612, 0x3a5a8380, 0xcbd8099a, 0xdd4c9745, 0xe7363822, 0x964075dc, 0x6b452a73, 0x0c9e2a30, + 0x0a4a93a0, 0x5a83cc6a, 0x94ac5c30, 0x0977e4fb, 0x43552cc5, 0x0fc73d1a, 0x76e3b8be, 0xe2ae96bf, + 0x3ff3bc1f, 0xdd2e849e, 0x724a0776, 0x6569f0dc, 0xd914127a, 0x75289927, 0x14d7bbed, 0x2a7f3624, + 0x12cd001d, 0x3bf85550, 0x36dc12cc, 0xa38b26be, 0xd6c1de7d, 0xbb9a017d, 0x9c2a54b4, 0xa42d7cf4, + 0x81adfd1c, 0x82e3bb4f, 0x9f3fca7b, 0x55f14501, 0x8258ae1a, 0x34bdfc68, 0xbae32498, 0x31958d06, + 0x32790d14, 0x520533a0, 0x54fcf483, 0xd238cbb7, 0xe245f05b, 0x810b8a0b, 0xd9ff83b7, 0x1078a72d, + 0xc8235e1c, 0x2534bd7f, 0xe6ff56ee, 0x298d1bc2, 0x14945c9d, 0x32398305, 0xd21924ee, 0x1447e908, + 0x26514887, 0x4d7ca5d3, 0x6640afe6, 0x058f223d, 0x7f4f1ab2, 0xa60237ab, 0x91723945, 0x1c3d8526, + 0x8c85e309, 0x77ae95c1, 0x08f3caf9, 0xd0d9bac2, 0xede86010, 0xa8a5443c, 0x92133e77, 0x81d11d84, + 0xad9a1f6d, 0xeee67d57, 0xd2c79185, 0x770a7808, 0x4bccbe5f, 0xf25f902b, 0x4a767264, 0x7b7bf7de, + 0x170d32c6, 0x3a061099, 0x505b25bf, 0x71969776, 0xb3221e63, 0x6f590d97, 0x4be433e4, 0xd4e6b009, + 0x490761ce, 0xccf4dc1b, 0x9cc810a3, 0x6b079839, 0x4eaf0e0e, 0x449f6802, 0x066e24a9, 0x2b602ced, + 0xbcf319be, 0xf387d103, 0x385b12c7, 0x309b66a6, 0x4efa8d0a, 0xc3ec907a, 0xfeb6fdeb, 0xc43b9f86, + 0xd0486e25, 0x6cc15288, 0xd14663e6, 0xe73f2c85, 0xbdb60270, 0x2c56936a, 0x39b371c9, 0x1810d902, + 0x3d5dc58d, 0xe51ec283, 0x16b61322, 0xe573b832, 0x989c7343, 0x58c73a54, 0xc24b10b1, 0x8c25561f, + 0x747d677b, 0x8bbcf594, 0x542a5c33, 0x624bff6c, 0xc02b22cf, 0x05b63746, 0xb1f0e0fa, 0x79ad3993, + 0xcb197b09, 0xf0e82ad5, 0x704e19ed, 0x18a0efb6, 0x9c451ab6, 0xb35bbe89, 0x90fad47a, 0x9bddef71, + 0x1bbd68f0, 0xe650567e, 0x24ca1523, 0x78b5040d, 0x228e45f6, 0xefc72799, 0xdb1f16e4, 0x2aa34446, + 0x6e44014f, 0x80d6a6ed, 0xd05104f6, 0x8a64bfcb, 0x0ed84b4f, 0x6d47caf4, 0x99680f7d, 0x873c4a9b, + 0x96af51f2, 0x6851e1a7, 0xa3bee720, 0x2aaa33f6, 0xe555de48, 0x049be239, 0xbc079f49, 0xfb0ba815, + 0xe2fafa87, 0xeee684de, 0x66359a08, 0x15d9bd30, 0x738f0274, 0x544f5ebf, 0x33bcdc99, 0xaf90cf63, + 0x56c27bd6, 0x0dec5e1b, 0xe37faf68, 0xcbe7ac39, 0xf5eb4896, 0x8637f1fa, 0xd8f6cf73, 0x82859a3c, + 0x6920ad33, 0xa25c2362, 0xb53b7dea, 0x9ca841d7, 0x8c01e9a5, 0x6f93bb28, 0x03bfe01d, 0x6ea85d56, + 0xe2330bdb, 0x89b498af, 0x9cf12b66, 0x26d067e7, 0x5994364b, 0x8a5abc26, 0xf9000f0e, 0xca75dd82, + 0xa6367cc9, 0xbb40fd30, 0x0ff65f3c, 0x68b26a6d, 0x190d0637, 0x8f3a86d2, 0xd329f60d, 0xfc087141, + 0x150dacc5, 0x463141ad, 0x8464c6dd, 0x4edbc95d, 0xb0d8e351, 0xf92e0bf6, 0x522e70ec, 0x9bd1efdc, + 0x988e150f, 0xd559e3c8, 0xd805dc62, 0x63356e75, 0x7be85622, 0x092938f8, 0xcdb65108, 0xb03f099d, + 0x0e97d90c, 0x00f78f30, 0xc85cf110, 0xa2093557, 0x1e690ccd, 0x316c9427, 0x8c28e778, 0x38045ba7, + 0xeceb45e6, 0x03a9144d, 0x7336a54f, 0xb325cc6d, 0x5e917025, 0x0028be7d, 0xf29917d7, 0x2aa4f6e7, + 0x0bd215e1, 0x05b47b60, 0xb020ddb9, 0xaa0a383f, 0xe8f43624, 0xd8397eaa, 0xc682f049, 0x4b0af2f5, + 0x312d5bcb, 0x21767e12, 0xd905d87e, 0x3fcb72c5, 0x4dfe146f, 0xf7423090, 0xc487ea8c, 0xd6b101ef, + 0xe28aaffb, 0x72497508, 0x40189eda, 0xa1512a47, 0x968417eb, 0x8acb34f1, 0x440df880, 0xc51b091f, + 0x911906b5, 0xaa019468, 0x100a26dd, 0xac458e97, 0xc8c2dc43, 0x928448a7, 0xf973b423, 0xff9ebbfa, + 0xcbcd3fab, 0x5a0271b2, 0xf4351db9, 0x2e3b72b6, 0xaa9c02a5, 0x4248f568, 0x2ecdef80, 0x72b39655, + 0xf6b0d4bf, 0xea7ad6bb, 0x0f3c9f1d, 0x4d4ff9a1, 0xfa974aa6, 0xfdef94fb, 0x28e62fc6, 0x91ea0a7f, + 0x0f35f573, 0x02d2c8d5, 0x9f20ebd1, 0x8b71994b, 0xab5bf23d, 0x432a19ac, 0x37307613, 0x0d979bdf, + 0x858addfc, 0xfcdae698, 0xef6b5a8b, 0x9207d9cf, 0xf06ed18d, 0x7bdd9b13, 0x11641545, 0x24ca68fe, + 0x27a66c37, 0xbcd81c4e, 0x5d6d8b55, 0xf21afc8b, 0x1db3f451, 0x2388da67, 0xe31921f2, 0x6e61b70e, + 0xeb083dd3, 0x302c39e9, 0x6e16e75d, 0x63877faf, 0xb922ef24, 0xd0486973, 0x44cc4067, 0xe727ac64, + 0xc425d173, 0x55e99e41, 0x11429987, 0x87819a41, 0x179bc12d, 0xd5dc916b, 0x341eadab, 0x023e2fd6, + 0x9c34baa6, 0x53a9ad65, 0x6b80a273, 0x97d37d20, 0x58f39f97, 0x15e4e133, 0x6b239b14, 0xd3b48e46, + 0xfd61dcad, 0xa6442940, 0xa84623fb, 0xfac85e08, 0x83c6400e, 0xbdd88d4c, 0x654f3de5, 0xfea30f62, + 0xd9dd2d21, 0x074b11f6, 0x28a672fd, 0x20f5ee2c, 0xe3ae9f1e, 0x793a0399, 0x5ec757ac, 0x2f4fd194, + 0x34445755, 0x8cd5909e, 0x2806649a, 0xf6b1fc1d, 0x4d3ea7dd, 0x2a0dd699, 0x772f5bcc, 0x70256d06, + 0x80e8c29a, 0x400cd98f, 0x79dadb3f, 0x0a546373, 0x643cd67d, 0x839158e3, 0x916994e9, 0xd4ab3b94, + 0x5e4c2391, 0x84bffe9b, 0x2044e34d, 0x6589a935, 0x01bfb843, 0xa7e1470a, 0x4a331fb5, 0xbc9cef48, + 0xb83e2e91, 0x28e53908, 0x4ae50552, 0x9dacf3c6, 0x2a81f58e, 0x14f3a8c6, 0xfc85982a, 0x9df5782f, + 0xf2502b44, 0xaf1cae6f, 0x2a4f497a, 0x121eaf3a, 0x087abf33, 0xde3449f4, 0xf960beb9, 0x64dd58f3, + 0x1c6181ff, 0x628e43cf, 0xaca8ddc0, 0xa2d4212d, 0xe2bef68c, 0x48608d32, 0x4dcf27d5, 0xbdde62c2, + 0x5311c8fa, 0x9b4608a8, 0xc45c2092, 0x228cf116, 0x23826bd6, 0xc6737769, 0x03a7b013, 0xca20a4a2, + 0x5157ee5c, 0x28664184, 0x4b37bec9, 0xc8b54d15, 0xe871e9b3, 0x89cd0f17, 0x669528e2, 0x297b302b, + 0xdafb3640, 0x48651cfc, 0xe6717424, 0x1d5bdba6, 0xaae40d3d, 0xf720f51a, 0x6c8b5f0b, 0x06a2cc65, + 0x298fc1d3, 0xc90806a3, 0x4134b61b, 0x638f6bfc, 0x8c9fe20a, 0x5dece7e2, 0x3b808df2, 0x00782f4e, + 0x30f655df, 0x4e9cebe0, 0xfd055138, 0xa04a53e0, 0xdd7feff8, 0xe2e15ea7, 0x4db5eb84, 0x4929c9a2, + 0xd25ac707, 0x9369f37f, 0x54551671, 0x0dc85c04, 0x1a2cbc00, 0x9151b897, 0xc29109d8, 0x696f781a, + 0x996b0430, 0x1c6ec90e, 0xd1545ace, 0x1eb1300f, 0xdbfb9dd4, 0x76efe36a, 0x81ab02bf, 0xb465e79d, + 0x1e3d2f51, 0x40af624d, 0xf067e36e, 0x65fcc813, 0xe2f08031, 0x67c96dcc, 0xd83466f7, 0x0d9717b6, + 0x2f1c6e7b, 0x37a518dc, 0x233121e1, 0xe9b3aabb, 0xb5db78a2, 0xf63a346f, 0xf9894fc9, 0x8ec074e7, + 0x73d9c253, 0x76a557e1, 0xfe9df9b5, 0x66ba99bf, 0xb458729f, 0x3aea0de5, 0x50ed9c66, 0xdd183014, + 0x81ca5d60, 0x8b6a4cc6, 0x0b87d7fe, 0x6e38d629, 0x4afcb037, 0x6cad20fb, 0xfdb35bdd, 0xf32d8d89, + 0xe3d89d1c, 0x7d300fef, 0xdeca2cf9, 0x6adab352, 0x17fef4ba, 0xf6f4eb81, 0xd26c4c08, 0x4ff3001d, + 0x928c0e70, 0xfd0d5b5b, 0xcf8b7836, 0xd3abc02c, 0x77aa29c3, 0xdb030137, 0xca53727d, 0x21da0e96, + 0x838050a3, 0xe555679b, 0x4e6d4ca8, 0xc44be4f9, 0x59de4c55, 0x2b45ed86, 0x46658c54, 0x31f38cde, + 0x72974ec7, 0x1d263c7f, 0xf07680b9, 0x1987b3ab, 0xa23a4c3f, 0xec3e2e62, 0x1e0d3a13, 0xe6db602f, + 0x65468c95, 0x7daeb998, 0x7009a879, 0x8ab42a63, 0xcec549cb, 0x527b2186, 0x72e48e1a, 0xa768c296, + 0x0f2e6e82, 0x0979e426, 0xd527f908, 0x36908c21, 0xc6c5b70d, 0x3f4aa25d, 0xe9ef8cda, 0x8bf5bf0b, + 0x0e6a6d9a, 0x046ea6dc, 0x5289c7fb, 0x04fc0ebc, 0x7bd1bd29, 0xdf702e07, 0xdec76f69, 0x5cee66c2, + 0x1b61b6c6, 0x84c180bf, 0x09645444, 0xea327c0a, 0x1294006e, 0x4e0a7066, 0x9b52c068, 0x8f8a9be5, + 0x5adcf221, 0x76f766ab, 0x7357f9e5, 0xc22155f1, 0x41aa1fa7, 0x21407383, 0x5e07fe19, 0xd53f38a5, + 0x01942a80, 0x8c6be40b, 0xe3ffb226, 0x9ee7f137, 0x48d22d86, 0x6b6a805a, 0x4df04c07, 0x00c744e9, + 0x73768a76, 0x13ee523e, 0xef1c77ea, 0xc5ba2546, 0xf87692e0, 0x3978fa6a, 0x56d43786, 0xe84feaf5, + 0xceb1174e, 0xc165b641, 0x9640454b, 0xc8f37c37, 0x81285b20, 0xdf64c22c, 0xe2dce298, 0x1b00a0ee, + 0x570450b1, 0xaf094542, 0x6abc02db, 0x3c4e744a, 0x58244784, 0x80db979b, 0x09db4da2, 0x56d24dfa, + 0x6e5f02ca, 0x50d82ef4, 0xd5dbacd2, 0x1fe56ce6, 0x92196740, 0x864cde60, 0xeb98cbf8, 0x21d6f35d, + 0x44309468, 0xcda42bca, 0xb0f91133, 0xfd74ad4b, 0xb56349bf, 0x223c526f, 0xb6bb1c43, 0x7a8e6ca9, + 0xa7a131c2, 0xd361f559, 0x854b2320, 0x4e91d293, 0xa2a99e35, 0xfe5096f1, 0xa290af42, 0x8d519c80, + 0x52001bf6, 0x39691e95, 0x30d3238b, 0x377b840c, 0x025cd5d3, 0x942a484a, 0x0b92345e, 0xf1dd7dda, + 0x1420eb81, 0x54e363af, 0x5986fb78, 0x09d6f5ee, 0x73b13ffc, 0x4e316657, 0xf7eb9e74, 0xe6b8b482, + 0x904c4367, 0x208de143, 0x3ef306fa, 0x7f33d618, 0x9a88a52b, 0xdc618ce3, 0xf3d8a2ef, 0x0639aac6, + 0xfa96499e, 0x4ea8636b, 0x0e86900f, 0x2b97fcf3, 0x9a23a4de, 0xfa345fa7, 0xdd8bdd03, 0x8b87e771, + 0xeef552ef, 0xa4f54da3, 0xf22212f9, 0x9b355a94, 0x3c921f02, 0x4cf951d6, 0x24ae9835, 0xa52c92e2, + 0x0b6cb974, 0x797c61ff, 0x82bee7fc, 0x7d80154a, 0x6c3885ad, 0x8cee8aa6, 0xbf78a234, 0x894b06d2, + 0x3f00d454, 0x42436039, 0xc946d146, 0x9f7e1ba3, 0xb5c9169e, 0x58ec3e68, 0x2801489e, 0xb1bd3078, + 0x33127fde, 0x65628c55, 0x3ecf3c5c, 0xb12fc0e0, 0xca27d6d8, 0xd28fbb9d, 0x175e5eae, 0xe8f5cdc0, + 0x600f4b28, 0xdf0ec6e8, 0x5e2b9562, 0x468bcb1e, 0xdf21d287, 0xfe2b34fb, 0x1a125902, 0x911241f7, + 0x1634c50a, 0x113cc81c, 0xba5a5acc, 0xda980e1c, 0x1f987a06, 0x5e70b7b3, 0x46689ded, 0x234f871a, + 0x9e0c4842, 0xb0f54124, 0x48b074b2, 0xb4a5a112, 0xc463243e, 0x05b75c7c, 0x08993f78, 0x4fb24bdd, + 0x7229e3f8, 0x157aee62, 0xbca2e941, 0x951b2b7e, 0x80599df1, 0x852734b6, 0xa8ede591, 0x35c8d635, + 0xd1c09aa2, 0x94bd5185, 0xcb642545, 0xeb18c020, 0x6d434f74, 0x5fb25419, 0xfbc93364, 0xc41ae40a, + 0x9a4c715f, 0xb8a79d11, 0xfd5f9a2a, 0x7fe34d37, 0xf6352ded, 0x2fb9d5bd, 0xb1d84aad, 0xd27eef95, + 0xcddc7c6f, 0xfb2e69b1, 0xe6437d84, 0xb2252a8d, 0x9ce36f74, 0xea14468d, 0xf5d9cdbf, 0x6e9de8fb, + 0xda0030bc, 0xe533fe28, 0xce45daa5, 0x339a65b1, 0x74e719b9, 0x82bf055b, 0x44a97716, 0xf6751964, + 0x3764f2fe, 0x096509d4, 0xb0cefaf7, 0xdeb7b720, 0xc5a2aef0, 0xe9d63b80, 0x3c2444c4, 0xa6a3a1c9, + 0xf4f176c7, 0xee254cb1, 0x62584972, 0x0e65f320, 0x6f4df051, 0x34d811ca, 0xe1b55d3d, 0x1369978b, + 0xedda2794, 0x12d68f88, 0x30f01b94, 0x8218e3c8, 0x89312965, 0x52db63b9, 0xb6bd84d4, 0x595a5499, + 0x74740da6, 0x2e5d00aa, 0xaa55b656, 0x705c71e2, 0xa952e8a9, 0x54a96501, 0xfb67294e, 0xff9ca978, + 0x892a3819, 0xad3b8880, 0x34c57254, 0x8c160027, 0x92aace4b, 0x1a92b1f7, 0x3747c9c2, 0x9a2d4044, + 0xa0d3f2d9, 0x87fe7742, 0x25a0b76d, 0x0be8e03e, 0x14ef7d6c, 0x45bed9e9, 0x57675006, 0xf3154e13, + 0x410ea73e, 0xb5a25905, 0x9800a259, 0x4465abed, 0xc72a9de6, 0x3ffb59e2, 0xf52888df, 0x98e228c0, + 0xdbb89db5, 0xeb81ad64, 0xbad8b3b1, 0x1e353afd, 0x02500ee0, 0x902f07c5, 0x1e32572a, 0x6adf467d, + 0xb72757cd, 0x36a751b2, 0xd170fb65, 0xdfbc27f1, 0xba20a7e2, 0x33d81931, 0x96ad1c5d, 0xd6c465ac, + 0xe651456c, 0xbd104078, 0xc728c4b7, 0x922b9813, 0x69ab6645, 0x007357b5, 0x7a1d3c31, 0xc017639c, + 0x5253de24, 0x36ab62a5, 0xeb52b65f, 0x6df87f6b, 0xa0460ff5, 0xad5ab686, 0x2dbf6024, 0x8828941a, + 0xb7d684f3, 0xe2bcfb4c, 0xf653f310, 0x7dce1bba, 0xde596e10, 0xb59dfcc7, 0x857f4a1a, 0x2c34a08b, + 0x574e6f46, 0xd6465a1f, 0x33198b55, 0x79b1a052, 0x1aa737cf, 0x032a5cce, 0x491258ee, 0x585bb166, + 0x6c747ea2, 0x2373b07d, 0x3dcd079f, 0x2c32291b, 0x2e7361cd, 0x24da7657, 0x90bd30c3, 0xfa118cac, + 0xb489a494, 0x7a9171bf, 0x02ffcca4, 0xcf61ea8a, 0xe9de5a1b, 0x968f4e8b, 0xe1a4d20a, 0xb1396c10, + 0xa6671a17, 0x86db28f0, 0x63668422, 0x6421467b, 0xec7bf608, 0x422e02d6, 0x6fd1b9ec, 0x724e3c6b, + 0xb292b18e, 0x8f5f12f6, 0xd6119835, 0xf153e548, 0x28619442, 0xd5138799, 0x57b40d3d, 0x79377661, + 0xc05432a4, 0x2ac497ea, 0x45106b71, 0xc05beae4, 0x02f964bf, 0xf3da674b, 0x47a92d38, 0x417ba24d, + 0x0d80c874, 0xc2ffef51, 0x41cc9a2f, 0x49cd2006, 0x451c078f, 0xc00d31c6, 0x1b2c5e3d, 0xceb0f13c, + 0xbebfc1a8, 0x5d9e9f5a, 0xf9c604e1, 0x75218d17, 0x18399e52, 0xb426b70c, 0xada5296d, 0x53f6f649, + 0xaef23201, 0xb2cf1458, 0xf671d4bb, 0x860a4077, 0x55628175, 0x7b1b9eec, 0x3b47624e, 0x040c5b97, + 0x6202c7dc, 0x51e52aaf, 0x55e5ef68, 0xf5a926b9, 0x29e6fe84, 0x3ee92719, 0xd7ae3743, 0x983f6cc0, + 0x92ecbef6, 0x67f593f0, 0xd066b718, 0x78ebe494, 0x2c815525, 0x46152ac1, 0x386aa6c7, 0x24c0e893, + 0x2665b356, 0x24b8e1d9, 0xd8521cb1, 0xa6be351a, 0xdaae2015, 0xdcdedafb, 0x54d09f33, 0x6552acd9, + 0xbbd5c45b, 0x5c3b169e, 0xb34ef7e9, 0x80d95b52, 0xdf654c7d, 0x2b3c2e4f, 0x753b175f, 0xa51fabe9, + 0x29c9daa2, 0xa95775a7, 0x41b4f636, 0x36f4c1ee, 0xbd57f7f6, 0x6bbcec6c, 0xa849fbe1, 0x5b6594b7, + 0xe421899b, 0x6a8569e8, 0x6dc1dff4, 0xfec54c4c, 0xd3949196, 0x2731943f, 0x55cef6f7, 0x7489175b, + 0x59818dc0, 0xe87c3e28, 0x60c80628, 0xbfd527a4, 0x345edd27, 0xdea598cf, 0x861e4ae3, 0xfde4f2f0, + 0xca0b0105, 0x584cada7, 0xf650b930, 0xc5697c74, 0xec76c7f3, 0xb3b9da55, 0x3acf8083, 0x44cccd25, + 0x61505f22, 0xe57808a9, 0x92a150ab, 0x5a0eaf16, 0x8714fdac, 0x1cf6d98c, 0x76215c33, 0x0203f76a, + 0x27ace2e0, 0x8555242f, 0x81e54fdc, 0xca3ddf66, 0xf4f6780c, 0xc464ea6a, 0xf2eafd72, 0x0dc619cd, + 0x59a2a719, 0x28a7f3de, 0x7c6730d2, 0x54514d0a, 0x2b87b911, 0xf2b8cd10, 0x5724452d, 0xccad1d0c, + 0xbd962636, 0x4054deec, 0x6bf99c33, 0xf41226ce, 0xdf725d18, 0xd1971a3a, 0xf3d866f0, 0x48d40f89, + 0x295a1317, 0x761ac669, 0x12f4dd90, 0x90c883b1, 0x90c1cedf, 0x8c65f2c8, 0xb741215b, 0x61d35a7f, + 0x38464e84, 0x56aaacc4, 0xbfdca521, 0x50ebd291, 0xd23475c6, 0x3d1640d0, 0xd6e08d1d, 0x547563f6, + 0xd2aab39c, 0xe48b6d2e, 0x4f7efc29, 0x157dcc2e, 0x5c68842b, 0x36437b52, 0x73737c05, 0x767b9d13, + 0xfbb28271, 0xd7b360e9, 0x00c212c2, 0xf5345b8e, 0x50cde457, 0x25810759, 0xab0e4e19, 0x56ace709, + 0x3d6f2ac1, 0xc0718694, 0x391475b0, 0xc3b6418c, 0x2ca0a85c, 0x64efa829, 0x21ff1c97, 0xa60fc14f, + 0xa0ce9151, 0xa9ac69ea, 0x8dfcd029, 0x78c6ed06, 0x92cd356e, 0xfb538afd, 0x80ef6562, 0x66bb9ed3, + 0x84f69f71, 0xe4ac74bc, 0x06aad1f8, 0x05c6984a, 0xfd72865d, 0x9330f37e, 0xc138c9ec, 0xca8ed7ca, + 0x3aa1267e, 0x704dd681, 0xe888a960, 0xd11a84a5, 0x8b8eb76b, 0x699c161b, 0x38dfb37b, 0x36cf18be, + 0x23518279, 0xb3f29001, 0x87245abd, 0xe74386f5, 0x4211a907, 0x3ae4dc79, 0xdcfc4888, 0x80c9737c, + 0xb6ba4ac2, 0xf50ed166, 0xf136c1ef, 0x35d5c7aa, 0x20f1dc17, 0xa07f803f, 0x148d16db, 0xb865767b, + 0x74f6abe7, 0xdb32d2c8, 0x486ccc5a, 0xa03bdb69, 0x1aaaa646, 0x2fb5d782, 0x43f28d0c, 0x4386e60f, + 0x80128d7b, 0x91ce7eb2, 0x38827431, 0x39b71694, 0x9c4c73d4, 0xfea1ae91, 0xb8e39325, 0x0ae4c708, + 0x0570534c, 0x16933617, 0x3a88e9a1, 0xe98a6fcd, 0x86f42f18, 0x7df36f98, 0xdff23f0a, 0xbb53a008, + 0xbfacb5fc, 0x28ae8578, 0x717ffbd1, 0x03e14e75, 0x76799649, 0x4ec5b25c, 0xa3ef1104, 0xf304a0a3, + 0xc4aa13d2, 0xb8dee790, 0xbf0db44f, 0x365a632d, 0x5b5829fb, 0x002a88d1, 0x9cdd3786, 0x5ab8846a, + 0xf88d1b5b, 0x77fa5599, 0x2283d6b2, 0x7cbf9268, 0x8a3bbab7, 0xcbf6c569, 0xef07aacc, 0x69cd6dce, + 0x88ed6e19, 0x36501df0, 0x9ab468c0, 0xf6a7d038, 0xcdcd02df, 0x180c7c3a, 0x44178a3c, 0x0810c164, + 0x7d206449, 0x9b34a56d, 0x9aaf65b9, 0x4b674e05, 0xe90f11eb, 0xdeccc267, 0x9befea71, 0xe2533dbd, + 0xac814021, 0xdf427c26, 0x2f8b31a1, 0xe3af1609, 0x5618aec2, 0x717b8ff5, 0xa0ca4903, 0xdd029f14, + 0xaf3f744e, 0x09607bd4, 0x25b1baa8, 0xdcf5171a, 0xbaa93d9f, 0x23caa958, 0x1e177e4d, 0x7700636c, + 0x2038d092, 0x96fceeb2, 0xa1efb4c1, 0x124a81d9, 0xb4a9b9e1, 0x0ea666c2, 0x7347a529, 0xdd50d2f4, + 0xba8c8665, 0x36aeb1b9, 0x1213fc37, 0xf56b3847, 0x5a3381b1, 0xd6de2958, 0x738bc644, 0xee384175, + 0xd8a56e8b, 0x22f8372d, 0x77354c08, 0xebb52cc7, 0xc60d884d, 0xe718afcf, 0xdadb37d0, 0xb83ac6ca, + 0x99b06574, 0xb52c4821, 0xb622743a, 0x1ce9f21e, 0x43f6e680, 0x5dbb34ba, 0xe384491a, 0xb13605b6, + 0x13c467f6, 0xbe11b7a8, 0x5763cf31, 0xf03e85ab, 0xd0440282, 0xf97f5fda, 0x46a5dc82, 0x8a765a8f, + 0x18f655f6, 0x87273113, 0x48c5aa3c, 0x68e0e1b5, 0xd73eb9c0, 0xef03c74e, 0x6b469104, 0xf80fe4a2, + 0x63e0881e, 0x2f359c75, 0xaa6b9416, 0x2bd4cf1f, 0xb5956c79, 0xa46e965d, 0x49aa12ba, 0xad7b0e3d, + 0x371ce674, 0x913791e9, 0xa0b55434, 0xb0dd3ea3, 0x13a905fd, 0x4fccd4ae, 0x2b1a9e1d, 0xdb855485, + 0xaed6b354, 0x0e6afbd2, 0x54e57470, 0x3124dd45, 0x3a45cd68, 0x41c0e048, 0xb3449481, 0x8dfbbf1e, + 0xdddb5676, 0x2cbb19fb, 0xd03ac1c4, 0x4ee8130f, 0x749c89a2, 0x8358d0f8, 0xec469f5e, 0x397c6fa6, + 0x625c8a41, 0x4a0ab8e7, 0xd2d2dc57, 0xf3aa653a, 0x38b5f560, 0x69e77d78, 0x993d41d3, 0x9a0709ba, + 0x76c850d4, 0xac400444, 0x4bf08ae4, 0xd327df53, 0x7425c9aa, 0x3b48d52f, 0x68572554, 0x2c08b38d, + 0x321bef1a, 0x77e8c9c8, 0xcbc1d1f4, 0x525ddcab, 0xfdee3742, 0xd4e60daa, 0x7b5efbcd, 0xb3d2889f, + 0xea20b17a, 0x9484e946, 0x622a8297, 0x4101cc3b, 0xf94ce07e, 0x9a409cb4, 0x04e5d547, 0xd0e45b47, + 0x97608d9e, 0x93727370, 0x66f36a0f, 0x23403ded, 0x4901be6d, 0xbc35a876, 0xd0fc9d2c, 0x14ac20ba, + 0xd9965114, 0x3b2a3e35, 0x9fd2431d, 0x73527869, 0xea2125ae, 0x9d84f155, 0x9462b814, 0x35edbe9e, + 0xaf54852a, 0xa1257922, 0xf5a51637, 0x13e2cbba, 0x7af2ed47, 0xd51751ac, 0xe51209d7, 0x55035e84, + 0x58947560, 0x3e4c1b12, 0x7f116883, 0xd8de7878, 0xfb6e37fe, 0x6634958a, 0xebb2d810, 0xc15c9b0c, + 0x3ba5f27e, 0xc144dd00, 0x493db62e, 0xcfd335a1, 0x308e308d, 0x5a7e9492, 0xcc4f25f1, 0xe3e3800a, + 0xf5424aed, 0x82218a6a, 0x6fabc824, 0x76a678c3, 0x12ce7592, 0x8026e96c, 0x3da576ee, 0xb9a2006c, + 0x4a179a80, 0x02664a50, 0xf9e239da, 0x1e383d0d, 0xcb25b5a3, 0xb74d5f78, 0x99a5fa16, 0xd8f854ff, + 0x393ac493, 0x127cbb82, 0xc7a7f276, 0x23625063, 0x1842013c, 0x3335013f, 0x39ebc960, 0x715947ee, + 0x5f9b04da, 0xb26ac9d8, 0x16b3774a, 0x0004f006, 0x4023c7b5, 0x39c9d77c, 0xce11a56b, 0x91775268, + 0x4e93e670, 0x8029631b, 0x83b8fd8b, 0xf0c5c784, 0x16421d3e, 0x6c992895, 0x499339a4, 0x20758295, + 0x211ac1a1, 0x4226ca1d, 0x4acf62c9, 0x737f760e, 0xa7e53bd0, 0xfe09a787, 0xe00a033c, 0x052175e5, + 0xef1196fb, 0x33a599af, 0x6aa21e3c, 0xd52436db, 0x7a2f0a6d, 0x592631f2, 0x7a45ff6d, 0x7c64c0b4, + 0xa4a742d5, 0xf0ffad2d, 0x2b9ecc49, 0xf5e826bd, 0x73b979a7, 0x8d895d2f, 0x2ff0e6bf, 0x02d8093c, + 0xa58410d8, 0xf3ab1631, 0x6fcdc5a1, 0x2431ccdd, 0x3b350b8c, 0x67e5fb01, 0x086afbd5, 0xe59b6199, + 0x1bdb79e9, 0x21e9801c, 0xfb7e55d3, 0x941a44b8, 0xec8a71a7, 0xc1aca3e4, 0x3dbdcf16, 0x8d66f223, + 0x585ef52f, 0x4b3dd8a5, 0x04ed2d15, 0x071c882b, 0x33c64db5, 0xa146f198, 0x322a23c6, 0x637b7d4d, + 0xd25b7fc0, 0x393b1793, 0x282fd176, 0xfdc7e9af, 0x58cf3987, 0x943864de, 0x2b18c40c, 0x3223b897, + 0xa6786035, 0xe24600ee, 0x927f3c15, 0x2e444077, 0xcbc15f6b, 0x203da4d1, 0xde1a1c2d, 0xba22950f, + 0xac974e88, 0xca225d3e, 0x4dbe3eeb, 0x540e1b0f, 0x31222d6a, 0x2c506ffd, 0x2497b1c3, 0xede63afe, + 0x2a630765, 0xf39b4813, 0x1c13cf57, 0xe94dbe87, 0xad0033f6, 0xf7ca58dc, 0x67dd5a8e, 0x9b0e8153, + 0xad5a8256, 0x7bea3a95, 0x8da7785e, 0xb20ad7f8, 0x18cf4d56, 0xd3836230, 0xf0a165fc, 0x6d8b5fc9, + 0xd2d7c12c, 0xbbd232cc, 0x07ab639f, 0x54781e8e, 0x4c06da76, 0x432a4607, 0x0e513502, 0x1fa73f36, + 0xb89e2790, 0x59e80aad, 0x1d3e0155, 0x49d7b913, 0xdf37e01b, 0xd8fb9e6c, 0xf2e9d759, 0xcf6980fc, + 0x11b44b5e, 0xc664d391, 0xd905a855, 0x4a9341c0, 0xa95b226c, 0x004fce7f, 0x89fcb6d4, 0xd2eb8b18, + 0xd451be9a, 0x3d190a08, 0x032d5dc1, 0xe7c61ffa, 0x34792afd, 0xf3d1fd9b, 0x8ac4b2d3, 0xc93eeded, + 0x579c43b5, 0x33d6cb45, 0x49846eff, 0x62684f5f, 0x39b9dfdb, 0xbe7980db, 0x5ff4d5a4, 0x5c4d6765, + 0xdcbea8cf, 0xaa3368a7, 0xf0b5e6e2, 0x481c2a46, 0xf0284212, 0xdbb4e942, 0x43c80e44, 0x3909dfbb, + 0x7b91fdd3, 0xac09aa50, 0xf87ac30c, 0x7ebf9c6e, 0x716db044, 0x8723dfc0, 0x2de10b9c, 0x77a57acb, + 0x9dd3fe23, 0x4e018264, 0xcc9a5771, 0x1257f58c, 0x40c77a0f, 0xc13c21af, 0x07087805, 0x6825fb66, + 0x417c204a, 0x345a1402, 0x687560a3, 0x89aaf1ea, 0xf56b2232, 0xc81d8b8e, 0x6240c4af, 0x835a6785, + 0x168f3b22, 0xa9a3a6bd, 0x65881ec9, 0xa70c4833, 0xff00bdbb, 0x846a20be, 0xcb306f3d, 0xbbe15da0, + 0x4fb5f424, 0xa8492500, 0x0c325432, 0x84c7e130, 0x0fb690ff, 0x19be9e31, 0xc2940bcf, 0x831f2e55, + 0x17d3d7ed, 0xcde41e0f, 0xf2d2e272, 0x0e47256f, 0x245c1f42, 0x35857bcd, 0x322a6381, 0x8a01b6e7, + 0xe68979ec, 0x4ced46e2, 0x025ebd41, 0x1fcadb11, 0x2bdfb357, 0xe41162f6, 0xf7ee42b7, 0xf92ce3c8, + 0x8c2c5123, 0x37711b73, 0x2f32d7de, 0x288d5f47, 0x351cc98b, 0x2139043b, 0xe8026c17, 0x6c558f0a, + 0xd5adcec1, 0xae37b604, 0x5854096d, 0xa5ad1c0d, 0xb5059af0, 0xadaf7efa, 0x5087e991, 0x1932d9fe, + 0x4a6fe3c4, 0xbcf329d7, 0x994789c2, 0x13b5955a, 0x9ea82b18, 0xc35e82c9, 0x20b50f11, 0x2b702ac4, + 0x6e397bdf, 0xc6f8bfc8, 0x845e1980, 0xaaf8e2e6, 0xcc62c26c, 0xe75874c1, 0x9b6234ac, 0xcb9030e4, + 0x3c9e8685, 0x3090beec, 0x77029fad, 0xfef325ca, 0x420c0abc, 0xdc428599, 0xc784cfbd, 0x1e884dad, + 0x1363c3c7, 0x5e758322, 0x842d36a1, 0x5da13df3, 0x4c4098f6, 0x475ff5aa, 0x71e0fc4d, 0x4ebc04ed, + 0x20e695dc, 0x6f4f9637, 0x41f4f796, 0x5c47d771, 0xb4e22701, 0x214d3f38, 0x5b7f40da, 0x6fc13afe, + 0x6210f11f, 0x8bc0240c, 0x269ce26d, 0xd4db3dbd, 0xb98dacfb, 0x72f30aab, 0x4bf1d5aa, 0xd721bd90, + 0xcfda4bc9, 0x07a094d7, 0x0f969d6d, 0x390bc5d3, 0xe32cfe00, 0xa6364364, 0x2271f7a6, 0x5351c80c, + 0x7d15fe5c, 0xd5b96905, 0x56a8710c, 0x73a75cd0, 0x1fa393d8, 0x87692687, 0x423d1d10, 0x285ff7cc, + 0x5d403e8e, 0x1637429c, 0x7fd383d9, 0xf634ebd4, 0xc5151b16, 0x1bcce3d8, 0x2c86f309, 0x83e84da9, + 0x12a16998, 0x0fa9e07f, 0xa35bba36, 0xe486d32e, 0x09ed92ea, 0x0d3784d3, 0xeae918b1, 0xb3e3926c, + 0xa19466a7, 0xf9488529, 0xf5d56885, 0x7aee756e, 0x8c2270be, 0xf987e9e7, 0x963619e1, 0x5bc1ef8c, + 0x0fe5e63b, 0x8a0241d8, 0xea988e9d, 0x4b9e2dd6, 0xfc16d320, 0xf155cbdb, 0x82db0a0d, 0x6159996b, + 0xb860562a, 0x6f7451dd, 0xf84e870c, 0x5ac761f5, 0x9cec2e9e, 0x8731b1f2, 0x3b02155f, 0x5b4683c8, + 0x1d25d060, 0x0291f575, 0x5b89721e, 0xa6171a97, 0x99b79fb5, 0x158e62ec, 0xe91ddc82, 0xc3a0ff2f, + 0x78eca51c, 0x22bbce43, 0x53668834, 0x5e3abc56, 0xad62e4f2, 0x14fd4dea, 0x2892611d, 0x84d739eb, + 0x4fc2dc77, 0x3833ec12, 0x7dc19f23, 0xdb7d177a, 0x63dc75d2, 0x1f5dc00b, 0x1cc37933, 0x23259f2d, + 0x57f2c9a0, 0x356f5a66, 0x2bec801b, 0xa0714ec3, 0x616d9af5, 0x8b2fabf5, 0x550f74a4, 0x88106a83, + 0x6e0f3310, 0x0d25ba4d, 0x224e9125, 0x43ee1235, 0x82b898b1, 0x1a3758e6, 0x3ed65ebf, 0xbae590f9, + 0x7bcd2f07, 0x200dfdb3, 0xaf95fa84, 0xc5e6c7c6, 0xd42308bb, 0x4069d66f, 0x542a0b92, 0x1dec30d2, + 0x648cc8e6, 0xc4555298, 0x54ef7507, 0x6e087965, 0x5e26e937, 0xff133f9b, 0xb7f54e1a, 0xf648abfe, + 0x16e22090, 0xddb2acfd, 0x85161593, 0xdcaa828e, 0xa6872983, 0xa0eaac8b, 0xfa43536c, 0x3e9d23de, + 0xd3222c3b, 0x73dd549b, 0x88182c2a, 0x30f99828, 0x8d2229c5, 0x22ee5829, 0x0810978f, 0x937c22e7, + 0xddc58a3e, 0xdbe216a7, 0x873e3b3a, 0xcb52f781, 0xd24b227e, 0xf61f5569, 0xae53896e, 0x57ce4c37, + 0x50db6020, 0x0b0f3d76, 0xff1bd622, 0x66a58a93, 0x0be84535, 0xaced6bae, 0x05f6f204, 0xf0b9205e, + 0x72f6ce57, 0xfe14c0db, 0xd06fa364, 0x01865e5b, 0x0cf729aa, 0xb629915d, 0x3404b7e3, 0x2d64a223, + 0xc8a683f0, 0x2a0131a7, 0xb1cee3b8, 0xf9e97bb7, 0xb12756b4, 0x18a279a0, 0x95786462, 0x23796f77, + 0x5fd3f678, 0xc80074b8, 0x7aff27a9, 0x665c2231, 0x39900c77, 0x72f4b936, 0x5d01905d, 0x2eb8458d, + 0x4c7a1ba8, 0x014c2aea, 0xd292ed1d, 0xb7def701, 0x582e38fa, 0xe0cf6fbd, 0x5d8df750, 0x7b307ced, + 0x2542097d, 0x8a2ee709, 0x463433df, 0x5d97e8d1, 0x4c837086, 0x67c21b33, 0x048330a1, 0x478d225f, + 0xc4ab65c8, 0x37bacdfa, 0x84633fdc, 0x2e6389e9, 0x70e04ed7, 0x6bff2efe, 0xd9833841, 0x3ef1c9ea, + 0xd68f44e6, 0x5a2c8806, 0x221ff1fe, 0x4e5397b6, 0xf6504dd1, 0xeea742dc, 0xa53934c5, 0x0efe7c43, + 0xee9de8c4, 0x1c3ad782, 0xedfbf51a, 0x2f51cb65, 0x60ce6557, 0xbe0e48c5, 0x43b22971, 0x190eaae3, + 0x0a00c06f, 0x8239e923, 0x83ea308d, 0x2b40ef32, 0x8522d95c, 0xc9090d63, 0x153cfdef, 0x3ee0ab53, + 0xd65d428f, 0x16c19332, 0x1375480c, 0x8f658d20, 0x199409e4, 0x1b900e46, 0x47464903, 0x295f3fd4, + 0x87719b7c, 0x8b116c3f, 0x28051cc4, 0x7f3892ea, 0x0ee4d6dc, 0x8d7fd31b, 0x05789851, 0x26fc88f0, + 0xfabb6ab9, 0xc8517d97, 0xc7726f07, 0x2d4f5728, 0x9546fcad, 0x95d5954e, 0xe45d6355, 0xcdaa0639, + 0xd939beb4, 0x8738d2dc, 0x5894c75a, 0xc30ecf79, 0x2e68d0f5, 0xbb4eb1aa, 0x77eb9da0, 0xc875da38, + 0x0e30c56a, 0xf21beeae, 0xeb47c2db, 0x0a808b03, 0x9b2ad203, 0xc1967924, 0x12aa1d54, 0x997c76e2, + 0xf15d7b92, 0xa6e9578e, 0xe2fb89b8, 0x4bfa5d12, 0x0047cc70, 0xc2837c20, 0x0f3f1dc1, 0xd89333de, + 0x09cd9893, 0x42712c59, 0xcbc83660, 0xb2b15c89, 0x613ea354, 0x4f19c10d, 0x4589d74a, 0x5380aa3a, + 0x0f5fe939, 0x3371f78e, 0x22e1b57c, 0x6a404080, 0x53020f77, 0xdb8a4897, 0x49b42596, 0x4ea01f60, + 0x47485774, 0xad2deb16, 0xb9699b51, 0xa5384da6, 0x1bb8b1f5, 0x1d9aab3a, 0x4df1ff7f, 0xba14cd5a, + 0x116ce1dd, 0x40419453, 0x19500413, 0x35b65d7a, 0x27e15733, 0x69a7bd65, 0x948578f8, 0x16599105, + 0x83ff46ba, 0xdabdccfc, 0x7cd55140, 0xef975476, 0x7d30b173, 0x34d4960d, 0xa9f206c4, 0x3c1b768b, + 0x6532ef5a, 0xf39b27d3, 0xf3efc75b, 0x11c58f62, 0xc56c3abc, 0xcb09c72b, 0x3c5df376, 0xfe498367, + 0x9bca67d4, 0x587a1032, 0x7c698805, 0x9ba085a8, 0xbd3a584b, 0x898ff4da, 0xb65ce9bf, 0x9fdcd942, + 0x7ac97394, 0x74907bb9, 0x249c114b, 0xdb138d20, 0xe1ade5dd, 0x08b5cf73, 0x4a65e5a7, 0x14960abd, + 0x88e4d1b1, 0x6a423485, 0x0c83da21, 0x3a800d73, 0x30c545da, 0x87593395, 0x6c314d92, 0xf4a7d163, + 0x3748a701, 0x8177b5d1, 0x84114242, 0xde17179f, 0x9dfe5c90, 0x9480fb84, 0xc0daa973, 0xb6a94d66, + 0x9fc14717, 0x1ab62c4e, 0xe82e3d0d, 0x250f4bc0, 0x295ddbd4, 0xee61473b, 0x82bff14a, 0x024820bc, + 0x237e9608, 0x29de615c, 0x89eaf308, 0xdbd3a327, 0x31d5bfe5, 0x6410c0b1, 0xf342ae51, 0xff73d94c, + 0xad50af63, 0xd99ebd33, 0x5a018593, 0xb488fe9c, 0x8c34d437, 0x3beab554, 0x0bdfdd05, 0xb7b4b5c0, + 0x10242ea6, 0xe09dd531, 0x429b5975, 0xf28d35b7, 0x0ade0bfd, 0xca6354e3, 0x23aedb6c, 0x9f22f6ee, + 0xa3fe7e9a, 0x4d123675, 0x7822c735, 0x611927ed, 0xdcdfe7f9, 0x5de49062, 0xbd2bf1a0, 0x09e189d6, + 0xce6a6d02, 0x5bdfdf2d, 0x0d5eb28b, 0xcd83aa65, 0x2432b483, 0x2a5e6db1, 0x1d95ef47, 0xb252438b, + 0x4b578890, 0xffd851d4, 0xe93909e3, 0x59e02f00, 0x54eed132, 0xd31fd8bc, 0x2cc1253e, 0x661896da, + 0xa7f94b31, 0x67dc0bb6, 0x26d5022c, 0x39703d52, 0x2caca28c, 0xa762e9c8, 0x1308fbd2, 0x8e2c43f6, + 0x1e47bbac, 0x337045db, 0x2e4889a4, 0x4a859b86, 0x22208929, 0x42b7de4b, 0xe22c9e3f, 0xf1251adc, + 0xa067d13b, 0xa94a78ee, 0x158363cf, 0xda62db89, 0xed1445d5, 0x449ab208, 0x771a2680, 0xd510f4fd, + 0x16dedfa1, 0xcd3daffd, 0x033875cc, 0x2fe57623, 0x13e1fda1, 0x66a5091a, 0x61731bcb, 0x6bdd4aea, + 0xc1544c1b, 0xb4d05767, 0x0e93925a, 0x6bac3c33, 0xf0277907, 0x63252e49, 0x2fd6dcb3, 0x611e34c3, + 0xa622ee7c, 0x84cd24c0, 0x28a218fb, 0xfce2d49a, 0x158bf2b9, 0xf2e17677, 0xb3601cac, 0x9bab54c5, + 0x031d5ee0, 0xc0426f76, 0x98f50f6e, 0xbae2660c, 0x31fee362, 0x13b2a2a8, 0xd48c31c6, 0x97befb1c, + 0xbb3d0b91, 0x16d39d36, 0xae5ab3f2, 0x4286ad35, 0xec3228be, 0xac4ac6ad, 0x0d9e6812, 0x74f0e0d1, + 0xc4cf638d, 0xa3e21817, 0x16bb2c6f, 0xde409196, 0x03464fd9, 0x0ca21586, 0xae153871, 0x0189aee9, + 0x82f079ba, 0xfdeebdcf, 0xa4014973, 0xca3b1e51, 0x520ec159, 0xd4fe7ab4, 0xf93c156e, 0x6751ff6d, + 0x100d8cd1, 0x2aa9ff13, 0x0a336ac3, 0x14d5e5df, 0x35f4b5a0, 0xe68451a0, 0xaf8be68f, 0x353c5be9, + 0x3f8189ef, 0x638d5301, 0x3207785d, 0x80c8d545, 0xc837e4d9, 0xc46f08b9, 0x5ad74af8, 0x9c85c09b, + 0x63500d08, 0xbe62ef46, 0xbe106669, 0x82d75e61, 0xa0a3fffb, 0x8be3675d, 0x713f8b59, 0x20a7e8ed, + 0xcd1f7162, 0x461c3592, 0xa0c9e1ef, 0x824d0a58, 0xd0c3b2fa, 0xeee82959, 0xbc6769af, 0x02c68f3d, + 0x0540b337, 0x143483e9, 0xbba449af, 0x00f4d161, 0x6f5e108c, 0xdc842a97, 0xe6ae5581, 0x9ff8cbf1, + 0x3fbc6daa, 0x1b33fb52, 0x93375c44, 0x989df9b7, 0xc8f80241, 0xbf8915bd, 0x46c4cb5b, 0x95a33af6, + 0xee68d786, 0xf7e3d33d, 0xade32492, 0x56220956, 0x5d62551c, 0xee60f791, 0x45dd8afe, 0x995df4a1, + 0x85461629, 0xbefd6911, 0x3e75bf68, 0x07e42489, 0xa5e8f48d, 0x243ffc33, 0x748ce810, 0x83832d0a, + 0x3c58e864, 0x791da38e, 0x74d234c3, 0xd819e2c6, 0xd3f4da52, 0x28a7c286, 0x9bf8be61, 0x60344118, + 0xc80338b2, 0xef3d6d3e, 0xa821e55a, 0xa7f833e7, 0x3111446c, 0x1b55213c, 0x0b54d245, 0xff5afa1a, + 0xe3cdfbdc, 0xb0c58c7c, 0xbd9326a1, 0xe815c0ac, 0x56612985, 0x1cf15f28, 0xfc5415a3, 0x931e8f09, + 0x800ef476, 0xe107fc23, 0x77bdd628, 0x1628cf74, 0xd64ae0be, 0x64ac44ff, 0x0a34ab9d, 0xb7efcae7, + 0x56b9d4fb, 0xbfe859f0, 0x2a44f6b3, 0x0742f328, 0x85f0c086, 0x7787abf5, 0x6ee9bb61, 0xbe667050, + 0xb71f868d, 0x4ab8f773, 0x5272b56e, 0x7d4dbe59, 0xd37968aa, 0x2c1845f6, 0xf2c461ec, 0x8afcb48c, + 0x2e0f1caf, 0x4a192e83, 0xb1cdfa9e, 0xf9e7095c, 0x30137027, 0xd42f1a1c, 0x40aaa7aa, 0xf57f7748, + 0xcd6dbddb, 0x85608ab3, 0x97773701, 0x8356cfb6, 0x46e20bef, 0xf422d319, 0xc5c45cfb, 0xf90db52b, + 0xbfd8ea8f, 0x2402a0ed, 0xe48d725d, 0xd6073b27, 0x4e85760d, 0xaff489b2, 0x70dc2eee, 0x44460819, + 0x84bf9f54, 0x7d10e536, 0xd9683c4a, 0x46a2bd42, 0x434bafcc, 0x1a5401e7, 0xa7acd2ad, 0x8ad1f70e, + 0x1e1edc8a, 0xf0ec3d6c, 0x52c11ca4, 0x53f03c4c, 0x341ef98b, 0x6c233fc8, 0x8ede8323, 0x8ea407ac, + 0x6f10090c, 0x491c2648, 0xca00d2ba, 0x652b9086, 0x43de86ca, 0x835b4a10, 0xd24b3fac, 0xaba49a65, + 0xfd74828e, 0x840f055b, 0x0acc649d, 0x8df4de94, 0xf9b68aaa, 0x8a5ef065, 0x3bb847a5, 0x111ad1e7, + 0x42277724, 0x8db0e3b2, 0x05b5abd9, 0xfeeada4e, 0x68dae96c, 0xfaae3509, 0x80811c53, 0xe292d0d7, + 0xce58e349, 0xa1c4ecee, 0xf5cc6d91, 0x5e16e551, 0x54f87a5a, 0x61b8efd9, 0x7eb6f357, 0x8469bb1b, + 0xb1cfc70e, 0x51afa53c, 0x002b7a2b, 0xd2d47197, 0x9d88daff, 0xc3fd0011, 0x6574fd51, 0xcd0c8f8e, + 0xa0fbc356, 0x0b910dad, 0x2e3fba7e, 0xb25a94e0, 0xdf26993a, 0x39e7c2a1, 0x74dd0348, 0x3ce2c199, + 0xa4e64374, 0xd3fded52, 0x81344859, 0xfff63e09, 0x44f70461, 0xafc0b071, 0x80240630, 0x364f7ede, + 0x08a2f2f3, 0xf2155b36, 0x24a3ae84, 0xad9fe7c8, 0x1f0db930, 0xe90a7474, 0x6ea16ca4, 0x83218439, + 0xaeceefe1, 0x191cfc41, 0xe91eb1a2, 0x6ac483ce, 0xfebb2524, 0xe7b2dc89, 0x199337da, 0xd0711b27, + 0x28e63c65, 0x6082d6d6, 0x9521effd, 0x40f721cb, 0x3872b4ca, 0x1a63fb13, 0x4c3b8f69, 0x74366f7d, + 0x86af014c, 0x897a1fc3, 0x74e3d80f, 0xbd047928, 0x9787b2d0, 0x4b9cab56, 0x9e829532, 0xabf836d9, + 0xadd76dfa, 0x5dd3e705, 0x8181a28b, 0xbde21b20, 0xaf00d52d, 0x6b8b48f1, 0x508e31c5, 0x0caf961b, + 0x2d2c17a1, 0x8b026cb9, 0x63358b80, 0x2ae1fc0d, 0xb0e88408, 0x1809d049, 0xf292a865, 0x45e27139, + 0x33bf6f1e, 0x8e7b36d8, 0x19e79e3a, 0x88204d4b, 0x579cf4e0, 0x5d0a9166, 0xd83e0175, 0xe65e7311, + 0xee567c89, 0x9f2054b3, 0xdc08d889, 0x51f247a9, 0x0bd173ad, 0x9400c3d5, 0xce338fc6, 0x2c82e885, + 0x64ee37f2, 0xfd26df0b, 0xb3fc98bf, 0x2454b0c2, 0xe383cf1a, 0x8309aaa2, 0xb4c3ad34, 0x451a6d53, + 0x9683053e, 0xcbb9765f, 0x4ca1f192, 0x3a2489ac, 0x119916e1, 0x83a48e3c, 0x91df4e34, 0x5cba46d1, + 0x7d56ae3b, 0x4d66ac64, 0x790e11ae, 0x8aecd3ef, 0x1843fe73, 0xb500925a, 0x53a9a5a3, 0x54a58440, + 0x4b955bb7, 0x12fdda20, 0x371a9078, 0x88f09921, 0x00c8491a, 0x31f6f6f2, 0xc6e6f3ec, 0x0fdc783b, + 0x80d34074, 0xba3cd811, 0x7f2c2e02, 0xa6acd92c, 0x46aa379d, 0xd32ea61f, 0xe7f1da67, 0xe8d8b0c1, + 0x1c6d4f0e, 0xfbff0b68, 0x9862d90a, 0x7538c1c7, 0x24dbdd99, 0xc97a77f7, 0x070f9951, 0xd01fbd16, + 0x8bd08ab0, 0x9a2175a6, 0x8f37d2ba, 0x734fc2df, 0x29dde138, 0x17fde4bf, 0xcf3701a3, 0x5a2ab3d0, + 0x0d0462e0, 0xc6b4e395, 0x7013b0c7, 0x33921aed, 0x40de7bfe, 0x8c4a177f, 0x5f61190e, 0xf68473b9, + 0x8fa6f778, 0x5f0ae814, 0x5d8afdce, 0x3034b623, 0x8b6d901e, 0xb8ce56fe, 0x3e8e0a34, 0x59c03203, + 0xed187c5a, 0xedacfdf7, 0x7450c726, 0xdd62dfb1, 0x165abf0a, 0x7627a917, 0xc0af1f9c, 0x2733e3e6, + 0xd991e42b, 0xcd07091e, 0x6e426be4, 0x787e6908, 0x806cc7a1, 0xf8ef6c59, 0xc994dbba, 0x0dd1c767, + 0xf8c3bb5e, 0xfac2bd69, 0x8e0650f2, 0x9c2c566d, 0xc60996b2, 0xa7c5d71d, 0xee4979f9, 0x0f0545ab, + 0x941aa1b0, 0x573b83e6, 0xc4577304, 0x37b37bc7, 0x882dff69, 0x6bc4d10c, 0x665c4e09, 0xfe1ab74f, + 0xa047c37e, 0x2d6c5828, 0xd0de995e, 0x5569ee10, 0xeca2c8b0, 0x500bfd22, 0x53c38fb0, 0xe221b415, + 0xaee81fb1, 0x75695037, 0xea88fe7f, 0xf1d03dd9, 0x0863d9e9, 0xe69cbf71, 0xb6f42f2c, 0xd41b43b5, + 0x9caedf88, 0x3b84244d, 0x99f983c8, 0x10b4c30b, 0x2fbe341d, 0x40817d0a, 0xbf0ee5cd, 0xfd1b656c, + 0x0d0b9270, 0xf8c07600, 0x4dea9de9, 0x9e1b237d, 0x86e276c9, 0xd17032b0, 0x02b50d74, 0x1bd7af4a, + 0x76f89830, 0x9baa528b, 0xf456468f, 0x039d78b0, 0x2c7e0a2d, 0x3be2edb6, 0x85859650, 0xaaa4fa12, + 0x08308b1f, 0x1fd5504a, 0x85054656, 0x6b5ddff0, 0x26062aae, 0x80f91306, 0x9b8b2d72, 0x10ba569d, + 0x3e7eca24, 0xb2ef676d, 0x41b6ac16, 0xcedceeb0, 0xcd500e7c, 0x66867eb5, 0x66986245, 0x9378255c, + 0x38c7233d, 0x4e37dd5e, 0xd43a1820, 0x12c7b1a8, 0x609095a6, 0xe55221ff, 0x8133c780, 0xb0f3410d, + 0xa0ac9cc8, 0x9c46a10f, 0xa12acd1c, 0x43ac1fec, 0x0f77b291, 0x76c5644b, 0x1e6b853e, 0xaa99343a, + 0xe6faf91f, 0x5e0d0a0d, 0xeffba7f6, 0x01d7e037, 0x80be7b31, 0x58e1fe32, 0x5757824c, 0x5be3c15c, + 0x213fe9ec, 0x292a16c4, 0x6b32d1d7, 0x246a1f4b, 0x1a4dd0b5, 0x7240aadd, 0x49f36be0, 0x9a5a009f, + 0x5045a2cd, 0x17d75a12, 0x2e6efd21, 0x6dd051a9, 0xec7afa89, 0xfb86e982, 0x3fdd1cd1, 0x18ed65af, + 0x1ae3c41b, 0xb3faec43, 0x5f9769e2, 0xd7feecd2, 0x5e5d9aba, 0x4006c140, 0x1dde61f1, 0x2163911d, + 0x9bc05a18, 0x1e894b6b, 0x752d0ca0, 0x1e52be9f, 0xfbec01a2, 0x2d7aaac3, 0xabf9affa, 0xffde13b1, + 0xc1069708, 0x6676db2a, 0xb86f08ef, 0xbe9f1344, 0x7b5923a5, 0x6f6217c2, 0xadf53d09, 0xb4c85816, + 0x69c66e6e, 0xc4eb49da, 0x9d0c60d1, 0x98bde406, 0x3451bdb3, 0x91a5f299, 0xb3168dcf, 0x35a60d8c, + 0xd1b207f3, 0xca993590, 0xa1832ba9, 0xa0c3ecdd, 0xc4116268, 0x4642dfba, 0x0b51534a, 0x67530938, + 0xd0cba26f, 0x4dcd44ed, 0x2912c713, 0x9dc2191d, 0xb0a2a2be, 0xe78570c0, 0x9351f736, 0xb60ab000, + 0xe96aeb3a, 0xcf71436b, 0x1377a13b, 0x54fb4449, 0x118fea05, 0xb2ea557a, 0x3cefe3a4, 0x419d1d98, + 0xb8393e17, 0xf79f5b53, 0x71442e6d, 0x20494929, 0xc21470f7, 0x2879b70d, 0xc6fc4d8d, 0xe5f5fe5a, + 0x2d667334, 0x689dd298, 0xd65d012f, 0xd5b38489, 0xcea58fe5, 0xa48d391e, 0x29553587, 0x5f4301f9, + 0xb8950cf8, 0xbeb1a792, 0x3183ee2c, 0xd5b874a1, 0xb009dfc3, 0x313f16ae, 0xa4314ec9, 0x8bb541d6, + 0xb3c1146f, 0x2fd41dff, 0x1f6d07b8, 0x2b5f78c8, 0xd54d921b, 0x3ac3ecad, 0x599f7a9a, 0x264e7436, + 0x510b1038, 0x8e47ee47, 0x1fb9a198, 0xf2c34a76, 0xbeca552a, 0x8866a0b5, 0xed874c0c, 0x33db4ddf, + 0xcfdb4463, 0x7fcad620, 0x8be6b551, 0x9204e606, 0xa7107926, 0xbed1bb51, 0x6cfe82dc, 0xc2837271, + 0x049890bc, 0xefeb5295, 0x0213c172, 0x179fd270, 0xa1d17930, 0xfcd5a1f9, 0xdb81e9e5, 0xc46c6fe8, + 0xe3bdc6bd, 0x535d77ca, 0x108845fa, 0xcc3aa3a7, 0xa65ef735, 0x82dfb86f, 0xb2eced69, 0x8db6569d, + 0x57db397a, 0xcf27fdd9, 0x1a484202, 0x6e2da89a, 0xe7c0a2bc, 0x4b2d97c8, 0x4d5a57b9, 0x6ffe0c17, + 0x5ec37ed5, 0x5fe96b0f, 0x3f2bb1f7, 0x7a5fb7a7, 0x26de0d2e, 0x6fc988c4, 0xf4a20dd9, 0x7f2e6b7c, + 0x10febc81, 0xdab65ff6, 0xf85bbc36, 0xa973fd1f, 0xa641de64, 0x44e86c34, 0x4e6720a2, 0x888287d8, + 0xf2935b94, 0x48588511, 0xc90d48db, 0x77849d2b, 0x6728ce59, 0x01f5b448, 0x86243a2b, 0xe78adc9a, + 0x8eb54221, 0xb3bf350b, 0x826f0dd5, 0xa2b4b7db, 0xcf3097d1, 0x5a010a4d, 0x4a49b0fa, 0x690d0682, + 0xc677cc8a, 0xc864d138, 0x69e400ef, 0x202efd9b, 0xdb6f4fcb, 0x7cec3953, 0xe75aff96, 0xe459cb24, + 0xabd842e4, 0xe884ad53, 0x701e47a9, 0x81a5e1ab, 0x13395a86, 0xf28003bc, 0x4f0e5db8, 0xfa5c9bb5, + 0x7acb3730, 0xa30196fa, 0xea14b2d4, 0xd6c0a695, 0xafea05b1, 0x38f37e93, 0x50802970, 0x1d3c0cd7, + 0x26a15ecb, 0x59430992, 0x7f26df2b, 0xa53a78c9, 0x839fa750, 0x777aa3ec, 0x1683759e, 0x519fc11d, + 0xdb805e0f, 0x8f293bc3, 0x25252203, 0x1b3d7a50, 0x89fb194e, 0x3c5333a1, 0x46949665, 0x1f8d9cd5, + 0x997fa296, 0x3834ec07, 0x2ec7f379, 0xadb868eb, 0x96ec9818, 0xc6632a85, 0xb9fa864d, 0x8a4ba952, + 0xd362033c, 0x7c343d7d, 0x6792d2cc, 0xe73af81f, 0x54e869c8, 0x6da1b91c, 0xd4878ae7, 0xf790e238, + 0x872d4697, 0x6e4df0da, 0xee9bbafc, 0x947a031b, 0xf8bd8656, 0x89806dd6, 0x28421959, 0xd24cf5a5, + 0x93112df6, 0x018c2020, 0x7ec9df8f, 0x2817ec70, 0x00d3d4d8, 0x7d3b814c, 0x13d023a3, 0xb14d9f18, + 0x09bb7525, 0x9666c41a, 0xdec7828c, 0x1fe5e21c, 0x8321a5ad, 0x209a4e69, 0x7bc2d245, 0x41b220a4, + 0x080b44ba, 0xe06f7423, 0x8b23cff3, 0xc5d1ea00, 0xc9e41270, 0x500d0cc0, 0xb2f204b4, 0xba666e85, + 0x47114ad0, 0x6be1bd09, 0x9eb49c70, 0xddfab2a8, 0x3586e20d, 0x7881f84f, 0x2c34204d, 0x52c7922b, + 0x18ca5a75, 0x13399e01, 0x9fa4e830, 0xc0ded8d6, 0x8c10a405, 0x6791b71c, 0xefb2b720, 0x6bcf4484, + 0x430c447e, 0x4f53d9ce, 0x11a73d78, 0x1fefe9ce, 0xa4a1ab3b, 0x4570f0b3, 0xe7b223e9, 0x2b468d5f, + 0xc17216f8, 0x2b108bcb, 0x1d444626, 0x8a15e428, 0xf73ac824, 0xe522f732, 0xee0f2b6c, 0xaf57373c, + 0x7dcb683a, 0x752ab2bf, 0x37194240, 0x976b8770, 0xb0290f71, 0x5d16752e, 0x52cca1aa, 0x487eb322, + 0x80051b59, 0xda203ff4, 0xd65a0969, 0x43fb7418, 0xfee7af64, 0x9b297b11, 0x64c632e2, 0x59c41b2d, + 0x088713a7, 0x5ac4450c, 0xe8a3bc7c, 0x7f630610, 0x7daea8f8, 0x9b0fc291, 0x3c7bbd83, 0xbfdafc11, + 0xc058e8ac, 0x768c5474, 0xa3c25b2e, 0x9058a196, 0x1c7b7a24, 0xeae46c8c, 0xe379d3a1, 0x3e1c6e68, + 0xa719c355, 0x1d4e30e3, 0x0b6111d4, 0x37bb65ac, 0x91a7b86a, 0x47ef0490, 0x4aecc2e7, 0xc0a135f7, + 0xaff09db0, 0x4528f952, 0x58f0c34f, 0xc0947d7d, 0x1c2fd30a, 0x23f160cc, 0xcc9ee026, 0xfc574828, + 0x4da547b2, 0x4ac96eee, 0x094b6bd7, 0xeda6365e, 0x9856c880, 0xfa29ec3e, 0x21a55e3b, 0x9414591e, + 0x523c44c6, 0x9431d63f, 0xab2d6ac7, 0xb3270ccb, 0xeda7b2e9, 0x96787ce3, 0x6cdd8130, 0x1d48456f, + 0xecaa2d36, 0x6e5ccb13, 0x67ab65b8, 0xc29727d3, 0x95f94c48, 0xf6312a2f, 0x3170cfe7, 0xfe772305, + 0xf0ee2f86, 0x92228be3, 0xc4ea5d8a, 0xfd64be12, 0x1ac7a1c6, 0x4ee94d66, 0xc1c47082, 0x7c561dbb, + 0x744187a7, 0x0f6b9c8a, 0x7457534d, 0xddcc5515, 0xf3bf98e7, 0xcb2561d0, 0x4b04b5bd, 0x177cae50, + 0xe45245f3, 0x83e63608, 0x984a3251, 0x19d48f58, 0x7204b194, 0xc71e27f1, 0xc137bb2f, 0xf482e6fb, + 0x471ef307, 0x3852d964, 0xe352c582, 0x332b8d41, 0x6f725750, 0x1a06b1fe, 0x979477e9, 0x27d67d18, + 0x65d54495, 0xf2de6518, 0x9ede2fc9, 0xd71288dd, 0xee864d71, 0x6a47547e, 0x623839ef, 0x2b0eacc8, + 0x9ccffb48, 0x5215e9cb, 0x8bee7740, 0xf4425380, 0x41790678, 0x01949e19, 0x0082e79e, 0xfecde2ce, + 0xae229b3c, 0x076e9560, 0x99258ccc, 0x717e0bf5, 0xc13d1611, 0x98d00aa5, 0x796e6065, 0xc52fe34a, + 0x97232751, 0x113d248d, 0xde201068, 0x8079787a, 0x7c9d9d55, 0x95aff0f3, 0x9f51b9f4, 0x6dad1437, + 0xfafc5cff, 0x536024c1, 0x8aba7ed5, 0x7799f98f, 0x7a63cf4d, 0x6fc57fee, 0xaf6cf6bb, 0xd4e1eb67, + 0x1e4879e3, 0x849334a8, 0xfd998720, 0x531cbf0c, 0xb81cc723, 0x4d72f3fd, 0x5114b39d, 0xd69d8649, + 0x98f17046, 0xa83517a8, 0xf93f17b2, 0xe9d45868, 0x513a1874, 0xeb32a25e, 0x30469aa7, 0x424a40f8, + 0xddcfff96, 0xcbe92926, 0x128f0258, 0x6bd4cd2b, 0x47753d21, 0x67b5fcc0, 0xf31da48d, 0xffd5aa85, + 0x7426e545, 0x2a6b5f6c, 0xacac3485, 0x9a925bc0, 0x536b5c8e, 0x7ba006a8, 0x692e8197, 0x4c367997, + 0x0d1110b5, 0x463291cd, 0xc0589a20, 0xde904ea6, 0xe3077226, 0xb8b83ce5, 0x23b22db6, 0x2c8ed0bd, + 0xeb50d59b, 0x665e90a8, 0x680cb7c2, 0x58f75f69, 0x2a857eac, 0x959e1c9c, 0xd2be19b0, 0x74e86872, + 0x960f237a, 0x64ea9100, 0x480c3ecb, 0x64945814, 0x43442b20, 0xba0ae85f, 0x8a8edb52, 0xe13ff8a7, + 0x27258361, 0xabbf9f27, 0x3673e6d1, 0x4540baae, 0x8b0045d8, 0x29d28730, 0xdc02da4e, 0xb3fda386, + 0x248fd9ce, 0x0a55f8d5, 0x8c97cf13, 0x1809fed9, 0xc9d9fc00, 0x7b934ca3, 0x9b788e76, 0xaf0a5a6d, + 0xc50d4b4f, 0xcf32d583, 0x2d80de90, 0x1175d164, 0xea1f0e2b, 0x736f275a, 0x871ea54b, 0x9a7392da, + 0xc7dbdd55, 0x918a6378, 0xb8c00fa9, 0x2518af13, 0xf0bb4ce9, 0x63f9f6ce, 0x70e1afbd, 0xd748e016, + 0x1bd08340, 0xdf867ab6, 0xa40b617c, 0x3f4280d9, 0x18f8e845, 0x68db688f, 0xadc5deba, 0xad802dae, + 0xbb9f2e06, 0x3647da52, 0x82fb4c0c, 0xa83a5c63, 0x4c8e87dd, 0x7ccdde33, 0xd6805e11, 0xdecfa903, + 0x7af66edc, 0x93472f61, 0x66e4bd89, 0x723c8727, 0x1138efb2, 0x34204c87, 0xb4eb26eb, 0xddaa108f, + 0x936f8895, 0x885054f5, 0x92bc62b7, 0xdc8dee86, 0x4423b48f, 0x35b32c52, 0xceffc2d5, 0x0ec98ae9, + 0x4a36c431, 0x52ac63e3, 0x3a3a5f77, 0x7f9cd4ae, 0x57d79054, 0x74f2d29a, 0x67bc6753, 0xe3fe5e7f, + 0x356eb65e, 0xdfcbacd9, 0xb33a34eb, 0x31d4cb95, 0xe298f266, 0xbe9c65dd, 0x6bca96d2, 0x13f10f9e, + 0xdf5d9fd1, 0xd1eeae31, 0x2e732794, 0x57e95698, 0xd6bf5dd4, 0x82d5aeb1, 0xd0e59205, 0x5c465fde, + 0xa20d9d27, 0xa2f82171, 0xf5b18f32, 0x9956e62c, 0x5d310db5, 0x56a2dc78, 0x1828132c, 0xfbbeeafc, + 0xdaabac72, 0x75797d05, 0x6e58420d, 0x75057ea5, 0x0db01a4e, 0x1abb66f2, 0x527e0d47, 0x20a55e6f, + 0x563d1332, 0x943c1630, 0xd390fb1c, 0x3011e487, 0x44b68774, 0xa6efaccc, 0xd69dda60, 0x34119c97, + 0x9eee29fa, 0x53f258e1, 0xb00b1068, 0x1f5305f8, 0x2459aa82, 0xe5d6c6a5, 0x3669ac66, 0x135f105c, + 0xfcaae7df, 0x97d054f8, 0xdfeb2266, 0xec0645ce, 0xc6a30263, 0x0f63d786, 0x6c847ca4, 0x4f1c5322, + 0xf30ae0e8, 0xa76b55cc, 0xc29309c7, 0x063235d0, 0xb5dc59a4, 0x7ebd7bf7, 0x9e3c14e5, 0xb21e4175, + 0x3b9e50d3, 0x0c77caa2, 0x518f6175, 0x695252ca, 0x42132de6, 0x81ce6827, 0x8fb743b1, 0x0343fbb4, + 0x05154b55, 0xfa049494, 0xaae19a90, 0x08f2ce94, 0x6ef1d04c, 0x41535bf7, 0x5e93dc88, 0xe507a51c, + 0xb674ca02, 0x6ab2205b, 0xbcf7087c, 0x1e240b22, 0xaf9d8440, 0x06e135c5, 0x3a4658b5, 0xbb75060e, + 0x9c510a85, 0xf7b5140c, 0xdd9e7168, 0x20d207ef, 0xf5112492, 0xf864987d, 0x0f56db07, 0x4b595d2b, + 0xfbbd8f7b, 0x66e3c1ba, 0x4ad6ab5d, 0x21af4afa, 0x210cceb1, 0x83f9b9fb, 0xb40bf455, 0x941ddde4, + 0xbf8d4980, 0x5c229f59, 0x3fa1deb1, 0xa54b5a1d, 0x5dce0a94, 0x33d7d999, 0x2dde7b4f, 0x3eba3005, + 0x1bea62d3, 0x762ff997, 0xea58a527, 0x1562fec8, 0xac904f1b, 0x0aed1f50, 0xba8f6366, 0x1fc43ecf, + 0x14e972e9, 0xc4db3034, 0x2b77d63e, 0xbc482210, 0x101efb50, 0x1e5e4826, 0x98bd1b27, 0x3a4a9b6b, + 0x4ec88ea7, 0xd1f2f67d, 0x8b51b740, 0xe63fd1c3, 0x55cc417e, 0x59aeb673, 0xbb6fcb1c, 0x0e9e6680, + 0x5e30cf2b, 0xfce93d86, 0xf0a6c11d, 0xe1e6fb02, 0xb08e2448, 0x9d03c261, 0xd9789872, 0x56b762d2, + 0x9feab826, 0x66478a31, 0xa1cd1a13, 0x3f367fe9, 0xaf8aca0a, 0x652791d9, 0x8284da49, 0x48979ece, + 0x1738bf27, 0xb0b41b71, 0xc9b6f316, 0x17a40619, 0x81824f21, 0x8b7767b8, 0xbde75351, 0x1fa6d4f5, + 0xc661aa2d, 0xb7d7a6a7, 0x8572606d, 0xaf66d126, 0xd26bc1a3, 0x453db881, 0x9e70ce62, 0x31bd421a, + 0xc0c87cd5, 0xd52bea5d, 0x8c803943, 0x0d9c694c, 0x92a1f1f8, 0x5c6565f5, 0x45aaee56, 0x2d79a18a, + 0x5c17d567, 0x194cf0ae, 0xedb6f0a7, 0xcf44b2de, 0xa4a6946e, 0x9dcc1494, 0xec296e61, 0x7b978299, + 0xa0185035, 0x204e82e1, 0xa0ec1151, 0x11b31d29, 0x3fbb06a6, 0x69ef4c6e, 0xbbeebb9d, 0x5fc7eae8, + 0xa2b71caf, 0x1aab5e49, 0x5f16ceb6, 0x955c7f9e, 0x73870841, 0xe496e0a0, 0x71bf6200, 0x92982209, + 0xac99ac17, 0x2e3b8e56, 0xb1918746, 0xcfec9fb3, 0x7284f91a, 0x7a53472c, 0xb056d608, 0x5dea8d2a, + 0xf32fd3f6, 0x325e94c2, 0x98c9af7e, 0x15fc2cd4, 0xec14b8cf, 0xe7a825b4, 0xea22dea2, 0x203aecb3, + 0x1192229d, 0xef81d653, 0x77ee7fe3, 0xba5349f7, 0x51a8b409, 0x6de989e6, 0x20a04339, 0x98420310, + 0xaf1b71fb, 0x17c3aa9b, 0x67955c0d, 0xab6110b4, 0xe13880e8, 0xfe7f15ac, 0x61d9c87f, 0xbb325aea, + 0x6994aaa2, 0x9d1a5147, 0x3c7501fe, 0x437bc739, 0x4ab8218d, 0x3665a0e7, 0xb71afc9e, 0x6a67e92a, + 0x302dcab4, 0x9d91430b, 0x314dc9d6, 0x536e4705, 0x054d834a, 0x06e27afc, 0x8da42b86, 0x15d80d75, + 0xb79d6f15, 0x27f4297b, 0xb6bf6504, 0x5b0208fd, 0xb215a6da, 0xd649d65f, 0x5a749d30, 0x02d1da63, + 0xdbd1054d, 0xa0389cd8, 0xd3a15a80, 0x2e382d03, 0x1f48722a, 0xa65b9e47, 0x423beed6, 0xbbe93230, + 0x1c9796c1, 0xa7323672, 0x4ab6fc9d, 0x0cb67f42, 0x45b1346c, 0x5088cb5f, 0x960bb223, 0xaf46cdee, + 0x348d48f5, 0xe1612ffa, 0x9e59f883, 0x1988837b, 0x5e299a5c, 0x51097382, 0x6463fa28, 0x0f20690a, + 0x15d65ffd, 0xf0a13f60, 0x2c719bc8, 0x2a54ab81, 0xcc35648e, 0xb16d392a, 0xeca35f9e, 0xd52beb77, + 0x4219dc8c, 0xe5bf45b1, 0x4fa0f7ea, 0x0a419277, 0xb1d47c16, 0x2c7972e7, 0xa2a76640, 0x5cf3c83f, + 0xc0e2526c, 0xdbba4fe5, 0x4f220643, 0xc9be3bd3, 0xc9598454, 0x4f1a5f83, 0x717a1dc9, 0xdbcfdefa, + 0xfde6534a, 0xa6a2e05d, 0x9dca36ed, 0x35a50650, 0x62222f4e, 0xe194f36a, 0xd7a141bc, 0x04ac8c54, + 0x82b13d7d, 0xcde67d11, 0xecfa1deb, 0xaa2719f6, 0x6fd144e1, 0x665d3d49, 0xabe1260d, 0x6ed53c59, + 0x76c4a420, 0xd5e02157, 0xa15e00cd, 0xe2261628, 0x5bd61327, 0xda8cd873, 0x99add7fc, 0xa7568b18, + 0x634e3427, 0x03f8ce4a, 0x533d07dc, 0x7e64eb34, 0x417b701b, 0xbf83c9b7, 0x46bfcc23, 0xe9bf4333, + 0xfbaeedbd, 0xd98ef483, 0xfafb0a4b, 0x5692fd57, 0xbe574825, 0x2aa75b17, 0x5eb195c8, 0xcdfef2a0, + 0x1d32fed8, 0xb72dcc19, 0x8b2cb0eb, 0x894dbb6b, 0xdea59fe5, 0x8f43a0b3, 0xa9ce8b8f, 0xf3f26bed, + 0x3504bca2, 0xea0bbc51, 0x3d76ee79, 0xc16a1666, 0x116b18e4, 0x5c2f3f4c, 0xc39d589a, 0x72c90294, + 0xfcf18147, 0x4ed00451, 0x344d10c1, 0x3d8fe6ac, 0x521b7ecf, 0xe68b3c7b, 0xe70d77ff, 0x2dbaa7b7, + 0x19c76d71, 0x178d5471, 0xc52d9852, 0x48d20f14, 0xeabe049e, 0x3eb8f755, 0xd8f1a494, 0x17252cf1, + 0xae9eafe0, 0x7381601b, 0x047fa68b, 0xa66318f4, 0xdd096533, 0x70911636, 0xb1c23b4b, 0x2ed2f74d, + 0x86b9d7bd, 0x92f33af0, 0x026ed20e, 0x2c93e3f1, 0x53744203, 0xd5f0d2ee, 0xbb4075a7, 0x2ed644d7, + 0x309d2ecc, 0x9701259d, 0xd525a5c0, 0x07e35149, 0x9779001f, 0xad6479fc, 0x96055510, 0x6fe3af93, + 0x45159ebc, 0x7ef0eddb, 0x2201a1fa, 0x6f228699, 0xf329915e, 0x5be6efb0, 0xc402968f, 0xda4e2f5c, + 0x03f2ad02, 0x035f234f, 0x8e301a2e, 0xd5e78710, 0xfc8805a9, 0x226005de, 0x81a9b2e0, 0xb636d412, + 0xdc1dea9e, 0x8ed49876, 0x1d45c601, 0x1843dbd2, 0x781db617, 0x3a702e6b, 0xdb572bec, 0xcad102ce, + 0x29070f97, 0xb38807d0, 0x6580e580, 0x1cdef69d, 0x725d2eb1, 0xcd4341db, 0xa87af6e7, 0xbcc188f6, + 0x9f679808, 0x78f4e1f8, 0xae4f5d03, 0x6a5f69bf, 0x69ffbc74, 0xa85c7e34, 0x82f7e540, 0x840a0d1b, + 0x9c2d5418, 0x1004781b, 0x22f2c43e, 0x1a87d18b, 0x3f6838b6, 0xe4c2e590, 0x6afd2306, 0xdf679af2, + 0x00fa9a07, 0x3f2901ff, 0x56c47752, 0xc2f46fc3, 0xe129aa1e, 0xa7e893eb, 0xd7e566c6, 0xc2decd6a, + 0x98f30d57, 0xc2446840, 0xb4a623fc, 0x8ff1e83d, 0x4b37c047, 0xf0e2176d, 0x1ec9c416, 0x509591d3, + 0x9bbae671, 0xe1aa30ab, 0x9c0c832b, 0x18099402, 0xa9b1cda8, 0x79469790, 0xf1c3c7dc, 0x5e37467e, + 0xc93e1807, 0x84e68ac2, 0x238bd2d0, 0x720a00cf, 0xeeba2ab5, 0x2e27b232, 0x319f9b68, 0xe217756b, + 0xa59ef9b5, 0x1ea998bc, 0xa5134967, 0x7d64339f, 0x2da5f53a, 0x4c4a998c, 0x7c1b8da0, 0xb6a4fc77, + 0x5492ed9d, 0x8e924111, 0x8b27ac5c, 0xba11e276, 0x9fc8ccec, 0x2ae3c4e3, 0x5e4ab7bb, 0xffdf6bdb, + 0xb00c77c4, 0x5b35081e, 0x57d06d41, 0xcffca0c1, 0x5cbc05da, 0x7623854d, 0x185c2d1e, 0x868a1316, + 0xdbc7ffc5, 0x82a6ced8, 0xb553101e, 0x0dbbb25a, 0x4b888ccd, 0x69206406, 0x1fc52664, 0x9e1a94a5, + 0xc1801651, 0x866e35e8, 0xfe10dc56, 0x63aab8b8, 0xf15ef47b, 0x430622da, 0x99942f82, 0x4174ad3d, + 0xe7724cff, 0xa93bdd3a, 0xb6f07b67, 0xf3401116, 0xead748a4, 0xcfa46f8b, 0xf528c6e8, 0xa11a1c17, + 0x6a5b12ae, 0x9bf4906d, 0xc51af5ca, 0xfa1615d8, 0xe58cd8c5, 0x65b29536, 0x51d297a2, 0xdf8a32e1, + 0xcb702c87, 0x976b1ffa, 0xd860b101, 0xed5e7240, 0x56eafbac, 0xc057808b, 0x9db24e03, 0x0a1502f5, + 0xae43d5e5, 0xb2db7387, 0x7603f6a3, 0xe5e65af5, 0x83e663e5, 0xb3669340, 0x1ac1ba77, 0x81411c10, + 0x2248ce16, 0x7768c07c, 0x52a0b0fa, 0x57267e4c, 0x7c2f8ddc, 0xd439358c, 0xd6cd0887, 0x6e7d6771, + 0xa8d5b0f9, 0x37e0a8e0, 0xb8744082, 0x723e24e5, 0x66f02f25, 0x497c9c3a, 0xda01686a, 0x2db5ed44, + 0xd8d42bac, 0xb6380b9a, 0xb9276588, 0x99a9d1be, 0x2e97cbc4, 0x38d4d32b, 0x38263b0e, 0x143083fc, + 0x3ae35c63, 0x64d750ff, 0x29276211, 0x94712f59, 0xc7714eeb, 0xec62fbf9, 0x32d8814c, 0x8636c69c, + 0x51c4a911, 0xf04827b1, 0xada636fa, 0x226e0993, 0x65a3869f, 0x2fce3149, 0xf8f9d427, 0xc40daea5, + 0xb137caa9, 0xc6ce9e80, 0x82d58753, 0x9dda8ea7, 0xb7d1f503, 0x422e8bee, 0xded9c03a, 0xfcc56e97, + 0x4534c067, 0xcc61e465, 0xf97b2cb4, 0xe21a6b2e, 0x10765b2b, 0xf3a330a6, 0xa782037e, 0xb042d918, + 0x5607853f, 0x601e8717, 0x9c1d4b76, 0x07ff7312, 0xa07cf6dc, 0xdfc9cce6, 0xffcb0c39, 0x5f65c5be, + 0xb88e5819, 0x06f15189, 0xdd502bd7, 0x7403a312, 0x54a9224d, 0x3b5617d3, 0xfeff6da1, 0x9db8c17c, + 0xe7c559af, 0x264a0a3f, 0x448136f4, 0xc3202f09, 0x75de19e3, 0xb4d1fddb, 0x6710e730, 0xed1441f6, + 0xaf0b4be8, 0x5f875036, 0x265b0bfb, 0xef232f04, 0xb51b8155, 0xb130203a, 0x5de73646, 0x2a6320e3, + 0x38b2bd89, 0x39b74c3f, 0x92f5fd61, 0x16a75982, 0x0a4b0ac9, 0xaf9318b1, 0x185de827, 0x85041043, + 0x10bc45e2, 0x8c638cef, 0xfca3686e, 0x993794a7, 0x70a0cee6, 0x7687ffc3, 0x8643e964, 0xb9650db6, + 0xe68f0c04, 0xf4e289f5, 0x50f32cca, 0xe9a1e2c6, 0x791deca8, 0x2467a6ec, 0xbdbd2a44, 0xea6f20ce, + 0xb6e9c373, 0x56270023, 0xa5cd4098, 0x922d1075, 0x408a911a, 0x62bd5c03, 0x0fa50509, 0xcea4f52d, + 0xdaf094fe, 0x069f864f, 0x9d5e4afd, 0x672f62ae, 0x5618b383, 0xe5cb7128, 0x50917ba2, 0xb2a28e82, + 0x5504dc78, 0x92a7b661, 0x09372c67, 0x83767795, 0x1c02091d, 0xbf89ad19, 0x88329d8f, 0x3d8fec3c, + 0x29c89fb8, 0x974e1456, 0x9c5776ff, 0x477c19ad, 0x305856ec, 0x7744218f, 0xf53d437b, 0xd6671e92, + 0xee9e8f46, 0x75cb8996, 0xbdba32d0, 0x49685513, 0x86529a37, 0xcf2edaf6, 0x017656a5, 0x7d2e0464, + 0xb0c3f20f, 0x16dbadf4, 0x02c73f93, 0x437c7e86, 0x24bdca3b, 0xb3ec5c8a, 0x17eed567, 0x679d7756, + 0x825c79bf, 0x273d6a38, 0x6e48d17b, 0x9d784f43, 0xf17dcd35, 0xc8389a23, 0xf4dab5dc, 0xbfe63e4a, + 0xa4645028, 0x38d8ee8d, 0x11c81bba, 0xa9e1a5c8, 0xe38663a4, 0x3b1d2a44, 0xececd524, 0x8b7fcee3, + 0xfb485183, 0x42c0272a, 0xdbe25fd8, 0x7386791b, 0x75928830, 0xb4898383, 0x714f86d9, 0xccb0b2fd, + 0x8339d6cd, 0x9fce5458, 0x944c7d3f, 0xa11757e2, 0x42948ddd, 0x942bcd30, 0x7fa58ca3, 0x79257e0f, + 0x37bce304, 0x21d5621f, 0x1e37541d, 0x964a1a04, 0xb22de566, 0xad2970b4, 0x540798c7, 0xcb39baca, + 0x88f6eada, 0x44c20c27, 0xf2f16243, 0x0bfecbba, 0x0f99710b, 0x48924e0b, 0xa2e6f059, 0x3b512295, + 0x1268e82a, 0xc0b47a92, 0x9b264e0e, 0xc49d6f2e, 0x4742e1b4, 0xe7e3538b, 0xb16cae19, 0xb9e55494, + 0xbaccff2d, 0x20442719, 0x75948c59, 0xf6a082a9, 0xe9adf8c1, 0x6420f5ec, 0x5b1eaea6, 0xf36f8464, + 0x40b9322e, 0xe5987987, 0xe927a375, 0x3b24dc9d, 0x05464db1, 0xd394699d, 0x1b265299, 0x6b314c9b, + 0x63b45845, 0x6a02faa3, 0x931bc14f, 0xc4ee54a7, 0x81341940, 0xdcc18b94, 0x51fabd1e, 0xb5c42513, + 0x75c86116, 0x2a1f5573, 0xd009aa61, 0x7d602504, 0xa353b42b, 0x630d9e9a, 0xc5cf6292, 0x1d5d80cb, + 0xff185fe2, 0x7b25bdca, 0x3ff96297, 0xa4da2a3a, 0xa8fc2b4c, 0x20f02811, 0xba3e30c6, 0xd1f76063, + 0xc920583d, 0x7ba9e8ff, 0x524e9284, 0x1b5f9591, 0xdf93b8c9, 0xd9bd934a, 0x584f9900, 0xf320c31a, + 0x4d05f79a, 0x4b33f33a, 0xf0379d2d, 0xfb6ad1fe, 0x47f957b7, 0xe55144a4, 0xa43bc017, 0x71702e80, + 0x00dc9514, 0x17e559b2, 0x354e2b68, 0x80a45f1e, 0xa226846f, 0x01d6456d, 0x24a01191, 0xf6727b65, + 0x1160c99e, 0x8d824f73, 0xcd22d90d, 0xe162d724, 0xa150fc4c, 0x640e18a3, 0x2729e1a2, 0xf99cb25b, + 0xede1dd8e, 0x13fef881, 0xc72019ad, 0x5478e2d4, 0x3fe5234f, 0xad923e38, 0xb4f95d7b, 0x560f0858, + 0xd1e04827, 0xe66bc016, 0xddf2b797, 0xfe833ea4, 0x2cd8b982, 0x91335439, 0x8aa0db9f, 0x444cbf52, + 0xb420bd0b, 0xe71f2c60, 0x0f9f0272, 0x8cb11eed, 0xd7bfd16e, 0x0740fcc1, 0x1bd3948d, 0xc2710f83, + 0x072cd067, 0x823dde63, 0xdf7464a4, 0xf6a61aca, 0x6e5ec528, 0x4c60bc6c, 0x6dcf04b6, 0x867991a0, + 0xdfef64df, 0x17d6b2b2, 0x0fc27e9c, 0xae8f7a19, 0xb08e0f05, 0x8a1b39b6, 0x7a4a7fc7, 0x7b7c0348, + 0x5111ce5d, 0xf5c6e6c4, 0x4f87f2eb, 0xcd64489a, 0x75f4a0bf, 0xd84f6b77, 0x62d5410e, 0x01b45a81, + 0xf92d9500, 0xd8c58987, 0xc28089a0, 0xb885f915, 0x6d58c3cc, 0xe2e88bde, 0x15094863, 0xdaebc40c, + 0x842cb161, 0xf6c907c2, 0x0e8fd67f, 0xc0f7c40e, 0xe979dc0c, 0x48cf1ee9, 0x3d50adda, 0x72411b8b, + 0xcca408c0, 0xf3f12d3a, 0x635d5b84, 0xc711b255, 0x3fc2abdf, 0xcf8b7698, 0x232170f1, 0x35f16acb, + 0xf8062a11, 0x5174b835, 0x924179b6, 0xcfa59665, 0xc9fbed6b, 0xf40f7c5d, 0xbeef51bd, 0x825cbc60, + 0x3986088d, 0xa6e4783b, 0xdf789d5e, 0xbac15c7d, 0x2f8d629e, 0x35763c0b, 0x474180c5, 0xa7477720, + 0xfa158efc, 0x1cfa4730, 0xb86441dd, 0x83594be0, 0x6096c4a7, 0x882eb4d0, 0x32e15141, 0xec3b2e41, + 0x2aaf9ecf, 0xa4321c13, 0xeea06772, 0xd7cbc495, 0x809883bb, 0x90e3a6fb, 0xc5f62625, 0xca2c9f8d, + 0xf0781c49, 0x4b73b389, 0x436cb761, 0xde33bb77, 0x9a0011ab, 0x04e16acf, 0x06b50455, 0x00e6eec4, + 0xde3d44de, 0xc4bc632e, 0x43efa5eb, 0x3d6e1e6c, 0x34abb7a8, 0x340fb909, 0x2a033e0e, 0xc999fab6, + 0x87b6f3ad, 0xd1d0c59c, 0x95f528df, 0xbbe10b29, 0x3b07e171, 0xb1a10c29, 0xe92eae53, 0x7eb564df, + 0x40574ec9, 0x1b12ae9a, 0x747ab3e8, 0x4088176a, 0xfec7374a, 0x3cb77862, 0x6dae9b61, 0xab882716, + 0xee24d9cf, 0x1d699a5e, 0xbe988b2f, 0xb58fc397, 0xb42359f0, 0xbfb58b36, 0x0e562ed6, 0x34ce61e2, + 0xd1102726, 0x1375f472, 0x624a4814, 0x10f67a83, 0x43b5165c, 0x61341794, 0xe0ac1105, 0x94eabb82, + 0x023a9a41, 0xde10bf2a, 0x6bc1f54f, 0x981aff4c, 0x3d764937, 0x2a432f6b, 0xaa08b041, 0xf3a4a1c0, + 0x9fbd9d60, 0x1d1f6327, 0x9dbe95af, 0x913540e9, 0xf91bea87, 0xe6bf1550, 0x38f40d4a, 0xb875ce5d, + 0x1a9fe8c8, 0x1d6f20cf, 0x2ef6a136, 0x35990433, 0xe036a07e, 0xbac8abbe, 0x6371724f, 0xfbdb3188, + 0xd1c8ec28, 0x8b2c987b, 0x2aafee2c, 0xaab7d2d1, 0x4fa335a8, 0xaf323251, 0x37706d40, 0x6b89f844, + 0xeda536a1, 0x655a2d9d, 0x4aa1de06, 0xfefbaac2, 0xf47a3730, 0xf6118bbe, 0x931c71ae, 0x34cf1847, + 0xd0f1e6ba, 0x6e09b067, 0xcdd294b0, 0xb6c00bf3, 0x353ae9b7, 0x0a1253e5, 0x812021f2, 0x54048e65, + 0xeeba3faa, 0x6ab98a6d, 0x1dee22ef, 0x525f8b52, 0x9aade45b, 0x82a29aa7, 0xefc94d49, 0xb3c65dc2, + 0x3b66c7b4, 0xb36adcb8, 0x4a43f399, 0x7c0134d3, 0x5c5427d1, 0x4294b8bd, 0x61218772, 0x3932b27e, + 0x028f7111, 0x94b494bc, 0x9869ac4e, 0x0c4f1c98, 0xf3621ac3, 0x77696b7b, 0x96596d84, 0x79696579, + 0x228357c1, 0xb60c937f, 0xe4a1b782, 0xd0928198, 0x8c0de9e3, 0x083cdfbe, 0x39a24ad8, 0xcce5a74f, + 0xabcaea6a, 0xbdf1a2e9, 0x0bc03d98, 0x3b834936, 0x8ea106ea, 0x9f4afc7c, 0xda6859ed, 0xcd0bc4b5, + 0xbe1d24a5, 0x6cc2aef0, 0x1372076e, 0x0fbcd61b, 0x99ebed2f, 0xcaf9094a, 0x1c486122, 0x50dade41, + 0xd5770cda, 0xb905a07b, 0xb675b9a2, 0xc4c7098f, 0xe07176a6, 0xdb659bd4, 0x68411d4e, 0xbb1b1394, + 0x4bb25e1b, 0xdac472a3, 0xf10e52b5, 0x4215d4ad, 0xd8275a4b, 0x7fe0b4d0, 0xce026dc3, 0x55c1d70a, + 0x7b10a09c, 0x99a79eea, 0x555887d0, 0x7c1737b1, 0xe47f852d, 0xebfb6594, 0x8ce633de, 0x7b0b0dc6, + 0x0f0e6551, 0x472f6339, 0xe922871f, 0x640a753a, 0x1dc580f9, 0xef53a70a, 0x38b2a812, 0xa6898a5e, + 0x124080da, 0x622e796f, 0x986f130e, 0xe8be60bc, 0x82b0e452, 0x6242c492, 0x3f11365c, 0x4b0c7da6, + 0x40c29798, 0x3bc890e0, 0xd8048b96, 0x8dfdff1c, 0x54cb3118, 0x8fb5d760, 0xa44917d0, 0xf51aa5d8, + 0x1cb06ad8, 0x32f32f89, 0x6fe3c8a8, 0x101b944c, 0x121098ec, 0x2d53d60b, 0xe59a53ae, 0x77555f80, + 0xd12f8be4, 0xf8d46983, 0xf732c5f7, 0xd9266207, 0x90d3f928, 0x9644a59b, 0x9b0cbb22, 0xe00c4674, + 0xbf75a78a, 0x574349cf, 0x8192aa06, 0xc57ff5a6, 0x3b980532, 0xeb52933c, 0x569fa044, 0xe1255acd, + 0x598935e7, 0x2290a5d4, 0x66f25261, 0x1e32c7ff, 0x9fbb45e4, 0x817b6a4f, 0x682c6a22, 0xe8337468, + 0x9c687e6b, 0x992565ff, 0x666d78a3, 0xf63b6e64, 0x27d1d005, 0x32291967, 0x4425e137, 0x31b89b21, + 0xdaeed23e, 0xef7f1943, 0x6fe4d85a, 0x1a801400, 0x753a1ff1, 0x50aead02, 0x663f06c4, 0x74976949, + 0x68f0c5b2, 0x03aaa845, 0x21d92bc6, 0x2de2effd, 0x91cc154e, 0xab23c2cc, 0xb0eeb6b6, 0xe0769ba3, + 0x5fba5d3d, 0x0ea71b44, 0xeff7df54, 0x4fb82494, 0xce417399, 0x460aa9c7, 0xa32f91ad, 0x7edc59e5, + 0x666ccade, 0xaaa39f52, 0xc40b60dd, 0xcef39155, 0x720c8b01, 0xd5681fa8, 0xe04ddbc6, 0x552bbf50, + 0x6932209b, 0xe6ccf3a7, 0xf0860d1c, 0x2f288fe1, 0xa5a0282e, 0x931e2b14, 0x530afb7c, 0xdd1f9ba2, + 0xb2591cfd, 0x9f7ef4c1, 0x325b3165, 0xaa7b6071, 0x976bfc8f, 0x79abdf0b, 0x875a27db, 0x6a5000cf, + 0x7343a91d, 0x426c307f, 0x9c4efcf4, 0xf03cec60, 0x82b3122d, 0x507d6d4e, 0xe693a5cc, 0x6f068436, + 0x4abdd9fb, 0x03d5ba42, 0x17358ed4, 0x79fa28f0, 0xf129e04b, 0xdcb78250, 0xedef1ac2, 0x64c38b4a, + 0x8f0617f7, 0x279c1a76, 0xaf8faae7, 0x0f9bb08f, 0x7ee9b044, 0x0028a34a, 0x0aa3a0ad, 0x683d9a04, + 0x0d0b66ad, 0xba43003e, 0x8fe5b977, 0x5896687f, 0x41313ac4, 0x8d8d628b, 0x3bb1d027, 0x09f2e7eb, + 0x3405cdb1, 0xefb9d046, 0xd0c1e36b, 0x4d08d85f, 0x90a7fc1e, 0xaa4ff406, 0x11ad1462, 0xc6304d5d, + 0x0a2e66ef, 0x369f96aa, 0xcdbbf44b, 0xa52cc93a, 0x9badb60d, 0x712c39ab, 0x3340755f, 0x3869d773, + 0xbdf27657, 0x37f1f7c8, 0xa1a8bffd, 0x8c405fdf, 0x28383175, 0xccef0122, 0x7ade97ae, 0xd0d5e95e, + 0x4d9d74fe, 0x247b65c7, 0x7c6f1297, 0xba034cf1, 0xf62a6db0, 0x1968318b, 0xf65fa9b2, 0x501ef4ca, + 0xd918f67f, 0x1a8c7c7f, 0xa17744ec, 0x458c9607, 0x0e7ec133, 0xf0a9b0c0, 0x7a1f9184, 0x6c70f8a4, + 0x6debac77, 0x3ef6d316, 0xa9ea8369, 0x389676ee, 0x4987b7e7, 0xe02c6d71, 0x3844654c, 0xd91d92b0, + 0xc567e19f, 0xb6c0bc89, 0x98723c4a, 0x8ffdb347, 0xc6c9659a, 0xc3539a59, 0xa7679332, 0x7950b4ef, + 0x43860898, 0x9d4fe232, 0x94b74f86, 0xae8ac0c0, 0xae7e3aa6, 0xe036aaa8, 0x0a50de91, 0xa10c9748, + 0xc47e95d5, 0x95cfcfa8, 0x4fb5a91c, 0x6d418c14, 0x33e65ea8, 0x7b7edeaf, 0xc004dfee, 0x5fa19f61, + 0xa5b8a754, 0x9803aadb, 0x1616f767, 0x98efc356, 0xd067749b, 0xdab13b2b, 0xdb6ea1d4, 0xf39eff2a, + 0x8492c403, 0x72650f5e, 0x9948a0dc, 0xc9fa08c3, 0x3e551b97, 0xdd65437e, 0x59ff0abd, 0x4a4dd73f, + 0xcb222db0, 0x01f8c2a4, 0x739dc936, 0x522cfdbf, 0x42e4e304, 0x092a15d6, 0x2f38b07c, 0xc7f2d146, + 0x19c893e1, 0x22013e18, 0x67371530, 0x65633b14, 0xf3bccf08, 0xcfad9bb8, 0x9d3c6984, 0x6fa332c6, + 0xb8c4d500, 0x5d93f30f, 0xc7c62515, 0xd5d1628b, 0x56b89d62, 0xb55f451a, 0xbcff0329, 0x51745214, + 0xb91354de, 0xae5d362d, 0x194c9170, 0xc534fb80, 0x3ca0e373, 0xab5e755b, 0x2751e0ef, 0xf565e081, + 0xd7c9793d, 0x14e3a253, 0x0bcd500c, 0x8b6ea3b7, 0x636bd43e, 0xec017976, 0xfea8a027, 0xba8098f8, + 0x2bdbb5c4, 0x82b1d70d, 0xa943f0bf, 0x17097abf, 0x7da54a57, 0x418914d2, 0x17eb856a, 0x06368a3d, + 0xba073018, 0x970eb818, 0x0283bb1b, 0xa4ee8229, 0x0baa4d94, 0x6148681c, 0x62d9b6bf, 0x696b44eb, + 0x9bb83ebc, 0x6edf3245, 0x84761f5f, 0x1e4e0c67, 0x79b4db4c, 0xc788da41, 0xfb490486, 0xd173c1db, + 0x4b81042d, 0x27e3fabb, 0xeef168ab, 0x24d79b58, 0x951225f2, 0xe770c12d, 0xd40d9bdb, 0xb24ebd4c, + 0x7e35072b, 0xfd89c8b4, 0x64220d6b, 0x486de048, 0xb256bcd6, 0x058a6244, 0x7990546b, 0x90e52ad4, + 0xed8a22e8, 0xd1d67440, 0x21ed6c82, 0xabd33e60, 0xf4a4b1ba, 0xc247003e, 0x1f46f01a, 0x5e69b630, + 0x58e7750f, 0x6371dfe2, 0x5a237b12, 0x910e1d5a, 0x5b938b25, 0x5f049199, 0xa3fc107e, 0x03995bcd, + 0x402f0f76, 0x671bfdcb, 0x04d0fc50, 0x5f0f4eb6, 0x5a49b7c2, 0x618309a2, 0xae1cc8a1, 0x4db03b46, + 0x75d96409, 0x58655014, 0xfaf3fa17, 0x606d832b, 0x8d682305, 0xf2ca0b63, 0xa765ecb9, 0x0fcc5e56, + 0x16c6f21a, 0x74f5c010, 0xdc60eea9, 0x1b0326d5, 0xed7947dd, 0xa8397565, 0xe1ed4252, 0xa099eea8, + 0xcfa025f5, 0x6d5a5313, 0xa9cad8aa, 0x4ded84c3, 0x5ccf6f14, 0x3a566cfb, 0x15a1a0af, 0x3ba1e830, + 0xac5f7211, 0x2165ffcd, 0xf9378f94, 0xe9d3f64c, 0xd84f62b9, 0x10c8e92f, 0x95aa404d, 0x0320e465, + 0xd7c19eb3, 0x6a54c456, 0xbae81ca6, 0x87dbab38, 0x8f5eca9e, 0xf31fce4d, 0xdec9a1b6, 0xea797cb4, + 0x2f172ca7, 0x88ea6c6f, 0xfc973493, 0x1f86c9dd, 0x66655cb8, 0xe0bc8d30, 0xcfd4ff1d, 0x7740ad68, + 0xfd6da951, 0x878b05f3, 0xb4d20fba, 0x542f5778, 0x3a8cf32c, 0x266ddab8, 0x5e0da0a6, 0x4eb37b9d, + 0x483feba6, 0x9e9b777d, 0x4cf29be4, 0x80f1be9c, 0xa1ec656b, 0xf85b90b9, 0x5680f4ba, 0x9c78be48, + 0x8e57862c, 0xd87c1b3f, 0x6d8cf6fc, 0x99806c67, 0xb0d306d9, 0x7d968ec1, 0xa26d4f4d, 0x4309a785, + 0x9bcb6306, 0x61851ee9, 0xbe057590, 0x2cf72fc0, 0xe7ae1a52, 0x00206782, 0xbfc9f4b7, 0x559ac924, + 0xdc5b6a4a, 0x3737b0fd, 0x6f45ba12, 0xc0e6a87a, 0x8b10a70b, 0xae9c246d, 0x05508ce0, 0x4a0fd854, + 0x34edf611, 0xe8ba4274, 0x793cdbfa, 0x98067f80, 0x31ee77ce, 0x54ae316f, 0xa57d371b, 0x36ac74e9, + 0x18c45e50, 0x8d97dc78, 0xb37bf4cb, 0xe8f3512b, 0x0398baba, 0x51da3c3b, 0x91ee9872, 0x37785d5b, + 0x21169ba4, 0x971871d3, 0xd328609b, 0x28847be1, 0xee69d685, 0x1510b69f, 0x9e2bbc5f, 0x25a0d7b3, + 0x2a5087fe, 0xc812a458, 0xff8a343c, 0x7675b6be, 0x07c9ff7c, 0x6d8be9b6, 0xebde3909, 0xff1947e7, + 0xcc3aaf87, 0x8e625d43, 0xd983185c, 0xdcc9b774, 0xcad03e6f, 0xa5751266, 0x23555e46, 0xb853d171, + 0x42245fb7, 0x14b5f2e0, 0x7efb2938, 0x23c35358, 0x661849e4, 0x389d348e, 0xd9ee4759, 0xf65bbb63, + 0xa687d040, 0x26cef1fa, 0x145dbbe8, 0x5ea9346f, 0x40c8b546, 0x0af52453, 0xf28f352d, 0x95eed25b, + 0xa68748b2, 0xd8187cc1, 0x6f90a76e, 0xad15a1cf, 0x88d58cff, 0x6869f7d3, 0xd2b0c42d, 0xb8f1a8ad, + 0xac161d7d, 0x5344fecf, 0x970113ce, 0x1d7c0545, 0x6766f4ca, 0x1388d561, 0x24abd81a, 0x93488086, + 0xbde70b6d, 0x5d352fd7, 0x5c293e29, 0xe68e40a6, 0x31291bab, 0xd01c17e6, 0x8258fd48, 0x736c6ec2, + 0xa2482ac5, 0xbdaaf275, 0xe209a79d, 0x7aef8ede, 0x0ada78c0, 0x86a6d4c8, 0xc9d3a3e4, 0x586b52f4, + 0x86c878dc, 0xd74bf89d, 0x21d0d802, 0x0fffdabe, 0xd4529f1f, 0x55320c93, 0xe7a723ea, 0xff9e4124, + 0x4dfa8221, 0xee08f48a, 0x61e8d193, 0x1eaf6e72, 0x3e5febce, 0xfd0f31c7, 0x9c10a92c, 0xd018c6bd, + 0x19493521, 0xc503daa0, 0x24f09482, 0x586f0190, 0x2ffe8e43, 0x775f5f32, 0xa82b1242, 0xd5a2a1a9, + 0x51652afb, 0x429d6a6f, 0xceb0f6a3, 0x45249bcd, 0xd2663998, 0xa5321d7d, 0xe740aaf2, 0x72b2c5ef, + 0x8aa29668, 0x7193fb86, 0xde556f8c, 0xc63e18d7, 0x4ccf9d84, 0xb1053dcd, 0x67b01d3d, 0xdb0ab8ed, + 0xedd8c554, 0xdbc51e80, 0xe542403c, 0x37db96a4, 0xb7e0ee99, 0x9ed32275, 0x696cff72, 0x79e5cbd1, + 0xeefb5e08, 0x96c73065, 0xf1a06b12, 0x0fbbfce1, 0xf335d698, 0x9147d7cd, 0x3418b9c5, 0xfdb2269e, + 0xa04e6c71, 0x383d12b6, 0x6508aed1, 0x5c937c9a, 0x673dc254, 0xe7ef33c0, 0x61f610e8, 0xe00c42ec, + 0x72ee7732, 0x046ff031, 0xa8390a3b, 0xf04bb63b, 0xa4f025ff, 0x480a27cf, 0x314a1bf3, 0x2c3e17b5, + 0x8976a1df, 0xadd52d67, 0x474fc91a, 0x4dcb2098, 0x9cc49616, 0x2f713e94, 0xd8aa2b98, 0x6c05aac8, + 0xb57a168d, 0x49166c34, 0x82b1fbde, 0xcd00e80e, 0x5a285c32, 0xf7812706, 0x8cd6bf92, 0xdd6ecf7c, + 0xffb50855, 0x0b493521, 0x2acb56df, 0x01724fd3, 0xccd153ce, 0x4e70e10c, 0x7ee7cdca, 0x62b2b4fa, + 0x883d93b8, 0x2f583b2f, 0x5f812757, 0x6fd9bb05, 0xf23a6857, 0xb6f75c26, 0xc8e300cb, 0x6db3f31c, + 0xde446127, 0xfd4bccfc, 0xc2d679d6, 0x91a8af5e, 0x0fac1d69, 0xb4b6c4eb, 0xc3b51dbf, 0xbfe5f40c, + 0x2db2d6f8, 0x83b105c5, 0xbc35931d, 0x0795080b, 0x02212070, 0x62c801f5, 0xe81062d9, 0x1e843da5, + 0xbf95c611, 0x706874cb, 0x7ca83956, 0x82f94caa, 0xd9380d5c, 0xd3535665, 0xc8cd3c70, 0xd25bc01f, + 0x19811278, 0x6c949d70, 0x436fcd7d, 0x067a77e4, 0xf6a4bdc9, 0xf35d1435, 0x0659ab02, 0x16f9bfe0, + 0xa928497c, 0xdc74bc7c, 0x509ba34e, 0x0cd13ae8, 0x2e83837c, 0x3ca3e8fe, 0x02948d0b, 0x177334b0, + 0xdc9a602b, 0x90f2240f, 0xd047b3a4, 0xb7f71e24, 0x1ef7b9ad, 0x0c773299, 0xa8a1a1d8, 0x3081b407, + 0x1500ab3f, 0xc2b5403c, 0x4d01e306, 0xeea68614, 0x3e115dca, 0xa1ab41c8, 0xd2b95eff, 0xfd900625, + 0x9713697f, 0xd6e556b9, 0x1021a153, 0xf46a7911, 0x48eb1f01, 0x9582bfd8, 0xd1ac67e2, 0xce6c5c2e, + 0x503b5f66, 0x358a9a74, 0x8eed4088, 0x072643cb, 0x04e8110e, 0x60c6289d, 0x452ae255, 0xe708983c, + 0x81064a90, 0x5b5e91d3, 0x0320915f, 0xfcd128e1, 0x26f12cb9, 0xb5d0207c, 0xc57c51d7, 0x035d4a20, + 0x5fc5ddbe, 0x1a8e99c9, 0x7178ec01, 0xae39264b, 0x012efc41, 0xd3596aa7, 0x9bc872c8, 0xc98cc14a, + 0x6e46bcf5, 0xcc01e332, 0x998b0c23, 0xd5a1d759, 0xf7c093cb, 0xa6aeb795, 0x97123b8f, 0xf46a1d1b, + 0x14e64983, 0xdaad3d18, 0xefa2e52c, 0xddc7e307, 0xba85cd51, 0x576988a4, 0xfb6dd4b7, 0xc3d6cba6, + 0xfda0c732, 0xe61154f8, 0x4c341ff1, 0xf93b4fdb, 0x914c42ad, 0x7d5d6c7b, 0x654ba6ec, 0xbd8d653e, + 0x72c83412, 0xccf52028, 0x34aa0916, 0xcaf0de3f, 0x1e5f8452, 0xaddc5fee, 0xd426ff6e, 0xbf382b9c, + 0x4c120ee6, 0x25f0d159, 0x38c1f4b7, 0x4dd3e988, 0xef950f82, 0xe8ac2616, 0xdf53dd15, 0x28119b06, + 0x57f4ccd7, 0xd5ca990b, 0x0462bfaa, 0xa6ab6849, 0xa8799ad5, 0x2039faa5, 0x4c1e79ba, 0xd4dd0c16, + 0x0b3446ab, 0xee16da11, 0xd93ddbe7, 0xb53c861e, 0x3906427a, 0x736ed96d, 0x9238e895, 0xf54898c9, + 0x16bbde55, 0xf5160196, 0x337a82a0, 0x9bf391c9, 0xb0f7e96a, 0x0f5b0e7a, 0x496a8803, 0x0216d8d8, + 0x6bafd8b3, 0x5aa1cf2f, 0x9019711c, 0xded2249d, 0xa10c682e, 0x5af86676, 0x354a6028, 0xafa23f79, + 0x1b09420e, 0x1566190a, 0x67fe3237, 0x1de7b6ae, 0x305a9cf0, 0x1695ae36, 0x1c63dcbd, 0xe42b88b5, + 0x455589b0, 0xcfe45cc4, 0xa764a724, 0x2a161cba, 0x1e61626c, 0xaec330d3, 0xe3ae06ad, 0x43d8be00, + 0x95a3ddd1, 0x1a8d2eb1, 0x6728c0d8, 0x3f8f9eee, 0xc34af570, 0xd97a2f1f, 0xbada7c1e, 0x79be4f67, + 0x586cb5e7, 0x440f39e7, 0x88b153f0, 0x73775a34, 0x358fe21d, 0xb6567d80, 0x1f5fc1af, 0x01761b36, + 0xd6fc56c1, 0xc0a12532, 0xf8600a8e, 0xac3f74d2, 0xeb3fa1a5, 0x0c65493e, 0xc9e0b3cb, 0xaf32a08e, + 0xa4bf2935, 0x2630ac30, 0x2bca2250, 0xd12ec439, 0x8af756ed, 0x15b3954d, 0xd0ad7d00, 0xf9bf5bcb, + 0xc6dd4eb5, 0x472232ea, 0xb1397f7d, 0x0c5c0ea9, 0x8ab1cfaf, 0x4a349e8a, 0x6c47dd00, 0x5e8a41cf, + 0x90417b98, 0x3b58ede2, 0xc20f45e2, 0xc3ddb07b, 0xd7b5e897, 0x57d3f101, 0x0a741d16, 0x7fc02d39, + 0x382ab09d, 0x7f375673, 0xd74d347b, 0xe62aae1c, 0x48c95e59, 0xcffa7cd2, 0x857b1616, 0x47769dcc, + 0xe2a220bc, 0x6b4073fa, 0xe436c830, 0xebcd2240, 0xa21a5cfe, 0xecb0e23a, 0xa90fbc72, 0xfbcad17a, + 0x3c4ca323, 0x8118d839, 0xfcd2aecc, 0x43bc1b0e, 0xc97f9c8c, 0x9757301f, 0xa6be43b3, 0xd6ebb009, + 0x1a7b31c1, 0x1092b7eb, 0x84ffbf7a, 0x392bb822, 0x3abedf26, 0x4c6d81c2, 0x0489966d, 0x661e365c, + 0x603fe40e, 0xcc6f6eea, 0x3401c347, 0xf43c797d, 0x811ca7db, 0x5a51d086, 0xe9f6a920, 0x1d215bf3, + 0x61d20dff, 0x5f7abb6f, 0x13ccf552, 0xeea20943, 0x426909c2, 0xc1b09cb1, 0x617121e0, 0x57cf50bc, + 0x3eb630c5, 0xfec330cf, 0xb83e5fa2, 0x946e5af8, 0x27b4ae6e, 0x701238a6, 0x63255411, 0xf027b0a4, + 0xc0456493, 0x9b98824d, 0x2cbbfd47, 0xe6253b54, 0xd664740a, 0xf9e4e565, 0x2c3dc951, 0xde6fdccd, + 0x545b040e, 0x9ee7d96e, 0xa5db1539, 0x3daec3fb, 0xa32a09b2, 0x40fca6b4, 0xe067e8ea, 0x78fcf287, + 0xb3c05d12, 0x74da0beb, 0x58675729, 0x8e35317b, 0xffcc9c8e, 0xb47c92d1, 0x8bce0df6, 0x38f1b308, + 0xce9cae15, 0xe039d297, 0xcdd48b20, 0x1d465312, 0x8646a90c, 0x57fde633, 0xac7dfd92, 0x49993a75, + 0xf8fcd84c, 0x70cbaca2, 0x800af985, 0x53ef5484, 0xbc0ae547, 0xcd3175cd, 0x502e0cef, 0xb0a5dba4, + 0xb8c5ef28, 0x5e8d8220, 0x41eba03b, 0x73cf75fc, 0x5a3fdb53, 0x82a5be62, 0x376bce71, 0xa6eace30, + 0x86b8ff8e, 0x90f46266, 0xc0e02249, 0xe00d93d4, 0xc1cdc2b9, 0x3807838c, 0xdefc9961, 0x5a3eb9ef, + 0xe2f714d5, 0xbb76d47e, 0xadb6327b, 0xa19175e0, 0x4570a038, 0x6191b837, 0xb3df3109, 0xcdc8fe23, + 0x58257378, 0xdcd184e9, 0x66b44e40, 0x821f5bff, 0xeae46685, 0x3c8d3e29, 0x0ad85416, 0xf74ed13a, + 0x5e2b8dc0, 0x6900c416, 0x1edf2860, 0x97c52bcf, 0xa04f263b, 0x94938d82, 0x6b5acecf, 0xa5f182b0, + 0x2b9b323d, 0x7aafc8a6, 0x2774d65a, 0x71bc380d, 0xbb3099d5, 0x6d57dd29, 0xaf0df20c, 0x0f4bbc56, + 0x5377c23a, 0xe14270ef, 0x081dd76b, 0x611b6760, 0x676b6879, 0xf638776a, 0x23d89e35, 0x48a4cdd5, + 0xd19a470b, 0xeb9f7d5e, 0xc36c619f, 0xfa0f7352, 0x55e709d6, 0xe6980338, 0x0e805043, 0xc936f37d, + 0x0b79e469, 0xd3241180, 0x3a9d4b8e, 0xca072da0, 0x9c530cef, 0xe29f3499, 0x58becb13, 0xf288c1f5, + 0xa6bc3b5b, 0x3e8cac9d, 0x8a33ea52, 0x2659ad02, 0xa670300d, 0x47d11e54, 0xe913af58, 0x61defe81, + 0xc8b6a311, 0x38c59898, 0x5ac363a3, 0x6ae0ddc7, 0x5dbcd7a2, 0xfa03ad6a, 0x3e4d6365, 0x34ef7e4b, + 0x4a41a13a, 0xb7048c66, 0xb93e3b53, 0x2d526d12, 0x9e375706, 0x3c981701, 0x842b4739, 0x1cf47647, + 0x18997928, 0xb51ec69f, 0xdf9ad2d4, 0x0a946aad, 0xf0ea088a, 0xd629af37, 0xf8d048cf, 0x7380e617, + 0x41765bde, 0x75f97d42, 0x487e2075, 0x96d94bee, 0x59a1edce, 0xe6272faa, 0xfc3ad0f2, 0x5784f39e, + 0x0418dcb7, 0x1e615888, 0x6fa0ab47, 0xa6e2a7b6, 0x6133be42, 0x874448cb, 0x3ba406b6, 0x8627a8b2, + 0x902860a8, 0x0cc62fdd, 0x0e534818, 0x2c19a6f8, 0x52644da1, 0x87767c18, 0x5ee408c6, 0x0ff7e353, + 0x000ff38f, 0x196333db, 0xa03cef63, 0x0ccc8bc5, 0x9847a8f1, 0x78b20a29, 0x13bc7808, 0x9f92739f, + 0x4fe53132, 0x60af5072, 0x6cf500a2, 0xf0fea320, 0xdaa05c3f, 0xff990108, 0x7921ae64, 0xc344f5df, + 0x2a0d75a5, 0x52c8965b, 0xc1fa43e2, 0x6ef86469, 0x5ab3ec1b, 0xfd79d612, 0xde176768, 0xc06a0987, + 0x8cc3f9b7, 0xc7819600, 0xb83ef36e, 0xf355f563, 0x855ac7cb, 0x4d1e6f21, 0xae04cba9, 0x5842785d, + 0x53810f15, 0x1af32601, 0x9a614acf, 0xbab5eb74, 0x4e011266, 0x700c08dd, 0x515693f5, 0xb2c6898b, + 0x316de133, 0xf4572b3f, 0x62316e6a, 0xe0993df8, 0x975eef60, 0xeb3a6fef, 0x431d30ad, 0xd5ca69a0, + 0x48fcd8f5, 0xd19cdfef, 0x0ad051d5, 0x6e2db237, 0xa0c15b94, 0xa3777185, 0xe459bcae, 0xb5f4c78c, + 0x47f3d166, 0xa75bfbd6, 0x33f5927a, 0xf4bd1f75, 0xdac782fb, 0x98212661, 0xfb311ab9, 0x123f5170, + 0xaab61226, 0xcf8c6e6b, 0xb4c40e0f, 0x4e6883c4, 0x6a3b811e, 0xc9bd8112, 0x3cb52c9f, 0x42438c01, + 0x2ab22a0c, 0x48e423dd, 0xfaf0acba, 0x49136193, 0xa7822c3d, 0x217df363, 0x8e937777, 0xf826433e, + 0xc9608097, 0x221d1cba, 0x3257d666, 0x2f20ab2e, 0xaf185582, 0x757654e5, 0x00336a3b, 0x5612cd08, + 0xaa78d2d6, 0xc534c686, 0xdc7564a0, 0xa60e574d, 0xc595e4f8, 0xb69ce904, 0x3f0174f7, 0x5f9bb78a, + 0x9eb491d8, 0x5da86441, 0xfdbcb58c, 0xe705d98d, 0xedc4f774, 0x5ff5d887, 0xaad590aa, 0xd84325a0, + 0x338aebd7, 0x877d02c9, 0x917f86bd, 0x3a5bee96, 0x2dfb0d22, 0xfa331238, 0x5dc845b6, 0xafea9f4e, + 0xb21cc514, 0x3bc34de5, 0x706b02b3, 0x72e64541, 0xfd7f1c22, 0x44294b1f, 0xfca29aff, 0xf6329f03, + 0xcf682b4c, 0xcb4f8b85, 0xad19b0ae, 0x225fc768, 0x590ad0a5, 0x87212f1d, 0xe8ddd7d7, 0xb4a319ab, + 0xea44711d, 0x956ee68b, 0x2b616f13, 0x63d7eb01, 0x7385b848, 0x5ed7f4b0, 0xabfb9eff, 0x9de5add7, + 0x7a724370, 0x908c3aed, 0x891fe0ae, 0x02e240ef, 0x15dda7d2, 0x4f2c22b3, 0xccdb22d5, 0x09dc904d, + 0xba0e0d75, 0xb37c2cfc, 0x9b5d7c3e, 0x7303d875, 0xbf39ba45, 0x852ade06, 0x9f2b5d93, 0x894b9974, + 0x94a45516, 0x89be1613, 0xec8c0ce5, 0x628231e4, 0xa3782043, 0x464a3366, 0x687ac722, 0x1571e803, + 0x75f89f73, 0x114dadbb, 0x9b27f2cb, 0x69d4ee53, 0x5a984555, 0x4d059996, 0xe8afaa8e, 0xf2325e6c, + 0xade95a10, 0x763406ba, 0x14e7cab2, 0x5c576a16, 0x53f0bff5, 0x07f73a76, 0x64b42993, 0x59aca97d, + 0x4497e354, 0x940cd459, 0xad046f49, 0x58d90416, 0x391c1960, 0x09e960fb, 0x7cd44c5c, 0xb33fb661, + 0x8bed08d9, 0x4043a385, 0x01fcff05, 0x420b478c, 0xb783c8fa, 0xfbf44dee, 0x2185a453, 0x065723e5, + 0xc4ffb660, 0x5c7dd8b5, 0xd3f39401, 0x6e47f6b8, 0xc852399f, 0xda14473e, 0xdbfa5a81, 0xde3652c1, + 0x43a9c409, 0xdf334f93, 0x9daa3132, 0x7e54dffe, 0xa8898974, 0x87a067f7, 0xd2ae1ee4, 0x9cc16142, + 0x76c5db86, 0xd960ef46, 0xa85c75dd, 0xfa392873, 0x7517879a, 0xaaffca16, 0x702307cb, 0xf1091881, + 0x70ddaaf3, 0x854e8b22, 0x2891e49a, 0x422399de, 0xa08c1818, 0xc2708c62, 0x9724044a, 0x4284f65e, + 0x4e514b01, 0x0d2b23eb, 0x2d98b15b, 0xf2459096, 0x0c492c52, 0x8f8844cd, 0x3ffbdaf0, 0xcbf43bf9, + 0x227cc031, 0x215ed493, 0xa0d3d0f4, 0xe45c2d5e, 0xa0cf2e95, 0xbd048419, 0x86474776, 0x31585b4c, + 0xe6cd5968, 0xa77689bb, 0x4decbc94, 0xfda65ca1, 0x86eb0061, 0x0f07b75e, 0x678c795f, 0x447de2d2, + 0x4b43c75a, 0xd42677b9, 0x86c73cd4, 0xe203e387, 0x8e6eb654, 0x3e5f2870, 0x3d91b59a, 0x71594d36, + 0x106bd905, 0x3990fd93, 0x99b03e14, 0xc333379f, 0x618ffd94, 0x352cedd5, 0x5bf5a5e9, 0x61961e1c, + 0xfcb1aa9d, 0x8fda6e66, 0x5cb46835, 0x9861797a, 0xbc51fb69, 0xcf0fff90, 0xa16e2e2c, 0x7eabee7d, + 0x45310671, 0xb28c3c03, 0x5ce85368, 0x1d8ea4e4, 0xb7d97180, 0x2656ec8e, 0x6748ee0c, 0xe68a56c6, + 0xdce2cd11, 0xb30274ec, 0x79633d8b, 0x5bf25860, 0x2f5313ca, 0xe1281997, 0xd3eb8033, 0xc972c058, + 0x3125757c, 0x74d28518, 0x1cf5d57c, 0xde938ad5, 0x4d6c0715, 0x4b7e242a, 0xbb27dfbc, 0xce10cd1a, + 0x7ce858c5, 0xc86bf719, 0x86214938, 0xbc1989d2, 0x62c0dbcd, 0x9a6d65b8, 0xf2479f85, 0x1cb5b3c6, + 0xb4cb4a72, 0x779eaf80, 0x3af34f07, 0xcab2ec38, 0x33cb879e, 0x0edbdd75, 0xc1861731, 0xaccf0775, + 0x9bdc5b95, 0x9804c0e5, 0xdc6802aa, 0xbfebf733, 0x4ce091a7, 0xca0dd8b8, 0xb09faf47, 0x5b7be910, + 0xcd716980, 0x31f775e6, 0xb4b18b37, 0xd2139770, 0x46fa5fa0, 0x91354900, 0xf599e6a8, 0xb5ce2817, + 0x08a33962, 0x16fd2876, 0xf925754b, 0xa9639bfe, 0x327abd62, 0x07dd8d04, 0x379dfe7d, 0x560c159a, + 0xe334bcae, 0x45f4bd87, 0x8d558639, 0x27149ac7, 0x9a32c6d2, 0xb4597b30, 0xf2bce222, 0xd96db404, + 0x0d08757d, 0xeee8d6e8, 0xbb1d6697, 0x0f6a83f5, 0xaf91e129, 0xb0aff70f, 0x9131644b, 0x02853e5b, + 0x41444aa7, 0xde3f462a, 0xeae89596, 0xef739281, 0xdadb52ce, 0xcaa343ef, 0xd83ab42c, 0x337dd81f, + 0x3888f967, 0x1b47cce2, 0x6083ffef, 0x7e291695, 0x57fc8a91, 0x9e06eb63, 0xbe91986d, 0x98446079, + 0x03cad1fa, 0x617385ed, 0x1545d959, 0xcb552459, 0xda4470ae, 0x8f823a22, 0x39d54315, 0x805193db, + 0x79a7e527, 0x402f1a5d, 0xf3fb81c8, 0x328d069a, 0x14b02bba, 0x44b48896, 0xaa0f77e2, 0xbaa7137a, + 0x613ac245, 0xfd021885, 0x1864cac6, 0x7792d64a, 0xb946eb4a, 0x81d04131, 0x5f088ecc, 0x6ff0c031, + 0x524340a7, 0x2c08c95f, 0x217ba22e, 0xdd32245b, 0x119033f6, 0x3b58cd63, 0x7805d92b, 0x4bba4c26, + 0x0780b1dc, 0x9c70ab88, 0x0ac0f61f, 0x66a0e422, 0x039447c9, 0x3f72b739, 0xeb78e335, 0x87e88ad1, + 0xd634dbbb, 0xe71f0ae6, 0x6ad1fef5, 0x17bea135, 0x1fa2fc11, 0xe93fe8cc, 0xaf88c28b, 0x82f51d36, + 0x4815fce4, 0x72a82999, 0xc77f86e5, 0xae38b465, 0x2fa43eb8, 0xe6b47e36, 0x533f20d0, 0x57deff4b, + 0x66ea30e5, 0xa9b294e8, 0xf2e9851f, 0xaddbbaed, 0x6b77acc1, 0x83443a6e, 0xa0f2c34e, 0xc4845b8d, + 0x7ca0766b, 0x47d24017, 0x25632dd2, 0xd56766a1, 0x91ece402, 0xcd090f94, 0x0b910e72, 0x659b8bea, + 0x6f338065, 0x5509d88e, 0xa94fee46, 0x0d42cb06, 0xc61636e2, 0xf1e92422, 0xd84c8086, 0x9cacb131, + 0xcdfe5b13, 0x346dd9b0, 0xf1f89fa2, 0x68b968bd, 0xa1e77a26, 0x469438c7, 0xec7c3295, 0x62ce8b9a, + 0x23b7b639, 0xedb7dc1b, 0x9f71c4a9, 0x37e1debc, 0x9c31d97a, 0xe4f4ce41, 0x00908c5b, 0x2e38bfed, + 0xc0075729, 0x38243831, 0x16ea358e, 0x2b7d3c26, 0xccd6b759, 0xe0f1d6cc, 0xb3a2a4fd, 0xe4ba12dd, + 0x989d9569, 0x5ee20a4e, 0x01b63094, 0x4524cce3, 0xf7167328, 0xb7c57193, 0xe04f4c56, 0x6db20378, + 0x99581f56, 0xe084afe7, 0x6ea221fc, 0xae5e8d9c, 0x2f2adae0, 0xe9d0cfd0, 0x4c33806a, 0xc55b31df, + 0x70b5f94e, 0xd43ef164, 0xefc6ece1, 0xf3fbf1e3, 0x04ec1c1a, 0x49d58be8, 0x9bd6280d, 0xc916da3f, + 0x4b221854, 0xe6953a7a, 0x85c54a50, 0x166bb578, 0x405fcdf1, 0xcb2b8b53, 0x48e21cc0, 0xabd61db5, + 0x53534a01, 0xffde1b6f, 0x181415cc, 0x1b892ebe, 0xff698c76, 0x941fd376, 0x322dd1f4, 0x926e6e00, + 0x0368d41f, 0xf1551441, 0x7b4cefea, 0xc156069a, 0xe22d1237, 0xdbc4f03f, 0x8c9827c8, 0x181e27de, + 0x14f3dc40, 0xa3284c3f, 0xa8d6200d, 0xf03eafa7, 0x44e2ad2e, 0x0d887d0f, 0x6fb115af, 0x5fed0381, + 0x53b14667, 0x7557a71f, 0x391abff5, 0x3035a00f, 0x05685054, 0x961022f7, 0x00c9b6ea, 0x06a22d14, + 0x9b2b151a, 0xde029666, 0xbbc9f603, 0xe812044a, 0x9f57d49e, 0xf84c1058, 0x31bbbe8c, 0x4cae56fa, + 0x5a382cd2, 0x7e72b67a, 0xef6bfd78, 0x7e7a8cff, 0xc418abca, 0xc2acab6b, 0x64bf3370, 0x344ddad4, + 0xb3ad7467, 0x7406b226, 0x9b831a27, 0x9505ffaf, 0xce9b2b6b, 0x54645115, 0x3bdf2bba, 0xc0942d94, + 0xe96b4818, 0x038d71a5, 0x6cd98601, 0xe3c85a4b, 0x0567c3a7, 0x4e7a887c, 0x81d87196, 0xb20e7433, + 0xf73cb13d, 0x887ed30c, 0x2734c124, 0xe5ae745b, 0x36a365f8, 0x8c920402, 0x9634c873, 0xe1026c9f, + 0xf01edefe, 0xba38fa1a, 0x2a013059, 0x1488a105, 0xba94b3fb, 0x94bedf65, 0xa2fa645f, 0xe5ee20c5, + 0x216f09ee, 0xf2d4538a, 0xfbd246fa, 0xe79c5ccb, 0x2e768e84, 0x0f583f30, 0x7a0fe7ba, 0x09ef7ffe, + 0x53b34e06, 0x47487e8f, 0x7317d1cb, 0xa3711c1a, 0x1b4dd7d8, 0x26cfebb4, 0xbdebda21, 0xfe99dc31, + 0x185894ba, 0xc0971508, 0x41b4b499, 0xb357886e, 0x533c1df7, 0x4c7b741d, 0x7a463723, 0x31e6c358, + 0x04e31496, 0x308a48ab, 0x7a7a559d, 0x7f3b8fe7, 0xa408898d, 0xa592553e, 0xe165216a, 0x4e356c23, + 0x104f3409, 0xe08a82a9, 0x941cd6b6, 0xf8cb4e84, 0x38735a75, 0x87d4a2ed, 0xe22c0c8c, 0xeed0089e, + 0xe72ac82f, 0x7ea65515, 0xbdb78c21, 0xd0f8f4e3, 0x545120de, 0x9fa8ac02, 0x88861c40, 0x6e920ed6, + 0xf9d169b7, 0x54b16da9, 0xae529cf8, 0x5f78d923, 0x10a2abf6, 0x85479202, 0x58c6fa8b, 0xf91b9a1b, + 0x3a802a8f, 0x8c054137, 0x6447181e, 0x58ffc712, 0x7a6bd70b, 0x2888d695, 0x23beb202, 0x11377fdc, + 0x22be27db, 0x0170eca5, 0xb9185114, 0x4b3e5f1e, 0x0a35b53f, 0x50cda340, 0xb4496937, 0xe5245574, + 0xf36968b5, 0xe8dd451d, 0x9599115d, 0xf3b485b5, 0x2c8fb5d3, 0xa34d3925, 0xa78cfe6d, 0x73eeba7b, + 0xce0cc0ed, 0x5eb8dc8d, 0xd6ff7738, 0x3c665fa0, 0xc94ab79b, 0x923d8b25, 0x0b2e7018, 0xd97b3aea, + 0x657a86ec, 0x6d3b71ac, 0x9b27f4f9, 0xc6b7a360, 0x70d30f51, 0xf3a3e468, 0xee6aad28, 0x8e7e0faf, + 0x51f1f935, 0xef510bd6, 0xf502bb82, 0x7f137f03, 0xba736f09, 0xa8ef4d55, 0xe8617db6, 0xe2a58792, + 0x277781f5, 0x0bc49361, 0x2b3a579c, 0x418974a3, 0xa06dee25, 0xaa37a097, 0x58687dfc, 0xfe4f9c63, + 0xb4cd4339, 0x881a2ffc, 0xaef31dba, 0xae66c485, 0x4dfd69fd, 0x7e92f22a, 0x20b5f86b, 0xb7b53c2e, + 0x9cb62a78, 0xeb418151, 0x1b01ae8a, 0xd14076c7, 0xd0586e1a, 0xf9b1228a, 0x72d6ac99, 0x414a6700, + 0xb0cbfbe7, 0x70233e69, 0xe7d72d68, 0x0e8a8769, 0x1555b41e, 0xb6b519cd, 0xd1ff0bdb, 0x95035e7d, + 0x9c5338ee, 0xb9414165, 0x0d973959, 0x8a251f47, 0xf67dd3ce, 0xd613653a, 0x27baf413, 0xb54ea330, + 0x4e382520, 0x95d40bb5, 0x2058a8d5, 0x9aed9824, 0xca54ef4f, 0x3a7c4f23, 0x56ac42dd, 0x5cd3079c, + 0xa5ca9504, 0xcecbc429, 0x767e93bf, 0x3b20ba6a, 0x7a631246, 0xd4e9ffaa, 0x42a65e2b, 0x750f9020, + 0x705e5436, 0xaf3dc7c7, 0xa090902d, 0x86919c3c, 0xa3dbd68f, 0xc4c79bee, 0x40f777b2, 0x70496cee, + 0xde93b77b, 0xd15ed389, 0xd23a7930, 0x951a31b3, 0x08742591, 0x405c631b, 0x3de8b50b, 0x52dcf7e9, + 0x2ebc286b, 0x2bf8773a, 0x6d5ba473, 0xd91d19d7, 0x0897412c, 0x3622a618, 0x4731f205, 0x3c47d758, + 0xe81d0cde, 0xecaaf728, 0x7a531ca4, 0x2c683c58, 0xb4e76ec3, 0x5eac5b6e, 0xd8535e3f, 0xf895e2bb, + 0x99c2e3dc, 0x9ba2b6d4, 0x7c192d64, 0x033d81aa, 0x8fbfba90, 0x1f0d901f, 0x272b44f0, 0x0e50e4a9, + 0x3dd04ce5, 0x72b85a19, 0x6a470c2f, 0x8064c816, 0x9c39573e, 0xa0a648cf, 0x97bb0802, 0x2975f701, + 0xe619cdfa, 0x55e31864, 0xcf579069, 0x357b5a52, 0x070183ac, 0x38ed48f9, 0xbbe0fa0f, 0x12053dc7, + 0x12997682, 0xd70cc4e9, 0x18cbb9be, 0x2ea26450, 0xbe4d453b, 0xe526b7ab, 0xba651020, 0x97bced76, + 0xc2c421e0, 0x75dda448, 0xf8c6819d, 0xb35608c7, 0xed75e45a, 0x96e38994, 0xb5b81cf6, 0xb72008b1, + 0xa5e40ffd, 0x9aef702c, 0xee1931e9, 0x91fd531c, 0x2483c541, 0x3ba1fe01, 0xc7f07d7b, 0x1f606b05, + 0xed422a23, 0x77c6bb9e, 0x7c85d1be, 0x82327dae, 0x8773dcfe, 0x347b7395, 0x4b3f396c, 0xbaf3fbf5, + 0x8a7b7fbe, 0x066951b2, 0x67a5e1a7, 0x1713d733, 0xf7578411, 0xc64f55d0, 0xeb8bc0ff, 0x9c90bef8, + 0xf288231d, 0xfd1a7840, 0xa3e8d895, 0x520604c3, 0x1de77727, 0xdf31a6e0, 0x3edd806a, 0x7fbb2584, + 0x88e2a3b2, 0xb6bf9556, 0x80b1a179, 0xb561cc05, 0x83a03efb, 0x237cdf05, 0x4a1d505f, 0xecd90193, + 0xfc5bff56, 0x164c4168, 0xcdd74d80, 0x0be7cdab, 0x75728feb, 0x3acb76d7, 0x0a871e0e, 0x5169ea32, + 0x018fbec9, 0xc5b1d222, 0x2bc24cc5, 0xa0a5dec3, 0x17369f31, 0x94332616, 0x8a8ad96d, 0x2a03c520, + 0x6e56db9e, 0x04d410d7, 0x822b6382, 0xe09b0148, 0xae59af26, 0x12d7dbd5, 0xf7ac4809, 0x4b820019, + 0x7ec89733, 0x05677a58, 0x2c091efe, 0xc8df6d36, 0x0373d6d2, 0xb6775506, 0x37816c6c, 0x5ec42af1, + 0x21d238e4, 0xfff473ac, 0x8d33207f, 0x4eba9040, 0xf621044d, 0x231509bb, 0xf847c104, 0x9af7a540, + 0x8e12b6c3, 0x9c28e0c5, 0x4a142902, 0x8660b7a5, 0x97e32680, 0xb215359f, 0x1f840aeb, 0x2d1c9173, + 0x74004404, 0x7e813dac, 0xd47e321e, 0xfdceaa99, 0xe136c65f, 0x18829acd, 0x572667c6, 0x956bdec7, + 0xaa7621e4, 0xf923ef13, 0x3dfb4772, 0x8dd4321f, 0x030d7297, 0x780deb54, 0x01e6da3b, 0x0f950e09, + 0xfb186429, 0x60500934, 0x099fd9df, 0xa4e39a9c, 0xb4ea0aeb, 0xc48b9af6, 0x319e01cd, 0x5fc5d75a, + 0xd77267d4, 0x20296e4d, 0x380a92d7, 0xb136d783, 0x8cf4850e, 0x36ad2059, 0x6b8619f2, 0xadcd0841, + 0xa79890c9, 0xe603fdcb, 0xc9ad43f9, 0xe347742b, 0xac1c1aee, 0x95f2b85e, 0xe7d75031, 0x32161c03, + 0x4fa50545, 0x82456f69, 0x6e9ded96, 0x83dfab5e, 0xea5c8532, 0xf19db209, 0xe644600d, 0xa31ecc79, + 0x4e5885f1, 0xcd4c1b7c, 0x41bc83bf, 0x7b48c2a4, 0x61acc133, 0xf63b0194, 0x99e36843, 0xc6398d37, + 0xab5e4f15, 0x3e22df06, 0x35bd6425, 0xc1a28bdb, 0x6f9b7be6, 0xc7884099, 0x58fa472c, 0x3ae89102, + 0xaf52587c, 0xa32701e7, 0x8d5a80d4, 0x3b7775ca, 0x3eaeef54, 0xeca6f0b6, 0x09bf0555, 0x010a14c2, + 0x7dae7244, 0x35f8b2ca, 0xcdd4f565, 0x08086c8b, 0xb9f3a495, 0x5a379d35, 0xfafbeaf7, 0x1c551174, + 0x933df966, 0x11a6b0ee, 0xceccf2c5, 0xcdc93c87, 0xe36497bb, 0xe09ef8cb, 0x9753f332, 0x3ce449b1, + 0xf5db63d2, 0x6741632c, 0xedc6b9a2, 0xc895a434, 0x7d0e2f6d, 0xa4e7863f, 0x5109e99c, 0x972bf5fc, + 0xd5c10dc0, 0x34b846a9, 0x381ca24b, 0x1ebc697b, 0x74ddac73, 0x44f7539b, 0xdb3fb717, 0x8cfdc1cf, + 0x67b51b74, 0x497f02b6, 0x9447abde, 0x79b3441e, 0xee54db9c, 0xb7111179, 0xe2eb3ecc, 0xbbae28d8, + 0x8fcc067b, 0xfa1ca657, 0x892d497b, 0x05b61ccd, 0xfff79345, 0xaa388cbd, 0x682ecba4, 0x0fa5db04, + 0x1c83d472, 0x490153f8, 0xeecbe760, 0x5c30514a, 0xb4eed176, 0x150c45f2, 0xc05543d1, 0x6f603cac, + 0x95c23309, 0xbc162843, 0x9b5ef89b, 0x83e9c1e6, 0xd8951632, 0xed07ea53, 0xc982dca3, 0x3376508a, + 0xd55a2b9c, 0xfa4a07df, 0xd3d03d1c, 0x4cbfe5fe, 0x01133c34, 0x8b8d9c89, 0xc9b7d28d, 0x9f9d1843, + 0xfdcd6626, 0xecc2955a, 0x7fd31277, 0x048910cd, 0x2bebf82b, 0x10255be0, 0x2282a20a, 0xed9fc123, + 0xf777b484, 0xb7ed4e14, 0x1545fce5, 0x4695a387, 0xd098e386, 0x2fb4f889, 0xa8d9b964, 0x0a7d5725, + 0xd3019238, 0xca372b7a, 0xc5ef4d5d, 0x1c9d97ad, 0xd091809e, 0x626de943, 0x8075e0a5, 0x2c66acf8, + 0x83f4f871, 0x39b753ec, 0xae7b560d, 0xe2fe282f, 0xb89e473b, 0x59c8f4f1, 0x4ed04005, 0x37314526, + 0x2151d593, 0xb1dacc70, 0xe2be0ef9, 0x951f92bc, 0xd510c391, 0xf6a8a11f, 0xee0fcf0e, 0x573ee846, + 0x974adfb8, 0x6a5de39f, 0x4401f700, 0xbc883cb8, 0xedf33bf5, 0xf7dc694a, 0x7a9d40c3, 0x9c10e8d9, + 0xbab68778, 0xdbed76e3, 0xb6e87484, 0x4d76f74f, 0xfe076687, 0x42d2301e, 0x25e45277, 0x43e19961, + 0xdb5d4db4, 0x09d869b7, 0x507cca8e, 0x30e0316e, 0x8a4cc402, 0x45881260, 0xa437ae20, 0xcf2c61d6, + 0x0ec5b110, 0x42f0e1f0, 0xc1b23652, 0x38bdd295, 0x008f6bca, 0xa89498f6, 0x19fff010, 0x60ebee7b, + 0x3b081c5f, 0x345eed80, 0x7fbbc9a4, 0x79e70a3b, 0x94073609, 0xf25ba507, 0x87bc9bb8, 0x032d983b, + 0x9bfcee7d, 0xde5fc3bf, 0xc1fe9af0, 0xd115af2d, 0x5bfe771a, 0xf9d2555e, 0xf64204f8, 0xb5df33af, + 0x76861f31, 0x92d9da4e, 0xf4052dd5, 0x78f0776a, 0xaf764e4f, 0x664b2f49, 0x7bb2aafc, 0x3f69edef, + 0x2bb6b9b5, 0xd881642f, 0xb02eb76c, 0x0e2b88fe, 0xa125fe47, 0x31789fa3, 0x651964a4, 0xb1595587, + 0xf0313770, 0x32ff3d48, 0x91b93dbd, 0x6637f916, 0xb5283ec0, 0x66daa329, 0x723131f1, 0xb986ba91, + 0x1bd6a9d7, 0x16762d3f, 0x57e7ba83, 0xddf18e6e, 0xc00005d7, 0xc21f3f8d, 0x6c58e8a6, 0xc04b6195, + 0x818444b2, 0xfad990d2, 0x664e7a15, 0xb25f2c92, 0xa758c736, 0x96d6c3bb, 0x5fa61f4a, 0x16725778, + 0xe0a03ee4, 0x429a6414, 0x6e8c809e, 0x04d01323, 0x33c7d53c, 0xf7b092f3, 0x588a6245, 0x488e01dc, + 0x73f8b206, 0x94ebd712, 0xe6717277, 0x2f7d1a73, 0x2fdd9a8b, 0xea2333f3, 0xed29442b, 0xb872b976, + 0xb2418d63, 0xec8340ab, 0x8cbffac3, 0x260136f3, 0xa583b520, 0xb0178673, 0x725b225f, 0xcd8c535a, + 0x04915965, 0xdc738cc0, 0xe5dfd76a, 0x52e8281d, 0x5bea1329, 0x400a5a0a, 0xeec70a50, 0x18506ed8, + 0x5d59bf67, 0xb9fed8f8, 0xc15195ac, 0x4a480846, 0xcb7b5d9d, 0xd957e594, 0x3d14fb91, 0x643cddcc, + 0xabaf4e06, 0x08ccf80d, 0x7e3b572c, 0x036052c3, 0x67ae860f, 0xd3175e19, 0x25d2a7e0, 0x9fa66985, + 0x35fcd2e4, 0x075147cb, 0xe22928e1, 0xa88ec785, 0x89756081, 0xb8784069, 0x75555ed0, 0x4b753d1e, + 0xd0527462, 0x78c01f01, 0x125406cc, 0xfc7126f8, 0x7adf095a, 0xefca646d, 0xb2e49d89, 0x1bb9ae0e, + 0x003ccc05, 0x1ac8245a, 0x37f55a9e, 0xdeaae6b5, 0xebd3a524, 0x1c086a73, 0x0d8a2d2f, 0x826551f2, + 0x829611f9, 0x2cc3a342, 0xbeda882b, 0x80b41f35, 0x76130ec4, 0xf820232b, 0x3c84645f, 0x1bb05dd5, + 0x0c927636, 0xed62739a, 0x8663f89c, 0x0ea39711, 0x461840eb, 0xfcf4d472, 0x367ae419, 0xb95cd90a, + 0x39fffd86, 0xf068ed93, 0xa1aa4ff6, 0xebb63809, 0xeb098257, 0x76eb2d7f, 0x91b9b23f, 0x4ebd112c, + 0xa6e2e57a, 0xe95275f4, 0x6f9c65ef, 0x5e9f9fbe, 0xee5977d1, 0xace79651, 0x689b10f5, 0x5088f3ff, + 0x584b32c2, 0x9fbcd9da, 0x6d382108, 0xcf52c115, 0x059c1505, 0x7a17d62d, 0xb3cb92cb, 0x6cbdcc50, + 0xfa23c97e, 0x77ed03e0, 0xc919558b, 0xeb891690, 0xc720e859, 0x1b21439d, 0x432e2d59, 0x20aac528, + 0x5bd860e4, 0x8012f6a9, 0x3118f630, 0xcf62e6ae, 0x32856d4d, 0x6e703184, 0xfad60943, 0x7d801348, + 0x6bd4ef8d, 0x99faf4dc, 0x931fb37f, 0x1b120020, 0x42c8c007, 0xb2a88c0b, 0x77e9d620, 0x223f5f65, + 0x5124ccfc, 0xbf6657f4, 0x7191e7ed, 0xe7459931, 0xb0949ab7, 0x7da0b528, 0x03665c7f, 0x0800d729, + 0xa8e6d622, 0x449b42be, 0xe40c2242, 0xffc1471e, 0x71dbf6f9, 0xbbeff438, 0x72439392, 0xe042921e, + 0xe0545b1a, 0x7e4ec420, 0x8194b326, 0xae06c53e, 0xb51929aa, 0x0a8dc3ab, 0x5534f810, 0x1e5cfe3c, + 0xbeb2d58f, 0xc375cf09, 0xbc9bbe7d, 0x652da572, 0x8902e052, 0xa027b072, 0x3e486ef0, 0xf10c9540, + 0xbcad8227, 0x26f774e8, 0x2c5223e1, 0x1e01993d, 0x5d48e5d2, 0x753b66e9, 0x59896b9f, 0x65f79306, + 0x3c646a20, 0xff9bea2e, 0x539a34dc, 0x88c08c5d, 0x305993f7, 0x29b383d1, 0x80c06052, 0xb9b76b4f, + 0x71afb1a9, 0x5df66f2a, 0x9298292d, 0x4003a77b, 0xa785146e, 0xd3f197f7, 0x312cb15c, 0xdd4aa4dd, + 0x103fc0ff, 0xe8b7a1bd, 0xcfd7053c, 0x532aafe5, 0x6eb1e08f, 0xb0165aae, 0xcb50c178, 0xd5aeec3f, + 0x3fed6554, 0xa3c71dd1, 0x1a09b48b, 0x6ed8d0c1, 0xf1b9a0c1, 0xd5f302bb, 0x60c842db, 0xf4767b5d, + 0x570eaf53, 0xa8ded893, 0xf3dcf58f, 0xa2a7c272, 0x8248fc47, 0x4458d461, 0x038093ab, 0x6bd266f7, + 0x5f712964, 0xb58aec19, 0xcff2f237, 0xd8e58cbf, 0x41b0d404, 0x3d128fdf, 0x2526b580, 0x131e57c6, + 0xba90b579, 0xcaa659e1, 0x8675a775, 0x2e3365c3, 0x84f7d4b4, 0x76c98be9, 0x1f588b20, 0x9ceb8aef, + 0x9a9cc5fe, 0x8418c398, 0x63e7a3ad, 0x032a194f, 0x44c24fdb, 0x399a2cd0, 0xc7ad7b90, 0x214746b5, + 0x834491da, 0x1edc91ca, 0x3341925b, 0x103067f8, 0x2b6abd98, 0x3dc5f8f3, 0x3738052d, 0xef8ca6f8, + 0xd71cd17a, 0x640eecf1, 0x7afe7924, 0xdb685c66, 0xc994fd10, 0xa779dda1, 0xc4920115, 0x41cf8755, + 0xd130bbf6, 0x911783cd, 0x1b7a26f6, 0x875c5553, 0x75885089, 0xa52422f7, 0x5a379f31, 0xd1e3995b, + 0xf76f57c1, 0xa7284429, 0xa3c974c5, 0x2a6134ac, 0xcc603274, 0xa4ac6ef6, 0xcd9b515f, 0xc88a1d54, + 0x27330dea, 0x14ad7ce2, 0xe8db8ad8, 0x4f59981a, 0xbacc2de2, 0x15e5c1d8, 0xe4efc3ce, 0x94f63c70, + 0x2b4e2a2e, 0xd0b91ddb, 0x0c93238e, 0xedd43a34, 0x82c974f9, 0x6902dbe4, 0xbadfb3f8, 0x1cf44909, + 0x3f3b13b2, 0x3e8df25c, 0x5302caa1, 0xaa92b2d4, 0x32dfefca, 0xe34a6585, 0xff4c188b, 0xe229ed79, + 0x07bb63d7, 0x3162e644, 0xed2e9ded, 0x5bc26fd3, 0x68b7743b, 0x5b5b5764, 0x0d864f84, 0x352530fe, + 0x640d2202, 0xbe8c435e, 0x2439bba2, 0x0a143580, 0x71e89c07, 0x55fe5f7f, 0x0527dd60, 0x1d900a24, + 0x5c961d15, 0xd85c0a49, 0xf417b525, 0xd9f7c962, 0x63f4c3bc, 0x92641f9c, 0x32659a0d, 0x7022ed0f, + 0x14701229, 0x7fdb9552, 0x7f34176a, 0x4493c3cb, 0x002b058b, 0x84423caa, 0xc58bfc00, 0xf59835e8, + 0x1647520c, 0xde77864f, 0xf109ec6e, 0xf4821240, 0x8d6d2c1a, 0xa9e90900, 0xa6dc0a05, 0xcbfb2fbe, + 0x6d538a55, 0xd40100df, 0x84723a91, 0x21283234, 0x840e1408, 0x76578c9b, 0xf0259aee, 0x6df5a124, + 0x51bee944, 0x78b56ed6, 0x569570b8, 0x1458274f, 0xbc36a175, 0xdcbec6a5, 0xca3bc5d9, 0x0a355647, + 0x99a0710d, 0x395c39cf, 0xfe2b35ca, 0xefbfea00, 0xf36b178d, 0x92cd8bbf, 0x189a69b4, 0xac2b12cf, + 0xec475795, 0x2005f5bb, 0x18a95a2b, 0x2fbce4c4, 0xfedd9931, 0x6c5a6f97, 0xf0f54784, 0x336a22ee, + 0x7912dcff, 0xd178ca41, 0x94b7b265, 0xf5676893, 0xfc951d9e, 0xbe9292b1, 0x8cc2c09e, 0xc1deb3b7, + 0x843f3134, 0x7172cf3e, 0xf1bd447a, 0xc2549956, 0x3e76fbce, 0x9e16395a, 0x4917a4d7, 0x586bc6ec, + 0xb53476ea, 0x604af522, 0x7e56b073, 0x37205dbd, 0xd32085c5, 0x034a042d, 0x0dc97437, 0xa066ba43, + 0xc2cf6826, 0x75bf32fa, 0x8694fcf4, 0x6dd59b43, 0xfd31b7a6, 0xa991c3a8, 0x1ab9113f, 0x4f5b25f6, + 0x1141bb1b, 0xb125e4cc, 0x657bfb8b, 0x7b1180c5, 0x1dd31577, 0xb11f7fda, 0xbcf96fca, 0x415c5f16, + 0xcba14686, 0xacc7a4a6, 0xc7abf4e9, 0xfeb7e64b, 0x457477f1, 0x9157f654, 0x2ccdbdd4, 0x13cacbc2, + 0xf2e95967, 0x38dd4156, 0x4810e760, 0xe053a39b, 0x7bceed09, 0x83844226, 0x37e53e84, 0x5151ffc4, + 0x331b7f49, 0x5bc52640, 0x9a1c4d85, 0xc1ffe7fb, 0xe21acb16, 0x7770f183, 0xd72cf199, 0x67e97ea1, + 0x7897e425, 0x69fe5223, 0x595f8177, 0xcf0bb40a, 0x58f3494b, 0x213df856, 0xa1c93368, 0xaa5462eb, + 0xeb4ebba1, 0x0745efc9, 0xdc73011c, 0x1aa88be6, 0x76b972f9, 0xaa58af60, 0x7b32b0af, 0xf12e16b7, + 0x3c6ff333, 0x38a6990a, 0x32e46342, 0x176cea65, 0xce5974ce, 0x8f3bbcf0, 0x7fffc522, 0xa663f6c8, + 0x320cdb11, 0x26b35da8, 0xc67f14d5, 0xf41814bf, 0x071646f3, 0x067ebb2a, 0x8715b1fb, 0x6c68683c, + 0x4e378686, 0xd1303851, 0x3a625804, 0x96f8b192, 0x7598c36c, 0x6ed75bcf, 0x1fdab8b8, 0x9d08c243, + 0x05ab9ccb, 0xf41bb850, 0x3f6292fa, 0x743767e7, 0x5d86a136, 0xfa0f329f, 0xc8962dfa, 0xedf36b27, + 0x87434a82, 0xff062374, 0x4ea11bd0, 0x65b20b24, 0x1537d388, 0x0b354a61, 0x65e00b3a, 0x4fcecc74, + 0xbc83eff2, 0x79f10970, 0xa590d898, 0x45713617, 0xff105916, 0x3163cd46, 0x70d260a3, 0xce350d49, + 0x5be24b62, 0x86fee546, 0xe1a2840c, 0xa6bdf229, 0x0b99d48c, 0xa737fe07, 0xa4d8fbe3, 0x0d99eafc, + 0xf1816c5e, 0x694cfa6e, 0x2e18bc79, 0xa1756b05, 0xf44a3671, 0x7277f561, 0xdd9563d2, 0xdfd7a792, + 0x9c3e353e, 0x9f1fdf0e, 0xed27e3c8, 0xf7c4bea4, 0x5833c658, 0x8c5c0477, 0x4c58538e, 0x83efd86b, + 0xf5a5c259, 0xded97091, 0xaf57f823, 0x93b338a8, 0x88a47b6a, 0x7e2bc2b9, 0x5b4160d0, 0xd1164169, + 0xdec4d820, 0x277c66ff, 0x6bef9cac, 0x183132f7, 0x76efe640, 0x16d3a2bf, 0x4decd32a, 0x359b9c23, + 0xbe88bff5, 0xffab0c74, 0xdf2604f6, 0xd7c2720f, 0xb0ed66d0, 0xfa4d83bb, 0x67255a36, 0x78cff557, + 0xd8c7711b, 0xbc9bd87c, 0x6ea7b316, 0x44c46f7b, 0x06458f1e, 0x6017430f, 0x27c9ad17, 0xa2ef37c2, + 0x54fbe006, 0x25396437, 0x61b2690b, 0x833896d1, 0xe5c275e5, 0x88dcb1c9, 0x85aff37f, 0x4a20d176, + 0x843ca992, 0xd9427139, 0xb819e293, 0x7c4abf88, 0x6c29aa5d, 0xe4bf0b8c, 0x035960ad, 0xcdee9407, + 0xd298853b, 0xc18c922e, 0x3136d438, 0x88ce2ac7, 0x458fb039, 0x006809b6, 0x4f9b4e43, 0x6a0089df, + 0x369ba3ea, 0x00f103e5, 0x6052006c, 0xc30e696e, 0x05cc7c95, 0x79a7aaf8, 0x702d39b5, 0x42c97b07, + 0x865807b8, 0x1d6d8513, 0x90a7a604, 0xcd25a928, 0x5de07b82, 0xdd243cd7, 0x76209294, 0x0a31349a, + 0x812ccf6f, 0xb4170011, 0x725c1a50, 0xd0d4a3c8, 0xa0d4b319, 0x84e183f7, 0x70d9a605, 0x4a5fbbdb, + 0x1662c661, 0x3ff23eab, 0x7bea7292, 0x8328ec11, 0xc8d082cd, 0x9db5420b, 0xbef21ef0, 0xbbe9fdca, + 0xa314e6f0, 0x75065ec1, 0x4c19b578, 0xf7fa11d1, 0x0c0e0a5c, 0xa3291548, 0x84d5ed82, 0x86b0800a, + 0x95b19895, 0x96dd4e78, 0x93bf0a1a, 0xf798d3b7, 0x730d7972, 0x1ae9bca8, 0x944b11f1, 0x91f1e41c, + 0x38492e79, 0x91f46eb7, 0x64e81458, 0xeccb90cf, 0x09816459, 0x63f312eb, 0x3f83d3c1, 0x73976771, + 0x9cbcd2c2, 0x3f09b7d5, 0xa12ede87, 0xa9ecec42, 0x2690962b, 0xe013c1f5, 0x5b7a005e, 0x9b39e838, + 0xf7ef00e6, 0xca46f464, 0xff0fa1a3, 0x19ff3424, 0x68b4e0e3, 0x3f1c0519, 0xefd34a87, 0x4da24a70, + 0x21f829ff, 0x8eeb21c3, 0x4b9cbaa0, 0xc06a79d6, 0x1f741cc6, 0x58e659c7, 0xc2b5cc06, 0x93b98606, + 0xcb425eea, 0xf4d22eb4, 0xe8f24025, 0xcb075a80, 0x0057f7fd, 0x19f2b629, 0xee368408, 0xbd37fc27, + 0xc1b2021c, 0xde664642, 0x3a76422b, 0xc451fef3, 0xad6327ff, 0xb7cee3ed, 0xc3368ed1, 0x3176e205, + 0xbfc294c4, 0xec5903e1, 0x923e7580, 0x0f52c1b6, 0x0c8420f5, 0x44374d6e, 0x1d6b1cca, 0x30ecc296, + 0xb9ce08d5, 0x13892af2, 0x63d3b63d, 0x5c793a31, 0x7f048c35, 0x2fdd786f, 0xf99df43d, 0x660fb825, + 0xfc40bd5b, 0x4e8a3dd1, 0x8c8fb2d8, 0x7ed015ef, 0x70256eb4, 0x8c88d1b0, 0x97a3953d, 0x2968a65a, + 0x05285a38, 0x08801b46, 0x795626c1, 0x7a76cc89, 0x748a6243, 0xd4946b7d, 0xf605fe33, 0x4304eb30, + 0xc249bacc, 0xbcb85543, 0xb705fd54, 0x36826cea, 0x26483e41, 0xd4033e4a, 0xc6c8b2bc, 0x384af452, + 0x298f0919, 0x872d913c, 0x5430525d, 0x8d580eb3, 0x8f896611, 0x7685103d, 0x855fa9d2, 0x79d83d46, + 0x55ba9173, 0x576fdea0, 0x18aff469, 0x0d8c0989, 0x4f715ce2, 0xce9ae7cc, 0xf226b88f, 0xab19c309, + 0x3510b504, 0x2373001b, 0xa878ca06, 0x718d9e6d, 0x76bc0db3, 0xf6feb35c, 0xa0d884ac, 0xec7b59bf, + 0x7e5f1c61, 0x440e1d98, 0x78de518f, 0x1c102aee, 0x588e3a68, 0x613a46ef, 0xd94af6c0, 0x95266382, + 0x7e750953, 0xb79d9da3, 0x19c07c6c, 0x8bc3363b, 0xedff5d36, 0xfe64aeca, 0x1cf375f6, 0xa652ac48, + 0x8e21f163, 0x3f8ab46f, 0xd139c4f4, 0x75e18eb1, 0x184dbb8c, 0xf0ee9346, 0x86be2748, 0xf1f5b156, + 0x7a02a164, 0x51a9dd8c, 0xa376d79e, 0x15ee14bd, 0xcd2ea3a7, 0xfc2a0727, 0x0ec0d861, 0x2099d01d, + 0xc4f4e145, 0x5d1351d3, 0x82c762c3, 0xa616d872, 0x4995e8e0, 0xe17276bc, 0x974138c6, 0x9148356a, + 0x9b0fc013, 0x20c31296, 0xf2c43db0, 0x90ea8b61, 0x5b8ee969, 0x79cdbca2, 0x1f43ffca, 0x78f84e87, + 0x286fd9bd, 0xd200d469, 0x2972e7d5, 0x89f7d40e, 0xa0237eec, 0x7a5a281c, 0xd7520236, 0x1c1fd338, + 0x89acdf50, 0x9e3cf2f3, 0x2524f908, 0x134fe489, 0x58707454, 0x33729e33, 0xbedee6c4, 0x3a7991bb, + 0xaca5aad9, 0x540741da, 0xe21a4821, 0x08130d8d, 0xa2a1ca43, 0xabf2bcc7, 0xf23df9ec, 0x9fa7bf58, + 0xb3bb2e25, 0xb604dcd9, 0x3022c1e4, 0xc41f0f04, 0x8d6d8ce3, 0x17019acb, 0xe026089e, 0x2f164801, + 0x8ec58664, 0x8ae4739c, 0xf0d097a3, 0x75576141, 0xe7a830d9, 0x482ca135, 0xde847208, 0x5fad9982, + 0xcbf5539c, 0x8c0fa5be, 0x6b086112, 0xcb0902bd, 0xeee59e43, 0xbb661759, 0xe6f08066, 0x069e512a, + 0x098ba5d7, 0x6178b9d7, 0x86529a7f, 0x3c69ba95, 0xa37986d3, 0x7641abee, 0x981d1ae4, 0x5fd58d80, + 0xdfb989ce, 0x053fe595, 0x4740fa73, 0xdf385c88, 0x062d6dc5, 0xea3cdf87, 0x8ac5dc85, 0x678fbeb9, + 0xfeb6931a, 0x0f1560b6, 0x945b41a4, 0x4020472d, 0xa519ad6a, 0x6720f811, 0x56808b5f, 0xc2ac3d53, + 0x46371601, 0x09b57749, 0xa09ede38, 0x9f9e64ac, 0x55b42659, 0x1972fef5, 0x1fc857b6, 0xff5d0f6a, + 0x2ad6576f, 0xc6975519, 0x36be16e6, 0xc053f378, 0x95fdc738, 0x6397747f, 0xb701df85, 0xb9310a7a, + 0x07571bd2, 0x9c3e31ae, 0x1daa3fa3, 0xc5d0ce02, 0x510f31ab, 0x18585e52, 0xcaa5c2d5, 0x126b2458, + 0x5f97b011, 0x5af120c5, 0xcfa480b0, 0xfb5ce08e, 0x76b3a78f, 0xd17f1c84, 0x9ba8a026, 0x46f6f232, + 0xbb30c102, 0x1bbc4ab1, 0x38d1fb53, 0xfbce0501, 0xb3910716, 0x343afd40, 0xc8781972, 0xa37e1868, + 0x8d443898, 0x13bf14b6, 0x21c50abd, 0x1e6fdd34, 0xb89ca415, 0xe8b002e5, 0xd94d7f23, 0xbd9ad4bc, + 0x0e829fbe, 0xc96b1589, 0xe358ec01, 0x9aa03f40, 0xba7b9481, 0xa8cafcab, 0x89d36271, 0xfd8d2320, + 0x53a010be, 0x04f1693e, 0xebb9e750, 0xa0e9089b, 0x3974bc10, 0xe8c6d3e6, 0x5aff8282, 0xca1d0395, + 0xb2d05e36, 0x3cbfc36f, 0xcc8dff11, 0xa0954b41, 0x808bec08, 0xa8a7320d, 0x8856d639, 0x89725fcd, + 0xc357651d, 0x80558b7c, 0xdb341a68, 0x3c9c24b2, 0x9a00877d, 0x052f382b, 0x25c68f11, 0x555ed9d4, + 0x76c821dc, 0x590701b2, 0xde59dbc9, 0xdd77c385, 0xbdda7472, 0x4a370041, 0x1229a605, 0x71dfaaae, + 0xac28605d, 0x28052df9, 0x3d1e299d, 0x11098665, 0x06b74fa1, 0x79c0961a, 0x1ca41e8e, 0xf8dcffdc, + 0x85cd584a, 0x3a4c0ae6, 0x379ea546, 0xf81b9d4f, 0xfb38cafe, 0x418bfb30, 0xc344aac7, 0x91610785, + 0x81080d1d, 0xb1546fef, 0xf86f2f7f, 0x27aac815, 0x85d95908, 0xf9f78452, 0x8f661cae, 0x33ad5530, + 0x2b47de87, 0x90f3fd31, 0x5a66a1d2, 0x6b19108a, 0x60241b73, 0x34efb87c, 0x78121c75, 0x41cec6d4, + 0x3c236eae, 0x8af7b8c9, 0x17dabecb, 0x601eadc9, 0x7b88f609, 0x6e1c45b0, 0x03c2e19e, 0xa2e9f072, + 0xa6ad8424, 0x96c63b68, 0xa527c8d4, 0x0d6c7a91, 0xc35bc1dc, 0x23c6006b, 0xb3042afe, 0xb61a2627, + 0xea93984c, 0xdfa98b3a, 0x2c941a3b, 0x63bf8098, 0x21323288, 0xf956e9e8, 0xfa694c1f, 0xc96cf9e4, + 0xc7407670, 0x641ee22e, 0xf5c89a9a, 0xba743c83, 0x3ce5dff4, 0xa723cb09, 0x24a74ed5, 0x76a203d5, + 0xd75616f7, 0x02703a2c, 0x54ce4a72, 0x349a90b2, 0x26211921, 0x45696a53, 0x5bc23a09, 0x23020879, + 0x860ac18b, 0x5c294a74, 0x5bc19c27, 0x9a38c8aa, 0x6dcbaa59, 0x916dbca5, 0xe9f564d3, 0xc7453874, + 0xbb5198b4, 0x82ddb1fe, 0x176f5d7b, 0x19635551, 0xf8f290e9, 0x804baa61, 0x21b490ff, 0x0e4b5896, + 0xe244659b, 0x1de0e85e, 0xfc716c59, 0xc13270e4, 0xd82d86a6, 0x85f21029, 0x346e5b45, 0x7217b027, + 0xbd67ee77, 0x0ed3f7c4, 0x426ac82b, 0x71eb6acd, 0xee364394, 0x95a277f8, 0xfedf2de7, 0x73fedb21, + 0x51f8c402, 0xa23bcc34, 0xa6d23cc6, 0x24273040, 0xaa4a161e, 0x1dadd6f0, 0x6c6a9895, 0xb0a47870, + 0x69658818, 0x9ee98a0d, 0x9182516a, 0x2db7f2b4, 0x2223c5db, 0xe5647acf, 0xe5b56ebf, 0xf7c56d03, + 0x7703c90e, 0xd4227b13, 0xd0ec4fd5, 0x7eb3faf6, 0x9f00f7d8, 0x2b6f3463, 0xe3dd23a5, 0x6206285b, + 0x9a2203b5, 0x5c0de2aa, 0x3d39d380, 0x7f430d4c, 0xab45495f, 0x8df49a4f, 0x64fc40c4, 0x5fffb450, + 0x27f69799, 0xbd01b628, 0x15a21a0a, 0xe97e87df, 0xddc594ec, 0xded75468, 0x200daeb3, 0x42bcc821, + 0xfe1ec843, 0xe83847b9, 0x1a972964, 0x5a2cbf00, 0x0a6bb43b, 0x1611ca06, 0x7ba1c793, 0xbd060d31, + 0xe7477d1b, 0xd6107dcf, 0x3d0ef773, 0xdd1c5dcd, 0xe04ff540, 0x0287fb88, 0x8062496f, 0x33167d66, + 0x0cf8a604, 0xb15efe7b, 0xf205e844, 0x6a19dd8e, 0x5230ff47, 0x8ca4fab7, 0xba017016, 0xbacdf86c, + 0x81c36174, 0x06f75ef7, 0xdb55fe9d, 0xe6f57af7, 0x55f4f0ed, 0xaccb4b07, 0x10f5695c, 0x2133e574, + 0x99343fcf, 0x602daeb5, 0xe8fc9e7c, 0x8598d416, 0x902005d3, 0xb94b4d60, 0xe578e659, 0xff7cac1d, + 0x465de97d, 0x18a23dea, 0xfe923621, 0x9e99af75, 0x27b75ce4, 0x7f181a3e, 0x9ab81240, 0xa6f87bf5, + 0x12bb798a, 0x9f2fead5, 0x88e8babd, 0x08456524, 0xaf4e16a6, 0xa6f1babc, 0x119da8c1, 0xae249f1f, + 0x96178f6a, 0x9a686299, 0xe9435503, 0x427dc5a1, 0xa229e3f6, 0x13ca3d00, 0x22de24d4, 0xb855942b, + 0x422be090, 0x65f01db8, 0x510d2724, 0xe34c43bf, 0x43606a7a, 0x123e7cdc, 0x98cdbd1a, 0x6036d935, + 0x8fc37f64, 0x67704200, 0x208af7f9, 0xdd960075, 0x9ce57d03, 0x0e469fb5, 0xf54cb351, 0x5985bbe1, + 0x4b2badfb, 0xf471e2f5, 0xd1f6dea0, 0x136ac650, 0x16129882, 0xe7586670, 0x4402b5f4, 0xe0da3f49, + 0x03c5bf5d, 0xb1a1c70c, 0x30e8c877, 0xd3888064, 0x64b362c5, 0x8cbb0e47, 0x388cbe5b, 0xbafc9edf, + 0x9f79737e, 0xf3a25362, 0x4629eec9, 0xc19c160d, 0x58d221c5, 0x5889d5ac, 0xddb410d6, 0x672478a0, + 0x792beba7, 0x6808b398, 0x15d600ec, 0xcd04bd29, 0x81dfc5c5, 0x80f3a923, 0xdbe7a0f2, 0x7d6ff346, + 0x9dbd4f82, 0xfa0ea0ed, 0x66efa39e, 0xddabb491, 0x0f0aa96c, 0xacef36a3, 0xf1fcb951, 0x26d72e14, + 0xc6b3be9c, 0x07e7a03a, 0x5ebc1b7e, 0xc471e019, 0x6858fc78, 0x1570112a, 0x53b138fd, 0x908a089e, + 0x40f7d2ce, 0xb9415274, 0xc273590b, 0xa0f228fc, 0xdabd320a, 0x1f35b083, 0xc5e13b01, 0x17928de1, + 0x20f7d091, 0xb2063cd7, 0x556efcd1, 0x4599bbd1, 0x36ed0a28, 0xa2d0d02a, 0xa96a5f5b, 0x37d0cbf8, + 0xb95cf5b7, 0xc8549271, 0x0f01c8fa, 0x5eca94e1, 0xd353216c, 0xde350770, 0x0564c15b, 0x0ab91b2c, + 0x55316d02, 0xd45df196, 0xbbfb11cc, 0xc9e9e1b5, 0x556b31e5, 0xc512b382, 0xbc46595b, 0x23084fe9, + 0xd1bd9a9f, 0x218f1bf5, 0xf109e69a, 0xe2dfd8da, 0x34ae84a0, 0xe28c2522, 0x105df1cf, 0x49fd2e9f, + 0x24220855, 0xb1ae9583, 0xc998e2fb, 0x13478198, 0xe102d8d0, 0x4bb30f01, 0x8d76f322, 0x7cc76299, + 0xbeff1da0, 0x6790d1df, 0x5d872366, 0xeb4f700f, 0xfb09b5aa, 0x5ee07776, 0x8bc46894, 0x45ff1326, + 0x91135dc1, 0x2a4cbb79, 0xbfd2917b, 0x86da6dc1, 0xa4c80eb5, 0xd0233ba2, 0xb1bfb720, 0x264a2692, + 0x9d575d7e, 0x116cead9, 0xb1bacfa0, 0xd63d6bc1, 0x3df1f9de, 0x7131dc90, 0x795bae41, 0xb1a81888, + 0xcec23dda, 0xf5aa4a9e, 0x3bd3afbb, 0x655df862, 0x0631b918, 0x1928cb78, 0x214d0e86, 0xaeb88ba8, + 0xe0bd96b6, 0x5232f37a, 0x3850e308, 0xee933a28, 0x1d0b307e, 0x8d2c8c1a, 0x2ca52036, 0xea8f3034, + 0x49669fbc, 0xd00b0b26, 0x4a6088dd, 0x3e8db9a9, 0xf0092ccf, 0x2a82b132, 0x55545b36, 0xce93e2e7, + 0xb98d01d7, 0xba940f27, 0xa937615b, 0x7ff535fe, 0x5d74e58f, 0x30b76a74, 0x3f2c51ca, 0x9129ab91, + 0x570c3783, 0x67b154a1, 0x374b371e, 0xcdb3263a, 0x20e27295, 0x3d184a2f, 0x9a6405bb, 0xc3114ddb, + 0x53c5e25d, 0xee555dc5, 0xd7051b37, 0xfaf9077e, 0xffbd4a41, 0xdbf232c2, 0xd38a34fb, 0xa38c935a, + 0xd5919c0c, 0xb44df404, 0x86d21a14, 0x9ad765c7, 0xd991488b, 0x82b993c4, 0x9431a976, 0x0a60a0b9, + 0x130118d4, 0xfcc92035, 0x772f40e9, 0x00ef88fe, 0x1301edc3, 0x26209557, 0xd0237f3c, 0x6467dcc7, + 0xf1aa298e, 0xb21c9506, 0xeb2b6865, 0xd8a36280, 0x5174c04d, 0x171c6c47, 0x078e29f8, 0x382501ed, + 0xe206c284, 0xcd9c1dc4, 0xb6c146e8, 0x29853dc8, 0x836a03b4, 0x902319af, 0x70ea6c91, 0xe671cf3c, + 0xa198a3bf, 0xb54daa79, 0xc94626be, 0x8f1829f6, 0xbd52e0b4, 0x953e0694, 0x0d2307ba, 0x975727fd, + 0x9263d1bf, 0x5a0f7381, 0xa865a0e7, 0x2288a99e, 0x52b6d963, 0xca6cf18e, 0x78abeb04, 0x0995ade6, + 0xd71fd616, 0x947dc959, 0x1ef9344d, 0xe4dff48e, 0xeae93239, 0x157a0a0f, 0x0a481144, 0xc11b1f36, + 0x495447fc, 0xdcc4324b, 0xc135d40e, 0x0beafb1a, 0x9e32c904, 0xcb879574, 0x4489df22, 0xd4f17632, + 0xb8e268b2, 0xd672ca77, 0x4750607e, 0xa29b7ee4, 0xf1718792, 0x56e16327, 0xae999ac5, 0x4638b01b, + 0x67a23599, 0x878b36a9, 0x9ba25081, 0x3535275f, 0x7416c25e, 0x4fdeb109, 0x4211ce78, 0x9ea20419, + 0x3af74031, 0x851c0df1, 0x9dfa1140, 0xf9701643, 0xd29010f6, 0x14865745, 0x775618ad, 0x41d6efc6, + 0xd281d623, 0x4b57e8cd, 0x8d05afc9, 0x7e033c6a, 0x001101a4, 0xa4ef3e2e, 0x24e4a684, 0x9d504e9d, + 0x83a4f7e2, 0x6693791c, 0xe34b3d4e, 0x6fff78f8, 0x9926db42, 0xfa85f38e, 0xee8577a4, 0x812c589d, + 0x7df0f904, 0xf568c7ce, 0x8c81c44a, 0xdd7f410f, 0xb7a9aed4, 0x6d56fc97, 0x66bbae67, 0x291890fb, + 0xbe563323, 0xdac62512, 0xb7872a52, 0xd79921a1, 0xbb0b7c19, 0x277534bb, 0x3a209fb9, 0xe18e2001, + 0x911dfe81, 0xebbc8c15, 0xbf3fbd8a, 0x053b7b3b, 0x68a2e03e, 0xf0d56cf6, 0xe760dea2, 0xcae206ac, + 0x08969d88, 0xb867b76e, 0x1c002cdb, 0xa8b6b392, 0xb3cfb908, 0x9e6b1889, 0xfee50bff, 0x9877dfd4, + 0x48e29b57, 0xfd78abb8, 0x018dbfc9, 0xf849f198, 0x1330709b, 0x3af89780, 0x7222de91, 0x7ab5d580, + 0x719ed745, 0x0972e1e9, 0x26d261a3, 0x62062d76, 0x358a0d59, 0x00b5638c, 0xf7a554af, 0x9698d7a9, + 0x48536c08, 0x2973a79a, 0x7259375b, 0xbe4e27d2, 0xba8cebbf, 0x14e7f8df, 0xfaad256c, 0xbb8ffada, + 0xa806e1c4, 0x778e7541, 0x42a798e9, 0x90401d7a, 0xcf161c9f, 0x1dd671d8, 0x5bd0d4f5, 0x8ba0817f, + 0x61378b85, 0x1866fc6b, 0xc3c1218a, 0x3f76f795, 0xb90ed869, 0x278c619f, 0x9187f6e9, 0x90d90bf9, + 0xdd3f480e, 0xcb39a001, 0x84991d50, 0xd2c0e5b9, 0xd0dcedf2, 0xa6697eba, 0xa5a13b89, 0xb6a51f7a, + 0xb3dcd631, 0xe3bf922c, 0x0c66732f, 0xdd866a08, 0xe7828afb, 0xe1f1b7f0, 0x7cd87397, 0xf71c4a07, + 0xe206dc1a, 0xe44a0202, 0x153e8c50, 0xe4f22ee4, 0x4ee5d0bd, 0x5be44078, 0xa0dfaede, 0xec8ca57f, + 0x6c25f9eb, 0x8c2a3842, 0x6cd125fe, 0xdd1d6a4b, 0x09fe9cc8, 0x1883ede4, 0xafa553a0, 0x365d8687, + 0x8898e525, 0x350d3297, 0xbc8ed844, 0xe2f38f92, 0x800e7a7a, 0xc4281948, 0x4afbcfaa, 0x72df7108, + 0xf7853828, 0xbcfcf9c7, 0xa09bba19, 0x20441896, 0x4080011a, 0x1acdb17e, 0xff9d6b70, 0xecec2bd1, + 0x54f13f6d, 0x4bbeb185, 0xfbfaca80, 0x28344051, 0x4ccecb4b, 0xc116e0ae, 0x63ec5e7a, 0xb32bc5d8, + 0xab500b99, 0xe0ae6ffc, 0x0584f70d, 0x334be93b, 0xbc8e0966, 0x0aeb1e98, 0x9ab68a24, 0x52528c9d, + 0xc6aaf491, 0x51b86cee, 0xa0bb4697, 0x5d1490ce, 0x1eadb87d, 0x5057f61c, 0x5a8aef7c, 0xebe05805, + 0xae4b5c10, 0x73ed290f, 0xf129aa16, 0xb0848637, 0x57bb5781, 0x046dfcff, 0x1bf831f5, 0x39fe9588, + 0x1b326435, 0xffaf6c97, 0x64ac67bc, 0x18fae905, 0x811fcabb, 0xcf3d69e5, 0xf544134f, 0xe7084fbf, + 0xadba93c1, 0x6579492e, 0xddb568c7, 0xf825c9e8, 0x8e4980e5, 0x81420f9a, 0xea0fd51c, 0x0ccf16ac, + 0x4c634862, 0x023efd53, 0xdbf32e67, 0x6a436d57, 0x747b6dd8, 0x0c9fecb7, 0xdc1b537b, 0x60a29919, + 0x1b0a023e, 0xd0b748e2, 0xd911cc9b, 0xf7bbb640, 0x856f1fd0, 0xdcbf8ced, 0x10488f15, 0xcf554094, + 0x1c62d872, 0x8bde4021, 0xdb8245e4, 0xe71a4619, 0x6bade24e, 0x17738eca, 0x7c4b9f21, 0x0b31e262, + 0xc40d7ff7, 0x279d457e, 0x2c525bcd, 0x235db53f, 0xc021913b, 0xc951a2b2, 0xa516a538, 0x19773405, + 0x1a49803d, 0xccbd357a, 0x7a54231b, 0x29fa58c5, 0x8b66254e, 0xb70ed0a2, 0x9e9ce6e7, 0xae336fac, + 0xea5d1ad9, 0x30564502, 0x03a916ce, 0x82dfd9c8, 0x20a8b355, 0x5301f4d8, 0xbc8d04f9, 0xef9fe645, + 0x8945d68c, 0x226a9b06, 0x07b1b45c, 0x036bba24, 0x6ae166ae, 0x1829c800, 0x2c7e6d8f, 0x91ea87a0, + 0x8bfad3bf, 0xb68053f2, 0xc865be3f, 0x00b84b7f, 0xc05c76c4, 0x10380b70, 0x5c0684cc, 0x8bbab50f, + 0xe0cf84a9, 0x50548855, 0x2260f0b0, 0xe3674296, 0x2603b026, 0xdd1add97, 0x9835891a, 0x74584a98, + 0x5434a421, 0x15c61ee1, 0x4725407b, 0x30e2acd3, 0xd97545ea, 0x578a6fa9, 0xbb6bb1a9, 0x5968ad07, + 0x9a41618b, 0x61e6fb0b, 0xeba2afb6, 0x3ac0483c, 0x3bd783a6, 0xe07e60ba, 0xd9aba84a, 0x0f520d76, + 0x04319e4c, 0xd8be9133, 0xe0810684, 0x74cb9e3d, 0xbeeccd95, 0x8a8312ae, 0x6a110601, 0xaf58de0f, + 0x82a6b178, 0x0fc0fd2b, 0xb68b8e86, 0x9e9d3347, 0x95f29c05, 0x03aad8b0, 0x6a524eed, 0xa2204dc5, + 0xa97cf12e, 0x39d1f0fe, 0x98b92e5e, 0x84e34f92, 0x3fb91a2d, 0x1adf5a44, 0x6d543a16, 0xea9a5398, + 0xf4c7f502, 0x91c05d90, 0xfd7de6cc, 0x769c4037, 0x66f63f30, 0xd02235cf, 0x7e75fcca, 0x2b89278d, + 0xb8d08d26, 0xef43fd7d, 0xdc0862a5, 0x8a974486, 0xede84850, 0xd61b99a6, 0xca52795d, 0xecae331d, + 0x569c6f36, 0x3bf57ec7, 0x67604650, 0x3c0c7354, 0xe85030a1, 0xae9d4eff, 0xf16ef0a6, 0xc8cc84c4, + 0x82e8518e, 0x5abdde2a, 0x0032c712, 0xe6ec7900, 0x9c98ef40, 0x9bf9609a, 0x9f50e1fc, 0xd8c6576c, + 0x9fa95530, 0x8554a844, 0xb991efa7, 0xcc63966b, 0x74ed277b, 0xcf98e696, 0xcb76c08c, 0xac16cd22, + 0xd6482d0a, 0xbc7ebd4e, 0x8b7c6395, 0x69b25197, 0xc0635024, 0x69bab473, 0x671c2338, 0xc1be3d87, + 0x16183154, 0xda2f6702, 0x7b4602bc, 0xdd7b2331, 0xf5117680, 0x68151ad6, 0x5df6e77c, 0xd7788951, + 0x36ba82c8, 0xc4d721e6, 0xf6c18d52, 0xa0f508bb, 0xd2e346cb, 0x098463c8, 0x467d22b2, 0x6d687d60, + 0x503256ba, 0x37501af5, 0x33a558fc, 0xad34e5d1, 0x9b8b14ab, 0x06d3b1de, 0x8e2f6f18, 0x397b3552, + 0xdc1a95ed, 0x06b6d586, 0xb1232366, 0x84d14cff, 0x6a5465df, 0x50881116, 0xfc357821, 0x26c6d7e8, + 0x6855a490, 0x1e13ce17, 0xcbbf0eee, 0xaa181c1f, 0xbf97a138, 0x892d3509, 0x2efa663f, 0x42ff1333, + 0x42177603, 0x801ae961, 0xf6d520fe, 0x0f373f54, 0x7e619985, 0x7ba24b6c, 0xba8f2f1b, 0x65b714c6, + 0xc003d5c1, 0x20aa80b2, 0xfc2a5168, 0xaabdf331, 0x578ee05d, 0x570ac5ec, 0x20444138, 0x98d6d35f, + 0xb50a84a7, 0x591358e4, 0xd10bccee, 0x53f708b5, 0x4f860cea, 0x84dff486, 0xd186b7f1, 0x35730511, + 0x2d312e0b, 0x0bf1dca6, 0x79ce48cd, 0x7a8ee4a7, 0x248b8aa6, 0x4bc8be95, 0x91431ed1, 0x4e8642de, + 0xc240a18d, 0x3f125ea8, 0xf9b16e2e, 0xb0d3457e, 0x28b8222c, 0xfa9df45d, 0xf50e0c77, 0xe2774daf, + 0x8a3de102, 0x9c57d0aa, 0xe72580f2, 0xb8a11d11, 0x16b190d1, 0x41ce37f0, 0xdd6d53a2, 0xaf8ba10f, + 0x32bfe8fe, 0xd2e9e3db, 0xd71479ba, 0x9a748657, 0x7f7a7db6, 0x8cda8e72, 0x7ab110a8, 0x79970d49, + 0x78c8a681, 0x12f95436, 0xb2f114fd, 0x2e882a9c, 0x23c5218c, 0xdf87c551, 0xa5cf7748, 0x8e4aa735, + 0x45b0b520, 0x911e694f, 0x19d87430, 0x0a4a14e7, 0xf679e5b9, 0xfe70c486, 0x8c66e057, 0x16068953, + 0x59c14fff, 0x2138a621, 0x7c154e92, 0xe268e941, 0x13e4aafd, 0x0d2a55dd, 0x87135cca, 0x90e02f08, + 0xb37f23e4, 0x83e47304, 0x1b7a54eb, 0x67da8700, 0x8c94bb85, 0x800d650c, 0x79b60bfa, 0xf999a97f, + 0xc056422b, 0x61f286bb, 0x12ca5197, 0x7367a88d, 0xe0f85d6d, 0xb4a4fa62, 0xd97cd257, 0xb315b990, + 0x405270ae, 0x3fd8db9f, 0x76b62090, 0xcdb526d8, 0x4c085944, 0x6615f24d, 0x40ada42a, 0xddddb571, + 0xff134628, 0x820788d6, 0x97e126a5, 0x411b3989, 0xf20d5837, 0xf807216b, 0x458e3b24, 0x9bff0796, + 0x81072b19, 0x753b3816, 0x0b353262, 0x2b18799f, 0x9e8af7c1, 0xad42c63a, 0xeb0800b9, 0xaf357043, + 0x81217ba8, 0x58884e7f, 0x5618ef2b, 0x71255922, 0x20fc3ffb, 0xf523b36b, 0x57ef749c, 0x865cae20, + 0xdcb52164, 0xaabbed0a, 0xeb8bb480, 0x2ca3a6ae, 0x1c175767, 0x9f86168a, 0x6992d208, 0x7e5500eb, + 0xca572054, 0x7d34a448, 0xcc88b7c2, 0xa9bf3e43, 0xe7e376ff, 0x9ccfd793, 0x773ff812, 0x0254c0a9, + 0xb208c0e0, 0x7bb59992, 0xaa05c43a, 0xe85979d0, 0xa50a653f, 0x2111a662, 0xe61f6dcd, 0x5ba37302, + 0x095031f3, 0xe3fda0ac, 0x0565fc1c, 0xac55197d, 0x6734deb5, 0x5e6c0026, 0x318734c1, 0xedb5b1c5, + 0x26c98e8d, 0xb0348375, 0x679c402a, 0xe21d3112, 0x8b7e757f, 0xe80a5125, 0xb5401514, 0x45437372, + 0xbd6c8e70, 0x8580871c, 0xdad28010, 0xf840cd13, 0xc7dac21d, 0x04fffa60, 0x6fc14b65, 0xb95bba82, + 0xd96b340b, 0xa7a80cd5, 0x55d6483a, 0x43f35aef, 0x3d3fd25b, 0xe93b0878, 0x7f7742b2, 0xf03d670a, + 0x93a74436, 0x31820138, 0x250563e3, 0xcba650d8, 0x09d21c6b, 0xf160abcc, 0x8197d31a, 0x9b22ed6d, + 0x561c8765, 0x7536d7f0, 0x01d5ddb9, 0x4648c169, 0xb00f89e4, 0xcd5f08a6, 0x2dcbecd2, 0x9bb86768, + 0x04ae371d, 0x32a449fe, 0xfb5f50ad, 0x38729d43, 0x8f9c0317, 0x80aa1b34, 0x5ba0d4fa, 0x435f94e2, + 0x3999998c, 0xfd358dce, 0xea470ccf, 0x521ea12f, 0x8c154b7d, 0x0d9a18a6, 0xd6e0ca67, 0x162cff3d, + 0x962aff25, 0x245cb740, 0xa2534a03, 0xf81a6032, 0xf356aaad, 0x62f27ef2, 0x9c47bd5d, 0xe63ca200, + 0x5a011a99, 0x43d2dc14, 0x01cf89df, 0x6150b8d1, 0x1f79c35f, 0x84503dec, 0x6e7c6a3c, 0xff770a53, + 0xca7350bf, 0xd5f651be, 0xb011b380, 0x688e437c, 0x8a9e867b, 0x781bdc1a, 0xfc732d6a, 0x73d2ca1e, + 0xed54a969, 0x0d31ca66, 0x32de06a3, 0x60c79a4e, 0x4e2f15cd, 0x1ce78ab0, 0xec91c3f1, 0xed6bddec, + 0x548be03f, 0x8e1d2ba5, 0x4a87b792, 0xee67296d, 0xb999b8c9, 0x717320d4, 0x361c83ab, 0xfecd526f, + 0x16af62ee, 0xc904f8bc, 0x2d4480ce, 0x3e7b41e5, 0x907ca114, 0x37f4d5e9, 0x422f14ff, 0x9cc95fd5, + 0x5c51c8ff, 0xdc298d5f, 0x6d050fc8, 0xba5946c5, 0x29bc9616, 0x94c55883, 0xdefb5831, 0xc65df868, + 0xc4e7733f, 0x5f8a6b4c, 0x25f5753a, 0xc4c2bfbd, 0xc419ee33, 0x2b03fcd2, 0xd653d476, 0xa38d94f0, + 0x91456749, 0x9b7a91b2, 0x3d201af9, 0x2c50ed86, 0x419256e3, 0xf1f1e1ff, 0x3fce549d, 0xb015f44b, + 0x925cfba7, 0x2b874114, 0x65bfd7d5, 0x06b3a66e, 0xcd3b2951, 0x66d407f6, 0xcd127d0a, 0xd6aaa6e8, + 0x8ac561b6, 0xdc64b420, 0x37bdbf48, 0x5216d090, 0xc664a969, 0xb878d59f, 0xbca0e3fd, 0xa3036e2a, + 0x6a088a54, 0xdcfb9442, 0xc3a828e0, 0x9170990a, 0x27952683, 0x9b979769, 0xaaa02e1b, 0x5cb2477b, + 0x295f4d00, 0x40963432, 0xea9cc1c7, 0xc7a84ac6, 0x3bcb593f, 0xa7b309ff, 0x72e6c9e5, 0xfa0763bd, + 0xe81cc3e8, 0x79a47b57, 0xc4260da4, 0xdd36874c, 0x91a12129, 0xb6e2c6f4, 0xb34b188d, 0x209e4e73, + 0x4fe025f2, 0x91c72e14, 0xe2afe55a, 0x50787b62, 0xcb77e1d0, 0xed2ee7af, 0x166ed84a, 0x756938c3, + 0x2111a643, 0xde8e12e5, 0x3a30fa30, 0xaa625b47, 0x90542bfd, 0x2555d7fd, 0xb2a85b1b, 0x8d8041d2, + 0x072a1bdd, 0xb810ec79, 0xed37c688, 0xce518126, 0x36229500, 0xe484da87, 0x4d6dfaf7, 0x12e88dfc, + 0x6b79be48, 0x202f29d0, 0x1c42ea6c, 0x49edf0a8, 0x220e64b5, 0x6ae0c0b5, 0xea1a2974, 0x14a4e973, + 0xea5f5848, 0xf919a543, 0x75e1c414, 0xde02cc81, 0x467badfb, 0x5622cdd8, 0xe30d1165, 0xa345e314, + 0x517efd05, 0xce85e5b9, 0x211c917e, 0x81d35ea0, 0x3d249c60, 0x17e67008, 0x519aca47, 0x4c4cadcf, + 0xf0331ed9, 0x1248655e, 0x5bedc342, 0xd8c6f524, 0xd5e27720, 0x83044816, 0x58773858, 0xbc351b17, + 0x75972748, 0x15fe10fe, 0x7b6d19f9, 0x5ac61cd2, 0x35666646, 0x19f64bab, 0x2946de62, 0xed67c8a9, + 0xdc8782ff, 0x8cc45d3d, 0xd6c6d9c3, 0x97e08851, 0x67d7bc02, 0x5b372b02, 0x407028cb, 0x608c9a00, + 0xacc43b84, 0xb03b781b, 0x402fa9fb, 0xeef4ea84, 0x77e71ad3, 0xe1875731, 0xc97f27b2, 0x2a7c751b, + 0xc0d1c375, 0x6312a904, 0x5da6cefb, 0x0243d708, 0xb21cc88d, 0xb7156c6d, 0x553d31f7, 0x44d141c0, + 0xa397ca8b, 0x03d62285, 0x0eed2c7b, 0xbebec393, 0xb37775e7, 0xfab3ef83, 0xc42678df, 0xb242f06a, + 0x8c86f763, 0x01ddb90e, 0xfa135adb, 0x2efc8c9a, 0x967fb913, 0x07b53535, 0x0986e408, 0xa0b5f3ef, + 0x53cf1dbd, 0x33391861, 0x8161f248, 0x3b7adc62, 0x8854ebb5, 0x45ed73dd, 0xbad32f6b, 0xf9377e1f, + 0x4df188d0, 0xaa39c6c5, 0x20cad5bd, 0xb5921414, 0x9f41f3c6, 0xa0286634, 0xc2765c2e, 0x4cc82e07, + 0xe82b2f8a, 0x24c99dd9, 0xb352c4e7, 0x320701d3, 0x02e4ae7e, 0x1ee28b99, 0xe92d99ce, 0x34b2a700, + 0x6a1b27f2, 0x8c12def4, 0x607add07, 0xfdb3e957, 0xc8da4b80, 0xbd132264, 0x85fe334f, 0xf350bf97, + 0x81eca1e5, 0xf50f1b0f, 0xf0f550cc, 0xa0710d8e, 0xcf3c425c, 0xc550e394, 0xe54af42f, 0x72dbdc69, + 0x3b251208, 0x27e7a20c, 0x6fee68de, 0x8732de28, 0x55090e54, 0xc15c7d2b, 0x4b33f0ef, 0xe03dd84b, + 0x9e9e742a, 0x0ed2df39, 0xf6b56333, 0x1afee604, 0xdfa7888c, 0x65e55fc1, 0xb7b0bb0e, 0x9a4e566f, + 0x4b144286, 0xc360bf2e, 0xace9186e, 0x6cd1b238, 0x128479bb, 0xa827fa4f, 0xc3ad2477, 0x1510f47d, + 0xbd8a06b2, 0xbafa53a2, 0x47c58fe8, 0x4b743493, 0x2887d968, 0xf3d28a09, 0x16e5ba68, 0xc3f500a5, + 0x03c84043, 0x3e04accc, 0x1af8c60d, 0xc06177aa, 0x3ff47f41, 0x7ddd7f85, 0x944851a3, 0x48f23eee, + 0x3839b9ae, 0x4dce85aa, 0xdc886a0a, 0x4e6d9553, 0xff69c28e, 0x0f770125, 0x7f555a1f, 0x2d83e86f, + 0xfe3e2a3f, 0xeff6c730, 0x7efe4f76, 0xedf54f4f, 0x25dfd0be, 0x6edad1e5, 0xd4be9f58, 0xc7d7c4ad, + 0x06973d96, 0x2820e9c3, 0xf8866f22, 0x9e1fc080, 0xfe655362, 0x39eddc7f, 0xa0233a01, 0x8bf98a77, + 0x55c58d9f, 0xf8caf1c1, 0x16ecdc76, 0x0cd77c70, 0x1e0ad506, 0x0055d64f, 0x43104852, 0x08e0b479, + 0xc5e518a3, 0x24d25ff9, 0xfea90920, 0xb24fedb3, 0xe58b3e7c, 0xe8ef477c, 0x0cdf7535, 0x10035c98, + 0xfdab5faf, 0x97f477e3, 0x7b72c2a7, 0xcb335efd, 0x8f19f274, 0x88d9e91f, 0x2d25b71b, 0xdac22cca, + 0x99e234f6, 0x499a564a, 0xc9fbc75c, 0xfc25807c, 0x8d9c5180, 0xea42a28b, 0x187bffd8, 0xf1622311, + 0xf5f599cc, 0xe1bfcd23, 0x00c90039, 0x2fbecaf5, 0x7d1c95be, 0x3cc3c7c1, 0x88435dbe, 0x99c9e2e8, + 0x4ac81caa, 0x678b616e, 0x3279aff8, 0xc9bf1ce0, 0x52c050c0, 0xc02011b6, 0x42dab4b0, 0xe48bca25, + 0xd70f3964, 0xe05ffef5, 0x07a1dfa8, 0x121872cc, 0xa450d032, 0x2ff817eb, 0x653b581e, 0x26a054f8, + 0xcb8c42f3, 0x1442e75b, 0x0d0197bb, 0xc1a3d837, 0x3e7c31c1, 0x5dc6c27c, 0x826caee8, 0x7fee250a, + 0x4c61b00c, 0x349f8b92, 0xb90315f8, 0x79d97c35, 0x4033e52f, 0x1271ebef, 0xc45d05c3, 0x23ff9b00, + 0xd53c67a5, 0xe681a79a, 0xbf88f9a0, 0xabc4208e, 0x56d57a67, 0x3fed5542, 0x1d450cd3, 0xe0f3ad7f, + 0x4f646a66, 0x2dd27c7c, 0xb428e2d9, 0xef35fb5a, 0x654734f8, 0x061b8593, 0xc7433bea, 0x1ebe889f, + 0xe00b2150, 0x38b18217, 0x8e2f1d7f, 0x4a3c69df, 0x80ab53ad, 0x42448ef2, 0x38b5e884, 0xa785f638, + 0x993f6f09, 0xff16791a, 0xc976b58d, 0xb676c962, 0x26294be6, 0x8a9275f5, 0x2919ea4d, 0x5eb82a85, + 0x795bec76, 0x8e93d3b1, 0xa961dfc9, 0xca29256b, 0x37c1e8c7, 0xf54da387, 0xe3aacf27, 0x7ec817ef, + 0xc3ea9f1c, 0x3cd883d6, 0xbc99e534, 0x68bfca4e, 0x17e9d14b, 0x4c7b50ef, 0x7eb068de, 0x8f168398, + 0x2d70cf0a, 0xc9d02e92, 0x6d7202fe, 0xadf58443, 0x33a5ff50, 0x045daf69, 0x23868acd, 0x07747dd5, + 0xa5e37791, 0x2b5e3aca, 0xea39bb6f, 0xe456ca5c, 0xe86b1a73, 0xa4b36897, 0x3c341703, 0x393de49c, + 0xcb248dbb, 0x7e762733, 0x8f8421d9, 0xdcd995ac, 0x6d1ed6e7, 0x5fd5c732, 0xae75d090, 0x3fc2960b, + 0xbbdbaf09, 0x0e99988c, 0x68a49b6f, 0x4dd21b12, 0xf44c9e5d, 0x61df0be1, 0xcd5229dc, 0x2659a9dd, + 0x81681b4c, 0xe0a6b0eb, 0x05b2f9b3, 0x0ff04901, 0x551e279f, 0xa4644de2, 0x9405c6d3, 0xcb695d82, + 0xb97a6773, 0x2834f409, 0x1b535bcc, 0x55e0b1ce, 0xf51fb513, 0x2d3688e7, 0x87b21564, 0x3b823add, + 0x227db57f, 0x5c177f3b, 0xffca340f, 0xbe7f423c, 0x800f9cef, 0xb62f43ae, 0xcecb15c0, 0xb2bcc928, + 0xed918a86, 0x6cdf5d3b, 0x71721eee, 0x8f1256e8, 0x6f117172, 0x3b424b44, 0x987da83b, 0x9d55607e, + 0xaa66f08d, 0x7c5340f9, 0xfd63e5b9, 0xe7607812, 0x36e8f03a, 0x6e0819bc, 0xd7f52ed8, 0x63f6fdd7, + 0x6ce5d3f9, 0x5aba2e8f, 0x8d7b3096, 0xf7b33ece, 0xd20186a0, 0x2886e756, 0xcaec5a16, 0x07700249, + 0x0bb2a466, 0x2ecd591e, 0x1f79caaf, 0xf3b75494, 0x58e4d87d, 0x6776bd93, 0xd9877693, 0xbb6160a2, + 0xba8141df, 0xed81c778, 0x39fe86d4, 0xa31e15dc, 0xd499fc24, 0x71c655d4, 0x43ad3c0c, 0x790be975, + 0xa9cc14d4, 0x083b6972, 0x248b977b, 0x399ce240, 0xdfaa1e35, 0xdf7576a6, 0xcd773f19, 0x02edf8b5, + 0x51322821, 0xf97f158c, 0xb2af51ff, 0x4738bf47, 0x37244f50, 0x077ce774, 0xa63cee74, 0x9f8e354c, + 0xe73b68a3, 0x9104db02, 0x56dceefe, 0x8f9065fd, 0x5b8217d3, 0x19903043, 0xe5183f3f, 0x43e565bd, + 0xeba8a819, 0xa8ccf499, 0x364e6e93, 0x54498716, 0x537279e6, 0xf8298285, 0x962be77f, 0x268e463a, + 0x5872fff6, 0x414e5a23, 0x2dd92c51, 0x9010d1e2, 0xc440f36d, 0xc83127fe, 0x89cc9aa7, 0x51022c9a, + 0xfb4b617c, 0x693ff33e, 0x89e08d7f, 0x4d4c2b4d, 0x5d244bff, 0x76d05007, 0xe900778c, 0xae4fc0dc, + 0x678bf294, 0xb0ae57be, 0x8037e766, 0xffcbc394, 0xc2804a86, 0x3a9870aa, 0x2f248b23, 0x42451fcb, + 0x6a475ec3, 0x13522ede, 0xb98a474b, 0xe778dbb5, 0x11ccf4cc, 0xa75115e5, 0xc92cecff, 0x850c52bd, + 0xe8785c85, 0xea879459, 0x89af6215, 0x2ff27401, 0xc525305b, 0x5ee69111, 0xcd4ed49c, 0x856f7eff, + 0xb00de927, 0x91b7dd8b, 0xec0c83a7, 0xa248b9ff, 0x52a509f2, 0x45f60d2e, 0x144c9d42, 0x9bc6e23b, + 0x079aadf6, 0xcd101c31, 0x923bb305, 0xb79e0468, 0x44517524, 0xdb9cd0b7, 0x368bda61, 0xc74d5c1e, + 0xa18f9bb6, 0x615dcb54, 0x6c52f005, 0x2994c5c3, 0xd2e02e13, 0x56eeb5ec, 0x96f1d0d7, 0x617d8d0b, + 0x0a25f145, 0xdc493037, 0xd5fbffae, 0xcf9a7db9, 0x8c3cb655, 0x97d2019f, 0x0551c124, 0xbf9a270f, + 0xcdbd1bef, 0x3cb4b1d0, 0x7aa822d3, 0x5b201b40, 0xd0b486be, 0xada6f8a6, 0x1624aaef, 0xaf6eae27, + 0x7de944cd, 0x0933abdd, 0x57a5ae1b, 0xf23ca597, 0xb50c2a46, 0x95894c3e, 0x0f2081a3, 0xb2bf9bde, + 0xe4cfb6e1, 0x147d6c9c, 0xbd0f0fc0, 0x9304f4f4, 0x6948040a, 0x3d7fa508, 0x88187bcf, 0x15ae4e82, + 0x5ae6ed4c, 0x2968b1c7, 0x1b4a0f53, 0x8f3633f0, 0x86ae7b9e, 0x5e163cf4, 0xb7571ca1, 0xa0de0b7b, + 0xdacfe4bc, 0x878538ab, 0xa4e2e163, 0xb00efe7c, 0x80b58628, 0xca48573c, 0x77640afb, 0x9a3a9312, + 0x0254bf6b, 0x0706b640, 0x0d514ea1, 0x796341a9, 0x643b1cd7, 0x5ec45efd, 0x2e3f865f, 0x8e768261, + 0xfb5fad62, 0x579f8b08, 0x01672fd8, 0x96a7ce1b, 0x497ef151, 0xa9f0aaa1, 0xa0c9fe67, 0x1a3c0e0a, + 0x13cae6d2, 0x4cadfba7, 0xc47bc183, 0x5dccf205, 0xa3fdf48b, 0x0d9b6620, 0x6d495301, 0x2be33db1, + 0x6b965ef7, 0x93e34e67, 0x22d25697, 0xdd1c968e, 0x3095e341, 0x707c690c, 0x702e75e1, 0xba836e09, + 0x5cf0b7d3, 0xa7769c50, 0x0acd804a, 0xe9e61b45, 0x47812a99, 0xa58c853a, 0x7f99902c, 0x853b4bdd, + 0xb5a70198, 0xef53d4b8, 0x7ed6e1b0, 0xe145fcfa, 0xed53149d, 0x9a844218, 0xde5504f6, 0x78836da9, + 0x54f969b5, 0xf9f5c1de, 0x86a58beb, 0x5f90ced5, 0xe44c5d9f, 0xa410ec0a, 0x669627fe, 0x0b8c8ba2, + 0x20e37b02, 0xd6dc6fc8, 0x31083ca5, 0x4522a428, 0x21f75f0c, 0x223b46e9, 0x77c3f643, 0xd8b77ddf, + 0xef693944, 0xc50d4134, 0xdedce476, 0xc13a5de9, 0xe5ea63d2, 0x4a64203e, 0x494cefdb, 0x8a6c9421, + 0x532d5ea4, 0x97a0c31f, 0x90caf72e, 0xb249d4e7, 0xce6cd5b4, 0x3171e1a5, 0xc115aa50, 0xce621a48, + 0xfea90ef2, 0x71fa04e4, 0x4c136558, 0xad9dd28c, 0x7258d445, 0x7c0cff11, 0xb0767e0e, 0x85974a84, + 0x29f73644, 0x974482db, 0xc5e9b80f, 0xd0e085b6, 0x23d4b3bf, 0xb3cd2359, 0xbd460537, 0xc80ee6f7, + 0x88ddca65, 0xd23a6579, 0x20619914, 0x057247fe, 0x120f331a, 0x0f458217, 0x05ff4bef, 0xfd68fa1a, + 0x4c94f534, 0x76f6844c, 0xd13572bb, 0x969489f1, 0x314a2ba7, 0xa365af15, 0x9075fae3, 0x6444eca3, + 0x461539d1, 0x2cfb1173, 0xe248e190, 0x0a605eec, 0x1d527953, 0x61aecf73, 0x9aabefc4, 0xff7aee4e, + 0x035ad33e, 0xe98020ea, 0x87f36bec, 0xada7f16d, 0xa875adb4, 0x20f870f4, 0x04eaf08b, 0x3b8255ff, + 0xc627dc82, 0x0abedfd0, 0xc343ae13, 0x0ec5a299, 0x1b6f3888, 0x22acfd52, 0x8e2036b6, 0x18f7642c, + 0xbac72b5d, 0x28504fd9, 0x866a1356, 0x5cc778a4, 0x494f7afc, 0x2b7e9b4c, 0xb3ad0544, 0x66b031ea, + 0x74c1563f, 0xd1d297d5, 0x8dcff1de, 0xc4359b07, 0xc767acb5, 0x62e64e72, 0x5c97846d, 0x126a5ff0, + 0xe9f501e1, 0x53101134, 0x4e6a6de8, 0x6c513be9, 0x5cf650a4, 0x39ba18a3, 0x182339b4, 0x6d8c7846, + 0xa38cc231, 0x0424dde7, 0xfd0932a2, 0xf1b28914, 0xc8078980, 0x4879bd4e, 0xfbd719b5, 0xf7776313, + 0x330533da, 0x5eb48aae, 0x34e70a21, 0xb77a176b, 0x7e472c67, 0x1a703cab, 0x9ec4ab61, 0xab3b83a3, + 0xcf232877, 0x97fd472f, 0xba5d9cad, 0x444cc0d0, 0xe7ea247e, 0x1b410bbb, 0xb48e1aa0, 0xf520caa9, + 0x92435db6, 0x2dda67c3, 0x6941d71b, 0xb400e475, 0x2fad0889, 0x31a92786, 0xc50b6b86, 0x450d66b3, + 0x0079c76b, 0x4780f743, 0x4e73f565, 0x1d7f0d6f, 0x5724e59d, 0x518c14f8, 0x709cb335, 0x996db614, + 0xa4baf54a, 0x5a41de4d, 0x445a9c59, 0x954a203c, 0xe0c969a5, 0x34091810, 0x809e0544, 0x93b218dc, + 0x64b22e3b, 0xc25e1ed3, 0x4464b73d, 0xeee5f4d0, 0xe4bfcbd5, 0xe1f89fac, 0xd37b1c19, 0x918c3bec, + 0xd91f9303, 0x4ad4622d, 0x22da49d9, 0xab430632, 0x96b9aca8, 0xe0b8884a, 0x810476b9, 0xe65ad6b0, + 0x5c87dce3, 0xd3edb1ce, 0x0f8f38e9, 0x90eb8d73, 0x509cc69b, 0xb97b0f43, 0x91ab6155, 0x0a467af8, + 0xba21b5b7, 0x0e4ff444, 0xcf196767, 0x70dd1caf, 0x0c2ded27, 0xed5a03cd, 0xf1eee0ad, 0x61b70854, + 0x97c61955, 0x5fa186ad, 0xd125dcd1, 0x2d4dc54f, 0x2f8bde4b, 0xfd436030, 0xabe12f63, 0x603a9f23, + 0x3de9b526, 0x02e74f34, 0x144d052d, 0x9fcb6405, 0xef6d6bf2, 0xf1b7e864, 0xf4e726c0, 0xf05bfe57, + 0xda318c06, 0xebc84b57, 0xeb0600bb, 0x61d2def8, 0x4cde1510, 0x632ca9cd, 0x59c132e4, 0x10456bd4, + 0xf55cb474, 0x6c0653a5, 0x5b10b967, 0x68653553, 0xdd8cec5b, 0xe0285a92, 0x50e8bc4c, 0xa41be731, + 0x1228a881, 0x7a8e4ca1, 0x1653c120, 0x0c477042, 0xc2cfe114, 0xbf30c5fd, 0x883cae84, 0x0b19d20c, + 0x9bbc7b7b, 0x45e18b4d, 0xff57c62c, 0xbf514718, 0x299801f9, 0x5d2cffc5, 0x74707569, 0xcaa2f295, + 0xe00333ea, 0x067218aa, 0xcc83b34f, 0xe5cfe03a, 0xb9535ce8, 0x6977eb48, 0x9c70e601, 0x50b45abf, + 0xd102ff5c, 0x843e0d78, 0xf4983b7f, 0xefb1b798, 0xe7e8f947, 0x14a250a2, 0x576edbd7, 0x69b956c9, + 0xf2dab39e, 0x48673e82, 0x23da18e2, 0x4c9026b3, 0x10f18625, 0x1e85ca73, 0x03a0880b, 0x3f4526f2, + 0x3bf917d0, 0x6a61562b, 0x9665ea39, 0xaa07e0f6, 0xfcc18b78, 0xc48ae23e, 0xa2d428fd, 0x773be066, + 0x58cf4b37, 0x9bd720e6, 0x6c5c09ba, 0xd08f17cc, 0xf97dc964, 0x95b60beb, 0xac9eeaa5, 0x49619eae, + 0xf7daa4c3, 0xf200b146, 0x661352e5, 0x2e5bac71, 0x5f34c3bf, 0x02763f4b, 0xbbc280e7, 0xf5ca9340, + 0x71102946, 0x020b69dd, 0x6fdad507, 0xf184446a, 0x3f0fd3b2, 0x7389c34e, 0x478384e3, 0xceeb1756, + 0xa45928f4, 0x8c63e98c, 0x0976428c, 0x1857c619, 0x04e8def8, 0x23070abc, 0x5d076e96, 0xe4ebcf36, + 0xbed38a0e, 0xa69302c7, 0x7fccb6ed, 0x0a83d6e1, 0x539eeebc, 0x7f8fe6f1, 0x03ee21a3, 0x92704df5, + 0x8ffdd0dc, 0x172f7298, 0x04aa4ba1, 0x4d23f169, 0x9ce3ceb6, 0xe09e42da, 0x5edb2e1d, 0x7bf9ea3f, + 0xa1553331, 0x42b5f43b, 0xde78af2c, 0x078c69cd, 0x71d2fa23, 0x5a05c002, 0xf60ae278, 0xcea35ccc, + 0x805c0bae, 0x539bb365, 0x8567a8e3, 0xb6e5329b, 0x45242871, 0x9d51ec88, 0x02b56050, 0x7594ff07, + 0x0892ee44, 0xaafad504, 0x3a243a07, 0x39ff0ffb, 0x4fe63fc8, 0x715fbff4, 0xbca90a42, 0xd0807467, + 0xaab4bc19, 0xd191d9e8, 0x6a8b47f1, 0x398f227b, 0x1f47fa79, 0xe63f2e15, 0x4bc136c9, 0xa09e4fae, + 0xbb480a52, 0x87e8b22f, 0x06c595c8, 0x4a83f4f1, 0xb5986463, 0xb4dd0203, 0xc083e115, 0x860ce90d, + 0xf41b086a, 0x0ef1e14a, 0x47cf6544, 0x438f40bf, 0x3d9ae76b, 0x23cb755c, 0x8ff1a3f0, 0x0704ea6a, + 0x0d3394b0, 0xd18f0fe8, 0xcc61b29e, 0x1f6c15b1, 0x5cef9dff, 0xe428c28b, 0xaa647f77, 0x40e6074a, + 0xc26541be, 0xfa686425, 0xfd77a573, 0xf45b9e88, 0xa9969367, 0xda54aa3b, 0x393c4ebb, 0xe1cfa198, + 0xd429bd24, 0x04df29ae, 0x94a93e73, 0x1275b87e, 0x47c552f1, 0x20942715, 0xde52dbc2, 0x0e7d0446, + 0x34225e82, 0xdd375519, 0x8ed8887d, 0xe4a7f7ba, 0xfbb7eb12, 0x3484740f, 0x6c305a25, 0x61e75416, + 0xa6cccf21, 0x22224306, 0x5df89939, 0x4dd27163, 0x5e576638, 0xb0b569a1, 0x7d3b5786, 0xbc87162e, + 0x2e57c460, 0xee1d543a, 0x01abadad, 0xff54842c, 0x5e53f7b7, 0x6f044d36, 0xcbbcceec, 0x048704e7, + 0x7c0966df, 0x8e8f303b, 0x73173ab0, 0xc9c8ee51, 0xd8778f80, 0x0e0d4f67, 0x85b8d186, 0x35867f11, + 0x635fd7bb, 0x4c4aa104, 0x203eac3a, 0x93f5a254, 0xb0a17832, 0x0a4d7c34, 0x762e7267, 0xe127b861, + 0x9711f99c, 0xdc664fdc, 0x29470a86, 0xc1d26a0c, 0xcb7f07ac, 0x02627751, 0xb8e71b9d, 0x78f2e0cb, + 0x74bb8d50, 0xde646197, 0x2dc8e9ae, 0xc460736d, 0xb7ee5567, 0xdd5624e7, 0x3ae9bdf5, 0x98bbf063, + 0x131a1ecf, 0xc952e908, 0x2baa4f74, 0x8308adf9, 0x52ebc164, 0xa73f0e5d, 0xdd6acc5c, 0x790b1885, + 0xd6ce1799, 0x0ae9bcd8, 0x19b25bc3, 0xb28ffc28, 0x6ffd96d0, 0x7af4cd33, 0xdd1138f8, 0xd2c65b2f, + 0xb84950d5, 0x83f23672, 0x13646f7a, 0xcc9a1edc, 0xf998e0e2, 0x3d77f746, 0xc00a24d0, 0xac0ae5f7, + 0x8e8928e5, 0x4c953638, 0xc8d578ac, 0x75aa2fa0, 0xfce4f691, 0x2ec11583, 0x7cd3cc69, 0x86a1bea0, + 0xec9636f0, 0xbb1e0694, 0xd98bf030, 0x2a58c9bf, 0x6dcbf1a5, 0xb102deeb, 0xcba297ad, 0xedecf7d8, + 0x4675a0fb, 0x6e5793b4, 0xe35b6186, 0x80917bbd, 0x934aecd6, 0xe56f880b, 0xa31e02be, 0x696380a4, + 0x50f4d04e, 0x58dce956, 0xb793c45a, 0x2d86fcbf, 0x21218254, 0x69cead67, 0xb2557bef, 0x3b673cb8, + 0xf1d8bd3d, 0xa4362e84, 0xf1735eb4, 0x29621e93, 0x870a2478, 0xea6a8fd5, 0xaedece26, 0x5b5135a8, + 0x74644c92, 0xc9c421be, 0x1accc536, 0x5d6d82c4, 0x8a03665f, 0xa91a235b, 0x9de4d228, 0xa9fbd2d1, + 0xe088ae72, 0xbebe24f1, 0x69a28e20, 0xfb2674bd, 0x45257544, 0xecc373d0, 0xf7d08e14, 0x79256c68, + 0x745516a6, 0xb22bfc79, 0x3ed71f17, 0x50f008ce, 0x32f8e301, 0x33e1d2c9, 0xcb4c5b1d, 0x87be0cd8, + 0x45e477a3, 0xa3b7b6da, 0xf1459e4a, 0x7e20e792, 0x36a77cde, 0x5de411e6, 0x5248efe9, 0xfc187d14, + 0xe3e471db, 0x2ec42208, 0xcb1a6b0c, 0xbbad69bb, 0xe8a470f9, 0x6f6d9d6b, 0x2d28522c, 0x88731f60, + 0xf4d1f7d3, 0x9e7d2279, 0x77af9a54, 0xa5873000, 0xfaded86c, 0xfcb9fb63, 0x4ac0bba7, 0xab670086, + 0xad53ecb4, 0x80413336, 0x98a2a9f5, 0x7aff9a71, 0x02357040, 0xb69e2741, 0x3e0edbc0, 0xec6ac785, + 0x88b9e946, 0x5ed51c43, 0x5f707ac1, 0xcdd9ed0f, 0xe3d982be, 0xc4d0c698, 0x08a143f3, 0xb61546cd, + 0x7a7e4cfb, 0xd6a1e496, 0x86eb86e3, 0x80d57b83, 0x6eec8920, 0x3e323aa7, 0xb9301196, 0x2ddcadcd, + 0x643b3afd, 0xabd78480, 0x2d356a3a, 0xe395c748, 0x64575a3a, 0xe56547c2, 0x3cdf23e3, 0x778a7436, + 0x47705472, 0xc6de24c1, 0x3a382de5, 0x9d76ad71, 0x8d54f42a, 0x43932aa2, 0xf34b9b73, 0x1dc63af3, + 0xbd3259d3, 0x7666b3ea, 0x2344ef7e, 0x48079ac5, 0xa9aaea7b, 0x437e125f, 0xbb1b8951, 0x3ec5c7d6, + 0xcd6a571d, 0x4c16184b, 0xfa0bd919, 0xdcbe3b7b, 0x2b593927, 0x3f614d3d, 0x23ddff73, 0x9c304074, + 0x309d0ed1, 0xa330d943, 0xa99efaa5, 0x2aa0f75c, 0x363d33c4, 0xcc688382, 0xedec0141, 0x2e2c6564, + 0x6d801e87, 0x729e3bc8, 0x38260f7e, 0xf25d1471, 0x0a2fbe53, 0x44245240, 0xa139bf0e, 0x41bb783f, + 0x814fe6fc, 0x22f049b5, 0x68e786a8, 0xa0b5f1ee, 0xd2b66401, 0xffed40c6, 0xc62fd8b2, 0x94439814, + 0xb9ce281f, 0xee50d1f8, 0xecd6c5d2, 0x81951253, 0x44c38c42, 0x400d21cd, 0xc2fb2464, 0xced0a17e, + 0xf06c24fd, 0xc3a3a718, 0x98201234, 0x2ecd332d, 0xb8dea35d, 0x19f1ff5d, 0x44e92cd7, 0x9ec92426, + 0x4f27acd1, 0x58d50ceb, 0xf8d8e3ff, 0x80497702, 0x969122b6, 0xc30f2745, 0x6f697882, 0xf780ba7c, +}; + +/*! +* \brief Size in words of the firmware image +*/ +#define LR11XX_FIRMWARE_IMAGE_SIZE 16648 + +#endif /* LR11XX_FW_H */ From 4ab0ac8a13acb8e23fcac2437a7b19f989642c4a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 15:00:05 +0200 Subject: [PATCH 1091/1848] [CI] Skip LR11x0 FW update build on Uno --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4becc1b73e..78a330c9c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,7 +46,7 @@ jobs: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. include: - id: arduino:avr:uno - run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble From 9ebafbe50791d73415d34e508312ae5a2ccd04e2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 15:02:36 +0200 Subject: [PATCH 1092/1848] Exclude FW images from linguist --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..a9bdec1b70 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# exclude binary patch files from language detection +src/modules/SX126x/patches linguist-detectable=false +src/modules/LR11x0/firmware linguist-detectable=false From 76f61144dfaade4352fdc573c22430498c88fc6c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 15:03:44 +0200 Subject: [PATCH 1093/1848] Fix gitattributes --- .gitattributes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index a9bdec1b70..bbf0d98075 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ # exclude binary patch files from language detection -src/modules/SX126x/patches linguist-detectable=false -src/modules/LR11x0/firmware linguist-detectable=false +src/modules/SX126x/patches/*.h linguist-detectable=false +src/modules/LR11x0/firmware/*.h linguist-detectable=false From 60d1738c9153a1163f4ec68f9615ee391994ad89 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 18:32:44 +0200 Subject: [PATCH 1094/1848] [AX25] Fix possible string truncation --- src/protocols/AX25/AX25.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 7e7d475e58..480ea343d3 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -59,8 +59,8 @@ AX25Frame::AX25Frame(const AX25Frame& frame) infoLen(frame.infoLen), rcvSeqNumber(frame.rcvSeqNumber), sendSeqNumber(frame.sendSeqNumber) { - strncpy(this->destCallsign, frame.destCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); - strncpy(this->srcCallsign, frame.srcCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + strncpy(this->destCallsign, frame.destCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); + strncpy(this->srcCallsign, frame.srcCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); if(frame.infoLen) { #if !RADIOLIB_STATIC_ONLY @@ -204,7 +204,7 @@ AX25Client::AX25Client(const AX25Client& ax25) : phyLayer(ax25.phyLayer), sourceSSID(ax25.sourceSSID), preambleLen(ax25.preambleLen) { - strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); #if !RADIOLIB_EXCLUDE_AFSK if(ax25.bellModem) { this->audio = ax25.audio; @@ -217,7 +217,7 @@ AX25Client& AX25Client::operator=(const AX25Client& ax25) { this->phyLayer = ax25.phyLayer; this->sourceSSID = ax25.sourceSSID; this->preambleLen = ax25.preambleLen; - strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN); + strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); #if !RADIOLIB_EXCLUDE_AFSK if(ax25.bellModem) { this->audio = ax25.audio; From 98c80a9cb97f8ee19435ee94b01e934aa2b5a280 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 19:05:03 +0200 Subject: [PATCH 1095/1848] [STM32WL] Fix output ramp time configuration --- src/modules/SX126x/STM32WLx.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index 69515fcfe4..e9f47167dd 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -93,9 +93,8 @@ int16_t STM32WLx::setOutputPower(int8_t power) { state = SX126x::fixPaClamping(use_hp); RADIOLIB_ASSERT(state); - // set output power - /// \todo power ramp time configuration - state = SX126x::setTxParams(power); + // set output power with default 200us ramp + state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); RADIOLIB_ASSERT(state); // restore OCP configuration From 534a2f2d6282b5d1e74e4eb8b7197c65f58d03b5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 19:09:04 +0200 Subject: [PATCH 1096/1848] [LR11x0] Fix struct initialization --- src/modules/LR11x0/LR11x0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 75cd360b08..1e5fe5b8f2 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1709,7 +1709,7 @@ bool LR11x0::findChip(uint8_t ver) { reset(); // read the version - LR11x0VersionInfo_t info = { 0 }; + LR11x0VersionInfo_t info; int16_t state = getVersionInfo(&info); if((state == RADIOLIB_ERR_NONE) && (info.device == ver)) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device); From 764c0bf27141fb3ee35391b859fa9b4b20d37fa6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 19:19:07 +0200 Subject: [PATCH 1097/1848] [CI] Disable LR11x0 firmware update on low-end platforms --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 78a330c9c2..1a195d1589 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,12 +49,13 @@ jobs: run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble - id: arduino:mbed:envie_m4 - id: arduino:megaavr:uno2018 run: | echo "options=':mode=on'" >> $GITHUB_OUTPUT - echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:sam:arduino_due_x - id: arduino:samd:arduino_zero_native - id: adafruit:samd:adafruit_feather_m0 @@ -110,7 +111,7 @@ jobs: echo "index-url=--additional-urls https://www.pjrc.com/teensy/package_teensy_index.json" >> $GITHUB_OUTPUT - id: arduino:renesas_uno:minima run: | - echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT runs-on: ubuntu-latest name: ${{ matrix.id }} From ffafb7353db3dd8198702626fb36b268da7697e2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 21:06:15 +0200 Subject: [PATCH 1098/1848] [CI] Fix syntax --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a195d1589..c5b7d191a7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,7 +48,8 @@ jobs: - id: arduino:avr:uno run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:avr:mega - run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT + run: | + echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:mbed:nano33ble - id: arduino:mbed:envie_m4 @@ -79,6 +80,7 @@ jobs: run: | echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT + - id: Intel:arc32:arduino_101 - id: SparkFun:apollo3:sfe_artemis run: | echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT From 648268d5c188314ccafca97243bc616779350ced Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 21:14:44 +0200 Subject: [PATCH 1099/1848] [CI] Remove Intel Arc (broken platform) --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c5b7d191a7..0039a14842 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,7 +80,6 @@ jobs: run: | echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - - id: Intel:arc32:arduino_101 - id: SparkFun:apollo3:sfe_artemis run: | echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT From e121f963dc0767228de813ab6b1b9fe63e09d08b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 May 2024 21:22:19 +0200 Subject: [PATCH 1100/1848] [CI] Skip LR11x0 firmware example on AVRs --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0039a14842..88f9a05fed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -99,13 +99,16 @@ jobs: - id: MegaCoreX:megaavr:4809 run: | echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:mbed_rp2040:pico - id: rp2040:rp2040:rpipico run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT - id: CubeCell:CubeCell:CubeCell-Board run: echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT - id: MegaCore:avr:1281 - run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT + run: | + echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: teensy:avr:teensy41 run: | echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT From f2e1b547d5a704122df06ba5461c6ca92fbfb218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Sch=C3=A4tzlein?= Date: Mon, 20 May 2024 10:51:41 +0200 Subject: [PATCH 1101/1848] fix payload of DevStatusAns mac-command Lorawan specs say (e.g. 1.0.4 or 1.1), that the first byte is the battery-level and the second byte is the margin. --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0636ddd0cd..60e7095729 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2386,9 +2386,9 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // set the uplink reply RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); cmd->len = 2; - cmd->payload[1] = this->battLevel; + cmd->payload[0] = this->battLevel; int8_t snr = this->phyLayer->getSNR(); - cmd->payload[0] = snr & 0x3F; + cmd->payload[1] = snr & 0x3F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusAns: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); return(true); From 2b650702120aae8ba5cc2e08ca8bdbb0f8022588 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 18:07:48 +0200 Subject: [PATCH 1102/1848] [CI] Disable LR11x0 FW update on most platforms --- .github/workflows/main.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 88f9a05fed..3cd10c89e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -59,10 +59,13 @@ jobs: echo "skip-pattern=(STM32WL|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: arduino:sam:arduino_due_x - id: arduino:samd:arduino_zero_native + run: | + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: adafruit:samd:adafruit_feather_m0 run: | echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: adafruit:nrf52:feather52832 run: | sudo apt-get update @@ -72,6 +75,7 @@ jobs: echo "/home/runner/.local/bin" >> $GITHUB_PATH echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: esp32:esp32:esp32 run: | python -m pip install pyserial @@ -86,15 +90,18 @@ jobs: echo "warnings='none'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT - id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC - run: echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT + run: | + echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - id: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1 run: | # Do *not* skip STM32WL examples - echo "skip-pattern=''" >> $GITHUB_OUTPUT + echo "skip-pattern='LR11x0_Firmware_Update'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT - id: stm32duino:STM32F1:mapleMini run: | echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT + echo "skip-pattern='LR11x0_Firmware_Update'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - id: MegaCoreX:megaavr:4809 run: | From 020a2ce8df8745d48ee06f41ddfd8dfe1bb0adca Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 18:08:27 +0200 Subject: [PATCH 1103/1848] [LR11x0] Do not use yield in example --- .../LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino index 43e7148ffc..97fbdaea3e 100644 --- a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino +++ b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino @@ -71,7 +71,7 @@ void setup() { // prompt the user Serial.println(F("[LR1110] Send any character to start the update")); - while(!Serial.available()) { yield(); } + while(!Serial.available()) { delay(1); } // upload update into LR11x0 non-volatile memory Serial.print(F("[LR1110] Updating firmware, this may take several seconds ... ")); From bcbefab4e841a3d4c649d2a90aec80d903f53397 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 19:19:14 +0200 Subject: [PATCH 1104/1848] [CI] Fix STM32WL skip pattern missing --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3cd10c89e8..359b4811a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -101,7 +101,7 @@ jobs: - id: stm32duino:STM32F1:mapleMini run: | echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT - echo "skip-pattern='LR11x0_Firmware_Update'" >> $GITHUB_OUTPUT + echo "skip-pattern='(STM32WL|LR11x0_Firmware_Update)'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - id: MegaCoreX:megaavr:4809 run: | From 8cda0d7a2671845c96039574d3d0bfa57c429742 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 19:30:07 +0200 Subject: [PATCH 1105/1848] [CI] Fix STM32F1 skip pattern --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 359b4811a8..04d7d17bfc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -101,7 +101,7 @@ jobs: - id: stm32duino:STM32F1:mapleMini run: | echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT - echo "skip-pattern='(STM32WL|LR11x0_Firmware_Update)'" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - id: MegaCoreX:megaavr:4809 run: | From 90627325d3718c2e5e61ac73f4f5d92748d272cf Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 19:39:51 +0200 Subject: [PATCH 1106/1848] [CI] Fix STM32F1 skip pattern --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 04d7d17bfc..c4de05ddf2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -101,7 +101,7 @@ jobs: - id: stm32duino:STM32F1:mapleMini run: | echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT - echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)'" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT - id: MegaCoreX:megaavr:4809 run: | From e52fe99f03bb717792cabf6006a50fce1d2bc951 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 19:56:47 +0200 Subject: [PATCH 1107/1848] [CC1101] Rework power check to not use constexpr --- src/modules/CC1101/CC1101.cpp | 39 ++++++++--------------------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 09e07b27b4..730065787a 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -589,7 +589,7 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped) { } int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { - constexpr int8_t allowedPwrs[8] = { -30, -20, -15, -10, 0, 5, 7, 10 }; + const int8_t allowedPwrs[8] = { -30, -20, -15, -10, 0, 5, 7, 10 }; if(clipped) { if(power <= -30) { @@ -608,7 +608,7 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { // if just a check occurs (and not requesting the raw power value), return now if(!raw) { - for(int i = 0; i < 8; i++) { + for(int i = 0; i < sizeof(allowedPwrs); i++) { if(allowedPwrs[i] == power) { return(RADIOLIB_ERR_NONE); } @@ -642,35 +642,14 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { {0xCB, 0xC8, 0xCB, 0xC7}, {0xC2, 0xC0, 0xC2, 0xC0}}; - switch(power) { - case allowedPwrs[0]: // -30 - *raw = paTable[0][f]; - break; - case allowedPwrs[1]: // -20 - *raw = paTable[1][f]; - break; - case allowedPwrs[2]: // -15 - *raw = paTable[2][f]; - break; - case allowedPwrs[3]: // -10 - *raw = paTable[3][f]; - break; - case allowedPwrs[4]: // 0 - *raw = paTable[4][f]; - break; - case allowedPwrs[5]: // 5 - *raw = paTable[5][f]; - break; - case allowedPwrs[6]: // 7 - *raw = paTable[6][f]; - break; - case allowedPwrs[7]: // 10 - *raw = paTable[7][f]; - break; - default: - return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + for(uint8_t i = 0; i < sizeof(allowedPwrs); i++) { + if(power == allowedPwrs[i]) { + *raw = paTable[i][f]; + return(RADIOLIB_ERR_NONE); + } } - return(RADIOLIB_ERR_NONE); + + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { From bfb27ec8c9fe7e99f1efebde8a1820d99b110313 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 20 May 2024 20:02:43 +0200 Subject: [PATCH 1108/1848] [CI] Skip CubeCell LR11x0 FW update --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c4de05ddf2..67adb83bbd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -111,7 +111,9 @@ jobs: - id: rp2040:rp2040:rpipico run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT - id: CubeCell:CubeCell:CubeCell-Board - run: echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT + run: | + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT + echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT - id: MegaCore:avr:1281 run: | echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT From 298a612699dbe74bd2747855719dbdbcc9b95c35 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Tue, 21 May 2024 12:03:49 +0200 Subject: [PATCH 1109/1848] [LoRaWAN] Change session activation (#1093) * [LoRaWAN] Improve session restoration/activation behaviour * [LoRaWAN] Custom return codes for session begin * [LoRaWAN] Separate begin() and activate() * [LoRaWAN] Fix activateABP() * [LoRaWAN] Additional error-code * [LoRaWAN] Fix rejoining during active session * [LoRaWAN] Expose clearSession, drop `force` * Update keywords... --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 2 +- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 6 +- .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 4 +- keywords.txt | 8 +- src/TypeDef.h | 20 + src/protocols/LoRaWAN/LoRaWAN.cpp | 486 +++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 74 ++- 7 files changed, 329 insertions(+), 271 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 637efa80b5..02ffb7d64e 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -43,7 +43,7 @@ void setup() { Serial.println(F("Initialise LoRaWAN Network credentials")); state = node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey, true); - debug(state < RADIOLIB_ERR_NONE, F("Session setup failed"), state, true); + debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Session setup failed"), state, true); Serial.println(F("Ready!\n")); } diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index f45830a199..7e2947a66d 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -46,11 +46,11 @@ void setup() { debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); // Override the default join rate - // uint8_t joinDR = 3; + uint8_t joinDR = 4; Serial.println(F("Join ('login') to the LoRaWAN Network")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); - debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true, joinDR); + debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); // Print the DevAddr Serial.print("[LoRaWAN] DevAddr: "); diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index c9b32eb3a0..6b8025726f 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -35,8 +35,8 @@ void setup() { debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); Serial.println(F("Join ('login') to the LoRaWAN Network")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true); - debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); Serial.println(F("Ready!\n")); } diff --git a/keywords.txt b/keywords.txt index c31d269aaf..41cda13884 100644 --- a/keywords.txt +++ b/keywords.txt @@ -316,16 +316,16 @@ checkDataRate KEYWORD2 setModem KEYWORD2 # LoRaWAN -wipe KEYWORD2 +clearSession KEYWORD2 getBufferNonces KEYWORD2 setBufferNonces KEYWORD2 getBufferSession KEYWORD2 setBufferSession KEYWORD2 -restore KEYWORD2 beginOTAA KEYWORD2 +activateOTAA KEYWORD2 beginABP KEYWORD2 -isJoined KEYWORD2 -saveSession KEYWORD2 +activateABP KEYWORD2 +isActivated KEYWORD2 sendMacCommandReq KEYWORD2 uplink KEYWORD2 downlink KEYWORD2 diff --git a/src/TypeDef.h b/src/TypeDef.h index 245eb72a4c..30c78bd8e9 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -563,6 +563,26 @@ */ #define RADIOLIB_LORAWAN_NO_DOWNLINK (-1116) +/*! + \brief The LoRaWAN session was successfully re-activated. +*/ +#define RADIOLIB_LORAWAN_SESSION_RESTORED (-1117) + +/*! + \brief A new LoRaWAN session is started. +*/ +#define RADIOLIB_LORAWAN_NEW_SESSION (-1118) + +/*! + \brief The supplied Nonces buffer is discarded as its activation information is invalid. +*/ +#define RADIOLIB_LORAWAN_NONCES_DISCARDED (-1119) + +/*! + \brief The supplied Session buffer is discarded as it doesn't match the Nonces. +*/ +#define RADIOLIB_LORAWAN_SESSION_DISCARDED (-1120) + // LR11x0-specific status codes /*! diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 60e7095729..c28a226eb5 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -44,17 +44,33 @@ void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA this->enableCSMA = enableCSMA; } -void LoRaWANNode::wipe() { +void LoRaWANNode::clearNonces() { + // clear & set all the device credentials memset(this->bufferNonces, 0, RADIOLIB_LW_NONCES_BUF_SIZE); + this->keyCheckSum = 0; + this->devNonce = 0; + this->joinNonce = 0; + this->isActive = false; +} + +void LoRaWANNode::clearSession() { memset(this->bufferSession, 0, RADIOLIB_LW_SESSION_BUF_SIZE); + memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); + memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; + this->isActive = false; } uint8_t* LoRaWANNode::getBufferNonces() { + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); + return(this->bufferNonces); } int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { - if(this->isJoined()) { + if(this->isActivated()) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); return(RADIOLIB_ERR_NONE); } @@ -62,24 +78,54 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); RADIOLIB_ASSERT(state); + bool isSameKeys = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_CHECKSUM]) == this->keyCheckSum; + bool isSameMode = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_MODE]) == this->lwMode; + bool isSameClass = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_CLASS]) == this->lwClass; + bool isSamePlan = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_PLAN]) == this->band->bandNum; + + // check if Nonces buffer matches the current configuration + if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { + // if configuration did not match, discard whatever is currently in the buffers and start fresh + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Discarding the Nonces buffer:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); + return(RADIOLIB_LORAWAN_NONCES_DISCARDED); + } + // copy the whole buffer over memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); + this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE]); + this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], 3); + // revert to inactive as long as no session is restored this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; + this->isActive = false; return(state); } uint8_t* LoRaWANNode::getBufferSession() { - // update buffer contents - this->saveSession(); + // store all frame counters + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN], this->aFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN], this->nFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP], this->confFCntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN], this->confFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT], this->adrFCnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP], this->fCntUp); + + // save the current uplink MAC command queue + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + + // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LW_SESSION_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_SIGNATURE], signature); return(this->bufferSession); } int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { - if(this->isJoined()) { + if(this->isActivated()) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); return(RADIOLIB_ERR_NONE); } @@ -92,79 +138,18 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_SESSION_NONCES_SIGNATURE]); if(signatureNonces != signatureInSession) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); - return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + return(RADIOLIB_LORAWAN_SESSION_DISCARDED); } // copy the whole buffer over memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LW_SESSION_BUF_SIZE); - // as both the Nonces and session are restored, revert to active session - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; - - return(state); -} - -int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { - // check if there are actually values in the buffer - size_t i = 0; - for(; i < size; i++) { - if(buffer[i]) { - break; - } - } - if(i == size) { - return(RADIOLIB_ERR_NETWORK_NOT_JOINED); - } - - // check integrity of the whole buffer (compare checksum to included checksum) - uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); - uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); - if(signature != checkSum) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04X, expected: %04X", checkSum, signature); - return(RADIOLIB_ERR_CHECKSUM_MISMATCH); - } - return(RADIOLIB_ERR_NONE); -} - -int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) { - // if already joined, ignore - if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) { - return(RADIOLIB_ERR_NONE); - } - - bool isSameKeys = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM]) == checkSum; - bool isSameMode = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE]) == lwMode; - bool isSameClass = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS]) == lwClass; - bool isSamePlan = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN]) == freqPlan; - - // check if Nonces buffer matches the current configuration - if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { - // if configuration did not match, discard whatever is currently in the buffers and start fresh - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (checksum: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Nonces buffer:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Clearing buffer and starting fresh"); - this->wipe(); - return(RADIOLIB_ERR_NETWORK_NOT_JOINED); - } - - if(lwMode == RADIOLIB_LW_MODE_OTAA) { - // Nonces buffer is OK, so we can at least restore Nonces - this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE]); - this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], 3); - } - + //// this code can be used in case breaking chances must be caught: // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LW_NONCES_VERSION]; // if (RADIOLIB_LW_NONCES_VERSION_VAL > nvm_table_version) { // // set default values for variables that are new or something // } - if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] == 0) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No active session in progress; please join the network"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE); - return(RADIOLIB_ERR_NETWORK_NOT_JOINED); - } - // pull all authentication keys from persistent storage this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR]); memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); @@ -183,22 +168,52 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass this->adrFCnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT]); this->fCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP]); - int16_t state = RADIOLIB_ERR_UNKNOWN; + // restore the complete MAC state - // for dynamic bands, first restore the defined channels before restoring ADR - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { - // restore the defined channels - state = this->restoreChannels(); - RADIOLIB_ASSERT(state); - } + // all-zero buffer used for checking if MAC commands are set + uint8_t bufferZeroes[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - // restore the complete MAC state LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_TX_PARAM_SETUP, + .cid = 0, .payload = { 0 }, - .len = MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn, + .len = 0, .repeat = 0, }; + + // for dynamic bands, first restore the defined channels before restoring ADR + // this is because the ADR command acts as a mask for the enabled channels + if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + // setup the default channels + state = this->setupChannelsDyn(); + RADIOLIB_ASSERT(state); + + // restore the session channels + uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; + + cmd.cid = RADIOLIB_LW_MAC_NEW_CHANNEL; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn; + memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + cmd.repeat = 1; + (void)execMacCommand(&cmd); + } + } + + uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LW_SESSION_DL_CHANNELS]; + + cmd.cid = RADIOLIB_LW_MAC_DL_CHANNEL; + for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LW_MAC_DL_CHANNEL].lenDn; + memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); + if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes + (void)execMacCommand(&cmd); + } + } + } + + cmd.cid = RADIOLIB_LW_MAC_TX_PARAM_SETUP, + cmd.len = MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn, memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_TX_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); @@ -209,8 +224,26 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass // for fixed bands, first restore ADR, then the defined channels if(this->band->bandType == RADIOLIB_LW_BAND_FIXED) { - state = this->restoreChannels(); + // setup the default channels + state = this->setupChannelsFix(this->subBand); RADIOLIB_ASSERT(state); + + // restore the session channels + uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; + + // there are at most 8 channel masks present + cmd.cid = RADIOLIB_LW_MAC_LINK_ADR; + for(int i = 0; i < 8; i++) { + cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); + // there COULD, according to spec, be an all zeroes ADR command - meh + if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { + break; + } + cmd.repeat = (i+1); + (void)execMacCommand(&cmd); + } + } cmd.cid = RADIOLIB_LW_MAC_DUTY_CYCLE; @@ -241,73 +274,35 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass // copy uplink MAC command queue back in place memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); + // as both the Nonces and session are restored, revert to active session + this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; + return(state); } -int16_t LoRaWANNode::restoreChannels() { - // first do the default channels, in case these are not covered by restored channels - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { - this->setupChannelsDyn(false); - } else { // RADIOLIB_LW_BAND_FIXED - this->setupChannelsFix(this->subBand); - } - - uint8_t bufferZeroes[5] = { 0 }; - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { - uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; - - LoRaWANMacCommand_t cmd = { .cid = RADIOLIB_LW_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0 }; - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn; - memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); - if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes - cmd.repeat = 1; - (void)execMacCommand(&cmd); - } - } - - uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LW_SESSION_DL_CHANNELS]; - - cmd.cid = RADIOLIB_LW_MAC_DL_CHANNEL; - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_DL_CHANNEL].lenDn; - memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); - if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes - (void)execMacCommand(&cmd); - } +int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { + // check if there are actually values in the buffer + size_t i = 0; + for(; i < size; i++) { + if(buffer[i]) { + break; } + } + if(i == size) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } - } else { // RADIOLIB_LW_BAND_FIXED - uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; - - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_LINK_ADR, - .payload = { 0 }, - .len = 0, - .repeat = 0, - }; - - // there are at most 8 channel masks present - for(int i = 0; i < 8; i++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); - // there COULD, according to spec, be an all zeroes ADR command - meh - if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { - break; - } - cmd.repeat = (i+1); - (void)execMacCommand(&cmd); - } + // check integrity of the whole buffer (compare checksum to included checksum) + uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); + uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); + if(signature != checkSum) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04X, expected: %04X", checkSum, signature); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); } return(RADIOLIB_ERR_NONE); } -void LoRaWANNode::beginCommon(uint8_t initialDr) { - // in case a new session is started while there is an ongoing session - // clear the MAC queues completely - memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); - memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); - +void LoRaWANNode::activateCommon(uint8_t initialDr) { uint8_t drUp = 0; if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { // if join datarate is user-specified and valid, select that value @@ -446,36 +441,47 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) { (void)execMacCommand(&cmd); } -int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force, uint8_t joinDr) { - // if not forced and already joined, don't do anything - if(!force && this->isJoined()) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginOTAA(): Did not rejoin: session already active"); - return(RADIOLIB_ERR_NONE); - } +void LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey) { + this->joinEUI = joinEUI; + this->devEUI = devEUI; + memcpy(this->nwkKey, nwkKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->appKey, appKey, RADIOLIB_AES128_KEY_SIZE); - int16_t state = RADIOLIB_ERR_UNKNOWN; - // generate activation key checksum - uint16_t checkSum = 0; - checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); - checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); - checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); - checkSum ^= LoRaWANNode::checkSum16(appKey, 16); + this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); + this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); + this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkKey, 16); + this->keyCheckSum ^= LoRaWANNode::checkSum16(appKey, 16); + + this->clearNonces(); + this->lwMode = RADIOLIB_LW_MODE_OTAA; + this->lwClass = RADIOLIB_LW_CLASS_A; +} - // if The Force is used, disable the active session; - // as a result, restore() will only restore Nonces if they are available, not the session - if(force) { - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; +int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) { + // check if there is an active session + if(this->isActivated()) { + // already activated, don't do anything + return(RADIOLIB_ERR_NONE); + } + if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) { + // session restored but not yet activated - do so now + this->isActive = true; + return(RADIOLIB_LORAWAN_SESSION_RESTORED); } - state = this->restore(checkSum, RADIOLIB_LW_MODE_OTAA, RADIOLIB_LW_CLASS_A, this->band->bandNum); + int16_t state = RADIOLIB_ERR_UNKNOWN; - if(!force) { - return(state); + // either no valid session was found or user forced a new session, so clear all activity + this->clearSession(); + + // starting a new session, so make sure to update event fields already + if(joinEvent) { + joinEvent->newSession = true; + joinEvent->devNonce = this->devNonce; + joinEvent->joinNonce = this->joinNonce; } - Module* mod = this->phyLayer->getMod(); - // setup join-request uplink/downlink frequencies and datarates if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { state = this->setupChannelsDyn(true); @@ -490,7 +496,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe joinDr = RADIOLIB_LW_DATA_RATE_UNUSED; } // setup all MAC properties to default values - this->beginCommon(joinDr); + this->activateCommon(joinDr); // select a random pair of Tx/Rx channels state = this->selectChannels(); @@ -502,29 +508,30 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // copy devNonce currently in use uint16_t devNonceUsed = this->devNonce; - // increment devNonce as we are sending another join-request - this->devNonce += 1; - - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE], this->devNonce); // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN]; // set the packet fields joinRequestMsg[0] = RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LW_MHDR_MAJOR_R1; - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS], devEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS], this->joinEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS], this->devEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code - uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); + uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); // send it + Module* mod = this->phyLayer->getMod(); state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN); this->rxDelayStart = mod->hal->millis(); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); + + // join-request successfully sent, so increase & save devNonce + this->devNonce += 1; + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE], this->devNonce); // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received this->rxDelays[0] = RADIOLIB_LW_JOIN_ACCEPT_DELAY_1_MS; @@ -563,7 +570,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // the first byte is the MAC header which is not encrypted uint8_t joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN]; joinAcceptMsg[0] = joinAcceptMsgEnc[0]; - RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); @@ -592,14 +599,14 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // 1.1 version, first we need to derive the join accept integrity key uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY; - LoRaWANNode::hton(&keyDerivationBuff[1], devEUI); - RadioLibAES128Instance.init(nwkKey); + LoRaWANNode::hton(&keyDerivationBuff[1], this->devEUI); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey); // prepare the buffer for MIC calculation uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; micBuff[0] = RADIOLIB_LW_JOIN_REQUEST_TYPE; - LoRaWANNode::hton(&micBuff[1], joinEUI); + LoRaWANNode::hton(&micBuff[1], this->joinEUI); LoRaWANNode::hton(&micBuff[9], devNonceUsed); memcpy(&micBuff[11], joinAcceptMsg, lenRx); @@ -609,7 +616,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } else { // 1.0 version - if(!verifyMIC(joinAcceptMsg, lenRx, nwkKey)) { + if(!verifyMIC(joinAcceptMsg, lenRx, this->nwkKey)) { return(RADIOLIB_ERR_CRC_MISMATCH); } @@ -650,23 +657,23 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe // check protocol version (1.0 vs 1.1) if(this->rev == 1) { // 1.1 version, derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS], this->joinEUI); LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY; - RadioLibAES128Instance.init(appKey); + RadioLibAES128Instance.init(this->appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY; - RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY; - RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey); keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY; - RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); // enqueue the RekeyInd MAC command to be sent in the next uplink @@ -684,11 +691,11 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY; - RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY; - RadioLibAES128Instance.init(nwkKey); + RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); memcpy(this->sNwkSIntKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); @@ -709,7 +716,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_OTAA); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], this->keyCheckSum); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], this->joinNonce, 3); this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; @@ -718,38 +725,31 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); - return(RADIOLIB_ERR_NONE); -} - -int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force, uint8_t initialDr) { - // if not forced and already joined, don't do anything - if(!force && this->isJoined()) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active"); - return(RADIOLIB_ERR_NONE); - } + // store DevAddr and all keys + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + + // set the signature of the Nonces buffer in the Session buffer + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], signature); - int16_t state = RADIOLIB_ERR_UNKNOWN; + // store network parameters + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev); - // check if we actually need to restart from a clean session - uint16_t checkSum = 0; - checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); - checkSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16); - checkSum ^= LoRaWANNode::checkSum16(appSKey, 16); - if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } - if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } + this->isActive = true; - // if The Force is used, disable the active session; - // as a result, restore() will not restore the session (and there are no Nonces in ABP mode) - if(force) { - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; + // received join-accept, so update JoinNonce value in event + if(joinEvent) { + joinEvent->joinNonce = this->joinNonce; } - state = this->restore(checkSum, RADIOLIB_LW_MODE_ABP, RADIOLIB_LW_CLASS_A, this->band->bandNum); - - if(!force) { - return(state); - } + return(RADIOLIB_LORAWAN_NEW_SESSION); +} +void LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey) { this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); @@ -763,6 +763,34 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } + // generate activation key checksum + this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); + this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16); + this->keyCheckSum ^= LoRaWANNode::checkSum16(appSKey, 16); + if(fNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } + if(sNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } + + // clear & set all the device credentials + this->clearNonces(); + this->lwMode = RADIOLIB_LW_MODE_ABP; + this->lwClass = RADIOLIB_LW_CLASS_A; +} + +int16_t LoRaWANNode::activateABP(uint8_t initialDr) { + // check if there is an active session + if(this->isActivated()) { + // already activated, don't do anything + return(RADIOLIB_ERR_NONE); + } + if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) { + // session restored but not yet activated - do so now + this->isActive = true; + return(RADIOLIB_LORAWAN_SESSION_RESTORED); + } + + // either no valid session was found or user forced a new session, so clear all activity + this->clearSession(); + // setup the uplink/downlink channels and initial datarate if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { this->setupChannelsDyn(); @@ -771,7 +799,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk } // setup all MAC properties to default values - this->beginCommon(initialDr); + this->activateCommon(initialDr); // reset all frame counters this->fCntUp = 0; @@ -786,53 +814,36 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_ABP); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], this->keyCheckSum); + // new session all good, so set active-bit to true this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); - return(RADIOLIB_ERR_NONE); -} - -bool LoRaWANNode::isJoined() { - return(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]); -} - -int16_t LoRaWANNode::saveSession() { // store DevAddr and all keys LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR], this->devAddr); memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - - // copy the signature of the Nonces buffer over to the Session buffer - uint16_t noncesSignature = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE]); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], noncesSignature); + + // set the signature of the Nonces buffer in the Session buffer + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], signature); // store network parameters LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev); - // store all frame counters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN], this->aFCntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN], this->nFCntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP], this->confFCntUp); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN], this->confFCntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT], this->adrFCnt); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP], this->fCntUp); - - // save the current uplink MAC command queue - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + this->isActive = true; - // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LW_SESSION_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_SIGNATURE], signature); + return(RADIOLIB_LORAWAN_NEW_SESSION); +} - return(RADIOLIB_ERR_NONE); +bool LoRaWANNode::isActivated() { + return(this->isActive); } #if defined(RADIOLIB_BUILD_ARDUINO) @@ -847,7 +858,7 @@ int16_t LoRaWANNode::uplink(const char* str, uint8_t fPort, bool isConfirmed, Lo int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { // if not joined, don't do anything - if(!this->isJoined()) { + if(!this->isActivated()) { return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } @@ -1980,6 +1991,9 @@ void LoRaWANNode::setADR(bool enable) { void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { this->dutyCycleEnabled = enable; + if(!enable) { + this->dutyCycle = 0; + } if(msPerHour <= 0) { this->dutyCycle = this->band->dutyCycle; } else { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index f16398e4dd..7a97705d08 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -460,6 +460,21 @@ enum LoRaWANBandNum_t { // array of currently supported bands extern const LoRaWANBand_t* LoRaWANBands[]; +/*! + \struct LoRaWANJoinEvent_t + \brief Structure to save extra information about activation event. +*/ +struct LoRaWANJoinEvent_t { + /*! \brief Whether a new session was started */ + bool newSession = false; + + /*! \brief The transmitted Join-Request DevNonce value */ + uint16_t devNonce = 0; + + /*! \brief The received Join-Request JoinNonce value */ + uint32_t joinNonce = 0; +}; + /*! \struct LoRaWANEvent_t \brief Structure to save extra information about uplink/downlink event. @@ -513,10 +528,9 @@ class LoRaWANNode { LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); /*! - \brief Wipe internal persistent parameters. - This will reset all counters and saved variables, so the device will have to rejoin the network. + \brief Clear an active session, so that the device will have to rejoin the network. */ - void wipe(); + void clearSession(); /*! \brief Returns the pointer to the internal buffer that holds the LW base parameters @@ -545,47 +559,43 @@ class LoRaWANNode { int16_t setBufferSession(uint8_t* persistentBuffer); /*! - \brief Restore session by loading information from persistent storage. - \returns \ref status_codes - */ - int16_t restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan); - - /*! - \brief Join network by performing over-the-air activation. By this procedure, - the device will perform an exchange with the network server and set all necessary configuration. + \brief Set the device credentials and activation configuration \param joinEUI 8-byte application identifier. \param devEUI 8-byte device identifier. \param nwkKey Pointer to the network AES-128 key. \param appKey Pointer to the application AES-128 key. - \param force Set to true to force joining even if previously joined. + */ + void beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey); + + /*! + \brief Join network by restoring OTAA session or performing over-the-air activation. By this procedure, + the device will perform an exchange with the network server and set all necessary configuration. \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LW_DATA_RATE_UNUSED); + int16_t activateOTAA(uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL); /*! - \brief Join network by performing activation by personalization. - In this procedure, all necessary configuration must be provided by the user. + \brief Set the device credentials and activation configuration \param addr Device address. \param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0. \param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0. \param nwkSEncKey Pointer to the MAC command network session key [NwkSEncKey] (LoRaWAN 1.1) or network session AES-128 key [NwkSKey] (LoRaWAN 1.0). \param appSKey Pointer to the application session AES-128 key. - \param force Set to true to force a new session, even if one exists. - \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) - \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force = false, uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED); - - /*! \brief Whether there is an ongoing session active */ - bool isJoined(); + void beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey); /*! - \brief Save the current state of the session to the session buffer. + \brief Join network by restoring ABP session or performing over-the-air activation. + In this procedure, all necessary configuration must be provided by the user. + \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t saveSession(); + int16_t activateABP(uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED); + + /*! \brief Whether there is an ongoing session active */ + bool isActivated(); /*! \brief Add a MAC command to the uplink queue. @@ -850,7 +860,7 @@ class LoRaWANNode { static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); - void beginCommon(uint8_t initialDr); + void activateCommon(uint8_t initialDr); // a buffer that holds all LW base parameters that should persist at all times! uint8_t bufferNonces[RADIOLIB_LW_NONCES_BUF_SIZE] = { 0 }; @@ -869,6 +879,15 @@ class LoRaWANNode { .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, }; + uint16_t lwMode = RADIOLIB_LW_MODE_NONE; + uint8_t lwClass = RADIOLIB_LW_CLASS_A; + bool isActive = false; + + uint64_t joinEUI = 0; + uint64_t devEUI = 0; + uint8_t nwkKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t appKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + // the following is either provided by the network server (OTAA) // or directly entered by the user (ABP) uint32_t devAddr = 0; @@ -877,6 +896,8 @@ class LoRaWANNode { uint8_t sNwkSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + + uint16_t keyCheckSum = 0; // device-specific parameters, persistent through sessions uint16_t devNonce = 0; @@ -956,6 +977,9 @@ class LoRaWANNode { // save the selected sub-band in case this must be restored in ADR control uint8_t subBand = 0; + // this will reset the device credentials, so the device starts completely new + void clearNonces(); + // wait for, open and listen during Rx1 and Rx2 windows; only performs listening int16_t downlinkCommon(); From 84402968c20efbf47fb6e24b0be056bf38cef67f Mon Sep 17 00:00:00 2001 From: lewisxhe Date: Sat, 25 May 2024 10:50:58 +0800 Subject: [PATCH 1110/1848] Fixed SX128X checkOutputPower --- src/modules/SX128x/SX128x.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a51ae78c2b..3132f26f4f 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -792,11 +792,11 @@ int16_t SX128x::setOutputPower(int8_t pwr) { return(setTxParams(this->power)); } -int16_t SX128x::checkOutputPower(int8_t power, int8_t* clipped) { +int16_t SX128x::checkOutputPower(int8_t pwr, int8_t* clipped) { if(clipped) { - *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, power)); + *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, pwr)); } - RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); return(RADIOLIB_ERR_NONE); } From 4a011e0915450eeb813f065331dd515beb7c33fb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 May 2024 07:13:31 +0200 Subject: [PATCH 1111/1848] [SX128x] Fix check output power argument name --- src/modules/SX128x/SX128x.cpp | 2 +- src/modules/SX128x/SX128x.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3132f26f4f..f35ccc264e 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -785,7 +785,7 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { int16_t SX128x::setOutputPower(int8_t pwr) { // check if power value is configurable - int16_t state = checkOutputPower(power, NULL); + int16_t state = checkOutputPower(pwr, NULL); RADIOLIB_ASSERT(state); this->power = pwr + 18; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 706cc62713..1a35228c27 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -630,11 +630,11 @@ class SX128x: public PhysicalLayer { /*! \brief Check if output power is configurable. - \param power Output power in dBm. + \param pwr Output power in dBm. \param clipped Clipped output power value to what is possible within the module's range. \returns \ref status_codes */ - int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + int16_t checkOutputPower(int8_t pwr, int8_t* clipped) override; /*! \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. From 875da9d89da59d2fe7751201824aa0a147393a20 Mon Sep 17 00:00:00 2001 From: HeadBoffin <60431281+HeadBoffin@users.noreply.github.com> Date: Sat, 25 May 2024 06:19:02 +0100 Subject: [PATCH 1112/1848] LW examples updated for new initialisation / join sequence (#1104) * Updated for new initalisation / join sequence * Removed duplicate entry * Pragmatic / conservative disabling on unknown configs with potentially wrong defines - to be investigated at a later date --------- Co-authored-by: Nick McCloud --- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 6 +- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 106 ++++++++++++++--- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 9 +- examples/LoRaWAN/LoRaWAN_Reference/config.h | 107 +++++++++++++++--- .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 11 +- examples/LoRaWAN/LoRaWAN_Starter/config.h | 107 +++++++++++++++--- 6 files changed, 298 insertions(+), 48 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 02ffb7d64e..0fa63de258 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -42,8 +42,10 @@ void setup() { debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); Serial.println(F("Initialise LoRaWAN Network credentials")); - state = node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey, true); - debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Session setup failed"), state, true); + node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey); + + node.activateABP(); + debug(state != RADIOLIB_ERR_NONE, F("Activate ABP failed"), state, true); Serial.println(F("Ready!\n")); } diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index f505800538..ba6ca167ee 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -73,14 +73,25 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma message ("Using Heltec WiFi LoRa32") SX1276 radio = new Module(18, 26, 14, 33); -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1276 radio = new Module(18, 26, 14, 35); + SX1278 radio = new Module(14, 4, 12, 16); + +// Pending verfication of which radio is shipped +// #elif defined(ARDUINO_heltec_wifi_lora_32_V2) +// #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") +// SX1276 radio = new Module(18, 26, 14, 35); -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3") - SX1262 radio = new Module(8, 14, 12, 13); +#elif defined(ARDUINO_heltec_wifi_lora_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +// Following not verified +#elif defined (ARDUINO_heltec_wireless_stick) + #pragma message ("Using Heltec Wireless Stick") + SX1278 radio = new Module(14, 4, 12, 16); + #elif defined (ARDUINO_HELTEC_WIRELESS_STICK) #pragma message ("Using Heltec Wireless Stick") SX1276 radio = new Module(18, 26, 14, 35); @@ -97,14 +108,8 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma message ("Using Heltec Wireless Stick Lite v3") SX1262 radio = new Module(34, 14, 12, 13); -#elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using CubeCell") - SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); - -#elif defined(ARDUINO_CUBECELL_BOARD_V2) - #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") - +// If we don't recognise the board #else #pragma message ("Unknown board - no automagic pinmap available") @@ -113,6 +118,9 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); // SX1278 radio = new Module(10, 2, 9, 3); + + // For Pi Pico + Waveshare HAT - work in progress + // SX1262 radio = new Module(3, 20, 15, 2, SPI1, RADIOLIB_DEFAULT_SPI_SETTINGS); #endif @@ -126,17 +134,89 @@ uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); + +// result code to text ... +String stateDecode(const int16_t result) { + switch (result) { + case RADIOLIB_ERR_NONE: + return "ERR_NONE"; + case RADIOLIB_ERR_CHIP_NOT_FOUND: + return "ERR_CHIP_NOT_FOUND"; + case RADIOLIB_ERR_PACKET_TOO_LONG: + return "ERR_PACKET_TOO_LONG"; + case RADIOLIB_ERR_RX_TIMEOUT: + return "ERR_RX_TIMEOUT"; + case RADIOLIB_ERR_CRC_MISMATCH: + return "ERR_CRC_MISMATCH"; + case RADIOLIB_ERR_INVALID_BANDWIDTH: + return "ERR_INVALID_BANDWIDTH"; + case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: + return "ERR_INVALID_SPREADING_FACTOR"; + case RADIOLIB_ERR_INVALID_CODING_RATE: + return "ERR_INVALID_CODING_RATE"; + case RADIOLIB_ERR_INVALID_FREQUENCY: + return "ERR_INVALID_FREQUENCY"; + case RADIOLIB_ERR_INVALID_OUTPUT_POWER: + return "ERR_INVALID_OUTPUT_POWER"; + case RADIOLIB_ERR_NETWORK_NOT_JOINED: + return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; + + case RADIOLIB_ERR_DOWNLINK_MALFORMED: + return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; + case RADIOLIB_ERR_INVALID_REVISION: + return "RADIOLIB_ERR_INVALID_REVISION"; + case RADIOLIB_ERR_INVALID_PORT: + return "RADIOLIB_ERR_INVALID_PORT"; + case RADIOLIB_ERR_NO_RX_WINDOW: + return "RADIOLIB_ERR_NO_RX_WINDOW"; + case RADIOLIB_ERR_INVALID_CHANNEL: + return "RADIOLIB_ERR_INVALID_CHANNEL"; + case RADIOLIB_ERR_INVALID_CID: + return "RADIOLIB_ERR_INVALID_CID"; + case RADIOLIB_ERR_UPLINK_UNAVAILABLE: + return "RADIOLIB_ERR_UPLINK_UNAVAILABLE"; + case RADIOLIB_ERR_COMMAND_QUEUE_FULL: + return "RADIOLIB_ERR_COMMAND_QUEUE_FULL"; + case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND: + return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; + case RADIOLIB_ERR_JOIN_NONCE_INVALID: + return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; + case RADIOLIB_ERR_N_FCNT_DOWN_INVALID: + return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID"; + case RADIOLIB_ERR_A_FCNT_DOWN_INVALID: + return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID"; + case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: + return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; + case RADIOLIB_ERR_CHECKSUM_MISMATCH: + return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; + case RADIOLIB_LORAWAN_NO_DOWNLINK: + return "RADIOLIB_LORAWAN_NO_DOWNLINK"; + case RADIOLIB_LORAWAN_SESSION_RESTORED: + return "RADIOLIB_LORAWAN_SESSION_RESTORED"; + case RADIOLIB_LORAWAN_NEW_SESSION: + return "RADIOLIB_LORAWAN_NEW_SESSION"; + case RADIOLIB_LORAWAN_NONCES_DISCARDED: + return "RADIOLIB_LORAWAN_NONCES_DISCARDED"; + case RADIOLIB_LORAWAN_SESSION_DISCARDED: + return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; + } + return "See TypeDef.h"; +} + // helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); - Serial.print("("); + Serial.print(" - "); + Serial.print(stateDecode(state)); + Serial.print(" ("); Serial.print(state); Serial.println(")"); while (Freeze); } } + // helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 7e2947a66d..6cfe5dc66b 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -48,8 +48,11 @@ void setup() { // Override the default join rate uint8_t joinDR = 4; - Serial.println(F("Join ('login') to the LoRaWAN Network")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true, joinDR); + // Setup the OTAA session information + node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + Serial.println(F("Join ('login') the LoRaWAN Network")); + state = node.activateOTAA(joinDR); debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); // Print the DevAddr @@ -72,7 +75,7 @@ void setup() { } void loop() { - int state = RADIOLIB_ERR_NONE; + int16_t state = RADIOLIB_ERR_NONE; // set battery fill level - the LoRaWAN network server // may periodically request this information diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index 19eaf57ef5..ace03ce55a 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -68,14 +68,25 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma message ("Using Heltec WiFi LoRa32") SX1276 radio = new Module(18, 26, 14, 33); -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1276 radio = new Module(18, 26, 14, 35); + SX1278 radio = new Module(14, 4, 12, 16); + +// Pending verfication of which radio is shipped +// #elif defined(ARDUINO_heltec_wifi_lora_32_V2) +// #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") +// SX1276 radio = new Module(18, 26, 14, 35); -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3") - SX1262 radio = new Module(8, 14, 12, 13); +#elif defined(ARDUINO_heltec_wifi_lora_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +// Following not verified +#elif defined (ARDUINO_heltec_wireless_stick) + #pragma message ("Using Heltec Wireless Stick") + SX1278 radio = new Module(14, 4, 12, 16); + #elif defined (ARDUINO_HELTEC_WIRELESS_STICK) #pragma message ("Using Heltec Wireless Stick") SX1276 radio = new Module(18, 26, 14, 35); @@ -92,14 +103,8 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma message ("Using Heltec Wireless Stick Lite v3") SX1262 radio = new Module(34, 14, 12, 13); -#elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using CubeCell") - SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); - -#elif defined(ARDUINO_CUBECELL_BOARD_V2) - #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") - +// If we don't recognise the board #else #pragma message ("Unknown board - no automagic pinmap available") @@ -108,6 +113,9 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); // SX1278 radio = new Module(10, 2, 9, 3); + + // For Pi Pico + Waveshare HAT - work in progress + // SX1262 radio = new Module(3, 20, 15, 2, SPI1, RADIOLIB_DEFAULT_SPI_SETTINGS); #endif @@ -120,17 +128,89 @@ uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); + +// result code to text ... +String stateDecode(const int16_t result) { + switch (result) { + case RADIOLIB_ERR_NONE: + return "ERR_NONE"; + case RADIOLIB_ERR_CHIP_NOT_FOUND: + return "ERR_CHIP_NOT_FOUND"; + case RADIOLIB_ERR_PACKET_TOO_LONG: + return "ERR_PACKET_TOO_LONG"; + case RADIOLIB_ERR_RX_TIMEOUT: + return "ERR_RX_TIMEOUT"; + case RADIOLIB_ERR_CRC_MISMATCH: + return "ERR_CRC_MISMATCH"; + case RADIOLIB_ERR_INVALID_BANDWIDTH: + return "ERR_INVALID_BANDWIDTH"; + case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: + return "ERR_INVALID_SPREADING_FACTOR"; + case RADIOLIB_ERR_INVALID_CODING_RATE: + return "ERR_INVALID_CODING_RATE"; + case RADIOLIB_ERR_INVALID_FREQUENCY: + return "ERR_INVALID_FREQUENCY"; + case RADIOLIB_ERR_INVALID_OUTPUT_POWER: + return "ERR_INVALID_OUTPUT_POWER"; + case RADIOLIB_ERR_NETWORK_NOT_JOINED: + return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; + + case RADIOLIB_ERR_DOWNLINK_MALFORMED: + return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; + case RADIOLIB_ERR_INVALID_REVISION: + return "RADIOLIB_ERR_INVALID_REVISION"; + case RADIOLIB_ERR_INVALID_PORT: + return "RADIOLIB_ERR_INVALID_PORT"; + case RADIOLIB_ERR_NO_RX_WINDOW: + return "RADIOLIB_ERR_NO_RX_WINDOW"; + case RADIOLIB_ERR_INVALID_CHANNEL: + return "RADIOLIB_ERR_INVALID_CHANNEL"; + case RADIOLIB_ERR_INVALID_CID: + return "RADIOLIB_ERR_INVALID_CID"; + case RADIOLIB_ERR_UPLINK_UNAVAILABLE: + return "RADIOLIB_ERR_UPLINK_UNAVAILABLE"; + case RADIOLIB_ERR_COMMAND_QUEUE_FULL: + return "RADIOLIB_ERR_COMMAND_QUEUE_FULL"; + case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND: + return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; + case RADIOLIB_ERR_JOIN_NONCE_INVALID: + return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; + case RADIOLIB_ERR_N_FCNT_DOWN_INVALID: + return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID"; + case RADIOLIB_ERR_A_FCNT_DOWN_INVALID: + return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID"; + case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: + return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; + case RADIOLIB_ERR_CHECKSUM_MISMATCH: + return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; + case RADIOLIB_LORAWAN_NO_DOWNLINK: + return "RADIOLIB_LORAWAN_NO_DOWNLINK"; + case RADIOLIB_LORAWAN_SESSION_RESTORED: + return "RADIOLIB_LORAWAN_SESSION_RESTORED"; + case RADIOLIB_LORAWAN_NEW_SESSION: + return "RADIOLIB_LORAWAN_NEW_SESSION"; + case RADIOLIB_LORAWAN_NONCES_DISCARDED: + return "RADIOLIB_LORAWAN_NONCES_DISCARDED"; + case RADIOLIB_LORAWAN_SESSION_DISCARDED: + return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; + } + return "See TypeDef.h"; +} + // helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); - Serial.print("("); + Serial.print(" - "); + Serial.print(stateDecode(state)); + Serial.print(" ("); Serial.print(state); Serial.println(")"); while (Freeze); } } + // helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { @@ -141,4 +221,5 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } + #endif diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 6b8025726f..07ba7038e3 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -31,11 +31,14 @@ void setup() { Serial.println(F("\nSetup ... ")); Serial.println(F("Initialise the radio")); - int state = radio.begin(); + int16_t state = radio.begin(); debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); - Serial.println(F("Join ('login') to the LoRaWAN Network")); - state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + // Setup the OTAA session information + node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + Serial.println(F("Join ('login') the LoRaWAN Network")); + state = node.activateOTAA(); debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); Serial.println(F("Ready!\n")); @@ -56,7 +59,7 @@ void loop() { uplinkPayload[2] = lowByte(value2); // Perform an uplink - int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + int16_t state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); Serial.print(F("Uplink complete, next in ")); diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index 19eaf57ef5..ace03ce55a 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -68,14 +68,25 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma message ("Using Heltec WiFi LoRa32") SX1276 radio = new Module(18, 26, 14, 33); -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1276 radio = new Module(18, 26, 14, 35); + SX1278 radio = new Module(14, 4, 12, 16); + +// Pending verfication of which radio is shipped +// #elif defined(ARDUINO_heltec_wifi_lora_32_V2) +// #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") +// SX1276 radio = new Module(18, 26, 14, 35); -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3") - SX1262 radio = new Module(8, 14, 12, 13); +#elif defined(ARDUINO_heltec_wifi_lora_32_V3) + #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") + SX1262 radio = new Module(8, 14, 12, 13); + +// Following not verified +#elif defined (ARDUINO_heltec_wireless_stick) + #pragma message ("Using Heltec Wireless Stick") + SX1278 radio = new Module(14, 4, 12, 16); + #elif defined (ARDUINO_HELTEC_WIRELESS_STICK) #pragma message ("Using Heltec Wireless Stick") SX1276 radio = new Module(18, 26, 14, 35); @@ -92,14 +103,8 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 #pragma message ("Using Heltec Wireless Stick Lite v3") SX1262 radio = new Module(34, 14, 12, 13); -#elif defined(ARDUINO_CUBECELL_BOARD) - #pragma message ("Using CubeCell") - SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); - -#elif defined(ARDUINO_CUBECELL_BOARD_V2) - #pragma error ("ARDUINO_CUBECELL_BOARD_V2 awaiting pin map") - +// If we don't recognise the board #else #pragma message ("Unknown board - no automagic pinmap available") @@ -108,6 +113,9 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); // SX1278 radio = new Module(10, 2, 9, 3); + + // For Pi Pico + Waveshare HAT - work in progress + // SX1262 radio = new Module(3, 20, 15, 2, SPI1, RADIOLIB_DEFAULT_SPI_SETTINGS); #endif @@ -120,17 +128,89 @@ uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); + +// result code to text ... +String stateDecode(const int16_t result) { + switch (result) { + case RADIOLIB_ERR_NONE: + return "ERR_NONE"; + case RADIOLIB_ERR_CHIP_NOT_FOUND: + return "ERR_CHIP_NOT_FOUND"; + case RADIOLIB_ERR_PACKET_TOO_LONG: + return "ERR_PACKET_TOO_LONG"; + case RADIOLIB_ERR_RX_TIMEOUT: + return "ERR_RX_TIMEOUT"; + case RADIOLIB_ERR_CRC_MISMATCH: + return "ERR_CRC_MISMATCH"; + case RADIOLIB_ERR_INVALID_BANDWIDTH: + return "ERR_INVALID_BANDWIDTH"; + case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: + return "ERR_INVALID_SPREADING_FACTOR"; + case RADIOLIB_ERR_INVALID_CODING_RATE: + return "ERR_INVALID_CODING_RATE"; + case RADIOLIB_ERR_INVALID_FREQUENCY: + return "ERR_INVALID_FREQUENCY"; + case RADIOLIB_ERR_INVALID_OUTPUT_POWER: + return "ERR_INVALID_OUTPUT_POWER"; + case RADIOLIB_ERR_NETWORK_NOT_JOINED: + return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; + + case RADIOLIB_ERR_DOWNLINK_MALFORMED: + return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; + case RADIOLIB_ERR_INVALID_REVISION: + return "RADIOLIB_ERR_INVALID_REVISION"; + case RADIOLIB_ERR_INVALID_PORT: + return "RADIOLIB_ERR_INVALID_PORT"; + case RADIOLIB_ERR_NO_RX_WINDOW: + return "RADIOLIB_ERR_NO_RX_WINDOW"; + case RADIOLIB_ERR_INVALID_CHANNEL: + return "RADIOLIB_ERR_INVALID_CHANNEL"; + case RADIOLIB_ERR_INVALID_CID: + return "RADIOLIB_ERR_INVALID_CID"; + case RADIOLIB_ERR_UPLINK_UNAVAILABLE: + return "RADIOLIB_ERR_UPLINK_UNAVAILABLE"; + case RADIOLIB_ERR_COMMAND_QUEUE_FULL: + return "RADIOLIB_ERR_COMMAND_QUEUE_FULL"; + case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND: + return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; + case RADIOLIB_ERR_JOIN_NONCE_INVALID: + return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; + case RADIOLIB_ERR_N_FCNT_DOWN_INVALID: + return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID"; + case RADIOLIB_ERR_A_FCNT_DOWN_INVALID: + return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID"; + case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: + return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; + case RADIOLIB_ERR_CHECKSUM_MISMATCH: + return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; + case RADIOLIB_LORAWAN_NO_DOWNLINK: + return "RADIOLIB_LORAWAN_NO_DOWNLINK"; + case RADIOLIB_LORAWAN_SESSION_RESTORED: + return "RADIOLIB_LORAWAN_SESSION_RESTORED"; + case RADIOLIB_LORAWAN_NEW_SESSION: + return "RADIOLIB_LORAWAN_NEW_SESSION"; + case RADIOLIB_LORAWAN_NONCES_DISCARDED: + return "RADIOLIB_LORAWAN_NONCES_DISCARDED"; + case RADIOLIB_LORAWAN_SESSION_DISCARDED: + return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; + } + return "See TypeDef.h"; +} + // helper function to display any issues void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { if (isFail) { Serial.print(message); - Serial.print("("); + Serial.print(" - "); + Serial.print(stateDecode(state)); + Serial.print(" ("); Serial.print(state); Serial.println(")"); while (Freeze); } } + // helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { @@ -141,4 +221,5 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } + #endif From fe221cf84fced24abd4e2061cc9c5a1782445da9 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 13:00:02 +0200 Subject: [PATCH 1113/1848] [LoRaWAN] Revert `LW` to `LORAWAN` --- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 4 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 958 +++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 466 ++++----- src/protocols/LoRaWAN/LoRaWANBands.cpp | 408 ++++---- 4 files changed, 918 insertions(+), 918 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 6cfe5dc66b..54e0c2be28 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -114,8 +114,8 @@ void loop() { // and also request the LinkCheck and DeviceTime MAC commands if(fcntUp % 64 == 0) { Serial.println(F("[LoRaWAN] Requesting LinkCheck and DeviceTime")); - node.sendMacCommandReq(RADIOLIB_LW_MAC_LINK_CHECK); - node.sendMacCommandReq(RADIOLIB_LW_MAC_DEVICE_TIME); + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails); } else { state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c28a226eb5..deab820984 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -46,7 +46,7 @@ void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA void LoRaWANNode::clearNonces() { // clear & set all the device credentials - memset(this->bufferNonces, 0, RADIOLIB_LW_NONCES_BUF_SIZE); + memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); this->keyCheckSum = 0; this->devNonce = 0; this->joinNonce = 0; @@ -54,17 +54,17 @@ void LoRaWANNode::clearNonces() { } void LoRaWANNode::clearSession() { - memset(this->bufferSession, 0, RADIOLIB_LW_SESSION_BUF_SIZE); + memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; this->isActive = false; } uint8_t* LoRaWANNode::getBufferNonces() { // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); return(this->bufferNonces); } @@ -75,31 +75,31 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { return(RADIOLIB_ERR_NONE); } - int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); RADIOLIB_ASSERT(state); - bool isSameKeys = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_CHECKSUM]) == this->keyCheckSum; - bool isSameMode = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_MODE]) == this->lwMode; - bool isSameClass = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_CLASS]) == this->lwClass; - bool isSamePlan = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_NONCES_PLAN]) == this->band->bandNum; + bool isSameKeys = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == this->keyCheckSum; + bool isSameMode = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_MODE]) == this->lwMode; + bool isSameClass = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_CLASS]) == this->lwClass; + bool isSamePlan = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_PLAN]) == this->band->bandNum; // check if Nonces buffer matches the current configuration if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { // if configuration did not match, discard whatever is currently in the buffers and start fresh RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Discarding the Nonces buffer:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); return(RADIOLIB_LORAWAN_NONCES_DISCARDED); } // copy the whole buffer over - memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE); + memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); - this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE]); - this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], 3); + this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); + this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); // revert to inactive as long as no session is restored - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false; + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; this->isActive = false; return(state); @@ -107,19 +107,19 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { uint8_t* LoRaWANNode::getBufferSession() { // store all frame counters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN], this->aFCntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN], this->nFCntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP], this->confFCntUp); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN], this->confFCntDown); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT], this->adrFCnt); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP], this->fCntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN], this->aFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN], this->nFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP], this->confFCntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFCntDown); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFCnt); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp); // save the current uplink MAC command queue - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LW_SESSION_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); return(this->bufferSession); } @@ -130,48 +130,48 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { return(RADIOLIB_ERR_NONE); } - int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_SESSION_BUF_SIZE); + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); RADIOLIB_ASSERT(state); // the Nonces buffer holds a checksum signature - compare this to the signature that is in the session buffer - uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE]); - uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LW_SESSION_NONCES_SIGNATURE]); + uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); + uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE]); if(signatureNonces != signatureInSession) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); return(RADIOLIB_LORAWAN_SESSION_DISCARDED); } // copy the whole buffer over - memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LW_SESSION_BUF_SIZE); + memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); //// this code can be used in case breaking chances must be caught: - // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LW_NONCES_VERSION]; - // if (RADIOLIB_LW_NONCES_VERSION_VAL > nvm_table_version) { + // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; + // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { // // set default values for variables that are new or something // } // pull all authentication keys from persistent storage - this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR]); - memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); + memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); // restore session parameters - this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION]); + this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); - this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID]); - this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_A_FCNT_DOWN]); - this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_N_FCNT_DOWN]); - this->confFCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_UP]); - this->confFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_CONF_FCNT_DOWN]); - this->adrFCnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_FCNT]); - this->fCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LW_SESSION_FCNT_UP]); + this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); + this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); + this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); + this->confFCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); + this->confFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); + this->adrFCnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); + this->fCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); // restore the complete MAC state // all-zero buffer used for checking if MAC commands are set - uint8_t bufferZeroes[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + uint8_t bufferZeroes[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; LoRaWANMacCommand_t cmd = { .cid = 0, @@ -182,17 +182,17 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { // for dynamic bands, first restore the defined channels before restoring ADR // this is because the ADR command acts as a mask for the enabled channels - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // setup the default channels state = this->setupChannelsDyn(); RADIOLIB_ASSERT(state); // restore the session channels - uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; + uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; - cmd.cid = RADIOLIB_LW_MAC_NEW_CHANNEL; - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn; + cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes cmd.repeat = 1; @@ -200,11 +200,11 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { } } - uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LW_SESSION_DL_CHANNELS]; + uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; - cmd.cid = RADIOLIB_LW_MAC_DL_CHANNEL; - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_DL_CHANNEL].lenDn; + cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes (void)execMacCommand(&cmd); @@ -212,29 +212,29 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { } } - cmd.cid = RADIOLIB_LW_MAC_TX_PARAM_SETUP, - cmd.len = MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn, - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_TX_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cmd.len); (void)execMacCommand(&cmd); // for fixed bands, first restore ADR, then the defined channels - if(this->band->bandType == RADIOLIB_LW_BAND_FIXED) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { // setup the default channels state = this->setupChannelsFix(this->subBand); RADIOLIB_ASSERT(state); // restore the session channels - uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS]; + uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; // there are at most 8 channel masks present - cmd.cid = RADIOLIB_LW_MAC_LINK_ADR; + cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; for(int i = 0; i < 8; i++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); // there COULD, according to spec, be an all zeroes ADR command - meh if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { @@ -246,36 +246,36 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { } - cmd.cid = RADIOLIB_LW_MAC_DUTY_CYCLE; - cmd.len = MacTable[RADIOLIB_LW_MAC_DUTY_CYCLE].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_DUTY_CYCLE], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_RX_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_RX_TIMING_SETUP], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_ADR_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_ADR_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_ADR_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP], cmd.len); + cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; + memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd.len); (void)execMacCommand(&cmd); // copy uplink MAC command queue back in place - memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LW_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); // as both the Nonces and session are restored, revert to active session - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; return(state); } @@ -304,46 +304,46 @@ int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { void LoRaWANNode::activateCommon(uint8_t initialDr) { uint8_t drUp = 0; - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // if join datarate is user-specified and valid, select that value - if(initialDr != RADIOLIB_LW_DATA_RATE_UNUSED) { + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { if(initialDr >= this->band->txFreqs[0].drMin && initialDr <= this->band->txFreqs[0].drMax) { drUp = initialDr; } else { // if there is no channel that allowed the user-specified datarate, revert to default datarate RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LW_DATA_RATE_UNUSED; + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; } } // if there is no (channel that allowed the) user-specified datarate, use a default datarate // we use the floor of the average datarate of the first default channel - if(initialDr == RADIOLIB_LW_DATA_RATE_UNUSED) { + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; } } else { // if the user specified a certain datarate, check if any of the configured channels allows it - if(initialDr != RADIOLIB_LW_DATA_RATE_UNUSED) { + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { uint8_t i = 0; - for(; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { - if(initialDr >= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin - && initialDr <= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax) { + for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(initialDr >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && initialDr <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { break; } } } // if there is no channel that allowed the user-specified datarate, revert to default datarate - if(i == RADIOLIB_LW_NUM_AVAILABLE_CHANNELS) { + if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LW_DATA_RATE_UNUSED; + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; } } // if there is no (channel that allowed the) user-specified datarate, use a default datarate // we use the join-request datarate for one of the available channels - if(initialDr == RADIOLIB_LW_DATA_RATE_UNUSED) { + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // randomly select one of 8 or 9 channels and find corresponding datarate uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 @@ -357,9 +357,9 @@ void LoRaWANNode::activateCommon(uint8_t initialDr) { } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_LINK_ADR, + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, - .len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, .repeat = 0, }; cmd.payload[0] = (drUp << 4); // set uplink datarate @@ -367,8 +367,8 @@ void LoRaWANNode::activateCommon(uint8_t initialDr) { cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_DUTY_CYCLE; - cmd.len = MacTable[RADIOLIB_LW_MAC_DUTY_CYCLE].lenDn; + cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; uint8_t maxDCyclePower; switch(this->band->dutyCycle) { case(0): @@ -387,21 +387,21 @@ void LoRaWANNode::activateCommon(uint8_t initialDr) { cmd.payload[0] = maxDCyclePower; (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LW_RX1_DR_OFFSET << 4); + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); cmd.payload[0] |= this->rx2.drMax; // may be set by user, otherwise band's default upon initialization uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LW_RECEIVE_DELAY_1_MS / 1000); + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_TX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn; + cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; cmd.payload[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; cmd.payload[0] |= (this->band->dwellTimeUp > 0 ? 1 : 0) << 4; uint8_t maxEIRPRaw; @@ -428,16 +428,16 @@ void LoRaWANNode::activateCommon(uint8_t initialDr) { cmd.payload[0] |= maxEIRPRaw; (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_ADR_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_ADR_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LW_ADR_ACK_LIMIT_EXP << 4); - cmd.payload[0] |= RADIOLIB_LW_ADR_ACK_DELAY_EXP; + cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); + cmd.payload[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LW_REJOIN_MAX_TIME_N << 4); - cmd.payload[0] |= RADIOLIB_LW_REJOIN_MAX_COUNT_N; + cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; + cmd.payload[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); + cmd.payload[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; (void)execMacCommand(&cmd); } @@ -454,8 +454,8 @@ void LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, this->keyCheckSum ^= LoRaWANNode::checkSum16(appKey, 16); this->clearNonces(); - this->lwMode = RADIOLIB_LW_MODE_OTAA; - this->lwClass = RADIOLIB_LW_CLASS_A; + this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA; + this->lwClass = RADIOLIB_LORAWAN_CLASS_A; } int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) { @@ -464,7 +464,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // already activated, don't do anything return(RADIOLIB_ERR_NONE); } - if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) { + if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) { // session restored but not yet activated - do so now this->isActive = true; return(RADIOLIB_LORAWAN_SESSION_RESTORED); @@ -483,7 +483,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } // setup join-request uplink/downlink frequencies and datarates - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { state = this->setupChannelsDyn(true); } else { state = this->setupChannelsFix(this->subBand); @@ -492,8 +492,8 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // on fixed bands, the join-datarate is specified per specification // therefore, we ignore the value that was specified by the user - if(this->band->bandType == RADIOLIB_LW_BAND_FIXED) { - joinDr = RADIOLIB_LW_DATA_RATE_UNUSED; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; } // setup all MAC properties to default values this->activateCommon(joinDr); @@ -503,51 +503,51 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RADIOLIB_ASSERT(state); // set the physical layer configuration for uplink - state = this->setPhyProperties(RADIOLIB_LW_CHANNEL_DIR_UPLINK); + state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // copy devNonce currently in use uint16_t devNonceUsed = this->devNonce; // build the join-request message - uint8_t joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN]; + uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; // set the packet fields - joinRequestMsg[0] = RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LW_MHDR_MAJOR_R1; - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS], this->joinEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS], this->devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); + joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], this->joinEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], this->devEUI); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code - uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); + uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); // send it Module* mod = this->phyLayer->getMod(); - state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN); + state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); this->rxDelayStart = mod->hal->millis(); RADIOLIB_ASSERT(state); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); // join-request successfully sent, so increase & save devNonce this->devNonce += 1; - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_DEV_NONCE], this->devNonce); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received - this->rxDelays[0] = RADIOLIB_LW_JOIN_ACCEPT_DELAY_1_MS; - this->rxDelays[1] = RADIOLIB_LW_JOIN_ACCEPT_DELAY_2_MS; + this->rxDelays[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; + this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received state = downlinkCommon(); RADIOLIB_ASSERT(state); // build the buffer for the reply data - uint8_t joinAcceptMsgEnc[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN]; + uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; // check received length size_t lenRx = this->phyLayer->getPacketLength(true); - if((lenRx != RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN, lenRx); + if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -560,24 +560,24 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } // check reply message type - if((joinAcceptMsgEnc[0] & RADIOLIB_LW_MHDR_MTYPE_MASK) != RADIOLIB_LW_MHDR_MTYPE_JOIN_ACCEPT) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LW_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } // decrypt the join accept message // this is done by encrypting again in ECB mode // the first byte is the MAC header which is not encrypted - uint8_t joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN]; + uint8_t joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; joinAcceptMsg[0] = joinAcceptMsgEnc[0]; RadioLibAES128Instance.init(this->nwkKey); - RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); + RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); // get current JoinNonce from downlink and previous JoinNonce from persistent storage - uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); // JoinNonce received must be greater than the last JoinNonce heard, else error @@ -586,26 +586,26 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } this->joinNonce = joinNonceNew; - this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], 3); - this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS]); + this->homeNetId = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); + this->devAddr = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); // check LoRaWAN revision (the MIC verification depends on this) - uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_DL_SETTINGS_POS]; - this->rev = (dlSettings & RADIOLIB_LW_JOIN_ACCEPT_R_1_1) >> 7; + uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; + this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN revision: 1.%d", this->rev); // verify MIC if(this->rev == 1) { // 1.1 version, first we need to derive the join accept integrity key uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY; LoRaWANNode::hton(&keyDerivationBuff[1], this->devEUI); RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey); // prepare the buffer for MIC calculation uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - micBuff[0] = RADIOLIB_LW_JOIN_REQUEST_TYPE; + micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], this->joinEUI); LoRaWANNode::hton(&micBuff[9], devNonceUsed); memcpy(&micBuff[11], joinAcceptMsg, lenRx); @@ -623,9 +623,9 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_RX_PARAM_SETUP, + .cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, .payload = { 0 }, - .len = MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn, + .len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, .repeat = 0, }; cmd.payload[0] = dlSettings & 0x7F; @@ -633,68 +633,68 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); (void)execMacCommand(&cmd); - cmd.cid = RADIOLIB_LW_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn; - cmd.payload[0] = joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_RX_DELAY_POS]; + cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; (void)execMacCommand(&cmd); // in case of dynamic band, setup the default channels first - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(false); } // process CFlist if present - if(lenRx == RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN) { - uint8_t cfList[RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; - memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN); + if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { + uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; + memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); this->processCFList(cfList); } // if no CFList was received, default or subband are already setup so don't need to do anything else // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); // check protocol version (1.0 vs 1.1) if(this->rev == 1) { // 1.1 version, derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS], this->joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], this->joinEUI); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(this->appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY; RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey); - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY; RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); // enqueue the RekeyInd MAC command to be sent in the next uplink LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_REKEY, + .cid = RADIOLIB_LORAWAN_MAC_REKEY, .payload = { this->rev }, .len = sizeof(uint8_t), - .repeat = 0x01 << RADIOLIB_LW_ADR_ACK_LIMIT_EXP, + .repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP, }; state = pushMacCommand(&cmd, &this->commandsUp); RADIOLIB_ASSERT(state); } else { // 1.0 version, just derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY; + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); - keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY; + keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); @@ -707,37 +707,37 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->fCntUp = 0; this->aFCntDown = 0; this->nFCntDown = 0; - this->confFCntUp = RADIOLIB_LW_FCNT_NONE; - this->confFCntDown = RADIOLIB_LW_FCNT_NONE; + this->confFCntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_VERSION], RADIOLIB_LW_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_OTAA); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], this->keyCheckSum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], this->joinNonce, 3); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_OTAA); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); // store DevAddr and all keys - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR], this->devAddr); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); // set the signature of the Nonces buffer in the Session buffer - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], signature); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); // store network parameters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); this->isActive = true; @@ -772,8 +772,8 @@ void LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIn // clear & set all the device credentials this->clearNonces(); - this->lwMode = RADIOLIB_LW_MODE_ABP; - this->lwClass = RADIOLIB_LW_CLASS_A; + this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; + this->lwClass = RADIOLIB_LORAWAN_CLASS_A; } int16_t LoRaWANNode::activateABP(uint8_t initialDr) { @@ -782,7 +782,7 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { // already activated, don't do anything return(RADIOLIB_ERR_NONE); } - if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) { + if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) { // session restored but not yet activated - do so now this->isActive = true; return(RADIOLIB_LORAWAN_SESSION_RESTORED); @@ -792,7 +792,7 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { this->clearSession(); // setup the uplink/downlink channels and initial datarate - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(); } else { this->setupChannelsFix(this->subBand); @@ -805,37 +805,37 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { this->fCntUp = 0; this->aFCntDown = 0; this->nFCntDown = 0; - this->confFCntUp = RADIOLIB_LW_FCNT_NONE; - this->confFCntDown = RADIOLIB_LW_FCNT_NONE; + this->confFCntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; // save the activation keys checksum, mode, class, frequency plan - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_VERSION], RADIOLIB_LW_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_ABP); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], this->keyCheckSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_ABP); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); // new session all good, so set active-bit to true - this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true; + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE], signature); + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); // store DevAddr and all keys - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_DEV_ADDR], this->devAddr); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); // set the signature of the Nonces buffer in the Session buffer - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], signature); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); // store network parameters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); this->isActive = true; @@ -881,7 +881,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon return(RADIOLIB_ERR_INVALID_PORT); } // fPort 0 is only allowed for MAC-only payloads - if(fPort == RADIOLIB_LW_FPORT_MAC_COMMAND) { + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { if (!this->isMACPayload) { return(RADIOLIB_ERR_INVALID_PORT); } @@ -893,16 +893,16 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) uint8_t fOptsLen = 0; - if(this->commandsUp.numCommands > 0 && fPort != RADIOLIB_LW_FPORT_MAC_COMMAND) { + if(this->commandsUp.numCommands > 0 && fPort != RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { // there are, assume the maximum possible FOpts len for buffer allocation fOptsLen = this->commandsUp.len; } // check maximum payload len as defined in phy - if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]]) { + if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { return(RADIOLIB_ERR_PACKET_TOO_LONG); // if testing with TS009 specification verification protocol, don't throw error but clip the message - // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]]; + // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; } bool adrAckReq = false; @@ -936,8 +936,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon break; case(2): { // try to decrease the datarate - if(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] > 0) { - if(this->setDatarate(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { + if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { adrStage = 0; // successfully did some ADR stuff } } @@ -947,7 +947,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon } break; case(3): { - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(false); // revert to default frequencies } else { // go back to default selected subband @@ -967,17 +967,17 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon // set the physical layer configuration for uplink this->selectChannels(); - state = this->setPhyProperties(RADIOLIB_LW_CHANNEL_DIR_UPLINK); + state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); // if dwell time is imposed, calculated expected time on air and cancel if exceeds - if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LW_FRAME_LEN(len, fOptsLen) - 16)/1000 > this->dwellTimeUp) { + if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen) - 16)/1000 > this->dwellTimeUp) { return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } // build the uplink message // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, fOptsLen); + size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen); #if RADIOLIB_STATIC_ONLY uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; #else @@ -986,36 +986,36 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon // set the packet fields if(isConfirmed) { - uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] = RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_UP; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; this->confFCntUp = this->fCntUp; } else { - uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] = RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_UP; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP; } - uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] |= RADIOLIB_LW_MHDR_MAJOR_R1; - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS], this->devAddr); + uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] |= RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); // length of fOpts will be added later - uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] = 0x00; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; if(this->adrEnabled) { - uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ADR_ENABLED; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; if(adrAckReq) { - uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ADR_ACK_REQ; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; } } // if the saved confirm-fCnt is set, set the ACK bit bool isConfirmingDown = false; - if(this->confFCntDown != RADIOLIB_LW_FCNT_NONE) { + if(this->confFCntDown != RADIOLIB_LORAWAN_FCNT_NONE) { isConfirmingDown = true; - uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= RADIOLIB_LW_FCTRL_ACK; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; } - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LW_FHDR_FCNT_POS], (uint16_t)this->fCntUp); + LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fCntUp); // check if we have some MAC commands to append if(fOptsLen > 0) { // assume maximum possible buffer size - uint8_t fOptsBuff[RADIOLIB_LW_FHDR_FOPTS_MAX_LEN]; + uint8_t fOptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; uint8_t* fOptsPtr = fOptsBuff; // append all MAC replies into fOpts buffer @@ -1037,41 +1037,41 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon } } - uplinkMsgLen = RADIOLIB_LW_FRAME_LEN(len, fOptsLen); - uplinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] |= fOptsLen; + uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen); + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= fOptsLen; // encrypt it - processAES(fOptsBuff, fOptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x01, true); + processAES(fOptsBuff, fOptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); } // set the fPort - uplinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)] = fPort; + uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsLen)] = fPort; // select encryption key based on the target fPort uint8_t* encKey = this->appSKey; - if(fPort == RADIOLIB_LW_FPORT_MAC_COMMAND) { + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { encKey = this->nwkSEncKey; } // encrypt the frame payload - processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(fOptsLen)], this->fCntUp, RADIOLIB_LW_CHANNEL_DIR_UPLINK, 0x00, true); + processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - block0[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; - block0[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_UPLINK; - LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&block0[RADIOLIB_LW_BLOCK_FCNT_POS], this->fCntUp); - block0[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); + block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; + block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], this->fCntUp); + block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); - if(this->confFCntDown != RADIOLIB_LW_FCNT_NONE) { - LoRaWANNode::hton(&block1[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntDown); + if(this->confFCntDown != RADIOLIB_LORAWAN_FCNT_NONE) { + LoRaWANNode::hton(&block1[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntDown); } - block1[RADIOLIB_LW_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; - block1[RADIOLIB_LW_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK].idx; + block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; + block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %d) decoded:", this->fCntUp); @@ -1097,14 +1097,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon } // send it (without the MIC calculation blocks) - state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LW_FHDR_LEN_START_OFFS); + state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); // set the timestamp so that we can measure when to start receiving this->rxDelayStart = mod->hal->millis(); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); // calculate Time on Air of this uplink in milliseconds - this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LW_FHDR_LEN_START_OFFS) / 1000; + this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; #if !RADIOLIB_STATIC_ONLY delete[] uplinkMsg; @@ -1112,14 +1112,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon RADIOLIB_ASSERT(state); // the downlink confirmation was acknowledged, so clear the counter value - this->confFCntDown = RADIOLIB_LW_FCNT_NONE; + this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; // pass the extra info if requested if(event) { - event->dir = RADIOLIB_LW_CHANNEL_DIR_UPLINK; + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; event->confirmed = isConfirmed; event->confirming = isConfirmingDown; - event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK]; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerSteps * 2; event->fCnt = this->fCntUp; @@ -1153,7 +1153,7 @@ int16_t LoRaWANNode::downlinkCommon() { } // set the physical layer configuration for downlink - int16_t state = this->setPhyProperties(RADIOLIB_LW_CHANNEL_DIR_DOWNLINK); + int16_t state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); RADIOLIB_ASSERT(state); // create the masks that are required for receiving downlinks @@ -1299,7 +1299,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a fPort - if(downlinkMsgLen < RADIOLIB_LW_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { + if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -1328,7 +1328,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // check the address - uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_DEV_ADDR_POS]); + uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); #if !RADIOLIB_STATIC_ONLY @@ -1338,11 +1338,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // calculate length of FOpts and payload - uint8_t fOptsLen = downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FHDR_FOPTS_LEN_MASK; + uint8_t fOptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; // check if the ACK bit is set, indicating this frame acknowledges the previous uplink bool isConfirmingUp = false; - if((downlinkMsg[RADIOLIB_LW_FHDR_FCTRL_POS] & RADIOLIB_LW_FCTRL_ACK)) { + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK)) { isConfirmingUp = true; } @@ -1351,19 +1351,19 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t payLen = downlinkMsgLen - 1 - 4 - 1 - 2 - fOptsLen - 4; // get the frame counter - uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LW_FHDR_FCNT_POS]); + uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); // set the MIC calculation blocks memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); - downlinkMsg[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_MIC_BLOCK_MAGIC; + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; // if this downlink is confirming an uplink, the MIC was generated with the least-significant 16 bits of that fCntUp if(isConfirmingUp && (this->rev == 1)) { - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); } - downlinkMsg[RADIOLIB_LW_BLOCK_DIR_POS] = RADIOLIB_LW_CHANNEL_DIR_DOWNLINK; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LW_BLOCK_FCNT_POS], fCnt16); - downlinkMsg[RADIOLIB_LW_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fCnt16); + downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); // check the MIC if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { @@ -1375,15 +1375,15 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // in LoRaWAN v1.1, a frame is a Network frame if there is no Application payload // i.e.: either no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) - uint8_t fPort = RADIOLIB_LW_FPORT_MAC_COMMAND; + uint8_t fPort = RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; bool isAppDownlink = false; if(this->rev == 0) { isAppDownlink = true; } if(payLen > 0) { payLen -= 1; // subtract one as fPort is set - fPort = downlinkMsg[RADIOLIB_LW_FHDR_FPORT_POS(fOptsLen)]; - if(fPort > RADIOLIB_LW_FPORT_MAC_COMMAND) { + fPort = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsLen)]; + if(fPort > RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { isAppDownlink = true; } else { fOptsLen = payLen; @@ -1406,7 +1406,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if that isn't the case and the received fCnt is smaller or equal to the last heard fCnt, then error uint32_t fCnt32 = fCnt16; if(fCntDownPrev > 0) { - if((fCnt16 <= fCntDownPrev) && ((0xFFFF - (uint16_t)fCntDownPrev + fCnt16) > RADIOLIB_LW_MAX_FCNT_GAP)) { + if((fCnt16 <= fCntDownPrev) && ((0xFFFF - (uint16_t)fCntDownPrev + fCnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1430,7 +1430,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) bool isConfirmedDown = false; - if((downlinkMsg[RADIOLIB_LW_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_DOWN) { + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { this->confFCntDown = this->aFCntDown; isConfirmedDown = true; } @@ -1439,7 +1439,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) if(fOptsLen > 0) { // there are some Fopts, decrypt them #if !RADIOLIB_STATIC_ONLY - uint8_t* fOpts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LW_FHDR_FOPTS_LEN_MASK, (int)fOptsLen)]; + uint8_t* fOpts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)fOptsLen)]; #else uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; #endif @@ -1447,11 +1447,11 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fCnt16 // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey - if(fOptsLen <= RADIOLIB_LW_FHDR_FOPTS_LEN_MASK) { + if(fOptsLen <= RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK) { uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LW_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); } else { - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); } bool hasADR = false; @@ -1464,9 +1464,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) while(remLen > 0) { uint8_t cid = *fOptsPtr; uint8_t macLen = getMacPayloadLength(cid); - if(cid == RADIOLIB_LW_MAC_LINK_ADR) { + if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { // if there was an earlier ADR command but it was not the last, ignore it - if(hasADR && lastCID != RADIOLIB_LW_MAC_LINK_ADR) { + if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); remLen -= (macLen + 1); fOptsPtr += (macLen + 1); @@ -1483,7 +1483,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .cid = cid, .payload = { 0 }, .len = macLen, - .repeat = (cid == RADIOLIB_LW_MAC_LINK_ADR ? numADR : (uint8_t)0), + .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), }; memcpy(cmd.payload, fOptsPtr + 1, macLen); @@ -1504,7 +1504,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #endif // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink - if(this->commandsUp.len > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { + if(this->commandsUp.len > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { size_t fOptsBufSize = this->commandsUp.len; #if RADIOLIB_STATIC_ONLY uint8_t fOptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -1536,7 +1536,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) bool prevDC = this->dutyCycleEnabled; this->dutyCycleEnabled = false; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); - state = this->uplink(fOptsBuff, fOptsBufSize, RADIOLIB_LW_FPORT_MAC_COMMAND); + state = this->uplink(fOptsBuff, fOptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); this->dutyCycleEnabled = prevDC; @@ -1547,7 +1547,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #if RADIOLIB_STATIC_ONLY uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; #else - uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK]]]; + uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; #endif size_t lenDown = 0; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Receiving after MAC-only uplink .. "); @@ -1566,10 +1566,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // pass the extra info if requested if(event) { - event->dir = RADIOLIB_LW_CHANNEL_DIR_DOWNLINK; + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; event->confirmed = isConfirmedDown; event->confirming = isConfirmingUp; - event->datarate = this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK]; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; event->freq = currentChannels[event->dir].freq; event->power = this->txPowerMax - this->txPowerSteps * 2; event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; @@ -1577,7 +1577,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } // if MAC-only payload, return now - if(fPort == RADIOLIB_LW_FPORT_MAC_COMMAND) { + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { // no payload *len = 0; #if !RADIOLIB_STATIC_ONLY @@ -1591,7 +1591,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) *len = payLen; // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fCnt16 - processAES(&downlinkMsg[RADIOLIB_LW_FRAME_PAYLOAD_POS(fOptsLen)], payLen, this->appSKey, data, fCnt32, RADIOLIB_LW_CHANNEL_DIR_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], payLen, this->appSKey, data, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; @@ -1704,7 +1704,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { RADIOLIB_ASSERT(state); // if this channel is an FSK channel, toggle the FSK switch - if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LW_DATA_RATE_FSK_50_K) { + if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { this->FSK = true; } else { this->FSK = false; @@ -1733,7 +1733,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { } // downlink messages are sent with inverted IQ - if(dir == RADIOLIB_LW_CHANNEL_DIR_DOWNLINK) { + if(dir == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { if(!this->FSK) { state = this->phyLayer->invertIQ(true); RADIOLIB_ASSERT(state); @@ -1745,15 +1745,15 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { uint8_t syncWordLen = 0; size_t preLen = 0; if(this->FSK) { - preLen = 8*RADIOLIB_LW_GFSK_PREAMBLE_LEN; - syncWord[0] = (uint8_t)(RADIOLIB_LW_GFSK_SYNC_WORD >> 16); - syncWord[1] = (uint8_t)(RADIOLIB_LW_GFSK_SYNC_WORD >> 8); - syncWord[2] = (uint8_t)RADIOLIB_LW_GFSK_SYNC_WORD; + preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); + syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; syncWordLen = 3; } else { - preLen = RADIOLIB_LW_LORA_PREAMBLE_LEN; - syncWord[0] = RADIOLIB_LW_LORA_SYNC_WORD; + preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; + syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; } @@ -1771,38 +1771,38 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { size_t num = 0; // copy the default defined channels into the first slots (where Tx = Rx) for(; num < 3 && this->band->txFreqs[num].enabled; num++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; } // if we're about to send a join-request, copy the join-request channels to the next slots if(joinRequest) { size_t numJR = 0; for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; } } // clear all remaining channels - for(; num < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; num++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LW_CHANNEL_NONE; + for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - for (int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax ); } } @@ -1816,8 +1816,8 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); // clear all existing channels - for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LW_CHANNEL_NONE; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } // if no subband is selected by user, cycle through banks of 8 using devNonce value @@ -1853,18 +1853,18 @@ int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { int16_t LoRaWANNode::processCFList(uint8_t* cfList) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // retrieve number of existing (default) channels size_t num = 0; - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(!this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(!this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { break; } num++; } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_NEW_CHANNEL, + .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, .payload = { 0 }, .len = 0, .repeat = 0, @@ -1872,19 +1872,19 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { // datarate range for all new channels is equal to the default channels cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; for(uint8_t i = 0; i < 5; i++, num++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; cmd.payload[0] = num; memcpy(&cmd.payload[1], &cfList[i*3], 3); (void)execMacCommand(&cmd); } - } else { // RADIOLIB_LW_BAND_FIXED + } else { // RADIOLIB_LORAWAN_BAND_FIXED // complete channel mask received, so clear all existing channels - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LW_CHANNEL_NONE; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_LINK_ADR, + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, .len = 0, .repeat = 0, @@ -1893,7 +1893,7 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { - cmd.len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; cmd.payload[0] = 0xFF; // same datarate and payload memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); // copy mask cmd.payload[3] = chMaskCntl << 4; // set chMaskCntl, set NbTrans = 0 -> keep the same @@ -1908,11 +1908,11 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { int16_t LoRaWANNode::selectChannels() { // figure out which channel IDs are enabled (chMask may have disabled some) and are valid for the current datarate uint8_t numChannels = 0; - uint8_t channelsEnabled[RADIOLIB_LW_NUM_AVAILABLE_CHANNELS]; - for(uint8_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { - if(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin - && this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax) { + uint8_t channelsEnabled[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin + && this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { channelsEnabled[numChannels] = i; numChannels++; } @@ -1924,26 +1924,26 @@ int16_t LoRaWANNode::selectChannels() { } // select a random ID & channel from the list of enabled and possible channels uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; - this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][channelID]; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // for dynamic bands, the downlink channel is the one matched to the uplink channel - this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][channelID]; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; - } else { // RADIOLIB_LW_BAND_FIXED + } else { // RADIOLIB_LORAWAN_BAND_FIXED // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels LoRaWANChannel_t channelDn; channelDn.enabled = true; - channelDn.idx = this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; + channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; channelDn.drMin = this->band->rx1Span.drMin; channelDn.drMax = this->band->rx1Span.drMax; - this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = channelDn; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn; } - uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = drDown; + uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; return(RADIOLIB_ERR_NONE); } @@ -1951,8 +1951,8 @@ int16_t LoRaWANNode::selectChannels() { int16_t LoRaWANNode::setDatarate(uint8_t drUp) { // scan through all enabled channels and check if the requested datarate is available bool isValidDR = false; - for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i]); + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); if(chnl->enabled) { if(drUp >= chnl->drMin && drUp <= chnl->drMax) { isValidDR = true; @@ -1966,9 +1966,9 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp) { } LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_LINK_ADR, + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, - .len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, .repeat = 0, }; cmd.payload[0] = (drUp << 4); @@ -2035,7 +2035,7 @@ uint8_t LoRaWANNode::maxPayloadDwellTime() { // configure current datarate DataRate_t dr; // TODO this may fail horribly? - (void)findDataRate(this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK], &dr); + (void)findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); (void)this->phyLayer->setDataRate(dr); uint8_t minPayLen = 0; uint8_t maxPayLen = 255; @@ -2060,12 +2060,12 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower) { // Tx Power is set in steps of two // the selected value is rounded down to nearest multiple of two away from txPowerMax // e.g. on EU868, max is 16; if 13 is selected then we set to 12 - uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LW_POWER_STEP_SIZE_DBM); + uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM); LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LW_MAC_LINK_ADR, + .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, .payload = { 0 }, - .len = MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, + .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, .repeat = 0, }; cmd.payload[0] = 0xF0; // keep datarate the same @@ -2087,20 +2087,20 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { uint8_t dataRateBand = this->band->dataRates[dr]; - if(dataRateBand & RADIOLIB_LW_DATA_RATE_FSK_50_K) { + if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { dataRate->fsk.bitRate = 50; dataRate->fsk.freqDev = 25; } else { uint8_t bw = dataRateBand & 0x0C; switch(bw) { - case(RADIOLIB_LW_DATA_RATE_BW_125_KHZ): + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): dataRate->lora.bandwidth = 125.0; break; - case(RADIOLIB_LW_DATA_RATE_BW_250_KHZ): + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): dataRate->lora.bandwidth = 250.0; break; - case(RADIOLIB_LW_DATA_RATE_BW_500_KHZ): + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): dataRate->lora.bandwidth = 500.0; break; default: @@ -2118,7 +2118,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { bool valid = false; - for(size_t i = 0; i < RADIOLIB_LW_NUM_MAC_COMMANDS; i++) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { valid = MacTable[i].user; } @@ -2129,11 +2129,11 @@ int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { } // if there are already 15 MAC bytes in the uplink queue, we can't add a new one - if(this->commandsUp.len + 1 > RADIOLIB_LW_FHDR_FOPTS_MAX_LEN) { + if(this->commandsUp.len + 1 > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The maximum number of FOpts payload was reached"); return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } - if(this->commandsUp.numCommands > RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE) { + if(this->commandsUp.numCommands > RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The RadioLib internal MAC command queue was full"); return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } @@ -2152,7 +2152,7 @@ int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { } int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { - if(queue->numCommands >= RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE) { + if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } @@ -2172,11 +2172,11 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que } queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload // move all subsequent commands one forward in the queue - if(index < RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE - 1) { - memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); + if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { + memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); } // set the latest element to all 0 - memset(&queue->commands[RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); + memset(&queue->commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); queue->numCommands--; return(RADIOLIB_ERR_NONE); } @@ -2189,34 +2189,34 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02X", cmd->cid); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); - if(cmd->cid >= RADIOLIB_LW_MAC_PROPRIETARY) { + if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { // TODO call user-provided callback for proprietary MAC commands? return(false); } switch(cmd->cid) { - case(RADIOLIB_LW_MAC_RESET): { + case(RADIOLIB_LORAWAN_MAC_RESET): { // get the server version uint8_t srvVersion = cmd->payload[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); if(srvVersion == this->rev) { // valid server version, stop sending the ResetInd MAC command - deleteMacCommand(RADIOLIB_LW_MAC_RESET, &this->commandsUp); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); } return(false); } break; - case(RADIOLIB_LW_MAC_LINK_CHECK): { + case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); // delete any existing response (does nothing if there is none) - deleteMacCommand(RADIOLIB_LW_MAC_LINK_CHECK, &this->commandsDown); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; - case(RADIOLIB_LW_MAC_LINK_ADR): { + case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { int16_t state = RADIOLIB_ERR_UNKNOWN; // get the ADR configuration uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; @@ -2233,16 +2233,16 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { if(drUp == 0x0F) { // keep the same drAck = 1; - } else if (this->band->dataRates[drUp] != RADIOLIB_LW_DATA_RATE_UNUSED) { + } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // check if the module supports this data rate DataRate_t dr; state = findDataRate(drUp, &dr); if(state == RADIOLIB_ERR_NONE) { uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMin, - this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] = drUp; - this->dataRates[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK] = drDown; + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, + this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; + this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; drAck = 1; } else { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); @@ -2274,22 +2274,22 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // only apply channel mask when the RFU bit is not set // (which is only set in internal MAC commands for changing Tx/Dr) if(!isInternalTxDr) { - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); - } else { // RADIOLIB_LW_BAND_FIXED + } else { // RADIOLIB_LORAWAN_BAND_FIXED if(cmd->repeat == 1) { // if this is the first ADR command in the queue, clear all saved channels // so we can apply the new channel mask RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); - for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LW_CHANNEL_NONE; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } // clear all previous channel masks - memset(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS], 0, 16*8); + memset(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS], 0, 16*8); } else { // if this is not the first ADR command, clear the ADR response that was in the queue - (void)deleteMacCommand(RADIOLIB_LW_MAC_LINK_ADR, &this->commandsUp); + (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); } chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask); @@ -2304,7 +2304,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state // but we don't bother and try to set each individual command if(drUp == 0x0F || !drAck) { - cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LW_CHANNEL_DIR_UPLINK] << 4); + cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); } if(txSteps == 0x0F || !pwrAck) { cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerSteps; @@ -2313,10 +2313,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; } - if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte if(isInternalTxDr) { - memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR] + 1, 3); + memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, 3); } // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again @@ -2325,24 +2325,24 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } // save to the single ADR MAC location - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); - } else { // RADIOLIB_LW_BAND_FIXED + } else { // RADIOLIB_LORAWAN_BAND_FIXED // save Tx/Dr to the Link ADR position in the session buffer - uint8_t bufTxDr[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + uint8_t bufTxDr[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; bufTxDr[0] = cmd->payload[0]; bufTxDr[3] = 1 << 7; - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_LINK_ADR], bufTxDr, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); // if RFU bit is set, this is just a change in Datarate or TxPower, in which case we don't save the channel masks // if the RFU bit is not set, we must save this channel mask if(!isInternalTxDr) { // save the channel mask to the uplink channels position in session buffer, with Tx and DR set to 'same' cmd->payload[0] = 0xFF; - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving mask to ULChannels[%d]:", (cmd->repeat - 1) * cmd->len); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); } } @@ -2355,7 +2355,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LW_MAC_DUTY_CYCLE): { + case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); if(maxDutyCycle == 0) { @@ -2364,13 +2364,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { this->dutyCycle = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000 / (RadioLibTime_t)(1UL << maxDutyCycle); } - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; - case(RADIOLIB_LW_MAC_RX_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP): { // get the configuration this->rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; uint8_t rx1OffsAck = 1; @@ -2384,10 +2384,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t chanAck = 0; if(this->phyLayer->setFrequency(this->rx2.freq) == RADIOLIB_ERR_NONE) { chanAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].freq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); // TODO this should be sent repeatedly until the next downlink cmd->len = 1; @@ -2396,7 +2396,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LW_MAC_DEV_STATUS): { + case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { // set the uplink reply RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); cmd->len = 2; @@ -2408,7 +2408,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LW_MAC_NEW_CHANNEL): { + case(RADIOLIB_LORAWAN_MAC_NEW_CHANNEL): { // get the configuration uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); @@ -2419,38 +2419,38 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint8_t newChAck = 0; uint8_t freqAck = 0; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].enabled = true; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].freq = freq; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq = freq; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; // downlink channel is identical to uplink channel - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex]; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex]; newChAck = 1; // check if the frequency is possible - if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { + if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { freqAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].freq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq:"); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][chIndex].drMax, - - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][chIndex].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax ); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // send the reply cmd->len = 1; @@ -2460,7 +2460,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LW_MAC_DL_CHANNEL): { + case(RADIOLIB_LORAWAN_MAC_DL_CHANNEL): { // get the configuration uint8_t chIndex = cmd->payload[0]; uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); @@ -2472,21 +2472,21 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { // check if the frequency is possible if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { freqDlAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK].freq); + this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } // update the downlink frequency - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq = freq; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq = freq; // check if the corresponding uplink frequency is actually set - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq > 0) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { freqUlAck = 1; } } } - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); // TODO send this repeatedly until a downlink is received cmd->len = 1; @@ -2496,7 +2496,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LW_MAC_RX_TIMING_SETUP): { + case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { // get the configuration uint8_t delay = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); @@ -2508,7 +2508,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { this->rxDelays[0] = delay * 1000; this->rxDelays[1] = this->rxDelays[0] + 1000; - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); // send the reply cmd->len = 0; @@ -2517,7 +2517,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(true); } break; - case(RADIOLIB_LW_MAC_TX_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP): { uint8_t dlDwell = (cmd->payload[0] & 0x20) >> 5; uint8_t ulDwell = (cmd->payload[0] & 0x10) >> 4; uint8_t maxEirpRaw = cmd->payload[0] & 0x0F; @@ -2528,50 +2528,50 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); this->dwellTimeEnabledUp = ulDwell ? true : false; - this->dwellTimeUp = ulDwell ? RADIOLIB_LW_DWELL_TIME : 0; + this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; this->dwellTimeEnabledDn = dlDwell ? true : false; - this->dwellTimeDn = dlDwell ? RADIOLIB_LW_DWELL_TIME : 0; + this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; - case(RADIOLIB_LW_MAC_REKEY): { + case(RADIOLIB_LORAWAN_MAC_REKEY): { // get the server version uint8_t srvVersion = cmd->payload[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); if((srvVersion > 0) && (srvVersion <= this->rev)) { // valid server version, stop sending the ReKey MAC command - deleteMacCommand(RADIOLIB_LW_MAC_REKEY, &this->commandsUp); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); } return(false); } break; - case(RADIOLIB_LW_MAC_ADR_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; this->adrDelayExp = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; return(true); } break; - case(RADIOLIB_LW_MAC_DEVICE_TIME): { + case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); // delete any existing response (does nothing if there is none) - deleteMacCommand(RADIOLIB_LW_MAC_DEVICE_TIME, &this->commandsDown); + deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); // insert response into MAC downlink queue pushMacCommand(cmd, &this->commandsDown); return(false); } break; - case(RADIOLIB_LW_MAC_FORCE_REJOIN): { + case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { // TODO implement this uint16_t rejoinReq = LoRaWANNode::ntoh(cmd->payload); uint8_t period = (rejoinReq & 0x3800) >> 11; @@ -2586,13 +2586,13 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(false); } break; - case(RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP): { + case(RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP): { // TODO implement this uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; uint8_t maxCount = cmd->payload[0] & 0x0F; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); - memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); cmd->len = 0; cmd->payload[0] = (1 << 1) | 1; @@ -2608,42 +2608,42 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { - for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskCntl == 0) { // apply the mask by looking at each channel bit if(chMask & (1UL << i)) { // if it should be enabled but is not currently defined, stop immediately - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LW_CHANNEL_INDEX_NONE) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { return(false); } - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled = true; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; } else { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled = false; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; } } else if(chMaskCntl == 6) { // enable all defined channels - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LW_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled = true; + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; } } } - for (int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax ); } } @@ -2656,8 +2656,8 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { // find out how many channels have already been configured uint8_t idx = 0; - for(size_t i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq > 0) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { idx++; } } @@ -2675,7 +2675,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; } } @@ -2697,7 +2697,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; } } @@ -2716,7 +2716,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; } // enable single channel from second span uint8_t chNum = 64 + i; @@ -2725,7 +2725,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; } } @@ -2746,16 +2746,16 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; } } } if(this->band->numTxSpans == 2 && chMaskCntl == 7) { // all channels off (clear all channels) - LoRaWANChannel_t chnl = RADIOLIB_LW_CHANNEL_NONE; - for(int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i] = chnl; + LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl; // downlink channels are not defined so don't need to reset } idx = 0; @@ -2770,26 +2770,26 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][idx++] = chnl; + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; } } } - for (int i = 0; i < RADIOLIB_LW_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled) { + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LW_CHANNEL_DIR_DOWNLINK][i].drMax + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax ); } } @@ -2808,8 +2808,8 @@ uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { } int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { - uint8_t payload[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - int16_t state = deleteMacCommand(RADIOLIB_LW_LINK_CHECK_REQ, &this->commandsDown, payload); + uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); RADIOLIB_ASSERT(state); if(margin) { *margin = payload[0]; } @@ -2819,8 +2819,8 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { } int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { - uint8_t payload[RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - int16_t state = deleteMacCommand(RADIOLIB_LW_MAC_DEVICE_TIME, &this->commandsDown, payload); + uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); RADIOLIB_ASSERT(state); if(gpsEpoch) { @@ -2897,11 +2897,11 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out // generate the encryption blocks uint8_t encBuffer[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; uint8_t encBlock[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - encBlock[RADIOLIB_LW_BLOCK_MAGIC_POS] = RADIOLIB_LW_ENC_BLOCK_MAGIC; - encBlock[RADIOLIB_LW_ENC_BLOCK_COUNTER_ID_POS] = ctrId; - encBlock[RADIOLIB_LW_BLOCK_DIR_POS] = dir; - LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&encBlock[RADIOLIB_LW_BLOCK_FCNT_POS], fCnt); + encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS] = ctrId; + encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = dir; + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fCnt); // now encrypt the input // on downlink frames, this has a decryption effect because server actually "decrypts" the plaintext @@ -2909,7 +2909,7 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out for(size_t i = 0; i < numBlocks; i++) { if(counter) { - encBlock[RADIOLIB_LW_ENC_BLOCK_COUNTER_POS] = i + 1; + encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS] = i + 1; } // encrypt the buffer diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 7a97705d08..7239550668 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1,200 +1,200 @@ -#if !defined(_RADIOLIB_LW_H) && !RADIOLIB_EXCLUDE_LORAWAN -#define _RADIOLIB_LW_H +#if !defined(_RADIOLIB_LORAWAN_H) && !RADIOLIB_EXCLUDE_LORAWAN +#define _RADIOLIB_LORAWAN_H #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" #include "../../utils/Cryptography.h" // activation mode -#define RADIOLIB_LW_MODE_OTAA (0x07AA) -#define RADIOLIB_LW_MODE_ABP (0x0AB9) -#define RADIOLIB_LW_MODE_NONE (0x0000) +#define RADIOLIB_LORAWAN_MODE_OTAA (0x07AA) +#define RADIOLIB_LORAWAN_MODE_ABP (0x0AB9) +#define RADIOLIB_LORAWAN_MODE_NONE (0x0000) // operation mode -#define RADIOLIB_LW_CLASS_A (0x0A) -#define RADIOLIB_LW_CLASS_B (0x0B) -#define RADIOLIB_LW_CLASS_C (0x0C) +#define RADIOLIB_LORAWAN_CLASS_A (0x0A) +#define RADIOLIB_LORAWAN_CLASS_B (0x0B) +#define RADIOLIB_LORAWAN_CLASS_C (0x0C) // preamble format -#define RADIOLIB_LW_LORA_SYNC_WORD (0x34) -#define RADIOLIB_LW_LORA_PREAMBLE_LEN (8) -#define RADIOLIB_LW_GFSK_SYNC_WORD (0xC194C1) -#define RADIOLIB_LW_GFSK_PREAMBLE_LEN (5) +#define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) +#define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) +#define RADIOLIB_LORAWAN_GFSK_SYNC_WORD (0xC194C1) +#define RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN (5) // MAC header field encoding MSB LSB DESCRIPTION -#define RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request -#define RADIOLIB_LW_MHDR_MTYPE_JOIN_ACCEPT (0x01 << 5) // 7 5 join accept -#define RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_UP (0x02 << 5) // 7 5 unconfirmed data up -#define RADIOLIB_LW_MHDR_MTYPE_UNCONF_DATA_DOWN (0x03 << 5) // 7 5 unconfirmed data down -#define RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_UP (0x04 << 5) // 7 5 confirmed data up -#define RADIOLIB_LW_MHDR_MTYPE_CONF_DATA_DOWN (0x05 << 5) // 7 5 confirmed data down -#define RADIOLIB_LW_MHDR_MTYPE_PROPRIETARY (0x07 << 5) // 7 5 proprietary -#define RADIOLIB_LW_MHDR_MTYPE_MASK (0x07 << 5) // 7 5 bitmask of all possible options -#define RADIOLIB_LW_MHDR_MAJOR_R1 (0x00 << 0) // 1 0 major version: LoRaWAN R1 +#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request +#define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT (0x01 << 5) // 7 5 join accept +#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP (0x02 << 5) // 7 5 unconfirmed data up +#define RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_DOWN (0x03 << 5) // 7 5 unconfirmed data down +#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP (0x04 << 5) // 7 5 confirmed data up +#define RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN (0x05 << 5) // 7 5 confirmed data down +#define RADIOLIB_LORAWAN_MHDR_MTYPE_PROPRIETARY (0x07 << 5) // 7 5 proprietary +#define RADIOLIB_LORAWAN_MHDR_MTYPE_MASK (0x07 << 5) // 7 5 bitmask of all possible options +#define RADIOLIB_LORAWAN_MHDR_MAJOR_R1 (0x00 << 0) // 1 0 major version: LoRaWAN R1 // frame control field encoding -#define RADIOLIB_LW_FCTRL_ADR_ENABLED (0x01 << 7) // 7 7 adaptive data rate: enabled -#define RADIOLIB_LW_FCTRL_ADR_DISABLED (0x00 << 7) // 7 7 disabled -#define RADIOLIB_LW_FCTRL_ADR_ACK_REQ (0x01 << 6) // 6 6 adaptive data rate ACK request -#define RADIOLIB_LW_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge -#define RADIOLIB_LW_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending +#define RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED (0x01 << 7) // 7 7 adaptive data rate: enabled +#define RADIOLIB_LORAWAN_FCTRL_ADR_DISABLED (0x00 << 7) // 7 7 disabled +#define RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ (0x01 << 6) // 6 6 adaptive data rate ACK request +#define RADIOLIB_LORAWAN_FCTRL_ACK (0x01 << 5) // 5 5 confirmed message acknowledge +#define RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING (0x01 << 4) // 4 4 downlink frame is pending // fPort field -#define RADIOLIB_LW_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only -#define RADIOLIB_LW_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved fPort values +#define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only +#define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved fPort values // MAC commands - only those sent from end-device to gateway -#define RADIOLIB_LW_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network -#define RADIOLIB_LW_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change -#define RADIOLIB_LW_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change -#define RADIOLIB_LW_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request -#define RADIOLIB_LW_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information -#define RADIOLIB_LW_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel -#define RADIOLIB_LW_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing +#define RADIOLIB_LORAWAN_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network +#define RADIOLIB_LORAWAN_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change +#define RADIOLIB_LORAWAN_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change +#define RADIOLIB_LORAWAN_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request +#define RADIOLIB_LORAWAN_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information +#define RADIOLIB_LORAWAN_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel +#define RADIOLIB_LORAWAN_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing -#define RADIOLIB_LW_NOPTS_LEN (8) +#define RADIOLIB_LORAWAN_NOPTS_LEN (8) // data rate encoding -#define RADIOLIB_LW_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps -#define RADIOLIB_LW_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 -#define RADIOLIB_LW_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 -#define RADIOLIB_LW_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 -#define RADIOLIB_LW_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 -#define RADIOLIB_LW_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 -#define RADIOLIB_LW_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 -#define RADIOLIB_LW_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz -#define RADIOLIB_LW_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz -#define RADIOLIB_LW_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz -#define RADIOLIB_LW_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value -#define RADIOLIB_LW_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 -#define RADIOLIB_LW_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 -#define RADIOLIB_LW_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 -#define RADIOLIB_LW_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 -#define RADIOLIB_LW_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate - -#define RADIOLIB_LW_CHANNEL_DIR_UPLINK (0x00 << 0) -#define RADIOLIB_LW_CHANNEL_DIR_DOWNLINK (0x01 << 0) -#define RADIOLIB_LW_CHANNEL_DIR_BOTH (0x02 << 0) -#define RADIOLIB_LW_CHANNEL_DIR_NONE (0x03 << 0) -#define RADIOLIB_LW_BAND_DYNAMIC (0) -#define RADIOLIB_LW_BAND_FIXED (1) -#define RADIOLIB_LW_CHANNEL_NUM_DATARATES (15) -#define RADIOLIB_LW_CHANNEL_INDEX_NONE (0xFF >> 0) +#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps +#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 +#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 +#define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate + +#define RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK (0x00 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0) +#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0) +#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) +#define RADIOLIB_LORAWAN_BAND_FIXED (1) +#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) +#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 0) // recommended default settings -#define RADIOLIB_LW_RECEIVE_DELAY_1_MS (1000) -#define RADIOLIB_LW_RECEIVE_DELAY_2_MS ((RADIOLIB_LW_RECEIVE_DELAY_1_MS) + 1000) -#define RADIOLIB_LW_RX1_DR_OFFSET (0) -#define RADIOLIB_LW_JOIN_ACCEPT_DELAY_1_MS (5000) -#define RADIOLIB_LW_JOIN_ACCEPT_DELAY_2_MS (6000) -#define RADIOLIB_LW_MAX_FCNT_GAP (16384) -#define RADIOLIB_LW_ADR_ACK_LIMIT_EXP (0x06) -#define RADIOLIB_LW_ADR_ACK_DELAY_EXP (0x05) -#define RADIOLIB_LW_RETRANSMIT_TIMEOUT_MIN_MS (1000) -#define RADIOLIB_LW_RETRANSMIT_TIMEOUT_MAX_MS (3000) -#define RADIOLIB_LW_POWER_STEP_SIZE_DBM (-2) -#define RADIOLIB_LW_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks -#define RADIOLIB_LW_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented +#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) +#define RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS ((RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS) + 1000) +#define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) +#define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384) +#define RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP (0x06) +#define RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP (0x05) +#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) +#define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS (3000) +#define RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM (-2) +#define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks +#define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented // join request message layout -#define RADIOLIB_LW_JOIN_REQUEST_LEN (23) -#define RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS (1) -#define RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS (9) -#define RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS (17) -#define RADIOLIB_LW_JOIN_REQUEST_TYPE (0xFF) -#define RADIOLIB_LW_JOIN_REQUEST_TYPE_0 (0x00) -#define RADIOLIB_LW_JOIN_REQUEST_TYPE_1 (0x01) -#define RADIOLIB_LW_JOIN_REQUEST_TYPE_2 (0x02) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS (9) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS (17) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE (0xFF) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_0 (0x00) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_1 (0x01) +#define RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE_2 (0x02) // join accept message layout -#define RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN (33) -#define RADIOLIB_LW_JOIN_ACCEPT_JOIN_NONCE_POS (1) -#define RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS (4) -#define RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS (7) -#define RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS (4) -#define RADIOLIB_LW_JOIN_ACCEPT_DL_SETTINGS_POS (11) -#define RADIOLIB_LW_JOIN_ACCEPT_RX_DELAY_POS (12) -#define RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS (12) -#define RADIOLIB_LW_JOIN_ACCEPT_CFLIST_POS (13) -#define RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN (16) -#define RADIOLIB_LW_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LW_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LW_JOIN_ACCEPT_CFLIST_LEN - 1) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN (33) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS (1) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS (4) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS (7) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS (4) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS (11) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS (13) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN (16) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN - 1) // join accept message variables -#define RADIOLIB_LW_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 -#define RADIOLIB_LW_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 -#define RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY (0x01) -#define RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY (0x02) -#define RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) -#define RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) -#define RADIOLIB_LW_JOIN_ACCEPT_JS_ENC_KEY (0x05) -#define RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY (0x06) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY (0x01) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY (0x02) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_S_NWK_S_INT_KEY (0x03) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_ENC_KEY (0x05) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY (0x06) // frame header layout -#define RADIOLIB_LW_FHDR_LEN_START_OFFS (16) -#define RADIOLIB_LW_FHDR_DEV_ADDR_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 1) -#define RADIOLIB_LW_FHDR_FCTRL_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 5) -#define RADIOLIB_LW_FHDR_FCNT_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 6) -#define RADIOLIB_LW_FHDR_FOPTS_POS (RADIOLIB_LW_FHDR_LEN_START_OFFS + 8) -#define RADIOLIB_LW_FHDR_FOPTS_LEN_MASK (0x0F) -#define RADIOLIB_LW_FHDR_FOPTS_MAX_LEN (15) -#define RADIOLIB_LW_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LW_FHDR_LEN_START_OFFS + 8 + (FOPTS)) -#define RADIOLIB_LW_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LW_FHDR_LEN_START_OFFS + 9 + (FOPTS)) -#define RADIOLIB_LW_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) +#define RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS (16) +#define RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 1) +#define RADIOLIB_LORAWAN_FHDR_FCTRL_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 5) +#define RADIOLIB_LORAWAN_FHDR_FCNT_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 6) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_POS (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK (0x0F) +#define RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN (15) +#define RADIOLIB_LORAWAN_FHDR_FPORT_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 8 + (FOPTS)) +#define RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(FOPTS) (RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS + 9 + (FOPTS)) +#define RADIOLIB_LORAWAN_FRAME_LEN(PAYLOAD, FOPTS) (16 + 13 + (PAYLOAD) + (FOPTS)) // payload encryption/MIC blocks common layout -#define RADIOLIB_LW_BLOCK_MAGIC_POS (0) -#define RADIOLIB_LW_BLOCK_CONF_FCNT_POS (1) -#define RADIOLIB_LW_BLOCK_DIR_POS (5) -#define RADIOLIB_LW_BLOCK_DEV_ADDR_POS (6) -#define RADIOLIB_LW_BLOCK_FCNT_POS (10) +#define RADIOLIB_LORAWAN_BLOCK_MAGIC_POS (0) +#define RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS (1) +#define RADIOLIB_LORAWAN_BLOCK_DIR_POS (5) +#define RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS (6) +#define RADIOLIB_LORAWAN_BLOCK_FCNT_POS (10) // payload encryption block layout -#define RADIOLIB_LW_ENC_BLOCK_MAGIC (0x01) -#define RADIOLIB_LW_ENC_BLOCK_COUNTER_ID_POS (4) -#define RADIOLIB_LW_ENC_BLOCK_COUNTER_POS (15) +#define RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC (0x01) +#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS (4) +#define RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_POS (15) // payload MIC blocks layout -#define RADIOLIB_LW_MIC_BLOCK_MAGIC (0x49) -#define RADIOLIB_LW_MIC_BLOCK_LEN_POS (15) -#define RADIOLIB_LW_MIC_DATA_RATE_POS (3) -#define RADIOLIB_LW_MIC_CH_INDEX_POS (4) +#define RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC (0x49) +#define RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS (15) +#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3) +#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4) // maximum allowed dwell time on bands that implement dwell time limitations -#define RADIOLIB_LW_DWELL_TIME (400) +#define RADIOLIB_LORAWAN_DWELL_TIME (400) // unused frame counter value -#define RADIOLIB_LW_FCNT_NONE (0xFFFFFFFF) +#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) // MAC commands -#define RADIOLIB_LW_NUM_MAC_COMMANDS (16) - -#define RADIOLIB_LW_MAC_RESET (0x01) -#define RADIOLIB_LW_MAC_LINK_CHECK (0x02) -#define RADIOLIB_LW_MAC_LINK_ADR (0x03) -#define RADIOLIB_LW_MAC_DUTY_CYCLE (0x04) -#define RADIOLIB_LW_MAC_RX_PARAM_SETUP (0x05) -#define RADIOLIB_LW_MAC_DEV_STATUS (0x06) -#define RADIOLIB_LW_MAC_NEW_CHANNEL (0x07) -#define RADIOLIB_LW_MAC_RX_TIMING_SETUP (0x08) -#define RADIOLIB_LW_MAC_TX_PARAM_SETUP (0x09) -#define RADIOLIB_LW_MAC_DL_CHANNEL (0x0A) -#define RADIOLIB_LW_MAC_REKEY (0x0B) -#define RADIOLIB_LW_MAC_ADR_PARAM_SETUP (0x0C) -#define RADIOLIB_LW_MAC_DEVICE_TIME (0x0D) -#define RADIOLIB_LW_MAC_FORCE_REJOIN (0x0E) -#define RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP (0x0F) -#define RADIOLIB_LW_MAC_PROPRIETARY (0x80) +#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) + +#define RADIOLIB_LORAWAN_MAC_RESET (0x01) +#define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02) +#define RADIOLIB_LORAWAN_MAC_LINK_ADR (0x03) +#define RADIOLIB_LORAWAN_MAC_DUTY_CYCLE (0x04) +#define RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP (0x05) +#define RADIOLIB_LORAWAN_MAC_DEV_STATUS (0x06) +#define RADIOLIB_LORAWAN_MAC_NEW_CHANNEL (0x07) +#define RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP (0x08) +#define RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP (0x09) +#define RADIOLIB_LORAWAN_MAC_DL_CHANNEL (0x0A) +#define RADIOLIB_LORAWAN_MAC_REKEY (0x0B) +#define RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP (0x0C) +#define RADIOLIB_LORAWAN_MAC_DEVICE_TIME (0x0D) +#define RADIOLIB_LORAWAN_MAC_FORCE_REJOIN (0x0E) +#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) +#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) // the length of internal MAC command queue - hopefully this is enough for most use cases -#define RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE (9) +#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) // the maximum number of simultaneously available channels -#define RADIOLIB_LW_NUM_AVAILABLE_CHANNELS (16) +#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) // maximum MAC command sizes -#define RADIOLIB_LW_MAX_MAC_COMMAND_LEN_DOWN (5) -#define RADIOLIB_LW_MAX_MAC_COMMAND_LEN_UP (2) -#define RADIOLIB_LW_MAX_NUM_ADR_COMMANDS (8) +#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) +#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) +#define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) /*! \struct LoRaWANMacSpec_t @@ -214,24 +214,24 @@ struct LoRaWANMacSpec_t { const bool user; }; -constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LW_NUM_MAC_COMMANDS + 1] = { +constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { { 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting - { RADIOLIB_LW_MAC_RESET, 1, 1, false }, - { RADIOLIB_LW_MAC_LINK_CHECK, 2, 0, true }, - { RADIOLIB_LW_MAC_LINK_ADR, 4, 1, false }, - { RADIOLIB_LW_MAC_DUTY_CYCLE, 1, 0, false }, - { RADIOLIB_LW_MAC_RX_PARAM_SETUP, 4, 1, false }, - { RADIOLIB_LW_MAC_DEV_STATUS, 0, 2, false }, - { RADIOLIB_LW_MAC_NEW_CHANNEL, 5, 1, false }, - { RADIOLIB_LW_MAC_RX_TIMING_SETUP, 1, 0, false }, - { RADIOLIB_LW_MAC_TX_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LW_MAC_DL_CHANNEL, 4, 1, false }, - { RADIOLIB_LW_MAC_REKEY, 1, 1, false }, - { RADIOLIB_LW_MAC_ADR_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LW_MAC_DEVICE_TIME, 5, 0, true }, - { RADIOLIB_LW_MAC_FORCE_REJOIN, 2, 0, false }, - { RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, - { RADIOLIB_LW_MAC_PROPRIETARY, 5, 0, true } + { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, + { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, + { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, + { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, + { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, + { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, + { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, + { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, + { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } }; /*! @@ -264,59 +264,59 @@ struct LoRaWANMacCommandQueue_t { uint8_t len; /*! \brief MAC command buffer */ - LoRaWANMacCommand_t commands[RADIOLIB_LW_MAC_COMMAND_QUEUE_SIZE]; + LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; }; -#define RADIOLIB_LW_NONCES_VERSION_VAL (0x0001) +#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) enum LoRaWANSchemeBase_t { - RADIOLIB_LW_NONCES_START = 0x00, - RADIOLIB_LW_NONCES_VERSION = RADIOLIB_LW_NONCES_START, // 2 bytes - RADIOLIB_LW_NONCES_MODE = RADIOLIB_LW_NONCES_VERSION + sizeof(uint16_t), // 2 bytes - RADIOLIB_LW_NONCES_CLASS = RADIOLIB_LW_NONCES_MODE + sizeof(uint16_t), // 1 byte - RADIOLIB_LW_NONCES_PLAN = RADIOLIB_LW_NONCES_CLASS + sizeof(uint8_t), // 1 byte - RADIOLIB_LW_NONCES_CHECKSUM = RADIOLIB_LW_NONCES_PLAN + sizeof(uint8_t), // 2 bytes - RADIOLIB_LW_NONCES_DEV_NONCE = RADIOLIB_LW_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes - RADIOLIB_LW_NONCES_JOIN_NONCE = RADIOLIB_LW_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes - RADIOLIB_LW_NONCES_ACTIVE = RADIOLIB_LW_NONCES_JOIN_NONCE + 3, // 1 byte - RADIOLIB_LW_NONCES_SIGNATURE = RADIOLIB_LW_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes - RADIOLIB_LW_NONCES_BUF_SIZE = RADIOLIB_LW_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size + RADIOLIB_LORAWAN_NONCES_START = 0x00, + RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes + RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes + RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte + RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size }; enum LoRaWANSchemeSession_t { - RADIOLIB_LW_SESSION_START = 0x00, - RADIOLIB_LW_SESSION_NWK_SENC_KEY = RADIOLIB_LW_SESSION_START, // 16 bytes - RADIOLIB_LW_SESSION_APP_SKEY = RADIOLIB_LW_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LW_SESSION_FNWK_SINT_KEY = RADIOLIB_LW_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LW_SESSION_SNWK_SINT_KEY = RADIOLIB_LW_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LW_SESSION_DEV_ADDR = RADIOLIB_LW_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes - RADIOLIB_LW_SESSION_NONCES_SIGNATURE = RADIOLIB_LW_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes - RADIOLIB_LW_SESSION_A_FCNT_DOWN = RADIOLIB_LW_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes - RADIOLIB_LW_SESSION_CONF_FCNT_UP = RADIOLIB_LW_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LW_SESSION_CONF_FCNT_DOWN = RADIOLIB_LW_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes - RADIOLIB_LW_SESSION_RJ_COUNT0 = RADIOLIB_LW_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes - RADIOLIB_LW_SESSION_RJ_COUNT1 = RADIOLIB_LW_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes - RADIOLIB_LW_SESSION_HOMENET_ID = RADIOLIB_LW_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes - RADIOLIB_LW_SESSION_VERSION = RADIOLIB_LW_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte - RADIOLIB_LW_SESSION_DUTY_CYCLE = RADIOLIB_LW_SESSION_VERSION + sizeof(uint8_t), // 1 byte - RADIOLIB_LW_SESSION_RX_PARAM_SETUP = RADIOLIB_LW_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LW_MAC_DUTY_CYCLE].lenDn, // 4 bytes - RADIOLIB_LW_SESSION_RX_TIMING_SETUP = RADIOLIB_LW_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_RX_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LW_SESSION_TX_PARAM_SETUP = RADIOLIB_LW_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LW_MAC_RX_TIMING_SETUP].lenDn, // 1 byte - RADIOLIB_LW_SESSION_ADR_PARAM_SETUP = RADIOLIB_LW_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_TX_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LW_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LW_SESSION_BEACON_FREQ = RADIOLIB_LW_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LW_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes - RADIOLIB_LW_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LW_SESSION_BEACON_FREQ + 3, // 4 bytes - RADIOLIB_LW_SESSION_PERIODICITY = RADIOLIB_LW_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte - RADIOLIB_LW_SESSION_LAST_TIME = RADIOLIB_LW_SESSION_PERIODICITY + 1, // 4 bytes - RADIOLIB_LW_SESSION_UL_CHANNELS = RADIOLIB_LW_SESSION_LAST_TIME + 4, // 16*5 bytes - RADIOLIB_LW_SESSION_DL_CHANNELS = RADIOLIB_LW_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LW_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes - RADIOLIB_LW_SESSION_MAC_QUEUE_UL = RADIOLIB_LW_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LW_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes - RADIOLIB_LW_SESSION_N_FCNT_DOWN = RADIOLIB_LW_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes - RADIOLIB_LW_SESSION_ADR_FCNT = RADIOLIB_LW_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LW_SESSION_LINK_ADR = RADIOLIB_LW_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes - RADIOLIB_LW_SESSION_FCNT_UP = RADIOLIB_LW_SESSION_LINK_ADR + MacTable[RADIOLIB_LW_MAC_LINK_ADR].lenDn, // 4 bytes - RADIOLIB_LW_SESSION_SIGNATURE = RADIOLIB_LW_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes - RADIOLIB_LW_SESSION_BUF_SIZE = RADIOLIB_LW_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size + RADIOLIB_LORAWAN_SESSION_START = 0x00, + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes + RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte + RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes + RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes + RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte + RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_LINK_ADR + MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, // 4 bytes + RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size }; /*! @@ -342,7 +342,7 @@ struct LoRaWANChannel_t { }; // alias for unused channel -#define RADIOLIB_LW_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LW_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } +#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } /*! \struct LoRaWANChannelSpan_t @@ -370,7 +370,7 @@ struct LoRaWANChannelSpan_t { }; // alias for unused channel span -#define RADIOLIB_LW_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED } +#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } /*! \struct LoRaWANBand_t @@ -384,7 +384,7 @@ struct LoRaWANBand_t { uint8_t bandType; /*! \brief Array of allowed maximum payload lengths for each data rate */ - uint8_t payloadLenMax[RADIOLIB_LW_CHANNEL_NUM_DATARATES]; + uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; /*! \brief Maximum allowed output power in this band in dBm */ int8_t powerMax; @@ -423,7 +423,7 @@ struct LoRaWANBand_t { LoRaWANChannel_t rx2; /*! \brief The corresponding datarates, bandwidths and coding rates for DR index */ - uint8_t dataRates[RADIOLIB_LW_CHANNEL_NUM_DATARATES]; + uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; }; // supported bands @@ -455,7 +455,7 @@ enum LoRaWANBandNum_t { }; // provide easy access to the number of currently supported bands -#define RADIOLIB_LW_NUM_SUPPORTED_BANDS (BandLast - BandEU868) +#define RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS (BandLast - BandEU868) // array of currently supported bands extern const LoRaWANBand_t* LoRaWANBands[]; @@ -480,7 +480,7 @@ struct LoRaWANJoinEvent_t { \brief Structure to save extra information about uplink/downlink event. */ struct LoRaWANEvent_t { - /*! \brief Event direction, one of RADIOLIB_LW_CHANNEL_DIR_* */ + /*! \brief Event direction, one of RADIOLIB_LORAWAN_CHANNEL_DIR_* */ uint8_t dir; /*! \brief Whether the event is confirmed or not (e.g., confirmed uplink sent by user application) */ @@ -534,7 +534,7 @@ class LoRaWANNode { /*! \brief Returns the pointer to the internal buffer that holds the LW base parameters - \returns Pointer to uint8_t array of size RADIOLIB_LW_NONCES_BUF_SIZE + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_NONCES_BUF_SIZE */ uint8_t* getBufferNonces(); @@ -547,7 +547,7 @@ class LoRaWANNode { /*! \brief Returns the pointer to the internal buffer that holds the LW session parameters - \returns Pointer to uint8_t array of size RADIOLIB_LW_SESSION_BUF_SIZE + \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_SESSION_BUF_SIZE */ uint8_t* getBufferSession(); @@ -573,7 +573,7 @@ class LoRaWANNode { \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t activateOTAA(uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL); + int16_t activateOTAA(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL); /*! \brief Set the device credentials and activation configuration @@ -592,7 +592,7 @@ class LoRaWANNode { \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t activateABP(uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED); + int16_t activateABP(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \brief Whether there is an ongoing session active */ bool isActivated(); @@ -863,10 +863,10 @@ class LoRaWANNode { void activateCommon(uint8_t initialDr); // a buffer that holds all LW base parameters that should persist at all times! - uint8_t bufferNonces[RADIOLIB_LW_NONCES_BUF_SIZE] = { 0 }; + uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; // a buffer that holds all LW session parameters that preferably persist, but can be afforded to get lost - uint8_t bufferSession[RADIOLIB_LW_SESSION_BUF_SIZE] = { 0 }; + uint8_t bufferSession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE] = { 0 }; LoRaWANMacCommandQueue_t commandsUp = { .numCommands = 0, @@ -879,8 +879,8 @@ class LoRaWANNode { .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, }; - uint16_t lwMode = RADIOLIB_LW_MODE_NONE; - uint8_t lwClass = RADIOLIB_LW_CLASS_A; + uint16_t lwMode = RADIOLIB_LORAWAN_MODE_NONE; + uint8_t lwClass = RADIOLIB_LORAWAN_CLASS_A; bool isActive = false; uint64_t joinEUI = 0; @@ -905,16 +905,16 @@ class LoRaWANNode { // session-specific parameters uint32_t homeNetId = 0; - uint8_t adrLimitExp = RADIOLIB_LW_ADR_ACK_LIMIT_EXP; - uint8_t adrDelayExp = RADIOLIB_LW_ADR_ACK_DELAY_EXP; + uint8_t adrLimitExp = RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; + uint8_t adrDelayExp = RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; uint8_t nbTrans = 1; // Number of allowed frame retransmissions uint8_t txPowerSteps = 0; uint8_t txPowerMax = 0; uint32_t fCntUp = 0; uint32_t aFCntDown = 0; uint32_t nFCntDown = 0; - uint32_t confFCntUp = RADIOLIB_LW_FCNT_NONE; - uint32_t confFCntDown = RADIOLIB_LW_FCNT_NONE; + uint32_t confFCntUp = RADIOLIB_LORAWAN_FCNT_NONE; + uint32_t confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; uint32_t adrFCnt = 0; // whether the current configured channel is in FSK mode @@ -945,13 +945,13 @@ class LoRaWANNode { uint8_t difsSlots; // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t availableChannels[2][RADIOLIB_LW_NUM_AVAILABLE_CHANNELS]; + LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; // currently configured channels for TX and RX1 - LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LW_CHANNEL_NONE, RADIOLIB_LW_CHANNEL_NONE }; + LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; // currently configured datarates for TX and RX1 - uint8_t dataRates[2] = { RADIOLIB_LW_DATA_RATE_UNUSED, RADIOLIB_LW_DATA_RATE_UNUSED }; + uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED }; // LoRaWAN revision (1.0 vs 1.1) uint8_t rev = 0; @@ -966,7 +966,7 @@ class LoRaWANNode { RadioLibTime_t rxDelayEnd = 0; // delays between the uplink and RX1/2 windows - RadioLibTime_t rxDelays[2] = { RADIOLIB_LW_RECEIVE_DELAY_1_MS, RADIOLIB_LW_RECEIVE_DELAY_2_MS }; + RadioLibTime_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; // device status - battery level uint8_t battLevel = 0xFF; diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 2c927f3ef6..eaeb0841ab 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -3,7 +3,7 @@ #if !RADIOLIB_EXCLUDE_LORAWAN // array of pointers to currently supported LoRaWAN bands -const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LW_NUM_SUPPORTED_BANDS] = { +const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { &EU868, &US915, &CN780, @@ -17,7 +17,7 @@ const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LW_NUM_SUPPORTED_BANDS] = { const LoRaWANBand_t EU868 = { .bandNum = BandEU868, - .bandType = RADIOLIB_LW_BAND_DYNAMIC, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, @@ -30,55 +30,55 @@ const LoRaWANBand_t EU868 = { { .enabled = true, .idx = 2, .freq = 868.500, .drMin = 0, .drMax = 5}, }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LW_CHANNEL_SPAN_NONE, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 869.525, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_FSK_50_K, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t US915 = { .bandNum = BandUS915, - .bandType = RADIOLIB_LW_BAND_FIXED, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, - .dwellTimeUp = RADIOLIB_LW_DWELL_TIME, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, .txFreqs = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 2, .txSpans = { @@ -105,32 +105,32 @@ const LoRaWANBand_t US915 = { .freqStep = 0.600, .drMin = 8, .drMax = 13, - .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }, .rx1DataRateBase = 10, .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t CN780 = { .bandNum = BandCN780, - .bandType = RADIOLIB_LW_BAND_DYNAMIC, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, @@ -149,34 +149,34 @@ const LoRaWANBand_t CN780 = { }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LW_CHANNEL_SPAN_NONE, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 786.000, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_FSK_50_K, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t EU433 = { .bandNum = BandEU433, - .bandType = RADIOLIB_LW_BAND_DYNAMIC, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, @@ -189,40 +189,40 @@ const LoRaWANBand_t EU433 = { { .enabled = true, .idx = 2, .freq = 433.575, .drMin = 0, .drMax = 5}, }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LW_CHANNEL_SPAN_NONE, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 434.665, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_FSK_50_K, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t AU915 = { .bandNum = BandAU915, - .bandType = RADIOLIB_LW_BAND_FIXED, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, .powerMax = 30, .powerNumSteps = 10, @@ -230,14 +230,14 @@ const LoRaWANBand_t AU915 = { .dwellTimeUp = 0, .dwellTimeDn = 0, .txFreqs = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 2, .txSpans = { @@ -264,32 +264,32 @@ const LoRaWANBand_t AU915 = { .freqStep = 0.600, .drMin = 8, .drMax = 13, - .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }, .rx1DataRateBase = 8, .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_500_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t CN500 = { .bandNum = BandCN500, - .bandType = RADIOLIB_LW_BAND_FIXED, + .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, .powerNumSteps = 7, @@ -297,14 +297,14 @@ const LoRaWANBand_t CN500 = { .dwellTimeUp = 0, .dwellTimeDn = 0, .txFreqs = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 1, .txSpans = { @@ -316,7 +316,7 @@ const LoRaWANBand_t CN500 = { .drMax = 5, .joinRequestDataRate = 0 }, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = { .numChannels = 48, @@ -324,78 +324,78 @@ const LoRaWANBand_t CN500 = { .freqStep = 0.200, .drMin = 0, .drMax = 5, - .joinRequestDataRate = RADIOLIB_LW_DATA_RATE_UNUSED + .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 505.300, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_5, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t AS923 = { .bandNum = BandAS923, - .bandType = RADIOLIB_LW_BAND_DYNAMIC, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, - .dwellTimeUp = RADIOLIB_LW_DWELL_TIME, - .dwellTimeDn = RADIOLIB_LW_DWELL_TIME, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txFreqs = { { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LW_CHANNEL_SPAN_NONE, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 2, .drMax = 2 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_250_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_FSK_50_K, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t KR920 = { .bandNum = BandKR920, - .bandType = RADIOLIB_LW_BAND_DYNAMIC, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, .powerNumSteps = 7, @@ -408,40 +408,40 @@ const LoRaWANBand_t KR920 = { { .enabled = true, .idx = 2, .freq = 922.500, .drMin = 0, .drMax = 5} }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LW_CHANNEL_SPAN_NONE, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 921.900, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; const LoRaWANBand_t IN865 = { .bandNum = BandIN865, - .bandType = RADIOLIB_LW_BAND_DYNAMIC, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, .powerNumSteps = 10, @@ -454,34 +454,34 @@ const LoRaWANBand_t IN865 = { { .enabled = true, .idx = 2, .freq = 865.9850, .drMin = 0, .drMax = 5} }, .txJoinReq = { - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE, - RADIOLIB_LW_CHANNEL_NONE + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, .txSpans = { - RADIOLIB_LW_CHANNEL_SPAN_NONE, - RADIOLIB_LW_CHANNEL_SPAN_NONE + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, - .rx1Span = RADIOLIB_LW_CHANNEL_SPAN_NONE, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 866.550, .drMin = 2, .drMax = 2 }, .dataRates = { - RADIOLIB_LW_DATA_RATE_SF_12 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_11 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_10 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_9 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_8 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_SF_7 | RADIOLIB_LW_DATA_RATE_BW_125_KHZ | RADIOLIB_LW_DATA_RATE_CR_4_7, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_FSK_50_K, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED, - RADIOLIB_LW_DATA_RATE_UNUSED + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; From 88b4da94c1d0edaa74db683fd64fbc26aeafacee Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 13:13:35 +0200 Subject: [PATCH 1114/1848] [LoRaWAN] Fix cppcheck warnings --- src/protocols/LoRaWAN/LoRaWAN.cpp | 37 ++++++++++++++++--------------- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index deab820984..9399814a47 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -634,8 +634,9 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) (void)execMacCommand(&cmd); cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; + memset(cmd.payload, 0, RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN); cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; (void)execMacCommand(&cmd); // in case of dynamic band, setup the default channels first @@ -677,12 +678,11 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); // enqueue the RekeyInd MAC command to be sent in the next uplink - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_REKEY, - .payload = { this->rev }, - .len = sizeof(uint8_t), - .repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP, - }; + cmd.cid = RADIOLIB_LORAWAN_MAC_REKEY; + memset(cmd.payload, 0, RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN); + cmd.payload[0] = this->rev; + cmd.len = sizeof(uint8_t); + cmd.repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; state = pushMacCommand(&cmd, &this->commandsUp); RADIOLIB_ASSERT(state); @@ -1460,16 +1460,16 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // process the MAC command(s) int8_t remLen = fOptsLen; - uint8_t* fOptsPtr = fOpts; + uint8_t* fOptsPtrDn = fOpts; while(remLen > 0) { - uint8_t cid = *fOptsPtr; + uint8_t cid = *fOptsPtrDn; uint8_t macLen = getMacPayloadLength(cid); if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { // if there was an earlier ADR command but it was not the last, ignore it if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); remLen -= (macLen + 1); - fOptsPtr += (macLen + 1); + fOptsPtrDn += (macLen + 1); lastCID = cid; continue; } @@ -1485,7 +1485,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) .len = macLen, .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), }; - memcpy(cmd.payload, fOptsPtr + 1, macLen); + memcpy(cmd.payload, fOptsPtrDn + 1, macLen); // process the MAC command bool sendUp = execMacCommand(&cmd); @@ -1495,7 +1495,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // processing succeeded, move in the buffer to the next command remLen -= (macLen + 1); - fOptsPtr += (macLen + 1); + fOptsPtrDn += (macLen + 1); lastCID = cid; } @@ -1511,13 +1511,13 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #else uint8_t* fOptsBuff = new uint8_t[fOptsBufSize]; #endif - uint8_t* fOptsPtr = fOptsBuff; + uint8_t* fOptsPtrUp = fOptsBuff; // append all MAC replies into fOpts buffer int16_t i = 0; for (; i < this->commandsUp.numCommands; i++) { LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; - memcpy(fOptsPtr, &cmd, 1 + cmd.len); - fOptsPtr += cmd.len + 1; + memcpy(fOptsPtrUp, &cmd, 1 + cmd.len); + fOptsPtrUp += cmd.len + 1; } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsBufSize); @@ -1539,10 +1539,10 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) state = this->uplink(fOptsBuff, fOptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); this->dutyCycleEnabled = prevDC; - #if !RADIOLIB_STATIC_ONLY delete[] fOptsBuff; #endif + RADIOLIB_ASSERT(state); #if RADIOLIB_STATIC_ONLY uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -1730,6 +1730,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); RADIOLIB_ASSERT(state); state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); + RADIOLIB_ASSERT(state); } // downlink messages are sent with inverted IQ @@ -1994,7 +1995,7 @@ void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { if(!enable) { this->dutyCycle = 0; } - if(msPerHour <= 0) { + if(msPerHour == 0) { this->dutyCycle = this->band->dutyCycle; } else { this->dutyCycle = msPerHour; @@ -2024,7 +2025,7 @@ RadioLibTime_t LoRaWANNode::timeUntilUplink() { void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { this->dwellTimeEnabledUp = enable; - if(msPerUplink <= 0) { + if(msPerUplink == 0) { this->dwellTimeUp = this->band->dwellTimeUp; } else { this->dwellTimeUp = msPerUplink; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 7239550668..1e8c7315d1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -243,7 +243,7 @@ struct LoRaWANMacCommand_t { uint8_t cid; /*! \brief Payload buffer (5 bytes is the longest possible) */ - uint8_t payload[5]; + uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN]; /*! \brief Length of the payload */ uint8_t len; From d4b25e75afa0aa51d9e6b1d66a99d4a4401408b3 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 14:38:04 +0200 Subject: [PATCH 1115/1848] [LoRaWAN] Hide Rx2 config into guarded setRx2Dr() --- keywords.txt | 1 + src/TypeDef.h | 9 +++++++-- src/protocols/LoRaWAN/LoRaWAN.cpp | 30 ++++++++++++++++++++++++++++-- src/protocols/LoRaWAN/LoRaWAN.h | 22 +++++++++++++++------- 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/keywords.txt b/keywords.txt index 41cda13884..8c91e6f439 100644 --- a/keywords.txt +++ b/keywords.txt @@ -326,6 +326,7 @@ activateOTAA KEYWORD2 beginABP KEYWORD2 activateABP KEYWORD2 isActivated KEYWORD2 +setRx2Dr KEYWORD2 sendMacCommandReq KEYWORD2 uplink KEYWORD2 downlink KEYWORD2 diff --git a/src/TypeDef.h b/src/TypeDef.h index 30c78bd8e9..da3eccc8b4 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -509,9 +509,9 @@ #define RADIOLIB_ERR_NO_RX_WINDOW (-1105) /*! - \brief No valid channel for the currently active LoRaWAN band was found. + \brief There are no channels available for the requested datarate. */ -#define RADIOLIB_ERR_INVALID_CHANNEL (-1106) +#define RADIOLIB_ERR_NO_CHANNEL_AVAILABLE (-1106) /*! \brief Invalid LoRaWAN MAC command ID. @@ -583,6 +583,11 @@ */ #define RADIOLIB_LORAWAN_SESSION_DISCARDED (-1120) +/*! + \brief The requested command is unavailable under the current LoRaWAN mode. +*/ +#define RADIOLIB_LORAWAN_INVALID_MODE (-1121) + // LR11x0-specific status codes /*! diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 9399814a47..e61c0045db 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1920,8 +1920,7 @@ int16_t LoRaWANNode::selectChannels() { } } if(numChannels == 0) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("There are no channels defined - are you in ABP mode with no defined subband?"); - return(RADIOLIB_ERR_INVALID_CHANNEL); + return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); } // select a random ID & channel from the list of enabled and possible channels uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; @@ -2117,6 +2116,33 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { return(state); } +int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { + // this can only be configured in ABP mode + if(this->lwMode != RADIOLIB_LORAWAN_MODE_ABP) { + return(RADIOLIB_LORAWAN_INVALID_MODE); + } + + // can only configure different datarate for dynamic bands + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); + } + + // check if datarate is available in the selected band + if(this->band->dataRates[dr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + // find and check if the datarate is available for this radio module + DataRate_t dataRate; + int16_t state = findDataRate(dr, &dataRate); + RADIOLIB_ASSERT(state); + + // passed all checks, so configure the datarate + this->rx2.drMax = dr; + + return(state); +} + int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { bool valid = false; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 1e8c7315d1..674b018904 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -513,12 +513,6 @@ struct LoRaWANEvent_t { class LoRaWANNode { public: - /*! \brief Offset between TX and RX1 (such that RX1 has equal or lower DR) */ - uint8_t rx1DrOffset = 0; - - /*! \brief RX2 channel properties - may be changed by MAC command */ - LoRaWANChannel_t rx2; - /*! \brief Default constructor. \param phy Pointer to the PhysicalLayer radio module. @@ -589,7 +583,7 @@ class LoRaWANNode { /*! \brief Join network by restoring ABP session or performing over-the-air activation. In this procedure, all necessary configuration must be provided by the user. - \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled) + \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled). \returns \ref status_codes */ int16_t activateABP(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); @@ -597,6 +591,14 @@ class LoRaWANNode { /*! \brief Whether there is an ongoing session active */ bool isActivated(); + /*! + \brief Configure the Rx2 datarate for ABP mode. + This should not be needed for LoRaWAN 1.1 as it is configured through the first downlink. + \param dr The datarate to be used for listening for downlinks in Rx2. + \returns \ref status_codes + */ + int16_t setRx2Dr(uint8_t dr); + /*! \brief Add a MAC command to the uplink queue. Only LinkCheck and DeviceTime are available to the user. @@ -953,6 +955,12 @@ class LoRaWANNode { // currently configured datarates for TX and RX1 uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED }; + // Rx2 channel properties - may be changed by MAC command + LoRaWANChannel_t rx2 = RADIOLIB_LORAWAN_CHANNEL_NONE; + + // offset between TX and RX1 (such that RX1 has equal or lower DR) + uint8_t rx1DrOffset = 0; + // LoRaWAN revision (1.0 vs 1.1) uint8_t rev = 0; From ceb91c91c70f5c45029c5ae346669d43eed3ec9c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 14:40:52 +0200 Subject: [PATCH 1116/1848] Update return codes in keywords.txt --- keywords.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index 8c91e6f439..773df7a2b7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -451,7 +451,7 @@ RADIOLIB_ERR_DOWNLINK_MALFORMED LITERAL1 RADIOLIB_ERR_INVALID_REVISION LITERAL1 RADIOLIB_ERR_INVALID_PORT LITERAL1 RADIOLIB_ERR_NO_RX_WINDOW LITERAL1 -RADIOLIB_ERR_INVALID_CHANNEL LITERAL1 +RADIOLIB_ERR_NO_CHANNEL_AVAILABLE LITERAL1 RADIOLIB_ERR_INVALID_CID LITERAL1 RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 @@ -459,10 +459,16 @@ RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 -RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1 -RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 +RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 RADIOLIB_LORAWAN_NO_DOWNLINK LITERAL1 +RADIOLIB_LORAWAN_SESSION_RESTORED LITERAL1 +RADIOLIB_LORAWAN_NEW_SESSION LITERAL1 +RADIOLIB_LORAWAN_NONCES_DISCARDED LITERAL1 +RADIOLIB_LORAWAN_SESSION_DISCARDED LITERAL1 +RADIOLIB_LORAWAN_INVALID_MODE LITERAL1 + +RADIOLIB_ERR_INVALID_WIFI_TYPE LITERAL1 RADIOLIB_LR1110_FIRMWARE_IN_RAM LITERAL1 RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LITERAL1 From 237531c9a034ab51ae86485091578935ed1169cd Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 15:00:36 +0200 Subject: [PATCH 1117/1848] [LoRaWAN] Improve FPort checks, add TS009 option --- src/TypeDef.h | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 31 +++++++++++++++++++++++++++---- src/protocols/LoRaWAN/LoRaWAN.h | 15 +++++++++++---- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index da3eccc8b4..1d59bf6cb3 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -499,7 +499,7 @@ #define RADIOLIB_ERR_INVALID_REVISION (-1103) /*! - \brief Invalid LoRaWAN uplink port requested by user. + \brief Invalid LoRaWAN uplink port requested by user, or downlink received at invalid port. */ #define RADIOLIB_ERR_INVALID_PORT (-1104) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e61c0045db..3958c49793 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -877,9 +877,13 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon } // check destination fPort - if(fPort > 0xDF) { + if(fPort > RADIOLIB_LORAWAN_FPORT_RESERVED) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is RFU.", fPort); return(RADIOLIB_ERR_INVALID_PORT); } + if(fPort == RADIOLIB_LORAWAN_FPORT_TS009 && this->TS009 == false) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! TS009 was not enabled.", fPort); + } // fPort 0 is only allowed for MAC-only payloads if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { if (!this->isMACPayload) { @@ -900,9 +904,12 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon // check maximum payload len as defined in phy if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - // if testing with TS009 specification verification protocol, don't throw error but clip the message - // len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; + // normally, throw an error if the packet is too long + if(this->TS009 == false) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + // if testing with TS009 Specification Verification Protocol, don't throw error but clip the message + len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; } bool adrAckReq = false; @@ -1383,6 +1390,22 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) if(payLen > 0) { payLen -= 1; // subtract one as fPort is set fPort = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsLen)]; + // check if fPort value is actually allowed + if(fPort > RADIOLIB_LORAWAN_FPORT_RESERVED) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Received downlink at FPort %d - rejected! This FPort is RFU!", fPort); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } + if(fPort == RADIOLIB_LORAWAN_FPORT_TS009 && this->TS009 == false) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Received downlink at FPort %d - rejected! TS009 was not enabled.", fPort); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } + if(fPort > RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { isAppDownlink = true; } else { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 674b018904..f9c8ab8ff4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -41,7 +41,8 @@ // fPort field #define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only -#define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 reserved fPort values +#define RADIOLIB_LORAWAN_FPORT_TS009 (0xE0 << 0) // 7 0 fPort used for TS009 testing +#define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 fPort values equal to and larger than this are reserved // MAC commands - only those sent from end-device to gateway #define RADIOLIB_LORAWAN_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network @@ -849,10 +850,16 @@ class LoRaWANNode { uint64_t getDevAddr(); /*! - \brief Get the Time-on-air of the last uplink message - \returns (RadioLibTime_t) time-on-air (ToA) of last uplink message + \brief Get the Time-on-air of the last uplink message. + \returns (RadioLibTime_t) time-on-air (ToA) of last uplink message. */ - RadioLibTime_t getLastToA(); + RadioLibTime_t getLastToA(); + + /*! + \brief TS009 Protocol Specification Verification switch + (allows FPort 224 and cuts off uplink payload instead of rejecting if maximum length exceeded). + */ + bool TS009 = false; #if !RADIOLIB_GODMODE private: From 7186ae598bda79949268a372a1ae973eaf6d7f6a Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 15:12:36 +0200 Subject: [PATCH 1118/1848] [LoRaWAN] Improve debug output --- src/protocols/LoRaWAN/LoRaWAN.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 3958c49793..6b13b27bb4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -527,7 +527,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); this->rxDelayStart = mod->hal->millis(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Join-request sent <-- Rx Delay start"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest sent (DevNonce = %d) <-- Rx Delay start", this->devNonce); // join-request successfully sent, so increase & save devNonce this->devNonce += 1; @@ -547,7 +547,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // check received length size_t lenRx = this->phyLayer->getPacketLength(true); if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -561,7 +561,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // check reply message type if((joinAcceptMsgEnc[0] & RADIOLIB_LORAWAN_MHDR_MTYPE_MASK) != RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept reply message type invalid, expected 0x%02x got 0x%02x", RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_ACCEPT, joinAcceptMsgEnc[0]); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -572,15 +572,14 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) joinAcceptMsg[0] = joinAcceptMsgEnc[0]; RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); - - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:"); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); - // get current JoinNonce from downlink and previous JoinNonce from persistent storage + // get current joinNonce from downlink uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept (JoinNonce = %d, previously %d):", joinNonceNew, this->joinNonce); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinNoncePrev: %d, JoinNonce: %d", this->joinNonce, joinNonceNew); - // JoinNonce received must be greater than the last JoinNonce heard, else error + // joinNonce received must be greater than the last joinNonce heard, else error if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { return(RADIOLIB_ERR_JOIN_NONCE_INVALID); } @@ -1193,7 +1192,7 @@ int16_t LoRaWANNode::downlinkCommon() { // open Rx window by starting receive with specified timeout state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d us timeout)... <-- Rx Delay end ", i+1, (int)timeoutHost); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", i+1, (int)(timeoutHost / 1000 + scanGuard / 2)); // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); From 139fc7ee358536301cf1fb79e6121270827f49c7 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 25 May 2024 15:25:46 +0200 Subject: [PATCH 1119/1848] [LoRaWAN] Force default Rx2 for JoinAccept --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6b13b27bb4..67d1fd517f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -537,6 +537,9 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->rxDelays[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; + // make sure the Rx2 settings are back to this band's default + this->rx2 = this->band->rx2; + // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received state = downlinkCommon(); RADIOLIB_ASSERT(state); From 214a566d9a317c8538b2b893f78376f65d02159c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 08:43:02 +0200 Subject: [PATCH 1120/1848] [CC1101] Make frequency range check bounds inclusive --- src/modules/CC1101/CC1101.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 730065787a..57835377b3 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -424,11 +424,13 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { int16_t CC1101::setFrequency(float freq) { // check allowed frequency range - if(!(((freq > 300.0) && (freq < 348.0)) || - ((freq > 387.0) && (freq < 464.0)) || - ((freq > 779.0) && (freq < 928.0)))) { + #if RADIOLIB_CHECK_PARAMS + if(!(((freq >= 300.0) && (freq <= 348.0)) || + ((freq >= 387.0) && (freq <= 464.0)) || + ((freq >= 779.0) && (freq <= 928.0)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } + #endif // set mode to standby SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); From 77bc8fb33ea6947faf2b7fbe95d7df1734651522 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 08:44:12 +0200 Subject: [PATCH 1121/1848] [SX126x] Added missing override --- src/modules/SX126x/SX126x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index e1297adca2..d66351bb99 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -551,7 +551,7 @@ class SX126x: public PhysicalLayer { Overload with warm start enabled for PhysicalLayer compatibility. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). From 195339a0c7a93a822fd8bd41520dc9eed1bda6b3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 08:44:42 +0200 Subject: [PATCH 1122/1848] [LR11x0] Added missing override --- src/modules/LR11x0/LR11x0.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 6db2f78302..7ba95a98e8 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -824,7 +824,7 @@ class LR11x0: public PhysicalLayer { Overload with warm start enabled for PhysicalLayer compatibility. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). From 16710d4daeefed57e874701f4a6139213b395b10 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 08:45:42 +0200 Subject: [PATCH 1123/1848] [SX128x] Added missing override --- src/modules/SX128x/SX128x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 1a35228c27..c93d79c4dc 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -462,7 +462,7 @@ class SX128x: public PhysicalLayer { Overload for PhysicalLayer compatibility. \returns \ref status_codes */ - int16_t sleep(); + int16_t sleep() override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). From 6c114804169ee65863447de53c4903b538ebed84 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 08:49:02 +0200 Subject: [PATCH 1124/1848] [LR11x0] Cppcheck cleanup --- src/modules/LR11x0/LR11x0.cpp | 6 +++--- src/modules/LR11x0/LR11x0.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 1e5fe5b8f2..7c61568fc3 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1573,7 +1573,7 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat state = this->getVersion(NULL, &device, NULL, NULL); RADIOLIB_ASSERT(state); if(device != RADIOLIB_LR11X0_DEVICE_BOOT) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to put device to bootloader mode, %02x != %02x", device, RADIOLIB_LR11X0_DEVICE_BOOT); + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to put device to bootloader mode, %02x != %02x", (unsigned int)device, (unsigned int)RADIOLIB_LR11X0_DEVICE_BOOT); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } @@ -1611,7 +1611,7 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat state = this->getVersion(NULL, &device, NULL, NULL); RADIOLIB_ASSERT(state); if(device == RADIOLIB_LR11X0_DEVICE_BOOT) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to kick device from bootloader mode, %02x == %02x", device, RADIOLIB_LR11X0_DEVICE_BOOT); + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to kick device from bootloader mode, %02x == %02x", (unsigned int)device, (unsigned int)RADIOLIB_LR11X0_DEVICE_BOOT); return(RADIOLIB_ERR_CHIP_NOT_FOUND); } @@ -2487,7 +2487,7 @@ int16_t LR11x0::setRangingParameter(uint8_t symbolNum) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff))); } -int16_t LR11x0::setRssiCalibration(int8_t* tune, int16_t gainOffset) { +int16_t LR11x0::setRssiCalibration(const int8_t* tune, int16_t gainOffset) { uint8_t buff[11] = { (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4), (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4), diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 7ba95a98e8..1f87df811f 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1418,7 +1418,7 @@ class LR11x0: public PhysicalLayer { int16_t setGfskWhitParams(uint16_t seed); int16_t setRxBoosted(bool en); int16_t setRangingParameter(uint8_t symbolNum); - int16_t setRssiCalibration(int8_t* tune, int16_t gainOffset); + int16_t setRssiCalibration(const int8_t* tune, int16_t gainOffset); int16_t setLoRaSyncWord(uint8_t sync); int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len); int16_t lrFhssSetSyncWord(uint32_t sync); From 45d3aac0d9c95402b8443f57e7271c9df0fe58cc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 08:55:38 +0200 Subject: [PATCH 1125/1848] [CC1101] Fixed signed comparison warning --- src/modules/CC1101/CC1101.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 57835377b3..72830ce0dd 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -610,7 +610,7 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { // if just a check occurs (and not requesting the raw power value), return now if(!raw) { - for(int i = 0; i < sizeof(allowedPwrs); i++) { + for(size_t i = 0; i < sizeof(allowedPwrs); i++) { if(allowedPwrs[i] == power) { return(RADIOLIB_ERR_NONE); } From 525fdfb1a011c1bbf71e5425ab76e9f71f8bbbee Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 09:02:23 +0200 Subject: [PATCH 1126/1848] [LoRaWAN] Cppcheck cleanup --- src/protocols/LoRaWAN/LoRaWAN.cpp | 15 ++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 67d1fd517f..476eb3264c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -550,7 +550,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // check received length size_t lenRx = this->phyLayer->getPacketLength(true); if((lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) && (lenRx != RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, lenRx); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept reply length mismatch, expected %dB got %luB", RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN, (unsigned long)lenRx); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -579,7 +579,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // get current joinNonce from downlink uint32_t joinNonceNew = LoRaWANNode::ntoh(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept (JoinNonce = %d, previously %d):", joinNonceNew, this->joinNonce); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept (JoinNonce = %lu, previously %lu):", (unsigned long)joinNonceNew, (unsigned long)this->joinNonce); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); // joinNonce received must be greater than the last joinNonce heard, else error @@ -1082,7 +1082,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %d) decoded:", this->fCntUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %lu) decoded:", (unsigned long)this->fCntUp); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -1309,7 +1309,7 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // check the minimum required frame length // an extra byte is subtracted because downlink frames may not have a fPort if(downlinkMsgLen < RADIOLIB_LORAWAN_FRAME_LEN(0, 0) - 1 - RADIOLIB_AES128_BLOCK_SIZE) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", downlinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink message too short (%lu bytes)", (unsigned long)downlinkMsgLen); return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } @@ -2269,7 +2269,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } break; case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { - int16_t state = RADIOLIB_ERR_UNKNOWN; // get the ADR configuration uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; uint8_t txSteps = cmd->payload[0] & 0x0F; @@ -2281,6 +2280,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTrans); // try to apply the datarate configuration + int16_t state; uint8_t drAck = 0; if(drUp == 0x0F) { // keep the same drAck = 1; @@ -2851,7 +2851,8 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { for (LoRaWANMacSpec_t entry : MacTable) { - if (entry.cid == cid) { + // cppcheck warns here we should use std::find_if, but some platforms may not have that + if (entry.cid == cid) { // cppcheck-suppress useStlAlgorithm return entry.lenDn; } } @@ -2939,7 +2940,7 @@ bool LoRaWANNode::performCAD() { return false; // Channel is free } -void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { +void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; if(len % RADIOLIB_AES128_BLOCK_SIZE) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index f9c8ab8ff4..7da5565157 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -954,7 +954,7 @@ class LoRaWANNode { uint8_t difsSlots; // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } }; // currently configured channels for TX and RX1 LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; @@ -1064,7 +1064,7 @@ class LoRaWANNode { bool performCAD(); // function to encrypt and decrypt payloads - void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); + void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum static uint16_t checkSum16(uint8_t *key, uint16_t keyLen); From 99bb02517323ca6325b507829225d259373812dc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 09:07:07 +0200 Subject: [PATCH 1127/1848] [PHY] Added missing zero inits --- src/protocols/PhysicalLayer/PhysicalLayer.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 9b3dc24cac..a32997d3f0 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -529,15 +529,15 @@ class PhysicalLayer { size_t maxPacketLength; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE - uint8_t bufferBitPos; - uint8_t bufferWritePos; - uint8_t bufferReadPos; - uint8_t buffer[RADIOLIB_STATIC_ARRAY_SIZE]; - uint32_t syncBuffer; - uint32_t directSyncWord; - uint8_t directSyncWordLen; - uint32_t directSyncWordMask; - bool gotSync; + uint8_t bufferBitPos = 0; + uint8_t bufferWritePos = 0; + uint8_t bufferReadPos = 0; + uint8_t buffer[RADIOLIB_STATIC_ARRAY_SIZE] = { 0 }; + uint32_t syncBuffer = 0; + uint32_t directSyncWord = 0; + uint8_t directSyncWordLen = 0; + uint32_t directSyncWordMask = 0; + bool gotSync = false; #endif virtual Module* getMod() = 0; From a5e2e58c36593df193bedcea5200b7aa8f90f069 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 09:22:28 +0200 Subject: [PATCH 1128/1848] [CI] Skip Pager examples for Uno --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 67adb83bbd..113e817893 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,7 +46,7 @@ jobs: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. include: - id: arduino:avr:uno - run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update|Pager)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: | echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT From 9a9e04d0474b7977fd9c663e8d31bfb8868a8b37 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 09:25:13 +0200 Subject: [PATCH 1129/1848] Add check for self-assignment --- src/protocols/AX25/AX25.cpp | 20 ++++++++++--------- src/protocols/ExternalRadio/ExternalRadio.cpp | 8 +++++--- src/protocols/Print/ITA2String.cpp | 14 +++++++------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 480ea343d3..c5913e9478 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -214,16 +214,18 @@ AX25Client::AX25Client(const AX25Client& ax25) } AX25Client& AX25Client::operator=(const AX25Client& ax25) { - this->phyLayer = ax25.phyLayer; - this->sourceSSID = ax25.sourceSSID; - this->preambleLen = ax25.preambleLen; - strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); - #if !RADIOLIB_EXCLUDE_AFSK - if(ax25.bellModem) { - this->audio = ax25.audio; - this->bellModem = new BellClient(ax25.audio); + if(&ax25 != this) { + this->phyLayer = ax25.phyLayer; + this->sourceSSID = ax25.sourceSSID; + this->preambleLen = ax25.preambleLen; + strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1); + #if !RADIOLIB_EXCLUDE_AFSK + if(ax25.bellModem) { + this->audio = ax25.audio; + this->bellModem = new BellClient(ax25.audio); + } + #endif } - #endif return(*this); } diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index d8c3a5fa46..212f8a155b 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -22,9 +22,11 @@ ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer(1, 0) { } ExternalRadio& ExternalRadio::operator=(const ExternalRadio& ext) { - this->prevFrf = ext.prevFrf; - if(ext.mod) { - this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio()); + if(&ext != this) { + this->prevFrf = ext.prevFrf; + if(ext.mod) { + this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio()); + } } return(*this); } diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp index 6c67faa541..368edebf32 100644 --- a/src/protocols/Print/ITA2String.cpp +++ b/src/protocols/Print/ITA2String.cpp @@ -30,12 +30,14 @@ ITA2String::ITA2String(const ITA2String& ita2) { } ITA2String& ITA2String::operator=(const ITA2String& ita2) { - this->asciiLen = ita2.asciiLen; - this->ita2Len = ita2.ita2Len; - #if !RADIOLIB_STATIC_ONLY - this->strAscii = new char[asciiLen + 1]; - #endif - strcpy(this->strAscii, ita2.strAscii); + if(&ita2 != this) { + this->asciiLen = ita2.asciiLen; + this->ita2Len = ita2.ita2Len; + #if !RADIOLIB_STATIC_ONLY + this->strAscii = new char[asciiLen + 1]; + #endif + strcpy(this->strAscii, ita2.strAscii); + } return(*this); } From 79d10c242ad264529284559f68e05fd4fedafb09 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 09:27:00 +0200 Subject: [PATCH 1130/1848] [LoRaWAN] Use memset for channel array init --- src/protocols/LoRaWAN/LoRaWAN.cpp | 1 + src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 476eb3264c..02c200a72c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -36,6 +36,7 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t this->difsSlots = 2; this->backoffMax = 6; this->enableCSMA = false; + memset(this->availableChannels, 0, sizeof(this->availableChannels)); } void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 7da5565157..fd75da52a3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -954,7 +954,7 @@ class LoRaWANNode { uint8_t difsSlots; // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS] = { { 0 }, { 0 } }; + LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; // currently configured channels for TX and RX1 LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; From 41f89198aac4974e64b01f283792d7ef06f04890 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 09:31:59 +0200 Subject: [PATCH 1131/1848] [Crypto] Suppress cppcheck unused private function --- src/utils/Cryptography.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index dd6644e45c..ed8f4d7a82 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -155,8 +155,6 @@ class RadioLibAES128 { void subWord(uint8_t* word); void rotWord(uint8_t* word); - void addRoundKey(uint8_t round, state_t* state, const uint8_t* roundKey); - void blockXor(uint8_t* dst, const uint8_t* a, const uint8_t* b); void blockLeftshift(uint8_t* dst, const uint8_t* src); void generateSubkeys(uint8_t* key1, uint8_t* key2); @@ -165,7 +163,9 @@ class RadioLibAES128 { void shiftRows(state_t* state, bool inv); void mixColumns(state_t* state, bool inv); - uint8_t mul(uint8_t a, uint8_t b); + // cppcheck seems convinced these are nut used, which is not true + uint8_t mul(uint8_t a, uint8_t b); // cppcheck-suppress unusedPrivateFunction + void addRoundKey(uint8_t round, state_t* state, const uint8_t* roundKey); // cppcheck-suppress unusedPrivateFunction }; // the global singleton From cc2cb2c9a00d4838df0dcf6b4ff71e95eee4e5f6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 11:26:15 +0100 Subject: [PATCH 1132/1848] [LoRaWAN] Fix shadowed variable --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 02c200a72c..eb2c9e5527 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2277,8 +2277,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; - uint8_t nbTrans = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTrans); + uint8_t nbTransMac = cmd->payload[3] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTransMac); // try to apply the datarate configuration int16_t state; @@ -2349,8 +2349,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { } } - if(nbTrans) { // if there is a value for NbTrans, set this value - this->nbTrans = nbTrans; + if(nbTransMac) { // if there is a value for NbTrans, set this value + this->nbTrans = nbTransMac; } // replace 'placeholder' or failed values with the current values for saving @@ -2362,7 +2362,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { if(txSteps == 0x0F || !pwrAck) { cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerSteps; } - if(nbTrans == 0) { + if(nbTransMac == 0) { cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; } From bb7c6592fcd7273ad3e5ac1b34302d03f61ef1da Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 12:49:14 +0100 Subject: [PATCH 1133/1848] [CI] Add cppcheck script --- .github/workflows/cppcheck.yml | 8 +++----- extras/cppcheck/cppcheck.sh | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100755 extras/cppcheck/cppcheck.sh diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 8f3ec3df76..43a815babd 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -18,10 +18,8 @@ jobs: - name: Install cppcheck run: - | - sudo apt-get update - sudo apt-get install -y cppcheck + - sudo apt-get update + - sudo apt-get install -y cppcheck - name: Run cppcheck - run: - cppcheck src --enable=all --force --inline-suppr --quiet --suppress=ConfigurationNotChecked --suppress=unusedFunction + run: ./extras/cppcheck/cppcheck.sh diff --git a/extras/cppcheck/cppcheck.sh b/extras/cppcheck/cppcheck.sh new file mode 100755 index 0000000000..d5906e1871 --- /dev/null +++ b/extras/cppcheck/cppcheck.sh @@ -0,0 +1,19 @@ +#! /bin/bash + +file=cppcheck.txt +cppcheck --version +cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked --suppress=unusedFunction --quiet >> $file 2>&1 +echo "Cppcheck finished with exit code $?" + +error=$(grep ": error:" $file | wc -l) +warning=$(grep ": warning:" $file | wc -l) +style=$(grep ": style:" $file | wc -l) +echo "found $error erros, $warning warnings and $style style issues" +if [ $error -gt "0" ] || [ $warning -gt "0" ] || [ $style -gt "0" ] +then + cat $file + exitcode=1 +fi + +rm $file +exit $exitcode From 0d491060b2e280959c4af75150427995b49af382 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 12:50:02 +0100 Subject: [PATCH 1134/1848] [CI] Fix cppcheck sequence --- .github/workflows/cppcheck.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 43a815babd..2c3edf88e4 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -17,9 +17,9 @@ jobs: uses: actions/checkout@v4 - name: Install cppcheck - run: - - sudo apt-get update - - sudo apt-get install -y cppcheck + run: | + sudo apt-get update + sudo apt-get install -y cppcheck - name: Run cppcheck run: ./extras/cppcheck/cppcheck.sh From c3e99c8698269f3eba1a3b4682a40d65c35e1fbb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 14:11:05 +0200 Subject: [PATCH 1135/1848] [LR11x0] Make regulator mode and Rx gain config public (#1108) --- src/modules/LR11x0/LR11x0.cpp | 27 ++++++++++++++++++++++----- src/modules/LR11x0/LR11x0.h | 20 +++++++++++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 7c61568fc3..c9d44f695d 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -44,6 +44,9 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t state = invertIQ(false); RADIOLIB_ASSERT(state); + state = setRegulatorLDO(); + RADIOLIB_ASSERT(state); + return(RADIOLIB_ERR_NONE); } @@ -85,6 +88,9 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uin state = setCRC(2); RADIOLIB_ASSERT(state); + state = setRegulatorLDO(); + RADIOLIB_ASSERT(state); + return(RADIOLIB_ERR_NONE); } @@ -103,6 +109,9 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVolt state = setSyncWord(0x12AD101B); RADIOLIB_ASSERT(state); + state = setRegulatorLDO(); + RADIOLIB_ASSERT(state); + // set fixed configuration return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0)); } @@ -1363,6 +1372,19 @@ float LR11x0::getDataRate() const { return(this->dataRateMeasured); } +int16_t LR11x0::setRegulatorLDO() { + return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_LDO)); +} + +int16_t LR11x0::setRegulatorDCDC() { + return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_DC_DC)); +} + +int16_t LR11x0::setRxBoostedGainMode(bool en) { + uint8_t buff[1] = { (uint8_t)en }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff))); +} + int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -2476,11 +2498,6 @@ int16_t LR11x0::setGfskWhitParams(uint16_t seed) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff))); } -int16_t LR11x0::setRxBoosted(bool en) { - uint8_t buff[1] = { (uint8_t)en }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff))); -} - int16_t LR11x0::setRangingParameter(uint8_t symbolNum) { // the first byte is reserved uint8_t buff[2] = { 0x00, symbolNum }; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 1f87df811f..1c48b536f4 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1247,6 +1247,25 @@ class LR11x0: public PhysicalLayer { */ float getDataRate() const; + /*! + \brief Set regulator mode to LDO. + \returns \ref status_codes + */ + int16_t setRegulatorLDO(); + + /*! + \brief Set regulator mode to DC-DC. + \returns \ref status_codes + */ + int16_t setRegulatorDCDC(); + + /*! + \brief Enables or disables Rx Boosted Gain mode (additional Rx gain for increased power consumption). + \param en True for Rx Boosted Gain, false for Rx Power Saving Gain + \returns \ref status_codes + */ + int16_t setRxBoostedGainMode(bool en); + /*! \brief Sets LR-FHSS configuration. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. @@ -1416,7 +1435,6 @@ class LR11x0: public PhysicalLayer { int16_t setRangingTxRxDelay(uint32_t delay); int16_t setGfskCrcParams(uint32_t init, uint32_t poly); int16_t setGfskWhitParams(uint16_t seed); - int16_t setRxBoosted(bool en); int16_t setRangingParameter(uint8_t symbolNum); int16_t setRssiCalibration(const int8_t* tune, int16_t gainOffset); int16_t setLoRaSyncWord(uint8_t sync); From 852d336c503cb4a0e1da5bd9a505670b7c3a54a0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 16:32:51 +0200 Subject: [PATCH 1136/1848] [SX126x] Added getMod implementation --- src/modules/SX126x/SX126x.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 50eeaca1b5..3b9f1b47ab 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1717,6 +1717,10 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } +Module* SX126x::getMod() { + return(this->mod); +} + int16_t SX126x::setFs() { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); } From f78b3ccc978990e9ef118067244552046110206d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 16:36:42 +0200 Subject: [PATCH 1137/1848] [MOD] Increase maximum number of RF switch pins to 5 --- .../STM32WLx_Channel_Activity_Detection.ino | 2 +- .../STM32WLx_Channel_Activity_Detection_Interrupt.ino | 2 +- .../STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino | 2 +- .../STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino | 2 +- .../STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino | 2 +- .../STM32WLx_Transmit_Interrupt.ino | 2 +- src/Module.cpp | 4 ++-- src/Module.h | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino index da07078265..7beab1ee2a 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino @@ -24,7 +24,7 @@ STM32WLx radio = new STM32WLx_Module(); // Some boards may not have either LP or HP. // For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = - {PC3, PC4, PC5}; + {PC3, PC4, PC5, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino index 9c14329d24..d730734f27 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -24,7 +24,7 @@ STM32WLx radio = new STM32WLx_Module(); // Some boards may not have either LP or HP. // For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = - {PC3, PC4, PC5}; + {PC3, PC4, PC5, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino index e2e90d62ba..5eaf4015d3 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino @@ -40,7 +40,7 @@ STM32WLx radio = new STM32WLx_Module(); // Some boards may not have either LP or HP. // For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = - {PC3, PC4, PC5}; + {PC3, PC4, PC5, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index 6d91cea4b6..a4841f930a 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -34,7 +34,7 @@ STM32WLx radio = new STM32WLx_Module(); // Some boards may not have either LP or HP. // For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = - {PC3, PC4, PC5}; + {PC3, PC4, PC5, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino index d35680a3a4..2bd2b02b44 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -35,7 +35,7 @@ STM32WLx radio = new STM32WLx_Module(); // Some boards may not have either LP or HP. // For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = - {PC3, PC4, PC5}; + {PC3, PC4, PC5, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index 60777c0284..d22f77b5ee 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -26,7 +26,7 @@ STM32WLx radio = new STM32WLx_Module(); // Some boards may not have either LP or HP. // For those, do not set the LP/HP entry in the table. static const uint32_t rfswitch_pins[] = - {PC3, PC4, PC5}; + {PC3, PC4, PC5, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { {STM32WLx::MODE_IDLE, {LOW, LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, HIGH, LOW}}, diff --git a/src/Module.cpp b/src/Module.cpp index 2dc3797576..72d5ba59c2 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -565,7 +565,7 @@ size_t Module::serialPrintf(const char* format, ...) { void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { // This can be on the stack, setRfSwitchTable copies the contents const uint32_t pins[] = { - rxEn, txEn, RADIOLIB_NC, + rxEn, txEn, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, }; // This must be static, since setRfSwitchTable stores a reference. @@ -578,7 +578,7 @@ void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { setRfSwitchTable(pins, table); } -void Module::setRfSwitchTable(const uint32_t (&pins)[3], const RfSwitchMode_t table[]) { +void Module::setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]) { memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins)); this->rfSwitchTable = table; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) diff --git a/src/Module.h b/src/Module.h index 72cb8e74c8..0cae41140b 100644 --- a/src/Module.h +++ b/src/Module.h @@ -71,7 +71,7 @@ class Module { value is ever increased and such an array gets extra zero elements (that will be interpreted as pin 0). */ - static const size_t RFSWITCH_MAX_PINS = 3; + static const size_t RFSWITCH_MAX_PINS = 5; /*! \struct RfSwitchMode_t @@ -546,7 +546,7 @@ class Module { uint32_t gpioPin = RADIOLIB_NC; // RF switch pins and table - uint32_t rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + uint32_t rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; const RfSwitchMode_t *rfSwitchTable = nullptr; #if RADIOLIB_INTERRUPT_TIMING From 3af427fefbcc13f42754f89dfa76ce59c709d264 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 16:43:54 +0200 Subject: [PATCH 1138/1848] [SX126x] Fix duplicate method --- src/modules/SX126x/SX126x.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 3b9f1b47ab..50eeaca1b5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1717,10 +1717,6 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } -Module* SX126x::getMod() { - return(this->mod); -} - int16_t SX126x::setFs() { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); } From a465f64969b7c05728578a9596e5067b27248728 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 17:03:45 +0200 Subject: [PATCH 1139/1848] [LR11x0] Implemented RF switch control --- ...x0_Channel_Activity_Detection_Blocking.ino | 31 +++++++++-- ...0_Channel_Activity_Detection_Interrupt.ino | 51 +++++++++++++----- .../LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino | 22 ++++---- .../LR11x0_LR_FHSS_Modem.ino | 22 ++++---- .../LR11x0_Receive_Blocking.ino | 31 +++++++++-- .../LR11x0_Receive_Interrupt.ino | 53 ++++++++++++++----- .../LR11x0_Transmit_Blocking.ino | 42 ++++++++++----- .../LR11x0_Transmit_Interrupt.ino | 31 +++++++++-- .../LR11x0_WiFi_Scan_Blocking.ino | 31 +++++++++-- .../LR11x0_WiFi_Scan_Interrupt.ino | 31 +++++++++-- src/modules/LR11x0/LR11x0.cpp | 22 ++++++++ src/modules/LR11x0/LR11x0.h | 31 +++++++++++ 12 files changed, 320 insertions(+), 78 deletions(-) diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino index 171c87de3f..d6cab7c7f4 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -7,6 +7,10 @@ of LoRa transmission, not just the preamble. Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. Using blocking CAD is not recommended, as it will lead to significant amount of timeouts, inefficient use of processor @@ -30,13 +34,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index 90f0c8aa4f..86578afb1c 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -1,18 +1,22 @@ /* - RadioLib LR11x0 Channel Activity Detection Example + RadioLib LR11x0 Channel Activity Detection Example - This example uses LR1110 to scan the current LoRa - channel and detect ongoing LoRa transmissions. - Unlike SX127x CAD, LR11x0 can detect any part - of LoRa transmission, not just the preamble. + This example uses LR1110 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, LR11x0 can detect any part + of LoRa transmission, not just the preamble. - Other modules from LR11x0 family can also be used. + Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -25,13 +29,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino index 45dc0507ba..bc0a59d0e2 100644 --- a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino +++ b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino @@ -1,19 +1,19 @@ /* - RadioLib LR11x0 GFSK Modem Example + RadioLib LR11x0 GFSK Modem Example - This example shows how to use GFSK modem in LR11x0 chips. + This example shows how to use GFSK modem in LR11x0 chips. - NOTE: The sketch below is just a guide on how to use - GFSK modem, so this code should not be run directly! - Instead, modify the other examples to use GFSK - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + GFSK modem, so this code should not be run directly! + Instead, modify the other examples to use GFSK + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino index a46d8a821e..094fce29b5 100644 --- a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -1,19 +1,19 @@ /* - RadioLib LR11x0 LR-FHSS Modem Example + RadioLib LR11x0 LR-FHSS Modem Example - This example shows how to use LR-FHSS modem in LR11x0 chips. + This example shows how to use LR-FHSS modem in LR11x0 chips. - NOTE: The sketch below is just a guide on how to use - LR-FHSS modem, so this code should not be run directly! - Instead, modify the other examples to use LR-FHSS - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + LR-FHSS modem, so this code should not be run directly! + Instead, modify the other examples to use LR-FHSS + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lr-fhss-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lr-fhss-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino index 8d0efc9a54..3e3c9eabd8 100644 --- a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -12,6 +12,10 @@ - preamble length Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. Using blocking receive is not recommended, as it will lead to significant amount of timeouts, inefficient use of processor @@ -35,13 +39,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index f20f2aafb2..b8be9c9b0f 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -1,24 +1,28 @@ /* - RadioLib LR11x0 Receive with Interrupts Example + RadioLib LR11x0 Receive with Interrupts Example - This example listens for LoRa transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. To successfully receive data, the following - settings have to be the same on both transmitter - and receiver: + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: - carrier frequency - bandwidth - spreading factor - coding rate - sync word - Other modules from LR11x0 family can also be used. + Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,13 +35,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index 741102ac24..8700369ec8 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -8,6 +8,10 @@ - arbitrary binary data (byte array) Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem @@ -26,13 +30,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -44,17 +69,6 @@ void setup() { delay(1000); while (true); } - - // some modules have an external RF switch - - // controlled via two pins (RX enable, TX enable) - // to enable automatic control of the switch, - // call the following method - // RX enable: 4 - // TX enable: 5 - /* - radio.setRfSwitchPins(4, 5); - */ } // counter to keep track of transmitted packets diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index e47c68f728..0593253ad3 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -9,6 +9,10 @@ - arbitrary binary data (byte array) Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem @@ -27,9 +31,26 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; @@ -37,6 +58,10 @@ int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino index b1643a3397..be898e4d9f 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino @@ -6,6 +6,10 @@ such as the frequency, country code and SSID. Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. Using blocking scan is not recommended, as depending on the scan settings, the program may be blocked @@ -28,13 +32,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino index bf999ba15d..af00066f96 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -6,6 +6,10 @@ such as the frequency, country code and SSID. Other modules from LR11x0 family can also be used. + + This example assumes Seeed Studio Wio WM1110 is used. + For other LR11x0 modules, some configuration such as + RF switch control may have to be adjusted. Using blocking scan is not recommended, as depending on the scan settings, the program may be blocked @@ -28,13 +32,34 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, + { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + END_OF_MODE_TABLE, +}; void setup() { Serial.begin(9600); + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index c9d44f695d..f7dea326c0 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1385,6 +1385,28 @@ int16_t LR11x0::setRxBoostedGainMode(bool en) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff))); } +void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + // find which pins are used + uint8_t enable = 0; + for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) { + if((pins[i] == RADIOLIB_NC) || (pins[i] > RADIOLIB_LR11X0_DIO10)) { + continue; + } + enable |= 1UL << pins[i]; + } + + // now get the configuration + uint8_t modes[7] = { 0 }; + for(size_t i = 0; i < 7; i++) { + for(size_t j = 0; j < Module::RFSWITCH_MAX_PINS; j++) { + modes[i] |= (table[i].values[j] > 0) ? (1UL << j) : 0; + } + } + + // set it + this->setDioAsRfSwitch(enable, modes[0], modes[1], modes[2], modes[3], modes[4], modes[5], modes[6]); +} + int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 1c48b536f4..4f60f9e5f6 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -240,6 +240,11 @@ #define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default) #define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled #define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default) +#define RADIOLIB_LR11X0_DIO5 (0) +#define RADIOLIB_LR11X0_DIO6 (1) +#define RADIOLIB_LR11X0_DIO7 (2) +#define RADIOLIB_LR11X0_DIO8 (3) +#define RADIOLIB_LR11X0_DIO10 (4) // RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS #define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted @@ -710,6 +715,29 @@ class LR11x0: public PhysicalLayer { */ explicit LR11x0(Module* mod); + /*! + \brief Custom operation modes for LR11x0. + Needed because LR11x0 has several modems (sub-GHz, 2.4 GHz etc.) in one package + */ + enum OpMode_t { + /*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */ + MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE, + /*! Standby/idle mode */ + MODE_STBY = Module::MODE_IDLE, + /*! Receive mode */ + MODE_RX = Module::MODE_RX, + /*! Low power transmission mode */ + MODE_TX = Module::MODE_TX, + /*! High power transmission mode */ + MODE_TX_HP, + /*! High frequency transmission mode */ + MODE_TX_HF, + /*! GNSS scanning mode */ + MODE_GNSS, + /*! WiFi scanning mode */ + MODE_WIFI, + }; + /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. */ @@ -1266,6 +1294,9 @@ class LR11x0: public PhysicalLayer { */ int16_t setRxBoostedGainMode(bool en); + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! \brief Sets LR-FHSS configuration. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. From 2536d8842cbabdfd9ca11ac03aa9c3398b443f28 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 18:59:05 +0200 Subject: [PATCH 1140/1848] Added PR template --- .../PULL_REQUEST_TEMPLATE/pull_request_template.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 0000000000..0855981a27 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,14 @@ +## Pull request template +Thank you for taking the time to contribute to RadioLib development! +To keep this library organized, please follow these rules. + +1. Make sure the the code in your PR is tested and that you understand all its impacts. +2. Ensure that all CI actions pass - PRs with failed CI will not be merged. CI actions run automatically for every commit pushed to the PR and test the following: + a. Compilation for Arduino, ESP-IDF and on Raspberry Pi + b. Runtime test on Raspberry Pi + c. GitHub CodeQL check + d. Cppcheck static code scan +3. Follow code style guidelines in [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md) +4. Heads up - all PRs undergo review, during which you may be asked to correct or change some things. The purpose of this review is to keep regressions and bugs at the minimum, and to keep consistent coding style. Please take them as constructive criticism from people who may have a different point-of-view than you do. + +After addressing/accepting the points above, delete the contents of this template and replace it with text explaining what is the goal of your PR, why you want to add it to the upstream and what are the foreseen impacts. Once again, thank you for taking the time to contribute! From 62df57885ac7fc8461546de24a1d3ed8a16a12af Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 May 2024 19:05:23 +0200 Subject: [PATCH 1141/1848] Move PR template --- .github/{PULL_REQUEST_TEMPLATE => }/pull_request_template.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{PULL_REQUEST_TEMPLATE => }/pull_request_template.md (100%) diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/pull_request_template.md rename to .github/pull_request_template.md From 6bd3f92cad04c564aeaf92f16703e0a2087e8030 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 May 2024 21:22:19 +0200 Subject: [PATCH 1142/1848] [LR11x0] Update RF switch map for WM1110 --- ...x0_Channel_Activity_Detection_Blocking.ino | 21 +++++++++---------- ...0_Channel_Activity_Detection_Interrupt.ino | 21 +++++++++---------- .../LR11x0_Receive_Blocking.ino | 21 +++++++++---------- .../LR11x0_Receive_Interrupt.ino | 21 +++++++++---------- .../LR11x0_Transmit_Blocking.ino | 21 +++++++++---------- .../LR11x0_Transmit_Interrupt.ino | 21 +++++++++---------- .../LR11x0_WiFi_Scan_Blocking.ino | 21 +++++++++---------- .../LR11x0_WiFi_Scan_Interrupt.ino | 21 +++++++++---------- 8 files changed, 80 insertions(+), 88 deletions(-) diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino index d6cab7c7f4..10712cd8db 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -35,23 +35,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index 86578afb1c..c1f29aa305 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -30,23 +30,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino index 3e3c9eabd8..cd40b81631 100644 --- a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -40,23 +40,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index b8be9c9b0f..1f9c86b200 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -36,23 +36,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index 8700369ec8..9ec59be1a1 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -31,23 +31,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 0593253ad3..459a1d3033 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -32,23 +32,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino index be898e4d9f..e2cafbef41 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino @@ -33,23 +33,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino index af00066f96..37b2431c36 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -33,23 +33,22 @@ LR1110 radio = new Module(10, 2, 3, 9); // set RF switch configuration for Wio WM1110 -// Wio WM1110 uses DIO5, 6, 7 and 8 for RF switching +// Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! static const uint32_t rfswitch_dio_pins[] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, - RADIOLIB_LR11X0_DIO7, RADIOLIB_LR11X0_DIO8, - RADIOLIB_NC + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 DIO8 - { LR11x0::MODE_STBY, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_RX, { HIGH, LOW, LOW, LOW } }, - { LR11x0::MODE_TX, { HIGH, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HP, { LOW, HIGH, LOW, LOW } }, - { LR11x0::MODE_TX_HF, { LOW, LOW, LOW, LOW } }, - { LR11x0::MODE_GNSS, { LOW, LOW, HIGH, LOW } }, - { LR11x0::MODE_WIFI, { LOW, LOW, LOW, HIGH } }, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, END_OF_MODE_TABLE, }; From 7d96b4290e26d534df72232814e1f8705f189484 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 May 2024 17:53:19 +0200 Subject: [PATCH 1143/1848] Bump version to 6.6.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 2a2ae157dd..a388ba0cb8 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "6.5.0" +version: "6.6.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121" url: "https://github.com/jgromes/RadioLib" diff --git a/library.json b/library.json index 3f91e3e963..2629b7097b 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.5.0", + "version": "6.6.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index d7abb49501..3d5f6ca65e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.5.0 +version=6.6.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 9d860abe2b..9e905aabc4 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -570,7 +570,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 6 -#define RADIOLIB_VERSION_MINOR 5 +#define RADIOLIB_VERSION_MINOR 6 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From e1830052a384d91bb209670b9797467fcdbc1896 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 May 2024 18:20:57 +0200 Subject: [PATCH 1144/1848] [CI] Temporarily disable ESP32 CI (platform broken) (CI_BUILD_ALL) --- .github/workflows/main.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 113e817893..280a0b1f0f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,6 @@ on: - arduino:samd:arduino_zero_native - adafruit:samd:adafruit_feather_m0 - adafruit:nrf52:feather52832 - - esp32:esp32:esp32 - esp8266:esp8266:generic - Intel:arc32:arduino_101 - SparkFun:apollo3:sfe_artemis @@ -76,10 +75,6 @@ jobs: echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - - id: esp32:esp32:esp32 - run: | - python -m pip install pyserial - echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT - id: esp8266:esp8266:generic run: | echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT From 954477b0c0589e6373692ce569ca117191667c30 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 May 2024 18:25:35 +0200 Subject: [PATCH 1145/1848] [LoRaWAN] Remove old error code (CI_BUILD_ALL) --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 2 -- examples/LoRaWAN/LoRaWAN_Reference/config.h | 2 -- examples/LoRaWAN/LoRaWAN_Starter/config.h | 2 -- 3 files changed, 6 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index ba6ca167ee..2cc13971f7 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -169,8 +169,6 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_INVALID_PORT"; case RADIOLIB_ERR_NO_RX_WINDOW: return "RADIOLIB_ERR_NO_RX_WINDOW"; - case RADIOLIB_ERR_INVALID_CHANNEL: - return "RADIOLIB_ERR_INVALID_CHANNEL"; case RADIOLIB_ERR_INVALID_CID: return "RADIOLIB_ERR_INVALID_CID"; case RADIOLIB_ERR_UPLINK_UNAVAILABLE: diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index ace03ce55a..d77b070cbb 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -163,8 +163,6 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_INVALID_PORT"; case RADIOLIB_ERR_NO_RX_WINDOW: return "RADIOLIB_ERR_NO_RX_WINDOW"; - case RADIOLIB_ERR_INVALID_CHANNEL: - return "RADIOLIB_ERR_INVALID_CHANNEL"; case RADIOLIB_ERR_INVALID_CID: return "RADIOLIB_ERR_INVALID_CID"; case RADIOLIB_ERR_UPLINK_UNAVAILABLE: diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index ace03ce55a..d77b070cbb 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -163,8 +163,6 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_INVALID_PORT"; case RADIOLIB_ERR_NO_RX_WINDOW: return "RADIOLIB_ERR_NO_RX_WINDOW"; - case RADIOLIB_ERR_INVALID_CHANNEL: - return "RADIOLIB_ERR_INVALID_CHANNEL"; case RADIOLIB_ERR_INVALID_CID: return "RADIOLIB_ERR_INVALID_CID"; case RADIOLIB_ERR_UPLINK_UNAVAILABLE: From b8d5b984d19655117f9104a4c6708376af3deec4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Jun 2024 08:30:40 +0200 Subject: [PATCH 1146/1848] [CI] Added ESP32 back to build matrix --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 280a0b1f0f..113e817893 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,6 +24,7 @@ on: - arduino:samd:arduino_zero_native - adafruit:samd:adafruit_feather_m0 - adafruit:nrf52:feather52832 + - esp32:esp32:esp32 - esp8266:esp8266:generic - Intel:arc32:arduino_101 - SparkFun:apollo3:sfe_artemis @@ -75,6 +76,10 @@ jobs: echo "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT + - id: esp32:esp32:esp32 + run: | + python -m pip install pyserial + echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT - id: esp8266:esp8266:generic run: | echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT From 5d9917eb06255e2bdddf301e65da8b88d5626d0a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Jun 2024 09:29:55 +0200 Subject: [PATCH 1147/1848] [LoRaWAN] Change FSK switch to modulation variable --- src/protocols/LoRaWAN/LoRaWAN.cpp | 55 +++++++++++++++++++------------ src/protocols/LoRaWAN/LoRaWAN.h | 10 ++++-- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index eb2c9e5527..ad33ceae96 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1227,7 +1227,7 @@ int16_t LoRaWANNode::downlinkCommon() { // if we got here due to a timeout, stop ongoing activities if(this->phyLayer->isRxTimeout()) { this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? - if(!this->FSK) { + if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { this->phyLayer->invertIQ(false); } @@ -1250,7 +1250,7 @@ int16_t LoRaWANNode::downlinkCommon() { // we have a message, clear actions, go to standby and reset the IQ inversion this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? this->phyLayer->clearPacketReceivedAction(); - if(!this->FSK) { + if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { state = this->phyLayer->invertIQ(false); RADIOLIB_ASSERT(state); } @@ -1731,9 +1731,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { // if this channel is an FSK channel, toggle the FSK switch if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - this->FSK = true; - } else { - this->FSK = false; + this->modulation = RADIOLIB_LORAWAN_MODULATION_GFSK; } int8_t pwr = this->txPowerMax - this->txPowerSteps * 2; @@ -1752,7 +1750,7 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, TX = %d dBm, BW = %6.3f kHz, CR = 4/%d", dr.lora.spreadingFactor, pwr, dr.lora.bandwidth, dr.lora.codingRate); - if(this->FSK) { + if(this->modulation == RADIOLIB_LORAWAN_MODULATION_GFSK) { state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); RADIOLIB_ASSERT(state); state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); @@ -1761,34 +1759,49 @@ int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { // downlink messages are sent with inverted IQ if(dir == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { - if(!this->FSK) { + if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { state = this->phyLayer->invertIQ(true); RADIOLIB_ASSERT(state); } } // this only needs to be done once-ish - uint8_t syncWord[3] = { 0 }; + uint8_t syncWord[4] = { 0 }; uint8_t syncWordLen = 0; size_t preLen = 0; - if(this->FSK) { - preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; - syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); - syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); - syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; - syncWordLen = 3; - - } else { - preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; - syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; - syncWordLen = 1; - + switch(this->modulation) { + case(RADIOLIB_LORAWAN_MODULATION_GFSK): { + preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); + syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; + syncWordLen = 3; + } break; + + case(RADIOLIB_LORAWAN_MODULATION_LORA): { + preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; + syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; + syncWordLen = 1; + } break; + + case(RADIOLIB_LORAWAN_MODULATION_LR_FHSS): { + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 24); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 16); + syncWord[2] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 8); + syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; + syncWordLen = 4; + } break; + + default: + return(RADIOLIB_ERR_WRONG_MODEM); } state = this->phyLayer->setSyncWord(syncWord, syncWordLen); RADIOLIB_ASSERT(state); - state = this->phyLayer->setPreambleLength(preLen); + if(this->modulation != RADIOLIB_LORAWAN_MODULATION_LR_FHSS) { + state = this->phyLayer->setPreambleLength(preLen); + } return(state); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index fd75da52a3..692f45e1a3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -15,11 +15,17 @@ #define RADIOLIB_LORAWAN_CLASS_B (0x0B) #define RADIOLIB_LORAWAN_CLASS_C (0x0C) +// modulation type +#define RADIOLIB_LORAWAN_MODULATION_LORA (0) +#define RADIOLIB_LORAWAN_MODULATION_GFSK (1) +#define RADIOLIB_LORAWAN_MODULATION_LR_FHSS (2) + // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) #define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) #define RADIOLIB_LORAWAN_GFSK_SYNC_WORD (0xC194C1) #define RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN (5) +#define RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD (0x2C0F7995) // MAC header field encoding MSB LSB DESCRIPTION #define RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST (0x00 << 5) // 7 5 message type: join request @@ -926,8 +932,8 @@ class LoRaWANNode { uint32_t confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; uint32_t adrFCnt = 0; - // whether the current configured channel is in FSK mode - bool FSK = false; + // modulation of the currently configured channel + uint8_t modulation = RADIOLIB_LORAWAN_MODULATION_LORA; // ADR is enabled by default bool adrEnabled = true; From aebbdd4c930bee9b36e82966b4ba3f947cc8b9cb Mon Sep 17 00:00:00 2001 From: "IoTThinks.com" Date: Tue, 4 Jun 2024 13:12:43 +0700 Subject: [PATCH 1148/1848] [LoRaWAN] To change CR to 4/5 for all frequency plans (#1115) To set AS923-1/2/3/4, IN868, EU433, KR, CN...use default CR 4/5 instead of CR 4/7 --- src/protocols/LoRaWAN/LoRaWANBands.cpp | 66 +++++++++++++------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index eaeb0841ab..dcafbd729d 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -156,13 +156,13 @@ const LoRaWANBand_t CN780 = { .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 786.000, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -202,13 +202,13 @@ const LoRaWANBand_t EU433 = { .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 434.665, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -375,13 +375,13 @@ const LoRaWANBand_t AS923 = { .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 2, .drMax = 2 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -421,12 +421,12 @@ const LoRaWANBand_t KR920 = { .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 921.900, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -467,12 +467,12 @@ const LoRaWANBand_t IN865 = { .rx1DataRateBase = 0, .rx2 = { .enabled = true, .idx = 0, .freq = 866.550, .drMin = 2, .drMax = 2 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_7, + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, From e42cd7e2a5e7d6e7b8f40842921dbf6049ba9b26 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Wed, 5 Jun 2024 21:27:19 +0200 Subject: [PATCH 1149/1848] [LoRaWAN] Fix dwelltime & JR-dr for AU915, add JR dwelltime check --- src/protocols/LoRaWAN/LoRaWAN.cpp | 9 +++++++++ src/protocols/LoRaWAN/LoRaWANBands.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ad33ceae96..4cac3fdba1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -36,6 +36,8 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t this->difsSlots = 2; this->backoffMax = 6; this->enableCSMA = false; + this->dwellTimeEnabledUp = this->dwellTimeUp != 0; + this->dwellTimeEnabledDn = this->dwellTimeDn != 0; memset(this->availableChannels, 0, sizeof(this->availableChannels)); } @@ -507,6 +509,13 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); + if(this->dwellTimeEnabledUp) { + RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + if(toa > this->dwellTimeUp) { + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); + } + } + // copy devNonce currently in use uint16_t devNonceUsed = this->devNonce; diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index dcafbd729d..d81ce7d05a 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -227,7 +227,7 @@ const LoRaWANBand_t AU915 = { .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, - .dwellTimeUp = 0, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -247,7 +247,7 @@ const LoRaWANBand_t AU915 = { .freqStep = 0.200, .drMin = 0, .drMax = 5, - .joinRequestDataRate = 0 + .joinRequestDataRate = 2 }, { .numChannels = 8, From 38abf92aaf6773b370385e18575cbab0d029a84c Mon Sep 17 00:00:00 2001 From: "IoTThinks.com" Date: Fri, 7 Jun 2024 15:04:38 +0700 Subject: [PATCH 1150/1848] [LoRaWAN] Added frequency plans AS923_2, AS923_3 and AS923_4 for Asian countries (#1116) * Added AS923_2, AS923_3 and AS923_4 These plans are used by Asian countries such as Vietnam, Indonesia, Philippines... --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 2 +- examples/LoRaWAN/LoRaWAN_Reference/config.h | 2 +- examples/LoRaWAN/LoRaWAN_Starter/config.h | 2 +- src/protocols/LoRaWAN/LoRaWAN.h | 6 + src/protocols/LoRaWAN/LoRaWANBands.cpp | 141 ++++++++++++++++++++ 5 files changed, 150 insertions(+), 3 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index 2cc13971f7..f4b8a8965b 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -28,7 +28,7 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index d77b070cbb..a721a9329e 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -24,7 +24,7 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index d77b070cbb..a721a9329e 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -24,7 +24,7 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN780, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 692f45e1a3..11bb7c595c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -441,6 +441,9 @@ extern const LoRaWANBand_t EU433; extern const LoRaWANBand_t AU915; extern const LoRaWANBand_t CN500; extern const LoRaWANBand_t AS923; +extern const LoRaWANBand_t AS923_2; +extern const LoRaWANBand_t AS923_3; +extern const LoRaWANBand_t AS923_4; extern const LoRaWANBand_t KR920; extern const LoRaWANBand_t IN865; @@ -456,6 +459,9 @@ enum LoRaWANBandNum_t { BandAU915, BandCN500, BandAS923, + BandAS923_2, + BandAS923_3, + BandAS923_4, BandKR920, BandIN865, BandLast diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index d81ce7d05a..4bb30a33c4 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -11,6 +11,9 @@ const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { &AU915, &CN500, &AS923, + &AS923_2, + &AS923_3, + &AS923_4, &KR920, &IN865, }; @@ -393,6 +396,144 @@ const LoRaWANBand_t AS923 = { } }; +const LoRaWANBand_t AS923_2 = { + .bandNum = BandAS923_2, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 921.400, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 921.600, .drMin = 0, .drMax = 5}, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 921.400, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t AS923_3 = { + .bandNum = BandAS923_3, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 916.600, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 916.800, .drMin = 0, .drMax = 5}, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 916.600, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + +const LoRaWANBand_t AS923_4 = { + .bandNum = BandAS923_4, + .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, + .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .powerMax = 16, + .powerNumSteps = 7, + .dutyCycle = 36000, + .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, + .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txFreqs = { + { .enabled = true, .idx = 0, .freq = 917.300, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 1, .freq = 917.500, .drMin = 0, .drMax = 5}, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txJoinReq = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .numTxSpans = 0, + .txSpans = { + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE + }, + .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, + .rx1DataRateBase = 0, + .rx2 = { .enabled = true, .idx = 0, .freq = 917.300, .drMin = 2, .drMax = 2 }, + .dataRates = { + RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED + } +}; + const LoRaWANBand_t KR920 = { .bandNum = BandKR920, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, From 68d0e393b76d42f5734a926e80e12170502e907f Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Fri, 7 Jun 2024 10:09:59 +0200 Subject: [PATCH 1151/1848] [LoRaWAN] Remove forbidden CN780 --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 2 +- examples/LoRaWAN/LoRaWAN_Reference/config.h | 2 +- examples/LoRaWAN/LoRaWAN_Starter/config.h | 2 +- keywords.txt | 4 +- src/protocols/LoRaWAN/LoRaWAN.h | 2 - src/protocols/LoRaWAN/LoRaWANBands.cpp | 47 --------------------- 6 files changed, 6 insertions(+), 53 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index f4b8a8965b..67008adf14 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -28,7 +28,7 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index a721a9329e..f3a43c8327 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -24,7 +24,7 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index a721a9329e..f3a43c8327 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -24,7 +24,7 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN780, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 diff --git a/keywords.txt b/keywords.txt index 773df7a2b7..dab4fb0515 100644 --- a/keywords.txt +++ b/keywords.txt @@ -83,11 +83,13 @@ Bell202 KEYWORD1 # LoRaWAN bands EU868 KEYWORD1 US915 KEYWORD1 -CN780 KEYWORD1 EU433 KEYWORD1 AU915 KEYWORD1 CN500 KEYWORD1 AS923 KEYWORD1 +AS923_2 KEYWORD1 +AS923_3 KEYWORD1 +AS923_4 KEYWORD1 KR920 KEYWORD1 IN865 KEYWORD1 diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 11bb7c595c..3af9477f40 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -436,7 +436,6 @@ struct LoRaWANBand_t { // supported bands extern const LoRaWANBand_t EU868; extern const LoRaWANBand_t US915; -extern const LoRaWANBand_t CN780; extern const LoRaWANBand_t EU433; extern const LoRaWANBand_t AU915; extern const LoRaWANBand_t CN500; @@ -454,7 +453,6 @@ extern const LoRaWANBand_t IN865; enum LoRaWANBandNum_t { BandEU868, BandUS915, - BandCN780, BandEU433, BandAU915, BandCN500, diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 4bb30a33c4..f67b85737b 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -6,7 +6,6 @@ const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { &EU868, &US915, - &CN780, &EU433, &AU915, &CN500, @@ -131,52 +130,6 @@ const LoRaWANBand_t US915 = { } }; -const LoRaWANBand_t CN780 = { - .bandNum = BandCN780, - .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 250, 230, 0, 0, 0, 0, 0, 0, 0 }, - .powerMax = 12, - .powerNumSteps = 5, - .dutyCycle = 3600, - .dwellTimeUp = 0, - .dwellTimeDn = 0, - .txFreqs = { - { .enabled = true, .idx = 0, .freq = 779.500, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 779.700, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 2, .freq = 779.900, .drMin = 0, .drMax = 5}, - }, - .txJoinReq = { - { .enabled = true, .idx = 3, .freq = 780.500, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 4, .freq = 780.700, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 5, .freq = 780.900, .drMin = 0, .drMax = 5} - }, - .numTxSpans = 0, - .txSpans = { - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE - }, - .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 786.000, .drMin = 0, .drMax = 0 }, - .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED - } -}; - const LoRaWANBand_t EU433 = { .bandNum = BandEU433, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, From 81b9e6cd53a6172fdd0be7136d44ae6de2e31f9b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Jun 2024 10:22:21 +0200 Subject: [PATCH 1152/1848] [LR11x0] Fix LR-FHSS time on air calculation (#1117) --- src/modules/LR11x0/LR11x0.cpp | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index f7dea326c0..7dccb214b1 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1329,7 +1329,36 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { return(((uint32_t)len * 8 * 1000000UL) / this->bitRate); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { - return(((uint32_t)len * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); + // calculate the number of bits based on coding rate + uint16_t N_bits; + switch(this->lrFhssCr) { + case RADIOLIB_LR11X0_LR_FHSS_CR_5_6: + N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? + break; + case RADIOLIB_LR11X0_LR_FHSS_CR_2_3: + N_bits = (len * 3) / 2; + break; + case RADIOLIB_LR11X0_LR_FHSS_CR_1_2: + N_bits = len * 2; + break; + case RADIOLIB_LR11X0_LR_FHSS_CR_1_3: + N_bits = len * 3; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + // calculate number of bits when accounting for unaligned last block + uint16_t N_payBits = (N_bits / RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS) * RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS; + uint16_t N_lastBlockBits = N_bits % RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS; + if(N_lastBlockBits) { + N_payBits += N_lastBlockBits + 2; + } + + // add header bits + uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + N_payBits; + return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); + } return(0); From e855636384bfa21f591d9e1f636941ac563d5875 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Jun 2024 10:27:39 +0200 Subject: [PATCH 1153/1848] [LR11x0] Added missing macros --- src/modules/LR11x0/LR11x0.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 4f60f9e5f6..04d5d2f8e6 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -482,6 +482,10 @@ #define RADIOLIB_LR11X0_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz #define RADIOLIB_LR11X0_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz #define RADIOLIB_LR11X0_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz +#define RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header +#define RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment +#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble +#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS (RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS + RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS) // RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS #define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled From a8b6c38488052263c53b01948f50ce22ed818af3 Mon Sep 17 00:00:00 2001 From: Jack Hance Date: Wed, 12 Jun 2024 10:46:10 -0500 Subject: [PATCH 1154/1848] [CC1101] Fix getRSSI data source (#1121) * [CC1101] Fix getRSSI data source * [CC1101] Fix packet mode not resetting directModeEnabled bool --- src/modules/CC1101/CC1101.cpp | 5 ++++- src/modules/CC1101/CC1101.h | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 72830ce0dd..cfce1f2ace 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1023,7 +1023,7 @@ int16_t CC1101::directMode(bool sync) { SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); int16_t state = 0; - this->directModeEnabled = sync; + this->directModeEnabled = true; if(sync) { // set GDO0 and GDO2 mapping state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0); @@ -1083,6 +1083,9 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) { state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTLEN, len); RADIOLIB_ASSERT(state); + // no longer in a direct mode + this->directModeEnabled = false; + // update the cached values this->packetLength = len; this->packetLengthConfig = mode; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index e61c5fc437..af315a370c 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -845,7 +845,7 @@ class CC1101: public PhysicalLayer { /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. - In asynchronous direct mode, returns the current RSSI level. + In direct or asynchronous direct mode, returns the current RSSI level. \returns RSSI in dBm. */ float getRSSI() override; @@ -1003,7 +1003,7 @@ class CC1101: public PhysicalLayer { bool promiscuous = false; bool crcOn = true; - bool directModeEnabled = true; + bool directModeEnabled = false; int8_t power = RADIOLIB_CC1101_DEFAULT_POWER; From 940eb07674eb3eda43a0bbe1538215c018fc7a8a Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 13 Jun 2024 17:09:23 +0200 Subject: [PATCH 1155/1848] [HAL] Fix tone on ESP32 IDF > 5.0.0 (#1123) --- src/ArduinoHal.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index fce0fb1b08..0f3dd3bb4e 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -126,6 +126,8 @@ void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, RadioLibTime_ if(prev == -1) { #if !defined(ESP_IDF_VERSION) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)) ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); + #else + ledcAttach(pin, frequency, 14); // 14-bit resolution should be enough #endif } if(prev != frequency) { From bc36c1e98afdc5f05402d129a2dc54184b7db453 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 14 Jun 2024 19:49:19 +0100 Subject: [PATCH 1156/1848] Use lgpio as the RPi HAL --- .github/workflows/main.yml | 7 +- examples/NonArduino/Raspberry/CMakeLists.txt | 2 +- examples/NonArduino/Raspberry/PiHal.h | 164 +++++++++++++------ examples/NonArduino/Raspberry/main.cpp | 8 +- 4 files changed, 126 insertions(+), 55 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 113e817893..4db4aaac35 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -259,7 +259,12 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y pigpio cmake + sudo apt-get install -y cmake wget swig python-dev python3-dev python-setuptools python3-setuptools + wget http://abyz.me.uk/lg/lg.zip + unzip lg.zip + cd lg + make + sudo make install - name: Install the library run: | diff --git a/examples/NonArduino/Raspberry/CMakeLists.txt b/examples/NonArduino/Raspberry/CMakeLists.txt index c9d47872f1..2e6d93497f 100644 --- a/examples/NonArduino/Raspberry/CMakeLists.txt +++ b/examples/NonArduino/Raspberry/CMakeLists.txt @@ -15,7 +15,7 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR add_executable(${PROJECT_NAME} main.cpp) # link both libraries -target_link_libraries(${PROJECT_NAME} RadioLib pigpio) +target_link_libraries(${PROJECT_NAME} RadioLib lgpio) # you can also specify RadioLib compile-time flags here #target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 5a1b288a6d..03dded742e 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -1,55 +1,53 @@ -#ifndef PI_HAL_H -#define PI_HAL_H +#ifndef PI_HAL_LGPIO_H +#define PI_HAL_LGPIO_H // include RadioLib #include // include the library for Raspberry GPIO pins -#include "pigpio.h" +#include -// these should really be swapped, but for some reason, -// it seems like the change directions are inverted in gpioSetAlert functions -#define PI_RISING (FALLING_EDGE) -#define PI_FALLING (RISING_EDGE) +#define PI_RISING (LG_RISING_EDGE) +#define PI_FALLING (LG_FALLING_EDGE) +#define PI_INPUT (0) +#define PI_OUTPUT (1) +#define PI_MAX_USER_GPIO (31) // forward declaration of alert handler that will be used to emulate interrupts -static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata); +static void lgpioAlertHandler(int num_alerts, lgGpioAlert_p alerts, void *userdata); // create a new Raspberry Pi hardware abstraction layer -// using the pigpio library +// using the lgpio library // the HAL must inherit from the base RadioLibHal class // and implement all of its virtual methods class PiHal : public RadioLibHal { public: // default constructor - initializes the base HAL and any needed private members - PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) - : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING), + PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0) + : RadioLibHal(PI_INPUT, PI_OUTPUT, LG_LOW, LG_HIGH, PI_RISING, PI_FALLING), + _gpioDevice(gpioDevice), + _spiDevice(spiDevice), _spiChannel(spiChannel), _spiSpeed(spiSpeed) { } void init() override { - // first initialise pigpio library - gpioInitialise(); + // first initialise lgpio library + if((_gpioHandle = lgGpiochipOpen(_gpioDevice)) < 0) { + fprintf(stderr, "Could not open GPIO chip: %s\n", lguErrorText(_gpioHandle)); + return; + } // now the SPI spiBegin(); - - // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio - gpioSetMode(18, PI_OUTPUT); - gpioWrite(18, PI_HIGH); } void term() override { // stop the SPI spiEnd(); - // pull the enable pin low - gpioSetMode(18, PI_OUTPUT); - gpioWrite(18, PI_LOW); - - // finally, stop the pigpio library - gpioTerminate(); + // finally, stop the lgpio library + lgGpiochipClose(_gpioHandle); } // GPIO-related methods (pinMode, digitalWrite etc.) should check @@ -59,7 +57,24 @@ class PiHal : public RadioLibHal { return; } - gpioSetMode(pin, mode); + int result; + int flags = 0; + switch(mode) { + case PI_INPUT: + result = lgGpioClaimInput(_gpioHandle, 0, pin); + break; + case PI_OUTPUT: + result = lgGpioClaimOutput(_gpioHandle, flags, pin, LG_HIGH); + break; + default: + fprintf(stderr, "Unknown pinMode mode %" PRIu32 "\n", mode); + return; + } + + if(result < 0) { + fprintf(stderr, "Could not claim pin %" PRIu32 " for mode %" PRIu32 ": %s\n", + pin, mode, lguErrorText(result)); + } } void digitalWrite(uint32_t pin, uint32_t value) override { @@ -67,7 +82,10 @@ class PiHal : public RadioLibHal { return; } - gpioWrite(pin, value); + int result = lgGpioWrite(_gpioHandle, pin, value); + if(result < 0) { + fprintf(stderr, "Error writing value to pin %" PRIu32 ": %s\n", pin, lguErrorText(result)); + } } uint32_t digitalRead(uint32_t pin) override { @@ -75,7 +93,11 @@ class PiHal : public RadioLibHal { return(0); } - return(gpioRead(pin)); + int result = lgGpioRead(_gpioHandle, pin); + if(result < 0) { + fprintf(stderr, "Error writing reading from pin %" PRIu32 ": %s\n", pin, lguErrorText(result)); + } + return result; } void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { @@ -83,13 +105,19 @@ class PiHal : public RadioLibHal { return; } + // set lgpio alert callback + int result = lgGpioClaimAlert(_gpioHandle, 0, mode, interruptNum, -1); + if(result < 0) { + fprintf(stderr, "Could not claim pin %" PRIu32 " for alert: %s\n", interruptNum, lguErrorText(result)); + return; + } + // enable emulated interrupt interruptEnabled[interruptNum] = true; interruptModes[interruptNum] = mode; interruptCallbacks[interruptNum] = interruptCb; - // set pigpio alert callback - gpioSetAlertFuncEx(interruptNum, pigpioAlertHandler, (void*)this); + lgGpioSetAlertsFunc(_gpioHandle, interruptNum, lgpioAlertHandler, (void *)this); } void detachInterrupt(uint32_t interruptNum) override { @@ -102,27 +130,44 @@ class PiHal : public RadioLibHal { interruptModes[interruptNum] = 0; interruptCallbacks[interruptNum] = NULL; - // disable pigpio alert callback - gpioSetAlertFuncEx(interruptNum, NULL, NULL); + // disable lgpio alert callback + lgGpioFree(_gpioHandle, interruptNum); + lgGpioSetAlertsFunc(_gpioHandle, interruptNum, NULL, NULL); } - void delay(RadioLibTime_t ms) override { - gpioDelay(ms * 1000); + void delay(unsigned long ms) override { + if(ms == 0) { + sched_yield(); + return; + } + + lguSleep(ms / 1000.0); } - void delayMicroseconds(RadioLibTime_t us) override { - gpioDelay(us); + void delayMicroseconds(unsigned long us) override { + if(us == 0) { + sched_yield(); + return; + } + + lguSleep(us / 1000000.0); } - RadioLibTime_t millis() override { - return(gpioTick() / 1000); + void yield() override { + sched_yield(); } - RadioLibTime_t micros() override { - return(gpioTick()); + unsigned long millis() override { + uint32_t time = lguTimestamp() / 1000000UL; + return time; } - long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override { + unsigned long micros() override { + uint32_t time = lguTimestamp() / 1000UL; + return time; + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { if(pin == RADIOLIB_NC) { return(0); } @@ -142,25 +187,38 @@ class PiHal : public RadioLibHal { void spiBegin() { if(_spiHandle < 0) { - _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + if((_spiHandle = lgSpiOpen(_spiDevice, _spiChannel, _spiSpeed, 0)) < 0) { + fprintf(stderr, "Could not open SPI handle on 0: %s\n", lguErrorText(_spiHandle)); + } } } void spiBeginTransaction() {} void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { - spiXfer(_spiHandle, (char*)out, (char*)in, len); + int result = lgSpiXfer(_spiHandle, (char *)out, (char*)in, len); + if(result < 0) { + fprintf(stderr, "Could not perform SPI transfer: %s\n", lguErrorText(result)); + } } void spiEndTransaction() {} void spiEnd() { if(_spiHandle >= 0) { - spiClose(_spiHandle); + lgSpiClose(_spiHandle); _spiHandle = -1; } } + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) { + lgTxPwm(_gpioHandle, pin, frequency, 50, 0, duration); + } + + void noTone(uint32_t pin) { + lgTxPwm(_gpioHandle, pin, 0, 0, 0, 0); + } + // interrupt emulation bool interruptEnabled[PI_MAX_USER_GPIO + 1]; uint32_t interruptModes[PI_MAX_USER_GPIO + 1]; @@ -170,24 +228,28 @@ class PiHal : public RadioLibHal { private: // the HAL can contain any additional private members const unsigned int _spiSpeed; + const uint8_t _gpioDevice; + const uint8_t _spiDevice; const uint8_t _spiChannel; + int _gpioHandle = -1; int _spiHandle = -1; }; // this handler emulates interrupts -static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata) { - if((event > PI_MAX_USER_GPIO) || (!userdata)) { +static void lgpioAlertHandler(int num_alerts, lgGpioAlert_p alerts, void *userdata) { + if(!userdata) return; - } - - // PiHal isntance is passed via the user data + + // PiHal instance is passed via the user data PiHal* hal = (PiHal*)userdata; // check the interrupt is enabled, the level matches and a callback exists - if((hal->interruptEnabled[event]) && - (hal->interruptModes[event] == level) && - (hal->interruptCallbacks[event])) { - hal->interruptCallbacks[event](); + for(lgGpioAlert_t *alert = alerts; alert < (alerts + num_alerts); alert++) { + if((hal->interruptEnabled[alert->report.gpio]) && + (hal->interruptModes[alert->report.gpio] == alert->report.level) && + (hal->interruptCallbacks[alert->report.gpio])) { + hal->interruptCallbacks[alert->report.gpio](); + } } } diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index 54ae3850a2..1dfa60bfc2 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -3,7 +3,8 @@ This example shows how to use RadioLib without Arduino. In this case, a Raspberry Pi with WaveShare SX1302 LoRaWAN Hat - using the pigpio library. + using the lgpio library + https://abyz.me.uk/lg/lgpio.html Can be used as a starting point to port RadioLib to any platform! See this API reference page for details on the RadioLib hardware abstraction @@ -44,10 +45,13 @@ int main(int argc, char** argv) { printf("success!\n"); // loop forever + int count = 0; for(;;) { // send a packet printf("[SX1261] Transmitting packet ... "); - state = radio.transmit("Hello World!"); + char str[64]; + sprintf(str, "Hello World! #%d", count++); + state = radio.transmit(str); if(state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted printf("success!\n"); From d31d9968affb812555aeb14b1d7da26f55cbed6d Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 19 Jun 2024 21:08:11 +0200 Subject: [PATCH 1157/1848] [LoRaWAN] Remove pin maps from example config file (#1106) --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 120 ++++---------------- examples/LoRaWAN/LoRaWAN_Reference/config.h | 120 ++++---------------- examples/LoRaWAN/LoRaWAN_Starter/config.h | 120 ++++---------------- examples/LoRaWAN/LoRaWAN_Starter/notes.md | 32 +----- 4 files changed, 67 insertions(+), 325 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index 67008adf14..ac7421803a 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -1,8 +1,21 @@ -#ifndef _CONFIG_H -#define _CONFIG_H +#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H +#define _RADIOLIB_EX_LORAWAN_CONFIG_H #include +// first you have to set your radio model and pin configuration +// this is provided just as a default example +SX1278 radio = new Module(10, 2, 9, 3); + +// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) +// and are using one of the supported boards, you can do the following: +/* +#define RADIO_BOARD_AUTO +#include + +Radio radio = new RadioModule(); +*/ + // how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds @@ -32,98 +45,9 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds const LoRaWANBand_t Region = EU868; const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 - // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... -// Auto select MCU <-> radio connections -// If you get an error message when compiling, it may be that the -// pinmap could not be determined - see the notes for more info - -// Adafruit -#if defined(ARDUINO_SAMD_FEATHER_M0) - #pragma message ("Adafruit Feather M0 with RFM95") - #pragma message ("Link required on board") - SX1276 radio = new Module(8, 3, 4, 6); - - -// LilyGo -#elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("Using TTGO LoRa32 v1 - no Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma message ("Using TTGO LoRa32 v2 + Display") - SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); - -#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) - #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO T-Beam") - SX1276 radio = new Module(18, 26, 23, 33); - - -// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma message ("Using Heltec WiFi LoRa32") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_heltec_wifi_lora_32_V2) - #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1278 radio = new Module(14, 4, 12, 16); - -// Pending verfication of which radio is shipped -// #elif defined(ARDUINO_heltec_wifi_lora_32_V2) -// #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") -// SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined(ARDUINO_heltec_wifi_lora_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") - SX1262 radio = new Module(8, 14, 12, 13); - - -// Following not verified -#elif defined (ARDUINO_heltec_wireless_stick) - #pragma message ("Using Heltec Wireless Stick") - SX1278 radio = new Module(14, 4, 12, 16); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK) - #pragma message ("Using Heltec Wireless Stick") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3) - #pragma message ("Using Heltec Wireless Stick v3") - SX1262 radio = new Module(8, 14, 12, 13); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE) - #pragma message ("Using Heltec Wireless Stick Lite") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3) - #pragma message ("Using Heltec Wireless Stick Lite v3") - SX1262 radio = new Module(34, 14, 12, 13); - - -// If we don't recognise the board -#else - #pragma message ("Unknown board - no automagic pinmap available") - - // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); - // SX1262 radio = new Module(8, 14, 12, 13); - - // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); - // SX1278 radio = new Module(10, 2, 9, 3); - - // For Pi Pico + Waveshare HAT - work in progress - // SX1262 radio = new Module(3, 20, 15, 2, SPI1, RADIOLIB_DEFAULT_SPI_SETTINGS); - -#endif - // copy over the keys in to the something that will not compile if incorrectly formatted uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR; uint8_t fNwkSIntKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY }; @@ -134,8 +58,8 @@ uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); - -// result code to text ... +// result code to text - these are error codes that can be raised when using LoRaWAN +// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list String stateDecode(const int16_t result) { switch (result) { case RADIOLIB_ERR_NONE: @@ -160,7 +84,6 @@ String stateDecode(const int16_t result) { return "ERR_INVALID_OUTPUT_POWER"; case RADIOLIB_ERR_NETWORK_NOT_JOINED: return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; - case RADIOLIB_ERR_DOWNLINK_MALFORMED: return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; case RADIOLIB_ERR_INVALID_REVISION: @@ -198,23 +121,22 @@ String stateDecode(const int16_t result) { case RADIOLIB_LORAWAN_SESSION_DISCARDED: return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; } - return "See TypeDef.h"; + return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; } // helper function to display any issues -void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { - if (isFail) { +void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) { + if(failed) { Serial.print(message); Serial.print(" - "); Serial.print(stateDecode(state)); Serial.print(" ("); Serial.print(state); Serial.println(")"); - while (Freeze); + while(halt) { delay(1); } } } - // helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index f3a43c8327..65be0af97f 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -1,8 +1,21 @@ -#ifndef _CONFIG_H -#define _CONFIG_H +#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H +#define _RADIOLIB_EX_LORAWAN_CONFIG_H #include +// first you have to set your radio model and pin configuration +// this is provided just as a default example +SX1278 radio = new Module(10, 2, 9, 3); + +// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) +// and are using one of the supported boards, you can do the following: +/* +#define RADIO_BOARD_AUTO +#include + +Radio radio = new RadioModule(); +*/ + // how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds @@ -31,94 +44,6 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... -// Auto select MCU <-> radio connections -// If you get an error message when compiling, it may be that the -// pinmap could not be determined - see the notes for more info - -// Adafruit -#if defined(ARDUINO_SAMD_FEATHER_M0) - #pragma message ("Adafruit Feather M0 with RFM95") - #pragma message ("Link required on board") - SX1276 radio = new Module(8, 3, 4, 6); - - -// LilyGo -#elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("Using TTGO LoRa32 v1 - no Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma message ("Using TTGO LoRa32 v2 + Display") - SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); - -#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) - #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO T-Beam") - SX1276 radio = new Module(18, 26, 23, 33); - - -// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma message ("Using Heltec WiFi LoRa32") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_heltec_wifi_lora_32_V2) - #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1278 radio = new Module(14, 4, 12, 16); - -// Pending verfication of which radio is shipped -// #elif defined(ARDUINO_heltec_wifi_lora_32_V2) -// #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") -// SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined(ARDUINO_heltec_wifi_lora_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") - SX1262 radio = new Module(8, 14, 12, 13); - - -// Following not verified -#elif defined (ARDUINO_heltec_wireless_stick) - #pragma message ("Using Heltec Wireless Stick") - SX1278 radio = new Module(14, 4, 12, 16); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK) - #pragma message ("Using Heltec Wireless Stick") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3) - #pragma message ("Using Heltec Wireless Stick v3") - SX1262 radio = new Module(8, 14, 12, 13); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE) - #pragma message ("Using Heltec Wireless Stick Lite") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3) - #pragma message ("Using Heltec Wireless Stick Lite v3") - SX1262 radio = new Module(34, 14, 12, 13); - - -// If we don't recognise the board -#else - #pragma message ("Unknown board - no automagic pinmap available") - - // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); - // SX1262 radio = new Module(8, 14, 12, 13); - - // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); - // SX1278 radio = new Module(10, 2, 9, 3); - - // For Pi Pico + Waveshare HAT - work in progress - // SX1262 radio = new Module(3, 20, 15, 2, SPI1, RADIOLIB_DEFAULT_SPI_SETTINGS); - -#endif - // copy over the EUI's & keys in to the something that will not compile if incorrectly formatted uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; @@ -128,8 +53,8 @@ uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); - -// result code to text ... +// result code to text - these are error codes that can be raised when using LoRaWAN +// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list String stateDecode(const int16_t result) { switch (result) { case RADIOLIB_ERR_NONE: @@ -154,7 +79,6 @@ String stateDecode(const int16_t result) { return "ERR_INVALID_OUTPUT_POWER"; case RADIOLIB_ERR_NETWORK_NOT_JOINED: return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; - case RADIOLIB_ERR_DOWNLINK_MALFORMED: return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; case RADIOLIB_ERR_INVALID_REVISION: @@ -192,23 +116,22 @@ String stateDecode(const int16_t result) { case RADIOLIB_LORAWAN_SESSION_DISCARDED: return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; } - return "See TypeDef.h"; + return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; } // helper function to display any issues -void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { - if (isFail) { +void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) { + if(failed) { Serial.print(message); Serial.print(" - "); Serial.print(stateDecode(state)); Serial.print(" ("); Serial.print(state); Serial.println(")"); - while (Freeze); + while(halt) { delay(1); } } } - // helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { @@ -219,5 +142,4 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } - #endif diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index f3a43c8327..65be0af97f 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -1,8 +1,21 @@ -#ifndef _CONFIG_H -#define _CONFIG_H +#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H +#define _RADIOLIB_EX_LORAWAN_CONFIG_H #include +// first you have to set your radio model and pin configuration +// this is provided just as a default example +SX1278 radio = new Module(10, 2, 9, 3); + +// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) +// and are using one of the supported boards, you can do the following: +/* +#define RADIO_BOARD_AUTO +#include + +Radio radio = new RadioModule(); +*/ + // how often to send an uplink - consider legal & FUP constraints - see notes const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds @@ -31,94 +44,6 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... -// Auto select MCU <-> radio connections -// If you get an error message when compiling, it may be that the -// pinmap could not be determined - see the notes for more info - -// Adafruit -#if defined(ARDUINO_SAMD_FEATHER_M0) - #pragma message ("Adafruit Feather M0 with RFM95") - #pragma message ("Link required on board") - SX1276 radio = new Module(8, 3, 4, 6); - - -// LilyGo -#elif defined(ARDUINO_TTGO_LORA32_V1) - #pragma message ("Using TTGO LoRa32 v1 - no Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TTGO_LORA32_V2) - #pragma message ("Using TTGO LoRa32 v2 + Display") - SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC); - -#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1 - #pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1262) - #pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map") - -#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276) - #pragma message ("Using TTGO T-Beam") - SX1276 radio = new Module(18, 26, 23, 33); - - -// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h -#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) - #pragma message ("Using Heltec WiFi LoRa32") - SX1276 radio = new Module(18, 26, 14, 33); - -#elif defined(ARDUINO_heltec_wifi_lora_32_V2) - #pragma message ("Using Heltec WiFi LoRa32 v2") - SX1278 radio = new Module(14, 4, 12, 16); - -// Pending verfication of which radio is shipped -// #elif defined(ARDUINO_heltec_wifi_lora_32_V2) -// #pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map") -// SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined(ARDUINO_heltec_wifi_lora_32_V3) - #pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C") - SX1262 radio = new Module(8, 14, 12, 13); - - -// Following not verified -#elif defined (ARDUINO_heltec_wireless_stick) - #pragma message ("Using Heltec Wireless Stick") - SX1278 radio = new Module(14, 4, 12, 16); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK) - #pragma message ("Using Heltec Wireless Stick") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3) - #pragma message ("Using Heltec Wireless Stick v3") - SX1262 radio = new Module(8, 14, 12, 13); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE) - #pragma message ("Using Heltec Wireless Stick Lite") - SX1276 radio = new Module(18, 26, 14, 35); - -#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3) - #pragma message ("Using Heltec Wireless Stick Lite v3") - SX1262 radio = new Module(34, 14, 12, 13); - - -// If we don't recognise the board -#else - #pragma message ("Unknown board - no automagic pinmap available") - - // SX1262 pin order: Module(NSS/CS, DIO1, RESET, BUSY); - // SX1262 radio = new Module(8, 14, 12, 13); - - // SX1278 pin order: Module(NSS/CS, DIO0, RESET, DIO1); - // SX1278 radio = new Module(10, 2, 9, 3); - - // For Pi Pico + Waveshare HAT - work in progress - // SX1262 radio = new Module(3, 20, 15, 2, SPI1, RADIOLIB_DEFAULT_SPI_SETTINGS); - -#endif - // copy over the EUI's & keys in to the something that will not compile if incorrectly formatted uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; @@ -128,8 +53,8 @@ uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // create the LoRaWAN node LoRaWANNode node(&radio, &Region, subBand); - -// result code to text ... +// result code to text - these are error codes that can be raised when using LoRaWAN +// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list String stateDecode(const int16_t result) { switch (result) { case RADIOLIB_ERR_NONE: @@ -154,7 +79,6 @@ String stateDecode(const int16_t result) { return "ERR_INVALID_OUTPUT_POWER"; case RADIOLIB_ERR_NETWORK_NOT_JOINED: return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; - case RADIOLIB_ERR_DOWNLINK_MALFORMED: return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; case RADIOLIB_ERR_INVALID_REVISION: @@ -192,23 +116,22 @@ String stateDecode(const int16_t result) { case RADIOLIB_LORAWAN_SESSION_DISCARDED: return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; } - return "See TypeDef.h"; + return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; } // helper function to display any issues -void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { - if (isFail) { +void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) { + if(failed) { Serial.print(message); Serial.print(" - "); Serial.print(stateDecode(state)); Serial.print(" ("); Serial.print(state); Serial.println(")"); - while (Freeze); + while(halt) { delay(1); } } } - // helper function to display a byte array void arrayDump(uint8_t *buffer, uint16_t len) { for(uint16_t c = 0; c < len; c++) { @@ -219,5 +142,4 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } - #endif diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md index 2821bef3e2..e68949e7a5 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/notes.md +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -141,31 +141,12 @@ If you are using US915 or AU915 then you should change the subBand const to 2. ### The pinmap -This is the connection between the MCU (ESP32/ATmega/SAMD) and the LoRa radio (SX1276/SX1262). +This is the connection between your microcontroller (ESP32, ATmega, SAMD etc.) and the radio (SX1276, SX1262, LR1110 etc.). +You have to select the correct module and set the correct pins. -Prebuilt modules are easy - we can detect the board and setup the pinmap for you. These boards are: - -* TTGO_LoRa32 -* TTGO_LoRa32_V1 -* TTGO_LORA32_V2 -* TTGO_LORA32_v21NEW -* HELTEC_WIFI_LORA_32 -* HELTEC_WIFI_LORA_32_V2 -* HELTEC_WIFI_LORA_32_V3 -* HELTEC_WIRELESS_STICK -* HELTEC_WIRELESS_STICK_V3 -* HELTEC_WIRELESS_STICK_LITE -* HELTEC_WIRELESS_STICK_LITE_V3 - -If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu. - -* TBEAM_USE_RADIO_SX1262 -* TBEAM_USE_RADIO_SX1276 - -Auto-setup for the Adafruit Feather M0 with RFM95 is included but you must solder a wire or use a jumper to link from pin 6 to io1: https://learn.adafruit.com/the-things-network-for-feather/arduino-wiring - -If you have a module that's not on this list, please go to the "Pinmap How-To" below. +Pin maps for commonly used radio modules are kept in a separate library, called RadioBoards: https://github.com/radiolib-org/RadioBoards +It can automatically detect your microcontroller platform and radio, and configure things for you. If you have a board that is not supported by RadioBoards, feel free to suggest it in the RadioBoards issues, or better yet - open a pull request there! ## Observations on the main sketch @@ -197,8 +178,3 @@ Coming soon ### Device testing The LoRaWAN code base works to a specification and once you are happy your device is able to join & send a few dozen uplinks, continuing to sit around waiting for an uplink to test your sensor code & payload format is a waste of your time. The solution is to write everything else in a different sketch, output the array to the serial console and then you can copy & paste the hex array in to the TTN console Payload Formatters section to test the decoding. - - -## Pinmap How-To - -Coming soon From ff7ac57aeba25fc5bc65218824acb1ae229921f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 19 Jun 2024 21:19:23 +0200 Subject: [PATCH 1158/1848] [CI] Remove lg archive after install --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4db4aaac35..e2635a8bfb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -265,6 +265,8 @@ jobs: cd lg make sudo make install + cd .. + sudo rm -rf lg - name: Install the library run: | From 87fac1797e8e8ef2a8c6cffb722e4212c3050a19 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jun 2024 17:04:46 +0200 Subject: [PATCH 1159/1848] [LR11x0] Do not read out GNSS and WiFi versions on LR1121 (#1128) --- src/modules/LR11x0/LR11x0.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 7dccb214b1..71737176b0 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1626,6 +1626,16 @@ int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) { int16_t state = this->getVersion(&info->hardware, &info->device, &info->fwMajor, &info->fwMinor); RADIOLIB_ASSERT(state); + + // LR1121 does not have GNSS and WiFi scanning + if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) { + info->fwMajorWiFi = 0; + info->fwMinorWiFi = 0; + info->fwGNSS = 0; + info->almanacGNSS = 0; + return(RADIOLIB_ERR_NONE); + } + state = this->wifiReadVersion(&info->fwMajorWiFi, &info->fwMinorWiFi); RADIOLIB_ASSERT(state); return(this->gnssReadVersion(&info->fwGNSS, &info->almanacGNSS)); @@ -1787,8 +1797,10 @@ bool LR11x0::findChip(uint8_t ver) { if((state == RADIOLIB_ERR_NONE) && (info.device == ver)) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device); RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor); - RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi); - RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS); + if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) { + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi); + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS); + } flagFound = true; } else { RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, info.device); From e406c550b81567b63513d4ae88fe631c73ab7d08 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 21 Jun 2024 17:53:11 +0200 Subject: [PATCH 1160/1848] [LR11x0] Fix output power configuration at S-band (#1128) --- src/modules/LR11x0/LR1110.cpp | 59 +++++++++- src/modules/LR11x0/LR1110.h | 35 ++++++ src/modules/LR11x0/LR1120.cpp | 82 +++++++++++++- src/modules/LR11x0/LR1120.h | 46 ++++++++ src/modules/LR11x0/LR11x0.cpp | 195 +++++++++++++++++++++------------- src/modules/LR11x0/LR11x0.h | 58 +++------- 6 files changed, 354 insertions(+), 121 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 77e1a02f78..62bf116f13 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -7,31 +7,40 @@ LR1110::LR1110(Module* mod) : LR11x0(mod) { int16_t LR1110::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } @@ -52,4 +61,48 @@ int16_t LR1110::setFrequency(float freq, bool calibrate, float band) { return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); } +int16_t LR1110::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { + // check if power value is configurable + int16_t state = this->checkOutputPower(power, NULL, forceHighPower); + RADIOLIB_ASSERT(state); + + // determine whether to use HP or LP PA and check range accordingly + bool useHp = forceHighPower || (power > 14); + + // TODO how and when to configure OCP? + + // update PA config - always use VBAT for high-power PA + state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + return(state); +} + +int16_t LR1110::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t LR1110::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { + if(forceHighPower || (power > 14)) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + return(RADIOLIB_ERR_NONE); +} + #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index 60040ed0cb..fcc65f2e63 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -86,6 +86,41 @@ class LR1110: public LR11x0 { \returns \ref status_codes */ int16_t setFrequency(float freq, bool calibrate, float band = 4); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool forceHighPower); + + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, PA will be determined automatically. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); #if !RADIOLIB_GODMODE private: diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index a110703631..a69dc35931 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -7,31 +7,40 @@ LR1120::LR1120(Module* mod) : LR11x0(mod) { int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1120::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage); + int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); return(state); } @@ -47,13 +56,76 @@ int16_t LR1120::setFrequency(float freq, bool calibrate, float band) { } // calibrate image rejection + int16_t state; if(calibrate) { - int16_t state = LR11x0::calibImage(freq - band, freq + band); + state = LR11x0::calibImage(freq - band, freq + band); RADIOLIB_ASSERT(state); } // set frequency - return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); + state = LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)); + RADIOLIB_ASSERT(state); + this->highFreq = (freq > 1000.0); + return(RADIOLIB_ERR_NONE); +} + +int16_t LR1120::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower) { + // check if power value is configurable + int16_t state = this->checkOutputPower(power, NULL, forceHighPower); + RADIOLIB_ASSERT(state); + + // determine whether to use HP or LP PA and check range accordingly + uint8_t paSel = 0; + uint8_t paSupply = 0; + if(this->highFreq) { + paSel = 2; + } else if(forceHighPower || (power > 14)) { + paSel = 1; + paSupply = 1; + } + + // TODO how and when to configure OCP? + + // update PA config - always use VBAT for high-power PA + state = setPaConfig(paSel, paSupply, 0x04, 0x07); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + return(state); +} + +int16_t LR1120::checkOutputPower(int8_t power, int8_t* clipped) { + return(checkOutputPower(power, clipped, false)); +} + +int16_t LR1120::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { + if(this->highFreq) { + if(clipped) { + *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, power)); + } + RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + return(RADIOLIB_ERR_NONE); + } + + if(forceHighPower || (power > 14)) { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + } + RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + return(RADIOLIB_ERR_NONE); } #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index 62045b028d..c4fbbde5d0 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -71,6 +71,8 @@ class LR1120: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, + setOutputPower() must be called in order to set the correct power amplifier! \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ @@ -79,6 +81,8 @@ class LR1120: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, + setOutputPower() must be called in order to set the correct power amplifier! \param freq Carrier frequency to be set in MHz. \param calibrate Run image calibration. \param band Half bandwidth for image calibration. For example, @@ -88,9 +92,51 @@ class LR1120: public LR11x0 { */ int16_t setFrequency(float freq, bool calibrate, float band = 4); + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). + \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA), -17 to 14 dBm (low-power PA) + or -18 to 13 dBm (high-frequency PA). + \param power Output power to be set in dBm. + \param forceHighPower Force using the high-power PA in sub-GHz bands, or high-frequency PA in 2.4 GHz band. + If set to false, PA will be determined automatically based on configured output power and frequency, + preferring the low-power PA but always using high-frequency PA in 2.4 GHz band. + Ignored when operating in 2.4 GHz band. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool forceHighPower); + + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, PA will be determined automatically. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Check if output power is configurable. + \param power Output power in dBm. + \param clipped Clipped output power value to what is possible within the module's range. + \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically + based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + Ignored when operating in 2.4 GHz band. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); + #if !RADIOLIB_GODMODE private: #endif + // flag to determine whether we are in the sub-GHz or 2.4 GHz range + // this is needed to automatically detect which PA to use + bool highFreq = false; }; diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 71737176b0..701ca6d1a6 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -13,7 +13,7 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, this->XTAL = false; } -int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); @@ -30,9 +30,6 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t state = setSyncWord(syncWord); RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -50,7 +47,7 @@ int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); @@ -64,9 +61,6 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uin state = setRxBandwidth(rxBw); RADIOLIB_ASSERT(state); - - state = setOutputPower(power); - RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -94,7 +88,7 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, int8_t power, uin return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { +int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS); RADIOLIB_ASSERT(state); @@ -103,9 +97,6 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVolt state = setLrFhssConfig(bw, cr); RADIOLIB_ASSERT(state); - state = setOutputPower(power); - RADIOLIB_ASSERT(state); - state = setSyncWord(0x12AD101B); RADIOLIB_ASSERT(state); @@ -605,50 +596,6 @@ int16_t LR11x0::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } -int16_t LR11x0::setOutputPower(int8_t power) { - return(this->setOutputPower(power, false)); -} - -int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) { - // check if power value is configurable - int16_t state = checkOutputPower(power, NULL, forceHighPower); - RADIOLIB_ASSERT(state); - - // determine whether to use HP or LP PA and check range accordingly - bool useHp = forceHighPower || (power > 14); - - // TODO how and when to configure OCP? - - // update PA config - always use VBAT for high-power PA - state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); - RADIOLIB_ASSERT(state); - - // set output power - state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); - return(state); -} - -int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped) { - return(checkOutputPower(power, clipped, false)); -} - -int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) { - if(forceHighPower || (power > 14)) { - if(clipped) { - *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); - } - RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - - } else { - if(clipped) { - *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); - } - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); - - } - return(RADIOLIB_ERR_NONE); -} - int16_t LR11x0::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -1057,6 +1004,10 @@ int16_t LR11x0::setDataRate(DataRate_t dr) { // set the coding rate state = this->setCodingRate(dr.lora.codingRate); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + + } return(state); @@ -1701,6 +1652,112 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat return(state); } +int16_t LR11x0::isGnssScanCapable() { + // get the version + LR11x0VersionInfo_t version; + int16_t state = this->getVersionInfo(&version); + RADIOLIB_ASSERT(state); + + // check the device firmware version is sufficient + uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; + if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { + return(RADIOLIB_ERR_NONE); + } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t LR11x0::gnssScan(uint16_t* resSize) { + // go to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE, 0); + RADIOLIB_ASSERT(state); + + state = this->gnssSetConstellationToUse(0x03); + RADIOLIB_ASSERT(state); + + // set scan mode + state = this->gnssSetMode(0x03); + RADIOLIB_ASSERT(state); + + // start scan with high effort + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start"); + state = this->gnssPerformScan(0x01, 0x3C, 8); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout + RadioLibTime_t softTimeout = 300UL * 1000UL; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); + this->standby(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + int8_t status = 0; + uint8_t info = 0; + state = this->gnssReadDemodStatus(&status, &info); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)status, (unsigned int)info); + + uint8_t fwVersion = 0; + uint32_t almanacCrc = 0; + uint8_t errCode = 0; + uint8_t almUpdMask = 0; + uint8_t freqSpace = 0; + state = this->gnssGetContextStatus(&fwVersion, &almanacCrc, &errCode, &almUpdMask, &freqSpace); + RADIOLIB_DEBUG_BASIC_PRINTLN("Context status fwVersion %d, almanacCrc %lx, errCode %d, almUpdMask %d, freqSpace %d", + (int)fwVersion, (unsigned long)almanacCrc, (int)errCode, (int)almUpdMask, (int)freqSpace); + RADIOLIB_ASSERT(state); + + uint8_t stat[53] = { 0 }; + state = this->gnssReadAlmanacStatus(stat); + RADIOLIB_ASSERT(state); + //Module::hexdump(NULL, stat, 53); + + return(this->gnssGetResultSize(resSize)); +} + +int16_t LR11x0::getGnssScanResult(uint16_t size) { + // read the result + uint8_t res[256] = { 0 }; + int16_t state = this->gnssReadResults(res, size); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Result type: %02x", (int)res[0]); + //Module::hexdump(NULL, res, size); + + return(state); +} + +int16_t LR11x0::getGnssPosition(float* lat, float* lon, bool filtered) { + uint8_t error = 0; + uint8_t nbSvUsed = 0; + uint16_t accuracy = 0; + int16_t state; + if(filtered) { + state = this->gnssReadDopplerSolverRes(&error, &nbSvUsed, NULL, NULL, NULL, NULL, lat, lon, &accuracy, NULL); + } else { + state = this->gnssReadDopplerSolverRes(&error, &nbSvUsed, lat, lon, &accuracy, NULL, NULL, NULL, NULL, NULL); + } + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Solver error %d, nbSvUsed %d, accuracy = %u", (int)error, (int)nbSvUsed, (unsigned int)accuracy); + + return(state); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -2885,21 +2942,17 @@ int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) { } int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) { - // send the command - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, true, NULL, 0); - RADIOLIB_ASSERT(state); - - // read the result - this requires some magic bytes first, that's why LR11x0::SPIcommand cannot be used - uint8_t cmd_buff[3] = { 0x00, 0x02, 0x18 }; + // send the command - datasheet here shows extra bytes being sent in the request + // but doing that fails so treat it like any other read command uint8_t buff[9] = { 0 }; - state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true); + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, false, buff, sizeof(buff)); // pass the replies - if(fwVersion) { *fwVersion = buff[0]; } - if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; } - if(errCode) { *errCode = (buff[5] & 0xF0) >> 4; } - if(almUpdMask) { *almUpdMask = (buff[5] & 0x0E) >> 1; } - if(freqSpace) { *freqSpace = ((buff[5] & 0x01) << 1) | ((buff[6] & 0x80) >> 7); } + if(fwVersion) { *fwVersion = buff[2]; } + if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[3]) << 24) | ((uint32_t)(buff[4]) << 16) | ((uint32_t)(buff[5]) << 8) | (uint32_t)buff[6]; } + if(errCode) { *errCode = (buff[7] & 0xF0) >> 4; } + if(almUpdMask) { *almUpdMask = (buff[7] & 0x0E) >> 1; } + if(freqSpace) { *freqSpace = ((buff[7] & 0x01) << 1) | ((buff[8] & 0x80) >> 7); } return(state); } @@ -3000,10 +3053,10 @@ int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t co return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); } -// TODO check version > 02.01 -int16_t LR11x0::gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { +int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { uint8_t buff[3] = { effort, resMask, nbSvMax }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SCAN, true, buff, sizeof(buff))); + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_SCAN, buff, sizeof(buff), false, false)); } int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 04d5d2f8e6..8aa16da01e 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -700,6 +700,10 @@ struct LR11x0VersionInfo_t { uint8_t almanacGNSS; }; +struct LR11x0GnssResult_t { + +}; + /*! \class LR11x0 \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. @@ -753,34 +757,31 @@ class LR11x0: public PhysicalLayer { \param sf LoRa spreading factor. \param cr LoRa coding rate denominator. \param syncWord 1-byte LoRa sync word. - \param power Output power in dBm. \param preambleLength LoRa preamble length in symbols \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage); + int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage); /*! \brief Initialization method for FSK modem. \param br FSK bit rate in kbps. \param freqDev Frequency deviation from carrier frequency in kHz. \param rxBw Receiver bandwidth in kHz. - \param power Output power in dBm. \param preambleLength FSK preamble length in bits. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginGFSK(float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage); + int16_t beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage); /*! \brief Initialization method for LR-FHSS modem. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. - \param power Output power in dBm. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginLRFHSS(uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage); + int16_t beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -980,41 +981,6 @@ class LR11x0: public PhysicalLayer { int16_t getChannelScanResult() override; // configuration methods - - /*! - \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). - \param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA. - \returns \ref status_codes - */ - int16_t setOutputPower(int8_t power) override; - - /*! - \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). - \param power Output power to be set in dBm. - \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically - based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. - \returns \ref status_codes - */ - int16_t setOutputPower(int8_t power, bool forceHighPower); - - /*! - \brief Check if output power is configurable. - This method is needed for compatibility with PhysicalLayer::checkOutputPower. - \param power Output power in dBm, PA will be determined automatically. - \param clipped Clipped output power value to what is possible within the module's range. - \returns \ref status_codes - */ - int16_t checkOutputPower(int8_t power, int8_t* clipped) override; - - /*! - \brief Check if output power is configurable. - \param power Output power in dBm. - \param clipped Clipped output power value to what is possible within the module's range. - \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically - based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. - \returns \ref status_codes - */ - int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); /*! \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. @@ -1392,6 +1358,14 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true); + + int16_t isGnssScanCapable(); + + int16_t gnssScan(uint16_t* resSize); + + int16_t getGnssScanResult(uint16_t size); + + int16_t getGnssPosition(float* lat, float* lon, bool filtered); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -1514,7 +1488,7 @@ class LR11x0: public PhysicalLayer { int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc); int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac); int16_t gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); - int16_t gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax); + int16_t gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax); int16_t gnssReadLastScanModeLaunched(uint8_t* lastScanMode); int16_t gnssFetchTime(uint8_t effort, uint8_t opt); int16_t gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy); From ce8e6fdfb031b92acf020cef201a9607fc56be31 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 25 Jun 2024 16:56:26 +0100 Subject: [PATCH 1161/1848] [SX126x] Added missing PHY getRSSI (#1132) --- src/modules/SX126x/SX126x.cpp | 4 ++++ src/modules/SX126x/SX126x.h | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 50eeaca1b5..591346d49c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1327,6 +1327,10 @@ float SX126x::getDataRate() const { return(this->dataRateMeasured); } +float SX126x::getRSSI() { + return(this->getRSSI(true)); +} + float SX126x::getRSSI(bool packet) { if(packet) { // get last packet RSSI from packet status diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d66351bb99..f05e5d9a01 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -917,11 +917,18 @@ class SX126x: public PhysicalLayer { float getDataRate() const; /*! - \brief GetsRSSI (Recorded Signal Strength Indicator). + \brief Gets recorded signal strength indicator. + Overload with packet mode enabled for PhysicalLayer compatibility. + \returns RSSI value in dBm. + */ + float getRSSI() override; + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator). \param packet Whether to read last packet RSSI, or the current value. \returns RSSI value in dBm. */ - float getRSSI(bool packet = true); + float getRSSI(bool packet); /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. From 33480235d61210a38c9c7e0c60291fce16132ff2 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 27 Jun 2024 17:38:29 +0200 Subject: [PATCH 1162/1848] [LoRaWAN] Fix JoinRequest dwelltime calculation --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 4cac3fdba1..bd12c06f65 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -510,7 +510,8 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RADIOLIB_ASSERT(state); if(this->dwellTimeEnabledUp) { - RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + // calculate JoinRequest time-on-air in milliseconds + RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; if(toa > this->dwellTimeUp) { return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } From 798ba3efbedc51057215726ff2807d9de2e297ee Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:28:58 +0200 Subject: [PATCH 1163/1848] [SX128x] Added delay to halting while loops --- .../SX128x_BLE_Modem/SX128x_BLE_Modem.ino | 4 ++-- ...28x_Channel_Activity_Detection_Blocking.ino | 2 +- ...8x_Channel_Activity_Detection_Interrupt.ino | 2 +- .../SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino | 4 ++-- .../SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino | 4 ++-- .../SX128x/SX128x_Ranging/SX128x_Ranging.ino | 2 +- .../SX128x_Receive_Blocking.ino | 2 +- .../SX128x_Receive_Interrupt.ino | 4 ++-- .../SX128x/SX128x_Settings/SX128x_Settings.ino | 18 +++++++++--------- .../SX128x_Transmit_Blocking.ino | 2 +- .../SX128x_Transmit_Interrupt.ino | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino index 5b7a1ffd09..be6b8266c9 100644 --- a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino +++ b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between any of the modems @@ -62,7 +62,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #warning "This sketch is just an API guide! Read the note at line 8." diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino index fef3ccc0e8..91ab462e8e 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino index 8daf635792..da0d8f7377 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino @@ -38,7 +38,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino index 168ab510a4..3216d36586 100644 --- a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino +++ b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino @@ -41,7 +41,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between any of the modems @@ -61,7 +61,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #warning "This sketch is just an API guide! Read the note at line 6." diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino index 13412b4930..447abf9ae7 100644 --- a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -41,7 +41,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between any of the modems @@ -61,7 +61,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #warning "This sketch is just an API guide! Read the note at line 6." diff --git a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino index d7427880ba..f69dfa98ae 100644 --- a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino +++ b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino b/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino index 2ba27130a4..024c99f9e9 100644 --- a/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino +++ b/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino @@ -50,7 +50,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 01ec27f3a9..ca63cb78f1 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -46,7 +46,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -61,7 +61,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino index 1bd5f8fc44..eb29c119c0 100644 --- a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino +++ b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -53,7 +53,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize the second LoRa instance with @@ -74,7 +74,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // you can also change the settings at runtime @@ -83,43 +83,43 @@ void setup() { // set carrier frequency to 2410.5 MHz if (radio1.setFrequency(2410.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set bandwidth to 203.125 kHz if (radio1.setBandwidth(203.125) == RADIOLIB_ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set spreading factor to 10 if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set coding rate to 6 if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set output power to -2 dBm if (radio1.setOutputPower(-2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set LoRa preamble length to 16 symbols (accepted range is 2 - 65535) if (radio1.setPreambleLength(16) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); - while (true); + while (true) { delay(10); } } // disable CRC if (radio1.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { Serial.println(F("Selected CRC is invalid for this module!")); - while (true); + while (true) { delay(10); } } Serial.println(F("All settings succesfully changed!")); diff --git a/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino index 18a26c9790..2727555d69 100644 --- a/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino +++ b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino @@ -52,7 +52,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // some modules have an external RF switch diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 811743da2c..17d462a100 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -45,7 +45,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From 44ee248de9cdf2b5d972e481d89d8a2b6632167f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:29:11 +0200 Subject: [PATCH 1164/1848] [AFSK] Added delay to halting while loops --- examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino | 4 ++-- examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino | 4 ++-- examples/AFSK/AFSK_Tone/AFSK_Tone.ino | 4 ++-- examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino index c933ebcc73..6f6c6cc5e8 100644 --- a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino +++ b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino @@ -46,7 +46,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize APRS client @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino index 7c8509166d..0d905d6a75 100644 --- a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino +++ b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AFSK client @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino index 3e2212269f..3071caf16b 100644 --- a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino +++ b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -56,7 +56,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AFSK client @@ -67,7 +67,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino b/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino index 9394d9ab27..d11c8ad06b 100644 --- a/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino +++ b/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino @@ -51,7 +51,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AFSK client @@ -62,7 +62,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // after that, set mode to OOK @@ -73,7 +73,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } From 3ebf371f6bc8a75bf2491b013df07b8f373fc0bd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:30:50 +0200 Subject: [PATCH 1165/1848] [APRS] Added delay to halting while loops --- examples/APRS/APRS_MicE/APRS_MicE.ino | 6 +++--- examples/APRS/APRS_Position/APRS_Position.ino | 6 +++--- examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/APRS/APRS_MicE/APRS_MicE.ino b/examples/APRS/APRS_MicE/APRS_MicE.ino index 5a84d0ea93..aec26ec9da 100644 --- a/examples/APRS/APRS_MicE/APRS_MicE.ino +++ b/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -74,7 +74,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AX.25 client @@ -88,7 +88,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize APRS client @@ -100,7 +100,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index c05ac1947a..06759f3920 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -74,7 +74,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AX.25 client @@ -88,7 +88,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize APRS client @@ -100,7 +100,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino index 31a2f82652..70681a95fd 100644 --- a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino +++ b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino @@ -54,7 +54,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize APRS client @@ -68,7 +68,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } From 6f1ec9f0163710ef6083de93e6cc9bc22f2af090 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:01 +0200 Subject: [PATCH 1166/1848] [AX25] Added delay to halting while loops --- examples/AX25/AX25_Frames/AX25_Frames.ino | 4 ++-- examples/AX25/AX25_Transmit/AX25_Transmit.ino | 4 ++-- examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index 8a55be748f..4c5fe47c11 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -64,7 +64,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AX.25 client @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index bbefc67c3a..1b0c754797 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -56,7 +56,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AX.25 client @@ -70,7 +70,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino index f60818c30e..fb26775ae7 100644 --- a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino +++ b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -66,7 +66,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize AX.25 client @@ -80,7 +80,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // Sometimes, it may be required to adjust audio @@ -95,7 +95,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } From 74c5bb253c44b8aa48ee5da8aec4c04cc3d9625c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:07 +0200 Subject: [PATCH 1167/1848] [Bell] Added delay to halting while loops --- examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino index 7ac4d5b3fa..ec1b08f40b 100644 --- a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino +++ b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino @@ -52,7 +52,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Bell 202 modem @@ -63,7 +63,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } From ab7ed60b2cad2c713383a5597a7aaed4de664c91 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:13 +0200 Subject: [PATCH 1168/1848] [CC1101] Added delay to halting while loops --- .../CC1101_Receive_Address.ino | 6 +++--- .../CC1101_Receive_Blocking.ino | 2 +- .../CC1101_Receive_Interrupt.ino | 4 ++-- .../CC1101/CC1101_Settings/CC1101_Settings.ino | 18 +++++++++--------- .../CC1101_Transmit_Address.ino | 6 +++--- .../CC1101_Transmit_Blocking.ino | 2 +- .../CC1101_Transmit_Interrupt.ino | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino index 2f912f081f..9eeaca9b45 100644 --- a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino +++ b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino @@ -39,7 +39,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set node address @@ -56,7 +56,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // address filtering can also be disabled @@ -70,7 +70,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } diff --git a/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino b/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino index 32dbe6bf15..11edd45cb2 100644 --- a/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino +++ b/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino @@ -46,7 +46,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 4f3e69d8e0..6b585fe507 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -44,7 +44,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -59,7 +59,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino index 680c60d119..8ba03b13e7 100644 --- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino +++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -50,7 +50,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize CC1101 with non-default settings @@ -67,7 +67,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // you can also change the settings at runtime @@ -76,42 +76,42 @@ void setup() { // set carrier frequency to 433.5 MHz if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("[CC1101] Selected frequency is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set bit rate to 100.0 kbps state = radio1.setBitRate(100.0); if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { Serial.println(F("[CC1101] Selected bit rate is invalid for this module!")); - while (true); + while (true) { delay(10); } } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[CC1101] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[CC1101] Increase receiver bandwidth to set this bit rate.")); - while (true); + while (true) { delay(10); } } // set receiver bandwidth to 250.0 kHz if (radio1.setRxBandwidth(250.0) == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[CC1101] Selected receiver bandwidth is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set allowed frequency deviation to 10.0 kHz if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[CC1101] Selected frequency deviation is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set output power to 5 dBm if (radio1.setOutputPower(5) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[CC1101] Selected output power is invalid for this module!")); - while (true); + while (true) { delay(10); } } // 2 bytes can be set as sync word if (radio1.setSyncWord(0x01, 0x23) == RADIOLIB_ERR_INVALID_SYNC_WORD) { Serial.println(F("[CC1101] Selected sync word is invalid for this module!")); - while (true); + while (true) { delay(10); } } } diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index 4aa219d335..ecdec62080 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -39,7 +39,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set node address @@ -56,7 +56,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // address filtering can also be disabled @@ -70,7 +70,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } diff --git a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index fc62ec6364..d42dbed626 100644 --- a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 455d83ddff..4e4e2a1f71 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From 59088418340b511521b7dd95e121e0e9c055d20a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:20 +0200 Subject: [PATCH 1169/1848] [FSK4] Added delay to halting while loops --- examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino | 6 +++--- examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino index 8a1153b05f..088f318b37 100644 --- a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino +++ b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino @@ -73,7 +73,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize FSK4 client @@ -97,7 +97,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // sometimes, it may be needed to set some manual corrections @@ -113,7 +113,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } diff --git a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino index 9c32091817..f8c542fe56 100644 --- a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino +++ b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -82,7 +82,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize FSK4 client @@ -98,7 +98,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // sometimes, it may be needed to set some manual corrections @@ -114,7 +114,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } From 83bf00358990027c8a765de7f0b0407067705c6e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:27 +0200 Subject: [PATCH 1170/1848] [Hell] Added delay to halting while loops --- .../Hellschreiber_Transmit/Hellschreiber_Transmit.ino | 4 ++-- .../Hellschreiber_Transmit_AFSK.ino | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino index 258962b60c..af480409d4 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -55,7 +55,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Hellschreiber client @@ -68,7 +68,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino index dbe267a5a8..f6d5992c07 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -65,7 +65,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Hellschreiber client @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } From 2b844ae816635d2a211bda9dd4b0d259422d2670 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:38 +0200 Subject: [PATCH 1171/1848] [LR11x0] Added delay to halting while loops --- .../LR11x0_Channel_Activity_Detection_Blocking.ino | 2 +- .../LR11x0_Channel_Activity_Detection_Interrupt.ino | 2 +- .../LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino | 6 +++--- examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino | 4 ++-- .../LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino | 4 ++-- .../LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino | 2 +- .../LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino | 4 ++-- .../LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino | 2 +- .../LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino | 2 +- .../LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino | 2 +- .../LR11x0_WiFi_Scan_Interrupt.ino | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino index 10712cd8db..636b488f24 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index c1f29aa305..d4a79299f4 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -64,7 +64,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino index 97fbdaea3e..8813b1daeb 100644 --- a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino +++ b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino @@ -63,7 +63,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // print the firmware versions before the update @@ -85,7 +85,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // print the firmware versions after the update @@ -121,7 +121,7 @@ void printVersions() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } diff --git a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino index bc0a59d0e2..b49d394ee9 100644 --- a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino +++ b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino @@ -41,7 +41,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between any of the modems @@ -63,7 +63,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // GFSK modem on LR11x0 can handle the sync word setting in bits, not just diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino index 094fce29b5..118103ab0b 100644 --- a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -41,7 +41,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between any of the modems @@ -61,7 +61,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #warning "This sketch is just an API guide! Read the note at line 6." diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino index cd40b81631..cf0736ffe4 100644 --- a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -74,7 +74,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index 1f9c86b200..4b9b946f1c 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -70,7 +70,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -85,7 +85,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index 9ec59be1a1..92045bdc10 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -66,7 +66,7 @@ void setup() { Serial.print(F("failed, code ")); Serial.println(state); delay(1000); - while (true); + while (true) { delay(10); } } } diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 459a1d3033..67f5052b0d 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino index e2cafbef41..1e07ffd298 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino @@ -67,7 +67,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino index 37b2431c36..fdf08a9c65 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -67,7 +67,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From 0023a730691574cb3dff2ff804d20c3cb19c19c7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:46 +0200 Subject: [PATCH 1172/1848] [Morse] Added delay to halting while loops --- examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino | 6 +++--- examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino | 6 +++--- examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino | 4 ++-- examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino index c078173f60..3b96d6386c 100644 --- a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino +++ b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino @@ -52,7 +52,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // when using one of the non-LoRa modules for Morse code @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // after that, set mode to OOK to emulate AM modulation @@ -80,7 +80,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // start direct mode reception diff --git a/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino b/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino index 6bedffa673..3aeae2c97d 100644 --- a/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino +++ b/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino @@ -57,7 +57,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Morse client @@ -70,7 +70,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // after that, set mode to OOK to emulate AM modulation @@ -81,7 +81,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino index 3ab9d08df3..1de8baa8b8 100644 --- a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino +++ b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -65,7 +65,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Morse client @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino index 4b35e77465..cbc027969b 100644 --- a/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino +++ b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino @@ -56,7 +56,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Morse client @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } From d3a81e4fa40652b9635c9843f2a299d1e0930f6f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:31:54 +0200 Subject: [PATCH 1173/1848] [nRF24] Added delay to halting while loops --- .../nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino | 4 ++-- .../nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino | 6 +++--- .../nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino | 4 ++-- .../nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino b/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino index 6ae29bbaff..b23e5e9915 100644 --- a/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino +++ b/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino @@ -44,7 +44,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set receive pipe 0 address @@ -59,7 +59,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index 1535bc661a..36622d6d35 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -41,7 +41,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set receive pipe 0 address @@ -56,7 +56,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set the function that will be called @@ -71,7 +71,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino index 402a3cffc8..c553eab281 100644 --- a/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino +++ b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino @@ -40,7 +40,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set transmit address @@ -55,7 +55,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 55834b8d78..58c18e73b2 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set transmit address @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set the function that will be called From 1178f5e718e4d14cc968b425d6a78b46cd7d791e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:32:05 +0200 Subject: [PATCH 1174/1848] [Pager] Added delay to halting while loops --- examples/Pager/Pager_Receive/Pager_Receive.ino | 6 +++--- examples/Pager/Pager_Transmit/Pager_Transmit.ino | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino index c8368930e0..9eabeb63be 100644 --- a/examples/Pager/Pager_Receive/Pager_Receive.ino +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -65,7 +65,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize Pager client @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // start receiving POCSAG messages @@ -90,7 +90,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/examples/Pager/Pager_Transmit/Pager_Transmit.ino index d23452d410..6bb331ddb1 100644 --- a/examples/Pager/Pager_Transmit/Pager_Transmit.ino +++ b/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -54,7 +54,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize Pager client @@ -67,7 +67,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } From ff5b7117bfd081c43474ea6817ed2a4adaac56cc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:32:19 +0200 Subject: [PATCH 1175/1848] [PHY] Added delay to halting while loops --- .../PhysicalLayer_Interface.ino | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino b/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino index 58a95360fa..b56da33f12 100644 --- a/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino +++ b/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino @@ -42,7 +42,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // or we can use the "phy" pointer to access the common layer @@ -54,7 +54,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // PhysicalLayer also contains basic functionality @@ -66,7 +66,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // try to receive now - this will almost certainly timeout @@ -82,7 +82,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // interrupt-driven versions of Rx/Tx are supported as well @@ -105,7 +105,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // ... or standby @@ -116,7 +116,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // there are also common SNR/RSSI measurement functions From d99dd952dfd4e5acadd6ebcbdb029f2fffdd6661 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:32:30 +0200 Subject: [PATCH 1176/1848] [RF69] Added delay to halting while loops --- .../RF69_Receive_AES/RF69_Receive_AES.ino | 2 +- .../RF69_Receive_Address.ino | 8 ++++---- .../RF69_Receive_Blocking.ino | 2 +- .../RF69_Receive_Interrupt.ino | 4 ++-- examples/RF69/RF69_Settings/RF69_Settings.ino | 20 +++++++++---------- .../RF69_Transmit_AES/RF69_Transmit_AES.ino | 2 +- .../RF69_Transmit_Address.ino | 8 ++++---- .../RF69_Transmit_Blocking.ino | 4 ++-- .../RF69_Transmit_Interrupt.ino | 4 ++-- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino index 8ca312129b..857a84fdc4 100644 --- a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino +++ b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino @@ -36,7 +36,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set AES key that will be used to decrypt the packet diff --git a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino index c6127995b4..37b196e6eb 100644 --- a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino +++ b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino @@ -38,7 +38,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set node address @@ -51,7 +51,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set broadcast address @@ -64,7 +64,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // address filtering can also be disabled @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } diff --git a/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino b/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino index a886b87dc6..6b2c02240e 100644 --- a/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino +++ b/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino @@ -45,7 +45,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 1bc87276ba..b44ac50223 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -36,7 +36,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -51,7 +51,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/RF69/RF69_Settings/RF69_Settings.ino b/examples/RF69/RF69_Settings/RF69_Settings.ino index 23626c2df9..f3d6f7f567 100644 --- a/examples/RF69/RF69_Settings/RF69_Settings.ino +++ b/examples/RF69/RF69_Settings/RF69_Settings.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize RF69 with non-default settings @@ -65,7 +65,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // you can also change the settings at runtime @@ -74,41 +74,41 @@ void setup() { // set carrier frequency to 433.5 MHz if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("[RF69] Selected frequency is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set bit rate to 100.0 kbps state = radio1.setBitRate(100.0); if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { Serial.println(F("[RF69] Selected bit rate is invalid for this module!")); - while (true); + while (true) { delay(10); } } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[RF69] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[RF69] Increase receiver bandwidth to set this bit rate.")); - while (true); + while (true) { delay(10); } } // set receiver bandwidth to 250.0 kHz state = radio1.setRxBandwidth(250.0); if (state == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[RF69] Selected receiver bandwidth is invalid for this module!")); - while (true); + while (true) { delay(10); } } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[RF69] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[RF69] Decrease bit rate to set this receiver bandwidth.")); - while (true); + while (true) { delay(10); } } // set allowed frequency deviation to 10.0 kHz if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[RF69] Selected frequency deviation is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set output power to 2 dBm if (radio1.setOutputPower(2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[RF69] Selected output power is invalid for this module!")); - while (true); + while (true) { delay(10); } } // up to 8 bytes can be set as sync word @@ -117,7 +117,7 @@ void setup() { uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; if (radio1.setSyncWord(syncWord, 8) == RADIOLIB_ERR_INVALID_SYNC_WORD) { Serial.println(F("[RF69] Selected sync word is invalid for this module!")); - while (true); + while (true) { delay(10); } } Serial.println(F("[RF69] All settings changed successfully!")); diff --git a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino index 48c9057761..6ef73915a3 100644 --- a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino +++ b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino @@ -36,7 +36,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set AES key to encrypt the packet diff --git a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino index e9b1fba163..ea3dfe3347 100644 --- a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino +++ b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino @@ -38,7 +38,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set node address @@ -51,7 +51,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set broadcast address @@ -64,7 +64,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // address filtering can also be disabled @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } */ } diff --git a/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino index 0a4897805a..78a2bac947 100644 --- a/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino +++ b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino @@ -42,7 +42,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // NOTE: some RF69 modules use high power output, @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } */ } diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index b168af7301..0eacb13dcf 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -42,7 +42,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -62,7 +62,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } */ From 3ee37e4de595998873349e4c14341e74c1b325da Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:32:38 +0200 Subject: [PATCH 1177/1848] [RTTY] Added delay to halting while loops --- examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 4 ++-- examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index 5d3b1387a7..3c5a74bdff 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -55,7 +55,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize RTTY client @@ -81,7 +81,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } /* diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino index c9b268cdd3..70a798f3dc 100644 --- a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -63,7 +63,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // initialize RTTY client @@ -81,7 +81,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } /* From abbbda671bca24191159e6e345241c468c60f4fe Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:32:48 +0200 Subject: [PATCH 1178/1848] [Si443x] Added delay to halting while loops --- .../Si443x_Receive_Blocking.ino | 2 +- .../Si443x_Receive_Interrupt.ino | 4 ++-- .../Si443x/Si443x_Settings/Si443x_Settings.ino | 18 +++++++++--------- .../Si443x_Transmit_Blocking.ino | 2 +- .../Si443x_Transmit_Interrupt.ino | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino b/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino index 54715ffa84..821be023e9 100644 --- a/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino +++ b/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino @@ -47,7 +47,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index a12d2ee390..b3e1c9a744 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -38,7 +38,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -53,7 +53,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino index 9823e97d0f..ab911e5867 100644 --- a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino +++ b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize Si4432 with non-default settings @@ -65,7 +65,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // you can also change the settings at runtime @@ -74,37 +74,37 @@ void setup() { // set carrier frequency to 433.5 MHz if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("[Si4432] Selected frequency is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set bit rate to 100.0 kbps state = radio1.setBitRate(100.0); if (state == RADIOLIB_ERR_INVALID_BIT_RATE) { Serial.println(F("[Si4432] Selected bit rate is invalid for this module!")); - while (true); + while (true) { delay(10); } } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) { Serial.println(F("[Si4432] Selected bit rate to bandwidth ratio is invalid!")); Serial.println(F("[Si4432] Increase receiver bandwidth to set this bit rate.")); - while (true); + while (true) { delay(10); } } // set receiver bandwidth to 284.8 kHz state = radio1.setRxBandwidth(284.8); if (state == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[Si4432] Selected receiver bandwidth is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set frequency deviation to 10.0 kHz if (radio1.setFrequencyDeviation(10.0) == RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[Si4432] Selected frequency deviation is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set output power to 2 dBm if (radio1.setOutputPower(2) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[Si4432] Selected output power is invalid for this module!")); - while (true); + while (true) { delay(10); } } // up to 4 bytes can be set as sync word @@ -112,7 +112,7 @@ void setup() { uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; if (radio1.setSyncWord(syncWord, 4) == RADIOLIB_ERR_INVALID_SYNC_WORD) { Serial.println(F("[Si4432] Selected sync word is invalid for this module!")); - while (true); + while (true) { delay(10); } } Serial.println(F("[Si4432] All settings changed successfully!")); diff --git a/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino index 7197281a97..240cd31bcc 100644 --- a/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino +++ b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino @@ -44,7 +44,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 685574746e..094e3bdbc5 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From e942ac5ffc74f499897e3c496aa5994c3d332d77 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:33:03 +0200 Subject: [PATCH 1179/1848] [SSTV] Added delay to halting while loops --- examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino | 8 ++++---- examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino index e532e2d407..46ec78a968 100644 --- a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino +++ b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -96,7 +96,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // when using one of the non-LoRa modules for SSTV @@ -113,7 +113,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set correction factor @@ -132,7 +132,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // to help tune the receiver, SSTVClient can send @@ -141,7 +141,7 @@ void setup() { // (SSTV header "leader tone") /* sstv.idle(); - while(true); + while (true) { delay(10); } */ } diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino index 924522b161..5ec48a5a0c 100644 --- a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -103,7 +103,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // when using one of the non-LoRa modules for SSTV @@ -119,7 +119,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // set correction factor @@ -138,14 +138,14 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // to help tune the receiver, SSTVClient can send // continuous 1900 Hz beep /* sstv.idle(); - while(true); + while (true) { delay(10); } */ } From 87c1851dc4343cce8df4a6f2eadb8d4c4790f456 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:33:19 +0200 Subject: [PATCH 1180/1848] [STM32WL] Added delay to halting while loops --- .../STM32WLx_Channel_Activity_Detection.ino | 2 +- .../STM32WLx_Channel_Activity_Detection_Interrupt.ino | 2 +- .../STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino | 4 ++-- .../STM32WLx_Receive_Interrupt.ino | 6 +++--- .../STM32WLx_Transmit_Blocking.ino | 4 ++-- .../STM32WLx_Transmit_Interrupt.ino | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino index 7beab1ee2a..0c4f9b8140 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino index d730734f27..4475a49647 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino index 5eaf4015d3..44163df24d 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Blocking/STM32WLx_Receive_Blocking.ino @@ -64,7 +64,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set appropriate TCXO voltage for Nucleo WL55JC1 @@ -74,7 +74,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index a4841f930a..a1da096873 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set appropriate TCXO voltage for Nucleo WL55JC1 @@ -68,7 +68,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -83,7 +83,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino index 2bd2b02b44..5a7d7b088f 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -59,7 +59,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set appropriate TCXO voltage for Nucleo WL55JC1 @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index d22f77b5ee..aed1c12540 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -53,7 +53,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set appropriate TCXO voltage for Nucleo WL55JC1 @@ -63,7 +63,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From 406197e66767b2c35e8cad1441aa21bafc20b142 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:33:25 +0200 Subject: [PATCH 1181/1848] [SX123x] Added delay to halting while loops --- .../SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino | 2 +- .../SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino b/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino index f79d35462a..66978b6bef 100644 --- a/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino +++ b/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino @@ -44,7 +44,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino b/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino index e311737e56..50bbe1bf43 100644 --- a/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino +++ b/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } From b34be58e1a22b185758ea14e4136237245c65105 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:33:34 +0200 Subject: [PATCH 1182/1848] [Stream] Added delay to halting while loops --- examples/Stream/Stream_Receive/Stream_Receive.ino | 4 ++-- examples/Stream/Stream_Transmit/Stream_Transmit.ino | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Stream/Stream_Receive/Stream_Receive.ino b/examples/Stream/Stream_Receive/Stream_Receive.ino index 39fc1bb636..e30f9378d1 100644 --- a/examples/Stream/Stream_Receive/Stream_Receive.ino +++ b/examples/Stream/Stream_Receive/Stream_Receive.ino @@ -51,7 +51,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -69,7 +69,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index 4789a6ebed..a3c6fb93bd 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -65,7 +65,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From 3bf973d5685cf3cfb69787e640d540f61f64fb82 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:34:29 +0200 Subject: [PATCH 1183/1848] [SX126x] Added delay to halting while loops --- ...6x_Channel_Activity_Detection_Blocking.ino | 2 +- ...x_Channel_Activity_Detection_Interrupt.ino | 2 +- ...26x_Channel_Activity_Detection_Receive.ino | 2 +- .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 4 +-- .../SX126x_PingPong/SX126x_PingPong.ino | 4 +-- .../SX126x_Receive_Blocking.ino | 2 +- .../SX126x_Receive_Interrupt.ino | 4 +-- .../SX126x_Settings/SX126x_Settings.ino | 26 +++++++++---------- .../SX126x_Spectrum_Scan.ino | 8 +++--- .../SX126x_Spectrum_Scan_Frequency.ino | 8 +++--- .../SX126x_Transmit_Blocking.ino | 2 +- .../SX126x_Transmit_Interrupt.ino | 2 +- 12 files changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino index 0d2380dd76..17d6b9f081 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index 651da66b91..0d0f45cd1d 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -43,7 +43,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino index 20b0ae92d5..6b68227e9e 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino @@ -45,7 +45,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index 2c394c5ccc..93a18b65be 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -44,7 +44,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between LoRa and FSK modes @@ -67,7 +67,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // FSK modem on SX126x can handle the sync word setting in bits, not just diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index 99a962b272..0ec708c899 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -61,7 +61,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -82,7 +82,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #endif } diff --git a/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino b/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino index 75fda8f65a..0dee95333d 100644 --- a/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino +++ b/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino @@ -53,7 +53,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 11d6ea81e8..017c78cdee 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -49,7 +49,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -64,7 +64,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index 530c49ab17..287403982c 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -59,7 +59,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize the second LoRa instance with @@ -80,7 +80,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // you can also change the settings at runtime @@ -89,56 +89,56 @@ void setup() { // set carrier frequency to 433.5 MHz if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set bandwidth to 250 kHz if (radio1.setBandwidth(250.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set spreading factor to 10 if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set coding rate to 6 if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set LoRa sync word to 0xAB if (radio1.setSyncWord(0xAB) != RADIOLIB_ERR_NONE) { Serial.println(F("Unable to set sync word!")); - while (true); + while (true) { delay(10); } } // set output power to 10 dBm (accepted range is -17 - 22 dBm) if (radio1.setOutputPower(10) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) // NOTE: set value to 0 to disable overcurrent protection if (radio1.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { Serial.println(F("Selected current limit is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set LoRa preamble length to 15 symbols (accepted range is 0 - 65535) if (radio1.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); - while (true); + while (true) { delay(10); } } // disable CRC if (radio1.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { Serial.println(F("Selected CRC is invalid for this module!")); - while (true); + while (true) { delay(10); } } // Some SX126x modules have TCXO (temperature compensated crystal @@ -146,7 +146,7 @@ void setup() { // the following method can be used. if (radio1.setTCXO(2.4) == RADIOLIB_ERR_INVALID_TCXO_VOLTAGE) { Serial.println(F("Selected TCXO voltage is invalid for this module!")); - while (true); + while (true) { delay(10); } } // Some SX126x modules use DIO2 as RF switch. To enable @@ -155,7 +155,7 @@ void setup() { // it can't be used as interrupt pin! if (radio1.setDio2AsRfSwitch() != RADIOLIB_ERR_NONE) { Serial.println(F("Failed to set DIO2 as RF switch!")); - while (true); + while (true) { delay(10); } } Serial.println(F("All settings succesfully changed!")); diff --git a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino index dbf4a9d253..987f4655c6 100644 --- a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino +++ b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino @@ -45,7 +45,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // upload a patch to the SX1262 to enable spectral scan @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // configure scan bandwidth to 234.4 kHz @@ -71,7 +71,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } @@ -87,7 +87,7 @@ void loop() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // wait for spectral scan to finish diff --git a/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino b/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino index e7d6b33a30..f5de4607c1 100644 --- a/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino +++ b/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino @@ -49,7 +49,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // upload a patch to the SX1262 to enable spectral scan @@ -62,7 +62,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // configure scan bandwidth to 234.4 kHz @@ -75,7 +75,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } } @@ -95,7 +95,7 @@ void loop() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while(true); + while (true) { delay(10); } } // wait for spectral scan to finish diff --git a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino index 8cf890eb5e..e090ef8e43 100644 --- a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino +++ b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // some modules have an external RF switch diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index be281597a1..5f0b9ea1a2 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -48,7 +48,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From 786dea5f56928152b62bf94e9f904bd06a6f3fdc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Jun 2024 18:34:41 +0200 Subject: [PATCH 1184/1848] [SX127x] Added delay to halting while loops --- ...7x_Channel_Activity_Detection_Blocking.ino | 2 +- ...x_Channel_Activity_Detection_Interrupt.ino | 2 +- ...27x_Channel_Activity_Detection_Receive.ino | 2 +- .../SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 6 ++--- .../SX127x_PingPong/SX127x_PingPong.ino | 4 ++-- .../SX127x_Receive_Blocking.ino | 2 +- .../SX127x_Receive_Direct.ino | 2 +- .../SX127x_Receive_FHSS.ino | 6 ++--- .../SX127x_Receive_Interrupt.ino | 4 ++-- .../SX127x_Settings/SX127x_Settings.ino | 22 +++++++++---------- .../SX127x_Transmit_Blocking.ino | 2 +- .../SX127x_Transmit_FHSS.ino | 4 ++-- .../SX127x_Transmit_Interrupt.ino | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino index 6a23001aa5..ebd3ed32f1 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino @@ -46,7 +46,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 631ae909bf..edb01aa4f7 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -42,7 +42,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino index 945ded9fcf..35f9d40df0 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -47,7 +47,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index aa2b2127f0..49617884c9 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -41,7 +41,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, you can switch between LoRa and FSK modes @@ -64,7 +64,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // FSK modulation can be changed to OOK @@ -77,7 +77,7 @@ void setup() { if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to change modulation, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #warning "This sketch is just an API guide! Read the note at line 6." diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index df025bc99d..0e191f204f 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -58,7 +58,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -79,7 +79,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } #endif } diff --git a/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino b/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino index bdfae6d5e8..b2a1e30218 100644 --- a/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino +++ b/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino @@ -50,7 +50,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino index dee4214f5d..d622a2a227 100644 --- a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino +++ b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino @@ -39,7 +39,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the direct mode sync word diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index d3423b9e54..7785a1730f 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -81,7 +81,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set hop period in symbols @@ -92,7 +92,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function to call when reception is finished @@ -109,7 +109,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } } diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 0e833e0d99..5d2adbffa7 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -46,7 +46,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called @@ -61,7 +61,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // if needed, 'listen' mode can be disabled by calling diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino index 007a49fbb3..6fbc631b5a 100644 --- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino +++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -52,7 +52,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // initialize the second LoRa instance with @@ -78,7 +78,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // you can also change the settings at runtime @@ -87,32 +87,32 @@ void setup() { // set carrier frequency to 433.5 MHz if (radio1.setFrequency(433.5) == RADIOLIB_ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set bandwidth to 250 kHz if (radio1.setBandwidth(250.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set spreading factor to 10 if (radio1.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set coding rate to 6 if (radio1.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set LoRa sync word to 0x14 // NOTE: value 0x34 is reserved for LoRaWAN networks and should not be used if (radio1.setSyncWord(0x14) != RADIOLIB_ERR_NONE) { Serial.println(F("Unable to set sync word!")); - while (true); + while (true) { delay(10); } } // set output power to 10 dBm (accepted range is -3 - 17 dBm) @@ -120,20 +120,20 @@ void setup() { // duty cycle MUST NOT exceed 1% if (radio1.setOutputPower(10) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) // NOTE: set value to 0 to disable overcurrent protection if (radio1.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { Serial.println(F("Selected current limit is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set LoRa preamble length to 15 symbols (accepted range is 6 - 65535) if (radio1.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); - while (true); + while (true) { delay(10); } } // set amplifier gain to 1 (accepted range is 1 - 6, where 1 is maximum gain) @@ -141,7 +141,7 @@ void setup() { // leave at 0 unless you know what you're doing if (radio1.setGain(1) == RADIOLIB_ERR_INVALID_GAIN) { Serial.println(F("Selected gain is invalid for this module!")); - while (true); + while (true) { delay(10); } } Serial.println(F("All settings successfully changed!")); diff --git a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino index 2298ac2cb0..e5b258e3eb 100644 --- a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino +++ b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino @@ -45,7 +45,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // some modules have an external RF switch diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index 15ef3ae818..5c2297db40 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -93,7 +93,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set hop period in symbols @@ -104,7 +104,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function to call when transmission is finished diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 7cdce59379..7b78080e39 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -45,7 +45,7 @@ void setup() { } else { Serial.print(F("failed, code ")); Serial.println(state); - while (true); + while (true) { delay(10); } } // set the function that will be called From edae29e1e9551211c1849182897f6af6656e1bd8 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Mon, 1 Jul 2024 21:29:12 +0300 Subject: [PATCH 1185/1848] [LR11x0] use the same irq mask for both DIO9 and DIO11 --- src/modules/LR11x0/LR11x0.cpp | 16 ++++++++++------ src/modules/LR11x0/LR11x0.h | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 701ca6d1a6..906c56c849 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -395,7 +395,7 @@ int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT, 0); + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT); RADIOLIB_ASSERT(state); if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { @@ -463,7 +463,7 @@ int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa irq |= RADIOLIB_LR11X0_IRQ_TIMEOUT; } - state = setDioIrqParams(irq, RADIOLIB_LR11X0_IRQ_NONE); + state = setDioIrqParams(irq); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -562,7 +562,7 @@ int16_t LR11x0::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det this->mod->setRfSwitchState(Module::MODE_RX); // set DIO pin mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE, RADIOLIB_LR11X0_IRQ_NONE); + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -1436,7 +1436,7 @@ int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, ui RADIOLIB_ASSERT(state); // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE, 0); + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE); RADIOLIB_ASSERT(state); // start scan with the maximum number of results and abort on timeout @@ -1675,7 +1675,7 @@ int16_t LR11x0::gnssScan(uint16_t* resSize) { RADIOLIB_ASSERT(state); // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE, 0); + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE); RADIOLIB_ASSERT(state); state = this->gnssSetConstellationToUse(0x03); @@ -1879,7 +1879,7 @@ int16_t LR11x0::config(uint8_t modem) { // clear IRQ state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); - state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE, RADIOLIB_LR11X0_IRQ_NONE); + state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE); RADIOLIB_ASSERT(state); // calibrate all blocks @@ -2149,6 +2149,10 @@ int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff))); } +int16_t LR11x0::setDioIrqParams(uint32_t irq) { + return(setDioIrqParams(irq, irq)); +} + int16_t LR11x0::clearIrq(uint32_t irq) { uint8_t buff[4] = { (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 8aa16da01e..e00c6bf63e 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1389,6 +1389,7 @@ class LR11x0: public PhysicalLayer { int16_t calibImage(float freq1, float freq2); int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg); int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2); + int16_t setDioIrqParams(uint32_t irq); int16_t clearIrq(uint32_t irq); int16_t configLfClock(uint8_t setup); int16_t setTcxoMode(uint8_t tune, uint32_t delay); From ace099735960b7a086d6d375c4a7d4742efcdfd6 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 4 Jul 2024 02:23:00 +1000 Subject: [PATCH 1186/1848] NonArduino: Tock: A collection of fixes for LoRaWAN support (#1145) --- examples/NonArduino/Tock/libtockHal.h | 37 ++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/examples/NonArduino/Tock/libtockHal.h b/examples/NonArduino/Tock/libtockHal.h index 85c53920cd..7ae8bf2ae7 100644 --- a/examples/NonArduino/Tock/libtockHal.h +++ b/examples/NonArduino/Tock/libtockHal.h @@ -55,6 +55,9 @@ typedef void (*gpioIrqFn)(void); +gpioIrqFn gpio_funcs[4] = { NULL, NULL, NULL, NULL}; +uint32_t frequency = 0; + /* * Get the the timer frequency in Hz. */ @@ -73,7 +76,7 @@ static void lora_phy_gpio_Callback (int gpioPin, __attribute__ ((unused)) int arg3, void* userdata) { - gpioIrqFn fn = *(gpioIrqFn*)(&userdata); + gpioIrqFn fn = gpio_funcs[gpioPin - 1]; if (fn != NULL ) { fn(); @@ -136,7 +139,8 @@ class TockHal : public RadioLibHal { return; } - libtock_lora_phy_gpio_command_interrupt_callback(lora_phy_gpio_Callback, &interruptCb); + gpio_funcs[interruptNum - 1] = interruptCb; + libtock_lora_phy_gpio_command_interrupt_callback(lora_phy_gpio_Callback, NULL); // set GPIO as input and enable interrupts on it libtock_lora_phy_gpio_enable_input(interruptNum, libtock_pull_down); @@ -148,24 +152,43 @@ class TockHal : public RadioLibHal { return; } + gpio_funcs[interruptNum - 1] = NULL; libtock_lora_phy_gpio_disable_interrupt(interruptNum); } void delay(unsigned long ms) override { - libtocksync_alarm_delay_ms( ms ); +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + libtocksync_alarm_delay_ms(ms); +#else + libtocksync_alarm_delay_ms(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); +#endif } void delayMicroseconds(unsigned long us) override { - libtocksync_alarm_delay_ms( us / 1000 ); +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + libtocksync_alarm_delay_ms(us / 1000); +#else + libtocksync_alarm_delay_ms((us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)) / 1000); +#endif } unsigned long millis() override { - uint32_t frequency, now; + uint32_t now; + unsigned long ms; + + if (frequency == 0) { + alarm_internal_frequency(&frequency); + } - alarm_internal_frequency(&frequency); alarm_internal_read(&now); - return (now / frequency) / 1000; + ms = now / (frequency / 1000); + +#if !defined(RADIOLIB_CLOCK_DRIFT_MS) + return ms; +#else + return ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS); +#endif } unsigned long micros() override { From 61a4cae9351fefa81227e7e8144bb83ce0285ff4 Mon Sep 17 00:00:00 2001 From: Oliver <107413444+OlliLausS@users.noreply.github.com> Date: Mon, 8 Jul 2024 22:37:09 +0200 Subject: [PATCH 1187/1848] Method SetBitrateTolerance added for CC1101, Updated error handling (#1152) * Update TypeDef.h * Update CC1101.h * Update CC1101.cpp * Update CC1101.cpp Update of error handling --- src/TypeDef.h | 5 +++++ src/modules/CC1101/CC1101.cpp | 9 +++++++++ src/modules/CC1101/CC1101.h | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/src/TypeDef.h b/src/TypeDef.h index 1d59bf6cb3..55434cf12a 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -292,6 +292,11 @@ */ #define RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE (-108) +/*! + \brief Supplied Bitrate tolerance value is out of Range. +*/ +#define RADIOLIB_ERR_INVALID_BIT_RATE_TOLERANCE_VALUE (-109) + // APRS status codes /*! diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index cfce1f2ace..7d08ac7a33 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -470,6 +470,15 @@ int16_t CC1101::setBitRate(float br) { return(state); } +int16_t CC1101::setBitRateTolerance(uint8_t brt) { + if (brt > 0x03) return (RADIOLIB_ERR_INVALID_BIT_RATE_TOLERANCE_VALUE); + + // Set Bit Rate tolerance + int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_BSCFG, brt, 1, 0); + + return(state); +} + int16_t CC1101::setRxBandwidth(float rxBw) { RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index af315a370c..55eb9a8433 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -738,6 +738,13 @@ class CC1101: public PhysicalLayer { */ int16_t setBitRate(float br) override; + /*! + \brief Sets bit rate tolerance in BSCFG register. Allowed values are 0:(0%), 1(3,125%), 2:(6,25%) and 3:(12,5%). + \param brt Bit rate tolerance to be set. + \returns \ref status_codes + */ + int16_t setBitRateTolerance(uint8_t brt); + /*! \brief Sets receiver bandwidth. Allowed values are 58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650 and 812 kHz. From a9bd1bffe88fcb88f2aff584cd2ea03bab1aa6ba Mon Sep 17 00:00:00 2001 From: Sebastian Kuzminsky Date: Mon, 8 Jul 2024 15:18:28 -0600 Subject: [PATCH 1188/1848] [SX127x] When clearing the FHSS interrupt, don't also clear all the others --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 13096257d2..d81671e838 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1660,7 +1660,7 @@ uint8_t SX127x::getFHSSChannel(void) { void SX127x::clearFHSSInt(void) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { return; //These are not the interrupts you are looking for } From 0eeb5fe0d91007f04f0ffe98701a27fecd600be6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 9 Jul 2024 21:01:09 +0200 Subject: [PATCH 1189/1848] [LoRaWAN] Fix #1154, finalize LW v1.0.4 Holiday parting gift - happy holidays! --- src/protocols/LoRaWAN/LoRaWAN.cpp | 205 ++++++++++++++++-------------- src/protocols/LoRaWAN/LoRaWAN.h | 6 + 2 files changed, 115 insertions(+), 96 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index bd12c06f65..e4c379c36f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -42,9 +42,18 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t } void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { - this->backoffMax = backoffMax; - this->difsSlots = difsSlots; - this->enableCSMA = enableCSMA; + this->backoffMax = backoffMax; + this->difsSlots = difsSlots; + this->enableCSMA = enableCSMA; +} + +void LoRaWANNode::createNonces() { + // set the device credentials + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], this->lwMode); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], this->lwClass); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); } void LoRaWANNode::clearNonces() { @@ -54,6 +63,7 @@ void LoRaWANNode::clearNonces() { this->devNonce = 0; this->joinNonce = 0; this->isActive = false; + this->rev = 0; } void LoRaWANNode::clearSession() { @@ -299,7 +309,7 @@ int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); if(signature != checkSum) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04X, expected: %04X", checkSum, signature); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04x, expected: %04x", checkSum, signature); return(RADIOLIB_ERR_CHECKSUM_MISMATCH); } return(RADIOLIB_ERR_NONE); @@ -445,20 +455,30 @@ void LoRaWANNode::activateCommon(uint8_t initialDr) { } void LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey) { + // clear all the device credentials in case there were any + this->clearNonces(); + this->joinEUI = joinEUI; this->devEUI = devEUI; - memcpy(this->nwkKey, nwkKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->appKey, appKey, RADIOLIB_AES128_KEY_SIZE); + if(nwkKey) { + this->rev = 1; + memcpy(this->nwkKey, nwkKey, RADIOLIB_AES128_KEY_SIZE); + } // generate activation key checksum this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); - this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkKey, 16); this->keyCheckSum ^= LoRaWANNode::checkSum16(appKey, 16); + if(nwkKey) { + this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkKey, 16); + } - this->clearNonces(); this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA; this->lwClass = RADIOLIB_LORAWAN_CLASS_A; + + // set the device credentials + this->createNonces(); } int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) { @@ -530,7 +550,12 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code - uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); + uint32_t mic = 0; + if(this->rev == 1) { + mic =this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); + } else { + mic =this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->appKey); + } LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); // send it @@ -584,7 +609,11 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // the first byte is the MAC header which is not encrypted uint8_t joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; joinAcceptMsg[0] = joinAcceptMsgEnc[0]; - RadioLibAES128Instance.init(this->nwkKey); + if(this->rev == 1) { + RadioLibAES128Instance.init(this->nwkKey); + } else { + RadioLibAES128Instance.init(this->appKey); + } RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]); // get current joinNonce from downlink @@ -593,9 +622,16 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinAccept (JoinNonce = %lu, previously %lu):", (unsigned long)joinNonceNew, (unsigned long)this->joinNonce); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinAcceptMsg, lenRx); - // joinNonce received must be greater than the last joinNonce heard, else error - if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { - return(RADIOLIB_ERR_JOIN_NONCE_INVALID); + if(this->rev == 1) { + // for v1.1, the JoinNonce received must be greater than the last joinNonce heard, else error + if((this->joinNonce > 0) && (joinNonceNew <= this->joinNonce)) { + return(RADIOLIB_ERR_JOIN_NONCE_INVALID); + } + } else { + // for v1.0.4, the JoinNonce is simply a non-repeating value (we only check the last value) + if(joinNonceNew == this->joinNonce) { + return(RADIOLIB_ERR_JOIN_NONCE_INVALID); + } } this->joinNonce = joinNonceNew; @@ -629,7 +665,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } else { // 1.0 version - if(!verifyMIC(joinAcceptMsg, lenRx, this->nwkKey)) { + if(!verifyMIC(joinAcceptMsg, lenRx, this->appKey)) { return(RADIOLIB_ERR_CRC_MISMATCH); } @@ -704,11 +740,11 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; - RadioLibAES128Instance.init(this->nwkKey); + RadioLibAES128Instance.init(this->appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_F_NWK_S_INT_KEY; - RadioLibAES128Instance.init(this->nwkKey); + RadioLibAES128Instance.init(this->appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey); memcpy(this->sNwkSIntKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); @@ -724,12 +760,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; - // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_OTAA); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; @@ -763,17 +794,19 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } void LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey) { + // clear all the device credentials in case there were any + this->clearNonces(); + this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); - if(fNwkSIntKey) { + if(fNwkSIntKey && sNwkSIntKey) { this->rev = 1; memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } else { memcpy(this->fNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); - } - if(sNwkSIntKey) { - memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->sNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); } // generate activation key checksum @@ -783,10 +816,11 @@ void LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIn if(fNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } if(sNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } - // clear & set all the device credentials - this->clearNonces(); this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; this->lwClass = RADIOLIB_LORAWAN_CLASS_A; + + // set the device credentials + this->createNonces(); } int16_t LoRaWANNode::activateABP(uint8_t initialDr) { @@ -822,13 +856,6 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; - // save the activation keys checksum, mode, class, frequency plan - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], RADIOLIB_LORAWAN_MODE_ABP); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], RADIOLIB_LORAWAN_CLASS_A); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); - // new session all good, so set active-bit to true this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; @@ -1060,8 +1087,13 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen); uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= fOptsLen; - // encrypt it - processAES(fOptsBuff, fOptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + if(this->rev == 1) { + // in LoRaWAN v1.1, the FOpts are encrypted using the NwkSEncKey + processAES(fOptsBuff, fOptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + } else { + // in LoRaWAN v1.0.x, the FOpts are unencrypted + memcpy(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], fOptsBuff, fOptsLen); + } } @@ -1484,8 +1516,14 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey if(fOptsLen <= RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK) { - uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); + if(this->rev == 1) { + // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey + uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); + } else { + // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted + memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen); + } } else { processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); } @@ -1839,23 +1877,9 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); - } - } + #if RADIOLIB_DEBUG_PROTOCOL + this->printChannels(); + #endif return(RADIOLIB_ERR_NONE); } @@ -2262,7 +2286,7 @@ int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* que } bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02X", cmd->cid); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02x", cmd->cid); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { @@ -2683,6 +2707,26 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { return(false); } +void LoRaWANNode::printChannels() { + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } + } +} + bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskCntl == 0) { @@ -2703,26 +2747,12 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; } } - + } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); - } - } + #if RADIOLIB_DEBUG_PROTOCOL + this->printChannels(); + #endif return(true); } @@ -2738,9 +2768,9 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { } } + LoRaWANChannel_t chnl; if((this->band->numTxSpans == 1 && chMaskCntl <= 5) || (this->band->numTxSpans == 2 && chMaskCntl <= 3)) { // select channels from first span - LoRaWANChannel_t chnl; for(uint8_t i = 0; i < 16; i++) { uint16_t mask = 1 << i; if(mask & chMask) { @@ -2763,7 +2793,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { } if(this->band->numTxSpans == 2 && chMaskCntl == 4) { // select channels from second span - LoRaWANChannel_t chnl; for(uint8_t i = 0; i < 8; i++) { uint16_t mask = 1 << i; if(mask & chMask) { @@ -2780,7 +2809,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { } if(this->band->numTxSpans == 2 && chMaskCntl == 5) { // a '1' enables a bank of 8 + 1 channels from 1st and 2nd span respectively - LoRaWANChannel_t chnl; for(uint8_t i = 0; i < 8; i++) { uint16_t mask = 1 << i; if(mask & chMask) { @@ -2811,7 +2839,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { this->setupChannelsFix(this->subBand); // a '1' enables a single channel from second span - LoRaWANChannel_t chnl; for(uint8_t i = 0; i < 8; i++) { uint16_t mask = 1 << i; if(mask & chMask) { @@ -2829,7 +2856,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { } if(this->band->numTxSpans == 2 && chMaskCntl == 7) { // all channels off (clear all channels) - LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl; // downlink channels are not defined so don't need to reset @@ -2852,23 +2879,9 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { } - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); - } - } + #if RADIOLIB_DEBUG_PROTOCOL + this->printChannels(); + #endif return(true); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 3af9477f40..a9524d9909 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1002,6 +1002,9 @@ class LoRaWANNode { // save the selected sub-band in case this must be restored in ADR control uint8_t subBand = 0; + // initalize the Nonces buffer after beginX() has been called + void createNonces(); + // this will reset the device credentials, so the device starts completely new void clearNonces(); @@ -1019,6 +1022,9 @@ class LoRaWANNode { // channels must be configured separately by setupChannelsDyn()! int16_t setPhyProperties(uint8_t dir); + // print the available channels through debug + void printChannels(); + // setup uplink/downlink channel data rates and frequencies // for dynamic channels, there is a small set of predefined channels // in case of JoinRequest, add some optional extra frequencies From 5b9cad0c8cf480314dcda4fc7688c0235f0ab002 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 10 Jul 2024 19:10:52 +1000 Subject: [PATCH 1190/1848] protocol: LoRaWAN: Allow configuring scanGuard The current code uses scanGuard to increase the Rx window. Sometimes the default 10ms scanGuard isn't enough. So allow uses of LoRaWAN to set a larger scanGuard. Signed-off-by: Alistair Francis --- src/protocols/LoRaWAN/LoRaWAN.cpp | 14 +++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index bd12c06f65..7aac3bca5d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1155,14 +1155,10 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon int16_t LoRaWANNode::downlinkCommon() { Module* mod = this->phyLayer->getMod(); - // according to the spec, the Rx window must be at least enough time to effectively detect a preamble - // but we pad it a bit on both sides (start and end) to make sure it is wide enough - const RadioLibTime_t scanGuard = 10; // Rx window padding in milliseconds - // check if there are any upcoming Rx windows // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 RadioLibTime_t now = mod->hal->millis(); // fix the current timestamp to prevent negative delays - if(now > this->rxDelayStart + this->rxDelays[0] - scanGuard) { + if(now > this->rxDelayStart + this->rxDelays[0] - this->scanGuard) { // if between start of Rx1 and end of Rx2, wait until Rx2 closes if(now < this->rxDelayStart + this->rxDelays[1]) { mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - now); @@ -1188,7 +1184,7 @@ int16_t LoRaWANNode::downlinkCommon() { downlinkAction = false; // calculate the Rx timeout - RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000; + RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*this->scanGuard*1000; RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); // wait for the start of the Rx window @@ -1198,8 +1194,8 @@ int16_t LoRaWANNode::downlinkCommon() { waitLen = this->rxDelays[i]; } // the waiting duration is shortened a bit to cover any possible timing errors - if(waitLen > scanGuard) { - waitLen -= scanGuard; + if(waitLen > this->scanGuard) { + waitLen -= this->scanGuard; } mod->hal->delay(waitLen); @@ -1209,7 +1205,7 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", i+1, (int)(timeoutHost / 1000 + scanGuard / 2)); // wait for the timeout to complete (and a small additional delay) - mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); + mod->hal->delay(timeoutHost / 1000 + this->scanGuard / 2); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 3af9477f40..13e3939874 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -871,6 +871,20 @@ class LoRaWANNode { */ bool TS009 = false; + /*! + \brief Rx window padding in milliseconds + according to the spec, the Rx window must be at least enough time to effectively detect a preamble + but we pad it a bit on both sides (start and end) to make sure it is wide enough + The larger this number the more power will be consumed! So be careful about changing it. + For debugging purposes 50 is a reasonable start, but for production devices it should + be as low as possible. + 0 is a valid time. + + 500 is the **maximum** value, but it is not a good idea to go anywhere near that. + If you have to go above 50 you probably have a bug somewhere. Check your device timing. + */ + RadioLibTime_t scanGuard = 10; + #if !RADIOLIB_GODMODE private: #endif From fb049cc3affb61d126af8bc49a16e864093030e2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 13 Jul 2024 14:53:57 +0100 Subject: [PATCH 1191/1848] [SSTV] Added Robot36 and Robot72 modes (#1160) --- keywords.txt | 2 + src/protocols/SSTV/SSTV.cpp | 217 ++++++++++++++++++++++++------------ src/protocols/SSTV/SSTV.h | 20 ++-- 3 files changed, 158 insertions(+), 81 deletions(-) diff --git a/keywords.txt b/keywords.txt index dab4fb0515..44d2487f38 100644 --- a/keywords.txt +++ b/keywords.txt @@ -74,6 +74,8 @@ Wrasse KEYWORD1 PasokonP3 KEYWORD1 PasokonP5 KEYWORD1 PasokonP7 KEYWORD1 +Robot36 KEYWORD1 +Robot72 KEYWORD1 # Bell Modems Bell101 KEYWORD1 diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 9d31e59795..3f72a3b23c 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -8,13 +8,13 @@ const SSTVMode_t Scottie1 { .scanPixelLen = 432, .numTones = 7, .tones = { - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 } } }; @@ -25,13 +25,13 @@ const SSTVMode_t Scottie2 { .scanPixelLen = 275, .numTones = 7, .tones = { - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 } } }; @@ -42,13 +42,13 @@ const SSTVMode_t ScottieDX { .scanPixelLen = 1080, .numTones = 7, .tones = { - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 } } }; @@ -59,14 +59,14 @@ const SSTVMode_t Martin1 { .scanPixelLen = 458, .numTones = 8, .tones = { - { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } + { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } } }; @@ -77,14 +77,14 @@ const SSTVMode_t Martin2 { .scanPixelLen = 229, .numTones = 8, .tones = { - { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } + { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } } }; @@ -95,11 +95,11 @@ const SSTVMode_t Wrasse { .scanPixelLen = 734, .numTones = 5, .tones = { - { .type = tone_t::GENERIC, .len = 5523, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 500, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 5523, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 500, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 } } }; @@ -110,13 +110,13 @@ const SSTVMode_t PasokonP3 { .scanPixelLen = 208, .numTones = 7, .tones = { - { .type = tone_t::GENERIC, .len = 5208, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 5208, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 } } }; @@ -127,13 +127,13 @@ const SSTVMode_t PasokonP5 { .scanPixelLen = 312, .numTones = 7, .tones = { - { .type = tone_t::GENERIC, .len = 7813, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 7813, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 } } }; @@ -144,13 +144,48 @@ const SSTVMode_t PasokonP7 { .scanPixelLen = 417, .numTones = 7, .tones = { - { .type = tone_t::GENERIC, .len = 10417, .freq = 1200 }, - { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, - { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, - { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, - { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, - { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + { .type = tone_t::GENERIC, .len = 10417, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t Robot36 { + .visCode = RADIOLIB_SSTV_ROBOT_36, + .width = 320, + .height = 240, + .scanPixelLen = 275, // this is the Y-scan length, Cb/Cr are one half + .numTones = 6, + .tones = { + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 3000, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 4500, .freq = 1500 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1900 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, // on even lines, this is the Cr component + } +}; + +const SSTVMode_t Robot72 { + .visCode = RADIOLIB_SSTV_ROBOT_72, + .width = 320, + .height = 240, + .scanPixelLen = 431, // this is the Y-scan length, Cb/Cr are one half + .numTones = 9, + .tones = { + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 3000, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN_Y, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 4500, .freq = 1500 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1900 }, + { .type = tone_t::SCAN_RED_CR, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 4500, .freq = 2300 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE_CB, .len = 0, .freq = 0 }, } }; @@ -210,8 +245,8 @@ void SSTVClient::idle() { } void SSTVClient::sendHeader() { - // save first header flag for Scottie modes - firstLine = true; + // reset line counter + lineCount = 0; phyLayer->transmitDirect(); // send the first part of header (leader-break-leader) @@ -247,10 +282,8 @@ void SSTVClient::sendHeader() { } void SSTVClient::sendLine(const uint32_t* imgLine) { - // check first line flag in Scottie modes - if(firstLine && ((txMode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { - firstLine = false; - + // check first line in Scottie modes + if((lineCount == 0) && ((txMode.visCode == RADIOLIB_SSTV_SCOTTIE_1) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_2) || (txMode.visCode == RADIOLIB_SSTV_SCOTTIE_DX))) { // send start sync tone this->tone(RADIOLIB_SSTV_TONE_BREAK, 9000); } @@ -258,31 +291,67 @@ void SSTVClient::sendLine(const uint32_t* imgLine) { // send all tones in sequence for(uint8_t i = 0; i < txMode.numTones; i++) { if((txMode.tones[i].type == tone_t::GENERIC) && (txMode.tones[i].len > 0)) { + // Robot36 has different separator tones for even and odd lines + uint32_t freq = txMode.tones[i].freq; + if((txMode.visCode == RADIOLIB_SSTV_ROBOT_36) && (i == 3)) { + freq = (lineCount % 2) ? 2300 : txMode.tones[3].freq; + } + // sync/porch tones - this->tone(txMode.tones[i].freq, txMode.tones[i].len); + this->tone(freq, txMode.tones[i].len); + } else { // scan lines for(uint16_t j = 0; j < txMode.width; j++) { uint32_t color = imgLine[j]; + uint32_t len = txMode.scanPixelLen; + + // Robot modes work in YCbCr + if((txMode.visCode == RADIOLIB_SSTV_ROBOT_36) || (txMode.visCode == RADIOLIB_SSTV_ROBOT_72)) { + uint8_t r = (color & 0x00FF0000) >> 16; + uint8_t g = (color & 0x0000FF00) >> 8; + uint8_t b = (color & 0x000000FF); + uint8_t y = 16.0 + (0.003906 * ((65.738 * r) + (129.057 * g) + (25.064 * b))); + uint8_t cb = 128.0 + (0.003906 * ((-37.945 * r) + (-74.494 * g) + (112.439 * b))); + uint8_t cr = 128.0 + (0.003906 * ((112.439 * r) + (-94.154 * g) + (-18.285 * b))); + color = ((uint32_t)y << 8); + if(txMode.visCode == RADIOLIB_SSTV_ROBOT_36) { + // odd lines carry Cb, even lines carry Cr + color |= (lineCount % 2) ? cb : cr; + } else { + color |= ((uint32_t)cr << 16) | cb; + } + + } + switch(txMode.tones[i].type) { - case(tone_t::SCAN_RED): + case(tone_t::SCAN_RED_CR): color &= 0x00FF0000; color >>= 16; + if((txMode.visCode == RADIOLIB_SSTV_ROBOT_36) || (txMode.visCode == RADIOLIB_SSTV_ROBOT_72)) { + len /= 2; + } break; - case(tone_t::SCAN_GREEN): + case(tone_t::SCAN_GREEN_Y): color &= 0x0000FF00; color >>= 8; break; - case(tone_t::SCAN_BLUE): + case(tone_t::SCAN_BLUE_CB): color &= 0x000000FF; + if((txMode.visCode == RADIOLIB_SSTV_ROBOT_36) || (txMode.visCode == RADIOLIB_SSTV_ROBOT_72)) { + len /= 2; + } break; case(tone_t::GENERIC): break; } - this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), txMode.scanPixelLen); + this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), len); } } } + + // increment line counter (needed for Robot36 mode) + lineCount++; } uint16_t SSTVClient::getPictureHeight() const { diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index 7c0feacd2a..3ec493a4eb 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -21,6 +21,8 @@ #define RADIOLIB_SSTV_PASOKON_P3 113 #define RADIOLIB_SSTV_PASOKON_P5 114 #define RADIOLIB_SSTV_PASOKON_P7 115 +#define RADIOLIB_SSTV_ROBOT_36 8 +#define RADIOLIB_SSTV_ROBOT_72 12 // SSTV tones in Hz #define RADIOLIB_SSTV_TONE_LEADER 1900 @@ -46,9 +48,9 @@ struct tone_t { */ enum { GENERIC = 0, - SCAN_GREEN, - SCAN_BLUE, - SCAN_RED + SCAN_GREEN_Y, + SCAN_BLUE_CB, + SCAN_RED_CR } type; /*! @@ -96,7 +98,7 @@ struct SSTVMode_t { /*! \brief Sequence of tones in each transmission line. This is used to create the correct encoding sequence. */ - tone_t tones[8]; + tone_t tones[9]; }; // all currently supported SSTV modes @@ -109,6 +111,8 @@ extern const SSTVMode_t Wrasse; extern const SSTVMode_t PasokonP3; extern const SSTVMode_t PasokonP5; extern const SSTVMode_t PasokonP7; +extern const SSTVMode_t Robot36; +extern const SSTVMode_t Robot72; /*! \class SSTVClient @@ -136,7 +140,8 @@ class SSTVClient { \brief Initialization method for 2-FSK. \param base Base "0 Hz tone" RF frequency to be used in MHz. \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, - ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7, + Robot36 and Robot37. \returns \ref status_codes */ int16_t begin(float base, const SSTVMode_t& mode); @@ -145,7 +150,8 @@ class SSTVClient { /*! \brief Initialization method for AFSK. \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, - ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7, + Robot36 and Robot37. \returns \ref status_codes */ int16_t begin(const SSTVMode_t& mode); @@ -192,7 +198,7 @@ class SSTVClient { uint32_t baseFreq = 0; SSTVMode_t txMode = Scottie1; - bool firstLine = true; + uint32_t lineCount = 0; void tone(float freq, RadioLibTime_t len = 0); }; From fffb1fae9f6c43997c7ee0993e68ec7cd80ebb17 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 13 Jul 2024 16:42:46 +0100 Subject: [PATCH 1192/1848] [PHY] Make transmit data const (#1156) --- src/modules/CC1101/CC1101.cpp | 6 +++--- src/modules/CC1101/CC1101.h | 4 ++-- src/modules/LR11x0/LR11x0.cpp | 8 ++++---- src/modules/LR11x0/LR11x0.h | 4 ++-- src/modules/RF69/RF69.cpp | 6 +++--- src/modules/RF69/RF69.h | 4 ++-- src/modules/SX126x/SX126x.cpp | 7 +++---- src/modules/SX126x/SX126x.h | 4 ++-- src/modules/SX127x/SX127x.cpp | 6 +++--- src/modules/SX127x/SX127x.h | 4 ++-- src/modules/SX128x/SX128x.cpp | 8 ++++---- src/modules/SX128x/SX128x.h | 4 ++-- src/modules/Si443x/Si443x.cpp | 6 +++--- src/modules/Si443x/Si443x.h | 4 ++-- src/modules/nRF24/nRF24.cpp | 6 +++--- src/modules/nRF24/nRF24.h | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.h | 4 ++-- 18 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 7d08ac7a33..45a5558a2c 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -98,7 +98,7 @@ void CC1101::reset() { SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); } -int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5); @@ -289,7 +289,7 @@ void CC1101::clearGdo2Action() { this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio())); } -int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // check packet length if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); @@ -317,7 +317,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // fill the FIFO - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, len); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), len); // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_TX); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 55eb9a8433..cb5efe71e4 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -575,7 +575,7 @@ class CC1101: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -687,7 +687,7 @@ class CC1101: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 906c56c849..dff27cebf6 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -130,7 +130,7 @@ int16_t LR11x0::reset() { return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); @@ -363,7 +363,7 @@ void LR11x0::clearPacketSentAction() { this->clearIrqAction(); } -int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; @@ -401,12 +401,12 @@ int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) { if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { // in LR-FHSS mode, the packet is built by the device // TODO add configurable grid step and device offset - state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC, true, this->lrFhssBw, this->lrFhssHopSeq, 0, data, len); + state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC, true, this->lrFhssBw, this->lrFhssHopSeq, 0, const_cast(data), len); RADIOLIB_ASSERT(state); } else { // write packet to buffer - state = writeBuffer8(data, len); + state = writeBuffer8(const_cast(data), len); RADIOLIB_ASSERT(state); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index e00c6bf63e..9177569cc5 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -797,7 +797,7 @@ class LR11x0: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -911,7 +911,7 @@ class LR11x0: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 260962a5eb..d5a07c9e9d 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -98,7 +98,7 @@ void RF69::reset() { this->mod->hal->delay(10); } -int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t RF69::transmit(const uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5); @@ -380,7 +380,7 @@ bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { return(false); } -int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t RF69::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = setMode(RADIOLIB_RF69_STANDBY); RADIOLIB_ASSERT(state); @@ -413,7 +413,7 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { packetLen = RADIOLIB_RF69_FIFO_THRESH - 1; this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_TX_START_CONDITION_FIFO_NOT_EMPTY, 7, 7); } - this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, data, packetLen); + this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, const_cast(data), packetLen); // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should // just add a padding byte that can be dropped without consequence diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 7d77ef66b3..a7a25e4941 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -523,7 +523,7 @@ class RF69: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -685,7 +685,7 @@ class RF69: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 591346d49c..6b4cdda5bd 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -228,7 +228,7 @@ int16_t SX126x::reset(bool verify) { } } -int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); @@ -512,8 +512,7 @@ void SX126x::clearChannelScanAction() { this->clearDio1Action(); } - -int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; @@ -548,7 +547,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // write packet to buffer - state = writeBuffer(data, len); + state = writeBuffer(const_cast(data), len); RADIOLIB_ASSERT(state); // clear interrupt flags diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index f05e5d9a01..0fc9b6ac82 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -506,7 +506,7 @@ class SX126x: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -630,7 +630,7 @@ class SX126x: public PhysicalLayer { \param addr Address to send the data to. Will only be added if address filtering was enabled. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index d81671e838..010c209b8d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -141,7 +141,7 @@ int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqD return(state); } -int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); @@ -549,7 +549,7 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) return(false); } -int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); @@ -609,7 +609,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1; this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); } - this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, data, packetLen); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, const_cast(data), packetLen); // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_TX); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index a9711d8194..7e8d5e5a44 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -633,7 +633,7 @@ class SX127x: public PhysicalLayer { \param addr Node address to transmit the packet to. Only used in FSK mode. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Binary receive method. Will attempt to receive arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -797,7 +797,7 @@ class SX127x: public PhysicalLayer { \param addr Node address to transmit the packet to. Only used in FSK mode. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index f35ccc264e..8f41a7970f 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -301,7 +301,7 @@ int16_t SX128x::reset(bool verify) { } } -int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // check packet length if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); @@ -485,7 +485,7 @@ void SX128x::clearPacketSentAction() { this->clearDio1Action(); } -int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t SX128x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; @@ -519,10 +519,10 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // write packet to buffer if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { // first 2 bytes of BLE payload are PDU header - state = writeBuffer(data, len, 2); + state = writeBuffer(const_cast(data), len, 2); RADIOLIB_ASSERT(state); } else { - state = writeBuffer(data, len); + state = writeBuffer(const_cast(data), len); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index c93d79c4dc..6ce9164f64 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -426,7 +426,7 @@ class SX128x: public PhysicalLayer { \param addr Address to send the data to. Unsupported, compatibility only. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -530,7 +530,7 @@ class SX128x: public PhysicalLayer { \param addr Address to send the data to. Unsupported, compatibility only. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 7dfd8eb821..4ba1b21c35 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -71,7 +71,7 @@ void Si443x::reset() { this->mod->hal->delay(100); } -int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t Si443x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (5ms + 500 % of expected time-on-air) RadioLibTime_t timeout = 5 + (uint32_t)((((float)(len * 8)) / this->bitRate) * 5); @@ -226,7 +226,7 @@ void Si443x::clearPacketSentAction() { this->clearIrqAction(); } -int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t Si443x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // check packet length if(len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); @@ -252,7 +252,7 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { (void)addr; // write packet to FIFO - this->mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, data, len); + this->mod->SPIwriteRegisterBurst(RADIOLIB_SI443X_REG_FIFO_ACCESS, const_cast(data), len); // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_TX); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 24f8bb0673..c100b04e2d 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -591,7 +591,7 @@ class Si443x: public PhysicalLayer { \param addr Node address to transmit the packet to. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long. @@ -683,7 +683,7 @@ class Si443x: public PhysicalLayer { \param addr Node address to transmit the packet to. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Clean up after transmission is done. diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 09d8bf0914..deafef27ed 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -82,7 +82,7 @@ int16_t nRF24::standby(uint8_t mode) { return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_CONFIG, mode, 1, 1)); } -int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t nRF24::transmit(const uint8_t* data, size_t len, uint8_t addr) { // start transmission int16_t state = startTransmit(data, len, addr); RADIOLIB_ASSERT(state); @@ -175,7 +175,7 @@ void nRF24::clearPacketSentAction() { this->clearIrqAction(); } -int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t nRF24::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // suppress unused variable warning (void)addr; @@ -205,7 +205,7 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { uint8_t buff[32]; memset(buff, 0x00, 32); memcpy(buff, data, len); - SPIwriteTxPayload(data, len); + SPIwriteTxPayload(const_cast(data), len); // CE high to start transmitting this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 14d2620973..428df70f4b 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -238,7 +238,7 @@ class nRF24: public PhysicalLayer { \param addr Dummy address parameter, to ensure PhysicalLayer compatibility. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr) override; + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr) override; /*! \brief Blocking binary receive method. @@ -305,7 +305,7 @@ class nRF24: public PhysicalLayer { \param addr Dummy address parameter, to ensure PhysicalLayer compatibility. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr) override; + int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr) override; /*! \brief Clean up after transmission is done. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index f351cb471f..dc97908bcc 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -53,7 +53,7 @@ int16_t PhysicalLayer::transmit(const char* str, uint8_t addr) { return(transmit((uint8_t*)str, strlen(str), addr)); } -int16_t PhysicalLayer::transmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t PhysicalLayer::transmit(const uint8_t* data, size_t len, uint8_t addr) { (void)data; (void)len; (void)addr; @@ -150,7 +150,7 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { return(startTransmit((uint8_t*)str, strlen(str), addr)); } -int16_t PhysicalLayer::startTransmit(uint8_t* data, size_t len, uint8_t addr) { +int16_t PhysicalLayer::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { (void)data; (void)len; (void)addr; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index a32997d3f0..ad53f622b3 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -98,7 +98,7 @@ class PhysicalLayer { \param addr Node address to transmit the packet to. Only used in FSK mode. \returns \ref status_codes */ - virtual int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + virtual int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0); #if defined(RADIOLIB_BUILD_ARDUINO) /*! @@ -181,7 +181,7 @@ class PhysicalLayer { \param addr Node address to transmit the packet to. Only used in FSK mode. \returns \ref status_codes */ - virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + virtual int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0); /*! \brief Clean up after transmission is done. From 858bf6409e1fa67f7d776dd7828e68f17d37bbe2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 16 Jul 2024 21:10:47 +0200 Subject: [PATCH 1193/1848] [LR11x0] Fix SNR calculation (#1161) --- src/modules/LR11x0/LR11x0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index dff27cebf6..3a1ffa39d6 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2374,7 +2374,7 @@ int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signal // pass the replies if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; } - if(snrPkt) { *snrPkt = (float)buff[1] / 4.0f; } + if(snrPkt) { *snrPkt = (float)((int8_t)buff[1]) / 4.0f; } if(signalRssiPkt) { *signalRssiPkt = buff[2]; } return(state); From ceba2d9b3bc7ee8311dfaf987cf3270a5c559e9a Mon Sep 17 00:00:00 2001 From: Nate Welch Date: Thu, 18 Jul 2024 08:45:29 -0500 Subject: [PATCH 1194/1848] Update SX1278.cpp to fix errataFix typo The binary representations that were being written to register 0x31 were not setting the correct bit. In particular for the 500kHz bandwidth setting. Changed from 0b1000000 to 0b10000000 --- src/modules/SX127x/SX1278.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 78251d2456..2d44b99e88 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -639,49 +639,49 @@ void SX1278::errataFix(bool rx) { uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 }; float rxFreq = frequency; if(fabs(SX127x::bandwidth - 7.8) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x48; fixedRegs[2] = 0x00; rxFreq += 0.00781; } else if(fabs(SX127x::bandwidth - 10.4) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.01042; } else if(fabs(SX127x::bandwidth - 15.6) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.01562; } else if(fabs(SX127x::bandwidth - 20.8) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.02083; } else if(fabs(SX127x::bandwidth - 31.25) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.03125; } else if(fabs(SX127x::bandwidth - 41.7) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.04167; } else if(fabs(SX127x::bandwidth - 62.5) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; } else if(fabs(SX127x::bandwidth - 125.0) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; } else if(fabs(SX127x::bandwidth - 250.0) <= 0.001) { - fixedRegs[0] = 0b0000000; + fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; } else if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { - fixedRegs[0] = 0b1000000; + fixedRegs[0] = 0b10000000; fixedRegs[1] = mod->SPIreadRegister(0x2F); fixedRegs[2] = mod->SPIreadRegister(0x30); } else { From 3985c2edc460edc0a0b5218d8ed50bb3bfcbe5a4 Mon Sep 17 00:00:00 2001 From: Nate Welch Date: Thu, 18 Jul 2024 09:20:59 -0500 Subject: [PATCH 1195/1848] Update SX1278.cpp Turn on LnaBoost even in AutoAGC mode LnaBoost can still be enabled when the gain is not manually set. The Receiver Sensitivity ratings in the SX1276/7/8 datasheet are specified with the LnaBoost enabled. I tested this on a few boards here and on average get a 3dB increase in signal strength. This is comparable to the SX1262 "Boosted Gain" setting --- src/modules/SX127x/SX1278.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 78251d2456..0af0d9b20e 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -380,6 +380,7 @@ int16_t SX1278::setGain(uint8_t gain) { if(gain == 0) { // gain set to 0, enable AGC loop state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2); + state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, RADIOLIB_SX127X_LNA_BOOST_ON, 1, 0); } else { state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); From 15b8489f1dd148aec6342692b706ed3f8e71efde Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Jul 2024 17:16:53 +0200 Subject: [PATCH 1196/1848] [LR11x0] Cleanup, mark GNSS methods as work-in-progress --- src/modules/LR11x0/LR11x0.cpp | 162 ++++++++++++++++++++++++++++++---- src/modules/LR11x0/LR11x0.h | 57 ++++++++++-- 2 files changed, 194 insertions(+), 25 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 3a1ffa39d6..a20d04b936 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1660,13 +1660,42 @@ int16_t LR11x0::isGnssScanCapable() { // check the device firmware version is sufficient uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; + state = RADIOLIB_ERR_UNSUPPORTED; if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { - return(RADIOLIB_ERR_NONE); + state = RADIOLIB_ERR_NONE; } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { - return(RADIOLIB_ERR_NONE); + state = RADIOLIB_ERR_NONE; } + RADIOLIB_ASSERT(state); - return(RADIOLIB_ERR_UNSUPPORTED); + // in debug mode, dump the almanac + #if RADIOLIB_DEBUG_BASIC + uint32_t addr = 0; + uint16_t sz = 0; + state = this->gnssAlmanacReadAddrSize(&addr, &sz); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz); + uint32_t buff[32] = { 0 }; + while(sz > 0) { + size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); + state = this->readRegMem32(addr, buff, len); + RADIOLIB_ASSERT(state); + Module::hexdump(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr); + addr += len*sizeof(uint32_t); + sz -= len*sizeof(uint32_t); + } + + uint8_t almanac[22] = { 0 }; + for(uint8_t i = 0; i < 128; i++) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i); + state = this->gnssAlmanacReadSV(i, almanac); + RADIOLIB_ASSERT(state); + Module::hexdump(NULL, almanac, 22); + } + + #endif + + return(state); } int16_t LR11x0::gnssScan(uint16_t* resSize) { @@ -1681,7 +1710,7 @@ int16_t LR11x0::gnssScan(uint16_t* resSize) { state = this->gnssSetConstellationToUse(0x03); RADIOLIB_ASSERT(state); - // set scan mode + // set scan mode (single vs multiple) state = this->gnssSetMode(0x03); RADIOLIB_ASSERT(state); @@ -1732,12 +1761,43 @@ int16_t LR11x0::gnssScan(uint16_t* resSize) { } int16_t LR11x0::getGnssScanResult(uint16_t size) { + uint32_t timing[31] = { 0 }; + uint8_t constDemod = 0; + int16_t state = this->gnssReadCumulTiming(timing, &constDemod); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timing:"); + for(size_t i = 0; i < 31; i++) { + uint32_t t = (timing[i] * 1000UL) / 32768UL; + RADIOLIB_DEBUG_BASIC_PRINTLN(" %d: %lu ms", i*4, t); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("constDemod: %d", constDemod); + + uint8_t nbSv = 0; + state = this->gnssGetNbSvDetected(&nbSv); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Detected %d SVs:", nbSv); + + uint8_t svId[32] = { 0 }; + uint8_t snr[32] = { 0 }; + int16_t doppler[32] = { 0 }; + state = this->gnssGetSvDetected(svId, snr, doppler, nbSv); + RADIOLIB_ASSERT(state); + for(size_t i = 0; i < nbSv; i++) { + RADIOLIB_DEBUG_BASIC_PRINTLN(" SV %d: C/N0 %i dB, Doppler %i Hz", i, snr[i] + 31, doppler[i]); + } + + float lat = 0; + float lon = 0; + state = this->gnssReadAssistancePosition(&lat, &lon); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("lat = %.5f, lon = %.5f", lat, lon); + // read the result uint8_t res[256] = { 0 }; - int16_t state = this->gnssReadResults(res, size); + state = this->gnssReadResults(res, size); RADIOLIB_ASSERT(state); RADIOLIB_DEBUG_BASIC_PRINTLN("Result type: %02x", (int)res[0]); - //Module::hexdump(NULL, res, size); + Module::hexdump(NULL, res, size); return(state); } @@ -2836,6 +2896,15 @@ int16_t LR11x0::wifiReadVersion(uint8_t* major, uint8_t* minor) { return(state); } +int16_t LR11x0::gnssReadRssi(int8_t* rssi) { + uint8_t reqBuff[1] = { 0x09 }; // some undocumented magic byte, from the official driver + uint8_t rplBuff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + if(rssi) { *rssi = rplBuff[1]; } + return(state); +} + int16_t LR11x0::gnssSetConstellationToUse(uint8_t mask) { uint8_t buff[1] = { mask }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE, true, buff, sizeof(buff))); @@ -2866,6 +2935,18 @@ int16_t LR11x0::gnssReadAlmanacUpdate(uint8_t* mask) { return(state); } +int16_t LR11x0::gnssSetFreqSearchSpace(uint8_t freq) { + uint8_t buff[1] = { freq }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadFreqSearchSpace(uint8_t* freq) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE, false, buff, sizeof(buff)); + if(freq) { *freq = buff[0]; } + return(state); +} + int16_t LR11x0::gnssReadVersion(uint8_t* fw, uint8_t* almanac) { uint8_t buff[2] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION, false, buff, sizeof(buff)); @@ -2971,7 +3052,7 @@ int16_t LR11x0::gnssGetNbSvDetected(uint8_t* nbSv) { return(state); } -int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, uint16_t* doppler, size_t nbSv) { +int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, int16_t* doppler, size_t nbSv) { // TODO this is arbitrary - is there an actual maximum? if(nbSv > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t)) { return(RADIOLIB_ERR_SPI_CMD_INVALID); @@ -3044,7 +3125,24 @@ int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); } -int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { +int16_t LR11x0::gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size) { + uint8_t buff[6] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE, false, buff, sizeof(buff)); + + if(addr) { *addr = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + if(size) { *size = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + + return(state); +} + +int16_t LR11x0::gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac) { + uint8_t reqBuff[2] = { svId, 0x01 }; // in theory multiple SV entries can be read at the same time, but we don't need that + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE, false, almanac, 22, reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + return(state); +} + +int16_t LR11x0::gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; uint8_t reqBuff[9] = { @@ -3057,6 +3155,23 @@ int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t co return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); } +int16_t LR11x0::gnssGetSvVisible(uint8_t nbSv, uint8_t** svId, int16_t** doppler, int16_t** dopplerErr) { + // enforce a maximum of 12 SVs + if(nbSv > 12) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + uint8_t buff[60] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER, false, buff, sizeof(buff)); + for(uint8_t i = 0; i < nbSv; i++) { + if(svId && svId[i]) { *svId[i] = buff[i*12]; } + if(doppler && doppler[i]) { *doppler[i] = ((uint16_t)(buff[i*12 + 1]) << 8) | (uint16_t)buff[i*12 + 2]; } + if(dopplerErr && dopplerErr[i]) { *dopplerErr[i] = ((uint16_t)(buff[i*12 + 3]) << 8) | (uint16_t)buff[i*12 + 4]; } + } + + return(state); +} + int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { uint8_t buff[3] = { effort, resMask, nbSvMax }; // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts @@ -3099,6 +3214,14 @@ int16_t LR11x0::gnssResetPosition(void) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0)); } +int16_t LR11x0::gnssReadWeekNumberRollover(uint8_t* status, uint8_t* rollover) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER, false, buff, sizeof(buff)); + if(status) { *status = buff[0]; } + if(rollover) { *rollover = buff[1]; } + return(state); +} + int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) { uint8_t buff[2] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff)); @@ -3112,7 +3235,7 @@ int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) { int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) { uint8_t rplBuff[125] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, 125); + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING, false, rplBuff, 125); RADIOLIB_ASSERT(state); // convert endians @@ -3181,6 +3304,16 @@ int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, true, buff, sizeof(buff))); } +int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed) { + uint8_t reqBuff[1] = { mask }; + uint8_t rplBuff[5] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + if(nbSvVisible) { *nbSvVisible = rplBuff[0]; } + if(elapsed) { *elapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } + return(state); +} + int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) { // TODO parse the reply into some structure return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53)); @@ -3212,14 +3345,9 @@ int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSa return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff))); } -int16_t LR11x0::gnssReadWNRollover(uint8_t* status, uint8_t* rollover) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WN_ROLLOVER, false, buff, sizeof(buff)); - - if(status) { *status = buff[0]; } - if(rollover) { *rollover = buff[1]; } - - return(state); +int16_t LR11x0::gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList) { + uint8_t reqBuff[2] = { mask, nbSv }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC, false, syncList, nbSv, reqBuff, sizeof(reqBuff))); } int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 9177569cc5..5b16a7c0a3 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -103,10 +103,13 @@ #define RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS (0x030A) #define RADIOLIB_LR11X0_CMD_WIFI_CFG_TIMESTAMP_AP_PHONE (0x030B) #define RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION (0x0320) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI (0x0222) #define RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE (0x0400) #define RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE (0x0401) #define RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE (0x0402) #define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE (0x0403) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE (0x0404) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE (0x0405) #define RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION (0x0406) #define RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS (0x0407) #define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408) @@ -116,6 +119,7 @@ #define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C) #define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D) #define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE (0x040F) #define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410) #define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411) #define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414) @@ -124,24 +128,28 @@ #define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417) #define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418) #define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE (0x041A) #define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER (0x0420) #define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426) #define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432) #define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434) #define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435) #define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER (0x0438) #define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439) #define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A) #define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B) +#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x044D) #define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F) #define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453) -#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0455) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0454) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS (0x0456) #define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457) #define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463) #define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464) -#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x0465) #define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_WN_ROLLOVER (0x0467) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC (0x0466) #define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469) #define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472) #define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502) @@ -1358,14 +1366,39 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true); - + + /*! + \brief Method to check whether the device is capable of performing a GNSS scan. + CAUTION: Work in progress! Most data is returned via debug prints. + \returns \ref status_codes + */ int16_t isGnssScanCapable(); + /*! + \brief Performs GNSS scan. + CAUTION: Work in progress! Most data is returned via debug prints. + \param resSize Pointer to a variable in which the result size will be saved. + \returns \ref status_codes + */ int16_t gnssScan(uint16_t* resSize); + /*! + \brief Get GNSS scan result. + CAUTION: Work in progress! Most data is returned via debug prints. + \param size Result size to read. + \returns \ref status_codes + */ int16_t getGnssScanResult(uint16_t size); - int16_t getGnssPosition(float* lat, float* lon, bool filtered); + /*! + \brief Get GNSS position. + CAUTION: Work in progress! Most data is returned via debug prints. + \param lat Pointer to a variable where latitude in degrees will be saved. + \param lon Pointer to a variable where longitude in degrees will be saved. + \param filtered Whether to save the filtered, or unfiltered value. Defaults to true (filtered). + \returns \ref status_codes + */ + int16_t getGnssPosition(float* lat, float* lon, bool filtered = true); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -1467,10 +1500,13 @@ class LR11x0: public PhysicalLayer { int16_t wifiCfgTimestampAPphone(uint32_t timestamp); int16_t wifiReadVersion(uint8_t* major, uint8_t* minor); + int16_t gnssReadRssi(int8_t* rssi); int16_t gnssSetConstellationToUse(uint8_t mask); int16_t gnssReadConstellationToUse(uint8_t* mask); int16_t gnssSetAlmanacUpdate(uint8_t mask); int16_t gnssReadAlmanacUpdate(uint8_t* mask); + int16_t gnssSetFreqSearchSpace(uint8_t freq); + int16_t gnssReadFreqSearchSpace(uint8_t* freq); int16_t gnssReadVersion(uint8_t* fw, uint8_t* almanac); int16_t gnssReadSupportedConstellations(uint8_t* mask); int16_t gnssSetMode(uint8_t mode); @@ -1482,19 +1518,23 @@ class LR11x0: public PhysicalLayer { int16_t gnssPushDmMsg(uint8_t* payload, size_t len); int16_t gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace); int16_t gnssGetNbSvDetected(uint8_t* nbSv); - int16_t gnssGetSvDetected(uint8_t* svId, uint8_t* snr, uint16_t* doppler, size_t nbSv); + int16_t gnssGetSvDetected(uint8_t* svId, uint8_t* snr, int16_t* doppler, size_t nbSv); int16_t gnssGetConsumption(uint32_t* cpu, uint32_t* radio); int16_t gnssGetResultSize(uint16_t* size); int16_t gnssReadResults(uint8_t* result, uint16_t size); int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc); int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac); - int16_t gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); + int16_t gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size); + int16_t gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac); + int16_t gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); + int16_t gnssGetSvVisible(uint8_t nbSv, uint8_t** svId, int16_t** doppler, int16_t** dopplerErr); int16_t gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax); int16_t gnssReadLastScanModeLaunched(uint8_t* lastScanMode); int16_t gnssFetchTime(uint8_t effort, uint8_t opt); int16_t gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy); int16_t gnssResetTime(void); int16_t gnssResetPosition(void); + int16_t gnssReadWeekNumberRollover(uint8_t* status, uint8_t* rollover); int16_t gnssReadDemodStatus(int8_t* status, uint8_t* info); int16_t gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod); int16_t gnssSetTime(uint32_t time, uint16_t accuracy); @@ -1502,12 +1542,13 @@ class LR11x0: public PhysicalLayer { int16_t gnssReadDelayResetAP(uint32_t* delay); int16_t gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask); int16_t gnssReadAlmanacStatus(uint8_t* status); + int16_t gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed); int16_t gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period); int16_t gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period); int16_t gnssConfigDelayResetAP(uint32_t delay); int16_t gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat); - int16_t gnssReadWNRollover(uint8_t* status, uint8_t* rollover); int16_t gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed); + int16_t gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList); int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1); int16_t cryptoSetKey(uint8_t keyId, uint8_t* key); From 0a77cae0de786fa635e5984a605868d56f16b4ec Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Jul 2024 17:25:53 +0200 Subject: [PATCH 1197/1848] [LR11x0] Remove debug hexdump --- src/modules/LR11x0/LR11x0.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index a20d04b936..c416b2d64f 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1797,7 +1797,6 @@ int16_t LR11x0::getGnssScanResult(uint16_t size) { state = this->gnssReadResults(res, size); RADIOLIB_ASSERT(state); RADIOLIB_DEBUG_BASIC_PRINTLN("Result type: %02x", (int)res[0]); - Module::hexdump(NULL, res, size); return(state); } From 737e948efc8e4250c3ed6b38239e4ab532b9211e Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Jul 2024 17:32:46 +0200 Subject: [PATCH 1198/1848] [LR11x0] Fix printf types --- src/modules/LR11x0/LR11x0.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index c416b2d64f..d1e1c0aa34 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1768,7 +1768,7 @@ int16_t LR11x0::getGnssScanResult(uint16_t size) { RADIOLIB_DEBUG_BASIC_PRINTLN("Timing:"); for(size_t i = 0; i < 31; i++) { uint32_t t = (timing[i] * 1000UL) / 32768UL; - RADIOLIB_DEBUG_BASIC_PRINTLN(" %d: %lu ms", i*4, t); + RADIOLIB_DEBUG_BASIC_PRINTLN(" %d: %lu ms", (int)i*4, (unsigned long)t); } RADIOLIB_DEBUG_BASIC_PRINTLN("constDemod: %d", constDemod); @@ -1783,7 +1783,7 @@ int16_t LR11x0::getGnssScanResult(uint16_t size) { state = this->gnssGetSvDetected(svId, snr, doppler, nbSv); RADIOLIB_ASSERT(state); for(size_t i = 0; i < nbSv; i++) { - RADIOLIB_DEBUG_BASIC_PRINTLN(" SV %d: C/N0 %i dB, Doppler %i Hz", i, snr[i] + 31, doppler[i]); + RADIOLIB_DEBUG_BASIC_PRINTLN(" SV %d: C/N0 %i dB, Doppler %i Hz", (int)i, snr[i] + 31, doppler[i]); } float lat = 0; From 7c3ed88c0d7697654e9fd2ec41479d489f286bd7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Jul 2024 16:41:13 +0200 Subject: [PATCH 1199/1848] [SX126x] Clarify DIO3 for AFSK-based examples --- examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino | 2 +- examples/AFSK/AFSK_Tone/AFSK_Tone.ino | 2 +- examples/APRS/APRS_MicE/APRS_MicE.ino | 2 +- examples/APRS/APRS_Position/APRS_Position.ino | 2 +- examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino | 2 +- examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino | 2 +- examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino | 2 +- .../Hellschreiber_Transmit_AFSK.ino | 2 +- examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino | 2 +- examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino | 2 +- examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino | 2 +- src/modules/SX126x/SX126x.cpp | 4 ++-- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino index 0d905d6a75..5b19bedfb6 100644 --- a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino +++ b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -9,7 +9,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino index 3071caf16b..ad6738a108 100644 --- a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino +++ b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -10,7 +10,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/APRS/APRS_MicE/APRS_MicE.ino b/examples/APRS/APRS_MicE/APRS_MicE.ino index aec26ec9da..6500cac5b4 100644 --- a/examples/APRS/APRS_MicE/APRS_MicE.ino +++ b/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -16,7 +16,7 @@ - CC1101 - nRF24 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index 06759f3920..5b237af7a7 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -16,7 +16,7 @@ - CC1101 - nRF24 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino index fb26775ae7..2b27bdc6c3 100644 --- a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino +++ b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -13,7 +13,7 @@ - CC1101 - nRF24 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino index ec1b08f40b..4b0e600eb1 100644 --- a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino +++ b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino @@ -33,7 +33,7 @@ SX1278 radio = new Module(10, 2, 9, 3); // SX1231: DIO2 // CC1101: GDO2 // Si443x/RFM2x: GPIO -// SX126x/LLCC68: DIO2 (only devices without TCXO!) +// SX126x/LLCC68: DIO2 BellClient bell(&radio, 5); void setup() { diff --git a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino index f8c542fe56..c31877b409 100644 --- a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino +++ b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -13,7 +13,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino index f6d5992c07..77feff0d16 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -12,7 +12,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino index 1de8baa8b8..de955cc624 100644 --- a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino +++ b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -12,7 +12,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino index 70a798f3dc..cbeb0fe157 100644 --- a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -10,7 +10,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 For default module settings, see the wiki page https://github.com/jgromes/RadioLib/wiki/Default-configuration diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino index 5ec48a5a0c..85fe8de571 100644 --- a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -12,7 +12,7 @@ - SX1231 - CC1101 - Si443x/RFM2x - - SX126x/LLCC68 (only devices without TCXO!) + - SX126x/LLCC68 NOTE: Some platforms (such as Arduino Uno) might not be fast enough to correctly diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6b4cdda5bd..ceaccf2946 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -345,8 +345,8 @@ int16_t SX126x::transmitDirect(uint32_t frf) { } RADIOLIB_ASSERT(state); - // start transmitting - uint8_t data[] = {RADIOLIB_SX126X_CMD_NOP}; + // direct mode activation intentionally skipped here, as it seems to lead to much worse results + uint8_t data[] = { RADIOLIB_SX126X_CMD_NOP }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); } From a6c9d0037a6dbe2a56740e81e9a4a7e7de8824f2 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 21 Jul 2024 21:37:01 +0200 Subject: [PATCH 1200/1848] [LoRaWAN] Collection of fixes - Fix v1.0.4 MAC-in-payload decryption - Don't process 0MHz frequencies from CFList - Fix downlink-event datarate not showing correctly after ADR request - Convert getDevAddr to uint32_t - Backend: improve MAC Queue<>Buffer processing --- examples/NonArduino/Tock/libtock-c | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 234 +++++++++++++++-------------- src/protocols/LoRaWAN/LoRaWAN.h | 14 +- 3 files changed, 135 insertions(+), 114 deletions(-) create mode 160000 examples/NonArduino/Tock/libtock-c diff --git a/examples/NonArduino/Tock/libtock-c b/examples/NonArduino/Tock/libtock-c new file mode 160000 index 0000000000..1c1f4c0810 --- /dev/null +++ b/examples/NonArduino/Tock/libtock-c @@ -0,0 +1 @@ +Subproject commit 1c1f4c0810aa0fbd50aa91a11aaa7c05d2abb1bc diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 4fc5d3725a..e0a750a387 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -692,13 +692,14 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { this->setupChannelsDyn(false); } - // process CFlist if present - if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { + + // process CFlist if present (and if CFListType matches used band type) + if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN && joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS] == this->band->bandType) { uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); this->processCFList(cfList); } - // if no CFList was received, default or subband are already setup so don't need to do anything else + // if no (valid) CFList was received, default or subband are already setup so don't need to do anything else // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; @@ -1063,27 +1064,12 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon if(fOptsLen > 0) { // assume maximum possible buffer size uint8_t fOptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; - uint8_t* fOptsPtr = fOptsBuff; - // append all MAC replies into fOpts buffer - int16_t i = 0; - for (; i < this->commandsUp.numCommands; i++) { - LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; - memcpy(fOptsPtr, &cmd, 1 + cmd.len); - fOptsPtr += cmd.len + 1; - } + this->macQueueToBuff(&(this->commandsUp), fOptsBuff); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsLen); - // pop the commands from back to front - for (; i >= 0; i--) { - if(this->commandsUp.commands[i].repeat > 0) { - this->commandsUp.commands[i].repeat--; - } else { - deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); - } - } - uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen); uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= fOptsLen; @@ -1109,6 +1095,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon // encrypt the frame payload processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); + // perform CSMA if enabled (do it now already, because MIC calculation depends on this) + if (enableCSMA) { + performCSMA(); + } + // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; @@ -1126,7 +1117,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %lu) decoded:", (unsigned long)this->fCntUp); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); // calculate authentication codes @@ -1143,11 +1133,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isCon LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } - // perform CSMA if enabled. - if (enableCSMA) { - performCSMA(); - } - // send it (without the MIC calculation blocks) state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); @@ -1278,6 +1263,7 @@ int16_t LoRaWANNode::downlinkCommon() { while(!downlinkAction) { mod->hal->yield(); // this should never happen, but if it does this would be an infinite loop + // TODO scale this value using expected ToA of maximum allowed payload length if(mod->hal->millis() - now > 3000UL) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink missing!"); downlinkComplete = false; @@ -1498,6 +1484,18 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) this->confFCntDown = this->aFCntDown; isConfirmedDown = true; } + + // pass the extra info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; + event->confirmed = isConfirmedDown; + event->confirming = isConfirmingUp; + event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; + event->freq = currentChannels[event->dir].freq; + event->power = this->txPowerMax - this->txPowerSteps * 2; + event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; + event->fPort = fPort; + } // process FOpts (if there are any) if(fOptsLen > 0) { @@ -1508,10 +1506,13 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; #endif - // TODO it COULD be the case that the assumed FCnt rollover is incorrect, if possible figure out a way to catch this and retry with just fCnt16 - // if there are <= 15 bytes of FOpts, they are in the FHDR, otherwise they are in the payload - // in case of the latter, process AES is if it were a normal payload but using the NwkSEncKey - if(fOptsLen <= RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK) { + // it COULD be the case that the assumed FCnt rollover is incorrect, in which case the following MAC decryption fails... + + if(payLen > 0 && fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + // if the MAC payload is in the payload, process AES is if it were a normal payload but using the NwkSEncKey instead + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + } else { + // if the MAC payload is piggybacked in the FHDR fields, the decryption depends on the LoRaWAN version. if(this->rev == 1) { // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata @@ -1520,53 +1521,27 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen); } - } else { - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); } - bool hasADR = false; - uint8_t numADR = 0; - uint8_t lastCID = 0; - - // process the MAC command(s) - int8_t remLen = fOptsLen; - uint8_t* fOptsPtrDn = fOpts; - while(remLen > 0) { - uint8_t cid = *fOptsPtrDn; - uint8_t macLen = getMacPayloadLength(cid); - if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { - // if there was an earlier ADR command but it was not the last, ignore it - if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); - remLen -= (macLen + 1); - fOptsPtrDn += (macLen + 1); - lastCID = cid; - continue; - } - // otherwise, set ADR flag to true and increase counter - hasADR = true; - numADR++; - } - if(macLen + 1 > remLen) - break; - LoRaWANMacCommand_t cmd = { - .cid = cid, - .payload = { 0 }, - .len = macLen, - .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), - }; - memcpy(cmd.payload, fOptsPtrDn + 1, macLen); - - // process the MAC command - bool sendUp = execMacCommand(&cmd); + // parse the fOpts into the MAC queue + this->macBufftoQueue(&(this->commandsDown), fOpts, fOptsLen); + + // process the MAC queue commands (any response is modified in-place) + int16_t i = 0; + for(; i < this->commandsDown.numCommands; i++) { + bool sendUp = execMacCommand(&(this->commandsDown.commands[i])); if(sendUp) { - pushMacCommand(&cmd, &this->commandsUp); + pushMacCommand(&(this->commandsDown.commands[i]), &(this->commandsUp)); } + } - // processing succeeded, move in the buffer to the next command - remLen -= (macLen + 1); - fOptsPtrDn += (macLen + 1); - lastCID = cid; + // pop the commands from back to front + for (; i >= 0; i--) { + if(this->commandsDown.commands[i].repeat > 0) { + this->commandsDown.commands[i].repeat--; + } else { + deleteMacCommand(this->commandsDown.commands[i].cid, &(this->commandsDown)); + } } #if !RADIOLIB_STATIC_ONLY @@ -1581,26 +1556,12 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) #else uint8_t* fOptsBuff = new uint8_t[fOptsBufSize]; #endif - uint8_t* fOptsPtrUp = fOptsBuff; - // append all MAC replies into fOpts buffer - int16_t i = 0; - for (; i < this->commandsUp.numCommands; i++) { - LoRaWANMacCommand_t cmd = this->commandsUp.commands[i]; - memcpy(fOptsPtrUp, &cmd, 1 + cmd.len); - fOptsPtrUp += cmd.len + 1; - } + + this->macQueueToBuff(&(this->commandsUp), fOptsBuff); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsBufSize); - // pop the commands from back to front - for (; i >= 0; i--) { - if(this->commandsUp.commands[i].repeat > 0) { - this->commandsUp.commands[i].repeat--; - } else { - deleteMacCommand(this->commandsUp.commands[i].cid, &this->commandsUp); - } - } - this->isMACPayload = true; // temporarily lift dutyCycle restrictions to allow immediate MAC response bool prevDC = this->dutyCycleEnabled; @@ -1634,18 +1595,6 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) // a downlink was received, so reset the ADR counter to the last uplink's fCnt this->adrFCnt = this->getFCntUp(); - // pass the extra info if requested - if(event) { - event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; - event->confirmed = isConfirmedDown; - event->confirming = isConfirmingUp; - event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; - event->freq = currentChannels[event->dir].freq; - event->power = this->txPowerMax - this->txPowerSteps * 2; - event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; - event->fPort = fPort; - } - // if MAC-only payload, return now if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { // no payload @@ -1939,9 +1888,16 @@ int16_t LoRaWANNode::processCFList(uint8_t* cfList) { .len = 0, .repeat = 0, }; + + uint8_t freqZero[3] = { 0 }; + // datarate range for all new channels is equal to the default channels cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; for(uint8_t i = 0; i < 5; i++, num++) { + // if the frequency fields are all zero, there are no more channels in the CFList + if(memcmp(&cfList[i*3], freqZero, 3) == 0) { + break; + } cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; cmd.payload[0] = num; memcpy(&cmd.payload[1], &cfList[i*3], 3); @@ -2247,6 +2203,70 @@ int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { return(true); } +void LoRaWANNode::macQueueToBuff(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer) { + // append all MAC replies into fOpts buffer + uint8_t* fOptsPtr = buffer; + int16_t i = 0; + for (; i < queue->numCommands; i++) { + LoRaWANMacCommand_t cmd = queue->commands[i]; + memcpy(fOptsPtr, &cmd, 1 + cmd.len); + fOptsPtr += cmd.len + 1; + } + + // pop the commands from back to front + for (; i >= 0; i--) { + if(queue->commands[i].repeat > 0) { + queue->commands[i].repeat--; + } else { + deleteMacCommand(queue->commands[i].cid, queue); + } + } + +} + +void LoRaWANNode::macBufftoQueue(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer, uint8_t len) { + bool hasADR = false; + uint8_t numADR = 0; + uint8_t lastCID = 0; + + // process the MAC command(s) + int8_t remLen = len; + uint8_t* fOptsPtr = buffer; + while(remLen > 0) { + uint8_t cid = *fOptsPtr; + uint8_t macLen = getMacPayloadLength(cid); + if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + // if there was an earlier ADR command but it was not the last, ignore it + if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); + remLen -= (macLen + 1); + fOptsPtr += (macLen + 1); + lastCID = cid; + continue; + } + // otherwise, set ADR flag to true and increase counter + hasADR = true; + numADR++; + } + if(macLen + 1 > remLen) + break; + LoRaWANMacCommand_t cmd = { + .cid = cid, + .payload = { 0 }, + .len = macLen, + .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), + }; + memcpy(cmd.payload, fOptsPtr + 1, macLen); + pushMacCommand(&cmd, queue); + + // move in the buffer to the next command + remLen -= (macLen + 1); + fOptsPtr += (macLen + 1); + lastCID = cid; + } + +} + int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); @@ -2304,11 +2324,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); - // delete any existing response (does nothing if there is none) - deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_CHECK, &this->commandsDown); + cmd->repeat = 255; // prevent the command from being deleted by setting repeat to maximum - // insert response into MAC downlink queue - pushMacCommand(cmd, &this->commandsDown); return(false); } break; @@ -2659,11 +2676,8 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); - // delete any existing response (does nothing if there is none) - deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown); + cmd->repeat = 255; // prevent the command from being deleted by setting repeat to maximum - // insert response into MAC downlink queue - pushMacCommand(cmd, &this->commandsDown); return(false); } break; @@ -2921,7 +2935,7 @@ int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, return(RADIOLIB_ERR_NONE); } -uint64_t LoRaWANNode::getDevAddr() { +uint32_t LoRaWANNode::getDevAddr() { return(this->devAddr); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 062d9a7ed5..5c2bbee97e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -855,13 +855,13 @@ class LoRaWANNode { /*! \brief Returns the DevAddr of the device, regardless of OTAA or ABP mode - \returns 8-byte DevAddr + \returns 4-byte DevAddr */ - uint64_t getDevAddr(); + uint32_t getDevAddr(); /*! - \brief Get the Time-on-air of the last uplink message. - \returns (RadioLibTime_t) time-on-air (ToA) of last uplink message. + \brief Get the Time-on-air of the last uplink message (in milliseconds). + \returns (RadioLibTime_t) time-on-air (ToA) of last uplink message (in milliseconds). */ RadioLibTime_t getLastToA(); @@ -1060,6 +1060,12 @@ class LoRaWANNode { // restore all available channels from persistent storage int16_t restoreChannels(); + // parse a MAC command queue into a buffer (uplinks) + void macQueueToBuff(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer); + + // parse a MAC buffer into a command queue (downlinks) + void macBufftoQueue(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer, uint8_t len); + // push MAC command to queue, done by copy int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); From 9195dbabdaf20791d2097ce89e576e577d908932 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sun, 21 Jul 2024 22:39:28 +0200 Subject: [PATCH 1201/1848] [LoRaWAN] Fix downlink user-MAC commands piling up --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e0a750a387..90325ecf53 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1497,6 +1497,9 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) event->fPort = fPort; } + // clear the previous MAC commands, if any + memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); + // process FOpts (if there are any) if(fOptsLen > 0) { // there are some Fopts, decrypt them From 6fdaef0953720249187f86b1d654e83fdcceb2ff Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 22 Jul 2024 21:29:54 +0200 Subject: [PATCH 1202/1848] Revert libtock being included --- examples/NonArduino/Tock/libtock-c | 1 - 1 file changed, 1 deletion(-) delete mode 160000 examples/NonArduino/Tock/libtock-c diff --git a/examples/NonArduino/Tock/libtock-c b/examples/NonArduino/Tock/libtock-c deleted file mode 160000 index 1c1f4c0810..0000000000 --- a/examples/NonArduino/Tock/libtock-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1c1f4c0810aa0fbd50aa91a11aaa7c05d2abb1bc From 39bfa5151870f5631fae32cbdeeaaac38abcd2e9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 Aug 2024 16:33:23 +0200 Subject: [PATCH 1203/1848] Added verbose assert --- src/BuildOpt.h | 14 ++++++++++++++ src/BuildOptUser.h | 1 + 2 files changed, 15 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 9e905aabc4..4b75f7b04c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -22,6 +22,9 @@ #if !defined(RADIOLIB_DEBUG_SPI) #define RADIOLIB_DEBUG_SPI (0) #endif +#if !defined(RADIOLIB_VERBOSE_ASSERT) + #define RADIOLIB_VERBOSE_ASSERT (0) +#endif // set which output port should be used for debug output // may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) @@ -453,6 +456,11 @@ #define RADIOLIB_EXCLUDE_STM32WLX (1) #endif +// if verbose assert is enabled, enable basic debug too +#if RADIOLIB_VERBOSE_ASSERT + #define RADIOLIB_DEBUG (1) +#endif + // set the global debug mode flag #if RADIOLIB_DEBUG_BASIC || RADIOLIB_DEBUG_PROTOCOL || RADIOLIB_DEBUG_SPI #define RADIOLIB_DEBUG (1) @@ -545,8 +553,14 @@ /*! \brief A simple assert macro, will return on error. + If RADIOLIB_VERBOSE_ASSERT is enabled, the macro will also print out file and line number trace, + at a significant program storage cost. */ +#if RADIOLIB_VERBOSE_ASSERT +#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { RADIOLIB_DEBUG_BASIC_PRINTLN("%d at %s:%d", STATEVAR, __FILE__, __LINE__); return(STATEVAR); } } +#else #define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } } +#endif /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled diff --git a/src/BuildOptUser.h b/src/BuildOptUser.h index d81104d7d2..562919ee16 100644 --- a/src/BuildOptUser.h +++ b/src/BuildOptUser.h @@ -8,5 +8,6 @@ //#define RADIOLIB_DEBUG_BASIC (1) // basic debugging (e.g. reporting GPIO timeouts or module not being found) //#define RADIOLIB_DEBUG_PROTOCOL (1) // protocol information (e.g. LoRaWAN internal information) //#define RADIOLIB_DEBUG_SPI (1) // verbose transcription of all SPI communication - produces large debug logs! +//#define RADIOLIB_VERBOSE_ASSERT (1) // verbose assertions - will print out print out file and line number on failure #endif From 4e274fab0740ca315c75b653a06d3932e4a2dbe2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 Aug 2024 21:41:10 +0200 Subject: [PATCH 1204/1848] Fix typo in comment --- src/BuildOptUser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOptUser.h b/src/BuildOptUser.h index 562919ee16..54f16d808f 100644 --- a/src/BuildOptUser.h +++ b/src/BuildOptUser.h @@ -8,6 +8,6 @@ //#define RADIOLIB_DEBUG_BASIC (1) // basic debugging (e.g. reporting GPIO timeouts or module not being found) //#define RADIOLIB_DEBUG_PROTOCOL (1) // protocol information (e.g. LoRaWAN internal information) //#define RADIOLIB_DEBUG_SPI (1) // verbose transcription of all SPI communication - produces large debug logs! -//#define RADIOLIB_VERBOSE_ASSERT (1) // verbose assertions - will print out print out file and line number on failure +//#define RADIOLIB_VERBOSE_ASSERT (1) // verbose assertions - will print out file and line number on failure #endif From 908e297d60bb5fef796a0600222533c011f64301 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 5 Aug 2024 21:03:39 +0200 Subject: [PATCH 1205/1848] [LR11x0] Added register to set LNA mode --- src/modules/LR11x0/LR11x0.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 5b16a7c0a3..741e86230b 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -176,6 +176,7 @@ // LR11X0 register map #define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414) #define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054) +#define RADIOLIB_LR11X0_REG_LNA_MODE (0x00F3008C) // TODO add fix for br 600/1200 bps // LR11X0 SPI command variables @@ -580,6 +581,11 @@ // RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX #define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata +// RADIOLIB_LR11X0_REG_LNA_MODE +#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_N (0x01UL << 4) // 7 4 LNA mode: single-ended RFI_N +#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_P (0x02UL << 4) // 7 4 single-ended RFI_P +#define RADIOLIB_LR11X0_LNA_MODE_DIFFERENTIAL (0x03UL << 4) // 7 4 differential (default) + /*! \struct LR11x0WifiResult_t \brief Structure to save result of passive WiFi scan. From d95e5e39e81682daf192ed441747729ae843c448 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 5 Aug 2024 21:06:35 +0200 Subject: [PATCH 1206/1848] [MOD] Added missing Doxygen parameter --- src/Module.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Module.h b/src/Module.h index 0cae41140b..e6e4acafe0 100644 --- a/src/Module.h +++ b/src/Module.h @@ -519,6 +519,7 @@ class Module { \param level RadioLib debug level, set to NULL to not print. \param data Data to dump. \param len Number of bytes to dump. + \param offset Address offset to add when printing the data. \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). \param be Print multi-byte data as big endian. Defaults to false. */ From 079874345b7e95d9b2fed462d50a720117c45e55 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 5 Aug 2024 21:08:35 +0200 Subject: [PATCH 1207/1848] [FEC] Move generically useful macros --- src/protocols/AX25/AX25.h | 7 +------ src/utils/FEC.h | 9 ++++++++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 3f2583205a..c7678a3a27 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -9,12 +9,7 @@ #include "../AFSK/AFSK.h" #include "../BellModem/BellModem.h" #include "../../utils/CRC.h" - -// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html -#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) -#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) ) -#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) -#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) +#include "../../utils/FEC.h" // maximum callsign length in bytes #define RADIOLIB_AX25_MAX_CALLSIGN_LEN 6 diff --git a/src/utils/FEC.h b/src/utils/FEC.h index 30ba17ef92..a33ff61f8f 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -71,4 +71,11 @@ class RadioLibBCH { // the global singleton extern RadioLibBCH RadioLibBCHInstance; -#endif \ No newline at end of file +// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html +#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) +#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) ) +#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) +#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) + + +#endif From 701c6f8e46c12d024b31b7ea66f5de04c6af4afc Mon Sep 17 00:00:00 2001 From: Maik Menz Date: Fri, 9 Aug 2024 19:19:33 +0200 Subject: [PATCH 1208/1848] SX127x: Set FIFO read pointer to the start of the current packet --- src/modules/SX127x/SX127x.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 010c209b8d..eaa8c46f69 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -658,6 +658,12 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // CRC is disabled according to packet header and enabled according to user // most likely damaged packet header state = RADIOLIB_ERR_LORA_HEADER_DAMAGED; + } else { + // set FIFO read pointer to the start of the current packet + state = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR); + if (state >= 0) { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, state); + } } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { From 141bdd09980811cab818433167e02682ec9c682b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 9 Aug 2024 21:25:39 +0200 Subject: [PATCH 1209/1848] [MOD] Make hexdump format match xxd --- src/Module.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 72d5ba59c2..7b78f3f13c 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -472,7 +472,7 @@ void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offs size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { char str[120]; - sprintf(str, "%07" PRIx32 " ", (uint32_t)i+offset); + sprintf(str, "%08" PRIx32 ": ", (uint32_t)i+offset); size_t line_len = 16; if(rem_len < line_len) { line_len = rem_len; @@ -485,21 +485,21 @@ void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offs step *= -1; } for(int32_t k = width - 1; k >= -width + 1; k+=step) { - sprintf(&str[8 + (j+m)*3], "%02x ", data[i+j+k+m]); + sprintf(&str[10 + (j+m)*3], "%02x ", data[i+j+k+m]); m++; } } else { - sprintf(&str[8 + (j)*3], "%02x ", data[i+j]); + sprintf(&str[10 + (j)*3], "%02x ", data[i+j]); } } for(size_t j = line_len; j < 16; j++) { - sprintf(&str[8 + j*3], " "); + sprintf(&str[10 + j*3], " "); } - str[56] = '|'; - str[57] = ' '; + //str[56] = '|'; + str[58] = ' '; // at this point we need to start escaping "%" characters - char* strPtr = &str[58]; + char* strPtr = &str[59]; for(size_t j = 0; j < line_len; j++) { char c = data[i+j]; if((c < ' ') || (c > '~')) { From 0620d8eddaa7876278d7ad4131b8b09989746327 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 10 Aug 2024 12:54:39 +0200 Subject: [PATCH 1210/1848] [SX126x] Start reading from Rx buffer offset Remove setting RxBaseAddr to 0 --- src/modules/SX126x/SX126x.cpp | 23 ++++++++++++++--------- src/modules/SX126x/SX126x.h | 8 ++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ceaccf2946..6bf3fc1c0c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -709,20 +709,17 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || (irq & RADIOLIB_SX126X_IRQ_HEADER_ERR)) { crcState = RADIOLIB_ERR_CRC_MISMATCH; } - - // get packet length - size_t length = getPacketLength(); + + // get packet length and Rx buffer offset + uint8_t offset = 0; + size_t length = getPacketLength(true, &offset); if((len != 0) && (len < length)) { // user requested less data than we got, only return what was requested length = len; } - // read packet data - state = readBuffer(data, length); - RADIOLIB_ASSERT(state); - - // reset the base addresses - state = setBufferBaseAddress(); + // read packet data starting at offset + state = readBuffer(data, length, offset); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -1395,6 +1392,11 @@ float SX126x::getFrequencyError() { size_t SX126x::getPacketLength(bool update) { (void)update; + return(this->getPacketLength(update, NULL)); +} + +size_t SX126x::getPacketLength(bool update, uint8_t* offset) { + (void)update; // in implicit mode, return the cached value if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) { @@ -1403,6 +1405,9 @@ size_t SX126x::getPacketLength(bool update) { uint8_t rxBufStatus[2] = {0, 0}; this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + + if(offset) { *offset = rxBufStatus[1]; } + return((size_t)rxBufStatus[0]); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 0fc9b6ac82..631695191b 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -952,6 +952,14 @@ class SX126x: public PhysicalLayer { */ size_t getPacketLength(bool update = true) override; + /*! + \brief Query modem for the packet length of received payload and Rx buffer offset. + \param update Update received packet length. Will return cached value when set to false. + \param offset Pointer to variable to store the Rx buffer offset. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update, uint8_t* offset); + /*! \brief Set modem in fixed packet length mode. Available in FSK mode only. \param len Packet length. From 5f6f6f9a3c894198e3c475cef1ff100748491616 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 10 Aug 2024 12:54:58 +0200 Subject: [PATCH 1211/1848] [SX128x] Start reading from Rx buffer offset --- src/modules/SX128x/SX128x.cpp | 21 +++++++++++++++------ src/modules/SX128x/SX128x.h | 10 +++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 8f41a7970f..aa8ec58cd5 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -617,15 +617,16 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { crcState = RADIOLIB_ERR_CRC_MISMATCH; } - // get packet length - size_t length = getPacketLength(); + // get packet length and Rx buffer offset + uint8_t offset = 0; + size_t length = getPacketLength(true, &offset); if((len != 0) && (len < length)) { // user requested less data than we got, only return what was requested length = len; } - // read packet data - state = readBuffer(data, length); + // read packet data starting at offset + state = readBuffer(data, length, offset); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -1254,6 +1255,11 @@ float SX128x::getFrequencyError() { size_t SX128x::getPacketLength(bool update) { (void)update; + return(this->getPacketLength(update, NULL)); +} + +size_t SX128x::getPacketLength(bool update, uint8_t* offset) { + (void)update; // in implicit mode, return the cached value if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) { @@ -1262,6 +1268,9 @@ size_t SX128x::getPacketLength(bool update) { uint8_t rxBufStatus[2] = {0, 0}; this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + + if(offset) { *offset = rxBufStatus[1]; } + return((size_t)rxBufStatus[0]); } @@ -1412,8 +1421,8 @@ int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); } -int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, RADIOLIB_SX128X_CMD_NOP }; +int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset }; return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 6ce9164f64..8c0d465a10 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -745,6 +745,14 @@ class SX128x: public PhysicalLayer { */ size_t getPacketLength(bool update = true) override; + /*! + \brief Query modem for the packet length of received payload and Rx buffer offset. + \param update Update received packet length. Will return cached value when set to false. + \param offset Pointer to variable to store the Rx buffer offset. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update, uint8_t* offset); + /*! \brief Get expected time-on-air for a given size of payload. \param len Payload length in bytes. @@ -820,7 +828,7 @@ class SX128x: public PhysicalLayer { int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); - int16_t readBuffer(uint8_t* data, uint8_t numBytes); + int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); int16_t setCad(); From 8b5d7051749ee5cad2130139e1a187ae153e5f7d Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 10 Aug 2024 18:40:09 +0200 Subject: [PATCH 1212/1848] [SX126x] Remove unnecessary `(void)update;` --- src/modules/SX126x/SX126x.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6bf3fc1c0c..b98fad5963 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1391,7 +1391,6 @@ float SX126x::getFrequencyError() { } size_t SX126x::getPacketLength(bool update) { - (void)update; return(this->getPacketLength(update, NULL)); } From ddaf1ffd5251c73d6c4019c5ef440ee7f1d7ab85 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 10 Aug 2024 18:40:19 +0200 Subject: [PATCH 1213/1848] [SX128x] Remove unnecessary `(void)update;` --- src/modules/SX128x/SX128x.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index aa8ec58cd5..3d17e029df 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1254,7 +1254,6 @@ float SX128x::getFrequencyError() { } size_t SX128x::getPacketLength(bool update) { - (void)update; return(this->getPacketLength(update, NULL)); } From 19ec9da281bb68437544899dbd6b0bd42684fc43 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 16 Aug 2024 00:03:55 +0200 Subject: [PATCH 1214/1848] [PHY] Generalize IRQ checks --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 3 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 35 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index dc97908bcc..02fc12c5b5 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -316,7 +316,8 @@ int16_t PhysicalLayer::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) return(RADIOLIB_ERR_UNSUPPORTED); } -bool PhysicalLayer::isRxTimeout() { +bool PhysicalLayer::isIrqSet(uint8_t irq) { + (void)irq; return(false); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index ad53f622b3..b6165647b0 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -4,6 +4,20 @@ #include "../../TypeDef.h" #include "../../Module.h" +// common IRQ flags +#define RADIOLIB_IRQ_TX_DONE 0x00 +#define RADIOLIB_IRQ_RX_DONE 0x01 +#define RADIOLIB_IRQ_PREAMBLE_DETECTED 0x02 +#define RADIOLIB_IRQ_SYNC_WORD_VALID 0x03 +#define RADIOLIB_IRQ_SYNC_WORD_ERROR 0x04 +#define RADIOLIB_IRQ_HEADER_VALID 0x05 +#define RADIOLIB_IRQ_HEADER_ERR 0x06 +#define RADIOLIB_IRQ_CRC_ERR 0x07 +#define RADIOLIB_IRQ_CAD_DONE 0x08 +#define RADIOLIB_IRQ_CAD_DETECTED 0x09 +#define RADIOLIB_IRQ_TIMEOUT 0x0A +#define RADIOLIB_IRQ_LR_FHSS_HOP 0x0B + /*! \struct LoRaRate_t \brief Data rate structure interpretation in case LoRa is used @@ -346,28 +360,29 @@ class PhysicalLayer { virtual RadioLibTime_t getTimeOnAir(size_t len); /*! - \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) - \param timeoutUs Timeout in microseconds to listen for - \returns Timeout value in a unit that is specific for the used module + \brief Calculate the timeout value for this specific module / series + (in number of symbols or units of time). + \param timeoutUs Timeout in microseconds to listen for. + \returns Timeout value in a unit that is specific for the used module. */ virtual RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); /*! - \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks - \param irqFlags The flags for which IRQs must be triggered - \param irqMask Mask indicating which IRQ triggers a DIO + \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks. + \param irqFlags The flags for which IRQs must be triggered. + \param irqMask Mask indicating which IRQ triggers a DIO. \returns \ref status_codes */ virtual int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); /*! - \brief Check whether the IRQ bit for RxTimeout is set - \returns Whether RxTimeout IRQ is set + \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). + \returns Whether requested IRQ is set. */ - virtual bool isRxTimeout(); + virtual bool isIrqSet(uint8_t irq); /*! - \brief Interrupt-driven channel activity detection method. interrupt will be activated + \brief Interrupt-driven channel activity detection method. Interrupt will be activated when packet is detected. Must be implemented in module class. \returns \ref status_codes */ From 0eb987a83cbf6d12f0f7307a60bff0afad9a2fe2 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 16 Aug 2024 00:04:34 +0200 Subject: [PATCH 1215/1848] [LR11x0] Generalize IRQ checks --- src/modules/LR11x0/LR11x0.cpp | 35 ++++++++++++++++++++++++++++++----- src/modules/LR11x0/LR11x0.h | 6 +++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index d1e1c0aa34..52c270cc61 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1328,12 +1328,37 @@ int16_t LR11x0::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -bool LR11x0::isRxTimeout() { - uint32_t irq = getIrqStatus(); - bool rxTimedOut = irq & RADIOLIB_LR11X0_IRQ_TIMEOUT; - return(rxTimedOut); +bool LR11x0::isIrqSet(uint8_t irq) { + uint16_t flags = getIrqStatus(); + switch(irq) { + case RADIOLIB_IRQ_TX_DONE: + return(flags & RADIOLIB_LR11X0_IRQ_TX_DONE); + case RADIOLIB_IRQ_RX_DONE: + return(flags & RADIOLIB_LR11X0_IRQ_RX_DONE); + case RADIOLIB_IRQ_PREAMBLE_DETECTED: + return(flags & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED); + case RADIOLIB_IRQ_SYNC_WORD_VALID: + return(flags & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID); + case RADIOLIB_IRQ_HEADER_VALID: + return(flags & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID); + case RADIOLIB_IRQ_HEADER_ERR: + return(flags & RADIOLIB_LR11X0_IRQ_HEADER_ERR); + case RADIOLIB_IRQ_CRC_ERR: + return(flags & RADIOLIB_LR11X0_IRQ_CRC_ERR); + case RADIOLIB_IRQ_CAD_DONE: + return(flags & RADIOLIB_LR11X0_IRQ_CAD_DONE); + case RADIOLIB_IRQ_CAD_DETECTED: + return(flags & RADIOLIB_LR11X0_IRQ_CAD_DETECTED); + case RADIOLIB_IRQ_TIMEOUT: + return(flags & RADIOLIB_LR11X0_IRQ_TIMEOUT); + case RADIOLIB_IRQ_LR_FHSS_HOP: + return(flags & RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP); + default: + return(false); + } + return(false); } - + uint8_t LR11x0::randomByte() { uint32_t num = 0; (void)getRandomNumber(&num); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 741e86230b..1f9fedbc81 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1229,10 +1229,10 @@ class LR11x0: public PhysicalLayer { int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; /*! - \brief Check whether the IRQ bit for RxTimeout is set - \returns Whether RxTimeout IRQ is set + \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). + \returns Whether requested IRQ is set. */ - bool isRxTimeout() override; + bool isIrqSet(uint8_t irq) override; /*! \brief Get one truly random byte from RSSI noise. From 3a73ed8c1ff4372f1a4bfdd42f595cc044df12a6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 16 Aug 2024 00:04:42 +0200 Subject: [PATCH 1216/1848] [SX126x] Generalize IRQ checks --- src/modules/SX126x/SX126x.cpp | 33 +++++++++++++++++++++++++++++---- src/modules/SX126x/SX126x.h | 6 +++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index b98fad5963..12b6f5f053 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1466,10 +1466,35 @@ int16_t SX126x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -bool SX126x::isRxTimeout() { - uint16_t irq = getIrqStatus(); - bool rxTimedOut = irq & RADIOLIB_SX126X_IRQ_TIMEOUT; - return(rxTimedOut); +bool SX126x::isIrqSet(uint8_t irq) { + uint16_t flags = getIrqStatus(); + switch(irq) { + case RADIOLIB_IRQ_TX_DONE: + return(flags & RADIOLIB_SX126X_IRQ_TX_DONE); + case RADIOLIB_IRQ_RX_DONE: + return(flags & RADIOLIB_SX126X_IRQ_RX_DONE); + case RADIOLIB_IRQ_PREAMBLE_DETECTED: + return(flags & RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED); + case RADIOLIB_IRQ_SYNC_WORD_VALID: + return(flags & RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID); + case RADIOLIB_IRQ_HEADER_VALID: + return(flags & RADIOLIB_SX126X_IRQ_HEADER_VALID); + case RADIOLIB_IRQ_HEADER_ERR: + return(flags & RADIOLIB_SX126X_IRQ_HEADER_ERR); + case RADIOLIB_IRQ_CRC_ERR: + return(flags & RADIOLIB_SX126X_IRQ_CRC_ERR); + case RADIOLIB_IRQ_CAD_DONE: + return(flags & RADIOLIB_SX126X_IRQ_CAD_DONE); + case RADIOLIB_IRQ_CAD_DETECTED: + return(flags & RADIOLIB_SX126X_IRQ_CAD_DETECTED); + case RADIOLIB_IRQ_TIMEOUT: + return(flags & RADIOLIB_SX126X_IRQ_TIMEOUT); + case RADIOLIB_IRQ_LR_FHSS_HOP: + return(flags & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP); + default: + return(false); + } + return(false); } int16_t SX126x::implicitHeader(size_t len) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 631695191b..1a4fd2ca75 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -997,10 +997,10 @@ class SX126x: public PhysicalLayer { int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; /*! - \brief Check whether the IRQ bit for RxTimeout is set - \returns Whether RxTimeout IRQ is set + \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). + \returns Whether requested IRQ is set. */ - bool isRxTimeout() override; + bool isIrqSet(uint8_t irq) override; /*! \brief Set implicit header mode for future reception/transmission. From 08f92cdd291d3aa2e394ca7843eadc22a927055c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 16 Aug 2024 00:04:52 +0200 Subject: [PATCH 1217/1848] [SX127x] Generalize IRQ checks --- src/modules/SX127x/SX127x.cpp | 25 +++++++++++++++++++++---- src/modules/SX127x/SX127x.h | 6 +++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index eaa8c46f69..621d2ee8ad 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1302,10 +1302,27 @@ int16_t SX127x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -bool SX127x::isRxTimeout() { - uint16_t irq = getIRQFlags(); - bool rxTimedOut = irq & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT; - return(rxTimedOut); +bool SX127x::isIrqSet(uint8_t irq) { + uint16_t flags = getIRQFlags(); + switch(irq) { + case RADIOLIB_IRQ_TX_DONE: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE); + case RADIOLIB_IRQ_RX_DONE: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE); + case RADIOLIB_IRQ_HEADER_VALID: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER); + case RADIOLIB_IRQ_CRC_ERR: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR); + case RADIOLIB_IRQ_CAD_DONE: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE); + case RADIOLIB_IRQ_CAD_DETECTED: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED); + case RADIOLIB_IRQ_TIMEOUT: + return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT); + default: + return(false); + } + return(false); } int16_t SX127x::setCrcFiltering(bool enable) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 7e8d5e5a44..34dba0b851 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1073,10 +1073,10 @@ class SX127x: public PhysicalLayer { int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; /*! - \brief Check whether the IRQ bit for RxTimeout is set - \returns Whether RxTimeout IRQ is set + \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). + \returns Whether requested IRQ is set. */ - bool isRxTimeout() override; + bool isIrqSet(uint8_t irq) override; /*! \brief Enable CRC filtering and generation. From b401d111273ff0d0c677d49125f9b2b84d3d5812 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 16 Aug 2024 00:05:06 +0200 Subject: [PATCH 1218/1848] [SX128x] Implement generalized IRQ checks --- src/modules/SX128x/SX128x.cpp | 31 +++++++++++++++++++++++++++++++ src/modules/SX128x/SX128x.h | 6 ++++++ 2 files changed, 37 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3d17e029df..35a1d46bd4 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -638,6 +638,37 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { return(state); } +bool SX128x::isIrqSet(uint8_t irq) { + uint16_t flags = getIrqStatus(); + switch(irq) { + case RADIOLIB_IRQ_TX_DONE: + return(flags & RADIOLIB_SX128X_IRQ_TX_DONE); + case RADIOLIB_IRQ_RX_DONE: + return(flags & RADIOLIB_SX128X_IRQ_RX_DONE); + case RADIOLIB_IRQ_PREAMBLE_DETECTED: + return(flags & RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED); + case RADIOLIB_IRQ_SYNC_WORD_VALID: + return(flags & RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID); + case RADIOLIB_IRQ_SYNC_WORD_ERROR: + return(flags & RADIOLIB_SX128X_IRQ_SYNC_WORD_ERROR); + case RADIOLIB_IRQ_HEADER_VALID: + return(flags & RADIOLIB_SX128X_IRQ_HEADER_VALID); + case RADIOLIB_IRQ_HEADER_ERR: + return(flags & RADIOLIB_SX128X_IRQ_HEADER_ERROR); + case RADIOLIB_IRQ_CRC_ERR: + return(flags & RADIOLIB_SX128X_IRQ_CRC_ERROR); + case RADIOLIB_IRQ_CAD_DONE: + return(flags & RADIOLIB_SX128X_IRQ_CAD_DONE); + case RADIOLIB_IRQ_CAD_DETECTED: + return(flags & RADIOLIB_SX128X_IRQ_CAD_DETECTED); + case RADIOLIB_IRQ_TIMEOUT: + return(flags & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT); + default: + return(false); + } + return(false); +} + int16_t SX128x::startChannelScan() { // check active modem if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 8c0d465a10..805c0579b0 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -576,6 +576,12 @@ class SX128x: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). + \returns Whether requested IRQ is set. + */ + bool isIrqSet(uint8_t irq) override; + /*! \brief Interrupt-driven channel activity detection method. DIO1 will be activated when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. From 32dc5babd4446abf86bb7ee43c381db19b2bbf9f Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 16 Aug 2024 00:05:55 +0200 Subject: [PATCH 1219/1848] [LoRaWAN] Move to generalized IRQ check (PHY) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 90325ecf53..92b0b2ee87 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1226,7 +1226,7 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set - if(!this->phyLayer->isRxTimeout()) { + if(!this->phyLayer->isIrqSet(RADIOLIB_IRQ_TIMEOUT)) { break; } else if(i == 0) { @@ -1248,7 +1248,7 @@ int16_t LoRaWANNode::downlinkCommon() { this->rxDelayEnd = mod->hal->millis(); // if we got here due to a timeout, stop ongoing activities - if(this->phyLayer->isRxTimeout()) { + if(this->phyLayer->isIrqSet(RADIOLIB_IRQ_TIMEOUT)) { this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { this->phyLayer->invertIQ(false); From 66799fca922968bef0d45b89f480d98d3e5a0791 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 16 Aug 2024 22:07:42 +0200 Subject: [PATCH 1220/1848] Update IDF manifest to new format --- idf_component.yml | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index a388ba0cb8..20a4d6d876 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,6 +1,41 @@ version: "6.6.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." -tags: "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121" +tags: + - radio + - communication + - morse + - cc1101 + - aprs + - sx1276 + - sx1278 + - sx1272 + - rtty + - ax25 + - afsk + - nrf24 + - rfm96 + - sx1231 + - rfm96 + - rfm98 + - sstv + - sx1278 + - sx1272 + - sx1276 + - sx1280 + - sx1281 + - sx1282 + - sx1261 + - sx1262 + - sx1268 + - si4432 + - rfm22 + - llcc68 + - pager + - pocsag + - lorawan + - lr1110 + - lr1120 + - lr1121 url: "https://github.com/jgromes/RadioLib" repository: "https://github.com/jgromes/RadioLib.git" license: "MIT" @@ -8,4 +43,4 @@ dependencies: # Required IDF version idf: ">=4.1" maintainers: - "Jan Gromeš " + - Jan Gromeš From c35f4044e70d5094400e083e86bb269be39aca3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 16 Aug 2024 22:12:13 +0200 Subject: [PATCH 1221/1848] Fixed duplicate tag in manifest files --- idf_component.yml | 2 +- library.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 20a4d6d876..f4b08176ed 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -13,7 +13,7 @@ tags: - ax25 - afsk - nrf24 - - rfm96 + - rf69 - sx1231 - rfm96 - rfm98 diff --git a/library.json b/library.json index 2629b7097b..165435255c 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "6.6.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", - "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", "repository": { From 382bf19100f75282a723fbf2c645ec578635218b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 16 Aug 2024 22:33:43 +0200 Subject: [PATCH 1222/1848] Remove more duplicates from manifest files --- idf_component.yml | 3 --- library.json | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index f4b08176ed..e7d7792a1c 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -18,9 +18,6 @@ tags: - rfm96 - rfm98 - sstv - - sx1278 - - sx1272 - - sx1276 - sx1280 - sx1281 - sx1282 diff --git a/library.json b/library.json index 165435255c..cbaf23b47e 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "6.6.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", - "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", "repository": { From 260534741d97d2847583847008e3d2cd8725b20a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Aug 2024 21:19:14 +0200 Subject: [PATCH 1223/1848] Added readme to ESP-IDF example --- examples/NonArduino/ESP-IDF/README.md | 10 ++++++++++ examples/NonArduino/ESP-IDF/main/idf_component.yml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 examples/NonArduino/ESP-IDF/README.md diff --git a/examples/NonArduino/ESP-IDF/README.md b/examples/NonArduino/ESP-IDF/README.md new file mode 100644 index 0000000000..401785eaa5 --- /dev/null +++ b/examples/NonArduino/ESP-IDF/README.md @@ -0,0 +1,10 @@ +# RadioLib ESP-IDF example + +This example shows how to use RadioLib as ESP-IDF component, without the Arduino framework. To run in ESP-IDF (or on any other platform), RadioLib includes an internal hardware abstraction layer (HAL). This software layer takes care of basic interaction with the hardware, such as performing SPI transaction or GPIO operations. To run on your chosen ESP microcontroller, you will likely have to customize the example HAL for your specific ESP type. + +## Structure of the example + +* `main/CMakeLists.txt` - IDF component CMake file +* `main/EspHal.h` - RadioLib HAL example implementation +* `main/idf_component.yml` - declaration of the RadioLib dependency for this example +* `main/main.cpp` - the example source code diff --git a/examples/NonArduino/ESP-IDF/main/idf_component.yml b/examples/NonArduino/ESP-IDF/main/idf_component.yml index 38382f42d0..ce1ccc2cb2 100644 --- a/examples/NonArduino/ESP-IDF/main/idf_component.yml +++ b/examples/NonArduino/ESP-IDF/main/idf_component.yml @@ -1,7 +1,7 @@ dependencies: RadioLib: # referenced locally because the example is a part of the repository itself - # under normal circumstances, it's preferrable to reference the repository instead + # under normal circumstances, it's preferable to reference the repository instead # for other options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html path: ../../../../../RadioLib #git: https://github.com/jgromes/RadioLib.git From 0bc0e3d9c86418a8a2306cee39601777cf035340 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 17 Aug 2024 22:03:48 +0200 Subject: [PATCH 1224/1848] [PHY, modules, LoRaWAN] Integrate feedback --- src/modules/LR11x0/LR11x0.cpp | 8 +++----- src/modules/LR11x0/LR11x0.h | 2 +- src/modules/SX126x/SX126x.cpp | 8 +++----- src/modules/SX126x/SX126x.h | 2 +- src/modules/SX127x/SX127x.cpp | 6 +++--- src/modules/SX127x/SX127x.h | 2 +- src/modules/SX128x/SX128x.cpp | 8 +++----- src/modules/SX128x/SX128x.h | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 12 ++++++++++-- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.h | 16 +++++++--------- 11 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 52c270cc61..bcef4d0bd0 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1328,7 +1328,7 @@ int16_t LR11x0::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -bool LR11x0::isIrqSet(uint8_t irq) { +int16_t LR11x0::checkIrq(uint8_t irq) { uint16_t flags = getIrqStatus(); switch(irq) { case RADIOLIB_IRQ_TX_DONE: @@ -1351,12 +1351,10 @@ bool LR11x0::isIrqSet(uint8_t irq) { return(flags & RADIOLIB_LR11X0_IRQ_CAD_DETECTED); case RADIOLIB_IRQ_TIMEOUT: return(flags & RADIOLIB_LR11X0_IRQ_TIMEOUT); - case RADIOLIB_IRQ_LR_FHSS_HOP: - return(flags & RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP); default: - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } uint8_t LR11x0::randomByte() { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 1f9fedbc81..dffac085fa 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1232,7 +1232,7 @@ class LR11x0: public PhysicalLayer { \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). \returns Whether requested IRQ is set. */ - bool isIrqSet(uint8_t irq) override; + int16_t checkIrq(uint8_t irq) override; /*! \brief Get one truly random byte from RSSI noise. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 12b6f5f053..1c2a9e4835 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1466,7 +1466,7 @@ int16_t SX126x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -bool SX126x::isIrqSet(uint8_t irq) { +int16_t SX126x::checkIrq(uint8_t irq) { uint16_t flags = getIrqStatus(); switch(irq) { case RADIOLIB_IRQ_TX_DONE: @@ -1489,12 +1489,10 @@ bool SX126x::isIrqSet(uint8_t irq) { return(flags & RADIOLIB_SX126X_IRQ_CAD_DETECTED); case RADIOLIB_IRQ_TIMEOUT: return(flags & RADIOLIB_SX126X_IRQ_TIMEOUT); - case RADIOLIB_IRQ_LR_FHSS_HOP: - return(flags & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP); default: - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } int16_t SX126x::implicitHeader(size_t len) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 1a4fd2ca75..68598650c3 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1000,7 +1000,7 @@ class SX126x: public PhysicalLayer { \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). \returns Whether requested IRQ is set. */ - bool isIrqSet(uint8_t irq) override; + int16_t checkIrq(uint8_t irq) override; /*! \brief Set implicit header mode for future reception/transmission. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 621d2ee8ad..7cc33c9fd2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1302,7 +1302,7 @@ int16_t SX127x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -bool SX127x::isIrqSet(uint8_t irq) { +int16_t SX127x::checkIrq(uint8_t irq) { uint16_t flags = getIRQFlags(); switch(irq) { case RADIOLIB_IRQ_TX_DONE: @@ -1320,9 +1320,9 @@ bool SX127x::isIrqSet(uint8_t irq) { case RADIOLIB_IRQ_TIMEOUT: return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT); default: - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } int16_t SX127x::setCrcFiltering(bool enable) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 34dba0b851..c00cd42f99 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1076,7 +1076,7 @@ class SX127x: public PhysicalLayer { \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). \returns Whether requested IRQ is set. */ - bool isIrqSet(uint8_t irq) override; + int16_t checkIrq(uint8_t irq) override; /*! \brief Enable CRC filtering and generation. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 35a1d46bd4..fb9ed3283f 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -638,7 +638,7 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { return(state); } -bool SX128x::isIrqSet(uint8_t irq) { +int16_t SX128x::checkIrq(uint8_t irq) { uint16_t flags = getIrqStatus(); switch(irq) { case RADIOLIB_IRQ_TX_DONE: @@ -649,8 +649,6 @@ bool SX128x::isIrqSet(uint8_t irq) { return(flags & RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED); case RADIOLIB_IRQ_SYNC_WORD_VALID: return(flags & RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID); - case RADIOLIB_IRQ_SYNC_WORD_ERROR: - return(flags & RADIOLIB_SX128X_IRQ_SYNC_WORD_ERROR); case RADIOLIB_IRQ_HEADER_VALID: return(flags & RADIOLIB_SX128X_IRQ_HEADER_VALID); case RADIOLIB_IRQ_HEADER_ERR: @@ -664,9 +662,9 @@ bool SX128x::isIrqSet(uint8_t irq) { case RADIOLIB_IRQ_TIMEOUT: return(flags & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT); default: - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } int16_t SX128x::startChannelScan() { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 805c0579b0..43c1f41285 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -580,7 +580,7 @@ class SX128x: public PhysicalLayer { \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). \returns Whether requested IRQ is set. */ - bool isIrqSet(uint8_t irq) override; + int16_t checkIrq(uint8_t irq) override; /*! \brief Interrupt-driven channel activity detection method. DIO1 will be activated diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 92b0b2ee87..c5739cc84c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1226,7 +1226,11 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set - if(!this->phyLayer->isIrqSet(RADIOLIB_IRQ_TIMEOUT)) { + state = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); + if(state == RADIOLIB_ERR_UNSUPPORTED) { + return(state); + } + if(state == 0) { break; } else if(i == 0) { @@ -1248,7 +1252,11 @@ int16_t LoRaWANNode::downlinkCommon() { this->rxDelayEnd = mod->hal->millis(); // if we got here due to a timeout, stop ongoing activities - if(this->phyLayer->isIrqSet(RADIOLIB_IRQ_TIMEOUT)) { + state = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); + if(state == RADIOLIB_ERR_UNSUPPORTED) { + return(state); + } + if(state == 1) { this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { this->phyLayer->invertIQ(false); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 02fc12c5b5..6953447c96 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -316,9 +316,9 @@ int16_t PhysicalLayer::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) return(RADIOLIB_ERR_UNSUPPORTED); } -bool PhysicalLayer::isIrqSet(uint8_t irq) { +int16_t PhysicalLayer::checkIrq(uint8_t irq) { (void)irq; - return(false); + return(RADIOLIB_ERR_UNSUPPORTED); } int16_t PhysicalLayer::startChannelScan() { diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index b6165647b0..408408aed7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -9,14 +9,12 @@ #define RADIOLIB_IRQ_RX_DONE 0x01 #define RADIOLIB_IRQ_PREAMBLE_DETECTED 0x02 #define RADIOLIB_IRQ_SYNC_WORD_VALID 0x03 -#define RADIOLIB_IRQ_SYNC_WORD_ERROR 0x04 -#define RADIOLIB_IRQ_HEADER_VALID 0x05 -#define RADIOLIB_IRQ_HEADER_ERR 0x06 -#define RADIOLIB_IRQ_CRC_ERR 0x07 -#define RADIOLIB_IRQ_CAD_DONE 0x08 -#define RADIOLIB_IRQ_CAD_DETECTED 0x09 -#define RADIOLIB_IRQ_TIMEOUT 0x0A -#define RADIOLIB_IRQ_LR_FHSS_HOP 0x0B +#define RADIOLIB_IRQ_HEADER_VALID 0x04 +#define RADIOLIB_IRQ_HEADER_ERR 0x05 +#define RADIOLIB_IRQ_CRC_ERR 0x06 +#define RADIOLIB_IRQ_CAD_DONE 0x07 +#define RADIOLIB_IRQ_CAD_DETECTED 0x08 +#define RADIOLIB_IRQ_TIMEOUT 0x09 /*! \struct LoRaRate_t @@ -379,7 +377,7 @@ class PhysicalLayer { \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). \returns Whether requested IRQ is set. */ - virtual bool isIrqSet(uint8_t irq); + virtual int16_t checkIrq(uint8_t irq); /*! \brief Interrupt-driven channel activity detection method. Interrupt will be activated From 647fa23ce9e95a8fdd421db2f77fff2dd6e53d6e Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 17 Aug 2024 22:04:28 +0200 Subject: [PATCH 1225/1848] [LoRaWAN] Remove redundant PHY check --- src/protocols/LoRaWAN/LoRaWAN.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c5739cc84c..c27feaa4fd 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1196,6 +1196,8 @@ int16_t LoRaWANNode::downlinkCommon() { this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); + int16_t timedOut = 0; + // perform listening in the two Rx windows for(uint8_t i = 0; i < 2; i++) { downlinkAction = false; @@ -1226,11 +1228,11 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set - state = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); - if(state == RADIOLIB_ERR_UNSUPPORTED) { - return(state); + timedOut = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); + if(timedOut == RADIOLIB_ERR_UNSUPPORTED) { + return(timedOut); } - if(state == 0) { + if(!timedOut) { break; } else if(i == 0) { @@ -1252,11 +1254,7 @@ int16_t LoRaWANNode::downlinkCommon() { this->rxDelayEnd = mod->hal->millis(); // if we got here due to a timeout, stop ongoing activities - state = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); - if(state == RADIOLIB_ERR_UNSUPPORTED) { - return(state); - } - if(state == 1) { + if(timedOut) { this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { this->phyLayer->invertIQ(false); From 6847fcda5cfb0afcf39ef64136bc9485ca86110e Mon Sep 17 00:00:00 2001 From: Pavlo Manovi Date: Thu, 29 Aug 2024 09:30:31 -0400 Subject: [PATCH 1226/1848] Reconcile implicit double / float promotion with math functions and passed function value types. Also suppress incorrect unused variable warnings when variables are used in logging macros. --- src/modules/LR11x0/LR11x0.cpp | 63 ++++++++++++++++++----------------- src/modules/RF69/RF69.cpp | 2 +- src/modules/SX123x/SX1233.cpp | 2 +- src/modules/SX126x/SX126x.cpp | 62 +++++++++++++++++----------------- src/modules/SX127x/SX1272.cpp | 6 ++-- src/modules/SX127x/SX1278.cpp | 42 +++++++++++------------ src/modules/SX127x/SX127x.cpp | 4 +-- src/modules/SX128x/SX128x.cpp | 10 +++--- src/modules/Si443x/Si443x.cpp | 30 ++++++++--------- src/protocols/Print/Print.cpp | 10 +++--- 10 files changed, 116 insertions(+), 115 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index bcef4d0bd0..b1ebbc448e 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -754,47 +754,47 @@ int16_t LR11x0::setRxBandwidth(float rxBw) { }*/ // check allowed receiver bandwidth values - if(fabs(rxBw - 4.8) <= 0.001) { + if(fabsf(rxBw - 4.8) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8; - } else if(fabs(rxBw - 5.8) <= 0.001) { + } else if(fabsf(rxBw - 5.8) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8; - } else if(fabs(rxBw - 7.3) <= 0.001) { + } else if(fabsf(rxBw - 7.3) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3; - } else if(fabs(rxBw - 9.7) <= 0.001) { + } else if(fabsf(rxBw - 9.7) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7; - } else if(fabs(rxBw - 11.7) <= 0.001) { + } else if(fabsf(rxBw - 11.7) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7; - } else if(fabs(rxBw - 14.6) <= 0.001) { + } else if(fabsf(rxBw - 14.6) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6; - } else if(fabs(rxBw - 19.5) <= 0.001) { + } else if(fabsf(rxBw - 19.5) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5; - } else if(fabs(rxBw - 23.4) <= 0.001) { + } else if(fabsf(rxBw - 23.4) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4; - } else if(fabs(rxBw - 29.3) <= 0.001) { + } else if(fabsf(rxBw - 29.3) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3; - } else if(fabs(rxBw - 39.0) <= 0.001) { + } else if(fabsf(rxBw - 39.0) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0; - } else if(fabs(rxBw - 46.9) <= 0.001) { + } else if(fabsf(rxBw - 46.9) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9; - } else if(fabs(rxBw - 58.6) <= 0.001) { + } else if(fabsf(rxBw - 58.6) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6; - } else if(fabs(rxBw - 78.2) <= 0.001) { + } else if(fabsf(rxBw - 78.2) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2; - } else if(fabs(rxBw - 93.8) <= 0.001) { + } else if(fabsf(rxBw - 93.8) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8; - } else if(fabs(rxBw - 117.3) <= 0.001) { + } else if(fabsf(rxBw - 117.3) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3; - } else if(fabs(rxBw - 156.2) <= 0.001) { + } else if(fabsf(rxBw - 156.2) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2; - } else if(fabs(rxBw - 187.2) <= 0.001) { + } else if(fabsf(rxBw - 187.2) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2; - } else if(fabs(rxBw - 234.3) <= 0.001) { + } else if(fabsf(rxBw - 234.3) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3; - } else if(fabs(rxBw - 312.0) <= 0.001) { + } else if(fabsf(rxBw - 312.0) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0; - } else if(fabs(rxBw - 373.6) <= 0.001) { + } else if(fabsf(rxBw - 373.6) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6; - } else if(fabs(rxBw - 467.0) <= 0.001) { + } else if(fabsf(rxBw - 467.0) <= 0.001) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0; } else { return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); @@ -1070,28 +1070,28 @@ int16_t LR11x0::setTCXO(float voltage, uint32_t delay) { } // check 0 V disable - if(fabs(voltage - 0.0) <= 0.001) { + if(fabsf(voltage - 0.0) <= 0.001) { setTcxoMode(0, 0); return(reset()); } // check allowed voltage values uint8_t tune = 0; - if(fabs(voltage - 1.6) <= 0.001) { + if(fabsf(voltage - 1.6) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6; - } else if(fabs(voltage - 1.7) <= 0.001) { + } else if(fabsf(voltage - 1.7) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7; - } else if(fabs(voltage - 1.8) <= 0.001) { + } else if(fabsf(voltage - 1.8) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8; - } else if(fabs(voltage - 2.2) <= 0.001) { + } else if(fabsf(voltage - 2.2) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2; - } else if(fabs(voltage - 2.4) <= 0.001) { + } else if(fabsf(voltage - 2.4) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4; - } else if(fabs(voltage - 2.7) <= 0.001) { + } else if(fabsf(voltage - 2.7) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7; - } else if(fabs(voltage - 3.0) <= 0.001) { + } else if(fabsf(voltage - 3.0) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0; - } else if(fabs(voltage - 3.3) <= 0.001) { + } else if(fabsf(voltage - 3.3) <= 0.001) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3; } else { return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); @@ -1265,7 +1265,7 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); } else { // long interleaving - abandon hope all ye who enter here @@ -1791,6 +1791,7 @@ int16_t LR11x0::getGnssScanResult(uint16_t size) { RADIOLIB_DEBUG_BASIC_PRINTLN("Timing:"); for(size_t i = 0; i < 31; i++) { uint32_t t = (timing[i] * 1000UL) / 32768UL; + (void)t; RADIOLIB_DEBUG_BASIC_PRINTLN(" %d: %lu ms", (int)i*4, (unsigned long)t); } RADIOLIB_DEBUG_BASIC_PRINTLN("constDemod: %d", constDemod); diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index d5a07c9e9d..2bbfeb57e0 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -589,7 +589,7 @@ int16_t RF69::setRxBandwidth(float rxBw) { for(int8_t e = 7; e >= 0; e--) { for(int8_t m = 2; m >= 0; m--) { float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2)))); - if(fabs(rxBw - (point / 1000.0)) <= 0.1) { + if(fabsf(rxBw - (point / 1000.0)) <= 0.1) { // set Rx bandwidth state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); if(state == RADIOLIB_ERR_NONE) { diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index 16c4bca143..23eb72c6f9 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -93,7 +93,7 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po int16_t SX1233::setBitRate(float br) { // check high bit-rate operation uint8_t pllBandwidth = RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE; - if((fabs(br - 500.0f) < 0.1) || (fabs(br - 600.0f) < 0.1)) { + if((fabsf(br - 500.0f) < 0.1) || (fabsf(br - 600.0f) < 0.1)) { pllBandwidth = RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE; } else { // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1c2a9e4835..c6185e05b4 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1011,47 +1011,47 @@ int16_t SX126x::setRxBandwidth(float rxBw) { this->rxBandwidthKhz = rxBw; // check allowed receiver bandwidth values - if(fabs(rxBw - 4.8) <= 0.001) { + if(fabsf(rxBw - 4.8) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8; - } else if(fabs(rxBw - 5.8) <= 0.001) { + } else if(fabsf(rxBw - 5.8) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8; - } else if(fabs(rxBw - 7.3) <= 0.001) { + } else if(fabsf(rxBw - 7.3) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3; - } else if(fabs(rxBw - 9.7) <= 0.001) { + } else if(fabsf(rxBw - 9.7) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7; - } else if(fabs(rxBw - 11.7) <= 0.001) { + } else if(fabsf(rxBw - 11.7) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7; - } else if(fabs(rxBw - 14.6) <= 0.001) { + } else if(fabsf(rxBw - 14.6) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6; - } else if(fabs(rxBw - 19.5) <= 0.001) { + } else if(fabsf(rxBw - 19.5) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5; - } else if(fabs(rxBw - 23.4) <= 0.001) { + } else if(fabsf(rxBw - 23.4) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4; - } else if(fabs(rxBw - 29.3) <= 0.001) { + } else if(fabsf(rxBw - 29.3) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3; - } else if(fabs(rxBw - 39.0) <= 0.001) { + } else if(fabsf(rxBw - 39.0) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0; - } else if(fabs(rxBw - 46.9) <= 0.001) { + } else if(fabsf(rxBw - 46.9) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9; - } else if(fabs(rxBw - 58.6) <= 0.001) { + } else if(fabsf(rxBw - 58.6) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6; - } else if(fabs(rxBw - 78.2) <= 0.001) { + } else if(fabsf(rxBw - 78.2) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2; - } else if(fabs(rxBw - 93.8) <= 0.001) { + } else if(fabsf(rxBw - 93.8) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8; - } else if(fabs(rxBw - 117.3) <= 0.001) { + } else if(fabsf(rxBw - 117.3) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3; - } else if(fabs(rxBw - 156.2) <= 0.001) { + } else if(fabsf(rxBw - 156.2) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; - } else if(fabs(rxBw - 187.2) <= 0.001) { + } else if(fabsf(rxBw - 187.2) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2; - } else if(fabs(rxBw - 234.3) <= 0.001) { + } else if(fabsf(rxBw - 234.3) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3; - } else if(fabs(rxBw - 312.0) <= 0.001) { + } else if(fabsf(rxBw - 312.0) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0; - } else if(fabs(rxBw - 373.6) <= 0.001) { + } else if(fabsf(rxBw - 373.6) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6; - } else if(fabs(rxBw - 467.0) <= 0.001) { + } else if(fabsf(rxBw - 467.0) <= 0.001) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0; } else { return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); @@ -1699,27 +1699,27 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { } // check 0 V disable - if(fabs(voltage - 0.0) <= 0.001) { + if(fabsf(voltage - 0.0) <= 0.001) { return(reset(true)); } // check alowed voltage values uint8_t data[4]; - if(fabs(voltage - 1.6) <= 0.001) { + if(fabsf(voltage - 1.6) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6; - } else if(fabs(voltage - 1.7) <= 0.001) { + } else if(fabsf(voltage - 1.7) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7; - } else if(fabs(voltage - 1.8) <= 0.001) { + } else if(fabsf(voltage - 1.8) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8; - } else if(fabs(voltage - 2.2) <= 0.001) { + } else if(fabsf(voltage - 2.2) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2; - } else if(fabs(voltage - 2.4) <= 0.001) { + } else if(fabsf(voltage - 2.4) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4; - } else if(fabs(voltage - 2.7) <= 0.001) { + } else if(fabsf(voltage - 2.7) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7; - } else if(fabs(voltage - 3.0) <= 0.001) { + } else if(fabsf(voltage - 3.0) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0; - } else if(fabs(voltage - 3.3) <= 0.001) { + } else if(fabsf(voltage - 3.3) <= 0.001) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3; } else { return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); @@ -2038,7 +2038,7 @@ int16_t SX126x::fixSensitivity() { RADIOLIB_ASSERT(state); // fix the value for LoRa with 500 kHz bandwidth - if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabs(this->bandwidthKhz - 500.0) <= 0.001)) { + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabsf(this->bandwidthKhz - 500.0) <= 0.001)) { sensitivityConfig &= 0xFB; } else { sensitivityConfig |= 0x04; diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 6e8b6c0bfb..50b088b243 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -102,11 +102,11 @@ int16_t SX1272::setBandwidth(float bw) { uint8_t newBandwidth; // check allowed bandwidth values - if(fabs(bw - 125.0) <= 0.001) { + if(fabsf(bw - 125.0) <= 0.001) { newBandwidth = RADIOLIB_SX1272_BW_125_00_KHZ; - } else if(fabs(bw - 250.0) <= 0.001) { + } else if(fabsf(bw - 250.0) <= 0.001) { newBandwidth = RADIOLIB_SX1272_BW_250_00_KHZ; - } else if(fabs(bw - 500.0) <= 0.001) { + } else if(fabsf(bw - 500.0) <= 0.001) { newBandwidth = RADIOLIB_SX1272_BW_500_00_KHZ; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 2a40eb6a7d..3265675f09 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -102,25 +102,25 @@ int16_t SX1278::setBandwidth(float bw) { uint8_t newBandwidth; // check allowed bandwidth values - if(fabs(bw - 7.8) <= 0.001) { + if(fabsf(bw - 7.8) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ; - } else if(fabs(bw - 10.4) <= 0.001) { + } else if(fabsf(bw - 10.4) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ; - } else if(fabs(bw - 15.6) <= 0.001) { + } else if(fabsf(bw - 15.6) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ; - } else if(fabs(bw - 20.8) <= 0.001) { + } else if(fabsf(bw - 20.8) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ; - } else if(fabs(bw - 31.25) <= 0.001) { + } else if(fabsf(bw - 31.25) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ; - } else if(fabs(bw - 41.7) <= 0.001) { + } else if(fabsf(bw - 41.7) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ; - } else if(fabs(bw - 62.5) <= 0.001) { + } else if(fabsf(bw - 62.5) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ; - } else if(fabs(bw - 125.0) <= 0.001) { + } else if(fabsf(bw - 125.0) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ; - } else if(fabs(bw - 250.0) <= 0.001) { + } else if(fabsf(bw - 250.0) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ; - } else if(fabs(bw - 500.0) <= 0.001) { + } else if(fabsf(bw - 500.0) <= 0.001) { newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); @@ -623,7 +623,7 @@ void SX1278::errataFix(bool rx) { // sensitivity optimization for 500kHz bandwidth // see SX1276/77/78 Errata, section 2.1 for details Module* mod = this->getMod(); - if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { + if(fabsf(SX127x::bandwidth - 500.0) <= 0.001) { if((frequency >= 862.0) && (frequency <= 1020.0)) { mod->SPIwriteRegister(0x36, 0x02); mod->SPIwriteRegister(0x3a, 0x64); @@ -639,49 +639,49 @@ void SX1278::errataFix(bool rx) { // figure out what we need to set uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 }; float rxFreq = frequency; - if(fabs(SX127x::bandwidth - 7.8) <= 0.001) { + if(fabsf(SX127x::bandwidth - 7.8) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x48; fixedRegs[2] = 0x00; rxFreq += 0.00781; - } else if(fabs(SX127x::bandwidth - 10.4) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 10.4) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.01042; - } else if(fabs(SX127x::bandwidth - 15.6) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 15.6) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.01562; - } else if(fabs(SX127x::bandwidth - 20.8) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 20.8) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.02083; - } else if(fabs(SX127x::bandwidth - 31.25) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 31.25) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.03125; - } else if(fabs(SX127x::bandwidth - 41.7) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 41.7) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; rxFreq += 0.04167; - } else if(fabs(SX127x::bandwidth - 62.5) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 62.5) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabs(SX127x::bandwidth - 125.0) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 125.0) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabs(SX127x::bandwidth - 250.0) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 250.0) <= 0.001) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabs(SX127x::bandwidth - 500.0) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 500.0) <= 0.001) { fixedRegs[0] = 0b10000000; fixedRegs[1] = mod->SPIreadRegister(0x2F); fixedRegs[2] = mod->SPIreadRegister(0x30); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7cc33c9fd2..778dc9e935 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -962,7 +962,7 @@ uint8_t SX127x::calculateBWManExp(float bandwidth) for(uint8_t e = 7; e >= 1; e--) { for(int8_t m = 2; m >= 0; m--) { float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); - if(fabs(bandwidth - ((point / 1000.0) + 0.05)) <= 0.5) { + if(fabsf(bandwidth - ((point / 1000.0) + 0.05)) <= 0.5) { return((m << 3) | e); } } @@ -1244,7 +1244,7 @@ float SX127x::getNumSymbols(size_t len) { float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); // get number of payload symbols - float n_pay = 8.0 + RADIOLIB_MAX(ceil((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); + float n_pay = 8.0 + RADIOLIB_MAX(ceilf((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); // add 4.25 symbols for the sync return(n_pre + n_pay + 4.25f); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index fb9ed3283f..088644cca5 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -734,13 +734,13 @@ int16_t SX128x::setBandwidth(float bw) { return(RADIOLIB_ERR_WRONG_MODEM); } - if(fabs(bw - 203.125) <= 0.001) { + if(fabsf(bw - 203.125) <= 0.001) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125; - } else if(fabs(bw - 406.25) <= 0.001) { + } else if(fabsf(bw - 406.25) <= 0.001) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25; - } else if(fabs(bw - 812.5) <= 0.001) { + } else if(fabsf(bw - 812.5) <= 0.001) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50; - } else if(fabs(bw - 1625.0) <= 0.001) { + } else if(fabsf(bw - 1625.0) <= 0.001) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); @@ -1349,7 +1349,7 @@ RadioLibTime_t SX128x::getTimeOnAir(size_t len) { uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); } else { // long interleaving - abandon hope all ye who enter here diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 4ba1b21c35..4db2ffca9f 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -426,63 +426,63 @@ int16_t Si443x::setRxBandwidth(float rxBw) { // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess /// \todo float tolerance equality as macro? - } else if(fabs(rxBw - 142.8) <= 0.001) { + } else if(fabsf(rxBw - 142.8) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 4; - } else if(fabs(rxBw - 167.8) <= 0.001) { + } else if(fabsf(rxBw - 167.8) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 5; - } else if(fabs(rxBw - 181.1) <= 0.001) { + } else if(fabsf(rxBw - 181.1) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 6; - } else if(fabs(rxBw - 191.5) <= 0.001) { + } else if(fabsf(rxBw - 191.5) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 15; - } else if(fabs(rxBw - 225.1) <= 0.001) { + } else if(fabsf(rxBw - 225.1) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 1; - } else if(fabs(rxBw - 248.8) <= 0.001) { + } else if(fabsf(rxBw - 248.8) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 2; - } else if(fabs(rxBw - 269.3) <= 0.001) { + } else if(fabsf(rxBw - 269.3) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 3; - } else if(fabs(rxBw - 284.8) <= 0.001) { + } else if(fabsf(rxBw - 284.8) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 4; - } else if(fabs(rxBw -335.5) <= 0.001) { + } else if(fabsf(rxBw -335.5) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 8; - } else if(fabs(rxBw - 391.8) <= 0.001) { + } else if(fabsf(rxBw - 391.8) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 9; - } else if(fabs(rxBw - 420.2) <= 0.001) { + } else if(fabsf(rxBw - 420.2) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 10; - } else if(fabs(rxBw - 468.4) <= 0.001) { + } else if(fabsf(rxBw - 468.4) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 11; - } else if(fabs(rxBw - 518.8) <= 0.001) { + } else if(fabsf(rxBw - 518.8) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 12; - } else if(fabs(rxBw - 577.0) <= 0.001) { + } else if(fabsf(rxBw - 577.0) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 13; - } else if(fabs(rxBw - 620.7) <= 0.001) { + } else if(fabsf(rxBw - 620.7) <= 0.001) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 14; diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp index 52e767beb5..c7abe69572 100644 --- a/src/protocols/Print/Print.cpp +++ b/src/protocols/Print/Print.cpp @@ -248,8 +248,8 @@ size_t RadioLibPrint::printFloat(double number, uint8_t digits) { char code[] = {0x00, 0x00, 0x00, 0x00}; if (isnan(number)) strcpy(code, "nan"); if (isinf(number)) strcpy(code, "inf"); - if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically - if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically + if (number > (double)4294967040.0) strcpy(code, "ovf"); // constant determined empirically + if (number < (double)-4294967040.0) strcpy(code, "ovf"); // constant determined empirically if(code[0] != 0x00) { if(this->encoding == RADIOLIB_ITA2) { @@ -264,7 +264,7 @@ size_t RadioLibPrint::printFloat(double number, uint8_t digits) { } // Handle negative numbers - if (number < 0.0) { + if (number < (double)0.0) { if(this->encoding == RADIOLIB_ITA2) { ITA2String ita2 = ITA2String("-"); uint8_t* arr = ita2.byteArr(); @@ -279,7 +279,7 @@ size_t RadioLibPrint::printFloat(double number, uint8_t digits) { // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; for(uint8_t i = 0; i < digits; ++i) { - rounding /= 10.0; + rounding /= (double)10.0; } number += rounding; @@ -302,7 +302,7 @@ size_t RadioLibPrint::printFloat(double number, uint8_t digits) { // Extract digits from the remainder one at a time while(digits-- > 0) { - remainder *= 10.0; + remainder *= (double) 10.0; unsigned int toPrint = (unsigned int)(remainder); n += RadioLibPrint::print(toPrint); remainder -= toPrint; From a68f689a853ec7193418f8cc3dada01ebd3b1d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 1 Sep 2024 08:34:00 +0200 Subject: [PATCH 1227/1848] Update module-not-working.md --- .github/ISSUE_TEMPLATE/module-not-working.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/module-not-working.md b/.github/ISSUE_TEMPLATE/module-not-working.md index 096d07a372..d6d8f35637 100644 --- a/.github/ISSUE_TEMPLATE/module-not-working.md +++ b/.github/ISSUE_TEMPLATE/module-not-working.md @@ -14,21 +14,35 @@ assignees: '' 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). -**Sketch that is causing the module fail** +

Sketch that is causing the module fail +

```c++ paste the sketch here, even if it is an unmodified example code ``` +

+
+ **Hardware setup** Wiring diagram, schematic, pictures etc. **Debug mode output** Enable the appropriate [debug levels](https://github.com/jgromes/RadioLib/wiki/Debug-mode) and paste the Serial monitor output here. For debugging protocols, enable `RADIOLIB_DEBUG_PROTOCOL`. For debugging issues with the radio module itself, enable `RADIOLIB_DEBUG_SPI`. +
Debug mode output +

+ +``` +paste the debug output here +``` + +

+
+ **Additional info (please complete):** - MCU: [e.g. Arduino Uno, ESP8266 etc.] - Link to Arduino core: [e.g. https://github.com/stm32duino/Arduino_Core_STM32 when using official STM32 core. See readme for links to all supported cores] - Wireless module type [e.g. CC1101, SX1268, etc.] - Arduino IDE version [e.g. 1.8.5] - - Library version [e.g. 3.0.0] + - Library version [e.g. 3.0.0 or git hash] From d9c0c4ed449ecaa63e8d0988aa6d712aeb3636fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 1 Sep 2024 08:35:37 +0200 Subject: [PATCH 1228/1848] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c1f2273c11..5ef9564242 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -13,9 +13,29 @@ Before submitting new issue, please check the [Troubleshooting Guide](https://gi **Describe the bug** A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode) **using the appropriate debug mode**. +
Debug mode output +

+ +``` +paste the debug output here +``` + +

+
+ **To Reproduce** Minimal Arduino sketch to reproduce the behavior. Please use Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)). +
Sketch that is causing the module fail +

+ +```c++ +paste the sketch here, even if it is an unmodified example code +``` + +

+
+ **Expected behavior** A clear and concise description of what you expected to happen. @@ -27,4 +47,4 @@ If applicable, add screenshots to help explain your problem. - Link to Arduino core: [e.g. https://github.com/stm32duino/Arduino_Core_STM32 when using official STM32 core. See readme for links to all supported cores] - Wireless module type [e.g. CC1101, SX1268, etc.] - Arduino IDE version [e.g. 1.8.5] - - Library version [e.g. 3.0.0] + - Library version [e.g. 3.0.0 or git hash] From bc801c70043c2482af8cd81947b855d7325a41ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 1 Sep 2024 18:19:07 +0200 Subject: [PATCH 1229/1848] [PHY] Channel scan configuration (#1190) * [PHY] Added channel scan configuration * [LR11x0] Added channel scan configuration * [SX126x] Added channel scan configuration * [SX128x] Added channel scan configuration * Use microsecond timeout * [PHY] Added generalized IRQ handling via PHY * [LR11x0] Added generalized IRQ handling via PHY * [SX126x] Added generalized IRQ handling via PHY * [SX127x] Added generalized IRQ handling via PHY * [SX128x] Added generalized IRQ handling via PHY * Added missing typedef * [PHY] Fix IRQ method argument type * [SX128x] Fix non-trivial initializer usage * [LR11x0] Added missing override specifiers * [SX126x] Added missing override specifiers * [SX127x] Added missing override specifiers * [SX128x] Added missing override specifiers * [PHY] Added missing IRQ map initializer * [CI] Drop APRS builds on AVR * [CI] Drop Morse builds for AVR * [PHY] Rework generic IRQ to allow multiple flags * [LR11x0] Rework generic IRQ to allow multiple flags * [SX126x] Rework generic IRQ to allow multiple flags * [SX127x] Rework generic IRQ to allow multiple flags * [SX128x] Rework generic IRQ to allow multiple flags * [LoRaWAN] Use generic IRQ * Add missing typedef * [SX127x] Make Rx mode implicit based on timeout * [SX127x] Fixed shadowed variable * [LR11x0] Fix missing initializers * [SX127x] Added default startReceive arguments * [LR11x0] Pass scan config by const reference * [SX126x] Pass scan config by const reference * [SX128x] Pass scan config by const reference * [PHY] Pass scan config by const reference * [SX127x] Add missing IRQ conversion * [SX126x] Fixed default CAD scan config IRQ * [LR11x0] Fixed default CAD scan config IRQ * [LR11x0] Fix comments referencing DIO1 --- .github/workflows/main.yml | 2 +- ...27x_Channel_Activity_Detection_Receive.ino | 4 +- src/TypeDef.h | 6 + src/modules/LR11x0/LR11x0.cpp | 102 ++++++---- src/modules/LR11x0/LR11x0.h | 36 ++-- src/modules/SX126x/SX126x.cpp | 156 +++++++-------- src/modules/SX126x/SX126x.h | 64 +++--- src/modules/SX127x/SX127x.cpp | 188 +++++++++++------- src/modules/SX127x/SX127x.h | 38 ++-- src/modules/SX128x/SX128x.cpp | 98 +++++---- src/modules/SX128x/SX128x.h | 47 ++++- src/protocols/LoRaWAN/LoRaWAN.cpp | 5 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 51 ++++- src/protocols/PhysicalLayer/PhysicalLayer.h | 161 +++++++++++++-- 14 files changed, 607 insertions(+), 351 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e2635a8bfb..063f259ed4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,7 +46,7 @@ jobs: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. include: - id: arduino:avr:uno - run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update|Pager)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update|Pager|APRS|Morse)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: | echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino index 35f9d40df0..f78d747a47 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -168,9 +168,9 @@ void loop() { // check if we got a preamble if(detectedFlag) { - // LoRa preamble was detected + // LoRa preamble was detected, start reception with timeout of 100 LoRa symbols Serial.print(F("[SX1278] Preamble detected, starting reception ... ")); - state = radio.startReceive(0, RADIOLIB_SX127X_RXSINGLE); + state = radio.startReceive(100); if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { diff --git a/src/TypeDef.h b/src/TypeDef.h index 55434cf12a..de6e06b6ea 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -615,6 +615,12 @@ */ typedef unsigned long RadioLibTime_t; +/*! + \brief Type used for radio-agnostic IRQ flags. IRQ to enable corresponds to the bit index (RadioLibIrq_t). + For example, if bit 0 is set, the module will enable its RADIOLIB_IRQ_TX_DONE (if it is supported). +*/ +typedef uint32_t RadioLibIrqFlags_t; + /*! \} */ diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index b1ebbc448e..1a0ac5a25a 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -11,6 +11,16 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { this->mod = mod; this->XTAL = false; + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR11X0_IRQ_RX_DONE; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR11X0_IRQ_HEADER_ERR; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR11X0_IRQ_CRC_ERR; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR11X0_IRQ_CAD_DONE; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR11X0_IRQ_CAD_DETECTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR11X0_IRQ_TIMEOUT; } int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { @@ -278,12 +288,23 @@ int16_t LR11x0::receiveDirect() { } int16_t LR11x0::scanChannel() { - return(this->scanChannel(RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT)); + ChannelScanConfig_t config = { + .cad = { + .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .detMin = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .exitMode = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->scanChannel(config)); } -int16_t LR11x0::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { +int16_t LR11x0::scanChannel(ChannelScanConfig_t config) { // set mode to CAD - int state = startChannelScan(symbolNum, detPeak, detMin); + int state = startChannelScan(config); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -460,10 +481,9 @@ int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa // set DIO mapping uint32_t irq = irqFlags; if(timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) { - irq |= RADIOLIB_LR11X0_IRQ_TIMEOUT; + irq |= (1UL << RADIOLIB_IRQ_TIMEOUT); } - - state = setDioIrqParams(irq); + state = setDioIrqParams(getIrqMapped(irq)); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -541,10 +561,21 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { } int16_t LR11x0::startChannelScan() { - return(this->startChannelScan(RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, RADIOLIB_LR11X0_CAD_PARAM_DEFAULT)); + ChannelScanConfig_t config = { + .cad = { + .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .detMin = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .exitMode = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->startChannelScan(config)); } -int16_t LR11x0::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { +int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &config) { // check active modem int16_t state = RADIOLIB_ERR_NONE; uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -562,7 +593,8 @@ int16_t LR11x0::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det this->mod->setRfSwitchState(Module::MODE_RX); // set DIO pin mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE); + uint16_t irqFlags = (config.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE : config.cad.irqFlags; + state = setDioIrqParams(irqFlags, irqFlags); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -570,7 +602,7 @@ int16_t LR11x0::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det RADIOLIB_ASSERT(state); // set mode to CAD - return(startCad(symbolNum, detPeak, detMin)); + return(startCad(config.cad.symNum, config.cad.detPeak, config.cad.detMin, config.cad.exitMode, config.cad.timeout)); } int16_t LR11x0::getChannelScanResult() { @@ -1322,39 +1354,16 @@ RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(timeout); } -int16_t LR11x0::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { - irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT; // flags that can appear in the IRQ register - irqMask = irqFlags; // on LR11x0, these are the same - return(RADIOLIB_ERR_NONE); +uint32_t LR11x0::getIrqFlags() { + return((uint32_t)this->getIrqStatus()); } -int16_t LR11x0::checkIrq(uint8_t irq) { - uint16_t flags = getIrqStatus(); - switch(irq) { - case RADIOLIB_IRQ_TX_DONE: - return(flags & RADIOLIB_LR11X0_IRQ_TX_DONE); - case RADIOLIB_IRQ_RX_DONE: - return(flags & RADIOLIB_LR11X0_IRQ_RX_DONE); - case RADIOLIB_IRQ_PREAMBLE_DETECTED: - return(flags & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED); - case RADIOLIB_IRQ_SYNC_WORD_VALID: - return(flags & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID); - case RADIOLIB_IRQ_HEADER_VALID: - return(flags & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID); - case RADIOLIB_IRQ_HEADER_ERR: - return(flags & RADIOLIB_LR11X0_IRQ_HEADER_ERR); - case RADIOLIB_IRQ_CRC_ERR: - return(flags & RADIOLIB_LR11X0_IRQ_CRC_ERR); - case RADIOLIB_IRQ_CAD_DONE: - return(flags & RADIOLIB_LR11X0_IRQ_CAD_DONE); - case RADIOLIB_IRQ_CAD_DETECTED: - return(flags & RADIOLIB_LR11X0_IRQ_CAD_DETECTED); - case RADIOLIB_IRQ_TIMEOUT: - return(flags & RADIOLIB_LR11X0_IRQ_TIMEOUT); - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - return(RADIOLIB_ERR_UNSUPPORTED); +int16_t LR11x0::setIrqFlags(uint32_t irq) { + return(this->setDioIrqParams(irq, irq)); +} + +int16_t LR11x0::clearIrqFlags(uint32_t irq) { + return(this->clearIrq(irq)); } uint8_t LR11x0::randomByte() { @@ -2008,7 +2017,7 @@ int16_t LR11x0::setPacketMode(uint8_t mode, uint8_t len) { return(state); } -int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { +int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); @@ -2035,9 +2044,16 @@ int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { min = 10; } + uint8_t mode = exitMode; + if(mode == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) { + mode = RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC; + } + + uint32_t timeout_raw = (float)timeout / 30.52f; + // set CAD parameters // TODO add configurable exit mode and timeout - state = setCadParams(num, peak, min, RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC, 0); + state = setCadParams(num, peak, min, mode, timeout_raw); RADIOLIB_ASSERT(state); // start CAD diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index dffac085fa..7c5737bd7a 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -844,12 +844,10 @@ class LR11x0: public PhysicalLayer { /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. - \param symbolNum Number of symbols for CAD detection. - \param detPeak Peak value for CAD detection. - \param detMin Minimum value for CAD detection. + \param config CAD configuration structure. \returns \ref status_codes */ - int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t scanChannel(ChannelScanConfig_t config) override; /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). @@ -979,14 +977,12 @@ class LR11x0: public PhysicalLayer { int16_t startChannelScan() override; /*! - \brief Interrupt-driven channel activity detection method. IRQ1 will be activated + \brief Interrupt-driven channel activity detection method. IRQ pin will be activated when LoRa preamble is detected, or upon timeout. - \param symbolNum Number of symbols for CAD detection. - \param detPeak Peak value for CAD detection. - \param detMin Minimum value for CAD detection. + \param config CAD configuration structure. \returns \ref status_codes */ - int16_t startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t startChannelScan(const ChannelScanConfig_t &config) override; /*! \brief Read the channel scan result @@ -1221,18 +1217,24 @@ class LR11x0: public PhysicalLayer { RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; /*! - \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks - \param irqFlags The flags for which IRQs must be triggered - \param irqMask Mask indicating which IRQ triggers a DIO + \brief Read currently active IRQ flags. + \returns IRQ flags. + */ + uint32_t getIrqFlags() override; + + /*! + \brief Set interrupt on IRQ pin to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; + int16_t setIrqFlags(uint32_t irq) override; /*! - \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). - \returns Whether requested IRQ is set. + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes */ - int16_t checkIrq(uint8_t irq) override; + int16_t clearIrqFlags(uint32_t irq) override; /*! \brief Get one truly random byte from RSSI noise. @@ -1618,7 +1620,7 @@ class LR11x0: public PhysicalLayer { bool findChip(uint8_t ver); int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); - int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); // common methods to avoid some copy-paste diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c6185e05b4..be314f6a9a 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -7,6 +7,16 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, this->mod = mod; this->XTAL = false; this->standbyXOSC = false; + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX126X_IRQ_TX_DONE; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX126X_IRQ_RX_DONE; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX126X_IRQ_HEADER_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_SX126X_IRQ_HEADER_ERR; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX126X_IRQ_CRC_ERR; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX126X_IRQ_CAD_DONE; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX126X_IRQ_CAD_DETECTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX126X_IRQ_TIMEOUT; } int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { @@ -317,7 +327,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { } // check whether this was a timeout or not - if((getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { + if((getIrqFlags() & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { standby(); fixImplicitTimeout(); clearIrqStatus(); @@ -425,12 +435,23 @@ int16_t SX126x::packetMode() { } int16_t SX126x::scanChannel() { - return(this->scanChannel(RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT)); -} - -int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + ChannelScanConfig_t config = { + .cad = { + .symNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .exitMode = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->scanChannel(config)); +} + +int16_t SX126x::scanChannel(ChannelScanConfig_t config) { // set mode to CAD - int state = startChannelScan(symbolNum, detPeak, detMin); + int state = startChannelScan(config); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -442,7 +463,6 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) return(getChannelScanResult()); } - int16_t SX126x::sleep() { return(SX126x::sleep(true)); } @@ -582,10 +602,10 @@ int16_t SX126x::finishTransmit() { } int16_t SX126x::startReceive() { - return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_SX126X_IRQ_RX_DEFAULT, RADIOLIB_SX126X_IRQ_RX_DONE, 0)); + return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t SX126x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { +int16_t SX126x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { (void)len; int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); RADIOLIB_ASSERT(state); @@ -599,7 +619,7 @@ int16_t SX126x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa return(state); } -int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags, uint16_t irqMask) { +int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) { // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay uint32_t transitionTime = this->tcxoDelay + 1000; sleepPeriod -= transitionTime; @@ -626,7 +646,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, u return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); } -int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, uint16_t irqFlags, uint16_t irqMask) { +int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) { if(senderPreambleLength == 0) { senderPreambleLength = this->preambleLengthLoRa; } @@ -664,12 +684,12 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ return(startReceiveDutyCycle(wakePeriod, sleepPeriod, irqFlags, irqMask)); } -int16_t SX126x::startReceiveCommon(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask) { +int16_t SX126x::startReceiveCommon(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) { // set DIO mapping if(timeout != RADIOLIB_SX126X_RX_TIMEOUT_INF) { - irqMask |= RADIOLIB_SX126X_IRQ_TIMEOUT; + irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); } - int16_t state = setDioIrqParams(irqFlags, irqMask); + int16_t state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask)); RADIOLIB_ASSERT(state); // set buffer pointers @@ -697,14 +717,14 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { // if that's the case, the first call will return "SPI command timeout error" // check the IRQ to be sure this really originated from timeout event int16_t state = this->mod->SPIcheckStream(); - if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqStatus() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { + if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqFlags() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { // this is definitely Rx timeout return(RADIOLIB_ERR_RX_TIMEOUT); } RADIOLIB_ASSERT(state); // check integrity CRC - uint16_t irq = getIrqStatus(); + uint16_t irq = getIrqFlags(); int16_t crcState = RADIOLIB_ERR_NONE; if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || (irq & RADIOLIB_SX126X_IRQ_HEADER_ERR)) { crcState = RADIOLIB_ERR_CRC_MISMATCH; @@ -732,10 +752,21 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { } int16_t SX126x::startChannelScan() { - return(this->startChannelScan(RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT, RADIOLIB_SX126X_CAD_PARAM_DEFAULT)); -} - -int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { + ChannelScanConfig_t config = { + .cad = { + .symNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .detMin = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .exitMode = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->startChannelScan(config)); +} + +int16_t SX126x::startChannelScan(const ChannelScanConfig_t &config) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -749,7 +780,7 @@ int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det this->mod->setRfSwitchState(Module::MODE_RX); // set DIO pin mapping - state = setDioIrqParams(RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE, RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE); + state = setDioIrqParams(getIrqMapped(config.cad.irqFlags), getIrqMapped(config.cad.irqMask)); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -757,7 +788,7 @@ int16_t SX126x::startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t det RADIOLIB_ASSERT(state); // set mode to CAD - state = setCad(symbolNum, detPeak, detMin); + state = setCad(config.cad.symNum, config.cad.detPeak, config.cad.detMin, config.cad.exitMode, config.cad.timeout); return(state); } @@ -768,7 +799,7 @@ int16_t SX126x::getChannelScanResult() { } // check CAD result - uint16_t cadResult = getIrqStatus(); + uint16_t cadResult = getIrqFlags(); if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DETECTED) { // detected some LoRa activity return(RADIOLIB_LORA_DETECTED); @@ -1460,39 +1491,18 @@ RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(timeout); } -int16_t SX126x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { - irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register - irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0 - return(RADIOLIB_ERR_NONE); +uint32_t SX126x::getIrqFlags() { + uint8_t data[] = { 0x00, 0x00 }; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); + return(((uint32_t)(data[0]) << 8) | data[1]); } -int16_t SX126x::checkIrq(uint8_t irq) { - uint16_t flags = getIrqStatus(); - switch(irq) { - case RADIOLIB_IRQ_TX_DONE: - return(flags & RADIOLIB_SX126X_IRQ_TX_DONE); - case RADIOLIB_IRQ_RX_DONE: - return(flags & RADIOLIB_SX126X_IRQ_RX_DONE); - case RADIOLIB_IRQ_PREAMBLE_DETECTED: - return(flags & RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED); - case RADIOLIB_IRQ_SYNC_WORD_VALID: - return(flags & RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID); - case RADIOLIB_IRQ_HEADER_VALID: - return(flags & RADIOLIB_SX126X_IRQ_HEADER_VALID); - case RADIOLIB_IRQ_HEADER_ERR: - return(flags & RADIOLIB_SX126X_IRQ_HEADER_ERR); - case RADIOLIB_IRQ_CRC_ERR: - return(flags & RADIOLIB_SX126X_IRQ_CRC_ERR); - case RADIOLIB_IRQ_CAD_DONE: - return(flags & RADIOLIB_SX126X_IRQ_CAD_DONE); - case RADIOLIB_IRQ_CAD_DETECTED: - return(flags & RADIOLIB_SX126X_IRQ_CAD_DETECTED); - case RADIOLIB_IRQ_TIMEOUT: - return(flags & RADIOLIB_SX126X_IRQ_TIMEOUT); - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - return(RADIOLIB_ERR_UNSUPPORTED); +int16_t SX126x::setIrqFlags(uint32_t irq) { + return(this->setDioIrqParams(irq, irq)); +} + +int16_t SX126x::clearIrqFlags(uint32_t irq) { + return(this->clearIrqStatus(irq)); } int16_t SX126x::implicitHeader(size_t len) { @@ -1761,8 +1771,7 @@ int16_t SX126x::setRx(uint32_t timeout) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } - -int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { +int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { // default CAD parameters are shown in Semtech AN1200.48, page 41. const uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30}; @@ -1773,29 +1782,17 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { this->spreadingFactor = 12; } - // build the packet + // build the packet with default configuration uint8_t data[7]; data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; data[1] = detPeakValues[this->spreadingFactor - 7]; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; - data[4] = 0x00; - data[5] = 0x00; - data[6] = 0x00; - - - /* - CAD Configuration Note: - The default CAD configuration applied by `scanChannel` overrides the optimal SF-specific configurations, leading to suboptimal detection. - I.e., anything that is not RADIOLIB_SX126X_CAD_PARAM_DEFAULT is overridden. But CAD settings are SF specific. - To address this, the user override has been commented out, ensuring consistent application of the optimal CAD settings as - per Semtech's Application Note AN1200.48 (page 41) for the 125KHz setting. This approach significantly reduces false CAD occurrences. - Testing has shown that there is no reason for a user to change CAD settings for anything other than most optimal ones described in AN1200.48 . - However, this change does not respect CAD configs from the LoRaWAN layer. Future considerations or use cases might require revisiting this decision. - Hence this note. -*/ + uint32_t timeout_raw = (float)timeout / 15.625f; + data[4] = (uint8_t)((timeout_raw >> 16) & 0xFF); + data[5] = (uint8_t)((timeout_raw >> 8) & 0xFF); + data[6] = (uint8_t)(timeout_raw & 0xFF); -/* // set user-provided values if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { data[0] = symbolNum; @@ -1809,10 +1806,9 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) { data[2] = detMin; } -*/ - (void)symbolNum; - (void)detPeak; - (void)detMin; + if(exitMode != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[3] = exitMode; + } // configure parameters int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); @@ -1859,12 +1855,6 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); } -uint16_t SX126x::getIrqStatus() { - uint8_t data[] = { 0x00, 0x00 }; - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2); - return(((uint16_t)(data[0]) << 8) | data[1]); -} - int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 68598650c3..143a25e0e0 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -222,7 +222,6 @@ #define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected #define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received #define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed -#define RADIOLIB_SX126X_IRQ_RX_DEFAULT 0b0000001001100010 // 14 0 default for Rx (RX_DONE, TIMEOUT, CRC_ERR and HEADER_ERR) #define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts #define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts @@ -533,18 +532,17 @@ class SX126x: public PhysicalLayer { /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + Configuration defaults to the values recommended by AN1200.48. \returns \ref status_codes */ int16_t scanChannel() override; /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. - \param symbolNum Number of symbols for CAD detection. Defaults to the value recommended by AN1200.48. - \param detPeak Peak value for CAD detection. Defaults to the value recommended by AN1200.48. - \param detMin Minimum value for CAD detection. Defaults to the value recommended by AN1200.48. + \param config CAD configuration structure. \returns \ref status_codes */ - int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t scanChannel(ChannelScanConfig_t config) override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). @@ -656,24 +654,26 @@ class SX126x: public PhysicalLayer { For any other value, timeout will be applied and signal will be generated on DIO1 for conditions defined by irqFlags and irqMask. - \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint32_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0); /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. Note that this function assumes the unit will take 500us + TCXO_delay to change state. See datasheet section 13.1.7, version 1.2. + \param rxPeriod The duration the receiver will be in Rx mode, in microseconds. \param sleepPeriod The duration the receiver will not be in Rx mode, in microseconds. - \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + + \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. \returns \ref status_codes */ - int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK); /*! \brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages. @@ -685,17 +685,11 @@ class SX126x: public PhysicalLayer { According to Semtech, receiver requires 8 symbols to reliably latch a preamble. This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1). - \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX126X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX126X_IRQ_RX_DONE. + \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. \returns \ref status_codes */ - int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); - - /*! - \brief Reads the current IRQ status. - \returns IRQ status bits - */ - uint16_t getIrqStatus(); + int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK); /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, @@ -717,12 +711,10 @@ class SX126x: public PhysicalLayer { /*! \brief Interrupt-driven channel activity detection method. DIO1 will be activated when LoRa preamble is detected, or upon timeout. - \param symbolNum Number of symbols for CAD detection. - \param detPeak Peak value for CAD detection. - \param detMin Minimum value for CAD detection. + \param config CAD configuration structure. \returns \ref status_codes */ - int16_t startChannelScan(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t startChannelScan(const ChannelScanConfig_t &config) override; /*! \brief Read the channel scan result @@ -989,18 +981,24 @@ class SX126x: public PhysicalLayer { RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; /*! - \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks - \param irqFlags The flags for which IRQs must be triggered - \param irqMask Mask indicating which IRQ triggers a DIO + \brief Read currently active IRQ flags. + \returns IRQ flags. + */ + uint32_t getIrqFlags() override; + + /*! + \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; + int16_t setIrqFlags(uint32_t irq) override; /*! - \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). - \returns Whether requested IRQ is set. + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes */ - int16_t checkIrq(uint8_t irq) override; + int16_t clearIrqFlags(uint32_t irq) override; /*! \brief Set implicit header mode for future reception/transmission. @@ -1160,7 +1158,7 @@ class SX126x: public PhysicalLayer { int16_t setFs(); int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); - int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin); + int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); @@ -1222,7 +1220,7 @@ class SX126x: public PhysicalLayer { int16_t config(uint8_t modem); bool findChip(const char* verStr); - int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE); + int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); int16_t directMode(); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 778dc9e935..b43bf6f3b6 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -12,6 +12,18 @@ int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWo this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + // set IRQ mapping - it is different for LoRa and FSK mode + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT; + // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); @@ -63,6 +75,18 @@ int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqD this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + // set IRQ mapping - it is different for LoRa and FSK mode + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_FLAG_PACKET_SENT << 8; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_FLAG_TIMEOUT << 0; + // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); @@ -193,7 +217,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set mode to receive - state = startReceive(len, RADIOLIB_SX127X_RXSINGLE); + state = startReceive(100, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len); RADIOLIB_ASSERT(state); // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout) @@ -211,13 +235,13 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { if(this->mod->getGpio() == RADIOLIB_NC) { // no GPIO pin provided, use software timeout if(this->mod->hal->millis() - start > timeout) { - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } } else { // GPIO provided, use that if(this->mod->hal->digitalRead(this->mod->getGpio())) { - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -229,7 +253,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; // set mode to receive - state = startReceive(len, RADIOLIB_SX127X_RX); + state = startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len); RADIOLIB_ASSERT(state); // wait for packet reception or timeout @@ -237,7 +261,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -362,21 +386,35 @@ int16_t SX127x::packetMode() { } int16_t SX127x::startReceive() { - return(this->startReceive(0, RADIOLIB_SX127X_RXCONTINUOUS)); + return(this->startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { +int16_t SX127x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { + uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS; + // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); + // set DIO pin mapping + state = this->setIrqFlags(getIrqMapped(irqFlags & irqMask)); + RADIOLIB_ASSERT(state); + int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { - // set DIO pin mapping + if(timeout != 0) { + // for non-zero timeout value, change mode to Rx single and set the timeout + mode = RADIOLIB_SX127X_RXSINGLE; + uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8); + uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym); + RADIOLIB_ASSERT(state); + } + + // in FHSS mode, enable channel change interrupt if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); - } else { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE | RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 7, 4); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4); } // set expected packet length for SF6 @@ -389,7 +427,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { RADIOLIB_ERRATA_SX127X(true); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set FIFO pointers state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); @@ -397,19 +435,11 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { RADIOLIB_ASSERT(state); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // set DIO pin mapping - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); - RADIOLIB_ASSERT(state); - // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // FSK modem does not distinguish between Rx single and continuous - if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_RX); - return(setMode(RADIOLIB_SX127X_RX)); - } + mode = RADIOLIB_SX127X_RX; } // set RF switch (if present) @@ -419,22 +449,6 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { return(setMode(mode)); } -int16_t SX127x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { - (void)irqFlags; - (void)irqMask; - uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS; - if(timeout != 0) { - // for non-zero timeout value, change mode to Rx single and set the timeout - mode = RADIOLIB_SX127X_RXSINGLE; - uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8); - uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF); - int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym); - RADIOLIB_ASSERT(state); - } - return(startReceive((uint8_t)len, mode)); -} - void SX127x::setDio0Action(void (*func)(void), uint32_t dir) { this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir); } @@ -571,7 +585,7 @@ int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ERRATA_SX127X(false); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set packet length state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); @@ -582,7 +596,7 @@ int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set DIO mapping if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { @@ -628,7 +642,7 @@ int16_t SX127x::finishTransmit() { mod->hal->delayMicroseconds(1000000/1200); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set mode to standby to disable transmitter/RF switch return(standby()); @@ -686,7 +700,7 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { this->packetLengthQueried = false; // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(state); } @@ -702,7 +716,7 @@ int16_t SX127x::startChannelScan() { RADIOLIB_ASSERT(state); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set DIO pin mapping state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); @@ -1295,36 +1309,66 @@ RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(numSymbols); } -int16_t SX127x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { - // IRQ flags/masks are inverted to what seems logical for SX127x (0 being activated, 1 being deactivated) - irqFlags = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT; - irqMask = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE & RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT; - return(RADIOLIB_ERR_NONE); +uint32_t SX127x::getIrqFlags() { + return((uint32_t)this->getIRQFlags()); } -int16_t SX127x::checkIrq(uint8_t irq) { - uint16_t flags = getIRQFlags(); - switch(irq) { - case RADIOLIB_IRQ_TX_DONE: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE); - case RADIOLIB_IRQ_RX_DONE: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE); - case RADIOLIB_IRQ_HEADER_VALID: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER); - case RADIOLIB_IRQ_CRC_ERR: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR); - case RADIOLIB_IRQ_CAD_DONE: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE); - case RADIOLIB_IRQ_CAD_DETECTED: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED); - case RADIOLIB_IRQ_TIMEOUT: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT); - default: - return(RADIOLIB_ERR_UNSUPPORTED); +int16_t SX127x::setIrqFlags(uint32_t irq) { + // this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ... + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + switch(irq) { + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE, 7, 6)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER, 1, 0)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR, 1, 0)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE, 7, 6)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 5, 4)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 5, 4)); + } + return(RADIOLIB_ERR_UNSUPPORTED); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + switch(irq) { + case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6)); + case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6)); + case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT, 7, 6)); + case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS, 3, 2)); + case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_TIMEOUT, 3, 2)); + } + return(RADIOLIB_ERR_UNSUPPORTED); } + return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t SX127x::clearIrqFlags(uint32_t irq) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, (uint8_t)irq); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, (uint8_t)irq); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, (uint8_t)(irq >> 8)); + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + int16_t SX127x::setCrcFiltering(bool enable) { this->crcOn = enable; @@ -1619,16 +1663,6 @@ int16_t SX127x::setActiveModem(uint8_t modem) { return(state); } -void SX127x::clearIRQFlags() { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, 0b11111111); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, 0b11111111); - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, 0b11111111); - } -} - void SX127x::clearFIFO(size_t count) { while(count) { this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index c00cd42f99..94db00ab62 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -160,7 +160,6 @@ #define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DONE 0b11111011 // 2 2 CAD complete #define RADIOLIB_SX127X_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL 0b11111101 // 1 1 FHSS change channel #define RADIOLIB_SX127X_MASK_IRQ_FLAG_CAD_DETECTED 0b11111110 // 0 0 valid LoRa signal detected during CAD operation -#define RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT 0b00011111 // 7 0 default for Rx (RX_TIMEOUT, RX_DONE, CRC_ERR) // RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR #define RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX 0b00000000 // 7 0 allocate the entire FIFO buffer for TX only @@ -500,6 +499,7 @@ #define RADIOLIB_SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received #define RADIOLIB_SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed #define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold +#define RADIOLIB_SX127X_FLAGS_ALL 0xFFFF // RADIOLIB_SX127X_REG_DIO_MAPPING_1 #define RADIOLIB_SX127X_DIO0_LORA_RX_DONE 0b00000000 // 7 6 @@ -812,27 +812,18 @@ class SX127x: public PhysicalLayer { */ int16_t startReceive() override; - /*! - \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. - \param len Expected length of packet to be received, or 0 when unused. - Defaults to 0, non-zero required for LoRa spreading factor 6. - \param mode Receive mode to be used. Defaults to RxContinuous. - \returns \ref status_codes - */ - int16_t startReceive(uint8_t len, uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS); - /*! \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. \param timeout Receive mode type and/or raw timeout value in symbols. When set to 0, the timeout will be infinite and the device will remain in Rx mode until explicitly commanded to stop (Rx continuous mode). When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set. - \param irqFlags Ignored. - \param irqMask Ignored. + \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. \param len Expected length of packet to be received. Required for LoRa spreading factor 6. \returns \ref status_codes */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override; + int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0) override; /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, @@ -1065,18 +1056,24 @@ class SX127x: public PhysicalLayer { RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; /*! - \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks - \param irqFlags The flags for which IRQs must be triggered - \param irqMask Mask indicating which IRQ triggers a DIO + \brief Read currently active IRQ flags. + \returns IRQ flags. + */ + uint32_t getIrqFlags() override; + + /*! + \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. \returns \ref status_codes */ - int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; + int16_t setIrqFlags(uint32_t irq) override; /*! - \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). - \returns Whether requested IRQ is set. + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes */ - int16_t checkIrq(uint8_t irq) override; + int16_t clearIrqFlags(uint32_t irq) override; /*! \brief Enable CRC filtering and generation. @@ -1257,7 +1254,6 @@ class SX127x: public PhysicalLayer { bool findChip(const uint8_t* vers, uint8_t num); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); - void clearIRQFlags(); void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read /*! diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 088644cca5..6ee188eba3 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -4,6 +4,16 @@ SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { this->mod = mod; + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX128X_IRQ_TX_DONE; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX128X_IRQ_RX_DONE; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX128X_IRQ_HEADER_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_SX128X_IRQ_HEADER_ERROR; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX128X_IRQ_CRC_ERROR; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX128X_IRQ_CAD_DONE; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX128X_IRQ_CAD_DETECTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; } int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) { @@ -411,8 +421,23 @@ int16_t SX128x::receiveDirect() { } int16_t SX128x::scanChannel() { + ChannelScanConfig_t config = { + .cad = { + .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT, + .detPeak = 0, + .detMin = 0, + .exitMode = 0, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->scanChannel(config)); +} + +int16_t SX128x::scanChannel(ChannelScanConfig_t config) { // set mode to CAD - int16_t state = startChannelScan(); + int16_t state = startChannelScan(config); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout @@ -558,10 +583,10 @@ int16_t SX128x::finishTransmit() { } int16_t SX128x::startReceive() { - return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT, RADIOLIB_SX128X_IRQ_RX_DONE, 0)); + return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t SX128x::startReceive(uint16_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { +int16_t SX128x::startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { (void)len; // check active modem @@ -571,10 +596,10 @@ int16_t SX128x::startReceive(uint16_t timeout, uint32_t irqFlags, uint32_t irqMa // set DIO mapping if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) { - irqMask |= RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT; + irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); } - int16_t state = setDioIrqParams(irqFlags, irqMask); + int16_t state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask)); RADIOLIB_ASSERT(state); // set buffer pointers @@ -638,36 +663,34 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { return(state); } -int16_t SX128x::checkIrq(uint8_t irq) { - uint16_t flags = getIrqStatus(); - switch(irq) { - case RADIOLIB_IRQ_TX_DONE: - return(flags & RADIOLIB_SX128X_IRQ_TX_DONE); - case RADIOLIB_IRQ_RX_DONE: - return(flags & RADIOLIB_SX128X_IRQ_RX_DONE); - case RADIOLIB_IRQ_PREAMBLE_DETECTED: - return(flags & RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED); - case RADIOLIB_IRQ_SYNC_WORD_VALID: - return(flags & RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID); - case RADIOLIB_IRQ_HEADER_VALID: - return(flags & RADIOLIB_SX128X_IRQ_HEADER_VALID); - case RADIOLIB_IRQ_HEADER_ERR: - return(flags & RADIOLIB_SX128X_IRQ_HEADER_ERROR); - case RADIOLIB_IRQ_CRC_ERR: - return(flags & RADIOLIB_SX128X_IRQ_CRC_ERROR); - case RADIOLIB_IRQ_CAD_DONE: - return(flags & RADIOLIB_SX128X_IRQ_CAD_DONE); - case RADIOLIB_IRQ_CAD_DETECTED: - return(flags & RADIOLIB_SX128X_IRQ_CAD_DETECTED); - case RADIOLIB_IRQ_TIMEOUT: - return(flags & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT); - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - return(RADIOLIB_ERR_UNSUPPORTED); +uint32_t SX128x::getIrqFlags() { + return((uint32_t)this->getIrqStatus()); +} + +int16_t SX128x::setIrqFlags(uint32_t irq) { + return(this->setDioIrqParams(irq, irq)); +} + +int16_t SX128x::clearIrqFlags(uint32_t irq) { + return(this->clearIrqStatus(irq)); } int16_t SX128x::startChannelScan() { + ChannelScanConfig_t config = { + .cad = { + .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT, + .detPeak = 0, + .detMin = 0, + .exitMode = 0, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->startChannelScan(config)); +} + +int16_t SX128x::startChannelScan(const ChannelScanConfig_t &config) { // check active modem if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -678,7 +701,7 @@ int16_t SX128x::startChannelScan() { RADIOLIB_ASSERT(state); // set DIO pin mapping - state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE); + state = setDioIrqParams(getIrqMapped(config.cad.irqFlags), getIrqMapped(config.cad.irqMask)); RADIOLIB_ASSERT(state); // clear interrupt flags @@ -689,7 +712,7 @@ int16_t SX128x::startChannelScan() { this->mod->setRfSwitchState(Module::MODE_RX); // set mode to CAD - return(setCad()); + return(setCad(config.cad.symNum)); } int16_t SX128x::getChannelScanResult() { @@ -1464,7 +1487,12 @@ int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); } -int16_t SX128x::setCad() { +int16_t SX128x::setCad(uint8_t symbolNum) { + // configure parameters + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, &symbolNum, 1); + RADIOLIB_ASSERT(state); + + // start CAD return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 43c1f41285..1e1dea1f0f 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -186,6 +186,7 @@ #define RADIOLIB_SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 #define RADIOLIB_SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 #define RADIOLIB_SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 +#define RADIOLIB_SX128X_CAD_PARAM_DEFAULT RADIOLIB_SX128X_CAD_ON_8_SYMB //RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS #define RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz @@ -327,7 +328,6 @@ #define RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid #define RADIOLIB_SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done #define RADIOLIB_SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done -#define RADIOLIB_SX128X_IRQ_RX_DEFAULT 0x4062 // 15 0 default for Rx (RX_DONE, RX_TX_TIMEOUT, CRC_ERROR and HEADER_ERROR) #define RADIOLIB_SX128X_IRQ_NONE 0x0000 // 15 0 none #define RADIOLIB_SX128X_IRQ_ALL 0xFFFF // 15 0 all @@ -457,6 +457,13 @@ class SX128x: public PhysicalLayer { */ int16_t scanChannel() override; + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \param config CAD configuration structure. + \returns \ref status_codes + */ + int16_t scanChannel(ChannelScanConfig_t config) override; + /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). Overload for PhysicalLayer compatibility. @@ -553,12 +560,12 @@ class SX128x: public PhysicalLayer { set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). If timeout other than infinite is set, signal will be generated on DIO1. - \param irqFlags Sets the IRQ flags, defaults to RADIOLIB_SX128X_IRQ_RX_DEFAULT. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RADIOLIB_SX128X_IRQ_RX_DONE. + \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. + \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. \param len Only for PhysicalLayer compatibility, not used. \returns \ref status_codes */ - int16_t startReceive(uint16_t timeout, uint32_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint32_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0); + int16_t startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0); /*! \brief Reads the current IRQ status. @@ -577,18 +584,40 @@ class SX128x: public PhysicalLayer { int16_t readData(uint8_t* data, size_t len) override; /*! - \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). - \returns Whether requested IRQ is set. + \brief Read currently active IRQ flags. + \returns IRQ flags. + */ + uint32_t getIrqFlags() override; + + /*! + \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + int16_t setIrqFlags(uint32_t irq) override; + + /*! + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes */ - int16_t checkIrq(uint8_t irq) override; + int16_t clearIrqFlags(uint32_t irq) override; /*! \brief Interrupt-driven channel activity detection method. DIO1 will be activated - when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. + when LoRa preamble is detected, or upon timeout. \returns \ref status_codes */ int16_t startChannelScan() override; + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. + \param config CAD configuration structure. + \returns \ref status_codes + */ + int16_t startChannelScan(const ChannelScanConfig_t &config) override; + /*! \brief Read the channel scan result \returns \ref status_codes @@ -837,7 +866,7 @@ class SX128x: public PhysicalLayer { int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); - int16_t setCad(); + int16_t setCad(uint8_t symbolNum); uint8_t getPacketType(); int16_t setRfFrequency(uint32_t frf); int16_t setTxParams(uint8_t pwr, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c27feaa4fd..a1f63a7d71 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1190,9 +1190,8 @@ int16_t LoRaWANNode::downlinkCommon() { RADIOLIB_ASSERT(state); // create the masks that are required for receiving downlinks - uint32_t irqFlags = 0; - uint32_t irqMask = 0; - this->phyLayer->irqRxDoneRxTimeout(irqFlags, irqMask); + RadioLibIrqFlags_t irqFlags = (1UL << RADIOLIB_IRQ_RX_DONE) | (1UL << RADIOLIB_IRQ_TIMEOUT); + RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 6953447c96..1a2c19f962 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -132,7 +132,7 @@ int16_t PhysicalLayer::startReceive() { return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { +int16_t PhysicalLayer::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { (void)timeout; (void)irqFlags; (void)irqMask; @@ -310,13 +310,44 @@ RadioLibTime_t PhysicalLayer::calculateRxTimeout(RadioLibTime_t timeoutUs) { return(0); } -int16_t PhysicalLayer::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { - (void)irqFlags; - (void)irqMask; +uint32_t PhysicalLayer::getIrqMapped(RadioLibIrqFlags_t irq) { + // iterate over all set bits and build the module-specific flags + uint32_t irqRaw = 0; + for(uint8_t i = 0; i < 8*(sizeof(RadioLibIrqFlags_t)); i++) { + if((irq & (uint32_t)(1UL << i)) && (this->irqMap[i] != RADIOLIB_IRQ_NOT_SUPPORTED)) { + irqRaw |= this->irqMap[i]; + } + } + + return(irqRaw); +} + +int16_t PhysicalLayer::checkIrq(RadioLibIrqType_t irq) { + if((irq > RADIOLIB_IRQ_TIMEOUT) || (this->irqMap[irq] == RADIOLIB_IRQ_NOT_SUPPORTED)) { + return(RADIOLIB_ERR_UNSUPPORTED); + } + + return(getIrqFlags() & this->irqMap[irq]); +} + +int16_t PhysicalLayer::setIrq(RadioLibIrqFlags_t irq) { + return(setIrqFlags(getIrqMapped(irq))); +} + +int16_t PhysicalLayer::clearIrq(RadioLibIrqFlags_t irq) { + return(clearIrqFlags(getIrqMapped(irq))); +} + +uint32_t PhysicalLayer::getIrqFlags() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::setIrqFlags(uint32_t irq) { + (void)irq; return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::checkIrq(uint8_t irq) { +int16_t PhysicalLayer::clearIrqFlags(uint32_t irq) { (void)irq; return(RADIOLIB_ERR_UNSUPPORTED); } @@ -325,6 +356,11 @@ int16_t PhysicalLayer::startChannelScan() { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::startChannelScan(const ChannelScanConfig_t &config) { + (void)config; + return(RADIOLIB_ERR_UNSUPPORTED); +} + int16_t PhysicalLayer::getChannelScanResult() { return(RADIOLIB_ERR_UNSUPPORTED); } @@ -333,6 +369,11 @@ int16_t PhysicalLayer::scanChannel() { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::scanChannel(ChannelScanConfig_t config) { + (void)config; + return(RADIOLIB_ERR_UNSUPPORTED); +} + int32_t PhysicalLayer::random(int32_t max) { if(max == 0) { return(0); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 408408aed7..0920076a48 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -4,17 +4,26 @@ #include "../../TypeDef.h" #include "../../Module.h" -// common IRQ flags -#define RADIOLIB_IRQ_TX_DONE 0x00 -#define RADIOLIB_IRQ_RX_DONE 0x01 -#define RADIOLIB_IRQ_PREAMBLE_DETECTED 0x02 -#define RADIOLIB_IRQ_SYNC_WORD_VALID 0x03 -#define RADIOLIB_IRQ_HEADER_VALID 0x04 -#define RADIOLIB_IRQ_HEADER_ERR 0x05 -#define RADIOLIB_IRQ_CRC_ERR 0x06 -#define RADIOLIB_IRQ_CAD_DONE 0x07 -#define RADIOLIB_IRQ_CAD_DETECTED 0x08 -#define RADIOLIB_IRQ_TIMEOUT 0x09 +// common IRQ values - the IRQ flags in RadioLibIrqFlags_t arguments are offset by this value +enum RadioLibIrqType_t { + RADIOLIB_IRQ_TX_DONE = 0x00, + RADIOLIB_IRQ_RX_DONE = 0x01, + RADIOLIB_IRQ_PREAMBLE_DETECTED = 0x02, + RADIOLIB_IRQ_SYNC_WORD_VALID = 0x03, + RADIOLIB_IRQ_HEADER_VALID = 0x04, + RADIOLIB_IRQ_HEADER_ERR = 0x05, + RADIOLIB_IRQ_CRC_ERR = 0x06, + RADIOLIB_IRQ_CAD_DONE = 0x07, + RADIOLIB_IRQ_CAD_DETECTED = 0x08, + RADIOLIB_IRQ_TIMEOUT = 0x09, + RADIOLIB_IRQ_NOT_SUPPORTED = 0x1F, // this must be the last value, intentionally set to 31 +}; + +// some commonly used default values - defined here to ensure all modules have the same default behavior +#define RADIOLIB_IRQ_RX_DEFAULT_FLAGS ((1UL << RADIOLIB_IRQ_RX_DONE) | (1UL << RADIOLIB_IRQ_TIMEOUT) | (1UL << RADIOLIB_IRQ_CRC_ERR) | (1UL << RADIOLIB_IRQ_HEADER_ERR)) +#define RADIOLIB_IRQ_RX_DEFAULT_MASK ((1UL << RADIOLIB_IRQ_RX_DONE)) +#define RADIOLIB_IRQ_CAD_DEFAULT_FLAGS ((1UL << RADIOLIB_IRQ_CAD_DETECTED) | (1UL << RADIOLIB_IRQ_CAD_DONE)) +#define RADIOLIB_IRQ_CAD_DEFAULT_MASK ((1UL << RADIOLIB_IRQ_CAD_DETECTED) | (1UL << RADIOLIB_IRQ_CAD_DONE)) /*! \struct LoRaRate_t @@ -39,7 +48,7 @@ struct FSKRate_t { /*! \brief FSK bit rate in kbps */ float bitRate; - /*! \brief FS frequency deviation in kHz*/ + /*! \brief FSK frequency deviation in kHz */ float freqDev; }; @@ -55,6 +64,54 @@ union DataRate_t { FSKRate_t fsk; }; +/*! + \struct CADScanConfig_t + \brief Channel scan configuration interpretation in case LoRa CAD is used +*/ +struct CADScanConfig_t { + /*! \brief Number of symbols to consider signal present */ + uint8_t symNum; + + /*! \brief Number of peak detection symbols */ + uint8_t detPeak; + + /*! \brief Number of minimum detection symbols */ + uint8_t detMin; + + /*! \brief Exit mode after signal detection is complete - module-specific value */ + uint8_t exitMode; + + /*! \brief Timeout in microseconds */ + RadioLibTime_t timeout; + + /*! \brief Optional IRQ flags to set, bits offset by the value of RADIOLIB_IRQ_ */ + RadioLibIrqFlags_t irqFlags; + + /*! \brief Optional IRQ mask to set, bits offset by the value of RADIOLIB_IRQ_ */ + RadioLibIrqFlags_t irqMask; +}; + +/*! + \struct RSSIScanConfig_t + \brief Channel scan configuration interpretation in case RSSI threshold is used +*/ +struct RSSIScanConfig_t { + /*! \brief RSSI limit in dBm */ + float limit; +}; + +/*! + \union ChannelScanConfig_t + \brief Common channel scan configuration structure +*/ +union ChannelScanConfig_t { + /*! \brief Interpretation for modems that use CAD (usually LoRa modems)*/ + CADScanConfig_t cad; + + /*! \brief Interpretation for modems that use RSSI threshold*/ + RSSIScanConfig_t rssi; +}; + /*! \class PhysicalLayer @@ -152,16 +209,16 @@ class PhysicalLayer { \param timeout Raw timeout value. Some modules use this argument to specify operation mode (single vs. continuous receive). \param irqFlags Sets the IRQ flags. - \param irqMask Sets the mask of IRQ flags that will trigger the DIO pin. + \param irqMask Sets the mask of IRQ flags that will trigger the radio interrupt pin. \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). \returns \ref status_codes */ - virtual int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len); + virtual int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len); /*! \brief Binary receive method. Must be implemented in module class. \param data Pointer to array to save the received binary data. - \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). \returns \ref status_codes */ virtual int16_t receive(uint8_t* data, size_t len); @@ -366,18 +423,59 @@ class PhysicalLayer { virtual RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs); /*! - \brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks. - \param irqFlags The flags for which IRQs must be triggered. - \param irqMask Mask indicating which IRQ triggers a DIO. - \returns \ref status_codes + \brief Convert from radio-agnostic IRQ flags to radio-specific flags. + \param irq Radio-agnostic IRQ flags. + \returns Flags for a specific radio module. */ - virtual int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask); + uint32_t getIrqMapped(RadioLibIrqFlags_t irq); /*! \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). - \returns Whether requested IRQ is set. + \param irq IRQ type to check, one of RADIOLIB_IRQ_*. + \returns 1 when requested IRQ is set, 0 when it is not or RADIOLIB_ERR_UNSUPPORTED if the IRQ is not supported. + */ + int16_t checkIrq(RadioLibIrqType_t irq); + + /*! + \brief Set interrupt on specific IRQ bit(s) (e.g. RxTimeout, CadDone). + Keep in mind that not all radio modules support all RADIOLIB_IRQ_ flags! + \param irq Flags to set, multiple bits may be enabled. IRQ to enable corresponds to the bit index (RadioLibIrq_t). + For example, if bit 0 is enabled, the module will enable its RADIOLIB_IRQ_TX_DONE (if it is supported). + \returns \ref status_codes + */ + int16_t setIrq(RadioLibIrqFlags_t irq); + + /*! + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + Keep in mind that not all radio modules support all RADIOLIB_IRQ_ flags! + \param irq Flags to set, multiple bits may be enabled. IRQ to enable corresponds to the bit index (RadioLibIrq_t). + For example, if bit 0 is enabled, the module will enable its RADIOLIB_IRQ_TX_DONE (if it is supported). + \returns \ref status_codes + */ + int16_t clearIrq(RadioLibIrqFlags_t irq); + + /*! + \brief Read currently active IRQ flags. + Must be implemented in module class. + \returns IRQ flags. */ - virtual int16_t checkIrq(uint8_t irq); + virtual uint32_t getIrqFlags(); + + /*! + \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + Must be implemented in module class. + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + virtual int16_t setIrqFlags(uint32_t irq); + + /*! + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + Must be implemented in module class. + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + virtual int16_t clearIrqFlags(uint32_t irq); /*! \brief Interrupt-driven channel activity detection method. Interrupt will be activated @@ -386,6 +484,14 @@ class PhysicalLayer { */ virtual int16_t startChannelScan(); + /*! + \brief Interrupt-driven channel activity detection method. interrupt will be activated + when packet is detected. Must be implemented in module class. + \param config Scan configuration structure. Interpretation depends on currently active modem. + \returns \ref status_codes + */ + virtual int16_t startChannelScan(const ChannelScanConfig_t &config); + /*! \brief Read the channel scan result \returns \ref status_codes @@ -400,6 +506,15 @@ class PhysicalLayer { */ virtual int16_t scanChannel(); + /*! + \brief Check whether the current communication channel is free or occupied. Performs CAD for LoRa modules, + or RSSI measurement for FSK modules. + \param config Scan configuration structure. Interpretation depends on currently active modem. + \returns RADIOLIB_CHANNEL_FREE when channel is free, + RADIOLIB_PREAMBLE_DETECTEDwhen occupied or other \ref status_codes. + */ + virtual int16_t scanChannel(ChannelScanConfig_t config); + /*! \brief Get truly random number in range 0 - max. \param max The maximum value of the random number (non-inclusive). @@ -531,6 +646,8 @@ class PhysicalLayer { #if !RADIOLIB_GODMODE protected: #endif + uint32_t irqMap[10] = { 0 }; + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void updateDirectBuffer(uint8_t bit); #endif From eda4ec22ae0039f3b9a2844d68ac2023ac0076a5 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sun, 1 Sep 2024 20:48:17 +0200 Subject: [PATCH 1230/1848] [SX126x][SX128x][LR11x0] Don't report CRC mismatch if valid header received (#1203) * Enable `HEADER_VALID` IRQ flags by default for receiving * [SX126x] Don't report CRC mismatch if valid header received * [SX128x] Don't report CRC mismatch if valid header received * [LR11x0] Don't report CRC mismatch if valid header received --- src/modules/LR11x0/LR11x0.cpp | 3 ++- src/modules/SX126x/SX126x.cpp | 3 ++- src/modules/SX128x/SX128x.cpp | 3 ++- src/protocols/PhysicalLayer/PhysicalLayer.h | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 1a0ac5a25a..3deac1c514 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -530,7 +530,8 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { // check integrity CRC uint32_t irq = getIrqStatus(); int16_t crcState = RADIOLIB_ERR_NONE; - if((irq & RADIOLIB_LR11X0_IRQ_CRC_ERR) || (irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR)) { + // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet) + if((irq & RADIOLIB_LR11X0_IRQ_CRC_ERR) || ((irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR) && !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID))) { crcState = RADIOLIB_ERR_CRC_MISMATCH; } diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index be314f6a9a..840b9f2d86 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -726,7 +726,8 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { // check integrity CRC uint16_t irq = getIrqFlags(); int16_t crcState = RADIOLIB_ERR_NONE; - if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || (irq & RADIOLIB_SX126X_IRQ_HEADER_ERR)) { + // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet) + if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || ((irq & RADIOLIB_SX126X_IRQ_HEADER_ERR) && !(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID))) { crcState = RADIOLIB_ERR_CRC_MISMATCH; } diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 6ee188eba3..250445a392 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -638,7 +638,8 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { // check integrity CRC uint16_t irq = getIrqStatus(); int16_t crcState = RADIOLIB_ERR_NONE; - if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || (irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR)) { + // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet) + if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || ((irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR) && !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID))) { crcState = RADIOLIB_ERR_CRC_MISMATCH; } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 0920076a48..3151b6166b 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -20,7 +20,7 @@ enum RadioLibIrqType_t { }; // some commonly used default values - defined here to ensure all modules have the same default behavior -#define RADIOLIB_IRQ_RX_DEFAULT_FLAGS ((1UL << RADIOLIB_IRQ_RX_DONE) | (1UL << RADIOLIB_IRQ_TIMEOUT) | (1UL << RADIOLIB_IRQ_CRC_ERR) | (1UL << RADIOLIB_IRQ_HEADER_ERR)) +#define RADIOLIB_IRQ_RX_DEFAULT_FLAGS ((1UL << RADIOLIB_IRQ_RX_DONE) | (1UL << RADIOLIB_IRQ_TIMEOUT) | (1UL << RADIOLIB_IRQ_CRC_ERR) | (1UL << RADIOLIB_IRQ_HEADER_VALID) | (1UL << RADIOLIB_IRQ_HEADER_ERR)) #define RADIOLIB_IRQ_RX_DEFAULT_MASK ((1UL << RADIOLIB_IRQ_RX_DONE)) #define RADIOLIB_IRQ_CAD_DEFAULT_FLAGS ((1UL << RADIOLIB_IRQ_CAD_DETECTED) | (1UL << RADIOLIB_IRQ_CAD_DONE)) #define RADIOLIB_IRQ_CAD_DEFAULT_MASK ((1UL << RADIOLIB_IRQ_CAD_DETECTED) | (1UL << RADIOLIB_IRQ_CAD_DONE)) From e0af297c76ef09df9fef6afcafe67196ab58957f Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 Sep 2024 18:22:43 +0200 Subject: [PATCH 1231/1848] [LR1110] Fix default startReceive flags --- src/modules/LR11x0/LR11x0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 3deac1c514..6d8ae12db7 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -460,7 +460,7 @@ int16_t LR11x0::finishTransmit() { } int16_t LR11x0::startReceive() { - return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE, 0, 0)); + return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { From 3115fc2d6700a9aee05888791ac930a910f2628f Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 Sep 2024 19:06:57 +0200 Subject: [PATCH 1232/1848] [LR11x0] Fix IRQ masking --- src/modules/LR11x0/LR11x0.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6d8ae12db7..4720591178 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -464,7 +464,6 @@ int16_t LR11x0::startReceive() { } int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { - (void)irqMask; (void)len; // check active modem @@ -479,11 +478,11 @@ int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa } // set DIO mapping - uint32_t irq = irqFlags; + uint32_t irq = irqMask; if(timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) { irq |= (1UL << RADIOLIB_IRQ_TIMEOUT); } - state = setDioIrqParams(getIrqMapped(irq)); + state = setDioIrqParams(getIrqMapped(irqFlags & irq)); RADIOLIB_ASSERT(state); // clear interrupt flags From 951bfc0625f966b8462be40318b9020558ed0a3e Mon Sep 17 00:00:00 2001 From: Jorropo Date: Sat, 7 Sep 2024 06:18:22 +0200 Subject: [PATCH 1233/1848] fix getRangingResult to properly account for signed numbers I got numbers like this as I approached the slave (raw values before converting to meters): ``` Ranged: 8 Ranged: 6 Ranged: 3 Ranged: 3 Ranged: 5 Ranged: 5 Ranged: 5 Ranged: 6 Ranged: 1 Ranged: 1 Ranged: 800000 Ranged: 800003 Ranged: 800003 ``` This is because the ToF becomes smaller than the correction factor resulting in a negative number. This patch performs Sign Extension from 24bits to 32bits. This result in returning a negative meter value which makes more sense than an impossibly big one. --- src/modules/SX128x/SX1280.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 7692c0a83d..a887b801af 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -176,7 +176,8 @@ float SX1280::getRangingResult() { RADIOLIB_ASSERT(state); // calculate the real result - uint32_t raw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; + uint32_t uraw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; + int32_t raw = (uraw & ((1<<23) - 1)) | (uraw >> 23 << 31); return((float)raw * 150.0 / (4.096 * this->bandwidthKhz)); } From 44d2ba8487b453ed9f006fcb550de5abbfbbfcf0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 07:17:50 +0200 Subject: [PATCH 1234/1848] [LR11x0] GNSS low level command fixes --- src/modules/LR11x0/LR11x0.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 4720591178..e441f6ab90 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2260,7 +2260,7 @@ int16_t LR11x0::clearIrq(uint32_t irq) { } int16_t LR11x0::configLfClock(uint8_t setup) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &setup, 1)); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK, true, &setup, 1)); } int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) { @@ -3229,7 +3229,8 @@ int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) { int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) { uint8_t buff[2] = { effort, opt }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, true, buff, sizeof(buff))); + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, buff, sizeof(buff), false, false)); } int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) { @@ -3238,9 +3239,22 @@ int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint3 // pass the replies if(err) { *err = buff[0]; } - if(time) { *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; } - if(nbUs) { *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } - if(timeAccuracy) { *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; } + + if(time) { + *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; + *time += 2UL*1024UL*7UL*24UL*3600UL; // assume WN rollover is at 2, this will fail sometime in 2038 + *time += 315964800UL; // convert to UTC + } + + if(nbUs) { + *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; + *nbUs /= 16; + } + + if(timeAccuracy) { + *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; + *timeAccuracy /= 16; + } return(state); } @@ -3340,7 +3354,8 @@ int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) { int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) { uint8_t buff[2] = { effort, bitMask }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, true, buff, sizeof(buff))); + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, buff, sizeof(buff), false, false)); } int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed) { @@ -3354,7 +3369,6 @@ int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint3 } int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) { - // TODO parse the reply into some structure return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53)); } @@ -3405,7 +3419,7 @@ int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskA uint8_t reqBuff[1] = { bitMask }; uint8_t rplBuff[8] = { 0 }; size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff)); + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff)); RADIOLIB_ASSERT(state); if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } From 3696672f6ffec2251f5aa0ea0d095d144fad3f84 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 18:58:46 +0200 Subject: [PATCH 1235/1848] [LR11x0] Remove WIP GNSS functionality (moved to branch) --- src/modules/LR11x0/LR11x0.cpp | 166 ---------------------------------- src/modules/LR11x0/LR11x0.h | 33 ------- 2 files changed, 199 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index e441f6ab90..38d3298c4f 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1684,172 +1684,6 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat return(state); } -int16_t LR11x0::isGnssScanCapable() { - // get the version - LR11x0VersionInfo_t version; - int16_t state = this->getVersionInfo(&version); - RADIOLIB_ASSERT(state); - - // check the device firmware version is sufficient - uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; - state = RADIOLIB_ERR_UNSUPPORTED; - if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { - state = RADIOLIB_ERR_NONE; - } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { - state = RADIOLIB_ERR_NONE; - } - RADIOLIB_ASSERT(state); - - // in debug mode, dump the almanac - #if RADIOLIB_DEBUG_BASIC - uint32_t addr = 0; - uint16_t sz = 0; - state = this->gnssAlmanacReadAddrSize(&addr, &sz); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz); - uint32_t buff[32] = { 0 }; - while(sz > 0) { - size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); - state = this->readRegMem32(addr, buff, len); - RADIOLIB_ASSERT(state); - Module::hexdump(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr); - addr += len*sizeof(uint32_t); - sz -= len*sizeof(uint32_t); - } - - uint8_t almanac[22] = { 0 }; - for(uint8_t i = 0; i < 128; i++) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i); - state = this->gnssAlmanacReadSV(i, almanac); - RADIOLIB_ASSERT(state); - Module::hexdump(NULL, almanac, 22); - } - - #endif - - return(state); -} - -int16_t LR11x0::gnssScan(uint16_t* resSize) { - // go to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE); - RADIOLIB_ASSERT(state); - - state = this->gnssSetConstellationToUse(0x03); - RADIOLIB_ASSERT(state); - - // set scan mode (single vs multiple) - state = this->gnssSetMode(0x03); - RADIOLIB_ASSERT(state); - - // start scan with high effort - RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start"); - state = this->gnssPerformScan(0x01, 0x3C, 8); - RADIOLIB_ASSERT(state); - - // wait for scan finished or timeout - RadioLibTime_t softTimeout = 300UL * 1000UL; - RadioLibTime_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start > softTimeout) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); - this->standby(); - return(RADIOLIB_ERR_RX_TIMEOUT); - } - } - - RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); - - state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); - RADIOLIB_ASSERT(state); - - int8_t status = 0; - uint8_t info = 0; - state = this->gnssReadDemodStatus(&status, &info); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)status, (unsigned int)info); - - uint8_t fwVersion = 0; - uint32_t almanacCrc = 0; - uint8_t errCode = 0; - uint8_t almUpdMask = 0; - uint8_t freqSpace = 0; - state = this->gnssGetContextStatus(&fwVersion, &almanacCrc, &errCode, &almUpdMask, &freqSpace); - RADIOLIB_DEBUG_BASIC_PRINTLN("Context status fwVersion %d, almanacCrc %lx, errCode %d, almUpdMask %d, freqSpace %d", - (int)fwVersion, (unsigned long)almanacCrc, (int)errCode, (int)almUpdMask, (int)freqSpace); - RADIOLIB_ASSERT(state); - - uint8_t stat[53] = { 0 }; - state = this->gnssReadAlmanacStatus(stat); - RADIOLIB_ASSERT(state); - //Module::hexdump(NULL, stat, 53); - - return(this->gnssGetResultSize(resSize)); -} - -int16_t LR11x0::getGnssScanResult(uint16_t size) { - uint32_t timing[31] = { 0 }; - uint8_t constDemod = 0; - int16_t state = this->gnssReadCumulTiming(timing, &constDemod); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Timing:"); - for(size_t i = 0; i < 31; i++) { - uint32_t t = (timing[i] * 1000UL) / 32768UL; - (void)t; - RADIOLIB_DEBUG_BASIC_PRINTLN(" %d: %lu ms", (int)i*4, (unsigned long)t); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("constDemod: %d", constDemod); - - uint8_t nbSv = 0; - state = this->gnssGetNbSvDetected(&nbSv); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Detected %d SVs:", nbSv); - - uint8_t svId[32] = { 0 }; - uint8_t snr[32] = { 0 }; - int16_t doppler[32] = { 0 }; - state = this->gnssGetSvDetected(svId, snr, doppler, nbSv); - RADIOLIB_ASSERT(state); - for(size_t i = 0; i < nbSv; i++) { - RADIOLIB_DEBUG_BASIC_PRINTLN(" SV %d: C/N0 %i dB, Doppler %i Hz", (int)i, snr[i] + 31, doppler[i]); - } - - float lat = 0; - float lon = 0; - state = this->gnssReadAssistancePosition(&lat, &lon); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("lat = %.5f, lon = %.5f", lat, lon); - - // read the result - uint8_t res[256] = { 0 }; - state = this->gnssReadResults(res, size); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Result type: %02x", (int)res[0]); - - return(state); -} - -int16_t LR11x0::getGnssPosition(float* lat, float* lon, bool filtered) { - uint8_t error = 0; - uint8_t nbSvUsed = 0; - uint16_t accuracy = 0; - int16_t state; - if(filtered) { - state = this->gnssReadDopplerSolverRes(&error, &nbSvUsed, NULL, NULL, NULL, NULL, lat, lon, &accuracy, NULL); - } else { - state = this->gnssReadDopplerSolverRes(&error, &nbSvUsed, lat, lon, &accuracy, NULL, NULL, NULL, NULL, NULL); - } - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Solver error %d, nbSvUsed %d, accuracy = %u", (int)error, (int)nbSvUsed, (unsigned int)accuracy); - - return(state); -} - int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 7c5737bd7a..43cefde39b 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1375,39 +1375,6 @@ class LR11x0: public PhysicalLayer { */ int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true); - /*! - \brief Method to check whether the device is capable of performing a GNSS scan. - CAUTION: Work in progress! Most data is returned via debug prints. - \returns \ref status_codes - */ - int16_t isGnssScanCapable(); - - /*! - \brief Performs GNSS scan. - CAUTION: Work in progress! Most data is returned via debug prints. - \param resSize Pointer to a variable in which the result size will be saved. - \returns \ref status_codes - */ - int16_t gnssScan(uint16_t* resSize); - - /*! - \brief Get GNSS scan result. - CAUTION: Work in progress! Most data is returned via debug prints. - \param size Result size to read. - \returns \ref status_codes - */ - int16_t getGnssScanResult(uint16_t size); - - /*! - \brief Get GNSS position. - CAUTION: Work in progress! Most data is returned via debug prints. - \param lat Pointer to a variable where latitude in degrees will be saved. - \param lon Pointer to a variable where longitude in degrees will be saved. - \param filtered Whether to save the filtered, or unfiltered value. Defaults to true (filtered). - \returns \ref status_codes - */ - int16_t getGnssPosition(float* lat, float* lon, bool filtered = true); - #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif From c4a129ed742a5fb3e3dc55cd4d067dc06ff78f0b Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 19:18:56 +0200 Subject: [PATCH 1236/1848] [PHY] Pass scan config by reference --- src/modules/LR11x0/LR11x0.cpp | 2 +- src/modules/LR11x0/LR11x0.h | 2 +- src/modules/SX126x/SX126x.cpp | 2 +- src/modules/SX126x/SX126x.h | 2 +- src/modules/SX128x/SX128x.cpp | 2 +- src/modules/SX128x/SX128x.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 38d3298c4f..80a3c0081c 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -302,7 +302,7 @@ int16_t LR11x0::scanChannel() { return(this->scanChannel(config)); } -int16_t LR11x0::scanChannel(ChannelScanConfig_t config) { +int16_t LR11x0::scanChannel(const ChannelScanConfig_t &config) { // set mode to CAD int state = startChannelScan(config); RADIOLIB_ASSERT(state); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 43cefde39b..e5a7baf62b 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -847,7 +847,7 @@ class LR11x0: public PhysicalLayer { \param config CAD configuration structure. \returns \ref status_codes */ - int16_t scanChannel(ChannelScanConfig_t config) override; + int16_t scanChannel(const ChannelScanConfig_t &config) override; /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 840b9f2d86..f94481a001 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -449,7 +449,7 @@ int16_t SX126x::scanChannel() { return(this->scanChannel(config)); } -int16_t SX126x::scanChannel(ChannelScanConfig_t config) { +int16_t SX126x::scanChannel(const ChannelScanConfig_t &config) { // set mode to CAD int state = startChannelScan(config); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 143a25e0e0..521921da04 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -542,7 +542,7 @@ class SX126x: public PhysicalLayer { \param config CAD configuration structure. \returns \ref status_codes */ - int16_t scanChannel(ChannelScanConfig_t config) override; + int16_t scanChannel(const ChannelScanConfig_t &config) override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 250445a392..8fc395bf56 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -435,7 +435,7 @@ int16_t SX128x::scanChannel() { return(this->scanChannel(config)); } -int16_t SX128x::scanChannel(ChannelScanConfig_t config) { +int16_t SX128x::scanChannel(const ChannelScanConfig_t &config) { // set mode to CAD int16_t state = startChannelScan(config); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 1e1dea1f0f..eab6eafc61 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -462,7 +462,7 @@ class SX128x: public PhysicalLayer { \param config CAD configuration structure. \returns \ref status_codes */ - int16_t scanChannel(ChannelScanConfig_t config) override; + int16_t scanChannel(const ChannelScanConfig_t &config) override; /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 1a2c19f962..5176073c90 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -369,7 +369,7 @@ int16_t PhysicalLayer::scanChannel() { return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::scanChannel(ChannelScanConfig_t config) { +int16_t PhysicalLayer::scanChannel(const ChannelScanConfig_t &config) { (void)config; return(RADIOLIB_ERR_UNSUPPORTED); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 3151b6166b..aa8fc710c6 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -513,7 +513,7 @@ class PhysicalLayer { \returns RADIOLIB_CHANNEL_FREE when channel is free, RADIOLIB_PREAMBLE_DETECTEDwhen occupied or other \ref status_codes. */ - virtual int16_t scanChannel(ChannelScanConfig_t config); + virtual int16_t scanChannel(const ChannelScanConfig_t &config); /*! \brief Get truly random number in range 0 - max. From aadfd0c48c6eda7c6958440307bacdc95f14e743 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 19:19:22 +0200 Subject: [PATCH 1237/1848] [PHY] Added LR-FHSS DataRate_t --- src/protocols/PhysicalLayer/PhysicalLayer.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index aa8fc710c6..b4218b5e95 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -52,6 +52,18 @@ struct FSKRate_t { float freqDev; }; +/*! + \struct LrFhssRate_t + \brief Data rate structure interpretation in case LR-FHSS is used +*/ +struct LrFhssRate_t { + /*! \brief Bandwidth */ + uint8_t bw; + + /*! \brief Coding rate */ + uint8_t cr; +}; + /*! \union DataRate_t \brief Common data rate structure From 9fb427d041fa77ba3a99459122fdf7388e34d9d0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 19:21:05 +0200 Subject: [PATCH 1238/1848] [SX128x] Fix unspecified integer width in ranging calculation --- src/modules/SX128x/SX1280.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index a887b801af..fae3516bf5 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -177,7 +177,7 @@ float SX1280::getRangingResult() { // calculate the real result uint32_t uraw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; - int32_t raw = (uraw & ((1<<23) - 1)) | (uraw >> 23 << 31); + int32_t raw = (uraw & ((1UL << 23) - 1)) | (uraw >> 23 << 31); return((float)raw * 150.0 / (4.096 * this->bandwidthKhz)); } From 4263a572b1ce36e4da7809949e5d1256b21b46de Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 19:21:37 +0200 Subject: [PATCH 1239/1848] [CI] Check for performance issues in cppcheck --- extras/cppcheck/cppcheck.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extras/cppcheck/cppcheck.sh b/extras/cppcheck/cppcheck.sh index d5906e1871..fe48a40c79 100755 --- a/extras/cppcheck/cppcheck.sh +++ b/extras/cppcheck/cppcheck.sh @@ -8,8 +8,9 @@ echo "Cppcheck finished with exit code $?" error=$(grep ": error:" $file | wc -l) warning=$(grep ": warning:" $file | wc -l) style=$(grep ": style:" $file | wc -l) -echo "found $error erros, $warning warnings and $style style issues" -if [ $error -gt "0" ] || [ $warning -gt "0" ] || [ $style -gt "0" ] +performance=$(grep ": performance:" $file | wc -l) +echo "found $error erros, $warning warnings, $style style and $performance performance issues" +if [ $error -gt "0" ] || [ $warning -gt "0" ] || [ $style -gt "0" ] || [ $performance -gt "0" ] then cat $file exitcode=1 From 47b8df68740e933dfa050326dff3daec4bc64d30 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 19:23:30 +0200 Subject: [PATCH 1240/1848] [LR11x0] Added ping-pong example --- .../LR11x0_PingPong/LR11x0_PingPong.ino | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino diff --git a/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino b/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino new file mode 100644 index 0000000000..b494a3c2d4 --- /dev/null +++ b/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino @@ -0,0 +1,166 @@ +/* + RadioLib LR11x0 Ping-Pong Example + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// uncomment the following only on one +// of the nodes to initiate the pings +//#define INITIATING_NODE + +// LR1110 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5 and DIO6 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, + END_OF_MODE_TABLE, +}; + +// save transmission states between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// flag to indicate transmission or reception state +bool transmitFlag = false; + +// flag to indicate that a packet was sent or received +volatile bool operationDone = false; + +// this function is called when a complete packet +// is transmitted or received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent or received a packet, set the flag + operationDone = true; +} + +void setup() { + Serial.begin(9600); + + // set RF switch control configuration + // this has to be done prior to calling begin() + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when new packet is received + radio.setIrqAction(setFlag); + + #if defined(INITIATING_NODE) + // send the first packet on this node + Serial.print(F("[LR1110] Sending first packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + #else + // start listening for LoRa packets on this node + Serial.print(F("[LR1110] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + #endif +} + +void loop() { + // check if the previous operation finished + if(operationDone) { + // reset flag + operationDone = false; + + if(transmitFlag) { + // the previous operation was transmission, listen for response + // print the result + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // listen for response + radio.startReceive(); + transmitFlag = false; + + } else { + // the previous operation was reception + // print data and send another packet + String str; + int state = radio.readData(str); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[LR1110] Received packet!")); + + // print data of the packet + Serial.print(F("[LR1110] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LR1110] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LR1110] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[LR1110] Sending another packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + } + + } +} From 50996fa66125e6f9d26ea24775bfce33334dbc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Tue, 10 Sep 2024 20:30:01 +0200 Subject: [PATCH 1241/1848] [CI] Arduino platform versions & ESP32 3.0.x workaround (#1213) * [CI] Add configurable package version * [CI] Fix package version passing * [CI] Fix swapped logic * [CI] Try esp32 arduino 2.0.17 to fix linker errors --- .github/workflows/main.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 063f259ed4..b933b93581 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -79,6 +79,7 @@ jobs: - id: esp32:esp32:esp32 run: | python -m pip install pyserial + echo "version=2.0.17" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT - id: esp8266:esp8266:generic run: | @@ -166,7 +167,11 @@ jobs: run: | arduino-cli core update-index ${{ format('{0}', steps.prep.outputs.index-url) }} - arduino-cli core install ${{ format('{0}:{1} {2}', steps.split.outputs._0, steps.split.outputs._1, steps.prep.outputs.index-url) }} + if [ -z '${{ steps.prep.outputs.version }}' ]; then + arduino-cli core install ${{ format('{0}:{1} {2}', steps.split.outputs._0, steps.split.outputs._1, steps.prep.outputs.index-url) }} + else + arduino-cli core install ${{ format('{0}:{1}@{3} {2}', steps.split.outputs._0, steps.split.outputs._1, steps.prep.outputs.index-url, steps.prep.outputs.version) }} + fi - name: Checkout repository if: ${{ env.run-build == 'true' }} From f7f0b62e7f22f098019446bab6862ba7ad1e2d94 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:11:16 +0200 Subject: [PATCH 1242/1848] [LoRaWAN] Major rework (#1204) * [LoRaWAN] Major rework * [LoRaWAN] Some CI fixes, add retransmission timeout * [LoRaWAN] CI fixes * [LoRaWAN] Add missing initializers * [LoRaWAN] Return Rx window number, fix casing * [LoRaWAN] Un-static functions to fix overriding * [LoRaWAN] Integrate feedback, fix session save/restore * [LoRaWAN] Add const * [LoRaWAN] Do not accept invalid Rx2 datarate * [LoRaWAN] Integrate feedback * [LoRaWAN] Fix retransmission, ADR backoff, setDatarate; reject out-of-band frequencies * Update keywords.txt * [LoRaWAN] Fix initial datarate, misc cleanup * [LoRaWAN] Update examples * [LoRaWAN] Update README * [LoRaWAN] Reject oversized downlinks * [LoRaWAN] Remove VLAs * [LoRaWAN] CI fixes * [LoRaWAN] More CI * [LoRaWAN] Fix getMaxPayloadLen * [LoRaWAN] Rename some status codes * [CI] Skip LoRaWAN on XMega48 * [CI] Skip FW update for LR11x0 --------- Co-authored-by: jgromes --- .github/workflows/main.yml | 3 +- examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino | 20 +- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 12 +- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 52 +- examples/LoRaWAN/LoRaWAN_Reference/config.h | 12 +- .../LoRaWAN_Starter/LoRaWAN_Starter.ino | 19 +- examples/LoRaWAN/LoRaWAN_Starter/config.h | 12 +- examples/LoRaWAN/README.md | 25 +- keywords.txt | 40 +- src/TypeDef.h | 10 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 4443 +++++++++-------- src/protocols/LoRaWAN/LoRaWAN.h | 788 +-- src/protocols/LoRaWAN/LoRaWANBands.cpp | 651 ++- 13 files changed, 3356 insertions(+), 2731 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b933b93581..e6da05ace2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -83,6 +83,7 @@ jobs: echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT - id: esp8266:esp8266:generic run: | + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - id: SparkFun:apollo3:sfe_artemis @@ -107,7 +108,7 @@ jobs: - id: MegaCoreX:megaavr:4809 run: | echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT - echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT + echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update|LoRaWAN)" >> $GITHUB_OUTPUT - id: arduino:mbed_rp2040:pico - id: rp2040:rp2040:rpipico run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT diff --git a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino index 0fa63de258..1442e0d4b3 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino +++ b/examples/LoRaWAN/LoRaWAN_ABP/LoRaWAN_ABP.ino @@ -10,12 +10,12 @@ After your device is registered, you can run this example. The device will join the network and start uploading data. - LoRaWAN v1.1 requires the use of persistent storage. + LoRaWAN v1.0.4/v1.1 requires the use of persistent storage. As this example does not use persistent storage, running this examples REQUIRES you to check "Resets frame counters" on your LoRaWAN dashboard. Refer to the notes or the network's documentation on how to do this. - To comply with LoRaWAN v1.1's persistent storage, refer to + To comply with LoRaWAN's persistent storage, refer to https://github.com/radiolib-org/radiolib-persistence For default module settings, see the wiki page @@ -66,8 +66,20 @@ void loop() { // Perform an uplink int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); - debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); + + // Check if a downlink was received + // (state 0 = no downlink, state 1/2 = downlink in window Rx1/Rx2) + if(state > 0) { + Serial.println(F("Received a downlink")); + } else { + Serial.println(F("No downlink received")); + } + + Serial.print(F("Next uplink in ")); + Serial.print(uplinkIntervalSeconds); + Serial.println(F(" seconds\n")); // Wait until next uplink - observing legal & TTN FUP constraints - delay(uplinkIntervalSeconds * 1000UL); + delay(uplinkIntervalSeconds * 1000UL); // delay needs milli-seconds } diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index ac7421803a..61bc63e0f3 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -110,16 +110,16 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; case RADIOLIB_ERR_CHECKSUM_MISMATCH: return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; - case RADIOLIB_LORAWAN_NO_DOWNLINK: - return "RADIOLIB_LORAWAN_NO_DOWNLINK"; + case RADIOLIB_ERR_NO_JOIN_ACCEPT: + return "RADIOLIB_ERR_NO_JOIN_ACCEPT"; case RADIOLIB_LORAWAN_SESSION_RESTORED: return "RADIOLIB_LORAWAN_SESSION_RESTORED"; case RADIOLIB_LORAWAN_NEW_SESSION: return "RADIOLIB_LORAWAN_NEW_SESSION"; - case RADIOLIB_LORAWAN_NONCES_DISCARDED: - return "RADIOLIB_LORAWAN_NONCES_DISCARDED"; - case RADIOLIB_LORAWAN_SESSION_DISCARDED: - return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; + case RADIOLIB_ERR_NONCES_DISCARDED: + return "RADIOLIB_ERR_NONCES_DISCARDED"; + case RADIOLIB_ERR_SESSION_DISCARDED: + return "RADIOLIB_ERR_SESSION_DISCARDED"; } return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; } diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 54e0c2be28..28b2946794 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -10,11 +10,11 @@ Also, most of the possible and available functions are shown here for reference. - LoRaWAN v1.1 requires the use of EEPROM (persistent storage). + LoRaWAN v1.0.4/v1.1 requires the use of EEPROM (persistent storage). Running this examples REQUIRES you to check "Resets DevNonces" on your LoRaWAN dashboard. Refer to the notes or the network's documentation on how to do this. - To comply with LoRaWAN v1.1's persistent storage, refer to + To comply with LoRaWAN's persistent storage, refer to https://github.com/radiolib-org/radiolib-persistence For default module settings, see the wiki page @@ -59,11 +59,11 @@ void setup() { Serial.print("[LoRaWAN] DevAddr: "); Serial.println((unsigned long)node.getDevAddr(), HEX); - // Disable the ADR algorithm (on by default which is preferable) - node.setADR(false); + // Enable the ADR algorithm (on by default which is preferable) + node.setADR(true); - // Set a fixed datarate - node.setDatarate(4); + // Set a datarate to start off with + node.setDatarate(5); // Manages uplink intervals to the TTN Fair Use Policy node.setDutyCycle(true, 1250); @@ -105,25 +105,28 @@ void loop() { LoRaWANEvent_t uplinkDetails; LoRaWANEvent_t downlinkDetails; - uint8_t Port = 10; + uint8_t fPort = 10; // Retrieve the last uplink frame counter - uint32_t fcntUp = node.getFCntUp(); + uint32_t fCntUp = node.getFCntUp(); - // Send a confirmed uplink every 64th frame + // Send a confirmed uplink on the second uplink // and also request the LinkCheck and DeviceTime MAC commands - if(fcntUp % 64 == 0) { - Serial.println(F("[LoRaWAN] Requesting LinkCheck and DeviceTime")); + Serial.println(F("Sending uplink")); + if(fCntUp == 1) { + Serial.println(F("and requesting LinkCheck and DeviceTime")); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); - state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails); + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), fPort, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails); } else { - state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize); + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), fPort, downlinkPayload, &downlinkSize, false, &uplinkDetails, &downlinkDetails); } - debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); - // Check if downlink was received - if(state != RADIOLIB_LORAWAN_NO_DOWNLINK) { + // Check if a downlink was received + // (state 0 = no downlink, state 1/2 = downlink in window Rx1/Rx2) + if(state > 0) { + Serial.println(F("Received a downlink")); // Did we get a downlink with data for us if(downlinkSize > 0) { Serial.println(F("Downlink data: ")); @@ -142,11 +145,6 @@ void loop() { Serial.print(radio.getSNR()); Serial.println(F(" dB")); - // print frequency error - Serial.print(F("[LoRaWAN] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); - // print extra information about the event Serial.println(F("[LoRaWAN] Event information:")); Serial.print(F("[LoRaWAN] Confirmed:\t")); @@ -158,13 +156,15 @@ void loop() { Serial.print(F("[LoRaWAN] Frequency:\t")); Serial.print(downlinkDetails.freq, 3); Serial.println(F(" MHz")); - Serial.print(F("[LoRaWAN] Output power:\t")); - Serial.print(downlinkDetails.power); - Serial.println(F(" dBm")); Serial.print(F("[LoRaWAN] Frame count:\t")); Serial.println(downlinkDetails.fCnt); Serial.print(F("[LoRaWAN] Port:\t\t")); Serial.println(downlinkDetails.fPort); + Serial.print(F("[LoRaWAN] Time-on-air: \t")); + Serial.print(node.getLastToA()); + Serial.println(F(" ms")); + Serial.print(F("[LoRaWAN] Rx window: \t")); + Serial.println(state); uint8_t margin = 0; uint8_t gwCnt = 0; @@ -184,6 +184,8 @@ void loop() { Serial.println(fracSecond); } + } else { + Serial.println(F("[LoRaWAN] No downlink received")); } // wait before sending another packet @@ -193,7 +195,7 @@ void loop() { Serial.print(F("[LoRaWAN] Next uplink in ")); Serial.print(delayMs/1000); - Serial.println(F("s")); + Serial.println(F(" seconds\n")); delay(delayMs); } diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index 65be0af97f..21c79f8ee3 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -105,16 +105,16 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; case RADIOLIB_ERR_CHECKSUM_MISMATCH: return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; - case RADIOLIB_LORAWAN_NO_DOWNLINK: - return "RADIOLIB_LORAWAN_NO_DOWNLINK"; + case RADIOLIB_ERR_NO_JOIN_ACCEPT: + return "RADIOLIB_ERR_NO_JOIN_ACCEPT"; case RADIOLIB_LORAWAN_SESSION_RESTORED: return "RADIOLIB_LORAWAN_SESSION_RESTORED"; case RADIOLIB_LORAWAN_NEW_SESSION: return "RADIOLIB_LORAWAN_NEW_SESSION"; - case RADIOLIB_LORAWAN_NONCES_DISCARDED: - return "RADIOLIB_LORAWAN_NONCES_DISCARDED"; - case RADIOLIB_LORAWAN_SESSION_DISCARDED: - return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; + case RADIOLIB_ERR_NONCES_DISCARDED: + return "RADIOLIB_ERR_NONCES_DISCARDED"; + case RADIOLIB_ERR_SESSION_DISCARDED: + return "RADIOLIB_ERR_SESSION_DISCARDED"; } return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; } diff --git a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino index 07ba7038e3..30b1e217c1 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino +++ b/examples/LoRaWAN/LoRaWAN_Starter/LoRaWAN_Starter.ino @@ -1,6 +1,8 @@ /* RadioLib LoRaWAN Starter Example + ! Please refer to the included notes to get started ! + This example joins a LoRaWAN network and will send uplink packets. Before you start, you will have to register your device at https://www.thethingsnetwork.org/ @@ -35,7 +37,8 @@ void setup() { debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); // Setup the OTAA session information - node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + debug(state != RADIOLIB_ERR_NONE, F("Initialise node failed"), state, true); Serial.println(F("Join ('login') the LoRaWAN Network")); state = node.activateOTAA(); @@ -60,11 +63,19 @@ void loop() { // Perform an uplink int16_t state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); - debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false); + debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); + + // Check if a downlink was received + // (state 0 = no downlink, state 1/2 = downlink in window Rx1/Rx2) + if(state > 0) { + Serial.println(F("Received a downlink")); + } else { + Serial.println(F("No downlink received")); + } - Serial.print(F("Uplink complete, next in ")); + Serial.print(F("Next uplink in ")); Serial.print(uplinkIntervalSeconds); - Serial.println(F(" seconds")); + Serial.println(F(" seconds\n")); // Wait until next uplink - observing legal & TTN FUP constraints delay(uplinkIntervalSeconds * 1000UL); // delay needs milli-seconds diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index 65be0af97f..21c79f8ee3 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -105,16 +105,16 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; case RADIOLIB_ERR_CHECKSUM_MISMATCH: return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; - case RADIOLIB_LORAWAN_NO_DOWNLINK: - return "RADIOLIB_LORAWAN_NO_DOWNLINK"; + case RADIOLIB_ERR_NO_JOIN_ACCEPT: + return "RADIOLIB_ERR_NO_JOIN_ACCEPT"; case RADIOLIB_LORAWAN_SESSION_RESTORED: return "RADIOLIB_LORAWAN_SESSION_RESTORED"; case RADIOLIB_LORAWAN_NEW_SESSION: return "RADIOLIB_LORAWAN_NEW_SESSION"; - case RADIOLIB_LORAWAN_NONCES_DISCARDED: - return "RADIOLIB_LORAWAN_NONCES_DISCARDED"; - case RADIOLIB_LORAWAN_SESSION_DISCARDED: - return "RADIOLIB_LORAWAN_SESSION_DISCARDED"; + case RADIOLIB_ERR_NONCES_DISCARDED: + return "RADIOLIB_ERR_NONCES_DISCARDED"; + case RADIOLIB_ERR_SESSION_DISCARDED: + return "RADIOLIB_ERR_SESSION_DISCARDED"; } return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; } diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index 8a44860f68..f4754c1bd7 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -1,16 +1,33 @@ # LoRaWAN examples -RadioLib LoRaWAN v1.1 examples. +RadioLib LoRaWAN examples. * [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) that come with this example to learn more about LoRaWAN and how to use it in RadioLib! * [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)! * [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib. ---- +## LoRaWAN versions & regional parameters +RadioLib implements both LoRaWAN v1.1 and v1.0.4. Confusingly, v1.0.4 is newer than v1.1, but v1.1 includes more security checks and as such **LoRaWAN v1.1 is preferred**. +The catch is in the Regional Parameters: as v1.0.4 is newer, it is more up to date regarding local laws & regulations. Therefore, RadioLib implements 1.0.4 as baseline and 1.1 as fallback, but **Regional Parameters v1.0.4 is preferred**. +_Note: the CN500 band is implemented as specified in RP v1.1, as the RP v1.0.4 version is much too complex._ +To activate a LoRaWAN v1.1 session, supply all the required keys: +```cpp +node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); +node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey); +``` + +To activate a LoRaWAN v1.0.4 session, set the keys that are not available to `NULL`: +```cpp +node.beginOTAA(joinEUI, devEUI, NULL, appKey); +node.beginABP(devAddr, NULL, NULL, nwkSEncKey, appSKey); +``` + +The device doesn't need to know the Regional Parameters version - that is of importance on the console. + +## LoRaWAN persistence > [!WARNING] -> These examples do not fully comply with LoRaWAN v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: +> These examples do not actually comply with LoRaWAN v1.0.4/v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: -## RadioLib persistence In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN v1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!** Currently, examples are available for the following platforms: diff --git a/keywords.txt b/keywords.txt index 44d2487f38..b22dbebd68 100644 --- a/keywords.txt +++ b/keywords.txt @@ -320,38 +320,38 @@ checkDataRate KEYWORD2 setModem KEYWORD2 # LoRaWAN -clearSession KEYWORD2 getBufferNonces KEYWORD2 setBufferNonces KEYWORD2 +clearSession KEYWORD2 getBufferSession KEYWORD2 setBufferSession KEYWORD2 beginOTAA KEYWORD2 -activateOTAA KEYWORD2 beginABP KEYWORD2 +activateOTAA KEYWORD2 activateABP KEYWORD2 isActivated KEYWORD2 -setRx2Dr KEYWORD2 -sendMacCommandReq KEYWORD2 -uplink KEYWORD2 -downlink KEYWORD2 sendReceive KEYWORD2 +sendMacCommandReq KEYWORD2 +getMacLinkCheckAns KEYWORD2 +getMacDeviceTimeAns KEYWORD2 +setDatarate KEYWORD2 +setTxPower KEYWORD2 +setRx2Dr KEYWORD2 +setADR KEYWORD2 +setDutyCycle KEYWORD2 +setDwellTime KEYWORD2 +setCSMA KEYWORD2 setDeviceStatus KEYWORD2 +scheduleTransmission KEYWORD2 getFCntUp KEYWORD2 getNFCntDown KEYWORD2 getAFCntDown KEYWORD2 resetFCntDown KEYWORD2 -setDatarate KEYWORD2 -setADR KEYWORD2 -setDutyCycle KEYWORD2 -dutyCycleInterval KEYWORD2 -timeUntilUplink KEYWORD2 -setDwellTime KEYWORD2 -maxPayloadDwellTime KEYWORD2 -setTxPower KEYWORD2 -getMacLinkCheckAns KEYWORD2 -getMacDeviceTimeAns KEYWORD2 getDevAddr KEYWORD2 getLastToA KEYWORD2 +dutyCycleInterval KEYWORD2 +timeUntilUplink KEYWORD2 +getMaxPayloadLen KEYWORD2 ####################################### # Constants (LITERAL1) @@ -465,12 +465,12 @@ RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 -RADIOLIB_LORAWAN_NO_DOWNLINK LITERAL1 +RADIOLIB_ERR_NO_JOIN_ACCEPT LITERAL1 RADIOLIB_LORAWAN_SESSION_RESTORED LITERAL1 RADIOLIB_LORAWAN_NEW_SESSION LITERAL1 -RADIOLIB_LORAWAN_NONCES_DISCARDED LITERAL1 -RADIOLIB_LORAWAN_SESSION_DISCARDED LITERAL1 -RADIOLIB_LORAWAN_INVALID_MODE LITERAL1 +RADIOLIB_ERR_NONCES_DISCARDED LITERAL1 +RADIOLIB_ERR_SESSION_DISCARDED LITERAL1 +RADIOLIB_ERR_INVALID_MODE LITERAL1 RADIOLIB_ERR_INVALID_WIFI_TYPE LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index de6e06b6ea..7f4d22785c 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -564,9 +564,9 @@ #define RADIOLIB_ERR_CHECKSUM_MISMATCH (-1115) /*! - \brief No downlink was received - most likely none was sent from the server. + \brief No JoinAccept was received - check your keys, or otherwise likely a range issue! */ -#define RADIOLIB_LORAWAN_NO_DOWNLINK (-1116) +#define RADIOLIB_ERR_NO_JOIN_ACCEPT (-1116) /*! \brief The LoRaWAN session was successfully re-activated. @@ -581,17 +581,17 @@ /*! \brief The supplied Nonces buffer is discarded as its activation information is invalid. */ -#define RADIOLIB_LORAWAN_NONCES_DISCARDED (-1119) +#define RADIOLIB_ERR_NONCES_DISCARDED (-1119) /*! \brief The supplied Session buffer is discarded as it doesn't match the Nonces. */ -#define RADIOLIB_LORAWAN_SESSION_DISCARDED (-1120) +#define RADIOLIB_ERR_SESSION_DISCARDED (-1120) /*! \brief The requested command is unavailable under the current LoRaWAN mode. */ -#define RADIOLIB_LORAWAN_INVALID_MODE (-1121) +#define RADIOLIB_ERR_INVALID_MODE (-1121) // LR11x0-specific status codes diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a1f63a7d71..d217347d85 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -6,57 +6,218 @@ #if !RADIOLIB_EXCLUDE_LORAWAN -// flag to indicate whether there was some action during Rx mode (timeout or downlink) -static volatile bool downlinkAction = false; - -// interrupt service routine to handle downlinks automatically -#if defined(ESP8266) || defined(ESP32) - IRAM_ATTR -#endif -static void LoRaWANNodeOnDownlinkAction(void) { - downlinkAction = true; -} - -uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_t min, uint8_t max) { - int8_t dr = uplink - offset + base; - if(dr < min) { - dr = min; - } else if (dr > max) { - dr = max; - } - return(dr); -} - LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand) { this->phyLayer = phy; this->band = band; - this->rx2 = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; this->txPowerMax = this->band->powerMax; this->subBand = subBand; - this->difsSlots = 2; - this->backoffMax = 6; - this->enableCSMA = false; this->dwellTimeEnabledUp = this->dwellTimeUp != 0; this->dwellTimeEnabledDn = this->dwellTimeDn != 0; - memset(this->availableChannels, 0, sizeof(this->availableChannels)); + memset(this->channelPlan, 0, sizeof(this->channelPlan)); } -void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { - this->backoffMax = backoffMax; - this->difsSlots = difsSlots; - this->enableCSMA = enableCSMA; +#if defined(RADIOLIB_BUILD_ARDUINO) +int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + const char* dataUp = strUp.c_str(); + + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t lenDown = 0; + uint8_t dataDown[251]; + + state = this->sendReceive((uint8_t*)dataUp, strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); + + if(state == RADIOLIB_ERR_NONE) { + // add null terminator + dataDown[lenDown] = '\0'; + + // initialize Arduino String class + strDown = String((char*)dataDown); + } + + return(state); } +#endif -void LoRaWANNode::createNonces() { - // set the device credentials - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], this->lwMode); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], this->lwClass); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); +int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t lenDown = 0; + uint8_t dataDown[251]; + + return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); +} + +int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, lenDown, isConfirmed, eventUp, eventDown)); +} + +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + // build a temporary buffer + // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL + size_t lenDown = 0; + uint8_t dataDown[251]; + + return(this->sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); +} + +int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { + if(!dataUp || !dataDown || !lenDown) { + return(RADIOLIB_ERR_NULL_POINTER); + } + int16_t state = RADIOLIB_ERR_UNKNOWN; + Module* mod = this->phyLayer->getMod(); + + // if after (at) ADR_ACK_LIMIT frames no RekeyConf was received, revert to Join state + if(this->fCntUp == (1UL << this->adrLimitExp)) { + state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_REKEY, this->fOptsUp, this->fOptsUpLen, NULL, RADIOLIB_LORAWAN_UPLINK); + if(state == RADIOLIB_ERR_NONE) { + this->clearSession(); + } + } + + // if not joined, don't do anything + if(!this->isActivated()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // check if the requested payload + fPort are allowed, also given dutycycle + uint8_t totalLen = lenUp + this->fOptsUpLen; + state = this->isValidUplink(&totalLen, fPort); + RADIOLIB_ASSERT(state); + + // in case of TS009, a payload that is too long may have gotten clipped, + // so recalculate the actual payload length + // (outside of TS009, a payload that is too long throws an error) + lenUp = totalLen - this->fOptsUpLen; + + // the first 16 bytes are reserved for MIC calculation blocks + size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(lenUp, this->fOptsUpLen); + #if RADIOLIB_STATIC_ONLY + uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen]; + #endif + + // build the encrypted uplink message + this->composeUplink(dataUp, lenUp, uplinkMsg, fPort, isConfirmed); + + // reset Time-on-Air as we are starting new uplink sequence + this->lastToA = 0; + + // repeat uplink+downlink up to 'nbTrans' times (ADR) + uint8_t trans = 0; + for(; trans < this->nbTrans; trans++) { + + // keep track of number of hopped channels + uint8_t numHops = this->maxChanges; + + // number of additional CAD tries + uint8_t numBackoff = 0; + if(this->backoffMax) { + numBackoff = this->phyLayer->random(1, this->backoffMax + 1); + } + + do { + // select a pair of Tx/Rx channels for uplink+downlink + this->selectChannels(); + + // generate and set uplink MIC (depends on selected channel) + this->micUplink(uplinkMsg, uplinkMsgLen); + + // if CSMA is enabled, repeat channel selection & encryption up to numHops times + } while(this->csmaEnabled && numHops-- > 0 && !this->csmaChannelClear(this->difsSlots, numBackoff)); + + // send it (without the MIC calculation blocks) + state = this->transmitUplink(&this->channels[RADIOLIB_LORAWAN_UPLINK], + &uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], + (uint8_t)(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS), + trans > 0); + if(state != RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] uplinkMsg; + #endif + return(state); + } + + // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received + state = receiveCommon(RADIOLIB_LORAWAN_DOWNLINK, this->channels, this->rxDelays, 2, this->rxDelayStart); + + // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4) + // must be present after any confirmed frame, so we force this here + if(isConfirmed) { + mod->hal->delay(this->phyLayer->random(1000, 3000)); + } + + // if an error occured or a downlink was received, stop retransmission + if(state != RADIOLIB_ERR_NONE) { + break; + } + // if no downlink was received, go on + + } // end of transmission & reception + + // note: if an error occured, it may still be the case that a transmission occured + // therefore, we act as if a transmission occured before throwing the actual error + // this feels to be the best way to comply to spec + + // increase frame counter by one for the next uplink + this->fCntUp += 1; + + // the downlink confirmation was acknowledged, so clear the counter value + this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; + + // pass the uplink info if requested + if(eventUp) { + eventUp->dir = RADIOLIB_LORAWAN_UPLINK; + eventUp->confirmed = isConfirmed; + eventUp->confirming = (this->confFCntDown != RADIOLIB_LORAWAN_FCNT_NONE); + eventUp->datarate = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + eventUp->freq = this->channels[RADIOLIB_LORAWAN_UPLINK].freq / 10000.0; + eventUp->power = this->txPowerMax - this->txPowerSteps * 2; + eventUp->fCnt = this->fCntUp; + eventUp->fPort = fPort; + eventUp->nbTrans = trans; + } + + // if a hardware error occurred, return + if(state < RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] uplinkMsg; + #endif + return(state); + } + + uint8_t rxWindow = state; + + // if no downlink was received, do an early exit + if(rxWindow == 0) { + // check if ADR backoff must occur + if(this->adrEnabled) { + this->adrBackoff(); + } + // remove only non-persistent MAC commands, the other commands should be re-sent until downlink is received + LoRaWANNode::clearMacCommands(this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + return(rxWindow); + } + + // a downlink was received, so we can clear the whole MAC uplink buffer + memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + this->fOptsUpLen = 0; + + state = this->parseDownlink(dataDown, lenDown, eventDown); + + // return an error code, if any, otherwise return Rx window (which is > 0) + RADIOLIB_ASSERT(state); + return(rxWindow); } void LoRaWANNode::clearNonces() { + // not a real version number, but helps debugging + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("This line was updated on 2024-09-08 at 00:01+2"); // clear & set all the device credentials memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); this->keyCheckSum = 0; @@ -66,15 +227,14 @@ void LoRaWANNode::clearNonces() { this->rev = 0; } -void LoRaWANNode::clearSession() { - memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); - memset(&(this->commandsUp), 0, sizeof(LoRaWANMacCommandQueue_t)); - memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; - this->isActive = false; -} - uint8_t* LoRaWANNode::getBufferNonces() { + // set the device credentials + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], this->lwMode); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], this->lwClass); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); @@ -102,7 +262,7 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Discarding the Nonces buffer:"); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); - return(RADIOLIB_LORAWAN_NONCES_DISCARDED); + return(RADIOLIB_ERR_NONCES_DISCARDED); } // copy the whole buffer over @@ -118,6 +278,161 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { return(state); } +void LoRaWANNode::clearSession() { + memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); + memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; + this->isActive = false; + + // reset all frame counters + this->fCntUp = 0; + this->aFCntDown = 0; + this->nFCntDown = 0; + this->confFCntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFCnt = 0; + + // reset number of retransmissions from ADR + this->nbTrans = 1; + + // clear CSMA settings + this->csmaEnabled = false; + this->maxChanges = 0; + this->difsSlots = 0; + this->backoffMax = 0; +} + +void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { + this->clearSession(); + + // setup JoinRequest uplink/downlink frequencies and datarates + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->selectChannelPlanDyn(true); + } else { + this->selectChannelPlanFix(); + } + + uint8_t drUp = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + + // on fixed bands, the first OTAA uplink (JoinRequest) is sent on fixed datarate + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && lwMode == RADIOLIB_LORAWAN_MODE_OTAA) { + // randomly select one of 8 or 9 channels and find corresponding datarate + uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; + uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 + if(rand <= 8) { + drUp = this->band->txSpans[0].drJoinRequest; // if one of the first 8 channels, select datarate of span 0 + } else { + drUp = this->band->txSpans[1].drJoinRequest; // if ninth channel, select datarate of span 1 + } + } else { + // on dynamic bands, the first OTAA uplink (JoinRequest) can be any available datarate + // this is also true for ABP on both dynamic and fixed bands, as there is no JoinRequest + if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + uint8_t i = 0; + for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { + if(initialDr >= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin + && initialDr <= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax) { + drUp = initialDr; + break; + } + } + } + // if there is no channel that allowed the user-specified datarate, revert to default datarate + if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); + initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + } + } + + // if there is no (channel that allowed the) user-specified datarate, use a default datarate + // we use the floor of the average datarate of the first enabled channel + if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { + uint8_t drMin = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin; + uint8_t drMax = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax; + drUp = (drMin + drMax) / 2; + } + } + } + } + + uint8_t cOcts[5]; // 5 = maximum downlink payload length + uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + uint8_t cLen = 1; // only apply Dr/Tx field + cOcts[0] = (drUp << 4); // set uplink datarate + cOcts[0] |= 0; // default to max Tx Power + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; + this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + uint8_t maxDCyclePower = 0; + switch(this->band->dutyCycle) { + case(3600): + maxDCyclePower = 10; + break; + case(36000): + maxDCyclePower = 7; + break; + } + cOcts[0] = maxDCyclePower; + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); + cOcts[0] |= this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr; // may be set by user, otherwise band's default upon initialization + LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq, 3); + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; + cOcts[0] |= (this->band->dwellTimeUp > 0 ? 1 : 0) << 4; + uint8_t maxEIRPRaw; + switch(this->band->powerMax) { + case(12): + maxEIRPRaw = 2; + break; + case(14): + maxEIRPRaw = 4; + break; + case(16): + maxEIRPRaw = 5; + break; + case(19): // this option does not exist for the TxParamSetupReq but will be caught during execution + maxEIRPRaw = 7; + break; + case(30): + maxEIRPRaw = 13; + break; + default: + maxEIRPRaw = 2; + break; + } + cOcts[0] |= maxEIRPRaw; + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); + cOcts[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); + cOcts[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; + (void)execMacCommand(cid, cOcts, cLen); +} + uint8_t* LoRaWANNode::getBufferSession() { // store all frame counters LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN], this->aFCntDown); @@ -127,8 +442,13 @@ uint8_t* LoRaWANNode::getBufferSession() { LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFCnt); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp); + uint16_t chMask = 0x0000; + (void)this->getAvailableChannels(&chMask); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], chMask); + // save the current uplink MAC command queue - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], &this->commandsUp, sizeof(LoRaWANMacCommandQueue_t)); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], this->fOptsUp, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], &this->fOptsUpLen, 1); // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); @@ -150,8 +470,9 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { uint16_t signatureNonces = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE]); uint16_t signatureInSession = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE]); if(signatureNonces != signatureInSession) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The supplied session buffer does not match the Nonces buffer"); - return(RADIOLIB_LORAWAN_SESSION_DISCARDED); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The Session buffer (%04x) does not match the Nonces buffer (%04x)", + signatureInSession, signatureNonces); + return(RADIOLIB_ERR_SESSION_DISCARDED); } // copy the whole buffer over @@ -183,109 +504,76 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { // restore the complete MAC state - // all-zero buffer used for checking if MAC commands are set - uint8_t bufferZeroes[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + uint8_t cOcts[14] = { 0 }; // TODO explain + uint8_t cid; + uint8_t cLen = 0; - LoRaWANMacCommand_t cmd = { - .cid = 0, - .payload = { 0 }, - .len = 0, - .repeat = 0, - }; + // setup the default channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->selectChannelPlanDyn(); + } else { // type == RADIOLIB_LORAWAN_BAND_FIXED) + this->selectChannelPlanFix(); + } - // for dynamic bands, first restore the defined channels before restoring ADR - // this is because the ADR command acts as a mask for the enabled channels + // for dynamic bands, the additional channels must be restored per-channel if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // setup the default channels - state = this->setupChannelsDyn(); - RADIOLIB_ASSERT(state); + // all-zero buffer used for checking if MAC commands are set + uint8_t bufferZeroes[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; // restore the session channels uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; - cmd.cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - memcpy(cmd.payload, startChannelsUp + (i * cmd.len), cmd.len); - if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes - cmd.repeat = 1; - (void)execMacCommand(&cmd); + memcpy(cOcts, startChannelsUp + (i * cLen), cLen); + if(memcmp(cOcts, bufferZeroes, cLen) != 0) { // only execute if it is not all zeroes + (void)execMacCommand(cid, cOcts, cLen); } } uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; - cmd.cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; + cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn; - memcpy(cmd.payload, startChannelsDown + (i * cmd.len), cmd.len); - if(memcmp(cmd.payload, bufferZeroes, cmd.len) != 0) { // only execute if it is not all zeroes - (void)execMacCommand(&cmd); + memcpy(cOcts, startChannelsDown + (i * cLen), cLen); + if(memcmp(cOcts, bufferZeroes, cLen) != 0) { // only execute if it is not all zeroes + (void)execMacCommand(cid, cOcts, cLen); } } } - cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd.len); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cmd.len); - (void)execMacCommand(&cmd); - - // for fixed bands, first restore ADR, then the defined channels - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { - // setup the default channels - state = this->setupChannelsFix(this->subBand); - RADIOLIB_ASSERT(state); + // restore the MAC state - ADR needs special care, the rest is straight default + cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cLen = 14; // special internal ADR command + memcpy(cOcts, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cLen); + (void)execMacCommand(cid, cOcts, cLen); - // restore the session channels - uint8_t *startMACpayload = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; - - // there are at most 8 channel masks present - cmd.cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - for(int i = 0; i < 8; i++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - memcpy(cmd.payload, startMACpayload + (i * cmd.len), cmd.len); - // there COULD, according to spec, be an all zeroes ADR command - meh - if(memcmp(cmd.payload, bufferZeroes, cmd.len) == 0) { - break; - } - cmd.repeat = (i+1); - (void)execMacCommand(&cmd); - } + uint8_t cids[6] = { + RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, + RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, + RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP + }; + uint16_t locs[6] = { + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE, RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP, + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP, RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP, + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + }; + for(uint8_t i = 0; i < 6; i++) { + (void)this->getMacLen(cids[i], &cLen, RADIOLIB_LORAWAN_DOWNLINK); + memcpy(cOcts, &this->bufferSession[locs[i]], cLen); + (void)execMacCommand(cids[i], cOcts, cLen); } - cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd.len); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd.len); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd.len); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd.len); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; - memcpy(cmd.payload, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd.len); - (void)execMacCommand(&cmd); + // set the available channels + uint16_t chMask = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS]); + this->setAvailableChannels(chMask); // copy uplink MAC command queue back in place - memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t)); + memcpy(this->fOptsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + memcpy(&this->fOptsUpLen, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], 1); // as both the Nonces and session are restored, revert to active session this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; @@ -293,292 +581,89 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { return(state); } -int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { - // check if there are actually values in the buffer - size_t i = 0; - for(; i < size; i++) { - if(buffer[i]) { - break; - } +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey) { + if(!appKey) { + return(RADIOLIB_ERR_NULL_POINTER); } - if(i == size) { - return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + // clear all the device credentials in case there were any + this->clearNonces(); + + this->joinEUI = joinEUI; + this->devEUI = devEUI; + memcpy(this->appKey, appKey, RADIOLIB_AES128_KEY_SIZE); + if(nwkKey) { + this->rev = 1; + memcpy(this->nwkKey, nwkKey, RADIOLIB_AES128_KEY_SIZE); } - // check integrity of the whole buffer (compare checksum to included checksum) - uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); - uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); - if(signature != checkSum) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04x, expected: %04x", checkSum, signature); - return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + // generate activation key checksum + this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), sizeof(uint64_t)); + this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), sizeof(uint64_t)); + this->keyCheckSum ^= LoRaWANNode::checkSum16(appKey, RADIOLIB_AES128_KEY_SIZE); + if(nwkKey) { + this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkKey, RADIOLIB_AES128_KEY_SIZE); } - return(RADIOLIB_ERR_NONE); -} -void LoRaWANNode::activateCommon(uint8_t initialDr) { - uint8_t drUp = 0; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // if join datarate is user-specified and valid, select that value - if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - if(initialDr >= this->band->txFreqs[0].drMin && initialDr <= this->band->txFreqs[0].drMax) { - drUp = initialDr; - } else { - // if there is no channel that allowed the user-specified datarate, revert to default datarate - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - } - } - - // if there is no (channel that allowed the) user-specified datarate, use a default datarate - // we use the floor of the average datarate of the first default channel - if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax) / 2; - } - - } else { - // if the user specified a certain datarate, check if any of the configured channels allows it - if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - uint8_t i = 0; - for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - if(initialDr >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin - && initialDr <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { - break; - } - } - } - // if there is no channel that allowed the user-specified datarate, revert to default datarate - if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - } - } - - // if there is no (channel that allowed the) user-specified datarate, use a default datarate - // we use the join-request datarate for one of the available channels - if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - // randomly select one of 8 or 9 channels and find corresponding datarate - uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; - uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 - if(rand <= 8) { - drUp = this->band->txSpans[0].joinRequestDataRate; // if one of the first 8 channels, select datarate of span 0 - } else { - drUp = this->band->txSpans[1].joinRequestDataRate; // if ninth channel, select datarate of span 1 - } - } - - } - - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, - .repeat = 0, - }; - cmd.payload[0] = (drUp << 4); // set uplink datarate - cmd.payload[0] |= 0; // default to max Tx Power - cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn; - uint8_t maxDCyclePower; - switch(this->band->dutyCycle) { - case(0): - maxDCyclePower = 0; - break; - case(3600): - maxDCyclePower = 10; - break; - case(36000): - maxDCyclePower = 7; - break; - default: - maxDCyclePower = 0; - break; - } - cmd.payload[0] = maxDCyclePower; - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); - cmd.payload[0] |= this->rx2.drMax; // may be set by user, otherwise band's default upon initialization - uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); - LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn; - cmd.payload[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; - cmd.payload[0] |= (this->band->dwellTimeUp > 0 ? 1 : 0) << 4; - uint8_t maxEIRPRaw; - switch(this->band->powerMax) { - case(12): - maxEIRPRaw = 2; - break; - case(14): - maxEIRPRaw = 4; - break; - case(16): - maxEIRPRaw = 5; - break; - case(19): // this option does not exist for the TxParamSetupReq but will be caught during execution - maxEIRPRaw = 7; - break; - case(30): - maxEIRPRaw = 13; - break; - default: - maxEIRPRaw = 2; - break; - } - cmd.payload[0] |= maxEIRPRaw; - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); - cmd.payload[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; - (void)execMacCommand(&cmd); + this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA; + this->lwClass = RADIOLIB_LORAWAN_CLASS_A; - cmd.cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn; - cmd.payload[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); - cmd.payload[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; - (void)execMacCommand(&cmd); + return(RADIOLIB_ERR_NONE); } -void LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey) { +int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey) { + if(!nwkSEncKey || !appSKey) { + return(RADIOLIB_ERR_NULL_POINTER); + } // clear all the device credentials in case there were any this->clearNonces(); - this->joinEUI = joinEUI; - this->devEUI = devEUI; - memcpy(this->appKey, appKey, RADIOLIB_AES128_KEY_SIZE); - if(nwkKey) { + this->devAddr = addr; + memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); + if(fNwkSIntKey && sNwkSIntKey) { this->rev = 1; - memcpy(this->nwkKey, nwkKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + } else { + memcpy(this->fNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->sNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); } // generate activation key checksum - this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&joinEUI), 8); - this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&devEUI), 8); - this->keyCheckSum ^= LoRaWANNode::checkSum16(appKey, 16); - if(nwkKey) { - this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkKey, 16); - } + this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), sizeof(uint32_t)); + this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); + this->keyCheckSum ^= LoRaWANNode::checkSum16(appSKey, RADIOLIB_AES128_KEY_SIZE); + if(fNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } + if(sNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } - this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA; + this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; this->lwClass = RADIOLIB_LORAWAN_CLASS_A; - // set the device credentials - this->createNonces(); + return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) { - // check if there is an active session - if(this->isActivated()) { - // already activated, don't do anything - return(RADIOLIB_ERR_NONE); - } - if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) { - // session restored but not yet activated - do so now - this->isActive = true; - return(RADIOLIB_LORAWAN_SESSION_RESTORED); - } - - int16_t state = RADIOLIB_ERR_UNKNOWN; - - // either no valid session was found or user forced a new session, so clear all activity - this->clearSession(); - - // starting a new session, so make sure to update event fields already - if(joinEvent) { - joinEvent->newSession = true; - joinEvent->devNonce = this->devNonce; - joinEvent->joinNonce = this->joinNonce; - } - - // setup join-request uplink/downlink frequencies and datarates - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - state = this->setupChannelsDyn(true); - } else { - state = this->setupChannelsFix(this->subBand); - } - RADIOLIB_ASSERT(state); - - // on fixed bands, the join-datarate is specified per specification - // therefore, we ignore the value that was specified by the user - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { - joinDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; - } - // setup all MAC properties to default values - this->activateCommon(joinDr); - - // select a random pair of Tx/Rx channels - state = this->selectChannels(); - RADIOLIB_ASSERT(state); - - // set the physical layer configuration for uplink - state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); - RADIOLIB_ASSERT(state); - - if(this->dwellTimeEnabledUp) { - // calculate JoinRequest time-on-air in milliseconds - RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; - if(toa > this->dwellTimeUp) { - return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); - } - } - +void LoRaWANNode::composeJoinRequest(uint8_t* out) { // copy devNonce currently in use uint16_t devNonceUsed = this->devNonce; - - // build the join-request message - uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; // set the packet fields - joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], this->joinEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], this->devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); + out[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], this->joinEUI); + LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], this->devEUI); + LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code uint32_t mic = 0; if(this->rev == 1) { - mic =this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); + mic =this->generateMIC(out, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey); } else { - mic =this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->appKey); + mic =this->generateMIC(out, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), this->appKey); } - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); - - // send it - Module* mod = this->phyLayer->getMod(); - state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); - this->rxDelayStart = mod->hal->millis(); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest sent (DevNonce = %d) <-- Rx Delay start", this->devNonce); - - // join-request successfully sent, so increase & save devNonce - this->devNonce += 1; - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); - - // configure Rx delay for join-accept message - these are re-configured once a valid join-request is received - this->rxDelays[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; - this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; - - // make sure the Rx2 settings are back to this band's default - this->rx2 = this->band->rx2; + LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic); +} - // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received - state = downlinkCommon(); - RADIOLIB_ASSERT(state); +int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { + int16_t state = RADIOLIB_ERR_UNKNOWN; // build the buffer for the reply data uint8_t joinAcceptMsgEnc[RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN]; @@ -656,7 +741,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], this->joinEUI); - LoRaWANNode::hton(&micBuff[9], devNonceUsed); + LoRaWANNode::hton(&micBuff[9], this->devNonce - 1); memcpy(&micBuff[11], joinAcceptMsg, lenRx); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { @@ -670,46 +755,39 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } } - - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, - .repeat = 0, - }; - cmd.payload[0] = dlSettings & 0x7F; - uint32_t rx2Freq = uint32_t(this->rx2.freq * 10000); // default Rx2 frequency - LoRaWANNode::hton(&cmd.payload[1], rx2Freq, 3); - (void)execMacCommand(&cmd); - - cmd.cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; - memset(cmd.payload, 0, RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN); - cmd.payload[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn; - (void)execMacCommand(&cmd); - // in case of dynamic band, setup the default channels first + // in case of dynamic band, reset the channels to clear JoinRequest-specific channels if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->setupChannelsDyn(false); + this->selectChannelPlanDyn(false); } + uint8_t cOcts[5]; + uint8_t cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; + uint8_t cLen = 0; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = dlSettings & 0x7F; + LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq, 3); + (void)execMacCommand(cid, cOcts, cLen); + + cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]; + (void)execMacCommand(cid, cOcts, cLen); + // process CFlist if present (and if CFListType matches used band type) if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN && joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS] == this->band->bandType) { - uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 }; - memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN); - this->processCFList(cfList); + this->processCFList(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS]); } // if no (valid) CFList was received, default or subband are already setup so don't need to do anything else - // prepare buffer for key derivation uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_JOIN_NONCE_POS], this->joinNonce, 3); // check protocol version (1.0 vs 1.1) if(this->rev == 1) { // 1.1 version, derive the keys - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], this->joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_JOIN_EUI_POS], this->joinEUI); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_DEV_NONCE_POS], this->devNonce - 1); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(this->appKey); @@ -727,19 +805,10 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RadioLibAES128Instance.init(this->nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); - // enqueue the RekeyInd MAC command to be sent in the next uplink - cmd.cid = RADIOLIB_LORAWAN_MAC_REKEY; - memset(cmd.payload, 0, RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN); - cmd.payload[0] = this->rev; - cmd.len = sizeof(uint8_t); - cmd.repeat = 0x01 << RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP; - state = pushMacCommand(&cmd, &this->commandsUp); - RADIOLIB_ASSERT(state); - } else { // 1.0 version, just derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce - 1); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(this->appKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -753,15 +822,16 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } - // reset all frame counters - this->fCntUp = 0; - this->aFCntDown = 0; - this->nFCntDown = 0; - this->confFCntUp = RADIOLIB_LORAWAN_FCNT_NONE; - this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; - this->adrFCnt = 0; + // for LW v1.1, send the RekeyInd MAC command + if(this->rev == 1) { + // enqueue the RekeyInd MAC command to be sent in the next uplink + cid = RADIOLIB_LORAWAN_MAC_REKEY; + this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_UPLINK); + cOcts[0] = this->rev; + state = LoRaWANNode::pushMacCommand(cid, cOcts, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + RADIOLIB_ASSERT(state); + } - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; @@ -772,10 +842,10 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // store DevAddr and all keys LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); // set the signature of the Nonces buffer in the Session buffer LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); @@ -786,45 +856,15 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->isActive = true; - // received join-accept, so update JoinNonce value in event + // received JoinAccept, so update JoinNonce value in event if(joinEvent) { joinEvent->joinNonce = this->joinNonce; } - return(RADIOLIB_LORAWAN_NEW_SESSION); -} - -void LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey) { - // clear all the device credentials in case there were any - this->clearNonces(); - - this->devAddr = addr; - memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); - memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); - if(fNwkSIntKey && sNwkSIntKey) { - this->rev = 1; - memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); - memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); - } else { - memcpy(this->fNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); - memcpy(this->sNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); - } - - // generate activation key checksum - this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast(&addr), 4); - this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16); - this->keyCheckSum ^= LoRaWANNode::checkSum16(appSKey, 16); - if(fNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } - if(sNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } - - this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; - this->lwClass = RADIOLIB_LORAWAN_CLASS_A; - - // set the device credentials - this->createNonces(); + return(state); } -int16_t LoRaWANNode::activateABP(uint8_t initialDr) { +int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) { // check if there is an active session if(this->isActivated()) { // already activated, don't do anything @@ -836,380 +876,467 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { return(RADIOLIB_LORAWAN_SESSION_RESTORED); } - // either no valid session was found or user forced a new session, so clear all activity - this->clearSession(); + int16_t state = RADIOLIB_ERR_UNKNOWN; + Module* mod = this->phyLayer->getMod(); - // setup the uplink/downlink channels and initial datarate - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->setupChannelsDyn(); - } else { - this->setupChannelsFix(this->subBand); + // starting a new session, so make sure to update event fields already + if(joinEvent) { + joinEvent->newSession = true; + joinEvent->devNonce = this->devNonce; + joinEvent->joinNonce = this->joinNonce; } // setup all MAC properties to default values - this->activateCommon(initialDr); - - // reset all frame counters - this->fCntUp = 0; - this->aFCntDown = 0; - this->nFCntDown = 0; - this->confFCntUp = RADIOLIB_LORAWAN_FCNT_NONE; - this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; - this->adrFCnt = 0; + this->createSession(RADIOLIB_LORAWAN_MODE_OTAA, joinDr); - // new session all good, so set active-bit to true - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + // build the JoinRequest message + uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; + this->composeJoinRequest(joinRequestMsg); - // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + // select a random pair of Tx/Rx channels + state = this->selectChannels(); + RADIOLIB_ASSERT(state); - // store DevAddr and all keys - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - - // set the signature of the Nonces buffer in the Session buffer - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); - - // store network parameters - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); + // set the physical layer configuration for uplink + state = this->setPhyProperties(&this->channels[RADIOLIB_LORAWAN_UPLINK], + RADIOLIB_LORAWAN_UPLINK, + this->txPowerMax - 2*this->txPowerSteps); + RADIOLIB_ASSERT(state); - this->isActive = true; + // calculate JoinRequest time-on-air in milliseconds + if(this->dwellTimeEnabledUp) { + RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; + if(toa > this->dwellTimeUp) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp); + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); + } + } - return(RADIOLIB_LORAWAN_NEW_SESSION); -} + // if requested, delay until transmitting JoinRequest + RadioLibTime_t tNow = mod->hal->millis(); + if(this->tUplink > tNow) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow)); + if(this->tUplink > mod->hal->millis()) { + mod->hal->delay(this->tUplink - mod->hal->millis()); + } + } -bool LoRaWANNode::isActivated() { - return(this->isActive); -} + // send it + state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + this->rxDelayStart = mod->hal->millis(); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest sent (DevNonce = %d) <-- Rx Delay start", this->devNonce); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); -#if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::uplink(String& str, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { - return(this->uplink(str.c_str(), fPort, isConfirmed, event)); -} -#endif + // JoinRequest successfully sent, so increase & save devNonce + this->devNonce += 1; + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); + + // configure Rx1 and Rx2 delay for JoinAccept message - these are re-configured once a valid JoinAccept is received + this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; + this->rxDelays[2] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; + + // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received + state = receiveCommon(RADIOLIB_LORAWAN_DOWNLINK, this->channels, this->rxDelays, 2, this->rxDelayStart); + if(state < RADIOLIB_ERR_NONE) { + return(state); + } else if (state == RADIOLIB_ERR_NONE) { + return(RADIOLIB_ERR_NO_JOIN_ACCEPT); + } + + // process JoinAccept message + state = this->processJoinAccept(joinEvent); + RADIOLIB_ASSERT(state); -int16_t LoRaWANNode::uplink(const char* str, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { - return(this->uplink((uint8_t*)str, strlen(str), fPort, isConfirmed, event)); + return(RADIOLIB_LORAWAN_NEW_SESSION); } -int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) { - // if not joined, don't do anything - if(!this->isActivated()) { - return(RADIOLIB_ERR_NETWORK_NOT_JOINED); +int16_t LoRaWANNode::activateABP(uint8_t initialDr) { + // check if there is an active session + if(this->isActivated()) { + // already activated, don't do anything + return(RADIOLIB_ERR_NONE); } + if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) { + // session restored but not yet activated - do so now + this->isActive = true; + return(RADIOLIB_LORAWAN_SESSION_RESTORED); + } + + // setup all MAC properties to default values + this->createSession(RADIOLIB_LORAWAN_MODE_ABP, initialDr); + + // new session all good, so set active-bit to true + this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + + // store DevAddr and all keys + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - Module* mod = this->phyLayer->getMod(); + // set the signature of the Nonces buffer in the Session buffer + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); - // check if the Rx windows were closed after sending the previous uplink - // this FORCES a user to call downlink() after an uplink() - if(this->rxDelayEnd < this->rxDelayStart) { - // not enough time elapsed since the last uplink, we may still be in an Rx window - return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); - } + // store network parameters + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); - // if adhering to dutyCycle and the time since last uplink + interval has not elapsed, return an error - if(this->dutyCycleEnabled && this->rxDelayStart + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > mod->hal->millis()) { - return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); - } + this->isActive = true; - // check destination fPort - if(fPort > RADIOLIB_LORAWAN_FPORT_RESERVED) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is RFU.", fPort); - return(RADIOLIB_ERR_INVALID_PORT); - } - if(fPort == RADIOLIB_LORAWAN_FPORT_TS009 && this->TS009 == false) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! TS009 was not enabled.", fPort); - } - // fPort 0 is only allowed for MAC-only payloads - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - if (!this->isMACPayload) { - return(RADIOLIB_ERR_INVALID_PORT); + return(RADIOLIB_LORAWAN_NEW_SESSION); +} + +void LoRaWANNode::processCFList(uint8_t* cfList) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); + + uint8_t cOcts[14] = { 0 }; // TODO explain + uint8_t cid; + uint8_t cLen = 0; + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // retrieve number of existing (default) channels + size_t num = 0; + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(!this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { + break; + } + num++; + } + + uint8_t freqZero[3] = { 0 }; + + // datarate range for all new channels is equal to the default channels + cOcts[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; + for(uint8_t i = 0; i < 5; i++, num++) { + // if the frequency fields are all zero, there are no more channels in the CFList + if(memcmp(&cfList[i*3], freqZero, 3) == 0) { + break; + } + cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + cOcts[0] = num; + memcpy(&cOcts[1], &cfList[i*3], 3); + (void)execMacCommand(cid, cOcts, cLen); + } + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // complete channel mask received, so clear all existing channels + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - // if this is MAC only payload, continue and reset for next uplink - this->isMACPayload = false; + + // copy channel mask straight over to LinkAdr MAC command + cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + cLen = 14; // special internal ADR length + cOcts[0] = 0xFF; // same datarate and cOcts + memcpy(&cOcts[1], cfList, 12); // copy mask + cOcts[13] = 0; // set NbTrans = 0 -> keep the same + (void)execMacCommand(cid, cOcts, cLen); } - int16_t state = RADIOLIB_ERR_UNKNOWN; +} + +bool LoRaWANNode::isActivated() { + return(this->isActive); +} - // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) - uint8_t fOptsLen = 0; - if(this->commandsUp.numCommands > 0 && fPort != RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - // there are, assume the maximum possible FOpts len for buffer allocation - fOptsLen = this->commandsUp.len; +int16_t LoRaWANNode::isValidUplink(uint8_t* len, uint8_t fPort) { + // check destination fPort + switch(fPort) { + case RADIOLIB_LORAWAN_FPORT_MAC_COMMAND: { + // MAC FPort only good if internally overruled + if (!this->isMACPayload) { + return(RADIOLIB_ERR_INVALID_PORT); + } + // if this is MAC only payload, continue and reset for next uplink + this->isMACPayload = false; + } break; + case RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN ... RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX: { + // all good + } break; + case RADIOLIB_LORAWAN_FPORT_TS009: { + // TS009 FPort only good if overruled during verification testing + if(!this->TS009) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is not enabled.", fPort); + return(RADIOLIB_ERR_INVALID_PORT); + } + } break; + case RADIOLIB_LORAWAN_FPORT_TS011: { + // TS011 FPort only good if overruled during relay exchange + if(!this->TS011) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is not enabled.", fPort); + return(RADIOLIB_ERR_INVALID_PORT); + } + } break; + default: { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is reserved.", fPort); + } break; } - // check maximum payload len as defined in phy - if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) { + // check maximum payload len as defined in band + uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; + if(this->TS011) { + maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater + } + if(*len > maxPayLen) { // normally, throw an error if the packet is too long if(this->TS009 == false) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } // if testing with TS009 Specification Verification Protocol, don't throw error but clip the message - len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]; + *len = maxPayLen; } - bool adrAckReq = false; - if(this->adrEnabled) { - // check if we need to do ADR stuff - uint32_t adrLimit = 0x01 << this->adrLimitExp; - uint32_t adrDelay = 0x01 << this->adrDelayExp; - if((this->fCntUp - this->adrFCnt) >= adrLimit) { - adrAckReq = true; - } - // if we hit the Limit + Delay, try one of three, in order: - // set TxPower to max, set DR to min, enable all default channels - if ((this->fCntUp - this->adrFCnt) == (adrLimit + adrDelay)) { - uint8_t adrStage = 1; - while(adrStage != 0) { - switch(adrStage) { - case(1): { - // if the TxPower field has some offset, remove it and switch to maximum power - if(this->txPowerSteps > 0) { - // set the maximum power supported by both the module and the band - state = this->setTxPower(this->txPowerMax); - if(state == RADIOLIB_ERR_NONE) { - this->txPowerSteps = 0; - adrStage = 0; // successfully did some ADR stuff - } - } - if(adrStage == 1) { // if nothing succeeded, proceed to stage 2 - adrStage = 2; - } - } - break; - case(2): { - // try to decrease the datarate - if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] > 0) { - if(this->setDatarate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] - 1) == RADIOLIB_ERR_NONE) { - adrStage = 0; // successfully did some ADR stuff - } - } - if(adrStage == 2) { // if nothing succeeded, proceed to stage 3 - adrStage = 3; - } - } - break; - case(3): { - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->setupChannelsDyn(false); // revert to default frequencies - } else { - // go back to default selected subband - // hopefully it'll help something, but probably not; at least we tried.. - this->setupChannelsFix(this->subBand); - } - adrStage = 0; // nothing else to do, so end the cycle - } - break; - } - } + return(RADIOLIB_ERR_NONE); +} + +void LoRaWANNode::adrBackoff() { + // check if we need to do ADR stuff + uint32_t adrLimit = 0x01 << this->adrLimitExp; + uint32_t adrDelay = 0x01 << this->adrDelayExp; + if((this->fCntUp - this->adrFCnt) >= adrLimit) { + this->adrAckReq = true; + } else { + this->adrAckReq = false; + } + + if ((this->fCntUp - this->adrFCnt) < (adrLimit + adrDelay)) { + return; + } + + // if we hit the Limit + Delay, try one of three, in order: + // set TxPower to max, set DR to min, enable all default channels - // we tried something to improve the range, so increase the ADR frame counter by 'ADR delay' - this->adrFCnt += adrDelay; + // as we try to do something to improve the range, increase the ADR frame counter by 'ADR delay' + this->adrFCnt += adrDelay; + + // if the TxPower field has some offset, remove it and switch to maximum power + if(this->txPowerSteps > 0) { + // set the maximum power supported by both the module and the band + if(this->setTxPower(this->txPowerMax) == RADIOLIB_ERR_NONE) { + return; } } - // set the physical layer configuration for uplink - this->selectChannels(); - state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); - RADIOLIB_ASSERT(state); + // try to decrease the datarate + if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > this->channels[RADIOLIB_LORAWAN_UPLINK].drMin) { + if(this->setDatarate(this->channels[RADIOLIB_LORAWAN_UPLINK].dr - 1) == RADIOLIB_ERR_NONE) { + return; + } + } - // if dwell time is imposed, calculated expected time on air and cancel if exceeds - if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen) - 16)/1000 > this->dwellTimeUp) { - return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + this->selectChannelPlanDyn(false); // revert to default frequencies + } else { + this->selectChannelPlanFix(); // go back to default selected subband } + this->nbTrans = 1; + return; // nothing else to do +} - // build the uplink message - // the first 16 bytes are reserved for MIC calculation blocks - size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen); - #if RADIOLIB_STATIC_ONLY - uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen]; - #endif - +void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed) { // set the packet fields if(isConfirmed) { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; + out[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; this->confFCntUp = this->fCntUp; } else { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP; + out[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_UNCONF_DATA_UP; } - uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] |= RADIOLIB_LORAWAN_MHDR_MAJOR_R1; - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); + out[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] |= RADIOLIB_LORAWAN_MHDR_MAJOR_R1; + LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS], this->devAddr); - // length of fOpts will be added later - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; if(this->adrEnabled) { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; if(adrAckReq) { - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; } } + + // check if we have some MAC commands to append + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= this->fOptsUpLen; // if the saved confirm-fCnt is set, set the ACK bit - bool isConfirmingDown = false; if(this->confFCntDown != RADIOLIB_LORAWAN_FCNT_NONE) { - isConfirmingDown = true; - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; } - LoRaWANNode::hton(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fCntUp); - - // check if we have some MAC commands to append - if(fOptsLen > 0) { - // assume maximum possible buffer size - uint8_t fOptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN]; - - this->macQueueToBuff(&(this->commandsUp), fOptsBuff); - - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsLen); + LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fCntUp); - uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(len, fOptsLen); - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= fOptsLen; + if(this->fOptsUpLen > 0) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload:"); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->fOptsUp, this->fOptsUpLen); if(this->rev == 1) { // in LoRaWAN v1.1, the FOpts are encrypted using the NwkSEncKey - processAES(fOptsBuff, fOptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true); + processAES(this->fOptsUp, this->fOptsUpLen, this->nwkSEncKey, &out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x01, true); } else { // in LoRaWAN v1.0.x, the FOpts are unencrypted - memcpy(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], fOptsBuff, fOptsLen); + memcpy(&out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fOptsUp, this->fOptsUpLen); } } // set the fPort - uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsLen)] = fPort; + out[RADIOLIB_LORAWAN_FHDR_FPORT_POS(this->fOptsUpLen)] = fPort; // select encryption key based on the target fPort uint8_t* encKey = this->appSKey; - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if((fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) || (fPort == RADIOLIB_LORAWAN_FPORT_TS011)) { encKey = this->nwkSEncKey; } // encrypt the frame payload - processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], this->fCntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); - - // perform CSMA if enabled (do it now already, because MIC calculation depends on this) - if (enableCSMA) { - performCSMA(); - } + processAES(in, lenIn, encKey, &out[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(this->fOptsUpLen)], this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x00, true); +} +void LoRaWANNode::micUplink(uint8_t* inOut, uint8_t lenInOut) { // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; - block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; + block0[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_UPLINK; LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); LoRaWANNode::hton(&block0[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], this->fCntUp); - block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = uplinkMsgLen - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); + block0[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = lenInOut - RADIOLIB_AES128_BLOCK_SIZE - sizeof(uint32_t); uint8_t block1[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; memcpy(block1, block0, RADIOLIB_AES128_BLOCK_SIZE); if(this->confFCntDown != RADIOLIB_LORAWAN_FCNT_NONE) { LoRaWANNode::hton(&block1[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntDown); } - block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; - block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; + block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->channels[RADIOLIB_LORAWAN_UPLINK].idx; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %lu) decoded:", (unsigned long)this->fCntUp); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(uplinkMsg, uplinkMsgLen); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(inOut, lenInOut); // calculate authentication codes - memcpy(uplinkMsg, block1, RADIOLIB_AES128_BLOCK_SIZE); - uint32_t micS = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->sNwkSIntKey); - memcpy(uplinkMsg, block0, RADIOLIB_AES128_BLOCK_SIZE); - uint32_t micF = this->generateMIC(uplinkMsg, uplinkMsgLen - sizeof(uint32_t), this->fNwkSIntKey); + memcpy(inOut, block1, RADIOLIB_AES128_BLOCK_SIZE); + uint32_t micS = this->generateMIC(inOut, lenInOut - sizeof(uint32_t), this->sNwkSIntKey); + memcpy(inOut, block0, RADIOLIB_AES128_BLOCK_SIZE); + uint32_t micF = this->generateMIC(inOut, lenInOut - sizeof(uint32_t), this->fNwkSIntKey); // check LoRaWAN revision if(this->rev == 1) { uint32_t mic = ((uint32_t)(micF & 0x0000FF00) << 16) | ((uint32_t)(micF & 0x0000000FF) << 16) | ((uint32_t)(micS & 0x0000FF00) >> 0) | ((uint32_t)(micS & 0x0000000FF) >> 0); - LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], mic); + LoRaWANNode::hton(&inOut[lenInOut - sizeof(uint32_t)], mic); } else { - LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); + LoRaWANNode::hton(&inOut[lenInOut - sizeof(uint32_t)], micF); } +} - // send it (without the MIC calculation blocks) - state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); +int16_t LoRaWANNode::transmitUplink(LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + Module* mod = this->phyLayer->getMod(); - // set the timestamp so that we can measure when to start receiving - this->rxDelayStart = mod->hal->millis(); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); + // check if the Rx windows were closed after sending the previous uplink + // this FORCES a user to call downlink() after an uplink() + if(this->rxDelayEnd < this->rxDelayStart) { + // not enough time elapsed since the last uplink, we may still be in an Rx window + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } - // calculate Time on Air of this uplink in milliseconds - this->lastToA = this->phyLayer->getTimeOnAir(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS) / 1000; + RadioLibTime_t tNow = mod->hal->millis(); + // if scheduled uplink time is in the past, reschedule to now + if(this->tUplink < tNow) { + this->tUplink = tNow; + } - #if !RADIOLIB_STATIC_ONLY - delete[] uplinkMsg; - #endif + // if dutycycle is enabled and the time since last uplink + interval has not elapsed, return an error + // but: don't check this for retransmissions + if(!retrans && this->dutyCycleEnabled) { + if(this->rxDelayStart + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) { + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + } + + // set the physical layer configuration for uplink + state = this->setPhyProperties(chnl, + RADIOLIB_LORAWAN_UPLINK, + this->txPowerMax - 2*this->txPowerSteps); RADIOLIB_ASSERT(state); - // the downlink confirmation was acknowledged, so clear the counter value - this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; - - // pass the extra info if requested - if(event) { - event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK; - event->confirmed = isConfirmed; - event->confirming = isConfirmingDown; - event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; - event->freq = currentChannels[event->dir].freq; - event->power = this->txPowerMax - this->txPowerSteps * 2; - event->fCnt = this->fCntUp; - event->fPort = fPort; + // if requested, wait until transmitting uplink + tNow = mod->hal->millis(); + if(this->tUplink > tNow) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow)); + if(this->tUplink > mod->hal->millis()) { + mod->hal->delay(this->tUplink - mod->hal->millis()); + } } - // increase frame counter by one for the next uplink - this->fCntUp += 1; + state = this->phyLayer->transmit(in, len); - return(RADIOLIB_ERR_NONE); + // set the timestamp so that we can measure when to start receiving + this->rxDelayStart = mod->hal->millis(); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); + + // increase Time on Air of the uplink sequence + this->lastToA += this->phyLayer->getTimeOnAir(len) / 1000; + + return(state); } -int16_t LoRaWANNode::downlinkCommon() { +// flag to indicate whether there was some action during Rx mode (timeout or downlink) +static volatile bool downlinkAction = false; + +// interrupt service routine to handle downlinks automatically +#if defined(ESP8266) || defined(ESP32) + IRAM_ATTR +#endif +static void LoRaWANNodeOnDownlinkAction(void) { + downlinkAction = true; +} + +int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChannels, const RadioLibTime_t* dlDelays, uint8_t numWindows, RadioLibTime_t tReference) { Module* mod = this->phyLayer->getMod(); + int16_t state = RADIOLIB_ERR_UNKNOWN; + // check if there are any upcoming Rx windows // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 RadioLibTime_t now = mod->hal->millis(); // fix the current timestamp to prevent negative delays - if(now > this->rxDelayStart + this->rxDelays[0] - this->scanGuard) { - // if between start of Rx1 and end of Rx2, wait until Rx2 closes - if(now < this->rxDelayStart + this->rxDelays[1]) { - mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - now); + if(now > tReference + dlDelays[1] - this->scanGuard) { + // if function was called while Rx windows are in progress, + // wait until last window closes to prevent very bad stuff + if(now < tReference + dlDelays[numWindows]) { + mod->hal->delay(dlDelays[numWindows] + tReference - now); } // update the end timestamp in case user got stuck between uplink and downlink this->rxDelayEnd = mod->hal->millis(); return(RADIOLIB_ERR_NO_RX_WINDOW); } - // set the physical layer configuration for downlink - int16_t state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK); - RADIOLIB_ASSERT(state); - - // create the masks that are required for receiving downlinks - RadioLibIrqFlags_t irqFlags = (1UL << RADIOLIB_IRQ_RX_DONE) | (1UL << RADIOLIB_IRQ_TIMEOUT); - RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; - + // setup interrupt this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); + RadioLibTime_t tOpen = 0; int16_t timedOut = 0; - // perform listening in the two Rx windows - for(uint8_t i = 0; i < 2; i++) { + // listen during the specified windows + uint8_t window = 1; + for(; window <= numWindows; window++) { downlinkAction = false; + // set the physical layer configuration for downlink + this->phyLayer->standby(); + state = this->setPhyProperties(&dlChannels[window], dir, this->txPowerMax - 2*this->txPowerSteps); + RADIOLIB_ASSERT(state); + // calculate the Rx timeout RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*this->scanGuard*1000; RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); // wait for the start of the Rx window - RadioLibTime_t waitLen = this->rxDelayStart + this->rxDelays[i] - mod->hal->millis(); + RadioLibTime_t waitLen = tReference + dlDelays[window] - mod->hal->millis(); // make sure that no underflow occured; if so, clip the delay (although this will likely miss any downlink) - if(waitLen > this->rxDelays[i]) { - waitLen = this->rxDelays[i]; + if(waitLen > dlDelays[window]) { + waitLen = dlDelays[window]; } // the waiting duration is shortened a bit to cover any possible timing errors if(waitLen > this->scanGuard) { @@ -1218,120 +1345,87 @@ int16_t LoRaWANNode::downlinkCommon() { mod->hal->delay(waitLen); // open Rx window by starting receive with specified timeout - state = this->phyLayer->startReceive(timeoutMod, irqFlags, irqMask, 0); + // TODO remove default arguments + state = this->phyLayer->startReceive(timeoutMod, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0); + tOpen = mod->hal->millis(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", i+1, (int)(timeoutHost / 1000 + scanGuard / 2)); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + scanGuard / 2)); // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + this->scanGuard / 2); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", i+1); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); - // check if the IRQ bit for Rx Timeout is set + // if the IRQ bit for Rx Timeout is not set, something is received, so stop the windows timedOut = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); if(timedOut == RADIOLIB_ERR_UNSUPPORTED) { return(timedOut); } if(!timedOut) { break; - - } else if(i == 0) { - // nothing in the first window, configure for the second - this->phyLayer->standby(); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); - state = this->phyLayer->setFrequency(this->rx2.freq); - RADIOLIB_ASSERT(state); - - DataRate_t dataRate; - state = findDataRate(this->rx2.drMax, &dataRate); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setDataRate(dataRate); - RADIOLIB_ASSERT(state); } - } // Rx windows are now closed this->rxDelayEnd = mod->hal->millis(); // if we got here due to a timeout, stop ongoing activities if(timedOut) { - this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? - if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { - this->phyLayer->invertIQ(false); - } - - return(RADIOLIB_LORAWAN_NO_DOWNLINK); + this->phyLayer->standby(); + return(RADIOLIB_ERR_NONE); } - // wait for the DIO to fire indicating a downlink is received - now = mod->hal->millis(); + // get the maximum allowed Time-on-Air of a packet given the current datarate + uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; + if(this->TS011) { + maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater + } + RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen); bool downlinkComplete = true; + + // wait for the DIO to fire indicating a downlink is received while(!downlinkAction) { mod->hal->yield(); - // this should never happen, but if it does this would be an infinite loop - // TODO scale this value using expected ToA of maximum allowed payload length - if(mod->hal->millis() - now > 3000UL) { + // stay in Rx mode for the maximum allowed Time-on-Air plus small grace period + if(mod->hal->millis() - tOpen > tMax + scanGuard) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink missing!"); downlinkComplete = false; break; } } - // we have a message, clear actions, go to standby and reset the IQ inversion - this->phyLayer->standby(); // TODO check: this should be done automagically due to RxSingle? - this->phyLayer->clearPacketReceivedAction(); - if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { - state = this->phyLayer->invertIQ(false); - RADIOLIB_ASSERT(state); - } - - if(!downlinkComplete) { - state = RADIOLIB_LORAWAN_NO_DOWNLINK; + // update time of downlink reception + if(downlinkComplete) { + this->tDownlink = mod->hal->millis(); } - return(state); -} - -#if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::downlink(String& str, LoRaWANEvent_t* event) { - int16_t state = RADIOLIB_ERR_UNKNOWN; + // we have a message, clear actions, go to standby + this->phyLayer->clearPacketReceivedAction(); + this->phyLayer->standby(); - // build a temporary buffer - // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL - size_t length = 0; - uint8_t data[251]; + // if all windows passed without receiving anything, return 0 + if(!downlinkComplete) { + state = 0; - // wait for downlink - state = this->downlink(data, &length, event); - if(state == RADIOLIB_ERR_NONE) { - // add null terminator - data[length] = '\0'; + // if we received something during a window, return the window number + } else { + state = window; + } - // initialize Arduino String class - str = String((char*)data); + // Any frame received by an end-device containing a MACPayload greater than + // the specified maximum length M over the data rate used to receive the frame + // SHALL be silently discarded. + if(this->phyLayer->getPacketLength() > maxPayLen) { + return(0); // act as if no downlink was received } return(state); } -#endif -int16_t LoRaWANNode::downlink(LoRaWANEvent_t* event) { +int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { int16_t state = RADIOLIB_ERR_UNKNOWN; - - // build a temporary buffer - // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL - size_t length = 0; - uint8_t data[251]; - - // wait for downlink - state = this->downlink(data, &length, event); - - return(state); -} - -int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { - // handle Rx1 and Rx2 windows - returns RADIOLIB_ERR_NONE if a downlink is received - int16_t state = downlinkCommon(); - RADIOLIB_ASSERT(state); + + // set user-data length to 0 to prevent undefined behaviour in case of bad use + // if there is user-data, this will be handled at the appropriate place + *len = 0; // get the packet length size_t downlinkMsgLen = this->phyLayer->getPacketLength(); @@ -1376,44 +1470,15 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } - // calculate length of FOpts and payload - uint8_t fOptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + // calculate length of piggy-backed FOpts + uint8_t fOptsPbLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; - // check if the ACK bit is set, indicating this frame acknowledges the previous uplink - bool isConfirmingUp = false; - if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK)) { - isConfirmingUp = true; - } - - // total - MHDR(1) - DevAddr(4) - FCtrl(1) - FCnt(2) - FOpts - MIC(4) - // potentially also an FPort, but we'll find out soon enough - uint8_t payLen = downlinkMsgLen - 1 - 4 - 1 - 2 - fOptsLen - 4; - - // get the frame counter - uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); - - // set the MIC calculation blocks - memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); - downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; - // if this downlink is confirming an uplink, the MIC was generated with the least-significant 16 bits of that fCntUp - if(isConfirmingUp && (this->rev == 1)) { - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); - } - downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fCnt16); - downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); - - // check the MIC - if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_CRC_MISMATCH); - } + // MHDR(1) - DevAddr(4) - FCtrl(1) - FCnt(2) - FOptsPb - Payload - MIC(4) + // potentially also an FPort, will find out next + uint8_t payLen = downlinkMsgLen - 1 - 4 - 1 - 2 - fOptsPbLen - 4; // in LoRaWAN v1.1, a frame is a Network frame if there is no Application payload - // i.e.: either no payload at all (empty frame or FOpts only), or MAC only payload (FPort = 0) + // i.e.: either no payload at all (empty frame or FOpts only), or MAC only payload uint8_t fPort = RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; bool isAppDownlink = false; if(this->rev == 0) { @@ -1421,32 +1486,52 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) } if(payLen > 0) { payLen -= 1; // subtract one as fPort is set - fPort = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsLen)]; + fPort = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsPbLen)]; + // check if fPort value is actually allowed - if(fPort > RADIOLIB_LORAWAN_FPORT_RESERVED) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Received downlink at FPort %d - rejected! This FPort is RFU!", fPort); - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_INVALID_PORT); - } - if(fPort == RADIOLIB_LORAWAN_FPORT_TS009 && this->TS009 == false) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Received downlink at FPort %d - rejected! TS009 was not enabled.", fPort); - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_INVALID_PORT); + switch(fPort) { + case RADIOLIB_LORAWAN_FPORT_MAC_COMMAND: { + // payload consists of all MAC commands (or is empty) + } break; + case RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN ... RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX: { + // payload is user-defined (or empty) - may carry piggybacked MAC commands + isAppDownlink = true; + } break; + case RADIOLIB_LORAWAN_FPORT_TS009: { + // TS009 FPort only good if overruled during verification testing + if(!this->TS009) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is not enabled.", fPort); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } + isAppDownlink = true; + } break; + case RADIOLIB_LORAWAN_FPORT_TS011: { + // TS011 FPort only good if overruled during relay exchange + if(!this->TS011) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is not enabled.", fPort); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } + isAppDownlink = true; + } break; + default: { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is reserved.", fPort); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } break; } - if(fPort > RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - isAppDownlink = true; - } else { - fOptsLen = payLen; - } } - - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %d) encoded:", isAppDownlink ? "A" : "N", fCnt16); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + + // get the frame counter + uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); // check the fCntDown value (Network or Application) uint32_t fCntDownPrev = 0; @@ -1475,6 +1560,33 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) fCnt32 |= ((uint32_t)msb << 16); // add back the MSB part } } + + // check if the ACK bit is set, indicating this frame acknowledges the previous uplink + bool isConfirmingUp = false; + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_ACK)) { + isConfirmingUp = true; + } + + // set the MIC calculation blocks + memset(downlinkMsg, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; + // if this downlink is confirming an uplink, the MIC was generated with the least-significant 16 bits of that fCntUp + // (LoRaWAN v1.1 only) + if(isConfirmingUp && (this->rev == 1)) { + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); + } + downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_DOWNLINK; + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fCnt32); + downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); + + // check the MIC + if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_CRC_MISMATCH); + } // save current fCnt to respective frame counter if (isAppDownlink) { @@ -1483,1516 +1595,1653 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) this->nFCntDown = fCnt32; } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) encoded:", + isAppDownlink ? "A" : "N", + (unsigned long)(isAppDownlink ? this->aFCntDown : this->nFCntDown)); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) bool isConfirmedDown = false; if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { this->confFCntDown = this->aFCntDown; isConfirmedDown = true; } + + // a downlink was received, so reset the ADR counter to the last uplink's fCnt + this->adrFCnt = this->getFCntUp(); - // pass the extra info if requested - if(event) { - event->dir = RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK; - event->confirmed = isConfirmedDown; - event->confirming = isConfirmingUp; - event->datarate = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]; - event->freq = currentChannels[event->dir].freq; - event->power = this->txPowerMax - this->txPowerSteps * 2; - event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; - event->fPort = fPort; + // if this downlink is on FPort 0, the FOptsLen is the length of the payload + // in any other case, the payload (length) is user accessible + uint8_t fOptsLen = fOptsPbLen; + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && payLen > 0) { + fOptsLen = payLen; + } else { + *len = payLen; } - // clear the previous MAC commands, if any - memset(&(this->commandsDown), 0, sizeof(LoRaWANMacCommandQueue_t)); - - // process FOpts (if there are any) - if(fOptsLen > 0) { - // there are some Fopts, decrypt them - #if !RADIOLIB_STATIC_ONLY - uint8_t* fOpts = new uint8_t[RADIOLIB_MAX(RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK, (int)fOptsLen)]; - #else - uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; - #endif + #if !RADIOLIB_STATIC_ONLY + uint8_t* fOpts = new uint8_t[fOptsLen]; + #else + uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + + // figure out if the payload should end up in user data or internal FOpts buffer + uint8_t* dest; + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + dest = fOpts; + } else { + dest = data; + } - // it COULD be the case that the assumed FCnt rollover is incorrect, in which case the following MAC decryption fails... + // figure out which key to use to decrypt the payload + uint8_t* encKey = this->appSKey; + if((fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) || (fPort == RADIOLIB_LORAWAN_FPORT_TS011)) { + encKey = this->nwkSEncKey; + } - if(payLen > 0 && fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - // if the MAC payload is in the payload, process AES is if it were a normal payload but using the NwkSEncKey instead - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); + // decrypt the frame payload + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsPbLen)], payLen, encKey, dest, fCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + + // decrypt any piggy-backed FOpts + if(fOptsPbLen > 0) { + // the decryption depends on the LoRaWAN version + if(this->rev == 1) { + // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey + uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); } else { - // if the MAC payload is piggybacked in the FHDR fields, the decryption depends on the LoRaWAN version. - if(this->rev == 1) { - // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey - uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, ctrId, true); - } else { - // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted - memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen); - } + // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted + memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen); } + } - // parse the fOpts into the MAC queue - this->macBufftoQueue(&(this->commandsDown), fOpts, fOptsLen); + // clear the previous MAC commands, if any + memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); - // process the MAC queue commands (any response is modified in-place) - int16_t i = 0; - for(; i < this->commandsDown.numCommands; i++) { - bool sendUp = execMacCommand(&(this->commandsDown.commands[i])); - if(sendUp) { - pushMacCommand(&(this->commandsDown.commands[i]), &(this->commandsUp)); - } - } + // process FOpts (if there are any) + uint8_t cid; + uint8_t fLen = 1; + uint8_t* mPtr = fOpts; + uint8_t procLen = 0; - // pop the commands from back to front - for (; i >= 0; i--) { - if(this->commandsDown.commands[i].repeat > 0) { - this->commandsDown.commands[i].repeat--; - } else { - deleteMacCommand(this->commandsDown.commands[i].cid, &(this->commandsDown)); - } - } + #if !RADIOLIB_STATIC_ONLY + uint8_t* fOptsRe = new uint8_t[250]; + #else + uint8_t fOptsRe[RADIOLIB_STATIC_ARRAY_SIZE]; + #endif + uint8_t fOptsReLen = 0; - #if !RADIOLIB_STATIC_ONLY - delete[] fOpts; - #endif + // indication whether LinkAdr MAC command has been processed + bool mAdr = false; - // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink - if(this->commandsUp.len > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { - size_t fOptsBufSize = this->commandsUp.len; - #if RADIOLIB_STATIC_ONLY - uint8_t fOptsBuff[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* fOptsBuff = new uint8_t[fOptsBufSize]; - #endif - - this->macQueueToBuff(&(this->commandsUp), fOptsBuff); - - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload (%d commands):", this->commandsUp.numCommands); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsBuff, fOptsBufSize); - - this->isMACPayload = true; - // temporarily lift dutyCycle restrictions to allow immediate MAC response - bool prevDC = this->dutyCycleEnabled; - this->dutyCycleEnabled = false; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); - state = this->uplink(fOptsBuff, fOptsBufSize, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); - this->dutyCycleEnabled = prevDC; - #if !RADIOLIB_STATIC_ONLY - delete[] fOptsBuff; - #endif - RADIOLIB_ASSERT(state); + while(procLen < fOptsLen) { + cid = *mPtr; // MAC id is the first byte + state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true); + RADIOLIB_ASSERT(state); + uint8_t fLenRe = 0; + state = this->getMacLen(cid, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true); + RADIOLIB_ASSERT(state); - #if RADIOLIB_STATIC_ONLY - uint8_t strDown[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* strDown = new uint8_t[this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK]]]; - #endif - size_t lenDown = 0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Receiving after MAC-only uplink .. "); - state = this->downlink(strDown, &lenDown); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(" .. state: %d", state); - #if !RADIOLIB_STATIC_ONLY - delete[] strDown; - #endif - RADIOLIB_ASSERT(state); + if(procLen + fLen > fOptsLen) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen, fLen); + return(RADIOLIB_ERR_INVALID_CID); } - } + bool reply = false; - // a downlink was received, so reset the ADR counter to the last uplink's fCnt - this->adrFCnt = this->getFCntUp(); + // if this is a LinkAdr MAC command, pre-process contiguous commands into one atomic block + if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + // if there was any LinkAdr command before, set NACK and continue without processing + if(mAdr) { + reply = true; + fOptsRe[fOptsReLen + 1] = 0x00; - // if MAC-only payload, return now - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - // no payload - *len = 0; - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif + // if this is the first LinkAdr command, do some special treatment: + } else { + mAdr = true; + uint8_t fAdrLen = 5; + uint8_t mAdrOpt[14] = { 0 }; + + // retrieve all contiguous LinkAdr commands + while(procLen + fLen + fAdrLen < fOptsLen + 1 && *(mPtr + fLen) == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + fLen += 5; // ADR command is 5 bytes + fLenRe += 2; // ADR response is 2 bytes + } - return(RADIOLIB_ERR_NONE); - } + // pre-process them into a single complete channel mask (stored in mAdrOpt) + LoRaWANNode::preprocessMacLinkAdr(mPtr, fLen, mAdrOpt); - // process Application payload - *len = payLen; + // execute like a normal MAC command (but pointing to mAdrOpt instead) + reply = this->execMacCommand(cid, mAdrOpt, 14, &fOptsRe[fOptsReLen + 1]); - // TODO it COULD be the case that the assumed rollover is incorrect, then figure out a way to catch this and retry with just fCnt16 - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], payLen, this->appSKey, data, fCnt32, RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK, 0x00, true); - - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif + // in LoRaWAN v1.0.x, all ACK bytes should have equal status - fix in post-processing + if(this->rev == 0) { + LoRaWANNode::postprocessMacLinkAdr(&fOptsRe[fOptsReLen], fLen); - return(RADIOLIB_ERR_NONE); -} + // in LoRaWAN v1.1, just provide one ACK, so no post-processing but cut off reply length + } else { + fLenRe = 2; + } + } -#if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { - // send the uplink - int16_t state = this->uplink(strUp, fPort, isConfirmed, eventUp); - RADIOLIB_ASSERT(state); + // MAC command other than LinkAdr, just process the payload + } else { + reply = this->execMacCommand(cid, mPtr + 1, fLen - 1, &fOptsRe[fOptsReLen + 1]); + } - // wait for the downlink - state = this->downlink(strDown, eventDown); - return(state); -} -#endif + if(reply) { + fOptsRe[fOptsReLen] = cid; + fOptsReLen += fLenRe; + } -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { - // send the uplink - int16_t state = this->uplink(dataUp, lenUp, fPort, isConfirmed, eventUp); - RADIOLIB_ASSERT(state); + procLen += fLen; + mPtr += fLen; + } - // wait for the downlink - state = this->downlink(eventDown); - return(state); -} + // remove all MAC commands except those whose payload can be requested by the user + // (which are LinkCheck and DeviceTime) + if(fOptsLen > 0) { + LoRaWANNode::clearMacCommands(fOpts, &fOptsLen, RADIOLIB_LORAWAN_DOWNLINK); + memcpy(this->fOptsDown, fOpts, fOptsLen); + } + this->fOptsDownLen = fOptsLen; + + // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink + if(fOptsReLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { -int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { - // send the uplink - int16_t state = this->uplink(strUp, fPort, isConfirmed, eventUp); - RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC-only payload (%d bytes):", fOptsReLen); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsRe, fOptsReLen); - // wait for the downlink - state = this->downlink(dataDown, lenDown, eventDown); - return(state); -} + this->isMACPayload = true; + // temporarily lift dutyCycle restrictions to allow immediate MAC response + bool prevDC = this->dutyCycleEnabled; + this->dutyCycleEnabled = false; -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { - // send the uplink - int16_t state = this->uplink(dataUp, lenUp, fPort, isConfirmed, eventUp); - RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); - // wait for the downlink - state = this->downlink(dataDown, lenDown, eventDown); - return(state); -} + this->sendReceive(fOptsRe, fOptsReLen, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); -void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { - this->battLevel = battLevel; -} + this->dutyCycleEnabled = prevDC; -// return fCnt of last uplink; also return 0 if no uplink occured yet -uint32_t LoRaWANNode::getFCntUp() { - if(this->fCntUp == 0) { - return(0); + } else { // fOptsReLen <= 15 + memcpy(this->fOptsUp, fOptsRe, fOptsReLen); + this->fOptsUpLen = fOptsReLen; } - return(this->fCntUp - 1); -} -uint32_t LoRaWANNode::getNFCntDown() { - return(this->nFCntDown); -} + // pass the extra info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_DOWNLINK; + event->confirmed = isConfirmedDown; + event->confirming = isConfirmingUp; + event->datarate = this->channels[RADIOLIB_LORAWAN_DOWNLINK].dr; + event->freq = channels[event->dir].freq / 10000.0; + event->power = this->txPowerMax - this->txPowerSteps * 2; + event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; + event->fPort = fPort; + } -uint32_t LoRaWANNode::getAFCntDown() { - return(this->aFCntDown); -} + #if !RADIOLIB_STATIC_ONLY + delete[] fOpts; + delete[] fOptsRe; + delete[] downlinkMsg; + #endif -void LoRaWANNode::resetFCntDown() { - this->nFCntDown = 0; - this->aFCntDown = 0; + return(RADIOLIB_ERR_NONE); } -uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { - if((msg == NULL) || (len == 0)) { - return(0); - } - - RadioLibAES128Instance.init(key); - uint8_t cmac[RADIOLIB_AES128_BLOCK_SIZE]; - RadioLibAES128Instance.generateCMAC(msg, len, cmac); - return(((uint32_t)cmac[0]) | ((uint32_t)cmac[1] << 8) | ((uint32_t)cmac[2] << 16) | ((uint32_t)cmac[3]) << 24); +bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn) { + uint8_t buff[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN]; + return(this->execMacCommand(cid, optIn, lenIn, buff)); } -bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { - if((msg == NULL) || (len < sizeof(uint32_t))) { - return(0); - } - - // extract MIC from the message - uint32_t micReceived = LoRaWANNode::ntoh(&msg[len - sizeof(uint32_t)]); +bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uint8_t* optOut) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02x", cid); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(optIn, lenIn); - // calculate the expected value and compare - uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); - if(micCalculated != micReceived) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); + if(cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { + // TODO call user-provided callback for proprietary MAC commands? return(false); } - return(true); -} + switch(cid) { + case(RADIOLIB_LORAWAN_MAC_RESET): { + // get the server version + uint8_t srvVersion = optIn[0]; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); + if(srvVersion == this->rev) { + // valid server version, stop sending the ResetInd MAC command + LoRaWANNode::deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + } + return(false); + } break; -int16_t LoRaWANNode::setPhyProperties(uint8_t dir) { - // set the physical layer configuration - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); - int16_t state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); - RADIOLIB_ASSERT(state); + case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); - // if this channel is an FSK channel, toggle the FSK switch - if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - this->modulation = RADIOLIB_LORAWAN_MODULATION_GFSK; - } + return(false); + } break; - int8_t pwr = this->txPowerMax - this->txPowerSteps * 2; - - // at this point, assume that Tx power value is already checked, so ignore the return value - (void)this->phyLayer->checkOutputPower(pwr, &pwr); - state = this->phyLayer->setOutputPower(pwr); - RADIOLIB_ASSERT(state); + case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { + // get the ADR configuration + uint8_t macDrUp = (optIn[0] & 0xF0) >> 4; + uint8_t macTxSteps = optIn[0] & 0x0F; + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkAdrReq: dataRate = %d, txSteps = %d, nbTrans = %d", macDrUp, macTxSteps, lenIn > 1 ? optIn[13] : 0); - DataRate_t dr; - state = findDataRate(this->dataRates[dir], &dr); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setDataRate(dr); - RADIOLIB_ASSERT(state); + uint8_t chMaskAck = 0; + uint8_t drAck = 0; + uint8_t pwrAck = 0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, TX = %d dBm, BW = %6.3f kHz, CR = 4/%d", - dr.lora.spreadingFactor, pwr, dr.lora.bandwidth, dr.lora.codingRate); + // first, get current configuration + uint64_t chMaskGrp0123 = 0; + uint32_t chMaskGrp45 = 0; + this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); + uint16_t chMaskActive = 0; + (void)this->getAvailableChannels(&chMaskActive); + uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + + // only apply channel mask if present (internal Dr/Tx commands do not set channel mask) + if(lenIn > 1) { + uint64_t macChMaskGrp0123 = LoRaWANNode::ntoh(&optIn[1]); + uint32_t macChMaskGrp45 = LoRaWANNode::ntoh(&optIn[9]); + // apply requested channel mask and enable all of them for testing datarate + chMaskAck = this->applyChannelMask(macChMaskGrp0123, macChMaskGrp45); + } else { + chMaskAck = true; + } + + this->setAvailableChannels(0xFFFF); - if(this->modulation == RADIOLIB_LORAWAN_MODULATION_GFSK) { - state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); - RADIOLIB_ASSERT(state); - } + int16_t state; - // downlink messages are sent with inverted IQ - if(dir == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) { - if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { - state = this->phyLayer->invertIQ(true); - RADIOLIB_ASSERT(state); - } - } + // try to apply the datarate configuration + // if value is set to 'keep current values', retrieve current value + if(macDrUp == 0x0F) { + macDrUp = currentDr; + } - // this only needs to be done once-ish - uint8_t syncWord[4] = { 0 }; - uint8_t syncWordLen = 0; - size_t preLen = 0; - switch(this->modulation) { - case(RADIOLIB_LORAWAN_MODULATION_GFSK): { - preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; - syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); - syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); - syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; - syncWordLen = 3; - } break; + if (this->band->dataRates[macDrUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + // check if the module supports this data rate + DataRate_t dr; + state = this->findDataRate(macDrUp, &dr); - case(RADIOLIB_LORAWAN_MODULATION_LORA): { - preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; - syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; - syncWordLen = 1; - } break; + // if datarate in hardware all good, set datarate for now + // and check if there are any available Tx channels for this datarate + if(state == RADIOLIB_ERR_NONE) { + this->channels[RADIOLIB_LORAWAN_UPLINK].dr = macDrUp; - case(RADIOLIB_LORAWAN_MODULATION_LR_FHSS): { - syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 24); - syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 16); - syncWord[2] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 8); - syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; - syncWordLen = 4; - } break; + // only if we have available Tx channels, we set an Ack + if(this->getAvailableChannels(NULL) > 0) { + drAck = 1; + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR: no channels available for datarate %d", macDrUp); + } + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR: hardware failure configurating datarate %d, code %d", macDrUp, state); + } + + } - default: - return(RADIOLIB_ERR_WRONG_MODEM); - } + // try to apply the power configuration + // if value is set to 'keep current values', retrieve current value + if(macTxSteps == 0x0F) { + macTxSteps = this->txPowerSteps; + } - state = this->phyLayer->setSyncWord(syncWord, syncWordLen); - RADIOLIB_ASSERT(state); + int8_t power = this->txPowerMax - 2*macTxSteps; + int8_t powerActual = 0; + state = this->phyLayer->checkOutputPower(power, &powerActual); + // only acknowledge if the radio is able to operate at or below the requested power level + if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { + pwrAck = 1; + this->txPowerSteps = macTxSteps; + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); + } - if(this->modulation != RADIOLIB_LORAWAN_MODULATION_LR_FHSS) { - state = this->phyLayer->setPreambleLength(preLen); - } - return(state); -} + // set ACK bits + optOut[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); -int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); - - size_t num = 0; - // copy the default defined channels into the first slots (where Tx = Rx) - for(; num < 3 && this->band->txFreqs[num].enabled; num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkAdrAns: %02x", optOut[0]); - // if we're about to send a join-request, copy the join-request channels to the next slots - if(joinRequest) { - size_t numJR = 0; - for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - } - } + // if ACK not completely successful, revert and stop + if(optOut[0] != 0x07) { + this->applyChannelMask(chMaskGrp0123, chMaskGrp45); + this->setAvailableChannels(chMaskActive); + this->channels[RADIOLIB_LORAWAN_UPLINK].dr = currentDr; + // Tx power was not modified + return(true); + } - // clear all remaining channels - for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } + // ACK successful, so apply and save + this->txPowerSteps = macTxSteps; + if(lenIn > 1) { + uint8_t macNbTrans = optIn[13] & 0x0F; + if(macNbTrans) { // if there is a value for NbTrans, set this value + this->nbTrans = macNbTrans; + } + } - #if RADIOLIB_DEBUG_PROTOCOL - this->printChannels(); - #endif - - return(RADIOLIB_ERR_NONE); -} + // restore original active channels + this->setAvailableChannels(chMaskActive); -// setup a subband and its corresponding join-request datarate -// WARNING: subBand starts at 1 (corresponds to all populair schemes) -int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", subBand); + // save to the ADR MAC location + // but first re-set the Dr/Tx/NbTrans field to make sure they're not set to 0xF + optIn[0] = (this->channels[RADIOLIB_LORAWAN_UPLINK].dr) << 4; + optIn[0] |= this->txPowerSteps; + if(lenIn > 1) { + optIn[13] = this->nbTrans; + } + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], optIn, lenIn); + + return(true); + } break; - // clear all existing channels - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } + case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { + uint8_t maxDutyCycle = optIn[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); + if(maxDutyCycle == 0) { + this->dutyCycle = this->band->dutyCycle; + } else { + this->dutyCycle = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000 / (RadioLibTime_t)(1UL << maxDutyCycle); + } - // if no subband is selected by user, cycle through banks of 8 using devNonce value - if(subBand == 0) { - uint8_t numBanks8 = this->band->txSpans[0].numChannels / 8; - subBand = this->devNonce % numBanks8; - } + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], optIn, lenIn); - uint8_t chMaskCntl = 0; - uint16_t chMask = 0; - - // if there are two channel spans, first set the channel from second span - if(this->band->numTxSpans == 2) { - chMaskCntl = 7; - chMask = (1 << (subBand - 1)); // set channel mask - this->applyChannelMaskFix(chMaskCntl, chMask); - } + return(true); + } break; - // chMask is set for 16 channels at once, so widen the Cntl value - chMaskCntl = (subBand - 1) / 2; // compensate the 1 offset + case(RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP): { + // get the configuration + uint8_t macRx1DrOffset = (optIn[0] & 0x70) >> 4; + uint8_t macRx2Dr = optIn[0] & 0x0F; + uint32_t macRx2Freq = LoRaWANNode::ntoh(&optIn[1], 3); + + uint8_t rx1DrOsAck = 0; + uint8_t rx2DrAck = 0; + uint8_t rx2FreqAck = 0; - // now select the correct bank of 8 channels - if(subBand % 2 == 0) { // even subbands - chMask = 0xFF00; - } else { - chMask = 0x00FF; // odd subbands - } - this->applyChannelMaskFix(chMaskCntl, chMask); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupReq: Rx1DrOffset = %d, rx2DataRate = %d, freq = %7.3f", + macRx1DrOffset, macRx2Dr, macRx2Freq / 10000.0); + + // check the requested configuration + uint8_t uplinkDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + DataRate_t dr; + if(this->band->rx1DrTable[uplinkDr][macRx1DrOffset] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->findDataRate(this->band->rx1DrTable[uplinkDr][macRx1DrOffset], &dr) == RADIOLIB_ERR_NONE) { + rx1DrOsAck = 1; + } + } + if(macRx2Dr >= this->band->rx2.drMin && macRx2Dr <= this->band->rx2.drMax) { + if(this->band->dataRates[macRx2Dr] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->findDataRate(macRx2Dr, &dr) == RADIOLIB_ERR_NONE) { + rx2DrAck = 1; + } + } + } + if(macRx2Freq >= this->band->freqMin && macRx2Freq <= this->band->freqMax) { + if(this->phyLayer->setFrequency(macRx2Freq / 10000.0) == RADIOLIB_ERR_NONE) { + rx2FreqAck = 1; + } + } + optOut[0] = (rx1DrOsAck << 2) | (rx2DrAck << 1) | (rx2FreqAck << 0); - return(RADIOLIB_ERR_NONE); -} + // if not fully acknowledged, return now without applying the requested configuration + if(optOut[0] != 0x07) { + return(true); + } -int16_t LoRaWANNode::processCFList(uint8_t* cfList) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); - - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // retrieve number of existing (default) channels - size_t num = 0; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(!this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - break; + // passed ACK, so apply configuration + this->rx1DrOffset = macRx1DrOffset; + this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr = macRx2Dr; + this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq = macRx2Freq; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], optIn, lenIn); + + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { + // set the uplink reply + optOut[0] = this->battLevel; + int8_t snr = this->phyLayer->getSNR(); + optOut[1] = snr & 0x3F; + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusAns: status = 0x%02x%02x", optOut[0], optOut[1]); + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_NEW_CHANNEL): { + // only implemented on dynamic bands + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + return(false); } - num++; - } - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, - .payload = { 0 }, - .len = 0, - .repeat = 0, - }; + // get the configuration + uint8_t macChIndex = optIn[0]; + uint32_t macFreq = LoRaWANNode::ntoh(&optIn[1], 3); + uint8_t macDrMax = (optIn[4] & 0xF0) >> 4; + uint8_t macDrMin = optIn[4] & 0x0F; + + uint8_t newChAck = 0; + uint8_t freqAck = 0; - uint8_t freqZero[3] = { 0 }; + // on LoRaWAN v1.1, the default channels may be modified - not on v1.0.x. + // in that case, only allow non-default channels to be modified + // there are at most three default channels, so either check for >2 or else if index is used + if(this->rev == 1 || macChIndex > 2 || this->band->txFreqs[macChIndex].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + newChAck = 1; + } - // datarate range for all new channels is equal to the default channels - cmd.payload[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; - for(uint8_t i = 0; i < 5; i++, num++) { - // if the frequency fields are all zero, there are no more channels in the CFList - if(memcmp(&cfList[i*3], freqZero, 3) == 0) { - break; + // check if the frequency is allowed and possible + if(macFreq >= this->band->freqMin && macFreq <= this->band->freqMax) { + if(this->phyLayer->setFrequency((float)macFreq / 10000.0) == RADIOLIB_ERR_NONE) { + freqAck = 1; + } + // otherwise, if frequency is 0, disable the channel which is also a valid option + } else if(macFreq == 0) { + freqAck = 1; } - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn; - cmd.payload[0] = num; - memcpy(&cmd.payload[1], &cfList[i*3], 3); - (void)execMacCommand(&cmd); - } - } else { // RADIOLIB_LORAWAN_BAND_FIXED - // complete channel mask received, so clear all existing channels - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = 0, - .repeat = 0, - }; + // set ACK bits + optOut[0] = (newChAck << 1) | (freqAck << 0); - // in case of mask-type bands, copy those frequencies that are masked true into the available TX channels - size_t numChMasks = 3 + this->band->numTxSpans; // 4 masks for bands with 2 spans, 5 spans for bands with 1 span - for(size_t chMaskCntl = 0; chMaskCntl < numChMasks; chMaskCntl++) { - cmd.len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; - cmd.payload[0] = 0xFF; // same datarate and payload - memcpy(&cmd.payload[1], &cfList[chMaskCntl*2], 2); // copy mask - cmd.payload[3] = chMaskCntl << 4; // set chMaskCntl, set NbTrans = 0 -> keep the same - cmd.repeat = (chMaskCntl + 1); - (void)execMacCommand(&cmd); - } - } + // if not fully acknowledged, return now without applying the requested configuration + if(optOut[0] != 0x03) { + return(true); + } - return(RADIOLIB_ERR_NONE); -} + // ACK successful, so apply and save + if(macFreq > 0) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].enabled = true; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].idx = macChIndex; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq = macFreq; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMin = macDrMin; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMax = macDrMax; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].available = true; + // downlink channel is identical to uplink channel + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex]; + } else { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; -int16_t LoRaWANNode::selectChannels() { - // figure out which channel IDs are enabled (chMask may have disabled some) and are valid for the current datarate - uint8_t numChannels = 0; - uint8_t channelsEnabled[RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - if(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] >= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin - && this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] <= this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax) { - channelsEnabled[numChannels] = i; - numChannels++; } - } - } - if(numChannels == 0) { - return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); - } - // select a random ID & channel from the list of enabled and possible channels - uint8_t channelID = channelsEnabled[this->phyLayer->random(numChannels)]; - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][channelID]; - - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // for dynamic bands, the downlink channel is the one matched to the uplink channel - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][channelID]; - - } else { // RADIOLIB_LORAWAN_BAND_FIXED - // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels - LoRaWANChannel_t channelDn; - channelDn.enabled = true; - channelDn.idx = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx % this->band->rx1Span.numChannels; - channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; - channelDn.drMin = this->band->rx1Span.drMin; - channelDn.drMax = this->band->rx1Span.drMax; - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = channelDn; - } - uint8_t drDown = getDownlinkDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].idx, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].enabled, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq / 10000.0, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMin, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMax, + + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].idx, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].enabled, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].freq / 10000.0, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].drMin, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].drMax + ); - return(RADIOLIB_ERR_NONE); -} + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + macChIndex * lenIn, optIn, lenIn); -int16_t LoRaWANNode::setDatarate(uint8_t drUp) { - // scan through all enabled channels and check if the requested datarate is available - bool isValidDR = false; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - LoRaWANChannel_t *chnl = &(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]); - if(chnl->enabled) { - if(drUp >= chnl->drMin && drUp <= chnl->drMax) { - isValidDR = true; - break; + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DL_CHANNEL): { + // only implemented on dynamic bands + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + return(false); } - } - } - if(!isValidDR) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); - return(RADIOLIB_ERR_INVALID_DATA_RATE); - } - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, - .repeat = 0, - }; - cmd.payload[0] = (drUp << 4); - cmd.payload[0] |= 0x0F; // keep Tx Power the same - cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored - cmd.payload[3] |= 0; // keep NbTrans the same - (void)execMacCommand(&cmd); + // get the configuration + uint8_t macChIndex = optIn[0]; + uint32_t macFreq = LoRaWANNode::ntoh(&optIn[1], 3); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %7.3f MHz", macChIndex, macFreq / 10000.0); + uint8_t freqDlAck = 0; + uint8_t freqUlAck = 0; + + // check if the frequency is allowed possible + if(macFreq >= this->band->freqMin && macFreq <= this->band->freqMax) { + if(this->phyLayer->setFrequency(macFreq / 10000.0) == RADIOLIB_ERR_NONE) { + freqDlAck = 1; + } + } + + // check if the corresponding uplink frequency is actually set + if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq > 0) { + freqUlAck = 1; + } - // check if ACK is set for Tx Power - if((cmd.payload[0] >> 1) != 1) { - return(RADIOLIB_ERR_INVALID_DATA_RATE); - } - - return(RADIOLIB_ERR_NONE); -} + // set ACK bits + optOut[0] = (freqUlAck << 1) | (freqDlAck << 0); -void LoRaWANNode::setADR(bool enable) { - this->adrEnabled = enable; -} + // if not fully acknowledged, return now without applying the requested configuration + if(optOut[0] != 0x03) { + return(true); + } -void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { - this->dutyCycleEnabled = enable; - if(!enable) { - this->dutyCycle = 0; - } - if(msPerHour == 0) { - this->dutyCycle = this->band->dutyCycle; - } else { - this->dutyCycle = msPerHour; - } -} + // ACK successful, so apply and save + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].freq = macFreq; -// given an airtime in milliseconds, calculate the minimum uplink interval -// to adhere to a given dutyCycle -RadioLibTime_t LoRaWANNode::dutyCycleInterval(RadioLibTime_t msPerHour, RadioLibTime_t airtime) { - if(msPerHour == 0 || airtime == 0) { - return(0); - } - RadioLibTime_t oneHourInMs = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000; - float numPackets = msPerHour / airtime; - RadioLibTime_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems - return(delayMs); -} + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + macChIndex * lenIn, optIn, lenIn); -RadioLibTime_t LoRaWANNode::timeUntilUplink() { - Module* mod = this->phyLayer->getMod(); - RadioLibTime_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); - if(mod->hal->millis() > nextUplink){ - return(0); - } - return(nextUplink - mod->hal->millis() + 1); -} + return(true); + } break; -void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { - this->dwellTimeEnabledUp = enable; - if(msPerUplink == 0) { - this->dwellTimeUp = this->band->dwellTimeUp; - } else { - this->dwellTimeUp = msPerUplink; - } -} + case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { + // get the configuration + uint8_t delay = optIn[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); + + // apply the configuration + if(delay == 0) { + delay = 1; + } + this->rxDelays[1] = delay * 1000; // Rx1 delay + this->rxDelays[2] = this->rxDelays[1] + 1000; // Rx2 delay -uint8_t LoRaWANNode::maxPayloadDwellTime() { - // configure current datarate - DataRate_t dr; - // TODO this may fail horribly? - (void)findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr); - (void)this->phyLayer->setDataRate(dr); - uint8_t minPayLen = 0; - uint8_t maxPayLen = 255; - uint8_t payLen = (minPayLen + maxPayLen) / 2; - // do some binary search to find maximum allowed payload length - while(payLen != minPayLen && payLen != maxPayLen) { - if(this->phyLayer->getTimeOnAir(payLen) > this->dwellTimeUp) { - maxPayLen = payLen; - } else { - minPayLen = payLen; - } - payLen = (minPayLen + maxPayLen) / 2; - } - return(payLen - 13); // fixed 13-byte header -} + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], optIn, lenIn); -int16_t LoRaWANNode::setTxPower(int8_t txPower) { - // only allow values within the band's (or MAC state) maximum - if(txPower > this->txPowerMax) { - return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); - } - // Tx Power is set in steps of two - // the selected value is rounded down to nearest multiple of two away from txPowerMax - // e.g. on EU868, max is 16; if 13 is selected then we set to 12 - uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM); + return(true); + } break; - LoRaWANMacCommand_t cmd = { - .cid = RADIOLIB_LORAWAN_MAC_LINK_ADR, - .payload = { 0 }, - .len = MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, - .repeat = 0, - }; - cmd.payload[0] = 0xF0; // keep datarate the same - cmd.payload[0] |= numSteps; // set the Tx Power - cmd.payload[3] = (1 << 7); // set the RFU bit, which means that the channel mask gets ignored - cmd.payload[3] |= 0; // keep NbTrans the same - (void)execMacCommand(&cmd); + case(RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP): { + // TxParamSetupReq is only supported on a subset of bands + // in other bands, silently ignore without response + if(!this->band->txParamSupported) { + return(false); + } + uint8_t dlDwell = (optIn[0] & 0x20) >> 5; + uint8_t ulDwell = (optIn[0] & 0x10) >> 4; + uint8_t maxEirpRaw = optIn[0] & 0x0F; - // check if ACK is set for Tx Power - if((cmd.payload[0] >> 2) != 1) { - return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); - } - - return(RADIOLIB_ERR_NONE); -} + // who the f came up with this ... + const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; + this->txPowerMax = eirpEncoding[maxEirpRaw]; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); -int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { - int16_t state = RADIOLIB_ERR_UNKNOWN; + this->dwellTimeEnabledUp = ulDwell ? true : false; + this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; - uint8_t dataRateBand = this->band->dataRates[dr]; + this->dwellTimeEnabledDn = dlDwell ? true : false; + this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; - if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) { - dataRate->fsk.bitRate = 50; - dataRate->fsk.freqDev = 25; - - } else { - uint8_t bw = dataRateBand & 0x0C; - switch(bw) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - dataRate->lora.bandwidth = 125.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - dataRate->lora.bandwidth = 250.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - dataRate->lora.bandwidth = 500.0; - break; - default: - dataRate->lora.bandwidth = 125.0; + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], optIn, lenIn); + + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_REKEY): { + // get the server version + uint8_t srvVersion = optIn[0]; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); + if((srvVersion > 0) && (srvVersion <= this->rev)) { + // valid server version, stop sending the ReKey MAC command + LoRaWANNode::deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + } + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { + this->adrLimitExp = (optIn[0] & 0xF0) >> 4; + this->adrDelayExp = optIn[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], optIn, lenIn); + + return(true); + } break; + + case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); + + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { + // TODO implement this + uint16_t rejoinReq = LoRaWANNode::ntoh(optIn); + uint8_t period = (rejoinReq & 0x3800) >> 11; + uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; + uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; + uint8_t dr = rejoinReq & 0x000F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ForceRejoinReq: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); + (void)period; + (void)maxRetries; + (void)rejoinType; + (void)dr; + return(false); + } break; + + case(RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP): { + // TODO implement this + uint8_t maxTime = (optIn[0] & 0xF0) >> 4; + uint8_t maxCount = optIn[0] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); + + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], optIn, lenIn); + + lenIn = 0; + optIn[0] = (1 << 1) | 1; + + (void)maxTime; + (void)maxCount; + return(true); + } break; + + default: { + // derived classes may implement additional MAC commands + return(derivedMacHandler(cid, optIn, lenIn, optOut)); } - - dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; - dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; } - state = this->phyLayer->checkDataRate(*dataRate); + return(false); +} - return(state); +bool LoRaWANNode::derivedMacHandler(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uint8_t* optOut) { + (void)cid; + (void)optIn; + (void)lenIn; + (void)optOut; + return(false); } -int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { - // this can only be configured in ABP mode - if(this->lwMode != RADIOLIB_LORAWAN_MODE_ABP) { - return(RADIOLIB_LORAWAN_INVALID_MODE); - } +void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAdrOpt) { + uint8_t fLen = 5; // single ADR command is 5 bytes + uint8_t numOpts = cLen / fLen; + uint64_t chMaskGrp0123 = 0; + uint32_t chMaskGrp45 = 0; - // can only configure different datarate for dynamic bands - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { - return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); - } + // set Dr/Tx field from last MAC command + mAdrOpt[0] = mPtr[cLen - fLen + 1]; - // check if datarate is available in the selected band - if(this->band->dataRates[dr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - return(RADIOLIB_ERR_INVALID_DATA_RATE); - } - - // find and check if the datarate is available for this radio module - DataRate_t dataRate; - int16_t state = findDataRate(dr, &dataRate); - RADIOLIB_ASSERT(state); + // set NbTrans partial field from last MAC command + mAdrOpt[13] = mPtr[cLen - fLen + 4] & 0x0F; - // passed all checks, so configure the datarate - this->rx2.drMax = dr; + uint8_t opt = 0; + while(opt < numOpts) { + uint8_t chMaskCntl = (mPtr[opt * fLen + 4] & 0x70) >> 4; + uint16_t chMask = LoRaWANNode::ntoh(&mPtr[opt * fLen + 2]); + switch(chMaskCntl) { + case 0 ... 3: + chMaskGrp0123 |= (uint64_t)chMask << (16 * chMaskCntl); + break; + case 4: + chMaskGrp45 |= (uint32_t)chMask; + break; + case 5: + // for CN500, this is just a normal channel mask + // for all other bands, the first 10 bits enable banks of 8 125kHz channels + if(this->band->bandNum == BandCN500) { + chMaskGrp45 |= (uint32_t)chMask << 16; + } else { + int bank = 0; + for(; bank < 8; bank++) { + if(chMask & ((uint16_t)1 << bank)) { + chMaskGrp0123 |= (0xFF << (8 * bank)); + } + } + for(; bank < 10; bank++) { + if(chMask & ((uint16_t)1 << bank)) { + chMaskGrp45 |= (0xFF << (8 * (bank - 8))); + } + } + } + break; + case 6: + // for dynamic bands: all channels ON (currently defined) + // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 + // except for CN500: all 125kHz channels ON + + // for dynamic bands: retrieve all defined channels + // for fixed bands: cannot store all defined channels, so select a random one from each bank + this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN500) { + chMaskGrp45 |= (uint32_t)chMask; + } + break; + case 7: + // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 + // except for CN500: RFU + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN500) { + chMaskGrp0123 = 0; + chMaskGrp45 |= (uint32_t)chMask; + } + break; + } + opt++; + } + LoRaWANNode::hton(&mAdrOpt[1], chMaskGrp0123); + LoRaWANNode::hton(&mAdrOpt[9], chMaskGrp45); +} - return(state); +void LoRaWANNode::postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen) { + uint8_t fLen = 5; // single ADR command is 5 bytes + uint8_t numOpts = cLen / fLen; + + // duplicate the ACK bits of the atomic block response 'numOpts' times + // skip one, as the first response is already there + for(int opt = 1; opt < numOpts; opt++) { + ack[opt*2 + 0] = RADIOLIB_LORAWAN_MAC_LINK_ADR; + ack[opt*2 + 1] = ack[1]; + } } -int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { - bool valid = false; +int16_t LoRaWANNode::getMacCommand(uint8_t cid, LoRaWANMacCommand_t* cmd) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { - valid = MacTable[i].user; + memcpy(cmd, &MacTable[i], sizeof(LoRaWANMacCommand_t)); + return(RADIOLIB_ERR_NONE); } } - if(!valid) { + // didn't find this CID, check if derived class can help (if any) + int16_t state = this->derivedMacFinder(cid, cmd); + return(state); +} + +int16_t LoRaWANNode::derivedMacFinder(uint8_t cid, LoRaWANMacCommand_t* cmd) { + (void)cid; + (void)cmd; + return(RADIOLIB_ERR_INVALID_CID); +} + +int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { + LoRaWANMacCommand_t cmd = RADIOLIB_LORAWAN_MAC_COMMAND_NONE; + int16_t state = this->getMacCommand(cid, &cmd); + RADIOLIB_ASSERT(state); + if(!cmd.user) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("You are not allowed to request this MAC command"); return(RADIOLIB_ERR_INVALID_CID); } // if there are already 15 MAC bytes in the uplink queue, we can't add a new one - if(this->commandsUp.len + 1 > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The maximum number of FOpts payload was reached"); + if(fOptsUpLen >= RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The maximum size of FOpts payload was reached"); return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } - if(this->commandsUp.numCommands > RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The RadioLib internal MAC command queue was full"); - return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); + + // if this MAC command is already in the queue, silently stop + if(this->getMacPayload(cid, this->fOptsUp, this->fOptsUpLen, NULL, RADIOLIB_LORAWAN_UPLINK) == RADIOLIB_ERR_NONE) { + return(RADIOLIB_ERR_NONE); } - // delete any prior requests for this MAC command, in case this is requested more than once - (void)deleteMacCommand(cid, &this->commandsUp); - - LoRaWANMacCommand_t cmd = { - .cid = cid, - .payload = { 0 }, - .len = 0, - .repeat = 0, - }; - pushMacCommand(&cmd, &this->commandsUp); - return(true); + state = LoRaWANNode::pushMacCommand(cid, NULL, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + return(state); } -void LoRaWANNode::macQueueToBuff(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer) { - // append all MAC replies into fOpts buffer - uint8_t* fOptsPtr = buffer; - int16_t i = 0; - for (; i < queue->numCommands; i++) { - LoRaWANMacCommand_t cmd = queue->commands[i]; - memcpy(fOptsPtr, &cmd, 1 + cmd.len); - fOptsPtr += cmd.len + 1; - } +int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { + uint8_t payload[2] = { 0 }; + int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_LINK_CHECK, this->fOptsDown, fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); + RADIOLIB_ASSERT(state); - // pop the commands from back to front - for (; i >= 0; i--) { - if(queue->commands[i].repeat > 0) { - queue->commands[i].repeat--; - } else { - deleteMacCommand(queue->commands[i].cid, queue); - } - } + if(margin) { *margin = payload[0]; } + if(gwCnt) { *gwCnt = payload[1]; } + return(RADIOLIB_ERR_NONE); } -void LoRaWANNode::macBufftoQueue(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer, uint8_t len) { - bool hasADR = false; - uint8_t numADR = 0; - uint8_t lastCID = 0; +int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { + uint8_t payload[5] = { 0 }; + int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, this->fOptsDown, fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); + RADIOLIB_ASSERT(state); - // process the MAC command(s) - int8_t remLen = len; - uint8_t* fOptsPtr = buffer; - while(remLen > 0) { - uint8_t cid = *fOptsPtr; - uint8_t macLen = getMacPayloadLength(cid); - if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { - // if there was an earlier ADR command but it was not the last, ignore it - if(hasADR && lastCID != RADIOLIB_LORAWAN_MAC_LINK_ADR) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Encountered non-consecutive block of ADR commands - skipping"); - remLen -= (macLen + 1); - fOptsPtr += (macLen + 1); - lastCID = cid; - continue; - } - // otherwise, set ADR flag to true and increase counter - hasADR = true; - numADR++; + if(gpsEpoch) { + *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); + if(returnUnix) { + uint32_t unixOffset = 315964800UL - 18UL; // 18 leap seconds since GPS epoch (Jan. 6th 1980) + *gpsEpoch += unixOffset; } - if(macLen + 1 > remLen) - break; - LoRaWANMacCommand_t cmd = { - .cid = cid, - .payload = { 0 }, - .len = macLen, - .repeat = (cid == RADIOLIB_LORAWAN_MAC_LINK_ADR ? numADR : (uint8_t)0), - }; - memcpy(cmd.payload, fOptsPtr + 1, macLen); - pushMacCommand(&cmd, queue); + } + if(fraction) { *fraction = payload[4]; } + + return(RADIOLIB_ERR_NONE); +} - // move in the buffer to the next command - remLen -= (macLen + 1); - fOptsPtr += (macLen + 1); - lastCID = cid; +int16_t LoRaWANNode::getMacLen(uint8_t cid, uint8_t* len, uint8_t dir, bool inclusive) { + LoRaWANMacCommand_t cmd = RADIOLIB_LORAWAN_MAC_COMMAND_NONE; + int16_t state = this->getMacCommand(cid, &cmd); + RADIOLIB_ASSERT(state); + if(dir == RADIOLIB_LORAWAN_UPLINK) { + *len = cmd.lenUp; + } else { + *len = cmd.lenDn; + } + if(inclusive) { + *len += 1; // add one byte for CID } + return(RADIOLIB_ERR_NONE); +} + +bool LoRaWANNode::isPersistentMacCommand(uint8_t cid, uint8_t dir) { + // if this MAC command doesn't exist, it wouldn't even get into the queue, so don't care about outcome + LoRaWANMacCommand_t cmd = RADIOLIB_LORAWAN_MAC_COMMAND_NONE; + (void)this->getMacCommand(cid, &cmd); + + // in the uplink direction, MAC payload should persist per spec + if(dir == RADIOLIB_LORAWAN_UPLINK) { + return(cmd.persist); + // in the downlink direction, MAC payload should persist if it is user-accessible + // which is the case for LinkCheck and DeviceTime + } else { + return(cmd.user); + } + return(false); } -int16_t LoRaWANNode::pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue) { - if(queue->numCommands >= RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) { +int16_t LoRaWANNode::pushMacCommand(uint8_t cid, uint8_t* cOcts, uint8_t* out, uint8_t* lenOut, uint8_t dir) { + uint8_t fLen = 0; + int16_t state = this->getMacLen(cid, &fLen, dir, true); + RADIOLIB_ASSERT(state); + + // check if we can even append the MAC command into the buffer + if(*lenOut + fLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { return(RADIOLIB_ERR_COMMAND_QUEUE_FULL); } - memcpy(&queue->commands[queue->numCommands], cmd, sizeof(LoRaWANMacCommand_t)); - queue->numCommands++; - queue->len += 1 + cmd->len; // 1 byte for command ID, len bytes for payload + out[*lenOut] = cid; // add MAC id + memcpy(&out[*lenOut + 1], cOcts, fLen - 1); // copy payload into buffer + *lenOut += fLen; // payload + command ID return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload) { - for(size_t index = 0; index < queue->numCommands; index++) { - if(queue->commands[index].cid == cid) { - // if a pointer to a payload is supplied, copy the command's payload over - if(payload) { - memcpy(payload, queue->commands[index].payload, queue->commands[index].len); - } - queue->len -= (1 + queue->commands[index].len); // 1 byte for command ID, len for payload - // move all subsequent commands one forward in the queue - if(index < RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1) { - memmove(&queue->commands[index], &queue->commands[index + 1], (RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - index - 1) * sizeof(LoRaWANMacCommand_t)); +int16_t LoRaWANNode::getMacPayload(uint8_t cid, uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t dir) { + size_t i = 0; + + while(i < lenIn) { + uint8_t id = in[i]; + uint8_t fLen = 0; + int16_t state = this->getMacLen(id, &fLen, dir, true); + RADIOLIB_ASSERT(state); + if(lenIn < i + fLen) { + return(RADIOLIB_ERR_INVALID_CID); + } + + // if this is the requested MAC id, copy the payload over + if(id == cid) { + // only copy payload if destination is supplied + if(out) { + memcpy(out, &in[i + 1], fLen - 1); } - // set the latest element to all 0 - memset(&queue->commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE - 1], 0x00, sizeof(LoRaWANMacCommand_t)); - queue->numCommands--; return(RADIOLIB_ERR_NONE); } + + // move on to next MAC command + i += fLen; } return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); } -bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[MAC] 0x%02x", cmd->cid); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(cmd->payload, cmd->len); +int16_t LoRaWANNode::deleteMacCommand(uint8_t cid, uint8_t* inOut, uint8_t* lenInOut, uint8_t dir) { + size_t i = 0; + while(i < *lenInOut) { + uint8_t id = inOut[i]; + uint8_t fLen = 0; + int16_t state = this->getMacLen(id, &fLen, dir); + RADIOLIB_ASSERT(state); + if(*lenInOut < i + fLen) { + return(RADIOLIB_ERR_INVALID_CID); + } - if(cmd->cid >= RADIOLIB_LORAWAN_MAC_PROPRIETARY) { - // TODO call user-provided callback for proprietary MAC commands? - return(false); - } + // if this is the requested MAC id, + if(id == cid) { + // remove it by moving the rest of the payload forward + memmove(&inOut[i], &inOut[i + fLen], *lenInOut - i - fLen); - switch(cmd->cid) { - case(RADIOLIB_LORAWAN_MAC_RESET): { - // get the server version - uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); - if(srvVersion == this->rev) { - // valid server version, stop sending the ResetInd MAC command - deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->commandsUp); - } - return(false); - } break; + // set the remainder of the queue to 0 + memset(&inOut[i + fLen], 0, *lenInOut - i - fLen); - case(RADIOLIB_LORAWAN_MAC_LINK_CHECK): { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkCheckAns: [user]"); - cmd->repeat = 255; // prevent the command from being deleted by setting repeat to maximum + *lenInOut -= fLen; + return(RADIOLIB_ERR_NONE); + } - return(false); - } break; + // move on to next MAC command + i += fLen; + } - case(RADIOLIB_LORAWAN_MAC_LINK_ADR): { - // get the ADR configuration - uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4; - uint8_t txSteps = cmd->payload[0] & 0x0F; - bool isInternalTxDr = cmd->payload[3] >> 7; + return(RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND); +} - uint16_t chMask = LoRaWANNode::ntoh(&cmd->payload[1]); - uint8_t chMaskCntl = (cmd->payload[3] & 0x70) >> 4; - uint8_t nbTransMac = cmd->payload[3] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTransMac); +void LoRaWANNode::clearMacCommands(uint8_t* inOut, uint8_t* lenInOut, uint8_t dir) { + size_t i = 0; + uint8_t numDeleted = 0; + while(i < *lenInOut) { + uint8_t id = inOut[i]; + uint8_t fLen = 1; // if there is an incorrect MAC command, we should at least move forward by one byte + (void)this->getMacLen(id, &fLen, dir, true); - // try to apply the datarate configuration - int16_t state; - uint8_t drAck = 0; - if(drUp == 0x0F) { // keep the same - drAck = 1; + // only clear MAC command if it should not persist until a downlink is received + if(!this->isPersistentMacCommand(id, dir)) { + // remove it by moving the rest of the payload forward + memmove(&inOut[i], &inOut[i + fLen], *lenInOut - i - fLen); - } else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - // check if the module supports this data rate - DataRate_t dr; - state = findDataRate(drUp, &dr); - if(state == RADIOLIB_ERR_NONE) { - uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin, - this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMax); - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] = drUp; - this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK] = drDown; - drAck = 1; - } else { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state); - drUp = 0x0F; // set value to 'keep the same' - } - - } + // set the remainder of the queue to 0 + memset(&inOut[i + fLen], 0, *lenInOut - i - fLen); - // try to apply the power configuration - uint8_t pwrAck = 0; - if(txSteps == 0x0F) { - pwrAck = 1; + numDeleted += fLen; + } - } else { - int8_t power = this->txPowerMax - 2*txSteps; - int8_t powerActual = 0; - state = this->phyLayer->checkOutputPower(power, &powerActual); - // only acknowledge if the radio is able to operate at or below the requested power level - if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { - pwrAck = 1; - this->txPowerSteps = txSteps; - } else { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); - txSteps = 0x0F; // set value to 'keep the same' - } - } - - uint8_t chMaskAck = 1; - // only apply channel mask when the RFU bit is not set - // (which is only set in internal MAC commands for changing Tx/Dr) - if(!isInternalTxDr) { - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - chMaskAck = (uint8_t)this->applyChannelMaskDyn(chMaskCntl, chMask); - - } else { // RADIOLIB_LORAWAN_BAND_FIXED - if(cmd->repeat == 1) { - // if this is the first ADR command in the queue, clear all saved channels - // so we can apply the new channel mask - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR mask: clearing channels"); - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - // clear all previous channel masks - memset(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS], 0, 16*8); - } else { - // if this is not the first ADR command, clear the ADR response that was in the queue - (void)deleteMacCommand(RADIOLIB_LORAWAN_MAC_LINK_ADR, &this->commandsUp); - } - chMaskAck = (uint8_t)this->applyChannelMaskFix(chMaskCntl, chMask); - - } - } - - if(nbTransMac) { // if there is a value for NbTrans, set this value - this->nbTrans = nbTransMac; - } - - // replace 'placeholder' or failed values with the current values for saving - // per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state - // but we don't bother and try to set each individual command - if(drUp == 0x0F || !drAck) { - cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4); - } - if(txSteps == 0x0F || !pwrAck) { - cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerSteps; - } - if(nbTransMac == 0) { - cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; - } - - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte - if(isInternalTxDr) { - memcpy(&(cmd->payload[1]), &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, 3); - } - - // if there was no channel mask (all zeroes), we should never apply that channel mask, so set RFU bit again - if(cmd->payload[1] == 0 && cmd->payload[2] == 0) { - cmd->payload[3] |= (1 << 7); - } - - // save to the single ADR MAC location - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], &(cmd->payload[0]), cmd->len); - - } else { // RADIOLIB_LORAWAN_BAND_FIXED - - // save Tx/Dr to the Link ADR position in the session buffer - uint8_t bufTxDr[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - bufTxDr[0] = cmd->payload[0]; - bufTxDr[3] = 1 << 7; - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], bufTxDr, cmd->len); - - // if RFU bit is set, this is just a change in Datarate or TxPower, in which case we don't save the channel masks - // if the RFU bit is not set, we must save this channel mask - if(!isInternalTxDr) { - // save the channel mask to the uplink channels position in session buffer, with Tx and DR set to 'same' - cmd->payload[0] = 0xFF; - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->payload, cmd->len); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Saving mask to ULChannels[%d]:", (cmd->repeat - 1) * cmd->len); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + (cmd->repeat - 1) * cmd->len, cmd->len); - } + // move on to next MAC command + i += fLen; + } + *lenInOut -= numDeleted; +} +int16_t LoRaWANNode::setDatarate(uint8_t drUp) { + // scan through all enabled channels and check if the requested datarate is available + bool isValidDR = false; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + LoRaWANChannel_t *chnl = &(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i]); + if(chnl->enabled) { + if(drUp >= chnl->drMin && drUp <= chnl->drMax) { + isValidDR = true; + break; } + } + } + if(!isValidDR) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } - // send the reply - cmd->len = 1; - cmd->payload[0] = (pwrAck << 2) | (drAck << 1) | (chMaskAck << 0); - cmd->repeat = 0; // discard any repeat value that may have been set - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRAns: status = 0x%02x", cmd->payload[0]); - return(true); - } break; + uint8_t cOcts[1]; + uint8_t cAck[1]; + uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + uint8_t cLen = 1; // only apply Dr/Tx field + cOcts[0] = (drUp << 4); // set requested datarate + cOcts[0] |= 0x0F; // keep Tx Power the same + (void)execMacCommand(cid, cOcts, cLen, cAck); - case(RADIOLIB_LORAWAN_MAC_DUTY_CYCLE): { - uint8_t maxDutyCycle = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DutyCycleReq: max duty cycle = 1/2^%d", maxDutyCycle); - if(maxDutyCycle == 0) { - this->dutyCycle = this->band->dutyCycle; - } else { - this->dutyCycle = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000 / (RadioLibTime_t)(1UL << maxDutyCycle); - } + // check if ACK is set for Datarate + if(!(cAck[0] & 0x02)) { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + return(RADIOLIB_ERR_NONE); +} - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE], cmd->payload, cmd->len); +int16_t LoRaWANNode::setTxPower(int8_t txPower) { + // only allow values within the band's (or MAC state) maximum + if(txPower > this->txPowerMax) { + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + // Tx Power is set in steps of two + // the selected value is rounded down to nearest multiple of two away from txPowerMax + // e.g. on EU868, max is 16; if 13 is selected then we set to 12 + uint8_t numSteps = (this->txPowerMax - txPower + 1) / (-RADIOLIB_LORAWAN_POWER_STEP_SIZE_DBM); - cmd->len = 0; - return(true); - } break; + uint8_t cOcts[1]; + uint8_t cAck[1]; + uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; + uint8_t cLen = 1; // only apply Dr/Tx field + cOcts[0] = 0xF0; // keep datarate the same + cOcts[0] |= numSteps; // set requested Tx Power + (void)execMacCommand(cid, cOcts, cLen, cAck); - case(RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP): { - // get the configuration - this->rx1DrOffset = (cmd->payload[0] & 0x70) >> 4; - uint8_t rx1OffsAck = 1; - this->rx2.drMax = cmd->payload[0] & 0x0F; - uint8_t rx2Ack = 1; - uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); - this->rx2.freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupReq: rx1DrOffset = %d, rx2DataRate = %d, freq = %f", this->rx1DrOffset, this->rx2.drMax, this->rx2.freq); - - // apply the configuration - uint8_t chanAck = 0; - if(this->phyLayer->setFrequency(this->rx2.freq) == RADIOLIB_ERR_NONE) { - chanAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); - } + // check if ACK is set for Tx Power + if(!(cAck[0] & 0x04)) { + return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); + } + + return(RADIOLIB_ERR_NONE); +} - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], cmd->payload, cmd->len); +int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { + // this can only be configured in ABP mode + if(this->lwMode != RADIOLIB_LORAWAN_MODE_ABP) { + return(RADIOLIB_ERR_INVALID_MODE); + } - // TODO this should be sent repeatedly until the next downlink - cmd->len = 1; - cmd->payload[0] = (rx1OffsAck << 2) | (rx2Ack << 1) | (chanAck << 0); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupAns: status = 0x%02x", cmd->payload[0]); - return(true); - } break; + // can only configure different datarate for dynamic bands + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); + } - case(RADIOLIB_LORAWAN_MAC_DEV_STATUS): { - // set the uplink reply - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusReq"); - cmd->len = 2; - cmd->payload[0] = this->battLevel; - int8_t snr = this->phyLayer->getSNR(); - cmd->payload[1] = snr & 0x3F; + // check if datarate is available in the selected band + if(this->band->dataRates[dr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + // find and check if the datarate is available for this radio module + DataRate_t dataRate; + int16_t state = findDataRate(dr, &dataRate); + RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DevStatusAns: status = 0x%02x%02x", cmd->payload[0], cmd->payload[1]); - return(true); - } break; + // passed all checks, so configure the datarate + this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr = dr; - case(RADIOLIB_LORAWAN_MAC_NEW_CHANNEL): { - // get the configuration - uint8_t chIndex = cmd->payload[0]; - uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); - float freq = (float)freqRaw/10000.0; - uint8_t maxDr = (cmd->payload[4] & 0xF0) >> 4; - uint8_t minDr = cmd->payload[4] & 0x0F; - - uint8_t newChAck = 0; - uint8_t freqAck = 0; + return(state); +} - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled = true; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx = chIndex; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq = freq; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin = minDr; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax = maxDr; - - // downlink channel is identical to uplink channel - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex] = this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex]; - newChAck = 1; - - // check if the frequency is possible - if(this->phyLayer->setFrequency(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq) == RADIOLIB_ERR_NONE) { - freqAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); - } - - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq:"); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][chIndex].drMax - ); +void LoRaWANNode::setADR(bool enable) { + this->adrEnabled = enable; +} - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); +void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { + this->dutyCycleEnabled = enable; + if(!enable) { + this->dutyCycle = 0; + } + if(msPerHour == 0) { + this->dutyCycle = this->band->dutyCycle; + } else { + this->dutyCycle = msPerHour; + } +} - // send the reply - cmd->len = 1; - cmd->payload[0] = (newChAck << 1) | (freqAck << 0); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelAns: status = 0x%02x", cmd->payload[0]); +void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { + this->dwellTimeEnabledUp = enable; + if(msPerUplink == 0) { + this->dwellTimeUp = this->band->dwellTimeUp; + } else { + this->dwellTimeUp = msPerUplink; + } +} - return(true); - } break; +// A user may enable CSMA to provide frames an additional layer of protection from interference. +// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma +void LoRaWANNode::setCSMA(bool csmaEnabled, uint8_t maxChanges, uint8_t backoffMax, uint8_t difsSlots) { + this->csmaEnabled = csmaEnabled; + if(csmaEnabled) { + this->maxChanges = maxChanges; + this->difsSlots = difsSlots; + this->backoffMax = backoffMax; + } else { + // disable all values + this->maxChanges = 0; + this->difsSlots = 0; + this->backoffMax = 0; + } +} - case(RADIOLIB_LORAWAN_MAC_DL_CHANNEL): { - // get the configuration - uint8_t chIndex = cmd->payload[0]; - uint32_t freqRaw = LoRaWANNode::ntoh(&cmd->payload[1], 3); - float freq = (float)freqRaw/10000.0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %f MHz", chIndex, freq); - uint8_t freqDlAck = 0; - uint8_t freqUlAck = 0; - - // check if the frequency is possible - if(this->phyLayer->setFrequency(freq) == RADIOLIB_ERR_NONE) { - freqDlAck = 1; - this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); - } - - // update the downlink frequency - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx == chIndex) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq = freq; - // check if the corresponding uplink frequency is actually set - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { - freqUlAck = 1; - } - } - } - - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + chIndex * cmd->len, cmd->payload, cmd->len); +void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { + this->battLevel = battLevel; +} - // TODO send this repeatedly until a downlink is received - cmd->len = 1; - cmd->payload[0] = (freqUlAck << 1) | (freqDlAck << 0); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelAns: status = 0x%02x", cmd->payload[0]); +void LoRaWANNode::scheduleTransmission(RadioLibTime_t tUplink) { + this->tUplink = tUplink; +} - return(true); - } break; +// return fCnt of last uplink; also return 0 if no uplink occured yet +uint32_t LoRaWANNode::getFCntUp() { + if(this->fCntUp == 0) { + return(0); + } + return(this->fCntUp - 1); +} - case(RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP): { - // get the configuration - uint8_t delay = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXTimingSetupReq: delay = %d sec", delay); - - // apply the configuration - if(delay == 0) { - delay = 1; - } - this->rxDelays[0] = delay * 1000; - this->rxDelays[1] = this->rxDelays[0] + 1000; +uint32_t LoRaWANNode::getNFCntDown() { + return(this->nFCntDown); +} - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], cmd->payload, cmd->len); +uint32_t LoRaWANNode::getAFCntDown() { + return(this->aFCntDown); +} - // send the reply - cmd->len = 0; +void LoRaWANNode::resetFCntDown() { + this->nFCntDown = 0; + this->aFCntDown = 0; +} - // TODO send this repeatedly until a downlink is received - return(true); - } break; +uint32_t LoRaWANNode::getDevAddr() { + return(this->devAddr); +} - case(RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP): { - uint8_t dlDwell = (cmd->payload[0] & 0x20) >> 5; - uint8_t ulDwell = (cmd->payload[0] & 0x10) >> 4; - uint8_t maxEirpRaw = cmd->payload[0] & 0x0F; +RadioLibTime_t LoRaWANNode::getLastToA() { + return(this->lastToA); +} - // who the f came up with this ... - const uint8_t eirpEncoding[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; - this->txPowerMax = eirpEncoding[maxEirpRaw]; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); +int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, int8_t pwr, size_t pre) { + // set the physical layer configuration + int16_t state = this->phyLayer->standby(); + if(state != RADIOLIB_ERR_NONE) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Failed to set radio into standby - is it connected?"); + return(state); + } - this->dwellTimeEnabledUp = ulDwell ? true : false; - this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; + // TODO implement PhysicalLayer::setModem() + // set modem-dependent functions + switch(this->band->dataRates[chnl->dr] & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { + case(RADIOLIB_LORAWAN_DATA_RATE_LORA): + this->modulation = RADIOLIB_LORAWAN_MODULATION_LORA; + // downlink messages are sent with inverted IQ + if(dir == RADIOLIB_LORAWAN_DOWNLINK) { + state = this->phyLayer->invertIQ(true); + } else { + state = this->phyLayer->invertIQ(false); + } + RADIOLIB_ASSERT(state); + break; + case(RADIOLIB_LORAWAN_DATA_RATE_FSK): + this->modulation = RADIOLIB_LORAWAN_MODULATION_GFSK; + state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); + RADIOLIB_ASSERT(state); + break; + case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): + this->modulation = RADIOLIB_LORAWAN_MODULATION_LR_FHSS; + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } - this->dwellTimeEnabledDn = dlDwell ? true : false; - this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %7.3f MHz", dir ? 'D' : 'U', chnl->freq / 10000.0); + state = this->phyLayer->setFrequency(chnl->freq / 10000.0); + RADIOLIB_ASSERT(state); + + // at this point, assume that Tx power value is already checked, so ignore the return value + // this call is only used to clip a value that is higher than the module supports + (void)this->phyLayer->checkOutputPower(pwr, &pwr); + state = this->phyLayer->setOutputPower(pwr); + RADIOLIB_ASSERT(state); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], cmd->payload, cmd->len); + DataRate_t dr; + state = findDataRate(chnl->dr, &dr); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setDataRate(dr); + RADIOLIB_ASSERT(state); - cmd->len = 0; - return(true); - } break; + if(this->modulation == RADIOLIB_LORAWAN_MODULATION_GFSK) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, TX = %d dBm, FD = %4.1f kHz", + dr.fsk.bitRate, pwr, dr.fsk.freqDev); + } + if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, TX = %d dBm, BW = %5.1f kHz, CR = 4/%d", + dr.lora.spreadingFactor, pwr, dr.lora.bandwidth, dr.lora.codingRate); + } - case(RADIOLIB_LORAWAN_MAC_REKEY): { - // get the server version - uint8_t srvVersion = cmd->payload[0]; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); - if((srvVersion > 0) && (srvVersion <= this->rev)) { - // valid server version, stop sending the ReKey MAC command - deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, &this->commandsUp); - } - return(false); + // this only needs to be done once-ish + uint8_t syncWord[4] = { 0 }; + uint8_t syncWordLen = 0; + size_t preLen = 0; + switch(this->modulation) { + case(RADIOLIB_LORAWAN_MODULATION_GFSK): { + preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); + syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; + syncWordLen = 3; } break; - case(RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP): { - this->adrLimitExp = (cmd->payload[0] & 0xF0) >> 4; - this->adrDelayExp = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADRParamSetupReq: limitExp = %d, delayExp = %d", this->adrLimitExp, this->adrDelayExp); - - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP], cmd->payload, cmd->len); - - cmd->len = 0; - return(true); + case(RADIOLIB_LORAWAN_MODULATION_LORA): { + preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; + syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; + syncWordLen = 1; } break; - case(RADIOLIB_LORAWAN_MAC_DEVICE_TIME): { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceTimeAns: [user]"); - cmd->repeat = 255; // prevent the command from being deleted by setting repeat to maximum - - return(false); + case(RADIOLIB_LORAWAN_MODULATION_LR_FHSS): { + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 24); + syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 16); + syncWord[2] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 8); + syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; + syncWordLen = 4; } break; - case(RADIOLIB_LORAWAN_MAC_FORCE_REJOIN): { - // TODO implement this - uint16_t rejoinReq = LoRaWANNode::ntoh(cmd->payload); - uint8_t period = (rejoinReq & 0x3800) >> 11; - uint8_t maxRetries = (rejoinReq & 0x0700) >> 8; - uint8_t rejoinType = (rejoinReq & 0x0070) >> 4; - uint8_t dr = rejoinReq & 0x000F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ForceRejoinReq: period = %d, maxRetries = %d, rejoinType = %d, dr = %d", period, maxRetries, rejoinType, dr); - (void)period; - (void)maxRetries; - (void)rejoinType; - (void)dr; - return(false); - } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } - case(RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP): { - // TODO implement this - uint8_t maxTime = (cmd->payload[0] & 0xF0) >> 4; - uint8_t maxCount = cmd->payload[0] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupReq: maxTime = %d, maxCount = %d", maxTime, maxCount); + state = this->phyLayer->setSyncWord(syncWord, syncWordLen); + RADIOLIB_ASSERT(state); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP], cmd->payload, cmd->len); + // if a preamble length is supplied, overrule the 'calculated' preamble length + if(pre) { + preLen = pre; + } + if(this->modulation != RADIOLIB_LORAWAN_MODULATION_LR_FHSS) { + state = this->phyLayer->setPreambleLength(preLen); + } + return(state); +} - cmd->len = 0; - cmd->payload[0] = (1 << 1) | 1; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RejoinParamSetupAns: status = 0x%02x", cmd->payload[0]); +// The following function implements LMAC, a CSMA scheme for LoRa as specified +// in the LoRa Alliance Technical Recommendation #13. +bool LoRaWANNode::csmaChannelClear(uint8_t difs, uint8_t numBackoff) { + // DIFS phase: perform #DIFS CAD operations + uint8_t numCads = 0; + for (; numCads < difs; numCads++) { + if (!this->cadChannelClear()) { + return(false); + } + } - (void)maxTime; - (void)maxCount; - return(true); - } break; + // BO phase: perform #numBackoff additional CAD operations + for (; numCads < difs + numBackoff; numCads++) { + if (!this->cadChannelClear()) { + return(false); + } } - return(false); + // none of the CADs showed activity, so all clear + return(true); } -void LoRaWANNode::printChannels() { - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, - - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax - ); - } +bool LoRaWANNode::cadChannelClear() { + int16_t state = this->phyLayer->scanChannel(); + // if activity was detected, channel is not clear + if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { + return(false); } + return(true); } -bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(chMaskCntl == 0) { - // apply the mask by looking at each channel bit - if(chMask & (1UL << i)) { - // if it should be enabled but is not currently defined, stop immediately - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - return(false); +void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45) { + // clear masks in case anything was set + *chMaskGrp0123 = 0; + *chMaskGrp45 = 0; + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; + if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + if(idx < 64) { + *chMaskGrp0123 |= ((uint64_t)1 << idx); + } else { + *chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); } - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; - } else { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = false; } - - } else if(chMaskCntl == 6) { - // enable all defined channels - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled = true; + } + } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED + // if a subband is set, we can set the channel indices straight from subband + if(this->subBand > 0 && this->subBand <= 8) { + // for sub band 1-8, set bank of 8 125kHz + single 500kHz channel + *chMaskGrp0123 |= 0xFF << ((this->subBand - 1) * 8); + *chMaskGrp45 |= 0x01 << ((this->subBand - 1) * 8); + } else if(this->subBand > 8 && this->subBand <= 12) { + // CN500 only: for sub band 9-12, set bank of 8 125kHz channels + *chMaskGrp45 |= 0xFF << ((this->subBand - 9) * 8); + } else { + // if subband is set to 0, all 125kHz channels are enabled + // however, we can 'only' store 16 channels, so we do not actually store these + // therefore, we select a random channel from each bank of 8 channels + uint8_t num125kHz = this->band->txSpans[0].numChannels; + uint8_t numBanks = num125kHz / 8; + for(uint8_t bank = 0; bank < numBanks; bank++) { + uint8_t bankIdx = this->phyLayer->random(8); + uint8_t idx = bank * 8 + bankIdx; + if(idx < 64) { + *chMaskGrp0123 |= ((uint64_t)1 << idx); + } else { + *chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); + } + } + // the 500 kHz channels are in the usual channel plan however + // these are the channel indices 64-71 for bands other than CN500 + if(this->band->bandNum != BandCN500) { + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; + if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE && idx >= 64) { + *chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); + } + } } } + } +} + +void LoRaWANNode::selectChannelPlanDyn(bool joinRequest) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); + size_t num = 0; + // copy the default defined channels into the first slots (where Tx = Rx) + for(; num < 3 && this->band->txFreqs[num].enabled; num++) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; + } + + // if we're about to send a JoinRequest, copy the JoinRequest channels to the next slots + if(joinRequest) { + size_t numJR = 0; + for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; + } + } + + // clear all remaining channels + for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } + // make sure the Rx2 settings are back to this band's default + this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; + + // make all enabled channels available for uplink selection + this->setAvailableChannels(0xFFFF); + #if RADIOLIB_DEBUG_PROTOCOL this->printChannels(); #endif - - return(true); } -bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("mask[%d] = 0x%04x", chMaskCntl, chMask); +// setup a subband and its corresponding JoinRequest datarate +// WARNING: subBand starts at 1 (corresponds to all populair schemes) +void LoRaWANNode::selectChannelPlanFix() { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", this->subBand); - // find out how many channels have already been configured - uint8_t idx = 0; + // clear all existing channels for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq > 0) { - idx++; - } + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } + + // get channel masks for this subband + uint64_t chMaskGrp0123 = 0; + uint32_t chMaskGrp45 = 0; + this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); + + // apply channel mask + this->applyChannelMask(chMaskGrp0123, chMaskGrp45); + + // make sure the Rx2 settings are back to this band's default + this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; - LoRaWANChannel_t chnl; - if((this->band->numTxSpans == 1 && chMaskCntl <= 5) || (this->band->numTxSpans == 2 && chMaskCntl <= 3)) { - // select channels from first span - for(uint8_t i = 0; i < 16; i++) { - uint16_t mask = 1 << i; - if(mask & chMask) { - uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95 - this->subBand = chNum / 8 + 1; // save configured subband in case we must reset the channels (1-based) - chnl.enabled = true; - chnl.idx = chNum; - chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; - chnl.drMin = this->band->txSpans[0].drMin; - chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + // make all enabled channels available for uplink selection + this->setAvailableChannels(0xFFFF); + + #if RADIOLIB_DEBUG_PROTOCOL + this->printChannels(); + #endif +} + +uint8_t LoRaWANNode::getAvailableChannels(uint16_t* chMask) { + uint8_t num = 0; + uint16_t mask = 0; + uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + // if channel is available and usable for current datarate, set corresponding bit + if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].available) { + if(currentDr >= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin && + currentDr <= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax) { + num++; + mask |= (0x0001 << i); } } + } + if(chMask) { + *chMask = mask; + } + return(num); +} +void LoRaWANNode::setAvailableChannels(uint16_t mask) { + for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + // if channel is enabled, set to available + if(mask & (0x0001 << i) && this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].available = true; + } else { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].available = false; + } } - if(this->band->numTxSpans == 1 && chMaskCntl == 6) { - // all channels on (but we revert to user-selected subband) - this->setupChannelsFix(this->subBand); +} + +int16_t LoRaWANNode::selectChannels() { + uint16_t chMask = 0x0000; + uint8_t numChannels = this->getAvailableChannels(&chMask); + // if there are no available channels, try resetting them all to available + if(numChannels == 0) { + this->setAvailableChannels(0xFFFF); + numChannels = this->getAvailableChannels(&chMask); + + // if there are still no channels available, give up + if(numChannels == 0) { + return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); + } } - if(this->band->numTxSpans == 2 && chMaskCntl == 4) { - // select channels from second span - for(uint8_t i = 0; i < 8; i++) { - uint16_t mask = 1 << i; - if(mask & chMask) { - uint8_t chNum = chMaskCntl * 16 + i; // 64 through 71 - chnl.enabled = true; - chnl.idx = chNum; - chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; - chnl.drMin = this->band->txSpans[1].drMin; - chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - } + + // select a random value within the number of possible channels + int chRand = this->phyLayer->random(numChannels); + + // retrieve the index of this channel by looping through the channel mask + int chIdx = -1; + while(chRand >= 0) { + chIdx++; + if(chMask & 0x0001) { + chRand--; } + chMask >>= 1; + } + + // as we are now going to use this channel, mark unavailable for next uplink + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][chIdx].available = false; + + uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + this->channels[RADIOLIB_LORAWAN_UPLINK] = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][chIdx]; + this->channels[RADIOLIB_LORAWAN_UPLINK].dr = currentDr; + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + // for dynamic bands, the downlink channel is the one matched to the uplink channel + this->channels[RADIOLIB_LORAWAN_DOWNLINK] = this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][chIdx]; + + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels + LoRaWANChannel_t channelDn = RADIOLIB_LORAWAN_CHANNEL_NONE; + channelDn.enabled = true; + channelDn.idx = this->channels[RADIOLIB_LORAWAN_UPLINK].idx % this->band->rx1Span.numChannels; + channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; + channelDn.drMin = this->band->rx1Span.drMin; + channelDn.drMax = this->band->rx1Span.drMax; + this->channels[RADIOLIB_LORAWAN_DOWNLINK] = channelDn; } - if(this->band->numTxSpans == 2 && chMaskCntl == 5) { - // a '1' enables a bank of 8 + 1 channels from 1st and 2nd span respectively - for(uint8_t i = 0; i < 8; i++) { - uint16_t mask = 1 << i; - if(mask & chMask) { - // enable bank of 8 channels from first span - for(uint8_t j = 0; j < 8; j++) { - uint8_t chNum = i * 8 + j; - chnl.enabled = true; - chnl.idx = chNum; - chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; - chnl.drMin = this->band->txSpans[0].drMin; - chnl.drMax = this->band->txSpans[0].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - } - // enable single channel from second span - uint8_t chNum = 64 + i; - chnl.enabled = true; - chnl.idx = chNum; - chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; - chnl.drMin = this->band->txSpans[1].drMin; - chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - } - } + uint8_t rx1Dr = this->band->rx1DrTable[currentDr][this->rx1DrOffset]; + // if downlink dwelltime is enabled, datarate < 2 cannot be used, so clip to 2 + // only in use on AS923_x bands + if(this->dwellTimeEnabledDn && rx1Dr < 2) { + rx1Dr = 2; } - if(this->band->numTxSpans == 2 && chMaskCntl == 6) { - // all channels on (but we revert to selected subband) - this->setupChannelsFix(this->subBand); + this->channels[RADIOLIB_LORAWAN_DOWNLINK].dr = rx1Dr; + + return(RADIOLIB_ERR_NONE); +} - // a '1' enables a single channel from second span - for(uint8_t i = 0; i < 8; i++) { - uint16_t mask = 1 << i; - if(mask & chMask) { - // enable single channel from second span - uint8_t chNum = 64 + i; +bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) { + int num = 0; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(chMaskGrp0123 & ((uint64_t)1 << i)) { + // if it should be enabled but is not currently defined, stop immediately + if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + return(false); + } + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled = true; + } else { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled = false; + } + } + } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED + LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + uint8_t spanNum = 0; + int chNum = 0; + int chOfs = 0; + for(; chNum < 64; chNum++) { + if(chMaskGrp0123 & ((uint64_t)1 << chNum)) { chnl.enabled = true; chnl.idx = chNum; - chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; - chnl.drMin = this->band->txSpans[1].drMin; - chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; + chnl.drMin = this->band->txSpans[spanNum].drMin; + chnl.drMax = this->band->txSpans[spanNum].drMax; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num++] = chnl; } } - - } - if(this->band->numTxSpans == 2 && chMaskCntl == 7) { - // all channels off (clear all channels) - chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = chnl; - // downlink channels are not defined so don't need to reset - } - idx = 0; - // a '1' enables a single channel from second span - for(uint8_t i = 0; i < 8; i++) { - uint16_t mask = 1 << i; - if(mask & chMask) { - // enable single channel from second span - uint8_t chNum = 64 + i; + if(this->band->numTxSpans > 1) { + spanNum += 1; + chNum = 0; + chOfs = 64; + } + for(; chNum < this->band->txSpans[spanNum].numChannels; chNum++) { + if(chMaskGrp45 & ((uint32_t)1 << chNum)) { chnl.enabled = true; - chnl.idx = chNum; - chnl.freq = this->band->txSpans[1].freqStart + i*this->band->txSpans[1].freqStep; - chnl.drMin = this->band->txSpans[1].drMin; - chnl.drMax = this->band->txSpans[1].drMax; - this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; + chnl.idx = chNum + chOfs; + chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; + chnl.drMin = this->band->txSpans[spanNum].drMin; + chnl.drMax = this->band->txSpans[spanNum].drMax; + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num++] = chnl; } } - } - #if RADIOLIB_DEBUG_PROTOCOL +#if RADIOLIB_DEBUG_PROTOCOL this->printChannels(); - #endif +#endif return(true); } -uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) { - for (LoRaWANMacSpec_t entry : MacTable) { - // cppcheck warns here we should use std::find_if, but some platforms may not have that - if (entry.cid == cid) { // cppcheck-suppress useStlAlgorithm - return entry.lenDn; +#if RADIOLIB_DEBUG_PROTOCOL +void LoRaWANNode::printChannels() { + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].freq / 10000.0, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin, + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax, + + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].idx, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].enabled, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].freq / 10000.0, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].drMin, + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].drMax + ); } } - // no idea about the length - return 0; } +#endif -int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { - uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload); - RADIOLIB_ASSERT(state); - - if(margin) { *margin = payload[0]; } - if(gwCnt) { *gwCnt = payload[1]; } +uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { + if((msg == NULL) || (len == 0)) { + return(0); + } - return(RADIOLIB_ERR_NONE); + RadioLibAES128Instance.init(key); + uint8_t cmac[RADIOLIB_AES128_BLOCK_SIZE]; + RadioLibAES128Instance.generateCMAC(msg, len, cmac); + return(((uint32_t)cmac[0]) | ((uint32_t)cmac[1] << 8) | ((uint32_t)cmac[2] << 16) | ((uint32_t)cmac[3]) << 24); } -int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { - uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; - int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload); - RADIOLIB_ASSERT(state); +bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { + if((msg == NULL) || (len < sizeof(uint32_t))) { + return(0); + } - if(gpsEpoch) { - *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); - if(returnUnix) { - uint32_t unixOffset = 315964800UL - 18UL; // 18 leap seconds since GPS epoch (Jan. 6th 1980) - *gpsEpoch += unixOffset; - } + // extract MIC from the message + uint32_t micReceived = LoRaWANNode::ntoh(&msg[len - sizeof(uint32_t)]); + + // calculate the expected value and compare + uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); + if(micCalculated != micReceived) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); + return(false); } - if(fraction) { *fraction = payload[4]; } - return(RADIOLIB_ERR_NONE); + return(true); } -uint32_t LoRaWANNode::getDevAddr() { - return(this->devAddr); +// given an airtime in milliseconds, calculate the minimum uplink interval +// to adhere to a given dutyCycle +RadioLibTime_t LoRaWANNode::dutyCycleInterval(RadioLibTime_t msPerHour, RadioLibTime_t airtime) { + if(msPerHour == 0 || airtime == 0) { + return(0); + } + RadioLibTime_t oneHourInMs = (RadioLibTime_t)60 * (RadioLibTime_t)60 * (RadioLibTime_t)1000; + float numPackets = msPerHour / airtime; + RadioLibTime_t delayMs = oneHourInMs / numPackets + 1; // + 1 to prevent rounding problems + return(delayMs); } -RadioLibTime_t LoRaWANNode::getLastToA() { - return(this->lastToA); +RadioLibTime_t LoRaWANNode::timeUntilUplink() { + Module* mod = this->phyLayer->getMod(); + RadioLibTime_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); + if(mod->hal->millis() > nextUplink){ + return(0); + } + return(nextUplink - mod->hal->millis() + 1); } -// The following function enables LMAC, a CSMA scheme for LoRa as specified -// in the LoRa Alliance Technical Recommendation #13. -// A user may enable CSMA to provide frames an additional layer of protection from interference. -// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma -void LoRaWANNode::performCSMA() { - - // Compute initial random back-off. - // When BO is reduced to zero, the function returns and the frame is transmitted. - uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1); - while (BO > 0) { - // DIFS: Check channel for DIFS_slots - bool channelFreeDuringDIFS = true; - for (uint8_t i = 0; i < this->difsSlots; i++) { - if (performCAD()) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during DIFS"); - channelFreeDuringDIFS = false; - // Channel is occupied during DIFS, hop to another. - this->selectChannels(); - break; - } - } - // Start reducing BO counter if DIFS slot was free. - if (channelFreeDuringDIFS) { - // Continue decrementing BO with per each CAD reporting free channel. - while (BO > 0) { - if (performCAD()) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Occupied channel during BO"); - // Channel is busy during CAD, hop to another and return to DIFS state again. - this->selectChannels(); - break; // Exit loop. Go back to DIFS state. - } - BO--; // Decrement BO by one if channel is free - } - } +uint8_t LoRaWANNode::getMaxPayloadLen() { + // configure the uplink channel properties + this->setPhyProperties(&this->channels[RADIOLIB_LORAWAN_UPLINK], + RADIOLIB_LORAWAN_UPLINK, + this->txPowerMax - 2*this->txPowerSteps); + + uint8_t minPayLen = 0; + uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; + if(this->TS011) { + maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater + } + + // if not limited by dwell-time, just return maximum + if(!this->dwellTimeEnabledUp) { + // subtract FHDR (13 bytes) as well as any FOpts + return(maxPayLen - 13 - this->fOptsUpLen); + } + + // fast exit in case upper limit is already good + if(this->phyLayer->getTimeOnAir(maxPayLen) / 1000 <= this->dwellTimeUp) { + // subtract FHDR (13 bytes) as well as any FOpts + return(maxPayLen - 13 - this->fOptsUpLen); + } + + // do some binary search to find maximum allowed payload length + uint8_t payLen = (minPayLen + maxPayLen) / 2; + while(payLen != minPayLen && payLen != maxPayLen) { + if(this->phyLayer->getTimeOnAir(payLen) / 1000 > this->dwellTimeUp) { + maxPayLen = payLen; + } else { + minPayLen = payLen; } + payLen = (minPayLen + maxPayLen) / 2; + } + // subtract FHDR (13 bytes) as well as any FOpts + return(payLen - 13 - this->fOptsUpLen); } -bool LoRaWANNode::performCAD() { - int16_t state = this->phyLayer->scanChannel(); - if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) { - return true; // Channel is busy - } - return false; // Channel is free + +int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { + int16_t state = this->phyLayer->standby(); + if(state != RADIOLIB_ERR_NONE) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Failed to set radio into standby - is it connected?"); + return(state); + } + + uint8_t dataRateBand = this->band->dataRates[dr]; + + switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { + case(RADIOLIB_LORAWAN_DATA_RATE_LORA): + dataRate->lora.spreadingFactor = ((dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_SF) >> 3) + 7; + switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): + dataRate->lora.bandwidth = 125.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): + dataRate->lora.bandwidth = 250.0; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): + dataRate->lora.bandwidth = 500.0; + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + dataRate->lora.codingRate = 5; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_FSK): + dataRate->fsk.bitRate = 50; + dataRate->fsk.freqDev = 25; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): + // not yet supported by DataRate_t + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + state = this->phyLayer->checkDataRate(*dataRate); + + return(state); } void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { @@ -3036,14 +3285,36 @@ void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_ } } -uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint16_t keyLen) { +int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { + // check if there are actually values in the buffer + size_t i = 0; + for(; i < size; i++) { + if(buffer[i]) { + break; + } + } + if(i == size) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // check integrity of the whole buffer (compare checksum to included checksum) + uint16_t checkSum = LoRaWANNode::checkSum16(buffer, size - 2); + uint16_t signature = LoRaWANNode::ntoh(&buffer[size - 2]); + if(signature != checkSum) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Calculated checksum: %04x, expected: %04x", checkSum, signature); + return(RADIOLIB_ERR_CHECKSUM_MISMATCH); + } + return(RADIOLIB_ERR_NONE); +} + +uint16_t LoRaWANNode::checkSum16(const uint8_t *key, uint16_t keyLen) { uint16_t checkSum = 0; for(uint16_t i = 0; i < keyLen; i += 2) { - checkSum ^= ((uint16_t)key[i] << 8) | key[i + 1]; - } - if(keyLen % 2 == 1) { - uint16_t val = ((uint16_t)key[keyLen - 1] << 8); - checkSum ^= val; + uint16_t word = (key[i] << 8); + if(i + 1 < keyLen) { + word |= key[i + 1]; + } + checkSum ^= word; } return(checkSum); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 5c2bbee97e..9b3dc6edb3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -47,42 +47,39 @@ // fPort field #define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only +#define RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN (0x01 << 0) // 7 0 start of user-allowed fPort range +#define RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX (0xDF << 0) // 7 0 end of user-allowed fPort range #define RADIOLIB_LORAWAN_FPORT_TS009 (0xE0 << 0) // 7 0 fPort used for TS009 testing +#define RADIOLIB_LORAWAN_FPORT_TS011 (0xE2 << 0) // 7 0 fPort used for TS011 Forwarding #define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 fPort values equal to and larger than this are reserved -// MAC commands - only those sent from end-device to gateway -#define RADIOLIB_LORAWAN_LINK_CHECK_REQ (0x02 << 0) // 7 0 MAC command: request to check connectivity to network -#define RADIOLIB_LORAWAN_LINK_ADR_ANS (0x03 << 0) // 7 0 answer to ADR change -#define RADIOLIB_LORAWAN_DUTY_CYCLE_ANS (0x04 << 0) // 7 0 answer to duty cycle change -#define RADIOLIB_LORAWAN_RX_PARAM_SETUP_ANS (0x05 << 0) // 7 0 answer to reception slot setup request -#define RADIOLIB_LORAWAN_DEV_STATUS_ANS (0x06 << 0) // 7 0 device status information -#define RADIOLIB_LORAWAN_NEW_CHANNEL_ANS (0x07 << 0) // 7 0 acknowledges change of a radio channel -#define RADIOLIB_LORAWAN_RX_TIMING_SETUP_ANS (0x08 << 0) // 7 0 acknowledges change of a reception slots timing - -#define RADIOLIB_LORAWAN_NOPTS_LEN (8) - // data rate encoding -#define RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K (0x01 << 7) // 7 7 FSK @ 50 kbps -#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x06 << 4) // 6 4 LoRa spreading factor: SF12 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x05 << 4) // 6 4 SF11 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x04 << 4) // 6 4 SF10 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x03 << 4) // 6 4 SF9 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x02 << 4) // 6 4 SF8 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x01 << 4) // 6 4 SF7 -#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x00 << 2) // 3 2 LoRa bandwidth: 500 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 2) // 3 2 250 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x02 << 2) // 3 2 125 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_RESERVED (0x03 << 2) // 3 2 reserved value -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_5 (0x00 << 0) // 1 0 LoRa coding rate: 4/5 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_6 (0x01 << 0) // 1 0 4/6 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_7 (0x02 << 0) // 1 0 4/7 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_4_8 (0x03 << 0) // 1 0 4/8 +#define RADIOLIB_LORAWAN_DATA_RATE_MODEM (0x03 << 6) // 7 6 modem mask +#define RADIOLIB_LORAWAN_DATA_RATE_LORA (0x00 << 6) // 7 6 use LoRa modem +#define RADIOLIB_LORAWAN_DATA_RATE_FSK (0x01 << 6) // 7 6 use FSK modem +#define RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS (0x02 << 6) // 7 6 use LR-FHSS modem +#define RADIOLIB_LORAWAN_DATA_RATE_SF (0x07 << 3) // 5 3 LoRa spreading factor mask +#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x05 << 3) // 5 3 LoRa spreading factor: SF12 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x04 << 3) // 5 3 SF11 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x03 << 3) // 5 3 SF10 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x02 << 3) // 5 3 SF9 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x01 << 3) // 5 3 SF8 +#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x00 << 3) // 5 3 SF7 +#define RADIOLIB_LORAWAN_DATA_RATE_BW (0x03 << 1) // 2 1 bandwith mask +#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x00 << 1) // 2 1 125 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 1) // 2 1 250 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x02 << 1) // 2 1 LoRa bandwidth: 500 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ (0x00 << 1) // 2 1 137 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ (0x01 << 1) // 2 1 336 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ (0x02 << 1) // 2 1 LR-FHSS bandwidth: 1523 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 (0x00 << 0) // 0 0 LR-FHSS coding rate: 1/3 +#define RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 (0x01 << 0) // 0 0 2/3 #define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate -#define RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK (0x00 << 0) -#define RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK (0x01 << 0) -#define RADIOLIB_LORAWAN_CHANNEL_DIR_BOTH (0x02 << 0) -#define RADIOLIB_LORAWAN_CHANNEL_DIR_NONE (0x03 << 0) +// channels and channel plans +#define RADIOLIB_LORAWAN_UPLINK (0x00 << 0) +#define RADIOLIB_LORAWAN_DOWNLINK (0x01 << 0) +#define RADIOLIB_LORAWAN_DIR_RX2 (0x02 << 0) #define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) #define RADIOLIB_LORAWAN_BAND_FIXED (1) #define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) @@ -118,14 +115,18 @@ #define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS (1) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS (4) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS (7) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS (4) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS (11) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS (12) -#define RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS (12) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS (13) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN (16) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_TYPE_POS (RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS + RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN - 1) +// join accept key derivation layout +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_JOIN_NONCE_POS (1) // regular keys +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_JOIN_EUI_POS (4) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_DEV_NONCE_POS (12) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_AES_DEV_ADDR_POS (1) // relay keys + // join accept message variables #define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_0 (0x00 << 7) // 7 7 LoRaWAN revision: 1.0 #define RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1 (0x01 << 7) // 7 7 1.1 @@ -135,6 +136,9 @@ #define RADIOLIB_LORAWAN_JOIN_ACCEPT_NWK_S_ENC_KEY (0x04) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_ENC_KEY (0x05) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY (0x06) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_ROOT_WOR_S_KEY (0x01) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_WOR_S_INT_KEY (0x01) +#define RADIOLIB_LORAWAN_JOIN_ACCEPT_WOR_S_ENC_KEY (0x02) // frame header layout #define RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS (16) @@ -172,8 +176,13 @@ // unused frame counter value #define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) +// TR013 CSMA recommended values +#define RADIOLIB_LORAWAN_DIFS_DEFAULT (2) +#define RADIOLIB_LORAWAN_BACKOFF_MAX_DEFAULT (6) +#define RADIOLIB_LORAWAN_MAX_CHANGES_DEFAULT (4) + // MAC commands -#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16) +#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (23) #define RADIOLIB_LORAWAN_MAC_RESET (0x01) #define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02) @@ -204,10 +213,10 @@ #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) /*! - \struct LoRaWANMacSpec_t + \struct LoRaWANMacCommand_t \brief MAC command specification structure. */ -struct LoRaWANMacSpec_t { +struct LoRaWANMacCommand_t { /*! \brief Command ID */ const uint8_t cid; @@ -216,87 +225,58 @@ struct LoRaWANMacSpec_t { /*! \brief Downlink message length */ const uint8_t lenUp; + + /*! \brief Some commands must be resent until Class A downlink received */ + const bool persist; /*! \brief Whether this MAC command can be issued by the user or not */ const bool user; }; -constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = { - { 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting - { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true }, - { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false }, - { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false }, - { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false }, - { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false }, - { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true }, - { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false }, - { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false }, - { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true } -}; - -/*! - \struct LoRaWANMacCommand_t - \brief Structure to save information about MAC command -*/ -struct LoRaWANMacCommand_t { - /*! \brief The command ID */ - uint8_t cid; - - /*! \brief Payload buffer (5 bytes is the longest possible) */ - uint8_t payload[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN]; - - /*! \brief Length of the payload */ - uint8_t len; - - /*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */ - uint8_t repeat; -}; - -/*! - \struct LoRaWANMacCommandQueue_t - \brief Structure to hold information about a queue of MAC commands -*/ -struct LoRaWANMacCommandQueue_t { - /*! \brief Number of commands in the queue */ - uint8_t numCommands; - - /*! \brief Total length of the queue */ - uint8_t len; - - /*! \brief MAC command buffer */ - LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE]; +#define RADIOLIB_LORAWAN_MAC_COMMAND_NONE { .cid = 0, .lenDn = 0, .lenUp = 0, .persist = false, .user = false } + +constexpr LoRaWANMacCommand_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS] = { + { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, false, true }, + { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false, false }, + { RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, true, false }, + { RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false, false }, + { RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, true, false }, + { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, true, false }, + { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, true, false }, + { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false, false }, + { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, false, true }, + { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false, false }, + { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, false, true }, }; #define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) enum LoRaWANSchemeBase_t { RADIOLIB_LORAWAN_NONCES_START = 0x00, - RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes - RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte - RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte - RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes - RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte - RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size + RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes + RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes + RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte + RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size }; enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_START = 0x00, - RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes - RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes - RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes + RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes + RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 4 bytes RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes @@ -306,22 +286,24 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte - RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn, // 4 bytes - RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte - RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes - RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes - RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte - RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes - RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes - RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes - RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + 1, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + 4, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + 1, // 3 bytes + RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes + RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte + RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*5, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*4, // 15 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN + RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN, // 4 bytes RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_LINK_ADR + MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, // 4 bytes + RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 14 bytes + RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS = RADIOLIB_LORAWAN_SESSION_LINK_ADR + 14, // 2 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS + 2, // 4 bytes RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size }; @@ -338,18 +320,25 @@ struct LoRaWANChannel_t { /*! \brief The channel number, as specified by defaults or the network */ uint8_t idx; - /*! \brief The channel frequency */ - float freq; + /*! \brief The channel frequency (coded in 100 Hz steps) */ + uint32_t freq; /*! \brief Minimum allowed datarate for this channel */ uint8_t drMin; /*! \brief Maximum allowed datarate for this channel (inclusive) */ uint8_t drMax; + + /*! \brief Datarate currently in use on this channel */ + uint8_t dr; + + /*! \brief Whether this channel is available for channel selection */ + bool available; }; // alias for unused channel -#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, .drMin = 0, .drMax = 0 } +#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, \ + .drMin = 0, .drMax = 0, .dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .available = false } /*! \struct LoRaWANChannelSpan_t @@ -360,11 +349,11 @@ struct LoRaWANChannelSpan_t { /*! \brief Total number of channels in the span */ uint8_t numChannels; - /*! \brief Center frequency of the first channel in span */ - float freqStart; + /*! \brief Center frequency of the first channel in span (coded in 100 Hz steps) */ + uint32_t freqStart; - /*! \brief Frequency step between adjacent channels */ - float freqStep; + /*! \brief Frequency step between adjacent channels (coded in 100 Hz steps) */ + uint32_t freqStep; /*! \brief Minimum allowed datarate for all channels in this span */ uint8_t drMin; @@ -373,11 +362,11 @@ struct LoRaWANChannelSpan_t { uint8_t drMax; /*! \brief Allowed data rates for a join request message */ - uint8_t joinRequestDataRate; + uint8_t drJoinRequest; }; // alias for unused channel span -#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } +#define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } /*! \struct LoRaWANBand_t @@ -390,7 +379,13 @@ struct LoRaWANBand_t { /*! \brief Whether the channels are fixed per specification, or dynamically allocated through the network (plus defaults) */ uint8_t bandType; - /*! \brief Array of allowed maximum payload lengths for each data rate */ + /*! \brief Minimum allowed frequency (coded in 100 Hz steps) */ + uint32_t freqMin; + + /*! \brief Maximum allowed frequency (coded in 100 Hz steps) */ + uint32_t freqMax; + + /*! \brief Array of allowed maximum payload lengths for each data rate (global maximum) */ uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; /*! \brief Maximum allowed output power in this band in dBm */ @@ -408,26 +403,34 @@ struct LoRaWANBand_t { /*! \brief Maximum dwell time per downlink message in milliseconds */ RadioLibTime_t dwellTimeDn; - /*! \brief A set of default uplink (TX) channels for frequency-type bands */ + /*! \brief Whether this band implements the MAC command TxParamSetupReq */ + bool txParamSupported; + + /*! \brief A set of default uplink (TX) channels for dynamic bands */ LoRaWANChannel_t txFreqs[3]; - /*! \brief A set of possible extra channels for the Join-Request message for frequency-type bands */ + /*! \brief A set of possible extra channels for the Join-Request message for dynamic bands */ LoRaWANChannel_t txJoinReq[3]; - /*! \brief The number of TX channel spans for mask-type bands */ + /*! \brief The number of TX channel spans for fixed bands */ uint8_t numTxSpans; - /*! \brief Default uplink (TX) channel spans for mask-type bands, including Join-Request parameters */ + /*! \brief Default uplink (TX) channel spans for fixed bands, including Join-Request parameters */ LoRaWANChannelSpan_t txSpans[2]; - /*! \brief Default downlink (RX1) channel span for mask-type bands */ + /*! \brief Default downlink (RX1) channel span for fixed bands */ LoRaWANChannelSpan_t rx1Span; - /*! \brief The base downlink data rate. Used to calculate data rate changes for adaptive data rate */ - uint8_t rx1DataRateBase; + uint8_t rx1DrTable[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES][8]; /*! \brief Backup channel for downlink (RX2) window */ LoRaWANChannel_t rx2; + + /*! \brief Relay channels for WoR uplink */ + LoRaWANChannel_t txWoR[2]; + + /*! \brief Relay channels for ACK downlink */ + LoRaWANChannel_t txAck[2]; /*! \brief The corresponding datarates, bandwidths and coding rates for DR index */ uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; @@ -515,6 +518,9 @@ struct LoRaWANEvent_t { /*! \brief Port number */ uint8_t fPort; + + /*! \brief Number of times this uplink was transmitted (ADR)*/ + uint8_t nbTrans; }; /*! @@ -532,11 +538,6 @@ class LoRaWANNode { */ LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand = 0); - /*! - \brief Clear an active session, so that the device will have to rejoin the network. - */ - void clearSession(); - /*! \brief Returns the pointer to the internal buffer that holds the LW base parameters \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_NONCES_BUF_SIZE @@ -550,6 +551,11 @@ class LoRaWANNode { */ int16_t setBufferNonces(uint8_t* persistentBuffer); + /*! + \brief Clear an active session, so that the device will have to rejoin the network. + */ + void clearSession(); + /*! \brief Returns the pointer to the internal buffer that holds the LW session parameters \returns Pointer to uint8_t array of size RADIOLIB_LORAWAN_SESSION_BUF_SIZE @@ -569,16 +575,9 @@ class LoRaWANNode { \param devEUI 8-byte device identifier. \param nwkKey Pointer to the network AES-128 key. \param appKey Pointer to the application AES-128 key. - */ - void beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey); - - /*! - \brief Join network by restoring OTAA session or performing over-the-air activation. By this procedure, - the device will perform an exchange with the network server and set all necessary configuration. - \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - int16_t activateOTAA(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey); /*! \brief Set the device credentials and activation configuration @@ -588,8 +587,17 @@ class LoRaWANNode { \param nwkSEncKey Pointer to the MAC command network session key [NwkSEncKey] (LoRaWAN 1.1) or network session AES-128 key [NwkSKey] (LoRaWAN 1.0). \param appSKey Pointer to the application session AES-128 key. + \returns \ref status_codes */ - void beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey); + int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey); + + /*! + \brief Join network by restoring OTAA session or performing over-the-air activation. By this procedure, + the device will perform an exchange with the network server and set all necessary configuration. + \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) + \returns \ref status_codes + */ + virtual int16_t activateOTAA(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL); /*! \brief Join network by restoring ABP session or performing over-the-air activation. @@ -602,103 +610,34 @@ class LoRaWANNode { /*! \brief Whether there is an ongoing session active */ bool isActivated(); - /*! - \brief Configure the Rx2 datarate for ABP mode. - This should not be needed for LoRaWAN 1.1 as it is configured through the first downlink. - \param dr The datarate to be used for listening for downlinks in Rx2. - \returns \ref status_codes - */ - int16_t setRx2Dr(uint8_t dr); - - /*! - \brief Add a MAC command to the uplink queue. - Only LinkCheck and DeviceTime are available to the user. - Other commands are ignored; duplicate MAC commands are discarded. - \param cid ID of the MAC command - \returns \ref status_codes - */ - int16_t sendMacCommandReq(uint8_t cid); - #if defined(RADIOLIB_BUILD_ARDUINO) /*! - \brief Send a message to the server. - \param str Address of Arduino String that will be transmitted. - \param fPort Port number to send the message to. - \param isConfirmed Whether to send a confirmed uplink or not. - \param event Pointer to a structure to store extra information about the event - (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes - */ - int16_t uplink(String& str, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); - #endif - - /*! - \brief Send a message to the server. - \param str C-string that will be transmitted. - \param fPort Port number to send the message to. - \param isConfirmed Whether to send a confirmed uplink or not. - \param event Pointer to a structure to store extra information about the event - (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes - */ - int16_t uplink(const char* str, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); - - /*! - \brief Send a message to the server. - \param data Data to send. - \param len Length of the data. + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \param strUp Address of Arduino String that will be transmitted. \param fPort Port number to send the message to. + \param strDown Address of Arduino String to save the received data. \param isConfirmed Whether to send a confirmed uplink or not. - \param event Pointer to a structure to store extra information about the event + \param eventUp Pointer to a structure to store extra information about the uplink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes - */ - int16_t uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* event = NULL); - - #if defined(RADIOLIB_BUILD_ARDUINO) - /*! - \brief Wait for downlink from the server in either RX1 or RX2 window. - \param str Address of Arduino String to save the received data. - \param event Pointer to a structure to store extra information about the event + \param eventDown Pointer to a structure to store extra information about the downlink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes + \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - int16_t downlink(String& str, LoRaWANEvent_t* event = NULL); + virtual int16_t sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); #endif - /*! - \brief Wait for downlink from the server in either RX1 or RX2 window. - \param data Buffer to save received data into. - \param len Pointer to variable that will be used to save the number of received bytes. - \param event Pointer to a structure to store extra information about the event - (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes - */ - int16_t downlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); - - /*! - \brief Wait for downlink, simplified to allow for simpler sendReceive - \param event Pointer to a structure to store extra information about the event - (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes - */ - int16_t downlink(LoRaWANEvent_t* event = NULL); - - #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. - \param strUp Address of Arduino String that will be transmitted. + \param strUp C-string that will be transmitted. \param fPort Port number to send the message to. - \param strDown Address of Arduino String to save the received data. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes + \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - int16_t sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); - #endif + virtual int16_t sendReceive(const char* strUp, uint8_t fPort, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. @@ -711,71 +650,69 @@ class LoRaWANNode { (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes + \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - int16_t sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + virtual int16_t sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! - \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. + \brief Send a message to the server and wait for a downlink but don't bother the user with downlink contents \param dataUp Data to send. \param lenUp Length of the data. \param fPort Port number to send the message to. - \param dataDown Buffer to save received data into. - \param lenDown Pointer to variable that will be used to save the number of received bytes. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes + \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + virtual int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! - \brief Send a message to the server and wait for a downlink but don't bother the user with downlink contents + \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. \param dataUp Data to send. \param lenUp Length of the data. \param fPort Port number to send the message to. + \param dataDown Buffer to save received data into. + \param lenDown Pointer to variable that will be used to save the number of received bytes. \param isConfirmed Whether to send a confirmed uplink or not. \param eventUp Pointer to a structure to store extra information about the uplink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \param eventDown Pointer to a structure to store extra information about the downlink event (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. - \returns \ref status_codes + \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + virtual int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! - \brief Set device status. - \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, - 254 for highest battery, 255 for unable to measure. - */ - void setDeviceStatus(uint8_t battLevel); - - /*! - \brief Returns the last uplink's frame counter; - also 0 if no uplink occured yet. - */ - uint32_t getFCntUp(); - - /*! - \brief Returns the last network downlink's frame counter; - also 0 if no network downlink occured yet. + \brief Add a MAC command to the uplink queue. + Only LinkCheck and DeviceTime are available to the user. + Other commands are ignored; duplicate MAC commands are discarded. + \param cid ID of the MAC command + \returns \ref status_codes */ - uint32_t getNFCntDown(); + int16_t sendMacCommandReq(uint8_t cid); - /*! - \brief Returns the last application downlink's frame counter; - also 0 if no application downlink occured yet. + /*! + \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. + Returns 'true' if a network response was successfully parsed. + Returns 'false' if there was no network response / parsing failed. + \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. + \param gwCnt Number of gateways that received the LinkCheckReq. + \returns \ref status_codes */ - uint32_t getAFCntDown(); + int16_t getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt); - /*! - \brief Reset the downlink frame counters (application and network) - This is unsafe and can possibly allow replay attacks using downlinks. - It mainly exists as part of the TS009 Specification Verification protocol. + /*! + \brief Returns the network time after requesting a DeviceTime MAC command. + Returns 'true' if a network response was successfully parsed. + Returns 'false' if there was no network response / parsing failed. + \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) + \param fraction Fractional-second, in 1/256-second steps + \param returnUnix If true, returns Unix timestamp instead of GPS (default true) + \returns \ref status_codes */ - void resetFCntDown(); + int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); /*! \brief Set uplink datarate. This should not be used when ADR is enabled. @@ -784,6 +721,21 @@ class LoRaWANNode { */ int16_t setDatarate(uint8_t drUp); + /*! + \brief Configure TX power of the radio module. + \param txPower Output power during TX mode to be set in dBm. + \returns \ref status_codes + */ + int16_t setTxPower(int8_t txPower); + + /*! + \brief Configure the Rx2 datarate for ABP mode. + This should not be needed for LoRaWAN 1.1 as it is configured through the first downlink. + \param dr The datarate to be used for listening for downlinks in Rx2. + \returns \ref status_codes + */ + int16_t setRx2Dr(uint8_t dr); + /*! \brief Toggle ADR to on or off. \param enable Whether to disable ADR or not. @@ -798,18 +750,6 @@ class LoRaWANNode { */ void setDutyCycle(bool enable = true, RadioLibTime_t msPerHour = 0); - /*! - \brief Calculate the minimum interval to adhere to a certain dutyCycle. - This interval is based on the ToA of one uplink and does not actually keep track of total airtime. - \param msPerHour The maximum allowed duty cycle (in milliseconds per hour). - \param airtime The airtime of the uplink. - \returns Required interval (delay) in milliseconds between consecutive uplinks. - */ - RadioLibTime_t dutyCycleInterval(RadioLibTime_t msPerHour, RadioLibTime_t airtime); - - /*! \brief Returns time in milliseconds until next uplink is available under dutyCycle limits */ - RadioLibTime_t timeUntilUplink(); - /*! \brief Toggle adherence to dwellTime limits to on or off. \param enable Whether to adhere to dwellTime limits or not (default true). @@ -818,40 +758,55 @@ class LoRaWANNode { */ void setDwellTime(bool enable, RadioLibTime_t msPerUplink = 0); - /*! - \brief Returns the maximum payload given the currently present dwell time limits. - WARNING: the addition of MAC commands may cause uplink errors; - if you want to be sure that your payload fits within dwell time limits, subtract 16 from the result! + /*! + \brief Configures CSMA for LoRaWAN as per TR013, LoRa Alliance. + \param csmaEnabled Enable/disable CSMA for LoRaWAN. + \param maxChanges Maximum number of channel hops if channel is used (default 4). + \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO (default). + \param difsSlots Num of CADs to estimate a clear CH (default 2). */ - uint8_t maxPayloadDwellTime(); + void setCSMA(bool csmaEnabled, uint8_t maxChanges = 4, uint8_t backoffMax = 0, uint8_t difsSlots = 2); /*! - \brief Configure TX power of the radio module. - \param txPower Output power during TX mode to be set in dBm. - \returns \ref status_codes + \brief Set device status. + \param battLevel Battery level to set. 0 for external power source, 1 for lowest battery, + 254 for highest battery, 255 for unable to measure. */ - int16_t setTxPower(int8_t txPower); + void setDeviceStatus(uint8_t battLevel); /*! - \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. - Returns 'true' if a network response was successfully parsed. - Returns 'false' if there was no network response / parsing failed. - \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. - \param gwCnt Number of gateways that received the LinkCheckReq. - \returns \ref status_codes + \brief Set the exact time a transmission should occur. Note: this is the internal clock time. + On Arduino platforms, this is the usual time supplied by millis(). + If the supplied time is larger than the current time, sendReceive() or uplink() will delay + until the scheduled time. + \param tUplink Transmission time in milliseconds, based on internal clock. */ - int16_t getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt); + void scheduleTransmission(RadioLibTime_t tUplink); - /*! - \brief Returns the network time after requesting a DeviceTime MAC command. - Returns 'true' if a network response was successfully parsed. - Returns 'false' if there was no network response / parsing failed. - \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) - \param fraction Fractional-second, in 1/256-second steps - \param returnUnix If true, returns Unix timestamp instead of GPS (default true) - \returns \ref status_codes + /*! + \brief Returns the last uplink's frame counter; + also 0 if no uplink occured yet. */ - int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); + uint32_t getFCntUp(); + + /*! + \brief Returns the last network downlink's frame counter; + also 0 if no network downlink occured yet. + */ + uint32_t getNFCntDown(); + + /*! + \brief Returns the last application downlink's frame counter; + also 0 if no application downlink occured yet. + */ + uint32_t getAFCntDown(); + + /*! + \brief Reset the downlink frame counters (application and network) + This is unsafe and can possibly allow replay attacks using downlinks. + It mainly exists as part of the TS009 Specification Verification protocol. + */ + void resetFCntDown(); /*! \brief Returns the DevAddr of the device, regardless of OTAA or ABP mode @@ -865,6 +820,24 @@ class LoRaWANNode { */ RadioLibTime_t getLastToA(); + /*! + \brief Calculate the minimum interval to adhere to a certain dutyCycle. + This interval is based on the ToA of one uplink and does not actually keep track of total airtime. + \param msPerHour The maximum allowed duty cycle (in milliseconds per hour). + \param airtime The airtime of the uplink. + \returns Required interval (delay) in milliseconds between consecutive uplinks. + */ + RadioLibTime_t dutyCycleInterval(RadioLibTime_t msPerHour, RadioLibTime_t airtime); + + /*! \brief Returns time in milliseconds until next uplink is available under dutyCycle limits */ + RadioLibTime_t timeUntilUplink(); + + /*! + \brief Returns the maximum allowed uplink payload size given the current MAC state. + Most importantly, this includes dwell time limitations and ADR. + */ + uint8_t getMaxPayloadLen(); + /*! \brief TS009 Protocol Specification Verification switch (allows FPort 224 and cuts off uplink payload instead of rejecting if maximum length exceeded). @@ -886,31 +859,21 @@ class LoRaWANNode { RadioLibTime_t scanGuard = 10; #if !RADIOLIB_GODMODE - private: + protected: #endif PhysicalLayer* phyLayer = NULL; const LoRaWANBand_t* band = NULL; - static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); - - void activateCommon(uint8_t initialDr); - // a buffer that holds all LW base parameters that should persist at all times! uint8_t bufferNonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE] = { 0 }; // a buffer that holds all LW session parameters that preferably persist, but can be afforded to get lost uint8_t bufferSession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE] = { 0 }; - LoRaWANMacCommandQueue_t commandsUp = { - .numCommands = 0, - .len = 0, - .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, - }; - LoRaWANMacCommandQueue_t commandsDown = { - .numCommands = 0, - .len = 0, - .commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } }, - }; + uint8_t fOptsUp[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN] = { 0 }; + uint8_t fOptsDown[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN] = { 0 }; + uint8_t fOptsUpLen = 0; + uint8_t fOptsDownLen = 0; uint16_t lwMode = RADIOLIB_LORAWAN_MODE_NONE; uint8_t lwClass = RADIOLIB_LORAWAN_CLASS_A; @@ -955,6 +918,7 @@ class LoRaWANNode { // ADR is enabled by default bool adrEnabled = true; + bool adrAckReq = false; // duty cycle is set upon initialization and activated in regions that impose this bool dutyCycleEnabled = false; @@ -965,29 +929,34 @@ class LoRaWANNode { uint16_t dwellTimeUp = 0; bool dwellTimeEnabledDn = false; uint16_t dwellTimeDn = 0; - + + RadioLibTime_t tUplink = 0; // scheduled uplink transmission time (internal clock) + RadioLibTime_t tDownlink = 0; // time at end of downlink reception + // enable/disable CSMA for LoRaWAN - bool enableCSMA; + bool csmaEnabled = false; + + // maximum number of channel hops during CSMA + uint8_t maxChanges = RADIOLIB_LORAWAN_MAX_CHANGES_DEFAULT; - // number of backoff slots to be decremented after DIFS phase. 0 to disable BO. + // number of backoff slots to be checked after DIFS phase. // A random BO avoids collisions in the case where two or more nodes start the CSMA // process at the same time. - uint8_t backoffMax; + uint8_t backoffMax = RADIOLIB_LORAWAN_BACKOFF_MAX_DEFAULT; // number of CADs to estimate a clear CH - uint8_t difsSlots; + uint8_t difsSlots = RADIOLIB_LORAWAN_DIFS_DEFAULT; // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t availableChannels[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; - - // currently configured channels for TX and RX1 - LoRaWANChannel_t currentChannels[2] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; + LoRaWANChannel_t channelPlan[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; - // currently configured datarates for TX and RX1 - uint8_t dataRates[2] = { RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED }; + // currently configured channels for TX, RX1, RX2 + LoRaWANChannel_t channels[3] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }; - // Rx2 channel properties - may be changed by MAC command - LoRaWANChannel_t rx2 = RADIOLIB_LORAWAN_CHANNEL_NONE; + // delays between the uplink and RX1/2 windows + // the first field is meaningless, but is used for offsetting for Rx windows 1 and 2 + RadioLibTime_t rxDelays[3] = { 0, RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; // offset between TX and RX1 (such that RX1 has equal or lower DR) uint8_t rx1DrOffset = 0; @@ -1004,9 +973,6 @@ class LoRaWANNode { // timestamp when the Rx1/2 windows were closed (timeout or uplink received) RadioLibTime_t rxDelayEnd = 0; - // delays between the uplink and RX1/2 windows - RadioLibTime_t rxDelays[2] = { RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; - // device status - battery level uint8_t battLevel = 0xFF; @@ -1016,94 +982,142 @@ class LoRaWANNode { // save the selected sub-band in case this must be restored in ADR control uint8_t subBand = 0; - // initalize the Nonces buffer after beginX() has been called - void createNonces(); + // allow port 226 for devices implementing TS011 + bool TS011 = false; // this will reset the device credentials, so the device starts completely new void clearNonces(); - // wait for, open and listen during Rx1 and Rx2 windows; only performs listening - int16_t downlinkCommon(); + // start a fresh session using default parameters + void createSession(uint16_t lwMode, uint8_t initialDr); - // method to generate message integrity code - uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); + // setup Join-Request payload + void composeJoinRequest(uint8_t* joinRequestMsg); - // method to verify message integrity code - // it assumes that the MIC is the last 4 bytes of the message - bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); + // extract Join-Accept payload and start a new session + int16_t processJoinAccept(LoRaWANJoinEvent_t *joinEvent); - // configure the common physical layer properties (preamble, sync word etc.) - // channels must be configured separately by setupChannelsDyn()! - int16_t setPhyProperties(uint8_t dir); + // a join-accept can piggy-back a set of channels or channel masks + void processCFList(uint8_t* cfList); - // print the available channels through debug - void printChannels(); + // check whether payload length and fport are allowed + int16_t isValidUplink(uint8_t* len, uint8_t fPort); + + // perform ADR backoff + void adrBackoff(); - // setup uplink/downlink channel data rates and frequencies - // for dynamic channels, there is a small set of predefined channels - // in case of JoinRequest, add some optional extra frequencies - int16_t setupChannelsDyn(bool joinRequest = false); + // create an encrypted uplink buffer, composing metadata, user data and MAC data + void composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed); - // setup uplink/downlink channel data rates and frequencies - // for fixed bands, we only allow one sub-band at a time to be selected - int16_t setupChannelsFix(uint8_t subBand); + // generate and set the MIC of an uplink buffer (depends on selected channels) + void micUplink(uint8_t* inOut, uint8_t lenInOut); - // a join-accept can piggy-back a set of channels or channel masks - int16_t processCFList(uint8_t* cfList); + // transmit uplink buffer on a specified channel + int16_t transmitUplink(LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans); - // select a set of random TX/RX channels for up- and downlink - int16_t selectChannels(); + // wait for, open and listen during receive windows; only performs listening + int16_t receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChannels, const RadioLibTime_t* dlDelays, uint8_t numWindows, RadioLibTime_t tReference); - // find the first usable data rate for the given band - int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); + // extract downlink payload and process MAC commands + int16_t parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); + + // execute mac command, return the number of processed bytes for sequential processing + bool execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn); + bool execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uint8_t* optOut); - // restore all available channels from persistent storage - int16_t restoreChannels(); + // possible override for additional MAC commands that are not in the base specification + virtual bool derivedMacHandler(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uint8_t* optOut); - // parse a MAC command queue into a buffer (uplinks) - void macQueueToBuff(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer); + // pre-process a (set of) LinkAdrReq commands into one super-channel-mask + Tx/Dr/NbTrans fields + void preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAdrOpt); - // parse a MAC buffer into a command queue (downlinks) - void macBufftoQueue(LoRaWANMacCommandQueue_t* queue, uint8_t* buffer, uint8_t len); + // post-process a (set of) LinkAdrAns commands depending on LoRaWAN version + void postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen); - // push MAC command to queue, done by copy - int16_t pushMacCommand(LoRaWANMacCommand_t* cmd, LoRaWANMacCommandQueue_t* queue); + // get the properties of a MAC command given a certain command ID + int16_t getMacCommand(uint8_t cid, LoRaWANMacCommand_t* cmd); - // delete a specific MAC command from queue, indicated by the command ID - // if a payload pointer is supplied, this returns the payload of the MAC command - int16_t deleteMacCommand(uint8_t cid, LoRaWANMacCommandQueue_t* queue, uint8_t* payload = NULL); + // possible override for additional MAC commands that are not in the base specification + virtual int16_t derivedMacFinder(uint8_t cid, LoRaWANMacCommand_t* cmd); - // execute mac command, return the number of processed bytes for sequential processing - bool execMacCommand(LoRaWANMacCommand_t* cmd); + // get the length of a certain MAC command in a specific direction (up/down) + // if inclusive is true, add one for the CID byte + int16_t getMacLen(uint8_t cid, uint8_t* len, uint8_t dir, bool inclusive = false); - // apply a channel mask to a set of readily defined channels (dynamic bands only) - bool applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask); + // find out of a MAC command should persist destruction + // in uplink direction, some commands must persist if no downlink is received + // in downlink direction, the user-accessible MAC commands remain available for retrieval + bool isPersistentMacCommand(uint8_t cid, uint8_t dir); - // define or delete channels from a fixed set of channels (fixed bands only) - bool applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask); + // push MAC command to queue, done by copy + int16_t pushMacCommand(uint8_t cid, uint8_t* cOcts, uint8_t* out, uint8_t* lenOut, uint8_t dir); - // get the payload length for a specific MAC command - uint8_t getMacPayloadLength(uint8_t cid); - - /*! - \brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance. - \param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO. - \param difsSlots Num of CADs to estimate a clear CH. - \param enableCSMA enable/disable CSMA for LoRaWAN. - */ - void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false); + // retrieve the payload of a certain MAC command, if present in the buffer + int16_t getMacPayload(uint8_t cid, uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t dir); + + // delete a specific MAC command from queue, indicated by the command ID + int16_t deleteMacCommand(uint8_t cid, uint8_t* inOut, uint8_t* lenInOut, uint8_t dir); + + // clear a MAC buffer, possible retaining persistent MAC commands + void clearMacCommands(uint8_t* inOut, uint8_t* lenInOut, uint8_t dir); + + // configure the common physical layer properties (frequency, sync word etc.) + int16_t setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, int8_t pwr, size_t pre = 0); // Performs CSMA as per LoRa Alliance Technical Recommendation 13 (TR-013). - void performCSMA(); + bool csmaChannelClear(uint8_t difs, uint8_t numBackoff); // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. - bool performCAD(); + bool cadChannelClear(); + + // get or create a complete 80-bit channel mask for current configuration + void getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45); + + // setup uplink/downlink channel data rates and frequencies + // for dynamic channels, there is a small set of predefined channels + // in case of JoinRequest, add some optional extra frequencies + void selectChannelPlanDyn(bool joinRequest = false); + + // setup uplink/downlink channel data rates and frequencies + // for fixed bands, we only allow one sub-band at a time to be selected + void selectChannelPlanFix(); + + // get the number of available channels, + // along with a 16-bit mask indicating which channels can be used next for uplink/downlink + uint8_t getAvailableChannels(uint16_t* mask); - // function to encrypt and decrypt payloads + // (re)set/restore which channels can be used next for uplink/downlink + void setAvailableChannels(uint16_t mask); + + // select a set of random TX/RX channels for up- and downlink + int16_t selectChannels(); + + // apply a 96-bit channel mask + bool applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45); + +#if RADIOLIB_DEBUG_PROTOCOL + // print the available channels through debug + void printChannels(); +#endif + + // method to generate message integrity code + uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); + + // method to verify message integrity code + // it assumes that the MIC is the last 4 bytes of the message + bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); + + // find the first usable data rate for the given band + int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); + + // function to encrypt and decrypt payloads (regular uplink/downlink) void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum - static uint16_t checkSum16(uint8_t *key, uint16_t keyLen); + static uint16_t checkSum16(const uint8_t *key, uint16_t keyLen); + + // check the integrity of a buffer using a 16-bit checksum located in the last two bytes of the buffer + static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); // network-to-host conversion method - takes data from network packet and converts it to the host endians template diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index f67b85737b..61de3844c0 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -20,16 +20,19 @@ const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { const LoRaWANBand_t EU868 = { .bandNum = BandEU868, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 8630000, + .freqMax = 8700000, + .payloadLenMax = { 59, 59, 59, 123, 250, 250, 250, 250, 58, 123, 58, 123, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, .dwellTimeUp = 0, .dwellTimeDn = 0, + .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 868.100, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 868.300, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 2, .freq = 868.500, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 0, .freq = 8681000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 8683000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 2, .freq = 8685000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, }, .txJoinReq = { RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -42,21 +45,45 @@ const LoRaWANBand_t EU868 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 869.525, .drMin = 0, .drMax = 0 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, + { 3, 2, 1, 0, 0, 0, 0xFF, 0xFF }, + { 4, 3, 2, 1, 0, 0, 0xFF, 0xFF }, + { 5, 4, 3, 2, 1, 0, 0xFF, 0xFF }, + { 6, 5, 4, 3, 2, 1, 0xFF, 0xFF }, + { 7, 6, 5, 4, 3, 2, 0xFF, 0xFF }, + { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, + { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 8695250, .drMin = 0, .drMax = 7, .dr = 0, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 8651000, .drMin = 2, .drMax = 2, .dr = 2, .available = true }, + { .enabled = true, .idx = 1, .freq = 8655000, .drMin = 2, .drMax = 2, .dr = 2, .available = true } + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 8653000, .drMin = 2, .drMax = 2, .dr = 2, .available = true }, + { .enabled = true, .idx = 1, .freq = 8659000, .drMin = 2, .drMax = 2, .dr = 2, .available = true } + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED @@ -66,12 +93,15 @@ const LoRaWANBand_t EU868 = { const LoRaWANBand_t US915 = { .bandNum = BandUS915, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, - .payloadLenMax = { 19, 61, 133, 250, 250, 0, 0, 0, 41, 117, 230, 230, 230, 230, 0 }, + .freqMin = 9020000, + .freqMax = 9280000, + .payloadLenMax = { 19, 61, 133, 250, 250, 58, 133, 0, 61, 137, 250, 250, 250, 250, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, + .txParamSupported = false, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -86,46 +116,70 @@ const LoRaWANBand_t US915 = { .txSpans = { { .numChannels = 64, - .freqStart = 902.300, - .freqStep = 0.200, + .freqStart = 9023000, + .freqStep = 2000, .drMin = 0, .drMax = 3, - .joinRequestDataRate = 0 + .drJoinRequest = 0 }, { .numChannels = 8, - .freqStart = 903.000, - .freqStep = 1.600, + .freqStart = 9030000, + .freqStep = 16000, .drMin = 4, .drMax = 4, - .joinRequestDataRate = 4 + .drJoinRequest = 4 } }, .rx1Span = { .numChannels = 8, - .freqStart = 923.300, - .freqStep = 0.600, + .freqStart = 9233000, + .freqStep = 6000, .drMin = 8, .drMax = 13, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DrTable = { + { 10, 9, 8, 8, 0xFF, 0xFF, 0xFF, 0xFF }, + { 11, 10, 9, 8, 0xFF, 0xFF, 0xFF, 0xFF }, + { 12, 11, 10, 9, 0xFF, 0xFF, 0xFF, 0xFF }, + { 13, 12, 11, 10, 0xFF, 0xFF, 0xFF, 0xFF }, + { 13, 13, 12, 11, 0xFF, 0xFF, 0xFF, 0xFF }, + { 10, 9, 8, 8, 0xFF, 0xFF, 0xFF, 0xFF }, + { 11, 10, 9, 8, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9167000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, + { .enabled = true, .idx = 1, .freq = 9199000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9183000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, + { .enabled = true, .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } }, - .rx1DataRateBase = 10, - .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; @@ -133,16 +187,19 @@ const LoRaWANBand_t US915 = { const LoRaWANBand_t EU433 = { .bandNum = BandEU433, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 4330000, + .freqMax = 4340000, + .payloadLenMax = { 59, 59, 59, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, .dutyCycle = 36000, .dwellTimeUp = 0, .dwellTimeDn = 0, + .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 433.175, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 433.375, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 2, .freq = 433.575, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 0, .freq = 4331750, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 4333750, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 2, .freq = 4335750, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, }, .txJoinReq = { RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -155,17 +212,41 @@ const LoRaWANBand_t EU433 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 434.665, .drMin = 0, .drMax = 0 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, + { 3, 2, 1, 0, 0, 0, 0xFF, 0xFF }, + { 4, 3, 2, 1, 0, 0, 0xFF, 0xFF }, + { 5, 4, 3, 2, 1, 0, 0xFF, 0xFF }, + { 6, 5, 4, 3, 2, 1, 0xFF, 0xFF }, + { 7, 6, 5, 4, 3, 2, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 4346650, .drMin = 0, .drMax = 7, .dr = 0, .available = true }, + .txWoR = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txAck = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -179,12 +260,15 @@ const LoRaWANBand_t EU433 = { const LoRaWANBand_t AU915 = { .bandNum = BandAU915, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 0, 41, 117, 230, 230, 230, 230, 0 }, + .freqMin = 9150000, + .freqMax = 9280000, + .payloadLenMax = { 59, 59, 59, 123, 250, 250, 250, 58, 61, 137, 250, 250, 250, 250, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, + .txParamSupported = true, // conflict: not implemented according to RP v1.1 .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -199,46 +283,70 @@ const LoRaWANBand_t AU915 = { .txSpans = { { .numChannels = 64, - .freqStart = 915.200, - .freqStep = 0.200, + .freqStart = 9152000, + .freqStep = 2000, .drMin = 0, .drMax = 5, - .joinRequestDataRate = 2 + .drJoinRequest = 2 }, { .numChannels = 8, - .freqStart = 915.900, - .freqStep = 1.600, + .freqStart = 9159000, + .freqStep = 16000, .drMin = 6, .drMax = 6, - .joinRequestDataRate = 6 + .drJoinRequest = 6 } }, .rx1Span = { .numChannels = 8, - .freqStart = 923.300, - .freqStep = 0.600, + .freqStart = 9233000, + .freqStep = 6000, .drMin = 8, .drMax = 13, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DrTable = { + { 8, 8, 8, 8, 8, 8, 0xFF, 0xFF }, + { 9, 8, 8, 8, 8, 8, 0xFF, 0xFF }, + { 10, 9, 8, 8, 8, 8, 0xFF, 0xFF }, + { 11, 10, 9, 8, 8, 8, 0xFF, 0xFF }, + { 12, 11, 10, 9, 8, 8, 0xFF, 0xFF }, + { 13, 12, 11, 10, 9, 8, 0xFF, 0xFF }, + { 13, 13, 12, 11, 10, 9, 0xFF, 0xFF }, + { 9, 8, 8, 8, 8, 8, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9167000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, + { .enabled = true, .idx = 1, .freq = 9199000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9183000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, + { .enabled = true, .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } }, - .rx1DataRateBase = 8, - .rx2 = { .enabled = true, .idx = 0, .freq = 923.300, .drMin = 8, .drMax = 8 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, RADIOLIB_LORAWAN_DATA_RATE_UNUSED } }; @@ -246,12 +354,15 @@ const LoRaWANBand_t AU915 = { const LoRaWANBand_t CN500 = { .bandNum = BandCN500, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 4700000, + .freqMax = 5100000, + .payloadLenMax = { 59, 59, 59, 123, 250, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, .powerNumSteps = 7, .dutyCycle = 0, .dwellTimeUp = 0, .dwellTimeDn = 0, + .txParamSupported = false, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -266,31 +377,55 @@ const LoRaWANBand_t CN500 = { .txSpans = { { .numChannels = 96, - .freqStart = 470.300, - .freqStep = 0.200, + .freqStart = 4703000, + .freqStep = 2000, .drMin = 0, .drMax = 5, - .joinRequestDataRate = 0 + .drJoinRequest = 0 }, RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = { .numChannels = 48, - .freqStart = 500.300, - .freqStep = 0.200, + .freqStart = 5003000, + .freqStep = 2000, .drMin = 0, .drMax = 5, - .joinRequestDataRate = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED + }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 1, 1, 1, 1, 1, 1, 0xFF, 0xFF }, + { 2, 1, 1, 1, 1, 1, 0xFF, 0xFF }, + { 3, 2, 1, 1, 1, 1, 0xFF, 0xFF }, + { 4, 3, 2, 1, 1, 1, 0xFF, 0xFF }, + { 5, 4, 3, 2, 1, 1, 0xFF, 0xFF }, + { 6, 5, 4, 3, 2, 1, 0xFF, 0xFF }, + { 7, 6, 5, 4, 3, 2, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 5053000, .drMin = 0, .drMax = 5, .dr = 0, .available = true }, + .txWoR = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txAck = { + RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE }, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 505.300, .drMin = 0, .drMax = 0 }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -306,15 +441,18 @@ const LoRaWANBand_t CN500 = { const LoRaWANBand_t AS923 = { .bandNum = BandAS923, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 9150000, + .freqMax = 9280000, + .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 9234000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { @@ -328,17 +466,41 @@ const LoRaWANBand_t AS923 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 923.200, .drMin = 2, .drMax = 2 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 1, 2 }, // note: + { 1, 0, 0, 0, 0, 0, 2, 3 }, // when downlinkDwellTime is one + { 2, 1, 0, 0, 0, 0, 3, 4 }, // we should clip any value <2 to 2 + { 3, 2, 1, 0, 0, 0, 4, 5 }, + { 4, 3, 2, 1, 0, 0, 5, 6 }, + { 5, 4, 3, 2, 1, 0, 6, 7 }, + { 6, 5, 4, 3, 2, 1, 7, 7 }, + { 7, 6, 5, 4, 3, 2, 7, 7 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9236000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9238000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -352,15 +514,18 @@ const LoRaWANBand_t AS923 = { const LoRaWANBand_t AS923_2 = { .bandNum = BandAS923_2, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 9150000, + .freqMax = 9280000, + .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 921.400, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 921.600, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 9216000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { @@ -374,17 +539,41 @@ const LoRaWANBand_t AS923_2 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 921.400, .drMin = 2, .drMax = 2 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 1, 2 }, // note: + { 1, 0, 0, 0, 0, 0, 2, 3 }, // when downlinkDwellTime is one + { 2, 1, 0, 0, 0, 0, 3, 4 }, // we should clip any value <2 to 2 + { 3, 2, 1, 0, 0, 0, 4, 5 }, + { 4, 3, 2, 1, 0, 0, 5, 6 }, + { 5, 4, 3, 2, 1, 0, 6, 7 }, + { 6, 5, 4, 3, 2, 1, 7, 7 }, + { 7, 6, 5, 4, 3, 2, 7, 7 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9218000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9220000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -398,15 +587,18 @@ const LoRaWANBand_t AS923_2 = { const LoRaWANBand_t AS923_3 = { .bandNum = BandAS923_3, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 9150000, + .freqMax = 9280000, + .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 916.600, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 916.800, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 9168000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { @@ -420,17 +612,41 @@ const LoRaWANBand_t AS923_3 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 916.600, .drMin = 2, .drMax = 2 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 1, 2 }, // note: + { 1, 0, 0, 0, 0, 0, 2, 3 }, // when downlinkDwellTime is one + { 2, 1, 0, 0, 0, 0, 3, 4 }, // we should clip any value <2 to 2 + { 3, 2, 1, 0, 0, 0, 4, 5 }, + { 4, 3, 2, 1, 0, 0, 5, 6 }, + { 5, 4, 3, 2, 1, 0, 6, 7 }, + { 6, 5, 4, 3, 2, 1, 7, 7 }, + { 7, 6, 5, 4, 3, 2, 7, 7 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9170000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9172000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -444,15 +660,18 @@ const LoRaWANBand_t AS923_3 = { const LoRaWANBand_t AS923_4 = { .bandNum = BandAS923_4, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 9170000, + .freqMax = 9200000, + .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, + .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 917.300, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 917.500, .drMin = 0, .drMax = 5}, + { .enabled = true, .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 9175000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txJoinReq = { @@ -466,17 +685,41 @@ const LoRaWANBand_t AS923_4 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 917.300, .drMin = 2, .drMax = 2 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 1, 2 }, // note: + { 1, 0, 0, 0, 0, 0, 2, 3 }, // when downlinkDwellTime is one + { 2, 1, 0, 0, 0, 0, 3, 4 }, // we should clip any value <2 to 2 + { 3, 2, 1, 0, 0, 0, 4, 5 }, + { 4, 3, 2, 1, 0, 0, 5, 6 }, + { 5, 4, 3, 2, 1, 0, 6, 7 }, + { 6, 5, 4, 3, 2, 1, 7, 7 }, + { 7, 6, 5, 4, 3, 2, 7, 7 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9177000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9179000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + RADIOLIB_LORAWAN_CHANNEL_NONE + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_FSK, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -490,16 +733,19 @@ const LoRaWANBand_t AS923_4 = { const LoRaWANBand_t KR920 = { .bandNum = BandKR920, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 9209000, + .freqMax = 9233000, + .payloadLenMax = { 59, 59, 59, 123, 250, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, .powerNumSteps = 7, .dutyCycle = 0, .dwellTimeUp = 0, .dwellTimeDn = 0, + .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 922.100, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 922.300, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 2, .freq = 922.500, .drMin = 0, .drMax = 5} + { .enabled = true, .idx = 0, .freq = 9221000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 9223000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 2, .freq = 9225000, .drMin = 0, .drMax = 5, .dr = 5, .available = true } }, .txJoinReq = { RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -512,15 +758,39 @@ const LoRaWANBand_t KR920 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 921.900, .drMin = 0, .drMax = 0 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, + { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, + { 3, 2, 1, 0, 0, 0, 0xFF, 0xFF }, + { 4, 3, 2, 1, 0, 0, 0xFF, 0xFF }, + { 5, 4, 3, 2, 1, 0, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 9219000, .drMin = 0, .drMax = 5, .dr = 0, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 9227000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 9229000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, @@ -536,16 +806,19 @@ const LoRaWANBand_t KR920 = { const LoRaWANBand_t IN865 = { .bandNum = BandIN865, .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, - .payloadLenMax = { 59, 59, 59, 123, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0 }, + .freqMin = 8650000, + .freqMax = 8670000, + .payloadLenMax = { 59, 59, 59, 123, 250, 250, 0, 250, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, .dwellTimeUp = 0, .dwellTimeDn = 0, + .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 865.0625, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 1, .freq = 865.4025, .drMin = 0, .drMax = 5}, - { .enabled = true, .idx = 2, .freq = 865.9850, .drMin = 0, .drMax = 5} + { .enabled = true, .idx = 0, .freq = 8650625, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 1, .freq = 8654025, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, + { .enabled = true, .idx = 2, .freq = 8659850, .drMin = 0, .drMax = 5, .dr = 5, .available = true } }, .txJoinReq = { RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -558,17 +831,41 @@ const LoRaWANBand_t IN865 = { RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, - .rx1DataRateBase = 0, - .rx2 = { .enabled = true, .idx = 0, .freq = 866.550, .drMin = 2, .drMax = 2 }, + .rx1DrTable = { + { 0, 0, 0, 0, 0, 0, 1, 2 }, + { 1, 0, 0, 0, 0, 0, 2, 3 }, + { 2, 1, 0, 0, 0, 0, 3, 4 }, + { 3, 2, 1, 0, 0, 0, 4, 5 }, + { 4, 3, 2, 1, 0, 0, 5, 5 }, + { 5, 4, 3, 2, 1, 0, 5, 7 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 7, 6, 5, 4, 3, 2, 7, 7 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + .rx2 = { .enabled = true, .idx = 0, .freq = 8665500, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .txWoR = { + { .enabled = true, .idx = 0, .freq = 8660000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 8667000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + }, + .txAck = { + { .enabled = true, .idx = 0, .freq = 8662000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 8669000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ | RADIOLIB_LORAWAN_DATA_RATE_CR_4_5, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, + RADIOLIB_LORAWAN_DATA_RATE_UNUSED, + RADIOLIB_LORAWAN_DATA_RATE_FSK, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, RADIOLIB_LORAWAN_DATA_RATE_UNUSED, From 78a6897e1b84709911ff6746fba86c78e942bdb1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 20:24:00 +0100 Subject: [PATCH 1243/1848] [LoRaWAN] Silence class-memaccess warning --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index d217347d85..0bbc30959b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2328,7 +2328,7 @@ void LoRaWANNode::postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen) { int16_t LoRaWANNode::getMacCommand(uint8_t cid, LoRaWANMacCommand_t* cmd) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { - memcpy(cmd, &MacTable[i], sizeof(LoRaWANMacCommand_t)); + memcpy((void*)cmd, (void*)&MacTable[i], sizeof(LoRaWANMacCommand_t)); return(RADIOLIB_ERR_NONE); } } From 8aedf53272086887f030c9d4bf4352d2ca5b717b Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 10 Sep 2024 20:27:49 +0100 Subject: [PATCH 1244/1848] [LoRaWAN] Fix narrow type comparison --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0bbc30959b..e732e19167 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2800,7 +2800,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, // in the LoRa Alliance Technical Recommendation #13. bool LoRaWANNode::csmaChannelClear(uint8_t difs, uint8_t numBackoff) { // DIFS phase: perform #DIFS CAD operations - uint8_t numCads = 0; + uint16_t numCads = 0; for (; numCads < difs; numCads++) { if (!this->cadChannelClear()) { return(false); From 400382b1e74642d888bae7214844e023a4dbf827 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 11 Sep 2024 21:05:01 +0200 Subject: [PATCH 1245/1848] [APRS] Fix string conversion in examples --- .../AFSK/AFSK_External_Radio/AFSK_External_Radio.ino | 11 ++++++++--- examples/APRS/APRS_Position/APRS_Position.ino | 11 ++++++++--- .../APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino | 10 ++++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino index 6f6c6cc5e8..9419157ba5 100644 --- a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino +++ b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino @@ -66,15 +66,20 @@ void loop() { Serial.print(F("[APRS] Sending position ... ")); // send a location without message or timestamp - int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E"); + char destination[] = "N0CALL"; + char latitude[] = "4911.67N"; + char longitude[] = "01635.96E"; + int state = aprs.sendPosition(destination, 0, latitude, longitude); delay(500); // send a location with message and without timestamp - state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!"); + char message[] = "I'm here!"; + state |= aprs.sendPosition(destination, 0, latitude, longitude, message); delay(500); // send a location with message and timestamp - state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z"); + char timestamp[] = "093045z"; + state |= aprs.sendPosition(destination, 0, latitude, longitude, message, timestamp); delay(500); if(state == RADIOLIB_ERR_NONE) { diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index 5b237af7a7..4a43d37d54 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -108,15 +108,20 @@ void loop() { Serial.print(F("[APRS] Sending position ... ")); // send a location without message or timestamp - int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E"); + char destination[] = "N0CALL"; + char latitude[] = "4911.67N"; + char longitude[] = "01635.96E"; + int state = aprs.sendPosition(destination, 0, latitude, longitude); delay(500); // send a location with message and without timestamp - state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!"); + char message[] = "I'm here!"; + state |= aprs.sendPosition(destination, 0, latitude, longitude, message); delay(500); // send a location with message and timestamp - state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z"); + char timestamp[] = "093045z"; + state |= aprs.sendPosition(destination, 0, latitude, longitude, message, timestamp); delay(500); if(state == RADIOLIB_ERR_NONE) { diff --git a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino index 70681a95fd..1a77aadbff 100644 --- a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino +++ b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino @@ -62,7 +62,8 @@ void setup() { // symbol: '>' (car) // callsign "N7LEM" // SSID 1 - state = aprs.begin('>', "N7LEM", 1); + char source[] = "N7LEM"; + state = aprs.begin('>', source, 1); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); } else { @@ -77,7 +78,12 @@ void loop() { // send a location with message and timestamp // SSID is set to 1, as APRS over LoRa uses WIDE1-1 path by default - int state = aprs.sendPosition("GPS", 1, "4911.67N", "01635.96E", "I'm here!", "093045z"); + char destination[] = "GPS"; + char latitude[] = "4911.67N"; + char longitude[] = "01635.96E"; + char message[] = "I'm here!"; + char timestamp[] = "093045z"; + int state = aprs.sendPosition(destination, 1, latitude, longitude, message, timestamp); delay(500); // you can also send Mic-E encoded messages From d9eb90e59b76920046027aaf1ebdc2647795b2c3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 11 Sep 2024 21:43:24 +0200 Subject: [PATCH 1246/1848] [APRS] Fix callsign in non-LoRa mode and buffer size (#1215) --- src/protocols/APRS/APRS.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index 5c54b217aa..b1f9b5a8b1 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -24,6 +24,11 @@ int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { table = '/'; } + // callsign is only processed for LoRa APRS + if(!callsign) { + return(RADIOLIB_ERR_NONE); + } + if(strlen(callsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) { return(RADIOLIB_ERR_INVALID_CALLSIGN); } @@ -43,7 +48,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat len += strlen(time); } #if !RADIOLIB_STATIC_ONLY - char* info = new char[len + 1]; + char* info = new char[len + 2]; #else char info[RADIOLIB_STATIC_ARRAY_SIZE]; #endif @@ -71,6 +76,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat // send the frame info[len] = '\0'; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("APRS Info: %s, length = %d", (void*)info, info, (int)len); int16_t state = sendFrame(destCallsign, destSSID, info); #if !RADIOLIB_STATIC_ONLY delete[] info; From 2d5de4bc0f760b62dac7c1648409d399af7ca73b Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 12 Sep 2024 07:01:56 +0200 Subject: [PATCH 1247/1848] [APRS] Fix debug print --- src/protocols/APRS/APRS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index b1f9b5a8b1..a5866ac617 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -76,7 +76,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat // send the frame info[len] = '\0'; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("APRS Info: %s, length = %d", (void*)info, info, (int)len); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("APRS Info: %s, length = %d", info, (int)len); int16_t state = sendFrame(destCallsign, destSSID, info); #if !RADIOLIB_STATIC_ONLY delete[] info; From d371b50c5af1ff945d4033eec8778a437f4a41c2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 13 Sep 2024 17:41:28 +0200 Subject: [PATCH 1248/1848] Added type casts for Arduino megaAVR --- src/BuildOpt.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4b75f7b04c..05d0036562 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -252,6 +252,9 @@ #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(PORTDUINO) // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every #define RADIOLIB_PLATFORM "Arduino megaAVR" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) #elif defined(ARDUINO_ARCH_APOLLO3) // Sparkfun Apollo3 boards From 740ee7e23551ff62b2b3567100a8e3d027be07cb Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 16 Sep 2024 00:39:12 +0200 Subject: [PATCH 1249/1848] [LoRaWAN] Verification cleanup --- src/protocols/LoRaWAN/LoRaWAN.cpp | 113 +++++++++++++++++++----------- src/protocols/LoRaWAN/LoRaWAN.h | 1 - 2 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e732e19167..03dfc573b6 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1009,6 +1009,9 @@ void LoRaWANNode::processCFList(uint8_t* cfList) { num++; } + cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; + (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); + uint8_t freqZero[3] = { 0 }; // datarate range for all new channels is equal to the default channels @@ -1018,8 +1021,6 @@ void LoRaWANNode::processCFList(uint8_t* cfList) { if(memcmp(&cfList[i*3], freqZero, 3) == 0) { break; } - cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; - (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = num; memcpy(&cOcts[1], &cfList[i*3], 3); (void)execMacCommand(cid, cOcts, cLen); @@ -1099,22 +1100,20 @@ void LoRaWANNode::adrBackoff() { // check if we need to do ADR stuff uint32_t adrLimit = 0x01 << this->adrLimitExp; uint32_t adrDelay = 0x01 << this->adrDelayExp; - if((this->fCntUp - this->adrFCnt) >= adrLimit) { - this->adrAckReq = true; - } else { - this->adrAckReq = false; + + // don't need to do any backoff for first Limit+Delay uplinks + if((this->fCntUp - this->adrFCnt) < (adrLimit + adrDelay)) { + return; } - if ((this->fCntUp - this->adrFCnt) < (adrLimit + adrDelay)) { + // only perform backoff every Delay uplinks + if((this->fCntUp - this->adrFCnt - adrLimit) % adrDelay != 0) { return; } // if we hit the Limit + Delay, try one of three, in order: // set TxPower to max, set DR to min, enable all default channels - // as we try to do something to improve the range, increase the ADR frame counter by 'ADR delay' - this->adrFCnt += adrDelay; - // if the TxPower field has some offset, remove it and switch to maximum power if(this->txPowerSteps > 0) { // set the maximum power supported by both the module and the band @@ -1136,7 +1135,11 @@ void LoRaWANNode::adrBackoff() { this->selectChannelPlanFix(); // go back to default selected subband } this->nbTrans = 1; - return; // nothing else to do + + // as there is nothing more to do, set ADR counter to maximum value to indicate that we've tried everything + this->adrFCnt = RADIOLIB_LORAWAN_FCNT_NONE; + + return; } void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed) { @@ -1153,7 +1156,11 @@ void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_ out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] = 0x00; if(this->adrEnabled) { out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; - if(adrAckReq) { + + // AdrAckReq is set if no downlink has been received for >=Limit uplinks + // but it is unset once backoff has been completed (which is internally denoted by adrFCnt == FCNT_NONE) + uint32_t adrLimit = 0x01 << this->adrLimitExp; + if(this->adrFCnt != RADIOLIB_LORAWAN_FCNT_NONE && (this->fCntUp - this->adrFCnt) >= adrLimit) { out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; } } @@ -1378,7 +1385,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne if(this->TS011) { maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater } - RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen); + RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13); // mandatory FHDR is 12/13 bytes bool downlinkComplete = true; // wait for the DIO to fire indicating a downlink is received @@ -1401,11 +1408,11 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne this->phyLayer->clearPacketReceivedAction(); this->phyLayer->standby(); - // if all windows passed without receiving anything, return 0 + // if all windows passed without receiving anything, set return value to 0 if(!downlinkComplete) { state = 0; - // if we received something during a window, return the window number + // if we received something during a window, set return value to the window number } else { state = window; } @@ -1413,7 +1420,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne // Any frame received by an end-device containing a MACPayload greater than // the specified maximum length M over the data rate used to receive the frame // SHALL be silently discarded. - if(this->phyLayer->getPacketLength() > maxPayLen) { + if(this->phyLayer->getPacketLength() > maxPayLen + 13) { // mandatory FHDR is 12/13 bytes return(0); // act as if no downlink was received } @@ -1529,6 +1536,15 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e } } + + // MAC commands SHALL NOT be present in the payload field and the frame options field simultaneously. + // Should this occur, the end-device SHALL silently discard the frame. + if(fOptsPbLen > 0 && payLen > 0 && fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } // get the frame counter uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); @@ -1917,9 +1933,19 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin this->txPowerSteps = macTxSteps; if(lenIn > 1) { uint8_t macNbTrans = optIn[13] & 0x0F; - if(macNbTrans) { // if there is a value for NbTrans, set this value + + // if there is a value for NbTrans > 0, apply it + if(macNbTrans) { this->nbTrans = macNbTrans; + } else { + // for LoRaWAN v1.0.4, if NbTrans == 0, the end-device SHALL use the default value (being 1) + if(this->rev == 0) { + this->nbTrans = 1; + } + // for LoRaWAN v1.1, if NbTrans == 0, the end-device SHALL keep the current NbTrans value unchanged + // so, don't do anything } + } // restore original active channels @@ -2022,14 +2048,22 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin uint8_t macDrMax = (optIn[4] & 0xF0) >> 4; uint8_t macDrMin = optIn[4] & 0x0F; - uint8_t newChAck = 0; + uint8_t drAck = 0; uint8_t freqAck = 0; - // on LoRaWAN v1.1, the default channels may be modified - not on v1.0.x. - // in that case, only allow non-default channels to be modified - // there are at most three default channels, so either check for >2 or else if index is used - if(this->rev == 1 || macChIndex > 2 || this->band->txFreqs[macChIndex].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - newChAck = 1; + // the default channels shall not be modified, so check if this is a default channel + // if the channel index is set, this channel is defined, so return a NACK + if(macChIndex < 3 && this->band->txFreqs[macChIndex].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + optOut[0] = 0; + return(true); + } + + // check if the outermost datarates are defined and if the device supports them + DataRate_t dr; + if(this->band->dataRates[macDrMin] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED && this->findDataRate(macDrMin, &dr) == RADIOLIB_ERR_NONE) { + if(this->band->dataRates[macDrMax] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED && this->findDataRate(macDrMax, &dr) == RADIOLIB_ERR_NONE) { + drAck = 1; + } } // check if the frequency is allowed and possible @@ -2043,7 +2077,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin } // set ACK bits - optOut[0] = (newChAck << 1) | (freqAck << 0); + optOut[0] = (drAck << 1) | (freqAck << 0); // if not fully acknowledged, return now without applying the requested configuration if(optOut[0] != 0x03) { @@ -3169,36 +3203,37 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { RADIOLIB_LORAWAN_UPLINK, this->txPowerMax - 2*this->txPowerSteps); - uint8_t minPayLen = 0; - uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; + // mandatory FHDR is 12/13, so add & subtract 13 from calculations where necessary + uint8_t minLen = 0; + uint8_t maxLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr] + 13; if(this->TS011) { - maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater + maxLen = RADIOLIB_MIN(maxLen, 230 + 13); // payload length is limited to 230 if under repeater } // if not limited by dwell-time, just return maximum if(!this->dwellTimeEnabledUp) { // subtract FHDR (13 bytes) as well as any FOpts - return(maxPayLen - 13 - this->fOptsUpLen); + return(maxLen - 13 - this->fOptsUpLen); } // fast exit in case upper limit is already good - if(this->phyLayer->getTimeOnAir(maxPayLen) / 1000 <= this->dwellTimeUp) { + if(this->phyLayer->getTimeOnAir(maxLen) / 1000 <= this->dwellTimeUp) { // subtract FHDR (13 bytes) as well as any FOpts - return(maxPayLen - 13 - this->fOptsUpLen); + return(maxLen - 13 - this->fOptsUpLen); } - // do some binary search to find maximum allowed payload length - uint8_t payLen = (minPayLen + maxPayLen) / 2; - while(payLen != minPayLen && payLen != maxPayLen) { - if(this->phyLayer->getTimeOnAir(payLen) / 1000 > this->dwellTimeUp) { - maxPayLen = payLen; + // do some binary search to find maximum allowed length + uint8_t curLen = (minLen + maxLen) / 2; + while(curLen != minLen && curLen != maxLen) { + if(this->phyLayer->getTimeOnAir(curLen) / 1000 > this->dwellTimeUp) { + maxLen = curLen; } else { - minPayLen = payLen; + minLen = curLen; } - payLen = (minPayLen + maxPayLen) / 2; + curLen = (minLen + maxLen) / 2; } // subtract FHDR (13 bytes) as well as any FOpts - return(payLen - 13 - this->fOptsUpLen); + return(curLen - 13 - this->fOptsUpLen); } int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { @@ -3234,7 +3269,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { break; case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): // not yet supported by DataRate_t - break; + return(RADIOLIB_ERR_UNSUPPORTED); default: return(RADIOLIB_ERR_UNSUPPORTED); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 9b3dc6edb3..347680c992 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -918,7 +918,6 @@ class LoRaWANNode { // ADR is enabled by default bool adrEnabled = true; - bool adrAckReq = false; // duty cycle is set upon initialization and activated in regions that impose this bool dutyCycleEnabled = false; From 7f1488eabcd5bc967af4b336b982cd58596e2591 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 16 Sep 2024 00:39:40 +0200 Subject: [PATCH 1250/1848] [LoRaWAN] Exit beta --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cc9f908895..a5eeaf49cd 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules: SX127x, RFM9x, SX126x, LR11x0 and SX128x - * NOTE: LoRaWAN support is currently in beta, feedback via [Issues](https://github.com/jgromes/RadioLib/issues) and [Discussions](https://github.com/jgromes/RadioLib/discussions) is appreciated! ### Supported Arduino platforms: * __Arduino__ From b76327c10f1b9b072429e4944912ff0535003478 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 16 Sep 2024 01:23:10 +0200 Subject: [PATCH 1251/1848] [LoRaWAN] Fix RekeyConf, change session buffer layout --- src/protocols/LoRaWAN/LoRaWAN.cpp | 23 ++++++++++++++++---- src/protocols/LoRaWAN/LoRaWAN.h | 36 +++++++++++++++---------------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 03dfc573b6..220535993b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -216,8 +216,6 @@ int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, u } void LoRaWANNode::clearNonces() { - // not a real version number, but helps debugging - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("This line was updated on 2024-09-08 at 00:01+2"); // clear & set all the device credentials memset(this->bufferNonces, 0, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); this->keyCheckSum = 0; @@ -2207,10 +2205,27 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // get the server version uint8_t srvVersion = optIn[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); + + // If the server’s version is invalid the device SHALL discard the RekeyConf command and retransmit the RekeyInd in the next uplink frame if((srvVersion > 0) && (srvVersion <= this->rev)) { - // valid server version, stop sending the ReKey MAC command - LoRaWANNode::deleteMacCommand(RADIOLIB_LORAWAN_MAC_REKEY, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + // valid server version, accept + this->rev = srvVersion; + + } else { + // if not a valid server version, retransmit RekeyInd + uint8_t cid = RADIOLIB_LORAWAN_MAC_REKEY; + uint8_t cLen = 0; + this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_UPLINK); + uint8_t cOcts[1] = { this->rev }; + (void)LoRaWANNode::pushMacCommand(cid, cOcts, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + + // discard RekeyConf, therefore return false so it doesn't send a reply + return(false); } + + optOut[0] = this->rev; + + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); return(false); } break; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 347680c992..4b1005114c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -277,15 +277,19 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 4 bytes - RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte - RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + 2, // 4 bytes + RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte + RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 14 bytes + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_LINK_ADR + 14, // 1 byte RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + 1, // 4 bytes RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + 4, // 1 byte RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + 1, // 1 byte @@ -297,15 +301,11 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*5, // 16*4 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*4, // 15 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE + 1, // 1 byte - RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN + RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN, // 4 bytes - RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes - RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 14 bytes - RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS = RADIOLIB_LORAWAN_SESSION_LINK_ADR + 14, // 2 bytes - RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS + 2, // 4 bytes - RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size + RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*4, // 2 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE = RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS + sizeof(uint16_t), // 15 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE + RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN, // 1 byte + RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size }; /*! From 97579292de5cd81aa01c44a6c95c1ff0f2239b57 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 16 Sep 2024 01:28:25 +0200 Subject: [PATCH 1252/1848] [LoRaWAN] Remove shadowed variable --- src/protocols/LoRaWAN/LoRaWAN.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 220535993b..783d2f30a9 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2213,7 +2213,6 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin } else { // if not a valid server version, retransmit RekeyInd - uint8_t cid = RADIOLIB_LORAWAN_MAC_REKEY; uint8_t cLen = 0; this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_UPLINK); uint8_t cOcts[1] = { this->rev }; From e9ed961c97d5e22004b2ca592c8a39bf65f17882 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 16 Sep 2024 08:36:14 +0200 Subject: [PATCH 1253/1848] [LoRaWAN] Fix ADR backoff --- src/protocols/LoRaWAN/LoRaWAN.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 783d2f30a9..7112bcac67 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1099,7 +1099,12 @@ void LoRaWANNode::adrBackoff() { uint32_t adrLimit = 0x01 << this->adrLimitExp; uint32_t adrDelay = 0x01 << this->adrDelayExp; - // don't need to do any backoff for first Limit+Delay uplinks + // check if we already tried everything (adrFCnt == FCNT_NONE) + if(this->adrFCnt == RADIOLIB_LORAWAN_FCNT_NONE) { + return; + } + + // no need to do any backoff for first Limit+Delay uplinks if((this->fCntUp - this->adrFCnt) < (adrLimit + adrDelay)) { return; } @@ -1121,7 +1126,7 @@ void LoRaWANNode::adrBackoff() { } // try to decrease the datarate - if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > this->channels[RADIOLIB_LORAWAN_UPLINK].drMin) { + if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > 0) { if(this->setDatarate(this->channels[RADIOLIB_LORAWAN_UPLINK].dr - 1) == RADIOLIB_ERR_NONE) { return; } From 9b4e4a86d2b4ec156a08c3a5968eddb10a156c69 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Sep 2024 18:46:45 +0200 Subject: [PATCH 1254/1848] [LoRaWAN] Fix EU868 data rate for WoR and ACK --- src/protocols/LoRaWAN/LoRaWANBands.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 61de3844c0..3b33bec51b 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -64,12 +64,12 @@ const LoRaWANBand_t EU868 = { }, .rx2 = { .enabled = true, .idx = 0, .freq = 8695250, .drMin = 0, .drMax = 7, .dr = 0, .available = true }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 8651000, .drMin = 2, .drMax = 2, .dr = 2, .available = true }, - { .enabled = true, .idx = 1, .freq = 8655000, .drMin = 2, .drMax = 2, .dr = 2, .available = true } + { .enabled = true, .idx = 0, .freq = 8651000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 8655000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } }, .txAck = { - { .enabled = true, .idx = 0, .freq = 8653000, .drMin = 2, .drMax = 2, .dr = 2, .available = true }, - { .enabled = true, .idx = 1, .freq = 8659000, .drMin = 2, .drMax = 2, .dr = 2, .available = true } + { .enabled = true, .idx = 0, .freq = 8653000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 8659000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } }, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, From 6aef0628b75102e610f8e9b10369725c7e0dcea8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Sep 2024 18:49:18 +0200 Subject: [PATCH 1255/1848] Bump version to 7.0.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index e7d7792a1c..5bbf3101d9 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "6.6.0" +version: "7.0.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index cbaf23b47e..d99e412cc3 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "6.6.0", + "version": "7.0.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 3d5f6ca65e..02c69b4f01 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=6.6.0 +version=7.0.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 05d0036562..23b953a0f3 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -586,8 +586,8 @@ #define RADIOLIB_ABS(x) ((x)>0?(x):-(x)) // version definitions -#define RADIOLIB_VERSION_MAJOR 6 -#define RADIOLIB_VERSION_MINOR 6 +#define RADIOLIB_VERSION_MAJOR 7 +#define RADIOLIB_VERSION_MINOR 0 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From 79b1b8c8873cc5c4393d20012c8ec87981d36394 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Sep 2024 18:56:22 +0200 Subject: [PATCH 1256/1848] [LoRaWAN] Fixed size_t comparison (CI_BUILD_ALL) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7112bcac67..b2ecd50c2c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1423,7 +1423,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne // Any frame received by an end-device containing a MACPayload greater than // the specified maximum length M over the data rate used to receive the frame // SHALL be silently discarded. - if(this->phyLayer->getPacketLength() > maxPayLen + 13) { // mandatory FHDR is 12/13 bytes + if(this->phyLayer->getPacketLength() > (size_t)(maxPayLen + 13)) { // mandatory FHDR is 12/13 bytes return(0); // act as if no downlink was received } From 8068bcc3567350a736af32a5efddd86c69d5e99f Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 19 Sep 2024 13:02:07 -0700 Subject: [PATCH 1257/1848] [SX128x] getRssi(false) without packet (#1222) * Update SX128x.h * Update SX128x.cpp --- src/modules/SX128x/SX128x.cpp | 11 +++++++++++ src/modules/SX128x/SX128x.h | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 8fc395bf56..d8488f1ce0 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1253,6 +1253,17 @@ float SX128x::getRSSI() { } } +float SX128x::getRSSI(bool packet) { + if (!packet) { + // get instantaneous RSSI value + uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU + this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3); + return ((float)data[0] / (-2.0)); + } else { + return this->getRSSI(); + } +} + float SX128x::getSNR() { // check active modem uint8_t modem = getPacketType(); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index eab6eafc61..cea6b7aded 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -761,6 +761,13 @@ class SX128x: public PhysicalLayer { */ float getRSSI() override; + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator). + \param packet Whether to read last packet RSSI, or the current value. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet); + /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa or ranging modem. \returns SNR of the last received packet in dB. From f045ed10b5409992233105fa935ec71de609e028 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 17:22:36 +0100 Subject: [PATCH 1258/1848] [FEC] Fix missing parentheses in macro --- src/protocols/AX25/AX25.cpp | 20 ++++++++++---------- src/utils/FEC.h | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index c5913e9478..82a64cebc6 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -402,7 +402,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { uint16_t stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8); if((frameBuff[i] >> shift) & 0x01) { // copy 1 and increment counter - SET_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos); + SET_BIT_IN_ARRAY_MSB(stuffedFrameBuff, stuffedFrameBuffPos); stuffedFrameBuffLenBits++; count++; @@ -412,14 +412,14 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8); // insert 0 and reset counter - CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos); + CLEAR_BIT_IN_ARRAY_MSB(stuffedFrameBuff, stuffedFrameBuffPos); stuffedFrameBuffLenBits++; count = 0; } } else { // copy 0 and reset counter - CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos); + CLEAR_BIT_IN_ARRAY_MSB(stuffedFrameBuff, stuffedFrameBuffPos); stuffedFrameBuffLenBits++; count = 0; } @@ -454,20 +454,20 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { for(size_t i = preambleLen + 1; i < stuffedFrameBuffLen*8; i++) { size_t currBitPos = i + 7 - 2*(i%8); size_t prevBitPos = (i - 1) + 7 - 2*((i - 1)%8); - if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos)) { + if(TEST_BIT_IN_ARRAY_MSB(stuffedFrameBuff, currBitPos)) { // bit is 1, no change, copy previous bit - if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, prevBitPos)) { - SET_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + if(TEST_BIT_IN_ARRAY_MSB(stuffedFrameBuff, prevBitPos)) { + SET_BIT_IN_ARRAY_MSB(stuffedFrameBuff, currBitPos); } else { - CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + CLEAR_BIT_IN_ARRAY_MSB(stuffedFrameBuff, currBitPos); } } else { // bit is 0, transition, copy inversion of the previous bit - if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, prevBitPos)) { - CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + if(TEST_BIT_IN_ARRAY_MSB(stuffedFrameBuff, prevBitPos)) { + CLEAR_BIT_IN_ARRAY_MSB(stuffedFrameBuff, currBitPos); } else { - SET_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos); + SET_BIT_IN_ARRAY_MSB(stuffedFrameBuff, currBitPos); } } } diff --git a/src/utils/FEC.h b/src/utils/FEC.h index a33ff61f8f..cf201b1148 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -72,10 +72,10 @@ class RadioLibBCH { extern RadioLibBCH RadioLibBCHInstance; // macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html -#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) -#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) ) -#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) ) -#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 ) +#define SET_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] |= (1 << ((k)%8)) ) +#define CLEAR_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] &= ~(1 << ((k)%8)) ) +#define TEST_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] & (1 << ((k)%8)) ) +#define GET_BIT_IN_ARRAY_MSB(A, k) ( (A[((k)/8)] & (1 << ((k)%8))) ? 1 : 0 ) #endif From 0e7c723fb17ce97c7ad3578cb740bb4e24724439 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 17:24:59 +0100 Subject: [PATCH 1259/1848] [SX126x] Move common setup code to common method --- src/modules/SX126x/SX126x.cpp | 98 +++-------------------------------- src/modules/SX126x/SX126x.h | 1 + 2 files changed, 7 insertions(+), 92 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f94481a001..72e3b36b41 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -20,35 +20,13 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, } int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->spiConfig.statusPos = 1; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - - // try to find the SX126x chip - if(!SX126x::findChip(this->chipType)) { - RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); - this->mod->term(); - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); - // BW in kHz and SF are required in order to calculate LDRO for setModulationParams // set the defaults, this will get overwritten later anyway this->bandwidthKhz = 500.0; this->spreadingFactor = 9; // initialize configuration variables (will be overwritten during public settings configuration) - this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; // initialized to 500 kHz, since lower valeus will interfere with LLCC68 + this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; // initialized to 500 kHz, since lower values will interfere with LLCC68 this->codingRate = RADIOLIB_SX126X_LORA_CR_4_7; this->ldrOptimize = 0x00; this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; @@ -57,22 +35,8 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo this->headerType = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT; this->implicitLen = 0xFF; - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - RADIOLIB_ASSERT(state); - - // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0) { - state = setTCXO(tcxoVoltage); - RADIOLIB_ASSERT(state); - } - - // configure settings not accessible by API - state = config(RADIOLIB_SX126X_PACKET_TYPE_LORA); + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -85,13 +49,6 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - if (useRegulatorLDO) { - state = setRegulatorLDO(); - } else { - state = setRegulatorDCDC(); - } - RADIOLIB_ASSERT(state); - // set publicly accessible settings that are not a part of begin method state = setCurrentLimit(60.0); RADIOLIB_ASSERT(state); @@ -109,54 +66,18 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo } int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->spiConfig.statusPos = 1; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - - // try to find the SX126x chip - if(!SX126x::findChip(this->chipType)) { - RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); - this->mod->term(); - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); - // initialize configuration variables (will be overwritten during public settings configuration) this->bitRate = 21333; // 48.0 kbps this->frequencyDev = 52428; // 50.0 kHz this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; this->rxBandwidthKhz = 156.2; this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; - this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCITT CRC configuration this->preambleLengthFSK = preambleLength; this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - RADIOLIB_ASSERT(state); - - // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0) { - state = setTCXO(tcxoVoltage); - RADIOLIB_ASSERT(state); - } - - // configure settings not accessible by API - state = config(RADIOLIB_SX126X_PACKET_TYPE_GFSK); + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -175,13 +96,6 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - if(useRegulatorLDO) { - state = setRegulatorLDO(); - } else { - state = setRegulatorDCDC(); - } - RADIOLIB_ASSERT(state); - // set publicly accessible settings that are not a part of begin method uint8_t sync[] = {0x12, 0xAD}; state = setSyncWord(sync, 2); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 521921da04..0c7d17b7a1 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1218,6 +1218,7 @@ class SX126x: public PhysicalLayer { size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + int16_t modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem); int16_t config(uint8_t modem); bool findChip(const char* verStr); int16_t startReceiveCommon(uint32_t timeout = RADIOLIB_SX126X_RX_TIMEOUT_INF, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK); From 102d06a9f8b2625002c94caae1f46e8a57487f74 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 17:28:51 +0100 Subject: [PATCH 1260/1848] [SX126x] Added missing implementation --- src/modules/SX126x/SX126x.cpp | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 72e3b36b41..924a5799e5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -2017,6 +2017,55 @@ Module* SX126x::getMod() { return(this->mod); } +int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + + // try to find the SX126x chip + if(!SX126x::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(modem); + RADIOLIB_ASSERT(state); + + if (useRegulatorLDO) { + state = setRegulatorLDO(); + } else { + state = setRegulatorDCDC(); + } + return(state); +} + int16_t SX126x::config(uint8_t modem) { // reset buffer base address int16_t state = setBufferBaseAddress(); From adb5018b729dc4497b013b4342affa124c8eeb1f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 18:17:29 +0100 Subject: [PATCH 1261/1848] [LR11x0] Fix shadowed variable --- src/modules/LR11x0/LR11x0.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 80a3c0081c..ce90017070 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -288,7 +288,7 @@ int16_t LR11x0::receiveDirect() { } int16_t LR11x0::scanChannel() { - ChannelScanConfig_t config = { + ChannelScanConfig_t cfg = { .cad = { .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, @@ -299,7 +299,7 @@ int16_t LR11x0::scanChannel() { .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, }, }; - return(this->scanChannel(config)); + return(this->scanChannel(cfg)); } int16_t LR11x0::scanChannel(const ChannelScanConfig_t &config) { @@ -561,7 +561,7 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { } int16_t LR11x0::startChannelScan() { - ChannelScanConfig_t config = { + ChannelScanConfig_t cfg = { .cad = { .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT, @@ -572,7 +572,7 @@ int16_t LR11x0::startChannelScan() { .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, }, }; - return(this->startChannelScan(config)); + return(this->startChannelScan(cfg)); } int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &config) { From b8cd1353b13569c328a8b01ed71b13f08f76d63b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 18:17:45 +0100 Subject: [PATCH 1262/1848] [SX126x] Fix shadowed variable --- src/modules/SX126x/SX126x.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 924a5799e5..447ae16a54 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -349,7 +349,7 @@ int16_t SX126x::packetMode() { } int16_t SX126x::scanChannel() { - ChannelScanConfig_t config = { + ChannelScanConfig_t cfg = { .cad = { .symNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, .detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, @@ -360,7 +360,7 @@ int16_t SX126x::scanChannel() { .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, }, }; - return(this->scanChannel(config)); + return(this->scanChannel(cfg)); } int16_t SX126x::scanChannel(const ChannelScanConfig_t &config) { @@ -667,7 +667,7 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { } int16_t SX126x::startChannelScan() { - ChannelScanConfig_t config = { + ChannelScanConfig_t cfg = { .cad = { .symNum = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, .detPeak = RADIOLIB_SX126X_CAD_PARAM_DEFAULT, @@ -678,7 +678,7 @@ int16_t SX126x::startChannelScan() { .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, }, }; - return(this->startChannelScan(config)); + return(this->startChannelScan(cfg)); } int16_t SX126x::startChannelScan(const ChannelScanConfig_t &config) { From 0f6e7653c713ad42c1452ceb183994f1b30c7e38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 18:17:58 +0100 Subject: [PATCH 1263/1848] [SX128x] Fix shadowed variable --- src/modules/SX128x/SX128x.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index d8488f1ce0..a51ad836f3 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -421,7 +421,7 @@ int16_t SX128x::receiveDirect() { } int16_t SX128x::scanChannel() { - ChannelScanConfig_t config = { + ChannelScanConfig_t cfg = { .cad = { .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT, .detPeak = 0, @@ -432,7 +432,7 @@ int16_t SX128x::scanChannel() { .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, }, }; - return(this->scanChannel(config)); + return(this->scanChannel(cfg)); } int16_t SX128x::scanChannel(const ChannelScanConfig_t &config) { @@ -677,7 +677,7 @@ int16_t SX128x::clearIrqFlags(uint32_t irq) { } int16_t SX128x::startChannelScan() { - ChannelScanConfig_t config = { + ChannelScanConfig_t cfg = { .cad = { .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT, .detPeak = 0, @@ -688,7 +688,7 @@ int16_t SX128x::startChannelScan() { .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, }, }; - return(this->startChannelScan(config)); + return(this->startChannelScan(cfg)); } int16_t SX128x::startChannelScan(const ChannelScanConfig_t &config) { From 07bcf386f5ece89ac7fdf9dd2bbf220407727556 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Sep 2024 18:31:58 +0100 Subject: [PATCH 1264/1848] [LR11x0] LR-FHSS reception is not supported --- .../LR11x0_LR_FHSS_Modem.ino | 23 ++----------------- src/modules/LR11x0/LR11x0.cpp | 13 ++++------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino index 118103ab0b..b858c9639f 100644 --- a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -2,6 +2,7 @@ RadioLib LR11x0 LR-FHSS Modem Example This example shows how to use LR-FHSS modem in LR11x0 chips. + This modem can only transmit data, and is not able to receive. NOTE: The sketch below is just a guide on how to use LR-FHSS modem, so this code should not be run directly! @@ -68,9 +69,7 @@ void setup() { } void loop() { - // LR-FHSS modem can use the same transmit/receive methods - // as the LoRa modem, even their interrupt-driven versions - + // LR-FHSS modem can only transmit! // transmit LR-FHSS packet int state = radio.transmit("Hello World!"); /* @@ -89,22 +88,4 @@ void loop() { Serial.println(state); } - // receive LR-FHSS packet - String str; - state = radio.receive(str); - /* - byte byteArr[8]; - int state = radio.receive(byteArr, 8); - */ - if (state == RADIOLIB_ERR_NONE) { - Serial.println(F("[LR1110] Received packet!")); - Serial.print(F("[LR1110] Data:\t")); - Serial.println(str); - } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { - Serial.println(F("[LR1110] Timed out while waiting for packet!")); - } else { - Serial.print(F("[LR1110] Failed to receive packet, code ")); - Serial.println(state); - } - } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index ce90017070..cbda7ddb6b 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -216,11 +216,8 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { - size_t maxLen = len; - if(len == 0) { - maxLen = 0xFF; - } - timeout = (RadioLibTime_t)(((maxLen * 8.0) / (RADIOLIB_LR11X0_LR_FHSS_BIT_RATE)) * 1000.0 * 5.0); + // this modem cannot receive + return(RADIOLIB_ERR_WRONG_MODEM); } else { return(RADIOLIB_ERR_UNKNOWN); @@ -472,8 +469,7 @@ int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa state = getPacketType(&modem); RADIOLIB_ASSERT(state); if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && - (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) && - (modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) { + (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -521,8 +517,7 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { state = getPacketType(&modem); RADIOLIB_ASSERT(state); if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && - (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) && - (modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) { + (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { return(RADIOLIB_ERR_WRONG_MODEM); } From a7a99a2097bf45e5aa8f4ac6882cabdf7b597aed Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 24 Sep 2024 20:02:27 +0200 Subject: [PATCH 1265/1848] [SX126x] Simplify Rx gain retention config --- src/modules/SX126x/SX126x.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f94481a001..09e3e57e72 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1113,18 +1113,8 @@ int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { // add Rx Gain register to retention memory if requested if(persist) { // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3 - uint8_t value0 = 0x01; - uint8_t value1 = 0x08; - uint8_t value2 = 0xAC; - - state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, &value0, 1); - RADIOLIB_ASSERT(state); - - state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1, &value1, 1); - RADIOLIB_ASSERT(state); - - state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2, &value2, 1); - RADIOLIB_ASSERT(state); + uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) }; + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3); } return(state); From da74aa26d290f541fdf973cab7176bbc9bb36551 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 25 Sep 2024 17:02:09 +0100 Subject: [PATCH 1266/1848] [SX126x] Simplify rx gain configuration --- src/modules/SX126x/SX126x.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 9c46b3b186..40c076e85d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1008,20 +1008,9 @@ int16_t SX126x::setRxBandwidth(float rxBw) { } int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { - // read the current register value - uint8_t rxGain = 0; - int16_t state = readRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); - RADIOLIB_ASSERT(state); - - // gain mode register value (SX1261/2 datasheet v2.1 section 9.6) - if(rxbgm) { - rxGain = RADIOLIB_SX126X_RX_GAIN_BOOSTED; - } else { - rxGain = RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; - } - // update RX gain setting register - state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); + uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; + int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); RADIOLIB_ASSERT(state); // add Rx Gain register to retention memory if requested From af27e44a525802267f51d6e93cdc73d31a3f5b0b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 25 Sep 2024 17:02:37 +0100 Subject: [PATCH 1267/1848] [SX126x] Fix instant RSSI reading --- src/modules/SX126x/SX126x.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 40c076e85d..17ad06635e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1260,9 +1260,9 @@ float SX126x::getRSSI(bool packet) { return(-1.0 * rssiPkt/2.0); } else { // get instantaneous RSSI value - uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3); - return((float)data[0] / (-2.0)); + uint8_t rssiRaw = 0; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, &rssiRaw, 1); + return((float)rssiRaw / (-2.0)); } } From a68df0f51527fea64c1c7d9a323ef6a6bce13c0b Mon Sep 17 00:00:00 2001 From: mixeysan <81270595+mixeysan@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:55:55 +1000 Subject: [PATCH 1268/1848] [LR11x0] Fix temperature reading (#1234) * Update LR11x0.cpp According LR1121 datasheet * Update LR11x0.cpp Now OK * Update LR11x0.cpp Now OK --- src/modules/LR11x0/LR11x0.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index cbda7ddb6b..81eb9ade07 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2121,7 +2121,8 @@ int16_t LR11x0::getTemp(float* temp) { // pass the replies if(temp) { uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; - *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1350.0f - 0.7295f); + raw = raw & 0x07FF; //According LR1121 datasheet we need [0..10] bits + *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1.35f - 0.7295f); //According LR1121 datasheet 1.35 } return(state); From ce673b29395da9906d9e739cb7a1eb1beea4bb60 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:57:26 +0200 Subject: [PATCH 1269/1848] [SX127x] Fix missing CRC mismatch error (#1236) --- src/modules/SX127x/SX127x.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b43bf6f3b6..1397e57c9d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -672,12 +672,11 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { // CRC is disabled according to packet header and enabled according to user // most likely damaged packet header state = RADIOLIB_ERR_LORA_HEADER_DAMAGED; - } else { - // set FIFO read pointer to the start of the current packet - state = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR); - if (state >= 0) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, state); - } + } + // set FIFO read pointer to the start of the current packet + int16_t addr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR); + if (addr >= 0) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, addr); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { From 56bf7c87c358dc23c4ebe3c70b67653c076cd942 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:13:08 +0200 Subject: [PATCH 1270/1848] [LR11x0] Implement automatic and forced LDRO (#1237) --- src/modules/LR11x0/LR11x0.cpp | 41 ++++++++++++++++++++++++++++++++++- src/modules/LR11x0/LR11x0.h | 15 +++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 81eb9ade07..a438e05e79 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1414,6 +1414,33 @@ void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], this->setDioAsRfSwitch(enable, modes[0], modes[1], modes[2], modes[3], modes[4], modes[5], modes[6]); } +int16_t LR11x0::forceLDRO(bool enable) { + // check packet type + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update modulation parameters + this->ldroAuto = false; + this->ldrOptimize = (uint8_t)enable; + return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR11x0::autoLDRO() { + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->ldroAuto = true; + return(RADIOLIB_ERR_NONE); +} + int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -2388,7 +2415,19 @@ int16_t LR11x0::setPacketType(uint8_t type) { } int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { - uint8_t buff[4] = { sf, bw, cr, ldro }; + // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + if(symbolLength >= 16.0) { + this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED; + } else { + this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED; + } + } else { + this->ldrOptimize = ldro; + } + + uint8_t buff[4] = { sf, bw, cr, this->ldrOptimize }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index e5a7baf62b..a408611422 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1283,6 +1283,21 @@ class LR11x0: public PhysicalLayer { /*! \copydoc Module::setRfSwitchTable */ void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to + the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call LR11x0::autoLDRO() + \param enable Force LDRO to be always enabled (true) or disabled (false). + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically + when symbol length exceeds 16 ms. + \returns \ref status_codes + */ + int16_t autoLDRO(); + /*! \brief Sets LR-FHSS configuration. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. From 42ae7c92ed584317d7206cfc463ba6260295dbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 27 Sep 2024 07:03:40 +0200 Subject: [PATCH 1271/1848] [LR112x] enabled higher bandwidth settings for 2.4G lora (#1235) * enabled higher bandwidth settings for 2.4G lora * document new parameters * use the same cutoff as this->highFreq --- src/modules/LR11x0/LR1120.cpp | 2 +- src/modules/LR11x0/LR11x0.cpp | 56 ++++++++++++++++++++++------------- src/modules/LR11x0/LR11x0.h | 11 +++++-- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index a69dc35931..0b67ee95bc 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -7,7 +7,7 @@ LR1120::LR1120(Module* mod) : LR11x0(mod) { int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, freq > 1000.0); RADIOLIB_ASSERT(state); // configure publicly accessible settings diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index a438e05e79..2d78249f35 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -23,13 +23,13 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR11X0_IRQ_TIMEOUT; } -int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage) { +int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool high) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // configure publicly accessible settings - state = setBandwidth(bw); + state = setBandwidth(bw, high); RADIOLIB_ASSERT(state); state = setSpreadingFactor(sf); @@ -623,7 +623,7 @@ int16_t LR11x0::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } -int16_t LR11x0::setBandwidth(float bw) { +int16_t LR11x0::setBandwidth(float bw, bool high) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); @@ -633,25 +633,39 @@ int16_t LR11x0::setBandwidth(float bw) { } // ensure byte conversion doesn't overflow - RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); - - // check allowed bandwidth values - uint8_t bw_div2 = bw / 2 + 0.01; - switch (bw_div2) { - case 31: // 62.5: - this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5; - break; - case 62: // 125.0: - this->bandwidth = RADIOLIB_LR11X0_LORA_BW_125_0; - break; - case 125: // 250.0 - this->bandwidth = RADIOLIB_LR11X0_LORA_BW_250_0; - break; - case 250: // 500.0 - this->bandwidth = RADIOLIB_LR11X0_LORA_BW_500_0; - break; - default: + if (high) { + RADIOLIB_CHECK_RANGE(bw, 203.125, 815.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + + if(fabsf(bw - 203.125) <= 0.001) { + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_203_125; + } else if(fabsf(bw - 406.25) <= 0.001) { + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_406_25; + } else if(fabsf(bw - 812.5) <= 0.001) { + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_812_50; + } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + } else { + RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + + // check allowed bandwidth values + uint8_t bw_div2 = bw / 2 + 0.01; + switch (bw_div2) { + case 31: // 62.5: + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5; + break; + case 62: // 125.0: + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_125_0; + break; + case 125: // 250.0 + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_250_0; + break; + case 250: // 500.0 + this->bandwidth = RADIOLIB_LR11X0_LORA_BW_500_0; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } } // update modulation parameters diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index a408611422..f6a4b44e3c 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -364,6 +364,9 @@ #define RADIOLIB_LR11X0_LORA_BW_125_0 (0x04UL << 0) // 7 0 125.0 kHz #define RADIOLIB_LR11X0_LORA_BW_250_0 (0x05UL << 0) // 7 0 250.0 kHz #define RADIOLIB_LR11X0_LORA_BW_500_0 (0x06UL << 0) // 7 0 500.0 kHz +#define RADIOLIB_LR11X0_LORA_BW_203_125 (0x0DUL << 0) // 7 0 203.0 kHz (2.4GHz only) +#define RADIOLIB_LR11X0_LORA_BW_406_25 (0x0EUL << 0) // 7 0 406.0 kHz (2.4GHz only) +#define RADIOLIB_LR11X0_LORA_BW_812_50 (0x0FUL << 0) // 7 0 812.0 kHz (2.4GHz only) #define RADIOLIB_LR11X0_LORA_CR_4_5_SHORT (0x01UL << 0) // 7 0 coding rate: 4/5 with short interleaver #define RADIOLIB_LR11X0_LORA_CR_4_6_SHORT (0x02UL << 0) // 7 0 4/6 with short interleaver #define RADIOLIB_LR11X0_LORA_CR_4_7_SHORT (0x03UL << 0) // 7 0 4/7 with short interleaver @@ -773,9 +776,10 @@ class LR11x0: public PhysicalLayer { \param syncWord 1-byte LoRa sync word. \param preambleLength LoRa preamble length in symbols \param tcxoVoltage TCXO reference voltage to be set. + \param high defaults to false for Sub-GHz band, true for frequencies above 1GHz \returns \ref status_codes */ - int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage); + int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool high = false); /*! \brief Initialization method for FSK modem. @@ -993,11 +997,12 @@ class LR11x0: public PhysicalLayer { // configuration methods /*! - \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. + \brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. (default, high = false) \param bw LoRa bandwidth to be set in kHz. + \param high if set to true, allowed bandwidth is 203.125, 406.25 and 812.5 kHz, frequency must be above 1GHz \returns \ref status_codes */ - int16_t setBandwidth(float bw); + int16_t setBandwidth(float bw, bool high = false); /*! \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. From 83e05701fe508b1d9bb0ab663dd0a695f3fb825d Mon Sep 17 00:00:00 2001 From: Ali Mosallaei Date: Fri, 27 Sep 2024 14:26:13 -0400 Subject: [PATCH 1272/1848] [HAL] Add tones support for the RPi Pico (#1239) * Add tones support for RPi Pico * Add dependencies to CMakeLists * Address review --- examples/NonArduino/Pico/CMakeLists.txt | 4 +- examples/NonArduino/Pico/PicoHal.h | 61 +++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/examples/NonArduino/Pico/CMakeLists.txt b/examples/NonArduino/Pico/CMakeLists.txt index e58520ff3d..c86122fb7c 100644 --- a/examples/NonArduino/Pico/CMakeLists.txt +++ b/examples/NonArduino/Pico/CMakeLists.txt @@ -23,11 +23,11 @@ add_executable(${PROJECT_NAME} ) # Pull in common dependencies -target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer RadioLib) +target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer pico_multicore hardware_pwm RadioLib) pico_enable_stdio_usb(${PROJECT_NAME} 1) pico_enable_stdio_uart(${PROJECT_NAME} 0) # Create map/bin/hex file etc. -pico_add_extra_outputs(${PROJECT_NAME}) \ No newline at end of file +pico_add_extra_outputs(${PROJECT_NAME}) diff --git a/examples/NonArduino/Pico/PicoHal.h b/examples/NonArduino/Pico/PicoHal.h index d01842574c..ec4d12e33b 100644 --- a/examples/NonArduino/Pico/PicoHal.h +++ b/examples/NonArduino/Pico/PicoHal.h @@ -8,6 +8,45 @@ #include #include "hardware/spi.h" #include "hardware/timer.h" +#include "hardware/pwm.h" +#include "hardware/clocks.h" +#include "pico/multicore.h" + +uint32_t toneLoopPin; +unsigned int toneLoopFrequency; +unsigned long toneLoopDuration; + +// pre-calculated pulse-widths for 1200 and 2200Hz +// we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6) +#define SLEEP_1200 416.666 +#define SLEEP_2200 227.272 + +// === NOTE === +// The tone(...) implementation uses the second core on the RPi Pico. This is to diminish as much +// jitter in the output tones as possible. + +void toneLoop(){ + gpio_set_dir(toneLoopPin, GPIO_OUT); + + uint32_t sleep_dur; + if (toneLoopFrequency == 1200) { + sleep_dur = SLEEP_1200; + } else if (toneLoopFrequency == 2200) { + sleep_dur = SLEEP_2200; + } else { + sleep_dur = 500000 / toneLoopFrequency; + } + + + // tone bitbang + while(1){ + gpio_put(toneLoopPin, 1); + sleep_us(sleep_dur); + gpio_put(toneLoopPin, 0); + sleep_us(sleep_dur); + tight_loop_contents(); + } +} // create a new Raspberry Pi Pico hardware abstraction // layer using the Pico SDK @@ -21,8 +60,7 @@ class PicoHal : public RadioLibHal { _spiSpeed(spiSpeed), _misoPin(misoPin), _mosiPin(mosiPin), - _sckPin(sckPin) { - } + _sckPin(sckPin){} void init() override { stdio_init_all(); @@ -110,6 +148,19 @@ class PicoHal : public RadioLibHal { return (this->micros() - start); } + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override { + // tones on the Pico are generated using bitbanging. This process is offloaded to the Pico's second core + multicore_reset_core1(); + toneLoopPin = pin; + toneLoopFrequency = frequency; + toneLoopDuration = duration; + multicore_launch_core1(toneLoop); + } + + void noTone(uint32_t pin) override { + multicore_reset_core1(); + } + void spiBegin() { spi_init(_spiChannel, _spiSpeed); spi_set_format(_spiChannel, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); @@ -125,6 +176,10 @@ class PicoHal : public RadioLibHal { spi_write_read_blocking(_spiChannel, out, in, len); } + void yield() override { + tight_loop_contents(); + } + void spiEndTransaction() {} void spiEnd() { @@ -140,4 +195,4 @@ class PicoHal : public RadioLibHal { uint32_t _sckPin; }; -#endif \ No newline at end of file +#endif From 98ad30eb103d22bb7e75f3cc900597403b0cfb1f Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Fri, 27 Sep 2024 20:30:42 +0200 Subject: [PATCH 1273/1848] [LR11x0] Fix CAD IRQ setting (#1240) --- src/modules/LR11x0/LR11x0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 2d78249f35..8a87959175 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -589,7 +589,7 @@ int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &config) { // set DIO pin mapping uint16_t irqFlags = (config.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE : config.cad.irqFlags; - state = setDioIrqParams(irqFlags, irqFlags); + state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqFlags)); RADIOLIB_ASSERT(state); // clear interrupt flags From 5d076f616a660c371a77fa6fe40ea2f079231ec5 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 28 Sep 2024 12:17:41 +0200 Subject: [PATCH 1274/1848] [LoRaWAN] Fix channel mask persistence (#1238) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 15 ++++++++++++--- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b2ecd50c2c..a4c6040418 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -440,11 +440,19 @@ uint8_t* LoRaWANNode::getBufferSession() { LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFCnt); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp); + // store the enabled channels + uint64_t chMaskGrp0123 = 0; + uint32_t chMaskGrp45 = 0; + this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, chMaskGrp0123); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 9, chMaskGrp45); + + // store the available/unused channels uint16_t chMask = 0x0000; (void)this->getAvailableChannels(&chMask); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], chMask); - // save the current uplink MAC command queue + // store the current uplink MAC command queue memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], this->fOptsUp, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], &this->fOptsUpLen, 1); @@ -2340,11 +2348,11 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd } break; case 6: - // for dynamic bands: all channels ON (currently defined) + // for dynamic bands: all channels ON (that are currently defined) // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 // except for CN500: all 125kHz channels ON - // for dynamic bands: retrieve all defined channels + // for dynamic bands: retrieve all currently defined channels // for fixed bands: cannot store all defined channels, so select a random one from each bank this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN500) { @@ -2896,6 +2904,7 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr } } } + } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED // if a subband is set, we can set the channel indices straight from subband if(this->subBand > 0 && this->subBand <= 8) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 4b1005114c..723c4624ba 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1069,7 +1069,7 @@ class LoRaWANNode { // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. bool cadChannelClear(); - // get or create a complete 80-bit channel mask for current configuration + // (dynamic bands:) get or (fixed bands:) create a complete 80-bit channel mask for current configuration void getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45); // setup uplink/downlink channel data rates and frequencies From 38fc7a97a4c195b7c10aa94215a1c53ec18a56ef Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 Sep 2024 13:29:41 +0200 Subject: [PATCH 1275/1848] [SX127x] Handle multiple IRQ flags (#1190) --- src/TypeDef.h | 5 ++ src/modules/SX127x/SX127x.cpp | 125 +++++++++++++++++++++++++--------- src/modules/SX127x/SX127x.h | 4 ++ 3 files changed, 102 insertions(+), 32 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index 7f4d22785c..4c9538661b 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -250,6 +250,11 @@ */ #define RADIOLIB_ERR_NULL_POINTER (-28) +/*! + \brief The requested IRQ configuration is not valid for this module. +*/ +#define RADIOLIB_ERR_INVALID_IRQ (-29) + // RF69-specific status codes /*! diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 1397e57c9d..94b278bdd5 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1314,43 +1314,104 @@ uint32_t SX127x::getIrqFlags() { int16_t SX127x::setIrqFlags(uint32_t irq) { // this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ... + // in addition, the configuration is often mutually exclusive, so we iterate over the set bits in a loop + uint8_t usedPinFlags = 0; + bool conflict = false; int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - switch(irq) { - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6)); - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE, 7, 6)); - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER, 1, 0)); - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR, 1, 0)); - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE, 7, 6)); - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 5, 4)); - case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 5, 4)); + int16_t state; + for(uint8_t i = 0; i <= 31; i++) { + // check if the bit is set + uint32_t irqBit = irq & (1UL << i); + if(!irqBit) { + continue; } - return(RADIOLIB_ERR_UNSUPPORTED); - - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - switch(irq) { - case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6)); - case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6)); - case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT, 7, 6)); - case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS, 3, 2)); - case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0): - return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_TIMEOUT, 3, 2)); + + // if not, decode it + uint8_t dioNum = 0; // DIO pin number and register value to set (address and MSB/LSB can be inferred) + uint8_t regVal = 0; + if(modem == RADIOLIB_SX127X_LORA) { + switch(irqBit) { + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE): + dioNum = 0; + regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT; + break; + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE): + dioNum = 0; + regVal = RADIOLIB_SX127X_DIO0_LORA_RX_DONE; + break; + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER): + dioNum = 3; + regVal = RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER; + break; + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR): + dioNum = 3; + regVal = RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR; + break; + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE): + dioNum = 0; + regVal = RADIOLIB_SX127X_DIO0_LORA_CAD_DONE; + break; + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED): + dioNum = 1; + regVal = RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED; + break; + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT): + dioNum = 1; + regVal = RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT; + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + switch(irqBit) { + case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8): + dioNum = 0; + regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT; + break; + case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8): + dioNum = 0; + regVal = RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY; + break; + case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0): + dioNum = 4; + regVal = RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT; + break; + case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0): + dioNum = 2; + regVal = RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS; + break; + case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0): + dioNum = 2; + regVal = RADIOLIB_SX127X_DIO2_PACK_TIMEOUT; + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } } - return(RADIOLIB_ERR_UNSUPPORTED); + + // check if this DIO pin has been set already + if(usedPinFlags & (1UL << dioNum)) { + // uh oh, this pin is used! + RADIOLIB_DEBUG_PRINTLN("Unable to set IRQ %04x on DIO%d due to conflict!", irqBit, (int)dioNum); + conflict = true; + continue; + } + + // DIO pin is unused, set the flag and configure it + usedPinFlags |= (1UL << dioNum); + uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_1 : RADIOLIB_SX127X_REG_DIO_MAPPING_2; + uint8_t msb = 7 - 2*(dioNum % 4); + state = this->mod->SPIsetRegValue(addr, regVal, msb, msb - 1); + RADIOLIB_ASSERT(state); } - return(RADIOLIB_ERR_UNSUPPORTED); + // if there was at least one conflict, this flag is set + if(conflict) { + return(RADIOLIB_ERR_INVALID_IRQ); + } + + return(state); } int16_t SX127x::clearIrqFlags(uint32_t irq) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 94db00ab62..ba492f1ddb 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1063,6 +1063,10 @@ class SX127x: public PhysicalLayer { /*! \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + NOTE: Unlike other modules that support IRQ abstraction (SX126x, LR11x0, etc.), + SX127x cannot configure multiple IRQs to signal using the same DIOx pin. + This method tries to configure IRQs in a "best effort" approach, and will skip conflicting flags. + RADIOLIB_ERR_INVALID_IRQ will be returned in this case. \param irq Module-specific IRQ flags. \returns \ref status_codes */ From 8a83df6ad466821530a9a8939053739768833bb4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Sep 2024 15:22:40 +0200 Subject: [PATCH 1276/1848] Bump version to 7.0.1 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 5bbf3101d9..984fd1c097 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.0.0" +version: "7.0.1" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index d99e412cc3..4f0c565e89 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.0.0", + "version": "7.0.1", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 02c69b4f01..a4c7cc964b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.0.0 +version=7.0.1 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 23b953a0f3..6df07b8160 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -588,7 +588,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 #define RADIOLIB_VERSION_MINOR 0 -#define RADIOLIB_VERSION_PATCH 0 +#define RADIOLIB_VERSION_PATCH 1 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 505c0f7910ab73353c42ee4735029554347e4b10 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Sep 2024 16:54:22 +0200 Subject: [PATCH 1277/1848] [CI] Free up some runner disk space (CI_BUILD_ALL) --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e6da05ace2..642e84716a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -134,6 +134,9 @@ jobs: run-build: ${{ (inputs.id != 'none' && matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) || inputs.id == 'all' || inputs.id == matrix.id }} steps: + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@v1.3.1 + - name: Install arduino-cli if: ${{ env.run-build == 'true' }} run: From 5a9ff5a4912f87918390348c8caa54ea8a6afada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 30 Sep 2024 16:17:00 +0200 Subject: [PATCH 1278/1848] [SX1227x] fix DIO register mapping (#1246) --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 94b278bdd5..036fce836a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1400,7 +1400,7 @@ int16_t SX127x::setIrqFlags(uint32_t irq) { // DIO pin is unused, set the flag and configure it usedPinFlags |= (1UL << dioNum); - uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_1 : RADIOLIB_SX127X_REG_DIO_MAPPING_2; + uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_2 : RADIOLIB_SX127X_REG_DIO_MAPPING_1; uint8_t msb = 7 - 2*(dioNum % 4); state = this->mod->SPIsetRegValue(addr, regVal, msb, msb - 1); RADIOLIB_ASSERT(state); From fdb3ac46ca0895060b533251ceea5679ddd23a12 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Sep 2024 18:10:18 +0200 Subject: [PATCH 1279/1848] [SX128x] Fix preamble length calculation (#1243) --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a51ad836f3..b1f47c7e83 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -870,7 +870,7 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { uint8_t m = 1; uint32_t len = 0; for(; e <= 15; e++) { - for(; m <= 15; m++) { + for(m = 1; m <= 15; m++) { len = m * (uint32_t(1) << e); if(len >= preambleLength) { break; From 406daee262d325012eef40e0ee8c8f9f16e61182 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Sep 2024 18:11:11 +0200 Subject: [PATCH 1280/1848] Bump version to 7.0.2 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 984fd1c097..1b3292c660 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.0.1" +version: "7.0.2" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 4f0c565e89..bd04ebf1b8 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.0.1", + "version": "7.0.2", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index a4c7cc964b..3b1bcba5c6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.0.1 +version=7.0.2 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 6df07b8160..60859443a8 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -588,7 +588,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 #define RADIOLIB_VERSION_MINOR 0 -#define RADIOLIB_VERSION_PATCH 1 +#define RADIOLIB_VERSION_PATCH 2 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 46a086cfa8d9383f5dd3321bed174a93417cbd29 Mon Sep 17 00:00:00 2001 From: jacobeva Date: Wed, 2 Oct 2024 16:59:25 +0100 Subject: [PATCH 1281/1848] [SX128x] Save context before sleep to allow TX to work on wake (#1249) (#1250) --- src/modules/SX128x/SX128x.cpp | 4 +++- src/modules/SX128x/SX128x.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index b1f47c7e83..5cbcc91c2c 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -461,7 +461,9 @@ int16_t SX128x::sleep(bool retainConfig) { if(!retainConfig) { sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; } - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, 0, 1, false, false); + RADIOLIB_ASSERT(state); + state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); // wait for SX128x to safely enter sleep mode this->mod->hal->delay(1); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index cea6b7aded..02162449ae 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -22,6 +22,7 @@ #define RADIOLIB_SX128X_CMD_READ_REGISTER 0x19 #define RADIOLIB_SX128X_CMD_WRITE_BUFFER 0x1A #define RADIOLIB_SX128X_CMD_READ_BUFFER 0x1B +#define RADIOLIB_SX128X_CMD_SAVE_CONTEXT 0xD5 #define RADIOLIB_SX128X_CMD_SET_SLEEP 0x84 #define RADIOLIB_SX128X_CMD_SET_STANDBY 0x80 #define RADIOLIB_SX128X_CMD_SET_FS 0xC1 From 6e665702419f8baa4740cbd1f05c844dd34364d9 Mon Sep 17 00:00:00 2001 From: jacobeva Date: Wed, 2 Oct 2024 19:05:21 +0100 Subject: [PATCH 1282/1848] [SX128x] Add setDataRate method for LoRa modem (#1251) --- src/modules/SX128x/SX128x.cpp | 16 ++++++++++++++++ src/modules/SX128x/SX128x.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 5cbcc91c2c..a7fe165b50 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -904,6 +904,22 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { return(RADIOLIB_ERR_WRONG_MODEM); } +int16_t SX128x::setDataRate(DataRate_t dr) { + // check active modem + uint8_t modem = getPacketType(); + int16_t state = RADIOLIB_ERR_NONE; + if (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + state = this->setCodingRate(dr.lora.codingRate); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); + } + return(state); +} + int16_t SX128x::setBitRate(float br) { // check active modem uint8_t modem = getPacketType(); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 02162449ae..6f584ead84 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -679,6 +679,13 @@ class SX128x: public PhysicalLayer { */ int16_t setPreambleLength(uint32_t preambleLength); + /*! + \brief Set data rate. + \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr) override; + /*! \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem). From 1f11cd1dd574c6ac9a2e1b8aadb34a2ec9cc0953 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Oct 2024 10:13:56 +0200 Subject: [PATCH 1283/1848] [LR1110] Added configurable LR-FHSS grid spacing --- src/modules/LR11x0/LR1110.cpp | 4 ++-- src/modules/LR11x0/LR1110.h | 3 ++- src/modules/LR11x0/LR1120.cpp | 4 ++-- src/modules/LR11x0/LR1120.h | 3 ++- src/modules/LR11x0/LR11x0.cpp | 9 ++++++--- src/modules/LR11x0/LR11x0.h | 5 +++-- src/protocols/PhysicalLayer/PhysicalLayer.h | 6 ++++++ 7 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 62bf116f13..7ebf5a7b97 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -31,9 +31,9 @@ int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_ return(state); } -int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { +int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index fcc65f2e63..3e1bc5fcee 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -58,13 +58,14 @@ class LR1110: public LR11x0 { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz. \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. \param power Output power in dBm. Defaults to 10 dBm. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. \returns \ref status_codes */ - int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, int8_t power = 10, float tcxoVoltage = 1.6); + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); // configuration methods diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 0b67ee95bc..9afa8dfb66 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -31,9 +31,9 @@ int16_t LR1120::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_ return(state); } -int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) { +int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::beginLRFHSS(bw, cr, tcxoVoltage); + int16_t state = LR11x0::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage); RADIOLIB_ASSERT(state); // configure publicly accessible settings diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index c4fbbde5d0..4abae5a93a 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -58,13 +58,14 @@ class LR1120: public LR11x0 { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz. \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. \param power Output power in dBm. Defaults to 10 dBm. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. \returns \ref status_codes */ - int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, int8_t power = 10, float tcxoVoltage = 1.6); + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); // configuration methods diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 8a87959175..70da0d3516 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -98,11 +98,14 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage) { +int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage) { // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS); RADIOLIB_ASSERT(state); + // set grid spacing + this->lrFhssGrid = narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC; + // configure publicly accessible settings state = setLrFhssConfig(bw, cr); RADIOLIB_ASSERT(state); @@ -418,8 +421,8 @@ int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { // in LR-FHSS mode, the packet is built by the device - // TODO add configurable grid step and device offset - state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC, true, this->lrFhssBw, this->lrFhssHopSeq, 0, const_cast(data), len); + // TODO add configurable device offset + state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, const_cast(data), len); RADIOLIB_ASSERT(state); } else { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index f6a4b44e3c..a52d64afd6 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -796,10 +796,11 @@ class LR11x0: public PhysicalLayer { \brief Initialization method for LR-FHSS modem. \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. \param tcxoVoltage TCXO reference voltage to be set. \returns \ref status_codes */ - int16_t beginLRFHSS(uint8_t bw, uint8_t cr, float tcxoVoltage); + int16_t beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -1594,7 +1595,7 @@ class LR11x0: public PhysicalLayer { uint16_t preambleLengthGFSK = 0; // cached LR-FHSS parameters - uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0; + uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0; uint16_t lrFhssHopSeq = 0; float dataRateMeasured = 0; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index b4218b5e95..c463e8b2cd 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -62,6 +62,9 @@ struct LrFhssRate_t { /*! \brief Coding rate */ uint8_t cr; + + /*! \brief Grid spacing */ + bool narrowGrid; }; /*! @@ -74,6 +77,9 @@ union DataRate_t { /*! \brief Interpretation for FSK modems */ FSKRate_t fsk; + + /*! \brief Interpretation for LR-FHSS modems */ + LrFhssRate_t lrFhss; }; /*! From dc77e6e6620340f184586ce5a202a223102dcd3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 7 Oct 2024 20:00:19 +0200 Subject: [PATCH 1284/1848] [SX126x] LR-FHSS support (#1228) * [FEC] Added Vitervi encoder * [SX126x] Added initial LR-FHSS transmission support * [CI] Use RPi build for CodeQL * [SX126x] Fix signed comparison warning * [FEC] Make input to Viterbi encoder const * [CI] Drop SX126x examples from Arduino Uno builds * [CI] Build SX123x for CodeQL scan * [FEC] Fix comparison type * [SX126x] Added configurable grid step * [SX126x] Rename convolutional coding class * [SX126x] Fix payload CRC * [SX126x] ADded LR-FHSS example * [SX126x] Make argument const --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/main.yml | 2 +- .../SX126x_LR_FHSS_Modem.ino | 94 +++++ src/modules/SX126x/SX1262.cpp | 18 + src/modules/SX126x/SX1262.h | 15 + src/modules/SX126x/SX1268.cpp | 18 + src/modules/SX126x/SX1268.h | 15 + src/modules/SX126x/SX126x.cpp | 169 +++++++- src/modules/SX126x/SX126x.h | 75 ++++ src/modules/SX126x/SX126x_LR_FHSS.cpp | 392 ++++++++++++++++++ src/utils/FEC.cpp | 56 +++ src/utils/FEC.h | 88 +++- 12 files changed, 933 insertions(+), 11 deletions(-) create mode 100644 examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino create mode 100644 src/modules/SX126x/SX126x_LR_FHSS.cpp diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c90f7c9d74..a658899a2b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -54,7 +54,7 @@ jobs: - name: Build example run: - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:uno $PWD/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino --warnings=all + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:uno $PWD/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino --warnings=all - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 642e84716a..7c518526ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,7 +46,7 @@ jobs: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. include: - id: arduino:avr:uno - run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update|Pager|APRS|Morse)" >> $GITHUB_OUTPUT + run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update|Pager|APRS|Morse|SX126x)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: | echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT diff --git a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino new file mode 100644 index 0000000000..d0f45f8d86 --- /dev/null +++ b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino @@ -0,0 +1,94 @@ +/* + RadioLib SX126x LR-FHSS Modem Example + + This example shows how to use LR-FHSS modem in SX126x chips. + This modem can only transmit data, and is not able to receive. + + NOTE: The sketch below is just a guide on how to use + LR-FHSS modem, so this code should not be run directly! + Instead, modify the other examples to use LR-FHSS + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; + +// or using CubeCell +//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginLRFHSS(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable LR-FHSS) + // radio.beginLRFHSS() start LR-FHSS modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setLrFhssConfig(RADIOLIB_SX126X_LR_FHSS_BW_1523_4, // bandwidth + RADIOLIB_SX126X_LR_FHSS_CR_1_2, // coding rate + 3, // header count + 0x13A); // hopping sequence seed + state = radio.setOutputPower(10.0); + state = radio.setSyncWord(0x12345678); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // LR-FHSS modem can only transmit! + // transmit LR-FHSS packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[SX1262] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1262] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[SX1262] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1262] Failed to transmit packet, code ")); + Serial.println(state); + } + +} diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 232ad63801..43c9706370 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -47,6 +47,24 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX1262::setFrequency(float freq) { return(setFrequency(freq, true)); } diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 7ae6789fdd..c05ee4b115 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -62,6 +62,21 @@ class SX1262: public SX126x { */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + /*! + \brief Initialization method for LR-FHSS modem. This modem only supports transmission! + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + // configuration methods /*! diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index c50baaf164..78cfdae349 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -47,6 +47,24 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX1268::setFrequency(float freq) { return(setFrequency(freq, true)); } diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 503c74e861..ad411ee793 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -61,6 +61,21 @@ class SX1268: public SX126x { */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + /*! + \brief Initialization method for LR-FHSS modem. This modem only supports transmission! + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + // configuration methods /*! diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 17ad06635e..7109d6d98d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -119,6 +119,47 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL return(state); } +int16_t SX126x::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage, bool useRegulatorLDO) { + this->lrFhssGridNonFcc = narrowGrid; + + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCurrentLimit(60.0); + RADIOLIB_ASSERT(state); + + state = setDio2AsRfSwitch(true); + RADIOLIB_ASSERT(state); + + // set all packet params to 0 (packet engine is disabled in LR-FHSS mode) + state = setPacketParamsFSK(0, 0, 0, 0, 0, 0, 0, 0); + RADIOLIB_ASSERT(state); + + // set bit rate + this->rxBandwidth = 0; + this->frequencyDev = 0; + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; + state = setBitRate(0.48828125f); + RADIOLIB_ASSERT(state); + + return(setLrFhssConfig(bw, cr)); +} + +int16_t SX126x::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeqId) { + // check and cache all parameters + RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_SX126X_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_SX126X_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE); + this->lrFhssCr = cr; + RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_SX126X_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_SX126X_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH); + this->lrFhssBw = bw; + RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE); + this->lrFhssHdrCount = hdrCount; + RADIOLIB_CHECK_RANGE((int16_t)hopSeqId, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING); + this->lrFhssHopSeqId = hopSeqId; + return(RADIOLIB_ERR_NONE); +} + int16_t SX126x::reset(bool verify) { // run the reset sequence this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); @@ -171,13 +212,34 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout + uint8_t modem = getPacketType(); RadioLibTime_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + while(true) { + // yield for multi-threaded platforms this->mod->hal->yield(); + + // check timeout if(this->mod->hal->millis() - start > timeout) { finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } + + // poll the interrupt pin + if(this->mod->hal->digitalRead(this->mod->getIrq())) { + // in LoRa or GFSK, only Tx done interrupt is enabled + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + break; + } + + // in LR-FHSS, IRQ signals both Tx done as frequency hop request + if(this->getIrqFlags() & RADIOLIB_SX126X_IRQ_TX_DONE) { + break; + } else { + // handle frequency hop + this->setLRFHSSHop(this->lrFhssHopNum % 16); + clearIrqStatus(); + } + } } // update data rate @@ -467,13 +529,17 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); - } else { + } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { return(RADIOLIB_ERR_UNKNOWN); } RADIOLIB_ASSERT(state); // set DIO mapping - state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE); + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE); + } else { + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP); + } RADIOLIB_ASSERT(state); // set buffer pointers @@ -481,7 +547,49 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // write packet to buffer + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { state = writeBuffer(const_cast(data), len); + + } else { + // first, reset the LR-FHSS state machine + state = resetLRFHSS(); + RADIOLIB_ASSERT(state); + + // skip hopping for the first 4 - lrFhssHdrCount blocks + for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) { + stepLRFHSS(); + } + + // in LR-FHSS mode, we need to build the entire packet manually + uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 }; + size_t frameLen = 0; + this->lrFhssFrameBitsRem = 0; + this->lrFhssFrameHopsRem = 0; + this->lrFhssHopNum = 0; + state = buildLRFHSSPacket(const_cast(data), len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem); + RADIOLIB_ASSERT(state); + + // FIXME check max len for FHSS + state = writeBuffer(frame, frameLen); + RADIOLIB_ASSERT(state); + + // activate hopping + uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem }; + state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3); + RADIOLIB_ASSERT(state); + + // write the initial hopping table + uint8_t initHops = this->lrFhssFrameHopsRem; + if(initHops > 16) { + initHops = 16; + }; + for(size_t i = 0; i < initHops; i++) { + // set the hop frequency and symbols + state = this->setLRFHSSHop(i); + RADIOLIB_ASSERT(state); + } + + } RADIOLIB_ASSERT(state); // clear interrupt flags @@ -1025,7 +1133,8 @@ int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { int16_t SX126x::setDataShaping(uint8_t sh) { // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + uint8_t modem = getPacketType(); + if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -1079,6 +1188,14 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } return(setSyncWord(syncWord[0])); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word + if(len != sizeof(uint32_t)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t)); + } return(RADIOLIB_ERR_WRONG_MODEM); @@ -1346,7 +1463,8 @@ int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { RadioLibTime_t SX126x::getTimeOnAir(size_t len) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact - if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) uint8_t sfCoeff2 = 8; @@ -1373,9 +1491,44 @@ RadioLibTime_t SX126x::getTimeOnAir(size_t len) { uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; return((symbolLength_us * nSymbol_x4) / 4); - } else { + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { return(((uint32_t)len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + // calculate the number of bits based on coding rate + uint16_t N_bits; + switch(this->lrFhssCr) { + case RADIOLIB_SX126X_LR_FHSS_CR_5_6: + N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? + break; + case RADIOLIB_SX126X_LR_FHSS_CR_2_3: + N_bits = (len * 3) / 2; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_2: + N_bits = len * 2; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_3: + N_bits = len * 3; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + // calculate number of bits when accounting for unaligned last block + uint16_t N_payBits = (N_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS; + uint16_t N_lastBlockBits = N_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS; + if(N_lastBlockBits) { + N_payBits += N_lastBlockBits + 2; + } + + // add header bits + uint16_t N_totalBits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + N_payBits; + return(((uint32_t)N_totalBits * 8 * 1000000UL) / 488.28215f); + } + + return(RADIOLIB_ERR_UNKNOWN); } RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) { @@ -1908,8 +2061,8 @@ int16_t SX126x::clearDeviceErrors() { int16_t SX126x::setFrequencyRaw(float freq) { // calculate raw value - uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; - return(setRfFrequency(frf)); + this->frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; + return(setRfFrequency(this->frf)); } int16_t SX126x::fixSensitivity() { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 0c7d17b7a1..a64356aaa0 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -8,6 +8,8 @@ #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" +#include "../../utils/FEC.h" +#include "../../utils/CRC.h" // SX126X physical layer properties #define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 @@ -434,6 +436,36 @@ // size of the spectral scan result #define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) +// LR-FHSS configuration +#define RADIOLIB_SX126X_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 +#define RADIOLIB_SX126X_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 +#define RADIOLIB_SX126X_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 +#define RADIOLIB_SX126X_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 +#define RADIOLIB_SX126X_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK +#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) +#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) +#define RADIOLIB_SX126X_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled +#define RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_SX126X_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz + +// LR-FHSS packet lengths +#define RADIOLIB_SX126X_LR_FHSS_MAX_ENC_SIZE (608) +#define RADIOLIB_SX126X_LR_FHSS_HEADER_BITS (114) +#define RADIOLIB_SX126X_LR_FHSS_HDR_BYTES (10) +#define RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES (4) +#define RADIOLIB_SX126X_LR_FHSS_FRAG_BITS (48) +#define RADIOLIB_SX126X_LR_FHSS_BLOCK_PREAMBLE_BITS (2) +#define RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS (RADIOLIB_SX126X_LR_FHSS_FRAG_BITS + RADIOLIB_SX126X_LR_FHSS_BLOCK_PREAMBLE_BITS) + /*! \class SX126x \brief Base class for %SX126x series. All derived classes for %SX126x (e.g. SX1262 or SX1268) inherit from this base class. @@ -489,6 +521,27 @@ class SX126x: public PhysicalLayer { */ int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); + /*! + \brief Initialization method for LR-FHSS modem. This modem only supports transmission! + \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. + \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage, bool useRegulatorLDO = false); + + /*! + \brief Sets LR-FHSS configuration. + \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. + \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. + \param hdrCount Header packet count, 1 - 4. Defaults to 3. + \param hopSeqId 9-bit seed number for PRNG generation of the hopping sequence. Defaults to 0x13A. + \returns \ref status_codes + */ + int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeqId = 0x100); + /*! \brief Reset method. Will reset the chip to the default state using RST pin. \param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly @@ -830,6 +883,7 @@ class SX126x: public PhysicalLayer { /*! \brief Sets FSK sync word in the form of array of up to 8 bytes. + Can also set LR-FHSS sync word, but its length must be 4 bytes. \param syncWord FSK sync word to be set. \param len FSK sync word length in bytes. \returns \ref status_codes @@ -1214,10 +1268,26 @@ class SX126x: public PhysicalLayer { uint32_t tcxoDelay = 0; uint8_t pwr = 0; + uint32_t frf = 0; size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + // LR-FHSS stuff - there's a lot of it because all the encoding happens in software + uint8_t lrFhssCr = RADIOLIB_SX126X_LR_FHSS_CR_2_3; + uint8_t lrFhssBw = RADIOLIB_SX126X_LR_FHSS_BW_722_66; + uint8_t lrFhssHdrCount = 3; + uint8_t lrFhssSyncWord[RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES] = { 0x12, 0xAD, 0x10, 0x1B }; + bool lrFhssGridNonFcc = false; + uint16_t lrFhssNgrid = 0; + uint16_t lrFhssLfsrState = 0; + uint16_t lrFhssPoly = 0; + uint16_t lrFhssSeed = 0; + uint16_t lrFhssHopSeqId = 0; + size_t lrFhssFrameBitsRem = 0; + size_t lrFhssFrameHopsRem = 0; + size_t lrFhssHopNum = 0; + int16_t modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem); int16_t config(uint8_t modem); bool findChip(const char* verStr); @@ -1232,6 +1302,11 @@ class SX126x: public PhysicalLayer { int16_t fixImplicitTimeout(); int16_t fixInvertedIQ(uint8_t iqConfig); + // LR-FHSS utilities + int16_t buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len, size_t* out_bits, size_t* out_hops); + int16_t resetLRFHSS(); + uint16_t stepLRFHSS(); + int16_t setLRFHSSHop(uint8_t index); void regdump(); void effectEvalPre(uint8_t* buff, uint32_t start); diff --git a/src/modules/SX126x/SX126x_LR_FHSS.cpp b/src/modules/SX126x/SX126x_LR_FHSS.cpp new file mode 100644 index 0000000000..f7cae3780f --- /dev/null +++ b/src/modules/SX126x/SX126x_LR_FHSS.cpp @@ -0,0 +1,392 @@ +#include "SX126x.h" +#include +#include +#if !RADIOLIB_EXCLUDE_SX126X + +/* + LR-FHSS implementation in this file is adapted from Setmech's LR-FHSS demo: + https://github.com/Lora-net/SWDM001/tree/master/lib/sx126x_driver + + Its SX126x driver is distributed under the Clear BSD License, + and to comply with its terms, it is reproduced below. + + The Clear BSD License + Copyright Semtech Corporation 2021. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the disclaimer + below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +// header interleaver +static const uint8_t LrFhssHeaderInterleaver[80] = { + 0, 18, 36, 54, 72, 4, 22, 40, + 58, 76, 8, 26, 44, 62, 12, 30, + 48, 66, 16, 34, 52, 70, 1, 19, + 37, 55, 73, 5, 23, 41, 59, 77, + 9, 27, 45, 63, 13, 31, 49, 67, + 17, 35, 53, 71, 2, 20, 38, 56, + 74, 6, 24, 42, 60, 78, 10, 28, + 46, 64, 14, 32, 50, 68, 3, 21, + 39, 57, 75, 7, 25, 43, 61, 79, + 11, 29, 47, 65, 15, 33, 51, 69, +}; + +int16_t SX126x::buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len, size_t* out_bits, size_t* out_hops) { + // perform payload whitening + uint8_t lfsr = 0xFF; + for(size_t i = 0; i < in_len; i++) { + uint8_t u = in[i] ^ lfsr; + + // we really shouldn't reuse the caller's memory in this way ... + // but since this is a private method it should be at least controlled, if not safe + out[i] = ((u & 0x0F) << 4 ) | ((u & 0xF0) >> 4); + lfsr = (lfsr << 1) | (((lfsr & 0x80) >> 7) ^ (((lfsr & 0x20) >> 5) ^ (((lfsr & 0x10) >> 4) ^ ((lfsr & 0x08) >> 3)))); + } + + // calculate the CRC-16 over the whitened data, looks like something custom + RadioLibCRCInstance.size = 16; + RadioLibCRCInstance.poly = 0x755B; + RadioLibCRCInstance.init = 0xFFFF; + RadioLibCRCInstance.out = 0x0000; + uint16_t crc16 = RadioLibCRCInstance.checksum(out, in_len); + + // add payload CRC + out[in_len] = (crc16 >> 8) & 0xFF; + out[in_len + 1] = crc16 & 0xFF; + out[in_len + 2] = 0; + + // encode the payload with CRC using convolutional coding with 1/3 rate into a temporary buffer + uint8_t tmp[RADIOLIB_SX126X_LR_FHSS_MAX_ENC_SIZE] = { 0 }; + size_t nb_bits = 0; + RadioLibConvCodeInstance.begin(3); + RadioLibConvCodeInstance.encode(out, 8 * (in_len + 2) + 6, tmp, &nb_bits); + memset(out, 0, RADIOLIB_SX126X_MAX_PACKET_LENGTH); + + // for rates other than the 1/3 base, puncture the code + if(this->lrFhssCr != RADIOLIB_SX126X_LR_FHSS_CR_1_3) { + uint32_t matrix_index = 0; + uint8_t matrix[15] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 }; + uint8_t matrix_len = 0; + switch(this->lrFhssCr) { + case RADIOLIB_SX126X_LR_FHSS_CR_5_6: + matrix_len = 15; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_2_3: + matrix_len = 6; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_2: + matrix_len = 3; + break; + } + + uint32_t j = 0; + for(uint32_t i = 0; i < nb_bits; i++) { + if(matrix[matrix_index]) { + if(TEST_BIT_IN_ARRAY_LSB(tmp, i)) { + SET_BIT_IN_ARRAY_LSB(out, j); + } else { + CLEAR_BIT_IN_ARRAY_LSB(out, j); + } + j++; + } + + if(++matrix_index == matrix_len) { + matrix_index = 0; + } + } + + nb_bits = j; + memcpy(tmp, out, (nb_bits + 7) / 8); + } + + // interleave the payload into output buffer + uint16_t step = 0; + while(step * step < nb_bits) { + // probably the silliest sqrt() I ever saw + step++; + } + + const uint16_t step_v = step >> 1; + step <<= 1; + + uint16_t pos = 0; + uint16_t st_idx = 0; + uint16_t st_idx_init = 0; + int16_t bits_left = nb_bits; + uint16_t out_row_index = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount; + + while(bits_left > 0) { + int16_t in_row_width = bits_left; + if(in_row_width > RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) { + in_row_width = RADIOLIB_SX126X_LR_FHSS_FRAG_BITS; + } + + // guard bits + CLEAR_BIT_IN_ARRAY_LSB(out, out_row_index); + CLEAR_BIT_IN_ARRAY_LSB(out, out_row_index + 1); + + for(int16_t j = 0; j < in_row_width; j++) { + // guard bit + if(TEST_BIT_IN_ARRAY_LSB(tmp, pos)) { + SET_BIT_IN_ARRAY_LSB(out, j + 2 + out_row_index); + } else { + CLEAR_BIT_IN_ARRAY_LSB(out, j + 2 + out_row_index); + } + + pos += step; + if(pos >= nb_bits) { + st_idx += step_v; + if(st_idx >= step) { + st_idx_init++; + st_idx = st_idx_init; + } + pos = st_idx; + } + } + + bits_left -= RADIOLIB_SX126X_LR_FHSS_FRAG_BITS; + out_row_index += 2 + in_row_width; + } + + nb_bits = out_row_index - RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount; + + // build the header + uint8_t raw_header[RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2]; + raw_header[0] = in_len; + raw_header[1] = (this->lrFhssCr << 3) | ((uint8_t)this->lrFhssGridNonFcc << 2) | + (RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED << 1) | (this->lrFhssBw >> 3); + raw_header[2] = ((this->lrFhssBw & 0x07) << 5) | (this->lrFhssHopSeqId >> 4); + raw_header[3] = ((this->lrFhssHopSeqId & 0x000F) << 4); + + // CRC-8 used seems to based on 8H2F, but without final XOR + RadioLibCRCInstance.size = 8; + RadioLibCRCInstance.poly = 0x2F; + RadioLibCRCInstance.init = 0xFF; + RadioLibCRCInstance.out = 0x00; + + uint16_t header_offset = 0; + for(size_t i = 0; i < this->lrFhssHdrCount; i++) { + // insert index and calculate the header CRC + raw_header[3] = (raw_header[3] & ~0x0C) | ((this->lrFhssHdrCount - i - 1) << 2); + raw_header[4] = RadioLibCRCInstance.checksum(raw_header, (RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2 - 1)); + + // convolutional encode + uint8_t coded_header[RADIOLIB_SX126X_LR_FHSS_HDR_BYTES] = { 0 }; + RadioLibConvCodeInstance.begin(2); + RadioLibConvCodeInstance.encode(raw_header, 8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2, coded_header); + // tail-biting seems to just do this twice ...? + RadioLibConvCodeInstance.encode(raw_header, 8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2, coded_header); + + // clear guard bits + CLEAR_BIT_IN_ARRAY_LSB(out, header_offset); + CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 1); + + // interleave the header directly to the physical payload buffer + for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2); j++) { + if(TEST_BIT_IN_ARRAY_LSB(coded_header, LrFhssHeaderInterleaver[j])) { + SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + j); + } else { + CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + j); + } + } + for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2); j++) { + if(TEST_BIT_IN_ARRAY_LSB(coded_header, LrFhssHeaderInterleaver[(8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j])) { + SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES) + j); + } else { + CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES) + j); + } + } + + // copy the sync word to the physical payload buffer + for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES); j++) { + if(TEST_BIT_IN_ARRAY_LSB(this->lrFhssSyncWord, j)) { + SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j); + } else { + CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j); + } + } + + header_offset += RADIOLIB_SX126X_LR_FHSS_HEADER_BITS; + } + + // calculate the number of hops and total number of bits + uint16_t length_bits = (in_len + 2) * 8 + 6; + switch(this->lrFhssCr) { + case RADIOLIB_SX126X_LR_FHSS_CR_5_6: + length_bits = ( ( length_bits * 6 ) + 4 ) / 5; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_2_3: + length_bits = length_bits * 3 / 2; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_2: + length_bits = length_bits * 2; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_3: + length_bits = length_bits * 3; + break; + } + + *out_hops = (length_bits + 47) / 48 + this->lrFhssHdrCount; + + // calculate total number of payload bits, after breaking into blocks + uint16_t payload_bits = length_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS; + uint16_t last_block_bits = length_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS; + if(last_block_bits > 0) { + // add the 2 guard bits for the last block + the actual remaining payload bits + payload_bits += last_block_bits + 2; + } + + *out_bits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + payload_bits; + *out_len = (*out_bits + 7) / 8; + + return(RADIOLIB_ERR_NONE); +} + +int16_t SX126x::resetLRFHSS() { + // initialize hopping configuration + const uint16_t numChan[] = { 80, 176, 280, 376, 688, 792, 1480, 1584, 3120, 3224 }; + + // LFSR polynomials for different ranges of lrFhssNgrid + const uint8_t lfsrPoly1[] = { 33, 45, 48, 51, 54, 57 }; + const uint8_t lfsrPoly2[] = { 65, 68, 71, 72 }; + const uint8_t lfsrPoly3[] = { 142, 149 }; + + uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52; + this->lrFhssNgrid = numChan[this->lrFhssBw] / nb_channel_in_grid; + this->lrFhssLfsrState = 6; + switch(this->lrFhssNgrid) { + case 10: + case 22: + case 28: + case 30: + case 35: + case 47: + this->lrFhssPoly = lfsrPoly1[this->lrFhssHopSeqId >> 6]; + this->lrFhssSeed = this->lrFhssHopSeqId & 0x3F; + if(this->lrFhssHopSeqId >= 384) { + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + break; + + case 60: + case 62: + this->lrFhssLfsrState = 56; + this->lrFhssPoly = lfsrPoly1[this->lrFhssHopSeqId >> 6]; + this->lrFhssSeed = this->lrFhssHopSeqId & 0x3F; + if(this->lrFhssHopSeqId >= 384) { + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + break; + + case 86: + case 99: + this->lrFhssPoly = lfsrPoly2[this->lrFhssHopSeqId >> 7]; + this->lrFhssSeed = this->lrFhssHopSeqId & 0x7F; + break; + + case 185: + case 198: + this->lrFhssPoly = lfsrPoly3[this->lrFhssHopSeqId >> 8]; + this->lrFhssSeed = this->lrFhssHopSeqId & 0xFF; + break; + + case 390: + case 403: + this->lrFhssPoly = 264; + this->lrFhssSeed = this->lrFhssHopSeqId; + break; + + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + return(RADIOLIB_ERR_NONE); +} + +uint16_t SX126x::stepLRFHSS() { + uint16_t hop; + do { + uint16_t lsb = this->lrFhssLfsrState & 1; + this->lrFhssLfsrState >>= 1; + if(lsb) { + this->lrFhssLfsrState ^= this->lrFhssPoly; + } + hop = this->lrFhssSeed; + if(hop != this->lrFhssLfsrState) { + hop ^= this->lrFhssLfsrState; + } + } while(hop > this->lrFhssNgrid); + return(hop); +} + +int16_t SX126x::setLRFHSSHop(uint8_t index) { + if(!this->lrFhssFrameHopsRem) { + return(RADIOLIB_ERR_NONE); + } + + uint16_t hop = stepLRFHSS(); + int16_t freq_table = hop - 1; + if(freq_table >= (int16_t)(this->lrFhssNgrid >> 1)) { + freq_table -= this->lrFhssNgrid; + } + + uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52; + uint32_t grid_offset = (1 + (this->lrFhssNgrid % 2)) * (nb_channel_in_grid / 2); + uint32_t grid_in_pll_steps = this->lrFhssGridNonFcc ? 4096 : 26624; + uint32_t freq_raw = this->frf - freq_table * grid_in_pll_steps - grid_offset * 512; + + if((this->lrFhssHopNum < this->lrFhssHdrCount)) { + if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) { + freq_raw += 256; + } + } + + uint8_t frq[4] = { (uint8_t)((freq_raw >> 24) & 0xFF), (uint8_t)((freq_raw >> 16) & 0xFF), (uint8_t)((freq_raw >> 8) & 0xFF), (uint8_t)(freq_raw & 0xFF) }; + int16_t state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(index), frq, sizeof(freq_raw)); + RADIOLIB_ASSERT(state); + + // (LR_FHSS_HEADER_BITS + pulse_shape_compensation) symbols on first sync_word, LR_FHSS_HEADER_BITS on + // next sync_words, LR_FHSS_BLOCK_BITS on payload + uint16_t numSymbols = RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS; + if(index == 0) { + numSymbols = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS + 1; // the +1 is "pulse_shape_compensation", but it's constant in the demo + } else if(index < this->lrFhssHdrCount) { + numSymbols = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS; + } else if(this->lrFhssFrameBitsRem < RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS) { + numSymbols = this->lrFhssFrameBitsRem; + } + + // write hop length in symbols + uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) }; + state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(index), sym, sizeof(uint16_t)); + RADIOLIB_ASSERT(state); + + this->lrFhssFrameBitsRem -= numSymbols; + this->lrFhssFrameHopsRem--; + this->lrFhssHopNum++; + return(RADIOLIB_ERR_NONE); +} + +#endif diff --git a/src/utils/FEC.cpp b/src/utils/FEC.cpp index 515014d0ab..7aadf4ab7e 100644 --- a/src/utils/FEC.cpp +++ b/src/utils/FEC.cpp @@ -307,3 +307,59 @@ uint32_t RadioLibBCH::encode(uint32_t dataword) { } RadioLibBCH RadioLibBCHInstance; + +RadioLibConvCode::RadioLibConvCode() { + +} + +void RadioLibConvCode::begin(uint8_t rt) { + this->enc_state = 0; + this->rate = rt; +} + +int16_t RadioLibConvCode::encode(const uint8_t* in, size_t in_bits, uint8_t* out, size_t* out_bits) { + if(!in || !out) { + return(RADIOLIB_ERR_UNKNOWN); + } + + size_t ind_bit; + uint16_t data_out_bitcount = 0; + uint32_t bin_out_word = 0; + + // iterate over the provided bits + for(ind_bit = 0; ind_bit < in_bits; ind_bit++) { + uint8_t cur_bit = GET_BIT_IN_ARRAY_LSB(in, ind_bit); + const uint32_t* lut_ptr = (this->rate == 2) ? ConvCodeTable1_2 : ConvCodeTable1_3; + uint8_t word_pos = this->enc_state / 4; + uint8_t byte_pos = (3 - (this->enc_state % 4)) * 8; + uint8_t nibble_pos = (1 - cur_bit) * 4; + uint8_t g1g0 = (lut_ptr[word_pos] >> (byte_pos + nibble_pos)) & 0x0F; + + uint8_t mod = this->rate == 2 ? 16 : 64; + this->enc_state = (this->enc_state * 2 + cur_bit) % mod; + bin_out_word |= (g1g0 << ((7 - (ind_bit % 8)) * this->rate)); + if(ind_bit % 8 == 7) { + if(this->rate == 3) { + *out++ = (uint8_t)(bin_out_word >> 16); + } + *out++ = (uint8_t)(bin_out_word >> 8); + *out++ = (uint8_t)bin_out_word; + bin_out_word = 0; + } + data_out_bitcount += this->rate; + } + + if(ind_bit % 8) { + if(this->rate == 3) { + *out++ = (uint8_t)(bin_out_word >> 16); + } + *out++ = (uint8_t)(bin_out_word >> 8); + *out++ = (uint8_t)bin_out_word; + } + + if(out_bits) { *out_bits = data_out_bitcount; } + + return(RADIOLIB_ERR_NONE); +} + +RadioLibConvCode RadioLibConvCodeInstance; diff --git a/src/utils/FEC.h b/src/utils/FEC.h index cf201b1148..788b0b52e9 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -31,7 +31,7 @@ class RadioLibBCH { RadioLibBCH(); /*! - \brief Default detructor. + \brief Default destructor. */ ~RadioLibBCH(); @@ -76,6 +76,92 @@ extern RadioLibBCH RadioLibBCHInstance; #define CLEAR_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] &= ~(1 << ((k)%8)) ) #define TEST_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] & (1 << ((k)%8)) ) #define GET_BIT_IN_ARRAY_MSB(A, k) ( (A[((k)/8)] & (1 << ((k)%8))) ? 1 : 0 ) +#define SET_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] |= (1 << (7 - ((k)%8))) ) +#define CLEAR_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] &= ~(1 << (7 - ((k)%8))) ) +#define TEST_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] & (1 << (7 - ((k)%8))) ) +#define GET_BIT_IN_ARRAY_LSB(A, k) ( (A[((k)/8)] & (1 << (7 - ((k)%8)))) ? 1 : 0 ) +/*! + \class RadioLibConvCode + \brief Class to perform convolutional coding wtih variable rates. + Only 1/2 and 1/3 rate is currently supported. + + Copnvolutional coder implementation in this class is adapted from Setmech's LR-FHSS demo: + https://github.com/Lora-net/SWDM001/tree/master/lib/sx126x_driver + + Its SX126x driver is distributed under the Clear BSD License, + and to comply with its terms, it is reproduced below. + + The Clear BSD License + Copyright Semtech Corporation 2021. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the disclaimer + below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +class RadioLibConvCode { + public: + /*! + \brief Default constructor. + */ + RadioLibConvCode(); + + /*! + \brief Initialization method. + \param rt Encoding rate denominator (1/x). Only 1/2 and 1/3 encoding is currently supported. + */ + void begin(uint8_t rt); + + /*! + \brief Encoding method. + \param in Input buffer (a byte array). + \param in_bits Input length in bits. + \param out Output buffer (a byte array). It is up to the caller + to ensure the buffer is large enough to fit the encoded data! + \param out_bits Pointer to a variable to save the number of encoded bits. + Ignored if set to NULL. + \returns \ref status_codes + */ + int16_t encode(const uint8_t* in, size_t in_bits, uint8_t* out, size_t* out_bits = NULL); + + private: + uint8_t enc_state = 0; + uint8_t rate = 0; +}; + +// each 32-bit word stores 8 values, one per each nibble +static const uint32_t ConvCodeTable1_3[16] = { + 0x07347043, 0x61521625, 0x16256152, 0x70430734, + 0x43703407, 0x25165261, 0x52612516, 0x34074370, + 0x70430734, 0x16256152, 0x61521625, 0x07347043, + 0x34074370, 0x52612516, 0x25165261, 0x43703407, +}; + +static const uint32_t ConvCodeTable1_2[4] = { + 0x03122130, 0x21300312, 0x30211203, 0x12033021, +}; + +extern RadioLibConvCode RadioLibConvCodeInstance; #endif From 9db98f2ab4b28b6ad4559398414123c07ddead5c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 7 Oct 2024 23:17:41 +0200 Subject: [PATCH 1285/1848] [LoRaWAN] Collection of fixes (also fixes #1254) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 14 +++++++++----- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a4c6040418..344d9450b6 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -183,11 +183,12 @@ int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, u eventUp->nbTrans = trans; } + #if !RADIOLIB_STATIC_ONLY + delete[] uplinkMsg; + #endif + // if a hardware error occurred, return if(state < RADIOLIB_ERR_NONE) { - #if !RADIOLIB_STATIC_ONLY - delete[] uplinkMsg; - #endif return(state); } @@ -938,6 +939,9 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->devNonce += 1; LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); + // set the Time on Air of the JoinRequest + this->lastToA = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; + // configure Rx1 and Rx2 delay for JoinAccept message - these are re-configured once a valid JoinAccept is received this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; this->rxDelays[2] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; @@ -1481,7 +1485,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08X, got 0x%08X", this->devAddr, addr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08lX, got 0x%08lX", this->devAddr, addr); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -3197,7 +3201,7 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { // calculate the expected value and compare uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); if(micCalculated != micReceived) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08x, got %08x", micCalculated, micReceived); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08lx, got %08lx", micCalculated, micReceived); return(false); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 723c4624ba..6ff198dfef 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -605,7 +605,7 @@ class LoRaWANNode { \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled). \returns \ref status_codes */ - int16_t activateABP(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + virtual int16_t activateABP(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); /*! \brief Whether there is an ongoing session active */ bool isActivated(); From bce4d9171522d0610ffd812f7d3b0b276677c28f Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 7 Oct 2024 23:29:14 +0200 Subject: [PATCH 1286/1848] [LoRaWAN] Fix type format --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 344d9450b6..cd71f85699 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1485,7 +1485,8 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); if(addr != this->devAddr) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08lX, got 0x%08lX", this->devAddr, addr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08lX, got 0x%08lX", + (unsigned long)this->devAddr, (unsigned long)addr); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -3201,7 +3202,8 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) { // calculate the expected value and compare uint32_t micCalculated = generateMIC(msg, len - sizeof(uint32_t), key); if(micCalculated != micReceived) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08lx, got %08lx", micCalculated, micReceived); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("MIC mismatch, expected %08lx, got %08lx", + (unsigned long)micCalculated, (unsigned long)micReceived); return(false); } From a7feeee1e03900cbf258c54abce182b05d38b800 Mon Sep 17 00:00:00 2001 From: Volker Christian Date: Wed, 9 Oct 2024 20:32:50 +0200 Subject: [PATCH 1287/1848] [SX1276, LoRaWAN] Fix confusing return value in LoRaWAN::processJoinAccept (#1262) The error RADIOLIB_ERR_LORA_HEADER_DAMAGED board returned fromreadData(...) and signaled from a SX1276 is in fact correctly ignored but the state variable is not corrected. This confuses the caller due to the wrongly returned state value RADIOLIB_ERR_LORA_HEADER_DAMAGED. Change: Clear state also. --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index cd71f85699..5e994c672c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -688,6 +688,8 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { // we can ignore that error if(state != RADIOLIB_ERR_LORA_HEADER_DAMAGED) { RADIOLIB_ASSERT(state); + } else { + state = RADIOLIB_ERR_NONE; } // check reply message type From aecef283807d5e5fb0e88bbf4dba41b25bd75cc4 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 10 Oct 2024 15:33:19 +0200 Subject: [PATCH 1288/1848] [LoRaWAN] Move templates to .h to prevent linker errors --- src/protocols/LoRaWAN/LoRaWAN.cpp | 26 -------------------------- src/protocols/LoRaWAN/LoRaWAN.h | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 5e994c672c..418fd263d4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -3390,30 +3390,4 @@ uint16_t LoRaWANNode::checkSum16(const uint8_t *key, uint16_t keyLen) { return(checkSum); } -template -T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { - uint8_t* buffPtr = buff; - size_t targetSize = sizeof(T); - if(size != 0) { - targetSize = size; - } - T res = 0; - for(size_t i = 0; i < targetSize; i++) { - res |= (uint32_t)(*(buffPtr++)) << 8*i; - } - return(res); -} - -template -void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { - uint8_t* buffPtr = buff; - size_t targetSize = sizeof(T); - if(size != 0) { - targetSize = size; - } - for(size_t i = 0; i < targetSize; i++) { - *(buffPtr++) = val >> 8*i; - } -} - #endif diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 6ff198dfef..da00dcfe2f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1127,4 +1127,30 @@ class LoRaWANNode { static void hton(uint8_t* buff, T val, size_t size = 0); }; +template +T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { + uint8_t* buffPtr = buff; + size_t targetSize = sizeof(T); + if(size != 0) { + targetSize = size; + } + T res = 0; + for(size_t i = 0; i < targetSize; i++) { + res |= (uint32_t)(*(buffPtr++)) << 8*i; + } + return(res); +} + +template +void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) { + uint8_t* buffPtr = buff; + size_t targetSize = sizeof(T); + if(size != 0) { + targetSize = size; + } + for(size_t i = 0; i < targetSize; i++) { + *(buffPtr++) = val >> 8*i; + } +} + #endif From d9ea40032fb8c1c11e672be1220d0c4d711c057a Mon Sep 17 00:00:00 2001 From: Volker Christian Date: Fri, 11 Oct 2024 20:08:04 +0200 Subject: [PATCH 1289/1848] [LoRaWAN] Just for convenience: Add a frmPending field in --- src/protocols/LoRaWAN/LoRaWAN.cpp | 1 + src/protocols/LoRaWAN/LoRaWAN.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 5e994c672c..26471f494b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1807,6 +1807,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e event->dir = RADIOLIB_LORAWAN_DOWNLINK; event->confirmed = isConfirmedDown; event->confirming = isConfirmingUp; + event->frmPending = (downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING) != 0; event->datarate = this->channels[RADIOLIB_LORAWAN_DOWNLINK].dr; event->freq = channels[event->dir].freq / 10000.0; event->power = this->txPowerMax - this->txPowerSteps * 2; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 6ff198dfef..d3c5f71504 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -504,6 +504,9 @@ struct LoRaWANEvent_t { (e.g., server downlink reply to confirmed uplink sent by user application)*/ bool confirming; + /*! \brief Whether further downlink messages are pending on the server side. */ + bool frmPending; + /*! \brief Datarate */ uint8_t datarate; From e9b6e27739007acdc890d48fef210277216feb36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Oct 2024 14:15:05 +0100 Subject: [PATCH 1290/1848] [SX126x] Fix FSK addresses on transmission (#1268) --- src/modules/SX126x/SX126x.cpp | 30 ++++++++++++++++++++++-------- src/modules/SX126x/SX126x.h | 5 +++-- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 7109d6d98d..63e37939bf 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -509,9 +509,6 @@ void SX126x::clearChannelScanAction() { } int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { - // suppress unused variable warning - (void)addr; - // check packet length if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); @@ -527,10 +524,19 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); + + // address is taken from the register + if(this->addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) { + RADIOLIB_ASSERT(state); + state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &addr, 1); + } + } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { return(RADIOLIB_ERR_UNKNOWN); + } RADIOLIB_ASSERT(state); @@ -617,7 +623,14 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t SX126x::finishTransmit() { // clear interrupt flags - clearIrqStatus(); + int16_t state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // restore the original node address + if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &this->nodeAddr, 1); + RADIOLIB_ASSERT(state); + } // set mode to standby to disable transmitter/RF switch return(standby()); @@ -739,14 +752,14 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { // if that's the case, the first call will return "SPI command timeout error" // check the IRQ to be sure this really originated from timeout event int16_t state = this->mod->SPIcheckStream(); - if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (getIrqFlags() & RADIOLIB_SX126X_IRQ_TIMEOUT)) { + uint16_t irq = getIrqFlags(); + if((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (irq & RADIOLIB_SX126X_IRQ_TIMEOUT)) { // this is definitely Rx timeout return(RADIOLIB_ERR_RX_TIMEOUT); } RADIOLIB_ASSERT(state); // check integrity CRC - uint16_t irq = getIrqFlags(); int16_t crcState = RADIOLIB_ERR_NONE; // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet) if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || ((irq & RADIOLIB_SX126X_IRQ_HEADER_ERR) && !(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID))) { @@ -1220,7 +1233,7 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { return(setSyncWord(syncWord, bytesLen)); } -int16_t SX126x::setNodeAddress(uint8_t nodeAddr) { +int16_t SX126x::setNodeAddress(uint8_t addr) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -1232,7 +1245,8 @@ int16_t SX126x::setNodeAddress(uint8_t nodeAddr) { RADIOLIB_ASSERT(state); // set node address - state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &nodeAddr, 1); + this->nodeAddr = addr; + state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &addr, 1); return(state); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index a64356aaa0..766e02087c 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -901,10 +901,10 @@ class SX126x: public PhysicalLayer { /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. - \param nodeAddr Node address to be set. + \param addr Node address to be set. \returns \ref status_codes */ - int16_t setNodeAddress(uint8_t nodeAddr); + int16_t setNodeAddress(uint8_t addr); /*! \brief Sets broadcast address. Calling this method will also enable address @@ -1263,6 +1263,7 @@ class SX126x: public PhysicalLayer { uint8_t rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; uint16_t preambleLengthFSK = 0; float rxBandwidthKhz = 0; + uint8_t nodeAddr = 0; float dataRateMeasured = 0; From 16504803d1d5ccd4ac08627bf6d9c5e808f1ff61 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 12 Oct 2024 14:15:23 +0100 Subject: [PATCH 1291/1848] [SX127x] Fix FSK address handling --- src/modules/SX127x/SX127x.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 036fce836a..55138aa1e2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -605,16 +605,18 @@ int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); } - // set packet length - if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); - } - - // check address filtering + // set packet length - increased by 1 when address filter is enabled uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); - if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); + if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len + 1); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); + } else { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); + } + } + } // write packet to FIFO From 363339144246bef30cc36653e0fa92cda9e279ce Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 14 Oct 2024 12:29:42 +0200 Subject: [PATCH 1292/1848] [LoRaWAN] Fix missing us-to-ms divisor --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 418fd263d4..44cb43154c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1402,7 +1402,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne if(this->TS011) { maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater } - RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13); // mandatory FHDR is 12/13 bytes + RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13) / 1000; // mandatory FHDR is 12/13 bytes bool downlinkComplete = true; // wait for the DIO to fire indicating a downlink is received From 56ae9ad76b1e91b6a0a95561c9b0670198268d27 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 14 Oct 2024 16:37:19 +0100 Subject: [PATCH 1293/1848] [SX126x] Fix second call to startReceive breaking reception (#1272) --- src/modules/SX126x/SX126x.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 63e37939bf..9c17cfede6 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -720,11 +720,15 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ } int16_t SX126x::startReceiveCommon(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) { + // ensure we are in standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + // set DIO mapping if(timeout != RADIOLIB_SX126X_RX_TIMEOUT_INF) { irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); } - int16_t state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask)); + state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask)); RADIOLIB_ASSERT(state); // set buffer pointers From 710a1540b58e491172497c3c69c8f58fc2ca7e65 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 14 Oct 2024 16:38:57 +0100 Subject: [PATCH 1294/1848] [STM32WLx] Update Rx interrupt example (#1272) --- .../STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index a1da096873..1fb31ddbe2 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -154,8 +154,5 @@ void loop() { Serial.println(state); } - - // put module back to listen mode - radio.startReceive(); } } From 00699ce2255ede99d233501484697d315f77bfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Fri, 18 Oct 2024 16:50:36 +0200 Subject: [PATCH 1295/1848] [LR11x0] GNSS support (#1275) * [LR11x0] Added WIP GNSS control * [LR11x0] Added almanac update * [LR11x0] Added almanac update example * [LR11x0] Add missing memory deallocation * [LR11x0] Fix underflow in delay until subframe * [LR11x0] Remove pin mapping from example * [LR11x0] Finish rework of the GNSS API * [LR11x0] Added position and satellite examples * [LR11x0] Fix result member in example * Added LR11x0 GNSS keywords * [LR11x0] Fix typo in macro name * [LR11x0] Print scan failed in example * [LR11x0] Added GNSS abort --- .../LR11x0_GNSS_Almanac_Update.ino | 151 +++++++++ .../LR11x0_GNSS_Autonomous_Position.ino | 103 ++++++ .../LR11x0_GNSS_Satellites.ino | 102 ++++++ keywords.txt | 19 ++ src/Module.cpp | 26 +- src/TypeDef.h | 21 ++ src/modules/LR11x0/LR11x0.cpp | 307 +++++++++++++++++- src/modules/LR11x0/LR11x0.h | 212 +++++++++++- 8 files changed, 925 insertions(+), 16 deletions(-) create mode 100644 examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino create mode 100644 examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino create mode 100644 examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino diff --git a/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino b/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino new file mode 100644 index 0000000000..964e865f8e --- /dev/null +++ b/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino @@ -0,0 +1,151 @@ +/* + RadioLib LR11x0 GNSS Almanac Update Example + + This example updates the LR11x0 GNSS almanac. + Almanac is a database of orbital predictions of + GNSS satellites, which allows the module to predict + when different satellites will appear in the sky, + and frequency of their signal. + + Up-to-date almanac is necessary for operation! + After an update, data will remain valid for 30 days. + All GNSS examples require at least limited + visibility of the sky! + + NOTE: This example will only work for LR11x0 devices + with sufficiently recent firmware! + LR1110: 4.1 + LR1120: 2.1 + If your device firmware reports older firmware, + update it using the LR11x0_Firmware_Update example. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// structure to save information about the GNSS almanac +LR11x0GnssAlmanacStatus_t almStatus; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.beginGNSS(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // check the firmware version + Serial.print(F("[LR1110] Checking firmware version ... ")); + state = radio.isGnssScanCapable(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("check passed!")); + } else { + Serial.println(F("check failed, firmware update needed.")); + while (true) { delay(10); } + } + + // run GNSS scans until we get at least the time + // NOTE: Depending on visibility of satellites, + // this may take multiple attempts! + while(true) { + // run GNSS scan + Serial.print(F("[LR1110] Running GNSS scan ... ")); + state = radio.gnssScan(NULL); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // check almanac status + Serial.print(F("[LR1110] Checking GNSS almanac ... ")); + state = radio.getGnssAlmanacStatus(&almStatus); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // we have the status, check if we have demodulated time + if(almStatus.gps.status < RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE) { + Serial.println(F("time unknown, another scan needed.")); + + } else if(almStatus.gps.numUpdateNeeded > 0) { + Serial.print(almStatus.gps.numUpdateNeeded); + Serial.println(F(" satellites out-of-date.")); + break; + + } else { + Serial.println(F("no update needed!")); + while (true) { delay(10); } + + } + } +} + +void loop() { + // wait until almanac data is available in the signal + // multiple attempts are needed for this + Serial.print(F("[LR1110] Waiting for subframe ... ")); + int state = radio.gnssDelayUntilSubframe(&almStatus, RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS); + if(state == RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE) { + Serial.println(F("not enough time left.")); + + // wait until the next update window + delay(2000); + + } else { + Serial.println(F("done!")); + + // we have enough time to start the update + Serial.print(F("[LR1110] Starting update ... ")); + state = radio.updateGnssAlmanac(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("failed, code ")); + Serial.println(state); + } else { + Serial.println(F("done!")); + } + + } + + // check whether another update is needed + Serial.print(F("[LR1110] Checking GNSS almanac ... ")); + state = radio.getGnssAlmanacStatus(&almStatus); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // check if we have completed the update + if(almStatus.gps.numUpdateNeeded == 0) { + Serial.println(F("all satellites up-to-date!")); + while (true) { delay(10); } + } else { + Serial.print(almStatus.gps.numUpdateNeeded); + Serial.println(F(" satellites out-of-date.")); + } + + // wait a bit before the next update attempt + delay(1000); + +} diff --git a/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino b/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino new file mode 100644 index 0000000000..84a40aa07f --- /dev/null +++ b/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino @@ -0,0 +1,103 @@ +/* + RadioLib LR11x0 GNSS Autonomous Position Example + + This example performs GNSS scans and calculates + position of the device using autonomous mode. + In this mode, scan data does not need to be uploaded + to LoRaCloud, however, it requires up-to-date almanac + data. Run the LR11x0_Almanac_Update example to update + the device almanac. + + NOTE: This example will only work for LR11x0 devices + with sufficiently recent firmware! + LR1110: 4.1 + LR1120: 2.1 + If your device firmware reports older firmware, + update it using the LR11x0_Firmware_Update example. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// structure to save information about the GNSS scan result +LR11x0GnssResult_t gnssResult; + +// structure to save information about the calculated GNSS position +LR11x0GnssPosition_t gnssPosition; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.beginGNSS(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // check the firmware version + Serial.print(F("[LR1110] Checking firmware version ... ")); + state = radio.isGnssScanCapable(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("check passed!")); + } else { + Serial.println(F("check failed, firmware update needed.")); + while (true) { delay(10); } + } + + Serial.println(F("Scan result\t| Latitude\t| Longitude\t| Accuracy\t| Number of satellites")); +} + +void loop() { + // run GNSS scan + int state = radio.gnssScan(&gnssResult); + if(state == RADIOLIB_ERR_NONE) { + // success! + Serial.print(gnssResult.demodStat); Serial.print("\t\t| "); + + // get the actual data + state = radio.getGnssPosition(&gnssPosition); + if(state == RADIOLIB_ERR_NONE) { + // print the position + Serial.print(gnssPosition.latitude, 6); + Serial.print("\t| "); + Serial.print(gnssPosition.longitude, 6); + Serial.print("\t| "); + Serial.print(gnssPosition.accuracy); + Serial.print("\t\t| "); + Serial.println(gnssPosition.numSatsUsed); + + } else { + Serial.print(F("Failed to read result, code ")); + Serial.print(state); + Serial.print(F(" (solver error ")); + Serial.print(RADIOLIB_GET_GNSS_SOLVER_ERROR(state)); + Serial.println(F(")")); + } + + } else { + Serial.print(F("Scan failed, code ")); + Serial.print(state); + Serial.print(F(" (demodulator error ")); + Serial.print(RADIOLIB_GET_GNSS_DEMOD_ERROR(state)); + Serial.println(F(")")); + + } + + // wait a bit before the next scan + delay(1000); +} diff --git a/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino b/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino new file mode 100644 index 0000000000..4104a23ffc --- /dev/null +++ b/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino @@ -0,0 +1,102 @@ +/* + RadioLib LR11x0 GNSS Satellites Example + + This example performs GNSS scans and shows the satellites + currently in view. It is mostly useful to verify + visibility and antenna setup. + + NOTE: This example will only work for LR11x0 devices + with sufficiently recent firmware! + LR1110: 4.1 + LR1120: 2.1 + If your device firmware reports older firmware, + update it using the LR11x0_Firmware_Update example. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---wifi-scan + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR1110 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR1110 radio = new Module(10, 2, 3, 9); + +// structure to save information about the GNSS scan result +LR11x0GnssResult_t gnssResult; + +void setup() { + Serial.begin(9600); + + // initialize LR1110 with default settings + Serial.print(F("[LR1110] Initializing ... ")); + int state = radio.beginGNSS(RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // check the firmware version + Serial.print(F("[LR1110] Checking firmware version ... ")); + state = radio.isGnssScanCapable(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("check passed!")); + } else { + Serial.println(F("check failed, firmware update needed.")); + while (true) { delay(10); } + } +} + +void loop() { + Serial.print(F("[LR1110] Running GNSS scan ... ")); + int state = radio.gnssScan(&gnssResult); + if(state != RADIOLIB_ERR_NONE) { + // some error occurred + Serial.print(F("failed, code ")); + Serial.print(state); + Serial.print(F(" (demodulator error ")); + Serial.print(RADIOLIB_GET_GNSS_DEMOD_ERROR(state)); + Serial.println(F(")")); + + } else { + Serial.println(F("success!")); + + // print the table header + Serial.print(F("[LR1110] Detected ")); + Serial.print(gnssResult.numSatsDet); + Serial.println(F(" satellite(s):")); + Serial.println(F(" # | ID | C/N0 [dB]\t| Doppler [Hz]")); + + // read all results at once + LR11x0GnssSatellite_t satellites[32]; + state = radio.getGnssSatellites(satellites, gnssResult.numSatsDet); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("Failed to read results, code ")); + Serial.println(state); + } else { + // print all the results + for(int i = 0; i < gnssResult.numSatsDet; i++) { + if(i < 10) { Serial.print(" "); } Serial.print(i); Serial.print(" | "); + Serial.print(satellites[i].svId); Serial.print(" | "); + Serial.print(satellites[i].c_n0); Serial.print("\t\t| "); + Serial.println(satellites[i].doppler); + + } + + } + + } + + // wait for a second before scanning again + delay(1000); +} diff --git a/keywords.txt b/keywords.txt index b22dbebd68..c5fd90b5ff 100644 --- a/keywords.txt +++ b/keywords.txt @@ -100,6 +100,11 @@ LR11x0WifiResult_t KEYWORD1 LR11x0WifiResultFull_t KEYWORD1 LR11x0WifiResultExtended_t KEYWORD1 LR11x0VersionInfo_t KEYWORD1 +LR11x0GnssResult_t KEYWORD1 +LR11x0GnssPosition_t KEYWORD1 +LR11x0GnssSatellite_t KEYWORD1 +LR11x0GnssAlmanacStatusPart_t KEYWORD1 +LR11x0GnssAlmanacStatus_t KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -261,6 +266,14 @@ setWiFiScanAction KEYWORD2 clearWiFiScanAction KEYWORD2 getVersionInfo KEYWORD2 updateFirmware KEYWORD2 +beginGNSS KEYWORD2 +isGnssScanCapable KEYWORD2 +gnssScan KEYWORD2 +getGnssAlmanacStatus KEYWORD2 +gnssDelayUntilSubframe KEYWORD2 +updateGnssAlmanac KEYWORD2 +getGnssPosition KEYWORD2 +getGnssSatellites KEYWORD2 # RTTY idle KEYWORD2 @@ -473,6 +486,12 @@ RADIOLIB_ERR_SESSION_DISCARDED LITERAL1 RADIOLIB_ERR_INVALID_MODE LITERAL1 RADIOLIB_ERR_INVALID_WIFI_TYPE LITERAL1 +RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE LITERAL1 +RADIOLIB_GET_GNSS_DEMOD_ERROR LITERAL1 +RADIOLIB_GET_GNSS_SOLVER_ERROR LITERAL1 +RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS LITERAL1 +RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU LITERAL1 +RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE LITERAL1 RADIOLIB_LR1110_FIRMWARE_IN_RAM LITERAL1 RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LITERAL1 diff --git a/src/Module.cpp b/src/Module.cpp index 7b78f3f13c..30d38b0352 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -339,18 +339,20 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write } // ensure GPIO is low - if(this->gpioPin == RADIOLIB_NC) { - this->hal->delay(50); - } else { - RadioLibTime_t start = this->hal->millis(); - while(this->hal->digitalRead(this->gpioPin)) { - this->hal->yield(); - if(this->hal->millis() - start >= this->spiConfig.timeout) { - RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); - #if !RADIOLIB_STATIC_ONLY - delete[] buffOut; - #endif - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + if(waitForGpio) { + if(this->gpioPin == RADIOLIB_NC) { + this->hal->delay(50); + } else { + RadioLibTime_t start = this->hal->millis(); + while(this->hal->digitalRead(this->gpioPin)) { + this->hal->yield(); + if(this->hal->millis() - start >= this->spiConfig.timeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); + #if !RADIOLIB_STATIC_ONLY + delete[] buffOut; + #endif + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } } } } diff --git a/src/TypeDef.h b/src/TypeDef.h index 4c9538661b..a252568564 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -605,6 +605,27 @@ */ #define RADIOLIB_ERR_INVALID_WIFI_TYPE (-1200) +/*! + \brief GNSS subframe not available in the next 2.3 seconds. +*/ +#define RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE (-1201) + +/*! + \brief Offset of GNSS demodulator errors. + See LR11x0 datasheet for details on the actual demodulator error +*/ +#define RADIOLIB_ERR_GNSS_DEMOD_OFFSET (-1210) +#define RADIOLIB_ERR_GNSS_DEMOD(X) (RADIOLIB_ERR_GNSS_DEMOD_OFFSET + (X)) +#define RADIOLIB_GET_GNSS_DEMOD_ERROR(X) ((X) - RADIOLIB_ERR_GNSS_DEMOD_OFFSET) + +/*! + \brief GNSS solver errors. + See LR11x0 datasheet for details on the actual solver error +*/ +#define RADIOLIB_ERR_GNSS_SOLVER_OFFSET (-1230) +#define RADIOLIB_ERR_GNSS_SOLVER(X) (RADIOLIB_ERR_GNSS_SOLVER_OFFSET - (X)) +#define RADIOLIB_GET_GNSS_SOLVER_ERROR(X) (-((X) - RADIOLIB_ERR_GNSS_SOLVER_OFFSET)) + /*! \} */ diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 70da0d3516..ee2e4b1c34 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -120,6 +120,34 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0)); } +int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) { + // set module properties and perform initial setup - packet type does not matter + int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + state = this->clearErrors(); + RADIOLIB_ASSERT(state); + + state = this->configLfClock(RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED | RADIOLIB_LR11X0_LF_CLK_XOSC); + RADIOLIB_ASSERT(state); + + uint16_t errs = 0; + state = this->getErrors(&errs); + RADIOLIB_ASSERT(state); + if(errs & 0x40) { + RADIOLIB_DEBUG_BASIC_PRINTLN("LF_XOSC_START_ERR"); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + state = this->gnssSetConstellationToUse(constellations); + RADIOLIB_ASSERT(state); + + state = setRegulatorLDO(); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); +} + int16_t LR11x0::reset() { // run the reset sequence this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); @@ -1723,6 +1751,260 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat return(state); } +int16_t LR11x0::isGnssScanCapable() { + // get the version + LR11x0VersionInfo_t version; + int16_t state = this->getVersionInfo(&version); + RADIOLIB_ASSERT(state); + + // check the device firmware version is sufficient + uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; + state = RADIOLIB_ERR_UNSUPPORTED; + if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { + state = RADIOLIB_ERR_NONE; + } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { + state = RADIOLIB_ERR_NONE; + } + RADIOLIB_ASSERT(state); + + // in debug mode, dump the almanac + #if RADIOLIB_DEBUG_PROTOCOL + uint32_t addr = 0; + uint16_t sz = 0; + state = this->gnssAlmanacReadAddrSize(&addr, &sz); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz); + uint32_t buff[32] = { 0 }; + while(sz > 0) { + size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); + state = this->readRegMem32(addr, buff, len); + RADIOLIB_ASSERT(state); + Module::hexdump(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr); + addr += len*sizeof(uint32_t); + sz -= len*sizeof(uint32_t); + } + + uint8_t almanac[22] = { 0 }; + for(uint8_t i = 0; i < 128; i++) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i); + state = this->gnssAlmanacReadSV(i, almanac); + RADIOLIB_ASSERT(state); + Module::hexdump(NULL, almanac, 22); + } + + #endif + + return(state); +} + +int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) { + if(!res) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + // go to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT); + RADIOLIB_ASSERT(state); + + // set scan mode (single vs multiple) + state = this->gnssSetMode(0x03); + RADIOLIB_ASSERT(state); + + // set RF switch + this->mod->setRfSwitchState(LR11x0::MODE_GNSS); + + // start scan with high effort + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start"); + state = this->gnssPerformScan(RADIOLIB_LR11X0_GNSS_EFFORT_MID, 0x3C, 16); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout + // this can take very long if both GPS and BeiDou are enabled + RadioLibTime_t softTimeout = 300UL * 1000UL; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + this->gnssAbort(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); + } + } + + // restore the switch + this->mod->setRfSwitchState(Module::MODE_IDLE); + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags + uint32_t irq = this->getIrqStatus(); + this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // retrieve the demodulator status + uint8_t info = 0; + state = this->gnssReadDemodStatus(&res->demodStat, &info); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)res->demodStat, (unsigned int)info); + + // retrieve the number of detected satellites + state = this->gnssGetNbSvDetected(&res->numSatsDet); + RADIOLIB_ASSERT(state); + + // retrieve the result size + state = this->gnssGetResultSize(&res->resSize); + RADIOLIB_ASSERT(state); + + // check and return demodulator status + if(res->demodStat < RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND) { + return(RADIOLIB_ERR_GNSS_DEMOD(res->demodStat)); + } + + return(state); +} + +int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) { + if(!stat) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + // save the time the time until subframe is relative to + stat->start = this->mod->hal->millis(); + + // get the raw data + uint8_t raw[53] = { 0 }; + int16_t state = this->gnssReadAlmanacStatus(raw); + RADIOLIB_ASSERT(state); + + // parse the reply + stat->gps.status = (int8_t)raw[0]; + stat->gps.timeUntilSubframe = ((uint32_t)(raw[1]) << 24) | ((uint32_t)(raw[2]) << 16) | ((uint32_t)(raw[3]) << 8) | (uint32_t)raw[4]; + stat->gps.numSubframes = raw[5]; + stat->gps.nextSubframe4SvId = raw[6]; + stat->gps.nextSubframe5SvId = raw[7]; + stat->gps.nextSubframeStart = raw[8]; + stat->gps.numUpdateNeeded = raw[9]; + stat->gps.flagsUpdateNeeded[0] = ((uint32_t)(raw[10]) << 24) | ((uint32_t)(raw[11]) << 16) | ((uint32_t)(raw[12]) << 8) | (uint32_t)raw[13]; + stat->gps.flagsActive[0] = ((uint32_t)(raw[14]) << 24) | ((uint32_t)(raw[15]) << 16) | ((uint32_t)(raw[16]) << 8) | (uint32_t)raw[17]; + stat->beidou.status = (int8_t)raw[18]; + stat->beidou.timeUntilSubframe = ((uint32_t)(raw[19]) << 24) | ((uint32_t)(raw[20]) << 16) | ((uint32_t)(raw[21]) << 8) | (uint32_t)raw[22]; + stat->beidou.numSubframes = raw[23]; + stat->beidou.nextSubframe4SvId = raw[24]; + stat->beidou.nextSubframe5SvId = raw[25]; + stat->beidou.nextSubframeStart = raw[26]; + stat->beidou.numUpdateNeeded = raw[27]; + stat->beidou.flagsUpdateNeeded[0] = ((uint32_t)(raw[28]) << 24) | ((uint32_t)(raw[29]) << 16) | ((uint32_t)(raw[30]) << 8) | (uint32_t)raw[31]; + stat->beidou.flagsUpdateNeeded[1] = ((uint32_t)(raw[32]) << 24) | ((uint32_t)(raw[33]) << 16) | ((uint32_t)(raw[34]) << 8) | (uint32_t)raw[35]; + stat->beidou.flagsActive[0] = ((uint32_t)(raw[36]) << 24) | ((uint32_t)(raw[37]) << 16) | ((uint32_t)(raw[38]) << 8) | (uint32_t)raw[39]; + stat->beidou.flagsActive[1] = ((uint32_t)(raw[40]) << 24) | ((uint32_t)(raw[41]) << 16) | ((uint32_t)(raw[42]) << 8) | (uint32_t)raw[43]; + stat->beidouSvNoAlmanacFlags[0] = ((uint32_t)(raw[44]) << 24) | ((uint32_t)(raw[45]) << 16) | ((uint32_t)(raw[46]) << 8) | (uint32_t)raw[47]; + stat->beidouSvNoAlmanacFlags[1] = ((uint32_t)(raw[18]) << 24) | ((uint32_t)(raw[49]) << 16) | ((uint32_t)(raw[50]) << 8) | (uint32_t)raw[51]; + stat->nextAlmanacId = raw[52]; + + return(state); +} + +int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) { + if(!stat) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + // almanac update has to be called at least 1.3 seconds before the subframe + // we use 2.3 seconds to be on the safe side + + // calculate absolute times + RadioLibTime_t window = stat->start + stat->gps.timeUntilSubframe - 2300; + if(constellation == RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU) { + window = stat->start + stat->beidou.timeUntilSubframe - 2300; + } + RadioLibTime_t now = this->mod->hal->millis(); + if(now > window) { + // we missed the window + return(RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE); + } + + RadioLibTime_t delay = window - now; + RADIOLIB_DEBUG_BASIC_PRINTLN("Time until subframe %lu ms", delay); + this->mod->hal->delay(delay); + return(RADIOLIB_ERR_NONE); +} + +// TODO fix last satellite always out of date +int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) { + int16_t state = this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT); + RADIOLIB_ASSERT(state); + + state = this->gnssAlmanacUpdateFromSat(RADIOLIB_LR11X0_GNSS_EFFORT_MID, constellation); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout, assumes 2 subframes and up to 2.3s pre-roll + uint32_t softTimeout = 16UL * 1000UL; + uint32_t start = this->mod->hal->millis(); + while (!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + this->gnssAbort(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for almanac update"); + } + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("GPS almanac update done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags + uint32_t irq = this->getIrqStatus(); + this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { + state = RADIOLIB_ERR_RX_TIMEOUT; + } + + return(state); +} + +int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) { + if(!pos) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t error = 0; + int16_t state; + if(filtered) { + state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, NULL, NULL, NULL, NULL, &pos->latitude, &pos->longitude, &pos->accuracy, NULL); + } else { + state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, &pos->latitude, &pos->longitude, &pos->accuracy, NULL, NULL, NULL, NULL, NULL); + } + RADIOLIB_ASSERT(state); + + // check the solver error + if(error != 0) { + return(RADIOLIB_ERR_GNSS_SOLVER(error)); + } + + return(state); +} + +int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) { + if((!sats) || (numSats >= 32)) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t svId[32] = { 0 }; + uint8_t snr[32] = { 0 }; + int16_t doppler[32] = { 0 }; + int16_t state = this->gnssGetSvDetected(svId, snr, doppler, numSats); + RADIOLIB_ASSERT(state); + for(size_t i = 0; i < numSats; i++) { + sats[i].svId = svId[i]; + sats[i].c_n0 = snr[i] + 31; + sats[i].doppler = doppler[i]; + } + + return(state); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -1816,7 +2098,9 @@ bool LR11x0::findChip(uint8_t ver) { // read the version LR11x0VersionInfo_t info; int16_t state = getVersionInfo(&info); - if((state == RADIOLIB_ERR_NONE) && (info.device == ver)) { + RADIOLIB_ASSERT(state); + + if(info.device == ver) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device); RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor); if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) { @@ -2122,7 +2406,7 @@ int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) { } int16_t LR11x0::setDioIrqParams(uint32_t irq) { - return(setDioIrqParams(irq, irq)); + return(setDioIrqParams(irq, 0)); } int16_t LR11x0::clearIrq(uint32_t irq) { @@ -3314,6 +3598,16 @@ int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskA return(state); } +void LR11x0::gnssAbort() { + // send the abort signal (single NOP) + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; + this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + + // wait for at least 2.9 seconds as specified by the user manual + this->mod->hal->delay(3000); +} + int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { if(!key) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); @@ -3374,11 +3668,17 @@ int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint // check the crypto engine state if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif return(RADIOLIB_ERR_SPI_CMD_FAILED); } // pass the data memcpy(dataOut, &rplBuff[1], len); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif return(state); } @@ -3609,6 +3909,9 @@ int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_ // pass the data memcpy(dataOut, &rplBuff[1], len); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif return(state); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index a52d64afd6..3f1939a5bd 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -274,7 +274,8 @@ #define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error #define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error #define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source) -#define RADIOLIB_LR11X0_IRQ_ALL (0x0BF80FFCUL) // 31 0 all interrupts +#define RADIOLIB_LR11X0_IRQ_GNSS_ABORT (0x01UL << 28) // 31 0 GNSS scan aborted +#define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts #define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts // RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK @@ -552,7 +553,7 @@ #define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error #define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed #define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz -#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 H +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 Hz #define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz #define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz @@ -564,6 +565,65 @@ #define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header #define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20) +// RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME +#define RADIOLIB_LR11X0_GNSS_EFFORT_LOW (0x00UL << 0) // 7 0 GNSS effort mode: low sensitivity +#define RADIOLIB_LR11X0_GNSS_EFFORT_MID (0x01UL << 0) // 7 0 medium sensitivity +#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW (0x00UL << 0) // 7 0 time fetch options: ToW only, requires WN to demodulated beforehand +#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN (0x01UL << 0) // 7 0 ToW and WN +#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN_ROLL (0x02UL << 0) // 7 0 ToW, WN and rollover + +// RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NOT_POSSIBLE (-21) // 7 0 GNSS demodulation status: not possible to demodulate +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SAT_LOST (-20) // 7 0 satellite lost +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALMANAC_DEMOD_ERROR (-19) // 7 0 almanac demodulation error +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOO_LATE (-18) // 7 0 woke up after preamble (demodulation started too late) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_20_MS_FAIL (-17) // 7 0 20ms real-time clock failed +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WAKE_UP_FAIL (-16) // 7 0 wake up sync failed +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_INVALID (-15) // 7 0 week number not validated +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_ACTIVE_SAT (-14) // 7 0 no active satellite selected in satellite list +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SLEEP_TOO_LONG (-13) // 7 0 sleep time too long +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_INVALID (-12) // 7 0 wrong time-of-week demodulated +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PREAMBLE_INVALID (-11) // 7 0 preamble not validated +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_DISABLED (-10) // 7 0 demodulator disabled +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_EXTR_FAILED (-9) // 7 0 demodulator extraction failed +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE (-8) // 7 0 no bit change found during demodulation start +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE_ADV (-7) // 7 0 no bit change found during advanced scan +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_SAT_FOUND (-6) // 7 0 no satellites found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SYNC_LOST (-5) // 7 0 word sync lost +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_NOT_ENOUGH (-3) // 7 0 parity check fail (not enough) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_TOO_MANY (-2) // 7 0 parity check fail (too many) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_PARITY (-1) // 7 0 parity check fail (no parity found) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_NONE (0) // 7 0 word sync search not started +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_POT (1) // 7 0 potential word sync found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_OK (2) // 7 0 word sync found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND (3) // 7 0 time-of-week found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_FOUND (4) // 7 0 week number and time-of-week found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALM_FOUND_UNSAVED (5) // 7 0 almanac found but not saved +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_HALF_ALM_SAVED (6) // 7 0 half of almanac found and saved +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_FULL_ALM_SAVED (7) // 7 0 full almanac found and saved +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WORD_SYNC_FOUND (0x01UL << 0) // 7 0 GNSS demodulation info: word synchronization found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_TOW_FOUND (0x01UL << 1) // 7 0 time-of-week found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_DEMODED (0x01UL << 2) // 7 0 week number demodulated +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_FOUND (0x01UL << 3) // 7 0 week number found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_1_FOUND (0x01UL << 4) // 7 0 subframe 1 found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_4_FOUND (0x01UL << 5) // 7 0 subframe 4 found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_5_FOUND (0x01UL << 6) // 7 0 subframe 5 found + +// RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS +#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE (0) // 7 0 GPS/BeiDou almanac status: all satellites up-to-date +#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_OUTDATED (1) // 7 0 at least one satellite needs update + +// RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NONE (0) // 7 0 internal 2D solver error: no error +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_RES_HIGH (1) // 7 0 residue too high +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_CONVERGED (2) // 7 0 not converged on solution +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_ENOUGH_SV (3) // 7 0 not enough satellites +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ILL_MATRIX (4) // 7 0 matrix error (?) +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_TIME (5) // 7 0 time error +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_PART_OLD (6) // 7 0 part of almanac too old or not available +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_INCONSISTENT (7) // 7 0 not consistent with history (?) +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_OLD (8) // 7 0 all of almanac too old + // RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY #define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success #define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed @@ -717,8 +777,90 @@ struct LR11x0VersionInfo_t { uint8_t almanacGNSS; }; +/*! + \struct LR11x0GnssResult_t + \brief Structure to report information results of a GNSS scan. +*/ struct LR11x0GnssResult_t { + /*! \brief Demodulator status. One of RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_* */ + int8_t demodStat; + + /*! \brief Number of satellites detected during the scan. */ + uint8_t numSatsDet; + + /*! \brief Result size, used when passing data to LoRa cloud. */ + uint16_t resSize; +}; + +/*! + \struct LR11x0GnssPosition_t + \brief Structure to report position from LR11x0 internal solver. +*/ +struct LR11x0GnssPosition_t { + /*! \brief Latitude in degrees. */ + float latitude; + + /*! \brief Longitude in degrees. */ + float longitude; + /*! \brief Accuracy of this result. */ + uint16_t accuracy; + + /*! \brief Number of satellites used to solve this position. */ + uint8_t numSatsUsed; +}; + +/*! + \struct LR11x0GnssSatellite_t + \brief Structure to save information about a satellite found during GNSS scan. +*/ +struct LR11x0GnssSatellite_t { + /*! \brief Satellite vehicle (SV) identifier. */ + uint8_t svId; + + /*! \brief C/N0 in dB. */ + uint8_t c_n0; + + /*! \brief Doppler shift of the signal in Hz. */ + int16_t doppler; +}; + +/*! + \struct LR11x0GnssAlmanacStatusPart_t + \brief Structure to save information about one constellation of the GNSS almanac. +*/ +struct LR11x0GnssAlmanacStatusPart_t { + int8_t status; + uint32_t timeUntilSubframe; + uint8_t numSubframes; + uint8_t nextSubframe4SvId; + uint8_t nextSubframe5SvId; + uint8_t nextSubframeStart; + uint8_t numUpdateNeeded; + uint32_t flagsUpdateNeeded[2]; + uint32_t flagsActive[2]; +}; + +/*! + \struct LR11x0GnssAlmanacStatus_t + \brief Structure to save information about the GNSS almanac. + This is not the actual almanac, just some context information about it. +*/ +struct LR11x0GnssAlmanacStatus_t { + /*! \brief GPS part of the almanac */ + LR11x0GnssAlmanacStatusPart_t gps; + + /*! \brief BeiDou part of the almanac */ + LR11x0GnssAlmanacStatusPart_t beidou; + + /*! \brief Extra flags present for BeiDou only */ + uint32_t beidouSvNoAlmanacFlags[2]; + + /*! \brief Next almanac ID */ + uint8_t nextAlmanacId; + + /*! \brief Timestamp of when almanac status was retrieved - timeUntilSubframe is relative to this value. */ + RadioLibTime_t start; }; /*! @@ -802,6 +944,14 @@ class LR11x0: public PhysicalLayer { */ int16_t beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage); + /*! + \brief Initialization method for GNSS scanning. + \param constellations GNSS constellations to use (GPS, BeiDou or both). Defaults to both. + \param tcxoVoltage TCXO reference voltage to be set. + \returns \ref status_codes + */ + int16_t beginGNSS(uint8_t constellations = RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS | RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU, float tcxoVoltage = 1.6); + /*! \brief Reset method. Will reset the chip to the default state using RST pin. \returns \ref status_codes @@ -1396,6 +1546,63 @@ class LR11x0: public PhysicalLayer { */ int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true); + /*! + \brief Method to check whether the device is capable of performing a GNSS scan. + \returns \ref status_codes + */ + int16_t isGnssScanCapable(); + + /*! + \brief Performs GNSS scan. + \param res Pointer to LR11x0GnssPosition_t structure to populate. + Will not be saved if set to NULL, defaults to NULL. + \returns \ref status_codes + */ + int16_t gnssScan(LR11x0GnssResult_t* res = NULL); + + /*! + \brief Read information about the almanac. + \param stat Pointer to structure to save the almanac status into. + This is not the actual almanac, just a structure providing information about it. + \returns \ref status_codes + */ + int16_t getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat); + + /*! + \brief Blocking wait until the next subframe with almanac data is available. + Used to control timing during almanac update from satellite. + \param stat Pointer to structure containing the almanac status read by getGnssAlmanacStatus. + This is not the actual almanac, just a structure providing information about it. + \param constellation Constellation to wait for, one of RADIOLIB_LR11X0_GNSS_CONSTELLATION_*. + Constellations cannot be updated at the same time, but rather must be updated sequentially! + \returns \ref status_codes + */ + int16_t gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation); + + /*! + \brief Perform almanac update. Must be called immediately after gnssDelayUntilSubframe. + \param constellation Constellation to update, one of RADIOLIB_LR11X0_GNSS_CONSTELLATION_*. + Constellations cannot be updated at the same time, but rather must be updated sequentially! + \returns \ref status_codes + */ + int16_t updateGnssAlmanac(uint8_t constellation); + + /*! + \brief Get GNSS position. Called after gnssScan to retrieve the position calculated by the internal solver. + \param pos Pointer to LR11x0GnssPosition_t structure to populate. + \param filtered Whether to save the filtered, or unfiltered values. Defaults to true (filtered). + \returns \ref status_codes + */ + int16_t getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered = true); + + /*! + \brief Get GNSS satellites found during the last scan. + \param sats Pointer to array of LR11x0GnssSatellite_t structures to populate. + \param numSats Number of satellites to read. Can be retrieved from LR11x0GnssResult_t passed to gnssScan. + \returns \ref status_codes + */ + int16_t getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -1546,6 +1753,7 @@ class LR11x0: public PhysicalLayer { int16_t gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed); int16_t gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList); int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1); + void gnssAbort(); int16_t cryptoSetKey(uint8_t keyId, uint8_t* key); int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key); From 0f2f5fdf4a12d5d48bcca56d74d80e9965a6ecc2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 19 Oct 2024 09:19:37 +0200 Subject: [PATCH 1296/1848] [FEC] Fix some typos --- src/utils/FEC.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/FEC.h b/src/utils/FEC.h index 788b0b52e9..807120c81f 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -83,10 +83,10 @@ extern RadioLibBCH RadioLibBCHInstance; /*! \class RadioLibConvCode - \brief Class to perform convolutional coding wtih variable rates. + \brief Class to perform convolutional coding with variable rates. Only 1/2 and 1/3 rate is currently supported. - Copnvolutional coder implementation in this class is adapted from Setmech's LR-FHSS demo: + Convolutional coder implementation in this class is adapted from Semtech's LR-FHSS demo: https://github.com/Lora-net/SWDM001/tree/master/lib/sx126x_driver Its SX126x driver is distributed under the Clear BSD License, From 4a155b192204598c0141a859c268995039d672a4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Oct 2024 14:22:23 +0100 Subject: [PATCH 1297/1848] [Utils] Move generally useful methods to utils --- src/BuildOpt.h | 10 +- src/Module.cpp | 96 +--------------- src/Module.h | 24 +--- src/modules/LR11x0/LR11x0.cpp | 4 +- src/protocols/AX25/AX25.cpp | 4 +- src/protocols/Pager/Pager.cpp | 12 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 3 +- src/utils/CRC.cpp | 4 +- src/utils/FEC.h | 10 -- src/utils/Utils.cpp | 105 ++++++++++++++++++ src/utils/Utils.h | 42 +++++++ 11 files changed, 170 insertions(+), 144 deletions(-) create mode 100644 src/utils/Utils.cpp create mode 100644 src/utils/Utils.h diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 60859443a8..3df71d83ce 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -473,10 +473,10 @@ #if RADIOLIB_DEBUG #if defined(RADIOLIB_BUILD_ARDUINO) - #define RADIOLIB_DEBUG_PRINT(...) Module::serialPrintf(__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN(M, ...) Module::serialPrintf(M "\n", ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M, ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) Module::serialPrintf(LEVEL "" M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT(...) rlb_printf(__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M "\n", ##__VA_ARGS__) // some platforms do not support printf("%f"), so it has to be done this way #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) @@ -492,7 +492,7 @@ #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif - #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) Module::hexdump(LEVEL, __VA_ARGS__) + #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) rlb_hexdump(LEVEL, __VA_ARGS__) #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} diff --git a/src/Module.cpp b/src/Module.cpp index 30d38b0352..33d9c09b4f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,15 +1,9 @@ #include "Module.h" // the following is probably only needed on non-Arduino builds -#include #include #include -#if RADIOLIB_DEBUG -// needed for debug print -#include -#endif - #if defined(RADIOLIB_BUILD_ARDUINO) #include "ArduinoHal.h" @@ -461,69 +455,7 @@ void Module::waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len) { #endif } -uint32_t Module::reflect(uint32_t in, uint8_t bits) { - uint32_t res = 0; - for(uint8_t i = 0; i < bits; i++) { - res |= (((in & ((uint32_t)1 << i)) >> i) << (bits - i - 1)); - } - return(res); -} - #if RADIOLIB_DEBUG -void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { - size_t rem_len = len; - for(size_t i = 0; i < len; i+=16) { - char str[120]; - sprintf(str, "%08" PRIx32 ": ", (uint32_t)i+offset); - size_t line_len = 16; - if(rem_len < line_len) { - line_len = rem_len; - } - for(size_t j = 0; j < line_len; j+=width) { - if(width > 1) { - int m = 0; - int step = width/2; - if(be) { - step *= -1; - } - for(int32_t k = width - 1; k >= -width + 1; k+=step) { - sprintf(&str[10 + (j+m)*3], "%02x ", data[i+j+k+m]); - m++; - } - } else { - sprintf(&str[10 + (j)*3], "%02x ", data[i+j]); - } - } - for(size_t j = line_len; j < 16; j++) { - sprintf(&str[10 + j*3], " "); - } - //str[56] = '|'; - str[58] = ' '; - - // at this point we need to start escaping "%" characters - char* strPtr = &str[59]; - for(size_t j = 0; j < line_len; j++) { - char c = data[i+j]; - if((c < ' ') || (c > '~')) { - c = '.'; - } else if(c == '%') { - *strPtr++ = '%'; - } - sprintf(strPtr++, "%c", c); - - } - for(size_t j = line_len; j < 16; j++) { - sprintf(strPtr++, " "); - } - if(level) { - RADIOLIB_DEBUG_PRINT(level); - } - RADIOLIB_DEBUG_PRINT(str); - RADIOLIB_DEBUG_PRINTLN(); - rem_len -= 16; - } -} - void Module::regdump(const char* level, uint16_t start, size_t len) { #if RADIOLIB_STATIC_ONLY uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -531,39 +463,13 @@ void Module::regdump(const char* level, uint16_t start, size_t len) { uint8_t* buff = new uint8_t[len]; #endif SPIreadRegisterBurst(start, len, buff); - hexdump(level, buff, len, start); + rlb_hexdump(level, buff, len, start); #if !RADIOLIB_STATIC_ONLY delete[] buff; #endif } #endif -#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) -// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 -size_t Module::serialPrintf(const char* format, ...) { - va_list arg; - va_start(arg, format); - char temp[64]; - char* buffer = temp; - size_t len = vsnprintf(temp, sizeof(temp), format, arg); - va_end(arg); - if (len > sizeof(temp) - 1) { - buffer = new char[len + 1]; - if (!buffer) { - return 0; - } - va_start(arg, format); - vsnprintf(buffer, len + 1, format, arg); - va_end(arg); - } - len = RADIOLIB_DEBUG_PORT.write(reinterpret_cast(buffer), len); - if (buffer != temp) { - delete[] buffer; - } - return len; -} -#endif - void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { // This can be on the stack, setRfSwitchTable copies the contents const uint32_t pins[] = { diff --git a/src/Module.h b/src/Module.h index e6e4acafe0..5d5072bf55 100644 --- a/src/Module.h +++ b/src/Module.h @@ -3,6 +3,7 @@ #include "TypeDef.h" #include "Hal.h" +#include "utils/Utils.h" #if defined(RADIOLIB_BUILD_ARDUINO) #include @@ -505,26 +506,7 @@ class Module { */ void waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len); - /*! - \brief Function to reflect bits within a byte. - \param in The input to reflect. - \param bits Number of bits to reflect. - \return The reflected input. - */ - static uint32_t reflect(uint32_t in, uint8_t bits); - #if RADIOLIB_DEBUG - /*! - \brief Function to dump data as hex into the debug port. - \param level RadioLib debug level, set to NULL to not print. - \param data Data to dump. - \param len Number of bytes to dump. - \param offset Address offset to add when printing the data. - \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). - \param be Print multi-byte data as big endian. Defaults to false. - */ - static void hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); - /*! \brief Function to dump device registers as hex into the debug port. \param level RadioLib debug level, set to NULL to not print. @@ -534,10 +516,6 @@ class Module { void regdump(const char* level, uint16_t start, size_t len); #endif - #if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) - static size_t serialPrintf(const char* format, ...); - #endif - #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index ee2e4b1c34..1736f8c953 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1779,7 +1779,7 @@ int16_t LR11x0::isGnssScanCapable() { size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); state = this->readRegMem32(addr, buff, len); RADIOLIB_ASSERT(state); - Module::hexdump(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr); + RADIOLIB_DEBUG_HEXDUMP(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr); addr += len*sizeof(uint32_t); sz -= len*sizeof(uint32_t); } @@ -1789,7 +1789,7 @@ int16_t LR11x0::isGnssScanCapable() { RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i); state = this->gnssAlmanacReadSV(i, almanac); RADIOLIB_ASSERT(state); - Module::hexdump(NULL, almanac, 22); + RADIOLIB_DEBUG_HEXDUMP(NULL, almanac, 22); } #endif diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 82a64cebc6..22e1220a2e 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -1,5 +1,7 @@ #include "AX25.h" + #include + #if !RADIOLIB_EXCLUDE_AX25 AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control) @@ -369,7 +371,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // flip bit order for(size_t i = 0; i < frameBuffLen; i++) { - frameBuff[i] = Module::reflect(frameBuff[i], 8); + frameBuff[i] = rlb_reflect(frameBuff[i], 8); } // calculate diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index e9aa14a479..e4914dd6bc 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -1,6 +1,8 @@ #include "Pager.h" + #include #include + #if defined(ESP_PLATFORM) #include "esp_attr.h" #endif @@ -177,7 +179,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t // first insert the remainder from previous code word (if any) if(remBits > 0) { // this doesn't apply to BCD messages, so no need to check that here - uint8_t prev = Module::reflect(data[dataPos - 1], 8); + uint8_t prev = rlb_reflect(data[dataPos - 1], 8); prev >>= 1; msg[blockPos] |= (uint32_t)prev << (RADIOLIB_PAGER_CODE_WORD_LEN - 1 - remBits); } @@ -191,7 +193,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t if(encoding == RADIOLIB_PAGER_BCD) { symbol = encodeBCD(symbol); } - symbol = Module::reflect(symbol, 8); + symbol = rlb_reflect(symbol, 8); symbol >>= (8 - symbolLength); // insert the next message symbol @@ -205,7 +207,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t uint8_t numSteps = (symbolPos - RADIOLIB_PAGER_FUNC_BITS_POS + symbolLength)/symbolLength; for(uint8_t j = 0; j < numSteps; j++) { symbol = encodeBCD(' '); - symbol = Module::reflect(symbol, 8); + symbol = rlb_reflect(symbol, 8); symbol >>= (8 - symbolLength); msg[blockPos] |= (uint32_t)symbol << symbolPos; symbolPos -= symbolLength; @@ -428,7 +430,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { uint32_t symbol = prevSymbol << (symbolLength - ovfBits) | currSymbol; // finally, we can flip the bits - symbol = Module::reflect((uint8_t)symbol, 8); + symbol = rlb_reflect((uint8_t)symbol, 8); symbol >>= (8 - symbolLength); // decode BCD and we're done @@ -446,7 +448,7 @@ int16_t PagerClient::readData(uint8_t* data, size_t* len, uint32_t* addr) { while(bitPos >= RADIOLIB_PAGER_MESSAGE_END_POS) { // get the message symbol from the code word and reverse bits uint32_t symbol = (cw & (0x7FUL << bitPos)) >> bitPos; - symbol = Module::reflect((uint8_t)symbol, 8); + symbol = rlb_reflect((uint8_t)symbol, 8); symbol >>= (8 - symbolLength); // decode BCD if needed diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 5176073c90..82eb5fba95 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -1,4 +1,5 @@ #include "PhysicalLayer.h" + #include PhysicalLayer::PhysicalLayer(float step, size_t maxLen) { @@ -481,7 +482,7 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { // check complete byte if(this->bufferBitPos == 8) { - this->buffer[this->bufferWritePos] = Module::reflect(this->buffer[this->bufferWritePos], 8); + this->buffer[this->bufferWritePos] = rlb_reflect(this->buffer[this->bufferWritePos], 8); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]); this->bufferWritePos++; diff --git a/src/utils/CRC.cpp b/src/utils/CRC.cpp index ac7fb74f06..d0dd03a0a4 100644 --- a/src/utils/CRC.cpp +++ b/src/utils/CRC.cpp @@ -11,7 +11,7 @@ uint32_t RadioLibCRC::checksum(const uint8_t* buff, size_t len) { if(i % 8 == 0) { uint32_t in = buff[pos++]; if(this->refIn) { - in = Module::reflect(in, 8); + in = rlb_reflect(in, 8); } crc ^= (in << (this->size - 8)); } @@ -26,7 +26,7 @@ uint32_t RadioLibCRC::checksum(const uint8_t* buff, size_t len) { crc ^= this->out; if(this->refOut) { - crc = Module::reflect(crc, this->size); + crc = rlb_reflect(crc, this->size); } crc &= (uint32_t)0xFFFFFFFF >> (32 - this->size); return(crc); diff --git a/src/utils/FEC.h b/src/utils/FEC.h index 807120c81f..9b9e99c37f 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -71,16 +71,6 @@ class RadioLibBCH { // the global singleton extern RadioLibBCH RadioLibBCHInstance; -// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html -#define SET_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] |= (1 << ((k)%8)) ) -#define CLEAR_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] &= ~(1 << ((k)%8)) ) -#define TEST_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] & (1 << ((k)%8)) ) -#define GET_BIT_IN_ARRAY_MSB(A, k) ( (A[((k)/8)] & (1 << ((k)%8))) ? 1 : 0 ) -#define SET_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] |= (1 << (7 - ((k)%8))) ) -#define CLEAR_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] &= ~(1 << (7 - ((k)%8))) ) -#define TEST_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] & (1 << (7 - ((k)%8))) ) -#define GET_BIT_IN_ARRAY_LSB(A, k) ( (A[((k)/8)] & (1 << (7 - ((k)%8)))) ? 1 : 0 ) - /*! \class RadioLibConvCode \brief Class to perform convolutional coding with variable rates. diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp new file mode 100644 index 0000000000..c2f12a6a16 --- /dev/null +++ b/src/utils/Utils.cpp @@ -0,0 +1,105 @@ +#include "Utils.h" + +#include +#include +#include +#include + +uint32_t rlb_reflect(uint32_t in, uint8_t bits) { + uint32_t res = 0; + for(uint8_t i = 0; i < bits; i++) { + res |= (((in & ((uint32_t)1 << i)) >> i) << (bits - i - 1)); + } + return(res); +} + +void rlb_hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { + #if RADIOLIB_DEBUG + size_t rem_len = len; + for(size_t i = 0; i < len; i+=16) { + char str[120]; + sprintf(str, "%08" PRIx32 ": ", (uint32_t)i+offset); + size_t line_len = 16; + if(rem_len < line_len) { + line_len = rem_len; + } + for(size_t j = 0; j < line_len; j+=width) { + if(width > 1) { + int m = 0; + int step = width/2; + if(be) { + step *= -1; + } + for(int32_t k = width - 1; k >= -width + 1; k+=step) { + sprintf(&str[10 + (j+m)*3], "%02x ", data[i+j+k+m]); + m++; + } + } else { + sprintf(&str[10 + (j)*3], "%02x ", data[i+j]); + } + } + for(size_t j = line_len; j < 16; j++) { + sprintf(&str[10 + j*3], " "); + } + str[58] = ' '; + + // at this point we need to start escaping "%" characters + char* strPtr = &str[59]; + for(size_t j = 0; j < line_len; j++) { + char c = data[i+j]; + if((c < ' ') || (c > '~')) { + c = '.'; + } else if(c == '%') { + *strPtr++ = '%'; + } + sprintf(strPtr++, "%c", c); + + } + for(size_t j = line_len; j < 16; j++) { + sprintf(strPtr++, " "); + } + if(level) { + RADIOLIB_DEBUG_PRINT(level); + } + RADIOLIB_DEBUG_PRINT(str); + RADIOLIB_DEBUG_PRINTLN(); + rem_len -= 16; + } + + #else + // outside of debug, this does nothing + (void)level; + (void)data; + (void)len; + (void)offset; + (void)width; + (void)be; + + #endif +} + +#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) +// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 +size_t rlb_printf(const char* format, ...) { + va_list arg; + va_start(arg, format); + char temp[64]; + char* buffer = temp; + size_t len = vsnprintf(temp, sizeof(temp), format, arg); + va_end(arg); + if (len > sizeof(temp) - 1) { + buffer = new char[len + 1]; + if (!buffer) { + return 0; + } + va_start(arg, format); + vsnprintf(buffer, len + 1, format, arg); + va_end(arg); + } + len = RADIOLIB_DEBUG_PORT.write(reinterpret_cast(buffer), len); + if (buffer != temp) { + delete[] buffer; + } + return len; +} +#endif diff --git a/src/utils/Utils.h b/src/utils/Utils.h new file mode 100644 index 0000000000..44e4c776be --- /dev/null +++ b/src/utils/Utils.h @@ -0,0 +1,42 @@ +#if !defined(_RADIOLIB_UTILS_H) +#define _RADIOLIB_UTILS_H + +#include "TypeDef.h" + +#include +#include + +// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html +#define SET_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] |= (1 << ((k)%8)) ) +#define CLEAR_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] &= ~(1 << ((k)%8)) ) +#define TEST_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] & (1 << ((k)%8)) ) +#define GET_BIT_IN_ARRAY_MSB(A, k) ( (A[((k)/8)] & (1 << ((k)%8))) ? 1 : 0 ) +#define SET_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] |= (1 << (7 - ((k)%8))) ) +#define CLEAR_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] &= ~(1 << (7 - ((k)%8))) ) +#define TEST_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] & (1 << (7 - ((k)%8))) ) +#define GET_BIT_IN_ARRAY_LSB(A, k) ( (A[((k)/8)] & (1 << (7 - ((k)%8)))) ? 1 : 0 ) + +/*! + \brief Function to reflect bits within a byte. + \param in The input to reflect. + \param bits Number of bits to reflect. + \return The reflected input. +*/ +uint32_t rlb_reflect(uint32_t in, uint8_t bits); + +/*! + \brief Function to dump data as hex into the debug port. + \param level RadioLib debug level, set to NULL to not print. + \param data Data to dump. + \param len Number of bytes to dump. + \param offset Address offset to add when printing the data. + \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). + \param be Print multi-byte data as big endian. Defaults to false. +*/ +void rlb_hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); + +#if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) +size_t rlb_printf(const char* format, ...); +#endif + +#endif From cc720a7a240bab9fe3e3063d7d99155ab50ac59d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Oct 2024 14:25:27 +0100 Subject: [PATCH 1298/1848] [SX127x] Added reset to home channel to FHSS examples (#1266) --- examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino | 4 ++++ examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index 7785a1730f..ede24586f0 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -86,6 +86,7 @@ void setup() { // set hop period in symbols // this will also enable FHSS + Serial.print(F("[SX1278] Setting hopping period ... ")); state = radio.setFHSSHoppingPeriod(9); if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -153,6 +154,9 @@ void loop() { // reset the counter hopsCompleted = 0; + // return to home channel before the next transaction + radio.setFrequency(channels[0]); + // put the module back to listen mode radio.startReceive(); diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index 5c2297db40..d7210af6d1 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -98,6 +98,7 @@ void setup() { // set hop period in symbols // this will also enable FHSS + Serial.print(F("[SX1278] Setting hopping period ... ")); state = radio.setFHSSHoppingPeriod(9); if (state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -147,7 +148,7 @@ void loop() { hopsCompleted = 0; // return to home channel before the next transaction - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + radio.setFrequency(channels[0]); // wait a second before transmitting again delay(1000); From afdf3783c3b0037cf4c624aabed4366dec281d55 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Oct 2024 14:39:33 +0100 Subject: [PATCH 1299/1848] [Utils] Drop redundant include --- src/utils/Utils.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 44e4c776be..57e9610b06 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -1,8 +1,6 @@ #if !defined(_RADIOLIB_UTILS_H) #define _RADIOLIB_UTILS_H -#include "TypeDef.h" - #include #include From 2aa8c6e82a700ad9746a0dc2290c01d758557d60 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Oct 2024 16:02:19 +0100 Subject: [PATCH 1300/1848] Update all examples, add link to RadioBoards --- .../AFSK_External_Radio.ino | 24 +++---- .../AFSK_Imperial_March.ino | 26 +++---- examples/AFSK/AFSK_Imperial_March/melody.h | 6 +- examples/AFSK/AFSK_Tone/AFSK_Tone.ino | 28 ++++---- examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino | 24 +++---- examples/APRS/APRS_MicE/APRS_MicE.ino | 58 ++++++++------- examples/APRS/APRS_Position/APRS_Position.ino | 58 ++++++++------- .../APRS_Position_LoRa/APRS_Position_LoRa.ino | 34 +++++---- examples/AX25/AX25_Frames/AX25_Frames.ino | 64 +++++++++-------- examples/AX25/AX25_Transmit/AX25_Transmit.ino | 50 +++++++------ .../AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino | 52 +++++++------- .../BellModem_Transmit/BellModem_Transmit.ino | 20 +++--- .../CC1101_Receive_Address.ino | 30 ++++---- .../CC1101_Receive_Blocking.ino | 10 ++- .../CC1101_Receive_Interrupt.ino | 38 +++++----- .../CC1101_Settings/CC1101_Settings.ino | 44 ++++++------ .../CC1101_Transmit_Address.ino | 30 ++++---- .../CC1101_Transmit_Blocking.ino | 10 ++- .../CC1101_Transmit_Interrupt.ino | 32 +++++---- examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino | 46 ++++++------ .../FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino | 42 ++++++----- .../Hellschreiber_Transmit.ino | 52 +++++++------- .../Hellschreiber_Transmit_AFSK.ino | 50 +++++++------ ...x0_Channel_Activity_Detection_Blocking.ino | 8 +++ ...0_Channel_Activity_Detection_Interrupt.ino | 8 +++ .../LR11x0_Firmware_Update.ino | 10 ++- .../LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino | 10 ++- .../LR11x0_GNSS_Almanac_Update.ino | 8 +++ .../LR11x0_GNSS_Autonomous_Position.ino | 8 +++ .../LR11x0_GNSS_Satellites.ino | 8 +++ .../LR11x0_LR_FHSS_Modem.ino | 10 ++- .../LR11x0_PingPong/LR11x0_PingPong.ino | 8 +++ .../LR11x0_Receive_Blocking.ino | 8 +++ .../LR11x0_Receive_Interrupt.ino | 8 +++ .../LR11x0_Transmit_Blocking.ino | 8 +++ .../LR11x0_Transmit_Interrupt.ino | 8 +++ .../LR11x0_WiFi_Scan_Blocking.ino | 8 +++ .../LR11x0_WiFi_Scan_Interrupt.ino | 8 +++ .../Morse_Receive_AM/Morse_Receive_AM.ino | 40 ++++++----- .../Morse_Transmit_AM/Morse_Transmit_AM.ino | 40 ++++++----- .../Morse_Transmit_FM/Morse_Transmit_FM.ino | 50 +++++++------ .../Morse_Transmit_SSB/Morse_Transmit_SSB.ino | 54 +++++++------- .../Pager/Pager_Receive/Pager_Receive.ino | 40 ++++++----- .../Pager/Pager_Transmit/Pager_Transmit.ino | 50 +++++++------ .../PhysicalLayer_Interface.ino | 20 ++++-- .../RF69_Receive_AES/RF69_Receive_AES.ino | 26 ++++--- .../RF69_Receive_Address.ino | 30 ++++---- .../RF69_Receive_Blocking.ino | 10 ++- .../RF69_Receive_Interrupt.ino | 26 ++++--- examples/RF69/RF69_Settings/RF69_Settings.ino | 44 ++++++------ .../RF69_Transmit_AES/RF69_Transmit_AES.ino | 26 ++++--- .../RF69_Transmit_Address.ino | 30 ++++---- .../RF69_Transmit_Blocking.ino | 10 ++- .../RF69_Transmit_Interrupt.ino | 32 +++++---- examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 52 +++++++------- .../RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino | 38 +++++----- examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino | 72 ++++++++++--------- .../SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino | 64 +++++++++-------- .../STM32WLx_Channel_Activity_Detection.ino | 18 ++--- ...x_Channel_Activity_Detection_Interrupt.ino | 18 ++--- .../STM32WLx_Receive_Interrupt.ino | 44 ++++++------ .../SX123x_Receive_Blocking.ino | 10 ++- .../SX123x_Transmit_Blocking.ino | 10 ++- ...6x_Channel_Activity_Detection_Blocking.ino | 13 ++-- ...x_Channel_Activity_Detection_Interrupt.ino | 33 ++++----- ...26x_Channel_Activity_Detection_Receive.ino | 13 ++-- .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 35 ++++----- .../SX126x_LR_FHSS_Modem.ino | 13 ++-- .../SX126x_PingPong/SX126x_PingPong.ino | 26 ++++--- .../SX126x_Receive_Blocking.ino | 61 ++++++++-------- .../SX126x_Receive_Interrupt.ino | 53 +++++++------- .../SX126x_Settings/SX126x_Settings.ino | 59 +++++++-------- .../SX126x_Spectrum_Scan.ino | 38 ++++++---- .../SX126x_Spectrum_Scan_Frequency.ino | 38 ++++++---- .../SX126x_Transmit_Blocking.ino | 13 ++-- .../SX126x_Transmit_Interrupt.ino | 13 ++-- ...7x_Channel_Activity_Detection_Blocking.ino | 10 ++- ...x_Channel_Activity_Detection_Interrupt.ino | 32 +++++---- ...27x_Channel_Activity_Detection_Receive.ino | 50 +++++++------ .../SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 32 +++++---- .../SX127x_PingPong/SX127x_PingPong.ino | 23 +++--- .../SX127x_Receive_Blocking.ino | 10 ++- .../SX127x_Receive_Direct.ino | 24 ++++--- .../SX127x_Receive_FHSS.ino | 40 ++++++----- .../SX127x_Receive_Interrupt.ino | 50 +++++++------ .../SX127x_Settings/SX127x_Settings.ino | 40 ++++++----- .../SX127x_Transmit_Blocking.ino | 10 ++- .../SX127x_Transmit_FHSS.ino | 40 ++++++----- .../SX127x_Transmit_Interrupt.ino | 10 ++- .../SX128x_BLE_Modem/SX128x_BLE_Modem.ino | 36 +++++----- ...8x_Channel_Activity_Detection_Blocking.ino | 10 ++- ...x_Channel_Activity_Detection_Interrupt.ino | 26 ++++--- .../SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino | 32 +++++---- .../SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino | 32 +++++---- .../SX128x/SX128x_Ranging/SX128x_Ranging.ino | 34 +++++---- .../SX128x_Receive_Blocking.ino | 10 ++- .../SX128x_Receive_Interrupt.ino | 50 +++++++------ .../SX128x_Settings/SX128x_Settings.ino | 50 +++++++------ .../SX128x_Transmit_Blocking.ino | 10 ++- .../SX128x_Transmit_Interrupt.ino | 10 ++- .../Si443x_Receive_Blocking.ino | 10 ++- .../Si443x_Receive_Interrupt.ino | 28 ++++---- .../Si443x_Settings/Si443x_Settings.ino | 44 ++++++------ .../Si443x_Transmit_Blocking.ino | 10 ++- .../Si443x_Transmit_Interrupt.ino | 10 ++- .../Stream/Stream_Receive/Stream_Receive.ino | 40 ++++++----- .../Stream_Transmit/Stream_Transmit.ino | 40 ++++++----- .../nRF24_Receive_Blocking.ino | 10 ++- .../nRF24_Receive_Interrupt.ino | 42 ++++++----- .../nRF24_Transmit_Blocking.ino | 32 +++++---- .../nRF24_Transmit_Interrupt.ino | 32 +++++---- 111 files changed, 1813 insertions(+), 1372 deletions(-) diff --git a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino index 9419157ba5..012d1e20ff 100644 --- a/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino +++ b/examples/AFSK/AFSK_External_Radio/AFSK_External_Radio.ino @@ -1,19 +1,19 @@ /* - RadioLib AFSK External Radio example + RadioLib AFSK External Radio example - This example shows how to use your Arduino - as modulator for an external analogue FM radio. - - The example sends APRS position reports with - audio modulated as AFSK at 1200 baud using - Bell 202 tones. However, any other AFSK - protocol (RTTY, SSTV, etc.) may be used as well. + This example shows how to use your Arduino + as modulator for an external analogue FM radio. + + The example sends APRS position reports with + audio modulated as AFSK at 1200 baud using + Bell 202 tones. However, any other AFSK + protocol (RTTY, SSTV, etc.) may be used as well. - DO NOT transmit in APRS bands unless - you have a ham radio license! + DO NOT transmit in APRS bands unless + you have a ham radio license! - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino index 5b19bedfb6..c52dbe5f2a 100644 --- a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino +++ b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -1,21 +1,21 @@ /* - RadioLib AFSK Imperial March Example + RadioLib AFSK Imperial March Example - This example shows how to EXECUTE ORDER 66 + This example shows how to EXECUTE ORDER 66 - Other modules that can be used for AFSK: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/AFSK/AFSK_Imperial_March/melody.h b/examples/AFSK/AFSK_Imperial_March/melody.h index 2f70f12922..64023de9d6 100644 --- a/examples/AFSK/AFSK_Imperial_March/melody.h +++ b/examples/AFSK/AFSK_Imperial_March/melody.h @@ -1,7 +1,7 @@ /* - Note definitions, melody and melody-related functions - adapted from https://github.com/robsoncouto/arduino-songs - by Robson Couto, 2019 + Note definitions, melody and melody-related functions + adapted from https://github.com/robsoncouto/arduino-songs + by Robson Couto, 2019 */ #define NOTE_B0 31 diff --git a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino index ad6738a108..ace105017a 100644 --- a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino +++ b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -1,22 +1,22 @@ /* - RadioLib AFSK Example + RadioLib AFSK Example - This example shows hot to send audio FSK tones - using SX1278's FSK modem. + This example shows hot to send audio FSK tones + using SX1278's FSK modem. - Other modules that can be used for AFSK: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino b/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino index d11c8ad06b..3ae965baed 100644 --- a/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino +++ b/examples/AFSK/AFSK_Tone_AM/AFSK_Tone_AM.ino @@ -1,20 +1,20 @@ /* - RadioLib AM-modulated AFSK Example + RadioLib AM-modulated AFSK Example - This example shows hot to send AM-modulated - audio FSK tones using SX1278's OOK modem. + This example shows hot to send AM-modulated + audio FSK tones using SX1278's OOK modem. - Other modules that can be used for AFSK: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/APRS/APRS_MicE/APRS_MicE.ino b/examples/APRS/APRS_MicE/APRS_MicE.ino index 6500cac5b4..414f5f3310 100644 --- a/examples/APRS/APRS_MicE/APRS_MicE.ino +++ b/examples/APRS/APRS_MicE/APRS_MicE.ino @@ -1,28 +1,28 @@ /* - RadioLib APRS Mic-E Example - - This example sends APRS position reports - encoded in the Mic-E format using SX1278's - FSK modem. The data is modulated as AFSK - at 1200 baud using Bell 202 tones. - - DO NOT transmit in APRS bands unless - you have a ham radio license! - - Other modules that can be used for APRS: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - nRF24 - - Si443x/RFM2x - - SX126x/LLCC68 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib APRS Mic-E Example + + This example sends APRS position reports + encoded in the Mic-E format using SX1278's + FSK modem. The data is modulated as AFSK + at 1200 baud using Bell 202 tones. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + Other modules that can be used for APRS: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + - SX126x/LLCC68 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -35,9 +35,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index 4a43d37d54..e18804846c 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -1,28 +1,28 @@ /* - RadioLib APRS Position Example - - This example sends APRS position reports - using SX1278's FSK modem. The data is - modulated as AFSK at 1200 baud using Bell - 202 tones. - - DO NOT transmit in APRS bands unless - you have a ham radio license! - - Other modules that can be used for APRS: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - nRF24 - - Si443x/RFM2x - - SX126x/LLCC68 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib APRS Position Example + + This example sends APRS position reports + using SX1278's FSK modem. The data is + modulated as AFSK at 1200 baud using Bell + 202 tones. + + DO NOT transmit in APRS bands unless + you have a ham radio license! + + Other modules that can be used for APRS: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + - SX126x/LLCC68 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -35,9 +35,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino index 1a77aadbff..b1cf8ad779 100644 --- a/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino +++ b/examples/APRS/APRS_Position_LoRa/APRS_Position_LoRa.ino @@ -1,20 +1,20 @@ /* - RadioLib APRS Position over LoRa Example + RadioLib APRS Position over LoRa Example - This example sends APRS position reports - using SX1278's LoRa modem. + This example sends APRS position reports + using SX1278's LoRa modem. - Other modules that can be used for APRS: - - SX127x/RFM9x - - SX126x/LLCC68 - - SX128x - - LR11x0 + Other modules that can be used for APRS: + - SX127x/RFM9x + - SX126x/LLCC68 + - SX128x + - LR11x0 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -27,9 +27,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create APRS client instance using the LoRa radio APRSClient aprs(&radio); diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index 4c5fe47c11..256e587b4e 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -1,31 +1,31 @@ /* - RadioLib AX.25 Frame Example - - This example shows how to send various - AX.25 frames using SX1278's FSK modem. - - Other modules that can be used for AX.25: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - LR11x0 - - Using raw AX.25 frames requires some - knowledge of the protocol, refer to - AX25_Transmit for basic operation. - Frames shown in this example are not - exhaustive; all possible AX.25 frames - should be supported. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib AX.25 Frame Example + + This example shows how to send various + AX.25 frames using SX1278's FSK modem. + + Other modules that can be used for AX.25: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - LR11x0 + + Using raw AX.25 frames requires some + knowledge of the protocol, refer to + AX25_Transmit for basic operation. + Frames shown in this example are not + exhaustive; all possible AX.25 frames + should be supported. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -38,9 +38,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AX.25 client instance using the FSK module AX25Client ax25(&radio); diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index 1b0c754797..6d244ac260 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -1,24 +1,24 @@ /* - RadioLib AX.25 Transmit Example - - This example sends AX.25 messages using - SX1278's FSK modem. - - Other modules that can be used for AX.25: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - LR11x0 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib AX.25 Transmit Example + + This example sends AX.25 messages using + SX1278's FSK modem. + + Other modules that can be used for AX.25: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - LR11x0 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AX.25 client instance using the FSK module AX25Client ax25(&radio); diff --git a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino index 2b27bdc6c3..b2288e6964 100644 --- a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino +++ b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -1,25 +1,25 @@ /* - RadioLib AX.25 Transmit AFSK Example - - This example sends AX.25 messages using - SX1278's FSK modem. The data is modulated - as AFSK at 1200 baud using Bell 202 tones. - - Other modules that can be used for AX.25 - with AFSK modulation: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - nRF24 - - Si443x/RFM2x - - SX126x/LLCC68 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib AX.25 Transmit AFSK Example + + This example sends AX.25 messages using + SX1278's FSK modem. The data is modulated + as AFSK at 1200 baud using Bell 202 tones. + + Other modules that can be used for AX.25 + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + - SX126x/LLCC68 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -32,9 +32,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino index 4b0e600eb1..abd96d4d0f 100644 --- a/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino +++ b/examples/BellModem/BellModem_Transmit/BellModem_Transmit.ino @@ -1,18 +1,18 @@ /* - RadioLib Bell Modem Transmit Example + RadioLib Bell Modem Transmit Example - This example shows how to transmit binary data - using audio Bell 202 tones. + This example shows how to transmit binary data + using audio Bell 202 tones. - Other implemented Bell modems - - Bell 101 - - Bell 103 + Other implemented Bell modems + - Bell 101 + - Bell 103 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino index 9eeaca9b45..11a6988d3b 100644 --- a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino +++ b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino @@ -1,17 +1,17 @@ /* - RadioLib CC1101 Receive with Address Example + RadioLib CC1101 Receive with Address Example - This example receives packets using CC1101 FSK radio - module. Packets can have 1-byte address of the - destination node. After setting node address, this node - will automatically filter out any packets that do not - contain either node address or broadcast addresses. + This example receives packets using CC1101 FSK radio + module. Packets can have 1-byte address of the + destination node. After setting node address, this node + will automatically filter out any packets that do not + contain either node address or broadcast addresses. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -24,9 +24,13 @@ // GDO2 pin: 3 (optional) CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino b/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino index 11edd45cb2..e24189c314 100644 --- a/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino +++ b/examples/CC1101/CC1101_Receive_Blocking/CC1101_Receive_Blocking.ino @@ -31,9 +31,13 @@ // GDO2 pin: 3 (optional) CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 6b585fe507..1a6528d704 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -1,22 +1,22 @@ /* - RadioLib CC1101 Receive with Interrupts Example + RadioLib CC1101 Receive with Interrupts Example - This example listens for FSK transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bit rate - - frequency deviation - - sync word + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -29,9 +29,13 @@ // GDO2 pin: 3 (optional) CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino index 8ba03b13e7..c3423e4bcd 100644 --- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino +++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -1,21 +1,21 @@ /* - RadioLib CC1101 Settings Example - - This example shows how to change all the properties of RF69 radio. - RadioLib currently supports the following settings: - - pins (SPI slave select, digital IO 0, digital IO 1) - - carrier frequency - - bit rate - - receiver bandwidth - - allowed frequency deviation - - output power during transmission - - sync word - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib CC1101 Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, digital IO 0, digital IO 1) + - carrier frequency + - bit rate + - receiver bandwidth + - allowed frequency deviation + - output power during transmission + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -35,9 +35,13 @@ CC1101 radio1 = new Module(10, 2, RADIOLIB_NC, 3); // GDO2 pin: 5 (optional) CC1101 radio2 = new Module(9, 4, RADIOLIB_NC, 5); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio3 = RadioShield.ModuleB; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio3 = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index ecdec62080..37bc21f59e 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -1,17 +1,17 @@ /* - RadioLib CC1101 Transmit to Address Example + RadioLib CC1101 Transmit to Address Example - This example transmits packets using CC1101 FSK radio - module. Packets can have 1-byte address of the - destination node. After setting node address, this node - will automatically filter out any packets that do not - contain either node address or broadcast addresses. + This example transmits packets using CC1101 FSK radio + module. Packets can have 1-byte address of the + destination node. After setting node address, this node + will automatically filter out any packets that do not + contain either node address or broadcast addresses. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -24,9 +24,13 @@ // GDO2 pin: 3 (optional) CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index d42dbed626..52f4fb94cd 100644 --- a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -28,9 +28,13 @@ // GDO2 pin: 3 CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 4e4e2a1f71..049c9706b7 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -1,18 +1,18 @@ /* - RadioLib CC1101 Transmit with Interrupts Example + RadioLib CC1101 Transmit with Interrupts Example - This example transmits packets using CC1101 FSK radio module. - Once a packet is transmitted, an interrupt is triggered. - Each packet contains up to 64 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using CC1101 FSK radio module. + Once a packet is transmitted, an interrupt is triggered. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -25,9 +25,13 @@ // GDO2 pin: 3 CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//CC1101 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino index 088f318b37..d521b8a568 100644 --- a/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino +++ b/examples/FSK4/FSK4_Transmit/FSK4_Transmit.ino @@ -1,27 +1,27 @@ /* - RadioLib FSK4 Transmit Example + RadioLib FSK4 Transmit Example - This example sends an example FSK-4 'Horus Binary' message - using SX1278's FSK modem. + This example sends an example FSK-4 'Horus Binary' message + using SX1278's FSK modem. - This signal can be demodulated using a SSB demodulator (SDR or otherwise), - and horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki + This signal can be demodulated using a SSB demodulator (SDR or otherwise), + and horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki - Other modules that can be used for FSK4: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - SX128x + Other modules that can be used for FSK4: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -34,9 +34,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create FSK4 client instance using the FSK module FSK4Client fsk4(&radio); diff --git a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino index c31877b409..58cc7aa9d3 100644 --- a/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino +++ b/examples/FSK4/FSK4_Transmit_AFSK/FSK4_Transmit_AFSK.ino @@ -1,25 +1,25 @@ /* - RadioLib FSK4 Transmit AFSK Example + RadioLib FSK4 Transmit AFSK Example - This example sends an example FSK-4 'Horus Binary' message - using SX1278's FSK modem. The data is modulated as AFSK. + This example sends an example FSK-4 'Horus Binary' message + using SX1278's FSK modem. The data is modulated as AFSK. - This signal can be demodulated using an FM demodulator (SDR or otherwise), - and horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki + This signal can be demodulated using an FM demodulator (SDR or otherwise), + and horusdemodlib: https://github.com/projecthorus/horusdemodlib/wiki - Other modules that can be used for FSK4: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 + Other modules that can be used for FSK4: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -32,9 +32,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino index af480409d4..ceebc924f2 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -1,25 +1,25 @@ /* - RadioLib Hellschreiber Transmit Example - - This example sends Hellschreiber message using - SX1278's FSK modem. - - Other modules that can be used for Hellschreiber: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - SX128x - - LR11x0 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib Hellschreiber Transmit Example + + This example sends Hellschreiber message using + SX1278's FSK modem. + + Other modules that can be used for Hellschreiber: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + - LR11x0 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -32,9 +32,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create Hellschreiber client instance using the FSK module HellClient hell(&radio); diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino index 77feff0d16..14fb049a66 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -1,24 +1,24 @@ /* - RadioLib Hellschreiber Transmit AFSK Example - - This example sends Hellschreiber message using - SX1278's FSK modem. The data is modulated - as AFSK. - - Other modules that can be used for Hellschreiber - with AFSK modulation: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib Hellschreiber Transmit AFSK Example + + This example sends Hellschreiber message using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for Hellschreiber + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino index 636b488f24..81b3f7bd57 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -34,6 +34,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index d4a79299f4..304bbc9d92 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -29,6 +29,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino index 8813b1daeb..03296fb480 100644 --- a/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino +++ b/examples/LR11x0/LR11x0_Firmware_Update/LR11x0_Firmware_Update.ino @@ -48,9 +48,13 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino index b49d394ee9..85e7bd4522 100644 --- a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino +++ b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino @@ -26,9 +26,13 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino b/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino index 964e865f8e..444ee65740 100644 --- a/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino +++ b/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino @@ -33,6 +33,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // structure to save information about the GNSS almanac LR11x0GnssAlmanacStatus_t almStatus; diff --git a/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino b/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino index 84a40aa07f..800a21b85e 100644 --- a/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino +++ b/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino @@ -29,6 +29,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // structure to save information about the GNSS scan result LR11x0GnssResult_t gnssResult; diff --git a/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino b/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino index 4104a23ffc..bd84bc4573 100644 --- a/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino +++ b/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino @@ -29,6 +29,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // structure to save information about the GNSS scan result LR11x0GnssResult_t gnssResult; diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino index b858c9639f..a7de634dae 100644 --- a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -27,9 +27,13 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//LR1110 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino b/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino index b494a3c2d4..b6b5e08de2 100644 --- a/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino +++ b/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino @@ -22,6 +22,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino index cf0736ffe4..aeb40679f5 100644 --- a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -39,6 +39,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index 4b9b946f1c..76b8919fb0 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -35,6 +35,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index 92045bdc10..bad54bd1d0 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -30,6 +30,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 67f5052b0d..2efdc263d9 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -31,6 +31,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino index 1e07ffd298..53bafd36bd 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino @@ -32,6 +32,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino index fdf08a9c65..fcae902a7a 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -32,6 +32,14 @@ // BUSY pin: 9 LR1110 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // set RF switch configuration for Wio WM1110 // Wio WM1110 uses DIO5 and DIO6 for RF switching // NOTE: other boards may be different! diff --git a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino index 3b96d6386c..e4fb4037a6 100644 --- a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino +++ b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino @@ -1,23 +1,23 @@ /* - RadioLib SX127x Morse Receive AM Example + RadioLib SX127x Morse Receive AM Example - This example receives Morse code message using - SX1278's FSK modem. The signal is expected to be - modulated as OOK, to be demodulated in AM mode. + This example receives Morse code message using + SX1278's FSK modem. The signal is expected to be + modulated as OOK, to be demodulated in AM mode. - Other modules that can be used for Morse Code - with AFSK modulation: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x + Other modules that can be used for Morse Code + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -30,9 +30,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // pin 5 is connected to SX1278 DIO2 diff --git a/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino b/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino index 3aeae2c97d..b81ba86176 100644 --- a/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino +++ b/examples/Morse/Morse_Transmit_AM/Morse_Transmit_AM.ino @@ -1,23 +1,23 @@ /* - RadioLib Morse Transmit AM Example + RadioLib Morse Transmit AM Example - This example sends Morse code message using - SX1278's FSK modem. The signal is modulated - as OOK, and may be demodulated in AM mode. + This example sends Morse code message using + SX1278's FSK modem. The signal is modulated + as OOK, and may be demodulated in AM mode. - Other modules that can be used for Morse Code - with AM modulation: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x + Other modules that can be used for Morse Code + with AM modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -30,9 +30,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // pin 5 is connected to SX1278 DIO2 diff --git a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino index de955cc624..b4ba7865f0 100644 --- a/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino +++ b/examples/Morse/Morse_Transmit_FM/Morse_Transmit_FM.ino @@ -1,24 +1,24 @@ /* - RadioLib Morse Transmit AFSK Example - - This example sends Morse code message using - SX1278's FSK modem. The signal is modulated - as AFSK, and may be demodulated in FM mode. - - Other modules that can be used for Morse Code - with AFSK modulation: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib Morse Transmit AFSK Example + + This example sends Morse code message using + SX1278's FSK modem. The signal is modulated + as AFSK, and may be demodulated in FM mode. + + Other modules that can be used for Morse Code + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino index cbc027969b..f7615e2006 100644 --- a/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino +++ b/examples/Morse/Morse_Transmit_SSB/Morse_Transmit_SSB.ino @@ -1,26 +1,26 @@ /* - RadioLib Morse Transmit SSB Example - - This example sends Morse code message using - SX1278's FSK modem. The signal is an unmodulated - carrier wave, and may be demodulated in SSB mode. - - Other modules that can be used for Morse Code: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - SX128x - - LR11x0 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib Morse Transmit SSB Example + + This example sends Morse code message using + SX1278's FSK modem. The signal is an unmodulated + carrier wave, and may be demodulated in SSB mode. + + Other modules that can be used for Morse Code: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + - LR11x0 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -33,9 +33,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create Morse client instance using the FSK module MorseClient morse(&radio); diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino index 9eabeb63be..edc97867f7 100644 --- a/examples/Pager/Pager_Receive/Pager_Receive.ino +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -1,24 +1,24 @@ /* - RadioLib Pager (POCSAG) Receive Example + RadioLib Pager (POCSAG) Receive Example - This example shows how to receive FSK packets without using - SX127x packet engine. + This example shows how to receive FSK packets without using + SX127x packet engine. - This example receives POCSAG messages using SX1278's - FSK modem in direct mode. + This example receives POCSAG messages using SX1278's + FSK modem in direct mode. - Other modules that can be used to receive POCSAG: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x + Other modules that can be used to receive POCSAG: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -45,9 +45,13 @@ const int pin = 5; // create Pager client instance using the FSK module PagerClient pager(&radio); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/examples/Pager/Pager_Transmit/Pager_Transmit.ino index 6bb331ddb1..3677fc781f 100644 --- a/examples/Pager/Pager_Transmit/Pager_Transmit.ino +++ b/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -1,24 +1,24 @@ /* - RadioLib Pager (POCSAG) Transmit Example - - This example sends POCSAG messages using SX1278's - FSK modem. - - Other modules that can be used to send POCSAG: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - SX128x - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib Pager (POCSAG) Transmit Example + + This example sends POCSAG messages using SX1278's + FSK modem. + + Other modules that can be used to send POCSAG: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create Pager client instance using the FSK module PagerClient pager(&radio); diff --git a/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino b/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino index b56da33f12..cdea9d9159 100644 --- a/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino +++ b/examples/PhysicalLayer/PhysicalLayer_Interface/PhysicalLayer_Interface.ino @@ -1,12 +1,12 @@ /* - RadioLib PhysicalLayer Interface Example + RadioLib PhysicalLayer Interface Example - This example shows how to use the common PhysicalLayer - to interface with different radio modules using the same - methods. + This example shows how to use the common PhysicalLayer + to interface with different radio modules using the same + methods. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,6 +23,14 @@ // extra GPIO/interrupt pin: 3 (unused on some modules) RADIO_TYPE radio = new Module(10, 2, 9, 3); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // get pointer to the common layer PhysicalLayer* phy = (PhysicalLayer*)&radio; diff --git a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino index 857a84fdc4..62d1dca3e0 100644 --- a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino +++ b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino @@ -1,15 +1,15 @@ /* - RadioLib RF69 Receive with AES Example + RadioLib RF69 Receive with AES Example - This example receives packets using RF69 FSK radio module. - Packets are decrypted using hardware AES. - NOTE: When using address filtering, the address byte is NOT encrypted! + This example receives packets using RF69 FSK radio module. + Packets are decrypted using hardware AES. + NOTE: When using address filtering, the address byte is NOT encrypted! - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -21,9 +21,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino index 37b196e6eb..f8d1fe91d6 100644 --- a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino +++ b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino @@ -1,17 +1,17 @@ /* - RadioLib RF69 Receive with Address Example + RadioLib RF69 Receive with Address Example - This example receives packets using RF69 FSK radio module. - Packets can have 1-byte address of the destination node. - After setting node (or broadcast) address, this node will - automatically filter out any packets that do not contain - either node address or broadcast address. + This example receives packets using RF69 FSK radio module. + Packets can have 1-byte address of the destination node. + After setting node (or broadcast) address, this node will + automatically filter out any packets that do not contain + either node address or broadcast address. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,9 +23,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino b/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino index 6b2c02240e..66f9aab550 100644 --- a/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino +++ b/examples/RF69/RF69_Receive_Blocking/RF69_Receive_Blocking.ino @@ -30,9 +30,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index b44ac50223..4678525e69 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -1,15 +1,15 @@ /* - RadioLib RF69 Receive with Interrupts Example + RadioLib RF69 Receive with Interrupts Example - This example listens for FSK transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -21,9 +21,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Settings/RF69_Settings.ino b/examples/RF69/RF69_Settings/RF69_Settings.ino index f3d6f7f567..f8729d207a 100644 --- a/examples/RF69/RF69_Settings/RF69_Settings.ino +++ b/examples/RF69/RF69_Settings/RF69_Settings.ino @@ -1,21 +1,21 @@ /* - RadioLib RF69 Settings Example - - This example shows how to change all the properties of RF69 radio. - RadioLib currently supports the following settings: - - pins (SPI slave select, digital IO 0, digital IO 1) - - carrier frequency - - bit rate - - receiver bandwidth - - allowed frequency deviation - - output power during transmission - - sync word - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib RF69 Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, digital IO 0, digital IO 1) + - carrier frequency + - bit rate + - receiver bandwidth + - allowed frequency deviation + - output power during transmission + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -33,9 +33,13 @@ RF69 radio1 = new Module(10, 2, 3); // RESET pin: 5 RF69 radio2 = new Module(9, 4, 5); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio3 = RadioShield.ModuleB; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio3 = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino index 6ef73915a3..4c311a9ea5 100644 --- a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino +++ b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino @@ -1,15 +1,15 @@ /* - RadioLib RF69 Transmit with AES Example + RadioLib RF69 Transmit with AES Example - This example transmits packets using RF69 FSK radio module. - Packets are encrypted using hardware AES. - NOTE: When using address filtering, the address byte is NOT encrypted! + This example transmits packets using RF69 FSK radio module. + Packets are encrypted using hardware AES. + NOTE: When using address filtering, the address byte is NOT encrypted! - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -21,9 +21,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino index ea3dfe3347..6604c033b7 100644 --- a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino +++ b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino @@ -1,17 +1,17 @@ /* - RadioLib RF69 Transmit to Address Example + RadioLib RF69 Transmit to Address Example - This example transmits packets using RF69 FSK radio module. - Packets can have 1-byte address of the destination node. - After setting node (or broadcast) address, this node will - automatically filter out any packets that do not contain - either node address or broadcast address. + This example transmits packets using RF69 FSK radio module. + Packets can have 1-byte address of the destination node. + After setting node (or broadcast) address, this node will + automatically filter out any packets that do not contain + either node address or broadcast address. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,9 +23,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino index 78a2bac947..fa70a7ad86 100644 --- a/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino +++ b/examples/RF69/RF69_Transmit_Blocking/RF69_Transmit_Blocking.ino @@ -27,9 +27,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 0eacb13dcf..c4de787540 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -1,18 +1,18 @@ /* - RadioLib RF69 Transmit with Interrupts Example + RadioLib RF69 Transmit with Interrupts Example - This example transmits FSK packets with one second delays - between them. Each packet contains up to 64 bytes - of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits FSK packets with one second delays + between them. Each packet contains up to 64 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -24,9 +24,13 @@ // RESET pin: 3 RF69 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//RF69 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index 3c5a74bdff..f839d878b0 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -1,25 +1,25 @@ /* - RadioLib RTTY Transmit Example - - This example sends RTTY message using SX1278's - FSK modem. - - Other modules that can be used for RTTY: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - SX126x - - nRF24 - - Si443x/RFM2x - - SX128x - - LR11x0 - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib RTTY Transmit Example + + This example sends RTTY message using SX1278's + FSK modem. + + Other modules that can be used for RTTY: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x + - LR11x0 + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -32,9 +32,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create RTTY client instance using the FSK module RTTYClient rtty(&radio); diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino index cbeb0fe157..2d8830cf1e 100644 --- a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -1,22 +1,22 @@ /* - RadioLib RTTY Transmit AFSK Example + RadioLib RTTY Transmit AFSK Example - This example sends RTTY message using SX1278's - FSK modem. The data is modulated as AFSK. + This example sends RTTY message using SX1278's + FSK modem. The data is modulated as AFSK. - Other modules that can be used for RTTY: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 + Other modules that can be used for RTTY: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -29,9 +29,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino index 46ec78a968..cf072c403a 100644 --- a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino +++ b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -1,35 +1,35 @@ /* - RadioLib SSTV Transmit Example - - The following example sends SSTV picture using - SX1278's FSK modem. - - Other modules that can be used for SSTV: - - SX127x/RFM9x - - RF69 - - SX1231 - - SX126x - - NOTE: SSTV is an analog modulation, and - requires precise frequency control. - Some of the above modules can only - set their frequency in rough steps, - so the result can be distorted. - Using high-precision radio with TCXO - (like SX126x) is recommended. - - NOTE: Some platforms (such as Arduino Uno) - might not be fast enough to correctly - send pictures via high-speed modes - like Scottie2 or Martin2. For those, - lower speed modes such as Wrasse, - Scottie1 or Martin1 are recommended. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SSTV Transmit Example + + The following example sends SSTV picture using + SX1278's FSK modem. + + Other modules that can be used for SSTV: + - SX127x/RFM9x + - RF69 + - SX1231 + - SX126x + + NOTE: SSTV is an analog modulation, and + requires precise frequency control. + Some of the above modules can only + set their frequency in rough steps, + so the result can be distorted. + Using high-precision radio with TCXO + (like SX126x) is recommended. + + NOTE: Some platforms (such as Arduino Uno) + might not be fast enough to correctly + send pictures via high-speed modes + like Scottie2 or Martin2. For those, + lower speed modes such as Wrasse, + Scottie1 or Martin1 are recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -42,9 +42,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create SSTV client instance using the FSK module SSTVClient sstv(&radio); diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino index 85fe8de571..667c436177 100644 --- a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -1,31 +1,31 @@ /* - RadioLib SSTV Transmit AFSK Example - - The following example sends SSTV picture using - SX1278's FSK modem. The data is modulated - as AFSK. - - Other modules that can be used for SSTV: - with AFSK modulation: - - SX127x/RFM9x - - RF69 - - SX1231 - - CC1101 - - Si443x/RFM2x - - SX126x/LLCC68 - - NOTE: Some platforms (such as Arduino Uno) - might not be fast enough to correctly - send pictures via high-speed modes - like Scottie2 or Martin2. For those, - lower speed modes such as Wrasse, - Scottie1 or Martin1 are recommended. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SSTV Transmit AFSK Example + + The following example sends SSTV picture using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for SSTV: + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + - SX126x/LLCC68 + + NOTE: Some platforms (such as Arduino Uno) + might not be fast enough to correctly + send pictures via high-speed modes + like Scottie2 or Martin2. For those, + lower speed modes such as Wrasse, + Scottie1 or Martin1 are recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -38,9 +38,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // create AFSK client instance using the FSK module // this requires connection to the module direct diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino index 0c4f9b8140..20401e9e82 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection/STM32WLx_Channel_Activity_Detection.ino @@ -1,16 +1,16 @@ /* - RadioLib STM32WLx Channel Activity Detection Example + RadioLib STM32WLx Channel Activity Detection Example - This example uses STM32WLx to scan the current LoRa - channel and detect ongoing LoRa transmissions. - Unlike SX127x CAD, SX126x/STM32WLx can detect any part - of LoRa transmission, not just the preamble. + This example uses STM32WLx to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x/STM32WLx can detect any part + of LoRa transmission, not just the preamble. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino index 4475a49647..1a0e390a6f 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -1,16 +1,16 @@ /* - RadioLib STM32WLx Channel Activity Detection Example + RadioLib STM32WLx Channel Activity Detection Example - This example uses STM32WLx to scan the current LoRa - channel and detect ongoing LoRa transmissions. - Unlike SX127x CAD, SX126x/STM32WLx can detect any part - of LoRa transmission, not just the preamble. + This example uses STM32WLx to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x/STM32WLx can detect any part + of LoRa transmission, not just the preamble. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index 1fb31ddbe2..fe203f2ac9 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -1,26 +1,26 @@ /* - RadioLib STM32WLx Receive with Interrupts Example - - This example listens for LoRa transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. To successfully receive data, the following - settings have to be the same on both transmitter - and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - This example assumes Nucleo WL55JC1 is used. For other Nucleo boards - or standalone STM32WL, some configuration such as TCXO voltage and - RF switch control may have to be adjusted. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib STM32WLx Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + This example assumes Nucleo WL55JC1 is used. For other Nucleo boards + or standalone STM32WL, some configuration such as TCXO voltage and + RF switch control may have to be adjusted. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library diff --git a/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino b/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino index 66978b6bef..896e1ba752 100644 --- a/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino +++ b/examples/SX123x/SX123x_Receive_Blocking/SX123x_Receive_Blocking.ino @@ -29,9 +29,13 @@ // RESET pin: 3 SX1231 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1231 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino b/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino index 50bbe1bf43..fd86924554 100644 --- a/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino +++ b/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino @@ -28,9 +28,13 @@ // RESET pin: 3 SX1231 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1231 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino index 17d6b9f081..8c668e1a19 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Blocking/SX126x_Channel_Activity_Detection_Blocking.ino @@ -30,12 +30,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index 0d0f45cd1d..c47b4b2878 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -1,18 +1,18 @@ /* - RadioLib SX126x Channel Activity Detection Example + RadioLib SX126x Channel Activity Detection Example - This example uses SX1262 to scan the current LoRa - channel and detect ongoing LoRa transmissions. - Unlike SX127x CAD, SX126x can detect any part - of LoRa transmission, not just the preamble. + This example uses SX1262 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, SX126x can detect any part + of LoRa transmission, not just the preamble. - Other modules from SX126x family can also be used. + Other modules from SX126x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -25,12 +25,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino index 6b68227e9e..ec89de086a 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino @@ -27,12 +27,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index 93a18b65be..9bffbeeed0 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -1,19 +1,19 @@ /* - RadioLib SX126x FSK Modem Example + RadioLib SX126x FSK Modem Example - This example shows how to use FSK modem in SX126x chips. + This example shows how to use FSK modem in SX126x chips. - NOTE: The sketch below is just a guide on how to use - FSK modem, so this code should not be run directly! - Instead, modify the other examples to use FSK - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + FSK modem, so this code should not be run directly! + Instead, modify the other examples to use FSK + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---fsk-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---fsk-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -26,12 +26,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino index d0f45f8d86..9b2794476a 100644 --- a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino +++ b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino @@ -27,12 +27,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino index 0ec708c899..ff409f34ce 100644 --- a/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino +++ b/examples/SX126x/SX126x_PingPong/SX126x_PingPong.ino @@ -1,11 +1,14 @@ /* - RadioLib SX126x Ping-Pong Example + RadioLib SX126x Ping-Pong Example - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + This example is intended to run on two SX126x radios, + and send packets between the two. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -22,12 +25,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission states between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino b/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino index 0dee95333d..a1641ed268 100644 --- a/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino +++ b/examples/SX126x/SX126x_Receive_Blocking/SX126x_Receive_Blocking.ino @@ -1,28 +1,28 @@ /* - RadioLib SX126x Blocking Receive Example - - This example listens for LoRa transmissions using SX126x Lora modules. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - preamble length - - Other modules from SX126x family can also be used. - - Using blocking receive is not recommended, as it will lead - to significant amount of timeouts, inefficient use of processor - time and can some miss packets! - Instead, interrupt receive is recommended. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX126x Blocking Receive Example + + This example listens for LoRa transmissions using SX126x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from SX126x family can also be used. + +Using blocking receive is not recommended, as it will lead +to significant amount of timeouts, inefficient use of processor +time and can some miss packets! +Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -35,12 +35,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 017c78cdee..42e27f2842 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -1,24 +1,24 @@ /* - RadioLib SX126x Receive with Interrupts Example - - This example listens for LoRa transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. To successfully receive data, the following - settings have to be the same on both transmitter - and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - Other modules from SX126x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX126x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,12 +31,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index 287403982c..71a4d8fb62 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -1,27 +1,27 @@ /* - RadioLib SX126x Settings Example - - This example shows how to change all the properties of LoRa transmission. - RadioLib currently supports the following settings: - - pins (SPI slave select, DIO1, DIO2, BUSY pin) - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - output power during transmission - - CRC - - preamble length - - TCXO voltage - - DIO2 RF switch control - - Other modules from SX126x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX126x Settings Example + + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, DIO1, DIO2, BUSY pin) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - output power during transmission + - CRC + - preamble length + - TCXO voltage + - DIO2 RF switch control + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -41,12 +41,13 @@ SX1262 radio1 = new Module(10, 2, 3, 9); // BUSY pin: 6 SX1268 radio2 = new Module(8, 4, 5, 6); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1261 radio3 = RadioShield.ModuleB; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio3 = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino index 987f4655c6..bf28f36a44 100644 --- a/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino +++ b/examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino @@ -1,24 +1,24 @@ /* - RadioLib SX126x Spectrum Scan Example + RadioLib SX126x Spectrum Scan Example - This example shows how to perform a spectrum power scan using SX126x. - The output is in the form of scan lines, each line has 33 power bins. - First power bin corresponds to -11 dBm, the second to -15 dBm and so on. - Higher number of samples in a bin corresponds to more power received - at that level. + This example shows how to perform a spectrum power scan using SX126x. + The output is in the form of scan lines, each line has 33 power bins. + First power bin corresponds to -11 dBm, the second to -15 dBm and so on. + Higher number of samples in a bin corresponds to more power received + at that level. - To show the results in a plot, run the Python script - RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py + To show the results in a plot, run the Python script + RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py - WARNING: This functionality is experimental and requires a binary patch - to be uploaded to the SX126x device. There may be some undocumented - side effects! + WARNING: This functionality is experimental and requires a binary patch + to be uploaded to the SX126x device. There may be some undocumented + side effects! - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -34,6 +34,14 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + void setup() { Serial.begin(115200); diff --git a/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino b/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino index f5de4607c1..71d3445ab2 100644 --- a/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino +++ b/examples/SX126x/SX126x_Spectrum_Scan_Frequency/SX126x_Spectrum_Scan_Frequency.ino @@ -1,24 +1,24 @@ /* - RadioLib SX126x Spectrum Scan Example + RadioLib SX126x Spectrum Scan Example - This example shows how to perform a spectrum power scan using SX126x. - The output is in the form of scan lines, each line has 33 power bins. - First power bin corresponds to -11 dBm, the second to -15 dBm and so on. - Higher number of samples in a bin corresponds to more power received - at that level. The example performs frequency sweep over a given range. + This example shows how to perform a spectrum power scan using SX126x. + The output is in the form of scan lines, each line has 33 power bins. + First power bin corresponds to -11 dBm, the second to -15 dBm and so on. + Higher number of samples in a bin corresponds to more power received + at that level. The example performs frequency sweep over a given range. - To show the results in a plot, run the Python script - RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py + To show the results in a plot, run the Python script + RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py - WARNING: This functionality is experimental and requires a binary patch - to be uploaded to the SX126x device. There may be some undocumented - side effects! + WARNING: This functionality is experimental and requires a binary patch + to be uploaded to the SX126x device. There may be some undocumented + side effects! - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -34,6 +34,14 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + // frequency range in MHz to scan const float freqStart = 431; const float freqEnd = 435; diff --git a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino index e090ef8e43..c222e2ff28 100644 --- a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino +++ b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino @@ -30,12 +30,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 5f0b9ea1a2..1acf3ee1a3 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -27,12 +27,13 @@ // BUSY pin: 9 SX1262 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1262 radio = RadioShield.ModuleA; - -// or using CubeCell -//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE); +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino index ebd3ed32f1..c88d934e83 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Blocking/SX127x_Channel_Activity_Detection_Blocking.ino @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index edb01aa4f7..95070e0ec9 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -1,19 +1,19 @@ /* - RadioLib SX127x Channel Activity Detection with Interrupts Example + RadioLib SX127x Channel Activity Detection with Interrupts Example - This example scans the current LoRa channel and detects - valid LoRa preambles. Preamble is the first part of - LoRa transmission, so this can be used to check - if the LoRa channel is free, or if you should start - receiving a message. + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -26,9 +26,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { // Serial port speed must be high enough for this example diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino index f78d747a47..9b03d2e207 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -1,24 +1,24 @@ /* - RadioLib SX127x Receive after Channel Activity Detection Example - - This example scans the current LoRa channel and detects - valid LoRa preambles. Preamble is the first part of - LoRa transmission, so this can be used to check - if the LoRa channel is free, or if you should start - receiving a message. If a preamble is detected, - the module will switch to receive mode and receive the packet. - - For most use-cases, it should be enough to just use the - interrupt-driven reception described in the example - "SX127x_Receive_Interrupt". - - Other modules from SX127x/RFM9x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX127x Receive after Channel Activity Detection Example + + This example scans the current LoRa channel and detects + valid LoRa preambles. Preamble is the first part of + LoRa transmission, so this can be used to check + if the LoRa channel is free, or if you should start + receiving a message. If a preamble is detected, + the module will switch to receive mode and receive the packet. + + For most use-cases, it should be enough to just use the + interrupt-driven reception described in the example + "SX127x_Receive_Interrupt". + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { // Serial port speed must be high enough for this example diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index 49617884c9..0dae88c896 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -1,19 +1,19 @@ /* - RadioLib SX127x FSK Modem Example + RadioLib SX127x FSK Modem Example - This example shows how to use FSK modem in SX127x chips. + This example shows how to use FSK modem in SX127x chips. - NOTE: The sketch below is just a guide on how to use - FSK modem, so this code should not be run directly! - Instead, modify the other examples to use FSK - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + FSK modem, so this code should not be run directly! + Instead, modify the other examples to use FSK + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---fsk-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---fsk-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -26,9 +26,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index 0e191f204f..eb2cc04c87 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -1,11 +1,14 @@ /* - RadioLib SX127x Ping-Pong Example + RadioLib SX127x Ping-Pong Example - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + This example is intended to run on two SX126x radios, + and send packets between the two. - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -22,9 +25,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission states between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino b/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino index b2a1e30218..d52eef5327 100644 --- a/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino +++ b/examples/SX127x/SX127x_Receive_Blocking/SX127x_Receive_Blocking.ino @@ -35,9 +35,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino index d622a2a227..f41493b2a8 100644 --- a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino +++ b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino @@ -1,14 +1,14 @@ /* - RadioLib SX127x Direct Receive Example + RadioLib SX127x Direct Receive Example - This example shows how to receive FSK packets without using - SX127x packet engine. + This example shows how to receive FSK packets without using + SX127x packet engine. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -24,9 +24,13 @@ SX1278 radio = new Module(10, 2, 9, 3); // DIO2 pin: 5 const int pin = 5; -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index ede24586f0..c17cd34367 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -1,24 +1,24 @@ /* - RadioLib SX127x Transmit with Frequency Hopping Example + RadioLib SX127x Transmit with Frequency Hopping Example - This example transmits packets using SX1278 LoRa radio module. - Each packet contains up to 256 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ - SX127x supports FHSS or Frequency Hopping Spread Spectrum. - Once a hopping period is set and a transmission is started, the radio - will begin triggering interrupts every hop period where the radio frequency - is changed to the next channel. + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. */ #include @@ -30,9 +30,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // flag to indicate that a packet was received volatile bool receivedFlag = false; diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 5d2adbffa7..451e4192e4 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -1,24 +1,24 @@ /* - RadioLib SX127x Receive with Interrupts Example - - This example listens for LoRa transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. To successfully receive data, the following - settings have to be the same on both transmitter - and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - Other modules from SX127x/RFM9x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX127x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino index 6fbc631b5a..aee08ff1a4 100644 --- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino +++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -1,23 +1,23 @@ /* - RadioLib SX127x Settings Example + RadioLib SX127x Settings Example - This example shows how to change all the properties of LoRa transmission. - RadioLib currently supports the following settings: - - pins (SPI slave select, digital IO 0, digital IO 1) - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - output power during transmission + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, digital IO 0, digital IO 1) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - output power during transmission - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -37,9 +37,13 @@ SX1278 radio1 = new Module(10, 2, 9, 3); // DIO1 pin: 6 SX1272 radio2 = new Module(9, 4, 5, 6); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1276 radio3 = RadioShield.ModuleB; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio3 = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino index e5b258e3eb..62264ef84a 100644 --- a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino +++ b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino @@ -30,9 +30,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index d7210af6d1..dac0ce16fc 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -1,24 +1,24 @@ /* - RadioLib SX127x Transmit with Frequency Hopping Example + RadioLib SX127x Transmit with Frequency Hopping Example - This example transmits packets using SX1278 LoRa radio module. - Each packet contains up to 255 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 255 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Other modules from SX127x/RFM9x family can also be used. + Other modules from SX127x/RFM9x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ - SX127x supports FHSS or Frequency Hopping Spread Spectrum. - Once a hopping period is set and a transmission is started, the radio - will begin triggering interrupts every hop period where the radio frequency - is changed to the next channel. + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. */ #include @@ -30,9 +30,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // flag to indicate that a packet was received volatile bool transmittedFlag = false; diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 7b78080e39..22785d7681 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -27,9 +27,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino index be6b8266c9..04767da039 100644 --- a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino +++ b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -1,21 +1,21 @@ /* - RadioLib SX128x BLE Modem Example + RadioLib SX128x BLE Modem Example - This example shows how to use BLE modem in SX128x chips. - RadioLib does not provide BLE protocol support (yet), - only compatibility with the physical layer. + This example shows how to use BLE modem in SX128x chips. + RadioLib does not provide BLE protocol support (yet), + only compatibility with the physical layer. - NOTE: The sketch below is just a guide on how to use - BLE modem, so this code should not be run directly! - Instead, modify the other examples to use BLE - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + BLE modem, so this code should not be run directly! + Instead, modify the other examples to use BLE + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---ble-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---ble-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -28,9 +28,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino index 91ab462e8e..e12a08b5c0 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Blocking/SX128x_Channel_Activity_Detection_Blocking.ino @@ -28,9 +28,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino index da0d8f7377..8a57e181b3 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino @@ -1,16 +1,16 @@ /* - RadioLib SX128x Channel Activity Detection Example + RadioLib SX128x Channel Activity Detection Example - This example uses SX1280 to scan the current LoRa - channel and detect ongoing LoRa transmissions. + This example uses SX1280 to scan the current LoRa + channel and detect ongoing LoRa transmissions. - Other modules from SX128x family can also be used. + Other modules from SX128x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For default module settings, see the wiki page +https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,9 +23,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino index 3216d36586..fb6bb1a59c 100644 --- a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino +++ b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino @@ -1,19 +1,19 @@ /* - RadioLib SX128x FLRC Modem Example + RadioLib SX128x FLRC Modem Example - This example shows how to use FLRC modem in SX128x chips. + This example shows how to use FLRC modem in SX128x chips. - NOTE: The sketch below is just a guide on how to use - FLRC modem, so this code should not be run directly! - Instead, modify the other examples to use FLRC - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + FLRC modem, so this code should not be run directly! + Instead, modify the other examples to use FLRC + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---flrc-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---flrc-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -26,9 +26,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino index 447abf9ae7..05c8e6c2b3 100644 --- a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -1,19 +1,19 @@ /* - RadioLib SX128x GFSK Modem Example + RadioLib SX128x GFSK Modem Example - This example shows how to use GFSK modem in SX128x chips. + This example shows how to use GFSK modem in SX128x chips. - NOTE: The sketch below is just a guide on how to use - GFSK modem, so this code should not be run directly! - Instead, modify the other examples to use GFSK - modem and use the appropriate configuration - methods. + NOTE: The sketch below is just a guide on how to use + GFSK modem, so this code should not be run directly! + Instead, modify the other examples to use GFSK + modem and use the appropriate configuration + methods. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---gfsk-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---gfsk-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -26,9 +26,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino index f69dfa98ae..9f6a92b650 100644 --- a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino +++ b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -1,21 +1,21 @@ /* - RadioLib SX128x Ranging Example + RadioLib SX128x Ranging Example - This example performs ranging exchange between two - SX1280 LoRa radio modules. Ranging allows to measure - distance between the modules using time-of-flight - measurement. + This example performs ranging exchange between two + SX1280 LoRa radio modules. Ranging allows to measure + distance between the modules using time-of-flight + measurement. - Only SX1280 and SX1282 without external RF switch support ranging! + Only SX1280 and SX1282 without external RF switch support ranging! - Note that to get accurate ranging results, calibration is needed! - The process is described in Semtech SX1280 Application Note AN1200.29 + Note that to get accurate ranging results, calibration is needed! + The process is described in Semtech SX1280 Application Note AN1200.29 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -28,9 +28,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino b/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino index 024c99f9e9..809b2c4a3a 100644 --- a/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino +++ b/examples/SX128x/SX128x_Receive_Blocking/SX128x_Receive_Blocking.ino @@ -35,9 +35,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index ca63cb78f1..0ca0406cab 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -1,24 +1,24 @@ /* - RadioLib SX128x Receive with Interrupts Example - - This example listens for LoRa transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. To successfully receive data, the following - settings have to be the same on both transmitter - and receiver: - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - sync word - - Other modules from SX128x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX128x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX128x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino index eb29c119c0..5792dc07e9 100644 --- a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino +++ b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -1,24 +1,24 @@ /* - RadioLib SX128x Settings Example - - This example shows how to change all the properties of LoRa transmission. - RadioLib currently supports the following settings: - - pins (SPI slave select, DIO1, DIO2, BUSY pin) - - carrier frequency - - bandwidth - - spreading factor - - coding rate - - output power during transmission - - CRC - - preamble length - - Other modules from SX128x family can also be used. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib SX128x Settings Example + + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, DIO1, DIO2, BUSY pin) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - output power during transmission + - CRC + - preamble length + + Other modules from SX128x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -38,9 +38,13 @@ SX1280 radio1 = new Module(10, 2, 3, 9); // BUSY pin: 6 SX1281 radio2 = new Module(8, 4, 5, 6); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1282 radio3 = RadioShield.ModuleB; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio3 = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino index 2727555d69..ea0fb169b8 100644 --- a/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino +++ b/examples/SX128x/SX128x_Transmit_Blocking/SX128x_Transmit_Blocking.ino @@ -30,9 +30,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 17d462a100..1c760d5a23 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -27,9 +27,13 @@ // BUSY pin: 9 SX1280 radio = new Module(10, 2, 3, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1280 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino b/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino index 821be023e9..8ab9942bcc 100644 --- a/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino +++ b/examples/Si443x/Si443x_Receive_Blocking/Si443x_Receive_Blocking.ino @@ -32,9 +32,13 @@ // SDN pin: 9 Si4432 radio = new Module(10, 2, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//Si4432 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index b3e1c9a744..45f18179fc 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -1,17 +1,17 @@ /* - RadioLib Si443x Receive with Interrupts Example + RadioLib Si443x Receive with Interrupts Example - This example listens for FSK transmissions and tries to - receive them. Once a packet is received, an interrupt is - triggered. + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. - Other modules from Si443x/RFM2x family can also be used. + Other modules from Si443x/RFM2x family can also be used. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,9 +23,13 @@ // SDN pin: 9 Si4432 radio = new Module(10, 2, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//Si4432 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino index ab911e5867..39a9dbe274 100644 --- a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino +++ b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino @@ -1,21 +1,21 @@ /* - RadioLib Si443x Settings Example - - This example shows how to change all the properties of RF69 radio. - RadioLib currently supports the following settings: - - pins (SPI slave select, nIRQ, shutdown) - - carrier frequency - - bit rate - - receiver bandwidth - - frequency deviation - - output power during transmission - - sync word - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib Si443x Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, nIRQ, shutdown) + - carrier frequency + - bit rate + - receiver bandwidth + - frequency deviation + - output power during transmission + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -33,9 +33,13 @@ Si4432 radio1 = new Module(10, 2, 9); // SDN pin: 7 Si4432 radio2 = new Module(8, 3, 7); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//Si4432 radio3 = RadioShield.ModuleB; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio3 = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino index 240cd31bcc..1137482b08 100644 --- a/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino +++ b/examples/Si443x/Si443x_Transmit_Blocking/Si443x_Transmit_Blocking.ino @@ -29,9 +29,13 @@ // SDN pin: 9 Si4432 radio = new Module(10, 2, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//Si4432 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 094e3bdbc5..44501860a7 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -25,9 +25,13 @@ // SDN pin: 9 Si4432 radio = new Module(10, 2, 9); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//Si4432 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/Stream/Stream_Receive/Stream_Receive.ino b/examples/Stream/Stream_Receive/Stream_Receive.ino index e30f9378d1..0abffd1756 100644 --- a/examples/Stream/Stream_Receive/Stream_Receive.ino +++ b/examples/Stream/Stream_Receive/Stream_Receive.ino @@ -1,24 +1,24 @@ /* - RadioLib Stream Receive Example + RadioLib Stream Receive Example - This example shows how to receive data in "Stream" mode. - In this mode, arbitrary length of data may be sent, up to - "infinite" continuous transmission between two devices. + This example shows how to receive data in "Stream" mode. + In this mode, arbitrary length of data may be sent, up to + "infinite" continuous transmission between two devices. - Caveats: - - CRC of the payload is not supported - - the length of the payload must be known in advance + Caveats: + - CRC of the payload is not supported + - the length of the payload must be known in advance - Modules that can be used for Stream are: - - SX127x/RFM9x (FSK mode only) - - RF69 - - SX1231 + Modules that can be used for Stream are: + - SX127x/RFM9x (FSK mode only) + - RF69 + - SX1231 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index a3c6fb93bd..45b93d38c2 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -1,24 +1,24 @@ /* - RadioLib Stream Transmit Example + RadioLib Stream Transmit Example - This example shows how to transmit data in "Stream" mode. - In this mode, arbitrary length of data may be sent, up to - "infinite" continuous transmission between two devices. + This example shows how to transmit data in "Stream" mode. + In this mode, arbitrary length of data may be sent, up to + "infinite" continuous transmission between two devices. - Caveats: - - CRC of the payload is not supported - - the length of the payload must be known in advance + Caveats: + - CRC of the payload is not supported + - the length of the payload must be known in advance - Modules that can be used for Stream are: - - SX127x/RFM9x (FSK mode only) - - RF69 - - SX1231 + Modules that can be used for Stream are: + - SX127x/RFM9x (FSK mode only) + - RF69 + - SX1231 - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -31,9 +31,13 @@ // DIO1 pin: 3 SX1278 radio = new Module(10, 2, 9, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//SX1278 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; diff --git a/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino b/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino index b23e5e9915..a3028cda77 100644 --- a/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino +++ b/examples/nRF24/nRF24_Receive_Blocking/nRF24_Receive_Blocking.ino @@ -29,9 +29,13 @@ // CE pin: 3 nRF24 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//nRF24 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index 36622d6d35..d081ff763f 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -1,20 +1,20 @@ /* - RadioLib nRF24 Receive Example - - This example listens for FSK transmissions using nRF24 2.4 GHz radio module. - Once a packet is received, an interrupt is triggered. - To successfully receive data, the following settings have to be the same - on both transmitter and receiver: - - carrier frequency - - data rate - - transmit pipe on transmitter must match receive pipe - on receiver - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + RadioLib nRF24 Receive Example + + This example listens for FSK transmissions using nRF24 2.4 GHz radio module. + Once a packet is received, an interrupt is triggered. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - data rate + - transmit pipe on transmitter must match receive pipe + on receiver + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -26,9 +26,13 @@ // CE pin: 3 nRF24 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//nRF24 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino index c553eab281..603b4bd571 100644 --- a/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino +++ b/examples/nRF24/nRF24_Transmit_Blocking/nRF24_Transmit_Blocking.ino @@ -1,19 +1,19 @@ /* - RadioLib nRF24 Transmit Example + RadioLib nRF24 Transmit Example - This example transmits packets using nRF24 2.4 GHz radio module. - Each packet contains up to 32 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using nRF24 2.4 GHz radio module. + Each packet contains up to 32 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Packet delivery is automatically acknowledged by the receiver. + Packet delivery is automatically acknowledged by the receiver. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -25,9 +25,13 @@ // CE pin: 3 nRF24 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//nRF24 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ void setup() { Serial.begin(9600); diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 58c18e73b2..0751e51128 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -1,19 +1,19 @@ /* - RadioLib nRF24 Transmit with Interrupts Example + RadioLib nRF24 Transmit with Interrupts Example - This example transmits packets using nRF24 2.4 GHz radio module. - Each packet contains up to 32 bytes of data, in the form of: - - Arduino String - - null-terminated char array (C-string) - - arbitrary binary data (byte array) + This example transmits packets using nRF24 2.4 GHz radio module. + Each packet contains up to 32 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) - Packet delivery is automatically acknowledged by the receiver. + Packet delivery is automatically acknowledged by the receiver. - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -25,9 +25,13 @@ // CE pin: 3 nRF24 radio = new Module(10, 2, 3); -// or using RadioShield -// https://github.com/jgromes/RadioShield -//nRF24 radio = RadioShield.ModuleA; +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; From a525d457ef42c4623bed3984de35f965b980b5cd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Oct 2024 16:20:49 +0100 Subject: [PATCH 1301/1848] Move RadioShield and CubeCell pin definition to RadioBoards --- keywords.txt | 1 - src/BuildOpt.h | 12 ------------ src/RadioLib.h | 42 ------------------------------------------ 3 files changed, 55 deletions(-) diff --git a/keywords.txt b/keywords.txt index c5fd90b5ff..273fd409c4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,7 +7,6 @@ ####################################### RadioLib KEYWORD1 -RadioShield KEYWORD1 Module KEYWORD1 RadioLibHal KEYWORD1 ArduinoHal KEYWORD1 diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 3df71d83ce..96b6be32d2 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -81,13 +81,6 @@ #define RADIOLIB_LOW_LEVEL (0) #endif -/* - * Enable pre-defined modules when using RadioShield, disabled by default. - */ -#if !defined(RADIOLIB_RADIOSHIELD) - #define RADIOLIB_RADIOSHIELD (0) -#endif - /* * Enable interrupt-based timing control * For details, see https://github.com/jgromes/RadioLib/wiki/Interrupt-Based-Timing @@ -142,7 +135,6 @@ * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword. * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. - * RADIOLIB_BUILTIN_MODULE - some platforms have a builtin radio module on fixed pins, this macro is used to specify that pinout. * * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). * @@ -320,10 +312,6 @@ #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PINMODE) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (IrqModes) - // provide an easy access to the on-board module - #include "board-config.h" - #define RADIOLIB_BUILTIN_MODULE RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY - // CubeCell doesn't seem to define nullptr, let's do something like that now #define nullptr NULL diff --git a/src/RadioLib.h b/src/RadioLib.h index 34b1d90e36..c416180bc5 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -114,46 +114,4 @@ #include "utils/CRC.h" #include "utils/Cryptography.h" -// only create Radio class when using RadioShield -#if RADIOLIB_RADIOSHIELD - -// RadioShield pin definitions -#define RADIOSHIELD_CS_A 10 -#define RADIOSHIELD_IRQ_A 2 -#define RADIOSHIELD_RST_A 9 -#define RADIOSHIELD_GPIO_A 8 -#define RADIOSHIELD_CS_B 5 -#define RADIOSHIELD_IRQ_B 3 -#define RADIOSHIELD_RST_B 7 -#define RADIOSHIELD_GPIO_B 6 - -/*! - \class Radio - - \brief Library control object when using RadioShield. - Contains two pre-configured "modules", which correspond to the slots on shield. -*/ -class Radio { - public: - - Module* ModuleA; - Module* ModuleB; - - /*! - \brief Default constructor. Only used to set ModuleA and ModuleB configuration. - */ - Radio() { - ModuleA = new Module(RADIOSHIELD_CS_A, RADIOSHIELD_IRQ_A, RADIOSHIELD_RST_A, RADIOSHIELD_GPIO_A); - ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_IRQ_B, RADIOSHIELD_RST_B, RADIOSHIELD_GPIO_B); - } - -#if RADIOLIB_GODMODE - private: -#endif - -}; - -Radio RadioShield; -#endif - #endif From 9e7c0129e6ebe6e026214f2d768abbfbef42ddf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 20 Oct 2024 19:14:33 +0200 Subject: [PATCH 1302/1848] [HAL] HALs in src (#1281) * [HAL] Move HALs to src * [CI] Temporarily drop unofficial STM32 (package down) * [LR11x0] Fix ambiguous call * [CI] Return Maple mini back to build matrix --- examples/NonArduino/ESP-IDF/main/main.cpp | 2 +- examples/NonArduino/Pico/main.cpp | 2 +- examples/NonArduino/Raspberry/main.cpp | 2 +- examples/NonArduino/Tock/main.cpp | 2 +- src/Module.cpp | 2 +- src/RadioLib.h | 2 +- src/{ => hal/Arduino}/ArduinoHal.cpp | 0 src/{ => hal/Arduino}/ArduinoHal.h | 0 .../NonArduino/ESP-IDF/main => src/hal/ESP-IDF}/EspHal.h | 0 {examples/NonArduino/Raspberry => src/hal/RPi}/PiHal.h | 0 {examples/NonArduino/Pico => src/hal/RPiPico}/PicoHal.h | 0 {examples/NonArduino => src/hal}/Tock/libtockHal.h | 0 src/modules/LR11x0/LR11x0.cpp | 4 +++- src/modules/SX126x/STM32WLx_Module.cpp | 2 +- src/protocols/BellModem/BellModem.h | 3 --- src/protocols/ExternalRadio/ExternalRadio.h | 3 --- src/utils/CRC.h | 3 --- src/utils/FEC.h | 3 --- 18 files changed, 10 insertions(+), 20 deletions(-) rename src/{ => hal/Arduino}/ArduinoHal.cpp (100%) rename src/{ => hal/Arduino}/ArduinoHal.h (100%) rename {examples/NonArduino/ESP-IDF/main => src/hal/ESP-IDF}/EspHal.h (100%) rename {examples/NonArduino/Raspberry => src/hal/RPi}/PiHal.h (100%) rename {examples/NonArduino/Pico => src/hal/RPiPico}/PicoHal.h (100%) rename {examples/NonArduino => src/hal}/Tock/libtockHal.h (100%) diff --git a/examples/NonArduino/ESP-IDF/main/main.cpp b/examples/NonArduino/ESP-IDF/main/main.cpp index 9a2272b6ed..45e6f75d71 100644 --- a/examples/NonArduino/ESP-IDF/main/main.cpp +++ b/examples/NonArduino/ESP-IDF/main/main.cpp @@ -17,7 +17,7 @@ #include // include the hardware abstraction layer -#include "EspHal.h" +#include "hal/ESP-IDF/EspHal.h" // create a new instance of the HAL class EspHal* hal = new EspHal(5, 19, 27); diff --git a/examples/NonArduino/Pico/main.cpp b/examples/NonArduino/Pico/main.cpp index 28b32251c1..c0b007fa40 100644 --- a/examples/NonArduino/Pico/main.cpp +++ b/examples/NonArduino/Pico/main.cpp @@ -41,7 +41,7 @@ #include // include the hardware abstraction layer -#include "PicoHal.h" +#include "hal/RPiPico/PicoHal.h" // create a new instance of the HAL class PicoHal* hal = new PicoHal(SPI_PORT, SPI_MISO, SPI_MOSI, SPI_SCK); diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index 1dfa60bfc2..702b197116 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -18,7 +18,7 @@ #include // include the hardware abstraction layer -#include "PiHal.h" +#include "hal/RPi/PiHal.h" // create a new instance of the HAL class // use SPI channel 1, because on Waveshare LoRaWAN Hat, diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index c8a5628d4a..e716d50976 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -28,7 +28,7 @@ #include // include the hardware abstraction layer -#include "libtockHal.h" +#include "hal/Tock/libtockHal.h" // the entry point for the program int main(void) { diff --git a/src/Module.cpp b/src/Module.cpp index 33d9c09b4f..8cc308d238 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -5,7 +5,7 @@ #include #if defined(RADIOLIB_BUILD_ARDUINO) -#include "ArduinoHal.h" +#include "hal/Arduino/ArduinoHal.h" Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) { this->hal = new ArduinoHal(); diff --git a/src/RadioLib.h b/src/RadioLib.h index c416180bc5..bd6c9598da 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -40,7 +40,7 @@ #include "Hal.h" #if defined(RADIOLIB_BUILD_ARDUINO) -#include "ArduinoHal.h" +#include "hal/Arduino/ArduinoHal.h" #endif diff --git a/src/ArduinoHal.cpp b/src/hal/Arduino/ArduinoHal.cpp similarity index 100% rename from src/ArduinoHal.cpp rename to src/hal/Arduino/ArduinoHal.cpp diff --git a/src/ArduinoHal.h b/src/hal/Arduino/ArduinoHal.h similarity index 100% rename from src/ArduinoHal.h rename to src/hal/Arduino/ArduinoHal.h diff --git a/examples/NonArduino/ESP-IDF/main/EspHal.h b/src/hal/ESP-IDF/EspHal.h similarity index 100% rename from examples/NonArduino/ESP-IDF/main/EspHal.h rename to src/hal/ESP-IDF/EspHal.h diff --git a/examples/NonArduino/Raspberry/PiHal.h b/src/hal/RPi/PiHal.h similarity index 100% rename from examples/NonArduino/Raspberry/PiHal.h rename to src/hal/RPi/PiHal.h diff --git a/examples/NonArduino/Pico/PicoHal.h b/src/hal/RPiPico/PicoHal.h similarity index 100% rename from examples/NonArduino/Pico/PicoHal.h rename to src/hal/RPiPico/PicoHal.h diff --git a/examples/NonArduino/Tock/libtockHal.h b/src/hal/Tock/libtockHal.h similarity index 100% rename from examples/NonArduino/Tock/libtockHal.h rename to src/hal/Tock/libtockHal.h diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 1736f8c953..cfa96bb64c 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -3601,7 +3601,9 @@ int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskA void LR11x0::gnssAbort() { // send the abort signal (single NOP) this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false); + // we need to call the most basic overload of the SPI write method otherwise the call will be ambiguous + uint8_t cmd[2] = { 0, 0 }; + this->mod->SPIwriteStream(cmd, 2, NULL, 0, false, false); this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; // wait for at least 2.9 seconds as specified by the user manual diff --git a/src/modules/SX126x/STM32WLx_Module.cpp b/src/modules/SX126x/STM32WLx_Module.cpp index 0f48d9aa65..d2dd47d093 100644 --- a/src/modules/SX126x/STM32WLx_Module.cpp +++ b/src/modules/SX126x/STM32WLx_Module.cpp @@ -9,7 +9,7 @@ This file is licensed under the MIT License: https://opensource.org/licenses/MIT #if !RADIOLIB_EXCLUDE_STM32WLX -#include "../../ArduinoHal.h" +#include "hal/Arduino/ArduinoHal.h" // This defines some dummy pin numbers (starting at NUM_DIGITAL_PINS to // guarantee these are not valid regular pin numbers) that can be passed diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h index 886e206ea8..e65f411791 100644 --- a/src/protocols/BellModem/BellModem.h +++ b/src/protocols/BellModem/BellModem.h @@ -3,9 +3,6 @@ #include "../../TypeDef.h" #include "../../Module.h" -#if defined(RADIOLIB_BUILD_ARDUINO) -#include "../../ArduinoHal.h" -#endif #if !RADIOLIB_EXCLUDE_BELL diff --git a/src/protocols/ExternalRadio/ExternalRadio.h b/src/protocols/ExternalRadio/ExternalRadio.h index 823674bc42..86befabcb9 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.h +++ b/src/protocols/ExternalRadio/ExternalRadio.h @@ -3,9 +3,6 @@ #include "../../TypeDef.h" #include "../../Module.h" -#if defined(RADIOLIB_BUILD_ARDUINO) -#include "../../ArduinoHal.h" -#endif #include "../PhysicalLayer/PhysicalLayer.h" diff --git a/src/utils/CRC.h b/src/utils/CRC.h index bec3d71037..a93a0259c4 100644 --- a/src/utils/CRC.h +++ b/src/utils/CRC.h @@ -3,9 +3,6 @@ #include "../TypeDef.h" #include "../Module.h" -#if defined(RADIOLIB_BUILD_ARDUINO) -#include "../ArduinoHal.h" -#endif // CCITT CRC properties (used by AX.25) #define RADIOLIB_CRC_CCITT_POLY (0x1021) diff --git a/src/utils/FEC.h b/src/utils/FEC.h index 9b9e99c37f..7e1341248c 100644 --- a/src/utils/FEC.h +++ b/src/utils/FEC.h @@ -3,9 +3,6 @@ #include "../TypeDef.h" #include "../Module.h" -#if defined(RADIOLIB_BUILD_ARDUINO) -#include "../ArduinoHal.h" -#endif // BCH(31, 21) code constants #define RADIOLIB_PAGER_BCH_N (31) From d40790826938c83c8e9ec173267e660cf6a1f844 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 22 Oct 2024 19:00:31 +0200 Subject: [PATCH 1303/1848] [Utils] Fix missing include --- src/utils/Utils.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 57e9610b06..638f2b63d7 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -4,6 +4,8 @@ #include #include +#include "../BuildOpt.h" + // macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html #define SET_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] |= (1 << ((k)%8)) ) #define CLEAR_BIT_IN_ARRAY_MSB(A, k) ( A[((k)/8)] &= ~(1 << ((k)%8)) ) @@ -33,7 +35,7 @@ uint32_t rlb_reflect(uint32_t in, uint8_t bits); */ void rlb_hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); -#if RADIOLIB_DEBUG and defined(RADIOLIB_BUILD_ARDUINO) +#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) size_t rlb_printf(const char* format, ...); #endif From 33ab117c6d6538240dd640918c4bcda59805ac12 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 22 Oct 2024 19:15:33 +0200 Subject: [PATCH 1304/1848] [LoRaWAN] Fix incorrect payload size values --- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- src/protocols/LoRaWAN/LoRaWANBands.cpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index cf27053efb..3816486f56 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -385,7 +385,7 @@ struct LoRaWANBand_t { /*! \brief Maximum allowed frequency (coded in 100 Hz steps) */ uint32_t freqMax; - /*! \brief Array of allowed maximum payload lengths for each data rate (global maximum) */ + /*! \brief Array of allowed maximum application payload lengths for each data rate (N-value) */ uint8_t payloadLenMax[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; /*! \brief Maximum allowed output power in this band in dBm */ diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 3b33bec51b..d29126aa01 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -22,7 +22,7 @@ const LoRaWANBand_t EU868 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 8630000, .freqMax = 8700000, - .payloadLenMax = { 59, 59, 59, 123, 250, 250, 250, 250, 58, 123, 58, 123, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 51, 115, 242, 242, 242, 242, 50, 115, 50, 115, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, @@ -95,7 +95,7 @@ const LoRaWANBand_t US915 = { .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .freqMin = 9020000, .freqMax = 9280000, - .payloadLenMax = { 19, 61, 133, 250, 250, 58, 133, 0, 61, 137, 250, 250, 250, 250, 0 }, + .payloadLenMax = { 11, 53, 125, 242, 242, 50, 125, 0, 53, 129, 242, 242, 242, 242, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, @@ -189,7 +189,7 @@ const LoRaWANBand_t EU433 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 4330000, .freqMax = 4340000, - .payloadLenMax = { 59, 59, 59, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 51, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 12, .powerNumSteps = 5, .dutyCycle = 36000, @@ -262,7 +262,7 @@ const LoRaWANBand_t AU915 = { .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .freqMin = 9150000, .freqMax = 9280000, - .payloadLenMax = { 59, 59, 59, 123, 250, 250, 250, 58, 61, 137, 250, 250, 250, 250, 0 }, + .payloadLenMax = { 51, 51, 51, 115, 242, 242, 242, 50, 53, 129, 242, 242, 242, 242, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, @@ -356,7 +356,7 @@ const LoRaWANBand_t CN500 = { .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .freqMin = 4700000, .freqMax = 5100000, - .payloadLenMax = { 59, 59, 59, 123, 250, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 51, 115, 242, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 19, .powerNumSteps = 7, .dutyCycle = 0, @@ -443,7 +443,7 @@ const LoRaWANBand_t AS923 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 9150000, .freqMax = 9280000, - .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 115, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, @@ -516,7 +516,7 @@ const LoRaWANBand_t AS923_2 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 9150000, .freqMax = 9280000, - .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 115, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, @@ -589,7 +589,7 @@ const LoRaWANBand_t AS923_3 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 9150000, .freqMax = 9280000, - .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 115, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, @@ -662,7 +662,7 @@ const LoRaWANBand_t AS923_4 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 9170000, .freqMax = 9200000, - .payloadLenMax = { 59, 59, 123, 123, 250, 250, 250, 250, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 115, 115, 242, 242, 242, 242, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 16, .powerNumSteps = 7, .dutyCycle = 36000, @@ -735,7 +735,7 @@ const LoRaWANBand_t KR920 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 9209000, .freqMax = 9233000, - .payloadLenMax = { 59, 59, 59, 123, 250, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 51, 115, 242, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 14, .powerNumSteps = 7, .dutyCycle = 0, @@ -808,7 +808,7 @@ const LoRaWANBand_t IN865 = { .bandType = RADIOLIB_LORAWAN_BAND_DYNAMIC, .freqMin = 8650000, .freqMax = 8670000, - .payloadLenMax = { 59, 59, 59, 123, 250, 250, 0, 250, 0, 0, 0, 0, 0, 0, 0 }, + .payloadLenMax = { 51, 51, 51, 115, 242, 242, 0, 242, 0, 0, 0, 0, 0, 0, 0 }, .powerMax = 30, .powerNumSteps = 10, .dutyCycle = 0, From 61494b8270702bef1e78b3335c0beb585d441962 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 22 Oct 2024 20:21:52 +0200 Subject: [PATCH 1305/1848] [LoRaWAN] Fix #1284 (max length) and channel struct for fixed bands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 50 ++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index cf5f599fb4..761d397042 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1398,9 +1398,9 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne } // get the maximum allowed Time-on-Air of a packet given the current datarate - uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; + uint8_t maxPayLen = this->band->payloadLenMax[dlChannels[window].dr]; if(this->TS011) { - maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater + maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater } RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13) / 1000; // mandatory FHDR is 12/13 bytes bool downlinkComplete = true; @@ -1978,7 +1978,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin optIn[13] = this->nbTrans; } memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], optIn, lenIn); - + return(true); } break; @@ -2796,7 +2796,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, } RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %7.3f MHz", dir ? 'D' : 'U', chnl->freq / 10000.0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency = %7.3f MHz, TX = %d dBm", chnl->freq / 10000.0, pwr); state = this->phyLayer->setFrequency(chnl->freq / 10000.0); RADIOLIB_ASSERT(state); @@ -2813,12 +2813,12 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, RADIOLIB_ASSERT(state); if(this->modulation == RADIOLIB_LORAWAN_MODULATION_GFSK) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, TX = %d dBm, FD = %4.1f kHz", - dr.fsk.bitRate, pwr, dr.fsk.freqDev); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, FD = %4.1f kHz", + dr.fsk.bitRate, dr.fsk.freqDev); } if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, TX = %d dBm, BW = %5.1f kHz, CR = 4/%d", - dr.lora.spreadingFactor, pwr, dr.lora.bandwidth, dr.lora.codingRate); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", + dr.lora.spreadingFactor, dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); } // this only needs to be done once-ish @@ -2901,7 +2901,10 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr *chMaskGrp0123 = 0; *chMaskGrp45 = 0; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + uint8_t numCh = this->getAvailableChannels(NULL); + + // if there are any channels selected, create the mask from those channels + if(numCh > 0) { for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { @@ -2912,6 +2915,13 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr } } } + return; + } + + // it should not happen that no channels are set for dynamic band + // but in that case, simply return + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + return; } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED // if a subband is set, we can set the channel indices straight from subband @@ -2923,9 +2933,9 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr // CN500 only: for sub band 9-12, set bank of 8 125kHz channels *chMaskGrp45 |= 0xFF << ((this->subBand - 9) * 8); } else { - // if subband is set to 0, all 125kHz channels are enabled - // however, we can 'only' store 16 channels, so we do not actually store these - // therefore, we select a random channel from each bank of 8 channels + // if subband is set to 0, all 125kHz channels are enabled. + // however, we can 'only' store 16 channels, so we don't use all channels at once. + // instead, we select a random channel from each bank of 8 channels + 1 from second plan. uint8_t num125kHz = this->band->txSpans[0].numChannels; uint8_t numBanks = num125kHz / 8; for(uint8_t bank = 0; bank < numBanks; bank++) { @@ -3009,10 +3019,6 @@ void LoRaWANNode::selectChannelPlanFix() { // make all enabled channels available for uplink selection this->setAvailableChannels(0xFFFF); - - #if RADIOLIB_DEBUG_PROTOCOL - this->printChannels(); - #endif } uint8_t LoRaWANNode::getAvailableChannels(uint16_t* chMask) { @@ -3109,7 +3115,6 @@ int16_t LoRaWANNode::selectChannels() { } bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) { - int num = 0; if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskGrp0123 & ((uint64_t)1 << i)) { @@ -3123,7 +3128,12 @@ bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) } } } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED + // full channel mask received, so clear all existing channels LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i] = chnl; + } + int num = 0; uint8_t spanNum = 0; int chNum = 0; int chOfs = 0; @@ -3240,12 +3250,12 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { RADIOLIB_LORAWAN_UPLINK, this->txPowerMax - 2*this->txPowerSteps); - // mandatory FHDR is 12/13, so add & subtract 13 from calculations where necessary uint8_t minLen = 0; - uint8_t maxLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr] + 13; + uint8_t maxLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; if(this->TS011) { - maxLen = RADIOLIB_MIN(maxLen, 230 + 13); // payload length is limited to 230 if under repeater + maxLen = RADIOLIB_MIN(maxLen, 222); // payload length is limited to N=222 if under repeater } + maxLen += 13; // mandatory FHDR is 12/13 bytes // if not limited by dwell-time, just return maximum if(!this->dwellTimeEnabledUp) { From 8bc4b9a330a28af2786005fed9f110911c08908d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 22 Oct 2024 20:38:20 +0200 Subject: [PATCH 1306/1848] [CC1101] Fix direct reception (#1257) --- src/modules/CC1101/CC1101.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 45a5558a2c..f2ff50afd7 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -234,8 +234,12 @@ int16_t CC1101::receiveDirect(bool sync) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_RX); + // enable promiscuous mode - needed for protocols that decode in software (e.g. PagerClient) + int16_t state = setPromiscuousMode(true); + RADIOLIB_ASSERT(state); + // activate direct mode - int16_t state = directMode(sync); + state = directMode(sync); RADIOLIB_ASSERT(state); // start receiving From 434afa52f2ba103f33f901bc2e8c493ac7aaa98d Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Wed, 23 Oct 2024 19:04:29 +0300 Subject: [PATCH 1307/1848] [LR11X0] FSK preamble detector length configuration (#1286) * [LR11X0] pay more attention to selection of FSK preamble detector length --- src/modules/LR11x0/LR11x0.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index cfa96bb64c..6bb4e22782 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1117,7 +1117,11 @@ int16_t LR11x0::setPreambleLength(size_t preambleLength) { return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { this->preambleLengthGFSK = preambleLength; - this->preambleDetLength = RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS; + this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS : + preambleLength >= 24 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS : + preambleLength >= 16 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS : + preambleLength > 0 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS : + RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED; return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } From fada24c1c4e4cc65300309604506a209fbe652e3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 23 Oct 2024 18:06:35 +0100 Subject: [PATCH 1308/1848] [APRS] Added repeaters (#1285) --- examples/APRS/APRS_Position/APRS_Position.ino | 35 ++++++++++++++----- keywords.txt | 2 ++ src/protocols/APRS/APRS.cpp | 18 ++++++++++ src/protocols/APRS/APRS.h | 20 +++++++++++ 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/examples/APRS/APRS_Position/APRS_Position.ino b/examples/APRS/APRS_Position/APRS_Position.ino index e18804846c..cf7f6977eb 100644 --- a/examples/APRS/APRS_Position/APRS_Position.ino +++ b/examples/APRS/APRS_Position/APRS_Position.ino @@ -109,32 +109,49 @@ void setup() { } void loop() { - Serial.print(F("[APRS] Sending position ... ")); + Serial.println(F("[APRS] Sending location reports")); // send a location without message or timestamp char destination[] = "N0CALL"; char latitude[] = "4911.67N"; char longitude[] = "01635.96E"; int state = aprs.sendPosition(destination, 0, latitude, longitude); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("[APRS] Failed to send location, code ")); + Serial.println(state); + } delay(500); // send a location with message and without timestamp char message[] = "I'm here!"; - state |= aprs.sendPosition(destination, 0, latitude, longitude, message); + state = aprs.sendPosition(destination, 0, latitude, longitude, message); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("[APRS] Failed to send location and message code ")); + Serial.println(state); + } delay(500); + + // you can also set repeater callsigns and SSIDs + // up to 8 repeaters may be used + // sendPosition will be sent with "WIDE2-2" path + char* repeaterCallsigns[] = { "WIDE2" }; + uint8_t repeaterSSIDs[] = { 2 }; + aprs.useRepeaters(repeaterCallsigns, repeaterSSIDs, 1); // send a location with message and timestamp char timestamp[] = "093045z"; - state |= aprs.sendPosition(destination, 0, latitude, longitude, message, timestamp); - delay(500); - - if(state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); + state = aprs.sendPosition(destination, 0, latitude, longitude, message, timestamp); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("[APRS] Failed to send location, message and timestamp code ")); Serial.println(state); } + delay(500); + + // when repeaters are no longer needed, they can be dropped + aprs.dropRepeaters(); // wait one minute before transmitting again + Serial.println(F("[APRS] All done!")); delay(60000); } + diff --git a/keywords.txt b/keywords.txt index 273fd409c4..d903819b78 100644 --- a/keywords.txt +++ b/keywords.txt @@ -313,6 +313,8 @@ noTone KEYWORD2 # APRS sendPosition KEYWORD2 sendMicE KEYWORD2 +useRepeaters KEYWORD2 +dropRepeaters KEYWORD2 # Pager sendTone KEYWORD2 diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index a5866ac617..c2fb72f3ed 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -260,6 +260,12 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME, RADIOLIB_AX25_PID_NO_LAYER_3, const_cast(info)); + // optionally set repeaters + if(this->repCalls && this->repSSIDs && this->numReps) { + int16_t state = frameUI.setRepeaters(this->repCalls, this->repSSIDs, this->numReps); + RADIOLIB_ASSERT(state); + } + return(axClient->sendFrame(&frameUI)); } else if(this->phyLayer != nullptr) { @@ -276,4 +282,16 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) return(RADIOLIB_ERR_WRONG_MODEM); } +void APRSClient::useRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) { + this->repCalls = repeaterCallsigns; + this->repSSIDs = repeaterSSIDs; + this->numReps = numRepeaters; +} + +void APRSClient::dropRepeaters() { + this->repCalls = NULL; + this->repSSIDs = NULL; + this->numReps = 0; +} + #endif diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index 7b14ad8891..44031fdea4 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -144,6 +144,21 @@ class APRSClient { */ int16_t sendFrame(char* destCallsign, uint8_t destSSID, char* info); + /*! + \brief Set the repeater callsigns and SSIDs to be used by the frames sent by sendPosition, sendMicE or sendFrame. + \param repeaterCallsigns Array of repeater callsigns in the form of null-terminated C-strings. + \param repeaterSSIDs Array of repeater SSIDs. + \param numRepeaters Number of repeaters, maximum is 8. + \returns \ref status_codes + */ + void useRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters); + + /*! + \brief Stop using repeaters. + \returns \ref status_codes + */ + void dropRepeaters(); + #if !RADIOLIB_GODMODE private: #endif @@ -153,6 +168,11 @@ class APRSClient { // default APRS symbol (car) char symbol = '>'; char table = '/'; + + // repeaters + char** repCalls = NULL; + uint8_t* repSSIDs = NULL; + uint8_t numReps = 0; // source callsign when using APRS over LoRa char src[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 }; From 64253f6e36c830d63b876989cdae54320d6299cd Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 25 Oct 2024 17:54:55 +0100 Subject: [PATCH 1309/1848] [HAL] Prevent reinit in PiHal --- src/hal/RPi/PiHal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hal/RPi/PiHal.h b/src/hal/RPi/PiHal.h index 03dded742e..76a6389b41 100644 --- a/src/hal/RPi/PiHal.h +++ b/src/hal/RPi/PiHal.h @@ -32,6 +32,10 @@ class PiHal : public RadioLibHal { } void init() override { + if(_gpioHandle != -1) { + return; + } + // first initialise lgpio library if((_gpioHandle = lgGpiochipOpen(_gpioDevice)) < 0) { fprintf(stderr, "Could not open GPIO chip: %s\n", lguErrorText(_gpioHandle)); @@ -48,6 +52,7 @@ class PiHal : public RadioLibHal { // finally, stop the lgpio library lgGpiochipClose(_gpioHandle); + _gpioHandle = -1; } // GPIO-related methods (pinMode, digitalWrite etc.) should check From e44e9b4bcef5c733c71ea943c1543b12323ec168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sat, 26 Oct 2024 17:49:35 +0200 Subject: [PATCH 1310/1848] [PHY] Get/Set modem (#1294) * [PHY] Added set modem method * Added new keyword * [SX126x] Added setModem implementation * [LoRaWAN] Use setModem * [PHY] Added getModem * [LoRaWAN] Use getModem instead of caching modulation * [SX126x] Implement getModem * Added new keywords * [LR11x0] Added get/set modem * [LLCC68] Added get/set modem * [SX126x] Added missing default branch * [SX127x] Added get/set modem * [SX128x] Added get/set modem * [CI] Drop Hellschreiber from AVR builds * [CI] Drop Arduino Uno from CI --- .github/workflows/main.yml | 7 +-- keywords.txt | 12 ++++- src/modules/LLCC68/LLCC68.cpp | 16 ++++++ src/modules/LLCC68/LLCC68.h | 8 +++ src/modules/LR11x0/LR1110.cpp | 15 ++++++ src/modules/LR11x0/LR1110.h | 8 +++ src/modules/LR11x0/LR1120.cpp | 15 ++++++ src/modules/LR11x0/LR1120.h | 8 +++ src/modules/LR11x0/LR11x0.cpp | 24 +++++++++ src/modules/LR11x0/LR11x0.h | 7 +++ src/modules/SX126x/SX1262.cpp | 16 ++++++ src/modules/SX126x/SX1262.h | 8 +++ src/modules/SX126x/SX1268.cpp | 16 ++++++ src/modules/SX126x/SX1268.h | 8 +++ src/modules/SX126x/SX126x.cpp | 21 ++++++++ src/modules/SX126x/SX126x.h | 7 +++ src/modules/SX127x/SX1272.cpp | 13 +++++ src/modules/SX127x/SX1272.h | 8 +++ src/modules/SX127x/SX1273.cpp | 13 +++++ src/modules/SX127x/SX1273.h | 8 +++ src/modules/SX127x/SX1276.cpp | 13 +++++ src/modules/SX127x/SX1276.h | 8 +++ src/modules/SX127x/SX1277.cpp | 13 +++++ src/modules/SX127x/SX1277.h | 8 +++ src/modules/SX127x/SX1278.cpp | 13 +++++ src/modules/SX127x/SX1278.h | 8 +++ src/modules/SX127x/SX1279.cpp | 13 +++++ src/modules/SX127x/SX1279.h | 8 +++ src/modules/SX127x/SX127x.cpp | 18 +++++++ src/modules/SX127x/SX127x.h | 7 +++ src/modules/SX128x/SX128x.cpp | 31 +++++++++++ src/modules/SX128x/SX128x.h | 15 ++++++ src/protocols/LoRaWAN/LoRaWAN.cpp | 52 ++++++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 8 --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 10 ++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 26 ++++++++++ 36 files changed, 456 insertions(+), 33 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7c518526ce..ba5e493d98 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,12 +10,11 @@ on: id: description: The ID of the platform on which the build is run required: true - default: arduino:avr:uno + default: arduino:avr:mega type: choice options: - all - none - - arduino:avr:uno - arduino:avr:mega - arduino:mbed:nano33ble - arduino:mbed:envie_m4 @@ -45,8 +44,6 @@ jobs: matrix: # platform-dependent settings - extra board options, board index URLs, skip patterns etc. include: - - id: arduino:avr:uno - run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update|Pager|APRS|Morse|SX126x)" >> $GITHUB_OUTPUT - id: arduino:avr:mega run: | echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT @@ -131,7 +128,7 @@ jobs: runs-on: ubuntu-latest name: ${{ matrix.id }} env: - run-build: ${{ (inputs.id != 'none' && matrix.id == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) || inputs.id == 'all' || inputs.id == matrix.id }} + run-build: ${{ (inputs.id != 'none' && matrix.id == 'arduino:avr:mega') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.id)) || inputs.id == 'all' || inputs.id == matrix.id }} steps: - name: Free Disk Space (Ubuntu) diff --git a/keywords.txt b/keywords.txt index d903819b78..179b4e2932 100644 --- a/keywords.txt +++ b/keywords.txt @@ -320,6 +320,15 @@ dropRepeaters KEYWORD2 sendTone KEYWORD2 # PhysicalLayer +RadioLibIrqType_t KEYWORD1 +LoRaRate_t KEYWORD1 +FSKRate_t KEYWORD1 +LrFhssRate_t KEYWORD1 +DataRate_t KEYWORD1 +CADScanConfig_t KEYWORD1 +RSSIScanConfig_t KEYWORD1 +ChannelScanConfig_t KEYWORD1 +ModemType_t KEYWORD1 dropSync KEYWORD2 setTimerFlag KEYWORD2 setInterruptSetup KEYWORD2 @@ -329,9 +338,8 @@ setPacketSentAction KEYWORD2 clearPacketSentAction KEYWORD2 setDataRate KEYWORD2 checkDataRate KEYWORD2 - -# BellModem setModem KEYWORD2 +getModem KEYWORD2 # LoRaWAN getBufferNonces KEYWORD2 diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index f7d458ad9b..18ce03dd26 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -116,4 +116,20 @@ int16_t LLCC68::checkDataRate(DataRate_t dr) { return(state); } +int16_t LLCC68::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + case(ModemType_t::LRFHSS): { + return(this->beginLRFHSS()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 08c52af338..a0b6d19e8a 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -69,6 +69,14 @@ class LLCC68: public SX1262 { \returns \ref status_codes */ int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 7ebf5a7b97..0950a3a34d 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -105,4 +105,19 @@ int16_t LR1110::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPo return(RADIOLIB_ERR_NONE); } +int16_t LR1110::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginGFSK()); + } break; + case(ModemType_t::LRFHSS): { + return(this->beginLRFHSS()); + } break; + } + return(RADIOLIB_ERR_WRONG_MODEM); +} + #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index 3e1bc5fcee..bd7818f8fb 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -123,6 +123,14 @@ class LR1110: public LR11x0 { */ int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; + #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 9afa8dfb66..ae4dc4a155 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -128,4 +128,19 @@ int16_t LR1120::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPo return(RADIOLIB_ERR_NONE); } +int16_t LR1120::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginGFSK()); + } break; + case(ModemType_t::LRFHSS): { + return(this->beginLRFHSS()); + } break; + } + return(RADIOLIB_ERR_WRONG_MODEM); +} + #endif \ No newline at end of file diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index 4abae5a93a..dde2420880 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -132,6 +132,14 @@ class LR1120: public LR11x0 { */ int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower); + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; + #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6bb4e22782..03d32d0486 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2009,6 +2009,30 @@ int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) return(state); } +int16_t LR11x0::getModem(ModemType_t* modem) { + if(!modem) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t packetType = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&packetType); + RADIOLIB_ASSERT(state); + + switch(packetType) { + case(RADIOLIB_LR11X0_PACKET_TYPE_LORA): + *modem = ModemType_t::LoRa; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_LR11X0_PACKET_TYPE_GFSK): + *modem = ModemType_t::FSK; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS): + *modem = ModemType_t::LRFHSS; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 3f1939a5bd..490c120381 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1602,6 +1602,13 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats); + + /*! + \brief Get modem currently in use by the radio. + \param modem Pointer to a variable to save the retrieved configuration into. + \returns \ref status_codes + */ + int16_t getModem(ModemType_t* modem) override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 43c9706370..c4e20eb2cc 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -145,4 +145,20 @@ int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) { return(RADIOLIB_ERR_NONE); } +int16_t SX1262::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + case(ModemType_t::LRFHSS): { + return(this->beginLRFHSS()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index c05ee4b115..0dc2744448 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -109,6 +109,14 @@ class SX1262: public SX126x { \returns \ref status_codes */ int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 78cfdae349..a8095b5a5c 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -140,4 +140,20 @@ int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) { return(RADIOLIB_ERR_NONE); } +int16_t SX1268::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + case(ModemType_t::LRFHSS): { + return(this->beginLRFHSS()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index ad411ee793..87cf9b5c75 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -107,6 +107,14 @@ class SX1268: public SX126x { \returns \ref status_codes */ int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 9c17cfede6..135ed05c10 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1662,6 +1662,27 @@ int16_t SX126x::invertIQ(bool enable) { return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } +int16_t SX126x::getModem(ModemType_t* modem) { + if(!modem) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t packetType = getPacketType(); + switch(packetType) { + case(RADIOLIB_SX126X_PACKET_TYPE_LORA): + *modem = ModemType_t::LoRa; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_SX126X_PACKET_TYPE_GFSK): + *modem = ModemType_t::FSK; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS): + *modem = ModemType_t::LRFHSS; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 766e02087c..8a0348c3ed 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1123,6 +1123,13 @@ class SX126x: public PhysicalLayer { */ int16_t invertIQ(bool enable) override; + /*! + \brief Get modem currently in use by the radio. + \param modem Pointer to a variable to save the retrieved configuration into. + \returns \ref status_codes + */ + int16_t getModem(ModemType_t* modem) override; + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is received in direct mode. diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 50b088b243..ed615705f9 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -585,4 +585,17 @@ void SX1272::errataFix(bool rx) { mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); } +int16_t SX1272::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 292bfd790c..2689969251 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -301,6 +301,14 @@ class SX1272: public SX127x { \returns \ref status_codes */ int16_t explicitHeader(); + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK or LoRa. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 9ef7c17552..0efbbe933e 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -115,4 +115,17 @@ int16_t SX1273::checkDataRate(DataRate_t dr) { return(state); } +int16_t SX1273::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 8e7ab1ca17..4e9dd1ed74 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -62,6 +62,14 @@ class SX1273: public SX1272 { \returns \ref status_codes */ int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK or LoRa. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index d45826fcc0..8890c6cb64 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -79,4 +79,17 @@ int16_t SX1276::setFrequency(float freq) { return(state); } +int16_t SX1276::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 89ab9f9ffb..64dbaa3e35 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -62,6 +62,14 @@ class SX1276: public SX1278 { \returns \ref status_codes */ int16_t setFrequency(float freq) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK or LoRa. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index fea394cd3a..c85a5fe554 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -157,4 +157,17 @@ int16_t SX1277::checkDataRate(DataRate_t dr) { return(state); } +int16_t SX1277::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index c7efd95ba9..fe068c0d75 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -83,6 +83,14 @@ class SX1277: public SX1278 { \returns \ref status_codes */ int16_t checkDataRate(DataRate_t dr) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK or LoRa. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 3265675f09..e53bfe3490 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -705,4 +705,17 @@ void SX1278::errataFix(bool rx) { mod->SPIsetRegValue(0x30, fixedRegs[2]); } +int16_t SX1278::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 3c2b0088a3..feb1d09cb8 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -313,6 +313,14 @@ class SX1278: public SX127x { \returns \ref status_codes */ int16_t explicitHeader(); + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK or LoRa. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 9f9ac03794..4babad0573 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -79,4 +79,17 @@ int16_t SX1279::setFrequency(float freq) { return(state); } +int16_t SX1279::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + #endif diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 1dceb42309..865b1b22c9 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -62,6 +62,14 @@ class SX1279: public SX1278 { \returns \ref status_codes */ int16_t setFrequency(float freq) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK or LoRa. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 55138aa1e2..425b1cb1cd 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1754,6 +1754,24 @@ int16_t SX127x::invertIQ(bool enable) { return(state); } +int16_t SX127x::getModem(ModemType_t* modem) { + if(!modem) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + int16_t packetType = getActiveModem(); + switch(packetType) { + case(RADIOLIB_SX127X_LORA): + *modem = ModemType_t::LoRa; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_SX127X_FSK_OOK): + *modem = ModemType_t::FSK; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX127x::setDirectAction(void (*func)(void)) { setDio1Action(func, this->mod->hal->GpioInterruptRising); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index ba492f1ddb..c54a549f63 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1149,6 +1149,13 @@ class SX127x: public PhysicalLayer { */ int16_t invertIQ(bool enable) override; + /*! + \brief Get modem currently in use by the radio. + \param modem Pointer to a variable to save the retrieved configuration into. + \returns \ref status_codes + */ + int16_t getModem(ModemType_t* modem) override; + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! \brief Set interrupt service routine function to call when data bit is received in direct mode. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a7fe165b50..5847f3d6c2 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -856,6 +856,37 @@ int16_t SX128x::checkOutputPower(int8_t pwr, int8_t* clipped) { return(RADIOLIB_ERR_NONE); } +int16_t SX128x::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::LoRa): { + return(this->begin()); + } break; + case(ModemType_t::FSK): { + return(this->beginGFSK()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + +int16_t SX128x::getModem(ModemType_t* modem) { + if(!modem) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t packetType = getPacketType(); + switch(packetType) { + case(RADIOLIB_SX128X_PACKET_TYPE_LORA): + *modem = ModemType_t::LoRa; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_SX128X_PACKET_TYPE_GFSK): + *modem = ModemType_t::FSK; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + int16_t SX128x::setPreambleLength(uint32_t preambleLength) { uint8_t modem = getPacketType(); if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 6f584ead84..ae1d46876f 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -671,6 +671,21 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ int16_t checkOutputPower(int8_t pwr, int8_t* clipped) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; + + /*! + \brief Get modem currently in use by the radio. + \param modem Pointer to a variable to save the retrieved configuration into. + \returns \ref status_codes + */ + int16_t getModem(ModemType_t* modem) override; /*! \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 761d397042..7e6e4a8c56 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2768,11 +2768,19 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, return(state); } - // TODO implement PhysicalLayer::setModem() + // get the currently configured modem from the radio + ModemType_t modem; + state = this->phyLayer->getModem(&modem); + RADIOLIB_ASSERT(state); + // set modem-dependent functions switch(this->band->dataRates[chnl->dr] & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { case(RADIOLIB_LORAWAN_DATA_RATE_LORA): - this->modulation = RADIOLIB_LORAWAN_MODULATION_LORA; + if(modem != ModemType_t::LoRa) { + state = this->phyLayer->setModem(ModemType_t::LoRa); + RADIOLIB_ASSERT(state); + } + modem = ModemType_t::LoRa; // downlink messages are sent with inverted IQ if(dir == RADIOLIB_LORAWAN_DOWNLINK) { state = this->phyLayer->invertIQ(true); @@ -2781,16 +2789,27 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, } RADIOLIB_ASSERT(state); break; + case(RADIOLIB_LORAWAN_DATA_RATE_FSK): - this->modulation = RADIOLIB_LORAWAN_MODULATION_GFSK; + if(modem != ModemType_t::FSK) { + state = this->phyLayer->setModem(ModemType_t::FSK); + RADIOLIB_ASSERT(state); + } + modem = ModemType_t::FSK; state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); RADIOLIB_ASSERT(state); state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); RADIOLIB_ASSERT(state); break; + case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): - this->modulation = RADIOLIB_LORAWAN_MODULATION_LR_FHSS; + if(modem != ModemType_t::LRFHSS) { + state = this->phyLayer->setModem(ModemType_t::LRFHSS); + RADIOLIB_ASSERT(state); + } + modem = ModemType_t::LRFHSS; break; + default: return(RADIOLIB_ERR_UNSUPPORTED); } @@ -2812,40 +2831,37 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, state = this->phyLayer->setDataRate(dr); RADIOLIB_ASSERT(state); - if(this->modulation == RADIOLIB_LORAWAN_MODULATION_GFSK) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, FD = %4.1f kHz", - dr.fsk.bitRate, dr.fsk.freqDev); - } - if(this->modulation == RADIOLIB_LORAWAN_MODULATION_LORA) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", - dr.lora.spreadingFactor, dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); - } - // this only needs to be done once-ish uint8_t syncWord[4] = { 0 }; uint8_t syncWordLen = 0; size_t preLen = 0; - switch(this->modulation) { - case(RADIOLIB_LORAWAN_MODULATION_GFSK): { + switch(modem) { + case(ModemType_t::FSK): { preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; syncWordLen = 3; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, FD = %4.1f kHz", + dr.fsk.bitRate, dr.fsk.freqDev); } break; - case(RADIOLIB_LORAWAN_MODULATION_LORA): { + case(ModemType_t::LoRa): { preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", + dr.lora.spreadingFactor, dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); } break; - case(RADIOLIB_LORAWAN_MODULATION_LR_FHSS): { + case(ModemType_t::LRFHSS): { syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 24); syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 16); syncWord[2] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 8); syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; syncWordLen = 4; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LR-FHSS: BW = 0x%02x, CR = 0x%02x kHz, grid = %c", + dr.lrfhss.bw, dr.lrfhss.cr, dr.lrFhss.narrowGrid ? 'N' : 'W'); } break; default: @@ -2859,7 +2875,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, if(pre) { preLen = pre; } - if(this->modulation != RADIOLIB_LORAWAN_MODULATION_LR_FHSS) { + if(modem != ModemType_t::LRFHSS) { state = this->phyLayer->setPreambleLength(preLen); } return(state); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 3816486f56..588882b9d2 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -15,11 +15,6 @@ #define RADIOLIB_LORAWAN_CLASS_B (0x0B) #define RADIOLIB_LORAWAN_CLASS_C (0x0C) -// modulation type -#define RADIOLIB_LORAWAN_MODULATION_LORA (0) -#define RADIOLIB_LORAWAN_MODULATION_GFSK (1) -#define RADIOLIB_LORAWAN_MODULATION_LR_FHSS (2) - // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) #define RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN (8) @@ -916,9 +911,6 @@ class LoRaWANNode { uint32_t confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; uint32_t adrFCnt = 0; - // modulation of the currently configured channel - uint8_t modulation = RADIOLIB_LORAWAN_MODULATION_LORA; - // ADR is enabled by default bool adrEnabled = true; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 82eb5fba95..1ad04e69cc 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -531,6 +531,16 @@ void PhysicalLayer::clearChannelScanAction() { } +int16_t PhysicalLayer::setModem(ModemType_t modem) { + (void)modem; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::getModem(ModemType_t* modem) { + (void)modem; + return(RADIOLIB_ERR_UNSUPPORTED); +} + #if RADIOLIB_INTERRUPT_TIMING void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { Module* mod = getMod(); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index c463e8b2cd..c5467990ef 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -130,6 +130,16 @@ union ChannelScanConfig_t { RSSIScanConfig_t rssi; }; +/*! + \enum ModemType_t + \brief Type of modem, used by setModem. +*/ +enum ModemType_t { + FSK = 0, + LoRa, + LRFHSS, +}; + /*! \class PhysicalLayer @@ -644,6 +654,21 @@ class PhysicalLayer { */ virtual void clearChannelScanAction(); + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set. Not all modems are implemented by all radio modules! + \returns \ref status_codes + */ + virtual int16_t setModem(ModemType_t modem); + + /*! + \brief Get modem currently in use by the radio. + \param modem Pointer to a variable to save the retrieved configuration into. + \returns \ref status_codes + */ + virtual int16_t getModem(ModemType_t* modem); + #if RADIOLIB_INTERRUPT_TIMING /*! @@ -702,6 +727,7 @@ class PhysicalLayer { friend class BellClient; friend class FT8Client; friend class LoRaWANNode; + friend class M17Client; }; #endif From 6b05e9fd23fd3b60ba8b13e07fcc05471d9d5b58 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Oct 2024 16:57:43 +0100 Subject: [PATCH 1311/1848] Added pointer assert --- src/BuildOpt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 96b6be32d2..80baff153c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -549,8 +549,10 @@ */ #if RADIOLIB_VERBOSE_ASSERT #define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { RADIOLIB_DEBUG_BASIC_PRINTLN("%d at %s:%d", STATEVAR, __FILE__, __LINE__); return(STATEVAR); } } +#define RADIOLIB_ASSERT_PTR(PTR) { if((PTR) == NULL) { RADIOLIB_DEBUG_BASIC_PRINTLN("NULL at %s:%d", __FILE__, __LINE__); return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } } #else #define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } } +#define RADIOLIB_ASSERT_PTR(PTR) { if((PTR) == NULL) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } } #endif /*! From 3952fe9139235653c21da478c7cc4232a824d8b5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Oct 2024 16:59:13 +0100 Subject: [PATCH 1312/1848] Use pointer assert --- src/modules/LR11x0/LR11x0.cpp | 79 +++++-------------- src/modules/SX126x/SX126x.cpp | 4 +- src/modules/SX127x/SX127x.cpp | 4 +- src/modules/SX128x/SX128x.cpp | 4 +- src/protocols/Pager/Pager.cpp | 4 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 +- 6 files changed, 27 insertions(+), 76 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 03d32d0486..2f97cc8f09 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1571,9 +1571,7 @@ int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) { } int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) { - if(!result) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(result); // read a single result uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE; @@ -1647,9 +1645,7 @@ int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, boo } int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { - if(!count) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(count); // start scan RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start"); @@ -1674,9 +1670,7 @@ int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_ } int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) { - if(!info) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(info); int16_t state = this->getVersion(&info->hardware, &info->device, &info->fwMajor, &info->fwMinor); RADIOLIB_ASSERT(state); @@ -1696,9 +1690,7 @@ int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) { } int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolatile) { - if(!image) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(image); // put the device to bootloader mode int16_t state = this->reboot(true); @@ -1802,9 +1794,7 @@ int16_t LR11x0::isGnssScanCapable() { } int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) { - if(!res) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(res); // go to standby int16_t state = standby(); @@ -1872,9 +1862,7 @@ int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) { } int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) { - if(!stat) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(stat); // save the time the time until subframe is relative to stat->start = this->mod->hal->millis(); @@ -1913,9 +1901,7 @@ int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) { } int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) { - if(!stat) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(stat); // almanac update has to be called at least 1.3 seconds before the subframe // we use 2.3 seconds to be on the safe side @@ -1969,9 +1955,7 @@ int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) { } int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) { - if(!pos) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(pos); uint8_t error = 0; int16_t state; @@ -1991,7 +1975,8 @@ int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) { } int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) { - if((!sats) || (numSats >= 32)) { + RADIOLIB_ASSERT_PTR(sats); + if(numSats >= 32) { return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); } @@ -2010,9 +1995,7 @@ int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) } int16_t LR11x0::getModem(ModemType_t* modem) { - if(!modem) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(modem); uint8_t packetType = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&packetType); @@ -2577,23 +2560,17 @@ int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) { } int16_t LR11x0::getChipEui(uint8_t* eui) { - if(!eui) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(eui); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) { - if(!eui) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(eui); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) { - if(!pin) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(pin); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); } @@ -2689,9 +2666,7 @@ int16_t LR11x0::getRssiInst(float* rssi) { } int16_t LR11x0::setGfskSyncWord(uint8_t* sync) { - if(!sync) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(sync); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)); } @@ -3340,9 +3315,7 @@ int16_t LR11x0::gnssGetResultSize(uint16_t* size) { } int16_t LR11x0::gnssReadResults(uint8_t* result, uint16_t size) { - if(!result) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(result); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS, false, result, size)); } @@ -3639,9 +3612,7 @@ void LR11x0::gnssAbort() { } int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { - if(!key) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(key); uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; buff[0] = keyId; memcpy(&buff[1], key, RADIOLIB_AES128_KEY_SIZE); @@ -3649,9 +3620,7 @@ int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { } int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key) { - if(!key) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(key); uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; buff[0] = srcKeyId; buff[1] = dstKeyId; @@ -3849,23 +3818,17 @@ int16_t LR11x0::bootReboot(bool stay) { } int16_t LR11x0::bootGetPin(uint8_t* pin) { - if(!pin) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(pin); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); } int16_t LR11x0::bootGetChipEui(uint8_t* eui) { - if(!eui) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(eui); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { - if(!eui) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(eui); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 135ed05c10..46c744e330 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1663,9 +1663,7 @@ int16_t SX126x::invertIQ(bool enable) { } int16_t SX126x::getModem(ModemType_t* modem) { - if(!modem) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(modem); uint8_t packetType = getPacketType(); switch(packetType) { diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 425b1cb1cd..a8c612276d 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1755,9 +1755,7 @@ int16_t SX127x::invertIQ(bool enable) { } int16_t SX127x::getModem(ModemType_t* modem) { - if(!modem) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(modem); int16_t packetType = getActiveModem(); switch(packetType) { diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 5847f3d6c2..7a5fc20b11 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -870,9 +870,7 @@ int16_t SX128x::setModem(ModemType_t modem) { } int16_t SX128x::getModem(ModemType_t* modem) { - if(!modem) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(modem); uint8_t packetType = getPacketType(); switch(packetType) { diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index e4914dd6bc..9d56ea40d4 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -316,9 +316,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; - if(!data) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(data); #endif // read the received data diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 1ad04e69cc..2872cca312 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -78,9 +78,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { } else { data = new uint8_t[length + 1]; } - if(!data) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(data); #endif // attempt packet reception @@ -180,9 +178,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; - if(!data) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } + RADIOLIB_ASSERT_PTR(data); #endif // read the received data From b12f7052bfd422b1d676b5625fda97294c429983 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Oct 2024 16:59:46 +0100 Subject: [PATCH 1313/1848] [CI] Drop Sparkfun Artemis from build matrix due to lonmg build time --- .github/workflows/main.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba5e493d98..06c8d6f826 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,7 +26,6 @@ on: - esp32:esp32:esp32 - esp8266:esp8266:generic - Intel:arc32:arduino_101 - - SparkFun:apollo3:sfe_artemis - STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC - STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1 - stm32duino:STM32F1:mapleMini @@ -83,11 +82,6 @@ jobs: echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - - id: SparkFun:apollo3:sfe_artemis - run: | - echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT - echo "warnings='none'" >> $GITHUB_OUTPUT - echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT - id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC run: | echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT From 709fbdb13a6a5a2010d0f2887c8cde6f6cadc1a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Oct 2024 17:07:37 +0100 Subject: [PATCH 1314/1848] [LR11x0] Prevent WiFi scanning attempts on LR1121 (#1290) --- src/modules/LR11x0/LR1121.h | 3 --- src/modules/LR11x0/LR11x0.cpp | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/LR11x0/LR1121.h b/src/modules/LR11x0/LR1121.h index 2dc0242bda..b1766c4bf4 100644 --- a/src/modules/LR11x0/LR1121.h +++ b/src/modules/LR11x0/LR1121.h @@ -21,9 +21,6 @@ class LR1121: public LR1120 { */ LR1121(Module* mod); // cppcheck-suppress noExplicitConstructor - // TODO this is where overrides to disable GNSS+WiFi scanning methods on LR1121 - // will be put once those are implemented - #if !RADIOLIB_GODMODE private: #endif diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 2f97cc8f09..aaf00bfed7 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1512,6 +1512,11 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16 } int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { + // LR1121 cannot do WiFi scanning + if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) { + return(RADIOLIB_ERR_UNSUPPORTED); + } + uint8_t type; switch(wifiType) { case('b'): From f23f798fe0e0f5a1016e013ad55ce8c86d82048c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 26 Oct 2024 18:13:02 +0100 Subject: [PATCH 1315/1848] [SX126x] Configure preamble detector length based on preamble --- src/modules/SX126x/SX126x.cpp | 25 +++++++++++++++---------- src/modules/SX126x/SX126x.h | 4 ++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 46c744e330..3e3e2e3153 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -968,7 +968,12 @@ int16_t SX126x::setPreambleLength(size_t preambleLength) { return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { this->preambleLengthFSK = preambleLength; - return(setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType)); + this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : + preambleLength >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : + preambleLength >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : + preambleLength > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : + RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; + return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType)); } return(RADIOLIB_ERR_UNKNOWN); @@ -1195,7 +1200,7 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { // update packet parameters this->syncWordLength = len * 8; - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); return(state); @@ -1245,7 +1250,7 @@ int16_t SX126x::setNodeAddress(uint8_t addr) { // enable address filtering (node only) this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE; - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // set node address @@ -1263,7 +1268,7 @@ int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) { // enable address filtering (node and broadcast) this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // set broadcast address @@ -1280,7 +1285,7 @@ int16_t SX126x::disableAddressFiltering() { // disable address filtering this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; - return(setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening)); + return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening)); } int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { @@ -1311,7 +1316,7 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // write initial CRC value @@ -1353,7 +1358,7 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { // disable whitening this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); } else { @@ -1373,7 +1378,7 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); RADIOLIB_ASSERT(state); - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); RADIOLIB_ASSERT(state); } return(state); @@ -1998,7 +2003,7 @@ int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { } // set requested packet mode - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, mode, len); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, mode, len); RADIOLIB_ASSERT(state); // update cached value @@ -2055,7 +2060,7 @@ int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t p return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); } -int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen, uint8_t preambleDetectorLen) { +int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen) { uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten}; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 8a0348c3ed..e644407225 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1233,7 +1233,7 @@ class SX126x: public PhysicalLayer { int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev); int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ); - int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF, uint8_t preambleDetectorLen = RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16); + int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setRegulatorMode(uint8_t mode); uint8_t getStatus(); @@ -1267,7 +1267,7 @@ class SX126x: public PhysicalLayer { bool ldroAuto = true; uint32_t bitRate = 0, frequencyDev = 0; - uint8_t rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; + uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; uint16_t preambleLengthFSK = 0; float rxBandwidthKhz = 0; uint8_t nodeAddr = 0; From 9f4c15333ce88c4fc0f2a22264d0b9e42ab14a32 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 07:18:04 +0000 Subject: [PATCH 1316/1848] [LoRaWAN] Fix debug variable --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7e6e4a8c56..b38bf97cc5 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2861,7 +2861,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; syncWordLen = 4; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LR-FHSS: BW = 0x%02x, CR = 0x%02x kHz, grid = %c", - dr.lrfhss.bw, dr.lrfhss.cr, dr.lrFhss.narrowGrid ? 'N' : 'W'); + dr.lrFhss.bw, dr.lrFhss.cr, dr.lrFhss.narrowGrid ? 'N' : 'W'); } break; default: From 28360f9b0f73222197f75c3db08b82a599b8ca8f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 07:39:46 +0000 Subject: [PATCH 1317/1848] [LR11x0] Calibrate image based on frequency change --- src/modules/LR11x0/LR1110.cpp | 20 +++++++++++++------- src/modules/LR11x0/LR1110.h | 9 ++++++--- src/modules/LR11x0/LR1120.cpp | 13 ++++++++----- src/modules/LR11x0/LR1120.h | 12 ++++++++---- src/modules/LR11x0/LR11x0.cpp | 6 +++--- src/modules/LR11x0/LR11x0.h | 12 +++++++++++- 6 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 0950a3a34d..26cbe2a706 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -1,4 +1,6 @@ #include "LR1110.h" +#include + #if !RADIOLIB_EXCLUDE_LR11X0 LR1110::LR1110(Module* mod) : LR11x0(mod) { @@ -45,20 +47,24 @@ int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, } int16_t LR1110::setFrequency(float freq) { - return(this->setFrequency(freq, true)); + return(this->setFrequency(freq, false)); } -int16_t LR1110::setFrequency(float freq, bool calibrate, float band) { +int16_t LR1110::setFrequency(float freq, bool skipCalibration, float band) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); - - // calibrate image rejection - if(calibrate) { - int16_t state = LR11x0::calibImage(freq - band, freq + band); + + // check if we need to recalibrate image + int16_t state; + if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ)) { + state = LR11x0::calibrateImageRejection(freq - band, freq + band); RADIOLIB_ASSERT(state); } // set frequency - return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f))); + state = LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)); + RADIOLIB_ASSERT(state); + this->freqMHz = freq; + return(state); } int16_t LR1110::setOutputPower(int8_t power) { diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index bd7818f8fb..b20388593e 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -71,7 +71,8 @@ class LR1110: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. - Will also perform calibrations. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ @@ -79,14 +80,16 @@ class LR1110: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG MHz. \param freq Carrier frequency to be set in MHz. - \param calibrate Run image calibration. + \param skipCalibration Skip automated image calibration. \param band Half bandwidth for image calibration. For example, if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate, float band = 4); + int16_t setFrequency(float freq, bool skipCalibration, float band = 4); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index ae4dc4a155..61294b7f2b 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -1,4 +1,6 @@ #include "LR1120.h" +#include + #if !RADIOLIB_EXCLUDE_LR11X0 LR1120::LR1120(Module* mod) : LR11x0(mod) { @@ -45,26 +47,27 @@ int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, } int16_t LR1120::setFrequency(float freq) { - return(this->setFrequency(freq, true)); + return(this->setFrequency(freq, false)); } -int16_t LR1120::setFrequency(float freq, bool calibrate, float band) { +int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) { if(!(((freq >= 150.0) && (freq <= 960.0)) || ((freq >= 1900.0) && (freq <= 2200.0)) || ((freq >= 2400.0) && (freq <= 2500.0)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } - // calibrate image rejection + // check if we need to recalibrate image int16_t state; - if(calibrate) { - state = LR11x0::calibImage(freq - band, freq + band); + if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ)) { + state = LR11x0::calibrateImageRejection(freq - band, freq + band); RADIOLIB_ASSERT(state); } // set frequency state = LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)); RADIOLIB_ASSERT(state); + this->freqMHz = freq; this->highFreq = (freq > 1000.0); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index dde2420880..3c532ebd14 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -71,7 +71,9 @@ class LR1120: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, - 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + 1900 - 2200 MHz and 2400 - 2500 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG MHz. NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, setOutputPower() must be called in order to set the correct power amplifier! \param freq Carrier frequency to be set in MHz. @@ -81,17 +83,19 @@ class LR1120: public LR11x0 { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, - 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + 1900 - 2200 MHz and 2400 - 2500 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG MHz. NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, setOutputPower() must be called in order to set the correct power amplifier! \param freq Carrier frequency to be set in MHz. - \param calibrate Run image calibration. + \param skipCalibration Skip automated image calibration. \param band Half bandwidth for image calibration. For example, if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate, float band = 4); + int16_t setFrequency(float freq, bool skipCalibration, float band = 4); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA). diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index aaf00bfed7..06686be20a 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2400,10 +2400,10 @@ int16_t LR11x0::setRegMode(uint8_t mode) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1)); } -int16_t LR11x0::calibImage(float freq1, float freq2) { +int16_t LR11x0::calibrateImageRejection(float freqMin, float freqMax) { uint8_t buff[2] = { - (uint8_t)floor((freq1 - 1.0f) / 4.0f), - (uint8_t)ceil((freq2 + 1.0f) / 4.0f) + (uint8_t)floor((freqMin - 1.0f) / 4.0f), + (uint8_t)ceil((freqMax + 1.0f) / 4.0f) }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff))); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 490c120381..68a3f5de19 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -233,6 +233,7 @@ #define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC #define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC #define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything +#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0) // RADIOLIB_LR11X0_CMD_SET_REG_MODE #define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes @@ -1609,6 +1610,15 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t getModem(ModemType_t* modem) override; + + /*! + \brief Perform image rejection calibration for the specified frequency band. + WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance + \param freqMin Frequency band lower bound. + \param freqMax Frequency band upper bound. + \returns \ref status_codes + */ + int16_t calibrateImageRejection(float freqMin, float freqMax); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -1629,7 +1639,6 @@ class LR11x0: public PhysicalLayer { int16_t clearErrors(void); int16_t calibrate(uint8_t params); int16_t setRegMode(uint8_t mode); - int16_t calibImage(float freq1, float freq2); int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg); int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2); int16_t setDioIrqParams(uint32_t irq); @@ -1790,6 +1799,7 @@ class LR11x0: public PhysicalLayer { protected: #endif uint8_t chipType = 0; + float freqMHz = 0; #if !RADIOLIB_GODMODE private: From b8b1afdae1b843a166d7fccf9e76f3ad1eaf4816 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 07:40:10 +0000 Subject: [PATCH 1318/1848] [SX126x] Calibrate image based on frequency change (#1292) --- src/modules/SX126x/SX1262.cpp | 45 +++++---------------------- src/modules/SX126x/SX1262.h | 8 +++-- src/modules/SX126x/SX1268.cpp | 39 +++++------------------ src/modules/SX126x/SX1268.h | 8 +++-- src/modules/SX126x/SX126x.cpp | 42 +++++++++++++++++++++++-- src/modules/SX126x/SX126x.h | 12 ++++++- src/modules/SX126x/SX126x_LR_FHSS.cpp | 3 +- 7 files changed, 79 insertions(+), 78 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index c4e20eb2cc..85253ab8d8 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -1,4 +1,6 @@ #include "SX1262.h" +#include + #if !RADIOLIB_EXCLUDE_SX126X SX1262::SX1262(Module* mod) : SX126x(mod) { @@ -66,49 +68,16 @@ int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, } int16_t SX1262::setFrequency(float freq) { - return(setFrequency(freq, true)); + return(setFrequency(freq, false)); } -int16_t SX1262::setFrequency(float freq, bool calibrate) { +int16_t SX1262::setFrequency(float freq, bool skipCalibration) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); - // calibrate image rejection - if(calibrate) { - uint8_t data[2] = { 0, 0 }; - - // try to match the frequency ranges - int freqBand = (int)freq; - if((freqBand >= 902) && (freqBand <= 928)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2; - } else if((freqBand >= 863) && (freqBand <= 870)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; - } else if((freqBand >= 779) && (freqBand <= 787)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; - } else if((freqBand >= 470) && (freqBand <= 510)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else if((freqBand >= 430) && (freqBand <= 440)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; - } - - int16_t state; - if(data[0]) { - // matched with predefined ranges, do the calibration - state = SX126x::calibrateImage(data); - - } else { - // if nothing matched, try custom calibration - the may or may not work - RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom"); - state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f); - - } - + // check if we need to recalibrate image + if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) { + int16_t state = this->calibrateImage(freq); RADIOLIB_ASSERT(state); - } // set frequency diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 0dc2744448..a7e0b677af 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -81,6 +81,8 @@ class SX1262: public SX126x { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ @@ -88,11 +90,13 @@ class SX1262: public SX126x { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ. \param freq Carrier frequency to be set in MHz. - \param calibrate Run image calibration. + \param skipCalibration Skip automated image calibration. \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate); + int16_t setFrequency(float freq, bool skipCalibration); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index a8095b5a5c..6ae42ea849 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -1,4 +1,6 @@ #include "SX1268.h" +#include + #if !RADIOLIB_EXCLUDE_SX126X SX1268::SX1268(Module* mod) : SX126x(mod) { @@ -66,44 +68,17 @@ int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, } int16_t SX1268::setFrequency(float freq) { - return(setFrequency(freq, true)); + return(setFrequency(freq, false)); } /// \todo integers only (all modules - frequency, data rate, bandwidth etc.) -int16_t SX1268::setFrequency(float freq, bool calibrate) { +int16_t SX1268::setFrequency(float freq, bool skipCalibration) { RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); - // calibrate image rejection - if(calibrate) { - uint8_t data[2] = { 0, 0 }; - - // try to match the frequency ranges - int freqBand = (int)freq; - if((freqBand >= 779) && (freqBand <= 787)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; - } else if((freqBand >= 470) && (freqBand <= 510)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else if((freqBand >= 430) && (freqBand <= 440)) { - data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; - } - - int16_t state; - if(data[0]) { - // matched with predefined ranges, do the calibration - state = SX126x::calibrateImage(data); - - } else { - // if nothing matched, try custom calibration - the may or may not work - RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom"); - state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f); - - } - + // check if we need to recalibrate image + if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) { + int16_t state = this->calibrateImage(freq); RADIOLIB_ASSERT(state); - } // set frequency diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 87cf9b5c75..c34bec8dd5 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -80,6 +80,8 @@ class SX1268: public SX126x { /*! \brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ @@ -87,11 +89,13 @@ class SX1268: public SX126x { /*! \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ. \param freq Carrier frequency to be set in MHz. - \param calibrate Run image calibration. + \param skipCalibration Skip automated image calibration. \returns \ref status_codes */ - int16_t setFrequency(float freq, bool calibrate); + int16_t setFrequency(float freq, bool skipCalibration); /*! \brief Sets output power. Allowed values are in range from -9 to 22 dBm. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 3e3e2e3153..8f8878c210 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1954,6 +1954,43 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } +int16_t SX126x::calibrateImage(float freq) { + uint8_t data[2] = { 0, 0 }; + + // try to match the frequency ranges + int freqBand = (int)freq; + if((freqBand >= 902) && (freqBand <= 928)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2; + } else if((freqBand >= 863) && (freqBand <= 870)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; + } else if((freqBand >= 779) && (freqBand <= 787)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2; + } else if((freqBand >= 470) && (freqBand <= 510)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; + } else if((freqBand >= 430) && (freqBand <= 440)) { + data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; + } + + int16_t state; + if(data[0]) { + // matched with predefined ranges, do the calibration + state = SX126x::calibrateImage(data); + + } else { + // if nothing matched, try custom calibration - the may or may not work + RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom"); + state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f); + + } + + return(state); +} + int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) { // calculate the calibration coefficients and calibrate image uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) }; @@ -2103,8 +2140,9 @@ int16_t SX126x::clearDeviceErrors() { int16_t SX126x::setFrequencyRaw(float freq) { // calculate raw value - this->frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; - return(setRfFrequency(this->frf)); + this->freqMHz = freq; + uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; + return(setRfFrequency(frf)); } int16_t SX126x::fixSensitivity() { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index e644407225..d1ca5451f7 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -201,6 +201,7 @@ #define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB #define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 #define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 +#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0) //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 @@ -1195,6 +1196,15 @@ class SX126x: public PhysicalLayer { */ int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT); + /*! + \brief Perform image rejection calibration for the specified frequency. + Will try to use Semtech-defined presets first, and if none of them matches, + custom iamge calibration will be attempted using calibrateImageRejection. + \param freq Frequency to perform the calibration for. + \returns \ref status_codes + */ + int16_t calibrateImage(float freq); + /*! \brief Perform image rejection calibration for the specified frequency band. WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance @@ -1246,6 +1256,7 @@ class SX126x: public PhysicalLayer { #endif const char* chipType = NULL; uint8_t bandwidth = 0; + float freqMHz = 0; // Allow subclasses to define different TX modes uint8_t txMode = Module::MODE_TX; @@ -1276,7 +1287,6 @@ class SX126x: public PhysicalLayer { uint32_t tcxoDelay = 0; uint8_t pwr = 0; - uint32_t frf = 0; size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; diff --git a/src/modules/SX126x/SX126x_LR_FHSS.cpp b/src/modules/SX126x/SX126x_LR_FHSS.cpp index f7cae3780f..b0e8a2b890 100644 --- a/src/modules/SX126x/SX126x_LR_FHSS.cpp +++ b/src/modules/SX126x/SX126x_LR_FHSS.cpp @@ -355,7 +355,8 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) { uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52; uint32_t grid_offset = (1 + (this->lrFhssNgrid % 2)) * (nb_channel_in_grid / 2); uint32_t grid_in_pll_steps = this->lrFhssGridNonFcc ? 4096 : 26624; - uint32_t freq_raw = this->frf - freq_table * grid_in_pll_steps - grid_offset * 512; + uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; + uint32_t freq_raw = frf - freq_table * grid_in_pll_steps - grid_offset * 512; if((this->lrFhssHopNum < this->lrFhssHdrCount)) { if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) { From 88e11fa0a2e18830c9e2954ff6a66231f753d03b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 08:17:56 +0000 Subject: [PATCH 1319/1848] Added note about Arduino Uno and smaller --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a5eeaf49cd..c608e2d6f7 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ SX127x, RFM9x, SX126x, LR11x0 and SX128x ### Supported Arduino platforms: * __Arduino__ * [__AVR__](https://github.com/arduino/ArduinoCore-avr) - Arduino Uno, Mega, Leonardo, Pro Mini, Nano etc. + * NOTE: Arduino boards based on ATmega328 (Uno, Pro Mini, Nano etc.) and smaller are NOT recommended. This is because the ATmega328 MCU is very constrained in terms of program and memory size, so the library will end up taking most of the space available. * [__mbed__](https://github.com/arduino/ArduinoCore-mbed) - Arduino Nano 33 BLE and Arduino Portenta H7 * [__megaAVR__](https://github.com/arduino/ArduinoCore-megaavr) - Arduino Uno WiFi Rev.2 and Nano Every * [__SAM__](https://github.com/arduino/ArduinoCore-sam) - Arduino Due From 334b5fd499dd1502b49a7d51c395d53880ae27a8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 19:23:35 +0000 Subject: [PATCH 1320/1848] [MOD] Added flag to distinguish DIO and GPIO pins --- src/BuildOpt.h | 4 ++-- src/Module.cpp | 11 +++++++---- src/Module.h | 7 +++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 80baff153c..195bea1c8c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -129,7 +129,7 @@ * Platform-specific configuration. * * RADIOLIB_PLATFORM - platform name, used in debugging to quickly check the correct platform is detected. - * RADIOLIB_NC - alias for unused pin, usually the largest possible value of uint8_t. + * RADIOLIB_NC - alias for unused pin, usually the largest possible value of uint32_t. * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. * RADIOLIB_NONVOLATILE - macro to place variable into program storage (usually Flash). * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). @@ -422,7 +422,7 @@ // generic non-Arduino platform #define RADIOLIB_PLATFORM "Generic" - #define RADIOLIB_NC (0xFF) + #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_NONVOLATILE #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*((uint8_t *)(void *)(addr))) #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*((uint32_t *)(void *)(addr))) diff --git a/src/Module.cpp b/src/Module.cpp index 8cc308d238..7b3c59aef3 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -489,15 +489,17 @@ void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { void Module::setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]) { memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins)); this->rfSwitchTable = table; - for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) + for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { this->hal->pinMode(pins[i], this->hal->GpioModeOutput); + } } const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const { const RfSwitchMode_t *row = this->rfSwitchTable; - while (row && row->mode != MODE_END_OF_TABLE) { - if (row->mode == mode) + while(row && row->mode != MODE_END_OF_TABLE) { + if(row->mode == mode) { return row; + } ++row; } return nullptr; @@ -514,8 +516,9 @@ void Module::setRfSwitchState(uint8_t mode) { const uint32_t *value = &row->values[0]; for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) { uint32_t pin = this->rfSwitchPins[i]; - if (pin != RADIOLIB_NC) + if(!(pin & RFSWITCH_PIN_FLAG)) { this->hal->digitalWrite(pin, *value); + } ++value; } } diff --git a/src/Module.h b/src/Module.h index 5d5072bf55..946c42e4d7 100644 --- a/src/Module.h +++ b/src/Module.h @@ -19,6 +19,13 @@ */ #define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} } +/*! + \def RFSWITCH_PIN_FLAG Bit flag used to mark unused pins in RF switch pin map. This can be either + unconnected pin marked with RADIOLIB_NC, or a pin controlled by the radio (e.g. DIOx pins on LR11x0), + as opposed to an MCU-controlled GPIO pin. +*/ +#define RFSWITCH_PIN_FLAG (0x01UL << 31) + /*! \defgroup module_spi_command_pos Position of commands in Module::spiConfig command array. \{ From 9f4d4ea15e2ec4bc025a51dc50a0959501083c40 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 19:24:11 +0000 Subject: [PATCH 1321/1848] [LR11x0] Fix RF swtich table handling (#1295) --- src/modules/LR11x0/LR11x0.cpp | 25 ++++++++++++++++++++++--- src/modules/LR11x0/LR11x0.h | 12 +++++++----- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 06686be20a..6d41e3e2db 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1445,17 +1445,36 @@ void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], // find which pins are used uint8_t enable = 0; for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) { - if((pins[i] == RADIOLIB_NC) || (pins[i] > RADIOLIB_LR11X0_DIO10)) { + // check if this pin is unused + if(pins[i] == RADIOLIB_NC) { continue; } - enable |= 1UL << pins[i]; + + // only keep DIO pins, there may be some GPIOs in the switch tabke + if(pins[i] & RFSWITCH_PIN_FLAG) { + enable |= 1UL << RADIOLIB_LR11X0_DIOx_VAL(pins[i]); + } + } // now get the configuration uint8_t modes[7] = { 0 }; for(size_t i = 0; i < 7; i++) { + // check end of table + if(table[i].mode == LR11x0::MODE_END_OF_TABLE) { + break; + } + + // get the mode ID in case the modes are out-of-order + uint8_t index = table[i].mode - LR11x0::MODE_STBY; + + // iterate over the pins for(size_t j = 0; j < Module::RFSWITCH_MAX_PINS; j++) { - modes[i] |= (table[i].values[j] > 0) ? (1UL << j) : 0; + // only process modes for the DIOx pins, skip GPIO pins + if(!(pins[j] & RFSWITCH_PIN_FLAG)) { + continue; + } + modes[index] |= (table[i].values[j] == this->mod->hal->GpioLevelHigh) ? (1UL << j) : 0; } } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 68a3f5de19..974e8e3b35 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -250,11 +250,13 @@ #define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default) #define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled #define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default) -#define RADIOLIB_LR11X0_DIO5 (0) -#define RADIOLIB_LR11X0_DIO6 (1) -#define RADIOLIB_LR11X0_DIO7 (2) -#define RADIOLIB_LR11X0_DIO8 (3) -#define RADIOLIB_LR11X0_DIO10 (4) +#define RADIOLIB_LR11X0_DIOx(X) ((X) | RFSWITCH_PIN_FLAG) +#define RADIOLIB_LR11X0_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG) +#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LR11X0_DIOx(0)) +#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LR11X0_DIOx(1)) +#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LR11X0_DIOx(2)) +#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LR11X0_DIOx(3)) +#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LR11X0_DIOx(4)) // RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS #define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted From 0156c9004efee62dca24aa5a4e012775f233d3d4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 27 Oct 2024 19:29:42 +0000 Subject: [PATCH 1322/1848] [LR11x0] Fix RF switch call in examples (#1295) --- ...x0_Channel_Activity_Detection_Blocking.ino | 7 +++--- ...0_Channel_Activity_Detection_Interrupt.ino | 7 +++--- .../LR11x0_GNSS_Almanac_Update.ino | 23 +++++++++++++++++++ .../LR11x0_GNSS_Autonomous_Position.ino | 23 +++++++++++++++++++ .../LR11x0_GNSS_Satellites.ino | 23 +++++++++++++++++++ .../LR11x0_PingPong/LR11x0_PingPong.ino | 7 +++--- .../LR11x0_Receive_Blocking.ino | 7 +++--- .../LR11x0_Receive_Interrupt.ino | 7 +++--- .../LR11x0_Transmit_Blocking.ino | 7 +++--- .../LR11x0_Transmit_Interrupt.ino | 7 +++--- .../LR11x0_WiFi_Scan_Blocking.ino | 7 +++--- .../LR11x0_WiFi_Scan_Interrupt.ino | 7 +++--- 12 files changed, 96 insertions(+), 36 deletions(-) diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino index 81b3f7bd57..0a6c13ca08 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Blocking/LR11x0_Channel_Activity_Detection_Blocking.ino @@ -65,10 +65,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -79,6 +75,9 @@ void setup() { Serial.println(state); while (true) { delay(10); } } + + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); } void loop() { diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index 304bbc9d92..e7e295cb9b 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -60,10 +60,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -75,6 +71,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // set the function that will be called // when LoRa packet or timeout is detected radio.setIrqAction(setFlag); diff --git a/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino b/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino index 444ee65740..0f02a25367 100644 --- a/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino +++ b/examples/LR11x0/LR11x0_GNSS_Almanac_Update/LR11x0_GNSS_Almanac_Update.ino @@ -41,6 +41,26 @@ LR1110 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5 and DIO6 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, + END_OF_MODE_TABLE, +}; + // structure to save information about the GNSS almanac LR11x0GnssAlmanacStatus_t almStatus; @@ -58,6 +78,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // check the firmware version Serial.print(F("[LR1110] Checking firmware version ... ")); state = radio.isGnssScanCapable(); diff --git a/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino b/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino index 800a21b85e..994b749da5 100644 --- a/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino +++ b/examples/LR11x0/LR11x0_GNSS_Autonomous_Position/LR11x0_GNSS_Autonomous_Position.ino @@ -37,6 +37,26 @@ LR1110 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5 and DIO6 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, + END_OF_MODE_TABLE, +}; + // structure to save information about the GNSS scan result LR11x0GnssResult_t gnssResult; @@ -57,6 +77,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // check the firmware version Serial.print(F("[LR1110] Checking firmware version ... ")); state = radio.isGnssScanCapable(); diff --git a/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino b/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino index bd84bc4573..ad0457c927 100644 --- a/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino +++ b/examples/LR11x0/LR11x0_GNSS_Satellites/LR11x0_GNSS_Satellites.ino @@ -37,6 +37,26 @@ LR1110 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// set RF switch configuration for Wio WM1110 +// Wio WM1110 uses DIO5 and DIO6 for RF switching +// NOTE: other boards may be different! +static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { HIGH, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, + END_OF_MODE_TABLE, +}; + // structure to save information about the GNSS scan result LR11x0GnssResult_t gnssResult; @@ -54,6 +74,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // check the firmware version Serial.print(F("[LR1110] Checking firmware version ... ")); state = radio.isGnssScanCapable(); diff --git a/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino b/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino index b6b5e08de2..a2a62f9611 100644 --- a/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino +++ b/examples/LR11x0/LR11x0_PingPong/LR11x0_PingPong.ino @@ -74,10 +74,6 @@ void setFlag(void) { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -89,6 +85,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // set the function that will be called // when new packet is received radio.setIrqAction(setFlag); diff --git a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino index aeb40679f5..341b1a74d2 100644 --- a/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino +++ b/examples/LR11x0/LR11x0_Receive_Blocking/LR11x0_Receive_Blocking.ino @@ -70,10 +70,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -84,6 +80,9 @@ void setup() { Serial.println(state); while (true) { delay(10); } } + + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); } void loop() { diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index 76b8919fb0..372c208f05 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -66,10 +66,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -81,6 +77,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // set the function that will be called // when new packet is received radio.setPacketReceivedAction(setFlag); diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index bad54bd1d0..66a9058dff 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -61,10 +61,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -76,6 +72,9 @@ void setup() { delay(1000); while (true) { delay(10); } } + + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); } // counter to keep track of transmitted packets diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 2efdc263d9..8e40eff29a 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -65,10 +65,6 @@ int transmissionState = RADIOLIB_ERR_NONE; void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -80,6 +76,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // set the function that will be called // when packet transmission is finished radio.setPacketSentAction(setFlag); diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino index 53bafd36bd..6da1b356e5 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Blocking/LR11x0_WiFi_Scan_Blocking.ino @@ -63,10 +63,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -77,6 +73,9 @@ void setup() { Serial.println(state); while (true) { delay(10); } } + + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); } void loop() { diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino index fcae902a7a..38872f2e84 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -63,10 +63,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { void setup() { Serial.begin(9600); - // set RF switch control configuration - // this has to be done prior to calling begin() - radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); - // initialize LR1110 with default settings Serial.print(F("[LR1110] Initializing ... ")); int state = radio.begin(); @@ -78,6 +74,9 @@ void setup() { while (true) { delay(10); } } + // set RF switch control configuration + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + // set the function that will be called // when WiFi scan is complete radio.setIrqAction(setFlag); From 412136845fa3f00ea2bee7db7e1c57d887ee2db5 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 13:02:58 +0100 Subject: [PATCH 1323/1848] [LoRaWAN] Fix persistence of channel mask (fixes #1293) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b38bf97cc5..f184c4b292 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2917,10 +2917,9 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr *chMaskGrp0123 = 0; *chMaskGrp45 = 0; - uint8_t numCh = this->getAvailableChannels(NULL); - // if there are any channels selected, create the mask from those channels - if(numCh > 0) { + // channels are always selected for dynamic bands and/or when a device is active + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC || this->isActivated()) { for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { @@ -2932,12 +2931,6 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr } } return; - } - - // it should not happen that no channels are set for dynamic band - // but in that case, simply return - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - return; } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED // if a subband is set, we can set the channel indices straight from subband From a953475b9a4324cd141a244e2dcb4e7bf266ef7d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 13:08:37 +0100 Subject: [PATCH 1324/1848] [ArduinoHal] Fix missing directory specifier in include --- src/hal/Arduino/ArduinoHal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/Arduino/ArduinoHal.h b/src/hal/Arduino/ArduinoHal.h index 959b9d2295..17efeec1c7 100644 --- a/src/hal/Arduino/ArduinoHal.h +++ b/src/hal/Arduino/ArduinoHal.h @@ -1,5 +1,5 @@ // make sure this is always compiled -#include "TypeDef.h" +#include "../../TypeDef.h" #if !defined(_RADIOLIB_ARDUINOHAL_H) #define _RADIOLIB_ARDUINOHAL_H From 1c0019ad1896a6a1979abddc86cc43148b3225ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 14:01:26 +0100 Subject: [PATCH 1325/1848] [SX126x] Fix signed comparison warning --- src/modules/SX126x/SX126x_LR_FHSS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x_LR_FHSS.cpp b/src/modules/SX126x/SX126x_LR_FHSS.cpp index b0e8a2b890..0f491f9151 100644 --- a/src/modules/SX126x/SX126x_LR_FHSS.cpp +++ b/src/modules/SX126x/SX126x_LR_FHSS.cpp @@ -123,7 +123,7 @@ int16_t SX126x::buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out // interleave the payload into output buffer uint16_t step = 0; - while(step * step < nb_bits) { + while((size_t)(step * step) < nb_bits) { // probably the silliest sqrt() I ever saw step++; } From f8b66b1cb5936b12b0a5212a041a67b653636471 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 14:04:48 +0100 Subject: [PATCH 1326/1848] [LR11x0] Added setDatarate for LR-FHSS --- src/modules/LR11x0/LR11x0.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6d41e3e2db..f87a7f88a8 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1078,7 +1078,12 @@ int16_t LR11x0::setDataRate(DataRate_t dr) { state = this->setCodingRate(dr.lora.codingRate); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + // set the basic config + state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); + RADIOLIB_ASSERT(state); + // set hopping grid + this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC; } From e2fd3f7532e199082e6ec4fa9c5bee7f8054a2cc Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 14:04:56 +0100 Subject: [PATCH 1327/1848] [SX126x] Added setDatarate for LR-FHSS --- src/modules/SX126x/SX126x.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 8f8878c210..23f5e38fdb 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1048,6 +1048,15 @@ int16_t SX126x::setDataRate(DataRate_t dr) { // set the coding rate state = this->setCodingRate(dr.lora.codingRate); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + // set the basic config + state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); + RADIOLIB_ASSERT(state); + + // set hopping grid + this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC; + } return(state); From 4bd05dee3d88c452c1e100c49d63152e589ca122 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 14:06:36 +0100 Subject: [PATCH 1328/1848] [SX126x] Fix member variable --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 23f5e38fdb..16062db119 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1055,7 +1055,7 @@ int16_t SX126x::setDataRate(DataRate_t dr) { RADIOLIB_ASSERT(state); // set hopping grid - this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC; + this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC; } From 9f04da29af41c60610fe4a67c2a67d5d6e7b1bf3 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 14:20:09 +0100 Subject: [PATCH 1329/1848] [PHY] Bump LR-FHSS bw member to `float` --- src/protocols/PhysicalLayer/PhysicalLayer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index c5467990ef..0b64df7f2e 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -58,7 +58,7 @@ struct FSKRate_t { */ struct LrFhssRate_t { /*! \brief Bandwidth */ - uint8_t bw; + float bw; /*! \brief Coding rate */ uint8_t cr; From ef0cfddd01f2802de3b2d99a62f4f740f447e068 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 14:20:26 +0100 Subject: [PATCH 1330/1848] [LoRaWAN] Improve modem switching --- src/protocols/LoRaWAN/LoRaWAN.cpp | 46 +++++++++++++++++++++++++++++-- src/protocols/LoRaWAN/LoRaWAN.h | 3 +- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index f184c4b292..9d5427baa3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -3299,10 +3299,13 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { return(state); } + ModemType_t modemNew; + uint8_t dataRateBand = this->band->dataRates[dr]; switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { case(RADIOLIB_LORAWAN_DATA_RATE_LORA): + modemNew = ModemType_t::LoRa; dataRate->lora.spreadingFactor = ((dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_SF) >> 3) + 7; switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): @@ -3320,18 +3323,55 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.codingRate = 5; break; case(RADIOLIB_LORAWAN_DATA_RATE_FSK): + modemNew = ModemType_t::FSK; dataRate->fsk.bitRate = 50; dataRate->fsk.freqDev = 25; break; case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): - // not yet supported by DataRate_t - return(RADIOLIB_ERR_UNSUPPORTED); + modemNew = ModemType_t::LRFHSS; + switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { + case(RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ): + dataRate->lrFhss.bw = 137.0; + dataRate->lrFhss.narrowGrid = 1; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ): + dataRate->lrFhss.bw = 336.0; + dataRate->lrFhss.narrowGrid = 1; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ): + dataRate->lrFhss.bw = 1523.0; + dataRate->lrFhss.narrowGrid = 0; + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_CR) { + case(RADIOLIB_LORAWAN_DATA_RATE_CR_1_3): + dataRate->lrFhss.bw = 1; + break; + case(RADIOLIB_LORAWAN_DATA_RATE_CR_2_3): + dataRate->lrFhss.bw = 2; + break; + default: + return(RADIOLIB_ERR_UNSUPPORTED);; + } + break; default: return(RADIOLIB_ERR_UNSUPPORTED); } - state = this->phyLayer->checkDataRate(*dataRate); + // get the currently configured modem from the radio + ModemType_t modemCurrent; + state = this->phyLayer->getModem(&modemCurrent); + RADIOLIB_ASSERT(state); + // if the required modem is different than the current one, change over + if(modemNew != modemCurrent) { + state = this->phyLayer->setModem(modemNew); + RADIOLIB_ASSERT(state); + } + + state = this->phyLayer->checkDataRate(*dataRate); return(state); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 588882b9d2..cc9c364194 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -60,13 +60,14 @@ #define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x02 << 3) // 5 3 SF9 #define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x01 << 3) // 5 3 SF8 #define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x00 << 3) // 5 3 SF7 -#define RADIOLIB_LORAWAN_DATA_RATE_BW (0x03 << 1) // 2 1 bandwith mask +#define RADIOLIB_LORAWAN_DATA_RATE_BW (0x03 << 1) // 2 1 bandwidth mask #define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x00 << 1) // 2 1 125 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 1) // 2 1 250 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x02 << 1) // 2 1 LoRa bandwidth: 500 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ (0x00 << 1) // 2 1 137 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ (0x01 << 1) // 2 1 336 kHz #define RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ (0x02 << 1) // 2 1 LR-FHSS bandwidth: 1523 kHz +#define RADIOLIB_LORAWAN_DATA_RATE_CR (0x01 << 0) // 0 0 coding rate mask #define RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 (0x00 << 0) // 0 0 LR-FHSS coding rate: 1/3 #define RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 (0x01 << 0) // 0 0 2/3 #define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate From 6a5dcc6a6a38fe545bf14efe129cf7838f96375b Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 14:26:48 +0100 Subject: [PATCH 1331/1848] [PHY] Revert LR-FHSS bw back to `uint8_t` --- src/protocols/PhysicalLayer/PhysicalLayer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 0b64df7f2e..c5467990ef 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -58,7 +58,7 @@ struct FSKRate_t { */ struct LrFhssRate_t { /*! \brief Bandwidth */ - float bw; + uint8_t bw; /*! \brief Coding rate */ uint8_t cr; From 05d5ef2947f60f688ff5e6ad91249b65ff54db2a Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 14:27:04 +0100 Subject: [PATCH 1332/1848] [LoRaWAN] Fix LR-FHSS bw encoding --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 9d5427baa3..a0a4f86c51 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -3331,15 +3331,15 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { modemNew = ModemType_t::LRFHSS; switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { case(RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ): - dataRate->lrFhss.bw = 137.0; + dataRate->lrFhss.bw = 0x02; // specific encoding dataRate->lrFhss.narrowGrid = 1; break; case(RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ): - dataRate->lrFhss.bw = 336.0; + dataRate->lrFhss.bw = 0x04; // specific encoding dataRate->lrFhss.narrowGrid = 1; break; case(RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ): - dataRate->lrFhss.bw = 1523.0; + dataRate->lrFhss.bw = 0x08; // specific encoding dataRate->lrFhss.narrowGrid = 0; break; default: From 5cd5d714a8a9ee010b8f60cccb7f6d9d09849643 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 28 Oct 2024 14:32:35 +0100 Subject: [PATCH 1333/1848] [LoRaWAN] Fix LR-FHSS cr encoding --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a0a4f86c51..6b4666a47b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -3347,13 +3347,13 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { } switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_CR) { case(RADIOLIB_LORAWAN_DATA_RATE_CR_1_3): - dataRate->lrFhss.bw = 1; + dataRate->lrFhss.cr = 0x03; break; case(RADIOLIB_LORAWAN_DATA_RATE_CR_2_3): - dataRate->lrFhss.bw = 2; + dataRate->lrFhss.cr = 0x01; break; default: - return(RADIOLIB_ERR_UNSUPPORTED);; + return(RADIOLIB_ERR_UNSUPPORTED); } break; default: From 7bbaf38651d82567e632dbd8adefeb02d213b276 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 14:43:46 +0100 Subject: [PATCH 1334/1848] Bump version to 7.1.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 1b3292c660..9f175c3bc0 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.0.2" +version: "7.1.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index bd04ebf1b8..9c27984d18 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.0.2", + "version": "7.1.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 3b1bcba5c6..26e9ffef47 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.0.2 +version=7.1.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 195bea1c8c..35ee44830f 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -577,8 +577,8 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 -#define RADIOLIB_VERSION_MINOR 0 -#define RADIOLIB_VERSION_PATCH 2 +#define RADIOLIB_VERSION_MINOR 1 +#define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 15a751a543c692ac6f9425677612c3aa3b18b89f Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 18:51:43 +0000 Subject: [PATCH 1335/1848] [SX126x] Fix LR-FHSS sync word --- examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino index 9b2794476a..44519d51d3 100644 --- a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino +++ b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino @@ -62,7 +62,8 @@ void setup() { 3, // header count 0x13A); // hopping sequence seed state = radio.setOutputPower(10.0); - state = radio.setSyncWord(0x12345678); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + state = radio.setSyncWord(syncWord, 4); if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); From 8f3a5c7430c815bf5371512c1e2a68f16464fedc Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 18:52:07 +0000 Subject: [PATCH 1336/1848] [LR11x0] Use array as LR-FHSS sync word --- .../LR11x0_LR_FHSS_Modem.ino | 3 +- src/modules/LR11x0/LR11x0.cpp | 48 +++++++++++-------- src/modules/LR11x0/LR11x0.h | 6 +-- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino index a7de634dae..f1c7c1980a 100644 --- a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -62,7 +62,8 @@ void setup() { 3, // header count 0x13A); // hopping sequence seed state = radio.setOutputPower(10.0); - state = radio.setSyncWord(0x12345678); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + state = radio.setSyncWord(syncWord, 4); if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index f87a7f88a8..cedf5b5ba4 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -110,7 +110,8 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV state = setLrFhssConfig(bw, cr); RADIOLIB_ASSERT(state); - state = setSyncWord(0x12AD101B); + uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B }; + state = setSyncWord(syncWord, 4); RADIOLIB_ASSERT(state); state = setRegulatorLDO(); @@ -758,20 +759,16 @@ int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) { return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } -int16_t LR11x0::setSyncWord(uint32_t syncWord) { +int16_t LR11x0::setSyncWord(uint8_t syncWord) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { - return(setLoRaSyncWord(syncWord & 0xFF)); - - } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { - return(lrFhssSetSyncWord(syncWord)); - + if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); } - return(RADIOLIB_ERR_WRONG_MODEM); + return(setLoRaSyncWord(syncWord)); } int16_t LR11x0::setBitRate(float br) { @@ -885,27 +882,36 @@ int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) { uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // update sync word length + this->syncWordLength = len*8; + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // sync word is passed most-significant byte first + uint8_t fullSyncWord[RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN] = { 0 }; + memcpy(fullSyncWord, syncWord, len); + return(setGfskSyncWord(fullSyncWord)); + + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // with length set to 1 and LoRa modem active, assume it is the LoRa sync word if(len > 1) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } return(setSyncWord(syncWord[0])); - } else if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); + } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word + if(len != sizeof(uint32_t)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + uint32_t sync = 0; + memcpy(&sync, syncWord, sizeof(uint32_t)); + return(lrFhssSetSyncWord(sync)); } - // update sync word length - this->syncWordLength = len*8; - state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); - RADIOLIB_ASSERT(state); - - // sync word is passed most-significant byte first - uint8_t fullSyncWord[RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN] = { 0 }; - memcpy(fullSyncWord, syncWord, len); - return(setGfskSyncWord(fullSyncWord)); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t LR11x0::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 974e8e3b35..9ee985d5b3 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1176,11 +1176,11 @@ class LR11x0: public PhysicalLayer { int16_t setCodingRate(uint8_t cr, bool longInterleave = false); /*! - \brief Sets LoRa or LR-FHSS sync word. - \param syncWord LoRa or LR-FHSS sync word to be set. For LoRa, only 8 least significant bits will be used + \brief Sets LoRa sync word. + \param syncWord LoRa sync word to be set. \returns \ref status_codes */ - int16_t setSyncWord(uint32_t syncWord); + int16_t setSyncWord(uint8_t syncWord); /*! \brief Sets GFSK bit rate. Allowed values range from 0.6 to 300.0 kbps. From 0096c11f9921168a44295fe5f38c477cdebc7acd Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 28 Oct 2024 21:32:20 +0100 Subject: [PATCH 1337/1848] [CC1101] Added support for 4-FSK (#823) --- keywords.txt | 1 + src/modules/CC1101/CC1101.cpp | 168 ++++++++++++++++++---------------- src/modules/CC1101/CC1101.h | 19 ++++ 3 files changed, 110 insertions(+), 78 deletions(-) diff --git a/keywords.txt b/keywords.txt index 179b4e2932..f70515d656 100644 --- a/keywords.txt +++ b/keywords.txt @@ -221,6 +221,7 @@ setGdo2Action KEYWORD2 clearGdo0Action KEYWORD2 clearGdo2Action KEYWORD2 setCrcFiltering KEYWORD2 +beginFSK4 KEYWORD2 # SX126x-specific setTCXO KEYWORD2 diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f2ff50afd7..727d37e7bc 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -7,84 +7,15 @@ CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SI } int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { - // set module properties - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_CC1101_CMD_READ; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_CC1101_CMD_WRITE; - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - - // try to find the CC1101 chip - uint8_t i = 0; - bool flagFound = false; - while((i < 10) && !flagFound) { - int16_t version = getChipVersion(); - if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { - flagFound = true; - } else { - RADIOLIB_DEBUG_BASIC_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); - this->mod->hal->delay(10); - i++; - } - } - - if(!flagFound) { - RADIOLIB_DEBUG_BASIC_PRINTLN("No CC1101 found!"); - this->mod->term(); - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } else { - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tCC1101"); - } - - // configure settings not accessible by API - int16_t state = config(); - RADIOLIB_ASSERT(state); - - // configure publicly accessible settings - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - - // configure bitrate - state = setBitRate(br); - RADIOLIB_ASSERT(state); - - // configure default RX bandwidth - state = setRxBandwidth(rxBw); - RADIOLIB_ASSERT(state); - - // configure default frequency deviation - state = setFrequencyDeviation(freqDev); - RADIOLIB_ASSERT(state); - - // configure default TX output power - state = setOutputPower(pwr); - RADIOLIB_ASSERT(state); - - // set default packet length mode - state = variablePacketLengthMode(); - RADIOLIB_ASSERT(state); - - // configure default preamble length - state = setPreambleLength(preambleLength, preambleLength - 4); - RADIOLIB_ASSERT(state); - - // set default data shaping - state = setDataShaping(RADIOLIB_SHAPING_NONE); - RADIOLIB_ASSERT(state); - - // set default encoding - state = setEncoding(RADIOLIB_ENCODING_NRZ); - RADIOLIB_ASSERT(state); - - // set default sync word - uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW; - state = setSyncWord(sw[0], sw[1], 0, false); - RADIOLIB_ASSERT(state); - - // flush FIFOs - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + // set the modulation and execute the common part + this->modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK; + return(this->beginCommon(freq, br, freqDev, rxBw, pwr, preambleLength)); +} - return(state); +int16_t CC1101::beginFSK4(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { + // set the modulation and execute the common part + this->modulation = RADIOLIB_CC1101_MOD_FORMAT_4_FSK; + return(this->beginCommon(freq, br, freqDev, rxBw, pwr, preambleLength)); } void CC1101::reset() { @@ -922,7 +853,7 @@ int16_t CC1101::setDataShaping(uint8_t sh) { // set data shaping switch(sh) { case RADIOLIB_SHAPING_NONE: - state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4); + state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, this->modulation, 6, 4); break; case RADIOLIB_SHAPING_0_5: state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_GFSK, 6, 4); @@ -1006,6 +937,87 @@ int16_t CC1101::setDIOMapping(uint32_t pin, uint32_t value) { return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0 - pin, value)); } +int16_t CC1101::beginCommon(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) { + // set module properties + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_CC1101_CMD_READ; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_CC1101_CMD_WRITE; + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + + // try to find the CC1101 chip + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + int16_t version = getChipVersion(); + if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) { + flagFound = true; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version); + this->mod->hal->delay(10); + i++; + } + } + + if(!flagFound) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No CC1101 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tCC1101"); + } + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + // configure bitrate + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // configure default RX bandwidth + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + // configure default frequency deviation + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + // configure default TX output power + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + // set default packet length mode + state = variablePacketLengthMode(); + RADIOLIB_ASSERT(state); + + // configure default preamble length + state = setPreambleLength(preambleLength, preambleLength - 4); + RADIOLIB_ASSERT(state); + + // set default data shaping + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + // set default encoding + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + // set default sync word + uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW; + state = setSyncWord(sw[0], sw[1], 0, false); + RADIOLIB_ASSERT(state); + + // flush FIFOs + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); + + return(state); +} + int16_t CC1101::config() { // Reset the radio. Registers may be dirty from previous usage. reset(); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index cb5efe71e4..8a303bf725 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -562,6 +562,24 @@ class CC1101: public PhysicalLayer { int8_t pwr = RADIOLIB_CC1101_DEFAULT_POWER, uint8_t preambleLength = RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); + /*! + \brief Initialization method for 4-FSK modulation. + \param freq Carrier frequency in MHz. Defaults to 434 MHz. + \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz. + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes + */ + int16_t beginFSK4( + float freq = RADIOLIB_CC1101_DEFAULT_FREQ, + float br = RADIOLIB_CC1101_DEFAULT_BR, + float freqDev = RADIOLIB_CC1101_DEFAULT_FREQDEV, + float rxBw = RADIOLIB_CC1101_DEFAULT_RXBW, + int8_t pwr = RADIOLIB_CC1101_DEFAULT_POWER, + uint8_t preambleLength = RADIOLIB_CC1101_DEFAULT_PREAMBLELEN); + /*! \brief Reset method - resets the chip using manual reset sequence (without RESET pin). */ @@ -1014,6 +1032,7 @@ class CC1101: public PhysicalLayer { int8_t power = RADIOLIB_CC1101_DEFAULT_POWER; + int16_t beginCommon(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength); int16_t config(); int16_t transmitDirect(bool sync, uint32_t frf); int16_t receiveDirect(bool sync); From 4564d87721997917c567f75c2078106ee92e757a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 29 Oct 2024 17:14:04 +0000 Subject: [PATCH 1338/1848] [PHY] Use less generic modem names (#1294) --- src/modules/LLCC68/LLCC68.cpp | 6 ++-- src/modules/LR11x0/LR1110.cpp | 6 ++-- src/modules/LR11x0/LR1120.cpp | 6 ++-- src/modules/LR11x0/LR11x0.cpp | 6 ++-- src/modules/SX126x/SX1262.cpp | 6 ++-- src/modules/SX126x/SX1268.cpp | 6 ++-- src/modules/SX126x/SX126x.cpp | 6 ++-- src/modules/SX127x/SX1272.cpp | 4 +-- src/modules/SX127x/SX1273.cpp | 4 +-- src/modules/SX127x/SX1276.cpp | 4 +-- src/modules/SX127x/SX1277.cpp | 4 +-- src/modules/SX127x/SX1278.cpp | 4 +-- src/modules/SX127x/SX1279.cpp | 4 +-- src/modules/SX127x/SX127x.cpp | 4 +-- src/modules/SX128x/SX128x.cpp | 8 +++--- src/protocols/LoRaWAN/LoRaWAN.cpp | 32 ++++++++++----------- src/protocols/PhysicalLayer/PhysicalLayer.h | 6 ++-- 17 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 18ce03dd26..12de7a52d0 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -118,13 +118,13 @@ int16_t LLCC68::checkDataRate(DataRate_t dr) { int16_t LLCC68::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; - case(ModemType_t::LRFHSS): { + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; default: diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 26cbe2a706..1fbc696b56 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -113,13 +113,13 @@ int16_t LR1110::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPo int16_t LR1110::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginGFSK()); } break; - case(ModemType_t::LRFHSS): { + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; } diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 61294b7f2b..fb6278223c 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -133,13 +133,13 @@ int16_t LR1120::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPo int16_t LR1120::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginGFSK()); } break; - case(ModemType_t::LRFHSS): { + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index cedf5b5ba4..6891cd59eb 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2038,13 +2038,13 @@ int16_t LR11x0::getModem(ModemType_t* modem) { switch(packetType) { case(RADIOLIB_LR11X0_PACKET_TYPE_LORA): - *modem = ModemType_t::LoRa; + *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); case(RADIOLIB_LR11X0_PACKET_TYPE_GFSK): - *modem = ModemType_t::FSK; + *modem = ModemType_t::RADIOLIB_MODEM_FSK; return(RADIOLIB_ERR_NONE); case(RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS): - *modem = ModemType_t::LRFHSS; + *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS; return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 85253ab8d8..426c2d0542 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -116,13 +116,13 @@ int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) { int16_t SX1262::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; - case(ModemType_t::LRFHSS): { + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; default: diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 6ae42ea849..7de82a2245 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -117,13 +117,13 @@ int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) { int16_t SX1268::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; - case(ModemType_t::LRFHSS): { + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; default: diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 16062db119..bddf8bec1c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1682,13 +1682,13 @@ int16_t SX126x::getModem(ModemType_t* modem) { uint8_t packetType = getPacketType(); switch(packetType) { case(RADIOLIB_SX126X_PACKET_TYPE_LORA): - *modem = ModemType_t::LoRa; + *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); case(RADIOLIB_SX126X_PACKET_TYPE_GFSK): - *modem = ModemType_t::FSK; + *modem = ModemType_t::RADIOLIB_MODEM_FSK; return(RADIOLIB_ERR_NONE); case(RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS): - *modem = ModemType_t::LRFHSS; + *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS; return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index ed615705f9..17a04dcf0f 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -587,10 +587,10 @@ void SX1272::errataFix(bool rx) { int16_t SX1272::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 0efbbe933e..6a3af96d57 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -117,10 +117,10 @@ int16_t SX1273::checkDataRate(DataRate_t dr) { int16_t SX1273::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 8890c6cb64..062d11b058 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -81,10 +81,10 @@ int16_t SX1276::setFrequency(float freq) { int16_t SX1276::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index c85a5fe554..59729e898a 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -159,10 +159,10 @@ int16_t SX1277::checkDataRate(DataRate_t dr) { int16_t SX1277::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index e53bfe3490..c768590598 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -707,10 +707,10 @@ void SX1278::errataFix(bool rx) { int16_t SX1278::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 4babad0573..a91273fd05 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -81,10 +81,10 @@ int16_t SX1279::setFrequency(float freq) { int16_t SX1279::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index a8c612276d..e4ba4c75ec 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1760,10 +1760,10 @@ int16_t SX127x::getModem(ModemType_t* modem) { int16_t packetType = getActiveModem(); switch(packetType) { case(RADIOLIB_SX127X_LORA): - *modem = ModemType_t::LoRa; + *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); case(RADIOLIB_SX127X_FSK_OOK): - *modem = ModemType_t::FSK; + *modem = ModemType_t::RADIOLIB_MODEM_FSK; return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 7a5fc20b11..37b9361943 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -858,10 +858,10 @@ int16_t SX128x::checkOutputPower(int8_t pwr, int8_t* clipped) { int16_t SX128x::setModem(ModemType_t modem) { switch(modem) { - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginGFSK()); } break; default: @@ -875,10 +875,10 @@ int16_t SX128x::getModem(ModemType_t* modem) { uint8_t packetType = getPacketType(); switch(packetType) { case(RADIOLIB_SX128X_PACKET_TYPE_LORA): - *modem = ModemType_t::LoRa; + *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); case(RADIOLIB_SX128X_PACKET_TYPE_GFSK): - *modem = ModemType_t::FSK; + *modem = ModemType_t::RADIOLIB_MODEM_FSK; return(RADIOLIB_ERR_NONE); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6b4666a47b..b8350003e6 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2776,11 +2776,11 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, // set modem-dependent functions switch(this->band->dataRates[chnl->dr] & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { case(RADIOLIB_LORAWAN_DATA_RATE_LORA): - if(modem != ModemType_t::LoRa) { - state = this->phyLayer->setModem(ModemType_t::LoRa); + if(modem != ModemType_t::RADIOLIB_MODEM_LORA) { + state = this->phyLayer->setModem(ModemType_t::RADIOLIB_MODEM_LORA); RADIOLIB_ASSERT(state); } - modem = ModemType_t::LoRa; + modem = ModemType_t::RADIOLIB_MODEM_LORA; // downlink messages are sent with inverted IQ if(dir == RADIOLIB_LORAWAN_DOWNLINK) { state = this->phyLayer->invertIQ(true); @@ -2791,11 +2791,11 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, break; case(RADIOLIB_LORAWAN_DATA_RATE_FSK): - if(modem != ModemType_t::FSK) { - state = this->phyLayer->setModem(ModemType_t::FSK); + if(modem != ModemType_t::RADIOLIB_MODEM_FSK) { + state = this->phyLayer->setModem(ModemType_t::RADIOLIB_MODEM_FSK); RADIOLIB_ASSERT(state); } - modem = ModemType_t::FSK; + modem = ModemType_t::RADIOLIB_MODEM_FSK; state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); RADIOLIB_ASSERT(state); state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); @@ -2803,11 +2803,11 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, break; case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): - if(modem != ModemType_t::LRFHSS) { - state = this->phyLayer->setModem(ModemType_t::LRFHSS); + if(modem != ModemType_t::RADIOLIB_MODEM_LRFHSS) { + state = this->phyLayer->setModem(ModemType_t::RADIOLIB_MODEM_LRFHSS); RADIOLIB_ASSERT(state); } - modem = ModemType_t::LRFHSS; + modem = ModemType_t::RADIOLIB_MODEM_LRFHSS; break; default: @@ -2836,7 +2836,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, uint8_t syncWordLen = 0; size_t preLen = 0; switch(modem) { - case(ModemType_t::FSK): { + case(ModemType_t::RADIOLIB_MODEM_FSK): { preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); @@ -2846,7 +2846,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, dr.fsk.bitRate, dr.fsk.freqDev); } break; - case(ModemType_t::LoRa): { + case(ModemType_t::RADIOLIB_MODEM_LORA): { preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; @@ -2854,7 +2854,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, dr.lora.spreadingFactor, dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); } break; - case(ModemType_t::LRFHSS): { + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 24); syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 16); syncWord[2] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 8); @@ -2875,7 +2875,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, if(pre) { preLen = pre; } - if(modem != ModemType_t::LRFHSS) { + if(modem != ModemType_t::RADIOLIB_MODEM_LRFHSS) { state = this->phyLayer->setPreambleLength(preLen); } return(state); @@ -3305,7 +3305,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { case(RADIOLIB_LORAWAN_DATA_RATE_LORA): - modemNew = ModemType_t::LoRa; + modemNew = ModemType_t::RADIOLIB_MODEM_LORA; dataRate->lora.spreadingFactor = ((dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_SF) >> 3) + 7; switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): @@ -3323,12 +3323,12 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.codingRate = 5; break; case(RADIOLIB_LORAWAN_DATA_RATE_FSK): - modemNew = ModemType_t::FSK; + modemNew = ModemType_t::RADIOLIB_MODEM_FSK; dataRate->fsk.bitRate = 50; dataRate->fsk.freqDev = 25; break; case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): - modemNew = ModemType_t::LRFHSS; + modemNew = ModemType_t::RADIOLIB_MODEM_LRFHSS; switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { case(RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ): dataRate->lrFhss.bw = 0x02; // specific encoding diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index c5467990ef..a8f66ce1ab 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -135,9 +135,9 @@ union ChannelScanConfig_t { \brief Type of modem, used by setModem. */ enum ModemType_t { - FSK = 0, - LoRa, - LRFHSS, + RADIOLIB_MODEM_FSK = 0, + RADIOLIB_MODEM_LORA, + RADIOLIB_MODEM_LRFHSS, }; /*! From a608075fc17e3286a624d9a1b51926af4c529b28 Mon Sep 17 00:00:00 2001 From: Victor Barpp Gomes <17840319+Kabbah@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:47:02 -0300 Subject: [PATCH 1339/1848] [LoRaWAN] Accept `const uint8_t*` on public API (#1302) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 20 ++++++++++---------- src/protocols/LoRaWAN/LoRaWAN.h | 24 ++++++++++++------------ src/utils/Utils.cpp | 2 +- src/utils/Utils.h | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b8350003e6..b0fcebb503 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -18,7 +18,7 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(const String& strUp, uint8_t fPort, String& strDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { int16_t state = RADIOLIB_ERR_UNKNOWN; const char* dataUp = strUp.c_str(); @@ -28,7 +28,7 @@ int16_t LoRaWANNode::sendReceive(String& strUp, uint8_t fPort, String& strDown, size_t lenDown = 0; uint8_t dataDown[251]; - state = this->sendReceive((uint8_t*)dataUp, strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); + state = this->sendReceive((const uint8_t*)dataUp, strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); if(state == RADIOLIB_ERR_NONE) { // add null terminator @@ -55,7 +55,7 @@ int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, uint8_t* data return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, lenDown, isConfirmed, eventUp, eventDown)); } -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; @@ -64,7 +64,7 @@ int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, b return(this->sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); } -int16_t LoRaWANNode::sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { +int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { if(!dataUp || !dataDown || !lenDown) { return(RADIOLIB_ERR_NULL_POINTER); } @@ -241,7 +241,7 @@ uint8_t* LoRaWANNode::getBufferNonces() { return(this->bufferNonces); } -int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) { +int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) { if(this->isActivated()) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); return(RADIOLIB_ERR_NONE); @@ -464,7 +464,7 @@ uint8_t* LoRaWANNode::getBufferSession() { return(this->bufferSession); } -int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { +int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { if(this->isActivated()) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active"); return(RADIOLIB_ERR_NONE); @@ -588,7 +588,7 @@ int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) { return(state); } -int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey) { +int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, const uint8_t* nwkKey, const uint8_t* appKey) { if(!appKey) { return(RADIOLIB_ERR_NULL_POINTER); } @@ -617,7 +617,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey) { +int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const uint8_t* sNwkSIntKey, const uint8_t* nwkSEncKey, const uint8_t* appSKey) { if(!nwkSEncKey || !appSKey) { return(RADIOLIB_ERR_NULL_POINTER); } @@ -1159,7 +1159,7 @@ void LoRaWANNode::adrBackoff() { return; } -void LoRaWANNode::composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed) { +void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed) { // set the packet fields if(isConfirmed) { out[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] = RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_UP; @@ -3416,7 +3416,7 @@ void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_ } } -int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) { +int16_t LoRaWANNode::checkBufferCommon(const uint8_t *buffer, uint16_t size) { // check if there are actually values in the buffer size_t i = 0; for(; i < size; i++) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index cc9c364194..79a4fcc63b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -548,7 +548,7 @@ class LoRaWANNode { \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferNonces) \returns \ref status_codes */ - int16_t setBufferNonces(uint8_t* persistentBuffer); + int16_t setBufferNonces(const uint8_t* persistentBuffer); /*! \brief Clear an active session, so that the device will have to rejoin the network. @@ -566,7 +566,7 @@ class LoRaWANNode { \param persistentBuffer Buffer that should match the internal format (previously extracted using getBufferSession) \returns \ref status_codes */ - int16_t setBufferSession(uint8_t* persistentBuffer); + int16_t setBufferSession(const uint8_t* persistentBuffer); /*! \brief Set the device credentials and activation configuration @@ -576,7 +576,7 @@ class LoRaWANNode { \param appKey Pointer to the application AES-128 key. \returns \ref status_codes */ - int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey); + int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, const uint8_t* nwkKey, const uint8_t* appKey); /*! \brief Set the device credentials and activation configuration @@ -588,7 +588,7 @@ class LoRaWANNode { \param appSKey Pointer to the application session AES-128 key. \returns \ref status_codes */ - int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey); + int16_t beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const uint8_t* sNwkSIntKey, const uint8_t* nwkSEncKey, const uint8_t* appSKey); /*! \brief Join network by restoring OTAA session or performing over-the-air activation. By this procedure, @@ -622,7 +622,7 @@ class LoRaWANNode { (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - virtual int16_t sendReceive(String& strUp, uint8_t fPort, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + virtual int16_t sendReceive(const String& strUp, uint8_t fPort, String& strDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); #endif /*! @@ -665,7 +665,7 @@ class LoRaWANNode { (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - virtual int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + virtual int16_t sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort = 1, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. @@ -681,7 +681,7 @@ class LoRaWANNode { (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes */ - virtual int16_t sendReceive(uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + virtual int16_t sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); /*! \brief Add a MAC command to the uplink queue. @@ -1002,7 +1002,7 @@ class LoRaWANNode { void adrBackoff(); // create an encrypted uplink buffer, composing metadata, user data and MAC data - void composeUplink(uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed); + void composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed); // generate and set the MIC of an uplink buffer (depends on selected channels) void micUplink(uint8_t* inOut, uint8_t lenInOut); @@ -1112,11 +1112,11 @@ class LoRaWANNode { static uint16_t checkSum16(const uint8_t *key, uint16_t keyLen); // check the integrity of a buffer using a 16-bit checksum located in the last two bytes of the buffer - static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size); + static int16_t checkBufferCommon(const uint8_t *buffer, uint16_t size); // network-to-host conversion method - takes data from network packet and converts it to the host endians template - static T ntoh(uint8_t* buff, size_t size = 0); + static T ntoh(const uint8_t* buff, size_t size = 0); // host-to-network conversion method - takes data from host variable and and converts it to network packet endians template @@ -1124,8 +1124,8 @@ class LoRaWANNode { }; template -T LoRaWANNode::ntoh(uint8_t* buff, size_t size) { - uint8_t* buffPtr = buff; +T LoRaWANNode::ntoh(const uint8_t* buff, size_t size) { + const uint8_t* buffPtr = buff; size_t targetSize = sizeof(T); if(size != 0) { targetSize = size; diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index c2f12a6a16..4111818fb9 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -13,7 +13,7 @@ uint32_t rlb_reflect(uint32_t in, uint8_t bits) { return(res); } -void rlb_hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { +void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { #if RADIOLIB_DEBUG size_t rem_len = len; for(size_t i = 0; i < len; i+=16) { diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 638f2b63d7..b8c4ac6137 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -33,7 +33,7 @@ uint32_t rlb_reflect(uint32_t in, uint8_t bits); \param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t). \param be Print multi-byte data as big endian. Defaults to false. */ -void rlb_hexdump(const char* level, uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); +void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); #if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) size_t rlb_printf(const char* format, ...); From e9dd3dc843608711bc8fb7c8a90c028e00725bf6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 2 Nov 2024 11:01:43 +0100 Subject: [PATCH 1340/1848] Added quick links to readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c608e2d6f7..81570a43e0 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ ## Universal wireless communication library for embedded devices -## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) and [FAQ](https://github.com/jgromes/RadioLib/wiki/Frequently-Asked-Questions) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference. - RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system. Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not! @@ -13,6 +11,12 @@ RadioLib natively supports Arduino, but can run in non-Arduino environments as w RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your microcontroller can handle! +### Quick links: +* [__Wiki__](https://github.com/jgromes/RadioLib/wiki) - contains useful general information on using this library +* [__FAQ__](https://github.com/jgromes/RadioLib/wiki/Frequently-Asked-Questions) - frequently asked questions, and answers +* [__API Reference__](https://jgromes.github.io/RadioLib) - full API reference, automatically generated from the source code +* [__Status Code Decoder__](https://jgromes.github.io/status_decoder/decode.html) - decoder for status codes returned by RadioLib methods + ### Supported modules: * __CC1101__ FSK radio module * __LLCC68__ LoRa module From b1d8850d92e966862c27290bf91fb46eaed213af Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 2 Nov 2024 21:38:43 +1000 Subject: [PATCH 1341/1848] hal: Tock: Re-enable pin after detaching interrupt (#1308) The Tock libtock_lora_phy_gpio_disable_interrupt() syscall will disable interrupts for the pin, but also put the pin into a disabled low power state. This isn't what RadioLib expects and casues subsequent LoRaWAN transfers to fail [1]. So after we disable interrupts and send the pin to low power let's re-enable inputs as RadioLib expects. 1: https://github.com/jgromes/RadioLib/discussions/1303 Signed-off-by: Alistair Francis --- src/hal/Tock/libtockHal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hal/Tock/libtockHal.h b/src/hal/Tock/libtockHal.h index 7ae8bf2ae7..9d597fd169 100644 --- a/src/hal/Tock/libtockHal.h +++ b/src/hal/Tock/libtockHal.h @@ -154,6 +154,7 @@ class TockHal : public RadioLibHal { gpio_funcs[interruptNum - 1] = NULL; libtock_lora_phy_gpio_disable_interrupt(interruptNum); + libtock_lora_phy_gpio_enable_input(interruptNum, libtock_pull_down); } void delay(unsigned long ms) override { From 72ecc275af5fe8303c58cb018783919e8809544b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 2 Nov 2024 17:38:41 +0100 Subject: [PATCH 1342/1848] Added links to status code decoder to issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- .github/ISSUE_TEMPLATE/feature_request.md | 4 ++-- .github/ISSUE_TEMPLATE/module-not-working.md | 2 +- .github/ISSUE_TEMPLATE/regular-issue.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5ef9564242..42def9184c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,8 +7,8 @@ assignees: '' --- -**IMPORTANT: Check the wiki** -Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +**IMPORTANT: Check the docs** +Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). **Describe the bug** A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode) **using the appropriate debug mode**. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index ec5c496ef0..a780df6d27 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,8 +7,8 @@ assignees: '' --- -**IMPORTANT: Check the wiki** -Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +**IMPORTANT: Check the docs** +Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] diff --git a/.github/ISSUE_TEMPLATE/module-not-working.md b/.github/ISSUE_TEMPLATE/module-not-working.md index d6d8f35637..70a4a00df8 100644 --- a/.github/ISSUE_TEMPLATE/module-not-working.md +++ b/.github/ISSUE_TEMPLATE/module-not-working.md @@ -9,7 +9,7 @@ assignees: '' **IMPORTANT: Before submitting an issue, please check the following:** 1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. -2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). 3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). diff --git a/.github/ISSUE_TEMPLATE/regular-issue.md b/.github/ISSUE_TEMPLATE/regular-issue.md index c55b36a1a2..7441c78f4e 100644 --- a/.github/ISSUE_TEMPLATE/regular-issue.md +++ b/.github/ISSUE_TEMPLATE/regular-issue.md @@ -9,7 +9,7 @@ assignees: '' **IMPORTANT: Before submitting an issue, please check the following:** 1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. -2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). 3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). From f15de1e7dd4494d3e59f1e860eba8956156b2ebc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 3 Nov 2024 11:16:26 +0100 Subject: [PATCH 1343/1848] Added missing links to doxygen mainpage --- src/RadioLib.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index bd6c9598da..adc6854a35 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -4,11 +4,15 @@ /*! \mainpage RadioLib Documentation - Universal wireless communication library for Arduino. + Universal wireless communication library for embedded devices. \par Currently Supported Wireless Modules and Protocols - CC1101 FSK module + - LLCC68 LoRa/FSK module + - LR11x0 LoRa/FSK/LR-FHSS module + - nRF24 FSK module - RF69 FSK module + - RFM2x FSK module - Si443x FSK module - SX126x LoRa/FSK module - SX127x LoRa/FSK module @@ -22,6 +26,8 @@ - Hellschreiber (HellClient) - 4-FSK (FSK4Client) - APRS (APRSClient) + - POCSAG (PagerClient) + - LoRaWAN (LoRaWANNode) \par Quick Links Documentation for most common methods can be found in its reference page (see the list above).\n From 49868938d6a1ac1004e7516603d851d443336a55 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 3 Nov 2024 12:57:19 +0100 Subject: [PATCH 1344/1848] Update links to status decoder --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .github/ISSUE_TEMPLATE/module-not-working.md | 2 +- .github/ISSUE_TEMPLATE/regular-issue.md | 2 +- README.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 42def9184c..486e056dfd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- **IMPORTANT: Check the docs** -Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). +Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://radiolib-org.github.io/status_decoder/decode.html). **Describe the bug** A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode) **using the appropriate debug mode**. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index a780df6d27..a01ef1684c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ assignees: '' --- **IMPORTANT: Check the docs** -Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). +Before submitting new issue, please check the [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and the [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://radiolib-org.github.io/status_decoder/decode.html). **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] diff --git a/.github/ISSUE_TEMPLATE/module-not-working.md b/.github/ISSUE_TEMPLATE/module-not-working.md index 70a4a00df8..be93f67097 100644 --- a/.github/ISSUE_TEMPLATE/module-not-working.md +++ b/.github/ISSUE_TEMPLATE/module-not-working.md @@ -9,7 +9,7 @@ assignees: '' **IMPORTANT: Before submitting an issue, please check the following:** 1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. -2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). +2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://radiolib-org.github.io/status_decoder/decode.html). 3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). diff --git a/.github/ISSUE_TEMPLATE/regular-issue.md b/.github/ISSUE_TEMPLATE/regular-issue.md index 7441c78f4e..3e1b8d0742 100644 --- a/.github/ISSUE_TEMPLATE/regular-issue.md +++ b/.github/ISSUE_TEMPLATE/regular-issue.md @@ -9,7 +9,7 @@ assignees: '' **IMPORTANT: Before submitting an issue, please check the following:** 1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. -2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://jgromes.github.io/status_decoder/decode.html). +2. RadioLib has a [Troubleshooting Guide](https://github.com/jgromes/RadioLib/wiki/Troubleshooting-Guide) Wiki page and an extensive [API documentation](https://jgromes.github.io/RadioLib/). If you are seeing an error code, we have [online status code decoder](https://radiolib-org.github.io/status_decoder/decode.html). 3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). 4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! 5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). diff --git a/README.md b/README.md index 81570a43e0..1a65085be7 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * [__Wiki__](https://github.com/jgromes/RadioLib/wiki) - contains useful general information on using this library * [__FAQ__](https://github.com/jgromes/RadioLib/wiki/Frequently-Asked-Questions) - frequently asked questions, and answers * [__API Reference__](https://jgromes.github.io/RadioLib) - full API reference, automatically generated from the source code -* [__Status Code Decoder__](https://jgromes.github.io/status_decoder/decode.html) - decoder for status codes returned by RadioLib methods +* [__Status Code Decoder__](https://radiolib-org.github.io/status_decoder/decode.html) - decoder for status codes returned by RadioLib methods ### Supported modules: * __CC1101__ FSK radio module From cb45f4fe5e81d4259594bb57251ebc8606e1154c Mon Sep 17 00:00:00 2001 From: SzczepanLeon <75840303+SzczepanLeon@users.noreply.github.com> Date: Sun, 3 Nov 2024 18:25:44 +0100 Subject: [PATCH 1345/1848] [SX127x/RF69] Added setFifoThreshold (#1309) * [SX127x] Added setFifoThreshold * [SX127x] Added setFifoThreshold * Add setFifoThreshold to RF69 class. * Documentation update, about setFifoThreshold. --- src/modules/RF69/RF69.cpp | 4 ++++ src/modules/RF69/RF69.h | 8 ++++++++ src/modules/SX127x/SX127x.cpp | 4 ++++ src/modules/SX127x/SX127x.h | 8 ++++++++ 4 files changed, 24 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 2bbfeb57e0..f87270be64 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -321,6 +321,10 @@ void RF69::clearFifoEmptyAction() { clearDio1Action(); } +void RF69::setFifoThreshold(uint8_t threshold) { + this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, threshold, 6, 0); +} + void RF69::setFifoFullAction(void (*func)(void)) { // set the interrupt this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_FIFO_THRESH, RADIOLIB_RF69_FIFO_THRESH, 6, 0); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index a7a25e4941..a5691b93fa 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -648,6 +648,14 @@ class RF69: public PhysicalLayer { */ void clearFifoEmptyAction(); + /*! + \brief Set FIFO threshold level. + Be aware that threshold is also set in setFifoFullAction method. + setFifoThreshold method must be called AFTER calling setFifoFullAction! + \param Threshold level. + */ + void setFifoThreshold(uint8_t threshold); + /*! \brief Set interrupt service routine function to call when FIFO is full. \param func Pointer to interrupt service routine. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index e4ba4c75ec..82755db058 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -504,6 +504,10 @@ void SX127x::clearFifoEmptyAction() { clearDio1Action(); } +void SX127x::setFifoThreshold(uint8_t threshold) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, threshold, 5, 0); +} + void SX127x::setFifoFullAction(void (*func)(void)) { // set the interrupt this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index c54a549f63..af00e57518 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -761,6 +761,14 @@ class SX127x: public PhysicalLayer { */ void clearFifoEmptyAction(); + /*! + \brief Set FIFO threshold level. + Be aware that threshold is also set in setFifoFullAction method. + setFifoThreshold method must be called AFTER calling setFifoFullAction! + \param Threshold level. + */ + void setFifoThreshold(uint8_t threshold); + /*! \brief Set interrupt service routine function to call when FIFO is full. \param func Pointer to interrupt service routine. From fe52311371dbde753555b6afb9472cd5db900174 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 3 Nov 2024 18:27:51 +0100 Subject: [PATCH 1346/1848] [SX127x] Added parameter doc and keyword --- keywords.txt | 1 + src/modules/RF69/RF69.h | 2 +- src/modules/SX127x/SX127x.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index f70515d656..9457fcb066 100644 --- a/keywords.txt +++ b/keywords.txt @@ -197,6 +197,7 @@ randomByte KEYWORD2 getPacketLength KEYWORD2 setFifoEmptyAction KEYWORD2 clearFifoEmptyAction KEYWORD2 +setFifoThreshold KEYWORD2 setFifoFullAction KEYWORD2 clearFifoFullAction KEYWORD2 fifoAdd KEYWORD2 diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index a5691b93fa..00ea43b935 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -652,7 +652,7 @@ class RF69: public PhysicalLayer { \brief Set FIFO threshold level. Be aware that threshold is also set in setFifoFullAction method. setFifoThreshold method must be called AFTER calling setFifoFullAction! - \param Threshold level. + \param threshold Threshold level in bytes. */ void setFifoThreshold(uint8_t threshold); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index af00e57518..92f36451ef 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -765,7 +765,7 @@ class SX127x: public PhysicalLayer { \brief Set FIFO threshold level. Be aware that threshold is also set in setFifoFullAction method. setFifoThreshold method must be called AFTER calling setFifoFullAction! - \param Threshold level. + \param threshold Threshold level in bytes. */ void setFifoThreshold(uint8_t threshold); From 29ede2c3545321f90ac8a8ea4583d3472c17ff80 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Nov 2024 17:43:28 +0100 Subject: [PATCH 1347/1848] [MOD] Optimize SPI register writing --- src/Module.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Module.cpp b/src/Module.cpp index 7b3c59aef3..1f83b7fbde 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -61,8 +61,16 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t return(RADIOLIB_ERR_INVALID_BIT_RANGE); } + // read the current value uint8_t currentValue = SPIreadRegister(reg); uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb))); + + // check if we actually need to update the register + if((currentValue & mask) == (value & mask)) { + return(RADIOLIB_ERR_NONE); + } + + // update the register uint8_t newValue = (currentValue & ~mask) | (value & mask); SPIwriteRegister(reg, newValue); From 9ac8bb9a7ebae198ac919992dc438ceb3a674d42 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Nov 2024 17:45:24 +0100 Subject: [PATCH 1348/1848] Drop debug decoder --- .gitignore | 4 -- extras/decoder/DebugDecoder.py | 111 --------------------------------- 2 files changed, 115 deletions(-) delete mode 100644 extras/decoder/DebugDecoder.py diff --git a/.gitignore b/.gitignore index b65463c981..425eeae59e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,6 @@ # Jetbrain IDEs .idea -# Debug decoder -extras/decoder/log.txt -extras/decoder/out.txt - # Spectrum scan extras/SX126x_Spectrum_Scan/out/* diff --git a/extras/decoder/DebugDecoder.py b/extras/decoder/DebugDecoder.py deleted file mode 100644 index c5c9b37130..0000000000 --- a/extras/decoder/DebugDecoder.py +++ /dev/null @@ -1,111 +0,0 @@ -import re, sys, argparse -from pathlib import Path -from argparse import RawTextHelpFormatter - - -''' -TODO list: - 1. Parse macro values (the names of bits in all registers in header file) - 2. Failed SPI write handling - 3. SX126x/SX128x handling -''' - - -def get_macro_name(value, macros): - for macro in macros: - if macro[1] == value: - return macro[0] - return 'UNKNOWN_VALUE' - - -def get_macro_value(value): - return ' 0x{0:02X}\n'.format(int(value, 16)) - - -parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' - RadioLib debug output decoder script. Turns RadioLib Serial dumps into readable text. - - Step-by-step guid on how to use the decoder: - 1. Uncomment lines 312 (#define RADIOLIB_DEBUG) and 313 (#define RADIOLIB_VERBOSE) in RadioLib/src/BuildOpt.h - 2. Recompile and upload the failing Arduino sketch - 3. Open Arduino IDE Serial Monitor and enable timestamps - 4. Copy the Serial output and save it into a .txt file - 5. Run this script - - Output will be saved in the file specified by --out and printed to the terminal -''') -parser.add_argument('file', metavar='file', type=str, help='Text file of the debug output') -parser.add_argument('--out', metavar='out', default='./out.txt', type=str, help='Where to save the decoded file (defaults to ./out.txt)') -args = parser.parse_args() - -# open the log file -log = open(args.file, 'r').readlines() - -# find modules that are in use -used_modules = [] -pattern_module = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?M\t') -for entry in log: - m = pattern_module.search(entry) - if m != None: - used_modules.append(entry[m.end():].rstrip()) - -# get paths to all relevant header files -header_files = [] -for path in Path('../../src').rglob('*.h'): - for module in used_modules: - if module in path.name: - header_files.append(path) - -# extract names of address macros from the header files -macro_addresses = [] -pattern_define = re.compile('#define \w* +\w*(\n| +\/\/){1}') -for path in header_files: - file = open(path, 'r').readlines() - for line in file: - m = pattern_define.search(line) - if m != None: - s = re.split(' +', m.group().rstrip()) - if (s.__len__() > 1) and ('_REG' in s[1]): - macro_addresses.append([s[1], int(s[2], 0)]) - -''' -# extract names of value macros for each adddress macro -macro_values = [] -for path in header_files: - file = open(path, 'r').readlines() - for line in file: - for module in used_modules: - pattern_addr_macro = re.compile('\/\/ SI443X_REG_\w+'.format(module.capitalize())) -''' - -# parse every line in the log file -out = [] -pattern_debug = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?[RWM]\t.+') -for entry in log: - m = pattern_debug.search(entry) - if m != None: - s = re.split('( |\t)+', entry.rstrip()) - cmd_len = int((s.__len__() - 7)/2) - new_entry = s[0] + s[1] + s[2] + s[3] - if s[4] == 'W': - macro_address = int(s[6], 16) - new_entry += 'write {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses)) - for i in range(cmd_len): - new_entry += get_macro_value(s[8 + 2*i]); - elif s[4] == 'R': - macro_address = int(s[6], 16) - new_entry += 'read {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses)) - for i in range(cmd_len): - new_entry += get_macro_value(s[8 + 2*i]); - elif s[4] == 'M': - new_entry += 'module {}\n'.format(s[6]) - out.append(new_entry) - else: - out.append(entry) - -# write the output file -out_file = open(args.out, 'w') -for line in out: - print(line, end='') - out_file.write(line) -out_file.close() From f3a8c6dc2d6b60a9269c0ce7c93031765bf68df4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 10 Nov 2024 17:47:15 +0100 Subject: [PATCH 1349/1848] Add link to online debug decoder --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1a65085be7..78a561f9ba 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * [__FAQ__](https://github.com/jgromes/RadioLib/wiki/Frequently-Asked-Questions) - frequently asked questions, and answers * [__API Reference__](https://jgromes.github.io/RadioLib) - full API reference, automatically generated from the source code * [__Status Code Decoder__](https://radiolib-org.github.io/status_decoder/decode.html) - decoder for status codes returned by RadioLib methods +* [__Debug Log Decoder__](https://radiolib-org.github.io/debug_decoder/decode.html) - decoder for RadioLib SPI debug logs ### Supported modules: * __CC1101__ FSK radio module From 9d9d480a4828ca041f1389bb21a6a572710211f4 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 15 Nov 2024 03:51:00 +1000 Subject: [PATCH 1350/1848] hal: Tock: Namespace HAL, update timer implementation and update libtock-c (#1313) * tock: use native time getter, remove globals Tock has direct support for querying time. The prior `millis()` method here replicated the same functionality, but missed some corner case concerns around overflow/wrapping. Instead, just use the native Tock time getter method. This also removes unneeded global variables and methods. * NonArduino/Tock: Update to latest libtock-c Update to the latest libtock-c commit. libtock-c now includes a libtockHal.h, so we can use that instead of the version here. Signed-off-by: Alistair Francis --------- Signed-off-by: Alistair Francis Co-authored-by: Pat Pannuto --- .github/workflows/main.yml | 2 +- examples/NonArduino/Tock/CMakeLists.txt | 28 ++- examples/NonArduino/Tock/README.md | 2 +- examples/NonArduino/Tock/build.sh | 4 +- examples/NonArduino/Tock/main.cpp | 6 +- src/hal/Tock/libtockHal.h | 226 ------------------------ 6 files changed, 33 insertions(+), 235 deletions(-) delete mode 100644 src/hal/Tock/libtockHal.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06c8d6f826..c28278a3c3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -247,7 +247,7 @@ jobs: run: | cd $PWD/examples/NonArduino/Tock git clone https://github.com/tock/libtock-c.git - cd libtock-c; git checkout dbee65a56d74b4bad166317f199e80b959f7c82c; cd ../ + cd libtock-c; git checkout c0202f9ab78da4a6e95f136cf5250701e3778f63; cd ../ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh rpi-build: diff --git a/examples/NonArduino/Tock/CMakeLists.txt b/examples/NonArduino/Tock/CMakeLists.txt index 42d6d67447..661968f849 100644 --- a/examples/NonArduino/Tock/CMakeLists.txt +++ b/examples/NonArduino/Tock/CMakeLists.txt @@ -50,7 +50,21 @@ add_executable(${PROJECT_NAME} main.cpp) # The build system for libtock-c is a bit odd and the version of libraries # built changes based on compiler version. if (RISCV_BUILD) - if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0") + if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0") + target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/rv32imc/libtocksync.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/riscv/lib/gcc/riscv64-unknown-elf/14.1.0/rv32i/ilp32/libgcc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a + ) + + target_include_directories(RadioLib AFTER PUBLIC + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/ + ) + elseif(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0") target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a @@ -80,7 +94,17 @@ if (RISCV_BUILD) ) endif() else() - if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0") + if (EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0") + target_link_libraries(${PROJECT_NAME} PUBLIC + RadioLib + $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a + $ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/cortex-m4/libtocksync.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/arm/lib/gcc/arm-none-eabi/14.1.0/libgcc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/arm/arm-none-eabi/lib/libstdc++.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/arm/arm-none-eabi/lib/libc.a + $ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/arm/arm-none-eabi/lib/libm.a + ) + elseif(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0") target_link_libraries(${PROJECT_NAME} PUBLIC RadioLib $ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a diff --git a/examples/NonArduino/Tock/README.md b/examples/NonArduino/Tock/README.md index cae7f38095..8022a303b9 100644 --- a/examples/NonArduino/Tock/README.md +++ b/examples/NonArduino/Tock/README.md @@ -23,7 +23,7 @@ The RadioLib example can be built with: $ git clone https://github.com/jgromes/RadioLib.git $ cd RadioLib/examples/NonArduino/Tock/ $ git clone https://github.com/tock/libtock-c.git -$ cd libtock-c; git checkout dbee65a56d74b4bad166317f199e80b959f7c82c; cd ../ +$ cd libtock-c; git checkout c0202f9ab78da4a6e95f136cf5250701e3778f63; cd ../ $ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh ``` diff --git a/examples/NonArduino/Tock/build.sh b/examples/NonArduino/Tock/build.sh index cb91a4aedf..2ac538e492 100755 --- a/examples/NonArduino/Tock/build.sh +++ b/examples/NonArduino/Tock/build.sh @@ -3,9 +3,9 @@ set -e rm -rf ./build-* -cd libtock-c/examples/cxx_hello +pushd ${LIBTOCK_C_DIRECTORY}/examples/cxx_hello make -j4 -cd ../../../ +popd mkdir -p build-arm cd build-arm diff --git a/examples/NonArduino/Tock/main.cpp b/examples/NonArduino/Tock/main.cpp index e716d50976..e0db2196e4 100644 --- a/examples/NonArduino/Tock/main.cpp +++ b/examples/NonArduino/Tock/main.cpp @@ -28,14 +28,14 @@ #include // include the hardware abstraction layer -#include "hal/Tock/libtockHal.h" +#include "RadioLib/libtockHal.h" // the entry point for the program int main(void) { printf("[SX1261] Initialising Radio ... \r\n"); // create a new instance of the HAL class - TockHal* hal = new TockHal(); + TockRadioLibHal* hal = new TockRadioLibHal(); // now we can create the radio module // pinout corresponds to the SparkFun LoRa Thing Plus - expLoRaBLE @@ -43,7 +43,7 @@ int main(void) { // DIO1 pin: 2 // NRST pin: 4 // BUSY pin: 1 - Module* tock_module = new Module(hal, RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY); + Module* tock_module = new Module(hal, RADIOLIB_RADIO_NSS, RADIOLIB_RADIO_DIO_1, RADIOLIB_RADIO_RESET, RADIOLIB_RADIO_BUSY); SX1262* radio = new SX1262(tock_module); // Setup the radio diff --git a/src/hal/Tock/libtockHal.h b/src/hal/Tock/libtockHal.h deleted file mode 100644 index 9d597fd169..0000000000 --- a/src/hal/Tock/libtockHal.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - RadioLib Non-Arduino Tock Library helper functions - - Licensed under the MIT License - - Copyright (c) 2023 Alistair Francis - - 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 TOCK_HAL_H -#define TOCK_HAL_H - -// include RadioLib -#include - -// include all the dependencies -#include "libtock/net/lora_phy.h" -#include "libtock/net/syscalls/lora_phy_syscalls.h" -#include "libtock-sync/net/lora_phy.h" -#include "libtock/peripherals/gpio.h" -#include "libtock-sync/services/alarm.h" -#include "libtock/kernel/read_only_state.h" - -#define RADIO_BUSY 1 -#define RADIO_DIO_1 2 -#define RADIO_DIO_3 3 -#define RADIO_RESET 4 -// Skip the chips select as Tock handles this for us -#define RADIO_NSS RADIOLIB_NC - -// define Arduino-style macros -#define PIN_LOW (0x0) -#define PIN_HIGH (0x1) -#define PIN_INPUT (0x01) -#define PIN_OUTPUT (0x03) -#define PIN_RISING (0x01) -#define PIN_FALLING (0x02) - -typedef void (*gpioIrqFn)(void); - -gpioIrqFn gpio_funcs[4] = { NULL, NULL, NULL, NULL}; -uint32_t frequency = 0; - -/* - * Get the the timer frequency in Hz. - */ -int alarm_internal_frequency(uint32_t* frequency) { - syscall_return_t rval = command(0x0, 1, 0, 0); - return tock_command_return_u32_to_returncode(rval, frequency); -} - -int alarm_internal_read(uint32_t* time) { - syscall_return_t rval = command(0x0, 2, 0, 0); - return tock_command_return_u32_to_returncode(rval, time); -} - -static void lora_phy_gpio_Callback (int gpioPin, - __attribute__ ((unused)) int arg2, - __attribute__ ((unused)) int arg3, - void* userdata) -{ - gpioIrqFn fn = gpio_funcs[gpioPin - 1]; - - if (fn != NULL ) { - fn(); - } -} - -class TockHal : public RadioLibHal { - public: - // default constructor - initializes the base HAL and any needed private members - TockHal() - : RadioLibHal(PIN_INPUT, PIN_OUTPUT, PIN_LOW, PIN_HIGH, PIN_RISING, PIN_FALLING) { - } - - void init() override { - } - - void term() override { - } - - // GPIO-related methods (pinMode, digitalWrite etc.) should check - // RADIOLIB_NC as an alias for non-connected pins - void pinMode(uint32_t pin, uint32_t mode) override { - if(pin == RADIOLIB_NC) { - return; - } - - if (mode == PIN_OUTPUT) { - libtock_lora_phy_gpio_enable_output(pin); - } else if (mode == PIN_INPUT) { - libtock_lora_phy_gpio_enable_input(pin, libtock_pull_down); - } - } - - void digitalWrite(uint32_t pin, uint32_t value) override { - if(pin == RADIOLIB_NC) { - return; - } - - if (value) { - libtock_lora_phy_gpio_set(pin); - } else { - libtock_lora_phy_gpio_clear(pin); - } - } - - uint32_t digitalRead(uint32_t pin) override { - int value; - - if(pin == RADIOLIB_NC) { - return 0; - } - - libtock_lora_phy_gpio_read(pin, &value); - - return value; - } - - void attachInterrupt(uint32_t interruptNum, gpioIrqFn interruptCb, uint32_t mode) override { - if(interruptNum == RADIOLIB_NC) { - return; - } - - gpio_funcs[interruptNum - 1] = interruptCb; - libtock_lora_phy_gpio_command_interrupt_callback(lora_phy_gpio_Callback, NULL); - - // set GPIO as input and enable interrupts on it - libtock_lora_phy_gpio_enable_input(interruptNum, libtock_pull_down); - libtock_lora_phy_gpio_enable_interrupt(interruptNum, libtock_change); - } - - void detachInterrupt(uint32_t interruptNum) override { - if(interruptNum == RADIOLIB_NC) { - return; - } - - gpio_funcs[interruptNum - 1] = NULL; - libtock_lora_phy_gpio_disable_interrupt(interruptNum); - libtock_lora_phy_gpio_enable_input(interruptNum, libtock_pull_down); - } - - void delay(unsigned long ms) override { -#if !defined(RADIOLIB_CLOCK_DRIFT_MS) - libtocksync_alarm_delay_ms(ms); -#else - libtocksync_alarm_delay_ms(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); -#endif - } - - void delayMicroseconds(unsigned long us) override { -#if !defined(RADIOLIB_CLOCK_DRIFT_MS) - libtocksync_alarm_delay_ms(us / 1000); -#else - libtocksync_alarm_delay_ms((us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)) / 1000); -#endif - } - - unsigned long millis() override { - uint32_t now; - unsigned long ms; - - if (frequency == 0) { - alarm_internal_frequency(&frequency); - } - - alarm_internal_read(&now); - - ms = now / (frequency / 1000); - -#if !defined(RADIOLIB_CLOCK_DRIFT_MS) - return ms; -#else - return ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS); -#endif - } - - unsigned long micros() override { - return millis() / 1000; - } - - long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { - return 0; - } - - void spiBegin() { - } - - void spiBeginTransaction() { - } - - void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { - libtocksync_lora_phy_read_write(out, in, len); - } - - void spiEndTransaction() { - } - - void spiEnd() { - } - - void yield() { - ::yield_no_wait(); - } - - private: -}; - -#endif From c7d6ad3e951300cd37871728e40894fe01eebc2a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 17 Nov 2024 19:43:40 +0100 Subject: [PATCH 1351/1848] Remove an outdated comment --- src/BuildOpt.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 35ee44830f..1464ad449b 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -133,11 +133,9 @@ * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. * RADIOLIB_NONVOLATILE - macro to place variable into program storage (usually Flash). * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). - * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword. + * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually via the `using` keyword. * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. * - * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). - * * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_ARDUINO, * and then specifying all platform parameters in the section below. This will override automatic * platform detection. From c467b005c2d106704372225cc0066b9ab3e1bbef Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 18 Nov 2024 18:24:12 +0100 Subject: [PATCH 1352/1848] [SX127x] Add missing state initialization (#1321) --- src/modules/SX127x/SX127x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 82755db058..6ab426f005 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1324,7 +1324,7 @@ int16_t SX127x::setIrqFlags(uint32_t irq) { uint8_t usedPinFlags = 0; bool conflict = false; int16_t modem = getActiveModem(); - int16_t state; + int16_t state = RADIOLIB_ERR_NONE; for(uint8_t i = 0; i <= 31; i++) { // check if the bit is set uint32_t irqBit = irq & (1UL << i); From 8eb6f0cf24c01fb8ff3381d1279425e8b9ac9d54 Mon Sep 17 00:00:00 2001 From: Walter Dunckel Date: Tue, 19 Nov 2024 06:30:10 -0800 Subject: [PATCH 1353/1848] Change order of setFlag function The change allows the code to compile. The same issue exists with a few other examples too. --- .../STM32WLx_Transmit_Interrupt.ino | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index aed1c12540..736be3bd83 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -38,6 +38,18 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -85,18 +97,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From b33647adc3a891f65821f40dca6222f481e4a621 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:51:30 +0100 Subject: [PATCH 1354/1848] [CC1101] Fixed order of ISR functions in examples --- .../CC1101_Receive_Interrupt.ino | 30 +++++++++---------- .../CC1101_Transmit_Interrupt.ino | 30 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 1a6528d704..9f9a18873c 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -37,6 +37,21 @@ CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -76,21 +91,6 @@ void setup() { // radio.readData(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 049c9706b7..76899670c5 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -36,6 +36,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -69,21 +84,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From 2dd69398e37a321b90dbf621bfdaef06327fcddd Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:51:42 +0100 Subject: [PATCH 1355/1848] [LR11x0] Fixed order of ISR functions in examples --- ...0_Channel_Activity_Detection_Interrupt.ino | 30 +++++++++---------- .../LR11x0_Receive_Interrupt.ino | 30 +++++++++---------- .../LR11x0_Transmit_Interrupt.ino | 30 +++++++++---------- .../LR11x0_WiFi_Scan_Interrupt.ino | 28 ++++++++--------- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino index e7e295cb9b..7de03b216e 100644 --- a/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Channel_Activity_Detection_Interrupt/LR11x0_Channel_Activity_Detection_Interrupt.ino @@ -57,6 +57,21 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { END_OF_MODE_TABLE, }; +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + void setup() { Serial.begin(9600); @@ -89,21 +104,6 @@ void setup() { } } -// flag to indicate that a packet was detected or CAD timed out -volatile bool scanFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // something happened, set the flag - scanFlag = true; -} - void loop() { // check if the flag is set if(scanFlag) { diff --git a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino index 372c208f05..3b1d60743c 100644 --- a/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Receive_Interrupt/LR11x0_Receive_Interrupt.ino @@ -63,6 +63,21 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { END_OF_MODE_TABLE, }; +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -105,21 +120,6 @@ void setup() { // radio.scanChannel(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 8e40eff29a..3086a9a6bb 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -62,6 +62,21 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -98,21 +113,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; diff --git a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino index 38872f2e84..21d90f2c35 100644 --- a/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino +++ b/examples/LR11x0/LR11x0_WiFi_Scan_Interrupt/LR11x0_WiFi_Scan_Interrupt.ino @@ -60,6 +60,20 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { END_OF_MODE_TABLE, }; +// flag to indicate that a scan was completed +volatile bool scanFlag = false; + +// this function is called when a scan is completed +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // scan is complete, set the flag + scanFlag = true; +} + void setup() { Serial.begin(9600); @@ -92,20 +106,6 @@ void setup() { } } -// flag to indicate that a scan was completed -volatile bool scanFlag = false; - -// this function is called when a scan is completed -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // scan is complete, set the flag - scanFlag = true; -} - void loop() { // check if the flag is set if(scanFlag) { From f95de45be7fdc1626022af25147805dabf851811 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:51:49 +0100 Subject: [PATCH 1356/1848] [nRF24] Fixed order of ISR functions in examples --- .../nRF24_Receive_Interrupt.ino | 30 +++++++++---------- .../nRF24_Transmit_Interrupt.ino | 30 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index d081ff763f..cb19db0cf2 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -34,6 +34,21 @@ nRF24 radio = new Module(10, 2, 3); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -88,21 +103,6 @@ void setup() { // radio.readData(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 0751e51128..9ee46c4f51 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -36,6 +36,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -84,21 +99,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From 1fa7d479ad2b5e1d6d0b66467d91e40b197f5c68 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:51:57 +0100 Subject: [PATCH 1357/1848] [RF69] Fixed order of ISR functions in examples --- .../RF69_Receive_Interrupt.ino | 30 +++++++++---------- .../RF69_Transmit_Interrupt.ino | 30 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 4678525e69..e596a28317 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -29,6 +29,21 @@ RF69 radio = new Module(10, 2, 3); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -68,21 +83,6 @@ void setup() { // radio.readData(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index c4de787540..58a3f07186 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -35,6 +35,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -85,21 +100,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From 12d81e6d0f079067ca6ec8e17d1062668026d03d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:52:02 +0100 Subject: [PATCH 1358/1848] [Si443x] Fixed order of ISR functions in examples --- .../Si443x_Receive_Interrupt.ino | 30 +++++++++---------- .../Si443x_Transmit_Interrupt.ino | 30 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index 45f18179fc..63be2b4166 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -31,6 +31,21 @@ Si4432 radio = new Module(10, 2, 9); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -70,21 +85,6 @@ void setup() { // radio.readData(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 44501860a7..d2e433c0e4 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -36,6 +36,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -69,21 +84,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From 0a6d6a26e1d61ae3b646b14a4961605d49e9dd75 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:52:10 +0100 Subject: [PATCH 1359/1848] [STM32WLx] Fixed order of ISR functions in examples --- ...x_Channel_Activity_Detection_Interrupt.ino | 24 +++++++++---------- .../STM32WLx_Receive_Interrupt.ino | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino index 1a0e390a6f..b5a67e6764 100644 --- a/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Channel_Activity_Detection_Interrupt/STM32WLx_Channel_Activity_Detection_Interrupt.ino @@ -33,6 +33,18 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { END_OF_MODE_TABLE, }; +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + void setup() { Serial.begin(9600); @@ -66,18 +78,6 @@ void setup() { } } -// flag to indicate that a packet was detected or CAD timed out -volatile bool scanFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -void setFlag(void) { - // something happened, set the flag - scanFlag = true; -} - void loop() { // check if the flag is set if(scanFlag) { diff --git a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino index fe203f2ac9..dc62255dcf 100644 --- a/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Receive_Interrupt/STM32WLx_Receive_Interrupt.ino @@ -43,6 +43,18 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { END_OF_MODE_TABLE, }; +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -97,18 +109,6 @@ void setup() { // radio.scanChannel(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { From a579eed780e24026dcd4058df61431d92b6d1058 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:52:16 +0100 Subject: [PATCH 1360/1848] [SX126x] Fixed order of ISR functions in examples --- ...x_Channel_Activity_Detection_Interrupt.ino | 30 ++++++++-------- ...26x_Channel_Activity_Detection_Receive.ino | 35 ++++++++++--------- .../SX126x_Receive_Interrupt.ino | 30 ++++++++-------- .../SX126x_Transmit_Interrupt.ino | 30 ++++++++-------- 4 files changed, 63 insertions(+), 62 deletions(-) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index c47b4b2878..d47b58df2f 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -33,6 +33,21 @@ SX1262 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + void setup() { Serial.begin(9600); @@ -62,21 +77,6 @@ void setup() { } } -// flag to indicate that a packet was detected or CAD timed out -volatile bool scanFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // something happened, set the flag - scanFlag = true; -} - void loop() { // check if the flag is set if(scanFlag) { diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino index ec89de086a..85b204d579 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Receive/SX126x_Channel_Activity_Detection_Receive.ino @@ -35,6 +35,24 @@ SX1262 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// whether we are receiving, or scanning +bool receiving = false; + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + void setup() { Serial.begin(9600); @@ -64,23 +82,6 @@ void setup() { } } -// flag to indicate that a packet was detected or CAD timed out -volatile bool scanFlag = false; - -bool receiving = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // something happened, set the flag - scanFlag = true; -} - void loop() { // check if the flag is set if(scanFlag) { diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 42e27f2842..de1664bf4a 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -39,6 +39,21 @@ SX1262 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -78,21 +93,6 @@ void setup() { // radio.scanChannel(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 1acf3ee1a3..fcc5c956de 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -38,6 +38,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -71,21 +86,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From 17bcfcd0bb94a5a1b11a1299476ecd7d234187ff Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:52:21 +0100 Subject: [PATCH 1361/1848] [SX127x] Fixed order of ISR functions in examples --- ...x_Channel_Activity_Detection_Interrupt.ino | 60 ++++++++--------- ...27x_Channel_Activity_Detection_Receive.ino | 66 +++++++++---------- .../SX127x_Receive_Direct.ino | 12 ++-- .../SX127x_Receive_Interrupt.ino | 30 ++++----- .../SX127x_Transmit_Interrupt.ino | 30 ++++----- 5 files changed, 99 insertions(+), 99 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 95070e0ec9..4efbf4a2aa 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -34,6 +34,36 @@ SX1278 radio = new Module(10, 2, 9, 3); Radio radio = new RadioModule(); */ +// flag to indicate that a preamble was not detected +volatile bool timeoutFlag = false; + +// flag to indicate that a preamble was detected +volatile bool detectedFlag = false; + +// this function is called when no preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagTimeout(void) { + // we timed out, set the flag + timeoutFlag = true; +} + +// this function is called when LoRa preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagDetected(void) { + // we got a preamble, set the flag + detectedFlag = true; +} + void setup() { // Serial port speed must be high enough for this example Serial.begin(115200); @@ -68,36 +98,6 @@ void setup() { } } -// flag to indicate that a preamble was not detected -volatile bool timeoutFlag = false; - -// flag to indicate that a preamble was detected -volatile bool detectedFlag = false; - -// this function is called when no preamble -// is detected within timeout period -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlagTimeout(void) { - // we timed out, set the flag - timeoutFlag = true; -} - -// this function is called when LoRa preamble -// is detected within timeout period -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlagDetected(void) { - // we got a preamble, set the flag - detectedFlag = true; -} - void loop() { // check if we need to restart channel activity detection if(detectedFlag || timeoutFlag) { diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino index 9b03d2e207..0e5670e849 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Receive/SX127x_Channel_Activity_Detection_Receive.ino @@ -39,6 +39,39 @@ SX1278 radio = new Module(10, 2, 9, 3); Radio radio = new RadioModule(); */ +// flag to indicate that a preamble was not detected +volatile bool timeoutFlag = false; + +// flag to indicate that a preamble was detected +volatile bool detectedFlag = false; + +// flag to indicate if we are currently receiving +bool receiving = false; + +// this function is called when no preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagTimeout(void) { + // we timed out, set the flag + timeoutFlag = true; +} + +// this function is called when LoRa preamble +// is detected within timeout period +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlagDetected(void) { + // we got a preamble, set the flag + detectedFlag = true; +} + void setup() { // Serial port speed must be high enough for this example Serial.begin(115200); @@ -74,39 +107,6 @@ void setup() { } } -// flag to indicate that a preamble was not detected -volatile bool timeoutFlag = false; - -// flag to indicate that a preamble was detected -volatile bool detectedFlag = false; - -// flag to indicate if we are currently receiving -bool receiving = false; - -// this function is called when no preamble -// is detected within timeout period -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlagTimeout(void) { - // we timed out, set the flag - timeoutFlag = true; -} - -// this function is called when LoRa preamble -// is detected within timeout period -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlagDetected(void) { - // we got a preamble, set the flag - detectedFlag = true; -} - void loop() { // check if we need to restart channel activity detection if(detectedFlag || timeoutFlag) { diff --git a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino index f41493b2a8..ff9c443c2f 100644 --- a/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino +++ b/examples/SX127x/SX127x_Receive_Direct/SX127x_Receive_Direct.ino @@ -32,6 +32,12 @@ const int pin = 5; Radio radio = new RadioModule(); */ +// this function is called when a new bit is received +void readBit(void) { + // read the data bit + radio.readBit(pin); +} + void setup() { Serial.begin(9600); @@ -59,12 +65,6 @@ void setup() { radio.receiveDirect(); } -// this function is called when a new bit is received -void readBit(void) { - // read the data bit - radio.readBit(pin); -} - void loop() { // we expect the packet to contain the string "Hello World!", // a length byte and 2 CRC bytes, that's 15 bytes in total diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 451e4192e4..ebb0483218 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -39,6 +39,21 @@ SX1278 radio = new Module(10, 2, 9, 3); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -78,21 +93,6 @@ void setup() { // radio.scanChannel(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 22785d7681..04385bc10b 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -38,6 +38,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -71,21 +86,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From 8d119fc2429b84c9cdf4943ddefeb4ade16e4a29 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 19 Nov 2024 18:52:27 +0100 Subject: [PATCH 1362/1848] [SX128x] Fixed order of ISR functions in examples --- ...x_Channel_Activity_Detection_Interrupt.ino | 30 +++++++++---------- .../SX128x_Receive_Interrupt.ino | 30 +++++++++---------- .../SX128x_Transmit_Interrupt.ino | 30 +++++++++---------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino index 8a57e181b3..8e3ab594a6 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection_Interrupt/SX128x_Channel_Activity_Detection_Interrupt.ino @@ -31,6 +31,21 @@ SX1280 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + void setup() { Serial.begin(9600); @@ -60,21 +75,6 @@ void setup() { } } -// flag to indicate that a packet was detected or CAD timed out -volatile bool scanFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // something happened, set the flag - scanFlag = true; -} - void loop() { // check if the flag is set if(scanFlag) { diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 0ca0406cab..984db2428b 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -39,6 +39,21 @@ SX1280 radio = new Module(10, 2, 3, 9); Radio radio = new RadioModule(); */ +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + void setup() { Serial.begin(9600); @@ -79,21 +94,6 @@ void setup() { // radio.scanChannel(); } -// flag to indicate that a packet was received -volatile bool receivedFlag = false; - -// this function is called when a complete packet -// is received by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we got a packet, set the flag - receivedFlag = true; -} - void loop() { // check if the flag is set if(receivedFlag) { diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 1c760d5a23..340efd1d5d 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -38,6 +38,21 @@ Radio radio = new RadioModule(); // save transmission state between loops int transmissionState = RADIOLIB_ERR_NONE; +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + void setup() { Serial.begin(9600); @@ -71,21 +86,6 @@ void setup() { */ } -// flag to indicate that a packet was sent -volatile bool transmittedFlag = false; - -// this function is called when a complete packet -// is transmitted by the module -// IMPORTANT: this function MUST be 'void' type -// and MUST NOT have any arguments! -#if defined(ESP8266) || defined(ESP32) - ICACHE_RAM_ATTR -#endif -void setFlag(void) { - // we sent a packet, set the flag - transmittedFlag = true; -} - // counter to keep track of transmitted packets int count = 0; From ef16e431af979538327967944df56af7e727675b Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 21 Nov 2024 20:09:05 +0100 Subject: [PATCH 1363/1848] [LR11x0] Disable DIO11 for GNSS only (#1275) --- src/modules/LR11x0/LR11x0.cpp | 7 +++++-- src/modules/LR11x0/LR11x0.h | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6891cd59eb..7b988371d5 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -129,6 +129,8 @@ int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) { state = this->clearErrors(); RADIOLIB_ASSERT(state); + // set GNSS flag to reserve DIO11 for LF clock + this->gnss = true; state = this->configLfClock(RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED | RADIOLIB_LR11X0_LF_CLK_XOSC); RADIOLIB_ASSERT(state); @@ -2066,6 +2068,7 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->spiConfig.stream = true; this->mod->spiConfig.parseStatusCb = SPIparseStatus; this->mod->spiConfig.checkStatusCb = SPIcheckStatus; + this->gnss = false; // try to find the LR11x0 chip - this will also reset the module at least once if(!LR11x0::findChip(this->chipType)) { @@ -2452,7 +2455,7 @@ int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) { } int16_t LR11x0::setDioIrqParams(uint32_t irq) { - return(setDioIrqParams(irq, 0)); + return(setDioIrqParams(irq, this->gnss ? 0 : irq)); } int16_t LR11x0::clearIrq(uint32_t irq) { @@ -2463,7 +2466,7 @@ int16_t LR11x0::clearIrq(uint32_t irq) { } int16_t LR11x0::configLfClock(uint8_t setup) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK, true, &setup, 1)); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK, true, &setup, 1)); } int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 9ee985d5b3..42685a9f94 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -33,7 +33,7 @@ #define RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH (0x0112) #define RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS (0x0113) #define RADIOLIB_LR11X0_CMD_CLEAR_IRQ (0x0114) -#define RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK (0x0116) +#define RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK (0x0116) #define RADIOLIB_LR11X0_CMD_SET_TCXO_MODE (0x0117) #define RADIOLIB_LR11X0_CMD_REBOOT (0x0118) #define RADIOLIB_LR11X0_CMD_GET_VBAT (0x0119) @@ -281,7 +281,7 @@ #define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts #define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts -// RADIOLIB_LR11X0_CMD_CONFIG_LF_LOCK +// RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK #define RADIOLIB_LR11X0_LF_CLK_RC (0x00UL << 0) // 1 0 32.768 kHz source: RC oscillator #define RADIOLIB_LR11X0_LF_CLK_XOSC (0x01UL << 0) // 1 0 crystal oscillator #define RADIOLIB_LR11X0_LF_CLK_EXT (0x02UL << 0) // 1 0 external signal on DIO11 @@ -1828,6 +1828,7 @@ class LR11x0: public PhysicalLayer { float dataRateMeasured = 0; uint8_t wifiScanMode = 0; + bool gnss = false; int16_t modSetup(float tcxoVoltage, uint8_t modem); static int16_t SPIparseStatus(uint8_t in); From 53e7a309a0b48c998ec43052e34339e405e0341c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 22 Nov 2024 17:14:59 +0100 Subject: [PATCH 1364/1848] [LLCC68] Added LLCC68 examples --- .../LLCC68_Receive_Blocking.ino | 105 +++++++++++++++++ .../LLCC68_Transmit_Blocking.ino | 106 ++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino create mode 100644 examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino diff --git a/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino b/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino new file mode 100644 index 0000000000..98e7b95e16 --- /dev/null +++ b/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino @@ -0,0 +1,105 @@ +/* + RadioLib LLCC68 Blocking Receive Example + + This example listens for LoRa transmissions using LLCC68 LoRa modules. + + NOTE: LLCC68 modules offer the same features as SX1261 and has the same + interface. Please see SX126x examples for full reference. + + WARNING: Often, LLCC68 modules are mislabeled. If you are seeing error -2 + (RADIOLIB_ERR_CHIP_NOT_FOUND) and debug mode shows "SX1261" as + the version string, use the SX1261 class! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LLCC68 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LLCC68 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LLCC68 with default settings + Serial.print(F("[LLCC68] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } +} + +void loop() { + Serial.print(F("[LLCC68] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[LLCC68] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[LLCC68] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[LLCC68] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + // print frequency error + Serial.print(F("[LLCC68] Frequency error:\t")); + Serial.print(radio.getFrequencyError()); + Serial.println(F(" Hz")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino b/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino new file mode 100644 index 0000000000..349c3f2c75 --- /dev/null +++ b/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino @@ -0,0 +1,106 @@ +/* + RadioLib SX126x Blocking Transmit Example + + This example transmits packets using LLCC68 LoRa radio module. + + NOTE: LLCC68 modules offer the same features as SX1261 and has the same + interface. Please see SX126x examples for full reference. + + WARNING: Often, LLCC68 modules are mislabeled. If you are seeing error -2 + (RADIOLIB_ERR_CHIP_NOT_FOUND) and debug mode shows "SX1261" as + the version string, use the SX1261 class! + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LLCC68 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LLCC68 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LLCC68 with default settings + Serial.print(F("[LLCC68] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[LLCC68] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[LLCC68] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} From 35f18b049bc146216f9da80dac47e991be29d775 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 22 Nov 2024 17:16:27 +0100 Subject: [PATCH 1365/1848] [LLCC68] Added note about different configuration --- .../LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino | 6 ++++-- .../LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino b/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino index 98e7b95e16..f934e18cd8 100644 --- a/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino +++ b/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino @@ -3,8 +3,10 @@ This example listens for LoRa transmissions using LLCC68 LoRa modules. - NOTE: LLCC68 modules offer the same features as SX1261 and has the same - interface. Please see SX126x examples for full reference. + NOTE: LLCC68 modules offer the same features as SX1261 and have the same + interface. The difference is in the available LoRa settings (not all + spreading factors are available on LLCC68). + Please see SX126x examples for full reference. WARNING: Often, LLCC68 modules are mislabeled. If you are seeing error -2 (RADIOLIB_ERR_CHIP_NOT_FOUND) and debug mode shows "SX1261" as diff --git a/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino b/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino index 349c3f2c75..8874f33916 100644 --- a/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino +++ b/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino @@ -3,8 +3,10 @@ This example transmits packets using LLCC68 LoRa radio module. - NOTE: LLCC68 modules offer the same features as SX1261 and has the same - interface. Please see SX126x examples for full reference. + NOTE: LLCC68 modules offer the same features as SX1261 and have the same + interface. The difference is in the available LoRa settings (not all + spreading factors are available on LLCC68). + Please see SX126x examples for full reference. WARNING: Often, LLCC68 modules are mislabeled. If you are seeing error -2 (RADIOLIB_ERR_CHIP_NOT_FOUND) and debug mode shows "SX1261" as From 0bd5bdc8963d6a8b5110aa34da897053f3d6c311 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 24 Nov 2024 09:29:58 +0100 Subject: [PATCH 1366/1848] [SX126x] Allow 15 dBm on SX1261 (#1329) --- src/modules/SX126x/SX1261.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index d6a90c3421..89af5c8363 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -16,11 +16,19 @@ int16_t SX1261::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // set PA config - state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1261, 0x00); + uint8_t paDutyCycle = 0x04; + int8_t txPwr = power; + if(power == 15) { + // for 15 dBm, increase the duty cycle and lowe the power to set + // SX1261/2 datasheet, DS.SX1261-2.W.APP Rev. 2.1 page 78 + paDutyCycle = 0x06; + txPwr--; + } + state = SX126x::setPaConfig(paDutyCycle, RADIOLIB_SX126X_PA_CONFIG_SX1261, 0x00); RADIOLIB_ASSERT(state); // set output power with default 200us ramp - state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); + state = SX126x::setTxParams(txPwr, RADIOLIB_SX126X_PA_RAMP_200U); RADIOLIB_ASSERT(state); // restore OCP configuration @@ -29,9 +37,9 @@ int16_t SX1261::setOutputPower(int8_t power) { int16_t SX1261::checkOutputPower(int8_t power, int8_t* clipped) { if(clipped) { - *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power)); + *clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(15, power)); } - RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -17, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); return(RADIOLIB_ERR_NONE); } From 24f1535088bb949d1c5cad8e78a9ed5cb97250f5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 24 Nov 2024 10:38:35 +0100 Subject: [PATCH 1367/1848] [SX126x] Fix upper power range in doxygen --- src/modules/SX126x/SX1261.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 196cc21bc4..5c5e3bed78 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -28,7 +28,7 @@ class SX1261 : public SX1262 { SX1261(Module* mod); // cppcheck-suppress noExplicitConstructor /*! - \brief Sets output power. Allowed values are in range from -17 to 14 dBm. + \brief Sets output power. Allowed values are in range from -17 to 15 dBm. \param power Output power to be set in dBm. \returns \ref status_codes */ From 855a64c05390a08405fc3a701bf64b41d2f59d1f Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 26 Nov 2024 19:46:43 +0100 Subject: [PATCH 1368/1848] [SX126x] Allow SX1261 version string for LLCC68 devices (#1329) --- .../LLCC68_Receive_Blocking.ino | 107 ----------------- .../LLCC68_Transmit_Blocking.ino | 108 ------------------ src/modules/LLCC68/LLCC68.cpp | 7 ++ src/modules/LLCC68/LLCC68.h | 1 + 4 files changed, 8 insertions(+), 215 deletions(-) delete mode 100644 examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino delete mode 100644 examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino diff --git a/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino b/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino deleted file mode 100644 index f934e18cd8..0000000000 --- a/examples/LLCC68/LLCC68_Receive_Blocking/LLCC68_Receive_Blocking.ino +++ /dev/null @@ -1,107 +0,0 @@ -/* - RadioLib LLCC68 Blocking Receive Example - - This example listens for LoRa transmissions using LLCC68 LoRa modules. - - NOTE: LLCC68 modules offer the same features as SX1261 and have the same - interface. The difference is in the available LoRa settings (not all - spreading factors are available on LLCC68). - Please see SX126x examples for full reference. - - WARNING: Often, LLCC68 modules are mislabeled. If you are seeing error -2 - (RADIOLIB_ERR_CHIP_NOT_FOUND) and debug mode shows "SX1261" as - the version string, use the SX1261 class! - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// LLCC68 has the following connections: -// NSS pin: 10 -// DIO1 pin: 2 -// NRST pin: 3 -// BUSY pin: 9 -LLCC68 radio = new Module(10, 2, 3, 9); - -// or detect the pinout automatically using RadioBoards -// https://github.com/radiolib-org/RadioBoards -/* -#define RADIO_BOARD_AUTO -#include -Radio radio = new RadioModule(); -*/ - -void setup() { - Serial.begin(9600); - - // initialize LLCC68 with default settings - Serial.print(F("[LLCC68] Initializing ... ")); - int state = radio.begin(); - if (state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true) { delay(10); } - } -} - -void loop() { - Serial.print(F("[LLCC68] Waiting for incoming transmission ... ")); - - // you can receive data as an Arduino String - String str; - int state = radio.receive(str); - - // you can also receive data as byte array - /* - byte byteArr[8]; - int state = radio.receive(byteArr, 8); - */ - - if (state == RADIOLIB_ERR_NONE) { - // packet was successfully received - Serial.println(F("success!")); - - // print the data of the packet - Serial.print(F("[LLCC68] Data:\t\t")); - Serial.println(str); - - // print the RSSI (Received Signal Strength Indicator) - // of the last received packet - Serial.print(F("[LLCC68] RSSI:\t\t")); - Serial.print(radio.getRSSI()); - Serial.println(F(" dBm")); - - // print the SNR (Signal-to-Noise Ratio) - // of the last received packet - Serial.print(F("[LLCC68] SNR:\t\t")); - Serial.print(radio.getSNR()); - Serial.println(F(" dB")); - - // print frequency error - Serial.print(F("[LLCC68] Frequency error:\t")); - Serial.print(radio.getFrequencyError()); - Serial.println(F(" Hz")); - - } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { - // timeout occurred while waiting for a packet - Serial.println(F("timeout!")); - - } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { - // packet was received, but is malformed - Serial.println(F("CRC error!")); - - } else { - // some other error occurred - Serial.print(F("failed, code ")); - Serial.println(state); - - } -} diff --git a/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino b/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino deleted file mode 100644 index 8874f33916..0000000000 --- a/examples/LLCC68/LLCC68_Transmit_Blocking/LLCC68_Transmit_Blocking.ino +++ /dev/null @@ -1,108 +0,0 @@ -/* - RadioLib SX126x Blocking Transmit Example - - This example transmits packets using LLCC68 LoRa radio module. - - NOTE: LLCC68 modules offer the same features as SX1261 and have the same - interface. The difference is in the available LoRa settings (not all - spreading factors are available on LLCC68). - Please see SX126x examples for full reference. - - WARNING: Often, LLCC68 modules are mislabeled. If you are seeing error -2 - (RADIOLIB_ERR_CHIP_NOT_FOUND) and debug mode shows "SX1261" as - the version string, use the SX1261 class! - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// LLCC68 has the following connections: -// NSS pin: 10 -// DIO1 pin: 2 -// NRST pin: 3 -// BUSY pin: 9 -LLCC68 radio = new Module(10, 2, 3, 9); - -// or detect the pinout automatically using RadioBoards -// https://github.com/radiolib-org/RadioBoards -/* -#define RADIO_BOARD_AUTO -#include -Radio radio = new RadioModule(); -*/ - -void setup() { - Serial.begin(9600); - - // initialize LLCC68 with default settings - Serial.print(F("[LLCC68] Initializing ... ")); - int state = radio.begin(); - if (state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true) { delay(10); } - } - - // some modules have an external RF switch - // controlled via two pins (RX enable, TX enable) - // to enable automatic control of the switch, - // call the following method - // RX enable: 4 - // TX enable: 5 - /* - radio.setRfSwitchPins(4, 5); - */ -} - -// counter to keep track of transmitted packets -int count = 0; - -void loop() { - Serial.print(F("[LLCC68] Transmitting packet ... ")); - - // you can transmit C-string or Arduino string up to - // 256 characters long - String str = "Hello World! #" + String(count++); - int state = radio.transmit(str); - - // you can also transmit byte array up to 256 bytes long - /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; - int state = radio.transmit(byteArr, 8); - */ - - if (state == RADIOLIB_ERR_NONE) { - // the packet was successfully transmitted - Serial.println(F("success!")); - - // print measured data rate - Serial.print(F("[LLCC68] Datarate:\t")); - Serial.print(radio.getDataRate()); - Serial.println(F(" bps")); - - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { - // the supplied packet was longer than 256 bytes - Serial.println(F("too long!")); - - } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { - // timeout occured while transmitting packet - Serial.println(F("timeout!")); - - } else { - // some other error occurred - Serial.print(F("failed, code ")); - Serial.println(state); - - } - - // wait for a second before transmitting again - delay(1000); -} diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 12de7a52d0..834f5eda86 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -9,6 +9,13 @@ LLCC68::LLCC68(Module* mod) : SX1262(mod) { int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { + // bit of a hack, but some LLCC68 chips report as "SX1261", try that + // for full discussion, see https://github.com/jgromes/RadioLib/issues/1329 + chipType = RADIOLIB_SX1261_CHIP_TYPE; + state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_DEBUG_PRINTLN("LLCC68 version string not found, using SX1261 instead"); + } RADIOLIB_ASSERT(state); // configure publicly accessible settings diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index a0b6d19e8a..7809c56cbf 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -7,6 +7,7 @@ #include "../../Module.h" #include "../SX126x/SX1262.h" +#include "../SX126x/SX1261.h" //RADIOLIB_SX126X_REG_VERSION_STRING #define RADIOLIB_LLCC68_CHIP_TYPE "LLCC68" From 3e634ffb88784b51f7e665b59e61377dcae97663 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 26 Nov 2024 22:26:12 +0100 Subject: [PATCH 1369/1848] [LoRaWAN] Simplify JoinRequest datarate handling --- src/protocols/LoRaWAN/LoRaWAN.cpp | 19 +----- src/protocols/LoRaWAN/LoRaWAN.h | 3 - src/protocols/LoRaWAN/LoRaWANBands.cpp | 95 ++++++-------------------- 3 files changed, 22 insertions(+), 95 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b0fcebb503..74b82ce134 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -346,15 +346,9 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { } // if there is no (channel that allowed the) user-specified datarate, use a default datarate - // we use the floor of the average datarate of the first enabled channel if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { - uint8_t drMin = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin; - uint8_t drMax = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax; - drUp = (drMin + drMax) / 2; - } - } + // use the specified datarate from the first channel (this is always defined) + drUp = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][0].dr; } } @@ -2980,15 +2974,6 @@ void LoRaWANNode::selectChannelPlanDyn(bool joinRequest) { this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; } - // if we're about to send a JoinRequest, copy the JoinRequest channels to the next slots - if(joinRequest) { - size_t numJR = 0; - for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; - } - } - // clear all remaining channels for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 79a4fcc63b..9cb7aab346 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -405,9 +405,6 @@ struct LoRaWANBand_t { /*! \brief A set of default uplink (TX) channels for dynamic bands */ LoRaWANChannel_t txFreqs[3]; - /*! \brief A set of possible extra channels for the Join-Request message for dynamic bands */ - LoRaWANChannel_t txJoinReq[3]; - /*! \brief The number of TX channel spans for fixed bands */ uint8_t numTxSpans; diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index d29126aa01..398de514f1 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -30,14 +30,9 @@ const LoRaWANBand_t EU868 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 8681000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 8683000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 2, .freq = 8685000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + { .enabled = true, .idx = 0, .freq = 8681000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 8683000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 2, .freq = 8685000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, }, .numTxSpans = 0, .txSpans = { @@ -107,11 +102,6 @@ const LoRaWANBand_t US915 = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, .numTxSpans = 2, .txSpans = { { @@ -197,14 +187,9 @@ const LoRaWANBand_t EU433 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 4331750, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 4333750, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 2, .freq = 4335750, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + { .enabled = true, .idx = 0, .freq = 4331750, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 4333750, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 2, .freq = 4335750, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, }, .numTxSpans = 0, .txSpans = { @@ -274,11 +259,6 @@ const LoRaWANBand_t AU915 = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, .numTxSpans = 2, .txSpans = { { @@ -368,11 +348,6 @@ const LoRaWANBand_t CN500 = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, .numTxSpans = 1, .txSpans = { { @@ -451,13 +426,8 @@ const LoRaWANBand_t AS923 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 9234000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, + { .enabled = true, .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9234000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -524,13 +494,8 @@ const LoRaWANBand_t AS923_2 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 9216000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, + { .enabled = true, .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9216000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -597,13 +562,8 @@ const LoRaWANBand_t AS923_3 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 9168000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, + { .enabled = true, .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9168000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -670,13 +630,8 @@ const LoRaWANBand_t AS923_4 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 9175000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - RADIOLIB_LORAWAN_CHANNEL_NONE - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, + { .enabled = true, .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9175000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -743,14 +698,9 @@ const LoRaWANBand_t KR920 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9221000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 9223000, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 2, .freq = 9225000, .drMin = 0, .drMax = 5, .dr = 5, .available = true } - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + { .enabled = true, .idx = 0, .freq = 9221000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 9223000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 2, .freq = 9225000, .drMin = 0, .drMax = 5, .dr = 3, .available = true } }, .numTxSpans = 0, .txSpans = { @@ -816,14 +766,9 @@ const LoRaWANBand_t IN865 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 8650625, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 1, .freq = 8654025, .drMin = 0, .drMax = 5, .dr = 5, .available = true }, - { .enabled = true, .idx = 2, .freq = 8659850, .drMin = 0, .drMax = 5, .dr = 5, .available = true } - }, - .txJoinReq = { - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE + { .enabled = true, .idx = 0, .freq = 8650625, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 1, .freq = 8654025, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .enabled = true, .idx = 2, .freq = 8659850, .drMin = 0, .drMax = 5, .dr = 3, .available = true } }, .numTxSpans = 0, .txSpans = { From 5e063e7ad867caadd39685497bf59a09fdecd18e Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 26 Nov 2024 22:27:18 +0100 Subject: [PATCH 1370/1848] [LoRaWAN] Update revision naming / RP revision B --- examples/LoRaWAN/LoRaWAN_Starter/notes.md | 2 +- examples/LoRaWAN/README.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md index e68949e7a5..49a37f845f 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/notes.md +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -52,7 +52,7 @@ You are making your own device using a third party LoRaWAN stack so there will n Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'. -Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision A. +Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B. At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the console generate them so they are properly formatted. diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index f4754c1bd7..d2a7325410 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -6,17 +6,17 @@ RadioLib LoRaWAN examples. * [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib. ## LoRaWAN versions & regional parameters -RadioLib implements both LoRaWAN v1.1 and v1.0.4. Confusingly, v1.0.4 is newer than v1.1, but v1.1 includes more security checks and as such **LoRaWAN v1.1 is preferred**. -The catch is in the Regional Parameters: as v1.0.4 is newer, it is more up to date regarding local laws & regulations. Therefore, RadioLib implements 1.0.4 as baseline and 1.1 as fallback, but **Regional Parameters v1.0.4 is preferred**. -_Note: the CN500 band is implemented as specified in RP v1.1, as the RP v1.0.4 version is much too complex._ +RadioLib implements both LoRaWAN Specification 1.1 and 1.0.4. Confusingly, 1.0.4 is newer than 1.1, but 1.1 includes more security checks and as such **LoRaWAN 1.1 is preferred**. +The catch is in the Regional Parameters: as RP002 1.0.4 is newer than RP001 1.1, it is more up to date regarding local laws & regulations. Therefore, RadioLib implements 1.0.4 as baseline and 1.1 (revision B) as fallback, and as such **RP002 Regional Parameters 1.0.4 is preferred**. +_Note: the CN500 band is implemented as specified in RP001 1.1 revision B, as the RP002 1.0.4 version is much too complex._ -To activate a LoRaWAN v1.1 session, supply all the required keys: +To activate a LoRaWAN 1.1 session, supply all the required keys: ```cpp node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey); ``` -To activate a LoRaWAN v1.0.4 session, set the keys that are not available to `NULL`: +To activate a LoRaWAN 1.0.4 session, set the keys that are not available to `NULL`: ```cpp node.beginOTAA(joinEUI, devEUI, NULL, appKey); node.beginABP(devAddr, NULL, NULL, nwkSEncKey, appSKey); @@ -26,9 +26,9 @@ The device doesn't need to know the Regional Parameters version - that is of imp ## LoRaWAN persistence > [!WARNING] -> These examples do not actually comply with LoRaWAN v1.0.4/v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: +> These examples do not actually comply with LoRaWAN 1.0.4/1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: -In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN v1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!** +In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN 1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!** Currently, examples are available for the following platforms: * [LoRaWAN for ESP32](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP32) From 5d6ca6251f9ebc97d721f4d73fcd60ed6aee3cc9 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 26 Nov 2024 23:03:09 +0100 Subject: [PATCH 1371/1848] [LoRaWAN] Code style fixes --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++------ src/protocols/LoRaWAN/LoRaWAN.h | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 74b82ce134..02858408ca 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -840,8 +840,10 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + // also store this signature in the Session buffer to make sure these buffers match uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); // store DevAddr and all keys LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); @@ -849,9 +851,6 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); - - // set the signature of the Nonces buffer in the Session buffer - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); // store network parameters LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); @@ -976,8 +975,10 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + // also store this signature in the Session buffer to make sure these buffers match uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); // store DevAddr and all keys LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); @@ -986,9 +987,6 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - // set the signature of the Nonces buffer in the Session buffer - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); - // store network parameters LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 9cb7aab346..ae942c632c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -273,8 +273,8 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 4 bytes - RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + 2, // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes From a692b72347b3ddf4ce225b0afc249c1b5a445063 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 30 Nov 2024 21:53:48 +0100 Subject: [PATCH 1372/1848] Move ESP-IDF HAL back to examples (#1322) --- {src/hal/ESP-IDF => examples/NonArduino/ESP-IDF/main}/EspHal.h | 2 +- examples/NonArduino/ESP-IDF/main/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename {src/hal/ESP-IDF => examples/NonArduino/ESP-IDF/main}/EspHal.h (98%) diff --git a/src/hal/ESP-IDF/EspHal.h b/examples/NonArduino/ESP-IDF/main/EspHal.h similarity index 98% rename from src/hal/ESP-IDF/EspHal.h rename to examples/NonArduino/ESP-IDF/main/EspHal.h index 340adbd630..3f7cd12557 100644 --- a/src/hal/ESP-IDF/EspHal.h +++ b/examples/NonArduino/ESP-IDF/main/EspHal.h @@ -7,7 +7,7 @@ // this example only works on ESP32 and is unlikely to work on ESP32S2/S3 etc. // if you need high portability, you should probably use Arduino anyway ... #if CONFIG_IDF_TARGET_ESP32 == 0 - #error Target is not ESP32! + #error This example HAL only supports ESP32 targets. Support for ESP32S2/S3 etc. can be added by adjusting this file to user needs. #endif // include all the dependencies diff --git a/examples/NonArduino/ESP-IDF/main/main.cpp b/examples/NonArduino/ESP-IDF/main/main.cpp index 45e6f75d71..9a2272b6ed 100644 --- a/examples/NonArduino/ESP-IDF/main/main.cpp +++ b/examples/NonArduino/ESP-IDF/main/main.cpp @@ -17,7 +17,7 @@ #include // include the hardware abstraction layer -#include "hal/ESP-IDF/EspHal.h" +#include "EspHal.h" // create a new instance of the HAL class EspHal* hal = new EspHal(5, 19, 27); From 116d60deb24714a74ad3e5de7012bac3e2c1157e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 8 Dec 2024 10:14:26 +0100 Subject: [PATCH 1373/1848] [SX128x] Make Tx timeout at least 5 ms --- src/modules/SX128x/SX128x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 37b9361943..3d1ce145e2 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -327,8 +327,8 @@ int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t state = standby(); RADIOLIB_ASSERT(state); - // calculate timeout in ms (500% of expected time-on-air) - RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; + // calculate timeout in ms (5ms + 500 % of expected time-on-air) + RadioLibTime_t timeout = 5 + (getTimeOnAir(len) * 5) / 1000; RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start transmission From 577a0761ac0b5468c68ded009b77dc3460ed95dc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 8 Dec 2024 10:15:22 +0100 Subject: [PATCH 1374/1848] [SX126x] Make Tx timeout at least 5 ms (#1338) --- src/modules/SX126x/SX126x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index bddf8bec1c..7defbbcb00 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -203,8 +203,8 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } - // calculate timeout in ms (500% of expected time-on-air) - RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; + // calculate timeout in ms (5ms + 500 % of expected time-on-air) + RadioLibTime_t timeout = 5 + (getTimeOnAir(len) * 5) / 1000; RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start transmission From 67e5c6ee7be886842b24bb60f23ffcdf32707a33 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Wed, 11 Dec 2024 13:57:59 +0300 Subject: [PATCH 1375/1848] fix build with Arduino Core for Silicon Labs EFR32 Series 2 --- src/BuildOpt.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 1464ad449b..faae44da0d 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -363,6 +363,13 @@ #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) +#elif defined(ARDUINO_ARCH_SILABS) + // Silicon Labs Arduino + #define RADIOLIB_PLATFORM "Arduino Silicon Labs" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" From 957a533089721300dff77990a6a26b640a63da51 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 14 Dec 2024 12:39:27 +0100 Subject: [PATCH 1376/1848] [LoRaWAN] Do not reject first JoinAccept for 1.0.4 on Chirpstack --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 02858408ca..2263d4a8d6 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -717,7 +717,7 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { } } else { // for v1.0.4, the JoinNonce is simply a non-repeating value (we only check the last value) - if(joinNonceNew == this->joinNonce) { + if((this->joinNonce > 0) && (joinNonceNew == this->joinNonce)) { return(RADIOLIB_ERR_JOIN_NONCE_INVALID); } } From f2a8a894d97e168c339902d8e7d18539f98d105c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Dec 2024 14:30:56 +0100 Subject: [PATCH 1377/1848] [CI] Add Silicon Labs board to supported platforms --- .github/workflows/main.yml | 4 ++++ README.md | 3 +++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c28278a3c3..963e4eb333 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,7 @@ on: - MegaCore:avr:1281 - teensy:avr:teensy41 - arduino:renesas_uno:minima + - SiliconLabs:silabs:xg24explorerkit jobs: build: @@ -118,6 +119,9 @@ jobs: - id: arduino:renesas_uno:minima run: | echo "skip-pattern=(STM32WL|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT + - id: SiliconLabs:silabs:xg24explorerkit + run: | + echo "index-url=--additional-urls https://siliconlabs.github.io/arduino/package_arduinosilabs_index.json" >> $GITHUB_OUTPUT runs-on: ubuntu-latest name: ${{ matrix.id }} diff --git a/README.md b/README.md index 78a561f9ba..ebbc7ecac6 100644 --- a/README.md +++ b/README.md @@ -94,4 +94,7 @@ SX127x, RFM9x, SX126x, LR11x0 and SX128x * __PJRC__ * [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards +* __Silicon Labs__ + * [__EFR32__](https://github.com/SiliconLabs/arduino) - Silicon Labs xG24, xG27 and other boards + The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstraction layer, which allows it to be easily ported even to non-Arduino environments. From 111de250ec1bc293dfd326388b454a46b157364b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 14 Dec 2024 14:49:23 +0100 Subject: [PATCH 1378/1848] [CC1101] Clarify maximum packet length (#1347) --- .../CC1101_Transmit_Address/CC1101_Transmit_Address.ino | 4 ++-- .../CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino | 4 ++-- .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 4 ++-- src/modules/CC1101/CC1101.h | 5 +---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index 37bc21f59e..89fef51c04 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -82,10 +82,10 @@ void setup() { void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); - // you can transmit C-string or Arduino string up to 63 characters long + // you can transmit C-string or Arduino string up to 64 characters long int state = radio.transmit("Hello World!"); - // you can also transmit byte array up to 63 bytes long + // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); diff --git a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index 52f4fb94cd..3f45061d9d 100644 --- a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -57,11 +57,11 @@ int count = 0; void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); - // you can transmit C-string or Arduino string up to 63 characters long + // you can transmit C-string or Arduino string up to 64 characters long String str = "Hello World! #" + String(count++); int state = radio.transmit(str); - // you can also transmit byte array up to 63 bytes long + // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 76899670c5..e1d88624ee 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -119,11 +119,11 @@ void loop() { Serial.print(F("[CC1101] Sending another packet ... ")); // you can transmit C-string or Arduino string up to - // 256 characters long + // 64 characters long String str = "Hello World! #" + String(count++); transmissionState = radio.startTransmit(str); - // you can also transmit byte array up to 256 bytes long + // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 8a303bf725..e1a71a47a0 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -8,7 +8,7 @@ // CC1101 physical layer properties #define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 -#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 63 +#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 64 #define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 #define RADIOLIB_CC1101_DIV_EXPONENT 16 @@ -191,9 +191,6 @@ // RADIOLIB_CC1101_REG_SYNC0 #define RADIOLIB_CC1101_SYNC_WORD_LSB 0x91 // 7 0 sync word LSB -// RADIOLIB_CC1101_REG_PKTLEN -#define RADIOLIB_CC1101_PACKET_LENGTH 0xFF // 7 0 packet length in bytes - // RADIOLIB_CC1101_REG_PKTCTRL1 #define RADIOLIB_CC1101_PQT 0x00 // 7 5 preamble quality threshold #define RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF 0b00000000 // 3 3 automatic Rx FIFO flush on CRC check fail: disabled (default) From 0cc72c8310c62f0dab8a4bac3db1836def0f3783 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 15 Dec 2024 15:48:05 +0100 Subject: [PATCH 1379/1848] [SX127x] Use length from startReceive in implicit header mode (#1345) --- src/modules/SX127x/SX1272.cpp | 29 ++++++----------------------- src/modules/SX127x/SX1272.h | 1 - src/modules/SX127x/SX1278.cpp | 29 ++++++----------------------- src/modules/SX127x/SX1278.h | 1 - src/modules/SX127x/SX127x.cpp | 32 +++++++++++++++++++++++++++----- src/modules/SX127x/SX127x.h | 2 ++ 6 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 17a04dcf0f..4b118d624f 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -497,11 +497,13 @@ int16_t SX1272::autoLDRO() { } int16_t SX1272::implicitHeader(size_t len) { - return(setHeaderType(RADIOLIB_SX1272_HEADER_IMPL_MODE, len)); + this->implicitHdr = true; + return(setHeaderType(RADIOLIB_SX1272_HEADER_IMPL_MODE, 2, len)); } int16_t SX1272::explicitHeader() { - return(setHeaderType(RADIOLIB_SX1272_HEADER_EXPL_MODE)); + this->implicitHdr = false; + return(setHeaderType(RADIOLIB_SX1272_HEADER_EXPL_MODE, 2)); } int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { @@ -521,11 +523,13 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers Module* mod = this->getMod(); if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { + this->implicitHdr = true; state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { + this->implicitHdr = false; state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); @@ -544,27 +548,6 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) { return(state); } -int16_t SX1272::setHeaderType(uint8_t headerType, size_t len) { - // check active modem - if(getActiveModem() != RADIOLIB_SX127X_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set requested packet mode - Module* mod = this->getMod(); - int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2); - RADIOLIB_ASSERT(state); - - // set length to register - state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); - RADIOLIB_ASSERT(state); - - // update cached value - SX127x::packetLength = len; - - return(state); -} - int16_t SX1272::configFSK() { // configure common registers int16_t state = SX127x::configFSK(); diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 2689969251..337558ec8b 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -316,7 +316,6 @@ class SX1272: public SX127x { int16_t setBandwidthRaw(uint8_t newBandwidth); int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); int16_t setCodingRateRaw(uint8_t newCodingRate); - int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); int16_t configFSK(); void errataFix(bool rx) override; diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index c768590598..df76e56b48 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -535,11 +535,13 @@ int16_t SX1278::autoLDRO() { } int16_t SX1278::implicitHeader(size_t len) { - return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, len)); + this->implicitHdr = true; + return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, len)); } int16_t SX1278::explicitHeader() { - return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE)); + this->implicitHdr = false; + return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE, 0)); } int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { @@ -559,11 +561,13 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers Module* mod = this->getMod(); if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { + this->implicitHdr = true; state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { + this->implicitHdr = false; state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); @@ -582,27 +586,6 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) { return(state); } -int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) { - // check active modem - if(getActiveModem() != RADIOLIB_SX127X_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set requested packet mode - Module* mod = this->getMod(); - int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0); - RADIOLIB_ASSERT(state); - - // set length to register - state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); - RADIOLIB_ASSERT(state); - - // update cached value - SX127x::packetLength = len; - - return(state); -} - int16_t SX1278::configFSK() { // configure common registers int16_t state = SX127x::configFSK(); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index feb1d09cb8..1fadf64be6 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -328,7 +328,6 @@ class SX1278: public SX127x { int16_t setBandwidthRaw(uint8_t newBandwidth); int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); int16_t setCodingRateRaw(uint8_t newCodingRate); - int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); int16_t configFSK(); void errataFix(bool rx) override; diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6ab426f005..a0c0130d2a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -417,8 +417,9 @@ int16_t SX127x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, Radi state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4); } - // set expected packet length for SF6 - if(this->spreadingFactor == 6) { + // in implicit header mode, use the provided length if it is nonzero + // otherwise we trust the user has previously set the payload length manually + if((this->implicitHdr) && (len != 0)) { state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); this->packetLength = len; } @@ -1211,12 +1212,12 @@ size_t SX127x::getPacketLength(bool update) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { - if(this->spreadingFactor != 6) { - // get packet length for SF7 - SF12 + if(!this->implicitHdr) { + // get packet length for explicit header mode return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES)); } else { - // return the cached value for SF6 + // return the cached value for implicit header mode return(this->packetLength); } @@ -1860,6 +1861,27 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { } } +int16_t SX127x::setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len) { + // check active modem + if(getActiveModem() != RADIOLIB_SX127X_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + Module* mod = this->getMod(); + int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex); + RADIOLIB_ASSERT(state); + + // set length to register + state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update cached value + SX127x::packetLength = len; + + return(state); +} + int16_t SX127x::setLowBatteryThreshold(int8_t level, uint32_t pin) { // check disable if(level < 0) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 92f36451ef..593f27e499 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1249,12 +1249,14 @@ class SX127x: public PhysicalLayer { uint8_t codingRate = 0; bool crcEnabled = false; bool ookEnabled = false; + bool implicitHdr = false; int16_t configFSK(); int16_t getActiveModem(); int16_t setFrequencyRaw(float newFreq); int16_t setBitRateCommon(float br, uint8_t fracRegAddr); float getRSSI(bool packet, bool skipReceive, int16_t offset); + int16_t setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len = 0xFF); #if !RADIOLIB_GODMODE private: From ded508cc253bd96539cee783563891bae4c7ea07 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 15 Dec 2024 15:53:06 +0100 Subject: [PATCH 1380/1848] [SX128x] Use length from startReceive in implicit header mode --- src/modules/SX128x/SX128x.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3d1ce145e2..21f6b21c12 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -589,7 +589,11 @@ int16_t SX128x::startReceive() { } int16_t SX128x::startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { - (void)len; + // in implicit header mode, use the provided length if it is nonzero + // otherwise we trust the user has previously set the payload length manually + if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (len != 0)) { + this->payloadLen = len; + } // check active modem if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { From 75f087b5c2f622d13f9c45fd4a5907f72cf09349 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 15 Dec 2024 15:53:13 +0100 Subject: [PATCH 1381/1848] [SX126x] Use length from startReceive in implicit header mode --- src/modules/SX126x/SX126x.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 7defbbcb00..936756d7e1 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -641,7 +641,12 @@ int16_t SX126x::startReceive() { } int16_t SX126x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { - (void)len; + // in implicit header mode, use the provided length if it is nonzero + // otherwise we trust the user has previously set the payload length manually + if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (len != 0)) { + this->implicitLen = len; + } + int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); RADIOLIB_ASSERT(state); From 5a8ba0003b39c4a2951c86a8b116b11f31ee590e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Dec 2024 08:19:15 +0000 Subject: [PATCH 1382/1848] [SX126x] Fix broken FSK packet params calls (#1350) (#1338) --- src/modules/SX126x/SX126x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 936756d7e1..c08c7e30d3 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -526,7 +526,7 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); // address is taken from the register if(this->addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) { @@ -748,7 +748,7 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, RadioLibIrqFlags_t irqFlags if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); } else { return(RADIOLIB_ERR_UNKNOWN); } From eeff547aa4a248b2da187cd6a6a340810ca56ee7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Dec 2024 18:49:18 +0000 Subject: [PATCH 1383/1848] [SX126x] Fix preamble detector configuration (#1350) --- src/modules/SX126x/SX126x.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c08c7e30d3..49fc2b27b9 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -973,10 +973,13 @@ int16_t SX126x::setPreambleLength(size_t preambleLength) { return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { this->preambleLengthFSK = preambleLength; - this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : - preambleLength >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : - preambleLength >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : - preambleLength > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : + // maximum preamble detector length is limited by sync word length + // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45 + uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK); + this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : + maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : + maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : + maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType)); } @@ -1214,6 +1217,15 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { // update packet parameters this->syncWordLength = len * 8; + + // maximum preamble detector length is limited by sync word length + // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45 + uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK); + this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : + maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : + maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : + maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : + RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); return(state); From 67547615af5b6c0719cbf321c5fba863c2117398 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 16 Dec 2024 19:01:30 +0000 Subject: [PATCH 1384/1848] [SX126x] Added notes about preamble detector to Doxygen (#1350) --- src/modules/SX126x/SX126x.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d1ca5451f7..46d5ba76da 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -823,6 +823,10 @@ class SX126x: public PhysicalLayer { /*! \brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535. \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK). + NOTE: In FSK mode, sync word length limits the preamble detector length + (the number of preamble bits that must be detected to start receiving packet). + For details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45. + Preamble detector length is adjusted automatically each time this method is called. \returns \ref status_codes */ int16_t setPreambleLength(size_t preambleLength) override; @@ -887,6 +891,10 @@ class SX126x: public PhysicalLayer { Can also set LR-FHSS sync word, but its length must be 4 bytes. \param syncWord FSK sync word to be set. \param len FSK sync word length in bytes. + NOTE: In FSK mode, sync word length limits the preamble detector length + (the number of preamble bits that must be detected to start receiving packet). + For details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45. + Preamble detector length is adjusted automatically each time this method is called. \returns \ref status_codes */ int16_t setSyncWord(uint8_t* syncWord, size_t len) override; From 6e3b870317770a38aa58ca55075ca8ee5b86bc13 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 Dec 2024 20:12:19 +0000 Subject: [PATCH 1385/1848] [SX126x] Drop support for FSK address filtering (#1268) --- src/modules/SX126x/SX126x.cpp | 77 ++++------------------------------- src/modules/SX126x/SX126x.h | 3 +- 2 files changed, 10 insertions(+), 70 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 49fc2b27b9..2cf9fb2343 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -74,7 +74,6 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; // CCITT CRC configuration this->preambleLengthFSK = preambleLength; - this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; // set module properties and perform initial setup int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_GFSK); @@ -515,7 +514,7 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { } // maximum packet length is decreased by 1 when address filtering is active - if((this->addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { + if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } @@ -526,13 +525,7 @@ int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType, len); - - // address is taken from the register - if(this->addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) { - RADIOLIB_ASSERT(state); - state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &addr, 1); - } + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, len); } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { return(RADIOLIB_ERR_UNKNOWN); @@ -626,12 +619,6 @@ int16_t SX126x::finishTransmit() { int16_t state = clearIrqStatus(); RADIOLIB_ASSERT(state); - // restore the original node address - if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &this->nodeAddr, 1); - RADIOLIB_ASSERT(state); - } - // set mode to standby to disable transmitter/RF switch return(standby()); } @@ -748,7 +735,7 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, RadioLibIrqFlags_t irqFlags if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); } else { return(RADIOLIB_ERR_UNKNOWN); } @@ -981,7 +968,7 @@ int16_t SX126x::setPreambleLength(size_t preambleLength) { maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; - return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType)); + return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType)); } return(RADIOLIB_ERR_UNKNOWN); @@ -1226,7 +1213,7 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); return(state); @@ -1268,52 +1255,6 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { return(setSyncWord(syncWord, bytesLen)); } -int16_t SX126x::setNodeAddress(uint8_t addr) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // enable address filtering (node only) - this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE; - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); - RADIOLIB_ASSERT(state); - - // set node address - this->nodeAddr = addr; - state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &addr, 1); - - return(state); -} - -int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // enable address filtering (node and broadcast) - this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST; - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); - RADIOLIB_ASSERT(state); - - // set broadcast address - state = writeRegister(RADIOLIB_SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1); - - return(state); -} - -int16_t SX126x::disableAddressFiltering() { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // disable address filtering - this->addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF; - return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening)); -} - int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { // check active modem uint8_t modem = getPacketType(); @@ -1342,7 +1283,7 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // write initial CRC value @@ -1384,7 +1325,7 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { // disable whitening this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); RADIOLIB_ASSERT(state); } else { @@ -1404,7 +1345,7 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); RADIOLIB_ASSERT(state); - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType); + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); RADIOLIB_ASSERT(state); } return(state); @@ -2066,7 +2007,7 @@ int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { } // set requested packet mode - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, mode, len); + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len); RADIOLIB_ASSERT(state); // update cached value diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 46d5ba76da..5fba5a38b6 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1286,10 +1286,9 @@ class SX126x: public PhysicalLayer { bool ldroAuto = true; uint32_t bitRate = 0, frequencyDev = 0; - uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0; + uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeFSK = 0, syncWordLength = 0, whitening = 0, packetType = 0; uint16_t preambleLengthFSK = 0; float rxBandwidthKhz = 0; - uint8_t nodeAddr = 0; float dataRateMeasured = 0; From 8c0e8a6586042e45621de03239ce6033d6ae10bf Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 Dec 2024 20:27:17 +0000 Subject: [PATCH 1386/1848] [SX126x] Remove address filtering from examples (#1268) --- .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index 9bffbeeed0..cc8849da39 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -126,33 +126,4 @@ void loop() { Serial.println(F("[SX1262] Failed to receive packet, code ")); Serial.println(state); } - - // FSK modem has built-in address filtering system - // it can be enabled by setting node address, broadcast - // address, or both - // - // to transmit packet to a particular address, - // use the following methods: - // - // radio.transmit("Hello World!", address); - // radio.startTransmit("Hello World!", address); - - // set node address to 0x02 - state = radio.setNodeAddress(0x02); - // set broadcast address to 0xFF - state = radio.setBroadcastAddress(0xFF); - if (state != RADIOLIB_ERR_NONE) { - Serial.println(F("[SX1262] Unable to set address filter, code ")); - Serial.println(state); - } - - // address filtering can also be disabled - // NOTE: calling this method will also erase previously set - // node and broadcast address - /* - state = radio.disableAddressFiltering(); - if (state != RADIOLIB_ERR_NONE) { - Serial.println(F("Unable to remove address filter, code ")); - } - */ } From 661b36cc4c4caa67c019943405a051b5e32752fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 Dec 2024 21:05:50 +0000 Subject: [PATCH 1387/1848] [SX126x] Suppress unused variable warning --- src/modules/SX126x/SX126x.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2cf9fb2343..1d8c0801b5 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -508,6 +508,8 @@ void SX126x::clearChannelScanAction() { } int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { + (void)addr; + // check packet length if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); From 89424a30253cf7dc4e4d6450132f821895237046 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Dec 2024 07:22:06 +0000 Subject: [PATCH 1388/1848] [LoRaWAN] Remove unused parameter --- src/protocols/LoRaWAN/LoRaWAN.cpp | 8 +- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- src/protocols/M17/M17.cpp | 168 ++++++++++++++++++++++++++++++ src/protocols/M17/M17.h | 98 +++++++++++++++++ 4 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 src/protocols/M17/M17.cpp create mode 100644 src/protocols/M17/M17.h diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 2263d4a8d6..93da73df3f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -307,7 +307,7 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { // setup JoinRequest uplink/downlink frequencies and datarates if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(true); + this->selectChannelPlanDyn(); } else { this->selectChannelPlanFix(); } @@ -761,7 +761,7 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { // in case of dynamic band, reset the channels to clear JoinRequest-specific channels if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(false); + this->selectChannelPlanDyn(); } uint8_t cOcts[5]; @@ -1139,7 +1139,7 @@ void LoRaWANNode::adrBackoff() { } if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(false); // revert to default frequencies + this->selectChannelPlanDyn(); // revert to default frequencies } else { this->selectChannelPlanFix(); // go back to default selected subband } @@ -2962,7 +2962,7 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr } } -void LoRaWANNode::selectChannelPlanDyn(bool joinRequest) { +void LoRaWANNode::selectChannelPlanDyn() { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); size_t num = 0; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index ae942c632c..45bdb4bc40 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1068,7 +1068,7 @@ class LoRaWANNode { // setup uplink/downlink channel data rates and frequencies // for dynamic channels, there is a small set of predefined channels // in case of JoinRequest, add some optional extra frequencies - void selectChannelPlanDyn(bool joinRequest = false); + void selectChannelPlanDyn(); // setup uplink/downlink channel data rates and frequencies // for fixed bands, we only allow one sub-band at a time to be selected diff --git a/src/protocols/M17/M17.cpp b/src/protocols/M17/M17.cpp new file mode 100644 index 0000000000..cc77f55970 --- /dev/null +++ b/src/protocols/M17/M17.cpp @@ -0,0 +1,168 @@ +#include "M17.h" + +#include "../../utils/CRC.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_M17 + +M17Client::M17Client(PhysicalLayer* phy) : FSK4Client(phy) { + phyLayer = phy; +} + +int16_t M17Client::begin(float base, char* addr) { + int16_t state = FSK4Client::begin(base, RADIOLIB_M17_SHIFT_HZ, RADIOLIB_M17_RATE_BAUD); + RADIOLIB_ASSERT(state); + + // FSK4: 0, 1600, 3200, 4800 + // M17: 800, 2400, -800, -2400 + int16_t offsets[] = { 800, 800, -4000, -7200 }; + FSK4Client::setCorrection(offsets); + + this->encodeAddr(addr, this->src); + + /*Module* mod = this->phyLayer->getMod(); + while(true) { + FSK4Client::write(0); + mod->hal->delay(1000); + FSK4Client::write(1); + mod->hal->delay(1000); + FSK4Client::write(2); + mod->hal->delay(1000); + FSK4Client::write(3); + mod->hal->delay(1000); + }*/ + + return(state); +} + +int16_t M17Client::transmit(uint8_t* data, size_t len, char* dst) { + uint8_t lsf[RADIOLIB_M17_LSF_MAXLEN_BYTES_ENCODED] = { 0 }; + size_t lsfLen = encodeLsf(dst, RADIOLIB_M17_LSF_MODE_PACKET | RADIOLIB_M17_LSF_DATA_TYPE_DATA | RADIOLIB_M17_LSF_ENC_NONE, lsf); + + // send preamble + for(size_t i = 0; i < RADIOLIB_M17_PRE_LEN_BYTES; i++) { + FSK4Client::write(RADIOLIB_M17_PRE_PATTERN_LSF); + } + + // send sync burst + FSK4Client::write(RADIOLIB_M17_SYNC_BURST_LSF >> 8); + FSK4Client::write(RADIOLIB_M17_SYNC_BURST_LSF & 0xFF); + + // send payload + FSK4Client::write(lsf, lsfLen); + + // dummy data + /*for(size_t i = 0; i < 200; i++) { + FSK4Client::write(0x00); + FSK4Client::write(0x55); + FSK4Client::write(0xAA); + FSK4Client::write(0xFF); + }*/ + + // send EOT + for(size_t i = 0; i < RADIOLIB_M17_EOT_LEN_BYTES / 2; i++) { + FSK4Client::write(RADIOLIB_M17_EOT_PATTERN >> 8); + FSK4Client::write(RADIOLIB_M17_EOT_PATTERN & 0xFF); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t M17Client::encodeAddr(char* in, uint8_t* out) { + //RADIOLIB_ASSERT_PTR(in); + //RADIOLIB_ASSERT_PTR(out); + + // TODO check max len and encodable/reserved addresses + uint64_t res = 0; + size_t len = strlen(in); + for(size_t i = 0; i < len; i++) { + uint8_t val = 0; + char c = in[i]; + if((c >= 'A') && (c <= 'Z')) { + val = c - 'A' + 1; + } else if((c >= '0') && (c <= '9')) { + val = c - '0' + 27; + } else if(c == '-') { + val = 37; + } else if(c == '/') { + val = 38; + } else if(c == '.') { + val = 39; + } else { + return(RADIOLIB_ERR_INVALID_CALLSIGN); + } + res += val * pow(40, i); + } + + // set the output + for(size_t i = 0; i < RADIOLIB_M17_ADDR_LEN; i++) { + out[i] = (res >> (i * 8)) & 0xFF; + } + + return(RADIOLIB_ERR_NONE); +} + +size_t M17Client::encodeLsf(char* dst, uint16_t type, uint8_t* out, uint8_t* meta, size_t metaLen) { + if(!out) { + return(0); + } + uint8_t* framePtr = out; + + // encode destination address + this->encodeAddr(dst, framePtr); + framePtr += RADIOLIB_M17_ADDR_LEN; + + // copy the source address + memcpy(framePtr, this->src, RADIOLIB_M17_ADDR_LEN); + framePtr += RADIOLIB_M17_ADDR_LEN; + + // set the type bits + (*framePtr++) = (type & 0xFF00) >> 8; + (*framePtr++) = type & 0x00FF; + + // TODO check meta + metaLen valid + if(meta) { + memcpy(framePtr, meta, metaLen); + } + framePtr += 14; + + // add CRC + RadioLibCRCInstance.size = 16; + RadioLibCRCInstance.poly = 0x5935; + RadioLibCRCInstance.init = 0xFFFF; + RadioLibCRCInstance.out = 0x0000; + uint16_t crc16 = RadioLibCRCInstance.checksum(out, 240/8 - sizeof(uint16_t)); + (*framePtr++) = (crc16 & 0xFF00) >> 8; + (*framePtr++) = crc16 & 0x00FF; + + // TODO add flush bits + framePtr++; + + // TODO convolutional encoding + framePtr+=30; + + // TODO puncturing + framePtr-=15; + + // TODO interleaving + + // randomize + size_t len = framePtr - out; + randomize(out, len); + return(len); +} + +void M17Client::randomize(uint8_t* buff, size_t len) { + if(!buff) { + return; + } + + for(size_t i = 0; i < len; i++) { + buff[i] ^= m17_randomizer[this->randIndex++]; + this->randIndex %= RADIOLIB_M17_RANDOMIZER_LEN; + } +} + +#endif diff --git a/src/protocols/M17/M17.h b/src/protocols/M17/M17.h new file mode 100644 index 0000000000..befbe693f4 --- /dev/null +++ b/src/protocols/M17/M17.h @@ -0,0 +1,98 @@ +#if !defined(_RADIOLIB_M17_H) +#define _RADIOLIB_M17_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_M17 + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../FSK4/FSK4.h" + +// basic M17 properties +#define RADIOLIB_M17_SHIFT_HZ (1600) +#define RADIOLIB_M17_RATE_BAUD (4800) + +// preamble +#define RADIOLIB_M17_PRE_LEN_BYTES (192/4) +#define RADIOLIB_M17_PRE_PATTERN_LSF (0x77) +#define RADIOLIB_M17_PRE_PATTERN_BERT (0xDD) + +// end-of-transmission +#define RADIOLIB_M17_EOT_LEN_BYTES (192/4) +#define RADIOLIB_M17_EOT_PATTERN (0x555D) + +// sync-burst +#define RADIOLIB_M17_SYNC_BURST_LSF (0x55F7) +#define RADIOLIB_M17_SYNC_BURST_BERT (0xDF55) +#define RADIOLIB_M17_SYNC_BURST_STREAM (0xFF5D) +#define RADIOLIB_M17_SYNC_BURST_PACKET (0x75FF) + +// link setup frame (LFS) bit fields MSB LSB DESCRIPTION +#define RADIOLIB_M17_LSF_MODE_PACKET (0x00UL << 0) // 0 0 LSF packet/stream indicator: packet +#define RADIOLIB_M17_LSF_MODE_STREAM (0x01UL << 0) // 0 0 stream +#define RADIOLIB_M17_LSF_DATA_TYPE_DATA (0x01UL << 1) // 2 1 data type: data +#define RADIOLIB_M17_LSF_DATA_TYPE_VOICE (0x02UL << 1) // 2 1 voice +#define RADIOLIB_M17_LSF_DATA_TYPE_VOICE_DATA (0x03UL << 1) // 2 1 data + voice +#define RADIOLIB_M17_LSF_ENC_NONE (0x00UL << 3) // 4 3 encryption: none +#define RADIOLIB_M17_LSF_ENC_SCRAMBLER (0x01UL << 3) // 4 3 scrambler +#define RADIOLIB_M17_LSF_ENC_AES (0x02UL << 3) // 4 3 AES +#define RADIOLIB_M17_LSF_ENC_OTHER (0x03UL << 3) // 4 3 other +#define RADIOLIB_M17_LSF_AES_LEN_128 (0x00UL << 5) // 6 5 encryption key length: 128-bit +#define RADIOLIB_M17_LSF_AES_LEN_192 (0x01UL << 5) // 6 5 192-bit +#define RADIOLIB_M17_LSF_AES_LEN_256 (0x02UL << 5) // 6 5 256-bit +#define RADIOLIB_M17_LSF_SCRAMLER_LEN_8 (0x00UL << 5) // 6 5 scrambler length: 8-bit +#define RADIOLIB_M17_LSF_SCRAMLER_LEN_16 (0x01UL << 5) // 6 5 16-bit +#define RADIOLIB_M17_LSF_SCRAMLER_LEN_24 (0x02UL << 5) // 6 5 24-bit + +// maximum length of LSF frame before puncturing +#define RADIOLIB_M17_LSF_MAXLEN_BYTES_ENCODED (368/8) + +#define RADIOLIB_M17_ADDR_LEN (6) + +#define RADIOLIB_M17_RANDOMIZER_LEN (46) + +static const uint8_t m17_randomizer[RADIOLIB_M17_RANDOMIZER_LEN] = { + 0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, + 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, + 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8, 0x6E, + 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, + 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, + 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3 +}; + +/*! + \class M17Client + \brief Client for M17 transmissions. +*/ +class M17Client: public FSK4Client { + public: + /*! + \brief Constructor for 4-FSK mode. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit M17Client(PhysicalLayer* phy); + + /*! + \brief Initialization method. + \param base Base (space) frequency to be used in MHz. + \returns \ref status_codes + */ + int16_t begin(float base, char* addr); + + int16_t transmit(uint8_t* data, size_t len, char* dst); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + uint8_t src[RADIOLIB_M17_ADDR_LEN] = { 0 }; + uint8_t randIndex = 0; + + int16_t encodeAddr(char* in, uint8_t* out); + size_t encodeLsf(char* dst, uint16_t type, uint8_t* out, uint8_t* meta = NULL, size_t metaLen = 0); + void randomize(uint8_t* buff, size_t len); +}; + +#endif + +#endif \ No newline at end of file From 02fe9f3119f9c4aaf5495a06052d74d987fb430b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Dec 2024 08:28:06 +0100 Subject: [PATCH 1389/1848] Remove dev files --- src/protocols/M17/M17.cpp | 168 -------------------------------------- src/protocols/M17/M17.h | 98 ---------------------- 2 files changed, 266 deletions(-) delete mode 100644 src/protocols/M17/M17.cpp delete mode 100644 src/protocols/M17/M17.h diff --git a/src/protocols/M17/M17.cpp b/src/protocols/M17/M17.cpp deleted file mode 100644 index cc77f55970..0000000000 --- a/src/protocols/M17/M17.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "M17.h" - -#include "../../utils/CRC.h" - -#include -#include - -#if !RADIOLIB_EXCLUDE_M17 - -M17Client::M17Client(PhysicalLayer* phy) : FSK4Client(phy) { - phyLayer = phy; -} - -int16_t M17Client::begin(float base, char* addr) { - int16_t state = FSK4Client::begin(base, RADIOLIB_M17_SHIFT_HZ, RADIOLIB_M17_RATE_BAUD); - RADIOLIB_ASSERT(state); - - // FSK4: 0, 1600, 3200, 4800 - // M17: 800, 2400, -800, -2400 - int16_t offsets[] = { 800, 800, -4000, -7200 }; - FSK4Client::setCorrection(offsets); - - this->encodeAddr(addr, this->src); - - /*Module* mod = this->phyLayer->getMod(); - while(true) { - FSK4Client::write(0); - mod->hal->delay(1000); - FSK4Client::write(1); - mod->hal->delay(1000); - FSK4Client::write(2); - mod->hal->delay(1000); - FSK4Client::write(3); - mod->hal->delay(1000); - }*/ - - return(state); -} - -int16_t M17Client::transmit(uint8_t* data, size_t len, char* dst) { - uint8_t lsf[RADIOLIB_M17_LSF_MAXLEN_BYTES_ENCODED] = { 0 }; - size_t lsfLen = encodeLsf(dst, RADIOLIB_M17_LSF_MODE_PACKET | RADIOLIB_M17_LSF_DATA_TYPE_DATA | RADIOLIB_M17_LSF_ENC_NONE, lsf); - - // send preamble - for(size_t i = 0; i < RADIOLIB_M17_PRE_LEN_BYTES; i++) { - FSK4Client::write(RADIOLIB_M17_PRE_PATTERN_LSF); - } - - // send sync burst - FSK4Client::write(RADIOLIB_M17_SYNC_BURST_LSF >> 8); - FSK4Client::write(RADIOLIB_M17_SYNC_BURST_LSF & 0xFF); - - // send payload - FSK4Client::write(lsf, lsfLen); - - // dummy data - /*for(size_t i = 0; i < 200; i++) { - FSK4Client::write(0x00); - FSK4Client::write(0x55); - FSK4Client::write(0xAA); - FSK4Client::write(0xFF); - }*/ - - // send EOT - for(size_t i = 0; i < RADIOLIB_M17_EOT_LEN_BYTES / 2; i++) { - FSK4Client::write(RADIOLIB_M17_EOT_PATTERN >> 8); - FSK4Client::write(RADIOLIB_M17_EOT_PATTERN & 0xFF); - } - - return(RADIOLIB_ERR_NONE); -} - -int16_t M17Client::encodeAddr(char* in, uint8_t* out) { - //RADIOLIB_ASSERT_PTR(in); - //RADIOLIB_ASSERT_PTR(out); - - // TODO check max len and encodable/reserved addresses - uint64_t res = 0; - size_t len = strlen(in); - for(size_t i = 0; i < len; i++) { - uint8_t val = 0; - char c = in[i]; - if((c >= 'A') && (c <= 'Z')) { - val = c - 'A' + 1; - } else if((c >= '0') && (c <= '9')) { - val = c - '0' + 27; - } else if(c == '-') { - val = 37; - } else if(c == '/') { - val = 38; - } else if(c == '.') { - val = 39; - } else { - return(RADIOLIB_ERR_INVALID_CALLSIGN); - } - res += val * pow(40, i); - } - - // set the output - for(size_t i = 0; i < RADIOLIB_M17_ADDR_LEN; i++) { - out[i] = (res >> (i * 8)) & 0xFF; - } - - return(RADIOLIB_ERR_NONE); -} - -size_t M17Client::encodeLsf(char* dst, uint16_t type, uint8_t* out, uint8_t* meta, size_t metaLen) { - if(!out) { - return(0); - } - uint8_t* framePtr = out; - - // encode destination address - this->encodeAddr(dst, framePtr); - framePtr += RADIOLIB_M17_ADDR_LEN; - - // copy the source address - memcpy(framePtr, this->src, RADIOLIB_M17_ADDR_LEN); - framePtr += RADIOLIB_M17_ADDR_LEN; - - // set the type bits - (*framePtr++) = (type & 0xFF00) >> 8; - (*framePtr++) = type & 0x00FF; - - // TODO check meta + metaLen valid - if(meta) { - memcpy(framePtr, meta, metaLen); - } - framePtr += 14; - - // add CRC - RadioLibCRCInstance.size = 16; - RadioLibCRCInstance.poly = 0x5935; - RadioLibCRCInstance.init = 0xFFFF; - RadioLibCRCInstance.out = 0x0000; - uint16_t crc16 = RadioLibCRCInstance.checksum(out, 240/8 - sizeof(uint16_t)); - (*framePtr++) = (crc16 & 0xFF00) >> 8; - (*framePtr++) = crc16 & 0x00FF; - - // TODO add flush bits - framePtr++; - - // TODO convolutional encoding - framePtr+=30; - - // TODO puncturing - framePtr-=15; - - // TODO interleaving - - // randomize - size_t len = framePtr - out; - randomize(out, len); - return(len); -} - -void M17Client::randomize(uint8_t* buff, size_t len) { - if(!buff) { - return; - } - - for(size_t i = 0; i < len; i++) { - buff[i] ^= m17_randomizer[this->randIndex++]; - this->randIndex %= RADIOLIB_M17_RANDOMIZER_LEN; - } -} - -#endif diff --git a/src/protocols/M17/M17.h b/src/protocols/M17/M17.h deleted file mode 100644 index befbe693f4..0000000000 --- a/src/protocols/M17/M17.h +++ /dev/null @@ -1,98 +0,0 @@ -#if !defined(_RADIOLIB_M17_H) -#define _RADIOLIB_M17_H - -#include "../../TypeDef.h" - -#if !RADIOLIB_EXCLUDE_M17 - -#include "../PhysicalLayer/PhysicalLayer.h" -#include "../FSK4/FSK4.h" - -// basic M17 properties -#define RADIOLIB_M17_SHIFT_HZ (1600) -#define RADIOLIB_M17_RATE_BAUD (4800) - -// preamble -#define RADIOLIB_M17_PRE_LEN_BYTES (192/4) -#define RADIOLIB_M17_PRE_PATTERN_LSF (0x77) -#define RADIOLIB_M17_PRE_PATTERN_BERT (0xDD) - -// end-of-transmission -#define RADIOLIB_M17_EOT_LEN_BYTES (192/4) -#define RADIOLIB_M17_EOT_PATTERN (0x555D) - -// sync-burst -#define RADIOLIB_M17_SYNC_BURST_LSF (0x55F7) -#define RADIOLIB_M17_SYNC_BURST_BERT (0xDF55) -#define RADIOLIB_M17_SYNC_BURST_STREAM (0xFF5D) -#define RADIOLIB_M17_SYNC_BURST_PACKET (0x75FF) - -// link setup frame (LFS) bit fields MSB LSB DESCRIPTION -#define RADIOLIB_M17_LSF_MODE_PACKET (0x00UL << 0) // 0 0 LSF packet/stream indicator: packet -#define RADIOLIB_M17_LSF_MODE_STREAM (0x01UL << 0) // 0 0 stream -#define RADIOLIB_M17_LSF_DATA_TYPE_DATA (0x01UL << 1) // 2 1 data type: data -#define RADIOLIB_M17_LSF_DATA_TYPE_VOICE (0x02UL << 1) // 2 1 voice -#define RADIOLIB_M17_LSF_DATA_TYPE_VOICE_DATA (0x03UL << 1) // 2 1 data + voice -#define RADIOLIB_M17_LSF_ENC_NONE (0x00UL << 3) // 4 3 encryption: none -#define RADIOLIB_M17_LSF_ENC_SCRAMBLER (0x01UL << 3) // 4 3 scrambler -#define RADIOLIB_M17_LSF_ENC_AES (0x02UL << 3) // 4 3 AES -#define RADIOLIB_M17_LSF_ENC_OTHER (0x03UL << 3) // 4 3 other -#define RADIOLIB_M17_LSF_AES_LEN_128 (0x00UL << 5) // 6 5 encryption key length: 128-bit -#define RADIOLIB_M17_LSF_AES_LEN_192 (0x01UL << 5) // 6 5 192-bit -#define RADIOLIB_M17_LSF_AES_LEN_256 (0x02UL << 5) // 6 5 256-bit -#define RADIOLIB_M17_LSF_SCRAMLER_LEN_8 (0x00UL << 5) // 6 5 scrambler length: 8-bit -#define RADIOLIB_M17_LSF_SCRAMLER_LEN_16 (0x01UL << 5) // 6 5 16-bit -#define RADIOLIB_M17_LSF_SCRAMLER_LEN_24 (0x02UL << 5) // 6 5 24-bit - -// maximum length of LSF frame before puncturing -#define RADIOLIB_M17_LSF_MAXLEN_BYTES_ENCODED (368/8) - -#define RADIOLIB_M17_ADDR_LEN (6) - -#define RADIOLIB_M17_RANDOMIZER_LEN (46) - -static const uint8_t m17_randomizer[RADIOLIB_M17_RANDOMIZER_LEN] = { - 0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, - 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, - 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8, 0x6E, - 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, - 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, - 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3 -}; - -/*! - \class M17Client - \brief Client for M17 transmissions. -*/ -class M17Client: public FSK4Client { - public: - /*! - \brief Constructor for 4-FSK mode. - \param phy Pointer to the wireless module providing PhysicalLayer communication. - */ - explicit M17Client(PhysicalLayer* phy); - - /*! - \brief Initialization method. - \param base Base (space) frequency to be used in MHz. - \returns \ref status_codes - */ - int16_t begin(float base, char* addr); - - int16_t transmit(uint8_t* data, size_t len, char* dst); - -#if !RADIOLIB_GODMODE - private: -#endif - PhysicalLayer* phyLayer; - uint8_t src[RADIOLIB_M17_ADDR_LEN] = { 0 }; - uint8_t randIndex = 0; - - int16_t encodeAddr(char* in, uint8_t* out); - size_t encodeLsf(char* dst, uint16_t type, uint8_t* out, uint8_t* meta = NULL, size_t metaLen = 0); - void randomize(uint8_t* buff, size_t len); -}; - -#endif - -#endif \ No newline at end of file From c2b44d2552a6d3b5e54f173c9db67e029922086d Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:48:03 +0100 Subject: [PATCH 1390/1848] Add FSK to supported LoRaWAN modulations --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebbc7ecac6..92ffe4475e 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x -* [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules: +* [__LoRaWAN__](https://lora-alliance.org/) using LoRa and FSK for modules: SX127x, RFM9x, SX126x, LR11x0 and SX128x ### Supported Arduino platforms: From 6622a0ac9954067304bbb3198bc4697dddeda533 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 19 Dec 2024 14:18:20 +0100 Subject: [PATCH 1391/1848] Bump version to 7.1.1 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 9f175c3bc0..e77395aa28 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.1.0" +version: "7.1.1" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 9c27984d18..71a6512893 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.1.0", + "version": "7.1.1", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 26e9ffef47..31518c460b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.1.0 +version=7.1.1 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index faae44da0d..ec31bc2595 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -583,7 +583,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 #define RADIOLIB_VERSION_MINOR 1 -#define RADIOLIB_VERSION_PATCH 0 +#define RADIOLIB_VERSION_PATCH 1 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From afa5da7fd65f7de9678aad504d84f955360adf5c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 20 Dec 2024 13:52:09 +0100 Subject: [PATCH 1392/1848] [CI] Add release workflow --- .github/workflows/release.yml | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..23a2e8fb29 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: "Release" + +on: workflow_dispatch + +jobs: + release: + name: Release RadioLib update + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Checkout latest tag + run: git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) + + - name: Setup Python + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install PlatformIO and ESP-IDF + run: | + pip install --upgrade platformio + pip install --upgrade idf-component-manager + + - name: PlatformIO publish + env: + PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }} + run: pio pkg publish --no-interactive + + - name: ESP-IDF publish + env: + IDF_COMPONENT_API_TOKEN: ${{ secrets.IDF_COMPONENT_API_TOKEN }} + run: compote component upload --name TestLib --namespace jgromes From c37015ef9467404d47261f8f4e737aadc8049009 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 20 Dec 2024 13:53:26 +0100 Subject: [PATCH 1393/1848] [CI] Fix typo --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 23a2e8fb29..6367c9ae5c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: run: git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) - name: Setup Python - - uses: actions/setup-python@v4 + uses: actions/setup-python@v4 with: python-version: '3.9' From 9bff1582bdab7f55a7a320e88e9757a6ff18cb4f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Dec 2024 16:25:52 +0000 Subject: [PATCH 1394/1848] [LR11x0] Use dummy SPI transfer for wakeup --- src/modules/LR11x0/LR11x0.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 7b988371d5..a360b935de 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -356,10 +356,9 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) { this->mod->setRfSwitchState(Module::MODE_IDLE); if(wakeup) { - // pull NSS low for a while to wake up - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - this->mod->hal->delay(1); - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + // send a NOP command - this pulls the NSS low to exit the sleep mode, + // while preventing interference with possible other SPI transactions + (void)this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false); } uint8_t buff[] = { mode }; From ff387e93ad75af01fbe211e3dee23474ddd5f85e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Dec 2024 16:25:59 +0000 Subject: [PATCH 1395/1848] [SX128x] Use dummy SPI transfer for wakeup --- src/modules/SX128x/SX128x.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 21f6b21c12..a86d82abce 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -480,8 +480,9 @@ int16_t SX128x::standby(uint8_t mode, bool wakeup) { this->mod->setRfSwitchState(Module::MODE_IDLE); if(wakeup) { - // pull NSS low to wake up - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + // send a NOP command - this pulls the NSS low to exit the sleep mode, + // while preventing interference with possible other SPI transactions + (void)this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false); } uint8_t data[] = { mode }; From b2b4c9e0f73bd9d5a435b291ee27574ee9c2f69f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Dec 2024 16:26:24 +0000 Subject: [PATCH 1396/1848] [SX126x] Use dummy SPI transfer for wakeup (#1364) --- src/modules/SX126x/SX126x.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1d8c0801b5..31aa2aa3d3 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -467,8 +467,10 @@ int16_t SX126x::standby(uint8_t mode, bool wakeup) { this->mod->setRfSwitchState(Module::MODE_IDLE); if(wakeup) { - // pull NSS low to wake up - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + // send a NOP command - this pulls the NSS low to exit the sleep mode, + // while preventing interference with possible other SPI transactions + // see https://github.com/jgromes/RadioLib/discussions/1364 + (void)this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false); } uint8_t data[] = { mode }; From af6de6a0e00bfba2450a861c260fe791cc56eccc Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Dec 2024 20:41:37 +0100 Subject: [PATCH 1397/1848] [CI] Fix library name in release CI --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6367c9ae5c..c8ce82d0e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,4 +34,4 @@ jobs: - name: ESP-IDF publish env: IDF_COMPONENT_API_TOKEN: ${{ secrets.IDF_COMPONENT_API_TOKEN }} - run: compote component upload --name TestLib --namespace jgromes + run: compote component upload --name RadioLib --namespace jgromes From 8e35b14faeafe3c82b46cb8d6ec3f89ec75796db Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Dec 2024 09:33:53 +0100 Subject: [PATCH 1398/1848] [nRF24] Use Module SPI transfer stream --- src/modules/nRF24/nRF24.cpp | 38 +------------------------------------ 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index deafef27ed..0218ddd7a1 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -615,43 +615,7 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { } void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { - // prepare the buffers - size_t buffLen = 1 + numBytes; - #if RADIOLIB_STATIC_ONLY - uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; - uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - uint8_t* buffOut = new uint8_t[buffLen]; - uint8_t* buffIn = new uint8_t[buffLen]; - #endif - uint8_t* buffOutPtr = buffOut; - - // copy the command - *(buffOutPtr++) = cmd; - - // copy the data - if(write) { - memcpy(buffOutPtr, dataOut, numBytes); - } else { - memset(buffOutPtr, 0x00, numBytes); - } - - // do the transfer - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - this->mod->hal->spiBeginTransaction(); - this->mod->hal->spiTransfer(buffOut, buffLen, buffIn); - this->mod->hal->spiEndTransaction(); - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); - - // copy the data - if(!write) { - memcpy(dataIn, &buffIn[1], numBytes); - } - - #if !RADIOLIB_STATIC_ONLY - delete[] buffOut; - delete[] buffIn; - #endif + (void)this->mod->SPItransferStream(&cmd, 1, write, dataOut, dataIn, numBytes, false); } #endif From c7fb0653108d83e01badc322f651945207302307 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Dec 2024 09:46:38 +0100 Subject: [PATCH 1399/1848] [CC1101] Simplify reset sequence --- src/modules/CC1101/CC1101.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 727d37e7bc..2d5f27ecae 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -19,13 +19,7 @@ int16_t CC1101::beginFSK4(float freq, float br, float freqDev, float rxBw, int8_ } void CC1101::reset() { - // this is the manual power-on-reset sequence - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - this->mod->hal->delayMicroseconds(5); - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); - this->mod->hal->delayMicroseconds(40); - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - this->mod->hal->delay(10); + // just send the command, the reset sequence as described in datasheet seems unnecessary in our usage SPIsendCommand(RADIOLIB_CC1101_CMD_RESET); } From 60a093775a93894e36cec36afc843663ceaec76b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Dec 2024 10:03:13 +0100 Subject: [PATCH 1400/1848] [CC1101] Use Module SPI transfer stream --- src/modules/CC1101/CC1101.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 2d5f27ecae..b91b949f71 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1160,21 +1160,7 @@ void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { } void CC1101::SPIsendCommand(uint8_t cmd) { - // pull NSS low - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - - // start transfer - this->mod->hal->spiBeginTransaction(); - - // send the command byte - uint8_t status = 0; - this->mod->hal->spiTransfer(&cmd, 1, &status); - - // stop transfer - this->mod->hal->spiEndTransaction(); - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); - RADIOLIB_DEBUG_SPI_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status); - (void)status; + this->mod->SPItransferStream(&cmd, 1, true, NULL, NULL, 0, false); } #endif From 92b687821ff4e6c358d866f84566f66672ab02b8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Dec 2024 10:03:42 +0100 Subject: [PATCH 1401/1848] [MOD] Remove getCs method (#1364) --- src/Module.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Module.h b/src/Module.h index 946c42e4d7..93c233e788 100644 --- a/src/Module.h +++ b/src/Module.h @@ -382,12 +382,9 @@ class Module { int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio); // pin number access methods - - /*! - \brief Access method to get the pin number of SPI chip select. - \returns Pin number of SPI chip select configured in the constructor. - */ - uint32_t getCs() const { return(csPin); } + // getCs is omitted on purpose, as it can interfere when accessing the SPI in a concurrent environment + // so it is considered to be part of the SPI pins and hence not accessible from outside + // see https://github.com/jgromes/RadioLib/discussions/1364 /*! \brief Access method to get the pin number of interrupt/GPIO. From bd4ede2fb782e30c89e44ff52b7e5137f010a1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Wed, 1 Jan 2025 14:14:08 +0100 Subject: [PATCH 1402/1848] [CI] Add size metrics (#1367) * [CI] Add CI scripts, save metrics on build * Fix token name * Fix path * Pass size files via artifacts * Fix path to artifacts * Fix git hash in artifact filename * Fix git hash * Fix artifact name * Fix artifact path * Avoid filenames with colons * Fix artifact paths * Remove incorrect cd * Add missing cd * Fix paths in second repo * More path fixing * Fix artifacts repo name * Remove path from example filename in output * Add hash to commit message * Fix typo * Fix artifact commit message * Move git hash * Use GITHUB_SHA variable * Drop markdown format --------- Co-authored-by: jgromes --- .github/workflows/main.yml | 69 ++++++++++++++++++++++---------- extras/test/ci/build_arduino.sh | 13 ++++++ extras/test/ci/build_examples.sh | 41 +++++++++++++++++++ extras/test/ci/parse_size.sh | 24 +++++++++++ 4 files changed, 126 insertions(+), 21 deletions(-) create mode 100755 extras/test/ci/build_arduino.sh create mode 100755 extras/test/ci/build_examples.sh create mode 100755 extras/test/ci/parse_size.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 963e4eb333..7e7e374bc0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -180,28 +180,55 @@ jobs: if: ${{ env.run-build == 'true' }} run: | - for example in $(find $PWD/examples -name '*.ino' | sort); do - # check whether to skip this sketch - if [ ! -z '${{ steps.prep.outputs.skip-pattern }}' ] && [[ ${example} =~ ${{ steps.prep.outputs.skip-pattern }} ]]; then - # skip sketch - echo -e "\n\033[1;33mSkipped ${example##*/} (matched with ${{ steps.prep.outputs.skip-pattern }})\033[0m"; - else - # apply special flags for LoRaWAN - if [[ ${example} =~ "LoRaWAN" ]]; then - flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1" - fi + cd $PWD/extras/test/ci + ./build_examples.sh ${{ matrix.id }} "${{ steps.prep.outputs.skip-pattern }}" ${{ steps.prep.outputs.options }} + + - name: Parse sizes + if: ${{ env.run-build == 'true' }} + run: + | + cd $PWD/extras/test/ci + ./parse_size.sh ${{ matrix.id }} + + - name: Extract short commit hash + id: short-hash + run: echo "::set-output name=short_sha::$(git rev-parse --short HEAD)" + + - name: Upload size report as artifact + uses: actions/upload-artifact@v3 + with: + name: size-file-${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }} + path: extras/test/ci/size_${{ steps.short-hash.outputs.short_sha }}_${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}.csv - # build sketch - echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; - arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.id }}${{ steps.prep.outputs.options }} --build-property compiler.cpp.extra_flags="$flags" $example --warnings=${{ steps.prep.outputs.warnings }} - if [ $? -ne 0 ]; then - echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; - exit 1; - else - echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n"; - fi - fi - done + metrics: + runs-on: ubuntu-latest + needs: build + steps: + - name: Clone artifact repo + run: + | + cd $PWD/.. + git clone https://${{ github.actor }}:${{ secrets.ACTIONS_METRICS_PUSH_TOKEN }}@github.com/radiolib-org/artifacts.git + cd artifacts + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + + - name: Download size artifacts + uses: actions/download-artifact@v3 + with: + path: aggregated-sizes + + - name: Push size files + run: + | + ls -R aggregated-sizes + mkdir -p $PWD/../artifacts/radiolib-ci/l0 + cp aggregated-sizes/*/size_*.csv $PWD/../artifacts/radiolib-ci/l0/. + cd $PWD/../artifacts/radiolib-ci + git add . + COMMIT_URL="https://github.com/jgromes/RadioLib/commit/$GITHUB_SHA" + git commit -m "Push artifacts from $COMMIT_URL" + git push origin main esp-build: runs-on: ubuntu-latest diff --git a/extras/test/ci/build_arduino.sh b/extras/test/ci/build_arduino.sh new file mode 100755 index 0000000000..1e46c10009 --- /dev/null +++ b/extras/test/ci/build_arduino.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +board=$1 +sketch=$2 +flags=$3 +warnings="all" + +arduino-cli compile \ + --libraries ../../../../ \ + --fqbn $board \ + --build-property compiler.cpp.extra_flags="$flags" \ + --warnings=$warnings \ + $sketch --export-binaries diff --git a/extras/test/ci/build_examples.sh b/extras/test/ci/build_examples.sh new file mode 100755 index 0000000000..44bfb9c375 --- /dev/null +++ b/extras/test/ci/build_examples.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +#board=arduino:avr:mega +board="$1" +#skip="(STM32WL|LR11x0_Firmware_Update|NonArduino)" +skip="$2" +#options="" +options="$3" + +# file for saving the compiled binary size reports +size_file="size_$board.txt" +rm -f $size_file + +path="../../../examples" +for example in $(find $path -name '*.ino' | sort); do + # check whether to skip this sketch + if [ ! -z '$skip' ] && [[ ${example} =~ ${skip} ]]; then + # skip sketch + echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $skip)\033[0m"; + else + # apply special flags for LoRaWAN + if [[ ${example} =~ "LoRaWAN" ]]; then + flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1" + fi + + # build sketch + echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; + board_opts=$board$options + ./build_arduino.sh $board_opts $example "$flags" + if [ $? -ne 0 ]; then + echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; + exit 1; + else + echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n"; + dir="$(dirname -- "$example")" + file="$(basename -- "$example")" + size="$(size $dir/build/*/$file.elf)" + echo $size >> $size_file + fi + fi +done diff --git a/extras/test/ci/parse_size.sh b/extras/test/ci/parse_size.sh new file mode 100755 index 0000000000..679a3f9c7f --- /dev/null +++ b/extras/test/ci/parse_size.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +board=$1 +hash=$(git rev-parse --short HEAD) + +in_file="size_$board.txt" +out_file="size_${hash}_${board//:/-}.csv" +rm -f $out_file + +# write the header +echo "text,data,bss,dec,hex,filename" > "$out_file" + +# convert to CSV +awk 'NR > 1 { + split($12, path_parts, "/"); + filename_with_ext = path_parts[length(path_parts)]; + split(filename_with_ext, filename_parts, "."); + filename = filename_parts[1]; + print $7 "," $8 "," $9 "," $10 "," $11 "," filename +}' "$in_file" >> "$out_file" + +# remove input file +rm -f $in_file + From 680e88c7394a103e1fe9f1b1fe057e36a2c54d3d Mon Sep 17 00:00:00 2001 From: CrispyAlice2 <73314488+CrispyAlice2@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:11:29 -0600 Subject: [PATCH 1403/1848] Fix frequency issue on SX127x (#1368) (#1369) * Fix frequency issue on SX127x (#1368) * Add force option to SPIsetRegValue * Fix indent --- src/Module.cpp | 4 ++-- src/Module.h | 3 ++- src/modules/SX127x/SX127x.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 1f83b7fbde..cd5ddc6815 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -56,7 +56,7 @@ int16_t Module::SPIgetRegValue(uint32_t reg, uint8_t msb, uint8_t lsb) { return(maskedValue); } -int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) { +int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask, bool force) { if((msb > 7) || (lsb > 7) || (lsb > msb)) { return(RADIOLIB_ERR_INVALID_BIT_RANGE); } @@ -66,7 +66,7 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb))); // check if we actually need to update the register - if((currentValue & mask) == (value & mask)) { + if((currentValue & mask) == (value & mask) && !force) { return(RADIOLIB_ERR_NONE); } diff --git a/src/Module.h b/src/Module.h index 93c233e788..328a7f5c1d 100644 --- a/src/Module.h +++ b/src/Module.h @@ -272,9 +272,10 @@ class Module { \param lsb Least significant bit of the register variable. Bits below this one will not be affected by the write operation. \param checkInterval Number of milliseconds between register writing and verification reading. Some registers need up to 10ms to process the change. \param checkMask Mask of bits to check, only bits set to 1 will be verified. + \param force Write new value even if the old value is the same. \returns \ref status_codes */ - int16_t SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF); + int16_t SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF, bool force = false); /*! \brief SPI burst read method. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index a0c0130d2a..9774b3a4c3 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1202,9 +1202,10 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; // write registers + // lsb needs to be written no matter what in order for the module to update the frequency state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF, 7U, 0U, 2U, 0xFF, true); return(state); } From 7141d261be4c4e653040c5535fe4f193d9da4d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Fri, 3 Jan 2025 19:27:13 +0100 Subject: [PATCH 1404/1848] [CI] Use SSH deploy key for metrics push (#1371) Co-authored-by: jgromes --- .github/workflows/main.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7e7e374bc0..dd7ee598c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -204,11 +204,18 @@ jobs: runs-on: ubuntu-latest needs: build steps: + - name: Set up SSH + run: | + mkdir -p ~/.ssh + echo "${{ secrets.ACTIONS_METRICS_DEPLOY_KEY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan github.com >> ~/.ssh/known_hosts + - name: Clone artifact repo run: | cd $PWD/.. - git clone https://${{ github.actor }}:${{ secrets.ACTIONS_METRICS_PUSH_TOKEN }}@github.com/radiolib-org/artifacts.git + git clone git@github.com:radiolib-org/artifacts.git cd artifacts git config --global user.name "${{ github.actor }}" git config --global user.email "${{ github.actor }}@users.noreply.github.com" From b5d36f11e5c0e12d22a83395f23c5b13df25f922 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 4 Jan 2025 11:22:28 +0100 Subject: [PATCH 1405/1848] [Pager] Minor formatting fixes --- src/protocols/Pager/Pager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 9d56ea40d4..4397462c5b 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -93,7 +93,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t } // Automatically set function bits based on given encoding - if (function == RADIOLIB_PAGER_FUNC_AUTO) { + if(function == RADIOLIB_PAGER_FUNC_AUTO) { if(encoding == RADIOLIB_PAGER_BCD) { function = RADIOLIB_PAGER_FUNC_BITS_NUMERIC; @@ -101,14 +101,14 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t function = RADIOLIB_PAGER_FUNC_BITS_ALPHA; } else { - return(RADIOLIB_ERR_INVALID_ENCODING); + return(RADIOLIB_ERR_INVALID_ENCODING); } if(len == 0) { function = RADIOLIB_PAGER_FUNC_BITS_TONE; } } - if (function > RADIOLIB_PAGER_FUNC_BITS_ALPHA) { + if(function > RADIOLIB_PAGER_FUNC_BITS_ALPHA) { return(RADIOLIB_ERR_INVALID_FUNCTION); } @@ -323,7 +323,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { state = readData(data, &length, addr); if(state == RADIOLIB_ERR_NONE) { - // check tone-only tramsissions + // check tone-only transmissions if(length == 0) { length = 6; strncpy((char*)data, "", length + 1); From 01e7fa07312175fdd94b1c0544d5c8b82a0044e7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 4 Jan 2025 11:23:07 +0100 Subject: [PATCH 1406/1848] [Pager] Fix sync words in long messages (#1112) --- src/protocols/Pager/Pager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 4397462c5b..7c9aeb6b59 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -168,7 +168,7 @@ int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t uint8_t blockPos = RADIOLIB_PAGER_PREAMBLE_LENGTH + 1 + framePos + 1 + i; // check if we need to skip a frame sync marker - if(((blockPos - (RADIOLIB_PAGER_PREAMBLE_LENGTH + 1)) % RADIOLIB_PAGER_BATCH_LEN) == 0) { + if(((blockPos - RADIOLIB_PAGER_PREAMBLE_LENGTH) % (RADIOLIB_PAGER_BATCH_LEN + 1)) == 0) { blockPos++; i++; } @@ -497,6 +497,7 @@ bool PagerClient::addressMatched(uint32_t addr) { void PagerClient::write(uint32_t* data, size_t len) { // write code words from buffer for(size_t i = 0; i < len; i++) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("POCSAG W\t%d\t%08lX", i, (long unsigned int)data[i]); PagerClient::write(data[i]); } } From 92d2dc0f09381a51acb39ac44994b8107665ff46 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 14:27:10 +0100 Subject: [PATCH 1407/1848] [LoRaWAN] Remove unused space in session buffer --- src/protocols/LoRaWAN/LoRaWAN.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 45bdb4bc40..18e3b53217 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -291,11 +291,7 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + 1, // 1 byte RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + 1, // 1 byte RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + 1, // 1 byte - RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + 1, // 3 bytes - RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes - RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte - RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes - RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + 1, // 16*5 bytes RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*5, // 16*4 bytes RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*4, // 2 bytes RADIOLIB_LORAWAN_SESSION_MAC_QUEUE = RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS + sizeof(uint16_t), // 15 bytes From 6ab358c2925b3e44dcc7ab209b8859dac285b8a0 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 14:43:20 +0100 Subject: [PATCH 1408/1848] [LoRaWAN] Improve dwell time handling under ADR --- src/protocols/LoRaWAN/LoRaWAN.cpp | 37 ++++++++++++++++--------------- src/protocols/LoRaWAN/LoRaWAN.h | 9 +++----- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 93da73df3f..d6b938f311 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -12,8 +12,6 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; this->txPowerMax = this->band->powerMax; this->subBand = subBand; - this->dwellTimeEnabledUp = this->dwellTimeUp != 0; - this->dwellTimeEnabledDn = this->dwellTimeDn != 0; memset(this->channelPlan, 0, sizeof(this->channelPlan)); } @@ -906,7 +904,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RADIOLIB_ASSERT(state); // calculate JoinRequest time-on-air in milliseconds - if(this->dwellTimeEnabledUp) { + if(this->dwellTimeUp) { RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; if(toa > this->dwellTimeUp) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp); @@ -1131,10 +1129,21 @@ void LoRaWANNode::adrBackoff() { } } - // try to decrease the datarate + // if datarate can be decreased, try it if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > 0) { - if(this->setDatarate(this->channels[RADIOLIB_LORAWAN_UPLINK].dr - 1) == RADIOLIB_ERR_NONE) { - return; + uint8_t oldDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + + if(this->setDatarate(oldDr - 1) == RADIOLIB_ERR_NONE) { + // if there is no dwell time limit, a lower datarate is OK + if(!this->dwellTimeUp) { + return; + } + // if there is a dwell time limit, check if this datarate allows an empty uplink + if(this->phyLayer->getTimeOnAir(13) / 1000 < this->dwellTimeUp) { + return; + } + // if the Time on Air of an empty uplink exceeded the dwell time, revert + this->setDatarate(oldDr); } } @@ -2203,10 +2212,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin this->txPowerMax = eirpEncoding[maxEirpRaw]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("TxParamSetupReq: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, eirpEncoding[maxEirpRaw]); - this->dwellTimeEnabledUp = ulDwell ? true : false; this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; - - this->dwellTimeEnabledDn = dlDwell ? true : false; this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0; memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP], optIn, lenIn); @@ -2690,13 +2696,8 @@ void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { } } -void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { - this->dwellTimeEnabledUp = enable; - if(msPerUplink == 0) { - this->dwellTimeUp = this->band->dwellTimeUp; - } else { - this->dwellTimeUp = msPerUplink; - } +void LoRaWANNode::setDwellTime(RadioLibTime_t msPerUplink) { + this->dwellTimeUp = msPerUplink; } // A user may enable CSMA to provide frames an additional layer of protection from interference. @@ -3098,7 +3099,7 @@ int16_t LoRaWANNode::selectChannels() { // if downlink dwelltime is enabled, datarate < 2 cannot be used, so clip to 2 // only in use on AS923_x bands - if(this->dwellTimeEnabledDn && rx1Dr < 2) { + if(this->dwellTimeDn && rx1Dr < 2) { rx1Dr = 2; } this->channels[RADIOLIB_LORAWAN_DOWNLINK].dr = rx1Dr; @@ -3250,7 +3251,7 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { maxLen += 13; // mandatory FHDR is 12/13 bytes // if not limited by dwell-time, just return maximum - if(!this->dwellTimeEnabledUp) { + if(!this->dwellTimeUp) { // subtract FHDR (13 bytes) as well as any FOpts return(maxLen - 13 - this->fOptsUpLen); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 18e3b53217..624405c1f3 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -743,12 +743,11 @@ class LoRaWANNode { void setDutyCycle(bool enable = true, RadioLibTime_t msPerHour = 0); /*! - \brief Toggle adherence to dwellTime limits to on or off. - \param enable Whether to adhere to dwellTime limits or not (default true). + \brief Set or disable uplink dwell time limitation; enabled by default if mandatory. \param msPerUplink The maximum allowed Time-on-Air per uplink in milliseconds - (default 0 = maximum allowed for configured band). + (0 = no dwell time limitation, make sure you follow regulations/law!). */ - void setDwellTime(bool enable, RadioLibTime_t msPerUplink = 0); + void setDwellTime(RadioLibTime_t msPerUplink); /*! \brief Configures CSMA for LoRaWAN as per TR013, LoRa Alliance. @@ -913,9 +912,7 @@ class LoRaWANNode { uint32_t dutyCycle = 0; // dwell time is set upon initialization and activated in regions that impose this - bool dwellTimeEnabledUp = false; uint16_t dwellTimeUp = 0; - bool dwellTimeEnabledDn = false; uint16_t dwellTimeDn = 0; RadioLibTime_t tUplink = 0; // scheduled uplink transmission time (internal clock) From 617d759ea5ee5a7267b88dfe91b536e3cf1d5373 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 14:48:25 +0100 Subject: [PATCH 1409/1848] [LoRaWAN] Fix some MAC commands not being resent --- src/protocols/LoRaWAN/LoRaWAN.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 624405c1f3..eb8839c553 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -232,7 +232,7 @@ struct LoRaWANMacCommand_t { #define RADIOLIB_LORAWAN_MAC_COMMAND_NONE { .cid = 0, .lenDn = 0, .lenUp = 0, .persist = false, .user = false } constexpr LoRaWANMacCommand_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS] = { - { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_RESET, 1, 1, true, false }, { RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, false, true }, { RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false, false }, { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false, false }, @@ -242,7 +242,7 @@ constexpr LoRaWANMacCommand_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS] = { { RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, true, false }, { RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, true, false }, { RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, true, false }, - { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, true, false }, { RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false, false }, { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, false, true }, { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false, false }, From 5952106e93fd94dd0499e7f7b109c1685ed1b491 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sat, 4 Jan 2025 15:05:36 +0100 Subject: [PATCH 1410/1848] [LoRaWAN] Update reference example --- examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 28b2946794..98a3e31285 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -68,8 +68,8 @@ void setup() { // Manages uplink intervals to the TTN Fair Use Policy node.setDutyCycle(true, 1250); - // Enable the dwell time limits - 400ms is the limit for the US - node.setDwellTime(true, 400); + // Update dwell time limits - 400ms is the limit for the US + node.setDwellTime(400); Serial.println(F("Ready!\n")); } From 283bfb43fed1d229c3b5e8ae2fe0f5611575537d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 16:04:05 +0100 Subject: [PATCH 1411/1848] [LoRaWAN] Revert change in dwell time arguments --- .../LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 11 +++++++++-- src/protocols/LoRaWAN/LoRaWAN.h | 5 +++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 98a3e31285..87d7f1ebce 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -69,7 +69,7 @@ void setup() { node.setDutyCycle(true, 1250); // Update dwell time limits - 400ms is the limit for the US - node.setDwellTime(400); + node.setDwellTime(true, 400); Serial.println(F("Ready!\n")); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index d6b938f311..53fd2a57bc 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2696,8 +2696,15 @@ void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { } } -void LoRaWANNode::setDwellTime(RadioLibTime_t msPerUplink) { - this->dwellTimeUp = msPerUplink; +void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) { + if(!enable) { + this->dwellTimeUp = 0; + + } else if(msPerUplink > 0) { + this->dwellTimeUp = msPerUplink; + } else { //msPerUplink == 0 + this->dwellTimeUp = this->band->dwellTimeUp; + } } // A user may enable CSMA to provide frames an additional layer of protection from interference. diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index eb8839c553..90a51ab8da 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -744,10 +744,11 @@ class LoRaWANNode { /*! \brief Set or disable uplink dwell time limitation; enabled by default if mandatory. + \param enable Whether to adhere to dwellTime limits or not (default true). \param msPerUplink The maximum allowed Time-on-Air per uplink in milliseconds - (0 = no dwell time limitation, make sure you follow regulations/law!). + (default 0 = band default value); make sure you follow regulations/law! */ - void setDwellTime(RadioLibTime_t msPerUplink); + void setDwellTime(bool enable, RadioLibTime_t msPerUplink = 0); /*! \brief Configures CSMA for LoRaWAN as per TR013, LoRa Alliance. From a3782b432c10598d8850277bf5c8c7d1e90f42e5 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 16:20:42 +0100 Subject: [PATCH 1412/1848] [LoRaWAN] Accept MAC channel mask if ADR is disabled --- src/protocols/LoRaWAN/LoRaWAN.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 53fd2a57bc..0705d6ade4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1930,7 +1930,6 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // only acknowledge if the radio is able to operate at or below the requested power level if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { pwrAck = 1; - this->txPowerSteps = macTxSteps; } else { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); } @@ -1942,10 +1941,17 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // if ACK not completely successful, revert and stop if(optOut[0] != 0x07) { - this->applyChannelMask(chMaskGrp0123, chMaskGrp45); - this->setAvailableChannels(chMaskActive); + // according to paragraph 4.3.1.1, if ADR is disabled, + // the ADR channel mask must be accepted even if drAck/pwrAck fails. + // therefore, only revert the channel mask if ADR is enabled. + if(this->adrEnabled) { + this->applyChannelMask(chMaskGrp0123, chMaskGrp45); + this->setAvailableChannels(chMaskActive); + } + // revert datarate this->channels[RADIOLIB_LORAWAN_UPLINK].dr = currentDr; - // Tx power was not modified + // Tx power was not actually modified + return(true); } From f346dd3687f5c3407a911a43cc85bc10ebc3bc91 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 23:18:37 +0100 Subject: [PATCH 1413/1848] [LoRaWAN] Improve handling of invalid MAC commands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0705d6ade4..120b1fb01d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -290,7 +290,8 @@ void LoRaWANNode::clearSession() { this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; - // reset number of retransmissions from ADR + // reset ADR state + this->txPowerSteps = 0; this->nbTrans = 1; // clear CSMA settings @@ -1562,7 +1563,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif - return(RADIOLIB_ERR_INVALID_PORT); + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } // get the frame counter @@ -1711,15 +1712,24 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e while(procLen < fOptsLen) { cid = *mPtr; // MAC id is the first byte + + // fetch length of MAC downlink payload state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true); - RADIOLIB_ASSERT(state); + if(state != RADIOLIB_ERR_NONE) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Unknown MAC CID %02x", cid); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + break; + } + + // already fetch length of MAC answer payload (if any) uint8_t fLenRe = 0; - state = this->getMacLen(cid, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true); - RADIOLIB_ASSERT(state); + (void)this->getMacLen(cid, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true); + // don't care about return value: the previous getMacLen() would have failed anyway if(procLen + fLen > fOptsLen) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen, fLen); - return(RADIOLIB_ERR_INVALID_CID); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen - procLen, fLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + break; } bool reply = false; From 33b65344c485aa3730b96aa204a0ed4b7e34adc6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 4 Jan 2025 23:27:18 +0100 Subject: [PATCH 1414/1848] [LoRaWAN] Fix ADR backoff difference between 1.0.4 and 1.1 --- src/protocols/LoRaWAN/LoRaWAN.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 120b1fb01d..07281be5ff 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1177,10 +1177,18 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ENABLED; // AdrAckReq is set if no downlink has been received for >=Limit uplinks - // but it is unset once backoff has been completed (which is internally denoted by adrFCnt == FCNT_NONE) uint32_t adrLimit = 0x01 << this->adrLimitExp; - if(this->adrFCnt != RADIOLIB_LORAWAN_FCNT_NONE && (this->fCntUp - this->adrFCnt) >= adrLimit) { - out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + if(this->rev == 1) { + // AdrAckReq is unset once backoff has been completed + // (which is internally denoted by adrFCnt == FCNT_NONE) + if(this->adrFCnt != RADIOLIB_LORAWAN_FCNT_NONE && (this->fCntUp - this->adrFCnt) >= adrLimit) { + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + } + } else { // rev == 0 + // AdrAckReq is always set, also when backoff has been completed + if(this->adrFCnt == RADIOLIB_LORAWAN_FCNT_NONE || (this->fCntUp - this->adrFCnt) >= adrLimit) { + out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ADR_ACK_REQ; + } } } @@ -1643,8 +1651,8 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e isConfirmedDown = true; } - // a downlink was received, so reset the ADR counter to the last uplink's fCnt - this->adrFCnt = this->getFCntUp(); + // a downlink was received, so restart the ADR counter with the next uplink + this->adrFCnt = this->getFCntUp() + 1; // if this downlink is on FPort 0, the FOptsLen is the length of the payload // in any other case, the payload (length) is user accessible From a63ca70558886888565bbe277d9d30682ea296a6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jan 2025 09:59:55 +0100 Subject: [PATCH 1415/1848] [Pager] Fix debug parameter type --- src/protocols/Pager/Pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 7c9aeb6b59..f286395ff5 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -497,7 +497,7 @@ bool PagerClient::addressMatched(uint32_t addr) { void PagerClient::write(uint32_t* data, size_t len) { // write code words from buffer for(size_t i = 0; i < len; i++) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("POCSAG W\t%d\t%08lX", i, (long unsigned int)data[i]); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("POCSAG W\t%lu\t%08lX", (long unsigned int)i, (long unsigned int)data[i]); PagerClient::write(data[i]); } } From cbb8d419d1d5955d55fc3db95bd0a601058860c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 5 Jan 2025 17:23:13 +0100 Subject: [PATCH 1416/1848] [CI] Unit test (#1373) * [CI] Add basic unit testing * [CI] Add gitignore * [CI] Install libfmt --------- Co-authored-by: jgromes --- .github/workflows/unit-test.yml | 27 ++ extras/test/unit/.gitignore | 1 + extras/test/unit/CMakeLists.txt | 29 +++ .../test/unit/include/HardwareEmulation.hpp | 71 ++++++ extras/test/unit/include/TestHal.hpp | 237 ++++++++++++++++++ extras/test/unit/test.sh | 13 + extras/test/unit/tests/TestModule.cpp | 103 ++++++++ extras/test/unit/tests/main.cpp | 5 + 8 files changed, 486 insertions(+) create mode 100644 .github/workflows/unit-test.yml create mode 100644 extras/test/unit/.gitignore create mode 100644 extras/test/unit/CMakeLists.txt create mode 100644 extras/test/unit/include/HardwareEmulation.hpp create mode 100644 extras/test/unit/include/TestHal.hpp create mode 100755 extras/test/unit/test.sh create mode 100644 extras/test/unit/tests/TestModule.cpp create mode 100644 extras/test/unit/tests/main.cpp diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml new file mode 100644 index 0000000000..58a7d72250 --- /dev/null +++ b/.github/workflows/unit-test.yml @@ -0,0 +1,27 @@ +name: "Unit test" + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + unit-test: + name: Build and run unit test + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libboost-all-dev libfmt-dev + + - name: Run unit test + run: | + cd extras/test/unit + ./test.sh diff --git a/extras/test/unit/.gitignore b/extras/test/unit/.gitignore new file mode 100644 index 0000000000..567609b123 --- /dev/null +++ b/extras/test/unit/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt new file mode 100644 index 0000000000..a907258c12 --- /dev/null +++ b/extras/test/unit/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.13) + +project(radiolib-unittest) + +# add RadioLib sources +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") + +# add test sources +file(GLOB_RECURSE TEST_SOURCES + "tests/main.cpp" + "tests/TestModule.cpp" +) + +# create the executable +add_executable(${PROJECT_NAME} ${TEST_SOURCES}) + +# include directories +target_include_directories(${PROJECT_NAME} PUBLIC include) + +# link RadioLib +target_link_libraries(${PROJECT_NAME} RadioLib fmt) + +# set target properties and options +set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra) + +# set RadioLib debug +#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI) +#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_PORT=stdout) diff --git a/extras/test/unit/include/HardwareEmulation.hpp b/extras/test/unit/include/HardwareEmulation.hpp new file mode 100644 index 0000000000..c2b324a846 --- /dev/null +++ b/extras/test/unit/include/HardwareEmulation.hpp @@ -0,0 +1,71 @@ +#ifndef HARDWARE_EMULATION_HPP +#define HARDWARE_EMULATION_HPP + +#include + +// value that is returned by the emualted radio class when performing SPI transfer to it +#define EMULATED_RADIO_SPI_RETURN (0xFF) + +// pin indexes +#define EMULATED_RADIO_NSS_PIN (1) +#define EMULATED_RADIO_IRQ_PIN (2) +#define EMULATED_RADIO_RST_PIN (3) +#define EMULATED_RADIO_GPIO_PIN (4) + +enum PinFunction_t { + PIN_UNASSIGNED = 0, + PIN_CS, + PIN_IRQ, + PIN_RST, + PIN_GPIO, +}; + +// structure for emulating GPIO pins +struct EmulatedPin_t { + uint32_t mode; + uint32_t value; + bool event; + PinFunction_t func; +}; + +// structure for emulating SPI registers +struct EmulatedRegister_t { + uint8_t value; + uint8_t readOnlyBitFlags; + bool bufferAccess; +}; + +// base class for emulated radio modules (SX126x etc.) +class EmulatedRadio { + public: + void connect(EmulatedPin_t* csPin, EmulatedPin_t* irqPin, EmulatedPin_t* rstPin, EmulatedPin_t* gpioPin) { + this->cs = csPin; + this->cs->func = PIN_CS; + this->irq = irqPin; + this->irq->func = PIN_IRQ; + this->rst = rstPin; + this->rst->func = PIN_RST; + this->gpio = gpioPin; + this->gpio->func = PIN_GPIO; + } + + virtual uint8_t HandleSPI(uint8_t b) { + (void)b; + // handle the SPI input and generate output here + return(EMULATED_RADIO_SPI_RETURN); + } + + virtual void HandleGPIO() { + // handle discrete GPIO signals here (e.g. reset state machine on NSS falling edge) + } + + protected: + // pointers to emulated GPIO pins + // this is done via pointers so that the same GPIO entity is shared, like with a real hardware + EmulatedPin_t* cs; + EmulatedPin_t* irq; + EmulatedPin_t* rst; + EmulatedPin_t* gpio; +}; + +#endif diff --git a/extras/test/unit/include/TestHal.hpp b/extras/test/unit/include/TestHal.hpp new file mode 100644 index 0000000000..cf1faff968 --- /dev/null +++ b/extras/test/unit/include/TestHal.hpp @@ -0,0 +1,237 @@ +#ifndef TEST_HAL_HPP +#define TEST_HAL_HPP + +#include +#include +#include + +#include + +#include +#include + +#if defined(TEST_HAL_LOG) +#define HAL_LOG(...) BOOST_TEST_MESSAGE(__VA_ARGS__) +#else +#define HAL_LOG(...) {} +#endif + +#include "HardwareEmulation.hpp" + +#define TEST_HAL_INPUT (0) +#define TEST_HAL_OUTPUT (1) +#define TEST_HAL_LOW (0) +#define TEST_HAL_HIGH (1) +#define TEST_HAL_RISING (0) +#define TEST_HAL_FALLING (1) + +// number of emulated GPIO pins +#define TEST_HAL_NUM_GPIO_PINS (32) + +#define TEST_HAL_SPI_LOG_LENGTH (512) + +class TestHal : public RadioLibHal { + public: + TestHal() : RadioLibHal(TEST_HAL_INPUT, TEST_HAL_OUTPUT, TEST_HAL_LOW, TEST_HAL_HIGH, TEST_HAL_RISING, TEST_HAL_FALLING) { } + + void init() override { + HAL_LOG("TestHal::init()"); + + // save program start timestamp + start = std::chrono::high_resolution_clock::now(); + + // init emulated GPIO + for(int i = 0; i < TEST_HAL_NUM_GPIO_PINS; i++) { + this->gpio[i].mode = 0; + this->gpio[i].value = 0; + this->gpio[i].event = false; + this->gpio[i].func = PIN_UNASSIGNED; + } + } + + void term() override { + HAL_LOG("TestHal::term()"); + } + + void pinMode(uint32_t pin, uint32_t mode) override { + HAL_LOG("TestHal::pinMode(pin=" << pin << ", mode=" << mode << " [" << ((mode == TEST_HAL_INPUT) ? "INPUT" : "OUTPUT") << "])"); + + // check the range + BOOST_ASSERT_MSG(pin < TEST_HAL_NUM_GPIO_PINS, "Pin number out of range"); + + // check known modes + BOOST_ASSERT_MSG(((mode == TEST_HAL_INPUT) || (mode == TEST_HAL_OUTPUT)), "Invalid pin mode"); + + // set mode + this->gpio[pin].mode = mode; + } + + void digitalWrite(uint32_t pin, uint32_t value) override { + HAL_LOG("TestHal::digitalWrite(pin=" << pin << ", value=" << value << " [" << ((value == TEST_HAL_LOW) ? "LOW" : "HIGH") << "])"); + + // check the range + BOOST_ASSERT_MSG(pin < TEST_HAL_NUM_GPIO_PINS, "Pin number out of range"); + + // check it is output + BOOST_ASSERT_MSG(this->gpio[pin].mode == TEST_HAL_OUTPUT, "GPIO is not output!"); + + // check known values + BOOST_ASSERT_MSG(((value == TEST_HAL_LOW) || (value == TEST_HAL_HIGH)), "Invalid output value"); + + // set value + this->gpio[pin].value = value; + this->gpio[pin].event = true; + if(radio) { + this->radio->HandleGPIO(); + } + this->gpio[pin].event = false; + } + + uint32_t digitalRead(uint32_t pin) override { + HAL_LOG("TestHal::digitalRead(pin=" << pin << ")"); + + // check the range + BOOST_ASSERT_MSG(pin < TEST_HAL_NUM_GPIO_PINS, "Pin number out of range"); + + // check it is input + BOOST_ASSERT_MSG(this->gpio[pin].mode == TEST_HAL_INPUT, "GPIO is not input"); + + // read the value + uint32_t value = this->gpio[pin].value; + HAL_LOG("TestHal::digitalRead(pin=" << pin << ")=" << value << " [" << ((value == TEST_HAL_LOW) ? "LOW" : "HIGH") << "]"); + return(value); + } + + void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { + HAL_LOG("TestHal::attachInterrupt(interruptNum=" << interruptNum << ", interruptCb=" << interruptCb << ", mode=" << mode << ")"); + } + + void detachInterrupt(uint32_t interruptNum) override { + HAL_LOG("TestHal::detachInterrupt(interruptNum=" << interruptNum << ")"); + } + + void delay(unsigned long ms) override { + HAL_LOG("TestHal::delay(ms=" << ms << ")"); + const auto start = std::chrono::high_resolution_clock::now(); + + // sleep_for is sufficient for ms-precision sleep + std::this_thread::sleep_for(std::chrono::duration(ms)); + + // measure and print + const auto end = std::chrono::high_resolution_clock::now(); + const std::chrono::duration elapsed = end - start; + HAL_LOG("TestHal::delay(ms=" << ms << ")=" << elapsed.count() << "ms"); + } + + void delayMicroseconds(unsigned long us) override { + HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")"); + const auto start = std::chrono::high_resolution_clock::now(); + + // busy wait is needed for microseconds precision + const auto len = std::chrono::microseconds(us); + while(std::chrono::high_resolution_clock::now() - start < len); + + // measure and print + const auto end = std::chrono::high_resolution_clock::now(); + const std::chrono::duration elapsed = end - start; + HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")=" << elapsed.count() << "us"); + } + + void yield() override { + HAL_LOG("TestHal::yield()"); + } + + unsigned long millis() override { + HAL_LOG("TestHal::millis()"); + std::chrono::time_point now = std::chrono::high_resolution_clock::now(); + auto res = std::chrono::duration_cast(now - this->start); + HAL_LOG("TestHal::millis()=" << res.count()); + return(res.count()); + } + + unsigned long micros() override { + HAL_LOG("TestHal::micros()"); + std::chrono::time_point now = std::chrono::high_resolution_clock::now(); + auto res = std::chrono::duration_cast(now - this->start); + HAL_LOG("TestHal::micros()=" << res.count()); + return(res.count()); + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { + HAL_LOG("TestHal::pulseIn(pin=" << pin << ", state=" << state << ", timeout=" << timeout << ")"); + return(0); + } + + void spiBegin() { + HAL_LOG("TestHal::spiBegin()"); + } + + void spiBeginTransaction() { + HAL_LOG("TestHal::spiBeginTransaction()"); + + // wipe history log + memset(this->spiLog, 0x00, TEST_HAL_SPI_LOG_LENGTH); + this->spiLogPtr = this->spiLog; + } + + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + HAL_LOG("TestHal::spiTransfer(len=" << len << ")"); + + for(size_t i = 0; i < len; i++) { + // append to log + (*this->spiLogPtr++) = out[i]; + + // process the SPI byte + in[i] = this->radio->HandleSPI(out[i]); + + // outpu debug + HAL_LOG(fmt::format("out={:#02x}, in={:#02x}", out[i], in[i])); + } + } + + void spiEndTransaction() { + HAL_LOG("TestHal::spiEndTransaction()"); + } + + void spiEnd() { + HAL_LOG("TestHal::spiEnd()"); + } + + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) { + HAL_LOG("TestHal::tone(pin=" << pin << ", frequency=" << frequency << ", duration=" << duration << ")"); + } + + void noTone(uint32_t pin) { + HAL_LOG("TestHal::noTone(pin=" << pin << ")"); + } + + // method to compare buffer to the internal SPI log, for verifying SPI transactions + int spiLogMemcmp(const void* in, size_t n) { + return(memcmp(this->spiLog, in, n)); + } + + // method that "connects" the emualted radio hardware to this HAL + void connectRadio(EmulatedRadio* r) { + this->radio = r; + this->radio->connect(&this->gpio[EMULATED_RADIO_NSS_PIN], + &this->gpio[EMULATED_RADIO_IRQ_PIN], + &this->gpio[EMULATED_RADIO_RST_PIN], + &this->gpio[EMULATED_RADIO_GPIO_PIN]); + } + + private: + // array of emulated GPIO pins + EmulatedPin_t gpio[TEST_HAL_NUM_GPIO_PINS]; + + // start time point + std::chrono::time_point start; + + // emulated radio hardware + EmulatedRadio* radio; + + // SPI history log + uint8_t spiLog[TEST_HAL_SPI_LOG_LENGTH]; + uint8_t* spiLogPtr; +}; + +#endif diff --git a/extras/test/unit/test.sh b/extras/test/unit/test.sh new file mode 100755 index 0000000000..369690adfb --- /dev/null +++ b/extras/test/unit/test.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +# build the test binary +mkdir -p build +cd build +cmake -G "CodeBlocks - Unix Makefiles" .. +make -j4 + +# run it +cd .. +./build/radiolib-unittest --log_level=message diff --git a/extras/test/unit/tests/TestModule.cpp b/extras/test/unit/tests/TestModule.cpp new file mode 100644 index 0000000000..f2815d6bc2 --- /dev/null +++ b/extras/test/unit/tests/TestModule.cpp @@ -0,0 +1,103 @@ +// boost test header +#include + +// mock HAL +#include "TestHal.hpp" + +// testing fixture +struct ModuleFixture { + TestHal* hal = nullptr; + Module* mod = nullptr; + EmulatedRadio* radioHardware = nullptr; + + ModuleFixture() { + BOOST_TEST_MESSAGE("--- Module fixture setup ---"); + hal = new TestHal(); + radioHardware = new EmulatedRadio(); + hal->connectRadio(radioHardware); + + mod = new Module(hal, EMULATED_RADIO_NSS_PIN, EMULATED_RADIO_IRQ_PIN, EMULATED_RADIO_RST_PIN, EMULATED_RADIO_GPIO_PIN); + mod->init(); + } + + ~ModuleFixture() { + BOOST_TEST_MESSAGE("--- Module fixture teardown ---"); + mod->term(); + delete[] mod; + delete[] hal; + } +}; + +BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture) + + BOOST_FIXTURE_TEST_CASE(Module_SPIgetRegValue_reg, ModuleFixture) + { + BOOST_TEST_MESSAGE("--- Test Module::SPIgetRegValue register access ---"); + int16_t ret; + + // basic register read with default config + const uint8_t address = 0x12; + const uint8_t spiTxn[] = { address, 0x00 }; + ret = mod->SPIgetRegValue(address); + + // check return code, value and history log + BOOST_TEST(ret >= RADIOLIB_ERR_NONE); + BOOST_TEST(ret == EMULATED_RADIO_SPI_RETURN); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + + // register read masking test + const uint8_t msb = 5; + const uint8_t lsb = 1; + ret = mod->SPIgetRegValue(address, msb, lsb); + BOOST_TEST(ret == 0x3E); + + // invalid mask tests (swapped MSB and LSB, out of range bit masks) + ret = mod->SPIgetRegValue(address, lsb, msb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIgetRegValue(address, 10, lsb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIgetRegValue(address, msb, 10); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + } + + BOOST_FIXTURE_TEST_CASE(Module_SPIgetRegValue_stream, ModuleFixture) + { + BOOST_TEST_MESSAGE("--- Test Module::SPIgetRegValue stream access ---"); + int16_t ret; + + // change settings to stream type + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; + mod->spiConfig.statusPos = 1; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; + mod->spiConfig.stream = true; + + // basic register read + const uint8_t address = 0x12; + const uint8_t spiTxn[] = { RADIOLIB_SX126X_CMD_READ_REGISTER, 0x00, address, 0x00, 0x00 }; + ret = mod->SPIgetRegValue(address); + + // check return code, value and history log + BOOST_TEST(ret >= RADIOLIB_ERR_NONE); + BOOST_TEST(ret == EMULATED_RADIO_SPI_RETURN); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + + // register read masking test + const uint8_t msb = 5; + const uint8_t lsb = 1; + ret = mod->SPIgetRegValue(address, msb, lsb); + BOOST_TEST(ret == 0x3E); + + // invalid mask tests (swapped MSB and LSB, out of range bit masks) + ret = mod->SPIgetRegValue(address, lsb, msb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIgetRegValue(address, 10, lsb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIgetRegValue(address, msb, 10); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/extras/test/unit/tests/main.cpp b/extras/test/unit/tests/main.cpp new file mode 100644 index 0000000000..be4b6efd8b --- /dev/null +++ b/extras/test/unit/tests/main.cpp @@ -0,0 +1,5 @@ +#define BOOST_TEST_MODULE "RadioLib Unit test" +#include + +// intentionally left blank, boost.test creates its own entrypoint + From 92c08c1ebff95dfd3c49077a80ff88d7c7db52ec Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jan 2025 17:46:30 +0100 Subject: [PATCH 1417/1848] [LR11x0] Added explicit typecast --- src/modules/LR11x0/LR11x0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index a360b935de..f039bc42d6 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -358,7 +358,7 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) { if(wakeup) { // send a NOP command - this pulls the NSS low to exit the sleep mode, // while preventing interference with possible other SPI transactions - (void)this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false); + (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false); } uint8_t buff[] = { mode }; From 5ea881c595403a8b1d50e7d89aa747972a84a32d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jan 2025 17:46:36 +0100 Subject: [PATCH 1418/1848] [SX126x] Added explicit typecast --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 31aa2aa3d3..f14e0f870c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -470,7 +470,7 @@ int16_t SX126x::standby(uint8_t mode, bool wakeup) { // send a NOP command - this pulls the NSS low to exit the sleep mode, // while preventing interference with possible other SPI transactions // see https://github.com/jgromes/RadioLib/discussions/1364 - (void)this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false); + (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false); } uint8_t data[] = { mode }; From 06f416935f8b23464181c6998084adb217382201 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jan 2025 17:46:42 +0100 Subject: [PATCH 1419/1848] [SX128x] Added explicit typecast --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a86d82abce..139fac55c7 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -482,7 +482,7 @@ int16_t SX128x::standby(uint8_t mode, bool wakeup) { if(wakeup) { // send a NOP command - this pulls the NSS low to exit the sleep mode, // while preventing interference with possible other SPI transactions - (void)this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false); + (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false); } uint8_t data[] = { mode }; From 49f21cc7073bf46bbb607668c3f67958a3b95f00 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jan 2025 18:28:40 +0100 Subject: [PATCH 1420/1848] [CI] Fix skipping for STM32 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dd7ee598c6..22383d8d3f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,7 +90,7 @@ jobs: - id: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1 run: | # Do *not* skip STM32WL examples - echo "skip-pattern='LR11x0_Firmware_Update'" >> $GITHUB_OUTPUT + echo "skip-pattern=(LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT - id: stm32duino:STM32F1:mapleMini run: | From d26b1ff38e2fbdced7d79689662dbd162fa54070 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 5 Jan 2025 20:20:04 +0100 Subject: [PATCH 1421/1848] Bump version to 7.1.2 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index e77395aa28..e5199c4cb1 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.1.1" +version: "7.1.2" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 71a6512893..6182a0cfbc 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.1.1", + "version": "7.1.2", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 31518c460b..f4a95869ad 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.1.1 +version=7.1.2 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index ec31bc2595..d64f500611 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -583,7 +583,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 #define RADIOLIB_VERSION_MINOR 1 -#define RADIOLIB_VERSION_PATCH 1 +#define RADIOLIB_VERSION_PATCH 2 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 2ca2ddf968215da2366a41d866cf74b8090f75f9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 6 Jan 2025 18:03:18 +0100 Subject: [PATCH 1422/1848] [CI] Fix passing STM32 part numbers --- .github/workflows/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 22383d8d3f..9779ea9c77 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -83,12 +83,14 @@ jobs: echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT - - id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC + - id: STMicroelectronics:stm32:GenF3 run: | + echo "options=':pnum=BLACKPILL_F303CC'" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT - - id: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1 + - id: STMicroelectronics:stm32:Nucleo_64 run: | + echo "options=':pnum=NUCLEO_WL55JC1'" >> $GITHUB_OUTPUT # Do *not* skip STM32WL examples echo "skip-pattern=(LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT From 9a8affde8e0b3d66ff91016dad0da9ef03d41eb3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 11 Jan 2025 09:32:12 +0100 Subject: [PATCH 1423/1848] Fix default debug port on non-Arduino platforms (#1380) --- src/BuildOpt.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index d64f500611..29be4d8ae7 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -29,7 +29,11 @@ // set which output port should be used for debug output // may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms) #if !defined(RADIOLIB_DEBUG_PORT) - #define RADIOLIB_DEBUG_PORT Serial + #if ARDUINO >= 100 + #define RADIOLIB_DEBUG_PORT Serial + #else + #define RADIOLIB_DEBUG_PORT stdout + #endif #endif /* @@ -433,10 +437,6 @@ #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*((uint32_t *)(void *)(addr))) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; - #if !defined(RADIOLIB_DEBUG_PORT) - #define RADIOLIB_DEBUG_PORT stdout - #endif - #define DEC 10 #define HEX 16 #define OCT 8 From 04b96873a35bbaeb7f41b0dba634df4dbe390449 Mon Sep 17 00:00:00 2001 From: petrel Date: Tue, 14 Jan 2025 15:03:43 +0800 Subject: [PATCH 1424/1848] [CC1101]Add sleep function (#1389) --- src/modules/CC1101/CC1101.cpp | 6 ++++++ src/modules/CC1101/CC1101.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index b91b949f71..91a89de577 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -116,6 +116,12 @@ int16_t CC1101::standby(uint8_t mode) { return(standby()); } +int16_t CC1101::sleep() { + int16_t state =standby(); + SPIsendCommand(RADIOLIB_CC1101_CMD_POWER_DOWN); + return(state); +} + int16_t CC1101::transmitDirect(uint32_t frf) { return transmitDirect(true, frf); } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index e1a71a47a0..694b737721 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -614,6 +614,12 @@ class CC1101: public PhysicalLayer { */ int16_t standby(uint8_t mode) override; + /*! + \brief Sets the module to sleep mode. + \returns \ref status_codes + */ + int16_t sleep() override; + /*! \brief Starts synchronous direct mode transmission. \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. From 4f1d367c93ebe2a658565f3a0a53b51d699005c5 Mon Sep 17 00:00:00 2001 From: Yegor Shytikov Date: Tue, 14 Jan 2025 11:56:03 -0800 Subject: [PATCH 1425/1848] [LR11x0] Skip frequency range verification (#1388) * Update LR1120.cpp LR1120 can set the frequency of the documented range. So, allowing another frequency was tested with the LR1121 Lyligo board, which works. Thanks! * Update LR1120.h * add RADIOLIB_CHECK_PARAMS * remove skipRfValidation parameter * Fix formating --- src/modules/LR11x0/LR1120.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index fb6278223c..89ac983417 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -51,11 +51,13 @@ int16_t LR1120::setFrequency(float freq) { } int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) { + #if RADIOLIB_CHECK_PARAMS if(!(((freq >= 150.0) && (freq <= 960.0)) || ((freq >= 1900.0) && (freq <= 2200.0)) || ((freq >= 2400.0) && (freq <= 2500.0)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } + #endif // check if we need to recalibrate image int16_t state; @@ -146,4 +148,4 @@ int16_t LR1120::setModem(ModemType_t modem) { return(RADIOLIB_ERR_WRONG_MODEM); } -#endif \ No newline at end of file +#endif From f3276c2e66542473e3180c5a1671393199732776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Fran=C4=8De=C5=A1kin?= Date: Mon, 13 Jan 2025 16:23:56 +0100 Subject: [PATCH 1426/1848] fix implicit conversion from float to double warnings --- src/modules/CC1101/CC1101.cpp | 42 +++---- src/modules/CC1101/CC1101.h | 2 +- src/modules/LLCC68/LLCC68.cpp | 10 +- src/modules/LR11x0/LR1110.cpp | 2 +- src/modules/LR11x0/LR1120.cpp | 10 +- src/modules/LR11x0/LR11x0.cpp | 108 ++++++++--------- src/modules/LR11x0/LR11x0.h | 4 +- src/modules/RF69/RF69.cpp | 24 ++-- src/modules/RF69/RF69.h | 2 +- src/modules/SX123x/SX1233.cpp | 4 +- src/modules/SX126x/SX1262.cpp | 2 +- src/modules/SX126x/SX1268.cpp | 2 +- src/modules/SX126x/SX126x.cpp | 112 +++++++++--------- src/modules/SX126x/SX126x.h | 4 +- src/modules/SX127x/SX1272.cpp | 18 +-- src/modules/SX127x/SX1273.cpp | 6 +- src/modules/SX127x/SX1276.cpp | 2 +- src/modules/SX127x/SX1277.cpp | 8 +- src/modules/SX127x/SX1278.cpp | 72 +++++------ src/modules/SX127x/SX1279.cpp | 2 +- src/modules/SX127x/SX127x.cpp | 52 ++++---- src/modules/SX127x/SX127x.h | 2 +- src/modules/SX128x/SX1280.cpp | 2 +- src/modules/SX128x/SX128x.cpp | 40 +++---- src/modules/SX128x/SX128x.h | 2 +- src/modules/Si443x/Si4430.cpp | 2 +- src/modules/Si443x/Si4432.cpp | 2 +- src/modules/Si443x/Si443x.cpp | 80 ++++++------- src/protocols/BellModem/BellModem.cpp | 2 +- src/protocols/FSK4/FSK4.cpp | 2 +- src/protocols/Hellschreiber/Hellschreiber.cpp | 4 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 +- src/protocols/Morse/Morse.cpp | 2 +- src/protocols/Pager/Pager.cpp | 2 +- src/protocols/RTTY/RTTY.cpp | 2 +- src/protocols/SSTV/SSTV.cpp | 4 +- 36 files changed, 320 insertions(+), 320 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 91a89de577..b2bf595a93 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -58,7 +58,7 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t CC1101::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full max-length packets at current bit rate) - RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0); + RadioLibTime_t timeout = 500 + (1.0f/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0f); // start reception int16_t state = startReceive(); @@ -360,9 +360,9 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { int16_t CC1101::setFrequency(float freq) { // check allowed frequency range #if RADIOLIB_CHECK_PARAMS - if(!(((freq >= 300.0) && (freq <= 348.0)) || - ((freq >= 387.0) && (freq <= 464.0)) || - ((freq >= 779.0) && (freq <= 928.0)))) { + if(!(((freq >= 300.0f) && (freq <= 348.0f)) || + ((freq >= 387.0f) && (freq <= 464.0f)) || + ((freq >= 779.0f) && (freq <= 928.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } #endif @@ -372,7 +372,7 @@ int16_t CC1101::setFrequency(float freq) { //set carrier frequency uint32_t base = 1; - uint32_t FRF = (freq * (base << 16)) / 26.0; + uint32_t FRF = (freq * (base << 16)) / 26.0f; int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0); state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); @@ -386,7 +386,7 @@ int16_t CC1101::setFrequency(float freq) { } int16_t CC1101::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 0.025, 600.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.025f, 600.0f, RADIOLIB_ERR_INVALID_BIT_RATE); // set mode to standby SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); @@ -394,7 +394,7 @@ int16_t CC1101::setBitRate(float br) { // calculate exponent and mantissa values uint8_t e = 0; uint8_t m = 0; - getExpMant(br * 1000.0, 256, 28, 14, e, m); + getExpMant(br * 1000.0f, 256, 28, 14, e, m); // set bit rate value int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0); @@ -415,7 +415,7 @@ int16_t CC1101::setBitRateTolerance(uint8_t brt) { } int16_t CC1101::setRxBandwidth(float rxBw) { - RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 58.0f, 812.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // set mode to standby SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE); @@ -423,8 +423,8 @@ int16_t CC1101::setRxBandwidth(float rxBw) { // calculate exponent and mantissa values for(int8_t e = 3; e >= 0; e--) { for(int8_t m = 3; m >= 0; m --) { - float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); - if(fabs((rxBw * 1000.0) - point) <= 1000) { + float point = (RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0f)/(8 * (m + 4) * ((uint32_t)1 << e)); + if(fabs((rxBw * 1000.0f - point) <= 1000.0f)) { // set Rx channel filter bandwidth return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); } @@ -456,13 +456,13 @@ int16_t CC1101::autoSetRxBandwidth() { int16_t CC1101::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 1.587; + if(freqDev < 0.0f) { + newFreqDev = 1.587f; } // check range unless 0 (special value) if (freqDev != 0) { - RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 1.587f, 380.8f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } // set mode to standby @@ -471,7 +471,7 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { // calculate exponent and mantissa values uint8_t e = 0; uint8_t m = 0; - getExpMant(newFreqDev * 1000.0, 8, 17, 7, e, m); + getExpMant(newFreqDev * 1000.0f, 8, 17, 7, e, m); // set frequency deviation value int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_DEVIATN, (e << 4), 6, 4); @@ -500,7 +500,7 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) { // // freqDev = (fXosc / 2^17) * (8 + m) * 2^e // - *freqDev = (1000.0 / (uint32_t(1) << 17)) - (8 + m) * (uint32_t(1) << e); + *freqDev = (1000.0f / (uint32_t(1) << 17)) - (8 + m) * (uint32_t(1) << e); return(RADIOLIB_ERR_NONE); } @@ -564,13 +564,13 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { // round to the known frequency settings uint8_t f; - if(this->frequency < 374.0) { + if(this->frequency < 374.0f) { // 315 MHz f = 0; - } else if(this->frequency < 650.5) { + } else if(this->frequency < 650.5f) { // 434 MHz f = 1; - } else if(this->frequency < 891.5) { + } else if(this->frequency < 891.5f) { // 868 MHz f = 2; } else { @@ -723,9 +723,9 @@ float CC1101::getRSSI() { if(!this->directModeEnabled) { if(this->rawRSSI >= 128) { - rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0; + rssi = (((float)this->rawRSSI - 256.0f)/2.0f) - 74.0f; } else { - rssi = (((float)this->rawRSSI)/2.0) - 74.0; + rssi = (((float)this->rawRSSI)/2.0f) - 74.0f; } } else { uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI); @@ -1070,7 +1070,7 @@ int16_t CC1101::directMode(bool sync) { void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant) { // get table origin point (exp = 0, mant = 0) - float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp); + float origin = (mantOffset * RADIOLIB_CC1101_CRYSTAL_FREQ * 1000000.0f)/((uint32_t)1 << divExp); // iterate over possible exponent values for(int8_t e = expMax; e >= 0; e--) { diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 694b737721..a586d3da98 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -9,7 +9,7 @@ // CC1101 physical layer properties #define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 #define RADIOLIB_CC1101_MAX_PACKET_LENGTH 64 -#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0 +#define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0f #define RADIOLIB_CC1101_DIV_EXPONENT 16 // CC1101 SPI commands diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 834f5eda86..fe1468a242 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -38,7 +38,7 @@ int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync } int16_t LLCC68::setBandwidth(float bw) { - RADIOLIB_CHECK_RANGE(bw, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); return(SX1262::setBandwidth(bw)); } @@ -95,14 +95,14 @@ int16_t LLCC68::checkDataRate(DataRate_t dr) { // select interpretation based on active modem uint8_t modem = this->getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); - uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01; + uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01f; switch (bw_div2) { case 62: // 125.0: RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 1fbc696b56..186f8331a6 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -51,7 +51,7 @@ int16_t LR1110::setFrequency(float freq) { } int16_t LR1110::setFrequency(float freq, bool skipCalibration, float band) { - RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 150.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // check if we need to recalibrate image int16_t state; diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 89ac983417..6c6c14e44b 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -9,7 +9,7 @@ LR1120::LR1120(Module* mod) : LR11x0(mod) { int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { // execute common part - int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, freq > 1000.0); + int16_t state = LR11x0::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, freq > 1000.0f); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -52,9 +52,9 @@ int16_t LR1120::setFrequency(float freq) { int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) { #if RADIOLIB_CHECK_PARAMS - if(!(((freq >= 150.0) && (freq <= 960.0)) || - ((freq >= 1900.0) && (freq <= 2200.0)) || - ((freq >= 2400.0) && (freq <= 2500.0)))) { + if(!(((freq >= 150.0f) && (freq <= 960.0f)) || + ((freq >= 1900.0f) && (freq <= 2200.0f)) || + ((freq >= 2400.0f) && (freq <= 2500.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } #endif @@ -70,7 +70,7 @@ int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) { state = LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)); RADIOLIB_ASSERT(state); this->freqMHz = freq; - this->highFreq = (freq > 1000.0); + this->highFreq = (freq > 1000.0f); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index f039bc42d6..493cd260ec 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -219,7 +219,7 @@ int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { RadioLibTime_t elapsed = this->mod->hal->micros() - start; // update data rate - this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0); + this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000000.0f); return(finishTransmit()); } @@ -238,7 +238,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (RadioLibTime_t)(symbolLength * 100.0); + timeout = (RadioLibTime_t)(symbolLength * 100.0f); } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) @@ -246,8 +246,8 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { if(len == 0) { maxLen = 0xFF; } - float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; - timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); + float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0f * 32.0f) / (float)this->bitRate; + timeout = (RadioLibTime_t)(((maxLen * 8.0f) / brBps) * 1000.0f * 5.0f); } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { // this modem cannot receive @@ -261,7 +261,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start reception - uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 30.52); + uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0f) / 30.52f); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); @@ -667,22 +667,22 @@ int16_t LR11x0::setBandwidth(float bw, bool high) { // ensure byte conversion doesn't overflow if (high) { - RADIOLIB_CHECK_RANGE(bw, 203.125, 815.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 203.125f, 815.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - if(fabsf(bw - 203.125) <= 0.001) { + if(fabsf(bw - 203.125f) <= 0.001f) { this->bandwidth = RADIOLIB_LR11X0_LORA_BW_203_125; - } else if(fabsf(bw - 406.25) <= 0.001) { + } else if(fabsf(bw - 406.25f) <= 0.001f) { this->bandwidth = RADIOLIB_LR11X0_LORA_BW_406_25; - } else if(fabsf(bw - 812.5) <= 0.001) { + } else if(fabsf(bw - 812.5f) <= 0.001f) { this->bandwidth = RADIOLIB_LR11X0_LORA_BW_812_50; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); } } else { - RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); // check allowed bandwidth values - uint8_t bw_div2 = bw / 2 + 0.01; + uint8_t bw_div2 = bw / 2 + 0.01f; switch (bw_div2) { case 31: // 62.5: this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5; @@ -773,7 +773,7 @@ int16_t LR11x0::setSyncWord(uint8_t syncWord) { } int16_t LR11x0::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; @@ -785,7 +785,7 @@ int16_t LR11x0::setBitRate(float br) { // set bit rate value // TODO implement fractional bit rate configuration - this->bitRate = br * 1000.0; + this->bitRate = br * 1000.0f; return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } @@ -800,12 +800,12 @@ int16_t LR11x0::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 0.6; + if(freqDev < 0.0f) { + newFreqDev = 0.6f; } - RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); - this->frequencyDev = newFreqDev * 1000.0; + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + this->frequencyDev = newFreqDev * 1000.0f; return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } @@ -824,47 +824,47 @@ int16_t LR11x0::setRxBandwidth(float rxBw) { }*/ // check allowed receiver bandwidth values - if(fabsf(rxBw - 4.8) <= 0.001) { + if(fabsf(rxBw - 4.8f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8; - } else if(fabsf(rxBw - 5.8) <= 0.001) { + } else if(fabsf(rxBw - 5.8f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8; - } else if(fabsf(rxBw - 7.3) <= 0.001) { + } else if(fabsf(rxBw - 7.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3; - } else if(fabsf(rxBw - 9.7) <= 0.001) { + } else if(fabsf(rxBw - 9.7f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7; - } else if(fabsf(rxBw - 11.7) <= 0.001) { + } else if(fabsf(rxBw - 11.7f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7; - } else if(fabsf(rxBw - 14.6) <= 0.001) { + } else if(fabsf(rxBw - 14.6f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6; - } else if(fabsf(rxBw - 19.5) <= 0.001) { + } else if(fabsf(rxBw - 19.5f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5; - } else if(fabsf(rxBw - 23.4) <= 0.001) { + } else if(fabsf(rxBw - 23.4f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4; - } else if(fabsf(rxBw - 29.3) <= 0.001) { + } else if(fabsf(rxBw - 29.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3; - } else if(fabsf(rxBw - 39.0) <= 0.001) { + } else if(fabsf(rxBw - 39.0f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0; - } else if(fabsf(rxBw - 46.9) <= 0.001) { + } else if(fabsf(rxBw - 46.9f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9; - } else if(fabsf(rxBw - 58.6) <= 0.001) { + } else if(fabsf(rxBw - 58.6f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6; - } else if(fabsf(rxBw - 78.2) <= 0.001) { + } else if(fabsf(rxBw - 78.2f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2; - } else if(fabsf(rxBw - 93.8) <= 0.001) { + } else if(fabsf(rxBw - 93.8f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8; - } else if(fabsf(rxBw - 117.3) <= 0.001) { + } else if(fabsf(rxBw - 117.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3; - } else if(fabsf(rxBw - 156.2) <= 0.001) { + } else if(fabsf(rxBw - 156.2f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2; - } else if(fabsf(rxBw - 187.2) <= 0.001) { + } else if(fabsf(rxBw - 187.2f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2; - } else if(fabsf(rxBw - 234.3) <= 0.001) { + } else if(fabsf(rxBw - 234.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3; - } else if(fabsf(rxBw - 312.0) <= 0.001) { + } else if(fabsf(rxBw - 312.0f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0; - } else if(fabsf(rxBw - 373.6) <= 0.001) { + } else if(fabsf(rxBw - 373.6f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6; - } else if(fabsf(rxBw - 467.0) <= 0.001) { + } else if(fabsf(rxBw - 467.0f) <= 0.001f) { this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0; } else { return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); @@ -1104,13 +1104,13 @@ int16_t LR11x0::checkDataRate(DataRate_t dr) { RADIOLIB_ASSERT(state); if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); @@ -1158,28 +1158,28 @@ int16_t LR11x0::setTCXO(float voltage, uint32_t delay) { } // check 0 V disable - if(fabsf(voltage - 0.0) <= 0.001) { + if(fabsf(voltage - 0.0f) <= 0.001f) { setTcxoMode(0, 0); return(reset()); } // check allowed voltage values uint8_t tune = 0; - if(fabsf(voltage - 1.6) <= 0.001) { + if(fabsf(voltage - 1.6f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6; - } else if(fabsf(voltage - 1.7) <= 0.001) { + } else if(fabsf(voltage - 1.7f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7; - } else if(fabsf(voltage - 1.8) <= 0.001) { + } else if(fabsf(voltage - 1.8f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8; - } else if(fabsf(voltage - 2.2) <= 0.001) { + } else if(fabsf(voltage - 2.2f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2; - } else if(fabsf(voltage - 2.4) <= 0.001) { + } else if(fabsf(voltage - 2.4f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4; - } else if(fabsf(voltage - 2.7) <= 0.001) { + } else if(fabsf(voltage - 2.7f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7; - } else if(fabsf(voltage - 3.0) <= 0.001) { + } else if(fabsf(voltage - 3.0f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0; - } else if(fabsf(voltage - 3.3) <= 0.001) { + } else if(fabsf(voltage - 3.3f) <= 0.001f) { tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3; } else { return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); @@ -1353,7 +1353,7 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); } else { // long interleaving - abandon hope all ye who enter here @@ -1362,7 +1362,7 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { } // get time-on-air in us - return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0); + return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0f); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { return(((uint32_t)len * 8 * 1000000UL) / this->bitRate); @@ -2082,7 +2082,7 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { RADIOLIB_ASSERT(state); // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0) { + if(!this->XTAL && tcxoVoltage > 0.0f) { state = setTCXO(tcxoVoltage); RADIOLIB_ASSERT(state); } @@ -2759,7 +2759,7 @@ int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - if(symbolLength >= 16.0) { + if(symbolLength >= 16.0f) { this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED; } else { this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 42685a9f94..68c052ddd9 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -233,7 +233,7 @@ #define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC #define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC #define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything -#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0) +#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0f) // RADIOLIB_LR11X0_CMD_SET_REG_MODE #define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes @@ -409,7 +409,7 @@ #define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz #define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz #define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215) // 31 0 LR FHSS bit rate: 488.28215 bps +#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps #define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw #define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0 #define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7 diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index f87270be64..cbbda86f40 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -122,7 +122,7 @@ int16_t RF69::transmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t RF69::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0); + RadioLibTime_t timeout = 500 + (1.0f/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0f); // start reception int16_t state = startReceive(); @@ -523,9 +523,9 @@ int16_t RF69::setOokPeakThresholdDecrement(uint8_t value) { int16_t RF69::setFrequency(float freq) { // check allowed frequency range - if(!(((freq > 290.0) && (freq < 340.0)) || - ((freq > 431.0) && (freq < 510.0)) || - ((freq > 862.0) && (freq < 1020.0)))) { + if(!(((freq > 290.0f) && (freq < 340.0f)) || + ((freq > 431.0f) && (freq < 510.0f)) || + ((freq > 862.0f) && (freq < 1020.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } @@ -559,7 +559,7 @@ int16_t RF69::getFrequency(float *freq) { int16_t RF69::setBitRate(float br) { // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine - RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); // check bitrate-bandwidth ratio if(!(br < 2000 * this->rxBandwidth)) { @@ -592,8 +592,8 @@ int16_t RF69::setRxBandwidth(float rxBw) { // calculate exponent and mantissa values for receiver bandwidth for(int8_t e = 7; e >= 0; e--) { for(int8_t m = 2; m >= 0; m--) { - float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2)))); - if(fabsf(rxBw - (point / 1000.0)) <= 0.1) { + float point = (RADIOLIB_RF69_CRYSTAL_FREQ * 1000000.0f)/(((4 * m) + 16) * ((uint32_t)1 << (e + (this->ookEnabled ? 3 : 2)))); + if(fabsf(rxBw - (point / 1000.0f)) <= 0.1f) { // set Rx bandwidth state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RX_BW, (m << 3) | e, 4, 0); if(state == RADIOLIB_ERR_NONE) { @@ -610,8 +610,8 @@ int16_t RF69::setRxBandwidth(float rxBw) { int16_t RF69::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 0.6; + if(freqDev < 0.0f) { + newFreqDev = 0.6f; } // check frequency deviation range @@ -648,7 +648,7 @@ int16_t RF69::getFrequencyDeviation(float *freqDev) { // calculate frequency deviation from raw value obtained from register // Fdev = Fstep * Fdev(13:0) (pag. 20 of datasheet) - *freqDev = (1000.0 * fdev * RADIOLIB_RF69_CRYSTAL_FREQ) / + *freqDev = (1000.0f * fdev * RADIOLIB_RF69_CRYSTAL_FREQ) / (uint32_t(1) << RADIOLIB_RF69_DIV_EXPONENT); return(RADIOLIB_ERR_NONE); @@ -928,9 +928,9 @@ float RF69::getRSSI() { } int16_t RF69::setRSSIThreshold(float dbm) { - RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); + RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); - return this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); + return this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0); } void RF69::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 00ea43b935..d30e8c3112 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -12,7 +12,7 @@ // RF69 physical layer properties #define RADIOLIB_RF69_FREQUENCY_STEP_SIZE 61.03515625 #define RADIOLIB_RF69_MAX_PACKET_LENGTH 64 -#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0 +#define RADIOLIB_RF69_CRYSTAL_FREQ 32.0f #define RADIOLIB_RF69_DIV_EXPONENT 19 // RF69 register map diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index 23eb72c6f9..81edc00ed7 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -93,11 +93,11 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po int16_t SX1233::setBitRate(float br) { // check high bit-rate operation uint8_t pllBandwidth = RADIOLIB_SX1233_PLL_BW_LOW_BIT_RATE; - if((fabsf(br - 500.0f) < 0.1) || (fabsf(br - 600.0f) < 0.1)) { + if((fabsf(br - 500.0f) < 0.1f) || (fabsf(br - 600.0f) < 0.1f)) { pllBandwidth = RADIOLIB_SX1233_PLL_BW_HIGH_BIT_RATE; } else { // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine - RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); } diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 426c2d0542..20bd436722 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -72,7 +72,7 @@ int16_t SX1262::setFrequency(float freq) { } int16_t SX1262::setFrequency(float freq, bool skipCalibration) { - RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 150.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // check if we need to recalibrate image if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) { diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 7de82a2245..f9ef606a6f 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -73,7 +73,7 @@ int16_t SX1268::setFrequency(float freq) { /// \todo integers only (all modules - frequency, data rate, bandwidth etc.) int16_t SX1268::setFrequency(float freq, bool skipCalibration) { - RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 410.0f, 810.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // check if we need to recalibrate image if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) { diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f14e0f870c..393a8ed0fc 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -243,7 +243,7 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // update data rate RadioLibTime_t elapsed = this->mod->hal->millis() - start; - this->dataRateMeasured = (len*8.0)/((float)elapsed/1000.0); + this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000.0f); return(finishTransmit()); } @@ -260,7 +260,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { // calculate timeout (100 LoRa symbols, the default for SX127x series) float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (RadioLibTime_t)(symbolLength * 100.0); + timeout = (RadioLibTime_t)(symbolLength * 100.0f); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { // calculate timeout (500 % of expected time-one-air) @@ -268,8 +268,8 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { if(len == 0) { maxLen = 0xFF; } - float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate; - timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0); + float brBps = (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (float)this->bitRate; + timeout = (RadioLibTime_t)(((maxLen * 8.0f) / brBps) * 1000.0f * 5.0f); } else { return(RADIOLIB_ERR_UNKNOWN); @@ -279,7 +279,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start reception - uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 15.625); + uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0f) / 15.625f); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); @@ -854,10 +854,10 @@ int16_t SX126x::setBandwidth(float bw) { } // ensure byte conversion doesn't overflow - RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); // check allowed bandwidth values - uint8_t bw_div2 = bw / 2 + 0.01; + uint8_t bw_div2 = bw / 2 + 0.01f; switch (bw_div2) { case 3: // 7.8: this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8; @@ -942,7 +942,7 @@ int16_t SX126x::setCurrentLimit(float currentLimit) { } // calculate raw value - uint8_t rawLimit = (uint8_t)(currentLimit / 2.5); + uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f); // update register return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1)); @@ -954,7 +954,7 @@ float SX126x::getCurrentLimit() { readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); // return the actual value - return((float)ocp * 2.5); + return((float)ocp * 2.5f); } int16_t SX126x::setPreambleLength(size_t preambleLength) { @@ -986,14 +986,14 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 0.6; + if(freqDev < 0.0f) { + newFreqDev = 0.6f; } - RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // calculate raw frequency deviation value - uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0)); + uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f)); // check modulation parameters this->frequencyDev = freqDevRaw; @@ -1010,11 +1010,11 @@ int16_t SX126x::setBitRate(float br) { } if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); } // calculate raw bit rate value - uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); + uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f)); // check modulation parameters this->bitRate = brRaw; @@ -1067,13 +1067,13 @@ int16_t SX126x::checkDataRate(DataRate_t dr) { // select interpretation based on active modem uint8_t modem = this->getPacketType(); if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); @@ -1095,47 +1095,47 @@ int16_t SX126x::setRxBandwidth(float rxBw) { this->rxBandwidthKhz = rxBw; // check allowed receiver bandwidth values - if(fabsf(rxBw - 4.8) <= 0.001) { + if(fabsf(rxBw - 4.8f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8; - } else if(fabsf(rxBw - 5.8) <= 0.001) { + } else if(fabsf(rxBw - 5.8f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8; - } else if(fabsf(rxBw - 7.3) <= 0.001) { + } else if(fabsf(rxBw - 7.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3; - } else if(fabsf(rxBw - 9.7) <= 0.001) { + } else if(fabsf(rxBw - 9.7f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7; - } else if(fabsf(rxBw - 11.7) <= 0.001) { + } else if(fabsf(rxBw - 11.7f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7; - } else if(fabsf(rxBw - 14.6) <= 0.001) { + } else if(fabsf(rxBw - 14.6f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6; - } else if(fabsf(rxBw - 19.5) <= 0.001) { + } else if(fabsf(rxBw - 19.5f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5; - } else if(fabsf(rxBw - 23.4) <= 0.001) { + } else if(fabsf(rxBw - 23.4f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4; - } else if(fabsf(rxBw - 29.3) <= 0.001) { + } else if(fabsf(rxBw - 29.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3; - } else if(fabsf(rxBw - 39.0) <= 0.001) { + } else if(fabsf(rxBw - 39.0f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0; - } else if(fabsf(rxBw - 46.9) <= 0.001) { + } else if(fabsf(rxBw - 46.9f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9; - } else if(fabsf(rxBw - 58.6) <= 0.001) { + } else if(fabsf(rxBw - 58.6f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6; - } else if(fabsf(rxBw - 78.2) <= 0.001) { + } else if(fabsf(rxBw - 78.2f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2; - } else if(fabsf(rxBw - 93.8) <= 0.001) { + } else if(fabsf(rxBw - 93.8f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8; - } else if(fabsf(rxBw - 117.3) <= 0.001) { + } else if(fabsf(rxBw - 117.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3; - } else if(fabsf(rxBw - 156.2) <= 0.001) { + } else if(fabsf(rxBw - 156.2f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; - } else if(fabsf(rxBw - 187.2) <= 0.001) { + } else if(fabsf(rxBw - 187.2f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2; - } else if(fabsf(rxBw - 234.3) <= 0.001) { + } else if(fabsf(rxBw - 234.3f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3; - } else if(fabsf(rxBw - 312.0) <= 0.001) { + } else if(fabsf(rxBw - 312.0f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0; - } else if(fabsf(rxBw - 373.6) <= 0.001) { + } else if(fabsf(rxBw - 373.6f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6; - } else if(fabsf(rxBw - 467.0) <= 0.001) { + } else if(fabsf(rxBw - 467.0f) <= 0.001f) { this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0; } else { return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); @@ -1373,7 +1373,7 @@ float SX126x::getRSSI(bool packet) { // get instantaneous RSSI value uint8_t rssiRaw = 0; this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, &rssiRaw, 1); - return((float)rssiRaw / (-2.0)); + return((float)rssiRaw / (-2.0f)); } } @@ -1418,9 +1418,9 @@ float SX126x::getFrequencyError() { // frequency error is negative efe |= (uint32_t) 0xFFF00000; efe = ~efe + 1; - error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0; + error = 1.55f * (float) efe / (1600.0f / (float) this->bandwidthKhz) * -1.0f; } else { - error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz); + error = 1.55f * (float) efe / (1600.0f / (float) this->bandwidthKhz); } return(error); @@ -1528,7 +1528,7 @@ RadioLibTime_t SX126x::getTimeOnAir(size_t len) { RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) { // the timeout value is given in units of 15.625 microseconds // the calling function should provide some extra width, as this number of units is truncated to integer - RadioLibTime_t timeout = timeoutUs / 15.625; + RadioLibTime_t timeout = timeoutUs / 15.625f; return(timeout); } @@ -1769,34 +1769,34 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { } // check 0 V disable - if(fabsf(voltage - 0.0) <= 0.001) { + if(fabsf(voltage - 0.0f) <= 0.001f) { return(reset(true)); } // check alowed voltage values uint8_t data[4]; - if(fabsf(voltage - 1.6) <= 0.001) { + if(fabsf(voltage - 1.6f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6; - } else if(fabsf(voltage - 1.7) <= 0.001) { + } else if(fabsf(voltage - 1.7f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7; - } else if(fabsf(voltage - 1.8) <= 0.001) { + } else if(fabsf(voltage - 1.8f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8; - } else if(fabsf(voltage - 2.2) <= 0.001) { + } else if(fabsf(voltage - 2.2f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2; - } else if(fabsf(voltage - 2.4) <= 0.001) { + } else if(fabsf(voltage - 2.4f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4; - } else if(fabsf(voltage - 2.7) <= 0.001) { + } else if(fabsf(voltage - 2.7f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7; - } else if(fabsf(voltage - 3.0) <= 0.001) { + } else if(fabsf(voltage - 3.0f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0; - } else if(fabsf(voltage - 3.3) <= 0.001) { + } else if(fabsf(voltage - 3.3f) <= 0.001f) { data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3; } else { return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); } // calculate delay - uint32_t delayValue = (float)delay / 15.625; + uint32_t delayValue = (float)delay / 15.625f; data[1] = (uint8_t)((delayValue >> 16) & 0xFF); data[2] = (uint8_t)((delayValue >> 8) & 0xFF); data[3] = (uint8_t)(delayValue & 0xFF); @@ -2040,7 +2040,7 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - if(symbolLength >= 16.0) { + if(symbolLength >= 16.0f) { this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; } else { this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; @@ -2126,7 +2126,7 @@ int16_t SX126x::fixSensitivity() { RADIOLIB_ASSERT(state); // fix the value for LoRa with 500 kHz bandwidth - if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabsf(this->bandwidthKhz - 500.0) <= 0.001)) { + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabsf(this->bandwidthKhz - 500.0f) <= 0.001f)) { sensitivityConfig &= 0xFB; } else { sensitivityConfig |= 0x04; @@ -2232,7 +2232,7 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) RADIOLIB_ASSERT(state); // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0) { + if(!this->XTAL && tcxoVoltage > 0.0f) { state = setTCXO(tcxoVoltage); RADIOLIB_ASSERT(state); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 5fba5a38b6..4784e675c6 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -14,7 +14,7 @@ // SX126X physical layer properties #define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 #define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0f #define RADIOLIB_SX126X_DIV_EXPONENT 25 // SX126X SPI commands @@ -201,7 +201,7 @@ #define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB #define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 #define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 -#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0) +#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0f) //RADIOLIB_SX126X_CMD_SET_PA_CONFIG #define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 4b118d624f..48f01a6572 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -83,7 +83,7 @@ void SX1272::reset() { } int16_t SX1272::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 860.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 860.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); @@ -102,11 +102,11 @@ int16_t SX1272::setBandwidth(float bw) { uint8_t newBandwidth; // check allowed bandwidth values - if(fabsf(bw - 125.0) <= 0.001) { + if(fabsf(bw - 125.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1272_BW_125_00_KHZ; - } else if(fabsf(bw - 250.0) <= 0.001) { + } else if(fabsf(bw - 250.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1272_BW_250_00_KHZ; - } else if(fabsf(bw - 500.0) <= 0.001) { + } else if(fabsf(bw - 500.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1272_BW_500_00_KHZ; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); @@ -121,7 +121,7 @@ int16_t SX1272::setBandwidth(float bw) { if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); - if(symbolLength >= 16.0) { + if(symbolLength >= 16.0f) { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); @@ -175,7 +175,7 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); - if(symbolLength >= 16.0) { + if(symbolLength >= 16.0f) { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); @@ -258,15 +258,15 @@ int16_t SX1272::checkDataRate(DataRate_t dr) { // select interpretation based on active modem int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 6a3af96d57..11aace90d1 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -98,15 +98,15 @@ int16_t SX1273::checkDataRate(DataRate_t dr) { // select interpretation based on active modem int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 062d11b058..819e5188bb 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -69,7 +69,7 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1276::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 59729e898a..758daf51bc 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -69,7 +69,7 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1277::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); @@ -140,15 +140,15 @@ int16_t SX1277::checkDataRate(DataRate_t dr) { // select interpretation based on active modem int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index df76e56b48..141a002998 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -83,7 +83,7 @@ void SX1278::reset() { } int16_t SX1278::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0f, 525.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); @@ -102,25 +102,25 @@ int16_t SX1278::setBandwidth(float bw) { uint8_t newBandwidth; // check allowed bandwidth values - if(fabsf(bw - 7.8) <= 0.001) { + if(fabsf(bw - 7.8f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ; - } else if(fabsf(bw - 10.4) <= 0.001) { + } else if(fabsf(bw - 10.4f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ; - } else if(fabsf(bw - 15.6) <= 0.001) { + } else if(fabsf(bw - 15.6f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ; - } else if(fabsf(bw - 20.8) <= 0.001) { + } else if(fabsf(bw - 20.8f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ; - } else if(fabsf(bw - 31.25) <= 0.001) { + } else if(fabsf(bw - 31.25f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ; - } else if(fabsf(bw - 41.7) <= 0.001) { + } else if(fabsf(bw - 41.7f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ; - } else if(fabsf(bw - 62.5) <= 0.001) { + } else if(fabsf(bw - 62.5f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ; - } else if(fabsf(bw - 125.0) <= 0.001) { + } else if(fabsf(bw - 125.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ; - } else if(fabsf(bw - 250.0) <= 0.001) { + } else if(fabsf(bw - 250.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ; - } else if(fabsf(bw - 500.0) <= 0.001) { + } else if(fabsf(bw - 500.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); @@ -135,7 +135,7 @@ int16_t SX1278::setBandwidth(float bw) { if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); - if(symbolLength >= 16.0) { + if(symbolLength >= 16.0f) { state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); @@ -189,7 +189,7 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); - if(symbolLength >= 16.0) { + if(symbolLength >= 16.0f) { state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); @@ -272,15 +272,15 @@ int16_t SX1278::checkDataRate(DataRate_t dr) { // select interpretation based on active modem int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); - if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0 <= 250.0) && (dr.fsk.freqDev <= 200.0))) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); @@ -476,7 +476,7 @@ float SX1278::getRSSI() { float SX1278::getRSSI(bool packet, bool skipReceive) { int16_t offset = -157; - if(frequency < 868.0) { + if(frequency < 868.0f) { offset = -164; } return(SX127x::getRSSI(packet, skipReceive, offset)); @@ -606,11 +606,11 @@ void SX1278::errataFix(bool rx) { // sensitivity optimization for 500kHz bandwidth // see SX1276/77/78 Errata, section 2.1 for details Module* mod = this->getMod(); - if(fabsf(SX127x::bandwidth - 500.0) <= 0.001) { - if((frequency >= 862.0) && (frequency <= 1020.0)) { + if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) { + if((frequency >= 862.0f) && (frequency <= 1020.0f)) { mod->SPIwriteRegister(0x36, 0x02); mod->SPIwriteRegister(0x3a, 0x64); - } else if((frequency >= 410.0) && (frequency <= 525.0)) { + } else if((frequency >= 410.0f) && (frequency <= 525.0f)) { mod->SPIwriteRegister(0x36, 0x02); mod->SPIwriteRegister(0x3a, 0x7F); } @@ -622,49 +622,49 @@ void SX1278::errataFix(bool rx) { // figure out what we need to set uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 }; float rxFreq = frequency; - if(fabsf(SX127x::bandwidth - 7.8) <= 0.001) { + if(fabsf(SX127x::bandwidth - 7.8f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x48; fixedRegs[2] = 0x00; - rxFreq += 0.00781; - } else if(fabsf(SX127x::bandwidth - 10.4) <= 0.001) { + rxFreq += 0.00781f; + } else if(fabsf(SX127x::bandwidth - 10.4f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; - rxFreq += 0.01042; - } else if(fabsf(SX127x::bandwidth - 15.6) <= 0.001) { + rxFreq += 0.01042f; + } else if(fabsf(SX127x::bandwidth - 15.6f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; - rxFreq += 0.01562; - } else if(fabsf(SX127x::bandwidth - 20.8) <= 0.001) { + rxFreq += 0.01562f; + } else if(fabsf(SX127x::bandwidth - 20.8f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; - rxFreq += 0.02083; - } else if(fabsf(SX127x::bandwidth - 31.25) <= 0.001) { + rxFreq += 0.02083f; + } else if(fabsf(SX127x::bandwidth - 31.25f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; - rxFreq += 0.03125; - } else if(fabsf(SX127x::bandwidth - 41.7) <= 0.001) { + rxFreq += 0.03125f; + } else if(fabsf(SX127x::bandwidth - 41.7f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x44; fixedRegs[2] = 0x00; - rxFreq += 0.04167; - } else if(fabsf(SX127x::bandwidth - 62.5) <= 0.001) { + rxFreq += 0.04167f; + } else if(fabsf(SX127x::bandwidth - 62.5f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabsf(SX127x::bandwidth - 125.0) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 125.0f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabsf(SX127x::bandwidth - 250.0) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 250.0f) <= 0.001f) { fixedRegs[0] = 0b00000000; fixedRegs[1] = 0x40; fixedRegs[2] = 0x00; - } else if(fabsf(SX127x::bandwidth - 500.0) <= 0.001) { + } else if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) { fixedRegs[0] = 0b10000000; fixedRegs[1] = mod->SPIreadRegister(0x2F); fixedRegs[2] = mod->SPIreadRegister(0x30); diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index a91273fd05..df87c388dc 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -69,7 +69,7 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1279::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 137.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 9774b3a4c3..b94bfdada2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -204,7 +204,7 @@ int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // update data rate RadioLibTime_t elapsed = this->mod->hal->millis() - start; - this->dataRate = (len*8.0)/((float)elapsed/1000.0); + this->dataRate = (len*8.0f)/((float)elapsed/1000.0f); return(finishTransmit()); } @@ -224,7 +224,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RadioLibTime_t timeout = 0; if(this->mod->getGpio() == RADIOLIB_NC) { float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - timeout = (RadioLibTime_t)(symbolLength * 100.0); + timeout = (RadioLibTime_t)(symbolLength * 100.0f); } // wait for packet reception or timeout @@ -844,14 +844,14 @@ float SX127x::getFrequencyError(bool autoCorrect) { // frequency error is negative raw |= (uint32_t)0xFFF00000; raw = ~raw + 1; - error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0) * -1.0; + error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f) * -1.0f; } else { - error = (((float)raw * (float)base)/32000000.0) * (this->bandwidth/500.0); + error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f); } if(autoCorrect) { // adjust LoRa modem data rate - float ppmOffset = 0.95 * (error/32.0); + float ppmOffset = 0.95f * (error/32.0f); this->mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset); } @@ -870,9 +870,9 @@ float SX127x::getFrequencyError(bool autoCorrect) { // frequency error is negative raw |= (uint32_t)0xFFF00000; raw = ~raw + 1; - error = (float)raw * (32000000.0 / (float)(base << 19)) * -1.0; + error = (float)raw * (32000000.0f / (float)(base << 19)) * -1.0f; } else { - error = (float)raw * (32000000.0 / (float)(base << 19)); + error = (float)raw * (32000000.0f / (float)(base << 19)); } return(error); @@ -894,7 +894,7 @@ float SX127x::getAFCError() raw |= this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB); uint32_t base = 1; - return raw * (32000000.0 / (float)(base << 19)); + return raw * (32000000.0f / (float)(base << 19)); } float SX127x::getSNR() { @@ -921,9 +921,9 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { // check allowed bit rate // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine if(ookEnabled) { - RADIOLIB_CHECK_RANGE(br, 0.5, 32.768002, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 + RADIOLIB_CHECK_RANGE(br, 0.5f, 32.768002f, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002 } else { - RADIOLIB_CHECK_RANGE(br, 0.5, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); } // set mode to STANDBY @@ -931,13 +931,13 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { RADIOLIB_ASSERT(state); // set bit rate - uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br; + uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br; state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0); state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0); // set fractional part of bit rate if(!ookEnabled) { - float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRateRaw; + float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br) - (float)bitRateRaw; uint8_t bitRateFrac = bitRateRem * 16; state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0); } @@ -956,12 +956,12 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 0.6; + if(freqDev < 0.0f) { + newFreqDev = 0.6f; } // check frequency deviation range - if(!((newFreqDev + this->bitRate/2.0 <= 250.0) && (freqDev <= 200.0))) { + if(!((newFreqDev + this->bitRate/2.0f <= 250.0f) && (freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } @@ -981,8 +981,8 @@ uint8_t SX127x::calculateBWManExp(float bandwidth) { for(uint8_t e = 7; e >= 1; e--) { for(int8_t m = 2; m >= 0; m--) { - float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); - if(fabsf(bandwidth - ((point / 1000.0) + 0.05)) <= 0.5) { + float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0f)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2))); + if(fabsf(bandwidth - ((point / 1000.0f) + 0.05f)) <= 0.5f) { return((m << 3) | e); } } @@ -996,7 +996,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) { return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // set mode to STANDBY int16_t state = setMode(RADIOLIB_SX127X_STANDBY); @@ -1012,7 +1012,7 @@ int16_t SX127x::setAFCBandwidth(float rxBw) { return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // set mode to STANDBY int16_t state = setMode(RADIOLIB_SX127X_STANDBY); @@ -1251,7 +1251,7 @@ float SX127x::getNumSymbols(size_t len) { // get Low Data Rate optimization flag float de = 0; - if (symbolLength >= 16.0) { + if (symbolLength >= 16.0f) { de = 1; } @@ -1265,7 +1265,7 @@ float SX127x::getNumSymbols(size_t len) { float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); // get number of payload symbols - float n_pay = 8.0 + RADIOLIB_MAX(ceilf((8.0 * (float) len - 4.0 * (float) this->spreadingFactor + 28.0 + 16.0 * crc - 20.0 * ih) / (4.0 * (float) this->spreadingFactor - 8.0 * de)) * (float) this->codingRate, 0.0); + float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) this->spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) this->spreadingFactor - 8.0f * de)) * (float) this->codingRate, 0.0f); // add 4.25 symbols for the sync return(n_pre + n_pay + 4.25f); @@ -1301,7 +1301,7 @@ RadioLibTime_t SX127x::getTimeOnAir(size_t len) { } // calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) - return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0)); + return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0f)) * 1000000.0f)); } return(RADIOLIB_ERR_UNKNOWN); @@ -1448,9 +1448,9 @@ int16_t SX127x::setCrcFiltering(bool enable) { } int16_t SX127x::setRSSIThreshold(float dbm) { - RADIOLIB_CHECK_RANGE(dbm, -127.5, 0, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); + RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD); - return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0 * dbm), 7, 0); + return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0); } int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { @@ -1830,7 +1830,7 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { // spread-spectrum modulation signal can be received below noise floor // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value float lastPacketSNR = SX127x::getSNR(); - if(lastPacketSNR < 0.0) { + if(lastPacketSNR < 0.0f) { lastPacketRSSI += lastPacketSNR; } return(lastPacketRSSI); @@ -1850,7 +1850,7 @@ float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) { } // read the value for FSK - float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0; + float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0f; // set mode back to standby if(!skipReceive) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 593f27e499..7e37162ca5 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -13,7 +13,7 @@ #define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 #define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 #define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 -#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0 +#define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0f #define RADIOLIB_SX127X_DIV_EXPONENT 19 // SX127x series common LoRa registers diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index fae3516bf5..b5d8ee0299 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -178,7 +178,7 @@ float SX1280::getRangingResult() { // calculate the real result uint32_t uraw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; int32_t raw = (uraw & ((1UL << 23) - 1)) | (uraw >> 23 << 31); - return((float)raw * 150.0 / (4.096 * this->bandwidthKhz)); + return((float)raw * 150.0f / (4.096f * this->bandwidthKhz)); } #endif diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 139fac55c7..7b47ffb957 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -364,7 +364,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); // start reception - uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); + uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625f); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); @@ -745,7 +745,7 @@ int16_t SX128x::getChannelScanResult() { } int16_t SX128x::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 2400.0f, 2500.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // calculate raw value uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_SX128X_CRYSTAL_FREQ; @@ -757,21 +757,21 @@ int16_t SX128x::setBandwidth(float bw) { uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { // check range for LoRa - RADIOLIB_CHECK_RANGE(bw, 203.125, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 203.125f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { // check range for ranging - RADIOLIB_CHECK_RANGE(bw, 406.25, 1625.0, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(bw, 406.25f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); } else { return(RADIOLIB_ERR_WRONG_MODEM); } - if(fabsf(bw - 203.125) <= 0.001) { + if(fabsf(bw - 203.125f) <= 0.001f) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125; - } else if(fabsf(bw - 406.25) <= 0.001) { + } else if(fabsf(bw - 406.25f) <= 0.001f) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25; - } else if(fabsf(bw - 812.5) <= 0.001) { + } else if(fabsf(bw - 812.5f) <= 0.001f) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50; - } else if(fabsf(bw - 1625.0) <= 0.001) { + } else if(fabsf(bw - 1625.0f) <= 0.001f) { this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); @@ -1020,21 +1020,21 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 62.5; + if(freqDev < 0.0f) { + newFreqDev = 62.5f; } - RADIOLIB_CHECK_RANGE(newFreqDev, 62.5, 1000.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols - if(newFreqDev == 0.0) { + if(newFreqDev == 0.0f) { this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35; this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3; return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); } // update modulation parameters - uint8_t modInd = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0); + uint8_t modInd = (uint8_t)((8.0f * (newFreqDev / (float)this->bitRateKbps)) - 1.0f); if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) { return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); } @@ -1293,7 +1293,7 @@ float SX128x::getRSSI() { uint8_t rssiSync = packetStatus[0]; float rssiMeasured = -1.0 * rssiSync/2.0; float snr = getSNR(); - if(snr <= 0.0) { + if(snr <= 0.0f) { return(rssiMeasured - snr); } else { return(rssiMeasured); @@ -1310,7 +1310,7 @@ float SX128x::getRSSI(bool packet) { // get instantaneous RSSI value uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3); - return ((float)data[0] / (-2.0)); + return ((float)data[0] / (-2.0f)); } else { return this->getRSSI(); } @@ -1332,7 +1332,7 @@ float SX128x::getSNR() { if(snr < 128) { return(snr/4.0); } else { - return((snr - 256)/4.0); + return((snr - 256)/4.0f); } } @@ -1361,9 +1361,9 @@ float SX128x::getFrequencyError() { // frequency error is negative efe |= (uint32_t) 0xFFF00000; efe = ~efe + 1; - error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz) * -1.0; + error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz) * -1.0f; } else { - error = 1.55 * (float) efe / (1600.0 / (float) this->bandwidthKhz); + error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz); } return(error); @@ -1436,7 +1436,7 @@ RadioLibTime_t SX128x::getTimeOnAir(size_t len) { uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); } else { // long interleaving - abandon hope all ye who enter here @@ -1445,7 +1445,7 @@ RadioLibTime_t SX128x::getTimeOnAir(size_t len) { } // get time-on-air in us - return(((uint32_t(1) << sf) / this->bandwidthKhz) * N_symbol * 1000.0); + return(((uint32_t(1) << sf) / this->bandwidthKhz) * N_symbol * 1000.0f); } else { return(((uint32_t)len * 8 * 1000) / this->bitRateKbps); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index ae1d46876f..7a090db881 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -12,7 +12,7 @@ // SX128X physical layer properties #define RADIOLIB_SX128X_FREQUENCY_STEP_SIZE 198.3642578 #define RADIOLIB_SX128X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0 +#define RADIOLIB_SX128X_CRYSTAL_FREQ 52.0f #define RADIOLIB_SX128X_DIV_EXPONENT 18 // SX128X SPI commands diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index 7f9ed5fbe1..6470f5e5fc 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -22,7 +22,7 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po } int16_t Si4430::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 900.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency return(Si443x::setFrequencyRaw(freq)); diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 56690862fd..1725bb4303 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -22,7 +22,7 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po } int16_t Si4432::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, RADIOLIB_ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 240.0f, 930.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency return(Si443x::setFrequencyRaw(freq)); diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 4db2ffca9f..3e61488ea4 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -94,7 +94,7 @@ int16_t Si443x::transmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t Si443x::receive(uint8_t* data, size_t len) { // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0); + RadioLibTime_t timeout = 500 + (1.0f/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0f); // start reception int16_t state = startReceive(); @@ -153,7 +153,7 @@ int16_t Si443x::transmitDirect(uint32_t frf) { // check high/low band uint8_t bandSelect = RADIOLIB_SI443X_BAND_SELECT_LOW; uint8_t freqBand = (newFreq / 10) - 24; - if(newFreq >= 480.0) { + if(newFreq >= 480.0f) { bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; freqBand = (newFreq / 20) - 24; } @@ -343,19 +343,19 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { } int16_t Si443x::setBitRate(float br) { - RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.123f, 256.0f, RADIOLIB_ERR_INVALID_BIT_RATE); // check high data rate uint8_t dataRateMode = RADIOLIB_SI443X_LOW_DATA_RATE_MODE; uint8_t exp = 21; - if(br >= 30.0) { + if(br >= 30.0f) { // bit rate above 30 kbps dataRateMode = RADIOLIB_SI443X_HIGH_DATA_RATE_MODE; exp = 16; } // calculate raw data rate value - uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0; + uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0f; // update registers int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); @@ -376,14 +376,14 @@ int16_t Si443x::setBitRate(float br) { int16_t Si443x::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0) { - newFreqDev = 0.625; + if(freqDev < 0.0f) { + newFreqDev = 0.625f; } - RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 0.625f, 320.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); // calculate raw frequency deviation value - uint16_t fdev = (uint16_t)(newFreqDev / 0.625); + uint16_t fdev = (uint16_t)(newFreqDev / 0.625f); // update registers int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); @@ -397,7 +397,7 @@ int16_t Si443x::setFrequencyDeviation(float freqDev) { } int16_t Si443x::setRxBandwidth(float rxBw) { - RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 620.7f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH); // decide which approximation to use for decimation rate and filter tap calculation uint8_t bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_OFF; @@ -405,84 +405,84 @@ int16_t Si443x::setRxBandwidth(float rxBw) { uint8_t filterSet = RADIOLIB_SI443X_IF_FILTER_COEFF_SET; // this is the "well-behaved" section - can be linearly approximated - if((rxBw >= 2.6) && (rxBw <= 4.5)) { + if((rxBw >= 2.6f) && (rxBw <= 4.5f)) { decRate = 5; - filterSet = ((rxBw - 2.1429)/0.3250 + 0.5); - } else if((rxBw > 4.5) && (rxBw <= 8.8)) { + filterSet = ((rxBw - 2.1429f)/0.3250f + 0.5f); + } else if((rxBw > 4.5f) && (rxBw <= 8.8f)) { decRate = 4; - filterSet = ((rxBw - 3.9857)/0.6643 + 0.5); - } else if((rxBw > 8.8) && (rxBw <= 17.5)) { + filterSet = ((rxBw - 3.9857f)/0.6643f + 0.5f); + } else if((rxBw > 8.8f) && (rxBw <= 17.5f)) { decRate = 3; - filterSet = ((rxBw - 7.6714)/1.3536 + 0.5); - } else if((rxBw > 17.5) && (rxBw <= 34.7)) { + filterSet = ((rxBw - 7.6714f)/1.3536f + 0.5f); + } else if((rxBw > 17.5f) && (rxBw <= 34.7f)) { decRate = 2; - filterSet = ((rxBw - 15.2000)/2.6893 + 0.5); - } else if((rxBw > 34.7) && (rxBw <= 69.2)) { + filterSet = ((rxBw - 15.2000f)/2.6893f + 0.5f); + } else if((rxBw > 34.7f) && (rxBw <= 69.2f)) { decRate = 1; - filterSet = ((rxBw - 30.2430)/5.3679 + 0.5); - } else if((rxBw > 69.2) && (rxBw <= 137.9)) { + filterSet = ((rxBw - 30.2430f)/5.3679f + 0.5f); + } else if((rxBw > 69.2f) && (rxBw <= 137.9f)) { decRate = 0; - filterSet = ((rxBw - 60.286)/10.7000 + 0.5); + filterSet = ((rxBw - 60.286f)/10.7000f + 0.5f); // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess /// \todo float tolerance equality as macro? - } else if(fabsf(rxBw - 142.8) <= 0.001) { + } else if(fabsf(rxBw - 142.8f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 4; - } else if(fabsf(rxBw - 167.8) <= 0.001) { + } else if(fabsf(rxBw - 167.8f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 5; - } else if(fabsf(rxBw - 181.1) <= 0.001) { + } else if(fabsf(rxBw - 181.1f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 6; - } else if(fabsf(rxBw - 191.5) <= 0.001) { + } else if(fabsf(rxBw - 191.5f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 15; - } else if(fabsf(rxBw - 225.1) <= 0.001) { + } else if(fabsf(rxBw - 225.1f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 1; - } else if(fabsf(rxBw - 248.8) <= 0.001) { + } else if(fabsf(rxBw - 248.8f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 2; - } else if(fabsf(rxBw - 269.3) <= 0.001) { + } else if(fabsf(rxBw - 269.3f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 3; - } else if(fabsf(rxBw - 284.8) <= 0.001) { + } else if(fabsf(rxBw - 284.8f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 4; - } else if(fabsf(rxBw -335.5) <= 0.001) { + } else if(fabsf(rxBw -335.5f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 8; - } else if(fabsf(rxBw - 391.8) <= 0.001) { + } else if(fabsf(rxBw - 391.8f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 9; - } else if(fabsf(rxBw - 420.2) <= 0.001) { + } else if(fabsf(rxBw - 420.2f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 10; - } else if(fabsf(rxBw - 468.4) <= 0.001) { + } else if(fabsf(rxBw - 468.4f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 11; - } else if(fabsf(rxBw - 518.8) <= 0.001) { + } else if(fabsf(rxBw - 518.8f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 12; - } else if(fabsf(rxBw - 577.0) <= 0.001) { + } else if(fabsf(rxBw - 577.0f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 13; - } else if(fabsf(rxBw - 620.7) <= 0.001) { + } else if(fabsf(rxBw - 620.7f) <= 0.001f) { bypass = RADIOLIB_SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 14; @@ -647,7 +647,7 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { uint8_t freqBand = (newFreq / 10) - 24; uint8_t afcLimiter = 80; this->frequency = newFreq; - if(newFreq >= 480.0) { + if(newFreq >= 480.0f) { bandSelect = RADIOLIB_SI443X_BAND_SELECT_HIGH; freqBand = (newFreq / 20) - 24; afcLimiter = 40; @@ -757,11 +757,11 @@ int16_t Si443x::updateClockRecovery() { ndec = (uint16_t)1 << ndecExp; } else { ndecExp *= -1; - ndec = 1.0/(float)((uint16_t)1 << ndecExp); + ndec = 1.0f/(float)((uint16_t)1 << ndecExp); } float rxOsr = ((float)(500 * (1 + 2*bypass))) / (ndec * this->bitRate * ((float)(1 + manch))); uint32_t ncoOff = (this->bitRate * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass)); - uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * this->bitRate) / (rxOsr * (this->frequencyDev / 0.625))); + uint16_t crGain = 2 + (((float)(65536.0f * (1 + manch)) * this->bitRate) / (rxOsr * (this->frequencyDev / 0.625f))); uint16_t rxOsr_fixed = (uint16_t)rxOsr; // print that whole mess diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp index 30da937263..a683393771 100644 --- a/src/protocols/BellModem/BellModem.cpp +++ b/src/protocols/BellModem/BellModem.cpp @@ -43,7 +43,7 @@ int16_t BellClient::begin(const BellModem_t& modem) { int16_t BellClient::setModem(const BellModem_t& modem) { this->modemType = modem; - this->toneLen = (1000000.0/(float)this->modemType.baudRate)*this->correction; + this->toneLen = (1000000.0f/(float)this->modemType.baudRate)*this->correction; return(RADIOLIB_ERR_NONE); } diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 7e2d737e81..4816513e12 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -34,7 +34,7 @@ int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { } // calculate 24-bit frequency - baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); // configure for direct mode return(phyLayer->startDirect()); diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index b79e7a4412..749b924e70 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -21,10 +21,10 @@ HellClient::HellClient(AFSKClient* audio) { int16_t HellClient::begin(float base, float rate) { // calculate 24-bit frequency baseFreqHz = base; - baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); // calculate "pixel" duration - pixelDuration = 1000000.0/rate; + pixelDuration = 1000000.0f/rate; // configure for direct mode return(phyLayer->startDirect()); diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 07281be5ff..2f1a367d2b 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2112,7 +2112,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // check if the frequency is allowed and possible if(macFreq >= this->band->freqMin && macFreq <= this->band->freqMax) { - if(this->phyLayer->setFrequency((float)macFreq / 10000.0) == RADIOLIB_ERR_NONE) { + if(this->phyLayer->setFrequency((float)macFreq / 10000.0f) == RADIOLIB_ERR_NONE) { freqAck = 1; } // otherwise, if frequency is 0, disable the channel which is also a valid option @@ -2172,7 +2172,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // get the configuration uint8_t macChIndex = optIn[0]; uint32_t macFreq = LoRaWANNode::ntoh(&optIn[1], 3); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %7.3f MHz", macChIndex, macFreq / 10000.0); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %7.3f MHz", macChIndex, macFreq / 10000.0f); uint8_t freqDlAck = 0; uint8_t freqUlAck = 0; diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index b41dae7684..5ea1ff6387 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -23,7 +23,7 @@ MorseClient::MorseClient(AFSKClient* audio) { int16_t MorseClient::begin(float base, uint8_t speed) { // calculate 24-bit frequency baseFreqHz = base; - baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); // calculate tone period for decoding basePeriod = (1000000.0f/base)/2.0f; diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index f286395ff5..8509e9bc81 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -39,7 +39,7 @@ int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shi // calculate 24-bit frequency baseFreq = base; - baseFreqRaw = (baseFreq * 1000000.0) / phyLayer->getFreqStep(); + baseFreqRaw = (baseFreq * 1000000.0f) / phyLayer->getFreqStep(); // calculate module carrier frequency resolution uint16_t step = round(phyLayer->getFreqStep()); diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 17da7d20c1..aceddbe85c 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -46,7 +46,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc } // calculate 24-bit frequency - baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); // configure for direct mode return(phyLayer->startDirect()); diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index 3f72a3b23c..b4df42522b 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -219,7 +219,7 @@ int16_t SSTVClient::begin(float base, const SSTVMode_t& mode) { txMode = mode; // calculate 24-bit frequency - baseFreq = (base * 1000000.0) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); // configure for direct mode return(phyLayer->startDirect()); @@ -345,7 +345,7 @@ void SSTVClient::sendLine(const uint32_t* imgLine) { case(tone_t::GENERIC): break; } - this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), len); + this->tone(RADIOLIB_SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549f), len); } } } From a5011914c5addd98974f1e11608e9707c0cb0be2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 16 Jan 2025 18:27:52 +0100 Subject: [PATCH 1427/1848] [CI] Disable self hosted runner actions --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9779ea9c77..d9076155f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -291,6 +291,7 @@ jobs: LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh rpi-build: + if: false # self-hosted runner temporarily disabled runs-on: [self-hosted, ARM64] steps: - name: Checkout repository @@ -322,6 +323,7 @@ jobs: ./build.sh rpi-test: + if: false # self-hosted runner temporarily disabled needs: rpi-build runs-on: [self-hosted, ARM64] steps: From cad09196de253cc7b92120110f468fe4d08d5599 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 16 Jan 2025 18:30:51 +0100 Subject: [PATCH 1428/1848] [CI] Use v4 artifact action --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d9076155f7..31d48940c4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -197,7 +197,7 @@ jobs: run: echo "::set-output name=short_sha::$(git rev-parse --short HEAD)" - name: Upload size report as artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: size-file-${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }} path: extras/test/ci/size_${{ steps.short-hash.outputs.short_sha }}_${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}.csv From 10c38164f26e6e974d4aa6eae3ad39bb99817dca Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 19:59:10 +0100 Subject: [PATCH 1429/1848] [LoRaWAN] Remove range expression in switch --- src/protocols/LoRaWAN/LoRaWAN.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 2f1a367d2b..17e51ca4e8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2352,7 +2352,10 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd uint8_t chMaskCntl = (mPtr[opt * fLen + 4] & 0x70) >> 4; uint16_t chMask = LoRaWANNode::ntoh(&mPtr[opt * fLen + 2]); switch(chMaskCntl) { - case 0 ... 3: + case 0: + case 1: + case 2: + case 3: chMaskGrp0123 |= (uint64_t)chMask << (16 * chMaskCntl); break; case 4: From c538cac769dcf0f84730237de04a43c645fae502 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 19:59:25 +0100 Subject: [PATCH 1430/1848] [Morse] Fix possible overflow --- src/protocols/Morse/Morse.cpp | 2 +- src/protocols/Morse/Morse.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 5ea1ff6387..c2ee4d74d8 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -56,7 +56,7 @@ char MorseClient::decode(uint8_t symbol, uint8_t len) { } // nothing found - return(RADIOLIB_MORSE_UNSUPPORTED); + return(RADIOLIB_MORSE_UNKNOWN_SYMBOL); } #if !RADIOLIB_EXCLUDE_AFSK diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 78d6a91079..abc5689086 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -14,6 +14,7 @@ #define RADIOLIB_MORSE_INTER_SYMBOL 0x00 #define RADIOLIB_MORSE_CHAR_COMPLETE 0x01 #define RADIOLIB_MORSE_WORD_COMPLETE 0x02 +#define RADIOLIB_MORSE_UNKNOWN_SYMBOL '*' // Morse character table: - using codes defined in ITU-R M.1677-1 // - Morse code representation is saved LSb first, using additional bit as guard From 7c464a06325a41459d56701816d8e6da1f797e99 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 19:59:50 +0100 Subject: [PATCH 1431/1848] Add double-promotion and pedantic warnings to CMake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2291050918..eabfb5d8f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ target_include_directories(RadioLib set_property(TARGET RadioLib PROPERTY CXX_STANDARD 20) # enable most warnings -target_compile_options(RadioLib PRIVATE -Wall -Wextra) +target_compile_options(RadioLib PRIVATE -Wall -Wextra -Wpedantic -Wdouble-promotion) include(GNUInstallDirs) From 4088db2cf2740bcbdafc7adea109bd4e6704d462 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 20:00:26 +0100 Subject: [PATCH 1432/1848] [MOD] Fix issues reported by new cppcheck --- src/Module.cpp | 24 ++++++++++++++++-------- src/Module.h | 12 ++++++------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index cd5ddc6815..1c819b0d83 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -25,7 +25,7 @@ Module::Module(const Module& mod) { } Module& Module::operator=(const Module& mod) { - memcpy((void*)&mod.spiConfig, &this->spiConfig, sizeof(SPIConfig_t)); + memcpy(reinterpret_cast(&(const_cast(mod)).spiConfig), &this->spiConfig, sizeof(SPIConfig_t)); this->csPin = mod.csPin; this->irqPin = mod.irqPin; this->rstPin = mod.rstPin; @@ -142,7 +142,7 @@ uint8_t Module::SPIreadRegister(uint32_t reg) { return(resp); } -void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) { +void Module::SPIwriteRegisterBurst(uint32_t reg, const uint8_t* data, size_t numBytes) { if(!spiConfig.stream) { SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], reg, data, NULL, numBytes); } else { @@ -174,7 +174,7 @@ void Module::SPIwriteRegister(uint32_t reg, uint8_t data) { } } -void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { +void Module::SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { // prepare the buffers size_t buffLen = this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8 + numBytes; #if RADIOLIB_STATIC_ONLY @@ -216,7 +216,7 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* // print debug information #if RADIOLIB_DEBUG_SPI - uint8_t* debugBuffPtr = NULL; + const uint8_t* debugBuffPtr = NULL; if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) { RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg); debugBuffPtr = &buffOut[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8]; @@ -245,7 +245,7 @@ int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); } -int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIreadStream(const uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio); RADIOLIB_ASSERT(state); @@ -264,7 +264,7 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_ #endif } -int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIwriteStream(uint16_t cmd, const uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { uint8_t cmdBuf[2]; uint8_t* cmdPtr = cmdBuf; for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) { @@ -273,7 +273,7 @@ int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, boo return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify)); } -int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { +int16_t Module::SPIwriteStream(const uint8_t* cmd, uint8_t cmdLen, const uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { // send the command int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio); RADIOLIB_ASSERT(state); @@ -315,7 +315,7 @@ int16_t Module::SPIcheckStream() { return(state); } -int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) { +int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) { // prepare the output buffer size_t buffLen = cmdLen + numBytes; if(!write) { @@ -348,6 +348,9 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write RadioLibTime_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); + + // this timeout check triggers a false positive from cppcheck + // cppcheck-suppress unsignedLessThanZero if(this->hal->millis() - start >= this->spiConfig.timeout) { RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY @@ -355,6 +358,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write #endif return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } + } } } @@ -382,6 +386,9 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write RadioLibTime_t start = this->hal->millis(); while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); + + // this timeout check triggers a false positive from cppcheck + // cppcheck-suppress unsignedLessThanZero if(this->hal->millis() - start >= this->spiConfig.timeout) { RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?"); #if !RADIOLIB_STATIC_ONLY @@ -390,6 +397,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write #endif return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } + } } } diff --git a/src/Module.h b/src/Module.h index 328a7f5c1d..17386aa76a 100644 --- a/src/Module.h +++ b/src/Module.h @@ -298,7 +298,7 @@ class Module { \param data Pointer to array that holds the data that will be written. \param numBytes Number of bytes that will be written. */ - void SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes); + void SPIwriteRegisterBurst(uint32_t reg, const uint8_t* data, size_t numBytes); /*! \brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead. @@ -315,7 +315,7 @@ class Module { \param dataIn Data that was transferred from slave to master. \param numBytes Number of bytes to transfer. */ - void SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); + void SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes); /*! \brief Method to check the result of last SPI stream transfer. @@ -344,7 +344,7 @@ class Module { \param verify Whether to verify the result of the transaction after it is finished. \returns \ref status_codes */ - int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIreadStream(const uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. @@ -355,7 +355,7 @@ class Module { \param verify Whether to verify the result of the transaction after it is finished. \returns \ref status_codes */ - int16_t SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIwriteStream(uint16_t cmd, const uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief Method to perform a write transaction with SPI stream. @@ -367,7 +367,7 @@ class Module { \param verify Whether to verify the result of the transaction after it is finished. \returns \ref status_codes */ - int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); + int16_t SPIwriteStream(const uint8_t* cmd, uint8_t cmdLen, const uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true); /*! \brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.). @@ -380,7 +380,7 @@ class Module { \param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x). \returns \ref status_codes */ - int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio); + int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio); // pin number access methods // getCs is omitted on purpose, as it can interfere when accessing the SPI in a concurrent environment From 5efdfb342a6f14bbc261f5717a94195cdff0da58 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 20:00:59 +0100 Subject: [PATCH 1433/1848] [CI] Always test from clean --- extras/test/unit/test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extras/test/unit/test.sh b/extras/test/unit/test.sh index 369690adfb..b2801a10fb 100755 --- a/extras/test/unit/test.sh +++ b/extras/test/unit/test.sh @@ -3,7 +3,8 @@ set -e # build the test binary -mkdir -p build +rm -rf build +mkdir build cd build cmake -G "CodeBlocks - Unix Makefiles" .. make -j4 From 673384718642dadb0ed78dc820aa87a2f762c7db Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 20:24:10 +0100 Subject: [PATCH 1434/1848] [CI] Suppress unused variable warnings for unimplemented functions --- extras/test/unit/include/TestHal.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/extras/test/unit/include/TestHal.hpp b/extras/test/unit/include/TestHal.hpp index cf1faff968..389bef13f4 100644 --- a/extras/test/unit/include/TestHal.hpp +++ b/extras/test/unit/include/TestHal.hpp @@ -104,10 +104,18 @@ class TestHal : public RadioLibHal { void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { HAL_LOG("TestHal::attachInterrupt(interruptNum=" << interruptNum << ", interruptCb=" << interruptCb << ", mode=" << mode << ")"); + + // TODO implement + (void)interruptNum; + (void)interruptCb; + (void)mode; } void detachInterrupt(uint32_t interruptNum) override { HAL_LOG("TestHal::detachInterrupt(interruptNum=" << interruptNum << ")"); + + // TODO implement + (void)interruptNum; } void delay(unsigned long ms) override { @@ -159,6 +167,11 @@ class TestHal : public RadioLibHal { long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { HAL_LOG("TestHal::pulseIn(pin=" << pin << ", state=" << state << ", timeout=" << timeout << ")"); + + // TODO implement + (void)pin; + (void)state; + (void)timeout; return(0); } @@ -199,10 +212,18 @@ class TestHal : public RadioLibHal { void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) { HAL_LOG("TestHal::tone(pin=" << pin << ", frequency=" << frequency << ", duration=" << duration << ")"); + + // TODO implement + (void)pin; + (void)frequency; + (void)duration; } void noTone(uint32_t pin) { HAL_LOG("TestHal::noTone(pin=" << pin << ")"); + + // TODO implement + (void)pin; } // method to compare buffer to the internal SPI log, for verifying SPI transactions From af34dd9691f0e4c0a7cbc587c26f36079ac66798 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 22:30:37 +0100 Subject: [PATCH 1435/1848] [CC1101] Cppcheck fixes --- src/modules/CC1101/CC1101.cpp | 36 +++++++++++++++++------------------ src/modules/CC1101/CC1101.h | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index b2bf595a93..1c0222c162 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -436,23 +436,23 @@ int16_t CC1101::setRxBandwidth(float rxBw) { } int16_t CC1101::autoSetRxBandwidth() { - // Uncertainty ~ +/- 40ppm for a cheap CC1101 - // Uncertainty * 2 for both transmitter and receiver - float uncertainty = ((this->frequency) * 40 * 2); - uncertainty = (uncertainty/1000); //Since bitrate is in kBit - float minbw = ((this->bitRate) + uncertainty); - - int possibles[16] = {58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650, 812}; - - for (int i = 0; i < 16; i++) { - if (possibles[i] > minbw) { - int16_t state = setRxBandwidth(possibles[i]); - return(state); - } + // Uncertainty ~ +/- 40ppm for a cheap CC1101 + // Uncertainty * 2 for both transmitter and receiver + float uncertainty = ((this->frequency) * 40 * 2); + uncertainty = (uncertainty/1000); //Since bitrate is in kBit + float minbw = ((this->bitRate) + uncertainty); + + const int options[16] = { 58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650, 812 }; + + for(int i = 0; i < 16; i++) { + if(options[i] > minbw) { + return(setRxBandwidth(options[i])); } - return(RADIOLIB_ERR_UNKNOWN); } + return(RADIOLIB_ERR_UNKNOWN); +} + int16_t CC1101::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; @@ -519,7 +519,7 @@ int16_t CC1101::setOutputPower(int8_t pwr) { // PA_TABLE[0] is the power to be used when transmitting a 0 (no power) // PA_TABLE[1] is the power to be used when transmitting a 1 (full power) - uint8_t paValues[2] = {0x00, powerRaw}; + const uint8_t paValues[2] = { 0x00, powerRaw }; SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2); return(RADIOLIB_ERR_NONE); @@ -598,7 +598,7 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } -int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { +int16_t CC1101::setSyncWord(const uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { if((maxErrBits > 1) || (len != 2)) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } @@ -1007,7 +1007,7 @@ int16_t CC1101::beginCommon(float freq, float br, float freqDev, float rxBw, int RADIOLIB_ASSERT(state); // set default sync word - uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW; + const uint8_t sw[RADIOLIB_CC1101_DEFAULT_SW_LEN] = RADIOLIB_CC1101_DEFAULT_SW; state = setSyncWord(sw[0], sw[1], 0, false); RADIOLIB_ASSERT(state); @@ -1161,7 +1161,7 @@ void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) { return(this->mod->SPIwriteRegister(reg, data)); } -void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { +void CC1101::SPIwriteRegisterBurst(uint8_t reg, const uint8_t* data, size_t len) { this->mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len); } diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index a586d3da98..576f8d7398 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -839,7 +839,7 @@ class CC1101: public PhysicalLayer { \param requireCarrierSense Require carrier sense above threshold in addition to sync word. \returns \ref status_codes */ - int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false); + int16_t setSyncWord(const uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false); /*! \brief Sets preamble length. @@ -1009,7 +1009,7 @@ class CC1101: public PhysicalLayer { int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2); void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes); uint8_t SPIreadRegister(uint8_t reg); - void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len); + void SPIwriteRegisterBurst(uint8_t reg, const uint8_t* data, size_t len); void SPIwriteRegister(uint8_t reg, uint8_t data); void SPIsendCommand(uint8_t cmd); From 21b8e5a364fdfa6120d8fcbab46d6a6cf55a4570 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 22:30:49 +0100 Subject: [PATCH 1436/1848] [LLCC68] Cppcheck fixes --- src/modules/LLCC68/LLCC68.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 7809c56cbf..949e666bdc 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -48,14 +48,14 @@ class LLCC68: public SX1262 { \param bw LoRa bandwidth to be set in kHz. \returns \ref status_codes */ - int16_t setBandwidth(float bw); + int16_t setBandwidth(float bw) override; /*! \brief Sets LoRa spreading factor. Allowed values range from 5 to 11, depending on currently set spreading factor. \param sf LoRa spreading factor to be set. \returns \ref status_codes */ - int16_t setSpreadingFactor(uint8_t sf); + int16_t setSpreadingFactor(uint8_t sf) override; /*! \brief Set data. From 3354cd89dfb78ccb5efc700ab193516b4641d46b Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 17 Jan 2025 22:31:20 +0100 Subject: [PATCH 1437/1848] [SX126x] MAke LLCC68-shared methods virtual --- src/modules/SX126x/SX126x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 4784e675c6..275faee390 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -783,14 +783,14 @@ class SX126x: public PhysicalLayer { \param bw LoRa bandwidth to be set in kHz. \returns \ref status_codes */ - int16_t setBandwidth(float bw); + virtual int16_t setBandwidth(float bw); /*! \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. \param sf LoRa spreading factor to be set. \returns \ref status_codes */ - int16_t setSpreadingFactor(uint8_t sf); + virtual int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. From 77dad34c05850a1e376105d37ed6f1d8745a4d4d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 15:21:40 +0100 Subject: [PATCH 1438/1848] [LR11x0] Cppcheck fixes --- src/modules/LR11x0/LR11x0.cpp | 75 ++++++++++++++++++----------------- src/modules/LR11x0/LR11x0.h | 38 +++++++++--------- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 493cd260ec..8aba735de5 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -287,7 +287,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { // check whether this was a timeout or not if((getIrqStatus() & RADIOLIB_LR11X0_IRQ_TIMEOUT) || softTimeout) { standby(); - clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -463,7 +463,7 @@ int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { } // clear interrupt flags - state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); RADIOLIB_ASSERT(state); // set RF switch (if present) @@ -483,7 +483,7 @@ int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t LR11x0::finishTransmit() { // clear interrupt flags - clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); // set mode to standby to disable transmitter/RF switch return(standby()); @@ -515,7 +515,7 @@ int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa RADIOLIB_ASSERT(state); // clear interrupt flags - state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); RADIOLIB_ASSERT(state); // set implicit mode and expected len if applicable @@ -580,7 +580,7 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // clear interrupt flags - state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); // check if CRC failed - this is done after reading data to give user the option to keep them RADIOLIB_ASSERT(crcState); @@ -626,7 +626,7 @@ int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &config) { RADIOLIB_ASSERT(state); // clear interrupt flags - state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); RADIOLIB_ASSERT(state); // set mode to CAD @@ -1419,7 +1419,7 @@ int16_t LR11x0::setIrqFlags(uint32_t irq) { } int16_t LR11x0::clearIrqFlags(uint32_t irq) { - return(this->clearIrq(irq)); + return(this->clearIrqState(irq)); } uint8_t LR11x0::randomByte() { @@ -1594,7 +1594,7 @@ void LR11x0::clearWiFiScanAction() { int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) { // clear IRQ first, as this is likely to be called right after scan has finished - int16_t state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + int16_t state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); RADIOLIB_ASSERT(state); uint8_t buff[1] = { 0 }; @@ -1765,7 +1765,7 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat uint32_t offset = i * maxLen; uint32_t len = (i == (numWrites - 1)) ? rem : maxLen; RADIOLIB_DEBUG_BASIC_PRINTLN("Writing chunk %d at offset %08lx (%u words)", (int)i, (unsigned long)offset, (unsigned int)len); - this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), (uint32_t*)&image[offset], len, nonvolatile); + this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), const_cast(&image[offset]), len, nonvolatile); } // kick the device from bootloader @@ -1811,7 +1811,7 @@ int16_t LR11x0::isGnssScanCapable() { size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); state = this->readRegMem32(addr, buff, len); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_HEXDUMP(NULL, (uint8_t*)buff, len*sizeof(uint32_t), addr); + RADIOLIB_DEBUG_HEXDUMP(NULL, reinterpret_cast(buff), len*sizeof(uint32_t), addr); addr += len*sizeof(uint32_t); sz -= len*sizeof(uint32_t); } @@ -1870,7 +1870,7 @@ int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) { // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags uint32_t irq = this->getIrqStatus(); - this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -1982,7 +1982,7 @@ int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) { // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags uint32_t irq = this->getIrqStatus(); - this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { state = RADIOLIB_ERR_RX_TIMEOUT; } @@ -2033,11 +2033,11 @@ int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) int16_t LR11x0::getModem(ModemType_t* modem) { RADIOLIB_ASSERT_PTR(modem); - uint8_t packetType = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - int16_t state = getPacketType(&packetType); + uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - switch(packetType) { + switch(type) { case(RADIOLIB_LR11X0_PACKET_TYPE_LORA): *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); @@ -2114,7 +2114,7 @@ int16_t LR11x0::SPIcheckStatus(Module* mod) { return(LR11x0::SPIparseStatus(buff[0])); } -int16_t LR11x0::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, uint8_t* out, size_t outLen) { +int16_t LR11x0::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) { int16_t state = RADIOLIB_ERR_UNKNOWN; if(!write) { // the SPI interface of LR11x0 requires two separate transactions for reading @@ -2175,7 +2175,7 @@ int16_t LR11x0::config(uint8_t modem) { RADIOLIB_ASSERT(state); // clear IRQ - state = this->clearIrq(RADIOLIB_LR11X0_IRQ_ALL); + state = this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE); RADIOLIB_ASSERT(state); @@ -2289,7 +2289,7 @@ Module* LR11x0::getMod() { return(this->mod); } -int16_t LR11x0::writeRegMem32(uint32_t addr, uint32_t* data, size_t len) { +int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); @@ -2457,7 +2457,7 @@ int16_t LR11x0::setDioIrqParams(uint32_t irq) { return(setDioIrqParams(irq, this->gnss ? 0 : irq)); } -int16_t LR11x0::clearIrq(uint32_t irq) { +int16_t LR11x0::clearIrqState(uint32_t irq) { uint8_t buff[4] = { (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), }; @@ -2958,7 +2958,7 @@ int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff))); } -int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len) { +int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len) { // check maximum size const uint8_t maxLen[4][4] = { { 189, 178, 167, 155, }, @@ -3005,7 +3005,7 @@ int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, true, buff, sizeof(buff))); } -int16_t LR11x0::configBleBeacon(uint8_t chan, uint8_t* payload, size_t len) { +int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len) { return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len)); } @@ -3019,11 +3019,11 @@ int16_t LR11x0::getLoRaRxHeaderInfos(uint8_t* info) { return(state); } -int16_t LR11x0::bleBeaconSend(uint8_t chan, uint8_t* payload, size_t len) { +int16_t LR11x0::bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len) { return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len)); } -int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len) { +int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len) { // check maximum size // TODO what is the actual maximum? if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { @@ -3366,7 +3366,7 @@ int16_t LR11x0::gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); } -int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac) { +int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, const uint8_t* svnAlmanac) { uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { svn }; memcpy(&buff[1], svnAlmanac, RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE - 1); return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); @@ -3640,7 +3640,7 @@ void LR11x0::gnssAbort() { // send the abort signal (single NOP) this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; // we need to call the most basic overload of the SPI write method otherwise the call will be ambiguous - uint8_t cmd[2] = { 0, 0 }; + const uint8_t cmd[2] = { 0, 0 }; this->mod->SPIwriteStream(cmd, 2, NULL, 0, false, false); this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; @@ -3648,7 +3648,7 @@ void LR11x0::gnssAbort() { this->mod->hal->delay(3000); } -int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { +int16_t LR11x0::cryptoSetKey(uint8_t keyId, const uint8_t* key) { RADIOLIB_ASSERT_PTR(key); uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; buff[0] = keyId; @@ -3656,7 +3656,7 @@ int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY, false, buff, sizeof(buff))); } -int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key) { +int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, const uint8_t* key) { RADIOLIB_ASSERT_PTR(key); uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; buff[0] = srcKeyId; @@ -3665,7 +3665,7 @@ int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY, false, buff, sizeof(buff))); } -int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, uint8_t* header, uint8_t* dataIn, size_t len, uint8_t* dataOut) { +int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, const uint8_t* header, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { // calculate buffer sizes size_t headerLen = 1; if(lwVer) { @@ -3718,7 +3718,7 @@ int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint return(state); } -int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, uint32_t* mic) { +int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, const uint8_t* data, size_t len, uint32_t* mic) { size_t reqLen = sizeof(uint8_t) + len; #if RADIOLIB_STATIC_ONLY uint8_t reqBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; @@ -3745,7 +3745,7 @@ int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, u return(state); } -int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* data, size_t len, bool* result) { +int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, const uint8_t* data, size_t len, bool* result) { size_t reqLen = sizeof(uint8_t) + sizeof(uint32_t) + len; #if RADIOLIB_STATIC_ONLY uint8_t reqBuff[sizeof(uint8_t) + sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; @@ -3776,15 +3776,15 @@ int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* dat return(state); } -int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { +int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01, keyId, dataIn, len, dataOut)); } -int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { +int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT, keyId, dataIn, len, dataOut)); } -int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { +int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT, keyId, dataIn, len, dataOut)); } @@ -3814,7 +3814,7 @@ int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) { return(state); } -int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) { +int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); @@ -3841,7 +3841,7 @@ int16_t LR11x0::bootEraseFlash(void) { return(state); } -int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) { +int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); @@ -3889,7 +3889,8 @@ int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d for(size_t i = 0; i < len; i++) { uint32_t bin = 0; if(nonvolatile) { - bin = RADIOLIB_NONVOLATILE_READ_DWORD(data + i); + uint32_t* ptr = const_cast(data) + i; + bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr); } else { bin = data[i]; } @@ -3906,7 +3907,7 @@ int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d return(state); } -int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut) { +int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { // build buffers #if RADIOLIB_STATIC_ONLY uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 68c052ddd9..03455d3502 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1628,7 +1628,7 @@ class LR11x0: public PhysicalLayer { Module* getMod() override; // LR11x0 SPI command implementations - int16_t writeRegMem32(uint32_t addr, uint32_t* data, size_t len); + int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); int16_t writeBuffer8(uint8_t* data, size_t len); int16_t readBuffer8(uint8_t* data, size_t len, size_t offset); @@ -1644,7 +1644,7 @@ class LR11x0: public PhysicalLayer { int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg); int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2); int16_t setDioIrqParams(uint32_t irq); - int16_t clearIrq(uint32_t irq); + int16_t clearIrqState(uint32_t irq); int16_t configLfClock(uint8_t setup); int16_t setTcxoMode(uint8_t tune, uint32_t delay); int16_t reboot(bool stay); @@ -1702,11 +1702,11 @@ class LR11x0: public PhysicalLayer { int16_t setRangingParameter(uint8_t symbolNum); int16_t setRssiCalibration(const int8_t* tune, int16_t gainOffset); int16_t setLoRaSyncWord(uint8_t sync); - int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len); + int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); int16_t lrFhssSetSyncWord(uint32_t sync); - int16_t configBleBeacon(uint8_t chan, uint8_t* payload, size_t len); + int16_t configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len); int16_t getLoRaRxHeaderInfos(uint8_t* info); - int16_t bleBeaconSend(uint8_t chan, uint8_t* payload, size_t len); + int16_t bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len); int16_t wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout); int16_t wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout); @@ -1744,7 +1744,7 @@ class LR11x0: public PhysicalLayer { int16_t gnssGetResultSize(uint16_t* size); int16_t gnssReadResults(uint8_t* result, uint16_t size); int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc); - int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac); + int16_t gnssAlmanacFullUpdateSV(uint8_t svn, const uint8_t* svnAlmanac); int16_t gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size); int16_t gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac); int16_t gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv); @@ -1773,29 +1773,29 @@ class LR11x0: public PhysicalLayer { int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1); void gnssAbort(); - int16_t cryptoSetKey(uint8_t keyId, uint8_t* key); - int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key); - int16_t cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, uint8_t* header, uint8_t* dataIn, size_t len, uint8_t* dataOut); - int16_t cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, uint32_t* mic); - int16_t cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* data, size_t len, bool* result); - int16_t cryptoAesEncrypt01(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); - int16_t cryptoAesEncrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); - int16_t cryptoAesDecrypt(uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoSetKey(uint8_t keyId, const uint8_t* key); + int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, const uint8_t* key); + int16_t cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, const uint8_t* header, const uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoComputeAesCmac(uint8_t keyId, const uint8_t* data, size_t len, uint32_t* mic); + int16_t cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, const uint8_t* data, size_t len, bool* result); + int16_t cryptoAesEncrypt01(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoAesEncrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoAesDecrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut); int16_t cryptoStoreToFlash(void); int16_t cryptoRestoreFromFlash(void); int16_t cryptoSetParam(uint8_t id, uint32_t value); int16_t cryptoGetParam(uint8_t id, uint32_t* value); - int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile); + int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile); int16_t cryptoCheckEncryptedFirmwareImageResult(bool* result); int16_t bootEraseFlash(void); - int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile); + int16_t bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile); int16_t bootReboot(bool stay); int16_t bootGetPin(uint8_t* pin); int16_t bootGetChipEui(uint8_t* eui); int16_t bootGetJoinEui(uint8_t* eui); - int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, uint8_t* out = NULL, size_t outLen = 0); + int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); #if !RADIOLIB_GODMODE protected: @@ -1840,9 +1840,9 @@ class LR11x0: public PhysicalLayer { int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); // common methods to avoid some copy-paste - int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len); + int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len); int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); - int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut); + int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut); }; #endif From beb66892871f10933aaa2870507f2f1d489bad0e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 15:25:48 +0100 Subject: [PATCH 1439/1848] [RF69] Cppcheck fixes --- src/modules/RF69/RF69.cpp | 6 +++--- src/modules/RF69/RF69.h | 4 ++-- src/modules/SX123x/SX1231.h | 2 +- src/modules/SX123x/SX1233.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index cbbda86f40..7638799163 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -219,7 +219,7 @@ int16_t RF69::packetMode() { return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_DATA_MODUL, RADIOLIB_RF69_PACKET_MODE, 6, 5)); } -void RF69::setAESKey(uint8_t* key) { +void RF69::setAESKey(const uint8_t* key) { this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_AES_KEY_1, key, 16); } @@ -364,7 +364,7 @@ bool RF69::fifoAdd(uint8_t* data, int totalLen, int* remLen) { bool RF69::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { // get pointer to the correct position in data buffer - uint8_t* dataPtr = (uint8_t*)&data[*rcvLen]; + uint8_t* dataPtr = const_cast(&data[*rcvLen]); // check how much data are we still expecting uint8_t len = RADIOLIB_RF69_FIFO_THRESH - 1; @@ -692,7 +692,7 @@ int16_t RF69::setOutputPower(int8_t pwr, bool highPower) { return(state); } -int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { +int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBits) { // check constraints if((maxErrBits > 7) || (len > 8)) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index d30e8c3112..9015d66d61 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -577,7 +577,7 @@ class RF69: public PhysicalLayer { \brief Sets AES key. \param key Key to be used for AES encryption. Must be exactly 16 bytes long. */ - void setAESKey(uint8_t* key); + void setAESKey(const uint8_t* key); /*! \brief Enables AES encryption. @@ -789,7 +789,7 @@ class RF69: public PhysicalLayer { \param len Sync word length in bytes. \param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0. */ - int16_t setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0); + int16_t setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0); /*! \brief Sets preamble length. diff --git a/src/modules/SX123x/SX1231.h b/src/modules/SX123x/SX1231.h index 6dc3735764..fae3aabf41 100644 --- a/src/modules/SX123x/SX1231.h +++ b/src/modules/SX123x/SX1231.h @@ -108,7 +108,7 @@ class SX1231: public RF69 { \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + virtual int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); #if !RADIOLIB_GODMODE protected: diff --git a/src/modules/SX123x/SX1233.h b/src/modules/SX123x/SX1233.h index bf9bb1481a..2cff2c66ad 100644 --- a/src/modules/SX123x/SX1233.h +++ b/src/modules/SX123x/SX1233.h @@ -38,7 +38,7 @@ class SX1233: public SX1231 { \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16) override; /*! \brief Sets bit rate. Allowed values range from 0.5 to 300.0 kbps. From d3d16433bfefaa7def43ed97f730f432f0bce7c0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 15:43:14 +0100 Subject: [PATCH 1440/1848] [SX126x] Cppcheck fixes --- src/modules/SX126x/STM32WLx.cpp | 2 +- src/modules/SX126x/STM32WLx.h | 8 ++-- src/modules/SX126x/SX1262.h | 4 +- src/modules/SX126x/SX126x.cpp | 53 ++++++++++++++------------- src/modules/SX126x/SX126x.h | 10 ++--- src/modules/SX126x/SX126x_LR_FHSS.cpp | 6 +-- 6 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/modules/SX126x/STM32WLx.cpp b/src/modules/SX126x/STM32WLx.cpp index e9f47167dd..d32477a9b2 100644 --- a/src/modules/SX126x/STM32WLx.cpp +++ b/src/modules/SX126x/STM32WLx.cpp @@ -45,7 +45,7 @@ int16_t STM32WLx::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // check the user did not request power output that is not possible - Module* mod = this->getMod(); + const Module* mod = this->getMod(); bool hp_supported = mod->findRfSwitchMode(MODE_TX_HP); bool lp_supported = mod->findRfSwitchMode(MODE_TX_LP); if((!lp_supported && (power < -9)) || (!hp_supported && (power > 14))) { diff --git a/src/modules/SX126x/STM32WLx.h b/src/modules/SX126x/STM32WLx.h index 993791aae1..317922cf08 100644 --- a/src/modules/SX126x/STM32WLx.h +++ b/src/modules/SX126x/STM32WLx.h @@ -66,12 +66,12 @@ class STM32WLx : public SX1262 { /*! \copydoc SX1262::begin */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false) override; /*! \copydoc SX1262::beginFSK */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false) override; // configuration methods @@ -113,12 +113,12 @@ class STM32WLx : public SX1262 { \brief Sets interrupt service routine to call when DIO1/2/3 activates. \param func ISR to call. */ - void setDio1Action(void (*func)(void)); + void setDio1Action(void (*func)(void)) override; /*! \brief Clears interrupt service routine to call when DIO1/2/3 activates. */ - void clearDio1Action(); + void clearDio1Action() override; /*! \brief Sets interrupt service routine to call when a packet is received. diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index a7e0b677af..d0e73a6e41 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -44,7 +44,7 @@ class SX1262: public SX126x { \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + virtual int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. @@ -60,7 +60,7 @@ class SX1262: public SX126x { \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + virtual int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for LR-FHSS modem. This modem only supports transmission! diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 393a8ed0fc..01148ecdac 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -331,7 +331,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // direct mode activation intentionally skipped here, as it seems to lead to much worse results - uint8_t data[] = { RADIOLIB_SX126X_CMD_NOP }; + const uint8_t data[] = { RADIOLIB_SX126X_CMD_NOP }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); } @@ -473,7 +473,7 @@ int16_t SX126x::standby(uint8_t mode, bool wakeup) { (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false); } - uint8_t data[] = { mode }; + const uint8_t data[] = { mode }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } @@ -672,7 +672,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, R int16_t state = startReceiveCommon(RADIOLIB_SX126X_RX_TIMEOUT_INF, irqFlags, irqMask); RADIOLIB_ASSERT(state); - uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), + const uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF), (uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6)); } @@ -1641,8 +1641,8 @@ int16_t SX126x::invertIQ(bool enable) { int16_t SX126x::getModem(ModemType_t* modem) { RADIOLIB_ASSERT_PTR(modem); - uint8_t packetType = getPacketType(); - switch(packetType) { + uint8_t type = getPacketType(); + switch(type) { case(RADIOLIB_SX126X_PACKET_TYPE_LORA): *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); @@ -1687,7 +1687,8 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) for(uint32_t i = 0; i < len / sizeof(uint32_t); i++) { uint32_t bin = 0; if(nonvolatile) { - bin = RADIOLIB_NONVOLATILE_READ_DWORD(patch + i); + uint32_t* ptr = const_cast(patch) + i; + bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr); } else { bin = patch[i]; } @@ -1726,7 +1727,7 @@ int16_t SX126x::spectralScanStart(uint16_t numSamples, uint8_t window, uint8_t i RADIOLIB_ASSERT(state); // now set the actual spectral scan parameters - uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval }; + const uint8_t data[3] = { (uint8_t)((numSamples >> 8) & 0xFF), (uint8_t)(numSamples & 0xFF), interval }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3)); } @@ -1822,12 +1823,12 @@ int16_t SX126x::setFs() { } int16_t SX126x::setTx(uint32_t timeout) { - uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; + const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); } int16_t SX126x::setRx(uint32_t timeout) { - uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; + const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); } @@ -1879,11 +1880,11 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8 } int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { - uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; + const uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); } -int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { +int16_t SX126x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) { this->mod->SPIwriteRegisterBurst(addr, data, numBytes); return(RADIOLIB_ERR_NONE); } @@ -1897,18 +1898,18 @@ int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { return(state); } -int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; +int16_t SX126x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) { + const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); } int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; + const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); } int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { - uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), + const uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; @@ -1916,12 +1917,12 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di } int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { - uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; + const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX126x::setRfFrequency(uint32_t frf) { - uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; + const uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } @@ -1974,7 +1975,7 @@ int16_t SX126x::setPaRampTime(uint8_t rampTime) { return(this->setTxParams(this->pwr, rampTime)); } -int16_t SX126x::calibrateImage(uint8_t* data) { +int16_t SX126x::calibrateImage(const uint8_t* data) { int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); // if something failed, show the device errors @@ -1996,7 +1997,7 @@ uint8_t SX126x::getPacketType() { } int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) { - uint8_t data[] = { pwr, rampTime }; + const uint8_t data[] = { pwr, rampTime }; int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2); if(state == RADIOLIB_ERR_NONE) { this->pwr = pwr; @@ -2050,12 +2051,12 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t } // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 - uint8_t data[4] = {sf, bw, cr, this->ldrOptimize}; + const uint8_t data[4] = {sf, bw, cr, this->ldrOptimize}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); } int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { - uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), + const uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); @@ -2064,24 +2065,24 @@ int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, ui int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) { int16_t state = fixInvertedIQ(invertIQ); RADIOLIB_ASSERT(state); - uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ}; + const uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); } int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen) { - uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + const uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); } int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { - uint8_t data[2] = {txBaseAddress, rxBaseAddress}; + const uint8_t data[2] = {txBaseAddress, rxBaseAddress}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX126x::setRegulatorMode(uint8_t mode) { - uint8_t data[1] = {mode}; + const uint8_t data[1] = {mode}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); } @@ -2105,7 +2106,7 @@ uint16_t SX126x::getDeviceErrors() { } int16_t SX126x::clearDeviceErrors() { - uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; + const uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 275faee390..e37265b0f7 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -634,12 +634,12 @@ class SX126x: public PhysicalLayer { \brief Sets interrupt service routine to call when DIO1 activates. \param func ISR to call. */ - void setDio1Action(void (*func)(void)); + virtual void setDio1Action(void (*func)(void)); /*! \brief Clears interrupt service routine to call when DIO1 activates. */ - void clearDio1Action(); + virtual void clearDio1Action(); /*! \brief Sets interrupt service routine to call when a packet is received. @@ -1238,14 +1238,14 @@ class SX126x: public PhysicalLayer { int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); int16_t setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); - int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); - int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + int16_t writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE); virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); - int16_t calibrateImage(uint8_t* data); + int16_t calibrateImage(const uint8_t* data); uint8_t getPacketType(); int16_t setTxParams(uint8_t power, uint8_t rampTime); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); diff --git a/src/modules/SX126x/SX126x_LR_FHSS.cpp b/src/modules/SX126x/SX126x_LR_FHSS.cpp index 0f491f9151..42c071afa0 100644 --- a/src/modules/SX126x/SX126x_LR_FHSS.cpp +++ b/src/modules/SX126x/SX126x_LR_FHSS.cpp @@ -87,7 +87,7 @@ int16_t SX126x::buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out // for rates other than the 1/3 base, puncture the code if(this->lrFhssCr != RADIOLIB_SX126X_LR_FHSS_CR_1_3) { uint32_t matrix_index = 0; - uint8_t matrix[15] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 }; + const uint8_t matrix[15] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 }; uint8_t matrix_len = 0; switch(this->lrFhssCr) { case RADIOLIB_SX126X_LR_FHSS_CR_5_6: @@ -364,7 +364,7 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) { } } - uint8_t frq[4] = { (uint8_t)((freq_raw >> 24) & 0xFF), (uint8_t)((freq_raw >> 16) & 0xFF), (uint8_t)((freq_raw >> 8) & 0xFF), (uint8_t)(freq_raw & 0xFF) }; + const uint8_t frq[4] = { (uint8_t)((freq_raw >> 24) & 0xFF), (uint8_t)((freq_raw >> 16) & 0xFF), (uint8_t)((freq_raw >> 8) & 0xFF), (uint8_t)(freq_raw & 0xFF) }; int16_t state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(index), frq, sizeof(freq_raw)); RADIOLIB_ASSERT(state); @@ -380,7 +380,7 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) { } // write hop length in symbols - uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) }; + const uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) }; state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(index), sym, sizeof(uint16_t)); RADIOLIB_ASSERT(state); From d23983bc1f1e595f7c59d8df8adc394767dd69e8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 16:39:17 +0100 Subject: [PATCH 1441/1848] [CI] Suppress missing includes in cppcheck --- extras/cppcheck/cppcheck.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extras/cppcheck/cppcheck.sh b/extras/cppcheck/cppcheck.sh index fe48a40c79..08e9a01e54 100755 --- a/extras/cppcheck/cppcheck.sh +++ b/extras/cppcheck/cppcheck.sh @@ -2,7 +2,14 @@ file=cppcheck.txt cppcheck --version -cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked --suppress=unusedFunction --quiet >> $file 2>&1 +cppcheck src --enable=all \ + --force \ + --inline-suppr \ + --suppress=ConfigurationNotChecked \ + --suppress=unusedFunction \ + --suppress=missingIncludeSystem \ + --suppress=missingInclude \ + --quiet >> $file 2>&1 echo "Cppcheck finished with exit code $?" error=$(grep ": error:" $file | wc -l) From 5e7be103641a8e0b05fc8d2029ff4127e4aa700c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:47:34 +0100 Subject: [PATCH 1442/1848] [nRF24] Cppcheck fixes --- src/modules/nRF24/nRF24.cpp | 8 ++++---- src/modules/nRF24/nRF24.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 0218ddd7a1..105ac298a9 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -387,7 +387,7 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) { return(state); } -int16_t nRF24::setTransmitPipe(uint8_t* addr) { +int16_t nRF24::setTransmitPipe(const uint8_t* addr) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); @@ -402,7 +402,7 @@ int16_t nRF24::setTransmitPipe(uint8_t* addr) { return(state); } -int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) { +int16_t nRF24::setReceivePipe(uint8_t pipeNum, const uint8_t* addr) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); @@ -610,11 +610,11 @@ void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) { SPItransfer(RADIOLIB_NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes); } -void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { +void nRF24::SPIwriteTxPayload(const uint8_t* data, uint8_t numBytes) { SPItransfer(RADIOLIB_NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes); } -void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { +void nRF24::SPItransfer(uint8_t cmd, bool write, const uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { (void)this->mod->SPItransferStream(&cmd, 1, write, dataOut, dataIn, numBytes, false); } diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 428df70f4b..e7db4ec548 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -374,7 +374,7 @@ class nRF24: public PhysicalLayer { \param addr Address to which the next packet shall be transmitted. \returns \ref status_codes */ - int16_t setTransmitPipe(uint8_t* addr); + int16_t setTransmitPipe(const uint8_t* addr); /*! \brief Sets address of receive pipes 0 or 1. The address width must be the same as the same @@ -384,7 +384,7 @@ class nRF24: public PhysicalLayer { \param addr Address from which %nRF24 shall receive new packets on the specified pipe. \returns \ref status_codes */ - int16_t setReceivePipe(uint8_t pipeNum, uint8_t* addr); + int16_t setReceivePipe(uint8_t pipeNum, const uint8_t* addr); /*! \brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes @@ -471,8 +471,8 @@ class nRF24: public PhysicalLayer { Module* getMod() override; void SPIreadRxPayload(uint8_t* data, uint8_t numBytes); - void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes); - void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0); + void SPIwriteTxPayload(const uint8_t* data, uint8_t numBytes); + void SPItransfer(uint8_t cmd, bool write = false, const uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0); #if !RADIOLIB_GODMODE private: From aaa48ba4d878a34e78f22ebc2391dd645fcd2247 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:47:54 +0100 Subject: [PATCH 1443/1848] [Si443x] Cppcheck fixes --- src/modules/Si443x/Si4430.h | 2 +- src/modules/Si443x/Si4431.h | 2 +- src/modules/Si443x/Si4432.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h index 2d212e058f..e7923687b7 100644 --- a/src/modules/Si443x/Si4430.h +++ b/src/modules/Si443x/Si4430.h @@ -35,7 +35,7 @@ class Si4430: public Si4432 { \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16) override; // configuration methods diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h index a8939ea16a..9eddc268b8 100644 --- a/src/modules/Si443x/Si4431.h +++ b/src/modules/Si443x/Si4431.h @@ -35,7 +35,7 @@ class Si4431: public Si4432 { \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16) override; // configuration methods diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h index f3ac066136..8bfe310104 100644 --- a/src/modules/Si443x/Si4432.h +++ b/src/modules/Si443x/Si4432.h @@ -35,7 +35,7 @@ class Si4432: public Si443x { \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); + virtual int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods From ddd4b23e656c4a982679149ed26469bda9d65fd4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:48:09 +0100 Subject: [PATCH 1444/1848] [SX126x] Cppcheck fixes --- src/modules/SX126x/SX126x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 01148ecdac..224858ebb2 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -931,7 +931,7 @@ int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { } // update register - uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; + const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)); } @@ -1154,7 +1154,7 @@ int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { // add Rx Gain register to retention memory if requested if(persist) { // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3 - uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) }; + const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) }; state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3); } From 06b3049e3889690cb9a40b3ab53eded6bf0b0c47 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:48:19 +0100 Subject: [PATCH 1445/1848] [SX127x] Cppcheck fixes --- src/modules/SX127x/SX1272.h | 6 +++--- src/modules/SX127x/SX1273.h | 4 ++-- src/modules/SX127x/SX1276.cpp | 4 ++-- src/modules/SX127x/SX1276.h | 4 ++-- src/modules/SX127x/SX1277.cpp | 4 ++-- src/modules/SX127x/SX1277.h | 6 +++--- src/modules/SX127x/SX1278.cpp | 4 ++-- src/modules/SX127x/SX1278.h | 8 ++++---- src/modules/SX127x/SX1279.cpp | 4 ++-- src/modules/SX127x/SX1279.h | 4 ++-- src/modules/SX127x/SX127x.cpp | 11 +++++------ src/modules/SX127x/SX127x.h | 6 +++--- 12 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 337558ec8b..142ee174ba 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -118,7 +118,7 @@ class SX1272: public SX127x { Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + virtual int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -160,7 +160,7 @@ class SX1272: public SX127x { \param sf %LoRa link spreading factor to be set. \returns \ref status_codes */ - int16_t setSpreadingFactor(uint8_t sf); + virtual int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. @@ -317,7 +317,7 @@ class SX1272: public SX127x { int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); int16_t setCodingRateRaw(uint8_t newCodingRate); - int16_t configFSK(); + int16_t configFSK() override; void errataFix(bool rx) override; #if !RADIOLIB_GODMODE diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 4e9dd1ed74..2a2e3b5efc 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -38,7 +38,7 @@ class SX1273: public SX1272 { Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override; // configuration methods @@ -47,7 +47,7 @@ class SX1273: public SX1272 { \param sf %LoRa link spreading factor to be set. \returns \ref status_codes */ - int16_t setSpreadingFactor(uint8_t sf); + int16_t setSpreadingFactor(uint8_t sf) override; /*! \brief Set data. diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 819e5188bb..596464fd4e 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -7,7 +7,7 @@ SX1276::SX1276(Module* mod) : SX1278(mod) { int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); @@ -39,7 +39,7 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 64dbaa3e35..e3d6ea0105 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -38,7 +38,7 @@ class SX1276: public SX1278 { Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override; /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -52,7 +52,7 @@ class SX1276: public SX1278 { \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false) override; // configuration methods diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 758daf51bc..155a6f3d31 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -7,7 +7,7 @@ SX1277::SX1277(Module* mod) : SX1278(mod) { int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); @@ -39,7 +39,7 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index fe068c0d75..22e68ad8e2 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -38,7 +38,7 @@ class SX1277: public SX1278 { Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override; /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -52,7 +52,7 @@ class SX1277: public SX1278 { \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false) override; // configuration methods @@ -68,7 +68,7 @@ class SX1277: public SX1278 { \param sf %LoRa link spreading factor to be set. \returns \ref status_codes */ - int16_t setSpreadingFactor(uint8_t sf); + int16_t setSpreadingFactor(uint8_t sf) override; /*! \brief Set data. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 141a002998..e370d0e3cb 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -8,7 +8,7 @@ SX1278::SX1278(Module* mod) : SX127x(mod) { int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); @@ -40,7 +40,7 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 1fadf64be6..2c2a30c5a1 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -129,7 +129,7 @@ class SX1278: public SX127x { Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + virtual int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -143,7 +143,7 @@ class SX1278: public SX127x { \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + virtual int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -171,7 +171,7 @@ class SX1278: public SX127x { \param sf %LoRa link spreading factor to be set. \returns \ref status_codes */ - int16_t setSpreadingFactor(uint8_t sf); + virtual int16_t setSpreadingFactor(uint8_t sf); /*! \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. @@ -329,7 +329,7 @@ class SX1278: public SX127x { int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); int16_t setCodingRateRaw(uint8_t newCodingRate); - int16_t configFSK(); + int16_t configFSK() override; void errataFix(bool rx) override; #if !RADIOLIB_GODMODE diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index df87c388dc..92d9f59cbd 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -7,7 +7,7 @@ SX1279::SX1279(Module* mod) : SX1278(mod) { int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength); RADIOLIB_ASSERT(state); @@ -39,7 +39,7 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; + const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X }; int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 865b1b22c9..fb2d5f4305 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -38,7 +38,7 @@ class SX1279: public SX1278 { Set to 0 to enable automatic gain control (recommended). \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0) override; /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -52,7 +52,7 @@ class SX1279: public SX1278 { \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false) override; // configuration methods diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b94bfdada2..7510833ed4 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -6,7 +6,7 @@ SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, this->mod = mod; } -int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) { +int16_t SX127x::begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) { // set module properties this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -69,7 +69,7 @@ int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWo return(state); } -int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { +int16_t SX127x::beginFSK(const uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -548,7 +548,7 @@ bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) { bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) { // get pointer to the correct position in data buffer - uint8_t* dataPtr = (uint8_t*)&data[*rcvLen]; + uint8_t* dataPtr = const_cast(&data[*rcvLen]); // check how much data are we still expecting uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1; @@ -1869,12 +1869,11 @@ int16_t SX127x::setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len) } // set requested packet mode - Module* mod = this->getMod(); - int16_t state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex); RADIOLIB_ASSERT(state); // set length to register - state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); RADIOLIB_ASSERT(state); // update cached value diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 7e37162ca5..1edfdcd481 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -606,7 +606,7 @@ class SX127x: public PhysicalLayer { \param preambleLength Length of %LoRa transmission preamble in symbols. \returns \ref status_codes */ - int16_t begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength); + int16_t begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength); /*! \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ. @@ -623,7 +623,7 @@ class SX127x: public PhysicalLayer { \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK. \returns \ref status_codes */ - int16_t beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); + int16_t beginFSK(const uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -1251,7 +1251,7 @@ class SX127x: public PhysicalLayer { bool ookEnabled = false; bool implicitHdr = false; - int16_t configFSK(); + virtual int16_t configFSK(); int16_t getActiveModem(); int16_t setFrequencyRaw(float newFreq); int16_t setBitRateCommon(float br, uint8_t fracRegAddr); From 80a44a3232427565edf7295d0fd2d862664a6b34 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:48:25 +0100 Subject: [PATCH 1446/1848] [SX128x] Cppcheck fixes --- src/modules/SX128x/SX1280.cpp | 6 ++--- src/modules/SX128x/SX1280.h | 2 +- src/modules/SX128x/SX128x.cpp | 42 +++++++++++++++++------------------ src/modules/SX128x/SX128x.h | 4 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index b5d8ee0299..d2bb12c4e9 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -33,7 +33,7 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { return(state); } -int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6]) { +int16_t SX1280::startRanging(bool master, uint32_t addr, const uint16_t calTable[3][6]) { // check active modem uint8_t modem = getPacketType(); if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) { @@ -80,7 +80,7 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] } // set ranging address - uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; state = writeRegister(addrReg, addrBuff, 4); RADIOLIB_ASSERT(state); @@ -116,7 +116,7 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] default: return(RADIOLIB_ERR_INVALID_BANDWIDTH); } - uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) }; + const uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) }; state = writeRegister(RADIOLIB_SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 2); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index e06faec5eb..c4cea00a2c 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -37,7 +37,7 @@ class SX1280: public SX1281 { \param calTable Ranging calibration table - set to NULL to use the default. \returns \ref status_codes */ - int16_t startRanging(bool master, uint32_t addr, uint16_t calTable[3][6] = NULL); + int16_t startRanging(bool master, uint32_t addr, const uint16_t calTable[3][6] = NULL); /*! \brief Gets ranging result of the last ranging exchange. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 7b47ffb957..85fa91f667 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -485,7 +485,7 @@ int16_t SX128x::standby(uint8_t mode, bool wakeup) { (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false); } - uint8_t data[] = { mode }; + const uint8_t data[] = { mode }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1)); } @@ -1129,7 +1129,7 @@ int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { } // update register - uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; + const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2)); } @@ -1177,7 +1177,7 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { RADIOLIB_ASSERT(state); // set initial CRC value - uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; + const uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3); return(state); @@ -1224,7 +1224,7 @@ int16_t SX128x::setAccessAddress(uint32_t addr) { } // set the address - uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); } @@ -1517,7 +1517,7 @@ uint8_t SX128x::getStatus() { return(data); } -int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { +int16_t SX128x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) { this->mod->SPIwriteRegisterBurst(addr, data, numBytes); return(RADIOLIB_ERR_NONE); } @@ -1531,23 +1531,23 @@ int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { return(state); } -int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset }; +int16_t SX128x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) { + const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset }; return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); } int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset }; + const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset }; return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); } int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) { - uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; + const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3)); } int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { - uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; + const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3)); } @@ -1567,42 +1567,42 @@ uint8_t SX128x::getPacketType() { } int16_t SX128x::setRfFrequency(uint32_t frf) { - uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; + const uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3)); } int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) { - uint8_t data[] = { pwr, rampTime }; + const uint8_t data[] = { pwr, rampTime }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2)); } int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { - uint8_t data[] = { txBaseAddress, rxBaseAddress }; + const uint8_t data[] = { txBaseAddress, rxBaseAddress }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); } int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { - uint8_t data[] = { modParam1, modParam2, modParam3 }; + const uint8_t data[] = { modParam1, modParam2, modParam3 }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); } int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen, uint8_t hdrType) { - uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten }; + const uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) { - uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 }; + const uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) { - uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 }; + const uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { - uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), + const uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) }; @@ -1616,17 +1616,17 @@ uint16_t SX128x::getIrqStatus() { } int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { - uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; + const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX128x::setRangingRole(uint8_t role) { - uint8_t data[] = { role }; + const uint8_t data[] = { role }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1)); } int16_t SX128x::setPacketType(uint8_t type) { - uint8_t data[] = { type }; + const uint8_t data[] = { type }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 7a090db881..cd143e9616 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -890,9 +890,9 @@ class SX128x: public PhysicalLayer { // SX128x SPI command implementations uint8_t getStatus(); - int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes); int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); - int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + int16_t writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); int16_t setTx(uint16_t periodBaseCount = RADIOLIB_SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = RADIOLIB_SX128X_PERIOD_BASE_15_625_US); From d4d98d37ced671e66c6005937689545795aa5935 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:48:41 +0100 Subject: [PATCH 1447/1848] [APRS] Cppcheck fixes --- src/protocols/APRS/APRS.cpp | 6 +++--- src/protocols/APRS/APRS.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index c2fb72f3ed..a2f9078d4a 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -14,7 +14,7 @@ APRSClient::APRSClient(PhysicalLayer* phy) { phyLayer = phy; } -int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { +int16_t APRSClient::begin(char sym, const char* callsign, uint8_t ssid, bool alt) { RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL); symbol = sym; @@ -39,7 +39,7 @@ int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) { return(RADIOLIB_ERR_NONE); } -int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg, char* time) { +int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, const char* lat, const char* lon, const char* msg, const char* time) { size_t len = 1 + strlen(lat) + 1 + strlen(lon); if(msg != NULL) { len += 1 + strlen(msg); @@ -84,7 +84,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat return(state); } -int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem, size_t telemLen, char* grid, char* status, int32_t alt) { +int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, const uint8_t* telem, size_t telemLen, const char* grid, const char* status, int32_t alt) { // sanity checks first if(((telemLen == 0) && (telem != NULL)) || ((telemLen != 0) && (telem == NULL))) { return(RADIOLIB_ERR_INVALID_MIC_E_TELEMETRY); diff --git a/src/protocols/APRS/APRS.h b/src/protocols/APRS/APRS.h index 44031fdea4..f496f3b17b 100644 --- a/src/protocols/APRS/APRS.h +++ b/src/protocols/APRS/APRS.h @@ -106,7 +106,7 @@ class APRSClient { \param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table. \returns \ref status_codes */ - int16_t begin(char sym, char* callsign = NULL, uint8_t ssid = 0, bool alt = false); + int16_t begin(char sym, const char* callsign = NULL, uint8_t ssid = 0, bool alt = false); /*! \brief Transmit position. @@ -118,7 +118,7 @@ class APRSClient { \param time Position timestamp. Defaults to NULL (no timestamp). \returns \ref status_codes */ - int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL); + int16_t sendPosition(char* destCallsign, uint8_t destSSID, const char* lat, const char* lon, const char* msg = NULL, const char* time = NULL); /*! \brief Transmit position using Mic-E encoding. @@ -133,7 +133,7 @@ class APRSClient { \param status Status message to send. NULL when not used. \param alt Altitude to send. RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED when not used. */ - int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, uint8_t* telem = NULL, size_t telemLen = 0, char* grid = NULL, char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED); + int16_t sendMicE(float lat, float lon, uint16_t heading, uint16_t speed, uint8_t type, const uint8_t* telem = NULL, size_t telemLen = 0, const char* grid = NULL, const char* status = NULL, int32_t alt = RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED); /*! \brief Transmit generic APRS frame. From dab2c3497c95d4d0dfb557e1f5d8272218f58c27 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:48:57 +0100 Subject: [PATCH 1448/1848] [AX.25] Cppcheck fixes --- src/protocols/AX25/AX25.cpp | 4 ++-- src/protocols/AX25/AX25.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 22e1220a2e..ad0e991699 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -14,7 +14,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src } -AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen) { +AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const uint8_t* info, uint16_t infoLen) { // destination callsign/SSID memcpy(this->destCallsign, destCallsign, strlen(destCallsign)); this->destCallsign[strlen(destCallsign)] = '\0'; @@ -142,7 +142,7 @@ AX25Frame& AX25Frame::operator=(const AX25Frame& frame) { return(*this); } -int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) { +int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, const uint8_t* repeaterSSIDs, uint8_t numRepeaters) { // check number of repeaters if((numRepeaters < 1) || (numRepeaters > 8)) { return(RADIOLIB_ERR_INVALID_NUM_REPEATERS); diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index c7678a3a27..1349954613 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -185,7 +185,7 @@ class AX25Frame { \param info Information field, in the form of arbitrary binary buffer. \param infoLen Number of bytes in the information field. */ - AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen); + AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const uint8_t* info, uint16_t infoLen); /*! \brief Copy constructor. @@ -211,7 +211,7 @@ class AX25Frame { \param numRepeaters Number of repeaters, maximum is 8. \returns \ref status_codes */ - int16_t setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters); + int16_t setRepeaters(char** repeaterCallsigns, const uint8_t* repeaterSSIDs, uint8_t numRepeaters); /*! \brief Method to set receive sequence number. From 9b8b9c28029dc38432a645bdb229ea4dd54910d5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:49:10 +0100 Subject: [PATCH 1449/1848] [FSK4] Cppcheck fixes --- src/protocols/FSK4/FSK4.cpp | 2 +- src/protocols/FSK4/FSK4.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 4816513e12..4eb9b7bf80 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -54,7 +54,7 @@ int16_t FSK4Client::setCorrection(int16_t offsets[], float length) { return(RADIOLIB_ERR_NONE); } -size_t FSK4Client::write(uint8_t* buff, size_t len) { +size_t FSK4Client::write(const uint8_t* buff, size_t len) { size_t n = 0; for(size_t i = 0; i < len; i++) { n += FSK4Client::write(buff[i]); diff --git a/src/protocols/FSK4/FSK4.h b/src/protocols/FSK4/FSK4.h index 31df4101c8..757e556d4d 100644 --- a/src/protocols/FSK4/FSK4.h +++ b/src/protocols/FSK4/FSK4.h @@ -59,7 +59,7 @@ class FSK4Client { \param len Number of bytes to transmit. \returns Number of transmitted bytes. */ - size_t write(uint8_t* buff, size_t len); + size_t write(const uint8_t* buff, size_t len); /*! \brief Transmit a single byte. From 1357d672c74c9bb7ce7c009b0a08d0076c49c188 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:49:24 +0100 Subject: [PATCH 1450/1848] [Hell] Cppcheck fixes --- src/protocols/Hellschreiber/Hellschreiber.cpp | 3 ++- src/protocols/Hellschreiber/Hellschreiber.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 749b924e70..907aab7cc6 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -73,7 +73,8 @@ size_t HellClient::write(uint8_t b) { uint8_t buff[RADIOLIB_HELL_FONT_WIDTH]; buff[0] = 0x00; for(uint8_t i = 0; i < RADIOLIB_HELL_FONT_WIDTH - 2; i++) { - buff[i + 1] = RADIOLIB_NONVOLATILE_READ_BYTE(&HellFont[pos][i]); + uint8_t* ptr = const_cast(&HellFont[pos][i]); + buff[i + 1] = RADIOLIB_NONVOLATILE_READ_BYTE(ptr); } buff[RADIOLIB_HELL_FONT_WIDTH - 1] = 0x00; diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 0c266979d7..ff78fd1b38 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -144,8 +144,8 @@ class HellClient: public RadioLibPrint { uint32_t pixelDuration = 0; bool invert = false; - size_t printNumber(unsigned long, uint8_t); - size_t printFloat(double, uint8_t); + size_t printNumber(unsigned long, uint8_t) override; + size_t printFloat(double, uint8_t) override; int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); int16_t standby(); From 208f4f8ad48d3cdac4830c97ed0d44aec9507bb6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:49:37 +0100 Subject: [PATCH 1451/1848] [Morse] Cppcheck fixes --- src/protocols/Morse/Morse.cpp | 6 ++++-- src/protocols/Morse/Morse.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index c2ee4d74d8..6c4ffaf2d2 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -48,7 +48,8 @@ char MorseClient::decode(uint8_t symbol, uint8_t len) { // iterate over the table for(uint8_t i = 0; i < sizeof(MorseTable); i++) { - uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[i]); + uint8_t* ptr = const_cast(&MorseTable[i]); + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(ptr); if(code == symbol) { // match, return the index + ASCII offset return((char)(i + RADIOLIB_MORSE_ASCII_OFFSET)); @@ -129,7 +130,8 @@ size_t MorseClient::write(uint8_t b) { } // get morse code from lookup table - uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]); + uint8_t* ptr = const_cast(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]); + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(ptr); // check unsupported characters if(code == RADIOLIB_MORSE_UNSUPPORTED) { diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index abc5689086..ad491bce83 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -172,8 +172,8 @@ class MorseClient: public RadioLibPrint { uint32_t pauseCounter = 0; RadioLibTime_t pauseStart = 0; - size_t printNumber(unsigned long, uint8_t); - size_t printFloat(double, uint8_t); + size_t printNumber(unsigned long, uint8_t) override; + size_t printFloat(double, uint8_t) override; int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); int16_t standby(); From bf1933a0c4713e850801b1b0e0cb062c80ce9cea Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:49:51 +0100 Subject: [PATCH 1452/1848] [Pager] Cppcheck fixes --- src/protocols/Pager/Pager.cpp | 10 +++++----- src/protocols/Pager/Pager.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 8509e9bc81..905778edf8 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -67,10 +67,10 @@ int16_t PagerClient::transmit(String& str, uint32_t addr, uint8_t encoding, uint #endif int16_t PagerClient::transmit(const char* str, uint32_t addr, uint8_t encoding, uint8_t function) { - return(PagerClient::transmit((uint8_t*)str, strlen(str), addr, encoding, function)); + return(PagerClient::transmit(reinterpret_cast(const_cast(str)), strlen(str), addr, encoding, function)); } -int16_t PagerClient::transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding, uint8_t function) { +int16_t PagerClient::transmit(const uint8_t* data, size_t len, uint32_t addr, uint8_t encoding, uint8_t function) { if(addr > RADIOLIB_PAGER_ADDRESS_MAX) { return(RADIOLIB_ERR_INVALID_ADDRESS_WIDTH); } @@ -326,14 +326,14 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { // check tone-only transmissions if(length == 0) { length = 6; - strncpy((char*)data, "", length + 1); + strncpy(reinterpret_cast(data), "", length + 1); } // add null terminator data[length] = 0; // initialize Arduino String class - str = String((char*)data); + str = String(reinterpret_cast(data)); } // deallocate temporary buffer @@ -494,7 +494,7 @@ bool PagerClient::addressMatched(uint32_t addr) { return(false); } -void PagerClient::write(uint32_t* data, size_t len) { +void PagerClient::write(const uint32_t* data, size_t len) { // write code words from buffer for(size_t i = 0; i < len; i++) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("POCSAG W\t%lu\t%08lX", (long unsigned int)i, (long unsigned int)data[i]); diff --git a/src/protocols/Pager/Pager.h b/src/protocols/Pager/Pager.h index 6963a686a9..4de463479c 100644 --- a/src/protocols/Pager/Pager.h +++ b/src/protocols/Pager/Pager.h @@ -117,7 +117,7 @@ class PagerClient { \param function bits (NUMERIC, TONE, ACTIVATION, ALPHANUMERIC). Allowed values 0 to 3. Defaults to auto select by specified encoding \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); + int16_t transmit(const uint8_t* data, size_t len, uint32_t addr, uint8_t encoding = RADIOLIB_PAGER_BCD, uint8_t function = RADIOLIB_PAGER_FUNC_AUTO); #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! @@ -190,7 +190,7 @@ class PagerClient { size_t filterNumAddresses = 0; bool inv = false; - void write(uint32_t* data, size_t len); + void write(const uint32_t* data, size_t len); void write(uint32_t codeWord); int16_t startReceiveCommon(); bool addressMatched(uint32_t addr); From d685534154f531c205e85c314018c81683ab2f38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:50:09 +0100 Subject: [PATCH 1453/1848] [Print] Cppcheck fixes --- src/protocols/Print/ITA2String.cpp | 8 ++++++-- src/protocols/Print/Print.cpp | 6 +++--- src/protocols/Print/Print.h | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp index 368edebf32..809a1c569e 100644 --- a/src/protocols/Print/ITA2String.cpp +++ b/src/protocols/Print/ITA2String.cpp @@ -122,11 +122,15 @@ uint16_t ITA2String::getBits(char c) { // search ITA2 table uint16_t code = 0x0000; for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { - if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { + char* ptr = const_cast(&ITA2Table[i][0]); + if(RADIOLIB_NONVOLATILE_READ_BYTE(ptr) == c) { // character is in letter shift code = (RADIOLIB_ITA2_LTRS << 5) | i; break; - } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { + } + + ptr = const_cast(&ITA2Table[i][1]); + if(RADIOLIB_NONVOLATILE_READ_BYTE(ptr) == c) { // character is in figures shift code = (RADIOLIB_ITA2_FIGS << 5) | i; break; diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp index c7abe69572..fffa26c4ac 100644 --- a/src/protocols/Print/Print.cpp +++ b/src/protocols/Print/Print.cpp @@ -59,7 +59,7 @@ size_t RadioLibPrint::print(const __FlashStringHelper* fstr) { ITA2String ita2 = ITA2String(str); n = RadioLibPrint::print(ita2); } else { - n = write((uint8_t*)str, len); + n = write(reinterpret_cast(str), len); } #if !RADIOLIB_STATIC_ONLY delete[] str; @@ -73,7 +73,7 @@ size_t RadioLibPrint::print(const String& str) { ITA2String ita2 = ITA2String(str.c_str()); n = RadioLibPrint::print(ita2); } else { - n = write((uint8_t*)str.c_str(), str.length()); + n = write(reinterpret_cast(const_cast(str.c_str())), str.length()); } return(n); } @@ -97,7 +97,7 @@ size_t RadioLibPrint::print(const char str[]) { ITA2String ita2 = ITA2String(str); n = RadioLibPrint::print(ita2); } else { - n = write((uint8_t*)str, strlen(str)); + n = write(reinterpret_cast(const_cast(str)), strlen(str)); } return(n); } diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index 3645416f9d..5760d484dd 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -62,8 +62,8 @@ class RadioLibPrint { uint8_t encoding = RADIOLIB_ASCII_EXTENDED; const char* lineFeed = "\r\n"; - size_t printNumber(unsigned long, uint8_t); - size_t printFloat(double, uint8_t); + virtual size_t printNumber(unsigned long, uint8_t); + virtual size_t printFloat(double, uint8_t); }; From de33ce4d6ae8c137dc142e045bd53fb7b0a7b109 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:50:53 +0100 Subject: [PATCH 1454/1848] [PHY] Cppcheck fixes --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 2872cca312..3bf447eee7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -51,7 +51,7 @@ int16_t PhysicalLayer::transmit(String& str, uint8_t addr) { #endif int16_t PhysicalLayer::transmit(const char* str, uint8_t addr) { - return(transmit((uint8_t*)str, strlen(str), addr)); + return(transmit(reinterpret_cast(const_cast(str)), strlen(str), addr)); } int16_t PhysicalLayer::transmit(const uint8_t* data, size_t len, uint8_t addr) { @@ -96,7 +96,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { data[length] = 0; // initialize Arduino String class - str = String((char*)data); + str = String(reinterpret_cast(data)); } // deallocate temporary buffer @@ -146,7 +146,7 @@ int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) { #endif int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { - return(startTransmit((uint8_t*)str, strlen(str), addr)); + return(startTransmit(reinterpret_cast(const_cast(str)), strlen(str), addr)); } int16_t PhysicalLayer::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { @@ -191,7 +191,7 @@ int16_t PhysicalLayer::readData(String& str, size_t len) { data[length] = 0; // initialize Arduino String class - str = String((char*)data); + str = String(reinterpret_cast(data)); } // deallocate temporary buffer From cc9ce359b6b4c41026a50d57edbefc9a1b98181b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:51:11 +0100 Subject: [PATCH 1455/1848] [OPT] Cppcheck fixes --- src/BuildOpt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 29be4d8ae7..c617c558fc 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -433,8 +433,8 @@ #define RADIOLIB_NC (0xFFFFFFFF) #define RADIOLIB_NONVOLATILE - #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*((uint8_t *)(void *)(addr))) - #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*((uint32_t *)(void *)(addr))) + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) (*(reinterpret_cast(reinterpret_cast(addr)))) + #define RADIOLIB_NONVOLATILE_READ_DWORD(addr) (*(reinterpret_cast(reinterpret_cast(addr)))) #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; #define DEC 10 From aab3e053862aa4e38e22910e734f4139f11bf3d6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:51:30 +0100 Subject: [PATCH 1456/1848] [Crypto] Cppcheck fixes --- src/utils/Cryptography.cpp | 14 ++++++++------ src/utils/Cryptography.h | 6 +++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp index 9411bd1a31..43477358e1 100644 --- a/src/utils/Cryptography.cpp +++ b/src/utils/Cryptography.cpp @@ -11,7 +11,7 @@ void RadioLibAES128::init(uint8_t* key) { this->keyExpansion(this->roundKey, key); } -size_t RadioLibAES128::encryptECB(uint8_t* in, size_t len, uint8_t* out) { +size_t RadioLibAES128::encryptECB(const uint8_t* in, size_t len, uint8_t* out) { size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; if(len % RADIOLIB_AES128_BLOCK_SIZE) { num_blocks++; @@ -27,7 +27,7 @@ size_t RadioLibAES128::encryptECB(uint8_t* in, size_t len, uint8_t* out) { return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); } -size_t RadioLibAES128::decryptECB(uint8_t* in, size_t len, uint8_t* out) { +size_t RadioLibAES128::decryptECB(const uint8_t* in, size_t len, uint8_t* out) { size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; if(len % RADIOLIB_AES128_BLOCK_SIZE) { num_blocks++; @@ -43,7 +43,7 @@ size_t RadioLibAES128::decryptECB(uint8_t* in, size_t len, uint8_t* out) { return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); } -void RadioLibAES128::generateCMAC(uint8_t* in, size_t len, uint8_t* cmac) { +void RadioLibAES128::generateCMAC(const uint8_t* in, size_t len, uint8_t* cmac) { uint8_t key1[RADIOLIB_AES128_BLOCK_SIZE]; uint8_t key2[RADIOLIB_AES128_BLOCK_SIZE]; this->generateSubkeys(key1, key2); @@ -155,7 +155,8 @@ void RadioLibAES128::decipher(state_t* state, uint8_t* roundKey) { void RadioLibAES128::subWord(uint8_t* word) { for(size_t i = 0; i < 4; i++) { - word[i] = RADIOLIB_NONVOLATILE_READ_BYTE(&aesSbox[word[i]]); + uint8_t* ptr = const_cast(&aesSbox[word[i]]); + word[i] = RADIOLIB_NONVOLATILE_READ_BYTE(ptr); } } @@ -198,7 +199,7 @@ void RadioLibAES128::generateSubkeys(uint8_t* key1, uint8_t* key2) { 0x00, 0x00, 0x00, 0x00 }; - uint8_t const_Rb[] = { + const uint8_t const_Rb[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -221,7 +222,8 @@ void RadioLibAES128::generateSubkeys(uint8_t* key1, uint8_t* key2) { void RadioLibAES128::subBytes(state_t* state, const uint8_t* box) { for(size_t row = 0; row < 4; row++) { for(size_t col = 0; col < 4; col++) { - (*state)[col][row] = RADIOLIB_NONVOLATILE_READ_BYTE(&box[(*state)[col][row]]); + uint8_t* ptr = const_cast(&box[(*state)[col][row]]); + (*state)[col][row] = RADIOLIB_NONVOLATILE_READ_BYTE(ptr); } } } diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index ed8f4d7a82..da5bb33f95 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -115,7 +115,7 @@ class RadioLibAES128 { to ensure the buffer is sufficiently large to save the data! \returns The number of bytes saved into the output buffer. */ - size_t encryptECB(uint8_t* in, size_t len, uint8_t* out); + size_t encryptECB(const uint8_t* in, size_t len, uint8_t* out); /*! \brief Perform ECB-type AES decryption. @@ -125,7 +125,7 @@ class RadioLibAES128 { to ensure the buffer is sufficiently large to save the data! \returns The number of bytes saved into the output buffer. */ - size_t decryptECB(uint8_t* in, size_t len, uint8_t* out); + size_t decryptECB(const uint8_t* in, size_t len, uint8_t* out); /*! \brief Calculate message authentication code according to RFC4493. @@ -133,7 +133,7 @@ class RadioLibAES128 { \param len Length of the input data. \param cmac Buffer to save the output MAC into. The buffer must be at least 16 bytes long! */ - void generateCMAC(uint8_t* in, size_t len, uint8_t* cmac); + void generateCMAC(const uint8_t* in, size_t len, uint8_t* cmac); /*! \brief Verify the received CMAC. This just calculates the CMAC again and compares the results. From ff24e2b2ae3a2eee92bf9992c2ddbbef4b8a40fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 17:51:57 +0100 Subject: [PATCH 1457/1848] [LoRaWAN] Cppcheck fixes --- src/protocols/LoRaWAN/LoRaWAN.cpp | 53 ++++++++++++++----------------- src/protocols/LoRaWAN/LoRaWAN.h | 12 ++++--- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 17e51ca4e8..948fffe7c4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -24,16 +24,16 @@ int16_t LoRaWANNode::sendReceive(const String& strUp, uint8_t fPort, String& str // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; - uint8_t dataDown[251]; + uint8_t dataDown[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE + 1]; - state = this->sendReceive((const uint8_t*)dataUp, strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); + state = this->sendReceive(reinterpret_cast(dataUp), strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); if(state == RADIOLIB_ERR_NONE) { // add null terminator dataDown[lenDown] = '\0'; // initialize Arduino String class - strDown = String((char*)dataDown); + strDown = String(reinterpret_cast(dataDown)); } return(state); @@ -44,20 +44,20 @@ int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, bool isConfir // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; - uint8_t dataDown[251]; + uint8_t dataDown[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE + 1]; - return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); + return(this->sendReceive(reinterpret_cast(const_cast(strUp)), strlen(strUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); } int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { - return(this->sendReceive((uint8_t*)strUp, strlen(strUp), fPort, dataDown, lenDown, isConfirmed, eventUp, eventDown)); + return(this->sendReceive(reinterpret_cast(const_cast(strUp)), strlen(strUp), fPort, dataDown, lenDown, isConfirmed, eventUp, eventDown)); } int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; - uint8_t dataDown[251]; + uint8_t dataDown[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE + 1]; return(this->sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); } @@ -518,10 +518,10 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { // for dynamic bands, the additional channels must be restored per-channel if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // all-zero buffer used for checking if MAC commands are set - uint8_t bufferZeroes[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; + const uint8_t bufferZeroes[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; // restore the session channels - uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; + const uint8_t *startChannelsUp = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS]; cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); @@ -532,7 +532,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { } } - uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; + const uint8_t *startChannelsDown = &this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS]; cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); @@ -550,12 +550,13 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { memcpy(cOcts, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cLen); (void)execMacCommand(cid, cOcts, cLen); - uint8_t cids[6] = { + const uint8_t cids[6] = { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP }; - uint16_t locs[6] = { + + const uint16_t locs[6] = { RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE, RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP, RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP @@ -995,7 +996,7 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { return(RADIOLIB_LORAWAN_NEW_SESSION); } -void LoRaWANNode::processCFList(uint8_t* cfList) { +void LoRaWANNode::processCFList(const uint8_t* cfList) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); uint8_t cOcts[14] = { 0 }; // TODO explain @@ -1015,7 +1016,7 @@ void LoRaWANNode::processCFList(uint8_t* cfList) { cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); - uint8_t freqZero[3] = { 0 }; + const uint8_t freqZero[3] = { 0 }; // datarate range for all new channels is equal to the default channels cOcts[4] = (this->band->txFreqs[0].drMax << 4) | this->band->txFreqs[0].drMin; @@ -1264,7 +1265,7 @@ void LoRaWANNode::micUplink(uint8_t* inOut, uint8_t lenInOut) { } } -int16_t LoRaWANNode::transmitUplink(LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans) { +int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans) { int16_t state = RADIOLIB_ERR_UNKNOWN; Module* mod = this->phyLayer->getMod(); @@ -1707,12 +1708,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e uint8_t fLen = 1; uint8_t* mPtr = fOpts; uint8_t procLen = 0; - - #if !RADIOLIB_STATIC_ONLY - uint8_t* fOptsRe = new uint8_t[250]; - #else - uint8_t fOptsRe[RADIOLIB_STATIC_ARRAY_SIZE]; - #endif + uint8_t fOptsRe[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE] = { 0 }; uint8_t fOptsReLen = 0; // indication whether LinkAdr MAC command has been processed @@ -1836,7 +1832,6 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e #if !RADIOLIB_STATIC_ONLY delete[] fOpts; - delete[] fOptsRe; delete[] downlinkMsg; #endif @@ -2213,7 +2208,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin if(delay == 0) { delay = 1; } - this->rxDelays[1] = delay * 1000; // Rx1 delay + this->rxDelays[1] = (RadioLibTime_t)delay * (RadioLibTime_t)1000; // Rx1 delay this->rxDelays[2] = this->rxDelays[1] + 1000; // Rx2 delay memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP], optIn, lenIn); @@ -2258,7 +2253,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // if not a valid server version, retransmit RekeyInd uint8_t cLen = 0; this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_UPLINK); - uint8_t cOcts[1] = { this->rev }; + const uint8_t cOcts[1] = { this->rev }; (void)LoRaWANNode::pushMacCommand(cid, cOcts, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); // discard RekeyConf, therefore return false so it doesn't send a reply @@ -2422,7 +2417,7 @@ void LoRaWANNode::postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen) { int16_t LoRaWANNode::getMacCommand(uint8_t cid, LoRaWANMacCommand_t* cmd) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { - memcpy((void*)cmd, (void*)&MacTable[i], sizeof(LoRaWANMacCommand_t)); + memcpy(reinterpret_cast(cmd), (void*)&MacTable[i], sizeof(LoRaWANMacCommand_t)); return(RADIOLIB_ERR_NONE); } } @@ -2521,7 +2516,7 @@ bool LoRaWANNode::isPersistentMacCommand(uint8_t cid, uint8_t dir) { return(false); } -int16_t LoRaWANNode::pushMacCommand(uint8_t cid, uint8_t* cOcts, uint8_t* out, uint8_t* lenOut, uint8_t dir) { +int16_t LoRaWANNode::pushMacCommand(uint8_t cid, const uint8_t* cOcts, uint8_t* out, uint8_t* lenOut, uint8_t dir) { uint8_t fLen = 0; int16_t state = this->getMacLen(cid, &fLen, dir, true); RADIOLIB_ASSERT(state); @@ -2538,7 +2533,7 @@ int16_t LoRaWANNode::pushMacCommand(uint8_t cid, uint8_t* cOcts, uint8_t* out, u return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::getMacPayload(uint8_t cid, uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t dir) { +int16_t LoRaWANNode::getMacPayload(uint8_t cid, const uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t dir) { size_t i = 0; while(i < lenIn) { @@ -2625,7 +2620,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp) { // scan through all enabled channels and check if the requested datarate is available bool isValidDR = false; for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - LoRaWANChannel_t *chnl = &(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i]); + const LoRaWANChannel_t *chnl = &(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i]); if(chnl->enabled) { if(drUp >= chnl->drMin && drUp <= chnl->drMax) { isValidDR = true; @@ -3220,7 +3215,7 @@ void LoRaWANNode::printChannels() { } #endif -uint32_t LoRaWANNode::generateMIC(uint8_t* msg, size_t len, uint8_t* key) { +uint32_t LoRaWANNode::generateMIC(const uint8_t* msg, size_t len, uint8_t* key) { if((msg == NULL) || (len == 0)) { return(0); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 90a51ab8da..977db46807 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -208,6 +208,8 @@ #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) +#define RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE (250) + /*! \struct LoRaWANMacCommand_t \brief MAC command specification structure. @@ -984,7 +986,7 @@ class LoRaWANNode { int16_t processJoinAccept(LoRaWANJoinEvent_t *joinEvent); // a join-accept can piggy-back a set of channels or channel masks - void processCFList(uint8_t* cfList); + void processCFList(const uint8_t* cfList); // check whether payload length and fport are allowed int16_t isValidUplink(uint8_t* len, uint8_t fPort); @@ -999,7 +1001,7 @@ class LoRaWANNode { void micUplink(uint8_t* inOut, uint8_t lenInOut); // transmit uplink buffer on a specified channel - int16_t transmitUplink(LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans); + int16_t transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans); // wait for, open and listen during receive windows; only performs listening int16_t receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChannels, const RadioLibTime_t* dlDelays, uint8_t numWindows, RadioLibTime_t tReference); @@ -1036,10 +1038,10 @@ class LoRaWANNode { bool isPersistentMacCommand(uint8_t cid, uint8_t dir); // push MAC command to queue, done by copy - int16_t pushMacCommand(uint8_t cid, uint8_t* cOcts, uint8_t* out, uint8_t* lenOut, uint8_t dir); + int16_t pushMacCommand(uint8_t cid, const uint8_t* cOcts, uint8_t* out, uint8_t* lenOut, uint8_t dir); // retrieve the payload of a certain MAC command, if present in the buffer - int16_t getMacPayload(uint8_t cid, uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t dir); + int16_t getMacPayload(uint8_t cid, const uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t dir); // delete a specific MAC command from queue, indicated by the command ID int16_t deleteMacCommand(uint8_t cid, uint8_t* inOut, uint8_t* lenInOut, uint8_t dir); @@ -1087,7 +1089,7 @@ class LoRaWANNode { #endif // method to generate message integrity code - uint32_t generateMIC(uint8_t* msg, size_t len, uint8_t* key); + uint32_t generateMIC(const uint8_t* msg, size_t len, uint8_t* key); // method to verify message integrity code // it assumes that the MIC is the last 4 bytes of the message From 1324b53f7bba3f8e5bf737ca042dfe5157e25cad Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 18:14:34 +0100 Subject: [PATCH 1458/1848] [Print] Fix duplicate methods --- src/protocols/Hellschreiber/Hellschreiber.h | 3 --- src/protocols/Morse/Morse.h | 3 --- src/protocols/Print/Print.h | 4 ++-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index ff78fd1b38..10e67272d1 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -144,9 +144,6 @@ class HellClient: public RadioLibPrint { uint32_t pixelDuration = 0; bool invert = false; - size_t printNumber(unsigned long, uint8_t) override; - size_t printFloat(double, uint8_t) override; - int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); int16_t standby(); }; diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index ad491bce83..3bcf0f9309 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -172,9 +172,6 @@ class MorseClient: public RadioLibPrint { uint32_t pauseCounter = 0; RadioLibTime_t pauseStart = 0; - size_t printNumber(unsigned long, uint8_t) override; - size_t printFloat(double, uint8_t) override; - int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); int16_t standby(); }; diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h index 5760d484dd..3645416f9d 100644 --- a/src/protocols/Print/Print.h +++ b/src/protocols/Print/Print.h @@ -62,8 +62,8 @@ class RadioLibPrint { uint8_t encoding = RADIOLIB_ASCII_EXTENDED; const char* lineFeed = "\r\n"; - virtual size_t printNumber(unsigned long, uint8_t); - virtual size_t printFloat(double, uint8_t); + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); }; From 64f0f5028bc6e8eba07071f8d182bb0d54f027fb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 18:14:56 +0100 Subject: [PATCH 1459/1848] [LoRaWAN] Cppcheck fixes --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 ++- src/utils/Cryptography.cpp | 4 ++-- src/utils/Cryptography.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 948fffe7c4..7c1323711c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2417,7 +2417,8 @@ void LoRaWANNode::postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen) { int16_t LoRaWANNode::getMacCommand(uint8_t cid, LoRaWANMacCommand_t* cmd) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { - memcpy(reinterpret_cast(cmd), (void*)&MacTable[i], sizeof(LoRaWANMacCommand_t)); + LoRaWANMacCommand_t* cmdPtr = const_cast(&MacTable[i]); + memcpy(reinterpret_cast(cmd), reinterpret_cast(cmdPtr), sizeof(LoRaWANMacCommand_t)); return(RADIOLIB_ERR_NONE); } } diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp index 43477358e1..2039d214bb 100644 --- a/src/utils/Cryptography.cpp +++ b/src/utils/Cryptography.cpp @@ -82,7 +82,7 @@ void RadioLibAES128::generateCMAC(const uint8_t* in, size_t len, uint8_t* cmac) delete[] buff; } -bool RadioLibAES128::verifyCMAC(uint8_t* in, size_t len, const uint8_t* cmac) { +bool RadioLibAES128::verifyCMAC(const uint8_t* in, size_t len, const uint8_t* cmac) { uint8_t cmacReal[RADIOLIB_AES128_BLOCK_SIZE]; this->generateCMAC(in, len, cmacReal); for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { @@ -192,7 +192,7 @@ void RadioLibAES128::blockLeftshift(uint8_t* dst, const uint8_t* src) { } void RadioLibAES128::generateSubkeys(uint8_t* key1, uint8_t* key2) { - uint8_t const_Zero[] = { + const uint8_t const_Zero[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index da5bb33f95..4a5ddca520 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -142,7 +142,7 @@ class RadioLibAES128 { \param cmac CMAC to verify. \returns True if valid, false otherwise. */ - bool verifyCMAC(uint8_t* in, size_t len, const uint8_t* cmac); + bool verifyCMAC(const uint8_t* in, size_t len, const uint8_t* cmac); private: uint8_t* keyPtr = nullptr; From 0cd69b2e6f544c97b885125a0de7934101ed28fb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 18:34:33 +0100 Subject: [PATCH 1460/1848] [CI] Use v4 artifact download --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 31d48940c4..d6e09112f9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -223,7 +223,7 @@ jobs: git config --global user.email "${{ github.actor }}@users.noreply.github.com" - name: Download size artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: aggregated-sizes From 269eb2fe3888bb32d2c5559a2b8bd278c1ce3c44 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 21:22:17 +0100 Subject: [PATCH 1461/1848] [LoRaWAN] Fix typecast --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7c1323711c..1f4a4dfe45 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2417,8 +2417,7 @@ void LoRaWANNode::postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen) { int16_t LoRaWANNode::getMacCommand(uint8_t cid, LoRaWANMacCommand_t* cmd) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) { if(MacTable[i].cid == cid) { - LoRaWANMacCommand_t* cmdPtr = const_cast(&MacTable[i]); - memcpy(reinterpret_cast(cmd), reinterpret_cast(cmdPtr), sizeof(LoRaWANMacCommand_t)); + memcpy(reinterpret_cast(cmd), reinterpret_cast(const_cast(&MacTable[i])), sizeof(LoRaWANMacCommand_t)); return(RADIOLIB_ERR_NONE); } } From cbb8126442f6da696f2d64dd4747caf44e79b8b5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Jan 2025 21:23:01 +0100 Subject: [PATCH 1462/1848] [LoRaWAN] Fix possible integer overflow --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 1f4a4dfe45..3b82c1f0b1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2958,11 +2958,11 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr // if a subband is set, we can set the channel indices straight from subband if(this->subBand > 0 && this->subBand <= 8) { // for sub band 1-8, set bank of 8 125kHz + single 500kHz channel - *chMaskGrp0123 |= 0xFF << ((this->subBand - 1) * 8); - *chMaskGrp45 |= 0x01 << ((this->subBand - 1) * 8); + *chMaskGrp0123 |= (uint64_t)0xFF << ((this->subBand - 1) * 8); + *chMaskGrp45 |= (uint32_t)0x01 << (this->subBand - 1); } else if(this->subBand > 8 && this->subBand <= 12) { // CN500 only: for sub band 9-12, set bank of 8 125kHz channels - *chMaskGrp45 |= 0xFF << ((this->subBand - 9) * 8); + *chMaskGrp45 |= (uint32_t)0xFF << ((this->subBand - 9) * 8); } else { // if subband is set to 0, all 125kHz channels are enabled. // however, we can 'only' store 16 channels, so we don't use all channels at once. From 21a77a6389144db0169881cb757c56d55a2f36b4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 13:26:51 +0000 Subject: [PATCH 1463/1848] [Morse] Fix debug output --- src/protocols/Morse/Morse.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 6c4ffaf2d2..c261773bf5 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -139,15 +139,16 @@ size_t MorseClient::write(uint8_t b) { } // iterate through codeword until guard bit is reached + RADIOLIB_DEBUG_PROTOCOL_PRINT("%c ", b); while(code > RADIOLIB_MORSE_GUARDBIT) { // send dot or dash if (code & RADIOLIB_MORSE_DASH) { - RADIOLIB_DEBUG_PROTOCOL_PRINT("-"); + RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG("-"); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(mod->hal->micros(), dashLength*1000); } else { - RADIOLIB_DEBUG_PROTOCOL_PRINT("."); + RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG("."); transmitDirect(baseFreq, baseFreqHz); mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000); } @@ -163,7 +164,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(); + RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG("\n"); return(1); } From 650d00b3e382d3d5ef8808103dc70ae1dbb81639 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 13:27:14 +0000 Subject: [PATCH 1464/1848] Added no-tag debug macro to protocol level --- src/BuildOpt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index c617c558fc..89c2685389 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -509,11 +509,13 @@ #if RADIOLIB_DEBUG_PROTOCOL #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_PRO: ", __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_PRO: ", __VA_ARGS__) #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_PRO: ", __VA_ARGS__); #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_PRO: ", __VA_ARGS__); #else #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {} #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) {} From 8126e6f508882e8872a99da3edf8f2cac63a8011 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 18:29:56 +0100 Subject: [PATCH 1465/1848] Suppress double promotion warning for debug --- src/modules/Si443x/Si443x.cpp | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 3e61488ea4..b66a9d228c 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -766,7 +766,7 @@ int16_t Si443x::updateClockRecovery() { // print that whole mess RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); - RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2); + RADIOLIB_DEBUG_BASIC_PRINT_FLOAT((double)rxOsr, 2); RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain); // update oversampling ratio diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 3b82c1f0b1..cc6ed3df73 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2167,7 +2167,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // get the configuration uint8_t macChIndex = optIn[0]; uint32_t macFreq = LoRaWANNode::ntoh(&optIn[1], 3); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %7.3f MHz", macChIndex, macFreq / 10000.0f); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %7.3f MHz", macChIndex, macFreq / 10000.0); uint8_t freqDlAck = 0; uint8_t freqUlAck = 0; @@ -2865,7 +2865,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; syncWordLen = 3; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, FD = %4.1f kHz", - dr.fsk.bitRate, dr.fsk.freqDev); + (double)dr.fsk.bitRate, (double)dr.fsk.freqDev); } break; case(ModemType_t::RADIOLIB_MODEM_LORA): { @@ -2873,7 +2873,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", - dr.lora.spreadingFactor, dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); + dr.lora.spreadingFactor, (double)dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); } break; case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { From 4733fdd9d1e656009642588bb975a9645c0b7322 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 18:30:02 +0100 Subject: [PATCH 1466/1848] Fix debug prints --- src/utils/Utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 4111818fb9..11a473c60c 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -59,9 +59,9 @@ void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t of sprintf(strPtr++, " "); } if(level) { - RADIOLIB_DEBUG_PRINT(level); + RADIOLIB_DEBUG_PRINT("%s", level); } - RADIOLIB_DEBUG_PRINT(str); + RADIOLIB_DEBUG_PRINT("%s", str); RADIOLIB_DEBUG_PRINTLN(); rem_len -= 16; } From 3e146c891eed7fe6412ae84a4e7aae8c63213d33 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 21:45:32 +0100 Subject: [PATCH 1467/1848] [CI] Fix SPI log wipe --- extras/test/unit/include/TestHal.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/extras/test/unit/include/TestHal.hpp b/extras/test/unit/include/TestHal.hpp index 389bef13f4..56b90cb601 100644 --- a/extras/test/unit/include/TestHal.hpp +++ b/extras/test/unit/include/TestHal.hpp @@ -47,6 +47,9 @@ class TestHal : public RadioLibHal { this->gpio[i].event = false; this->gpio[i].func = PIN_UNASSIGNED; } + + // wipe history log + this->spiLogWipe(); } void term() override { @@ -181,10 +184,6 @@ class TestHal : public RadioLibHal { void spiBeginTransaction() { HAL_LOG("TestHal::spiBeginTransaction()"); - - // wipe history log - memset(this->spiLog, 0x00, TEST_HAL_SPI_LOG_LENGTH); - this->spiLogPtr = this->spiLog; } void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { @@ -228,7 +227,14 @@ class TestHal : public RadioLibHal { // method to compare buffer to the internal SPI log, for verifying SPI transactions int spiLogMemcmp(const void* in, size_t n) { - return(memcmp(this->spiLog, in, n)); + int ret = memcmp(this->spiLog, in, n); + this->spiLogWipe(); + return(ret); + } + + void spiLogWipe() { + memset(this->spiLog, 0x00, TEST_HAL_SPI_LOG_LENGTH); + this->spiLogPtr = this->spiLog; } // method that "connects" the emualted radio hardware to this HAL From c4ac0ac68b8b8b12cd03691b407e03d809e67935 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 21:46:00 +0100 Subject: [PATCH 1468/1848] [CI] Add artificial delay to unit test emulated SPI --- extras/test/unit/include/TestHal.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extras/test/unit/include/TestHal.hpp b/extras/test/unit/include/TestHal.hpp index 56b90cb601..ae98745bf9 100644 --- a/extras/test/unit/include/TestHal.hpp +++ b/extras/test/unit/include/TestHal.hpp @@ -196,7 +196,12 @@ class TestHal : public RadioLibHal { // process the SPI byte in[i] = this->radio->HandleSPI(out[i]); - // outpu debug + // artificial delay to emulate SPI running at a finite speed + // this is added because timeouts are based on time duration, + // so we need to make sure some time actually elapses + this->delayMicroseconds(100); + + // output debug HAL_LOG(fmt::format("out={:#02x}, in={:#02x}", out[i], in[i])); } } From bedab1a66dc088fbe1bee0c9c42c5d1de7a8f834 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Jan 2025 21:48:39 +0100 Subject: [PATCH 1469/1848] [CI] Add unit test for SPIsetRegValue --- extras/test/unit/CMakeLists.txt | 3 +- extras/test/unit/tests/TestModule.cpp | 130 +++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt index a907258c12..300b886935 100644 --- a/extras/test/unit/CMakeLists.txt +++ b/extras/test/unit/CMakeLists.txt @@ -25,5 +25,4 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra) # set RadioLib debug -#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI) -#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_PORT=stdout) +#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI RADIOLIB_DEBUG_PROTOCOL) diff --git a/extras/test/unit/tests/TestModule.cpp b/extras/test/unit/tests/TestModule.cpp index f2815d6bc2..6bd145930a 100644 --- a/extras/test/unit/tests/TestModule.cpp +++ b/extras/test/unit/tests/TestModule.cpp @@ -48,8 +48,9 @@ BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture) // register read masking test const uint8_t msb = 5; const uint8_t lsb = 1; + const uint8_t maskedValue = 0x3E; ret = mod->SPIgetRegValue(address, msb, lsb); - BOOST_TEST(ret == 0x3E); + BOOST_TEST(ret == maskedValue); // invalid mask tests (swapped MSB and LSB, out of range bit masks) ret = mod->SPIgetRegValue(address, lsb, msb); @@ -60,6 +61,60 @@ BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture) BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); } + BOOST_FIXTURE_TEST_CASE(Module_SPIsetRegValue_reg, ModuleFixture) + { + BOOST_TEST_MESSAGE("--- Test Module::SPIsetRegValue register access ---"); + int16_t ret; + + // basic register write with default config + const uint8_t address = 0x12; + const uint8_t value = 0xAB; + const uint8_t spiTxn[] = { address, 0x00, 0x80 | address, value }; + ret = mod->SPIsetRegValue(address, value); + + // check return code and history log + // this will return write error because the bare emulated radio has no internal logic + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + + // register write masking test + const uint8_t msb = 5; + const uint8_t lsb = 1; + const uint8_t maskedValue = 0xEB; + const uint8_t spiTxn2[] = { address, 0x00, 0x80 | address, maskedValue }; + ret = mod->SPIsetRegValue(address, value, msb, lsb); + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn2, sizeof(spiTxn2)) == 0); + + // invalid mask tests (swapped MSB and LSB, out of range bit masks) + ret = mod->SPIsetRegValue(address, value, lsb, msb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIsetRegValue(address, value, 10, lsb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIsetRegValue(address, value, msb, 10); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + + // check interval test + const uint8_t interval = 200; + const unsigned long start = hal->micros(); + ret = mod->SPIsetRegValue(address, value, 7, 0, interval); + const unsigned long stop = hal->micros(); + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + const unsigned long elapsed = stop - start; + BOOST_TEST(elapsed >= (unsigned long)interval*1000UL); + + // disabled check mask test + ret = mod->SPIsetRegValue(address, value, 7, 0, 2, 0); + BOOST_TEST(ret == RADIOLIB_ERR_NONE); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + + // forced write test + ret = mod->SPIsetRegValue(address, value, 7, 0, 2, 0xFF, true); + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + } + BOOST_FIXTURE_TEST_CASE(Module_SPIgetRegValue_stream, ModuleFixture) { BOOST_TEST_MESSAGE("--- Test Module::SPIgetRegValue stream access ---"); @@ -88,8 +143,9 @@ BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture) // register read masking test const uint8_t msb = 5; const uint8_t lsb = 1; + const uint8_t maskedValue = 0x3E; ret = mod->SPIgetRegValue(address, msb, lsb); - BOOST_TEST(ret == 0x3E); + BOOST_TEST(ret == maskedValue); // invalid mask tests (swapped MSB and LSB, out of range bit masks) ret = mod->SPIgetRegValue(address, lsb, msb); @@ -100,4 +156,74 @@ BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture) BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); } + BOOST_FIXTURE_TEST_CASE(Module_SPIsetRegValue_stream, ModuleFixture) + { + BOOST_TEST_MESSAGE("--- Test Module::SPIsetRegValue stream access ---"); + int16_t ret; + + // change settings to stream type + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; + mod->spiConfig.statusPos = 1; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP; + mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; + mod->spiConfig.stream = true; + + // basic register write with default config + const uint8_t address = 0x12; + const uint8_t value = 0xAB; + const uint8_t spiTxn[] = { + RADIOLIB_SX126X_CMD_READ_REGISTER, 0x00, address, 0x00, 0x00, + RADIOLIB_SX126X_CMD_WRITE_REGISTER, 0x00, address, value, + }; + ret = mod->SPIsetRegValue(address, value); + + // check return code and history log + // this will return write error because the bare emulated radio has no internal logic + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + + // register write masking test + const uint8_t msb = 5; + const uint8_t lsb = 1; + const uint8_t maskedValue = 0xEB; + const uint8_t spiTxn2[] = { + RADIOLIB_SX126X_CMD_READ_REGISTER, 0x00, address, 0x00, 0x00, + RADIOLIB_SX126X_CMD_WRITE_REGISTER, 0x00, address, maskedValue, + }; + ret = mod->SPIsetRegValue(address, value, msb, lsb); + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn2, sizeof(spiTxn2)) == 0); + + // invalid mask tests (swapped MSB and LSB, out of range bit masks) + ret = mod->SPIsetRegValue(address, value, lsb, msb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIsetRegValue(address, value, 10, lsb); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + ret = mod->SPIsetRegValue(address, value, msb, 10); + BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE); + + // check interval test + const uint8_t interval = 200; + const unsigned long start = hal->micros(); + ret = mod->SPIsetRegValue(address, value, 7, 0, interval); + const unsigned long stop = hal->micros(); + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + const unsigned long elapsed = stop - start; + BOOST_TEST(elapsed >= (unsigned long)interval*1000UL); + + // disabled check mask test + ret = mod->SPIsetRegValue(address, value, 7, 0, 2, 0); + BOOST_TEST(ret == RADIOLIB_ERR_NONE); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + + // forced write test + ret = mod->SPIsetRegValue(address, value, 7, 0, 2, 0xFF, true); + BOOST_TEST(ret == RADIOLIB_ERR_SPI_WRITE_FAILED); + BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0); + } + BOOST_AUTO_TEST_SUITE_END() From 5979a2a7be02e0aafd849f5d7d6f7f1e274a6e1e Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Thu, 23 Jan 2025 15:35:09 +0300 Subject: [PATCH 1470/1848] add chip revision number for SX123xH --- src/modules/SX123x/SX1231.cpp | 5 ++++- src/modules/SX123x/SX1231.h | 1 + src/modules/SX123x/SX1233.cpp | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/SX123x/SX1231.cpp b/src/modules/SX123x/SX1231.cpp index 11424eed31..2b64ff6e7b 100644 --- a/src/modules/SX123x/SX1231.cpp +++ b/src/modules/SX123x/SX1231.cpp @@ -17,7 +17,10 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po bool flagFound = false; while((i < 10) && !flagFound) { int16_t version = getChipVersion(); - if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) { + if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || + (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || + (version == RADIOLIB_SX123X_CHIP_REVISION_2_C) || + (version == RADIOLIB_SX123X_CHIP_REVISION_2_D)) { flagFound = true; this->chipRevision = version; } else { diff --git a/src/modules/SX123x/SX1231.h b/src/modules/SX123x/SX1231.h index fae3aabf41..6e9b66d974 100644 --- a/src/modules/SX123x/SX1231.h +++ b/src/modules/SX123x/SX1231.h @@ -11,6 +11,7 @@ #define RADIOLIB_SX123X_CHIP_REVISION_2_A 0x21 #define RADIOLIB_SX123X_CHIP_REVISION_2_B 0x22 #define RADIOLIB_SX123X_CHIP_REVISION_2_C 0x23 +#define RADIOLIB_SX123X_CHIP_REVISION_2_D 0x24 // RADIOLIB_SX1231 specific register map #define RADIOLIB_SX1231_REG_TEST_OOK 0x6E diff --git a/src/modules/SX123x/SX1233.cpp b/src/modules/SX123x/SX1233.cpp index 81edc00ed7..e414095ef4 100644 --- a/src/modules/SX123x/SX1233.cpp +++ b/src/modules/SX123x/SX1233.cpp @@ -18,7 +18,10 @@ int16_t SX1233::begin(float freq, float br, float freqDev, float rxBw, int8_t po bool flagFound = false; while((i < 10) && !flagFound) { int16_t version = getChipVersion(); - if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || (version == RADIOLIB_SX123X_CHIP_REVISION_2_C)) { + if((version == RADIOLIB_SX123X_CHIP_REVISION_2_A) || + (version == RADIOLIB_SX123X_CHIP_REVISION_2_B) || + (version == RADIOLIB_SX123X_CHIP_REVISION_2_C) || + (version == RADIOLIB_SX123X_CHIP_REVISION_2_D)) { flagFound = true; this->chipRevision = version; } else { From d0cfd5a461692de1c01173cbfb8565c47bbaadcb Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 23 Jan 2025 18:41:16 +0100 Subject: [PATCH 1471/1848] [CI] Only push metrics from master --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d6e09112f9..f8f0b4ef6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -191,6 +191,7 @@ jobs: | cd $PWD/extras/test/ci ./parse_size.sh ${{ matrix.id }} + cat size_${{ steps.short-hash.outputs.short_sha }}_${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}.csv - name: Extract short commit hash id: short-hash @@ -205,6 +206,7 @@ jobs: metrics: runs-on: ubuntu-latest needs: build + if: github.ref == 'refs/heads/master' steps: - name: Set up SSH run: | From c6096ad3b87a14fc212208a8b7d995ccf3d80e70 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 23 Jan 2025 19:04:06 +0100 Subject: [PATCH 1472/1848] [CI] Fix steps order --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f8f0b4ef6d..7ee70772a7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -185,6 +185,10 @@ jobs: cd $PWD/extras/test/ci ./build_examples.sh ${{ matrix.id }} "${{ steps.prep.outputs.skip-pattern }}" ${{ steps.prep.outputs.options }} + - name: Extract short commit hash + id: short-hash + run: echo "::set-output name=short_sha::$(git rev-parse --short HEAD)" + - name: Parse sizes if: ${{ env.run-build == 'true' }} run: @@ -193,10 +197,6 @@ jobs: ./parse_size.sh ${{ matrix.id }} cat size_${{ steps.short-hash.outputs.short_sha }}_${{ steps.split.outputs._0 }}-${{ steps.split.outputs._1 }}-${{ steps.split.outputs._2 }}.csv - - name: Extract short commit hash - id: short-hash - run: echo "::set-output name=short_sha::$(git rev-parse --short HEAD)" - - name: Upload size report as artifact uses: actions/upload-artifact@v4 with: From fc6ff698b9d593d31ee1580f847a15d9ab59bed2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 27 Jan 2025 18:44:49 +0100 Subject: [PATCH 1473/1848] [RF69] Fix sync word length not set correctly (#1400) --- src/modules/RF69/RF69.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 7638799163..6780a17c8f 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -705,12 +705,15 @@ int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBit } } + // enable filtering int16_t state = enableSyncWordFiltering(maxErrBits); RADIOLIB_ASSERT(state); + // set the length + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, len, 5, 3); + // set sync word register this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); - if(state == RADIOLIB_ERR_NONE) { this->syncWordLength = len; } @@ -805,7 +808,11 @@ int16_t RF69::variablePacketLengthMode(uint8_t maxLen) { int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) { // enable sync word recognition - return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC | (this->syncWordLength - 1) << 3 | maxErrBits, 7, 0)); + int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, RADIOLIB_RF69_SYNC_ON | RADIOLIB_RF69_FIFO_FILL_CONDITION_SYNC, 7, 6); + RADIOLIB_ASSERT(state); + + // set maximum error bits + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, maxErrBits, 3, 0)); } int16_t RF69::disableSyncWordFiltering() { From c187960cc170a7b441cc8bcb8f9c0a37a809d8f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Jan 2025 17:51:20 +0000 Subject: [PATCH 1474/1848] [SX126x] Add public method to handle LR-FHSS hopping --- keywords.txt | 1 + src/modules/SX126x/SX126x.cpp | 13 +++++++++++-- src/modules/SX126x/SX126x.h | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index 9457fcb066..f6bc613b6d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -246,6 +246,7 @@ spectralScanAbort KEYWORD2 spectralScanGetStatus KEYWORD2 spectralScanGetResult KEYWORD2 setPaRampTime KEYWORD2 +hopLRFHSS KEYWORD2 # nRF24 setIrqAction KEYWORD2 diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 224858ebb2..777dce09cb 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -235,8 +235,7 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { break; } else { // handle frequency hop - this->setLRFHSSHop(this->lrFhssHopNum % 16); - clearIrqStatus(); + this->hopLRFHSS(); } } } @@ -477,6 +476,16 @@ int16_t SX126x::standby(uint8_t mode, bool wakeup) { return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); } +int16_t SX126x::hopLRFHSS() { + if(!(this->getIrqFlags() & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP)) { + return(RADIOLIB_ERR_TX_TIMEOUT); + } + + int16_t state = this->setLRFHSSHop(this->lrFhssHopNum % 16); + RADIOLIB_ASSERT(state); + return(clearIrqStatus()); +} + void SX126x::setDio1Action(void (*func)(void)) { this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index e37265b0f7..371926cae2 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -628,6 +628,13 @@ class SX126x: public PhysicalLayer { */ int16_t standby(uint8_t mode, bool wakeup = true); + /*! + \brief Handle LR-FHSS hop. + When using LR-FHSS in interrupt-driven mode, this method MUST be called each time an interrupt is triggered! + \returns \ref status_codes + */ + int16_t hopLRFHSS(); + // interrupt methods /*! From 779e0aa4dd624c23f21351cb783000c255adc2a2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Jan 2025 20:45:41 +0100 Subject: [PATCH 1475/1848] [SX126x] Rename LR-FHSS modem example to transmit --- .../SX126x_LR_FHSS_Modem.ino | 96 --------------- .../SX126x_LR_FHSS_Transmit_Blocking.ino | 113 ++++++++++++++++++ 2 files changed, 113 insertions(+), 96 deletions(-) delete mode 100644 examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino create mode 100644 examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino diff --git a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino b/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino deleted file mode 100644 index 44519d51d3..0000000000 --- a/examples/SX126x/SX126x_LR_FHSS_Modem/SX126x_LR_FHSS_Modem.ino +++ /dev/null @@ -1,96 +0,0 @@ -/* - RadioLib SX126x LR-FHSS Modem Example - - This example shows how to use LR-FHSS modem in SX126x chips. - This modem can only transmit data, and is not able to receive. - - NOTE: The sketch below is just a guide on how to use - LR-FHSS modem, so this code should not be run directly! - Instead, modify the other examples to use LR-FHSS - modem and use the appropriate configuration - methods. - - For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem - - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ -*/ - -// include the library -#include - -// SX1262 has the following connections: -// NSS pin: 10 -// IRQ pin: 2 -// NRST pin: 3 -// BUSY pin: 9 -SX1262 radio = new Module(10, 2, 3, 9); - -// or detect the pinout automatically using RadioBoards -// https://github.com/radiolib-org/RadioBoards -/* -#define RADIO_BOARD_AUTO -#include -Radio radio = new RadioModule(); -*/ - -void setup() { - Serial.begin(9600); - - // initialize SX1262 with default settings - Serial.print(F("[SX1262] Initializing ... ")); - int state = radio.beginLRFHSS(); - if (state == RADIOLIB_ERR_NONE) { - Serial.println(F("success!")); - } else { - Serial.print(F("failed, code ")); - Serial.println(state); - while (true) { delay(10); } - } - - // if needed, you can switch between any of the modems - // - // radio.begin() start LoRa modem (and disable LR-FHSS) - // radio.beginLRFHSS() start LR-FHSS modem (and disable LoRa) - - // the following settings can also - // be modified at run-time - state = radio.setFrequency(433.5); - state = radio.setLrFhssConfig(RADIOLIB_SX126X_LR_FHSS_BW_1523_4, // bandwidth - RADIOLIB_SX126X_LR_FHSS_CR_1_2, // coding rate - 3, // header count - 0x13A); // hopping sequence seed - state = radio.setOutputPower(10.0); - uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; - state = radio.setSyncWord(syncWord, 4); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Unable to set configuration, code ")); - Serial.println(state); - while (true) { delay(10); } - } - - #warning "This sketch is just an API guide! Read the note at line 6." -} - -void loop() { - // LR-FHSS modem can only transmit! - // transmit LR-FHSS packet - int state = radio.transmit("Hello World!"); - /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x67, - 0x89, 0xAB, 0xCD, 0xEF}; - int state = radio.transmit(byteArr, 8); - */ - if (state == RADIOLIB_ERR_NONE) { - Serial.println(F("[SX1262] Packet transmitted successfully!")); - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { - Serial.println(F("[SX1262] Packet too long!")); - } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { - Serial.println(F("[SX1262] Timed out while transmitting!")); - } else { - Serial.println(F("[SX1262] Failed to transmit packet, code ")); - Serial.println(state); - } - -} diff --git a/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino b/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino new file mode 100644 index 0000000000..4dea005bbf --- /dev/null +++ b/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino @@ -0,0 +1,113 @@ +/* + RadioLib SX126x LR-FHSS Modem Example + + This example shows how to use LR-FHSS modem in SX126x chips. + This modem can only transmit data, and is not able to receive. + + This example transmits packets using SX1262 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX126x family can also be used. + + Using blocking transmit is not recommended, as it will lead + to inefficient use of processor time! + Instead, interrupt transmit is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginLRFHSS(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // LR-FHSS modem can only transmit! + Serial.print(F("[SX1262] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[SX1262] Datarate:\t")); + Serial.print(radio.getDataRate()); + Serial.println(F(" bps")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occurred while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} From 5eb90ea17a8f83b541c4fcbdc081b573dd0b6f54 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Jan 2025 21:14:36 +0100 Subject: [PATCH 1476/1848] [SX126x] Add LR-FHSS interrupt transmit example --- .../SX126x_LR_FHSS_Transmit_Interrupt.ino | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino diff --git a/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino b/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino new file mode 100644 index 0000000000..1a22079838 --- /dev/null +++ b/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino @@ -0,0 +1,151 @@ +/* + RadioLib SX126x LR-FHSS Transmit with Interrupts Example + + This example shows how to use LR-FHSS modem in SX126x chips. + This modem can only transmit data, and is not able to receive. + + This example transmits packets using SX1262 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lr-fhss-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1262 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// flag to indicate that a packet was sent +// or a frequency hop is needed +volatile bool flag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet or need to hop, set the flag + flag = true; +} + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + int state = radio.beginLRFHSS(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[SX1262] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // LR-FHSS modem can only transmit! + + // check if the previous transmission finished + if(flag) { + // reset flag + flag = false; + + // check if this was caused by hopping or transmission finished + if(radio.getIrqFlags() & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP) { + radio.hopLRFHSS(); + + } else { + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1262] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + + } + + + + } + +} From 27653e1cf7292d643e996028c1a40931e7867143 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 30 Jan 2025 20:58:53 +0100 Subject: [PATCH 1477/1848] [LoRaWAN] Allow support for misc MAC commands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 23 ++++++++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 3 ++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index cc6ed3df73..91cdf65d66 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1718,14 +1718,14 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e cid = *mPtr; // MAC id is the first byte // fetch length of MAC downlink payload - state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true); + state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true, mPtr + 1); if(state != RADIOLIB_ERR_NONE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Unknown MAC CID %02x", cid); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); break; } - // already fetch length of MAC answer payload (if any) + // already fetch length of MAC answer payload (if any), include CID uint8_t fLenRe = 0; (void)this->getMacLen(cid, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true); // don't care about return value: the previous getMacLen() would have failed anyway @@ -2484,17 +2484,21 @@ int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::getMacLen(uint8_t cid, uint8_t* len, uint8_t dir, bool inclusive) { +int16_t LoRaWANNode::getMacLen(uint8_t cid, uint8_t* len, uint8_t dir, bool inclusive, uint8_t* payload) { + (void)payload; + + *len = 0; + if(inclusive) { + *len += 1; // add one byte for CID + } + LoRaWANMacCommand_t cmd = RADIOLIB_LORAWAN_MAC_COMMAND_NONE; int16_t state = this->getMacCommand(cid, &cmd); RADIOLIB_ASSERT(state); if(dir == RADIOLIB_LORAWAN_UPLINK) { - *len = cmd.lenUp; + *len += cmd.lenUp; } else { - *len = cmd.lenDn; - } - if(inclusive) { - *len += 1; // add one byte for CID + *len += cmd.lenDn; } return(RADIOLIB_ERR_NONE); } @@ -2596,7 +2600,8 @@ void LoRaWANNode::clearMacCommands(uint8_t* inOut, uint8_t* lenInOut, uint8_t di uint8_t numDeleted = 0; while(i < *lenInOut) { uint8_t id = inOut[i]; - uint8_t fLen = 1; // if there is an incorrect MAC command, we should at least move forward by one byte + uint8_t fLen = 0; + // include CID byte, so if command fails, we still move one byte forward (void)this->getMacLen(id, &fLen, dir, true); // only clear MAC command if it should not persist until a downlink is received diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 977db46807..1bfa782c13 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1030,7 +1030,8 @@ class LoRaWANNode { // get the length of a certain MAC command in a specific direction (up/down) // if inclusive is true, add one for the CID byte - int16_t getMacLen(uint8_t cid, uint8_t* len, uint8_t dir, bool inclusive = false); + // include payload in case the MAC command has a dynamic length + virtual int16_t getMacLen(uint8_t cid, uint8_t* len, uint8_t dir, bool inclusive = false, uint8_t* payload = NULL); // find out of a MAC command should persist destruction // in uplink direction, some commands must persist if no downlink is received From 8c304a89c10d86f04fd3b1a1f2fe86635a731e56 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 31 Jan 2025 17:59:47 +0100 Subject: [PATCH 1478/1848] [LLCC68] Add override begin FSK and LR-FHSS methods (#1405) --- src/modules/LLCC68/LLCC68.cpp | 50 +++++++++++++++++++++++++++++++++++ src/modules/LLCC68/LLCC68.h | 33 ++++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index fe1468a242..17f19794ee 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -37,6 +37,56 @@ int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync return(state); } +int16_t LLCC68::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { + // bit of a hack, but some LLCC68 chips report as "SX1261", try that + // for full discussion, see https://github.com/jgromes/RadioLib/issues/1329 + chipType = RADIOLIB_SX1261_CHIP_TYPE; + state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO); + RADIOLIB_DEBUG_PRINTLN("LLCC68 version string not found, using SX1261 instead"); + } + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t LLCC68::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO); + if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) { + // bit of a hack, but some LLCC68 chips report as "SX1261", try that + // for full discussion, see https://github.com/jgromes/RadioLib/issues/1329 + chipType = RADIOLIB_SX1261_CHIP_TYPE; + state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO); + RADIOLIB_DEBUG_PRINTLN("LLCC68 version string not found, using SX1261 instead"); + } + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t LLCC68::setBandwidth(float bw) { RADIOLIB_CHECK_RANGE(bw, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); return(SX1262::setBandwidth(bw)); diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 949e666bdc..5dadf380e1 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -40,7 +40,38 @@ class LLCC68: public SX1262 { \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false); - + + /*! + \brief Initialization method for FSK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + + /*! + \brief Initialization method for LR-FHSS modem. This modem only supports transmission! + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + // configuration methods /*! From b634c9c71190a725e62d38063969fae659c6a6ab Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 31 Jan 2025 18:09:52 +0100 Subject: [PATCH 1479/1848] [SX126x] Add missing virtual specifier (#1405) --- src/modules/SX126x/SX1262.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index d0e73a6e41..08ac1b6b23 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -75,7 +75,7 @@ class SX1262: public SX126x { \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + virtual int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods From 8ab989ab53d4d015776c8d72cc2d807ac2455810 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 31 Jan 2025 18:25:38 +0100 Subject: [PATCH 1480/1848] [CI] Add helper script to cppcheck single path --- extras/cppcheck/check_file.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 extras/cppcheck/check_file.sh diff --git a/extras/cppcheck/check_file.sh b/extras/cppcheck/check_file.sh new file mode 100755 index 0000000000..a560cd339f --- /dev/null +++ b/extras/cppcheck/check_file.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +if [[ $@ -lt 1 ]]; then + echo "Usage: $0 " + exit 1 +fi + +path=$1 + +cppcheck --version +cppcheck $path --enable=all \ + --force \ + --inline-suppr \ + --suppress=ConfigurationNotChecked \ + --suppress=unusedFunction \ + --suppress=missingIncludeSystem \ + --suppress=missingInclude \ + --quiet From 4deec953e8d5edbbf5aca0f0c5460d19c990db45 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 31 Jan 2025 18:25:57 +0100 Subject: [PATCH 1481/1848] [LLCC68] Add missing override specifiers --- src/modules/LLCC68/LLCC68.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index 5dadf380e1..e548fa573c 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -39,7 +39,7 @@ class LLCC68: public SX1262 { \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 0, bool useRegulatorLDO = false) override; /*! \brief Initialization method for FSK modem. @@ -49,13 +49,13 @@ class LLCC68: public SX1262 { \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 0 V (XTAL). If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. To use XTAL, either set this value to 0, or set SX126x::XTAL to true. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 0, bool useRegulatorLDO = false) override; /*! \brief Initialization method for LR-FHSS modem. This modem only supports transmission! @@ -64,13 +64,13 @@ class LLCC68: public SX1262 { \param cr LR-FHSS coding rate, one of RADIOLIB_SX126X_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. \param power Output power in dBm. Defaults to 10 dBm. - \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 0 V (XTAL). If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. To use XTAL, either set this value to 0, or set SX126x::XTAL to true. \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. \returns \ref status_codes */ - int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_SX126X_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_SX126X_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 0, bool useRegulatorLDO = false) override; // configuration methods From f2461edaec22689fa331019b90d5f44d8af1e92b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Feb 2025 21:05:58 +0100 Subject: [PATCH 1482/1848] [SX127x] Fix mistake in doxygen comment (#1411) --- src/modules/SX127x/SX1276.h | 2 +- src/modules/SX127x/SX1277.h | 2 +- src/modules/SX127x/SX1278.h | 4 ++-- src/modules/SX127x/SX1279.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index e3d6ea0105..006e682ed1 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -27,7 +27,7 @@ class SX1276: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 22e68ad8e2..0df03daca4 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -27,7 +27,7 @@ class SX1277: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 2c2a30c5a1..215e3b28a5 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -118,7 +118,7 @@ class SX1278: public SX127x { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. @@ -160,7 +160,7 @@ class SX1278: public SX127x { int16_t setFrequency(float freq) override; /*! - \brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode. + \brief Sets %LoRa link bandwidth. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode. \param bw %LoRa link bandwidth to be set in kHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index fb2d5f4305..7d304ecc0a 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -27,7 +27,7 @@ class SX1279: public SX1278 { /*! \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module. \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 960.0 MHz. - \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. + \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. From 33fd64928865b2f3f0e489571112d9f6c11baa05 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Feb 2025 09:33:16 +0100 Subject: [PATCH 1483/1848] Ensure output dir of spectrum scan always exists --- .gitignore | 3 --- extras/SX126x_Spectrum_Scan/out/.gitignore | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 extras/SX126x_Spectrum_Scan/out/.gitignore diff --git a/.gitignore b/.gitignore index 425eeae59e..db0e8bbf71 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,6 @@ # Jetbrain IDEs .idea -# Spectrum scan -extras/SX126x_Spectrum_Scan/out/* - # PlatformIO .pio* diff --git a/extras/SX126x_Spectrum_Scan/out/.gitignore b/extras/SX126x_Spectrum_Scan/out/.gitignore new file mode 100644 index 0000000000..9a219e8f1e --- /dev/null +++ b/extras/SX126x_Spectrum_Scan/out/.gitignore @@ -0,0 +1,2 @@ +# all output pictures +*.png From 9e832526a57e5fe946118a23fb87a905408cc2dd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Feb 2025 10:10:13 +0100 Subject: [PATCH 1484/1848] [SX127x] Fix lower power range of RFO (#1412) --- src/modules/SX127x/SX1278.cpp | 4 ++-- src/modules/SX127x/SX1278.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index e370d0e3cb..199d96967a 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -344,9 +344,9 @@ int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) { if(useRfo) { // RFO output if(clipped) { - *clipped = RADIOLIB_MAX(-3, RADIOLIB_MIN(15, power)); + *clipped = RADIOLIB_MAX(-4, RADIOLIB_MIN(15, power)); } - RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + RADIOLIB_CHECK_RANGE(power, -4, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } else { // PA_BOOST output, check high-power operation if(clipped) { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 215e3b28a5..4b24e9dc72 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -202,7 +202,7 @@ class SX1278: public SX127x { int16_t checkDataRate(DataRate_t dr) override; /*! - \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). + \brief Sets transmission output power. Allowed values range from -4 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST. \param power Transmission output power in dBm. \returns \ref status_codes @@ -210,7 +210,7 @@ class SX1278: public SX127x { int16_t setOutputPower(int8_t power) override; /*! - \brief Sets transmission output power. Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). + \brief Sets transmission output power. Allowed values range from -4 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. \param power Transmission output power in dBm. \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. From 3563e7257ac3fc9801fea21dd773cc3d8685a42b Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Wed, 5 Feb 2025 13:23:36 +0300 Subject: [PATCH 1485/1848] a fix for build with Arduino Core for Zephyr OS for Nano 33 BLE and Portenta H7 targets --- src/BuildOpt.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 89c2685389..297a91e4c7 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -264,20 +264,24 @@ #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #if defined(ARDUINO_ARCH_MBED) // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_MBED_TONE_OVERRIDE + #endif -#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) +#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_H7) // Arduino Portenta H7 #define RADIOLIB_PLATFORM "Portenta H7" #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #if defined(ARDUINO_ARCH_MBED) // Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds #define RADIOLIB_TONE_UNSUPPORTED #define RADIOLIB_MBED_TONE_OVERRIDE + #endif #elif defined(__STM32F4__) || defined(__STM32F1__) // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) From 2550fae4cb2901d05001514ded9c69deba42235e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Wed, 5 Feb 2025 20:41:43 +0100 Subject: [PATCH 1486/1848] [PHY] Staged modes (#1414) * [PHY] Add PHY support for staged modes * [SX126x] Add support for staged Rx/Tx * [PHY] Add missing virtual specifiers * [SX126x] Add missing overrides * [LoRaWAN] Use new stageMode and launchMode, reduce scanGuard * [LoRaWAN] A-synchronize transmissions (#1410) * [PHY] Pass mode config by reference * [PHY] Add default implementation of start transmit/receive * [SX126x] Implement staged modes * [SX128x] Implement staged modes * [SX127x] Implement staged modes * [LR11x0] Implement staged modes * [SX127x] Remove unused method from header * [SX126x] Make array const * Add new methods to keywords --------- Co-authored-by: StevenCellist --- keywords.txt | 2 + src/modules/LR11x0/LR11x0.cpp | 229 +++++++------- src/modules/LR11x0/LR11x0.h | 34 +- src/modules/SX126x/SX126x.cpp | 274 +++++++++-------- src/modules/SX126x/SX126x.h | 35 +-- src/modules/SX127x/SX127x.cpp | 290 ++++++++++-------- src/modules/SX127x/SX127x.h | 30 +- src/modules/SX128x/SX128x.cpp | 229 +++++++------- src/modules/SX128x/SX128x.h | 32 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 90 +++++- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 42 ++- src/protocols/PhysicalLayer/PhysicalLayer.h | 82 ++++- 13 files changed, 771 insertions(+), 600 deletions(-) diff --git a/keywords.txt b/keywords.txt index f6bc613b6d..85ed0ed9a7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -343,6 +343,8 @@ setDataRate KEYWORD2 checkDataRate KEYWORD2 setModem KEYWORD2 getModem KEYWORD2 +stageMode KEYWORD2 +launchMode KEYWORD2 # LoRaWAN getBufferNonces KEYWORD2 diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 8aba735de5..9a2085bab8 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -414,73 +414,6 @@ void LR11x0::clearPacketSentAction() { this->clearIrqAction(); } -int16_t LR11x0::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { - // suppress unused variable warning - (void)addr; - - // check packet length - if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // maximum packet length is decreased by 1 when address filtering is active - if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // set packet Length - int16_t state = RADIOLIB_ERR_NONE; - uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - state = getPacketType(&modem); - RADIOLIB_ASSERT(state); - if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { - state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcTypeLoRa, this->invertIQEnabled); - - } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); - - } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { - return(RADIOLIB_ERR_UNKNOWN); - - } - RADIOLIB_ASSERT(state); - - // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT); - RADIOLIB_ASSERT(state); - - if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { - // in LR-FHSS mode, the packet is built by the device - // TODO add configurable device offset - state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, const_cast(data), len); - RADIOLIB_ASSERT(state); - - } else { - // write packet to buffer - state = writeBuffer8(const_cast(data), len); - RADIOLIB_ASSERT(state); - - } - - // clear interrupt flags - state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); - RADIOLIB_ASSERT(state); - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_TX); - - // start transmission - state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE); - RADIOLIB_ASSERT(state); - - // wait for BUSY to go low (= PA ramp up done) - while(this->mod->hal->digitalRead(this->mod->getGpio())) { - this->mod->hal->yield(); - } - - return(state); -} - int16_t LR11x0::finishTransmit() { // clear interrupt flags clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); @@ -493,46 +426,6 @@ int16_t LR11x0::startReceive() { return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) { - (void)len; - - // check active modem - int16_t state = RADIOLIB_ERR_NONE; - uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - state = getPacketType(&modem); - RADIOLIB_ASSERT(state); - if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && - (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set DIO mapping - uint32_t irq = irqMask; - if(timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) { - irq |= (1UL << RADIOLIB_IRQ_TIMEOUT); - } - state = setDioIrqParams(getIrqMapped(irqFlags & irq)); - RADIOLIB_ASSERT(state); - - // clear interrupt flags - state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); - RADIOLIB_ASSERT(state); - - // set implicit mode and expected len if applicable - if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) { - state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled); - RADIOLIB_ASSERT(state); - } - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_RX); - - // set mode to receive - state = setRx(timeout); - - return(state); -} - uint32_t LR11x0::getIrqStatus() { // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes uint8_t buff[6] = { 0 }; @@ -2052,6 +1945,124 @@ int16_t LR11x0::getModem(ModemType_t* modem) { return(RADIOLIB_ERR_WRONG_MODEM); } +int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { + int16_t state; + + switch(mode) { + case(RADIOLIB_RADIO_MODE_RX): { + // check active modem + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && + (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set DIO mapping + if(cfg->receive.timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) { + cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); + } + state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask)); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // set implicit mode and expected len if applicable + if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + } + this->rxTimeout = cfg->receive.timeout; + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + // check packet length + if(cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // maximum packet length is decreased by 1 when address filtering is active + if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set packet Length + state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled); + + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); + + } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + return(RADIOLIB_ERR_UNKNOWN); + + } + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT); + RADIOLIB_ASSERT(state); + + if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + // in LR-FHSS mode, the packet is built by the device + // TODO add configurable device offset + state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len); + RADIOLIB_ASSERT(state); + + } else { + // write packet to buffer + state = writeBuffer8(cfg->transmit.data, cfg->transmit.len); + RADIOLIB_ASSERT(state); + + } + + // clear interrupt flags + state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = mode; + return(state); +} + +int16_t LR11x0::launchMode() { + int16_t state; + switch(this->stagedMode) { + case(RADIOLIB_RADIO_MODE_RX): { + this->mod->setRfSwitchState(Module::MODE_RX); + state = setRx(this->rxTimeout); + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + this->mod->setRfSwitchState(Module::MODE_TX); + state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = RADIOLIB_RADIO_MODE_NONE; + return(state); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); @@ -2334,12 +2345,12 @@ int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { return(state); } -int16_t LR11x0::writeBuffer8(uint8_t* data, size_t len) { +int16_t LR11x0::writeBuffer8(const uint8_t* data, size_t len) { // check maximum size if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, data, len)); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, const_cast(data), len)); } int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 03455d3502..6e95bde30d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -877,6 +877,7 @@ class LR11x0: public PhysicalLayer { using PhysicalLayer::transmit; using PhysicalLayer::receive; using PhysicalLayer::startTransmit; + using PhysicalLayer::startReceive; using PhysicalLayer::readData; /*! @@ -1073,16 +1074,6 @@ class LR11x0: public PhysicalLayer { */ void clearPacketSentAction() override; - /*! - \brief Interrupt-driven binary transmit method. - Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes - */ - int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; - /*! \brief Clean up after transmission is done. \returns \ref status_codes @@ -1097,20 +1088,6 @@ class LR11x0: public PhysicalLayer { */ int16_t startReceive() override; - /*! - \brief Interrupt-driven receive method. IRQ1 will be activated when full packet is received. - \param timeout Raw timeout value, expressed as multiples of 1/32.768 kHz (approximately 30.52 us). - Defaults to RADIOLIB_LR11X0_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), - set to RADIOLIB_LR11X0_RX_TIMEOUT_NONE for no timeout (Rx single mode). - If timeout other than infinite is set, signal will be generated on IRQ1. - - \param irqFlags Sets the IRQ flags that will trigger IRQ1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE. - \param irqMask Only for PhysicalLayer compatibility, not used. - \param len Only for PhysicalLayer compatibility, not used. - \returns \ref status_codes - */ - int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, uint32_t irqMask = 0, size_t len = 0); - /*! \brief Reads the current IRQ status. \returns IRQ status bits @@ -1622,6 +1599,12 @@ class LR11x0: public PhysicalLayer { */ int16_t calibrateImageRejection(float freqMin, float freqMax); + /*! \copydoc PhysicalLayer::stageMode */ + int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; + + /*! \copydoc PhysicalLayer::launchMode */ + int16_t launchMode() override; + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -1630,7 +1613,7 @@ class LR11x0: public PhysicalLayer { // LR11x0 SPI command implementations int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); - int16_t writeBuffer8(uint8_t* data, size_t len); + int16_t writeBuffer8(const uint8_t* data, size_t len); int16_t readBuffer8(uint8_t* data, size_t len, size_t offset); int16_t clearRxBuffer(void); int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data); @@ -1829,6 +1812,7 @@ class LR11x0: public PhysicalLayer { uint8_t wifiScanMode = 0; bool gnss = false; + uint32_t rxTimeout = 0; int16_t modSetup(float tcxoVoltage, uint8_t modem); static int16_t SPIparseStatus(uint8_t in); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 777dce09cb..26f169c771 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -518,115 +518,6 @@ void SX126x::clearChannelScanAction() { this->clearDio1Action(); } -int16_t SX126x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { - (void)addr; - - // check packet length - if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // maximum packet length is decreased by 1 when address filtering is active - if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // set packet Length - int16_t state = RADIOLIB_ERR_NONE; - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, this->headerType, this->invertIQEnabled); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, len); - - } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - return(RADIOLIB_ERR_UNKNOWN); - - } - RADIOLIB_ASSERT(state); - - // set DIO mapping - if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE); - } else { - state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP); - } - RADIOLIB_ASSERT(state); - - // set buffer pointers - state = setBufferBaseAddress(); - RADIOLIB_ASSERT(state); - - // write packet to buffer - if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - state = writeBuffer(const_cast(data), len); - - } else { - // first, reset the LR-FHSS state machine - state = resetLRFHSS(); - RADIOLIB_ASSERT(state); - - // skip hopping for the first 4 - lrFhssHdrCount blocks - for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) { - stepLRFHSS(); - } - - // in LR-FHSS mode, we need to build the entire packet manually - uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 }; - size_t frameLen = 0; - this->lrFhssFrameBitsRem = 0; - this->lrFhssFrameHopsRem = 0; - this->lrFhssHopNum = 0; - state = buildLRFHSSPacket(const_cast(data), len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem); - RADIOLIB_ASSERT(state); - - // FIXME check max len for FHSS - state = writeBuffer(frame, frameLen); - RADIOLIB_ASSERT(state); - - // activate hopping - uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem }; - state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3); - RADIOLIB_ASSERT(state); - - // write the initial hopping table - uint8_t initHops = this->lrFhssFrameHopsRem; - if(initHops > 16) { - initHops = 16; - }; - for(size_t i = 0; i < initHops; i++) { - // set the hop frequency and symbols - state = this->setLRFHSSHop(i); - RADIOLIB_ASSERT(state); - } - - } - RADIOLIB_ASSERT(state); - - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // fix sensitivity - state = fixSensitivity(); - RADIOLIB_ASSERT(state); - - // set RF switch (if present) - this->mod->setRfSwitchState(this->txMode); - - // start transmission - state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); - RADIOLIB_ASSERT(state); - - // wait for BUSY to go low (= PA ramp up done) - while(this->mod->hal->digitalRead(this->mod->getGpio())) { - this->mod->hal->yield(); - } - - return(state); -} - int16_t SX126x::finishTransmit() { // clear interrupt flags int16_t state = clearIrqStatus(); @@ -640,25 +531,6 @@ int16_t SX126x::startReceive() { return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t SX126x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { - // in implicit header mode, use the provided length if it is nonzero - // otherwise we trust the user has previously set the payload length manually - if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (len != 0)) { - this->implicitLen = len; - } - - int16_t state = startReceiveCommon(timeout, irqFlags, irqMask); - RADIOLIB_ASSERT(state); - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_RX); - - // set mode to receive - state = setRx(timeout); - - return(state); -} - int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) { // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay uint32_t transitionTime = this->tcxoDelay + 1000; @@ -1666,6 +1538,152 @@ int16_t SX126x::getModem(ModemType_t* modem) { return(RADIOLIB_ERR_WRONG_MODEM); } +int16_t SX126x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { + int16_t state; + + switch(mode) { + case(RADIOLIB_RADIO_MODE_RX): { + // in implicit header mode, use the provided length if it is nonzero + // otherwise we trust the user has previously set the payload length manually + if((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) { + this->implicitLen = cfg->receive.len; + } + + state = startReceiveCommon(cfg->receive.timeout, cfg->receive.irqFlags, cfg->receive.irqMask); + RADIOLIB_ASSERT(state); + + this->rxTimeout = cfg->receive.timeout; + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + // check packet length + if(cfg->transmit.len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // maximum packet length is decreased by 1 when address filtering is active + if((RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && + (cfg->transmit.len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set packet Length + state = RADIOLIB_ERR_NONE; + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, cfg->transmit.len, this->headerType, this->invertIQEnabled); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, cfg->transmit.len); + + } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + return(RADIOLIB_ERR_UNKNOWN); + + } + RADIOLIB_ASSERT(state); + + // set DIO mapping + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE); + } else { + state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP, RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_LR_FHSS_HOP); + } + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // write packet to buffer + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + state = writeBuffer(cfg->transmit.data, cfg->transmit.len); + + } else { + // first, reset the LR-FHSS state machine + state = resetLRFHSS(); + RADIOLIB_ASSERT(state); + + // skip hopping for the first 4 - lrFhssHdrCount blocks + for(int i = 0; i < 4 - this->lrFhssHdrCount; ++i ) { + stepLRFHSS(); + } + + // in LR-FHSS mode, we need to build the entire packet manually + uint8_t frame[RADIOLIB_SX126X_MAX_PACKET_LENGTH] = { 0 }; + size_t frameLen = 0; + this->lrFhssFrameBitsRem = 0; + this->lrFhssFrameHopsRem = 0; + this->lrFhssHopNum = 0; + state = buildLRFHSSPacket(cfg->transmit.data, cfg->transmit.len, frame, &frameLen, &this->lrFhssFrameBitsRem, &this->lrFhssFrameHopsRem); + RADIOLIB_ASSERT(state); + + // FIXME check max len for FHSS + state = writeBuffer(frame, frameLen); + RADIOLIB_ASSERT(state); + + // activate hopping + const uint8_t hopCfg[] = { RADIOLIB_SX126X_HOPPING_ENABLED, (uint8_t)frameLen, (uint8_t)this->lrFhssFrameHopsRem }; + state = writeRegister(RADIOLIB_SX126X_REG_HOPPING_ENABLE, hopCfg, 3); + RADIOLIB_ASSERT(state); + + // write the initial hopping table + uint8_t initHops = this->lrFhssFrameHopsRem; + if(initHops > 16) { + initHops = 16; + }; + for(size_t i = 0; i < initHops; i++) { + // set the hop frequency and symbols + state = this->setLRFHSSHop(i); + RADIOLIB_ASSERT(state); + } + + } + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // fix sensitivity + state = fixSensitivity(); + RADIOLIB_ASSERT(state); + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = mode; + return(state); +} + +int16_t SX126x::launchMode() { + int16_t state; + switch(this->stagedMode) { + case(RADIOLIB_RADIO_MODE_RX): { + this->mod->setRfSwitchState(Module::MODE_RX); + state = setRx(this->rxTimeout); + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + this->mod->setRfSwitchState(this->txMode); + state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = RADIOLIB_RADIO_MODE_NONE; + return(state); +} + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX126x::setDirectAction(void (*func)(void)) { setDio1Action(func); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 371926cae2..6198029fab 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -478,6 +478,7 @@ class SX126x: public PhysicalLayer { using PhysicalLayer::transmit; using PhysicalLayer::receive; using PhysicalLayer::startTransmit; + using PhysicalLayer::startReceive; using PhysicalLayer::readData; /*! @@ -681,16 +682,6 @@ class SX126x: public PhysicalLayer { */ void clearChannelScanAction() override; - /*! - \brief Interrupt-driven binary transmit method. - Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. - \returns \ref status_codes - */ - int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; - /*! \brief Clean up after transmission is done. \returns \ref status_codes @@ -705,23 +696,6 @@ class SX126x: public PhysicalLayer { */ int16_t startReceive() override; - /*! - \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - \param timeout Receive mode type and/or raw timeout value, expressed as multiples of 15.625 us. - When set to RADIOLIB_SX126X_RX_TIMEOUT_INF, the timeout will be infinite and the device will remain - in Rx mode until explicitly commanded to stop (Rx continuous mode). - When set to RADIOLIB_SX126X_RX_TIMEOUT_NONE, there will be no timeout and the device will return - to standby when a packet is received (Rx single mode). - For any other value, timeout will be applied and signal will be generated on DIO1 for conditions - defined by irqFlags and irqMask. - - \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. - \param len Only for PhysicalLayer compatibility, not used. - \returns \ref status_codes - */ - int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0); - /*! \brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen. Note that this function assumes the unit will take 500us + TCXO_delay to change state. @@ -1145,6 +1119,12 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ int16_t getModem(ModemType_t* modem) override; + + /*! \copydoc PhysicalLayer::stageMode */ + int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; + + /*! \copydoc PhysicalLayer::launchMode */ + int16_t launchMode() override; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! @@ -1304,6 +1284,7 @@ class SX126x: public PhysicalLayer { size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + uint32_t rxTimeout = 0; // LR-FHSS stuff - there's a lot of it because all the encoding happens in software uint8_t lrFhssCr = RADIOLIB_SX126X_LR_FHSS_CR_2_3; diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7510833ed4..c8a422785e 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -389,67 +389,6 @@ int16_t SX127x::startReceive() { return(this->startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t SX127x::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { - uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS; - - // set mode to standby - int16_t state = setMode(RADIOLIB_SX127X_STANDBY); - RADIOLIB_ASSERT(state); - - // set DIO pin mapping - state = this->setIrqFlags(getIrqMapped(irqFlags & irqMask)); - RADIOLIB_ASSERT(state); - - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - if(timeout != 0) { - // for non-zero timeout value, change mode to Rx single and set the timeout - mode = RADIOLIB_SX127X_RXSINGLE; - uint8_t msb_sym = (timeout > 0x3FF) ? 0x3 : (uint8_t)(timeout >> 8); - uint8_t lsb_sym = (timeout > 0x3FF) ? 0xFF : (uint8_t)(timeout & 0xFF); - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym); - RADIOLIB_ASSERT(state); - } - - // in FHSS mode, enable channel change interrupt - if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4); - } - - // in implicit header mode, use the provided length if it is nonzero - // otherwise we trust the user has previously set the payload length manually - if((this->implicitHdr) && (len != 0)) { - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); - this->packetLength = len; - } - - // apply fixes to errata - RADIOLIB_ERRATA_SX127X(true); - - // clear interrupt flags - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - - // set FIFO pointers - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); - RADIOLIB_ASSERT(state); - - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // clear interrupt flags - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - - // FSK modem does not distinguish between Rx single and continuous - mode = RADIOLIB_SX127X_RX; - } - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_RX); - - // set mode to receive - return(setMode(mode)); -} - void SX127x::setDio0Action(void (*func)(void), uint32_t dir) { this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir); } @@ -568,80 +507,6 @@ bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) return(false); } -int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { - // set mode to standby - int16_t state = setMode(RADIOLIB_SX127X_STANDBY); - - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - // check packet length - if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // set DIO mapping - if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { - this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); - } else { - this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6); - } - - // apply fixes to errata - RADIOLIB_ERRATA_SX127X(false); - - // clear interrupt flags - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - - // set packet length - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); - - // set FIFO pointers - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); - - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // clear interrupt flags - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - - // set DIO mapping - if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { - this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4); - } else { - this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); - } - - // set packet length - increased by 1 when address filter is enabled - uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); - if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { - if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len + 1); - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, addr); - } else { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, len); - } - - } - - } - - // write packet to FIFO - size_t packetLen = len; - if((modem == RADIOLIB_SX127X_FSK_OOK) && (len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { - packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1; - this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); - } - this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, const_cast(data), packetLen); - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_TX); - - // start transmission - state |= setMode(RADIOLIB_SX127X_TX); - RADIOLIB_ASSERT(state); - - return(RADIOLIB_ERR_NONE); -} - int16_t SX127x::finishTransmit() { // wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags // not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO, @@ -1776,6 +1641,161 @@ int16_t SX127x::getModem(ModemType_t* modem) { return(RADIOLIB_ERR_WRONG_MODEM); } +int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { + int16_t state; + + switch(mode) { + case(RADIOLIB_RADIO_MODE_RX): { + this->rxMode = RADIOLIB_SX127X_RXCONTINUOUS; + + // set mode to standby + state = setMode(RADIOLIB_SX127X_STANDBY); + RADIOLIB_ASSERT(state); + + // set DIO pin mapping + state = this->setIrqFlags(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask)); + RADIOLIB_ASSERT(state); + + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + if(cfg->receive.timeout != 0) { + // for non-zero timeout value, change mode to Rx single and set the timeout + this->rxMode = RADIOLIB_SX127X_RXSINGLE; + uint8_t msb_sym = (cfg->receive.timeout > 0x3FF) ? 0x3 : (uint8_t)(cfg->receive.timeout >> 8); + uint8_t lsb_sym = (cfg->receive.timeout > 0x3FF) ? 0xFF : (uint8_t)(cfg->receive.timeout & 0xFF); + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym); + RADIOLIB_ASSERT(state); + } + + // in FHSS mode, enable channel change interrupt + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4); + } + + // in implicit header mode, use the provided length if it is nonzero + // otherwise we trust the user has previously set the payload length manually + if((this->implicitHdr) && (cfg->receive.len != 0)) { + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->receive.len); + this->packetLength = cfg->receive.len; + } + + // apply fixes to errata + RADIOLIB_ERRATA_SX127X(true); + + // clear interrupt flags + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); + + // set FIFO pointers + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); + RADIOLIB_ASSERT(state); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // clear interrupt flags + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); + + // FSK modem does not distinguish between Rx single and continuous + this->rxMode = RADIOLIB_SX127X_RX; + } + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + // set mode to standby + state = setMode(RADIOLIB_SX127X_STANDBY); + + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + // check packet length + if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set DIO mapping + if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4); + } else { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6); + } + + // apply fixes to errata + RADIOLIB_ERRATA_SX127X(false); + + // clear interrupt flags + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); + + // set packet length + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->transmit.len); + + // set FIFO pointers + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // clear interrupt flags + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); + + // set DIO mapping + if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4); + } else { + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + } + + // set packet length - increased by 1 when address filter is enabled + uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1); + if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) { + if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len + 1); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.addr); + } else { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len); + } + + } + + } + + // write packet to FIFO + size_t packetLen = cfg->transmit.len; + if((modem == RADIOLIB_SX127X_FSK_OOK) && (cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) { + packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1; + this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); + } + this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.data, packetLen); + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = mode; + return(state); +} + +int16_t SX127x::launchMode() { + int16_t state; + switch(this->stagedMode) { + case(RADIOLIB_RADIO_MODE_RX): { + this->mod->setRfSwitchState(Module::MODE_RX); + state = setMode(this->rxMode); + RADIOLIB_ASSERT(state); + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + this->mod->setRfSwitchState(Module::MODE_TX); + state = setMode(RADIOLIB_SX127X_TX); + RADIOLIB_ASSERT(state); + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = RADIOLIB_RADIO_MODE_NONE; + return(state); +} + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX127x::setDirectAction(void (*func)(void)) { setDio1Action(func, this->mod->hal->GpioInterruptRising); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 1edfdcd481..59d5cb2cf3 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -586,6 +586,7 @@ class SX127x: public PhysicalLayer { using PhysicalLayer::transmit; using PhysicalLayer::receive; using PhysicalLayer::startTransmit; + using PhysicalLayer::startReceive; using PhysicalLayer::readData; // constructor @@ -798,15 +799,6 @@ class SX127x: public PhysicalLayer { */ bool fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen); - /*! - \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. - \param data Binary data that will be transmitted. - \param len Length of binary data to transmit (in bytes). - \param addr Node address to transmit the packet to. Only used in FSK mode. - \returns \ref status_codes - */ - int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; - /*! \brief Clean up after transmission is done. \returns \ref status_codes @@ -820,19 +812,6 @@ class SX127x: public PhysicalLayer { */ int16_t startReceive() override; - /*! - \brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer. - \param timeout Receive mode type and/or raw timeout value in symbols. - When set to 0, the timeout will be infinite and the device will remain - in Rx mode until explicitly commanded to stop (Rx continuous mode). - When non-zero (maximum 1023), the device will be set to Rx single mode and timeout will be set. - \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. - \param len Expected length of packet to be received. Required for LoRa spreading factor 6. - \returns \ref status_codes - */ - int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0) override; - /*! \brief Reads data that was received after calling startReceive method. When the packet length is not known in advance, getPacketLength method must be called BEFORE calling readData! @@ -1163,6 +1142,12 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ int16_t getModem(ModemType_t* modem) override; + + /*! \copydoc PhysicalLayer::stageMode */ + int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; + + /*! \copydoc PhysicalLayer::launchMode */ + int16_t launchMode() override; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! @@ -1268,6 +1253,7 @@ class SX127x: public PhysicalLayer { float dataRate = 0; bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; + uint8_t rxMode = RADIOLIB_SX127X_RXCONTINUOUS; int16_t config(); int16_t directMode(); diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 85fa91f667..fe58c7c0cc 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -513,70 +513,6 @@ void SX128x::clearPacketSentAction() { this->clearDio1Action(); } -int16_t SX128x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { - // suppress unused variable warning - (void)addr; - - // check packet length - if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - - // set packet Length - int16_t state = RADIOLIB_ERR_NONE; - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { - state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, len, this->crcLoRa, this->invertIQEnabled); - } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { - state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, len); - } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { - state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); - } else { - return(RADIOLIB_ERR_WRONG_MODEM); - } - RADIOLIB_ASSERT(state); - - // update output power - state = setTxParams(this->power); - RADIOLIB_ASSERT(state); - - // set buffer pointers - state = setBufferBaseAddress(); - RADIOLIB_ASSERT(state); - - // write packet to buffer - if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { - // first 2 bytes of BLE payload are PDU header - state = writeBuffer(const_cast(data), len, 2); - RADIOLIB_ASSERT(state); - } else { - state = writeBuffer(const_cast(data), len); - RADIOLIB_ASSERT(state); - } - - // set DIO mapping - state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE); - RADIOLIB_ASSERT(state); - - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_TX); - - // start transmission - state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); - RADIOLIB_ASSERT(state); - - // wait for BUSY to go low (= PA ramp up done) - while(this->mod->hal->digitalRead(this->mod->getGpio())) { - this->mod->hal->yield(); - } - - return(state); -} - int16_t SX128x::finishTransmit() { // clear interrupt flags clearIrqStatus(); @@ -589,49 +525,6 @@ int16_t SX128x::startReceive() { return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -int16_t SX128x::startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { - // in implicit header mode, use the provided length if it is nonzero - // otherwise we trust the user has previously set the payload length manually - if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (len != 0)) { - this->payloadLen = len; - } - - // check active modem - if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set DIO mapping - if(timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) { - irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); - } - - int16_t state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqMask)); - RADIOLIB_ASSERT(state); - - // set buffer pointers - state = setBufferBaseAddress(); - RADIOLIB_ASSERT(state); - - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // set implicit mode and expected len if applicable - if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { - state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); - RADIOLIB_ASSERT(state); - } - - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_RX); - - // set mode to receive - state = setRx(timeout); - - return(state); -} - int16_t SX128x::readData(uint8_t* data, size_t len) { // check active modem if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { @@ -1493,6 +1386,128 @@ int16_t SX128x::invertIQ(bool enable) { return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled)); } +int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { + int16_t state; + + switch(mode) { + case(RADIOLIB_RADIO_MODE_RX): { + // in implicit header mode, use the provided length if it is nonzero + // otherwise we trust the user has previously set the payload length manually + if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) { + this->payloadLen = cfg->receive.len; + } + + // check active modem + if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set DIO mapping + if(cfg->receive.timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) { + cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); + } + + state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags), getIrqMapped(cfg->receive.irqMask)); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set implicit mode and expected len if applicable + if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + } + this->rxTimeout = cfg->receive.timeout; + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + // check packet length + if(cfg->transmit.len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set packet Length + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled); + } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, cfg->transmit.len); + } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { + state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); + } + RADIOLIB_ASSERT(state); + + // update output power + state = setTxParams(this->power); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // write packet to buffer + if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { + // first 2 bytes of BLE payload are PDU header + state = writeBuffer(cfg->transmit.data, cfg->transmit.len, 2); + RADIOLIB_ASSERT(state); + } else { + state = writeBuffer(cfg->transmit.data, cfg->transmit.len); + RADIOLIB_ASSERT(state); + } + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = mode; + return(state); +} + +int16_t SX128x::launchMode() { + int16_t state; + switch(this->stagedMode) { + case(RADIOLIB_RADIO_MODE_RX): { + this->mod->setRfSwitchState(Module::MODE_RX); + state = setRx(this->rxTimeout); + RADIOLIB_ASSERT(state); + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + this->mod->setRfSwitchState(Module::MODE_TX); + state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = RADIOLIB_RADIO_MODE_NONE; + return(state); +} + #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void SX128x::setDirectAction(void (*func)(void)) { // SX128x is unable to perform direct mode reception diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index cd143e9616..0211ed26eb 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -354,6 +354,7 @@ class SX128x: public PhysicalLayer { using PhysicalLayer::transmit; using PhysicalLayer::receive; using PhysicalLayer::startTransmit; + using PhysicalLayer::startReceive; using PhysicalLayer::readData; /*! @@ -530,16 +531,6 @@ class SX128x: public PhysicalLayer { */ void clearPacketSentAction() override; - /*! - \brief Interrupt-driven binary transmit method. - Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. - \param addr Address to send the data to. Unsupported, compatibility only. - \returns \ref status_codes - */ - int16_t startTransmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; - /*! \brief Clean up after transmission is done. \returns \ref status_codes @@ -554,20 +545,6 @@ class SX128x: public PhysicalLayer { */ int16_t startReceive() override; - /*! - \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. - \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to - RADIOLIB_SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), - set to RADIOLIB_SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). - If timeout other than infinite is set, signal will be generated on DIO1. - - \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. - \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. - \param len Only for PhysicalLayer compatibility, not used. - \returns \ref status_codes - */ - int16_t startReceive(uint16_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0); - /*! \brief Reads the current IRQ status. \returns IRQ status bits @@ -863,6 +840,12 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ int16_t invertIQ(bool enable) override; + + /*! \copydoc PhysicalLayer::stageMode */ + int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; + + /*! \copydoc PhysicalLayer::launchMode */ + int16_t launchMode() override; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE /*! @@ -920,6 +903,7 @@ class SX128x: public PhysicalLayer { // common parameters uint8_t power = 0; + uint32_t rxTimeout = 0; // cached LoRa parameters uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD; diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 91cdf65d66..333623a114 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -906,14 +906,22 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RADIOLIB_ASSERT(state); // calculate JoinRequest time-on-air in milliseconds + RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; + if(this->dwellTimeUp) { - RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; if(toa > this->dwellTimeUp) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp); return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } } + RadioModeConfig_t modeCfg; + modeCfg.transmit.data = joinRequestMsg; + modeCfg.transmit.len = RADIOLIB_LORAWAN_JOIN_REQUEST_LEN; + modeCfg.transmit.addr = 0; + state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_TX, &modeCfg); + RADIOLIB_ASSERT(state); + // if requested, delay until transmitting JoinRequest RadioLibTime_t tNow = mod->hal->millis(); if(this->tUplink > tNow) { @@ -923,8 +931,26 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } } - // send it - state = this->phyLayer->transmit(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); + // start transmission + state = this->phyLayer->launchMode(); + RADIOLIB_ASSERT(state); + + // sleep for the duration of the transmission + mod->hal->delay(toa); + RadioLibTime_t txEnd = mod->hal->millis(); + + // wait for an additional transmission duration as Tx timeout period + while(!mod->hal->digitalRead(mod->getIrq())) { + // yield for multi-threaded platforms + mod->hal->yield(); + + if(mod->hal->millis() > txEnd + toa) { + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + state = this->phyLayer->finishTransmit(); + + // set the timestamp so that we can measure when to start receiving this->rxDelayStart = mod->hal->millis(); RADIOLIB_ASSERT(state); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest sent (DevNonce = %d) <-- Rx Delay start", this->devNonce); @@ -935,7 +961,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); // set the Time on Air of the JoinRequest - this->lastToA = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; + this->lastToA = toa; // configure Rx1 and Rx2 delay for JoinAccept message - these are re-configured once a valid JoinAccept is received this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; @@ -1270,7 +1296,6 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u Module* mod = this->phyLayer->getMod(); // check if the Rx windows were closed after sending the previous uplink - // this FORCES a user to call downlink() after an uplink() if(this->rxDelayEnd < this->rxDelayStart) { // not enough time elapsed since the last uplink, we may still be in an Rx window return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); @@ -1295,6 +1320,22 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u RADIOLIB_LORAWAN_UPLINK, this->txPowerMax - 2*this->txPowerSteps); RADIOLIB_ASSERT(state); + + // check whether dwell time limitation is exceeded + RadioLibTime_t toa = this->phyLayer->getTimeOnAir(len) / 1000; + if(this->dwellTimeUp) { + if(toa > this->dwellTimeUp) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp); + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); + } + } + + RadioModeConfig_t modeCfg; + modeCfg.transmit.data = in; + modeCfg.transmit.len = len; + modeCfg.transmit.addr = 0; + state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_TX, &modeCfg); + RADIOLIB_ASSERT(state); // if requested, wait until transmitting uplink tNow = mod->hal->millis(); @@ -1305,14 +1346,31 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u } } - state = this->phyLayer->transmit(in, len); + // start transmission + state = this->phyLayer->launchMode(); + RADIOLIB_ASSERT(state); + + // sleep for the duration of the transmission + mod->hal->delay(toa); + RadioLibTime_t txEnd = mod->hal->millis(); + + // wait for an additional transmission duration as Tx timeout period + while(!mod->hal->digitalRead(mod->getIrq())) { + // yield for multi-threaded platforms + mod->hal->yield(); + + if(mod->hal->millis() > txEnd + toa) { + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + state = this->phyLayer->finishTransmit(); // set the timestamp so that we can measure when to start receiving this->rxDelayStart = mod->hal->millis(); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); // increase Time on Air of the uplink sequence - this->lastToA += this->phyLayer->getTimeOnAir(len) / 1000; + this->lastToA += toa; return(state); } @@ -1364,8 +1422,17 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne RADIOLIB_ASSERT(state); // calculate the Rx timeout - RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*this->scanGuard*1000; + RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + this->scanGuard*1000; RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); + + // TODO remove default arguments + RadioModeConfig_t modeCfg; + modeCfg.receive.timeout = timeoutMod; + modeCfg.receive.irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS; + modeCfg.receive.irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; + modeCfg.receive.len = 0; + state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); + RADIOLIB_ASSERT(state); // wait for the start of the Rx window RadioLibTime_t waitLen = tReference + dlDelays[window] - mod->hal->millis(); @@ -1380,14 +1447,13 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne mod->hal->delay(waitLen); // open Rx window by starting receive with specified timeout - // TODO remove default arguments - state = this->phyLayer->startReceive(timeoutMod, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0); + state = this->phyLayer->launchMode(); tOpen = mod->hal->millis(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + scanGuard / 2)); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); // wait for the timeout to complete (and a small additional delay) - mod->hal->delay(timeoutHost / 1000 + this->scanGuard / 2); + mod->hal->delay(timeoutHost / 1000 + 2); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); // if the IRQ bit for Rx Timeout is not set, something is received, so stop the windows diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 1bfa782c13..48272336e7 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -850,7 +850,7 @@ class LoRaWANNode { 500 is the **maximum** value, but it is not a good idea to go anywhere near that. If you have to go above 50 you probably have a bug somewhere. Check your device timing. */ - RadioLibTime_t scanGuard = 10; + RadioLibTime_t scanGuard = 5; #if !RADIOLIB_GODMODE protected: diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 3bf447eee7..3b7d870a13 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -132,11 +132,18 @@ int16_t PhysicalLayer::startReceive() { } int16_t PhysicalLayer::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) { - (void)timeout; - (void)irqFlags; - (void)irqMask; - (void)len; - return(RADIOLIB_ERR_UNSUPPORTED); + RadioModeConfig_t cfg = { + .receive = { + .timeout = timeout, + .irqFlags = irqFlags, + .irqMask = irqMask, + .len = len, + } + }; + + int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg); + RADIOLIB_ASSERT(state); + return(this->launchMode()); } #if defined(RADIOLIB_BUILD_ARDUINO) @@ -150,10 +157,17 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { } int16_t PhysicalLayer::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { - (void)data; - (void)len; - (void)addr; - return(RADIOLIB_ERR_UNSUPPORTED); + RadioModeConfig_t cfg = { + .transmit = { + .data = data, + .len = len, + .addr = addr, + } + }; + + int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_TX, &cfg); + RADIOLIB_ASSERT(state); + return(this->launchMode()); } int16_t PhysicalLayer::finishTransmit() { @@ -537,6 +551,16 @@ int16_t PhysicalLayer::getModem(ModemType_t* modem) { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { + (void)mode; + (void)cfg; + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t PhysicalLayer::launchMode() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + #if RADIOLIB_INTERRUPT_TIMING void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) { Module* mod = getMod(); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index a8f66ce1ab..3d785b6d22 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -130,6 +130,58 @@ union ChannelScanConfig_t { RSSIScanConfig_t rssi; }; +struct StandbyConfig_t { + /*! \brief Module-specific standby mode configuration. */ + uint8_t mode; +}; + +struct ReceiveConfig_t { + /*! \brief Raw timeout value. Some modules use this argument to specify operation mode (single vs. continuous receive). */ + uint32_t timeout; + + /*! \brief Sets the IRQ flags. */ + RadioLibIrqFlags_t irqFlags; + + /*! \brief Sets the mask of IRQ flags that will trigger the radio interrupt pin. */ + RadioLibIrqFlags_t irqMask; + + /*! \brief Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). */ + size_t len; +}; + +struct TransmitConfig_t { + /*! \brief Binary data that will be transmitted. */ + const uint8_t* data; + + /*! \brief Length of binary data to transmit (in bytes). */ + size_t len; + + /*! \brief Node address to transmit the packet to. Only used in FSK mode. */ + uint8_t addr; +}; + +struct SleepConfig_t { + /*! \brief Module-specific sleep mode configuration. */ + uint8_t mode; +}; + +union RadioModeConfig_t { + /*! \brief Interpretation for standby mode */ + StandbyConfig_t standby; + + /*! \brief Interpretation for Rx mode */ + ReceiveConfig_t receive; + + /*! \brief Interpretation for Tx mode */ + TransmitConfig_t transmit; + + /*! \brief Interpretation for scanning */ + ChannelScanConfig_t scan; + + /*! \brief Interpretation for sleep mode */ + SleepConfig_t sleep; +}; + /*! \enum ModemType_t \brief Type of modem, used by setModem. @@ -140,6 +192,19 @@ enum ModemType_t { RADIOLIB_MODEM_LRFHSS, }; +/*! + \enum RadioModeType_t + \brief Basic radio operating modes, used by stageMode. +*/ +enum RadioModeType_t { + RADIOLIB_RADIO_MODE_NONE = 0, + RADIOLIB_RADIO_MODE_STANDBY, + RADIOLIB_RADIO_MODE_RX, + RADIOLIB_RADIO_MODE_TX, + RADIOLIB_RADIO_MODE_SCAN, + RADIOLIB_RADIO_MODE_SLEEP, +}; + /*! \class PhysicalLayer @@ -241,7 +306,7 @@ class PhysicalLayer { \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). \returns \ref status_codes */ - virtual int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len); + virtual int16_t startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, size_t len = 0); /*! \brief Binary receive method. Must be implemented in module class. @@ -669,6 +734,20 @@ class PhysicalLayer { */ virtual int16_t getModem(ModemType_t* modem); + /*! + \brief Stage mode of the radio to be launched later using launchMode. + \param mode Radio mode to prepare. + \param cfg Configuration of this mode (mode-dependent). + \returns \ref status_codes + */ + virtual int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg); + + /*! + \brief Launch previously staged mode. + \returns \ref status_codes + */ + virtual int16_t launchMode(); + #if RADIOLIB_INTERRUPT_TIMING /*! @@ -690,6 +769,7 @@ class PhysicalLayer { protected: #endif uint32_t irqMap[10] = { 0 }; + RadioModeType_t stagedMode = RADIOLIB_RADIO_MODE_NONE; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE void updateDirectBuffer(uint8_t bit); From 8c2c7b6cb5984c29dada8c4aca6ed14d90c07f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Thu, 6 Feb 2025 07:00:03 +0100 Subject: [PATCH 1487/1848] [LoRaWAN] Add methods to allow user-provided sleep function (#1410) * [LoRaWAN] Add methods to allow user-provided sleep function * Add example sleep function * [LoRaWAN] Switch all delay calls to sleepDelay * [LoRaWAN] Remove unused variable --------- Co-authored-by: StevenCellist --- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 3 ++ examples/LoRaWAN/LoRaWAN_Reference/config.h | 15 +++++++++ keywords.txt | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 33 ++++++++++++++----- src/protocols/LoRaWAN/LoRaWAN.h | 20 +++++++++++ 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 87d7f1ebce..884df67570 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -48,6 +48,9 @@ void setup() { // Override the default join rate uint8_t joinDR = 4; + // Optionally provide a custom sleep function - see config.h + //node.setSleepFunction(customDelay); + // Setup the OTAA session information node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index 21c79f8ee3..565e32d18e 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -142,4 +142,19 @@ void arrayDump(uint8_t *buffer, uint16_t len) { Serial.println(); } +// Custom delay function: +// Communication over LoRaWAN includes a lot of delays. +// By default, RadioLib will use the Arduino delay() function, +// which will waste a lot of power. However, you can put your +// microcontroller to sleep instead by customizing the function below, +// and providing it to RadioLib via "node.setSleepFunction". +// NOTE: You ahve to ensure that this function is timed precisely, and +// does actually wait for the amount of time specified! +// Failure to do so will result in missed downlinks or failed join! +void customDelay(RadioLibTime_t ms) { + // this is just an example, so we use the Arduino delay() function, + // but you can put your microcontroller to sleep here + ::delay(ms); +} + #endif diff --git a/keywords.txt b/keywords.txt index 85ed0ed9a7..64415e2f68 100644 --- a/keywords.txt +++ b/keywords.txt @@ -379,6 +379,7 @@ getLastToA KEYWORD2 dutyCycleInterval KEYWORD2 timeUntilUplink KEYWORD2 getMaxPayloadLen KEYWORD2 +setSleepFunction KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 333623a114..6c7f5a31e4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -67,7 +67,6 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP return(RADIOLIB_ERR_NULL_POINTER); } int16_t state = RADIOLIB_ERR_UNKNOWN; - Module* mod = this->phyLayer->getMod(); // if after (at) ADR_ACK_LIMIT frames no RekeyConf was received, revert to Join state if(this->fCntUp == (1UL << this->adrLimitExp)) { @@ -147,7 +146,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4) // must be present after any confirmed frame, so we force this here if(isConfirmed) { - mod->hal->delay(this->phyLayer->random(1000, 3000)); + this->sleepDelay(this->phyLayer->random(1000, 3000)); } // if an error occured or a downlink was received, stop retransmission @@ -927,7 +926,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) if(this->tUplink > tNow) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow)); if(this->tUplink > mod->hal->millis()) { - mod->hal->delay(this->tUplink - mod->hal->millis()); + this->sleepDelay(this->tUplink - mod->hal->millis()); } } @@ -936,7 +935,7 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RADIOLIB_ASSERT(state); // sleep for the duration of the transmission - mod->hal->delay(toa); + this->sleepDelay(toa); RadioLibTime_t txEnd = mod->hal->millis(); // wait for an additional transmission duration as Tx timeout period @@ -1342,7 +1341,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u if(this->tUplink > tNow) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow)); if(this->tUplink > mod->hal->millis()) { - mod->hal->delay(this->tUplink - mod->hal->millis()); + this->sleepDelay(this->tUplink - mod->hal->millis()); } } @@ -1351,7 +1350,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u RADIOLIB_ASSERT(state); // sleep for the duration of the transmission - mod->hal->delay(toa); + this->sleepDelay(toa); RadioLibTime_t txEnd = mod->hal->millis(); // wait for an additional transmission duration as Tx timeout period @@ -1398,7 +1397,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne // if function was called while Rx windows are in progress, // wait until last window closes to prevent very bad stuff if(now < tReference + dlDelays[numWindows]) { - mod->hal->delay(dlDelays[numWindows] + tReference - now); + this->sleepDelay(dlDelays[numWindows] + tReference - now); } // update the end timestamp in case user got stuck between uplink and downlink this->rxDelayEnd = mod->hal->millis(); @@ -1444,7 +1443,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne if(waitLen > this->scanGuard) { waitLen -= this->scanGuard; } - mod->hal->delay(waitLen); + this->sleepDelay(waitLen); // open Rx window by starting receive with specified timeout state = this->phyLayer->launchMode(); @@ -1453,7 +1452,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); // wait for the timeout to complete (and a small additional delay) - mod->hal->delay(timeoutHost / 1000 + 2); + this->sleepDelay(timeoutHost / 1000 + this->scanGuard / 2); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); // if the IRQ bit for Rx Timeout is not set, something is received, so stop the windows @@ -3376,6 +3375,10 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { return(curLen - 13 - this->fOptsUpLen); } +void LoRaWANNode::setSleepFunction(SleepCb_t cb) { + this->sleepCb = cb; +} + int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t state = this->phyLayer->standby(); if(state != RADIOLIB_ERR_NONE) { @@ -3500,6 +3503,18 @@ void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_ } } +void LoRaWANNode::sleepDelay(RadioLibTime_t ms) { + // if the user did not provide sleep callback, or the duration is short, just call delay + if((this->sleepCb == nullptr) || (ms <= RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD)) { + Module* mod = this->phyLayer->getMod(); + mod->hal->delay(ms); + return; + } + + // otherwise, call the user-provided callback + this->sleepCb(ms); +} + int16_t LoRaWANNode::checkBufferCommon(const uint8_t *buffer, uint16_t size) { // check if there are actually values in the buffer size_t i = 0; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 48272336e7..fd86f9921f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -210,6 +210,9 @@ #define RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE (250) +// threshold at which sleeping via user callback enabled, in ms +#define RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD (50) + /*! \struct LoRaWANMacCommand_t \brief MAC command specification structure. @@ -832,6 +835,18 @@ class LoRaWANNode { */ uint8_t getMaxPayloadLen(); + /*! \brief Callback to a user-provided sleep function. */ + typedef void (*SleepCb_t)(RadioLibTime_t ms); + + /*! + \brief Set custom delay/sleep function callback. If set, LoRaWAN node will call + this function to wait for periods of time longer than RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD. + This can be used to lower the power consumption by putting the host microcontroller to sleep. + NOTE: Since this method will call a user-provided function, it is up to the user to ensure + that the time duration spent in that sleep function is accurate to at least 1 ms! + */ + void setSleepFunction(SleepCb_t cb); + /*! \brief TS009 Protocol Specification Verification switch (allows FPort 224 and cuts off uplink payload instead of rejecting if maximum length exceeded). @@ -973,6 +988,8 @@ class LoRaWANNode { // allow port 226 for devices implementing TS011 bool TS011 = false; + SleepCb_t sleepCb = nullptr; + // this will reset the device credentials, so the device starts completely new void clearNonces(); @@ -1102,6 +1119,9 @@ class LoRaWANNode { // function to encrypt and decrypt payloads (regular uplink/downlink) void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); + // function that allows sleeping via user-provided callback + void sleepDelay(RadioLibTime_t ms); + // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum static uint16_t checkSum16(const uint8_t *key, uint16_t keyLen); From e86fb2764914a387a54ff0e5894692b3997c16d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 10 Feb 2025 08:35:52 +0100 Subject: [PATCH 1488/1848] [CI] Measure code coverage after unit test (#1417) * [CI] Measure code coverage after unit test * [CI] Update workflow * [CI] Fix indentation * [CI] Ignore geninfo errors * [CI] Force gcov 11 * [CI] Install gcc 11 * [CI] Revert gcc-11 * Use ubuntu 22.04 as unit test runner * Deploy coverage report to github pages * Add coverage link --------- Co-authored-by: jgromes --- .github/workflows/unit-test.yml | 24 ++++++++++++++++++++++-- extras/test/unit/.gitignore | 1 + extras/test/unit/CMakeLists.txt | 6 ++++-- extras/test/unit/coverage.sh | 12 ++++++++++++ src/RadioLib.h | 1 + 5 files changed, 40 insertions(+), 4 deletions(-) create mode 100755 extras/test/unit/coverage.sh diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 58a7d72250..0d61656cc6 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -10,7 +10,7 @@ on: jobs: unit-test: name: Build and run unit test - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout repository @@ -19,9 +19,29 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y libboost-all-dev libfmt-dev + sudo apt-get install -y libboost-all-dev libfmt-dev lcov - name: Run unit test run: | cd extras/test/unit ./test.sh + + - name: Measure test coverage + run: | + cd extras/test/unit + ./coverage.sh + + - name: Upload coverage report as artifact + uses: actions/upload-artifact@v4 + with: + name: coverage_report + path: extras/test/unit/lcov.report + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: extras/test/unit/lcov.report + destination_dir: coverage + keep_files: true diff --git a/extras/test/unit/.gitignore b/extras/test/unit/.gitignore index 567609b123..b9f0c3b031 100644 --- a/extras/test/unit/.gitignore +++ b/extras/test/unit/.gitignore @@ -1 +1,2 @@ build/ +lcov* diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt index 300b886935..a3943e84f2 100644 --- a/extras/test/unit/CMakeLists.txt +++ b/extras/test/unit/CMakeLists.txt @@ -18,11 +18,13 @@ add_executable(${PROJECT_NAME} ${TEST_SOURCES}) target_include_directories(${PROJECT_NAME} PUBLIC include) # link RadioLib -target_link_libraries(${PROJECT_NAME} RadioLib fmt) +target_link_libraries(${PROJECT_NAME} RadioLib fmt gcov) # set target properties and options set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) -target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra) +set(BUILD_FLAGS -Wall -Wextra -fprofile-arcs -ftest-coverage -O0) +target_compile_options(${PROJECT_NAME} PRIVATE ${BUILD_FLAGS}) +target_compile_options(RadioLib PRIVATE ${BUILD_FLAGS}) # set RadioLib debug #target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI RADIOLIB_DEBUG_PROTOCOL) diff --git a/extras/test/unit/coverage.sh b/extras/test/unit/coverage.sh new file mode 100755 index 0000000000..c2c3c9dd3b --- /dev/null +++ b/extras/test/unit/coverage.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e +filename="lcov" +rm -rf $filename.* +lcov --capture --directory build --output-file "${filename}.info" + +# filter out boost and C++ standard library +lcov --remove "${filename}.info" "/usr/*/boost/*" "/usr/include/c++/*" --output-file "${filename}.info" + +# generate HTML +genhtml "${filename}.info" --output-directory "${filename}.report" diff --git a/src/RadioLib.h b/src/RadioLib.h index adc6854a35..3c362e117d 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -37,6 +37,7 @@ - PhysicalLayer - FSK and LoRa radio modules \see https://github.com/jgromes/RadioLib + \see https://jgromes.github.io/RadioLib/coverage/src/index.html \copyright Copyright (c) 2019 Jan Gromes */ From e087449c0b451170c4c4880a910d0b1338f6cf95 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 11 Feb 2025 14:28:31 +0100 Subject: [PATCH 1489/1848] Use configurable line feed for debug output (#1398) --- src/BuildOpt.h | 18 +++++++++++------- src/modules/Si443x/Si443x.cpp | 4 ++-- src/protocols/Morse/Morse.cpp | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 297a91e4c7..e9a405165c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -118,6 +118,10 @@ //#define RADIOLIB_CLOCK_DRIFT_MS (0) #endif +#if !defined(RADIOLIB_LINE_FEED) + #define RADIOLIB_LINE_FEED "\r\n" +#endif + #if ARDUINO >= 100 // Arduino build #include "Arduino.h" @@ -471,9 +475,9 @@ #if RADIOLIB_DEBUG #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT(...) rlb_printf(__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M, ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) // some platforms do not support printf("%f"), so it has to be done this way #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) @@ -483,8 +487,8 @@ #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M, ##__VA_ARGS__) #endif #if !defined(RADIOLIB_DEBUG_PRINTLN) - #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "\n", ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "\n", ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) #endif #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif @@ -545,12 +549,12 @@ #define RADIOLIB_VALUE_TO_STRING(x) #x #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) -#define RADIOLIB_INFO "\nRadioLib Info\nVersion: \"" \ +#define RADIOLIB_INFO "" RADIOLIB_LINE_FEED "RadioLib Info" RADIOLIB_LINE_FEED "Version: \"" \ RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ - RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \ - "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \ + RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"" RADIOLIB_LINE_FEED \ + "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "" RADIOLIB_LINE_FEED \ "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) /*! diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index b66a9d228c..cb09bfada2 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -765,9 +765,9 @@ int16_t Si443x::updateClockRecovery() { uint16_t rxOsr_fixed = (uint16_t)rxOsr; // print that whole mess - RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch); + RADIOLIB_DEBUG_BASIC_PRINTLN("%X %X %X", bypass, decRate, manch); RADIOLIB_DEBUG_BASIC_PRINT_FLOAT((double)rxOsr, 2); - RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain); + RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X" RADIOLIB_LINE_FEED "%lu\t%lX" RADIOLIB_LINE_FEED "%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain); // update oversampling ratio int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index c261773bf5..fbacc82441 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -86,7 +86,7 @@ int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) { if((pauseLen >= low*(float)letterSpace) && (pauseLen <= high*(float)letterSpace)) { return(RADIOLIB_MORSE_CHAR_COMPLETE); } else if(pauseLen > wordSpace) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("\n"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN(RADIOLIB_LINE_FEED ""); return(RADIOLIB_MORSE_WORD_COMPLETE); } @@ -164,7 +164,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000); - RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG("\n"); + RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(RADIOLIB_LINE_FEED); return(1); } From 2e35481fc2708dae5df7810abaaaae750c83f8e2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 11 Feb 2025 15:21:30 +0100 Subject: [PATCH 1490/1848] Fix script argument check --- extras/cppcheck/check_file.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/cppcheck/check_file.sh b/extras/cppcheck/check_file.sh index a560cd339f..45c32744c7 100755 --- a/extras/cppcheck/check_file.sh +++ b/extras/cppcheck/check_file.sh @@ -1,6 +1,6 @@ #!/bin/bash -if [[ $@ -lt 1 ]]; then +if [[ $# -lt 1 ]]; then echo "Usage: $0 " exit 1 fi From 584f547954fc17b2420121b38960183fbc8ef01d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 11 Feb 2025 15:22:32 +0100 Subject: [PATCH 1491/1848] Fix debug info macro (#1398) --- src/BuildOpt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index e9a405165c..47511abaae 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -549,13 +549,13 @@ #define RADIOLIB_VALUE_TO_STRING(x) #x #define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x) -#define RADIOLIB_INFO "" RADIOLIB_LINE_FEED "RadioLib Info" RADIOLIB_LINE_FEED "Version: \"" \ +#define RADIOLIB_INFO "\r\nRadioLib Info\nVersion: \"" \ RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \ RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \ RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \ - RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"" RADIOLIB_LINE_FEED \ - "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "" RADIOLIB_LINE_FEED \ - "Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) + RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\r\n" \ + "Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\r\n" \ + RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) /*! \brief A simple assert macro, will return on error. From bcbf2a12e19aadfe859fa57b1ff349798d96a971 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 11 Feb 2025 20:18:32 +0100 Subject: [PATCH 1492/1848] [CI] Allow code coverage report deploy only from master --- .github/workflows/unit-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 0d61656cc6..b46a5160f0 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -38,6 +38,7 @@ jobs: path: extras/test/unit/lcov.report - name: Deploy to GitHub Pages + if: github.ref == 'refs/heads/master' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} From b9c214db95393efbfee58e1900f0618f0c93b9ba Mon Sep 17 00:00:00 2001 From: Crsarmv7l <85343771+Crsarmv7l@users.noreply.github.com> Date: Thu, 13 Feb 2025 17:20:56 +0100 Subject: [PATCH 1493/1848] [CC1101] FIFO Refills to transmit packets up to 255 bytes (#1404) * Update CC1101.h Add Max packet size for FIFO Refills * Define FIFO Size, Max packet Length for FIFO refills * FIFO REFILL - Go through FSTXON State - Check MARCSTATE to ensure ready to tx - Initial FIFO fill - Check FIFO bytes twice in accordance with errata - Refill FIFO - Check MARCSTATE is idle before returning * Fix typos * Fix another typo * min -> std::min per build check * Revert std::min back to min * Use RADIOLIB_MIN Macro instead of min * Move MARC State check for Idle to finishTransmit function Change allows startTransmit to stop blocking once the last bytes are added to the FIFO * Add timeouts for both MARC state checks * Fix typo * No interrupt for packets bigger than 64 bytes * Initialize state as RADIOLIB_ERR_NONE if avoiding ISR * Update example with packet size and discussion link * Update example with new packet size and discussion link * Update example, clarify blocking on greater than 64 bytes link discussion * Update doxygen comments for 255 byte limit, limitations and discussion link --- .../CC1101_Transmit_Address.ino | 5 +- .../CC1101_Transmit_Blocking.ino | 8 +-- .../CC1101_Transmit_Interrupt.ino | 12 ++-- src/modules/CC1101/CC1101.cpp | 63 +++++++++++++++++-- src/modules/CC1101/CC1101.h | 8 ++- 5 files changed, 79 insertions(+), 17 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index 89fef51c04..7042015623 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -82,10 +82,11 @@ void setup() { void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); - // you can transmit C-string or Arduino string up to 64 characters long + // you can transmit C-string or Arduino string up to 255 characters long int state = radio.transmit("Hello World!"); - // you can also transmit byte array up to 64 bytes long + // you can also transmit byte array up to 255 bytes long + // With some limitations see here: https://github.com/jgromes/RadioLib/discussions/1138 /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); diff --git a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino index 3f45061d9d..809cfa60bf 100644 --- a/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino +++ b/examples/CC1101/CC1101_Transmit_Blocking/CC1101_Transmit_Blocking.ino @@ -2,7 +2,7 @@ RadioLib CC1101 Blocking Transmit Example This example transmits packets using CC1101 FSK radio module. - Each packet contains up to 64 bytes of data, in the form of: + Each packet contains up to 255 bytes of data with some limitations (https://github.com/jgromes/RadioLib/discussions/1138), in the form of: - Arduino String - null-terminated char array (C-string) - arbitrary binary data (byte array) @@ -57,11 +57,11 @@ int count = 0; void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); - // you can transmit C-string or Arduino string up to 64 characters long + // you can transmit C-string or Arduino string up to 255 characters long String str = "Hello World! #" + String(count++); int state = radio.transmit(str); - // you can also transmit byte array up to 64 bytes long + // you can also transmit byte array up to 255 bytes long with some limitations; https://github.com/jgromes/RadioLib/discussions/1138 /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = radio.transmit(byteArr, 8); @@ -72,7 +72,7 @@ void loop() { Serial.println(F("success!")); } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { - // the supplied packet was longer than 64 bytes + // the supplied packet was longer than 255 bytes Serial.println(F("too long!")); } else { diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index e1d88624ee..e99e1910ca 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -3,7 +3,7 @@ This example transmits packets using CC1101 FSK radio module. Once a packet is transmitted, an interrupt is triggered. - Each packet contains up to 64 bytes of data, in the form of: + Each packet contains up to 255 bytes of data with some limitations (https://github.com/jgromes/RadioLib/discussions/1138), in the form of: - Arduino String - null-terminated char array (C-string) - arbitrary binary data (byte array) @@ -73,10 +73,12 @@ void setup() { Serial.print(F("[CC1101] Sending first packet ... ")); // you can transmit C-string or Arduino string up to - // 64 characters long + // 255 characters long transmissionState = radio.startTransmit("Hello World!"); - // you can also transmit byte array up to 64 bytes long + // you can also transmit byte array up to 255 bytes long + // When transmitting more than 64 bytes startTransmit blocks to refill the FIFO. + // Blocking ceases once the last bytes have been placed in the FIFO /* byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; @@ -119,11 +121,11 @@ void loop() { Serial.print(F("[CC1101] Sending another packet ... ")); // you can transmit C-string or Arduino string up to - // 64 characters long + // 255 characters long String str = "Hello World! #" + String(count++); transmissionState = radio.startTransmit(str); - // you can also transmit byte array up to 64 bytes long + // you can also transmit byte array up to 255 bytes long with limitations https://github.com/jgromes/RadioLib/discussions/1138 /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 1c0222c162..288be6333b 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -236,23 +236,49 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // flush Tx FIFO SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); - // set GDO0 mapping - int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); - RADIOLIB_ASSERT(state); + // Turn on freq oscilator + SPIsendCommand(RADIOLIB_CC1101_CMD_FSTXON); + + // Check MARCSTATE and wait until ready to tx + // 724us is the longest time for calibrate per datasheet + RadioLibTime_t start = this->mod->hal->micros(); + while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != 0x12) { + if(this->mod->hal->micros() - start > 724) { + standby(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + + // set GDO0 mapping only if we aren't refilling the FIFO + int16_t state = RADIOLIB_ERR_NONE; + if(len <= RADIOLIB_CC1101_FIFO_SIZE) { + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); + RADIOLIB_ASSERT(state); + } + + // data put on FIFO + uint8_t dataSent = 0; // optionally write packet length if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { + if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len); + dataSent+= 1; } // check address filtering uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr); + dataSent += 1; } // fill the FIFO - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), len); + uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), initialWrite); + dataSent += initialWrite; // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_TX); @@ -260,11 +286,40 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to transmit SPIsendCommand(RADIOLIB_CC1101_CMD_TX); + // Keep feeding the FIFO until the packet is done + while (dataSent < len) { + uint8_t fifoBytes = 0; + uint8_t prevFifobytes = 0; + + // Check number of bytes on FIFO twice due to the CC1101 errata. Block until two reads are equal. + do{ + fifoBytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); + prevFifobytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); + } while (fifoBytes != prevFifobytes); + + //If there is room add more data to the FIFO + if (fifoBytes < RADIOLIB_CC1101_FIFO_SIZE) { + uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - fifoBytes), (uint8_t)(len - dataSent)); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(&data[dataSent]), bytesToWrite); + dataSent += bytesToWrite; + } + } return(state); } int16_t CC1101::finishTransmit() { // set mode to standby to disable transmitter/RF switch + + // Check MARCSTATE for Idle to let anything in the FIFO empty + // Timeout is 2x FIFO transmit time + RadioLibTime_t timeout = (1.0f/(this->bitRate))*(RADIOLIB_CC1101_FIFO_SIZE*2.0f); + RadioLibTime_t start = this->mod->hal->millis(); + while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != 0x01) { + if(this->mod->hal->millis() - start > timeout) { + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + int16_t state = standby(); RADIOLIB_ASSERT(state); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 576f8d7398..d85179d2c6 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -8,7 +8,8 @@ // CC1101 physical layer properties #define RADIOLIB_CC1101_FREQUENCY_STEP_SIZE 396.7285156 -#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 64 +#define RADIOLIB_CC1101_MAX_PACKET_LENGTH 255 +#define RADIOLIB_CC1101_FIFO_SIZE 64 #define RADIOLIB_CC1101_CRYSTAL_FREQ 26.0f #define RADIOLIB_CC1101_DIV_EXPONENT 16 @@ -701,7 +702,10 @@ class CC1101: public PhysicalLayer { void clearPacketSentAction() override; /*! - \brief Interrupt-driven binary transmit method. + \brief Interrupt-driven binary transmit method for packets less than 64 bytes. + Method blocks for packets longer than 64 bytes up to a 255 byte limit, until + the last bytes are placed in the FIFO. Some limitations and issues apply; see discussion: + https://github.com/jgromes/RadioLib/discussions/1138 Overloads for string-based transmissions are implemented in PhysicalLayer. \param data Binary data to be sent. \param len Number of bytes to send. From 977b2c28c8989167719e9f0df8ee69b67b3feddb Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 13 Feb 2025 18:57:44 +0100 Subject: [PATCH 1494/1848] [nRF24] Add public LNA control method (#1392) --- src/modules/nRF24/nRF24.cpp | 4 ++++ src/modules/nRF24/nRF24.h | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 105ac298a9..a6c2f841f2 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -561,6 +561,10 @@ int16_t nRF24::setEncoding(uint8_t encoding) { return(RADIOLIB_ERR_NONE); } +int16_t nRF24::setLNA(bool enable) { + return(this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, enable ? RADIOLIB_NRF24_RF_LNA_ON : RADIOLIB_NRF24_RF_LNA_OFF, 0, 0)); +} + void nRF24::clearIRQ() { // clear status bits this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_STATUS, RADIOLIB_NRF24_RX_DR | RADIOLIB_NRF24_TX_DS | RADIOLIB_NRF24_MAX_RT, 6, 4); diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index e7db4ec548..48d21fe7a7 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -123,6 +123,8 @@ #define RADIOLIB_NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm #define RADIOLIB_NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm #define RADIOLIB_NRF24_RF_PWR_0_DBM 0b00000110 // 2 1 0 dBm (default) +#define RADIOLIB_NRF24_RF_LNA_OFF 0b00000000 // 0 0 LNA gain: Off +#define RADIOLIB_NRF24_RF_LNA_ON 0b00000001 // 0 0 On // RADIOLIB_NRF24_REG_STATUS #define RADIOLIB_NRF24_RX_DR 0b01000000 // 6 6 Rx data ready @@ -464,6 +466,14 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Enable or disable the low-noise amplifier. + Improves receive performance at the cost of increased power consumption. + \param enable True to enable. + \returns \ref status_codes + */ + int16_t setLNA(bool enable); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: From 35059a86fff8ec7ed737ab9ac5369739d322216a Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 14 Feb 2025 22:03:10 +0100 Subject: [PATCH 1495/1848] [SX126x] Remove node address methods from header (#1422) --- src/modules/SX126x/SX126x.h | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 6198029fab..d06d37e592 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -889,27 +889,6 @@ class SX126x: public PhysicalLayer { */ int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen); - /*! - \brief Sets node address. Calling this method will also enable address filtering for node address only. - \param addr Node address to be set. - \returns \ref status_codes - */ - int16_t setNodeAddress(uint8_t addr); - - /*! - \brief Sets broadcast address. Calling this method will also enable address - filtering for node and broadcast address. - \param broadAddr Node address to be set. - \returns \ref status_codes - */ - int16_t setBroadcastAddress(uint8_t broadAddr); - - /*! - \brief Disables address filtering. Calling this method will also erase previously set addresses. - \returns \ref status_codes - */ - int16_t disableAddressFiltering(); - /*! \brief Sets CRC configuration. \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. From 2fd2926c9f2d84b5705bcd59b7e25b02aa57f698 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:47:45 +0100 Subject: [PATCH 1496/1848] [PHY] Make frequency step and max packet length public variables --- src/protocols/ExternalRadio/ExternalRadio.cpp | 9 ++++++--- src/protocols/FSK4/FSK4.cpp | 4 ++-- src/protocols/Hellschreiber/Hellschreiber.cpp | 2 +- src/protocols/Morse/Morse.cpp | 2 +- src/protocols/Pager/Pager.cpp | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 +------- src/protocols/PhysicalLayer/PhysicalLayer.h | 18 +++++++----------- src/protocols/RTTY/RTTY.cpp | 4 ++-- src/protocols/SSTV/SSTV.cpp | 6 +++--- 9 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index 212f8a155b..48a7790c23 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -1,20 +1,23 @@ #include "ExternalRadio.h" #if defined(RADIOLIB_BUILD_ARDUINO) -ExternalRadio::ExternalRadio(uint32_t pin) : PhysicalLayer(1, 0) { +ExternalRadio::ExternalRadio(uint32_t pin) : PhysicalLayer() { + this->freqStep = 1; mod = new Module(RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin); mod->hal->pinMode(pin, mod->hal->GpioModeOutput); this->prevFrf = 0; } #endif -ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer(1, 0) { +ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer() { + this->freqStep = 1; mod = new Module(hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, pin); mod->hal->pinMode(pin, mod->hal->GpioModeOutput); this->prevFrf = 0; } -ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer(1, 0) { +ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer() { + this->freqStep = 1; this->prevFrf = ext.prevFrf; if(ext.mod) { this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio()); diff --git a/src/protocols/FSK4/FSK4.cpp b/src/protocols/FSK4/FSK4.cpp index 4eb9b7bf80..b96362e2a5 100644 --- a/src/protocols/FSK4/FSK4.cpp +++ b/src/protocols/FSK4/FSK4.cpp @@ -34,7 +34,7 @@ int16_t FSK4Client::begin(float base, uint32_t shift, uint16_t rate) { } // calculate 24-bit frequency - baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->freqStep; // configure for direct mode return(phyLayer->startDirect()); @@ -109,7 +109,7 @@ int16_t FSK4Client::standby() { int32_t FSK4Client::getRawShift(int32_t shift) { // calculate module carrier frequency resolution - int32_t step = round(phyLayer->getFreqStep()); + int32_t step = round(phyLayer->freqStep); // check minimum shift value if(RADIOLIB_ABS(shift) < step / 2) { diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index 907aab7cc6..5e5d3c2b9e 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -21,7 +21,7 @@ HellClient::HellClient(AFSKClient* audio) { int16_t HellClient::begin(float base, float rate) { // calculate 24-bit frequency baseFreqHz = base; - baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->freqStep; // calculate "pixel" duration pixelDuration = 1000000.0f/rate; diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index fbacc82441..b5de27418c 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -23,7 +23,7 @@ MorseClient::MorseClient(AFSKClient* audio) { int16_t MorseClient::begin(float base, uint8_t speed) { // calculate 24-bit frequency baseFreqHz = base; - baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->freqStep; // calculate tone period for decoding basePeriod = (1000000.0f/base)/2.0f; diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index 905778edf8..e4615a5133 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -39,10 +39,10 @@ int16_t PagerClient::begin(float base, uint16_t speed, bool invert, uint16_t shi // calculate 24-bit frequency baseFreq = base; - baseFreqRaw = (baseFreq * 1000000.0f) / phyLayer->getFreqStep(); + baseFreqRaw = (baseFreq * 1000000.0f) / phyLayer->freqStep; // calculate module carrier frequency resolution - uint16_t step = round(phyLayer->getFreqStep()); + uint16_t step = round(phyLayer->freqStep); // calculate raw frequency shift shiftFreqHz = shift; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 3b7d870a13..b2e61d7d4e 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -2,9 +2,7 @@ #include -PhysicalLayer::PhysicalLayer(float step, size_t maxLen) { - this->freqStep = step; - this->maxPacketLength = maxLen; +PhysicalLayer::PhysicalLayer() { #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE this->bufferBitPos = 0; this->bufferWritePos = 0; @@ -294,10 +292,6 @@ int16_t PhysicalLayer::checkDataRate(DataRate_t dr) { return(RADIOLIB_ERR_UNSUPPORTED); } -float PhysicalLayer::getFreqStep() const { - return(this->freqStep); -} - size_t PhysicalLayer::getPacketLength(bool update) { (void)update; return(0); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 3d785b6d22..8cb32a0deb 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -216,14 +216,18 @@ enum RadioModeType_t { class PhysicalLayer { public: + /*! \brief Frequency step of the synthesizer in Hz. */ + float freqStep; + + /*! \brief Maximum length of packet that can be received by the module. */ + size_t maxPacketLength; + // constructor /*! \brief Default constructor. - \param step Frequency step of the synthesizer in Hz. - \param maxLen Maximum length of packet that can be received by the module. */ - PhysicalLayer(float step, size_t maxLen); + PhysicalLayer(); // basic methods @@ -475,12 +479,6 @@ class PhysicalLayer { */ virtual int16_t checkDataRate(DataRate_t dr); - /*! - \brief Gets the module frequency step size that was set in constructor. - \returns Synthesizer frequency step size in Hz. - */ - float getFreqStep() const; - /*! \brief Query modem for the packet length of received payload. Must be implemented in module class. \param update Update received packet length. Will return cached value when set to false. @@ -778,8 +776,6 @@ class PhysicalLayer { #if !RADIOLIB_GODMODE private: #endif - float freqStep; - size_t maxPacketLength; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE uint8_t bufferBitPos = 0; diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index aceddbe85c..61fe7cdfa7 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -31,7 +31,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc bitDuration = (RadioLibTime_t)1000000/rate; // calculate module carrier frequency resolution - uint32_t step = round(phyLayer->getFreqStep()); + uint32_t step = round(phyLayer->freqStep); // check minimum shift value if(shift < step / 2) { @@ -46,7 +46,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc } // calculate 24-bit frequency - baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->freqStep; // configure for direct mode return(phyLayer->startDirect()); diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index b4df42522b..397dc80b5f 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -219,7 +219,7 @@ int16_t SSTVClient::begin(float base, const SSTVMode_t& mode) { txMode = mode; // calculate 24-bit frequency - baseFreq = (base * 1000000.0f) / phyLayer->getFreqStep(); + baseFreq = (base * 1000000.0f) / phyLayer->freqStep; // configure for direct mode return(phyLayer->startDirect()); @@ -365,10 +365,10 @@ void SSTVClient::tone(float freq, RadioLibTime_t len) { if(audioClient != nullptr) { audioClient->tone(freq, false); } else { - phyLayer->transmitDirect(baseFreq + (freq / phyLayer->getFreqStep())); + phyLayer->transmitDirect(baseFreq + (freq / phyLayer->freqStep)); } #else - phyLayer->transmitDirect(baseFreq + (freq / phyLayer->getFreqStep())); + phyLayer->transmitDirect(baseFreq + (freq / phyLayer->freqStep)); #endif mod->waitForMicroseconds(start, len); } From 8286e2d7701e0f359440697a0d273ea594b9e207 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:08 +0100 Subject: [PATCH 1497/1848] [CC1101] Use public frequency step and max packet length variables --- src/modules/CC1101/CC1101.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 288be6333b..e3628a529f 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -2,7 +2,9 @@ #include #if !RADIOLIB_EXCLUDE_CC1101 -CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) { +CC1101::CC1101(Module* module) : PhysicalLayer() { + this->freqStep = RADIOLIB_CC1101_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_CC1101_MAX_PACKET_LENGTH; this->mod = module; } From 78e299145946ee8a66ee1f8aae51c1b7e6ce1a68 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:16 +0100 Subject: [PATCH 1498/1848] [LR11x0] Use public frequency step and max packet length variables --- src/modules/LR11x0/LR11x0.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 9a2085bab8..9a25a9cb4f 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -8,7 +8,9 @@ #if !RADIOLIB_EXCLUDE_LR11X0 -LR11x0::LR11x0(Module* mod) : PhysicalLayer(RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE, RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { +LR11x0::LR11x0(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; this->mod = mod; this->XTAL = false; this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE; From e4daea6251e52f56379b9212162335babb12b76a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:23 +0100 Subject: [PATCH 1499/1848] [nRF24] Use public frequency step and max packet length variables --- src/modules/nRF24/nRF24.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index a6c2f841f2..c46404ee40 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -2,7 +2,9 @@ #include #if !RADIOLIB_EXCLUDE_NRF24 -nRF24::nRF24(Module* mod) : PhysicalLayer(RADIOLIB_NRF24_FREQUENCY_STEP_SIZE, RADIOLIB_NRF24_MAX_PACKET_LENGTH) { +nRF24::nRF24(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_NRF24_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_NRF24_MAX_PACKET_LENGTH; this->mod = mod; } From 558e60b18dcbbc3840cd097cc9316d9909fdfa5d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:33 +0100 Subject: [PATCH 1500/1848] [RF69] Use public frequency step and max packet length variables --- src/modules/RF69/RF69.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 6780a17c8f..f1fdd7fc68 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -2,7 +2,9 @@ #include #if !RADIOLIB_EXCLUDE_RF69 -RF69::RF69(Module* module) : PhysicalLayer(RADIOLIB_RF69_FREQUENCY_STEP_SIZE, RADIOLIB_RF69_MAX_PACKET_LENGTH) { +RF69::RF69(Module* module) : PhysicalLayer() { + this->freqStep = RADIOLIB_RF69_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_RF69_MAX_PACKET_LENGTH; this->mod = module; } From c420d69193d48b4439d0517a2c5dda98beefaa2b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:45 +0100 Subject: [PATCH 1501/1848] [Si443x] Use public frequency step and max packet length variables --- src/modules/Si443x/Si443x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index cb09bfada2..0de41b36e9 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -2,7 +2,9 @@ #include #if !RADIOLIB_EXCLUDE_SI443X -Si443x::Si443x(Module* mod) : PhysicalLayer(RADIOLIB_SI443X_FREQUENCY_STEP_SIZE, RADIOLIB_SI443X_MAX_PACKET_LENGTH) { +Si443x::Si443x(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_SI443X_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_SI443X_MAX_PACKET_LENGTH; this->mod = mod; } From 699f025581dc51e5522c51b92262ae645d24b289 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:51 +0100 Subject: [PATCH 1502/1848] [SX126x] Use public frequency step and max packet length variables --- src/modules/SX126x/SX126x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 26f169c771..16bf80942a 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -3,7 +3,9 @@ #include #if !RADIOLIB_EXCLUDE_SX126X -SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) { +SX126x::SX126x(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_SX126X_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_SX126X_MAX_PACKET_LENGTH; this->mod = mod; this->XTAL = false; this->standbyXOSC = false; From 24c71661703774ce019a823049edb60828cad408 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:48:55 +0100 Subject: [PATCH 1503/1848] [SX127x] Use public frequency step and max packet length variables --- src/modules/SX127x/SX127x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index c8a422785e..54e9e8f8fc 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -2,7 +2,9 @@ #include #if !RADIOLIB_EXCLUDE_SX127X -SX127x::SX127x(Module* mod) : PhysicalLayer(RADIOLIB_SX127X_FREQUENCY_STEP_SIZE, RADIOLIB_SX127X_MAX_PACKET_LENGTH) { +SX127x::SX127x(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_SX127X_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_SX127X_MAX_PACKET_LENGTH; this->mod = mod; } From 5f1303aaba4a60aaf4cde6b2d8047b17440c543e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:49:01 +0100 Subject: [PATCH 1504/1848] [SX128x] Use public frequency step and max packet length variables --- src/modules/SX128x/SX128x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index fe58c7c0cc..288ec92863 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -2,7 +2,9 @@ #include #if !RADIOLIB_EXCLUDE_SX128X -SX128x::SX128x(Module* mod) : PhysicalLayer(RADIOLIB_SX128X_FREQUENCY_STEP_SIZE, RADIOLIB_SX128X_MAX_PACKET_LENGTH) { +SX128x::SX128x(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_SX128X_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_SX128X_MAX_PACKET_LENGTH; this->mod = mod; this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX128X_IRQ_TX_DONE; this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX128X_IRQ_RX_DONE; From 4a557f51627c4469acb68bf2a051a7224665d65e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Feb 2025 14:57:36 +0100 Subject: [PATCH 1505/1848] [PHY] Add missing member variable init --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index b2e61d7d4e..e698092c1f 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -3,6 +3,8 @@ #include PhysicalLayer::PhysicalLayer() { + this->freqStep = 1; + this->maxPacketLength = 1; #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE this->bufferBitPos = 0; this->bufferWritePos = 0; From 9c82d1bdc2296ac206336f341b09ee97b9c3531f Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 17 Feb 2025 17:42:20 +0100 Subject: [PATCH 1506/1848] [LR11x0] Fix latitude/longitude for negative values (#1379) --- src/modules/LR11x0/LR11x0.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 9a25a9cb4f..04b703f095 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -3541,11 +3541,11 @@ int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, floa if(error) { *error = buff[0]; } if(nbSvUsed) { *nbSvUsed = buff[1]; } if(lat) { - uint16_t latRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; + int16_t latRaw = ((int16_t)(buff[2]) << 8) | (int16_t)buff[3]; *lat = ((float)latRaw * 90.0f)/2048.0f; } if(lon) { - uint16_t lonRaw = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; + int16_t lonRaw = ((int16_t)(buff[4]) << 8) | (int16_t)buff[5]; *lon = ((float)lonRaw * 180.0f)/2048.0f; } if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } From ae65265268accd9ea7db807ed18f3f34896a43fa Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 17 Feb 2025 18:36:36 +0100 Subject: [PATCH 1507/1848] [LR11x0] Fix rest of latitude/longitude conversion (#1379) --- src/modules/LR11x0/LR11x0.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 04b703f095..bf8dc997c6 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -3254,8 +3254,8 @@ int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, } int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) { - uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; - uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; + int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; + int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; uint8_t buff[4] = { (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), @@ -3269,11 +3269,11 @@ int16_t LR11x0::gnssReadAssistancePosition(float* lat, float* lon) { // pass the replies if(lat) { - uint16_t latRaw = ((uint16_t)(buff[0]) << 8) | (uint16_t)(buff[1]); + int16_t latRaw = ((int16_t)(buff[0]) << 8) | (int16_t)(buff[1]); *lat = ((float)latRaw*90.0f)/2048.0f; } if(lon) { - uint16_t lonRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)(buff[3]); + int16_t lonRaw = ((int16_t)(buff[2]) << 8) | (int16_t)(buff[3]); *lon = ((float)lonRaw*180.0f)/2048.0f; } @@ -3403,8 +3403,8 @@ int16_t LR11x0::gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac) { } int16_t LR11x0::gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { - uint16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; - uint16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; + int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; + int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; uint8_t reqBuff[9] = { (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), @@ -3551,11 +3551,11 @@ int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, floa if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; } if(latFilt) { - uint16_t latRaw = ((uint16_t)(buff[10]) << 8) | (uint16_t)buff[11]; + int16_t latRaw = ((int16_t)(buff[10]) << 8) | (int16_t)buff[11]; *latFilt = ((float)latRaw * 90.0f)/2048.0f; } if(lonFilt) { - uint16_t lonRaw = ((uint16_t)(buff[12]) << 8) | (uint16_t)buff[13]; + int16_t lonRaw = ((int16_t)(buff[12]) << 8) | (int16_t)buff[13]; *lonFilt = ((float)lonRaw * 180.0f)/2048.0f; } if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; } From 6a96d44b2bdee76bd7dbaca09eb24067d02adba1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 17 Feb 2025 21:19:18 +0100 Subject: [PATCH 1508/1848] [SX127x] Fix automated RFO selection (#1412) --- src/modules/SX127x/SX1272.cpp | 3 ++- src/modules/SX127x/SX1272.h | 5 +++-- src/modules/SX127x/SX1278.cpp | 3 ++- src/modules/SX127x/SX1278.h | 5 +++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 48f01a6572..e6e4406d64 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -279,8 +279,9 @@ int16_t SX1272::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } -int16_t SX1272::setOutputPower(int8_t power, bool useRfo) { +int16_t SX1272::setOutputPower(int8_t power, bool forceRfo) { // check if power value is configurable + bool useRfo = (power < 2) || forceRfo; int16_t state = checkOutputPower(power, NULL, useRfo); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 142ee174ba..aa412efcc0 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -201,10 +201,11 @@ class SX1272: public SX127x { /*! \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). \param power Transmission output power in dBm. - \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. + \param forceRfo Whether to force using the RFO pin for the RF output (true) + or the lave the selection up to user (false) based on power output. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool useRfo); + int16_t setOutputPower(int8_t power, bool forceRfo); /*! \brief Check if output power is configurable. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 199d96967a..308ad5c3b9 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -293,8 +293,9 @@ int16_t SX1278::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } -int16_t SX1278::setOutputPower(int8_t power, bool useRfo) { +int16_t SX1278::setOutputPower(int8_t power, bool forceRfo) { // check if power value is configurable + bool useRfo = (power < 2) || forceRfo; int16_t state = checkOutputPower(power, NULL, useRfo); RADIOLIB_ASSERT(state); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 4b24e9dc72..a43e99f496 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -213,10 +213,11 @@ class SX1278: public SX127x { \brief Sets transmission output power. Allowed values range from -4 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. \param power Transmission output power in dBm. - \param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output. + \param forceRfo Whether to force using the RFO pin for the RF output (true) + or the lave the selection up to user (false) based on power output. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool useRfo); + int16_t setOutputPower(int8_t power, bool forceRfo); /*! \brief Check if output power is configurable. From 648ecbed3b6f477ecf1f2cf96175cff1d0118326 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 18 Feb 2025 07:20:42 +0100 Subject: [PATCH 1509/1848] [SX127x] Fix typo in doxygen comment --- src/modules/SX127x/SX1272.h | 2 +- src/modules/SX127x/SX1278.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index aa412efcc0..f3d835459b 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -202,7 +202,7 @@ class SX1272: public SX127x { \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). \param power Transmission output power in dBm. \param forceRfo Whether to force using the RFO pin for the RF output (true) - or the lave the selection up to user (false) based on power output. + or to leave the selection up to user (false) based on power output. \returns \ref status_codes */ int16_t setOutputPower(int8_t power, bool forceRfo); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index a43e99f496..dc606885c9 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -214,7 +214,7 @@ class SX1278: public SX127x { High power +20 dBm operation is also supported, on the PA_BOOST pin. \param power Transmission output power in dBm. \param forceRfo Whether to force using the RFO pin for the RF output (true) - or the lave the selection up to user (false) based on power output. + or to leave the selection up to user (false) based on power output. \returns \ref status_codes */ int16_t setOutputPower(int8_t power, bool forceRfo); From cf776230a448faf7414f2809e12b95b68ada9014 Mon Sep 17 00:00:00 2001 From: Crsarmv7l <85343771+Crsarmv7l@users.noreply.github.com> Date: Wed, 19 Feb 2025 19:44:01 +0100 Subject: [PATCH 1510/1848] Slightly increase timeout while waiting for MARC state to be ready for TX (#1429) --- src/modules/CC1101/CC1101.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index e3628a529f..13fdf11a90 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -243,9 +243,10 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // Check MARCSTATE and wait until ready to tx // 724us is the longest time for calibrate per datasheet + // Needs a bit more time for reliability RadioLibTime_t start = this->mod->hal->micros(); while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != 0x12) { - if(this->mod->hal->micros() - start > 724) { + if(this->mod->hal->micros() - start > 800) { standby(); return(RADIOLIB_ERR_TX_TIMEOUT); } From c9690a7955bbcf6234abb50d64bc29584bb2aff5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 27 Feb 2025 18:16:30 +0100 Subject: [PATCH 1511/1848] [EXT] Remove redundant null check (#1436) --- src/protocols/ExternalRadio/ExternalRadio.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/protocols/ExternalRadio/ExternalRadio.cpp b/src/protocols/ExternalRadio/ExternalRadio.cpp index 48a7790c23..b597f6f1a9 100644 --- a/src/protocols/ExternalRadio/ExternalRadio.cpp +++ b/src/protocols/ExternalRadio/ExternalRadio.cpp @@ -35,9 +35,7 @@ ExternalRadio& ExternalRadio::operator=(const ExternalRadio& ext) { } ExternalRadio::~ExternalRadio() { - if(this->mod) { - delete this->mod; - } + delete this->mod; } Module* ExternalRadio::getMod() { From 07792dc90fa43abe1886d3e92478708cfcbe2c1c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 2 Mar 2025 08:31:47 +0100 Subject: [PATCH 1512/1848] [MOD] Return debug information even after post-transfer GPIO timeout (#1434) --- src/Module.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 1c819b0d83..385f393056 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -317,6 +317,7 @@ int16_t Module::SPIcheckStream() { int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, const uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio) { // prepare the output buffer + int16_t state = RADIOLIB_ERR_NONE; size_t buffLen = cmdLen + numBytes; if(!write) { buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8); @@ -391,20 +392,18 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write // cppcheck-suppress unsignedLessThanZero if(this->hal->millis() - start >= this->spiConfig.timeout) { RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?"); - #if !RADIOLIB_STATIC_ONLY - delete[] buffOut; - delete[] buffIn; - #endif - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + + // do not return yet to display the debug output + state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; + break; } } } } - // parse status - int16_t state = RADIOLIB_ERR_NONE; - if((this->spiConfig.parseStatusCb != nullptr) && (numBytes > 0)) { + // parse status (only if GPIO did not timeout) + if((state == RADIOLIB_ERR_NONE) && (this->spiConfig.parseStatusCb != nullptr) && (numBytes > 0)) { state = this->spiConfig.parseStatusCb(buffIn[this->spiConfig.statusPos]); } From 56729041b33a9d71555725d4400d2a1539225a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 2 Mar 2025 09:37:55 +0100 Subject: [PATCH 1513/1848] [MOD] Add debug timestamps (#1440) --- src/BuildOpt.h | 82 ++++++++++++++++++++++++--------------------- src/Hal.cpp | 12 ++++++- src/Hal.h | 3 ++ src/Module.cpp | 8 ++--- src/utils/Utils.cpp | 23 ++++++++++--- src/utils/Utils.h | 4 +-- 6 files changed, 82 insertions(+), 50 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 47511abaae..2f8b10018c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -473,23 +473,20 @@ #endif #if RADIOLIB_DEBUG - #if defined(RADIOLIB_BUILD_ARDUINO) - #define RADIOLIB_DEBUG_PRINT(...) rlb_printf(__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M, ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(LEVEL "" M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) + #if !defined(RADIOLIB_DEBUG_PRINT) + #define RADIOLIB_DEBUG_PRINT(M, ...) rlb_printf(false, M, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) rlb_printf(true, LEVEL "" M, ##__VA_ARGS__) + #endif - // some platforms do not support printf("%f"), so it has to be done this way + #if !defined(RADIOLIB_DEBUG_PRINTLN) + #define RADIOLIB_DEBUG_PRINTLN(M, ...) rlb_printf(false, M RADIOLIB_LINE_FEED, ##__VA_ARGS__) + #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) rlb_printf(true, LEVEL "" M RADIOLIB_LINE_FEED, ##__VA_ARGS__) + #endif + + // some Arduino platforms do not support printf("%f"), so it has to be done this way + #if defined(RADIOLIB_BUILD_ARDUINO) #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) #else - #if !defined(RADIOLIB_DEBUG_PRINT) - #define RADIOLIB_DEBUG_PRINT(...) fprintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__) - #define RADIOLIB_DEBUG_PRINT_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M, ##__VA_ARGS__) - #endif - #if !defined(RADIOLIB_DEBUG_PRINTLN) - #define RADIOLIB_DEBUG_PRINTLN(M, ...) fprintf(RADIOLIB_DEBUG_PORT, M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) - #define RADIOLIB_DEBUG_PRINTLN_LVL(LEVEL, M, ...) fprintf(RADIOLIB_DEBUG_PORT, LEVEL "" M "" RADIOLIB_LINE_FEED, ##__VA_ARGS__) - #endif #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif @@ -497,52 +494,61 @@ #else #define RADIOLIB_DEBUG_PRINT(...) {} #define RADIOLIB_DEBUG_PRINTLN(...) {} - #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) {} + #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) {} #define RADIOLIB_DEBUG_HEXDUMP(...) {} #endif +#define RADIOLIB_DEBUG_TAG ": " +#define RADIOLIB_DEBUG_TAG_BASIC "RLB_DBG" RADIOLIB_DEBUG_TAG +#define RADIOLIB_DEBUG_TAG_PROTOCOL "RLB_PRO" RADIOLIB_DEBUG_TAG +#define RADIOLIB_DEBUG_TAG_SPI "RLB_SPI" RADIOLIB_DEBUG_TAG + #if RADIOLIB_DEBUG_BASIC - #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_DBG: ", __VA_ARGS__) - #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) - #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_DBG: ", __VA_ARGS__) - #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_DBG: ", __VA_ARGS__); - #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_DBG: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) #else #define RADIOLIB_DEBUG_BASIC_PRINT(...) {} - #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) {} - #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINTLN_NOTAG(...) {} #endif #if RADIOLIB_DEBUG_PROTOCOL - #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_PRO: ", __VA_ARGS__) - #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) - #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_PRO: ", __VA_ARGS__) - #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_PRO: ", __VA_ARGS__); - #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_PRO: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) #else #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {} - #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {} - #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(...) {} #endif #if RADIOLIB_DEBUG_SPI - #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL("RLB_SPI: ", __VA_ARGS__) - #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT_LVL("", __VA_ARGS__) - #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL("RLB_SPI: ", __VA_ARGS__) - #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN_LVL("", __VA_ARGS__) - #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT("RLB_SPI: ", __VA_ARGS__); - #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP("RLB_SPI: ", __VA_ARGS__); + #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) #else #define RADIOLIB_DEBUG_SPI_PRINT(...) {} - #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_SPI_PRINTLN(...) {} - #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {} - #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {} #endif // debug info strings diff --git a/src/Hal.cpp b/src/Hal.cpp index acc43bfe7f..90c86f4fda 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -1,12 +1,18 @@ #include "Hal.h" +static RadioLibHal* rlb_timestamp_hal = nullptr; + RadioLibHal::RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling) : GpioModeInput(input), GpioModeOutput(output), GpioLevelLow(low), GpioLevelHigh(high), GpioInterruptRising(rising), - GpioInterruptFalling(falling) {} + GpioInterruptFalling(falling) { + if(!rlb_timestamp_hal) { + rlb_timestamp_hal = this; + } + } void RadioLibHal::init() { @@ -33,3 +39,7 @@ void RadioLibHal::yield() { uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); } + +RadioLibTime_t rlb_time_us() { + return(rlb_timestamp_hal == nullptr ? 0 : rlb_timestamp_hal->micros()); +} diff --git a/src/Hal.h b/src/Hal.h index 291b34735d..3676fea26d 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -6,6 +6,9 @@ #include "BuildOpt.h" +/*! \brief Global-scope function that returns timestamp since start (in microseconds). */ +RadioLibTime_t rlb_time_us(); + /*! \class RadioLibHal \brief Hardware abstraction library base interface. diff --git a/src/Module.cpp b/src/Module.cpp index 385f393056..4ed06b468f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -227,7 +227,7 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uin for(size_t n = 0; n < numBytes; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]); } - RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); #endif #if !RADIOLIB_STATIC_ONLY @@ -426,7 +426,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write for(; n < cmdLen; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", cmd[n]); } - RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); // print data bytes RADIOLIB_DEBUG_SPI_PRINT("SI\t"); @@ -436,12 +436,12 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write for(; n < buffLen; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]); } - RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); RADIOLIB_DEBUG_SPI_PRINT("SO\t"); for(n = 0; n < buffLen; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffIn[n]); } - RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(); + RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); #endif #if !RADIOLIB_STATIC_ONLY diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 11a473c60c..2119f31647 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -1,7 +1,9 @@ #include "Utils.h" +#include "Hal.h" #include #include +#include #include #include @@ -59,7 +61,7 @@ void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t of sprintf(strPtr++, " "); } if(level) { - RADIOLIB_DEBUG_PRINT("%s", level); + RADIOLIB_DEBUG_PRINT_LVL("", "%s", level); } RADIOLIB_DEBUG_PRINT("%s", str); RADIOLIB_DEBUG_PRINTLN(); @@ -78,14 +80,20 @@ void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t of #endif } -#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) +#if RADIOLIB_DEBUG // https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50 -size_t rlb_printf(const char* format, ...) { +size_t rlb_printf(bool ts, const char* format, ...) { va_list arg; va_start(arg, format); char temp[64]; char* buffer = temp; - size_t len = vsnprintf(temp, sizeof(temp), format, arg); + RadioLibTime_t timestamp = rlb_time_us(); + unsigned long sec = timestamp/1000000UL; + unsigned long usec = timestamp%1000000UL; + size_t len_ts = 0; + if(ts) { len_ts = snprintf(temp, sizeof(temp), "[%lu.%06lu] ", sec, usec); } + size_t len_str = vsnprintf(&temp[len_ts], sizeof(temp) - len_ts, format, arg); + size_t len = len_ts + len_str; va_end(arg); if (len > sizeof(temp) - 1) { buffer = new char[len + 1]; @@ -93,10 +101,15 @@ size_t rlb_printf(const char* format, ...) { return 0; } va_start(arg, format); - vsnprintf(buffer, len + 1, format, arg); + if(ts) { len_ts = snprintf(buffer, len_ts + 1, "[%lu.%06lu] ", sec, usec); } + vsnprintf(buffer + len_ts, len_str + 1, format, arg); va_end(arg); } + #if defined(RADIOLIB_BUILD_ARDUINO) len = RADIOLIB_DEBUG_PORT.write(reinterpret_cast(buffer), len); + #else + len = fwrite(buffer, sizeof(temp[0]), len, RADIOLIB_DEBUG_PORT); + #endif if (buffer != temp) { delete[] buffer; } diff --git a/src/utils/Utils.h b/src/utils/Utils.h index b8c4ac6137..c979548f88 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -35,8 +35,8 @@ uint32_t rlb_reflect(uint32_t in, uint8_t bits); */ void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false); -#if RADIOLIB_DEBUG && defined(RADIOLIB_BUILD_ARDUINO) -size_t rlb_printf(const char* format, ...); +#if RADIOLIB_DEBUG +size_t rlb_printf(bool ts, const char* format, ...); #endif #endif From 01d1bdae2ce714f749a07cb922b2adb9e3298697 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sun, 2 Mar 2025 22:26:16 +0300 Subject: [PATCH 1514/1848] [SX128x] Add support for GFSK fixed packet length mode (#1441) * [SX1280] add support for GFSK fixed packet length mode * [SX1280] meet cpp check * [SX1280] cleanup --- src/modules/SX128x/SX128x.cpp | 38 +++++++++++++++++++++++++++-------- src/modules/SX128x/SX128x.h | 18 ++++++++++++++++- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 288ec92863..3c18d68d98 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -772,8 +772,7 @@ int16_t SX128x::setModem(ModemType_t modem) { int16_t SX128x::getModem(ModemType_t* modem) { RADIOLIB_ASSERT_PTR(modem); - uint8_t packetType = getPacketType(); - switch(packetType) { + switch(getPacketType()) { case(RADIOLIB_SX128X_PACKET_TYPE_LORA): *modem = ModemType_t::RADIOLIB_MODEM_LORA; return(RADIOLIB_ERR_NONE); @@ -827,7 +826,7 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { // update packet parameters this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4; - return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType)); } return(RADIOLIB_ERR_WRONG_MODEM); @@ -1014,7 +1013,7 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { /// \todo add support for multiple sync words this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1; } - return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType)); } int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { @@ -1045,7 +1044,7 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { } } this->crcGFSK = len << 4; - state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening); + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType); RADIOLIB_ASSERT(state); // set initial CRC value @@ -1107,7 +1106,7 @@ int16_t SX128x::setWhitening(bool enabled) { } if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { - return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening)); + return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType)); } return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening)); } @@ -1284,6 +1283,14 @@ size_t SX128x::getPacketLength(bool update, uint8_t* offset) { return((size_t)rxBufStatus[0]); } +int16_t SX128x::fixedPacketLengthMode(uint8_t len) { + return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED, len)); +} + +int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen)); +} + RadioLibTime_t SX128x::getTimeOnAir(size_t len) { // check active modem uint8_t modem = getPacketType(); @@ -1439,7 +1446,7 @@ int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled); } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) { - state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, cfg->transmit.len); + state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType, cfg->transmit.len); } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) { state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening); } else { @@ -1603,7 +1610,7 @@ int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_ return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); } -int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen, uint8_t hdrType) { +int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen) { const uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten }; return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7)); } @@ -1647,6 +1654,21 @@ int16_t SX128x::setPacketType(uint8_t type) { return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1)); } +int16_t SX128x::setPacketMode(uint8_t mode, uint8_t len) { + // check active modem + if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + int16_t state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, mode, len); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetType = mode; + return(state); +} + int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) { // check active modem uint8_t modem = getPacketType(); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 0211ed26eb..0fe91a4b1f 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -795,6 +795,20 @@ class SX128x: public PhysicalLayer { */ size_t getPacketLength(bool update, uint8_t* offset); + /*! + \brief Set modem in fixed packet length mode. Available in GFSK mode only. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX128X_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. Available in GFSK mode only. + \param maxLen Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX128X_MAX_PACKET_LENGTH); + /*! \brief Get expected time-on-air for a given size of payload. \param len Payload length in bytes. @@ -885,7 +899,7 @@ class SX128x: public PhysicalLayer { int16_t setTxParams(uint8_t pwr, uint8_t rampTime = RADIOLIB_SX128X_PA_RAMP_10_US); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3); - int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t payLen = 0xFF, uint8_t hdrType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE); + int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen = 0xFF); int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten); int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ = RADIOLIB_SX128X_LORA_IQ_STANDARD); int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX128X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX128X_IRQ_NONE); @@ -913,6 +927,7 @@ class SX128x: public PhysicalLayer { uint16_t bitRateKbps = 0; uint8_t bitRate = 0, modIndex = 0, shaping = 0; uint8_t preambleLengthGFSK = 0, syncWordLen = 0, syncWordMatch = 0, crcGFSK = 0, whitening = 0; + uint8_t packetType = RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE; // cached FLRC parameters uint8_t codingRateFLRC = 0; @@ -921,6 +936,7 @@ class SX128x: public PhysicalLayer { uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0; int16_t config(uint8_t modem); + int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); }; From d142928e9f6b47635ff1b7e2b9fa39f3c179bd48 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Mon, 3 Mar 2025 10:34:26 +0300 Subject: [PATCH 1515/1848] [SX128x] fix for invalid GSFK sync words order (#1444) --- src/modules/SX128x/SX128x.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 3c18d68d98..b55eb92ed7 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -996,10 +996,9 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { this->syncWordLen = len; } - // reverse sync word byte order uint8_t syncWordBuff[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; for(uint8_t i = 0; i < len; i++) { - syncWordBuff[4 - i] = syncWord[i]; + syncWordBuff[i] = syncWord[i]; } // update sync word From 08e0c0e61372e7ccbed430884e92167e37a59635 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 3 Mar 2025 08:36:03 +0100 Subject: [PATCH 1516/1848] [SX128x] Simplify sync word configuration --- src/modules/SX128x/SX128x.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index b55eb92ed7..0e6ca23ed2 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -996,13 +996,8 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { this->syncWordLen = len; } - uint8_t syncWordBuff[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; - for(uint8_t i = 0; i < len; i++) { - syncWordBuff[i] = syncWord[i]; - } - // update sync word - int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, syncWordBuff, 5); + int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, syncWord, len); RADIOLIB_ASSERT(state); // update packet parameters From d605bc2058ede0bd0dace4c944f2acaefd1057c6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 4 Mar 2025 08:10:09 +0100 Subject: [PATCH 1517/1848] [SX128x] Add missing const cast --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 0e6ca23ed2..7a719ab41c 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -997,7 +997,7 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { } // update sync word - int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, syncWord, len); + int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, const_cast(syncWord), len); RADIOLIB_ASSERT(state); // update packet parameters From 6bf0c3f7357518e3c00c9b88b158872b8ef91469 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Thu, 6 Mar 2025 09:09:01 +0300 Subject: [PATCH 1518/1848] [RF69] a fix for invalid sync word length setting (#1448) * [RF69] a fix for invalid sync word length setting * [RF69] fix maxErrBits width --- src/modules/RF69/RF69.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index f1fdd7fc68..d484a9eb94 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -696,7 +696,7 @@ int16_t RF69::setOutputPower(int8_t pwr, bool highPower) { int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBits) { // check constraints - if((maxErrBits > 7) || (len > 8)) { + if((maxErrBits > 7) || (len == 0) || (len > 8)) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } @@ -712,12 +712,12 @@ int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBit RADIOLIB_ASSERT(state); // set the length - state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, len, 5, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, len-1, 5, 3); // set sync word register this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); if(state == RADIOLIB_ERR_NONE) { - this->syncWordLength = len; + this->syncWordLength = len-1; } return(state); @@ -814,7 +814,7 @@ int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) { RADIOLIB_ASSERT(state); // set maximum error bits - return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, maxErrBits, 3, 0)); + return(this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, maxErrBits, 2, 0)); } int16_t RF69::disableSyncWordFiltering() { From c88cf551cc2a3c9d2bb918f14a1359c9d2d58dc8 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Thu, 6 Mar 2025 19:47:59 +0300 Subject: [PATCH 1519/1848] [SX128x] fix for improper GFSK syncword setting with length other than 5 bytes (#1446) * [SX128x] fix for improper GFSK syncword setting with length other than 5 bytes * [SX128x] misc. rework --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 7a719ab41c..e0ddb6a365 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -997,7 +997,7 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { } // update sync word - int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4, const_cast(syncWord), len); + int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), const_cast(syncWord), len); RADIOLIB_ASSERT(state); // update packet parameters From 7577ae413f1b0888475e406b4596debcd051a0f3 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 6 Mar 2025 18:31:20 +0100 Subject: [PATCH 1520/1848] Fix for CN470 (formerly CN500) --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 6 ++++-- examples/LoRaWAN/LoRaWAN_Reference/config.h | 6 ++++-- examples/LoRaWAN/LoRaWAN_Starter/config.h | 6 ++++-- examples/LoRaWAN/README.md | 2 +- keywords.txt | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 18 +++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 4 ++-- src/protocols/LoRaWAN/LoRaWANBands.cpp | 8 ++++---- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index 61bc63e0f3..b6c2bfeea4 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -41,9 +41,11 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN470 const LoRaWANBand_t Region = EU868; -const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + +// subband choice: for US915/AU915 set to 2, for CN470 set to 1, otherwise leave on 0 +const uint8_t subBand = 0; // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index 565e32d18e..7512140ca2 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -37,9 +37,11 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN470 const LoRaWANBand_t Region = EU868; -const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + +// subband choice: for US915/AU915 set to 2, for CN470 set to 1, otherwise leave on 0 +const uint8_t subBand = 0; // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index 21c79f8ee3..7aa606f1b9 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -37,9 +37,11 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds // for the curious, the #ifndef blocks allow for automated testing &/or you can // put your EUI & keys in to your platformio.ini - see wiki for more tips -// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN470 const LoRaWANBand_t Region = EU868; -const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + +// subband choice: for US915/AU915 set to 2, for CN470 set to 1, otherwise leave on 0 +const uint8_t subBand = 0; // ============================================================================ // Below is to support the sketch - only make changes if the notes say so ... diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index d2a7325410..e521567de5 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -8,7 +8,7 @@ RadioLib LoRaWAN examples. ## LoRaWAN versions & regional parameters RadioLib implements both LoRaWAN Specification 1.1 and 1.0.4. Confusingly, 1.0.4 is newer than 1.1, but 1.1 includes more security checks and as such **LoRaWAN 1.1 is preferred**. The catch is in the Regional Parameters: as RP002 1.0.4 is newer than RP001 1.1, it is more up to date regarding local laws & regulations. Therefore, RadioLib implements 1.0.4 as baseline and 1.1 (revision B) as fallback, and as such **RP002 Regional Parameters 1.0.4 is preferred**. -_Note: the CN500 band is implemented as specified in RP001 1.1 revision B, as the RP002 1.0.4 version is much too complex._ +_Note: the CN470 band is implemented as specified in RP001 1.1 revision B, as the RP002 1.0.4 version is much too complex._ To activate a LoRaWAN 1.1 session, supply all the required keys: ```cpp diff --git a/keywords.txt b/keywords.txt index 64415e2f68..e50821bc3d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -86,7 +86,7 @@ EU868 KEYWORD1 US915 KEYWORD1 EU433 KEYWORD1 AU915 KEYWORD1 -CN500 KEYWORD1 +CN470 KEYWORD1 AS923 KEYWORD1 AS923_2 KEYWORD1 AS923_3 KEYWORD1 diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6c7f5a31e4..7ef60d3416 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2422,9 +2422,9 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd chMaskGrp45 |= (uint32_t)chMask; break; case 5: - // for CN500, this is just a normal channel mask + // for CN470, this is just a normal channel mask // for all other bands, the first 10 bits enable banks of 8 125kHz channels - if(this->band->bandNum == BandCN500) { + if(this->band->bandNum == BandCN470) { chMaskGrp45 |= (uint32_t)chMask << 16; } else { int bank = 0; @@ -2443,19 +2443,19 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd case 6: // for dynamic bands: all channels ON (that are currently defined) // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 - // except for CN500: all 125kHz channels ON + // except for CN470: all 125kHz channels ON // for dynamic bands: retrieve all currently defined channels // for fixed bands: cannot store all defined channels, so select a random one from each bank this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN500) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN470) { chMaskGrp45 |= (uint32_t)chMask; } break; case 7: // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 - // except for CN500: RFU - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN500) { + // except for CN470: RFU + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN470) { chMaskGrp0123 = 0; chMaskGrp45 |= (uint32_t)chMask; } @@ -3031,7 +3031,7 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr *chMaskGrp0123 |= (uint64_t)0xFF << ((this->subBand - 1) * 8); *chMaskGrp45 |= (uint32_t)0x01 << (this->subBand - 1); } else if(this->subBand > 8 && this->subBand <= 12) { - // CN500 only: for sub band 9-12, set bank of 8 125kHz channels + // CN470 only: for sub band 9-12, set bank of 8 125kHz channels *chMaskGrp45 |= (uint32_t)0xFF << ((this->subBand - 9) * 8); } else { // if subband is set to 0, all 125kHz channels are enabled. @@ -3049,8 +3049,8 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr } } // the 500 kHz channels are in the usual channel plan however - // these are the channel indices 64-71 for bands other than CN500 - if(this->band->bandNum != BandCN500) { + // these are the channel indices 64-71 for bands other than CN470 + if(this->band->bandNum != BandCN470) { for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE && idx >= 64) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index fd86f9921f..e2c42647f4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -435,7 +435,7 @@ extern const LoRaWANBand_t EU868; extern const LoRaWANBand_t US915; extern const LoRaWANBand_t EU433; extern const LoRaWANBand_t AU915; -extern const LoRaWANBand_t CN500; +extern const LoRaWANBand_t CN470; extern const LoRaWANBand_t AS923; extern const LoRaWANBand_t AS923_2; extern const LoRaWANBand_t AS923_3; @@ -452,7 +452,7 @@ enum LoRaWANBandNum_t { BandUS915, BandEU433, BandAU915, - BandCN500, + BandCN470, BandAS923, BandAS923_2, BandAS923_3, diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 398de514f1..2c3370f2e7 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -8,7 +8,7 @@ const LoRaWANBand_t* LoRaWANBands[RADIOLIB_LORAWAN_NUM_SUPPORTED_BANDS] = { &US915, &EU433, &AU915, - &CN500, + &CN470, &AS923, &AS923_2, &AS923_3, @@ -331,8 +331,8 @@ const LoRaWANBand_t AU915 = { } }; -const LoRaWANBand_t CN500 = { - .bandNum = BandCN500, +const LoRaWANBand_t CN470 = { + .bandNum = BandCN470, .bandType = RADIOLIB_LORAWAN_BAND_FIXED, .freqMin = 4700000, .freqMax = 5100000, @@ -356,7 +356,7 @@ const LoRaWANBand_t CN500 = { .freqStep = 2000, .drMin = 0, .drMax = 5, - .drJoinRequest = 0 + .drJoinRequest = 3 }, RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE }, From 77db225396426d6b465a7185451e38e03939027a Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 8 Mar 2025 13:02:05 +0300 Subject: [PATCH 1521/1848] [RF69] further fix for sync word length --- src/modules/RF69/RF69.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index d484a9eb94..8671e137e8 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -712,7 +712,7 @@ int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBit RADIOLIB_ASSERT(state); // set the length - state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, len-1, 5, 3); + state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_SYNC_CONFIG, (len-1)<<3, 5, 3); // set sync word register this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); From d526ac3091e39fdbe17ffb581b776c3dc6a7db9b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 8 Mar 2025 13:09:54 +0100 Subject: [PATCH 1522/1848] [RF69] Remove redundant sync word length caching --- src/modules/RF69/RF69.cpp | 4 ---- src/modules/RF69/RF69.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 8671e137e8..0b91e5a9a5 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -716,10 +716,6 @@ int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBit // set sync word register this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_SYNC_VALUE_1, syncWord, len); - if(state == RADIOLIB_ERR_NONE) { - this->syncWordLength = len-1; - } - return(state); } diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 9015d66d61..daaea43381 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1031,8 +1031,6 @@ class RF69: public PhysicalLayer { bool promiscuous = false; - uint8_t syncWordLength = RADIOLIB_RF69_DEFAULT_SW_LEN; - bool bitSync = true; int16_t directMode(); From 416f52d92a772279ebd57f26fe7881c7ace22d3d Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 14 Mar 2025 20:14:23 +0100 Subject: [PATCH 1523/1848] [Si443x] Fix CRC error IRQ (#1430) --- src/modules/Si443x/Si443x.cpp | 40 +++++++++++++++++------- src/modules/Si443x/Si443x.h | 57 +++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 0de41b36e9..cf88f7a342 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -28,7 +28,7 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_1, RADIOLIB_SI443X_SOFTWARE_RESET); // clear POR interrupt - clearIRQFlags(); + clearIrqStatus(); // configure settings not accessible by API int16_t state = config(); @@ -107,7 +107,7 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { while(this->mod->hal->digitalRead(this->mod->getIrq())) { if(this->mod->hal->millis() - start > timeout) { standby(); - clearIRQFlags(); + clearIrqStatus(); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -243,7 +243,7 @@ int16_t Si443x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_TX_FIFO_CLEAR, 0, 0); // clear interrupt flags - clearIRQFlags(); + clearIrqStatus(); // set packet length if (this->packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { @@ -271,7 +271,7 @@ int16_t Si443x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { int16_t Si443x::finishTransmit() { // clear interrupt flags - clearIRQFlags(); + clearIrqStatus(); // set mode to standby to disable transmitter/RF switch return(standby()); @@ -287,7 +287,7 @@ int16_t Si443x::startReceive() { this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_OP_FUNC_CONTROL_2, RADIOLIB_SI443X_RX_FIFO_CLEAR, 1, 1); // clear interrupt flags - clearIRQFlags(); + clearIrqStatus(); // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_RX); @@ -311,8 +311,15 @@ int16_t Si443x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMa } int16_t Si443x::readData(uint8_t* data, size_t len) { - // clear interrupt flags - clearIRQFlags(); + // read interrupt flags + uint32_t irq = getIrqFlags(); + + // check integrity CRC + // Si443x does not have the option to keep the data after CRC failed + // reading the FIFO will just repeat the first byte (see https://github.com/jgromes/RadioLib/issues/1430) + if(irq & RADIOLIB_SI443X_CRC_ERROR_INTERRUPT) { + return(RADIOLIB_ERR_CRC_MISMATCH); + } // get packet length size_t length = getPacketLength(); @@ -339,7 +346,7 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // clear interrupt flags - clearIRQFlags(); + clearIrqStatus(); return(RADIOLIB_ERR_NONE); } @@ -635,6 +642,18 @@ int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) { return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen)); } +uint32_t Si443x::getIrqFlags() { + uint8_t data[] = { 0x00, 0x00 }; + this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, data); + return(((uint32_t)(data[0]) << 8) | data[1]); +} + +int16_t Si443x::clearIrqFlags(uint32_t irq) { + (void)irq; + (void)getIrqFlags(); + return(RADIOLIB_ERR_NONE); +} + Module* Si443x::getMod() { return(this->mod); } @@ -707,9 +726,8 @@ bool Si443x::findChip() { return(flagFound); } -void Si443x::clearIRQFlags() { - uint8_t buff[2]; - this->mod->SPIreadRegisterBurst(RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1, 2, buff); +void Si443x::clearIrqStatus() { + (void)getIrqFlags(); } void Si443x::clearFIFO(size_t count) { diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index c100b04e2d..42ddc9e7cb 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -128,19 +128,19 @@ #define RADIOLIB_SI443X_IDLE 0b00000000 // 1 0 idle // RADIOLIB_SI443X_REG_INTERRUPT_STATUS_1 -#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full -#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty -#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full -#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx -#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done -#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received -#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed +#define RADIOLIB_SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 << 8 // 7 7 Tx/Rx FIFO overflow or underflow +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 << 8 // 6 6 Tx FIFO almost full +#define RADIOLIB_SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 << 8 // 5 5 Tx FIFO almost empty +#define RADIOLIB_SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 << 8 // 4 4 Rx FIFO almost full +#define RADIOLIB_SI443X_EXTERNAL_INTERRUPT 0b00001000 << 8 // 3 3 external interrupt occurred on GPIOx +#define RADIOLIB_SI443X_PACKET_SENT_INTERRUPT 0b00000100 << 8 // 2 2 packet transmission done +#define RADIOLIB_SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 << 8 // 1 1 valid packet has been received +#define RADIOLIB_SI443X_CRC_ERROR_INTERRUPT 0b00000001 << 8 // 0 0 CRC failed // RADIOLIB_SI443X_REG_INTERRUPT_STATUS_2 #define RADIOLIB_SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected -#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected -#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected +#define RADIOLIB_SI443X_VALID_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected +#define RADIOLIB_SI443X_INVALID_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected #define RADIOLIB_SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold #define RADIOLIB_SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired #define RADIOLIB_SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected @@ -159,8 +159,8 @@ // RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2 #define RADIOLIB_SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled -#define RADIOLIB_SI443X_VALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled -#define RADIOLIB_SI443X_INVALID_RADIOLIB_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled +#define RADIOLIB_SI443X_VALID_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled +#define RADIOLIB_SI443X_INVALID_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled #define RADIOLIB_SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled #define RADIOLIB_SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled #define RADIOLIB_SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled @@ -810,18 +810,31 @@ class Si443x: public PhysicalLayer { #endif /*! - \brief Set modem in fixed packet length mode. - \param len Packet length. - \returns \ref status_codes - */ - int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + \brief Set modem in fixed packet length mode. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH); /*! - \brief Set modem in variable packet length mode. - \param maxLen Maximum packet length. + \brief Set modem in variable packet length mode. + \param maxLen Maximum packet length. \returns \ref status_codes - */ - int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + + /*! + \brief Read currently active IRQ flags. + \returns IRQ flags. + */ + uint32_t getIrqFlags() override; + + /*! + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + int16_t clearIrqFlags(uint32_t irq) override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -847,7 +860,7 @@ class Si443x: public PhysicalLayer { uint8_t packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; bool findChip(); - void clearIRQFlags(); + void clearIrqStatus(); void clearFIFO(size_t count); int16_t config(); int16_t updateClockRecovery(); From f0e686eaa959f1e0b796fd10cb051d4ba2691b9f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 14 Mar 2025 20:14:52 +0100 Subject: [PATCH 1524/1848] [Si443x] Add CRC configuration (#1430) --- src/modules/Si443x/Si443x.cpp | 17 ++++++++++++++--- src/modules/Si443x/Si443x.h | 9 +++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index cf88f7a342..b121635a6e 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -54,10 +54,13 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) state = packetMode(); RADIOLIB_ASSERT(state); - state = setDataShaping(0); + state = setDataShaping(RADIOLIB_SHAPING_NONE); RADIOLIB_ASSERT(state); - state = setEncoding(0); + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + state = setCRC(true); RADIOLIB_ASSERT(state); state = variablePacketLengthMode(); @@ -293,7 +296,8 @@ int16_t Si443x::startReceive() { this->mod->setRfSwitchState(Module::MODE_RX); // set interrupt mapping - this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED); + uint8_t irq = this->crcEnabled ? (RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED | RADIOLIB_SI443X_CRC_ERROR_ENABLED) : RADIOLIB_SI443X_VALID_PACKET_RECEIVED_ENABLED; + this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_1, irq); this->mod->SPIwriteRegister(RADIOLIB_SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // set mode to receive @@ -654,6 +658,13 @@ int16_t Si443x::clearIrqFlags(uint32_t irq) { return(RADIOLIB_ERR_NONE); } +int16_t Si443x::setCRC(bool enable, bool mode) { + this->crcEnabled = enable; + uint8_t crcEn = enable ? RADIOLIB_SI443X_CRC_ON : RADIOLIB_SI443X_CRC_OFF; + uint8_t crcCfg = mode ? RADIOLIB_SI443X_CRC_IBM_CRC16 : RADIOLIB_SI443X_CRC_CCITT; + return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_DATA_ACCESS_CONTROL, crcEn | crcCfg, 2, 0)); +} + Module* Si443x::getMod() { return(this->mod); } diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 42ddc9e7cb..a5e843ddd1 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -836,6 +836,14 @@ class Si443x: public PhysicalLayer { */ int16_t clearIrqFlags(uint32_t irq) override; + /*! + \brief Enables/disables CRC of transmitted or received packets. + \param enable Enable (true) or disable (false) CRC. + \param mode Set CRC mode + \returns \ref status_codes + */ + int16_t setCRC(bool enable, bool mode = false); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -858,6 +866,7 @@ class Si443x: public PhysicalLayer { size_t packetLength = 0; bool packetLengthQueried = false; uint8_t packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; + bool crcEnabled = false; bool findChip(); void clearIrqStatus(); From ec785005aa607b4da7c0e5f4367ebf379a43e477 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Mar 2025 21:47:20 +0100 Subject: [PATCH 1525/1848] [SX126x] Zero-initialize version string --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 16bf80942a..2b33642200 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -2359,7 +2359,7 @@ bool SX126x::findChip(const char* verStr) { reset(); // read the version string - char version[16]; + char version[16] = { 0 }; this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast(version)); // check version register From a88ec8dc0860914e6fad0c266c23a90daf99e8ea Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Fri, 4 Apr 2025 08:26:14 +0300 Subject: [PATCH 1526/1848] add few RADIOLIB_EXCLUDE_XXXX options missing (#1474) * add few RADIOLIB_EXCLUDE_XXXX options missing * add RADIOLIB_EXCLUDE_FSK4 and RADIOLIB_EXCLUDE_PAGER --- src/BuildOpt.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 2f8b10018c..6d6a6a67d2 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -196,6 +196,12 @@ //#define RADIOLIB_EXCLUDE_RTTY (1) //#define RADIOLIB_EXCLUDE_SSTV (1) //#define RADIOLIB_EXCLUDE_DIRECT_RECEIVE (1) + //#define RADIOLIB_EXCLUDE_BELL (1) + //#define RADIOLIB_EXCLUDE_APRS (1) + //#define RADIOLIB_EXCLUDE_LORAWAN (1) + //#define RADIOLIB_EXCLUDE_LR11X0 (1) + //#define RADIOLIB_EXCLUDE_FSK4 (1) + //#define RADIOLIB_EXCLUDE_PAGER (1) #elif defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. From 13ad2f63f98d990819e3eafb171f9541c963bb8f Mon Sep 17 00:00:00 2001 From: jcrespoc Date: Tue, 15 Apr 2025 18:13:10 +0200 Subject: [PATCH 1527/1848] [CC1101] Fix variable packet length with address enabled (#1483) --- src/modules/CC1101/CC1101.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 13fdf11a90..a086fa3ec9 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -262,17 +262,19 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // data put on FIFO uint8_t dataSent = 0; + uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); + // optionally write packet length if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } - SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len); + SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len + (filter != RADIOLIB_CC1101_ADR_CHK_NONE? 1:0)); dataSent+= 1; } // check address filtering - uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); + //uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr); dataSent += 1; From c570b44dc35f3d2cddf326926b17b1ea91e32328 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 16 Apr 2025 17:58:42 +0200 Subject: [PATCH 1528/1848] [LR11x0] Accept bootloader as valid device ID (#1487) --- src/modules/LR11x0/LR11x0.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index bf8dc997c6..711e91a063 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -2161,13 +2161,16 @@ bool LR11x0::findChip(uint8_t ver) { int16_t state = getVersionInfo(&info); RADIOLIB_ASSERT(state); - if(info.device == ver) { + if((info.device == ver) || (info.device == RADIOLIB_LR11X0_DEVICE_BOOT)) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device); RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor); if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) { RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi); RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS); } + if(info.device == RADIOLIB_LR11X0_DEVICE_BOOT) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Warning: device is in bootloader mode! Only FW update is possible now."); + } flagFound = true; } else { RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, info.device); @@ -2176,6 +2179,7 @@ bool LR11x0::findChip(uint8_t ver) { i++; } } + return(flagFound); } From 3002cdf3717cdd22171ff39081d1da16b8e052ba Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 4 May 2025 19:04:15 +0200 Subject: [PATCH 1529/1848] [SX127x] Fix register check when switching modems (#1496) --- src/modules/SX127x/SX127x.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 54e9e8f8fc..7b319129c3 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1591,7 +1591,9 @@ int16_t SX127x::setActiveModem(uint8_t modem) { int16_t state = setMode(RADIOLIB_SX127X_SLEEP); // set modem - state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5); + // low frequency access (bit 3) automatically resets when switching modem + // so we exclude it from the check + state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5, 0xF7); // set mode to STANDBY state |= setMode(RADIOLIB_SX127X_STANDBY); From 9209afcf865753b8398af9bb60deb2cbe48adf65 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 6 May 2025 13:28:56 +0200 Subject: [PATCH 1530/1848] [LoRaWAN] Improve window timing accuracy (#1491) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 41 ++++++++++++++++++++----------- src/protocols/LoRaWAN/LoRaWAN.h | 5 +++- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7ef60d3416..2233a2f1e0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -930,8 +930,11 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) } } - // start transmission + // start transmission, and time the duration of launchMode() to offset window timing + RadioLibTime_t spiStart = mod->hal->millis(); state = this->phyLayer->launchMode(); + RadioLibTime_t spiEnd = mod->hal->millis(); + this->launchDuration = spiEnd - spiStart; RADIOLIB_ASSERT(state); // sleep for the duration of the transmission @@ -1345,8 +1348,11 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u } } - // start transmission + // start transmission, and time the duration of launchMode() to offset window timing + RadioLibTime_t spiStart = mod->hal->millis(); state = this->phyLayer->launchMode(); + RadioLibTime_t spiEnd = mod->hal->millis(); + this->launchDuration = spiEnd - spiStart; RADIOLIB_ASSERT(state); // sleep for the duration of the transmission @@ -1433,15 +1439,16 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); RADIOLIB_ASSERT(state); - // wait for the start of the Rx window - RadioLibTime_t waitLen = tReference + dlDelays[window] - mod->hal->millis(); - // make sure that no underflow occured; if so, clip the delay (although this will likely miss any downlink) + // calculate time at which the window should open + RadioLibTime_t tWindow = tReference + dlDelays[window]; + // wait for the start of the Rx window launch + // - the launch of Rx window takes a few milliseconds, so shorten the waitLen a bit (launchDuration) + // - the Rx window is padded using scanGuard, so shorten the waitLen a bit (scanGuard / 2) + RadioLibTime_t waitLen = tWindow - mod->hal->millis() - this->launchDuration - this->scanGuard / 2; + + // make sure that no underflow occured; if so, there's something weird going on so return an error if(waitLen > dlDelays[window]) { - waitLen = dlDelays[window]; - } - // the waiting duration is shortened a bit to cover any possible timing errors - if(waitLen > this->scanGuard) { - waitLen -= this->scanGuard; + return(RADIOLIB_ERR_NO_RX_WINDOW); } this->sleepDelay(waitLen); @@ -1449,11 +1456,17 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne state = this->phyLayer->launchMode(); tOpen = mod->hal->millis(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opening Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); - // wait for the timeout to complete (and a small additional delay) - this->sleepDelay(timeoutHost / 1000 + this->scanGuard / 2); + // wait for the timeout to complete (and a small delay in case the RxTimeout interrupt needs to fire) + this->sleepDelay(timeoutHost / 1000); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); + while(mod->hal->millis() - tOpen <= timeoutHost / 1000 + this->scanGuard) { + // wait for the DIO interrupt to fire (RxDone or RxTimeout) + if(downlinkAction) { + break; + } + } // if the IRQ bit for Rx Timeout is not set, something is received, so stop the windows timedOut = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); @@ -1485,7 +1498,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne while(!downlinkAction) { mod->hal->yield(); // stay in Rx mode for the maximum allowed Time-on-Air plus small grace period - if(mod->hal->millis() - tOpen > tMax + scanGuard) { + if(mod->hal->millis() - tOpen > tMax + this->scanGuard) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink missing!"); downlinkComplete = false; break; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index e2c42647f4..2ca4c737f9 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -865,7 +865,7 @@ class LoRaWANNode { 500 is the **maximum** value, but it is not a good idea to go anywhere near that. If you have to go above 50 you probably have a bug somewhere. Check your device timing. */ - RadioLibTime_t scanGuard = 5; + RadioLibTime_t scanGuard = 10; #if !RADIOLIB_GODMODE protected: @@ -976,6 +976,9 @@ class LoRaWANNode { // timestamp when the Rx1/2 windows were closed (timeout or uplink received) RadioLibTime_t rxDelayEnd = 0; + // duration of SPI transaction for phyLayer->launchMode() + RadioLibTime_t launchDuration = 0; + // device status - battery level uint8_t battLevel = 0xFF; From 32642b7d7bfaefdf7fc8d974b3678647be8fe6c2 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 6 May 2025 13:39:26 +0200 Subject: [PATCH 1531/1848] [LoRaWAN] Handle bad block of LinkADRReq (#1497) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 2233a2f1e0..6fbc7cc520 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2429,9 +2429,15 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd case 1: case 2: case 3: + // clear the target 16-bit block + chMaskGrp0123 &= ~((uint64_t)0xFFFF << (16 * chMaskCntl)); + // set the new 16-bit value in that block chMaskGrp0123 |= (uint64_t)chMask << (16 * chMaskCntl); break; case 4: + // clear the target 16-bit block + chMaskGrp45 &= ~((uint32_t)0xFFFF); + // set the new 16-bit value in that block chMaskGrp45 |= (uint32_t)chMask; break; case 5: From f16854abd0778de6d6dfab88fd6d7fb4821d1480 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 6 May 2025 14:28:18 +0200 Subject: [PATCH 1532/1848] [LoRaWAN] Simplify FCnt rollover --- src/protocols/LoRaWAN/LoRaWAN.cpp | 48 ++++++++++++------------------- src/protocols/LoRaWAN/LoRaWAN.h | 1 - 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6fbc7cc520..855677ec83 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1461,7 +1461,7 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne // wait for the timeout to complete (and a small delay in case the RxTimeout interrupt needs to fire) this->sleepDelay(timeoutHost / 1000); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); - while(mod->hal->millis() - tOpen <= timeoutHost / 1000 + this->scanGuard) { + while(mod->hal->millis() - tOpen - timeoutHost / 1000 <= this->scanGuard) { // wait for the DIO interrupt to fire (RxDone or RxTimeout) if(downlinkAction) { break; @@ -1654,35 +1654,24 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e } // get the frame counter - uint16_t fCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); + uint32_t payFCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); - // check the fCntDown value (Network or Application) - uint32_t fCntDownPrev = 0; + // check the FCntDown value (Network or Application) + uint32_t devFCnt32 = 0; if (isAppDownlink) { - fCntDownPrev = this->aFCntDown; + devFCnt32 = this->aFCntDown; } else { - fCntDownPrev = this->nFCntDown; + devFCnt32 = this->nFCntDown; } - // if this is not the first downlink... - // assume a 16-bit to 32-bit rollover if difference between counters in LSB is smaller than MAX_FCNT_GAP - // if that isn't the case and the received fCnt is smaller or equal to the last heard fCnt, then error - uint32_t fCnt32 = fCnt16; - if(fCntDownPrev > 0) { - if((fCnt16 <= fCntDownPrev) && ((0xFFFF - (uint16_t)fCntDownPrev + fCnt16) > RADIOLIB_LORAWAN_MAX_FCNT_GAP)) { - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - if (isAppDownlink) { - return(RADIOLIB_ERR_A_FCNT_DOWN_INVALID); - } else { - return(RADIOLIB_ERR_N_FCNT_DOWN_INVALID); - } - } else if (fCnt16 <= fCntDownPrev) { - uint16_t msb = (fCntDownPrev >> 16) + 1; // assume a rollover - fCnt32 |= ((uint32_t)msb << 16); // add back the MSB part - } + // assume a rollover if the FCnt16 in the payload is smaller than the previous FCnt16 known by device + // (MAX_FCNT_GAP is deprecated for 1.0.4 / 1.1, TTS and CS both apply a 16-bit rollover) + if(payFCnt16 < (devFCnt32 & 0xFFFF)) { + Serial.printf("Rollover: %d -> %d\n", payFCnt16, devFCnt32); + devFCnt32 += 0x10000; // apply rollover } + devFCnt32 &= ~0xFFFF; // clear lower 16 bits known by device + devFCnt32 |= payFCnt16; // set lower 16 bits from payload // check if the ACK bit is set, indicating this frame acknowledges the previous uplink bool isConfirmingUp = false; @@ -1700,10 +1689,11 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e } downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_DOWNLINK; LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fCnt32); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], devFCnt32); downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); // check the MIC + // (if a rollover was more than 16-bit, this will always throw CRC mismatch) if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; @@ -1713,9 +1703,9 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e // save current fCnt to respective frame counter if (isAppDownlink) { - this->aFCntDown = fCnt32; + this->aFCntDown = devFCnt32; } else { - this->nFCntDown = fCnt32; + this->nFCntDown = devFCnt32; } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) encoded:", @@ -1763,7 +1753,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e } // decrypt the frame payload - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsPbLen)], payLen, encKey, dest, fCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsPbLen)], payLen, encKey, dest, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); // decrypt any piggy-backed FOpts if(fOptsPbLen > 0) { @@ -1771,7 +1761,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e if(this->rev == 1) { // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen, this->nwkSEncKey, fOpts, fCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen, this->nwkSEncKey, fOpts, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); } else { // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 2ca4c737f9..b1dc63813e 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -87,7 +87,6 @@ #define RADIOLIB_LORAWAN_RX1_DR_OFFSET (0) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS (5000) #define RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS (6000) -#define RADIOLIB_LORAWAN_MAX_FCNT_GAP (16384) #define RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP (0x06) #define RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP (0x05) #define RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS (1000) From 7305324e9f30b524255788a651f9676ef9af8ca4 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 6 May 2025 14:32:09 +0200 Subject: [PATCH 1533/1848] [LoRaWAN] Fix debug statement --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 855677ec83..342c0c34c4 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1667,7 +1667,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e // assume a rollover if the FCnt16 in the payload is smaller than the previous FCnt16 known by device // (MAX_FCNT_GAP is deprecated for 1.0.4 / 1.1, TTS and CS both apply a 16-bit rollover) if(payFCnt16 < (devFCnt32 & 0xFFFF)) { - Serial.printf("Rollover: %d -> %d\n", payFCnt16, devFCnt32); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rollover: %d -> %d", payFCnt16, devFCnt32); devFCnt32 += 0x10000; // apply rollover } devFCnt32 &= ~0xFFFF; // clear lower 16 bits known by device From 208d619d5b56bde1b84809334635db801f31dcca Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 8 May 2025 00:37:26 +0200 Subject: [PATCH 1534/1848] [Utils] Fix include path --- src/utils/Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 2119f31647..7daa7fdf6d 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -1,5 +1,5 @@ #include "Utils.h" -#include "Hal.h" +#include "../Hal.h" #include #include From 6b985c351648f8a03b5317774af23ee5681a5884 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 8 May 2025 00:39:37 +0200 Subject: [PATCH 1535/1848] [LoRaWAN] Tighten uplink timing --- src/protocols/LoRaWAN/LoRaWAN.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 342c0c34c4..2696e5b464 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -923,11 +923,9 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) // if requested, delay until transmitting JoinRequest RadioLibTime_t tNow = mod->hal->millis(); - if(this->tUplink > tNow) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow)); - if(this->tUplink > mod->hal->millis()) { - this->sleepDelay(this->tUplink - mod->hal->millis()); - } + if(this->tUplink > tNow + this->launchDuration) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow - this->launchDuration)); + this->sleepDelay(this->tUplink - this->launchDuration - mod->hal->millis()); } // start transmission, and time the duration of launchMode() to offset window timing @@ -1341,11 +1339,9 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u // if requested, wait until transmitting uplink tNow = mod->hal->millis(); - if(this->tUplink > tNow) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow)); - if(this->tUplink > mod->hal->millis()) { - this->sleepDelay(this->tUplink - mod->hal->millis()); - } + if(this->tUplink > tNow + this->launchDuration) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow - this->launchDuration)); + this->sleepDelay(this->tUplink - this->launchDuration - mod->hal->millis()); } // start transmission, and time the duration of launchMode() to offset window timing From ac2e743e21256edde060676e8aa2a769f31ab877 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 8 May 2025 00:41:43 +0200 Subject: [PATCH 1536/1848] [LoRaWAN] Prevent possible negative delay --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 2696e5b464..6b6a48f9c5 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -925,7 +925,10 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) RadioLibTime_t tNow = mod->hal->millis(); if(this->tUplink > tNow + this->launchDuration) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow - this->launchDuration)); - this->sleepDelay(this->tUplink - this->launchDuration - mod->hal->millis()); + tNow = mod->hal->millis(); + if(this->tUplink > tNow + this->launchDuration) { + this->sleepDelay(this->tUplink - tNow - this->launchDuration); + } } // start transmission, and time the duration of launchMode() to offset window timing @@ -1341,7 +1344,10 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u tNow = mod->hal->millis(); if(this->tUplink > tNow + this->launchDuration) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow - this->launchDuration)); - this->sleepDelay(this->tUplink - this->launchDuration - mod->hal->millis()); + tNow = mod->hal->millis(); + if(this->tUplink > tNow + this->launchDuration) { + this->sleepDelay(this->tUplink - tNow - this->launchDuration); + } } // start transmission, and time the duration of launchMode() to offset window timing From 5a24ae1ce8b81a5d21fe6b752958cb9854c170a6 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Thu, 8 May 2025 16:51:34 +0200 Subject: [PATCH 1537/1848] Update LoRaWAN examples README --- examples/LoRaWAN/README.md | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index e521567de5..871dbddbba 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -3,35 +3,10 @@ RadioLib LoRaWAN examples. * [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) that come with this example to learn more about LoRaWAN and how to use it in RadioLib! * [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)! -* [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib. +* [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA, this example shows how you can do this using RadioLib. However, to comply with the specification, the full session must persist through resets and power loss - you would need proper NVM for this. Really, we recommend using OTAA. -## LoRaWAN versions & regional parameters -RadioLib implements both LoRaWAN Specification 1.1 and 1.0.4. Confusingly, 1.0.4 is newer than 1.1, but 1.1 includes more security checks and as such **LoRaWAN 1.1 is preferred**. -The catch is in the Regional Parameters: as RP002 1.0.4 is newer than RP001 1.1, it is more up to date regarding local laws & regulations. Therefore, RadioLib implements 1.0.4 as baseline and 1.1 (revision B) as fallback, and as such **RP002 Regional Parameters 1.0.4 is preferred**. -_Note: the CN470 band is implemented as specified in RP001 1.1 revision B, as the RP002 1.0.4 version is much too complex._ +> [!CAUTION] +> These examples are quick wins during development. However, for production devices, you will need to add persistence to your device. See the wiki for more details, or head straight to some [persistence examples](https://github.com/radiolib-org/radiolib-persistence). -To activate a LoRaWAN 1.1 session, supply all the required keys: -```cpp -node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); -node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey); -``` - -To activate a LoRaWAN 1.0.4 session, set the keys that are not available to `NULL`: -```cpp -node.beginOTAA(joinEUI, devEUI, NULL, appKey); -node.beginABP(devAddr, NULL, NULL, nwkSEncKey, appSKey); -``` - -The device doesn't need to know the Regional Parameters version - that is of importance on the console. - -## LoRaWAN persistence -> [!WARNING] -> These examples do not actually comply with LoRaWAN 1.0.4/1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below: - -In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN 1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!** -Currently, examples are available for the following platforms: - -* [LoRaWAN for ESP32](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP32) -* [LoRaWAN for ESP8266](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP8266) - -_This list is last updated at 30/03/2024._ +> [!TIP] +> Refer to the [Wiki](https://github.com/jgromes/RadioLib/wiki/LoRaWAN) for guides and information, for example on LoRaWAN versions, registering your device and more. From 1dae175022b702524479d9f715f5765c8bdc1666 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Thu, 8 May 2025 17:09:31 +0200 Subject: [PATCH 1538/1848] Update LoRaWAN notes --- examples/LoRaWAN/LoRaWAN_Starter/notes.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Starter/notes.md b/examples/LoRaWAN/LoRaWAN_Starter/notes.md index 49a37f845f..9305968ef1 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/notes.md +++ b/examples/LoRaWAN/LoRaWAN_Starter/notes.md @@ -1,10 +1,8 @@ - - # RadioLib LoRaWAN on TTN starter script ## Welcome -These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C coding ninja but some familarity with C and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration. +These notes are for someone who has successfully created a few sketches for their Arduino based device but is starting out with LoRaWAN. You don't have to be a C++ coding ninja but some familarity with C++ and procedural programming is assumed. The absolutely simplest way to get started is to buy some known good hardware that's all done for you so you can concentrate on the code & configuration. ## Introduction @@ -18,7 +16,7 @@ For questions about using RadioLib there is the discussions section (https://git ## Register & setup on TTN -This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Helium does not support LoRaWAN v1.1 which is the version implemented by RadioLib. Chirpstack & other LoRaWAN Network Server (LNS) stacks have not yet been tried so YMMV. +This sketch isn't particularly aimed at The Things Stack (TTS) but you can get a free Sandbox account and the following instructions are for that. Chirpstack works just as well, but the buttons and labels may have different names. We discourage the use of Helium as it does not support LoRaWAN v1.1 and has some other odd limitations. Other LoRaWAN Network Servers (LNS) have not been tested by the developers, so YMMV. Why no screen shots? TTS is a web based app, one that you will need to become familiar with and we will need to direct you to some of the less obvious parts. So much better that you learn the layouts in concept than slavishly follow screen shots that can & will go stale. @@ -52,13 +50,13 @@ You are making your own device using a third party LoRaWAN stack so there will n Choose the Frequency plan appropriate for your region. Consider that almost all countries have laws relating to what frequencies you use so don't get creative. For Europe please use the recommended option. For other regions use the entry marked 'used by TTN'. -Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP001 Regional Parameters 1.1 revision B. +Choose LoRaWAN 1.1.0 - the last one in the list - the latest specfication. RadioLib uses RP002 Regional Parameters 1.0.4. At this point you will be asked for your JoinEUI. As this is a DIY device and we are using RadioLib, you can use all zero's as recommended by The LoRa Alliance TR007 Technical Recommendations document. Once you've put in all zeros and clicked confirm you will be asked for a DevEUI, AppKey and NwkKey. It is preferable to have the console generate them so they are properly formatted. -Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like devicename-01. The you can click the blue 'Register device'. +Your End device ID can be changed to make the device more identifiable. Something related to your hardware helps - like `devicename-01`. The you can click the blue 'Register device'. -When many sensors are big deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do. +When retail sensors are being deployed, a device is registered, batteries put in, it joins and gets on with sending data for the next few years. For development purposes however we need to turn off one of the security settings so that you can join & uplink out of the normal sequence that a device in the field would do. Click on General Settings, scroll down to Join settings, click the Expand button, scroll down and click the 'Resets join nonces' option. You will see a warning about replay attacks which is entirely proper & correct. If anyone eavesdropping in your area on your LoRa transmissions could fake a join and send uplinks from their device but only if they happened to find out your AppKey & NwkKey which is kept securely on the TTN servers and is never transmitted over the air, so they'd also have to login to your account, which is protected by your password. From 4ccc28f18b0d14978bcae6101586bb327bd720f6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 11 May 2025 17:43:08 +0200 Subject: [PATCH 1539/1848] [LoRaWAN] Fix Arduino sendReceive not setting downlink string --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6b6a48f9c5..1445fab9bf 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -28,7 +28,7 @@ int16_t LoRaWANNode::sendReceive(const String& strUp, uint8_t fPort, String& str state = this->sendReceive(reinterpret_cast(dataUp), strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); - if(state == RADIOLIB_ERR_NONE) { + if(state > RADIOLIB_ERR_NONE) { // add null terminator dataDown[lenDown] = '\0'; @@ -157,8 +157,8 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP } // end of transmission & reception - // note: if an error occured, it may still be the case that a transmission occured - // therefore, we act as if a transmission occured before throwing the actual error + // note: if an error occurred, it may still be the case that a transmission occurred + // therefore, we act as if a transmission occurred before throwing the actual error // this feels to be the best way to comply to spec // increase frame counter by one for the next uplink From f00395b5b77e85a72265959e0aaba82d0ff8127d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 15 May 2025 09:21:02 +0200 Subject: [PATCH 1540/1848] [LoRaWAN] Fix Reset and Rekey MAC commands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 34 ++++++++++++------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 1445fab9bf..a5beb1c3b1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -639,6 +639,10 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const u this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; this->lwClass = RADIOLIB_LORAWAN_CLASS_A; + if(this->rev == 1) { + LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + } + return(RADIOLIB_ERR_NONE); } @@ -1927,9 +1931,10 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // get the server version uint8_t srvVersion = optIn[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ResetConf: server version 1.%d", srvVersion); - if(srvVersion == this->rev) { - // valid server version, stop sending the ResetInd MAC command - LoRaWANNode::deleteMacCommand(RADIOLIB_LORAWAN_MAC_RESET, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + if(srvVersion != this->rev) { + // invalid server version, resend the ResetInd MAC command + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ERROR! Please disable your device and consult supported LoRaWAN versions"); + (void)LoRaWANNode::pushMacCommand(cid, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); } return(false); } break; @@ -2314,25 +2319,12 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin uint8_t srvVersion = optIn[0]; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RekeyConf: server version = 1.%d", srvVersion); - // If the server’s version is invalid the device SHALL discard the RekeyConf command and retransmit the RekeyInd in the next uplink frame - if((srvVersion > 0) && (srvVersion <= this->rev)) { - // valid server version, accept - this->rev = srvVersion; - - } else { - // if not a valid server version, retransmit RekeyInd - uint8_t cLen = 0; - this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_UPLINK); - const uint8_t cOcts[1] = { this->rev }; - (void)LoRaWANNode::pushMacCommand(cid, cOcts, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); - - // discard RekeyConf, therefore return false so it doesn't send a reply - return(false); + // If the server's version is invalid the device SHALL discard the RekeyConf command and retransmit the RekeyInd in the next uplink frame + if(srvVersion != this->rev) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ERROR! Please disable your device and consult supported LoRaWAN versions"); + (void)LoRaWANNode::pushMacCommand(cid, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); } - - optOut[0] = this->rev; - - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); + return(false); } break; From 6495247bbfd23f1c894fa87539114009ef4a6bdf Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 May 2025 21:43:59 +0200 Subject: [PATCH 1541/1848] [SX127x] Add emulated Rx single mode (#1496) --- src/modules/SX127x/SX127x.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7b319129c3..d8dfd677fc 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1175,12 +1175,21 @@ RadioLibTime_t SX127x::getTimeOnAir(size_t len) { } RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) { - // the timeout is given as the number of symbols - // the calling function should provide some extra width, as this number of symbols is truncated to integer - // the order of operators is swapped here to decrease the effects of this truncation error - float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - RadioLibTime_t numSymbols = (timeoutUs / symbolLength) / 1000; - return(numSymbols); + RadioLibTime_t timeout = 0; + if(getActiveModem() == RADIOLIB_SX127X_LORA) { + // for LoRa, the timeout is given as the number of symbols + // the calling function should provide some extra width, as this number of symbols is truncated to integer + // the order of operators is swapped here to decrease the effects of this truncation error + float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + timeout = (timeoutUs / symbolLength) / 1000; + + } else { + // for FSK, the timeout is in units of 16x bit time + timeout = ((float)timeoutUs / ((16.0f * 1000.0f) / this->bitRate)); + + } + + return(timeout); } uint32_t SX127x::getIrqFlags() { @@ -1696,10 +1705,15 @@ int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { RADIOLIB_ASSERT(state); } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + // for non-zero timeout value, emulate timeout + state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, cfg->receive.timeout & 0xFF); + RADIOLIB_ASSERT(state); + // clear interrupt flags clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - // FSK modem does not distinguish between Rx single and continuous + // FSK modem does not actually distinguish between Rx single and continuous mode, + // Rx single is emulated using timeout this->rxMode = RADIOLIB_SX127X_RX; } } break; From fff056ced75286753dc3cb23e20edf7f6134bb54 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 28 May 2025 20:24:12 +0200 Subject: [PATCH 1542/1848] [HAL] Make RPi Pico tone helpers static --- src/hal/RPiPico/PicoHal.cpp | 45 +++++++++++++++++++++++++++++++++++++ src/hal/RPiPico/PicoHal.h | 45 +------------------------------------ 2 files changed, 46 insertions(+), 44 deletions(-) create mode 100644 src/hal/RPiPico/PicoHal.cpp diff --git a/src/hal/RPiPico/PicoHal.cpp b/src/hal/RPiPico/PicoHal.cpp new file mode 100644 index 0000000000..754eed7184 --- /dev/null +++ b/src/hal/RPiPico/PicoHal.cpp @@ -0,0 +1,45 @@ +#include "PicoHal.h" + +// pre-calculated pulse-widths for 1200 and 2200Hz +// we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6) +#define SLEEP_1200 416.666 +#define SLEEP_2200 227.272 + +static uint32_t toneLoopPin; +static unsigned int toneLoopFrequency; +static unsigned long toneLoopDuration; + +// === NOTE === +// The tone(...) implementation uses the second core on the RPi Pico. This is to diminish as much +// jitter in the output tones as possible. + +static void toneLoop() { + gpio_set_dir(toneLoopPin, GPIO_OUT); + + uint32_t sleep_dur; + if(toneLoopFrequency == 1200) { + sleep_dur = SLEEP_1200; + } else if(toneLoopFrequency == 2200) { + sleep_dur = SLEEP_2200; + } else { + sleep_dur = 500000 / toneLoopFrequency; + } + + // tone bitbang + while(1) { + gpio_put(toneLoopPin, 1); + sleep_us(sleep_dur); + gpio_put(toneLoopPin, 0); + sleep_us(sleep_dur); + tight_loop_contents(); + } +} + +void PicoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) { + // tones on the Pico are generated using bitbanging. This process is offloaded to the Pico's second core + multicore_reset_core1(); + toneLoopPin = pin; + toneLoopFrequency = frequency; + toneLoopDuration = duration; + multicore_launch_core1(toneLoop); +} diff --git a/src/hal/RPiPico/PicoHal.h b/src/hal/RPiPico/PicoHal.h index ec4d12e33b..f5ba3ef93b 100644 --- a/src/hal/RPiPico/PicoHal.h +++ b/src/hal/RPiPico/PicoHal.h @@ -12,42 +12,6 @@ #include "hardware/clocks.h" #include "pico/multicore.h" -uint32_t toneLoopPin; -unsigned int toneLoopFrequency; -unsigned long toneLoopDuration; - -// pre-calculated pulse-widths for 1200 and 2200Hz -// we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6) -#define SLEEP_1200 416.666 -#define SLEEP_2200 227.272 - -// === NOTE === -// The tone(...) implementation uses the second core on the RPi Pico. This is to diminish as much -// jitter in the output tones as possible. - -void toneLoop(){ - gpio_set_dir(toneLoopPin, GPIO_OUT); - - uint32_t sleep_dur; - if (toneLoopFrequency == 1200) { - sleep_dur = SLEEP_1200; - } else if (toneLoopFrequency == 2200) { - sleep_dur = SLEEP_2200; - } else { - sleep_dur = 500000 / toneLoopFrequency; - } - - - // tone bitbang - while(1){ - gpio_put(toneLoopPin, 1); - sleep_us(sleep_dur); - gpio_put(toneLoopPin, 0); - sleep_us(sleep_dur); - tight_loop_contents(); - } -} - // create a new Raspberry Pi Pico hardware abstraction // layer using the Pico SDK // the HAL must inherit from the base RadioLibHal class @@ -148,14 +112,7 @@ class PicoHal : public RadioLibHal { return (this->micros() - start); } - void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override { - // tones on the Pico are generated using bitbanging. This process is offloaded to the Pico's second core - multicore_reset_core1(); - toneLoopPin = pin; - toneLoopFrequency = frequency; - toneLoopDuration = duration; - multicore_launch_core1(toneLoop); - } + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override; void noTone(uint32_t pin) override { multicore_reset_core1(); From 3b1747a9df7661511ea0cd7af9d8c34dec5f1420 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 May 2025 16:20:47 +0200 Subject: [PATCH 1543/1848] [HAL] Exclude HAL source files from default build --- CMakeLists.txt | 4 ++++ examples/NonArduino/Pico/CMakeLists.txt | 1 + 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index eabfb5d8f4..0d8a55d1a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,10 @@ file(GLOB_RECURSE RADIOLIB_SOURCES "src/*.cpp" ) +# exclude all HAL source files, except the default Arduino HAL +list(FILTER RADIOLIB_SOURCES EXCLUDE REGEX "src/hal/.*\\.cpp") +list(APPEND RADIOLIB_SOURCES "src/hal/Arduino/ArduinoHal.cpp") + add_library(RadioLib ${RADIOLIB_SOURCES}) target_include_directories(RadioLib diff --git a/examples/NonArduino/Pico/CMakeLists.txt b/examples/NonArduino/Pico/CMakeLists.txt index c86122fb7c..36e9c4e4ce 100644 --- a/examples/NonArduino/Pico/CMakeLists.txt +++ b/examples/NonArduino/Pico/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR add_executable(${PROJECT_NAME} main.cpp + "${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib/src/hal/RPiPico/PicoHal.cpp" ) # Pull in common dependencies From 776ab477c4b08f4721788d0ac473d748d0711669 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 May 2025 16:29:50 +0200 Subject: [PATCH 1544/1848] Fix source files globbing for ESP-IDF --- CMakeLists.txt | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d8a55d1a4..1d34a0ea5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,18 @@ cmake_minimum_required(VERSION 3.13) +# first gather the files since this is needed for both ESP-IDF as well as other builds +file(GLOB_RECURSE RADIOLIB_SOURCES + "src/*.cpp" +) + +# exclude all HAL source files, except the default Arduino HAL +list(FILTER RADIOLIB_SOURCES EXCLUDE REGEX "src/hal/.*\\.cpp") +list(APPEND RADIOLIB_SOURCES "src/hal/Arduino/ArduinoHal.cpp") + if(ESP_PLATFORM) # Build RadioLib as an ESP-IDF component # required because ESP-IDF runs cmake in script mode # and needs idf_component_register() - file(GLOB_RECURSE RADIOLIB_ESP_SOURCES - "src/*.*" - ) idf_component_register( SRCS ${RADIOLIB_ESP_SOURCES} @@ -22,14 +28,6 @@ endif() project(radiolib) -file(GLOB_RECURSE RADIOLIB_SOURCES - "src/*.cpp" -) - -# exclude all HAL source files, except the default Arduino HAL -list(FILTER RADIOLIB_SOURCES EXCLUDE REGEX "src/hal/.*\\.cpp") -list(APPEND RADIOLIB_SOURCES "src/hal/Arduino/ArduinoHal.cpp") - add_library(RadioLib ${RADIOLIB_SOURCES}) target_include_directories(RadioLib From d0624f7b85fab6e7d4f6eaa0eda4c6e7fc612666 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 May 2025 17:09:08 +0200 Subject: [PATCH 1545/1848] Fix sources for IDF component --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d34a0ea5a..fa896a9248 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ if(ESP_PLATFORM) # and needs idf_component_register() idf_component_register( - SRCS ${RADIOLIB_ESP_SOURCES} + SRCS ${RADIOLIB_SOURCES} INCLUDE_DIRS . src ) From faa5ab11d2b7beb8fa2d4d2a098f06910740c714 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 May 2025 17:31:27 +0200 Subject: [PATCH 1546/1848] [HAL] Add macro guards to PicoHal --- CMakeLists.txt | 3 +-- examples/NonArduino/Pico/CMakeLists.txt | 2 +- src/hal/RPiPico/PicoHal.cpp | 4 ++++ src/hal/RPiPico/PicoHal.h | 4 ++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa896a9248..b208f79d37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,8 @@ file(GLOB_RECURSE RADIOLIB_SOURCES "src/*.cpp" ) -# exclude all HAL source files, except the default Arduino HAL +# exclude all HAL source files list(FILTER RADIOLIB_SOURCES EXCLUDE REGEX "src/hal/.*\\.cpp") -list(APPEND RADIOLIB_SOURCES "src/hal/Arduino/ArduinoHal.cpp") if(ESP_PLATFORM) # Build RadioLib as an ESP-IDF component diff --git a/examples/NonArduino/Pico/CMakeLists.txt b/examples/NonArduino/Pico/CMakeLists.txt index 36e9c4e4ce..84729dbe50 100644 --- a/examples/NonArduino/Pico/CMakeLists.txt +++ b/examples/NonArduino/Pico/CMakeLists.txt @@ -22,11 +22,11 @@ add_executable(${PROJECT_NAME} main.cpp "${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib/src/hal/RPiPico/PicoHal.cpp" ) +target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_BUILD_RPI_PICO) # Pull in common dependencies target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer pico_multicore hardware_pwm RadioLib) - pico_enable_stdio_usb(${PROJECT_NAME} 1) pico_enable_stdio_uart(${PROJECT_NAME} 0) diff --git a/src/hal/RPiPico/PicoHal.cpp b/src/hal/RPiPico/PicoHal.cpp index 754eed7184..03e6733f39 100644 --- a/src/hal/RPiPico/PicoHal.cpp +++ b/src/hal/RPiPico/PicoHal.cpp @@ -1,5 +1,7 @@ #include "PicoHal.h" +#if defined(RADIOLIB_BUILD_RPI_PICO) + // pre-calculated pulse-widths for 1200 and 2200Hz // we do this to save calculation time (see https://github.com/khoih-prog/RP2040_PWM/issues/6) #define SLEEP_1200 416.666 @@ -43,3 +45,5 @@ void PicoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) toneLoopDuration = duration; multicore_launch_core1(toneLoop); } + +#endif diff --git a/src/hal/RPiPico/PicoHal.h b/src/hal/RPiPico/PicoHal.h index f5ba3ef93b..dfa06f1c93 100644 --- a/src/hal/RPiPico/PicoHal.h +++ b/src/hal/RPiPico/PicoHal.h @@ -1,6 +1,8 @@ #ifndef PICO_HAL_H #define PICO_HAL_H +#if defined(RADIOLIB_BUILD_RPI_PICO) + // include RadioLib #include @@ -153,3 +155,5 @@ class PicoHal : public RadioLibHal { }; #endif + +#endif From 49d340e667f418e2e337c9e1d59d39cc19d21752 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Thu, 29 May 2025 21:08:24 +0200 Subject: [PATCH 1547/1848] [LoRaWAN] Implement Class C (including multicast) (#1504) * [SX126x] Add unified RxContinuous timeout * [SX127x] Add unified RxContinuous timeout * [SX128x] Add unified RxContinuous timeout * [LR11x0] Add unified RxContinuous timeout * [LoRaWAN] Implement Class C * [LoRaWAN] Fix cppcheck issue * [LoRaWAN] Add a few comments * [LoRaWAN] Add a few more comments * [LoRaWAN] Improve debug line * [LoRaWAN] Prohibit class switching before join * [LoRaWAN] Fix Class C downlink details * [LoRaWAN] Implement Class C multicast * Update keywords.txt * [LoRaWAN] Fix error codes in examples * [LoRaWAN] Declare Multicast key arguments `const` * [LoRaWAN] Small fixes for Class C * [LoRaWAN] Small fixes for Class C * [LoRaWAN] Fix Class C feedback --- examples/LoRaWAN/LoRaWAN_ABP/configABP.h | 8 +- examples/LoRaWAN/LoRaWAN_Reference/config.h | 8 +- examples/LoRaWAN/LoRaWAN_Starter/config.h | 8 +- keywords.txt | 7 +- src/TypeDef.h | 8 +- src/modules/LR11x0/LR11x0.cpp | 5 + src/modules/SX126x/SX126x.cpp | 4 + src/modules/SX127x/SX127x.cpp | 4 + src/modules/SX128x/SX128x.cpp | 4 + src/protocols/LoRaWAN/LoRaWAN.cpp | 740 +++++++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 98 ++- 11 files changed, 599 insertions(+), 295 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h index b6c2bfeea4..a19a1dc62d 100644 --- a/examples/LoRaWAN/LoRaWAN_ABP/configABP.h +++ b/examples/LoRaWAN/LoRaWAN_ABP/configABP.h @@ -72,8 +72,8 @@ String stateDecode(const int16_t result) { return "ERR_PACKET_TOO_LONG"; case RADIOLIB_ERR_RX_TIMEOUT: return "ERR_RX_TIMEOUT"; - case RADIOLIB_ERR_CRC_MISMATCH: - return "ERR_CRC_MISMATCH"; + case RADIOLIB_ERR_MIC_MISMATCH: + return "ERR_MIC_MISMATCH"; case RADIOLIB_ERR_INVALID_BANDWIDTH: return "ERR_INVALID_BANDWIDTH"; case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: @@ -104,10 +104,6 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; case RADIOLIB_ERR_JOIN_NONCE_INVALID: return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; - case RADIOLIB_ERR_N_FCNT_DOWN_INVALID: - return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID"; - case RADIOLIB_ERR_A_FCNT_DOWN_INVALID: - return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID"; case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; case RADIOLIB_ERR_CHECKSUM_MISMATCH: diff --git a/examples/LoRaWAN/LoRaWAN_Reference/config.h b/examples/LoRaWAN/LoRaWAN_Reference/config.h index 7512140ca2..5de9cc98a1 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/config.h +++ b/examples/LoRaWAN/LoRaWAN_Reference/config.h @@ -67,8 +67,8 @@ String stateDecode(const int16_t result) { return "ERR_PACKET_TOO_LONG"; case RADIOLIB_ERR_RX_TIMEOUT: return "ERR_RX_TIMEOUT"; - case RADIOLIB_ERR_CRC_MISMATCH: - return "ERR_CRC_MISMATCH"; + case RADIOLIB_ERR_MIC_MISMATCH: + return "ERR_MIC_MISMATCH"; case RADIOLIB_ERR_INVALID_BANDWIDTH: return "ERR_INVALID_BANDWIDTH"; case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: @@ -99,10 +99,6 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; case RADIOLIB_ERR_JOIN_NONCE_INVALID: return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; - case RADIOLIB_ERR_N_FCNT_DOWN_INVALID: - return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID"; - case RADIOLIB_ERR_A_FCNT_DOWN_INVALID: - return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID"; case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; case RADIOLIB_ERR_CHECKSUM_MISMATCH: diff --git a/examples/LoRaWAN/LoRaWAN_Starter/config.h b/examples/LoRaWAN/LoRaWAN_Starter/config.h index 7aa606f1b9..7d025abc21 100644 --- a/examples/LoRaWAN/LoRaWAN_Starter/config.h +++ b/examples/LoRaWAN/LoRaWAN_Starter/config.h @@ -67,8 +67,8 @@ String stateDecode(const int16_t result) { return "ERR_PACKET_TOO_LONG"; case RADIOLIB_ERR_RX_TIMEOUT: return "ERR_RX_TIMEOUT"; - case RADIOLIB_ERR_CRC_MISMATCH: - return "ERR_CRC_MISMATCH"; + case RADIOLIB_ERR_MIC_MISMATCH: + return "ERR_MIC_MISMATCH"; case RADIOLIB_ERR_INVALID_BANDWIDTH: return "ERR_INVALID_BANDWIDTH"; case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: @@ -99,10 +99,6 @@ String stateDecode(const int16_t result) { return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; case RADIOLIB_ERR_JOIN_NONCE_INVALID: return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; - case RADIOLIB_ERR_N_FCNT_DOWN_INVALID: - return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID"; - case RADIOLIB_ERR_A_FCNT_DOWN_INVALID: - return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID"; case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; case RADIOLIB_ERR_CHECKSUM_MISMATCH: diff --git a/keywords.txt b/keywords.txt index e50821bc3d..e65fc66adf 100644 --- a/keywords.txt +++ b/keywords.txt @@ -357,6 +357,9 @@ beginABP KEYWORD2 activateOTAA KEYWORD2 activateABP KEYWORD2 isActivated KEYWORD2 +setClass KEYWORD2 +startMulticastSession KEYWORD2 +stopMulticastSession KEYWORD2 sendReceive KEYWORD2 sendMacCommandReq KEYWORD2 getMacLinkCheckAns KEYWORD2 @@ -489,8 +492,8 @@ RADIOLIB_ERR_UPLINK_UNAVAILABLE LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_FULL LITERAL1 RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND LITERAL1 RADIOLIB_ERR_JOIN_NONCE_INVALID LITERAL1 -RADIOLIB_ERR_N_FCNT_DOWN_INVALID LITERAL1 -RADIOLIB_ERR_A_FCNT_DOWN_INVALID LITERAL1 +RADIOLIB_ERR_MIC_MISMATCH LITERAL1 +RADIOLIB_ERR_MULTICAST_FCNT_INVALID LITERAL1 RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1 RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1 RADIOLIB_ERR_NO_JOIN_ACCEPT LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index a252568564..c9d550f926 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -549,14 +549,14 @@ #define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111) /*! - \brief Received downlink Network frame counter is invalid (lower than last heard value). + \brief The downlink MIC could not be verified (incorrect key or invalid FCnt) */ -#define RADIOLIB_ERR_N_FCNT_DOWN_INVALID (-1112) +#define RADIOLIB_ERR_MIC_MISMATCH (-1112) /*! - \brief Received downlink Application frame counter is invalid (lower than last heard value). + \brief Multicast frame counter is invalid (outside bounds). */ -#define RADIOLIB_ERR_A_FCNT_DOWN_INVALID (-1113) +#define RADIOLIB_ERR_MULTICAST_FCNT_INVALID (-1113) /*! \brief Uplink payload length at this datarate exceeds the active dwell time limitations. diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 711e91a063..95dbde605b 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1977,6 +1977,11 @@ int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled); RADIOLIB_ASSERT(state); } + + // if max(uint32_t) is used, revert to RxContinuous + if(cfg->receive.timeout == 0xFFFFFFFF) { + cfg->receive.timeout = 0xFFFFFF; + } this->rxTimeout = cfg->receive.timeout; } break; diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 2b33642200..4753c0ce96 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1554,6 +1554,10 @@ int16_t SX126x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { state = startReceiveCommon(cfg->receive.timeout, cfg->receive.irqFlags, cfg->receive.irqMask); RADIOLIB_ASSERT(state); + // if max(uint32_t) is used, revert to RxContinuous + if(cfg->receive.timeout == 0xFFFFFFFF) { + cfg->receive.timeout = 0xFFFFFF; + } this->rxTimeout = cfg->receive.timeout; } break; diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index d8dfd677fc..068fcad471 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1671,6 +1671,10 @@ int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { + // if max(uint32_t) is used, revert to RxContinuous + if(cfg->receive.timeout == 0xFFFFFFFF) { + cfg->receive.timeout = 0; + } if(cfg->receive.timeout != 0) { // for non-zero timeout value, change mode to Rx single and set the timeout this->rxMode = RADIOLIB_SX127X_RXSINGLE; diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index e0ddb6a365..4c6d17b7c7 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1426,6 +1426,10 @@ int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled); RADIOLIB_ASSERT(state); } + // if max(uint32_t) is used, revert to RxContinuous + if(cfg->receive.timeout == 0xFFFFFFFF) { + cfg->receive.timeout = 0xFFFF; + } this->rxTimeout = cfg->receive.timeout; } break; diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index a5beb1c3b1..88382e54ea 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -9,7 +9,8 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand) { this->phyLayer = phy; this->band = band; - this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; this->txPowerMax = this->band->powerMax; this->subBand = subBand; memset(this->channelPlan, 0, sizeof(this->channelPlan)); @@ -141,12 +142,13 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP } // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received - state = receiveCommon(RADIOLIB_LORAWAN_DOWNLINK, this->channels, this->rxDelays, 2, this->rxDelayStart); + state = this->receiveDownlink(); // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4) // must be present after any confirmed frame, so we force this here if(isConfirmed) { - this->sleepDelay(this->phyLayer->random(1000, 3000)); + this->sleepDelay(this->phyLayer->random(RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS, + RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS)); } // if an error occured or a downlink was received, stop retransmission @@ -178,6 +180,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP eventUp->fCnt = this->fCntUp; eventUp->fPort = fPort; eventUp->nbTrans = trans; + eventUp->multicast = false; } #if !RADIOLIB_STATIC_ONLY @@ -205,11 +208,16 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // a downlink was received, so we can clear the whole MAC uplink buffer memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); this->fOptsUpLen = 0; - - state = this->parseDownlink(dataDown, lenDown, eventDown); - // return an error code, if any, otherwise return Rx window (which is > 0) + state = this->parseDownlink(dataDown, lenDown, rxWindow, eventDown); RADIOLIB_ASSERT(state); + + // if in Class C, open up RxC window + if(this->lwClass == RADIOLIB_LORAWAN_CLASS_C) { + this->receiveClassC(); + } + + // return Rx window (which is > 0) return(rxWindow); } @@ -227,7 +235,6 @@ uint8_t* LoRaWANNode::getBufferNonces() { // set the device credentials LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION], RADIOLIB_LORAWAN_NONCES_VERSION_VAL); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE], this->lwMode); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CLASS], this->lwClass); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_PLAN], this->band->bandNum); LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_CHECKSUM], this->keyCheckSum); @@ -249,13 +256,12 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) { bool isSameKeys = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_CHECKSUM]) == this->keyCheckSum; bool isSameMode = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_MODE]) == this->lwMode; - bool isSameClass = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_CLASS]) == this->lwClass; bool isSamePlan = LoRaWANNode::ntoh(&persistentBuffer[RADIOLIB_LORAWAN_NONCES_PLAN]) == this->band->bandNum; // check if Nonces buffer matches the current configuration - if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) { + if(!isSameKeys || !isSameMode || !isSamePlan) { // if configuration did not match, discard whatever is currently in the buffers and start fresh - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, plan: %d)", isSameKeys, isSameMode, isSamePlan); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Discarding the Nonces buffer:"); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); return(RADIOLIB_ERR_NONCES_DISCARDED); @@ -298,6 +304,9 @@ void LoRaWANNode::clearSession() { this->maxChanges = 0; this->difsSlots = 0; this->backoffMax = 0; + + // revert to default Class A + this->lwClass = RADIOLIB_LORAWAN_CLASS_A; } void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { @@ -374,8 +383,8 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); - cOcts[0] |= this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr; // may be set by user, otherwise band's default upon initialization - LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq, 3); + cOcts[0] |= this->channels[RADIOLIB_LORAWAN_RX2].dr; // may be set by user, otherwise band's default upon initialization + LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_RX2].freq, 3); (void)execMacCommand(cid, cOcts, cLen); cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; @@ -432,6 +441,7 @@ uint8_t* LoRaWANNode::getBufferSession() { LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN], this->confFCntDown); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFCnt); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS], this->lwClass); // store the enabled channels uint64_t chMaskGrp0123 = 0; @@ -492,7 +502,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { // restore session parameters this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRaWAN session: v1.%d", this->rev); + this->lwClass = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS]); this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); @@ -605,7 +615,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, const uint8_t* } this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA; - this->lwClass = RADIOLIB_LORAWAN_CLASS_A; return(RADIOLIB_ERR_NONE); } @@ -637,7 +646,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const u if(sNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); } this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; - this->lwClass = RADIOLIB_LORAWAN_CLASS_A; if(this->rev == 1) { LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); @@ -751,13 +759,13 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { memcpy(&micBuff[11], joinAcceptMsg, lenRx); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { - return(RADIOLIB_ERR_CRC_MISMATCH); + return(RADIOLIB_ERR_MIC_MISMATCH); } } else { // 1.0 version if(!verifyMIC(joinAcceptMsg, lenRx, this->appKey)) { - return(RADIOLIB_ERR_CRC_MISMATCH); + return(RADIOLIB_ERR_MIC_MISMATCH); } } @@ -772,7 +780,7 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { uint8_t cLen = 0; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = dlSettings & 0x7F; - LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq, 3); + LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_RX2].freq, 3); (void)execMacCommand(cid, cOcts, cLen); cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; @@ -881,9 +889,6 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) return(RADIOLIB_LORAWAN_SESSION_RESTORED); } - int16_t state = RADIOLIB_ERR_UNKNOWN; - Module* mod = this->phyLayer->getMod(); - // starting a new session, so make sure to update event fields already if(joinEvent) { joinEvent->newSession = true; @@ -899,83 +904,27 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->composeJoinRequest(joinRequestMsg); // select a random pair of Tx/Rx channels - state = this->selectChannels(); - RADIOLIB_ASSERT(state); - - // set the physical layer configuration for uplink - state = this->setPhyProperties(&this->channels[RADIOLIB_LORAWAN_UPLINK], - RADIOLIB_LORAWAN_UPLINK, - this->txPowerMax - 2*this->txPowerSteps); - RADIOLIB_ASSERT(state); - - // calculate JoinRequest time-on-air in milliseconds - RadioLibTime_t toa = this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_JOIN_REQUEST_LEN) / 1000; - - if(this->dwellTimeUp) { - if(toa > this->dwellTimeUp) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp); - return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); - } - } - - RadioModeConfig_t modeCfg; - modeCfg.transmit.data = joinRequestMsg; - modeCfg.transmit.len = RADIOLIB_LORAWAN_JOIN_REQUEST_LEN; - modeCfg.transmit.addr = 0; - state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_TX, &modeCfg); + int16_t state = this->selectChannels(); RADIOLIB_ASSERT(state); + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest (DevNonce = %d):", this->devNonce); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); - // if requested, delay until transmitting JoinRequest - RadioLibTime_t tNow = mod->hal->millis(); - if(this->tUplink > tNow + this->launchDuration) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow - this->launchDuration)); - tNow = mod->hal->millis(); - if(this->tUplink > tNow + this->launchDuration) { - this->sleepDelay(this->tUplink - tNow - this->launchDuration); - } - } - - // start transmission, and time the duration of launchMode() to offset window timing - RadioLibTime_t spiStart = mod->hal->millis(); - state = this->phyLayer->launchMode(); - RadioLibTime_t spiEnd = mod->hal->millis(); - this->launchDuration = spiEnd - spiStart; - RADIOLIB_ASSERT(state); - - // sleep for the duration of the transmission - this->sleepDelay(toa); - RadioLibTime_t txEnd = mod->hal->millis(); - - // wait for an additional transmission duration as Tx timeout period - while(!mod->hal->digitalRead(mod->getIrq())) { - // yield for multi-threaded platforms - mod->hal->yield(); - - if(mod->hal->millis() > txEnd + toa) { - return(RADIOLIB_ERR_TX_TIMEOUT); - } - } - state = this->phyLayer->finishTransmit(); - - // set the timestamp so that we can measure when to start receiving - this->rxDelayStart = mod->hal->millis(); + state = this->transmitUplink(&this->channels[RADIOLIB_LORAWAN_UPLINK], + joinRequestMsg, + RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("JoinRequest sent (DevNonce = %d) <-- Rx Delay start", this->devNonce); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN); // JoinRequest successfully sent, so increase & save devNonce this->devNonce += 1; LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); - // set the Time on Air of the JoinRequest - this->lastToA = toa; - // configure Rx1 and Rx2 delay for JoinAccept message - these are re-configured once a valid JoinAccept is received this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; this->rxDelays[2] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received - state = receiveCommon(RADIOLIB_LORAWAN_DOWNLINK, this->channels, this->rxDelays, 2, this->rxDelayStart); + state = this->receiveDownlink(); if(state < RADIOLIB_ERR_NONE) { return(state); } else if (state == RADIOLIB_ERR_NONE) { @@ -1083,6 +1032,91 @@ bool LoRaWANNode::isActivated() { return(this->isActive); } +int16_t LoRaWANNode::setClass(uint8_t cls) { + // only allow switching class once activated + if(!this->isActivated()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // only Class A/B/C exist + if(cls > RADIOLIB_LORAWAN_CLASS_C) { + return(RADIOLIB_ERR_UNSUPPORTED); + } + + // Class B is not implemented + if(cls == RADIOLIB_LORAWAN_CLASS_B) { + return(RADIOLIB_ERR_UNSUPPORTED); + } + + // for LoRaWAN v1.0.4, simply switch class + if(this->rev == 0) { + this->lwClass = cls; + return(RADIOLIB_ERR_NONE); + } + + // for LoRaWAN v1.1, queue the DeviceModeInd MAC command + // it will only switch once DeviceModeConf is received + uint8_t cOct = cls; + int16_t state = LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_MODE, &cOct, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + return(state); +} + +int16_t LoRaWANNode::startMulticastSession(uint8_t cls, uint32_t mcAddr, const uint8_t* mcAppSKey, const uint8_t* mcNwkSKey, uint32_t mcFCntMin, uint32_t mcFCntMax, uint32_t mcFreq, uint8_t mcDr) { + this->multicast = false; + + if(!this->isActivated()) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // currently only possible for Class C + if(cls == RADIOLIB_LORAWAN_CLASS_B) { + return(RADIOLIB_ERR_UNSUPPORTED); + } + + if(mcAppSKey == nullptr || mcNwkSKey == nullptr) { + return(RADIOLIB_ERR_NULL_POINTER); + } + + // check if frequency is within band + if(mcFreq == 0) { + mcFreq = this->channels[RADIOLIB_LORAWAN_RX2].freq * 100; + } + if(mcFreq / 100 < this->band->freqMin || mcFreq / 100 > this->band->freqMax) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + + // check if datarate is defined + if(mcDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + mcDr = this->channels[RADIOLIB_LORAWAN_RX2].dr; + } + if(this->band->dataRates[mcDr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } + + // check the frame counter range + if(mcFCntMin >= mcFCntMax) { + return(RADIOLIB_ERR_MULTICAST_FCNT_INVALID); + } + + // all checks passed, so apply configuration + this->multicast = cls; + this->channels[RADIOLIB_LORAWAN_RX_BC].freq = mcFreq / 100; + this->channels[RADIOLIB_LORAWAN_RX_BC].dr = mcDr; + this->channels[RADIOLIB_LORAWAN_RX_BC].drMin = mcDr; + this->channels[RADIOLIB_LORAWAN_RX_BC].drMax = mcDr; + this->mcAddr = mcAddr; + memcpy(this->mcAppSKey, mcAppSKey, RADIOLIB_AES128_KEY_SIZE); + memcpy(this->mcNwkSKey, mcNwkSKey, RADIOLIB_AES128_KEY_SIZE); + this->mcAFCnt = mcFCntMin; + this->mcAFCntMax = mcFCntMax; + + return(RADIOLIB_ERR_NONE); +} + +void LoRaWANNode::stopMulticastSession() { + this->multicast = false; +} + int16_t LoRaWANNode::isValidUplink(uint8_t* len, uint8_t fPort) { // check destination fPort switch(fPort) { @@ -1242,7 +1276,7 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, if(this->rev == 1) { // in LoRaWAN v1.1, the FOpts are encrypted using the NwkSEncKey - processAES(this->fOptsUp, this->fOptsUpLen, this->nwkSEncKey, &out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x01, true); + processAES(this->fOptsUp, this->fOptsUpLen, this->nwkSEncKey, &out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->devAddr, this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x01, true); } else { // in LoRaWAN v1.0.x, the FOpts are unencrypted memcpy(&out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fOptsUp, this->fOptsUpLen); @@ -1260,7 +1294,7 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, } // encrypt the frame payload - processAES(in, lenIn, encKey, &out[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(this->fOptsUpLen)], this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x00, true); + processAES(in, lenIn, encKey, &out[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(this->fOptsUpLen)], this->devAddr, this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x00, true); } void LoRaWANNode::micUplink(uint8_t* inOut, uint8_t lenInOut) { @@ -1302,12 +1336,6 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u int16_t state = RADIOLIB_ERR_UNKNOWN; Module* mod = this->phyLayer->getMod(); - // check if the Rx windows were closed after sending the previous uplink - if(this->rxDelayEnd < this->rxDelayStart) { - // not enough time elapsed since the last uplink, we may still be in an Rx window - return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); - } - RadioLibTime_t tNow = mod->hal->millis(); // if scheduled uplink time is in the past, reschedule to now if(this->tUplink < tNow) { @@ -1330,6 +1358,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u // check whether dwell time limitation is exceeded RadioLibTime_t toa = this->phyLayer->getTimeOnAir(len) / 1000; + if(this->dwellTimeUp) { if(toa > this->dwellTimeUp) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Dwell time exceeded: ToA = %lu, max = %d", (unsigned long)toa, this->dwellTimeUp); @@ -1397,122 +1426,95 @@ static void LoRaWANNodeOnDownlinkAction(void) { downlinkAction = true; } -int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChannels, const RadioLibTime_t* dlDelays, uint8_t numWindows, RadioLibTime_t tReference) { +int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChannel, uint8_t window, const RadioLibTime_t dlDelay, RadioLibTime_t tReference) { Module* mod = this->phyLayer->getMod(); int16_t state = RADIOLIB_ERR_UNKNOWN; - // check if there are any upcoming Rx windows - // if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1 - RadioLibTime_t now = mod->hal->millis(); // fix the current timestamp to prevent negative delays - if(now > tReference + dlDelays[1] - this->scanGuard) { - // if function was called while Rx windows are in progress, - // wait until last window closes to prevent very bad stuff - if(now < tReference + dlDelays[numWindows]) { - this->sleepDelay(dlDelays[numWindows] + tReference - now); - } - // update the end timestamp in case user got stuck between uplink and downlink - this->rxDelayEnd = mod->hal->millis(); + // either both must be set or none + if((dlDelay == 0 && tReference > 0) || (dlDelay > 0 && tReference == 0)) { return(RADIOLIB_ERR_NO_RX_WINDOW); } - // setup interrupt - this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); + // set the physical layer configuration for downlink + state = this->setPhyProperties(dlChannel, dir, this->txPowerMax - 2*this->txPowerSteps); + RADIOLIB_ASSERT(state); - RadioLibTime_t tOpen = 0; - int16_t timedOut = 0; + // calculate the timeout of an empty packet plus scanGuard + RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + this->scanGuard*1000; - // listen during the specified windows - uint8_t window = 1; - for(; window <= numWindows; window++) { - downlinkAction = false; + // get the maximum allowed Time-on-Air of a packet given the current datarate + uint8_t maxPayLen = this->band->payloadLenMax[dlChannel->dr]; + if(this->TS011) { + maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater + } + RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13) / 1000; // mandatory FHDR is 12/13 bytes - // set the physical layer configuration for downlink - this->phyLayer->standby(); - state = this->setPhyProperties(&dlChannels[window], dir, this->txPowerMax - 2*this->txPowerSteps); - RADIOLIB_ASSERT(state); + // set the radio Rx parameters + RadioModeConfig_t modeCfg; + modeCfg.receive.irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS; + modeCfg.receive.irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; + modeCfg.receive.len = 0; + modeCfg.receive.timeout = this->phyLayer->calculateRxTimeout(timeoutHost); - // calculate the Rx timeout - RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + this->scanGuard*1000; - RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost); - - // TODO remove default arguments - RadioModeConfig_t modeCfg; - modeCfg.receive.timeout = timeoutMod; - modeCfg.receive.irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS; - modeCfg.receive.irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; - modeCfg.receive.len = 0; - state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); - RADIOLIB_ASSERT(state); + state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); + RADIOLIB_ASSERT(state); + // setup interrupt + this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); + downlinkAction = false; + + // if the Rx window must be awaited, do so + RadioLibTime_t tNow = mod->hal->millis(); + if(dlDelay > 0 && tReference > 0) { // calculate time at which the window should open - RadioLibTime_t tWindow = tReference + dlDelays[window]; - // wait for the start of the Rx window launch // - the launch of Rx window takes a few milliseconds, so shorten the waitLen a bit (launchDuration) // - the Rx window is padded using scanGuard, so shorten the waitLen a bit (scanGuard / 2) - RadioLibTime_t waitLen = tWindow - mod->hal->millis() - this->launchDuration - this->scanGuard / 2; - - // make sure that no underflow occured; if so, there's something weird going on so return an error - if(waitLen > dlDelays[window]) { + RadioLibTime_t tWindow = tReference + dlDelay - this->launchDuration - this->scanGuard / 2; + if(tNow > tWindow) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Window too late by %d ms", tNow - tWindow); return(RADIOLIB_ERR_NO_RX_WINDOW); } - this->sleepDelay(waitLen); + this->sleepDelay(tWindow - tNow); + } - // open Rx window by starting receive with specified timeout - state = this->phyLayer->launchMode(); - tOpen = mod->hal->millis(); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); - - // wait for the timeout to complete (and a small delay in case the RxTimeout interrupt needs to fire) - this->sleepDelay(timeoutHost / 1000); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); - while(mod->hal->millis() - tOpen - timeoutHost / 1000 <= this->scanGuard) { - // wait for the DIO interrupt to fire (RxDone or RxTimeout) - if(downlinkAction) { - break; - } - } + // open Rx window by starting receive with specified timeout + state = this->phyLayer->launchMode(); + RadioLibTime_t tOpen = mod->hal->millis(); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); + + // sleep for the duration of the padded Rx window + this->sleepDelay(timeoutHost / 1000); + + // wait for the DIO interrupt to fire (RxDone or RxTimeout) + // use a small additional delay in case the RxTimeout interrupt is slow to fire + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); + while(!downlinkAction && mod->hal->millis() - tOpen <= timeoutHost / 1000 + this->scanGuard) { + mod->hal->yield(); + } - // if the IRQ bit for Rx Timeout is not set, something is received, so stop the windows - timedOut = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); - if(timedOut == RADIOLIB_ERR_UNSUPPORTED) { - return(timedOut); - } - if(!timedOut) { - break; - } + // check IRQ bit for RxTimeout + int16_t timedOut = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); + if(timedOut == RADIOLIB_ERR_UNSUPPORTED) { + return(timedOut); } - // Rx windows are now closed - this->rxDelayEnd = mod->hal->millis(); - // if we got here due to a timeout, stop ongoing activities + // if the IRQ bit for RxTimeout is set, put chip in standby and return if(timedOut) { + this->phyLayer->clearPacketReceivedAction(); this->phyLayer->standby(); - return(RADIOLIB_ERR_NONE); - } - - // get the maximum allowed Time-on-Air of a packet given the current datarate - uint8_t maxPayLen = this->band->payloadLenMax[dlChannels[window].dr]; - if(this->TS011) { - maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater + return(0); // no downlink } - RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13) / 1000; // mandatory FHDR is 12/13 bytes - bool downlinkComplete = true; - // wait for the DIO to fire indicating a downlink is received - while(!downlinkAction) { + // if the IRQ bit for RxTimeout is not set, something is being received, + // so keep listening for maximum ToA waiting for the DIO to fire + while(!downlinkAction && mod->hal->millis() - tOpen < tMax + this->scanGuard) { mod->hal->yield(); - // stay in Rx mode for the maximum allowed Time-on-Air plus small grace period - if(mod->hal->millis() - tOpen > tMax + this->scanGuard) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink missing!"); - downlinkComplete = false; - break; - } } // update time of downlink reception - if(downlinkComplete) { + if(downlinkAction) { this->tDownlink = mod->hal->millis(); } @@ -1520,14 +1522,12 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne this->phyLayer->clearPacketReceivedAction(); this->phyLayer->standby(); - // if all windows passed without receiving anything, set return value to 0 - if(!downlinkComplete) { - state = 0; - - // if we received something during a window, set return value to the window number - } else { - state = window; + // if all windows passed without receiving anything, return 0 for no window + if(!downlinkAction) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink missing!"); + return(0); } + downlinkAction = false; // Any frame received by an end-device containing a MACPayload greater than // the specified maximum length M over the data rate used to receive the frame @@ -1536,10 +1536,144 @@ int16_t LoRaWANNode::receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChanne return(0); // act as if no downlink was received } + // return downlink window number (1/2) + return(window); +} + +int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { + // only open RxC if the device is Unicast-C or Multicast-C, otherwise ignore without error + if(this->lwClass != RADIOLIB_LORAWAN_CLASS_C && this->multicast != RADIOLIB_LORAWAN_CLASS_C) { + return(RADIOLIB_ERR_NONE); + } + Module* mod = this->phyLayer->getMod(); + + RadioLibTime_t tStart = mod->hal->millis(); + + // set the physical layer configuration for Class C window + int16_t state = this->setPhyProperties(&this->channels[RADIOLIB_LORAWAN_RX_BC], RADIOLIB_LORAWAN_DOWNLINK, this->txPowerMax - 2*this->txPowerSteps); + RADIOLIB_ASSERT(state); + + // setup interrupt + this->phyLayer->setPacketReceivedAction(LoRaWANNodeOnDownlinkAction); + downlinkAction = false; + + // configure radio + RadioModeConfig_t modeCfg; + if(timeout) { + timeout -= (mod->hal->millis() - tStart); + timeout -= this->launchDuration; + modeCfg.receive.timeout = this->phyLayer->calculateRxTimeout(timeout * 1000); + } else { + modeCfg.receive.timeout = 0xFFFFFFFF; // max(uint32_t) is used for RxContinuous + } + modeCfg.receive.irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS; + modeCfg.receive.irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; + modeCfg.receive.len = 0; + state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); + RADIOLIB_ASSERT(state); + + // open RxC window by starting receive with specified timeout + state = this->phyLayer->launchMode(); + RadioLibTime_t tOpen = mod->hal->millis(); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened RxC window"); + + if(timeout) { + // wait for the DIO interrupt to fire (RxDone or RxTimeout) + // use a small additional delay in case the RxTimeout interrupt is slow to fire + while(!downlinkAction && mod->hal->millis() - tOpen <= timeout + this->scanGuard) { + mod->hal->yield(); + } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closed RxC window"); + + // check IRQ bit for RxTimeout + int16_t timedOut = this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT); + if(timedOut == RADIOLIB_ERR_UNSUPPORTED) { + return(timedOut); + } + + // if the IRQ bit for RxTimeout is set, put chip in standby and return + if(timedOut) { + this->phyLayer->clearPacketReceivedAction(); + this->phyLayer->standby(); + return(0); // no downlink + } + + // update time of downlink reception + if(downlinkAction) { + this->tDownlink = mod->hal->millis(); + } + + // we have a message, clear actions, go to standby + this->phyLayer->clearPacketReceivedAction(); + this->phyLayer->standby(); + + // if all windows passed without receiving anything, return 0 for no window + if(!downlinkAction) { + return(0); + } + downlinkAction = false; + + // Any frame received by an end-device containing a MACPayload greater than + // the specified maximum length M over the data rate used to receive the frame + // SHALL be silently discarded. + uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_RX_BC].dr]; + if(this->TS011) { + maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater + } + if(this->phyLayer->getPacketLength() > (size_t)(maxPayLen + 13)) { // mandatory FHDR is 12/13 bytes + return(0); // act as if no downlink was received + } + + // return downlink window number (3 = RxC) + return(RADIOLIB_LORAWAN_RX_BC); + } + return(state); } -int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event) { +int16_t LoRaWANNode::receiveDownlink() { + Module* mod = this->phyLayer->getMod(); + + // if applicable, open Class C between uplink and Rx1 + RadioLibTime_t timeoutClassC = this->rxDelayStart + this->rxDelays[RADIOLIB_LORAWAN_RX1] - \ + mod->hal->millis() - 5*this->scanGuard; + int16_t state = this->receiveClassC(timeoutClassC); + RADIOLIB_ASSERT(state); + + // open Rx1 window + state = this->receiveClassA(RADIOLIB_LORAWAN_DOWNLINK, + &this->channels[RADIOLIB_LORAWAN_RX1], + RADIOLIB_LORAWAN_RX1, + this->rxDelays[RADIOLIB_LORAWAN_RX1], + this->rxDelayStart); + RADIOLIB_ASSERT(state); + + // for LoRaWAN v1.1 Class C, there is no Rx2 window: it keeps RxC open uninterrupted + if(this->lwClass == RADIOLIB_LORAWAN_CLASS_C && this->rev == 1) { + state = this->receiveClassC(); + return(state); + } + + // for LoRaWAN v1.0.4 Class C, there is an RxC window between Rx1 and Rx2 + timeoutClassC = this->rxDelayStart + this->rxDelays[RADIOLIB_LORAWAN_RX2] - \ + mod->hal->millis() - 5*this->scanGuard; + state = this->receiveClassC(timeoutClassC); + RADIOLIB_ASSERT(state); + + // open Rx2 window + state = this->receiveClassA(RADIOLIB_LORAWAN_DOWNLINK, + &this->channels[RADIOLIB_LORAWAN_RX2], + RADIOLIB_LORAWAN_RX2, + this->rxDelays[RADIOLIB_LORAWAN_RX2], + this->rxDelayStart); + RADIOLIB_ASSERT(state); + + state = this->receiveClassC(); + return(state); +} + +int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, LoRaWANEvent_t* event) { int16_t state = RADIOLIB_ERR_UNKNOWN; // set user-data length to 0 to prevent undefined behaviour in case of bad use @@ -1581,9 +1715,13 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e // check the address uint32_t addr = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_DEV_ADDR_POS]); - if(addr != this->devAddr) { + uint32_t expectedAddr = this->devAddr; + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + expectedAddr = this->mcAddr; + } + if(addr != expectedAddr) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Device address mismatch, expected 0x%08lX, got 0x%08lX", - (unsigned long)this->devAddr, (unsigned long)addr); + (unsigned long)expectedAddr, (unsigned long)addr); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1612,6 +1750,16 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e switch(fPort) { case RADIOLIB_LORAWAN_FPORT_MAC_COMMAND: { // payload consists of all MAC commands (or is empty) + + // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. + // (...) it SHALL silently discard the entire frame. + // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). + if(window == RADIOLIB_LORAWAN_RX_BC) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } } break; case RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN ... RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX: { // payload is user-defined (or empty) - may carry piggybacked MAC commands @@ -1658,16 +1806,32 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e #endif return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } + + // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. + // (...) it SHALL silently discard the entire frame. + // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). + if(fOptsPbLen > 0 && window == RADIOLIB_LORAWAN_RX_BC) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } // get the frame counter uint32_t payFCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); - // check the FCntDown value (Network or Application) + // check the FCntDown value (Network or Application, or Multicast) uint32_t devFCnt32 = 0; - if (isAppDownlink) { - devFCnt32 = this->aFCntDown; + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + // multicast: McApp downlink counter + devFCnt32 = this->mcAFCnt; } else { - devFCnt32 = this->nFCntDown; + // unicast: App or Nwk downlink + if(isAppDownlink) { + devFCnt32 = this->aFCntDown; + } else { + devFCnt32 = this->nFCntDown; + } } // assume a rollover if the FCnt16 in the payload is smaller than the previous FCnt16 known by device @@ -1676,8 +1840,18 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rollover: %d -> %d", payFCnt16, devFCnt32); devFCnt32 += 0x10000; // apply rollover } - devFCnt32 &= ~0xFFFF; // clear lower 16 bits known by device - devFCnt32 |= payFCnt16; // set lower 16 bits from payload + devFCnt32 &= ~0xFFFF; // clear lower 16 bits known by device + devFCnt32 |= payFCnt16; // set lower 16 bits from payload + + // for multicast, a maximum FCnt value is defined in TS005 + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + if(devFCnt32 > this->mcAFCntMax) { + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_MULTICAST_FCNT_INVALID); + } + } // check if the ACK bit is set, indicating this frame acknowledges the previous uplink bool isConfirmingUp = false; @@ -1694,29 +1868,40 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_CONF_FCNT_POS], (uint16_t)this->confFCntUp); } downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_DOWNLINK; - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], addr); LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], devFCnt32); downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); // check the MIC - // (if a rollover was more than 16-bit, this will always throw CRC mismatch) - if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, this->sNwkSIntKey)) { + // (if a rollover was more than 16-bit, this will always result in MIC mismatch) + uint8_t* micKey = this->sNwkSIntKey; + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + micKey = this->mcNwkSKey; + } + if(!verifyMIC(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen, micKey)) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif - return(RADIOLIB_ERR_CRC_MISMATCH); + return(RADIOLIB_ERR_MIC_MISMATCH); } - // save current fCnt to respective frame counter - if (isAppDownlink) { - this->aFCntDown = devFCnt32; + // save current FCnt to respective frame counter + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + // multicast: McApp downlink + this->mcAFCnt = devFCnt32; } else { - this->nFCntDown = devFCnt32; + // unicast: App or Nwk downlink + if(isAppDownlink) { + this->aFCntDown = devFCnt32; + } else { + this->nFCntDown = devFCnt32; + } } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) encoded:", - isAppDownlink ? "A" : "N", - (unsigned long)(isAppDownlink ? this->aFCntDown : this->nFCntDown)); + (this->multicast && window == RADIOLIB_LORAWAN_RX_BC) ? "M" : + (isAppDownlink ? "A" : "N"), + (unsigned long)devFCnt32); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) @@ -1725,9 +1910,6 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e this->confFCntDown = this->aFCntDown; isConfirmedDown = true; } - - // a downlink was received, so restart the ADR counter with the next uplink - this->adrFCnt = this->getFCntUp() + 1; // if this downlink is on FPort 0, the FOptsLen is the length of the payload // in any other case, the payload (length) is user accessible @@ -1754,20 +1936,49 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e // figure out which key to use to decrypt the payload uint8_t* encKey = this->appSKey; - if((fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) || (fPort == RADIOLIB_LORAWAN_FPORT_TS011)) { + if((fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) || (fPort == RADIOLIB_LORAWAN_FPORT_TS011)) { encKey = this->nwkSEncKey; } + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + encKey = this->mcAppSKey; + } // decrypt the frame payload - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsPbLen)], payLen, encKey, dest, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsPbLen)], payLen, encKey, dest, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + // pass the event info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_DOWNLINK; + event->confirmed = isConfirmedDown; + event->confirming = isConfirmingUp; + event->frmPending = (downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING) != 0; + event->datarate = this->channels[window].dr; + event->freq = this->channels[window].freq / 10000.0; + event->power = this->txPowerMax - this->txPowerSteps * 2; + event->fCnt = devFCnt32; + event->fPort = fPort; + event->multicast = (bool)this->multicast; + } + + // for RxBC downlinks, return already, we aren't allowed to do any FOpts stuff + if(window == RADIOLIB_LORAWAN_RX_BC) { + #if !RADIOLIB_STATIC_ONLY + delete[] fOpts; + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_NONE); + } + + // a downlink was received, so restart the ADR counter with the next uplink + this->adrFCnt = this->getFCntUp() + 1; + // decrypt any piggy-backed FOpts if(fOptsPbLen > 0) { // the decryption depends on the LoRaWAN version if(this->rev == 1) { // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen, this->nwkSEncKey, fOpts, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen, this->nwkSEncKey, fOpts, this->devAddr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); } else { // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen); @@ -1891,19 +2102,6 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e this->fOptsUpLen = fOptsReLen; } - // pass the extra info if requested - if(event) { - event->dir = RADIOLIB_LORAWAN_DOWNLINK; - event->confirmed = isConfirmedDown; - event->confirming = isConfirmingUp; - event->frmPending = (downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING) != 0; - event->datarate = this->channels[RADIOLIB_LORAWAN_DOWNLINK].dr; - event->freq = channels[event->dir].freq / 10000.0; - event->power = this->txPowerMax - this->txPowerSteps * 2; - event->fCnt = isAppDownlink ? this->aFCntDown : this->nFCntDown; - event->fPort = fPort; - } - #if !RADIOLIB_STATIC_ONLY delete[] fOpts; delete[] downlinkMsg; @@ -1912,6 +2110,38 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* e return(RADIOLIB_ERR_NONE); } +int16_t LoRaWANNode::getDownlinkClassC(uint8_t* dataDown, size_t* lenDown, LoRaWANEvent_t* eventDown) { + // only allow if the device is Unicast-C or Multicast-C, otherwise ignore without error + if(this->lwClass != RADIOLIB_LORAWAN_CLASS_C && this->multicast != RADIOLIB_LORAWAN_CLASS_C) { + return(RADIOLIB_ERR_NONE); + } + + int16_t state = RADIOLIB_ERR_NONE; + + if(downlinkAction) { + state = this->parseDownlink(dataDown, lenDown, RADIOLIB_LORAWAN_RX_BC, eventDown); + downlinkAction = false; + + // if downlink parsed successfully, set state to RxC window + if(state == RADIOLIB_ERR_NONE) { + state = RADIOLIB_LORAWAN_RX_BC; + + // otherwise, if device is acting as Multicast on top of the same Unicast class, + // try decrypting it as a Unicast downlink by temporarily disabling Multicast + } else if(this->multicast == this->lwClass) { + this->multicast = false; + state = this->parseDownlink(dataDown, lenDown, RADIOLIB_LORAWAN_RX_BC, eventDown); + this->multicast = this->lwClass; + // if downlink parsed succesfully, set state to RxC window + if(state == RADIOLIB_ERR_NONE) { + state = RADIOLIB_LORAWAN_RX_BC; + } + } + } + + return(state); +} + bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn) { uint8_t buff[RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN]; return(this->execMacCommand(cid, optIn, lenIn, buff)); @@ -2133,8 +2363,10 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // passed ACK, so apply configuration this->rx1DrOffset = macRx1DrOffset; - this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr = macRx2Dr; - this->channels[RADIOLIB_LORAWAN_DIR_RX2].freq = macRx2Freq; + this->channels[RADIOLIB_LORAWAN_RX2].dr = macRx2Dr; + this->channels[RADIOLIB_LORAWAN_RX2].freq = macRx2Freq; + this->channels[RADIOLIB_LORAWAN_RX_BC].dr = macRx2Dr; + this->channels[RADIOLIB_LORAWAN_RX_BC].freq = macRx2Freq; memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP], optIn, lenIn); return(true); @@ -2375,6 +2607,26 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin return(true); } break; + case(RADIOLIB_LORAWAN_MAC_DEVICE_MODE): { + // only implemented on LoRaWAN v1.1 + if(this->rev == 0) { + return(false); + } + + if(optIn[0] > RADIOLIB_LORAWAN_CLASS_C) { + return(false); + } + + // retrieve pending class from MAC uplink queue + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DeviceMode: Switching to LoRaWAN Class %s", + optIn[0] == RADIOLIB_LORAWAN_CLASS_A ? "A" : + optIn[0] == RADIOLIB_LORAWAN_CLASS_B ? "B" : "C"); + + this->lwClass = optIn[0]; + + return(false); + } break; + default: { // derived classes may implement additional MAC commands return(derivedMacHandler(cid, optIn, lenIn, optOut)); @@ -2770,7 +3022,8 @@ int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { RADIOLIB_ASSERT(state); // passed all checks, so configure the datarate - this->channels[RADIOLIB_LORAWAN_DIR_RX2].dr = dr; + this->channels[RADIOLIB_LORAWAN_RX2].dr = dr; + this->channels[RADIOLIB_LORAWAN_RX_BC].dr = dr; return(state); } @@ -2856,12 +3109,7 @@ RadioLibTime_t LoRaWANNode::getLastToA() { } int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, int8_t pwr, size_t pre) { - // set the physical layer configuration - int16_t state = this->phyLayer->standby(); - if(state != RADIOLIB_ERR_NONE) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Failed to set radio into standby - is it connected?"); - return(state); - } + int16_t state = RADIOLIB_ERR_NONE; // get the currently configured modem from the radio ModemType_t modem; @@ -3081,7 +3329,8 @@ void LoRaWANNode::selectChannelPlanDyn() { } // make sure the Rx2 settings are back to this band's default - this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; // make all enabled channels available for uplink selection this->setAvailableChannels(0xFFFF); @@ -3110,7 +3359,8 @@ void LoRaWANNode::selectChannelPlanFix() { this->applyChannelMask(chMaskGrp0123, chMaskGrp45); // make sure the Rx2 settings are back to this band's default - this->channels[RADIOLIB_LORAWAN_DIR_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; // make all enabled channels available for uplink selection this->setAvailableChannels(0xFFFF); @@ -3184,7 +3434,7 @@ int16_t LoRaWANNode::selectChannels() { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { // for dynamic bands, the downlink channel is the one matched to the uplink channel - this->channels[RADIOLIB_LORAWAN_DOWNLINK] = this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][chIdx]; + this->channels[RADIOLIB_LORAWAN_RX1] = this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][chIdx]; } else { // RADIOLIB_LORAWAN_BAND_FIXED // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels @@ -3194,7 +3444,7 @@ int16_t LoRaWANNode::selectChannels() { channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; channelDn.drMin = this->band->rx1Span.drMin; channelDn.drMax = this->band->rx1Span.drMax; - this->channels[RADIOLIB_LORAWAN_DOWNLINK] = channelDn; + this->channels[RADIOLIB_LORAWAN_RX1] = channelDn; } uint8_t rx1Dr = this->band->rx1DrTable[currentDr][this->rx1DrOffset]; @@ -3204,7 +3454,7 @@ int16_t LoRaWANNode::selectChannels() { if(this->dwellTimeDn && rx1Dr < 2) { rx1Dr = 2; } - this->channels[RADIOLIB_LORAWAN_DOWNLINK].dr = rx1Dr; + this->channels[RADIOLIB_LORAWAN_RX1].dr = rx1Dr; return(RADIOLIB_ERR_NONE); } @@ -3383,11 +3633,7 @@ void LoRaWANNode::setSleepFunction(SleepCb_t cb) { } int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { - int16_t state = this->phyLayer->standby(); - if(state != RADIOLIB_ERR_NONE) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Failed to set radio into standby - is it connected?"); - return(state); - } + int16_t state = RADIOLIB_ERR_NONE; ModemType_t modemNew; @@ -3457,6 +3703,8 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { // if the required modem is different than the current one, change over if(modemNew != modemCurrent) { + state = this->phyLayer->standby(); + RADIOLIB_ASSERT(state); state = this->phyLayer->setModem(modemNew); RADIOLIB_ASSERT(state); } @@ -3465,7 +3713,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { return(state); } -void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { +void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t addr, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; if(len % RADIOLIB_AES128_BLOCK_SIZE) { @@ -3478,7 +3726,7 @@ void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_ encBlock[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_ENC_BLOCK_MAGIC; encBlock[RADIOLIB_LORAWAN_ENC_BLOCK_COUNTER_ID_POS] = ctrId; encBlock[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = dir; - LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], this->devAddr); + LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], addr); LoRaWANNode::hton(&encBlock[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], fCnt); // now encrypt the input diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index b1dc63813e..35ddf1da61 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -11,9 +11,9 @@ #define RADIOLIB_LORAWAN_MODE_NONE (0x0000) // operation mode -#define RADIOLIB_LORAWAN_CLASS_A (0x0A) -#define RADIOLIB_LORAWAN_CLASS_B (0x0B) -#define RADIOLIB_LORAWAN_CLASS_C (0x0C) +#define RADIOLIB_LORAWAN_CLASS_A (0x00) +#define RADIOLIB_LORAWAN_CLASS_B (0x01) +#define RADIOLIB_LORAWAN_CLASS_C (0x02) // preamble format #define RADIOLIB_LORAWAN_LORA_SYNC_WORD (0x34) @@ -73,9 +73,11 @@ #define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate // channels and channel plans -#define RADIOLIB_LORAWAN_UPLINK (0x00 << 0) -#define RADIOLIB_LORAWAN_DOWNLINK (0x01 << 0) -#define RADIOLIB_LORAWAN_DIR_RX2 (0x02 << 0) +#define RADIOLIB_LORAWAN_UPLINK (0x00 << 0) +#define RADIOLIB_LORAWAN_DOWNLINK (0x01 << 0) +#define RADIOLIB_LORAWAN_RX1 (0x01 << 0) +#define RADIOLIB_LORAWAN_RX2 (0x02 << 0) +#define RADIOLIB_LORAWAN_RX_BC (0x03 << 0) #define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) #define RADIOLIB_LORAWAN_BAND_FIXED (1) #define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) @@ -177,7 +179,7 @@ #define RADIOLIB_LORAWAN_MAX_CHANGES_DEFAULT (4) // MAC commands -#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (23) +#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (24) #define RADIOLIB_LORAWAN_MAC_RESET (0x01) #define RADIOLIB_LORAWAN_MAC_LINK_CHECK (0x02) @@ -194,6 +196,7 @@ #define RADIOLIB_LORAWAN_MAC_DEVICE_TIME (0x0D) #define RADIOLIB_LORAWAN_MAC_FORCE_REJOIN (0x0E) #define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) +#define RADIOLIB_LORAWAN_MAC_DEVICE_MODE (0x20) #define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) // the length of internal MAC command queue - hopefully this is enough for most use cases @@ -251,6 +254,7 @@ constexpr LoRaWANMacCommand_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS] = { { RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, false, true }, { RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false, false }, { RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false, false }, + { RADIOLIB_LORAWAN_MAC_DEVICE_MODE, 1, 1, true, false }, { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, false, true }, }; @@ -260,8 +264,7 @@ enum LoRaWANSchemeBase_t { RADIOLIB_LORAWAN_NONCES_START = 0x00, RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes - RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte - RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte + RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes @@ -288,7 +291,8 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte - RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 14 bytes + RADIOLIB_LORAWAN_SESSION_CLASS = RADIOLIB_LORAWAN_SESSION_VERSION + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_CLASS + sizeof(uint8_t), // 14 bytes RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_LINK_ADR + 14, // 1 byte RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + 1, // 4 bytes RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + 4, // 1 byte @@ -517,6 +521,9 @@ struct LoRaWANEvent_t { /*! \brief Number of times this uplink was transmitted (ADR)*/ uint8_t nbTrans; + + /*! \brief Multicast or unicast */ + bool multicast; }; /*! @@ -606,6 +613,26 @@ class LoRaWANNode { /*! \brief Whether there is an ongoing session active */ bool isActivated(); + /*! \brief Configure class (RADIOLIB_LORAWAN_CLASS_A or RADIOLIB_LORAWAN_CLASS_C) */ + int16_t setClass(uint8_t cls); + + /*! + \brief Start a Multicast session. + \param cls The LoRaWAN Class used for this session (only C is supported). + \param mcAddr The Multicast address. + \param mcAppSKey The Multicast payload encryption key. + \param mcNwkSKey The Multicast payload integrity key. + \param mcFCntMin The minimum expected Multicast frame counter. + \param mcFCntMin The maximum allowed Multicast frame counter. + \param mcFreq The frequency used for the Multicast downlinks (in Hz). Default = 0 uses Rx2 frequency. + \param mcDr The datarate used for the Multicast downlinks. Default = 0 uses Rx2 datarate. + \returns \ref status_codes + */ + int16_t startMulticastSession(uint8_t cls, uint32_t mcAddr, const uint8_t* mcAppSKey, const uint8_t* mcNwkSKey, uint32_t mcFCntMin = 0, uint32_t mcFCntMax = 0xFFFFFFFF, uint32_t mcFreq = 0, uint8_t mcDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + + /*! \brief Stop an ongoing multicast session */ + void stopMulticastSession(); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Send a message to the server and wait for a downlink during Rx1 and/or Rx2 window. @@ -680,6 +707,16 @@ class LoRaWANNode { */ virtual int16_t sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed = false, LoRaWANEvent_t* eventUp = NULL, LoRaWANEvent_t* eventDown = NULL); + /*! + \brief Check if there is an RxC downlink and parse it if available. + \param dataDown Buffer to save received data into. + \param lenDown Pointer to variable that will be used to save the number of received bytes. + \param eventDown Pointer to a structure to store extra information about the downlink event + (fPort, frame counter, etc.). If set to NULL, no extra information will be passed to the user. + \returns Window number > 0 if downlink was received, 0 is no downlink was received, otherwise \ref status_codes + */ + int16_t getDownlinkClassC(uint8_t* dataDown, size_t* lenDown, LoRaWANEvent_t* eventDown = NULL); + /*! \brief Add a MAC command to the uplink queue. Only LinkCheck and DeviceTime are available to the user. @@ -935,6 +972,14 @@ class LoRaWANNode { RadioLibTime_t tUplink = 0; // scheduled uplink transmission time (internal clock) RadioLibTime_t tDownlink = 0; // time at end of downlink reception + // multicast parameters + uint8_t multicast = false; + uint32_t mcAddr = 0; + uint8_t mcAppSKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint8_t mcNwkSKey[RADIOLIB_AES128_KEY_SIZE] = { 0 }; + uint32_t mcAFCnt = 0; + uint32_t mcAFCntMax = 0; + // enable/disable CSMA for LoRaWAN bool csmaEnabled = false; @@ -946,21 +991,21 @@ class LoRaWANNode { // process at the same time. uint8_t backoffMax = RADIOLIB_LORAWAN_BACKOFF_MAX_DEFAULT; - // number of CADs to estimate a clear CH + // number of CADs to estimate a clear channel uint8_t difsSlots = RADIOLIB_LORAWAN_DIFS_DEFAULT; // available channel frequencies from list passed during OTA activation LoRaWANChannel_t channelPlan[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; - // currently configured channels for TX, RX1, RX2 - LoRaWANChannel_t channels[3] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, - RADIOLIB_LORAWAN_CHANNEL_NONE }; + // currently configured channels for Tx, Rx1, Rx2, RxBC + LoRaWANChannel_t channels[4] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, + RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; - // delays between the uplink and RX1/2 windows + // delays between the uplink and Rx1/2 windows // the first field is meaningless, but is used for offsetting for Rx windows 1 and 2 RadioLibTime_t rxDelays[3] = { 0, RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; - // offset between TX and RX1 (such that RX1 has equal or lower DR) + // offset between Tx and Rx1 (such that Rx1 has equal or lower DR) uint8_t rx1DrOffset = 0; // LoRaWAN revision (1.0 vs 1.1) @@ -969,12 +1014,9 @@ class LoRaWANNode { // Time on Air of last uplink RadioLibTime_t lastToA = 0; - // timestamp to measure the RX1/2 delay (from uplink end) + // timestamp to measure the Rx1/2 delay (from uplink end) RadioLibTime_t rxDelayStart = 0; - // timestamp when the Rx1/2 windows were closed (timeout or uplink received) - RadioLibTime_t rxDelayEnd = 0; - // duration of SPI transaction for phyLayer->launchMode() RadioLibTime_t launchDuration = 0; @@ -1020,13 +1062,19 @@ class LoRaWANNode { void micUplink(uint8_t* inOut, uint8_t lenInOut); // transmit uplink buffer on a specified channel - int16_t transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans); + int16_t transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans = false); + + // handle one of the Class A receive windows with a given channel and certain timestamps + int16_t receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChannel, uint8_t window, const RadioLibTime_t dlDelay, RadioLibTime_t tReference); + + // handle a Class C receive window with timeout (between Class A windows) or without (between uplinks) + int16_t receiveClassC(RadioLibTime_t timeout = 0); - // wait for, open and listen during receive windows; only performs listening - int16_t receiveCommon(uint8_t dir, const LoRaWANChannel_t* dlChannels, const RadioLibTime_t* dlDelays, uint8_t numWindows, RadioLibTime_t tReference); + // open a series of Class A (and C) downlinks + int16_t receiveDownlink(); // extract downlink payload and process MAC commands - int16_t parseDownlink(uint8_t* data, size_t* len, LoRaWANEvent_t* event = NULL); + int16_t parseDownlink(uint8_t* data, size_t* len, uint8_t window, LoRaWANEvent_t* event = NULL); // execute mac command, return the number of processed bytes for sequential processing bool execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn); @@ -1119,7 +1167,7 @@ class LoRaWANNode { int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); // function to encrypt and decrypt payloads (regular uplink/downlink) - void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); + void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t addr, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); // function that allows sleeping via user-provided callback void sleepDelay(RadioLibTime_t ms); From 06af9a8f7f1f29d8106528ca12b37886e69e5c7e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 May 2025 10:36:37 +0200 Subject: [PATCH 1548/1848] [LoRaWAN] Do not use range in switch case --- src/protocols/LoRaWAN/LoRaWAN.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 88382e54ea..045e156d27 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1128,9 +1128,6 @@ int16_t LoRaWANNode::isValidUplink(uint8_t* len, uint8_t fPort) { // if this is MAC only payload, continue and reset for next uplink this->isMACPayload = false; } break; - case RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN ... RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX: { - // all good - } break; case RADIOLIB_LORAWAN_FPORT_TS009: { // TS009 FPort only good if overruled during verification testing if(!this->TS009) { @@ -1146,6 +1143,10 @@ int16_t LoRaWANNode::isValidUplink(uint8_t* len, uint8_t fPort) { } } break; default: { + if((fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN) && (fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX)) { + // user payload ports, all good + break; + } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is reserved.", fPort); } break; } @@ -1761,10 +1762,6 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } } break; - case RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN ... RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX: { - // payload is user-defined (or empty) - may carry piggybacked MAC commands - isAppDownlink = true; - } break; case RADIOLIB_LORAWAN_FPORT_TS009: { // TS009 FPort only good if overruled during verification testing if(!this->TS009) { @@ -1788,6 +1785,11 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L isAppDownlink = true; } break; default: { + if((fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN) && (fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX)) { + // payload is user-defined (or empty) - may carry piggybacked MAC commands + isAppDownlink = true; + break; + } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is reserved.", fPort); #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; From 6430fa5e383d3566a4660010afddebca781f0950 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 May 2025 09:54:23 +0100 Subject: [PATCH 1549/1848] [LR11x0] Split source into multiple files --- src/modules/LR11x0/LR11x0.cpp | 2072 +----------------------- src/modules/LR11x0/LR11x0_commands.cpp | 845 ++++++++++ src/modules/LR11x0/LR11x0_crypto.cpp | 231 +++ src/modules/LR11x0/LR11x0_gnss.cpp | 757 +++++++++ src/modules/LR11x0/LR11x0_wifi.cpp | 267 +++ 5 files changed, 2101 insertions(+), 2071 deletions(-) create mode 100644 src/modules/LR11x0/LR11x0_commands.cpp create mode 100644 src/modules/LR11x0/LR11x0_crypto.cpp create mode 100644 src/modules/LR11x0/LR11x0_gnss.cpp create mode 100644 src/modules/LR11x0/LR11x0_wifi.cpp diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 95dbde605b..cd8ecfd85c 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1,10 +1,7 @@ #include "LR11x0.h" -#include "../../utils/CRC.h" -#include "../../utils/Cryptography.h" - -#include #include +#include #if !RADIOLIB_EXCLUDE_LR11X0 @@ -1437,169 +1434,6 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16 return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { - // LR1121 cannot do WiFi scanning - if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) { - return(RADIOLIB_ERR_UNSUPPORTED); - } - - uint8_t type; - switch(wifiType) { - case('b'): - type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_B; - break; - case('g'): - type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_G; - break; - case('n'): - type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_N; - break; - case('*'): - type = RADIOLIB_LR11X0_WIFI_SCAN_ALL; - break; - default: - return(RADIOLIB_ERR_INVALID_WIFI_TYPE); - } - - // go to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // reset cumulative timings - state = wifiResetCumulTimings(); - RADIOLIB_ASSERT(state); - - // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE); - RADIOLIB_ASSERT(state); - - // start scan with the maximum number of results and abort on timeout - this->wifiScanMode = mode; - state = wifiScan(type, chanMask, this->wifiScanMode, RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS, numScans, timeout, RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED); - return(state); -} - -void LR11x0::setWiFiScanAction(void (*func)(void)) { - this->setIrqAction(func); -} - -void LR11x0::clearWiFiScanAction() { - this->clearIrqAction(); -} - -int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) { - // clear IRQ first, as this is likely to be called right after scan has finished - int16_t state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); - RADIOLIB_ASSERT(state); - - uint8_t buff[1] = { 0 }; - state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff)); - - // pass the replies - if(count) { *count = buff[0]; } - - return(state); -} - -int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) { - RADIOLIB_ASSERT_PTR(result); - - // read a single result - uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE; - uint8_t raw[RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN] = { 0 }; - int16_t state = wifiReadResults(index, 1, format, raw); - RADIOLIB_ASSERT(state); - - // parse the information - switch(raw[0] & 0x03) { - case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_B): - result->type = 'b'; - break; - case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_G): - result->type = 'g'; - break; - case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_N): - result->type = 'n'; - break; - } - result->dataRateId = (raw[0] & 0xFC) >> 2; - result->channelFreq = 2407 + (raw[1] & 0x0F)*5; - result->origin = (raw[1] & 0x30) >> 4; - result->ap = (raw[1] & 0x40) != 0; - result->rssi = (float)raw[2] / -2.0f;; - memcpy(result->mac, &raw[3], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); - - if(!brief) { - if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) { - LR11x0WifiResultExtended_t* resultExtended = reinterpret_cast(result); - resultExtended->rate = raw[3]; - resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5])); - resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7])); - resultExtended->frameType = raw[9] & 0x03; - resultExtended->frameSubType = (raw[9] & 0x3C) >> 2; - resultExtended->toDistributionSystem = (raw[9] & 0x40) != 0; - resultExtended->fromDistributionSystem = (raw[9] & 0x80) != 0; - memcpy(resultExtended->mac0, &raw[10], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); - memcpy(resultExtended->mac, &raw[16], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); - memcpy(resultExtended->mac2, &raw[22], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); - resultExtended->timestamp = (((uint64_t)raw[28] << 56) | ((uint64_t)raw[29] << 48)) | - (((uint64_t)raw[30] << 40) | ((uint64_t)raw[31] << 32)) | - (((uint64_t)raw[32] << 24) | ((uint64_t)raw[33] << 16)) | - (((uint64_t)raw[34] << 8) | (uint64_t)raw[35]); - resultExtended->periodBeacon = (((uint16_t)raw[36] << 8) | ((uint16_t)raw[37])) * 1024UL; - resultExtended->seqCtrl = (((uint16_t)raw[38] << 8) | ((uint16_t)raw[39])); - memcpy(resultExtended->ssid, &raw[40], RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN); - resultExtended->currentChannel = raw[72]; - memcpy(resultExtended->countryCode, &raw[73], 2); - resultExtended->countryCode[2] = '\0'; - resultExtended->ioReg = raw[75]; - resultExtended->fcsCheckOk = (raw[76] != 0); - resultExtended->phiOffset = (((uint16_t)raw[77] << 8) | ((uint16_t)raw[78])); - return(RADIOLIB_ERR_NONE); - } - - LR11x0WifiResultFull_t* resultFull = reinterpret_cast(result); - resultFull->frameType = raw[3] & 0x03; - resultFull->frameSubType = (raw[3] & 0x3C) >> 2; - resultFull->toDistributionSystem = (raw[3] & 0x40) != 0; - resultFull->fromDistributionSystem = (raw[3] & 0x80) != 0; - memcpy(resultFull->mac, &raw[4], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); - resultFull->phiOffset = (((uint16_t)raw[10] << 8) | ((uint16_t)raw[11])); - resultFull->timestamp = (((uint64_t)raw[12] << 56) | ((uint64_t)raw[13] << 48)) | - (((uint64_t)raw[14] << 40) | ((uint64_t)raw[15] << 32)) | - (((uint64_t)raw[16] << 24) | ((uint64_t)raw[17] << 16)) | - (((uint64_t)raw[18] << 8) | (uint64_t)raw[19]); - resultFull->periodBeacon = (((uint16_t)raw[20] << 8) | ((uint16_t)raw[21])) * 1024UL; - } - - return(RADIOLIB_ERR_NONE); -} - -int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { - RADIOLIB_ASSERT_PTR(count); - - // start scan - RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start"); - int16_t state = startWifiScan(wifiType, mode, chanMask, numScans, timeout); - RADIOLIB_ASSERT(state); - - // wait for scan finished or timeout - RadioLibTime_t softTimeout = 30UL * 1000UL; - RadioLibTime_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start > softTimeout) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); - this->standby(); - return(RADIOLIB_ERR_RX_TIMEOUT); - } - } - RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); - - // read number of results - return(getWifiScanResultsCount(count)); -} - int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) { RADIOLIB_ASSERT_PTR(info); @@ -1678,253 +1512,6 @@ int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolat return(state); } -int16_t LR11x0::isGnssScanCapable() { - // get the version - LR11x0VersionInfo_t version; - int16_t state = this->getVersionInfo(&version); - RADIOLIB_ASSERT(state); - - // check the device firmware version is sufficient - uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; - state = RADIOLIB_ERR_UNSUPPORTED; - if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { - state = RADIOLIB_ERR_NONE; - } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { - state = RADIOLIB_ERR_NONE; - } - RADIOLIB_ASSERT(state); - - // in debug mode, dump the almanac - #if RADIOLIB_DEBUG_PROTOCOL - uint32_t addr = 0; - uint16_t sz = 0; - state = this->gnssAlmanacReadAddrSize(&addr, &sz); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz); - uint32_t buff[32] = { 0 }; - while(sz > 0) { - size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); - state = this->readRegMem32(addr, buff, len); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_HEXDUMP(NULL, reinterpret_cast(buff), len*sizeof(uint32_t), addr); - addr += len*sizeof(uint32_t); - sz -= len*sizeof(uint32_t); - } - - uint8_t almanac[22] = { 0 }; - for(uint8_t i = 0; i < 128; i++) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i); - state = this->gnssAlmanacReadSV(i, almanac); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_HEXDUMP(NULL, almanac, 22); - } - - #endif - - return(state); -} - -int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) { - RADIOLIB_ASSERT_PTR(res); - - // go to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set DIO mapping - state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT); - RADIOLIB_ASSERT(state); - - // set scan mode (single vs multiple) - state = this->gnssSetMode(0x03); - RADIOLIB_ASSERT(state); - - // set RF switch - this->mod->setRfSwitchState(LR11x0::MODE_GNSS); - - // start scan with high effort - RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start"); - state = this->gnssPerformScan(RADIOLIB_LR11X0_GNSS_EFFORT_MID, 0x3C, 16); - RADIOLIB_ASSERT(state); - - // wait for scan finished or timeout - // this can take very long if both GPS and BeiDou are enabled - RadioLibTime_t softTimeout = 300UL * 1000UL; - RadioLibTime_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start > softTimeout) { - this->gnssAbort(); - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); - } - } - - // restore the switch - this->mod->setRfSwitchState(Module::MODE_IDLE); - RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); - - // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags - uint32_t irq = this->getIrqStatus(); - this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); - if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { - return(RADIOLIB_ERR_RX_TIMEOUT); - } - - // retrieve the demodulator status - uint8_t info = 0; - state = this->gnssReadDemodStatus(&res->demodStat, &info); - RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)res->demodStat, (unsigned int)info); - - // retrieve the number of detected satellites - state = this->gnssGetNbSvDetected(&res->numSatsDet); - RADIOLIB_ASSERT(state); - - // retrieve the result size - state = this->gnssGetResultSize(&res->resSize); - RADIOLIB_ASSERT(state); - - // check and return demodulator status - if(res->demodStat < RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND) { - return(RADIOLIB_ERR_GNSS_DEMOD(res->demodStat)); - } - - return(state); -} - -int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) { - RADIOLIB_ASSERT_PTR(stat); - - // save the time the time until subframe is relative to - stat->start = this->mod->hal->millis(); - - // get the raw data - uint8_t raw[53] = { 0 }; - int16_t state = this->gnssReadAlmanacStatus(raw); - RADIOLIB_ASSERT(state); - - // parse the reply - stat->gps.status = (int8_t)raw[0]; - stat->gps.timeUntilSubframe = ((uint32_t)(raw[1]) << 24) | ((uint32_t)(raw[2]) << 16) | ((uint32_t)(raw[3]) << 8) | (uint32_t)raw[4]; - stat->gps.numSubframes = raw[5]; - stat->gps.nextSubframe4SvId = raw[6]; - stat->gps.nextSubframe5SvId = raw[7]; - stat->gps.nextSubframeStart = raw[8]; - stat->gps.numUpdateNeeded = raw[9]; - stat->gps.flagsUpdateNeeded[0] = ((uint32_t)(raw[10]) << 24) | ((uint32_t)(raw[11]) << 16) | ((uint32_t)(raw[12]) << 8) | (uint32_t)raw[13]; - stat->gps.flagsActive[0] = ((uint32_t)(raw[14]) << 24) | ((uint32_t)(raw[15]) << 16) | ((uint32_t)(raw[16]) << 8) | (uint32_t)raw[17]; - stat->beidou.status = (int8_t)raw[18]; - stat->beidou.timeUntilSubframe = ((uint32_t)(raw[19]) << 24) | ((uint32_t)(raw[20]) << 16) | ((uint32_t)(raw[21]) << 8) | (uint32_t)raw[22]; - stat->beidou.numSubframes = raw[23]; - stat->beidou.nextSubframe4SvId = raw[24]; - stat->beidou.nextSubframe5SvId = raw[25]; - stat->beidou.nextSubframeStart = raw[26]; - stat->beidou.numUpdateNeeded = raw[27]; - stat->beidou.flagsUpdateNeeded[0] = ((uint32_t)(raw[28]) << 24) | ((uint32_t)(raw[29]) << 16) | ((uint32_t)(raw[30]) << 8) | (uint32_t)raw[31]; - stat->beidou.flagsUpdateNeeded[1] = ((uint32_t)(raw[32]) << 24) | ((uint32_t)(raw[33]) << 16) | ((uint32_t)(raw[34]) << 8) | (uint32_t)raw[35]; - stat->beidou.flagsActive[0] = ((uint32_t)(raw[36]) << 24) | ((uint32_t)(raw[37]) << 16) | ((uint32_t)(raw[38]) << 8) | (uint32_t)raw[39]; - stat->beidou.flagsActive[1] = ((uint32_t)(raw[40]) << 24) | ((uint32_t)(raw[41]) << 16) | ((uint32_t)(raw[42]) << 8) | (uint32_t)raw[43]; - stat->beidouSvNoAlmanacFlags[0] = ((uint32_t)(raw[44]) << 24) | ((uint32_t)(raw[45]) << 16) | ((uint32_t)(raw[46]) << 8) | (uint32_t)raw[47]; - stat->beidouSvNoAlmanacFlags[1] = ((uint32_t)(raw[18]) << 24) | ((uint32_t)(raw[49]) << 16) | ((uint32_t)(raw[50]) << 8) | (uint32_t)raw[51]; - stat->nextAlmanacId = raw[52]; - - return(state); -} - -int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) { - RADIOLIB_ASSERT_PTR(stat); - - // almanac update has to be called at least 1.3 seconds before the subframe - // we use 2.3 seconds to be on the safe side - - // calculate absolute times - RadioLibTime_t window = stat->start + stat->gps.timeUntilSubframe - 2300; - if(constellation == RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU) { - window = stat->start + stat->beidou.timeUntilSubframe - 2300; - } - RadioLibTime_t now = this->mod->hal->millis(); - if(now > window) { - // we missed the window - return(RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE); - } - - RadioLibTime_t delay = window - now; - RADIOLIB_DEBUG_BASIC_PRINTLN("Time until subframe %lu ms", delay); - this->mod->hal->delay(delay); - return(RADIOLIB_ERR_NONE); -} - -// TODO fix last satellite always out of date -int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) { - int16_t state = this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT); - RADIOLIB_ASSERT(state); - - state = this->gnssAlmanacUpdateFromSat(RADIOLIB_LR11X0_GNSS_EFFORT_MID, constellation); - RADIOLIB_ASSERT(state); - - // wait for scan finished or timeout, assumes 2 subframes and up to 2.3s pre-roll - uint32_t softTimeout = 16UL * 1000UL; - uint32_t start = this->mod->hal->millis(); - while (!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start > softTimeout) { - this->gnssAbort(); - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for almanac update"); - } - } - - RADIOLIB_DEBUG_BASIC_PRINTLN("GPS almanac update done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); - - // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags - uint32_t irq = this->getIrqStatus(); - this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); - if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { - state = RADIOLIB_ERR_RX_TIMEOUT; - } - - return(state); -} - -int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) { - RADIOLIB_ASSERT_PTR(pos); - - uint8_t error = 0; - int16_t state; - if(filtered) { - state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, NULL, NULL, NULL, NULL, &pos->latitude, &pos->longitude, &pos->accuracy, NULL); - } else { - state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, &pos->latitude, &pos->longitude, &pos->accuracy, NULL, NULL, NULL, NULL, NULL); - } - RADIOLIB_ASSERT(state); - - // check the solver error - if(error != 0) { - return(RADIOLIB_ERR_GNSS_SOLVER(error)); - } - - return(state); -} - -int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) { - RADIOLIB_ASSERT_PTR(sats); - if(numSats >= 32) { - return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); - } - - uint8_t svId[32] = { 0 }; - uint8_t snr[32] = { 0 }; - int16_t doppler[32] = { 0 }; - int16_t state = this->gnssGetSvDetected(svId, snr, doppler, numSats); - RADIOLIB_ASSERT(state); - for(size_t i = 0; i < numSats; i++) { - sats[i].svId = svId[i]; - sats[i].c_n0 = snr[i] + 31; - sats[i].doppler = doppler[i]; - } - - return(state); -} - int16_t LR11x0::getModem(ModemType_t* modem) { RADIOLIB_ASSERT_PTR(modem); @@ -2311,1661 +1898,4 @@ Module* LR11x0::getMod() { return(this->mod); } -int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { - // check maximum size - if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); -} - -int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { - // check maximum size - if(len >= (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // the request contains the address and length - uint8_t reqBuff[5] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)len, - }; - - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - #if RADIOLIB_STATIC_ONLY - uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; - #endif - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); - - // convert endians - if(data && (state == RADIOLIB_ERR_NONE)) { - for(size_t i = 0; i < len; i++) { - data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; - } - } - - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - - return(state); -} - -int16_t LR11x0::writeBuffer8(const uint8_t* data, size_t len) { - // check maximum size - if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, const_cast(data), len)); -} - -int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) { - // check maximum size - if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // build buffers - size_t reqLen = 2*sizeof(uint8_t) + len; - #if RADIOLIB_STATIC_ONLY - uint8_t reqBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* reqBuff = new uint8_t[reqLen]; - #endif - - // set the offset and length - reqBuff[0] = (uint8_t)offset; - reqBuff[1] = (uint8_t)len; - - // send the request - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_BUFFER, false, data, len, reqBuff, reqLen); - #if !RADIOLIB_STATIC_ONLY - delete[] reqBuff; - #endif - return(state); -} - -int16_t LR11x0::clearRxBuffer(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER, true, NULL, 0)); -} - -int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { - uint8_t buff[12] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff))); -} - -int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { - uint8_t buff[6] = { 0 }; - - // the status check command doesn't return status in the same place as other read commands - // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used - // it also seems to ignore the actual command, and just sending in bunch of NOPs will work - int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - - // pass the replies - if(stat1) { *stat1 = buff[0]; } - if(stat2) { *stat2 = buff[1]; } - if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; } - - return(state); -} - -int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) { - uint8_t buff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff)); - - // pass the replies - if(hw) { *hw = buff[0]; } - if(device) { *device = buff[1]; } - if(major) { *major = buff[2]; } - if(minor) { *minor = buff[3]; } - - return(state); -} - -int16_t LR11x0::getErrors(uint16_t* err) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_ERRORS, false, buff, sizeof(buff)); - - // pass the replies - if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } - - return(state); -} - -int16_t LR11x0::clearErrors(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_ERRORS, true, NULL, 0)); -} - -int16_t LR11x0::calibrate(uint8_t params) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIBRATE, true, ¶ms, 1)); -} - -int16_t LR11x0::setRegMode(uint8_t mode) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1)); -} - -int16_t LR11x0::calibrateImageRejection(float freqMin, float freqMax) { - uint8_t buff[2] = { - (uint8_t)floor((freqMin - 1.0f) / 4.0f), - (uint8_t)ceil((freqMax + 1.0f) / 4.0f) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) { - uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) { - uint8_t buff[8] = { - (uint8_t)((irq1 >> 24) & 0xFF), (uint8_t)((irq1 >> 16) & 0xFF), (uint8_t)((irq1 >> 8) & 0xFF), (uint8_t)(irq1 & 0xFF), - (uint8_t)((irq2 >> 24) & 0xFF), (uint8_t)((irq2 >> 16) & 0xFF), (uint8_t)((irq2 >> 8) & 0xFF), (uint8_t)(irq2 & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setDioIrqParams(uint32_t irq) { - return(setDioIrqParams(irq, this->gnss ? 0 : irq)); -} - -int16_t LR11x0::clearIrqState(uint32_t irq) { - uint8_t buff[4] = { - (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, true, buff, sizeof(buff))); -} - -int16_t LR11x0::configLfClock(uint8_t setup) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK, true, &setup, 1)); -} - -int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) { - uint8_t buff[4] = { - tune, (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TCXO_MODE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::reboot(bool stay) { - uint8_t buff[1] = { (uint8_t)(stay*3) }; - return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false)); -} - -int16_t LR11x0::getVbat(float* vbat) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VBAT, false, buff, sizeof(buff)); - - // pass the replies - if(vbat) { *vbat = (((float)buff[0]/51.0f) - 1.0f)*1.35f; } - - return(state); -} - -int16_t LR11x0::getTemp(float* temp) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_TEMP, false, buff, sizeof(buff)); - - // pass the replies - if(temp) { - uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; - raw = raw & 0x07FF; //According LR1121 datasheet we need [0..10] bits - *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1.35f - 0.7295f); //According LR1121 datasheet 1.35 - } - - return(state); -} - -int16_t LR11x0::setFs(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_FS, true, NULL, 0)); -} - -int16_t LR11x0::getRandomNumber(uint32_t* rnd) { - uint8_t buff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff)); - - // pass the replies - if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } - - return(state); -} - -int16_t LR11x0::eraseInfoPage(void) { - // only page 1 can be erased - uint8_t buff[1] = { RADIOLIB_LR11X0_INFO_PAGE }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) { - // check maximum size - if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - size_t buffLen = sizeof(uint8_t) + sizeof(uint16_t) + len*sizeof(uint32_t); - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[sizeof(uint8_t) + sizeof(uint16_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* dataBuff = new uint8_t[buffLen]; - #endif - - // set the address - dataBuff[0] = RADIOLIB_LR11X0_INFO_PAGE; - dataBuff[1] = (uint8_t)((addr >> 8) & 0xFF); - dataBuff[2] = (uint8_t)(addr & 0xFF); - - // convert endians - for(size_t i = 0; i < len; i++) { - dataBuff[3 + i] = (uint8_t)((data[i] >> 24) & 0xFF); - dataBuff[4 + i] = (uint8_t)((data[i] >> 16) & 0xFF); - dataBuff[5 + i] = (uint8_t)((data[i] >> 8) & 0xFF); - dataBuff[6 + i] = (uint8_t)(data[i] & 0xFF); - } - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen); - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - -int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) { - // check maximum size - if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // the request contains the address and length - uint8_t reqBuff[4] = { - RADIOLIB_LR11X0_INFO_PAGE, - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)len, - }; - - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - #if RADIOLIB_STATIC_ONLY - uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; - #endif - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); - - // convert endians - if(data && (state == RADIOLIB_ERR_NONE)) { - for(size_t i = 0; i < len; i++) { - data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; - } - } - - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - - return(state); -} - -int16_t LR11x0::getChipEui(uint8_t* eui) { - RADIOLIB_ASSERT_PTR(eui); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); -} - -int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) { - RADIOLIB_ASSERT_PTR(eui); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); -} - -int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) { - RADIOLIB_ASSERT_PTR(pin); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); -} - -int16_t LR11x0::enableSpiCrc(bool en) { - // TODO implement this - (void)en; - // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected - /*RadioLibCRCInstance.size = 8; - RadioLibCRCInstance.poly = 0xA6; - RadioLibCRCInstance.init = 0xFF; - RadioLibCRCInstance.out = 0x00; - RadioLibCRCInstance.refIn = true; - RadioLibCRCInstance.refOut = true;*/ - return(RADIOLIB_ERR_UNSUPPORTED); -} - -int16_t LR11x0::driveDiosInSleepMode(bool en) { - uint8_t buff[1] = { (uint8_t)en }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::resetStats(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_RESET_STATS, true, NULL, 0)); -} - -int16_t LR11x0::getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2) { - uint8_t buff[8] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_STATS, false, buff, sizeof(buff)); - - // pass the replies - if(nbPktReceived) { *nbPktReceived = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } - if(nbPktCrcError) { *nbPktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } - if(data1) { *data1 = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } - if(data2) { *data2 = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } - - return(state); -} - -int16_t LR11x0::getPacketType(uint8_t* type) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE, false, buff, sizeof(buff)); - - // pass the replies - if(type) { *type = buff[0]; } - - return(state); -} - -int16_t LR11x0::getRxBufferStatus(uint8_t* len, uint8_t* startOffset) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS, false, buff, sizeof(buff)); - - // pass the replies - if(len) { *len = buff[0]; } - if(startOffset) { *startOffset = buff[1]; } - - return(state); -} - -int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt) { - uint8_t buff[3] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); - - // pass the replies - if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; } - if(snrPkt) { *snrPkt = (float)((int8_t)buff[1]) / 4.0f; } - if(signalRssiPkt) { *signalRssiPkt = buff[2]; } - - return(state); -} - -int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat) { - uint8_t buff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); - - // pass the replies - if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; } - if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; } - if(rxLen) { *rxLen = buff[2]; } - if(stat) { *stat = buff[3]; } - - return(state); -} - -int16_t LR11x0::getRssiInst(float* rssi) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RSSI_INST, false, buff, sizeof(buff)); - - // pass the replies - if(rssi) { *rssi = (float)buff[0] / -2.0f; } - - return(state); -} - -int16_t LR11x0::setGfskSyncWord(uint8_t* sync) { - RADIOLIB_ASSERT_PTR(sync); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)); -} - -int16_t LR11x0::setLoRaPublicNetwork(bool pub) { - uint8_t buff[1] = { (uint8_t)pub }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRx(uint32_t timeout) { - uint8_t buff[3] = { - (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setTx(uint32_t timeout) { - uint8_t buff[3] = { - (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRfFrequency(uint32_t rfFreq) { - uint8_t buff[4] = { - (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF), - (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff))); -} - -int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) { - uint8_t buff[7] = { - (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), intMode, - (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_AUTO_TX_RX, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout) { - uint8_t buff[7] = { - symNum, detPeak, detMin, cadExitMode, - (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setPacketType(uint8_t type) { - uint8_t buff[1] = { type }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { - // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled - if(this->ldroAuto) { - float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - if(symbolLength >= 16.0f) { - this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED; - } else { - this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED; - } - } else { - this->ldrOptimize = ldro; - } - - uint8_t buff[4] = { sf, bw, cr, this->ldrOptimize }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { - uint8_t buff[10] = { - (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF), - (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw, - (uint8_t)((freqDev >> 24) & 0xFF), (uint8_t)((freqDev >> 16) & 0xFF), - (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setModulationParamsLrFhss(uint32_t br, uint8_t sh) { - uint8_t buff[5] = { - (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF), - (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setModulationParamsSigfox(uint32_t br, uint8_t sh) { - // same as for LR-FHSS - return(this->setModulationParamsLrFhss(br, sh)); -} - -int16_t LR11x0::setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) { - uint8_t buff[6] = { - (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), - hdrType, payloadLen, crcType, invertIQ - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten) { - uint8_t buff[9] = { - (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), - preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum) { - uint8_t buff[7] = { - payloadLen, (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF), - (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF), - (uint8_t)((bitNum >> 8) & 0xFF), (uint8_t)(bitNum & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setTxParams(int8_t pwr, uint8_t ramp) { - uint8_t buff[2] = { (uint8_t)pwr, ramp }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setPacketAdrs(uint8_t node, uint8_t broadcast) { - uint8_t buff[2] = { node, broadcast }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRxTxFallbackMode(uint8_t mode) { - uint8_t buff[1] = { mode }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode) { - uint8_t buff[7] = { - (uint8_t)((rxPeriod >> 16) & 0xFF), (uint8_t)((rxPeriod >> 8) & 0xFF), (uint8_t)(rxPeriod & 0xFF), - (uint8_t)((sleepPeriod >> 16) & 0xFF), (uint8_t)((sleepPeriod >> 8) & 0xFF), (uint8_t)(sleepPeriod & 0xFF), - mode - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel) { - uint8_t buff[4] = { paSel, regPaSupply, paDutyCycle, paHpSel }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PA_CONFIG, true, buff, sizeof(buff))); -} - -int16_t LR11x0::stopTimeoutOnPreamble(bool stop) { - uint8_t buff[1] = { (uint8_t)stop }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setCad(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD, true, NULL, 0)); -} - -int16_t LR11x0::setTxCw(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_CW, true, NULL, 0)); -} - -int16_t LR11x0::setTxInfinitePreamble(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE, true, NULL, 0)); -} - -int16_t LR11x0::setLoRaSynchTimeout(uint8_t symbolNum) { - uint8_t buff[1] = { symbolNum }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) { - uint8_t buff[5] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), checkLen - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRangingReqAddr(uint32_t addr) { - uint8_t buff[4] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff))); -} - -int16_t LR11x0::getRangingResult(uint8_t type, float* res) { - uint8_t reqBuff[1] = { type }; - uint8_t rplBuff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - - if(res) { - if(type == RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE) { - uint32_t raw = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; - *res = ((float)(raw*3e8))/((float)(4096*this->bandwidthKhz*1000)); - } else { - *res = (float)rplBuff[3]/2.0f; - } - } - - return(state); -} - -int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) { - uint8_t buff[4] = { - (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF), - (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) { - uint8_t buff[8] = { - (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF), - (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), - (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF), - (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff))); - -} - -int16_t LR11x0::setGfskWhitParams(uint16_t seed) { - uint8_t buff[2] = { - (uint8_t)((seed >> 8) & 0xFF), (uint8_t)(seed & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRangingParameter(uint8_t symbolNum) { - // the first byte is reserved - uint8_t buff[2] = { 0x00, symbolNum }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setRssiCalibration(const int8_t* tune, int16_t gainOffset) { - uint8_t buff[11] = { - (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4), - (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4), - (uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4), - (uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4), - (uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4), - (uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4), - (uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4), - (uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4), - (uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4), - (uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff))); -} - -int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { - uint8_t buff[1] = { sync }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff))); -} - -int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len) { - // check maximum size - const uint8_t maxLen[4][4] = { - { 189, 178, 167, 155, }, - { 151, 142, 133, 123, }, - { 112, 105, 99, 92, }, - { 74, 69, 65, 60, }, - }; - if((cr > RADIOLIB_LR11X0_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // build buffers - size_t buffLen = 9 + len; - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[9 + 190]; - #else - uint8_t* dataBuff = new uint8_t[buffLen]; - #endif - - // set properties of the packet - dataBuff[0] = hdrCount; - dataBuff[1] = cr; - dataBuff[2] = RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK; - dataBuff[3] = grid; - dataBuff[4] = (uint8_t)hop; - dataBuff[5] = bw; - dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01); - dataBuff[7] = (uint8_t)(hopSeq & 0xFF); - dataBuff[8] = devOffset; - memcpy(&dataBuff[9], payload, len); - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen); - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - -int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) { - uint8_t buff[4] = { - (uint8_t)((sync >> 24) & 0xFF), (uint8_t)((sync >> 16) & 0xFF), - (uint8_t)((sync >> 8) & 0xFF), (uint8_t)(sync & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, true, buff, sizeof(buff))); -} - -int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len) { - return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len)); -} - -int16_t LR11x0::getLoRaRxHeaderInfos(uint8_t* info) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff)); - - // pass the replies - if(info) { *info = buff[0]; } - - return(state); -} - -int16_t LR11x0::bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len) { - return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len)); -} - -int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len) { - // check maximum size - // TODO what is the actual maximum? - if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // build buffers - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* dataBuff = new uint8_t[sizeof(uint8_t) + len]; - #endif - - // set the channel - dataBuff[0] = chan; - memcpy(&dataBuff[1], payload, len); - - int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len); - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - -int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) { - uint8_t buff[9] = { - type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - acqMode, nbMaxRes, nbScanPerChan, - (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), - abortOnTimeout - }; - - // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts - return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_WIFI_SCAN, buff, sizeof(buff), false, false)); -} - -int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { - uint8_t buff[9] = { - type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - acqMode, nbMaxRes, - (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF), - (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT, true, buff, sizeof(buff))); -} - -int16_t LR11x0::wifiCountryCode(uint16_t mask, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) { - uint8_t buff[7] = { - (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - nbMaxRes, nbScanPerChan, - (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), - abortOnTimeout - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { - uint8_t buff[7] = { - (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - nbMaxRes, - (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF), - (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); -} - -int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) { - uint8_t buff[3] = { index, nbResults, format }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN, buff, sizeof(buff))); -} - -int16_t LR11x0::wifiResetCumulTimings(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS, true, NULL, 0)); -} - -int16_t LR11x0::wifiReadCumulTimings(uint32_t* detection, uint32_t* capture, uint32_t* demodulation) { - uint8_t buff[16] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS, false, buff, sizeof(buff)); - - // pass the replies - if(detection) { *detection = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } - if(capture) { *capture = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; } - if(demodulation) { *demodulation = ((uint32_t)(buff[12]) << 24) | ((uint32_t)(buff[13]) << 16) | ((uint32_t)(buff[14]) << 8) | (uint32_t)buff[15]; } - - return(state); -} - -int16_t LR11x0::wifiGetNbCountryCodeResults(uint8_t* nbResults) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS, false, buff, sizeof(buff)); - - // pass the replies - if(nbResults) { *nbResults = buff[0]; } - - return(state); -} - -int16_t LR11x0::wifiReadCountryCodeResults(uint8_t index, uint8_t nbResults, uint8_t* results) { - uint8_t reqBuff[2] = { index, nbResults }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff))); -} - -int16_t LR11x0::wifiCfgTimestampAPphone(uint32_t timestamp) { - uint8_t buff[4] = { - (uint8_t)((timestamp >> 24) & 0xFF), (uint8_t)((timestamp >> 16) & 0xFF), - (uint8_t)((timestamp >> 8) & 0xFF), (uint8_t)(timestamp & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); -} - -int16_t LR11x0::wifiReadVersion(uint8_t* major, uint8_t* minor) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION, false, buff, sizeof(buff)); - - // pass the replies - if(major) { *major = buff[0]; } - if(minor) { *minor = buff[1]; } - - return(state); -} - -int16_t LR11x0::gnssReadRssi(int8_t* rssi) { - uint8_t reqBuff[1] = { 0x09 }; // some undocumented magic byte, from the official driver - uint8_t rplBuff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - if(rssi) { *rssi = rplBuff[1]; } - return(state); -} - -int16_t LR11x0::gnssSetConstellationToUse(uint8_t mask) { - uint8_t buff[1] = { mask }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssReadConstellationToUse(uint8_t* mask) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE, false, buff, sizeof(buff)); - - // pass the replies - if(mask) { *mask = buff[0]; } - - return(state); -} - -int16_t LR11x0::gnssSetAlmanacUpdate(uint8_t mask) { - uint8_t buff[1] = { mask }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssReadAlmanacUpdate(uint8_t* mask) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE, false, buff, sizeof(buff)); - - // pass the replies - if(mask) { *mask = buff[0]; } - - return(state); -} - -int16_t LR11x0::gnssSetFreqSearchSpace(uint8_t freq) { - uint8_t buff[1] = { freq }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssReadFreqSearchSpace(uint8_t* freq) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE, false, buff, sizeof(buff)); - if(freq) { *freq = buff[0]; } - return(state); -} - -int16_t LR11x0::gnssReadVersion(uint8_t* fw, uint8_t* almanac) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION, false, buff, sizeof(buff)); - - // pass the replies - if(fw) { *fw = buff[0]; } - if(almanac) { *almanac = buff[1]; } - - return(state); -} - -int16_t LR11x0::gnssReadSupportedConstellations(uint8_t* mask) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS, false, buff, sizeof(buff)); - - // pass the replies - if(mask) { *mask = buff[0]; } - - return(state); -} - -int16_t LR11x0::gnssSetMode(uint8_t mode) { - uint8_t buff[1] = { mode }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_MODE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssAutonomous(uint32_t gpsTime, uint8_t resMask, uint8_t nbSvMask) { - uint8_t buff[7] = { - (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF), - (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF), - RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE, resMask, nbSvMask - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, uint8_t nbSvMask) { - uint8_t buff[7] = { - (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF), - (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF), - effort, resMask, nbSvMask - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ASSISTED, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) { - int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; - int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; - uint8_t buff[4] = { - (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), - (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssReadAssistancePosition(float* lat, float* lon) { - uint8_t buff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION, false, buff, sizeof(buff)); - - // pass the replies - if(lat) { - int16_t latRaw = ((int16_t)(buff[0]) << 8) | (int16_t)(buff[1]); - *lat = ((float)latRaw*90.0f)/2048.0f; - } - if(lon) { - int16_t lonRaw = ((int16_t)(buff[2]) << 8) | (int16_t)(buff[3]); - *lon = ((float)lonRaw*180.0f)/2048.0f; - } - - return(state); -} - -int16_t LR11x0::gnssPushSolverMsg(uint8_t* payload, size_t len) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG, true, payload, len)); -} - -int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG, true, payload, len)); -} - -int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) { - // send the command - datasheet here shows extra bytes being sent in the request - // but doing that fails so treat it like any other read command - uint8_t buff[9] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, false, buff, sizeof(buff)); - - // pass the replies - if(fwVersion) { *fwVersion = buff[2]; } - if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[3]) << 24) | ((uint32_t)(buff[4]) << 16) | ((uint32_t)(buff[5]) << 8) | (uint32_t)buff[6]; } - if(errCode) { *errCode = (buff[7] & 0xF0) >> 4; } - if(almUpdMask) { *almUpdMask = (buff[7] & 0x0E) >> 1; } - if(freqSpace) { *freqSpace = ((buff[7] & 0x01) << 1) | ((buff[8] & 0x80) >> 7); } - - return(state); -} - -int16_t LR11x0::gnssGetNbSvDetected(uint8_t* nbSv) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED, false, buff, sizeof(buff)); - - // pass the replies - if(nbSv) { *nbSv = buff[0]; } - - return(state); -} - -int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, int16_t* doppler, size_t nbSv) { - // TODO this is arbitrary - is there an actual maximum? - if(nbSv > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t)) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // build buffers - size_t buffLen = nbSv*sizeof(uint32_t); - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* dataBuff = new uint8_t[buffLen]; - #endif - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED, false, dataBuff, buffLen); - if(state == RADIOLIB_ERR_NONE) { - for(size_t i = 0; i < nbSv; i++) { - if(svId) { svId[i] = dataBuff[4*i]; } - if(snr) { snr[i] = dataBuff[4*i + 1]; } - if(doppler) { doppler[i] = ((uint16_t)(dataBuff[4*i + 2]) << 8) | (uint16_t)dataBuff[4*i + 3]; } - } - } - - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - -int16_t LR11x0::gnssGetConsumption(uint32_t* cpu, uint32_t* radio) { - uint8_t buff[8] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION, false, buff, sizeof(buff)); - - // pass the replies - if(cpu) { *cpu = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } - if(radio) { *radio = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } - - return(state); -} - -int16_t LR11x0::gnssGetResultSize(uint16_t* size) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE, false, buff, sizeof(buff)); - - // pass the replies - if(size) { *size = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } - - return(state); -} - -int16_t LR11x0::gnssReadResults(uint8_t* result, uint16_t size) { - RADIOLIB_ASSERT_PTR(result); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS, false, result, size)); -} - -int16_t LR11x0::gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc) { - uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { - RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID, - (uint8_t)((date >> 8) & 0xFF), (uint8_t)(date & 0xFF), - (uint8_t)((globalCrc >> 24) & 0xFF), (uint8_t)((globalCrc >> 16) & 0xFF), - (uint8_t)((globalCrc >> 8) & 0xFF), (uint8_t)(globalCrc & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, const uint8_t* svnAlmanac) { - uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { svn }; - memcpy(&buff[1], svnAlmanac, RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE - 1); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size) { - uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE, false, buff, sizeof(buff)); - - if(addr) { *addr = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } - if(size) { *size = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } - - return(state); -} - -int16_t LR11x0::gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac) { - uint8_t reqBuff[2] = { svId, 0x01 }; // in theory multiple SV entries can be read at the same time, but we don't need that - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE, false, almanac, 22, reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - return(state); -} - -int16_t LR11x0::gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { - int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; - int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; - uint8_t reqBuff[9] = { - (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), - (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), - (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), - (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), - constellation, - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); -} - -int16_t LR11x0::gnssGetSvVisible(uint8_t nbSv, uint8_t** svId, int16_t** doppler, int16_t** dopplerErr) { - // enforce a maximum of 12 SVs - if(nbSv > 12) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - uint8_t buff[60] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER, false, buff, sizeof(buff)); - for(uint8_t i = 0; i < nbSv; i++) { - if(svId && svId[i]) { *svId[i] = buff[i*12]; } - if(doppler && doppler[i]) { *doppler[i] = ((uint16_t)(buff[i*12 + 1]) << 8) | (uint16_t)buff[i*12 + 2]; } - if(dopplerErr && dopplerErr[i]) { *dopplerErr[i] = ((uint16_t)(buff[i*12 + 3]) << 8) | (uint16_t)buff[i*12 + 4]; } - } - - return(state); -} - -int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { - uint8_t buff[3] = { effort, resMask, nbSvMax }; - // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts - return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_SCAN, buff, sizeof(buff), false, false)); -} - -int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED, false, buff, sizeof(buff)); - - // pass the replies - if(lastScanMode) { *lastScanMode = buff[0]; } - - return(state); -} - -int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) { - uint8_t buff[2] = { effort, opt }; - // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts - return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, buff, sizeof(buff), false, false)); -} - -int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) { - uint8_t buff[12] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_TIME, false, buff, sizeof(buff)); - - // pass the replies - if(err) { *err = buff[0]; } - - if(time) { - *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; - *time += 2UL*1024UL*7UL*24UL*3600UL; // assume WN rollover is at 2, this will fail sometime in 2038 - *time += 315964800UL; // convert to UTC - } - - if(nbUs) { - *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; - *nbUs /= 16; - } - - if(timeAccuracy) { - *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; - *timeAccuracy /= 16; - } - - return(state); -} - -int16_t LR11x0::gnssResetTime(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME, true, NULL, 0)); -} - -int16_t LR11x0::gnssResetPosition(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0)); -} - -int16_t LR11x0::gnssReadWeekNumberRollover(uint8_t* status, uint8_t* rollover) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER, false, buff, sizeof(buff)); - if(status) { *status = buff[0]; } - if(rollover) { *rollover = buff[1]; } - return(state); -} - -int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) { - uint8_t buff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff)); - - // pass the replies - if(status) { *status = (int8_t)buff[0]; } - if(info) { *info = buff[1]; } - - return(state); -} - -int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) { - uint8_t rplBuff[125] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING, false, rplBuff, 125); - RADIOLIB_ASSERT(state); - - // convert endians - if(timing) { - for(size_t i = 0; i < 31; i++) { - timing[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)]; - } - } - - if(constDemod) { *constDemod = rplBuff[124]; } - - return(state); -} - -int16_t LR11x0::gnssSetTime(uint32_t time, uint16_t accuracy) { - uint8_t buff[6] = { - (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), - (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), - (uint8_t)((accuracy >> 8) & 0xFF), (uint8_t)(accuracy & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_TIME, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt) { - uint8_t buff[18] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES, false, buff, sizeof(buff)); - - // pass the replies - if(error) { *error = buff[0]; } - if(nbSvUsed) { *nbSvUsed = buff[1]; } - if(lat) { - int16_t latRaw = ((int16_t)(buff[2]) << 8) | (int16_t)buff[3]; - *lat = ((float)latRaw * 90.0f)/2048.0f; - } - if(lon) { - int16_t lonRaw = ((int16_t)(buff[4]) << 8) | (int16_t)buff[5]; - *lon = ((float)lonRaw * 180.0f)/2048.0f; - } - if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } - if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; } - if(latFilt) { - int16_t latRaw = ((int16_t)(buff[10]) << 8) | (int16_t)buff[11]; - *latFilt = ((float)latRaw * 90.0f)/2048.0f; - } - if(lonFilt) { - int16_t lonRaw = ((int16_t)(buff[12]) << 8) | (int16_t)buff[13]; - *lonFilt = ((float)lonRaw * 180.0f)/2048.0f; - } - if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; } - if(xtalFilt) { *xtalFilt = ((uint16_t)(buff[16]) << 8) | (uint16_t)buff[17]; } - - return(state); -} - -int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) { - uint8_t buff[3] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP, false, buff, sizeof(buff)); - - if(delay) { *delay = ((uint32_t)(buff[0]) << 16) | ((uint32_t)(buff[1]) << 8) | (uint32_t)buff[2]; } - - return(state); -} - -int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) { - uint8_t buff[2] = { effort, bitMask }; - // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts - return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, buff, sizeof(buff), false, false)); -} - -int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed) { - uint8_t reqBuff[1] = { mask }; - uint8_t rplBuff[5] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - if(nbSvVisible) { *nbSvVisible = rplBuff[0]; } - if(elapsed) { *elapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } - return(state); -} - -int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53)); -} - -int16_t LR11x0::gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period) { - uint8_t buff[4] = { bitMask, svType, (uint8_t)((period >> 8) & 0xFF), (uint8_t)(period & 0xFF) }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period) { - uint8_t reqBuff[2] = { bitMask, svType }; - uint8_t rplBuff[2] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - - if(period) { *period = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; } - - return(state); -} - -int16_t LR11x0::gnssConfigDelayResetAP(uint32_t delay) { - uint8_t buff[3] = { (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP, true, buff, sizeof(buff))); -} - -int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat) { - uint8_t reqBuff[1] = { bitMask }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff))); -} - -int16_t LR11x0::gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList) { - uint8_t reqBuff[2] = { mask, nbSv }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC, false, syncList, nbSv, reqBuff, sizeof(reqBuff))); -} - -int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) { - uint8_t reqBuff[1] = { bitMask }; - uint8_t rplBuff[5] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - - if(nbVisSat) { *nbVisSat = rplBuff[0]; } - if(timeElapsed) { *timeElapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } - - return(state); -} - -int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1) { - uint8_t reqBuff[1] = { bitMask }; - uint8_t rplBuff[8] = { 0 }; - size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - - if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } - if(bitMaskActivated1) { *bitMaskActivated1 = ((uint32_t)(rplBuff[4]) << 24) | ((uint32_t)(rplBuff[5]) << 16) | ((uint32_t)(rplBuff[6]) << 8) | (uint32_t)rplBuff[7]; } - - return(state); -} - -void LR11x0::gnssAbort() { - // send the abort signal (single NOP) - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - // we need to call the most basic overload of the SPI write method otherwise the call will be ambiguous - const uint8_t cmd[2] = { 0, 0 }; - this->mod->SPIwriteStream(cmd, 2, NULL, 0, false, false); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - - // wait for at least 2.9 seconds as specified by the user manual - this->mod->hal->delay(3000); -} - -int16_t LR11x0::cryptoSetKey(uint8_t keyId, const uint8_t* key) { - RADIOLIB_ASSERT_PTR(key); - uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; - buff[0] = keyId; - memcpy(&buff[1], key, RADIOLIB_AES128_KEY_SIZE); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY, false, buff, sizeof(buff))); -} - -int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, const uint8_t* key) { - RADIOLIB_ASSERT_PTR(key); - uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; - buff[0] = srcKeyId; - buff[1] = dstKeyId; - memcpy(&buff[2], key, RADIOLIB_AES128_KEY_SIZE); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY, false, buff, sizeof(buff))); -} - -int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, const uint8_t* header, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { - // calculate buffer sizes - size_t headerLen = 1; - if(lwVer) { - headerLen += 11; // LoRaWAN 1.1 header is 11 bytes longer than 1.0 - } - size_t reqLen = 3*sizeof(uint8_t) + headerLen + len; - size_t rplLen = sizeof(uint8_t) + len; - - // build buffers - #if RADIOLIB_STATIC_ONLY - uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* reqBuff = new uint8_t[reqLen]; - uint8_t* rplBuff = new uint8_t[rplLen]; - #endif - - // set the request fields - reqBuff[0] = decKeyId; - reqBuff[1] = verKeyId; - reqBuff[2] = lwVer; - memcpy(&reqBuff[3], header, headerLen); - memcpy(&reqBuff[3 + headerLen], dataIn, len); - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT, false, rplBuff, rplLen, reqBuff, reqLen); - #if !RADIOLIB_STATIC_ONLY - delete[] reqBuff; - #endif - if(state != RADIOLIB_ERR_NONE) { - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - return(state); - } - - // check the crypto engine state - if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - return(RADIOLIB_ERR_SPI_CMD_FAILED); - } - - // pass the data - memcpy(dataOut, &rplBuff[1], len); - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - return(state); -} - -int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, const uint8_t* data, size_t len, uint32_t* mic) { - size_t reqLen = sizeof(uint8_t) + len; - #if RADIOLIB_STATIC_ONLY - uint8_t reqBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* reqBuff = new uint8_t[reqLen]; - #endif - uint8_t rplBuff[5] = { 0 }; - - reqBuff[0] = keyId; - memcpy(&reqBuff[1], data, len); - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); - #if !RADIOLIB_STATIC_ONLY - delete[] reqBuff; - #endif - - // check the crypto engine state - if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); - return(RADIOLIB_ERR_SPI_CMD_FAILED); - } - - if(mic) { *mic = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } - return(state); -} - -int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, const uint8_t* data, size_t len, bool* result) { - size_t reqLen = sizeof(uint8_t) + sizeof(uint32_t) + len; - #if RADIOLIB_STATIC_ONLY - uint8_t reqBuff[sizeof(uint8_t) + sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* reqBuff = new uint8_t[reqLen]; - #endif - uint8_t rplBuff[1] = { 0 }; - - reqBuff[0] = keyId; - reqBuff[1] = (uint8_t)((micExp >> 24) & 0xFF); - reqBuff[2] = (uint8_t)((micExp >> 16) & 0xFF); - reqBuff[3] = (uint8_t)((micExp >> 8) & 0xFF); - reqBuff[4] = (uint8_t)(micExp & 0xFF); - memcpy(&reqBuff[5], data, len); - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); - #if !RADIOLIB_STATIC_ONLY - delete[] reqBuff; - #endif - - // check the crypto engine state - if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); - return(RADIOLIB_ERR_SPI_CMD_FAILED); - } - - if(result) { *result = (rplBuff[0] == RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS); } - return(state); -} - -int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { - return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01, keyId, dataIn, len, dataOut)); -} - -int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { - return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT, keyId, dataIn, len, dataOut)); -} - -int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { - return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT, keyId, dataIn, len, dataOut)); -} - -int16_t LR11x0::cryptoStoreToFlash(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH, true, NULL, 0)); -} - -int16_t LR11x0::cryptoRestoreFromFlash(void) { - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH, true, NULL, 0)); -} - -int16_t LR11x0::cryptoSetParam(uint8_t id, uint32_t value) { - uint8_t buff[5] = { - id, - (uint8_t)((value >> 24) & 0xFF), (uint8_t)((value >> 16) & 0xFF), - (uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM, true, buff, sizeof(buff))); -} - -int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) { - uint8_t reqBuff[1] = { id }; - uint8_t rplBuff[4] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); - RADIOLIB_ASSERT(state); - if(value) { *value = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } - return(state); -} - -int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) { - // check maximum size - if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); -} - -int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { - uint8_t buff[1] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT, false, buff, sizeof(buff)); - - // pass the replies - if(result) { *result = (bool)buff[0]; } - - return(state); -} - -int16_t LR11x0::bootEraseFlash(void) { - // erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds - RadioLibTime_t timeout = this->mod->spiConfig.timeout; - this->mod->spiConfig.timeout = 3000; - int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false); - this->mod->spiConfig.timeout = timeout; - return(state); -} - -int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) { - // check maximum size - if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); -} - -int16_t LR11x0::bootReboot(bool stay) { - uint8_t buff[1] = { (uint8_t)stay }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff))); -} - -int16_t LR11x0::bootGetPin(uint8_t* pin) { - RADIOLIB_ASSERT_PTR(pin); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); -} - -int16_t LR11x0::bootGetChipEui(uint8_t* eui) { - RADIOLIB_ASSERT_PTR(eui); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); -} - -int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { - RADIOLIB_ASSERT_PTR(eui); - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); -} - -int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* dataBuff = new uint8_t[buffLen]; - #endif - - // set the address or offset - dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF); - dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF); - dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF); - dataBuff[3] = (uint8_t)(addrOffset & 0xFF); - - // convert endians - for(size_t i = 0; i < len; i++) { - uint32_t bin = 0; - if(nonvolatile) { - uint32_t* ptr = const_cast(data) + i; - bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr); - } else { - bin = data[i]; - } - dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF); - dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF); - dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF); - dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); - } - - int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - -int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { - // build buffers - #if RADIOLIB_STATIC_ONLY - uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* reqBuff = new uint8_t[sizeof(uint8_t) + len]; - uint8_t* rplBuff = new uint8_t[sizeof(uint8_t) + len]; - #endif - - // set the request fields - reqBuff[0] = keyId; - memcpy(&reqBuff[1], dataIn, len); - - int16_t state = this->SPIcommand(cmd, false, rplBuff, sizeof(uint8_t) + len, reqBuff, sizeof(uint8_t) + len); - #if !RADIOLIB_STATIC_ONLY - delete[] reqBuff; - #endif - if(state != RADIOLIB_ERR_NONE) { - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - return(state); - } - - // check the crypto engine state - if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { - RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); - return(RADIOLIB_ERR_SPI_CMD_FAILED); - } - - // pass the data - memcpy(dataOut, &rplBuff[1], len); - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - return(state); -} - #endif diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp new file mode 100644 index 0000000000..e00232e4a7 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -0,0 +1,845 @@ +#include "LR11x0.h" + +#include "../../utils/CRC.h" +#include "../../utils/Cryptography.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR11X0 + +int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); +} + +int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len >= (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + + // convert endians + if(data && (state == RADIOLIB_ERR_NONE)) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + + return(state); +} + +int16_t LR11x0::writeBuffer8(const uint8_t* data, size_t len) { + // check maximum size + if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_BUFFER, true, const_cast(data), len)); +} + +int16_t LR11x0::readBuffer8(uint8_t* data, size_t len, size_t offset) { + // check maximum size + if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t reqLen = 2*sizeof(uint8_t) + len; + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + #endif + + // set the offset and length + reqBuff[0] = (uint8_t)offset; + reqBuff[1] = (uint8_t)len; + + // send the request + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_BUFFER, false, data, len, reqBuff, reqLen); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + return(state); +} + +int16_t LR11x0::clearRxBuffer(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER, true, NULL, 0)); +} + +int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { + uint8_t buff[12] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff))); +} + +int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { + uint8_t buff[6] = { 0 }; + + // the status check command doesn't return status in the same place as other read commands + // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used + // it also seems to ignore the actual command, and just sending in bunch of NOPs will work + int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); + + // pass the replies + if(stat1) { *stat1 = buff[0]; } + if(stat2) { *stat2 = buff[1]; } + if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; } + + return(state); +} + +int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff)); + + // pass the replies + if(hw) { *hw = buff[0]; } + if(device) { *device = buff[1]; } + if(major) { *major = buff[2]; } + if(minor) { *minor = buff[3]; } + + return(state); +} + +int16_t LR11x0::getErrors(uint16_t* err) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_ERRORS, false, buff, sizeof(buff)); + + // pass the replies + if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + + return(state); +} + +int16_t LR11x0::clearErrors(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_ERRORS, true, NULL, 0)); +} + +int16_t LR11x0::calibrate(uint8_t params) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIBRATE, true, ¶ms, 1)); +} + +int16_t LR11x0::setRegMode(uint8_t mode) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_REG_MODE, true, &mode, 1)); +} + +int16_t LR11x0::calibrateImageRejection(float freqMin, float freqMax) { + uint8_t buff[2] = { + (uint8_t)floor((freqMin - 1.0f) / 4.0f), + (uint8_t)ceil((freqMax + 1.0f) / 4.0f) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) { + uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setDioIrqParams(uint32_t irq1, uint32_t irq2) { + uint8_t buff[8] = { + (uint8_t)((irq1 >> 24) & 0xFF), (uint8_t)((irq1 >> 16) & 0xFF), (uint8_t)((irq1 >> 8) & 0xFF), (uint8_t)(irq1 & 0xFF), + (uint8_t)((irq2 >> 24) & 0xFF), (uint8_t)((irq2 >> 16) & 0xFF), (uint8_t)((irq2 >> 8) & 0xFF), (uint8_t)(irq2 & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setDioIrqParams(uint32_t irq) { + return(setDioIrqParams(irq, this->gnss ? 0 : irq)); +} + +int16_t LR11x0::clearIrqState(uint32_t irq) { + uint8_t buff[4] = { + (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, true, buff, sizeof(buff))); +} + +int16_t LR11x0::configLfClock(uint8_t setup) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK, true, &setup, 1)); +} + +int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) { + uint8_t buff[4] = { + tune, (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TCXO_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::reboot(bool stay) { + uint8_t buff[1] = { (uint8_t)(stay*3) }; + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false)); +} + +int16_t LR11x0::getVbat(float* vbat) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VBAT, false, buff, sizeof(buff)); + + // pass the replies + if(vbat) { *vbat = (((float)buff[0]/51.0f) - 1.0f)*1.35f; } + + return(state); +} + +int16_t LR11x0::getTemp(float* temp) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_TEMP, false, buff, sizeof(buff)); + + // pass the replies + if(temp) { + uint16_t raw = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; + raw = raw & 0x07FF; //According LR1121 datasheet we need [0..10] bits + *temp = 25.0f - (1000.0f/1.7f)*(((float)raw/2047.0f)*1.35f - 0.7295f); //According LR1121 datasheet 1.35 + } + + return(state); +} + +int16_t LR11x0::setFs(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_FS, true, NULL, 0)); +} + +int16_t LR11x0::getRandomNumber(uint32_t* rnd) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff)); + + // pass the replies + if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + + return(state); +} + +int16_t LR11x0::eraseInfoPage(void) { + // only page 1 can be erased + uint8_t buff[1] = { RADIOLIB_LR11X0_INFO_PAGE }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + size_t buffLen = sizeof(uint8_t) + sizeof(uint16_t) + len*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint8_t) + sizeof(uint16_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set the address + dataBuff[0] = RADIOLIB_LR11X0_INFO_PAGE; + dataBuff[1] = (uint8_t)((addr >> 8) & 0xFF); + dataBuff[2] = (uint8_t)(addr & 0xFF); + + // convert endians + for(size_t i = 0; i < len; i++) { + dataBuff[3 + i] = (uint8_t)((data[i] >> 24) & 0xFF); + dataBuff[4 + i] = (uint8_t)((data[i] >> 16) & 0xFF); + dataBuff[5 + i] = (uint8_t)((data[i] >> 8) & 0xFF); + dataBuff[6 + i] = (uint8_t)(data[i] & 0xFF); + } + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen); + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::readInfoPage(uint16_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[4] = { + RADIOLIB_LR11X0_INFO_PAGE, + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_INFO_PAGE, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + + // convert endians + if(data && (state == RADIOLIB_ERR_NONE)) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + + return(state); +} + +int16_t LR11x0::getChipEui(uint8_t* eui) { + RADIOLIB_ASSERT_PTR(eui); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::getSemtechJoinEui(uint8_t* eui) { + RADIOLIB_ASSERT_PTR(eui); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::deriveRootKeysAndGetPin(uint8_t* pin) { + RADIOLIB_ASSERT_PTR(pin); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); +} + +int16_t LR11x0::enableSpiCrc(bool en) { + // TODO implement this + (void)en; + // LR11X0 CRC is gen 0xA6 (0x65 but reflected), init 0xFF, input and result reflected + /*RadioLibCRCInstance.size = 8; + RadioLibCRCInstance.poly = 0xA6; + RadioLibCRCInstance.init = 0xFF; + RadioLibCRCInstance.out = 0x00; + RadioLibCRCInstance.refIn = true; + RadioLibCRCInstance.refOut = true;*/ + return(RADIOLIB_ERR_UNSUPPORTED); +} + +int16_t LR11x0::driveDiosInSleepMode(bool en) { + uint8_t buff[1] = { (uint8_t)en }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::resetStats(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_RESET_STATS, true, NULL, 0)); +} + +int16_t LR11x0::getStats(uint16_t* nbPktReceived, uint16_t* nbPktCrcError, uint16_t* data1, uint16_t* data2) { + uint8_t buff[8] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_STATS, false, buff, sizeof(buff)); + + // pass the replies + if(nbPktReceived) { *nbPktReceived = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(nbPktCrcError) { *nbPktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(data1) { *data1 = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + if(data2) { *data2 = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } + + return(state); +} + +int16_t LR11x0::getPacketType(uint8_t* type) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE, false, buff, sizeof(buff)); + + // pass the replies + if(type) { *type = buff[0]; } + + return(state); +} + +int16_t LR11x0::getRxBufferStatus(uint8_t* len, uint8_t* startOffset) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(len) { *len = buff[0]; } + if(startOffset) { *startOffset = buff[1]; } + + return(state); +} + +int16_t LR11x0::getPacketStatusLoRa(float* rssiPkt, float* snrPkt, float* signalRssiPkt) { + uint8_t buff[3] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(rssiPkt) { *rssiPkt = (float)buff[0] / -2.0f; } + if(snrPkt) { *snrPkt = (float)((int8_t)buff[1]) / 4.0f; } + if(signalRssiPkt) { *signalRssiPkt = buff[2]; } + + return(state); +} + +int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rxLen, uint8_t* stat) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; } + if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; } + if(rxLen) { *rxLen = buff[2]; } + if(stat) { *stat = buff[3]; } + + return(state); +} + +int16_t LR11x0::getRssiInst(float* rssi) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RSSI_INST, false, buff, sizeof(buff)); + + // pass the replies + if(rssi) { *rssi = (float)buff[0] / -2.0f; } + + return(state); +} + +int16_t LR11x0::setGfskSyncWord(uint8_t* sync) { + RADIOLIB_ASSERT_PTR(sync); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)); +} + +int16_t LR11x0::setLoRaPublicNetwork(bool pub) { + uint8_t buff[1] = { (uint8_t)pub }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRx(uint32_t timeout) { + uint8_t buff[3] = { + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setTx(uint32_t timeout) { + uint8_t buff[3] = { + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRfFrequency(uint32_t rfFreq) { + uint8_t buff[4] = { + (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF), + (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff))); +} + +int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) { + uint8_t buff[7] = { + (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), intMode, + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_AUTO_TX_RX, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setCadParams(uint8_t symNum, uint8_t detPeak, uint8_t detMin, uint8_t cadExitMode, uint32_t timeout) { + uint8_t buff[7] = { + symNum, detPeak, detMin, cadExitMode, + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketType(uint8_t type) { + uint8_t buff[1] = { type }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsLoRa(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { + // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + if(symbolLength >= 16.0f) { + this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_ENABLED; + } else { + this->ldrOptimize = RADIOLIB_LR11X0_LORA_LDRO_DISABLED; + } + } else { + this->ldrOptimize = ldro; + } + + uint8_t buff[4] = { sf, bw, cr, this->ldrOptimize }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsGFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { + uint8_t buff[10] = { + (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF), + (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh, rxBw, + (uint8_t)((freqDev >> 24) & 0xFF), (uint8_t)((freqDev >> 16) & 0xFF), + (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsLrFhss(uint32_t br, uint8_t sh) { + uint8_t buff[5] = { + (uint8_t)((br >> 24) & 0xFF), (uint8_t)((br >> 16) & 0xFF), + (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setModulationParamsSigfox(uint32_t br, uint8_t sh) { + // same as for LR-FHSS + return(this->setModulationParamsLrFhss(br, sh)); +} + +int16_t LR11x0::setPacketParamsLoRa(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) { + uint8_t buff[6] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + hdrType, payloadLen, crcType, invertIQ + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketParamsGFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t syncWordLen, uint8_t addrCmp, uint8_t packType, uint8_t payloadLen, uint8_t crcType, uint8_t whiten) { + uint8_t buff[9] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + preambleDetectorLen, syncWordLen, addrCmp, packType, payloadLen, crcType, whiten + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketParamsSigfox(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t bitNum) { + uint8_t buff[7] = { + payloadLen, (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF), + (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF), + (uint8_t)((bitNum >> 8) & 0xFF), (uint8_t)(bitNum & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setTxParams(int8_t pwr, uint8_t ramp) { + uint8_t buff[2] = { (uint8_t)pwr, ramp }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPacketAdrs(uint8_t node, uint8_t broadcast) { + uint8_t buff[2] = { node, broadcast }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRxTxFallbackMode(uint8_t mode) { + uint8_t buff[1] = { mode }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, uint8_t mode) { + uint8_t buff[7] = { + (uint8_t)((rxPeriod >> 16) & 0xFF), (uint8_t)((rxPeriod >> 8) & 0xFF), (uint8_t)(rxPeriod & 0xFF), + (uint8_t)((sleepPeriod >> 16) & 0xFF), (uint8_t)((sleepPeriod >> 8) & 0xFF), (uint8_t)(sleepPeriod & 0xFF), + mode + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setPaConfig(uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel) { + uint8_t buff[4] = { paSel, regPaSupply, paDutyCycle, paHpSel }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_PA_CONFIG, true, buff, sizeof(buff))); +} + +int16_t LR11x0::stopTimeoutOnPreamble(bool stop) { + uint8_t buff[1] = { (uint8_t)stop }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setCad(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_CAD, true, NULL, 0)); +} + +int16_t LR11x0::setTxCw(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_CW, true, NULL, 0)); +} + +int16_t LR11x0::setTxInfinitePreamble(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE, true, NULL, 0)); +} + +int16_t LR11x0::setLoRaSynchTimeout(uint8_t symbolNum) { + uint8_t buff[1] = { symbolNum }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) { + uint8_t buff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), checkLen + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRangingReqAddr(uint32_t addr) { + uint8_t buff[4] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff))); +} + +int16_t LR11x0::getRangingResult(uint8_t type, float* res) { + uint8_t reqBuff[1] = { type }; + uint8_t rplBuff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(res) { + if(type == RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE) { + uint32_t raw = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; + *res = ((float)(raw*3e8))/((float)(4096*this->bandwidthKhz*1000)); + } else { + *res = (float)rplBuff[3]/2.0f; + } + } + + return(state); +} + +int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) { + uint8_t buff[4] = { + (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF), + (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) { + uint8_t buff[8] = { + (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF), + (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), + (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF), + (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff))); + +} + +int16_t LR11x0::setGfskWhitParams(uint16_t seed) { + uint8_t buff[2] = { + (uint8_t)((seed >> 8) & 0xFF), (uint8_t)(seed & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRangingParameter(uint8_t symbolNum) { + // the first byte is reserved + uint8_t buff[2] = { 0x00, symbolNum }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setRssiCalibration(const int8_t* tune, int16_t gainOffset) { + uint8_t buff[11] = { + (uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4), + (uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4), + (uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4), + (uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4), + (uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4), + (uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4), + (uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4), + (uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4), + (uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4), + (uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff))); +} + +int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { + uint8_t buff[1] = { sync }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff))); +} + +int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len) { + // check maximum size + const uint8_t maxLen[4][4] = { + { 189, 178, 167, 155, }, + { 151, 142, 133, 123, }, + { 112, 105, 99, 92, }, + { 74, 69, 65, 60, }, + }; + if((cr > RADIOLIB_LR11X0_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t buffLen = 9 + len; + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[9 + 190]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set properties of the packet + dataBuff[0] = hdrCount; + dataBuff[1] = cr; + dataBuff[2] = RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK; + dataBuff[3] = grid; + dataBuff[4] = (uint8_t)hop; + dataBuff[5] = bw; + dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01); + dataBuff[7] = (uint8_t)(hopSeq & 0xFF); + dataBuff[8] = devOffset; + memcpy(&dataBuff[9], payload, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen); + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) { + uint8_t buff[4] = { + (uint8_t)((sync >> 24) & 0xFF), (uint8_t)((sync >> 16) & 0xFF), + (uint8_t)((sync >> 8) & 0xFF), (uint8_t)(sync & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, true, buff, sizeof(buff))); +} + +int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len) { + return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len)); +} + +int16_t LR11x0::getLoRaRxHeaderInfos(uint8_t* info) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff)); + + // pass the replies + if(info) { *info = buff[0]; } + + return(state); +} + +int16_t LR11x0::bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len) { + return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND, chan, payload, len)); +} + +int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len) { + // check maximum size + // TODO what is the actual maximum? + if(len > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[sizeof(uint8_t) + len]; + #endif + + // set the channel + dataBuff[0] = chan; + memcpy(&dataBuff[1], payload, len); + + int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len); + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::bootEraseFlash(void) { + // erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds + RadioLibTime_t timeout = this->mod->spiConfig.timeout; + this->mod->spiConfig.timeout = 3000; + int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false); + this->mod->spiConfig.timeout = timeout; + return(state); +} + +int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); +} + +int16_t LR11x0::bootReboot(bool stay) { + uint8_t buff[1] = { (uint8_t)stay }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::bootGetPin(uint8_t* pin) { + RADIOLIB_ASSERT_PTR(pin); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_PIN, false, pin, RADIOLIB_LR11X0_PIN_LEN)); +} + +int16_t LR11x0::bootGetChipEui(uint8_t* eui) { + RADIOLIB_ASSERT_PTR(eui); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { + RADIOLIB_ASSERT_PTR(eui); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); +} + +int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set the address or offset + dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF); + dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF); + dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF); + dataBuff[3] = (uint8_t)(addrOffset & 0xFF); + + // convert endians + for(size_t i = 0; i < len; i++) { + uint32_t bin = 0; + if(nonvolatile) { + uint32_t* ptr = const_cast(data) + i; + bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr); + } else { + bin = data[i]; + } + dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF); + dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF); + dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF); + dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); + } + + int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +#endif diff --git a/src/modules/LR11x0/LR11x0_crypto.cpp b/src/modules/LR11x0/LR11x0_crypto.cpp new file mode 100644 index 0000000000..6d58662273 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_crypto.cpp @@ -0,0 +1,231 @@ +#include "LR11x0.h" + +#include "../../utils/Cryptography.h" +#include + +#if !RADIOLIB_EXCLUDE_LR11X0 + +int16_t LR11x0::cryptoSetKey(uint8_t keyId, const uint8_t* key) { + RADIOLIB_ASSERT_PTR(key); + uint8_t buff[1 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; + buff[0] = keyId; + memcpy(&buff[1], key, RADIOLIB_AES128_KEY_SIZE); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY, false, buff, sizeof(buff))); +} + +int16_t LR11x0::cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, const uint8_t* key) { + RADIOLIB_ASSERT_PTR(key); + uint8_t buff[2 + RADIOLIB_AES128_KEY_SIZE] = { 0 }; + buff[0] = srcKeyId; + buff[1] = dstKeyId; + memcpy(&buff[2], key, RADIOLIB_AES128_KEY_SIZE); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY, false, buff, sizeof(buff))); +} + +int16_t LR11x0::cryptoProcessJoinAccept(uint8_t decKeyId, uint8_t verKeyId, uint8_t lwVer, const uint8_t* header, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { + // calculate buffer sizes + size_t headerLen = 1; + if(lwVer) { + headerLen += 11; // LoRaWAN 1.1 header is 11 bytes longer than 1.0 + } + size_t reqLen = 3*sizeof(uint8_t) + headerLen + len; + size_t rplLen = sizeof(uint8_t) + len; + + // build buffers + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + uint8_t* rplBuff = new uint8_t[rplLen]; + #endif + + // set the request fields + reqBuff[0] = decKeyId; + reqBuff[1] = verKeyId; + reqBuff[2] = lwVer; + memcpy(&reqBuff[3], header, headerLen); + memcpy(&reqBuff[3 + headerLen], dataIn, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT, false, rplBuff, rplLen, reqBuff, reqLen); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + if(state != RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); + } + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + // pass the data + memcpy(dataOut, &rplBuff[1], len); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); +} + +int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, const uint8_t* data, size_t len, uint32_t* mic) { + size_t reqLen = sizeof(uint8_t) + len; + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[sizeof(uint8_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + #endif + uint8_t rplBuff[5] = { 0 }; + + reqBuff[0] = keyId; + memcpy(&reqBuff[1], data, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + if(mic) { *mic = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } + return(state); +} + +int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, const uint8_t* data, size_t len, bool* result) { + size_t reqLen = sizeof(uint8_t) + sizeof(uint32_t) + len; + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[sizeof(uint8_t) + sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[reqLen]; + #endif + uint8_t rplBuff[1] = { 0 }; + + reqBuff[0] = keyId; + reqBuff[1] = (uint8_t)((micExp >> 24) & 0xFF); + reqBuff[2] = (uint8_t)((micExp >> 16) & 0xFF); + reqBuff[3] = (uint8_t)((micExp >> 8) & 0xFF); + reqBuff[4] = (uint8_t)(micExp & 0xFF); + memcpy(&reqBuff[5], data, len); + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + if(result) { *result = (rplBuff[0] == RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS); } + return(state); +} + +int16_t LR11x0::cryptoAesEncrypt01(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { + return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01, keyId, dataIn, len, dataOut)); +} + +int16_t LR11x0::cryptoAesEncrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { + return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT, keyId, dataIn, len, dataOut)); +} + +int16_t LR11x0::cryptoAesDecrypt(uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { + return(this->cryptoCommon(RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT, keyId, dataIn, len, dataOut)); +} + +int16_t LR11x0::cryptoStoreToFlash(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH, true, NULL, 0)); +} + +int16_t LR11x0::cryptoRestoreFromFlash(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH, true, NULL, 0)); +} + +int16_t LR11x0::cryptoSetParam(uint8_t id, uint32_t value) { + uint8_t buff[5] = { + id, + (uint8_t)((value >> 24) & 0xFF), (uint8_t)((value >> 16) & 0xFF), + (uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM, true, buff, sizeof(buff))); +} + +int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) { + uint8_t reqBuff[1] = { id }; + uint8_t rplBuff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + if(value) { *value = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } + return(state); +} + +int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile) { + // check maximum size + if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); +} + +int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT, false, buff, sizeof(buff)); + + // pass the replies + if(result) { *result = (bool)buff[0]; } + + return(state); +} + +int16_t LR11x0::cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut) { + // build buffers + #if RADIOLIB_STATIC_ONLY + uint8_t reqBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + uint8_t rplBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* reqBuff = new uint8_t[sizeof(uint8_t) + len]; + uint8_t* rplBuff = new uint8_t[sizeof(uint8_t) + len]; + #endif + + // set the request fields + reqBuff[0] = keyId; + memcpy(&reqBuff[1], dataIn, len); + + int16_t state = this->SPIcommand(cmd, false, rplBuff, sizeof(uint8_t) + len, reqBuff, sizeof(uint8_t) + len); + #if !RADIOLIB_STATIC_ONLY + delete[] reqBuff; + #endif + if(state != RADIOLIB_ERR_NONE) { + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); + } + + // check the crypto engine state + if(rplBuff[0] != RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Crypto Engine error: %02x", rplBuff[0]); + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } + + // pass the data + memcpy(dataOut, &rplBuff[1], len); + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + return(state); +} + +#endif diff --git a/src/modules/LR11x0/LR11x0_gnss.cpp b/src/modules/LR11x0/LR11x0_gnss.cpp new file mode 100644 index 0000000000..25028378f4 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_gnss.cpp @@ -0,0 +1,757 @@ +#include "LR11x0.h" + +#include + +#if !RADIOLIB_EXCLUDE_LR11X0 + +int16_t LR11x0::isGnssScanCapable() { + // get the version + LR11x0VersionInfo_t version; + int16_t state = this->getVersionInfo(&version); + RADIOLIB_ASSERT(state); + + // check the device firmware version is sufficient + uint16_t versionFull = ((uint16_t)version.fwMajor << 8) | (uint16_t)version.fwMinor; + state = RADIOLIB_ERR_UNSUPPORTED; + if((version.device == RADIOLIB_LR11X0_DEVICE_LR1110) && (versionFull >= 0x0401)) { + state = RADIOLIB_ERR_NONE; + } else if((version.device == RADIOLIB_LR11X0_DEVICE_LR1120) && (versionFull >= 0x0201)) { + state = RADIOLIB_ERR_NONE; + } + RADIOLIB_ASSERT(state); + + // in debug mode, dump the almanac + #if RADIOLIB_DEBUG_PROTOCOL + uint32_t addr = 0; + uint16_t sz = 0; + state = this->gnssAlmanacReadAddrSize(&addr, &sz); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac@%08x, %d bytes", addr, sz); + uint32_t buff[32] = { 0 }; + while(sz > 0) { + size_t len = sz > 32 ? 32 : sz/sizeof(uint32_t); + state = this->readRegMem32(addr, buff, len); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_HEXDUMP(NULL, reinterpret_cast(buff), len*sizeof(uint32_t), addr); + addr += len*sizeof(uint32_t); + sz -= len*sizeof(uint32_t); + } + + uint8_t almanac[22] = { 0 }; + for(uint8_t i = 0; i < 128; i++) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Almanac[%d]:", i); + state = this->gnssAlmanacReadSV(i, almanac); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_HEXDUMP(NULL, almanac, 22); + } + + #endif + + return(state); +} + +int16_t LR11x0::gnssScan(LR11x0GnssResult_t* res) { + RADIOLIB_ASSERT_PTR(res); + + // go to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT); + RADIOLIB_ASSERT(state); + + // set scan mode (single vs multiple) + state = this->gnssSetMode(0x03); + RADIOLIB_ASSERT(state); + + // set RF switch + this->mod->setRfSwitchState(LR11x0::MODE_GNSS); + + // start scan with high effort + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan start"); + state = this->gnssPerformScan(RADIOLIB_LR11X0_GNSS_EFFORT_MID, 0x3C, 16); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout + // this can take very long if both GPS and BeiDou are enabled + RadioLibTime_t softTimeout = 300UL * 1000UL; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + this->gnssAbort(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); + } + } + + // restore the switch + this->mod->setRfSwitchState(Module::MODE_IDLE); + RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags + uint32_t irq = this->getIrqStatus(); + this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); + if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // retrieve the demodulator status + uint8_t info = 0; + state = this->gnssReadDemodStatus(&res->demodStat, &info); + RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_BASIC_PRINTLN("Demod status %d, info %02x", (int)res->demodStat, (unsigned int)info); + + // retrieve the number of detected satellites + state = this->gnssGetNbSvDetected(&res->numSatsDet); + RADIOLIB_ASSERT(state); + + // retrieve the result size + state = this->gnssGetResultSize(&res->resSize); + RADIOLIB_ASSERT(state); + + // check and return demodulator status + if(res->demodStat < RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND) { + return(RADIOLIB_ERR_GNSS_DEMOD(res->demodStat)); + } + + return(state); +} + +int16_t LR11x0::getGnssAlmanacStatus(LR11x0GnssAlmanacStatus_t *stat) { + RADIOLIB_ASSERT_PTR(stat); + + // save the time the time until subframe is relative to + stat->start = this->mod->hal->millis(); + + // get the raw data + uint8_t raw[53] = { 0 }; + int16_t state = this->gnssReadAlmanacStatus(raw); + RADIOLIB_ASSERT(state); + + // parse the reply + stat->gps.status = (int8_t)raw[0]; + stat->gps.timeUntilSubframe = ((uint32_t)(raw[1]) << 24) | ((uint32_t)(raw[2]) << 16) | ((uint32_t)(raw[3]) << 8) | (uint32_t)raw[4]; + stat->gps.numSubframes = raw[5]; + stat->gps.nextSubframe4SvId = raw[6]; + stat->gps.nextSubframe5SvId = raw[7]; + stat->gps.nextSubframeStart = raw[8]; + stat->gps.numUpdateNeeded = raw[9]; + stat->gps.flagsUpdateNeeded[0] = ((uint32_t)(raw[10]) << 24) | ((uint32_t)(raw[11]) << 16) | ((uint32_t)(raw[12]) << 8) | (uint32_t)raw[13]; + stat->gps.flagsActive[0] = ((uint32_t)(raw[14]) << 24) | ((uint32_t)(raw[15]) << 16) | ((uint32_t)(raw[16]) << 8) | (uint32_t)raw[17]; + stat->beidou.status = (int8_t)raw[18]; + stat->beidou.timeUntilSubframe = ((uint32_t)(raw[19]) << 24) | ((uint32_t)(raw[20]) << 16) | ((uint32_t)(raw[21]) << 8) | (uint32_t)raw[22]; + stat->beidou.numSubframes = raw[23]; + stat->beidou.nextSubframe4SvId = raw[24]; + stat->beidou.nextSubframe5SvId = raw[25]; + stat->beidou.nextSubframeStart = raw[26]; + stat->beidou.numUpdateNeeded = raw[27]; + stat->beidou.flagsUpdateNeeded[0] = ((uint32_t)(raw[28]) << 24) | ((uint32_t)(raw[29]) << 16) | ((uint32_t)(raw[30]) << 8) | (uint32_t)raw[31]; + stat->beidou.flagsUpdateNeeded[1] = ((uint32_t)(raw[32]) << 24) | ((uint32_t)(raw[33]) << 16) | ((uint32_t)(raw[34]) << 8) | (uint32_t)raw[35]; + stat->beidou.flagsActive[0] = ((uint32_t)(raw[36]) << 24) | ((uint32_t)(raw[37]) << 16) | ((uint32_t)(raw[38]) << 8) | (uint32_t)raw[39]; + stat->beidou.flagsActive[1] = ((uint32_t)(raw[40]) << 24) | ((uint32_t)(raw[41]) << 16) | ((uint32_t)(raw[42]) << 8) | (uint32_t)raw[43]; + stat->beidouSvNoAlmanacFlags[0] = ((uint32_t)(raw[44]) << 24) | ((uint32_t)(raw[45]) << 16) | ((uint32_t)(raw[46]) << 8) | (uint32_t)raw[47]; + stat->beidouSvNoAlmanacFlags[1] = ((uint32_t)(raw[18]) << 24) | ((uint32_t)(raw[49]) << 16) | ((uint32_t)(raw[50]) << 8) | (uint32_t)raw[51]; + stat->nextAlmanacId = raw[52]; + + return(state); +} + +int16_t LR11x0::gnssDelayUntilSubframe(LR11x0GnssAlmanacStatus_t *stat, uint8_t constellation) { + RADIOLIB_ASSERT_PTR(stat); + + // almanac update has to be called at least 1.3 seconds before the subframe + // we use 2.3 seconds to be on the safe side + + // calculate absolute times + RadioLibTime_t window = stat->start + stat->gps.timeUntilSubframe - 2300; + if(constellation == RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU) { + window = stat->start + stat->beidou.timeUntilSubframe - 2300; + } + RadioLibTime_t now = this->mod->hal->millis(); + if(now > window) { + // we missed the window + return(RADIOLIB_ERR_GNSS_SUBFRAME_NOT_AVAILABLE); + } + + RadioLibTime_t delay = window - now; + RADIOLIB_DEBUG_BASIC_PRINTLN("Time until subframe %lu ms", delay); + this->mod->hal->delay(delay); + return(RADIOLIB_ERR_NONE); +} + +// TODO fix last satellite always out of date +int16_t LR11x0::updateGnssAlmanac(uint8_t constellation) { + int16_t state = this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_GNSS_DONE | RADIOLIB_LR11X0_IRQ_GNSS_ABORT); + RADIOLIB_ASSERT(state); + + state = this->gnssAlmanacUpdateFromSat(RADIOLIB_LR11X0_GNSS_EFFORT_MID, constellation); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout, assumes 2 subframes and up to 2.3s pre-roll + uint32_t softTimeout = 16UL * 1000UL; + uint32_t start = this->mod->hal->millis(); + while (!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + this->gnssAbort(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for almanac update"); + } + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("GPS almanac update done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + // distinguish between GNSS-done and GNSS-abort outcomes and clear the flags + uint32_t irq = this->getIrqStatus(); + this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); + if(irq & RADIOLIB_LR11X0_IRQ_GNSS_ABORT) { + state = RADIOLIB_ERR_RX_TIMEOUT; + } + + return(state); +} + +int16_t LR11x0::getGnssPosition(LR11x0GnssPosition_t* pos, bool filtered) { + RADIOLIB_ASSERT_PTR(pos); + + uint8_t error = 0; + int16_t state; + if(filtered) { + state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, NULL, NULL, NULL, NULL, &pos->latitude, &pos->longitude, &pos->accuracy, NULL); + } else { + state = this->gnssReadDopplerSolverRes(&error, &pos->numSatsUsed, &pos->latitude, &pos->longitude, &pos->accuracy, NULL, NULL, NULL, NULL, NULL); + } + RADIOLIB_ASSERT(state); + + // check the solver error + if(error != 0) { + return(RADIOLIB_ERR_GNSS_SOLVER(error)); + } + + return(state); +} + +int16_t LR11x0::getGnssSatellites(LR11x0GnssSatellite_t* sats, uint8_t numSats) { + RADIOLIB_ASSERT_PTR(sats); + if(numSats >= 32) { + return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t svId[32] = { 0 }; + uint8_t snr[32] = { 0 }; + int16_t doppler[32] = { 0 }; + int16_t state = this->gnssGetSvDetected(svId, snr, doppler, numSats); + RADIOLIB_ASSERT(state); + for(size_t i = 0; i < numSats; i++) { + sats[i].svId = svId[i]; + sats[i].c_n0 = snr[i] + 31; + sats[i].doppler = doppler[i]; + } + + return(state); +} + +int16_t LR11x0::gnssReadRssi(int8_t* rssi) { + uint8_t reqBuff[1] = { 0x09 }; // some undocumented magic byte, from the official driver + uint8_t rplBuff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + if(rssi) { *rssi = rplBuff[1]; } + return(state); +} + +int16_t LR11x0::gnssSetConstellationToUse(uint8_t mask) { + uint8_t buff[1] = { mask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadConstellationToUse(uint8_t* mask) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE, false, buff, sizeof(buff)); + + // pass the replies + if(mask) { *mask = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssSetAlmanacUpdate(uint8_t mask) { + uint8_t buff[1] = { mask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAlmanacUpdate(uint8_t* mask) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE, false, buff, sizeof(buff)); + + // pass the replies + if(mask) { *mask = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssSetFreqSearchSpace(uint8_t freq) { + uint8_t buff[1] = { freq }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadFreqSearchSpace(uint8_t* freq) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE, false, buff, sizeof(buff)); + if(freq) { *freq = buff[0]; } + return(state); +} + +int16_t LR11x0::gnssReadVersion(uint8_t* fw, uint8_t* almanac) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION, false, buff, sizeof(buff)); + + // pass the replies + if(fw) { *fw = buff[0]; } + if(almanac) { *almanac = buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadSupportedConstellations(uint8_t* mask) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS, false, buff, sizeof(buff)); + + // pass the replies + if(mask) { *mask = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssSetMode(uint8_t mode) { + uint8_t buff[1] = { mode }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_MODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAutonomous(uint32_t gpsTime, uint8_t resMask, uint8_t nbSvMask) { + uint8_t buff[7] = { + (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF), + (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF), + RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE, resMask, nbSvMask + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAssisted(uint32_t gpsTime, uint8_t effort, uint8_t resMask, uint8_t nbSvMask) { + uint8_t buff[7] = { + (uint8_t)((gpsTime >> 24) & 0xFF), (uint8_t)((gpsTime >> 16) & 0xFF), + (uint8_t)((gpsTime >> 8) & 0xFF), (uint8_t)(gpsTime & 0xFF), + effort, resMask, nbSvMask + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ASSISTED, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssSetAssistancePosition(float lat, float lon) { + int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; + int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; + uint8_t buff[4] = { + (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), + (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAssistancePosition(float* lat, float* lon) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION, false, buff, sizeof(buff)); + + // pass the replies + if(lat) { + int16_t latRaw = ((int16_t)(buff[0]) << 8) | (int16_t)(buff[1]); + *lat = ((float)latRaw*90.0f)/2048.0f; + } + if(lon) { + int16_t lonRaw = ((int16_t)(buff[2]) << 8) | (int16_t)(buff[3]); + *lon = ((float)lonRaw*180.0f)/2048.0f; + } + + return(state); +} + +int16_t LR11x0::gnssPushSolverMsg(uint8_t* payload, size_t len) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG, true, payload, len)); +} + +int16_t LR11x0::gnssPushDmMsg(uint8_t* payload, size_t len) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG, true, payload, len)); +} + +int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, uint8_t* errCode, uint8_t* almUpdMask, uint8_t* freqSpace) { + // send the command - datasheet here shows extra bytes being sent in the request + // but doing that fails so treat it like any other read command + uint8_t buff[9] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(fwVersion) { *fwVersion = buff[2]; } + if(almanacCrc) { *almanacCrc = ((uint32_t)(buff[3]) << 24) | ((uint32_t)(buff[4]) << 16) | ((uint32_t)(buff[5]) << 8) | (uint32_t)buff[6]; } + if(errCode) { *errCode = (buff[7] & 0xF0) >> 4; } + if(almUpdMask) { *almUpdMask = (buff[7] & 0x0E) >> 1; } + if(freqSpace) { *freqSpace = ((buff[7] & 0x01) << 1) | ((buff[8] & 0x80) >> 7); } + + return(state); +} + +int16_t LR11x0::gnssGetNbSvDetected(uint8_t* nbSv) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED, false, buff, sizeof(buff)); + + // pass the replies + if(nbSv) { *nbSv = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, int16_t* doppler, size_t nbSv) { + // TODO this is arbitrary - is there an actual maximum? + if(nbSv > RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t)) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t buffLen = nbSv*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED, false, dataBuff, buffLen); + if(state == RADIOLIB_ERR_NONE) { + for(size_t i = 0; i < nbSv; i++) { + if(svId) { svId[i] = dataBuff[4*i]; } + if(snr) { snr[i] = dataBuff[4*i + 1]; } + if(doppler) { doppler[i] = ((uint16_t)(dataBuff[4*i + 2]) << 8) | (uint16_t)dataBuff[4*i + 3]; } + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + +int16_t LR11x0::gnssGetConsumption(uint32_t* cpu, uint32_t* radio) { + uint8_t buff[8] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION, false, buff, sizeof(buff)); + + // pass the replies + if(cpu) { *cpu = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + if(radio) { *radio = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } + + return(state); +} + +int16_t LR11x0::gnssGetResultSize(uint16_t* size) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE, false, buff, sizeof(buff)); + + // pass the replies + if(size) { *size = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadResults(uint8_t* result, uint16_t size) { + RADIOLIB_ASSERT_PTR(result); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS, false, result, size)); +} + +int16_t LR11x0::gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc) { + uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { + RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID, + (uint8_t)((date >> 8) & 0xFF), (uint8_t)(date & 0xFF), + (uint8_t)((globalCrc >> 24) & 0xFF), (uint8_t)((globalCrc >> 16) & 0xFF), + (uint8_t)((globalCrc >> 8) & 0xFF), (uint8_t)(globalCrc & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAlmanacFullUpdateSV(uint8_t svn, const uint8_t* svnAlmanac) { + uint8_t buff[RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE] = { svn }; + memcpy(&buff[1], svnAlmanac, RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE - 1); + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssAlmanacReadAddrSize(uint32_t* addr, uint16_t* size) { + uint8_t buff[6] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE, false, buff, sizeof(buff)); + + if(addr) { *addr = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + if(size) { *size = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + + return(state); +} + +int16_t LR11x0::gnssAlmanacReadSV(uint8_t svId, uint8_t* almanac) { + uint8_t reqBuff[2] = { svId, 0x01 }; // in theory multiple SV entries can be read at the same time, but we don't need that + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE, false, almanac, 22, reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + return(state); +} + +int16_t LR11x0::gnssGetNbSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv) { + int16_t latRaw = (lat*2048.0f)/90.0f + 0.5f; + int16_t lonRaw = (lon*2048.0f)/180.0f + 0.5f; + uint8_t reqBuff[9] = { + (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), + (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), + (uint8_t)((latRaw >> 8) & 0xFF), (uint8_t)(latRaw & 0xFF), + (uint8_t)((lonRaw >> 8) & 0xFF), (uint8_t)(lonRaw & 0xFF), + constellation, + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::gnssGetSvVisible(uint8_t nbSv, uint8_t** svId, int16_t** doppler, int16_t** dopplerErr) { + // enforce a maximum of 12 SVs + if(nbSv > 12) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + uint8_t buff[60] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER, false, buff, sizeof(buff)); + for(uint8_t i = 0; i < nbSv; i++) { + if(svId && svId[i]) { *svId[i] = buff[i*12]; } + if(doppler && doppler[i]) { *doppler[i] = ((uint16_t)(buff[i*12 + 1]) << 8) | (uint16_t)buff[i*12 + 2]; } + if(dopplerErr && dopplerErr[i]) { *dopplerErr[i] = ((uint16_t)(buff[i*12 + 3]) << 8) | (uint16_t)buff[i*12 + 4]; } + } + + return(state); +} + +int16_t LR11x0::gnssPerformScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) { + uint8_t buff[3] = { effort, resMask, nbSvMax }; + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_SCAN, buff, sizeof(buff), false, false)); +} + +int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED, false, buff, sizeof(buff)); + + // pass the replies + if(lastScanMode) { *lastScanMode = buff[0]; } + + return(state); +} + +int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) { + uint8_t buff[2] = { effort, opt }; + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, buff, sizeof(buff), false, false)); +} + +int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) { + uint8_t buff[12] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_TIME, false, buff, sizeof(buff)); + + // pass the replies + if(err) { *err = buff[0]; } + + if(time) { + *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; + *time += 2UL*1024UL*7UL*24UL*3600UL; // assume WN rollover is at 2, this will fail sometime in 2038 + *time += 315964800UL; // convert to UTC + } + + if(nbUs) { + *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; + *nbUs /= 16; + } + + if(timeAccuracy) { + *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; + *timeAccuracy /= 16; + } + + return(state); +} + +int16_t LR11x0::gnssResetTime(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME, true, NULL, 0)); +} + +int16_t LR11x0::gnssResetPosition(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0)); +} + +int16_t LR11x0::gnssReadWeekNumberRollover(uint8_t* status, uint8_t* rollover) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER, false, buff, sizeof(buff)); + if(status) { *status = buff[0]; } + if(rollover) { *rollover = buff[1]; } + return(state); +} + +int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff)); + + // pass the replies + if(status) { *status = (int8_t)buff[0]; } + if(info) { *info = buff[1]; } + + return(state); +} + +int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) { + uint8_t rplBuff[125] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING, false, rplBuff, 125); + RADIOLIB_ASSERT(state); + + // convert endians + if(timing) { + for(size_t i = 0; i < 31; i++) { + timing[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)]; + } + } + + if(constDemod) { *constDemod = rplBuff[124]; } + + return(state); +} + +int16_t LR11x0::gnssSetTime(uint32_t time, uint16_t accuracy) { + uint8_t buff[6] = { + (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), + (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), + (uint8_t)((accuracy >> 8) & 0xFF), (uint8_t)(accuracy & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_TIME, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt) { + uint8_t buff[18] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES, false, buff, sizeof(buff)); + + // pass the replies + if(error) { *error = buff[0]; } + if(nbSvUsed) { *nbSvUsed = buff[1]; } + if(lat) { + int16_t latRaw = ((int16_t)(buff[2]) << 8) | (int16_t)buff[3]; + *lat = ((float)latRaw * 90.0f)/2048.0f; + } + if(lon) { + int16_t lonRaw = ((int16_t)(buff[4]) << 8) | (int16_t)buff[5]; + *lon = ((float)lonRaw * 180.0f)/2048.0f; + } + if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } + if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; } + if(latFilt) { + int16_t latRaw = ((int16_t)(buff[10]) << 8) | (int16_t)buff[11]; + *latFilt = ((float)latRaw * 90.0f)/2048.0f; + } + if(lonFilt) { + int16_t lonRaw = ((int16_t)(buff[12]) << 8) | (int16_t)buff[13]; + *lonFilt = ((float)lonRaw * 180.0f)/2048.0f; + } + if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; } + if(xtalFilt) { *xtalFilt = ((uint16_t)(buff[16]) << 8) | (uint16_t)buff[17]; } + + return(state); +} + +int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) { + uint8_t buff[3] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP, false, buff, sizeof(buff)); + + if(delay) { *delay = ((uint32_t)(buff[0]) << 16) | ((uint32_t)(buff[1]) << 8) | (uint32_t)buff[2]; } + + return(state); +} + +int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) { + uint8_t buff[2] = { effort, bitMask }; + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, buff, sizeof(buff), false, false)); +} + +int16_t LR11x0::gnssReadKeepSyncStatus(uint8_t mask, uint8_t* nbSvVisible, uint32_t* elapsed) { + uint8_t reqBuff[1] = { mask }; + uint8_t rplBuff[5] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + if(nbSvVisible) { *nbSvVisible = rplBuff[0]; } + if(elapsed) { *elapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } + return(state); +} + +int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53)); +} + +int16_t LR11x0::gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period) { + uint8_t buff[4] = { bitMask, svType, (uint8_t)((period >> 8) & 0xFF), (uint8_t)(period & 0xFF) }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period) { + uint8_t reqBuff[2] = { bitMask, svType }; + uint8_t rplBuff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(period) { *period = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; } + + return(state); +} + +int16_t LR11x0::gnssConfigDelayResetAP(uint32_t delay) { + uint8_t buff[3] = { (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP, true, buff, sizeof(buff))); +} + +int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat) { + uint8_t reqBuff[1] = { bitMask }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::gnssGetSvSync(uint8_t mask, uint8_t nbSv, uint8_t* syncList) { + uint8_t reqBuff[2] = { mask, nbSv }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC, false, syncList, nbSv, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) { + uint8_t reqBuff[1] = { bitMask }; + uint8_t rplBuff[5] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(nbVisSat) { *nbVisSat = rplBuff[0]; } + if(timeElapsed) { *timeElapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; } + + return(state); +} + +int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1) { + uint8_t reqBuff[1] = { bitMask }; + uint8_t rplBuff[8] = { 0 }; + size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff)); + RADIOLIB_ASSERT(state); + + if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } + if(bitMaskActivated1) { *bitMaskActivated1 = ((uint32_t)(rplBuff[4]) << 24) | ((uint32_t)(rplBuff[5]) << 16) | ((uint32_t)(rplBuff[6]) << 8) | (uint32_t)rplBuff[7]; } + + return(state); +} + +void LR11x0::gnssAbort() { + // send the abort signal (single NOP) + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; + // we need to call the most basic overload of the SPI write method otherwise the call will be ambiguous + const uint8_t cmd[2] = { 0, 0 }; + this->mod->SPIwriteStream(cmd, 2, NULL, 0, false, false); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + + // wait for at least 2.9 seconds as specified by the user manual + this->mod->hal->delay(3000); +} + +#endif diff --git a/src/modules/LR11x0/LR11x0_wifi.cpp b/src/modules/LR11x0/LR11x0_wifi.cpp new file mode 100644 index 0000000000..34362a3325 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_wifi.cpp @@ -0,0 +1,267 @@ +#include "LR11x0.h" + +#include + +#if !RADIOLIB_EXCLUDE_LR11X0 + +int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { + // LR1121 cannot do WiFi scanning + if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) { + return(RADIOLIB_ERR_UNSUPPORTED); + } + + uint8_t type; + switch(wifiType) { + case('b'): + type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_B; + break; + case('g'): + type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_G; + break; + case('n'): + type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_N; + break; + case('*'): + type = RADIOLIB_LR11X0_WIFI_SCAN_ALL; + break; + default: + return(RADIOLIB_ERR_INVALID_WIFI_TYPE); + } + + // go to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // reset cumulative timings + state = wifiResetCumulTimings(); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE); + RADIOLIB_ASSERT(state); + + // start scan with the maximum number of results and abort on timeout + this->wifiScanMode = mode; + state = wifiScan(type, chanMask, this->wifiScanMode, RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS, numScans, timeout, RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED); + return(state); +} + +void LR11x0::setWiFiScanAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void LR11x0::clearWiFiScanAction() { + this->clearIrqAction(); +} + +int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) { + // clear IRQ first, as this is likely to be called right after scan has finished + int16_t state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); + RADIOLIB_ASSERT(state); + + uint8_t buff[1] = { 0 }; + state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff)); + + // pass the replies + if(count) { *count = buff[0]; } + + return(state); +} + +int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) { + RADIOLIB_ASSERT_PTR(result); + + // read a single result + uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE; + uint8_t raw[RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN] = { 0 }; + int16_t state = wifiReadResults(index, 1, format, raw); + RADIOLIB_ASSERT(state); + + // parse the information + switch(raw[0] & 0x03) { + case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_B): + result->type = 'b'; + break; + case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_G): + result->type = 'g'; + break; + case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_N): + result->type = 'n'; + break; + } + result->dataRateId = (raw[0] & 0xFC) >> 2; + result->channelFreq = 2407 + (raw[1] & 0x0F)*5; + result->origin = (raw[1] & 0x30) >> 4; + result->ap = (raw[1] & 0x40) != 0; + result->rssi = (float)raw[2] / -2.0f;; + memcpy(result->mac, &raw[3], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + + if(!brief) { + if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) { + LR11x0WifiResultExtended_t* resultExtended = reinterpret_cast(result); + resultExtended->rate = raw[3]; + resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5])); + resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7])); + resultExtended->frameType = raw[9] & 0x03; + resultExtended->frameSubType = (raw[9] & 0x3C) >> 2; + resultExtended->toDistributionSystem = (raw[9] & 0x40) != 0; + resultExtended->fromDistributionSystem = (raw[9] & 0x80) != 0; + memcpy(resultExtended->mac0, &raw[10], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + memcpy(resultExtended->mac, &raw[16], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + memcpy(resultExtended->mac2, &raw[22], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + resultExtended->timestamp = (((uint64_t)raw[28] << 56) | ((uint64_t)raw[29] << 48)) | + (((uint64_t)raw[30] << 40) | ((uint64_t)raw[31] << 32)) | + (((uint64_t)raw[32] << 24) | ((uint64_t)raw[33] << 16)) | + (((uint64_t)raw[34] << 8) | (uint64_t)raw[35]); + resultExtended->periodBeacon = (((uint16_t)raw[36] << 8) | ((uint16_t)raw[37])) * 1024UL; + resultExtended->seqCtrl = (((uint16_t)raw[38] << 8) | ((uint16_t)raw[39])); + memcpy(resultExtended->ssid, &raw[40], RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN); + resultExtended->currentChannel = raw[72]; + memcpy(resultExtended->countryCode, &raw[73], 2); + resultExtended->countryCode[2] = '\0'; + resultExtended->ioReg = raw[75]; + resultExtended->fcsCheckOk = (raw[76] != 0); + resultExtended->phiOffset = (((uint16_t)raw[77] << 8) | ((uint16_t)raw[78])); + return(RADIOLIB_ERR_NONE); + } + + LR11x0WifiResultFull_t* resultFull = reinterpret_cast(result); + resultFull->frameType = raw[3] & 0x03; + resultFull->frameSubType = (raw[3] & 0x3C) >> 2; + resultFull->toDistributionSystem = (raw[3] & 0x40) != 0; + resultFull->fromDistributionSystem = (raw[3] & 0x80) != 0; + memcpy(resultFull->mac, &raw[4], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN); + resultFull->phiOffset = (((uint16_t)raw[10] << 8) | ((uint16_t)raw[11])); + resultFull->timestamp = (((uint64_t)raw[12] << 56) | ((uint64_t)raw[13] << 48)) | + (((uint64_t)raw[14] << 40) | ((uint64_t)raw[15] << 32)) | + (((uint64_t)raw[16] << 24) | ((uint64_t)raw[17] << 16)) | + (((uint64_t)raw[18] << 8) | (uint64_t)raw[19]); + resultFull->periodBeacon = (((uint16_t)raw[20] << 8) | ((uint16_t)raw[21])) * 1024UL; + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) { + RADIOLIB_ASSERT_PTR(count); + + // start scan + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start"); + int16_t state = startWifiScan(wifiType, mode, chanMask, numScans, timeout); + RADIOLIB_ASSERT(state); + + // wait for scan finished or timeout + RadioLibTime_t softTimeout = 30UL * 1000UL; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start > softTimeout) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ"); + this->standby(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + } + RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start)); + + // read number of results + return(getWifiScanResultsCount(count)); +} + +int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) { + uint8_t buff[9] = { + type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + acqMode, nbMaxRes, nbScanPerChan, + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + abortOnTimeout + }; + + // call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts + return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_WIFI_SCAN, buff, sizeof(buff), false, false)); +} + +int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { + uint8_t buff[9] = { + type, (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + acqMode, nbMaxRes, + (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF), + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiCountryCode(uint16_t mask, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout) { + uint8_t buff[7] = { + (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + nbMaxRes, nbScanPerChan, + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + abortOnTimeout + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) { + uint8_t buff[7] = { + (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + nbMaxRes, + (uint8_t)((timePerChan >> 8) & 0xFF), (uint8_t)(timePerChan & 0xFF), + (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) { + uint8_t buff[3] = { index, nbResults, format }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiResetCumulTimings(void) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS, true, NULL, 0)); +} + +int16_t LR11x0::wifiReadCumulTimings(uint32_t* detection, uint32_t* capture, uint32_t* demodulation) { + uint8_t buff[16] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS, false, buff, sizeof(buff)); + + // pass the replies + if(detection) { *detection = ((uint32_t)(buff[4]) << 24) | ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; } + if(capture) { *capture = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; } + if(demodulation) { *demodulation = ((uint32_t)(buff[12]) << 24) | ((uint32_t)(buff[13]) << 16) | ((uint32_t)(buff[14]) << 8) | (uint32_t)buff[15]; } + + return(state); +} + +int16_t LR11x0::wifiGetNbCountryCodeResults(uint8_t* nbResults) { + uint8_t buff[1] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS, false, buff, sizeof(buff)); + + // pass the replies + if(nbResults) { *nbResults = buff[0]; } + + return(state); +} + +int16_t LR11x0::wifiReadCountryCodeResults(uint8_t index, uint8_t nbResults, uint8_t* results) { + uint8_t reqBuff[2] = { index, nbResults }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff))); +} + +int16_t LR11x0::wifiCfgTimestampAPphone(uint32_t timestamp) { + uint8_t buff[4] = { + (uint8_t)((timestamp >> 24) & 0xFF), (uint8_t)((timestamp >> 16) & 0xFF), + (uint8_t)((timestamp >> 8) & 0xFF), (uint8_t)(timestamp & 0xFF) + }; + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff))); +} + +int16_t LR11x0::wifiReadVersion(uint8_t* major, uint8_t* minor) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION, false, buff, sizeof(buff)); + + // pass the replies + if(major) { *major = buff[0]; } + if(minor) { *minor = buff[1]; } + + return(state); +} + +#endif From f7c60711690558f15e7126ee3ae6da52861ee410 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 1 Jun 2025 08:30:07 +0200 Subject: [PATCH 1550/1848] [LoRaWAN] Add Class C and Multicast examples --- .../LoRaWAN_Class_C/LoRaWAN_Class_C.ino | 136 ++++++++++++++++ examples/LoRaWAN/LoRaWAN_Class_C/config.h | 141 ++++++++++++++++ .../LoRaWAN_Multicast/LoRaWAN_Multicast.ino | 133 +++++++++++++++ examples/LoRaWAN/LoRaWAN_Multicast/config.h | 154 ++++++++++++++++++ 4 files changed, 564 insertions(+) create mode 100644 examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino create mode 100644 examples/LoRaWAN/LoRaWAN_Class_C/config.h create mode 100644 examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino create mode 100644 examples/LoRaWAN/LoRaWAN_Multicast/config.h diff --git a/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino b/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino new file mode 100644 index 0000000000..7ac2d46c67 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino @@ -0,0 +1,136 @@ +/* + RadioLib LoRaWAN Class C Example + + This example joins a LoRaWAN network and switches to Class C. + Note that a confirmed uplink with a confirming downlink is + required for the switch to Class C to complete. This example + assumes that coverage is good enough to receive the downlink + at once. It is up to you to handle the situation if coverage + is worse. + + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN + +*/ + +#include "config.h" + +void setup() { + Serial.begin(115200); + while(!Serial); + delay(5000); // Give time to switch to the serial monitor + Serial.println(F("\nSetup ... ")); + + Serial.println(F("Initialise the radio")); + int16_t state = radio.begin(); + debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); + + // Setup the OTAA session information + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + debug(state != RADIOLIB_ERR_NONE, F("Initialise node failed"), state, true); + + Serial.println(F("Join ('login') the LoRaWAN Network")); + state = node.activateOTAA(); + debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); + + // switch class + node.setClass(RADIOLIB_LORAWAN_CLASS_C); + + // read the note at the top about this first confirmed uplink + const char* payload = "C"; + Serial.println(F("Sending a confirmed uplink")); + state = node.sendReceive(payload, 1, true); + debug(state <= 0, F("No downlink received"), state, true); + + Serial.println(F("Ready!\n")); +} + +uint32_t lastUplink = 0; + +void loop() { + uint8_t downlinkPayload[255]; + size_t downlinkLen = 0; + LoRaWANEvent_t downlinkEvent; + + // check if a Class C downlink is ready for processing + // tip: internally, this just checks a boolean; + // it does not poll the radio over SPI. + // tip: you are not required to continuously call + // this function; you can do other stuff in between. + // however, a downlink may be overwritten if you + // don't call this function in time for the previous one. + int16_t state = node.getDownlinkClassC(downlinkPayload, &downlinkLen, &downlinkEvent); + if(state > 0) { + Serial.println(F("Received a Class C downlink!")); + // Did we get a downlink with data for us + if(downlinkLen > 0) { + Serial.println(F("Downlink data: ")); + arrayDump(downlinkPayload, downlinkLen); + } + + // print extra information about the event + Serial.println(F("[LoRaWAN] Event information:")); + Serial.print(F("[LoRaWAN] Datarate:\t")); + Serial.println(downlinkEvent.datarate); + Serial.print(F("[LoRaWAN] Frequency:\t")); + Serial.print(downlinkEvent.freq, 3); + Serial.println(F(" MHz")); + Serial.print(F("[LoRaWAN] Frame count:\t")); + Serial.println(downlinkEvent.fCnt); + Serial.print(F("[LoRaWAN] Port:\t\t")); + Serial.println(downlinkEvent.fPort); + Serial.println(F(" ms")); + Serial.print(F("[LoRaWAN] Rx window: \t")); + Serial.println(state); + Serial.print(F("[LoRaWAN] Cast:\t\t")); + Serial.println(downlinkEvent.multicast ? "Multi" : "Uni"); + } + + // if less than uplinkIntervalSeconds have elapsed since previous uplink, + // stop and go back to the top of the loop() + if(millis() - lastUplink < uplinkIntervalSeconds * 1000) { + return; + } + + Serial.println(F("Sending uplink")); + + // This is the place to gather the sensor inputs + // Instead of reading any real sensor, we just generate some random numbers as example + uint8_t value1 = radio.random(100); + uint16_t value2 = radio.random(2000); + + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = value1; + uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(value2); + + // Perform an uplink + int16_t state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); + + // Check if a downlink was received + // (state 0 = no downlink, state 1/2/3 = downlink in window Rx1/Rx2/RxC) + if(state > 0) { + Serial.println(F("Received a downlink")); + } else { + Serial.println(F("No downlink received")); + } + + Serial.print(F("Next uplink in ")); + Serial.print(uplinkIntervalSeconds); + Serial.println(F(" seconds\n")); + + // set timestamp of last uplink + lastUplink = millis(); +} diff --git a/examples/LoRaWAN/LoRaWAN_Class_C/config.h b/examples/LoRaWAN/LoRaWAN_Class_C/config.h new file mode 100644 index 0000000000..dd853274f3 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Class_C/config.h @@ -0,0 +1,141 @@ +#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H +#define _RADIOLIB_EX_LORAWAN_CONFIG_H + +#include + +// first you have to set your radio model and pin configuration +// this is provided just as a default example +SX1262 radio = new Module(8, 14, 12, 13); + +// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) +// and are using one of the supported boards, you can do the following: +/* +#define RADIO_BOARD_AUTO +#include + +Radio radio = new RadioModule(); +*/ + +// how often to send an uplink - consider legal & FUP constraints - see notes +const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds + +// joinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// the Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// for the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; + +// create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + +// result code to text - these are error codes that can be raised when using LoRaWAN +// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list +String stateDecode(const int16_t result) { + switch (result) { + case RADIOLIB_ERR_NONE: + return "ERR_NONE"; + case RADIOLIB_ERR_CHIP_NOT_FOUND: + return "ERR_CHIP_NOT_FOUND"; + case RADIOLIB_ERR_PACKET_TOO_LONG: + return "ERR_PACKET_TOO_LONG"; + case RADIOLIB_ERR_RX_TIMEOUT: + return "ERR_RX_TIMEOUT"; + case RADIOLIB_ERR_MIC_MISMATCH: + return "ERR_MIC_MISMATCH"; + case RADIOLIB_ERR_INVALID_BANDWIDTH: + return "ERR_INVALID_BANDWIDTH"; + case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: + return "ERR_INVALID_SPREADING_FACTOR"; + case RADIOLIB_ERR_INVALID_CODING_RATE: + return "ERR_INVALID_CODING_RATE"; + case RADIOLIB_ERR_INVALID_FREQUENCY: + return "ERR_INVALID_FREQUENCY"; + case RADIOLIB_ERR_INVALID_OUTPUT_POWER: + return "ERR_INVALID_OUTPUT_POWER"; + case RADIOLIB_ERR_NETWORK_NOT_JOINED: + return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; + case RADIOLIB_ERR_DOWNLINK_MALFORMED: + return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; + case RADIOLIB_ERR_INVALID_REVISION: + return "RADIOLIB_ERR_INVALID_REVISION"; + case RADIOLIB_ERR_INVALID_PORT: + return "RADIOLIB_ERR_INVALID_PORT"; + case RADIOLIB_ERR_NO_RX_WINDOW: + return "RADIOLIB_ERR_NO_RX_WINDOW"; + case RADIOLIB_ERR_INVALID_CID: + return "RADIOLIB_ERR_INVALID_CID"; + case RADIOLIB_ERR_UPLINK_UNAVAILABLE: + return "RADIOLIB_ERR_UPLINK_UNAVAILABLE"; + case RADIOLIB_ERR_COMMAND_QUEUE_FULL: + return "RADIOLIB_ERR_COMMAND_QUEUE_FULL"; + case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND: + return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; + case RADIOLIB_ERR_JOIN_NONCE_INVALID: + return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; + case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: + return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; + case RADIOLIB_ERR_CHECKSUM_MISMATCH: + return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; + case RADIOLIB_ERR_NO_JOIN_ACCEPT: + return "RADIOLIB_ERR_NO_JOIN_ACCEPT"; + case RADIOLIB_LORAWAN_SESSION_RESTORED: + return "RADIOLIB_LORAWAN_SESSION_RESTORED"; + case RADIOLIB_LORAWAN_NEW_SESSION: + return "RADIOLIB_LORAWAN_NEW_SESSION"; + case RADIOLIB_ERR_NONCES_DISCARDED: + return "RADIOLIB_ERR_NONCES_DISCARDED"; + case RADIOLIB_ERR_SESSION_DISCARDED: + return "RADIOLIB_ERR_SESSION_DISCARDED"; + } + return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; +} + +// helper function to display any issues +void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) { + if(failed) { + Serial.print(message); + Serial.print(" - "); + Serial.print(stateDecode(state)); + Serial.print(" ("); + Serial.print(state); + Serial.println(")"); + while(halt) { delay(1); } + } +} + +// helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for(uint16_t c = 0; c < len; c++) { + char b = buffer[c]; + if(b < 0x10) { Serial.print('0'); } + Serial.print(b, HEX); + } + Serial.println(); +} + +#endif diff --git a/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino b/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino new file mode 100644 index 0000000000..9be571bfe8 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino @@ -0,0 +1,133 @@ +/* + RadioLib LoRaWAN Multicast Example + + This example joins a LoRaWAN network and starts a + Multicast session (only Multicast over Class C is implemented). + You should refer to the network's documentation on how + to create a Multicast group (or device). + Note that you can switch the device to Class C as well + to receive Unicast downlinks. In this case, you must + use the downlink event details to discern whether a + downlink belongs to the Unicast or Multicast session. + + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN + +*/ + +#include "config.h" + +void setup() { + Serial.begin(115200); + while(!Serial); + delay(5000); // Give time to switch to the serial monitor + Serial.println(F("\nSetup ... ")); + + Serial.println(F("Initialise the radio")); + int16_t state = radio.begin(); + debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); + + // Setup the OTAA session information + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + debug(state != RADIOLIB_ERR_NONE, F("Initialise node failed"), state, true); + + Serial.println(F("Join ('login') the LoRaWAN Network")); + state = node.activateOTAA(); + debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); + + // Start a Multicast session over Class C + // (this will automatically perform a switch to Class C for Multicast) + node.startMulticastSession(RADIOLIB_LORAWAN_CLASS_C, mcDevAddr, mcAppSKey, mcNwkSKey); + + Serial.println(F("Ready!\n")); +} + +uint32_t lastUplink = 0; + +void loop() { + uint8_t downlinkPayload[255]; + size_t downlinkLen = 0; + LoRaWANEvent_t downlinkEvent; + + // check if a Class C downlink is ready for processing + // tip: internally, this just checks a boolean; + // it does not poll the radio over SPI. + // tip: you are not required to continuously call + // this function; you can do other stuff in between. + // however, a downlink may be overwritten if you + // don't call this function in time for the previous one. + int16_t state = node.getDownlinkClassC(downlinkPayload, &downlinkLen, &downlinkEvent); + if(state > 0) { + Serial.println(F("Received a Class C downlink!")); + // Did we get a downlink with data for us + if(downlinkLen > 0) { + Serial.println(F("Downlink data: ")); + arrayDump(downlinkPayload, downlinkLen); + } + + // print extra information about the event + Serial.println(F("[LoRaWAN] Event information:")); + Serial.print(F("[LoRaWAN] Datarate:\t")); + Serial.println(downlinkEvent.datarate); + Serial.print(F("[LoRaWAN] Frequency:\t")); + Serial.print(downlinkEvent.freq, 3); + Serial.println(F(" MHz")); + Serial.print(F("[LoRaWAN] Frame count:\t")); + Serial.println(downlinkEvent.fCnt); + Serial.print(F("[LoRaWAN] Port:\t\t")); + Serial.println(downlinkEvent.fPort); + Serial.println(F(" ms")); + Serial.print(F("[LoRaWAN] Rx window: \t")); + Serial.println(state); + Serial.print(F("[LoRaWAN] Cast:\t\t")); + Serial.println(downlinkEvent.multicast ? "Multi" : "Uni"); + } + + // if less than uplinkIntervalSeconds have elapsed since previous uplink, + // stop and go back to the top of the loop() + if(millis() - lastUplink < uplinkIntervalSeconds * 1000) { + return; + } + + Serial.println(F("Sending uplink")); + + // This is the place to gather the sensor inputs + // Instead of reading any real sensor, we just generate some random numbers as example + uint8_t value1 = radio.random(100); + uint16_t value2 = radio.random(2000); + + // Build payload byte array + uint8_t uplinkPayload[3]; + uplinkPayload[0] = value1; + uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions + uplinkPayload[2] = lowByte(value2); + + // Perform an uplink + int16_t state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); + + // Check if a downlink was received + // (state 0 = no downlink, state 1/2/3 = downlink in window Rx1/Rx2/RxC) + if(state > 0) { + Serial.println(F("Received a downlink")); + } else { + Serial.println(F("No downlink received")); + } + + Serial.print(F("Next uplink in ")); + Serial.print(uplinkIntervalSeconds); + Serial.println(F(" seconds\n")); + + // set timestamp of last uplink + lastUplink = millis(); +} diff --git a/examples/LoRaWAN/LoRaWAN_Multicast/config.h b/examples/LoRaWAN/LoRaWAN_Multicast/config.h new file mode 100644 index 0000000000..bbe12e715d --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_Multicast/config.h @@ -0,0 +1,154 @@ +#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H +#define _RADIOLIB_EX_LORAWAN_CONFIG_H + +#include + +// first you have to set your radio model and pin configuration +// this is provided just as a default example +SX1262 radio = new Module(8, 14, 12, 13); + +// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) +// and are using one of the supported boards, you can do the following: +/* +#define RADIO_BOARD_AUTO +#include + +Radio radio = new RadioModule(); +*/ + +// how often to send an uplink - consider legal & FUP constraints - see notes +const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds + +// joinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// the Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +#ifndef RADIOLIB_LORAWAN_MC_DEV_ADDR // Replace with your Multicast Device Address +#define RADIOLIB_LORAWAN_MC_DEV_ADDR 0x--------------- +#endif +#ifndef RADIOLIB_LORAWAN_MC_APP_SKEY // Replace with your Multicast App SKey +#define RADIOLIB_LORAWAN_MC_APP_SKEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_MC_NWK_SKEY // Put your Multicast Nwk SKey here +#define RADIOLIB_LORAWAN_MC_NWK_SKEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// for the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + +// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; +uint32_t mcDevAddr = RADIOLIB_LORAWAN_MC_DEV_ADDR; +uint8_t mcAppSKey[] = { RADIOLIB_LORAWAN_MC_APP_SKEY }; +uint8_t mcNwkSKey[] = { RADIOLIB_LORAWAN_MC_NWK_SKEY }; + +// create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + +// result code to text - these are error codes that can be raised when using LoRaWAN +// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list +String stateDecode(const int16_t result) { + switch (result) { + case RADIOLIB_ERR_NONE: + return "ERR_NONE"; + case RADIOLIB_ERR_CHIP_NOT_FOUND: + return "ERR_CHIP_NOT_FOUND"; + case RADIOLIB_ERR_PACKET_TOO_LONG: + return "ERR_PACKET_TOO_LONG"; + case RADIOLIB_ERR_RX_TIMEOUT: + return "ERR_RX_TIMEOUT"; + case RADIOLIB_ERR_MIC_MISMATCH: + return "ERR_MIC_MISMATCH"; + case RADIOLIB_ERR_INVALID_BANDWIDTH: + return "ERR_INVALID_BANDWIDTH"; + case RADIOLIB_ERR_INVALID_SPREADING_FACTOR: + return "ERR_INVALID_SPREADING_FACTOR"; + case RADIOLIB_ERR_INVALID_CODING_RATE: + return "ERR_INVALID_CODING_RATE"; + case RADIOLIB_ERR_INVALID_FREQUENCY: + return "ERR_INVALID_FREQUENCY"; + case RADIOLIB_ERR_INVALID_OUTPUT_POWER: + return "ERR_INVALID_OUTPUT_POWER"; + case RADIOLIB_ERR_NETWORK_NOT_JOINED: + return "RADIOLIB_ERR_NETWORK_NOT_JOINED"; + case RADIOLIB_ERR_DOWNLINK_MALFORMED: + return "RADIOLIB_ERR_DOWNLINK_MALFORMED"; + case RADIOLIB_ERR_INVALID_REVISION: + return "RADIOLIB_ERR_INVALID_REVISION"; + case RADIOLIB_ERR_INVALID_PORT: + return "RADIOLIB_ERR_INVALID_PORT"; + case RADIOLIB_ERR_NO_RX_WINDOW: + return "RADIOLIB_ERR_NO_RX_WINDOW"; + case RADIOLIB_ERR_INVALID_CID: + return "RADIOLIB_ERR_INVALID_CID"; + case RADIOLIB_ERR_UPLINK_UNAVAILABLE: + return "RADIOLIB_ERR_UPLINK_UNAVAILABLE"; + case RADIOLIB_ERR_COMMAND_QUEUE_FULL: + return "RADIOLIB_ERR_COMMAND_QUEUE_FULL"; + case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND: + return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND"; + case RADIOLIB_ERR_JOIN_NONCE_INVALID: + return "RADIOLIB_ERR_JOIN_NONCE_INVALID"; + case RADIOLIB_ERR_DWELL_TIME_EXCEEDED: + return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED"; + case RADIOLIB_ERR_CHECKSUM_MISMATCH: + return "RADIOLIB_ERR_CHECKSUM_MISMATCH"; + case RADIOLIB_ERR_NO_JOIN_ACCEPT: + return "RADIOLIB_ERR_NO_JOIN_ACCEPT"; + case RADIOLIB_LORAWAN_SESSION_RESTORED: + return "RADIOLIB_LORAWAN_SESSION_RESTORED"; + case RADIOLIB_LORAWAN_NEW_SESSION: + return "RADIOLIB_LORAWAN_NEW_SESSION"; + case RADIOLIB_ERR_NONCES_DISCARDED: + return "RADIOLIB_ERR_NONCES_DISCARDED"; + case RADIOLIB_ERR_SESSION_DISCARDED: + return "RADIOLIB_ERR_SESSION_DISCARDED"; + } + return "See https://jgromes.github.io/RadioLib/group__status__codes.html"; +} + +// helper function to display any issues +void debug(bool failed, const __FlashStringHelper* message, int state, bool halt) { + if(failed) { + Serial.print(message); + Serial.print(" - "); + Serial.print(stateDecode(state)); + Serial.print(" ("); + Serial.print(state); + Serial.println(")"); + while(halt) { delay(1); } + } +} + +// helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for(uint16_t c = 0; c < len; c++) { + char b = buffer[c]; + if(b < 0x10) { Serial.print('0'); } + Serial.print(b, HEX); + } + Serial.println(); +} + +#endif From d7205cd00636cb2d24d27b0362638dc29394fb97 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Jun 2025 10:06:25 +0200 Subject: [PATCH 1551/1848] [LoRaWAN] Fix variable redefinition --- examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino | 2 +- examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino b/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino index 7ac2d46c67..db2a5e791c 100644 --- a/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino +++ b/examples/LoRaWAN/LoRaWAN_Class_C/LoRaWAN_Class_C.ino @@ -116,7 +116,7 @@ void loop() { uplinkPayload[2] = lowByte(value2); // Perform an uplink - int16_t state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); // Check if a downlink was received diff --git a/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino b/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino index 9be571bfe8..7e5be0b0f4 100644 --- a/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino +++ b/examples/LoRaWAN/LoRaWAN_Multicast/LoRaWAN_Multicast.ino @@ -113,7 +113,7 @@ void loop() { uplinkPayload[2] = lowByte(value2); // Perform an uplink - int16_t state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); + state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload)); debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false); // Check if a downlink was received From c852a379533659dec4e8af20f43121ee93e11456 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Jun 2025 10:32:00 +0200 Subject: [PATCH 1552/1848] [CI] Fix missing flags for LoRaWAN examples --- extras/test/ci/build_examples.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extras/test/ci/build_examples.sh b/extras/test/ci/build_examples.sh index 44bfb9c375..fc1434fbd2 100755 --- a/extras/test/ci/build_examples.sh +++ b/extras/test/ci/build_examples.sh @@ -20,7 +20,12 @@ for example in $(find $path -name '*.ino' | sort); do else # apply special flags for LoRaWAN if [[ ${example} =~ "LoRaWAN" ]]; then - flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1" + flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 \ + -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 \ + -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 \ + -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 \ + -DRADIOLIB_LORAWAN_MC_DEV_ADDR=0 -DRADIOLIB_LORAWAN_MC_APP_SKEY=0 \ + -DRADIOLIB_LORAWAN_MC_NWK_SKEY=0 -DARDUINO_TTGO_LORA32_V1" fi # build sketch From 2472fbdf727e7263167bdc511f2bd0744194dd33 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 9 Jun 2025 20:26:10 +0200 Subject: [PATCH 1553/1848] [LR2021] Initial WIP commit --- src/RadioLib.h | 1 + src/modules/LR2021/LR2021.cpp | 73 ++++++++ src/modules/LR2021/LR2021.h | 230 +++++++++++++++++++++++++ src/modules/LR2021/LR2021_commands.cpp | 10 ++ 4 files changed, 314 insertions(+) create mode 100644 src/modules/LR2021/LR2021.cpp create mode 100644 src/modules/LR2021/LR2021.h create mode 100644 src/modules/LR2021/LR2021_commands.cpp diff --git a/src/RadioLib.h b/src/RadioLib.h index 3c362e117d..f051c6b0a7 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -78,6 +78,7 @@ #include "modules/LR11x0/LR1110.h" #include "modules/LR11x0/LR1120.h" #include "modules/LR11x0/LR1121.h" +#include "modules/LR2021/LR2021.h" #include "modules/nRF24/nRF24.h" #include "modules/RF69/RF69.h" #include "modules/RFM2x/RFM22.h" diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp new file mode 100644 index 0000000000..e8b1c530e0 --- /dev/null +++ b/src/modules/LR2021/LR2021.cpp @@ -0,0 +1,73 @@ +#include "LR2021.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +LR2021::LR2021(Module* mod) : PhysicalLayer() { + this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE; + this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH; + this->mod = mod; + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR2021_IRQ_TX_DONE; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR2021_IRQ_RX_DONE; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR2021_IRQ_CRC_ERROR; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT; +} + +Module* LR2021::getMod() { + return(this->mod); +} + +int16_t LR2021::SPIparseStatus(uint8_t in) { + /*if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } else if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_FAIL) { + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } else if((in == 0x00) || (in == 0xFF)) { + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + }*/ + return(RADIOLIB_ERR_NONE); +} + +int16_t LR2021::SPIcheckStatus(Module* mod) { + // the status check command doesn't return status in the same place as other read commands, + // but only as the first byte (as with any other command), hence LR2021::SPIcommand can't be used + // it also seems to ignore the actual command, and just sending in bunch of NOPs will work + uint8_t buff[6] = { 0 }; + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; + int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + RADIOLIB_ASSERT(state); + return(LR2021::SPIparseStatus(buff[0])); +} + +int16_t LR2021::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + if(!write) { + // the SPI interface of LR2021 requires two separate transactions for reading + // send the 16-bit command + state = this->mod->SPIwriteStream(cmd, out, outLen, true, false); + RADIOLIB_ASSERT(state); + + // read the result without command + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0; + state = this->mod->SPIreadStream(RADIOLIB_LR2021_CMD_NOP, data, len, true, false); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + + } else { + // write is just a single transaction + state = this->mod->SPIwriteStream(cmd, data, len, true, true); + + } + + return(state); +} + +#endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h new file mode 100644 index 0000000000..8cd2dede8a --- /dev/null +++ b/src/modules/LR2021/LR2021.h @@ -0,0 +1,230 @@ +#if !defined(RADIOLIB_LR2021_H) +#define RADIOLIB_LR2021_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR2021 + +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// LR2021 physical layer properties +#define RADIOLIB_LR2021_FREQUENCY_STEP_SIZE 1.0 +#define RADIOLIB_LR2021_MAX_PACKET_LENGTH 255 +#define RADIOLIB_LR2021_CRYSTAL_FREQ 32.0 +#define RADIOLIB_LR2021_DIV_EXPONENT 25 + +// LR2021 SPI commands +#define RADIOLIB_LR2021_CMD_NOP (0x0000) +#define RADIOLIB_LR2021_CMD_READ_RX_FIFO (0x0001) +#define RADIOLIB_LR2021_CMD_WRITE_TX_FIFO (0x0002) +#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32 (0x0104) +#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32 (0x0105) +#define RADIOLIB_LR2021_CMD_READ_REG_MEM_32 (0x0106) +#define RADIOLIB_LR2021_CMD_SET_SLEEP (0x0127) +#define RADIOLIB_LR2021_CMD_SET_STANDBY (0x0128) +#define RADIOLIB_LR2021_CMD_SET_FS (0x0129) +#define RADIOLIB_LR2021_CMD_SET_ADDITIONAL_REG_TO_RETAIN (0x012A) +#define RADIOLIB_LR2021_CMD_SET_RX (0x020C) +#define RADIOLIB_LR2021_CMD_SET_TX (0x020D) +#define RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE (0x0206) +#define RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE (0x0210) +#define RADIOLIB_LR2021_CMD_SET_AUTO_RX_TX (0x0211) +#define RADIOLIB_LR2021_CMD_GET_RX_PKT_LENGTH (0x0212) +#define RADIOLIB_LR2021_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0209) +#define RADIOLIB_LR2021_CMD_RESET_RX_STATS (0x020A) +#define RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT (0x0215) +#define RADIOLIB_LR2021_CMD_SET_REG_MODE (0x0121) +#define RADIOLIB_LR2021_CMD_CALIBRATE (0x0122) +#define RADIOLIB_LR2021_CMD_CALIB_FRONT_END (0x0123) +#define RADIOLIB_LR2021_CMD_GET_V_BAT (0x0124) +#define RADIOLIB_LR2021_CMD_GET_TEMP (0x0125) +#define RADIOLIB_LR2021_CMD_SET_EOL_CONFIG (0x0130) +#define RADIOLIB_LR2021_CMD_GET_RANDOM_NUMBER (0x0126) +#define RADIOLIB_LR2021_CMD_GET_STATUS (0x0100) +#define RADIOLIB_LR2021_CMD_GET_VERSION (0x0101) +#define RADIOLIB_LR2021_CMD_CLEAR_ERRORS (0x0111) +#define RADIOLIB_LR2021_CMD_GET_ERRORS (0x0110) +#define RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION (0x0112) +#define RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG (0x0115) +#define RADIOLIB_LR2021_CMD_CLEAR_IRQ (0x0116) +#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS (0x0117) +#define RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ (0x011A) +#define RADIOLIB_LR2021_CMD_GET_FIFO_IRQ_FLAGS (0x011B) +#define RADIOLIB_LR2021_CMD_CLEAR_FIFO_IRQ_FLAGS (0x0114) +#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_FIFO_IRQ_FLAGS (0x012E) +#define RADIOLIB_LR2021_CMD_GET_RX_FIFO_LEVEL (0x011C) +#define RADIOLIB_LR2021_CMD_GET_TX_FIFO_LEVEL (0x011D) +#define RADIOLIB_LR2021_CMD_CLEAR_RX_FIFO (0x011E) +#define RADIOLIB_LR2021_CMD_CLEAR_TX_FIFO (0x011F) +#define RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK (0x0118) +#define RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS (0x0119) +#define RADIOLIB_LR2021_CMD_SET_TCXO_MODE (0x0120) +#define RADIOLIB_LR2021_CMD_SET_XOSC_CP_TRIM (0x0131) +#define RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY (0x0200) +#define RADIOLIB_LR2021_CMD_SET_RX_PATH (0x0201) +#define RADIOLIB_LR2021_CMD_GET_RSSI_INST (0x020B) +#define RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION (0x0205) +#define RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE (0x0216) +#define RADIOLIB_LR2021_CMD_GET_TIMESTAMP_VALUE (0x0217) +#define RADIOLIB_LR2021_CMD_SET_CCA (0x0218) +#define RADIOLIB_LR2021_CMD_GET_CCA_RESULT (0x0219) +#define RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL (0x021A) +#define RADIOLIB_LR2021_CMD_SET_CAD_PARAMS (0x021B) +#define RADIOLIB_LR2021_CMD_SET_CAD (0x021C) +#define RADIOLIB_LR2021_CMD_SEL_PA (0x020F) +#define RADIOLIB_LR2021_CMD_SET_PA_CONFIG (0x0202) +#define RADIOLIB_LR2021_CMD_SET_TX_PARAMS (0x0203) +#define RADIOLIB_LR2021_CMD_SET_PACKET_TYPE (0x0207) +#define RADIOLIB_LR2021_CMD_GET_PACKET_TYPE (0x0208) +#define RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS (0x0220) +#define RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS (0x0221) +#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT (0x0222) +#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD (0x0223) +#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG (0x0224) +#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD (0x0225) +#define RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS (0x0227) +#define RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS (0x0229) +#define RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS (0x022A) +#define RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS (0x022B) +#define RADIOLIB_LR2021_CMD_SET_LORA_HOPPING (0x022C) +#define RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC (0x021D) +#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CAD (0x021E) +#define RADIOLIB_LR2021_CMD_SET_RANGING_ADDR (0x0278) +#define RADIOLIB_LR2021_CMD_SET_RANGING_REQ_ADDR (0x0279) +#define RADIOLIB_LR2021_CMD_GET_RANGING_RESULT (0x027A) +#define RADIOLIB_LR2021_CMD_GET_RANGING_STATS (0x027D) +#define RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY (0x027B) +#define RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS (0x027C) +#define RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS (0x0240) +#define RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS (0x0241) +#define RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS (0x0242) +#define RADIOLIB_LR2021_CMD_SET_FSK_CRC_PARAMS (0x0243) +#define RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD (0x0244) +#define RADIOLIB_LR2021_CMD_SET_FSK_ADDRESS (0x0245) +#define RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS (0x0246) +#define RADIOLIB_LR2021_CMD_GET_FSK_PACKET_STATUS (0x0247) +#define RADIOLIB_LR2021_CMD_SET_WMBUS_PARAMS (0x026A) +#define RADIOLIB_LR2021_CMD_GET_WMBUS_RX_STATS (0x026C) +#define RADIOLIB_LR2021_CMD_GET_WMBUS_PACKET_STATUS (0x026D) +#define RADIOLIB_LR2021_CMD_SET_WMBUS_FILTERING_ADDRESS (0x026E) +#define RADIOLIB_LR2021_CMD_SET_WISUN_MODE (0x0270) +#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_PARAMS (0x0271) +#define RADIOLIB_LR2021_CMD_GET_WISUN_RX_STATS (0x0272) +#define RADIOLIB_LR2021_CMD_GET_WISUN_PACKET_STATUS (0x0273) +#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_LEN (0x0274) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_PARAMS (0x0297) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_HOME_ID_FILTERING (0x0298) +#define RADIOLIB_LR2021_CMD_GET_ZWAVE_RX_STATS (0x0299) +#define RADIOLIB_LR2021_CMD_GET_ZWAVE_PACKET_STATUS (0x029A) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_BEAM_FILTERING (0x029B) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN_CONFIG (0x029C) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN (0x029D) +#define RADIOLIB_LR2021_CMD_SET_BLE_MODULATION_PARAMS (0x0260) +#define RADIOLIB_LR2021_CMD_SET_BLE_CHANNEL_PARAMS (0x0261) +#define RADIOLIB_LR2021_CMD_SET_BLE_PDU_LEN (0x0266) +#define RADIOLIB_LR2021_CMD_SET_BLE_TX (0x0262) +#define RADIOLIB_LR2021_CMD_GET_BLE_RX_STATS (0x0264) +#define RADIOLIB_LR2021_CMD_GET_BLE_PACKET_STATUS (0x0265) +#define RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS (0x029F) +#define RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS (0x02A0) +#define RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS (0x02A1) +#define RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN (0x02A2) +#define RADIOLIB_LR2021_CMD_SET_OQPSK_ADDRESS (0x02A3) +#define RADIOLIB_LR2021_CMD_SET_BPSK_MODULATION_PARAMS (0x0250) +#define RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS (0x0251) +#define RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS (0x0248) +#define RADIOLIB_LR2021_CMD_SET_FLRC_PACKET_PARAMS (0x0249) +#define RADIOLIB_LR2021_CMD_GET_FLRC_RX_STATS (0x024A) +#define RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS (0x024B) +#define RADIOLIB_LR2021_CMD_SET_FLRC_SYNCWORD (0x024C) +#define RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME (0x0256) +#define RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD (0x0257) +#define RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS (0x0281) +#define RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS (0x0282) +#define RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS (0x0283) +#define RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD (0x0284) +#define RADIOLIB_LR2021_CMD_SET_OOK_ADDRESS (0x0285) +#define RADIOLIB_LR2021_CMD_GET_OOK_RX_STATS (0x0286) +#define RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS (0x0287) +#define RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR (0x0288) +#define RADIOLIB_LR2021_CMD_SET_OOK_WHITENING_PARAMS (0x0289) +#define RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE (0x020E) + +// RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG +#define RADIOLIB_LR2021_IRQ_RX_FIFO (0x01UL << 0) // 31 0 interrupt: Rx FIFO threshold reached +#define RADIOLIB_LR2021_IRQ_TX_FIFO (0x01UL << 1) // 31 0 Tx FIFO threshold reached +#define RADIOLIB_LR2021_IRQ_RNG_REQ_VALID (0x01UL << 2) // 31 0 ranging slave received valid request +#define RADIOLIB_LR2021_IRQ_TX_TIMESTAMP (0x01UL << 3) // 31 0 end of packet Tx timestamp +#define RADIOLIB_LR2021_IRQ_RX_TIMESTAMP (0x01UL << 4) // 31 0 end of packet Rx timestamp +#define RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED (0x01UL << 5) // 31 0 preamble detected +#define RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID (0x01UL << 6) // 31 0 LoRa header received and valid +#define RADIOLIB_LR2021_IRQ_SYNCWORD_VALID (0x01UL << 6) // 31 0 sync word valid +#define RADIOLIB_LR2021_IRQ_CAD_DETECTED (0x01UL << 7) // 31 0 channel activity detected +#define RADIOLIB_LR2021_IRQ_LORA_HDR_TIMESTAMP (0x01UL << 8) // 31 0 LoRa header timestamp +#define RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR (0x01UL << 9) // 31 0 LoRa header CRC error +#define RADIOLIB_LR2021_IRQ_EOL (0x01UL << 10) // 31 0 end of life +#define RADIOLIB_LR2021_IRQ_PA_OCP_OVP (0x01UL << 11) // 31 0 PA overcurrent/overvoltage triggered +#define RADIOLIB_LR2021_IRQ_LORA_TX_RX_HOP (0x01UL << 12) // 31 0 LoRa intra-packet hopping +#define RADIOLIB_LR2021_IRQ_SYNC_FAIL (0x01UL << 13) // 31 0 sync word match detection failed +#define RADIOLIB_LR2021_IRQ_LORA_SYMBOL_END (0x01UL << 14) // 31 0 symbol end +#define RADIOLIB_LR2021_IRQ_LORA_TIMESTAMP_STAT (0x01UL << 15) // 31 0 new stats available +#define RADIOLIB_LR2021_IRQ_ERROR (0x01UL << 16) // 31 0 error other than command error +#define RADIOLIB_LR2021_IRQ_CMD_ERROR (0x01UL << 17) // 31 0 command error +#define RADIOLIB_LR2021_IRQ_RX_DONE (0x01UL << 18) // 31 0 packet received +#define RADIOLIB_LR2021_IRQ_TX_DONE (0x01UL << 19) // 31 0 packet transmitted +#define RADIOLIB_LR2021_IRQ_CAD_DONE (0x01UL << 20) // 31 0 CAD finished +#define RADIOLIB_LR2021_IRQ_TIMEOUT (0x01UL << 21) // 31 0 Rx or Tx timeout +#define RADIOLIB_LR2021_IRQ_CRC_ERROR (0x01UL << 22) // 31 0 CRC error +#define RADIOLIB_LR2021_IRQ_LEN_ERROR (0x01UL << 23) // 31 0 length error on received packet +#define RADIOLIB_LR2021_IRQ_ADDR_ERROR (0x01UL << 24) // 31 0 packet with incorrect address received +#define RADIOLIB_LR2021_IRQ_FHSS (0x01UL << 25) // 31 0 FHSS intra-packet hopping +#define RADIOLIB_LR2021_IRQ_INTER_PACKET_FREQ (0x01UL << 26) // 31 0 inter packet hopping can load new frequency table +#define RADIOLIB_LR2021_IRQ_INTER_NEW_PAYLOAD (0x01UL << 27) // 31 0 inter packet hopping can load new payload +#define RADIOLIB_LR2021_IRQ_RNG_RESP_DONE (0x01UL << 28) // 31 0 slave ranging response sent +#define RADIOLIB_LR2021_IRQ_RNG_REQ_DIS (0x01UL << 29) // 31 0 ranging request discarded +#define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response +#define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout + +/*! + \class LR2021 + \brief +*/ +class LR2021: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::startReceive; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + \param mod Instance of Module that will be used to communicate with the radio. + */ + explicit LR2021(Module* mod); + +#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL + protected: +#endif + Module* getMod() override; + +#if !RADIOLIB_GODMODE + protected: +#endif + int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); + +#if !RADIOLIB_GODMODE + private: +#endif + Module* mod; + + static int16_t SPIparseStatus(uint8_t in); + static int16_t SPIcheckStatus(Module* mod); +}; + +#endif + +#endif diff --git a/src/modules/LR2021/LR2021_commands.cpp b/src/modules/LR2021/LR2021_commands.cpp new file mode 100644 index 0000000000..e11aa49438 --- /dev/null +++ b/src/modules/LR2021/LR2021_commands.cpp @@ -0,0 +1,10 @@ +#include "LR2021.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + + + +#endif From 0ce1a38deb83b63079bb44f14fcb4a2e07ede53a Mon Sep 17 00:00:00 2001 From: Toshik Soni Date: Sat, 14 Jun 2025 10:28:19 +0530 Subject: [PATCH 1554/1848] Fix RFM typo in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 92ffe4475e..0066ccaac1 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __LR11x0__ series LoRa/GFSK modules (LR1110, LR1120, LR1121) * __nRF24L01__ 2.4 GHz module * __RF69__ FSK/OOK radio module -* __RFM2x__ series FSK modules (RFM22, RM23) -* __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98) +* __RFM2x__ series FSK modules (RFM22, RFM23) +* __RFM9x__ series LoRa modules (RFM95, RFM96, RFM97, RFM98) * __Si443x__ series FSK modules (Si4430, Si4431, Si4432) * __STM32WL__ integrated microcontroller/LoRa module * __SX126x__ series LoRa modules (SX1261, SX1262, SX1268) From 494cfb692e6173ae6311dcc3d67cd29b79cc684d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 16 Jun 2025 08:49:19 +0200 Subject: [PATCH 1555/1848] [LoRaWAN] Self-certified! (Class A, dynamic channelplan) Fix network uplinks, ADR backoff, FSK TxTimeout, FCnt replay, ADR RFU values, MAC payload cut-off, uplink size (#1524) --- src/TypeDef.h | 9 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 141 +++++++++++++++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 7 +- 3 files changed, 114 insertions(+), 43 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index c9d550f926..ae1841d971 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -549,9 +549,9 @@ #define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111) /*! - \brief The downlink MIC could not be verified (incorrect key or invalid FCnt) + \brief The downlink frame counter is slightly lower than expected, looks like a replay attack. */ -#define RADIOLIB_ERR_MIC_MISMATCH (-1112) +#define RADIOLIB_ERR_DOWNLINK_FCNT_INVALID (-1112) /*! \brief Multicast frame counter is invalid (outside bounds). @@ -598,6 +598,11 @@ */ #define RADIOLIB_ERR_INVALID_MODE (-1121) +/*! + \brief The downlink MIC could not be verified (incorrect key or invalid FCnt) +*/ +#define RADIOLIB_ERR_MIC_MISMATCH (-1122) + // LR11x0-specific status codes /*! diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 045e156d27..e2cf3ee0d9 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -64,7 +64,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP } int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fPort, uint8_t* dataDown, size_t* lenDown, bool isConfirmed, LoRaWANEvent_t* eventUp, LoRaWANEvent_t* eventDown) { - if(!dataUp || !dataDown || !lenDown) { + if((lenUp > 0 && !dataUp) || !dataDown || !lenDown) { return(RADIOLIB_ERR_NULL_POINTER); } int16_t state = RADIOLIB_ERR_UNKNOWN; @@ -82,26 +82,44 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } + if(lenUp == 0 && fPort == 0) { + this->isMACPayload = true; + } + // check if the requested payload + fPort are allowed, also given dutycycle - uint8_t totalLen = lenUp + this->fOptsUpLen; - state = this->isValidUplink(&totalLen, fPort); + state = this->isValidUplink(lenUp + this->fOptsUpLen, fPort); RADIOLIB_ASSERT(state); - // in case of TS009, a payload that is too long may have gotten clipped, - // so recalculate the actual payload length - // (outside of TS009, a payload that is too long throws an error) - lenUp = totalLen - this->fOptsUpLen; - // the first 16 bytes are reserved for MIC calculation blocks size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(lenUp, this->fOptsUpLen); #if RADIOLIB_STATIC_ONLY uint8_t uplinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t frmPayload[RADIOLIB_STATIC_ARRAY_SIZE]; #else uint8_t* uplinkMsg = new uint8_t[uplinkMsgLen]; + uint8_t* frmPayload = new uint8_t[lenUp + this->fOptsUpLen]; #endif + + uint8_t frmLen = 0; + + // if the payload consists of piggybacked MAC only, move this to the FRMPayload + if(this->isMACPayload && lenUp == 0) { + memcpy(frmPayload, this->fOptsUp, this->fOptsUpLen); + frmLen = this->fOptsUpLen; + + memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + this->fOptsUpLen = 0; + + this->isMACPayload = false; // reset for next uplink + + // if there is user payload, move this to the FRMPayload + } else { + memcpy(frmPayload, dataUp, lenUp); + frmLen = lenUp; + } // build the encrypted uplink message - this->composeUplink(dataUp, lenUp, uplinkMsg, fPort, isConfirmed); + this->composeUplink(frmPayload, frmLen, uplinkMsg, fPort, isConfirmed); // reset Time-on-Air as we are starting new uplink sequence this->lastToA = 0; @@ -135,8 +153,13 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP (uint8_t)(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS), trans > 0); if(state != RADIOLIB_ERR_NONE) { + // sometimes, a spurious error can occur even though the uplink was transmitted + // therefore, just to be safe, increase frame counter by one for the next uplink + this->fCntUp += 1; + #if !RADIOLIB_STATIC_ONLY delete[] uplinkMsg; + delete[] frmPayload; #endif return(state); } @@ -185,6 +208,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP #if !RADIOLIB_STATIC_ONLY delete[] uplinkMsg; + delete[] frmPayload; #endif // if a hardware error occurred, return @@ -1117,16 +1141,15 @@ void LoRaWANNode::stopMulticastSession() { this->multicast = false; } -int16_t LoRaWANNode::isValidUplink(uint8_t* len, uint8_t fPort) { +int16_t LoRaWANNode::isValidUplink(size_t len, uint8_t fPort) { // check destination fPort switch(fPort) { case RADIOLIB_LORAWAN_FPORT_MAC_COMMAND: { - // MAC FPort only good if internally overruled + // MAC FPort only good if internally overruled (no application payload) if (!this->isMACPayload) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is reserved.", fPort); return(RADIOLIB_ERR_INVALID_PORT); } - // if this is MAC only payload, continue and reset for next uplink - this->isMACPayload = false; } break; case RADIOLIB_LORAWAN_FPORT_TS009: { // TS009 FPort only good if overruled during verification testing @@ -1154,15 +1177,13 @@ int16_t LoRaWANNode::isValidUplink(uint8_t* len, uint8_t fPort) { // check maximum payload len as defined in band uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; if(this->TS011) { - maxPayLen = RADIOLIB_MIN(maxPayLen, 230); // payload length is limited to 230 if under repeater + maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater } - if(*len > maxPayLen) { - // normally, throw an error if the packet is too long - if(this->TS009 == false) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); - } - // if testing with TS009 Specification Verification Protocol, don't throw error but clip the message - *len = maxPayLen; + + // throw an error if the packet is too long + if(len > maxPayLen) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("%d bytes payload exceeding limit of %d bytes", len, maxPayLen); + return(RADIOLIB_ERR_PACKET_TOO_LONG); } return(RADIOLIB_ERR_NONE); @@ -1209,7 +1230,7 @@ void LoRaWANNode::adrBackoff() { return; } // if there is a dwell time limit, check if this datarate allows an empty uplink - if(this->phyLayer->getTimeOnAir(13) / 1000 < this->dwellTimeUp) { + if(this->phyLayer->getTimeOnAir(13) / 1000 <= this->dwellTimeUp) { return; } // if the Time on Air of an empty uplink exceeded the dwell time, revert @@ -1217,11 +1238,40 @@ void LoRaWANNode::adrBackoff() { } } + // last resort: enable all (default) channels if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(); // revert to default frequencies + // in a dynamic band, default channels are never modified, so safe to assume they exist + for(int num = 0; num < 3; num++) { + if(this->band->txFreqs[num].enabled) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num].enabled = true; + } + } } else { - this->selectChannelPlanFix(); // go back to default selected subband + // in a fixed band, all channels must be enabled + // officially, this should be subband = 0, but so far, + // reverting to the used subband seems a sensible solution + this->selectChannelPlanFix(); + } + + // re-enabling default channels may have enabled channels that do support + // the next required datarate; if datarate can be decreased, try it + if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > 0) { + uint8_t oldDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + + if(this->setDatarate(oldDr - 1) == RADIOLIB_ERR_NONE) { + // if there is no dwell time limit, a lower datarate is OK + if(!this->dwellTimeUp) { + return; + } + // if there is a dwell time limit, check if this datarate allows an empty uplink + if(this->phyLayer->getTimeOnAir(13) / 1000 <= this->dwellTimeUp) { + return; + } + // if the Time on Air of an empty uplink exceeded the dwell time, revert + this->setDatarate(oldDr); + } } + this->nbTrans = 1; // as there is nothing more to do, set ADR counter to maximum value to indicate that we've tried everything @@ -1298,7 +1348,7 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, processAES(in, lenIn, encKey, &out[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(this->fOptsUpLen)], this->devAddr, this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x00, true); } -void LoRaWANNode::micUplink(uint8_t* inOut, uint8_t lenInOut) { +void LoRaWANNode::micUplink(uint8_t* inOut, size_t lenInOut) { // create blocks for MIC calculation uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; @@ -1400,7 +1450,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u // yield for multi-threaded platforms mod->hal->yield(); - if(mod->hal->millis() > txEnd + toa) { + if(mod->hal->millis() > txEnd + this->scanGuard) { return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -1820,7 +1870,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } // get the frame counter - uint32_t payFCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); + uint16_t payFCnt16 = LoRaWANNode::ntoh(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCNT_POS]); // check the FCntDown value (Network or Application, or Multicast) uint32_t devFCnt32 = 0; @@ -1836,11 +1886,18 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } } + // if the downlink FCnt16 value is 'slightly' lower than expected by the device, assume a replay attack + uint16_t devFCnt16 = (uint16_t)devFCnt32; + if(devFCnt16 > 0 && (uint16_t)(devFCnt16 - payFCnt16) < RADIOLIB_LORAWAN_MIN_ROLLOVER_FCNT_GAP) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rejected: %d -> %d", devFCnt16, payFCnt16); + return(RADIOLIB_ERR_DOWNLINK_FCNT_INVALID); + } + // assume a rollover if the FCnt16 in the payload is smaller than the previous FCnt16 known by device // (MAX_FCNT_GAP is deprecated for 1.0.4 / 1.1, TTS and CS both apply a 16-bit rollover) - if(payFCnt16 < (devFCnt32 & 0xFFFF)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rollover: %d -> %d", payFCnt16, devFCnt32); - devFCnt32 += 0x10000; // apply rollover + if(payFCnt16 < devFCnt16) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rollover: %d -> %d", devFCnt16, payFCnt16); + devFCnt32 += 0x10000; // add 16-bit value } devFCnt32 &= ~0xFFFF; // clear lower 16 bits known by device devFCnt32 |= payFCnt16; // set lower 16 bits from payload @@ -2009,6 +2066,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L if(state != RADIOLIB_ERR_NONE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Unknown MAC CID %02x", cid); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + fOptsLen = procLen; // truncate to last processed MAC command break; } @@ -2020,6 +2078,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L if(procLen + fLen > fOptsLen) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen - procLen, fLen); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + fOptsLen = procLen; // truncate to last processed MAC command break; } @@ -2065,7 +2124,8 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L reply = this->execMacCommand(cid, mPtr + 1, fLen - 1, &fOptsRe[fOptsReLen + 1]); } - if(reply) { + // if there is a reply, only add it to the reply if maximum payload size allows + if(reply && (fOptsReLen + fLenRe <= this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr])) { fOptsRe[fOptsReLen] = cid; fOptsReLen += fLenRe; } @@ -2244,14 +2304,17 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin macTxSteps = this->txPowerSteps; } - int8_t power = this->txPowerMax - 2*macTxSteps; - int8_t powerActual = 0; - state = this->phyLayer->checkOutputPower(power, &powerActual); - // only acknowledge if the radio is able to operate at or below the requested power level - if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { - pwrAck = 1; - } else { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); + // only allow TxPower if less than / equal to the maximum number of defined steps + if(macTxSteps <= this->band->powerNumSteps) { + int8_t power = this->txPowerMax - 2*macTxSteps; + int8_t powerActual = 0; + state = this->phyLayer->checkOutputPower(power, &powerActual); + // only acknowledge if the radio is able to operate at or below the requested power level + if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) { + pwrAck = 1; + } else { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state); + } } // set ACK bits diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 35ddf1da61..98ea9d7d79 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -97,6 +97,9 @@ #define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks #define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented +// developer recommended default setting (not specified) +#define RADIOLIB_LORAWAN_MIN_ROLLOVER_FCNT_GAP (16384) // equal to deprecated MaxFCntGap + // join request message layout #define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) #define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) @@ -1050,7 +1053,7 @@ class LoRaWANNode { void processCFList(const uint8_t* cfList); // check whether payload length and fport are allowed - int16_t isValidUplink(uint8_t* len, uint8_t fPort); + int16_t isValidUplink(size_t len, uint8_t fPort); // perform ADR backoff void adrBackoff(); @@ -1059,7 +1062,7 @@ class LoRaWANNode { void composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, uint8_t fPort, bool isConfirmed); // generate and set the MIC of an uplink buffer (depends on selected channels) - void micUplink(uint8_t* inOut, uint8_t lenInOut); + void micUplink(uint8_t* inOut, size_t lenInOut); // transmit uplink buffer on a specified channel int16_t transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans = false); From 827fbd9f171c2a2a923d76e6451980a49225c88d Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 16 Jun 2025 10:56:38 +0200 Subject: [PATCH 1556/1848] Add new LoRaWAN examples to the LoRaWAN README --- examples/LoRaWAN/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/LoRaWAN/README.md b/examples/LoRaWAN/README.md index 871dbddbba..2ad96c20a8 100644 --- a/examples/LoRaWAN/README.md +++ b/examples/LoRaWAN/README.md @@ -4,6 +4,8 @@ RadioLib LoRaWAN examples. * [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) that come with this example to learn more about LoRaWAN and how to use it in RadioLib! * [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)! * [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA, this example shows how you can do this using RadioLib. However, to comply with the specification, the full session must persist through resets and power loss - you would need proper NVM for this. Really, we recommend using OTAA. +* [LoRaWAN_Class_C](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Class_C): this shows how to use Class C on top of Class A. This is useful for continuously-powered devices (no batteries) such as lights. If you deploy multiple similar devices, please use Multicast instead. +* [LoRaWAN_Multicast](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Multicast): a showcase of Multicast over Class C. This is particularly useful for groups of devices such as a series of street lights. > [!CAUTION] > These examples are quick wins during development. However, for production devices, you will need to add persistence to your device. See the wiki for more details, or head straight to some [persistence examples](https://github.com/radiolib-org/radiolib-persistence). From 5b38ce9f2080ef984b4d5bee5c04abfa5174d1bb Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 16 Jun 2025 10:56:46 +0200 Subject: [PATCH 1557/1848] Add LoRaWAN Class and pre-certification info to README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0066ccaac1..281178043c 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,10 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__LoRaWAN__](https://lora-alliance.org/) using LoRa and FSK for modules: -SX127x, RFM9x, SX126x, LR11x0 and SX128x +SX127x, RFM9x, SX126x, LR11x0 and SX128x + * Supports Class A and C (and Multicast over C) + * Pre-certified for Class A on dynamic channelplans (EU868-style) + * See the [wiki](https://github.com/jgromes/RadioLib/wiki/LoRaWAN) and [notes](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for more information. ### Supported Arduino platforms: * __Arduino__ From a7db7947f1eb14f63aa5f3a5a105e8ef639040f9 Mon Sep 17 00:00:00 2001 From: Christian Harris Date: Wed, 18 Jun 2025 16:47:55 -0700 Subject: [PATCH 1558/1848] Optimize CAD for improved detection rate and SF5/SF6 --- src/modules/SX126x/SX126x.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 4753c0ce96..abe8508103 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1866,20 +1866,12 @@ int16_t SX126x::setRx(uint32_t timeout) { } int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { - // default CAD parameters are shown in Semtech AN1200.48, page 41. - const uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30}; - - // CAD parameters aren't available for SF-6. Just to be safe. - if(this->spreadingFactor < 7) { - this->spreadingFactor = 7; - } else if(this->spreadingFactor > 12) { - this->spreadingFactor = 12; - } + // default CAD parameters are selected according to recommendations on Semtech DS.SX1261-2.W.APP rev. 1.1, page 92. // build the packet with default configuration uint8_t data[7]; - data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB; - data[1] = detPeakValues[this->spreadingFactor - 7]; + data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; + data[1] = this->spreadingFactor + 13; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; uint32_t timeout_raw = (float)timeout / 15.625f; From 70b0a89b014792a1bc4e33db4b209048d754b95e Mon Sep 17 00:00:00 2001 From: Darian Leung <32921628+Dazza0@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:30:21 +0800 Subject: [PATCH 1559/1848] [LR11X0] Add support for specifying PA ramp time - `setOutputPower()` now accepts a `rampTimeUs` argument - `roundRampTime()` rounds up the ramp time to a discerte register value supported by the LR11X0 module. --- src/modules/LR11x0/LR1110.cpp | 4 +-- src/modules/LR11x0/LR1110.h | 4 ++- src/modules/LR11x0/LR1120.cpp | 4 +-- src/modules/LR11x0/LR1120.h | 4 ++- src/modules/LR11x0/LR11x0.h | 25 ++++++++++++++- src/modules/LR11x0/LR11x0_commands.cpp | 42 ++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 186f8331a6..43aeddbce1 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -71,7 +71,7 @@ int16_t LR1110::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } -int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { +int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs) { // check if power value is configurable int16_t state = this->checkOutputPower(power, NULL, forceHighPower); RADIOLIB_ASSERT(state); @@ -86,7 +86,7 @@ int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower) { RADIOLIB_ASSERT(state); // set output power - state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + state = setTxParams(power, roundRampTime(rampTimeUs)); return(state); } diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index b20388593e..e1503de150 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -103,9 +103,11 @@ class LR1110: public LR11x0 { \param power Output power to be set in dBm. \param forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used. + \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the + nearest discrete ramp time supported by the PA. Defaults to 48 us. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool forceHighPower); + int16_t setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs = 48); /*! \brief Check if output power is configurable. diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 6c6c14e44b..fb0d9050fb 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -78,7 +78,7 @@ int16_t LR1120::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } -int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower) { +int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs) { // check if power value is configurable int16_t state = this->checkOutputPower(power, NULL, forceHighPower); RADIOLIB_ASSERT(state); @@ -100,7 +100,7 @@ int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower) { RADIOLIB_ASSERT(state); // set output power - state = setTxParams(power, RADIOLIB_LR11X0_PA_RAMP_48U); + state = setTxParams(power, roundRampTime(rampTimeUs)); return(state); } diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index 3c532ebd14..d60933d2ec 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -112,9 +112,11 @@ class LR1120: public LR11x0 { If set to false, PA will be determined automatically based on configured output power and frequency, preferring the low-power PA but always using high-frequency PA in 2.4 GHz band. Ignored when operating in 2.4 GHz band. + \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the + nearest discrete ramp time supported by the PA. Defaults to 48 us. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, bool forceHighPower); + int16_t setOutputPower(int8_t power, bool forceHighPower, uint32_t rampTimeUs = 48); /*! \brief Check if output power is configurable. diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 6e95bde30d..c7f2d6278d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -443,7 +443,22 @@ #define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled // RADIOLIB_LR11X0_CMD_SET_TX_PARAMS -#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 PA ramp time: 48 us +#define RADIOLIB_LR11X0_PA_RAMP_16U (0x00UL << 0) // 7 0 PA ramp time: 16 us +#define RADIOLIB_LR11X0_PA_RAMP_32U (0x01UL << 0) // 7 0 32 us +#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 48 us +#define RADIOLIB_LR11X0_PA_RAMP_64U (0x03UL << 0) // 7 0 64 us +#define RADIOLIB_LR11X0_PA_RAMP_80U (0x04UL << 0) // 7 0 80 us +#define RADIOLIB_LR11X0_PA_RAMP_96U (0x05UL << 0) // 7 0 96 us +#define RADIOLIB_LR11X0_PA_RAMP_112U (0x06UL << 0) // 7 0 112 us +#define RADIOLIB_LR11X0_PA_RAMP_128U (0x07UL << 0) // 7 0 128 us +#define RADIOLIB_LR11X0_PA_RAMP_144U (0x08UL << 0) // 7 0 144 us +#define RADIOLIB_LR11X0_PA_RAMP_160U (0x09UL << 0) // 7 0 160 us +#define RADIOLIB_LR11X0_PA_RAMP_176U (0x0AUL << 0) // 7 0 176 us +#define RADIOLIB_LR11X0_PA_RAMP_192U (0x0BUL << 0) // 7 0 192 us +#define RADIOLIB_LR11X0_PA_RAMP_208U (0x0CUL << 0) // 7 0 208 us +#define RADIOLIB_LR11X0_PA_RAMP_240U (0x0DUL << 0) // 7 0 240 us +#define RADIOLIB_LR11X0_PA_RAMP_272U (0x0EUL << 0) // 7 0 272 us +#define RADIOLIB_LR11X0_PA_RAMP_304U (0x0FUL << 0) // 7 0 304 us // RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE #define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC @@ -1610,6 +1625,14 @@ class LR11x0: public PhysicalLayer { #endif Module* getMod() override; + // LR11x0 command helpers + /*! + \brief Round up a PA power ramp time to register value + \param rampTimeUs Ramp time in microseconds + \returns Register value of rounded ramp time + */ + uint8_t roundRampTime(uint32_t rampTimeUs); + // LR11x0 SPI command implementations int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index e00232e4a7..e40c2fdd42 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -8,6 +8,48 @@ #if !RADIOLIB_EXCLUDE_LR11X0 +uint8_t LR11x0::roundRampTime(uint32_t rampTimeUs) +{ + uint8_t regVal; + + // Round up the ramp time to nearest discrete register value + if(rampTimeUs <= 16) { + regVal = RADIOLIB_LR11X0_PA_RAMP_16U; + } else if(rampTimeUs <= 32) { + regVal = RADIOLIB_LR11X0_PA_RAMP_32U; + } else if(rampTimeUs <= 48) { + regVal = RADIOLIB_LR11X0_PA_RAMP_48U; + } else if(rampTimeUs <= 64) { + regVal = RADIOLIB_LR11X0_PA_RAMP_64U; + } else if(rampTimeUs <= 80) { + regVal = RADIOLIB_LR11X0_PA_RAMP_80U; + } else if(rampTimeUs <= 96) { + regVal = RADIOLIB_LR11X0_PA_RAMP_96U; + } else if(rampTimeUs <= 112) { + regVal = RADIOLIB_LR11X0_PA_RAMP_112U; + } else if(rampTimeUs <= 128) { + regVal = RADIOLIB_LR11X0_PA_RAMP_128U; + } else if(rampTimeUs <= 144) { + regVal = RADIOLIB_LR11X0_PA_RAMP_144U; + } else if(rampTimeUs <= 160) { + regVal = RADIOLIB_LR11X0_PA_RAMP_160U; + } else if(rampTimeUs <= 176) { + regVal = RADIOLIB_LR11X0_PA_RAMP_176U; + } else if(rampTimeUs <= 192) { + regVal = RADIOLIB_LR11X0_PA_RAMP_192U; + } else if(rampTimeUs <= 208) { + regVal = RADIOLIB_LR11X0_PA_RAMP_208U; + } else if(rampTimeUs <= 240) { + regVal = RADIOLIB_LR11X0_PA_RAMP_240U; + } else if(rampTimeUs <= 272) { + regVal = RADIOLIB_LR11X0_PA_RAMP_272U; + } else { // 304 + regVal = RADIOLIB_LR11X0_PA_RAMP_304U; + } + + return regVal; +} + int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { From 83fbedb83354c29e5a7156f230f32c0aeafd9dd9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 20 Jun 2025 18:15:43 +0200 Subject: [PATCH 1560/1848] [SX126x] Fixed packet offset in implicit header mode (#1520) --- src/modules/SX126x/SX126x.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index abe8508103..5291c0137d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1316,11 +1316,12 @@ size_t SX126x::getPacketLength(bool update) { size_t SX126x::getPacketLength(bool update, uint8_t* offset) { (void)update; - // in implicit mode, return the cached value - if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT)) { + // in implicit mode, return the cached value if the offset was not requested + if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (!offset)) { return(this->implicitLen); } + // if offset was requested, or in explicit mode, we always have to perform the SPI transaction uint8_t rxBufStatus[2] = {0, 0}; this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); From f2fbd73044ac93f9a9ba8284e6954b59960d0d79 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sat, 21 Jun 2025 15:48:30 +0200 Subject: [PATCH 1561/1848] [LoRaWAN] Provide support for TSxxx packages (including TS009 reference implementation) (#1528) * [LoRaWAN] Fix for incorrect use of dutycycle function * [LoRaWAN] Implement TSxxx package support And fix an MIC problem for >16-bit downlink FCnt * Revert unused error code * [LoRaWAN] Add TS009 example * [LoRaWAN] Comment a platform dependency in TS009 header * [LoRaWAN] Make TSxxx example platform independent * [LoRaWAN] Remove unused variable * [LoRaWAN] Remove printf from example * [LoRaWAN] Fix scope of variables * [LoRaWAN] Remove printf from example * [LoRaWAN] Fix cppcheck issue * [LoRaWAN] Feedback improvements --- .../LoRaWAN_TS_Packages/LoRaWAN_TS009.h | 239 ++++++++ .../LoRaWAN_TS_Packages.ino | 171 ++++++ examples/LoRaWAN/LoRaWAN_TS_Packages/config.h | 115 ++++ .../LoRaWAN/LoRaWAN_TS_Packages/lorawan.h | 76 +++ src/TypeDef.h | 9 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 571 +++++++++--------- src/protocols/LoRaWAN/LoRaWAN.h | 110 +++- 7 files changed, 1000 insertions(+), 291 deletions(-) create mode 100644 examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h create mode 100644 examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino create mode 100644 examples/LoRaWAN/LoRaWAN_TS_Packages/config.h create mode 100644 examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h new file mode 100644 index 0000000000..6e360c5d3d --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h @@ -0,0 +1,239 @@ +#include +#include +// #include + +#warning "The variables below must match your main code. Please check your radio type!" +extern SX1278 radio; // this can be any LoRaWAN-compatible type (e.g. SX1262) +extern LoRaWANNode node; +extern uint32_t periodicity; +extern bool isConfirmed; +extern bool reply; +extern uint8_t dataUp[255]; +extern size_t lenUp; +extern uint8_t fPort; + +#define RADIOLIB_LORAWAN_TS009_PACKAGE_VERSION (0x00) +#define RADIOLIB_LORAWAN_TS009_DUT_RESET (0x01) +#define RADIOLIB_LORAWAN_TS009_DUT_JOIN (0x02) +#define RADIOLIB_LORAWAN_TS009_SWITCH_CLASS (0x03) +#define RADIOLIB_LORAWAN_TS009_ADR_BIT_CHANGE (0x04) +#define RADIOLIB_LORAWAN_TS009_REGIONAL_DUTY_CYCLE (0x05) +#define RADIOLIB_LORAWAN_TS009_TX_PERIODICITY_CHANGE (0x06) +#define RADIOLIB_LORAWAN_TS009_TX_FRAMES_CTRL (0x07) +#define RADIOLIB_LORAWAN_TS009_ECHO_PAYLOAD (0x08) +#define RADIOLIB_LORAWAN_TS009_RX_APP_CNT (0x09) +#define RADIOLIB_LORAWAN_TS009_RX_APP_CNT_RESET (0x0A) +#define RADIOLIB_LORAWAN_TS009_LINK_CHECK (0x20) +#define RADIOLIB_LORAWAN_TS009_DEVICE_TIME (0x21) +#define RADIOLIB_LORAWAN_TS009_PING_SLOT_INFO (0x22) +#define RADIOLIB_LORAWAN_TS009_TX_CW (0x7D) +#define RADIOLIB_LORAWAN_TS009_DUT_FPORT224_DISABLE (0x7E) +#define RADIOLIB_LORAWAN_TS009_DUT_VERSIONS (0x7F) + +/*! + \brief This function implements the TS009 specification. + To enable this package, add this to your setup: + `node.addAppPackage(RADIOLIB_LORAWAN_PACKAGE_TS009, handleTS009)` + Make sure that all `extern` variables are handled in your user code! +*/ +void handleTS009(uint8_t* dataDown, size_t lenDown) { + if(lenDown == 0 || dataDown == NULL) { + return; + } + RADIOLIB_DEBUG_PRINTLN("CID = %02x, len = %d", dataDown[0], lenDown - 1); + + switch(dataDown[0]) { + case(RADIOLIB_LORAWAN_TS009_PACKAGE_VERSION): { + lenUp = 3; + dataUp[1] = 5; // PackageIdentifier + dataUp[2] = 1; // PackageVersion + fPort = RADIOLIB_LORAWAN_FPORT_TS009; + RADIOLIB_DEBUG_PRINTLN("PackageIdentifier: %d, PackageVersion: %d", dataUp[1], dataUp[2]); + + reply = true; + } break; + + case(RADIOLIB_LORAWAN_TS009_DUT_RESET): { + RADIOLIB_DEBUG_PRINTLN("Restarting..."); + + #warning "Please implement this reset function yourself!" + + // the function to reset the MCU is platform-dependent + // for ESP32 for example, this would be: + // ESP.restart(); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_DUT_JOIN): { + RADIOLIB_DEBUG_PRINTLN("Reverting to Join state"); + node.clearSession(); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_SWITCH_CLASS): { + uint8_t classType = dataDown[1]; + node.setClass(classType); + RADIOLIB_DEBUG_PRINTLN("Switching to class: %s", classType == 0 ? "A" : (classType == 1 ? "B" : "C")); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_ADR_BIT_CHANGE): { + bool adr = (bool)dataDown[1]; + node.setADR(adr); + RADIOLIB_DEBUG_PRINTLN("ADR: %d", adr); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_REGIONAL_DUTY_CYCLE): { + bool dutycycle = (bool)dataDown[1]; + node.setDutyCycle(dutycycle, 36000); + RADIOLIB_DEBUG_PRINTLN("Dutycycle: %d", dutycycle); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_TX_PERIODICITY_CHANGE): { + uint32_t defaultIntervalSecs = 30; + uint32_t intervals[11] = {defaultIntervalSecs, 5, 10, 20, 30, 40, 50, 60, 120, 240, 480}; + periodicity = intervals[dataDown[1]]; + + RADIOLIB_DEBUG_PRINTLN("Tx Periodicity: %d", periodicity); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_TX_FRAMES_CTRL): { + switch(dataDown[1]) { + case(0): + // no change + // isConfirmed = isConfirmed; + break; + case(1): + isConfirmed = false; + break; + case(2): + isConfirmed = true; + break; + } + RADIOLIB_DEBUG_PRINTLN("Confirmed: %d", isConfirmed); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_ECHO_PAYLOAD): { + lenUp = lenDown; + for (int i = 1; i < lenDown; i++) { + dataUp[i] = dataDown[i] + 1; + } + fPort = RADIOLIB_LORAWAN_FPORT_TS009; + RADIOLIB_DEBUG_PRINTLN("Echoing payload"); + + reply = true; + } break; + + case(RADIOLIB_LORAWAN_TS009_RX_APP_CNT): { + lenUp = 3; + uint16_t aFcntDown16 = (uint16_t)node.getAFCntDown(); + dataUp[1] = aFcntDown16 & 0xFF; + dataUp[2] = aFcntDown16 >> 8; + fPort = RADIOLIB_LORAWAN_FPORT_TS009; + RADIOLIB_DEBUG_PRINTLN("aFCntDown16: %d", aFcntDown16); + + reply = true; + } break; + + case(RADIOLIB_LORAWAN_TS009_RX_APP_CNT_RESET): { + RADIOLIB_DEBUG_PRINTLN("Resetting Application Frame count"); + node.resetFCntDown(); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_LINK_CHECK): { + lenUp = 0; + fPort = RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK); + RADIOLIB_DEBUG_PRINTLN("Requesting LinkCheck"); + + reply = true; + } break; + + case(RADIOLIB_LORAWAN_TS009_DEVICE_TIME): { + lenUp = 0; + fPort = RADIOLIB_LORAWAN_FPORT_MAC_COMMAND; + node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME); + RADIOLIB_DEBUG_PRINTLN("Requesting DeviceTime"); + + reply = true; + } break; + + case(RADIOLIB_LORAWAN_TS009_PING_SLOT_INFO): { + lenUp = 0; + RADIOLIB_DEBUG_PRINTLN("Requesting PingSlotInfo not implemented"); + // send PingSlotInfo MAC command which is not implemented + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_TX_CW): { + // not implemented + uint16_t timeout = (dataDown[2] << 8) | dataDown[1]; + uint32_t freqRaw = (dataDown[5] << 16) | (dataDown[4] << 8) | (dataDown[3]); + float freq = (float)freqRaw/10000.0; + uint8_t txPower = dataDown[6]; + RADIOLIB_DEBUG_PRINTLN("Continuous wave: %7.3f MHz, %d dBm, %d s", freq, txPower, timeout); + radio.setFrequency(freq); + radio.setOutputPower(txPower); + radio.transmitDirect(); + delay(timeout * 1000); + radio.standby(); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_DUT_FPORT224_DISABLE): { + RADIOLIB_DEBUG_PRINTLN("Disabling FPort 224"); + node.removePackage(RADIOLIB_LORAWAN_PACKAGE_TS009); + + reply = false; + } break; + + case(RADIOLIB_LORAWAN_TS009_DUT_VERSIONS): { + lenUp = 13; + // firmware version - this is RadioLib's version as an example + dataUp[1] = RADIOLIB_VERSION_MAJOR; + dataUp[2] = RADIOLIB_VERSION_MINOR; + dataUp[3] = RADIOLIB_VERSION_PATCH; + dataUp[4] = RADIOLIB_VERSION_EXTRA; + + // lorawan version + dataUp[5] = 1; +#if (LORAWAN_VERSION == 1) + dataUp[6] = 1; + dataUp[7] = 0; +#else + dataUp[6] = 0; + dataUp[7] = 4; +#endif + dataUp[8] = 0; + + // regional parameters version + dataUp[9] = 1; + dataUp[10] = 0; + dataUp[11] = 4; + dataUp[12] = 0; + fPort = RADIOLIB_LORAWAN_FPORT_TS009; + RADIOLIB_DEBUG_PRINTLN("Requested DUT versions"); + + reply = true; + } break; + } + + // if we must reply, copy the command ID into the uplink buffer + if(reply) { + dataUp[0] = dataDown[0]; + } +} \ No newline at end of file diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino new file mode 100644 index 0000000000..f9c1f437c3 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino @@ -0,0 +1,171 @@ +/* + RadioLib LoRaWAN Packages Example + + This example shows how the TS009 package can be used + and is the sketch used for passing pre-certification testing. + This scheme can also be used for other future packages + such as TS003/004/005/006/007 which, combined, build FUOTA. + + PLEASE NOTE that this is a highly customized sketch with + settings that likely violate laws & regulations, and it is + intended to be used with RF blocking materials and attenuators. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + For LoRaWAN details, see the wiki page + https://github.com/jgromes/RadioLib/wiki/LoRaWAN + +*/ + +#include +#include + +#include "LoRaWAN_TS009.h" +#include "config.h" +#include "lorawan.h" + +uint32_t periodicity = uplinkIntervalSeconds; +bool isConfirmed = false; +bool reply = false; + +uint8_t fPort = 1; +uint8_t dataUp[255]; +uint8_t dataDown[255]; +size_t lenUp = 0; +size_t lenDown = 0; + +void setup() { + Serial.begin(115200); + delay(3000); + + Serial.print(F("Initialise the radio ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // setup, restore and join the network + lwBegin(); + lwRestore(); + lwActivate(); + + // add TS009 package + node.addAppPackage(RADIOLIB_LORAWAN_PACKAGE_TS009, handleTS009); + + // LCTT (TS009 testing) has a huge timing problem on the JoinAccept Rx2 window... + node.scanGuard = 100; + + // these settings are totally not recommended + // but unfortunately they are the default settings for TS009 testing + node.setDutyCycle(false); + node.setADR(false); +} + +void loop() { + while(!node.isActivated()) { + lwActivate(); + // this 5s interval is way too short for normal use! + // but you'd be waiting around for long minutes during TS009 testing otherwise + if(!node.isActivated()) { + delay(5000); + } + node.setDutyCycle(false); + } + + int state = RADIOLIB_ERR_NONE; + LoRaWANEvent_t eventUp; + LoRaWANEvent_t eventDown; + + uint32_t start = millis(); + + Serial.println("--------------------"); + Serial.println("[LoRaWAN] Sending uplink packet ... "); + if (!reply) { + memset(dataUp, 0, 255); + lenUp = 4; + fPort = 1; + sprintf((char*)dataUp, "%04d", node.getFCntUp()); + state = node.sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, &eventUp, &eventDown); + } else { + reply = false; + state = node.sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, &eventUp, &eventDown); + } + + if(state >= RADIOLIB_ERR_NONE) { + Serial.println(F("[LoRaWAN] success!")); + } + + if(state > 0) { + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(lenDown > 0) { + arrayDump(dataDown, lenDown); + } else { + Serial.println(F("")); + } + + Serial.print(F("[LoRaWAN] FPort:\t")); + Serial.print(eventDown.fPort); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LoRaWAN] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LoRaWAN] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + uint8_t margin = 0; + uint8_t gwCnt = 0; + if(node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) { + Serial.print(F("[LoRaWAN] LinkCheck margin:\t")); + Serial.println(margin); + Serial.print(F("[LoRaWAN] LinkCheck count:\t")); + Serial.println(gwCnt); + } + + uint32_t networkTime = 0; + uint8_t fracSecond = 0; + if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) { + Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); + Serial.println(networkTime); + Serial.print(F("[LoRaWAN] DeviceTime second:\t")); + Serial.print(fracSecond); + Serial.println(F("/256")); + } + + } else if(state == 0) { + Serial.println(F("No downlink!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + uint32_t end = millis(); + + uint32_t delayDc = node.timeUntilUplink(); + uint32_t delayMs = periodicity*1000; + if(delayMs > end - start) { + delayMs -= (end - start); + } else { + delayMs = 1; + } + delayMs += 50; + Serial.print(F("Delay: ")); + Serial.print(max(delayDc, delayMs)); + Serial.println(F(" ms")); + + // wait before sending another packet + delay(max(delayDc, delayMs)); +} \ No newline at end of file diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/config.h b/examples/LoRaWAN/LoRaWAN_TS_Packages/config.h new file mode 100644 index 0000000000..9c64a4da04 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/config.h @@ -0,0 +1,115 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +// first you have to set your radio model and pin configuration +// this is provided just as a default example +SX1278 radio = new Module(10, 2, 9, 3); + +// if you have RadioBoards (https://github.com/radiolib-org/RadioBoards) +// and are using one of the supported boards, you can do the following: +/* +#define RADIO_BOARD_AUTO +#include + +Radio radio = new RadioModule(); +*/ + +// how often to send an uplink - consider legal & FUP constraints +const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds + +#define LORAWAN_VERSION (0) // use version 1.LORAWAN_VERSION when joining +#define LORAWAN_OTAA (1) // use OTAA (1) or ABP (0) + +#if (LORAWAN_OTAA == 1) +// joinEUI - previous versions of LoRaWAN called this AppEUI +// for development purposes you can use all zeros - see wiki for details +#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000 + +// the Device EUI & two keys can be generated on the TTN console +#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI +#define RADIOLIB_LORAWAN_DEV_EUI 0x---------------- +#endif +#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key +#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted +uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI; +uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI; +uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY }; + +#if (LORAWAN_VERSION == 1) +#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here +#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY }; // LW v1.1 only +#endif + +#else // ABP + +#ifndef RADIOLIB_LORAWAN_DEV_ADDR // Replace with your DevAddr +#define RADIOLIB_LORAWAN_DEV_ADDR 0x------ +#endif + +#ifndef RADIOLIB_LORAWAN_NWKSENC_KEY // Replace with your NwkSEnc Key +#define RADIOLIB_LORAWAN_NWKSENC_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_APPS_KEY // Replace with your AppS Key +#define RADIOLIB_LORAWAN_APPS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif + +// copy over the keys in to the something that will not compile if incorrectly formatted +uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR; +uint8_t sNwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; +uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY }; + +#if (LORAWAN_VERSION == 1) +#ifndef RADIOLIB_LORAWAN_FNWKSINT_KEY // Replace with your FNwkSInt Key +#define RADIOLIB_LORAWAN_FNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +#ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key +#define RADIOLIB_LORAWAN_SNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x-- +#endif +uint8_t fNwkSIntKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY }; // LW v1.1 only +uint8_t sNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // LW v1.1 only +#endif + +#endif // OTAA/ABP + +// for the curious, the #ifndef blocks allow for automated testing &/or you can +// put your EUI & keys in to your platformio.ini - see wiki for more tips + +// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t Region = EU868; +const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0 + +// ============================================================================ +// Below is to support the sketch - only make changes if the notes say so ... + +// create the LoRaWAN node +LoRaWANNode node(&radio, &Region, subBand); + +// helper function to display any issues +void debug(bool isFail, const __FlashStringHelper* message, int state, bool Freeze) { + if (isFail) { + Serial.print(message); + Serial.print("("); + Serial.print(state); + Serial.println(")"); + while (Freeze); + } +} + +// helper function to display a byte array +void arrayDump(uint8_t *buffer, uint16_t len) { + for(uint16_t c = 0; c < len; c++) { + char b = buffer[c]; + if(b < 0x10) { Serial.print('0'); } + Serial.print(b, HEX); + } + Serial.println(); +} + +#endif \ No newline at end of file diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h b/examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h new file mode 100644 index 0000000000..95220fcbc6 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/lorawan.h @@ -0,0 +1,76 @@ +#ifndef _LORAWAN_H +#define _LORAWAN_H + +#include +#include "config.h" + +#warning "You are required to implement persistence here! (ESP32 example provided in comments)" + +// #include +// Preferences store; +// uint8_t LWnonces[RADIOLIB_LORAWAN_NONCES_BUF_SIZE]; + +bool lwBegin() { +#if (LORAWAN_OTAA == 1) + #if (LORAWAN_VERSION == 1) + node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + #else + node.beginOTAA(joinEUI, devEUI, NULL, appKey); + #endif +#else + #if (LORAWAN_VERSION == 1) + node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, sNwkSEncKey, appSKey); + #else + node.beginABP(devAddr, NULL, NULL, sNwkSEncKey, appSKey); + #endif +#endif + return(true); +} + +int16_t lwRestore() { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // store.begin("radiolib"); + // if (store.isKey("nonces")) { + // radio.standby(); + + // store.getBytes("nonces", LWnonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + // state = node.setBufferNonces(LWnonces); + // } + // store.end(); + + return(state); +} + +void lwActivate() { + int16_t state = RADIOLIB_ERR_NETWORK_NOT_JOINED; + Serial.println(F("[LoRaWAN] Attempting network join ... ")); + + radio.standby(); + +#if (LORAWAN_OTAA == 1) + state = node.activateOTAA(); +#else + state = node.activateABP(); +#endif + + if(state == RADIOLIB_LORAWAN_SESSION_RESTORED) { + Serial.println(F("[LoRaWAN] Session restored!")); + return; + } + + // store.begin("radiolib"); + // uint8_t *persist = node.getBufferNonces(); + // store.putBytes("nonces", persist, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); + // store.end(); + + if(state == RADIOLIB_LORAWAN_NEW_SESSION) { + Serial.println(F("[LoRaWAN] Successfully started new session!")); + return; + } + + Serial.print(F("[LoRaWAN] Failed, code ")); + Serial.println(state); +} + +#endif \ No newline at end of file diff --git a/src/TypeDef.h b/src/TypeDef.h index ae1841d971..c9d550f926 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -549,9 +549,9 @@ #define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111) /*! - \brief The downlink frame counter is slightly lower than expected, looks like a replay attack. + \brief The downlink MIC could not be verified (incorrect key or invalid FCnt) */ -#define RADIOLIB_ERR_DOWNLINK_FCNT_INVALID (-1112) +#define RADIOLIB_ERR_MIC_MISMATCH (-1112) /*! \brief Multicast frame counter is invalid (outside bounds). @@ -598,11 +598,6 @@ */ #define RADIOLIB_ERR_INVALID_MODE (-1121) -/*! - \brief The downlink MIC could not be verified (incorrect key or invalid FCnt) -*/ -#define RADIOLIB_ERR_MIC_MISMATCH (-1122) - // LR11x0-specific status codes /*! diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e2cf3ee0d9..29f569ae35 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -14,6 +14,9 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t this->txPowerMax = this->band->powerMax; this->subBand = subBand; memset(this->channelPlan, 0, sizeof(this->channelPlan)); + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; i++) { + this->packages[i] = RADIOLIB_LORAWAN_PACKAGE_NONE; + } } #if defined(RADIOLIB_BUILD_ARDUINO) @@ -228,10 +231,6 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP LoRaWANNode::clearMacCommands(this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); return(rxWindow); } - - // a downlink was received, so we can clear the whole MAC uplink buffer - memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); - this->fOptsUpLen = 0; state = this->parseDownlink(dataDown, lenDown, rxWindow, eventDown); RADIOLIB_ASSERT(state); @@ -1143,40 +1142,30 @@ void LoRaWANNode::stopMulticastSession() { int16_t LoRaWANNode::isValidUplink(size_t len, uint8_t fPort) { // check destination fPort - switch(fPort) { - case RADIOLIB_LORAWAN_FPORT_MAC_COMMAND: { - // MAC FPort only good if internally overruled (no application payload) - if (!this->isMACPayload) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is reserved.", fPort); - return(RADIOLIB_ERR_INVALID_PORT); - } - } break; - case RADIOLIB_LORAWAN_FPORT_TS009: { - // TS009 FPort only good if overruled during verification testing - if(!this->TS009) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is not enabled.", fPort); - return(RADIOLIB_ERR_INVALID_PORT); - } - } break; - case RADIOLIB_LORAWAN_FPORT_TS011: { - // TS011 FPort only good if overruled during relay exchange - if(!this->TS011) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is not enabled.", fPort); - return(RADIOLIB_ERR_INVALID_PORT); - } - } break; - default: { - if((fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN) && (fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX)) { - // user payload ports, all good + bool ok = false; + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && this->isMACPayload) { + ok = true; + } + if(fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN && fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX) { + ok = true; + } + if(fPort >= RADIOLIB_LORAWAN_FPORT_RESERVED) { + for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { + if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + ok = true; break; } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is reserved.", fPort); - } break; + } + } + + if(!ok) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Requested uplink at FPort %d - rejected! This FPort is reserved.", fPort); + return(RADIOLIB_ERR_INVALID_PORT); } // check maximum payload len as defined in band uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; - if(this->TS011) { + if(this->packages[RADIOLIB_LORAWAN_PACKAGE_TS011].enabled) { maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater } @@ -1340,9 +1329,16 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, // select encryption key based on the target fPort uint8_t* encKey = this->appSKey; - if((fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) || (fPort == RADIOLIB_LORAWAN_FPORT_TS011)) { + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { encKey = this->nwkSEncKey; } + // check if any of the packages uses this FPort + for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { + if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + encKey = this->packages[id].isAppPack ? this->appSKey : this->nwkSEncKey; + break; + } + } // encrypt the frame payload processAES(in, lenIn, encKey, &out[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(this->fOptsUpLen)], this->devAddr, this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x00, true); @@ -1496,7 +1492,7 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne // get the maximum allowed Time-on-Air of a packet given the current datarate uint8_t maxPayLen = this->band->payloadLenMax[dlChannel->dr]; - if(this->TS011) { + if(this->packages[RADIOLIB_LORAWAN_PACKAGE_TS011].enabled) { maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater } RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13) / 1000; // mandatory FHDR is 12/13 bytes @@ -1669,7 +1665,7 @@ int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { // the specified maximum length M over the data rate used to receive the frame // SHALL be silently discarded. uint8_t maxPayLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_RX_BC].dr]; - if(this->TS011) { + if(this->packages[RADIOLIB_LORAWAN_PACKAGE_TS011].enabled) { maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater } if(this->phyLayer->getPacketLength() > (size_t)(maxPayLen + 13)) { // mandatory FHDR is 12/13 bytes @@ -1779,12 +1775,12 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } - // calculate length of piggy-backed FOpts - uint8_t fOptsPbLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + // calculate length of (piggy-backed) FOpts + uint8_t fOptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; - // MHDR(1) - DevAddr(4) - FCtrl(1) - FCnt(2) - FOptsPb - Payload - MIC(4) + // MHDR(1) - DevAddr(4) - FCtrl(1) - FCnt(2) - FOpts - Payload - MIC(4) // potentially also an FPort, will find out next - uint8_t payLen = downlinkMsgLen - 1 - 4 - 1 - 2 - fOptsPbLen - 4; + uint8_t payLen = downlinkMsgLen - 1 - 4 - 1 - 2 - fOptsLen - 4; // in LoRaWAN v1.1, a frame is a Network frame if there is no Application payload // i.e.: either no payload at all (empty frame or FOpts only), or MAC only payload @@ -1795,74 +1791,62 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } if(payLen > 0) { payLen -= 1; // subtract one as fPort is set - fPort = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsPbLen)]; - - // check if fPort value is actually allowed - switch(fPort) { - case RADIOLIB_LORAWAN_FPORT_MAC_COMMAND: { - // payload consists of all MAC commands (or is empty) - - // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. - // (...) it SHALL silently discard the entire frame. - // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). - if(window == RADIOLIB_LORAWAN_RX_BC) { - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_DOWNLINK_MALFORMED); - } - } break; - case RADIOLIB_LORAWAN_FPORT_TS009: { - // TS009 FPort only good if overruled during verification testing - if(!this->TS009) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is not enabled.", fPort); - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_INVALID_PORT); - } - isAppDownlink = true; - } break; - case RADIOLIB_LORAWAN_FPORT_TS011: { - // TS011 FPort only good if overruled during relay exchange - if(!this->TS011) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is not enabled.", fPort); - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_INVALID_PORT); - } - isAppDownlink = true; - } break; - default: { - if((fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN) && (fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX)) { - // payload is user-defined (or empty) - may carry piggybacked MAC commands - isAppDownlink = true; + fPort = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(fOptsLen)]; + + // check destination fPort + bool ok = false; + + // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. + // (...) it SHALL silently discard the entire frame. + // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && window < RADIOLIB_LORAWAN_RX_BC) { + // payload consists of all MAC commands (or is empty) + ok = true; + } + if(fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN && fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX) { + ok = true; + isAppDownlink = true; + } + // check if any of the packages uses this FPort + if(fPort >= RADIOLIB_LORAWAN_FPORT_RESERVED) { + for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { + if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + ok = true; + isAppDownlink = this->packages[id].isAppPack; break; } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink at FPort %d - rejected! This FPort is reserved.", fPort); - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_INVALID_PORT); - } break; + } } + if(!ok) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Received downlink at FPort %d - rejected! This FPort is reserved.", fPort); + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_INVALID_PORT); + } } - // MAC commands SHALL NOT be present in the payload field and the frame options field simultaneously. - // Should this occur, the end-device SHALL silently discard the frame. - if(fOptsPbLen > 0 && payLen > 0 && fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - #if !RADIOLIB_STATIC_ONLY - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + // handle FOpts in uplink with FPort = 0 (or absent which means 0) + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if(fOptsLen > 0 && payLen > 0) { + // MAC commands SHALL NOT be present in the payload field and the frame options field simultaneously. + // Should this occur, the end-device SHALL silently discard the frame. + #if !RADIOLIB_STATIC_ONLY + delete[] downlinkMsg; + #endif + return(RADIOLIB_ERR_DOWNLINK_MALFORMED); + } + // if FOpts are in the payload, use this instead + if(payLen > 0) { + fOptsLen = payLen; + } } // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. // (...) it SHALL silently discard the entire frame. // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). - if(fOptsPbLen > 0 && window == RADIOLIB_LORAWAN_RX_BC) { + if(fOptsLen > 0 && window == RADIOLIB_LORAWAN_RX_BC) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -1886,17 +1870,11 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } } - // if the downlink FCnt16 value is 'slightly' lower than expected by the device, assume a replay attack - uint16_t devFCnt16 = (uint16_t)devFCnt32; - if(devFCnt16 > 0 && (uint16_t)(devFCnt16 - payFCnt16) < RADIOLIB_LORAWAN_MIN_ROLLOVER_FCNT_GAP) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rejected: %d -> %d", devFCnt16, payFCnt16); - return(RADIOLIB_ERR_DOWNLINK_FCNT_INVALID); - } - - // assume a rollover if the FCnt16 in the payload is smaller than the previous FCnt16 known by device + // assume a rollover if the FCnt16 in the payload is equal to / smaller + // than the previous FCnt16 known by device // (MAX_FCNT_GAP is deprecated for 1.0.4 / 1.1, TTS and CS both apply a 16-bit rollover) - if(payFCnt16 < devFCnt16) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rollover: %d -> %d", devFCnt16, payFCnt16); + if(devFCnt32 > 0 && payFCnt16 <= (uint16_t)devFCnt32) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FCnt rollover: %d -> %d", (uint16_t)devFCnt32, payFCnt16); devFCnt32 += 0x10000; // add 16-bit value } devFCnt32 &= ~0xFFFF; // clear lower 16 bits known by device @@ -1928,7 +1906,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DIR_POS] = RADIOLIB_LORAWAN_DOWNLINK; LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_DEV_ADDR_POS], addr); - LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], devFCnt32); + LoRaWANNode::hton(&downlinkMsg[RADIOLIB_LORAWAN_BLOCK_FCNT_POS], devFCnt32); downlinkMsg[RADIOLIB_LORAWAN_MIC_BLOCK_LEN_POS] = downlinkMsgLen - sizeof(uint32_t); // check the MIC @@ -1943,8 +1921,15 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L #endif return(RADIOLIB_ERR_MIC_MISMATCH); } - - // save current FCnt to respective frame counter + + // all checks passed, so dump its contents and start processing + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) encoded:", + (this->multicast && window == RADIOLIB_LORAWAN_RX_BC) ? "M" : + (isAppDownlink ? "A" : "N"), + (unsigned long)devFCnt32); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + + // save new FCnt to respective frame counter if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { // multicast: McApp downlink this->mcAFCnt = devFCnt32; @@ -1957,26 +1942,24 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) encoded:", - (this->multicast && window == RADIOLIB_LORAWAN_RX_BC) ? "M" : - (isAppDownlink ? "A" : "N"), - (unsigned long)devFCnt32); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); - - // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) bool isConfirmedDown = false; - if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { - this->confFCntDown = this->aFCntDown; - isConfirmedDown = true; - } - - // if this downlink is on FPort 0, the FOptsLen is the length of the payload - // in any other case, the payload (length) is user accessible - uint8_t fOptsLen = fOptsPbLen; - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && payLen > 0) { - fOptsLen = payLen; - } else { - *len = payLen; + + // do some housekeeping for normal Class A downlinks (not allowed for Class B/C) + if(window < RADIOLIB_LORAWAN_RX_BC) { + // if this is a confirmed frame, save the downlink number (only app frames can be confirmed) + if((downlinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS] & 0xFE) == RADIOLIB_LORAWAN_MHDR_MTYPE_CONF_DATA_DOWN) { + this->confFCntDown = this->aFCntDown; + isConfirmedDown = true; + } + + // a Class A downlink was received, so restart the ADR counter with the next uplink + this->adrFCnt = this->getFCntUp() + 1; + + // a Class A downlink was received, so we can clear the MAC uplink and downlink buffers + memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + this->fOptsUpLen = 0; + memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + this->fOptsDownLen = 0; } #if !RADIOLIB_STATIC_ONLY @@ -1985,183 +1968,174 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; #endif - // figure out if the payload should end up in user data or internal FOpts buffer - uint8_t* dest; - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - dest = fOpts; - } else { - dest = data; - } - - // figure out which key to use to decrypt the payload - uint8_t* encKey = this->appSKey; - if((fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) || (fPort == RADIOLIB_LORAWAN_FPORT_TS011)) { - encKey = this->nwkSEncKey; - } - if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { - encKey = this->mcAppSKey; - } - - // decrypt the frame payload - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsPbLen)], payLen, encKey, dest, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + // decrypt any FOpts on FPort = 0, in which case FOptsLen is the length of the payload + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && payLen > 0) { + payLen = 0; + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], fOptsLen, this->nwkSEncKey, fOpts, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); - // pass the event info if requested - if(event) { - event->dir = RADIOLIB_LORAWAN_DOWNLINK; - event->confirmed = isConfirmedDown; - event->confirming = isConfirmingUp; - event->frmPending = (downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING) != 0; - event->datarate = this->channels[window].dr; - event->freq = this->channels[window].freq / 10000.0; - event->power = this->txPowerMax - this->txPowerSteps * 2; - event->fCnt = devFCnt32; - event->fPort = fPort; - event->multicast = (bool)this->multicast; - } - - // for RxBC downlinks, return already, we aren't allowed to do any FOpts stuff - if(window == RADIOLIB_LORAWAN_RX_BC) { - #if !RADIOLIB_STATIC_ONLY - delete[] fOpts; - delete[] downlinkMsg; - #endif - return(RADIOLIB_ERR_NONE); - } - - // a downlink was received, so restart the ADR counter with the next uplink - this->adrFCnt = this->getFCntUp() + 1; - // decrypt any piggy-backed FOpts - if(fOptsPbLen > 0) { + } else if(fOptsLen > 0) { // the decryption depends on the LoRaWAN version if(this->rev == 1) { // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen, this->nwkSEncKey, fOpts, this->devAddr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, this->devAddr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); } else { // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted - memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsPbLen); + memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen); } } - // clear the previous MAC commands, if any - memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); - - // process FOpts (if there are any) - uint8_t cid; - uint8_t fLen = 1; - uint8_t* mPtr = fOpts; - uint8_t procLen = 0; - uint8_t fOptsRe[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE] = { 0 }; - uint8_t fOptsReLen = 0; + // process any FOpts + if(fOptsLen > 0) { + uint8_t* mPtr = fOpts; + uint8_t procLen = 0; + uint8_t fOptsRe[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE] = { 0 }; + uint8_t fOptsReLen = 0; + + // indication whether LinkAdr MAC command has been processed + bool mAdr = false; + + while(procLen < fOptsLen) { + uint8_t cid = *mPtr; // MAC id is the first byte + + // fetch length of MAC downlink command and uplink response + uint8_t fLen = 1; + uint8_t fLenRe = 1; + state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true, mPtr + 1); + if(state != RADIOLIB_ERR_NONE) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Unknown MAC CID %02x", cid); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + fOptsLen = procLen; // truncate to last processed MAC command + break; + } + (void)this->getMacLen(cid, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true); - // indication whether LinkAdr MAC command has been processed - bool mAdr = false; + // check whether the complete payload is present + if(procLen + fLen > fOptsLen) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen - procLen, fLen); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + fOptsLen = procLen; // truncate to last processed MAC command + break; + } - while(procLen < fOptsLen) { - cid = *mPtr; // MAC id is the first byte + bool reply = false; - // fetch length of MAC downlink payload - state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true, mPtr + 1); - if(state != RADIOLIB_ERR_NONE) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Unknown MAC CID %02x", cid); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); - fOptsLen = procLen; // truncate to last processed MAC command - break; - } + // if this is a LinkAdr MAC command, pre-process contiguous commands into one atomic block + if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + // if there was any LinkAdr command before, set NACK and continue without processing + if(mAdr) { + reply = true; + fOptsRe[fOptsReLen + 1] = 0x00; - // already fetch length of MAC answer payload (if any), include CID - uint8_t fLenRe = 0; - (void)this->getMacLen(cid, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true); - // don't care about return value: the previous getMacLen() would have failed anyway + // if this is the first LinkAdr command, do some special treatment: + } else { + mAdr = true; + uint8_t fAdrLen = 5; + uint8_t mAdrOpt[14] = { 0 }; + + // retrieve all contiguous LinkAdr commands + while(procLen + fLen + fAdrLen < fOptsLen + 1 && *(mPtr + fLen) == RADIOLIB_LORAWAN_MAC_LINK_ADR) { + fLen += 5; // ADR command is 5 bytes + fLenRe += 2; // ADR response is 2 bytes + } - if(procLen + fLen > fOptsLen) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen - procLen, fLen); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); - fOptsLen = procLen; // truncate to last processed MAC command - break; - } + // pre-process them into a single complete channel mask (stored in mAdrOpt) + LoRaWANNode::preprocessMacLinkAdr(mPtr, fLen, mAdrOpt); - bool reply = false; + // execute like a normal MAC command (but pointing to mAdrOpt instead) + reply = this->execMacCommand(cid, mAdrOpt, 14, &fOptsRe[fOptsReLen + 1]); - // if this is a LinkAdr MAC command, pre-process contiguous commands into one atomic block - if(cid == RADIOLIB_LORAWAN_MAC_LINK_ADR) { - // if there was any LinkAdr command before, set NACK and continue without processing - if(mAdr) { - reply = true; - fOptsRe[fOptsReLen + 1] = 0x00; + // in LoRaWAN v1.0.x, all ACK bytes should have equal status - fix in post-processing + if(this->rev == 0) { + LoRaWANNode::postprocessMacLinkAdr(&fOptsRe[fOptsReLen], fLen); - // if this is the first LinkAdr command, do some special treatment: - } else { - mAdr = true; - uint8_t fAdrLen = 5; - uint8_t mAdrOpt[14] = { 0 }; - - // retrieve all contiguous LinkAdr commands - while(procLen + fLen + fAdrLen < fOptsLen + 1 && *(mPtr + fLen) == RADIOLIB_LORAWAN_MAC_LINK_ADR) { - fLen += 5; // ADR command is 5 bytes - fLenRe += 2; // ADR response is 2 bytes + // in LoRaWAN v1.1, just provide one ACK, so no post-processing but cut off reply length + } else { + fLenRe = 2; + } } - // pre-process them into a single complete channel mask (stored in mAdrOpt) - LoRaWANNode::preprocessMacLinkAdr(mPtr, fLen, mAdrOpt); - - // execute like a normal MAC command (but pointing to mAdrOpt instead) - reply = this->execMacCommand(cid, mAdrOpt, 14, &fOptsRe[fOptsReLen + 1]); - - // in LoRaWAN v1.0.x, all ACK bytes should have equal status - fix in post-processing - if(this->rev == 0) { - LoRaWANNode::postprocessMacLinkAdr(&fOptsRe[fOptsReLen], fLen); - - // in LoRaWAN v1.1, just provide one ACK, so no post-processing but cut off reply length - } else { - fLenRe = 2; - } + // MAC command other than LinkAdr, just process the payload + } else { + reply = this->execMacCommand(cid, mPtr + 1, fLen - 1, &fOptsRe[fOptsReLen + 1]); } - // MAC command other than LinkAdr, just process the payload - } else { - reply = this->execMacCommand(cid, mPtr + 1, fLen - 1, &fOptsRe[fOptsReLen + 1]); - } + // if there is a reply, only add it to the reply if maximum payload size allows + if(reply && (fOptsReLen + fLenRe <= this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr])) { + fOptsRe[fOptsReLen] = cid; + fOptsReLen += fLenRe; + } - // if there is a reply, only add it to the reply if maximum payload size allows - if(reply && (fOptsReLen + fLenRe <= this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr])) { - fOptsRe[fOptsReLen] = cid; - fOptsReLen += fLenRe; + procLen += fLen; + mPtr += fLen; } - procLen += fLen; - mPtr += fLen; - } - - // remove all MAC commands except those whose payload can be requested by the user - // (which are LinkCheck and DeviceTime) - if(fOptsLen > 0) { + // remove all MAC commands except those whose payload can be requested by the user + // (which are LinkCheck and DeviceTime) LoRaWANNode::clearMacCommands(fOpts, &fOptsLen, RADIOLIB_LORAWAN_DOWNLINK); memcpy(this->fOptsDown, fOpts, fOptsLen); - } - this->fOptsDownLen = fOptsLen; - - // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink - if(fOptsReLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + this->fOptsDownLen = fOptsLen; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC-only payload (%d bytes):", fOptsReLen); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsRe, fOptsReLen); + // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink + if(fOptsReLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { - this->isMACPayload = true; - // temporarily lift dutyCycle restrictions to allow immediate MAC response - bool prevDC = this->dutyCycleEnabled; - this->dutyCycleEnabled = false; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("! Sending MAC-only uplink (%d bytes):", fOptsReLen); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsRe, fOptsReLen); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Sending MAC-only uplink .. "); + this->isMACPayload = true; - this->sendReceive(fOptsRe, fOptsReLen, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + // temporarily lift dutyCycle restrictions to allow immediate MAC response + bool prevDC = this->dutyCycleEnabled; + this->dutyCycleEnabled = false; + this->sendReceive(fOptsRe, fOptsReLen, RADIOLIB_LORAWAN_FPORT_MAC_COMMAND); + this->dutyCycleEnabled = prevDC; - this->dutyCycleEnabled = prevDC; + } else { // fOptsReLen <= 15 + memcpy(this->fOptsUp, fOptsRe, fOptsReLen); + this->fOptsUpLen = fOptsReLen; + } + } - } else { // fOptsReLen <= 15 - memcpy(this->fOptsUp, fOptsRe, fOptsReLen); - this->fOptsUpLen = fOptsReLen; + // figure out which key to use to decrypt the payload + uint8_t* encKey = this->appSKey; + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + encKey = this->mcAppSKey; + } + for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { + if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + encKey = this->packages[id].isAppPack ? this->appSKey : this->nwkSEncKey; + break; + } + } + + // decrypt the frame payload + // by default, the data and length are user-accessible + processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], payLen, encKey, data, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + *len = payLen; + + // however, if this frame belongs to a package, redirect instead and 'hide' contents from the user + // just to be sure that it doesn't get re-interpreted... + for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { + if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + this->packages[id].callback(data, *len); + memset(data, 0, *len); + *len = 0; + } + } + + // pass the event info if requested + if(event) { + event->dir = RADIOLIB_LORAWAN_DOWNLINK; + event->confirmed = isConfirmedDown; + event->confirming = isConfirmingUp; + event->frmPending = (downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FCTRL_FRAME_PENDING) != 0; + event->datarate = this->channels[window].dr; + event->freq = this->channels[window].freq / 10000.0; + event->power = this->txPowerMax - this->txPowerSteps * 2; + event->fCnt = devFCnt32; + event->fPort = fPort; + event->multicast = (bool)this->multicast; } #if !RADIOLIB_STATIC_ONLY @@ -3101,6 +3075,7 @@ void LoRaWANNode::setDutyCycle(bool enable, RadioLibTime_t msPerHour) { this->dutyCycleEnabled = enable; if(!enable) { this->dutyCycle = 0; + return; } if(msPerHour == 0) { this->dutyCycle = this->band->dutyCycle; @@ -3662,7 +3637,7 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { uint8_t minLen = 0; uint8_t maxLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; - if(this->TS011) { + if(this->packages[RADIOLIB_LORAWAN_PACKAGE_TS011].enabled) { maxLen = RADIOLIB_MIN(maxLen, 222); // payload length is limited to N=222 if under repeater } maxLen += 13; // mandatory FHDR is 12/13 bytes @@ -3697,6 +3672,58 @@ void LoRaWANNode::setSleepFunction(SleepCb_t cb) { this->sleepCb = cb; } +int16_t LoRaWANNode::addAppPackage(uint8_t packageId, PackageCb_t callback) { + if(packageId >= RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES) { + return(RADIOLIB_ERR_INVALID_MODE); + } + return(this->addAppPackage(packageId, callback, PackageTable[packageId].packFPort)); +} + +int16_t LoRaWANNode::addAppPackage(uint8_t packageId, PackageCb_t callback, uint8_t fPort) { + if(packageId >= RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES) { + return(RADIOLIB_ERR_INVALID_MODE); + } + if(PackageTable[packageId].isAppPack == false) { + return(RADIOLIB_ERR_INVALID_MODE); + } + if(PackageTable[packageId].fixedFPort && fPort != PackageTable[packageId].packFPort) { + return(RADIOLIB_ERR_INVALID_PORT); + } + if(callback == NULL) { + return(RADIOLIB_ERR_NULL_POINTER); + } + this->packages[packageId] = PackageTable[packageId]; + this->packages[packageId].packFPort = fPort; + this->packages[packageId].callback = callback; + this->packages[packageId].enabled = true; + return(RADIOLIB_ERR_NONE); +} + +int16_t LoRaWANNode::addNwkPackage(uint8_t packageId, PackageCb_t callback) { + if(packageId >= RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES) { + return(RADIOLIB_ERR_INVALID_MODE); + } + if(PackageTable[packageId].isAppPack == true) { + return(RADIOLIB_ERR_INVALID_MODE); + } + if(callback == NULL) { + return(RADIOLIB_ERR_NULL_POINTER); + } + this->packages[packageId] = PackageTable[packageId]; + this->packages[packageId].callback = callback; + this->packages[packageId].enabled = true; + return(RADIOLIB_ERR_NONE); +} + +void LoRaWANNode::removePackage(uint8_t packageId) { + // silently ignore, assume that the user supplies decent index + if(packageId >= RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES) { + return; + } + this->packages[packageId].enabled = false; + return; +} + int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t state = RADIOLIB_ERR_NONE; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 98ea9d7d79..d9d9e30ced 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -44,8 +44,6 @@ #define RADIOLIB_LORAWAN_FPORT_MAC_COMMAND (0x00 << 0) // 7 0 payload contains MAC commands only #define RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN (0x01 << 0) // 7 0 start of user-allowed fPort range #define RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX (0xDF << 0) // 7 0 end of user-allowed fPort range -#define RADIOLIB_LORAWAN_FPORT_TS009 (0xE0 << 0) // 7 0 fPort used for TS009 testing -#define RADIOLIB_LORAWAN_FPORT_TS011 (0xE2 << 0) // 7 0 fPort used for TS011 Forwarding #define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 fPort values equal to and larger than this are reserved // data rate encoding @@ -97,9 +95,6 @@ #define RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N (10) // send rejoin request 16384 uplinks #define RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N (15) // once every year, not actually implemented -// developer recommended default setting (not specified) -#define RADIOLIB_LORAWAN_MIN_ROLLOVER_FCNT_GAP (16384) // equal to deprecated MaxFCntGap - // join request message layout #define RADIOLIB_LORAWAN_JOIN_REQUEST_LEN (23) #define RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS (1) @@ -202,6 +197,27 @@ #define RADIOLIB_LORAWAN_MAC_DEVICE_MODE (0x20) #define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) +// number of supported LoRaWAN TS packages +#define RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES (7) + +// Package ID numbering as per TS008 (TS011 ID is made up) +#define RADIOLIB_LORAWAN_PACKAGE_TS007 (0) +#define RADIOLIB_LORAWAN_PACKAGE_TS003 (1) +#define RADIOLIB_LORAWAN_PACKAGE_TS005 (2) +#define RADIOLIB_LORAWAN_PACKAGE_TS004 (3) +#define RADIOLIB_LORAWAN_PACKAGE_TS006 (4) +#define RADIOLIB_LORAWAN_PACKAGE_TS009 (5) +#define RADIOLIB_LORAWAN_PACKAGE_TS011 (6) + +// Package FPort (specified or recommended) +#define RADIOLIB_LORAWAN_FPORT_TS007 (225) +#define RADIOLIB_LORAWAN_FPORT_TS003 (202) +#define RADIOLIB_LORAWAN_FPORT_TS005 (200) +#define RADIOLIB_LORAWAN_FPORT_TS004 (201) +#define RADIOLIB_LORAWAN_FPORT_TS006 (203) +#define RADIOLIB_LORAWAN_FPORT_TS009 (224) +#define RADIOLIB_LORAWAN_FPORT_TS011 (226) + // the length of internal MAC command queue - hopefully this is enough for most use cases #define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) @@ -261,6 +277,45 @@ constexpr LoRaWANMacCommand_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS] = { { RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, false, true }, }; +/*! \brief A user-supplied callback for LoRaWAN Application Packages (TSxxx) */ +typedef void (*PackageCb_t)(uint8_t* dataDown, size_t lenDown); + +/*! + \struct LoRaWANPackage_t + \brief LoRaWAN Packages structure (for TSxxx documents). +*/ +struct LoRaWANPackage_t { + /*! \brief Package ID as per TS008 */ + uint8_t packId; + + /*! \brief Package default FPort (specified or recommended) */ + uint8_t packFPort; + + /*! \brief Whether the package runs through the Application layer */ + bool isAppPack; + + /*! \brief Whether the FPort value is fixed or may be modified */ + bool fixedFPort; + + /*! \brief Whether the package is currently in use */ + bool enabled; + + /*! \brief User-provided callback for handling package downlinks */ + PackageCb_t callback; +}; + +constexpr LoRaWANPackage_t PackageTable[RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES] = { + { RADIOLIB_LORAWAN_PACKAGE_TS007, RADIOLIB_LORAWAN_FPORT_TS007, true, false, false }, + { RADIOLIB_LORAWAN_PACKAGE_TS003, RADIOLIB_LORAWAN_FPORT_TS003, true, true, false }, + { RADIOLIB_LORAWAN_PACKAGE_TS005, RADIOLIB_LORAWAN_FPORT_TS005, true, true, false }, + { RADIOLIB_LORAWAN_PACKAGE_TS004, RADIOLIB_LORAWAN_FPORT_TS004, true, true, false }, + { RADIOLIB_LORAWAN_PACKAGE_TS006, RADIOLIB_LORAWAN_FPORT_TS006, true, true, false }, + { RADIOLIB_LORAWAN_PACKAGE_TS009, RADIOLIB_LORAWAN_FPORT_TS009, true, false, false }, + { RADIOLIB_LORAWAN_PACKAGE_TS011, RADIOLIB_LORAWAN_FPORT_TS011, false, false, false } +}; + +#define RADIOLIB_LORAWAN_PACKAGE_NONE { .packId = 0, .packFPort = 0, .isAppPack = false, .fixedFPort = false, .enabled = false, .callback = NULL } + #define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) enum LoRaWANSchemeBase_t { @@ -886,11 +941,37 @@ class LoRaWANNode { */ void setSleepFunction(SleepCb_t cb); - /*! - \brief TS009 Protocol Specification Verification switch - (allows FPort 224 and cuts off uplink payload instead of rejecting if maximum length exceeded). + /*! + \brief Add a LoRaWAN Application Package as defined in one of the TSxxx documents. + Any downlinks that occur on the corresponding FPort will be redirected to + a supplied callback that implements this package. These downlink contents will be + hidden from the user as the downlink buffer will be empty and the length zero. + The package may need to overrule the behaviour of your device - refer to the examples. + Advanced users only! + \param packageId The ID of the package (one of RADIOLIB_LORAWAN_PACKAGE_TSxxx). + \param callback The downlink handler for this package of type (uint8_t* dataDown, size_t lenDown). + \returns \ref status_codes + */ + int16_t addAppPackage(uint8_t packageId, PackageCb_t callback); + + /*! + \brief Add a LoRaWAN Application Package as defined in one of the TSxxx documents. + Any downlinks that occur on the corresponding FPort will be redirected to + a supplied callback that implements this package. These downlink contents will be + hidden from the user as the downlink buffer will be empty and the length zero. + The package may need to overrule the behaviour of your device - refer to the examples. + Advanced users only! + \param packageId The ID of the package (one of RADIOLIB_LORAWAN_PACKAGE_TSxxx). + \param callback The downlink handler for this package of type (uint8_t* dataDown, size_t lenDown). + \param fPort A custom FPort for packages that have a default FPort < 224. + \returns \ref status_codes + */ + int16_t addAppPackage(uint8_t packageId, PackageCb_t callback, uint8_t fPort); + + /*! + \brief Disable a package that was previously added. */ - bool TS009 = false; + void removePackage(uint8_t packageId); /*! \brief Rx window padding in milliseconds @@ -983,6 +1064,9 @@ class LoRaWANNode { uint32_t mcAFCnt = 0; uint32_t mcAFCntMax = 0; + // enabled TS packages + LoRaWANPackage_t packages[RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES]; + // enable/disable CSMA for LoRaWAN bool csmaEnabled = false; @@ -1032,9 +1116,7 @@ class LoRaWANNode { // save the selected sub-band in case this must be restored in ADR control uint8_t subBand = 0; - // allow port 226 for devices implementing TS011 - bool TS011 = false; - + // user-provided sleep callback SleepCb_t sleepCb = nullptr; // this will reset the device credentials, so the device starts completely new @@ -1079,6 +1161,10 @@ class LoRaWANNode { // extract downlink payload and process MAC commands int16_t parseDownlink(uint8_t* data, size_t* len, uint8_t window, LoRaWANEvent_t* event = NULL); + // add a LoRaWAN package that runs through the network layer + // (not available to users, they are only allowed to add application packages) + int16_t addNwkPackage(uint8_t packageId, PackageCb_t callback); + // execute mac command, return the number of processed bytes for sequential processing bool execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn); bool execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uint8_t* optOut); From bfa440aa1cfc548f2d628b45842b2240b150eca5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 21 Jun 2025 16:49:26 +0200 Subject: [PATCH 1562/1848] [LoRaWAN] Add missing callback initializer --- src/protocols/LoRaWAN/LoRaWAN.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index d9d9e30ced..9fb7764a1c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -305,13 +305,13 @@ struct LoRaWANPackage_t { }; constexpr LoRaWANPackage_t PackageTable[RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES] = { - { RADIOLIB_LORAWAN_PACKAGE_TS007, RADIOLIB_LORAWAN_FPORT_TS007, true, false, false }, - { RADIOLIB_LORAWAN_PACKAGE_TS003, RADIOLIB_LORAWAN_FPORT_TS003, true, true, false }, - { RADIOLIB_LORAWAN_PACKAGE_TS005, RADIOLIB_LORAWAN_FPORT_TS005, true, true, false }, - { RADIOLIB_LORAWAN_PACKAGE_TS004, RADIOLIB_LORAWAN_FPORT_TS004, true, true, false }, - { RADIOLIB_LORAWAN_PACKAGE_TS006, RADIOLIB_LORAWAN_FPORT_TS006, true, true, false }, - { RADIOLIB_LORAWAN_PACKAGE_TS009, RADIOLIB_LORAWAN_FPORT_TS009, true, false, false }, - { RADIOLIB_LORAWAN_PACKAGE_TS011, RADIOLIB_LORAWAN_FPORT_TS011, false, false, false } + { RADIOLIB_LORAWAN_PACKAGE_TS007, RADIOLIB_LORAWAN_FPORT_TS007, true, false, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS003, RADIOLIB_LORAWAN_FPORT_TS003, true, true, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS005, RADIOLIB_LORAWAN_FPORT_TS005, true, true, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS004, RADIOLIB_LORAWAN_FPORT_TS004, true, true, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS006, RADIOLIB_LORAWAN_FPORT_TS006, true, true, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS009, RADIOLIB_LORAWAN_FPORT_TS009, true, false, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS011, RADIOLIB_LORAWAN_FPORT_TS011, false, false, false, NULL } }; #define RADIOLIB_LORAWAN_PACKAGE_NONE { .packId = 0, .packFPort = 0, .isAppPack = false, .fixedFPort = false, .enabled = false, .callback = NULL } From 48a863d8010ec1d42c67d4f699286c0c5c4af5fd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 21 Jun 2025 17:46:41 +0200 Subject: [PATCH 1563/1848] Bump version to 7.2.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index e5199c4cb1..4c41c600cb 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.1.2" +version: "7.2.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 6182a0cfbc..821d3ee17e 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.1.2", + "version": "7.2.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index f4a95869ad..c5faa3dda6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.1.2 +version=7.2.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 6d6a6a67d2..66d24b1d03 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -604,8 +604,8 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 -#define RADIOLIB_VERSION_MINOR 1 -#define RADIOLIB_VERSION_PATCH 2 +#define RADIOLIB_VERSION_MINOR 2 +#define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From a3a4b15791d380dfa7c21c1fe2450e4693a076ef Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sat, 21 Jun 2025 21:00:22 +0200 Subject: [PATCH 1564/1848] [LoRaWAN] Bump nonces buffer version --- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 9fb7764a1c..93bd9a8742 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -316,7 +316,7 @@ constexpr LoRaWANPackage_t PackageTable[RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES] #define RADIOLIB_LORAWAN_PACKAGE_NONE { .packId = 0, .packFPort = 0, .isAppPack = false, .fixedFPort = false, .enabled = false, .callback = NULL } -#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001) +#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0002) enum LoRaWANSchemeBase_t { RADIOLIB_LORAWAN_NONCES_START = 0x00, From ed67ef372aa4171c2299d134fbcde0091911b11a Mon Sep 17 00:00:00 2001 From: Darian Leung <32921628+Dazza0@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:49:59 +0800 Subject: [PATCH 1565/1848] refactor: Use sdkconfig.defaults for ESP-IDF example ESP-IDF allows projects to specify a sdkconfig.defaults values which contain preset values for configuration options of relevance to the project. This allows ESP-IDF to use those presets while supplying default values for all other configuration options, when generting the final sdkconfig file. Changes: - Ran `idf.py save-defconfig` to find non-default value configs. Saved relevant ones to `sdkconfig.defaults` - Removed `sdkconfig` file - Added `sdkconfig` to `.gitignore` as ESP-IDF will generate a `sdkconfig` based on `sdkconfig.defaults` when building. --- examples/NonArduino/ESP-IDF/.gitignore | 1 + examples/NonArduino/ESP-IDF/README.md | 1 + examples/NonArduino/ESP-IDF/sdkconfig | 1669 ----------------- .../NonArduino/ESP-IDF/sdkconfig.defaults | 2 + 4 files changed, 4 insertions(+), 1669 deletions(-) delete mode 100644 examples/NonArduino/ESP-IDF/sdkconfig create mode 100644 examples/NonArduino/ESP-IDF/sdkconfig.defaults diff --git a/examples/NonArduino/ESP-IDF/.gitignore b/examples/NonArduino/ESP-IDF/.gitignore index f9b3ce2818..a6007c83eb 100644 --- a/examples/NonArduino/ESP-IDF/.gitignore +++ b/examples/NonArduino/ESP-IDF/.gitignore @@ -1,3 +1,4 @@ # generated by ESP-IDF managed_components/ dependencies.lock +sdkconfig diff --git a/examples/NonArduino/ESP-IDF/README.md b/examples/NonArduino/ESP-IDF/README.md index 401785eaa5..df1d0b728b 100644 --- a/examples/NonArduino/ESP-IDF/README.md +++ b/examples/NonArduino/ESP-IDF/README.md @@ -8,3 +8,4 @@ This example shows how to use RadioLib as ESP-IDF component, without the Arduino * `main/EspHal.h` - RadioLib HAL example implementation * `main/idf_component.yml` - declaration of the RadioLib dependency for this example * `main/main.cpp` - the example source code +* `sdkconfig.defaults` - List of preset configuration option values for ESP-IDF. All other options use default values provided by ESP-IDF. diff --git a/examples/NonArduino/ESP-IDF/sdkconfig b/examples/NonArduino/ESP-IDF/sdkconfig deleted file mode 100644 index ea8d75690c..0000000000 --- a/examples/NonArduino/ESP-IDF/sdkconfig +++ /dev/null @@ -1,1669 +0,0 @@ -# -# Automatically generated file. DO NOT EDIT. -# Espressif IoT Development Framework (ESP-IDF) Project Configuration -# -CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" -CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" -CONFIG_SOC_DPORT_WORKAROUND="Not determined" -CONFIG_SOC_CAPS_ECO_VER_MAX=301 -CONFIG_SOC_ADC_SUPPORTED=y -CONFIG_SOC_DAC_SUPPORTED=y -CONFIG_SOC_MCPWM_SUPPORTED=y -CONFIG_SOC_SDMMC_HOST_SUPPORTED=y -CONFIG_SOC_BT_SUPPORTED=y -CONFIG_SOC_PCNT_SUPPORTED=y -CONFIG_SOC_WIFI_SUPPORTED=y -CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y -CONFIG_SOC_TWAI_SUPPORTED=y -CONFIG_SOC_EMAC_SUPPORTED=y -CONFIG_SOC_ULP_SUPPORTED=y -CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y -CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y -CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y -CONFIG_SOC_RTC_MEM_SUPPORTED=y -CONFIG_SOC_I2S_SUPPORTED=y -CONFIG_SOC_RMT_SUPPORTED=y -CONFIG_SOC_SDM_SUPPORTED=y -CONFIG_SOC_SUPPORT_COEXISTENCE=y -CONFIG_SOC_AES_SUPPORTED=y -CONFIG_SOC_MPI_SUPPORTED=y -CONFIG_SOC_SHA_SUPPORTED=y -CONFIG_SOC_FLASH_ENC_SUPPORTED=y -CONFIG_SOC_SECURE_BOOT_SUPPORTED=y -CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y -CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5 -CONFIG_SOC_XTAL_SUPPORT_26M=y -CONFIG_SOC_XTAL_SUPPORT_40M=y -CONFIG_SOC_XTAL_SUPPORT_AUTO_DETECT=y -CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y -CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y -CONFIG_SOC_ADC_DMA_SUPPORTED=y -CONFIG_SOC_ADC_PERIPH_NUM=2 -CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10 -CONFIG_SOC_ADC_ATTEN_NUM=4 -CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2 -CONFIG_SOC_ADC_PATT_LEN_MAX=16 -CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=9 -CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 -CONFIG_SOC_ADC_DIGI_RESULT_BYTES=2 -CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 -CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=2 -CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=20 -CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=9 -CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 -CONFIG_SOC_RTC_SLOW_CLOCK_SUPPORT_8MD256=y -CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y -CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=5 -CONFIG_SOC_CPU_CORES_NUM=2 -CONFIG_SOC_CPU_INTR_NUM=32 -CONFIG_SOC_CPU_HAS_FPU=y -CONFIG_SOC_CPU_BREAKPOINTS_NUM=2 -CONFIG_SOC_CPU_WATCHPOINTS_NUM=2 -CONFIG_SOC_CPU_WATCHPOINT_SIZE=64 -CONFIG_SOC_DAC_PERIPH_NUM=2 -CONFIG_SOC_DAC_RESOLUTION=8 -CONFIG_SOC_GPIO_PORT=1 -CONFIG_SOC_GPIO_PIN_COUNT=40 -CONFIG_SOC_GPIO_VALID_GPIO_MASK=0xFFFFFFFFFF -CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA -CONFIG_SOC_I2C_NUM=2 -CONFIG_SOC_I2C_FIFO_LEN=32 -CONFIG_SOC_I2C_SUPPORT_SLAVE=y -CONFIG_SOC_I2C_SUPPORT_APB=y -CONFIG_SOC_CLK_APLL_SUPPORTED=y -CONFIG_SOC_APLL_MULTIPLIER_OUT_MIN_HZ=350000000 -CONFIG_SOC_APLL_MULTIPLIER_OUT_MAX_HZ=500000000 -CONFIG_SOC_APLL_MIN_HZ=5303031 -CONFIG_SOC_APLL_MAX_HZ=125000000 -CONFIG_SOC_I2S_NUM=2 -CONFIG_SOC_I2S_HW_VERSION_1=y -CONFIG_SOC_I2S_SUPPORTS_APLL=y -CONFIG_SOC_I2S_SUPPORTS_PDM=y -CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y -CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y -CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y -CONFIG_SOC_I2S_SUPPORTS_ADC=y -CONFIG_SOC_I2S_SUPPORTS_DAC=y -CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y -CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y -CONFIG_SOC_I2S_LCD_I80_VARIANT=y -CONFIG_SOC_LCD_I80_SUPPORTED=y -CONFIG_SOC_LCD_I80_BUSES=2 -CONFIG_SOC_LCD_I80_BUS_WIDTH=24 -CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y -CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y -CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y -CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y -CONFIG_SOC_LEDC_CHANNEL_NUM=8 -CONFIG_SOC_LEDC_TIMER_BIT_WIDE_NUM=20 -CONFIG_SOC_MCPWM_GROUPS=2 -CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 -CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 -CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 -CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 -CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 -CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 -CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y -CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 -CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 -CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 -CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 -CONFIG_SOC_PCNT_GROUPS=1 -CONFIG_SOC_PCNT_UNITS_PER_GROUP=8 -CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 -CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 -CONFIG_SOC_RMT_GROUPS=1 -CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=8 -CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=8 -CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8 -CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=64 -CONFIG_SOC_RMT_SUPPORT_REF_TICK=y -CONFIG_SOC_RMT_SUPPORT_APB=y -CONFIG_SOC_RMT_CHANNEL_CLK_INDEPENDENT=y -CONFIG_SOC_RTCIO_PIN_COUNT=18 -CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y -CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y -CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y -CONFIG_SOC_SDM_GROUPS=1 -CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8 -CONFIG_SOC_SPI_HD_BOTH_INOUT_SUPPORTED=y -CONFIG_SOC_SPI_AS_CS_SUPPORTED=y -CONFIG_SOC_SPI_PERIPH_NUM=3 -CONFIG_SOC_SPI_DMA_CHAN_NUM=2 -CONFIG_SOC_SPI_MAX_CS_NUM=3 -CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 -CONFIG_SOC_SPI_MAX_PRE_DIVIDER=8192 -CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y -CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y -CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y -CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y -CONFIG_SOC_TIMER_GROUPS=2 -CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2 -CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 -CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 -CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y -CONFIG_SOC_TOUCH_VERSION_1=y -CONFIG_SOC_TOUCH_SENSOR_NUM=10 -CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF -CONFIG_SOC_TWAI_BRP_MIN=2 -CONFIG_SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT=y -CONFIG_SOC_UART_NUM=3 -CONFIG_SOC_UART_SUPPORT_APB_CLK=y -CONFIG_SOC_UART_SUPPORT_REF_TICK=y -CONFIG_SOC_UART_FIFO_LEN=128 -CONFIG_SOC_UART_BITRATE_MAX=5000000 -CONFIG_SOC_SPIRAM_SUPPORTED=y -CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y -CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG=y -CONFIG_SOC_SHA_SUPPORT_SHA1=y -CONFIG_SOC_SHA_SUPPORT_SHA256=y -CONFIG_SOC_SHA_SUPPORT_SHA384=y -CONFIG_SOC_SHA_SUPPORT_SHA512=y -CONFIG_SOC_RSA_MAX_BIT_LEN=4096 -CONFIG_SOC_AES_SUPPORT_AES_128=y -CONFIG_SOC_AES_SUPPORT_AES_192=y -CONFIG_SOC_AES_SUPPORT_AES_256=y -CONFIG_SOC_SECURE_BOOT_V1=y -CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=y -CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 -CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 -CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y -CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y -CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y -CONFIG_SOC_PM_SUPPORT_RTC_FAST_MEM_PD=y -CONFIG_SOC_PM_SUPPORT_RTC_SLOW_MEM_PD=y -CONFIG_SOC_PM_SUPPORT_MODEM_PD=y -CONFIG_SOC_SDMMC_USE_IOMUX=y -CONFIG_SOC_SDMMC_NUM_SLOTS=2 -CONFIG_SOC_WIFI_WAPI_SUPPORT=y -CONFIG_SOC_WIFI_CSI_SUPPORT=y -CONFIG_SOC_WIFI_MESH_SUPPORT=y -CONFIG_SOC_BLE_SUPPORTED=y -CONFIG_SOC_BLE_MESH_SUPPORTED=y -CONFIG_SOC_BT_CLASSIC_SUPPORTED=y -CONFIG_IDF_CMAKE=y -CONFIG_IDF_TARGET_ARCH_XTENSA=y -CONFIG_IDF_TARGET_ARCH="xtensa" -CONFIG_IDF_TARGET="esp32" -CONFIG_IDF_TARGET_ESP32=y -CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 - -# -# Build type -# -CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y -# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set -CONFIG_APP_BUILD_GENERATE_BINARIES=y -CONFIG_APP_BUILD_BOOTLOADER=y -CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y -# CONFIG_APP_REPRODUCIBLE_BUILD is not set -# CONFIG_APP_NO_BLOBS is not set -# CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set -# CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set -# end of Build type - -# -# Bootloader config -# -CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 -CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y -# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set -# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set -# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set -CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y -# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set -CONFIG_BOOTLOADER_LOG_LEVEL=3 -# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set -CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y -# CONFIG_BOOTLOADER_FACTORY_RESET is not set -# CONFIG_BOOTLOADER_APP_TEST is not set -CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y -CONFIG_BOOTLOADER_WDT_ENABLE=y -# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set -CONFIG_BOOTLOADER_WDT_TIME_MS=9000 -# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set -# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set -# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set -# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set -CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 -# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set -CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y -# end of Bootloader config - -# -# Security features -# -CONFIG_SECURE_BOOT_V1_SUPPORTED=y -# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set -# CONFIG_SECURE_BOOT is not set -# CONFIG_SECURE_FLASH_ENC_ENABLED is not set -# end of Security features - -# -# Application manager -# -CONFIG_APP_COMPILE_TIME_DATE=y -# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set -# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set -# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set -CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 -# end of Application manager - -CONFIG_ESP_ROM_HAS_CRC_LE=y -CONFIG_ESP_ROM_HAS_CRC_BE=y -CONFIG_ESP_ROM_HAS_MZ_CRC32=y -CONFIG_ESP_ROM_HAS_JPEG_DECODE=y -CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y - -# -# Serial flasher config -# -# CONFIG_ESPTOOLPY_NO_STUB is not set -# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set -# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set -CONFIG_ESPTOOLPY_FLASHMODE_DIO=y -# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set -CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y -CONFIG_ESPTOOLPY_FLASHMODE="dio" -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="2MB" -# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set -CONFIG_ESPTOOLPY_BEFORE_RESET=y -# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set -CONFIG_ESPTOOLPY_BEFORE="default_reset" -CONFIG_ESPTOOLPY_AFTER_RESET=y -# CONFIG_ESPTOOLPY_AFTER_NORESET is not set -CONFIG_ESPTOOLPY_AFTER="hard_reset" -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 -# end of Serial flasher config - -# -# Partition Table -# -CONFIG_PARTITION_TABLE_SINGLE_APP=y -# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set -# CONFIG_PARTITION_TABLE_TWO_OTA is not set -# CONFIG_PARTITION_TABLE_CUSTOM is not set -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" -CONFIG_PARTITION_TABLE_OFFSET=0x8000 -CONFIG_PARTITION_TABLE_MD5=y -# end of Partition Table - -# -# Compiler options -# -CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y -# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set -# CONFIG_COMPILER_OPTIMIZATION_PERF is not set -# CONFIG_COMPILER_OPTIMIZATION_NONE is not set -CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y -# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set -# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set -CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y -CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 -# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set -CONFIG_COMPILER_HIDE_PATHS_MACROS=y -# CONFIG_COMPILER_CXX_EXCEPTIONS is not set -# CONFIG_COMPILER_CXX_RTTI is not set -CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y -# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set -# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set -# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set -# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set -# CONFIG_COMPILER_DUMP_RTL_FILES is not set -# end of Compiler options - -# -# Component config -# - -# -# Application Level Tracing -# -# CONFIG_APPTRACE_DEST_JTAG is not set -CONFIG_APPTRACE_DEST_NONE=y -# CONFIG_APPTRACE_DEST_UART1 is not set -# CONFIG_APPTRACE_DEST_UART2 is not set -CONFIG_APPTRACE_DEST_UART_NONE=y -CONFIG_APPTRACE_UART_TASK_PRIO=1 -CONFIG_APPTRACE_LOCK_ENABLE=y -# end of Application Level Tracing - -# -# Bluetooth -# -# CONFIG_BT_ENABLED is not set -# end of Bluetooth - -# -# Driver Configurations -# - -# -# Legacy ADC Configuration -# -CONFIG_ADC_DISABLE_DAC=y -# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set - -# -# Legacy ADC Calibration Configuration -# -CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y -CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y -CONFIG_ADC_CAL_LUT_ENABLE=y -# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set -# end of Legacy ADC Calibration Configuration -# end of Legacy ADC Configuration - -# -# SPI Configuration -# -# CONFIG_SPI_MASTER_IN_IRAM is not set -CONFIG_SPI_MASTER_ISR_IN_IRAM=y -# CONFIG_SPI_SLAVE_IN_IRAM is not set -CONFIG_SPI_SLAVE_ISR_IN_IRAM=y -# end of SPI Configuration - -# -# TWAI Configuration -# -# CONFIG_TWAI_ISR_IN_IRAM is not set -CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y -CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y -CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y -CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y -CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y -# end of TWAI Configuration - -# -# UART Configuration -# -# CONFIG_UART_ISR_IN_IRAM is not set -# end of UART Configuration - -# -# GPIO Configuration -# -# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set -# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set -# end of GPIO Configuration - -# -# Sigma Delta Modulator Configuration -# -# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set -# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set -# CONFIG_SDM_ENABLE_DEBUG_LOG is not set -# end of Sigma Delta Modulator Configuration - -# -# GPTimer Configuration -# -# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set -# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set -# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set -# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set -# end of GPTimer Configuration - -# -# PCNT Configuration -# -# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set -# CONFIG_PCNT_ISR_IRAM_SAFE is not set -# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set -# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set -# end of PCNT Configuration - -# -# RMT Configuration -# -# CONFIG_RMT_ISR_IRAM_SAFE is not set -# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set -# CONFIG_RMT_ENABLE_DEBUG_LOG is not set -# end of RMT Configuration - -# -# MCPWM Configuration -# -# CONFIG_MCPWM_ISR_IRAM_SAFE is not set -# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set -# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set -# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set -# end of MCPWM Configuration - -# -# I2S Configuration -# -# CONFIG_I2S_ISR_IRAM_SAFE is not set -# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set -# CONFIG_I2S_ENABLE_DEBUG_LOG is not set -# end of I2S Configuration -# end of Driver Configurations - -# -# eFuse Bit Manager -# -# CONFIG_EFUSE_CUSTOM_TABLE is not set -# CONFIG_EFUSE_VIRTUAL is not set -# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set -CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y -# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set -CONFIG_EFUSE_MAX_BLK_LEN=192 -# end of eFuse Bit Manager - -# -# ESP-TLS -# -CONFIG_ESP_TLS_USING_MBEDTLS=y -# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set -# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set -# CONFIG_ESP_TLS_SERVER is not set -# CONFIG_ESP_TLS_PSK_VERIFICATION is not set -# CONFIG_ESP_TLS_INSECURE is not set -# end of ESP-TLS - -# -# ADC and ADC Calibration -# -# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set -# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set - -# -# ADC Calibration Configurations -# -CONFIG_ADC_CALI_EFUSE_TP_ENABLE=y -CONFIG_ADC_CALI_EFUSE_VREF_ENABLE=y -CONFIG_ADC_CALI_LUT_ENABLE=y -# end of ADC Calibration Configurations - -CONFIG_ADC_DISABLE_DAC_OUTPUT=y -# end of ADC and ADC Calibration - -# -# Common ESP-related -# -CONFIG_ESP_ERR_TO_NAME_LOOKUP=y -# end of Common ESP-related - -# -# Ethernet -# -CONFIG_ETH_ENABLED=y -CONFIG_ETH_USE_ESP32_EMAC=y -CONFIG_ETH_PHY_INTERFACE_RMII=y -CONFIG_ETH_RMII_CLK_INPUT=y -# CONFIG_ETH_RMII_CLK_OUTPUT is not set -CONFIG_ETH_RMII_CLK_IN_GPIO=0 -CONFIG_ETH_DMA_BUFFER_SIZE=512 -CONFIG_ETH_DMA_RX_BUFFER_NUM=10 -CONFIG_ETH_DMA_TX_BUFFER_NUM=10 -CONFIG_ETH_USE_SPI_ETHERNET=y -# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set -# CONFIG_ETH_SPI_ETHERNET_W5500 is not set -# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set -# CONFIG_ETH_USE_OPENETH is not set -# CONFIG_ETH_TRANSMIT_MUTEX is not set -# end of Ethernet - -# -# Event Loop Library -# -# CONFIG_ESP_EVENT_LOOP_PROFILING is not set -CONFIG_ESP_EVENT_POST_FROM_ISR=y -CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y -# end of Event Loop Library - -# -# GDB Stub -# -# end of GDB Stub - -# -# ESP HTTP client -# -CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set -# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set -# end of ESP HTTP client - -# -# HTTP Server -# -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 -CONFIG_HTTPD_MAX_URI_LEN=512 -CONFIG_HTTPD_ERR_RESP_NO_DELAY=y -CONFIG_HTTPD_PURGE_BUF_LEN=32 -# CONFIG_HTTPD_LOG_PURGE_DATA is not set -# CONFIG_HTTPD_WS_SUPPORT is not set -# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set -# end of HTTP Server - -# -# ESP HTTPS OTA -# -# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set -# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set -# end of ESP HTTPS OTA - -# -# ESP HTTPS server -# -# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set -# end of ESP HTTPS server - -# -# Hardware Settings -# - -# -# Chip revision -# -CONFIG_ESP32_REV_MIN_0=y -# CONFIG_ESP32_REV_MIN_1 is not set -# CONFIG_ESP32_REV_MIN_1_1 is not set -# CONFIG_ESP32_REV_MIN_2 is not set -# CONFIG_ESP32_REV_MIN_3 is not set -# CONFIG_ESP32_REV_MIN_3_1 is not set -CONFIG_ESP32_REV_MIN=0 -CONFIG_ESP32_REV_MIN_FULL=0 -CONFIG_ESP_REV_MIN_FULL=0 - -# -# Maximum Supported ESP32 Revision (Rev v3.99) -# -CONFIG_ESP32_REV_MAX_FULL=399 -CONFIG_ESP_REV_MAX_FULL=399 -# end of Chip revision - -# -# MAC Config -# -CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y -CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y -CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y -CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y -# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set -CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y -CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 -# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set -# end of MAC Config - -# -# Sleep Config -# -# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set -CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y -# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set -CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y -# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set -CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000 -# end of Sleep Config - -# -# RTC Clock Config -# -CONFIG_RTC_CLK_SRC_INT_RC=y -# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set -# CONFIG_RTC_CLK_SRC_EXT_OSC is not set -# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set -CONFIG_RTC_CLK_CAL_CYCLES=1024 -# end of RTC Clock Config - -# -# Peripheral Control -# -# CONFIG_PERIPH_CTRL_FUNC_IN_IRAM is not set -# end of Peripheral Control - -# -# Main XTAL Config -# -# CONFIG_XTAL_FREQ_26 is not set -CONFIG_XTAL_FREQ_40=y -# CONFIG_XTAL_FREQ_AUTO is not set -CONFIG_XTAL_FREQ=40 -# end of Main XTAL Config -# end of Hardware Settings - -# -# LCD and Touch Panel -# - -# -# LCD Touch Drivers are maintained in the IDF Component Registry -# - -# -# LCD Peripheral Configuration -# -CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 -# CONFIG_LCD_ENABLE_DEBUG_LOG is not set -# end of LCD Peripheral Configuration -# end of LCD and Touch Panel - -# -# ESP NETIF Adapter -# -CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 -CONFIG_ESP_NETIF_TCPIP_LWIP=y -# CONFIG_ESP_NETIF_LOOPBACK is not set -# CONFIG_ESP_NETIF_L2_TAP is not set -# CONFIG_ESP_NETIF_BRIDGE_EN is not set -# end of ESP NETIF Adapter - -# -# PHY -# -CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y -# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set -CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 -CONFIG_ESP_PHY_MAX_TX_POWER=20 -CONFIG_ESP_PHY_REDUCE_TX_POWER=y -# end of PHY - -# -# Power Management -# -# CONFIG_PM_ENABLE is not set -# end of Power Management - -# -# ESP PSRAM -# -# CONFIG_SPIRAM is not set -# end of ESP PSRAM - -# -# ESP Ringbuf -# -# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set -# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set -# end of ESP Ringbuf - -# -# ESP System Settings -# -# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set -CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y -# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set -CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 - -# -# Memory -# -# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set -# end of Memory - -# -# Trace memory -# -# CONFIG_ESP32_TRAX is not set -CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 -# end of Trace memory - -# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set -CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y -# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set -# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set -# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set - -# -# Memory protection -# -# end of Memory protection - -CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 -CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 -CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y -# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set -# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set -CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 -CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 -CONFIG_ESP_CONSOLE_UART_DEFAULT=y -# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_NONE is not set -CONFIG_ESP_CONSOLE_UART=y -CONFIG_ESP_CONSOLE_MULTIPLE_UART=y -CONFIG_ESP_CONSOLE_UART_NUM=0 -CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 -CONFIG_ESP_INT_WDT=y -CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 -CONFIG_ESP_INT_WDT_CHECK_CPU1=y -CONFIG_ESP_TASK_WDT_EN=y -CONFIG_ESP_TASK_WDT_INIT=y -# CONFIG_ESP_TASK_WDT_PANIC is not set -CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 -CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y -CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y -# CONFIG_ESP_PANIC_HANDLER_IRAM is not set -# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set -CONFIG_ESP_DEBUG_OCDAWARE=y -# CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 is not set -CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y - -# -# Brownout Detector -# -CONFIG_ESP_BROWNOUT_DET=y -CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0=y -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7 is not set -CONFIG_ESP_BROWNOUT_DET_LVL=0 -# end of Brownout Detector - -# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set -CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y -# end of ESP System Settings - -# -# IPC (Inter-Processor Call) -# -CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 -CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y -CONFIG_ESP_IPC_ISR_ENABLE=y -# end of IPC (Inter-Processor Call) - -# -# High resolution timer (esp_timer) -# -# CONFIG_ESP_TIMER_PROFILING is not set -CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y -CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y -CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 -CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 -# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set -CONFIG_ESP_TIMER_IMPL_TG0_LAC=y -# end of High resolution timer (esp_timer) - -# -# Wi-Fi -# -CONFIG_ESP32_WIFI_ENABLED=y -CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 -CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 -# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y -CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 -# CONFIG_ESP32_WIFI_CSI_ENABLED is not set -CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y -CONFIG_ESP32_WIFI_TX_BA_WIN=6 -CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y -CONFIG_ESP32_WIFI_RX_BA_WIN=6 -CONFIG_ESP32_WIFI_NVS_ENABLED=y -CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y -# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set -CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 -CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 -CONFIG_ESP32_WIFI_IRAM_OPT=y -CONFIG_ESP32_WIFI_RX_IRAM_OPT=y -CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y -CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y -# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set -CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y -# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y -# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set -CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 -# end of Wi-Fi - -# -# Core dump -# -# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set -# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set -CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y -# end of Core dump - -# -# FAT Filesystem support -# -CONFIG_FATFS_VOLUME_COUNT=2 -# CONFIG_FATFS_SECTOR_512 is not set -# CONFIG_FATFS_SECTOR_1024 is not set -# CONFIG_FATFS_SECTOR_2048 is not set -CONFIG_FATFS_SECTOR_4096=y -CONFIG_FATFS_SECTORS_PER_CLUSTER_1=y -# CONFIG_FATFS_SECTORS_PER_CLUSTER_2 is not set -# CONFIG_FATFS_SECTORS_PER_CLUSTER_4 is not set -# CONFIG_FATFS_SECTORS_PER_CLUSTER_8 is not set -# CONFIG_FATFS_SECTORS_PER_CLUSTER_16 is not set -# CONFIG_FATFS_SECTORS_PER_CLUSTER_32 is not set -# CONFIG_FATFS_SECTORS_PER_CLUSTER_64 is not set -# CONFIG_FATFS_SECTORS_PER_CLUSTER_128 is not set -# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set -CONFIG_FATFS_CODEPAGE_437=y -# CONFIG_FATFS_CODEPAGE_720 is not set -# CONFIG_FATFS_CODEPAGE_737 is not set -# CONFIG_FATFS_CODEPAGE_771 is not set -# CONFIG_FATFS_CODEPAGE_775 is not set -# CONFIG_FATFS_CODEPAGE_850 is not set -# CONFIG_FATFS_CODEPAGE_852 is not set -# CONFIG_FATFS_CODEPAGE_855 is not set -# CONFIG_FATFS_CODEPAGE_857 is not set -# CONFIG_FATFS_CODEPAGE_860 is not set -# CONFIG_FATFS_CODEPAGE_861 is not set -# CONFIG_FATFS_CODEPAGE_862 is not set -# CONFIG_FATFS_CODEPAGE_863 is not set -# CONFIG_FATFS_CODEPAGE_864 is not set -# CONFIG_FATFS_CODEPAGE_865 is not set -# CONFIG_FATFS_CODEPAGE_866 is not set -# CONFIG_FATFS_CODEPAGE_869 is not set -# CONFIG_FATFS_CODEPAGE_932 is not set -# CONFIG_FATFS_CODEPAGE_936 is not set -# CONFIG_FATFS_CODEPAGE_949 is not set -# CONFIG_FATFS_CODEPAGE_950 is not set -CONFIG_FATFS_AUTO_TYPE=y -# CONFIG_FATFS_FAT12 is not set -# CONFIG_FATFS_FAT16 is not set -CONFIG_FATFS_CODEPAGE=437 -CONFIG_FATFS_LFN_NONE=y -# CONFIG_FATFS_LFN_HEAP is not set -# CONFIG_FATFS_LFN_STACK is not set -CONFIG_FATFS_FS_LOCK=0 -CONFIG_FATFS_TIMEOUT_MS=10000 -CONFIG_FATFS_PER_FILE_CACHE=y -# CONFIG_FATFS_USE_FASTSEEK is not set -# end of FAT Filesystem support - -# -# FreeRTOS -# - -# -# Kernel -# -# CONFIG_FREERTOS_SMP is not set -# CONFIG_FREERTOS_UNICORE is not set -CONFIG_FREERTOS_HZ=1000 -# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set -# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set -CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y -CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 -CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 -# CONFIG_FREERTOS_USE_IDLE_HOOK is not set -# CONFIG_FREERTOS_USE_TICK_HOOK is not set -CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 -# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set -CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 -CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 -CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 -CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 -# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set -# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set -# end of Kernel - -# -# Port -# -CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y -# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set -# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set -CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y -CONFIG_FREERTOS_ISR_STACKSIZE=1536 -CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y -# CONFIG_FREERTOS_FPU_IN_ISR is not set -CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y -CONFIG_FREERTOS_CORETIMER_0=y -# CONFIG_FREERTOS_CORETIMER_1 is not set -CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y -# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set -# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set -# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set -CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y -CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y -# end of Port - -CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF -CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y -CONFIG_FREERTOS_DEBUG_OCDAWARE=y -# end of FreeRTOS - -# -# Hardware Abstraction Layer (HAL) and Low Level (LL) -# -CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y -# CONFIG_HAL_ASSERTION_DISABLE is not set -# CONFIG_HAL_ASSERTION_SILENT is not set -# CONFIG_HAL_ASSERTION_ENABLE is not set -CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 -# end of Hardware Abstraction Layer (HAL) and Low Level (LL) - -# -# Heap memory debugging -# -CONFIG_HEAP_POISONING_DISABLED=y -# CONFIG_HEAP_POISONING_LIGHT is not set -# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set -CONFIG_HEAP_TRACING_OFF=y -# CONFIG_HEAP_TRACING_STANDALONE is not set -# CONFIG_HEAP_TRACING_TOHOST is not set -# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set -# end of Heap memory debugging - -# -# Log output -# -# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set -# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set -# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set -CONFIG_LOG_DEFAULT_LEVEL_INFO=y -# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set -# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_LOG_DEFAULT_LEVEL=3 -CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y -# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set -# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set -CONFIG_LOG_MAXIMUM_LEVEL=3 -CONFIG_LOG_COLORS=y -CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y -# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set -# end of Log output - -# -# LWIP -# -CONFIG_LWIP_LOCAL_HOSTNAME="espressif" -# CONFIG_LWIP_NETIF_API is not set -# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set -# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set -CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y -# CONFIG_LWIP_L2_TO_L3_COPY is not set -# CONFIG_LWIP_IRAM_OPTIMIZATION is not set -CONFIG_LWIP_TIMERS_ONDEMAND=y -CONFIG_LWIP_MAX_SOCKETS=10 -# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set -# CONFIG_LWIP_SO_LINGER is not set -CONFIG_LWIP_SO_REUSE=y -CONFIG_LWIP_SO_REUSE_RXTOALL=y -# CONFIG_LWIP_SO_RCVBUF is not set -# CONFIG_LWIP_NETBUF_RECVINFO is not set -CONFIG_LWIP_IP4_FRAG=y -CONFIG_LWIP_IP6_FRAG=y -# CONFIG_LWIP_IP4_REASSEMBLY is not set -# CONFIG_LWIP_IP6_REASSEMBLY is not set -# CONFIG_LWIP_IP_FORWARD is not set -# CONFIG_LWIP_STATS is not set -CONFIG_LWIP_ESP_GRATUITOUS_ARP=y -CONFIG_LWIP_GARP_TMR_INTERVAL=60 -CONFIG_LWIP_ESP_MLDV6_REPORT=y -CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 -CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 -CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y -# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set -CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y -# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set -CONFIG_LWIP_DHCP_OPTIONS_LEN=68 -CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 -CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 - -# -# DHCP server -# -CONFIG_LWIP_DHCPS=y -CONFIG_LWIP_DHCPS_LEASE_UNIT=60 -CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 -# end of DHCP server - -# CONFIG_LWIP_AUTOIP is not set -CONFIG_LWIP_IPV6=y -# CONFIG_LWIP_IPV6_AUTOCONFIG is not set -CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 -# CONFIG_LWIP_IPV6_FORWARD is not set -# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set -CONFIG_LWIP_NETIF_LOOPBACK=y -CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 - -# -# TCP -# -CONFIG_LWIP_MAX_ACTIVE_TCP=16 -CONFIG_LWIP_MAX_LISTENING_TCP=16 -CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y -CONFIG_LWIP_TCP_MAXRTX=12 -CONFIG_LWIP_TCP_SYNMAXRTX=12 -CONFIG_LWIP_TCP_MSS=1440 -CONFIG_LWIP_TCP_TMR_INTERVAL=250 -CONFIG_LWIP_TCP_MSL=60000 -CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 -CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 -CONFIG_LWIP_TCP_WND_DEFAULT=5744 -CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 -CONFIG_LWIP_TCP_QUEUE_OOSEQ=y -# CONFIG_LWIP_TCP_SACK_OUT is not set -CONFIG_LWIP_TCP_OVERSIZE_MSS=y -# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set -# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set -CONFIG_LWIP_TCP_RTO_TIME=1500 -# end of TCP - -# -# UDP -# -CONFIG_LWIP_MAX_UDP_PCBS=16 -CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 -# end of UDP - -# -# Checksums -# -# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set -# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set -CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y -# end of Checksums - -CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 -CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y -# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set -# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set -CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF -# CONFIG_LWIP_PPP_SUPPORT is not set -CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 -CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 -# CONFIG_LWIP_SLIP_SUPPORT is not set - -# -# ICMP -# -CONFIG_LWIP_ICMP=y -# CONFIG_LWIP_MULTICAST_PING is not set -# CONFIG_LWIP_BROADCAST_PING is not set -# end of ICMP - -# -# LWIP RAW API -# -CONFIG_LWIP_MAX_RAW_PCBS=16 -# end of LWIP RAW API - -# -# SNTP -# -CONFIG_LWIP_SNTP_MAX_SERVERS=1 -# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set -CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 -# end of SNTP - -CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 -CONFIG_LWIP_ESP_LWIP_ASSERT=y - -# -# Hooks -# -# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set -CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y -# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set -CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y -# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set -# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set -CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y -# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set -# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set -CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y -# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set -# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set -CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y -# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set -# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set -# end of Hooks - -# CONFIG_LWIP_DEBUG is not set -# end of LWIP - -# -# mbedTLS -# -CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y -# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set -# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set -CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y -CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 -CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 -# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set -# CONFIG_MBEDTLS_DEBUG is not set - -# -# mbedTLS v3.x related -# -# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set -# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set -# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set -# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set -CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y -# end of mbedTLS v3.x related - -# -# Certificate Bundle -# -CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y -CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y -# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set -# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set -# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set -CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 -# end of Certificate Bundle - -# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set -# CONFIG_MBEDTLS_CMAC_C is not set -CONFIG_MBEDTLS_HARDWARE_AES=y -CONFIG_MBEDTLS_HARDWARE_MPI=y -CONFIG_MBEDTLS_HARDWARE_SHA=y -CONFIG_MBEDTLS_ROM_MD5=y -# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set -# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set -CONFIG_MBEDTLS_HAVE_TIME=y -# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set -# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set -CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y -CONFIG_MBEDTLS_SHA512_C=y -CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y -# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set -# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set -# CONFIG_MBEDTLS_TLS_DISABLED is not set -CONFIG_MBEDTLS_TLS_SERVER=y -CONFIG_MBEDTLS_TLS_CLIENT=y -CONFIG_MBEDTLS_TLS_ENABLED=y - -# -# TLS Key Exchange Methods -# -# CONFIG_MBEDTLS_PSK_MODES is not set -CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y -# end of TLS Key Exchange Methods - -CONFIG_MBEDTLS_SSL_RENEGOTIATION=y -CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set -# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set -CONFIG_MBEDTLS_SSL_ALPN=y -CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y -CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y - -# -# Symmetric Ciphers -# -CONFIG_MBEDTLS_AES_C=y -# CONFIG_MBEDTLS_CAMELLIA_C is not set -# CONFIG_MBEDTLS_DES_C is not set -# CONFIG_MBEDTLS_BLOWFISH_C is not set -# CONFIG_MBEDTLS_XTEA_C is not set -CONFIG_MBEDTLS_CCM_C=y -CONFIG_MBEDTLS_GCM_C=y -# CONFIG_MBEDTLS_NIST_KW_C is not set -# end of Symmetric Ciphers - -# CONFIG_MBEDTLS_RIPEMD160_C is not set - -# -# Certificates -# -CONFIG_MBEDTLS_PEM_PARSE_C=y -CONFIG_MBEDTLS_PEM_WRITE_C=y -CONFIG_MBEDTLS_X509_CRL_PARSE_C=y -CONFIG_MBEDTLS_X509_CSR_PARSE_C=y -# end of Certificates - -CONFIG_MBEDTLS_ECP_C=y -# CONFIG_MBEDTLS_DHM_C is not set -CONFIG_MBEDTLS_ECDH_C=y -CONFIG_MBEDTLS_ECDSA_C=y -# CONFIG_MBEDTLS_ECJPAKE_C is not set -CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y -CONFIG_MBEDTLS_ECP_NIST_OPTIM=y -# CONFIG_MBEDTLS_POLY1305_C is not set -# CONFIG_MBEDTLS_CHACHA20_C is not set -# CONFIG_MBEDTLS_HKDF_C is not set -# CONFIG_MBEDTLS_THREADING_C is not set -# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set -# CONFIG_MBEDTLS_SECURITY_RISKS is not set -# end of mbedTLS - -# -# ESP-MQTT Configurations -# -CONFIG_MQTT_PROTOCOL_311=y -# CONFIG_MQTT_PROTOCOL_5 is not set -CONFIG_MQTT_TRANSPORT_SSL=y -CONFIG_MQTT_TRANSPORT_WEBSOCKET=y -CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y -# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set -# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set -# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set -# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set -# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set -# CONFIG_MQTT_CUSTOM_OUTBOX is not set -# end of ESP-MQTT Configurations - -# -# Newlib -# -CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y -# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set -# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set -# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set -# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set -CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y -# CONFIG_NEWLIB_NANO_FORMAT is not set -CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y -# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set -# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set -# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set -# end of Newlib - -# -# NVS -# -# CONFIG_NVS_ASSERT_ERROR_CHECK is not set -# end of NVS - -# -# OpenThread -# -# CONFIG_OPENTHREAD_ENABLED is not set -# end of OpenThread - -# -# Protocomm -# -CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y -CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y -CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y -# end of Protocomm - -# -# PThreads -# -CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 -CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 -CONFIG_PTHREAD_STACK_MIN=768 -CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y -# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set -# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set -CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 -CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" -# end of PThreads - -# -# MMU Config -# -CONFIG_MMU_PAGE_SIZE_64KB=y -CONFIG_MMU_PAGE_MODE="64KB" -CONFIG_MMU_PAGE_SIZE=0x10000 -# end of MMU Config - -# -# SPI Flash driver -# -# CONFIG_SPI_FLASH_VERIFY_WRITE is not set -# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set -CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y -CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y -# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set -# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set -# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set -# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set -CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y -CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 -CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 -CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 -# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set -# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set -# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set - -# -# SPI Flash behavior when brownout -# -CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y -CONFIG_SPI_FLASH_BROWNOUT_RESET=y -# end of SPI Flash behavior when brownout - -# -# Auto-detect flash chips -# -CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y -CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y -CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y -CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y -# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set -# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set -# end of Auto-detect flash chips - -CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y -# end of SPI Flash driver - -# -# SPIFFS Configuration -# -CONFIG_SPIFFS_MAX_PARTITIONS=3 - -# -# SPIFFS Cache Configuration -# -CONFIG_SPIFFS_CACHE=y -CONFIG_SPIFFS_CACHE_WR=y -# CONFIG_SPIFFS_CACHE_STATS is not set -# end of SPIFFS Cache Configuration - -CONFIG_SPIFFS_PAGE_CHECK=y -CONFIG_SPIFFS_GC_MAX_RUNS=10 -# CONFIG_SPIFFS_GC_STATS is not set -CONFIG_SPIFFS_PAGE_SIZE=256 -CONFIG_SPIFFS_OBJ_NAME_LEN=32 -# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set -CONFIG_SPIFFS_USE_MAGIC=y -CONFIG_SPIFFS_USE_MAGIC_LENGTH=y -CONFIG_SPIFFS_META_LENGTH=4 -CONFIG_SPIFFS_USE_MTIME=y - -# -# Debug Configuration -# -# CONFIG_SPIFFS_DBG is not set -# CONFIG_SPIFFS_API_DBG is not set -# CONFIG_SPIFFS_GC_DBG is not set -# CONFIG_SPIFFS_CACHE_DBG is not set -# CONFIG_SPIFFS_CHECK_DBG is not set -# CONFIG_SPIFFS_TEST_VISUALISATION is not set -# end of Debug Configuration -# end of SPIFFS Configuration - -# -# TCP Transport -# - -# -# Websocket -# -CONFIG_WS_TRANSPORT=y -CONFIG_WS_BUFFER_SIZE=1024 -# CONFIG_WS_DYNAMIC_BUFFER is not set -# end of Websocket -# end of TCP Transport - -# -# Ultra Low Power (ULP) Co-processor -# -# CONFIG_ULP_COPROC_ENABLED is not set -# end of Ultra Low Power (ULP) Co-processor - -# -# Unity unit testing library -# -CONFIG_UNITY_ENABLE_FLOAT=y -CONFIG_UNITY_ENABLE_DOUBLE=y -# CONFIG_UNITY_ENABLE_64BIT is not set -# CONFIG_UNITY_ENABLE_COLOR is not set -CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y -# CONFIG_UNITY_ENABLE_FIXTURE is not set -# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set -# end of Unity unit testing library - -# -# Root Hub configuration -# -# end of Root Hub configuration - -# -# Virtual file system -# -CONFIG_VFS_SUPPORT_IO=y -CONFIG_VFS_SUPPORT_DIR=y -CONFIG_VFS_SUPPORT_SELECT=y -CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y -CONFIG_VFS_SUPPORT_TERMIOS=y - -# -# Host File System I/O (Semihosting) -# -CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 -# end of Host File System I/O (Semihosting) -# end of Virtual file system - -# -# Wear Levelling -# -# CONFIG_WL_SECTOR_SIZE_512 is not set -CONFIG_WL_SECTOR_SIZE_4096=y -CONFIG_WL_SECTOR_SIZE=4096 -# end of Wear Levelling - -# -# Wi-Fi Provisioning Manager -# -CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 -CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 -# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set -CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y -# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set -# end of Wi-Fi Provisioning Manager - -# -# Supplicant -# -CONFIG_WPA_MBEDTLS_CRYPTO=y -CONFIG_WPA_MBEDTLS_TLS_CLIENT=y -# CONFIG_WPA_WAPI_PSK is not set -# CONFIG_WPA_SUITE_B_192 is not set -# CONFIG_WPA_DEBUG_PRINT is not set -# CONFIG_WPA_TESTING_OPTIONS is not set -# CONFIG_WPA_WPS_STRICT is not set -# CONFIG_WPA_11KV_SUPPORT is not set -# CONFIG_WPA_MBO_SUPPORT is not set -# CONFIG_WPA_DPP_SUPPORT is not set -# CONFIG_WPA_11R_SUPPORT is not set -# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set -# end of Supplicant -# end of Component config - -# Deprecated options for backward compatibility -# CONFIG_NO_BLOBS is not set -# CONFIG_ESP32_NO_BLOBS is not set -# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set -# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set -CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y -# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set -CONFIG_LOG_BOOTLOADER_LEVEL=3 -# CONFIG_APP_ROLLBACK_ENABLE is not set -# CONFIG_FLASH_ENCRYPTION_ENABLED is not set -# CONFIG_FLASHMODE_QIO is not set -# CONFIG_FLASHMODE_QOUT is not set -CONFIG_FLASHMODE_DIO=y -# CONFIG_FLASHMODE_DOUT is not set -CONFIG_MONITOR_BAUD=115200 -CONFIG_OPTIMIZATION_LEVEL_DEBUG=y -CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y -# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set -# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set -CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y -# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set -# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set -CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 -# CONFIG_CXX_EXCEPTIONS is not set -CONFIG_STACK_CHECK_NONE=y -# CONFIG_STACK_CHECK_NORM is not set -# CONFIG_STACK_CHECK_STRONG is not set -# CONFIG_STACK_CHECK_ALL is not set -# CONFIG_WARN_WRITE_STRINGS is not set -# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set -CONFIG_ESP32_APPTRACE_DEST_NONE=y -CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y -CONFIG_ADC2_DISABLE_DAC=y -# CONFIG_MCPWM_ISR_IN_IRAM is not set -# CONFIG_EVENT_LOOP_PROFILING is not set -CONFIG_POST_EVENTS_FROM_ISR=y -CONFIG_POST_EVENTS_FROM_IRAM_ISR=y -# CONFIG_OTA_ALLOW_HTTP is not set -# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set -CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y -CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 -# CONFIG_ESP_SYSTEM_PD_FLASH is not set -CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 -CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y -CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y -# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set -# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set -# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set -# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set -# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set -# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set -CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 -# CONFIG_ESP32_XTAL_FREQ_26 is not set -CONFIG_ESP32_XTAL_FREQ_40=y -# CONFIG_ESP32_XTAL_FREQ_AUTO is not set -CONFIG_ESP32_XTAL_FREQ=40 -CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y -# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set -CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 -CONFIG_ESP32_PHY_MAX_TX_POWER=20 -CONFIG_REDUCE_PHY_TX_POWER=y -CONFIG_ESP32_REDUCE_PHY_TX_POWER=y -# CONFIG_SPIRAM_SUPPORT is not set -# CONFIG_ESP32_SPIRAM_SUPPORT is not set -# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set -CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y -# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set -CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160 -CONFIG_TRACEMEM_RESERVE_DRAM=0x0 -# CONFIG_ESP32_PANIC_PRINT_HALT is not set -CONFIG_ESP32_PANIC_PRINT_REBOOT=y -# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set -# CONFIG_ESP32_PANIC_GDBSTUB is not set -CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 -CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_MAIN_TASK_STACK_SIZE=3584 -CONFIG_CONSOLE_UART_DEFAULT=y -# CONFIG_CONSOLE_UART_CUSTOM is not set -# CONFIG_CONSOLE_UART_NONE is not set -# CONFIG_ESP_CONSOLE_UART_NONE is not set -CONFIG_CONSOLE_UART=y -CONFIG_CONSOLE_UART_NUM=0 -CONFIG_CONSOLE_UART_BAUDRATE=115200 -CONFIG_INT_WDT=y -CONFIG_INT_WDT_TIMEOUT_MS=300 -CONFIG_INT_WDT_CHECK_CPU1=y -CONFIG_TASK_WDT=y -CONFIG_ESP_TASK_WDT=y -# CONFIG_TASK_WDT_PANIC is not set -CONFIG_TASK_WDT_TIMEOUT_S=5 -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y -CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y -# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set -CONFIG_ESP32_DEBUG_OCDAWARE=y -CONFIG_BROWNOUT_DET=y -CONFIG_ESP32_BROWNOUT_DET=y -CONFIG_BROWNOUT_DET_LVL_SEL_0=y -CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y -# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set -CONFIG_BROWNOUT_DET_LVL=0 -CONFIG_ESP32_BROWNOUT_DET_LVL=0 -# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set -CONFIG_IPC_TASK_STACK_SIZE=1024 -CONFIG_TIMER_TASK_STACK_SIZE=3584 -# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set -# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set -CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y -CONFIG_TIMER_TASK_PRIORITY=1 -CONFIG_TIMER_TASK_STACK_DEPTH=2048 -CONFIG_TIMER_QUEUE_LENGTH=10 -# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set -# CONFIG_HAL_ASSERTION_SILIENT is not set -# CONFIG_L2_TO_L3_COPY is not set -CONFIG_ESP_GRATUITOUS_ARP=y -CONFIG_GARP_TMR_INTERVAL=60 -CONFIG_TCPIP_RECVMBOX_SIZE=32 -CONFIG_TCP_MAXRTX=12 -CONFIG_TCP_SYNMAXRTX=12 -CONFIG_TCP_MSS=1440 -CONFIG_TCP_MSL=60000 -CONFIG_TCP_SND_BUF_DEFAULT=5744 -CONFIG_TCP_WND_DEFAULT=5744 -CONFIG_TCP_RECVMBOX_SIZE=6 -CONFIG_TCP_QUEUE_OOSEQ=y -CONFIG_TCP_OVERSIZE_MSS=y -# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set -# CONFIG_TCP_OVERSIZE_DISABLE is not set -CONFIG_UDP_RECVMBOX_SIZE=6 -CONFIG_TCPIP_TASK_STACK_SIZE=3072 -CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y -# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set -# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set -CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF -# CONFIG_PPP_SUPPORT is not set -CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT=y -CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y -# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set -# CONFIG_ESP32_TIME_SYSCALL_USE_HRT is not set -# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set -# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set -CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 -CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 -CONFIG_ESP32_PTHREAD_STACK_MIN=768 -CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y -# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set -# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set -CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 -CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" -CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y -# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set -# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set -# CONFIG_ESP32_ULP_COPROC_ENABLED is not set -CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y -CONFIG_SUPPORT_TERMIOS=y -CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 -# End of deprecated options diff --git a/examples/NonArduino/ESP-IDF/sdkconfig.defaults b/examples/NonArduino/ESP-IDF/sdkconfig.defaults new file mode 100644 index 0000000000..c95181cf1f --- /dev/null +++ b/examples/NonArduino/ESP-IDF/sdkconfig.defaults @@ -0,0 +1,2 @@ +# Increase FreeRTOS tick rate to 1000 Hz +CONFIG_FREERTOS_HZ=1000 From 01fa4d0c2d44438690b576254fa562ef3cfa6ceb Mon Sep 17 00:00:00 2001 From: Darian Leung <32921628+Dazza0@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:07:02 +0800 Subject: [PATCH 1566/1848] [LR11X0] Add missing description to 'offset' parameter in 'getPacketLength()' --- src/modules/LR11x0/LR11x0.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index c7f2d6278d..54a8466de6 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1349,6 +1349,7 @@ class LR11x0: public PhysicalLayer { /*! \brief Query modem for the packet length of received payload. \param update Update received packet length. Will return cached value when set to false. + \param offset Pointer to a variable that will hold the receive packet's offset in the RX buffer \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update, uint8_t* offset); From d2cef5bc9fddfbde6b9b8f440d1b88c7aca0bc76 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 00:39:48 +0200 Subject: [PATCH 1567/1848] Update keywords.txt --- keywords.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index e65fc66adf..2576cd8702 100644 --- a/keywords.txt +++ b/keywords.txt @@ -376,7 +376,6 @@ scheduleTransmission KEYWORD2 getFCntUp KEYWORD2 getNFCntDown KEYWORD2 getAFCntDown KEYWORD2 -resetFCntDown KEYWORD2 getDevAddr KEYWORD2 getLastToA KEYWORD2 dutyCycleInterval KEYWORD2 From a4375086ac3e1fbe1c8f87162aca001ab1c28ba1 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 00:36:06 +0200 Subject: [PATCH 1568/1848] [LoRaWAN] Fix to RP 1.0.4 / 1.1B --- src/protocols/LoRaWAN/LoRaWANBands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 2c3370f2e7..07ad788bda 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -92,7 +92,7 @@ const LoRaWANBand_t US915 = { .freqMax = 9280000, .payloadLenMax = { 11, 53, 125, 242, 242, 50, 125, 0, 53, 129, 242, 242, 242, 242, 0 }, .powerMax = 30, - .powerNumSteps = 10, + .powerNumSteps = 14, .dutyCycle = 0, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, From a52a03b15579ff993b0f055de37a4a7c507ea0c6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 00:36:49 +0200 Subject: [PATCH 1569/1848] [LoRaWAN] Remove unused TS009 function from example --- examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h index 6e360c5d3d..569778a589 100644 --- a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h @@ -148,7 +148,7 @@ void handleTS009(uint8_t* dataDown, size_t lenDown) { case(RADIOLIB_LORAWAN_TS009_RX_APP_CNT_RESET): { RADIOLIB_DEBUG_PRINTLN("Resetting Application Frame count"); - node.resetFCntDown(); + RADIOLIB_DEBUG_PRINTLN("WARNING: not implemented - never used in tests!"); reply = false; } break; From 75ac7b74879272aacba5eeb28f679e3ab65f0e47 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 00:39:00 +0200 Subject: [PATCH 1570/1848] [LoRaWAN] Pre-certified for fixed channelplans! Some cleanup to do with the channel masks; temporary `addDefaultChannelsMask()` --- src/protocols/LoRaWAN/LoRaWAN.cpp | 147 +++++++++++++++++++++++++----- src/protocols/LoRaWAN/LoRaWAN.h | 10 +- 2 files changed, 126 insertions(+), 31 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 29f569ae35..7ba5d9c7bb 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -536,7 +536,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { // restore the complete MAC state - uint8_t cOcts[14] = { 0 }; // TODO explain + uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size uint8_t cid; uint8_t cLen = 0; @@ -1004,7 +1004,7 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { void LoRaWANNode::processCFList(const uint8_t* cfList) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); - uint8_t cOcts[14] = { 0 }; // TODO explain + uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size uint8_t cid; uint8_t cLen = 0; @@ -1236,10 +1236,9 @@ void LoRaWANNode::adrBackoff() { } } } else { - // in a fixed band, all channels must be enabled - // officially, this should be subband = 0, but so far, - // reverting to the used subband seems a sensible solution - this->selectChannelPlanFix(); + // in a fixed band, all default channels must be enabled + // this means reverting to the original subband + this->addDefaultChannelsMask(); } // re-enabling default channels may have enabled channels that do support @@ -2005,7 +2004,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L state = this->getMacLen(cid, &fLen, RADIOLIB_LORAWAN_DOWNLINK, true, mPtr + 1); if(state != RADIOLIB_ERR_NONE) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Unknown MAC CID %02x", cid); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC payload"); fOptsLen = procLen; // truncate to last processed MAC command break; } @@ -2014,7 +2013,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // check whether the complete payload is present if(procLen + fLen > fOptsLen) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Incomplete MAC command %02x (%d bytes, expected %d)", cid, fOptsLen - procLen, fLen); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC commands"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("WARNING: Skipping remaining MAC payload"); fOptsLen = procLen; // truncate to last processed MAC command break; } @@ -2061,8 +2060,8 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L reply = this->execMacCommand(cid, mPtr + 1, fLen - 1, &fOptsRe[fOptsReLen + 1]); } - // if there is a reply, only add it to the reply if maximum payload size allows - if(reply && (fOptsReLen + fLenRe <= this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr])) { + // if there is a reply, add it to the response payload + if(reply) { fOptsRe[fOptsReLen] = cid; fOptsReLen += fLenRe; } @@ -2079,12 +2078,34 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(fOptsReLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { + this->isMACPayload = true; + } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("! Sending MAC-only uplink (%d bytes):", fOptsReLen); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsRe, fOptsReLen); + // get the maximum uplink payload size + uint8_t maxReLen = this->getMaxPayloadLen(); + // truncate uplink payload size if necessary, and send separate uplink + if(fOptsReLen > maxReLen) { this->isMACPayload = true; + fOptsReLen = 0; + uint8_t fLenRe = 0; + uint8_t* mPtr = fOpts; + while(fOptsReLen + fLenRe <= maxReLen) { + fOptsReLen += fLenRe; + + // fetch length of MAC uplink response + (void)this->getMacLen(*mPtr, &fLenRe, RADIOLIB_LORAWAN_UPLINK, true, mPtr + 1); + mPtr += fLenRe; + } + } + + // if the limit on number of FOpts is reached, send a MAC-only uplink + // otherwise, the user might get stuck as the app payload won't fit + if(this->isMACPayload) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("! Sending MAC-only uplink (%d bytes):", fOptsReLen); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(fOptsRe, fOptsReLen); + // temporarily lift dutyCycle restrictions to allow immediate MAC response bool prevDC = this->dutyCycleEnabled; this->dutyCycleEnabled = false; @@ -2686,8 +2707,11 @@ bool LoRaWANNode::derivedMacHandler(uint8_t cid, uint8_t* optIn, uint8_t lenIn, void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAdrOpt) { uint8_t fLen = 5; // single ADR command is 5 bytes uint8_t numOpts = cLen / fLen; + + // get the current channel plan mask uint64_t chMaskGrp0123 = 0; uint32_t chMaskGrp45 = 0; + this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); // set Dr/Tx field from last MAC command mAdrOpt[0] = mPtr[cLen - fLen + 1]; @@ -2719,30 +2743,31 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd // for CN470, this is just a normal channel mask // for all other bands, the first 10 bits enable banks of 8 125kHz channels if(this->band->bandNum == BandCN470) { + chMaskGrp45 &= ~((uint32_t)0xFFFF << 16); chMaskGrp45 |= (uint32_t)chMask << 16; } else { int bank = 0; for(; bank < 8; bank++) { + chMaskGrp0123 &= ~((uint64_t)0xFF << (8 * bank)); if(chMask & ((uint16_t)1 << bank)) { - chMaskGrp0123 |= (0xFF << (8 * bank)); + chMaskGrp0123 |= ((uint64_t)0xFF << (8 * bank)); } } for(; bank < 10; bank++) { + chMaskGrp45 &= ~((uint32_t)0xFF << (8 * (bank - 8))); if(chMask & ((uint16_t)1 << bank)) { - chMaskGrp45 |= (0xFF << (8 * (bank - 8))); + chMaskGrp45 |= ((uint32_t)0xFF << (8 * (bank - 8))); } } } break; case 6: // for dynamic bands: all channels ON (that are currently defined) - // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 - // except for CN470: all 125kHz channels ON + // for fixed bands: all default 125kHz channels ON, channel mask similar to ChMask = 4 + // except for CN470: all default 125kHz channels ON - // for dynamic bands: retrieve all currently defined channels - // for fixed bands: cannot store all defined channels, so select a random one from each bank - this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN470) { + chMaskGrp45 &= ~((uint32_t)0xFFFF); chMaskGrp45 |= (uint32_t)chMask; } break; @@ -3135,11 +3160,6 @@ uint32_t LoRaWANNode::getAFCntDown() { return(this->aFCntDown); } -void LoRaWANNode::resetFCntDown() { - this->nFCntDown = 0; - this->aFCntDown = 0; -} - uint32_t LoRaWANNode::getDevAddr() { return(this->devAddr); } @@ -3295,6 +3315,69 @@ bool LoRaWANNode::cadChannelClear() { return(true); } +void LoRaWANNode::addDefaultChannelsMask() { + // get channel masks for this subband + uint64_t chMaskGrp0123 = 0; + uint32_t chMaskGrp45 = 0; + this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); + + // if there are any channels selected, create the mask from those channels + // channels are always selected for dynamic bands and/or when a device is active + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(int num = 0; num < 3; num++) { + if(this->band->txFreqs[num].enabled) { + chMaskGrp0123 |= ((uint64_t)1 << num); + } + } + + } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED + // if a subband is set, we can set the channel indices straight from subband + if(this->subBand > 0 && this->subBand <= 8) { + // for sub band 1-8, set bank of 8 125kHz + single 500kHz channel + chMaskGrp0123 |= (uint64_t)0xFF << ((this->subBand - 1) * 8); + chMaskGrp45 |= (uint32_t)0x01 << (this->subBand - 1); + } else if(this->subBand > 8 && this->subBand <= 12) { + // CN470 only: for sub band 9-12, set bank of 8 125kHz channels + chMaskGrp45 |= (uint32_t)0xFF << ((this->subBand - 9) * 8); + } else { + // if subband is set to 0, all 125kHz channels are enabled. + // however, we can 'only' store 16 channels, so we don't use all channels at once. + // instead, we select a random channel from each bank of 8 channels + 1 from second plan. + uint8_t num125kHz = this->band->txSpans[0].numChannels; + uint8_t numBanks = num125kHz / 8; + for(uint8_t bank = 0; bank < numBanks; bank++) { + uint8_t bankIdx = this->phyLayer->random(8); + uint8_t idx = bank * 8 + bankIdx; + if(idx < 64) { + chMaskGrp0123 |= ((uint64_t)1 << idx); + } else { + chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); + } + } + // the 500 kHz channels are in the usual channel plan however + // these are the channel indices 64-71 for bands other than CN470 + if(this->band->bandNum != BandCN470) { + for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; + if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE && idx >= 64) { + chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); + } + } + } + } + } + + // apply channel mask + this->applyChannelMask(chMaskGrp0123, chMaskGrp45); + + // make sure the Rx2 settings are back to this band's default + this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; + this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; + + // make all enabled channels available for uplink selection + this->setAvailableChannels(0xFFFF); +} + void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45) { // clear masks in case anything was set *chMaskGrp0123 = 0; @@ -3524,6 +3607,12 @@ bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) int chOfs = 0; for(; chNum < 64; chNum++) { if(chMaskGrp0123 & ((uint64_t)1 << chNum)) { + // if a subband is specified, any channel must be within the specified subband + // we subtract 1 here because subbands are numbered starting from 1 + if(this->subBand > 0 && (chNum / 8) != (this->subBand - 1)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Channel %d not allowed for subband %d", chNum, this->subBand); + return(false); + } chnl.enabled = true; chnl.idx = chNum; chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; @@ -3539,6 +3628,16 @@ bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) } for(; chNum < this->band->txSpans[spanNum].numChannels; chNum++) { if(chMaskGrp45 & ((uint32_t)1 << chNum)) { + // if a subband is specified, any channel must be within the specified subband + // we subtract 1 here because subbands are numbered starting from 1 + if(this->band->numTxSpans == 1 && this->subBand > 0 && (chNum / 8) != (this->subBand - 1)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Channel %d not allowed for subband %d", chNum, this->subBand); + return(false); + } + if(this->band->numTxSpans > 1 && this->subBand > 0 && chNum != (this->subBand - 1)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Channel %d not allowed for subband %d", chNum, this->subBand); + return(false); + } chnl.enabled = true; chnl.idx = chNum + chOfs; chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 93bd9a8742..9e45481313 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -892,13 +892,6 @@ class LoRaWANNode { */ uint32_t getAFCntDown(); - /*! - \brief Reset the downlink frame counters (application and network) - This is unsafe and can possibly allow replay attacks using downlinks. - It mainly exists as part of the TS009 Specification Verification protocol. - */ - void resetFCntDown(); - /*! \brief Returns the DevAddr of the device, regardless of OTAA or ABP mode \returns 4-byte DevAddr @@ -1215,6 +1208,9 @@ class LoRaWANNode { // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. bool cadChannelClear(); + // get the current channel mask and add all default channels + void addDefaultChannelsMask(); + // (dynamic bands:) get or (fixed bands:) create a complete 80-bit channel mask for current configuration void getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45); From 4b56b5be5f56604de50bdfe9066337ed8bd2bec7 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 12:24:08 +0200 Subject: [PATCH 1571/1848] [LoRaWAN] Remove outdated RP 1.1A comment --- src/protocols/LoRaWAN/LoRaWANBands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 07ad788bda..53e9e15fdd 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -253,7 +253,7 @@ const LoRaWANBand_t AU915 = { .dutyCycle = 0, .dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME, .dwellTimeDn = 0, - .txParamSupported = true, // conflict: not implemented according to RP v1.1 + .txParamSupported = true, .txFreqs = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, From 073e57cbbb69011c517ca3f95d5b7537fd799992 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 12:27:11 +0200 Subject: [PATCH 1572/1848] [LoRaWAN] Clean up fixed plan channel handling, fix default DR --- src/protocols/LoRaWAN/LoRaWAN.cpp | 167 +++++------------------------- src/protocols/LoRaWAN/LoRaWAN.h | 15 +-- 2 files changed, 27 insertions(+), 155 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7ba5d9c7bb..e19e0b856d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -335,12 +335,8 @@ void LoRaWANNode::clearSession() { void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { this->clearSession(); - // setup JoinRequest uplink/downlink frequencies and datarates - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(); - } else { - this->selectChannelPlanFix(); - } + // setup the default channels + this->addDefaultChannels(); uint8_t drUp = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; @@ -541,11 +537,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { uint8_t cLen = 0; // setup the default channels - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(); - } else { // type == RADIOLIB_LORAWAN_BAND_FIXED) - this->selectChannelPlanFix(); - } + this->addDefaultChannels(); // for dynamic bands, the additional channels must be restored per-channel if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { @@ -792,11 +784,6 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { } } - - // in case of dynamic band, reset the channels to clear JoinRequest-specific channels - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - this->selectChannelPlanDyn(); - } uint8_t cOcts[5]; uint8_t cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; @@ -1228,18 +1215,7 @@ void LoRaWANNode::adrBackoff() { } // last resort: enable all (default) channels - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // in a dynamic band, default channels are never modified, so safe to assume they exist - for(int num = 0; num < 3; num++) { - if(this->band->txFreqs[num].enabled) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num].enabled = true; - } - } - } else { - // in a fixed band, all default channels must be enabled - // this means reverting to the original subband - this->addDefaultChannelsMask(); - } + this->addDefaultChannels(); // re-enabling default channels may have enabled channels that do support // the next required datarate; if datarate can be decreased, try it @@ -2090,7 +2066,10 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L fOptsReLen = 0; uint8_t fLenRe = 0; - uint8_t* mPtr = fOpts; + + // move back to the start of the uplink buffer + mPtr = fOpts; + // and add as many MAC commands as space is available while(fOptsReLen + fLenRe <= maxReLen) { fOptsReLen += fLenRe; @@ -2719,8 +2698,7 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd // set NbTrans partial field from last MAC command mAdrOpt[13] = mPtr[cLen - fLen + 4] & 0x0F; - uint8_t opt = 0; - while(opt < numOpts) { + for(uint8_t opt = 0; opt < numOpts; opt++) { uint8_t chMaskCntl = (mPtr[opt * fLen + 4] & 0x70) >> 4; uint16_t chMask = LoRaWANNode::ntoh(&mPtr[opt * fLen + 2]); switch(chMaskCntl) { @@ -2780,7 +2758,6 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd } break; } - opt++; } LoRaWANNode::hton(&mAdrOpt[1], chMaskGrp0123); LoRaWANNode::hton(&mAdrOpt[9], chMaskGrp45); @@ -3315,14 +3292,13 @@ bool LoRaWANNode::cadChannelClear() { return(true); } -void LoRaWANNode::addDefaultChannelsMask() { - // get channel masks for this subband +void LoRaWANNode::addDefaultChannels() { + // get current channel masks uint64_t chMaskGrp0123 = 0; uint32_t chMaskGrp45 = 0; this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - // if there are any channels selected, create the mask from those channels - // channels are always selected for dynamic bands and/or when a device is active + // there are at most three default channels for dynamic bands if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { for(int num = 0; num < 3; num++) { if(this->band->txFreqs[num].enabled) { @@ -3343,10 +3319,12 @@ void LoRaWANNode::addDefaultChannelsMask() { // if subband is set to 0, all 125kHz channels are enabled. // however, we can 'only' store 16 channels, so we don't use all channels at once. // instead, we select a random channel from each bank of 8 channels + 1 from second plan. + chMaskGrp0123 = 0; + chMaskGrp45 = 0; uint8_t num125kHz = this->band->txSpans[0].numChannels; uint8_t numBanks = num125kHz / 8; + uint8_t bankIdx = this->phyLayer->random(8); for(uint8_t bank = 0; bank < numBanks; bank++) { - uint8_t bankIdx = this->phyLayer->random(8); uint8_t idx = bank * 8 + bankIdx; if(idx < 64) { chMaskGrp0123 |= ((uint64_t)1 << idx); @@ -3357,12 +3335,7 @@ void LoRaWANNode::addDefaultChannelsMask() { // the 500 kHz channels are in the usual channel plan however // these are the channel indices 64-71 for bands other than CN470 if(this->band->bandNum != BandCN470) { - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; - if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE && idx >= 64) { - chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); - } - } + chMaskGrp45 |= ((uint32_t)1 << bankIdx); } } } @@ -3384,8 +3357,7 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr *chMaskGrp45 = 0; // if there are any channels selected, create the mask from those channels - // channels are always selected for dynamic bands and/or when a device is active - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC || this->isActivated()) { + if(this->isActivated()) { for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { @@ -3396,97 +3368,7 @@ void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGr } } } - return; - - } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED - // if a subband is set, we can set the channel indices straight from subband - if(this->subBand > 0 && this->subBand <= 8) { - // for sub band 1-8, set bank of 8 125kHz + single 500kHz channel - *chMaskGrp0123 |= (uint64_t)0xFF << ((this->subBand - 1) * 8); - *chMaskGrp45 |= (uint32_t)0x01 << (this->subBand - 1); - } else if(this->subBand > 8 && this->subBand <= 12) { - // CN470 only: for sub band 9-12, set bank of 8 125kHz channels - *chMaskGrp45 |= (uint32_t)0xFF << ((this->subBand - 9) * 8); - } else { - // if subband is set to 0, all 125kHz channels are enabled. - // however, we can 'only' store 16 channels, so we don't use all channels at once. - // instead, we select a random channel from each bank of 8 channels + 1 from second plan. - uint8_t num125kHz = this->band->txSpans[0].numChannels; - uint8_t numBanks = num125kHz / 8; - for(uint8_t bank = 0; bank < numBanks; bank++) { - uint8_t bankIdx = this->phyLayer->random(8); - uint8_t idx = bank * 8 + bankIdx; - if(idx < 64) { - *chMaskGrp0123 |= ((uint64_t)1 << idx); - } else { - *chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); - } - } - // the 500 kHz channels are in the usual channel plan however - // these are the channel indices 64-71 for bands other than CN470 - if(this->band->bandNum != BandCN470) { - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; - if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE && idx >= 64) { - *chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); - } - } - } - } - } -} - -void LoRaWANNode::selectChannelPlanDyn() { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up dynamic channels"); - - size_t num = 0; - // copy the default defined channels into the first slots (where Tx = Rx) - for(; num < 3 && this->band->txFreqs[num].enabled; num++) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; - } - - // clear all remaining channels - for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - - // make sure the Rx2 settings are back to this band's default - this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; - this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; - - // make all enabled channels available for uplink selection - this->setAvailableChannels(0xFFFF); - - #if RADIOLIB_DEBUG_PROTOCOL - this->printChannels(); - #endif -} - -// setup a subband and its corresponding JoinRequest datarate -// WARNING: subBand starts at 1 (corresponds to all populair schemes) -void LoRaWANNode::selectChannelPlanFix() { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Setting up fixed channels (subband %d)", this->subBand); - - // clear all existing channels - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; } - - // get channel masks for this subband - uint64_t chMaskGrp0123 = 0; - uint32_t chMaskGrp45 = 0; - this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - - // apply channel mask - this->applyChannelMask(chMaskGrp0123, chMaskGrp45); - - // make sure the Rx2 settings are back to this band's default - this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; - this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; - - // make all enabled channels available for uplink selection - this->setAvailableChannels(0xFFFF); } uint8_t LoRaWANNode::getAvailableChannels(uint16_t* chMask) { @@ -3585,15 +3467,12 @@ int16_t LoRaWANNode::selectChannels() { bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(chMaskGrp0123 & ((uint64_t)1 << i)) { - // if it should be enabled but is not currently defined, stop immediately - if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - return(false); - } - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled = true; - } else { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled = false; + bool en = chMaskGrp0123 & ((uint64_t)1 << i); + // if it should be enabled but is not currently defined, stop immediately + if(en && this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + return(false); } + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled = en; } } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED // full channel mask received, so clear all existing channels @@ -3618,6 +3497,8 @@ bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; chnl.drMin = this->band->txSpans[spanNum].drMin; chnl.drMax = this->band->txSpans[spanNum].drMax; + // set the default datarate to the middle datarate, rounded up + chnl.dr = (chnl.drMin + chnl.drMax + 1) / 2; this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num++] = chnl; } } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 9e45481313..47db068364 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1208,21 +1208,12 @@ class LoRaWANNode { // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. bool cadChannelClear(); - // get the current channel mask and add all default channels - void addDefaultChannelsMask(); + // add all default channels on top of the current channels + void addDefaultChannels(); - // (dynamic bands:) get or (fixed bands:) create a complete 80-bit channel mask for current configuration + // get a complete 80-bit channel mask for current configuration void getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45); - // setup uplink/downlink channel data rates and frequencies - // for dynamic channels, there is a small set of predefined channels - // in case of JoinRequest, add some optional extra frequencies - void selectChannelPlanDyn(); - - // setup uplink/downlink channel data rates and frequencies - // for fixed bands, we only allow one sub-band at a time to be selected - void selectChannelPlanFix(); - // get the number of available channels, // along with a 16-bit mask indicating which channels can be used next for uplink/downlink uint8_t getAvailableChannels(uint16_t* mask); From bbcb3ec6d5148b1e3f7d84fc5150e9b23f9e6777 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:51:13 +0200 Subject: [PATCH 1573/1848] Change README to reflect general LoRaWAN pre-certified status --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 281178043c..b7cd9e3786 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__LoRaWAN__](https://lora-alliance.org/) using LoRa and FSK for modules: SX127x, RFM9x, SX126x, LR11x0 and SX128x - * Supports Class A and C (and Multicast over C) - * Pre-certified for Class A on dynamic channelplans (EU868-style) + * Supports Class A and C (and Multicast over C). + * Pre-certified for Class A. * See the [wiki](https://github.com/jgromes/RadioLib/wiki/LoRaWAN) and [notes](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for more information. ### Supported Arduino platforms: From 227e40b855a7e34383c3a9bb4531ea85f0294b9c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 30 Jun 2025 15:25:58 +0200 Subject: [PATCH 1574/1848] [LoRaWAN] Fix dynamic default channels, fix #1538 --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index e19e0b856d..fa6a25b515 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2048,9 +2048,9 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // remove all MAC commands except those whose payload can be requested by the user // (which are LinkCheck and DeviceTime) - LoRaWANNode::clearMacCommands(fOpts, &fOptsLen, RADIOLIB_LORAWAN_DOWNLINK); - memcpy(this->fOptsDown, fOpts, fOptsLen); this->fOptsDownLen = fOptsLen; + LoRaWANNode::clearMacCommands(fOpts, &this->fOptsDownLen, RADIOLIB_LORAWAN_DOWNLINK); + memcpy(this->fOptsDown, fOpts, this->fOptsDownLen); // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(fOptsReLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { @@ -2819,7 +2819,7 @@ int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) { int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { uint8_t payload[2] = { 0 }; - int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_LINK_CHECK, this->fOptsDown, fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); + int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_LINK_CHECK, this->fOptsDown, this->fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); RADIOLIB_ASSERT(state); if(margin) { *margin = payload[0]; } @@ -2830,7 +2830,7 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { uint8_t payload[5] = { 0 }; - int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, this->fOptsDown, fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); + int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, this->fOptsDown, this->fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); RADIOLIB_ASSERT(state); if(gpsEpoch) { @@ -3302,6 +3302,8 @@ void LoRaWANNode::addDefaultChannels() { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { for(int num = 0; num < 3; num++) { if(this->band->txFreqs[num].enabled) { + this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; + this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; chMaskGrp0123 |= ((uint64_t)1 << num); } } From 5f73a87a3a8d3c939a4c18abf1ff932e7ff3042a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Mon, 30 Jun 2025 19:03:47 +0200 Subject: [PATCH 1575/1848] [CI] ESP-IDF fix (#1547) * [CI] Fix esp-idf version to 5.4.2 * [CI] Fix path --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7ee70772a7..2be588716c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -257,6 +257,9 @@ jobs: mkdir -p ~/esp cd ~/esp git clone --recursive https://github.com/espressif/esp-idf.git + cd esp-idf + git checkout v5.4.2 + git submodule update --init --recursive - name: Install ESP-IDF run: | From 32c3570ad3a67c18ebb82b64ecd8b9431f48c051 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 1 Jul 2025 19:55:51 +0200 Subject: [PATCH 1576/1848] [SX128x] Add missing register write when setting SF (#1549) --- src/modules/SX128x/SX128x.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 4c6d17b7c7..c4167ee3e6 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -695,7 +695,7 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) { int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa); RADIOLIB_ASSERT(state); - // update mystery register in LoRa mode - SX1280 datasheet v3.0 section 13.4.1 + // update mystery register in LoRa mode - SX1280 datasheet rev 3.2 section 14.4.1 if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { uint8_t data = 0; if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) { @@ -706,6 +706,15 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) { data = 0x32; } state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1); + RADIOLIB_ASSERT(state); + + // this register must also be updated for some reason + state = SX128x::readRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1); + RADIOLIB_ASSERT(state); + + data |= 0x01; + state = SX128x::writeRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1); + RADIOLIB_ASSERT(state); } return(state); From e98e7b724328debc563ad3b136026a1d50fca1f5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 5 Jul 2025 10:44:51 +0100 Subject: [PATCH 1577/1848] [Pager] Fix message buffer size calculation (#1535) --- src/protocols/Pager/Pager.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index e4615a5133..b3a14b1513 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -124,13 +124,8 @@ int16_t PagerClient::transmit(const uint8_t* data, size_t len, uint32_t addr, ui numDataBlocks += 1; } - // calculate number of batches - size_t numBatches = (1 + framePos + numDataBlocks) / RADIOLIB_PAGER_BATCH_LEN + 1; - if((1 + numDataBlocks) % RADIOLIB_PAGER_BATCH_LEN == 0) { - numBatches -= 1; - } - - // calculate message length in 32-bit code words + // calculate number of batches and message length in 32-bit code words + size_t numBatches = (framePos + numDataBlocks + RADIOLIB_PAGER_BATCH_LEN) / RADIOLIB_PAGER_BATCH_LEN; size_t msgLen = RADIOLIB_PAGER_PREAMBLE_LENGTH + (1 + RADIOLIB_PAGER_BATCH_LEN) * numBatches; #if RADIOLIB_STATIC_ONLY @@ -172,6 +167,7 @@ int16_t PagerClient::transmit(const uint8_t* data, size_t len, uint32_t addr, ui blockPos++; i++; } + RADIOLIB_DEBUG_PROTOCOL_PRINT("blockPos = %d\n", blockPos); // mark this as a message code word msg[blockPos] = RADIOLIB_PAGER_MESSAGE_CODE_WORD << (RADIOLIB_PAGER_CODE_WORD_LEN - 1); From d0db02e3358f0b39d8ba6d2f9097d31c063ee536 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 5 Jul 2025 10:45:26 +0100 Subject: [PATCH 1578/1848] [Pager] Fix missing method call in example --- examples/Pager/Pager_Transmit/Pager_Transmit.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/Pager/Pager_Transmit/Pager_Transmit.ino b/examples/Pager/Pager_Transmit/Pager_Transmit.ino index 3677fc781f..67846e866e 100644 --- a/examples/Pager/Pager_Transmit/Pager_Transmit.ino +++ b/examples/Pager/Pager_Transmit/Pager_Transmit.ino @@ -93,6 +93,8 @@ void loop() { delay(500); // we can also send only a tone + state |= pager.sendTone(1234567); + delay(500); if(state == RADIOLIB_ERR_NONE) { Serial.println(F("success!")); @@ -101,6 +103,6 @@ void loop() { Serial.println(state); } - // wait for a second before transmitting again + // wait for 3 seconds before transmitting again delay(3000); } From 6bc37af47fa760167fbd112d31419fb0f7286105 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 5 Jul 2025 20:55:32 +0200 Subject: [PATCH 1579/1848] [RF69] Remove hacky padding byte (#1552) --- src/modules/RF69/RF69.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 0b91e5a9a5..37fc990489 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -421,12 +421,6 @@ int16_t RF69::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { } this->mod->SPIwriteRegisterBurst(RADIOLIB_RF69_REG_FIFO, const_cast(data), packetLen); - // this is a hack, but it seems than in Stream mode, Rx FIFO level is getting triggered 1 byte before it should - // just add a padding byte that can be dropped without consequence - if(len > RADIOLIB_RF69_MAX_PACKET_LENGTH) { - this->mod->SPIwriteRegister(RADIOLIB_RF69_REG_FIFO, '/'); - } - // enable +20 dBm operation if(this->power > 17) { state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_OFF | 0x0F); From f6239d01c132f9b5dd1ef5495f539628e4b7bdce Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 6 Jul 2025 14:44:31 +0200 Subject: [PATCH 1580/1848] [CC1101] Fix discarded packets triggering data read (#1484) --- src/modules/CC1101/CC1101.cpp | 12 ++++++++---- src/modules/CC1101/CC1101.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index a086fa3ec9..20768ea911 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -261,7 +261,6 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // data put on FIFO uint8_t dataSent = 0; - uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); // optionally write packet length @@ -274,7 +273,6 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { } // check address filtering - //uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0); if(filter != RADIOLIB_CC1101_ADR_CHK_NONE) { SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, addr); dataSent += 1; @@ -343,8 +341,14 @@ int16_t CC1101::startReceive() { SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); // set GDO0 mapping - // GDO0 is de-asserted at packet end, hence it is inverted here - state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDO0_INV | RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 6, 0); + // this is the only interrupt source that works reliably + // RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED gets triggered by both packet received as well as packet discarded, + // RADIOLIB_CC1101_GDOX_PKT_RECEIVED_CRC_OK does not get triggered with CRC disabled + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END, 6, 0); + RADIOLIB_ASSERT(state); + + // set Rx FIFO threshold to the maximum Rx size + state = SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_1_RX_64, 3, 0); RADIOLIB_ASSERT(state); // set RF switch (if present) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index d85179d2c6..c710012123 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -183,6 +183,7 @@ #define RADIOLIB_CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB #define RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4 #define RADIOLIB_CC1101_FIFO_THR_TX_33_RX_32 0b00000111 // 3 0 TX fifo threshold: 33, RX fifo threshold: 32 +#define RADIOLIB_CC1101_FIFO_THR_TX_1_RX_64 0b00001111 // 3 0 TX fifo threshold: 1, RX fifo threshold: 64 #define RADIOLIB_CC1101_FIFO_THRESH_TX 33 #define RADIOLIB_CC1101_FIFO_THRESH_RX 32 From b91c6af112e423dcb14529ade5827802a14e1015 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 9 Jul 2025 19:57:26 +0200 Subject: [PATCH 1581/1848] Bump version to 7.2.1 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 4c41c600cb..dd0524c8e3 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.2.0" +version: "7.2.1" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 821d3ee17e..5b9c3f026a 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.2.0", + "version": "7.2.1", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index c5faa3dda6..aa817e81b9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.2.0 +version=7.2.1 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 66d24b1d03..03def78232 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -605,7 +605,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 #define RADIOLIB_VERSION_MINOR 2 -#define RADIOLIB_VERSION_PATCH 0 +#define RADIOLIB_VERSION_PATCH 1 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From 7fb07921bf4fb0ad6d84c4ae34e7aad1fa45603f Mon Sep 17 00:00:00 2001 From: Totoo Date: Tue, 15 Jul 2025 17:47:37 +0200 Subject: [PATCH 1582/1848] [PHY] Add a virtual destructor (#1557) * Update PhysicalLayer.h Add a virtual destructor, so can use new + delete on inherited objects * Update PhysicalLayer.h deleted empty lines --- src/protocols/PhysicalLayer/PhysicalLayer.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 8cb32a0deb..273bd61bbc 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -229,6 +229,11 @@ class PhysicalLayer { */ PhysicalLayer(); + /*! + \brief Default destructor. + */ + virtual ~PhysicalLayer() = default; + // basic methods #if defined(RADIOLIB_BUILD_ARDUINO) From 2c8000aa341b91b4a48ea6ebc72d455eeb4fa731 Mon Sep 17 00:00:00 2001 From: James Ashby Date: Fri, 18 Jul 2025 08:30:41 +0100 Subject: [PATCH 1583/1848] Modified the attachInterrupt function in PicoHal.h so that the mode argument is passed into the events argument of gpio_set_irq_enabled_with_callback. Previosly this used hard coded values that caused spurious (extra) interrupts. --- src/hal/RPiPico/PicoHal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hal/RPiPico/PicoHal.h b/src/hal/RPiPico/PicoHal.h index dfa06f1c93..7cb6025e7c 100644 --- a/src/hal/RPiPico/PicoHal.h +++ b/src/hal/RPiPico/PicoHal.h @@ -69,7 +69,7 @@ class PicoHal : public RadioLibHal { return; } - gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)interruptCb); + gpio_set_irq_enabled_with_callback(interruptNum, mode, true, (gpio_irq_callback_t)interruptCb); } void detachInterrupt(uint32_t interruptNum) override { @@ -77,7 +77,7 @@ class PicoHal : public RadioLibHal { return; } - gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL); + gpio_set_irq_enabled_with_callback(interruptNum, 0, false, NULL); } void delay(unsigned long ms) override { From d05dbf07d12cb3a953bc13238f97ebc271b4f517 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 20 Jul 2025 11:40:32 +0200 Subject: [PATCH 1584/1848] [SX126x] Add missing state assert (#1561) --- src/modules/SX126x/SX126x.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 5291c0137d..cdeaaf761d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -616,6 +616,7 @@ int16_t SX126x::startReceiveCommon(uint32_t timeout, RadioLibIrqFlags_t irqFlags // clear interrupt flags state = clearIrqStatus(); + RADIOLIB_ASSERT(state); // restore original packet length uint8_t modem = getPacketType(); From 1dfd194c9ce9bae456c09e774767b810b32951e0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 21 Jul 2025 07:03:15 +0200 Subject: [PATCH 1585/1848] [HAL] Fix RPiPico detach interrupt (#1558) --- src/hal/RPiPico/PicoHal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/RPiPico/PicoHal.h b/src/hal/RPiPico/PicoHal.h index 7cb6025e7c..8329707de0 100644 --- a/src/hal/RPiPico/PicoHal.h +++ b/src/hal/RPiPico/PicoHal.h @@ -77,7 +77,7 @@ class PicoHal : public RadioLibHal { return; } - gpio_set_irq_enabled_with_callback(interruptNum, 0, false, NULL); + gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL); } void delay(unsigned long ms) override { From 910403c5313e376656171c9d8f3971da1dbf1736 Mon Sep 17 00:00:00 2001 From: Tiaan-Alberts Date: Mon, 11 Aug 2025 10:32:02 +0200 Subject: [PATCH 1586/1848] Fix overload-virtual errors --- src/modules/CC1101/CC1101.cpp | 7 +++++++ src/modules/CC1101/CC1101.h | 15 +++++++++++++++ src/modules/RF69/RF69.cpp | 2 +- src/modules/RF69/RF69.h | 2 +- src/modules/SX128x/SX128x.cpp | 2 +- src/modules/SX128x/SX128x.h | 2 +- src/modules/Si443x/Si443x.cpp | 2 +- src/modules/Si443x/Si443x.h | 2 +- 8 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 20768ea911..072157be38 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -662,6 +662,10 @@ int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) { return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); } +int16_t CC1101::setSyncWord(uint8_t* sync, size_t len) { + return this->setSyncWord(sync, len, 0, false); +} + int16_t CC1101::setSyncWord(const uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) { if((maxErrBits > 1) || (len != 2)) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); @@ -690,6 +694,9 @@ int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bo return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits, requireCarrierSense)); } +int16_t CC1101::setPreambleLength(size_t len) { + return this->setPreambleLength(len, 7*4); +} int16_t CC1101::setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold) { // check allowed values uint8_t value; diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index c710012123..37226aa089 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -826,6 +826,14 @@ class CC1101: public PhysicalLayer { */ int16_t checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw); + /*! + \brief Set 1 or 2 bytes of sync word. + \param sync Pointer to the sync word. + \param len Sync word length in bytes. Maximum length depends on the module used. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* sync, size_t len); + /*! \brief Sets 16-bit sync word as a two byte value. \param syncH MSB of the sync word. @@ -846,6 +854,13 @@ class CC1101: public PhysicalLayer { */ int16_t setSyncWord(const uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false); + /*! + \brief Sets preamble length. + \param len Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. + \returns \ref status_codes + */ + int16_t setPreambleLength(size_t len); + /*! \brief Sets preamble length. \param preambleLength Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 37fc990489..72b3b9b233 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -713,7 +713,7 @@ int16_t RF69::setSyncWord(const uint8_t* syncWord, size_t len, uint8_t maxErrBit return(state); } -int16_t RF69::setPreambleLength(uint8_t preambleLen) { +int16_t RF69::setPreambleLength(size_t preambleLen) { // RF69 configures preamble length in bytes if(preambleLen % 8 != 0) { return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index daaea43381..14fdc62427 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -796,7 +796,7 @@ class RF69: public PhysicalLayer { \param preambleLen Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. \returns \ref status_codes */ - int16_t setPreambleLength(uint8_t preambleLen); + int16_t setPreambleLength(size_t preambleLen); /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index c4167ee3e6..5a8c9a1daa 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -793,7 +793,7 @@ int16_t SX128x::getModem(ModemType_t* modem) { return(RADIOLIB_ERR_WRONG_MODEM); } -int16_t SX128x::setPreambleLength(uint32_t preambleLength) { +int16_t SX128x::setPreambleLength(size_t preambleLength) { uint8_t modem = getPacketType(); if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // LoRa or ranging diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 0fe91a4b1f..7b8e7cdf3e 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -669,7 +669,7 @@ class SX128x: public PhysicalLayer { \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC). \returns \ref status_codes */ - int16_t setPreambleLength(uint32_t preambleLength); + int16_t setPreambleLength(size_t preambleLength); /*! \brief Set data rate. diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index b121635a6e..4eb32e3457 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -533,7 +533,7 @@ int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { return(state); } -int16_t Si443x::setPreambleLength(uint8_t preambleLen) { +int16_t Si443x::setPreambleLength(size_t preambleLen) { // Si443x configures preamble length in 4-bit nibbles if(preambleLen % 4 != 0) { return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index a5e843ddd1..64403860e6 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -752,7 +752,7 @@ class Si443x: public PhysicalLayer { \param preambleLen Preamble length to be set (in bits). \returns \ref status_codes */ - int16_t setPreambleLength(uint8_t preambleLen); + int16_t setPreambleLength(size_t preambleLen); /*! \brief Query modem for the packet length of received payload. From 8e3bb5992c8308145dec49ae540c60c702ab706c Mon Sep 17 00:00:00 2001 From: Tiaan-Alberts Date: Mon, 11 Aug 2025 19:09:17 +0200 Subject: [PATCH 1587/1848] Fix static analysis failure --- src/modules/CC1101/CC1101.h | 4 ++-- src/modules/RF69/RF69.h | 2 +- src/modules/SX128x/SX128x.h | 2 +- src/modules/Si443x/Si443x.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 37226aa089..8dd68bea84 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -832,7 +832,7 @@ class CC1101: public PhysicalLayer { \param len Sync word length in bytes. Maximum length depends on the module used. \returns \ref status_codes */ - int16_t setSyncWord(uint8_t* sync, size_t len); + int16_t setSyncWord(uint8_t *sync, size_t len) override; /*! \brief Sets 16-bit sync word as a two byte value. @@ -859,7 +859,7 @@ class CC1101: public PhysicalLayer { \param len Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. \returns \ref status_codes */ - int16_t setPreambleLength(size_t len); + int16_t setPreambleLength(size_t len) override; /*! \brief Sets preamble length. diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 14fdc62427..86ef9303c7 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -796,7 +796,7 @@ class RF69: public PhysicalLayer { \param preambleLen Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. \returns \ref status_codes */ - int16_t setPreambleLength(size_t preambleLen); + int16_t setPreambleLength(size_t preambleLen) override; /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 7b8e7cdf3e..6c35f49832 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -669,7 +669,7 @@ class SX128x: public PhysicalLayer { \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC). \returns \ref status_codes */ - int16_t setPreambleLength(size_t preambleLength); + int16_t setPreambleLength(size_t preambleLength) override; /*! \brief Set data rate. diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 64403860e6..286c9937ac 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -752,7 +752,7 @@ class Si443x: public PhysicalLayer { \param preambleLen Preamble length to be set (in bits). \returns \ref status_codes */ - int16_t setPreambleLength(size_t preambleLen); + int16_t setPreambleLength(size_t preambleLen) override; /*! \brief Query modem for the packet length of received payload. From 388779d678c43d25aaa72624a40bb12ade920113 Mon Sep 17 00:00:00 2001 From: Tiaan-Alberts Date: Tue, 12 Aug 2025 08:26:32 +0200 Subject: [PATCH 1588/1848] restore CC1101:begin behaviour for setPreambleLength(size_t len) from 7*4 to len-4 --- src/modules/CC1101/CC1101.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 072157be38..bd89c706f2 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -695,7 +695,7 @@ int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bo } int16_t CC1101::setPreambleLength(size_t len) { - return this->setPreambleLength(len, 7*4); + return this->setPreambleLength(len, len-4); } int16_t CC1101::setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold) { // check allowed values From e47f1e20afbc255d0fe9b50ba3793817c21d022a Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 21 Aug 2025 18:39:36 +0200 Subject: [PATCH 1589/1848] [SX127x] Clarify FSK FIFO size is due to hardware (#1578) --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 59d5cb2cf3..37135f98e4 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -12,7 +12,7 @@ // SX127x physical layer properties #define RADIOLIB_SX127X_FREQUENCY_STEP_SIZE 61.03515625 #define RADIOLIB_SX127X_MAX_PACKET_LENGTH 255 -#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 +#define RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK 64 // as per datasheet Rev. 7, page 66, the FSK FIFO is just 64 bytes #define RADIOLIB_SX127X_CRYSTAL_FREQ 32.0f #define RADIOLIB_SX127X_DIV_EXPONENT 19 From 3d94858f368adea0759aebabbb58f044c228676c Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sun, 24 Aug 2025 20:21:53 +0200 Subject: [PATCH 1590/1848] [LoRaWAN] Channel improvements (#1573) * [LoRaWAN] Improve channel management * [LoRaWAN] Fixes for fixed bands * [LoRaWAN] Resolve CI feedback * Potential fix for code scanning alert no. 35: Comparison of narrow type with wide type in loop condition Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * [LoRaWAN] Fix pRNG seed * [LoRaWAN] Restore channel masks and flags within and outside of sessions * [LoRaWAN] Remove debug output * [LoRaWAN] Fully persistent channel management * [LoRaWAN] Update Nonces buffer version --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- src/protocols/LoRaWAN/LoRaWAN.cpp | 916 ++++++++++++------------- src/protocols/LoRaWAN/LoRaWAN.h | 108 ++- src/protocols/LoRaWAN/LoRaWANBands.cpp | 118 ++-- 3 files changed, 538 insertions(+), 604 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index fa6a25b515..440d7f48c0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -9,11 +9,8 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band, uint8_t subBand) { this->phyLayer = phy; this->band = band; - this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; - this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; - this->txPowerMax = this->band->powerMax; this->subBand = subBand; - memset(this->channelPlan, 0, sizeof(this->channelPlan)); + memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels)); for(int i = 0; i < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; i++) { this->packages[i] = RADIOLIB_LORAWAN_PACKAGE_NONE; } @@ -137,7 +134,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // number of additional CAD tries uint8_t numBackoff = 0; if(this->backoffMax) { - numBackoff = this->phyLayer->random(1, this->backoffMax + 1); + numBackoff = 1 + rand() % this->backoffMax; } do { @@ -173,8 +170,9 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4) // must be present after any confirmed frame, so we force this here if(isConfirmed) { - this->sleepDelay(this->phyLayer->random(RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS, - RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS)); + int min = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS; + int max = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS; + this->sleepDelay(min + rand() % (max - min)); } // if an error occured or a downlink was received, stop retransmission @@ -250,8 +248,7 @@ void LoRaWANNode::clearNonces() { this->keyCheckSum = 0; this->devNonce = 0; this->joinNonce = 0; - this->isActive = false; - this->rev = 0; + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE; } uint8_t* LoRaWANNode::getBufferNonces() { @@ -274,6 +271,12 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) { return(RADIOLIB_ERR_NONE); } + // // this code can be used in case breaking chances must be caught: + // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; + // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { + // // set default values for variables that are new or something + // } + int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); RADIOLIB_ASSERT(state); @@ -296,10 +299,6 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) { this->devNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); this->joinNonce = LoRaWANNode::ntoh(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); - // revert to inactive as long as no session is restored - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; - this->isActive = false; - return(state); } @@ -307,8 +306,6 @@ void LoRaWANNode::clearSession() { memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false; - this->isActive = false; // reset all frame counters this->fCntUp = 0; @@ -318,9 +315,8 @@ void LoRaWANNode::clearSession() { this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; - // reset ADR state - this->txPowerSteps = 0; - this->nbTrans = 1; + // set Tx power limit + this->txPowerMax = this->band->powerMax; // clear CSMA settings this->csmaEnabled = false; @@ -330,61 +326,49 @@ void LoRaWANNode::clearSession() { // revert to default Class A this->lwClass = RADIOLIB_LORAWAN_CLASS_A; -} -void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { - this->clearSession(); + // set a seed for the pseudo-rng using a truly random value from radio noise + srand(this->phyLayer->random(INT32_MAX)); - // setup the default channels - this->addDefaultChannels(); + // reset all channels + memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels)); - uint8_t drUp = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + // reset Rx2 channel to default value + this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; - // on fixed bands, the first OTAA uplink (JoinRequest) is sent on fixed datarate - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && lwMode == RADIOLIB_LORAWAN_MODE_OTAA) { - // randomly select one of 8 or 9 channels and find corresponding datarate - uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; - uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 - if(rand <= 8) { - drUp = this->band->txSpans[0].drJoinRequest; // if one of the first 8 channels, select datarate of span 0 - } else { - drUp = this->band->txSpans[1].drJoinRequest; // if ninth channel, select datarate of span 1 - } - } else { - // on dynamic bands, the first OTAA uplink (JoinRequest) can be any available datarate - // this is also true for ABP on both dynamic and fixed bands, as there is no JoinRequest - if(initialDr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - uint8_t i = 0; - for(; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { - if(initialDr >= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin - && initialDr <= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax) { - drUp = initialDr; - break; - } - } - } - // if there is no channel that allowed the user-specified datarate, revert to default datarate - if(i == RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Datarate %d is not valid - using default", initialDr); - initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE; +} + +void LoRaWANNode::createSession() { + // setup default channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(int num = 0; num < 3; num++) { + if(this->band->txFreqs[num].freq) { + // copy the channels from the current channel plan + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; + this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; } } - - // if there is no (channel that allowed the) user-specified datarate, use a default datarate - if(initialDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - // use the specified datarate from the first channel (this is always defined) - drUp = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][0].dr; - } } + this->enableDefaultChannels(); + // set default MAC state + + // set data rate and Tx power uint8_t cOcts[5]; // 5 = maximum downlink payload length uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; uint8_t cLen = 1; // only apply Dr/Tx field - cOcts[0] = (drUp << 4); // set uplink datarate - cOcts[0] |= 0; // default to max Tx Power + uint8_t drUp; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax + 1) / 2; + } else { // RADIOLIB_LORAWAN_BAND_FIXED + drUp = (this->band->txSpans[0].drMin + this->band->txSpans[0].drMin + 1) / 2; + } + cOcts[0] = (drUp << 4); // set requested datarate + cOcts[0] |= 0x00; // set maximum Tx power (void)execMacCommand(cid, cOcts, cLen); + // set maximum dutycycle cid = RADIOLIB_LORAWAN_MAC_DUTY_CYCLE; this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); uint8_t maxDCyclePower = 0; @@ -399,18 +383,21 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { cOcts[0] = maxDCyclePower; (void)execMacCommand(cid, cOcts, cLen); + // set Rx2 frequency and datarate cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); - cOcts[0] |= this->channels[RADIOLIB_LORAWAN_RX2].dr; // may be set by user, otherwise band's default upon initialization - LoRaWANNode::hton(&cOcts[1], this->channels[RADIOLIB_LORAWAN_RX2].freq, 3); + cOcts[0] |= this->channels[RADIOLIB_LORAWAN_RX2].dr; // user may override the Rx2 datarate + LoRaWANNode::hton(&cOcts[1], this->band->rx2.freq, 3); (void)execMacCommand(cid, cOcts, cLen); + // set Rx1 and Rx2 delay cid = RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = (RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS / 1000); (void)execMacCommand(cid, cOcts, cLen); + // set dwelltime and maximum Tx power cid = RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = (this->band->dwellTimeDn > 0 ? 1 : 0) << 5; @@ -439,17 +426,22 @@ void LoRaWANNode::createSession(uint16_t lwMode, uint8_t initialDr) { cOcts[0] |= maxEIRPRaw; (void)execMacCommand(cid, cOcts, cLen); + // set ADR backoff parameters cid = RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = (RADIOLIB_LORAWAN_ADR_ACK_LIMIT_EXP << 4); cOcts[0] |= RADIOLIB_LORAWAN_ADR_ACK_DELAY_EXP; (void)execMacCommand(cid, cOcts, cLen); + // set Rejoin parameters cid = RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); cOcts[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); cOcts[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; (void)execMacCommand(cid, cOcts, cLen); + + // set up a new session, ready for activation + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVATING; } uint8_t* LoRaWANNode::getBufferSession() { @@ -461,23 +453,18 @@ uint8_t* LoRaWANNode::getBufferSession() { LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT], this->adrFCnt); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS], this->lwClass); - - // store the enabled channels - uint64_t chMaskGrp0123 = 0; - uint32_t chMaskGrp45 = 0; - this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, chMaskGrp0123); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 9, chMaskGrp45); - - // store the available/unused channels - uint16_t chMask = 0x0000; - (void)this->getAvailableChannels(&chMask); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], chMask); - + // store the current uplink MAC command queue memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], this->fOptsUp, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], &this->fOptsUpLen, 1); + // store the channel masks and unused channel flags + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, this->channelMasks, sizeof(this->channelMasks)); + memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], this->channelFlags, sizeof(this->channelFlags)); + + // store the session status + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_STATUS], this->sessionStatus); + // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); @@ -506,38 +493,21 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { // copy the whole buffer over memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); - //// this code can be used in case breaking chances must be caught: - // uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION]; - // if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) { - // // set default values for variables that are new or something - // } - - // pull all authentication keys from persistent storage - this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); - memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); - memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); - - // restore session parameters - this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); - this->lwClass = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS]); - this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); - this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); - this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); - this->confFCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); - this->confFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); - this->adrFCnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); - this->fCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); - - // restore the complete MAC state + // setup the default channels + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(int num = 0; num < 3; num++) { + if(this->band->txFreqs[num].freq) { + // copy the channels from the current channel plan + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; + this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; + } + } + } + this->enableDefaultChannels(); uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size uint8_t cid; - uint8_t cLen = 0; - - // setup the default channels - this->addDefaultChannels(); + uint8_t cLen; // for dynamic bands, the additional channels must be restored per-channel if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { @@ -549,7 +519,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; i++) { memcpy(cOcts, startChannelsUp + (i * cLen), cLen); if(memcmp(cOcts, bufferZeroes, cLen) != 0) { // only execute if it is not all zeroes (void)execMacCommand(cid, cOcts, cLen); @@ -560,7 +530,7 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { cid = RADIOLIB_LORAWAN_MAC_DL_CHANNEL; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; i++) { memcpy(cOcts, startChannelsDown + (i * cLen), cLen); if(memcmp(cOcts, bufferZeroes, cLen) != 0) { // only execute if it is not all zeroes (void)execMacCommand(cid, cOcts, cLen); @@ -568,40 +538,64 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) { } } - // restore the MAC state - ADR needs special care, the rest is straight default + // restore the datarate and channels cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cLen = 14; // special internal ADR command + cLen = 14; // only apply Dr/Tx field memcpy(cOcts, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cLen); (void)execMacCommand(cid, cOcts, cLen); + // always restore the channels, so as to adhere to channel hopping between JoinRequests + memcpy(this->channelFlags, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS); + + // restore the session status + this->sessionStatus = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_STATUS]); + + // check if the session is active, if not, don't restore anything else + if(this->sessionStatus != RADIOLIB_LORAWAN_SESSION_ACTIVE) { + return(RADIOLIB_ERR_NETWORK_NOT_JOINED); + } + + // restore the rest of the MAC state const uint8_t cids[6] = { RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP }; - const uint16_t locs[6] = { RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE, RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP, RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP }; - for(uint8_t i = 0; i < 6; i++) { (void)this->getMacLen(cids[i], &cLen, RADIOLIB_LORAWAN_DOWNLINK); memcpy(cOcts, &this->bufferSession[locs[i]], cLen); (void)execMacCommand(cids[i], cOcts, cLen); } - // set the available channels - uint16_t chMask = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS]); - this->setAvailableChannels(chMask); - // copy uplink MAC command queue back in place memcpy(this->fOptsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memcpy(&this->fOptsUpLen, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], 1); + // restore authentication keys + this->devAddr = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]); + memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE); + + // restore session parameters + this->rev = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]); + this->lwClass = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS]); + this->homeNetId = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]); + this->aFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]); + this->nFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]); + this->confFCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]); + this->confFCntDown = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]); + this->adrFCnt = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]); + this->fCntUp = LoRaWANNode::ntoh(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]); + // as both the Nonces and session are restored, revert to active session - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_PENDING; return(state); } @@ -610,8 +604,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, const uint8_t* if(!appKey) { return(RADIOLIB_ERR_NULL_POINTER); } - // clear all the device credentials in case there were any + // clear all the device parameters in case there were any this->clearNonces(); + this->clearSession(); this->joinEUI = joinEUI; this->devEUI = devEUI; @@ -638,8 +633,9 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const u if(!nwkSEncKey || !appSKey) { return(RADIOLIB_ERR_NULL_POINTER); } - // clear all the device credentials in case there were any + // clear all the device parameters in case there were any this->clearNonces(); + this->clearSession(); this->devAddr = addr; memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); @@ -662,10 +658,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const u this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; - if(this->rev == 1) { - LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); - } - return(RADIOLIB_ERR_NONE); } @@ -858,27 +850,17 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; - - // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer - // also store this signature in the Session buffer to make sure these buffers match - uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); - LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); - LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); - // store DevAddr and all keys LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], this->nwkSEncKey, RADIOLIB_AES128_KEY_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE); - + // store network parameters LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); - this->isActive = true; - // received JoinAccept, so update JoinNonce value in event if(joinEvent) { joinEvent->joinNonce = this->joinNonce; @@ -887,18 +869,30 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) { return(state); } -int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) { +int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) { + // only allow OTAA mode + if(this->lwMode != RADIOLIB_LORAWAN_MODE_OTAA) { + return(RADIOLIB_ERR_INVALID_MODE); + } + // check if there is an active session if(this->isActivated()) { // already activated, don't do anything return(RADIOLIB_ERR_NONE); } - if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) { + + // check if there is a restored session + if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_PENDING) { // session restored but not yet activated - do so now - this->isActive = true; + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE; return(RADIOLIB_LORAWAN_SESSION_RESTORED); } + // if there is no session, reset everything to defaults + if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_NONE) { + this->createSession(); + } + // starting a new session, so make sure to update event fields already if(joinEvent) { joinEvent->newSession = true; @@ -906,9 +900,6 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) joinEvent->joinNonce = this->joinNonce; } - // setup all MAC properties to default values - this->createSession(RADIOLIB_LORAWAN_MODE_OTAA, joinDr); - // build the JoinRequest message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; this->composeJoinRequest(joinRequestMsg); @@ -929,6 +920,12 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) this->devNonce += 1; LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE], this->devNonce); + // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer + // also store this signature in the Session buffer to make sure these buffers match + uint16_t signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); + // configure Rx1 and Rx2 delay for JoinAccept message - these are re-configured once a valid JoinAccept is received this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; this->rxDelays[2] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; @@ -945,26 +942,41 @@ int16_t LoRaWANNode::activateOTAA(uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) state = this->processJoinAccept(joinEvent); RADIOLIB_ASSERT(state); + // regenerate the Nonces signature as we received new Nonces in the JoinAccept + signature = LoRaWANNode::checkSum16(this->bufferNonces, RADIOLIB_LORAWAN_NONCES_BUF_SIZE - 2); + LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); + LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); + + (void)this->calculateChannelFlags(); + + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE; + return(RADIOLIB_LORAWAN_NEW_SESSION); } -int16_t LoRaWANNode::activateABP(uint8_t initialDr) { +int16_t LoRaWANNode::activateABP() { + // only allow ABP mode + if(this->lwMode != RADIOLIB_LORAWAN_MODE_ABP) { + return(RADIOLIB_ERR_INVALID_MODE); + } + // check if there is an active session if(this->isActivated()) { // already activated, don't do anything return(RADIOLIB_ERR_NONE); } - if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) { + + // check if there is a restored session + if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_PENDING) { // session restored but not yet activated - do so now - this->isActive = true; + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE; return(RADIOLIB_LORAWAN_SESSION_RESTORED); } - // setup all MAC properties to default values - this->createSession(RADIOLIB_LORAWAN_MODE_ABP, initialDr); - - // new session all good, so set active-bit to true - this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; + // if there is no session, reset everything to defaults + if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_NONE) { + this->createSession(); + } // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer // also store this signature in the Session buffer to make sure these buffers match @@ -983,7 +995,11 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); - this->isActive = true; + if(this->rev == 1) { + LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK); + } + + this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE; return(RADIOLIB_LORAWAN_NEW_SESSION); } @@ -991,20 +1007,20 @@ int16_t LoRaWANNode::activateABP(uint8_t initialDr) { void LoRaWANNode::processCFList(const uint8_t* cfList) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Processing CFList"); - uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size + uint8_t cOcts[14] = { 0 }; // see Wiki for special length uint8_t cid; uint8_t cLen = 0; - + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // retrieve number of existing (default) channels + // retrieve number of default channels size_t num = 0; - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(!this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { + for(int i = 0; i < 3; i++) { + if(this->band->txFreqs[i].freq == 0) { break; } num++; } - + cid = RADIOLIB_LORAWAN_MAC_NEW_CHANNEL; (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); @@ -1022,24 +1038,20 @@ void LoRaWANNode::processCFList(const uint8_t* cfList) { (void)execMacCommand(cid, cOcts, cLen); } } else { // RADIOLIB_LORAWAN_BAND_FIXED - // complete channel mask received, so clear all existing channels - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i] = RADIOLIB_LORAWAN_CHANNEL_NONE; - } - - // copy channel mask straight over to LinkAdr MAC command + // apply channel mask cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - cLen = 14; // special internal ADR length - cOcts[0] = 0xFF; // same datarate and cOcts - memcpy(&cOcts[1], cfList, 12); // copy mask - cOcts[13] = 0; // set NbTrans = 0 -> keep the same + cLen = 14; + cOcts[0] = 0xF0; // keep datarate the same + cOcts[0] |= 0x0F; // keep Tx Power the same + cOcts[13] = 0x01; // default NbTrans = 1 + memcpy(&cOcts[1], cfList, sizeof(this->channelMasks)); (void)execMacCommand(cid, cOcts, cLen); } } bool LoRaWANNode::isActivated() { - return(this->isActive); + return(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_ACTIVE); } int16_t LoRaWANNode::setClass(uint8_t cls) { @@ -1215,7 +1227,7 @@ void LoRaWANNode::adrBackoff() { } // last resort: enable all (default) channels - this->addDefaultChannels(); + this->enableDefaultChannels(); // re-enabling default channels may have enabled channels that do support // the next required datarate; if datarate can be decreased, try it @@ -2223,25 +2235,33 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin uint8_t pwrAck = 0; // first, get current configuration - uint64_t chMaskGrp0123 = 0; - uint32_t chMaskGrp45 = 0; - this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - uint16_t chMaskActive = 0; - (void)this->getAvailableChannels(&chMaskActive); + uint16_t currentMasks[RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16]; + uint16_t currentFlags[RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16]; + memcpy(currentMasks, this->channelMasks, sizeof(this->channelMasks)); + memcpy(currentFlags, this->channelFlags, sizeof(this->channelFlags)); uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; // only apply channel mask if present (internal Dr/Tx commands do not set channel mask) + chMaskAck = true; if(lenIn > 1) { - uint64_t macChMaskGrp0123 = LoRaWANNode::ntoh(&optIn[1]); - uint32_t macChMaskGrp45 = LoRaWANNode::ntoh(&optIn[9]); - // apply requested channel mask and enable all of them for testing datarate - chMaskAck = this->applyChannelMask(macChMaskGrp0123, macChMaskGrp45); - } else { - chMaskAck = true; + this->enableDefaultChannels(true); + for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16; i++) { + uint16_t m8 = (uint16_t)optIn[1 + 2*i] | ((uint16_t)optIn[2 + 2*i] << 8); + uint16_t m16 = this->channelMasks[i]; + + // If m8 has a bit that m16 doesn't have, it will show up here + uint16_t diff = m8 & ~m16; + + if(diff) { + chMaskAck = false; + break; // found one, no need to check further + } + + // save new mask already, will revert if a rejection occurs + this->channelMasks[i] = m8; + } } - this->setAvailableChannels(0xFFFF); - int16_t state; // try to apply the datarate configuration @@ -2250,7 +2270,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin macDrUp = currentDr; } - if (this->band->dataRates[macDrUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->band->dataRates[macDrUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { // check if the module supports this data rate DataRate_t dr; state = this->findDataRate(macDrUp, &dr); @@ -2259,17 +2279,14 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // and check if there are any available Tx channels for this datarate if(state == RADIOLIB_ERR_NONE) { this->channels[RADIOLIB_LORAWAN_UPLINK].dr = macDrUp; + drAck = this->calculateChannelFlags(); - // only if we have available Tx channels, we set an Ack - if(this->getAvailableChannels(NULL) > 0) { - drAck = 1; - } else { + if(!drAck) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR: no channels available for datarate %d", macDrUp); } } else { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR: hardware failure configurating datarate %d, code %d", macDrUp, state); } - } // try to apply the power configuration @@ -2300,10 +2317,11 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin if(optOut[0] != 0x07) { // according to paragraph 4.3.1.1, if ADR is disabled, // the ADR channel mask must be accepted even if drAck/pwrAck fails. - // therefore, only revert the channel mask if ADR is enabled. + // therefore, only revert the channel masks/flags if ADR is enabled. if(this->adrEnabled) { - this->applyChannelMask(chMaskGrp0123, chMaskGrp45); - this->setAvailableChannels(chMaskActive); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Reverting to previous channel masks"); + memcpy(this->channelMasks, currentMasks, sizeof(this->channelMasks)); + memcpy(this->channelFlags, currentFlags, sizeof(this->channelFlags)); } // revert datarate this->channels[RADIOLIB_LORAWAN_UPLINK].dr = currentDr; @@ -2328,12 +2346,8 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // for LoRaWAN v1.1, if NbTrans == 0, the end-device SHALL keep the current NbTrans value unchanged // so, don't do anything } - } - // restore original active channels - this->setAvailableChannels(chMaskActive); - // save to the ADR MAC location // but first re-set the Dr/Tx/NbTrans field to make sure they're not set to 0xF optIn[0] = (this->channels[RADIOLIB_LORAWAN_UPLINK].dr) << 4; @@ -2433,12 +2447,15 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin uint8_t macDrMax = (optIn[4] & 0xF0) >> 4; uint8_t macDrMin = optIn[4] & 0x0F; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq: index = %d, freq = %7.3f MHz, DR %d-%d", + macChIndex, macFreq / 10000.0, macDrMin, macDrMax); + uint8_t drAck = 0; uint8_t freqAck = 0; // the default channels shall not be modified, so check if this is a default channel // if the channel index is set, this channel is defined, so return a NACK - if(macChIndex < 3 && this->band->txFreqs[macChIndex].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { + if(macChIndex < 3 && this->band->txFreqs[macChIndex].freq > 0) { optOut[0] = 0; return(true); } @@ -2471,34 +2488,25 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // ACK successful, so apply and save if(macFreq > 0) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].enabled = true; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].idx = macChIndex; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq = macFreq; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMin = macDrMin; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMax = macDrMax; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].available = true; + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].idx = macChIndex; + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq = macFreq; + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMin = macDrMin; + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMax = macDrMax; // downlink channel is identical to uplink channel - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex]; + this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex]; + + // add the new channel + this->channelMasks[0] |= (0x0001 << macChIndex); + this->channelFlags[0] |= (0x0001 << macChIndex); } else { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; + this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; + this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; + // remove this channel + this->channelMasks[0] &= ~(0x0001 << macChIndex); + this->channelFlags[0] &= ~(0x0001 << macChIndex); } - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].idx, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].enabled, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq / 10000.0, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMin, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMax, - - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].idx, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].enabled, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].freq / 10000.0, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].drMin, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].drMax - ); - memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + macChIndex * lenIn, optIn, lenIn); return(true); @@ -2525,7 +2533,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin } // check if the corresponding uplink frequency is actually set - if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq > 0) { + if(this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq > 0) { freqUlAck = 1; } @@ -2538,7 +2546,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin } // ACK successful, so apply and save - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].freq = macFreq; + this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].freq = macFreq; memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DL_CHANNELS] + macChIndex * lenIn, optIn, lenIn); @@ -2687,14 +2695,12 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd uint8_t fLen = 5; // single ADR command is 5 bytes uint8_t numOpts = cLen / fLen; - // get the current channel plan mask - uint64_t chMaskGrp0123 = 0; - uint32_t chMaskGrp45 = 0; - this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - // set Dr/Tx field from last MAC command mAdrOpt[0] = mPtr[cLen - fLen + 1]; + uint16_t adrMasks[RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS / 2]; + memcpy(adrMasks, this->channelMasks, sizeof(this->channelMasks)); + // set NbTrans partial field from last MAC command mAdrOpt[13] = mPtr[cLen - fLen + 4] & 0x0F; @@ -2706,61 +2712,67 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd case 1: case 2: case 3: - // clear the target 16-bit block - chMaskGrp0123 &= ~((uint64_t)0xFFFF << (16 * chMaskCntl)); - // set the new 16-bit value in that block - chMaskGrp0123 |= (uint64_t)chMask << (16 * chMaskCntl); - break; case 4: - // clear the target 16-bit block - chMaskGrp45 &= ~((uint32_t)0xFFFF); // set the new 16-bit value in that block - chMaskGrp45 |= (uint32_t)chMask; + adrMasks[chMaskCntl] = chMask; break; case 5: // for CN470, this is just a normal channel mask - // for all other bands, the first 10 bits enable banks of 8 125kHz channels if(this->band->bandNum == BandCN470) { - chMaskGrp45 &= ~((uint32_t)0xFFFF << 16); - chMaskGrp45 |= (uint32_t)chMask << 16; + // set the new 16-bit value in that block + adrMasks[chMaskCntl] = chMask; + + // for all other bands, the first 10 bits enable banks of 8 125kHz channels } else { - int bank = 0; - for(; bank < 8; bank++) { - chMaskGrp0123 &= ~((uint64_t)0xFF << (8 * bank)); + for(int bank = 0; bank < 10; bank++) { if(chMask & ((uint16_t)1 << bank)) { - chMaskGrp0123 |= ((uint64_t)0xFF << (8 * bank)); - } - } - for(; bank < 10; bank++) { - chMaskGrp45 &= ~((uint32_t)0xFF << (8 * (bank - 8))); - if(chMask & ((uint16_t)1 << bank)) { - chMaskGrp45 |= ((uint32_t)0xFF << (8 * (bank - 8))); + // add bank of 8 125kHz channels + uint8_t bank16 = bank / 2; + uint16_t mask16 = 0x00FF << 8 * (bank % 2); + adrMasks[bank16] |= mask16; + // for banks 0 to 7, also add the corresponding 500 kHz channel + if(bank < 8) { + adrMasks[5] |= 0x0001 << bank; + } } } } break; case 6: // for dynamic bands: all channels ON (that are currently defined) + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; i++) { + if(this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][i].freq > 0) { + adrMasks[0] |= (0x0001 << i); + } + } + } // for fixed bands: all default 125kHz channels ON, channel mask similar to ChMask = 4 // except for CN470: all default 125kHz channels ON - - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN470) { - chMaskGrp45 &= ~((uint32_t)0xFFFF); - chMaskGrp45 |= (uint32_t)chMask; + else if(this->band->bandNum != BandCN470) { + for(int cnt = 0; cnt < 4; cnt++) { + adrMasks[cnt] = 0xFFFF; + } + adrMasks[chMaskCntl] = chMask; + } else { // BandCN470 + for(int cnt = 0; cnt < 5; cnt++) { + adrMasks[cnt] = 0xFFFF; + } } break; case 7: - // for fixed bands: all 125kHz channels ON, channel mask similar to ChMask = 4 + // for fixed bands: all 125kHz channels OFF, channel mask similar to ChMask = 4 // except for CN470: RFU if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN470) { - chMaskGrp0123 = 0; - chMaskGrp45 |= (uint32_t)chMask; + for(int cnt = 0; cnt < 4; cnt++) { + adrMasks[cnt] = 0x0000; + } + adrMasks[chMaskCntl] = chMask; } break; } } - LoRaWANNode::hton(&mAdrOpt[1], chMaskGrp0123); - LoRaWANNode::hton(&mAdrOpt[9], chMaskGrp45); + memcpy(&mAdrOpt[1], adrMasks, sizeof(adrMasks)); } void LoRaWANNode::postprocessMacLinkAdr(uint8_t* ack, uint8_t cLen) { @@ -2983,22 +2995,6 @@ void LoRaWANNode::clearMacCommands(uint8_t* inOut, uint8_t* lenInOut, uint8_t di } int16_t LoRaWANNode::setDatarate(uint8_t drUp) { - // scan through all enabled channels and check if the requested datarate is available - bool isValidDR = false; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - const LoRaWANChannel_t *chnl = &(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i]); - if(chnl->enabled) { - if(drUp >= chnl->drMin && drUp <= chnl->drMax) { - isValidDR = true; - break; - } - } - } - if(!isValidDR) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); - return(RADIOLIB_ERR_INVALID_DATA_RATE); - } - uint8_t cOcts[1]; uint8_t cAck[1]; uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; @@ -3009,6 +3005,7 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp) { // check if ACK is set for Datarate if(!(cAck[0] & 0x02)) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("No defined channel allows datarate %d", drUp); return(RADIOLIB_ERR_INVALID_DATA_RATE); } @@ -3049,13 +3046,18 @@ int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { // can only configure different datarate for dynamic bands if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { - return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); + return(RADIOLIB_ERR_INVALID_MODE); } // check if datarate is available in the selected band if(this->band->dataRates[dr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { return(RADIOLIB_ERR_INVALID_DATA_RATE); } + + // check if datarate is within the allowed range for Rx2 + if(dr < this->band->rx2.drMin || dr > this->band->rx2.drMax) { + return(RADIOLIB_ERR_INVALID_DATA_RATE); + } // find and check if the datarate is available for this radio module DataRate_t dataRate; @@ -3292,169 +3294,209 @@ bool LoRaWANNode::cadChannelClear() { return(true); } -void LoRaWANNode::addDefaultChannels() { - // get current channel masks - uint64_t chMaskGrp0123 = 0; - uint32_t chMaskGrp45 = 0; - this->getChannelPlanMask(&chMaskGrp0123, &chMaskGrp45); - - // there are at most three default channels for dynamic bands +void LoRaWANNode::enableDefaultChannels(bool addDynamic) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - for(int num = 0; num < 3; num++) { - if(this->band->txFreqs[num].enabled) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; - chMaskGrp0123 |= ((uint64_t)1 << num); + int num = 0; + // there are at most three default channels for dynamic bands + for(; num < 3; num++) { + if(this->band->txFreqs[num].freq) { + this->channelMasks[0] |= (0x0001 << num); + this->channelFlags[0] |= (0x0001 << num); + } + } + if(addDynamic) { + for(; num < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; num++) { + if(this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num].freq) { + this->channelMasks[0] |= (0x0001 << num); + this->channelFlags[0] |= (0x0001 << num); + } } } } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED // if a subband is set, we can set the channel indices straight from subband - if(this->subBand > 0 && this->subBand <= 8) { - // for sub band 1-8, set bank of 8 125kHz + single 500kHz channel - chMaskGrp0123 |= (uint64_t)0xFF << ((this->subBand - 1) * 8); - chMaskGrp45 |= (uint32_t)0x01 << (this->subBand - 1); - } else if(this->subBand > 8 && this->subBand <= 12) { - // CN470 only: for sub band 9-12, set bank of 8 125kHz channels - chMaskGrp45 |= (uint32_t)0xFF << ((this->subBand - 9) * 8); + if(this->subBand) { + // add bank of 8 125kHz channels + uint8_t bank16 = (this->subBand - 1) / 2; + uint16_t mask16 = 0x00FF << 8 * ((this->subBand - 1) % 2); + this->channelMasks[bank16] |= mask16; + + // for all bands except CN470: add 500kHz channel + if (this->band->bandNum != BandCN470) { + this->channelMasks[4] |= (0x0001 << (this->subBand - 1)); + } } else { - // if subband is set to 0, all 125kHz channels are enabled. - // however, we can 'only' store 16 channels, so we don't use all channels at once. - // instead, we select a random channel from each bank of 8 channels + 1 from second plan. - chMaskGrp0123 = 0; - chMaskGrp45 = 0; + // if subband is set to 0, all channels are enabled uint8_t num125kHz = this->band->txSpans[0].numChannels; - uint8_t numBanks = num125kHz / 8; - uint8_t bankIdx = this->phyLayer->random(8); - for(uint8_t bank = 0; bank < numBanks; bank++) { - uint8_t idx = bank * 8 + bankIdx; - if(idx < 64) { - chMaskGrp0123 |= ((uint64_t)1 << idx); - } else { - chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); - } + uint8_t numBanks16 = num125kHz / 16; + for(uint8_t bank = 0; bank < numBanks16; bank++) { + this->channelMasks[bank] |= 0xFFFF; } - // the 500 kHz channels are in the usual channel plan however - // these are the channel indices 64-71 for bands other than CN470 + + // for all bands except CN470: add 500kHz channels if(this->band->bandNum != BandCN470) { - chMaskGrp45 |= ((uint32_t)1 << bankIdx); + this->channelMasks[4] |= 0x00FF; } } } - - // apply channel mask - this->applyChannelMask(chMaskGrp0123, chMaskGrp45); - - // make sure the Rx2 settings are back to this band's default - this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; - this->channels[RADIOLIB_LORAWAN_RX_BC] = this->band->rx2; - - // make all enabled channels available for uplink selection - this->setAvailableChannels(0xFFFF); } -void LoRaWANNode::getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45) { - // clear masks in case anything was set - *chMaskGrp0123 = 0; - *chMaskGrp45 = 0; +bool LoRaWANNode::calculateChannelFlags() { + // clear all flags + memset(this->channelFlags, 0, sizeof(this->channelFlags)); + bool any = false; - // if there are any channels selected, create the mask from those channels - if(this->isActivated()) { - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - uint8_t idx = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx; - if(idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - if(idx < 64) { - *chMaskGrp0123 |= ((uint64_t)1 << idx); - } else { - *chMaskGrp45 |= ((uint32_t)1 << (idx - 64)); - } + uint8_t drUp = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + for(size_t i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; i++) { + // skip channel if not available + if((this->channelMasks[0] & (0x0001 << i)) == 0) { + continue; + } + // check if datarate is allowed for this channel + if(drUp >= this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][i].drMin \ + && drUp <= this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][i].drMax) { + this->channelFlags[0] |= (0x0001 << i); + any = true; } } - } -} -uint8_t LoRaWANNode::getAvailableChannels(uint16_t* chMask) { - uint8_t num = 0; - uint16_t mask = 0; - uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - // if channel is available and usable for current datarate, set corresponding bit - if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].available) { - if(currentDr >= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin && - currentDr <= this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax) { - num++; - mask |= (0x0001 << i); + } else { // RADIOLIB_LORAWAN_BAND_FIXED + // during activation of fixed bands, flag all available channels + // the datarate will be determined from there + if(!this->isActivated() && this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + memcpy(this->channelFlags, this->channelMasks, sizeof(this->channelMasks)); + return(true); + } + + // check first frequency span to see if the datarate is allowed and any channel is available + if(drUp >= this->band->txSpans[0].drMin && drUp <= this->band->txSpans[0].drMax) { + // if the datarate is OK, all channel in this span can be used + for(int i = 0; i < this->band->txSpans[0].numChannels / 16; i++) { + this->channelFlags[i] = this->channelMasks[i]; + if(this->channelMasks[i]) { + any = true; + } } } - } - if(chMask) { - *chMask = mask; - } - return(num); -} -void LoRaWANNode::setAvailableChannels(uint16_t mask) { - for(uint8_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - // if channel is enabled, set to available - if(mask & (0x0001 << i) && this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].available = true; - } else { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].available = false; + // check second frequency span to see if the datarate is allowed and any channel is available + if(drUp >= this->band->txSpans[1].drMin && drUp <= this->band->txSpans[1].drMax) { + this->channelFlags[4] = this->channelMasks[4]; + if(this->channelMasks[4]) { + any = true; + } } } + return(any); } int16_t LoRaWANNode::selectChannels() { - uint16_t chMask = 0x0000; - uint8_t numChannels = this->getAvailableChannels(&chMask); + // save the current uplink datarate + uint8_t uplinkDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + + int channelMax = RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS; + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + channelMax = this->band->txSpans[0].numChannels + this->band->txSpans[1].numChannels; + } - // if there are no available channels, try resetting them all to available - if(numChannels == 0) { - this->setAvailableChannels(0xFFFF); - numChannels = this->getAvailableChannels(&chMask); + // check if any channel is flagged available + bool flag = false; + for(int i = 0; i < (channelMax + 15) / 16; i++) { + if(this->channelFlags[i]) { + flag = true; + break; + } + } - // if there are still no channels available, give up - if(numChannels == 0) { + // if all channels are exhausted, mark all channels as available again + if(flag == false) { + bool any = this->calculateChannelFlags(); + if(!any) { return(RADIOLIB_ERR_NO_CHANNEL_AVAILABLE); } } - // select a random value within the number of possible channels - int chRand = this->phyLayer->random(numChannels); + int start = 0; + int end = channelMax; + + // for fixed bands without subband (subband = 0), + // join requests should be sent using a specific scheme (see RP 1.0.4 / 1.1B) + if(!this->isActivated() && this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->subBand == 0) { + // retrieve the number of 125 kHz banks + uint8_t num125kHzBanks = this->band->txSpans[0].numChannels / 8; + // if there is a 500 kHz span, add a 'virtual' bank + uint8_t divisor = num125kHzBanks + (this->band->txSpans[1].numChannels ? 1 : 0); + uint8_t bank = (this->devNonce - this->joinNonce) % divisor; + // if we selected a 125 kHz bank, select a random channel from this bank + if(bank < num125kHzBanks) { + start = bank * 8; + end = (bank + 1) * 8; - // retrieve the index of this channel by looping through the channel mask - int chIdx = -1; - while(chRand >= 0) { - chIdx++; - if(chMask & 0x0001) { - chRand--; + // if we selected the 500 kHz bank, select a random channel from this whole span + } else { + start = this->band->txSpans[0].numChannels; + end = start + this->band->txSpans[1].numChannels; + } + } + + // select a random channel index using reservoir sampling + uint8_t idx = 0; + uint8_t seen = 0; + for(int i = start; i < end; i++) { + if(this->channelFlags[i/16] & (0x0001 << (i % 16))) { + seen++; + if(rand() % seen == 0) { + idx = i; + } } - chMask >>= 1; } - // as we are now going to use this channel, mark unavailable for next uplink - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][chIdx].available = false; + // remove the channel from the available channels + uint16_t mask = ~(0x01 << (idx % 16)); + this->channelFlags[idx/16] &= mask; - uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; - this->channels[RADIOLIB_LORAWAN_UPLINK] = this->channelPlan[RADIOLIB_LORAWAN_UPLINK][chIdx]; - this->channels[RADIOLIB_LORAWAN_UPLINK].dr = currentDr; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - // for dynamic bands, the downlink channel is the one matched to the uplink channel - this->channels[RADIOLIB_LORAWAN_RX1] = this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][chIdx]; - + // copy the channels from the current channel plan + this->channels[RADIOLIB_LORAWAN_UPLINK] = this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][idx]; + this->channels[RADIOLIB_LORAWAN_RX1] = this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][idx]; + } else { // RADIOLIB_LORAWAN_BAND_FIXED - // for fixed bands, the downlink channel is the uplink channel ID `modulo` number of downlink channels - LoRaWANChannel_t channelDn = RADIOLIB_LORAWAN_CHANNEL_NONE; - channelDn.enabled = true; - channelDn.idx = this->channels[RADIOLIB_LORAWAN_UPLINK].idx % this->band->rx1Span.numChannels; - channelDn.freq = this->band->rx1Span.freqStart + channelDn.idx*this->band->rx1Span.freqStep; - channelDn.drMin = this->band->rx1Span.drMin; - channelDn.drMax = this->band->rx1Span.drMax; - this->channels[RADIOLIB_LORAWAN_RX1] = channelDn; + uint8_t offs = 0; + uint8_t span = 0; + if(idx >= this->band->txSpans[0].numChannels && this->band->numTxSpans == 2) { + idx -= this->band->txSpans[0].numChannels; + offs = this->band->txSpans[0].numChannels; + span = 1; + } + // calculated the frequency based on the channel index + LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; + chnl.idx = idx + offs; + chnl.freq = this->band->txSpans[span].freqStart + idx*this->band->txSpans[span].freqStep; + chnl.drMin = this->band->txSpans[span].drMin; + chnl.drMax = this->band->txSpans[span].drMax; + this->channels[RADIOLIB_LORAWAN_UPLINK] = chnl; + + // the downlink channel is the uplink channel ID `modulo` number of downlink channels + chnl.idx = this->channels[RADIOLIB_LORAWAN_UPLINK].idx % this->band->rx1Span.numChannels; + chnl.freq = this->band->rx1Span.freqStart + chnl.idx*this->band->rx1Span.freqStep; + chnl.drMin = this->band->rx1Span.drMin; + chnl.drMax = this->band->rx1Span.drMax; + this->channels[RADIOLIB_LORAWAN_RX1] = chnl; + + // for JoinRequests, pick the datarate required for this channel + if(!this->isActivated()) { + uplinkDr = this->band->txSpans[span].drJoinRequest; + } } - uint8_t rx1Dr = this->band->rx1DrTable[currentDr][this->rx1DrOffset]; + + // set the uplink datarate + this->channels[RADIOLIB_LORAWAN_UPLINK].dr = uplinkDr; + + // lookup the Rx1 datarate + uint8_t rx1Dr = this->band->rx1DrTable[this->channels[RADIOLIB_LORAWAN_UPLINK].dr][this->rx1DrOffset]; // if downlink dwelltime is enabled, datarate < 2 cannot be used, so clip to 2 // only in use on AS923_x bands @@ -3466,100 +3508,6 @@ int16_t LoRaWANNode::selectChannels() { return(RADIOLIB_ERR_NONE); } -bool LoRaWANNode::applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45) { - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - for(int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - bool en = chMaskGrp0123 & ((uint64_t)1 << i); - // if it should be enabled but is not currently defined, stop immediately - if(en && this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { - return(false); - } - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled = en; - } - } else { // bandType == RADIOLIB_LORAWAN_BAND_FIXED - // full channel mask received, so clear all existing channels - LoRaWANChannel_t chnl = RADIOLIB_LORAWAN_CHANNEL_NONE; - for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i] = chnl; - } - int num = 0; - uint8_t spanNum = 0; - int chNum = 0; - int chOfs = 0; - for(; chNum < 64; chNum++) { - if(chMaskGrp0123 & ((uint64_t)1 << chNum)) { - // if a subband is specified, any channel must be within the specified subband - // we subtract 1 here because subbands are numbered starting from 1 - if(this->subBand > 0 && (chNum / 8) != (this->subBand - 1)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Channel %d not allowed for subband %d", chNum, this->subBand); - return(false); - } - chnl.enabled = true; - chnl.idx = chNum; - chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; - chnl.drMin = this->band->txSpans[spanNum].drMin; - chnl.drMax = this->band->txSpans[spanNum].drMax; - // set the default datarate to the middle datarate, rounded up - chnl.dr = (chnl.drMin + chnl.drMax + 1) / 2; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num++] = chnl; - } - } - if(this->band->numTxSpans > 1) { - spanNum += 1; - chNum = 0; - chOfs = 64; - } - for(; chNum < this->band->txSpans[spanNum].numChannels; chNum++) { - if(chMaskGrp45 & ((uint32_t)1 << chNum)) { - // if a subband is specified, any channel must be within the specified subband - // we subtract 1 here because subbands are numbered starting from 1 - if(this->band->numTxSpans == 1 && this->subBand > 0 && (chNum / 8) != (this->subBand - 1)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Channel %d not allowed for subband %d", chNum, this->subBand); - return(false); - } - if(this->band->numTxSpans > 1 && this->subBand > 0 && chNum != (this->subBand - 1)) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Channel %d not allowed for subband %d", chNum, this->subBand); - return(false); - } - chnl.enabled = true; - chnl.idx = chNum + chOfs; - chnl.freq = this->band->txSpans[spanNum].freqStart + chNum*this->band->txSpans[spanNum].freqStep; - chnl.drMin = this->band->txSpans[spanNum].drMin; - chnl.drMax = this->band->txSpans[spanNum].drMax; - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][num++] = chnl; - } - } - } - -#if RADIOLIB_DEBUG_PROTOCOL - this->printChannels(); -#endif - - return(true); -} - -#if RADIOLIB_DEBUG_PROTOCOL -void LoRaWANNode::printChannels() { - for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - if(this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled) { - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %d %7.3f (%d - %d) | DL: %3d %d %7.3f (%d - %d)", - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].idx, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].enabled, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].freq / 10000.0, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMin, - this->channelPlan[RADIOLIB_LORAWAN_UPLINK][i].drMax, - - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].idx, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].enabled, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].freq / 10000.0, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].drMin, - this->channelPlan[RADIOLIB_LORAWAN_DOWNLINK][i].drMax - ); - } - } -} -#endif - uint32_t LoRaWANNode::generateMIC(const uint8_t* msg, size_t len, uint8_t* key) { if((msg == NULL) || (len == 0)) { return(0); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 47db068364..f13ed7470f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -79,7 +79,6 @@ #define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) #define RADIOLIB_LORAWAN_BAND_FIXED (1) #define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) -#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 0) // recommended default settings #define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) @@ -218,11 +217,10 @@ #define RADIOLIB_LORAWAN_FPORT_TS009 (224) #define RADIOLIB_LORAWAN_FPORT_TS011 (226) -// the length of internal MAC command queue - hopefully this is enough for most use cases -#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9) - // the maximum number of simultaneously available channels -#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) +#define RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS (16) +#define RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS (12) +#define RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS (96) // maximum MAC command sizes #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) @@ -231,6 +229,12 @@ #define RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE (250) +// session states +#define RADIOLIB_LORAWAN_SESSION_NONE (0x00) +#define RADIOLIB_LORAWAN_SESSION_ACTIVATING (0x01) +#define RADIOLIB_LORAWAN_SESSION_PENDING (0x02) +#define RADIOLIB_LORAWAN_SESSION_ACTIVE (0x03) + // threshold at which sleeping via user callback enabled, in ms #define RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD (50) @@ -316,7 +320,7 @@ constexpr LoRaWANPackage_t PackageTable[RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES] #define RADIOLIB_LORAWAN_PACKAGE_NONE { .packId = 0, .packFPort = 0, .isAppPack = false, .fixedFPort = false, .enabled = false, .callback = NULL } -#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0002) +#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0003) enum LoRaWANSchemeBase_t { RADIOLIB_LORAWAN_NONCES_START = 0x00, @@ -326,20 +330,20 @@ enum LoRaWANSchemeBase_t { RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes - RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte - RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes + RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 2 bytes RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size }; enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_START = 0x00, - RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes + RADIOLIB_LORAWAN_SESSION_STATUS = RADIOLIB_LORAWAN_SESSION_START, // 1 byte + RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_STATUS + 1, // 16 bytes RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 4 bytes - RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes - RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes + RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes + RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes @@ -349,19 +353,19 @@ enum LoRaWANSchemeSession_t { RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte - RADIOLIB_LORAWAN_SESSION_CLASS = RADIOLIB_LORAWAN_SESSION_VERSION + 1, // 1 byte - RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_CLASS + sizeof(uint8_t), // 14 bytes - RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_LINK_ADR + 14, // 1 byte - RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + 1, // 4 bytes - RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + 4, // 1 byte - RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + 1, // 1 byte - RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + 1, // 1 byte - RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + 1, // 1 byte - RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + 1, // 16*5 bytes - RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*5, // 16*4 bytes - RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS*4, // 2 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE = RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS + sizeof(uint16_t), // 15 bytes - RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE + RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN, // 1 byte + RADIOLIB_LORAWAN_SESSION_CLASS = RADIOLIB_LORAWAN_SESSION_VERSION + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_CLASS + sizeof(uint8_t), // 14 bytes + RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_LINK_ADR + 14, // 1 byte + RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + 1, // 4 bytes + RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + 4, // 1 byte + RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + 1, // 1 byte + RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + 1, // 16*5 bytes + RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS*5, // 16*4 bytes + RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS*4, // 2 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE = RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS + RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS, // 12 bytes // 15 bytes + RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE + RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN, // 1 byte RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN + sizeof(uint8_t), // 2 bytes RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size }; @@ -372,9 +376,6 @@ enum LoRaWANSchemeSession_t { To save space, adjacent channels are saved in "spans". */ struct LoRaWANChannel_t { - /*! \brief Whether this channel is enabled (can be used) or is disabled */ - bool enabled; - /*! \brief The channel number, as specified by defaults or the network */ uint8_t idx; @@ -389,14 +390,11 @@ struct LoRaWANChannel_t { /*! \brief Datarate currently in use on this channel */ uint8_t dr; - - /*! \brief Whether this channel is available for channel selection */ - bool available; }; // alias for unused channel -#define RADIOLIB_LORAWAN_CHANNEL_NONE { .enabled = false, .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, \ - .drMin = 0, .drMax = 0, .dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, .available = false } +#define RADIOLIB_LORAWAN_CHANNEL_NONE { .idx = 0, .freq = 0, .drMin = 0, .drMax = 0, \ + .dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } /*! \struct LoRaWANChannelSpan_t @@ -613,7 +611,7 @@ class LoRaWANNode { int16_t setBufferNonces(const uint8_t* persistentBuffer); /*! - \brief Clear an active session, so that the device will have to rejoin the network. + \brief Clear an active session. This requires the device to rejoin the network. */ void clearSession(); @@ -655,18 +653,16 @@ class LoRaWANNode { /*! \brief Join network by restoring OTAA session or performing over-the-air activation. By this procedure, the device will perform an exchange with the network server and set all necessary configuration. - \param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled) \returns \ref status_codes */ - virtual int16_t activateOTAA(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL); + virtual int16_t activateOTAA(LoRaWANJoinEvent_t *joinEvent = NULL); /*! \brief Join network by restoring ABP session or performing over-the-air activation. In this procedure, all necessary configuration must be provided by the user. - \param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled). \returns \ref status_codes */ - virtual int16_t activateABP(uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED); + virtual int16_t activateABP(); /*! \brief Whether there is an ongoing session active */ bool isActivated(); @@ -999,7 +995,7 @@ class LoRaWANNode { uint16_t lwMode = RADIOLIB_LORAWAN_MODE_NONE; uint8_t lwClass = RADIOLIB_LORAWAN_CLASS_A; - bool isActive = false; + uint8_t sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE; uint64_t joinEUI = 0; uint64_t devEUI = 0; @@ -1074,8 +1070,12 @@ class LoRaWANNode { // number of CADs to estimate a clear channel uint8_t difsSlots = RADIOLIB_LORAWAN_DIFS_DEFAULT; - // available channel frequencies from list passed during OTA activation - LoRaWANChannel_t channelPlan[2][RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS]; + // dynamic channels + LoRaWANChannel_t dynamicChannels[2][RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS]; + + // masks: which channels are defined/active; flags: which should be used next + uint16_t channelMasks[RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16] = { 0 }; + uint16_t channelFlags[RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16] = { 0 }; // currently configured channels for Tx, Rx1, Rx2, RxBC LoRaWANChannel_t channels[4] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, @@ -1115,8 +1115,8 @@ class LoRaWANNode { // this will reset the device credentials, so the device starts completely new void clearNonces(); - // start a fresh session using default parameters - void createSession(uint16_t lwMode, uint8_t initialDr); + // setup an empty session with default parameters + void createSession(); // setup Join-Request payload void composeJoinRequest(uint8_t* joinRequestMsg); @@ -1208,30 +1208,16 @@ class LoRaWANNode { // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. bool cadChannelClear(); - // add all default channels on top of the current channels - void addDefaultChannels(); + // enable all default channels on top of the current channels + void enableDefaultChannels(bool addDynamic = false); - // get a complete 80-bit channel mask for current configuration - void getChannelPlanMask(uint64_t* chMaskGrp0123, uint32_t* chMaskGrp45); - - // get the number of available channels, - // along with a 16-bit mask indicating which channels can be used next for uplink/downlink - uint8_t getAvailableChannels(uint16_t* mask); - - // (re)set/restore which channels can be used next for uplink/downlink - void setAvailableChannels(uint16_t mask); + // calculate which channels are available given the current datarate + // returns true if there is any such channel, false otherwise + bool calculateChannelFlags(); // select a set of random TX/RX channels for up- and downlink int16_t selectChannels(); - // apply a 96-bit channel mask - bool applyChannelMask(uint64_t chMaskGrp0123, uint32_t chMaskGrp45); - -#if RADIOLIB_DEBUG_PROTOCOL - // print the available channels through debug - void printChannels(); -#endif - // method to generate message integrity code uint32_t generateMIC(const uint8_t* msg, size_t len, uint8_t* key); diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index 53e9e15fdd..c1044cbac0 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -30,9 +30,9 @@ const LoRaWANBand_t EU868 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 8681000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 8683000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 2, .freq = 8685000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .idx = 0, .freq = 8681000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 8683000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 2, .freq = 8685000, .drMin = 0, .drMax = 5, .dr = 3 }, }, .numTxSpans = 0, .txSpans = { @@ -57,14 +57,14 @@ const LoRaWANBand_t EU868 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 8695250, .drMin = 0, .drMax = 7, .dr = 0, .available = true }, + .rx2 = { .idx = 0, .freq = 8695250, .drMin = 0, .drMax = 7, .dr = 0 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 8651000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 8655000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + { .idx = 0, .freq = 8651000, .drMin = 3, .drMax = 3, .dr = 3 }, + { .idx = 1, .freq = 8655000, .drMin = 3, .drMax = 3, .dr = 3 } }, .txAck = { - { .enabled = true, .idx = 0, .freq = 8653000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 8659000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + { .idx = 0, .freq = 8653000, .drMin = 3, .drMax = 3, .dr = 3 }, + { .idx = 1, .freq = 8659000, .drMin = 3, .drMax = 3, .dr = 3 } }, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, @@ -146,14 +146,14 @@ const LoRaWANBand_t US915 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8, .available = true }, + .rx2 = { .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9167000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, - { .enabled = true, .idx = 1, .freq = 9199000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } + { .idx = 0, .freq = 9167000, .drMin = 10, .drMax = 10, .dr = 10 }, + { .idx = 1, .freq = 9199000, .drMin = 10, .drMax = 10, .dr = 10 } }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9183000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, - { .enabled = true, .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } + { .idx = 0, .freq = 9183000, .drMin = 10, .drMax = 10, .dr = 10 }, + { .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10 } }, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, @@ -187,9 +187,9 @@ const LoRaWANBand_t EU433 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 4331750, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 4333750, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 2, .freq = 4335750, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .idx = 0, .freq = 4331750, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 4333750, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 2, .freq = 4335750, .drMin = 0, .drMax = 5, .dr = 3 }, }, .numTxSpans = 0, .txSpans = { @@ -214,7 +214,7 @@ const LoRaWANBand_t EU433 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 4346650, .drMin = 0, .drMax = 7, .dr = 0, .available = true }, + .rx2 = { .idx = 0, .freq = 4346650, .drMin = 0, .drMax = 7, .dr = 0 }, .txWoR = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE @@ -303,14 +303,14 @@ const LoRaWANBand_t AU915 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8, .available = true }, + .rx2 = { .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9167000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, - { .enabled = true, .idx = 1, .freq = 9199000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } + { .idx = 0, .freq = 9167000, .drMin = 10, .drMax = 10, .dr = 10 }, + { .idx = 1, .freq = 9199000, .drMin = 10, .drMax = 10, .dr = 10 } }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9183000, .drMin = 10, .drMax = 10, .dr = 10, .available = true }, - { .enabled = true, .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10, .available = true } + { .idx = 0, .freq = 9183000, .drMin = 10, .drMax = 10, .dr = 10 }, + { .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10 } }, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, @@ -385,7 +385,7 @@ const LoRaWANBand_t CN470 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 5053000, .drMin = 0, .drMax = 5, .dr = 0, .available = true }, + .rx2 = { .idx = 0, .freq = 5053000, .drMin = 0, .drMax = 5, .dr = 0 }, .txWoR = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE @@ -426,8 +426,8 @@ const LoRaWANBand_t AS923 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9234000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 9234000, .drMin = 0, .drMax = 5, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -453,13 +453,13 @@ const LoRaWANBand_t AS923 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .rx2 = { .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9236000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9236000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9238000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9238000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { @@ -494,8 +494,8 @@ const LoRaWANBand_t AS923_2 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9216000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 9216000, .drMin = 0, .drMax = 5, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -521,13 +521,13 @@ const LoRaWANBand_t AS923_2 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .rx2 = { .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9218000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9218000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9220000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9220000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { @@ -562,8 +562,8 @@ const LoRaWANBand_t AS923_3 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9168000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 9168000, .drMin = 0, .drMax = 5, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -589,13 +589,13 @@ const LoRaWANBand_t AS923_3 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .rx2 = { .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9170000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9170000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9172000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9172000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { @@ -630,8 +630,8 @@ const LoRaWANBand_t AS923_4 = { .dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME, .txParamSupported = true, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9175000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, + { .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 9175000, .drMin = 0, .drMax = 5, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .numTxSpans = 0, @@ -657,13 +657,13 @@ const LoRaWANBand_t AS923_4 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .rx2 = { .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9177000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9177000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9179000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, + { .idx = 0, .freq = 9179000, .drMin = 3, .drMax = 3, .dr = 3 }, RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { @@ -698,9 +698,9 @@ const LoRaWANBand_t KR920 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 9221000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9223000, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 2, .freq = 9225000, .drMin = 0, .drMax = 5, .dr = 3, .available = true } + { .idx = 0, .freq = 9221000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 9223000, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 2, .freq = 9225000, .drMin = 0, .drMax = 5, .dr = 3 } }, .numTxSpans = 0, .txSpans = { @@ -725,14 +725,14 @@ const LoRaWANBand_t KR920 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 9219000, .drMin = 0, .drMax = 5, .dr = 0, .available = true }, + .rx2 = { .idx = 0, .freq = 9219000, .drMin = 0, .drMax = 5, .dr = 0 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 9227000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + { .idx = 0, .freq = 9227000, .drMin = 3, .drMax = 3, .dr = 3 }, + { .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3 } }, .txAck = { - { .enabled = true, .idx = 0, .freq = 9229000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + { .idx = 0, .freq = 9229000, .drMin = 3, .drMax = 3, .dr = 3 }, + { .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3 } }, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, @@ -766,9 +766,9 @@ const LoRaWANBand_t IN865 = { .dwellTimeDn = 0, .txParamSupported = false, .txFreqs = { - { .enabled = true, .idx = 0, .freq = 8650625, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 8654025, .drMin = 0, .drMax = 5, .dr = 3, .available = true }, - { .enabled = true, .idx = 2, .freq = 8659850, .drMin = 0, .drMax = 5, .dr = 3, .available = true } + { .idx = 0, .freq = 8650625, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 1, .freq = 8654025, .drMin = 0, .drMax = 5, .dr = 3 }, + { .idx = 2, .freq = 8659850, .drMin = 0, .drMax = 5, .dr = 3 } }, .numTxSpans = 0, .txSpans = { @@ -793,14 +793,14 @@ const LoRaWANBand_t IN865 = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, - .rx2 = { .enabled = true, .idx = 0, .freq = 8665500, .drMin = 0, .drMax = 7, .dr = 2, .available = true }, + .rx2 = { .idx = 0, .freq = 8665500, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { - { .enabled = true, .idx = 0, .freq = 8660000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 8667000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + { .idx = 0, .freq = 8660000, .drMin = 3, .drMax = 3, .dr = 3 }, + { .idx = 1, .freq = 8667000, .drMin = 3, .drMax = 3, .dr = 3 } }, .txAck = { - { .enabled = true, .idx = 0, .freq = 8662000, .drMin = 3, .drMax = 3, .dr = 3, .available = true }, - { .enabled = true, .idx = 1, .freq = 8669000, .drMin = 3, .drMax = 3, .dr = 3, .available = true } + { .idx = 0, .freq = 8662000, .drMin = 3, .drMax = 3, .dr = 3 }, + { .idx = 1, .freq = 8669000, .drMin = 3, .drMax = 3, .dr = 3 } }, .dataRates = { RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, From 4cd658f5b5d51b26cd0225f0a09edb1068c65b0e Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 28 Aug 2025 09:06:03 +0200 Subject: [PATCH 1591/1848] [LoRaWAN] Fixes for network package --- src/protocols/LoRaWAN/LoRaWAN.cpp | 25 ++++++++++++------------- src/protocols/LoRaWAN/LoRaWAN.h | 13 ++++++++----- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 440d7f48c0..0a0bffeb49 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -164,7 +164,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP return(state); } - // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received + // handle Rx windows - returns window > 0 if a downlink is received state = this->receiveDownlink(); // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4) @@ -930,7 +930,7 @@ int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) { this->rxDelays[1] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_1_MS; this->rxDelays[2] = RADIOLIB_LORAWAN_JOIN_ACCEPT_DELAY_2_MS; - // handle Rx1 and Rx2 windows - returns window > 0 if a downlink is received + // handle Rx windows - returns window > 0 if a downlink is received state = this->receiveDownlink(); if(state < RADIOLIB_ERR_NONE) { return(state); @@ -1786,9 +1786,11 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. // (...) it SHALL silently discard the entire frame. // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && window < RADIOLIB_LORAWAN_RX_BC) { - // payload consists of all MAC commands (or is empty) - ok = true; + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { + if(this->lwClass == RADIOLIB_LORAWAN_CLASS_A || window < RADIOLIB_LORAWAN_RX_BC) { + // payload consists of all MAC commands (or is empty) + ok = true; + } } if(fPort >= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MIN && fPort <= RADIOLIB_LORAWAN_FPORT_PAYLOAD_MAX) { ok = true; @@ -1833,7 +1835,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. // (...) it SHALL silently discard the entire frame. // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). - if(fOptsLen > 0 && window == RADIOLIB_LORAWAN_RX_BC) { + if(fOptsLen > 0 && this->lwClass != RADIOLIB_LORAWAN_CLASS_A && window == RADIOLIB_LORAWAN_RX_BC) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; #endif @@ -2126,10 +2128,11 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], payLen, encKey, data, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); *len = payLen; - // however, if this frame belongs to a package, redirect instead and 'hide' contents from the user + // however, if this frame belongs to an application package, + // redirect instead and 'hide' contents from the user // just to be sure that it doesn't get re-interpreted... for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { - if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + if(this->packages[id].enabled && this->packages[id].isAppPack && fPort == this->packages[id].packFPort) { this->packages[id].callback(data, *len); memset(data, 0, *len); *len = 0; @@ -3629,18 +3632,14 @@ int16_t LoRaWANNode::addAppPackage(uint8_t packageId, PackageCb_t callback, uint return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::addNwkPackage(uint8_t packageId, PackageCb_t callback) { +int16_t LoRaWANNode::addNwkPackage(uint8_t packageId) { if(packageId >= RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES) { return(RADIOLIB_ERR_INVALID_MODE); } if(PackageTable[packageId].isAppPack == true) { return(RADIOLIB_ERR_INVALID_MODE); } - if(callback == NULL) { - return(RADIOLIB_ERR_NULL_POINTER); - } this->packages[packageId] = PackageTable[packageId]; - this->packages[packageId].callback = callback; this->packages[packageId].enabled = true; return(RADIOLIB_ERR_NONE); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index f13ed7470f..69ab67ca4f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1081,9 +1081,12 @@ class LoRaWANNode { LoRaWANChannel_t channels[4] = { RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE, RADIOLIB_LORAWAN_CHANNEL_NONE }; - // delays between the uplink and Rx1/2 windows - // the first field is meaningless, but is used for offsetting for Rx windows 1 and 2 - RadioLibTime_t rxDelays[3] = { 0, RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS }; + // delays between the uplink and Rx windows + // the first field is meaningless, but is used for offsetting the Rx windows + RadioLibTime_t rxDelays[4] = { 0, + RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS, + RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS, + 0 }; // offset between Tx and Rx1 (such that Rx1 has equal or lower DR) uint8_t rx1DrOffset = 0; @@ -1149,14 +1152,14 @@ class LoRaWANNode { int16_t receiveClassC(RadioLibTime_t timeout = 0); // open a series of Class A (and C) downlinks - int16_t receiveDownlink(); + virtual int16_t receiveDownlink(); // extract downlink payload and process MAC commands int16_t parseDownlink(uint8_t* data, size_t* len, uint8_t window, LoRaWANEvent_t* event = NULL); // add a LoRaWAN package that runs through the network layer // (not available to users, they are only allowed to add application packages) - int16_t addNwkPackage(uint8_t packageId, PackageCb_t callback); + int16_t addNwkPackage(uint8_t packageId); // execute mac command, return the number of processed bytes for sequential processing bool execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn); From 42c3b2e41638ca9cee3fab8a06db6a58d52c9710 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 28 Aug 2025 09:28:27 +0200 Subject: [PATCH 1592/1848] [LoRaWAN] Put radio to sleep during Rx windows and RetransmitTimeout --- src/protocols/LoRaWAN/LoRaWAN.cpp | 30 +++++++++++++++++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0a0bffeb49..80655ab3df 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1425,7 +1425,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u RADIOLIB_ASSERT(state); // sleep for the duration of the transmission - this->sleepDelay(toa); + this->sleepDelay(toa, false); RadioLibTime_t txEnd = mod->hal->millis(); // wait for an additional transmission duration as Tx timeout period @@ -1519,7 +1519,7 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); // sleep for the duration of the padded Rx window - this->sleepDelay(timeoutHost / 1000); + this->sleepDelay(timeoutHost / 1000, false); // wait for the DIO interrupt to fire (RxDone or RxTimeout) // use a small additional delay in case the RxTimeout interrupt is slow to fire @@ -3775,16 +3775,32 @@ void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_ } } -void LoRaWANNode::sleepDelay(RadioLibTime_t ms) { - // if the user did not provide sleep callback, or the duration is short, just call delay - if((this->sleepCb == nullptr) || (ms <= RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD)) { +void LoRaWANNode::sleepDelay(RadioLibTime_t ms, bool radioOff) { + // if the duration is short, just call delay + if(ms <= 2 || ms <= RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD) { Module* mod = this->phyLayer->getMod(); mod->hal->delay(ms); return; } - // otherwise, call the user-provided callback - this->sleepCb(ms); + // if radioOff is requested, put the radio to sleep + if(radioOff) { + this->phyLayer->sleep(); + ms -= 2; + } + + // call the user-provided callback if provided + if(this->sleepCb) { + this->sleepCb(ms); + } else { + // if no callback is provided, just delay + Module* mod = this->phyLayer->getMod(); + mod->hal->delay(ms); + } + + if(radioOff) { + this->phyLayer->standby(); + } } int16_t LoRaWANNode::checkBufferCommon(const uint8_t *buffer, uint16_t size) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 69ab67ca4f..43e9bca1ac 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1235,7 +1235,7 @@ class LoRaWANNode { void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t addr, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); // function that allows sleeping via user-provided callback - void sleepDelay(RadioLibTime_t ms); + void sleepDelay(RadioLibTime_t ms, bool radioOff = true); // 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum static uint16_t checkSum16(const uint8_t *key, uint16_t keyLen); From a28234e262a1bb023dd61ae5b51a85c3e6b3c3f2 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 29 Aug 2025 13:29:34 +0200 Subject: [PATCH 1593/1848] [SX127x] Add safety delay while entering sleep --- src/modules/SX127x/SX127x.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 068fcad471..0fcafd9f5c 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -296,7 +296,12 @@ int16_t SX127x::sleep() { this->mod->setRfSwitchState(Module::MODE_IDLE); // set mode to sleep - return(setMode(RADIOLIB_SX127X_SLEEP)); + int16_t state = setMode(RADIOLIB_SX127X_SLEEP); + + // wait for SX127x to safely enter sleep mode + this->mod->hal->delay(1); + + return(state); } int16_t SX127x::standby() { From b78ff1444e54a5b38b2781d6d2f30f70ac02b05b Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Tue, 2 Sep 2025 09:22:34 +0200 Subject: [PATCH 1594/1848] Add support for LoRa coding rate 4/4 (#1587) * [SX1272] Add support for coding rate 4/4 * [SX1278] Add support for coding rate 4/4 * [SX126x] Add support for coding rate 4/4 * [LR11x0] Add support for coding rate 4/4 * [SX128x] Add support for coding rate 4/4 --- src/modules/LLCC68/LLCC68.cpp | 2 +- src/modules/LLCC68/LLCC68.h | 3 ++- src/modules/LR11x0/LR1110.h | 3 ++- src/modules/LR11x0/LR1120.h | 3 ++- src/modules/LR11x0/LR11x0.cpp | 7 +++++-- src/modules/LR11x0/LR11x0.h | 6 ++++-- src/modules/SX126x/SX1262.h | 3 ++- src/modules/SX126x/SX1268.h | 3 ++- src/modules/SX126x/SX126x.cpp | 4 ++-- src/modules/SX126x/SX126x.h | 6 ++++-- src/modules/SX127x/SX1272.cpp | 5 ++++- src/modules/SX127x/SX1272.h | 9 ++++++--- src/modules/SX127x/SX1273.cpp | 2 +- src/modules/SX127x/SX1273.h | 3 ++- src/modules/SX127x/SX1276.h | 3 ++- src/modules/SX127x/SX1277.cpp | 2 +- src/modules/SX127x/SX1277.h | 3 ++- src/modules/SX127x/SX1278.cpp | 5 ++++- src/modules/SX127x/SX1278.h | 9 ++++++--- src/modules/SX127x/SX1279.h | 3 ++- src/modules/SX128x/SX128x.cpp | 17 +++++++++++++++-- src/modules/SX128x/SX128x.h | 6 ++++-- 22 files changed, 75 insertions(+), 32 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 17f19794ee..15ab5c6446 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -151,7 +151,7 @@ int16_t LLCC68::checkDataRate(DataRate_t dr) { } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01f; switch (bw_div2) { case 62: // 125.0: diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index e548fa573c..d260b0b13c 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -29,7 +29,8 @@ class LLCC68: public SX1262 { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index e1503de150..05067e52f5 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -27,7 +27,8 @@ class LR1110: public LR11x0 { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index d60933d2ec..14cd4f3d31 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -27,7 +27,8 @@ class LR1120: public LR11x0 { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index cd8ecfd85c..4bcc5c6445 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -628,10 +628,13 @@ int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) { return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); if(longInterleave) { switch(cr) { + case 4: + this->codingRate = 0; + break; case 5: case 6: this->codingRate = cr; @@ -1003,7 +1006,7 @@ int16_t LR11x0::checkDataRate(DataRate_t dr) { } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 54a8466de6..21c1dc3b7c 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -933,7 +933,8 @@ class LR11x0: public PhysicalLayer { \brief Initialization method for LoRa modem. \param bw LoRa bandwidth in kHz. \param sf LoRa spreading factor. - \param cr LoRa coding rate denominator. + \param cr LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. \param preambleLength LoRa preamble length in symbols \param tcxoVoltage TCXO reference voltage to be set. @@ -1159,7 +1160,8 @@ class LR11x0: public PhysicalLayer { int16_t setSpreadingFactor(uint8_t sf, bool legacy = false); /*! - \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param cr LoRa coding rate denominator to be set. \param longInterleave Enable long interleaver when set to true. Note that CR 4/7 is not possible with long interleaver enabled! diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 08ac1b6b23..d9668ba836 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -34,7 +34,8 @@ class SX1262: public SX126x { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index c34bec8dd5..28b246e359 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -33,7 +33,8 @@ class SX1268: public SX126x { \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. + Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index cdeaaf761d..d7c0af39d2 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -801,7 +801,7 @@ int16_t SX126x::setCodingRate(uint8_t cr) { return(RADIOLIB_ERR_WRONG_MODEM); } - RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters this->codingRate = cr - 4; @@ -958,7 +958,7 @@ int16_t SX126x::checkDataRate(DataRate_t dr) { } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index d06d37e592..2bcac6a642 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -501,7 +501,8 @@ class SX126x: public PhysicalLayer { /*! \brief Initialization method for LoRa modem. - \param cr LoRa coding rate denominator. Allowed values range from 5 to 8. + \param cr LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 1-byte LoRa sync word. \param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535. \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. @@ -774,7 +775,8 @@ class SX126x: public PhysicalLayer { virtual int16_t setSpreadingFactor(uint8_t sf); /*! - \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param cr LoRa coding rate denominator to be set. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index e6e4406d64..313cbff0fe 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -195,6 +195,9 @@ int16_t SX1272::setCodingRate(uint8_t cr) { // check allowed coding rate values switch(cr) { + case 4: + newCodingRate = RADIOLIB_SX1272_CR_4_4; + break; case 5: newCodingRate = RADIOLIB_SX1272_CR_4_5; break; @@ -267,7 +270,7 @@ int16_t SX1272::checkDataRate(DataRate_t dr) { } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index f3d835459b..92760148c0 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -31,7 +31,8 @@ #define RADIOLIB_SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz #define RADIOLIB_SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz #define RADIOLIB_SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz -#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 error coding rate: 4/5 +#define RADIOLIB_SX1272_CR_4_4 0b00000000 // 5 3 error coding rate: 4/4 (undocumented) +#define RADIOLIB_SX1272_CR_4_5 0b00001000 // 5 3 4/5 #define RADIOLIB_SX1272_CR_4_6 0b00010000 // 5 3 4/6 #define RADIOLIB_SX1272_CR_4_7 0b00011000 // 5 3 4/7 #define RADIOLIB_SX1272_CR_4_8 0b00100000 // 5 3 4/8 @@ -109,7 +110,8 @@ class SX1272: public SX127x { \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. @@ -163,7 +165,8 @@ class SX1272: public SX127x { virtual int16_t setSpreadingFactor(uint8_t sf); /*! - \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. + \brief Sets %LoRa link coding rate denominator. Allowed values range from 4 to 8. Only available in %LoRa mode. + Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC. \param cr %LoRa link coding rate denominator to be set. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index 11aace90d1..c9b1f4b2b9 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -107,7 +107,7 @@ int16_t SX1273::checkDataRate(DataRate_t dr) { } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 2a2e3b5efc..40395d9917 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -29,7 +29,8 @@ class SX1273: public SX1272 { \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz. \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 006e682ed1..0ea9ea4db5 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -29,7 +29,8 @@ class SX1276: public SX1278 { \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 155a6f3d31..c4b4a1f74e 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -149,7 +149,7 @@ int16_t SX1277::checkDataRate(DataRate_t dr) { } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 0df03daca4..eaaf3c649a 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -29,7 +29,8 @@ class SX1277: public SX1278 { \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz. \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 9. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 308ad5c3b9..dab91a5afc 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -209,6 +209,9 @@ int16_t SX1278::setCodingRate(uint8_t cr) { // check allowed coding rate values switch(cr) { + case 4: + newCodingRate = RADIOLIB_SX1278_CR_4_4; + break; case 5: newCodingRate = RADIOLIB_SX1278_CR_4_5; break; @@ -281,7 +284,7 @@ int16_t SX1278::checkDataRate(DataRate_t dr) { } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index dc606885c9..9155db9d4d 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -49,7 +49,8 @@ #define RADIOLIB_SX1278_BW_125_00_KHZ 0b01110000 // 7 4 125.00 kHz #define RADIOLIB_SX1278_BW_250_00_KHZ 0b10000000 // 7 4 250.00 kHz #define RADIOLIB_SX1278_BW_500_00_KHZ 0b10010000 // 7 4 500.00 kHz -#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 error coding rate: 4/5 +#define RADIOLIB_SX1278_CR_4_4 0b00000000 // 3 1 error coding rate: 4/4 (undocumented) +#define RADIOLIB_SX1278_CR_4_5 0b00000010 // 3 1 4/5 #define RADIOLIB_SX1278_CR_4_6 0b00000100 // 3 1 4/6 #define RADIOLIB_SX1278_CR_4_7 0b00000110 // 3 1 4/7 #define RADIOLIB_SX1278_CR_4_8 0b00001000 // 3 1 4/8 @@ -120,7 +121,8 @@ class SX1278: public SX127x { \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. @@ -174,7 +176,8 @@ class SX1278: public SX127x { virtual int16_t setSpreadingFactor(uint8_t sf); /*! - \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode. + \brief Sets %LoRa link coding rate denominator. Allowed values range from 4 to 8. Only available in %LoRa mode. + Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC. \param cr %LoRa link coding rate denominator to be set. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 7d304ecc0a..b2b5b73548 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -29,7 +29,8 @@ class SX1279: public SX1278 { \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 960.0 MHz. \param bw %LoRa link bandwidth in kHz. Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. \param sf %LoRa link spreading factor. Allowed values range from 6 to 12. - \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8. + \param cr %LoRa link coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 5a8c9a1daa..0f50aa0d77 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -726,11 +726,24 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { // LoRa/ranging if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { - RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) { - this->codingRateLoRa = cr; + switch(cr) { + case 4: + this->codingRateLoRa = 0; + break; + case 5: + case 6: + this->codingRateLoRa = cr; + break; + case 8: + this->codingRateLoRa = cr - 1; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } } else { this->codingRateLoRa = cr - 4; } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 6c35f49832..9f42f946f0 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -370,7 +370,8 @@ class SX128x: public PhysicalLayer { \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. \param bw LoRa bandwidth in kHz. Defaults to 812.5 kHz. \param sf LoRa spreading factor. Defaults to 9. - \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. \param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX128X_SYNC_WORD_PRIVATE (0x12). \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 12 symbols. @@ -626,7 +627,8 @@ class SX128x: public PhysicalLayer { int16_t setSpreadingFactor(uint8_t sf); /*! - \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 + means no coding, is undocumented and not recommended without your own FEC. \param cr LoRa coding rate denominator to be set. \param longInterleaving Whether to enable long interleaving mode. Not available for coding rate 4/7, defaults to false. From f7612e9a65f4ed846be0939cb1ae0a8e842f3169 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Tue, 2 Sep 2025 20:28:12 +0200 Subject: [PATCH 1595/1848] Add methods to retrieve received LoRa header info (#1588) * [LR11x0] Move Rx header infos to public method * [SX126x] Add LoRa Rx header infos method * [SX127x] Add LoRa Rx header infos method * [SX128x] Add LoRa Rx header infos method * Add `getLoRaRxHeaderInfo` to keywords --- keywords.txt | 1 + src/modules/LR11x0/LR11x0.h | 9 ++++++++- src/modules/LR11x0/LR11x0_commands.cpp | 10 ++++++++-- src/modules/SX126x/SX126x.cpp | 20 +++++++++++++++++--- src/modules/SX126x/SX126x.h | 11 ++++++++++- src/modules/SX127x/SX127x.cpp | 14 ++++++++++++++ src/modules/SX127x/SX127x.h | 8 ++++++++ src/modules/SX128x/SX128x.cpp | 14 ++++++++++++++ src/modules/SX128x/SX128x.h | 9 +++++++++ 9 files changed, 89 insertions(+), 7 deletions(-) diff --git a/keywords.txt b/keywords.txt index 2576cd8702..9a7accd944 100644 --- a/keywords.txt +++ b/keywords.txt @@ -195,6 +195,7 @@ getFHSSChannel KEYWORD2 clearFHSSInt KEYWORD2 randomByte KEYWORD2 getPacketLength KEYWORD2 +getLoRaRxHeaderInfo KEYWORD2 setFifoEmptyAction KEYWORD2 clearFifoEmptyAction KEYWORD2 setFifoThreshold KEYWORD2 diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 21c1dc3b7c..612bbbad2a 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1356,6 +1356,14 @@ class LR11x0: public PhysicalLayer { */ size_t getPacketLength(bool update, uint8_t* offset); + /*! + \brief Get LoRa header information from last received packet. Only valid in explicit header mode. + \param cr Pointer to variable to store the coding rate. + \param hasCRC Pointer to variable to store the CRC status. + \returns \ref status_codes + */ + int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + /*! \brief Get expected time-on-air for a given size of payload \param len Payload length in bytes. @@ -1714,7 +1722,6 @@ class LR11x0: public PhysicalLayer { int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); int16_t lrFhssSetSyncWord(uint32_t sync); int16_t configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len); - int16_t getLoRaRxHeaderInfos(uint8_t* info); int16_t bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len); int16_t wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint8_t nbScanPerChan, uint16_t timeout, uint8_t abortOnTimeout); diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index e40c2fdd42..e430bbe0bf 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -770,12 +770,18 @@ int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len return(this->bleBeaconCommon(RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON, chan, payload, len)); } -int16_t LR11x0::getLoRaRxHeaderInfos(uint8_t* info) { +int16_t LR11x0::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) { + // check if in explicit header mode + if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + uint8_t buff[1] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS, false, buff, sizeof(buff)); // pass the replies - if(info) { *info = buff[0]; } + if(cr) { *cr = (buff[0] & 0x70) >> 4; } + if(hasCRC) { *hasCRC = (buff[0] & RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED) != 0; } return(state); } diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index d7c0af39d2..949c864d84 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1286,11 +1286,11 @@ float SX126x::getFrequencyError() { // read the raw frequency error register values uint8_t efeRaw[3] = {0}; - int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR, &efeRaw[0], 1); + int16_t state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC, &efeRaw[0], 1); RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 1, &efeRaw[1], 1); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC + 1, &efeRaw[1], 1); RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR + 2, &efeRaw[2], 1); + state = readRegister(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC + 2, &efeRaw[2], 1); RADIOLIB_ASSERT(state); uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2]; efe &= 0x0FFFFF; @@ -1331,6 +1331,20 @@ size_t SX126x::getPacketLength(bool update, uint8_t* offset) { return((size_t)rxBufStatus[0]); } +int16_t SX126x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) { + int16_t state = RADIOLIB_ERR_NONE; + + // check if in explicit header mode + if(this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX126X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; } + if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC, 4, 4) != 0); } + + return(state); +} + int16_t SX126x::fixedPacketLengthMode(uint8_t len) { return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2bcac6a642..9868081217 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -120,7 +120,8 @@ #define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 #define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 -#define RADIOLIB_SX126X_REG_FREQ_ERROR 0x076B +#define RADIOLIB_SX126X_REG_LORA_RX_CODING_RATE 0x0749 +#define RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC 0x076B #define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD #define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 #define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 @@ -977,6 +978,14 @@ class SX126x: public PhysicalLayer { */ size_t getPacketLength(bool update, uint8_t* offset); + /*! + \brief Get LoRa header information from last received packet. Only valid in explicit header mode. + \param cr Pointer to variable to store the coding rate. + \param hasCRC Pointer to variable to store the CRC status. + \returns \ref status_codes + */ + int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + /*! \brief Set modem in fixed packet length mode. Available in FSK mode only. \param len Packet length. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 0fcafd9f5c..b40b294c47 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1109,6 +1109,20 @@ size_t SX127x::getPacketLength(bool update) { return(this->packetLength); } +int16_t SX127x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) { + int16_t state = RADIOLIB_ERR_NONE; + + // check if in explicit header mode + if(this->implicitHdr) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_STAT, 7, 5) >> 5; } + if(hasCRC) { *hasCRC = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) != 0; } + + return(state); +} + int16_t SX127x::fixedPacketLengthMode(uint8_t len) { return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len)); } diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 37135f98e4..7600764970 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1007,6 +1007,14 @@ class SX127x: public PhysicalLayer { */ size_t getPacketLength(bool update = true) override; + /*! + \brief Get LoRa header information from last received packet. Only valid in explicit header mode. + \param cr Pointer to variable to store the coding rate. + \param hasCRC Pointer to variable to store the CRC status. + \returns \ref status_codes + */ + int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + /*! \brief Set modem in fixed packet length mode. Available in FSK mode only. \param len Packet length. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 0f50aa0d77..fbd7e8a234 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1299,6 +1299,20 @@ size_t SX128x::getPacketLength(bool update, uint8_t* offset) { return((size_t)rxBufStatus[0]); } +int16_t SX128x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) { + int16_t state = RADIOLIB_ERR_NONE; + + // check if in explicit header mode + if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; } + if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_FEI_MSB, 4, 4) != 0); } + + return(state); +} + int16_t SX128x::fixedPacketLengthMode(uint8_t len) { return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED, len)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 9f42f946f0..26f93783eb 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -84,6 +84,7 @@ #define RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION 0x093C #define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB 0x0944 #define RADIOLIB_SX128X_REG_LORA_SYNC_WORD_LSB 0x0945 +#define RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE 0x0950 #define RADIOLIB_SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 #define RADIOLIB_SX128X_REG_FEI_MSB 0x0954 #define RADIOLIB_SX128X_REG_FEI_MID 0x0955 @@ -797,6 +798,14 @@ class SX128x: public PhysicalLayer { */ size_t getPacketLength(bool update, uint8_t* offset); + /*! + \brief Get LoRa header information from last received packet. Only valid in explicit header mode. + \param cr Pointer to variable to store the coding rate. + \param hasCRC Pointer to variable to store the CRC status. + \returns \ref status_codes + */ + int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + /*! \brief Set modem in fixed packet length mode. Available in GFSK mode only. \param len Packet length. From 8833871aef1dd2405bd554b83ab9c3e8dada4f1f Mon Sep 17 00:00:00 2001 From: Marus Alexander Date: Fri, 5 Sep 2025 14:48:08 +0300 Subject: [PATCH 1596/1848] Fixed a small bug in receive() method --- src/modules/SX128x/SX128x.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index fbd7e8a234..98f05960e3 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -363,7 +363,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // calculate timeout (1000% of expected time-on-air) RadioLibTime_t timeout = getTimeOnAir(len) * 10; - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", (uint32_t)((timeout + 999) / 1000)); // start reception uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625f); @@ -372,11 +372,11 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout bool softTimeout = false; - RadioLibTime_t start = this->mod->hal->millis(); + RadioLibTime_t start = this->mod->hal->micros(); while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio - if(this->mod->hal->millis() - start > timeout) { + if(this->mod->hal->micros() - start > timeout) { softTimeout = true; break; } From bbb2e4e575816b9a5db41d43517b4e0217f0ab0d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 7 Sep 2025 17:45:10 +0200 Subject: [PATCH 1597/1848] [LoRaWAN] Add extra padding to prevent adrMasks overflow --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 80655ab3df..c1e0056857 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2701,7 +2701,9 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd // set Dr/Tx field from last MAC command mAdrOpt[0] = mPtr[cLen - fLen + 1]; - uint16_t adrMasks[RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS / 2]; + // extra 2 bytes are added on the end, because in theory, + // chMaskCntl can go up to 7 (though it probably shouldn't) + uint16_t adrMasks[(RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS / 2) + 2]; memcpy(adrMasks, this->channelMasks, sizeof(this->channelMasks)); // set NbTrans partial field from last MAC command From 7fc83f732cbbd13e7af917f9bf7a5cad5d5f8a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Wed, 10 Sep 2025 07:07:28 +0200 Subject: [PATCH 1598/1848] User-controlled timeout for blocking receive (#1592) * [PHY] Add timeout argument to blocking receive method * [PHY] Add finishReceive method for cleanup after Rx * [SX126x] Implement finishReceive method * [SX126x] Implement blocking receive timeout * [CC1101] Implement blocking receive timeout * [CC1101] Implement finishReceive * [nRF24] Implement blocking receive timeout * [nRF24] Implement finishReceive * [RF69] Implement finishReceive * [RF69] Implement finishReceive * [Si443x] Implement blocking receive timeout * [Si443x] Implement finishReceive * [SX128x] Implement blocking receive timeout * [SX128x] Implement finishReceive * [LR11x0] Implement blocking receive timeout * [LR11x0] Implement finishReceive * [SX127x] Implement blocking receive timeout * [SX127x] Implement finishReceive * Add finishReceive to keywords * [CC1101] Fix incorrect timeout reference * [SX126x] Simplify receive timeout duration (5x ToA instead of 100 symbols) * [LR11x0] Simplify receive timeout duration (5x ToA instead of 100 symbols) * [SX127x] Simplify receive timeout duration (5x ToA instead of 100 symbols) * Fix swapped order of operations in finishReceive * [SX128x] Add explanation regarding 10x timeout value --- keywords.txt | 1 + src/modules/CC1101/CC1101.cpp | 32 ++++--- src/modules/CC1101/CC1101.h | 14 ++- src/modules/LR11x0/LR11x0.cpp | 64 ++++++------- src/modules/LR11x0/LR11x0.h | 14 ++- src/modules/RF69/RF69.cpp | 26 ++++-- src/modules/RF69/RF69.h | 14 ++- src/modules/SX126x/SX126x.cpp | 64 ++++++------- src/modules/SX126x/SX126x.h | 14 ++- src/modules/SX127x/SX127x.cpp | 92 +++++++++---------- src/modules/SX127x/SX127x.h | 10 +- src/modules/SX128x/SX128x.cpp | 23 ++++- src/modules/SX128x/SX128x.h | 14 ++- src/modules/Si443x/Si443x.cpp | 26 +++--- src/modules/Si443x/Si443x.h | 10 +- src/modules/nRF24/nRF24.cpp | 24 +++-- src/modules/nRF24/nRF24.h | 18 +++- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 11 ++- src/protocols/PhysicalLayer/PhysicalLayer.h | 16 +++- 19 files changed, 300 insertions(+), 187 deletions(-) diff --git a/keywords.txt b/keywords.txt index 9a7accd944..b723abc423 100644 --- a/keywords.txt +++ b/keywords.txt @@ -133,6 +133,7 @@ startTransmit KEYWORD2 finishTransmit KEYWORD2 startReceive KEYWORD2 readData KEYWORD2 +finishReceive KEYWORD2 startChannelScan KEYWORD2 getChannelScanResult KEYWORD2 setBandwidth KEYWORD2 diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index bd89c706f2..6078ddf39d 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -58,9 +58,12 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t CC1101::receive(uint8_t* data, size_t len) { - // calculate timeout (500 ms + 400 full max-length packets at current bit rate) - RadioLibTime_t timeout = 500 + (1.0f/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0f); +int16_t CC1101::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + // calculate timeout (500 ms + 400 full max-length packets at current bit rate) + timeoutInternal = 500 + (1.0f/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0f); + } // start reception int16_t state = startReceive(); @@ -71,9 +74,8 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->millis() - start > timeout) { - standby(); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + if(this->mod->hal->millis() - start > timeoutInternal) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -83,9 +85,8 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->millis() - start > timeout) { - standby(); - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + if(this->mod->hal->millis() - start > timeoutInternal) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -410,17 +411,18 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) if(SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { - - // set mode to standby - standby(); - - // flush Rx FIFO - SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + finishReceive(); } return(state); } +int16_t CC1101::finishReceive() { + int16_t state = standby(); + SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); + return(state); +} + int16_t CC1101::setFrequency(float freq) { // check allowed frequency range #if RADIOLIB_CHECK_PARAMS diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 8dd68bea84..f416f9dec5 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -597,11 +597,13 @@ class CC1101: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Sets the module to standby mode. @@ -747,6 +749,12 @@ class CC1101: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; + // configuration methods /*! diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 4bcc5c6445..573cd8557f 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -223,44 +223,38 @@ int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t LR11x0::receive(uint8_t* data, size_t len) { +int16_t LR11x0::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); - RadioLibTime_t timeout = 0; + // calculate timeout based on the configured modem + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + // get currently active modem + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) { + // calculate timeout (500 % of expected time-one-air) + size_t maxLen = len; + if(len == 0) { maxLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; } + timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000; + + } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + // this modem cannot receive + return(RADIOLIB_ERR_WRONG_MODEM); - // get currently active modem - uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - state = getPacketType(&modem); - RADIOLIB_ASSERT(state); - if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { - // calculate timeout (100 LoRa symbols, the default for SX127x series) - float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (RadioLibTime_t)(symbolLength * 100.0f); - - } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - // calculate timeout (500 % of expected time-one-air) - size_t maxLen = len; - if(len == 0) { - maxLen = 0xFF; + } else { + return(RADIOLIB_ERR_UNKNOWN); + } - float brBps = ((float)(RADIOLIB_LR11X0_CRYSTAL_FREQ) * 1000000.0f * 32.0f) / (float)this->bitRate; - timeout = (RadioLibTime_t)(((maxLen * 8.0f) / brBps) * 1000.0f * 5.0f); - - } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { - // this modem cannot receive - return(RADIOLIB_ERR_WRONG_MODEM); - - } else { - return(RADIOLIB_ERR_UNKNOWN); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal); // start reception - uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0f) / 30.52f); + uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 30.52f); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); @@ -270,7 +264,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio - if(this->mod->hal->millis() - start > timeout) { + if(this->mod->hal->millis() - start > timeoutInternal) { softTimeout = true; break; } @@ -285,8 +279,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) { // check whether this was a timeout or not if((getIrqStatus() & RADIOLIB_LR11X0_IRQ_TIMEOUT) || softTimeout) { - standby(); - clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -480,6 +473,15 @@ int16_t LR11x0::readData(uint8_t* data, size_t len) { return(state); } +int16_t LR11x0::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + return(clearIrqState(RADIOLIB_LR11X0_IRQ_ALL)); +} + int16_t LR11x0::startChannelScan() { ChannelScanConfig_t cfg = { .cad = { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 612bbbad2a..4a9f30e63d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -991,11 +991,13 @@ class LR11x0: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Starts direct mode transmission. @@ -1119,6 +1121,12 @@ class LR11x0: public PhysicalLayer { \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; /*! \brief Interrupt-driven channel activity detection method. IRQ1 will be activated diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 72b3b9b233..c47f6d07ea 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -122,9 +122,12 @@ int16_t RF69::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t RF69::receive(uint8_t* data, size_t len) { - // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - RadioLibTime_t timeout = 500 + (1.0f/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0f); +int16_t RF69::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) + timeoutInternal = 500 + (1.0f/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0f); + } // start reception int16_t state = startReceive(); @@ -135,9 +138,8 @@ int16_t RF69::receive(uint8_t* data, size_t len) { while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - if(this->mod->hal->millis() - start > timeout) { - standby(); - clearIRQFlags(); + if(this->mod->hal->millis() - start > timeoutInternal) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -477,12 +479,20 @@ int16_t RF69::readData(uint8_t* data, size_t len) { // clear internal flag so getPacketLength can return the new packet length this->packetLengthQueried = false; - // clear interrupt flags - clearIRQFlags(); + finishReceive(); return(RADIOLIB_ERR_NONE); } +int16_t RF69::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + + // clear interrupt flags + clearIRQFlags(); + return(state); +} + int16_t RF69::setOOK(bool enable) { // set OOK and if successful, save the new setting int16_t state = RADIOLIB_ERR_NONE; diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 86ef9303c7..bcdd1800d9 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -528,11 +528,13 @@ class RF69: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Sets the module to sleep mode. @@ -727,6 +729,12 @@ class RF69: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; + // configuration methods /*! diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 949c864d84..1eec8e2f81 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -249,38 +249,23 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t SX126x::receive(uint8_t* data, size_t len) { +int16_t SX126x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); - RadioLibTime_t timeout = 0; - - // get currently active modem - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - // calculate timeout (100 LoRa symbols, the default for SX127x series) - float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - timeout = (RadioLibTime_t)(symbolLength * 100.0f); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { // calculate timeout (500 % of expected time-one-air) size_t maxLen = len; - if(len == 0) { - maxLen = 0xFF; - } - float brBps = (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (float)this->bitRate; - timeout = (RadioLibTime_t)(((maxLen * 8.0f) / brBps) * 1000.0f * 5.0f); - - } else { - return(RADIOLIB_ERR_UNKNOWN); - + if(len == 0) { maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH; } + timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000; } - RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal); // start reception - uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0f) / 15.625f); + uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 15.625f); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); @@ -290,7 +275,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); // safety check, the timeout should be done by the radio - if(this->mod->hal->millis() - start > timeout) { + if(this->mod->hal->millis() - start > timeoutInternal) { softTimeout = true; break; } @@ -302,20 +287,16 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { return(state); } + // cache the IRQ flags and clean up after reception + uint32_t irqFlags = getIrqFlags(); + state = finishReceive(); + RADIOLIB_ASSERT(state); + // check whether this was a timeout or not - if((getIrqFlags() & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { - standby(); - fixImplicitTimeout(); - clearIrqStatus(); + if((irqFlags & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { return(RADIOLIB_ERR_RX_TIMEOUT); } - // fix timeout in implicit LoRa mode - if(((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { - state = fixImplicitTimeout(); - RADIOLIB_ASSERT(state); - } - // read the received data return(readData(data, len)); } @@ -529,6 +510,20 @@ int16_t SX126x::finishTransmit() { return(standby()); } +int16_t SX126x::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // try to fix timeout error in implicit header mode + // check for modem type and header mode is done in fixImplicitTimeout() + state = fixImplicitTimeout(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + return(clearIrqStatus()); +} + int16_t SX126x::startReceive() { return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } @@ -2200,7 +2195,8 @@ int16_t SX126x::fixImplicitTimeout() { //check if we're in implicit LoRa mode if(!((this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) { - return(RADIOLIB_ERR_WRONG_MODEM); + // not in the correct mode, nothing to do here + return(RADIOLIB_ERR_NONE); } // stop RTC counter diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 9868081217..2817399406 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -567,11 +567,13 @@ class SX126x: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Starts direct mode transmission. @@ -689,6 +691,12 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ int16_t finishTransmit() override; + + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; /*! \brief Interrupt-driven receive method with default parameters. diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b40b294c47..d13064b6b2 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -211,68 +211,55 @@ int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t SX127x::receive(uint8_t* data, size_t len) { +int16_t SX127x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { // set mode to standby int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - // set mode to receive - state = startReceive(100, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len); - RADIOLIB_ASSERT(state); + // calculate timeout based on the configured modem + RadioLibTime_t timeoutInternal = timeout; + uint32_t timeoutValue = 0; + if(!timeoutInternal) { + // calculate timeout (500 % of expected time-one-air) + size_t maxLen = len; + if(len == 0) { maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH; } + timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000; - // if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout) - RadioLibTime_t timeout = 0; - if(this->mod->getGpio() == RADIOLIB_NC) { - float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - timeout = (RadioLibTime_t)(symbolLength * 100.0f); - } + // convert to symbols + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + timeoutValue = (float)timeoutInternal / symbolLength; + } - // wait for packet reception or timeout - RadioLibTime_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal); - if(this->mod->getGpio() == RADIOLIB_NC) { - // no GPIO pin provided, use software timeout - if(this->mod->hal->millis() - start > timeout) { - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - return(RADIOLIB_ERR_RX_TIMEOUT); - } - } else { - // GPIO provided, use that - if(this->mod->hal->digitalRead(this->mod->getGpio())) { - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - return(RADIOLIB_ERR_RX_TIMEOUT); - } - } + // start reception + state = startReceive(timeoutValue, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len); + RADIOLIB_ASSERT(state); + // wait for packet reception or timeout + bool softTimeout = false; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + // check the blocking timeout + if(this->mod->hal->millis() - start > timeoutInternal) { + softTimeout = true; + break; } + } - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // calculate timeout in ms (500 % of expected time-on-air) - RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000; - - // set mode to receive - state = startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len); - RADIOLIB_ASSERT(state); + // cache the IRQ flags and clean up after reception + uint16_t irqFlags = getIRQFlags(); + state = finishReceive(); + RADIOLIB_ASSERT(state); - // wait for packet reception or timeout - RadioLibTime_t start = this->mod->hal->millis(); - while(!this->mod->hal->digitalRead(this->mod->getIrq())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start > timeout) { - clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); - return(RADIOLIB_ERR_RX_TIMEOUT); - } - } + // check whether this was a timeout or not + if(softTimeout || (irqFlags & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + return(RADIOLIB_ERR_RX_TIMEOUT); } // read the received data - state = readData(data, len); - - return(state); + return(readData(data, len)); } int16_t SX127x::scanChannel() { @@ -583,6 +570,15 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { return(state); } +int16_t SX127x::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + return(clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL)); +} + int16_t SX127x::startChannelScan() { // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 7600764970..db0d8e803f 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -641,9 +641,11 @@ class SX127x: public PhysicalLayer { For overloads to receive Arduino String, see PhysicalLayer::receive. \param data Pointer to array to save the received binary data. \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Performs scan for valid %LoRa preamble in the current channel. @@ -822,6 +824,12 @@ class SX127x: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; + /*! \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected. DIO1 will be activated if there's no preamble detected before timeout. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 98f05960e3..89e163329e 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -350,7 +350,7 @@ int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t SX128x::receive(uint8_t* data, size_t len) { +int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { // check active modem uint8_t modem = getPacketType(); if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) { @@ -362,11 +362,16 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // calculate timeout (1000% of expected time-on-air) - RadioLibTime_t timeout = getTimeOnAir(len) * 10; + // for most other modules, it is 500%, however, the overall datarates of SX128x are higher + // so we use higher value for the default timeout + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + timeoutInternal = getTimeOnAir(len) * 10; + } RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", (uint32_t)((timeout + 999) / 1000)); // start reception - uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625f); + uint32_t timeoutValue = (uint32_t)((float)timeoutInternal / 15.625f); state = startReceive(timeoutValue); RADIOLIB_ASSERT(state); @@ -390,8 +395,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { // check whether this was a timeout or not if((getIrqStatus() & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT) || softTimeout) { - standby(); - clearIrqStatus(); + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } @@ -566,6 +570,15 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { return(state); } +int16_t SX128x::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + return(clearIrqStatus()); +} + uint32_t SX128x::getIrqFlags() { return((uint32_t)this->getIrqStatus()); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 26f93783eb..e4d8535922 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -435,11 +435,13 @@ class SX128x: public PhysicalLayer { /*! \brief Blocking binary receive method. Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Starts direct mode transmission. @@ -562,6 +564,12 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; /*! \brief Read currently active IRQ flags. diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 4eb32e3457..4d2e866309 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -97,9 +97,12 @@ int16_t Si443x::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t Si443x::receive(uint8_t* data, size_t len) { - // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) - RadioLibTime_t timeout = 500 + (1.0f/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0f); +int16_t Si443x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + // calculate timeout (500 ms + 400 full max-length packets at current bit rate) + timeoutInternal = 500 + (1.0f/(this->bitRate))*(RADIOLIB_SI443X_MAX_PACKET_LENGTH*400.0f); + } // start reception int16_t state = startReceive(); @@ -108,9 +111,8 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout RadioLibTime_t start = this->mod->hal->millis(); while(this->mod->hal->digitalRead(this->mod->getIrq())) { - if(this->mod->hal->millis() - start > timeout) { - standby(); - clearIrqStatus(); + if(this->mod->hal->millis() - start > timeoutInternal) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -345,14 +347,16 @@ int16_t Si443x::readData(uint8_t* data, size_t len) { // clear internal flag so getPacketLength can return the new packet length this->packetLengthQueried = false; - // set mode to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); + return(finishReceive()); +} +int16_t Si443x::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + // clear interrupt flags clearIrqStatus(); - - return(RADIOLIB_ERR_NONE); + return(state); } int16_t Si443x::setBitRate(float br) { diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 286c9937ac..93bd9c9310 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -598,9 +598,11 @@ class Si443x: public PhysicalLayer { For overloads to receive Arduino String, see PhysicalLayer::receive. \param data Pointer to array to save the received binary data. \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. @@ -717,6 +719,12 @@ class Si443x: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; + // configuration methods /*! diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index c46404ee40..10cad0d26a 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -110,7 +110,13 @@ int16_t nRF24::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(finishTransmit()); } -int16_t nRF24::receive(uint8_t* data, size_t len) { +int16_t nRF24::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + // calculate timeout (15 retries * 4ms (max Tx time as per datasheet) + 10 ms) + timeoutInternal = ((15 * 4) + 10); + } + // start reception int16_t state = startReceive(); RADIOLIB_ASSERT(state); @@ -120,10 +126,9 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { while(this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); - // check timeout: 15 retries * 4ms (max Tx time as per datasheet) + 10 ms - if(this->mod->hal->millis() - start >= ((15 * 4) + 10)) { - standby(); - clearIRQ(); + // check timeout + if(this->mod->hal->millis() - start >= timeoutInternal) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -274,10 +279,15 @@ int16_t nRF24::readData(uint8_t* data, size_t len) { // read packet data SPIreadRxPayload(data, length); - // clear interrupt + return(finishReceive()); +} + +int16_t nRF24::finishReceive() { + // clear interrupt flags clearIRQ(); - return(RADIOLIB_ERR_NONE); + // set mode to standby to disable transmitter/RF switch + return(standby()); } int16_t nRF24::setFrequency(float freq) { diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 48d21fe7a7..686a63c595 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -243,13 +243,15 @@ class nRF24: public PhysicalLayer { int16_t transmit(const uint8_t* data, size_t len, uint8_t addr) override; /*! - \brief Blocking binary receive method. - Overloads for string-based transmissions are implemented in PhysicalLayer. - \param data Binary data to be sent. - \param len Number of bytes to send. + \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long. + For overloads to receive Arduino String, see PhysicalLayer::receive. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len) override; + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; /*! \brief Starts direct mode transmission. @@ -340,6 +342,12 @@ class nRF24: public PhysicalLayer { */ int16_t readData(uint8_t* data, size_t len) override; + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; + // configuration methods /*! diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index e698092c1f..4036f67f35 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -62,7 +62,7 @@ int16_t PhysicalLayer::transmit(const uint8_t* data, size_t len, uint8_t addr) { } #if defined(RADIOLIB_BUILD_ARDUINO) -int16_t PhysicalLayer::receive(String& str, size_t len) { +int16_t PhysicalLayer::receive(String& str, size_t len, RadioLibTime_t timeout) { int16_t state = RADIOLIB_ERR_NONE; // user can override the length of data to read @@ -82,7 +82,7 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { #endif // attempt packet reception - state = receive(data, length); + state = receive(data, length, timeout); // any of the following leads to at least some data being available // let's leave the decision of whether to keep it or not up to the user @@ -108,9 +108,10 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { } #endif -int16_t PhysicalLayer::receive(uint8_t* data, size_t len) { +int16_t PhysicalLayer::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { (void)data; (void)len; + (void)timeout; return(RADIOLIB_ERR_UNSUPPORTED); } @@ -174,6 +175,10 @@ int16_t PhysicalLayer::finishTransmit() { return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t PhysicalLayer::finishReceive() { + return(RADIOLIB_ERR_UNSUPPORTED); +} + #if defined(RADIOLIB_BUILD_ARDUINO) int16_t PhysicalLayer::readData(String& str, size_t len) { int16_t state = RADIOLIB_ERR_NONE; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 273bd61bbc..f61c6434e7 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -275,10 +275,12 @@ class PhysicalLayer { /*! \brief Arduino String receive method. \param str Address of Arduino String to save the received data. - \param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet + \param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - int16_t receive(String& str, size_t len = 0); + int16_t receive(String& str, size_t len = 0, RadioLibTime_t timeout = 0); #endif /*! @@ -321,9 +323,11 @@ class PhysicalLayer { \brief Binary receive method. Must be implemented in module class. \param data Pointer to array to save the received binary data. \param len Packet length, needed for some modules under special circumstances (e.g. LoRa implicit header mode). + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ - virtual int16_t receive(uint8_t* data, size_t len); + virtual int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0); #if defined(RADIOLIB_BUILD_ARDUINO) /*! @@ -360,6 +364,12 @@ class PhysicalLayer { */ virtual int16_t finishTransmit(); + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + virtual int16_t finishReceive(); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Reads data that was received after calling startReceive method. From d27d98874cf488bbc2d56d3655d38f344baca16f Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 15 Sep 2025 16:29:07 +0200 Subject: [PATCH 1599/1848] [SX126x] Add comment regarding preamble length for duty cycle Rx (#1597) --- src/modules/SX126x/SX126x.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 2817399406..5114f23c45 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -724,6 +724,8 @@ class SX126x: public PhysicalLayer { \brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages. \param senderPreambleLength Expected preamble length of the messages to receive. If set to zero, the currently configured preamble length will be used. Defaults to zero. + If the sender preamble length is variable or unknown, the maximum expected size should be configured + on the receiver side by calling setPreambleLength prior to startReceiveDutyCycleAuto. \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols of any preamble of the specified length. Defaults to 8. From 334c003a27f1053cd9739963d243f7d02e6c8f38 Mon Sep 17 00:00:00 2001 From: Chris Leishman Date: Tue, 16 Sep 2025 21:55:47 -0700 Subject: [PATCH 1600/1848] [SX126x] No need to call standby() after a verified reset (#1603) --- src/modules/SX126x/SX126x.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1eec8e2f81..c10bbdf31c 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -2261,12 +2261,8 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) } RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); + // reset the module and verify startup (module will be in standby mode after this) + int16_t state = reset(true); RADIOLIB_ASSERT(state); // set TCXO control, if requested From b49314d0bb57db06d710d52aa9f83336a1c6fc9c Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 17 Sep 2025 07:09:25 +0200 Subject: [PATCH 1601/1848] [LR11x0] Use IRQ value from map --- src/modules/LR11x0/LR11x0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 573cd8557f..c3a4086aff 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -278,7 +278,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { } // check whether this was a timeout or not - if((getIrqStatus() & RADIOLIB_LR11X0_IRQ_TIMEOUT) || softTimeout) { + if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } From 198d1697a36a27efa099a8aefcede0aaff06e0e1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 17 Sep 2025 07:09:33 +0200 Subject: [PATCH 1602/1848] [SX128x] Use IRQ value from map --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 89e163329e..491a99eb56 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -394,7 +394,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { } // check whether this was a timeout or not - if((getIrqStatus() & RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT) || softTimeout) { + if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } From 04b4eb95b6be738a4da852f272bb58a716bc28a5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 17 Sep 2025 07:10:37 +0200 Subject: [PATCH 1603/1848] [SX127x] Fix finishReceive clearing IRQ flags prematurely (#1592) --- src/modules/SX127x/SX127x.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index d13064b6b2..3ae6c1b317 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -248,13 +248,9 @@ int16_t SX127x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { } } - // cache the IRQ flags and clean up after reception - uint16_t irqFlags = getIRQFlags(); - state = finishReceive(); - RADIOLIB_ASSERT(state); - // check whether this was a timeout or not - if(softTimeout || (irqFlags & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } From fc7becd6f507a07daf98a5f09b75b591becfc0ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 17 Sep 2025 07:10:55 +0200 Subject: [PATCH 1604/1848] [SX126x] Fix finishReceive clearing IRQ flags prematurely (#1592) --- src/modules/SX126x/SX126x.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c10bbdf31c..fb31f50d35 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -287,13 +287,9 @@ int16_t SX126x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { return(state); } - // cache the IRQ flags and clean up after reception - uint32_t irqFlags = getIrqFlags(); - state = finishReceive(); - RADIOLIB_ASSERT(state); - // check whether this was a timeout or not - if((irqFlags & RADIOLIB_SX126X_IRQ_TIMEOUT) || softTimeout) { + if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } From d7c7718b72ebc2e1310ea8b52b013e5bc8b5482f Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 17 Sep 2025 07:15:32 +0200 Subject: [PATCH 1605/1848] Fix typo in method names --- src/modules/LR11x0/LR11x0.cpp | 2 +- src/modules/SX128x/SX128x.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index c3a4086aff..26ee791dcc 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -278,7 +278,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { } // check whether this was a timeout or not - if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 491a99eb56..798e6d19b4 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -394,7 +394,7 @@ int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { } // check whether this was a timeout or not - if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + if(softTimeout || (getIrqStatus() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } From 3220774a1fc9e767810918caf52fafc6273eb22b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 17 Sep 2025 07:18:20 +0200 Subject: [PATCH 1606/1848] [SX126x] Fix typo in method names (#1592) --- src/modules/SX126x/SX126x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index fb31f50d35..b29a29699b 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -288,7 +288,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { } // check whether this was a timeout or not - if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { (void)finishReceive(); return(RADIOLIB_ERR_RX_TIMEOUT); } From 804470eff1fb03d53a2bc7ffc06e311da5194013 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Wed, 17 Sep 2025 17:08:19 +0200 Subject: [PATCH 1607/1848] Add `calculateTimeOnAir()` method to relevant modules (#1596) * [PhysicalLayer] Add packet configurations * Add `calculateTimeOnAir()` method to relevant modules * Add calculateTimeOnAir to keywords.txt * Add TOA unit tests * Remove old methods and equivalance tests * Explicitly assign all struct members * Fix cppcheck errors * [SX127x] Make `reset()` and `errataFix()` virtual --- extras/test/unit/CMakeLists.txt | 1 + .../unit/tests/TestCalculateTimeOnAir.cpp | 67 ++++++++ keywords.txt | 1 + src/modules/LR11x0/LR11x0.cpp | 149 +++++++++------- src/modules/LR11x0/LR11x0.h | 10 ++ src/modules/SX126x/SX126x.cpp | 160 ++++++++++++------ src/modules/SX126x/SX126x.h | 10 ++ src/modules/SX127x/SX1272.cpp | 3 + src/modules/SX127x/SX1272.h | 6 - src/modules/SX127x/SX1278.cpp | 3 + src/modules/SX127x/SX1278.h | 6 - src/modules/SX127x/SX127x.cpp | 114 +++++++++---- src/modules/SX127x/SX127x.h | 24 ++- src/modules/SX128x/SX128x.cpp | 77 ++++++--- src/modules/SX128x/SX128x.h | 12 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 44 ++++- 16 files changed, 498 insertions(+), 189 deletions(-) create mode 100644 extras/test/unit/tests/TestCalculateTimeOnAir.cpp diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt index a3943e84f2..49e222e915 100644 --- a/extras/test/unit/CMakeLists.txt +++ b/extras/test/unit/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR file(GLOB_RECURSE TEST_SOURCES "tests/main.cpp" "tests/TestModule.cpp" + "tests/TestCalculateTimeOnAir.cpp" ) # create the executable diff --git a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp new file mode 100644 index 0000000000..56d0d04df4 --- /dev/null +++ b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp @@ -0,0 +1,67 @@ +#include +#include "modules/SX126x/SX126x.h" +#include "modules/SX127x/SX127x.h" +#include "modules/SX128x/SX128x.h" +#include "modules/LR11x0/LR11x0.h" + +// --- Config structure --- +struct RadioConfig { + std::string name; // Radio name + ModemType_t modem; + DataRate_t dr; + PacketConfig_t pc; + std::vector payload_len; + std::vector expected_toa; // Expected time on air in microseconds from Semtech calculators +}; + +// --- Test configurations with golden values --- +std::vector allConfigs = { + { "SX126x", RADIOLIB_MODEM_LORA, {.lora={7,125,5}}, {.lora={8,false,true,true}}, {1,10,50,255}, {30976,46336,128256,548096} }, // 30.97, 46.33, 128.25, 548.09 + { "SX126x", RADIOLIB_MODEM_LORA, {.lora={11,250,8}}, {.lora={16,true,false,false}}, {5,15,100,200}, {296960,362496,1411072,2590720} }, // 296.96, 362.49, 1410, 2590 + { "SX126x", RADIOLIB_MODEM_FSK, {.fsk={100,10}}, {.fsk={16,16,2}}, {1,16,64,200}, {560,1760,5600,16480} }, + { "SX126x", RADIOLIB_MODEM_LRFHSS,{.lrFhss={RADIOLIB_LR11X0_LR_FHSS_BW_386_72,RADIOLIB_SX126X_LR_FHSS_CR_2_3,false}}, {.lrFhss={2}}, {1,20,100}, {3784697,4259832,6324212} }, + + { "SX127x", RADIOLIB_MODEM_LORA, {.lora={6,125,6}}, {.lora={8,false,true,false}}, {7,23,98,156}, {23000,39000,115000,174000} }, // 20.61, 39.04, 115.84, 174.21 + { "SX127x", RADIOLIB_MODEM_LORA, {.lora={8,250,8}}, {.lora={32,true,true,false}}, {10,20,80,160}, {70000,87000,210000,373000} }, // 69.89, 86.27, 209.15, 372.99 + { "SX127x", RADIOLIB_MODEM_FSK, {.fsk={100,5}}, {.fsk={16,16,3}}, {1,16,32,61}, {640,1840,3120,5440} }, + + { "SX128x", RADIOLIB_MODEM_LORA, {.lora={5,400,5}}, {.lora={8,false,true,false}}, {1,50,200}, {2580,10179,34180} }, // 2.54, 10.02, 33.65 + { "SX128x", RADIOLIB_MODEM_LORA, {.lora={12,800,7}}, {.lora={16,false,true,true}}, {10,100,250}, {216319,861440,1936640} }, // 212.99, 848.19, 1910 + { "SX128x", RADIOLIB_MODEM_FSK, {.fsk={250,100}}, {.fsk={16,16,2}}, {1,32,64,128}, {224,1216,2240,4288} }, + + { "LR11x0", RADIOLIB_MODEM_LORA, {.lora={10,250,5}}, {.lora={8,false,true,true}}, {1,20,100}, {103424,205824,615424} }, // 103.42, 205.82, 615.42 + { "LR11x0", RADIOLIB_MODEM_LORA, {.lora={11,500,6}}, {.lora={32,true,false,false}}, {10,25,200}, {205824,279552,1065984} }, // 205.82, 279.55, 1070 + { "LR11x0", RADIOLIB_MODEM_FSK, {.fsk={200,50}}, {.fsk={16,32,2}}, {1,32,64,200}, {360,1600,2880,8320} }, + { "LR11x0", RADIOLIB_MODEM_LRFHSS,{.lrFhss={RADIOLIB_LR11X0_LR_FHSS_BW_136_72,RADIOLIB_LR11X0_LR_FHSS_CR_1_3,true}}, {.lrFhss={1}}, {1,10,50}, {1949692,2392059,4456440} }, +}; + +BOOST_AUTO_TEST_SUITE(suite_TimeOnAir) + +BOOST_AUTO_TEST_CASE(TimeOnAir_AllRadios) { + for (const auto& cfg : allConfigs) { + BOOST_TEST_MESSAGE("--- Test calculateTimeOnAir " << cfg.name << ", modem=" << cfg.modem << " ---"); + + for (size_t i = 0; i < cfg.payload_len.size(); i++) { + auto len = cfg.payload_len[i]; + RadioLibTime_t toa = 0; + + if (cfg.name == "SX126x") { + SX126x dummy(nullptr); + toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); + } else if (cfg.name == "SX127x") { + SX127x dummy(nullptr); + toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); + } else if (cfg.name == "SX128x") { + SX128x dummy(nullptr); + toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); + } else if (cfg.name == "LR11x0") { + LR11x0 dummy(nullptr); + toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); + } + + BOOST_CHECK_EQUAL(toa, cfg.expected_toa[i]); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/keywords.txt b/keywords.txt index b723abc423..8f92c34eb9 100644 --- a/keywords.txt +++ b/keywords.txt @@ -230,6 +230,7 @@ beginFSK4 KEYWORD2 setTCXO KEYWORD2 setDio2AsRfSwitch KEYWORD2 getTimeOnAir KEYWORD2 +calculateTimeOnAir KEYWORD2 implicitHeader KEYWORD2 explicitHeader KEYWORD2 setSyncBits KEYWORD2 diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 26ee791dcc..2d97aa7176 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1203,71 +1203,44 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { return((size_t)len); } -RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { +RadioLibTime_t LR11x0::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { // check active modem - uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - (void)getPacketType(&type); - if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { - // calculate number of symbols - float N_symbol = 0; - if(this->codingRate <= RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) { - // legacy coding rate - nice and simple - - // get SF coefficients - float coeff1 = 0; - int16_t coeff2 = 0; - int16_t coeff3 = 0; - if(this->spreadingFactor < 7) { - // SF5, SF6 - coeff1 = 6.25; - coeff2 = 4*this->spreadingFactor; - coeff3 = 4*this->spreadingFactor; - } else if(this->spreadingFactor < 11) { - // SF7. SF8, SF9, SF10 - coeff1 = 4.25; - coeff2 = 4*this->spreadingFactor + 8; - coeff3 = 4*this->spreadingFactor; - } else { - // SF11, SF12 - coeff1 = 4.25; - coeff2 = 4*this->spreadingFactor + 8; - coeff3 = 4*(this->spreadingFactor - 2); - } - - // get CRC length - int16_t N_bitCRC = 16; - if(this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_DISABLED) { - N_bitCRC = 0; - } - - // get header length - int16_t N_symbolHeader = 20; - if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) { - N_symbolHeader = 0; - } - - // calculate number of LoRa preamble symbols - uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); - - // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); - - } else { - // long interleaving - abandon hope all ye who enter here - /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 + if (modem == ModemType_t::RADIOLIB_MODEM_LORA) { + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ; + uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) + uint8_t sfCoeff2 = 8; + if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) { + sfCoeff1_x4 = 25; // 6.25 * 4 + sfCoeff2 = 0; + } + uint8_t sfDivisor = 4*dr.lora.spreadingFactor; + if(pc.lora.ldrOptimize) { + sfDivisor = 4*(dr.lora.spreadingFactor - 2); + } + const int8_t bitsPerCrc = 16; + const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20; + // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) + int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header; + if(bitCount < 0) { + bitCount = 0; } + // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) + uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + + // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit + uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4; // get time-on-air in us - return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0f); + return((symbolLength_us * nSymbol_x4) / 4); - } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - return(((uint32_t)len * 8 * 1000000UL) / this->bitRate); - - } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + } else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) { + return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f))); + + } else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) { // calculate the number of bits based on coding rate uint16_t N_bits; - switch(this->lrFhssCr) { + switch(dr.lrFhss.cr) { case RADIOLIB_LR11X0_LR_FHSS_CR_5_6: N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? break; @@ -1292,14 +1265,74 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { } // add header bits - uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + N_payBits; + uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits; return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); } return(0); } +RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { + ModemType_t modem; + int32_t state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + + DataRate_t dr = {}; + PacketConfig_t pc = {}; + switch(modem) { + case ModemType_t::RADIOLIB_MODEM_LORA: { + uint8_t cr = this->codingRate; + // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values + if (cr < 5) { + cr = cr + 4; + } else if (cr == 7) { + cr = cr + 1; + } + + dr.lora.spreadingFactor = this->spreadingFactor; + dr.lora.bandwidth = this->bandwidthKhz; + dr.lora.codingRate = cr; + + pc.lora.preambleLength = this->preambleLengthLoRa; + pc.lora.implicitHeader = (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) ? true : false; + pc.lora.crcEnabled = (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED) ? true : false; + pc.lora.ldrOptimize = (bool)this->ldrOptimize; + break; + } + case ModemType_t::RADIOLIB_MODEM_FSK: { + dr.fsk.bitRate = (float)this->bitRate / 1000.0f; + dr.fsk.freqDev = (float)this->frequencyDev; + + uint8_t crcLen = 0; + if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV) { + crcLen = 1; + } else if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV) { + crcLen = 2; + } + + pc.fsk.preambleLength = this->preambleLengthGFSK; + pc.fsk.syncWordLength = this->syncWordLength; + pc.fsk.crcLength = crcLen; + break; + } + case ModemType_t::RADIOLIB_MODEM_LRFHSS: { + dr.lrFhss.bw = this->lrFhssBw; + dr.lrFhss.cr = this->lrFhssCr; + dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC) ? true : false; + + pc.lrFhss.hdrCount = this->lrFhssHdrCount; + break; + } + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(this->calculateTimeOnAir(modem, dr, pc, len)); +} + RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) { // the timeout value is given in units of 30.52 microseconds // the calling function should provide some extra width, as this number of units is truncated to integer diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 4a9f30e63d..2d00cbb063 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1372,6 +1372,16 @@ class LR11x0: public PhysicalLayer { */ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + /*! + \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. + \param modem Modem type. + \param dr Data rate. + \param pc Packet config. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + /*! \brief Get expected time-on-air for a given size of payload \param len Payload length in bytes. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index b29a29699b..c6e7f65d20 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1344,75 +1344,123 @@ int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen)); } -RadioLibTime_t SX126x::getTimeOnAir(size_t len) { +RadioLibTime_t SX126x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; - uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) - uint8_t sfCoeff2 = 8; - if(this->spreadingFactor == 5 || this->spreadingFactor == 6) { - sfCoeff1_x4 = 25; // 6.25 * 4 - sfCoeff2 = 0; + switch (modem) { + case RADIOLIB_MODEM_LORA: { + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ; + uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) + uint8_t sfCoeff2 = 8; + if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) { + sfCoeff1_x4 = 25; // 6.25 * 4 + sfCoeff2 = 0; + } + uint8_t sfDivisor = 4*dr.lora.spreadingFactor; + if(pc.lora.ldrOptimize) { + sfDivisor = 4*(dr.lora.spreadingFactor - 2); + } + const int8_t bitsPerCrc = 16; + const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20; + + // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) + int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header; + if(bitCount < 0) { + bitCount = 0; + } + // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) + uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + + // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit + uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4; + + return((symbolLength_us * nSymbol_x4) / 4); } - uint8_t sfDivisor = 4*this->spreadingFactor; - if(symbolLength_us >= 16000) { - sfDivisor = 4*(this->spreadingFactor - 2); + case RADIOLIB_MODEM_FSK: { + return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f))); } - const int8_t bitsPerCrc = 16; - const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; + case RADIOLIB_MODEM_LRFHSS: { + // calculate the number of bits based on coding rate + uint16_t N_bits; + switch(dr.lrFhss.cr) { + case RADIOLIB_SX126X_LR_FHSS_CR_5_6: + N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? + break; + case RADIOLIB_SX126X_LR_FHSS_CR_2_3: + N_bits = (len * 3) / 2; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_2: + N_bits = len * 2; + break; + case RADIOLIB_SX126X_LR_FHSS_CR_1_3: + N_bits = len * 3; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + // calculate number of bits when accounting for unaligned last block + uint16_t N_payBits = (N_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS; + uint16_t N_lastBlockBits = N_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS; + if(N_lastBlockBits) { + N_payBits += N_lastBlockBits + 2; + } - // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) - int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header; - if(bitCount < 0) { - bitCount = 0; + // add header bits + uint16_t N_totalBits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits; + return(((uint32_t)N_totalBits * 8 * 1000000UL) / 488.28215f); } - // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) - uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } - // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit - uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; + return(RADIOLIB_ERR_UNKNOWN); +} - return((symbolLength_us * nSymbol_x4) / 4); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(((uint32_t)len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32)); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - // calculate the number of bits based on coding rate - uint16_t N_bits; - switch(this->lrFhssCr) { - case RADIOLIB_SX126X_LR_FHSS_CR_5_6: - N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? - break; - case RADIOLIB_SX126X_LR_FHSS_CR_2_3: - N_bits = (len * 3) / 2; - break; - case RADIOLIB_SX126X_LR_FHSS_CR_1_2: - N_bits = len * 2; - break; - case RADIOLIB_SX126X_LR_FHSS_CR_1_3: - N_bits = len * 3; - break; - default: - return(RADIOLIB_ERR_INVALID_CODING_RATE); +RadioLibTime_t SX126x::getTimeOnAir(size_t len) { + uint8_t type = getPacketType(); + ModemType_t modem = RADIOLIB_MODEM_LORA; + DataRate_t dataRate = {}; + PacketConfig_t packetConfig = {}; + + if(type == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + dataRate.lora.spreadingFactor = this->spreadingFactor; + dataRate.lora.bandwidth = this->bandwidthKhz; + dataRate.lora.codingRate = (uint8_t)(this->codingRate + 4); + + packetConfig.lora.preambleLength = this->preambleLengthLoRa; + packetConfig.lora.crcEnabled = (bool)this->crcTypeLoRa; + packetConfig.lora.implicitHeader = this->headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT; + packetConfig.lora.ldrOptimize = (bool)this->ldrOptimize; + } else if(type == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + modem = RADIOLIB_MODEM_FSK; + + dataRate.fsk.bitRate = RADIOLIB_SX126X_CRYSTAL_FREQ * 32.0f * 1000.0f / (float)this->bitRate; + dataRate.fsk.freqDev = (float)this->frequencyDev; + + uint8_t crcLen = 0; + if(this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_1_BYTE || this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV) { + crcLen = 1; + } else if(this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_2_BYTE || this->crcTypeFSK == RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV) { + crcLen = 2; } - // calculate number of bits when accounting for unaligned last block - uint16_t N_payBits = (N_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS; - uint16_t N_lastBlockBits = N_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS; - if(N_lastBlockBits) { - N_payBits += N_lastBlockBits + 2; - } + packetConfig.fsk.preambleLength = this->preambleLengthFSK; + packetConfig.fsk.syncWordLength = this->syncWordLength; + packetConfig.fsk.crcLength = crcLen; + } else if(type == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + modem = RADIOLIB_MODEM_LRFHSS; - // add header bits - uint16_t N_totalBits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + N_payBits; - return(((uint32_t)N_totalBits * 8 * 1000000UL) / 488.28215f); - + dataRate.lrFhss.bw = this->lrFhssBw; + dataRate.lrFhss.cr = this->lrFhssCr; + dataRate.lrFhss.narrowGrid = this->lrFhssGridNonFcc; + + packetConfig.lrFhss.hdrCount = this->lrFhssHdrCount; + } else { + return(RADIOLIB_ERR_WRONG_MODEM); } - return(RADIOLIB_ERR_UNKNOWN); + return(calculateTimeOnAir(modem, dataRate, packetConfig, len)); } RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 5114f23c45..c2f8422d1f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1010,6 +1010,16 @@ class SX126x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH); + /*! + \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. + \param modem Modem type. + \param dr Data rate. + \param pc Packet config. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + /*! \brief Get expected time-on-air for a given size of payload \param len Payload length in bytes. diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 313cbff0fe..ce4682bee7 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -122,8 +122,10 @@ int16_t SX1272::setBandwidth(float bw) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); if(symbolLength >= 16.0f) { + this->ldroEnabled = true; state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { + this->ldroEnabled = false; state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } @@ -483,6 +485,7 @@ int16_t SX1272::forceLDRO(bool enable) { } this->ldroAuto = false; + this->ldroEnabled = enable; Module* mod = this->getMod(); if(enable) { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 92760148c0..5a269276ce 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -324,12 +324,6 @@ class SX1272: public SX127x { int16_t configFSK() override; void errataFix(bool rx) override; -#if !RADIOLIB_GODMODE - private: -#endif - bool ldroAuto = true; - bool ldroEnabled = false; - }; #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index dab91a5afc..14335fbce7 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -136,8 +136,10 @@ int16_t SX1278::setBandwidth(float bw) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); if(symbolLength >= 16.0f) { + this->ldroEnabled = true; state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); } else { + this->ldroEnabled = false; state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); } } @@ -522,6 +524,7 @@ int16_t SX1278::forceLDRO(bool enable) { Module* mod = this->getMod(); this->ldroAuto = false; + this->ldroEnabled = enable; if(enable) { return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); } else { diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 9155db9d4d..3cfcb19cfc 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -336,12 +336,6 @@ class SX1278: public SX127x { int16_t configFSK() override; void errataFix(bool rx) override; -#if !RADIOLIB_GODMODE - private: -#endif - bool ldroAuto = true; - bool ldroEnabled = false; - }; /*! diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 3ae6c1b317..b6875a192a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -258,6 +258,10 @@ int16_t SX127x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { return(readData(data, len)); } +void SX127x::reset() { + // should be implemented in derived class +} + int16_t SX127x::scanChannel() { // start CAD int16_t state = startChannelScan(); @@ -452,6 +456,11 @@ void SX127x::clearFifoFullAction() { this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4); } +void SX127x::errataFix(bool rx) { + (void)rx; + // should be implemented in derived class +} + bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) { // subtract first (this may be the first time we get to modify the remaining length) *remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1; @@ -829,6 +838,8 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } + this->frequencyDev = newFreqDev; + // set mode to STANDBY int16_t state = setMode(RADIOLIB_SX127X_STANDBY); RADIOLIB_ASSERT(state); @@ -1123,68 +1134,99 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen)); } -float SX127x::getNumSymbols(size_t len) { - // get symbol length in us - float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; - +float SX127x::getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc) { // get Low Data Rate optimization flag - float de = 0; - if (symbolLength >= 16.0f) { - de = 1; - } + float de = pc.lora.ldrOptimize ? 1.0f : 0.0f; // get explicit/implicit header enabled flag - float ih = (float) this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, 0, 0); - + float ih = (float) pc.lora.implicitHeader; + // get CRC enabled flag - float crc = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + float crc = (float) pc.lora.crcEnabled; // get number of preamble symbols - float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + float n_pre = (float) pc.lora.preambleLength; // get number of payload symbols - float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) this->spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) this->spreadingFactor - 8.0f * de)) * (float) this->codingRate, 0.0f); + float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) dr.lora.spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) dr.lora.spreadingFactor - 8.0f * de)) * (float) dr.lora.codingRate, 0.0f); // add 4.25 symbols for the sync return(n_pre + n_pay + 4.25f); } -RadioLibTime_t SX127x::getTimeOnAir(size_t len) { - // check active modem - uint8_t modem = getActiveModem(); - if (modem == RADIOLIB_SX127X_LORA) { +RadioLibTime_t SX127x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { + if (modem == RADIOLIB_MODEM_LORA) { // get symbol length in us - float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth; + float symbolLength = (float) (uint32_t(1) << dr.lora.spreadingFactor) / (float) dr.lora.bandwidth; // get number of symbols - float n_sym = getNumSymbols(len); + float n_sym = getNumSymbols(len, dr, pc); // get time-on-air in us return ceil((double)symbolLength * (double)n_sym) * 1000; - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - // get number of bits preamble - float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; - // get the number of bits of the sync word - float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8; - // get CRC bits - float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16; - - if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { - // if packet size fixed -> len = fixed packet length - len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); - } else { - // if packet variable -> Add 1 extra byte for payload length - len += 1; - } - + } else if(modem == RADIOLIB_MODEM_FSK) { + // calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec) - return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0f)) * 1000000.0f)); + return((uint32_t) ((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (float) (len * 8)) / (dr.fsk.bitRate * 1000.0f)) * 1000000.0f)); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); } return(RADIOLIB_ERR_UNKNOWN); } +RadioLibTime_t SX127x::getTimeOnAir(size_t len) { + uint8_t modem = getActiveModem(); + DataRate_t dr = {}; + PacketConfig_t pc = {}; + + switch (modem) { + case(RADIOLIB_SX127X_LORA): { + dr.lora.spreadingFactor = this->spreadingFactor; + dr.lora.bandwidth = this->bandwidth; + dr.lora.codingRate = this->codingRate; + + // Get number of preamble symbols + uint16_t n_pre = ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB)); + + pc.lora.preambleLength = n_pre; + pc.lora.implicitHeader = this->implicitHdr; + pc.lora.crcEnabled = this->crcEnabled; + pc.lora.ldrOptimize = this->ldroEnabled; + + return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_LORA, dr, pc, len)); + } + case(RADIOLIB_SX127X_FSK_OOK): { + dr.fsk.bitRate = this->bitRate; + dr.fsk.freqDev = this->frequencyDev; + + // get number of bits preamble + uint16_t n_pre = (uint16_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8; + // get the number of bits of the sync word + uint8_t n_syncWord = (uint8_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8); + // get CRC enabled status + bool crcEn = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON); + + pc.fsk.preambleLength = n_pre; + pc.fsk.syncWordLength = n_syncWord; + pc.fsk.crcLength = (uint8_t)(crcEn * 2); + + if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) { + // if packet size fixed -> len = fixed packet length + len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK); + } else { + // if packet variable -> Add 1 extra byte for payload length + len += 1; + } + + return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dr, pc, len)); + } + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) { RadioLibTime_t timeout = 0; if(getActiveModem() == RADIOLIB_SX127X_LORA) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index db0d8e803f..8d91ba2b0d 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -610,9 +610,9 @@ class SX127x: public PhysicalLayer { int16_t begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength); /*! - \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ. + \brief Reset method. Will reset the chip to the default state using RST pin. Should be implemented in derived class since SX1272 and SX1278 implementations differ. */ - virtual void reset() = 0; + virtual void reset(); /*! \brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class. @@ -1040,9 +1040,11 @@ class SX127x: public PhysicalLayer { /*! \brief Convert from bytes to LoRa symbols. \param len Payload length in bytes. + \param dr Data rate. + \param pc Packet configuration. \returns The total number of LoRa symbols, including preamble, sync and possible header. */ - float getNumSymbols(size_t len); + float getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc); /*! \brief Get expected time-on-air for a given size of payload. @@ -1051,6 +1053,16 @@ class SX127x: public PhysicalLayer { */ RadioLibTime_t getTimeOnAir(size_t len) override; + /*! + \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. + \param modem Modem type. + \param dr Data rate. + \param pc Packet config. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + /*! \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) \param timeoutUs Timeout in microseconds to listen for @@ -1251,6 +1263,8 @@ class SX127x: public PhysicalLayer { bool crcEnabled = false; bool ookEnabled = false; bool implicitHdr = false; + bool ldroAuto = false; + bool ldroEnabled = false; virtual int16_t configFSK(); int16_t getActiveModem(); @@ -1264,7 +1278,7 @@ class SX127x: public PhysicalLayer { #endif Module* mod; - float bitRate = 0; + float bitRate = 0, frequencyDev = 0; bool crcOn = true; // default value used in FSK mode float dataRate = 0; bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once @@ -1286,7 +1300,7 @@ class SX127x: public PhysicalLayer { */ static uint8_t calculateBWManExp(float bandwidth); - virtual void errataFix(bool rx) = 0; + virtual void errataFix(bool rx); // should be implemented in derived class }; #endif diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 798e6d19b4..6d1be330f7 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -969,6 +969,7 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { } // update modulation parameters + this->frequencyDev = newFreqDev; this->modIndex = modInd; return(setModulationParams(this->bitRate, this->modIndex, this->shaping)); } @@ -1334,15 +1335,13 @@ int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) { return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen)); } -RadioLibTime_t SX128x::getTimeOnAir(size_t len) { - // check active modem - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { - // calculate number of symbols - float N_symbol = 0; - uint8_t sf = this->spreadingFactor >> 4; - if(this->codingRateLoRa <= RADIOLIB_SX128X_LORA_CR_4_8) { - // legacy coding rate - nice and simple +RadioLibTime_t SX128x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { + switch(modem) { + case (ModemType_t::RADIOLIB_MODEM_LORA): { + // calculate number of symbols + float N_symbol = 0; + uint8_t sf = dr.lora.spreadingFactor; + float cr = (float)dr.lora.codingRate; // get SF coefficients float coeff1 = 0; @@ -1367,33 +1366,73 @@ RadioLibTime_t SX128x::getTimeOnAir(size_t len) { // get CRC length int16_t N_bitCRC = 16; - if(this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_OFF) { + if(!pc.lora.crcEnabled) { N_bitCRC = 0; } // get header length int16_t N_symbolHeader = 20; - if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) { + if(pc.lora.implicitHeader) { N_symbolHeader = 0; } // calculate number of LoRa preamble symbols - uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); + uint32_t N_symbolPreamble = pc.lora.preambleLength; // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRateLoRa + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * cr; - } else { - // long interleaving - abandon hope all ye who enter here - /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 + // get time-on-air in us + return(((uint32_t(1) << sf) / dr.lora.bandwidth) * N_symbol * 1000.0f); + } + case (ModemType_t::RADIOLIB_MODEM_FSK): + return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f))); + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } + +} + +RadioLibTime_t SX128x::getTimeOnAir(size_t len) { + // check active modem + uint8_t modem = getPacketType(); + DataRate_t dr = {}; + PacketConfig_t pc = {}; + + if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { + uint8_t sf = this->spreadingFactor >> 4; + uint8_t cr = this->codingRateLoRa; + // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values + if (cr < 5) { + cr = cr + 4; + } else if (cr == 7) { + cr = cr + 1; } + + dr.lora.spreadingFactor = sf; + dr.lora.codingRate = cr; + dr.lora.bandwidth = this->bandwidthKhz; + + uint16_t preambleLength = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); + + pc.lora.preambleLength = preambleLength; + pc.lora.implicitHeader = this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT; + pc.lora.crcEnabled = this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON; + pc.lora.ldrOptimize = false; + + return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_LORA, dr, pc, len)); + } else if (modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) { + dr.fsk.bitRate = (float)this->bitRateKbps; + dr.fsk.freqDev = this->frequencyDev; - // get time-on-air in us - return(((uint32_t(1) << sf) / this->bandwidthKhz) * N_symbol * 1000.0f); + pc.fsk.preambleLength = ((uint16_t)this->preambleLengthGFSK >> 2) + 4; + pc.fsk.syncWordLength = ((this->syncWordLen >> 1) + 1) * 8; + pc.fsk.crcLength = this->crcGFSK >> 4; + return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_FSK, dr, pc, len)); } else { - return(((uint32_t)len * 8 * 1000) / this->bitRateKbps); + return(RADIOLIB_ERR_WRONG_MODEM); } } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index e4d8535922..7f6f8fce83 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -828,6 +828,16 @@ class SX128x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX128X_MAX_PACKET_LENGTH); + /*! + \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. + \param modem Modem type. + \param dr Data rate. + \param pc Packet config. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + /*! \brief Get expected time-on-air for a given size of payload. \param len Payload length in bytes. @@ -942,7 +952,7 @@ class SX128x: public PhysicalLayer { uint8_t invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD; // cached GFSK parameters - float modIndexReal = 0; + float modIndexReal = 0, frequencyDev = 0; uint16_t bitRateKbps = 0; uint8_t bitRate = 0, modIndex = 0, shaping = 0; uint8_t preambleLengthGFSK = 0, syncWordLen = 0, syncWordMatch = 0, crcGFSK = 0, whitening = 0; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index f61c6434e7..8876b2bc40 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -35,8 +35,8 @@ struct LoRaRate_t { /*! \brief LoRa bandwidth in kHz */ float bandwidth; - - /*! \brief LoRa coding rate */ + + /*! \brief LoRa coding rate denominator */ uint8_t codingRate; }; @@ -82,6 +82,46 @@ union DataRate_t { LrFhssRate_t lrFhss; }; +struct LoRaPacketConfig_t { + /*! \brief LoRa preamble length */ + uint16_t preambleLength; + + /*! \brief LoRa implicit header mode */ + bool implicitHeader; + + /*! \brief LoRa CRC mode */ + bool crcEnabled; + + /*! \brief LoRa low data rate optimization */ + bool ldrOptimize; +}; + +struct FSKPacketConfig_t { + /*! \brief FSK preamble length in bits */ + uint16_t preambleLength; + + /*! \brief Length of the sync word in bits */ + uint8_t syncWordLength; + + /*! \brief FSK CRC length in bytes */ + uint8_t crcLength; +}; + +struct LrFhssPacketConfig_t { + /*! \brief LR-FHSS header count (1 - 4) */ + uint8_t hdrCount; +}; + +/*! + \union PacketConfig_t + \brief Common packet configuration structure +*/ +union PacketConfig_t { + LoRaPacketConfig_t lora; + FSKPacketConfig_t fsk; + LrFhssPacketConfig_t lrFhss; +}; + /*! \struct CADScanConfig_t \brief Channel scan configuration interpretation in case LoRa CAD is used From e23bae3bbd3e482af67df151c18f2f394c148636 Mon Sep 17 00:00:00 2001 From: Chris Leishman Date: Wed, 17 Sep 2025 08:24:33 -0700 Subject: [PATCH 1608/1848] [SX126x] Use a default of either 8 or 12 for minSymbols in startReceiveDutyCycleAuto (#1600) * [SX126x] Update doc of startReceiveDutyCycleAuto Note that the minimum preamble size should be set to 12 for SF5-6. * [SX126x] Set default for minSymbols in startReceiveDutyCycleAuto Change default argument value to 0, then set min symbols to 8 or 12 as appropriate. --- src/modules/SX126x/SX126x.cpp | 7 +++++++ src/modules/SX126x/SX126x.h | 11 ++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c6e7f65d20..920920c12d 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -555,6 +555,13 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ if(senderPreambleLength == 0) { senderPreambleLength = this->preambleLengthLoRa; } + if(minSymbols == 0) { + if (this->spreadingFactor <= 6) { + minSymbols = 12; + } else { + minSymbols = 8; + } + } // worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep. // in this case, we don't catch minSymbols before going to sleep, diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index c2f8422d1f..97296853e9 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -727,16 +727,17 @@ class SX126x: public PhysicalLayer { If the sender preamble length is variable or unknown, the maximum expected size should be configured on the receiver side by calling setPreambleLength prior to startReceiveDutyCycleAuto. - \param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols - of any preamble of the specified length. Defaults to 8. - According to Semtech, receiver requires 8 symbols to reliably latch a preamble. - This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1). + \param minSymbols Ensure that the unit will catch at least this many symbols of any preamble of the specified senderPreambleLength. + To reliably latch a preamble, the receiver requires 8 symbols for SF7-12 and 12 symbols for SF5-6 (see datasheet section 6.1.1.1, version 1.2). + If set to zero, the minimum required symbols will be used. Defaults to 0. + + If senderPreambleLength is less than 2*minSymbols + 1, this method is equivalent to startReceive(). \param irqFlags Sets the IRQ flags, defaults to RX done, RX timeout, CRC error and header error. \param irqMask Sets the mask of IRQ flags that will trigger DIO1, defaults to RX done. \returns \ref status_codes */ - int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK); + int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 0, RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK); /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, From 37ed8f5bb0a0f67753acd35dd110bc165f70ad1f Mon Sep 17 00:00:00 2001 From: Chris Leishman Date: Wed, 17 Sep 2025 08:33:35 -0700 Subject: [PATCH 1609/1848] [SX126x] For receiveDutyCycleAuto, check senderPreambleLength is shorter than configured preamble (#1602) * [SX126x] Update doc of startReceiveDutyCycleAuto Indicate that the senderPreambleLength should never exceed the configured preamble length. * [SX126x] For receiveDutyCycleAuto, check senderPreambleLength is shorter than configured preamble Return RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH otherwise. --- src/modules/SX126x/SX126x.cpp | 3 +++ src/modules/SX126x/SX126x.h | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 920920c12d..478fb1bdd6 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -554,6 +554,9 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, R int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) { if(senderPreambleLength == 0) { senderPreambleLength = this->preambleLengthLoRa; + } else if (senderPreambleLength > this->preambleLengthLoRa) { + // the unit must be configured to expect a preamble length at least as long as the sender is using + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); } if(minSymbols == 0) { if (this->spreadingFactor <= 6) { diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 97296853e9..6f1df53f00 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -724,8 +724,9 @@ class SX126x: public PhysicalLayer { \brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages. \param senderPreambleLength Expected preamble length of the messages to receive. If set to zero, the currently configured preamble length will be used. Defaults to zero. - If the sender preamble length is variable or unknown, the maximum expected size should be configured - on the receiver side by calling setPreambleLength prior to startReceiveDutyCycleAuto. + This value cannot exceed the configured preamble length. If the sender preamble length is variable, set the + maximum expected length by calling setPreambleLength(maximumExpectedLength) prior to this method, and use the + minimum expected length here. \param minSymbols Ensure that the unit will catch at least this many symbols of any preamble of the specified senderPreambleLength. To reliably latch a preamble, the receiver requires 8 symbols for SF7-12 and 12 symbols for SF5-6 (see datasheet section 6.1.1.1, version 1.2). From a94f263cac8418c14e71ace5a233e1d91cfb921c Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Sep 2025 18:05:57 +0200 Subject: [PATCH 1610/1848] [SX126x] Split main source file into multiple files --- src/modules/SX126x/SX126x.cpp | 1018 ------------------------ src/modules/SX126x/SX126x.h | 445 +---------- src/modules/SX126x/SX126x_commands.cpp | 248 ++++++ src/modules/SX126x/SX126x_commands.h | 67 ++ src/modules/SX126x/SX126x_config.cpp | 779 ++++++++++++++++++ src/modules/SX126x/SX126x_registers.h | 395 +++++++++ 6 files changed, 1492 insertions(+), 1460 deletions(-) create mode 100644 src/modules/SX126x/SX126x_commands.cpp create mode 100644 src/modules/SX126x/SX126x_commands.h create mode 100644 src/modules/SX126x/SX126x_config.cpp create mode 100644 src/modules/SX126x/SX126x_registers.h diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 478fb1bdd6..105dc7e0c8 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -416,45 +416,6 @@ int16_t SX126x::scanChannel(const ChannelScanConfig_t &config) { return(getChannelScanResult()); } -int16_t SX126x::sleep() { - return(SX126x::sleep(true)); -} - -int16_t SX126x::sleep(bool retainConfig) { - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_IDLE); - - uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF; - if(!retainConfig) { - sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; - } - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); - - // wait for SX126x to safely enter sleep mode - this->mod->hal->delay(1); - - return(state); -} - -int16_t SX126x::standby() { - return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC)); -} - -int16_t SX126x::standby(uint8_t mode, bool wakeup) { - // set RF switch (if present) - this->mod->setRfSwitchState(Module::MODE_IDLE); - - if(wakeup) { - // send a NOP command - this pulls the NSS low to exit the sleep mode, - // while preventing interference with possible other SPI transactions - // see https://github.com/jgromes/RadioLib/discussions/1364 - (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false); - } - - const uint8_t data[] = { mode }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); -} - int16_t SX126x::hopLRFHSS() { if(!(this->getIrqFlags() & RADIOLIB_SX126X_IRQ_LR_FHSS_HOP)) { return(RADIOLIB_ERR_TX_TIMEOUT); @@ -465,38 +426,6 @@ int16_t SX126x::hopLRFHSS() { return(clearIrqStatus()); } -void SX126x::setDio1Action(void (*func)(void)) { - this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); -} - -void SX126x::clearDio1Action() { - this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); -} - -void SX126x::setPacketReceivedAction(void (*func)(void)) { - this->setDio1Action(func); -} - -void SX126x::clearPacketReceivedAction() { - this->clearDio1Action(); -} - -void SX126x::setPacketSentAction(void (*func)(void)) { - this->setDio1Action(func); -} - -void SX126x::clearPacketSentAction() { - this->clearDio1Action(); -} - -void SX126x::setChannelScanAction(void (*func)(void)) { - this->setDio1Action(func); -} - -void SX126x::clearChannelScanAction() { - this->clearDio1Action(); -} - int16_t SX126x::finishTransmit() { // clear interrupt flags int16_t state = clearIrqStatus(); @@ -732,514 +661,6 @@ int16_t SX126x::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } -int16_t SX126x::setBandwidth(float bw) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // ensure byte conversion doesn't overflow - RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - - // check allowed bandwidth values - uint8_t bw_div2 = bw / 2 + 0.01f; - switch (bw_div2) { - case 3: // 7.8: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8; - break; - case 5: // 10.4: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4; - break; - case 7: // 15.6: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6; - break; - case 10: // 20.8: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8; - break; - case 15: // 31.25: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25; - break; - case 20: // 41.7: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7; - break; - case 31: // 62.5: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5; - break; - case 62: // 125.0: - this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0; - break; - case 125: // 250.0 - this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0; - break; - case 250: // 500.0 - this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; - break; - default: - return(RADIOLIB_ERR_INVALID_BANDWIDTH); - } - - // update modulation parameters - this->bandwidthKhz = bw; - return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); -} - -int16_t SX126x::setSpreadingFactor(uint8_t sf) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - - // update modulation parameters - this->spreadingFactor = sf; - return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); -} - -int16_t SX126x::setCodingRate(uint8_t cr) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); - - // update modulation parameters - this->codingRate = cr - 4; - return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); -} - -int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // update register - const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; - return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)); -} - -int16_t SX126x::setCurrentLimit(float currentLimit) { - // check allowed range - if(!((currentLimit >= 0) && (currentLimit <= 140))) { - return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT); - } - - // calculate raw value - uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f); - - // update register - return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1)); -} - -float SX126x::getCurrentLimit() { - // get the raw value - uint8_t ocp = 0; - readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); - - // return the actual value - return((float)ocp * 2.5f); -} - -int16_t SX126x::setPreambleLength(size_t preambleLength) { - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - this->preambleLengthLoRa = preambleLength; - return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - this->preambleLengthFSK = preambleLength; - // maximum preamble detector length is limited by sync word length - // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45 - uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK); - this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : - maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : - maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : - maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : - RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; - return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType)); - } - - return(RADIOLIB_ERR_UNKNOWN); -} - -int16_t SX126x::setFrequencyDeviation(float freqDev) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set frequency deviation to lowest available setting (required for digimodes) - float newFreqDev = freqDev; - if(freqDev < 0.0f) { - newFreqDev = 0.6f; - } - - RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); - - // calculate raw frequency deviation value - uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f)); - - // check modulation parameters - this->frequencyDev = freqDevRaw; - - // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); -} - -int16_t SX126x::setBitRate(float br) { - // check active modem - uint8_t modem = getPacketType(); - if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); - } - - // calculate raw bit rate value - uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f)); - - // check modulation parameters - this->bitRate = brRaw; - - // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); -} - -int16_t SX126x::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; - - // select interpretation based on active modem - uint8_t modem = this->getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - // set the bit rate - state = this->setBitRate(dr.fsk.bitRate); - RADIOLIB_ASSERT(state); - - // set the frequency deviation - state = this->setFrequencyDeviation(dr.fsk.freqDev); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - // set the spreading factor - state = this->setSpreadingFactor(dr.lora.spreadingFactor); - RADIOLIB_ASSERT(state); - - // set the bandwidth - state = this->setBandwidth(dr.lora.bandwidth); - RADIOLIB_ASSERT(state); - - // set the coding rate - state = this->setCodingRate(dr.lora.codingRate); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - // set the basic config - state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); - RADIOLIB_ASSERT(state); - - // set hopping grid - this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC; - - } - - return(state); -} - -int16_t SX126x::checkDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; - - // select interpretation based on active modem - uint8_t modem = this->getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); - RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); - return(RADIOLIB_ERR_NONE); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); - RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); - return(RADIOLIB_ERR_NONE); - - } - - return(state); -} - -int16_t SX126x::setRxBandwidth(float rxBw) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // check modulation parameters - /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) { - return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); - }*/ - this->rxBandwidthKhz = rxBw; - - // check allowed receiver bandwidth values - if(fabsf(rxBw - 4.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8; - } else if(fabsf(rxBw - 5.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8; - } else if(fabsf(rxBw - 7.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3; - } else if(fabsf(rxBw - 9.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7; - } else if(fabsf(rxBw - 11.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7; - } else if(fabsf(rxBw - 14.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6; - } else if(fabsf(rxBw - 19.5f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5; - } else if(fabsf(rxBw - 23.4f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4; - } else if(fabsf(rxBw - 29.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3; - } else if(fabsf(rxBw - 39.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0; - } else if(fabsf(rxBw - 46.9f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9; - } else if(fabsf(rxBw - 58.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6; - } else if(fabsf(rxBw - 78.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2; - } else if(fabsf(rxBw - 93.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8; - } else if(fabsf(rxBw - 117.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3; - } else if(fabsf(rxBw - 156.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; - } else if(fabsf(rxBw - 187.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2; - } else if(fabsf(rxBw - 234.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3; - } else if(fabsf(rxBw - 312.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0; - } else if(fabsf(rxBw - 373.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6; - } else if(fabsf(rxBw - 467.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0; - } else { - return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); - } - - // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); -} - -int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { - // update RX gain setting register - uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; - int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); - RADIOLIB_ASSERT(state); - - // add Rx Gain register to retention memory if requested - if(persist) { - // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3 - const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) }; - state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3); - } - - return(state); -} - -int16_t SX126x::setDataShaping(uint8_t sh) { - // check active modem - uint8_t modem = getPacketType(); - if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set data shaping - switch(sh) { - case RADIOLIB_SHAPING_NONE: - this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE; - break; - case RADIOLIB_SHAPING_0_3: - this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3; - break; - case RADIOLIB_SHAPING_0_5: - this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; - break; - case RADIOLIB_SHAPING_0_7: - this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7; - break; - case RADIOLIB_SHAPING_1_0: - this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; - break; - default: - return(RADIOLIB_ERR_INVALID_DATA_SHAPING); - } - - // update modulation parameters - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); -} - -int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { - // check active modem - uint8_t modem = getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - // check sync word Length - if(len > 8) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } - - // write sync word - int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len); - RADIOLIB_ASSERT(state); - - // update packet parameters - this->syncWordLength = len * 8; - - // maximum preamble detector length is limited by sync word length - // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45 - uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK); - this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : - maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : - maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : - maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : - RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); - - return(state); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - // with length set to 1 and LoRa modem active, assume it is the LoRa sync word - if(len > 1) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } - return(setSyncWord(syncWord[0])); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word - if(len != sizeof(uint32_t)) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } - memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t)); - - } - - return(RADIOLIB_ERR_WRONG_MODEM); -} - -int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // check sync word Length - if(bitsLen > 0x40) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } - - uint8_t bytesLen = bitsLen / 8; - if ((bitsLen % 8) != 0) { - bytesLen++; - } - - return(setSyncWord(syncWord, bytesLen)); -} - -int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { - // check active modem - uint8_t modem = getPacketType(); - - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - // update packet parameters - switch(len) { - case 0: - this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF; - break; - case 1: - if(inverted) { - this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV; - } else { - this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE; - } - break; - case 2: - if(inverted) { - this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; - } else { - this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE; - } - break; - default: - return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); - } - - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); - RADIOLIB_ASSERT(state); - - // write initial CRC value - uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)}; - state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2); - RADIOLIB_ASSERT(state); - - // write CRC polynomial value - data[0] = (uint8_t)((polynomial >> 8) & 0xFF); - data[1] = (uint8_t)(polynomial & 0xFF); - state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2); - - return(state); - - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { - // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion - - // update packet parameters - if(len) { - this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; - } else { - this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF; - } - - return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); - } - - return(RADIOLIB_ERR_UNKNOWN); -} - -int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - int16_t state = RADIOLIB_ERR_NONE; - if(!enabled) { - // disable whitening - this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; - - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); - RADIOLIB_ASSERT(state); - - } else { - // enable whitening - this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON; - - // write initial whitening value - // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register" - uint8_t data[2]; - // first read the actual value and mask 7 MSB which we can not change - // if different value is written in 7 MSB, the Rx won't even work (tested on HW) - state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1); - RADIOLIB_ASSERT(state); - - data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01); - data[1] = (uint8_t)(initial & 0xFF); - state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); - RADIOLIB_ASSERT(state); - - state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); - RADIOLIB_ASSERT(state); - } - return(state); -} - float SX126x::getDataRate() const { return(this->dataRateMeasured); } @@ -1346,14 +767,6 @@ int16_t SX126x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) { return(state); } -int16_t SX126x::fixedPacketLengthMode(uint8_t len) { - return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len)); -} - -int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { - return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen)); -} - RadioLibTime_t SX126x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact @@ -1494,55 +907,6 @@ int16_t SX126x::clearIrqFlags(uint32_t irq) { return(this->clearIrqStatus(irq)); } -int16_t SX126x::implicitHeader(size_t len) { - return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len)); -} - -int16_t SX126x::explicitHeader() { - return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT)); -} - -int16_t SX126x::setRegulatorLDO() { - return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO)); -} - -int16_t SX126x::setRegulatorDCDC() { - return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC)); -} - -int16_t SX126x::setEncoding(uint8_t encoding) { - return(setWhitening(encoding)); -} - -void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { - this->mod->setRfSwitchPins(rxEn, txEn); -} - -void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { - this->mod->setRfSwitchTable(pins, table); -} - -int16_t SX126x::forceLDRO(bool enable) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // update modulation parameters - this->ldroAuto = false; - this->ldrOptimize = (uint8_t)enable; - return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); -} - -int16_t SX126x::autoLDRO() { - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - this->ldroAuto = true; - return(RADIOLIB_ERR_NONE); -} - uint8_t SX126x::randomByte() { // set some magic registers this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_ANA_LNA, RADIOLIB_SX126X_LNA_RNG_ENABLED, 0, 0); @@ -1572,20 +936,6 @@ uint8_t SX126x::randomByte() { return(randByte); } -int16_t SX126x::invertIQ(bool enable) { - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - if(enable) { - this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED; - } else { - this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; - } - - return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); -} - int16_t SX126x::getModem(ModemType_t* modem) { RADIOLIB_ASSERT_PTR(modem); @@ -1853,169 +1203,6 @@ int16_t SX126x::spectralScanGetResult(uint16_t* results) { return(RADIOLIB_ERR_NONE); } -int16_t SX126x::setTCXO(float voltage, uint32_t delay) { - // check if TCXO is enabled at all - if(this->XTAL) { - return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); - } - - // set mode to standby - standby(); - - // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it - if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) { - clearDeviceErrors(); - } - - // check 0 V disable - if(fabsf(voltage - 0.0f) <= 0.001f) { - return(reset(true)); - } - - // check alowed voltage values - uint8_t data[4]; - if(fabsf(voltage - 1.6f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6; - } else if(fabsf(voltage - 1.7f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7; - } else if(fabsf(voltage - 1.8f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8; - } else if(fabsf(voltage - 2.2f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2; - } else if(fabsf(voltage - 2.4f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4; - } else if(fabsf(voltage - 2.7f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7; - } else if(fabsf(voltage - 3.0f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0; - } else if(fabsf(voltage - 3.3f) <= 0.001f) { - data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3; - } else { - return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); - } - - // calculate delay - uint32_t delayValue = (float)delay / 15.625f; - data[1] = (uint8_t)((delayValue >> 16) & 0xFF); - data[2] = (uint8_t)((delayValue >> 8) & 0xFF); - data[3] = (uint8_t)(delayValue & 0xFF); - - this->tcxoDelay = delay; - - // enable TCXO control on DIO3 - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); -} - -int16_t SX126x::setDio2AsRfSwitch(bool enable) { - uint8_t data = 0; - if(enable) { - data = RADIOLIB_SX126X_DIO2_AS_RF_SWITCH; - } else { - data = RADIOLIB_SX126X_DIO2_AS_IRQ; - } - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); -} - -int16_t SX126x::setFs() { - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); -} - -int16_t SX126x::setTx(uint32_t timeout) { - const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); -} - -int16_t SX126x::setRx(uint32_t timeout) { - const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); -} - -int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { - // default CAD parameters are selected according to recommendations on Semtech DS.SX1261-2.W.APP rev. 1.1, page 92. - - // build the packet with default configuration - uint8_t data[7]; - data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; - data[1] = this->spreadingFactor + 13; - data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; - data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; - uint32_t timeout_raw = (float)timeout / 15.625f; - data[4] = (uint8_t)((timeout_raw >> 16) & 0xFF); - data[5] = (uint8_t)((timeout_raw >> 8) & 0xFF); - data[6] = (uint8_t)(timeout_raw & 0xFF); - - // set user-provided values - if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { - data[0] = symbolNum; - } - - if(detPeak != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { - data[1] = detPeak; - } - - if(detMin != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { - data[2] = detMin; - } - - if(exitMode != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { - data[3] = exitMode; - } - - // configure parameters - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); - RADIOLIB_ASSERT(state); - - // start CAD - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); -} - -int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { - const uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); -} - -int16_t SX126x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) { - this->mod->SPIwriteRegisterBurst(addr, data, numBytes); - return(RADIOLIB_ERR_NONE); -} - -int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - // send the command - this->mod->SPIreadRegisterBurst(addr, numBytes, data); - - // check the status - int16_t state = this->mod->SPIcheckStream(); - return(state); -} - -int16_t SX126x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) { - const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; - return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); -} - -int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { - const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; - return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); -} - -int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { - const uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), - (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), - (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), - (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); -} - -int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { - const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); -} - -int16_t SX126x::setRfFrequency(uint32_t frf) { - const uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); -} - int16_t SX126x::calibrateImage(float freq) { uint8_t data[2] = { 0, 0 }; @@ -2061,152 +1248,6 @@ int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) { return(this->calibrateImage(data)); } -int16_t SX126x::setPaRampTime(uint8_t rampTime) { - return(this->setTxParams(this->pwr, rampTime)); -} - -int16_t SX126x::calibrateImage(const uint8_t* data) { - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); - - // if something failed, show the device errors - #if RADIOLIB_DEBUG_BASIC - if(state != RADIOLIB_ERR_NONE) { - // unless mode is forced to standby, device errors will be 0 - standby(); - uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); - } - #endif - return(state); -} - -uint8_t SX126x::getPacketType() { - uint8_t data = 0xFF; - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); - return(data); -} - -int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) { - const uint8_t data[] = { pwr, rampTime }; - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2); - if(state == RADIOLIB_ERR_NONE) { - this->pwr = pwr; - } - return(state); -} - -int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set requested packet mode - int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len); - RADIOLIB_ASSERT(state); - - // update cached value - this->packetType = mode; - return(state); -} - -int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // set requested packet mode - int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled); - RADIOLIB_ASSERT(state); - - // update cached value - this->headerType = hdrType; - this->implicitLen = len; - - return(state); -} - -int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { - // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled - if(this->ldroAuto) { - float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; - if(symbolLength >= 16.0f) { - this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; - } else { - this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; - } - } else { - this->ldrOptimize = ldro; - } - // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 - // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 - const uint8_t data[4] = {sf, bw, cr, this->ldrOptimize}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); -} - -int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { - const uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), - sh, rxBw, - (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); -} - -int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) { - int16_t state = fixInvertedIQ(invertIQ); - RADIOLIB_ASSERT(state); - const uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); -} - -int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen) { - const uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), - preambleDetectorLen, syncWordLen, addrCmp, - packType, payloadLen, crcType, whiten}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); -} - -int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { - const uint8_t data[2] = {txBaseAddress, rxBaseAddress}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); -} - -int16_t SX126x::setRegulatorMode(uint8_t mode) { - const uint8_t data[1] = {mode}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); -} - -uint8_t SX126x::getStatus() { - uint8_t data = 0; - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 0); - return(data); -} - -uint32_t SX126x::getPacketStatus() { - uint8_t data[3] = {0, 0, 0}; - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); - return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]); -} - -uint16_t SX126x::getDeviceErrors() { - uint8_t data[2] = {0, 0}; - this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); - uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]); - return(opError); -} - -int16_t SX126x::clearDeviceErrors() { - const uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); -} - -int16_t SX126x::setFrequencyRaw(float freq) { - // calculate raw value - this->freqMHz = freq; - uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; - return(setRfFrequency(frf)); -} - int16_t SX126x::fixSensitivity() { // fix receiver sensitivity for 500 kHz LoRa // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.1 for details @@ -2337,65 +1378,6 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) return(state); } -int16_t SX126x::config(uint8_t modem) { - // reset buffer base address - int16_t state = setBufferBaseAddress(); - RADIOLIB_ASSERT(state); - - // set modem - uint8_t data[7]; - data[0] = modem; - state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); - RADIOLIB_ASSERT(state); - - // set Rx/Tx fallback mode to STDBY_RC - data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; - state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); - RADIOLIB_ASSERT(state); - - // set some CAD parameters - will be overwritten when calling CAD anyway - data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; - data[1] = this->spreadingFactor + 13; - data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; - data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; - data[4] = 0x00; - data[5] = 0x00; - data[6] = 0x00; - state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); - RADIOLIB_ASSERT(state); - - // clear IRQ - state = clearIrqStatus(); - state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); - RADIOLIB_ASSERT(state); - - // calibrate all blocks - data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; - state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); - RADIOLIB_ASSERT(state); - - // wait for calibration completion - this->mod->hal->delay(5); - while(this->mod->hal->digitalRead(this->mod->getGpio())) { - this->mod->hal->yield(); - } - - // check calibration result - state = this->mod->SPIcheckStream(); - - // if something failed, show the device errors - #if RADIOLIB_DEBUG_BASIC - if(state != RADIOLIB_ERR_NONE) { - // unless mode is forced to standby, device errors will be 0 - standby(); - uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); - } - #endif - - return(state); -} - int16_t SX126x::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) { return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 6f1df53f00..36a4fdf8c3 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -11,454 +11,15 @@ #include "../../utils/FEC.h" #include "../../utils/CRC.h" +#include "SX126x_commands.h" +#include "SX126x_registers.h" + // SX126X physical layer properties #define RADIOLIB_SX126X_FREQUENCY_STEP_SIZE 0.9536743164 #define RADIOLIB_SX126X_MAX_PACKET_LENGTH 255 #define RADIOLIB_SX126X_CRYSTAL_FREQ 32.0f #define RADIOLIB_SX126X_DIV_EXPONENT 25 -// SX126X SPI commands -// operational modes commands -#define RADIOLIB_SX126X_CMD_NOP 0x00 -#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84 -#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80 -#define RADIOLIB_SX126X_CMD_SET_FS 0xC1 -#define RADIOLIB_SX126X_CMD_SET_TX 0x83 -#define RADIOLIB_SX126X_CMD_SET_RX 0x82 -#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F -#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 -#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5 -#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 -#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 -#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96 -#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89 -#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98 -#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95 -#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 - -// register and buffer access commands -#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D -#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D -#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E -#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E - -// DIO and IRQ control -#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 -#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12 -#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02 -#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D -#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 - -// RF, modulation and packet commands -#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86 -#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A -#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11 -#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E -#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B -#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C -#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 -#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F -#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0 - -// status commands -#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 -#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15 -#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 -#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14 -#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17 -#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 -#define RADIOLIB_SX126X_CMD_GET_STATS 0x10 -#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 - -#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 -#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A -#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B - -// SX126X register map -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 -#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 -#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 -#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 -#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 -#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) -#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) -#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 -#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 -#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582 -#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 -#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 -#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 -#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 -#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 -#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 -#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 -#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 -#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB -#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC -#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD -#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE -#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF -#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0 -#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1 -#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2 -#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3 -#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4 -#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5 -#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6 -#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 -#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD -#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE -#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 -#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 -#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 -#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 -#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 -#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 -#define RADIOLIB_SX126X_REG_LORA_RX_CODING_RATE 0x0749 -#define RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC 0x076B -#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD -#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B -#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C -#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D -#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E -#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B -#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC -#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 -#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 -#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 -#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 -#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5 -#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 -#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 -#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 -#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 -#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 -#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 -#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 - -// SX126X SPI command variables -//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION -#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) -#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained -#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled -#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled - -//RADIOLIB_SX126X_CMD_SET_STANDBY -#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator -#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator - -//RADIOLIB_SX126X_CMD_SET_RX -#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) -#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) - -//RADIOLIB_SX126X_CMD_SET_TX -#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) - -//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE -#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) -#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection - -//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE -#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) -#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC - -//RADIOLIB_SX126X_CMD_CALIBRATE -#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled -#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks - -//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 -#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0f) - -//RADIOLIB_SX126X_CMD_SET_PA_CONFIG -#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 -#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 -#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 - -//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) - -//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop -#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout -#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected -#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished -#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received -#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error -#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received -#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected -#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected -#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received -#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed -#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts -#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts - -//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL -#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ -#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control - -//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V - -//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE -#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK -#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa -#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS - -//RADIOLIB_SX126X_CMD_SET_TX_PARAMS -#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us -#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us -#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us -#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us -#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us -#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us -#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us -#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us - -//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS -#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 -#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz -#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz -#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz -#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz -#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz -#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz -#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz -#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz -#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz -#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz -#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz -#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 -#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 -#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 -#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 -#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled -#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled - -//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast -#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) -#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) -#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled -#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte -#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte -#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted -#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted -#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled -#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled -#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit -#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit -#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled -#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled -#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard -#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted - -//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS -#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 -#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 -#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 -#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 -#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 -#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode -#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected -#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value -#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter - -//RADIOLIB_SX126X_CMD_GET_STATUS -#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC -#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC -#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS -#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX -#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX -#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved -#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out -#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command -#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute -#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done -#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed - -//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent - -//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS -#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed -#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock -#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start -#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed -#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed -#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed -#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed -#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed - -//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS -#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us -#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us -#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us - -// SX126X SPI register variables -//RADIOLIB_SX126X_REG_HOPPING_ENABLE -#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled -#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) - -//RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB -#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. -#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. - -// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 -#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default) -#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled - -// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 -#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default) -#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled - -// RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE -#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled -#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled -#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled -#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled -#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled -#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled - -// RADIOLIB_SX126X_REG_DIOX_IN_ENABLE -#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled -#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled -#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled -#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled -#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled -#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled - -// RADIOLIB_SX126X_REG_RX_GAIN -#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted -#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving -#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan - -// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE -#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled -#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled - -// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS -#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none -#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing -#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted -#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed - -// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW -#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window - -// RADIOLIB_SX126X_REG_ANA_LNA -#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled -#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled - -// RADIOLIB_SX126X_REG_ANA_MIXER -#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled -#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled - -// size of the spectral scan result -#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) - -// LR-FHSS configuration -#define RADIOLIB_SX126X_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 -#define RADIOLIB_SX126X_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 -#define RADIOLIB_SX126X_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 -#define RADIOLIB_SX126X_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 -#define RADIOLIB_SX126X_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK -#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) -#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) -#define RADIOLIB_SX126X_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled -#define RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled -#define RADIOLIB_SX126X_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz -#define RADIOLIB_SX126X_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz - // LR-FHSS packet lengths #define RADIOLIB_SX126X_LR_FHSS_MAX_ENC_SIZE (608) #define RADIOLIB_SX126X_LR_FHSS_HEADER_BITS (114) diff --git a/src/modules/SX126x/SX126x_commands.cpp b/src/modules/SX126x/SX126x_commands.cpp new file mode 100644 index 0000000000..e2afba0f90 --- /dev/null +++ b/src/modules/SX126x/SX126x_commands.cpp @@ -0,0 +1,248 @@ +#include "SX126x.h" + +// this file contains implementation of all commands +// supported by the SX126x SPI interface +// in most cases, the names of methods match those in the datasheet +// however, sometimes slight changes had to be made in order to +// better fit the RadioLib API + +#if !RADIOLIB_EXCLUDE_SX126X + +int16_t SX126x::sleep() { + return(SX126x::sleep(true)); +} + +int16_t SX126x::sleep(bool retainConfig) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF; + if(!retainConfig) { + sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF; + } + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false, false); + + // wait for SX126x to safely enter sleep mode + this->mod->hal->delay(1); + + return(state); +} + +int16_t SX126x::standby() { + return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC)); +} + +int16_t SX126x::standby(uint8_t mode, bool wakeup) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + if(wakeup) { + // send a NOP command - this pulls the NSS low to exit the sleep mode, + // while preventing interference with possible other SPI transactions + // see https://github.com/jgromes/RadioLib/discussions/1364 + (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX126X_CMD_NOP, NULL, 0, false, false); + } + + const uint8_t data[] = { mode }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1)); +} + +int16_t SX126x::setFs() { + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_FS, NULL, 0)); +} + +int16_t SX126x::setTx(uint32_t timeout) { + const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX, data, 3)); +} + +int16_t SX126x::setRx(uint32_t timeout) { + const uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); +} + +int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { + // default CAD parameters are selected according to recommendations on Semtech DS.SX1261-2.W.APP rev. 1.1, page 92. + + // build the packet with default configuration + uint8_t data[7]; + data[0] = RADIOLIB_SX126X_CAD_ON_4_SYMB; + data[1] = this->spreadingFactor + 13; + data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; + data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; + uint32_t timeout_raw = (float)timeout / 15.625f; + data[4] = (uint8_t)((timeout_raw >> 16) & 0xFF); + data[5] = (uint8_t)((timeout_raw >> 8) & 0xFF); + data[6] = (uint8_t)(timeout_raw & 0xFF); + + // set user-provided values + if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[0] = symbolNum; + } + + if(detPeak != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[1] = detPeak; + } + + if(detMin != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[2] = detMin; + } + + if(exitMode != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { + data[3] = exitMode; + } + + // configure parameters + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + RADIOLIB_ASSERT(state); + + // start CAD + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); +} + +int16_t SX126x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) { + this->mod->SPIwriteRegisterBurst(addr, data, numBytes); + return(RADIOLIB_ERR_NONE); +} + +int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + // send the command + this->mod->SPIreadRegisterBurst(addr, numBytes, data); + + // check the status + int16_t state = this->mod->SPIcheckStream(); + return(state); +} + +int16_t SX126x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) { + const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset }; + return(this->mod->SPIwriteStream(cmd, 2, data, numBytes)); +} + +int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + const uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, offset }; + return(this->mod->SPIreadStream(cmd, 2, data, numBytes)); +} + +int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { + const uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), + (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), + (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), + (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); +} + +int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { + const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); +} + +int16_t SX126x::setRfFrequency(uint32_t frf) { + const uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); +} + +int16_t SX126x::calibrateImage(const uint8_t* data) { + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2); + + // if something failed, show the device errors + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); + } + #endif + return(state); +} + +uint8_t SX126x::getPacketType() { + uint8_t data = 0xFF; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1); + return(data); +} + +int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) { + const uint8_t data[] = { pwr, rampTime }; + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2); + if(state == RADIOLIB_ERR_NONE) { + this->pwr = pwr; + } + return(state); +} + +int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { + // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + if(symbolLength >= 16.0f) { + this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON; + } else { + this->ldrOptimize = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF; + } + } else { + this->ldrOptimize = ldro; + } + // 500/9/8 - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8 + // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7 + const uint8_t data[4] = {sf, bw, cr, this->ldrOptimize}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4)); +} + +int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev) { + const uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), + sh, rxBw, + (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); +} + +int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) { + int16_t state = fixInvertedIQ(invertIQ); + RADIOLIB_ASSERT(state); + const uint8_t data[6] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), hdrType, payloadLen, crcType, invertIQ}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6)); +} + +int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType, uint8_t payloadLen) { + const uint8_t data[9] = {(uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + preambleDetectorLen, syncWordLen, addrCmp, + packType, payloadLen, crcType, whiten}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); +} + +int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { + const uint8_t data[2] = {txBaseAddress, rxBaseAddress}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); +} + +int16_t SX126x::setRegulatorMode(uint8_t mode) { + const uint8_t data[1] = {mode}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1)); +} + +uint8_t SX126x::getStatus() { + uint8_t data = 0; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 0); + return(data); +} + +uint32_t SX126x::getPacketStatus() { + uint8_t data[3] = {0, 0, 0}; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3); + return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]); +} + +uint16_t SX126x::getDeviceErrors() { + uint8_t data[2] = {0, 0}; + this->mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2); + uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) | ((uint16_t)data[1]); + return(opError); +} + +int16_t SX126x::clearDeviceErrors() { + const uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2)); +} + +#endif \ No newline at end of file diff --git a/src/modules/SX126x/SX126x_commands.h b/src/modules/SX126x/SX126x_commands.h new file mode 100644 index 0000000000..cb17aedcc6 --- /dev/null +++ b/src/modules/SX126x/SX126x_commands.h @@ -0,0 +1,67 @@ +#if !defined(_RADIOLIB_SX126X_COMMANDS_H) +#define _RADIOLIB_SX126X_COMMANDS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +// SX126X SPI commands +// operational modes commands +#define RADIOLIB_SX126X_CMD_NOP 0x00 +#define RADIOLIB_SX126X_CMD_SET_SLEEP 0x84 +#define RADIOLIB_SX126X_CMD_SET_STANDBY 0x80 +#define RADIOLIB_SX126X_CMD_SET_FS 0xC1 +#define RADIOLIB_SX126X_CMD_SET_TX 0x83 +#define RADIOLIB_SX126X_CMD_SET_RX 0x82 +#define RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F +#define RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define RADIOLIB_SX126X_CMD_SET_CAD 0xC5 +#define RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2 +#define RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE 0x96 +#define RADIOLIB_SX126X_CMD_CALIBRATE 0x89 +#define RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE 0x98 +#define RADIOLIB_SX126X_CMD_SET_PA_CONFIG 0x95 +#define RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93 + +// register and buffer access commands +#define RADIOLIB_SX126X_CMD_WRITE_REGISTER 0x0D +#define RADIOLIB_SX126X_CMD_READ_REGISTER 0x1D +#define RADIOLIB_SX126X_CMD_WRITE_BUFFER 0x0E +#define RADIOLIB_SX126X_CMD_READ_BUFFER 0x1E + +// DIO and IRQ control +#define RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08 +#define RADIOLIB_SX126X_CMD_GET_IRQ_STATUS 0x12 +#define RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS 0x02 +#define RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D +#define RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97 + +// RF, modulation and packet commands +#define RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY 0x86 +#define RADIOLIB_SX126X_CMD_SET_PACKET_TYPE 0x8A +#define RADIOLIB_SX126X_CMD_GET_PACKET_TYPE 0x11 +#define RADIOLIB_SX126X_CMD_SET_TX_PARAMS 0x8E +#define RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS 0x8B +#define RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS 0x8C +#define RADIOLIB_SX126X_CMD_SET_CAD_PARAMS 0x88 +#define RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define RADIOLIB_SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0 + +// status commands +#define RADIOLIB_SX126X_CMD_GET_STATUS 0xC0 +#define RADIOLIB_SX126X_CMD_GET_RSSI_INST 0x15 +#define RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS 0x13 +#define RADIOLIB_SX126X_CMD_GET_PACKET_STATUS 0x14 +#define RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS 0x17 +#define RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07 +#define RADIOLIB_SX126X_CMD_GET_STATS 0x10 +#define RADIOLIB_SX126X_CMD_RESET_STATS 0x00 + +#define RADIOLIB_SX126X_CMD_PRAM_UPDATE 0xD9 +#define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A +#define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B + +#endif + +#endif diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp new file mode 100644 index 0000000000..13c6c08cc1 --- /dev/null +++ b/src/modules/SX126x/SX126x_config.cpp @@ -0,0 +1,779 @@ +#include "SX126x.h" + +// this file contains all configuration methods +// of the SX126x, which let user control the +// modulation properties, packet configuration etc. + +#if !RADIOLIB_EXCLUDE_SX126X + +void SX126x::setDio1Action(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); +} + +void SX126x::clearDio1Action() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void SX126x::setPacketReceivedAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearPacketReceivedAction() { + this->clearDio1Action(); +} + +void SX126x::setPacketSentAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearPacketSentAction() { + this->clearDio1Action(); +} + +void SX126x::setChannelScanAction(void (*func)(void)) { + this->setDio1Action(func); +} + +void SX126x::clearChannelScanAction() { + this->clearDio1Action(); +} + +int16_t SX126x::setBandwidth(float bw) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // ensure byte conversion doesn't overflow + RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); + + // check allowed bandwidth values + uint8_t bw_div2 = bw / 2 + 0.01f; + switch (bw_div2) { + case 3: // 7.8: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8; + break; + case 5: // 10.4: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4; + break; + case 7: // 15.6: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6; + break; + case 10: // 20.8: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8; + break; + case 15: // 31.25: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25; + break; + case 20: // 41.7: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7; + break; + case 31: // 62.5: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5; + break; + case 62: // 125.0: + this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0; + break; + case 125: // 250.0 + this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0; + break; + case 250: // 500.0 + this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // update modulation parameters + this->bandwidthKhz = bw; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::setSpreadingFactor(uint8_t sf) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + + // update modulation parameters + this->spreadingFactor = sf; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::setCodingRate(uint8_t cr) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + // update modulation parameters + this->codingRate = cr - 4; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update register + const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))}; + return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)); +} + +int16_t SX126x::setCurrentLimit(float currentLimit) { + // check allowed range + if(!((currentLimit >= 0) && (currentLimit <= 140))) { + return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT); + } + + // calculate raw value + uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f); + + // update register + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1)); +} + +float SX126x::getCurrentLimit() { + // get the raw value + uint8_t ocp = 0; + readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + + // return the actual value + return((float)ocp * 2.5f); +} + +int16_t SX126x::setPreambleLength(size_t preambleLength) { + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + this->preambleLengthLoRa = preambleLength; + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + this->preambleLengthFSK = preambleLength; + // maximum preamble detector length is limited by sync word length + // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45 + uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK); + this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : + maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : + maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : + maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : + RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; + return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType)); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX126x::setFrequencyDeviation(float freqDev) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0f) { + newFreqDev = 0.6f; + } + + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + + // calculate raw frequency deviation value + uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f)); + + // check modulation parameters + this->frequencyDev = freqDevRaw; + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setBitRate(float br) { + // check active modem + uint8_t modem = getPacketType(); + if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + } + + // calculate raw bit rate value + uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f)); + + // check modulation parameters + this->bitRate = brRaw; + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + // set the basic config + state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); + RADIOLIB_ASSERT(state); + + // set hopping grid + this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC; + + } + + return(state); +} + + +int16_t SX126x::checkDataRate(DataRate_t dr) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // select interpretation based on active modem + uint8_t modem = this->getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +int16_t SX126x::setRxBandwidth(float rxBw) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check modulation parameters + /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) { + return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); + }*/ + this->rxBandwidthKhz = rxBw; + + // check allowed receiver bandwidth values + if(fabsf(rxBw - 4.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8; + } else if(fabsf(rxBw - 5.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8; + } else if(fabsf(rxBw - 7.3f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3; + } else if(fabsf(rxBw - 9.7f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7; + } else if(fabsf(rxBw - 11.7f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7; + } else if(fabsf(rxBw - 14.6f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6; + } else if(fabsf(rxBw - 19.5f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5; + } else if(fabsf(rxBw - 23.4f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4; + } else if(fabsf(rxBw - 29.3f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3; + } else if(fabsf(rxBw - 39.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0; + } else if(fabsf(rxBw - 46.9f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9; + } else if(fabsf(rxBw - 58.6f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6; + } else if(fabsf(rxBw - 78.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2; + } else if(fabsf(rxBw - 93.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8; + } else if(fabsf(rxBw - 117.3f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3; + } else if(fabsf(rxBw - 156.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2; + } else if(fabsf(rxBw - 187.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2; + } else if(fabsf(rxBw - 234.3f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3; + } else if(fabsf(rxBw - 312.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0; + } else if(fabsf(rxBw - 373.6f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6; + } else if(fabsf(rxBw - 467.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0; + } else { + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + } + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { + // update RX gain setting register + uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; + int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); + RADIOLIB_ASSERT(state); + + // add Rx Gain register to retention memory if requested + if(persist) { + // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3 + const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) }; + state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3); + } + + return(state); +} + +int16_t SX126x::setDataShaping(uint8_t sh) { + // check active modem + uint8_t modem = getPacketType(); + if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE; + break; + case RADIOLIB_SHAPING_0_3: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3; + break; + case RADIOLIB_SHAPING_0_5: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5; + break; + case RADIOLIB_SHAPING_0_7: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7; + break; + case RADIOLIB_SHAPING_1_0: + this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1; + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + // update modulation parameters + return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // check sync word Length + if(len > 8) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // write sync word + int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len); + RADIOLIB_ASSERT(state); + + // update packet parameters + this->syncWordLength = len * 8; + + // maximum preamble detector length is limited by sync word length + // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45 + uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK); + this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 : + maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 : + maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 : + maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 : + RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF; + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); + + return(state); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + return(setSyncWord(syncWord[0])); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word + if(len != sizeof(uint32_t)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t)); + + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check sync word Length + if(bitsLen > 0x40) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + uint8_t bytesLen = bitsLen / 8; + if ((bitsLen % 8) != 0) { + bytesLen++; + } + + return(setSyncWord(syncWord, bytesLen)); +} + +int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { + // check active modem + uint8_t modem = getPacketType(); + + if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // update packet parameters + switch(len) { + case 0: + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF; + break; + case 1: + if(inverted) { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV; + } else { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE; + } + break; + case 2: + if(inverted) { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV; + } else { + this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE; + } + break; + default: + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + + // write initial CRC value + uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)}; + state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2); + RADIOLIB_ASSERT(state); + + // write CRC polynomial value + data[0] = (uint8_t)((polynomial >> 8) & 0xFF); + data[1] = (uint8_t)(polynomial & 0xFF); + state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2); + + return(state); + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion + + // update packet parameters + if(len) { + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON; + } else { + this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF; + } + + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + int16_t state = RADIOLIB_ERR_NONE; + if(!enabled) { + // disable whitening + this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF; + + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + + } else { + // enable whitening + this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON; + + // write initial whitening value + // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register" + uint8_t data[2]; + // first read the actual value and mask 7 MSB which we can not change + // if different value is written in 7 MSB, the Rx won't even work (tested on HW) + state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1); + RADIOLIB_ASSERT(state); + + data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01); + data[1] = (uint8_t)(initial & 0xFF); + state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2); + RADIOLIB_ASSERT(state); + + state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType); + RADIOLIB_ASSERT(state); + } + return(state); +} + +int16_t SX126x::fixedPacketLengthMode(uint8_t len) { + return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len)); +} + +int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen)); +} +int16_t SX126x::implicitHeader(size_t len) { + return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len)); +} + +int16_t SX126x::explicitHeader() { + return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT)); +} + +int16_t SX126x::setRegulatorLDO() { + return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO)); +} + +int16_t SX126x::setRegulatorDCDC() { + return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC)); +} + +int16_t SX126x::setEncoding(uint8_t encoding) { + return(setWhitening(encoding)); +} + +void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) { + this->mod->setRfSwitchPins(rxEn, txEn); +} + +void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + this->mod->setRfSwitchTable(pins, table); +} + +int16_t SX126x::forceLDRO(bool enable) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // update modulation parameters + this->ldroAuto = false; + this->ldrOptimize = (uint8_t)enable; + return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t SX126x::autoLDRO() { + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->ldroAuto = true; + return(RADIOLIB_ERR_NONE); +} + +int16_t SX126x::invertIQ(bool enable) { + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + if(enable) { + this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED; + } else { + this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; + } + + return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled)); +} + +int16_t SX126x::setTCXO(float voltage, uint32_t delay) { + // check if TCXO is enabled at all + if(this->XTAL) { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // set mode to standby + standby(); + + // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it + if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) { + clearDeviceErrors(); + } + + // check 0 V disable + if(fabsf(voltage - 0.0f) <= 0.001f) { + return(reset(true)); + } + + // check alowed voltage values + uint8_t data[4]; + if(fabsf(voltage - 1.6f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6; + } else if(fabsf(voltage - 1.7f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7; + } else if(fabsf(voltage - 1.8f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8; + } else if(fabsf(voltage - 2.2f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2; + } else if(fabsf(voltage - 2.4f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4; + } else if(fabsf(voltage - 2.7f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7; + } else if(fabsf(voltage - 3.0f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0; + } else if(fabsf(voltage - 3.3f) <= 0.001f) { + data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3; + } else { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // calculate delay + uint32_t delayValue = (float)delay / 15.625f; + data[1] = (uint8_t)((delayValue >> 16) & 0xFF); + data[2] = (uint8_t)((delayValue >> 8) & 0xFF); + data[3] = (uint8_t)(delayValue & 0xFF); + + this->tcxoDelay = delay; + + // enable TCXO control on DIO3 + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4)); +} + +int16_t SX126x::setDio2AsRfSwitch(bool enable) { + uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); +} +int16_t SX126x::setPaRampTime(uint8_t rampTime) { + return(this->setTxParams(this->pwr, rampTime)); +} + +int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetType = mode; + return(state); +} + +int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) { + // check active modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + + // update cached value + this->headerType = hdrType; + this->implicitLen = len; + + return(state); +} + +int16_t SX126x::setFrequencyRaw(float freq) { + // calculate raw value + this->freqMHz = freq; + uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; + return(setRfFrequency(frf)); +} + +int16_t SX126x::config(uint8_t modem) { + // reset buffer base address + int16_t state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // set modem + uint8_t data[7]; + data[0] = modem; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1); + RADIOLIB_ASSERT(state); + + // set Rx/Tx fallback mode to STDBY_RC + data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); + RADIOLIB_ASSERT(state); + + // set some CAD parameters - will be overwritten when calling CAD anyway + data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB; + data[1] = this->spreadingFactor + 13; + data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; + data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; + data[4] = 0x00; + data[5] = 0x00; + data[6] = 0x00; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); + RADIOLIB_ASSERT(state); + + // clear IRQ + state = clearIrqStatus(); + state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE); + RADIOLIB_ASSERT(state); + + // calibrate all blocks + data[0] = RADIOLIB_SX126X_CALIBRATE_ALL; + state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false); + RADIOLIB_ASSERT(state); + + // wait for calibration completion + this->mod->hal->delay(5); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + // check calibration result + state = this->mod->SPIcheckStream(); + + // if something failed, show the device errors + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); + } + #endif + + return(state); +} + +#endif diff --git a/src/modules/SX126x/SX126x_registers.h b/src/modules/SX126x/SX126x_registers.h new file mode 100644 index 0000000000..15ac88f11b --- /dev/null +++ b/src/modules/SX126x/SX126x_registers.h @@ -0,0 +1,395 @@ +#if !defined(_RADIOLIB_SX126X_REGISTERS_H) +#define _RADIOLIB_SX126X_REGISTERS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_SX126X + +// SX126X register map +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 +#define RADIOLIB_SX126X_REG_VERSION_STRING 0x0320 +#define RADIOLIB_SX126X_REG_HOPPING_ENABLE 0x0385 +#define RADIOLIB_SX126X_REG_LR_FHSS_PACKET_LENGTH 0x0386 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_HOPPING_BLOCKS 0x0387 +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(X) (0x0388 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_LSB(X) (0x0389 + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(X) (0x038A + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_1(X) (0x038B + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_2(X) (0x038C + (X)*6) +#define RADIOLIB_SX126X_REG_LR_FHSS_FREQX_3(X) (0x038D + (X)*6) +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT 0x0401 +#define RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE 0x0580 +#define RADIOLIB_SX126X_REG_DIOX_DRIVE_STRENGTH 0x0582 +#define RADIOLIB_SX126X_REG_DIOX_IN_ENABLE 0x0583 +#define RADIOLIB_SX126X_REG_DIOX_PULL_UP_CTRL 0x0584 +#define RADIOLIB_SX126X_REG_DIOX_PULL_DOWN_CTRL 0x0585 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 +#define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 +#define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 +#define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 +#define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB +#define RADIOLIB_SX126X_REG_CRC_INITIAL_MSB 0x06BC +#define RADIOLIB_SX126X_REG_CRC_INITIAL_LSB 0x06BD +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE +#define RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF +#define RADIOLIB_SX126X_REG_SYNC_WORD_0 0x06C0 +#define RADIOLIB_SX126X_REG_SYNC_WORD_1 0x06C1 +#define RADIOLIB_SX126X_REG_SYNC_WORD_2 0x06C2 +#define RADIOLIB_SX126X_REG_SYNC_WORD_3 0x06C3 +#define RADIOLIB_SX126X_REG_SYNC_WORD_4 0x06C4 +#define RADIOLIB_SX126X_REG_SYNC_WORD_5 0x06C5 +#define RADIOLIB_SX126X_REG_SYNC_WORD_6 0x06C6 +#define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 +#define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD +#define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 +#define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 +#define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 +#define RADIOLIB_SX126X_REG_IQ_CONFIG 0x0736 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB 0x0740 +#define RADIOLIB_SX126X_REG_LORA_SYNC_WORD_LSB 0x0741 +#define RADIOLIB_SX126X_REG_LORA_RX_CODING_RATE 0x0749 +#define RADIOLIB_SX126X_REG_FREQ_ERROR_RX_CRC 0x076B +#define RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS 0x07CD +#define RADIOLIB_SX126X_REG_RX_ADDR_PTR 0x0803 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_0 0x0819 +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_1 0x081A +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_2 0x081B +#define RADIOLIB_SX126X_REG_RANDOM_NUMBER_3 0x081C +#define RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1 +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_0 0x088B +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_1 0x088C +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_2 0x088D +#define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E +#define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B +#define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC +#define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 +#define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 +#define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_P 0x08E4 +#define RADIOLIB_SX126X_REG_ANA_MIXER 0x08E5 +#define RADIOLIB_SX126X_REG_OCP_CONFIGURATION 0x08E7 +#define RADIOLIB_SX126X_REG_RTC_CTRL 0x0902 +#define RADIOLIB_SX126X_REG_XTA_TRIM 0x0911 +#define RADIOLIB_SX126X_REG_XTB_TRIM 0x0912 +#define RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL 0x0920 +#define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 +#define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 + +// SX126X SPI command variables +//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION +#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) +#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained +#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled +#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled + +//RADIOLIB_SX126X_CMD_SET_STANDBY +#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator + +//RADIOLIB_SX126X_CMD_SET_RX +#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) + +//RADIOLIB_SX126X_CMD_SET_TX +#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) + +//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection + +//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE +#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + +//RADIOLIB_SX126X_CMD_CALIBRATE +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks + +//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 +#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0f) + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 +#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 +#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 + +//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) + +//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop +#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout +#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected +#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished +#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received +#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error +#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received +#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected +#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received +#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts +#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts + +//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL +#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ +#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control + +//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V + +//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE +#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK +#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS + +//RADIOLIB_SX126X_CMD_SET_TX_PARAMS +#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us +#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us +#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us +#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us +#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us +#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us +#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us +#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us + +//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 +#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz +#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz +#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz +#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz +#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz +#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz +#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz +#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz +#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz +#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz +#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz +#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled + +//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast +#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) +#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) +#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted +#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled +#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit +#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled +#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard +#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted + +//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS +#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 +#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 +#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 +#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 +#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode +#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected +#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value +#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter + +//RADIOLIB_SX126X_CMD_GET_STATUS +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC +#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS +#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX +#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX +#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved +#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out +#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command +#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute +#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done +#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent + +//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS +#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed +#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock +#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start +#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed +#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed +#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed +#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed +#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed + +//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS +#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us + +// SX126X SPI register variables +//RADIOLIB_SX126X_REG_HOPPING_ENABLE +#define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled +#define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) + +//RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB + LSB +#define RADIOLIB_SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved. +#define RADIOLIB_SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried. + +// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 +#define RADIOLIB_SX126X_TX_BITBANG_1_DISABLED 0b00000000 // 6 4 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_1_ENABLED 0b00010000 // 6 4 enabled + +// RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 +#define RADIOLIB_SX126X_TX_BITBANG_0_DISABLED 0b00000000 // 3 0 Tx bitbang: disabled (default) +#define RADIOLIB_SX126X_TX_BITBANG_0_ENABLED 0b00001100 // 3 0 enabled + +// RADIOLIB_SX126X_REG_DIOX_OUT_ENABLE +#define RADIOLIB_SX126X_DIO1_OUT_DISABLED 0b00000010 // 1 1 DIO1 output: disabled +#define RADIOLIB_SX126X_DIO1_OUT_ENABLED 0b00000000 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_OUT_DISABLED 0b00000100 // 2 2 DIO2 output: disabled +#define RADIOLIB_SX126X_DIO2_OUT_ENABLED 0b00000000 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_OUT_DISABLED 0b00001000 // 3 3 DIO3 output: disabled +#define RADIOLIB_SX126X_DIO3_OUT_ENABLED 0b00000000 // 3 3 enabled + +// RADIOLIB_SX126X_REG_DIOX_IN_ENABLE +#define RADIOLIB_SX126X_DIO1_IN_DISABLED 0b00000000 // 1 1 DIO1 input: disabled +#define RADIOLIB_SX126X_DIO1_IN_ENABLED 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_DIO2_IN_DISABLED 0b00000000 // 2 2 DIO2 input: disabled +#define RADIOLIB_SX126X_DIO2_IN_ENABLED 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_DIO3_IN_DISABLED 0b00000000 // 3 3 DIO3 input: disabled +#define RADIOLIB_SX126X_DIO3_IN_ENABLED 0b00001000 // 3 3 enabled + +// RADIOLIB_SX126X_REG_RX_GAIN +#define RADIOLIB_SX126X_RX_GAIN_BOOSTED 0x96 // 7 0 Rx gain: boosted +#define RADIOLIB_SX126X_RX_GAIN_POWER_SAVING 0x94 // 7 0 power saving +#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan + +// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE +#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled +#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled + +// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS +#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing +#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted +#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed + +// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW +#define RADIOLIB_SX126X_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window + +// RADIOLIB_SX126X_REG_ANA_LNA +#define RADIOLIB_SX126X_LNA_RNG_DISABLED 0b00000001 // 0 0 random number: disabled +#define RADIOLIB_SX126X_LNA_RNG_ENABLED 0b00000000 // 0 0 enabled + +// RADIOLIB_SX126X_REG_ANA_MIXER +#define RADIOLIB_SX126X_MIXER_RNG_DISABLED 0b00000001 // 7 7 random number: disabled +#define RADIOLIB_SX126X_MIXER_RNG_ENABLED 0b00000000 // 7 7 enabled + +// size of the spectral scan result +#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33) + +// LR-FHSS configuration +#define RADIOLIB_SX126X_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 +#define RADIOLIB_SX126X_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 +#define RADIOLIB_SX126X_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 +#define RADIOLIB_SX126X_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 +#define RADIOLIB_SX126X_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK +#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) +#define RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) +#define RADIOLIB_SX126X_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled +#define RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_SX126X_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz +#define RADIOLIB_SX126X_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz + +#endif + +#endif From 21af3bf7ca3078c7ce293feb8ca0162ef37d4b7f Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Sep 2025 18:12:51 +0200 Subject: [PATCH 1611/1848] [SX126x] Add missing header files --- src/modules/SX126x/SX126x_config.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 13c6c08cc1..9a9788ea60 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -1,5 +1,8 @@ #include "SX126x.h" +#include +#include + // this file contains all configuration methods // of the SX126x, which let user control the // modulation properties, packet configuration etc. From 28707e8477d1897c312d91e65a7ae60f8d131f65 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Sep 2025 18:22:26 +0200 Subject: [PATCH 1612/1848] [SX126x] Add missing method --- src/modules/SX126x/SX126x_commands.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/SX126x/SX126x_commands.cpp b/src/modules/SX126x/SX126x_commands.cpp index e2afba0f90..f883346800 100644 --- a/src/modules/SX126x/SX126x_commands.cpp +++ b/src/modules/SX126x/SX126x_commands.cpp @@ -100,6 +100,11 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8 return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0)); } +int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { + const uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4)); +} + int16_t SX126x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) { this->mod->SPIwriteRegisterBurst(addr, data, numBytes); return(RADIOLIB_ERR_NONE); From 70bca65888d76fd777e25f957c8a759dc5384266 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 18 Sep 2025 19:27:25 +0200 Subject: [PATCH 1613/1848] [PHY] Add calculateTimeOnAir virtual method and override it in module classes --- src/modules/LR11x0/LR11x0.h | 2 +- src/modules/SX126x/SX126x.h | 2 +- src/modules/SX127x/SX127x.h | 2 +- src/modules/SX128x/SX128x.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 8 ++++++++ src/protocols/PhysicalLayer/PhysicalLayer.h | 10 ++++++++++ 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 2d00cbb063..8686f79e30 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1380,7 +1380,7 @@ class LR11x0: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; /*! \brief Get expected time-on-air for a given size of payload diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 36a4fdf8c3..ca6f2a2370 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -581,7 +581,7 @@ class SX126x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; /*! \brief Get expected time-on-air for a given size of payload diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 8d91ba2b0d..383b4369ce 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1061,7 +1061,7 @@ class SX127x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; /*! \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 7f6f8fce83..c9c471c693 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -836,7 +836,7 @@ class SX128x: public PhysicalLayer { \param len Payload length in bytes. \returns Expected time-on-air in microseconds. */ - RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; /*! \brief Get expected time-on-air for a given size of payload. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 4036f67f35..781705d0e0 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -312,6 +312,14 @@ float PhysicalLayer::getSNR() { return(RADIOLIB_ERR_UNSUPPORTED); } +RadioLibTime_t PhysicalLayer::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { + (void)modem; + (void)dr; + (void)pc; + (void)len; + return(0); +} + RadioLibTime_t PhysicalLayer::getTimeOnAir(size_t len) { (void)len; return(0); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 8876b2bc40..1ef4b46408 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -552,6 +552,16 @@ class PhysicalLayer { \returns SNR of the last received packet in dB. */ virtual float getSNR(); + + /*! + \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. + \param modem Modem type. + \param dr Data rate. + \param pc Packet config. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + virtual RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len); /*! \brief Get expected time-on-air for a given size of payload From 778a73e32b2eb8c567b94c6117fa41b4803a7d92 Mon Sep 17 00:00:00 2001 From: Chris Leishman Date: Fri, 19 Sep 2025 09:52:23 -0700 Subject: [PATCH 1614/1848] [SX126x] Remove extraneous reset after findChip (#1604) --- src/modules/SX126x/SX126x.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 105dc7e0c8..f2abcecb0a 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1347,8 +1347,8 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS; this->mod->spiConfig.stream = true; this->mod->spiConfig.parseStatusCb = SPIparseStatus; - - // try to find the SX126x chip + + // find the SX126x chip - this will also reset the module and verify the module if(!SX126x::findChip(this->chipType)) { RADIOLIB_DEBUG_BASIC_PRINTLN("No SX126x found!"); this->mod->term(); @@ -1356,9 +1356,7 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) } RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX126x"); - // reset the module and verify startup (module will be in standby mode after this) - int16_t state = reset(true); - RADIOLIB_ASSERT(state); + int16_t state = RADIOLIB_ERR_NONE; // set TCXO control, if requested if(!this->XTAL && tcxoVoltage > 0.0f) { @@ -1396,7 +1394,7 @@ bool SX126x::findChip(const char* verStr) { bool flagFound = false; while((i < 10) && !flagFound) { // reset the module - reset(); + reset(true); // read the version string char version[16] = { 0 }; From 5885ede6810536eb7bdfc80555c63730842844c2 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Sat, 20 Sep 2025 10:27:45 +0200 Subject: [PATCH 1615/1848] [LoRaWAN] Update modem, datarate and ToA handling (#1609) * [PHY] Add empty modem * [LoRaWAN] WIP: update datarate / TOA handling * [PHY] Add modem to datarate functions * [LLCC68] Add modem argument to datarate functions * [LR11x0] Add modem argument to datarate functions * [SX126x] Add modem argument to datarate functions * [SX127x] Add modem argument to datarate functions * [SX128x] Add modem argument to datarate functions * [LoRaWAN] Change datarate handling * [LoRaWAN] Fix LR-FHSS header count * [LoRaWAN] Update RFU datarates * [LR11x0] Add default case to `setModem()` * [LoRaWAN] Remove unused variable --- src/modules/LLCC68/LLCC68.cpp | 41 +- src/modules/LLCC68/LLCC68.h | 14 +- src/modules/LR11x0/LR1110.cpp | 2 + src/modules/LR11x0/LR1120.cpp | 2 + src/modules/LR11x0/LR11x0.cpp | 47 +- src/modules/LR11x0/LR11x0.h | 14 +- src/modules/SX126x/SX126x.h | 14 +- src/modules/SX126x/SX126x_config.cpp | 43 +- src/modules/SX127x/SX1272.cpp | 41 +- src/modules/SX127x/SX1272.h | 14 +- src/modules/SX127x/SX1273.cpp | 41 +- src/modules/SX127x/SX1273.h | 14 +- src/modules/SX127x/SX1277.cpp | 41 +- src/modules/SX127x/SX1277.h | 14 +- src/modules/SX127x/SX1278.cpp | 41 +- src/modules/SX127x/SX1278.h | 14 +- src/modules/SX128x/SX128x.cpp | 25 +- src/modules/SX128x/SX128x.h | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 345 ++++------- src/protocols/LoRaWAN/LoRaWAN.h | 37 +- src/protocols/LoRaWAN/LoRaWANBands.cpp | 582 +++++++++--------- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 6 +- src/protocols/PhysicalLayer/PhysicalLayer.h | 15 +- 23 files changed, 738 insertions(+), 671 deletions(-) diff --git a/src/modules/LLCC68/LLCC68.cpp b/src/modules/LLCC68/LLCC68.cpp index 15ab5c6446..8ea29f9433 100644 --- a/src/modules/LLCC68/LLCC68.cpp +++ b/src/modules/LLCC68/LLCC68.cpp @@ -110,12 +110,26 @@ int16_t LLCC68::setSpreadingFactor(uint8_t sf) { return(SX1262::setSpreadingFactor(sf)); } -int16_t LLCC68::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; +int16_t LLCC68::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); - // select interpretation based on active modem - uint8_t modem = this->getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -123,7 +137,7 @@ int16_t LLCC68::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -139,17 +153,22 @@ int16_t LLCC68::setDataRate(DataRate_t dr) { return(state); } -int16_t LLCC68::checkDataRate(DataRate_t dr) { +int16_t LLCC68::checkDataRate(DataRate_t dr, ModemType_t modem) { int16_t state = RADIOLIB_ERR_UNKNOWN; - // select interpretation based on active modem - uint8_t modem = this->getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); uint8_t bw_div2 = dr.lora.bandwidth / 2 + 0.01f; diff --git a/src/modules/LLCC68/LLCC68.h b/src/modules/LLCC68/LLCC68.h index d260b0b13c..80470bea45 100644 --- a/src/modules/LLCC68/LLCC68.h +++ b/src/modules/LLCC68/LLCC68.h @@ -90,18 +90,22 @@ class LLCC68: public SX1262 { int16_t setSpreadingFactor(uint8_t sf) override; /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 43aeddbce1..46fd4f1537 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -122,6 +122,8 @@ int16_t LR1110::setModem(ModemType_t modem) { case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); } return(RADIOLIB_ERR_WRONG_MODEM); } diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index fb0d9050fb..6ce025eccb 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -144,6 +144,8 @@ int16_t LR1120::setModem(ModemType_t modem) { case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { return(this->beginLRFHSS()); } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); } return(RADIOLIB_ERR_WRONG_MODEM); } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 2d97aa7176..d156158d95 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -955,13 +955,26 @@ int16_t LR11x0::setWhitening(bool enabled, uint16_t initial) { return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } -int16_t LR11x0::setDataRate(DataRate_t dr) { - // select interpretation based on active modem - uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - int16_t state = getPacketType(&type); +int16_t LR11x0::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); RADIOLIB_ASSERT(state); + + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } - if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -969,7 +982,7 @@ int16_t LR11x0::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -981,7 +994,7 @@ int16_t LR11x0::setDataRate(DataRate_t dr) { // set the coding rate state = this->setCodingRate(dr.lora.codingRate); - } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { + } else if(modem == RADIOLIB_MODEM_LRFHSS) { // set the basic config state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); RADIOLIB_ASSERT(state); @@ -994,18 +1007,22 @@ int16_t LR11x0::setDataRate(DataRate_t dr) { return(state); } -int16_t LR11x0::checkDataRate(DataRate_t dr) { - // select interpretation based on active modem - uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - int16_t state = getPacketType(&type); - RADIOLIB_ASSERT(state); +int16_t LR11x0::checkDataRate(DataRate_t dr, ModemType_t modem) { + int16_t state = RADIOLIB_ERR_UNKNOWN; - if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); - } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); @@ -1013,7 +1030,7 @@ int16_t LR11x0::checkDataRate(DataRate_t dr) { } - return(RADIOLIB_ERR_UNKNOWN); + return(state); } int16_t LR11x0::setPreambleLength(size_t preambleLength) { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 8686f79e30..36103e2890 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1284,18 +1284,22 @@ class LR11x0: public PhysicalLayer { int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF); /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Sets preamble length for LoRa or GFSK modem. Allowed values range from 1 to 65535. diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index ca6f2a2370..410f8f2507 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -403,18 +403,22 @@ class SX126x: public PhysicalLayer { int16_t setBitRate(float br) override; /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Sets FSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 9a9788ea60..3018f428db 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -217,12 +217,26 @@ int16_t SX126x::setBitRate(float br) { return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } -int16_t SX126x::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; +int16_t SX126x::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); - // select interpretation based on active modem - uint8_t modem = this->getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -230,7 +244,7 @@ int16_t SX126x::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -242,7 +256,7 @@ int16_t SX126x::setDataRate(DataRate_t dr) { // set the coding rate state = this->setCodingRate(dr.lora.codingRate); - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + } else if(modem == RADIOLIB_MODEM_LRFHSS) { // set the basic config state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); RADIOLIB_ASSERT(state); @@ -256,17 +270,22 @@ int16_t SX126x::setDataRate(DataRate_t dr) { } -int16_t SX126x::checkDataRate(DataRate_t dr) { +int16_t SX126x::checkDataRate(DataRate_t dr, ModemType_t modem) { int16_t state = RADIOLIB_ERR_UNKNOWN; - // select interpretation based on active modem - uint8_t modem = this->getPacketType(); - if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); - } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index ce4682bee7..c4a91c7759 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -228,12 +228,26 @@ int16_t SX1272::setBitRate(float br) { return(SX127x::setBitRateCommon(br, RADIOLIB_SX1272_REG_BIT_RATE_FRAC)); } -int16_t SX1272::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; +int16_t SX1272::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); + + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } - // select interpretation based on active modem - uint8_t modem = this->getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -241,7 +255,7 @@ int16_t SX1272::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -257,19 +271,24 @@ int16_t SX1272::setDataRate(DataRate_t dr) { return(state); } -int16_t SX1272::checkDataRate(DataRate_t dr) { +int16_t SX1272::checkDataRate(DataRate_t dr, ModemType_t modem) { int16_t state = RADIOLIB_ERR_UNKNOWN; - // select interpretation based on active modem - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index 5a269276ce..e3f0c1de89 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -180,18 +180,22 @@ class SX1272: public SX127x { int16_t setBitRate(float br) override; /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Sets transmission output power. Allowed values range from -1 to 14 dBm (RFO pin) or +2 to +20 dBm (PA_BOOST pin). diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index c9b1f4b2b9..25bd1de365 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -67,12 +67,26 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) { return(state); } -int16_t SX1273::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; +int16_t SX1273::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); + + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } - // select interpretation based on active modem - uint8_t modem = this->getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -80,7 +94,7 @@ int16_t SX1273::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -92,19 +106,24 @@ int16_t SX1273::setDataRate(DataRate_t dr) { return(state); } -int16_t SX1273::checkDataRate(DataRate_t dr) { +int16_t SX1273::checkDataRate(DataRate_t dr, ModemType_t modem) { int16_t state = RADIOLIB_ERR_UNKNOWN; - // select interpretation based on active modem - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 40395d9917..24d4bc952d 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -51,18 +51,22 @@ class SX1273: public SX1272 { int16_t setSpreadingFactor(uint8_t sf) override; /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index c4b4a1f74e..ad87fdd64e 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -109,12 +109,26 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } -int16_t SX1277::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; +int16_t SX1277::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); - // select interpretation based on active modem - uint8_t modem = this->getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -122,7 +136,7 @@ int16_t SX1277::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -134,19 +148,24 @@ int16_t SX1277::setDataRate(DataRate_t dr) { return(state); } -int16_t SX1277::checkDataRate(DataRate_t dr) { +int16_t SX1277::checkDataRate(DataRate_t dr, ModemType_t modem) { int16_t state = RADIOLIB_ERR_UNKNOWN; - // select interpretation based on active modem - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index eaaf3c649a..dabc654546 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -72,18 +72,22 @@ class SX1277: public SX1278 { int16_t setSpreadingFactor(uint8_t sf) override; /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 14335fbce7..74a861d43d 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -242,12 +242,26 @@ int16_t SX1278::setBitRate(float br) { return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC)); } -int16_t SX1278::setDataRate(DataRate_t dr) { - int16_t state = RADIOLIB_ERR_UNKNOWN; +int16_t SX1278::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); + + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } - // select interpretation based on active modem - uint8_t modem = this->getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); @@ -255,7 +269,7 @@ int16_t SX1278::setDataRate(DataRate_t dr) { // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); @@ -271,19 +285,24 @@ int16_t SX1278::setDataRate(DataRate_t dr) { return(state); } -int16_t SX1278::checkDataRate(DataRate_t dr) { +int16_t SX1278::checkDataRate(DataRate_t dr, ModemType_t modem) { int16_t state = RADIOLIB_ERR_UNKNOWN; - // select interpretation based on active modem - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_FSK_OOK) { + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); - } else if(modem == RADIOLIB_SX127X_LORA) { + } else if(modem == RADIOLIB_MODEM_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 3cfcb19cfc..524c52625e 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -191,18 +191,22 @@ class SX1278: public SX127x { int16_t setBitRate(float br) override; /*! - \brief Set data. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Check the data rate can be configured by this module. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK or LoRa). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - int16_t checkDataRate(DataRate_t dr) override; + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Sets transmission output power. Allowed values range from -4 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 6d1be330f7..f11de7e07d 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -867,11 +867,26 @@ int16_t SX128x::setPreambleLength(size_t preambleLength) { return(RADIOLIB_ERR_WRONG_MODEM); } -int16_t SX128x::setDataRate(DataRate_t dr) { - // check active modem - uint8_t modem = getPacketType(); - int16_t state = RADIOLIB_ERR_NONE; - if (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) { +int16_t SX128x::setDataRate(DataRate_t dr, ModemType_t modem) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); + + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if (modem == RADIOLIB_MODEM_LORA) { state = this->setBandwidth(dr.lora.bandwidth); RADIOLIB_ASSERT(state); state = this->setSpreadingFactor(dr.lora.spreadingFactor); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index c9c471c693..af5ec9b5ee 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -687,7 +687,7 @@ class SX128x: public PhysicalLayer { \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). \returns \ref status_codes */ - int16_t setDataRate(DataRate_t dr) override; + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; /*! \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c1e0056857..175991e8c8 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1041,9 +1041,9 @@ void LoRaWANNode::processCFList(const uint8_t* cfList) { // apply channel mask cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cLen = 14; - cOcts[0] = 0xF0; // keep datarate the same - cOcts[0] |= 0x0F; // keep Tx Power the same - cOcts[13] = 0x01; // default NbTrans = 1 + cOcts[0] = RADIOLIB_LORAWAN_DATA_RATE_UNUSED << 4; // keep datarate the same + cOcts[0] |= RADIOLIB_LORAWAN_TX_POWER_UNUSED; // keep Tx Power the same + cOcts[13] = 0x01; // default NbTrans = 1 memcpy(&cOcts[1], cfList, sizeof(this->channelMasks)); (void)execMacCommand(cid, cOcts, cLen); } @@ -1111,7 +1111,7 @@ int16_t LoRaWANNode::startMulticastSession(uint8_t cls, uint32_t mcAddr, const u if(mcDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { mcDr = this->channels[RADIOLIB_LORAWAN_RX2].dr; } - if(this->band->dataRates[mcDr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->band->dataRates[mcDr].modem != RADIOLIB_MODEM_NONE) { return(RADIOLIB_ERR_INVALID_DATA_RATE); } @@ -1209,20 +1209,22 @@ void LoRaWANNode::adrBackoff() { } // if datarate can be decreased, try it - if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > 0) { - uint8_t oldDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; - - if(this->setDatarate(oldDr - 1) == RADIOLIB_ERR_NONE) { - // if there is no dwell time limit, a lower datarate is OK - if(!this->dwellTimeUp) { - return; - } - // if there is a dwell time limit, check if this datarate allows an empty uplink - if(this->phyLayer->getTimeOnAir(13) / 1000 <= this->dwellTimeUp) { + uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + if(currentDr > 0) { + + // check if dwelltime limitation allows a lower datarate + if(this->dwellTimeUp) { + const ModemType_t modem = this->band->dataRates[currentDr - 1].modem; + const DataRate_t* dr = &this->band->dataRates[currentDr - 1].dr; + const PacketConfig_t* pc = &this->band->dataRates[currentDr - 1].pc; + if(this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, 13) / 1000 > this->dwellTimeUp) { return; } - // if the Time on Air of an empty uplink exceeded the dwell time, revert - this->setDatarate(oldDr); + } + + // try to decrease datarate (given channelplan and radio) + if(this->setDatarate(currentDr - 1) == RADIOLIB_ERR_NONE) { + return; } } @@ -1231,20 +1233,21 @@ void LoRaWANNode::adrBackoff() { // re-enabling default channels may have enabled channels that do support // the next required datarate; if datarate can be decreased, try it - if(this->channels[RADIOLIB_LORAWAN_UPLINK].dr > 0) { - uint8_t oldDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; - - if(this->setDatarate(oldDr - 1) == RADIOLIB_ERR_NONE) { - // if there is no dwell time limit, a lower datarate is OK - if(!this->dwellTimeUp) { - return; - } - // if there is a dwell time limit, check if this datarate allows an empty uplink - if(this->phyLayer->getTimeOnAir(13) / 1000 <= this->dwellTimeUp) { + if(currentDr > 0) { + + // check if dwelltime limitation allows a lower datarate + if(this->dwellTimeUp) { + const ModemType_t modem = this->band->dataRates[currentDr - 1].modem; + const DataRate_t* dr = &this->band->dataRates[currentDr - 1].dr; + const PacketConfig_t* pc = &this->band->dataRates[currentDr - 1].pc; + if(this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, 13) / 1000 > this->dwellTimeUp) { return; } - // if the Time on Air of an empty uplink exceeded the dwell time, revert - this->setDatarate(oldDr); + } + + // try to decrease datarate (given channelplan and radio) + if(this->setDatarate(currentDr - 1) == RADIOLIB_ERR_NONE) { + return; } } @@ -1384,14 +1387,11 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u } } - // set the physical layer configuration for uplink - state = this->setPhyProperties(chnl, - RADIOLIB_LORAWAN_UPLINK, - this->txPowerMax - 2*this->txPowerSteps); - RADIOLIB_ASSERT(state); - - // check whether dwell time limitation is exceeded - RadioLibTime_t toa = this->phyLayer->getTimeOnAir(len) / 1000; + const uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + const ModemType_t modem = this->band->dataRates[currentDr].modem; + const DataRate_t* dr = &this->band->dataRates[currentDr].dr; + const PacketConfig_t* pc = &this->band->dataRates[currentDr].pc; + RadioLibTime_t toa = this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, len) / 1000; if(this->dwellTimeUp) { if(toa > this->dwellTimeUp) { @@ -1400,6 +1400,12 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u } } + // set the physical layer configuration for uplink + state = this->setPhyProperties(chnl, + RADIOLIB_LORAWAN_UPLINK, + this->txPowerMax - 2*this->txPowerSteps); + RADIOLIB_ASSERT(state); + RadioModeConfig_t modeCfg; modeCfg.transmit.data = in; modeCfg.transmit.len = len; @@ -1470,26 +1476,32 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne return(RADIOLIB_ERR_NO_RX_WINDOW); } - // set the physical layer configuration for downlink - state = this->setPhyProperties(dlChannel, dir, this->txPowerMax - 2*this->txPowerSteps); - RADIOLIB_ASSERT(state); - - // calculate the timeout of an empty packet plus scanGuard - RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + this->scanGuard*1000; + const uint8_t currentDr = dlChannel->dr; + const ModemType_t modem = this->band->dataRates[currentDr].modem; + const DataRate_t* dr = &this->band->dataRates[currentDr].dr; + const PacketConfig_t* pc = &this->band->dataRates[currentDr].pc; + RadioLibTime_t toaMinUs = this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, 0); // get the maximum allowed Time-on-Air of a packet given the current datarate uint8_t maxPayLen = this->band->payloadLenMax[dlChannel->dr]; if(this->packages[RADIOLIB_LORAWAN_PACKAGE_TS011].enabled) { maxPayLen = RADIOLIB_MIN(maxPayLen, 222); // payload length is limited to 222 if under repeater } - RadioLibTime_t tMax = this->phyLayer->getTimeOnAir(maxPayLen + 13) / 1000; // mandatory FHDR is 12/13 bytes + RadioLibTime_t toaMaxMs = this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, maxPayLen + 13) / 1000; + + // set the physical layer configuration for downlink + state = this->setPhyProperties(dlChannel, dir, this->txPowerMax - 2*this->txPowerSteps); + RADIOLIB_ASSERT(state); + + // calculate the timeout of an empty packet plus scanGuard + RadioLibTime_t timeoutUs = toaMinUs + this->scanGuard*1000; // set the radio Rx parameters RadioModeConfig_t modeCfg; modeCfg.receive.irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS; modeCfg.receive.irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK; modeCfg.receive.len = 0; - modeCfg.receive.timeout = this->phyLayer->calculateRxTimeout(timeoutHost); + modeCfg.receive.timeout = this->phyLayer->calculateRxTimeout(timeoutUs); state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); RADIOLIB_ASSERT(state); @@ -1516,15 +1528,15 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne state = this->phyLayer->launchMode(); RadioLibTime_t tOpen = mod->hal->millis(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutHost / 1000 + 2)); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutUs / 1000 + 2)); // sleep for the duration of the padded Rx window - this->sleepDelay(timeoutHost / 1000, false); + this->sleepDelay(timeoutUs / 1000, false); // wait for the DIO interrupt to fire (RxDone or RxTimeout) // use a small additional delay in case the RxTimeout interrupt is slow to fire RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); - while(!downlinkAction && mod->hal->millis() - tOpen <= timeoutHost / 1000 + this->scanGuard) { + while(!downlinkAction && mod->hal->millis() - tOpen <= timeoutUs / 1000 + this->scanGuard) { mod->hal->yield(); } @@ -1543,7 +1555,7 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne // if the IRQ bit for RxTimeout is not set, something is being received, // so keep listening for maximum ToA waiting for the DIO to fire - while(!downlinkAction && mod->hal->millis() - tOpen < tMax + this->scanGuard) { + while(!downlinkAction && mod->hal->millis() - tOpen < toaMaxMs + this->scanGuard) { mod->hal->yield(); } @@ -2269,15 +2281,15 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // try to apply the datarate configuration // if value is set to 'keep current values', retrieve current value - if(macDrUp == 0x0F) { + if(macDrUp == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { macDrUp = currentDr; } - if(this->band->dataRates[macDrUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->band->dataRates[macDrUp].modem != RADIOLIB_MODEM_NONE) { // check if the module supports this data rate - DataRate_t dr; - state = this->findDataRate(macDrUp, &dr); - + state = this->phyLayer->checkDataRate(this->band->dataRates[macDrUp].dr, + this->band->dataRates[macDrUp].modem); + // if datarate in hardware all good, set datarate for now // and check if there are any available Tx channels for this datarate if(state == RADIOLIB_ERR_NONE) { @@ -2294,7 +2306,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // try to apply the power configuration // if value is set to 'keep current values', retrieve current value - if(macTxSteps == 0x0F) { + if(macTxSteps == RADIOLIB_LORAWAN_TX_POWER_UNUSED) { macTxSteps = this->txPowerSteps; } @@ -2392,15 +2404,19 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // check the requested configuration uint8_t uplinkDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; - DataRate_t dr; - if(this->band->rx1DrTable[uplinkDr][macRx1DrOffset] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - if(this->findDataRate(this->band->rx1DrTable[uplinkDr][macRx1DrOffset], &dr) == RADIOLIB_ERR_NONE) { + uint8_t rx1Dr = this->band->rx1DrTable[uplinkDr][macRx1DrOffset]; + if(rx1Dr != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + int16_t state = this->phyLayer->checkDataRate(this->band->dataRates[rx1Dr].dr, + this->band->dataRates[rx1Dr].modem); + if(state == RADIOLIB_ERR_NONE) { rx1DrOsAck = 1; } } if(macRx2Dr >= this->band->rx2.drMin && macRx2Dr <= this->band->rx2.drMax) { - if(this->band->dataRates[macRx2Dr] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { - if(this->findDataRate(macRx2Dr, &dr) == RADIOLIB_ERR_NONE) { + if(this->band->dataRates[macRx2Dr].modem != RADIOLIB_MODEM_NONE) { + int16_t state = this->phyLayer->checkDataRate(this->band->dataRates[macRx2Dr].dr, + this->band->dataRates[macRx2Dr].modem); + if(state == RADIOLIB_ERR_NONE) { rx2DrAck = 1; } } @@ -2464,10 +2480,11 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin } // check if the outermost datarates are defined and if the device supports them - DataRate_t dr; - if(this->band->dataRates[macDrMin] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED && this->findDataRate(macDrMin, &dr) == RADIOLIB_ERR_NONE) { - if(this->band->dataRates[macDrMax] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED && this->findDataRate(macDrMax, &dr) == RADIOLIB_ERR_NONE) { - drAck = 1; + if(this->band->dataRates[macDrMin].modem != RADIOLIB_MODEM_NONE && this->band->dataRates[macDrMax].modem != RADIOLIB_MODEM_NONE) { + if(this->phyLayer->checkDataRate(this->band->dataRates[macDrMin].dr, this->band->dataRates[macDrMin].modem) == RADIOLIB_ERR_NONE) { + if(this->phyLayer->checkDataRate(this->band->dataRates[macDrMax].dr, this->band->dataRates[macDrMax].modem) == RADIOLIB_ERR_NONE) { + drAck = 1; + } } } @@ -3003,9 +3020,9 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp) { uint8_t cOcts[1]; uint8_t cAck[1]; uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - uint8_t cLen = 1; // only apply Dr/Tx field - cOcts[0] = (drUp << 4); // set requested datarate - cOcts[0] |= 0x0F; // keep Tx Power the same + uint8_t cLen = 1; // only apply Dr/Tx field + cOcts[0] = (drUp << 4); // set requested datarate + cOcts[0] |= RADIOLIB_LORAWAN_TX_POWER_UNUSED; // keep Tx Power the same (void)execMacCommand(cid, cOcts, cLen, cAck); // check if ACK is set for Datarate @@ -3030,9 +3047,9 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower) { uint8_t cOcts[1]; uint8_t cAck[1]; uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; - uint8_t cLen = 1; // only apply Dr/Tx field - cOcts[0] = 0xF0; // keep datarate the same - cOcts[0] |= numSteps; // set requested Tx Power + uint8_t cLen = 1; // only apply Dr/Tx field + cOcts[0] = RADIOLIB_LORAWAN_DATA_RATE_UNUSED << 4; // keep datarate the same + cOcts[0] |= numSteps; // set requested Tx Power (void)execMacCommand(cid, cOcts, cLen, cAck); // check if ACK is set for Tx Power @@ -3055,7 +3072,7 @@ int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { } // check if datarate is available in the selected band - if(this->band->dataRates[dr] == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->band->dataRates[dr].modem != RADIOLIB_MODEM_NONE) { return(RADIOLIB_ERR_INVALID_DATA_RATE); } @@ -3065,8 +3082,7 @@ int16_t LoRaWANNode::setRx2Dr(uint8_t dr) { } // find and check if the datarate is available for this radio module - DataRate_t dataRate; - int16_t state = findDataRate(dr, &dataRate); + int16_t state = this->phyLayer->checkDataRate(this->band->dataRates[dr].dr, this->band->dataRates[dr].modem); RADIOLIB_ASSERT(state); // passed all checks, so configure the datarate @@ -3155,51 +3171,12 @@ RadioLibTime_t LoRaWANNode::getLastToA() { int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, int8_t pwr, size_t pre) { int16_t state = RADIOLIB_ERR_NONE; - // get the currently configured modem from the radio - ModemType_t modem; - state = this->phyLayer->getModem(&modem); + // set datarate (and modem implicitly) + const DataRate_t* dr = &this->band->dataRates[chnl->dr].dr; + state = this->phyLayer->checkDataRate(*dr, this->band->dataRates[chnl->dr].modem); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setDataRate(*dr, this->band->dataRates[chnl->dr].modem); RADIOLIB_ASSERT(state); - - // set modem-dependent functions - switch(this->band->dataRates[chnl->dr] & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { - case(RADIOLIB_LORAWAN_DATA_RATE_LORA): - if(modem != ModemType_t::RADIOLIB_MODEM_LORA) { - state = this->phyLayer->setModem(ModemType_t::RADIOLIB_MODEM_LORA); - RADIOLIB_ASSERT(state); - } - modem = ModemType_t::RADIOLIB_MODEM_LORA; - // downlink messages are sent with inverted IQ - if(dir == RADIOLIB_LORAWAN_DOWNLINK) { - state = this->phyLayer->invertIQ(true); - } else { - state = this->phyLayer->invertIQ(false); - } - RADIOLIB_ASSERT(state); - break; - - case(RADIOLIB_LORAWAN_DATA_RATE_FSK): - if(modem != ModemType_t::RADIOLIB_MODEM_FSK) { - state = this->phyLayer->setModem(ModemType_t::RADIOLIB_MODEM_FSK); - RADIOLIB_ASSERT(state); - } - modem = ModemType_t::RADIOLIB_MODEM_FSK; - state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); - RADIOLIB_ASSERT(state); - break; - - case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): - if(modem != ModemType_t::RADIOLIB_MODEM_LRFHSS) { - state = this->phyLayer->setModem(ModemType_t::RADIOLIB_MODEM_LRFHSS); - RADIOLIB_ASSERT(state); - } - modem = ModemType_t::RADIOLIB_MODEM_LRFHSS; - break; - - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency = %7.3f MHz, TX = %d dBm", chnl->freq / 10000.0, pwr); @@ -3212,33 +3189,41 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, state = this->phyLayer->setOutputPower(pwr); RADIOLIB_ASSERT(state); - DataRate_t dr; - state = findDataRate(chnl->dr, &dr); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setDataRate(dr); - RADIOLIB_ASSERT(state); - // this only needs to be done once-ish uint8_t syncWord[4] = { 0 }; uint8_t syncWordLen = 0; - size_t preLen = 0; - switch(modem) { + + switch(this->band->dataRates[chnl->dr].modem) { case(ModemType_t::RADIOLIB_MODEM_FSK): { - preLen = 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN; + state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING); + RADIOLIB_ASSERT(state); + state = this->phyLayer->setPreambleLength(pre ? pre : 8*RADIOLIB_LORAWAN_GFSK_PREAMBLE_LEN); + RADIOLIB_ASSERT(state); + syncWord[0] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 16); syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; syncWordLen = 3; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, FD = %4.1f kHz", - (double)dr.fsk.bitRate, (double)dr.fsk.freqDev); + (double)dr->fsk.bitRate, (double)dr->fsk.freqDev); } break; case(ModemType_t::RADIOLIB_MODEM_LORA): { - preLen = RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN; + if(dir == RADIOLIB_LORAWAN_DOWNLINK) { + state = this->phyLayer->invertIQ(true); + } else { + state = this->phyLayer->invertIQ(false); + } + RADIOLIB_ASSERT(state); + state = this->phyLayer->setPreambleLength(pre ? pre : RADIOLIB_LORAWAN_LORA_PREAMBLE_LEN); + RADIOLIB_ASSERT(state); + syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", - dr.lora.spreadingFactor, (double)dr.lora.bandwidth, dr.lora.codingRate, dir ? 'D' : 'U'); + dr->lora.spreadingFactor, (double)dr->lora.bandwidth, dr->lora.codingRate, dir ? 'D' : 'U'); } break; case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { @@ -3248,7 +3233,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; syncWordLen = 4; RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LR-FHSS: BW = 0x%02x, CR = 0x%02x kHz, grid = %c", - dr.lrFhss.bw, dr.lrFhss.cr, dr.lrFhss.narrowGrid ? 'N' : 'W'); + dr->lrFhss.bw, dr->lrFhss.cr, dr->lrFhss.narrowGrid ? 'N' : 'W'); } break; default: @@ -3258,13 +3243,6 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, state = this->phyLayer->setSyncWord(syncWord, syncWordLen); RADIOLIB_ASSERT(state); - // if a preamble length is supplied, overrule the 'calculated' preamble length - if(pre) { - preLen = pre; - } - if(modem != ModemType_t::RADIOLIB_MODEM_LRFHSS) { - state = this->phyLayer->setPreambleLength(preLen); - } return(state); } @@ -3565,11 +3543,6 @@ RadioLibTime_t LoRaWANNode::timeUntilUplink() { } uint8_t LoRaWANNode::getMaxPayloadLen() { - // configure the uplink channel properties - this->setPhyProperties(&this->channels[RADIOLIB_LORAWAN_UPLINK], - RADIOLIB_LORAWAN_UPLINK, - this->txPowerMax - 2*this->txPowerSteps); - uint8_t minLen = 0; uint8_t maxLen = this->band->payloadLenMax[this->channels[RADIOLIB_LORAWAN_UPLINK].dr]; if(this->packages[RADIOLIB_LORAWAN_PACKAGE_TS011].enabled) { @@ -3583,8 +3556,13 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { return(maxLen - 13 - this->fOptsUpLen); } + const uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + const ModemType_t modem = this->band->dataRates[currentDr].modem; + const DataRate_t* dr = &this->band->dataRates[currentDr].dr; + const PacketConfig_t* pc = &this->band->dataRates[currentDr].pc; + // fast exit in case upper limit is already good - if(this->phyLayer->getTimeOnAir(maxLen) / 1000 <= this->dwellTimeUp) { + if(this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, maxLen) / 1000 <= this->dwellTimeUp) { // subtract FHDR (13 bytes) as well as any FOpts return(maxLen - 13 - this->fOptsUpLen); } @@ -3592,7 +3570,7 @@ uint8_t LoRaWANNode::getMaxPayloadLen() { // do some binary search to find maximum allowed length uint8_t curLen = (minLen + maxLen) / 2; while(curLen != minLen && curLen != maxLen) { - if(this->phyLayer->getTimeOnAir(curLen) / 1000 > this->dwellTimeUp) { + if(this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, curLen) / 1000 > this->dwellTimeUp) { maxLen = curLen; } else { minLen = curLen; @@ -3655,87 +3633,6 @@ void LoRaWANNode::removePackage(uint8_t packageId) { return; } -int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { - int16_t state = RADIOLIB_ERR_NONE; - - ModemType_t modemNew; - - uint8_t dataRateBand = this->band->dataRates[dr]; - - switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_MODEM) { - case(RADIOLIB_LORAWAN_DATA_RATE_LORA): - modemNew = ModemType_t::RADIOLIB_MODEM_LORA; - dataRate->lora.spreadingFactor = ((dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_SF) >> 3) + 7; - switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ): - dataRate->lora.bandwidth = 125.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ): - dataRate->lora.bandwidth = 250.0; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ): - dataRate->lora.bandwidth = 500.0; - break; - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - dataRate->lora.codingRate = 5; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_FSK): - modemNew = ModemType_t::RADIOLIB_MODEM_FSK; - dataRate->fsk.bitRate = 50; - dataRate->fsk.freqDev = 25; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS): - modemNew = ModemType_t::RADIOLIB_MODEM_LRFHSS; - switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_BW) { - case(RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ): - dataRate->lrFhss.bw = 0x02; // specific encoding - dataRate->lrFhss.narrowGrid = 1; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ): - dataRate->lrFhss.bw = 0x04; // specific encoding - dataRate->lrFhss.narrowGrid = 1; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ): - dataRate->lrFhss.bw = 0x08; // specific encoding - dataRate->lrFhss.narrowGrid = 0; - break; - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - switch(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_CR) { - case(RADIOLIB_LORAWAN_DATA_RATE_CR_1_3): - dataRate->lrFhss.cr = 0x03; - break; - case(RADIOLIB_LORAWAN_DATA_RATE_CR_2_3): - dataRate->lrFhss.cr = 0x01; - break; - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - break; - default: - return(RADIOLIB_ERR_UNSUPPORTED); - } - - // get the currently configured modem from the radio - ModemType_t modemCurrent; - state = this->phyLayer->getModem(&modemCurrent); - RADIOLIB_ASSERT(state); - - // if the required modem is different than the current one, change over - if(modemNew != modemCurrent) { - state = this->phyLayer->standby(); - RADIOLIB_ASSERT(state); - state = this->phyLayer->setModem(modemNew); - RADIOLIB_ASSERT(state); - } - - state = this->phyLayer->checkDataRate(*dataRate); - return(state); -} - void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t addr, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 43e9bca1ac..4d6244bc65 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -47,28 +47,8 @@ #define RADIOLIB_LORAWAN_FPORT_RESERVED (0xE0 << 0) // 7 0 fPort values equal to and larger than this are reserved // data rate encoding -#define RADIOLIB_LORAWAN_DATA_RATE_MODEM (0x03 << 6) // 7 6 modem mask -#define RADIOLIB_LORAWAN_DATA_RATE_LORA (0x00 << 6) // 7 6 use LoRa modem -#define RADIOLIB_LORAWAN_DATA_RATE_FSK (0x01 << 6) // 7 6 use FSK modem -#define RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS (0x02 << 6) // 7 6 use LR-FHSS modem -#define RADIOLIB_LORAWAN_DATA_RATE_SF (0x07 << 3) // 5 3 LoRa spreading factor mask -#define RADIOLIB_LORAWAN_DATA_RATE_SF_12 (0x05 << 3) // 5 3 LoRa spreading factor: SF12 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_11 (0x04 << 3) // 5 3 SF11 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_10 (0x03 << 3) // 5 3 SF10 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_9 (0x02 << 3) // 5 3 SF9 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_8 (0x01 << 3) // 5 3 SF8 -#define RADIOLIB_LORAWAN_DATA_RATE_SF_7 (0x00 << 3) // 5 3 SF7 -#define RADIOLIB_LORAWAN_DATA_RATE_BW (0x03 << 1) // 2 1 bandwidth mask -#define RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ (0x00 << 1) // 2 1 125 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ (0x01 << 1) // 2 1 250 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ (0x02 << 1) // 2 1 LoRa bandwidth: 500 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ (0x00 << 1) // 2 1 137 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ (0x01 << 1) // 2 1 336 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ (0x02 << 1) // 2 1 LR-FHSS bandwidth: 1523 kHz -#define RADIOLIB_LORAWAN_DATA_RATE_CR (0x01 << 0) // 0 0 coding rate mask -#define RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 (0x00 << 0) // 0 0 LR-FHSS coding rate: 1/3 -#define RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 (0x01 << 0) // 0 0 2/3 -#define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0xFF << 0) // 7 0 unused data rate +#define RADIOLIB_LORAWAN_DATA_RATE_UNUSED (0x0F << 0) // reserved / unused data rate +#define RADIOLIB_LORAWAN_TX_POWER_UNUSED (0x0F << 0) // reserved / unused Tx power // channels and channel plans #define RADIOLIB_LORAWAN_UPLINK (0x00 << 0) @@ -424,6 +404,14 @@ struct LoRaWANChannelSpan_t { // alias for unused channel span #define RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE { .numChannels = 0, .freqStart = 0, .freqStep = 0, .drMin = 0, .drMax = 0, .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } +struct LoRaWANDataRate_t { + ModemType_t modem; + DataRate_t dr; + PacketConfig_t pc; +}; + +#define RADIOLIB_DATARATE_NONE { .modem = RADIOLIB_MODEM_NONE, .dr = {.lora = {0, 0, 0}}, .pc = {.lora = { 8, 0, 0, 0}}} + /*! \struct LoRaWANBand_t \brief Structure to save information about LoRaWAN band @@ -486,7 +474,7 @@ struct LoRaWANBand_t { LoRaWANChannel_t txAck[2]; /*! \brief The corresponding datarates, bandwidths and coding rates for DR index */ - uint8_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; + LoRaWANDataRate_t dataRates[RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES]; }; // supported bands @@ -1228,9 +1216,6 @@ class LoRaWANNode { // it assumes that the MIC is the last 4 bytes of the message bool verifyMIC(uint8_t* msg, size_t len, uint8_t* key); - // find the first usable data rate for the given band - int16_t findDataRate(uint8_t dr, DataRate_t* dataRate); - // function to encrypt and decrypt payloads (regular uplink/downlink) void processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t addr, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter); diff --git a/src/protocols/LoRaWAN/LoRaWANBands.cpp b/src/protocols/LoRaWAN/LoRaWANBands.cpp index c1044cbac0..38c8fed544 100644 --- a/src/protocols/LoRaWAN/LoRaWANBands.cpp +++ b/src/protocols/LoRaWAN/LoRaWANBands.cpp @@ -41,21 +41,21 @@ const LoRaWANBand_t EU868 = { }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DrTable = { - { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, - { 3, 2, 1, 0, 0, 0, 0xFF, 0xFF }, - { 4, 3, 2, 1, 0, 0, 0xFF, 0xFF }, - { 5, 4, 3, 2, 1, 0, 0xFF, 0xFF }, - { 6, 5, 4, 3, 2, 1, 0xFF, 0xFF }, - { 7, 6, 5, 4, 3, 2, 0xFF, 0xFF }, - { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, - { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 1, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 2, 1, 0, 0, 0, 0, 0x0F, 0x0F }, + { 3, 2, 1, 0, 0, 0, 0x0F, 0x0F }, + { 4, 3, 2, 1, 0, 0, 0x0F, 0x0F }, + { 5, 4, 3, 2, 1, 0, 0x0F, 0x0F }, + { 6, 5, 4, 3, 2, 1, 0x0F, 0x0F }, + { 7, 6, 5, 4, 3, 2, 0x0F, 0x0F }, + { 1, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 2, 1, 0, 0, 0, 0, 0x0F, 0x0F }, + { 1, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 2, 1, 0, 0, 0, 0, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 8695250, .drMin = 0, .drMax = 7, .dr = 0 }, .txWoR = { @@ -67,21 +67,21 @@ const LoRaWANBand_t EU868 = { { .idx = 1, .freq = 8659000, .drMin = 3, .drMax = 3, .dr = 3 } }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_137_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_336_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 250, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {2, 3, 1}}, .pc = {.lrFhss = {3}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {2, 1, 1}}, .pc = {.lrFhss = {2}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {4, 3, 1}}, .pc = {.lrFhss = {3}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {4, 1, 1}}, .pc = {.lrFhss = {2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -130,21 +130,21 @@ const LoRaWANBand_t US915 = { .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }, .rx1DrTable = { - { 10, 9, 8, 8, 0xFF, 0xFF, 0xFF, 0xFF }, - { 11, 10, 9, 8, 0xFF, 0xFF, 0xFF, 0xFF }, - { 12, 11, 10, 9, 0xFF, 0xFF, 0xFF, 0xFF }, - { 13, 12, 11, 10, 0xFF, 0xFF, 0xFF, 0xFF }, - { 13, 13, 12, 11, 0xFF, 0xFF, 0xFF, 0xFF }, - { 10, 9, 8, 8, 0xFF, 0xFF, 0xFF, 0xFF }, - { 11, 10, 9, 8, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 10, 9, 8, 8, 0x0F, 0x0F, 0x0F, 0x0F }, + { 11, 10, 9, 8, 0x0F, 0x0F, 0x0F, 0x0F }, + { 12, 11, 10, 9, 0x0F, 0x0F, 0x0F, 0x0F }, + { 13, 12, 11, 10, 0x0F, 0x0F, 0x0F, 0x0F }, + { 13, 13, 12, 11, 0x0F, 0x0F, 0x0F, 0x0F }, + { 10, 9, 8, 8, 0x0F, 0x0F, 0x0F, 0x0F }, + { 11, 10, 9, 8, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8 }, .txWoR = { @@ -156,21 +156,21 @@ const LoRaWANBand_t US915 = { { .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10 } }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_2_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {8, 3, 0}}, .pc = {.lrFhss = {3}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {8, 1, 0}}, .pc = {.lrFhss = {2}}}, + RADIOLIB_DATARATE_NONE, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + RADIOLIB_DATARATE_NONE } }; @@ -198,21 +198,21 @@ const LoRaWANBand_t EU433 = { }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DrTable = { - { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, - { 3, 2, 1, 0, 0, 0, 0xFF, 0xFF }, - { 4, 3, 2, 1, 0, 0, 0xFF, 0xFF }, - { 5, 4, 3, 2, 1, 0, 0xFF, 0xFF }, - { 6, 5, 4, 3, 2, 1, 0xFF, 0xFF }, - { 7, 6, 5, 4, 3, 2, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 1, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 2, 1, 0, 0, 0, 0, 0x0F, 0x0F }, + { 3, 2, 1, 0, 0, 0, 0x0F, 0x0F }, + { 4, 3, 2, 1, 0, 0, 0x0F, 0x0F }, + { 5, 4, 3, 2, 1, 0, 0x0F, 0x0F }, + { 6, 5, 4, 3, 2, 1, 0x0F, 0x0F }, + { 7, 6, 5, 4, 3, 2, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 4346650, .drMin = 0, .drMax = 7, .dr = 0 }, .txWoR = { @@ -224,21 +224,21 @@ const LoRaWANBand_t EU433 = { RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 250, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -287,21 +287,21 @@ const LoRaWANBand_t AU915 = { .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }, .rx1DrTable = { - { 8, 8, 8, 8, 8, 8, 0xFF, 0xFF }, - { 9, 8, 8, 8, 8, 8, 0xFF, 0xFF }, - { 10, 9, 8, 8, 8, 8, 0xFF, 0xFF }, - { 11, 10, 9, 8, 8, 8, 0xFF, 0xFF }, - { 12, 11, 10, 9, 8, 8, 0xFF, 0xFF }, - { 13, 12, 11, 10, 9, 8, 0xFF, 0xFF }, - { 13, 13, 12, 11, 10, 9, 0xFF, 0xFF }, - { 9, 8, 8, 8, 8, 8, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 8, 8, 8, 8, 8, 8, 0x0F, 0x0F }, + { 9, 8, 8, 8, 8, 8, 0x0F, 0x0F }, + { 10, 9, 8, 8, 8, 8, 0x0F, 0x0F }, + { 11, 10, 9, 8, 8, 8, 0x0F, 0x0F }, + { 12, 11, 10, 9, 8, 8, 0x0F, 0x0F }, + { 13, 12, 11, 10, 9, 8, 0x0F, 0x0F }, + { 13, 13, 12, 11, 10, 9, 0x0F, 0x0F }, + { 9, 8, 8, 8, 8, 8, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9233000, .drMin = 8, .drMax = 13, .dr = 8 }, .txWoR = { @@ -313,21 +313,21 @@ const LoRaWANBand_t AU915 = { { .idx = 1, .freq = 9215000, .drMin = 10, .drMax = 10, .dr = 10 } }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LR_FHSS | RADIOLIB_LORAWAN_DATA_RATE_CR_1_3 | RADIOLIB_LORAWAN_DATA_RATE_BW_1523_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_500_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LRFHSS, .dr = {.lrFhss = {8, 3, 0}}, .pc = {.lrFhss = {3}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 500, 5}}, .pc = {.lora = {8, false, true, false}}}, + RADIOLIB_DATARATE_NONE } }; @@ -369,21 +369,21 @@ const LoRaWANBand_t CN470 = { .drJoinRequest = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }, .rx1DrTable = { - { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 1, 1, 1, 1, 1, 1, 0xFF, 0xFF }, - { 2, 1, 1, 1, 1, 1, 0xFF, 0xFF }, - { 3, 2, 1, 1, 1, 1, 0xFF, 0xFF }, - { 4, 3, 2, 1, 1, 1, 0xFF, 0xFF }, - { 5, 4, 3, 2, 1, 1, 0xFF, 0xFF }, - { 6, 5, 4, 3, 2, 1, 0xFF, 0xFF }, - { 7, 6, 5, 4, 3, 2, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 1, 1, 1, 1, 1, 1, 0x0F, 0x0F }, + { 2, 1, 1, 1, 1, 1, 0x0F, 0x0F }, + { 3, 2, 1, 1, 1, 1, 0x0F, 0x0F }, + { 4, 3, 2, 1, 1, 1, 0x0F, 0x0F }, + { 5, 4, 3, 2, 1, 1, 0x0F, 0x0F }, + { 6, 5, 4, 3, 2, 1, 0x0F, 0x0F }, + { 7, 6, 5, 4, 3, 2, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 5053000, .drMin = 0, .drMax = 5, .dr = 0 }, .txWoR = { @@ -395,21 +395,21 @@ const LoRaWANBand_t CN470 = { RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -445,13 +445,13 @@ const LoRaWANBand_t AS923 = { { 5, 4, 3, 2, 1, 0, 6, 7 }, { 6, 5, 4, 3, 2, 1, 7, 7 }, { 7, 6, 5, 4, 3, 2, 7, 7 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9232000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { @@ -463,21 +463,21 @@ const LoRaWANBand_t AS923 = { RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 250, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -513,13 +513,13 @@ const LoRaWANBand_t AS923_2 = { { 5, 4, 3, 2, 1, 0, 6, 7 }, { 6, 5, 4, 3, 2, 1, 7, 7 }, { 7, 6, 5, 4, 3, 2, 7, 7 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9214000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { @@ -531,21 +531,21 @@ const LoRaWANBand_t AS923_2 = { RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 250, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -581,13 +581,13 @@ const LoRaWANBand_t AS923_3 = { { 5, 4, 3, 2, 1, 0, 6, 7 }, { 6, 5, 4, 3, 2, 1, 7, 7 }, { 7, 6, 5, 4, 3, 2, 7, 7 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9166000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { @@ -599,21 +599,21 @@ const LoRaWANBand_t AS923_3 = { RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 250, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -649,13 +649,13 @@ const LoRaWANBand_t AS923_4 = { { 5, 4, 3, 2, 1, 0, 6, 7 }, { 6, 5, 4, 3, 2, 1, 7, 7 }, { 7, 6, 5, 4, 3, 2, 7, 7 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9173000, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { @@ -667,21 +667,21 @@ const LoRaWANBand_t AS923_4 = { RADIOLIB_LORAWAN_CHANNEL_NONE }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_250_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 250, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -709,21 +709,21 @@ const LoRaWANBand_t KR920 = { }, .rx1Span = RADIOLIB_LORAWAN_CHANNEL_SPAN_NONE, .rx1DrTable = { - { 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 1, 0, 0, 0, 0, 0, 0xFF, 0xFF }, - { 2, 1, 0, 0, 0, 0, 0xFF, 0xFF }, - { 3, 2, 1, 0, 0, 0, 0xFF, 0xFF }, - { 4, 3, 2, 1, 0, 0, 0xFF, 0xFF }, - { 5, 4, 3, 2, 1, 0, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 1, 0, 0, 0, 0, 0, 0x0F, 0x0F }, + { 2, 1, 0, 0, 0, 0, 0x0F, 0x0F }, + { 3, 2, 1, 0, 0, 0, 0x0F, 0x0F }, + { 4, 3, 2, 1, 0, 0, 0x0F, 0x0F }, + { 5, 4, 3, 2, 1, 0, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 9219000, .drMin = 0, .drMax = 5, .dr = 0 }, .txWoR = { @@ -735,21 +735,21 @@ const LoRaWANBand_t KR920 = { { .idx = 1, .freq = 9231000, .drMin = 3, .drMax = 3, .dr = 3 } }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; @@ -783,15 +783,15 @@ const LoRaWANBand_t IN865 = { { 3, 2, 1, 0, 0, 0, 4, 5 }, { 4, 3, 2, 1, 0, 0, 5, 5 }, { 5, 4, 3, 2, 1, 0, 5, 7 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, { 7, 6, 5, 4, 3, 2, 7, 7 }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, + { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, .rx2 = { .idx = 0, .freq = 8665500, .drMin = 0, .drMax = 7, .dr = 2 }, .txWoR = { @@ -803,21 +803,21 @@ const LoRaWANBand_t IN865 = { { .idx = 1, .freq = 8669000, .drMin = 3, .drMax = 3, .dr = 3 } }, .dataRates = { - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_12 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_11 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_10 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_9 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_8 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_LORA | RADIOLIB_LORAWAN_DATA_RATE_SF_7 | RADIOLIB_LORAWAN_DATA_RATE_BW_125_KHZ, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_FSK, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED, - RADIOLIB_LORAWAN_DATA_RATE_UNUSED + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {12, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {11, 125, 5}}, .pc = {.lora = {8, false, true, true}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = {10, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 9, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 8, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + { .modem = RADIOLIB_MODEM_LORA, .dr = {.lora = { 7, 125, 5}}, .pc = {.lora = {8, false, true, false}}}, + RADIOLIB_DATARATE_NONE, + { .modem = RADIOLIB_MODEM_FSK, .dr = {.fsk = {50, 25}}, .pc = {.fsk = {40, 24, 2}}}, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE, + RADIOLIB_DATARATE_NONE } }; diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 781705d0e0..d2016ece25 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -289,13 +289,15 @@ int16_t PhysicalLayer::setPreambleLength(size_t len) { return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::setDataRate(DataRate_t dr) { +int16_t PhysicalLayer::setDataRate(DataRate_t dr, ModemType_t modem) { (void)dr; + (void)modem; return(RADIOLIB_ERR_UNSUPPORTED); } -int16_t PhysicalLayer::checkDataRate(DataRate_t dr) { +int16_t PhysicalLayer::checkDataRate(DataRate_t dr, ModemType_t modem) { (void)dr; + (void)modem; return(RADIOLIB_ERR_UNSUPPORTED); } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 1ef4b46408..4d68922be9 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -230,6 +230,7 @@ enum ModemType_t { RADIOLIB_MODEM_FSK = 0, RADIOLIB_MODEM_LORA, RADIOLIB_MODEM_LRFHSS, + RADIOLIB_MODEM_NONE, // last entry }; /*! @@ -521,18 +522,22 @@ class PhysicalLayer { virtual int16_t setPreambleLength(size_t len); /*! - \brief Set data. Must be implemented in module class if the module supports it. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \brief Set data rate. Must be implemented in module class if the module supports it. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - virtual int16_t setDataRate(DataRate_t dr); + virtual int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE); /*! \brief Check the data rate can be configured by this module. Must be implemented in module class if the module supports it. - \param dr Data rate struct. Interpretation depends on currently active modem (FSK or LoRa). + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. \returns \ref status_codes */ - virtual int16_t checkDataRate(DataRate_t dr); + virtual int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE); /*! \brief Query modem for the packet length of received payload. Must be implemented in module class. From f35d12421fa271083f23cbf7793f8036b03ae51b Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 20 Sep 2025 11:04:45 +0200 Subject: [PATCH 1616/1848] Improve support for LoRa coding rate with Long Interleaver (#1606) * Add error for packet too short * [SX126x] Add support for Long Interleaver coding rates * [LR11x0] Add packet length check for long interleaver * [LR11x0] Update comment on Long Interleaver * [SX128x] Update Long Interleaver CR 4/8 macro * [SX128x] Add packet length check for CR 4/8 with long interleaver * [SX126x] Add definitions for new CR with long interleaver --- src/TypeDef.h | 5 +++++ src/modules/LR11x0/LR11x0.cpp | 11 +++++++++++ src/modules/LR11x0/LR11x0.h | 3 ++- src/modules/SX126x/SX126x.cpp | 21 ++++++++++++++++++++- src/modules/SX126x/SX126x.h | 5 ++++- src/modules/SX126x/SX126x_config.cpp | 22 ++++++++++++++++++++-- src/modules/SX126x/SX126x_registers.h | 3 +++ src/modules/SX128x/SX128x.cpp | 7 ++++++- src/modules/SX128x/SX128x.h | 2 +- 9 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index c9d550f926..e54559a891 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -255,6 +255,11 @@ */ #define RADIOLIB_ERR_INVALID_IRQ (-29) +/*! + \brief Packet supplied to transmission method was shorter than required. +*/ +#define RADIOLIB_ERR_PACKET_TOO_SHORT (-30) + // RF69-specific status codes /*! diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index d156158d95..5f2674e894 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -179,6 +179,17 @@ int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // check packet length + if (this->codingRate > RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) { + // Long Interleaver needs at least 8 bytes + if(len < 8) { + return(RADIOLIB_ERR_PACKET_TOO_SHORT); + } + + // Long Interleaver supports up to 253 bytes if CRC is enabled + if (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 2)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + } if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 36103e2890..b3b6599d21 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1172,7 +1172,8 @@ class LR11x0: public PhysicalLayer { is undocumented and not recommended without your own FEC. \param cr LoRa coding rate denominator to be set. \param longInterleave Enable long interleaver when set to true. - Note that CR 4/7 is not possible with long interleaver enabled! + Note that with long interleaver enabled, CR 4/7 is not possible, there are packet length restrictions, + and it is not compatible with SX127x radios! \returns \ref status_codes */ int16_t setCodingRate(uint8_t cr, bool longInterleave = false); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index f2abcecb0a..660b03959e 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -200,6 +200,17 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // check packet length + if(this->codingRate > RADIOLIB_SX126X_LORA_CR_4_8) { + // Long Interleaver needs at least 8 bytes + if(len < 8) { + return(RADIOLIB_ERR_PACKET_TOO_SHORT); + } + + // Long Interleaver supports up to 253 bytes if CRC is enabled + if(this->crcTypeLoRa == RADIOLIB_SX126X_LORA_CRC_ON && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 2)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + } if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } @@ -847,9 +858,17 @@ RadioLibTime_t SX126x::getTimeOnAir(size_t len) { PacketConfig_t packetConfig = {}; if(type == RADIOLIB_SX126X_PACKET_TYPE_LORA) { + uint8_t cr = this->codingRate; + // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values + if (cr < 5) { + cr = cr + 4; + } else if (cr == 7) { + cr = cr + 1; + } + + dataRate.lora.codingRate = cr; dataRate.lora.spreadingFactor = this->spreadingFactor; dataRate.lora.bandwidth = this->bandwidthKhz; - dataRate.lora.codingRate = (uint8_t)(this->codingRate + 4); packetConfig.lora.preambleLength = this->preambleLengthLoRa; packetConfig.lora.crcEnabled = (bool)this->crcTypeLoRa; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 410f8f2507..959d4f2d08 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -352,9 +352,12 @@ class SX126x: public PhysicalLayer { \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, is undocumented and not recommended without your own FEC. \param cr LoRa coding rate denominator to be set. + \param longInterleave Enable long interleaver when set to true. + Note that with long interleaver enabled, CR 4/7 is not possible, there are packet length restrictions, + and it is not compatible with SX127x radios. \returns \ref status_codes */ - int16_t setCodingRate(uint8_t cr); + int16_t setCodingRate(uint8_t cr, bool longInterleave = false); /*! \brief Sets LoRa sync word. diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 3018f428db..a4715aed68 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -105,7 +105,7 @@ int16_t SX126x::setSpreadingFactor(uint8_t sf) { return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } -int16_t SX126x::setCodingRate(uint8_t cr) { +int16_t SX126x::setCodingRate(uint8_t cr, bool longInterleave) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); @@ -113,8 +113,26 @@ int16_t SX126x::setCodingRate(uint8_t cr) { RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + if(longInterleave) { + switch(cr) { + case 4: + this->codingRate = 0; + break; + case 5: + case 6: + this->codingRate = cr; + break; + case 8: + this->codingRate = cr - 1; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + } else { + this->codingRate = cr - 4; + } + // update modulation parameters - this->codingRate = cr - 4; return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } diff --git a/src/modules/SX126x/SX126x_registers.h b/src/modules/SX126x/SX126x_registers.h index 15ac88f11b..44690b75b1 100644 --- a/src/modules/SX126x/SX126x_registers.h +++ b/src/modules/SX126x/SX126x_registers.h @@ -230,6 +230,9 @@ #define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 #define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 #define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX126X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaver +#define RADIOLIB_SX126X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaver +#define RADIOLIB_SX126X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaver #define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled #define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index f11de7e07d..d0a6adbaad 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -315,7 +315,12 @@ int16_t SX128x::reset(bool verify) { int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) { // check packet length - if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { + if(this->codingRateLoRa == RADIOLIB_SX128X_LORA_CR_4_8_LI && this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON) { + // Long Interleaver at CR 4/8 supports up to 253 bytes if CRC is enabled + if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH - 2) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + } else if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index af5ec9b5ee..a179a052d7 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -253,7 +253,7 @@ #define RADIOLIB_SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 #define RADIOLIB_SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving #define RADIOLIB_SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving -#define RADIOLIB_SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving +#define RADIOLIB_SX128X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaving //RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS #define RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none From 8ac7893e8e9484deeaa42f01041e2c9781930a84 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Sep 2025 11:57:31 +0200 Subject: [PATCH 1617/1848] [SX128x] Fix warning for preamble length --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index d0a6adbaad..b80337c648 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -828,7 +828,7 @@ int16_t SX128x::setPreambleLength(size_t preambleLength) { uint8_t modem = getPacketType(); if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // LoRa or ranging - RADIOLIB_CHECK_RANGE(preambleLength, 2, 491520, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + RADIOLIB_CHECK_RANGE((uint32_t)preambleLength, 2, 491520, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); // check preamble length is even - no point even trying odd numbers if(preambleLength % 2 != 0) { From c938127f16883a67e9bafbfbc0febdb0bfe25627 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 20 Sep 2025 12:51:39 +0200 Subject: [PATCH 1618/1848] [SX128x] Limit preamble length to 16bit numbers --- src/modules/SX128x/SX128x.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index b80337c648..ef2748e958 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -828,7 +828,8 @@ int16_t SX128x::setPreambleLength(size_t preambleLength) { uint8_t modem = getPacketType(); if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) { // LoRa or ranging - RADIOLIB_CHECK_RANGE((uint32_t)preambleLength, 2, 491520, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + // the actual limit is 491520, however, some platforms (notably AVR) limit size_t to 16 bits + RADIOLIB_CHECK_RANGE(preambleLength, 2, 65534, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); // check preamble length is even - no point even trying odd numbers if(preambleLength % 2 != 0) { From a679e60ff9696e726f4cc51931557a21950e09ce Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 20 Sep 2025 20:24:21 +0200 Subject: [PATCH 1619/1848] [LoRaWAN] Fix CI warnings in examples --- .../LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino | 12 ++++++------ examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h | 7 +++---- .../LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 884df67570..53b21b2997 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -44,18 +44,18 @@ void setup() { Serial.println(F("Initialise the radio")); state = radio.begin(); debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true); - - // Override the default join rate - uint8_t joinDR = 4; - + // Optionally provide a custom sleep function - see config.h //node.setSleepFunction(customDelay); - + // Setup the OTAA session information node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + // Override the default join rate + node.setDatarate(4); + Serial.println(F("Join ('login') the LoRaWAN Network")); - state = node.activateOTAA(joinDR); + state = node.activateOTAA(); debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true); // Print the DevAddr diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h index 569778a589..63704d8ed1 100644 --- a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS009.h @@ -126,7 +126,7 @@ void handleTS009(uint8_t* dataDown, size_t lenDown) { case(RADIOLIB_LORAWAN_TS009_ECHO_PAYLOAD): { lenUp = lenDown; - for (int i = 1; i < lenDown; i++) { + for (size_t i = 1; i < lenDown; i++) { dataUp[i] = dataDown[i] + 1; } fPort = RADIOLIB_LORAWAN_FPORT_TS009; @@ -179,9 +179,8 @@ void handleTS009(uint8_t* dataDown, size_t lenDown) { } break; case(RADIOLIB_LORAWAN_TS009_TX_CW): { - // not implemented - uint16_t timeout = (dataDown[2] << 8) | dataDown[1]; - uint32_t freqRaw = (dataDown[5] << 16) | (dataDown[4] << 8) | (dataDown[3]); + uint16_t timeout = ((uint16_t)dataDown[2] << 8) | (uint16_t)dataDown[1]; + uint32_t freqRaw = ((uint32_t)dataDown[5] << 16) | ((uint32_t)dataDown[4] << 8) | ((uint32_t)dataDown[3]); float freq = (float)freqRaw/10000.0; uint8_t txPower = dataDown[6]; RADIOLIB_DEBUG_PRINTLN("Continuous wave: %7.3f MHz, %d dBm, %d s", freq, txPower, timeout); diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino index f9c1f437c3..4b8cdb2e64 100644 --- a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino @@ -92,7 +92,7 @@ void loop() { memset(dataUp, 0, 255); lenUp = 4; fPort = 1; - sprintf((char*)dataUp, "%04d", node.getFCntUp()); + sprintf((char*)dataUp, "%04lu", node.getFCntUp()); state = node.sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, &eventUp, &eventDown); } else { reply = false; From a3ab19ea785749428e2aaa00b16775b034647b2f Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 20 Sep 2025 21:05:51 +0200 Subject: [PATCH 1620/1848] [LoRaWAN] Fix for ADR masks on fixed bands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 175991e8c8..93d61b396d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2718,9 +2718,7 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd // set Dr/Tx field from last MAC command mAdrOpt[0] = mPtr[cLen - fLen + 1]; - // extra 2 bytes are added on the end, because in theory, - // chMaskCntl can go up to 7 (though it probably shouldn't) - uint16_t adrMasks[(RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS / 2) + 2]; + uint16_t adrMasks[RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS / 2]; memcpy(adrMasks, this->channelMasks, sizeof(this->channelMasks)); // set NbTrans partial field from last MAC command @@ -2769,13 +2767,13 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd } } } - // for fixed bands: all default 125kHz channels ON, channel mask similar to ChMask = 4 + // for fixed bands: all default 125kHz channels ON, channel mask similar to ChMaskCntl = 4 // except for CN470: all default 125kHz channels ON else if(this->band->bandNum != BandCN470) { for(int cnt = 0; cnt < 4; cnt++) { adrMasks[cnt] = 0xFFFF; } - adrMasks[chMaskCntl] = chMask; + adrMasks[4] = chMask; } else { // BandCN470 for(int cnt = 0; cnt < 5; cnt++) { adrMasks[cnt] = 0xFFFF; @@ -2783,13 +2781,13 @@ void LoRaWANNode::preprocessMacLinkAdr(uint8_t* mPtr, uint8_t cLen, uint8_t* mAd } break; case 7: - // for fixed bands: all 125kHz channels OFF, channel mask similar to ChMask = 4 + // for fixed bands: all 125kHz channels OFF, channel mask similar to ChMaskCntl = 4 // except for CN470: RFU if(this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED && this->band->bandNum != BandCN470) { for(int cnt = 0; cnt < 4; cnt++) { adrMasks[cnt] = 0x0000; } - adrMasks[chMaskCntl] = chMask; + adrMasks[4] = chMask; } break; } From 2a2f6e0edf5a527cd83d2a04a7e2eb5d220329cd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 21 Sep 2025 08:23:02 +0200 Subject: [PATCH 1621/1848] Bump version to 7.3.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index dd0524c8e3..3fd094612e 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.2.1" +version: "7.3.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 5b9c3f026a..c8b131d5fc 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.2.1", + "version": "7.3.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index aa817e81b9..e044b27b32 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.2.1 +version=7.3.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 03def78232..4d5fc26aa8 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -604,8 +604,8 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 -#define RADIOLIB_VERSION_MINOR 2 -#define RADIOLIB_VERSION_PATCH 1 +#define RADIOLIB_VERSION_MINOR 3 +#define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 #define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA)) From aeac7566dc619a2598ee97cc7601e2c7681275a5 Mon Sep 17 00:00:00 2001 From: Chris Leishman Date: Mon, 22 Sep 2025 10:37:59 -0700 Subject: [PATCH 1622/1848] [SX126x] Update doc of SX126x::getPacketLength (#1611) Add a note that the update parameter is not used for SX126x modules --- src/modules/SX126x/SX126x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 959d4f2d08..63d1bb08cd 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -545,14 +545,14 @@ class SX126x: public PhysicalLayer { /*! \brief Query modem for the packet length of received payload. - \param update Update received packet length. Will return cached value when set to false. + \param update Not used for SX126x modules. \returns Length of last received packet in bytes. */ size_t getPacketLength(bool update = true) override; /*! \brief Query modem for the packet length of received payload and Rx buffer offset. - \param update Update received packet length. Will return cached value when set to false. + \param update Not used for SX126x modules. \param offset Pointer to variable to store the Rx buffer offset. \returns Length of last received packet in bytes. */ From 05ba4e17a4f89205a229a18b9ef358065673b657 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 22 Sep 2025 20:28:53 +0100 Subject: [PATCH 1623/1848] [HAL] Fix RPi HAL initialization order --- src/hal/RPi/PiHal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hal/RPi/PiHal.h b/src/hal/RPi/PiHal.h index 76a6389b41..d67fe51204 100644 --- a/src/hal/RPi/PiHal.h +++ b/src/hal/RPi/PiHal.h @@ -27,8 +27,8 @@ class PiHal : public RadioLibHal { : RadioLibHal(PI_INPUT, PI_OUTPUT, LG_LOW, LG_HIGH, PI_RISING, PI_FALLING), _gpioDevice(gpioDevice), _spiDevice(spiDevice), - _spiChannel(spiChannel), - _spiSpeed(spiSpeed) { + _spiSpeed(spiSpeed), + _spiChannel(spiChannel) { } void init() override { @@ -232,9 +232,9 @@ class PiHal : public RadioLibHal { private: // the HAL can contain any additional private members - const unsigned int _spiSpeed; const uint8_t _gpioDevice; const uint8_t _spiDevice; + const unsigned int _spiSpeed; const uint8_t _spiChannel; int _gpioHandle = -1; int _spiHandle = -1; From 50bd0a19dcfc9b46de245cbb0184f7905c38cbfe Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 27 Sep 2025 10:35:30 +0200 Subject: [PATCH 1624/1848] [LoRaWAN] Fix persistent downlink MAC content (#1616) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 93d61b396d..40f4603f3a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -90,6 +90,10 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP state = this->isValidUplink(lenUp + this->fOptsUpLen, fPort); RADIOLIB_ASSERT(state); + // clear the MAC downlink buffer as we are going to transmit a new uplink + memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); + this->fOptsDownLen = 0; + // the first 16 bytes are reserved for MIC calculation blocks size_t uplinkMsgLen = RADIOLIB_LORAWAN_FRAME_LEN(lenUp, this->fOptsUpLen); #if RADIOLIB_STATIC_ONLY @@ -1956,11 +1960,9 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // a Class A downlink was received, so restart the ADR counter with the next uplink this->adrFCnt = this->getFCntUp() + 1; - // a Class A downlink was received, so we can clear the MAC uplink and downlink buffers + // a Class A downlink was received, so we can clear the MAC uplink buffer memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); this->fOptsUpLen = 0; - memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); - this->fOptsDownLen = 0; } #if !RADIOLIB_STATIC_ONLY From 8362b5618af8c047c2f9453f7035edf90d06fc3d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 27 Sep 2025 10:39:20 +0200 Subject: [PATCH 1625/1848] [LoRaWAN] Fix for Package FPort --- src/protocols/LoRaWAN/LoRaWAN.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 4d6244bc65..05b0067b92 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -278,7 +278,7 @@ struct LoRaWANPackage_t { /*! \brief Whether the package runs through the Application layer */ bool isAppPack; - /*! \brief Whether the FPort value is fixed or may be modified */ + /*! \brief Whether the FPort value has a fixed value by specification */ bool fixedFPort; /*! \brief Whether the package is currently in use */ @@ -289,13 +289,13 @@ struct LoRaWANPackage_t { }; constexpr LoRaWANPackage_t PackageTable[RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES] = { - { RADIOLIB_LORAWAN_PACKAGE_TS007, RADIOLIB_LORAWAN_FPORT_TS007, true, false, false, NULL }, - { RADIOLIB_LORAWAN_PACKAGE_TS003, RADIOLIB_LORAWAN_FPORT_TS003, true, true, false, NULL }, - { RADIOLIB_LORAWAN_PACKAGE_TS005, RADIOLIB_LORAWAN_FPORT_TS005, true, true, false, NULL }, - { RADIOLIB_LORAWAN_PACKAGE_TS004, RADIOLIB_LORAWAN_FPORT_TS004, true, true, false, NULL }, - { RADIOLIB_LORAWAN_PACKAGE_TS006, RADIOLIB_LORAWAN_FPORT_TS006, true, true, false, NULL }, - { RADIOLIB_LORAWAN_PACKAGE_TS009, RADIOLIB_LORAWAN_FPORT_TS009, true, false, false, NULL }, - { RADIOLIB_LORAWAN_PACKAGE_TS011, RADIOLIB_LORAWAN_FPORT_TS011, false, false, false, NULL } + { RADIOLIB_LORAWAN_PACKAGE_TS007, RADIOLIB_LORAWAN_FPORT_TS007, true, true, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS003, RADIOLIB_LORAWAN_FPORT_TS003, true, false, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS005, RADIOLIB_LORAWAN_FPORT_TS005, true, false, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS004, RADIOLIB_LORAWAN_FPORT_TS004, true, false, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS006, RADIOLIB_LORAWAN_FPORT_TS006, true, false, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS009, RADIOLIB_LORAWAN_FPORT_TS009, true, true, false, NULL }, + { RADIOLIB_LORAWAN_PACKAGE_TS011, RADIOLIB_LORAWAN_FPORT_TS011, false, true, false, NULL } }; #define RADIOLIB_LORAWAN_PACKAGE_NONE { .packId = 0, .packFPort = 0, .isAppPack = false, .fixedFPort = false, .enabled = false, .callback = NULL } From 581882371fea468d3088a39c6a327244f6169ee1 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 27 Sep 2025 10:39:38 +0200 Subject: [PATCH 1626/1848] [LoRaWAN] Fix for Package MAC commands --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 40f4603f3a..14993dcbb1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2997,7 +2997,7 @@ void LoRaWANNode::clearMacCommands(uint8_t* inOut, uint8_t* lenInOut, uint8_t di uint8_t id = inOut[i]; uint8_t fLen = 0; // include CID byte, so if command fails, we still move one byte forward - (void)this->getMacLen(id, &fLen, dir, true); + (void)this->getMacLen(id, &fLen, dir, true, &inOut[i+1]); // only clear MAC command if it should not persist until a downlink is received if(!this->isPersistentMacCommand(id, dir)) { From e8a4d7983e176a0003e216f386c0b061319383b1 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 27 Sep 2025 11:37:40 +0200 Subject: [PATCH 1627/1848] [LoRaWAN] Change `getMacDeviceTimeAns` to return current time --- .../LoRaWAN_Reference/LoRaWAN_Reference.ino | 13 ++++---- .../LoRaWAN_TS_Packages.ino | 14 ++++---- src/protocols/LoRaWAN/LoRaWAN.cpp | 33 ++++++++++++------- src/protocols/LoRaWAN/LoRaWAN.h | 17 +++++----- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino index 53b21b2997..f39d08babd 100644 --- a/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino +++ b/examples/LoRaWAN/LoRaWAN_Reference/LoRaWAN_Reference.ino @@ -178,13 +178,14 @@ void loop() { Serial.println(gwCnt); } - uint32_t networkTime = 0; - uint8_t fracSecond = 0; - if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) { + uint32_t timestamp = 0; + uint16_t milliseconds = 0; + if(node.getMacDeviceTimeAns(×tamp, &milliseconds, true) == RADIOLIB_ERR_NONE) { Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); - Serial.println(networkTime); - Serial.print(F("[LoRaWAN] DeviceTime second:\t1/")); - Serial.println(fracSecond); + Serial.println(timestamp); + Serial.print(F("[LoRaWAN] DeviceTime frac:\t")); + Serial.print(milliseconds); + Serial.println(F(" ms")); } } else { diff --git a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino index 4b8cdb2e64..df1cf5f308 100644 --- a/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino +++ b/examples/LoRaWAN/LoRaWAN_TS_Packages/LoRaWAN_TS_Packages.ino @@ -134,14 +134,14 @@ void loop() { Serial.println(gwCnt); } - uint32_t networkTime = 0; - uint8_t fracSecond = 0; - if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) { + uint32_t timestamp = 0; + uint16_t milliseconds = 0; + if(node.getMacDeviceTimeAns(×tamp, &milliseconds, true) == RADIOLIB_ERR_NONE) { Serial.print(F("[LoRaWAN] DeviceTime Unix:\t")); - Serial.println(networkTime); - Serial.print(F("[LoRaWAN] DeviceTime second:\t")); - Serial.print(fracSecond); - Serial.println(F("/256")); + Serial.println(timestamp); + Serial.print(F("[LoRaWAN] DeviceTime frac:\t")); + Serial.print(milliseconds); + Serial.println(F(" ms")); } } else if(state == 0) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 14993dcbb1..7be2439cc5 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1386,7 +1386,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u // if dutycycle is enabled and the time since last uplink + interval has not elapsed, return an error // but: don't check this for retransmissions if(!retrans && this->dutyCycleEnabled) { - if(this->rxDelayStart + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) { + if(this->tUplinkEnd + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) { return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); } } @@ -1450,7 +1450,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u state = this->phyLayer->finishTransmit(); // set the timestamp so that we can measure when to start receiving - this->rxDelayStart = mod->hal->millis(); + this->tUplinkEnd = mod->hal->millis(); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); // increase Time on Air of the uplink sequence @@ -1686,7 +1686,7 @@ int16_t LoRaWANNode::receiveDownlink() { Module* mod = this->phyLayer->getMod(); // if applicable, open Class C between uplink and Rx1 - RadioLibTime_t timeoutClassC = this->rxDelayStart + this->rxDelays[RADIOLIB_LORAWAN_RX1] - \ + RadioLibTime_t timeoutClassC = this->tUplinkEnd + this->rxDelays[RADIOLIB_LORAWAN_RX1] - \ mod->hal->millis() - 5*this->scanGuard; int16_t state = this->receiveClassC(timeoutClassC); RADIOLIB_ASSERT(state); @@ -1696,7 +1696,7 @@ int16_t LoRaWANNode::receiveDownlink() { &this->channels[RADIOLIB_LORAWAN_RX1], RADIOLIB_LORAWAN_RX1, this->rxDelays[RADIOLIB_LORAWAN_RX1], - this->rxDelayStart); + this->tUplinkEnd); RADIOLIB_ASSERT(state); // for LoRaWAN v1.1 Class C, there is no Rx2 window: it keeps RxC open uninterrupted @@ -1706,7 +1706,7 @@ int16_t LoRaWANNode::receiveDownlink() { } // for LoRaWAN v1.0.4 Class C, there is an RxC window between Rx1 and Rx2 - timeoutClassC = this->rxDelayStart + this->rxDelays[RADIOLIB_LORAWAN_RX2] - \ + timeoutClassC = this->tUplinkEnd + this->rxDelays[RADIOLIB_LORAWAN_RX2] - \ mod->hal->millis() - 5*this->scanGuard; state = this->receiveClassC(timeoutClassC); RADIOLIB_ASSERT(state); @@ -1716,7 +1716,7 @@ int16_t LoRaWANNode::receiveDownlink() { &this->channels[RADIOLIB_LORAWAN_RX2], RADIOLIB_LORAWAN_RX2, this->rxDelays[RADIOLIB_LORAWAN_RX2], - this->rxDelayStart); + this->tUplinkEnd); RADIOLIB_ASSERT(state); state = this->receiveClassC(); @@ -2862,19 +2862,28 @@ int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) { +int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* timestamp, uint16_t* fraction, bool returnUnix) { uint8_t payload[5] = { 0 }; int16_t state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, this->fOptsDown, this->fOptsDownLen, payload, RADIOLIB_LORAWAN_DOWNLINK); RADIOLIB_ASSERT(state); - if(gpsEpoch) { - *gpsEpoch = LoRaWANNode::ntoh(&payload[0]); + Module* mod = this->phyLayer->getMod(); + + // calculate the millisecond fraction + RadioLibTime_t ms = (RadioLibTime_t)payload[4] * 1000UL / 256UL; + + // add offset between current time and end of uplink transmission + ms += mod->hal->millis() - this->tUplinkEnd; + + if(timestamp) { + *timestamp = LoRaWANNode::ntoh(&payload[0]); + *timestamp += ms / 1000; if(returnUnix) { uint32_t unixOffset = 315964800UL - 18UL; // 18 leap seconds since GPS epoch (Jan. 6th 1980) - *gpsEpoch += unixOffset; + *timestamp += unixOffset; } } - if(fraction) { *fraction = payload[4]; } + if(fraction) { *fraction = ms % 1000; } return(RADIOLIB_ERR_NONE); } @@ -3535,7 +3544,7 @@ RadioLibTime_t LoRaWANNode::dutyCycleInterval(RadioLibTime_t msPerHour, RadioLib RadioLibTime_t LoRaWANNode::timeUntilUplink() { Module* mod = this->phyLayer->getMod(); - RadioLibTime_t nextUplink = this->rxDelayStart + dutyCycleInterval(this->dutyCycle, this->lastToA); + RadioLibTime_t nextUplink = this->tUplinkEnd + dutyCycleInterval(this->dutyCycle, this->lastToA); if(mod->hal->millis() > nextUplink){ return(0); } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 05b0067b92..de2cc055ac 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -770,8 +770,6 @@ class LoRaWANNode { /*! \brief Returns the quality of connectivity after requesting a LinkCheck MAC command. - Returns 'true' if a network response was successfully parsed. - Returns 'false' if there was no network response / parsing failed. \param margin Link margin in dB of LinkCheckReq demodulation at gateway side. \param gwCnt Number of gateways that received the LinkCheckReq. \returns \ref status_codes @@ -780,14 +778,15 @@ class LoRaWANNode { /*! \brief Returns the network time after requesting a DeviceTime MAC command. - Returns 'true' if a network response was successfully parsed. - Returns 'false' if there was no network response / parsing failed. - \param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980) - \param fraction Fractional-second, in 1/256-second steps - \param returnUnix If true, returns Unix timestamp instead of GPS (default true) + Note: the network returns the time at the end of the uplink transmission. + The return value of this function automatically adjusts to the current time. + This time is supposed to be <100ms accurate, but may be accurate to 1 second. + \param timestamp Number of seconds since GPS epoch (Jan. 6th 1980). + \param milliseconds Milliseconds on top of the timestamp. + \param returnUnix If true, returns Unix timestamp instead of GPS (default true). \returns \ref status_codes */ - int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true); + int16_t getMacDeviceTimeAns(uint32_t* timestamp, uint16_t* milliseconds, bool returnUnix = true); /*! \brief Set uplink datarate. This should not be used when ADR is enabled. @@ -1086,7 +1085,7 @@ class LoRaWANNode { RadioLibTime_t lastToA = 0; // timestamp to measure the Rx1/2 delay (from uplink end) - RadioLibTime_t rxDelayStart = 0; + RadioLibTime_t tUplinkEnd = 0; // duration of SPI transaction for phyLayer->launchMode() RadioLibTime_t launchDuration = 0; From e0fc757dc009a0e3ad557189fa5faee1147dce19 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 27 Sep 2025 12:12:14 +0200 Subject: [PATCH 1628/1848] [LoRaWAN] Improve logging --- src/protocols/LoRaWAN/LoRaWAN.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7be2439cc5..ab26941d60 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1451,7 +1451,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u // set the timestamp so that we can measure when to start receiving this->tUplinkEnd = mod->hal->millis(); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent <-- Rx Delay start"); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent (ToA = %d ms)", toa); // increase Time on Air of the uplink sequence this->lastToA += toa; @@ -1532,14 +1532,14 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne state = this->phyLayer->launchMode(); RadioLibTime_t tOpen = mod->hal->millis(); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Opened Rx%d window (%d ms timeout)... <-- Rx Delay end ", window, (int)(timeoutUs / 1000 + 2)); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rx%d window open (%lu + %lu ms)", window, timeoutUs / 1000UL, this->scanGuard); // sleep for the duration of the padded Rx window this->sleepDelay(timeoutUs / 1000, false); // wait for the DIO interrupt to fire (RxDone or RxTimeout) // use a small additional delay in case the RxTimeout interrupt is slow to fire - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closing Rx%d window", window); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Rx%d window closing", window); while(!downlinkAction && mod->hal->millis() - tOpen <= timeoutUs / 1000 + this->scanGuard) { mod->hal->yield(); } @@ -3187,8 +3187,8 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, state = this->phyLayer->setDataRate(*dr, this->band->dataRates[chnl->dr].modem); RADIOLIB_ASSERT(state); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN(""); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency = %7.3f MHz, TX = %d dBm", chnl->freq / 10000.0, pwr); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(""); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Frequency = %7.3f MHz, TX = %d dBm", chnl->freq / 10000.0, pwr); state = this->phyLayer->setFrequency(chnl->freq / 10000.0); RADIOLIB_ASSERT(state); @@ -3215,7 +3215,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; syncWordLen = 3; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("FSK: BR = %4.1f, FD = %4.1f kHz", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[FSK] BR = %4.1f, FD = %4.1f kHz", (double)dr->fsk.bitRate, (double)dr->fsk.freqDev); } break; @@ -3231,7 +3231,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LoRa: SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[LoRa] SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", dr->lora.spreadingFactor, (double)dr->lora.bandwidth, dr->lora.codingRate, dir ? 'D' : 'U'); } break; @@ -3241,7 +3241,7 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[2] = (uint8_t)(RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD >> 8); syncWord[3] = (uint8_t)RADIOLIB_LORAWAN_LR_FHSS_SYNC_WORD; syncWordLen = 4; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LR-FHSS: BW = 0x%02x, CR = 0x%02x kHz, grid = %c", + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[LR-FHSS] BW = 0x%02x, CR = 0x%02x kHz, grid = %c", dr->lrFhss.bw, dr->lrFhss.cr, dr->lrFhss.narrowGrid ? 'N' : 'W'); } break; From 335911f1df0d6a74dc927c318b431971a8500527 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 7 Oct 2025 19:38:00 +0200 Subject: [PATCH 1629/1848] [LoRaWAN] Fix for downlinks after confirmed uplinks --- src/protocols/LoRaWAN/LoRaWAN.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ab26941d60..36fa3f6b44 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -171,20 +171,24 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // handle Rx windows - returns window > 0 if a downlink is received state = this->receiveDownlink(); - // RETRANSMIT_TIMEOUT is 2s +/- 1s (RP v1.0.4) - // must be present after any confirmed frame, so we force this here - if(isConfirmed) { - int min = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS; - int max = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS; - this->sleepDelay(min + rand() % (max - min)); - } - // if an error occured or a downlink was received, stop retransmission if(state != RADIOLIB_ERR_NONE) { break; } // if no downlink was received, go on + // When an end-device has requested an ACK from the Network but has not yet received it, + // it SHALL wait RETRANSMIT_TIMEOUT seconds after RECEIVE_DELAY2 seconds have elapsed + // after the end of the previous uplink transmission before sending a new uplink (repetition or new frame). + // The RETRANSMIT_TIMEOUT delay is not required between unconfirmed uplinks, + // or after the ACK has been successfully demodulated by the end-device. + if(isConfirmed) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Retransmit timeout"); + int min = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MIN_MS; + int max = RADIOLIB_LORAWAN_RETRANSMIT_TIMEOUT_MAX_MS; + this->sleepDelay(min + rand() % (max - min)); + } + } // end of transmission & reception // note: if an error occurred, it may still be the case that a transmission occurred From b0e049bfd60430cd287508f727f38f6e3e85503d Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 7 Oct 2025 19:54:12 +0200 Subject: [PATCH 1630/1848] [LoRaWAN] Logic optimization --- src/protocols/LoRaWAN/LoRaWAN.cpp | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 36fa3f6b44..ff99b63283 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1243,15 +1243,7 @@ void LoRaWANNode::adrBackoff() { // the next required datarate; if datarate can be decreased, try it if(currentDr > 0) { - // check if dwelltime limitation allows a lower datarate - if(this->dwellTimeUp) { - const ModemType_t modem = this->band->dataRates[currentDr - 1].modem; - const DataRate_t* dr = &this->band->dataRates[currentDr - 1].dr; - const PacketConfig_t* pc = &this->band->dataRates[currentDr - 1].pc; - if(this->phyLayer->calculateTimeOnAir(modem, *dr, *pc, 13) / 1000 > this->dwellTimeUp) { - return; - } - } + // dwelltime check is already done a few lines ago // try to decrease datarate (given channelplan and radio) if(this->setDatarate(currentDr - 1) == RADIOLIB_ERR_NONE) { @@ -1301,12 +1293,14 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, // check if we have some MAC commands to append out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= this->fOptsUpLen; - // if the saved confirm-fCnt is set, set the ACK bit + // if the ConfirmFCnt is set, there is a downlink to acknowledge, so set the ACK bit if(this->confFCntDown != RADIOLIB_LORAWAN_FCNT_NONE) { out[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] |= RADIOLIB_LORAWAN_FCTRL_ACK; } + // set FCnt and FPort fields LoRaWANNode::hton(&out[RADIOLIB_LORAWAN_FHDR_FCNT_POS], (uint16_t)this->fCntUp); + out[RADIOLIB_LORAWAN_FHDR_FPORT_POS(this->fOptsUpLen)] = fPort; if(this->fOptsUpLen > 0) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink MAC payload:"); @@ -1316,15 +1310,11 @@ void LoRaWANNode::composeUplink(const uint8_t* in, uint8_t lenIn, uint8_t* out, // in LoRaWAN v1.1, the FOpts are encrypted using the NwkSEncKey processAES(this->fOptsUp, this->fOptsUpLen, this->nwkSEncKey, &out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->devAddr, this->fCntUp, RADIOLIB_LORAWAN_UPLINK, 0x01, true); } else { - // in LoRaWAN v1.0.x, the FOpts are unencrypted + // in LoRaWAN v1.0, the FOpts are unencrypted memcpy(&out[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fOptsUp, this->fOptsUpLen); } - } - // set the fPort - out[RADIOLIB_LORAWAN_FHDR_FPORT_POS(this->fOptsUpLen)] = fPort; - // select encryption key based on the target fPort uint8_t* encKey = this->appSKey; if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { @@ -1359,7 +1349,7 @@ void LoRaWANNode::micUplink(uint8_t* inOut, size_t lenInOut) { block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->channels[RADIOLIB_LORAWAN_UPLINK].idx; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %lu) decoded:", (unsigned long)this->fCntUp); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink (FCntUp = %lu) encoded:", (unsigned long)this->fCntUp); RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(inOut, lenInOut); // calculate authentication codes From 80d09eb52d8e427e68e78cdcdcb87d9660e05646 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 7 Oct 2025 20:05:45 +0200 Subject: [PATCH 1631/1848] [LoRaWAN] Process downlinks in-place --- src/protocols/LoRaWAN/LoRaWAN.cpp | 104 +++++++++++++++--------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ff99b63283..7417268408 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1772,8 +1772,10 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } - // calculate length of (piggy-backed) FOpts + // calculate length of piggy-backed FOpts + bool isPiggyBacking = false; uint8_t fOptsLen = downlinkMsg[RADIOLIB_LORAWAN_FHDR_FCTRL_POS] & RADIOLIB_LORAWAN_FHDR_FOPTS_LEN_MASK; + isPiggyBacking = fOptsLen > 0; // MHDR(1) - DevAddr(4) - FCtrl(1) - FCnt(2) - FOpts - Payload - MIC(4) // potentially also an FPort, will find out next @@ -1826,9 +1828,9 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } } - // handle FOpts in uplink with FPort = 0 (or absent which means 0) - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND) { - if(fOptsLen > 0 && payLen > 0) { + // get FOpts length if FPort = 0 and there is downlink payload + if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && payLen > 0) { + if(fOptsLen > 0) { // MAC commands SHALL NOT be present in the payload field and the frame options field simultaneously. // Should this occur, the end-device SHALL silently discard the frame. #if !RADIOLIB_STATIC_ONLY @@ -1836,15 +1838,15 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L #endif return(RADIOLIB_ERR_DOWNLINK_MALFORMED); } - // if FOpts are in the payload, use this instead - if(payLen > 0) { - fOptsLen = payLen; - } + // there is no application payload as all of it is FOpts + fOptsLen = payLen; + payLen = 0; } // LoRaWAN v1.0.4 only: A Class B/C downlink SHALL NOT transport any MAC command. // (...) it SHALL silently discard the entire frame. // However, we also enforce this for LoRaWAN v1.1 (TTS does not allow this anyway). + // Note: we check Device Class == A because Relay also uses a third Rx window if(fOptsLen > 0 && this->lwClass != RADIOLIB_LORAWAN_CLASS_A && window == RADIOLIB_LORAWAN_RX_BC) { #if !RADIOLIB_STATIC_ONLY delete[] downlinkMsg; @@ -1921,12 +1923,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L return(RADIOLIB_ERR_MIC_MISMATCH); } - // all checks passed, so dump its contents and start processing - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) encoded:", - (this->multicast && window == RADIOLIB_LORAWAN_RX_BC) ? "M" : - (isAppDownlink ? "A" : "N"), - (unsigned long)devFCnt32); - RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + // all checks passed, so start processing // save new FCnt to respective frame counter if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { @@ -1959,33 +1956,51 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L this->fOptsUpLen = 0; } - #if !RADIOLIB_STATIC_ONLY - uint8_t* fOpts = new uint8_t[fOptsLen]; - #else - uint8_t fOpts[RADIOLIB_STATIC_ARRAY_SIZE]; - #endif - - // decrypt any FOpts on FPort = 0, in which case FOptsLen is the length of the payload - if(fPort == RADIOLIB_LORAWAN_FPORT_MAC_COMMAND && payLen > 0) { - payLen = 0; - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)], fOptsLen, this->nwkSEncKey, fOpts, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); - - // decrypt any piggy-backed FOpts - } else if(fOptsLen > 0) { + uint8_t* fOptsPtr; + // decrypt any piggy-backed FOpts (in-place) + if(fOptsLen > 0 && isPiggyBacking) { + fOptsPtr = &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS]; // the decryption depends on the LoRaWAN version + // in LoRaWAN v1.0, the piggy-backed FOpts are unencrypted + // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey if(this->rev == 1) { - // in LoRaWAN v1.1, the piggy-backed FOpts are encrypted using the NwkSEncKey uint8_t ctrId = 0x01 + isAppDownlink; // see LoRaWAN v1.1 errata - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen, this->nwkSEncKey, fOpts, this->devAddr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); - } else { - // in LoRaWAN v1.0.x, the piggy-backed FOpts are unencrypted - memcpy(fOpts, &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], (size_t)fOptsLen); + processAES(fOptsPtr, (size_t)fOptsLen, this->nwkSEncKey, fOptsPtr, this->devAddr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, ctrId, true); } + + // decrypt any FOpts in the payload (in-place) + } else if(fOptsLen > 0) { + fOptsPtr = &downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(0)]; + processAES(fOptsPtr, (size_t)fOptsLen, this->nwkSEncKey, fOptsPtr, this->devAddr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); } + // figure out which key to use to decrypt the application payload + uint8_t* encKey = this->appSKey; + if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { + encKey = this->mcAppSKey; + } + for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { + if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { + encKey = this->packages[id].isAppPack ? this->appSKey : this->nwkSEncKey; + break; + } + } + + // decrypt the frame payload (in-place to allow a fully decrypted hex-dump next) + uint8_t* payloadPtr = &downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)]; + processAES(payloadPtr, payLen, encKey, payloadPtr, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); + data = payloadPtr; + + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) decoded:", + (this->multicast && window == RADIOLIB_LORAWAN_RX_BC) ? "M" : + (isAppDownlink ? "A" : "N"), + (unsigned long)devFCnt32); + RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(downlinkMsg, RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen); + + // process any FOpts if(fOptsLen > 0) { - uint8_t* mPtr = fOpts; + uint8_t* mPtr = fOptsPtr; uint8_t procLen = 0; uint8_t fOptsRe[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE] = { 0 }; uint8_t fOptsReLen = 0; @@ -2070,9 +2085,11 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // remove all MAC commands except those whose payload can be requested by the user // (which are LinkCheck and DeviceTime) + LoRaWANNode::clearMacCommands(fOptsPtr, &fOptsLen, RADIOLIB_LORAWAN_DOWNLINK); + + // copy over the remaining FOpts from the downlink to an internal buffer this->fOptsDownLen = fOptsLen; - LoRaWANNode::clearMacCommands(fOpts, &this->fOptsDownLen, RADIOLIB_LORAWAN_DOWNLINK); - memcpy(this->fOptsDown, fOpts, this->fOptsDownLen); + memcpy(this->fOptsDown, fOptsPtr, this->fOptsDownLen); // if fOptsLen for the next uplink is larger than can be piggybacked onto an uplink, send separate uplink if(fOptsReLen > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) { @@ -2090,7 +2107,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L uint8_t fLenRe = 0; // move back to the start of the uplink buffer - mPtr = fOpts; + mPtr = fOptsPtr; // and add as many MAC commands as space is available while(fOptsReLen + fLenRe <= maxReLen) { fOptsReLen += fLenRe; @@ -2119,21 +2136,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } } - // figure out which key to use to decrypt the payload - uint8_t* encKey = this->appSKey; - if(this->multicast && window == RADIOLIB_LORAWAN_RX_BC) { - encKey = this->mcAppSKey; - } - for(int id = 0; id < RADIOLIB_LORAWAN_NUM_SUPPORTED_PACKAGES; id++) { - if(this->packages[id].enabled && fPort == this->packages[id].packFPort) { - encKey = this->packages[id].isAppPack ? this->appSKey : this->nwkSEncKey; - break; - } - } - - // decrypt the frame payload // by default, the data and length are user-accessible - processAES(&downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)], payLen, encKey, data, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); *len = payLen; // however, if this frame belongs to an application package, @@ -2162,7 +2165,6 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L } #if !RADIOLIB_STATIC_ONLY - delete[] fOpts; delete[] downlinkMsg; #endif From 40c37a8d4f39b20a83ad98e1b267f3035404fb3b Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 7 Oct 2025 20:28:18 +0200 Subject: [PATCH 1632/1848] [LoRaWAN] Fix MAC-only payload truncation --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 7417268408..517c808e2f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2107,7 +2107,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L uint8_t fLenRe = 0; // move back to the start of the uplink buffer - mPtr = fOptsPtr; + mPtr = fOptsRe; // and add as many MAC commands as space is available while(fOptsReLen + fLenRe <= maxReLen) { fOptsReLen += fLenRe; From 6e9d10c8cc71cf28e57069512c9e68e1becb2cb7 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 7 Oct 2025 20:28:52 +0200 Subject: [PATCH 1633/1848] [LoRaWAN] Cleanup Timeout IRQ, shortcut zero-length AES --- src/protocols/LoRaWAN/LoRaWAN.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 517c808e2f..ab479accd7 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1547,6 +1547,7 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne // if the IRQ bit for RxTimeout is set, put chip in standby and return if(timedOut) { this->phyLayer->clearPacketReceivedAction(); + this->phyLayer->clearIrq(1UL << RADIOLIB_IRQ_TIMEOUT); this->phyLayer->standby(); return(0); // no downlink } @@ -1639,6 +1640,7 @@ int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { // if the IRQ bit for RxTimeout is set, put chip in standby and return if(timedOut) { this->phyLayer->clearPacketReceivedAction(); + this->phyLayer->clearIrq(1UL << RADIOLIB_IRQ_TIMEOUT); this->phyLayer->standby(); return(0); // no downlink } @@ -3639,6 +3641,10 @@ void LoRaWANNode::removePackage(uint8_t packageId) { } void LoRaWANNode::processAES(const uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t addr, uint32_t fCnt, uint8_t dir, uint8_t ctrId, bool counter) { + if(len == 0) { + return; + } + // figure out how many encryption blocks are there size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; if(len % RADIOLIB_AES128_BLOCK_SIZE) { From a7f321ff763e538729e473f75ab6e596b6cd1d13 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 7 Oct 2025 22:38:07 +0200 Subject: [PATCH 1634/1848] Fix CI warning --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index ab479accd7..66f3742374 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1958,7 +1958,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L this->fOptsUpLen = 0; } - uint8_t* fOptsPtr; + uint8_t* fOptsPtr = NULL; // decrypt any piggy-backed FOpts (in-place) if(fOptsLen > 0 && isPiggyBacking) { fOptsPtr = &downlinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS]; From e60d2624f20fa6122c08741cf026b38502e8d34a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Oct 2025 21:12:27 +0200 Subject: [PATCH 1635/1848] [LR11x0] Move functions common with LR2021 --- src/modules/LR11x0/LR11x0.h | 5 ++- src/modules/LR11x0/LR11x0_commands.cpp | 43 ++------------------------ src/modules/LR11x0/LR11x0_crypto.cpp | 4 ++- src/modules/LR11x0/LR_common.cpp | 39 +++++++++++++++++++++++ src/modules/LR11x0/LR_common.h | 8 +++++ 5 files changed, 55 insertions(+), 44 deletions(-) create mode 100644 src/modules/LR11x0/LR_common.cpp create mode 100644 src/modules/LR11x0/LR_common.h diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index b3b6599d21..b8e34ac9b6 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -301,8 +301,8 @@ // RADIOLIB_LR11X0_CMD_SET_SLEEP #define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled #define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled -#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 0) // 1 1 automated wakeup: disabled -#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 0) // 1 1 enabled +#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 1) // 1 1 automated wakeup: disabled +#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 1) // 1 1 enabled // RADIOLIB_LR11X0_CMD_SET_STANDBY #define RADIOLIB_LR11X0_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator @@ -1881,7 +1881,6 @@ class LR11x0: public PhysicalLayer { // common methods to avoid some copy-paste int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, const uint8_t* payload, size_t len); - int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, const uint8_t* dataIn, size_t len, uint8_t* dataOut); }; diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index e430bbe0bf..95bf66e97e 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -2,6 +2,7 @@ #include "../../utils/CRC.h" #include "../../utils/Cryptography.h" +#include "LR_common.h" #include #include @@ -55,7 +56,7 @@ int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); + return(LR_writeCommon(this->mod, RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); } int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { @@ -829,7 +830,7 @@ int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, s if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); + return(LR_writeCommon(this->mod, RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); } int16_t LR11x0::bootReboot(bool stay) { @@ -852,42 +853,4 @@ int16_t LR11x0::bootGetJoinEui(uint8_t* eui) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN)); } -int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* dataBuff = new uint8_t[buffLen]; - #endif - - // set the address or offset - dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF); - dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF); - dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF); - dataBuff[3] = (uint8_t)(addrOffset & 0xFF); - - // convert endians - for(size_t i = 0; i < len; i++) { - uint32_t bin = 0; - if(nonvolatile) { - uint32_t* ptr = const_cast(data) + i; - bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr); - } else { - bin = data[i]; - } - dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF); - dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF); - dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF); - dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); - } - - int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - #endif diff --git a/src/modules/LR11x0/LR11x0_crypto.cpp b/src/modules/LR11x0/LR11x0_crypto.cpp index 6d58662273..9730db5b09 100644 --- a/src/modules/LR11x0/LR11x0_crypto.cpp +++ b/src/modules/LR11x0/LR11x0_crypto.cpp @@ -1,6 +1,8 @@ #include "LR11x0.h" #include "../../utils/Cryptography.h" +#include "LR_common.h" + #include #if !RADIOLIB_EXCLUDE_LR11X0 @@ -176,7 +178,7 @@ int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); + return(LR_writeCommon(this->mod, RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); } int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp new file mode 100644 index 0000000000..ed211ff28a --- /dev/null +++ b/src/modules/LR11x0/LR_common.cpp @@ -0,0 +1,39 @@ +#include "LR_common.h" + +int16_t LR_writeCommon(Module* mod, uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set the address or offset + dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF); + dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF); + dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF); + dataBuff[3] = (uint8_t)(addrOffset & 0xFF); + + // convert endians + for(size_t i = 0; i < len; i++) { + uint32_t bin = 0; + if(nonvolatile) { + uint32_t* ptr = const_cast(data) + i; + bin = RADIOLIB_NONVOLATILE_READ_DWORD(ptr); + } else { + bin = data[i]; + } + dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF); + dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF); + dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF); + dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); + } + + int16_t state = mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h new file mode 100644 index 0000000000..74c75b9a86 --- /dev/null +++ b/src/modules/LR11x0/LR_common.h @@ -0,0 +1,8 @@ +#if !defined(RADIOLIB_LR_COMMON_H) +#define RADIOLIB_LR_COMMON_H + +#include "../../Module.h" + +int16_t LR_writeCommon(Module* mod, uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); + +#endif From f203c77c161c02fa4e02e9c8c4a402b1e0c6660c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Oct 2025 21:12:56 +0200 Subject: [PATCH 1636/1848] [LR2021] Add first few SPI commands --- src/modules/LR2021/LR2021.cpp | 21 +++++++++ src/modules/LR2021/LR2021.h | 20 ++++++++ src/modules/LR2021/LR2021_commands.cpp | 64 ++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index e8b1c530e0..b72443a2a4 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -21,6 +21,27 @@ LR2021::LR2021(Module* mod) : PhysicalLayer() { this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT; } +int16_t LR2021::sleep() { + return(this->sleep(RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED, 0)); +} + +int16_t LR2021::sleep(uint8_t cfg, uint32_t time) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + uint8_t buff[] = { cfg, + (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), + (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), + }; + + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_SET_SLEEP, true, buff, sizeof(buff)); + + // wait for the module to safely enter sleep mode + this->mod->hal->delay(1); + + return(state); +} + Module* LR2021::getMod() { return(this->mod); } diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 8cd2dede8a..20e9d7763a 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -187,6 +187,16 @@ #define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response #define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout +// RADIOLIB_LR2021_CMD_WRITE_REG_MEM +#define RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes + +// RADIOLIB_LR2021_CMD_SET_SLEEP +#define RADIOLIB_LR2021_SLEEP_32K_CLK_DISABLED (0x00UL << 0) // 0 0 32 kHz clock: disabled +#define RADIOLIB_LR2021_SLEEP_32K_CLK_ENABLED (0x01UL << 0) // 0 0 enabled +#define RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED (0x00UL << 1) // 1 1 configuration retention in sleep mode: disabled +#define RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED (0x01UL << 1) // 1 1 enabled + + /*! \class LR2021 \brief @@ -206,6 +216,9 @@ class LR2021: public PhysicalLayer { */ explicit LR2021(Module* mod); + int16_t sleep(); + int16_t sleep(uint8_t cfg, uint32_t time); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -223,6 +236,13 @@ class LR2021: public PhysicalLayer { static int16_t SPIparseStatus(uint8_t in); static int16_t SPIcheckStatus(Module* mod); + + int16_t readRadioRxFifo(uint8_t* data, size_t len); + int16_t writeRadioTxFifo(uint8_t* data, size_t len); + int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); + int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data); + int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); + }; #endif diff --git a/src/modules/LR2021/LR2021_commands.cpp b/src/modules/LR2021/LR2021_commands.cpp index e11aa49438..599d2da65f 100644 --- a/src/modules/LR2021/LR2021_commands.cpp +++ b/src/modules/LR2021/LR2021_commands.cpp @@ -1,10 +1,74 @@ #include "LR2021.h" +#include "../LR11x0/LR_common.h" + #include #include #if !RADIOLIB_EXCLUDE_LR2021 +int16_t LR2021::readRadioRxFifo(uint8_t* data, size_t len) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_READ_RX_FIFO, false, data, len, NULL, 0)); +} + +int16_t LR2021::writeRadioTxFifo(uint8_t* data, size_t len) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_TX_FIFO, true, data, len, NULL, 0)); +} + +// TODO reuse LR11x0 method +int16_t LR2021::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(LR_writeCommon(this->mod, RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32, addr, data, len, false)); +} + +// TODO reuse LR11x0 method +int16_t LR2021::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { + uint8_t buff[12] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32, true, buff, sizeof(buff))); +} + +// TODO reuse LR11x0 method +int16_t LR2021::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len >= (RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_READ_REG_MEM_32, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + // convert endians + if(data && (state == RADIOLIB_ERR_NONE)) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + + return(state); +} #endif From d696fed842bc77c6699ac83d9611a7d6e1c838d6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 13 Oct 2025 20:36:34 +0100 Subject: [PATCH 1637/1848] [LRxxxx] Create base class for common LR11xx and LR20xx commands --- src/modules/LR11x0/LR11x0.cpp | 27 +-------- src/modules/LR11x0/LR11x0.h | 5 +- src/modules/LR11x0/LR11x0_commands.cpp | 4 +- src/modules/LR11x0/LR11x0_crypto.cpp | 2 +- src/modules/LR11x0/LR_common.cpp | 84 +++++++++++++++++++++++++- src/modules/LR11x0/LR_common.h | 19 +++++- src/modules/LR2021/LR2021.cpp | 24 +------- src/modules/LR2021/LR2021.h | 7 +-- src/modules/LR2021/LR2021_commands.cpp | 56 ----------------- 9 files changed, 111 insertions(+), 117 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 5f2674e894..50b044903c 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -5,7 +5,7 @@ #if !RADIOLIB_EXCLUDE_LR11X0 -LR11x0::LR11x0(Module* mod) : PhysicalLayer() { +LR11x0::LR11x0(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE; this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; this->mod = mod; @@ -1227,7 +1227,8 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { } uint8_t len = 0; - (void)getRxBufferStatus(&len, offset); + int state = getRxBufferStatus(&len, offset); + RADIOLIB_DEBUG_BASIC_PRINT("getRxBufferStatus state = %d\n", state); return((size_t)len); } @@ -1785,28 +1786,6 @@ int16_t LR11x0::SPIcheckStatus(Module* mod) { return(LR11x0::SPIparseStatus(buff[0])); } -int16_t LR11x0::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) { - int16_t state = RADIOLIB_ERR_UNKNOWN; - if(!write) { - // the SPI interface of LR11x0 requires two separate transactions for reading - // send the 16-bit command - state = this->mod->SPIwriteStream(cmd, out, outLen, true, false); - RADIOLIB_ASSERT(state); - - // read the result without command - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0; - state = this->mod->SPIreadStream(RADIOLIB_LR11X0_CMD_NOP, data, len, true, false); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - - } else { - // write is just a single transaction - state = this->mod->SPIwriteStream(cmd, data, len, true, true); - - } - - return(state); -} - bool LR11x0::findChip(uint8_t ver) { uint8_t i = 0; bool flagFound = false; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index b8e34ac9b6..5bc1ab6e00 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -8,6 +8,7 @@ #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" +#include "../LR11x0/LR_common.h" // LR11X0 physical layer properties #define RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE 1.0 @@ -886,7 +887,7 @@ struct LR11x0GnssAlmanacStatus_t { \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. This class should not be instantiated directly from user code, only from its derived classes. */ -class LR11x0: public PhysicalLayer { +class LR11x0: public PhysicalLayer, public LRxxxx { public: // introduce PhysicalLayer overloads using PhysicalLayer::transmit; @@ -1834,8 +1835,6 @@ class LR11x0: public PhysicalLayer { int16_t bootGetChipEui(uint8_t* eui); int16_t bootGetJoinEui(uint8_t* eui); - int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); - #if !RADIOLIB_GODMODE protected: #endif diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index 95bf66e97e..f55966b6d5 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -56,7 +56,7 @@ int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(LR_writeCommon(this->mod, RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); + return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false)); } int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { @@ -830,7 +830,7 @@ int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, s if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(LR_writeCommon(this->mod, RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); + return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); } int16_t LR11x0::bootReboot(bool stay) { diff --git a/src/modules/LR11x0/LR11x0_crypto.cpp b/src/modules/LR11x0/LR11x0_crypto.cpp index 9730db5b09..625db10bad 100644 --- a/src/modules/LR11x0/LR11x0_crypto.cpp +++ b/src/modules/LR11x0/LR11x0_crypto.cpp @@ -178,7 +178,7 @@ int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, const uint32_ if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } - return(LR_writeCommon(this->mod, RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); + return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile)); } int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) { diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index ed211ff28a..a928d667fd 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -1,6 +1,64 @@ #include "LR_common.h" -int16_t LR_writeCommon(Module* mod, uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { +LRxxxx::LRxxxx(Module* mod) { + this->mod = mod; +} + +int16_t LRxxxx::writeRegMem32(uint16_t cmd, uint32_t addr, const uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(cmd, addr, data, len, false)); +} + +int16_t LRxxxx::writeRegMemMask32(uint16_t cmd, uint32_t addr, uint32_t mask, uint32_t data) { + uint8_t buff[12] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), + }; + return(this->SPIcommand(cmd, true, buff, sizeof(buff))); +} + +int16_t LRxxxx::readRegMem32(uint16_t cmd, uint32_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len >= (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(cmd, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + + // convert endians + if(data && (state == RADIOLIB_ERR_NONE)) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + + return(state); +} + +int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { // build buffers - later we need to ensure endians are correct, // so there is probably no way to do this without copying buffers and iterating size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); @@ -31,9 +89,31 @@ int16_t LR_writeCommon(Module* mod, uint16_t cmd, uint32_t addrOffset, const uin dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); } - int16_t state = mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); + int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); #if !RADIOLIB_STATIC_ONLY delete[] dataBuff; #endif return(state); } + +int16_t LRxxxx::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + if(!write) { + // the SPI interface of LR11x0 requires two separate transactions for reading + // send the 16-bit command + state = this->mod->SPIwriteStream(cmd, out, outLen, true, false); + RADIOLIB_ASSERT(state); + + // read the result without command + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0; + state = this->mod->SPIreadStream(RADIOLIB_LRXXXX_CMD_NOP, data, len, true, false); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + + } else { + // write is just a single transaction + state = this->mod->SPIwriteStream(cmd, data, len, true, true); + + } + + return(state); +} diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 74c75b9a86..e45b7ef68a 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -3,6 +3,23 @@ #include "../../Module.h" -int16_t LR_writeCommon(Module* mod, uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); +#define RADIOLIB_LRXXXX_CMD_NOP (0x0000) +#define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (256) + +class LRxxxx { + public: + LRxxxx(Module* mod); + + protected: + int16_t writeRegMem32(uint16_t cmd, uint32_t addr, const uint32_t* data, size_t len); + int16_t writeRegMemMask32(uint16_t cmd, uint32_t addr, uint32_t mask, uint32_t data); + int16_t readRegMem32(uint16_t cmd, uint32_t addr, uint32_t* data, size_t len); + + int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); + int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); + + private: + Module* mod; +}; #endif diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index b72443a2a4..d8e57f9b5e 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -5,7 +5,7 @@ #if !RADIOLIB_EXCLUDE_LR2021 -LR2021::LR2021(Module* mod) : PhysicalLayer() { +LR2021::LR2021(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE; this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH; this->mod = mod; @@ -69,26 +69,4 @@ int16_t LR2021::SPIcheckStatus(Module* mod) { return(LR2021::SPIparseStatus(buff[0])); } -int16_t LR2021::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) { - int16_t state = RADIOLIB_ERR_UNKNOWN; - if(!write) { - // the SPI interface of LR2021 requires two separate transactions for reading - // send the 16-bit command - state = this->mod->SPIwriteStream(cmd, out, outLen, true, false); - RADIOLIB_ASSERT(state); - - // read the result without command - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0; - state = this->mod->SPIreadStream(RADIOLIB_LR2021_CMD_NOP, data, len, true, false); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - - } else { - // write is just a single transaction - state = this->mod->SPIwriteStream(cmd, data, len, true, true); - - } - - return(state); -} - #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 20e9d7763a..f85da01a87 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -8,6 +8,7 @@ #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" +#include "../LR11x0/LR_common.h" // LR2021 physical layer properties #define RADIOLIB_LR2021_FREQUENCY_STEP_SIZE 1.0 @@ -187,9 +188,6 @@ #define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response #define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout -// RADIOLIB_LR2021_CMD_WRITE_REG_MEM -#define RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes - // RADIOLIB_LR2021_CMD_SET_SLEEP #define RADIOLIB_LR2021_SLEEP_32K_CLK_DISABLED (0x00UL << 0) // 0 0 32 kHz clock: disabled #define RADIOLIB_LR2021_SLEEP_32K_CLK_ENABLED (0x01UL << 0) // 0 0 enabled @@ -201,7 +199,7 @@ \class LR2021 \brief */ -class LR2021: public PhysicalLayer { +class LR2021: public PhysicalLayer, public LRxxxx { public: // introduce PhysicalLayer overloads using PhysicalLayer::transmit; @@ -227,7 +225,6 @@ class LR2021: public PhysicalLayer { #if !RADIOLIB_GODMODE protected: #endif - int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); #if !RADIOLIB_GODMODE private: diff --git a/src/modules/LR2021/LR2021_commands.cpp b/src/modules/LR2021/LR2021_commands.cpp index 599d2da65f..aba53c42d5 100644 --- a/src/modules/LR2021/LR2021_commands.cpp +++ b/src/modules/LR2021/LR2021_commands.cpp @@ -15,60 +15,4 @@ int16_t LR2021::writeRadioTxFifo(uint8_t* data, size_t len) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_TX_FIFO, true, data, len, NULL, 0)); } -// TODO reuse LR11x0 method -int16_t LR2021::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { - // check maximum size - if(len > (RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - return(LR_writeCommon(this->mod, RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32, addr, data, len, false)); -} - -// TODO reuse LR11x0 method -int16_t LR2021::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { - uint8_t buff[12] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32, true, buff, sizeof(buff))); -} - -// TODO reuse LR11x0 method -int16_t LR2021::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { - // check maximum size - if(len >= (RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // the request contains the address and length - uint8_t reqBuff[5] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)len, - }; - - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - #if RADIOLIB_STATIC_ONLY - uint8_t rplBuff[RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; - #endif - - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_READ_REG_MEM_32, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); - - // convert endians - if(data && (state == RADIOLIB_ERR_NONE)) { - for(size_t i = 0; i < len; i++) { - data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; - } - } - - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - - return(state); -} #endif From 9b330ffa992285c84347360e46afb19cd5b526d3 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 16 Oct 2025 13:01:49 +0200 Subject: [PATCH 1638/1848] [LoRaWAN] Fix for payload processing (#1626 comment) --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 66f3742374..83a3d9b659 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1991,7 +1991,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L // decrypt the frame payload (in-place to allow a fully decrypted hex-dump next) uint8_t* payloadPtr = &downlinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(fOptsLen)]; processAES(payloadPtr, payLen, encKey, payloadPtr, addr, devFCnt32, RADIOLIB_LORAWAN_DOWNLINK, 0x00, true); - data = payloadPtr; + memcpy(data, payloadPtr, payLen); RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Downlink (%sFCntDown = %lu) decoded:", (this->multicast && window == RADIOLIB_LORAWAN_RX_BC) ? "M" : From 15aa3927731e6dda6f0edb53f066e2cc5a43229c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 16:12:50 +0100 Subject: [PATCH 1639/1848] [LR11x0] Only keep minimum commands in LR common class --- src/modules/LR11x0/LR11x0.cpp | 23 -------- src/modules/LR11x0/LR11x0.h | 4 -- src/modules/LR11x0/LR11x0_commands.cpp | 16 ------ src/modules/LR11x0/LR_common.cpp | 77 +++++++++++--------------- src/modules/LR11x0/LR_common.h | 23 ++++++-- 5 files changed, 48 insertions(+), 95 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 50b044903c..f8e93d95a8 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1763,29 +1763,6 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { return(config(modem)); } -int16_t LR11x0::SPIparseStatus(uint8_t in) { - if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } else if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_FAIL) { - return(RADIOLIB_ERR_SPI_CMD_FAILED); - } else if((in == 0x00) || (in == 0xFF)) { - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } - return(RADIOLIB_ERR_NONE); -} - -int16_t LR11x0::SPIcheckStatus(Module* mod) { - // the status check command doesn't return status in the same place as other read commands, - // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used - // it also seems to ignore the actual command, and just sending in bunch of NOPs will work - uint8_t buff[6] = { 0 }; - mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; - int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - RADIOLIB_ASSERT(state); - return(LR11x0::SPIparseStatus(buff[0])); -} - bool LR11x0::findChip(uint8_t ver) { uint8_t i = 0; bool flagFound = false; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 5bc1ab6e00..779f664055 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -183,10 +183,6 @@ // LR11X0 SPI command variables // RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION -#define RADIOLIB_LR11X0_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed -#define RADIOLIB_LR11X0_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error -#define RADIOLIB_LR11X0_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed -#define RADIOLIB_LR11X0_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted #define RADIOLIB_LR11X0_STAT_1_IRQ_INACTIVE (0x00UL << 0) // 0 0 interrupt status: inactive #define RADIOLIB_LR11X0_STAT_1_IRQ_ACTIVE (0x01UL << 0) // 0 0 at least 1 interrupt active #define RADIOLIB_LR11X0_STAT_2_CMD_RST_CLEARED (0x00UL << 4) // 7 4 reset status: cleared diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index f55966b6d5..fea40bbd39 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -143,22 +143,6 @@ int16_t LR11x0::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK, true, buff, sizeof(buff))); } -int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { - uint8_t buff[6] = { 0 }; - - // the status check command doesn't return status in the same place as other read commands - // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used - // it also seems to ignore the actual command, and just sending in bunch of NOPs will work - int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - - // pass the replies - if(stat1) { *stat1 = buff[0]; } - if(stat2) { *stat2 = buff[1]; } - if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; } - - return(state); -} - int16_t LR11x0::getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor) { uint8_t buff[4] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_VERSION, false, buff, sizeof(buff)); diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index a928d667fd..c55475e580 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -4,58 +4,43 @@ LRxxxx::LRxxxx(Module* mod) { this->mod = mod; } -int16_t LRxxxx::writeRegMem32(uint16_t cmd, uint32_t addr, const uint32_t* data, size_t len) { - // check maximum size - if(len > (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - return(this->writeCommon(cmd, addr, data, len, false)); -} +int16_t LRxxxx::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { + uint8_t buff[6] = { 0 }; -int16_t LRxxxx::writeRegMemMask32(uint16_t cmd, uint32_t addr, uint32_t mask, uint32_t data) { - uint8_t buff[12] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), - (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), - }; - return(this->SPIcommand(cmd, true, buff, sizeof(buff))); -} - -int16_t LRxxxx::readRegMem32(uint16_t cmd, uint32_t addr, uint32_t* data, size_t len) { - // check maximum size - if(len >= (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } + // the status check command doesn't return status in the same place as other read commands + // but only as the first byte (as with any other command), hence LRxxxx::SPIcommand can't be used + // it also seems to ignore the actual command, and just sending in bunch of NOPs will work + int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - // the request contains the address and length - uint8_t reqBuff[5] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)len, - }; + // pass the replies + if(stat1) { *stat1 = buff[0]; } + if(stat2) { *stat2 = buff[1]; } + if(irq) { *irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; } - // build buffers - later we need to ensure endians are correct, - // so there is probably no way to do this without copying buffers and iterating - #if RADIOLIB_STATIC_ONLY - uint8_t rplBuff[RADIOLIB_LR2021_SPI_MAX_READ_WRITE_LEN]; - #else - uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; - #endif - - int16_t state = this->SPIcommand(cmd, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + return(state); +} - // convert endians - if(data && (state == RADIOLIB_ERR_NONE)) { - for(size_t i = 0; i < len; i++) { - data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; - } +int16_t LRxxxx::SPIparseStatus(uint8_t in) { + if((in & 0b00001110) == RADIOLIB_LRXXXX_STAT_1_CMD_PERR) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } else if((in & 0b00001110) == RADIOLIB_LRXXXX_STAT_1_CMD_FAIL) { + return(RADIOLIB_ERR_SPI_CMD_FAILED); + } else if((in == 0x00) || (in == 0xFF)) { + return(RADIOLIB_ERR_CHIP_NOT_FOUND); } + return(RADIOLIB_ERR_NONE); +} - #if !RADIOLIB_STATIC_ONLY - delete[] rplBuff; - #endif - - return(state); +int16_t LRxxxx::SPIcheckStatus(Module* mod) { + // the status check command doesn't return status in the same place as other read commands, + // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used + // it also seems to ignore the actual command, and just sending in bunch of NOPs will work + uint8_t buff[6] = { 0 }; + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; + int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + RADIOLIB_ASSERT(state); + return(LRxxxx::SPIparseStatus(buff[0])); } int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) { diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index e45b7ef68a..cafddd156b 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -3,21 +3,32 @@ #include "../../Module.h" -#define RADIOLIB_LRXXXX_CMD_NOP (0x0000) -#define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (256) +#define RADIOLIB_LRXXXX_CMD_NOP (0x0000) +#define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (256) + +// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION +#define RADIOLIB_LRXXXX_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed +#define RADIOLIB_LRXXXX_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error +#define RADIOLIB_LRXXXX_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed +#define RADIOLIB_LRXXXX_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted class LRxxxx { public: LRxxxx(Module* mod); protected: - int16_t writeRegMem32(uint16_t cmd, uint32_t addr, const uint32_t* data, size_t len); - int16_t writeRegMemMask32(uint16_t cmd, uint32_t addr, uint32_t mask, uint32_t data); - int16_t readRegMem32(uint16_t cmd, uint32_t addr, uint32_t* data, size_t len); - + // a lot of SPI commands have the same structure and arguments on both LR11xx as well as LR2021 + // the only difference is the 16-bit command code - however, having everything in this base class + // will actually increase the binary size, because of the extra method calls that are needed + // for that reason, only the methods that are 100% the same are kept here + int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); + int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); + static int16_t SPIparseStatus(uint8_t in); + static int16_t SPIcheckStatus(Module* mod); + private: Module* mod; }; From 3310547a655f0472ea7c1ae43b4dc4d44dbb50dd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 16:13:24 +0100 Subject: [PATCH 1640/1848] [LR11x0] Remove SPI cehck methods --- src/modules/LR11x0/LR11x0.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 779f664055..809c3db39f 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -1866,8 +1866,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { uint32_t rxTimeout = 0; int16_t modSetup(float tcxoVoltage, uint8_t modem); - static int16_t SPIparseStatus(uint8_t in); - static int16_t SPIcheckStatus(Module* mod); bool findChip(uint8_t ver); int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); From 369cc9f3a16f77dabe8944bc4be426d3c5bbcbad Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 16:13:46 +0100 Subject: [PATCH 1641/1848] [LR11x0] Add missing void cast --- src/modules/LR11x0/LR11x0.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index f8e93d95a8..0b536d3698 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1229,6 +1229,7 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { uint8_t len = 0; int state = getRxBufferStatus(&len, offset); RADIOLIB_DEBUG_BASIC_PRINT("getRxBufferStatus state = %d\n", state); + (void)state; return((size_t)len); } From 99e6537d0e013e837ed69bbed0f5277c4332d730 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 16:14:12 +0100 Subject: [PATCH 1642/1848] [LR2021] Add all chip control commands --- src/modules/LR2021/LR2021.cpp | 26 +-- src/modules/LR2021/LR2021.h | 221 ++++--------------- src/modules/LR2021/LR2021_commands.cpp | 289 ++++++++++++++++++++++++ src/modules/LR2021/LR2021_commands.h | 293 +++++++++++++++++++++++++ 4 files changed, 623 insertions(+), 206 deletions(-) create mode 100644 src/modules/LR2021/LR2021_commands.h diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index d8e57f9b5e..5b07e7cec1 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -19,6 +19,9 @@ LR2021::LR2021(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE; this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED; this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + this->mod->spiConfig.checkStatusCb = SPIcheckStatus; } int16_t LR2021::sleep() { @@ -46,27 +49,4 @@ Module* LR2021::getMod() { return(this->mod); } -int16_t LR2021::SPIparseStatus(uint8_t in) { - /*if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } else if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_FAIL) { - return(RADIOLIB_ERR_SPI_CMD_FAILED); - } else if((in == 0x00) || (in == 0xFF)) { - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - }*/ - return(RADIOLIB_ERR_NONE); -} - -int16_t LR2021::SPIcheckStatus(Module* mod) { - // the status check command doesn't return status in the same place as other read commands, - // but only as the first byte (as with any other command), hence LR2021::SPIcommand can't be used - // it also seems to ignore the actual command, and just sending in bunch of NOPs will work - uint8_t buff[6] = { 0 }; - mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; - int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - RADIOLIB_ASSERT(state); - return(LR2021::SPIparseStatus(buff[0])); -} - #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index f85da01a87..76dfc23586 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -9,6 +9,7 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" #include "../LR11x0/LR_common.h" +#include "LR2021_commands.h" // LR2021 physical layer properties #define RADIOLIB_LR2021_FREQUENCY_STEP_SIZE 1.0 @@ -16,185 +17,6 @@ #define RADIOLIB_LR2021_CRYSTAL_FREQ 32.0 #define RADIOLIB_LR2021_DIV_EXPONENT 25 -// LR2021 SPI commands -#define RADIOLIB_LR2021_CMD_NOP (0x0000) -#define RADIOLIB_LR2021_CMD_READ_RX_FIFO (0x0001) -#define RADIOLIB_LR2021_CMD_WRITE_TX_FIFO (0x0002) -#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32 (0x0104) -#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32 (0x0105) -#define RADIOLIB_LR2021_CMD_READ_REG_MEM_32 (0x0106) -#define RADIOLIB_LR2021_CMD_SET_SLEEP (0x0127) -#define RADIOLIB_LR2021_CMD_SET_STANDBY (0x0128) -#define RADIOLIB_LR2021_CMD_SET_FS (0x0129) -#define RADIOLIB_LR2021_CMD_SET_ADDITIONAL_REG_TO_RETAIN (0x012A) -#define RADIOLIB_LR2021_CMD_SET_RX (0x020C) -#define RADIOLIB_LR2021_CMD_SET_TX (0x020D) -#define RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE (0x0206) -#define RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE (0x0210) -#define RADIOLIB_LR2021_CMD_SET_AUTO_RX_TX (0x0211) -#define RADIOLIB_LR2021_CMD_GET_RX_PKT_LENGTH (0x0212) -#define RADIOLIB_LR2021_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0209) -#define RADIOLIB_LR2021_CMD_RESET_RX_STATS (0x020A) -#define RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT (0x0215) -#define RADIOLIB_LR2021_CMD_SET_REG_MODE (0x0121) -#define RADIOLIB_LR2021_CMD_CALIBRATE (0x0122) -#define RADIOLIB_LR2021_CMD_CALIB_FRONT_END (0x0123) -#define RADIOLIB_LR2021_CMD_GET_V_BAT (0x0124) -#define RADIOLIB_LR2021_CMD_GET_TEMP (0x0125) -#define RADIOLIB_LR2021_CMD_SET_EOL_CONFIG (0x0130) -#define RADIOLIB_LR2021_CMD_GET_RANDOM_NUMBER (0x0126) -#define RADIOLIB_LR2021_CMD_GET_STATUS (0x0100) -#define RADIOLIB_LR2021_CMD_GET_VERSION (0x0101) -#define RADIOLIB_LR2021_CMD_CLEAR_ERRORS (0x0111) -#define RADIOLIB_LR2021_CMD_GET_ERRORS (0x0110) -#define RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION (0x0112) -#define RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG (0x0115) -#define RADIOLIB_LR2021_CMD_CLEAR_IRQ (0x0116) -#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS (0x0117) -#define RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ (0x011A) -#define RADIOLIB_LR2021_CMD_GET_FIFO_IRQ_FLAGS (0x011B) -#define RADIOLIB_LR2021_CMD_CLEAR_FIFO_IRQ_FLAGS (0x0114) -#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_FIFO_IRQ_FLAGS (0x012E) -#define RADIOLIB_LR2021_CMD_GET_RX_FIFO_LEVEL (0x011C) -#define RADIOLIB_LR2021_CMD_GET_TX_FIFO_LEVEL (0x011D) -#define RADIOLIB_LR2021_CMD_CLEAR_RX_FIFO (0x011E) -#define RADIOLIB_LR2021_CMD_CLEAR_TX_FIFO (0x011F) -#define RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK (0x0118) -#define RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS (0x0119) -#define RADIOLIB_LR2021_CMD_SET_TCXO_MODE (0x0120) -#define RADIOLIB_LR2021_CMD_SET_XOSC_CP_TRIM (0x0131) -#define RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY (0x0200) -#define RADIOLIB_LR2021_CMD_SET_RX_PATH (0x0201) -#define RADIOLIB_LR2021_CMD_GET_RSSI_INST (0x020B) -#define RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION (0x0205) -#define RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE (0x0216) -#define RADIOLIB_LR2021_CMD_GET_TIMESTAMP_VALUE (0x0217) -#define RADIOLIB_LR2021_CMD_SET_CCA (0x0218) -#define RADIOLIB_LR2021_CMD_GET_CCA_RESULT (0x0219) -#define RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL (0x021A) -#define RADIOLIB_LR2021_CMD_SET_CAD_PARAMS (0x021B) -#define RADIOLIB_LR2021_CMD_SET_CAD (0x021C) -#define RADIOLIB_LR2021_CMD_SEL_PA (0x020F) -#define RADIOLIB_LR2021_CMD_SET_PA_CONFIG (0x0202) -#define RADIOLIB_LR2021_CMD_SET_TX_PARAMS (0x0203) -#define RADIOLIB_LR2021_CMD_SET_PACKET_TYPE (0x0207) -#define RADIOLIB_LR2021_CMD_GET_PACKET_TYPE (0x0208) -#define RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS (0x0220) -#define RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS (0x0221) -#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT (0x0222) -#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD (0x0223) -#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG (0x0224) -#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD (0x0225) -#define RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS (0x0227) -#define RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS (0x0229) -#define RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS (0x022A) -#define RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS (0x022B) -#define RADIOLIB_LR2021_CMD_SET_LORA_HOPPING (0x022C) -#define RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC (0x021D) -#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CAD (0x021E) -#define RADIOLIB_LR2021_CMD_SET_RANGING_ADDR (0x0278) -#define RADIOLIB_LR2021_CMD_SET_RANGING_REQ_ADDR (0x0279) -#define RADIOLIB_LR2021_CMD_GET_RANGING_RESULT (0x027A) -#define RADIOLIB_LR2021_CMD_GET_RANGING_STATS (0x027D) -#define RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY (0x027B) -#define RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS (0x027C) -#define RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS (0x0240) -#define RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS (0x0241) -#define RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS (0x0242) -#define RADIOLIB_LR2021_CMD_SET_FSK_CRC_PARAMS (0x0243) -#define RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD (0x0244) -#define RADIOLIB_LR2021_CMD_SET_FSK_ADDRESS (0x0245) -#define RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS (0x0246) -#define RADIOLIB_LR2021_CMD_GET_FSK_PACKET_STATUS (0x0247) -#define RADIOLIB_LR2021_CMD_SET_WMBUS_PARAMS (0x026A) -#define RADIOLIB_LR2021_CMD_GET_WMBUS_RX_STATS (0x026C) -#define RADIOLIB_LR2021_CMD_GET_WMBUS_PACKET_STATUS (0x026D) -#define RADIOLIB_LR2021_CMD_SET_WMBUS_FILTERING_ADDRESS (0x026E) -#define RADIOLIB_LR2021_CMD_SET_WISUN_MODE (0x0270) -#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_PARAMS (0x0271) -#define RADIOLIB_LR2021_CMD_GET_WISUN_RX_STATS (0x0272) -#define RADIOLIB_LR2021_CMD_GET_WISUN_PACKET_STATUS (0x0273) -#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_LEN (0x0274) -#define RADIOLIB_LR2021_CMD_SET_ZWAVE_PARAMS (0x0297) -#define RADIOLIB_LR2021_CMD_SET_ZWAVE_HOME_ID_FILTERING (0x0298) -#define RADIOLIB_LR2021_CMD_GET_ZWAVE_RX_STATS (0x0299) -#define RADIOLIB_LR2021_CMD_GET_ZWAVE_PACKET_STATUS (0x029A) -#define RADIOLIB_LR2021_CMD_SET_ZWAVE_BEAM_FILTERING (0x029B) -#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN_CONFIG (0x029C) -#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN (0x029D) -#define RADIOLIB_LR2021_CMD_SET_BLE_MODULATION_PARAMS (0x0260) -#define RADIOLIB_LR2021_CMD_SET_BLE_CHANNEL_PARAMS (0x0261) -#define RADIOLIB_LR2021_CMD_SET_BLE_PDU_LEN (0x0266) -#define RADIOLIB_LR2021_CMD_SET_BLE_TX (0x0262) -#define RADIOLIB_LR2021_CMD_GET_BLE_RX_STATS (0x0264) -#define RADIOLIB_LR2021_CMD_GET_BLE_PACKET_STATUS (0x0265) -#define RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS (0x029F) -#define RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS (0x02A0) -#define RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS (0x02A1) -#define RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN (0x02A2) -#define RADIOLIB_LR2021_CMD_SET_OQPSK_ADDRESS (0x02A3) -#define RADIOLIB_LR2021_CMD_SET_BPSK_MODULATION_PARAMS (0x0250) -#define RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS (0x0251) -#define RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS (0x0248) -#define RADIOLIB_LR2021_CMD_SET_FLRC_PACKET_PARAMS (0x0249) -#define RADIOLIB_LR2021_CMD_GET_FLRC_RX_STATS (0x024A) -#define RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS (0x024B) -#define RADIOLIB_LR2021_CMD_SET_FLRC_SYNCWORD (0x024C) -#define RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME (0x0256) -#define RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD (0x0257) -#define RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS (0x0281) -#define RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS (0x0282) -#define RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS (0x0283) -#define RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD (0x0284) -#define RADIOLIB_LR2021_CMD_SET_OOK_ADDRESS (0x0285) -#define RADIOLIB_LR2021_CMD_GET_OOK_RX_STATS (0x0286) -#define RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS (0x0287) -#define RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR (0x0288) -#define RADIOLIB_LR2021_CMD_SET_OOK_WHITENING_PARAMS (0x0289) -#define RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE (0x020E) - -// RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG -#define RADIOLIB_LR2021_IRQ_RX_FIFO (0x01UL << 0) // 31 0 interrupt: Rx FIFO threshold reached -#define RADIOLIB_LR2021_IRQ_TX_FIFO (0x01UL << 1) // 31 0 Tx FIFO threshold reached -#define RADIOLIB_LR2021_IRQ_RNG_REQ_VALID (0x01UL << 2) // 31 0 ranging slave received valid request -#define RADIOLIB_LR2021_IRQ_TX_TIMESTAMP (0x01UL << 3) // 31 0 end of packet Tx timestamp -#define RADIOLIB_LR2021_IRQ_RX_TIMESTAMP (0x01UL << 4) // 31 0 end of packet Rx timestamp -#define RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED (0x01UL << 5) // 31 0 preamble detected -#define RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID (0x01UL << 6) // 31 0 LoRa header received and valid -#define RADIOLIB_LR2021_IRQ_SYNCWORD_VALID (0x01UL << 6) // 31 0 sync word valid -#define RADIOLIB_LR2021_IRQ_CAD_DETECTED (0x01UL << 7) // 31 0 channel activity detected -#define RADIOLIB_LR2021_IRQ_LORA_HDR_TIMESTAMP (0x01UL << 8) // 31 0 LoRa header timestamp -#define RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR (0x01UL << 9) // 31 0 LoRa header CRC error -#define RADIOLIB_LR2021_IRQ_EOL (0x01UL << 10) // 31 0 end of life -#define RADIOLIB_LR2021_IRQ_PA_OCP_OVP (0x01UL << 11) // 31 0 PA overcurrent/overvoltage triggered -#define RADIOLIB_LR2021_IRQ_LORA_TX_RX_HOP (0x01UL << 12) // 31 0 LoRa intra-packet hopping -#define RADIOLIB_LR2021_IRQ_SYNC_FAIL (0x01UL << 13) // 31 0 sync word match detection failed -#define RADIOLIB_LR2021_IRQ_LORA_SYMBOL_END (0x01UL << 14) // 31 0 symbol end -#define RADIOLIB_LR2021_IRQ_LORA_TIMESTAMP_STAT (0x01UL << 15) // 31 0 new stats available -#define RADIOLIB_LR2021_IRQ_ERROR (0x01UL << 16) // 31 0 error other than command error -#define RADIOLIB_LR2021_IRQ_CMD_ERROR (0x01UL << 17) // 31 0 command error -#define RADIOLIB_LR2021_IRQ_RX_DONE (0x01UL << 18) // 31 0 packet received -#define RADIOLIB_LR2021_IRQ_TX_DONE (0x01UL << 19) // 31 0 packet transmitted -#define RADIOLIB_LR2021_IRQ_CAD_DONE (0x01UL << 20) // 31 0 CAD finished -#define RADIOLIB_LR2021_IRQ_TIMEOUT (0x01UL << 21) // 31 0 Rx or Tx timeout -#define RADIOLIB_LR2021_IRQ_CRC_ERROR (0x01UL << 22) // 31 0 CRC error -#define RADIOLIB_LR2021_IRQ_LEN_ERROR (0x01UL << 23) // 31 0 length error on received packet -#define RADIOLIB_LR2021_IRQ_ADDR_ERROR (0x01UL << 24) // 31 0 packet with incorrect address received -#define RADIOLIB_LR2021_IRQ_FHSS (0x01UL << 25) // 31 0 FHSS intra-packet hopping -#define RADIOLIB_LR2021_IRQ_INTER_PACKET_FREQ (0x01UL << 26) // 31 0 inter packet hopping can load new frequency table -#define RADIOLIB_LR2021_IRQ_INTER_NEW_PAYLOAD (0x01UL << 27) // 31 0 inter packet hopping can load new payload -#define RADIOLIB_LR2021_IRQ_RNG_RESP_DONE (0x01UL << 28) // 31 0 slave ranging response sent -#define RADIOLIB_LR2021_IRQ_RNG_REQ_DIS (0x01UL << 29) // 31 0 ranging request discarded -#define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response -#define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout - -// RADIOLIB_LR2021_CMD_SET_SLEEP -#define RADIOLIB_LR2021_SLEEP_32K_CLK_DISABLED (0x00UL << 0) // 0 0 32 kHz clock: disabled -#define RADIOLIB_LR2021_SLEEP_32K_CLK_ENABLED (0x01UL << 0) // 0 0 enabled -#define RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED (0x00UL << 1) // 1 1 configuration retention in sleep mode: disabled -#define RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED (0x01UL << 1) // 1 1 enabled - - /*! \class LR2021 \brief @@ -231,15 +53,48 @@ class LR2021: public PhysicalLayer, public LRxxxx { #endif Module* mod; - static int16_t SPIparseStatus(uint8_t in); - static int16_t SPIcheckStatus(Module* mod); - + // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); int16_t writeRadioTxFifo(uint8_t* data, size_t len); int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data); int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); - + int16_t setFs(void); + int16_t setAdditionalRegToRetain(uint8_t slot, uint32_t addr); + int16_t setRx(uint32_t timeout); + int16_t setTx(uint32_t timeout); + int16_t setRxTxFallbackMode(uint8_t mode); + int16_t setRxDutyCycle(uint32_t rxMaxTime, uint32_t cycleTime, uint8_t cfg); + int16_t autoTxRx(uint32_t delay, uint8_t mode, uint32_t timeout); + int16_t getRxPktLength(uint16_t* len); + int16_t resetRxStats(void); + int16_t setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout); + int16_t setRegMode(uint8_t simoUsage, uint8_t rampTimes[4]); + int16_t calibrate(uint8_t blocks); + int16_t calibrateFrontEnd(uint16_t freq[3]); + int16_t getVbat(uint8_t resolution, uint16_t* vbat); + int16_t getTemp(uint8_t source, uint8_t resolution, float* temp); + int16_t setEolConfig(bool enable, uint8_t trim); + int16_t getRandomNumber(uint32_t* rnd); + int16_t getVersion(uint8_t* major, uint8_t* minor); + int16_t clearErrors(void); + int16_t getErrors(uint16_t* err); + int16_t setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive); + int16_t setDioIrqConfig(uint8_t dio, uint32_t irq); + int16_t clearIrq(uint32_t irq); + int16_t getAndClearIrqStatus(uint32_t* irq); + int16_t configFifoIrq(uint8_t rxFifoIrq, uint8_t txFifoIrq, uint8_t rxHighThreshold, uint8_t txHighThreshold); + int16_t getFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags); + int16_t clearFifoIrqFlags(uint8_t rxFifoFlags, uint8_t txFifoFlags); + int16_t getAndClearFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags); + int16_t getRxFifoLevel(uint16_t* level); + int16_t getTxFifoLevel(uint16_t* level); + int16_t clearRxFifo(void); + int16_t clearTxFifo(void); + int16_t configLfClock(uint8_t cfg); + int16_t configClkOutputs(uint8_t scaling); + int16_t setTcxoMode(uint8_t tune, uint32_t startTime); + int16_t setXoscCpTrim(uint8_t xta, uint8_t xtb, uint8_t startTime); }; #endif diff --git a/src/modules/LR2021/LR2021_commands.cpp b/src/modules/LR2021/LR2021_commands.cpp index aba53c42d5..4e1b5788d7 100644 --- a/src/modules/LR2021/LR2021_commands.cpp +++ b/src/modules/LR2021/LR2021_commands.cpp @@ -15,4 +15,293 @@ int16_t LR2021::writeRadioTxFifo(uint8_t* data, size_t len) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_TX_FIFO, true, data, len, NULL, 0)); } +int16_t LR2021::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { + // check maximum size + if(len > (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + return(this->writeCommon(RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32, addr, data, len, false)); +} + +int16_t LR2021::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { + uint8_t buff[12] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), + (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32, true, buff, sizeof(buff))); +} + +int16_t LR2021::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { + // check maximum size + if(len >= (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // the request contains the address and length + uint8_t reqBuff[5] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + (uint8_t)len, + }; + + // build buffers - later we need to ensure endians are correct, + // so there is probably no way to do this without copying buffers and iterating + #if RADIOLIB_STATIC_ONLY + uint8_t rplBuff[RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN]; + #else + uint8_t* rplBuff = new uint8_t[len*sizeof(uint32_t)]; + #endif + + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_READ_REG_MEM_32, false, rplBuff, len*sizeof(uint32_t), reqBuff, sizeof(reqBuff)); + + // convert endians + if(data && (state == RADIOLIB_ERR_NONE)) { + for(size_t i = 0; i < len; i++) { + data[i] = ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[3 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[4 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[5 + i*sizeof(uint32_t)]; + } + } + + #if !RADIOLIB_STATIC_ONLY + delete[] rplBuff; + #endif + + return(state); +} + +int16_t LR2021::setFs(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FS, true, NULL, 0)); +} + +int16_t LR2021::setAdditionalRegToRetain(uint8_t slot, uint32_t addr) { + uint8_t buff[] = { + slot, (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + }; + + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_ADDITIONAL_REG_TO_RETAIN, true, buff, sizeof(buff))); +} + +int16_t LR2021::setRx(uint32_t timeout) { + uint8_t buff[] = { + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX, true, buff, sizeof(buff))); +} + +int16_t LR2021::setTx(uint32_t timeout) { + uint8_t buff[] = { + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX, true, buff, sizeof(buff))); +} + +int16_t LR2021::setRxTxFallbackMode(uint8_t mode) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE, true, &mode, sizeof(mode))); +} + +int16_t LR2021::setRxDutyCycle(uint32_t rxMaxTime, uint32_t cycleTime, uint8_t cfg) { + uint8_t buff[] = { + (uint8_t)((rxMaxTime >> 16) & 0xFF), (uint8_t)((rxMaxTime >> 8) & 0xFF), (uint8_t)(rxMaxTime & 0xFF), + (uint8_t)((cycleTime >> 16) & 0xFF), (uint8_t)((cycleTime >> 8) & 0xFF), (uint8_t)(cycleTime & 0xFF), + cfg + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE, true, buff, sizeof(buff))); +} + +int16_t LR2021::autoTxRx(uint32_t delay, uint8_t mode, uint32_t timeout) { + uint8_t buff[] = { + (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), mode, + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AUTO_RX_TX, true, buff, sizeof(buff))); +} + +int16_t LR2021::getRxPktLength(uint16_t* len) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RX_PKT_LENGTH, false, buff, sizeof(buff)); + if(len) { *len = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + return(state); +} + +int16_t LR2021::resetRxStats(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_RESET_RX_STATS, true, NULL, 0)); +} + +int16_t LR2021::setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout) { + uint8_t buff[] = { + (uint8_t)((rxTimeout >> 16) & 0xFF), (uint8_t)((rxTimeout >> 8) & 0xFF), (uint8_t)(rxTimeout & 0xFF), + (uint8_t)((txTimeout >> 16) & 0xFF), (uint8_t)((txTimeout >> 8) & 0xFF), (uint8_t)(txTimeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT, true, buff, sizeof(buff))); +} + +int16_t LR2021::setRegMode(uint8_t simoUsage, uint8_t rampTimes[4]) { + uint8_t buff[] = { simoUsage, + rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RC2RU], rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_TX2RU], + rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RU2RC], rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RAMP_DOWN], + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_REG_MODE, true, buff, sizeof(buff))); +} + +int16_t LR2021::calibrate(uint8_t blocks) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CALIBRATE, true, &blocks, sizeof(blocks))); +} + +int16_t LR2021::calibrateFrontEnd(uint16_t freq[3]) { + uint8_t buff[] = { + (uint8_t)((freq[0] >> 8) & 0xFF), (uint8_t)(freq[0] & 0xFF), + (uint8_t)((freq[1] >> 8) & 0xFF), (uint8_t)(freq[1] & 0xFF), + (uint8_t)((freq[2] >> 8) & 0xFF), (uint8_t)(freq[2] & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CALIB_FRONT_END, true, buff, sizeof(buff))); +} + +int16_t LR2021::getVbat(uint8_t resolution, uint16_t* vbat) { + uint8_t reqBuff[] = { (uint8_t)(RADIOLIB_LR20210_VBAT_FORMAT_MV | ((RADIOLIB_LR20210_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) }; + uint8_t rplBuff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_V_BAT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + if(vbat) { *vbat = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; } + return(state); +} + +int16_t LR2021::getTemp(uint8_t source, uint8_t resolution, float* temp) { + uint8_t reqBuff[] = { (uint8_t)((source & 0x30) | RADIOLIB_LR20210_TEMP_FORMAT_DEG_C | ((RADIOLIB_LR20210_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) }; + uint8_t rplBuff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TEMP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + if(temp) { + uint16_t raw = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; + *temp = (float)raw/32.0f; + } + return(state); +} + +int16_t LR2021::setEolConfig(bool enable, uint8_t trim) { + uint8_t buff[] = { (uint8_t)((trim & 0x06) | (uint8_t)enable) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_EOL_CONFIG, true, buff, sizeof(buff))); +} + +int16_t LR2021::getRandomNumber(uint32_t* rnd) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANDOM_NUMBER, false, buff, sizeof(buff)); + if(rnd) { *rnd = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) | (uint32_t)buff[3]; } + return(state); +} + +int16_t LR2021::getVersion(uint8_t* major, uint8_t* minor) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_VERSION, false, buff, sizeof(buff)); + if(major) { *major = buff[0]; } + if(minor) { *minor = buff[1]; } + return(state); +} + +int16_t LR2021::clearErrors(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_ERRORS, true, NULL, 0)); +} + +int16_t LR2021::getErrors(uint16_t* err) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_ERRORS, false, buff, sizeof(buff)); + if(err) { *err = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + return(state); +} + +int16_t LR2021::setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive) { + uint8_t buff[] = { dio, (uint8_t)((func & 0xF0) | (pullDrive & 0x0F)) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION, true, buff, sizeof(buff))); +} + +int16_t LR2021::setDioIrqConfig(uint8_t dio, uint32_t irq) { + uint8_t buff[] = { dio, + (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), + (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG, true, buff, sizeof(buff))); +} + +int16_t LR2021::clearIrq(uint32_t irq) { + uint8_t buff[] = { + (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), + (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_IRQ, true, buff, sizeof(buff))); +} + +int16_t LR2021::getAndClearIrqStatus(uint32_t* irq) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS, false, buff, sizeof(buff)); + if(irq) { *irq = ((uint16_t)(buff[0]) << 24) | ((uint16_t)(buff[1]) << 16) | ((uint16_t)(buff[2]) << 8) |(uint16_t)buff[3]; } + return(state); +} + +int16_t LR2021::configFifoIrq(uint8_t rxFifoIrq, uint8_t txFifoIrq, uint8_t rxHighThreshold, uint8_t txHighThreshold) { + uint8_t buff[] = { rxFifoIrq, txFifoIrq, rxHighThreshold, txHighThreshold }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ, true, buff, sizeof(buff))); +} + +int16_t LR2021::getFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FIFO_IRQ_FLAGS, false, buff, sizeof(buff)); + if(rxFifoFlags) { *rxFifoFlags = buff[0]; } + if(txFifoFlags) { *txFifoFlags = buff[1]; } + return(state); +} + +int16_t LR2021::clearFifoIrqFlags(uint8_t rxFifoFlags, uint8_t txFifoFlags) { + uint8_t buff[] = { rxFifoFlags, txFifoFlags }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_FIFO_IRQ_FLAGS, true, buff, sizeof(buff))); +} + +int16_t LR2021::getAndClearFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_AND_CLEAR_FIFO_IRQ_FLAGS, false, buff, sizeof(buff)); + if(rxFifoFlags) { *rxFifoFlags = buff[0]; } + if(txFifoFlags) { *txFifoFlags = buff[1]; } + return(state); +} + +int16_t LR2021::getRxFifoLevel(uint16_t* level) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RX_FIFO_LEVEL, false, buff, sizeof(buff)); + if(level) { *level = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + return(state); +} + +int16_t LR2021::getTxFifoLevel(uint16_t* level) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TX_FIFO_LEVEL, false, buff, sizeof(buff)); + if(level) { *level = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + return(state); +} + +int16_t LR2021::clearRxFifo(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_RX_FIFO, true, NULL, 0)); +} + +int16_t LR2021::clearTxFifo(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_TX_FIFO, true, NULL, 0)); +} + +int16_t LR2021::configLfClock(uint8_t cfg) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK, true, &cfg, sizeof(cfg))); +} + +int16_t LR2021::configClkOutputs(uint8_t scaling) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS, true, &scaling, sizeof(scaling))); +} + +int16_t LR2021::setTcxoMode(uint8_t tune, uint32_t startTime) { + uint8_t buff[] = { (uint8_t)(tune & 0x07), + (uint8_t)((startTime >> 24) & 0xFF), (uint8_t)((startTime >> 16) & 0xFF), + (uint8_t)((startTime >> 8) & 0xFF), (uint8_t)(startTime & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setXoscCpTrim(uint8_t xta, uint8_t xtb, uint8_t startTime) { + uint8_t buff[] = { (uint8_t)(xta & 0x3F), (uint8_t)(xtb & 0x3F), startTime }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS, true, buff, sizeof(buff))); +} + #endif diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h new file mode 100644 index 0000000000..5108a37285 --- /dev/null +++ b/src/modules/LR2021/LR2021_commands.h @@ -0,0 +1,293 @@ +#if !defined(RADIOLIB_LR2021_COMMANDS_H) +#define RADIOLIB_LR2021_COMMANDS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR2021 + +// LR2021 SPI commands +#define RADIOLIB_LR2021_CMD_NOP (0x0000) +#define RADIOLIB_LR2021_CMD_READ_RX_FIFO (0x0001) +#define RADIOLIB_LR2021_CMD_WRITE_TX_FIFO (0x0002) +#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32 (0x0104) +#define RADIOLIB_LR2021_CMD_WRITE_REG_MEM_MASK_32 (0x0105) +#define RADIOLIB_LR2021_CMD_READ_REG_MEM_32 (0x0106) +#define RADIOLIB_LR2021_CMD_SET_SLEEP (0x0127) +#define RADIOLIB_LR2021_CMD_SET_STANDBY (0x0128) +#define RADIOLIB_LR2021_CMD_SET_FS (0x0129) +#define RADIOLIB_LR2021_CMD_SET_ADDITIONAL_REG_TO_RETAIN (0x012A) +#define RADIOLIB_LR2021_CMD_SET_RX (0x020C) +#define RADIOLIB_LR2021_CMD_SET_TX (0x020D) +#define RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE (0x0206) +#define RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE (0x0210) +#define RADIOLIB_LR2021_CMD_SET_AUTO_RX_TX (0x0211) +#define RADIOLIB_LR2021_CMD_GET_RX_PKT_LENGTH (0x0212) +#define RADIOLIB_LR2021_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0209) +#define RADIOLIB_LR2021_CMD_RESET_RX_STATS (0x020A) +#define RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT (0x0215) +#define RADIOLIB_LR2021_CMD_SET_REG_MODE (0x0121) +#define RADIOLIB_LR2021_CMD_CALIBRATE (0x0122) +#define RADIOLIB_LR2021_CMD_CALIB_FRONT_END (0x0123) +#define RADIOLIB_LR2021_CMD_GET_V_BAT (0x0124) +#define RADIOLIB_LR2021_CMD_GET_TEMP (0x0125) +#define RADIOLIB_LR2021_CMD_SET_EOL_CONFIG (0x0130) +#define RADIOLIB_LR2021_CMD_GET_RANDOM_NUMBER (0x0126) +#define RADIOLIB_LR2021_CMD_GET_STATUS (0x0100) +#define RADIOLIB_LR2021_CMD_GET_VERSION (0x0101) +#define RADIOLIB_LR2021_CMD_CLEAR_ERRORS (0x0111) +#define RADIOLIB_LR2021_CMD_GET_ERRORS (0x0110) +#define RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION (0x0112) +#define RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG (0x0115) +#define RADIOLIB_LR2021_CMD_CLEAR_IRQ (0x0116) +#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS (0x0117) +#define RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ (0x011A) +#define RADIOLIB_LR2021_CMD_GET_FIFO_IRQ_FLAGS (0x011B) +#define RADIOLIB_LR2021_CMD_CLEAR_FIFO_IRQ_FLAGS (0x0114) +#define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_FIFO_IRQ_FLAGS (0x012E) +#define RADIOLIB_LR2021_CMD_GET_RX_FIFO_LEVEL (0x011C) +#define RADIOLIB_LR2021_CMD_GET_TX_FIFO_LEVEL (0x011D) +#define RADIOLIB_LR2021_CMD_CLEAR_RX_FIFO (0x011E) +#define RADIOLIB_LR2021_CMD_CLEAR_TX_FIFO (0x011F) +#define RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK (0x0118) +#define RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS (0x0119) +#define RADIOLIB_LR2021_CMD_SET_TCXO_MODE (0x0120) +#define RADIOLIB_LR2021_CMD_SET_XOSC_CP_TRIM (0x0131) +#define RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY (0x0200) +#define RADIOLIB_LR2021_CMD_SET_RX_PATH (0x0201) +#define RADIOLIB_LR2021_CMD_GET_RSSI_INST (0x020B) +#define RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION (0x0205) +#define RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE (0x0216) +#define RADIOLIB_LR2021_CMD_GET_TIMESTAMP_VALUE (0x0217) +#define RADIOLIB_LR2021_CMD_SET_CCA (0x0218) +#define RADIOLIB_LR2021_CMD_GET_CCA_RESULT (0x0219) +#define RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL (0x021A) +#define RADIOLIB_LR2021_CMD_SET_CAD_PARAMS (0x021B) +#define RADIOLIB_LR2021_CMD_SET_CAD (0x021C) +#define RADIOLIB_LR2021_CMD_SEL_PA (0x020F) +#define RADIOLIB_LR2021_CMD_SET_PA_CONFIG (0x0202) +#define RADIOLIB_LR2021_CMD_SET_TX_PARAMS (0x0203) +#define RADIOLIB_LR2021_CMD_SET_PACKET_TYPE (0x0207) +#define RADIOLIB_LR2021_CMD_GET_PACKET_TYPE (0x0208) +#define RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS (0x0220) +#define RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS (0x0221) +#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT (0x0222) +#define RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD (0x0223) +#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG (0x0224) +#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD (0x0225) +#define RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS (0x0227) +#define RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS (0x0229) +#define RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS (0x022A) +#define RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS (0x022B) +#define RADIOLIB_LR2021_CMD_SET_LORA_HOPPING (0x022C) +#define RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC (0x021D) +#define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CAD (0x021E) +#define RADIOLIB_LR2021_CMD_SET_RANGING_ADDR (0x0278) +#define RADIOLIB_LR2021_CMD_SET_RANGING_REQ_ADDR (0x0279) +#define RADIOLIB_LR2021_CMD_GET_RANGING_RESULT (0x027A) +#define RADIOLIB_LR2021_CMD_GET_RANGING_STATS (0x027D) +#define RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY (0x027B) +#define RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS (0x027C) +#define RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS (0x0240) +#define RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS (0x0241) +#define RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS (0x0242) +#define RADIOLIB_LR2021_CMD_SET_FSK_CRC_PARAMS (0x0243) +#define RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD (0x0244) +#define RADIOLIB_LR2021_CMD_SET_FSK_ADDRESS (0x0245) +#define RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS (0x0246) +#define RADIOLIB_LR2021_CMD_GET_FSK_PACKET_STATUS (0x0247) +#define RADIOLIB_LR2021_CMD_SET_WMBUS_PARAMS (0x026A) +#define RADIOLIB_LR2021_CMD_GET_WMBUS_RX_STATS (0x026C) +#define RADIOLIB_LR2021_CMD_GET_WMBUS_PACKET_STATUS (0x026D) +#define RADIOLIB_LR2021_CMD_SET_WMBUS_FILTERING_ADDRESS (0x026E) +#define RADIOLIB_LR2021_CMD_SET_WISUN_MODE (0x0270) +#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_PARAMS (0x0271) +#define RADIOLIB_LR2021_CMD_GET_WISUN_RX_STATS (0x0272) +#define RADIOLIB_LR2021_CMD_GET_WISUN_PACKET_STATUS (0x0273) +#define RADIOLIB_LR2021_CMD_SET_WISUN_PACKET_LEN (0x0274) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_PARAMS (0x0297) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_HOME_ID_FILTERING (0x0298) +#define RADIOLIB_LR2021_CMD_GET_ZWAVE_RX_STATS (0x0299) +#define RADIOLIB_LR2021_CMD_GET_ZWAVE_PACKET_STATUS (0x029A) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_BEAM_FILTERING (0x029B) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN_CONFIG (0x029C) +#define RADIOLIB_LR2021_CMD_SET_ZWAVE_SCAN (0x029D) +#define RADIOLIB_LR2021_CMD_SET_BLE_MODULATION_PARAMS (0x0260) +#define RADIOLIB_LR2021_CMD_SET_BLE_CHANNEL_PARAMS (0x0261) +#define RADIOLIB_LR2021_CMD_SET_BLE_PDU_LEN (0x0266) +#define RADIOLIB_LR2021_CMD_SET_BLE_TX (0x0262) +#define RADIOLIB_LR2021_CMD_GET_BLE_RX_STATS (0x0264) +#define RADIOLIB_LR2021_CMD_GET_BLE_PACKET_STATUS (0x0265) +#define RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS (0x029F) +#define RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS (0x02A0) +#define RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS (0x02A1) +#define RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN (0x02A2) +#define RADIOLIB_LR2021_CMD_SET_OQPSK_ADDRESS (0x02A3) +#define RADIOLIB_LR2021_CMD_SET_BPSK_MODULATION_PARAMS (0x0250) +#define RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS (0x0251) +#define RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS (0x0248) +#define RADIOLIB_LR2021_CMD_SET_FLRC_PACKET_PARAMS (0x0249) +#define RADIOLIB_LR2021_CMD_GET_FLRC_RX_STATS (0x024A) +#define RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS (0x024B) +#define RADIOLIB_LR2021_CMD_SET_FLRC_SYNCWORD (0x024C) +#define RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME (0x0256) +#define RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD (0x0257) +#define RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS (0x0281) +#define RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS (0x0282) +#define RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS (0x0283) +#define RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD (0x0284) +#define RADIOLIB_LR2021_CMD_SET_OOK_ADDRESS (0x0285) +#define RADIOLIB_LR2021_CMD_GET_OOK_RX_STATS (0x0286) +#define RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS (0x0287) +#define RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR (0x0288) +#define RADIOLIB_LR2021_CMD_SET_OOK_WHITENING_PARAMS (0x0289) +#define RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE (0x020E) + +// RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG +#define RADIOLIB_LR2021_IRQ_RX_FIFO (0x01UL << 0) // 31 0 interrupt: Rx FIFO threshold reached +#define RADIOLIB_LR2021_IRQ_TX_FIFO (0x01UL << 1) // 31 0 Tx FIFO threshold reached +#define RADIOLIB_LR2021_IRQ_RNG_REQ_VALID (0x01UL << 2) // 31 0 ranging slave received valid request +#define RADIOLIB_LR2021_IRQ_TX_TIMESTAMP (0x01UL << 3) // 31 0 end of packet Tx timestamp +#define RADIOLIB_LR2021_IRQ_RX_TIMESTAMP (0x01UL << 4) // 31 0 end of packet Rx timestamp +#define RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED (0x01UL << 5) // 31 0 preamble detected +#define RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID (0x01UL << 6) // 31 0 LoRa header received and valid +#define RADIOLIB_LR2021_IRQ_SYNCWORD_VALID (0x01UL << 6) // 31 0 sync word valid +#define RADIOLIB_LR2021_IRQ_CAD_DETECTED (0x01UL << 7) // 31 0 channel activity detected +#define RADIOLIB_LR2021_IRQ_LORA_HDR_TIMESTAMP (0x01UL << 8) // 31 0 LoRa header timestamp +#define RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR (0x01UL << 9) // 31 0 LoRa header CRC error +#define RADIOLIB_LR2021_IRQ_EOL (0x01UL << 10) // 31 0 end of life +#define RADIOLIB_LR2021_IRQ_PA_OCP_OVP (0x01UL << 11) // 31 0 PA overcurrent/overvoltage triggered +#define RADIOLIB_LR2021_IRQ_LORA_TX_RX_HOP (0x01UL << 12) // 31 0 LoRa intra-packet hopping +#define RADIOLIB_LR2021_IRQ_SYNC_FAIL (0x01UL << 13) // 31 0 sync word match detection failed +#define RADIOLIB_LR2021_IRQ_LORA_SYMBOL_END (0x01UL << 14) // 31 0 symbol end +#define RADIOLIB_LR2021_IRQ_LORA_TIMESTAMP_STAT (0x01UL << 15) // 31 0 new stats available +#define RADIOLIB_LR2021_IRQ_ERROR (0x01UL << 16) // 31 0 error other than command error +#define RADIOLIB_LR2021_IRQ_CMD_ERROR (0x01UL << 17) // 31 0 command error +#define RADIOLIB_LR2021_IRQ_RX_DONE (0x01UL << 18) // 31 0 packet received +#define RADIOLIB_LR2021_IRQ_TX_DONE (0x01UL << 19) // 31 0 packet transmitted +#define RADIOLIB_LR2021_IRQ_CAD_DONE (0x01UL << 20) // 31 0 CAD finished +#define RADIOLIB_LR2021_IRQ_TIMEOUT (0x01UL << 21) // 31 0 Rx or Tx timeout +#define RADIOLIB_LR2021_IRQ_CRC_ERROR (0x01UL << 22) // 31 0 CRC error +#define RADIOLIB_LR2021_IRQ_LEN_ERROR (0x01UL << 23) // 31 0 length error on received packet +#define RADIOLIB_LR2021_IRQ_ADDR_ERROR (0x01UL << 24) // 31 0 packet with incorrect address received +#define RADIOLIB_LR2021_IRQ_FHSS (0x01UL << 25) // 31 0 FHSS intra-packet hopping +#define RADIOLIB_LR2021_IRQ_INTER_PACKET_FREQ (0x01UL << 26) // 31 0 inter packet hopping can load new frequency table +#define RADIOLIB_LR2021_IRQ_INTER_NEW_PAYLOAD (0x01UL << 27) // 31 0 inter packet hopping can load new payload +#define RADIOLIB_LR2021_IRQ_RNG_RESP_DONE (0x01UL << 28) // 31 0 slave ranging response sent +#define RADIOLIB_LR2021_IRQ_RNG_REQ_DIS (0x01UL << 29) // 31 0 ranging request discarded +#define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response +#define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout + +// RADIOLIB_LR2021_CMD_SET_SLEEP +#define RADIOLIB_LR2021_SLEEP_32K_CLK_DISABLED (0x00UL << 0) // 0 0 32 kHz clock: disabled +#define RADIOLIB_LR2021_SLEEP_32K_CLK_ENABLED (0x01UL << 0) // 0 0 enabled +#define RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED (0x00UL << 1) // 1 1 configuration retention in sleep mode: disabled +#define RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED (0x01UL << 1) // 1 1 enabled + +// RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC +#define RADIOLIB_LR2021_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC +#define RADIOLIB_LR2021_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis + +// RADIOLIB_LR2021_CMD_SET_RX_DUTY_CYCLE +#define RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default) +#define RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD + +// RADIOLIB_LR20210_CMD_AUTO_TX_RX +#define RADIOLIB_LR20210_AUTO_MODE_NONE (0x00UL << 0) // 1 0 auto rx-tx mode: never enable auto rx-tx +#define RADIOLIB_LR20210_AUTO_MODE_ALWAYS (0x01UL << 0) // 1 0 auto rx-tx on every RxDone or TxDone event +#define RADIOLIB_LR20210_AUTO_MODE_OK (0x02UL << 0) // 1 0 auto rx-tx on valid Rx packet only (Tx always) +#define RADIOLIB_LR20210_AUTO_MODE_CLEAR_DISABLED (0x00UL << 7) // 7 7 automatically disable auto rx-tx on timeout: disabled +#define RADIOLIB_LR20210_AUTO_MODE_CLEAR_ENABLED (0x01UL << 7) // 7 7 enabled + +// RADIOLIB_LR2021_CMD_SET_REG_MODE +#define RADIOLIB_LR20210_REG_MODE_SIMO_OFF (0x00UL << 0) // 7 0 SIMO mode: disabled +#define RADIOLIB_LR20210_REG_MODE_SIMO_NORMAL (0x02UL << 0) // 7 0 normal +#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_2_US (0x00UL << 5) // 6 5 ramp timing resolution: 2 us +#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_4_US (0x01UL << 5) // 6 5 4 us +#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_8_US (0x02UL << 5) // 6 5 8 us +#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_16_US (0x03UL << 5) // 6 5 16 us +#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RC2RU (0) +#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_TX2RU (1) +#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RU2RC (2) +#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RAMP_DOWN (3) + +// RADIOLIB_LR2021_CMD_CALIBRATE +#define RADIOLIB_LR20210_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 blocks to calibrate: low-frequency RC +#define RADIOLIB_LR20210_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high-frequency RC +#define RADIOLIB_LR20210_CALIBRATE_PLL (0x01UL << 2) // 2 2 phase-locked loop +#define RADIOLIB_LR20210_CALIBRATE_AAF (0x01UL << 3) // 3 3 anti-aliasing filter +#define RADIOLIB_LR20210_CALIBRATE_MU (0x01UL << 5) // 4 4 measurement unit +#define RADIOLIB_LR20210_CALIBRATE_PA_OFF (0x01UL << 6) // 5 5 power amplifier offset +#define RADIOLIB_LR20210_CALIBRATE_ALL (0x6FUL << 0) // 7 0 everything + +// RADIOLIB_LR2021_CMD_CALIB_FRONT_END +#define RADIOLIB_LR20210_CALIBRATE_FE_LF_PATH (0x00UL << 15) // 15 15 calibration path: low-frequency +#define RADIOLIB_LR20210_CALIBRATE_FE_HF_PATH (0x01UL << 15) // 15 15 high-frequency + +// RADIOLIB_LR2021_CMD_GET_V_BAT +#define RADIOLIB_LR20210_VBAT_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw +#define RADIOLIB_LR20210_VBAT_FORMAT_MV (0x01UL << 3) // 3 3 millivolts +#define RADIOLIB_LR20210_MEAS_RESOLUTION_OFFSET (8) + +// RADIOLIB_LR2021_CMD_GET_TEMP +#define RADIOLIB_LR20210_TEMP_SOURCE_VBE (0x00UL << 4) // 4 4 temperature source: sensor near Vbe junction +#define RADIOLIB_LR20210_TEMP_SOURCE_XOSC (0x01UL << 4) // 4 4 sensor near XOSC +#define RADIOLIB_LR20210_TEMP_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw +#define RADIOLIB_LR20210_TEMP_FORMAT_DEG_C (0x01UL << 3) // 3 3 degress Celsius + +// RADIOLIB_LR2021_CMD_SET_EOL_CONFIG +#define RADIOLIB_LR20210_EOL_TRIM_1V6 (0x00UL << 1) // 3 1 EoL trigger threshold: 1.60 V +#define RADIOLIB_LR20210_EOL_TRIM_1V67 (0x01UL << 1) // 3 1 1.67 V +#define RADIOLIB_LR20210_EOL_TRIM_1V74 (0x02UL << 1) // 3 1 1.74 V +#define RADIOLIB_LR20210_EOL_TRIM_1V8 (0x03UL << 1) // 3 1 1.80 V +#define RADIOLIB_LR20210_EOL_TRIM_1V88 (0x04UL << 1) // 3 1 1.88 V (default) +#define RADIOLIB_LR20210_EOL_TRIM_1V95 (0x05UL << 1) // 3 1 1.95 V +#define RADIOLIB_LR20210_EOL_TRIM_2V0 (0x06UL << 1) // 3 1 2.00 V +#define RADIOLIB_LR20210_EOL_TRIM_2V1 (0x07UL << 1) // 3 1 2.10 V + +// RADIOLIB_LR2021_CMD_GET_ERRORS +#define RADIOLIB_LR20210_HF_XOSC_START_ERR (0x01UL << 0) // 15 0 error: high-frequency XOSC failed to start +#define RADIOLIB_LR20210_LF_XOSC_START_ERR (0x01UL << 1) // 15 0 low-frequency XOSC failed to start +#define RADIOLIB_LR20210_PLL_LOCK_ERR (0x01UL << 2) // 15 0 PLL failed to lock +#define RADIOLIB_LR20210_LF_RC_CALIB_ERR (0x01UL << 3) // 15 0 low-frequency RC calibration failed +#define RADIOLIB_LR20210_HF_RC_CALIB_ERR (0x01UL << 4) // 15 0 high-frequency RC calibration failed +#define RADIOLIB_LR20210_PLL_CALIB_ERR (0x01UL << 5) // 15 0 PLL calibration failed +#define RADIOLIB_LR20210_AAF_CALIB_ERR (0x01UL << 6) // 15 0 anti-aliasing filter calibration failed +#define RADIOLIB_LR20210_IMG_CALIB_ERR (0x01UL << 7) // 15 0 image rejection calibration failed +#define RADIOLIB_LR20210_CHIP_BUSY_ERR (0x01UL << 8) // 15 0 Tx or Rx could not be processed because chips was busy +#define RADIOLIB_LR20210_RXFREQ_NO_FE_CAL_ERR (0x01UL << 9) // 15 0 front-end calibration nto available for this Rx frequency +#define RADIOLIB_LR20210_MEAS_UNIT_ADC_CALIB_ERR (0x01UL << 10) // 15 0 measurement unit ADC calibration failed +#define RADIOLIB_LR20210_PA_OFFSET_CALIB_ERR (0x01UL << 11) // 15 0 PA offset calibration failed +#define RADIOLIB_LR20210_PPF_CALIB_ERR (0x01UL << 12) // 15 0 poly-phase filter calibration failed +#define RADIOLIB_LR20210_SRC_CALIB_ERR (0x01UL << 13) // 15 0 self-reception cancellation calibration failed + +// RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION +#define RADIOLIB_LR20210_DIO_FUNCTION_NONE (0x00UL << 4) // 7 4 DIO function: none +#define RADIOLIB_LR20210_DIO_FUNCTION_IRQ (0x01UL << 4) // 7 4 interrupt +#define RADIOLIB_LR20210_DIO_FUNCTION_RF_SWITCH (0x02UL << 4) // 7 4 RF switch +#define RADIOLIB_LR20210_DIO_FUNCTION_GPIO_OUTPUT_LOW (0x05UL << 4) // 7 4 low output +#define RADIOLIB_LR20210_DIO_FUNCTION_GPIO_OUTPUT_HIGH (0x06UL << 4) // 7 4 high output +#define RADIOLIB_LR20210_DIO_FUNCTION_HF_CLK_OUT (0x07UL << 4) // 7 4 high-frequency clock output +#define RADIOLIB_LR20210_DIO_FUNCTION_LF_CLK_OUT (0x08UL << 4) // 7 4 low-frequency clock output (DIO7-11 only) +#define RADIOLIB_LR20210_DIO_FUNCTION_TX_TRIGGER (0x09UL << 4) // 7 4 Tx trigger +#define RADIOLIB_LR20210_DIO_FUNCTION_RX_TRIGGER (0x0AUL << 4) // 7 4 Rx trigger +#define RADIOLIB_LR20210_DIO_SLEEP_PULL_NONE (0x00UL << 0) // 3 0 pull up/down in sleep mode: none +#define RADIOLIB_LR20210_DIO_SLEEP_PULL_DOWN (0x01UL << 0) // 3 0 pull-down +#define RADIOLIB_LR20210_DIO_SLEEP_PULL_UP (0x02UL << 0) // 3 0 pull-up +#define RADIOLIB_LR20210_DIO_SLEEP_PULL_AUTO (0x03UL << 0) // 3 0 auto + +// RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ +#define RADIOLIB_LR20210_FIFO_IRQ_EMPTY (0x01UL << 0) // 7 0 FIFO interrupt on: empty FIFO +#define RADIOLIB_LR20210_FIFO_IRQ_LOW (0x01UL << 1) // 7 0 level below threshold +#define RADIOLIB_LR20210_FIFO_IRQ_HIGH (0x01UL << 2) // 7 0 level above threshold +#define RADIOLIB_LR20210_FIFO_IRQ_FULL (0x01UL << 3) // 7 0 full FIFO +#define RADIOLIB_LR20210_FIFO_IRQ_OVERFLOW (0x01UL << 4) // 7 0 overflow +#define RADIOLIB_LR20210_FIFO_IRQ_UNDERFLOW (0x01UL << 5) // 7 0 underflow + +// RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK +#define RADIOLIB_LR20210_LF_CLOCK_INTERNAL_RC (0x00UL << 0) // 7 0 low-frequency source: internal 32 kHz RC oscillator +#define RADIOLIB_LR20210_LF_CLOCK_EXTERNAL (0x02UL << 0) // 7 0 external 32.768 kHz signal on DIO11 + +#endif + +#endif From 65a0f48f9a750d18c9bd3a016da369e57a2480b3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 16:15:43 +0100 Subject: [PATCH 1643/1848] [LR2021] Rename file --- .../LR2021/{LR2021_commands.cpp => LR2021_cmds_chip_control.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/modules/LR2021/{LR2021_commands.cpp => LR2021_cmds_chip_control.cpp} (100%) diff --git a/src/modules/LR2021/LR2021_commands.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp similarity index 100% rename from src/modules/LR2021/LR2021_commands.cpp rename to src/modules/LR2021/LR2021_cmds_chip_control.cpp From 833f79dace05464f5f71a5045bcbf76c0b308d3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 17:17:55 +0100 Subject: [PATCH 1644/1848] [LR2021] Add radio commands --- src/modules/LR2021/LR2021.h | 20 ++ .../LR2021/LR2021_cmds_chip_control.cpp | 8 +- src/modules/LR2021/LR2021_cmds_radio.cpp | 124 ++++++++++ src/modules/LR2021/LR2021_commands.h | 215 ++++++++++++------ 4 files changed, 289 insertions(+), 78 deletions(-) create mode 100644 src/modules/LR2021/LR2021_cmds_radio.cpp diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 76dfc23586..5dfc2874fe 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -95,6 +95,26 @@ class LR2021: public PhysicalLayer, public LRxxxx { int16_t configClkOutputs(uint8_t scaling); int16_t setTcxoMode(uint8_t tune, uint32_t startTime); int16_t setXoscCpTrim(uint8_t xta, uint8_t xtb, uint8_t startTime); + + // radio frequency front end commands + int16_t setRfFrequency(uint32_t rfFreq); + int16_t setRxPath(uint8_t rxPath, uint8_t rxBoost); + int16_t getRssiInst(float* rssi); + int16_t setRssiCalibration(uint8_t rxPath, uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]); + int16_t setTimestampSource(uint8_t index, uint8_t source); + int16_t getTimestampValue(uint8_t index, uint32_t* timestamp); + int16_t setCca(uint32_t duration, uint8_t gain); + int16_t getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg); + int16_t setAgcGainManual(uint8_t gain); + int16_t setCadParams(uint32_t cadTimeout, uint8_t threshold, uint8_t exitMode, uint32_t trxTimeout); + int16_t setCad(void); + int16_t selPa(uint8_t pa); + int16_t setPaConfig(uint8_t pa, uint8_t paLfMode, uint8_t paLfDutyCycle, uint8_t paLfSlices, uint8_t paHfDutyCycle); + int16_t setTxParams(int8_t txPower, uint8_t rampTime); + + // modem configuration commands + int16_t setPacketType(uint8_t packetType); + int16_t getPacketType(uint8_t* packetType); }; #endif diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index 4e1b5788d7..623392f7f7 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -138,8 +138,8 @@ int16_t LR2021::setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout) { int16_t LR2021::setRegMode(uint8_t simoUsage, uint8_t rampTimes[4]) { uint8_t buff[] = { simoUsage, - rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RC2RU], rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_TX2RU], - rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RU2RC], rampTimes[RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RAMP_DOWN], + rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RC2RU], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_TX2RU], + rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RU2RC], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RAMP_DOWN], }; return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_REG_MODE, true, buff, sizeof(buff))); } @@ -158,7 +158,7 @@ int16_t LR2021::calibrateFrontEnd(uint16_t freq[3]) { } int16_t LR2021::getVbat(uint8_t resolution, uint16_t* vbat) { - uint8_t reqBuff[] = { (uint8_t)(RADIOLIB_LR20210_VBAT_FORMAT_MV | ((RADIOLIB_LR20210_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) }; + uint8_t reqBuff[] = { (uint8_t)(RADIOLIB_LR2021_VBAT_FORMAT_MV | ((RADIOLIB_LR2021_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) }; uint8_t rplBuff[2] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_V_BAT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); if(vbat) { *vbat = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; } @@ -166,7 +166,7 @@ int16_t LR2021::getVbat(uint8_t resolution, uint16_t* vbat) { } int16_t LR2021::getTemp(uint8_t source, uint8_t resolution, float* temp) { - uint8_t reqBuff[] = { (uint8_t)((source & 0x30) | RADIOLIB_LR20210_TEMP_FORMAT_DEG_C | ((RADIOLIB_LR20210_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) }; + uint8_t reqBuff[] = { (uint8_t)((source & 0x30) | RADIOLIB_LR2021_TEMP_FORMAT_DEG_C | ((RADIOLIB_LR2021_MEAS_RESOLUTION_OFFSET + resolution) & 0x07)) }; uint8_t rplBuff[2] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TEMP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); if(temp) { diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp new file mode 100644 index 0000000000..6df41c91e5 --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -0,0 +1,124 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setRfFrequency(uint32_t rfFreq) { + uint8_t buff[] = { + (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF), + (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff))); +} + +int16_t LR2021::setRxPath(uint8_t rxPath, uint8_t rxBoost) { + uint8_t buff[] = { (uint8_t)(rxPath & 0x01), (uint8_t)(rxBoost & 0x07) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RX_PATH, true, buff, sizeof(buff))); +} + +int16_t LR2021::getRssiInst(float* rssi) { + uint8_t buff[2] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RSSI_INST, false, buff, sizeof(buff)); + if(rssi) { + uint16_t raw = ((uint16_t)(buff[0]) << 1) | (uint16_t)((buff[1] >> 7) & 0x01); + *rssi = (float)raw/-2.0f; + } + return(state); +} + +int16_t LR2021::setRssiCalibration(uint8_t rxPath, uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]) { + uint8_t buff[1 + RADIOLIB_LR2021_GAIN_TABLE_LENGTH] = { 0 }; + buff[0] = rxPath; + for(uint8_t i = 0; i < RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i++) { + buff[1 + i] = (uint8_t)((gain[i] & 0x300) >> 8); + buff[2 + i] = (uint8_t)(gain[i] & 0xFF); + buff[3 + i] = noiseFloor[i]; + } + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff))); +} + +int16_t LR2021::setTimestampSource(uint8_t index, uint8_t source) { + uint8_t buff[] = { (uint8_t)(((index & 0x03) << 4) | (source & 0x0F)) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE, true, buff, sizeof(buff))); +} + +int16_t LR2021::getTimestampValue(uint8_t index, uint32_t* timestamp) { + uint8_t reqBuff[] = { (uint8_t)(index & 0x03) }; + uint8_t rplBuff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TIMESTAMP_VALUE, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); + if(timestamp) { *timestamp = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; } + return(state); +} + +int16_t LR2021::setCca(uint32_t duration, uint8_t gain) { + uint8_t buff[] = { + (uint8_t)((duration >> 16) & 0xFF), (uint8_t)((duration >> 8) & 0xFF), (uint8_t)(duration & 0xFF), gain, + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_CCA, true, buff, sizeof(buff))); +} + +int16_t LR2021::getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg) { + uint8_t buff[4] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_CCA_RESULT, false, buff, sizeof(buff)); + uint16_t raw = 0; + if(rssiMin) { + raw = ((uint16_t)(buff[0]) << 1) | (uint16_t)((buff[3] >> 2) & 0x01); + *rssiMin = (float)raw/-2.0f; + } + if(rssiMax) { + raw = ((uint16_t)(buff[1]) << 1) | (uint16_t)((buff[3] >> 1) & 0x01); + *rssiMax = (float)raw/-2.0f; + } + if(rssiAvg) { + raw = ((uint16_t)(buff[2]) << 1) | (uint16_t)((buff[3] >> 0) & 0x01); + *rssiAvg = (float)raw/-2.0f; + } + return(state); +} + +int16_t LR2021::setAgcGainManual(uint8_t gain) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain))); +} + +int16_t LR2021::setCadParams(uint32_t cadTimeout, uint8_t threshold, uint8_t exitMode, uint32_t trxTimeout) { + uint8_t buff[] = { + (uint8_t)((cadTimeout >> 16) & 0xFF), (uint8_t)((cadTimeout >> 8) & 0xFF), (uint8_t)(cadTimeout & 0xFF), + threshold, (uint8_t)(exitMode & 0x03), + (uint8_t)((trxTimeout >> 16) & 0xFF), (uint8_t)((trxTimeout >> 8) & 0xFF), (uint8_t)(trxTimeout & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_CAD_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setCad(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_CAD, true, NULL, 0)); +} + +int16_t LR2021::selPa(uint8_t pa) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SEL_PA, true, &pa, sizeof(pa))); +} + +int16_t LR2021::setPaConfig(uint8_t pa, uint8_t paLfMode, uint8_t paLfDutyCycle, uint8_t paLfSlices, uint8_t paHfDutyCycle) { + uint8_t buff[] = { + (uint8_t)(pa << 7), (uint8_t)(paLfMode & 0x03), (uint8_t)(paLfDutyCycle & 0xF0), (uint8_t)(paLfSlices & 0x0F), (uint8_t)(paHfDutyCycle & 0x1F), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_PA_CONFIG, true, buff, sizeof(buff))); +} + +int16_t LR2021::setTxParams(int8_t txPower, uint8_t rampTime) { + uint8_t buff[] = { (uint8_t)(txPower * 2), rampTime }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setPacketType(uint8_t packetType) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_PACKET_TYPE, true, &packetType, sizeof(packetType))); +} + +int16_t LR2021::getPacketType(uint8_t* packetType) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_GET_PACKET_TYPE, true, packetType, sizeof(uint8_t))); +} + +#endif diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 5108a37285..707bae5687 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -193,100 +193,167 @@ #define RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD // RADIOLIB_LR20210_CMD_AUTO_TX_RX -#define RADIOLIB_LR20210_AUTO_MODE_NONE (0x00UL << 0) // 1 0 auto rx-tx mode: never enable auto rx-tx -#define RADIOLIB_LR20210_AUTO_MODE_ALWAYS (0x01UL << 0) // 1 0 auto rx-tx on every RxDone or TxDone event -#define RADIOLIB_LR20210_AUTO_MODE_OK (0x02UL << 0) // 1 0 auto rx-tx on valid Rx packet only (Tx always) -#define RADIOLIB_LR20210_AUTO_MODE_CLEAR_DISABLED (0x00UL << 7) // 7 7 automatically disable auto rx-tx on timeout: disabled -#define RADIOLIB_LR20210_AUTO_MODE_CLEAR_ENABLED (0x01UL << 7) // 7 7 enabled +#define RADIOLIB_LR2021_AUTO_MODE_NONE (0x00UL << 0) // 1 0 auto rx-tx mode: never enable auto rx-tx +#define RADIOLIB_LR2021_AUTO_MODE_ALWAYS (0x01UL << 0) // 1 0 auto rx-tx on every RxDone or TxDone event +#define RADIOLIB_LR2021_AUTO_MODE_OK (0x02UL << 0) // 1 0 auto rx-tx on valid Rx packet only (Tx always) +#define RADIOLIB_LR2021_AUTO_MODE_CLEAR_DISABLED (0x00UL << 7) // 7 7 automatically disable auto rx-tx on timeout: disabled +#define RADIOLIB_LR2021_AUTO_MODE_CLEAR_ENABLED (0x01UL << 7) // 7 7 enabled // RADIOLIB_LR2021_CMD_SET_REG_MODE -#define RADIOLIB_LR20210_REG_MODE_SIMO_OFF (0x00UL << 0) // 7 0 SIMO mode: disabled -#define RADIOLIB_LR20210_REG_MODE_SIMO_NORMAL (0x02UL << 0) // 7 0 normal -#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_2_US (0x00UL << 5) // 6 5 ramp timing resolution: 2 us -#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_4_US (0x01UL << 5) // 6 5 4 us -#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_8_US (0x02UL << 5) // 6 5 8 us -#define RADIOLIB_LR20210_REG_MODE_RAMP_RES_16_US (0x03UL << 5) // 6 5 16 us -#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RC2RU (0) -#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_TX2RU (1) -#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RU2RC (2) -#define RADIOLIB_LR20210_REG_MODE_RAMP_INDEX_RAMP_DOWN (3) +#define RADIOLIB_LR2021_REG_MODE_SIMO_OFF (0x00UL << 0) // 7 0 SIMO mode: disabled +#define RADIOLIB_LR2021_REG_MODE_SIMO_NORMAL (0x02UL << 0) // 7 0 normal +#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_2_US (0x00UL << 5) // 6 5 ramp timing resolution: 2 us +#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_4_US (0x01UL << 5) // 6 5 4 us +#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_8_US (0x02UL << 5) // 6 5 8 us +#define RADIOLIB_LR2021_REG_MODE_RAMP_RES_16_US (0x03UL << 5) // 6 5 16 us +#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RC2RU (0) +#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_TX2RU (1) +#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RU2RC (2) +#define RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RAMP_DOWN (3) // RADIOLIB_LR2021_CMD_CALIBRATE -#define RADIOLIB_LR20210_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 blocks to calibrate: low-frequency RC -#define RADIOLIB_LR20210_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high-frequency RC -#define RADIOLIB_LR20210_CALIBRATE_PLL (0x01UL << 2) // 2 2 phase-locked loop -#define RADIOLIB_LR20210_CALIBRATE_AAF (0x01UL << 3) // 3 3 anti-aliasing filter -#define RADIOLIB_LR20210_CALIBRATE_MU (0x01UL << 5) // 4 4 measurement unit -#define RADIOLIB_LR20210_CALIBRATE_PA_OFF (0x01UL << 6) // 5 5 power amplifier offset -#define RADIOLIB_LR20210_CALIBRATE_ALL (0x6FUL << 0) // 7 0 everything +#define RADIOLIB_LR2021_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 blocks to calibrate: low-frequency RC +#define RADIOLIB_LR2021_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high-frequency RC +#define RADIOLIB_LR2021_CALIBRATE_PLL (0x01UL << 2) // 2 2 phase-locked loop +#define RADIOLIB_LR2021_CALIBRATE_AAF (0x01UL << 3) // 3 3 anti-aliasing filter +#define RADIOLIB_LR2021_CALIBRATE_MU (0x01UL << 5) // 4 4 measurement unit +#define RADIOLIB_LR2021_CALIBRATE_PA_OFF (0x01UL << 6) // 5 5 power amplifier offset +#define RADIOLIB_LR2021_CALIBRATE_ALL (0x6FUL << 0) // 7 0 everything // RADIOLIB_LR2021_CMD_CALIB_FRONT_END -#define RADIOLIB_LR20210_CALIBRATE_FE_LF_PATH (0x00UL << 15) // 15 15 calibration path: low-frequency -#define RADIOLIB_LR20210_CALIBRATE_FE_HF_PATH (0x01UL << 15) // 15 15 high-frequency +#define RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH (0x00UL << 15) // 15 15 calibration path: low-frequency +#define RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH (0x01UL << 15) // 15 15 high-frequency // RADIOLIB_LR2021_CMD_GET_V_BAT -#define RADIOLIB_LR20210_VBAT_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw -#define RADIOLIB_LR20210_VBAT_FORMAT_MV (0x01UL << 3) // 3 3 millivolts -#define RADIOLIB_LR20210_MEAS_RESOLUTION_OFFSET (8) +#define RADIOLIB_LR2021_VBAT_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw +#define RADIOLIB_LR2021_VBAT_FORMAT_MV (0x01UL << 3) // 3 3 millivolts +#define RADIOLIB_LR2021_MEAS_RESOLUTION_OFFSET (8) // RADIOLIB_LR2021_CMD_GET_TEMP -#define RADIOLIB_LR20210_TEMP_SOURCE_VBE (0x00UL << 4) // 4 4 temperature source: sensor near Vbe junction -#define RADIOLIB_LR20210_TEMP_SOURCE_XOSC (0x01UL << 4) // 4 4 sensor near XOSC -#define RADIOLIB_LR20210_TEMP_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw -#define RADIOLIB_LR20210_TEMP_FORMAT_DEG_C (0x01UL << 3) // 3 3 degress Celsius +#define RADIOLIB_LR2021_TEMP_SOURCE_VBE (0x00UL << 4) // 4 4 temperature source: sensor near Vbe junction +#define RADIOLIB_LR2021_TEMP_SOURCE_XOSC (0x01UL << 4) // 4 4 sensor near XOSC +#define RADIOLIB_LR2021_TEMP_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw +#define RADIOLIB_LR2021_TEMP_FORMAT_DEG_C (0x01UL << 3) // 3 3 degress Celsius // RADIOLIB_LR2021_CMD_SET_EOL_CONFIG -#define RADIOLIB_LR20210_EOL_TRIM_1V6 (0x00UL << 1) // 3 1 EoL trigger threshold: 1.60 V -#define RADIOLIB_LR20210_EOL_TRIM_1V67 (0x01UL << 1) // 3 1 1.67 V -#define RADIOLIB_LR20210_EOL_TRIM_1V74 (0x02UL << 1) // 3 1 1.74 V -#define RADIOLIB_LR20210_EOL_TRIM_1V8 (0x03UL << 1) // 3 1 1.80 V -#define RADIOLIB_LR20210_EOL_TRIM_1V88 (0x04UL << 1) // 3 1 1.88 V (default) -#define RADIOLIB_LR20210_EOL_TRIM_1V95 (0x05UL << 1) // 3 1 1.95 V -#define RADIOLIB_LR20210_EOL_TRIM_2V0 (0x06UL << 1) // 3 1 2.00 V -#define RADIOLIB_LR20210_EOL_TRIM_2V1 (0x07UL << 1) // 3 1 2.10 V +#define RADIOLIB_LR2021_EOL_TRIM_1V6 (0x00UL << 1) // 3 1 EoL trigger threshold: 1.60 V +#define RADIOLIB_LR2021_EOL_TRIM_1V67 (0x01UL << 1) // 3 1 1.67 V +#define RADIOLIB_LR2021_EOL_TRIM_1V74 (0x02UL << 1) // 3 1 1.74 V +#define RADIOLIB_LR2021_EOL_TRIM_1V8 (0x03UL << 1) // 3 1 1.80 V +#define RADIOLIB_LR2021_EOL_TRIM_1V88 (0x04UL << 1) // 3 1 1.88 V (default) +#define RADIOLIB_LR2021_EOL_TRIM_1V95 (0x05UL << 1) // 3 1 1.95 V +#define RADIOLIB_LR2021_EOL_TRIM_2V0 (0x06UL << 1) // 3 1 2.00 V +#define RADIOLIB_LR2021_EOL_TRIM_2V1 (0x07UL << 1) // 3 1 2.10 V // RADIOLIB_LR2021_CMD_GET_ERRORS -#define RADIOLIB_LR20210_HF_XOSC_START_ERR (0x01UL << 0) // 15 0 error: high-frequency XOSC failed to start -#define RADIOLIB_LR20210_LF_XOSC_START_ERR (0x01UL << 1) // 15 0 low-frequency XOSC failed to start -#define RADIOLIB_LR20210_PLL_LOCK_ERR (0x01UL << 2) // 15 0 PLL failed to lock -#define RADIOLIB_LR20210_LF_RC_CALIB_ERR (0x01UL << 3) // 15 0 low-frequency RC calibration failed -#define RADIOLIB_LR20210_HF_RC_CALIB_ERR (0x01UL << 4) // 15 0 high-frequency RC calibration failed -#define RADIOLIB_LR20210_PLL_CALIB_ERR (0x01UL << 5) // 15 0 PLL calibration failed -#define RADIOLIB_LR20210_AAF_CALIB_ERR (0x01UL << 6) // 15 0 anti-aliasing filter calibration failed -#define RADIOLIB_LR20210_IMG_CALIB_ERR (0x01UL << 7) // 15 0 image rejection calibration failed -#define RADIOLIB_LR20210_CHIP_BUSY_ERR (0x01UL << 8) // 15 0 Tx or Rx could not be processed because chips was busy -#define RADIOLIB_LR20210_RXFREQ_NO_FE_CAL_ERR (0x01UL << 9) // 15 0 front-end calibration nto available for this Rx frequency -#define RADIOLIB_LR20210_MEAS_UNIT_ADC_CALIB_ERR (0x01UL << 10) // 15 0 measurement unit ADC calibration failed -#define RADIOLIB_LR20210_PA_OFFSET_CALIB_ERR (0x01UL << 11) // 15 0 PA offset calibration failed -#define RADIOLIB_LR20210_PPF_CALIB_ERR (0x01UL << 12) // 15 0 poly-phase filter calibration failed -#define RADIOLIB_LR20210_SRC_CALIB_ERR (0x01UL << 13) // 15 0 self-reception cancellation calibration failed +#define RADIOLIB_LR2021_HF_XOSC_START_ERR (0x01UL << 0) // 15 0 error: high-frequency XOSC failed to start +#define RADIOLIB_LR2021_LF_XOSC_START_ERR (0x01UL << 1) // 15 0 low-frequency XOSC failed to start +#define RADIOLIB_LR2021_PLL_LOCK_ERR (0x01UL << 2) // 15 0 PLL failed to lock +#define RADIOLIB_LR2021_LF_RC_CALIB_ERR (0x01UL << 3) // 15 0 low-frequency RC calibration failed +#define RADIOLIB_LR2021_HF_RC_CALIB_ERR (0x01UL << 4) // 15 0 high-frequency RC calibration failed +#define RADIOLIB_LR2021_PLL_CALIB_ERR (0x01UL << 5) // 15 0 PLL calibration failed +#define RADIOLIB_LR2021_AAF_CALIB_ERR (0x01UL << 6) // 15 0 anti-aliasing filter calibration failed +#define RADIOLIB_LR2021_IMG_CALIB_ERR (0x01UL << 7) // 15 0 image rejection calibration failed +#define RADIOLIB_LR2021_CHIP_BUSY_ERR (0x01UL << 8) // 15 0 Tx or Rx could not be processed because chips was busy +#define RADIOLIB_LR2021_RXFREQ_NO_FE_CAL_ERR (0x01UL << 9) // 15 0 front-end calibration nto available for this Rx frequency +#define RADIOLIB_LR2021_MEAS_UNIT_ADC_CALIB_ERR (0x01UL << 10) // 15 0 measurement unit ADC calibration failed +#define RADIOLIB_LR2021_PA_OFFSET_CALIB_ERR (0x01UL << 11) // 15 0 PA offset calibration failed +#define RADIOLIB_LR2021_PPF_CALIB_ERR (0x01UL << 12) // 15 0 poly-phase filter calibration failed +#define RADIOLIB_LR2021_SRC_CALIB_ERR (0x01UL << 13) // 15 0 self-reception cancellation calibration failed // RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION -#define RADIOLIB_LR20210_DIO_FUNCTION_NONE (0x00UL << 4) // 7 4 DIO function: none -#define RADIOLIB_LR20210_DIO_FUNCTION_IRQ (0x01UL << 4) // 7 4 interrupt -#define RADIOLIB_LR20210_DIO_FUNCTION_RF_SWITCH (0x02UL << 4) // 7 4 RF switch -#define RADIOLIB_LR20210_DIO_FUNCTION_GPIO_OUTPUT_LOW (0x05UL << 4) // 7 4 low output -#define RADIOLIB_LR20210_DIO_FUNCTION_GPIO_OUTPUT_HIGH (0x06UL << 4) // 7 4 high output -#define RADIOLIB_LR20210_DIO_FUNCTION_HF_CLK_OUT (0x07UL << 4) // 7 4 high-frequency clock output -#define RADIOLIB_LR20210_DIO_FUNCTION_LF_CLK_OUT (0x08UL << 4) // 7 4 low-frequency clock output (DIO7-11 only) -#define RADIOLIB_LR20210_DIO_FUNCTION_TX_TRIGGER (0x09UL << 4) // 7 4 Tx trigger -#define RADIOLIB_LR20210_DIO_FUNCTION_RX_TRIGGER (0x0AUL << 4) // 7 4 Rx trigger -#define RADIOLIB_LR20210_DIO_SLEEP_PULL_NONE (0x00UL << 0) // 3 0 pull up/down in sleep mode: none -#define RADIOLIB_LR20210_DIO_SLEEP_PULL_DOWN (0x01UL << 0) // 3 0 pull-down -#define RADIOLIB_LR20210_DIO_SLEEP_PULL_UP (0x02UL << 0) // 3 0 pull-up -#define RADIOLIB_LR20210_DIO_SLEEP_PULL_AUTO (0x03UL << 0) // 3 0 auto +#define RADIOLIB_LR2021_DIO_FUNCTION_NONE (0x00UL << 4) // 7 4 DIO function: none +#define RADIOLIB_LR2021_DIO_FUNCTION_IRQ (0x01UL << 4) // 7 4 interrupt +#define RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH (0x02UL << 4) // 7 4 RF switch +#define RADIOLIB_LR2021_DIO_FUNCTION_GPIO_OUTPUT_LOW (0x05UL << 4) // 7 4 low output +#define RADIOLIB_LR2021_DIO_FUNCTION_GPIO_OUTPUT_HIGH (0x06UL << 4) // 7 4 high output +#define RADIOLIB_LR2021_DIO_FUNCTION_HF_CLK_OUT (0x07UL << 4) // 7 4 high-frequency clock output +#define RADIOLIB_LR2021_DIO_FUNCTION_LF_CLK_OUT (0x08UL << 4) // 7 4 low-frequency clock output (DIO7-11 only) +#define RADIOLIB_LR2021_DIO_FUNCTION_TX_TRIGGER (0x09UL << 4) // 7 4 Tx trigger +#define RADIOLIB_LR2021_DIO_FUNCTION_RX_TRIGGER (0x0AUL << 4) // 7 4 Rx trigger +#define RADIOLIB_LR2021_DIO_SLEEP_PULL_NONE (0x00UL << 0) // 3 0 pull up/down in sleep mode: none +#define RADIOLIB_LR2021_DIO_SLEEP_PULL_DOWN (0x01UL << 0) // 3 0 pull-down +#define RADIOLIB_LR2021_DIO_SLEEP_PULL_UP (0x02UL << 0) // 3 0 pull-up +#define RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO (0x03UL << 0) // 3 0 auto // RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ -#define RADIOLIB_LR20210_FIFO_IRQ_EMPTY (0x01UL << 0) // 7 0 FIFO interrupt on: empty FIFO -#define RADIOLIB_LR20210_FIFO_IRQ_LOW (0x01UL << 1) // 7 0 level below threshold -#define RADIOLIB_LR20210_FIFO_IRQ_HIGH (0x01UL << 2) // 7 0 level above threshold -#define RADIOLIB_LR20210_FIFO_IRQ_FULL (0x01UL << 3) // 7 0 full FIFO -#define RADIOLIB_LR20210_FIFO_IRQ_OVERFLOW (0x01UL << 4) // 7 0 overflow -#define RADIOLIB_LR20210_FIFO_IRQ_UNDERFLOW (0x01UL << 5) // 7 0 underflow +#define RADIOLIB_LR2021_FIFO_IRQ_EMPTY (0x01UL << 0) // 7 0 FIFO interrupt on: empty FIFO +#define RADIOLIB_LR2021_FIFO_IRQ_LOW (0x01UL << 1) // 7 0 level below threshold +#define RADIOLIB_LR2021_FIFO_IRQ_HIGH (0x01UL << 2) // 7 0 level above threshold +#define RADIOLIB_LR2021_FIFO_IRQ_FULL (0x01UL << 3) // 7 0 full FIFO +#define RADIOLIB_LR2021_FIFO_IRQ_OVERFLOW (0x01UL << 4) // 7 0 overflow +#define RADIOLIB_LR2021_FIFO_IRQ_UNDERFLOW (0x01UL << 5) // 7 0 underflow // RADIOLIB_LR2021_CMD_CONFIG_LF_CLOCK -#define RADIOLIB_LR20210_LF_CLOCK_INTERNAL_RC (0x00UL << 0) // 7 0 low-frequency source: internal 32 kHz RC oscillator -#define RADIOLIB_LR20210_LF_CLOCK_EXTERNAL (0x02UL << 0) // 7 0 external 32.768 kHz signal on DIO11 +#define RADIOLIB_LR2021_LF_CLOCK_INTERNAL_RC (0x00UL << 0) // 7 0 low-frequency source: internal 32 kHz RC oscillator +#define RADIOLIB_LR2021_LF_CLOCK_EXTERNAL (0x02UL << 0) // 7 0 external 32.768 kHz signal on DIO11 + +// RADIOLIB_LR2021_CMD_SET_RX_PATH +#define RADIOLIB_LR2021_RX_PATH_LF (0x00UL << 0) // 7 0 Rx path: low-frequency +#define RADIOLIB_LR2021_RX_PATH_HF (0x01UL << 0) // 7 0 high-frequency + +// RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION +#define RADIOLIB_LR2021_RSSI_PATH_LF (0x01UL << 0) // 0 0 Rx path for RSSI: low-frequency +#define RADIOLIB_LR2021_RSSI_PATH_HF (0x01UL << 1) // 1 1 high-frequency +#define RADIOLIB_LR2021_GAIN_TABLE_LENGTH (27) + +// RADIOLIB_LR2021_CMD_SET_TIMESTAMP_SOURCE +#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_NONE (0x00UL << 0) // 3 0 timestamp source: none +#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_TX_DONE (0x01UL << 0) // 3 0 Tx done +#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_RX_DONE (0x02UL << 0) // 3 0 Rx done +#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_SYNC (0x03UL << 0) // 3 0 sync +#define RADIOLIB_LR2021_TIMESTAMP_SOURCE_HEADER (0x04UL << 0) // 3 0 LoRa header + +// RADIOLIB_LR2021_CMD_SET_CAD_PARAMS +#define RADIOLIB_LR2021_CAD_EXIT_MODE_FALLBACK (0x00UL << 0) // 1 0 CAD exit mode: the configured fallback mode +#define RADIOLIB_LR2021_CAD_EXIT_MODE_TX (0x01UL << 0) // 1 0 Tx +#define RADIOLIB_LR2021_CAD_EXIT_MODE_RX (0x02UL << 0) // 1 0 Rx + +// RADIOLIB_LR2021_CMD_SEL_PA +#define RADIOLIB_LR2021_PA_LOW_POWER (0x00UL << 0) // 1 0 PA to use: low-power +#define RADIOLIB_LR2021_PA_HIGH_POWER (0x01UL << 0) // 1 0 high-power + +// RADIOLIB_LR2021_CMD_SET_PA_CONFIG +#define RADIOLIB_LR2021_PA_LF_MODE_FSM (0x00UL << 0) // 1 0 PA LF mode: full single-ended mode +#define RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED (0x06UL << 4) // 7 4 PA LF duty cycle: PA not used +#define RADIOLIB_LR2021_PA_LF_SLICES_UNUSED (0x07UL << 0) // 3 0 PA LF slices: PA not used +#define RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED (0x10UL << 0) // 4 0 PA HF duty cycle: PA not used + +// RADIOLIB_LR2021_CMD_SET_TX_PARAMS +#define RADIOLIB_LR2021_RAMP_TIME_2_US (0x00UL << 0) // 7 0 PA ramp time: 2 us +#define RADIOLIB_LR2021_RAMP_TIME_4_US (0x01UL << 0) // 7 0 4 us +#define RADIOLIB_LR2021_RAMP_TIME_8_US (0x02UL << 0) // 7 0 8 us +#define RADIOLIB_LR2021_RAMP_TIME_16_US (0x03UL << 0) // 7 0 16 us +#define RADIOLIB_LR2021_RAMP_TIME_32_US (0x04UL << 0) // 7 0 32 us +#define RADIOLIB_LR2021_RAMP_TIME_48_US (0x05UL << 0) // 7 0 48 us +#define RADIOLIB_LR2021_RAMP_TIME_64_US (0x06UL << 0) // 7 0 64 us +#define RADIOLIB_LR2021_RAMP_TIME_80_US (0x07UL << 0) // 7 0 80 us +#define RADIOLIB_LR2021_RAMP_TIME_96_US (0x08UL << 0) // 7 0 96 us +#define RADIOLIB_LR2021_RAMP_TIME_112_US (0x09UL << 0) // 7 0 112 us +#define RADIOLIB_LR2021_RAMP_TIME_128_US (0x0AUL << 0) // 7 0 128 us +#define RADIOLIB_LR2021_RAMP_TIME_144_US (0x0BUL << 0) // 7 0 144 us +#define RADIOLIB_LR2021_RAMP_TIME_160_US (0x0CUL << 0) // 7 0 160 us +#define RADIOLIB_LR2021_RAMP_TIME_176_US (0x0DUL << 0) // 7 0 176 us +#define RADIOLIB_LR2021_RAMP_TIME_192_US (0x0EUL << 0) // 7 0 192 us +#define RADIOLIB_LR2021_RAMP_TIME_208_US (0x0FUL << 0) // 7 0 208 us +#define RADIOLIB_LR2021_RAMP_TIME_240_US (0x10UL << 0) // 7 0 240 us +#define RADIOLIB_LR2021_RAMP_TIME_272_US (0x11UL << 0) // 7 0 272 us +#define RADIOLIB_LR2021_RAMP_TIME_304_US (0x12UL << 0) // 7 0 304 us + +// RADIOLIB_LR2021_CMD_SET_PACKET_TYPE +#define RADIOLIB_LR2021_PACKET_TYPE_LORA (0x00UL << 0) // 7 0 packet type: LoRa +#define RADIOLIB_LR2021_PACKET_TYPE_FSK (0x02UL << 0) // 7 0 FSK +#define RADIOLIB_LR2021_PACKET_TYPE_BLE (0x03UL << 0) // 7 0 BLE +#define RADIOLIB_LR2021_PACKET_TYPE_RTTOF (0x04UL << 0) // 7 0 RTToF +#define RADIOLIB_LR2021_PACKET_TYPE_FLRC (0x05UL << 0) // 7 0 FLRC +#define RADIOLIB_LR2021_PACKET_TYPE_BPSK (0x06UL << 0) // 7 0 BPSK +#define RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS (0x07UL << 0) // 7 0 LR-FHSS +#define RADIOLIB_LR2021_PACKET_TYPE_WM_BUS (0x08UL << 0) // 7 0 WM-BUS +#define RADIOLIB_LR2021_PACKET_TYPE_WI_SUN (0x09UL << 0) // 7 0 WI-SUN +#define RADIOLIB_LR2021_PACKET_TYPE_OOK (0x0AUL << 0) // 7 0 OOK +#define RADIOLIB_LR2021_PACKET_TYPE_RAW (0x0BUL << 0) // 7 0 RAW +#define RADIOLIB_LR2021_PACKET_TYPE_Z_WAVE (0x0CUL << 0) // 7 0 Z-WAVE +#define RADIOLIB_LR2021_PACKET_TYPE_OQPSK (0x0DUL << 0) // 7 0 OQPSK #endif From ad88f1425cccc5052a88a261fac03725841c07d6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Oct 2025 20:19:38 +0100 Subject: [PATCH 1645/1848] [LR2021] Add LoRa commands --- src/modules/LR2021/LR2021.h | 21 ++++ src/modules/LR2021/LR2021_cmds_lora.cpp | 129 ++++++++++++++++++++++++ src/modules/LR2021/LR2021_commands.h | 45 +++++++++ src/modules/LR2021/LR2021_registers.h | 14 +++ 4 files changed, 209 insertions(+) create mode 100644 src/modules/LR2021/LR2021_cmds_lora.cpp create mode 100644 src/modules/LR2021/LR2021_registers.h diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 5dfc2874fe..b2d23e5d01 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -53,6 +53,11 @@ class LR2021: public PhysicalLayer, public LRxxxx { #endif Module* mod; + // cached LoRa parameters + bool ldroAuto = true; + uint8_t bandwidth = 0, spreadingFactor = 0, ldrOptimize = 0; + float bandwidthKhz = 0; + // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); int16_t writeRadioTxFifo(uint8_t* data, size_t len); @@ -115,6 +120,22 @@ class LR2021: public PhysicalLayer, public LRxxxx { // modem configuration commands int16_t setPacketType(uint8_t packetType); int16_t getPacketType(uint8_t* packetType); + + // LoRa commands + int16_t setLoRaModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); + int16_t setLoRaPacketParams(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ); + int16_t setLoRaSynchTimeout(uint8_t numSymbols, bool format); + int16_t setLoRaSyncword(uint16_t syncword); + int16_t setLoRaSideDetConfig(uint8_t* configs, size_t numSideDets); + int16_t setLoRaSideDetSyncword(uint8_t* syncwords, size_t numSideDets); + int16_t setLoRaCadParams(uint8_t numSymbols, bool preambleOnly, uint8_t pnrDelta, uint8_t cadExitMode, uint32_t timeout, uint8_t detPeak); + int16_t setLoRaCad(void); + int16_t getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint16_t* headerCrcError, uint16_t* falseSynch); + int16_t getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket); + int16_t setLoRaAddress(uint8_t addrLen, uint8_t addrPos, uint8_t* addr); + int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, uint32_t* freqHops, size_t numFreqHops); + int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum); + int16_t setLoRaSideDetCad(uint8_t* pnrDelta, uint8_t* detPeak, size_t numSideDets); }; #endif diff --git a/src/modules/LR2021/LR2021_cmds_lora.cpp b/src/modules/LR2021/LR2021_cmds_lora.cpp new file mode 100644 index 0000000000..cf92e9d551 --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_lora.cpp @@ -0,0 +1,129 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setLoRaModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { + // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled + if(this->ldroAuto) { + float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz; + if(symbolLength >= 16.0f) { + this->ldrOptimize = RADIOLIB_LR2021_LORA_LDRO_ENABLED; + } else { + this->ldrOptimize = RADIOLIB_LR2021_LORA_LDRO_DISABLED; + } + } else { + this->ldrOptimize = ldro; + } + + uint8_t buff[] = { (uint8_t)(((sf & 0x0F) << 4) | (bw & 0x0F)), (uint8_t)(((cr & 0x0F) << 4) | this->ldrOptimize) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaPacketParams(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ) { + uint8_t buff[] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), payloadLen, + (uint8_t)(((hdrType & 0x01) << 2) | ((crcType & 0x01) << 1) | (invertIQ & 0x01)), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaSynchTimeout(uint8_t numSymbols, bool format) { + uint8_t buff[] = { numSymbols, (uint8_t)format }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaSyncword(uint16_t syncword) { + uint8_t buff[] = { (uint8_t)((syncword >> 8) & 0xFF), (uint8_t)(syncword & 0xFF) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaSideDetConfig(uint8_t* configs, size_t numSideDets) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG, true, configs, numSideDets)); +} + +int16_t LR2021::setLoRaSideDetSyncword(uint8_t* syncwords, size_t numSideDets) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD, true, syncwords, numSideDets)); +} + +int16_t LR2021::setLoRaCadParams(uint8_t numSymbols, bool preambleOnly, uint8_t pnrDelta, uint8_t cadExitMode, uint32_t timeout, uint8_t detPeak) { + uint8_t buff[] = { + numSymbols, (uint8_t)(((uint8_t)preambleOnly << 4) | (pnrDelta & 0x0F)), cadExitMode, + (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF), + (uint8_t)(detPeak & 0x7F) + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaCad(void) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_CAD, true, NULL, 0)); +} + +int16_t LR2021::getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint16_t* headerCrcError, uint16_t* falseSynch) { + uint8_t buff[8] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS, false, buff, sizeof(buff)); + if(pktRxTotal) { *pktRxTotal = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(pktCrcError) { *pktCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(headerCrcError) { *headerCrcError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + if(falseSynch) { *falseSynch = ((uint16_t)(buff[7]) << 8) | (uint16_t)buff[6]; } + return(state); +} + +int16_t LR2021::getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket) { + uint8_t buff[9] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS, false, buff, sizeof(buff)); + uint16_t raw = 0; + if(crc) { *crc = (buff[0] & 0x10) >> 4; } + if(cr) { *cr = buff[0] & 0x0F; } + if(packetLen) { *packetLen = buff[1]; } + if(snrPacket) { *snrPacket = (float)((int8_t)buff[2]) / 4.0f; } + if(rssiPacket) { + raw = (uint16_t)buff[3] << 1; + *rssiPacket = (float)raw / -2.0f; + } + if(rssiSignalPacket) { + raw = (uint16_t)buff[4] << 1; + *rssiSignalPacket = (float)raw / -2.0f; + } + return(state); +} + +int16_t LR2021::setLoRaAddress(uint8_t addrLen, uint8_t addrPos, uint8_t* addr) { + if(addrLen > 8) { return(RADIOLIB_ERR_UNKNOWN); } + uint8_t buff[9] = { (uint8_t)(((addrLen & 0x0F) << 4) | (addrPos & 0x0F)) }; + memcpy(&buff[1], addr, addrLen); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, uint32_t* freqHops, size_t numFreqHops) { + if(numFreqHops > 40) { return(RADIOLIB_ERR_UNKNOWN); } + uint8_t buff[2 + 160] = { (uint8_t)(hopCtrl | ((hopPeriod & 0xF00) >> 8)), (uint8_t)(hopPeriod & 0xFF) }; + for(uint8_t i = 0; i < numFreqHops; i++) { + buff[i + 2] = (freqHops[i] >> 24) & 0xFF; + buff[i + 3] = (freqHops[i] >> 16) & 0xFF; + buff[i + 4] = (freqHops[i] >> 8) & 0xFF; + buff[i + 5] = freqHops[i] & 0xFF; + } + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_HOPPING, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaTxSync(uint8_t function, uint8_t dioNum) { + uint8_t buff[] = { (uint8_t)(function | (dioNum & 0x3F)) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC, true, buff, sizeof(buff))); +} + +int16_t LR2021::setLoRaSideDetCad(uint8_t* pnrDelta, uint8_t* detPeak, size_t numSideDets) { + uint8_t buff[6] = { 0 }; + for(uint8_t i = 0; i < numSideDets; i++) { + if(i >= 3) { return(RADIOLIB_ERR_UNKNOWN); } + buff[2*i] = pnrDelta[i] & 0x0F; + buff[2*i + 1] = detPeak[i] & 0x7F; + } + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC, true, buff, 2*numSideDets)); +} + +#endif diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 707bae5687..a5cc323d21 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -75,6 +75,7 @@ #define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CONFIG (0x0224) #define RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_SYNCWORD (0x0225) #define RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS (0x0227) +#define RADIOLIB_LR2021_CMD_SET_LORA_CAD (0x0228) #define RADIOLIB_LR2021_CMD_GET_LORA_RX_STATS (0x0229) #define RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS (0x022A) #define RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS (0x022B) @@ -355,6 +356,50 @@ #define RADIOLIB_LR2021_PACKET_TYPE_Z_WAVE (0x0CUL << 0) // 7 0 Z-WAVE #define RADIOLIB_LR2021_PACKET_TYPE_OQPSK (0x0DUL << 0) // 7 0 OQPSK +// RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS +#define RADIOLIB_LR2021_LORA_BW_31 (0x02UL << 0) // 3 0 LoRa bandwidth: 31.25 kHz +#define RADIOLIB_LR2021_LORA_BW_41 (0x0AUL << 0) // 3 0 41.67 kHz +#define RADIOLIB_LR2021_LORA_BW_83 (0x0BUL << 0) // 3 0 83.34 kHz +#define RADIOLIB_LR2021_LORA_BW_62 (0x03UL << 0) // 3 0 62.50 kHz +#define RADIOLIB_LR2021_LORA_BW_125 (0x04UL << 0) // 3 0 125 kHz +#define RADIOLIB_LR2021_LORA_BW_250 (0x05UL << 0) // 3 0 250 kHz +#define RADIOLIB_LR2021_LORA_BW_500 (0x06UL << 0) // 3 0 500 kHz +#define RADIOLIB_LR2021_LORA_BW_1000 (0x07UL << 0) // 3 0 1000 kHz +#define RADIOLIB_LR2021_LORA_BW_812 (0x0FUL << 0) // 3 0 812 kHz +#define RADIOLIB_LR2021_LORA_BW_406 (0x0EUL << 0) // 3 0 406 kHz +#define RADIOLIB_LR2021_LORA_BW_203 (0x0DUL << 0) // 3 0 203 kHz +#define RADIOLIB_LR2021_LORA_BW_101 (0x0CUL << 0) // 3 0 101 kHz +#define RADIOLIB_LR2021_LORA_CR_4_5 (0x01UL << 0) // 3 0 LoRa coding rate: 4/5 +#define RADIOLIB_LR2021_LORA_CR_4_6 (0x02UL << 0) // 3 0 4/6 +#define RADIOLIB_LR2021_LORA_CR_4_7 (0x03UL << 0) // 3 0 4/7 +#define RADIOLIB_LR2021_LORA_CR_4_8 (0x04UL << 0) // 3 0 4/8 +#define RADIOLIB_LR2021_LORA_CR_4_5_LI (0x05UL << 0) // 3 0 4/5 long interleaver +#define RADIOLIB_LR2021_LORA_CR_4_6_LI (0x06UL << 0) // 3 0 4/6 long interleaver +#define RADIOLIB_LR2021_LORA_CR_4_7_LI (0x07UL << 0) // 3 0 4/7 long interleaver +#define RADIOLIB_LR2021_LORA_LDRO_DISABLED (0x00UL << 0) // 1 0 LDRO/PPM configuration: disabled +#define RADIOLIB_LR2021_LORA_LDRO_ENABLED (0x01UL << 0) // 1 0 enabled + +// RADIOLIB_LR2021_CMD_SET_LORA_PACKET_PARAMS +#define RADIOLIB_LR2021_LORA_HEADER_EXPLICIT (0x00UL << 2) // 2 2 LoRa header mode: explicit +#define RADIOLIB_LR2021_LORA_HEADER_IMPLICIT (0x01UL << 2) // 2 2 implicit +#define RADIOLIB_LR2021_LORA_CRC_DISABLED (0x00UL << 1) // 1 1 LoRa CRC: disabled +#define RADIOLIB_LR2021_LORA_CRC_ENABLED (0x01UL << 1) // 1 1 enabled +#define RADIOLIB_LR2021_LORA_IQ_STANDARD (0x00UL << 0) // 0 0 LoRa IQ: standard +#define RADIOLIB_LR2021_LORA_IQ_INVERTED (0x01UL << 0) // 0 0 inverted + +// RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT +#define RADIOLIB_LR2021_LORA_SYNCH_TIMEOUT_FORMAT_SYMBOLS (0x00UL << 0) // 7 0 LoRa synch timeout format: number of symbols +#define RADIOLIB_LR2021_LORA_SYNCH_TIMEOUT_FORMAT_MANT_EXP (0x01UL << 0) // 7 0 mantissa-exponent + +// RADIOLIB_LR2021_CMD_SET_LORA_HOPPING +#define RADIOLIB_LR2021_LORA_HOPPING_DISABLED (0x00UL << 6) // 7 6 LoRa intra-packet hopping: disabled +#define RADIOLIB_LR2021_LORA_HOPPING_ENABLED (0x01UL << 6) // 7 6 enabled + +// RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC +#define RADIOLIB_LR2021_LORA_TX_SYNC_DISABLED (0x00UL << 6) // 7 6 Tx sync: disabled +#define RADIOLIB_LR2021_LORA_TX_SYNC_MASTER (0x01UL << 6) // 7 6 master (wait for signal to transmit sync frame) +#define RADIOLIB_LR2021_LORA_TX_SYNC_SLAVE (0x02UL << 6) // 7 6 slave (output signal on sync frame) + #endif #endif diff --git a/src/modules/LR2021/LR2021_registers.h b/src/modules/LR2021/LR2021_registers.h new file mode 100644 index 0000000000..8db1b1f3ee --- /dev/null +++ b/src/modules/LR2021/LR2021_registers.h @@ -0,0 +1,14 @@ +#if !defined(RADIOLIB_LR2021_REGISTERS_H) +#define RADIOLIB_LR2021_REGISTERS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR2021 + +// LR2021 SPI registers +#define RADIOLIB_LR2021_REG_LORA_MODEM_TXRX_CFG0 (0xF30A14) +#define RADIOLIB_LR2021_REG_LORA_MODEM_MAIN_TX_CFG1 (0xF30A24) + +#endif + +#endif From 494c6661674b9a96d143a4b0578fb0e40a08c513 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Oct 2025 19:05:34 +0100 Subject: [PATCH 1646/1848] [LR11x0] Split registers. commands and types into separate headers --- src/modules/LR11x0/LR11x0.h | 870 +------------------------- src/modules/LR11x0/LR11x0_commands.h | 640 +++++++++++++++++++ src/modules/LR11x0/LR11x0_registers.h | 30 + src/modules/LR11x0/LR11x0_types.h | 230 +++++++ 4 files changed, 904 insertions(+), 866 deletions(-) create mode 100644 src/modules/LR11x0/LR11x0_commands.h create mode 100644 src/modules/LR11x0/LR11x0_registers.h create mode 100644 src/modules/LR11x0/LR11x0_types.h diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index b3b6599d21..d0ff44f802 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -9,878 +9,16 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" +#include "LR11x0_commands.h" +#include "LR11x0_registers.h" +#include "LR11x0_types.h" + // LR11X0 physical layer properties #define RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE 1.0 #define RADIOLIB_LR11X0_MAX_PACKET_LENGTH 255 #define RADIOLIB_LR11X0_CRYSTAL_FREQ 32.0 #define RADIOLIB_LR11X0_DIV_EXPONENT 25 -// LR11X0 SPI commands -#define RADIOLIB_LR11X0_CMD_NOP (0x0000) -#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM (0x0105) -#define RADIOLIB_LR11X0_CMD_READ_REG_MEM (0x0106) -#define RADIOLIB_LR11X0_CMD_WRITE_BUFFER (0x0109) -#define RADIOLIB_LR11X0_CMD_READ_BUFFER (0x010A) -#define RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER (0x010B) -#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK (0x010C) -#define RADIOLIB_LR11X0_CMD_GET_STATUS (0x0100) -#define RADIOLIB_LR11X0_CMD_GET_VERSION (0x0101) -#define RADIOLIB_LR11X0_CMD_GET_ERRORS (0x010D) -#define RADIOLIB_LR11X0_CMD_CLEAR_ERRORS (0x010E) -#define RADIOLIB_LR11X0_CMD_CALIBRATE (0x010F) -#define RADIOLIB_LR11X0_CMD_SET_REG_MODE (0x0110) -#define RADIOLIB_LR11X0_CMD_CALIB_IMAGE (0x0111) -#define RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH (0x0112) -#define RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS (0x0113) -#define RADIOLIB_LR11X0_CMD_CLEAR_IRQ (0x0114) -#define RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK (0x0116) -#define RADIOLIB_LR11X0_CMD_SET_TCXO_MODE (0x0117) -#define RADIOLIB_LR11X0_CMD_REBOOT (0x0118) -#define RADIOLIB_LR11X0_CMD_GET_VBAT (0x0119) -#define RADIOLIB_LR11X0_CMD_GET_TEMP (0x011A) -#define RADIOLIB_LR11X0_CMD_SET_SLEEP (0x011B) -#define RADIOLIB_LR11X0_CMD_SET_STANDBY (0x011C) -#define RADIOLIB_LR11X0_CMD_SET_FS (0x011D) -#define RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER (0x0120) -#define RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE (0x0121) -#define RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE (0x0122) -#define RADIOLIB_LR11X0_CMD_READ_INFO_PAGE (0x0123) -#define RADIOLIB_LR11X0_CMD_GET_CHIP_EUI (0x0125) -#define RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI (0x0126) -#define RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN (0x0127) -#define RADIOLIB_LR11X0_CMD_ENABLE_SPI_CRC (0x0128) -#define RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE (0x012A) -#define RADIOLIB_LR11X0_CMD_RESET_STATS (0x0200) -#define RADIOLIB_LR11X0_CMD_GET_STATS (0x0201) -#define RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE (0x0202) -#define RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS (0x0203) -#define RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS (0x0204) -#define RADIOLIB_LR11X0_CMD_GET_RSSI_INST (0x0205) -#define RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD (0x0206) -#define RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK (0x0208) -#define RADIOLIB_LR11X0_CMD_SET_RX (0x0209) -#define RADIOLIB_LR11X0_CMD_SET_TX (0x020A) -#define RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY (0x020B) -#define RADIOLIB_LR11X0_CMD_AUTO_TX_RX (0x020C) -#define RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS (0x020D) -#define RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE (0x020E) -#define RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS (0x020F) -#define RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS (0x0210) -#define RADIOLIB_LR11X0_CMD_SET_TX_PARAMS (0x0211) -#define RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS (0x0212) -#define RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE (0x0213) -#define RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE (0x0214) -#define RADIOLIB_LR11X0_CMD_SET_PA_CONFIG (0x0215) -#define RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0217) -#define RADIOLIB_LR11X0_CMD_SET_CAD (0x0218) -#define RADIOLIB_LR11X0_CMD_SET_TX_CW (0x0219) -#define RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE (0x021A) -#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT (0x021B) -#define RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR (0x021C) -#define RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR (0x021D) -#define RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT (0x021E) -#define RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY (0x021F) -#define RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS (0x0224) -#define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225) -#define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227) -#define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228) -#define RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION (0x0229) -#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B) -#define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C) -#define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D) -#define RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON (0x022E) -#define RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS (0x0230) -#define RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND (0x0231) -#define RADIOLIB_LR11X0_CMD_WIFI_SCAN (0x0300) -#define RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT (0x0301) -#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE (0x0302) -#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT (0x0303) -#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS (0x0305) -#define RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS (0x0306) -#define RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS (0x0307) -#define RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS (0x0308) -#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS (0x0309) -#define RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS (0x030A) -#define RADIOLIB_LR11X0_CMD_WIFI_CFG_TIMESTAMP_AP_PHONE (0x030B) -#define RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION (0x0320) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI (0x0222) -#define RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE (0x0400) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE (0x0401) -#define RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE (0x0402) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE (0x0403) -#define RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE (0x0404) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE (0x0405) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION (0x0406) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS (0x0407) -#define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408) -#define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409) -#define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A) -#define RADIOLIB_LR11X0_CMD_GNSS_SCAN (0x040B) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D) -#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E) -#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE (0x040F) -#define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411) -#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414) -#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG (0x0415) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS (0x0416) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE (0x041A) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER (0x0420) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426) -#define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434) -#define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435) -#define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER (0x0438) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A) -#define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B) -#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x044D) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453) -#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0454) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS (0x0456) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457) -#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466) -#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC (0x0466) -#define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469) -#define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472) -#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502) -#define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503) -#define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504) -#define RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC (0x0505) -#define RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC (0x0506) -#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01 (0x0507) -#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT (0x0508) -#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT (0x0509) -#define RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH (0x050A) -#define RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH (0x050B) -#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM (0x050D) -#define RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM (0x050E) -#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE (0x050F) -#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT (0x0510) -#define RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH (0x8000) -#define RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED (0x8003) -#define RADIOLIB_LR11X0_CMD_BOOT_REBOOT (0x8005) -#define RADIOLIB_LR11X0_CMD_BOOT_GET_PIN (0x800B) -#define RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI (0x800C) -#define RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI (0x800D) - -// LR11X0 register map -#define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414) -#define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054) -#define RADIOLIB_LR11X0_REG_LNA_MODE (0x00F3008C) -// TODO add fix for br 600/1200 bps - -// LR11X0 SPI command variables - -// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION -#define RADIOLIB_LR11X0_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed -#define RADIOLIB_LR11X0_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error -#define RADIOLIB_LR11X0_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed -#define RADIOLIB_LR11X0_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted -#define RADIOLIB_LR11X0_STAT_1_IRQ_INACTIVE (0x00UL << 0) // 0 0 interrupt status: inactive -#define RADIOLIB_LR11X0_STAT_1_IRQ_ACTIVE (0x01UL << 0) // 0 0 at least 1 interrupt active -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_CLEARED (0x00UL << 4) // 7 4 reset status: cleared -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_ANALOG (0x01UL << 4) // 7 4 analog (power on, brown-out) -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_EXTERNAL (0x02UL << 4) // 7 4 NRESET pin -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_SYSTEM (0x03UL << 4) // 7 4 system -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WATCHDOG (0x04UL << 4) // 7 4 watchdog -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WAKEUP (0x05UL << 4) // 7 4 NSS toggling wake-up -#define RADIOLIB_LR11X0_STAT_2_CMD_RST_RTC (0x06UL << 4) // 7 4 realtime clock -#define RADIOLIB_LR11X0_STAT_2_MODE_SLEEP (0x00UL << 1) // 3 1 chip mode: sleep -#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_RC (0x01UL << 1) // 3 1 standby with RC oscillator -#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_OSC (0x02UL << 1) // 3 1 standby with external oscillator -#define RADIOLIB_LR11X0_STAT_2_MODE_FS (0x03UL << 1) // 3 1 frequency synthesis -#define RADIOLIB_LR11X0_STAT_2_MODE_RX (0x04UL << 1) // 3 1 receive -#define RADIOLIB_LR11X0_STAT_2_MODE_TX (0x05UL << 1) // 3 1 transmit -#define RADIOLIB_LR11X0_STAT_2_MODE_WIFI_GNSS (0x06UL << 1) // 3 1 WiFi or GNSS geolocation -#define RADIOLIB_LR11X0_STAT_2_BOOT (0x00UL << 0) // 0 0 code executed from: bootloader -#define RADIOLIB_LR11X0_STAT_2_FLASH (0x01UL << 0) // 0 0 flash - -// RADIOLIB_LR11X0_CMD_WRITE_REG_MEM -#define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes - -// RADIOLIB_LR11X0_CMD_GET_VERSION -#define RADIOLIB_LR11X0_DEVICE_LR1110 (0x01UL << 0) // 7 0 HW device: LR1110 -#define RADIOLIB_LR11X0_DEVICE_LR1120 (0x02UL << 0) // 7 0 LR1120 -#define RADIOLIB_LR11X0_DEVICE_LR1121 (0x03UL << 0) // 7 0 LR1121 -#define RADIOLIB_LR11X0_DEVICE_BOOT (0xDFUL << 0) // 7 0 bootloader mode - -// RADIOLIB_LR11X0_CMD_GET_ERRORS -#define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated -#define RADIOLIB_LR11X0_ERROR_STAT_HF_RC_CALIB_ERR (0x01UL << 1) // 15 0 high frequency RC not calibrated -#define RADIOLIB_LR11X0_ERROR_STAT_ADC_CALIB_ERR (0x01UL << 2) // 15 0 ADC not calibrated -#define RADIOLIB_LR11X0_ERROR_STAT_PLL_CALIB_ERR (0x01UL << 3) // 15 0 PLL not calibrated -#define RADIOLIB_LR11X0_ERROR_STAT_IMG_CALIB_ERR (0x01UL << 4) // 15 0 image rejection not calibrated -#define RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR (0x01UL << 5) // 15 0 high frequency oscillator failed to start -#define RADIOLIB_LR11X0_ERROR_STAT_LF_XOSC_START_ERR (0x01UL << 6) // 15 0 low frequency oscillator failed to start -#define RADIOLIB_LR11X0_ERROR_STAT_PLL_LOCK_ERR (0x01UL << 7) // 15 0 PLL failed to lock -#define RADIOLIB_LR11X0_ERROR_STAT_RX_ADC_OFFSET_ERR (0x01UL << 8) // 15 0 ADC offset not calibrated - -// RADIOLIB_LR11X0_CMD_CALIBRATE -#define RADIOLIB_LR11X0_CALIBRATE_PLL_TX (0x01UL << 5) // 5 5 calibrate: Tx PLL -#define RADIOLIB_LR11X0_CALIBRATE_IMG (0x01UL << 4) // 4 4 image rejection -#define RADIOLIB_LR11X0_CALIBRATE_ADC (0x01UL << 3) // 3 3 A/D converter -#define RADIOLIB_LR11X0_CALIBRATE_PLL (0x01UL << 2) // 2 2 PLL -#define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC -#define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC -#define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything -#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0f) - -// RADIOLIB_LR11X0_CMD_SET_REG_MODE -#define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes -#define RADIOLIB_LR11X0_REG_MODE_DC_DC (0x01UL << 0) // 0 0 DC-DC and LDO - -// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH -#define RADIOLIB_LR11X0_RFSW_DIO5_ENABLED (0x01UL << 0) // 4 0 RF switch: DIO5 enabled -#define RADIOLIB_LR11X0_RFSW_DIO5_DISABLED (0x00UL << 0) // 4 0 DIO5 disabled (default) -#define RADIOLIB_LR11X0_RFSW_DIO6_ENABLED (0x01UL << 1) // 4 0 RF switch: DIO6 enabled -#define RADIOLIB_LR11X0_RFSW_DIO6_DISABLED (0x00UL << 1) // 4 0 DIO6 disabled (default) -#define RADIOLIB_LR11X0_RFSW_DIO7_ENABLED (0x01UL << 2) // 4 0 RF switch: DIO7 enabled -#define RADIOLIB_LR11X0_RFSW_DIO7_DISABLED (0x00UL << 2) // 4 0 DIO7 disabled (default) -#define RADIOLIB_LR11X0_RFSW_DIO8_ENABLED (0x01UL << 3) // 4 0 RF switch: DIO8 enabled -#define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default) -#define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled -#define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default) -#define RADIOLIB_LR11X0_DIOx(X) ((X) | RFSWITCH_PIN_FLAG) -#define RADIOLIB_LR11X0_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG) -#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LR11X0_DIOx(0)) -#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LR11X0_DIOx(1)) -#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LR11X0_DIOx(2)) -#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LR11X0_DIOx(3)) -#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LR11X0_DIOx(4)) - -// RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted -#define RADIOLIB_LR11X0_IRQ_RX_DONE (0x01UL << 3) // 31 0 packet received -#define RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED (0x01UL << 4) // 31 0 preamble detected -#define RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID (0x01UL << 5) // 31 0 sync word or LoRa header valid -#define RADIOLIB_LR11X0_IRQ_HEADER_ERR (0x01UL << 6) // 31 0 LoRa header CRC error -#define RADIOLIB_LR11X0_IRQ_CRC_ERR (0x01UL << 7) // 31 0 packet CRC error -#define RADIOLIB_LR11X0_IRQ_CAD_DONE (0x01UL << 8) // 31 0 CAD completed -#define RADIOLIB_LR11X0_IRQ_CAD_DETECTED (0x01UL << 9) // 31 0 CAD detected -#define RADIOLIB_LR11X0_IRQ_TIMEOUT (0x01UL << 10) // 31 0 Rx or Tx timeout -#define RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP (0x01UL << 11) // 31 0 FHSS hop -#define RADIOLIB_LR11X0_IRQ_GNSS_DONE (0x01UL << 19) // 31 0 GNSS scan finished -#define RADIOLIB_LR11X0_IRQ_WIFI_DONE (0x01UL << 20) // 31 0 WiFi scan finished -#define RADIOLIB_LR11X0_IRQ_LBD (0x01UL << 21) // 31 0 low battery detected -#define RADIOLIB_LR11X0_IRQ_CMD_ERROR (0x01UL << 22) // 31 0 command error -#define RADIOLIB_LR11X0_IRQ_ERROR (0x01UL << 23) // 31 0 some other error than CMD_ERR -#define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error -#define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error -#define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source) -#define RADIOLIB_LR11X0_IRQ_GNSS_ABORT (0x01UL << 28) // 31 0 GNSS scan aborted -#define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts -#define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts - -// RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK -#define RADIOLIB_LR11X0_LF_CLK_RC (0x00UL << 0) // 1 0 32.768 kHz source: RC oscillator -#define RADIOLIB_LR11X0_LF_CLK_XOSC (0x01UL << 0) // 1 0 crystal oscillator -#define RADIOLIB_LR11X0_LF_CLK_EXT (0x02UL << 0) // 1 0 external signal on DIO11 -#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED (0x00UL << 2) // 2 2 -#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED (0x01UL << 2) // 2 2 - -// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V - -// RADIOLIB_LR11X0_CMD_SET_SLEEP -#define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled -#define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled -#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 0) // 1 1 automated wakeup: disabled -#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 0) // 1 1 enabled - -// RADIOLIB_LR11X0_CMD_SET_STANDBY -#define RADIOLIB_LR11X0_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator -#define RADIOLIB_LR11X0_STANDBY_XOSC (0x00UL << 0) // 7 0 XTAL/TCXO oscillator - -// RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE -#define RADIOLIB_LR11X0_INFO_PAGE (1) - -// RADIOLIB_LR11X0_CMD_GET_CHIP_EUI -#define RADIOLIB_LR11X0_EUI_LEN (8) - -// RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN -#define RADIOLIB_LR11X0_PIN_LEN (4) - -// RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS -#define RADIOLIB_LR11X0_RX_STATUS_ADDR_ERR (0x01UL << 5) // 7 0 Rx status: address filtering error -#define RADIOLIB_LR11X0_RX_STATUS_CRC_ERR (0x01UL << 4) // 7 0 CRC error -#define RADIOLIB_LR11X0_RX_STATUS_LEN_ERR (0x01UL << 3) // 7 0 length filtering error -#define RADIOLIB_LR11X0_RX_STATUS_ABORTED (0x01UL << 2) // 7 0 packet reception aborted -#define RADIOLIB_LR11X0_RX_STATUS_PACKET_RECEIVED (0x01UL << 1) // 7 0 packet received -#define RADIOLIB_LR11X0_RX_STATUS_PACKET_SENT (0x01UL << 0) // 7 0 packet sent - -// RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD -#define RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN (8) - -// RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK -#define RADIOLIB_LR11X0_LORA_PRIVATE_NETWORK (0x00UL << 0) // 7 0 LoRa sync word: private network -#define RADIOLIB_LR11X0_LORA_PUBLIC_NETWORK (0x01UL << 0) // 7 0 public network - -// RADIOLIB_LR11X0_CMD_SET_RX -#define RADIOLIB_LR11X0_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode) -#define RADIOLIB_LR11X0_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode) - -// RADIOLIB_LR11X0_CMD_SET_TX -#define RADIOLIB_LR11X0_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout - -// RADIOLIB_LR11X0_CMD_AUTO_TX_RX -#define RADIOLIB_LR11X0_AUTO_TX_RX_DISABLED (0xFFFFFFUL) // 23 0 disable auto Tx/Rx mode -#define RADIOLIB_LR11X0_AUTO_TX_RX_SKIP_INT (0x000000UL) // 23 0 skip intermediary mode -#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_SLEEP (0x00UL << 0) // 1 0 intermediary mode: sleep -#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_RC (0x01UL << 0) // 1 0 standby with RC -#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC -#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis -#define RADIOLIB_LR11X0_AUTO_TX_RX_TIMEOUT_DISABLED (0x000000UL) // 23 0 disable timeout of the second mode - -// RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS -#define RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC (0x00UL << 0) // 7 0 mode to set after CAD: standby with RC -#define RADIOLIB_LR11X0_CAD_EXIT_MODE_RX (0x01UL << 0) // 7 0 receive if activity detected -#define RADIOLIB_LR11X0_CAD_EXIT_MODE_LBT (0x10UL << 0) // 7 0 transmit if no activity detected -#define RADIOLIB_LR11X0_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value - -// RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE -#define RADIOLIB_LR11X0_PACKET_TYPE_NONE (0x00UL << 0) // 2 0 packet type: none -#define RADIOLIB_LR11X0_PACKET_TYPE_GFSK (0x01UL << 0) // 2 0 (G)FSK -#define RADIOLIB_LR11X0_PACKET_TYPE_LORA (0x02UL << 0) // 2 0 LoRa -#define RADIOLIB_LR11X0_PACKET_TYPE_SIGFOX (0x03UL << 0) // 2 0 Sigfox -#define RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS (0x04UL << 0) // 2 0 GMSK/LR-FHSS -#define RADIOLIB_LR11X0_PACKET_TYPE_RANGING (0x05UL << 0) // 2 0 ranging -#define RADIOLIB_LR11X0_PACKET_TYPE_BLE (0x06UL << 0) // 2 0 BLE beacon - -// RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS -#define RADIOLIB_LR11X0_LORA_BW_62_5 (0x03UL << 0) // 7 0 LoRa bandwidth: 62.5 kHz -#define RADIOLIB_LR11X0_LORA_BW_125_0 (0x04UL << 0) // 7 0 125.0 kHz -#define RADIOLIB_LR11X0_LORA_BW_250_0 (0x05UL << 0) // 7 0 250.0 kHz -#define RADIOLIB_LR11X0_LORA_BW_500_0 (0x06UL << 0) // 7 0 500.0 kHz -#define RADIOLIB_LR11X0_LORA_BW_203_125 (0x0DUL << 0) // 7 0 203.0 kHz (2.4GHz only) -#define RADIOLIB_LR11X0_LORA_BW_406_25 (0x0EUL << 0) // 7 0 406.0 kHz (2.4GHz only) -#define RADIOLIB_LR11X0_LORA_BW_812_50 (0x0FUL << 0) // 7 0 812.0 kHz (2.4GHz only) -#define RADIOLIB_LR11X0_LORA_CR_4_5_SHORT (0x01UL << 0) // 7 0 coding rate: 4/5 with short interleaver -#define RADIOLIB_LR11X0_LORA_CR_4_6_SHORT (0x02UL << 0) // 7 0 4/6 with short interleaver -#define RADIOLIB_LR11X0_LORA_CR_4_7_SHORT (0x03UL << 0) // 7 0 4/7 with short interleaver -#define RADIOLIB_LR11X0_LORA_CR_4_8_SHORT (0x04UL << 0) // 7 0 4/8 with short interleaver -#define RADIOLIB_LR11X0_LORA_CR_4_5_LONG (0x05UL << 0) // 7 0 4/5 with long interleaver -#define RADIOLIB_LR11X0_LORA_CR_4_6_LONG (0x06UL << 0) // 7 0 4/6 with long interleaver -#define RADIOLIB_LR11X0_LORA_CR_4_8_LONG (0x07UL << 0) // 7 0 4/8 with long interleaver -#define RADIOLIB_LR11X0_LORA_LDRO_DISABLED (0x00UL << 0) // 7 0 low data rate optimize: disabled -#define RADIOLIB_LR11X0_LORA_LDRO_ENABLED (0x01UL << 0) // 7 0 enabled -#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_DISABLED (0x00UL << 31) // 31 0 divide bit rate value by 256: disabled -#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_ENABLED (0x01UL << 31) // 31 0 enabled -#define RADIOLIB_LR11X0_GFSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none -#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3 (0x08UL << 0) // 7 0 Gaussian, BT = 0.3 -#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5 (0x09UL << 0) // 7 0 Gaussian, BT = 0.5 -#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7 (0x0AUL << 0) // 7 0 Gaussian, BT = 0.7 -#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 Gaussian, BT = 1.0 -#define RADIOLIB_LR11X0_GFSK_SHAPING_RAISED_COSINE_BT_0_7 (0x16UL << 0) // 7 0 raised cosine, BT = 0.7 -#define RADIOLIB_LR11X0_GFSK_RX_BW_4_8 (0x1FUL << 0) // 7 0 GFSK Rx bandwidth: 4.8 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_5_8 (0x17UL << 0) // 7 0 5.8 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_7_3 (0x0FUL << 0) // 7 0 7.3 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_9_7 (0x1EUL << 0) // 7 0 9.7 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_11_7 (0x16UL << 0) // 7 0 11.7 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_14_6 (0x0EUL << 0) // 7 0 14.6 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_19_5 (0x1DUL << 0) // 7 0 19.5 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_23_4 (0x15UL << 0) // 7 0 23.4 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_29_3 (0x0DUL << 0) // 7 0 29.3 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_39_0 (0x1CUL << 0) // 7 0 39.0 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_46_9 (0x14UL << 0) // 7 0 46.9 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_58_6 (0x0CUL << 0) // 7 0 58.6 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_78_2 (0x1BUL << 0) // 7 0 78.2 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_93_8 (0x13UL << 0) // 7 0 93.8 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_117_3 (0x0BUL << 0) // 7 0 117.3 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_156_2 (0x1AUL << 0) // 7 0 156.2 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_187_2 (0x12UL << 0) // 7 0 187.2 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_234_3 (0x0AUL << 0) // 7 0 234.3 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz -#define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps -#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw -#define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0 -#define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7 - -// RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS -#define RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit -#define RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit -#define RADIOLIB_LR11X0_LORA_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length -#define RADIOLIB_LR11X0_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled -#define RADIOLIB_LR11X0_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled -#define RADIOLIB_LR11X0_LORA_IQ_STANDARD (0x00UL << 0) // 7 0 IQ setup: standard -#define RADIOLIB_LR11X0_LORA_IQ_INVERTED (0x01UL << 0) // 7 0 inverted -#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED (0x00UL << 0) // 7 0 preamble detector: disabled -#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS (0x04UL << 0) // 7 0 8 bits -#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS (0x05UL << 0) // 7 0 16 bits -#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS (0x06UL << 0) // 7 0 24 bits -#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS (0x07UL << 0) // 7 0 32 bits -#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled -#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE (0x01UL << 0) // 7 0 node address -#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast address -#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED (0x00UL << 0) // 7 0 packet length: fixed -#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE (0x01UL << 0) // 7 0 variable -#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE_SX128X (0x02UL << 0) // 7 0 variable, SX128x 9-bit length encoding -#define RADIOLIB_LR11X0_GFSK_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length -#define RADIOLIB_LR11X0_GFSK_CRC_DISABLED (0x01UL << 0) // 7 0 CRC: disabled -#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE (0x00UL << 0) // 7 0 1-byte -#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE (0x02UL << 0) // 7 0 2-byte -#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV (0x04UL << 0) // 7 0 1-byte, inverted -#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV (0x06UL << 0) // 7 0 2-byte, inverted -#define RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED (0x00UL << 0) // 7 0 whitening: disabled -#define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled - -// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS -#define RADIOLIB_LR11X0_PA_RAMP_16U (0x00UL << 0) // 7 0 PA ramp time: 16 us -#define RADIOLIB_LR11X0_PA_RAMP_32U (0x01UL << 0) // 7 0 32 us -#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 48 us -#define RADIOLIB_LR11X0_PA_RAMP_64U (0x03UL << 0) // 7 0 64 us -#define RADIOLIB_LR11X0_PA_RAMP_80U (0x04UL << 0) // 7 0 80 us -#define RADIOLIB_LR11X0_PA_RAMP_96U (0x05UL << 0) // 7 0 96 us -#define RADIOLIB_LR11X0_PA_RAMP_112U (0x06UL << 0) // 7 0 112 us -#define RADIOLIB_LR11X0_PA_RAMP_128U (0x07UL << 0) // 7 0 128 us -#define RADIOLIB_LR11X0_PA_RAMP_144U (0x08UL << 0) // 7 0 144 us -#define RADIOLIB_LR11X0_PA_RAMP_160U (0x09UL << 0) // 7 0 160 us -#define RADIOLIB_LR11X0_PA_RAMP_176U (0x0AUL << 0) // 7 0 176 us -#define RADIOLIB_LR11X0_PA_RAMP_192U (0x0BUL << 0) // 7 0 192 us -#define RADIOLIB_LR11X0_PA_RAMP_208U (0x0CUL << 0) // 7 0 208 us -#define RADIOLIB_LR11X0_PA_RAMP_240U (0x0DUL << 0) // 7 0 240 us -#define RADIOLIB_LR11X0_PA_RAMP_272U (0x0EUL << 0) // 7 0 272 us -#define RADIOLIB_LR11X0_PA_RAMP_304U (0x0FUL << 0) // 7 0 304 us - -// RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE -#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC -#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC -#define RADIOLIB_LR11X0_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis - -// RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE -#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default) -#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD -#define RADIOLIB_LR11X0_TIMING_STEP (1.0f/32768.0f) // 23 0 timing step fo delays - -// RADIOLIB_LR11X0_CMD_SET_PA_CONFIG -#define RADIOLIB_LR11X0_PA_SEL_LP (0x00UL << 0) // 7 0 PA select: low power PA -#define RADIOLIB_LR11X0_PA_SEL_HP (0x01UL << 0) // 7 0 high power PA -#define RADIOLIB_LR11X0_PA_SEL_HF (0x02UL << 0) // 7 0 high frequency PA -#define RADIOLIB_LR11X0_PA_SUPPLY_INTERNAL (0x00UL << 0) // 7 0 PA power source: internal -#define RADIOLIB_LR11X0_PA_SUPPLY_VBAT (0x01UL << 0) // 7 0 VBAT (required for >= 14 dBm) - -// RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE -#define RADIOLIB_LR11X0_STOP_ON_SYNC_HEADER (0x00UL << 0) // 0 0 stop timeout on: sync word or header (default) -#define RADIOLIB_LR11X0_STOP_ON_PREAMBLE (0x01UL << 0) // 0 0 preamble - -// RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT -#define RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE (0) // 7 0 ranging result type: distance -#define RADIOLIB_LR11X0_RANGING_RESULT_RSSI (1) // 7 0 RSSI - -// RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED -#define RADIOLIB_LR11X0_RX_BOOSTED_ENABLED (0x01UL << 0) // 0 0 Rx boosted mode: enabled -#define RADIOLIB_LR11X0_RX_BOOSTED_DISABLED (0x00UL << 0) // 0 0 disabled - -// RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD -#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12) -#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PUBLIC (0x34) - -// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME -#define RADIOLIB_LR11X0_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 -#define RADIOLIB_LR11X0_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 -#define RADIOLIB_LR11X0_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 -#define RADIOLIB_LR11X0_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 -#define RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK -#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) -#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) -#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled -#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled -#define RADIOLIB_LR11X0_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz -#define RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header -#define RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment -#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble -#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS (RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS + RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS) - -// RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS -#define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled -#define RADIOLIB_LR11X0_LAST_HEADER_CRC_DISABLED (0x00UL << 4) // 4 4 disabled - -// RADIOLIB_LR11X0_CMD_WIFI_SCAN -#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_B (0x01UL << 0) // 7 0 Wi-Fi type to scan: 802.11b -#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_G (0x02UL << 0) // 7 0 802.11g -#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_N (0x03UL << 0) // 7 0 802.11n -#define RADIOLIB_LR11X0_WIFI_SCAN_ALL (0x04UL << 0) // 7 0 all (802.11b first) -#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_ONLY (0x01UL << 0) // 7 0 Wi-Fi acquisition mode: beacon only -#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_PACKET (0x02UL << 0) // 7 0 beacon and packet -#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_TRAFFIC (0x03UL << 0) // 7 0 full traffic -#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON (0x04UL << 0) // 7 0 full beacon -#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon -#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled -#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled -#define RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS (32) // 7 0 maximum possible number of Wi-Fi scan results -#define RADIOLIB_LR11X0_WIFI_ALL_CHANNELS (0x3FFFUL) // 16 0 scan all channels - -// RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS -#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete -#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic -#define RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN (79) // 7 0 maximum possible Wi-Fi scan size -#define RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN (6) // 7 0 MAC address length in bytes -#define RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN (32) // 7 0 SSID length in bytes - -// RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE -#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS -#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU (0x01UL << 1) // 7 0 BeiDou - -// RADIOLIB_LR11X0_CMD_GNSS_SET_MODE -#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_SCAN (0x00UL << 0) // 7 0 GNSS scanning mode: single/legacy -#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_MULTIPLE (0x03UL << 1) // 7 0 multiple/advanced - -// RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS -#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_ENABLED (0x01UL << 0) // 0 0 GNSS results in NAV message: pseudo-range (in single scan mode) or Doppler information (in multiple scan mode) -#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_DISABLED (0x00UL << 0) // 0 0 not included -#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_ENABLED (0x01UL << 1) // 1 1 Doppler information -#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_DISABLED (0x00UL << 1) // 1 1 not included -#define RADIOLIB_LR11X0_GNSS_NB_SV_ALL (0x00UL << 0) // 7 0 include all detected satellites -#define RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE (0x00UL << 0) // 7 0 reserved, always 0 - -// RADIOLIB_LR11X0_CMD_GNSS_ASSISTED -#define RADIOLIB_LR11X0_GNSS_ASSIST_LOW_POWER (0x00UL << 0) // 7 0 effort mode: low power -#define RADIOLIB_LR11X0_GNSS_ASSIST_BEST_EFFORT (0x01UL << 0) // 7 0 best effort - -// RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS -#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_NONE (0x00UL << 0) // 7 4 error code: none -#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_OLD (0x01UL << 0) // 7 4 almanac too old -#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_CRC (0x02UL << 0) // 7 4 almanac CRC mismatch -#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error -#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed -#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz -#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 Hz -#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz -#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz - -// RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE -#define RADIOLIB_LR11X0_SV_CONSTELLATION_GPS (0x00UL << 0) // 7 0 GNSS constellation: GPS -#define RADIOLIB_LR11X0_SV_CONSTELLATION_BEIDOU (0x01UL << 0) // 7 0 BeiDou - -// RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE -#define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header -#define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20) - -// RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME -#define RADIOLIB_LR11X0_GNSS_EFFORT_LOW (0x00UL << 0) // 7 0 GNSS effort mode: low sensitivity -#define RADIOLIB_LR11X0_GNSS_EFFORT_MID (0x01UL << 0) // 7 0 medium sensitivity -#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW (0x00UL << 0) // 7 0 time fetch options: ToW only, requires WN to demodulated beforehand -#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN (0x01UL << 0) // 7 0 ToW and WN -#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN_ROLL (0x02UL << 0) // 7 0 ToW, WN and rollover - -// RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NOT_POSSIBLE (-21) // 7 0 GNSS demodulation status: not possible to demodulate -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SAT_LOST (-20) // 7 0 satellite lost -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALMANAC_DEMOD_ERROR (-19) // 7 0 almanac demodulation error -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOO_LATE (-18) // 7 0 woke up after preamble (demodulation started too late) -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_20_MS_FAIL (-17) // 7 0 20ms real-time clock failed -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WAKE_UP_FAIL (-16) // 7 0 wake up sync failed -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_INVALID (-15) // 7 0 week number not validated -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_ACTIVE_SAT (-14) // 7 0 no active satellite selected in satellite list -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SLEEP_TOO_LONG (-13) // 7 0 sleep time too long -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_INVALID (-12) // 7 0 wrong time-of-week demodulated -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PREAMBLE_INVALID (-11) // 7 0 preamble not validated -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_DISABLED (-10) // 7 0 demodulator disabled -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_EXTR_FAILED (-9) // 7 0 demodulator extraction failed -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE (-8) // 7 0 no bit change found during demodulation start -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE_ADV (-7) // 7 0 no bit change found during advanced scan -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_SAT_FOUND (-6) // 7 0 no satellites found -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SYNC_LOST (-5) // 7 0 word sync lost -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_NOT_ENOUGH (-3) // 7 0 parity check fail (not enough) -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_TOO_MANY (-2) // 7 0 parity check fail (too many) -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_PARITY (-1) // 7 0 parity check fail (no parity found) -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_NONE (0) // 7 0 word sync search not started -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_POT (1) // 7 0 potential word sync found -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_OK (2) // 7 0 word sync found -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND (3) // 7 0 time-of-week found -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_FOUND (4) // 7 0 week number and time-of-week found -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALM_FOUND_UNSAVED (5) // 7 0 almanac found but not saved -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_HALF_ALM_SAVED (6) // 7 0 half of almanac found and saved -#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_FULL_ALM_SAVED (7) // 7 0 full almanac found and saved -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WORD_SYNC_FOUND (0x01UL << 0) // 7 0 GNSS demodulation info: word synchronization found -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_TOW_FOUND (0x01UL << 1) // 7 0 time-of-week found -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_DEMODED (0x01UL << 2) // 7 0 week number demodulated -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_FOUND (0x01UL << 3) // 7 0 week number found -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_1_FOUND (0x01UL << 4) // 7 0 subframe 1 found -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_4_FOUND (0x01UL << 5) // 7 0 subframe 4 found -#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_5_FOUND (0x01UL << 6) // 7 0 subframe 5 found - -// RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS -#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE (0) // 7 0 GPS/BeiDou almanac status: all satellites up-to-date -#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_OUTDATED (1) // 7 0 at least one satellite needs update - -// RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NONE (0) // 7 0 internal 2D solver error: no error -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_RES_HIGH (1) // 7 0 residue too high -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_CONVERGED (2) // 7 0 not converged on solution -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_ENOUGH_SV (3) // 7 0 not enough satellites -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ILL_MATRIX (4) // 7 0 matrix error (?) -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_TIME (5) // 7 0 time error -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_PART_OLD (6) // 7 0 part of almanac too old or not available -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_INCONSISTENT (7) // 7 0 not consistent with history (?) -#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_OLD (8) // 7 0 all of almanac too old - -// RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY -#define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success -#define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed -#define RADIOLIB_LR11X0_CRYPTO_STATUS_INV_KEY_ID (0x03UL << 0) // 7 0 key/parameter source or destination ID error -#define RADIOLIB_LR11X0_CRYPTO_STATUS_BUF_SIZE (0x05UL << 0) // 7 0 data buffer size invalid -#define RADIOLIB_LR11X0_CRYPTO_STATUS_ERROR (0x06UL << 0) // 7 0 generic error - -// RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT -#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_0 (0x00UL << 0) // 7 0 LoRaWAN version: 1.0.x -#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_1 (0x01UL << 0) // 7 0 1.1 - -// LR11X0 SPI register variables - -// RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT -#define RADIOLIB_LR11X0_SF6_SX126X (0x00UL << 18) // 18 18 SF6 mode: SX126x series -#define RADIOLIB_LR11X0_SF6_SX127X (0x01UL << 18) // 18 18 SX127x series - -// RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX -#define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata - -// RADIOLIB_LR11X0_REG_LNA_MODE -#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_N (0x01UL << 4) // 7 4 LNA mode: single-ended RFI_N -#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_P (0x02UL << 4) // 7 4 single-ended RFI_P -#define RADIOLIB_LR11X0_LNA_MODE_DIFFERENTIAL (0x03UL << 4) // 7 4 differential (default) - -/*! - \struct LR11x0WifiResult_t - \brief Structure to save result of passive WiFi scan. - This result only saves the basic information. -*/ -struct LR11x0WifiResult_t { - /*! \brief WiFi (802.11) signal type, 'b', 'n' or 'g' */ - char type; - - /*! \brief Data rate ID holding information about modulation and coding rate. See LR11x0 user manual for details. */ - uint8_t dataRateId; - - /*! \brief Channel frequency in MHz */ - uint16_t channelFreq; - - /*! \brief MAC address origin: from gateway (1), phone (2) or undetermined (3) */ - uint8_t origin; - - /*! \brief Whether this signal was sent by an access point (true) or end device (false) */ - bool ap; - - /*! \brief RSSI in dBm */ - float rssi; - - /*! \brief MAC address */ - uint8_t mac[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; -}; - -/*! - \struct LR11x0WifiResultFull_t - \brief Structure to save result of passive WiFi scan. - This result saves additional information alongside that in LR11x0WifiResult_t. -*/ -struct LR11x0WifiResultFull_t: public LR11x0WifiResult_t { - /*! \brief Frame type. See LR11x0 user manual for details. */ - uint8_t frameType; - - /*! \brief Frame sub type. See LR11x0 user manual for details. */ - uint8_t frameSubType; - - /*! \brief Frame sent from client station to distribution system. */ - bool toDistributionSystem; - - /*! \brief Frame sent from distribution system to client station. */ - bool fromDistributionSystem; - - /*! \brief See LR11x0 user manual for details. */ - uint16_t phiOffset; - - /*! \brief Number of microseconds the AP has been active. */ - uint64_t timestamp; - - /*! \brief Beacon period in microseconds. */ - uint32_t periodBeacon; -}; - -/*! - \struct LR11x0WifiResultExtended_t - \brief Structure to save result of passive WiFi scan. - This result saves additional information alongside that in LR11x0WifiResultFull_t. - Only scans performed with RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON acquisition mode - can yield this result! -*/ -struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t { - /*! \brief Data rate. See LR11x0 user manual for details. */ - uint8_t rate; - - /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ - uint16_t service; - - /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ - uint16_t length; - - /*! \brief MAC address 0 */ - uint8_t mac0[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; - - /*! \brief MAC address 2 */ - uint8_t mac2[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; - - /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ - uint16_t seqCtrl; - - /*! \brief SSID */ - uint8_t ssid[RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN]; - - /*! \brief WiFi channel number */ - uint8_t currentChannel; - - /*! \brief Two-letter country code (null-terminated string). */ - char countryCode[3]; - - /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ - uint8_t ioReg; - - /*! \brief True if frame check sequences is valid, false otherwise. */ - bool fcsCheckOk; -}; - -/*! - \struct LR11x0VersionInfo_t - \brief Structure to report information about versions of the LR11x0 hardware and firmware. -*/ -struct LR11x0VersionInfo_t { - /*! \brief Hardware revision. */ - uint8_t hardware; - - /*! \brief Which device this is - one of RADIOLIB_LR11X0_DEVICE_* macros. */ - uint8_t device; - - /*! \brief Major revision of the base firmware. */ - uint8_t fwMajor; - - /*! \brief Minor revision of the base firmware. */ - uint8_t fwMinor; - - /*! \brief Major revision of the WiFi firmware. */ - uint8_t fwMajorWiFi; - - /*! \brief Minor revision of the WiFi firmware. */ - uint8_t fwMinorWiFi; - - /*! \brief Revision of the GNSS firmware. */ - uint8_t fwGNSS; - - /*! \brief Almanac revision of the GNSS firmware. */ - uint8_t almanacGNSS; -}; - -/*! - \struct LR11x0GnssResult_t - \brief Structure to report information results of a GNSS scan. -*/ -struct LR11x0GnssResult_t { - /*! \brief Demodulator status. One of RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_* */ - int8_t demodStat; - - /*! \brief Number of satellites detected during the scan. */ - uint8_t numSatsDet; - - /*! \brief Result size, used when passing data to LoRa cloud. */ - uint16_t resSize; -}; - -/*! - \struct LR11x0GnssPosition_t - \brief Structure to report position from LR11x0 internal solver. -*/ -struct LR11x0GnssPosition_t { - /*! \brief Latitude in degrees. */ - float latitude; - - /*! \brief Longitude in degrees. */ - float longitude; - - /*! \brief Accuracy of this result. */ - uint16_t accuracy; - - /*! \brief Number of satellites used to solve this position. */ - uint8_t numSatsUsed; -}; - -/*! - \struct LR11x0GnssSatellite_t - \brief Structure to save information about a satellite found during GNSS scan. -*/ -struct LR11x0GnssSatellite_t { - /*! \brief Satellite vehicle (SV) identifier. */ - uint8_t svId; - - /*! \brief C/N0 in dB. */ - uint8_t c_n0; - - /*! \brief Doppler shift of the signal in Hz. */ - int16_t doppler; -}; - -/*! - \struct LR11x0GnssAlmanacStatusPart_t - \brief Structure to save information about one constellation of the GNSS almanac. -*/ -struct LR11x0GnssAlmanacStatusPart_t { - int8_t status; - uint32_t timeUntilSubframe; - uint8_t numSubframes; - uint8_t nextSubframe4SvId; - uint8_t nextSubframe5SvId; - uint8_t nextSubframeStart; - uint8_t numUpdateNeeded; - uint32_t flagsUpdateNeeded[2]; - uint32_t flagsActive[2]; -}; - -/*! - \struct LR11x0GnssAlmanacStatus_t - \brief Structure to save information about the GNSS almanac. - This is not the actual almanac, just some context information about it. -*/ -struct LR11x0GnssAlmanacStatus_t { - /*! \brief GPS part of the almanac */ - LR11x0GnssAlmanacStatusPart_t gps; - - /*! \brief BeiDou part of the almanac */ - LR11x0GnssAlmanacStatusPart_t beidou; - - /*! \brief Extra flags present for BeiDou only */ - uint32_t beidouSvNoAlmanacFlags[2]; - - /*! \brief Next almanac ID */ - uint8_t nextAlmanacId; - - /*! \brief Timestamp of when almanac status was retrieved - timeUntilSubframe is relative to this value. */ - RadioLibTime_t start; -}; - /*! \class LR11x0 \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h new file mode 100644 index 0000000000..ff3e26a903 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -0,0 +1,640 @@ +#if !defined(RADIOLIB_LR11X0_COMMANDS_H) +#define RADIOLIB_LR11X0_COMMANDS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +// LR11X0 SPI commands +#define RADIOLIB_LR11X0_CMD_NOP (0x0000) +#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM (0x0105) +#define RADIOLIB_LR11X0_CMD_READ_REG_MEM (0x0106) +#define RADIOLIB_LR11X0_CMD_WRITE_BUFFER (0x0109) +#define RADIOLIB_LR11X0_CMD_READ_BUFFER (0x010A) +#define RADIOLIB_LR11X0_CMD_CLEAR_RX_BUFFER (0x010B) +#define RADIOLIB_LR11X0_CMD_WRITE_REG_MEM_MASK (0x010C) +#define RADIOLIB_LR11X0_CMD_GET_STATUS (0x0100) +#define RADIOLIB_LR11X0_CMD_GET_VERSION (0x0101) +#define RADIOLIB_LR11X0_CMD_GET_ERRORS (0x010D) +#define RADIOLIB_LR11X0_CMD_CLEAR_ERRORS (0x010E) +#define RADIOLIB_LR11X0_CMD_CALIBRATE (0x010F) +#define RADIOLIB_LR11X0_CMD_SET_REG_MODE (0x0110) +#define RADIOLIB_LR11X0_CMD_CALIB_IMAGE (0x0111) +#define RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH (0x0112) +#define RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS (0x0113) +#define RADIOLIB_LR11X0_CMD_CLEAR_IRQ (0x0114) +#define RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK (0x0116) +#define RADIOLIB_LR11X0_CMD_SET_TCXO_MODE (0x0117) +#define RADIOLIB_LR11X0_CMD_REBOOT (0x0118) +#define RADIOLIB_LR11X0_CMD_GET_VBAT (0x0119) +#define RADIOLIB_LR11X0_CMD_GET_TEMP (0x011A) +#define RADIOLIB_LR11X0_CMD_SET_SLEEP (0x011B) +#define RADIOLIB_LR11X0_CMD_SET_STANDBY (0x011C) +#define RADIOLIB_LR11X0_CMD_SET_FS (0x011D) +#define RADIOLIB_LR11X0_CMD_GET_RANDOM_NUMBER (0x0120) +#define RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE (0x0121) +#define RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE (0x0122) +#define RADIOLIB_LR11X0_CMD_READ_INFO_PAGE (0x0123) +#define RADIOLIB_LR11X0_CMD_GET_CHIP_EUI (0x0125) +#define RADIOLIB_LR11X0_CMD_GET_SEMTECH_JOIN_EUI (0x0126) +#define RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN (0x0127) +#define RADIOLIB_LR11X0_CMD_ENABLE_SPI_CRC (0x0128) +#define RADIOLIB_LR11X0_CMD_DRIVE_DIOS_IN_SLEEP_MODE (0x012A) +#define RADIOLIB_LR11X0_CMD_RESET_STATS (0x0200) +#define RADIOLIB_LR11X0_CMD_GET_STATS (0x0201) +#define RADIOLIB_LR11X0_CMD_GET_PACKET_TYPE (0x0202) +#define RADIOLIB_LR11X0_CMD_GET_RX_BUFFER_STATUS (0x0203) +#define RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS (0x0204) +#define RADIOLIB_LR11X0_CMD_GET_RSSI_INST (0x0205) +#define RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD (0x0206) +#define RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK (0x0208) +#define RADIOLIB_LR11X0_CMD_SET_RX (0x0209) +#define RADIOLIB_LR11X0_CMD_SET_TX (0x020A) +#define RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY (0x020B) +#define RADIOLIB_LR11X0_CMD_AUTO_TX_RX (0x020C) +#define RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS (0x020D) +#define RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE (0x020E) +#define RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS (0x020F) +#define RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS (0x0210) +#define RADIOLIB_LR11X0_CMD_SET_TX_PARAMS (0x0211) +#define RADIOLIB_LR11X0_CMD_SET_PACKET_ADRS (0x0212) +#define RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE (0x0213) +#define RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE (0x0214) +#define RADIOLIB_LR11X0_CMD_SET_PA_CONFIG (0x0215) +#define RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE (0x0217) +#define RADIOLIB_LR11X0_CMD_SET_CAD (0x0218) +#define RADIOLIB_LR11X0_CMD_SET_TX_CW (0x0219) +#define RADIOLIB_LR11X0_CMD_SET_TX_INFINITE_PREAMBLE (0x021A) +#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNCH_TIMEOUT (0x021B) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_ADDR (0x021C) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR (0x021D) +#define RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT (0x021E) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY (0x021F) +#define RADIOLIB_LR11X0_CMD_SET_GFSK_CRC_PARAMS (0x0224) +#define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225) +#define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227) +#define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228) +#define RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION (0x0229) +#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B) +#define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C) +#define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D) +#define RADIOLIB_LR11X0_CMD_CONFIG_BLE_BEACON (0x022E) +#define RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS (0x0230) +#define RADIOLIB_LR11X0_CMD_BLE_BEACON_SEND (0x0231) +#define RADIOLIB_LR11X0_CMD_WIFI_SCAN (0x0300) +#define RADIOLIB_LR11X0_CMD_WIFI_SCAN_TIME_LIMIT (0x0301) +#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE (0x0302) +#define RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT (0x0303) +#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS (0x0305) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS (0x0306) +#define RADIOLIB_LR11X0_CMD_WIFI_RESET_CUMUL_TIMINGS (0x0307) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_CUMUL_TIMINGS (0x0308) +#define RADIOLIB_LR11X0_CMD_WIFI_GET_NB_COUNTRY_CODE_RESULTS (0x0309) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_COUNTRY_CODE_RESULTS (0x030A) +#define RADIOLIB_LR11X0_CMD_WIFI_CFG_TIMESTAMP_AP_PHONE (0x030B) +#define RADIOLIB_LR11X0_CMD_WIFI_READ_VERSION (0x0320) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_RSSI (0x0222) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE (0x0400) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_CONSTELLATION_TO_USE (0x0401) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_ALMANAC_UPDATE (0x0402) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE (0x0403) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_FREQ_SEARCH_SPACE (0x0404) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_FREQ_SEARCH_SPACE (0x0405) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_VERSION (0x0406) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_SUPPORTED_CONSTELLATIONS (0x0407) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408) +#define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409) +#define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A) +#define RADIOLIB_LR11X0_CMD_GNSS_SCAN (0x040B) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_READ_ADDR_SIZE (0x040F) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411) +#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414) +#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_DM_MSG (0x0415) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS (0x0416) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_PER_SATELLITE (0x041A) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE_DOPPLER (0x0420) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426) +#define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434) +#define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435) +#define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_WEEK_NUMBER_ROLLOWER (0x0438) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A) +#define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B) +#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x044D) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453) +#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0454) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_KEEP_SYNC_STATUS (0x0456) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457) +#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466) +#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_SYNC (0x0466) +#define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469) +#define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472) +#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502) +#define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503) +#define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504) +#define RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC (0x0505) +#define RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC (0x0506) +#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT_01 (0x0507) +#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_ENCRYPT (0x0508) +#define RADIOLIB_LR11X0_CMD_CRYPTO_AES_DECRYPT (0x0509) +#define RADIOLIB_LR11X0_CMD_CRYPTO_STORE_TO_FLASH (0x050A) +#define RADIOLIB_LR11X0_CMD_CRYPTO_RESTORE_FROM_FLASH (0x050B) +#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_PARAM (0x050D) +#define RADIOLIB_LR11X0_CMD_CRYPTO_GET_PARAM (0x050E) +#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE (0x050F) +#define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT (0x0510) +#define RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH (0x8000) +#define RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED (0x8003) +#define RADIOLIB_LR11X0_CMD_BOOT_REBOOT (0x8005) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_PIN (0x800B) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI (0x800C) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI (0x800D) + +// LR11X0 SPI command variables + +// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION +#define RADIOLIB_LR11X0_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed +#define RADIOLIB_LR11X0_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error +#define RADIOLIB_LR11X0_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed +#define RADIOLIB_LR11X0_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted +#define RADIOLIB_LR11X0_STAT_1_IRQ_INACTIVE (0x00UL << 0) // 0 0 interrupt status: inactive +#define RADIOLIB_LR11X0_STAT_1_IRQ_ACTIVE (0x01UL << 0) // 0 0 at least 1 interrupt active +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_CLEARED (0x00UL << 4) // 7 4 reset status: cleared +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_ANALOG (0x01UL << 4) // 7 4 analog (power on, brown-out) +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_EXTERNAL (0x02UL << 4) // 7 4 NRESET pin +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_SYSTEM (0x03UL << 4) // 7 4 system +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WATCHDOG (0x04UL << 4) // 7 4 watchdog +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_WAKEUP (0x05UL << 4) // 7 4 NSS toggling wake-up +#define RADIOLIB_LR11X0_STAT_2_CMD_RST_RTC (0x06UL << 4) // 7 4 realtime clock +#define RADIOLIB_LR11X0_STAT_2_MODE_SLEEP (0x00UL << 1) // 3 1 chip mode: sleep +#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_RC (0x01UL << 1) // 3 1 standby with RC oscillator +#define RADIOLIB_LR11X0_STAT_2_MODE_STBY_OSC (0x02UL << 1) // 3 1 standby with external oscillator +#define RADIOLIB_LR11X0_STAT_2_MODE_FS (0x03UL << 1) // 3 1 frequency synthesis +#define RADIOLIB_LR11X0_STAT_2_MODE_RX (0x04UL << 1) // 3 1 receive +#define RADIOLIB_LR11X0_STAT_2_MODE_TX (0x05UL << 1) // 3 1 transmit +#define RADIOLIB_LR11X0_STAT_2_MODE_WIFI_GNSS (0x06UL << 1) // 3 1 WiFi or GNSS geolocation +#define RADIOLIB_LR11X0_STAT_2_BOOT (0x00UL << 0) // 0 0 code executed from: bootloader +#define RADIOLIB_LR11X0_STAT_2_FLASH (0x01UL << 0) // 0 0 flash + +// RADIOLIB_LR11X0_CMD_WRITE_REG_MEM +#define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes + +// RADIOLIB_LR11X0_CMD_GET_VERSION +#define RADIOLIB_LR11X0_DEVICE_LR1110 (0x01UL << 0) // 7 0 HW device: LR1110 +#define RADIOLIB_LR11X0_DEVICE_LR1120 (0x02UL << 0) // 7 0 LR1120 +#define RADIOLIB_LR11X0_DEVICE_LR1121 (0x03UL << 0) // 7 0 LR1121 +#define RADIOLIB_LR11X0_DEVICE_BOOT (0xDFUL << 0) // 7 0 bootloader mode + +// RADIOLIB_LR11X0_CMD_GET_ERRORS +#define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_HF_RC_CALIB_ERR (0x01UL << 1) // 15 0 high frequency RC not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_ADC_CALIB_ERR (0x01UL << 2) // 15 0 ADC not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_PLL_CALIB_ERR (0x01UL << 3) // 15 0 PLL not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_IMG_CALIB_ERR (0x01UL << 4) // 15 0 image rejection not calibrated +#define RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR (0x01UL << 5) // 15 0 high frequency oscillator failed to start +#define RADIOLIB_LR11X0_ERROR_STAT_LF_XOSC_START_ERR (0x01UL << 6) // 15 0 low frequency oscillator failed to start +#define RADIOLIB_LR11X0_ERROR_STAT_PLL_LOCK_ERR (0x01UL << 7) // 15 0 PLL failed to lock +#define RADIOLIB_LR11X0_ERROR_STAT_RX_ADC_OFFSET_ERR (0x01UL << 8) // 15 0 ADC offset not calibrated + +// RADIOLIB_LR11X0_CMD_CALIBRATE +#define RADIOLIB_LR11X0_CALIBRATE_PLL_TX (0x01UL << 5) // 5 5 calibrate: Tx PLL +#define RADIOLIB_LR11X0_CALIBRATE_IMG (0x01UL << 4) // 4 4 image rejection +#define RADIOLIB_LR11X0_CALIBRATE_ADC (0x01UL << 3) // 3 3 A/D converter +#define RADIOLIB_LR11X0_CALIBRATE_PLL (0x01UL << 2) // 2 2 PLL +#define RADIOLIB_LR11X0_CALIBRATE_HF_RC (0x01UL << 1) // 1 1 high frequency RC +#define RADIOLIB_LR11X0_CALIBRATE_LF_RC (0x01UL << 0) // 0 0 low frequency RC +#define RADIOLIB_LR11X0_CALIBRATE_ALL (0x3FUL << 0) // 5 0 everything +#define RADIOLIB_LR11X0_CAL_IMG_FREQ_TRIG_MHZ (20.0f) + +// RADIOLIB_LR11X0_CMD_SET_REG_MODE +#define RADIOLIB_LR11X0_REG_MODE_LDO (0x00UL << 0) // 0 0 regulator mode: LDO in all modes +#define RADIOLIB_LR11X0_REG_MODE_DC_DC (0x01UL << 0) // 0 0 DC-DC and LDO + +// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH +#define RADIOLIB_LR11X0_RFSW_DIO5_ENABLED (0x01UL << 0) // 4 0 RF switch: DIO5 enabled +#define RADIOLIB_LR11X0_RFSW_DIO5_DISABLED (0x00UL << 0) // 4 0 DIO5 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO6_ENABLED (0x01UL << 1) // 4 0 RF switch: DIO6 enabled +#define RADIOLIB_LR11X0_RFSW_DIO6_DISABLED (0x00UL << 1) // 4 0 DIO6 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO7_ENABLED (0x01UL << 2) // 4 0 RF switch: DIO7 enabled +#define RADIOLIB_LR11X0_RFSW_DIO7_DISABLED (0x00UL << 2) // 4 0 DIO7 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO8_ENABLED (0x01UL << 3) // 4 0 RF switch: DIO8 enabled +#define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default) +#define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled +#define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default) +#define RADIOLIB_LR11X0_DIOx(X) ((X) | RFSWITCH_PIN_FLAG) +#define RADIOLIB_LR11X0_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG) +#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LR11X0_DIOx(0)) +#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LR11X0_DIOx(1)) +#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LR11X0_DIOx(2)) +#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LR11X0_DIOx(3)) +#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LR11X0_DIOx(4)) + +// RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted +#define RADIOLIB_LR11X0_IRQ_RX_DONE (0x01UL << 3) // 31 0 packet received +#define RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED (0x01UL << 4) // 31 0 preamble detected +#define RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID (0x01UL << 5) // 31 0 sync word or LoRa header valid +#define RADIOLIB_LR11X0_IRQ_HEADER_ERR (0x01UL << 6) // 31 0 LoRa header CRC error +#define RADIOLIB_LR11X0_IRQ_CRC_ERR (0x01UL << 7) // 31 0 packet CRC error +#define RADIOLIB_LR11X0_IRQ_CAD_DONE (0x01UL << 8) // 31 0 CAD completed +#define RADIOLIB_LR11X0_IRQ_CAD_DETECTED (0x01UL << 9) // 31 0 CAD detected +#define RADIOLIB_LR11X0_IRQ_TIMEOUT (0x01UL << 10) // 31 0 Rx or Tx timeout +#define RADIOLIB_LR11X0_IRQ_LR_FHSS_HOP (0x01UL << 11) // 31 0 FHSS hop +#define RADIOLIB_LR11X0_IRQ_GNSS_DONE (0x01UL << 19) // 31 0 GNSS scan finished +#define RADIOLIB_LR11X0_IRQ_WIFI_DONE (0x01UL << 20) // 31 0 WiFi scan finished +#define RADIOLIB_LR11X0_IRQ_LBD (0x01UL << 21) // 31 0 low battery detected +#define RADIOLIB_LR11X0_IRQ_CMD_ERROR (0x01UL << 22) // 31 0 command error +#define RADIOLIB_LR11X0_IRQ_ERROR (0x01UL << 23) // 31 0 some other error than CMD_ERR +#define RADIOLIB_LR11X0_IRQ_FSK_LEN_ERROR (0x01UL << 24) // 31 0 FSK packet received with length error +#define RADIOLIB_LR11X0_IRQ_FSK_ADDR_ERROR (0x01UL << 25) // 31 0 FSK packet received with address error +#define RADIOLIB_LR11X0_IRQ_LORA_RX_TIMESTAMP (0x01UL << 27) // 31 0 last LoRa symbol was received (timestamp source) +#define RADIOLIB_LR11X0_IRQ_GNSS_ABORT (0x01UL << 28) // 31 0 GNSS scan aborted +#define RADIOLIB_LR11X0_IRQ_ALL (0x1BF80FFCUL) // 31 0 all interrupts +#define RADIOLIB_LR11X0_IRQ_NONE (0x00UL << 0) // 31 0 no interrupts + +// RADIOLIB_LR11X0_CMD_CONFIG_LF_CLOCK +#define RADIOLIB_LR11X0_LF_CLK_RC (0x00UL << 0) // 1 0 32.768 kHz source: RC oscillator +#define RADIOLIB_LR11X0_LF_CLK_XOSC (0x01UL << 0) // 1 0 crystal oscillator +#define RADIOLIB_LR11X0_LF_CLK_EXT (0x02UL << 0) // 1 0 external signal on DIO11 +#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED (0x00UL << 2) // 2 2 +#define RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED (0x01UL << 2) // 2 2 + +// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V +#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V + +// RADIOLIB_LR11X0_CMD_SET_SLEEP +#define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled +#define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled +#define RADIOLIB_LR11X0_SLEEP_WAKEUP_DISABLED (0x00UL << 0) // 1 1 automated wakeup: disabled +#define RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED (0x01UL << 0) // 1 1 enabled + +// RADIOLIB_LR11X0_CMD_SET_STANDBY +#define RADIOLIB_LR11X0_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator +#define RADIOLIB_LR11X0_STANDBY_XOSC (0x00UL << 0) // 7 0 XTAL/TCXO oscillator + +// RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE +#define RADIOLIB_LR11X0_INFO_PAGE (1) + +// RADIOLIB_LR11X0_CMD_GET_CHIP_EUI +#define RADIOLIB_LR11X0_EUI_LEN (8) + +// RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN +#define RADIOLIB_LR11X0_PIN_LEN (4) + +// RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS +#define RADIOLIB_LR11X0_RX_STATUS_ADDR_ERR (0x01UL << 5) // 7 0 Rx status: address filtering error +#define RADIOLIB_LR11X0_RX_STATUS_CRC_ERR (0x01UL << 4) // 7 0 CRC error +#define RADIOLIB_LR11X0_RX_STATUS_LEN_ERR (0x01UL << 3) // 7 0 length filtering error +#define RADIOLIB_LR11X0_RX_STATUS_ABORTED (0x01UL << 2) // 7 0 packet reception aborted +#define RADIOLIB_LR11X0_RX_STATUS_PACKET_RECEIVED (0x01UL << 1) // 7 0 packet received +#define RADIOLIB_LR11X0_RX_STATUS_PACKET_SENT (0x01UL << 0) // 7 0 packet sent + +// RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD +#define RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN (8) + +// RADIOLIB_LR11X0_CMD_SET_LORA_PUBLIC_NETWORK +#define RADIOLIB_LR11X0_LORA_PRIVATE_NETWORK (0x00UL << 0) // 7 0 LoRa sync word: private network +#define RADIOLIB_LR11X0_LORA_PUBLIC_NETWORK (0x01UL << 0) // 7 0 public network + +// RADIOLIB_LR11X0_CMD_SET_RX +#define RADIOLIB_LR11X0_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_LR11X0_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode) + +// RADIOLIB_LR11X0_CMD_SET_TX +#define RADIOLIB_LR11X0_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout + +// RADIOLIB_LR11X0_CMD_AUTO_TX_RX +#define RADIOLIB_LR11X0_AUTO_TX_RX_DISABLED (0xFFFFFFUL) // 23 0 disable auto Tx/Rx mode +#define RADIOLIB_LR11X0_AUTO_TX_RX_SKIP_INT (0x000000UL) // 23 0 skip intermediary mode +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_SLEEP (0x00UL << 0) // 1 0 intermediary mode: sleep +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_RC (0x01UL << 0) // 1 0 standby with RC +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC +#define RADIOLIB_LR11X0_AUTO_INTERMEDIARY_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis +#define RADIOLIB_LR11X0_AUTO_TX_RX_TIMEOUT_DISABLED (0x000000UL) // 23 0 disable timeout of the second mode + +// RADIOLIB_LR11X0_CMD_SET_CAD_PARAMS +#define RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC (0x00UL << 0) // 7 0 mode to set after CAD: standby with RC +#define RADIOLIB_LR11X0_CAD_EXIT_MODE_RX (0x01UL << 0) // 7 0 receive if activity detected +#define RADIOLIB_LR11X0_CAD_EXIT_MODE_LBT (0x10UL << 0) // 7 0 transmit if no activity detected +#define RADIOLIB_LR11X0_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value + +// RADIOLIB_LR11X0_CMD_SET_PACKET_TYPE +#define RADIOLIB_LR11X0_PACKET_TYPE_NONE (0x00UL << 0) // 2 0 packet type: none +#define RADIOLIB_LR11X0_PACKET_TYPE_GFSK (0x01UL << 0) // 2 0 (G)FSK +#define RADIOLIB_LR11X0_PACKET_TYPE_LORA (0x02UL << 0) // 2 0 LoRa +#define RADIOLIB_LR11X0_PACKET_TYPE_SIGFOX (0x03UL << 0) // 2 0 Sigfox +#define RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS (0x04UL << 0) // 2 0 GMSK/LR-FHSS +#define RADIOLIB_LR11X0_PACKET_TYPE_RANGING (0x05UL << 0) // 2 0 ranging +#define RADIOLIB_LR11X0_PACKET_TYPE_BLE (0x06UL << 0) // 2 0 BLE beacon + +// RADIOLIB_LR11X0_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_LR11X0_LORA_BW_62_5 (0x03UL << 0) // 7 0 LoRa bandwidth: 62.5 kHz +#define RADIOLIB_LR11X0_LORA_BW_125_0 (0x04UL << 0) // 7 0 125.0 kHz +#define RADIOLIB_LR11X0_LORA_BW_250_0 (0x05UL << 0) // 7 0 250.0 kHz +#define RADIOLIB_LR11X0_LORA_BW_500_0 (0x06UL << 0) // 7 0 500.0 kHz +#define RADIOLIB_LR11X0_LORA_BW_203_125 (0x0DUL << 0) // 7 0 203.0 kHz (2.4GHz only) +#define RADIOLIB_LR11X0_LORA_BW_406_25 (0x0EUL << 0) // 7 0 406.0 kHz (2.4GHz only) +#define RADIOLIB_LR11X0_LORA_BW_812_50 (0x0FUL << 0) // 7 0 812.0 kHz (2.4GHz only) +#define RADIOLIB_LR11X0_LORA_CR_4_5_SHORT (0x01UL << 0) // 7 0 coding rate: 4/5 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_6_SHORT (0x02UL << 0) // 7 0 4/6 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_7_SHORT (0x03UL << 0) // 7 0 4/7 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_8_SHORT (0x04UL << 0) // 7 0 4/8 with short interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_5_LONG (0x05UL << 0) // 7 0 4/5 with long interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_6_LONG (0x06UL << 0) // 7 0 4/6 with long interleaver +#define RADIOLIB_LR11X0_LORA_CR_4_8_LONG (0x07UL << 0) // 7 0 4/8 with long interleaver +#define RADIOLIB_LR11X0_LORA_LDRO_DISABLED (0x00UL << 0) // 7 0 low data rate optimize: disabled +#define RADIOLIB_LR11X0_LORA_LDRO_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_DISABLED (0x00UL << 31) // 31 0 divide bit rate value by 256: disabled +#define RADIOLIB_LR11X0_GFSK_BIT_RATE_DIV_ENABLED (0x01UL << 31) // 31 0 enabled +#define RADIOLIB_LR11X0_GFSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3 (0x08UL << 0) // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5 (0x09UL << 0) // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7 (0x0AUL << 0) // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 Gaussian, BT = 1.0 +#define RADIOLIB_LR11X0_GFSK_SHAPING_RAISED_COSINE_BT_0_7 (0x16UL << 0) // 7 0 raised cosine, BT = 0.7 +#define RADIOLIB_LR11X0_GFSK_RX_BW_4_8 (0x1FUL << 0) // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_5_8 (0x17UL << 0) // 7 0 5.8 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_7_3 (0x0FUL << 0) // 7 0 7.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_9_7 (0x1EUL << 0) // 7 0 9.7 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_11_7 (0x16UL << 0) // 7 0 11.7 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_14_6 (0x0EUL << 0) // 7 0 14.6 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_19_5 (0x1DUL << 0) // 7 0 19.5 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_23_4 (0x15UL << 0) // 7 0 23.4 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_29_3 (0x0DUL << 0) // 7 0 29.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_39_0 (0x1CUL << 0) // 7 0 39.0 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_46_9 (0x14UL << 0) // 7 0 46.9 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_58_6 (0x0CUL << 0) // 7 0 58.6 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_78_2 (0x1BUL << 0) // 7 0 78.2 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_93_8 (0x13UL << 0) // 7 0 93.8 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_117_3 (0x0BUL << 0) // 7 0 117.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_156_2 (0x1AUL << 0) // 7 0 156.2 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_187_2 (0x12UL << 0) // 7 0 187.2 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_234_3 (0x0AUL << 0) // 7 0 234.3 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz +#define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps +#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw +#define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0 +#define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7 + +// RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS +#define RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit +#define RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit +#define RADIOLIB_LR11X0_LORA_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length +#define RADIOLIB_LR11X0_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled +#define RADIOLIB_LR11X0_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled +#define RADIOLIB_LR11X0_LORA_IQ_STANDARD (0x00UL << 0) // 7 0 IQ setup: standard +#define RADIOLIB_LR11X0_LORA_IQ_INVERTED (0x01UL << 0) // 7 0 inverted +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED (0x00UL << 0) // 7 0 preamble detector: disabled +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS (0x04UL << 0) // 7 0 8 bits +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS (0x05UL << 0) // 7 0 16 bits +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS (0x06UL << 0) // 7 0 24 bits +#define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS (0x07UL << 0) // 7 0 32 bits +#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled +#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE (0x01UL << 0) // 7 0 node address +#define RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast address +#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED (0x00UL << 0) // 7 0 packet length: fixed +#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE (0x01UL << 0) // 7 0 variable +#define RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE_SX128X (0x02UL << 0) // 7 0 variable, SX128x 9-bit length encoding +#define RADIOLIB_LR11X0_GFSK_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length +#define RADIOLIB_LR11X0_GFSK_CRC_DISABLED (0x01UL << 0) // 7 0 CRC: disabled +#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE (0x00UL << 0) // 7 0 1-byte +#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE (0x02UL << 0) // 7 0 2-byte +#define RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV (0x04UL << 0) // 7 0 1-byte, inverted +#define RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV (0x06UL << 0) // 7 0 2-byte, inverted +#define RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED (0x00UL << 0) // 7 0 whitening: disabled +#define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled + +// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS +#define RADIOLIB_LR11X0_PA_RAMP_16U (0x00UL << 0) // 7 0 PA ramp time: 16 us +#define RADIOLIB_LR11X0_PA_RAMP_32U (0x01UL << 0) // 7 0 32 us +#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 48 us +#define RADIOLIB_LR11X0_PA_RAMP_64U (0x03UL << 0) // 7 0 64 us +#define RADIOLIB_LR11X0_PA_RAMP_80U (0x04UL << 0) // 7 0 80 us +#define RADIOLIB_LR11X0_PA_RAMP_96U (0x05UL << 0) // 7 0 96 us +#define RADIOLIB_LR11X0_PA_RAMP_112U (0x06UL << 0) // 7 0 112 us +#define RADIOLIB_LR11X0_PA_RAMP_128U (0x07UL << 0) // 7 0 128 us +#define RADIOLIB_LR11X0_PA_RAMP_144U (0x08UL << 0) // 7 0 144 us +#define RADIOLIB_LR11X0_PA_RAMP_160U (0x09UL << 0) // 7 0 160 us +#define RADIOLIB_LR11X0_PA_RAMP_176U (0x0AUL << 0) // 7 0 176 us +#define RADIOLIB_LR11X0_PA_RAMP_192U (0x0BUL << 0) // 7 0 192 us +#define RADIOLIB_LR11X0_PA_RAMP_208U (0x0CUL << 0) // 7 0 208 us +#define RADIOLIB_LR11X0_PA_RAMP_240U (0x0DUL << 0) // 7 0 240 us +#define RADIOLIB_LR11X0_PA_RAMP_272U (0x0EUL << 0) // 7 0 272 us +#define RADIOLIB_LR11X0_PA_RAMP_304U (0x0FUL << 0) // 7 0 304 us + +// RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC +#define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC +#define RADIOLIB_LR11X0_FALLBACK_MODE_FS (0x03UL << 0) // 1 0 frequency synthesis + +// RADIOLIB_LR11X0_CMD_SET_RX_DUTY_CYCLE +#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX (0x00UL << 0) // 0 0 mode in Rx windows: Rx (default) +#define RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_CAD (0x01UL << 0) // 0 0 CAD +#define RADIOLIB_LR11X0_TIMING_STEP (1.0f/32768.0f) // 23 0 timing step fo delays + +// RADIOLIB_LR11X0_CMD_SET_PA_CONFIG +#define RADIOLIB_LR11X0_PA_SEL_LP (0x00UL << 0) // 7 0 PA select: low power PA +#define RADIOLIB_LR11X0_PA_SEL_HP (0x01UL << 0) // 7 0 high power PA +#define RADIOLIB_LR11X0_PA_SEL_HF (0x02UL << 0) // 7 0 high frequency PA +#define RADIOLIB_LR11X0_PA_SUPPLY_INTERNAL (0x00UL << 0) // 7 0 PA power source: internal +#define RADIOLIB_LR11X0_PA_SUPPLY_VBAT (0x01UL << 0) // 7 0 VBAT (required for >= 14 dBm) + +// RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE +#define RADIOLIB_LR11X0_STOP_ON_SYNC_HEADER (0x00UL << 0) // 0 0 stop timeout on: sync word or header (default) +#define RADIOLIB_LR11X0_STOP_ON_PREAMBLE (0x01UL << 0) // 0 0 preamble + +// RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT +#define RADIOLIB_LR11X0_RANGING_RESULT_DISTANCE (0) // 7 0 ranging result type: distance +#define RADIOLIB_LR11X0_RANGING_RESULT_RSSI (1) // 7 0 RSSI + +// RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED +#define RADIOLIB_LR11X0_RX_BOOSTED_ENABLED (0x01UL << 0) // 0 0 Rx boosted mode: enabled +#define RADIOLIB_LR11X0_RX_BOOSTED_DISABLED (0x00UL << 0) // 0 0 disabled + +// RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD +#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12) +#define RADIOLIB_LR11X0_LORA_SYNC_WORD_PUBLIC (0x34) + +// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME +#define RADIOLIB_LR11X0_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 +#define RADIOLIB_LR11X0_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 +#define RADIOLIB_LR11X0_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 +#define RADIOLIB_LR11X0_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 +#define RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK +#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) +#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) +#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled +#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_LR11X0_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz +#define RADIOLIB_LR11X0_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz +#define RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header +#define RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment +#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble +#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS (RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS + RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS) + +// RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS +#define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled +#define RADIOLIB_LR11X0_LAST_HEADER_CRC_DISABLED (0x00UL << 4) // 4 4 disabled + +// RADIOLIB_LR11X0_CMD_WIFI_SCAN +#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_B (0x01UL << 0) // 7 0 Wi-Fi type to scan: 802.11b +#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_G (0x02UL << 0) // 7 0 802.11g +#define RADIOLIB_LR11X0_WIFI_SCAN_802_11_N (0x03UL << 0) // 7 0 802.11n +#define RADIOLIB_LR11X0_WIFI_SCAN_ALL (0x04UL << 0) // 7 0 all (802.11b first) +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_ONLY (0x01UL << 0) // 7 0 Wi-Fi acquisition mode: beacon only +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_BEACON_PACKET (0x02UL << 0) // 7 0 beacon and packet +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_TRAFFIC (0x03UL << 0) // 7 0 full traffic +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON (0x04UL << 0) // 7 0 full beacon +#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon +#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled +#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled +#define RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS (32) // 7 0 maximum possible number of Wi-Fi scan results +#define RADIOLIB_LR11X0_WIFI_ALL_CHANNELS (0x3FFFUL) // 16 0 scan all channels + +// RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS +#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete +#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic +#define RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN (79) // 7 0 maximum possible Wi-Fi scan size + +// RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE +#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS +#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU (0x01UL << 1) // 7 0 BeiDou + +// RADIOLIB_LR11X0_CMD_GNSS_SET_MODE +#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_SCAN (0x00UL << 0) // 7 0 GNSS scanning mode: single/legacy +#define RADIOLIB_LR11X0_GNSS_MODE_SINGLE_MULTIPLE (0x03UL << 1) // 7 0 multiple/advanced + +// RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS +#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_ENABLED (0x01UL << 0) // 0 0 GNSS results in NAV message: pseudo-range (in single scan mode) or Doppler information (in multiple scan mode) +#define RADIOLIB_LR11X0_GNSS_RES_PSEUDO_DOPPLER_DISABLED (0x00UL << 0) // 0 0 not included +#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_ENABLED (0x01UL << 1) // 1 1 Doppler information +#define RADIOLIB_LR11X0_GNSS_RES_DOPPLER_DISABLED (0x00UL << 1) // 1 1 not included +#define RADIOLIB_LR11X0_GNSS_NB_SV_ALL (0x00UL << 0) // 7 0 include all detected satellites +#define RADIOLIB_LR11X0_GNSS_AUTO_EFFORT_MODE (0x00UL << 0) // 7 0 reserved, always 0 + +// RADIOLIB_LR11X0_CMD_GNSS_ASSISTED +#define RADIOLIB_LR11X0_GNSS_ASSIST_LOW_POWER (0x00UL << 0) // 7 0 effort mode: low power +#define RADIOLIB_LR11X0_GNSS_ASSIST_BEST_EFFORT (0x01UL << 0) // 7 0 best effort + +// RADIOLIB_LR11X0_CMD_GNSS_GET_CONTEXT_STATUS +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_NONE (0x00UL << 0) // 7 4 error code: none +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_OLD (0x01UL << 0) // 7 4 almanac too old +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_CRC (0x02UL << 0) // 7 4 almanac CRC mismatch +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_FLASH (0x03UL << 0) // 7 4 flash integrity error +#define RADIOLIB_LR11X0_GNSS_CONTEXT_ERR_ALMANAC_UPD (0x04UL << 0) // 7 4 almanac update not allowed +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_250_HZ (0x00UL << 0) // 8 7 frequency search space: 250 Hz +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_500_HZ (0x01UL << 0) // 8 7 500 Hz +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_1000_HZ (0x02UL << 0) // 8 7 1000 Hz +#define RADIOLIB_LR11X0_GNSS_CONTEXT_FREQ_SPACE_2000_HZ (0x03UL << 0) // 8 7 2000 Hz + +// RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE +#define RADIOLIB_LR11X0_SV_CONSTELLATION_GPS (0x00UL << 0) // 7 0 GNSS constellation: GPS +#define RADIOLIB_LR11X0_SV_CONSTELLATION_BEIDOU (0x01UL << 0) // 7 0 BeiDou + +// RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE +#define RADIOLIB_LR11X0_GNSS_ALMANAC_HEADER_ID (0x80UL << 0) // 7 0 starting byte of GNSS almanac header +#define RADIOLIB_LR11X0_GNSS_ALMANAC_BLOCK_SIZE (20) + +// RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME +#define RADIOLIB_LR11X0_GNSS_EFFORT_LOW (0x00UL << 0) // 7 0 GNSS effort mode: low sensitivity +#define RADIOLIB_LR11X0_GNSS_EFFORT_MID (0x01UL << 0) // 7 0 medium sensitivity +#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW (0x00UL << 0) // 7 0 time fetch options: ToW only, requires WN to demodulated beforehand +#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN (0x01UL << 0) // 7 0 ToW and WN +#define RADIOLIB_LR11X0_GNSS_FETCH_TIME_OPT_TOW_WN_ROLL (0x02UL << 0) // 7 0 ToW, WN and rollover + +// RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NOT_POSSIBLE (-21) // 7 0 GNSS demodulation status: not possible to demodulate +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SAT_LOST (-20) // 7 0 satellite lost +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALMANAC_DEMOD_ERROR (-19) // 7 0 almanac demodulation error +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOO_LATE (-18) // 7 0 woke up after preamble (demodulation started too late) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_20_MS_FAIL (-17) // 7 0 20ms real-time clock failed +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WAKE_UP_FAIL (-16) // 7 0 wake up sync failed +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_INVALID (-15) // 7 0 week number not validated +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_ACTIVE_SAT (-14) // 7 0 no active satellite selected in satellite list +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SLEEP_TOO_LONG (-13) // 7 0 sleep time too long +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_INVALID (-12) // 7 0 wrong time-of-week demodulated +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PREAMBLE_INVALID (-11) // 7 0 preamble not validated +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_DISABLED (-10) // 7 0 demodulator disabled +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_EXTR_FAILED (-9) // 7 0 demodulator extraction failed +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE (-8) // 7 0 no bit change found during demodulation start +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_BIT_CHANGE_ADV (-7) // 7 0 no bit change found during advanced scan +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_SAT_FOUND (-6) // 7 0 no satellites found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_SYNC_LOST (-5) // 7 0 word sync lost +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_NOT_ENOUGH (-3) // 7 0 parity check fail (not enough) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_PARITY_TOO_MANY (-2) // 7 0 parity check fail (too many) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_NO_PARITY (-1) // 7 0 parity check fail (no parity found) +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_NONE (0) // 7 0 word sync search not started +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_POT (1) // 7 0 potential word sync found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WORD_SYNC_OK (2) // 7 0 word sync found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_TOW_FOUND (3) // 7 0 time-of-week found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_WN_FOUND (4) // 7 0 week number and time-of-week found +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_ALM_FOUND_UNSAVED (5) // 7 0 almanac found but not saved +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_HALF_ALM_SAVED (6) // 7 0 half of almanac found and saved +#define RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_FULL_ALM_SAVED (7) // 7 0 full almanac found and saved +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WORD_SYNC_FOUND (0x01UL << 0) // 7 0 GNSS demodulation info: word synchronization found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_TOW_FOUND (0x01UL << 1) // 7 0 time-of-week found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_DEMODED (0x01UL << 2) // 7 0 week number demodulated +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_WN_FOUND (0x01UL << 3) // 7 0 week number found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_1_FOUND (0x01UL << 4) // 7 0 subframe 1 found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_4_FOUND (0x01UL << 5) // 7 0 subframe 4 found +#define RADIOLIB_LR11X0_GNSS_DEMOD_INFO_SUBFRAME_5_FOUND (0x01UL << 6) // 7 0 subframe 5 found + +// RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS +#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_UP_TO_DATE (0) // 7 0 GPS/BeiDou almanac status: all satellites up-to-date +#define RADIOLIB_LR11X0_GNSS_ALMANAC_STATUS_OUTDATED (1) // 7 0 at least one satellite needs update + +// RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NONE (0) // 7 0 internal 2D solver error: no error +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_RES_HIGH (1) // 7 0 residue too high +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_CONVERGED (2) // 7 0 not converged on solution +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_NOT_ENOUGH_SV (3) // 7 0 not enough satellites +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ILL_MATRIX (4) // 7 0 matrix error (?) +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_TIME (5) // 7 0 time error +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_PART_OLD (6) // 7 0 part of almanac too old or not available +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_INCONSISTENT (7) // 7 0 not consistent with history (?) +#define RADIOLIB_LR11X0_GNSS_SOLVER_ERR_ALM_OLD (8) // 7 0 all of almanac too old + +// RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY +#define RADIOLIB_LR11X0_CRYPTO_STATUS_SUCCESS (0x00UL << 0) // 7 0 crypto engine status: success +#define RADIOLIB_LR11X0_CRYPTO_STATUS_FAIL_CMAC (0x01UL << 0) // 7 0 MIC check failed +#define RADIOLIB_LR11X0_CRYPTO_STATUS_INV_KEY_ID (0x03UL << 0) // 7 0 key/parameter source or destination ID error +#define RADIOLIB_LR11X0_CRYPTO_STATUS_BUF_SIZE (0x05UL << 0) // 7 0 data buffer size invalid +#define RADIOLIB_LR11X0_CRYPTO_STATUS_ERROR (0x06UL << 0) // 7 0 generic error + +// RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT +#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_0 (0x00UL << 0) // 7 0 LoRaWAN version: 1.0.x +#define RADIOLIB_LR11X0_CRYPTO_LORAWAN_VERSION_1_1 (0x01UL << 0) // 7 0 1.1 + +#endif + +#endif diff --git a/src/modules/LR11x0/LR11x0_registers.h b/src/modules/LR11x0/LR11x0_registers.h new file mode 100644 index 0000000000..c1534565c6 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_registers.h @@ -0,0 +1,30 @@ +#if !defined(RADIOLIB_LR11X0_REGISTERS_H) +#define RADIOLIB_LR11X0_REGISTERS_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +// LR11X0 register map +#define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414) +#define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054) +#define RADIOLIB_LR11X0_REG_LNA_MODE (0x00F3008C) +// TODO add fix for br 600/1200 bps + +// LR11X0 SPI register variables + +// RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT +#define RADIOLIB_LR11X0_SF6_SX126X (0x00UL << 18) // 18 18 SF6 mode: SX126x series +#define RADIOLIB_LR11X0_SF6_SX127X (0x01UL << 18) // 18 18 SX127x series + +// RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX +#define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata + +// RADIOLIB_LR11X0_REG_LNA_MODE +#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_N (0x01UL << 4) // 7 4 LNA mode: single-ended RFI_N +#define RADIOLIB_LR11X0_LNA_MODE_SINGLE_RFI_P (0x02UL << 4) // 7 4 single-ended RFI_P +#define RADIOLIB_LR11X0_LNA_MODE_DIFFERENTIAL (0x03UL << 4) // 7 4 differential (default) + +#endif + +#endif diff --git a/src/modules/LR11x0/LR11x0_types.h b/src/modules/LR11x0/LR11x0_types.h new file mode 100644 index 0000000000..f30e49f800 --- /dev/null +++ b/src/modules/LR11x0/LR11x0_types.h @@ -0,0 +1,230 @@ +#if !defined(RADIOLIB_LR11X0_TYPES_H) +#define RADIOLIB_LR11X0_TYPES_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR11X0 + +// MAC address length in bytes +#define RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN (6) + +// SSID length in bytes +#define RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN (32) + +/*! + \struct LR11x0WifiResult_t + \brief Structure to save result of passive WiFi scan. + This result only saves the basic information. +*/ +struct LR11x0WifiResult_t { + /*! \brief WiFi (802.11) signal type, 'b', 'n' or 'g' */ + char type; + + /*! \brief Data rate ID holding information about modulation and coding rate. See LR11x0 user manual for details. */ + uint8_t dataRateId; + + /*! \brief Channel frequency in MHz */ + uint16_t channelFreq; + + /*! \brief MAC address origin: from gateway (1), phone (2) or undetermined (3) */ + uint8_t origin; + + /*! \brief Whether this signal was sent by an access point (true) or end device (false) */ + bool ap; + + /*! \brief RSSI in dBm */ + float rssi; + + /*! \brief MAC address */ + uint8_t mac[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; +}; + +/*! + \struct LR11x0WifiResultFull_t + \brief Structure to save result of passive WiFi scan. + This result saves additional information alongside that in LR11x0WifiResult_t. +*/ +struct LR11x0WifiResultFull_t: public LR11x0WifiResult_t { + /*! \brief Frame type. See LR11x0 user manual for details. */ + uint8_t frameType; + + /*! \brief Frame sub type. See LR11x0 user manual for details. */ + uint8_t frameSubType; + + /*! \brief Frame sent from client station to distribution system. */ + bool toDistributionSystem; + + /*! \brief Frame sent from distribution system to client station. */ + bool fromDistributionSystem; + + /*! \brief See LR11x0 user manual for details. */ + uint16_t phiOffset; + + /*! \brief Number of microseconds the AP has been active. */ + uint64_t timestamp; + + /*! \brief Beacon period in microseconds. */ + uint32_t periodBeacon; +}; + +/*! + \struct LR11x0WifiResultExtended_t + \brief Structure to save result of passive WiFi scan. + This result saves additional information alongside that in LR11x0WifiResultFull_t. + Only scans performed with RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON acquisition mode + can yield this result! +*/ +struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t { + /*! \brief Data rate. See LR11x0 user manual for details. */ + uint8_t rate; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint16_t service; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint16_t length; + + /*! \brief MAC address 0 */ + uint8_t mac0[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; + + /*! \brief MAC address 2 */ + uint8_t mac2[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN]; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint16_t seqCtrl; + + /*! \brief SSID */ + uint8_t ssid[RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN]; + + /*! \brief WiFi channel number */ + uint8_t currentChannel; + + /*! \brief Two-letter country code (null-terminated string). */ + char countryCode[3]; + + /*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */ + uint8_t ioReg; + + /*! \brief True if frame check sequences is valid, false otherwise. */ + bool fcsCheckOk; +}; + +/*! + \struct LR11x0VersionInfo_t + \brief Structure to report information about versions of the LR11x0 hardware and firmware. +*/ +struct LR11x0VersionInfo_t { + /*! \brief Hardware revision. */ + uint8_t hardware; + + /*! \brief Which device this is - one of RADIOLIB_LR11X0_DEVICE_* macros. */ + uint8_t device; + + /*! \brief Major revision of the base firmware. */ + uint8_t fwMajor; + + /*! \brief Minor revision of the base firmware. */ + uint8_t fwMinor; + + /*! \brief Major revision of the WiFi firmware. */ + uint8_t fwMajorWiFi; + + /*! \brief Minor revision of the WiFi firmware. */ + uint8_t fwMinorWiFi; + + /*! \brief Revision of the GNSS firmware. */ + uint8_t fwGNSS; + + /*! \brief Almanac revision of the GNSS firmware. */ + uint8_t almanacGNSS; +}; + +/*! + \struct LR11x0GnssResult_t + \brief Structure to report information results of a GNSS scan. +*/ +struct LR11x0GnssResult_t { + /*! \brief Demodulator status. One of RADIOLIB_LR11X0_GNSS_DEMOD_STATUS_* */ + int8_t demodStat; + + /*! \brief Number of satellites detected during the scan. */ + uint8_t numSatsDet; + + /*! \brief Result size, used when passing data to LoRa cloud. */ + uint16_t resSize; +}; + +/*! + \struct LR11x0GnssPosition_t + \brief Structure to report position from LR11x0 internal solver. +*/ +struct LR11x0GnssPosition_t { + /*! \brief Latitude in degrees. */ + float latitude; + + /*! \brief Longitude in degrees. */ + float longitude; + + /*! \brief Accuracy of this result. */ + uint16_t accuracy; + + /*! \brief Number of satellites used to solve this position. */ + uint8_t numSatsUsed; +}; + +/*! + \struct LR11x0GnssSatellite_t + \brief Structure to save information about a satellite found during GNSS scan. +*/ +struct LR11x0GnssSatellite_t { + /*! \brief Satellite vehicle (SV) identifier. */ + uint8_t svId; + + /*! \brief C/N0 in dB. */ + uint8_t c_n0; + + /*! \brief Doppler shift of the signal in Hz. */ + int16_t doppler; +}; + +/*! + \struct LR11x0GnssAlmanacStatusPart_t + \brief Structure to save information about one constellation of the GNSS almanac. +*/ +struct LR11x0GnssAlmanacStatusPart_t { + int8_t status; + uint32_t timeUntilSubframe; + uint8_t numSubframes; + uint8_t nextSubframe4SvId; + uint8_t nextSubframe5SvId; + uint8_t nextSubframeStart; + uint8_t numUpdateNeeded; + uint32_t flagsUpdateNeeded[2]; + uint32_t flagsActive[2]; +}; + +/*! + \struct LR11x0GnssAlmanacStatus_t + \brief Structure to save information about the GNSS almanac. + This is not the actual almanac, just some context information about it. +*/ +struct LR11x0GnssAlmanacStatus_t { + /*! \brief GPS part of the almanac */ + LR11x0GnssAlmanacStatusPart_t gps; + + /*! \brief BeiDou part of the almanac */ + LR11x0GnssAlmanacStatusPart_t beidou; + + /*! \brief Extra flags present for BeiDou only */ + uint32_t beidouSvNoAlmanacFlags[2]; + + /*! \brief Next almanac ID */ + uint8_t nextAlmanacId; + + /*! \brief Timestamp of when almanac status was retrieved - timeUntilSubframe is relative to this value. */ + RadioLibTime_t start; +}; + +#endif + +#endif From 975975523c059a81ed594b0f486dcf3de5bc6161 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Oct 2025 19:06:48 +0100 Subject: [PATCH 1647/1848] [LR11x0] Add GFSK workaround registers --- src/modules/LR11x0/LR11x0_registers.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0_registers.h b/src/modules/LR11x0/LR11x0_registers.h index c1534565c6..685745971c 100644 --- a/src/modules/LR11x0/LR11x0_registers.h +++ b/src/modules/LR11x0/LR11x0_registers.h @@ -9,7 +9,9 @@ #define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414) #define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054) #define RADIOLIB_LR11X0_REG_LNA_MODE (0x00F3008C) -// TODO add fix for br 600/1200 bps +#define RADIOLIB_LR11X0_REG_GFSK_FIX1 (0x00F20344) +#define RADIOLIB_LR11X0_REG_GFSK_FIX2 (0x00F20348) +#define RADIOLIB_LR11X0_REG_GFSK_FIX3 (0x00F20244) // LR11X0 SPI register variables From b680b0756712081e1eb2dcb36226b441c8b85049 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 19 Oct 2025 20:02:20 +0100 Subject: [PATCH 1648/1848] [LR11x0] Add method to get boot hash --- src/modules/LR11x0/LR11x0.h | 1 + src/modules/LR11x0/LR11x0_commands.cpp | 4 ++++ src/modules/LR11x0/LR11x0_commands.h | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index d0ff44f802..9ff1001615 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -967,6 +967,7 @@ class LR11x0: public PhysicalLayer { int16_t bootEraseFlash(void); int16_t bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, size_t len, bool nonvolatile); + int16_t bootGetHash(uint8_t hash[RADIOLIB_LR11X0_HASH_LEN]); int16_t bootReboot(bool stay); int16_t bootGetPin(uint8_t* pin); int16_t bootGetChipEui(uint8_t* eui); diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index e430bbe0bf..1699ef8dd5 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -832,6 +832,10 @@ int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, const uint32_t* data, s return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile)); } +int16_t LR11x0::bootGetHash(uint8_t hash[RADIOLIB_LR11X0_HASH_LEN]) { + return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_HASH, false, hash, RADIOLIB_LR11X0_HASH_LEN)); +} + int16_t LR11x0::bootReboot(bool stay) { uint8_t buff[1] = { (uint8_t)stay }; return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_REBOOT, true, buff, sizeof(buff))); diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index ff3e26a903..d0c0d18afa 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -158,6 +158,7 @@ #define RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE_RESULT (0x0510) #define RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH (0x8000) #define RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED (0x8003) +#define RADIOLIB_LR11X0_CMD_BOOT_GET_HASH (0x8004) #define RADIOLIB_LR11X0_CMD_BOOT_REBOOT (0x8005) #define RADIOLIB_LR11X0_CMD_BOOT_GET_PIN (0x800B) #define RADIOLIB_LR11X0_CMD_BOOT_GET_CHIP_EUI (0x800C) @@ -298,6 +299,9 @@ // RADIOLIB_LR11X0_CMD_GET_CHIP_EUI #define RADIOLIB_LR11X0_EUI_LEN (8) +// RADIOLIB_LR11X0_CMD_GET_HASH +#define RADIOLIB_LR11X0_HASH_LEN (10) + // RADIOLIB_LR11X0_CMD_DERIVE_ROOT_KEYS_AND_GET_PIN #define RADIOLIB_LR11X0_PIN_LEN (4) From 5f6f846c87a7a5d093ee502dbf516a0ce75e7b84 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 21 Oct 2025 17:15:46 +0100 Subject: [PATCH 1649/1848] [LR11x0] Add GFSK workaround --- src/modules/LR11x0/LR1120.cpp | 4 +- src/modules/LR11x0/LR11x0.cpp | 94 +++++++++++++++++++++++++- src/modules/LR11x0/LR11x0.h | 4 ++ src/modules/LR11x0/LR11x0_commands.cpp | 42 ------------ 4 files changed, 98 insertions(+), 46 deletions(-) diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 6ce025eccb..9f42fff26c 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -71,7 +71,9 @@ int16_t LR1120::setFrequency(float freq, bool skipCalibration, float band) { RADIOLIB_ASSERT(state); this->freqMHz = freq; this->highFreq = (freq > 1000.0f); - return(RADIOLIB_ERR_NONE); + + // apply workaround for GFSK + return(workaroundGFSK()); } int16_t LR1120::setOutputPower(int8_t power) { diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 5f2674e894..d183810d5c 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -694,7 +694,11 @@ int16_t LR11x0::setBitRate(float br) { // set bit rate value // TODO implement fractional bit rate configuration this->bitRate = br * 1000.0f; - return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); + state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + RADIOLIB_ASSERT(state); + + // apply workaround + return(workaroundGFSK()); } int16_t LR11x0::setFrequencyDeviation(float freqDev) { @@ -714,7 +718,11 @@ int16_t LR11x0::setFrequencyDeviation(float freqDev) { RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); this->frequencyDev = newFreqDev * 1000.0f; - return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); + state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + RADIOLIB_ASSERT(state); + + // apply workaround + return(workaroundGFSK()); } int16_t LR11x0::setRxBandwidth(float rxBw) { @@ -779,7 +787,11 @@ int16_t LR11x0::setRxBandwidth(float rxBw) { } // update modulation parameters - return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); + state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + RADIOLIB_ASSERT(state); + + // apply workaround + return(workaroundGFSK()); } int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) { @@ -1723,6 +1735,82 @@ int16_t LR11x0::launchMode() { return(state); } +uint8_t LR11x0::roundRampTime(uint32_t rampTimeUs) { + uint8_t regVal; + + // Round up the ramp time to nearest discrete register value + if(rampTimeUs <= 16) { + regVal = RADIOLIB_LR11X0_PA_RAMP_16U; + } else if(rampTimeUs <= 32) { + regVal = RADIOLIB_LR11X0_PA_RAMP_32U; + } else if(rampTimeUs <= 48) { + regVal = RADIOLIB_LR11X0_PA_RAMP_48U; + } else if(rampTimeUs <= 64) { + regVal = RADIOLIB_LR11X0_PA_RAMP_64U; + } else if(rampTimeUs <= 80) { + regVal = RADIOLIB_LR11X0_PA_RAMP_80U; + } else if(rampTimeUs <= 96) { + regVal = RADIOLIB_LR11X0_PA_RAMP_96U; + } else if(rampTimeUs <= 112) { + regVal = RADIOLIB_LR11X0_PA_RAMP_112U; + } else if(rampTimeUs <= 128) { + regVal = RADIOLIB_LR11X0_PA_RAMP_128U; + } else if(rampTimeUs <= 144) { + regVal = RADIOLIB_LR11X0_PA_RAMP_144U; + } else if(rampTimeUs <= 160) { + regVal = RADIOLIB_LR11X0_PA_RAMP_160U; + } else if(rampTimeUs <= 176) { + regVal = RADIOLIB_LR11X0_PA_RAMP_176U; + } else if(rampTimeUs <= 192) { + regVal = RADIOLIB_LR11X0_PA_RAMP_192U; + } else if(rampTimeUs <= 208) { + regVal = RADIOLIB_LR11X0_PA_RAMP_208U; + } else if(rampTimeUs <= 240) { + regVal = RADIOLIB_LR11X0_PA_RAMP_240U; + } else if(rampTimeUs <= 272) { + regVal = RADIOLIB_LR11X0_PA_RAMP_272U; + } else { // 304 + regVal = RADIOLIB_LR11X0_PA_RAMP_304U; + } + + return regVal; +} + +int16_t LR11x0::workaroundGFSK() { + // first, check we are using GFSK modem + uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; + int16_t state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { + // not in GFSK, nothing to do here + return(RADIOLIB_ERR_NONE); + } + + // this seems to always be the first step (even when resetting) + state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX1, 0x30, 0x10); + RADIOLIB_ASSERT(state); + + // these are the default values that will be applied if nothing matches + uint32_t valFix2 = 0x01; + uint32_t valFix3 = 0x0A01; + + // next, decide what to change based on modulation properties + if((this->bitRate == 1200) && (this->frequencyDev == 5000) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_19_5)) { + // workaround for 1.2 kbps + valFix2 = 0x04; + + } else if((this->bitRate == 600) && (this->frequencyDev == 800) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_4_8)) { + // value to write depends on the frequency + valFix3 = (this->freqMHz >= 1000.0f) ? 0x1100 : 0x0600; + + } + + // update the registers + state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX2, 0x05, valFix2); + RADIOLIB_ASSERT(state); + return(this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX3, 0x01FF03, valFix3)); +} + int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 9ff1001615..9eeb37aa87 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -805,6 +805,10 @@ class LR11x0: public PhysicalLayer { */ uint8_t roundRampTime(uint32_t rampTimeUs); + // method that applies some magic workaround for specific bitrate, frequency deviation, + // receiver bandwidth and carrier frequencies for GFSK (and resets it in all other cases) + int16_t workaroundGFSK(); + // LR11x0 SPI command implementations int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index 1699ef8dd5..4739b7ae50 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -8,48 +8,6 @@ #if !RADIOLIB_EXCLUDE_LR11X0 -uint8_t LR11x0::roundRampTime(uint32_t rampTimeUs) -{ - uint8_t regVal; - - // Round up the ramp time to nearest discrete register value - if(rampTimeUs <= 16) { - regVal = RADIOLIB_LR11X0_PA_RAMP_16U; - } else if(rampTimeUs <= 32) { - regVal = RADIOLIB_LR11X0_PA_RAMP_32U; - } else if(rampTimeUs <= 48) { - regVal = RADIOLIB_LR11X0_PA_RAMP_48U; - } else if(rampTimeUs <= 64) { - regVal = RADIOLIB_LR11X0_PA_RAMP_64U; - } else if(rampTimeUs <= 80) { - regVal = RADIOLIB_LR11X0_PA_RAMP_80U; - } else if(rampTimeUs <= 96) { - regVal = RADIOLIB_LR11X0_PA_RAMP_96U; - } else if(rampTimeUs <= 112) { - regVal = RADIOLIB_LR11X0_PA_RAMP_112U; - } else if(rampTimeUs <= 128) { - regVal = RADIOLIB_LR11X0_PA_RAMP_128U; - } else if(rampTimeUs <= 144) { - regVal = RADIOLIB_LR11X0_PA_RAMP_144U; - } else if(rampTimeUs <= 160) { - regVal = RADIOLIB_LR11X0_PA_RAMP_160U; - } else if(rampTimeUs <= 176) { - regVal = RADIOLIB_LR11X0_PA_RAMP_176U; - } else if(rampTimeUs <= 192) { - regVal = RADIOLIB_LR11X0_PA_RAMP_192U; - } else if(rampTimeUs <= 208) { - regVal = RADIOLIB_LR11X0_PA_RAMP_208U; - } else if(rampTimeUs <= 240) { - regVal = RADIOLIB_LR11X0_PA_RAMP_240U; - } else if(rampTimeUs <= 272) { - regVal = RADIOLIB_LR11X0_PA_RAMP_272U; - } else { // 304 - regVal = RADIOLIB_LR11X0_PA_RAMP_304U; - } - - return regVal; -} - int16_t LR11x0::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { // check maximum size if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { From f6f72f9963aa204feec86d558e5c35912b0c957b Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 21 Oct 2025 19:24:16 +0100 Subject: [PATCH 1650/1848] [SX126x] Move command variables to commands file --- src/modules/SX126x/SX126x_commands.h | 231 +++++++++++++++++++++++++ src/modules/SX126x/SX126x_registers.h | 233 +------------------------- 2 files changed, 232 insertions(+), 232 deletions(-) diff --git a/src/modules/SX126x/SX126x_commands.h b/src/modules/SX126x/SX126x_commands.h index cb17aedcc6..2ce7f3ac1e 100644 --- a/src/modules/SX126x/SX126x_commands.h +++ b/src/modules/SX126x/SX126x_commands.h @@ -62,6 +62,237 @@ #define RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS 0x9A #define RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS 0x9B +// SX126X SPI command variables +//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION +#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) +#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained +#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled +#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled + +//RADIOLIB_SX126X_CMD_SET_STANDBY +#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator + +//RADIOLIB_SX126X_CMD_SET_RX +#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) + +//RADIOLIB_SX126X_CMD_SET_TX +#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) + +//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) +#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection + +//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE +#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + +//RADIOLIB_SX126X_CMD_CALIBRATE +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled +#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled +#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks + +//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B +#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 +#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 +#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 +#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 +#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 +#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0f) + +//RADIOLIB_SX126X_CMD_SET_PA_CONFIG +#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 +#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 +#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 + +//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator +#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) + +//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS +#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop +#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout +#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected +#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished +#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received +#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error +#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received +#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected +#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected +#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received +#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed +#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts +#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts + +//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL +#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ +#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control + +//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V +#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V + +//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE +#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK +#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS + +//RADIOLIB_SX126X_CMD_SET_TX_PARAMS +#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us +#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us +#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us +#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us +#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us +#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us +#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us +#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us + +//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS +#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 +#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz +#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz +#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz +#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz +#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz +#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz +#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz +#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz +#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz +#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz +#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz +#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz +#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define RADIOLIB_SX126X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaver +#define RADIOLIB_SX126X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaver +#define RADIOLIB_SX126X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaver +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled +#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled + +//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits +#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only +#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast +#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) +#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) +#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte +#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted +#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted +#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled +#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit +#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled +#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard +#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted + +//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS +#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 +#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 +#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 +#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 +#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode +#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected +#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value +#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter + +//RADIOLIB_SX126X_CMD_GET_STATUS +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC +#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC +#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS +#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX +#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX +#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved +#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out +#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command +#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute +#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done +#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received +#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent + +//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS +#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed +#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock +#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start +#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed +#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed +#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed +#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed +#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed + +//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS +#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us +#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us + #endif #endif diff --git a/src/modules/SX126x/SX126x_registers.h b/src/modules/SX126x/SX126x_registers.h index 44690b75b1..a20cc56c5d 100644 --- a/src/modules/SX126x/SX126x_registers.h +++ b/src/modules/SX126x/SX126x_registers.h @@ -79,239 +79,8 @@ #define RADIOLIB_SX126X_REG_EVENT_MASK 0x0944 #define RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE 0x8000 -// SX126X SPI command variables -//RADIOLIB_SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION -#define RADIOLIB_SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) -#define RADIOLIB_SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained -#define RADIOLIB_SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled -#define RADIOLIB_SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled - -//RADIOLIB_SX126X_CMD_SET_STANDBY -#define RADIOLIB_SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator -#define RADIOLIB_SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator - -//RADIOLIB_SX126X_CMD_SET_RX -#define RADIOLIB_SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode) -#define RADIOLIB_SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode) - -//RADIOLIB_SX126X_CMD_SET_TX -#define RADIOLIB_SX126X_TX_TIMEOUT_NONE 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode) - -//RADIOLIB_SX126X_CMD_STOP_TIMER_ON_PREAMBLE -#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default) -#define RADIOLIB_SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection - -//RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE -#define RADIOLIB_SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) -#define RADIOLIB_SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC - -//RADIOLIB_SX126X_CMD_CALIBRATE -#define RADIOLIB_SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled -#define RADIOLIB_SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled -#define RADIOLIB_SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled -#define RADIOLIB_SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled -#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled -#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks - -//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B -#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75 -#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1 -#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7 -#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1 -#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 -#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0f) - -//RADIOLIB_SX126X_CMD_SET_PA_CONFIG -#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 -#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01 -#define RADIOLIB_SX126X_PA_CONFIG_SX1262_8 0x00 - -//RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator -#define RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default) - -//RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS -#define RADIOLIB_SX126X_IRQ_LR_FHSS_HOP 0b0100000000000000 // 14 14 PA ramped up during LR-FHSS hop -#define RADIOLIB_SX126X_IRQ_TIMEOUT 0b0000001000000000 // 9 9 Rx or Tx timeout -#define RADIOLIB_SX126X_IRQ_CAD_DETECTED 0b0000000100000000 // 8 8 channel activity detected -#define RADIOLIB_SX126X_IRQ_CAD_DONE 0b0000000010000000 // 7 7 channel activity detection finished -#define RADIOLIB_SX126X_IRQ_CRC_ERR 0b0000000001000000 // 6 6 wrong CRC received -#define RADIOLIB_SX126X_IRQ_HEADER_ERR 0b0000000000100000 // 5 5 LoRa header CRC error -#define RADIOLIB_SX126X_IRQ_HEADER_VALID 0b0000000000010000 // 4 4 valid LoRa header received -#define RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID 0b0000000000001000 // 3 3 valid sync word detected -#define RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED 0b0000000000000100 // 2 2 preamble detected -#define RADIOLIB_SX126X_IRQ_RX_DONE 0b0000000000000010 // 1 1 packet received -#define RADIOLIB_SX126X_IRQ_TX_DONE 0b0000000000000001 // 0 0 packet transmission completed -#define RADIOLIB_SX126X_IRQ_ALL 0b0100001111111111 // 14 0 all interrupts -#define RADIOLIB_SX126X_IRQ_NONE 0b0000000000000000 // 14 0 no interrupts - -//RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL -#define RADIOLIB_SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ -#define RADIOLIB_SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control - -//RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V -#define RADIOLIB_SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V - -//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE -#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK -#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa -#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS - -//RADIOLIB_SX126X_CMD_SET_TX_PARAMS -#define RADIOLIB_SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us -#define RADIOLIB_SX126X_PA_RAMP_20U 0x01 // 7 0 20 us -#define RADIOLIB_SX126X_PA_RAMP_40U 0x02 // 7 0 40 us -#define RADIOLIB_SX126X_PA_RAMP_80U 0x03 // 7 0 80 us -#define RADIOLIB_SX126X_PA_RAMP_200U 0x04 // 7 0 200 us -#define RADIOLIB_SX126X_PA_RAMP_800U 0x05 // 7 0 800 us -#define RADIOLIB_SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us -#define RADIOLIB_SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us - -//RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS -#define RADIOLIB_SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7 -#define RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1 -#define RADIOLIB_SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz -#define RADIOLIB_SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz -#define RADIOLIB_SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz -#define RADIOLIB_SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz -#define RADIOLIB_SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz -#define RADIOLIB_SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz -#define RADIOLIB_SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz -#define RADIOLIB_SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz -#define RADIOLIB_SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz -#define RADIOLIB_SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz -#define RADIOLIB_SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz -#define RADIOLIB_SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz -#define RADIOLIB_SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 -#define RADIOLIB_SX126X_LORA_CR_4_6 0x02 // 7 0 4/6 -#define RADIOLIB_SX126X_LORA_CR_4_7 0x03 // 7 0 4/7 -#define RADIOLIB_SX126X_LORA_CR_4_8 0x04 // 7 0 4/8 -#define RADIOLIB_SX126X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaver -#define RADIOLIB_SX126X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaver -#define RADIOLIB_SX126X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaver -#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled -#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled - -//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits -#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only -#define RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast -#define RADIOLIB_SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides) -#define RADIOLIB_SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet) -#define RADIOLIB_SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled -#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte -#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte -#define RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted -#define RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted -#define RADIOLIB_SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled -#define RADIOLIB_SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled -#define RADIOLIB_SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit -#define RADIOLIB_SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit -#define RADIOLIB_SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled -#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled -#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard -#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted - -//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS -#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 -#define RADIOLIB_SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2 -#define RADIOLIB_SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4 -#define RADIOLIB_SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8 -#define RADIOLIB_SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16 -#define RADIOLIB_SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode -#define RADIOLIB_SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected -#define RADIOLIB_SX126X_CAD_PARAM_DEFAULT 0xFF // 7 0 used by the CAD methods to specify default parameter value -#define RADIOLIB_SX126X_CAD_PARAM_DET_MIN 10 // 7 0 default detMin CAD parameter - -//RADIOLIB_SX126X_CMD_GET_STATUS -#define RADIOLIB_SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC -#define RADIOLIB_SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC -#define RADIOLIB_SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS -#define RADIOLIB_SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX -#define RADIOLIB_SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX -#define RADIOLIB_SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved -#define RADIOLIB_SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out -#define RADIOLIB_SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command -#define RADIOLIB_SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute -#define RADIOLIB_SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done -#define RADIOLIB_SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed - -//RADIOLIB_SX126X_CMD_GET_PACKET_STATUS -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received -#define RADIOLIB_SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent - -//RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS -#define RADIOLIB_SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed -#define RADIOLIB_SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock -#define RADIOLIB_SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start -#define RADIOLIB_SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed -#define RADIOLIB_SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed -#define RADIOLIB_SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed -#define RADIOLIB_SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed -#define RADIOLIB_SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed - -//RADIOLIB_SX126X_CMD_SET_LBT_SCAN_PARAMS + RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS -#define RADIOLIB_SX126X_SCAN_INTERVAL_7_68_US 10 // 7 0 RSSI reading interval: 7.68 us -#define RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US 11 // 7 0 8.20 us -#define RADIOLIB_SX126X_SCAN_INTERVAL_8_68_US 12 // 7 0 8.68 us - // SX126X SPI register variables -//RADIOLIB_SX126X_REG_HOPPING_ENABLE +//RADIOLIB_SX126X_REG_HOPPING_ENABLE MSB LSB DESCRIPTION #define RADIOLIB_SX126X_HOPPING_ENABLED 0b00000001 // 0 0 intra-packet hopping for LR-FHSS: enabled #define RADIOLIB_SX126X_HOPPING_DISABLED 0b00000000 // 0 0 (disabled) From 1de98370ebfd2c17b39a7bb2bf889766850fc2a9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 21 Oct 2025 20:16:22 +0100 Subject: [PATCH 1651/1848] [SX126x] Add experimental BPSK support --- keywords.txt | 1 + src/modules/SX126x/SX1262.cpp | 18 ++++++++++++ src/modules/SX126x/SX1262.h | 14 +++++++++ src/modules/SX126x/SX1268.cpp | 18 ++++++++++++ src/modules/SX126x/SX1268.h | 16 ++++++++++- src/modules/SX126x/SX126x.cpp | 40 +++++++++++++++++++++++++- src/modules/SX126x/SX126x.h | 11 +++++++ src/modules/SX126x/SX126x_commands.cpp | 18 ++++++++++++ src/modules/SX126x/SX126x_commands.h | 8 ++++++ src/modules/SX126x/SX126x_config.cpp | 13 +++++++-- src/modules/SX126x/SX126x_registers.h | 1 + 11 files changed, 154 insertions(+), 4 deletions(-) diff --git a/keywords.txt b/keywords.txt index 8f92c34eb9..819952f8d2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -227,6 +227,7 @@ setCrcFiltering KEYWORD2 beginFSK4 KEYWORD2 # SX126x-specific +beginBPSK KEYWORD2 setTCXO KEYWORD2 setDio2AsRfSwitch KEYWORD2 getTimeOnAir KEYWORD2 diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 20bd436722..a72163f060 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -49,6 +49,24 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1262::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { // execute common part int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO); diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index d9668ba836..da2c31bf56 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -63,6 +63,20 @@ class SX1262: public SX126x { */ virtual int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + /*! + \brief Initialization method for BPSK modem. + NOTE: Proceed with caution! BPSK support in SX126x is epxerimental and poorly documented! + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 600 bps, only 100 and 600 bps is supported + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + virtual int16_t beginBPSK(float freq = 434.0, float br = 0.6, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + /*! \brief Initialization method for LR-FHSS modem. This modem only supports transmission! \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index f9ef606a6f..018ffb6eb1 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -49,6 +49,24 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } +int16_t SX1268::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { + // execute common part + int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) { // execute common part int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO); diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 28b246e359..911d2e7a40 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -61,7 +61,21 @@ class SX1268: public SX126x { \returns \ref status_codes */ int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); - + + /*! + \brief Initialization method for BPSK modem. + NOTE: Proceed with caution! BPSK support in SX126x is epxerimental and poorly documented! + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 600 bps, only 100 and 600 bps is supported. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set SX126x::XTAL to true. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + virtual int16_t beginBPSK(float freq = 434.0, float br = 0.6, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + /*! \brief Initialization method for LR-FHSS modem. This modem only supports transmission! \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 660b03959e..9d096438bb 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -120,6 +120,22 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL return(state); } +int16_t SX126x::beginBPSK(float br, float tcxoVoltage, bool useRegulatorLDO) { + // set module properties and perform initial setup + int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_BPSK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setDio2AsRfSwitch(true); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX126x::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage, bool useRegulatorLDO) { this->lrFhssGridNonFcc = narrowGrid; @@ -898,8 +914,21 @@ RadioLibTime_t SX126x::getTimeOnAir(size_t len) { dataRate.lrFhss.narrowGrid = this->lrFhssGridNonFcc; packetConfig.lrFhss.hdrCount = this->lrFhssHdrCount; + } else if(type == RADIOLIB_SX126X_PACKET_TYPE_BPSK) { + // BPSK is so experimental it does not have a specific data rate structure + // so just reuse FSK + modem = RADIOLIB_MODEM_FSK; + + dataRate.fsk.bitRate = RADIOLIB_SX126X_CRYSTAL_FREQ * 32.0f * 1000.0f / (float)this->bitRate; + dataRate.fsk.freqDev = 0; + + packetConfig.fsk.preambleLength = 0; + packetConfig.fsk.syncWordLength = 0; + packetConfig.fsk.crcLength = 0; + } else { return(RADIOLIB_ERR_WRONG_MODEM); + } return(calculateTimeOnAir(modem, dataRate, packetConfig, len)); @@ -1015,7 +1044,16 @@ int16_t SX126x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) { state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, cfg->transmit.len); - + + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) { + uint16_t rampUp = RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_600_BPS; + uint16_t rampDown = RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_600_BPS; + if(this->bitRate == 100) { + rampUp = RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_100_BPS; + rampDown = RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_100_BPS; + } + state = setPacketParamsBPSK(cfg->transmit.len, rampUp, rampDown, 8*cfg->transmit.len); + } else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { return(RADIOLIB_ERR_UNKNOWN); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 63d1bb08cd..adb9180861 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -86,6 +86,15 @@ class SX126x: public PhysicalLayer { */ int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); + /*! + \brief Initialization method for BPSK modem. + \param br FSK bit rate in kbps. Only 100 and 600 bps is supported. + \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes + */ + int16_t beginBPSK(float br, float tcxoVoltage, bool useRegulatorLDO = false); + /*! \brief Initialization method for LR-FHSS modem. This modem only supports transmission! \param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values. @@ -817,8 +826,10 @@ class SX126x: public PhysicalLayer { int16_t setTxParams(uint8_t power, uint8_t rampTime); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev); + int16_t setModulationParamsBPSK(uint32_t br, uint8_t sh = RADIOLIB_SX126X_BPSK_PULSE_SHAPE); int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ); int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF); + int16_t setPacketParamsBPSK(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t payloadLenBits); int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); int16_t setRegulatorMode(uint8_t mode); uint8_t getStatus(); diff --git a/src/modules/SX126x/SX126x_commands.cpp b/src/modules/SX126x/SX126x_commands.cpp index f883346800..114c38ac4c 100644 --- a/src/modules/SX126x/SX126x_commands.cpp +++ b/src/modules/SX126x/SX126x_commands.cpp @@ -202,6 +202,11 @@ int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, ui return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8)); } +int16_t SX126x::setModulationParamsBPSK(uint32_t br, uint8_t sh) { + const uint8_t data[] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh}; + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, sizeof(data))); +} + int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) { int16_t state = fixInvertedIQ(invertIQ); RADIOLIB_ASSERT(state); @@ -216,6 +221,19 @@ int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetecto return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9)); } +int16_t SX126x::setPacketParamsBPSK(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t payloadLenBits) { + const uint8_t data[] = { payloadLen, + (uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF), + (uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF), + (uint8_t)((payloadLenBits >> 8) & 0xFF), (uint8_t)(payloadLenBits & 0xFF) + }; + + // this one is a bit different, it seems to be split into command transaction and then a register write + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, sizeof(uint8_t)); + RADIOLIB_ASSERT(state); + return(this->writeRegister(RADIOLIB_SX126X_REG_BPSK_PACKET_PARAMS, &data[1], sizeof(data) - sizeof(uint8_t))); +} + int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { const uint8_t data[2] = {txBaseAddress, rxBaseAddress}; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); diff --git a/src/modules/SX126x/SX126x_commands.h b/src/modules/SX126x/SX126x_commands.h index 2ce7f3ac1e..b66124b7e0 100644 --- a/src/modules/SX126x/SX126x_commands.h +++ b/src/modules/SX126x/SX126x_commands.h @@ -160,6 +160,7 @@ //RADIOLIB_SX126X_CMD_SET_PACKET_TYPE #define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK #define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define RADIOLIB_SX126X_PACKET_TYPE_BPSK 0x02 // 7 0 BPSK #define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS //RADIOLIB_SX126X_CMD_SET_TX_PARAMS @@ -218,6 +219,7 @@ #define RADIOLIB_SX126X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaver #define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled #define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled +#define RADIOLIB_SX126X_BPSK_PULSE_SHAPE 0x16 // 7 0 BSPK pulse shape double OSR, RRC, BT=0.7 //RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS #define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled @@ -243,6 +245,12 @@ #define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled #define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard #define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted +#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_NONE 0x0000 // 15 0 BPSK ramp-up time optimization: none +#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_100_BPS 0x370F // 15 0 for 100 bps +#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_600_BPS 0x092F // 15 0 for 600 bps +#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_NONE 0x0000 // 15 0 BPSK ramp-down time optimization: none +#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_100_BPS 0x1D70 // 15 0 for 100 bps +#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_600_BPS 0x04E1 // 15 0 for 600 bps //RADIOLIB_SX126X_CMD_SET_CAD_PARAMS #define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index a4715aed68..88336f3931 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -217,12 +217,18 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { int16_t SX126x::setBitRate(float br) { // check active modem uint8_t modem = getPacketType(); - if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) { + if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && + (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) && + (modem != RADIOLIB_SX126X_PACKET_TYPE_BPSK)) { return(RADIOLIB_ERR_WRONG_MODEM); } - if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { + if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) { + // this should be just either 100 or 600 bps, not the range + // but the BPSK support is so experimental it probably does not matter + RADIOLIB_CHECK_RANGE(br, 0.1f, 0.6f, RADIOLIB_ERR_INVALID_BIT_RATE); } // calculate raw bit rate value @@ -232,6 +238,9 @@ int16_t SX126x::setBitRate(float br) { this->bitRate = brRaw; // update modulation parameters + if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) { + return(setModulationParamsBPSK(this->bitRate)); + } return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); } diff --git a/src/modules/SX126x/SX126x_registers.h b/src/modules/SX126x/SX126x_registers.h index a20cc56c5d..86ee5d968f 100644 --- a/src/modules/SX126x/SX126x_registers.h +++ b/src/modules/SX126x/SX126x_registers.h @@ -6,6 +6,7 @@ #if !RADIOLIB_EXCLUDE_SX126X // SX126X register map +#define RADIOLIB_SX126X_REG_BPSK_PACKET_PARAMS 0x00F0 #define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6 #define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6 #define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6 From f73398533e8d71466fab6826279a93654d70effe Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 24 Oct 2025 16:12:39 +0100 Subject: [PATCH 1652/1848] [SX126x] Add workaround for GFSK --- src/modules/SX126x/SX126x.cpp | 42 +++++++++++++++++++++++++++ src/modules/SX126x/SX126x.h | 1 + src/modules/SX126x/SX126x_config.cpp | 10 +++++-- src/modules/SX126x/SX126x_registers.h | 3 ++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 9d096438bb..5a57fec875 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1386,6 +1386,48 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) { return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1)); } +int16_t SX126x::fixGFSK() { + // method that applies some magic workaround for specific bitrate, frequency deviation, + // receiver bandwidth and carrier frequencies for GFSK (and resets it in all other cases) + // this is not documented in the datasheet, only in Semtech repositories for SX126x and LR11xx + + // first, check we are using GFSK modem + if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { + // not in GFSK, nothing to do here + return(RADIOLIB_ERR_NONE); + } + + // next, decide what to change based on modulation properties + int16_t state = RADIOLIB_ERR_UNKNOWN; + if(this->bitRate == 1200) { + // workaround for 1.2 kbps + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_3, 0x00, 4, 4); + + } else if(this->bitRate == 600) { + // workaround for 0.6 kbps + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_1, 0x18, 4, 3); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x04, 4, 2); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_3, 0x00, 4, 4); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_4, 0x50, 6, 4); + + } else { + // reset + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_1, 0x08, 4, 3); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00, 4, 2); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_3, 0x10, 4, 4); + RADIOLIB_ASSERT(state); + state = this->mod->SPIsetRegValue(RADIOLIB_SX126X_REG_GFSK_FIX_4, 0x00, 6, 4); + + } + + return(state); +} + Module* SX126x::getMod() { return(this->mod); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index adb9180861..6ace5aa77b 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -905,6 +905,7 @@ class SX126x: public PhysicalLayer { int16_t fixSensitivity(); int16_t fixImplicitTimeout(); int16_t fixInvertedIQ(uint8_t iqConfig); + int16_t fixGFSK(); // LR-FHSS utilities int16_t buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len, size_t* out_bits, size_t* out_hops); diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 88336f3931..a8dc3ecfe8 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -238,10 +238,16 @@ int16_t SX126x::setBitRate(float br) { this->bitRate = brRaw; // update modulation parameters + int16_t state = RADIOLIB_ERR_UNKNOWN; if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) { - return(setModulationParamsBPSK(this->bitRate)); + state = setModulationParamsBPSK(this->bitRate); + } else { + state = setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); } - return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); + RADIOLIB_ASSERT(state); + + // apply workaround or reset it, as needed + return(fixGFSK()); } int16_t SX126x::setDataRate(DataRate_t dr, ModemType_t modem) { diff --git a/src/modules/SX126x/SX126x_registers.h b/src/modules/SX126x/SX126x_registers.h index 86ee5d968f..e1dd7621eb 100644 --- a/src/modules/SX126x/SX126x_registers.h +++ b/src/modules/SX126x/SX126x_registers.h @@ -29,6 +29,7 @@ #define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_0 0x0587 #define RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE 0x0610 #define RADIOLIB_SX126X_REG_TX_BITBANG_ENABLE_1 0x0680 +#define RADIOLIB_SX126X_REG_GFSK_FIX_4 0x06AC #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB 0x06B8 #define RADIOLIB_SX126X_REG_WHITENING_INITIAL_LSB 0x06B9 #define RADIOLIB_SX126X_REG_RX_TX_PLD_LEN 0x06BB @@ -46,6 +47,7 @@ #define RADIOLIB_SX126X_REG_SYNC_WORD_7 0x06C7 #define RADIOLIB_SX126X_REG_NODE_ADDRESS 0x06CD #define RADIOLIB_SX126X_REG_BROADCAST_ADDRESS 0x06CE +#define RADIOLIB_SX126X_REG_GFSK_FIX_1 0x06D1 #define RADIOLIB_SX126X_REG_PAYLOAD_LENGTH 0x0702 #define RADIOLIB_SX126X_REG_PACKET_PARAMS 0x0704 #define RADIOLIB_SX126X_REG_LORA_SYNC_TIMEOUT 0x0706 @@ -67,6 +69,7 @@ #define RADIOLIB_SX126X_REG_RF_FREQUENCY_3 0x088E #define RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW 0x089B #define RADIOLIB_SX126X_REG_RX_GAIN 0x08AC +#define RADIOLIB_SX126X_REG_GFSK_FIX_3 0x08B8 #define RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG 0x08D8 #define RADIOLIB_SX126X_REG_ANA_LNA 0x08E2 #define RADIOLIB_SX126X_REG_LNA_CAP_TUNE_N 0x08E3 From 027393904d80043eadb800da3eac4549bba7e73e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Oct 2025 20:33:39 +0100 Subject: [PATCH 1653/1848] Fix typo --- src/modules/LR11x0/LR11x0.h | 2 +- src/modules/SX126x/SX126x.h | 2 +- src/modules/SX127x/SX127x.h | 2 +- src/modules/SX128x/SX128x.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 9eeb37aa87..e6a6fcc517 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -469,7 +469,7 @@ class LR11x0: public PhysicalLayer { /*! \brief Enable/disable inversion of the I and Q signals - \param enable QI inversion enabled (true) or disabled (false); + \param enable IQ inversion enabled (true) or disabled (false); \returns \ref status_codes */ int16_t invertIQ(bool enable) override; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 6ace5aa77b..69e72c8a71 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -697,7 +697,7 @@ class SX126x: public PhysicalLayer { /*! \brief Enable/disable inversion of the I and Q signals - \param enable QI inversion enabled (true) or disabled (false); + \param enable IQ inversion enabled (true) or disabled (false); \returns \ref status_codes */ int16_t invertIQ(bool enable) override; diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 383b4369ce..b4f7ec41f2 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1159,7 +1159,7 @@ class SX127x: public PhysicalLayer { /*! \brief Enable/disable inversion of the I and Q signals - \param enable QI inversion enabled (true) or disabled (false); + \param enable IQ inversion enabled (true) or disabled (false); \returns \ref status_codes */ int16_t invertIQ(bool enable) override; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index a179a052d7..a2d2eb308e 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -879,7 +879,7 @@ class SX128x: public PhysicalLayer { /*! \brief Enable/disable inversion of the I and Q signals - \param enable QI inversion enabled (true) or disabled (false); + \param enable IQ inversion enabled (true) or disabled (false); \returns \ref status_codes */ int16_t invertIQ(bool enable) override; From 230c7ca549af898bb47c2d7f1f7669808f890b7f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 25 Oct 2025 20:34:59 +0100 Subject: [PATCH 1654/1848] [SX126x] Remove setSyncBits method (#1633) --- keywords.txt | 1 - src/modules/SX126x/SX126x.h | 9 --------- src/modules/SX126x/SX126x_config.cpp | 19 ------------------- 3 files changed, 29 deletions(-) diff --git a/keywords.txt b/keywords.txt index 819952f8d2..63443a2bdd 100644 --- a/keywords.txt +++ b/keywords.txt @@ -234,7 +234,6 @@ getTimeOnAir KEYWORD2 calculateTimeOnAir KEYWORD2 implicitHeader KEYWORD2 explicitHeader KEYWORD2 -setSyncBits KEYWORD2 setWhitening KEYWORD2 startReceiveDutyCycle KEYWORD2 startReceiveDutyCycleAuto KEYWORD2 diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 69e72c8a71..a4cbccce50 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -472,15 +472,6 @@ class SX126x: public PhysicalLayer { */ int16_t setSyncWord(uint8_t* syncWord, size_t len) override; - /*! - \brief Sets FSK sync word in the form of array of up to 8 bytes. - \param syncWord FSK sync word to be set. - \param bitsLen FSK sync word length in bits. If length is not divisible by 8, - least significant bits of syncWord will be ignored. - \returns \ref status_codes - */ - int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen); - /*! \brief Sets CRC configuration. \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index a8dc3ecfe8..9b2887e042 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -487,25 +487,6 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) { return(RADIOLIB_ERR_WRONG_MODEM); } -int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { - // check active modem - if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - // check sync word Length - if(bitsLen > 0x40) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } - - uint8_t bytesLen = bitsLen / 8; - if ((bitsLen % 8) != 0) { - bytesLen++; - } - - return(setSyncWord(syncWord, bytesLen)); -} - int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) { // check active modem uint8_t modem = getPacketType(); From e6de3e284bd1dae07a50fdc60be38016b93ea7cf Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Oct 2025 07:17:29 +0000 Subject: [PATCH 1655/1848] [SX126x] Remove setSyncBits from example --- examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index cc8849da39..04dcbe58ff 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -71,13 +71,6 @@ void setup() { while (true) { delay(10); } } - // FSK modem on SX126x can handle the sync word setting in bits, not just - // whole bytes. The value used is left-justified. - // This makes same result as radio.setSyncWord(syncWord, 8): - state = radio.setSyncBits(syncWord, 64); - // This will use 0x012 as sync word (12 bits only): - state = radio.setSyncBits(syncWord, 12); - // FSK modem allows advanced CRC configuration // Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted) // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted) From e6dcb46de35d4949924f5063a82c7b9cf235a26a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Oct 2025 07:17:42 +0000 Subject: [PATCH 1656/1848] [LR11x0] Remove setSyncBits method --- .../LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino | 7 ------- src/modules/LR11x0/LR11x0.cpp | 21 ------------------- src/modules/LR11x0/LR11x0.h | 9 -------- 3 files changed, 37 deletions(-) diff --git a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino index 85e7bd4522..c3a80037ee 100644 --- a/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino +++ b/examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino @@ -70,13 +70,6 @@ void setup() { while (true) { delay(10); } } - // GFSK modem on LR11x0 can handle the sync word setting in bits, not just - // whole bytes. The value used is left-justified. - // This makes same result as radio.setSyncWord(syncWord, 8): - state = radio.setSyncBits(syncWord, 64); - // This will use 0x012 as sync word (12 bits only): - state = radio.setSyncBits(syncWord, 12); - // GFSK modem allows advanced CRC configuration // Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted) // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index d183810d5c..614ebba274 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -835,27 +835,6 @@ int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) { return(RADIOLIB_ERR_WRONG_MODEM); } -int16_t LR11x0::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { - if((!syncWord) || (!bitsLen) || (bitsLen > 8*RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) { - return(RADIOLIB_ERR_INVALID_SYNC_WORD); - } - - // check active modem - uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; - int16_t state = getPacketType(&type); - RADIOLIB_ASSERT(state); - if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - uint8_t bytesLen = bitsLen / 8; - if ((bitsLen % 8) != 0) { - bytesLen++; - } - - return(setSyncWord(syncWord, bytesLen)); -} - int16_t LR11x0::setNodeAddress(uint8_t nodeAddr) { // check active modem uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index e6a6fcc517..70f102d9c1 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -353,15 +353,6 @@ class LR11x0: public PhysicalLayer { */ int16_t setSyncWord(uint8_t* syncWord, size_t len) override; - /*! - \brief Sets GFSK sync word in the form of array of up to 8 bytes. - \param syncWord GFSK sync word to be set. - \param bitsLen GFSK sync word length in bits. If length is not divisible by 8, - least significant bits of syncWord will be ignored. - \returns \ref status_codes - */ - int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen); - /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. \param nodeAddr Node address to be set. From b1ed82189d3f5b40fc90b036c931e8ec8600917f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 26 Oct 2025 08:56:00 +0100 Subject: [PATCH 1657/1848] Bump version to 7.4.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 3fd094612e..b9fa9678eb 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.3.0" +version: "7.4.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index c8b131d5fc..4a5d73dbf8 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.3.0", + "version": "7.4.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index e044b27b32..651c8d51d7 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.3.0 +version=7.4.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 4d5fc26aa8..5046c3167d 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -604,7 +604,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 -#define RADIOLIB_VERSION_MINOR 3 +#define RADIOLIB_VERSION_MINOR 4 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From 79187ce080f8b57312cacf2e851ac5d50673ae63 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Oct 2025 07:19:50 +0000 Subject: [PATCH 1658/1848] [SX128x] Add finishRanging method (#1605) --- keywords.txt | 1 + src/modules/SX128x/SX1280.cpp | 32 ++++++++++++++++++++++---------- src/modules/SX128x/SX1280.h | 6 ++++++ src/modules/SX128x/SX128x.h | 4 +++- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/keywords.txt b/keywords.txt index 63443a2bdd..4292707298 100644 --- a/keywords.txt +++ b/keywords.txt @@ -306,6 +306,7 @@ beginBLE KEYWORD2 setAccessAddress KEYWORD2 range KEYWORD2 startRanging KEYWORD2 +finishRanging KEYWORD2 getRangingResult KEYWORD2 # Hellschreiber diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index d2bb12c4e9..345af8f968 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -17,20 +17,12 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { while(!mod->hal->digitalRead(mod->getIrq())) { mod->hal->yield(); if(mod->hal->millis() - start > 10000) { - clearIrqStatus(); - standby(); + (void)finishRanging(); return(RADIOLIB_ERR_RANGING_TIMEOUT); } } - // clear interrupt flags - state = clearIrqStatus(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - - return(state); + return(finishRanging()); } int16_t SX1280::startRanging(bool master, uint32_t addr, const uint16_t calTable[3][6]) { @@ -140,6 +132,26 @@ int16_t SX1280::startRanging(bool master, uint32_t addr, const uint16_t calTable return(state); } +int16_t SX1280::finishRanging() { + // start by clearing interrupt flags + int16_t state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // restore back to LoRa communication + // config sets up the bare minimum + state = config(RADIOLIB_SX128X_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + // restore modulation and packet parameters and we're done + state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa); + RADIOLIB_ASSERT(state); + return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa)); +} + float SX1280::getRangingResult() { // set mode to standby XOSC int16_t state = standby(RADIOLIB_SX128X_STANDBY_XOSC); diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index c4cea00a2c..a67c11def0 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -38,6 +38,12 @@ class SX1280: public SX1281 { \returns \ref status_codes */ int16_t startRanging(bool master, uint32_t addr, const uint16_t calTable[3][6] = NULL); + + /*! + \brief Clean up after ranging is done. Will set modem back to LoRa mode. + \returns \ref status_codes + */ + int16_t finishRanging(); /*! \brief Gets ranging result of the last ranging exchange. diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index a2d2eb308e..d5f7f93590 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -936,6 +936,9 @@ class SX128x: public PhysicalLayer { int16_t setRangingRole(uint8_t role); int16_t setPacketType(uint8_t type); + // protected so that it can be accessed from SX1280 class during reinit after ranging is complete + int16_t config(uint8_t modem); + #if !RADIOLIB_GODMODE private: #endif @@ -964,7 +967,6 @@ class SX128x: public PhysicalLayer { // cached BLE parameters uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0; - int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); }; From f6b007403d11953fa670737e286e56ed46cac5d0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Oct 2025 07:39:38 +0000 Subject: [PATCH 1659/1848] [SX128x] Add getRangingResultRaw method (#1605) --- keywords.txt | 1 + src/modules/SX128x/SX1280.cpp | 15 ++++++++++++--- src/modules/SX128x/SX1280.h | 8 ++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index 4292707298..5ee1b44491 100644 --- a/keywords.txt +++ b/keywords.txt @@ -308,6 +308,7 @@ range KEYWORD2 startRanging KEYWORD2 finishRanging KEYWORD2 getRangingResult KEYWORD2 +getRangingResultRaw KEYWORD2 # Hellschreiber printGlyph KEYWORD2 diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 345af8f968..5a641183f8 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -152,7 +152,16 @@ int16_t SX1280::finishRanging() { return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa)); } +int32_t SX1280::getRangingResultRaw() { + return(getRangingResultCommon(false)); +} + float SX1280::getRangingResult() { + int32_t raw = getRangingResultCommon(true); + return((float)raw * 150.0f / (4.096f * this->bandwidthKhz)); +} + +int32_t SX1280::getRangingResultCommon(bool filtered) { // set mode to standby XOSC int16_t state = standby(RADIOLIB_SX128X_STANDBY_XOSC); RADIOLIB_ASSERT(state); @@ -171,7 +180,7 @@ float SX1280::getRangingResult() { RADIOLIB_ASSERT(state); data[0] &= 0xCF; - data[0] |= (1 << 4); + data[0] |= ((uint8_t)filtered << 4); state = writeRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1); RADIOLIB_ASSERT(state); @@ -187,10 +196,10 @@ float SX1280::getRangingResult() { state = standby(); RADIOLIB_ASSERT(state); - // calculate the real result + // convert to signed uint32_t uraw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; int32_t raw = (uraw & ((1UL << 23) - 1)) | (uraw >> 23 << 31); - return((float)raw * 150.0f / (4.096f * this->bandwidthKhz)); + return(raw); } #endif diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index a67c11def0..90c68c7ce0 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -51,10 +51,18 @@ class SX1280: public SX1281 { */ float getRangingResult(); + /*! + \brief Gets ranging result of the last ranging exchange. + \returns Ranging result in arbitrary raw units. For conversion to meters, + see SX1280 datasheet, or use the getRangingResult method. + */ + int32_t getRangingResultRaw(); + #if !RADIOLIB_GODMODE private: #endif + int32_t getRangingResultCommon(bool filtered); }; #endif From 600c008e9181f6417dd2604f1d5d7b445538c577 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Oct 2025 07:55:23 +0000 Subject: [PATCH 1660/1848] [SX1280] Add device type check based on register version string --- src/modules/SX128x/SX1280.cpp | 2 +- src/modules/SX128x/SX1280.h | 3 + src/modules/SX128x/SX1281.cpp | 2 +- src/modules/SX128x/SX1281.h | 3 + src/modules/SX128x/SX1282.cpp | 2 +- src/modules/SX128x/SX1282.h | 3 + src/modules/SX128x/SX128x.cpp | 167 ++++++++++++++-------------------- src/modules/SX128x/SX128x.h | 5 + 8 files changed, 84 insertions(+), 103 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 5a641183f8..32078e613e 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -3,7 +3,7 @@ #if !RADIOLIB_EXCLUDE_SX128X SX1280::SX1280(Module* mod) : SX1281(mod) { - + chipType = RADIOLIB_SX1280_CHIP_TYPE; } int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) { diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index 90c68c7ce0..2e2bc04da8 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -9,6 +9,9 @@ #include "SX128x.h" #include "SX1281.h" +// RADIOLIB_SX128X_REG_VERSION_STRING +#define RADIOLIB_SX1280_CHIP_TYPE "SX1280" + /*! \class SX1280 \brief Derived class for %SX1280 modules. diff --git a/src/modules/SX128x/SX1281.cpp b/src/modules/SX128x/SX1281.cpp index 71e7476e78..b6bdf77fc7 100644 --- a/src/modules/SX128x/SX1281.cpp +++ b/src/modules/SX128x/SX1281.cpp @@ -2,7 +2,7 @@ #if !RADIOLIB_EXCLUDE_SX128X SX1281::SX1281(Module* mod) : SX128x(mod) { - + chipType = RADIOLIB_SX1281_CHIP_TYPE; } #endif diff --git a/src/modules/SX128x/SX1281.h b/src/modules/SX128x/SX1281.h index 3d697dad46..9cdc95e691 100644 --- a/src/modules/SX128x/SX1281.h +++ b/src/modules/SX128x/SX1281.h @@ -8,6 +8,9 @@ #include "../../Module.h" #include "SX128x.h" +// RADIOLIB_SX128X_REG_VERSION_STRING +#define RADIOLIB_SX1281_CHIP_TYPE "SX1281" + /*! \class SX1281 \brief Derived class for %SX1281 modules. diff --git a/src/modules/SX128x/SX1282.cpp b/src/modules/SX128x/SX1282.cpp index d58ba3d37f..f801d62fdf 100644 --- a/src/modules/SX128x/SX1282.cpp +++ b/src/modules/SX128x/SX1282.cpp @@ -3,7 +3,7 @@ /// \todo implement advanced ranging SX1282::SX1282(Module* mod) : SX1280(mod) { - + chipType = RADIOLIB_SX1282_CHIP_TYPE; } #endif diff --git a/src/modules/SX128x/SX1282.h b/src/modules/SX128x/SX1282.h index dc51ba9d86..0b98c94a54 100644 --- a/src/modules/SX128x/SX1282.h +++ b/src/modules/SX128x/SX1282.h @@ -9,6 +9,9 @@ #include "SX128x.h" #include "SX1280.h" +// RADIOLIB_SX128X_REG_VERSION_STRING +#define RADIOLIB_SX1282_CHIP_TYPE "SX1282" + /*! \class SX1282 \brief Derived class for %SX1282 modules. diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index ef2748e958..c1086f0fba 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1,5 +1,6 @@ #include "SX128x.h" #include +#include #if !RADIOLIB_EXCLUDE_SX128X SX128x::SX128x(Module* mod) : PhysicalLayer() { @@ -19,21 +20,6 @@ SX128x::SX128x(Module* mod) : PhysicalLayer() { } int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->spiConfig.statusPos = 1; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); - // initialize LoRa modulation variables this->bandwidthKhz = bw; this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9; @@ -45,16 +31,8 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync this->payloadLen = 0xFF; this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON; - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(RADIOLIB_SX128X_PACKET_TYPE_LORA); + // set module properties and perform initial setup + int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -83,21 +61,6 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync } int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, uint16_t preambleLength) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->spiConfig.statusPos = 1; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); - // initialize GFSK modulation variables this->bitRateKbps = br; this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; @@ -112,16 +75,8 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(RADIOLIB_SX128X_PACKET_TYPE_GFSK); + // set module properties and perform initial setup + int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_GFSK); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -155,21 +110,6 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui } int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uint8_t dataShaping) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->spiConfig.statusPos = 1; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); - // initialize BLE modulation variables this->bitRateKbps = br; this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4; @@ -181,16 +121,8 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE; this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON; - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(RADIOLIB_SX128X_PACKET_TYPE_BLE); + // set module properties and perform initial setup + int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_BLE); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -213,21 +145,6 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin } int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping) { - // set module properties - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; - this->mod->spiConfig.statusPos = 1; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); - // initialize FLRC modulation variables this->bitRateKbps = br; this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6; @@ -241,16 +158,8 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1 this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE; this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF; - // reset the module and verify startup - int16_t state = reset(); - RADIOLIB_ASSERT(state); - - // set mode to standby - state = standby(); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(RADIOLIB_SX128X_PACKET_TYPE_FLRC); + // set module properties and perform initial setup + int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_FLRC); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -1642,6 +1551,33 @@ Module* SX128x::getMod() { return(this->mod); } +int16_t SX128x::modSetup(uint8_t modem) { + // set module properties + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8; + this->mod->spiConfig.statusPos = 1; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + + // find the chip - this will also reset the module and verify the module + if(!SX128x::findChip(this->chipType)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No SX128x found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x"); + + // configure settings not accessible by API + return(config(modem)); +} + uint8_t SX128x::getStatus() { uint8_t data = 0; this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0); @@ -1826,4 +1762,35 @@ int16_t SX128x::SPIparseStatus(uint8_t in) { return(RADIOLIB_ERR_NONE); } +bool SX128x::findChip(const char* verStr) { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(true); + + // read the version string + char version[16] = { 0 }; + this->mod->SPIreadRegisterBurst(RADIOLIB_SX128X_REG_VERSION_STRING, 16, reinterpret_cast(version)); + + // check version register + if(strncmp(verStr, version, 6) == 0) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX128x: RADIOLIB_SX128X_REG_VERSION_STRING:"); + RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN(); + flagFound = true; + } else { + #if RADIOLIB_DEBUG_BASIC + RADIOLIB_DEBUG_BASIC_PRINTLN("SX128x not found! (%d of 10 tries) RADIOLIB_SX128X_REG_VERSION_STRING:", i + 1); + RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING); + RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr); + #endif + this->mod->hal->delay(10); + i++; + } + } + + return(flagFound); +} + #endif diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index d5f7f93590..cba802158c 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -57,6 +57,7 @@ #define RADIOLIB_SX128X_CMD_SET_ADVANCED_RANGING 0x9A // SX128X register map +#define RADIOLIB_SX128X_REG_VERSION_STRING 0x01F0 #define RADIOLIB_SX128X_REG_GAIN_MODE 0x0891 #define RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 #define RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING 0x089E @@ -907,7 +908,10 @@ class SX128x: public PhysicalLayer { #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif + const char* chipType = NULL; + Module* getMod() override; + int16_t modSetup(uint8_t modem); // cached LoRa parameters float bandwidthKhz = 0; @@ -967,6 +971,7 @@ class SX128x: public PhysicalLayer { // cached BLE parameters uint8_t connectionState = 0, crcBLE = 0, bleTestPayload = 0; + bool findChip(const char* verStr); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF); }; From b446fc1e9316abe10d737b2a2eaa8436ab389ba8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Oct 2025 11:14:53 +0100 Subject: [PATCH 1661/1848] [SX126x] Fix incorrect bit rate range check (#1636) --- src/modules/SX126x/SX126x_config.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 9b2887e042..3266756a92 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -224,7 +224,8 @@ int16_t SX126x::setBitRate(float br) { } if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) { - RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + // at the moment only the very specific 488.28125 bps rate is supported + RADIOLIB_CHECK_RANGE(br, 0.488f, 0.489f, RADIOLIB_ERR_INVALID_BIT_RATE); } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) { // this should be just either 100 or 600 bps, not the range // but the BPSK support is so experimental it probably does not matter From 217ab3c2431325abae591f6bcad63dcaecc7ca57 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Oct 2025 16:48:42 +0000 Subject: [PATCH 1662/1848] [LR2021] Add ranging and GFSK commands --- src/modules/LR2021/LR2021.h | 19 +++++ src/modules/LR2021/LR2021_cmds_gfsk.cpp | 96 ++++++++++++++++++++++ src/modules/LR2021/LR2021_cmds_lora.cpp | 4 +- src/modules/LR2021/LR2021_cmds_ranging.cpp | 68 +++++++++++++++ src/modules/LR2021/LR2021_commands.h | 66 +++++++++++++++ 5 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/modules/LR2021/LR2021_cmds_gfsk.cpp create mode 100644 src/modules/LR2021/LR2021_cmds_ranging.cpp diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index b2d23e5d01..98bcb501e6 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -136,6 +136,25 @@ class LR2021: public PhysicalLayer, public LRxxxx { int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, uint32_t* freqHops, size_t numFreqHops); int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum); int16_t setLoRaSideDetCad(uint8_t* pnrDelta, uint8_t* detPeak, size_t numSideDets); + + // ranging commands + int16_t setRangingAddr(uint32_t addr, uint8_t checkLen); + int16_t setRangingReqAddr(uint32_t addr); + int16_t getRangingResult(uint8_t type, uint32_t* rng1, uint8_t* rssi1, uint32_t* rng2); + int16_t getRangingStats(uint16_t* exchangeValid, uint16_t* requestValid, uint16_t* responseDone, uint16_t* timeout, uint16_t* requestDiscarded); + int16_t setRangingTxRxDelay(uint32_t delay); + int16_t setRangingParams(bool spyMode, uint8_t nbSymbols); + + // GFSK commands + int16_t setFskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); + int16_t setFskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree); + int16_t setFskWhiteningParams(uint8_t whitenType, uint16_t init); + int16_t setFskCrcParams(uint32_t poly, uint32_t init); + int16_t setFskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst); + int16_t setFskAddress(uint8_t addrNode, uint8_t addrBroadcast); + int16_t getFskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout); + int16_t getFskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); + }; #endif diff --git a/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/src/modules/LR2021/LR2021_cmds_gfsk.cpp new file mode 100644 index 0000000000..3f16a2f7ac --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_gfsk.cpp @@ -0,0 +1,96 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setFskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { + uint8_t buff[] = { + (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF), + (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF), + pulseShape, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), + (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setFskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree) { + uint8_t buff[] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), preambleDetect, + (uint8_t)(((uint8_t)longPreamble << 5) | ((uint8_t)pldLenBits << 4) | (addrComp << 2) | ((uint8_t)packetFormat & 0x03)), + (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF), + (uint8_t)((crc << 4) | (dcFree << 4)), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setFskWhiteningParams(uint8_t whitenType, uint16_t init) { + uint8_t buff[] = { + (uint8_t)((whitenType << 4) | (uint8_t)((init >> 8) & 0x0F)), + (uint8_t)(init & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setFskCrcParams(uint32_t poly, uint32_t init) { + uint8_t buff[] = { + (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF), + (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF), + (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF), + (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_CRC_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setFskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { + uint8_t buff[9] = { 0 }; + for(size_t i = 0; i < syncWordLen; i++) { + buff[7 - i] = syncWord[i]; + } + buff[8] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD, true, buff, sizeof(buff))); +} + +int16_t LR2021::setFskAddress(uint8_t addrNode, uint8_t addrBroadcast) { + uint8_t buff[] = { addrNode, addrBroadcast }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_ADDRESS, true, buff, sizeof(buff))); +} + +int16_t LR2021::getFskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout) { + uint8_t buff[14] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(packetCrcError) { *packetCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + if(preambleDet) { *preambleDet = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } + if(syncOk) { *syncOk = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; } + if(syncFail) { *syncFail = ((uint16_t)(buff[10]) << 8) | (uint16_t)buff[11]; } + if(timeout) { *timeout = ((uint16_t)(buff[12]) << 8) | (uint16_t)buff[13]; } + return(state); +} + +int16_t LR2021::getFskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { + uint8_t buff[6] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + uint16_t raw = 0; + if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(rssiAvg) { + raw = (uint16_t)buff[2] << 1; + raw |= (buff[4] & 0x04) >> 2; + *rssiAvg = (float)raw / -2.0f; + } + if(rssiSync) { + raw = (uint16_t)buff[3] << 1; + raw |= (buff[4] & 0x01); + *rssiSync = (float)raw / -2.0f; + } + if(addrMatchNode) { *addrMatchNode = (buff[4] & 0x10); } + if(addrMatchBroadcast) { *addrMatchBroadcast = (buff[4] & 0x20); } + if(lqi) { *lqi = buff[5] * 4.0f; } + return(state); +} + +#endif diff --git a/src/modules/LR2021/LR2021_cmds_lora.cpp b/src/modules/LR2021/LR2021_cmds_lora.cpp index cf92e9d551..7adf091323 100644 --- a/src/modules/LR2021/LR2021_cmds_lora.cpp +++ b/src/modules/LR2021/LR2021_cmds_lora.cpp @@ -74,7 +74,7 @@ int16_t LR2021::getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint } int16_t LR2021::getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket) { - uint8_t buff[9] = { 0 }; + uint8_t buff[6] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS, false, buff, sizeof(buff)); uint16_t raw = 0; if(crc) { *crc = (buff[0] & 0x10) >> 4; } @@ -83,10 +83,12 @@ int16_t LR2021::getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLe if(snrPacket) { *snrPacket = (float)((int8_t)buff[2]) / 4.0f; } if(rssiPacket) { raw = (uint16_t)buff[3] << 1; + raw |= (buff[5] & 0x02) >> 1; *rssiPacket = (float)raw / -2.0f; } if(rssiSignalPacket) { raw = (uint16_t)buff[4] << 1; + raw |= buff[5] & 0x01; *rssiSignalPacket = (float)raw / -2.0f; } return(state); diff --git a/src/modules/LR2021/LR2021_cmds_ranging.cpp b/src/modules/LR2021/LR2021_cmds_ranging.cpp new file mode 100644 index 0000000000..34f2832111 --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_ranging.cpp @@ -0,0 +1,68 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setRangingAddr(uint32_t addr, uint8_t checkLen) { + uint8_t buff[] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + checkLen, + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_ADDR, true, buff, sizeof(buff))); +} + +int16_t LR2021::setRangingReqAddr(uint32_t addr) { + uint8_t buff[] = { + (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), + (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff))); +} + +int16_t LR2021::getRangingResult(uint8_t type, uint32_t* rng1, uint8_t* rssi1, uint32_t* rng2) { + uint8_t reqBuff[] = { type }; + uint8_t rplBuff[7] = { 0 }; + + // TODO implement AGC gains readout + size_t rplLen = (type == RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW) ? 7 : 4; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, rplLen); + + if(rng1) { *rng1 = ((uint32_t)(rplBuff[0]) << 16) | ((uint32_t)(rplBuff[1]) << 8) | (uint32_t)rplBuff[2]; } + if(rssi1) { *rssi1 = rplBuff[3]; } + if(rng2 && (type == RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW_EXT)) { + *rng2 = ((uint32_t)(rplBuff[4]) << 16) | ((uint32_t)(rplBuff[5]) << 8) | (uint32_t)rplBuff[6]; + } + + return(state); +} + +int16_t LR2021::getRangingStats(uint16_t* exchangeValid, uint16_t* requestValid, uint16_t* responseDone, uint16_t* timeout, uint16_t* requestDiscarded) { + uint8_t buff[10] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANGING_STATS, false, buff, sizeof(buff)); + if(exchangeValid) { *exchangeValid = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(requestValid) { *requestValid = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(responseDone) { *responseDone = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + if(timeout) { *timeout = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; } + if(requestDiscarded) { *requestDiscarded = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; } + return(state); +} + +int16_t LR2021::setRangingTxRxDelay(uint32_t delay) { + uint8_t buff[] = { + (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF), + (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff))); +} + +int16_t LR2021::setRangingParams(bool spyMode, uint8_t nbSymbols) { + uint8_t buff[] = { (uint8_t)(((uint8_t)spyMode << 6) | (nbSymbols & 0x3F)) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS, true, buff, sizeof(buff))); +} + +#endif diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index a5cc323d21..694bb71182 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -400,6 +400,72 @@ #define RADIOLIB_LR2021_LORA_TX_SYNC_MASTER (0x01UL << 6) // 7 6 master (wait for signal to transmit sync frame) #define RADIOLIB_LR2021_LORA_TX_SYNC_SLAVE (0x02UL << 6) // 7 6 slave (output signal on sync frame) +// RADIOLIB_LR2021_CMD_GET_RANGING_RESULT +#define RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW (0x00UL << 0) // 7 0 ranging result type: raw +#define RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW_EXT (0x01UL << 0) // 7 0 extended raw +#define RADIOLIB_LR2021_RANGING_RESULT_TYPE_GAINS (0x02UL << 0) // 7 0 AGC gain steps + +// RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS +#define RADIOLIB_LR2021_FSK_BITRATE_BPS (0x00UL << 31) // 7 0 bitrate units: bits per second +#define RADIOLIB_LR2021_FSK_BITRATE_FRACTIONAL (0x01UL << 31) // 7 0 fractional (1/256 bps) +#define RADIOLIB_LR2021_FSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none +#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_2_0 (0x02UL << 0) // 7 0 Gaussian, BT = 2.0 +#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_0_3 (0x04UL << 0) // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_0_5 (0x05UL << 0) // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_0_7 (0x06UL << 0) // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_1_0 (0x07UL << 0) // 7 0 Gaussian, BT = 1.0 +// TODO implement the other bandwidths as well (and figure out a way how to calculate it) +#define RADIOLIB_LR2021_GFSK_RX_BW_4_8 (39) // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_5_8 (215) // 7 0 5.8 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_7_4 (87) // 7 0 7.4 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_9_7 (38) // 7 0 9.6 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_12_0 (30) // 7 0 12.0 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_14_9 (86) // 7 0 14.9 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_19_2 (37) // 7 0 19.2 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_23_1 (213) // 7 0 21.3 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_29_8 (85) // 7 0 29.8 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_38_5 (36) // 7 0 38.5 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_46_3 (212) // 7 0 46.3 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_59_5 (84) // 7 0 59.5 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_76_9 (35) // 7 0 76.9 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_92_6 (211) // 7 0 92.6 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_119_0 (83) // 7 0 119.0 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_153_8 (34) // 7 0 153.8 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_185_2 (210) // 7 0 185.2 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_238_1 (82) // 7 0 238.1 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_307_7 (33) // 7 0 307.7 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_370_4 (209) // 7 0 370.4 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_476_2 (81) // 7 0 476.2 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_555_6 (216) // 7 0 555.6 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_666_7 (152) // 7 0 666.7 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_769_2 (24) // 7 0 769.2 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_1111 (200) // 7 0 1111 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_2222 (192) // 7 0 2222 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_2666 (128) // 7 0 2667 kHz +#define RADIOLIB_LR2021_GFSK_RX_BW_3076 (0) // 7 0 3077 kHz + +// RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS +#define RADIOLIB_LR2021_GFSK_ADDR_FILT_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled +#define RADIOLIB_LR2021_GFSK_ADDR_FILT_NODE (0x01UL << 0) // 7 0 node only +#define RADIOLIB_LR2021_GFSK_ADDR_FILT_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast +#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_FIXED (0x00UL << 0) // 7 0 packet format: fixed length +#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_VARIABLE_8BIT (0x01UL << 0) // 7 0 variable, 8-bit length +#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_VARIABLE_9BIT (0x02UL << 0) // 7 0 variable, 9-bit length (for SX128x compatibility) +#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_VARIABLE_15BIT (0x03UL << 0) // 7 0 variable, 15-bit length +#define RADIOLIB_LR2021_GFSK_CRC_OFF (0x00UL << 0) // 7 0 CRC: disabled +#define RADIOLIB_LR2021_GFSK_CRC8 (0x01UL << 0) // 7 0 1-byte +#define RADIOLIB_LR2021_GFSK_CRC16 (0x02UL << 0) // 7 0 2-byte +#define RADIOLIB_LR2021_GFSK_CRC24 (0x03UL << 0) // 7 0 3-byte +#define RADIOLIB_LR2021_GFSK_CRC32 (0x04UL << 0) // 7 0 4-byte +#define RADIOLIB_LR2021_GFSK_CRC8_INV (0x09UL << 0) // 7 0 1-byte, inverted +#define RADIOLIB_LR2021_GFSK_CRC16_INV (0x0AUL << 0) // 7 0 2-byte, inverted +#define RADIOLIB_LR2021_GFSK_CRC24_INV (0x0BUL << 0) // 7 0 3-byte, inverted +#define RADIOLIB_LR2021_GFSK_CRC32_INV (0x0CUL << 0) // 7 0 4-byte, inverted + +// RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS +#define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR11x0 +#define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX128X (0x01UL << 0) // 7 0 compatible with SX128x + #endif #endif From fa4ca41bdb21e9431c88aed29b6b079eddc8fab1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Oct 2025 19:23:33 +0000 Subject: [PATCH 1663/1848] [LR2021] Add FLRC, OQPSK and BPSK commands --- src/modules/LR2021/LR2021.h | 17 +++++++ src/modules/LR2021/LR2021_cmds_flrc.cpp | 61 +++++++++++++++++++++++ src/modules/LR2021/LR2021_cmds_misc.cpp | 27 +++++++++++ src/modules/LR2021/LR2021_cmds_oqpsk.cpp | 62 ++++++++++++++++++++++++ src/modules/LR2021/LR2021_commands.h | 35 +++++++++++-- 5 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 src/modules/LR2021/LR2021_cmds_flrc.cpp create mode 100644 src/modules/LR2021/LR2021_cmds_misc.cpp create mode 100644 src/modules/LR2021/LR2021_cmds_oqpsk.cpp diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 98bcb501e6..0c5bb6dcf4 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -155,6 +155,23 @@ class LR2021: public PhysicalLayer, public LRxxxx { int16_t getFskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout); int16_t getFskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); + // OQPSK commands + int16_t setOqpskParams(uint8_t mode, uint8_t rxBw, uint8_t payloadLen, uint16_t preambleLen, bool addrFilt, bool fcsManual); + int16_t getOqpskRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError); + int16_t getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, float* rssiAvg, float* rssiSync, float* lqi); + int16_t setOqpskPacketLen(uint8_t len); + int16_t setOqpskAddress(uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId); + + // BPSK commands + int16_t setBpskModulationParams(uint32_t bitRate, uint8_t pulseShape, bool diff, uint8_t diffInit); + int16_t setBpskPacketParams(uint8_t payloadLen, uint8_t mode, bool sigFoxControlMsg, uint8_t sigFoxRank); + + // FLRC commands + int16_t setFlrcModulationParams(uint8_t brBw, uint8_t cr, uint8_t pulseShape); + int16_t setFlrcPacketParams(uint8_t agcPreambleLen, uint8_t syncWordLen, uint8_t syncWordTx, uint8_t syncMatch, bool fixedLength, uint8_t crc, uint16_t payloadLen); + int16_t getFlrcRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError); + int16_t getFlrcPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, uint8_t* syncWordNum); + int16_t setFlrcSyncWord(uint8_t syncWordNum, uint32_t syncWord); }; #endif diff --git a/src/modules/LR2021/LR2021_cmds_flrc.cpp b/src/modules/LR2021/LR2021_cmds_flrc.cpp new file mode 100644 index 0000000000..1c66d32373 --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_flrc.cpp @@ -0,0 +1,61 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setFlrcModulationParams(uint8_t brBw, uint8_t cr, uint8_t pulseShape) { + uint8_t buff[] = { brBw, (uint8_t)((cr << 4) | (pulseShape & 0x0F)) }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setFlrcPacketParams(uint8_t agcPreambleLen, uint8_t syncWordLen, uint8_t syncWordTx, uint8_t syncMatch, bool fixedLength, uint8_t crc, uint16_t payloadLen) { + uint8_t buff[] = { + (uint8_t)(((agcPreambleLen & 0x0F) << 2) | (syncWordLen / 2)), + (uint8_t)(((syncWordTx & 0x03) << 6) | ((syncMatch & 0x07) << 3) | ((uint8_t)fixedLength << 2) | (crc & 0x03)), + (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FLRC_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::getFlrcRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError) { + uint8_t buff[14] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FLRC_RX_STATS, false, buff, sizeof(buff)); + if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(packetCrcError) { *packetCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + return(state); +} + +int16_t LR2021::getFlrcPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, uint8_t* syncWordNum) { + uint8_t buff[5] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS, false, buff, sizeof(buff)); + uint16_t raw = 0; + if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(rssiAvg) { + raw = (uint16_t)buff[2] << 1; + raw |= (buff[4] & 0x04) >> 2; + *rssiAvg = (float)raw / -2.0f; + } + if(rssiSync) { + raw = (uint16_t)buff[3] << 1; + raw |= (buff[4] & 0x01); + *rssiSync = (float)raw / -2.0f; + } + if(syncWordNum) { *syncWordNum = (buff[4] & 0xF0) >> 4; } + return(state); +} + +int16_t LR2021::setFlrcSyncWord(uint8_t syncWordNum, uint32_t syncWord) { + uint8_t buff[] = { + syncWordNum, + (uint8_t)((syncWord >> 24) & 0xFF), (uint8_t)((syncWord >> 16) & 0xFF), + (uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FLRC_SYNCWORD, true, buff, sizeof(buff))); +} + +#endif diff --git a/src/modules/LR2021/LR2021_cmds_misc.cpp b/src/modules/LR2021/LR2021_cmds_misc.cpp new file mode 100644 index 0000000000..564fe7383a --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_misc.cpp @@ -0,0 +1,27 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setBpskModulationParams(uint32_t bitRate, uint8_t pulseShape, bool diff, uint8_t diffInit) { + uint8_t buff[] = { + (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF), + (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF), + (uint8_t)((pulseShape << 4) | ((uint8_t)diff << 2) | (diffInit & 0x03)), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_BPSK_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setBpskPacketParams(uint8_t payloadLen, uint8_t mode, bool sigFoxControlMsg, uint8_t sigFoxRank) { + uint8_t buff[] = { + payloadLen, + (uint8_t)((mode << 4) | ((uint8_t)sigFoxControlMsg << 2) | (sigFoxRank & 0x03)), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +#endif diff --git a/src/modules/LR2021/LR2021_cmds_oqpsk.cpp b/src/modules/LR2021/LR2021_cmds_oqpsk.cpp new file mode 100644 index 0000000000..2d7445e407 --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_oqpsk.cpp @@ -0,0 +1,62 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setOqpskParams(uint8_t mode, uint8_t rxBw, uint8_t payloadLen, uint16_t preambleLen, bool addrFilt, bool fcsManual) { + uint8_t buff[] = { + mode, rxBw, payloadLen, + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + (uint8_t)((uint8_t)addrFilt << 1 | (uint8_t)fcsManual), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::getOqpskRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError) { + uint8_t buff[6] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS, false, buff, sizeof(buff)); + if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(crcError) { *crcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + return(state); +} + +int16_t LR2021::getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, float* rssiAvg, float* rssiSync, float* lqi) { + uint8_t buff[7] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS, false, buff, sizeof(buff)); + if(rxHeader) { *rxHeader = buff[0]; } + if(payloadLen) { *payloadLen = ((uint16_t)(buff[1]) << 8) | (uint16_t)buff[2]; } + uint16_t raw = 0; + if(rssiAvg) { + raw = (uint16_t)buff[3] << 1; + raw |= (buff[5] & 0x04) >> 2; + *rssiAvg = (float)raw / -2.0f; + } + if(rssiSync) { + raw = (uint16_t)buff[4] << 1; + raw |= (buff[5] & 0x01); + *rssiSync = (float)raw / -2.0f; + } + if(lqi) { *lqi = buff[6] * 4.0f; } + return(state); +} + +int16_t LR2021::setOqpskPacketLen(uint8_t len) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN, true, &len, sizeof(len))); +} + +int16_t LR2021::setOqpskAddress(uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId) { + uint8_t buff[] = { + longDestAddr[7], longDestAddr[6], longDestAddr[5], longDestAddr[4], + longDestAddr[3], longDestAddr[2], longDestAddr[1], longDestAddr[0], + (uint8_t)((shortDestAddr >> 8) & 0xFF), (uint8_t)(shortDestAddr & 0xFF), + (uint8_t)((panId >> 8) & 0xFF), (uint8_t)(panId & 0xFF), transId, + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_ADDRESS, true, buff, sizeof(buff))); +} + +#endif diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 694bb71182..6bdf48829c 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -409,11 +409,15 @@ #define RADIOLIB_LR2021_FSK_BITRATE_BPS (0x00UL << 31) // 7 0 bitrate units: bits per second #define RADIOLIB_LR2021_FSK_BITRATE_FRACTIONAL (0x01UL << 31) // 7 0 fractional (1/256 bps) #define RADIOLIB_LR2021_FSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none -#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_2_0 (0x02UL << 0) // 7 0 Gaussian, BT = 2.0 -#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_0_3 (0x04UL << 0) // 7 0 Gaussian, BT = 0.3 -#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_0_5 (0x05UL << 0) // 7 0 Gaussian, BT = 0.5 -#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_0_7 (0x06UL << 0) // 7 0 Gaussian, BT = 0.7 -#define RADIOLIB_LR2021_FSK_SHAPING_GAUSS_BT_1_0 (0x07UL << 0) // 7 0 Gaussian, BT = 1.0 +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_2_0 (0x02UL << 0) // 7 0 Gaussian, BT = 2.0 +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_4 (0x03UL << 0) // 7 0 Root-Raised-Cosine with 0.4 roll-off +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_0_3 (0x04UL << 0) // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_0_5 (0x05UL << 0) // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_0_7 (0x06UL << 0) // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_1_0 (0x07UL << 0) // 7 0 Gaussian, BT = 1.0 +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_3 (0x08UL << 0) // 7 0 Root-Raised-Cosine with 0.3 roll-off +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_5 (0x09UL << 0) // 7 0 Root-Raised-Cosine with 0.5 roll-off +#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_7 (0x0AUL << 0) // 7 0 Root-Raised-Cosine with 0.7 roll-off // TODO implement the other bandwidths as well (and figure out a way how to calculate it) #define RADIOLIB_LR2021_GFSK_RX_BW_4_8 (39) // 7 0 GFSK Rx bandwidth: 4.8 kHz #define RADIOLIB_LR2021_GFSK_RX_BW_5_8 (215) // 7 0 5.8 kHz @@ -466,6 +470,27 @@ #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR11x0 #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX128X (0x01UL << 0) // 7 0 compatible with SX128x +// RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS +#define RADIOLIB_LR2021_OQPSK_TYPE_15_4 (0x00UL << 0) // 7 0 OQPSK type: 802.15.4 PHY, 250 kbps bit rate + +// RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS +#define RADIOLIB_LR2021_BPSK_MODE_RAW (0x00UL << 0) // 7 0 encoding mode: raw +#define RADIOLIB_LR2021_BPSK_MODE_SIGFOX (0x01UL << 0) // 7 0 SigFox PHY + +// RADIOLIB_LR2021_CMD_SET_FLRC_MODULATION_PARAMS +#define RADIOLIB_LR2021_FLRC_BR_2600 (0x00UL << 0) // 7 0 bitrate/bandwidth: 2600 kbps, 2666 kHz +#define RADIOLIB_LR2021_FLRC_BR_2080 (0x01UL << 0) // 7 0 2080 kbps, 2222 kHz +#define RADIOLIB_LR2021_FLRC_BR_1300 (0x02UL << 0) // 7 0 1300 kbps, 1333 kHz +#define RADIOLIB_LR2021_FLRC_BR_1040 (0x03UL << 0) // 7 0 1040 kbps, 1333 kHz +#define RADIOLIB_LR2021_FLRC_BR_650 (0x04UL << 0) // 7 0 650 kbps, 888 kHz +#define RADIOLIB_LR2021_FLRC_BR_520 (0x05UL << 0) // 7 0 520 kbps, 769 kHz +#define RADIOLIB_LR2021_FLRC_BR_325 (0x06UL << 0) // 7 0 325 kbps, 444 kHz +#define RADIOLIB_LR2021_FLRC_BR_260 (0x07UL << 0) // 7 0 260 kbps, 444 kHz +#define RADIOLIB_LR2021_FLRC_CR_1_2 (0x00UL << 0) // 7 0 coding rate: 1/2 +#define RADIOLIB_LR2021_FLRC_CR_3_4 (0x01UL << 0) // 7 0 3/4 +#define RADIOLIB_LR2021_FLRC_CR_1_0 (0x02UL << 0) // 7 0 1 (uncoded) +#define RADIOLIB_LR2021_FLRC_CR_2_3 (0x03UL << 0) // 7 0 2/3 + #endif #endif From 482eaea059ade54254148a7d591e9cea77b76d86 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Oct 2025 19:27:11 +0000 Subject: [PATCH 1664/1848] [LR2021] Add LR-FHSS and OOK commands --- src/modules/LR11x0/LR1110.h | 6 +- src/modules/LR11x0/LR1120.h | 6 +- src/modules/LR11x0/LR11x0.cpp | 26 ++--- src/modules/LR11x0/LR11x0.h | 1 - src/modules/LR11x0/LR11x0_commands.cpp | 39 -------- src/modules/LR11x0/LR11x0_commands.h | 25 ----- src/modules/LR11x0/LR_common.cpp | 41 ++++++++ src/modules/LR11x0/LR_common.h | 32 +++++- src/modules/LR2021/LR2021.h | 20 ++++ src/modules/LR2021/LR2021_cmds_misc.cpp | 12 +++ src/modules/LR2021/LR2021_cmds_ook.cpp | 92 ++++++++++++++++++ src/modules/LR2021/LR2021_commands.h | 123 +++++++++++++----------- src/modules/LR2021/LR2021_types.h | 24 +++++ 13 files changed, 305 insertions(+), 142 deletions(-) create mode 100644 src/modules/LR2021/LR2021_cmds_ook.cpp create mode 100644 src/modules/LR2021/LR2021_types.h diff --git a/src/modules/LR11x0/LR1110.h b/src/modules/LR11x0/LR1110.h index 05067e52f5..d5943c531a 100644 --- a/src/modules/LR11x0/LR1110.h +++ b/src/modules/LR11x0/LR1110.h @@ -57,8 +57,8 @@ class LR1110: public LR11x0 { /*! \brief Initialization method for LR-FHSS modem. \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz. - \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. \param power Output power in dBm. Defaults to 10 dBm. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. @@ -66,7 +66,7 @@ class LR1110: public LR11x0 { To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. \returns \ref status_codes */ - int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); // configuration methods diff --git a/src/modules/LR11x0/LR1120.h b/src/modules/LR11x0/LR1120.h index 14cd4f3d31..09d9497ea0 100644 --- a/src/modules/LR11x0/LR1120.h +++ b/src/modules/LR11x0/LR1120.h @@ -57,8 +57,8 @@ class LR1120: public LR11x0 { /*! \brief Initialization method for LR-FHSS modem. \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz. - \param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. \param power Output power in dBm. Defaults to 10 dBm. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. @@ -66,7 +66,7 @@ class LR1120: public LR11x0 { To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. \returns \ref status_codes */ - int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); // configuration methods diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 97a82e6a2c..fe569196c7 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -103,7 +103,7 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV RADIOLIB_ASSERT(state); // set grid spacing - this->lrFhssGrid = narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC; + this->lrFhssGrid = narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC; // configure publicly accessible settings state = setLrFhssConfig(bw, cr); @@ -1002,7 +1002,7 @@ int16_t LR11x0::setDataRate(DataRate_t dr, ModemType_t modem) { RADIOLIB_ASSERT(state); // set hopping grid - this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC; + this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC; } @@ -1262,16 +1262,16 @@ RadioLibTime_t LR11x0::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, Pack // calculate the number of bits based on coding rate uint16_t N_bits; switch(dr.lrFhss.cr) { - case RADIOLIB_LR11X0_LR_FHSS_CR_5_6: + case RADIOLIB_LRXXXX_LR_FHSS_CR_5_6: N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? break; - case RADIOLIB_LR11X0_LR_FHSS_CR_2_3: + case RADIOLIB_LRXXXX_LR_FHSS_CR_2_3: N_bits = (len * 3) / 2; break; - case RADIOLIB_LR11X0_LR_FHSS_CR_1_2: + case RADIOLIB_LRXXXX_LR_FHSS_CR_1_2: N_bits = len * 2; break; - case RADIOLIB_LR11X0_LR_FHSS_CR_1_3: + case RADIOLIB_LRXXXX_LR_FHSS_CR_1_3: N_bits = len * 3; break; default: @@ -1279,14 +1279,14 @@ RadioLibTime_t LR11x0::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, Pack } // calculate number of bits when accounting for unaligned last block - uint16_t N_payBits = (N_bits / RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS) * RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS; - uint16_t N_lastBlockBits = N_bits % RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS; + uint16_t N_payBits = (N_bits / RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS) * RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS; + uint16_t N_lastBlockBits = N_bits % RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS; if(N_lastBlockBits) { N_payBits += N_lastBlockBits + 2; } // add header bits - uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits; + uint16_t N_totalBits = (RADIOLIB_LRXXXX_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits; return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); } else { @@ -1342,7 +1342,7 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { case ModemType_t::RADIOLIB_MODEM_LRFHSS: { dr.lrFhss.bw = this->lrFhssBw; dr.lrFhss.cr = this->lrFhssCr; - dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC) ? true : false; + dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC) ? true : false; pc.lrFhss.hdrCount = this->lrFhssHdrCount; break; @@ -1482,9 +1482,9 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16 } // check and cache all parameters - RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE); this->lrFhssCr = cr; - RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH); this->lrFhssBw = bw; RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE); this->lrFhssHdrCount = hdrCount; @@ -1666,7 +1666,7 @@ int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) { // in LR-FHSS mode, the packet is built by the device // TODO add configurable device offset - state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len); + state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len); RADIOLIB_ASSERT(state); } else { diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index dd409cc941..63a86ab722 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -876,7 +876,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { int16_t setRangingParameter(uint8_t symbolNum); int16_t setRssiCalibration(const int8_t* tune, int16_t gainOffset); int16_t setLoRaSyncWord(uint8_t sync); - int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); int16_t lrFhssSetSyncWord(uint32_t sync); int16_t configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len); int16_t bleBeaconSend(uint8_t chan, const uint8_t* payload, size_t len); diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index f938c38a87..200200284a 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -662,45 +662,6 @@ int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff))); } -int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len) { - // check maximum size - const uint8_t maxLen[4][4] = { - { 189, 178, 167, 155, }, - { 151, 142, 133, 123, }, - { 112, 105, 99, 92, }, - { 74, 69, 65, 60, }, - }; - if((cr > RADIOLIB_LR11X0_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) { - return(RADIOLIB_ERR_SPI_CMD_INVALID); - } - - // build buffers - size_t buffLen = 9 + len; - #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[9 + 190]; - #else - uint8_t* dataBuff = new uint8_t[buffLen]; - #endif - - // set properties of the packet - dataBuff[0] = hdrCount; - dataBuff[1] = cr; - dataBuff[2] = RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK; - dataBuff[3] = grid; - dataBuff[4] = (uint8_t)hop; - dataBuff[5] = bw; - dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01); - dataBuff[7] = (uint8_t)(hopSeq & 0xFF); - dataBuff[8] = devOffset; - memcpy(&dataBuff[9], payload, len); - - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen); - #if !RADIOLIB_STATIC_ONLY - delete[] dataBuff; - #endif - return(state); -} - int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) { uint8_t buff[4] = { (uint8_t)((sync >> 24) & 0xFF), (uint8_t)((sync >> 16) & 0xFF), diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index d0c0d18afa..f4050ca4c0 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -481,31 +481,6 @@ #define RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12) #define RADIOLIB_LR11X0_LORA_SYNC_WORD_PUBLIC (0x34) -// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME -#define RADIOLIB_LR11X0_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 -#define RADIOLIB_LR11X0_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 -#define RADIOLIB_LR11X0_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 -#define RADIOLIB_LR11X0_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 -#define RADIOLIB_LR11X0_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK -#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) -#define RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) -#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled -#define RADIOLIB_LR11X0_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled -#define RADIOLIB_LR11X0_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz -#define RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header -#define RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment -#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble -#define RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS (RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS + RADIOLIB_LR11X0_LR_FHSS_BLOCK_PREAMBLE_BITS) - // RADIOLIB_LR11X0_CMD_GET_LORA_RX_HEADER_INFOS #define RADIOLIB_LR11X0_LAST_HEADER_CRC_ENABLED (0x01UL << 4) // 4 4 last header CRC: enabled #define RADIOLIB_LR11X0_LAST_HEADER_CRC_DISABLED (0x00UL << 4) // 4 4 disabled diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index c55475e580..325a4ec1c3 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -1,5 +1,7 @@ #include "LR_common.h" +#include + LRxxxx::LRxxxx(Module* mod) { this->mod = mod; } @@ -20,6 +22,45 @@ int16_t LRxxxx::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { return(state); } +int16_t LRxxxx::lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len) { + // check maximum size + const uint8_t maxLen[4][4] = { + { 189, 178, 167, 155, }, + { 151, 142, 133, 123, }, + { 112, 105, 99, 92, }, + { 74, 69, 65, 60, }, + }; + if((cr > RADIOLIB_LRXXXX_LR_FHSS_CR_1_3) || ((hdrCount - 1) > (int)sizeof(maxLen[0])) || (len > maxLen[cr][hdrCount - 1])) { + return(RADIOLIB_ERR_SPI_CMD_INVALID); + } + + // build buffers + size_t buffLen = 9 + len; + #if RADIOLIB_STATIC_ONLY + uint8_t dataBuff[9 + 190]; + #else + uint8_t* dataBuff = new uint8_t[buffLen]; + #endif + + // set properties of the packet + dataBuff[0] = hdrCount; + dataBuff[1] = cr; + dataBuff[2] = RADIOLIB_LRXXXX_LR_FHSS_MOD_TYPE_GMSK; + dataBuff[3] = grid; + dataBuff[4] = hop; + dataBuff[5] = bw; + dataBuff[6] = (uint8_t)((hopSeq >> 8) & 0x01); + dataBuff[7] = (uint8_t)(hopSeq & 0xFF); + dataBuff[8] = devOffset; + memcpy(&dataBuff[9], payload, len); + + int16_t state = this->SPIcommand(cmd, true, dataBuff, buffLen); + #if !RADIOLIB_STATIC_ONLY + delete[] dataBuff; + #endif + return(state); +} + int16_t LRxxxx::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_LRXXXX_STAT_1_CMD_PERR) { return(RADIOLIB_ERR_SPI_CMD_INVALID); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index cafddd156b..c7f6623fd0 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -6,12 +6,41 @@ #define RADIOLIB_LRXXXX_CMD_NOP (0x0000) #define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (256) -// RADIOLIB_LR11X0_CMD_GET_STATUS MSB LSB DESCRIPTION +// RADIOLIB_LR11X0_CMD_GET_STATUS +// RADIOLIB_LR2021_CMD_GET_STATUS MSB LSB DESCRIPTION #define RADIOLIB_LRXXXX_STAT_1_CMD_FAIL (0x00UL << 1) // 3 1 command status: last command could not be executed #define RADIOLIB_LRXXXX_STAT_1_CMD_PERR (0x01UL << 1) // 3 1 processing error #define RADIOLIB_LRXXXX_STAT_1_CMD_OK (0x02UL << 1) // 3 1 successfully processed #define RADIOLIB_LRXXXX_STAT_1_CMD_DAT (0x03UL << 1) // 3 1 successfully processed, data is being transmitted +// RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME +// RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME +#define RADIOLIB_LRXXXX_LR_FHSS_CR_5_6 (0x00UL << 0) // 7 0 LR FHSS coding rate: 5/6 +#define RADIOLIB_LRXXXX_LR_FHSS_CR_2_3 (0x01UL << 0) // 7 0 2/3 +#define RADIOLIB_LRXXXX_LR_FHSS_CR_1_2 (0x02UL << 0) // 7 0 1/2 +#define RADIOLIB_LRXXXX_LR_FHSS_CR_1_3 (0x03UL << 0) // 7 0 1/3 +#define RADIOLIB_LRXXXX_LR_FHSS_MOD_TYPE_GMSK (0x00UL << 0) // 7 0 LR FHSS modulation: GMSK +#define RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC (0x00UL << 0) // 7 0 LR FHSS step size: 25.390625 kHz (FCC) +#define RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC (0x01UL << 0) // 7 0 3.90625 kHz (non-FCC) +#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_DISABLED (0x00UL << 0) // 7 0 LR FHSS hopping: disabled +#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_ENABLED (0x01UL << 0) // 7 0 enabled +#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_TEST_NO_HOP (0x02UL << 0) // 7 0 test mode (packet encoded, no hopping) +#define RADIOLIB_LRXXXX_LR_FHSS_HOPPING_TEST_PA_RAMP (0x03UL << 0) // 7 0 test mode (PA ramp up, no hopping) +#define RADIOLIB_LRXXXX_LR_FHSS_BW_39_06 (0x00UL << 0) // 7 0 LR FHSS bandwidth: 39.06 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_85_94 (0x01UL << 0) // 7 0 85.94 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_136_72 (0x02UL << 0) // 7 0 136.72 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_183_59 (0x03UL << 0) // 7 0 183.59 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_335_94 (0x04UL << 0) // 7 0 335.94 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_386_72 (0x05UL << 0) // 7 0 386.72 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_722_66 (0x06UL << 0) // 7 0 722.66 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_773_44 (0x07UL << 0) // 7 0 773.44 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_1523_4 (0x08UL << 0) // 7 0 1523.4 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2 (0x09UL << 0) // 7 0 1574.2 kHz +#define RADIOLIB_LRXXXX_LR_FHSS_HEADER_BITS (114) // 7 0 LR FHSS packet bit widths: header +#define RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS (48) // 7 0 payload fragment +#define RADIOLIB_LRXXXX_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble +#define RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS (RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS + RADIOLIB_LRXXXX_LR_FHSS_BLOCK_PREAMBLE_BITS) + class LRxxxx { public: LRxxxx(Module* mod); @@ -22,6 +51,7 @@ class LRxxxx { // will actually increase the binary size, because of the extra method calls that are needed // for that reason, only the methods that are 100% the same are kept here int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); + int16_t lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 0c5bb6dcf4..725fa06076 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -10,6 +10,7 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" #include "../LR11x0/LR_common.h" #include "LR2021_commands.h" +#include "LR2021_types.h" // LR2021 physical layer properties #define RADIOLIB_LR2021_FREQUENCY_STEP_SIZE 1.0 @@ -172,6 +173,25 @@ class LR2021: public PhysicalLayer, public LRxxxx { int16_t getFlrcRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError); int16_t getFlrcPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, uint8_t* syncWordNum); int16_t setFlrcSyncWord(uint8_t syncWordNum, uint32_t syncWord); + + // LR-FHSS commands + int16_t lrFhssSetSyncword(uint32_t syncWord); + //! \TODO: [LR2021] Implement reading/writing LR-FHSS hopping table + //int16_t readLrFhssHoppingTable(LR2021LrFhssHopTableEntry_t* hopTable[40], size_t* hopTableLen); + //int16_t writeLrFhssHoppingTable(LR2021LrFhssHopTableEntry_t* hopTable[40], size_t hopTableLen); + + // OOK commands + int16_t setOokModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint8_t depth); + int16_t setOokPacketParams(uint16_t preambleLen, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t manchester); + int16_t setOokCrcParams(uint32_t poly, uint32_t init); + int16_t setOokSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst); + int16_t setOokAddress(uint8_t addrNode, uint8_t addrBroadcast); + int16_t getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError); + int16_t getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); + int16_t setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uint8_t patternNumRepeaters, bool syncWordRaw, bool sofDelimiterRising, uint8_t sofDelimiterLen); + + // test commands + int16_t setTxTestMode(uint8_t mode); }; #endif diff --git a/src/modules/LR2021/LR2021_cmds_misc.cpp b/src/modules/LR2021/LR2021_cmds_misc.cpp index 564fe7383a..302b441cc5 100644 --- a/src/modules/LR2021/LR2021_cmds_misc.cpp +++ b/src/modules/LR2021/LR2021_cmds_misc.cpp @@ -24,4 +24,16 @@ int16_t LR2021::setBpskPacketParams(uint8_t payloadLen, uint8_t mode, bool sigFo return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_BPSK_PACKET_PARAMS, true, buff, sizeof(buff))); } +int16_t LR2021::lrFhssSetSyncword(uint32_t syncWord) { + uint8_t buff[] = { + (uint8_t)((syncWord >> 24) & 0xFF), (uint8_t)((syncWord >> 16) & 0xFF), + (uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD, true, buff, sizeof(buff))); +} + +int16_t LR2021::setTxTestMode(uint8_t mode) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE, true, &mode, sizeof(mode))); +} + #endif diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp new file mode 100644 index 0000000000..78c25f6f4c --- /dev/null +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -0,0 +1,92 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setOokModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint8_t depth) { + uint8_t buff[] = { + (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF), + (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF), + pulseShape, rxBw, depth, + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setOokPacketParams(uint16_t preambleLen, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t manchester) { + uint8_t buff[] = { + (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), + (uint8_t)((addrComp << 2) | ((uint8_t)packetFormat & 0x03)), + (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF), + (uint8_t)((crc << 4) | (manchester << 4)), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setOokCrcParams(uint32_t poly, uint32_t init) { + uint8_t buff[] = { + (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF), + (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF), + (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF), + (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS, true, buff, sizeof(buff))); +} + +int16_t LR2021::setOokSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { + uint8_t buff[5] = { 0 }; + for(size_t i = 0; i < syncWordLen; i++) { + buff[3 - i] = syncWord[i]; + } + buff[4] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD, true, buff, sizeof(buff))); +} + +int16_t LR2021::setOokAddress(uint8_t addrNode, uint8_t addrBroadcast) { + uint8_t buff[] = { addrNode, addrBroadcast }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_ADDRESS, true, buff, sizeof(buff))); +} + +int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError) { + uint8_t buff[6] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(crcError) { *crcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } + if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } + return(state); +} + +int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { + uint8_t buff[6] = { 0 }; + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + uint16_t raw = 0; + if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } + if(rssiAvg) { + raw = (uint16_t)buff[2] << 1; + raw |= (buff[4] & 0x04) >> 2; + *rssiAvg = (float)raw / -2.0f; + } + if(rssiSync) { + raw = (uint16_t)buff[3] << 1; + raw |= (buff[4] & 0x01); + *rssiSync = (float)raw / -2.0f; + } + if(addrMatchNode) { *addrMatchNode = (buff[4] & 0x10); } + if(addrMatchBroadcast) { *addrMatchBroadcast = (buff[4] & 0x20); } + if(lqi) { *lqi = buff[5] * 4.0f; } + return(state); +} + +int16_t LR2021::setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uint8_t patternNumRepeaters, bool syncWordRaw, bool sofDelimiterRising, uint8_t sofDelimiterLen) { + uint8_t buff[] = { + (uint8_t)((preamblePattern >> 8) & 0xFF), (uint8_t)(preamblePattern & 0xFF), + (uint8_t)(patternLen & 0x0F), (uint8_t)(patternNumRepeaters & 0x1F), + (uint8_t)(((uint8_t)syncWordRaw << 5) | ((uint8_t)sofDelimiterRising << 4) | (sofDelimiterLen & 0x0F)), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS, true, buff, sizeof(buff))); +} + +#endif diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 6bdf48829c..121ba79898 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -406,68 +406,68 @@ #define RADIOLIB_LR2021_RANGING_RESULT_TYPE_GAINS (0x02UL << 0) // 7 0 AGC gain steps // RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS -#define RADIOLIB_LR2021_FSK_BITRATE_BPS (0x00UL << 31) // 7 0 bitrate units: bits per second -#define RADIOLIB_LR2021_FSK_BITRATE_FRACTIONAL (0x01UL << 31) // 7 0 fractional (1/256 bps) -#define RADIOLIB_LR2021_FSK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_2_0 (0x02UL << 0) // 7 0 Gaussian, BT = 2.0 -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_4 (0x03UL << 0) // 7 0 Root-Raised-Cosine with 0.4 roll-off -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_0_3 (0x04UL << 0) // 7 0 Gaussian, BT = 0.3 -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_0_5 (0x05UL << 0) // 7 0 Gaussian, BT = 0.5 -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_0_7 (0x06UL << 0) // 7 0 Gaussian, BT = 0.7 -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_GAUSS_BT_1_0 (0x07UL << 0) // 7 0 Gaussian, BT = 1.0 -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_3 (0x08UL << 0) // 7 0 Root-Raised-Cosine with 0.3 roll-off -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_5 (0x09UL << 0) // 7 0 Root-Raised-Cosine with 0.5 roll-off -#define RADIOLIB_LR2021_FSK_BPSK_FLRC_SHAPING_RRC_ROLLOFF_0_7 (0x0AUL << 0) // 7 0 Root-Raised-Cosine with 0.7 roll-off +#define RADIOLIB_LR2021_GFSK_BPSK_OOK_BITRATE_BPS (0x00UL << 31) // 7 0 bitrate units: bits per second +#define RADIOLIB_LR2021_GFSK_BPSK_OOK_BITRATE_FRACTIONAL (0x01UL << 31) // 7 0 fractional (1/256 bps) +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_2_0 (0x02UL << 0) // 7 0 Gaussian, BT = 2.0 +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_4 (0x03UL << 0) // 7 0 Root-Raised-Cosine with 0.4 roll-off +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3 (0x04UL << 0) // 7 0 Gaussian, BT = 0.3 +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5 (0x05UL << 0) // 7 0 Gaussian, BT = 0.5 +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7 (0x06UL << 0) // 7 0 Gaussian, BT = 0.7 +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0 (0x07UL << 0) // 7 0 Gaussian, BT = 1.0 +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_3 (0x08UL << 0) // 7 0 Root-Raised-Cosine with 0.3 roll-off +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_5 (0x09UL << 0) // 7 0 Root-Raised-Cosine with 0.5 roll-off +#define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_RRC_ROLLOFF_0_7 (0x0AUL << 0) // 7 0 Root-Raised-Cosine with 0.7 roll-off // TODO implement the other bandwidths as well (and figure out a way how to calculate it) -#define RADIOLIB_LR2021_GFSK_RX_BW_4_8 (39) // 7 0 GFSK Rx bandwidth: 4.8 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_5_8 (215) // 7 0 5.8 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_7_4 (87) // 7 0 7.4 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_9_7 (38) // 7 0 9.6 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_12_0 (30) // 7 0 12.0 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_14_9 (86) // 7 0 14.9 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_19_2 (37) // 7 0 19.2 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_23_1 (213) // 7 0 21.3 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_29_8 (85) // 7 0 29.8 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_38_5 (36) // 7 0 38.5 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_46_3 (212) // 7 0 46.3 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_59_5 (84) // 7 0 59.5 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_76_9 (35) // 7 0 76.9 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_92_6 (211) // 7 0 92.6 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_119_0 (83) // 7 0 119.0 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_153_8 (34) // 7 0 153.8 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_185_2 (210) // 7 0 185.2 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_238_1 (82) // 7 0 238.1 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_307_7 (33) // 7 0 307.7 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_370_4 (209) // 7 0 370.4 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_476_2 (81) // 7 0 476.2 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_555_6 (216) // 7 0 555.6 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_666_7 (152) // 7 0 666.7 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_769_2 (24) // 7 0 769.2 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_1111 (200) // 7 0 1111 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_2222 (192) // 7 0 2222 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_2666 (128) // 7 0 2667 kHz -#define RADIOLIB_LR2021_GFSK_RX_BW_3076 (0) // 7 0 3077 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8 (39) // 7 0 GFSK Rx bandwidth: 4.8 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8 (215) // 7 0 5.8 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4 (87) // 7 0 7.4 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7 (38) // 7 0 9.6 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0 (30) // 7 0 12.0 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9 (86) // 7 0 14.9 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2 (37) // 7 0 19.2 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1 (213) // 7 0 21.3 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8 (85) // 7 0 29.8 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5 (36) // 7 0 38.5 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3 (212) // 7 0 46.3 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5 (84) // 7 0 59.5 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9 (35) // 7 0 76.9 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6 (211) // 7 0 92.6 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0 (83) // 7 0 119.0 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8 (34) // 7 0 153.8 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2 (210) // 7 0 185.2 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1 (82) // 7 0 238.1 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7 (33) // 7 0 307.7 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4 (209) // 7 0 370.4 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2 (81) // 7 0 476.2 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6 (216) // 7 0 555.6 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7 (152) // 7 0 666.7 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2 (24) // 7 0 769.2 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111 (200) // 7 0 1111 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222 (192) // 7 0 2222 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666 (128) // 7 0 2667 kHz +#define RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076 (0) // 7 0 3077 kHz // RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS -#define RADIOLIB_LR2021_GFSK_ADDR_FILT_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled -#define RADIOLIB_LR2021_GFSK_ADDR_FILT_NODE (0x01UL << 0) // 7 0 node only -#define RADIOLIB_LR2021_GFSK_ADDR_FILT_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast -#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_FIXED (0x00UL << 0) // 7 0 packet format: fixed length -#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_VARIABLE_8BIT (0x01UL << 0) // 7 0 variable, 8-bit length -#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_VARIABLE_9BIT (0x02UL << 0) // 7 0 variable, 9-bit length (for SX128x compatibility) -#define RADIOLIB_LR2021_GFSK_PACKET_FORMAT_VARIABLE_15BIT (0x03UL << 0) // 7 0 variable, 15-bit length -#define RADIOLIB_LR2021_GFSK_CRC_OFF (0x00UL << 0) // 7 0 CRC: disabled -#define RADIOLIB_LR2021_GFSK_CRC8 (0x01UL << 0) // 7 0 1-byte -#define RADIOLIB_LR2021_GFSK_CRC16 (0x02UL << 0) // 7 0 2-byte -#define RADIOLIB_LR2021_GFSK_CRC24 (0x03UL << 0) // 7 0 3-byte -#define RADIOLIB_LR2021_GFSK_CRC32 (0x04UL << 0) // 7 0 4-byte -#define RADIOLIB_LR2021_GFSK_CRC8_INV (0x09UL << 0) // 7 0 1-byte, inverted -#define RADIOLIB_LR2021_GFSK_CRC16_INV (0x0AUL << 0) // 7 0 2-byte, inverted -#define RADIOLIB_LR2021_GFSK_CRC24_INV (0x0BUL << 0) // 7 0 3-byte, inverted -#define RADIOLIB_LR2021_GFSK_CRC32_INV (0x0CUL << 0) // 7 0 4-byte, inverted +#define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled +#define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE (0x01UL << 0) // 7 0 node only +#define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast +#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED (0x00UL << 0) // 7 0 packet format: fixed length +#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT (0x01UL << 0) // 7 0 variable, 8-bit length +#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_9BIT (0x02UL << 0) // 7 0 variable, 9-bit length (for SX128x compatibility) +#define RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_15BIT (0x03UL << 0) // 7 0 variable, 15-bit length +#define RADIOLIB_LR2021_GFSK_OOK_CRC_OFF (0x00UL << 0) // 7 0 CRC: disabled +#define RADIOLIB_LR2021_GFSK_OOK_CRC8 (0x01UL << 0) // 7 0 1-byte +#define RADIOLIB_LR2021_GFSK_OOK_CRC16 (0x02UL << 0) // 7 0 2-byte +#define RADIOLIB_LR2021_GFSK_OOK_CRC24 (0x03UL << 0) // 7 0 3-byte +#define RADIOLIB_LR2021_GFSK_OOK_CRC32 (0x04UL << 0) // 7 0 4-byte +#define RADIOLIB_LR2021_GFSK_OOK_CRC8_INV (0x09UL << 0) // 7 0 1-byte, inverted +#define RADIOLIB_LR2021_GFSK_OOK_CRC16_INV (0x0AUL << 0) // 7 0 2-byte, inverted +#define RADIOLIB_LR2021_GFSK_OOK_CRC24_INV (0x0BUL << 0) // 7 0 3-byte, inverted +#define RADIOLIB_LR2021_GFSK_OOK_CRC32_INV (0x0CUL << 0) // 7 0 4-byte, inverted // RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS -#define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR11x0 +#define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR2021 #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX128X (0x01UL << 0) // 7 0 compatible with SX128x // RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS @@ -491,6 +491,15 @@ #define RADIOLIB_LR2021_FLRC_CR_1_0 (0x02UL << 0) // 7 0 1 (uncoded) #define RADIOLIB_LR2021_FLRC_CR_2_3 (0x03UL << 0) // 7 0 2/3 +// RADIOLIB_LR2021_CMD_SET_OOK_MODULATION_PARAMS +#define RADIOLIB_LR2021_OOK_DEPTH_FULL (0x00UL << 0) // 7 0 magnitude depth: limited by the PA +#define RADIOLIB_LR2021_OOK_DEPTH_20_DB (0x01UL << 0) // 7 0 20 dB maximum + +// RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS +#define RADIOLIB_LR2021_OOK_MANCHESTER_OFF (0x00UL << 0) // 3 0 Manchester encoding: disabled +#define RADIOLIB_LR2021_OOK_MANCHESTER_ON (0x01UL << 0) // 3 0 enabled +#define RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV (0x03UL << 0) // 3 0 enabled, inverted + #endif #endif diff --git a/src/modules/LR2021/LR2021_types.h b/src/modules/LR2021/LR2021_types.h new file mode 100644 index 0000000000..1097047ddb --- /dev/null +++ b/src/modules/LR2021/LR2021_types.h @@ -0,0 +1,24 @@ +#if !defined(RADIOLIB_LR2021_TYPES_H) +#define RADIOLIB_LR2021_TYPES_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_LR2021 + +/*! + \struct LR2021LrFhssHopTableEntry_t + \brief Structure to save information about LR-FHSS hopping table entry. +*/ +struct LR2021LrFhssHopTableEntry_t { + bool hoppingEnable; + bool convertFreq; + uint16_t packetLen; + uint8_t numUsedFrequencies; + uint8_t numHoppingBlocks; + uint32_t freq; + uint16_t numSymbols; +}; + +#endif + +#endif From faa0afb4974b7a82a3c634c7414570ebea057e46 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Nov 2025 15:58:26 +0000 Subject: [PATCH 1665/1848] [Utils] Add generic (de)scrambler function --- src/utils/Utils.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++ src/utils/Utils.h | 15 ++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 7daa7fdf6d..e384ac6118 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -15,6 +15,55 @@ uint32_t rlb_reflect(uint32_t in, uint8_t bits) { return(res); } +// fast-ish popcount function for use in calculating LFSR feedback value +// without relying on __builtin_popcount() which may or may not be available +// from https://stackoverflow.com/a/51388846 +static uint8_t rlb_popcount(uint32_t in) { + in = (in & 0x55555555UL) + ((in >> 1) & 0x55555555UL); + in = (in & 0x33333333UL) + ((in >> 2) & 0x33333333UL); + in = (in & 0x0F0F0F0FUL) + ((in >> 4) & 0x0F0F0F0FUL); + in = (in & 0x00FF00FFUL) + ((in >> 8) & 0x00FF00FFUL); + in = (in & 0x0000FFFFUL) + ((in >>16) & 0x0000FFFFUL); + return(in); +} + +void rlb_scrambler(uint8_t* data, size_t len, const uint32_t poly, const uint32_t init, bool scramble) { + if(!poly) { + return; + } + + // set the inital feedback register state + uint32_t lsfr = init; + + // now do the shifting + uint8_t out = 0; + for(size_t i = 0; i < len; i++) { + // for each data byte + for(int j = 7; j >= 0; j--) { + // for each bit in each data byte, calculate the next bit + uint8_t feedback = rlb_popcount(lsfr & poly) & 1UL; + uint8_t inbit = (data[i] & (1UL << j)) >> j; + uint32_t nextbit = feedback ^ inbit; + + // shift the feedback register + lsfr <<= 1; + + // now add the next bit + // when scrambling, it is the calculated next bit + // when descrambling, it is the input bit + lsfr |= scramble ? nextbit : inbit; + + // shift the output buffer and add the next bit + out <<= 1; + out |= nextbit; + } + + // extract the new byte + data[i] = out; + out = 0; + } +} + void rlb_hexdump(const char* level, const uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) { #if RADIOLIB_DEBUG size_t rem_len = len; diff --git a/src/utils/Utils.h b/src/utils/Utils.h index c979548f88..8a144c0034 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -16,6 +16,11 @@ #define TEST_BIT_IN_ARRAY_LSB(A, k) ( A[((k)/8)] & (1 << (7 - ((k)%8))) ) #define GET_BIT_IN_ARRAY_LSB(A, k) ( (A[((k)/8)] & (1 << (7 - ((k)%8)))) ? 1 : 0 ) +// frequently used scrambling configurations +// the final bit (x^0 term in polynomial notation) is assumed to always be present +#define RADIOLIB_SCRAMBLER_G3RUH_POLY (0x00021001UL) // x^17 + x^12 + 1 +#define RADIOLIB_SCRAMBLER_G3RUH_INIT (0x00000000UL) + /*! \brief Function to reflect bits within a byte. \param in The input to reflect. @@ -24,6 +29,16 @@ */ uint32_t rlb_reflect(uint32_t in, uint8_t bits); +/*! + \brief Function to scramble or descramble input using a linear feedback shift register (LFSR). + \param data The input data to (de)scramble. + \param len Number of input bytes. + \param poly Polynomial to use for scrambling. + \param init Initial LFSR value, sometimes called seed. + \param scramble Whether to perform scrambling (true) or de-scrambling (false). +*/ +void rlb_scrambler(uint8_t* data, size_t len, const uint32_t poly, const uint32_t init, bool scramble); + /*! \brief Function to dump data as hex into the debug port. \param level RadioLib debug level, set to NULL to not print. From 0db2156864d61b5cb156a535351337c30585cccb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Nov 2025 17:12:18 +0000 Subject: [PATCH 1666/1848] [LR11x0] Move reset to common class --- src/modules/LR11x0/LR11x0.cpp | 23 ----------------------- src/modules/LR11x0/LR11x0.h | 6 ------ src/modules/LR11x0/LR_common.cpp | 23 +++++++++++++++++++++++ src/modules/LR11x0/LR_common.h | 6 ++++++ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index fe569196c7..cb02c51131 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -150,29 +150,6 @@ int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) { return(RADIOLIB_ERR_NONE); } -int16_t LR11x0::reset() { - // run the reset sequence - this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); - this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); - this->mod->hal->delay(10); - this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); - - // the typical transition duration should be 273 ms - this->mod->hal->delay(300); - - // wait for BUSY to go low - RadioLibTime_t start = this->mod->hal->millis(); - while(this->mod->hal->digitalRead(this->mod->getGpio())) { - this->mod->hal->yield(); - if(this->mod->hal->millis() - start >= 3000) { - RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after reset!"); - return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); - } - } - - return(RADIOLIB_ERR_NONE); -} - int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = standby(); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 63a86ab722..d7bc01d07d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -111,12 +111,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { */ int16_t beginGNSS(uint8_t constellations = RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS | RADIOLIB_LR11X0_GNSS_CONSTELLATION_BEIDOU, float tcxoVoltage = 1.6); - /*! - \brief Reset method. Will reset the chip to the default state using RST pin. - \returns \ref status_codes - */ - int16_t reset(); - /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 325a4ec1c3..55fac7da61 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -6,6 +6,29 @@ LRxxxx::LRxxxx(Module* mod) { this->mod = mod; } +int16_t LRxxxx::reset() { + // run the reset sequence + this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow); + this->mod->hal->delay(10); + this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh); + + // the typical transition duration should be 273 ms + this->mod->hal->delay(300); + + // wait for BUSY to go low + RadioLibTime_t start = this->mod->hal->millis(); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + if(this->mod->hal->millis() - start >= 3000) { + RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after reset!"); + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); + } + } + + return(RADIOLIB_ERR_NONE); +} + int16_t LRxxxx::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) { uint8_t buff[6] = { 0 }; diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index c7f6623fd0..972869c6da 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -45,6 +45,12 @@ class LRxxxx { public: LRxxxx(Module* mod); + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + \returns \ref status_codes + */ + int16_t reset(); + protected: // a lot of SPI commands have the same structure and arguments on both LR11xx as well as LR2021 // the only difference is the 16-bit command code - however, having everything in this base class From 287bb85a5e3a490cca1843279a0cca702d2d2f4d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Nov 2025 17:13:26 +0000 Subject: [PATCH 1667/1848] [LR2021] Add common setU32 method --- src/modules/LR11x0/LR11x0_commands.cpp | 29 ++++--------------- src/modules/LR11x0/LR_common.cpp | 8 +++++ src/modules/LR11x0/LR_common.h | 3 ++ .../LR2021/LR2021_cmds_chip_control.cpp | 6 +--- src/modules/LR2021/LR2021_cmds_misc.cpp | 6 +--- src/modules/LR2021/LR2021_cmds_radio.cpp | 6 +--- src/modules/LR2021/LR2021_cmds_ranging.cpp | 6 +--- 7 files changed, 20 insertions(+), 44 deletions(-) diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index 200200284a..815f9d8265 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -162,10 +162,7 @@ int16_t LR11x0::setDioIrqParams(uint32_t irq) { } int16_t LR11x0::clearIrqState(uint32_t irq) { - uint8_t buff[4] = { - (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR11X0_CMD_CLEAR_IRQ, irq)); } int16_t LR11x0::configLfClock(uint8_t setup) { @@ -431,11 +428,7 @@ int16_t LR11x0::setTx(uint32_t timeout) { } int16_t LR11x0::setRfFrequency(uint32_t rfFreq) { - uint8_t buff[4] = { - (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF), - (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RF_FREQUENCY, rfFreq)); } int16_t LR11x0::autoTxRx(uint32_t delay, uint8_t intMode, uint32_t timeout) { @@ -584,11 +577,7 @@ int16_t LR11x0::setRangingAddr(uint32_t addr, uint8_t checkLen) { } int16_t LR11x0::setRangingReqAddr(uint32_t addr) { - uint8_t buff[4] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RANGING_REQ_ADDR, addr)); } int16_t LR11x0::getRangingResult(uint8_t type, float* res) { @@ -610,11 +599,7 @@ int16_t LR11x0::getRangingResult(uint8_t type, float* res) { } int16_t LR11x0::setRangingTxRxDelay(uint32_t delay) { - uint8_t buff[4] = { - (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF), - (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR11X0_CMD_SET_RANGING_TX_RX_DELAY, delay)); } int16_t LR11x0::setGfskCrcParams(uint32_t init, uint32_t poly) { @@ -663,11 +648,7 @@ int16_t LR11x0::setLoRaSyncWord(uint8_t sync) { } int16_t LR11x0::lrFhssSetSyncWord(uint32_t sync) { - uint8_t buff[4] = { - (uint8_t)((sync >> 24) & 0xFF), (uint8_t)((sync >> 16) & 0xFF), - (uint8_t)((sync >> 8) & 0xFF), (uint8_t)(sync & 0xFF) - }; - return(this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD, sync)); } int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len) { diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 55fac7da61..0787367398 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -84,6 +84,14 @@ int16_t LRxxxx::lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uin return(state); } +int16_t LRxxxx::setU32(uint16_t cmd, uint32_t u32) { + uint8_t buff[] = { + (uint8_t)((u32 >> 24) & 0xFF), (uint8_t)((u32 >> 16) & 0xFF), + (uint8_t)((u32 >> 8) & 0xFF), (uint8_t)(u32 & 0xFF), + }; + return(this->SPIcommand(cmd, true, buff, sizeof(buff))); +} + int16_t LRxxxx::SPIparseStatus(uint8_t in) { if((in & 0b00001110) == RADIOLIB_LRXXXX_STAT_1_CMD_PERR) { return(RADIOLIB_ERR_SPI_CMD_INVALID); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 972869c6da..fbcfa6c8ef 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -59,6 +59,9 @@ class LRxxxx { int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); int16_t lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); + // several commands just send unsigned 32-bit number + int16_t setU32(uint16_t cmd, uint32_t u32); + int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile); int16_t SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out = NULL, size_t outLen = 0); diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index 623392f7f7..1bd6161ec4 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -221,11 +221,7 @@ int16_t LR2021::setDioIrqConfig(uint8_t dio, uint32_t irq) { } int16_t LR2021::clearIrq(uint32_t irq) { - uint8_t buff[] = { - (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), - (uint8_t)((irq >> 8) & 0xFF), (uint8_t)(irq & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_CLEAR_IRQ, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR2021_CMD_CLEAR_IRQ, irq)); } int16_t LR2021::getAndClearIrqStatus(uint32_t* irq) { diff --git a/src/modules/LR2021/LR2021_cmds_misc.cpp b/src/modules/LR2021/LR2021_cmds_misc.cpp index 302b441cc5..0be29e63f9 100644 --- a/src/modules/LR2021/LR2021_cmds_misc.cpp +++ b/src/modules/LR2021/LR2021_cmds_misc.cpp @@ -25,11 +25,7 @@ int16_t LR2021::setBpskPacketParams(uint8_t payloadLen, uint8_t mode, bool sigFo } int16_t LR2021::lrFhssSetSyncword(uint32_t syncWord) { - uint8_t buff[] = { - (uint8_t)((syncWord >> 24) & 0xFF), (uint8_t)((syncWord >> 16) & 0xFF), - (uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR2021_CMD_LR_FHSS_SET_SYNCWORD, syncWord)); } int16_t LR2021::setTxTestMode(uint8_t mode) { diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index 6df41c91e5..7039e65371 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -8,11 +8,7 @@ #if !RADIOLIB_EXCLUDE_LR2021 int16_t LR2021::setRfFrequency(uint32_t rfFreq) { - uint8_t buff[] = { - (uint8_t)((rfFreq >> 24) & 0xFF), (uint8_t)((rfFreq >> 16) & 0xFF), - (uint8_t)((rfFreq >> 8) & 0xFF), (uint8_t)(rfFreq & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR2021_CMD_SET_RF_FREQUENCY, rfFreq)); } int16_t LR2021::setRxPath(uint8_t rxPath, uint8_t rxBoost) { diff --git a/src/modules/LR2021/LR2021_cmds_ranging.cpp b/src/modules/LR2021/LR2021_cmds_ranging.cpp index 34f2832111..db8a4509de 100644 --- a/src/modules/LR2021/LR2021_cmds_ranging.cpp +++ b/src/modules/LR2021/LR2021_cmds_ranging.cpp @@ -53,11 +53,7 @@ int16_t LR2021::getRangingStats(uint16_t* exchangeValid, uint16_t* requestValid, } int16_t LR2021::setRangingTxRxDelay(uint32_t delay) { - uint8_t buff[] = { - (uint8_t)((delay >> 24) & 0xFF), (uint8_t)((delay >> 16) & 0xFF), - (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF), - }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY, true, buff, sizeof(buff))); + return(this->setU32(RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY, delay)); } int16_t LR2021::setRangingParams(bool spyMode, uint8_t nbSymbols) { From 2b80e655cf1bb47190b11c3e97cccb6e6d3cbfea Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 1 Nov 2025 17:13:52 +0000 Subject: [PATCH 1668/1848] [LR2021] Add standby and begin --- src/modules/LR2021/LR2021.cpp | 44 ++++++++++++++++++++++++++++ src/modules/LR2021/LR2021.h | 35 ++++++++++++++++++++-- src/modules/LR2021/LR2021_commands.h | 8 +++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 5b07e7cec1..7bc0d17fd0 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -24,6 +24,50 @@ LR2021::LR2021(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->mod->spiConfig.checkStatusCb = SPIcheckStatus; } +int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength) { + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.statusPos = 0; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + this->mod->spiConfig.checkStatusCb = SPIcheckStatus; + + // reset the radio + (void)reset(); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t LR2021::standby() { + return(this->standby(RADIOLIB_LR2021_STANDBY_RC)); +} + +int16_t LR2021::standby(uint8_t mode, bool wakeup) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_IDLE); + + if(wakeup) { + // send a NOP command - this pulls the NSS low to exit the sleep mode, + // while preventing interference with possible other SPI transactions + (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR2021_CMD_NOP, NULL, 0, false, false); + } + + uint8_t buff[] = { mode }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_STANDBY, true, buff, sizeof(buff))); +} + int16_t LR2021::sleep() { return(this->sleep(RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED, 0)); } diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 725fa06076..8e69a2f515 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -35,8 +35,39 @@ class LR2021: public PhysicalLayer, public LRxxxx { \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. */ - explicit LR2021(Module* mod); - + LR2021(Module* mod); // cppcheck-suppress noExplicitConstructor + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + \param sf LoRa spreading factor. Defaults to 9. + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. + \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE (0x12). + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8); + + /*! + \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). + \returns \ref status_codes + */ + int16_t standby() override; + + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR2021_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_LR2021_STANDBY_XOSC (32 MHz external crystal oscillator). + \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. + \returns \ref status_codes + */ + int16_t standby(uint8_t mode, bool wakeup = true); + int16_t sleep(); int16_t sleep(uint8_t cfg, uint32_t time); diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 121ba79898..d55126a7f6 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -184,6 +184,10 @@ #define RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED (0x00UL << 1) // 1 1 configuration retention in sleep mode: disabled #define RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED (0x01UL << 1) // 1 1 enabled +// RADIOLIB_LR2021_CMD_SET_STANDBY +#define RADIOLIB_LR2021_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator +#define RADIOLIB_LR2021_STANDBY_XOSC (0x01UL << 0) // 7 0 XOSC oscillator + // RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE #define RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC #define RADIOLIB_LR2021_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC @@ -391,6 +395,10 @@ #define RADIOLIB_LR2021_LORA_SYNCH_TIMEOUT_FORMAT_SYMBOLS (0x00UL << 0) // 7 0 LoRa synch timeout format: number of symbols #define RADIOLIB_LR2021_LORA_SYNCH_TIMEOUT_FORMAT_MANT_EXP (0x01UL << 0) // 7 0 mantissa-exponent +// RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD +#define RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE (0x12UL << 0) // 7 0 LoRa sync word: 0x12 (private networks) +#define RADIOLIB_LR2021_LORA_SYNC_WORD_LORAWAN (0x34UL << 0) // 7 0 0x34 (LoRaWAN reserved) + // RADIOLIB_LR2021_CMD_SET_LORA_HOPPING #define RADIOLIB_LR2021_LORA_HOPPING_DISABLED (0x00UL << 6) // 7 6 LoRa intra-packet hopping: disabled #define RADIOLIB_LR2021_LORA_HOPPING_ENABLED (0x01UL << 6) // 7 6 enabled From d46c50fccda76deb44c1eecb8ffc9a376acd3428 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Fri, 7 Nov 2025 09:56:04 +0100 Subject: [PATCH 1669/1848] Add support for Arduino Uno Q (Zephyr) --- src/BuildOpt.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 5046c3167d..6575680270 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -388,6 +388,13 @@ #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) +#elif defined(ARDUINO_ARCH_ZEPHYR) && defined(ARDUINO_UNO_Q) + // Arduino Uno Q (Zephyr OS) + #define RADIOLIB_PLATFORM "Arduino Uno Q (Zephyr OS)" + #define RADIOLIB_ARDUINOHAL_PIN_MODE_CAST (PinMode) + #define RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST (PinStatus) + #define RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST (PinStatus) + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" From 536c7267362e2c1345be7054ba45e503252975ff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 9 Nov 2025 15:50:56 +0100 Subject: [PATCH 1670/1848] [SX127x] Enable automatic LDRO by default (#1638) --- src/modules/SX127x/SX127x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index b4f7ec41f2..43d577bbd8 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1263,7 +1263,7 @@ class SX127x: public PhysicalLayer { bool crcEnabled = false; bool ookEnabled = false; bool implicitHdr = false; - bool ldroAuto = false; + bool ldroAuto = true; bool ldroEnabled = false; virtual int16_t configFSK(); From 0d9ee434cd3d369b0d6a9dd037d3e339ecbb2c3c Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 10 Nov 2025 20:25:58 +0100 Subject: [PATCH 1671/1848] [SX128x] Fix packet length mode not configurable on FLRC (#1644) --- src/modules/SX128x/SX128x.cpp | 3 ++- src/modules/SX128x/SX128x.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index c1086f0fba..7c3f951413 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1699,7 +1699,8 @@ int16_t SX128x::setPacketType(uint8_t type) { int16_t SX128x::setPacketMode(uint8_t mode, uint8_t len) { // check active modem - if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_GFSK) { + uint8_t modem = getPacketType(); + if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { return(RADIOLIB_ERR_WRONG_MODEM); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index cba802158c..2f77a773d5 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -816,14 +816,14 @@ class SX128x: public PhysicalLayer { int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); /*! - \brief Set modem in fixed packet length mode. Available in GFSK mode only. + \brief Set modem in fixed packet length mode. Available in GFSK and FLRC modes only. \param len Packet length. \returns \ref status_codes */ int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SX128X_MAX_PACKET_LENGTH); /*! - \brief Set modem in variable packet length mode. Available in GFSK mode only. + \brief Set modem in variable packet length mode. Available in GFSK and FLRC modes only. \param maxLen Maximum packet length. \returns \ref status_codes */ From 3a5dac095d9f4c823fdc8a9e8f8e427244134981 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 11 Nov 2025 20:11:24 +0000 Subject: [PATCH 1672/1848] [SX1280] Use only raw ranging results until we figure out the filter --- src/modules/SX128x/SX1280.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 32078e613e..fa496e2f79 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -157,7 +157,7 @@ int32_t SX1280::getRangingResultRaw() { } float SX1280::getRangingResult() { - int32_t raw = getRangingResultCommon(true); + int32_t raw = getRangingResultCommon(false); return((float)raw * 150.0f / (4.096f * this->bandwidthKhz)); } @@ -167,7 +167,7 @@ int32_t SX1280::getRangingResultCommon(bool filtered) { RADIOLIB_ASSERT(state); // enable clock - uint8_t data[4]; + uint8_t data[3] = { 0 }; state = readRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); RADIOLIB_ASSERT(state); @@ -175,7 +175,10 @@ int32_t SX1280::getRangingResultCommon(bool filtered) { state = writeRegister(RADIOLIB_SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1); RADIOLIB_ASSERT(state); - // set result type to filtered + // set result type filtered/raw + // TODO: at the moment, filtered values do not work and just return huge numbers + // the datasheet also isn't exactly clear on how to use the filtering + // (when to reset, when are samples added etc.) state = readRegister(RADIOLIB_SX128X_REG_RANGING_TYPE, data, 1); RADIOLIB_ASSERT(state); @@ -185,20 +188,15 @@ int32_t SX1280::getRangingResultCommon(bool filtered) { RADIOLIB_ASSERT(state); // read the register values - state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MSB, &data[0], 1); - RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MID, &data[1], 1); - RADIOLIB_ASSERT(state); - state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_LSB, &data[2], 1); + state = readRegister(RADIOLIB_SX128X_REG_RANGING_RESULT_MSB, data, 3); RADIOLIB_ASSERT(state); // set mode to standby RC state = standby(); RADIOLIB_ASSERT(state); - // convert to signed - uint32_t uraw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2]; - int32_t raw = (uraw & ((1UL << 23) - 1)) | (uraw >> 23 << 31); + // shifting everything by 8 bits more to the left will convert the result to signed number + int32_t raw = ((((int32_t)data[0]) << 24) | (((int32_t)data[1]) << 16) | (((int32_t)data[2]) << 8)) >> 8; return(raw); } From 4ca36bc043f8e829bb6843c04bd7e2473abbd1ca Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Nov 2025 18:39:28 +0000 Subject: [PATCH 1673/1848] [CC1101] Increase MARCSTATE timeout in Tx to 1600 us (#1647) --- src/modules/CC1101/CC1101.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 6078ddf39d..0084f2346f 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -247,13 +247,13 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // Needs a bit more time for reliability RadioLibTime_t start = this->mod->hal->micros(); while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != 0x12) { - if(this->mod->hal->micros() - start > 800) { + if(this->mod->hal->micros() - start > 1600) { standby(); return(RADIOLIB_ERR_TX_TIMEOUT); } } - // set GDO0 mapping only if we aren't refilling the FIFO + // set GDO2 mapping only if we aren't refilling the FIFO int16_t state = RADIOLIB_ERR_NONE; if(len <= RADIOLIB_CC1101_FIFO_SIZE) { state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); From eb13d5beb15737e8ba55336a93a65d4289727af0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Nov 2025 20:29:26 +0000 Subject: [PATCH 1674/1848] [HAL] Fix falling interrupts not reported in RPi HAL --- src/hal/RPi/PiHal.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hal/RPi/PiHal.h b/src/hal/RPi/PiHal.h index d67fe51204..914a1699a5 100644 --- a/src/hal/RPi/PiHal.h +++ b/src/hal/RPi/PiHal.h @@ -119,9 +119,11 @@ class PiHal : public RadioLibHal { // enable emulated interrupt interruptEnabled[interruptNum] = true; - interruptModes[interruptNum] = mode; interruptCallbacks[interruptNum] = interruptCb; + // lpgio reports the value of level after an interrupt, not the actual direction + interruptModes[interruptNum] = (mode == this->GpioInterruptFalling) ? LG_LOW : LG_HIGH; + lgGpioSetAlertsFunc(_gpioHandle, interruptNum, lgpioAlertHandler, (void *)this); } From 4bba92f382aa7482e23d587b95ba6b4ecdf6e58e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 15 Nov 2025 20:30:22 +0000 Subject: [PATCH 1675/1848] [CC1101] Reset GDO pins to high-Z state as part of Tx/Rx cleanup (#1647) --- src/modules/CC1101/CC1101.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 0084f2346f..ee1d553095 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -39,7 +39,7 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { - finishTransmit(); + (void)finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -50,7 +50,7 @@ int16_t CC1101::transmit(const uint8_t* data, size_t len, uint8_t addr) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { - finishTransmit(); + (void)finishTransmit(); return(RADIOLIB_ERR_TX_TIMEOUT); } } @@ -329,8 +329,9 @@ int16_t CC1101::finishTransmit() { // flush Tx FIFO SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX); - - return(state); + + // reset GDO2 back to high-Z + return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0)); } int16_t CC1101::startReceive() { @@ -389,7 +390,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { // check if status bytes are enabled (default: RADIOLIB_CC1101_APPEND_STATUS_ON) bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON; - // If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. + // if status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO. int16_t state = RADIOLIB_ERR_NONE; if (isAppendStatus) { // read RSSI byte @@ -409,18 +410,22 @@ int16_t CC1101::readData(uint8_t* data, size_t len) { // clear internal flag so getPacketLength can return the new packet length this->packetLengthQueried = false; - // Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) + // flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE) if(SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) { - finishReceive(); + (void)finishReceive(); } return(state); } int16_t CC1101::finishReceive() { + // go to standby and flush the FIFO int16_t state = standby(); SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX); - return(state); + RADIOLIB_ASSERT(state); + + // reset GDO0 back to high-Z + return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0)); } int16_t CC1101::setFrequency(float freq) { From 4aca5b59101118f72f4da2c62fd6e42cfaf7a6e5 Mon Sep 17 00:00:00 2001 From: Jack Pearson Date: Wed, 26 Nov 2025 13:16:53 -0600 Subject: [PATCH 1676/1848] Fix `receive` `timeout` parameter docs --- src/modules/SX128x/SX128x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 2f77a773d5..5ba4248253 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -438,7 +438,7 @@ class SX128x: public PhysicalLayer { Overloads for string-based transmissions are implemented in PhysicalLayer. \param data Pointer to array to save the received binary data. \param len Number of bytes that will be received. Must be known in advance for binary transmissions. - \param timeout Reception timeout in milliseconds. If set to 0, + \param timeout Reception timeout in microseconds. If set to 0, timeout period will be calculated automatically based on the radio configuration. \returns \ref status_codes */ From 92e2f333f12dda8d727dac1c9083b691b34f3796 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 14 Dec 2025 19:29:58 +0000 Subject: [PATCH 1677/1848] [SX126x] Autocorrect TCXO selected instead of XTAL --- src/modules/SX126x/SX126x.cpp | 21 +++++++++++++++++++++ src/modules/SX126x/SX126x_config.cpp | 14 +------------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 5a57fec875..ccb55b1bb1 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1465,6 +1465,27 @@ int16_t SX126x::modSetup(float tcxoVoltage, bool useRegulatorLDO, uint8_t modem) // configure settings not accessible by API state = config(modem); + + // if something failed, check the device errors + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + (void)standby(); + uint16_t errors = getDeviceErrors(); + RADIOLIB_DEBUG_BASIC_PRINTLN("Config failed, device errors: 0x%X", errors); + + // SPI command fail and oscillator start error flag indicate incorrectly set oscillator + if((state == RADIOLIB_ERR_SPI_CMD_FAILED) && (errors & RADIOLIB_SX126X_XOSC_START_ERR)) { + // typically users with XTAL devices will try to call the default begin method + // disable TCXO and try to run config again + this->XTAL = false; + RADIOLIB_DEBUG_BASIC_PRINTLN("Bad oscillator selected, trying XTAL"); + + state = setTCXO(0); + RADIOLIB_ASSERT(state); + + state = config(modem); + } + } RADIOLIB_ASSERT(state); if (useRegulatorLDO) { diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 3266756a92..0d60825eb9 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -798,19 +798,7 @@ int16_t SX126x::config(uint8_t modem) { } // check calibration result - state = this->mod->SPIcheckStream(); - - // if something failed, show the device errors - #if RADIOLIB_DEBUG_BASIC - if(state != RADIOLIB_ERR_NONE) { - // unless mode is forced to standby, device errors will be 0 - standby(); - uint16_t errors = getDeviceErrors(); - RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); - } - #endif - - return(state); + return(this->mod->SPIcheckStream()); } #endif From d4f70126a30aab6f467639569a830183ed635b1f Mon Sep 17 00:00:00 2001 From: Vinx911 Date: Sat, 20 Dec 2025 05:09:35 +0800 Subject: [PATCH 1678/1848] Add a destructor method to RadioLibHal (#1661) * Add a destructor function to RadioLibHal * Fix memory deallocation in ModuleFixture destructor --- extras/test/unit/tests/TestModule.cpp | 4 ++-- src/Hal.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/extras/test/unit/tests/TestModule.cpp b/extras/test/unit/tests/TestModule.cpp index 6bd145930a..669a643626 100644 --- a/extras/test/unit/tests/TestModule.cpp +++ b/extras/test/unit/tests/TestModule.cpp @@ -23,8 +23,8 @@ struct ModuleFixture { ~ModuleFixture() { BOOST_TEST_MESSAGE("--- Module fixture teardown ---"); mod->term(); - delete[] mod; - delete[] hal; + delete mod; + delete hal; } }; diff --git a/src/Hal.h b/src/Hal.h index 3676fea26d..9768474bc3 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -60,6 +60,11 @@ class RadioLibHal { */ RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling); + /*! + \brief Default destructor. + */ + virtual ~RadioLibHal() = default; + // pure virtual methods - these must be implemented by the hardware abstraction for RadioLib to function /*! From f25979f5c7e57529d2537de7d32757b026fe2826 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Dec 2025 09:46:29 +0000 Subject: [PATCH 1679/1848] [LR11x0] Move common members to base class --- src/modules/LR11x0/LR11x0.cpp | 25 ++++++++----------------- src/modules/LR11x0/LR11x0.h | 15 --------------- src/modules/LR11x0/LR11x0_commands.h | 10 ---------- src/modules/LR11x0/LR_common.cpp | 8 ++++++++ src/modules/LR11x0/LR_common.h | 27 ++++++++++++++++++++++++++- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index cb02c51131..3cc823ca11 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -8,8 +8,6 @@ LR11x0::LR11x0(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE; this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; - this->mod = mod; - this->XTAL = false; this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE; this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR11X0_IRQ_RX_DONE; this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED; @@ -1059,21 +1057,21 @@ int16_t LR11x0::setTCXO(float voltage, uint32_t delay) { // check allowed voltage values uint8_t tune = 0; if(fabsf(voltage - 1.6f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6; } else if(fabsf(voltage - 1.7f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7; } else if(fabsf(voltage - 1.8f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8; } else if(fabsf(voltage - 2.2f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2; } else if(fabsf(voltage - 2.4f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4; } else if(fabsf(voltage - 2.7f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7; } else if(fabsf(voltage - 3.0f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0; } else if(fabsf(voltage - 3.3f) <= 0.001f) { - tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3; + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3; } else { return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); } @@ -1773,17 +1771,10 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - this->mod->spiConfig.statusPos = 0; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - this->mod->spiConfig.checkStatusCb = SPIcheckStatus; this->gnss = false; // try to find the LR11x0 chip - this will also reset the module at least once diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index d7bc01d07d..2515333856 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -62,11 +62,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { /*! WiFi scanning mode */ MODE_WIFI, }; - - /*! - \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. - */ - bool XTAL; /*! \brief Initialization method for LoRa modem. @@ -971,16 +966,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { #if !RADIOLIB_GODMODE private: #endif - Module* mod; - - // cached LoRa parameters - uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; - uint16_t preambleLengthLoRa = 0; - float bandwidthKhz = 0; - bool ldroAuto = true; - size_t implicitLen = 0; - bool invertIQEnabled = false; - // cached GFSK parameters uint32_t bitRate = 0, frequencyDev = 0; uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0; diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index f4050ca4c0..74f2affdba 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -273,16 +273,6 @@ #define RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED (0x00UL << 2) // 2 2 #define RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED (0x01UL << 2) // 2 2 -// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V -#define RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V - // RADIOLIB_LR11X0_CMD_SET_SLEEP #define RADIOLIB_LR11X0_SLEEP_RETENTION_DISABLED (0x00UL << 0) // 0 0 configuration retention in sleep mode: disabled #define RADIOLIB_LR11X0_SLEEP_RETENTION_ENABLED (0x01UL << 0) // 0 0 enabled diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 0787367398..f4e775049c 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -4,6 +4,14 @@ LRxxxx::LRxxxx(Module* mod) { this->mod = mod; + this->XTAL = false; + this->mod->spiConfig.stream = true; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.statusPos = 0; + this->mod->spiConfig.parseStatusCb = SPIparseStatus; + this->mod->spiConfig.checkStatusCb = SPIcheckStatus; } int16_t LRxxxx::reset() { diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index fbcfa6c8ef..2963227186 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -41,6 +41,17 @@ #define RADIOLIB_LRXXXX_LR_FHSS_BLOCK_PREAMBLE_BITS (2) // 7 0 block preamble #define RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS (RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS + RADIOLIB_LRXXXX_LR_FHSS_BLOCK_PREAMBLE_BITS) +// RADIOLIB_LR11X0_CMD_SET_TCXO_MODE +// RADIOLIB_LR2021_CMD_SET_TCXO_MODE +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6 (0x00UL << 0) // 2 0 TCXO supply voltage: 1.6V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7 (0x01UL << 0) // 2 0 1.7V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8 (0x02UL << 0) // 2 0 1.8V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2 (0x03UL << 0) // 2 0 2.2V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4 (0x04UL << 0) // 2 0 2.4V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7 (0x05UL << 0) // 2 0 2.7V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V +#define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V + class LRxxxx { public: LRxxxx(Module* mod); @@ -51,7 +62,22 @@ class LRxxxx { */ int16_t reset(); + /*! + \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. + */ + bool XTAL; + protected: + Module* mod; + + // cached LoRa parameters + uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; + uint16_t preambleLengthLoRa = 0; + float bandwidthKhz = 0; + bool ldroAuto = true; + size_t implicitLen = 0; + bool invertIQEnabled = false; + // a lot of SPI commands have the same structure and arguments on both LR11xx as well as LR2021 // the only difference is the 16-bit command code - however, having everything in this base class // will actually increase the binary size, because of the extra method calls that are needed @@ -69,7 +95,6 @@ class LRxxxx { static int16_t SPIcheckStatus(Module* mod); private: - Module* mod; }; #endif From 0f994bf8db2d3606b761af0c60a11a75c828ad5f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Dec 2025 09:46:45 +0000 Subject: [PATCH 1680/1848] [LR2021] Add LoRa begin method and basic config --- src/modules/LR2021/LR2021.cpp | 123 ++++++++++-- src/modules/LR2021/LR2021.h | 84 ++++++++- src/modules/LR2021/LR2021_cmds_lora.cpp | 5 +- src/modules/LR2021/LR2021_commands.h | 2 + src/modules/LR2021/LR2021_config.cpp | 240 ++++++++++++++++++++++++ 5 files changed, 429 insertions(+), 25 deletions(-) create mode 100644 src/modules/LR2021/LR2021_config.cpp diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 7bc0d17fd0..252e474892 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -8,7 +8,6 @@ LR2021::LR2021(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE; this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH; - this->mod = mod; this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR2021_IRQ_TX_DONE; this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR2021_IRQ_RX_DONE; this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED; @@ -19,35 +18,63 @@ LR2021::LR2021(Module* mod) : PhysicalLayer(), LRxxxx(mod) { this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE; this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED; this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - this->mod->spiConfig.checkStatusCb = SPIcheckStatus; } -int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength) { +int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - this->mod->spiConfig.statusPos = 0; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; - this->mod->spiConfig.stream = true; - this->mod->spiConfig.parseStatusCb = SPIparseStatus; - this->mod->spiConfig.checkStatusCb = SPIcheckStatus; - // reset the radio - (void)reset(); + // try to find the chip - this will also reset the module at least once + if(!this->findChip()) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No LR2021 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR2021"); // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); - return(state); + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0f) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(RADIOLIB_LR2021_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setSyncWord(syncWord); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + state = setCRC(2); + RADIOLIB_ASSERT(state); + + state = invertIQ(false); + RADIOLIB_ASSERT(state); + + return(RADIOLIB_ERR_NONE); } int16_t LR2021::standby() { @@ -93,4 +120,70 @@ Module* LR2021::getMod() { return(this->mod); } +bool LR2021::findChip(void) { + // this is the only version mentioned in datasheet + const uint8_t expMajor = 0x01; + const uint8_t expMinor = 0x18; + + uint8_t i = 0; + bool flagFound = false; + uint8_t fwMajor = 0, fwMinor = 0; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // read the version + int16_t state = getVersion(&fwMajor, &fwMinor); + RADIOLIB_ASSERT(state); + + if((fwMajor == expMajor) && (fwMajor == expMinor)) { + RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR2021"); + RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)fwMajor, (int)fwMinor); + flagFound = true; + } else { + RADIOLIB_DEBUG_BASIC_PRINTLN("LR2021 not found! (%d of 10 tries) FW version: = %d.%d", (int)fwMajor, (int)fwMinor); + RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: %d.%d", (int)expMajor, (int)expMinor); + this->mod->hal->delay(10); + i++; + } + } + + return(flagFound); +} + +int16_t LR2021::config(uint8_t modem) { + // set Rx/Tx fallback mode to STDBY_RC + int16_t state = this->setRxTxFallbackMode(RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC); + RADIOLIB_ASSERT(state); + + // clear IRQ + state = this->clearIrq(RADIOLIB_LR2021_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // calibrate all blocks + (void)this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL); + + // wait for calibration completion + this->mod->hal->delay(5); + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + + // if something failed, show the device errors + // TODO legacy from LR11x0, chech if this really works on LR2021 + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + // unless mode is forced to standby, device errors will be 0 + standby(); + uint16_t errors = 0; + getErrors(&errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); + } + #endif + + // set modem + state = this->setPacketType(modem); + return(state); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 8e69a2f515..80f46dd972 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -49,9 +49,12 @@ class LR2021: public PhysicalLayer, public LRxxxx { \param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE (0x12). \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6); /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). @@ -71,6 +74,76 @@ class LR2021: public PhysicalLayer, public LRxxxx { int16_t sleep(); int16_t sleep(uint8_t cfg, uint32_t time); + // configuration methods + + /*! + \brief Sets LoRa bandwidth. Allowed values are 31.25, 41.67, 62.5, 83.34, 125.0, + 101.56, 203.13, 250.0, 406.25, 500.0 kHz, 812.5 kHz and 1000.0 kHz. + \param bw LoRa bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. + \param sf LoRa spreading factor to be set. + \param legacy Enable legacy mode for SF6 - this allows to communicate with SX127x at SF6. + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf, bool legacy = false); + + /*! + \brief Sets LoRa coding rate denominator. Allowed values range from 4 to 8. Note that a value of 4 means no coding, + is undocumented and not recommended without your own FEC. + \param cr LoRa coding rate denominator to be set. + \param longInterleave Enable long interleaver when set to true. + Note that with long interleaver enabled, CR 4/7 is not possible, there are packet length restrictions, + and it is not compatible with SX127x radios! + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr, bool longInterleave = false); + + /*! + \brief Sets LoRa sync word. + \param syncWord LoRa sync word to be set. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t syncWord); + + /*! + \brief Sets preamble length for LoRa or GFSK modem. Allowed values range from 1 to 65535. + \param preambleLength Preamble length to be set in symbols (LoRa) or bits (GFSK). + \returns \ref status_codes + */ + int16_t setPreambleLength(size_t preambleLength) override; + + /*! + \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration. + \param voltage TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. + Set to 0 to disable TCXO. + NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO). + \param delay TCXO timeout in us. Defaults to 5000 us. + \returns \ref status_codes + */ + int16_t setTCXO(float voltage, uint32_t delay = 5000); + + /*! + \brief Sets CRC configuration. + \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. + \param initial Initial CRC value. GFSK only. Defaults to 0x1D0F (CCIT CRC). + \param polynomial Polynomial for CRC calculation. GFSK only. Defaults to 0x1021 (CCIT CRC). + \param inverted Invert CRC bytes. GFSK only. Defaults to true (CCIT CRC). + \returns \ref status_codes + */ + int16_t setCRC(uint8_t len, uint32_t initial = 0x00001D0FUL, uint32_t polynomial = 0x00001021UL, bool inverted = true); + + /*! + \brief Enable/disable inversion of the I and Q signals + \param enable IQ inversion enabled (true) or disabled (false); + \returns \ref status_codes + */ + int16_t invertIQ(bool enable) override; + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -83,12 +156,9 @@ class LR2021: public PhysicalLayer, public LRxxxx { #if !RADIOLIB_GODMODE private: #endif - Module* mod; - // cached LoRa parameters - bool ldroAuto = true; - uint8_t bandwidth = 0, spreadingFactor = 0, ldrOptimize = 0; - float bandwidthKhz = 0; + bool findChip(void); + int16_t config(uint8_t modem); // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); @@ -157,7 +227,7 @@ class LR2021: public PhysicalLayer, public LRxxxx { int16_t setLoRaModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setLoRaPacketParams(uint16_t preambleLen, uint8_t hdrType, uint8_t payloadLen, uint8_t crcType, uint8_t invertIQ); int16_t setLoRaSynchTimeout(uint8_t numSymbols, bool format); - int16_t setLoRaSyncword(uint16_t syncword); + int16_t setLoRaSyncword(uint8_t syncword); int16_t setLoRaSideDetConfig(uint8_t* configs, size_t numSideDets); int16_t setLoRaSideDetSyncword(uint8_t* syncwords, size_t numSideDets); int16_t setLoRaCadParams(uint8_t numSymbols, bool preambleOnly, uint8_t pnrDelta, uint8_t cadExitMode, uint32_t timeout, uint8_t detPeak); diff --git a/src/modules/LR2021/LR2021_cmds_lora.cpp b/src/modules/LR2021/LR2021_cmds_lora.cpp index 7adf091323..8ad55c95ff 100644 --- a/src/modules/LR2021/LR2021_cmds_lora.cpp +++ b/src/modules/LR2021/LR2021_cmds_lora.cpp @@ -37,9 +37,8 @@ int16_t LR2021::setLoRaSynchTimeout(uint8_t numSymbols, bool format) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCH_TIMEOUT, true, buff, sizeof(buff))); } -int16_t LR2021::setLoRaSyncword(uint16_t syncword) { - uint8_t buff[] = { (uint8_t)((syncword >> 8) & 0xFF), (uint8_t)(syncword & 0xFF) }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD, true, buff, sizeof(buff))); +int16_t LR2021::setLoRaSyncword(uint8_t syncword) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SYNCWORD, true, &syncword, sizeof(syncword))); } int16_t LR2021::setLoRaSideDetConfig(uint8_t* configs, size_t numSideDets) { diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index d55126a7f6..e02db0e4df 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -177,6 +177,7 @@ #define RADIOLIB_LR2021_IRQ_RNG_REQ_DIS (0x01UL << 29) // 31 0 ranging request discarded #define RADIOLIB_LR2021_IRQ_RNG_EXCH_VALID (0x01UL << 30) // 31 0 master receive valid ranging response #define RADIOLIB_LR2021_IRQ_RNG_TIMEOUT (0x01UL << 31) // 31 0 ranging timeout +#define RADIOLIB_LR2021_IRQ_ALL (0xFFFFFFFFUL) // 31 0 all interrupts // RADIOLIB_LR2021_CMD_SET_SLEEP #define RADIOLIB_LR2021_SLEEP_32K_CLK_DISABLED (0x00UL << 0) // 0 0 32 kHz clock: disabled @@ -359,6 +360,7 @@ #define RADIOLIB_LR2021_PACKET_TYPE_RAW (0x0BUL << 0) // 7 0 RAW #define RADIOLIB_LR2021_PACKET_TYPE_Z_WAVE (0x0CUL << 0) // 7 0 Z-WAVE #define RADIOLIB_LR2021_PACKET_TYPE_OQPSK (0x0DUL << 0) // 7 0 OQPSK +#define RADIOLIB_LR2021_PACKET_TYPE_NONE (0xFFUL << 0) // 2 0 none // RADIOLIB_LR2021_CMD_SET_LORA_MODULATION_PARAMS #define RADIOLIB_LR2021_LORA_BW_31 (0x02UL << 0) // 3 0 LoRa bandwidth: 31.25 kHz diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp new file mode 100644 index 0000000000..43da8f27da --- /dev/null +++ b/src/modules/LR2021/LR2021_config.cpp @@ -0,0 +1,240 @@ +#include "LR2021.h" + +#include "../LR11x0/LR_common.h" + +#include + +#if !RADIOLIB_EXCLUDE_LR2021 + +int16_t LR2021::setBandwidth(float bw) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // convert to int to avoid bunch of math + int bw_div2 = bw / 2 + 0.01f; + + // check allowed bandwidth values + switch (bw_div2) { + case 15: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_31; + break; + case 20: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_41; + break; + case 31: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_62; + break; + case 41: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_83; + break; + case 50: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_101; + break; + case 101: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_203; + break; + case 62: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_125; + break; + case 125: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_250; + break; + case 203: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_406; + break; + case 250: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_500; + break; + case 406: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_812; + break; + case 500: + this->bandwidth = RADIOLIB_LR2021_LORA_BW_1000; + break; + default: + return(RADIOLIB_ERR_INVALID_BANDWIDTH); + } + + // update modulation parameters + this->bandwidthKhz = bw; + return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR2021::setSpreadingFactor(uint8_t sf, bool legacy) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + + // TODO enable SF6 legacy mode + if(legacy && (sf == 6)) { + //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18); + } + + // update modulation parameters + this->spreadingFactor = sf; + return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + if(longInterleave) { + switch(cr) { + case 4: + this->codingRate = 0; + break; + case 5: + case 6: + this->codingRate = cr; + break; + case 8: + this->codingRate = cr - 1; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + } else { + this->codingRate = cr - 4; + + } + + // update modulation parameters + return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); +} + +int16_t LR2021::setSyncWord(uint8_t syncWord) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(setLoRaSyncword(syncWord)); +} + +int16_t LR2021::setPreambleLength(size_t preambleLength) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) { + this->preambleLengthLoRa = preambleLength; + return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); + } + + // TODO implement other modems + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t LR2021::setTCXO(float voltage, uint32_t delay) { + // check if TCXO is enabled at all + if(this->XTAL) { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // set mode to standby + standby(); + + // check oscillator startup error flag and clear it + // TODO legacy from LR11x0, chech if this really works on LR2021 + uint16_t errors = 0; + int16_t state = getErrors(&errors); + RADIOLIB_ASSERT(state); + if(errors & RADIOLIB_LR2021_HF_XOSC_START_ERR) { + clearErrors(); + } + + // check 0 V disable + if(fabsf(voltage - 0.0f) <= 0.001f) { + setTcxoMode(0, 0); + return(reset()); + } + + // check allowed voltage values + uint8_t tune = 0; + if(fabsf(voltage - 1.6f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6; + } else if(fabsf(voltage - 1.7f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7; + } else if(fabsf(voltage - 1.8f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8; + } else if(fabsf(voltage - 2.2f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2; + } else if(fabsf(voltage - 2.4f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4; + } else if(fabsf(voltage - 2.7f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7; + } else if(fabsf(voltage - 3.0f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0; + } else if(fabsf(voltage - 3.3f) <= 0.001f) { + tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3; + } else { + return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE); + } + + // calculate delay value + uint32_t delayValue = (uint32_t)((float)delay / 30.52f); + if(delayValue == 0) { + delayValue = 1; + } + + // enable TCXO control + return(setTcxoMode(tune, delayValue)); +} + +int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) { + // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion + this->crcTypeLoRa = len > 0 ? RADIOLIB_LR2021_LORA_CRC_ENABLED : RADIOLIB_LR2021_LORA_CRC_DISABLED; + state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled); + } + + // TODO implement other modems + (void)initial; + (void)polynomial; + (void)inverted; + + return(state); +} + +int16_t LR2021::invertIQ(bool enable) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->invertIQEnabled = enable; + return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); +} + +#endif \ No newline at end of file From b070a998695d1acc0a3ce2e7ddf4b1492cb7eb48 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Dec 2025 15:17:26 +0000 Subject: [PATCH 1681/1848] [LR11x0] Move basic IRQ methods to base class --- src/modules/LR11x0/LR11x0.cpp | 36 +----------------------- src/modules/LR11x0/LR11x0.h | 44 +---------------------------- src/modules/LR11x0/LR_common.cpp | 36 +++++++++++++++++++++++- src/modules/LR11x0/LR_common.h | 48 ++++++++++++++++++++++++++++++-- 4 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 3cc823ca11..4809aa719e 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -5,7 +5,7 @@ #if !RADIOLIB_EXCLUDE_LR11X0 -LR11x0::LR11x0(Module* mod) : PhysicalLayer(), LRxxxx(mod) { +LR11x0::LR11x0(Module* mod) : LRxxxx(mod) { this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE; this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE; @@ -368,30 +368,6 @@ int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) { return(state); } -void LR11x0::setIrqAction(void (*func)(void)) { - this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); -} - -void LR11x0::clearIrqAction() { - this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); -} - -void LR11x0::setPacketReceivedAction(void (*func)(void)) { - this->setIrqAction(func); -} - -void LR11x0::clearPacketReceivedAction() { - this->clearIrqAction(); -} - -void LR11x0::setPacketSentAction(void (*func)(void)) { - this->setIrqAction(func); -} - -void LR11x0::clearPacketSentAction() { - this->clearIrqAction(); -} - int16_t LR11x0::finishTransmit() { // clear interrupt flags clearIrqState(RADIOLIB_LR11X0_IRQ_ALL); @@ -404,16 +380,6 @@ int16_t LR11x0::startReceive() { return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); } -uint32_t LR11x0::getIrqStatus() { - // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes - uint8_t buff[6] = { 0 }; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; - mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; - uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; - return(irq); -} - int16_t LR11x0::readData(uint8_t* data, size_t len) { // check active modem int16_t state = RADIOLIB_ERR_NONE; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 2515333856..148a2cd187 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -7,7 +7,6 @@ #include "../../Module.h" -#include "../../protocols/PhysicalLayer/PhysicalLayer.h" #include "../LR11x0/LR_common.h" #include "LR11x0_commands.h" @@ -25,7 +24,7 @@ \brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class. This class should not be instantiated directly from user code, only from its derived classes. */ -class LR11x0: public PhysicalLayer, public LRxxxx { +class LR11x0: public LRxxxx { public: // introduce PhysicalLayer overloads using PhysicalLayer::transmit; @@ -187,39 +186,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { // interrupt methods - /*! - \brief Sets interrupt service routine to call when IRQ1 activates. - \param func ISR to call. - */ - void setIrqAction(void (*func)(void)); - - /*! - \brief Clears interrupt service routine to call when IRQ1 activates. - */ - void clearIrqAction(); - - /*! - \brief Sets interrupt service routine to call when a packet is received. - \param func ISR to call. - */ - void setPacketReceivedAction(void (*func)(void)) override; - - /*! - \brief Clears interrupt service routine to call when a packet is received. - */ - void clearPacketReceivedAction() override; - - /*! - \brief Sets interrupt service routine to call when a packet is sent. - \param func ISR to call. - */ - void setPacketSentAction(void (*func)(void)) override; - - /*! - \brief Clears interrupt service routine to call when a packet is sent. - */ - void clearPacketSentAction() override; - /*! \brief Clean up after transmission is done. \returns \ref status_codes @@ -234,12 +200,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { */ int16_t startReceive() override; - /*! - \brief Reads the current IRQ status. - \returns IRQ status bits - */ - uint32_t getIrqStatus(); - /*! \brief Reads data received after calling startReceive method. When the packet length is not known in advance, getPacketLength method must be called BEFORE calling readData! @@ -975,8 +935,6 @@ class LR11x0: public PhysicalLayer, public LRxxxx { uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0; uint16_t lrFhssHopSeq = 0; - float dataRateMeasured = 0; - uint8_t wifiScanMode = 0; bool gnss = false; uint32_t rxTimeout = 0; diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index f4e775049c..d1b93adc61 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -2,7 +2,7 @@ #include -LRxxxx::LRxxxx(Module* mod) { +LRxxxx::LRxxxx(Module* mod) : PhysicalLayer() { this->mod = mod; this->XTAL = false; this->mod->spiConfig.stream = true; @@ -14,6 +14,40 @@ LRxxxx::LRxxxx(Module* mod) { this->mod->spiConfig.checkStatusCb = SPIcheckStatus; } +void LRxxxx::setIrqAction(void (*func)(void)) { + this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising); +} + +void LRxxxx::clearIrqAction() { + this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq())); +} + +void LRxxxx::setPacketReceivedAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void LRxxxx::clearPacketReceivedAction() { + this->clearIrqAction(); +} + +void LRxxxx::setPacketSentAction(void (*func)(void)) { + this->setIrqAction(func); +} + +void LRxxxx::clearPacketSentAction() { + this->clearIrqAction(); +} + +uint32_t LRxxxx::getIrqStatus() { + // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes + uint8_t buff[6] = { 0 }; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; + mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; + return(irq); +} + int16_t LRxxxx::reset() { // run the reset sequence this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 2963227186..85a09d2e18 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -2,6 +2,7 @@ #define RADIOLIB_LR_COMMON_H #include "../../Module.h" +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" #define RADIOLIB_LRXXXX_CMD_NOP (0x0000) #define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (256) @@ -52,23 +53,64 @@ #define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V #define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V -class LRxxxx { +class LRxxxx: public PhysicalLayer { public: LRxxxx(Module* mod); + /*! + \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. + */ + bool XTAL; + /*! \brief Reset method. Will reset the chip to the default state using RST pin. \returns \ref status_codes */ int16_t reset(); + /*! + \brief Sets interrupt service routine to call when IRQ1 activates. + \param func ISR to call. + */ + void setIrqAction(void (*func)(void)); + /*! - \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. + \brief Clears interrupt service routine to call when IRQ1 activates. */ - bool XTAL; + void clearIrqAction(); + + /*! + \brief Sets interrupt service routine to call when a packet is received. + \param func ISR to call. + */ + void setPacketReceivedAction(void (*func)(void)) override; + + /*! + \brief Clears interrupt service routine to call when a packet is received. + */ + void clearPacketReceivedAction() override; + + /*! + \brief Sets interrupt service routine to call when a packet is sent. + \param func ISR to call. + */ + void setPacketSentAction(void (*func)(void)) override; + + /*! + \brief Clears interrupt service routine to call when a packet is sent. + */ + void clearPacketSentAction() override; + + /*! + \brief Reads the current IRQ status. + \returns IRQ status bits + */ + uint32_t getIrqStatus(); protected: Module* mod; + + float dataRateMeasured = 0; // cached LoRa parameters uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; From f1b8b684b0a85f0524e4887a1c1c52945dcc962a Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 28 Dec 2025 15:17:55 +0000 Subject: [PATCH 1682/1848] [LR2021] Add basic interrupt methods --- src/modules/LR2021/LR2021.cpp | 395 ++++++++++++++++++++- src/modules/LR2021/LR2021.h | 133 ++++++- src/modules/LR2021/LR2021_cmds_ranging.cpp | 2 +- src/modules/LR2021/LR2021_commands.h | 11 + src/modules/LR2021/LR2021_config.cpp | 8 +- 5 files changed, 534 insertions(+), 15 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 252e474892..2533ddf239 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -5,7 +5,7 @@ #if !RADIOLIB_EXCLUDE_LR2021 -LR2021::LR2021(Module* mod) : PhysicalLayer(), LRxxxx(mod) { +LR2021::LR2021(Module* mod) : LRxxxx(mod) { this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE; this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH; this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR2021_IRQ_TX_DONE; @@ -77,6 +77,183 @@ int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync return(RADIOLIB_ERR_NONE); } +int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check packet length + if (this->codingRate > RADIOLIB_LR2021_LORA_CR_4_8) { + // Long Interleaver needs at least 8 bytes + if(len < 8) { + return(RADIOLIB_ERR_PACKET_TOO_SHORT); + } + + // Long Interleaver supports up to 253 bytes if CRC is enabled + if (this->crcTypeLoRa == RADIOLIB_LR2021_LORA_CRC_ENABLED && (len > RADIOLIB_LR2021_MAX_PACKET_LENGTH - 2)) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + } + if(len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // get currently active modem + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + RadioLibTime_t timeout = getTimeOnAir(len); + if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) { + // calculate timeout (150% of expected time-on-air) + timeout = (timeout * 3) / 2; + + } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_FSK) || (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS)) { + // calculate timeout (500% of expected time-on-air) + timeout = timeout * 5; + + } else { + return(RADIOLIB_ERR_UNKNOWN); + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + RadioLibTime_t start = this->mod->hal->micros(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + if(this->mod->hal->micros() - start > timeout) { + finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } + } + RadioLibTime_t elapsed = this->mod->hal->micros() - start; + + // update data rate + this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000000.0f); + + return(finishTransmit()); +} + +int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // calculate timeout based on the configured modem + RadioLibTime_t timeoutInternal = timeout; + if(!timeoutInternal) { + // get currently active modem + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR2021_PACKET_TYPE_FSK)) { + // calculate timeout (500 % of expected time-one-air) + size_t maxLen = len; + if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; } + timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000; + + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) { + // this modem cannot receive + return(RADIOLIB_ERR_WRONG_MODEM); + + } else { + return(RADIOLIB_ERR_UNKNOWN); + + } + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal); + + // start reception + uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 30.52f); + state = startReceive(timeoutValue); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + bool softTimeout = false; + RadioLibTime_t start = this->mod->hal->millis(); + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + // safety check, the timeout should be done by the radio + if(this->mod->hal->millis() - start > timeoutInternal) { + softTimeout = true; + break; + } + } + + // if it was a timeout, this will return an error code + //! \TODO: [LR2021] taken from SX126x, does this really work? + state = standby(); + if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) { + return(state); + } + + // check whether this was a timeout or not + if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) { + (void)finishReceive(); + return(RADIOLIB_ERR_RX_TIMEOUT); + } + + // read the received data + return(readData(data, len)); +} + +int16_t LR2021::transmitDirect(uint32_t frf) { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_TX); + + // user requested to start transmitting immediately (required for RTTY) + int16_t state = RADIOLIB_ERR_NONE; + if(frf != 0) { + state = setRfFrequency(frf); + } + RADIOLIB_ASSERT(state); + + // start transmitting + return(setTxTestMode(RADIOLIB_LR2021_TX_TEST_MODE_CW)); +} + +int16_t LR2021::receiveDirect() { + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // LR2021 is unable to output received data directly + return(RADIOLIB_ERR_UNKNOWN); +} + +int16_t LR2021::scanChannel() { + ChannelScanConfig_t cfg = { + .cad = { + .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->scanChannel(cfg)); +} + +int16_t LR2021::scanChannel(const ChannelScanConfig_t &config) { + // set mode to CAD + int state = startChannelScan(config); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + while(!this->mod->hal->digitalRead(this->mod->getIrq())) { + this->mod->hal->yield(); + } + + // check CAD result + return(getChannelScanResult()); +} + int16_t LR2021::standby() { return(this->standby(RADIOLIB_LR2021_STANDBY_RC)); } @@ -96,16 +273,16 @@ int16_t LR2021::standby(uint8_t mode, bool wakeup) { } int16_t LR2021::sleep() { - return(this->sleep(RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED, 0)); + return(this->sleep(true, 0)); } -int16_t LR2021::sleep(uint8_t cfg, uint32_t time) { +int16_t LR2021::sleep(bool retainConfig, uint32_t sleepTime) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); - uint8_t buff[] = { cfg, - (uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF), - (uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF), + uint8_t buff[] = { (uint8_t)(retainConfig ? RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED : RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED), + (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF), + (uint8_t)((sleepTime >> 8) & 0xFF), (uint8_t)(sleepTime & 0xFF), }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_SET_SLEEP, true, buff, sizeof(buff)); @@ -116,6 +293,154 @@ int16_t LR2021::sleep(uint8_t cfg, uint32_t time) { return(state); } +size_t LR2021::getPacketLength(bool update) { + (void)update; + + // in implicit mode, return the cached value + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + (void)getPacketType(&type); + if((type == RADIOLIB_LR2021_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT)) { + return(this->implicitLen); + } + + uint16_t len = 0; + (void)getRxPktLength(&len); + return((size_t)len); +} + +int16_t LR2021::finishTransmit() { + // clear interrupt flags + clearIrq(RADIOLIB_LR2021_IRQ_ALL); + + // set mode to standby to disable transmitter/RF switch + return(standby()); +} + +int16_t LR2021::startReceive() { + return(this->startReceive(RADIOLIB_LR2021_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0)); +} + +int16_t LR2021::readData(uint8_t* data, size_t len) { + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && + (modem != RADIOLIB_LR2021_PACKET_TYPE_FSK)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check integrity CRC + uint32_t irq = getIrqStatus(); + int16_t crcState = RADIOLIB_ERR_NONE; + // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet) + //! \TODO: [LR2021] legacy from LR11x0, is it still needed? + if((irq & RADIOLIB_LR2021_IRQ_CRC_ERROR) || (!(irq & RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID))) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; + } + + // get packet length + size_t length = getPacketLength(); + if((len != 0) && (len < length)) { + // user requested less data than we got, only return what was requested + length = len; + } + + // read packet data + state = readRadioRxFifo(data, length); + RADIOLIB_ASSERT(state); + + // clear the Rx buffer + state = clearRxFifo(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + + // check if CRC failed - this is done after reading data to give user the option to keep them + RADIOLIB_ASSERT(crcState); + + return(state); +} + +int16_t LR2021::finishReceive() { + // set mode to standby to disable RF switch + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + return(clearIrq(RADIOLIB_LR2021_IRQ_ALL)); +} + +int16_t LR2021::startChannelScan() { + ChannelScanConfig_t cfg = { + .cad = { + .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT, + .timeout = 0, + .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK, + }, + }; + return(this->startChannelScan(cfg)); +} + +int16_t LR2021::startChannelScan(const ChannelScanConfig_t &config) { + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // set RF switch (if present) + this->mod->setRfSwitchState(Module::MODE_RX); + + // set DIO pin mapping + uint32_t irqFlags = (config.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR2021_IRQ_CAD_DETECTED | RADIOLIB_LR2021_IRQ_CAD_DONE : config.cad.irqFlags; + state = setDioIrqConfig(this->irqDioNum, getIrqMapped(irqFlags)); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // set mode to CAD + return(startCad(config.cad.symNum, config.cad.detPeak, config.cad.detMin, config.cad.exitMode, config.cad.timeout)); +} + +int16_t LR2021::getChannelScanResult() { + // check active modem + int16_t state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check CAD result + uint32_t cadResult = getIrqStatus(); + if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DETECTED) { + // detected some LoRa activity + return(RADIOLIB_LORA_DETECTED); + } else if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DONE) { + // channel is free + return(RADIOLIB_CHANNEL_FREE); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + Module* LR2021::getMod() { return(this->mod); } @@ -160,6 +485,15 @@ int16_t LR2021::config(uint8_t modem) { state = this->clearIrq(RADIOLIB_LR2021_IRQ_ALL); RADIOLIB_ASSERT(state); + // validate DIO pin number + if((this->irqDioNum < 5) || (this->irqDioNum > 11)) { + return(RADIOLIB_ERR_INVALID_DIO_PIN); + } + + // set the DIO to IRQ + state = this->setDioFunction(this->irqDioNum, RADIOLIB_LR2021_DIO_FUNCTION_IRQ, RADIOLIB_LR2021_DIO_SLEEP_PULL_NONE); + RADIOLIB_ASSERT(state); + // calibrate all blocks (void)this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL); @@ -170,7 +504,7 @@ int16_t LR2021::config(uint8_t modem) { } // if something failed, show the device errors - // TODO legacy from LR11x0, chech if this really works on LR2021 + //! \TODO: [LR2021] legacy from LR11x0, check if this really works on LR2021 #if RADIOLIB_DEBUG_BASIC if(state != RADIOLIB_ERR_NONE) { // unless mode is forced to standby, device errors will be 0 @@ -186,4 +520,51 @@ int16_t LR2021::config(uint8_t modem) { return(state); } +int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // select CAD parameters + //! \TODO: [LR2021] the magic numbers for CAD are based on Semtech examples, this is probably suboptimal + uint8_t num = symbolNum; + if(num == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { + num = 2; + } + + const uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 }; + uint8_t peak = detPeak; + if(peak == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { + peak = detPeakValues[this->spreadingFactor - 5]; + } + + uint8_t min = detMin; + if(min == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { + min = 10; + } + + uint8_t mode = exitMode; + if(mode == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { + mode = RADIOLIB_LR2021_CAD_EXIT_MODE_FALLBACK; + } + + uint32_t timeout_raw = (float)timeout / 30.52f; + + //! \TODO: [LR2021] The datasheet says this CAD is only based on RSSI, but the reference to the LoRa CAD is GetLoraRxStats ...? + (void)peak; + (void)min; + + // set CAD parameters + //! \TODO: [LR2021] add configurable exit mode and timeout + state = setCadParams(timeout_raw, num, mode, timeout_raw); + RADIOLIB_ASSERT(state); + + // start CAD + return(setCad()); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 80f46dd972..e69d273d22 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -22,7 +22,7 @@ \class LR2021 \brief */ -class LR2021: public PhysicalLayer, public LRxxxx { +class LR2021: public LRxxxx { public: // introduce PhysicalLayer overloads using PhysicalLayer::transmit; @@ -37,6 +37,11 @@ class LR2021: public PhysicalLayer, public LRxxxx { */ LR2021(Module* mod); // cppcheck-suppress noExplicitConstructor + /*! + \brief Which DIO pin is to be used as the interrupt pin. + */ + uint32_t irqDioNum = 5; + // basic methods /*! @@ -56,6 +61,54 @@ class LR2021: public PhysicalLayer, public LRxxxx { */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6); + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Binary data to be sent. + \param len Number of bytes to send. + \param addr Address to send the data to. Will only be added if address filtering was enabled. + \returns \ref status_codes + */ + int16_t transmit(const uint8_t* data, size_t len, uint8_t addr = 0) override; + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + \param timeout Reception timeout in milliseconds. If set to 0, + timeout period will be calculated automatically based on the radio configuration. + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len, RadioLibTime_t timeout = 0) override; + + /*! + \brief Starts direct mode transmission. + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0) override; + + /*! + \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as LR2021 does not support direct mode reception. + Will always return RADIOLIB_ERR_UNKNOWN. + \returns \ref status_codes + */ + int16_t receiveDirect() override; + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \returns \ref status_codes + */ + int16_t scanChannel() override; + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \param config CAD configuration structure. + \returns \ref status_codes + */ + int16_t scanChannel(const ChannelScanConfig_t &config) override; + /*! \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). \returns \ref status_codes @@ -71,8 +124,81 @@ class LR2021: public PhysicalLayer, public LRxxxx { */ int16_t standby(uint8_t mode, bool wakeup = true); - int16_t sleep(); - int16_t sleep(uint8_t cfg, uint32_t time); + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + Overload with warm start enabled for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t sleep() override; + + /*! + \brief Sets the module to sleep mode. To wake the device up, call standby(). + \param retainConfig Set to true to retain configuration of the currently active modem ("warm start") + or to false to discard current configuration ("cold start"). Defaults to true. + \param sleepTime Sleep duration (enables automatic wakeup), in multiples of 30.52 us. Ignored if set to 0. + \returns \ref status_codes + */ + int16_t sleep(bool retainConfig, uint32_t sleepTime); + + /*! + \brief Query modem for the packet length of received payload. + \param update Update received packet length. Will return cached value when set to false. + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true) override; + + // interrupt methods + + /*! + \brief Clean up after transmission is done. + \returns \ref status_codes + */ + int16_t finishTransmit() override; + + /*! + \brief Interrupt-driven receive method with default parameters. + Implemented for compatibility with PhysicalLayer. + + \returns \ref status_codes + */ + int16_t startReceive() override; + + /*! + \brief Reads data received after calling startReceive method. When the packet length is not known in advance, + getPacketLength method must be called BEFORE calling readData! + \param data Pointer to array to save the received binary data. + \param len Number of bytes that will be read. When set to 0, the packet length will be retrieved automatically. + When more bytes than received are requested, only the number of bytes requested will be returned. + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len) override; + + /*! + \brief Clean up after reception is done. + \returns \ref status_codes + */ + int16_t finishReceive() override; + + /*! + \brief Interrupt-driven channel activity detection method. IRQ1 will be activated + when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48. + \returns \ref status_codes + */ + int16_t startChannelScan() override; + + /*! + \brief Interrupt-driven channel activity detection method. IRQ pin will be activated + when LoRa preamble is detected, or upon timeout. + \param config CAD configuration structure. + \returns \ref status_codes + */ + int16_t startChannelScan(const ChannelScanConfig_t &config) override; + + /*! + \brief Read the channel scan result + \returns \ref status_codes + */ + int16_t getChannelScanResult() override; // configuration methods @@ -159,6 +285,7 @@ class LR2021: public PhysicalLayer, public LRxxxx { bool findChip(void); int16_t config(uint8_t modem); + int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); diff --git a/src/modules/LR2021/LR2021_cmds_ranging.cpp b/src/modules/LR2021/LR2021_cmds_ranging.cpp index db8a4509de..0d48ba525f 100644 --- a/src/modules/LR2021/LR2021_cmds_ranging.cpp +++ b/src/modules/LR2021/LR2021_cmds_ranging.cpp @@ -28,7 +28,7 @@ int16_t LR2021::getRangingResult(uint8_t type, uint32_t* rng1, uint8_t* rssi1, u uint8_t reqBuff[] = { type }; uint8_t rplBuff[7] = { 0 }; - // TODO implement AGC gains readout + //! \TODO: [LR2021] implement AGC gains readout size_t rplLen = (type == RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW) ? 7 : 4; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, rplLen); diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index e02db0e4df..af4b0f1835 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -189,6 +189,10 @@ #define RADIOLIB_LR2021_STANDBY_RC (0x00UL << 0) // 7 0 standby mode: RC oscillator #define RADIOLIB_LR2021_STANDBY_XOSC (0x01UL << 0) // 7 0 XOSC oscillator +// RADIOLIB_LR2021_CMD_SET_RX +#define RADIOLIB_LR2021_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode) +#define RADIOLIB_LR2021_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode) + // RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE #define RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC #define RADIOLIB_LR2021_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC @@ -314,6 +318,7 @@ #define RADIOLIB_LR2021_CAD_EXIT_MODE_FALLBACK (0x00UL << 0) // 1 0 CAD exit mode: the configured fallback mode #define RADIOLIB_LR2021_CAD_EXIT_MODE_TX (0x01UL << 0) // 1 0 Tx #define RADIOLIB_LR2021_CAD_EXIT_MODE_RX (0x02UL << 0) // 1 0 Rx +#define RADIOLIB_LR2021_CAD_PARAM_DEFAULT (0xFFUL << 0) // 7 0 used by the CAD methods to specify default parameter value // RADIOLIB_LR2021_CMD_SEL_PA #define RADIOLIB_LR2021_PA_LOW_POWER (0x00UL << 0) // 1 0 PA to use: low-power @@ -510,6 +515,12 @@ #define RADIOLIB_LR2021_OOK_MANCHESTER_ON (0x01UL << 0) // 3 0 enabled #define RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV (0x03UL << 0) // 3 0 enabled, inverted +// RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE +#define RADIOLIB_LR2021_TX_TEST_MODE_NORMAL_TX (0x00UL << 0) // 7 0 Tx test mode: normal +#define RADIOLIB_LR2021_TX_TEST_MODE_INF_PREAMBLE (0x01UL << 0) // 7 0 infinite preamble +#define RADIOLIB_LR2021_TX_TEST_MODE_CW (0x02UL << 0) // 7 0 continuous wave +#define RADIOLIB_LR2021_TX_TEST_MODE_PRBS9 (0x03UL << 0) // 7 0 pseudo-random bits + #endif #endif diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 43da8f27da..e8af57c1fc 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -76,7 +76,7 @@ int16_t LR2021::setSpreadingFactor(uint8_t sf, bool legacy) { RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); - // TODO enable SF6 legacy mode + //! \TODO: [LR2021] enable SF6 legacy mode if(legacy && (sf == 6)) { //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18); } @@ -144,7 +144,7 @@ int16_t LR2021::setPreambleLength(size_t preambleLength) { return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); } - // TODO implement other modems + //! \TODO: [LR2021] implement other modems return(RADIOLIB_ERR_WRONG_MODEM); } @@ -159,7 +159,7 @@ int16_t LR2021::setTCXO(float voltage, uint32_t delay) { standby(); // check oscillator startup error flag and clear it - // TODO legacy from LR11x0, chech if this really works on LR2021 + //! \TODO: [LR2021] legacy from LR11x0, chech if this really works on LR2021 uint16_t errors = 0; int16_t state = getErrors(&errors); RADIOLIB_ASSERT(state); @@ -216,7 +216,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled); } - // TODO implement other modems + //! \TODO: [LR2021] implement other modems (void)initial; (void)polynomial; (void)inverted; From 7cdba134165127b55b5a2f4db09450b27b810d92 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 29 Dec 2025 08:27:18 +0000 Subject: [PATCH 1683/1848] [LR11x0] Move pa ramp rounding function to base class --- src/modules/LR11x0/LR1110.cpp | 3 +- src/modules/LR11x0/LR1120.cpp | 3 +- src/modules/LR11x0/LR11x0.cpp | 41 ------------------------ src/modules/LR11x0/LR11x0.h | 9 ------ src/modules/LR11x0/LR11x0_commands.h | 18 ----------- src/modules/LR11x0/LR_common.cpp | 47 ++++++++++++++++++++++++++++ src/modules/LR11x0/LR_common.h | 24 ++++++++++++++ src/modules/LR2021/LR2021_commands.h | 21 ------------- 8 files changed, 75 insertions(+), 91 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 46fd4f1537..685158b626 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -86,7 +86,8 @@ int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampT RADIOLIB_ASSERT(state); // set output power - state = setTxParams(power, roundRampTime(rampTimeUs)); + // the value returned by LRxxxx class is offset by 3 for LR11x0 + state = setTxParams(power, roundRampTime(rampTimeUs) - 0x03); return(state); } diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 9f42fff26c..3cd83a0c28 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -102,7 +102,8 @@ int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampT RADIOLIB_ASSERT(state); // set output power - state = setTxParams(power, roundRampTime(rampTimeUs)); + // the value returned by LRxxxx class is offset by 3 for LR11x0 + state = setTxParams(power, roundRampTime(rampTimeUs) - 0x03); return(state); } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 4809aa719e..89aac98bf7 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1657,47 +1657,6 @@ int16_t LR11x0::launchMode() { return(state); } -uint8_t LR11x0::roundRampTime(uint32_t rampTimeUs) { - uint8_t regVal; - - // Round up the ramp time to nearest discrete register value - if(rampTimeUs <= 16) { - regVal = RADIOLIB_LR11X0_PA_RAMP_16U; - } else if(rampTimeUs <= 32) { - regVal = RADIOLIB_LR11X0_PA_RAMP_32U; - } else if(rampTimeUs <= 48) { - regVal = RADIOLIB_LR11X0_PA_RAMP_48U; - } else if(rampTimeUs <= 64) { - regVal = RADIOLIB_LR11X0_PA_RAMP_64U; - } else if(rampTimeUs <= 80) { - regVal = RADIOLIB_LR11X0_PA_RAMP_80U; - } else if(rampTimeUs <= 96) { - regVal = RADIOLIB_LR11X0_PA_RAMP_96U; - } else if(rampTimeUs <= 112) { - regVal = RADIOLIB_LR11X0_PA_RAMP_112U; - } else if(rampTimeUs <= 128) { - regVal = RADIOLIB_LR11X0_PA_RAMP_128U; - } else if(rampTimeUs <= 144) { - regVal = RADIOLIB_LR11X0_PA_RAMP_144U; - } else if(rampTimeUs <= 160) { - regVal = RADIOLIB_LR11X0_PA_RAMP_160U; - } else if(rampTimeUs <= 176) { - regVal = RADIOLIB_LR11X0_PA_RAMP_176U; - } else if(rampTimeUs <= 192) { - regVal = RADIOLIB_LR11X0_PA_RAMP_192U; - } else if(rampTimeUs <= 208) { - regVal = RADIOLIB_LR11X0_PA_RAMP_208U; - } else if(rampTimeUs <= 240) { - regVal = RADIOLIB_LR11X0_PA_RAMP_240U; - } else if(rampTimeUs <= 272) { - regVal = RADIOLIB_LR11X0_PA_RAMP_272U; - } else { // 304 - regVal = RADIOLIB_LR11X0_PA_RAMP_304U; - } - - return regVal; -} - int16_t LR11x0::workaroundGFSK() { // first, check we are using GFSK modem uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 148a2cd187..0562d95ba9 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -738,14 +738,6 @@ class LR11x0: public LRxxxx { #endif Module* getMod() override; - // LR11x0 command helpers - /*! - \brief Round up a PA power ramp time to register value - \param rampTimeUs Ramp time in microseconds - \returns Register value of rounded ramp time - */ - uint8_t roundRampTime(uint32_t rampTimeUs); - // method that applies some magic workaround for specific bitrate, frequency deviation, // receiver bandwidth and carrier frequencies for GFSK (and resets it in all other cases) int16_t workaroundGFSK(); @@ -921,7 +913,6 @@ class LR11x0: public LRxxxx { protected: #endif uint8_t chipType = 0; - float freqMHz = 0; #if !RADIOLIB_GODMODE private: diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index 74f2affdba..e09c4d2caa 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -420,24 +420,6 @@ #define RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED (0x00UL << 0) // 7 0 whitening: disabled #define RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED (0x01UL << 0) // 7 0 enabled -// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS -#define RADIOLIB_LR11X0_PA_RAMP_16U (0x00UL << 0) // 7 0 PA ramp time: 16 us -#define RADIOLIB_LR11X0_PA_RAMP_32U (0x01UL << 0) // 7 0 32 us -#define RADIOLIB_LR11X0_PA_RAMP_48U (0x02UL << 0) // 7 0 48 us -#define RADIOLIB_LR11X0_PA_RAMP_64U (0x03UL << 0) // 7 0 64 us -#define RADIOLIB_LR11X0_PA_RAMP_80U (0x04UL << 0) // 7 0 80 us -#define RADIOLIB_LR11X0_PA_RAMP_96U (0x05UL << 0) // 7 0 96 us -#define RADIOLIB_LR11X0_PA_RAMP_112U (0x06UL << 0) // 7 0 112 us -#define RADIOLIB_LR11X0_PA_RAMP_128U (0x07UL << 0) // 7 0 128 us -#define RADIOLIB_LR11X0_PA_RAMP_144U (0x08UL << 0) // 7 0 144 us -#define RADIOLIB_LR11X0_PA_RAMP_160U (0x09UL << 0) // 7 0 160 us -#define RADIOLIB_LR11X0_PA_RAMP_176U (0x0AUL << 0) // 7 0 176 us -#define RADIOLIB_LR11X0_PA_RAMP_192U (0x0BUL << 0) // 7 0 192 us -#define RADIOLIB_LR11X0_PA_RAMP_208U (0x0CUL << 0) // 7 0 208 us -#define RADIOLIB_LR11X0_PA_RAMP_240U (0x0DUL << 0) // 7 0 240 us -#define RADIOLIB_LR11X0_PA_RAMP_272U (0x0EUL << 0) // 7 0 272 us -#define RADIOLIB_LR11X0_PA_RAMP_304U (0x0FUL << 0) // 7 0 304 us - // RADIOLIB_LR11X0_CMD_SET_RX_TX_FALLBACK_MODE #define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC #define RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index d1b93adc61..4012571dfc 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -126,6 +126,53 @@ int16_t LRxxxx::lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uin return(state); } +uint8_t LRxxxx::roundRampTime(uint32_t rampTimeUs) { + uint8_t regVal; + + // Round up the ramp time to nearest discrete register value + if(rampTimeUs <= 2) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_2U; + } else if(rampTimeUs <= 4) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_4U; + } else if(rampTimeUs <= 8) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_8U; + } else if(rampTimeUs <= 16) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_16U; + } else if(rampTimeUs <= 32) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_32U; + } else if(rampTimeUs <= 48) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_48U; + } else if(rampTimeUs <= 64) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_64U; + } else if(rampTimeUs <= 80) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_80U; + } else if(rampTimeUs <= 96) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_96U; + } else if(rampTimeUs <= 112) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_112U; + } else if(rampTimeUs <= 128) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_128U; + } else if(rampTimeUs <= 144) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_144U; + } else if(rampTimeUs <= 160) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_160U; + } else if(rampTimeUs <= 176) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_176U; + } else if(rampTimeUs <= 192) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_192U; + } else if(rampTimeUs <= 208) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_208U; + } else if(rampTimeUs <= 240) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_240U; + } else if(rampTimeUs <= 272) { + regVal = RADIOLIB_LRXXXX_PA_RAMP_272U; + } else { // 304 + regVal = RADIOLIB_LRXXXX_PA_RAMP_304U; + } + + return regVal; +} + int16_t LRxxxx::setU32(uint16_t cmd, uint32_t u32) { uint8_t buff[] = { (uint8_t)((u32 >> 24) & 0xFF), (uint8_t)((u32 >> 16) & 0xFF), diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 85a09d2e18..17a1bf3063 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -53,6 +53,28 @@ #define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0 (0x06UL << 0) // 2 0 3.0V #define RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3 (0x07UL << 0) // 2 0 3.3V +// RADIOLIB_LR11X0_CMD_SET_TX_PARAMS +// RADIOLIB_LR2021_CMD_SET_TX_PARAMS +#define RADIOLIB_LRXXXX_PA_RAMP_2U (0x00UL << 0) // 7 0 PA ramp time: 2 us (LR2021 only) +#define RADIOLIB_LRXXXX_PA_RAMP_4U (0x01UL << 0) // 7 0 4 us (LR2021 only) +#define RADIOLIB_LRXXXX_PA_RAMP_8U (0x02UL << 0) // 7 0 8 us (LR2021 only) +#define RADIOLIB_LRXXXX_PA_RAMP_16U (0x03UL << 0) // 7 0 16 us +#define RADIOLIB_LRXXXX_PA_RAMP_32U (0x04UL << 0) // 7 0 32 us +#define RADIOLIB_LRXXXX_PA_RAMP_48U (0x05UL << 0) // 7 0 48 us +#define RADIOLIB_LRXXXX_PA_RAMP_64U (0x06UL << 0) // 7 0 64 us +#define RADIOLIB_LRXXXX_PA_RAMP_80U (0x07UL << 0) // 7 0 80 us +#define RADIOLIB_LRXXXX_PA_RAMP_96U (0x08UL << 0) // 7 0 96 us +#define RADIOLIB_LRXXXX_PA_RAMP_112U (0x09UL << 0) // 7 0 112 us +#define RADIOLIB_LRXXXX_PA_RAMP_128U (0x0AUL << 0) // 7 0 128 us +#define RADIOLIB_LRXXXX_PA_RAMP_144U (0x0BUL << 0) // 7 0 144 us +#define RADIOLIB_LRXXXX_PA_RAMP_160U (0x0CUL << 0) // 7 0 160 us +#define RADIOLIB_LRXXXX_PA_RAMP_176U (0x0DUL << 0) // 7 0 176 us +#define RADIOLIB_LRXXXX_PA_RAMP_192U (0x0EUL << 0) // 7 0 192 us +#define RADIOLIB_LRXXXX_PA_RAMP_208U (0x0FUL << 0) // 7 0 208 us +#define RADIOLIB_LRXXXX_PA_RAMP_240U (0x10UL << 0) // 7 0 240 us +#define RADIOLIB_LRXXXX_PA_RAMP_272U (0x11UL << 0) // 7 0 272 us +#define RADIOLIB_LRXXXX_PA_RAMP_304U (0x12UL << 0) // 7 0 304 us + class LRxxxx: public PhysicalLayer { public: LRxxxx(Module* mod); @@ -110,6 +132,7 @@ class LRxxxx: public PhysicalLayer { protected: Module* mod; + float freqMHz = 0; float dataRateMeasured = 0; // cached LoRa parameters @@ -126,6 +149,7 @@ class LRxxxx: public PhysicalLayer { // for that reason, only the methods that are 100% the same are kept here int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); int16_t lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); + uint8_t roundRampTime(uint32_t rampTimeUs); // several commands just send unsigned 32-bit number int16_t setU32(uint16_t cmd, uint32_t u32); diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index af4b0f1835..e8b002b6d3 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -330,27 +330,6 @@ #define RADIOLIB_LR2021_PA_LF_SLICES_UNUSED (0x07UL << 0) // 3 0 PA LF slices: PA not used #define RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED (0x10UL << 0) // 4 0 PA HF duty cycle: PA not used -// RADIOLIB_LR2021_CMD_SET_TX_PARAMS -#define RADIOLIB_LR2021_RAMP_TIME_2_US (0x00UL << 0) // 7 0 PA ramp time: 2 us -#define RADIOLIB_LR2021_RAMP_TIME_4_US (0x01UL << 0) // 7 0 4 us -#define RADIOLIB_LR2021_RAMP_TIME_8_US (0x02UL << 0) // 7 0 8 us -#define RADIOLIB_LR2021_RAMP_TIME_16_US (0x03UL << 0) // 7 0 16 us -#define RADIOLIB_LR2021_RAMP_TIME_32_US (0x04UL << 0) // 7 0 32 us -#define RADIOLIB_LR2021_RAMP_TIME_48_US (0x05UL << 0) // 7 0 48 us -#define RADIOLIB_LR2021_RAMP_TIME_64_US (0x06UL << 0) // 7 0 64 us -#define RADIOLIB_LR2021_RAMP_TIME_80_US (0x07UL << 0) // 7 0 80 us -#define RADIOLIB_LR2021_RAMP_TIME_96_US (0x08UL << 0) // 7 0 96 us -#define RADIOLIB_LR2021_RAMP_TIME_112_US (0x09UL << 0) // 7 0 112 us -#define RADIOLIB_LR2021_RAMP_TIME_128_US (0x0AUL << 0) // 7 0 128 us -#define RADIOLIB_LR2021_RAMP_TIME_144_US (0x0BUL << 0) // 7 0 144 us -#define RADIOLIB_LR2021_RAMP_TIME_160_US (0x0CUL << 0) // 7 0 160 us -#define RADIOLIB_LR2021_RAMP_TIME_176_US (0x0DUL << 0) // 7 0 176 us -#define RADIOLIB_LR2021_RAMP_TIME_192_US (0x0EUL << 0) // 7 0 192 us -#define RADIOLIB_LR2021_RAMP_TIME_208_US (0x0FUL << 0) // 7 0 208 us -#define RADIOLIB_LR2021_RAMP_TIME_240_US (0x10UL << 0) // 7 0 240 us -#define RADIOLIB_LR2021_RAMP_TIME_272_US (0x11UL << 0) // 7 0 272 us -#define RADIOLIB_LR2021_RAMP_TIME_304_US (0x12UL << 0) // 7 0 304 us - // RADIOLIB_LR2021_CMD_SET_PACKET_TYPE #define RADIOLIB_LR2021_PACKET_TYPE_LORA (0x00UL << 0) // 7 0 packet type: LoRa #define RADIOLIB_LR2021_PACKET_TYPE_FSK (0x02UL << 0) // 7 0 FSK From 8e38bce554964454cac3506afd612bf873cb05fe Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 29 Dec 2025 08:27:58 +0000 Subject: [PATCH 1684/1848] [LR2021] Implement frequency and output power config --- src/modules/LR2021/LR2021.cpp | 6 +++ src/modules/LR2021/LR2021.h | 53 +++++++++++++++++++ src/modules/LR2021/LR2021_commands.h | 1 + src/modules/LR2021/LR2021_config.cpp | 73 +++++++++++++++++++++++++++ src/modules/LR2021/LR2021_registers.h | 14 +++++ 5 files changed, 147 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 2533ddf239..9e23975c69 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -52,6 +52,9 @@ int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + state = setBandwidth(bw); RADIOLIB_ASSERT(state); @@ -64,6 +67,9 @@ int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync state = setSyncWord(syncWord); RADIOLIB_ASSERT(state); + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index e69d273d22..4c0961406f 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -202,6 +202,56 @@ class LR2021: public LRxxxx { // configuration methods + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, + 1900 - 2200 MHz and 2400 - 2500 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG MHz. + NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, + setOutputPower() must be called in order to set the correct power amplifier! + \param freq Carrier frequency to be set in MHz. + \returns \ref status_codes + */ + int16_t setFrequency(float freq) override; + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz, + 1900 - 2200 MHz and 2400 - 2500 MHz. + Will automatically perform image calibration if the frequency changes by + more than RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG MHz. + NOTE: When switching between sub-GHz and high-frequency bands, after changing the frequency, + setOutputPower() must be called in order to set the correct power amplifier! + \param freq Carrier frequency to be set in MHz. + \param skipCalibration Skip automated image calibration. + \returns \ref status_codes + */ + int16_t setFrequency(float freq, bool skipCalibration); + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (sub-GHz PA) or -19 to 12 dBm (high-frequency PA). + \param power Output power to be set in dBm. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power) override; + + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (sub-GHz PA) or -19 to 12 dBm (high-frequency PA). + \param power Output power to be set in dBm. + \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the + nearest discrete ramp time supported by the PA. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, uint32_t rampTimeUs); + + /*! + \brief Check if output power is configurable. + This method is needed for compatibility with PhysicalLayer::checkOutputPower. + \param power Output power in dBm, PA will be determined automatically. + \param clipped Clipped output power value to what is possible within the module's range. + \returns \ref status_codes + */ + int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + /*! \brief Sets LoRa bandwidth. Allowed values are 31.25, 41.67, 62.5, 83.34, 125.0, 101.56, 203.13, 250.0, 406.25, 500.0 kHz, 812.5 kHz and 1000.0 kHz. @@ -282,6 +332,9 @@ class LR2021: public LRxxxx { #if !RADIOLIB_GODMODE private: #endif + // flag to determine whether we are in the sub-GHz or 2.4 GHz range + // this is needed to automatically detect which PA to use + bool highFreq = false; bool findChip(void); int16_t config(uint8_t modem); diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index e8b002b6d3..4f763f45e5 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -233,6 +233,7 @@ // RADIOLIB_LR2021_CMD_CALIB_FRONT_END #define RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH (0x00UL << 15) // 15 15 calibration path: low-frequency #define RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH (0x01UL << 15) // 15 15 high-frequency +#define RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ (20.0f) // RADIOLIB_LR2021_CMD_GET_V_BAT #define RADIOLIB_LR2021_VBAT_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index e8af57c1fc..c33c89972c 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -6,6 +6,79 @@ #if !RADIOLIB_EXCLUDE_LR2021 +int16_t LR2021::setFrequency(float freq) { + return(this->setFrequency(freq, false)); +} + +int16_t LR2021::setFrequency(float freq, bool skipCalibration) { + #if RADIOLIB_CHECK_PARAMS + if(!(((freq >= 150.0f) && (freq <= 960.0f)) || + ((freq >= 1900.0f) && (freq <= 2200.0f)) || + ((freq >= 2400.0f) && (freq <= 2500.0f)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + #endif + + // check if we need to recalibrate image + int16_t state; + if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ)) { + // we do, get the nearest multiple of 4 MHz + uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 }; + frequencies[0] |= (freq > 1000.0f) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; + state = calibrateFrontEnd(frequencies); + RADIOLIB_ASSERT(state); + } + + // set frequency + state = setRfFrequency((uint32_t)(freq*1000000.0f)); + RADIOLIB_ASSERT(state); + this->freqMHz = freq; + this->highFreq = (freq > 1000.0f); + return(state); +} + +int16_t LR2021::setOutputPower(int8_t power) { + return(this->setOutputPower(power, false)); +} + +int16_t LR2021::setOutputPower(int8_t power, uint32_t rampTimeUs) { + // check if power value is configurable + int16_t state = this->checkOutputPower(power, NULL); + RADIOLIB_ASSERT(state); + + //! \TODO: [LR2021] how and when to configure OCP? + //! \TODO: [LR2021] Determine the optimal PA configuration + // update PA config + state = setPaConfig(this->highFreq, + RADIOLIB_LR2021_PA_LF_MODE_FSM, + RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED, + RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, + RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, roundRampTime(rampTimeUs)); + return(state); +} + +int16_t LR2021::checkOutputPower(int8_t power, int8_t* clipped) { + if(this->highFreq) { + if(clipped) { + *clipped = RADIOLIB_MAX(-19, RADIOLIB_MIN(12, power)); + } + RADIOLIB_CHECK_RANGE(power, -19, 12, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } else { + if(clipped) { + *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power)); + } + RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER); + + } + + return(RADIOLIB_ERR_NONE); +} + int16_t LR2021::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; diff --git a/src/modules/LR2021/LR2021_registers.h b/src/modules/LR2021/LR2021_registers.h index 8db1b1f3ee..06ea739f13 100644 --- a/src/modules/LR2021/LR2021_registers.h +++ b/src/modules/LR2021/LR2021_registers.h @@ -6,8 +6,22 @@ #if !RADIOLIB_EXCLUDE_LR2021 // LR2021 SPI registers +#define RADIOLIB_LR2021_REG_DCDC_FREQ_LF (0x80004C) +#define RADIOLIB_LR2021_REG_DCDC_SWITCHER (0xF20024) +#define RADIOLIB_LR2021_REG_RTTOF_RSSI_POWER_OFFSET (0xF30128) +#define RADIOLIB_LR2021_REG_RESULT_DEVIATION_CHANNEL_FILTER (0xF3013C) +#define RADIOLIB_LR2021_REG_RESULT_DEVIATION_DCC (0xF30134) +#define RADIOLIB_LR2021_REG_RTTOF_RSSI_MAX_GAIN (0xF301A4) #define RADIOLIB_LR2021_REG_LORA_MODEM_TXRX_CFG0 (0xF30A14) #define RADIOLIB_LR2021_REG_LORA_MODEM_MAIN_TX_CFG1 (0xF30A24) +#define RADIOLIB_LR2021_REG_RTTOF_EXTENDED_STUCK (0xF30B50) +#define RADIOLIB_LR2021_REG_BLE_PHY_CODED_FREQ_DRIFT (0xF30C28) +#define RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD (0xF30E14) +#define RADIOLIB_LR2021_REG_RTTOF_RF_FREQ (0xF40144) +#define RADIOLIB_LR2021_REG_DCDC_ADC_CTRL (0xF40200) +#define RADIOLIB_LR2021_REG_OCP_CONTROL_UNLOCK (0xF40338) +#define RADIOLIB_LR2021_REG_OCP_THRESHOLDS (0xF40300) +#define RADIOLIB_LR2021_REG_DCDC_RX_PATH (0xF40430) #endif From 6adaf76b57c7222ed4bc48faaf70ecc5617c9e75 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 29 Dec 2025 14:03:20 +0000 Subject: [PATCH 1685/1848] [LR2021] Rename FSK to GFSK for consistency with LR11xx --- src/modules/LR2021/LR2021.cpp | 6 ++--- src/modules/LR2021/LR2021.h | 16 ++++++------- src/modules/LR2021/LR2021_cmds_gfsk.cpp | 32 ++++++++++++------------- src/modules/LR2021/LR2021_cmds_ook.cpp | 6 ++--- src/modules/LR2021/LR2021_commands.h | 24 +++++++++---------- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 9e23975c69..7f1305a978 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -113,7 +113,7 @@ int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (150% of expected time-on-air) timeout = (timeout * 3) / 2; - } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_FSK) || (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS)) { + } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS)) { // calculate timeout (500% of expected time-on-air) timeout = timeout * 5; @@ -156,7 +156,7 @@ int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; state = getPacketType(&modem); RADIOLIB_ASSERT(state); - if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR2021_PACKET_TYPE_FSK)) { + if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { // calculate timeout (500 % of expected time-one-air) size_t maxLen = len; if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; } @@ -333,7 +333,7 @@ int16_t LR2021::readData(uint8_t* data, size_t len) { state = getPacketType(&modem); RADIOLIB_ASSERT(state); if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && - (modem != RADIOLIB_LR2021_PACKET_TYPE_FSK)) { + (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { return(RADIOLIB_ERR_WRONG_MODEM); } diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 4c0961406f..12f510bc70 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -428,14 +428,14 @@ class LR2021: public LRxxxx { int16_t setRangingParams(bool spyMode, uint8_t nbSymbols); // GFSK commands - int16_t setFskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); - int16_t setFskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree); - int16_t setFskWhiteningParams(uint8_t whitenType, uint16_t init); - int16_t setFskCrcParams(uint32_t poly, uint32_t init); - int16_t setFskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst); - int16_t setFskAddress(uint8_t addrNode, uint8_t addrBroadcast); - int16_t getFskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout); - int16_t getFskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); + int16_t setGfskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); + int16_t setGfskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree); + int16_t setGfskWhiteningParams(uint8_t whitenType, uint16_t init); + int16_t setGfskCrcParams(uint32_t poly, uint32_t init); + int16_t setGfskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst); + int16_t setGfskAddress(uint8_t addrNode, uint8_t addrBroadcast); + int16_t getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout); + int16_t getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); // OQPSK commands int16_t setOqpskParams(uint8_t mode, uint8_t rxBw, uint8_t payloadLen, uint16_t preambleLen, bool addrFilt, bool fcsManual); diff --git a/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/src/modules/LR2021/LR2021_cmds_gfsk.cpp index 3f16a2f7ac..999137f738 100644 --- a/src/modules/LR2021/LR2021_cmds_gfsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_gfsk.cpp @@ -7,61 +7,61 @@ #if !RADIOLIB_EXCLUDE_LR2021 -int16_t LR2021::setFskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { +int16_t LR2021::setGfskModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) { uint8_t buff[] = { (uint8_t)((bitRate >> 24) & 0xFF), (uint8_t)((bitRate >> 16) & 0xFF), (uint8_t)((bitRate >> 8) & 0xFF), (uint8_t)(bitRate & 0xFF), pulseShape, rxBw, (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF), }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_MODULATION_PARAMS, true, buff, sizeof(buff))); } -int16_t LR2021::setFskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree) { +int16_t LR2021::setGfskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree) { uint8_t buff[] = { (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), preambleDetect, (uint8_t)(((uint8_t)longPreamble << 5) | ((uint8_t)pldLenBits << 4) | (addrComp << 2) | ((uint8_t)packetFormat & 0x03)), (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF), (uint8_t)((crc << 4) | (dcFree << 4)), }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_PACKET_PARAMS, true, buff, sizeof(buff))); } -int16_t LR2021::setFskWhiteningParams(uint8_t whitenType, uint16_t init) { +int16_t LR2021::setGfskWhiteningParams(uint8_t whitenType, uint16_t init) { uint8_t buff[] = { (uint8_t)((whitenType << 4) | (uint8_t)((init >> 8) & 0x0F)), (uint8_t)(init & 0xFF), }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_WHITENING_PARAMS, true, buff, sizeof(buff))); } -int16_t LR2021::setFskCrcParams(uint32_t poly, uint32_t init) { +int16_t LR2021::setGfskCrcParams(uint32_t poly, uint32_t init) { uint8_t buff[] = { (uint8_t)((poly >> 24) & 0xFF), (uint8_t)((poly >> 16) & 0xFF), (uint8_t)((poly >> 8) & 0xFF), (uint8_t)(poly & 0xFF), (uint8_t)((init >> 24) & 0xFF), (uint8_t)((init >> 16) & 0xFF), (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_CRC_PARAMS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff))); } -int16_t LR2021::setFskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { +int16_t LR2021::setGfskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { uint8_t buff[9] = { 0 }; for(size_t i = 0; i < syncWordLen; i++) { buff[7 - i] = syncWord[i]; } buff[8] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD, true, buff, sizeof(buff))); } -int16_t LR2021::setFskAddress(uint8_t addrNode, uint8_t addrBroadcast) { +int16_t LR2021::setGfskAddress(uint8_t addrNode, uint8_t addrBroadcast) { uint8_t buff[] = { addrNode, addrBroadcast }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_ADDRESS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_ADDRESS, true, buff, sizeof(buff))); } -int16_t LR2021::getFskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout) { +int16_t LR2021::getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout) { uint8_t buff[14] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(packetCrcError) { *packetCrcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } @@ -72,9 +72,9 @@ int16_t LR2021::getFskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint return(state); } -int16_t LR2021::getFskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { +int16_t LR2021::getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); uint16_t raw = 0; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 78c25f6f4c..d925968d27 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -42,7 +42,7 @@ int16_t LR2021::setOokSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFi buff[3 - i] = syncWord[i]; } buff[4] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD, true, buff, sizeof(buff))); } int16_t LR2021::setOokAddress(uint8_t addrNode, uint8_t addrBroadcast) { @@ -52,7 +52,7 @@ int16_t LR2021::setOokAddress(uint8_t addrNode, uint8_t addrBroadcast) { int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError) { uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(crcError) { *crcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } @@ -61,7 +61,7 @@ int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); uint16_t raw = 0; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 4f763f45e5..c3974630f7 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -88,14 +88,14 @@ #define RADIOLIB_LR2021_CMD_GET_RANGING_STATS (0x027D) #define RADIOLIB_LR2021_CMD_SET_RANGING_TX_RX_DELAY (0x027B) #define RADIOLIB_LR2021_CMD_SET_RANGING_PARAMS (0x027C) -#define RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS (0x0240) -#define RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS (0x0241) -#define RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS (0x0242) -#define RADIOLIB_LR2021_CMD_SET_FSK_CRC_PARAMS (0x0243) -#define RADIOLIB_LR2021_CMD_SET_FSK_SYNCWORD (0x0244) -#define RADIOLIB_LR2021_CMD_SET_FSK_ADDRESS (0x0245) -#define RADIOLIB_LR2021_CMD_GET_FSK_RX_STATS (0x0246) -#define RADIOLIB_LR2021_CMD_GET_FSK_PACKET_STATUS (0x0247) +#define RADIOLIB_LR2021_CMD_SET_GFSK_MODULATION_PARAMS (0x0240) +#define RADIOLIB_LR2021_CMD_SET_GFSK_PACKET_PARAMS (0x0241) +#define RADIOLIB_LR2021_CMD_SET_GFSK_WHITENING_PARAMS (0x0242) +#define RADIOLIB_LR2021_CMD_SET_GFSK_CRC_PARAMS (0x0243) +#define RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD (0x0244) +#define RADIOLIB_LR2021_CMD_SET_GFSK_ADDRESS (0x0245) +#define RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS (0x0246) +#define RADIOLIB_LR2021_CMD_GET_GFSK_PACKET_STATUS (0x0247) #define RADIOLIB_LR2021_CMD_SET_WMBUS_PARAMS (0x026A) #define RADIOLIB_LR2021_CMD_GET_WMBUS_RX_STATS (0x026C) #define RADIOLIB_LR2021_CMD_GET_WMBUS_PACKET_STATUS (0x026D) @@ -333,7 +333,7 @@ // RADIOLIB_LR2021_CMD_SET_PACKET_TYPE #define RADIOLIB_LR2021_PACKET_TYPE_LORA (0x00UL << 0) // 7 0 packet type: LoRa -#define RADIOLIB_LR2021_PACKET_TYPE_FSK (0x02UL << 0) // 7 0 FSK +#define RADIOLIB_LR2021_PACKET_TYPE_GFSK (0x02UL << 0) // 7 0 FSK #define RADIOLIB_LR2021_PACKET_TYPE_BLE (0x03UL << 0) // 7 0 BLE #define RADIOLIB_LR2021_PACKET_TYPE_RTTOF (0x04UL << 0) // 7 0 RTToF #define RADIOLIB_LR2021_PACKET_TYPE_FLRC (0x05UL << 0) // 7 0 FLRC @@ -400,7 +400,7 @@ #define RADIOLIB_LR2021_RANGING_RESULT_TYPE_RAW_EXT (0x01UL << 0) // 7 0 extended raw #define RADIOLIB_LR2021_RANGING_RESULT_TYPE_GAINS (0x02UL << 0) // 7 0 AGC gain steps -// RADIOLIB_LR2021_CMD_SET_FSK_MODULATION_PARAMS +// RADIOLIB_LR2021_CMD_SET_GFSK_MODULATION_PARAMS #define RADIOLIB_LR2021_GFSK_BPSK_OOK_BITRATE_BPS (0x00UL << 31) // 7 0 bitrate units: bits per second #define RADIOLIB_LR2021_GFSK_BPSK_OOK_BITRATE_FRACTIONAL (0x01UL << 31) // 7 0 fractional (1/256 bps) #define RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE (0x00UL << 0) // 7 0 shaping filter: none @@ -443,7 +443,7 @@ #define RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666 (128) // 7 0 2667 kHz #define RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076 (0) // 7 0 3077 kHz -// RADIOLIB_LR2021_CMD_SET_FSK_PACKET_PARAMS +// RADIOLIB_LR2021_CMD_SET_GFSK_PACKET_PARAMS #define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED (0x00UL << 0) // 7 0 address filtering: disabled #define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE (0x01UL << 0) // 7 0 node only #define RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST (0x02UL << 0) // 7 0 node and broadcast @@ -461,7 +461,7 @@ #define RADIOLIB_LR2021_GFSK_OOK_CRC24_INV (0x0BUL << 0) // 7 0 3-byte, inverted #define RADIOLIB_LR2021_GFSK_OOK_CRC32_INV (0x0CUL << 0) // 7 0 4-byte, inverted -// RADIOLIB_LR2021_CMD_SET_FSK_WHITENING_PARAMS +// RADIOLIB_LR2021_CMD_SET_GFSK_WHITENING_PARAMS #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR2021 #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX128X (0x01UL << 0) // 7 0 compatible with SX128x From a6c97ac009ba9d2f4cdade7c9a663d561f88fe33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sat, 3 Jan 2026 15:31:48 +0100 Subject: [PATCH 1686/1848] [HAL] Rework RPi Pico interrupts (#1667) (#1669) --- src/hal/RPiPico/PicoHal.h | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/hal/RPiPico/PicoHal.h b/src/hal/RPiPico/PicoHal.h index 8329707de0..256e159622 100644 --- a/src/hal/RPiPico/PicoHal.h +++ b/src/hal/RPiPico/PicoHal.h @@ -12,8 +12,29 @@ #include "hardware/timer.h" #include "hardware/pwm.h" #include "hardware/clocks.h" +#include "hardware/gpio.h" #include "pico/multicore.h" +#define PI_PICO_MAX_USER_GPIO (48) + +// because the Pico SDK does not allow to pass user data into interrupt handlers, +// we keep it as a global here. This is hacky and means that multiple PicoHal +// instances share the same interrupts, which is weird and will probably break. +// However, there seems to be no real use case for creating multiple intances of the HAL +static irq_handler_t picoHalUserCallbacks[PI_PICO_MAX_USER_GPIO] = { 0 }; +static uint32_t picoHalIrqEventMasks[PI_PICO_MAX_USER_GPIO] = { 0 }; + +static void picoInterruptHandler(void) { + for(int gpio = 0; gpio < PI_PICO_MAX_USER_GPIO; gpio++) { + if(gpio_get_irq_event_mask(gpio) == picoHalIrqEventMasks[gpio]) { + gpio_acknowledge_irq(gpio, picoHalIrqEventMasks[gpio]); + if(picoHalUserCallbacks[gpio]) { + picoHalUserCallbacks[gpio](); + } + } + } +} + // create a new Raspberry Pi Pico hardware abstraction // layer using the Pico SDK // the HAL must inherit from the base RadioLibHal class @@ -69,7 +90,14 @@ class PicoHal : public RadioLibHal { return; } - gpio_set_irq_enabled_with_callback(interruptNum, mode, true, (gpio_irq_callback_t)interruptCb); + // set callbacks + picoHalUserCallbacks[interruptNum] = (irq_handler_t)interruptCb; + picoHalIrqEventMasks[interruptNum] = mode; + + // enable IRQ and set the internal callback + gpio_set_irq_enabled(interruptNum, mode, true); + gpio_add_raw_irq_handler_masked(1UL << interruptNum, picoInterruptHandler); + irq_set_enabled(IO_IRQ_BANK0, true); } void detachInterrupt(uint32_t interruptNum) override { @@ -77,7 +105,12 @@ class PicoHal : public RadioLibHal { return; } - gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL); + // disable the IRQ + gpio_set_irq_enabled(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false); + + // clear callbacks + picoHalUserCallbacks[interruptNum] = NULL; + picoHalIrqEventMasks[interruptNum] = 0; } void delay(unsigned long ms) override { From 2c187e7c9168519a24d377047cfb3cdb1d4a4cff Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 3 Jan 2026 15:46:35 +0000 Subject: [PATCH 1687/1848] [CI] Cleanup before ESP-IDF clone --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2be588716c..672eeed9e9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -254,6 +254,7 @@ jobs: - name: Clone ESP-IDF run: | + rm -rf ~/esp mkdir -p ~/esp cd ~/esp git clone --recursive https://github.com/espressif/esp-idf.git From bffaf7d7e878735233d59b30ad1d3ac2736f5bba Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 3 Jan 2026 15:55:09 +0000 Subject: [PATCH 1688/1848] [CI] Update ESP-IDF --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 672eeed9e9..bfe8265e49 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -259,7 +259,7 @@ jobs: cd ~/esp git clone --recursive https://github.com/espressif/esp-idf.git cd esp-idf - git checkout v5.4.2 + git checkout v5.4.3 git submodule update --init --recursive - name: Install ESP-IDF From badec217a7c575b252d345ed551bf8b4ed8c306e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sat, 3 Jan 2026 20:54:31 +0100 Subject: [PATCH 1689/1848] [CI] Fix ESP-IDF CI (#1670) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bfe8265e49..951b38123f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -257,7 +257,7 @@ jobs: rm -rf ~/esp mkdir -p ~/esp cd ~/esp - git clone --recursive https://github.com/espressif/esp-idf.git + git clone https://github.com/espressif/esp-idf.git cd esp-idf git checkout v5.4.3 git submodule update --init --recursive From e11293ea0eddca530c7c02efc42bf554d3f19c52 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Wed, 7 Jan 2026 11:46:39 +0100 Subject: [PATCH 1690/1848] [LoRaWAN] Fix setting DataRate and TxPower before join --- src/protocols/LoRaWAN/LoRaWAN.cpp | 37 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 83a3d9b659..9004f7215f 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -323,7 +323,8 @@ void LoRaWANNode::clearSession() { this->confFCntDown = RADIOLIB_LORAWAN_FCNT_NONE; this->adrFCnt = 0; - // set Tx power limit + // reset Tx steps and power limit + this->txPowerSteps = 0; this->txPowerMax = this->band->powerMax; // clear CSMA settings @@ -339,8 +340,12 @@ void LoRaWANNode::clearSession() { srand(this->phyLayer->random(INT32_MAX)); // reset all channels + memset(this->channels, 0, sizeof(this->channels)); memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels)); + // reset the JoinRequest datarate + this->channels[RADIOLIB_LORAWAN_UPLINK].dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED; + // reset Rx2 channel to default value this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2; @@ -361,19 +366,25 @@ void LoRaWANNode::createSession() { this->enableDefaultChannels(); // set default MAC state + uint8_t cOcts[5]; // 5 = maximum downlink payload length // set data rate and Tx power - uint8_t cOcts[5]; // 5 = maximum downlink payload length uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; uint8_t cLen = 1; // only apply Dr/Tx field - uint8_t drUp; - if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { - drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax + 1) / 2; - } else { // RADIOLIB_LORAWAN_BAND_FIXED - drUp = (this->band->txSpans[0].drMin + this->band->txSpans[0].drMin + 1) / 2; + + // DR and TxPower may have been configured before creating session, + // otherwise they are default values (see ::clearSession) + uint8_t drUp = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; + if(drUp == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { + if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { + drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax + 1) / 2; + } else { // RADIOLIB_LORAWAN_BAND_FIXED + drUp = (this->band->txSpans[0].drMin + this->band->txSpans[0].drMin + 1) / 2; + } } - cOcts[0] = (drUp << 4); // set requested datarate - cOcts[0] |= 0x00; // set maximum Tx power + uint8_t txSteps = this->txPowerSteps; + cOcts[0] = (drUp << 4); + cOcts[0] |= txSteps; (void)execMacCommand(cid, cOcts, cLen); // set maximum dutycycle @@ -3024,6 +3035,10 @@ void LoRaWANNode::clearMacCommands(uint8_t* inOut, uint8_t* lenInOut, uint8_t di } int16_t LoRaWANNode::setDatarate(uint8_t drUp) { + // if called before activation, already create a session + if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_NONE) { + this->createSession(); + } uint8_t cOcts[1]; uint8_t cAck[1]; uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; @@ -3042,6 +3057,10 @@ int16_t LoRaWANNode::setDatarate(uint8_t drUp) { } int16_t LoRaWANNode::setTxPower(int8_t txPower) { + // if called before activation, already create a session + if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_NONE) { + this->createSession(); + } // only allow values within the band's (or MAC state) maximum if(txPower > this->txPowerMax) { return(RADIOLIB_ERR_INVALID_OUTPUT_POWER); From 6df4a87960f10a9670836126ef69b51923e69ca5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 7 Jan 2026 20:31:48 +0100 Subject: [PATCH 1691/1848] [Pager] Fix receive example implying SX126x can be used (#1672) --- examples/Pager/Pager_Receive/Pager_Receive.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/Pager/Pager_Receive/Pager_Receive.ino b/examples/Pager/Pager_Receive/Pager_Receive.ino index edc97867f7..61a010f3d4 100644 --- a/examples/Pager/Pager_Receive/Pager_Receive.ino +++ b/examples/Pager/Pager_Receive/Pager_Receive.ino @@ -39,7 +39,6 @@ SX1278 radio = new Module(10, 2, 9, 3); // SX1231: DIO2 // CC1101: GDO2 // Si443x/RFM2x: GPIO -// SX126x/LLCC68: DIO2 const int pin = 5; // create Pager client instance using the FSK module From be9787d150d90f2adf93e083244539dd3692a9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Fri, 9 Jan 2026 21:51:07 +0100 Subject: [PATCH 1692/1848] [SX126x] Add optimized PA configuration table for SX1262 and SX1268 (#1662) * [SX126x] Add optimized PA table for SX1262 * [SX1262] Update optimized PA table * [SX126x] Fix doxygen comments * [SX1268] Add optimized PA table for SX1268 * [SX126x] Make PA configuration accessible via public API --- src/modules/SX126x/SX1262.cpp | 22 +++++-------- src/modules/SX126x/SX1262.h | 46 ++++++++++++++++++++++++++++ src/modules/SX126x/SX1268.cpp | 22 +++++-------- src/modules/SX126x/SX1268.h | 46 ++++++++++++++++++++++++++++ src/modules/SX126x/SX126x.h | 26 ++++++++++++++++ src/modules/SX126x/SX126x_config.cpp | 19 ++++++++++++ 6 files changed, 153 insertions(+), 28 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index a72163f060..8c7c0a3ac0 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -103,25 +103,19 @@ int16_t SX1262::setFrequency(float freq, bool skipCalibration) { } int16_t SX1262::setOutputPower(int8_t power) { + return(setOutputPower(power, true)); +} + +int16_t SX1262::setOutputPower(int8_t power, bool optimize) { // check if power value is configurable int16_t state = checkOutputPower(power, NULL); RADIOLIB_ASSERT(state); - // get current OCP configuration - uint8_t ocp = 0; - state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); - RADIOLIB_ASSERT(state); - // set PA config - state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1262); - RADIOLIB_ASSERT(state); - - // set output power with default 200us ramp - state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); - RADIOLIB_ASSERT(state); - - // restore OCP configuration - return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + int8_t paVal = optimize ? this->paOptTable[power + 9].paVal : power; + uint8_t paDutyCycle = optimize ? this->paOptTable[power + 9].paDutyCycle : 0x04; + uint8_t hpMax = optimize ? this->paOptTable[power + 9].hpMax : 0x07; + return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1262)); } int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) { diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index da2c31bf56..95d8f4a094 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -121,6 +121,14 @@ class SX1262: public SX126x { */ virtual int16_t setOutputPower(int8_t power) override; + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm. + \param power Output power to be set in dBm. + \param optimize Whether to use power-optimized PA configuration (true) or datasheet default (false). + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool optimize); + /*! \brief Check if output power is configurable. \param power Output power in dBm. @@ -141,6 +149,44 @@ class SX1262: public SX126x { private: #endif + // this is a lookup table for optimized PA configuration + // it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628 + // see also https://github.com/radiolib-org/power-tests + const SX126x::paTableEntry_t paOptTable[32] = { + { .paDutyCycle = 2, .hpMax = 2, .paVal = -5 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 0 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 3 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 0 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 6 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 2 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 6 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 11 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 11 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 14 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 14 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 11 }, + { .paDutyCycle = 3, .hpMax = 1, .paVal = 21 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 17 }, + { .paDutyCycle = 4, .hpMax = 2, .paVal = 13 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 1, .hpMax = 4, .paVal = 19 }, + { .paDutyCycle = 1, .hpMax = 4, .paVal = 20 }, + { .paDutyCycle = 3, .hpMax = 3, .paVal = 20 }, + { .paDutyCycle = 2, .hpMax = 5, .paVal = 19 }, + { .paDutyCycle = 1, .hpMax = 6, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 6, .paVal = 22 }, + { .paDutyCycle = 4, .hpMax = 6, .paVal = 22 }, + { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 }, + }; + }; #endif diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 018ffb6eb1..5015dcd5b7 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -104,25 +104,19 @@ int16_t SX1268::setFrequency(float freq, bool skipCalibration) { } int16_t SX1268::setOutputPower(int8_t power) { + return(setOutputPower(power, true)); +} + +int16_t SX1268::setOutputPower(int8_t power, bool optimize) { // check if power value is configurable int16_t state = checkOutputPower(power, NULL); RADIOLIB_ASSERT(state); - // get current OCP configuration - uint8_t ocp = 0; - state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); - RADIOLIB_ASSERT(state); - // set PA config - state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1268); - RADIOLIB_ASSERT(state); - - // set output power with default 200us ramp - state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); - RADIOLIB_ASSERT(state); - - // restore OCP configuration - return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + int8_t paVal = optimize ? this->paOptTable[power + 9].paVal : power; + uint8_t paDutyCycle = optimize ? this->paOptTable[power + 9].paDutyCycle : 0x04; + uint8_t hpMax = optimize ? this->paOptTable[power + 9].hpMax : 0x07; + return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1268)); } int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) { diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 911d2e7a40..c6eae7442d 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -119,6 +119,14 @@ class SX1268: public SX126x { */ int16_t setOutputPower(int8_t power) override; + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm. + \param power Output power to be set in dBm. + \param optimize Whether to use power-optimized PA configuration (true) or datasheet default (false). + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, bool optimize); + /*! \brief Check if output power is configurable. \param power Output power in dBm. @@ -139,6 +147,44 @@ class SX1268: public SX126x { private: #endif + // this is a lookup table for optimized PA configuration + // it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628 + // see also https://github.com/radiolib-org/power-tests + const SX126x::paTableEntry_t paOptTable[32] = { + { .paDutyCycle = 2, .hpMax = 1, .paVal = -3 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = -2 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 0 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = -1 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 2 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 0 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 1 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 }, + { .paDutyCycle = 1, .hpMax = 3, .paVal = 3 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 5 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 9 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 8 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 7 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 13 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 11 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 19 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 19 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 17 }, + { .paDutyCycle = 1, .hpMax = 6, .paVal = 12 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 16 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 18 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 2, .hpMax = 3, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 6, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 7, .paVal = 22 }, + { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 }, + }; + }; #endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index a4cbccce50..a1513f819d 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -43,6 +43,17 @@ class SX126x: public PhysicalLayer { using PhysicalLayer::startReceive; using PhysicalLayer::readData; + /*! + \struct paTableEntry_t + \brief This structure is used as entry in the PA lookup table, + to optimize PA configuration for minimum power consumption. + */ + struct __attribute__((packed)) paTableEntry_t { + uint8_t paDutyCycle: 4; + uint8_t hpMax: 4; + int8_t paVal; + }; + /*! \brief Default constructor. \param mod Instance of Module that will be used to communicate with the radio. @@ -795,6 +806,21 @@ class SX126x: public PhysicalLayer { */ int16_t setPaRampTime(uint8_t rampTime); + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm. + This method allows user full control over PA configuration parameters. + If you set incorrect PA configuration values, you can fail to reach the + desired output power level or damage your device. + Unless you can verify the output power, it is strongly advised to use + SX1262::setOutputPower(power) or SX1268::setOutputPower(power). + \param power Output power to be set in dBm. + \param paDutyCycle Raw PA duty cycle value. + \param hpMax Raw hpMax value. + \param deviceSel Device select. Use either RADIOLIB_SX126X_PA_CONFIG_SX1262 or RADIOLIB_SX126X_PA_CONFIG_SX1268. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 0d60825eb9..3a13404b1a 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -711,10 +711,29 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } + int16_t SX126x::setPaRampTime(uint8_t rampTime) { return(this->setTxParams(this->pwr, rampTime)); } +int16_t SX126x::setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel) { + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + RADIOLIB_ASSERT(state); + + // set PA config + state = SX126x::setPaConfig(paDutyCycle, deviceSel, hpMax); + RADIOLIB_ASSERT(state); + + // set output power with default 200us ramp + state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U); + RADIOLIB_ASSERT(state); + + // restore OCP configuration + return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); +} + int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) { // check active modem if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) { From 9d096018c478f8e7929de681635589a8948accc9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 10 Jan 2026 12:14:37 +0100 Subject: [PATCH 1693/1848] Bump version to 7.5.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index b9fa9678eb..6a6b28f6d0 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.4.0" +version: "7.5.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index 4a5d73dbf8..3d4b786285 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.4.0", + "version": "7.5.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 651c8d51d7..9306030f91 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.4.0 +version=7.5.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 6575680270..ef2eb1d4f6 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -611,7 +611,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 -#define RADIOLIB_VERSION_MINOR 4 +#define RADIOLIB_VERSION_MINOR 5 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From 5cf858282992c5ec258cb50c7006e7fde7fec87b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 10 Jan 2026 16:39:13 +0000 Subject: [PATCH 1694/1848] [LR11x0] Add public interface for PA control --- src/modules/LR11x0/LR1110.cpp | 8 ++------ src/modules/LR11x0/LR1120.cpp | 8 ++------ src/modules/LR11x0/LR11x0.cpp | 10 ++++++++++ src/modules/LR11x0/LR11x0.h | 20 ++++++++++++++++++++ src/modules/LR11x0/LR11x0_commands.h | 2 ++ 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 46fd4f1537..87b707b30b 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -81,12 +81,8 @@ int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampT // TODO how and when to configure OCP? - // update PA config - always use VBAT for high-power PA - state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07); - RADIOLIB_ASSERT(state); - - // set output power - state = setTxParams(power, roundRampTime(rampTimeUs)); + // update PA config and set output power - always use VBAT for high-power PA + state = LR11x0::setOutputPower(power, (uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07, rampTimeUs); return(state); } diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index 9f42fff26c..f0c6ebd9fc 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -97,12 +97,8 @@ int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampT // TODO how and when to configure OCP? - // update PA config - always use VBAT for high-power PA - state = setPaConfig(paSel, paSupply, 0x04, 0x07); - RADIOLIB_ASSERT(state); - - // set output power - state = setTxParams(power, roundRampTime(rampTimeUs)); + // update PA config and set output power - always use VBAT for high-power PA + state = LR11x0::setOutputPower(power, paSel, paSupply, 0x04, 0x07, rampTimeUs); return(state); } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 614ebba274..c8a08df78f 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1402,6 +1402,16 @@ int16_t LR11x0::setRxBoostedGainMode(bool en) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff))); } +int16_t LR11x0::setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint32_t rampTimeUs) { + // set PA config + int16_t state = setPaConfig(paSel, regPaSupply, paDutyCycle, paHpSel); + RADIOLIB_ASSERT(state); + + // set output power + state = setTxParams(power, roundRampTime(rampTimeUs)); + return(state); +} + void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { // find which pins are used uint8_t enable = 0; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 70f102d9c1..986100e56d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -594,6 +594,26 @@ class LR11x0: public PhysicalLayer { */ int16_t setRxBoostedGainMode(bool en); + /*! + \brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA), + -17 to 14 dBm (low-power PA) and -18 to 13 dBm (high-frequency PA). + This method allows user full control over PA configuration parameters. + If you set incorrect PA configuration values, you can fail to reach the + desired output power level or damage your device. + Unless you can verify the output power, it is strongly advised to use + LR1110::setOutputPower(power) or LR1120::setOutputPower(power). + \param power Output power to be set in dBm. + \param paSel PA selection, low-power, high-power or high-frequency. One of RADIOLIB_LR11X0_PA_SEL_* macros. + \param regPaSupply PA power source selection, internal regulator or VBAT. One of RADIOLIB_LR11X0_PA_SUPPLY_* macros. + Must be set to RADIOLIB_LR11X0_PA_SUPPLY_VBAT when output power is more than 14 dBm. + \param paDutyCycle PA duty cycle. + \param paHpSel High-power PA size control. + \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the + nearest discrete ramp time supported by the PA. Defaults to 48 us. + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint32_t rampTimeUs = 48); + /*! \copydoc Module::setRfSwitchTable */ void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index d0c0d18afa..3ad2f4aa70 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -464,6 +464,8 @@ #define RADIOLIB_LR11X0_PA_SEL_HF (0x02UL << 0) // 7 0 high frequency PA #define RADIOLIB_LR11X0_PA_SUPPLY_INTERNAL (0x00UL << 0) // 7 0 PA power source: internal #define RADIOLIB_LR11X0_PA_SUPPLY_VBAT (0x01UL << 0) // 7 0 VBAT (required for >= 14 dBm) +#define RADIOLIB_LR11X0_PA_DC_DEFAULT (0x04UL << 0) // 7 0 PA duty cycle: default value +#define RADIOLIB_LR11X0_PA_DC_MAX (0x07UL << 0) // 7 0 maximum value // RADIOLIB_LR11X0_CMD_STOP_TIMEOUT_ON_PREAMBLE #define RADIOLIB_LR11X0_STOP_ON_SYNC_HEADER (0x00UL << 0) // 0 0 stop timeout on: sync word or header (default) From 34774e3149d21d2df1e435fc293e1d7b913651d6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 11 Jan 2026 13:51:34 +0100 Subject: [PATCH 1695/1848] [SX126x] Move PA optimized tables out of derived classes (#1675) --- src/modules/SX126x/SX1262.cpp | 45 ++++++++++++++++++++++++++++++++--- src/modules/SX126x/SX1262.h | 38 ----------------------------- src/modules/SX126x/SX1268.cpp | 44 +++++++++++++++++++++++++++++++--- src/modules/SX126x/SX1268.h | 38 ----------------------------- 4 files changed, 83 insertions(+), 82 deletions(-) diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 8c7c0a3ac0..63c221aabe 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -3,6 +3,45 @@ #if !RADIOLIB_EXCLUDE_SX126X +// this is a lookup table for optimized PA configuration +// it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628 +// see also https://github.com/radiolib-org/power-tests +static const SX126x::paTableEntry_t paOptTable[32] = { + { .paDutyCycle = 2, .hpMax = 2, .paVal = -5 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 0 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 3 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 0 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 6 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 2 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 6 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 11 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 11 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 14 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 14 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 11 }, + { .paDutyCycle = 3, .hpMax = 1, .paVal = 21 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 17 }, + { .paDutyCycle = 4, .hpMax = 2, .paVal = 13 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 1, .hpMax = 4, .paVal = 19 }, + { .paDutyCycle = 1, .hpMax = 4, .paVal = 20 }, + { .paDutyCycle = 3, .hpMax = 3, .paVal = 20 }, + { .paDutyCycle = 2, .hpMax = 5, .paVal = 19 }, + { .paDutyCycle = 1, .hpMax = 6, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 6, .paVal = 22 }, + { .paDutyCycle = 4, .hpMax = 6, .paVal = 22 }, + { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 }, +}; + + SX1262::SX1262(Module* mod) : SX126x(mod) { chipType = RADIOLIB_SX1262_CHIP_TYPE; } @@ -112,9 +151,9 @@ int16_t SX1262::setOutputPower(int8_t power, bool optimize) { RADIOLIB_ASSERT(state); // set PA config - int8_t paVal = optimize ? this->paOptTable[power + 9].paVal : power; - uint8_t paDutyCycle = optimize ? this->paOptTable[power + 9].paDutyCycle : 0x04; - uint8_t hpMax = optimize ? this->paOptTable[power + 9].hpMax : 0x07; + int8_t paVal = optimize ? paOptTable[power + 9].paVal : power; + uint8_t paDutyCycle = optimize ? paOptTable[power + 9].paDutyCycle : 0x04; + uint8_t hpMax = optimize ? paOptTable[power + 9].hpMax : 0x07; return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1262)); } diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index 95d8f4a094..454e00a898 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -149,44 +149,6 @@ class SX1262: public SX126x { private: #endif - // this is a lookup table for optimized PA configuration - // it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628 - // see also https://github.com/radiolib-org/power-tests - const SX126x::paTableEntry_t paOptTable[32] = { - { .paDutyCycle = 2, .hpMax = 2, .paVal = -5 }, - { .paDutyCycle = 2, .hpMax = 1, .paVal = 0 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 3 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 0 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 6 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 2 }, - { .paDutyCycle = 4, .hpMax = 1, .paVal = 6 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 11 }, - { .paDutyCycle = 2, .hpMax = 1, .paVal = 11 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 14 }, - { .paDutyCycle = 2, .hpMax = 1, .paVal = 14 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 20 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 22 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 11 }, - { .paDutyCycle = 3, .hpMax = 1, .paVal = 21 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 17 }, - { .paDutyCycle = 4, .hpMax = 2, .paVal = 13 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 20 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 22 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 }, - { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 }, - { .paDutyCycle = 1, .hpMax = 4, .paVal = 19 }, - { .paDutyCycle = 1, .hpMax = 4, .paVal = 20 }, - { .paDutyCycle = 3, .hpMax = 3, .paVal = 20 }, - { .paDutyCycle = 2, .hpMax = 5, .paVal = 19 }, - { .paDutyCycle = 1, .hpMax = 6, .paVal = 22 }, - { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 }, - { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 }, - { .paDutyCycle = 3, .hpMax = 6, .paVal = 22 }, - { .paDutyCycle = 4, .hpMax = 6, .paVal = 22 }, - { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 }, - }; - }; #endif diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 5015dcd5b7..93cd6b37a6 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -3,6 +3,44 @@ #if !RADIOLIB_EXCLUDE_SX126X +// this is a lookup table for optimized PA configuration +// it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628 +// see also https://github.com/radiolib-org/power-tests +static const SX126x::paTableEntry_t paOptTable[32] = { + { .paDutyCycle = 2, .hpMax = 1, .paVal = -3 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = -2 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 0 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = -1 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 2 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 0 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 1 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 }, + { .paDutyCycle = 1, .hpMax = 3, .paVal = 3 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 5 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 9 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 8 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 7 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 13 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 11 }, + { .paDutyCycle = 1, .hpMax = 1, .paVal = 19 }, + { .paDutyCycle = 2, .hpMax = 1, .paVal = 19 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 17 }, + { .paDutyCycle = 1, .hpMax = 6, .paVal = 12 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 16 }, + { .paDutyCycle = 4, .hpMax = 1, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 18 }, + { .paDutyCycle = 1, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 }, + { .paDutyCycle = 2, .hpMax = 3, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 6, .paVal = 20 }, + { .paDutyCycle = 1, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 }, + { .paDutyCycle = 3, .hpMax = 7, .paVal = 22 }, + { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 }, +}; + SX1268::SX1268(Module* mod) : SX126x(mod) { chipType = RADIOLIB_SX1268_CHIP_TYPE; } @@ -113,9 +151,9 @@ int16_t SX1268::setOutputPower(int8_t power, bool optimize) { RADIOLIB_ASSERT(state); // set PA config - int8_t paVal = optimize ? this->paOptTable[power + 9].paVal : power; - uint8_t paDutyCycle = optimize ? this->paOptTable[power + 9].paDutyCycle : 0x04; - uint8_t hpMax = optimize ? this->paOptTable[power + 9].hpMax : 0x07; + int8_t paVal = optimize ? paOptTable[power + 9].paVal : power; + uint8_t paDutyCycle = optimize ? paOptTable[power + 9].paDutyCycle : 0x04; + uint8_t hpMax = optimize ? paOptTable[power + 9].hpMax : 0x07; return(SX126x::setOutputPower(paVal, paDutyCycle, hpMax, RADIOLIB_SX126X_PA_CONFIG_SX1268)); } diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index c6eae7442d..d97da55b07 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -147,44 +147,6 @@ class SX1268: public SX126x { private: #endif - // this is a lookup table for optimized PA configuration - // it was determined by testing in https://github.com/jgromes/RadioLib/issues/1628 - // see also https://github.com/radiolib-org/power-tests - const SX126x::paTableEntry_t paOptTable[32] = { - { .paDutyCycle = 2, .hpMax = 1, .paVal = -3 }, - { .paDutyCycle = 2, .hpMax = 1, .paVal = -2 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 0 }, - { .paDutyCycle = 4, .hpMax = 1, .paVal = -1 }, - { .paDutyCycle = 2, .hpMax = 1, .paVal = 2 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 0 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 1 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 3 }, - { .paDutyCycle = 1, .hpMax = 3, .paVal = 3 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 5 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 9 }, - { .paDutyCycle = 4, .hpMax = 1, .paVal = 8 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 7 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 13 }, - { .paDutyCycle = 4, .hpMax = 1, .paVal = 11 }, - { .paDutyCycle = 1, .hpMax = 1, .paVal = 19 }, - { .paDutyCycle = 2, .hpMax = 1, .paVal = 19 }, - { .paDutyCycle = 4, .hpMax = 1, .paVal = 17 }, - { .paDutyCycle = 1, .hpMax = 6, .paVal = 12 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 16 }, - { .paDutyCycle = 4, .hpMax = 1, .paVal = 22 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 18 }, - { .paDutyCycle = 1, .hpMax = 2, .paVal = 21 }, - { .paDutyCycle = 2, .hpMax = 2, .paVal = 21 }, - { .paDutyCycle = 3, .hpMax = 2, .paVal = 21 }, - { .paDutyCycle = 2, .hpMax = 3, .paVal = 20 }, - { .paDutyCycle = 1, .hpMax = 6, .paVal = 20 }, - { .paDutyCycle = 1, .hpMax = 5, .paVal = 22 }, - { .paDutyCycle = 2, .hpMax = 5, .paVal = 22 }, - { .paDutyCycle = 3, .hpMax = 5, .paVal = 22 }, - { .paDutyCycle = 3, .hpMax = 7, .paVal = 22 }, - { .paDutyCycle = 4, .hpMax = 7, .paVal = 22 }, - }; - }; #endif From bcf8b212899e6346a27c50c4f9474a7a0f609733 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:05:19 +0000 Subject: [PATCH 1696/1848] [HAL] Add missing pullup flags to RPi Hal --- src/hal/RPi/PiHal.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hal/RPi/PiHal.h b/src/hal/RPi/PiHal.h index 914a1699a5..74e80939dd 100644 --- a/src/hal/RPi/PiHal.h +++ b/src/hal/RPi/PiHal.h @@ -63,13 +63,12 @@ class PiHal : public RadioLibHal { } int result; - int flags = 0; switch(mode) { case PI_INPUT: - result = lgGpioClaimInput(_gpioHandle, 0, pin); + result = lgGpioClaimInput(_gpioHandle, LG_SET_PULL_UP, pin); break; case PI_OUTPUT: - result = lgGpioClaimOutput(_gpioHandle, flags, pin, LG_HIGH); + result = lgGpioClaimOutput(_gpioHandle, 0, pin, LG_HIGH); break; default: fprintf(stderr, "Unknown pinMode mode %" PRIu32 "\n", mode); From 3b3ecd1eb0c8e3ab891f0c20740b37d6264423af Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:08:02 +0000 Subject: [PATCH 1697/1848] [LR2021] Fix SPI status width and version check --- src/modules/LR2021/LR2021.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 7f1305a978..4954605bad 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -18,16 +18,17 @@ LR2021::LR2021(Module* mod) : LRxxxx(mod) { this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE; this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED; this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; } int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; // try to find the chip - this will also reset the module at least once if(!this->findChip()) { @@ -467,7 +468,7 @@ bool LR2021::findChip(void) { int16_t state = getVersion(&fwMajor, &fwMinor); RADIOLIB_ASSERT(state); - if((fwMajor == expMajor) && (fwMajor == expMinor)) { + if((fwMajor == expMajor) && (fwMinor == expMinor)) { RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR2021"); RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)fwMajor, (int)fwMinor); flagFound = true; From 822cf2ac2f33717644ec9990a4c5b0e1649def69 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:14:34 +0000 Subject: [PATCH 1698/1848] [LR11x0] Fix PA config --- src/modules/LR11x0/LR1110.cpp | 3 ++- src/modules/LR11x0/LR1120.cpp | 3 ++- src/modules/LR11x0/LR11x0.cpp | 4 ++-- src/modules/LR11x0/LR11x0.h | 5 ++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/modules/LR11x0/LR1110.cpp b/src/modules/LR11x0/LR1110.cpp index 87b707b30b..20bf56c52f 100644 --- a/src/modules/LR11x0/LR1110.cpp +++ b/src/modules/LR11x0/LR1110.cpp @@ -82,7 +82,8 @@ int16_t LR1110::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampT // TODO how and when to configure OCP? // update PA config and set output power - always use VBAT for high-power PA - state = LR11x0::setOutputPower(power, (uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07, rampTimeUs); + // the value returned by LRxxxx class is offset by 3 for LR11x0 + state = LR11x0::setOutputPower(power, (uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07, roundRampTime(rampTimeUs) - 0x03); return(state); } diff --git a/src/modules/LR11x0/LR1120.cpp b/src/modules/LR11x0/LR1120.cpp index f0c6ebd9fc..aa68528362 100644 --- a/src/modules/LR11x0/LR1120.cpp +++ b/src/modules/LR11x0/LR1120.cpp @@ -98,7 +98,8 @@ int16_t LR1120::setOutputPower(int8_t power, bool forceHighPower, uint32_t rampT // TODO how and when to configure OCP? // update PA config and set output power - always use VBAT for high-power PA - state = LR11x0::setOutputPower(power, paSel, paSupply, 0x04, 0x07, rampTimeUs); + // the value returned by LRxxxx class is offset by 3 for LR11x0 + state = LR11x0::setOutputPower(power, paSel, paSupply, 0x04, 0x07, roundRampTime(rampTimeUs) - 0x03); return(state); } diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 8095a26b2f..6337d73303 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1345,13 +1345,13 @@ int16_t LR11x0::setRxBoostedGainMode(bool en) { return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff))); } -int16_t LR11x0::setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint32_t rampTimeUs) { +int16_t LR11x0::setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint8_t rampTime) { // set PA config int16_t state = setPaConfig(paSel, regPaSupply, paDutyCycle, paHpSel); RADIOLIB_ASSERT(state); // set output power - state = setTxParams(power, roundRampTime(rampTimeUs)); + state = setTxParams(power, rampTime); return(state); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 69feceec92..e58d19f4f3 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -558,11 +558,10 @@ class LR11x0: public LRxxxx { Must be set to RADIOLIB_LR11X0_PA_SUPPLY_VBAT when output power is more than 14 dBm. \param paDutyCycle PA duty cycle. \param paHpSel High-power PA size control. - \param rampTimeUs PA power ramping time in microseconds. Provided value is rounded up to the - nearest discrete ramp time supported by the PA. Defaults to 48 us. + \param rampTime PA power ramping time raw value, one of RADIOLIB_LRXXXX_PA_RAMP_* macros. \returns \ref status_codes */ - int16_t setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint32_t rampTimeUs = 48); + int16_t setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint8_t rampTime); /*! \copydoc Module::setRfSwitchTable */ void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); From b1a7ae2f88995a1262be046a42f57843ecccc099 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:20:23 +0000 Subject: [PATCH 1699/1848] [LR2021] Fix SPI status width --- src/modules/LR2021/LR2021.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 4954605bad..13240cea34 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -22,7 +22,7 @@ LR2021::LR2021(Module* mod) : LRxxxx(mod) { this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; } int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { From 062e6b05d5d0f4f7bdcd9d81ace7584d1bb84f66 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:43:44 +0000 Subject: [PATCH 1700/1848] [LR2021] Fix SPI width swapping in base class --- src/modules/LR11x0/LR11x0.cpp | 1 + src/modules/LR11x0/LR_common.cpp | 7 ++++--- src/modules/LR2021/LR2021.cpp | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6337d73303..de9b8d093a 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1710,6 +1710,7 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; this->gnss = false; // try to find the LR11x0 chip - this will also reset the module at least once diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 4012571dfc..da80518af7 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -8,7 +8,6 @@ LRxxxx::LRxxxx(Module* mod) : PhysicalLayer() { this->mod->spiConfig.stream = true; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; this->mod->spiConfig.statusPos = 0; this->mod->spiConfig.parseStatusCb = SPIparseStatus; this->mod->spiConfig.checkStatusCb = SPIcheckStatus; @@ -41,9 +40,10 @@ void LRxxxx::clearPacketSentAction() { uint32_t LRxxxx::getIrqStatus() { // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes uint8_t buff[6] = { 0 }; + Module::BitWidth_t statusWidth = mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS]; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = statusWidth; uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5]; return(irq); } @@ -197,9 +197,10 @@ int16_t LRxxxx::SPIcheckStatus(Module* mod) { // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used // it also seems to ignore the actual command, and just sending in bunch of NOPs will work uint8_t buff[6] = { 0 }; + Module::BitWidth_t statusWidth = mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS]; mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true); - mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; + mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = statusWidth; RADIOLIB_ASSERT(state); return(LRxxxx::SPIparseStatus(buff[0])); } diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 13240cea34..1dedece73a 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -18,17 +18,17 @@ LR2021::LR2021(Module* mod) : LRxxxx(mod) { this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE; this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED; this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; } int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { this->mod->init(); this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; // try to find the chip - this will also reset the module at least once if(!this->findChip()) { From b958a8164195dc63ef4ff8d1250d9be2c645b0b1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:44:05 +0000 Subject: [PATCH 1701/1848] [LR2021] Fix wrong SPI read --- src/modules/LR2021/LR2021_cmds_radio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index 7039e65371..00c0984a94 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -114,7 +114,7 @@ int16_t LR2021::setPacketType(uint8_t packetType) { } int16_t LR2021::getPacketType(uint8_t* packetType) { - return(this->SPIcommand(RADIOLIB_LR2021_CMD_GET_PACKET_TYPE, true, packetType, sizeof(uint8_t))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_GET_PACKET_TYPE, false, packetType, sizeof(uint8_t))); } #endif From 31a5ad365ec5a761d14aff46a7569ccafc2d4784 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 17:44:21 +0000 Subject: [PATCH 1702/1848] [LR2021] Fix DIO5 can only be pull up --- src/modules/LR2021/LR2021.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 1dedece73a..a29657a6b6 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -498,7 +498,9 @@ int16_t LR2021::config(uint8_t modem) { } // set the DIO to IRQ - state = this->setDioFunction(this->irqDioNum, RADIOLIB_LR2021_DIO_FUNCTION_IRQ, RADIOLIB_LR2021_DIO_SLEEP_PULL_NONE); + // DIO5 can only be pull up + uint8_t pull = this->irqDioNum == 5 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_NONE; + state = this->setDioFunction(this->irqDioNum, RADIOLIB_LR2021_DIO_FUNCTION_IRQ, pull); RADIOLIB_ASSERT(state); // calibrate all blocks From 9d2daad5581341c5ac5417ba62f48889bfbb01ed Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 19:57:02 +0000 Subject: [PATCH 1703/1848] [HAL] Make pull/up down configurable through HAL --- src/Hal.cpp | 7 +++++++ src/Hal.h | 8 ++++++++ src/hal/RPi/PiHal.h | 13 ++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Hal.cpp b/src/Hal.cpp index 90c86f4fda..9fdf1089bc 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -40,6 +40,13 @@ uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); } +void RadioLibHal::pullUpDown(uint32_t pin, bool enable, bool up) { + // the default implementation does nothing + (void)pin; + (void)enable; + (void)up; +} + RadioLibTime_t rlb_time_us() { return(rlb_timestamp_hal == nullptr ? 0 : rlb_timestamp_hal->micros()); } diff --git a/src/Hal.h b/src/Hal.h index 9768474bc3..bda07c756d 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -215,6 +215,14 @@ class RadioLibHal { \returns The interrupt number of a given pin. */ virtual uint32_t pinToInterrupt(uint32_t pin); + + /*! + \brief Enable or disable pull up or pull down for a specific pin. + \param pin Pin to change. + \param enable True to enable, false to disable. + \param up Pull direction, true for pull up, false for pull down. + */ + virtual void pullUpDown(uint32_t pin, bool enable, bool up); }; #endif diff --git a/src/hal/RPi/PiHal.h b/src/hal/RPi/PiHal.h index 74e80939dd..2bd0bec6e6 100644 --- a/src/hal/RPi/PiHal.h +++ b/src/hal/RPi/PiHal.h @@ -65,7 +65,7 @@ class PiHal : public RadioLibHal { int result; switch(mode) { case PI_INPUT: - result = lgGpioClaimInput(_gpioHandle, LG_SET_PULL_UP, pin); + result = lgGpioClaimInput(_gpioHandle, 0, pin); break; case PI_OUTPUT: result = lgGpioClaimOutput(_gpioHandle, 0, pin, LG_HIGH); @@ -225,6 +225,17 @@ class PiHal : public RadioLibHal { lgTxPwm(_gpioHandle, pin, 0, 0, 0, 0); } + void pullUpDown(uint32_t pin, bool enable, bool up) { + if(pin == RADIOLIB_NC) { + return; + } + + int flags = enable ? (up ? LG_SET_PULL_UP : LG_SET_PULL_DOWN) : LG_SET_PULL_NONE; + int result = lgGpioClaimInput(_gpioHandle, flags, pin); + fprintf(stderr, "Could not claim pin %" PRIu32 " with flags %" PRIu32 ": %s\n", + pin, flags, lguErrorText(result)); + } + // interrupt emulation bool interruptEnabled[PI_MAX_USER_GPIO + 1]; uint32_t interruptModes[PI_MAX_USER_GPIO + 1]; From f391ce7ce0e1d3b5903ec7f32e9f7b7771329c34 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 20:04:19 +0000 Subject: [PATCH 1704/1848] [HAL] Save pull up/down flags internally on RPi --- src/hal/RPi/PiHal.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/hal/RPi/PiHal.h b/src/hal/RPi/PiHal.h index 2bd0bec6e6..f2947904c7 100644 --- a/src/hal/RPi/PiHal.h +++ b/src/hal/RPi/PiHal.h @@ -65,10 +65,10 @@ class PiHal : public RadioLibHal { int result; switch(mode) { case PI_INPUT: - result = lgGpioClaimInput(_gpioHandle, 0, pin); + result = lgGpioClaimInput(_gpioHandle, pinFlags[pin], pin); break; case PI_OUTPUT: - result = lgGpioClaimOutput(_gpioHandle, 0, pin, LG_HIGH); + result = lgGpioClaimOutput(_gpioHandle, pinFlags[pin], pin, LG_HIGH); break; default: fprintf(stderr, "Unknown pinMode mode %" PRIu32 "\n", mode); @@ -226,14 +226,11 @@ class PiHal : public RadioLibHal { } void pullUpDown(uint32_t pin, bool enable, bool up) { - if(pin == RADIOLIB_NC) { + if((pin == RADIOLIB_NC) || (pin > PI_MAX_USER_GPIO)) { return; } - int flags = enable ? (up ? LG_SET_PULL_UP : LG_SET_PULL_DOWN) : LG_SET_PULL_NONE; - int result = lgGpioClaimInput(_gpioHandle, flags, pin); - fprintf(stderr, "Could not claim pin %" PRIu32 " with flags %" PRIu32 ": %s\n", - pin, flags, lguErrorText(result)); + pinFlags[pin] = enable ? (up ? LG_SET_PULL_UP : LG_SET_PULL_DOWN) : LG_SET_PULL_NONE; } // interrupt emulation @@ -250,6 +247,8 @@ class PiHal : public RadioLibHal { const uint8_t _spiChannel; int _gpioHandle = -1; int _spiHandle = -1; + + int pinFlags[PI_MAX_USER_GPIO + 1] = { 0 }; }; // this handler emulates interrupts From 090fe1dd3ace839c064e753020e1da5526d10eae Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 13 Jan 2026 20:08:46 +0000 Subject: [PATCH 1705/1848] [LR2021] Implement Rx/Tx mode staging --- src/modules/LR11x0/LR11x0.h | 5 - src/modules/LR11x0/LR_common.h | 5 + src/modules/LR2021/LR2021.cpp | 122 ++++++++++++++++++ src/modules/LR2021/LR2021.h | 8 +- .../LR2021/LR2021_cmds_chip_control.cpp | 4 +- src/modules/LR2021/LR2021_commands.h | 3 + 6 files changed, 139 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index e58d19f4f3..df136d1b48 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -941,13 +941,8 @@ class LR11x0: public LRxxxx { uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0; uint16_t preambleLengthGFSK = 0; - // cached LR-FHSS parameters - uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0; - uint16_t lrFhssHopSeq = 0; - uint8_t wifiScanMode = 0; bool gnss = false; - uint32_t rxTimeout = 0; int16_t modSetup(float tcxoVoltage, uint8_t modem); bool findChip(uint8_t ver); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 17a1bf3063..44fca2df1c 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -134,6 +134,7 @@ class LRxxxx: public PhysicalLayer { float freqMHz = 0; float dataRateMeasured = 0; + uint32_t rxTimeout = 0; // cached LoRa parameters uint8_t bandwidth = 0, spreadingFactor = 0, codingRate = 0, ldrOptimize = 0, crcTypeLoRa = 0, headerType = 0; @@ -143,6 +144,10 @@ class LRxxxx: public PhysicalLayer { size_t implicitLen = 0; bool invertIQEnabled = false; + // cached LR-FHSS parameters + uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0; + uint16_t lrFhssHopSeq = 0; + // a lot of SPI commands have the same structure and arguments on both LR11xx as well as LR2021 // the only difference is the 16-bit command code - however, having everything in this base class // will actually increase the binary size, because of the extra method calls that are needed diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index a29657a6b6..3417fb22ec 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -576,4 +576,126 @@ int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uin return(setCad()); } +int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { + int16_t state; + + switch(mode) { + case(RADIOLIB_RADIO_MODE_RX): { + // check active modem + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && + (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set DIO mapping + if(cfg->receive.timeout != RADIOLIB_LR2021_RX_TIMEOUT_INF) { + cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT); + } + state = setDioIrqConfig(this->irqDioNum, getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask)); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + RADIOLIB_ASSERT(state); + + // set implicit mode and expected len if applicable + if((this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR2021_PACKET_TYPE_LORA)) { + state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + } + + // if max(uint32_t) is used, revert to RxContinuous + if(cfg->receive.timeout == 0xFFFFFFFF) { + cfg->receive.timeout = 0xFFFFFF; + } + this->rxTimeout = cfg->receive.timeout; + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + // check packet length + if(cfg->transmit.len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // maximum packet length is decreased by 1 when address filtering is active + //! \todo [LR2021] implement GFSK address filtering + + // set packet Length + state = RADIOLIB_ERR_NONE; + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) { + state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled); + + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + //! \todo [LR2021] implement GFSK + //state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); + + } else if(modem != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) { + return(RADIOLIB_ERR_UNKNOWN); + + } + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqConfig(this->irqDioNum, RADIOLIB_LR2021_IRQ_TX_DONE | RADIOLIB_LR2021_IRQ_TIMEOUT); + RADIOLIB_ASSERT(state); + + if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) { + // in LR-FHSS mode, the packet is built by the device + //! \todo [LR2021] add configurable LR-FHSS device offset + state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len); + RADIOLIB_ASSERT(state); + + } else { + // write packet to buffer + state = writeRadioTxFifo(cfg->transmit.data, cfg->transmit.len); + RADIOLIB_ASSERT(state); + + } + + // clear interrupt flags + state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + RADIOLIB_ASSERT(state); + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = mode; + return(state); +} + +int16_t LR2021::launchMode() { + int16_t state; + switch(this->stagedMode) { + case(RADIOLIB_RADIO_MODE_RX): { + this->mod->setRfSwitchState(Module::MODE_RX); + state = setRx(this->rxTimeout); + } break; + + case(RADIOLIB_RADIO_MODE_TX): { + this->mod->setRfSwitchState(Module::MODE_TX); + state = setTx(RADIOLIB_LR2021_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(this->mod->hal->digitalRead(this->mod->getGpio())) { + this->mod->hal->yield(); + } + } break; + + default: + return(RADIOLIB_ERR_UNSUPPORTED); + } + + this->stagedMode = RADIOLIB_RADIO_MODE_NONE; + return(state); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 12f510bc70..65ed344db3 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -319,6 +319,12 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t invertIQ(bool enable) override; + + /*! \copydoc PhysicalLayer::stageMode */ + int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; + + /*! \copydoc PhysicalLayer::launchMode */ + int16_t launchMode() override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: @@ -342,7 +348,7 @@ class LR2021: public LRxxxx { // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); - int16_t writeRadioTxFifo(uint8_t* data, size_t len); + int16_t writeRadioTxFifo(const uint8_t* data, size_t len); int16_t writeRegMem32(uint32_t addr, const uint32_t* data, size_t len); int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data); int16_t readRegMem32(uint32_t addr, uint32_t* data, size_t len); diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index 1bd6161ec4..1f61fde273 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -11,8 +11,8 @@ int16_t LR2021::readRadioRxFifo(uint8_t* data, size_t len) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_READ_RX_FIFO, false, data, len, NULL, 0)); } -int16_t LR2021::writeRadioTxFifo(uint8_t* data, size_t len) { - return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_TX_FIFO, true, data, len, NULL, 0)); +int16_t LR2021::writeRadioTxFifo(const uint8_t* data, size_t len) { + return(this->SPIcommand(RADIOLIB_LR2021_CMD_WRITE_TX_FIFO, true, const_cast(data), len, NULL, 0)); } int16_t LR2021::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index c3974630f7..8fb8f87c85 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -193,6 +193,9 @@ #define RADIOLIB_LR2021_RX_TIMEOUT_NONE (0x000000UL) // 23 0 Rx timeout duration: no timeout (Rx single mode) #define RADIOLIB_LR2021_RX_TIMEOUT_INF (0xFFFFFFUL) // 23 0 infinite (Rx continuous mode) +// RADIOLIB_LR2021_CMD_SET_TX +#define RADIOLIB_LR2021_TX_TIMEOUT_NONE (0x000000UL) // 23 0 disable Tx timeout + // RADIOLIB_LR2021_CMD_SET_RX_TX_FALLBACK_MODE #define RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC (0x01UL << 0) // 1 0 fallback mode after Rx/Tx: standby with RC #define RADIOLIB_LR2021_FALLBACK_MODE_STBY_XOSC (0x02UL << 0) // 1 0 standby with XOSC From dbb2466ab120a484c05f8aa96828468635737e21 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Jan 2026 18:57:22 +0000 Subject: [PATCH 1706/1848] [LR2021] Fix copypaste errors in commands --- src/modules/LR2021/LR2021_cmds_chip_control.cpp | 4 ++-- src/modules/LR2021/LR2021_cmds_gfsk.cpp | 2 +- src/modules/LR2021/LR2021_cmds_lora.cpp | 2 +- src/modules/LR2021/LR2021_cmds_ook.cpp | 8 ++++---- src/modules/LR2021/LR2021_cmds_oqpsk.cpp | 2 +- src/modules/LR2021/LR2021_config.cpp | 1 - 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index 1f61fde273..c6e912d923 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -292,12 +292,12 @@ int16_t LR2021::setTcxoMode(uint8_t tune, uint32_t startTime) { (uint8_t)((startTime >> 24) & 0xFF), (uint8_t)((startTime >> 16) & 0xFF), (uint8_t)((startTime >> 8) & 0xFF), (uint8_t)(startTime & 0xFF), }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TCXO_MODE, true, buff, sizeof(buff))); } int16_t LR2021::setXoscCpTrim(uint8_t xta, uint8_t xtb, uint8_t startTime) { uint8_t buff[] = { (uint8_t)(xta & 0x3F), (uint8_t)(xtb & 0x3F), startTime }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_CONFIG_CLK_OUTPUTS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_XOSC_CP_TRIM, true, buff, sizeof(buff))); } #endif diff --git a/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/src/modules/LR2021/LR2021_cmds_gfsk.cpp index 999137f738..befa5010bd 100644 --- a/src/modules/LR2021/LR2021_cmds_gfsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_gfsk.cpp @@ -74,7 +74,7 @@ int16_t LR2021::getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uin int16_t LR2021::getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_PACKET_STATUS, false, buff, sizeof(buff)); uint16_t raw = 0; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { diff --git a/src/modules/LR2021/LR2021_cmds_lora.cpp b/src/modules/LR2021/LR2021_cmds_lora.cpp index 8ad55c95ff..30c3b25dc8 100644 --- a/src/modules/LR2021/LR2021_cmds_lora.cpp +++ b/src/modules/LR2021/LR2021_cmds_lora.cpp @@ -124,7 +124,7 @@ int16_t LR2021::setLoRaSideDetCad(uint8_t* pnrDelta, uint8_t* detPeak, size_t nu buff[2*i] = pnrDelta[i] & 0x0F; buff[2*i + 1] = detPeak[i] & 0x7F; } - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC, true, buff, 2*numSideDets)); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_SIDE_DET_CAD, true, buff, 2*numSideDets)); } #endif diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index d925968d27..398c38c02f 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -42,7 +42,7 @@ int16_t LR2021::setOokSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFi buff[3 - i] = syncWord[i]; } buff[4] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD, true, buff, sizeof(buff))); } int16_t LR2021::setOokAddress(uint8_t addrNode, uint8_t addrBroadcast) { @@ -52,7 +52,7 @@ int16_t LR2021::setOokAddress(uint8_t addrNode, uint8_t addrBroadcast) { int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError) { uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OOK_RX_STATS, false, buff, sizeof(buff)); if(packetRx) { *packetRx = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(crcError) { *crcError = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3]; } if(lenError) { *lenError = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5]; } @@ -61,7 +61,7 @@ int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS, false, buff, sizeof(buff)); uint16_t raw = 0; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { @@ -86,7 +86,7 @@ int16_t LR2021::setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uin (uint8_t)(patternLen & 0x0F), (uint8_t)(patternNumRepeaters & 0x1F), (uint8_t)(((uint8_t)syncWordRaw << 5) | ((uint8_t)sofDelimiterRising << 4) | (sofDelimiterLen & 0x0F)), }; - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS, true, buff, sizeof(buff))); + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR, true, buff, sizeof(buff))); } #endif diff --git a/src/modules/LR2021/LR2021_cmds_oqpsk.cpp b/src/modules/LR2021/LR2021_cmds_oqpsk.cpp index 2d7445e407..65044cf1b1 100644 --- a/src/modules/LR2021/LR2021_cmds_oqpsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_oqpsk.cpp @@ -27,7 +27,7 @@ int16_t LR2021::getOqpskRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t int16_t LR2021::getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, float* rssiAvg, float* rssiSync, float* lqi) { uint8_t buff[7] = { 0 }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_RX_STATS, false, buff, sizeof(buff)); + int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS, false, buff, sizeof(buff)); if(rxHeader) { *rxHeader = buff[0]; } if(payloadLen) { *payloadLen = ((uint16_t)(buff[1]) << 8) | (uint16_t)buff[2]; } uint16_t raw = 0; diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index c33c89972c..0b97109250 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -232,7 +232,6 @@ int16_t LR2021::setTCXO(float voltage, uint32_t delay) { standby(); // check oscillator startup error flag and clear it - //! \TODO: [LR2021] legacy from LR11x0, chech if this really works on LR2021 uint16_t errors = 0; int16_t state = getErrors(&errors); RADIOLIB_ASSERT(state); From 2675673d4a04d3912909c43db8f642f14d7eb521 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Jan 2026 20:13:25 +0000 Subject: [PATCH 1707/1848] [LR2021] Fix checking of status code during calibration --- src/modules/LR2021/LR2021.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 3417fb22ec..612733cba1 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -504,7 +504,7 @@ int16_t LR2021::config(uint8_t modem) { RADIOLIB_ASSERT(state); // calibrate all blocks - (void)this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL); + state = this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL); // wait for calibration completion this->mod->hal->delay(5); @@ -513,15 +513,14 @@ int16_t LR2021::config(uint8_t modem) { } // if something failed, show the device errors - //! \TODO: [LR2021] legacy from LR11x0, check if this really works on LR2021 #if RADIOLIB_DEBUG_BASIC if(state != RADIOLIB_ERR_NONE) { - // unless mode is forced to standby, device errors will be 0 - standby(); uint16_t errors = 0; getErrors(&errors); RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); } + #else + RADIOLIB_ASSERT(state); #endif // set modem From 7a89e4610bafe635a0162e3b0bde37a9175df6f9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Jan 2026 20:13:44 +0000 Subject: [PATCH 1708/1848] [LR2021] Set default TCXO startup timeout to 1 second --- src/modules/LR2021/LR2021.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 65ed344db3..71c5a3790d 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -298,10 +298,11 @@ class LR2021: public LRxxxx { \param voltage TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. Set to 0 to disable TCXO. NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO). - \param delay TCXO timeout in us. Defaults to 5000 us. + \param delay TCXO timeout in us. Defaults to 1000000 (1 second), because especially on the first startup, + this delay may be measured very inaccurately. \returns \ref status_codes */ - int16_t setTCXO(float voltage, uint32_t delay = 5000); + int16_t setTCXO(float voltage, uint32_t delay = 1000000); /*! \brief Sets CRC configuration. From 0df34583c74dc857f4841aecf4081a5c2402ce6b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 14 Jan 2026 20:14:23 +0000 Subject: [PATCH 1709/1848] [LR11x0] Fix checking of status code during calibration --- src/modules/LR11x0/LR11x0.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index de9b8d093a..2a813ad7f4 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1783,7 +1783,7 @@ int16_t LR11x0::config(uint8_t modem) { RADIOLIB_ASSERT(state); // calibrate all blocks - (void)this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL); + state = this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL); // wait for calibration completion this->mod->hal->delay(5); @@ -1800,6 +1800,8 @@ int16_t LR11x0::config(uint8_t modem) { getErrors(&errors); RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors); } + #else + RADIOLIB_ASSERT(state); #endif // set modem From daf6d408c0d1e8308d0162406bc6636e1985e2f0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 07:47:38 +0000 Subject: [PATCH 1710/1848] [LR2021] Add device rrors check during freq calibration --- src/modules/LR2021/LR2021_commands.h | 2 ++ src/modules/LR2021/LR2021_config.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 8fb8f87c85..d5cecc4e7e 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -274,6 +274,8 @@ #define RADIOLIB_LR2021_PA_OFFSET_CALIB_ERR (0x01UL << 11) // 15 0 PA offset calibration failed #define RADIOLIB_LR2021_PPF_CALIB_ERR (0x01UL << 12) // 15 0 poly-phase filter calibration failed #define RADIOLIB_LR2021_SRC_CALIB_ERR (0x01UL << 13) // 15 0 self-reception cancellation calibration failed +#define RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR (0x01UL << 14) // 15 0 RSSI saturation during SRC calibration +#define RADIOLIB_LR2021_SRC_TOLERANCE_CALIB_ERR (0x01UL << 15) // 15 0 self-reception cancellation values out of tolernce // RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION #define RADIOLIB_LR2021_DIO_FUNCTION_NONE (0x00UL << 4) // 7 4 DIO function: none diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 0b97109250..b543529917 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -26,6 +26,16 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 }; frequencies[0] |= (freq > 1000.0f) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; state = calibrateFrontEnd(frequencies); + // if something failed, show the device errors + #if RADIOLIB_DEBUG_BASIC + if(state != RADIOLIB_ERR_NONE) { + uint16_t errors = 0; + getErrors(&errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration failed, device errors: 0x%X", errors); + } + #else + RADIOLIB_ASSERT(state); + #endif RADIOLIB_ASSERT(state); } From af24e569bb44ed7e1d0e01893abd4f3ae65183fd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 08:12:23 +0000 Subject: [PATCH 1711/1848] [LR2021] Attempt multiple FE calibrations --- src/TypeDef.h | 6 ++++ src/modules/LR2021/LR2021_config.cpp | 50 ++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index e54559a891..efc05f3273 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -631,6 +631,12 @@ #define RADIOLIB_ERR_GNSS_SOLVER(X) (RADIOLIB_ERR_GNSS_SOLVER_OFFSET - (X)) #define RADIOLIB_GET_GNSS_SOLVER_ERROR(X) (-((X) - RADIOLIB_ERR_GNSS_SOLVER_OFFSET)) +// LR2021-specific status codes +/*! + \brief Front end calibration failed. Often this is caused by a neraby high-power transmitter. +*/ +#define RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED (-1300) + /*! \} */ diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index b543529917..de6fbb281f 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -6,6 +6,9 @@ #if !RADIOLIB_EXCLUDE_LR2021 +// maximum number of allowed frontend calibration attempts +#define RADIOLIB_LR2021_MAX_CAL_ATTEMPTS (10) + int16_t LR2021::setFrequency(float freq) { return(this->setFrequency(freq, false)); } @@ -22,21 +25,40 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { // check if we need to recalibrate image int16_t state; if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ)) { - // we do, get the nearest multiple of 4 MHz - uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 }; - frequencies[0] |= (freq > 1000.0f) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; - state = calibrateFrontEnd(frequencies); - // if something failed, show the device errors - #if RADIOLIB_DEBUG_BASIC - if(state != RADIOLIB_ERR_NONE) { - uint16_t errors = 0; - getErrors(&errors); - RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration failed, device errors: 0x%X", errors); + // calibration can fail if there is a strong interfering source + // run it several times until it passes + int i = 0; + for(; i < RADIOLIB_LR2021_MAX_CAL_ATTEMPTS; i++) { + // get the nearest multiple of 4 MHz + uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 }; + frequencies[0] |= (freq > 1000.0f) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; + state = calibrateFrontEnd(frequencies); + + // if something failed, check the device errors + if(state != RADIOLIB_ERR_NONE) { + uint16_t errors = 0; + getErrors(&errors); + RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration #%d failed, device errors: 0x%X", i, errors); + + // if this is casued by something else than RSSI saturation, repeating will not help + if((errors & RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR) == 0) { + return(state); + } + + // wait a little while before the next attempt + this->mod->hal->delay(5); + + } else { + // calibration passed + break; + } + } - #else - RADIOLIB_ASSERT(state); - #endif - RADIOLIB_ASSERT(state); + + if(i == RADIOLIB_LR2021_MAX_CAL_ATTEMPTS) { + return(RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED); + } + } // set frequency From 49c57ad6c9a820bd15a5b68fd1a05e55ebbec9cc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 08:12:34 +0000 Subject: [PATCH 1712/1848] [LR2021] Fix radio data readout --- src/modules/LR2021/LR2021_cmds_chip_control.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index c6e912d923..aff9f38603 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -8,7 +8,11 @@ #if !RADIOLIB_EXCLUDE_LR2021 int16_t LR2021::readRadioRxFifo(uint8_t* data, size_t len) { - return(this->SPIcommand(RADIOLIB_LR2021_CMD_READ_RX_FIFO, false, data, len, NULL, 0)); + // FIFO read is just a single transaction sent without the status code + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0; + int16_t state = this->mod->SPIreadStream(RADIOLIB_LR2021_CMD_READ_RX_FIFO, data, len, true, false); + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; + return(state); } int16_t LR2021::writeRadioTxFifo(const uint8_t* data, size_t len) { From fd6ede4ddecc39af119d2bf5954fa0265c46a690 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 11:59:57 +0000 Subject: [PATCH 1713/1848] [LR11x0] Move ToA methods to base class --- src/modules/LR11x0/LR11x0.cpp | 145 ++----------------------- src/modules/LR11x0/LR11x0.h | 22 ---- src/modules/LR11x0/LR11x0_commands.cpp | 2 +- src/modules/LR11x0/LR11x0_commands.h | 6 - src/modules/LR11x0/LR_common.cpp | 125 +++++++++++++++++++++ src/modules/LR11x0/LR_common.h | 30 +++++ 6 files changed, 164 insertions(+), 166 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 2a813ad7f4..7676586195 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -115,7 +115,7 @@ int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoV RADIOLIB_ASSERT(state); // set fixed configuration - return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0)); + return(setModulationParamsLrFhss(RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0)); } int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) { @@ -161,7 +161,7 @@ int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { } // Long Interleaver supports up to 253 bytes if CRC is enabled - if (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 2)) { + if (this->crcTypeLoRa == RADIOLIB_LRXXXX_LORA_CRC_ENABLED && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 2)) { return(RADIOLIB_ERR_PACKET_TOO_LONG); } } @@ -1059,7 +1059,7 @@ int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool RADIOLIB_ASSERT(state); if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) { // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion - this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED; + this->crcTypeLoRa = len > 0 ? RADIOLIB_LRXXXX_LORA_CRC_ENABLED : RADIOLIB_LRXXXX_LORA_CRC_DISABLED; state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { @@ -1086,6 +1086,7 @@ int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } + this->crcLenGFSK = len; state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); @@ -1154,7 +1155,7 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { // in implicit mode, return the cached value uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE; (void)getPacketType(&type); - if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT)) { + if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT)) { return(this->implicitLen); } @@ -1165,136 +1166,6 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { return((size_t)len); } -RadioLibTime_t LR11x0::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { - // check active modem - if (modem == ModemType_t::RADIOLIB_MODEM_LORA) { - uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ; - uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) - uint8_t sfCoeff2 = 8; - if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) { - sfCoeff1_x4 = 25; // 6.25 * 4 - sfCoeff2 = 0; - } - uint8_t sfDivisor = 4*dr.lora.spreadingFactor; - if(pc.lora.ldrOptimize) { - sfDivisor = 4*(dr.lora.spreadingFactor - 2); - } - const int8_t bitsPerCrc = 16; - const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20; - - // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) - int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header; - if(bitCount < 0) { - bitCount = 0; - } - // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) - uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); - - // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit - uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4; - - // get time-on-air in us - return((symbolLength_us * nSymbol_x4) / 4); - - } else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) { - return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f))); - - } else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) { - // calculate the number of bits based on coding rate - uint16_t N_bits; - switch(dr.lrFhss.cr) { - case RADIOLIB_LRXXXX_LR_FHSS_CR_5_6: - N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? - break; - case RADIOLIB_LRXXXX_LR_FHSS_CR_2_3: - N_bits = (len * 3) / 2; - break; - case RADIOLIB_LRXXXX_LR_FHSS_CR_1_2: - N_bits = len * 2; - break; - case RADIOLIB_LRXXXX_LR_FHSS_CR_1_3: - N_bits = len * 3; - break; - default: - return(RADIOLIB_ERR_INVALID_CODING_RATE); - } - - // calculate number of bits when accounting for unaligned last block - uint16_t N_payBits = (N_bits / RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS) * RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS; - uint16_t N_lastBlockBits = N_bits % RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS; - if(N_lastBlockBits) { - N_payBits += N_lastBlockBits + 2; - } - - // add header bits - uint16_t N_totalBits = (RADIOLIB_LRXXXX_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits; - return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE); - - } else { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - return(0); -} - -RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { - ModemType_t modem; - int32_t state = this->getModem(&modem); - RADIOLIB_ASSERT(state); - - DataRate_t dr = {}; - PacketConfig_t pc = {}; - switch(modem) { - case ModemType_t::RADIOLIB_MODEM_LORA: { - uint8_t cr = this->codingRate; - // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values - if (cr < 5) { - cr = cr + 4; - } else if (cr == 7) { - cr = cr + 1; - } - - dr.lora.spreadingFactor = this->spreadingFactor; - dr.lora.bandwidth = this->bandwidthKhz; - dr.lora.codingRate = cr; - - pc.lora.preambleLength = this->preambleLengthLoRa; - pc.lora.implicitHeader = (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) ? true : false; - pc.lora.crcEnabled = (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED) ? true : false; - pc.lora.ldrOptimize = (bool)this->ldrOptimize; - break; - } - case ModemType_t::RADIOLIB_MODEM_FSK: { - dr.fsk.bitRate = (float)this->bitRate / 1000.0f; - dr.fsk.freqDev = (float)this->frequencyDev; - - uint8_t crcLen = 0; - if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV) { - crcLen = 1; - } else if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV) { - crcLen = 2; - } - - pc.fsk.preambleLength = this->preambleLengthGFSK; - pc.fsk.syncWordLength = this->syncWordLength; - pc.fsk.crcLength = crcLen; - break; - } - case ModemType_t::RADIOLIB_MODEM_LRFHSS: { - dr.lrFhss.bw = this->lrFhssBw; - dr.lrFhss.cr = this->lrFhssCr; - dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC) ? true : false; - - pc.lrFhss.hdrCount = this->lrFhssHdrCount; - break; - } - default: - return(RADIOLIB_ERR_WRONG_MODEM); - } - - return(this->calculateTimeOnAir(modem, dr, pc, len)); -} - RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) { // the timeout value is given in units of 30.52 microseconds // the calling function should provide some extra width, as this number of units is truncated to integer @@ -1321,11 +1192,11 @@ uint8_t LR11x0::randomByte() { } int16_t LR11x0::implicitHeader(size_t len) { - return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT, len)); + return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT, len)); } int16_t LR11x0::explicitHeader() { - return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT)); + return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT)); } float LR11x0::getDataRate() const { @@ -1570,7 +1441,7 @@ int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { RADIOLIB_ASSERT(state); // set implicit mode and expected len if applicable - if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) { + if((this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) { state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled); RADIOLIB_ASSERT(state); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index df136d1b48..fad30bb030 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -456,23 +456,6 @@ class LR11x0: public LRxxxx { */ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); - /*! - \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. - \param modem Modem type. - \param dr Data rate. - \param pc Packet config. - \param len Payload length in bytes. - \returns Expected time-on-air in microseconds. - */ - RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; - - /*! - \brief Get expected time-on-air for a given size of payload - \param len Payload length in bytes. - \returns Expected time-on-air in microseconds. - */ - RadioLibTime_t getTimeOnAir(size_t len) override; - /*! \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) \param timeoutUs Timeout in microseconds to listen for @@ -936,11 +919,6 @@ class LR11x0: public LRxxxx { #if !RADIOLIB_GODMODE private: #endif - // cached GFSK parameters - uint32_t bitRate = 0, frequencyDev = 0; - uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0; - uint16_t preambleLengthGFSK = 0; - uint8_t wifiScanMode = 0; bool gnss = false; diff --git a/src/modules/LR11x0/LR11x0_commands.cpp b/src/modules/LR11x0/LR11x0_commands.cpp index 815f9d8265..c5dc5fb3e9 100644 --- a/src/modules/LR11x0/LR11x0_commands.cpp +++ b/src/modules/LR11x0/LR11x0_commands.cpp @@ -657,7 +657,7 @@ int16_t LR11x0::configBleBeacon(uint8_t chan, const uint8_t* payload, size_t len int16_t LR11x0::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) { // check if in explicit header mode - if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) { + if(this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) { return(RADIOLIB_ERR_WRONG_MODEM); } diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index 7b3d2923aa..93c24fd567 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -387,17 +387,11 @@ #define RADIOLIB_LR11X0_GFSK_RX_BW_312_0 (0x19UL << 0) // 7 0 312.0 kHz #define RADIOLIB_LR11X0_GFSK_RX_BW_373_6 (0x11UL << 0) // 7 0 373.6 kHz #define RADIOLIB_LR11X0_GFSK_RX_BW_467_0 (0x09UL << 0) // 7 0 467.0 kHz -#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps -#define RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw #define RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0 (0x0BUL << 0) // 7 0 shaping filter: Gaussian, BT = 1.0 #define RADIOLIB_LR11X0_SIGFOX_SHAPING_GAUSSIAN_BT_0_7 (0x16UL << 0) // 7 0 shaping filter: Gaussian, BT = 0.7 // RADIOLIB_LR11X0_CMD_SET_PACKET_PARAMS -#define RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit -#define RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit #define RADIOLIB_LR11X0_LORA_PAYLOAD_LEN_ANY (0x00UL << 0) // 7 0 accept any payload length -#define RADIOLIB_LR11X0_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled -#define RADIOLIB_LR11X0_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled #define RADIOLIB_LR11X0_LORA_IQ_STANDARD (0x00UL << 0) // 7 0 IQ setup: standard #define RADIOLIB_LR11X0_LORA_IQ_INVERTED (0x01UL << 0) // 7 0 inverted #define RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED (0x00UL << 0) // 7 0 preamble detector: disabled diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index da80518af7..6cb314ac8d 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -48,6 +48,131 @@ uint32_t LRxxxx::getIrqStatus() { return(irq); } +RadioLibTime_t LRxxxx::getTimeOnAir(size_t len) { + ModemType_t modem; + int32_t state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + + DataRate_t dr = {}; + PacketConfig_t pc = {}; + switch(modem) { + case ModemType_t::RADIOLIB_MODEM_LORA: { + uint8_t cr = this->codingRate; + // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values + if (cr < 5) { + cr = cr + 4; + } else if (cr == 7) { + cr = cr + 1; + } + + dr.lora.spreadingFactor = this->spreadingFactor; + dr.lora.bandwidth = this->bandwidthKhz; + dr.lora.codingRate = cr; + + pc.lora.preambleLength = this->preambleLengthLoRa; + pc.lora.implicitHeader = (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT); + pc.lora.crcEnabled = (this->crcTypeLoRa == RADIOLIB_LRXXXX_LORA_CRC_ENABLED); + pc.lora.ldrOptimize = (bool)this->ldrOptimize; + break; + } + + case ModemType_t::RADIOLIB_MODEM_FSK: { + dr.fsk.bitRate = (float)this->bitRate / 1000.0f; + dr.fsk.freqDev = (float)this->frequencyDev; + pc.fsk.preambleLength = this->preambleLengthGFSK; + pc.fsk.syncWordLength = this->syncWordLength; + pc.fsk.crcLength = this->crcLenGFSK; + break; + } + + case ModemType_t::RADIOLIB_MODEM_LRFHSS: { + dr.lrFhss.bw = this->lrFhssBw; + dr.lrFhss.cr = this->lrFhssCr; + dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC) ? true : false; + + pc.lrFhss.hdrCount = this->lrFhssHdrCount; + break; + } + + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(this->calculateTimeOnAir(modem, dr, pc, len)); +} + +RadioLibTime_t LRxxxx::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) { + // check active modem + if (modem == ModemType_t::RADIOLIB_MODEM_LORA) { + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ; + uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) + uint8_t sfCoeff2 = 8; + if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) { + sfCoeff1_x4 = 25; // 6.25 * 4 + sfCoeff2 = 0; + } + uint8_t sfDivisor = 4*dr.lora.spreadingFactor; + if(pc.lora.ldrOptimize) { + sfDivisor = 4*(dr.lora.spreadingFactor - 2); + } + const int8_t bitsPerCrc = 16; + const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20; + + // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) + int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header; + if(bitCount < 0) { + bitCount = 0; + } + // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) + uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + + // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit + uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4; + + // get time-on-air in us + return((symbolLength_us * nSymbol_x4) / 4); + + } else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) { + return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f))); + + } else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) { + // calculate the number of bits based on coding rate + uint16_t N_bits; + switch(dr.lrFhss.cr) { + case RADIOLIB_LRXXXX_LR_FHSS_CR_5_6: + N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4? + break; + case RADIOLIB_LRXXXX_LR_FHSS_CR_2_3: + N_bits = (len * 3) / 2; + break; + case RADIOLIB_LRXXXX_LR_FHSS_CR_1_2: + N_bits = len * 2; + break; + case RADIOLIB_LRXXXX_LR_FHSS_CR_1_3: + N_bits = len * 3; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + // calculate number of bits when accounting for unaligned last block + uint16_t N_payBits = (N_bits / RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS) * RADIOLIB_LRXXXX_LR_FHSS_BLOCK_BITS; + uint16_t N_lastBlockBits = N_bits % RADIOLIB_LRXXXX_LR_FHSS_FRAG_BITS; + if(N_lastBlockBits) { + N_payBits += N_lastBlockBits + 2; + } + + // add header bits + uint16_t N_totalBits = (RADIOLIB_LRXXXX_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits; + return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE); + + } else { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(0); +} + int16_t LRxxxx::reset() { // run the reset sequence this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 44fca2df1c..4793ebcc6d 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -75,6 +75,14 @@ #define RADIOLIB_LRXXXX_PA_RAMP_272U (0x11UL << 0) // 7 0 272 us #define RADIOLIB_LRXXXX_PA_RAMP_304U (0x12UL << 0) // 7 0 304 us +// common configuration values +#define RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps +#define RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw +#define RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT (0x00UL << 0) // 7 0 LoRa header mode: explicit +#define RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT (0x01UL << 0) // 7 0 implicit +#define RADIOLIB_LRXXXX_LORA_CRC_ENABLED (0x01UL << 0) // 7 0 CRC: enabled +#define RADIOLIB_LRXXXX_LORA_CRC_DISABLED (0x00UL << 0) // 7 0 disabled + class LRxxxx: public PhysicalLayer { public: LRxxxx(Module* mod); @@ -129,6 +137,23 @@ class LRxxxx: public PhysicalLayer { */ uint32_t getIrqStatus(); + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t getTimeOnAir(size_t len) override; + + /*! + \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. + \param modem Modem type. + \param dr Data rate. + \param pc Packet config. + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; + protected: Module* mod; @@ -144,6 +169,11 @@ class LRxxxx: public PhysicalLayer { size_t implicitLen = 0; bool invertIQEnabled = false; + // cached GFSK parameters + uint32_t bitRate = 0, frequencyDev = 0; + uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, crcLenGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0; + uint16_t preambleLengthGFSK = 0; + // cached LR-FHSS parameters uint8_t lrFhssCr = 0, lrFhssBw = 0, lrFhssHdrCount = 0, lrFhssGrid = 0; uint16_t lrFhssHopSeq = 0; From 12341b1631c48153b743072516002602a6a9db26 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 12:00:16 +0000 Subject: [PATCH 1714/1848] [LR2021] Add missing getModem implementation --- src/modules/LR2021/LR2021.cpp | 22 ++++++++++++++++++++++ src/modules/LR2021/LR2021.h | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 612733cba1..cfc155b14e 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -575,6 +575,28 @@ int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uin return(setCad()); } +int16_t LR2021::getModem(ModemType_t* modem) { + RADIOLIB_ASSERT_PTR(modem); + + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + + switch(type) { + case(RADIOLIB_LR2021_PACKET_TYPE_LORA): + *modem = ModemType_t::RADIOLIB_MODEM_LORA; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_LR2021_PACKET_TYPE_GFSK): + *modem = ModemType_t::RADIOLIB_MODEM_FSK; + return(RADIOLIB_ERR_NONE); + case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS): + *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { int16_t state; diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 71c5a3790d..20473ba64e 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -320,6 +320,13 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t invertIQ(bool enable) override; + + /*! + \brief Get modem currently in use by the radio. + \param modem Pointer to a variable to save the retrieved configuration into. + \returns \ref status_codes + */ + int16_t getModem(ModemType_t* modem); /*! \copydoc PhysicalLayer::stageMode */ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; From a811caedaced2ff95a9a5335660f4b0d3cd6f384 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:26:54 +0000 Subject: [PATCH 1715/1848] [CI] Fix macros in ToA unit test --- extras/test/unit/tests/TestCalculateTimeOnAir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp index 56d0d04df4..165dd20118 100644 --- a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp +++ b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp @@ -19,7 +19,7 @@ std::vector allConfigs = { { "SX126x", RADIOLIB_MODEM_LORA, {.lora={7,125,5}}, {.lora={8,false,true,true}}, {1,10,50,255}, {30976,46336,128256,548096} }, // 30.97, 46.33, 128.25, 548.09 { "SX126x", RADIOLIB_MODEM_LORA, {.lora={11,250,8}}, {.lora={16,true,false,false}}, {5,15,100,200}, {296960,362496,1411072,2590720} }, // 296.96, 362.49, 1410, 2590 { "SX126x", RADIOLIB_MODEM_FSK, {.fsk={100,10}}, {.fsk={16,16,2}}, {1,16,64,200}, {560,1760,5600,16480} }, - { "SX126x", RADIOLIB_MODEM_LRFHSS,{.lrFhss={RADIOLIB_LR11X0_LR_FHSS_BW_386_72,RADIOLIB_SX126X_LR_FHSS_CR_2_3,false}}, {.lrFhss={2}}, {1,20,100}, {3784697,4259832,6324212} }, + { "SX126x", RADIOLIB_MODEM_LRFHSS,{.lrFhss={RADIOLIB_SX126X_LR_FHSS_BW_386_72,RADIOLIB_SX126X_LR_FHSS_CR_2_3,false}}, {.lrFhss={2}}, {1,20,100}, {3784697,4259832,6324212} }, { "SX127x", RADIOLIB_MODEM_LORA, {.lora={6,125,6}}, {.lora={8,false,true,false}}, {7,23,98,156}, {23000,39000,115000,174000} }, // 20.61, 39.04, 115.84, 174.21 { "SX127x", RADIOLIB_MODEM_LORA, {.lora={8,250,8}}, {.lora={32,true,true,false}}, {10,20,80,160}, {70000,87000,210000,373000} }, // 69.89, 86.27, 209.15, 372.99 @@ -32,7 +32,7 @@ std::vector allConfigs = { { "LR11x0", RADIOLIB_MODEM_LORA, {.lora={10,250,5}}, {.lora={8,false,true,true}}, {1,20,100}, {103424,205824,615424} }, // 103.42, 205.82, 615.42 { "LR11x0", RADIOLIB_MODEM_LORA, {.lora={11,500,6}}, {.lora={32,true,false,false}}, {10,25,200}, {205824,279552,1065984} }, // 205.82, 279.55, 1070 { "LR11x0", RADIOLIB_MODEM_FSK, {.fsk={200,50}}, {.fsk={16,32,2}}, {1,32,64,200}, {360,1600,2880,8320} }, - { "LR11x0", RADIOLIB_MODEM_LRFHSS,{.lrFhss={RADIOLIB_LR11X0_LR_FHSS_BW_136_72,RADIOLIB_LR11X0_LR_FHSS_CR_1_3,true}}, {.lrFhss={1}}, {1,10,50}, {1949692,2392059,4456440} }, + { "LR11x0", RADIOLIB_MODEM_LRFHSS,{.lrFhss={RADIOLIB_LRXXXX_LR_FHSS_BW_136_72,RADIOLIB_LRXXXX_LR_FHSS_CR_1_3,true}}, {.lrFhss={1}}, {1,10,50}, {1949692,2392059,4456440} }, }; BOOST_AUTO_TEST_SUITE(suite_TimeOnAir) From 9a6e1236427eb373e0221dbdcce4bf388bc12bd2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:32:01 +0000 Subject: [PATCH 1716/1848] [LR2021] Fix IRQ bit width --- src/modules/LR2021/LR2021_cmds_chip_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index aff9f38603..cec0c75480 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -231,7 +231,7 @@ int16_t LR2021::clearIrq(uint32_t irq) { int16_t LR2021::getAndClearIrqStatus(uint32_t* irq) { uint8_t buff[4] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS, false, buff, sizeof(buff)); - if(irq) { *irq = ((uint16_t)(buff[0]) << 24) | ((uint16_t)(buff[1]) << 16) | ((uint16_t)(buff[2]) << 8) |(uint16_t)buff[3]; } + if(irq) { *irq = ((uint32_t)(buff[0]) << 24) | ((uint32_t)(buff[1]) << 16) | ((uint32_t)(buff[2]) << 8) |(uint32_t)buff[3]; } return(state); } From 3ff8cce2f7d7826eb223225871b667911633bb02 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:32:37 +0000 Subject: [PATCH 1717/1848] [LR2021] Fix RSSI calibration buffer size --- src/modules/LR2021/LR2021_cmds_radio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index 00c0984a94..d9a7a82973 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -27,9 +27,9 @@ int16_t LR2021::getRssiInst(float* rssi) { } int16_t LR2021::setRssiCalibration(uint8_t rxPath, uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]) { - uint8_t buff[1 + RADIOLIB_LR2021_GAIN_TABLE_LENGTH] = { 0 }; + uint8_t buff[1 + 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH] = { 0 }; buff[0] = rxPath; - for(uint8_t i = 0; i < RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i++) { + for(uint8_t i = 0; i < 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i+=3) { buff[1 + i] = (uint8_t)((gain[i] & 0x300) >> 8); buff[2 + i] = (uint8_t)(gain[i] & 0xFF); buff[3 + i] = noiseFloor[i]; From 87ee86bb302f83dbfd2fe3297c07af746cb509c7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:33:35 +0000 Subject: [PATCH 1718/1848] [LR11x0] Fix macros in LR-FHSS example --- examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino index f1c7c1980a..a0dc436d9b 100644 --- a/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino +++ b/examples/LR11x0/LR11x0_LR_FHSS_Modem/LR11x0_LR_FHSS_Modem.ino @@ -57,8 +57,8 @@ void setup() { // the following settings can also // be modified at run-time state = radio.setFrequency(433.5); - state = radio.setLrFhssConfig(RADIOLIB_LR11X0_LR_FHSS_BW_1523_4, // bandwidth - RADIOLIB_LR11X0_LR_FHSS_CR_1_2, // coding rate + state = radio.setLrFhssConfig(RADIOLIB_LRXXXX_LR_FHSS_BW_1523_4, // bandwidth + RADIOLIB_LRXXXX_LR_FHSS_CR_1_2, // coding rate 3, // header count 0x13A); // hopping sequence seed state = radio.setOutputPower(10.0); From ae9632b8aff1e8463a7b3559fbe59fed811dd8d9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:44:59 +0000 Subject: [PATCH 1719/1848] [LR11x0] Remove redundant method --- src/modules/LR11x0/LR11x0.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index fad30bb030..9060167125 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -752,7 +752,6 @@ class LR11x0: public LRxxxx { int16_t clearRxBuffer(void); int16_t writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data); - int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); int16_t getVersion(uint8_t* hw, uint8_t* device, uint8_t* major, uint8_t* minor); int16_t getErrors(uint16_t* err); int16_t clearErrors(void); From 2de1adc525d81dc50c48b40adc118e862694cebb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:45:25 +0000 Subject: [PATCH 1720/1848] [LR2021] Fix cppcheck issues --- src/modules/LR11x0/LR_common.h | 2 +- src/modules/LR2021/LR2021.cpp | 14 ++++++------- src/modules/LR2021/LR2021.h | 20 +++++++++---------- .../LR2021/LR2021_cmds_chip_control.cpp | 6 +++--- src/modules/LR2021/LR2021_cmds_flrc.cpp | 2 +- src/modules/LR2021/LR2021_cmds_gfsk.cpp | 2 +- src/modules/LR2021/LR2021_cmds_lora.cpp | 8 ++++---- src/modules/LR2021/LR2021_cmds_oqpsk.cpp | 4 ++-- src/modules/LR2021/LR2021_cmds_radio.cpp | 4 ++-- src/modules/LR2021/LR2021_cmds_ranging.cpp | 2 +- src/modules/LR2021/LR2021_config.cpp | 2 +- 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 4793ebcc6d..0c03b79d5c 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -85,7 +85,7 @@ class LRxxxx: public PhysicalLayer { public: - LRxxxx(Module* mod); + explicit LRxxxx(Module* mod); /*! \brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false. diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index cfc155b14e..64f10f3776 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -317,7 +317,7 @@ size_t LR2021::getPacketLength(bool update) { int16_t LR2021::finishTransmit() { // clear interrupt flags - clearIrq(RADIOLIB_LR2021_IRQ_ALL); + clearIrqState(RADIOLIB_LR2021_IRQ_ALL); // set mode to standby to disable transmitter/RF switch return(standby()); @@ -363,7 +363,7 @@ int16_t LR2021::readData(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // clear interrupt flags - state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL); // check if CRC failed - this is done after reading data to give user the option to keep them RADIOLIB_ASSERT(crcState); @@ -377,7 +377,7 @@ int16_t LR2021::finishReceive() { RADIOLIB_ASSERT(state); // clear interrupt flags - return(clearIrq(RADIOLIB_LR2021_IRQ_ALL)); + return(clearIrqState(RADIOLIB_LR2021_IRQ_ALL)); } int16_t LR2021::startChannelScan() { @@ -418,7 +418,7 @@ int16_t LR2021::startChannelScan(const ChannelScanConfig_t &config) { RADIOLIB_ASSERT(state); // clear interrupt flags - state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL); RADIOLIB_ASSERT(state); // set mode to CAD @@ -489,7 +489,7 @@ int16_t LR2021::config(uint8_t modem) { RADIOLIB_ASSERT(state); // clear IRQ - state = this->clearIrq(RADIOLIB_LR2021_IRQ_ALL); + state = this->clearIrqState(RADIOLIB_LR2021_IRQ_ALL); RADIOLIB_ASSERT(state); // validate DIO pin number @@ -619,7 +619,7 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { RADIOLIB_ASSERT(state); // clear interrupt flags - state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL); RADIOLIB_ASSERT(state); // set implicit mode and expected len if applicable @@ -680,7 +680,7 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { } // clear interrupt flags - state = clearIrq(RADIOLIB_LR2021_IRQ_ALL); + state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL); RADIOLIB_ASSERT(state); } break; diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 20473ba64e..d3449e7d27 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -320,13 +320,13 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t invertIQ(bool enable) override; - + /*! \brief Get modem currently in use by the radio. \param modem Pointer to a variable to save the retrieved configuration into. \returns \ref status_codes */ - int16_t getModem(ModemType_t* modem); + int16_t getModem(ModemType_t* modem) override; /*! \copydoc PhysicalLayer::stageMode */ int16_t stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) override; @@ -370,9 +370,9 @@ class LR2021: public LRxxxx { int16_t getRxPktLength(uint16_t* len); int16_t resetRxStats(void); int16_t setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout); - int16_t setRegMode(uint8_t simoUsage, uint8_t rampTimes[4]); + int16_t setRegMode(uint8_t simoUsage, const uint8_t rampTimes[4]); int16_t calibrate(uint8_t blocks); - int16_t calibrateFrontEnd(uint16_t freq[3]); + int16_t calibrateFrontEnd(const uint16_t freq[3]); int16_t getVbat(uint8_t resolution, uint16_t* vbat); int16_t getTemp(uint8_t source, uint8_t resolution, float* temp); int16_t setEolConfig(bool enable, uint8_t trim); @@ -382,7 +382,7 @@ class LR2021: public LRxxxx { int16_t getErrors(uint16_t* err); int16_t setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive); int16_t setDioIrqConfig(uint8_t dio, uint32_t irq); - int16_t clearIrq(uint32_t irq); + int16_t clearIrqState(uint32_t irq); int16_t getAndClearIrqStatus(uint32_t* irq); int16_t configFifoIrq(uint8_t rxFifoIrq, uint8_t txFifoIrq, uint8_t rxHighThreshold, uint8_t txHighThreshold); int16_t getFifoIrqFlags(uint8_t* rxFifoFlags, uint8_t* txFifoFlags); @@ -401,7 +401,7 @@ class LR2021: public LRxxxx { int16_t setRfFrequency(uint32_t rfFreq); int16_t setRxPath(uint8_t rxPath, uint8_t rxBoost); int16_t getRssiInst(float* rssi); - int16_t setRssiCalibration(uint8_t rxPath, uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]); + int16_t setRssiCalibration(uint8_t rxPath, const uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], const uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]); int16_t setTimestampSource(uint8_t index, uint8_t source); int16_t getTimestampValue(uint8_t index, uint32_t* timestamp); int16_t setCca(uint32_t duration, uint8_t gain); @@ -428,10 +428,10 @@ class LR2021: public LRxxxx { int16_t setLoRaCad(void); int16_t getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint16_t* headerCrcError, uint16_t* falseSynch); int16_t getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket); - int16_t setLoRaAddress(uint8_t addrLen, uint8_t addrPos, uint8_t* addr); - int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, uint32_t* freqHops, size_t numFreqHops); + int16_t setLoRaAddress(uint8_t addrLen, uint8_t addrPos, const uint8_t* addr); + int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops); int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum); - int16_t setLoRaSideDetCad(uint8_t* pnrDelta, uint8_t* detPeak, size_t numSideDets); + int16_t setLoRaSideDetCad(const uint8_t* pnrDelta, const uint8_t* detPeak, size_t numSideDets); // ranging commands int16_t setRangingAddr(uint32_t addr, uint8_t checkLen); @@ -456,7 +456,7 @@ class LR2021: public LRxxxx { int16_t getOqpskRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError); int16_t getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, float* rssiAvg, float* rssiSync, float* lqi); int16_t setOqpskPacketLen(uint8_t len); - int16_t setOqpskAddress(uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId); + int16_t setOqpskAddress(const uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId); // BPSK commands int16_t setBpskModulationParams(uint32_t bitRate, uint8_t pulseShape, bool diff, uint8_t diffInit); diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index cec0c75480..097f6d4216 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -140,7 +140,7 @@ int16_t LR2021::setDefaultRxTxTimeout(uint32_t rxTimeout, uint32_t txTimeout) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DEFAULT_RX_TX_TIMEOUT, true, buff, sizeof(buff))); } -int16_t LR2021::setRegMode(uint8_t simoUsage, uint8_t rampTimes[4]) { +int16_t LR2021::setRegMode(uint8_t simoUsage, const uint8_t rampTimes[4]) { uint8_t buff[] = { simoUsage, rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RC2RU], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_TX2RU], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RU2RC], rampTimes[RADIOLIB_LR2021_REG_MODE_RAMP_INDEX_RAMP_DOWN], @@ -152,7 +152,7 @@ int16_t LR2021::calibrate(uint8_t blocks) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_CALIBRATE, true, &blocks, sizeof(blocks))); } -int16_t LR2021::calibrateFrontEnd(uint16_t freq[3]) { +int16_t LR2021::calibrateFrontEnd(const uint16_t freq[3]) { uint8_t buff[] = { (uint8_t)((freq[0] >> 8) & 0xFF), (uint8_t)(freq[0] & 0xFF), (uint8_t)((freq[1] >> 8) & 0xFF), (uint8_t)(freq[1] & 0xFF), @@ -224,7 +224,7 @@ int16_t LR2021::setDioIrqConfig(uint8_t dio, uint32_t irq) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG, true, buff, sizeof(buff))); } -int16_t LR2021::clearIrq(uint32_t irq) { +int16_t LR2021::clearIrqState(uint32_t irq) { return(this->setU32(RADIOLIB_LR2021_CMD_CLEAR_IRQ, irq)); } diff --git a/src/modules/LR2021/LR2021_cmds_flrc.cpp b/src/modules/LR2021/LR2021_cmds_flrc.cpp index 1c66d32373..a7731905b2 100644 --- a/src/modules/LR2021/LR2021_cmds_flrc.cpp +++ b/src/modules/LR2021/LR2021_cmds_flrc.cpp @@ -33,7 +33,7 @@ int16_t LR2021::getFlrcRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uin int16_t LR2021::getFlrcPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, uint8_t* syncWordNum) { uint8_t buff[5] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_FLRC_PACKET_STATUS, false, buff, sizeof(buff)); - uint16_t raw = 0; + uint16_t raw; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { raw = (uint16_t)buff[2] << 1; diff --git a/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/src/modules/LR2021/LR2021_cmds_gfsk.cpp index befa5010bd..b9a31d091b 100644 --- a/src/modules/LR2021/LR2021_cmds_gfsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_gfsk.cpp @@ -75,7 +75,7 @@ int16_t LR2021::getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uin int16_t LR2021::getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_GFSK_PACKET_STATUS, false, buff, sizeof(buff)); - uint16_t raw = 0; + uint16_t raw; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { raw = (uint16_t)buff[2] << 1; diff --git a/src/modules/LR2021/LR2021_cmds_lora.cpp b/src/modules/LR2021/LR2021_cmds_lora.cpp index 30c3b25dc8..3db944abae 100644 --- a/src/modules/LR2021/LR2021_cmds_lora.cpp +++ b/src/modules/LR2021/LR2021_cmds_lora.cpp @@ -75,7 +75,7 @@ int16_t LR2021::getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint int16_t LR2021::getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket) { uint8_t buff[6] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS, false, buff, sizeof(buff)); - uint16_t raw = 0; + uint16_t raw; if(crc) { *crc = (buff[0] & 0x10) >> 4; } if(cr) { *cr = buff[0] & 0x0F; } if(packetLen) { *packetLen = buff[1]; } @@ -93,14 +93,14 @@ int16_t LR2021::getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLe return(state); } -int16_t LR2021::setLoRaAddress(uint8_t addrLen, uint8_t addrPos, uint8_t* addr) { +int16_t LR2021::setLoRaAddress(uint8_t addrLen, uint8_t addrPos, const uint8_t* addr) { if(addrLen > 8) { return(RADIOLIB_ERR_UNKNOWN); } uint8_t buff[9] = { (uint8_t)(((addrLen & 0x0F) << 4) | (addrPos & 0x0F)) }; memcpy(&buff[1], addr, addrLen); return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_ADDRESS, true, buff, sizeof(buff))); } -int16_t LR2021::setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, uint32_t* freqHops, size_t numFreqHops) { +int16_t LR2021::setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops) { if(numFreqHops > 40) { return(RADIOLIB_ERR_UNKNOWN); } uint8_t buff[2 + 160] = { (uint8_t)(hopCtrl | ((hopPeriod & 0xF00) >> 8)), (uint8_t)(hopPeriod & 0xFF) }; for(uint8_t i = 0; i < numFreqHops; i++) { @@ -117,7 +117,7 @@ int16_t LR2021::setLoRaTxSync(uint8_t function, uint8_t dioNum) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_LORA_TX_SYNC, true, buff, sizeof(buff))); } -int16_t LR2021::setLoRaSideDetCad(uint8_t* pnrDelta, uint8_t* detPeak, size_t numSideDets) { +int16_t LR2021::setLoRaSideDetCad(const uint8_t* pnrDelta, const uint8_t* detPeak, size_t numSideDets) { uint8_t buff[6] = { 0 }; for(uint8_t i = 0; i < numSideDets; i++) { if(i >= 3) { return(RADIOLIB_ERR_UNKNOWN); } diff --git a/src/modules/LR2021/LR2021_cmds_oqpsk.cpp b/src/modules/LR2021/LR2021_cmds_oqpsk.cpp index 65044cf1b1..9090f8c277 100644 --- a/src/modules/LR2021/LR2021_cmds_oqpsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_oqpsk.cpp @@ -30,7 +30,7 @@ int16_t LR2021::getOqpskPacketStatus(uint8_t* rxHeader, uint16_t* payloadLen, fl int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OQPSK_PACKET_STATUS, false, buff, sizeof(buff)); if(rxHeader) { *rxHeader = buff[0]; } if(payloadLen) { *payloadLen = ((uint16_t)(buff[1]) << 8) | (uint16_t)buff[2]; } - uint16_t raw = 0; + uint16_t raw; if(rssiAvg) { raw = (uint16_t)buff[3] << 1; raw |= (buff[5] & 0x04) >> 2; @@ -49,7 +49,7 @@ int16_t LR2021::setOqpskPacketLen(uint8_t len) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OQPSK_PACKET_LEN, true, &len, sizeof(len))); } -int16_t LR2021::setOqpskAddress(uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId) { +int16_t LR2021::setOqpskAddress(const uint8_t longDestAddr[8], uint16_t shortDestAddr, uint16_t panId, uint8_t transId) { uint8_t buff[] = { longDestAddr[7], longDestAddr[6], longDestAddr[5], longDestAddr[4], longDestAddr[3], longDestAddr[2], longDestAddr[1], longDestAddr[0], diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index d9a7a82973..db0ba475da 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -26,7 +26,7 @@ int16_t LR2021::getRssiInst(float* rssi) { return(state); } -int16_t LR2021::setRssiCalibration(uint8_t rxPath, uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]) { +int16_t LR2021::setRssiCalibration(uint8_t rxPath, const uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], const uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]) { uint8_t buff[1 + 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH] = { 0 }; buff[0] = rxPath; for(uint8_t i = 0; i < 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i+=3) { @@ -60,7 +60,7 @@ int16_t LR2021::setCca(uint32_t duration, uint8_t gain) { int16_t LR2021::getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg) { uint8_t buff[4] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_CCA_RESULT, false, buff, sizeof(buff)); - uint16_t raw = 0; + uint16_t raw; if(rssiMin) { raw = ((uint16_t)(buff[0]) << 1) | (uint16_t)((buff[3] >> 2) & 0x01); *rssiMin = (float)raw/-2.0f; diff --git a/src/modules/LR2021/LR2021_cmds_ranging.cpp b/src/modules/LR2021/LR2021_cmds_ranging.cpp index 0d48ba525f..7cc499835a 100644 --- a/src/modules/LR2021/LR2021_cmds_ranging.cpp +++ b/src/modules/LR2021/LR2021_cmds_ranging.cpp @@ -25,7 +25,7 @@ int16_t LR2021::setRangingReqAddr(uint32_t addr) { } int16_t LR2021::getRangingResult(uint8_t type, uint32_t* rng1, uint8_t* rssi1, uint32_t* rng2) { - uint8_t reqBuff[] = { type }; + const uint8_t reqBuff[] = { type }; uint8_t rplBuff[7] = { 0 }; //! \TODO: [LR2021] implement AGC gains readout diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index de6fbb281f..8e76945384 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -32,7 +32,7 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { // get the nearest multiple of 4 MHz uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 }; frequencies[0] |= (freq > 1000.0f) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; - state = calibrateFrontEnd(frequencies); + state = calibrateFrontEnd(const_cast(frequencies)); // if something failed, check the device errors if(state != RADIOLIB_ERR_NONE) { From 5d0a4d6b3f9d414a9afb8dab65fdd336f8c2c485 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:56:52 +0000 Subject: [PATCH 1721/1848] [LR2021] More cppcheck fixers --- src/modules/LR2021/LR2021.h | 4 ++-- src/modules/LR2021/LR2021_cmds_ook.cpp | 2 +- src/modules/LR2021/LR2021_cmds_radio.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index d3449e7d27..7ff59f37a0 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -446,7 +446,7 @@ class LR2021: public LRxxxx { int16_t setGfskPacketParams(uint16_t preambleLen, uint8_t preambleDetect, bool longPreamble, bool pldLenBits, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t dcFree); int16_t setGfskWhiteningParams(uint8_t whitenType, uint16_t init); int16_t setGfskCrcParams(uint32_t poly, uint32_t init); - int16_t setGfskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst); + int16_t setGfskSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst); int16_t setGfskAddress(uint8_t addrNode, uint8_t addrBroadcast); int16_t getGfskRxStats(uint16_t* packetRx, uint16_t* packetCrcError, uint16_t* lenError, uint16_t* preambleDet, uint16_t* syncOk, uint16_t* syncFail, uint16_t* timeout); int16_t getGfskPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); @@ -479,7 +479,7 @@ class LR2021: public LRxxxx { int16_t setOokModulationParams(uint32_t bitRate, uint8_t pulseShape, uint8_t rxBw, uint8_t depth); int16_t setOokPacketParams(uint16_t preambleLen, uint8_t addrComp, uint8_t packetFormat, uint16_t payloadLen, uint8_t crc, uint8_t manchester); int16_t setOokCrcParams(uint32_t poly, uint32_t init); - int16_t setOokSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst); + int16_t setOokSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst); int16_t setOokAddress(uint8_t addrNode, uint8_t addrBroadcast); int16_t getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError); int16_t getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 398c38c02f..691979e731 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -36,7 +36,7 @@ int16_t LR2021::setOokCrcParams(uint32_t poly, uint32_t init) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_CRC_PARAMS, true, buff, sizeof(buff))); } -int16_t LR2021::setOokSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { +int16_t LR2021::setOokSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { uint8_t buff[5] = { 0 }; for(size_t i = 0; i < syncWordLen; i++) { buff[3 - i] = syncWord[i]; diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index db0ba475da..4e69f60c93 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -29,10 +29,10 @@ int16_t LR2021::getRssiInst(float* rssi) { int16_t LR2021::setRssiCalibration(uint8_t rxPath, const uint16_t gain[RADIOLIB_LR2021_GAIN_TABLE_LENGTH], const uint8_t noiseFloor[RADIOLIB_LR2021_GAIN_TABLE_LENGTH]) { uint8_t buff[1 + 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH] = { 0 }; buff[0] = rxPath; - for(uint8_t i = 0; i < 3*RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i+=3) { - buff[1 + i] = (uint8_t)((gain[i] & 0x300) >> 8); - buff[2 + i] = (uint8_t)(gain[i] & 0xFF); - buff[3 + i] = noiseFloor[i]; + for(uint8_t i = 0; i < RADIOLIB_LR2021_GAIN_TABLE_LENGTH; i++) { + buff[1 + 3*i] = (uint8_t)((gain[i] & 0x300) >> 8); + buff[2 + 3*i] = (uint8_t)(gain[i] & 0xFF); + buff[3 + 3*i] = noiseFloor[i]; } return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff))); } From 0a9ed18a9a4ecc19676881c20a206761e4c128fe Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 13:59:01 +0000 Subject: [PATCH 1722/1848] [LR2021] Fix sync word method --- src/modules/LR2021/LR2021_cmds_gfsk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/src/modules/LR2021/LR2021_cmds_gfsk.cpp index b9a31d091b..c0c1b7e324 100644 --- a/src/modules/LR2021/LR2021_cmds_gfsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_gfsk.cpp @@ -45,7 +45,7 @@ int16_t LR2021::setGfskCrcParams(uint32_t poly, uint32_t init) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_CRC_PARAMS, true, buff, sizeof(buff))); } -int16_t LR2021::setGfskSyncword(uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { +int16_t LR2021::setGfskSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { uint8_t buff[9] = { 0 }; for(size_t i = 0; i < syncWordLen; i++) { buff[7 - i] = syncWord[i]; From a334ec6cd479f8da21d812ee50776bd4ae22334b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 14:16:16 +0000 Subject: [PATCH 1723/1848] [CI] Fix ToA unit test --- extras/test/unit/tests/TestCalculateTimeOnAir.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp index 165dd20118..4177a0070b 100644 --- a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp +++ b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp @@ -29,6 +29,7 @@ std::vector allConfigs = { { "SX128x", RADIOLIB_MODEM_LORA, {.lora={12,800,7}}, {.lora={16,false,true,true}}, {10,100,250}, {216319,861440,1936640} }, // 212.99, 848.19, 1910 { "SX128x", RADIOLIB_MODEM_FSK, {.fsk={250,100}}, {.fsk={16,16,2}}, {1,32,64,128}, {224,1216,2240,4288} }, + // also covers LR2021 as the calculation is shared in the LRxxxx base class { "LR11x0", RADIOLIB_MODEM_LORA, {.lora={10,250,5}}, {.lora={8,false,true,true}}, {1,20,100}, {103424,205824,615424} }, // 103.42, 205.82, 615.42 { "LR11x0", RADIOLIB_MODEM_LORA, {.lora={11,500,6}}, {.lora={32,true,false,false}}, {10,25,200}, {205824,279552,1065984} }, // 205.82, 279.55, 1070 { "LR11x0", RADIOLIB_MODEM_FSK, {.fsk={200,50}}, {.fsk={16,32,2}}, {1,32,64,200}, {360,1600,2880,8320} }, @@ -45,17 +46,20 @@ BOOST_AUTO_TEST_CASE(TimeOnAir_AllRadios) { auto len = cfg.payload_len[i]; RadioLibTime_t toa = 0; + // create a dummy module class instance that the derived classes may reference + Module mod(nullptr, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC); + if (cfg.name == "SX126x") { - SX126x dummy(nullptr); + SX126x dummy(&mod); toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); } else if (cfg.name == "SX127x") { - SX127x dummy(nullptr); + SX127x dummy(&mod); toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); } else if (cfg.name == "SX128x") { - SX128x dummy(nullptr); + SX128x dummy(&mod); toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); } else if (cfg.name == "LR11x0") { - LR11x0 dummy(nullptr); + LR11x0 dummy(&mod); toa = dummy.calculateTimeOnAir(cfg.modem, cfg.dr, cfg.pc, len); } From 928ede6be74aa96242ad3ad91676ffc07dd31b44 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 14:18:13 +0000 Subject: [PATCH 1724/1848] [LR2021] Fix redundant definitions --- src/modules/LR11x0/LR11x0.cpp | 1 - src/modules/LR2021/LR2021.cpp | 1 - src/modules/LR2021/LR2021_cmds_ook.cpp | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 7676586195..260cdc955e 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1465,7 +1465,6 @@ int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { } // set packet Length - state = RADIOLIB_ERR_NONE; uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE; state = getPacketType(&modem); RADIOLIB_ASSERT(state); diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 64f10f3776..5a0a22ab1b 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -645,7 +645,6 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { //! \todo [LR2021] implement GFSK address filtering // set packet Length - state = RADIOLIB_ERR_NONE; uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; state = getPacketType(&modem); RADIOLIB_ASSERT(state); diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 691979e731..0c7becbb19 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -62,7 +62,7 @@ int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS, false, buff, sizeof(buff)); - uint16_t raw = 0; + uint16_t raw; if(packetLen) { *packetLen = ((uint16_t)(buff[0]) << 8) | (uint16_t)buff[1]; } if(rssiAvg) { raw = (uint16_t)buff[2] << 1; From 369ba4ed57895af4c9a2e11de25e5d37623a9d8c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 17 Jan 2026 17:44:57 +0000 Subject: [PATCH 1725/1848] [LR2021] Add temperature and voltage readout --- src/modules/LR2021/LR2021.cpp | 26 +++++++++++++++++++ src/modules/LR2021/LR2021.h | 15 +++++++++++ .../LR2021/LR2021_cmds_chip_control.cpp | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 5a0a22ab1b..01598878f4 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -718,4 +718,30 @@ int16_t LR2021::launchMode() { return(state); } +float LR2021::getVoltage(uint8_t bits) { + if((bits < 8) || (bits > 13)) { + return(0); + } + + uint16_t val; + if(getVbat(bits, &val) != RADIOLIB_ERR_NONE) { + return(0); + } + + return((float)val / 1000.0f); +} + +float LR2021::getTemperature(uint8_t source, uint8_t bits) { + if((bits < 8) || (bits > 13)) { + return(0); + } + + float val; + if(getTemp(source, bits, &val) != RADIOLIB_ERR_NONE) { + return(0); + } + + return(val); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 7ff59f37a0..39b630fc54 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -333,6 +333,21 @@ class LR2021: public LRxxxx { /*! \copydoc PhysicalLayer::launchMode */ int16_t launchMode() override; + + /*! + \brief Read the supply voltage on the Vbat pin. + \param bits Measurement resolution in bits, 8 to 13. + \returns \ref Supply voltage in volts. + */ + float getVoltage(uint8_t bits = 13); + + /*! + \brief Read the temperature. + \param source Measurement source, one of RADIOLIB_LR2021_TEMP_SOURCE_* macros. + \param bits Measurement resolution in bits, 8 to 13. + \returns \ref Temperature in degrees Celsius. + */ + float getTemperature(uint8_t source, uint8_t bits = 13); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index 097f6d4216..d9855c06a4 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -175,7 +175,7 @@ int16_t LR2021::getTemp(uint8_t source, uint8_t resolution, float* temp) { int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_TEMP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff)); if(temp) { uint16_t raw = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; - *temp = (float)raw/32.0f; + *temp = (float)raw/320.0f; } return(state); } From 72808cdc2c2b3f13debfe84094f79d2874bfd2e8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 16:05:52 +0000 Subject: [PATCH 1726/1848] [MOD] Add support for 24-bit SPI addresses --- src/Module.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Module.h b/src/Module.h index 17386aa76a..ca2c21ee6e 100644 --- a/src/Module.h +++ b/src/Module.h @@ -177,6 +177,7 @@ class Module { BITS_0 = 0, BITS_8 = 8, BITS_16 = 16, + BITS_24 = 24, BITS_32 = 32, }; From e3af85867bea07d2bd3d4455928407e17cd695b0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 16:06:35 +0000 Subject: [PATCH 1727/1848] [LR2021] Fix address widths --- src/modules/LR11x0/LR11x0.cpp | 1 + src/modules/LR11x0/LR_common.cpp | 22 +++++++++++++--------- src/modules/LR11x0/LR_common.h | 2 +- src/modules/LR2021/LR2021.cpp | 1 + 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 260cdc955e..aa3195fb0d 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1580,6 +1580,7 @@ int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) { this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8; this->gnss = false; diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 6cb314ac8d..3ea2dd143c 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -6,7 +6,6 @@ LRxxxx::LRxxxx(Module* mod) : PhysicalLayer() { this->mod = mod; this->XTAL = false; this->mod->spiConfig.stream = true; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16; this->mod->spiConfig.statusPos = 0; this->mod->spiConfig.parseStatusCb = SPIparseStatus; @@ -341,10 +340,15 @@ int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d #endif // set the address or offset - dataBuff[0] = (uint8_t)((addrOffset >> 24) & 0xFF); - dataBuff[1] = (uint8_t)((addrOffset >> 16) & 0xFF); - dataBuff[2] = (uint8_t)((addrOffset >> 8) & 0xFF); - dataBuff[3] = (uint8_t)(addrOffset & 0xFF); + uint8_t* dataBuffPtr = (uint8_t*)dataBuff; + if(this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] >= Module::BITS_32) { + // LR2021 has 24-bit address, whereas LR11x0 has 32-bit + *(dataBuffPtr++) = (uint8_t)((addrOffset >> 24) & 0xFF); + } + + *(dataBuffPtr++) = (uint8_t)((addrOffset >> 16) & 0xFF); + *(dataBuffPtr++) = (uint8_t)((addrOffset >> 8) & 0xFF); + *(dataBuffPtr++) = (uint8_t)(addrOffset & 0xFF); // convert endians for(size_t i = 0; i < len; i++) { @@ -355,10 +359,10 @@ int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d } else { bin = data[i]; } - dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF); - dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF); - dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF); - dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF); + *(dataBuffPtr++) = (uint8_t)((bin >> 24) & 0xFF); + *(dataBuffPtr++) = (uint8_t)((bin >> 16) & 0xFF); + *(dataBuffPtr++) = (uint8_t)((bin >> 8) & 0xFF); + *(dataBuffPtr++) = (uint8_t)(bin & 0xFF); } int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 0c03b79d5c..0af8ceec3f 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -5,7 +5,7 @@ #include "../../protocols/PhysicalLayer/PhysicalLayer.h" #define RADIOLIB_LRXXXX_CMD_NOP (0x0000) -#define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (256) +#define RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN (128) // intentionally limited to the length supported by LR2021 // RADIOLIB_LR11X0_CMD_GET_STATUS // RADIOLIB_LR2021_CMD_GET_STATUS MSB LSB DESCRIPTION diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 01598878f4..a0e534a9ae 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -28,6 +28,7 @@ int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_24; this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; // try to find the chip - this will also reset the module at least once From b172ee3189361e59766d331b06184354ff8eae3f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 16:06:51 +0000 Subject: [PATCH 1728/1848] [LR2021] Fix memory read and write commands --- src/modules/LR2021/LR2021_cmds_chip_control.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index d9855c06a4..0ea3c1f57d 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -28,8 +28,8 @@ int16_t LR2021::writeRegMem32(uint32_t addr, const uint32_t* data, size_t len) { } int16_t LR2021::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { - uint8_t buff[12] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), + uint8_t buff[11] = { + (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), (uint8_t)((mask >> 24) & 0xFF), (uint8_t)((mask >> 16) & 0xFF), (uint8_t)((mask >> 8) & 0xFF), (uint8_t)(mask & 0xFF), (uint8_t)((data >> 24) & 0xFF), (uint8_t)((data >> 16) & 0xFF), (uint8_t)((data >> 8) & 0xFF), (uint8_t)(data & 0xFF), }; @@ -38,15 +38,14 @@ int16_t LR2021::writeRegMemMask32(uint32_t addr, uint32_t mask, uint32_t data) { int16_t LR2021::readRegMem32(uint32_t addr, uint32_t* data, size_t len) { // check maximum size - if(len >= (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { + if(len > (RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) { return(RADIOLIB_ERR_SPI_CMD_INVALID); } // the request contains the address and length - uint8_t reqBuff[5] = { - (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), - (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF), - (uint8_t)len, + uint8_t reqBuff[4] = { + (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), + (uint8_t)(addr & 0xFF), (uint8_t)len, }; // build buffers - later we need to ensure endians are correct, From 3072504a0d3db0e7fa522356e80d139f589b3456 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 17:18:32 +0000 Subject: [PATCH 1729/1848] [LR11x0] Fix cast --- src/modules/LR11x0/LR_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 3ea2dd143c..02b6cfb0f0 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -340,7 +340,7 @@ int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d #endif // set the address or offset - uint8_t* dataBuffPtr = (uint8_t*)dataBuff; + uint8_t* dataBuffPtr = reinterpret_cast(dataBuff); if(this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] >= Module::BITS_32) { // LR2021 has 24-bit address, whereas LR11x0 has 32-bit *(dataBuffPtr++) = (uint8_t)((addrOffset >> 24) & 0xFF); From f6e513c3d41c8f585ddacc9e93120d7bffa2658b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 17:40:22 +0000 Subject: [PATCH 1730/1848] [LR2021] Add methods to read RSSI and SNR --- src/modules/LR2021/LR2021.cpp | 41 +++++++++++++++++++++++++++++++++++ src/modules/LR2021/LR2021.h | 20 +++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index a0e534a9ae..7808effccc 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -745,4 +745,45 @@ float LR2021::getTemperature(uint8_t source, uint8_t bits) { return(val); } +float LR2021::getRSSI() { + return(this->getRSSI(true)); +} + +float LR2021::getRSSI(bool packet) { + float rssi = 0; + int16_t state; + if(!packet) { + // get instantenous RSSI value + state = this->getRssiInst(&rssi); + if(state != RADIOLIB_ERR_NONE) { return(0); } + return(rssi); + } + + // check modem type + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + state = this->getPacketType(&modem); + if(state != RADIOLIB_ERR_NONE) { return(0); } + if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) { + state = this->getLoRaPacketStatus(NULL, NULL, NULL, NULL, &rssi, NULL); + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + state = this->getGfskPacketStatus(NULL, &rssi, NULL, NULL, NULL, NULL); + } else { + return(0); + } + + if(state != RADIOLIB_ERR_NONE) { return(0); } + return(rssi); +} + +float LR2021::getSNR() { + float snr; + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = this->getPacketType(&modem); + if(state != RADIOLIB_ERR_NONE) { return(0); } + if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { return(0); } + state = this->getLoRaPacketStatus(NULL, NULL, NULL, &snr, NULL, NULL); + if(state != RADIOLIB_ERR_NONE) { return(0); } + return(snr); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 39b630fc54..4a70509e3f 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -348,6 +348,26 @@ class LR2021: public LRxxxx { \returns \ref Temperature in degrees Celsius. */ float getTemperature(uint8_t source, uint8_t bits = 13); + + /*! + \brief Gets recorded signal strength indicator. + Overload with packet mode enabled for PhysicalLayer compatibility. + \returns RSSI value in dBm. + */ + float getRSSI() override; + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator). + \param packet Whether to read last packet RSSI, or the current value. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. + \returns SNR of the last received packet in dB. + */ + float getSNR() override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: From 985cef69762764f3b3c5e8429c33ca9b667a232d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 19:46:46 +0000 Subject: [PATCH 1731/1848] [LR2021] Move basic module setup to common method --- src/modules/LR2021/LR2021.cpp | 72 +++++++++++++++++++---------------- src/modules/LR2021/LR2021.h | 1 + 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 7808effccc..ea4def62bb 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -21,42 +21,11 @@ LR2021::LR2021(Module* mod) : LRxxxx(mod) { } int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) { - this->mod->init(); - this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); - this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; - this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_24; - this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; - - // try to find the chip - this will also reset the module at least once - if(!this->findChip()) { - RADIOLIB_DEBUG_BASIC_PRINTLN("No LR2021 found!"); - this->mod->term(); - return(RADIOLIB_ERR_CHIP_NOT_FOUND); - } - RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR2021"); - - // set mode to standby - int16_t state = standby(); - RADIOLIB_ASSERT(state); - - // set TCXO control, if requested - if(!this->XTAL && tcxoVoltage > 0.0f) { - state = setTCXO(tcxoVoltage); - RADIOLIB_ASSERT(state); - } - - // configure settings not accessible by API - state = config(RADIOLIB_LR2021_PACKET_TYPE_LORA); + // set module properties and perform initial setup + int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_LORA); RADIOLIB_ASSERT(state); // configure publicly accessible settings - state = setFrequency(freq); - RADIOLIB_ASSERT(state); - state = setBandwidth(bw); RADIOLIB_ASSERT(state); @@ -453,6 +422,43 @@ Module* LR2021::getMod() { return(this->mod); } +int16_t LR2021::modSetup(float freq, float tcxoVoltage, uint8_t modem) { + this->mod->init(); + this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); + this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP; + this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_24; + this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16; + + // try to find the chip - this will also reset the module at least once + if(!this->findChip()) { + RADIOLIB_DEBUG_BASIC_PRINTLN("No LR2021 found!"); + this->mod->term(); + return(RADIOLIB_ERR_CHIP_NOT_FOUND); + } + RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR2021"); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set TCXO control, if requested + if(!this->XTAL && tcxoVoltage > 0.0f) { + state = setTCXO(tcxoVoltage); + RADIOLIB_ASSERT(state); + } + + // configure settings not accessible by API + state = config(modem); + RADIOLIB_ASSERT(state); + + state = setFrequency(freq); + return(state); +} + bool LR2021::findChip(void) { // this is the only version mentioned in datasheet const uint8_t expMajor = 0x01; diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 4a70509e3f..47fe93c5a5 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -385,6 +385,7 @@ class LR2021: public LRxxxx { // this is needed to automatically detect which PA to use bool highFreq = false; + int16_t modSetup(float freq, float tcxoVoltage, uint8_t modem); bool findChip(void); int16_t config(uint8_t modem); int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); From 214c5c4399e73bb128c5f8f65a64025bca2a63f3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 18 Jan 2026 20:16:36 +0000 Subject: [PATCH 1732/1848] [LR2021] Set Rx path based on frequency band --- src/modules/LR2021/LR2021.cpp | 4 ++++ src/modules/LR2021/LR2021_commands.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index ea4def62bb..838db19ee2 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -617,6 +617,10 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { return(RADIOLIB_ERR_WRONG_MODEM); } + + // set the correct Rx path + state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? RADIOLIB_LR2021_RX_BOOST_HF : RADIOLIB_LR2021_RX_BOOST_LF); + RADIOLIB_ASSERT(state); // set DIO mapping if(cfg->receive.timeout != RADIOLIB_LR2021_RX_TIMEOUT_INF) { diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index d5cecc4e7e..ed176bd86f 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -307,6 +307,8 @@ // RADIOLIB_LR2021_CMD_SET_RX_PATH #define RADIOLIB_LR2021_RX_PATH_LF (0x00UL << 0) // 7 0 Rx path: low-frequency #define RADIOLIB_LR2021_RX_PATH_HF (0x01UL << 0) // 7 0 high-frequency +#define RADIOLIB_LR2021_RX_BOOST_LF (0x00UL << 0) // 7 0 Rx boost: low-frequency +#define RADIOLIB_LR2021_RX_BOOST_HF (0x04UL << 0) // 7 0 high-frequency // RADIOLIB_LR2021_CMD_SET_RSSI_CALIBRATION #define RADIOLIB_LR2021_RSSI_PATH_LF (0x01UL << 0) // 0 0 Rx path for RSSI: low-frequency From e51d3af726a9aa4343b50056e67a0e2a92d36dd1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 21 Jan 2026 06:00:00 +0000 Subject: [PATCH 1733/1848] [SX126x] Fix direct transmit not transmitting on some platforms (#1677) --- src/modules/SX126x/SX126x.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index ccb55b1bb1..c03e744994 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -336,8 +336,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // direct mode activation intentionally skipped here, as it seems to lead to much worse results - const uint8_t data[] = { RADIOLIB_SX126X_CMD_NOP }; - return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1)); + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); } int16_t SX126x::receiveDirect() { From e9fec4ffa6ac1a7302f6d9a14a7df5be7840506b Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Jan 2026 05:44:07 +0000 Subject: [PATCH 1734/1848] [LR11x0] Move Rx timeout calculation to base class --- src/modules/LR11x0/LR11x0.cpp | 7 ------- src/modules/LR11x0/LR11x0.h | 7 ------- src/modules/LR11x0/LR_common.cpp | 7 +++++++ src/modules/LR11x0/LR_common.h | 7 +++++++ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index aa3195fb0d..6339aa7d1f 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1166,13 +1166,6 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { return((size_t)len); } -RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) { - // the timeout value is given in units of 30.52 microseconds - // the calling function should provide some extra width, as this number of units is truncated to integer - RadioLibTime_t timeout = timeoutUs / 30.52; - return(timeout); -} - uint32_t LR11x0::getIrqFlags() { return((uint32_t)this->getIrqStatus()); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 9060167125..5c5e61781b 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -456,13 +456,6 @@ class LR11x0: public LRxxxx { */ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); - /*! - \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) - \param timeoutUs Timeout in microseconds to listen for - \returns Timeout value in a unit that is specific for the used module - */ - RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; - /*! \brief Read currently active IRQ flags. \returns IRQ flags. diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 02b6cfb0f0..91f9b90807 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -172,6 +172,13 @@ RadioLibTime_t LRxxxx::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, Pack return(0); } +RadioLibTime_t LRxxxx::calculateRxTimeout(RadioLibTime_t timeoutUs) { + // the timeout value is given in units of 30.52 microseconds + // the calling function should provide some extra width, as this number of units is truncated to integer + RadioLibTime_t timeout = timeoutUs / 30.52; + return(timeout); +} + int16_t LRxxxx::reset() { // run the reset sequence this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput); diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 0af8ceec3f..c903b48035 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -154,6 +154,13 @@ class LRxxxx: public PhysicalLayer { */ RadioLibTime_t calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) override; + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; + protected: Module* mod; From 9d7dedd00136d72addce62c9f8c1eb9061cbc298 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 22 Jan 2026 05:44:37 +0000 Subject: [PATCH 1735/1848] [LR2021] Add RNG method --- src/modules/LR2021/LR2021.cpp | 6 ++++++ src/modules/LR2021/LR2021.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 838db19ee2..65d6145b33 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -796,4 +796,10 @@ float LR2021::getSNR() { return(snr); } +uint8_t LR2021::randomByte() { + uint32_t num = 0; + (void)getRandomNumber(&num); + return((uint8_t)num); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 47fe93c5a5..f93eca7a51 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -368,6 +368,12 @@ class LR2021: public LRxxxx { \returns SNR of the last received packet in dB. */ float getSNR() override; + + /*! + \brief Get one truly random byte from RSSI noise. + \returns TRNG byte. + */ + uint8_t randomByte() override; #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: From c684258fa3b6a5fab5f85b686134de7c5605621f Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 23 Jan 2026 20:30:09 +0000 Subject: [PATCH 1736/1848] [LR2021] Fix ToA not being calculated --- src/modules/LR11x0/LR11x0.cpp | 7 +++++++ src/modules/LR11x0/LR11x0.h | 7 +++++++ src/modules/LR11x0/LR_common.cpp | 6 +----- src/modules/LR11x0/LR_common.h | 8 +------- src/modules/LR2021/LR2021.cpp | 6 ++++++ src/modules/LR2021/LR2021.h | 7 +++++++ 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6339aa7d1f..4ecce2d8ea 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -986,6 +986,7 @@ int16_t LR11x0::setPreambleLength(size_t preambleLength) { return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) { this->preambleLengthGFSK = preambleLength; + //! \TODO: [LR11x0] this can probably be simplified with a simple calculation this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS : preambleLength >= 24 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS : preambleLength >= 16 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS : @@ -1166,6 +1167,12 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) { return((size_t)len); } +RadioLibTime_t LR11x0::getTimeOnAir(size_t len) { + ModemType_t modem; + getModem(&modem); + return(LRxxxx::getTimeOnAir(len, modem)); +} + uint32_t LR11x0::getIrqFlags() { return((uint32_t)this->getIrqStatus()); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 5c5e61781b..0f02a5431a 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -456,6 +456,13 @@ class LR11x0: public LRxxxx { */ int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t getTimeOnAir(size_t len) override; + /*! \brief Read currently active IRQ flags. \returns IRQ flags. diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 91f9b90807..acac2b5d55 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -47,11 +47,7 @@ uint32_t LRxxxx::getIrqStatus() { return(irq); } -RadioLibTime_t LRxxxx::getTimeOnAir(size_t len) { - ModemType_t modem; - int32_t state = this->getModem(&modem); - RADIOLIB_ASSERT(state); - +RadioLibTime_t LRxxxx::getTimeOnAir(size_t len, ModemType_t modem) { DataRate_t dr = {}; PacketConfig_t pc = {}; switch(modem) { diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index c903b48035..62b6474cd7 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -137,13 +137,6 @@ class LRxxxx: public PhysicalLayer { */ uint32_t getIrqStatus(); - /*! - \brief Get expected time-on-air for a given size of payload - \param len Payload length in bytes. - \returns Expected time-on-air in microseconds. - */ - RadioLibTime_t getTimeOnAir(size_t len) override; - /*! \brief Calculate the expected time-on-air for a given modem, data rate, packet configuration and payload size. \param modem Modem type. @@ -192,6 +185,7 @@ class LRxxxx: public PhysicalLayer { int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); int16_t lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); uint8_t roundRampTime(uint32_t rampTimeUs); + RadioLibTime_t getTimeOnAir(size_t len, ModemType_t modem); // several commands just send unsigned 32-bit number int16_t setU32(uint16_t cmd, uint32_t u32); diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 65d6145b33..7bf5819f55 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -582,6 +582,12 @@ int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uin return(setCad()); } +RadioLibTime_t LR2021::getTimeOnAir(size_t len) { + ModemType_t modem; + getModem(&modem); + return(LRxxxx::getTimeOnAir(len, modem)); +} + int16_t LR2021::getModem(ModemType_t* modem) { RADIOLIB_ASSERT_PTR(modem); diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index f93eca7a51..bf4b9875f8 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -321,6 +321,13 @@ class LR2021: public LRxxxx { */ int16_t invertIQ(bool enable) override; + /*! + \brief Get expected time-on-air for a given size of payload + \param len Payload length in bytes. + \returns Expected time-on-air in microseconds. + */ + RadioLibTime_t getTimeOnAir(size_t len) override; + /*! \brief Get modem currently in use by the radio. \param modem Pointer to a variable to save the retrieved configuration into. From b4364340d44ff861cca7199d205d44c0aa0e142d Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 23 Jan 2026 20:30:36 +0000 Subject: [PATCH 1737/1848] [LR2021] Add support for GFSK, FLRC and LR-FHSS modems --- src/modules/LR2021/LR2021.cpp | 129 ++++++- src/modules/LR2021/LR2021.h | 143 ++++++++ src/modules/LR2021/LR2021_commands.h | 3 + src/modules/LR2021/LR2021_config.cpp | 493 +++++++++++++++++++++++++-- 4 files changed, 724 insertions(+), 44 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 7bf5819f55..c143430583 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -49,9 +49,111 @@ int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = invertIQ(false); + return(state); +} + +int16_t LR2021::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8; + this->frequencyDev = freqDev * 1000.0f; + + // set module properties and perform initial setup + int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_GFSK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x12, 0xAD }; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + state = setCRC(2); + return(state); +} + +int16_t LR2021::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage) { +// set module properties and perform initial setup + int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS); + RADIOLIB_ASSERT(state); + + // set grid spacing + this->lrFhssGrid = narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC; + + // configure publicly accessible settings + state = setLrFhssConfig(bw, cr); RADIOLIB_ASSERT(state); - return(RADIOLIB_ERR_NONE); + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B }; + state = setSyncWord(syncWord, 4); + return(state); +} + +int16_t LR2021::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping, float tcxoVoltage) { + // initialize FLRC modulation variables + this->bitRateFlrc = br; + this->codingRateFlrc = RADIOLIB_LR2021_FLRC_CR_3_4; + this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5; + + // initialize FLRC packet variables + this->preambleLengthGFSK = preambleLength; + this->crcLenGFSK = 1; + + // set module properties and perform initial setup + int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_FLRC); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(pwr); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setDataShaping(dataShaping); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D}; + state = setSyncWord(sync, 4); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH); + return(state); } int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) { @@ -84,12 +186,14 @@ int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) { // calculate timeout (150% of expected time-on-air) timeout = (timeout * 3) / 2; - } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS)) { + } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || + (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) || + (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC)) { // calculate timeout (500% of expected time-on-air) timeout = timeout * 5; } else { - return(RADIOLIB_ERR_UNKNOWN); + return(RADIOLIB_ERR_WRONG_MODEM); } RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout); @@ -127,7 +231,9 @@ int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; state = getPacketType(&modem); RADIOLIB_ASSERT(state); - if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { + if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) || + (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || + (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC)) { // calculate timeout (500 % of expected time-one-air) size_t maxLen = len; if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; } @@ -620,7 +726,8 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { state = getPacketType(&modem); RADIOLIB_ASSERT(state); if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && - (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { + (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) && + (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -669,13 +776,15 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled); } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { - //! \todo [LR2021] implement GFSK - //state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); - - } else if(modem != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) { - return(RADIOLIB_ERR_UNKNOWN); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); + + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { + state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, cfg->transmit.len); + } else { + return(RADIOLIB_ERR_WRONG_MODEM); } + RADIOLIB_ASSERT(state); // set DIO mapping diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index bf4b9875f8..335fc0ad69 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -61,6 +61,47 @@ class LR2021: public LRxxxx { */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6); + /*! + \brief Initialization method for FSK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FSK bit rate in kbps. Defaults to 4.8 kbps. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 5.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 153.8 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength FSK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t beginGFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 153.8, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6); + + /*! + \brief Initialization method for LR-FHSS modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. Defaults to 722.66 kHz. + \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. Defaults to 2/3 coding rate. + \param narrowGrid Whether to use narrow (3.9 kHz) or wide (25.39 kHz) grid spacing. Defaults to true (narrow/non-FCC) grid. + \param power Output power in dBm. Defaults to 10 dBm. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + \returns \ref status_codes + */ + int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); + + /*! + \brief Initialization method for FLRC modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br FLRC bit rate in kbps. Defaults to 650 kbps. + \param cr FLRC coding rate. Defaults to 3 (coding rate 3/4). + \param pwr Output power in dBm. Defaults to 10 dBm. + \param preambleLength FLRC preamble length in bits. Defaults to 16 bits. + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + \returns \ref status_codes + */ + int16_t beginFLRC(float freq = 434.0, uint16_t br = 650, uint8_t cr = 3, int8_t pwr = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5, float tcxoVoltage = 1.6); + /*! \brief Blocking binary transmit method. Overloads for string-based transmissions are implemented in PhysicalLayer. @@ -321,6 +362,103 @@ class LR2021: public LRxxxx { */ int16_t invertIQ(bool enable) override; + /*! + \brief Sets GFSK bit rate. Allowed values range from 0.6 to 300.0 kbps. + \param br FSK bit rate to be set in kbps. + \returns \ref status_codes + */ + int16_t setBitRate(float br) override; + + /*! + \brief Sets GFSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. + \param freqDev GFSK frequency deviation to be set in kHz. + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev) override; + + /*! + \brief Sets GFSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, + 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. + \param rxBw GFSK receiver bandwidth to be set in kHz. + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets GFSK sync word in the form of array of up to 8 bytes. + \param syncWord GFSK sync word to be set. + \param len GFSK sync word length in bytes. + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len) override; + + /*! + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. + Set to RADIOLIB_SHAPING_NONE to disable data shaping. + \param sh Time-bandwidth product of Gaussian filter to be set. + \returns \ref status_codes + */ + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Sets transmission encoding. Available in GFSK mode only. Serves only as alias for PhysicalLayer compatibility. + \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Set modem in fixed packet length mode. Available in GFSK mode only. + \param len Packet length. + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_LR2021_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. Available in GFSK mode only. + \param maxLen Maximum packet length. + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH); + + /*! + \brief Sets GFSK whitening parameters. + \param enabled True = Whitening enabled + \param initial Initial value used for the whitening LFSR in GFSK mode. + By default set to 0x01FF for compatibility with SX127x and LoRaWAN. + \returns \ref status_codes + */ + int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF); + + /*! + \brief Set data rate. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. + \returns \ref status_codes + */ + int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; + + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; + + /*! + \brief Sets LR-FHSS configuration. + \param bw LR-FHSS bandwidth, one of RADIOLIB_LRXXXX_LR_FHSS_BW_* values. + \param cr LR-FHSS coding rate, one of RADIOLIB_LRXXXX_LR_FHSS_CR_* values. + \param hdrCount Header packet count, 1 - 4. Defaults to 3. + \param hopSeed 9-bit seed number for PRNG generation of the hopping sequence. Defaults to 0x13A. + \returns \ref status_codes + */ + int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeed = 0x13A); + /*! \brief Get expected time-on-air for a given size of payload \param len Payload length in bytes. @@ -398,9 +536,14 @@ class LR2021: public LRxxxx { // this is needed to automatically detect which PA to use bool highFreq = false; + // cached FLRC parameters + uint16_t bitRateFlrc; + uint8_t codingRateFlrc; + int16_t modSetup(float freq, float tcxoVoltage, uint8_t modem); bool findChip(void); int16_t config(uint8_t modem); + int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); // chip control commands diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index ed176bd86f..e458939ea6 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -472,6 +472,9 @@ #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX (0x00UL << 0) // 7 0 whitening type: compatible with SX126x and LR2021 #define RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX128X (0x01UL << 0) // 7 0 compatible with SX128x +// RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD +#define RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN (8) + // RADIOLIB_LR2021_CMD_SET_OQPSK_PARAMS #define RADIOLIB_LR2021_OQPSK_TYPE_15_4 (0x00UL << 0) // 7 0 OQPSK type: 802.15.4 PHY, 250 kbps bit rate diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 8e76945384..e8f7f2f083 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -3,6 +3,7 @@ #include "../LR11x0/LR_common.h" #include +#include #if !RADIOLIB_EXCLUDE_LR2021 @@ -196,35 +197,43 @@ int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) { uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { - return(RADIOLIB_ERR_WRONG_MODEM); - } + if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) { + RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + + if(longInterleave) { + switch(cr) { + case 4: + this->codingRate = 0; + break; + case 5: + case 6: + this->codingRate = cr; + break; + case 8: + this->codingRate = cr - 1; + break; + default: + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } + + } else { + this->codingRate = cr - 4; + + } - RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + // update modulation parameters + return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); - if(longInterleave) { - switch(cr) { - case 4: - this->codingRate = 0; - break; - case 5: - case 6: - this->codingRate = cr; - break; - case 8: - this->codingRate = cr - 1; - break; - default: - return(RADIOLIB_ERR_INVALID_CODING_RATE); - } - - } else { - this->codingRate = cr - 4; + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { + RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE); + + // update modulation parameters + this->codingRateFlrc = (cr - 2) * 2; + return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape)); } - - // update modulation parameters - return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); + + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t LR2021::setSyncWord(uint8_t syncWord) { @@ -247,9 +256,17 @@ int16_t LR2021::setPreambleLength(size_t preambleLength) { if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) { this->preambleLengthLoRa = preambleLength; return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); - } + + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + this->preambleLengthGFSK = preambleLength; + this->preambleDetLength = (preambleLength / 8) << 3; + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { + this->preambleLengthGFSK = preambleLength / 4; + return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH)); - //! \TODO: [LR2021] implement other modems + } return(RADIOLIB_ERR_WRONG_MODEM); } @@ -317,15 +334,36 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) { // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion this->crcTypeLoRa = len > 0 ? RADIOLIB_LR2021_LORA_CRC_ENABLED : RADIOLIB_LR2021_LORA_CRC_DISABLED; - state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled); - } + return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); - //! \TODO: [LR2021] implement other modems - (void)initial; - (void)polynomial; - (void)inverted; + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + if(len > 4) { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } - return(state); + this->crcTypeGFSK = len; + if(inverted) { + this->crcTypeGFSK += 0x08; + } + + this->crcLenGFSK = len; + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + return(setGfskCrcParams(initial, polynomial)); + + + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + if((len == 1) || (len > 4)) { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + + this->crcLenGFSK = len; + return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH)); + + } + + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t LR2021::invertIQ(bool enable) { @@ -341,4 +379,391 @@ int16_t LR2021::invertIQ(bool enable) { return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); } +int16_t LR2021::setBitRate(float br) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + //! \TODO: [LR2021] implement fractional bit rate configuration + this->bitRate = br * 1000.0f; + state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + return(state); + + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { + if((uint16_t)br == 260) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_260; + } else if((uint16_t)br == 325) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_325; + } else if((uint16_t)br == 520) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_520; + } else if((uint16_t)br == 650) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_650; + } else if((uint16_t)br == 1040) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1040; + } else if((uint16_t)br == 1300) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1300; + } else if((uint16_t)br == 2080) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2080; + } else if((uint16_t)br == 2600) { + this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2600; + } else { + return(RADIOLIB_ERR_INVALID_BIT_RATE); + } + + // update modulation parameters + return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape)); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t LR2021::setFrequencyDeviation(float freqDev) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set frequency deviation to lowest available setting (required for digimodes) + float newFreqDev = freqDev; + if(freqDev < 0.0f) { + newFreqDev = 0.6f; + } + + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + this->frequencyDev = newFreqDev * 1000.0f; + state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + return(state); +} + +int16_t LR2021::setRxBandwidth(float rxBw) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check allowed receiver bandwidth values + if(fabsf(rxBw - 4.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8; + } else if(fabsf(rxBw - 5.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8; + } else if(fabsf(rxBw - 7.4f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4; + } else if(fabsf(rxBw - 9.7f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7; + } else if(fabsf(rxBw - 12.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0; + } else if(fabsf(rxBw - 14.9f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9; + } else if(fabsf(rxBw - 19.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2; + } else if(fabsf(rxBw - 23.1f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1; + } else if(fabsf(rxBw - 29.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8; + } else if(fabsf(rxBw - 38.5f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5; + } else if(fabsf(rxBw - 46.3f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3; + } else if(fabsf(rxBw - 59.5f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5; + } else if(fabsf(rxBw - 76.9f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9; + } else if(fabsf(rxBw - 92.6f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6; + } else if(fabsf(rxBw - 119.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0; + } else if(fabsf(rxBw - 153.8f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8; + } else if(fabsf(rxBw - 185.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2; + } else if(fabsf(rxBw - 238.1f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1; + } else if(fabsf(rxBw - 307.7f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7; + } else if(fabsf(rxBw - 370.4f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4; + } else if(fabsf(rxBw - 476.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2; + } else if(fabsf(rxBw - 555.6f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6; + } else if(fabsf(rxBw - 666.7f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7; + } else if(fabsf(rxBw - 769.2f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2; + } else if(fabsf(rxBw - 1111.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111; + } else if(fabsf(rxBw - 2222.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222; + } else if(fabsf(rxBw - 2666.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666; + } else if(fabsf(rxBw - 3076.0f) <= 0.001f) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076; + } else { + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); + } + + // update modulation parameters + state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + return(state); +} + +int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) { + if((!syncWord) || (!len) || (len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + + uint32_t sync = 0; + switch(type) { + case(RADIOLIB_LR2021_PACKET_TYPE_GFSK): + // update sync word length + this->syncWordLength = len*8; + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // default to MSB-first + return(setGfskSyncword(const_cast(syncWord), len, true)); + + case(RADIOLIB_LR2021_PACKET_TYPE_LORA): + // with length set to 1 and LoRa modem active, assume it is the LoRa sync word + if(len > 1) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + return(setSyncWord(syncWord[0])); + + case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS): + // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word + if(len != sizeof(uint32_t)) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + memcpy(&sync, syncWord, sizeof(uint32_t)); + return(lrFhssSetSyncword(sync)); + + case(RADIOLIB_LR2021_PACKET_TYPE_FLRC): + // FLRC requires 16 or 32-bit sync word + if(!((len == 0) || (len == 2) || (len == 4))) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + + // update sync word length + this->syncWordLength = len*8; + state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + memcpy(&sync, syncWord, sizeof(uint32_t)); + return(setFlrcSyncWord(1, sync)); + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + +int16_t LR2021::setDataShaping(uint8_t sh) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || (type == RADIOLIB_LR2021_PACKET_TYPE_FLRC))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE; + break; + case RADIOLIB_SHAPING_0_3: + this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3; + break; + case RADIOLIB_SHAPING_0_5: + this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5; + break; + case RADIOLIB_SHAPING_0_7: + this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7; + break; + case RADIOLIB_SHAPING_1_0: + this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0; + break; + default: + return(RADIOLIB_ERR_INVALID_DATA_SHAPING); + } + + // update modulation parameters + if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { + return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape)); + } + return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); +} + +int16_t LR2021::setEncoding(uint8_t encoding) { + return(setWhitening(encoding)); +} + +int16_t LR2021::fixedPacketLengthMode(uint8_t len) { + return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, len)); +} + +int16_t LR2021::variablePacketLengthMode(uint8_t maxLen) { + return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT, maxLen)); +} + +int16_t LR2021::setWhitening(bool enabled, uint16_t initial) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + this->whitening = (uint8_t)enabled; + if(enabled) { + // enable whitening + //! \TODO: [LR2021] Implement SX128x-compatible whitening + this->whitening = RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX; + + // write initial whitening value + state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial); + RADIOLIB_ASSERT(state); + } + + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); +} + +int16_t LR2021::setDataRate(DataRate_t dr, ModemType_t modem ) { + // get the current modem + ModemType_t currentModem; + int16_t state = this->getModem(¤tModem); + RADIOLIB_ASSERT(state); + + // switch over if the requested modem is different + if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) { + state = this->standby(); + RADIOLIB_ASSERT(state); + state = this->setModem(modem); + RADIOLIB_ASSERT(state); + } + + if(modem == RADIOLIB_MODEM_NONE) { + modem = currentModem; + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { + // set the bit rate + state = this->setBitRate(dr.fsk.bitRate); + RADIOLIB_ASSERT(state); + + // set the frequency deviation + state = this->setFrequencyDeviation(dr.fsk.freqDev); + + } else if(modem == RADIOLIB_MODEM_LORA) { + // set the spreading factor + state = this->setSpreadingFactor(dr.lora.spreadingFactor); + RADIOLIB_ASSERT(state); + + // set the bandwidth + state = this->setBandwidth(dr.lora.bandwidth); + RADIOLIB_ASSERT(state); + + // set the coding rate + state = this->setCodingRate(dr.lora.codingRate); + + } else if(modem == RADIOLIB_MODEM_LRFHSS) { + // set the basic config + state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr); + RADIOLIB_ASSERT(state); + + // set hopping grid + this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC; + + } + + return(state); +} + +int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_MODEM_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + +int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // check and cache all parameters + RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE); + this->lrFhssCr = cr; + RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH); + this->lrFhssBw = bw; + RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE); + this->lrFhssHdrCount = hdrCount; + RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING); + this->lrFhssHopSeq = hopSeed; + return(RADIOLIB_ERR_NONE); +} + +int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + // set requested packet mode + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetType = mode; + return(state); + + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { + state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, mode == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, len); + RADIOLIB_ASSERT(state); + + this->packetType = mode; + return(state); + + } + + return(RADIOLIB_ERR_WRONG_MODEM); +} + #endif \ No newline at end of file From 72324be3faede3af7109d006066dd7bfa18e5a06 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 23 Jan 2026 20:40:09 +0000 Subject: [PATCH 1738/1848] [LR2021] Add missing initialization --- src/modules/LR2021/LR2021.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 335fc0ad69..466a03d1f6 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -537,8 +537,8 @@ class LR2021: public LRxxxx { bool highFreq = false; // cached FLRC parameters - uint16_t bitRateFlrc; - uint8_t codingRateFlrc; + uint16_t = 0; + uint8_t codingRateFlrc = 0; int16_t modSetup(float freq, float tcxoVoltage, uint8_t modem); bool findChip(void); From d230f3f5eff08822ee55933c5a9853ef38cbadae Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 23 Jan 2026 20:40:25 +0000 Subject: [PATCH 1739/1848] [LR2021] Fix typo --- src/modules/LR2021/LR2021.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 466a03d1f6..c92968bc57 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -537,7 +537,7 @@ class LR2021: public LRxxxx { bool highFreq = false; // cached FLRC parameters - uint16_t = 0; + uint16_t bitRateFlrc = 0; uint8_t codingRateFlrc = 0; int16_t modSetup(float freq, float tcxoVoltage, uint8_t modem); From c46381b94a19fddc5085d389f6bff19abecb140b Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 24 Jan 2026 16:12:57 +0300 Subject: [PATCH 1740/1848] [LR2021] set implicit or explicit LoRa header type (#1678) * [LR2021] set implicit or explicit LoRa header type * [LR2021] use LoRa in method's name * [LR2021] use of LR2021_config.cpp ; GFSK address filter --- src/modules/LR2021/LR2021.h | 37 ++++++++++++- src/modules/LR2021/LR2021_config.cpp | 78 ++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index c92968bc57..19c05c9f82 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -392,6 +392,27 @@ class LR2021: public LRxxxx { */ int16_t setSyncWord(uint8_t* syncWord, size_t len) override; + /*! + \brief Sets node address. Calling this method will also enable address filtering for node address only. + \param nodeAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setNodeAddress(uint8_t nodeAddr); + + /*! + \brief Sets broadcast address. Calling this method will also enable address + filtering for node and broadcast address. + \param broadAddr Node address to be set. + \returns \ref status_codes + */ + int16_t setBroadcastAddress(uint8_t broadAddr); + + /*! + \brief Disables address filtering. Calling this method will also erase previously set addresses. + \returns \ref status_codes + */ + int16_t disableAddressFiltering(); + /*! \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. @@ -519,7 +540,20 @@ class LR2021: public LRxxxx { \returns TRNG byte. */ uint8_t randomByte() override; - + + /*! + \brief Set implicit header mode for future reception/transmission. + \param len Payload length in bytes. + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + \returns \ref status_codes + */ + int16_t explicitHeader(); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -624,6 +658,7 @@ class LR2021: public LRxxxx { int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops); int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum); int16_t setLoRaSideDetCad(const uint8_t* pnrDelta, const uint8_t* detPeak, size_t numSideDets); + int16_t setLoRaHeaderType(uint8_t hdrType, size_t len = 0xFF); // ranging commands int16_t setRangingAddr(uint32_t addr, uint8_t checkLen); diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index e8f7f2f083..453bea8ccb 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -766,4 +766,82 @@ int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { return(RADIOLIB_ERR_WRONG_MODEM); } +int16_t LR2021::setLoRaHeaderType(uint8_t hdrType, size_t len) { + uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&modem); + RADIOLIB_ASSERT(state); + if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // set requested packet mode + state = setLoRaPacketParams(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled); + RADIOLIB_ASSERT(state); + + // update cached value + this->headerType = hdrType; + this->implicitLen = len; + + return(state); +} + +int16_t LR2021::implicitHeader(size_t len) { + return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_IMPLICIT, len)); +} + +int16_t LR2021::explicitHeader() { + return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_EXPLICIT)); +} + +int16_t LR2021::setNodeAddress(uint8_t nodeAddr) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node only) + this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE; + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // set node address + this->node = nodeAddr; + return(setGfskAddress(this->node, 0)); +} + +int16_t LR2021::setBroadcastAddress(uint8_t broadAddr) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // enable address filtering (node and broadcast) + this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST; + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // set node and broadcast address + return(setGfskAddress(this->node, broadAddr)); +} + +int16_t LR2021::disableAddressFiltering() { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + // disable address filterin + this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED; + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); +} + #endif \ No newline at end of file From e9ab31b7fe3a3d3b2624931934b37059fd36142f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 14:34:02 +0000 Subject: [PATCH 1741/1848] [LR2021] Add support for OOK modem --- keywords.txt | 4 + src/modules/LR2021/LR2021.cpp | 54 +++++++++++- src/modules/LR2021/LR2021.h | 35 +++++++- src/modules/LR2021/LR2021_cmds_ook.cpp | 8 ++ src/modules/LR2021/LR2021_config.cpp | 114 +++++++++++++++++++------ 5 files changed, 180 insertions(+), 35 deletions(-) diff --git a/keywords.txt b/keywords.txt index 5ee1b44491..2d6a67a953 100644 --- a/keywords.txt +++ b/keywords.txt @@ -17,6 +17,7 @@ LLCC68 KEYWORD1 LR1110 KEYWORD1 LR1120 KEYWORD1 LR1121 KEYWORD1 +LR2021 KEYWORD1 nRF24 KEYWORD1 RF69 KEYWORD1 RFM22 KEYWORD1 @@ -280,6 +281,9 @@ updateGnssAlmanac KEYWORD2 getGnssPosition KEYWORD2 getGnssSatellites KEYWORD2 +# LR2021 +beginOOK KEYWORD2 + # RTTY idle KEYWORD2 byteArr KEYWORD2 diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index c143430583..5be59c7893 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -93,6 +93,44 @@ int16_t LR2021::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_ state = setCRC(2); return(state); } + +int16_t LR2021::beginOOK(float freq, float br, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) { + this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8; + + // set module properties and perform initial setup + int16_t state = this->modSetup(freq, tcxoVoltage, RADIOLIB_LR2021_PACKET_TYPE_OOK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x12, 0xAD }; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + state = setCRC(2); + return(state); +} int16_t LR2021::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage) { // set module properties and perform initial setup @@ -188,7 +226,8 @@ int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) { } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) || - (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC)) { + (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) || + (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) { // calculate timeout (500% of expected time-on-air) timeout = timeout * 5; @@ -233,7 +272,8 @@ int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) { RADIOLIB_ASSERT(state); if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || - (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC)) { + (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) || + (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) { // calculate timeout (500 % of expected time-one-air) size_t maxLen = len; if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; } @@ -410,7 +450,9 @@ int16_t LR2021::readData(uint8_t* data, size_t len) { state = getPacketType(&modem); RADIOLIB_ASSERT(state); if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && - (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK)) { + (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) && + (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) && + (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -727,7 +769,8 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { RADIOLIB_ASSERT(state); if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) && - (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC)) { + (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) && + (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -778,6 +821,9 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, cfg->transmit.len); diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 19c05c9f82..10461f0180 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -56,7 +56,7 @@ class LR2021: public LRxxxx { \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. - To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + To use XTAL, either set this value to 0, or set LR2021::XTAL to true. \returns \ref status_codes */ int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6); @@ -71,11 +71,25 @@ class LR2021: public LRxxxx { \param preambleLength FSK preamble length in bits. Defaults to 16 bits. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. - To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + To use XTAL, either set this value to 0, or set LR2021::XTAL to true. \returns \ref status_codes */ int16_t beginGFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 153.8, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6); + /*! + \brief Initialization method for OOK modem. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + \param br OOK bit rate in kbps. Defaults to 4.8 kbps. + \param rxBw Receiver bandwidth in kHz. Defaults to 153.8 kHz. + \param power Output power in dBm. Defaults to 10 dBm. + \param preambleLength OOK preamble length in bits. Defaults to 16 bits. + \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. + If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. + To use XTAL, either set this value to 0, or set LR2021::XTAL to true. + \returns \ref status_codes + */ + int16_t beginOOK(float freq = 434.0, float br = 4.8, float rxBw = 153.8, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6); + /*! \brief Initialization method for LR-FHSS modem. \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. @@ -85,7 +99,7 @@ class LR2021: public LRxxxx { \param power Output power in dBm. Defaults to 10 dBm. \param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V. If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL. - To use XTAL, either set this value to 0, or set LR11x0::XTAL to true. + To use XTAL, either set this value to 0, or set LR2021::XTAL to true. \returns \ref status_codes */ int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LRXXXX_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LRXXXX_LR_FHSS_CR_2_3, bool narrowGrid = true, int8_t power = 10, float tcxoVoltage = 1.6); @@ -554,6 +568,18 @@ class LR2021: public LRxxxx { */ int16_t explicitHeader(); + /*! + \brief Set OOK detector properties. The default values are set to allow ADS-B reception. + \param pattern Preamble pattern, should end with 01 or 10 (binary). + \param len Preamble patter length in bits. + \param repeats Number of preamble repeats, maximum of 31. + \param syncRaw Whether the sync word is send raw (unencoded) or encoded. Set to true for encoded sync word. + \param rising Whether the start of frame delimiter edge is rising (true) or falling (false). + \param sofLen Start-of-frame length in bits. + \returns \ref status_codes + */ + int16_t ookDetector(uint16_t pattern = 0x0285, uint8_t len = 10, uint8_t repeats = 0, bool syncRaw = false, bool rising = false, uint8_t sofLen = 0); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -658,7 +684,7 @@ class LR2021: public LRxxxx { int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops); int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum); int16_t setLoRaSideDetCad(const uint8_t* pnrDelta, const uint8_t* detPeak, size_t numSideDets); - int16_t setLoRaHeaderType(uint8_t hdrType, size_t len = 0xFF); + int16_t setLoRaHeaderType(uint8_t hdrType, size_t len = RADIOLIB_LR2021_MAX_PACKET_LENGTH); // ranging commands int16_t setRangingAddr(uint32_t addr, uint8_t checkLen); @@ -711,6 +737,7 @@ class LR2021: public LRxxxx { int16_t getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError); int16_t getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); int16_t setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uint8_t patternNumRepeaters, bool syncWordRaw, bool sofDelimiterRising, uint8_t sofDelimiterLen); + int16_t setOokWhiteningParams(uint8_t bitIdx, uint16_t poly, uint16_t init); // test commands int16_t setTxTestMode(uint8_t mode); diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 0c7becbb19..1b0406f8cb 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -89,4 +89,12 @@ int16_t LR2021::setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uin return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_DETECTOR, true, buff, sizeof(buff))); } +int16_t LR2021::setOokWhiteningParams(uint8_t bitIdx, uint16_t poly, uint16_t init) { + uint8_t buff[] = { + (uint8_t)((bitIdx << 4) | ((poly >> 8) & 0x0FF)), (uint8_t)(poly & 0xFF), + (uint8_t)((init >> 8) & 0xFF), (uint8_t)(init & 0xFF), + }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_WHITENING_PARAMS, true, buff, sizeof(buff))); +} + #endif diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 453bea8ccb..19b0d3ab89 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -262,6 +262,11 @@ int16_t LR2021::setPreambleLength(size_t preambleLength) { this->preambleDetLength = (preambleLength / 8) << 3; return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + this->preambleLengthGFSK = preambleLength; + this->preambleDetLength = (preambleLength / 8) << 3; + return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { this->preambleLengthGFSK = preambleLength / 4; return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH)); @@ -346,14 +351,27 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool this->crcTypeGFSK += 0x08; } - this->crcLenGFSK = len; state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); return(setGfskCrcParams(initial, polynomial)); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + if(len > 4) { + return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); + } + + this->crcTypeGFSK = len; + if(inverted) { + this->crcTypeGFSK += 0x08; + } + + state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + return(setOokCrcParams(initial, polynomial)); - } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { if((len == 1) || (len > 4)) { return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } @@ -390,6 +408,14 @@ int16_t LR2021::setBitRate(float br) { this->bitRate = br * 1000.0f; state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); return(state); + + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + //! \TODO: [LR2021] implement fractional bit rate configuration + this->bitRate = br * 1000.0f; + //! \TODO: [LR2021] implement OOK magnitude depth configuration + state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL); + return(state); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { if((uint16_t)br == 260) { @@ -445,7 +471,8 @@ int16_t LR2021::setRxBandwidth(float rxBw) { uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || + (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) { return(RADIOLIB_ERR_WRONG_MODEM); } @@ -511,7 +538,11 @@ int16_t LR2021::setRxBandwidth(float rxBw) { } // update modulation parameters - state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); + } else { + state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL); + } return(state); } @@ -528,14 +559,13 @@ int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) { uint32_t sync = 0; switch(type) { case(RADIOLIB_LR2021_PACKET_TYPE_GFSK): - // update sync word length - this->syncWordLength = len*8; - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); - RADIOLIB_ASSERT(state); - // default to MSB-first return(setGfskSyncword(const_cast(syncWord), len, true)); + case(RADIOLIB_LR2021_PACKET_TYPE_OOK): + // default to MSB-first + return(setOokSyncword(const_cast(syncWord), len, true)); + case(RADIOLIB_LR2021_PACKET_TYPE_LORA): // with length set to 1 and LoRa modem active, assume it is the LoRa sync word if(len > 1) { @@ -574,9 +604,6 @@ int16_t LR2021::setDataShaping(uint8_t sh) { uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || (type == RADIOLIB_LR2021_PACKET_TYPE_FLRC))) { - return(RADIOLIB_ERR_WRONG_MODEM); - } // set data shaping switch(sh) { @@ -602,8 +629,12 @@ int16_t LR2021::setDataShaping(uint8_t sh) { // update modulation parameters if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape)); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { + return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + return(setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL)); } - return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev)); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t LR2021::setEncoding(uint8_t encoding) { @@ -623,22 +654,30 @@ int16_t LR2021::setWhitening(bool enabled, uint16_t initial) { uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); - if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - this->whitening = (uint8_t)enabled; - if(enabled) { - // enable whitening - //! \TODO: [LR2021] Implement SX128x-compatible whitening - this->whitening = RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX; - - // write initial whitening value - state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial); - RADIOLIB_ASSERT(state); + + switch(type) { + case(RADIOLIB_LR2021_PACKET_TYPE_GFSK): + //! \TODO: [LR2021] Implement SX128x-compatible whitening + if(enabled) { + state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial); + RADIOLIB_ASSERT(state); + } + this->whitening = enabled; + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + + case(RADIOLIB_LR2021_PACKET_TYPE_OOK): + this->whitening = enabled; + if(enabled) { + //! \TODO: [LR2021] Implement configurable index and polynomial + state = setOokWhiteningParams(12, 0x01FF, initial); + } else { + state = setOokWhiteningParams(0, 0, 0); + } + RADIOLIB_ASSERT(state); + return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } - return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + return(RADIOLIB_ERR_WRONG_MODEM); } int16_t LR2021::setDataRate(DataRate_t dr, ModemType_t modem ) { @@ -754,6 +793,15 @@ int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { this->packetType = mode; return(state); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + // set requested packet mode + state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); + RADIOLIB_ASSERT(state); + + // update cached value + this->packetType = mode; + return(state); + } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, mode == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, len); RADIOLIB_ASSERT(state); @@ -844,4 +892,16 @@ int16_t LR2021::disableAddressFiltering() { return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } +int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool syncRaw, bool rising, uint8_t sofLen) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_OOK) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen)); +} + #endif \ No newline at end of file From 593ac68978192e4ce4f4aa7f7d2541ccef9ecc6f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 15:51:47 +0000 Subject: [PATCH 1742/1848] [LR2021] Add support for multi-SF reception --- keywords.txt | 6 +++ src/TypeDef.h | 5 ++ src/modules/LR2021/LR2021.h | 16 ++++++ src/modules/LR2021/LR2021_config.cpp | 71 +++++++++++++++++++++++++++ src/modules/LR2021/LR2021_registers.h | 1 + src/modules/LR2021/LR2021_types.h | 18 +++++++ 6 files changed, 117 insertions(+) diff --git a/keywords.txt b/keywords.txt index 2d6a67a953..3afa875ef4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -106,6 +106,9 @@ LR11x0GnssSatellite_t KEYWORD1 LR11x0GnssAlmanacStatusPart_t KEYWORD1 LR11x0GnssAlmanacStatus_t KEYWORD1 +# LR2021 structures +LR2021LoRaSideDetector_t + ####################################### # Methods and Functions (KEYWORD2) ####################################### @@ -532,3 +535,6 @@ RADIOLIB_LR1120_FIRMWARE_0102 LITERAL1 RADIOLIB_LR1120_FIRMWARE_0201 LITERAL1 RADIOLIB_LR1121_FIRMWARE_0102 LITERAL1 RADIOLIB_LR1121_FIRMWARE_0103 LITERAL1 + +RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED LITERAL1 +RADIOLIB_ERR_INVALID_SIDE_DETECT LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index efc05f3273..c27e148c5e 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -637,6 +637,11 @@ */ #define RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED (-1300) +/*! + \brief Multi-SF side detector configuration is invalid. +*/ +#define RADIOLIB_ERR_INVALID_SIDE_DETECT (-1301) + /*! \} */ diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 10461f0180..fa055e2efe 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -580,6 +580,22 @@ class LR2021: public LRxxxx { */ int16_t ookDetector(uint16_t pattern = 0x0285, uint8_t len = 10, uint8_t repeats = 0, bool syncRaw = false, bool rising = false, uint8_t sofLen = 0); + /*! + \brief Configure LoRa side detector, which enables to detect mutiple spreading factors and receive one of them. + The following limitations apply: + * In Rx mode, all side-detector spreading factors must be higher than the primary one (configured via begin or setSpreadingFactor) + * For CAD mode, the above condition is inverted - all side-detector spreading factors must be smaller + * All packets to be detected must have the same header type (implicit or explicit) + * If bandwidth is higher than 500 kHz, at most 2 side detectors are allowed. + * If the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed. + * All spreading factors must be different. + * The diference between maximum and minimum spreading factor used must be less than or equal to 4. + \param cfg Pointer to an array of side detector configuration structures. Set to null to disable all side detectors. + \param numDetectors Number of side detectors to configure. Maximum of 3, set to 0 to to disable all side detectors. + \returns \ref status_codes + */ + int16_t setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 19b0d3ab89..f7f0118a27 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -904,4 +904,75 @@ int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen)); } +int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors) { + // some basic sanity checks + if((cfg == nullptr) || (numDetectors == 0)) { + return(RADIOLIB_ERR_NONE); + } + + if(((cfg == nullptr) && (numDetectors > 0)) || (numDetectors > 3)) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + + // if bandwidth is higher than 500 kHz, at most 2 side detectors are allowed + if((this->bandwidthKhz > 500.0f) && (numDetectors > 2)) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + + // if the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed + if((this->spreadingFactor >= 10) && (numDetectors > 2)) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + + // condition of the primary spreading factor being the smallest/largest is not checked + // this is intentional, because it depends on whether the user wants to start Rx or CAD + + uint8_t detectors[3] = { 0 }; + uint8_t syncWords[3] = { 0 }; + uint8_t minSf = this->spreadingFactor; + for(size_t i = 0; i < numDetectors; i++) { + // all side-detector spreading factors must be higher than the primary one + //! \todo [LR2021] implement multi-SF for CAD (main SF must be smallest!) + if(this->spreadingFactor >= cfg[i].sf) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + + // the diference between maximum and minimum spreading factor used must be less than or equal to 4 + if(cfg[i].sf - minSf > 4) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + + if(cfg[i].sf < minSf) { minSf = cfg[i].sf; } + + detectors[i] = cfg[i].sf << 4 | cfg[i].ldro << 2 | cfg[i].invertIQ; + syncWords[i] = cfg[i].syncWord; + } + + // all spreading factors must be different + if(numDetectors >= 2) { + if(cfg[0].sf == cfg[1].sf) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + } + + if(numDetectors == 3) { + if((cfg[1].sf == cfg[2].sf) || (cfg[0].sf == cfg[2].sf)) { + return(RADIOLIB_ERR_INVALID_SIDE_DETECT); + } + } + + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + state = setLoRaSideDetConfig(detectors, numDetectors); + RADIOLIB_ASSERT(state); + + return(setLoRaSideDetSyncword(syncWords, numDetectors)); +} + #endif \ No newline at end of file diff --git a/src/modules/LR2021/LR2021_registers.h b/src/modules/LR2021/LR2021_registers.h index 06ea739f13..c39a01acf6 100644 --- a/src/modules/LR2021/LR2021_registers.h +++ b/src/modules/LR2021/LR2021_registers.h @@ -14,6 +14,7 @@ #define RADIOLIB_LR2021_REG_RTTOF_RSSI_MAX_GAIN (0xF301A4) #define RADIOLIB_LR2021_REG_LORA_MODEM_TXRX_CFG0 (0xF30A14) #define RADIOLIB_LR2021_REG_LORA_MODEM_MAIN_TX_CFG1 (0xF30A24) +#define RADIOLIB_LR2021_REG_LORA_EXT_FREQ_ERR_CTRL (0xF30A2C) #define RADIOLIB_LR2021_REG_RTTOF_EXTENDED_STUCK (0xF30B50) #define RADIOLIB_LR2021_REG_BLE_PHY_CODED_FREQ_DRIFT (0xF30C28) #define RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD (0xF30E14) diff --git a/src/modules/LR2021/LR2021_types.h b/src/modules/LR2021/LR2021_types.h index 1097047ddb..c04aee3ecd 100644 --- a/src/modules/LR2021/LR2021_types.h +++ b/src/modules/LR2021/LR2021_types.h @@ -19,6 +19,24 @@ struct LR2021LrFhssHopTableEntry_t { uint16_t numSymbols; }; +/*! + \struct LR2021LoRaSideDetector_t + \brief Structure to configure multi-SF detection +*/ +struct LR2021LoRaSideDetector_t { + /*! \brief Spreading factor value */ + uint8_t sf; + + /*! \brief Low datarate optimization enabled for this detector */ + bool ldro; + + /*! \brief IQ inversion for this detector */ + bool invertIQ; + + /*! \brief LoRa sync word for this detector */ + uint8_t syncWord; +}; + #endif #endif From d1685695d6dce2ef0c29726b80df5a873f190dae Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 16:32:02 +0000 Subject: [PATCH 1743/1848] [LR2021] Fix logic error in multiSF config --- src/modules/LR2021/LR2021_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index f7f0118a27..67473c62d9 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -910,7 +910,7 @@ int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numD return(RADIOLIB_ERR_NONE); } - if(((cfg == nullptr) && (numDetectors > 0)) || (numDetectors > 3)) { + if(numDetectors > 3) { return(RADIOLIB_ERR_INVALID_SIDE_DETECT); } From d4dc68ae1be22d22453fb0cae80005aae75f4a35 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 18:39:54 +0100 Subject: [PATCH 1744/1848] [LR2021] Add basic examples --- ...21_Channel_Activity_Detection_Blocking.ino | 77 +++++++++ ...1_Channel_Activity_Detection_Interrupt.ino | 112 +++++++++++++ .../LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino | 150 ++++++++++++++++++ .../LR2021_LR_FHSS_Modem.ino | 96 +++++++++++ .../LR2021_PingPong/LR2021_PingPong.ino | 150 ++++++++++++++++++ .../LR2021_Receive_Blocking.ino | 106 +++++++++++++ .../LR2021_Receive_Interrupt.ino | 140 ++++++++++++++++ .../LR2021_Transmit_Blocking.ino | 92 +++++++++++ .../LR2021_Transmit_Interrupt.ino | 133 ++++++++++++++++ 9 files changed, 1056 insertions(+) create mode 100644 examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino create mode 100644 examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino create mode 100644 examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino create mode 100644 examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino create mode 100644 examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino create mode 100644 examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino create mode 100644 examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino create mode 100644 examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino create mode 100644 examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino diff --git a/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino b/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino new file mode 100644 index 0000000000..47151778ff --- /dev/null +++ b/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino @@ -0,0 +1,77 @@ +/* + RadioLib LR2021 Blocking Channel Activity Detection Example + + This example uses LR2021 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, LR2021 can detect any part + of LoRa transmission, not just the preamble. + + Using blocking CAD is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt CAD is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } +} + +void loop() { + Serial.print(F("[LR2021] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = radio.scanChannel(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino b/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino new file mode 100644 index 0000000000..60715e4210 --- /dev/null +++ b/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino @@ -0,0 +1,112 @@ +/* + RadioLib LR2021 Channel Activity Detection Example + + This example uses LR2021 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + Unlike SX127x CAD, LR2021 can detect any part + of LoRa transmission, not just the preamble. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// flag to indicate that a packet was detected or CAD timed out +volatile bool scanFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // something happened, set the flag + scanFlag = true; +} + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when LoRa packet or timeout is detected + radio.setIrqAction(setFlag); + + // start scanning the channel + Serial.print(F("[LR2021] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } +} + +void loop() { + // check if the flag is set + if(scanFlag) { + // reset flag + scanFlag = false; + + // check CAD result + int state = radio.getChannelScanResult(); + + if (state == RADIOLIB_LORA_DETECTED) { + // LoRa packet was detected + Serial.println(F("[LR2021] Packet detected!")); + + } else if (state == RADIOLIB_CHANNEL_FREE) { + // channel is free + Serial.println(F("[LR2021] Channel is free!")); + + } else { + // some other error occurred + Serial.print(F("[LR2021] Failed, code ")); + Serial.println(state); + + } + + // start scanning the channel again + Serial.print(F("[LR2021] Starting scan for LoRa preamble ... ")); + state = radio.startChannelScan(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + } +} diff --git a/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino b/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino new file mode 100644 index 0000000000..0eee304698 --- /dev/null +++ b/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino @@ -0,0 +1,150 @@ +/* + RadioLib LR2021 GFSK Modem Example + + This example shows how to use GFSK modem in LR2021 chips. + + NOTE: The sketch below is just a guide on how to use + GFSK modem, so this code should not be run directly! + Instead, modify the other examples to use GFSK + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.beginGFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable GFSK) + // radio.beginGFSK() start GFSK modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setBitRate(100.0); + state = radio.setFrequencyDeviation(10.0); + state = radio.setRxBandwidth(250.0); + state = radio.setOutputPower(10.0); + state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.setSyncWord(syncWord, 8); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // GFSK modem allows advanced CRC configuration + // Default is CCITT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted) + // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted) + state = radio.setCRC(2, 0xFFFF, 0x8005, false); + // set CRC length to 0 to disable CRC + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // GFSK modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit GFSK packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR2021] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[LR2021] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[LR2021] Timed out while transmitting!")); + } else { + Serial.println(F("[LR2021] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive GFSK packet + String str; + state = radio.receive(str); + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR2021] Received packet!")); + Serial.print(F("[LR2021] Data:\t")); + Serial.println(str); + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("[LR2021] Timed out while waiting for packet!")); + } else { + Serial.print(F("[LR2021] Failed to receive packet, code ")); + Serial.println(state); + } + + // GFSK modem has built-in address filtering system + // it can be enabled by setting node address, broadcast + // address, or both + // + // to transmit packet to a particular address, + // use the following methods: + // + // radio.transmit("Hello World!", address); + // radio.startTransmit("Hello World!", address); + + // set node address to 0x02 + state = radio.setNodeAddress(0x02); + // set broadcast address to 0xFF + state = radio.setBroadcastAddress(0xFF); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[LR2021] Unable to set address filter, code ")); + Serial.println(state); + } + + // address filtering can also be disabled + // NOTE: calling this method will also erase previously set + // node and broadcast address + /* + state = radio.disableAddressFiltering(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to remove address filter, code ")); + } + */ +} diff --git a/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino b/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino new file mode 100644 index 0000000000..bdd2407f08 --- /dev/null +++ b/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino @@ -0,0 +1,96 @@ +/* + RadioLib LR2021 LR-FHSS Modem Example + + This example shows how to use LR-FHSS modem in LR2021 chips. + This modem can only transmit data, and is not able to receive. + + NOTE: The sketch below is just a guide on how to use + LR-FHSS modem, so this code should not be run directly! + Instead, modify the other examples to use LR-FHSS + modem and use the appropriate configuration + methods. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lr-fhss-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.beginLRFHSS(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // if needed, you can switch between any of the modems + // + // radio.begin() start LoRa modem (and disable LR-FHSS) + // radio.beginLRFHSS() start LR-FHSS modem (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = radio.setFrequency(433.5); + state = radio.setLrFhssConfig(RADIOLIB_LRXXXX_LR_FHSS_BW_1523_4, // bandwidth + RADIOLIB_LRXXXX_LR_FHSS_CR_1_2, // coding rate + 3, // header count + 0x13A); // hopping sequence seed + state = radio.setOutputPower(10.0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + state = radio.setSyncWord(syncWord, 4); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // LR-FHSS modem can only transmit! + // transmit LR-FHSS packet + int state = radio.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[LR2021] Packet transmitted successfully!")); + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + Serial.println(F("[LR2021] Packet too long!")); + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + Serial.println(F("[LR2021] Timed out while transmitting!")); + } else { + Serial.println(F("[LR2021] Failed to transmit packet, code ")); + Serial.println(state); + } + +} diff --git a/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino b/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino new file mode 100644 index 0000000000..f8e6e89ce6 --- /dev/null +++ b/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino @@ -0,0 +1,150 @@ +/* + RadioLib LR2021 Ping-Pong Example + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// uncomment the following only on one +// of the nodes to initiate the pings +//#define INITIATING_NODE + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// save transmission states between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// flag to indicate transmission or reception state +bool transmitFlag = false; + +// flag to indicate that a packet was sent or received +volatile bool operationDone = false; + +// this function is called when a complete packet +// is transmitted or received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent or received a packet, set the flag + operationDone = true; +} + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when new packet is received + radio.setIrqAction(setFlag); + + #if defined(INITIATING_NODE) + // send the first packet on this node + Serial.print(F("[LR2021] Sending first packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + #else + // start listening for LoRa packets on this node + Serial.print(F("[LR2021] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + #endif +} + +void loop() { + // check if the previous operation finished + if(operationDone) { + // reset flag + operationDone = false; + + if(transmitFlag) { + // the previous operation was transmission, listen for response + // print the result + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // listen for response + radio.startReceive(); + transmitFlag = false; + + } else { + // the previous operation was reception + // print data and send another packet + String str; + int state = radio.readData(str); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[LR2021] Received packet!")); + + // print data of the packet + Serial.print(F("[LR2021] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LR2021] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LR2021] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[LR2021] Sending another packet ... ")); + transmissionState = radio.startTransmit("Hello World!"); + transmitFlag = true; + } + + } +} diff --git a/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino b/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino new file mode 100644 index 0000000000..93fc9c5e36 --- /dev/null +++ b/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino @@ -0,0 +1,106 @@ +/* + RadioLib LR2021 Blocking Receive Example + + This example listens for LoRa transmissions using LR2021 Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Using blocking receive is not recommended, as it will lead + to significant amount of timeouts, inefficient use of processor + time and can some miss packets! + Instead, interrupt receive is recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } +} + +void loop() { + Serial.print(F("[LR2021] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = radio.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = radio.receive(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[LR2021] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[LR2021] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[LR2021] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino b/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino new file mode 100644 index 0000000000..a5419e347f --- /dev/null +++ b/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino @@ -0,0 +1,140 @@ +/* + RadioLib LR2021 Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[LR2021] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.scanChannel(); +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[LR2021] Received packet!")); + + // print data of the packet + Serial.print(F("[LR2021] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LR2021] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LR2021] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} diff --git a/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino b/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino new file mode 100644 index 0000000000..72fbd27dc7 --- /dev/null +++ b/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino @@ -0,0 +1,92 @@ +/* + RadioLib LR2021 Blocking Transmit Example + + This example transmits packets using LR2021 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + delay(1000); + while (true) { delay(10); } + } +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + Serial.print(F("[LR2021] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + // NOTE: transmit() is a blocking method! + // See example LR11x0_Transmit_Interrupt for details + // on non-blocking transmission method. + String str = "Hello World! #" + String(count++); + int state = radio.transmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = radio.transmit(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else if (state == RADIOLIB_ERR_TX_TIMEOUT) { + // timeout occurred while transmitting packet + Serial.println(F("timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino new file mode 100644 index 0000000000..20f2cac65f --- /dev/null +++ b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino @@ -0,0 +1,133 @@ +/* + RadioLib LR2021 Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we sent a packet, set the flag + transmittedFlag = true; +} + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when packet transmission is finished + radio.setPacketSentAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[LR2021] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = radio.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = radio.startTransmit(byteArr, 8); + */ +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[LR2021] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + String str = "Hello World! #" + String(count++); + transmissionState = radio.startTransmit(str); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + transmissionState = radio.startTransmit(byteArr, 8); + */ + } +} From 98d785a9f1cff5eee6f5223bb4d453148c0bc2ec Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 19:01:52 +0100 Subject: [PATCH 1745/1848] [LR2021] Fix typos --- src/modules/LR2021/LR2021.cpp | 2 +- src/modules/LR2021/LR2021.h | 8 ++++---- src/modules/LR2021/LR2021_commands.h | 2 +- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 5be59c7893..2d22114e2d 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -924,7 +924,7 @@ float LR2021::getRSSI(bool packet) { float rssi = 0; int16_t state; if(!packet) { - // get instantenous RSSI value + // get instantaneous RSSI value state = this->getRssiInst(&rssi); if(state != RADIOLIB_ERR_NONE) { return(0); } return(rssi); diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index fa055e2efe..674bb71214 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -362,9 +362,9 @@ class LR2021: public LRxxxx { /*! \brief Sets CRC configuration. \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC. - \param initial Initial CRC value. GFSK only. Defaults to 0x1D0F (CCIT CRC). - \param polynomial Polynomial for CRC calculation. GFSK only. Defaults to 0x1021 (CCIT CRC). - \param inverted Invert CRC bytes. GFSK only. Defaults to true (CCIT CRC). + \param initial Initial CRC value. GFSK only. Defaults to 0x1D0F (CCITT CRC). + \param polynomial Polynomial for CRC calculation. GFSK only. Defaults to 0x1021 (CCITT CRC). + \param inverted Invert CRC bytes. GFSK only. Defaults to true (CCITT CRC). \returns \ref status_codes */ int16_t setCRC(uint8_t len, uint32_t initial = 0x00001D0FUL, uint32_t polynomial = 0x00001021UL, bool inverted = true); @@ -589,7 +589,7 @@ class LR2021: public LRxxxx { * If bandwidth is higher than 500 kHz, at most 2 side detectors are allowed. * If the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed. * All spreading factors must be different. - * The diference between maximum and minimum spreading factor used must be less than or equal to 4. + * The difference between maximum and minimum spreading factor used must be less than or equal to 4. \param cfg Pointer to an array of side detector configuration structures. Set to null to disable all side detectors. \param numDetectors Number of side detectors to configure. Maximum of 3, set to 0 to to disable all side detectors. \returns \ref status_codes diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index e458939ea6..22003e4fa9 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -247,7 +247,7 @@ #define RADIOLIB_LR2021_TEMP_SOURCE_VBE (0x00UL << 4) // 4 4 temperature source: sensor near Vbe junction #define RADIOLIB_LR2021_TEMP_SOURCE_XOSC (0x01UL << 4) // 4 4 sensor near XOSC #define RADIOLIB_LR2021_TEMP_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw -#define RADIOLIB_LR2021_TEMP_FORMAT_DEG_C (0x01UL << 3) // 3 3 degress Celsius +#define RADIOLIB_LR2021_TEMP_FORMAT_DEG_C (0x01UL << 3) // 3 3 degrees Celsius // RADIOLIB_LR2021_CMD_SET_EOL_CONFIG #define RADIOLIB_LR2021_EOL_TRIM_1V6 (0x00UL << 1) // 3 1 EoL trigger threshold: 1.60 V diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 67473c62d9..dfc5b6fe4c 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -41,7 +41,7 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { getErrors(&errors); RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration #%d failed, device errors: 0x%X", i, errors); - // if this is casued by something else than RSSI saturation, repeating will not help + // if this is caused by something else than RSSI saturation, repeating will not help if((errors & RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR) == 0) { return(state); } @@ -937,7 +937,7 @@ int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numD return(RADIOLIB_ERR_INVALID_SIDE_DETECT); } - // the diference between maximum and minimum spreading factor used must be less than or equal to 4 + // the difference between maximum and minimum spreading factor used must be less than or equal to 4 if(cfg[i].sf - minSf > 4) { return(RADIOLIB_ERR_INVALID_SIDE_DETECT); } From f86497f00f0f6fa5aaeb48289a04820f45887c5b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 19:02:03 +0100 Subject: [PATCH 1746/1848] [LR2021] Add multi-SF example --- .../LR2021_Receive_MultiSF.ino | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino diff --git a/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino b/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino new file mode 100644 index 0000000000..8366dc1f6a --- /dev/null +++ b/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino @@ -0,0 +1,174 @@ +/* + RadioLib LR2021 Receive Multi-SF Example + + This example listens for LoRa transmissions with different + spreading factors and tries to receive them. + Once a packet is received, an interrupt is triggered. + + There are the following limits on configuration of multi-SF + (or side-detect) reception: + * In Rx mode, all side-detector spreading factors must be higher + than the primary one (configured via begin or setSpreadingFactor). + * For CAD mode, the above condition is inverted, + all side-detector spreading factors must be smaller. + * All packets to be detected/received must have the same header type + (implicit or explicit). + * If bandwidth is higher than 500 kHz, + at most 2 side detectors are allowed. + * If the primary spreading factor is 10, 11 or 12, + at most 2 side detectors are allowed. + * All spreading factors must be different. + * The difference between maximum and minimum spreading factor used + must be less than or equal to 4. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void setup() { + Serial.begin(9600); + + // initialize LR2021 with default settings + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.begin(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // prepare array of side detector configuration structures + // for spreading factors 10 - 12 + // as the default spreading factor is 9, this satisfies + // the conditions listed at the top of this example + // this is just an example; you can also set different + // sync words, IQ inversions and low data-rate optimization + // depending on the types of transmitters you expect + const struct LR2021LoRaSideDetector_t sideDet[3] = { + { .sf = 10, .ldro = false, .invertIQ = false, + .syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE }, + { .sf = 11, .ldro = true, .invertIQ = false, + .syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE }, + { .sf = 12, .ldro = true, .invertIQ = false, + .syncWord = RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE }, + }; + Serial.print(F("[LR2021] Setting side detector configuration ... ")); + state = radio.setSideDetector(sideDet, 3); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[LR2021] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.scanChannel(); +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int numBytes = radio.getPacketLength(); + int state = radio.readData(byteArr, numBytes); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[LR2021] Received packet!")); + + // print data of the packet + Serial.print(F("[LR2021] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[LR2021] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[LR2021] SNR:\t\t")); + Serial.print(radio.getSNR()); + Serial.println(F(" dB")); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} From 009eb519d7fd4822cbdd2225b345108fd36b63b0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 19:06:53 +0100 Subject: [PATCH 1747/1848] [LR2021] Fix example links --- .../LR2021_Channel_Activity_Detection_Interrupt.ino | 2 +- examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino | 2 +- examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino | 2 +- examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino | 2 +- .../LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino | 2 +- .../LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino | 2 +- .../LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino | 2 +- .../LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino | 2 +- .../LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino b/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino index 60715e4210..ee77211432 100644 --- a/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino @@ -7,7 +7,7 @@ of LoRa transmission, not just the preamble. For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino b/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino index 0eee304698..b025b3be2e 100644 --- a/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino +++ b/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino @@ -10,7 +10,7 @@ methods. For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---gfsk-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino b/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino index bdd2407f08..237434e76d 100644 --- a/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino +++ b/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino @@ -11,7 +11,7 @@ methods. For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lr-fhss-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lr-fhss-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino b/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino index f8e6e89ce6..1de592171e 100644 --- a/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino +++ b/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino @@ -2,7 +2,7 @@ RadioLib LR2021 Ping-Pong Example For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino b/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino index 93fc9c5e36..18deaf8230 100644 --- a/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino +++ b/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino @@ -17,7 +17,7 @@ Instead, interrupt receive is recommended. For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino b/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino index a5419e347f..952754db2b 100644 --- a/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino +++ b/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino @@ -13,7 +13,7 @@ - sync word For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino b/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino index 8366dc1f6a..570475c2be 100644 --- a/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino +++ b/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino @@ -22,7 +22,7 @@ must be less than or equal to 4. For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino b/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino index 72fbd27dc7..714acddd42 100644 --- a/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino +++ b/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino @@ -8,7 +8,7 @@ - arbitrary binary data (byte array) For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ diff --git a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino index 20f2cac65f..e45f18fe9d 100644 --- a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino +++ b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino @@ -9,7 +9,7 @@ - arbitrary binary data (byte array) For default module settings, see the wiki page - https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem + https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr2021---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ From 9d2122b2bc3b477ad2c0e2953f61a88ea56e0fce Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 19:07:51 +0100 Subject: [PATCH 1748/1848] [LR2021] Update readme and add LR2021 to tags --- README.md | 11 ++++++----- idf_component.yml | 1 + library.json | 2 +- library.properties | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b7cd9e3786..d9d6b5f0bb 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __CC1101__ FSK radio module * __LLCC68__ LoRa module * __LR11x0__ series LoRa/GFSK modules (LR1110, LR1120, LR1121) +* __LR2021__ series LoRa/GFSK/LR-FHSS/FLRC/OOK modules * __nRF24L01__ 2.4 GHz module * __RF69__ FSK/OOK radio module * __RFM2x__ series FSK modules (RFM22, RFM23) @@ -35,21 +36,21 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github ### Supported protocols and digital modes: * [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0 and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0, LR2021 and SX128x * [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0, LR2021 and SX128x * [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0, LR2021 and SX128x * [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules: -SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0, LR2021 and SX128x * [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules: SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * [__LoRaWAN__](https://lora-alliance.org/) using LoRa and FSK for modules: -SX127x, RFM9x, SX126x, LR11x0 and SX128x +SX127x, RFM9x, SX126x, LR11x0, LR2021 and SX128x * Supports Class A and C (and Multicast over C). * Pre-certified for Class A. * See the [wiki](https://github.com/jgromes/RadioLib/wiki/LoRaWAN) and [notes](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for more information. diff --git a/idf_component.yml b/idf_component.yml index 6a6b28f6d0..8ca03b163b 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -33,6 +33,7 @@ tags: - lr1110 - lr1120 - lr1121 + - lr2021 url: "https://github.com/jgromes/RadioLib" repository: "https://github.com/jgromes/RadioLib.git" license: "MIT" diff --git a/library.json b/library.json index 3d4b786285..133537e072 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "7.5.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", - "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121, lr2021", "homepage": "https://github.com/jgromes/RadioLib", "repository": { diff --git a/library.properties b/library.properties index 9306030f91..4f2e0828b3 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=7.5.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library -paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). +paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110, LR2021 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). category=Communication url=https://github.com/jgromes/RadioLib architectures=* From 3ebeabf04e507245d4a140f74cf4e9c0eaf6f618 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 24 Jan 2026 19:11:08 +0100 Subject: [PATCH 1749/1848] [LR2021] Add keywords --- keywords.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index 3afa875ef4..5331a2cdb0 100644 --- a/keywords.txt +++ b/keywords.txt @@ -107,7 +107,7 @@ LR11x0GnssAlmanacStatusPart_t KEYWORD1 LR11x0GnssAlmanacStatus_t KEYWORD1 # LR2021 structures -LR2021LoRaSideDetector_t +LR2021LoRaSideDetector_t KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -286,6 +286,7 @@ getGnssSatellites KEYWORD2 # LR2021 beginOOK KEYWORD2 +setSideDetector KEYWORD2 # RTTY idle KEYWORD2 From c8a3e999a044680065e30b5d6b3fa3f28bed8b60 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 25 Jan 2026 07:02:02 +0000 Subject: [PATCH 1750/1848] [LR2021] Fix typos --- src/modules/LR11x0/LR11x0.cpp | 2 +- src/modules/LR2021/LR2021_config.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 4ecce2d8ea..76453686c3 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -822,7 +822,7 @@ int16_t LR11x0::disableAddressFiltering() { return(RADIOLIB_ERR_WRONG_MODEM); } - // disable address filterin + // disable address filtering this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED; return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index dfc5b6fe4c..7b8a75a3b0 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -887,7 +887,7 @@ int16_t LR2021::disableAddressFiltering() { return(RADIOLIB_ERR_WRONG_MODEM); } - // disable address filterin + // disable address filtering this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED; return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } From 3ba383bf52490c0121cc27ecd1b7130975d08880 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 25 Jan 2026 08:13:29 +0000 Subject: [PATCH 1751/1848] [LR2021] Implement RF switch control --- src/modules/LR11x0/LR11x0.cpp | 2 +- src/modules/LR11x0/LR11x0_commands.h | 12 ++++----- src/modules/LR11x0/LR_common.h | 5 ++++ src/modules/LR2021/LR2021.h | 23 +++++++++++++++++ .../LR2021/LR2021_cmds_chip_control.cpp | 5 ++++ src/modules/LR2021/LR2021_commands.h | 10 ++++++++ src/modules/LR2021/LR2021_config.cpp | 25 +++++++++++++++++++ 7 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 76453686c3..bd03852047 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1237,7 +1237,7 @@ void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], // only keep DIO pins, there may be some GPIOs in the switch tabke if(pins[i] & RFSWITCH_PIN_FLAG) { - enable |= 1UL << RADIOLIB_LR11X0_DIOx_VAL(pins[i]); + enable |= 1UL << RADIOLIB_LRXXXX_DIOx_VAL(pins[i]); } } diff --git a/src/modules/LR11x0/LR11x0_commands.h b/src/modules/LR11x0/LR11x0_commands.h index 93c24fd567..aa4c22f116 100644 --- a/src/modules/LR11x0/LR11x0_commands.h +++ b/src/modules/LR11x0/LR11x0_commands.h @@ -235,13 +235,11 @@ #define RADIOLIB_LR11X0_RFSW_DIO8_DISABLED (0x00UL << 3) // 4 0 DIO8 disabled (default) #define RADIOLIB_LR11X0_RFSW_DIO10_ENABLED (0x01UL << 4) // 4 0 RF switch: DIO10 enabled #define RADIOLIB_LR11X0_RFSW_DIO10_DISABLED (0x00UL << 4) // 4 0 DIO10 disabled (default) -#define RADIOLIB_LR11X0_DIOx(X) ((X) | RFSWITCH_PIN_FLAG) -#define RADIOLIB_LR11X0_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG) -#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LR11X0_DIOx(0)) -#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LR11X0_DIOx(1)) -#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LR11X0_DIOx(2)) -#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LR11X0_DIOx(3)) -#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LR11X0_DIOx(4)) +#define RADIOLIB_LR11X0_DIO5 (RADIOLIB_LRXXXX_DIOx(0)) +#define RADIOLIB_LR11X0_DIO6 (RADIOLIB_LRXXXX_DIOx(1)) +#define RADIOLIB_LR11X0_DIO7 (RADIOLIB_LRXXXX_DIOx(2)) +#define RADIOLIB_LR11X0_DIO8 (RADIOLIB_LRXXXX_DIOx(3)) +#define RADIOLIB_LR11X0_DIO10 (RADIOLIB_LRXXXX_DIOx(4)) // RADIOLIB_LR11X0_CMD_SET_DIO_IRQ_PARAMS #define RADIOLIB_LR11X0_IRQ_TX_DONE (0x01UL << 2) // 31 0 interrupt: packet transmitted diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 62b6474cd7..37843e53d4 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -75,6 +75,11 @@ #define RADIOLIB_LRXXXX_PA_RAMP_272U (0x11UL << 0) // 7 0 272 us #define RADIOLIB_LRXXXX_PA_RAMP_304U (0x12UL << 0) // 7 0 304 us +// RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH +// RADIOLIB_LR2021_CMD_SET_DIO_AS_RF_SWITCH +#define RADIOLIB_LRXXXX_DIOx(X) ((X) | RFSWITCH_PIN_FLAG) +#define RADIOLIB_LRXXXX_DIOx_VAL(X) ((X) & ~RFSWITCH_PIN_FLAG) + // common configuration values #define RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE (488.28215f) // 31 0 LR FHSS bit rate: 488.28215 bps #define RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE_RAW (0x8001E848UL) // 31 0 488.28215 bps in raw diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 674bb71214..d62516cd56 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -42,6 +42,25 @@ class LR2021: public LRxxxx { */ uint32_t irqDioNum = 5; + /*! + \brief Custom operation modes for LR2021. + Needed because LR2021 has several modems (sub-GHz, 2.4 GHz etc.) in one package + */ + enum OpMode_t { + /*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */ + MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE, + /*! Standby/idle mode */ + MODE_STBY = Module::MODE_IDLE, + /*! Receive mode */ + MODE_RX = Module::MODE_RX, + /*! Transmission mode */ + MODE_TX = Module::MODE_TX, + /*! High frequency receive mode */ + MODE_RX_HF, + /*! High frequency transmission mode */ + MODE_TX_HF, + }; + // basic methods /*! @@ -306,6 +325,9 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t checkOutputPower(int8_t power, int8_t* clipped) override; + + /*! \copydoc Module::setRfSwitchTable */ + void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]); /*! \brief Sets LoRa bandwidth. Allowed values are 31.25, 41.67, 62.5, 83.34, 125.0, @@ -649,6 +671,7 @@ class LR2021: public LRxxxx { int16_t clearErrors(void); int16_t getErrors(uint16_t* err); int16_t setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive); + int16_t setDioRfSwitchConfig(uint8_t dio, uint8_t func); int16_t setDioIrqConfig(uint8_t dio, uint32_t irq); int16_t clearIrqState(uint32_t irq); int16_t getAndClearIrqStatus(uint32_t* irq); diff --git a/src/modules/LR2021/LR2021_cmds_chip_control.cpp b/src/modules/LR2021/LR2021_cmds_chip_control.cpp index 0ea3c1f57d..65183fa1c9 100644 --- a/src/modules/LR2021/LR2021_cmds_chip_control.cpp +++ b/src/modules/LR2021/LR2021_cmds_chip_control.cpp @@ -215,6 +215,11 @@ int16_t LR2021::setDioFunction(uint8_t dio, uint8_t func, uint8_t pullDrive) { return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION, true, buff, sizeof(buff))); } +int16_t LR2021::setDioRfSwitchConfig(uint8_t dio, uint8_t func) { + uint8_t buff[] = { dio, func }; + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_DIO_RF_SWITCH_CONFIG, true, buff, sizeof(buff))); +} + int16_t LR2021::setDioIrqConfig(uint8_t dio, uint32_t irq) { uint8_t buff[] = { dio, (uint8_t)((irq >> 24) & 0xFF), (uint8_t)((irq >> 16) & 0xFF), diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 22003e4fa9..89c851850d 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -37,6 +37,7 @@ #define RADIOLIB_LR2021_CMD_CLEAR_ERRORS (0x0111) #define RADIOLIB_LR2021_CMD_GET_ERRORS (0x0110) #define RADIOLIB_LR2021_CMD_SET_DIO_FUNCTION (0x0112) +#define RADIOLIB_LR2021_CMD_SET_DIO_RF_SWITCH_CONFIG (0x0113) #define RADIOLIB_LR2021_CMD_SET_DIO_IRQ_CONFIG (0x0115) #define RADIOLIB_LR2021_CMD_CLEAR_IRQ (0x0116) #define RADIOLIB_LR2021_CMD_GET_AND_CLEAR_IRQ_STATUS (0x0117) @@ -292,6 +293,15 @@ #define RADIOLIB_LR2021_DIO_SLEEP_PULL_UP (0x02UL << 0) // 3 0 pull-up #define RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO (0x03UL << 0) // 3 0 auto +// RADIOLIB_LR2021_CMD_SET_DIO_RF_SWITCH_CONFIG +#define RADIOLIB_LR2021_DIO5 (RADIOLIB_LRXXXX_DIOx(0)) +#define RADIOLIB_LR2021_DIO6 (RADIOLIB_LRXXXX_DIOx(1)) +#define RADIOLIB_LR2021_DIO7 (RADIOLIB_LRXXXX_DIOx(2)) +#define RADIOLIB_LR2021_DIO8 (RADIOLIB_LRXXXX_DIOx(3)) +#define RADIOLIB_LR2021_DIO9 (RADIOLIB_LRXXXX_DIOx(4)) +#define RADIOLIB_LR2021_DIO10 (RADIOLIB_LRXXXX_DIOx(5)) +#define RADIOLIB_LR2021_DIO11 (RADIOLIB_LRXXXX_DIOx(6)) + // RADIOLIB_LR2021_CMD_CONFIG_FIFO_IRQ #define RADIOLIB_LR2021_FIFO_IRQ_EMPTY (0x01UL << 0) // 7 0 FIFO interrupt on: empty FIFO #define RADIOLIB_LR2021_FIFO_IRQ_LOW (0x01UL << 1) // 7 0 level below threshold diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 7b8a75a3b0..5e71d8b780 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -112,6 +112,31 @@ int16_t LR2021::checkOutputPower(int8_t power, int8_t* clipped) { return(RADIOLIB_ERR_NONE); } +void LR2021::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) { + // find which pins are used + // on LR2021, modes are configured per DIO (exact opposite of LR11x0) + uint8_t dioConfigs[7] = { 0 }; + for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) { + // check if this pin is unused + if(pins[i] == RADIOLIB_NC) { continue; } + + // only keep DIO pins, there may be some GPIOs in the switch tabke + if((pins[i] & RFSWITCH_PIN_FLAG) == 0) { continue; } + + // find modes in which this pin is used + uint32_t dioNum = RADIOLIB_LRXXXX_DIOx_VAL(pins[i]); + size_t j = 0; + while(table[j].mode != LR2021::MODE_END_OF_TABLE) { + dioConfigs[dioNum] |= (table[j].values[i] == this->mod->hal->GpioLevelHigh) ? (1UL << (table[j].mode - 1)) : 0; + j++; + } + + // enable RF control for this pin and set the modes in which it is active + (void)this->setDioFunction(dioNum + 5, RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH, RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO); + (void)this->setDioRfSwitchConfig(dioNum + 5, dioConfigs[i]); + } +} + int16_t LR2021::setBandwidth(float bw) { // check active modem uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; From 1e371b8ec82309ebbc62c5e0109dad339dee8b27 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 25 Jan 2026 08:23:41 +0000 Subject: [PATCH 1752/1848] [LR2021] Add DIO IRQ configuration to examples --- .../LR2021_Channel_Activity_Detection_Blocking.ino | 5 +++++ .../LR2021_Channel_Activity_Detection_Interrupt.ino | 5 +++++ examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino | 5 +++++ .../LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino | 5 +++++ examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino | 5 +++++ .../LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino | 5 +++++ .../LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino | 5 +++++ .../LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino | 5 +++++ .../LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino | 5 +++++ .../LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino | 5 +++++ 10 files changed, 50 insertions(+) diff --git a/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino b/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino index 47151778ff..31fe6be1cc 100644 --- a/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino +++ b/examples/LR2021/LR2021_Channel_Activity_Detection_Blocking/LR2021_Channel_Activity_Detection_Blocking.ino @@ -39,6 +39,11 @@ Radio radio = new RadioModule(); void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino b/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino index ee77211432..e3ff8029a3 100644 --- a/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino +++ b/examples/LR2021/LR2021_Channel_Activity_Detection_Interrupt/LR2021_Channel_Activity_Detection_Interrupt.ino @@ -49,6 +49,11 @@ void setFlag(void) { void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino b/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino index b025b3be2e..ad8997a6ca 100644 --- a/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino +++ b/examples/LR2021/LR2021_GFSK_Modem/LR2021_GFSK_Modem.ino @@ -37,6 +37,11 @@ Radio radio = new RadioModule(); void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.beginGFSK(); diff --git a/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino b/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino index 237434e76d..097c1f34ee 100644 --- a/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino +++ b/examples/LR2021/LR2021_LR_FHSS_Modem/LR2021_LR_FHSS_Modem.ino @@ -38,6 +38,11 @@ Radio radio = new RadioModule(); void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.beginLRFHSS(); diff --git a/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino b/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino index 1de592171e..4a399d88e1 100644 --- a/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino +++ b/examples/LR2021/LR2021_PingPong/LR2021_PingPong.ino @@ -54,6 +54,11 @@ void setFlag(void) { void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino b/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino index 18deaf8230..709d61d3e4 100644 --- a/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino +++ b/examples/LR2021/LR2021_Receive_Blocking/LR2021_Receive_Blocking.ino @@ -44,6 +44,11 @@ Radio radio = new RadioModule(); void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino b/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino index 952754db2b..bcc63abb69 100644 --- a/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino +++ b/examples/LR2021/LR2021_Receive_Interrupt/LR2021_Receive_Interrupt.ino @@ -55,6 +55,11 @@ void setFlag(void) { void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino b/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino index 570475c2be..d516a7c0ae 100644 --- a/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino +++ b/examples/LR2021/LR2021_Receive_MultiSF/LR2021_Receive_MultiSF.ino @@ -64,6 +64,11 @@ void setFlag(void) { void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino b/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino index 714acddd42..7b6518b417 100644 --- a/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino +++ b/examples/LR2021/LR2021_Transmit_Blocking/LR2021_Transmit_Blocking.ino @@ -35,6 +35,11 @@ Radio radio = new RadioModule(); void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); diff --git a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino index e45f18fe9d..d3ed5b5404 100644 --- a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino +++ b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino @@ -54,6 +54,11 @@ void setFlag(void) { void setup() { Serial.begin(9600); + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + // initialize LR2021 with default settings Serial.print(F("[LR2021] Initializing ... ")); int state = radio.begin(); From 1141a09d05fb2bcd58e8258a36c76dcf0dcbf8e5 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 25 Jan 2026 15:38:20 +0100 Subject: [PATCH 1753/1848] [LRxxxx] Fix typo in definition --- src/modules/LR11x0/LR_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index acac2b5d55..775d7ca0b2 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -337,7 +337,7 @@ int16_t LRxxxx::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* d // so there is probably no way to do this without copying buffers and iterating size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t); #if RADIOLIB_STATIC_ONLY - uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN]; + uint8_t dataBuff[sizeof(uint32_t) + RADIOLIB_LRXXXX_SPI_MAX_READ_WRITE_LEN]; #else uint8_t* dataBuff = new uint8_t[buffLen]; #endif From 37241af946e50de826178e82c47a5f58bd05e800 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 18:52:59 +0000 Subject: [PATCH 1754/1848] [LR2021] Fix handling opf FLRC parameters --- src/modules/LR2021/LR2021_config.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 5e71d8b780..776bc37455 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -253,7 +253,7 @@ int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) { RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters - this->codingRateFlrc = (cr - 2) * 2; + this->codingRateFlrc = cr; return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape)); } @@ -293,7 +293,10 @@ int16_t LR2021::setPreambleLength(size_t preambleLength) { return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { - this->preambleLengthGFSK = preambleLength / 4; + if((preambleLength % 4) != 0) { + return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH); + } + this->preambleLengthGFSK = (preambleLength / 4) - 1; return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH)); } @@ -401,7 +404,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION); } - this->crcLenGFSK = len; + this->crcLenGFSK = len ? len - 1 : 0; return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH)); } @@ -463,6 +466,10 @@ int16_t LR2021::setBitRate(float br) { return(RADIOLIB_ERR_INVALID_BIT_RATE); } + // it is slightly weird to reuse the GFSK bitrate variable in this way + // but if GFSK gets enabled it should get reset anyway ... I think + this->bitRate = br; + // update modulation parameters return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape)); } @@ -613,7 +620,7 @@ int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) { } // update sync word length - this->syncWordLength = len*8; + this->syncWordLength = len/2; state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH); RADIOLIB_ASSERT(state); From 03bf4ec20856ea3b0ce13062f2983bfdb0aea1a1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 18:53:22 +0000 Subject: [PATCH 1755/1848] [LR2021] Add explicit CRC configuration for FLRC --- src/modules/LR2021/LR2021.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 2d22114e2d..94d20c361b 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -191,6 +191,9 @@ int16_t LR2021::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1 RADIOLIB_ASSERT(state); state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + state = setCRC(2); return(state); } From c0795aa9a82ce39cbe2a9ac2f9bcbaa30472402e Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 18:53:35 +0000 Subject: [PATCH 1756/1848] [LR2021] Add missing ToA calculation for FLRC --- src/modules/LR2021/LR2021.cpp | 49 ++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 94d20c361b..61eba99ba3 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -734,9 +734,52 @@ int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uin } RadioLibTime_t LR2021::getTimeOnAir(size_t len) { - ModemType_t modem; - getModem(&modem); - return(LRxxxx::getTimeOnAir(len, modem)); + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + + switch(type) { + // basic modems are supported by the LRxxxx base class + case(RADIOLIB_LR2021_PACKET_TYPE_LORA): + return(LRxxxx::getTimeOnAir(len, ModemType_t::RADIOLIB_MODEM_LORA)); + case(RADIOLIB_LR2021_PACKET_TYPE_GFSK): + return(LRxxxx::getTimeOnAir(len, ModemType_t::RADIOLIB_MODEM_FSK)); + case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS): + return(LRxxxx::getTimeOnAir(len, ModemType_t::RADIOLIB_MODEM_LRFHSS)); + case(RADIOLIB_LR2021_PACKET_TYPE_FLRC): { + //! \todo [LR2021] Add FLRC to the modems supported in ModemType_t + + // calculate the bits of the uncoded part of the packet + size_t n_uncoded_bits = (this->preambleLengthGFSK + 1)*4 + 21 + this->syncWordLength*16; + if(this->packetType != RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) { n_uncoded_bits+= 16; } + + // calculate bits in the coded part + size_t n_coded_bits = len*8; + if(this->crcLenGFSK != 0) { n_coded_bits += (this->crcLenGFSK + 1)*8; } + if(this->codingRateFlrc <= RADIOLIB_LR2021_FLRC_CR_3_4) { n_coded_bits += 6; } + float n_coded_bits_flt = n_coded_bits; + switch(this->codingRateFlrc) { + case(RADIOLIB_LR2021_FLRC_CR_1_2): + n_coded_bits += 6; + n_coded_bits_flt = (float)n_coded_bits*2.0f; + break; + case(RADIOLIB_LR2021_FLRC_CR_3_4): + n_coded_bits += 6; + n_coded_bits_flt = ((float)n_coded_bits*4.0f)/3.0f; + break; + case(RADIOLIB_LR2021_FLRC_CR_2_3): + n_coded_bits_flt = ((float)n_coded_bits*3.0f)/2.0f; + break; + } + n_coded_bits = n_coded_bits_flt + 0.5f; + + // now calculate the real time on air + return((float)(n_uncoded_bits + n_coded_bits) / (float)(this->bitRate / 1000.0f)); + } + } + + RADIOLIB_DEBUG_BASIC_PRINTLN("Called getTimeOnAir() for invalid modem (%02x)!", type); + return(0); } int16_t LR2021::getModem(ModemType_t* modem) { From e71e3052ee70aff43a0fdd6f26028623c3db5d38 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 19:18:24 +0000 Subject: [PATCH 1757/1848] [LR2021] Fix FLRC coding rate check --- src/modules/LR2021/LR2021.cpp | 2 +- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 61eba99ba3..cb323d3022 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -750,7 +750,7 @@ RadioLibTime_t LR2021::getTimeOnAir(size_t len) { //! \todo [LR2021] Add FLRC to the modems supported in ModemType_t // calculate the bits of the uncoded part of the packet - size_t n_uncoded_bits = (this->preambleLengthGFSK + 1)*4 + 21 + this->syncWordLength*16; + size_t n_uncoded_bits = (this->preambleLengthGFSK + 1)*4 + 21 + this->syncWordLength*8; if(this->packetType != RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) { n_uncoded_bits+= 16; } // calculate bits in the coded part diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 776bc37455..9fe31567cc 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -250,7 +250,7 @@ int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) { return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { - RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE); + RADIOLIB_CHECK_RANGE(cr, 0, 4, RADIOLIB_ERR_INVALID_CODING_RATE); // update modulation parameters this->codingRateFlrc = cr; @@ -620,7 +620,7 @@ int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) { } // update sync word length - this->syncWordLength = len/2; + this->syncWordLength = len; state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH); RADIOLIB_ASSERT(state); From 99d971a81051206fa0b78c6a2a94cab132fcd33d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 19:26:09 +0000 Subject: [PATCH 1758/1848] [LR2021] Fix FLRC sync word byte order --- src/modules/LR2021/LR2021_config.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 9fe31567cc..1b83395c5f 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -624,7 +624,10 @@ int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) { state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH); RADIOLIB_ASSERT(state); - memcpy(&sync, syncWord, sizeof(uint32_t)); + sync |= (uint32_t)syncWord[0] << 24; + sync |= (uint32_t)syncWord[1] << 16; + sync |= (uint32_t)syncWord[2] << 8; + sync |= (uint32_t)syncWord[3]; return(setFlrcSyncWord(1, sync)); } From b04841b640191616bcc0f1ab386abcfdb676fd90 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 19:31:09 +0000 Subject: [PATCH 1759/1848] [LR2021] Fix range check --- src/modules/LR2021/LR2021.h | 4 ++-- src/modules/LR2021/LR2021_config.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index d62516cd56..29525a7bf1 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -127,13 +127,13 @@ class LR2021: public LRxxxx { \brief Initialization method for FLRC modem. \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. \param br FLRC bit rate in kbps. Defaults to 650 kbps. - \param cr FLRC coding rate. Defaults to 3 (coding rate 3/4). + \param cr FLRC coding rate. Defaults to RADIOLIB_LR2021_FLRC_CR_2_3 (coding rate 2/3). \param pwr Output power in dBm. Defaults to 10 dBm. \param preambleLength FLRC preamble length in bits. Defaults to 16 bits. \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. \returns \ref status_codes */ - int16_t beginFLRC(float freq = 434.0, uint16_t br = 650, uint8_t cr = 3, int8_t pwr = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5, float tcxoVoltage = 1.6); + int16_t beginFLRC(float freq = 434.0, uint16_t br = 650, uint8_t cr = RADIOLIB_LR2021_FLRC_CR_2_3, int8_t pwr = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5, float tcxoVoltage = 1.6); /*! \brief Blocking binary transmit method. diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 1b83395c5f..9411fee298 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -250,7 +250,9 @@ int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) { return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { - RADIOLIB_CHECK_RANGE(cr, 0, 4, RADIOLIB_ERR_INVALID_CODING_RATE); + if(cr > RADIOLIB_LR2021_FLRC_CR_2_3) { + return(RADIOLIB_ERR_INVALID_CODING_RATE); + } // update modulation parameters this->codingRateFlrc = cr; From a1c436fa010a0d22cd9e422ba36f8bd3f120a29f Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 20:09:51 +0000 Subject: [PATCH 1760/1848] [LR2021] Add Rx gain boost configuration --- src/modules/LR2021/LR2021.cpp | 2 +- src/modules/LR2021/LR2021.h | 8 ++++++++ src/modules/LR2021/LR2021_config.cpp | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index cb323d3022..28927068b7 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -821,7 +821,7 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { } // set the correct Rx path - state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? RADIOLIB_LR2021_RX_BOOST_HF : RADIOLIB_LR2021_RX_BOOST_LF); + state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->gainMode); RADIOLIB_ASSERT(state); // set DIO mapping diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 29525a7bf1..ff0d9dd226 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -516,6 +516,13 @@ class LR2021: public LRxxxx { */ int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeed = 0x13A); + /*! + \brief Enables or disables Rx Boosted Gain mode (additional Rx gain for increased power consumption). + \param level Rx gain boost level. 0 (disabled) to 7 (maximum boost). + \returns \ref status_codes + */ + int16_t setRxBoostedGainMode(uint8_t level); + /*! \brief Get expected time-on-air for a given size of payload \param len Payload length in bytes. @@ -633,6 +640,7 @@ class LR2021: public LRxxxx { // flag to determine whether we are in the sub-GHz or 2.4 GHz range // this is needed to automatically detect which PA to use bool highFreq = false; + uint8_t gainMode = RADIOLIB_LR2021_RX_BOOST_LF; // cached FLRC parameters uint16_t bitRateFlrc = 0; diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 9411fee298..a008a0d1a3 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -816,6 +816,13 @@ int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16 return(RADIOLIB_ERR_NONE); } +int16_t LR2021::setRxBoostedGainMode(uint8_t level) { + int16_t state = this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->gainMode); + RADIOLIB_ASSERT(state); + this->gainMode = level; + return(state); +} + int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { // check active modem uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; From c496281f581938b396bcfe6311b0833d4fd0c936 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 27 Jan 2026 20:13:21 +0000 Subject: [PATCH 1761/1848] [LR2021] Split Rx gain cofiguration per band --- src/modules/LR2021/LR2021.cpp | 2 +- src/modules/LR2021/LR2021.h | 3 ++- src/modules/LR2021/LR2021_config.cpp | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 28927068b7..f3ee0685d4 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -821,7 +821,7 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { } // set the correct Rx path - state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->gainMode); + state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf); RADIOLIB_ASSERT(state); // set DIO mapping diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index ff0d9dd226..ca023d8c8f 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -640,7 +640,8 @@ class LR2021: public LRxxxx { // flag to determine whether we are in the sub-GHz or 2.4 GHz range // this is needed to automatically detect which PA to use bool highFreq = false; - uint8_t gainMode = RADIOLIB_LR2021_RX_BOOST_LF; + uint8_t gainModeLf = RADIOLIB_LR2021_RX_BOOST_LF; + uint8_t gainModeHf = RADIOLIB_LR2021_RX_BOOST_HF; // cached FLRC parameters uint16_t bitRateFlrc = 0; diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index a008a0d1a3..efb945b7cf 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -817,9 +817,13 @@ int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16 } int16_t LR2021::setRxBoostedGainMode(uint8_t level) { - int16_t state = this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->gainMode); + int16_t state = this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf); RADIOLIB_ASSERT(state); - this->gainMode = level; + if(this->highFreq) { + this->gainModeHf = level; + } else { + this->gainModeLf = level; + } return(state); } From 9f5938fdf75cbed14c4082d20298794eda75d075 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 28 Jan 2026 20:15:41 +0000 Subject: [PATCH 1762/1848] [LR2021] Add final missing PHY methods --- src/modules/LR2021/LR2021.cpp | 32 +++++++++++++++++++++++++++++ src/modules/LR2021/LR2021.h | 38 ++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index f3ee0685d4..b691011761 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -384,6 +384,10 @@ int16_t LR2021::standby() { return(this->standby(RADIOLIB_LR2021_STANDBY_RC)); } +int16_t LR2021::standby(uint8_t mode) { + return(this->standby(mode, true)); +} + int16_t LR2021::standby(uint8_t mode, bool wakeup) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); @@ -569,6 +573,34 @@ int16_t LR2021::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } +uint32_t LR2021::getIrqFlags() { + return(getIrqStatus()); +} + +int16_t LR2021::setIrqFlags(uint32_t irq) { + return(this->setDioIrqConfig(this->irqDioNum, irq)); +} + +int16_t LR2021::clearIrqFlags(uint32_t irq) { + return(this->clearIrqState(irq)); +} + +int16_t LR2021::setModem(ModemType_t modem) { + switch(modem) { + case(ModemType_t::RADIOLIB_MODEM_LORA): { + return(this->begin()); + } break; + case(ModemType_t::RADIOLIB_MODEM_FSK): { + return(this->beginGFSK()); + } break; + case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { + return(this->beginLRFHSS()); + } break; + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } +} + Module* LR2021::getMod() { return(this->mod); } diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index ca023d8c8f..ee7ec49cca 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -189,6 +189,14 @@ class LR2021: public LRxxxx { */ int16_t standby() override; + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR2021_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_LR2021_STANDBY_XOSC (32 MHz external crystal oscillator). + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Sets the module to standby mode. \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR2021_STANDBY_RC (13 MHz RC oscillator) @@ -196,7 +204,7 @@ class LR2021: public LRxxxx { \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. \returns \ref status_codes */ - int16_t standby(uint8_t mode, bool wakeup = true); + int16_t standby(uint8_t mode, bool wakeup); /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). @@ -273,6 +281,34 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t getChannelScanResult() override; + + /*! + \brief Read currently active IRQ flags. + \returns IRQ flags. + */ + uint32_t getIrqFlags() override; + + /*! + \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + int16_t setIrqFlags(uint32_t irq) override; + + /*! + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + int16_t clearIrqFlags(uint32_t irq) override; + + /*! + \brief Set modem for the radio to use. Will perform full reset and reconfigure the radio + using its default parameters. + \param modem Modem type to set - FSK, LoRa or LR-FHSS. + \returns \ref status_codes + */ + int16_t setModem(ModemType_t modem) override; // configuration methods From 4afbfd3ed3cfcb21502e3c2dcd41615beee8f0a9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 Jan 2026 06:25:00 +0000 Subject: [PATCH 1763/1848] [LR2021] Fix default OOK pattern length --- src/modules/LR2021/LR2021.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index ee7ec49cca..993ba6ca15 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -636,14 +636,14 @@ class LR2021: public LRxxxx { /*! \brief Set OOK detector properties. The default values are set to allow ADS-B reception. \param pattern Preamble pattern, should end with 01 or 10 (binary). - \param len Preamble patter length in bits. + \param len Preamble pattern length in bits. \param repeats Number of preamble repeats, maximum of 31. \param syncRaw Whether the sync word is send raw (unencoded) or encoded. Set to true for encoded sync word. \param rising Whether the start of frame delimiter edge is rising (true) or falling (false). \param sofLen Start-of-frame length in bits. \returns \ref status_codes */ - int16_t ookDetector(uint16_t pattern = 0x0285, uint8_t len = 10, uint8_t repeats = 0, bool syncRaw = false, bool rising = false, uint8_t sofLen = 0); + int16_t ookDetector(uint16_t pattern = 0x0285, uint8_t len = 16, uint8_t repeats = 0, bool syncRaw = false, bool rising = false, uint8_t sofLen = 0); /*! \brief Configure LoRa side detector, which enables to detect mutiple spreading factors and receive one of them. From bbf5a424d3becc9045df212fbe9d8c7f92a66930 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 Jan 2026 17:27:39 +0000 Subject: [PATCH 1764/1848] [LR2021] Fix LoRa CRC and PA ramp config --- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index efb945b7cf..6973c6a0a9 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -71,7 +71,7 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { } int16_t LR2021::setOutputPower(int8_t power) { - return(this->setOutputPower(power, false)); + return(this->setOutputPower(power, 48)); } int16_t LR2021::setOutputPower(int8_t power, uint32_t rampTimeUs) { @@ -368,7 +368,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool RADIOLIB_ASSERT(state); if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) { // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion - this->crcTypeLoRa = len > 0 ? RADIOLIB_LR2021_LORA_CRC_ENABLED : RADIOLIB_LR2021_LORA_CRC_DISABLED; + this->crcTypeLoRa = len > 0; return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { From ea5331653d206b4be81ddee378887f47b67ffed6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 Jan 2026 17:44:10 +0000 Subject: [PATCH 1765/1848] [PHY] Fix IRQ check failing for 32-bit IRQs --- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index d2016ece25..5dc92779cf 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -349,7 +349,7 @@ int16_t PhysicalLayer::checkIrq(RadioLibIrqType_t irq) { return(RADIOLIB_ERR_UNSUPPORTED); } - return(getIrqFlags() & this->irqMap[irq]); + return((getIrqFlags() & this->irqMap[irq]) != 0); } int16_t PhysicalLayer::setIrq(RadioLibIrqFlags_t irq) { From a6640991a4940cbb3737d5d5368917b6cd435aa6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 29 Jan 2026 20:06:28 +0000 Subject: [PATCH 1766/1848] [LR2021] Fix sleep mode waiting for busy to go low --- src/modules/LR2021/LR2021.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index b691011761..c8c19e2c00 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -415,7 +415,8 @@ int16_t LR2021::sleep(bool retainConfig, uint32_t sleepTime) { (uint8_t)((sleepTime >> 8) & 0xFF), (uint8_t)(sleepTime & 0xFF), }; - int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_SET_SLEEP, true, buff, sizeof(buff)); + // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low + int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR2021_CMD_SET_SLEEP, buff, sizeof(buff), false, false); // wait for the module to safely enter sleep mode this->mod->hal->delay(1); From abe7884da0a7ca34d9557fdca5eea877d487854c Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 30 Jan 2026 17:27:18 +0000 Subject: [PATCH 1767/1848] [LR11xx] Fix waiting for busy when going to sleep --- src/modules/LR11x0/LR11x0.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index bd03852047..6b450eb93d 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -360,7 +360,8 @@ int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) { buff[0] |= RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED; } - int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_SLEEP, true, buff, sizeof(buff)); + // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low + int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_SET_SLEEP, buff, sizeof(buff), false, false); // wait for the module to safely enter sleep mode this->mod->hal->delay(1); From c4ea3d1a1c79de154740ff7c34e89d0a77376e0e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 30 Jan 2026 17:42:36 +0000 Subject: [PATCH 1768/1848] [LoRaWAN] Add waiting loop to ensure downlink always completes --- src/protocols/LoRaWAN/LoRaWAN.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 9004f7215f..4c20469b34 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1568,6 +1568,18 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne while(!downlinkAction && mod->hal->millis() - tOpen < toaMaxMs + this->scanGuard) { mod->hal->yield(); } + + // sometimes we can get to a state when reception is still ongoing, but has not finished yet + // this has been observed on LR2021 - wait until either timeout, or Rx done is raised + // it should never take more than 300 ms + RadioLibTime_t start = mod->hal->millis(); + while(!this->phyLayer->checkIrq(RADIOLIB_IRQ_TIMEOUT) && !this->phyLayer->checkIrq(RADIOLIB_IRQ_RX_DONE)) { + mod->hal->yield(); + if(mod->hal->millis() - start >= 300) { + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Timeout without IRQ!"); + break; + } + } // update time of downlink reception if(downlinkAction) { From 30d20ae36fe2e22f30a8fb97980847cfa0e69ad3 Mon Sep 17 00:00:00 2001 From: "Sylvain \"tnt\" Munaut" Date: Fri, 30 Jan 2026 19:07:59 +0100 Subject: [PATCH 1769/1848] Re-Fix for #1667 (#1681) * [SX127x] Fix typo in startChannelScan doc string It's DIO1 that fires when a preamble is detected, and DIO0 if timeout. (see both the datasheet and the example code) Signed-off-by: Sylvain Munaut * [HAL] Rework RPi Pico interrupts again (#1667) The short story is that the raw handlers are not associated with the mask given, the handler itself will be added to a linked link by the generic IRQ code, so adding the same handler several time for different interrupts yields not what you expect. The current code also doesn't remove the handler before setting a new one which leads to `assert` crashing the CPU. The new strategy here is that once a pin is used with the HAL, we always keep the shared HAL handler bound to it. Internally we keep a list of what pin map to which user handler. When a new pin is used we temporarely disable interrupt, unbind the HAL handler completely and re-bind it with the new set of pin. And then re-enable the GPIO interrupts. AFAICT from reading the SDK code, that's the only option. To avoid having to do that whole thing too often (it's a rather large block of code with interrupts disabled), we never remove our raw handler once it's attached to a pin, we just remove the user handler from our internal list. I don't think that's a problem since those pins where the user would use the HAL are pins from the radio module and so are managed by the HAL. Signed-off-by: Sylvain Munaut * [CI] Upgrade RPi Pico SDK to 2.2.0 --------- Signed-off-by: Sylvain Munaut Co-authored-by: jgromes --- .github/workflows/main.yml | 2 +- src/hal/RPiPico/PicoHal.h | 21 ++++++++++++++++++--- src/modules/SX127x/SX127x.h | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 951b38123f..977edb42a4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -356,7 +356,7 @@ jobs: mkdir -p ~/rpi-pico cd ~/rpi-pico git clone https://github.com/raspberrypi/pico-sdk.git - cd pico-sdk && git checkout 1.5.1 + cd pico-sdk && git checkout 2.2.0 - name: Build the example run: | diff --git a/src/hal/RPiPico/PicoHal.h b/src/hal/RPiPico/PicoHal.h index 256e159622..daf5a75c93 100644 --- a/src/hal/RPiPico/PicoHal.h +++ b/src/hal/RPiPico/PicoHal.h @@ -23,6 +23,7 @@ // However, there seems to be no real use case for creating multiple intances of the HAL static irq_handler_t picoHalUserCallbacks[PI_PICO_MAX_USER_GPIO] = { 0 }; static uint32_t picoHalIrqEventMasks[PI_PICO_MAX_USER_GPIO] = { 0 }; +static uint64_t picoHalIrqMask = 0; static void picoInterruptHandler(void) { for(int gpio = 0; gpio < PI_PICO_MAX_USER_GPIO; gpio++) { @@ -94,10 +95,24 @@ class PicoHal : public RadioLibHal { picoHalUserCallbacks[interruptNum] = (irq_handler_t)interruptCb; picoHalIrqEventMasks[interruptNum] = mode; - // enable IRQ and set the internal callback + // is it a new interrupt for us to grab ? + if (!(picoHalIrqMask & (1ULL << interruptNum))) { + // if we have a handler in place, we must remove it to avoid 'assert' in the PDK + // and we must disable interrupt to make sure we don't miss anything during that + // shuffling + if (picoHalIrqMask) { + irq_set_enabled(IO_IRQ_BANK0, false); + gpio_remove_raw_irq_handler_masked64(picoHalIrqMask, picoInterruptHandler); + } + + // (re-)add shared handler with the new mask + picoHalIrqMask |= (1ULL << interruptNum); + gpio_add_raw_irq_handler_masked64(picoHalIrqMask, picoInterruptHandler); + irq_set_enabled(IO_IRQ_BANK0, true); + } + + // enable GPIO to generate interrupt gpio_set_irq_enabled(interruptNum, mode, true); - gpio_add_raw_irq_handler_masked(1UL << interruptNum, picoInterruptHandler); - irq_set_enabled(IO_IRQ_BANK0, true); } void detachInterrupt(uint32_t interruptNum) override { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 43d577bbd8..35b357e74b 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -831,8 +831,8 @@ class SX127x: public PhysicalLayer { int16_t finishReceive() override; /*! - \brief Interrupt-driven channel activity detection method. DIO0 will be activated when LoRa preamble is detected. - DIO1 will be activated if there's no preamble detected before timeout. + \brief Interrupt-driven channel activity detection method. DIO1 will be activated when LoRa preamble is detected. + DIO0 will be activated if there's no preamble detected before timeout. \returns \ref status_codes */ int16_t startChannelScan() override; From b80288b32f94d56f4bd5c25b6680471651a5f88b Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 11:35:01 +0000 Subject: [PATCH 1770/1848] [SX128x] Fix null dereference --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 7c3f951413..b9e325e978 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -381,7 +381,7 @@ int16_t SX128x::sleep(bool retainConfig) { if(!retainConfig) { sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH; } - int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, 0, 1, false, false); + int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, NULL, 0, false, false); RADIOLIB_ASSERT(state); state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false); From 2cc4611f8b174476ddcb66b186ed919e8b1373b2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 11:35:10 +0000 Subject: [PATCH 1771/1848] [SX128x] Add missing PHY methods --- src/modules/SX128x/SX128x.cpp | 41 +++++++++++++++++++++++++++++++++-- src/modules/SX128x/SX128x.h | 30 ++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index b9e325e978..966db18266 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -395,6 +395,10 @@ int16_t SX128x::standby() { return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC)); } +int16_t SX128x::standby(uint8_t mode) { + return(SX128x::standby(mode, true)); +} + int16_t SX128x::standby(uint8_t mode, bool wakeup) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); @@ -813,6 +817,32 @@ int16_t SX128x::setDataRate(DataRate_t dr, ModemType_t modem) { return(state); } +int16_t SX128x::checkDataRate(DataRate_t dr, ModemType_t modem) { + int16_t state = RADIOLIB_ERR_UNKNOWN; + + // retrieve modem if not supplied + if(modem == RADIOLIB_MODEM_NONE) { + state = this->getModem(&modem); + RADIOLIB_ASSERT(state); + } + + // select interpretation based on modem + if(modem == RADIOLIB_MODEM_FSK) { + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 125.0f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_MODEM_LORA) { + RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); + RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 203.0f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); + RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE); + return(RADIOLIB_ERR_NONE); + + } + + return(state); +} + int16_t SX128x::setBitRate(float br) { // check active modem uint8_t modem = getPacketType(); @@ -934,7 +964,7 @@ int16_t SX128x::setDataShaping(uint8_t sh) { } } -int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { +int16_t SX128x::setSyncWord(uint8_t* sync, size_t len) { // check active modem uint8_t modem = getPacketType(); if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) { @@ -963,7 +993,7 @@ int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) { } // update sync word - int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), const_cast(syncWord), len); + int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), sync, len); RADIOLIB_ASSERT(state); // update packet parameters @@ -1367,6 +1397,13 @@ RadioLibTime_t SX128x::getTimeOnAir(size_t len) { } +RadioLibTime_t SX128x::calculateRxTimeout(RadioLibTime_t timeoutUs) { + // the timeout value is given in units of 15.625 microseconds + // the calling function should provide some extra width, as this number of units is truncated to integer + RadioLibTime_t timeout = timeoutUs / 15.625f; + return(timeout); +} + int16_t SX128x::implicitHeader(size_t len) { return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len)); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 5ba4248253..2ca9bbf629 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -492,6 +492,14 @@ class SX128x: public PhysicalLayer { */ int16_t standby() override; + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC + (13 MHz RC oscillator) or RADIOLIB_SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Sets the module to standby mode. \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX128X_STANDBY_RC @@ -499,7 +507,7 @@ class SX128x: public PhysicalLayer { \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. \returns \ref status_codes */ - int16_t standby(uint8_t mode, bool wakeup = false); + int16_t standby(uint8_t mode, bool wakeup); // interrupt methods @@ -690,6 +698,15 @@ class SX128x: public PhysicalLayer { */ int16_t setDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; + /*! + \brief Check the data rate can be configured by this module. + \param dr Data rate struct. + \param modem The modem corresponding to the requested datarate (FSK, LoRa or LR-FHSS). + Defaults to currently active modem if not supplied. + \returns \ref status_codes + */ + int16_t checkDataRate(DataRate_t dr, ModemType_t modem = RADIOLIB_MODEM_NONE) override; + /*! \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem). @@ -716,11 +733,11 @@ class SX128x: public PhysicalLayer { /*! \brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, the sync word must be exactly 4 bytes long - \param syncWord Sync word to be set. + \param sync Sync word to be set. \param len Sync word length in bytes. \returns \ref status_codes */ - int16_t setSyncWord(const uint8_t* syncWord, uint8_t len); + int16_t setSyncWord(uint8_t* sync, size_t len) override; /*! \brief Sets LoRa sync word. @@ -846,6 +863,13 @@ class SX128x: public PhysicalLayer { */ RadioLibTime_t getTimeOnAir(size_t len) override; + /*! + \brief Calculate the timeout value for this specific module / series (in number of symbols or units of time) + \param timeoutUs Timeout in microseconds to listen for + \returns Timeout value in a unit that is specific for the used module + */ + RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override; + /*! \brief Set implicit header mode for future reception/transmission. \returns \ref status_codes From b3bd508b3de012b467a7b3ff2f208d1369742049 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 11:35:23 +0000 Subject: [PATCH 1772/1848] [LR11x0] Add missing PHY override --- src/modules/LR11x0/LR11x0.cpp | 4 ++++ src/modules/LR11x0/LR11x0.h | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 6b450eb93d..21452e2b18 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -329,6 +329,10 @@ int16_t LR11x0::standby() { return(LR11x0::standby(RADIOLIB_LR11X0_STANDBY_RC)); } +int16_t LR11x0::standby(uint8_t mode) { + return(LR11x0::standby(mode, true)); +} + int16_t LR11x0::standby(uint8_t mode, bool wakeup) { // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_IDLE); diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 0f02a5431a..84c4033d4d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -159,6 +159,14 @@ class LR11x0: public LRxxxx { */ int16_t standby() override; + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR11X0_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_LR11X0_STANDBY_XOSC (32 MHz external crystal oscillator). + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Sets the module to standby mode. \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_LR11X0_STANDBY_RC (13 MHz RC oscillator) @@ -166,7 +174,7 @@ class LR11x0: public LRxxxx { \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. \returns \ref status_codes */ - int16_t standby(uint8_t mode, bool wakeup = true); + int16_t standby(uint8_t mode, bool wakeup); /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). From 28c9ac4c3264b03572432cb4c7352a2c2cf4ba79 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 11:35:36 +0000 Subject: [PATCH 1773/1848] [SX126x] Add missing PHY override --- src/modules/SX126x/SX126x.h | 10 +++++++++- src/modules/SX126x/SX126x_commands.cpp | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index a1513f819d..3fb8146341 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -205,6 +205,14 @@ class SX126x: public PhysicalLayer { */ int16_t standby() override; + /*! + \brief Sets the module to standby mode. + \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) + or RADIOLIB_SX126X_STANDBY_XOSC (32 MHz external crystal oscillator). + \returns \ref status_codes + */ + int16_t standby(uint8_t mode) override; + /*! \brief Sets the module to standby mode. \param mode Oscillator to be used in standby mode. Can be set to RADIOLIB_SX126X_STANDBY_RC (13 MHz RC oscillator) @@ -212,7 +220,7 @@ class SX126x: public PhysicalLayer { \param wakeup Whether to force the module to wake up. Setting to true will immediately attempt to wake up the module. \returns \ref status_codes */ - int16_t standby(uint8_t mode, bool wakeup = true); + int16_t standby(uint8_t mode, bool wakeup); /*! \brief Handle LR-FHSS hop. diff --git a/src/modules/SX126x/SX126x_commands.cpp b/src/modules/SX126x/SX126x_commands.cpp index 114c38ac4c..bc2b14246c 100644 --- a/src/modules/SX126x/SX126x_commands.cpp +++ b/src/modules/SX126x/SX126x_commands.cpp @@ -29,7 +29,11 @@ int16_t SX126x::sleep(bool retainConfig) { } int16_t SX126x::standby() { - return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC)); + return(SX126x::standby(this->standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC : RADIOLIB_SX126X_STANDBY_RC, true)); +} + +int16_t SX126x::standby(uint8_t mode) { + return(SX126x::standby(mode, true)); } int16_t SX126x::standby(uint8_t mode, bool wakeup) { From 5bdcc665ddddec8cc579fcf76010a48ede290dd8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 11:35:48 +0000 Subject: [PATCH 1774/1848] [SX127x] Add missing PHY override --- src/modules/SX127x/SX127x.cpp | 16 ++++++++++++++++ src/modules/SX127x/SX127x.h | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b6875a192a..6b647ec8b8 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -263,6 +263,14 @@ void SX127x::reset() { } int16_t SX127x::scanChannel() { + // the configuration is not actually used + const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } }; + return(scanChannel(cfg)); +} + +int16_t SX127x::scanChannel(const ChannelScanConfig_t &config) { + (void)config; + // start CAD int16_t state = startChannelScan(); RADIOLIB_ASSERT(state); @@ -585,6 +593,14 @@ int16_t SX127x::finishReceive() { } int16_t SX127x::startChannelScan() { + // the configuration is not actually used + const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } }; + return(startChannelScan(cfg)); +} + +int16_t SX127x::startChannelScan(const ChannelScanConfig_t &config) { + (void)config; + // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 35b357e74b..b39ff9525b 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -653,6 +653,13 @@ class SX127x: public PhysicalLayer { */ int16_t scanChannel() override; + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + \param config Ignored. Implemented only for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t scanChannel(const ChannelScanConfig_t &config) override; + /*! \brief Sets the %LoRa module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. %Module will wake up automatically when methods like transmit or receive are called. @@ -837,6 +844,14 @@ class SX127x: public PhysicalLayer { */ int16_t startChannelScan() override; + /*! + \brief Interrupt-driven channel activity detection method. DIO1 will be activated + when LoRa preamble is detected, or upon timeout. + \param config Ignored. Implemented only for PhysicalLayer compatibility. + \returns \ref status_codes + */ + int16_t startChannelScan(const ChannelScanConfig_t &config) override; + /*! \brief Read the channel scan result. \returns \ref status_codes @@ -1256,8 +1271,8 @@ class SX127x: public PhysicalLayer { protected: #endif float frequency = 0; - float bandwidth = 0; - uint8_t spreadingFactor = 0; + float bandwidth = 125; + uint8_t spreadingFactor = 9; size_t packetLength = 0; uint8_t codingRate = 0; bool crcEnabled = false; From 5461e8ba30b933f5abcdade45217045043cac9a8 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 12:48:21 +0000 Subject: [PATCH 1775/1848] [PHY] Remove setDIOMapping from PhysicaLayer --- src/modules/CC1101/CC1101.h | 2 +- src/modules/RF69/RF69.h | 2 +- src/modules/SX127x/SX127x.h | 2 +- src/protocols/PhysicalLayer/PhysicalLayer.cpp | 6 ------ src/protocols/PhysicalLayer/PhysicalLayer.h | 8 -------- 5 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index f416f9dec5..860ee3a7f9 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -1025,7 +1025,7 @@ class CC1101: public PhysicalLayer { \param value The value that indicates which function to place on that pin. See chip datasheet for details. \returns \ref status_codes */ - int16_t setDIOMapping(uint32_t pin, uint32_t value) override; + int16_t setDIOMapping(uint32_t pin, uint32_t value); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index bcdd1800d9..136817e8fa 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1007,7 +1007,7 @@ class RF69: public PhysicalLayer { \param value The value that indicates which function to place on that pin. See chip datasheet for details. \returns \ref status_codes */ - int16_t setDIOMapping(uint32_t pin, uint32_t value) override; + int16_t setDIOMapping(uint32_t pin, uint32_t value); #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index b39ff9525b..e5764484c0 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1236,7 +1236,7 @@ class SX127x: public PhysicalLayer { \param value The value that indicates which function to place on that pin. See chip datasheet for details. \returns \ref status_codes */ - int16_t setDIOMapping(uint32_t pin, uint32_t value) override; + int16_t setDIOMapping(uint32_t pin, uint32_t value); /*! \brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it. diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 5dc92779cf..67888deaaf 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -522,12 +522,6 @@ void PhysicalLayer::readBit(uint32_t pin) { #endif -int16_t PhysicalLayer::setDIOMapping(uint32_t pin, uint32_t value) { - (void)pin; - (void)value; - return(RADIOLIB_ERR_UNSUPPORTED); -} - void PhysicalLayer::setPacketReceivedAction(void (*func)(void)) { (void)func; } diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 4d68922be9..d0f2a549b2 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -746,14 +746,6 @@ class PhysicalLayer { uint8_t read(bool drop = true); #endif - /*! - \brief Configure DIO pin mapping to get a given signal on a DIO pin (if available). - \param pin Pin number onto which a signal is to be placed. - \param value The value that indicates which function to place on that pin. See chip datasheet for details. - \returns \ref status_codes - */ - virtual int16_t setDIOMapping(uint32_t pin, uint32_t value); - /*! \brief Sets interrupt service routine to call when a packet is received. \param func ISR to call. From b4d5ac911141b09f267f9cc8687d7f9b449d4e26 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 12:50:30 +0000 Subject: [PATCH 1776/1848] [CI] Add PHY completion unit test --- extras/test/unit/CMakeLists.txt | 8 +- extras/test/unit/include/ModuleFixture.hpp | 19 ++ extras/test/unit/include/TestHal.hpp | 6 +- extras/test/unit/tests/ModuleFixture.cpp | 20 ++ .../unit/tests/TestCalculateTimeOnAir.cpp | 2 +- extras/test/unit/tests/TestModule.cpp | 26 +-- extras/test/unit/tests/TestPhyComplete.cpp | 199 ++++++++++++++++++ 7 files changed, 251 insertions(+), 29 deletions(-) create mode 100644 extras/test/unit/include/ModuleFixture.hpp create mode 100644 extras/test/unit/tests/ModuleFixture.cpp create mode 100644 extras/test/unit/tests/TestPhyComplete.cpp diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt index 49e222e915..d3dc81131c 100644 --- a/extras/test/unit/CMakeLists.txt +++ b/extras/test/unit/CMakeLists.txt @@ -2,14 +2,18 @@ cmake_minimum_required(VERSION 3.13) project(radiolib-unittest) +#set(CMAKE_BUILD_TYPE Debug) + # add RadioLib sources add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") # add test sources file(GLOB_RECURSE TEST_SOURCES "tests/main.cpp" + "tests/ModuleFixture.cpp" "tests/TestModule.cpp" "tests/TestCalculateTimeOnAir.cpp" + "tests/TestPhyComplete.cpp" ) # create the executable @@ -27,5 +31,5 @@ set(BUILD_FLAGS -Wall -Wextra -fprofile-arcs -ftest-coverage -O0) target_compile_options(${PROJECT_NAME} PRIVATE ${BUILD_FLAGS}) target_compile_options(RadioLib PRIVATE ${BUILD_FLAGS}) -# set RadioLib debug -#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI RADIOLIB_DEBUG_PROTOCOL) +# enable GodMode to access the private/protected members +target_compile_definitions(RadioLib PUBLIC -DRADIOLIB_GODMODE=1) diff --git a/extras/test/unit/include/ModuleFixture.hpp b/extras/test/unit/include/ModuleFixture.hpp new file mode 100644 index 0000000000..e5cf47eac8 --- /dev/null +++ b/extras/test/unit/include/ModuleFixture.hpp @@ -0,0 +1,19 @@ +#ifndef MODULE_FIXTURE_HPP +#define MODULE_FIXTURE_HPP + +#include + +#include "TestHal.hpp" + +// testing fixture +class ModuleFixture { + public: + TestHal* hal = nullptr; + Module* mod = nullptr; + EmulatedRadio* radioHardware = nullptr; + + ModuleFixture(); + ~ModuleFixture(); +}; + +#endif diff --git a/extras/test/unit/include/TestHal.hpp b/extras/test/unit/include/TestHal.hpp index ae98745bf9..ac1d98faa0 100644 --- a/extras/test/unit/include/TestHal.hpp +++ b/extras/test/unit/include/TestHal.hpp @@ -32,6 +32,8 @@ class TestHal : public RadioLibHal { public: + bool spiLogEnabled = true; + TestHal() : RadioLibHal(TEST_HAL_INPUT, TEST_HAL_OUTPUT, TEST_HAL_LOW, TEST_HAL_HIGH, TEST_HAL_RISING, TEST_HAL_FALLING) { } void init() override { @@ -191,7 +193,9 @@ class TestHal : public RadioLibHal { for(size_t i = 0; i < len; i++) { // append to log - (*this->spiLogPtr++) = out[i]; + if(this->spiLogEnabled) { + (*this->spiLogPtr++) = out[i]; + } // process the SPI byte in[i] = this->radio->HandleSPI(out[i]); diff --git a/extras/test/unit/tests/ModuleFixture.cpp b/extras/test/unit/tests/ModuleFixture.cpp new file mode 100644 index 0000000000..f5f1163d6b --- /dev/null +++ b/extras/test/unit/tests/ModuleFixture.cpp @@ -0,0 +1,20 @@ +#include + +#include "ModuleFixture.hpp" + +ModuleFixture::ModuleFixture() { + BOOST_TEST_MESSAGE("--- Module fixture setup ---"); + hal = new TestHal(); + radioHardware = new EmulatedRadio(); + hal->connectRadio(radioHardware); + + mod = new Module(hal, EMULATED_RADIO_NSS_PIN, EMULATED_RADIO_IRQ_PIN, EMULATED_RADIO_RST_PIN, EMULATED_RADIO_GPIO_PIN); + mod->init(); +} + +ModuleFixture::~ModuleFixture() { + BOOST_TEST_MESSAGE("--- Module fixture teardown ---"); + mod->term(); + delete mod; + delete hal; +} diff --git a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp index 4177a0070b..5510bd4f0f 100644 --- a/extras/test/unit/tests/TestCalculateTimeOnAir.cpp +++ b/extras/test/unit/tests/TestCalculateTimeOnAir.cpp @@ -15,7 +15,7 @@ struct RadioConfig { }; // --- Test configurations with golden values --- -std::vector allConfigs = { +static std::vector allConfigs = { { "SX126x", RADIOLIB_MODEM_LORA, {.lora={7,125,5}}, {.lora={8,false,true,true}}, {1,10,50,255}, {30976,46336,128256,548096} }, // 30.97, 46.33, 128.25, 548.09 { "SX126x", RADIOLIB_MODEM_LORA, {.lora={11,250,8}}, {.lora={16,true,false,false}}, {5,15,100,200}, {296960,362496,1411072,2590720} }, // 296.96, 362.49, 1410, 2590 { "SX126x", RADIOLIB_MODEM_FSK, {.fsk={100,10}}, {.fsk={16,16,2}}, {1,16,64,200}, {560,1760,5600,16480} }, diff --git a/extras/test/unit/tests/TestModule.cpp b/extras/test/unit/tests/TestModule.cpp index 669a643626..866c51e9e5 100644 --- a/extras/test/unit/tests/TestModule.cpp +++ b/extras/test/unit/tests/TestModule.cpp @@ -2,31 +2,7 @@ #include // mock HAL -#include "TestHal.hpp" - -// testing fixture -struct ModuleFixture { - TestHal* hal = nullptr; - Module* mod = nullptr; - EmulatedRadio* radioHardware = nullptr; - - ModuleFixture() { - BOOST_TEST_MESSAGE("--- Module fixture setup ---"); - hal = new TestHal(); - radioHardware = new EmulatedRadio(); - hal->connectRadio(radioHardware); - - mod = new Module(hal, EMULATED_RADIO_NSS_PIN, EMULATED_RADIO_IRQ_PIN, EMULATED_RADIO_RST_PIN, EMULATED_RADIO_GPIO_PIN); - mod->init(); - } - - ~ModuleFixture() { - BOOST_TEST_MESSAGE("--- Module fixture teardown ---"); - mod->term(); - delete mod; - delete hal; - } -}; +#include "ModuleFixture.hpp" BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture) diff --git a/extras/test/unit/tests/TestPhyComplete.cpp b/extras/test/unit/tests/TestPhyComplete.cpp new file mode 100644 index 0000000000..5affe146ab --- /dev/null +++ b/extras/test/unit/tests/TestPhyComplete.cpp @@ -0,0 +1,199 @@ +#include + +#include "ModuleFixture.hpp" + +#include "modules/SX126x/SX1261.h" +#include "modules/SX126x/SX1262.h" +#include "modules/SX126x/SX1268.h" +#include "modules/SX127x/SX1272.h" +#include "modules/SX127x/SX1273.h" +#include "modules/SX127x/SX1276.h" +#include "modules/SX127x/SX1277.h" +#include "modules/SX127x/SX1278.h" +#include "modules/SX127x/SX1279.h" +#include "modules/SX128x/SX1280.h" +#include "modules/SX128x/SX1281.h" +#include "modules/SX128x/SX1282.h" +#include "modules/LR11x0/LR1110.h" +#include "modules/LR11x0/LR1120.h" +#include "modules/LR11x0/LR1121.h" +#include "modules/LR2021/LR2021.h" + +BOOST_FIXTURE_TEST_SUITE(suite_PhyComplete, ModuleFixture) + +BOOST_FIXTURE_TEST_CASE(PhyComplete_AllRadios, ModuleFixture) { + struct RadioPhy { + std::string name; // Radio name + PhysicalLayer* phy; + }; + + hal->spiLogEnabled = false; + + std::vector allPhys = { + { "SX1261", new SX1261(mod) }, + { "SX1262", new SX1262(mod) }, + { "SX1268", new SX1268(mod) }, + { "SX1272", new SX1272(mod) }, + { "SX1273", new SX1273(mod) }, + { "SX1276", new SX1276(mod) }, + { "SX1277", new SX1277(mod) }, + { "SX1278", new SX1278(mod) }, + { "SX1279", new SX1272(mod) }, + { "SX1280", new SX1280(mod) }, + { "SX1281", new SX1281(mod) }, + { "SX1282", new SX1282(mod) }, + { "LR1110", new LR1110(mod) }, + { "LR1120", new LR1120(mod) }, + { "LR1121", new LR1121(mod) }, + { "LR2021", new LR2021(mod) }, + }; + + int state; + uint8_t testBuff[256] = { 0 }; + for(const auto& radio : allPhys) { + BOOST_TEST_MESSAGE("--- Test phyComplete " << radio.name << " ---"); + + state = radio.phy->transmit(testBuff, 1, 0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->sleep(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->standby(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->standby(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->startReceive(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->startReceive(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->receive(testBuff, 1); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->startTransmit(testBuff, 1, 0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->finishTransmit(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->finishReceive(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->readData(testBuff, 1); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->transmitDirect(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->receiveDirect(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setFrequency(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setBitRate(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setFrequencyDeviation(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setDataShaping(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setEncoding(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->invertIQ(false); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setOutputPower(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->checkOutputPower(0, nullptr); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setSyncWord(testBuff, 1); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setPreambleLength(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + DataRate_t dr = { .lora = { .spreadingFactor = 0, .bandwidth = 0, .codingRate = 0 } }; + state = radio.phy->setDataRate(dr); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->checkDataRate(dr); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->getPacketLength(); + BOOST_TEST(state != 0); + + state = radio.phy->getRSSI(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->getSNR(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + PacketConfig_t pc = { .lora = { .preambleLength = 0, .implicitHeader = false, + .crcEnabled = false, .ldrOptimize = false } }; + state = radio.phy->calculateTimeOnAir(RADIOLIB_MODEM_NONE, dr, pc, 0); + BOOST_TEST(state != 0); + + state = radio.phy->getTimeOnAir(100); + BOOST_TEST(state != 0); + + state = radio.phy->calculateRxTimeout(100000); + BOOST_TEST(state != 0); + + state = radio.phy->getIrqFlags(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setIrqFlags(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->clearIrqFlags(0); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->startChannelScan(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + const ChannelScanConfig_t csc = { .rssi = { .limit = 0 } }; + state = radio.phy->startChannelScan(csc); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->getChannelScanResult(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->scanChannel(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->scanChannel(csc); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->randomByte(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + state = radio.phy->setModem(RADIOLIB_MODEM_NONE); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + ModemType_t modem; + state = radio.phy->getModem(&modem); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + RadioModeConfig_t cfg = { .receive = { .timeout = 0, .irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS, + .irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK, .len = 0 }}; + state = radio.phy->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + + radio.phy->stagedMode = RADIOLIB_RADIO_MODE_RX; + state = radio.phy->launchMode(); + BOOST_TEST(state != RADIOLIB_ERR_UNSUPPORTED); + } + +} + +BOOST_AUTO_TEST_SUITE_END() From d2dcd6d0ca1296fb9155a1dcb76eab3f6afa0942 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 31 Jan 2026 19:26:36 +0300 Subject: [PATCH 1777/1848] [LR2021] DIO5 can only do DIO_SLEEP_PULL_UP (#1685) --- src/modules/LR2021/LR2021_config.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 6973c6a0a9..0ae1555bfc 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -131,8 +131,10 @@ void LR2021::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], j++; } + // For DIO = 5, only DIO_SLEEP_PULL_UP is accepted. Otherwise the SetDioFunction returns FAIL. + uint8_t pull = dioNum == 0 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO; // enable RF control for this pin and set the modes in which it is active - (void)this->setDioFunction(dioNum + 5, RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH, RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO); + (void)this->setDioFunction(dioNum + 5, RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH, pull); (void)this->setDioRfSwitchConfig(dioNum + 5, dioConfigs[i]); } } @@ -1023,4 +1025,4 @@ int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numD return(setLoRaSideDetSyncword(syncWords, numDetectors)); } -#endif \ No newline at end of file +#endif From dc5c5376fd0f24fc1adb36df5787a243e8ba9c28 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:03:21 +0000 Subject: [PATCH 1778/1848] [CC1101] Remove measured data rate methods --- .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index e99e1910ca..0a87645dbc 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -99,10 +99,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); From df88978c659e7c851f74243d306aac6266f7a0d4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:03:36 +0000 Subject: [PATCH 1779/1848] [LR11x0] Remove measured data rate methods --- .../LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino | 5 ----- .../LR11x0_Transmit_Interrupt.ino | 4 ---- src/modules/LR11x0/LR11x0.cpp | 8 -------- src/modules/LR11x0/LR11x0.h | 6 ------ src/modules/LR11x0/LR_common.h | 1 - src/modules/LR2021/LR2021.cpp | 4 ---- 6 files changed, 28 deletions(-) diff --git a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino index 66a9058dff..982401164d 100644 --- a/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino +++ b/examples/LR11x0/LR11x0_Transmit_Blocking/LR11x0_Transmit_Blocking.ino @@ -101,11 +101,6 @@ void loop() { // the packet was successfully transmitted Serial.println(F("success!")); - // print measured data rate - Serial.print(F("[LR1110] Datarate:\t")); - Serial.print(radio.getDataRate()); - Serial.println(F(" bps")); - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino index 3086a9a6bb..14942deb45 100644 --- a/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino +++ b/examples/LR11x0/LR11x0_Transmit_Interrupt/LR11x0_Transmit_Interrupt.ino @@ -126,10 +126,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 21452e2b18..52b3d5dbf7 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -201,10 +201,6 @@ int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_TX_TIMEOUT); } } - RadioLibTime_t elapsed = this->mod->hal->micros() - start; - - // update data rate - this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000000.0f); return(finishTransmit()); } @@ -1204,10 +1200,6 @@ int16_t LR11x0::explicitHeader() { return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT)); } -float LR11x0::getDataRate() const { - return(this->dataRateMeasured); -} - int16_t LR11x0::setRegulatorLDO() { return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_LDO)); } diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 84c4033d4d..a1649dc368 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -510,12 +510,6 @@ class LR11x0: public LRxxxx { */ int16_t explicitHeader(); - /*! - \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. - \returns Effective data rate in bps. - */ - float getDataRate() const; - /*! \brief Set regulator mode to LDO. \returns \ref status_codes diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 37843e53d4..4a097d762d 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -163,7 +163,6 @@ class LRxxxx: public PhysicalLayer { Module* mod; float freqMHz = 0; - float dataRateMeasured = 0; uint32_t rxTimeout = 0; // cached LoRa parameters diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index c8c19e2c00..776a18a4e0 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -253,10 +253,6 @@ int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) { return(RADIOLIB_ERR_TX_TIMEOUT); } } - RadioLibTime_t elapsed = this->mod->hal->micros() - start; - - // update data rate - this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000000.0f); return(finishTransmit()); } From 9e5224bee67dd9e32cd2407aff4f2606a972a3be Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:03:44 +0000 Subject: [PATCH 1780/1848] [LR2021] Remove measured data rate methods --- .../LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino index d3ed5b5404..8265ed2d5b 100644 --- a/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino +++ b/examples/LR2021/LR2021_Transmit_Interrupt/LR2021_Transmit_Interrupt.ino @@ -102,10 +102,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); From 0177ed89e0c051e0f87f333fb807cc0c5e914c03 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:03:58 +0000 Subject: [PATCH 1781/1848] [nRF24] Remove measured data rate methods --- .../nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 9ee46c4f51..5d5f5de656 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -112,10 +112,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); From 1c88d09209a809b4183ed2fc60abe6c4e3ae8f9f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:04:05 +0000 Subject: [PATCH 1782/1848] [RF69] Remove measured data rate methods --- .../RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 58a3f07186..63b9c8dac9 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -113,10 +113,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); From 53e0271498d590ce3ac3a291c26da7068da2b174 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:04:28 +0000 Subject: [PATCH 1783/1848] [SX126x] Remove measured data rate methods --- .../STM32WLx_Transmit_Blocking.ino | 5 ----- .../STM32WLx_Transmit_Interrupt.ino | 4 ---- .../SX126x_LR_FHSS_Transmit_Blocking.ino | 5 ----- .../SX126x_LR_FHSS_Transmit_Interrupt.ino | 4 ---- .../SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino | 5 ----- .../SX126x_Transmit_Interrupt.ino | 4 ---- examples/Stream/Stream_Transmit/Stream_Transmit.ino | 4 ---- src/modules/SX126x/SX126x.cpp | 8 -------- src/modules/SX126x/SX126x.h | 8 -------- 9 files changed, 47 deletions(-) diff --git a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino index 5a7d7b088f..4a366da32a 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Blocking/STM32WLx_Transmit_Blocking.ino @@ -94,11 +94,6 @@ void loop() { // the packet was successfully transmitted Serial.println(F("success!")); - // print measured data rate - Serial.print(F("[STM32WL] Datarate:\t")); - Serial.print(radio.getDataRate()); - Serial.println(F(" bps")); - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino index 736be3bd83..77dcc29b80 100644 --- a/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino +++ b/examples/STM32WLx/STM32WLx_Transmit_Interrupt/STM32WLx_Transmit_Interrupt.ino @@ -110,10 +110,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); diff --git a/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino b/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino index 4dea005bbf..8e72cb86c4 100644 --- a/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino +++ b/examples/SX126x/SX126x_LR_FHSS_Transmit_Blocking/SX126x_LR_FHSS_Transmit_Blocking.ino @@ -88,11 +88,6 @@ void loop() { // the packet was successfully transmitted Serial.println(F("success!")); - // print measured data rate - Serial.print(F("[SX1262] Datarate:\t")); - Serial.print(radio.getDataRate()); - Serial.println(F(" bps")); - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino b/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino index 1a22079838..d1812452cb 100644 --- a/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_LR_FHSS_Transmit_Interrupt/SX126x_LR_FHSS_Transmit_Interrupt.ino @@ -109,10 +109,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); diff --git a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino index c222e2ff28..3c34ecd92f 100644 --- a/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino +++ b/examples/SX126x/SX126x_Transmit_Blocking/SX126x_Transmit_Blocking.ino @@ -84,11 +84,6 @@ void loop() { // the packet was successfully transmitted Serial.println(F("success!")); - // print measured data rate - Serial.print(F("[SX1262] Datarate:\t")); - Serial.print(radio.getDataRate()); - Serial.println(F(" bps")); - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index fcc5c956de..b8a3f5c88f 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -99,10 +99,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); diff --git a/examples/Stream/Stream_Transmit/Stream_Transmit.ino b/examples/Stream/Stream_Transmit/Stream_Transmit.ino index 45b93d38c2..8280a405af 100644 --- a/examples/Stream/Stream_Transmit/Stream_Transmit.ino +++ b/examples/Stream/Stream_Transmit/Stream_Transmit.ino @@ -130,10 +130,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index c03e744994..e4a786fd27 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -269,10 +269,6 @@ int16_t SX126x::transmit(const uint8_t* data, size_t len, uint8_t addr) { } } - // update data rate - RadioLibTime_t elapsed = this->mod->hal->millis() - start; - this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000.0f); - return(finishTransmit()); } @@ -687,10 +683,6 @@ int16_t SX126x::getChannelScanResult() { return(RADIOLIB_ERR_UNKNOWN); } -float SX126x::getDataRate() const { - return(this->dataRateMeasured); -} - float SX126x::getRSSI() { return(this->getRSSI(true)); } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 3fb8146341..7e47a3d09b 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -527,12 +527,6 @@ class SX126x: public PhysicalLayer { */ int16_t setDio2AsRfSwitch(bool enable = true); - /*! - \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes. - \returns Effective data rate in bps. - */ - float getDataRate() const; - /*! \brief Gets recorded signal strength indicator. Overload with packet mode enabled for PhysicalLayer compatibility. @@ -893,8 +887,6 @@ class SX126x: public PhysicalLayer { uint16_t preambleLengthFSK = 0; float rxBandwidthKhz = 0; - float dataRateMeasured = 0; - uint32_t tcxoDelay = 0; uint8_t pwr = 0; From 7954251072bb3fe1354cae533f6a9dfe4d9761f2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 17:04:42 +0000 Subject: [PATCH 1784/1848] [SX127x] Remove measured data rate methods --- .../SX127x_Transmit_Blocking.ino | 5 ----- .../SX127x_Transmit_Interrupt.ino | 4 ---- src/modules/SX127x/SX127x.cpp | 11 ----------- src/modules/SX127x/SX127x.h | 7 ------- 4 files changed, 27 deletions(-) diff --git a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino index 62264ef84a..28f5bea4cb 100644 --- a/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino +++ b/examples/SX127x/SX127x_Transmit_Blocking/SX127x_Transmit_Blocking.ino @@ -84,11 +84,6 @@ void loop() { // the packet was successfully transmitted Serial.println(F(" success!")); - // print measured data rate - Serial.print(F("[SX1278] Datarate:\t")); - Serial.print(radio.getDataRate()); - Serial.println(F(" bps")); - } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes Serial.println(F("too long!")); diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 04385bc10b..773a0082f5 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -99,10 +99,6 @@ void loop() { // packet was successfully sent Serial.println(F("transmission finished!")); - // NOTE: when using interrupt-driven transmit method, - // it is not possible to automatically measure - // transmission data rate using getDataRate() - } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 6b647ec8b8..19a3ff9f64 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -65,9 +65,6 @@ int16_t SX127x::begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t state = SX127x::invertIQ(false); RADIOLIB_ASSERT(state); - // initialize internal variables - this->dataRate = 0.0; - return(state); } @@ -204,10 +201,6 @@ int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) { } } - // update data rate - RadioLibTime_t elapsed = this->mod->hal->millis() - start; - this->dataRate = (len*8.0f)/((float)elapsed/1000.0f); - return(finishTransmit()); } @@ -797,10 +790,6 @@ float SX127x::getSNR() { return(rawSNR / 4.0); } -float SX127x::getDataRate() const { - return(this->dataRate); -} - int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index e5764484c0..7eb8a8066b 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -907,12 +907,6 @@ class SX127x: public PhysicalLayer { */ float getSNR() override; - /*! - \brief Get data rate of the latest transmitted packet. - \returns Last packet data rate in bps (bits per second). - */ - float getDataRate() const; - /*! \brief Sets FSK frequency deviation from carrier frequency. Allowed values depend on bit rate setting and must be lower than 200 kHz. Only available in FSK mode. \param freqDev Frequency deviation to be set (in kHz). @@ -1295,7 +1289,6 @@ class SX127x: public PhysicalLayer { float bitRate = 0, frequencyDev = 0; bool crcOn = true; // default value used in FSK mode - float dataRate = 0; bool packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once uint8_t packetLengthConfig = RADIOLIB_SX127X_PACKET_VARIABLE; uint8_t rxMode = RADIOLIB_SX127X_RXCONTINUOUS; From 08a7853a1ce70832d65bc1440efc271067f62c5c Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 31 Jan 2026 20:05:41 +0300 Subject: [PATCH 1785/1848] [LR2021] fix invalid GFSK payload length unit (#1687) --- src/modules/LR2021/LR2021.cpp | 4 ++-- src/modules/LR2021/LR2021_config.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 776a18a4e0..3a1c2b3722 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -894,7 +894,7 @@ int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) { state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled); } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) { state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening); @@ -1038,4 +1038,4 @@ uint8_t LR2021::randomByte() { return((uint8_t)num); } -#endif \ No newline at end of file +#endif diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 0ae1555bfc..0dac2ea086 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -289,7 +289,7 @@ int16_t LR2021::setPreambleLength(size_t preambleLength) { } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { this->preambleLengthGFSK = preambleLength; this->preambleDetLength = (preambleLength / 8) << 3; - return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { this->preambleLengthGFSK = preambleLength; @@ -383,7 +383,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool this->crcTypeGFSK += 0x08; } - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); return(setGfskCrcParams(initial, polynomial)); @@ -702,7 +702,7 @@ int16_t LR2021::setWhitening(bool enabled, uint16_t initial) { RADIOLIB_ASSERT(state); } this->whitening = enabled; - return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); case(RADIOLIB_LR2021_PACKET_TYPE_OOK): this->whitening = enabled; @@ -836,7 +836,7 @@ int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { RADIOLIB_ASSERT(state); if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { // set requested packet mode - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); // update cached value @@ -902,7 +902,7 @@ int16_t LR2021::setNodeAddress(uint8_t nodeAddr) { // enable address filtering (node only) this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE; - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); // set node address @@ -921,7 +921,7 @@ int16_t LR2021::setBroadcastAddress(uint8_t broadAddr) { // enable address filtering (node and broadcast) this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST; - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); // set node and broadcast address @@ -939,7 +939,7 @@ int16_t LR2021::disableAddressFiltering() { // disable address filtering this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED; - return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, true, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); } int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool syncRaw, bool rising, uint8_t sofLen) { @@ -1025,4 +1025,4 @@ int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numD return(setLoRaSideDetSyncword(syncWords, numDetectors)); } -#endif +#endif \ No newline at end of file From 95516cbae0b44c3ebc1c52b0273e3ed02333a69d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 31 Jan 2026 18:12:10 +0000 Subject: [PATCH 1786/1848] [LR2021] Optimize RxBw config --- src/modules/LR2021/LR2021.h | 1 + src/modules/LR2021/LR2021_config.cpp | 121 ++++++++++++++------------- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 993ba6ca15..ead57a42a4 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -688,6 +688,7 @@ class LR2021: public LRxxxx { int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); + int16_t findRxBw(float rxBw, uint8_t* val); // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 0dac2ea086..1b13f66b89 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -502,6 +502,65 @@ int16_t LR2021::setFrequencyDeviation(float freqDev) { return(state); } +int16_t LR2021::findRxBw(float rxBw, uint8_t* val) { + // lookup tables to avoid comparing a whole bunch of floats + uint16_t rxBwAvg[] = { + 53, 66, 85, 108, 134, 170, 211, 264, + 341, 424, 529, 682, 847, 1058, 1364, + 1695, 2116, 2729, 3390, 4233, 5159, + 6111, 7179, 9401, 16665, 24440, 28710, + }; + uint8_t rxBwRaw[] = { + RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666, + RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076, + }; + + // iterate through the table and find whether the user-provided value + // is lower than the pre-computed average of the adjacent bandwidth values + // if it is, we consider that to be a match even though the actual value is not precise + uint16_t rxBwInt = rxBw*10.0f; + for(size_t i = 0; i < sizeof(rxBwAvg)/sizeof(rxBwAvg[0]); i++) { + if(rxBwInt < rxBwAvg[i]) { + *val = rxBwRaw[i]; + return(RADIOLIB_ERR_NONE); + } + } + + // if nothing matched up to here, match with the last value + if(rxBwInt <= 30760) { + *val = rxBwRaw[sizeof(rxBwRaw) - 1]; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); +} + int16_t LR2021::setRxBandwidth(float rxBw) { // check active modem uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; @@ -512,66 +571,8 @@ int16_t LR2021::setRxBandwidth(float rxBw) { return(RADIOLIB_ERR_WRONG_MODEM); } - // check allowed receiver bandwidth values - if(fabsf(rxBw - 4.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8; - } else if(fabsf(rxBw - 5.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8; - } else if(fabsf(rxBw - 7.4f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4; - } else if(fabsf(rxBw - 9.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7; - } else if(fabsf(rxBw - 12.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0; - } else if(fabsf(rxBw - 14.9f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9; - } else if(fabsf(rxBw - 19.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2; - } else if(fabsf(rxBw - 23.1f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1; - } else if(fabsf(rxBw - 29.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8; - } else if(fabsf(rxBw - 38.5f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5; - } else if(fabsf(rxBw - 46.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3; - } else if(fabsf(rxBw - 59.5f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5; - } else if(fabsf(rxBw - 76.9f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9; - } else if(fabsf(rxBw - 92.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6; - } else if(fabsf(rxBw - 119.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0; - } else if(fabsf(rxBw - 153.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8; - } else if(fabsf(rxBw - 185.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2; - } else if(fabsf(rxBw - 238.1f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1; - } else if(fabsf(rxBw - 307.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7; - } else if(fabsf(rxBw - 370.4f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4; - } else if(fabsf(rxBw - 476.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2; - } else if(fabsf(rxBw - 555.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6; - } else if(fabsf(rxBw - 666.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7; - } else if(fabsf(rxBw - 769.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2; - } else if(fabsf(rxBw - 1111.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111; - } else if(fabsf(rxBw - 2222.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222; - } else if(fabsf(rxBw - 2666.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666; - } else if(fabsf(rxBw - 3076.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076; - } else { - return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); - } + state = findRxBw(rxBw, &this->rxBandwidth); + RADIOLIB_ASSERT(state); // update modulation parameters if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { From 925f516e2e306d99d30d8abb91eaf37932e4746f Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 31 Jan 2026 23:13:30 +0300 Subject: [PATCH 1787/1848] [LR2021] a fix for reverse order of bytes in GFSK sync word (#1686) --- src/modules/LR2021/LR2021_cmds_gfsk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_cmds_gfsk.cpp b/src/modules/LR2021/LR2021_cmds_gfsk.cpp index c0c1b7e324..6aeeec79f7 100644 --- a/src/modules/LR2021/LR2021_cmds_gfsk.cpp +++ b/src/modules/LR2021/LR2021_cmds_gfsk.cpp @@ -47,8 +47,8 @@ int16_t LR2021::setGfskCrcParams(uint32_t poly, uint32_t init) { int16_t LR2021::setGfskSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { uint8_t buff[9] = { 0 }; - for(size_t i = 0; i < syncWordLen; i++) { - buff[7 - i] = syncWord[i]; + for(int8_t i = 7; i >= (int8_t) (RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN - syncWordLen); i--) { + buff[i] = syncWord[i - (int8_t) (RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN - syncWordLen)]; } buff[8] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_GFSK_SYNCWORD, true, buff, sizeof(buff))); From 4eecf2216dc14d78c8c808750101cd8f899bff12 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Feb 2026 07:47:23 +0000 Subject: [PATCH 1788/1848] [LR11x0] Move optimized RxBw config to base class --- src/modules/LR11x0/LR11x0.cpp | 72 ++++++++++------------------ src/modules/LR11x0/LR_common.cpp | 29 +++++++++++ src/modules/LR11x0/LR_common.h | 1 + src/modules/LR2021/LR2021.h | 1 - src/modules/LR2021/LR2021_config.cpp | 52 +++++--------------- 5 files changed, 68 insertions(+), 87 deletions(-) diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index 52b3d5dbf7..a254f1f8ad 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -681,52 +681,32 @@ int16_t LR11x0::setRxBandwidth(float rxBw) { return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS); }*/ - // check allowed receiver bandwidth values - if(fabsf(rxBw - 4.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8; - } else if(fabsf(rxBw - 5.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8; - } else if(fabsf(rxBw - 7.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3; - } else if(fabsf(rxBw - 9.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7; - } else if(fabsf(rxBw - 11.7f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7; - } else if(fabsf(rxBw - 14.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6; - } else if(fabsf(rxBw - 19.5f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5; - } else if(fabsf(rxBw - 23.4f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4; - } else if(fabsf(rxBw - 29.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3; - } else if(fabsf(rxBw - 39.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0; - } else if(fabsf(rxBw - 46.9f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9; - } else if(fabsf(rxBw - 58.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6; - } else if(fabsf(rxBw - 78.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2; - } else if(fabsf(rxBw - 93.8f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8; - } else if(fabsf(rxBw - 117.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3; - } else if(fabsf(rxBw - 156.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2; - } else if(fabsf(rxBw - 187.2f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2; - } else if(fabsf(rxBw - 234.3f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3; - } else if(fabsf(rxBw - 312.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0; - } else if(fabsf(rxBw - 373.6f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6; - } else if(fabsf(rxBw - 467.0f) <= 0.001f) { - this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0; - } else { - return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); - } + const uint8_t rxBwLut[] = { + RADIOLIB_LR11X0_GFSK_RX_BW_4_8, + RADIOLIB_LR11X0_GFSK_RX_BW_5_8, + RADIOLIB_LR11X0_GFSK_RX_BW_7_3, + RADIOLIB_LR11X0_GFSK_RX_BW_9_7, + RADIOLIB_LR11X0_GFSK_RX_BW_11_7, + RADIOLIB_LR11X0_GFSK_RX_BW_14_6, + RADIOLIB_LR11X0_GFSK_RX_BW_19_5, + RADIOLIB_LR11X0_GFSK_RX_BW_23_4, + RADIOLIB_LR11X0_GFSK_RX_BW_29_3, + RADIOLIB_LR11X0_GFSK_RX_BW_39_0, + RADIOLIB_LR11X0_GFSK_RX_BW_46_9, + RADIOLIB_LR11X0_GFSK_RX_BW_58_6, + RADIOLIB_LR11X0_GFSK_RX_BW_78_2, + RADIOLIB_LR11X0_GFSK_RX_BW_93_8, + RADIOLIB_LR11X0_GFSK_RX_BW_117_3, + RADIOLIB_LR11X0_GFSK_RX_BW_156_2, + RADIOLIB_LR11X0_GFSK_RX_BW_187_2, + RADIOLIB_LR11X0_GFSK_RX_BW_234_3, + RADIOLIB_LR11X0_GFSK_RX_BW_312_0, + RADIOLIB_LR11X0_GFSK_RX_BW_373_6, + RADIOLIB_LR11X0_GFSK_RX_BW_467_0, + }; + + state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 467.0f, &this->rxBandwidth); + RADIOLIB_ASSERT(state); // update modulation parameters state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); diff --git a/src/modules/LR11x0/LR_common.cpp b/src/modules/LR11x0/LR_common.cpp index 775d7ca0b2..cf70628496 100644 --- a/src/modules/LR11x0/LR_common.cpp +++ b/src/modules/LR11x0/LR_common.cpp @@ -300,6 +300,35 @@ uint8_t LRxxxx::roundRampTime(uint32_t rampTimeUs) { return regVal; } +int16_t LRxxxx::findRxBw(float rxBw, const uint8_t* lut, size_t lutSize, float rxBwMax, uint8_t* val) { + // lookup tables to avoid comparing a whole bunch of floats + const uint16_t rxBwAvg[] = { + 53, 66, 85, 108, 134, 170, 211, 264, + 341, 424, 529, 682, 847, 1058, 1364, + 1695, 2116, 2729, 3390, 4233, 5159, + 6111, 7179, 9401, 16665, 24440, 28710, + }; + + // iterate through the table and find whether the user-provided value + // is lower than the pre-computed average of the adjacent bandwidth values + // if it is, we consider that to be a match even though the actual value is not precise + uint16_t rxBwInt = rxBw*10.0f; + for(size_t i = 0; i < lutSize; i++) { + if(rxBwInt < rxBwAvg[i]) { + *val = lut[i]; + return(RADIOLIB_ERR_NONE); + } + } + + // if nothing matched up to here, match with the last value + if(rxBwInt <= rxBwMax*10) { + *val = lut[lutSize - 1]; + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); +} + int16_t LRxxxx::setU32(uint16_t cmd, uint32_t u32) { uint8_t buff[] = { (uint8_t)((u32 >> 24) & 0xFF), (uint8_t)((u32 >> 16) & 0xFF), diff --git a/src/modules/LR11x0/LR_common.h b/src/modules/LR11x0/LR_common.h index 4a097d762d..0cc5634692 100644 --- a/src/modules/LR11x0/LR_common.h +++ b/src/modules/LR11x0/LR_common.h @@ -189,6 +189,7 @@ class LRxxxx: public PhysicalLayer { int16_t getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq); int16_t lrFhssBuildFrame(uint16_t cmd, uint8_t hdrCount, uint8_t cr, uint8_t grid, uint8_t hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, const uint8_t* payload, size_t len); uint8_t roundRampTime(uint32_t rampTimeUs); + int16_t findRxBw(float rxBw, const uint8_t* lut, size_t lutSize, float rxBwMax, uint8_t* val); RadioLibTime_t getTimeOnAir(size_t len, ModemType_t modem); // several commands just send unsigned 32-bit number diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index ead57a42a4..993ba6ca15 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -688,7 +688,6 @@ class LR2021: public LRxxxx { int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); - int16_t findRxBw(float rxBw, uint8_t* val); // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 1b13f66b89..df3d6f7fbc 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -502,15 +502,17 @@ int16_t LR2021::setFrequencyDeviation(float freqDev) { return(state); } -int16_t LR2021::findRxBw(float rxBw, uint8_t* val) { - // lookup tables to avoid comparing a whole bunch of floats - uint16_t rxBwAvg[] = { - 53, 66, 85, 108, 134, 170, 211, 264, - 341, 424, 529, 682, 847, 1058, 1364, - 1695, 2116, 2729, 3390, 4233, 5159, - 6111, 7179, 9401, 16665, 24440, 28710, - }; - uint8_t rxBwRaw[] = { +int16_t LR2021::setRxBandwidth(float rxBw) { + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || + (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) { + return(RADIOLIB_ERR_WRONG_MODEM); + } + + const uint8_t rxBwLut[] = { RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8, RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8, RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4, @@ -541,37 +543,7 @@ int16_t LR2021::findRxBw(float rxBw, uint8_t* val) { RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076, }; - // iterate through the table and find whether the user-provided value - // is lower than the pre-computed average of the adjacent bandwidth values - // if it is, we consider that to be a match even though the actual value is not precise - uint16_t rxBwInt = rxBw*10.0f; - for(size_t i = 0; i < sizeof(rxBwAvg)/sizeof(rxBwAvg[0]); i++) { - if(rxBwInt < rxBwAvg[i]) { - *val = rxBwRaw[i]; - return(RADIOLIB_ERR_NONE); - } - } - - // if nothing matched up to here, match with the last value - if(rxBwInt <= 30760) { - *val = rxBwRaw[sizeof(rxBwRaw) - 1]; - return(RADIOLIB_ERR_NONE); - } - - return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH); -} - -int16_t LR2021::setRxBandwidth(float rxBw) { - // check active modem - uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; - int16_t state = getPacketType(&type); - RADIOLIB_ASSERT(state); - if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || - (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) { - return(RADIOLIB_ERR_WRONG_MODEM); - } - - state = findRxBw(rxBw, &this->rxBandwidth); + state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 3076.0f, &this->rxBandwidth); RADIOLIB_ASSERT(state); // update modulation parameters From bcde610d15bda02af0e907e6299055e5b399b4db Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sun, 1 Feb 2026 10:55:33 +0300 Subject: [PATCH 1789/1848] [LR2021] set max limit of GFSK frequency deviation in accordance with datasheet (#1689) --- src/modules/LR2021/LR2021.h | 2 +- src/modules/LR2021/LR2021_config.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 993ba6ca15..59e28f33c8 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -442,7 +442,7 @@ class LR2021: public LRxxxx { int16_t setBitRate(float br) override; /*! - \brief Sets GFSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz. + \brief Sets GFSK frequency deviation. Allowed values range from 0.6 to 500.0 kHz. \param freqDev GFSK frequency deviation to be set in kHz. \returns \ref status_codes */ diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index df3d6f7fbc..9fa725ef18 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -492,11 +492,11 @@ int16_t LR2021::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for digimodes) float newFreqDev = freqDev; - if(freqDev < 0.0f) { + if(freqDev < 0.6f) { newFreqDev = 0.6f; } - RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); this->frequencyDev = newFreqDev * 1000.0f; state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); return(state); @@ -756,7 +756,7 @@ int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) { // select interpretation based on modem if(modem == RADIOLIB_MODEM_FSK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); - RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_MODEM_LORA) { @@ -998,4 +998,4 @@ int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numD return(setLoRaSideDetSyncword(syncWords, numDetectors)); } -#endif \ No newline at end of file +#endif From 97263cd42ecbf952e73cf5c7a426333a2233be7f Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sun, 1 Feb 2026 13:06:57 +0300 Subject: [PATCH 1790/1848] [LR2021] fix for no-CRC GFSK and OOK operations when inverted bit is set (default) (#1688) --- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 9fa725ef18..98d6ea50b2 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -379,7 +379,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool } this->crcTypeGFSK = len; - if(inverted) { + if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) { this->crcTypeGFSK += 0x08; } @@ -394,7 +394,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool } this->crcTypeGFSK = len; - if(inverted) { + if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) { this->crcTypeGFSK += 0x08; } From 1c5b02ece16aecb429f1a256b5c23956a007ce9d Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sun, 1 Feb 2026 13:07:22 +0300 Subject: [PATCH 1791/1848] [LR2021] set max limit of GFSK/OOK bit rate in accordance with datasheet (#1690) --- src/modules/LR2021/LR2021.h | 2 +- src/modules/LR2021/LR2021_config.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 59e28f33c8..03612ebb19 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -435,7 +435,7 @@ class LR2021: public LRxxxx { int16_t invertIQ(bool enable) override; /*! - \brief Sets GFSK bit rate. Allowed values range from 0.6 to 300.0 kbps. + \brief Sets GFSK bit rate. Allowed values range from 0.5 to 2000.0 kbps. \param br FSK bit rate to be set in kbps. \returns \ref status_codes */ diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 98d6ea50b2..c4e97afbb5 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -435,14 +435,14 @@ int16_t LR2021::setBitRate(float br) { int16_t state = getPacketType(&type); RADIOLIB_ASSERT(state); if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { - RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE); //! \TODO: [LR2021] implement fractional bit rate configuration this->bitRate = br * 1000.0f; state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev); return(state); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { - RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE); //! \TODO: [LR2021] implement fractional bit rate configuration this->bitRate = br * 1000.0f; //! \TODO: [LR2021] implement OOK magnitude depth configuration @@ -755,8 +755,8 @@ int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) { // select interpretation based on modem if(modem == RADIOLIB_MODEM_FSK) { - RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); - RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); + RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE); + RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_MODEM_LORA) { From a73d92693a259e5bf8197b94f604aeebe94aced6 Mon Sep 17 00:00:00 2001 From: Olivier Ouellet <85790609+olivierouellet@users.noreply.github.com> Date: Sun, 1 Feb 2026 07:29:41 -0500 Subject: [PATCH 1792/1848] [HAL] Fix overflow bug by adding casting to delay(), delayMicroseconds(), millis() and micros() (#1691) * Fix overflow bug by adding casting to delay(), delayMicroseconds(), millis() and micros() * Change final casting to RadioLibTime_t --- src/hal/Arduino/ArduinoHal.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hal/Arduino/ArduinoHal.cpp b/src/hal/Arduino/ArduinoHal.cpp index 0f3dd3bb4e..9af7c183c6 100644 --- a/src/hal/Arduino/ArduinoHal.cpp +++ b/src/hal/Arduino/ArduinoHal.cpp @@ -57,7 +57,7 @@ void inline ArduinoHal::delay(RadioLibTime_t ms) { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) ::delay(ms); #else - ::delay(ms * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); + ::delay((RadioLibTime_t)((uint64_t)ms * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS))); #endif } @@ -65,7 +65,7 @@ void inline ArduinoHal::delayMicroseconds(RadioLibTime_t us) { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) ::delayMicroseconds(us); #else - ::delayMicroseconds(us * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); + ::delayMicroseconds((RadioLibTime_t)((uint64_t)us * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS))); #endif } @@ -73,7 +73,7 @@ RadioLibTime_t inline ArduinoHal::millis() { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) return(::millis()); #else - return(::millis() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); + return (RadioLibTime_t)((uint64_t)::millis() * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS)); #endif } @@ -81,7 +81,7 @@ RadioLibTime_t inline ArduinoHal::micros() { #if !defined(RADIOLIB_CLOCK_DRIFT_MS) return(::micros()); #else - return(::micros() * 1000 / (1000 + RADIOLIB_CLOCK_DRIFT_MS)); + return (RadioLibTime_t)((uint64_t)::micros() * 1000ULL / (1000ULL + (uint64_t)RADIOLIB_CLOCK_DRIFT_MS)); #endif } From f1de01d459dcba7ca808fc9442d6d5aa307b7231 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 1 Feb 2026 14:48:28 +0100 Subject: [PATCH 1793/1848] [LoRaWAN] Fix dutycycle not enforced (#1682) --- src/TypeDef.h | 2 +- src/protocols/LoRaWAN/LoRaWAN.cpp | 49 +++++++++++++++++++------------ src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index c27e148c5e..d1075a43f9 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -534,7 +534,7 @@ #define RADIOLIB_ERR_INVALID_CID (-1107) /*! - \brief User requested to start uplink while still inside RX window or under dutycycle. + \brief User requested to start uplink while under dutycycle. */ #define RADIOLIB_ERR_UPLINK_UNAVAILABLE (-1108) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 4c20469b34..2858eddb87 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -82,6 +82,20 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP return(RADIOLIB_ERR_NETWORK_NOT_JOINED); } + Module *mod = this->phyLayer->getMod(); + RadioLibTime_t tNow = mod->hal->millis(); + // if scheduled uplink time is in the past, reschedule to now + if(this->tUplink < tNow) { + this->tUplink = tNow; + } + + // if dutycycle is enabled and the time since last uplink + interval has not elapsed, return an error + if(this->dutyCycleEnabled) { + if(this->tUplinkEnd + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) { + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + } + if(lenUp == 0 && fPort == 0) { this->isMACPayload = true; } @@ -154,8 +168,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // send it (without the MIC calculation blocks) state = this->transmitUplink(&this->channels[RADIOLIB_LORAWAN_UPLINK], &uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], - (uint8_t)(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS), - trans > 0); + (uint8_t)(uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS)); if(state != RADIOLIB_ERR_NONE) { // sometimes, a spurious error can occur even though the uplink was transmitted // therefore, just to be safe, increase frame counter by one for the next uplink @@ -912,6 +925,20 @@ int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) { this->createSession(); } + Module *mod = this->phyLayer->getMod(); + RadioLibTime_t tNow = mod->hal->millis(); + // if scheduled uplink time is in the past, reschedule to now + if(this->tUplink < tNow) { + this->tUplink = tNow; + } + + // if dutycycle is enabled and the time since last uplink + interval has not elapsed, return an error + if(this->dutyCycleEnabled) { + if(this->tUplinkEnd + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) { + return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); + } + } + // starting a new session, so make sure to update event fields already if(joinEvent) { joinEvent->newSession = true; @@ -1378,24 +1405,10 @@ void LoRaWANNode::micUplink(uint8_t* inOut, size_t lenInOut) { } } -int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans) { +int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len) { int16_t state = RADIOLIB_ERR_UNKNOWN; Module* mod = this->phyLayer->getMod(); - RadioLibTime_t tNow = mod->hal->millis(); - // if scheduled uplink time is in the past, reschedule to now - if(this->tUplink < tNow) { - this->tUplink = tNow; - } - - // if dutycycle is enabled and the time since last uplink + interval has not elapsed, return an error - // but: don't check this for retransmissions - if(!retrans && this->dutyCycleEnabled) { - if(this->tUplinkEnd + (RadioLibTime_t)dutyCycleInterval(this->dutyCycle, this->lastToA) > this->tUplink) { - return(RADIOLIB_ERR_UPLINK_UNAVAILABLE); - } - } - const uint8_t currentDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; const ModemType_t modem = this->band->dataRates[currentDr].modem; const DataRate_t* dr = &this->band->dataRates[currentDr].dr; @@ -1423,7 +1436,7 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u RADIOLIB_ASSERT(state); // if requested, wait until transmitting uplink - tNow = mod->hal->millis(); + RadioLibTime_t tNow = mod->hal->millis(); if(this->tUplink > tNow + this->launchDuration) { RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Delaying transmission by %lu ms", (unsigned long)(this->tUplink - tNow - this->launchDuration)); tNow = mod->hal->millis(); diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index de2cc055ac..19422a9f50 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -1130,7 +1130,7 @@ class LoRaWANNode { void micUplink(uint8_t* inOut, size_t lenInOut); // transmit uplink buffer on a specified channel - int16_t transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len, bool retrans = false); + int16_t transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, uint8_t len); // handle one of the Class A receive windows with a given channel and certain timestamps int16_t receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChannel, uint8_t window, const RadioLibTime_t dlDelay, RadioLibTime_t tReference); From bf49141046d072b6ed08ff989520d3a10c630c1f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Feb 2026 20:19:12 +0000 Subject: [PATCH 1794/1848] [LR2021] Extend allowed frequency range to 1090 MHz --- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index c4e97afbb5..24f4d9e2c3 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -16,7 +16,7 @@ int16_t LR2021::setFrequency(float freq) { int16_t LR2021::setFrequency(float freq, bool skipCalibration) { #if RADIOLIB_CHECK_PARAMS - if(!(((freq >= 150.0f) && (freq <= 960.0f)) || + if(!(((freq >= 150.0f) && (freq <= 1090.0f)) || ((freq >= 1900.0f) && (freq <= 2200.0f)) || ((freq >= 2400.0f) && (freq <= 2500.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); @@ -66,7 +66,7 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { state = setRfFrequency((uint32_t)(freq*1000000.0f)); RADIOLIB_ASSERT(state); this->freqMHz = freq; - this->highFreq = (freq > 1000.0f); + this->highFreq = (freq > 1100.0f); return(state); } From aedddcd77b2e8e6b37e68f3ece6c62d5331ffb4d Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Feb 2026 20:19:47 +0000 Subject: [PATCH 1795/1848] [LR2021] Allow empty sync words --- src/modules/LR2021/LR2021_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 24f4d9e2c3..507b144d2a 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -556,7 +556,7 @@ int16_t LR2021::setRxBandwidth(float rxBw) { } int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) { - if((!syncWord) || (!len) || (len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN)) { + if(len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN) { return(RADIOLIB_ERR_INVALID_SYNC_WORD); } From 10e0eb22df7c65f07a1213fa30aacd06cca5ffb3 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 1 Feb 2026 20:29:21 +0000 Subject: [PATCH 1796/1848] [LR2021] Fix packet mode not being applied correctly for GFSK and OOK --- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 507b144d2a..0ca30f7f2f 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -809,7 +809,7 @@ int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { RADIOLIB_ASSERT(state); if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { // set requested packet mode - state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); + state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); // update cached value @@ -818,7 +818,7 @@ int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) { } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { // set requested packet mode - state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, len, this->crcTypeGFSK, this->whitening); + state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); // update cached value From bf7a08270387fb8dec59331b42bd2a25826c824b Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 Feb 2026 15:31:46 +0000 Subject: [PATCH 1797/1848] [LR2021] Fix OOK Manchester encoding configuration --- src/modules/LR2021/LR2021_cmds_ook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 1b0406f8cb..7d473f9b4b 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -21,7 +21,7 @@ int16_t LR2021::setOokPacketParams(uint16_t preambleLen, uint8_t addrComp, uint8 (uint8_t)((preambleLen >> 8) & 0xFF), (uint8_t)(preambleLen & 0xFF), (uint8_t)((addrComp << 2) | ((uint8_t)packetFormat & 0x03)), (uint8_t)((payloadLen >> 8) & 0xFF), (uint8_t)(payloadLen & 0xFF), - (uint8_t)((crc << 4) | (manchester << 4)), + (uint8_t)(((crc << 4) & 0xF0) | (manchester & 0x0F)), }; return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS, true, buff, sizeof(buff))); } From 1569b5e9bdc6f8ec10f8bebb8773f2978fda79a9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 Feb 2026 15:32:22 +0000 Subject: [PATCH 1798/1848] [LR2021] Fix instant RSSI measurement --- src/modules/LR2021/LR2021.cpp | 4 +++- src/modules/LR2021/LR2021.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 3a1c2b3722..f3408cad40 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -995,12 +995,14 @@ float LR2021::getRSSI() { return(this->getRSSI(true)); } -float LR2021::getRSSI(bool packet) { +float LR2021::getRSSI(bool packet, bool skipReceive) { float rssi = 0; int16_t state; if(!packet) { // get instantaneous RSSI value + if(!skipReceive) { (void)startReceive(); } state = this->getRssiInst(&rssi); + if(!skipReceive) { (void)standby(); } if(state != RADIOLIB_ERR_NONE) { return(0); } return(rssi); } diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 03612ebb19..bb9de59982 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -604,9 +604,10 @@ class LR2021: public LRxxxx { /*! \brief Gets RSSI (Recorded Signal Strength Indicator). \param packet Whether to read last packet RSSI, or the current value. + \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. \returns RSSI value in dBm. */ - float getRSSI(bool packet); + float getRSSI(bool packet, bool skipReceive = false); /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. From 4f3d2abcbcb234603a05f192ee0714e3ce363720 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 3 Feb 2026 15:33:08 +0000 Subject: [PATCH 1799/1848] [LR2021] Make gain config method public --- src/modules/LR2021/LR2021.h | 8 ++++++++ src/modules/LR2021/LR2021_cmds_radio.cpp | 4 ---- src/modules/LR2021/LR2021_config.cpp | 7 +++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index bb9de59982..8e7d4a5a89 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -662,6 +662,14 @@ class LR2021: public LRxxxx { */ int16_t setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors); + /*! + \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 13, + where 13 is the highest gain. Set to 0 to enable automatic gain control (recommended). + \param gain Gain of receiver LNA (low-noise amplifier) to be set. + \returns \ref status_codes + */ + int16_t setGain(uint8_t gain); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index 4e69f60c93..f8394d5a7a 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -76,10 +76,6 @@ int16_t LR2021::getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg) { return(state); } -int16_t LR2021::setAgcGainManual(uint8_t gain) { - return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain))); -} - int16_t LR2021::setCadParams(uint32_t cadTimeout, uint8_t threshold, uint8_t exitMode, uint32_t trxTimeout) { uint8_t buff[] = { (uint8_t)((cadTimeout >> 16) & 0xFF), (uint8_t)((cadTimeout >> 8) & 0xFF), (uint8_t)(cadTimeout & 0xFF), diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 0ca30f7f2f..15bc2c1024 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -998,4 +998,11 @@ int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numD return(setLoRaSideDetSyncword(syncWords, numDetectors)); } +int16_t LR2021::setGain(uint8_t gain) { + if(gain > 13) { + return(RADIOLIB_ERR_INVALID_GAIN); + } + return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain))); +} + #endif From ce816306cb0bf0dffc533c3a399b843ac56831b8 Mon Sep 17 00:00:00 2001 From: Olivier Ouellet <85790609+olivierouellet@users.noreply.github.com> Date: Thu, 5 Feb 2026 01:17:58 -0500 Subject: [PATCH 1800/1848] Potential overflow fix for RADIOLIB_SPI_PARANOID (#1698) --- src/Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.cpp b/src/Module.cpp index 4ed06b468f..b0a616085e 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -81,7 +81,7 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t #if RADIOLIB_DEBUG_SPI uint8_t readValue = 0x00; #endif - while(this->hal->micros() - start < (checkInterval * 1000)) { + while(this->hal->micros() - start < ((RadioLibTime_t)checkInterval * 1000UL)) { uint8_t val = SPIreadRegister(reg); if((val & checkMask) == (newValue & checkMask)) { // check passed, we can stop the loop From d3eabae9792916746a2a46cd5127548f7353cbf7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 5 Feb 2026 16:40:59 +0000 Subject: [PATCH 1801/1848] [MOD] Clarify rationale for skipping counter init (#1696) --- src/Module.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Module.cpp b/src/Module.cpp index b0a616085e..138db69dbf 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -433,6 +433,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write for(n = 0; n < cmdLen; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("\t"); } + // initialization of n to 0 is skipped here, because we want to skip the command bytes for(; n < buffLen; n++) { RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]); } From 490af9b116193d626a86712931b22337f4d2384c Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 5 Feb 2026 17:49:34 +0000 Subject: [PATCH 1802/1848] [LR2021] Fix encoding configuration for OOK Manchester --- src/modules/LR2021/LR2021_config.cpp | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 15bc2c1024..c2b345b7f0 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -650,7 +650,34 @@ int16_t LR2021::setDataShaping(uint8_t sh) { } int16_t LR2021::setEncoding(uint8_t encoding) { - return(setWhitening(encoding)); + // check active modem + uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; + int16_t state = getPacketType(&type); + RADIOLIB_ASSERT(state); + + switch(type) { + case(RADIOLIB_LR2021_PACKET_TYPE_GFSK): + return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING)); + + case(RADIOLIB_LR2021_PACKET_TYPE_OOK): + switch(encoding) { + case(RADIOLIB_ENCODING_NRZ): + case(RADIOLIB_ENCODING_WHITENING): + return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING)); + case(RADIOLIB_ENCODING_MANCHESTER): + case(RADIOLIB_ENCODING_MANCHESTER_INV): + state = setWhitening(false); + this->whitening = encoding; + return(state); + default: + return(RADIOLIB_ERR_INVALID_ENCODING); + } + + default: + return(RADIOLIB_ERR_WRONG_MODEM); + } + + return(state); } int16_t LR2021::fixedPacketLengthMode(uint8_t len) { From 368237a4474057b2de783204cce2ee12ff6ea658 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 5 Feb 2026 17:50:20 +0000 Subject: [PATCH 1803/1848] [LR2021] Add method to configure OOK threshold --- src/modules/LR2021/LR2021.h | 8 +++++++- src/modules/LR2021/LR2021_config.cpp | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 8e7d4a5a89..7e71d4929a 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -645,6 +645,13 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t ookDetector(uint16_t pattern = 0x0285, uint8_t len = 16, uint8_t repeats = 0, bool syncRaw = false, bool rising = false, uint8_t sofLen = 0); + + /*! + \brief Set OOK detection threshold. + \param level Threshold level in dB + \returns \ref status_codes + */ + int16_t setOokDetectionThreshold(int16_t level); /*! \brief Configure LoRa side detector, which enables to detect mutiple spreading factors and receive one of them. @@ -751,7 +758,6 @@ class LR2021: public LRxxxx { int16_t getTimestampValue(uint8_t index, uint32_t* timestamp); int16_t setCca(uint32_t duration, uint8_t gain); int16_t getCcaResult(float* rssiMin, float* rssiMax, float* rssiAvg); - int16_t setAgcGainManual(uint8_t gain); int16_t setCadParams(uint32_t cadTimeout, uint8_t threshold, uint8_t exitMode, uint32_t trxTimeout); int16_t setCad(void); int16_t selPa(uint8_t pa); diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index c2b345b7f0..68e56c7fc5 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -1,6 +1,7 @@ #include "LR2021.h" #include "../LR11x0/LR_common.h" +#include "LR2021_registers.h" #include #include @@ -954,6 +955,11 @@ int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen)); } +int16_t LR2021::setOokDetectionThreshold(int16_t level) { + int16_t levelRaw = 64 + level; + return(this->writeRegMemMask32(RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD, (0x7FUL << 20), (uint32_t)levelRaw << 20)); +} + int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors) { // some basic sanity checks if((cfg == nullptr) || (numDetectors == 0)) { From e13aa3f3cfa22ee93026630568a3c542bece9c11 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 5 Feb 2026 17:52:03 +0000 Subject: [PATCH 1804/1848] [LR2021] Add inverted manchester encoding --- src/TypeDef.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/TypeDef.h b/src/TypeDef.h index d1075a43f9..84555b2585 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -61,6 +61,11 @@ */ #define RADIOLIB_ENCODING_WHITENING (0x02) +/*! + \brief Inverted Manchester encoding. +*/ +#define RADIOLIB_ENCODING_MANCHESTER_INV (0x03) + /*! \} */ From 74812e58df38648bbd0c1928499108f38ae5e027 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 6 Feb 2026 19:28:32 +0000 Subject: [PATCH 1805/1848] [MOD] Format stream bytes in debug with fixed width --- src/Module.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 138db69dbf..2ea328295b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -424,7 +424,9 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write } size_t n = 0; for(; n < cmdLen; n++) { - RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", cmd[n]); + // tab character intentionally omitted here + // command is a single number so this is easier to parse + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X", cmd[n]); } RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); @@ -435,12 +437,12 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write } // initialization of n to 0 is skipped here, because we want to skip the command bytes for(; n < buffLen; n++) { - RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffOut[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X\t", buffOut[n]); } RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); RADIOLIB_DEBUG_SPI_PRINT("SO\t"); for(n = 0; n < buffLen; n++) { - RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", buffIn[n]); + RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%02X\t", buffIn[n]); } RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(""); #endif From 35e9c3910ac137d795be513a20a429f6bdcff51e Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 7 Feb 2026 18:14:05 +0000 Subject: [PATCH 1806/1848] [LR2021] Fix CRC polynomial and init swapped --- src/modules/LR2021/LR2021.h | 2 +- src/modules/LR2021/LR2021_config.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 7e71d4929a..fb3a41ce40 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -639,7 +639,7 @@ class LR2021: public LRxxxx { \param pattern Preamble pattern, should end with 01 or 10 (binary). \param len Preamble pattern length in bits. \param repeats Number of preamble repeats, maximum of 31. - \param syncRaw Whether the sync word is send raw (unencoded) or encoded. Set to true for encoded sync word. + \param syncRaw Whether the sync word is send raw (unencoded) or encoded. Set to false for encoded sync word. \param rising Whether the start of frame delimiter edge is rising (true) or falling (false). \param sofLen Start-of-frame length in bits. \returns \ref status_codes diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index 68e56c7fc5..b454ffdeb0 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -387,7 +387,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); - return(setGfskCrcParams(initial, polynomial)); + return(setGfskCrcParams(polynomial, initial)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) { if(len > 4) { @@ -402,7 +402,7 @@ int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening); RADIOLIB_ASSERT(state); - return(setOokCrcParams(initial, polynomial)); + return(setOokCrcParams(polynomial, initial)); } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) { if((len == 1) || (len > 4)) { From 7ca6b3387f4a92bb5231f2d6becae68f5c9bf628 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 8 Feb 2026 15:45:44 +0100 Subject: [PATCH 1807/1848] [LoRaWAN] Move random's seed to session creation --- src/protocols/LoRaWAN/LoRaWAN.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 2858eddb87..c98ed94a1c 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -349,9 +349,6 @@ void LoRaWANNode::clearSession() { // revert to default Class A this->lwClass = RADIOLIB_LORAWAN_CLASS_A; - // set a seed for the pseudo-rng using a truly random value from radio noise - srand(this->phyLayer->random(INT32_MAX)); - // reset all channels memset(this->channels, 0, sizeof(this->channels)); memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels)); @@ -365,7 +362,10 @@ void LoRaWANNode::clearSession() { this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE; } -void LoRaWANNode::createSession() { +void LoRaWANNode::createSession() { + // set a seed for the pseudo-rng using a truly random value from radio noise + srand(this->phyLayer->random(INT32_MAX)); + // setup default channels if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { for(int num = 0; num < 3; num++) { From 4eb6443116f6e5e4c5605a99f32624248270d676 Mon Sep 17 00:00:00 2001 From: Olivier Ouellet <85790609+olivierouellet@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:50:20 -0500 Subject: [PATCH 1808/1848] [LoRaWAN] Fix for float not supported on newlib-nano (#1697) * Fix for float not supported on newlib-nano * Fix for unused variable warning * Change using RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT * Added RXParamSetupReq line * Delete added spaces for alignment * Changed 2 other macros printing floats --- src/BuildOpt.h | 18 ++++++++++++----- src/protocols/LoRaWAN/LoRaWAN.cpp | 32 +++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index ef2eb1d4f6..d6053d05fb 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -498,9 +498,11 @@ // some Arduino platforms do not support printf("%f"), so it has to be done this way #if defined(RADIOLIB_BUILD_ARDUINO) - #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) + #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) + #define RADIOLIB_DEBUG_PRINT_FLOAT_LVL(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL); RADIOLIB_DEBUG_PORT.print(VAL, DECIMALS) #else - #define RADIOLIB_DEBUG_PRINT_FLOAT(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) + #define RADIOLIB_DEBUG_PRINT_FLOAT(VAL, DECIMALS) RADIOLIB_DEBUG_PRINT("%.3f", VAL) + #define RADIOLIB_DEBUG_PRINT_FLOAT_LVL(LEVEL, VAL, DECIMALS) RADIOLIB_DEBUG_PRINT(LEVEL "%.3f", VAL) #endif #define RADIOLIB_DEBUG_HEXDUMP(LEVEL, ...) rlb_hexdump(LEVEL, __VA_ARGS__) @@ -520,9 +522,10 @@ #define RADIOLIB_DEBUG_BASIC_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) #define RADIOLIB_DEBUG_BASIC_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) - #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT_LVL(RADIOLIB_DEBUG_TAG_BASIC, __VA_ARGS__) #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) #define RADIOLIB_DEBUG_BASIC_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT_NOTAG(...) RADIOLIB_DEBUG_PRINT_FLOAT(__VA_ARGS__) #else #define RADIOLIB_DEBUG_BASIC_PRINT(...) {} #define RADIOLIB_DEBUG_BASIC_PRINTLN(...) {} @@ -530,15 +533,17 @@ #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_BASIC_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_BASIC_PRINTLN_NOTAG(...) {} + #define RADIOLIB_DEBUG_BASIC_PRINT_FLOAT_NOTAG(...) {} #endif #if RADIOLIB_DEBUG_PROTOCOL #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) #define RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) - #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT_LVL(RADIOLIB_DEBUG_TAG_PROTOCOL, __VA_ARGS__) #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG(...) RADIOLIB_DEBUG_PRINT_FLOAT(__VA_ARGS__) #else #define RADIOLIB_DEBUG_PROTOCOL_PRINT(...) {} #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN(...) {} @@ -546,15 +551,17 @@ #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_PROTOCOL_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(...) {} + #define RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG(...) {} #endif #if RADIOLIB_DEBUG_SPI #define RADIOLIB_DEBUG_SPI_PRINT(...) RADIOLIB_DEBUG_PRINT_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) #define RADIOLIB_DEBUG_SPI_PRINTLN(...) RADIOLIB_DEBUG_PRINTLN_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) #define RADIOLIB_DEBUG_SPI_HEXDUMP(...) RADIOLIB_DEBUG_HEXDUMP(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) - #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) RADIOLIB_DEBUG_PRINT_FLOAT_LVL(RADIOLIB_DEBUG_TAG_SPI, __VA_ARGS__) #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__) #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) RADIOLIB_DEBUG_PRINTLN(__VA_ARGS__) + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT_NOTAG(...) RADIOLIB_DEBUG_PRINT_FLOAT(__VA_ARGS__) #else #define RADIOLIB_DEBUG_SPI_PRINT(...) {} #define RADIOLIB_DEBUG_SPI_PRINTLN(...) {} @@ -562,6 +569,7 @@ #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT(...) {} #define RADIOLIB_DEBUG_SPI_PRINT_NOTAG(...) {} #define RADIOLIB_DEBUG_SPI_PRINTLN_NOTAG(...) {} + #define RADIOLIB_DEBUG_SPI_PRINT_FLOAT_NOTAG(...) {} #endif // debug info strings diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c98ed94a1c..babf8265db 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -2435,8 +2435,9 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin uint8_t rx2DrAck = 0; uint8_t rx2FreqAck = 0; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("RXParamSetupReq: Rx1DrOffset = %d, rx2DataRate = %d, freq = %7.3f", - macRx1DrOffset, macRx2Dr, macRx2Freq / 10000.0); + RADIOLIB_DEBUG_PROTOCOL_PRINT("RXParamSetupReq: Rx1DrOffset = %d, rx2DataRate = %d, freq = ", macRx1DrOffset, macRx2Dr); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG(macRx2Freq / 10000.0, 3); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(""); // check the requested configuration uint8_t uplinkDr = this->channels[RADIOLIB_LORAWAN_UPLINK].dr; @@ -2502,8 +2503,9 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin uint8_t macDrMax = (optIn[4] & 0xF0) >> 4; uint8_t macDrMin = optIn[4] & 0x0F; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq: index = %d, freq = %7.3f MHz, DR %d-%d", - macChIndex, macFreq / 10000.0, macDrMin, macDrMax); + RADIOLIB_DEBUG_PROTOCOL_PRINT("NewChannelReq: index = %d, freq = ", macChIndex); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG((double)macFreq / 10000.0, 3); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(" MHz, DR %d-%d", macDrMin, macDrMax); uint8_t drAck = 0; uint8_t freqAck = 0; @@ -2577,7 +2579,9 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin // get the configuration uint8_t macChIndex = optIn[0]; uint32_t macFreq = LoRaWANNode::ntoh(&optIn[1], 3); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("DlChannelReq: index = %d, freq = %7.3f MHz", macChIndex, macFreq / 10000.0); + RADIOLIB_DEBUG_PROTOCOL_PRINT("DlChannelReq: index = %d, freq = ", macChIndex); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG((double)macFreq / 10000.0, 3); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(" MHz"); uint8_t freqDlAck = 0; uint8_t freqUlAck = 0; @@ -3230,7 +3234,9 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, RADIOLIB_ASSERT(state); RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(""); - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Frequency = %7.3f MHz, TX = %d dBm", chnl->freq / 10000.0, pwr); + RADIOLIB_DEBUG_PROTOCOL_PRINT("Frequency = "); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG(chnl->freq / 10000.0, 3); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(" MHz, TX = %d dBm", pwr); state = this->phyLayer->setFrequency(chnl->freq / 10000.0); RADIOLIB_ASSERT(state); @@ -3257,8 +3263,12 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[1] = (uint8_t)(RADIOLIB_LORAWAN_GFSK_SYNC_WORD >> 8); syncWord[2] = (uint8_t)RADIOLIB_LORAWAN_GFSK_SYNC_WORD; syncWordLen = 3; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[FSK] BR = %4.1f, FD = %4.1f kHz", - (double)dr->fsk.bitRate, (double)dr->fsk.freqDev); + RADIOLIB_DEBUG_PROTOCOL_PRINT("[FSK] BR = "); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG((double)dr->fsk.bitRate, 1); + RADIOLIB_DEBUG_PROTOCOL_PRINT(", FD = "); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG((double)dr->fsk.freqDev, 1); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(" kHz"); + } break; case(ModemType_t::RADIOLIB_MODEM_LORA): { @@ -3273,8 +3283,10 @@ int16_t LoRaWANNode::setPhyProperties(const LoRaWANChannel_t* chnl, uint8_t dir, syncWord[0] = RADIOLIB_LORAWAN_LORA_SYNC_WORD; syncWordLen = 1; - RADIOLIB_DEBUG_PROTOCOL_PRINTLN("[LoRa] SF = %d, BW = %5.1f kHz, CR = 4/%d, IQ: %c", - dr->lora.spreadingFactor, (double)dr->lora.bandwidth, dr->lora.codingRate, dir ? 'D' : 'U'); + RADIOLIB_DEBUG_PROTOCOL_PRINT("[LoRa] SF = %d, BW = ", dr->lora.spreadingFactor); + RADIOLIB_DEBUG_PROTOCOL_PRINT_FLOAT_NOTAG((double)dr->lora.bandwidth, 1); + RADIOLIB_DEBUG_PROTOCOL_PRINTLN_NOTAG(" kHz, CR = 4/%d, IQ: %c", dr->lora.codingRate, dir ? 'D' : 'U'); + } break; case(ModemType_t::RADIOLIB_MODEM_LRFHSS): { From 87bf5785a3ca58dae184cff7b9860bef84a09b5c Mon Sep 17 00:00:00 2001 From: Olivier Ouellet <85790609+olivierouellet@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:50:54 -0500 Subject: [PATCH 1809/1848] [HAL] Add dwt_init() to ArduinoHal::init() for ARDUINO_ARCH_STM32 (#1701) --- src/hal/Arduino/ArduinoHal.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hal/Arduino/ArduinoHal.cpp b/src/hal/Arduino/ArduinoHal.cpp index 9af7c183c6..04989bcfd3 100644 --- a/src/hal/Arduino/ArduinoHal.cpp +++ b/src/hal/Arduino/ArduinoHal.cpp @@ -10,6 +10,9 @@ void ArduinoHal::init() { if(initInterface) { spiBegin(); } + #if defined(ARDUINO_ARCH_STM32) + dwt_init(); + #endif } void ArduinoHal::term() { From 116d975cdcaf138e3bdb96fba17a03adcc1fab7c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 12 Feb 2026 19:33:31 +0100 Subject: [PATCH 1810/1848] [LoRaWAN] Add band and class getters --- src/protocols/LoRaWAN/LoRaWAN.cpp | 8 ++++++++ src/protocols/LoRaWAN/LoRaWAN.h | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index babf8265db..eb7bd87671 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -3199,6 +3199,14 @@ void LoRaWANNode::scheduleTransmission(RadioLibTime_t tUplink) { this->tUplink = tUplink; } +const LoRaWANBand_t* LoRaWANNode::getBand() { + return(this->band); +} + +uint8_t LoRaWANNode::getClass() { + return(this->lwClass); +} + // return fCnt of last uplink; also return 0 if no uplink occured yet uint32_t LoRaWANNode::getFCntUp() { if(this->fCntUp == 0) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 19422a9f50..0babc59889 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -857,6 +857,18 @@ class LoRaWANNode { */ void scheduleTransmission(RadioLibTime_t tUplink); + /*! + \brief Get the LoRaWAN band used by this node. + \returns Pointer to the used band. + */ + const LoRaWANBand_t* getBand(); + + /*! + \brief Get the LoRaWAN class of this node. + \returns Class type (RADIOLIB_LORAWAN_CLASS_*). + */ + uint8_t getClass(); + /*! \brief Returns the last uplink's frame counter; also 0 if no uplink occured yet. From 5b901a33338887e38960b6972358e19cc938f1b4 Mon Sep 17 00:00:00 2001 From: Vladislav Date: Fri, 13 Feb 2026 16:40:32 +0300 Subject: [PATCH 1811/1848] [LoRaWAN] Fix incorrect DR calculation for fixed band in createSession() --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index eb7bd87671..4fafd27c88 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -392,7 +392,7 @@ void LoRaWANNode::createSession() { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { drUp = (this->band->txFreqs[0].drMin + this->band->txFreqs[0].drMax + 1) / 2; } else { // RADIOLIB_LORAWAN_BAND_FIXED - drUp = (this->band->txSpans[0].drMin + this->band->txSpans[0].drMin + 1) / 2; + drUp = (this->band->txSpans[0].drMin + this->band->txSpans[0].drMax + 1) / 2; } } uint8_t txSteps = this->txPowerSteps; From c659d3eb1cdcb3464ed64934327daf0fe1a83e4e Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 15 Feb 2026 14:00:39 +0100 Subject: [PATCH 1812/1848] [LoRaWAN] Add version getter --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++++ src/protocols/LoRaWAN/LoRaWAN.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 4fafd27c88..68affd744d 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -3207,6 +3207,10 @@ uint8_t LoRaWANNode::getClass() { return(this->lwClass); } +uint8_t LoRaWANNode::getVersionMajor() { + return(this->rev); +} + // return fCnt of last uplink; also return 0 if no uplink occured yet uint32_t LoRaWANNode::getFCntUp() { if(this->fCntUp == 0) { diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 0babc59889..e3f39968e1 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -869,6 +869,12 @@ class LoRaWANNode { */ uint8_t getClass(); + /*! + \brief Get the LoRaWAN version of this node. + \returns Version major number (0 for LoRaWAN 1.0.x, 1 for LoRaWAN 1.1). + */ + uint8_t getVersionMajor(); + /*! \brief Returns the last uplink's frame counter; also 0 if no uplink occured yet. From 1d68c7635eeb44b61179df5c62b46e7ca5c13fb6 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 15 Feb 2026 14:01:05 +0100 Subject: [PATCH 1813/1848] [LoRaWAN] Fix invalid multicast datarate --- src/protocols/LoRaWAN/LoRaWAN.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 68affd744d..c01003f642 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1157,7 +1157,7 @@ int16_t LoRaWANNode::startMulticastSession(uint8_t cls, uint32_t mcAddr, const u if(mcDr == RADIOLIB_LORAWAN_DATA_RATE_UNUSED) { mcDr = this->channels[RADIOLIB_LORAWAN_RX2].dr; } - if(this->band->dataRates[mcDr].modem != RADIOLIB_MODEM_NONE) { + if(this->band->dataRates[mcDr].modem == RADIOLIB_MODEM_NONE) { return(RADIOLIB_ERR_INVALID_DATA_RATE); } From 2c4870054b6c314cfd2b55d551d30c65205121f2 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 17 Feb 2026 15:41:22 +0100 Subject: [PATCH 1814/1848] [LoRaWAN] Open/close RxC window on start/end of multicast session --- src/protocols/LoRaWAN/LoRaWAN.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index c01003f642..5f4073f0e0 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1119,6 +1119,14 @@ int16_t LoRaWANNode::setClass(uint8_t cls) { // for LoRaWAN v1.0.4, simply switch class if(this->rev == 0) { this->lwClass = cls; + + // stop any ongoing activity + this->phyLayer->standby(); + + // if switching to Class C, open the RxC window + if(cls == RADIOLIB_LORAWAN_CLASS_C) { + this->receiveClassC(); + } return(RADIOLIB_ERR_NONE); } @@ -1178,11 +1186,24 @@ int16_t LoRaWANNode::startMulticastSession(uint8_t cls, uint32_t mcAddr, const u this->mcAFCnt = mcFCntMin; this->mcAFCntMax = mcFCntMax; + // open the RxC window with Multicast configuration + if(cls == RADIOLIB_LORAWAN_CLASS_C) { + this->receiveClassC(); + } + return(RADIOLIB_ERR_NONE); } void LoRaWANNode::stopMulticastSession() { this->multicast = false; + + // stop any ongoing activity + this->phyLayer->standby(); + + // if in Class C, re-open RxC window with normal unicast configuration + if(this->lwClass == RADIOLIB_LORAWAN_CLASS_C) { + this->receiveClassC(); + } } int16_t LoRaWANNode::isValidUplink(size_t len, uint8_t fPort) { @@ -1732,10 +1753,9 @@ int16_t LoRaWANNode::receiveDownlink() { RADIOLIB_ASSERT(state); // for LoRaWAN v1.1 Class C, there is no Rx2 window: it keeps RxC open uninterrupted - if(this->lwClass == RADIOLIB_LORAWAN_CLASS_C && this->rev == 1) { - state = this->receiveClassC(); - return(state); - } + // HOWEVER, since Multicast sessions may use different frequency and datarate, + // and it is NOT specified by the spec if the device should then ignore normal Rx2, + // we choose to ignore this part of the spec and open Rx2 as specified in v1.0.4 // for LoRaWAN v1.0.4 Class C, there is an RxC window between Rx1 and Rx2 timeoutClassC = this->tUplinkEnd + this->rxDelays[RADIOLIB_LORAWAN_RX2] - \ From c1ff483263e0698e710f2806761e0ca773e64326 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Tue, 17 Feb 2026 15:48:35 +0100 Subject: [PATCH 1815/1848] Add new LoRaWAN keywords --- keywords.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/keywords.txt b/keywords.txt index 5331a2cdb0..c903daa5da 100644 --- a/keywords.txt +++ b/keywords.txt @@ -386,6 +386,9 @@ setDwellTime KEYWORD2 setCSMA KEYWORD2 setDeviceStatus KEYWORD2 scheduleTransmission KEYWORD2 +getBand KEYWORD2 +getClass KEYWORD2 +getVersionMajor KEYWORD2 getFCntUp KEYWORD2 getNFCntDown KEYWORD2 getAFCntDown KEYWORD2 From a50accbd50f165200e60ec0c567a3648f84fe564 Mon Sep 17 00:00:00 2001 From: StevenCellist <47155822+StevenCellist@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:00:23 +0100 Subject: [PATCH 1816/1848] [Crypto] Add streaming functionality to CMAC (#1707) * [Crypto] Add streaming functionality to CMAC * [Crypto] Add return code * [Crypto] Fix missing OK return code * [CI] Add CMAC crypto unit test * [CI] Use global AES instance * [Crypto] Fix for size being multiple of 16 * [CI] Add messages to crypto test * [CI] Try to fix unit test stuck in CI * [Crypto] Make CMAC update method void --------- Co-authored-by: jgromes --- extras/test/unit/CMakeLists.txt | 3 +- extras/test/unit/test.sh | 7 +- extras/test/unit/tests/TestCrypto.cpp | 81 ++++++++++++++++++ src/utils/Cryptography.cpp | 117 +++++++++++++++++++------- src/utils/Cryptography.h | 30 +++++++ 5 files changed, 206 insertions(+), 32 deletions(-) create mode 100644 extras/test/unit/tests/TestCrypto.cpp diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt index d3dc81131c..a874a88e1b 100644 --- a/extras/test/unit/CMakeLists.txt +++ b/extras/test/unit/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(radiolib-unittest) -#set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_BUILD_TYPE Debug) # add RadioLib sources add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") @@ -14,6 +14,7 @@ file(GLOB_RECURSE TEST_SOURCES "tests/TestModule.cpp" "tests/TestCalculateTimeOnAir.cpp" "tests/TestPhyComplete.cpp" + "tests/TestCrypto.cpp" ) # create the executable diff --git a/extras/test/unit/test.sh b/extras/test/unit/test.sh index b2801a10fb..0646b10ceb 100755 --- a/extras/test/unit/test.sh +++ b/extras/test/unit/test.sh @@ -11,4 +11,9 @@ make -j4 # run it cd .. -./build/radiolib-unittest --log_level=message + +# TODO silly workaround to prevent this from getting stuck in CI +./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_Module +./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_TimeOnAir +./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_PhyComplete +./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_Crypto diff --git a/extras/test/unit/tests/TestCrypto.cpp b/extras/test/unit/tests/TestCrypto.cpp new file mode 100644 index 0000000000..ff7e719e32 --- /dev/null +++ b/extras/test/unit/tests/TestCrypto.cpp @@ -0,0 +1,81 @@ +// boost test header +#include + +// the crypto header +#include "utils/Cryptography.h" + +#include + +// test message, key and vectors +// from https://www.rfc-editor.org/rfc/rfc4493.html#section-4 + +static const unsigned char msg[64] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; + +static unsigned char key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; + +static const unsigned char testVectEx1[] = { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 +}; + +static const unsigned char testVectEx2[] = { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c +}; + +static const unsigned char testVectEx3[] = { + 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 +}; + +static const unsigned char testVectEx4[] = { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe +}; + +BOOST_AUTO_TEST_SUITE(suite_Crypto) + +BOOST_AUTO_TEST_CASE(Crypto_CMAC) { + BOOST_TEST_MESSAGE("--- Test Crypto::CMAC ---"); + uint8_t cmac[RADIOLIB_AES128_BLOCK_SIZE]; + size_t testLen; + + BOOST_TEST_MESSAGE("--- Test Crypto::CMAC RFC 4493 chapter 4 Example 1: len = 0 ---"); + testLen = 0; + RadioLibAES128Instance.init(key); + RadioLibAES128Instance.generateCMAC(msg, testLen, cmac); + BOOST_TEST(memcmp(cmac, testVectEx1, RADIOLIB_AES128_BLOCK_SIZE) == 0); + + BOOST_TEST_MESSAGE("--- Test Crypto::CMAC RFC 4493 chapter 4 Example 2: len = 16 ---"); + testLen = 16; + RadioLibAES128Instance.init(key); + RadioLibAES128Instance.generateCMAC(msg, testLen, cmac); + BOOST_TEST(memcmp(cmac, testVectEx2, RADIOLIB_AES128_BLOCK_SIZE) == 0); + + + BOOST_TEST_MESSAGE("--- Test Crypto::CMAC RFC 4493 chapter 4 Example 2: len = 40 ---"); + testLen = 40; + RadioLibAES128Instance.init(key); + RadioLibAES128Instance.generateCMAC(msg, testLen, cmac); + BOOST_TEST(memcmp(cmac, testVectEx3, RADIOLIB_AES128_BLOCK_SIZE) == 0); + + BOOST_TEST_MESSAGE("--- Test Crypto::CMAC RFC 4493 chapter 4 Example 2: len = 64 ---"); + testLen = 64; + RadioLibAES128Instance.init(key); + RadioLibAES128Instance.generateCMAC(msg, testLen, cmac); + BOOST_TEST(memcmp(cmac, testVectEx4, RADIOLIB_AES128_BLOCK_SIZE) == 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/utils/Cryptography.cpp b/src/utils/Cryptography.cpp index 2039d214bb..7ea4acb78e 100644 --- a/src/utils/Cryptography.cpp +++ b/src/utils/Cryptography.cpp @@ -43,43 +43,100 @@ size_t RadioLibAES128::decryptECB(const uint8_t* in, size_t len, uint8_t* out) { return(num_blocks*RADIOLIB_AES128_BLOCK_SIZE); } -void RadioLibAES128::generateCMAC(const uint8_t* in, size_t len, uint8_t* cmac) { - uint8_t key1[RADIOLIB_AES128_BLOCK_SIZE]; - uint8_t key2[RADIOLIB_AES128_BLOCK_SIZE]; - this->generateSubkeys(key1, key2); +/* + * CMAC streaming API + * + * Usage: + * RadioLibCMAC_State st; + * RadioLibAES128_initCMACState(&RadioLibAES128Instance, &st); + * RadioLibAES128_updateCMACState(&RadioLibAES128Instance, &st, chunk1, len1); + * RadioLibAES128_updateCMACState(&RadioLibAES128Instance, &st, chunk2, len2); + * uint8_t mac[16]; + * RadioLibAES128_finishCMACState(&RadioLibAES128Instance, &st, mac); + */ + +void RadioLibAES128::initCMAC(RadioLibCmacState* st) { + if(!st) { + return; + } + memset(st->X, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + memset(st->buffer, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + st->buffer_len = 0; + st->subkeys_generated = false; +} - size_t num_blocks = len / RADIOLIB_AES128_BLOCK_SIZE; - bool flag = true; - if(len % RADIOLIB_AES128_BLOCK_SIZE) { - num_blocks++; - flag = false; +void RadioLibAES128::updateCMAC(RadioLibCmacState* st, const uint8_t* data, size_t len) { + if(!st || (!data && len != 0)) { + return; } - uint8_t* buff = new uint8_t[num_blocks * RADIOLIB_AES128_BLOCK_SIZE]; - memset(buff, 0, num_blocks * RADIOLIB_AES128_BLOCK_SIZE); - memcpy(buff, in, len); - if (flag) { - this->blockXor(&buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], key1); - } else { - buff[len] = 0x80; - this->blockXor(&buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], key2); + // ensure subkeys are present + if(!st->subkeys_generated) { + this->generateSubkeys(st->k1, st->k2); + st->subkeys_generated = true; } - uint8_t X[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; + uint8_t tmp[RADIOLIB_AES128_BLOCK_SIZE]; + size_t offset = 0; + + while(len > 0) { + + // fill buffer up to one full block + size_t to_copy = RADIOLIB_AES128_BLOCK_SIZE - st->buffer_len; + if(to_copy > len) { + to_copy = len; + } + + // copy the data into the buffer + memcpy(&st->buffer[st->buffer_len], &data[offset], to_copy); + st->buffer_len += to_copy; + offset += to_copy; + len -= to_copy; + + // if we now have a full block AND there is still more input remaining, + // this block is NOT the final one, so process it. + if(st->buffer_len == RADIOLIB_AES128_BLOCK_SIZE && len > 0) { + this->blockXor(tmp, st->buffer, st->X); + this->encryptECB(tmp, RADIOLIB_AES128_BLOCK_SIZE, st->X); + st->buffer_len = 0; + } + } +} + +void RadioLibAES128::finishCMAC(RadioLibCmacState* st, uint8_t* out) { + if(!st || !out) { + return; + } + + // ensure subkeys are present + if(!st->subkeys_generated) { + this->generateSubkeys(st->k1, st->k2); + st->subkeys_generated = true; + } + + uint8_t last[RADIOLIB_AES128_BLOCK_SIZE]; uint8_t Y[RADIOLIB_AES128_BLOCK_SIZE]; - for(size_t i = 0; i < num_blocks - 1; i++) { - this->blockXor(Y, &buff[i*RADIOLIB_AES128_BLOCK_SIZE], X); - this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, X); + if(st->buffer_len == RADIOLIB_AES128_BLOCK_SIZE) { + this->blockXor(last, st->buffer, st->k1); + } else { + memset(last, 0x00, RADIOLIB_AES128_BLOCK_SIZE); + if(st->buffer_len > 0) { + memcpy(last, st->buffer, st->buffer_len); + } + last[st->buffer_len] = 0x80; + this->blockXor(last, last, st->k2); } - this->blockXor(Y, &buff[(num_blocks - 1)*RADIOLIB_AES128_BLOCK_SIZE], X); - this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, cmac); - delete[] buff; + + this->blockXor(Y, last, st->X); + this->encryptECB(Y, RADIOLIB_AES128_BLOCK_SIZE, out); +} + +void RadioLibAES128::generateCMAC(const uint8_t* in, size_t len, uint8_t* cmac) { + RadioLibCmacState st; + this->initCMAC(&st); + this->updateCMAC(&st, in, len); + this->finishCMAC(&st, cmac); } bool RadioLibAES128::verifyCMAC(const uint8_t* in, size_t len, const uint8_t* cmac) { @@ -293,4 +350,4 @@ uint8_t RadioLibAES128::mul(uint8_t a, uint8_t b) { return(out); } -RadioLibAES128 RadioLibAES128Instance; +RadioLibAES128 RadioLibAES128Instance; \ No newline at end of file diff --git a/src/utils/Cryptography.h b/src/utils/Cryptography.h index 4a5ddca520..bb5d2379df 100644 --- a/src/utils/Cryptography.h +++ b/src/utils/Cryptography.h @@ -12,6 +12,15 @@ #define RADIOLIB_AES128_N_R (10) #define RADIOLIB_AES128_KEY_EXP_SIZE (176) +typedef struct { + uint8_t X[RADIOLIB_AES128_BLOCK_SIZE]; + uint8_t buffer[RADIOLIB_AES128_BLOCK_SIZE]; + size_t buffer_len; + uint8_t k1[RADIOLIB_AES128_BLOCK_SIZE]; + uint8_t k2[RADIOLIB_AES128_BLOCK_SIZE]; + bool subkeys_generated; +} RadioLibCmacState; + // helper type typedef uint8_t state_t[4][4]; @@ -135,6 +144,27 @@ class RadioLibAES128 { */ void generateCMAC(const uint8_t* in, size_t len, uint8_t* cmac); + /*! + \brief Initialize the CMAC state. This must be called before any updateCMAC calls. + \param st State to initialize. + */ + void initCMAC(RadioLibCmacState* st); + + /*! + \brief Update the CMAC state with a chunk of data. This can be called multiple times to process the data in chunks. + \param st State to update. + \param data Input data (unpadded). + \param len Length of the input data. + */ + void updateCMAC(RadioLibCmacState* st, const uint8_t* data, size_t len); + + /*! + \brief Finalize the CMAC calculation and save the result. This must be called after all updateCMAC calls are done. + \param st State to finalize. + \param out Buffer to save the output MAC into. The buffer must be at least 16 bytes long! + */ + void finishCMAC(RadioLibCmacState* st, uint8_t* out); + /*! \brief Verify the received CMAC. This just calculates the CMAC again and compares the results. \param in Input data (unpadded). From ce3013408441d25a10f8075ae0188ddb16de3ac7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Feb 2026 16:54:52 +0000 Subject: [PATCH 1817/1848] [CI] Fix CI getting stuck on unit test --- extras/test/unit/CMakeLists.txt | 2 +- extras/test/unit/include/TestHal.hpp | 11 ++++++----- extras/test/unit/test.sh | 6 +----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/extras/test/unit/CMakeLists.txt b/extras/test/unit/CMakeLists.txt index a874a88e1b..10689abb26 100644 --- a/extras/test/unit/CMakeLists.txt +++ b/extras/test/unit/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(radiolib-unittest) -set(CMAKE_BUILD_TYPE Debug) +#set(CMAKE_BUILD_TYPE Debug) # add RadioLib sources add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib") diff --git a/extras/test/unit/include/TestHal.hpp b/extras/test/unit/include/TestHal.hpp index ac1d98faa0..434335b11c 100644 --- a/extras/test/unit/include/TestHal.hpp +++ b/extras/test/unit/include/TestHal.hpp @@ -140,14 +140,15 @@ class TestHal : public RadioLibHal { HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")"); const auto start = std::chrono::high_resolution_clock::now(); - // busy wait is needed for microseconds precision - const auto len = std::chrono::microseconds(us); - while(std::chrono::high_resolution_clock::now() - start < len); + // this is incredibly hacky, but there is no reliable way for sub-ms sleeping + std::this_thread::sleep_for(std::chrono::duration(1)); // measure and print const auto end = std::chrono::high_resolution_clock::now(); - const std::chrono::duration elapsed = end - start; - HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")=" << elapsed.count() << "us"); + const std::chrono::duration elapsed = end - start; + + HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")=" << elapsed.count() << "ms"); + (void)us; } void yield() override { diff --git a/extras/test/unit/test.sh b/extras/test/unit/test.sh index 0646b10ceb..234168238b 100755 --- a/extras/test/unit/test.sh +++ b/extras/test/unit/test.sh @@ -12,8 +12,4 @@ make -j4 # run it cd .. -# TODO silly workaround to prevent this from getting stuck in CI -./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_Module -./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_TimeOnAir -./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_PhyComplete -./build/radiolib-unittest --log_level=message --detect_memory_leaks --run_test=suite_Crypto +./build/radiolib-unittest --log_level=message --detect_memory_leaks From c8b9e7e8ee6dda02b7669fa81bd13309af1fbcff Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Feb 2026 18:00:39 +0000 Subject: [PATCH 1818/1848] [LR2021] Fix incorrect logic of LoRa header IRQ check --- src/modules/LR2021/LR2021.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index f3408cad40..7595af8847 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -463,12 +463,18 @@ int16_t LR2021::readData(uint8_t* data, size_t len) { // check integrity CRC uint32_t irq = getIrqStatus(); int16_t crcState = RADIOLIB_ERR_NONE; - // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet) - //! \TODO: [LR2021] legacy from LR11x0, is it still needed? - if((irq & RADIOLIB_LR2021_IRQ_CRC_ERROR) || (!(irq & RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID))) { + // report CRC mismatch when there's a payload CRC error + if(irq & RADIOLIB_LR2021_IRQ_CRC_ERROR) { crcState = RADIOLIB_ERR_CRC_MISMATCH; } + // for LoRa modem and explicit header mode, check also also header valid flag + if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) && + (this->headerType == RADIOLIB_LR2021_LORA_HEADER_EXPLICIT) && + (!(irq & RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID))) { + crcState = RADIOLIB_ERR_LORA_HEADER_DAMAGED; + } + // get packet length size_t length = getPacketLength(); if((len != 0) && (len < length)) { From ac70f5f462f96c051dc5b359b1daf32407e90025 Mon Sep 17 00:00:00 2001 From: Olivier Ouellet <85790609+olivierouellet@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:56:58 -0500 Subject: [PATCH 1819/1848] [LoRaWAN] Change sessionStatus before calculateChannelFlags in activateOTAA (#1706) Fixes missing uplinks after join in fixed bands. --- src/protocols/LoRaWAN/LoRaWAN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 5f4073f0e0..b7ba3f98c7 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -993,10 +993,10 @@ int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) { LoRaWANNode::hton(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_SIGNATURE], signature); LoRaWANNode::hton(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE], signature); - (void)this->calculateChannelFlags(); - this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE; + (void)this->calculateChannelFlags(); + return(RADIOLIB_LORAWAN_NEW_SESSION); } From b97f8564d79c4e7757ec3a3719c8633e2d813c25 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Thu, 19 Feb 2026 08:50:53 +0100 Subject: [PATCH 1820/1848] [LoRaWAN] Remove redundant condition --- src/protocols/LoRaWAN/LoRaWAN.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index b7ba3f98c7..0efe4ab7da 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -995,6 +995,7 @@ int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) { this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE; + // calculate channel flags after setting session to active (void)this->calculateChannelFlags(); return(RADIOLIB_LORAWAN_NEW_SESSION); @@ -3443,7 +3444,7 @@ bool LoRaWANNode::calculateChannelFlags() { } else { // RADIOLIB_LORAWAN_BAND_FIXED // during activation of fixed bands, flag all available channels // the datarate will be determined from there - if(!this->isActivated() && this->band->bandType == RADIOLIB_LORAWAN_BAND_FIXED) { + if(!this->isActivated()) { memcpy(this->channelFlags, this->channelMasks, sizeof(this->channelMasks)); return(true); } From 5bb0c62c90a7cb58b57131696b81399603dfe338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Thu, 19 Feb 2026 17:02:41 +0100 Subject: [PATCH 1821/1848] [ADS-B] ADS-B support (LR2021 only) (#1700) * [ADS-B] Initial WIP commit * [ADS-B] Add basic example * [CI] Fix cppcheck issues * [ADS-B] Fix example extension and path * [ADS-B] Add missing cast in example * [ADS-B] Add missing cast in example * [LR2021] Fix inverted Manchester configuration * [ADS-B] Fix callsign parsing * [ADS-B] Add method to parse hex ID * [ADS-B] Make input pointers const * [ADS-B] Implement aircraft position decoding * [ADS-B] Add altitude and position decoding to example * [ADS-B] Fix debug conversions * [ADS-B] Add live monitor script * [ADS-B] Add monitor example * [LR2021] Fix incorrect logic of LoRa header IRQ check --- examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino | 166 +++++++++++++ examples/ADSB/ADSB_Receive/ADSB_Receive.ino | 223 +++++++++++++++++ extras/ADSB_Monitor/ADSBMonitorServer.py | 141 +++++++++++ src/RadioLib.h | 1 + src/TypeDef.h | 11 + src/modules/LR2021/LR2021_commands.h | 2 +- src/modules/LR2021/LR2021_config.cpp | 12 +- src/protocols/ADSB/ADSB.cpp | 256 ++++++++++++++++++++ src/protocols/ADSB/ADSB.h | 165 +++++++++++++ 9 files changed, 974 insertions(+), 3 deletions(-) create mode 100644 examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino create mode 100644 examples/ADSB/ADSB_Receive/ADSB_Receive.ino create mode 100755 extras/ADSB_Monitor/ADSBMonitorServer.py create mode 100644 src/protocols/ADSB/ADSB.cpp create mode 100644 src/protocols/ADSB/ADSB.h diff --git a/examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino b/examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino new file mode 100644 index 0000000000..5e9508e745 --- /dev/null +++ b/examples/ADSB/ADSB_Monitor/ADSB_Monitor.ino @@ -0,0 +1,166 @@ +/* + RadioLib ADS-B Monitor Example + + This example shows how to receive ADS-B messages + using LR2021 OOK modem and forward them to be displayed + in a live dashboard. + + To show the live dashboard in a terminal, run the Python script + RadioLib/extras/ADSB_Monitor/ADSBMonitorServer.py, + and then connect to from "modeslive" from the pyModeS package + (see the script helptext for installation instructions). + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// create ADS-B client instance using the module +ADSBClient adsb(&radio); + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void setup() { + Serial.begin(9600); + + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + + // initialize LR2021 OOK modem at 1090 MHz, + // 2 Mbps bit rate and receiver bandwidth 3076 kHz + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.beginOOK(1090, 2000, 3076); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // initialize ADS-B client + Serial.print(F("[ADS-B] Initializing ... ")); + state = adsb.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // apply LR2021-specific settings + Serial.print(F("[LR2021] Setting configuration ... ")); + state = radio.setRxBoostedGainMode(7); + state += radio.setCRC(3, 0, 0x1FFF409UL, false); + state += radio.ookDetector(); + state += radio.fixedPacketLengthMode(11); + state += radio.setGain(13); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // measure current noise floor and add some margin + // this values is later used to set the signal detection threshold + float threshold = radio.getRSSI(false) + 10; + Serial.print(F("[LR2021] Detection threshold: ")); + Serial.print(threshold, 2); + Serial.println(F(" dBm")); + + Serial.print(F("[LR2021] Setting threshold ... ")); + state = radio.setOokDetectionThreshold(threshold); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[LR2021] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // read the received binary data + // ADS-B frames have fixed length of 14 bytes, + // 3 of which are used as CRC which is handled automatically + uint8_t buff[11] = { 0 }; + int state = radio.readData(buff, 11); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + // print it out, further processing is done by pyModeS + Serial.print(F("[ADS-B] ")); + for(int i = 0; i < 11; i++) { + if(buff[i] < 0x10) { Serial.print('0'); } + Serial.print(buff[i], HEX); + } + + // pyModeS expects the data to include the CRC + // but does not seem to be actually checking it + // since we handle CRC automatically, just append 3 null bytes + Serial.println(F("000000")); + + } + + } + +} diff --git a/examples/ADSB/ADSB_Receive/ADSB_Receive.ino b/examples/ADSB/ADSB_Receive/ADSB_Receive.ino new file mode 100644 index 0000000000..5bd25921eb --- /dev/null +++ b/examples/ADSB/ADSB_Receive/ADSB_Receive.ino @@ -0,0 +1,223 @@ +/* + RadioLib ADS-B Reception Example + + This example shows how to receive ADS-B messages + using LR2021 OOK modem. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// LR2021 has the following connections: +// NSS pin: 10 +// IRQ pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +LR2021 radio = new Module(10, 2, 3, 9); + +// or detect the pinout automatically using RadioBoards +// https://github.com/radiolib-org/RadioBoards +/* +#define RADIO_BOARD_AUTO +#include +Radio radio = new RadioModule(); +*/ + +// create ADS-B client instance using the module +ADSBClient adsb(&radio); + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFlag(void) { + // we got a packet, set the flag + receivedFlag = true; +} + +void setup() { + Serial.begin(9600); + + // LR2021 allows to use any DIO pin as the interrupt + // as an example, we set DIO10 to be the IRQ + // this has to be done prior to calling begin()! + radio.irqDioNum = 10; + + // initialize LR2021 OOK modem at 1090 MHz, + // 2 Mbps bit rate and receiver bandwidth 3076 kHz + Serial.print(F("[LR2021] Initializing ... ")); + int state = radio.beginOOK(1090, 2000, 3076); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // initialize ADS-B client + Serial.print(F("[ADS-B] Initializing ... ")); + state = adsb.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // apply LR2021-specific settings + Serial.print(F("[LR2021] Setting configuration ... ")); + state = radio.setRxBoostedGainMode(7); + state += radio.setCRC(3, 0, 0x1FFF409UL, false); + state += radio.ookDetector(); + state += radio.fixedPacketLengthMode(11); + state += radio.setGain(13); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // measure current noise floor and add some margin + // this values is later used to set the signal detection threshold + float threshold = radio.getRSSI(false) + 10; + Serial.print(F("[LR2021] Detection threshold: ")); + Serial.print(threshold, 2); + Serial.println(F(" dBm")); + + Serial.print(F("[LR2021] Setting threshold ... ")); + state = radio.setOokDetectionThreshold(threshold); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } + + // set the reference position (position of the receiver) + // this will be used later to calculate the aircraft position + adsb.setReferencePosition(46.24722039359617f, 12.097993784412322f); + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[LR2021] Starting to listen ... ")); + state = radio.startReceive(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) { delay(10); } + } +} + +// these variables will be used later to save decoded information +ADSBFrame frame; +ADSBAircraftCategory category; +char callsign[RADIOLIB_ADSB_CALLSIGN_LEN]; +char hexId[RADIOLIB_ADSB_HEX_ID_LEN]; +ADSBAircraftCategory cat; +int alt; +float lat, lon; +bool altGnss; + +void loop() { + // check if the flag is set + if(receivedFlag) { + // reset flag + receivedFlag = false; + + // read the received binary data + // ADS-B frames have fixed length of 14 bytes, + // 3 of which are used as CRC which is handled automatically + uint8_t buff[11] = { 0 }; + int state = radio.readData(buff, 11); + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[LR2021] Received packet!")); + + state = adsb.decode(buff, &frame); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("[ADS-B] Decoded frame!")); + // print the decoded information + Serial.print(F("[ADS-B] DF = ")); + Serial.println(frame.downlinkFormat); + Serial.print(F("[ADS-B] CA = ")); + Serial.println(frame.capability); + Serial.print(F("[ADS-B] Message type = ")); + Serial.println((int)frame.messageType); + + // get the hexadecimal ID (ICAO address) of the transceiver + state = adsb.parseHexId(&frame, hexId); + if (state == RADIOLIB_ERR_NONE) { + Serial.print(F("[ADS-B] Hex ID = ")); + Serial.println(hexId); + } + + // further information depends on the message type + switch(frame.messageType) { + case(ADSBMessageType::AIRCRAFT_ID): + adsb.parseCallsign(&frame, callsign, &cat); + Serial.print(F("[ADS-B] Callsign = ")); + Serial.println(callsign); + Serial.print(F("[ADS-B] Category = ")); + Serial.println((int)category); + break; + + case(ADSBMessageType::AIRBORNE_POS_ALT_BARO): + case(ADSBMessageType::AIRBORNE_POS_ALT_GNSS): + adsb.parseAirbornePosition(&frame, &alt, &lat, &lon, &altGnss); + Serial.print(F("[ADS-B] Altitude = ")); + Serial.print(alt); + if(altGnss) { Serial.println(" meters\n"); } else { Serial.println(" feet\n"); } + Serial.print(F("[ADS-B] Latitude = ")); + Serial.println(lat, 6); + Serial.print(F("[ADS-B] Longitude = ")); + Serial.println(lon, 6); + break; + + default: + break; + + } + + } else { + Serial.print(F("[ADS-B] Failed to decode, code ")); + Serial.println(state); + + } + + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + } +} diff --git a/extras/ADSB_Monitor/ADSBMonitorServer.py b/extras/ADSB_Monitor/ADSBMonitorServer.py new file mode 100755 index 0000000000..3fbb490c7b --- /dev/null +++ b/extras/ADSB_Monitor/ADSBMonitorServer.py @@ -0,0 +1,141 @@ +#!/usr/bin/python3 +# -*- encoding: utf-8 -*- + +import argparse +import sys +import zmq +import serial +import threading +import queue +import time + +from argparse import RawTextHelpFormatter + +# default settings +DEFAULT_BAUDRATE = 115200 +DEFAULT_SERVER_PORT = 30002 + +# marker to filter out ADS-B messages from the rest of the serial stream +ADSB_MESSAGE_MARKER = '[ADS-B]' + +class SerialToZMQBridge: + def __init__(self, serial_port, baudrate, zmq_host="0.0.0.0", zmq_port=5555): + self.serial_port = serial_port + self.baudrate = baudrate + self.zmq_host = zmq_host + self.zmq_port = zmq_port + + self.context = zmq.Context() + self.socket = self.context.socket(zmq.STREAM) + self.socket.setsockopt(zmq.LINGER, 0) + self.socket.bind(f"tcp://{self.zmq_host}:{self.zmq_port}") + + self.serial = serial.Serial( + port=self.serial_port, + baudrate=self.baudrate, + timeout=1 + ) + + self.clients = set() + self.serial_queue = queue.Queue() + + self.running = True + + def serial_reader(self): + """Continuously read from serial and queue messages.""" + while self.running: + try: + line = self.serial.readline() + if line: + line = line.decode(errors='ignore').strip() + print(f"[SERIAL RX] {line}") + + # read the ADS-B frames and add the markers expected by pyModeS + if ADSB_MESSAGE_MARKER in line: + msg = '*' + line.split(' ')[1].strip() + ';' + self.serial_queue.put(msg.encode('utf-8')) + + except Exception as e: + print(f"Serial read error: {e}") + time.sleep(1) + + def run(self): + print(f"ZMQ STREAM server listening on tcp://{self.zmq_host}:{self.zmq_port}") + print(f"Listening to serial port {self.serial_port} @ {self.baudrate}") + + threading.Thread(target=self.serial_reader, daemon=True).start() + + poller = zmq.Poller() + poller.register(self.socket, zmq.POLLIN) + + try: + while self.running: + # Poll ZMQ socket + events = dict(poller.poll(100)) + + if self.socket in events: + identity, message = self.socket.recv_multipart() + + if message == b'': + # Connection event + print(f"[ZMQ] Client connected/disconnected: {identity}") + self.clients.add(identity) + continue + + print(f"[ZMQ RX] {identity}: {message.decode(errors='ignore')}") + + # Send serial data to all connected clients + while not self.serial_queue.empty(): + data = self.serial_queue.get() + for client_id in list(self.clients): + try: + self.socket.send_multipart([client_id, data]) + print(f"[ZMQ TX] Sent to {client_id}") + except zmq.ZMQError: + self.clients.discard(client_id) + + except KeyboardInterrupt: + print("Shutting down...") + + finally: + self.running = False + self.serial.close() + self.socket.close() + self.context.term() + + +def main(): + parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' + RadioLib ADS-B Monitor script. Serves as server for "modeslive" live traffic decoder from pyModeS + (https://github.com/junzis/pyModeS). + + Depends on pyserial and pyModeS, install by: + 'python3 -m pip install pyserial pyModeS' + + Step-by-step guide on how to use the script: + 1. Upload the ADSB_Monitor example to your Arduino board with LR2021 connected. + 2. Run the script with appropriate arguments. + 3. Run "modeslive --source net --connect localhost 30002 raw" + ''') + parser.add_argument('port', + type=str, + help='COM port to connect to the device') + parser.add_argument('--speed', + default=DEFAULT_BAUDRATE, + type=int, + help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})') + parser.add_argument('--server-port', + default=DEFAULT_SERVER_PORT, + type=int, + help=f'server port to be used by modeslive (defaults to {DEFAULT_SERVER_PORT})') + args = parser.parse_args() + + bridge = SerialToZMQBridge( + serial_port=args.port, + baudrate=args.speed, + zmq_port=args.server_port + ) + bridge.run() + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/RadioLib.h b/src/RadioLib.h index f051c6b0a7..602a588c18 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -117,6 +117,7 @@ #include "protocols/Print/Print.h" #include "protocols/BellModem/BellModem.h" #include "protocols/LoRaWAN/LoRaWAN.h" +#include "protocols/ADSB/ADSB.h" // utilities #include "utils/CRC.h" diff --git a/src/TypeDef.h b/src/TypeDef.h index 84555b2585..424d8c2dcc 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -647,6 +647,17 @@ */ #define RADIOLIB_ERR_INVALID_SIDE_DETECT (-1301) +// ADS-B-specific status codes +/*! + \brief The message type is invalid for this operation. +*/ +#define RADIOLIB_ERR_ADSB_INVALID_MSG_TYPE (-1400) + +/*! + \brief The parsed aircraft category is invalid. +*/ +#define RADIOLIB_ERR_ADSB_INVALID_CATEGORY (-1401) + /*! \} */ diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 89c851850d..21a8dbae83 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -513,7 +513,7 @@ // RADIOLIB_LR2021_CMD_SET_OOK_PACKET_PARAMS #define RADIOLIB_LR2021_OOK_MANCHESTER_OFF (0x00UL << 0) // 3 0 Manchester encoding: disabled #define RADIOLIB_LR2021_OOK_MANCHESTER_ON (0x01UL << 0) // 3 0 enabled -#define RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV (0x03UL << 0) // 3 0 enabled, inverted +#define RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV (0x09UL << 0) // 3 0 enabled, inverted // RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE #define RADIOLIB_LR2021_TX_TEST_MODE_NORMAL_TX (0x00UL << 0) // 7 0 Tx test mode: normal diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index b454ffdeb0..b924792d1d 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -665,11 +665,19 @@ int16_t LR2021::setEncoding(uint8_t encoding) { case(RADIOLIB_ENCODING_NRZ): case(RADIOLIB_ENCODING_WHITENING): return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING)); + case(RADIOLIB_ENCODING_MANCHESTER): + state = setWhitening(false); + RADIOLIB_ASSERT(state); + this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON; + return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + case(RADIOLIB_ENCODING_MANCHESTER_INV): state = setWhitening(false); - this->whitening = encoding; - return(state); + RADIOLIB_ASSERT(state); + this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV; + return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening)); + default: return(RADIOLIB_ERR_INVALID_ENCODING); } diff --git a/src/protocols/ADSB/ADSB.cpp b/src/protocols/ADSB/ADSB.cpp new file mode 100644 index 0000000000..7ae5d6eddc --- /dev/null +++ b/src/protocols/ADSB/ADSB.cpp @@ -0,0 +1,256 @@ +#include "ADSB.h" + +#if !RADIOLIB_EXCLUDE_ADSB + +#include + +ADSBClient::ADSBClient(PhysicalLayer* phy) { + phyLayer = phy; +} + +int16_t ADSBClient::begin() { + // set what is supported by PHY + int16_t state = phyLayer->setFrequency(RADIOLIB_ADSB_CARRIER_FREQUENCY); + RADIOLIB_ASSERT(state); + + state = phyLayer->setPreambleLength(16); + RADIOLIB_ASSERT(state); + + state = phyLayer->setSyncWord(NULL, 0); + RADIOLIB_ASSERT(state); + + state = phyLayer->setEncoding(RADIOLIB_ENCODING_MANCHESTER_INV); + return(state); +} + +int16_t ADSBClient::decode(const uint8_t in[RADIOLIB_ADSB_FRAME_LEN_BYTES], ADSBFrame* out) { + RADIOLIB_ASSERT_PTR(out); + + // get the basic information + out->downlinkFormat = (in[0] & 0xF8) >> 3; + out->capability = in[0] & 0x07; + for(int i = 0; i < RADIOLIB_ADSB_FRAME_ICAO_LEN_BYTES; i++) { + out->icao[i] = in[RADIOLIB_ADSB_FRAME_ICAO_POS + i]; + } + + // lookup table to avoid a whole bunch of if-else statements + const ADSBMessageType msgTypeLut[] = { + ADSBMessageType::RESERVED, + ADSBMessageType::AIRCRAFT_ID, ADSBMessageType::AIRCRAFT_ID, + ADSBMessageType::AIRCRAFT_ID, ADSBMessageType::AIRCRAFT_ID, + ADSBMessageType::SURFACE_POS, ADSBMessageType::SURFACE_POS, + ADSBMessageType::SURFACE_POS, ADSBMessageType::SURFACE_POS, + ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO, + ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO, + ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO, + ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO, + ADSBMessageType::AIRBORNE_POS_ALT_BARO, ADSBMessageType::AIRBORNE_POS_ALT_BARO, + ADSBMessageType::AIRBORNE_VEL, + ADSBMessageType::AIRBORNE_POS_ALT_GNSS, + ADSBMessageType::AIRBORNE_POS_ALT_GNSS, + ADSBMessageType::AIRBORNE_POS_ALT_GNSS, + ADSBMessageType::RESERVED, ADSBMessageType::RESERVED, + ADSBMessageType::RESERVED, ADSBMessageType::RESERVED, ADSBMessageType::RESERVED, + ADSBMessageType::AIRCRAFT_STATUS, + ADSBMessageType::TARGET_STATE, + ADSBMessageType::RESERVED, + ADSBMessageType::AIRCRAFT_OPS_STATUS, + }; + + // get the message type and then the message itself + uint8_t typeCode = (in[RADIOLIB_ADSB_FRAME_MESSAGE_POS] & (0x1F << 3)) >> 3; + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADS-B Type Code = %d", typeCode); + out->messageType = msgTypeLut[typeCode]; + for(int i = 0; i < RADIOLIB_ADSB_FRAME_MESSAGE_LEN_BYTES; i++) { + out->message[i] = in[RADIOLIB_ADSB_FRAME_MESSAGE_POS + i]; + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t ADSBClient::parseHexId(const ADSBFrame* in, char id[RADIOLIB_ADSB_HEX_ID_LEN]) { + RADIOLIB_ASSERT_PTR(in); + + for(int i = 0; i < RADIOLIB_ADSB_HEX_ID_LEN / 2; i++) { + snprintf(&id[2*i], 3, "%02X", in->icao[i]); + } + + id[RADIOLIB_ADSB_HEX_ID_LEN - 1] = '\0'; + return(RADIOLIB_ERR_NONE); +} + +int16_t ADSBClient::parseCallsign(const ADSBFrame* in, char callsign[RADIOLIB_ADSB_CALLSIGN_LEN], ADSBAircraftCategory* cat) { + RADIOLIB_ASSERT_PTR(in); + + if(in->messageType != ADSBMessageType::AIRCRAFT_ID) { + return(RADIOLIB_ERR_ADSB_INVALID_MSG_TYPE); + } + + // precomputed bitshifts + callsign[0] = (in->message[1] & (0x3F << 2)) >> 2; + callsign[1] = ((in->message[1] & (0x03 >> 0)) << 4) | ((in->message[2] & (0x0F << 4)) >> 4); + callsign[2] = ((in->message[2] & (0x0F << 0)) << 2) | ((in->message[3] & (0x03 << 6)) >> 6); + callsign[3] = in->message[3] & 0x3F; + callsign[4] = (in->message[4] & (0x3F << 2)) >> 2; + callsign[5] = ((in->message[4] & (0x03 >> 0)) << 4) | ((in->message[5] & (0x0F << 4)) >> 4); + callsign[6] = ((in->message[5] & (0x0F << 0)) << 2) | ((in->message[6] & (0x03 << 6)) >> 6); + callsign[7] = in->message[6] & 0x3F; + callsign[RADIOLIB_ADSB_CALLSIGN_LEN - 1] = '\0'; + + // convert to ASCII + for(int i = 0; i < RADIOLIB_ADSB_CALLSIGN_LEN - 1; i++) { + if((callsign[i] >= 1) && (callsign[i] <= 26)) { + callsign[i] += '@'; + } else if(callsign[i] == 32) { + callsign[i] = ' '; + } else if(!((callsign[i] >= '0') && (callsign[i] <= '9'))) { + callsign[i] = '\0'; + } + } + + // only continue processing if category was requested by user + if(!cat) { return(RADIOLIB_ERR_NONE);} + + uint8_t type = (in->message[0] & 0xF8) >> 3; + uint8_t category = in->message[0] & 0x03; + if(type < 2) { + *cat = ADSBAircraftCategory::RESERVED; + return(RADIOLIB_ERR_NONE); + } else if(category == 0) { + *cat = ADSBAircraftCategory::NONE; + return(RADIOLIB_ERR_NONE); + } + + // lookup table to avoid a whole bunch of if-else statements + const ADSBAircraftCategory catLut[] = { + ADSBAircraftCategory::SURFACE_EMERGENCY, + ADSBAircraftCategory::RESERVED, + ADSBAircraftCategory::SURFACE_SERVICE, + ADSBAircraftCategory::GROUND_OBSTRUCTION, + ADSBAircraftCategory::GROUND_OBSTRUCTION, + ADSBAircraftCategory::GROUND_OBSTRUCTION, + ADSBAircraftCategory::GROUND_OBSTRUCTION, + ADSBAircraftCategory::GLIDER, + ADSBAircraftCategory::LIGHTER_THAN_AIR, + ADSBAircraftCategory::PARACHUTIST, + ADSBAircraftCategory::ULTRALIGHT_PARAGLIDER, + ADSBAircraftCategory::RESERVED, + ADSBAircraftCategory::UAV, + ADSBAircraftCategory::SPACE_VEHICLE, + ADSBAircraftCategory::LIGHT, + ADSBAircraftCategory::MEDIUM_1, + ADSBAircraftCategory::MEDIUM_2, + ADSBAircraftCategory::HIGH_VORTEX, + ADSBAircraftCategory::HEAVY, + ADSBAircraftCategory::HIGH_PERFORMANCE, + ADSBAircraftCategory::ROTORCRAFT, + }; + + // the index is parsed from the type and category + // in real world values overflowing the lookup table should not appear, + // but better to check anyway + size_t index = (type - 2)*7 + (category - 1); + if(index >= sizeof(catLut)/sizeof(catLut[0])) { + return(RADIOLIB_ERR_ADSB_INVALID_CATEGORY); + } + + *cat = catLut[index]; + return(RADIOLIB_ERR_NONE); +} + +void ADSBClient::setReferencePosition(float lat, float lon) { + this->refPos[0] = lat; + this->refPos[1] = lon; +} + +// lookup table for longitude zones +// having this as lookup avoids a whole bunch of floating-point calculations +static const float lonZoneLut[] = { + 87.0000000000000f, 86.5353699751210f, 85.7554162094442f, 84.8916619070209f, 83.9917356298057f, + 83.0719944471981f, 82.1395698051061f, 81.1980134927195f, 80.2492321328051f, 79.2942822545693f, + 78.3337408292275f, 77.3678946132819f, 76.3968439079447f, 75.4205625665336f, 74.4389341572514f, + 73.4517744166787f, 72.4588454472895f, 71.4598647302898f, 70.4545107498760f, 69.4424263114402f, + 68.4232202208333f, 67.3964677408467f, 66.3617100838262f, 65.3184530968209f, 64.2661652256744f, + 63.2042747938193f, 62.1321665921033f, 61.0491777424635f, 59.9545927669403f, 58.8476377614846f, + 57.7274735386611f, 56.5931875620592f, 55.4437844449504f, 54.2781747227290f, 53.0951615279600f, + 51.8934246916877f, 50.6715016555384f, 49.4277643925569f, 48.1603912809662f, 46.8673325249875f, + 45.5462672266023f, 44.1945495141927f, 42.8091401224356f, 41.3865183226024f, 39.9225668433386f, + 38.4124189241226f, 36.8502510759353f, 35.2289959779639f, 33.5399343629848f, 31.7720970768108f, + 29.9113568573181f, 27.9389871012190f, 25.8292470705878f, 23.5450448655707f, 21.0293949260285f, + 18.1862635707134f, 14.8281743686868f, 10.4704712999685f, +}; + +int16_t ADSBClient::parseAirbornePosition(const ADSBFrame* in, int* alt, float* lat, float* lon, bool* altGnss) { + RADIOLIB_ASSERT_PTR(in); + + if((in->messageType != ADSBMessageType::AIRBORNE_POS_ALT_BARO) && + (in->messageType != ADSBMessageType::AIRBORNE_POS_ALT_GNSS)) { + return(RADIOLIB_ERR_ADSB_INVALID_MSG_TYPE); + } + + // parse altitude + if(alt) { + if(in->messageType == ADSBMessageType::AIRBORNE_POS_ALT_BARO) { + // barometric altitude, get the raw value without the Q bit + uint16_t altRaw = ((in->message[1] & 0xFE) << 3) | ((in->message[2] & 0xF0) >> 4); + + // now get the step size based on the Q bit and calculate + int step = (in->message[1] & 0x01) ? 25 : 100; + *alt = step*(int)altRaw - 1000; + + } else { + // GNSS altitude, which is just meters + *alt = (in->message[1] << 4) | ((in->message[2] & 0xF0) >> 4); + + } + + // pass the source flag, if requested + if(altGnss) { *altGnss = (in->messageType == ADSBMessageType::AIRBORNE_POS_ALT_GNSS); } + } + + // check if this is an even or odd frame + bool odd = in->message[2] & 0x04; + + // always calculate the latitude - it is needed to also calculate longitude + uint32_t latRaw = (((uint32_t)(in->message[2] & 0x03)) << 15) | ((uint32_t)in->message[3] << 7) | (uint32_t)((in->message[4] & 0xFE) >> 1); + float latCpr = (float)latRaw / (float)(1UL << 17); + float latZoneSize = odd ? 360.0f/59.0f : 6.0f; + int latZoneIdx = floor(this->refPos[0] / latZoneSize) + floor((fmod(this->refPos[0], latZoneSize) / latZoneSize) - latCpr + 0.5f); + float tmpLat = latZoneSize * (latZoneIdx + (float)latCpr); + if(lat) { *lat = tmpLat; } + RADIOLIB_DEBUG_PROTOCOL_PRINT("latRaw=%d\n", latRaw); + RADIOLIB_DEBUG_PROTOCOL_PRINT("latCpr=%f\n", (double)latCpr); + RADIOLIB_DEBUG_PROTOCOL_PRINT("latZoneSize=%f\n", (double)latZoneSize); + RADIOLIB_DEBUG_PROTOCOL_PRINT("latZoneIdx=%d\n", latZoneIdx); + + // only calculate longitude if the user requested it + if(lon) { + int lonZone = 1; + if(abs(tmpLat) < 87.0f) { + for(size_t i = 0; i < sizeof(lonZoneLut)/sizeof(lonZoneLut[0]); i++) { + if(abs(tmpLat) >= lonZoneLut[i]) { + lonZone = i + 1; + break; + } + } + if(lonZone == 1) { + lonZone = 59; + } + } + uint32_t lonRaw = (((uint32_t)(in->message[4] & 0x01)) << 16) | ((uint32_t)in->message[5] << 8) | (uint32_t)in->message[6]; + float lonCpr = (float)lonRaw / (float)(1UL << 17); + float lonZoneSize = 360.0f / RADIOLIB_MAX(lonZone - (int)odd, 1); + int lonZoneIdx = floor(this->refPos[1] / lonZoneSize) + floor((fmod(this->refPos[1], lonZoneSize) / lonZoneSize) - lonCpr + 0.5f); + *lon = lonZoneSize * (lonZoneIdx + (float)lonCpr); + + RADIOLIB_DEBUG_PROTOCOL_PRINT("lonRaw=%d\n", lonRaw); + RADIOLIB_DEBUG_PROTOCOL_PRINT("lonCpr=%f\n", (double)lonCpr); + RADIOLIB_DEBUG_PROTOCOL_PRINT("lonZone=%d\n", lonZone); + RADIOLIB_DEBUG_PROTOCOL_PRINT("lonZoneSize=%f\n", (double)lonZoneSize); + RADIOLIB_DEBUG_PROTOCOL_PRINT("lonZoneIdx=%d\n", lonZoneIdx); + } + + return(RADIOLIB_ERR_NONE); +} + +#endif diff --git a/src/protocols/ADSB/ADSB.h b/src/protocols/ADSB/ADSB.h new file mode 100644 index 0000000000..9e91bb6b16 --- /dev/null +++ b/src/protocols/ADSB/ADSB.h @@ -0,0 +1,165 @@ +#if !defined(RADIOLIB_ADSB_H) +#define RADIOLIB_ADSB_H + +#include "../../TypeDef.h" + +#if !RADIOLIB_EXCLUDE_ADSB + +#include "../PhysicalLayer/PhysicalLayer.h" + +#define RADIOLIB_ADSB_CARRIER_FREQUENCY (1090.0f) + +// basic ADS-B frame structure +#define RADIOLIB_ADSB_FRAME_LEN_BYTES (14) +#define RADIOLIB_ADSB_FRAME_DF_CA_POS (0) +#define RADIOLIB_ADSB_FRAME_ICAO_LEN_BYTES (3) +#define RADIOLIB_ADSB_FRAME_ICAO_POS (1) +#define RADIOLIB_ADSB_FRAME_MESSAGE_LEN_BYTES (7) +#define RADIOLIB_ADSB_FRAME_MESSAGE_POS (4) +#define RADIOLIB_ADSB_FRAME_PARITY_INTERROGATOR_LEN_BYTES (3) +#define RADIOLIB_ADSB_FRAME_PARITY_INTERROGATOR_POS (11) + +// length of the ICAO address, including a terminating null +#define RADIOLIB_ADSB_HEX_ID_LEN (6 + 1) + +// length of the callsign, including a terminating null +#define RADIOLIB_ADSB_CALLSIGN_LEN (8 + 1) + +/*! + \enum ADSBMessageType + \brief ADS-B Message Type +*/ +enum class ADSBMessageType { + AIRCRAFT_ID = 0, + SURFACE_POS, + AIRBORNE_POS_ALT_BARO, + AIRBORNE_VEL, + AIRBORNE_POS_ALT_GNSS, + AIRCRAFT_STATUS, + TARGET_STATE, + AIRCRAFT_OPS_STATUS, + RESERVED, +}; + +/*! + \enum ADSBAircraftCategory + \brief ADS-B Aircraft category +*/ +enum class ADSBAircraftCategory { + NONE = 0, + SURFACE_EMERGENCY, + SURFACE_SERVICE, + GROUND_OBSTRUCTION, + GLIDER, + LIGHTER_THAN_AIR, + PARACHUTIST, + ULTRALIGHT_PARAGLIDER, + UAV, + SPACE_VEHICLE, + LIGHT, + MEDIUM_1, + MEDIUM_2, + HIGH_VORTEX, + HEAVY, + HIGH_PERFORMANCE, + ROTORCRAFT, + RESERVED, +}; + +/*! + \struct ADSBFrame + \brief ADS-B Frame structure +*/ +struct ADSBFrame { + public: + /*! \brief Downlink format (DF). Received frames should always have DF = 17. */ + uint8_t downlinkFormat; + + /*! \brief Transponder capability. */ + uint8_t capability; + + /*! \brief Transponder ICAO address. */ + uint8_t icao[RADIOLIB_ADSB_FRAME_ICAO_LEN_BYTES]; + + /*! \brief Message type. */ + ADSBMessageType messageType; + + /*! \brief Message buffer, interpretation is dependent on the value of messageType. */ + uint8_t message[RADIOLIB_ADSB_FRAME_MESSAGE_LEN_BYTES]; +}; + +/*! + \class ADSBClient + \brief Client for receiving and decoding ADS-B broadcast. +*/ +class ADSBClient { + public: + /*! + \brief Default constructor. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + explicit ADSBClient(PhysicalLayer* phy); + + /*! + \brief Initialization method. + \returns \ref status_codes + */ + int16_t begin(); + + /*! + \brief Frame decoding method, turns raw received binary data into ADS-B frame. + \param in Received raw data. + \param out Pointer to ADSBFrame where the decoded frame will be saved. + \returns \ref status_codes + */ + int16_t decode(const uint8_t in[RADIOLIB_ADSB_FRAME_LEN_BYTES], ADSBFrame* out); + + /*! + \brief Method to parse the transponder ICAO address (hex ID). + \param in Pointer to ADSBFrame where decoded frame was saved. + \param callsign Buffer where the parsed ID will be saved as null-terminated string. + \returns \ref status_codes + */ + int16_t parseHexId(const ADSBFrame* in, char id[RADIOLIB_ADSB_HEX_ID_LEN]); + + /*! + \brief Method to parse callsign from a received frame. + \param in Pointer to ADSBFrame where decoded frame was saved. + \param callsign Buffer where the parsed callsign will be saved as null-terminated string. + \param cat If set, parsed aircraft category will be saved here. + \returns \ref status_codes + */ + int16_t parseCallsign(const ADSBFrame* in, char callsign[RADIOLIB_ADSB_CALLSIGN_LEN], ADSBAircraftCategory* cat = NULL); + + /*! + \brief Method to set reference position to be used during airborne position calculation. + \param lat Reference latitude in degrees (north positive, south negative). + \param lat Reference longitude in degrees (east positive, west negative). + */ + void setReferencePosition(float lat, float lon); + + /*! + \brief Parse aircraft position from incoming frame, uasing reference position set by setReferencePosition. + The reference position is the "rough area" where the aircraft is located, typically it is the receiver location. + Aircraft position will be calcualted accurately only within 180 nautical miles (about 333 km) from the reference position! + \param in Pointer to ADSBFrame where decoded frame was saved. + \param alt Pointer to variable where the parsed altitude will be saved. Can be set to null to skip altitude calculation. + Units are feet for barometric altitude, meters for GNSS altitude. + \param lat Pointer to variable where the parsed latitude in degrees will be saved. Can be set to null to skip latitude calculation. + \param lon Pointer to variable where the parsed longitude in degrees will be saved. Can be set to null to skip longitude calculation. + \param altGnss If set, this variable will be set to true if the altitude source is GNSS, or false if the altitude is barometric. + */ + int16_t parseAirbornePosition(const ADSBFrame* in, int* alt, float* lat, float* lon, bool* altGnss = NULL); + +#if !RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* phyLayer; + + // reference position + float refPos[2] = { 0, 0 }; +}; + +#endif + +#endif From 68cc9775c09cd2f79edbcc940fbf69de9774a99d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 19 Feb 2026 20:05:08 +0100 Subject: [PATCH 1822/1848] [ADS-B] Add support info to readme and keywords --- README.md | 1 + idf_component.yml | 1 + library.json | 2 +- library.properties | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d9d6b5f0bb..218bb151fd 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __SX123x__ FSK/OOK radio modules (SX1231, SX1233) ### Supported protocols and digital modes: +* [__ADS-B__](https://mode-s.org/1090mhz/content/ads-b/1-basics.html) using OOK for LR2021 * [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0, LR2021 and SX128x * [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: diff --git a/idf_component.yml b/idf_component.yml index 8ca03b163b..3b4c8a5038 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -34,6 +34,7 @@ tags: - lr1120 - lr1121 - lr2021 + - adsb url: "https://github.com/jgromes/RadioLib" repository: "https://github.com/jgromes/RadioLib.git" license: "MIT" diff --git a/library.json b/library.json index 133537e072..d354a644a2 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "RadioLib", "version": "7.5.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", - "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121, lr2021", + "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121, lr2021, adsb", "homepage": "https://github.com/jgromes/RadioLib", "repository": { diff --git a/library.properties b/library.properties index 4f2e0828b3..774e064e88 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=7.5.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library -paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110, LR2021 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN). +paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110, LR2021 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN, ADS-B). category=Communication url=https://github.com/jgromes/RadioLib architectures=* From 0d3a63c2590e19e5ec44e89b579cd8317c506ec2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 19 Feb 2026 20:05:42 +0100 Subject: [PATCH 1823/1848] Bump version to 7.6.0 --- idf_component.yml | 2 +- library.json | 2 +- library.properties | 2 +- src/BuildOpt.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idf_component.yml b/idf_component.yml index 3b4c8a5038..94705a94de 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "7.5.0" +version: "7.6.0" description: "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN)." tags: - radio diff --git a/library.json b/library.json index d354a644a2..073d2f2e9f 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "RadioLib", - "version": "7.5.0", + "version": "7.6.0", "description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).", "keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rf69, sx1231, rfm96, rfm98, sstv, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag, lorawan, lr1110, lr1120, lr1121, lr2021, adsb", "homepage": "https://github.com/jgromes/RadioLib", diff --git a/library.properties b/library.properties index 774e064e88..bad6c1e5d5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=7.5.0 +version=7.6.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library diff --git a/src/BuildOpt.h b/src/BuildOpt.h index d6053d05fb..37c6c47905 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -619,7 +619,7 @@ // version definitions #define RADIOLIB_VERSION_MAJOR 7 -#define RADIOLIB_VERSION_MINOR 5 +#define RADIOLIB_VERSION_MINOR 6 #define RADIOLIB_VERSION_PATCH 0 #define RADIOLIB_VERSION_EXTRA 0 From f403b9c3d735bbd467ee92c1baf8ea216b608125 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 19 Feb 2026 20:49:56 +0100 Subject: [PATCH 1824/1848] [LR2021 Fix frequency calibration for LF band --- src/modules/LR2021/LR2021_commands.h | 1 + src/modules/LR2021/LR2021_config.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 21a8dbae83..d858c7807f 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -238,6 +238,7 @@ #define RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH (0x00UL << 15) // 15 15 calibration path: low-frequency #define RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH (0x01UL << 15) // 15 15 high-frequency #define RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ (20.0f) +#define RADIOLIB_LR2021_LF_CUTOFF_FREQ (1500.0f) // RADIOLIB_LR2021_CMD_GET_V_BAT #define RADIOLIB_LR2021_VBAT_FORMAT_RAW (0x00UL << 3) // 3 3 readout format: raw diff --git a/src/modules/LR2021/LR2021_config.cpp b/src/modules/LR2021/LR2021_config.cpp index b924792d1d..d01df5d03f 100644 --- a/src/modules/LR2021/LR2021_config.cpp +++ b/src/modules/LR2021/LR2021_config.cpp @@ -33,7 +33,7 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { for(; i < RADIOLIB_LR2021_MAX_CAL_ATTEMPTS; i++) { // get the nearest multiple of 4 MHz uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 }; - frequencies[0] |= (freq > 1000.0f) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; + frequencies[0] |= (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH; state = calibrateFrontEnd(const_cast(frequencies)); // if something failed, check the device errors @@ -67,7 +67,7 @@ int16_t LR2021::setFrequency(float freq, bool skipCalibration) { state = setRfFrequency((uint32_t)(freq*1000000.0f)); RADIOLIB_ASSERT(state); this->freqMHz = freq; - this->highFreq = (freq > 1100.0f); + this->highFreq = (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ); return(state); } From 8566665beeb9dca17ea7ac42b7c936e2293aa73c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sat, 21 Feb 2026 10:48:14 +0100 Subject: [PATCH 1825/1848] [LoRaWAN] Fix payload buffer size --- src/protocols/LoRaWAN/LoRaWAN.cpp | 10 +++++----- src/protocols/LoRaWAN/LoRaWAN.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 0efe4ab7da..bb5b69aba7 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -25,7 +25,7 @@ int16_t LoRaWANNode::sendReceive(const String& strUp, uint8_t fPort, String& str // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; - uint8_t dataDown[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE + 1]; + uint8_t dataDown[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE + 1]; state = this->sendReceive(reinterpret_cast(dataUp), strlen(dataUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown); @@ -45,7 +45,7 @@ int16_t LoRaWANNode::sendReceive(const char* strUp, uint8_t fPort, bool isConfir // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; - uint8_t dataDown[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE + 1]; + uint8_t dataDown[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE + 1]; return(this->sendReceive(reinterpret_cast(const_cast(strUp)), strlen(strUp), fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); } @@ -58,7 +58,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP // build a temporary buffer // LoRaWAN downlinks can have 250 bytes at most with 1 extra byte for NULL size_t lenDown = 0; - uint8_t dataDown[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE + 1]; + uint8_t dataDown[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE + 1]; return(this->sendReceive(dataUp, lenUp, fPort, dataDown, &lenDown, isConfirmed, eventUp, eventDown)); } @@ -1798,7 +1798,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L #if !RADIOLIB_STATIC_ONLY uint8_t* downlinkMsg = new uint8_t[RADIOLIB_AES128_BLOCK_SIZE + downlinkMsgLen]; #else - uint8_t downlinkMsg[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t downlinkMsg[RADIOLIB_AES128_BLOCK_SIZE + RADIOLIB_STATIC_ARRAY_SIZE]; #endif // read the data @@ -2061,7 +2061,7 @@ int16_t LoRaWANNode::parseDownlink(uint8_t* data, size_t* len, uint8_t window, L if(fOptsLen > 0) { uint8_t* mPtr = fOptsPtr; uint8_t procLen = 0; - uint8_t fOptsRe[RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE] = { 0 }; + uint8_t fOptsRe[RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE] = { 0 }; uint8_t fOptsReLen = 0; // indication whether LinkAdr MAC command has been processed diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index e3f39968e1..0d09a9b499 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -207,7 +207,7 @@ #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) -#define RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE (250) +#define RADIOLIB_LORAWAN_MAX_PAYLOAD_SIZE (242) // session states #define RADIOLIB_LORAWAN_SESSION_NONE (0x00) From b65a27aa4899d114c36b1032c3293e5b93bdcc80 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Feb 2026 10:37:21 +0000 Subject: [PATCH 1826/1848] [PHY] Fix size of some static-only buffers in protocols --- src/protocols/APRS/APRS.cpp | 2 +- src/protocols/AX25/AX25.cpp | 4 ++-- src/protocols/Pager/Pager.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/APRS/APRS.cpp b/src/protocols/APRS/APRS.cpp index a2f9078d4a..8fa932adc3 100644 --- a/src/protocols/APRS/APRS.cpp +++ b/src/protocols/APRS/APRS.cpp @@ -50,7 +50,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, const cha #if !RADIOLIB_STATIC_ONLY char* info = new char[len + 2]; #else - char info[RADIOLIB_STATIC_ARRAY_SIZE]; + char info[RADIOLIB_STATIC_ARRAY_SIZE + 2]; #endif // build the info field diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index ad0e991699..c05a4d20c9 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -307,7 +307,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { #if !RADIOLIB_STATIC_ONLY uint8_t* frameBuff = new uint8_t[frameBuffLen + 2]; #else - uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE + 2]; #endif uint8_t* frameBuffPtr = frameBuff; @@ -390,7 +390,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags uint8_t* stuffedFrameBuff = new uint8_t[preambleLen + 1 + (6*frameBuffLen)/5 + 2]; #else - uint8_t stuffedFrameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t stuffedFrameBuff[1 + (6*RADIOLIB_STATIC_ARRAY_SIZE)/5 + 2]; #endif // initialize buffer to all zeros diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index b3a14b1513..d3ae9784a5 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -309,7 +309,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { // build a temporary buffer #if RADIOLIB_STATIC_ONLY - uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; + uint8_t data[RADIOLIB_STATIC_PROTOCOL_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; RADIOLIB_ASSERT_PTR(data); From b28aa2b6833c4397bc9d6d0b0eac59cad40e34d7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Feb 2026 10:39:16 +0000 Subject: [PATCH 1827/1848] [MOD] Increase static only-buffers and allow build override --- src/BuildOpt.h | 6 ++++++ src/Module.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 37c6c47905..0ed4ef86d4 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -106,6 +106,12 @@ #define RADIOLIB_STATIC_ARRAY_SIZE (256) #endif +// allow user to set custom SPI buffer size +// the default covers the maximum supported SPI command, address and status +#if !defined(RADIOLIB_STATIC_SPI_ARRAY_SIZE) + #define RADIOLIB_STATIC_SPI_ARRAY_SIZE (3*sizeof(uint32_t) + (RADIOLIB_STATIC_ARRAY_SIZE)) +#endif + /* * Uncomment on boards whose clock runs too slow or too fast * Set the value according to the following scheme: diff --git a/src/Module.cpp b/src/Module.cpp index 2ea328295b..e07c9382f0 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -178,8 +178,8 @@ void Module::SPItransfer(uint16_t cmd, uint32_t reg, const uint8_t* dataOut, uin // prepare the buffers size_t buffLen = this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8 + numBytes; #if RADIOLIB_STATIC_ONLY - uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; - uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffOut[RADIOLIB_STATIC_SPI_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_SPI_ARRAY_SIZE]; #else uint8_t* buffOut = new uint8_t[buffLen]; uint8_t* buffIn = new uint8_t[buffLen]; @@ -323,7 +323,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8); } #if RADIOLIB_STATIC_ONLY - uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffOut[RADIOLIB_STATIC_SPI_ARRAY_SIZE]; #else uint8_t* buffOut = new uint8_t[buffLen]; #endif @@ -366,7 +366,7 @@ int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write // prepare the input buffer #if RADIOLIB_STATIC_ONLY - uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_SPI_ARRAY_SIZE]; #else uint8_t* buffIn = new uint8_t[buffLen]; #endif From 2f1fcd608034737e1e61469f587c3529cecca2e5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 Feb 2026 15:59:36 +0000 Subject: [PATCH 1828/1848] [Pager] Fix invalid array size for static-only buffer --- src/protocols/Pager/Pager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Pager/Pager.cpp b/src/protocols/Pager/Pager.cpp index d3ae9784a5..b3a14b1513 100644 --- a/src/protocols/Pager/Pager.cpp +++ b/src/protocols/Pager/Pager.cpp @@ -309,7 +309,7 @@ int16_t PagerClient::readData(String& str, size_t len, uint32_t* addr) { // build a temporary buffer #if RADIOLIB_STATIC_ONLY - uint8_t data[RADIOLIB_STATIC_PROTOCOL_ARRAY_SIZE + 1]; + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; #else uint8_t* data = new uint8_t[length + 1]; RADIOLIB_ASSERT_PTR(data); From 83b5dc7276fcb1688b08eb8e3e26a4b511693629 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 28 Feb 2026 16:00:15 +0000 Subject: [PATCH 1829/1848] [CI] Add job to test builds for static-only buffers --- .github/workflows/static.yml | 46 ++++++++++++++++++++++++++++++++++++ extras/test/unit/test.sh | 4 +++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/static.yml diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml new file mode 100644 index 0000000000..74b53f2d14 --- /dev/null +++ b/.github/workflows/static.yml @@ -0,0 +1,46 @@ +name: "Static Memory Management Test" + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + static-memory: + name: Build Arduino and non-Arduino with enabled static memory management + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install dependencies for unit test + run: | + sudo apt-get update + sudo apt-get install -y libboost-all-dev libfmt-dev lcov + + - name: Run unit test for static memory management + run: | + cd extras/test/unit + ./test.sh -DRADIOLIB_STATIC_ONLY + + - name: Install arduino-cli + run: + | + mkdir -p ~/.local/bin + echo "~/.local/bin" >> $GITHUB_PATH + curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=~/.local/bin sh + + - name: Install platform + run: + | + arduino-cli core update-index + arduino-cli core install arduino:avr + + - name: Build Arduino example + run: + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:mega $PWD/examples/SX123x/SX123x_Transmit_Blocking/SX123x_Transmit_Blocking.ino --warnings=all --build-property compiler.cpp.extra_flags="-DRADIOLIB_STATIC_ONLY" + + diff --git a/extras/test/unit/test.sh b/extras/test/unit/test.sh index 234168238b..dead8b7857 100755 --- a/extras/test/unit/test.sh +++ b/extras/test/unit/test.sh @@ -2,11 +2,13 @@ set -e +args=$1 + # build the test binary rm -rf build mkdir build cd build -cmake -G "CodeBlocks - Unix Makefiles" .. +cmake -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} ${args}" .. make -j4 # run it From b0a3f2d4f9dee58eb34525a34a6dd0fb92c4d384 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:42 +0100 Subject: [PATCH 1830/1848] [LR11x0] Expose instantaneous RSSI measurement (#1714) * [LR11x0] Expose instantaneous RSSI measurement * Rephrase "Recorded" to "Received" * Add `skipReceive` parameter for instantaneous RSSI measurement * Fix cppcheck error --- src/modules/CC1101/CC1101.h | 2 +- src/modules/LR11x0/LR11x0.cpp | 16 ++++++++++++++++ src/modules/LR11x0/LR11x0.h | 11 ++++++++++- src/modules/LR2021/LR2021.h | 7 ++++--- src/modules/RF69/RF69.h | 2 +- src/modules/SX126x/SX126x.h | 4 ++-- src/modules/SX127x/SX1272.h | 4 ++-- src/modules/SX127x/SX1278.h | 4 ++-- src/modules/SX128x/SX128x.h | 4 ++-- src/protocols/PhysicalLayer/PhysicalLayer.h | 2 +- 10 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 860ee3a7f9..b89472619c 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -900,7 +900,7 @@ class CC1101: public PhysicalLayer { int16_t setOOK(bool enableOOK); /*! - \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet. In direct or asynchronous direct mode, returns the current RSSI level. \returns RSSI in dBm. */ diff --git a/src/modules/LR11x0/LR11x0.cpp b/src/modules/LR11x0/LR11x0.cpp index a254f1f8ad..c8f0dc07fe 100644 --- a/src/modules/LR11x0/LR11x0.cpp +++ b/src/modules/LR11x0/LR11x0.cpp @@ -1109,6 +1109,22 @@ float LR11x0::getRSSI() { return(val); } +float LR11x0::getRSSI(bool packet, bool skipReceive) { + float val = 0; + + // check if RSSI of packet is requested + if (packet) { + val = getRSSI(); + } else { + if(!skipReceive) { (void)startReceive(); } + int16_t state = getRssiInst(&val); + if(!skipReceive) { (void)standby(); } + if(state != RADIOLIB_ERR_NONE) { return(0); } + } + + return(val); +} + float LR11x0::getSNR() { float val = 0; diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index a1649dc368..495154c28d 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -424,11 +424,20 @@ class LR11x0: public LRxxxx { int16_t invertIQ(bool enable) override; /*! - \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem. + \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem. \returns RSSI of the last received packet in dBm. */ float getRSSI() override; + /*! + \brief Gets RSSI (Received Signal Strength Indicator). + \param packet Whether to read last packet RSSI, or the current value. + \param skipReceive Set to true to skip putting radio in receive mode for instantaneous RSSI measurement. + If false, after the RSSI measurement, the radio will be in standby mode. + \returns RSSI value in dBm. + */ + float getRSSI(bool packet, bool skipReceive = false); + /*! \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem. \returns SNR of the last received packet in dB. diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index fb3a41ce40..1a309d69b8 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -595,16 +595,17 @@ class LR2021: public LRxxxx { float getTemperature(uint8_t source, uint8_t bits = 13); /*! - \brief Gets recorded signal strength indicator. + \brief Gets received signal strength indicator. Overload with packet mode enabled for PhysicalLayer compatibility. \returns RSSI value in dBm. */ float getRSSI() override; /*! - \brief Gets RSSI (Recorded Signal Strength Indicator). + \brief Gets RSSI (Received Signal Strength Indicator). \param packet Whether to read last packet RSSI, or the current value. - \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. + \param skipReceive Set to true to skip putting radio in receive mode for instantaneous RSSI measurement. + If false, after the RSSI measurement, the radio will be in standby mode. \returns RSSI value in dBm. */ float getRSSI(bool packet, bool skipReceive = false); diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 136817e8fa..fa612a9a74 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -957,7 +957,7 @@ class RF69: public PhysicalLayer { int16_t setLnaTestBoost(bool value); /*! - \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet. \returns Last packet RSSI in dBm. */ float getRSSI() override; diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 7e47a3d09b..590a018c49 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -528,14 +528,14 @@ class SX126x: public PhysicalLayer { int16_t setDio2AsRfSwitch(bool enable = true); /*! - \brief Gets recorded signal strength indicator. + \brief Gets received signal strength indicator. Overload with packet mode enabled for PhysicalLayer compatibility. \returns RSSI value in dBm. */ float getRSSI() override; /*! - \brief Gets RSSI (Recorded Signal Strength Indicator). + \brief Gets RSSI (Received Signal Strength Indicator). \param packet Whether to read last packet RSSI, or the current value. \returns RSSI value in dBm. */ diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index e3f0c1de89..1a0da34492 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -258,14 +258,14 @@ class SX1272: public SX127x { int16_t setDataShapingOOK(uint8_t sh); /*! - \brief Gets recorded signal strength indicator. + \brief Gets received signal strength indicator. Overload with packet mode enabled for PhysicalLayer compatibility. \returns RSSI value in dBm. */ float getRSSI() override; /*! - \brief Gets recorded signal strength indicator. + \brief Gets received signal strength indicator. \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. \returns RSSI value in dBm. diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 524c52625e..df56e090be 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -270,14 +270,14 @@ class SX1278: public SX127x { int16_t setDataShapingOOK(uint8_t sh); /*! - \brief Gets recorded signal strength indicator. + \brief Gets received signal strength indicator. Overload with packet mode enabled for PhysicalLayer compatibility. \returns RSSI value in dBm. */ float getRSSI() override; /*! - \brief Gets recorded signal strength indicator. + \brief Gets received signal strength indicator. \param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK. \param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode. \returns RSSI value in dBm. diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 2ca9bbf629..2e968aafde 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -785,13 +785,13 @@ class SX128x: public PhysicalLayer { int16_t setGainControl(uint8_t gain = 0); /*! - \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet. \returns RSSI of the last received packet in dBm. */ float getRSSI() override; /*! - \brief Gets RSSI (Recorded Signal Strength Indicator). + \brief Gets RSSI (Received Signal Strength Indicator). \param packet Whether to read last packet RSSI, or the current value. \returns RSSI value in dBm. */ diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index d0f2a549b2..dcb6ce75fb 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -547,7 +547,7 @@ class PhysicalLayer { virtual size_t getPacketLength(bool update = true); /*! - \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + \brief Gets RSSI (Received Signal Strength Indicator) of the last received packet. \returns RSSI of the last received packet in dBm. */ virtual float getRSSI(); From 7fe071a0a68ee6599304874dcea8ffea46a54393 Mon Sep 17 00:00:00 2001 From: Wessel Date: Sat, 7 Mar 2026 16:52:35 +0100 Subject: [PATCH 1831/1848] [SX126x] Implement proper AGC reset (#1718) For SX126x: reset analog registers Co-authored-by: Wessel Nieboer --- src/modules/LR11x0/LR11x0.h | 1 - src/modules/SX126x/SX126x.h | 18 +++++++++++++ src/modules/SX126x/SX126x_commands.cpp | 36 ++++++++++++++++++++++++++ src/modules/SX126x/SX126x_config.cpp | 3 +++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/modules/LR11x0/LR11x0.h b/src/modules/LR11x0/LR11x0.h index 495154c28d..0a7fee3e1c 100644 --- a/src/modules/LR11x0/LR11x0.h +++ b/src/modules/LR11x0/LR11x0.h @@ -931,7 +931,6 @@ class LR11x0: public LRxxxx { #endif uint8_t wifiScanMode = 0; bool gnss = false; - int16_t modSetup(float tcxoVoltage, uint8_t modem); bool findChip(uint8_t ver); int16_t config(uint8_t modem); diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 590a018c49..984fb92fb1 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -184,6 +184,22 @@ class SX126x: public PhysicalLayer { */ int16_t scanChannel(const ChannelScanConfig_t &config) override; + /*! + \brief Reset the AGC gain state by performing a warm sleep, recalibration, and + image rejection calibration cycle. Re-applies DIO2 RF switch and RX boosted gain + settings if previously configured. Leaves the radio in standby mode. + \returns \ref status_codes + */ + int16_t resetAGC(); + + /*! + \brief Perform calibration of the specified blocks. + \param params Calibration parameters - bitfield of RADIOLIB_SX126X_CALIBRATE_* values. + Use RADIOLIB_SX126X_CALIBRATE_ALL to calibrate all blocks. + \returns \ref status_codes + */ + int16_t calibrate(uint8_t params); + /*! \brief Sets the module to sleep mode. To wake the device up, call standby(). Overload with warm start enabled for PhysicalLayer compatibility. @@ -889,6 +905,8 @@ class SX126x: public PhysicalLayer { uint32_t tcxoDelay = 0; uint8_t pwr = 0; + bool dio2RfSwitch = false; + bool rxBoostedGainMode = false; size_t implicitLen = 0; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; diff --git a/src/modules/SX126x/SX126x_commands.cpp b/src/modules/SX126x/SX126x_commands.cpp index bc2b14246c..f8e1cbdd49 100644 --- a/src/modules/SX126x/SX126x_commands.cpp +++ b/src/modules/SX126x/SX126x_commands.cpp @@ -8,6 +8,42 @@ #if !RADIOLIB_EXCLUDE_SX126X +int16_t SX126x::resetAGC() { + // warm sleep to power down the analog frontend + int16_t state = sleep(true); + RADIOLIB_ASSERT(state); + + // wake to RC standby + state = standby(RADIOLIB_SX126X_STANDBY_RC, true); + RADIOLIB_ASSERT(state); + + // recalibrate all blocks + state = calibrate(RADIOLIB_SX126X_CALIBRATE_ALL); + RADIOLIB_ASSERT(state); + + // re-calibrate image rejection for the operating frequency + state = calibrateImage(this->freqMHz); + RADIOLIB_ASSERT(state); + + // re-apply DIO2 RF switch if it was configured + if(this->dio2RfSwitch) { + state = setDio2AsRfSwitch(true); + RADIOLIB_ASSERT(state); + } + + // re-apply RX boosted gain if it was configured + if(this->rxBoostedGainMode) { + state = setRxBoostedGainMode(true); + RADIOLIB_ASSERT(state); + } + + return(RADIOLIB_ERR_NONE); +} + +int16_t SX126x::calibrate(uint8_t params) { + return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, ¶ms, 1, true, false)); +} + int16_t SX126x::sleep() { return(SX126x::sleep(true)); } diff --git a/src/modules/SX126x/SX126x_config.cpp b/src/modules/SX126x/SX126x_config.cpp index 3a13404b1a..c8b56e68aa 100644 --- a/src/modules/SX126x/SX126x_config.cpp +++ b/src/modules/SX126x/SX126x_config.cpp @@ -394,6 +394,8 @@ int16_t SX126x::setRxBandwidth(float rxBw) { } int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) { + this->rxBoostedGainMode = rxbgm; + // update RX gain setting register uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING; int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1); @@ -708,6 +710,7 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { } int16_t SX126x::setDio2AsRfSwitch(bool enable) { + this->dio2RfSwitch = enable; uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ; return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1)); } From 65084d0c5c34988b34cc75949cbe00022807bb2c Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Sun, 8 Mar 2026 15:06:25 +0100 Subject: [PATCH 1832/1848] [LoRaWAN] Add optional activity LEDs --- keywords.txt | 1 + src/protocols/LoRaWAN/LoRaWAN.cpp | 48 +++++++++++++++++++++++++++++-- src/protocols/LoRaWAN/LoRaWAN.h | 9 ++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index c903daa5da..1498d81da3 100644 --- a/keywords.txt +++ b/keywords.txt @@ -385,6 +385,7 @@ setDutyCycle KEYWORD2 setDwellTime KEYWORD2 setCSMA KEYWORD2 setDeviceStatus KEYWORD2 +setActivityLeds KEYWORD2 scheduleTransmission KEYWORD2 getBand KEYWORD2 getClass KEYWORD2 diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index bb5b69aba7..340b5812cf 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -1200,6 +1200,11 @@ void LoRaWANNode::stopMulticastSession() { // stop any ongoing activity this->phyLayer->standby(); + + if(this->ledPins[RADIOLIB_LORAWAN_RX_BC] != RADIOLIB_NC) { + Module *mod = this->phyLayer->getMod(); + mod->hal->digitalWrite(this->ledPins[RADIOLIB_LORAWAN_RX_BC], mod->hal->GpioLevelLow); + } // if in Class C, re-open RxC window with normal unicast configuration if(this->lwClass == RADIOLIB_LORAWAN_CLASS_C) { @@ -1467,6 +1472,10 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u } } + if(this->ledPins[0] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[0], mod->hal->GpioLevelHigh); + } + // start transmission, and time the duration of launchMode() to offset window timing RadioLibTime_t spiStart = mod->hal->millis(); state = this->phyLayer->launchMode(); @@ -1491,6 +1500,11 @@ int16_t LoRaWANNode::transmitUplink(const LoRaWANChannel_t* chnl, uint8_t* in, u // set the timestamp so that we can measure when to start receiving this->tUplinkEnd = mod->hal->millis(); + + if(this->ledPins[0] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[0], mod->hal->GpioLevelLow); + } + RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Uplink sent (ToA = %d ms)", toa); // increase Time on Air of the uplink sequence @@ -1568,6 +1582,10 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne this->sleepDelay(tWindow - tNow); } + if(window < 4 && this->ledPins[window] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[window], mod->hal->GpioLevelHigh); + } + // open Rx window by starting receive with specified timeout state = this->phyLayer->launchMode(); RadioLibTime_t tOpen = mod->hal->millis(); @@ -1595,6 +1613,9 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne this->phyLayer->clearPacketReceivedAction(); this->phyLayer->clearIrq(1UL << RADIOLIB_IRQ_TIMEOUT); this->phyLayer->standby(); + if(window < 4 && this->ledPins[window] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[window], mod->hal->GpioLevelLow); + } return(0); // no downlink } @@ -1624,6 +1645,9 @@ int16_t LoRaWANNode::receiveClassA(uint8_t dir, const LoRaWANChannel_t* dlChanne // we have a message, clear actions, go to standby this->phyLayer->clearPacketReceivedAction(); this->phyLayer->standby(); + if(window < 4 && this->ledPins[window] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[window], mod->hal->GpioLevelLow); + } // if all windows passed without receiving anything, return 0 for no window if(!downlinkAction) { @@ -1675,6 +1699,10 @@ int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { state = this->phyLayer->stageMode(RADIOLIB_RADIO_MODE_RX, &modeCfg); RADIOLIB_ASSERT(state); + if(this->ledPins[RADIOLIB_LORAWAN_RX_BC] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[RADIOLIB_LORAWAN_RX_BC], mod->hal->GpioLevelHigh); + } + // open RxC window by starting receive with specified timeout state = this->phyLayer->launchMode(); RadioLibTime_t tOpen = mod->hal->millis(); @@ -1683,8 +1711,7 @@ int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { if(timeout) { // wait for the DIO interrupt to fire (RxDone or RxTimeout) - // use a small additional delay in case the RxTimeout interrupt is slow to fire - while(!downlinkAction && mod->hal->millis() - tOpen <= timeout + this->scanGuard) { + while(!downlinkAction && mod->hal->millis() - tOpen <= timeout) { mod->hal->yield(); } RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Closed RxC window"); @@ -1700,6 +1727,9 @@ int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { this->phyLayer->clearPacketReceivedAction(); this->phyLayer->clearIrq(1UL << RADIOLIB_IRQ_TIMEOUT); this->phyLayer->standby(); + if(this->ledPins[RADIOLIB_LORAWAN_RX_BC] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[RADIOLIB_LORAWAN_RX_BC], mod->hal->GpioLevelLow); + } return(0); // no downlink } @@ -1711,6 +1741,9 @@ int16_t LoRaWANNode::receiveClassC(RadioLibTime_t timeout) { // we have a message, clear actions, go to standby this->phyLayer->clearPacketReceivedAction(); this->phyLayer->standby(); + if(this->ledPins[RADIOLIB_LORAWAN_RX_BC] != RADIOLIB_NC) { + mod->hal->digitalWrite(this->ledPins[RADIOLIB_LORAWAN_RX_BC], mod->hal->GpioLevelLow); + } // if all windows passed without receiving anything, return 0 for no window if(!downlinkAction) { @@ -3216,6 +3249,17 @@ void LoRaWANNode::setDeviceStatus(uint8_t battLevel) { this->battLevel = battLevel; } +void LoRaWANNode::setActivityLeds(const uint32_t pins[4]) { + Module *mod = this->phyLayer->getMod(); + // configure each provided pin and store in the ledPins array + for(uint8_t i = 0; i < 4; i++) { + if(pins[i] != RADIOLIB_NC) { + mod->hal->pinMode(pins[i], mod->hal->GpioModeOutput); + } + this->ledPins[i] = pins[i]; + } +} + void LoRaWANNode::scheduleTransmission(RadioLibTime_t tUplink) { this->tUplink = tUplink; } diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 0d09a9b499..994d96673a 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -848,6 +848,13 @@ class LoRaWANNode { */ void setDeviceStatus(uint8_t battLevel); + /*! + \brief Set pins for activity LEDs that will indicate when the radio is transmitting (Tx) or receiving (Rx). + \param pins Array of 4 pin numbers: [Tx, Rx1, Rx2, RxBC]. + Use RADIOLIB_NC to disable individual indicators. + */ + void setActivityLeds(const uint32_t pins[4]); + /*! \brief Set the exact time a transmission should occur. Note: this is the internal clock time. On Arduino platforms, this is the usual time supplied by millis(). @@ -1093,6 +1100,8 @@ class LoRaWANNode { RADIOLIB_LORAWAN_RECEIVE_DELAY_2_MS, 0 }; + uint32_t ledPins[4] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC }; + // offset between Tx and Rx1 (such that Rx1 has equal or lower DR) uint8_t rx1DrOffset = 0; From fb1020f753e59616bcdfd48427a8724dd9c86638 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 11 Mar 2026 19:43:16 +0000 Subject: [PATCH 1833/1848] [LR2021] Make getLoRaPacketStatus public (#1721) --- src/modules/LR2021/LR2021.h | 14 +++++++++++++- src/modules/LR2021/LR2021_cmds_lora.cpp | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 1a309d69b8..4fb707ea55 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -678,6 +678,19 @@ class LR2021: public LRxxxx { */ int16_t setGain(uint8_t gain); + /*! + \brief Read status of the last received packet. + Each parameter can be set to NULL if the caller is not intending to process it. + \param cr Coding rate of the last received packet + \param crc Will be set to true if the last packet had a CRC, false otherwise + \param packetLen Length of the last received packet in bytes + \param snrPacket SNR of the last received packet in dB + \param rssiPacket RSSI of the last received packet in dBm + \param rssiSignalPacket Estimation of the RSSI of LoRa signal after despreading in dBm + \returns \ref status_codes + */ + int16_t getLoRaPacketStatus(uint8_t* cr, bool* crc, uint8_t* packetLen = NULL, float* snrPacket = NULL, float* rssiPacket = NULL, float* rssiSignalPacket = NULL); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif @@ -779,7 +792,6 @@ class LR2021: public LRxxxx { int16_t setLoRaCadParams(uint8_t numSymbols, bool preambleOnly, uint8_t pnrDelta, uint8_t cadExitMode, uint32_t timeout, uint8_t detPeak); int16_t setLoRaCad(void); int16_t getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint16_t* headerCrcError, uint16_t* falseSynch); - int16_t getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket); int16_t setLoRaAddress(uint8_t addrLen, uint8_t addrPos, const uint8_t* addr); int16_t setLoRaHopping(uint8_t hopCtrl, uint16_t hopPeriod, const uint32_t* freqHops, size_t numFreqHops); int16_t setLoRaTxSync(uint8_t function, uint8_t dioNum); diff --git a/src/modules/LR2021/LR2021_cmds_lora.cpp b/src/modules/LR2021/LR2021_cmds_lora.cpp index 3db944abae..68f6eafc4d 100644 --- a/src/modules/LR2021/LR2021_cmds_lora.cpp +++ b/src/modules/LR2021/LR2021_cmds_lora.cpp @@ -72,7 +72,7 @@ int16_t LR2021::getLoRaRxStats(uint16_t* pktRxTotal, uint16_t* pktCrcError, uint return(state); } -int16_t LR2021::getLoRaPacketStatus(uint8_t* crc, uint8_t* cr, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket) { +int16_t LR2021::getLoRaPacketStatus(uint8_t* cr, bool* crc, uint8_t* packetLen, float* snrPacket, float* rssiPacket, float* rssiSignalPacket) { uint8_t buff[6] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_LORA_PACKET_STATUS, false, buff, sizeof(buff)); uint16_t raw; From 687e51727f1264777e3ecf4969f928827a3d2850 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 14 Mar 2026 11:02:10 +0300 Subject: [PATCH 1834/1848] [LR2021] a fix for reverse order of bytes in OOK sync word (#1722) * [LR2021] a fix for reverse order of bytes in OOK sync word * [LR2021] Add check for OOK sync word length --------- Co-authored-by: jgromes --- src/modules/LR2021/LR2021_cmds_ook.cpp | 9 +++++++-- src/modules/LR2021/LR2021_commands.h | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 7d473f9b4b..3dd3fe1082 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -37,9 +37,14 @@ int16_t LR2021::setOokCrcParams(uint32_t poly, uint32_t init) { } int16_t LR2021::setOokSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst) { + // OOK maximum sync word length is just 32-bits, unlike GFSK + if(syncWordLen > RADIOLIB_LR2021_OOK_SYNC_WORD_LEN) { + return(RADIOLIB_ERR_INVALID_SYNC_WORD); + } + uint8_t buff[5] = { 0 }; - for(size_t i = 0; i < syncWordLen; i++) { - buff[3 - i] = syncWord[i]; + for(int8_t i = 3; i >= (int8_t) (RADIOLIB_LR2021_OOK_SYNC_WORD_LEN - syncWordLen); i--) { + buff[i] = syncWord[i - (int8_t) (RADIOLIB_LR2021_OOK_SYNC_WORD_LEN - syncWordLen)]; } buff[4] = (uint8_t)msbFirst << 7 | ((syncWordLen*8) & 0x7F); return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD, true, buff, sizeof(buff))); diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index d858c7807f..1d36e05433 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -516,6 +516,9 @@ #define RADIOLIB_LR2021_OOK_MANCHESTER_ON (0x01UL << 0) // 3 0 enabled #define RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV (0x09UL << 0) // 3 0 enabled, inverted +// RADIOLIB_LR2021_CMD_SET_OOK_SYNCWORD +#define RADIOLIB_LR2021_OOK_SYNC_WORD_LEN (4) + // RADIOLIB_LR2021_CMD_SET_TX_TEST_MODE #define RADIOLIB_LR2021_TX_TEST_MODE_NORMAL_TX (0x00UL << 0) // 7 0 Tx test mode: normal #define RADIOLIB_LR2021_TX_TEST_MODE_INF_PREAMBLE (0x01UL << 0) // 7 0 infinite preamble From bd38aa484686706394584561e3082209407db9f6 Mon Sep 17 00:00:00 2001 From: Linar Yusupov Date: Sat, 14 Mar 2026 11:04:57 +0300 Subject: [PATCH 1835/1848] [LR2021] a fix for OOK packet's RSSI return value (#1723) * [LR2021] a fix for OOK packet's RSSI return value * [LR2021] Add comment about packet RSSI for OOK modem --------- Co-authored-by: jgromes --- src/modules/LR2021/LR2021.cpp | 2 ++ src/modules/LR2021/LR2021.h | 3 ++- src/modules/LR2021/LR2021_cmds_ook.cpp | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 7595af8847..9fe67d38a0 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -1021,6 +1021,8 @@ float LR2021::getRSSI(bool packet, bool skipReceive) { state = this->getLoRaPacketStatus(NULL, NULL, NULL, NULL, &rssi, NULL); } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) { state = this->getGfskPacketStatus(NULL, &rssi, NULL, NULL, NULL, NULL); + } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) { + state = this->getOokPacketStatus(NULL, NULL, &rssi, NULL, NULL, NULL); } else { return(0); } diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 4fb707ea55..4a90b57125 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -604,6 +604,7 @@ class LR2021: public LRxxxx { /*! \brief Gets RSSI (Received Signal Strength Indicator). \param packet Whether to read last packet RSSI, or the current value. + NOTE: With OOK modem, the "packet" RSSI value is the received power level of the high bits (digital 1). \param skipReceive Set to true to skip putting radio in receive mode for instantaneous RSSI measurement. If false, after the RSSI measurement, the radio will be in standby mode. \returns RSSI value in dBm. @@ -847,7 +848,7 @@ class LR2021: public LRxxxx { int16_t setOokSyncword(const uint8_t* syncWord, size_t syncWordLen, bool msbFirst); int16_t setOokAddress(uint8_t addrNode, uint8_t addrBroadcast); int16_t getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* lenError); - int16_t getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); + int16_t getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiHigh, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi); int16_t setOokDetector(uint16_t preamblePattern, uint8_t patternLen, uint8_t patternNumRepeaters, bool syncWordRaw, bool sofDelimiterRising, uint8_t sofDelimiterLen); int16_t setOokWhiteningParams(uint8_t bitIdx, uint16_t poly, uint16_t init); diff --git a/src/modules/LR2021/LR2021_cmds_ook.cpp b/src/modules/LR2021/LR2021_cmds_ook.cpp index 3dd3fe1082..392a097b2c 100644 --- a/src/modules/LR2021/LR2021_cmds_ook.cpp +++ b/src/modules/LR2021/LR2021_cmds_ook.cpp @@ -64,7 +64,7 @@ int16_t LR2021::getOokRxStats(uint16_t* packetRx, uint16_t* crcError, uint16_t* return(state); } -int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiSync, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { +int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* rssiHigh, bool* addrMatchNode, bool* addrMatchBroadcast, float* lqi) { uint8_t buff[6] = { 0 }; int16_t state = this->SPIcommand(RADIOLIB_LR2021_CMD_GET_OOK_PACKET_STATUS, false, buff, sizeof(buff)); uint16_t raw; @@ -74,10 +74,10 @@ int16_t LR2021::getOokPacketStatus(uint16_t* packetLen, float* rssiAvg, float* r raw |= (buff[4] & 0x04) >> 2; *rssiAvg = (float)raw / -2.0f; } - if(rssiSync) { + if(rssiHigh) { raw = (uint16_t)buff[3] << 1; raw |= (buff[4] & 0x01); - *rssiSync = (float)raw / -2.0f; + *rssiHigh = (float)raw / -2.0f; } if(addrMatchNode) { *addrMatchNode = (buff[4] & 0x10); } if(addrMatchBroadcast) { *addrMatchBroadcast = (buff[4] & 0x20); } From 989c64aea7f2f0587f5f6e4342e15ef9585e8e3b Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 Mar 2026 16:42:53 +0000 Subject: [PATCH 1836/1848] [SX127x] Enforce frequency range checking (#1724) --- src/modules/SX127x/SX1276.cpp | 6 +++++- src/modules/SX127x/SX1276.h | 2 +- src/modules/SX127x/SX1277.cpp | 6 +++++- src/modules/SX127x/SX1277.h | 2 +- src/modules/SX127x/SX1278.cpp | 5 ++++- src/modules/SX127x/SX1278.h | 2 +- src/modules/SX127x/SX1279.cpp | 6 +++++- src/modules/SX127x/SX1279.h | 2 +- 8 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 596464fd4e..09c6afe447 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -69,7 +69,11 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1276::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY); + if(!(((freq >= 137.0f) && (freq <= 175.0f)) || + ((freq >= 410.0f) && (freq <= 525.0f)) || + ((freq >= 862.0f) && (freq <= 1020.0f)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 0ea9ea4db5..be453470d2 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -58,7 +58,7 @@ class SX1276: public SX1278 { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 410.0 to 525.0 MHz and 862.0 to 1020 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index ad87fdd64e..e24988806d 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -69,7 +69,11 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1277::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY); + if(!(((freq >= 137.0f) && (freq <= 175.0f)) || + ((freq >= 410.0f) && (freq <= 525.0f)) || + ((freq >= 862.0f) && (freq <= 1020.0f)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index dabc654546..89c630ebb9 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -58,7 +58,7 @@ class SX1277: public SX1278 { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 410.0 to 525.0 MHz and 862.0 to 1020 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 74a861d43d..8d6a3353a4 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -83,7 +83,10 @@ void SX1278::reset() { } int16_t SX1278::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0f, 525.0f, RADIOLIB_ERR_INVALID_FREQUENCY); + if(!(((freq >= 137.0f) && (freq <= 175.0f)) || + ((freq >= 410.0f) && (freq <= 525.0f)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index df56e090be..e3882dc701 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -155,7 +155,7 @@ class SX1278: public SX127x { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz and 410.0 to 525.0 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 92d9f59cbd..5f167c6831 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -69,7 +69,11 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1279::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 137.0f, 960.0f, RADIOLIB_ERR_INVALID_FREQUENCY); + if(!(((freq >= 137.0f) && (freq <= 160.0f)) || + ((freq >= 410.0f) && (freq <= 480.0f)) || + ((freq >= 779.0f) && (freq <= 960.0f)))) { + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index b2b5b73548..b0cddf0191 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -58,7 +58,7 @@ class SX1279: public SX1278 { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 960.0 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 160.0 MHz, 410.0 to 480.0 MHz and 779.0 to 960 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ From 7f7eca4149ba54dbb8cefa822664bd94e82d44c2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 17 Mar 2026 19:13:25 +0000 Subject: [PATCH 1837/1848] [AX.25] Add support for G3RUH coding (#1637) --- src/protocols/AX25/AX25.cpp | 10 ++++++++++ src/protocols/AX25/AX25.h | 9 +++++++++ src/utils/Utils.h | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index c05a4d20c9..ea16083ff0 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -263,6 +263,11 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preL return(phyLayer->startDirect()); } +void AX25Client::setScrambler(uint32_t poly, uint32_t init) { + this->scramblerPoly = poly; + this->scramblerInit = init; +} + #if defined(RADIOLIB_BUILD_ARDUINO) int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t destSSID) { return(transmit(str.c_str(), destCallsign, destSSID)); @@ -474,6 +479,11 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } } + // do the scrambling + if(scramblerPoly) { + rlb_scrambler(stuffedFrameBuff, stuffedFrameBuffLen, scramblerPoly, scramblerInit, true); + } + // transmit int16_t state = RADIOLIB_ERR_NONE; #if !RADIOLIB_EXCLUDE_AFSK diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index 1349954613..250cf17e8a 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -281,6 +281,13 @@ class AX25Client { */ int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preLen = 8); + /*! + \brief Set scrambling polynomail and initial value. + \param poly Scramling polynomial. Use RADIOLIB_SCRAMBLER_G3RUH_POLY for G3RUH coding. + \param poly Initial scrambler value. Use RADIOLIB_SCRAMBLER_G3RUH_INIT for G3RUH coding. + */ + void setScrambler(uint32_t poly, uint32_t init = 0); + #if defined(RADIOLIB_BUILD_ARDUINO) /*! \brief Transmit unnumbered information (UI) frame. @@ -324,6 +331,8 @@ class AX25Client { char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 }; uint8_t sourceSSID = 0; uint16_t preambleLen = 0; + uint32_t scramblerInit = 0; + uint32_t scramblerPoly = 0; void getCallsign(char* buff); uint8_t getSSID(); diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 8a144c0034..f668a13ea4 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -18,7 +18,7 @@ // frequently used scrambling configurations // the final bit (x^0 term in polynomial notation) is assumed to always be present -#define RADIOLIB_SCRAMBLER_G3RUH_POLY (0x00021001UL) // x^17 + x^12 + 1 +#define RADIOLIB_SCRAMBLER_G3RUH_POLY (0x00010800UL) // x^17 + x^12 + 1 #define RADIOLIB_SCRAMBLER_G3RUH_INIT (0x00000000UL) /*! From dff0ee6f165f9c58a6ce1a2caae97917b46a7cf1 Mon Sep 17 00:00:00 2001 From: FernandoGM5 <120804676+FernandoGM5@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:21:42 +0100 Subject: [PATCH 1838/1848] Fix dataSent update in CC1101 FIFO handling Corrected dataSent update logic to assign initialWrite directly. --- src/modules/CC1101/CC1101.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index ee1d553095..bc3afaf55e 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -282,7 +282,7 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // fill the FIFO uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), initialWrite); - dataSent += initialWrite; + dataSent = initialWrite; // set RF switch (if present) this->mod->setRfSwitchState(Module::MODE_TX); From c9e061a330d735a18854566bd58e344f2c07b022 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 18 Mar 2026 17:24:02 +0000 Subject: [PATCH 1839/1848] [CC1101] Add explanation for coutner reset --- src/modules/CC1101/CC1101.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index bc3afaf55e..86da5ca933 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -266,8 +266,8 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // optionally write packet length if(this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) { - if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); + if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); } SPIwriteRegister(RADIOLIB_CC1101_REG_FIFO, len + (filter != RADIOLIB_CC1101_ADR_CHK_NONE? 1:0)); dataSent+= 1; @@ -282,6 +282,8 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // fill the FIFO uint8_t initialWrite = RADIOLIB_MIN((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(data), initialWrite); + + // reset the data sent counter as it will be used later to calculate the remaining number of bytes to read from the user buffer dataSent = initialWrite; // set RF switch (if present) @@ -290,24 +292,26 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { // set mode to transmit SPIsendCommand(RADIOLIB_CC1101_CMD_TX); - // Keep feeding the FIFO until the packet is done + // keep feeding the FIFO until the packet is done while (dataSent < len) { uint8_t fifoBytes = 0; uint8_t prevFifobytes = 0; - // Check number of bytes on FIFO twice due to the CC1101 errata. Block until two reads are equal. - do{ + // check number of bytes on FIFO twice due to the CC1101 errata + // block until two reads are equal + do { fifoBytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); prevFifobytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); - } while (fifoBytes != prevFifobytes); + } while(fifoBytes != prevFifobytes); //If there is room add more data to the FIFO - if (fifoBytes < RADIOLIB_CC1101_FIFO_SIZE) { - uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - fifoBytes), (uint8_t)(len - dataSent)); - SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(&data[dataSent]), bytesToWrite); - dataSent += bytesToWrite; + if(fifoBytes < RADIOLIB_CC1101_FIFO_SIZE) { + uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - fifoBytes), (uint8_t)(len - dataSent)); + SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(&data[dataSent]), bytesToWrite); + dataSent += bytesToWrite; } } + return(state); } From db2fbcaeb875432cc7b16098474c80532488d843 Mon Sep 17 00:00:00 2001 From: SeeedZhangyh Date: Thu, 19 Mar 2026 10:24:55 +0800 Subject: [PATCH 1840/1848] [LR2021] Add getLoRaRxHeaderInfo function --- src/modules/LR2021/LR2021.cpp | 6 ++++++ src/modules/LR2021/LR2021.h | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 9fe67d38a0..14e1484620 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -1048,4 +1048,10 @@ uint8_t LR2021::randomByte() { return((uint8_t)num); } +int16_t LR2021::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC){ + int16_t state; + state = this->getLoRaPacketStatus(cr, hasCRC, NULL, NULL, NULL, NULL); + return (state); +} + #endif diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 4a90b57125..b37f414b2d 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -691,7 +691,15 @@ class LR2021: public LRxxxx { \returns \ref status_codes */ int16_t getLoRaPacketStatus(uint8_t* cr, bool* crc, uint8_t* packetLen = NULL, float* snrPacket = NULL, float* rssiPacket = NULL, float* rssiSignalPacket = NULL); - + + /*! + \brief Get LoRa header information from last received packet. Implementation based on getLoRaPacketStatus. + \param cr Pointer to variable to store the coding rate. + \param hasCRC Pointer to variable to store the CRC status. + \returns \ref status_codes + */ + int16_t getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC); + #if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL protected: #endif From 25c50b4ce63b8c57d7fc18781e3fe446f7707ed5 Mon Sep 17 00:00:00 2001 From: SeeedZhangyh Date: Thu, 19 Mar 2026 13:51:45 +0800 Subject: [PATCH 1841/1848] [LR2021] Updated CAD detection for LR 2021, resolving the freezing issue (#1727) * Updated CAD detection for LR 2021, resolving the freezing issue. * Updated CAD detection for LR 2021, resolving the freezing issue. * update * Modify Parameter Position * [LR2021] Cleanup fast CAD handling --------- Co-authored-by: jgromes --- src/modules/LR2021/LR2021.cpp | 29 ++++++++++++---------------- src/modules/LR2021/LR2021.h | 9 ++++++++- src/modules/LR2021/LR2021_commands.h | 4 ++++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index 9fe67d38a0..724192c19a 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -550,7 +550,7 @@ int16_t LR2021::startChannelScan(const ChannelScanConfig_t &config) { RADIOLIB_ASSERT(state); // set mode to CAD - return(startCad(config.cad.symNum, config.cad.detPeak, config.cad.detMin, config.cad.exitMode, config.cad.timeout)); + return(startCad(config.cad.symNum, config.cad.detPeak, this->fastCad, config.cad.exitMode, config.cad.timeout)); } int16_t LR2021::getChannelScanResult() { @@ -721,7 +721,7 @@ int16_t LR2021::config(uint8_t modem) { return(state); } -int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) { +int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, bool fast, uint8_t exitMode, RadioLibTime_t timeout) { // check active modem uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE; int16_t state = getPacketType(&type); @@ -731,22 +731,21 @@ int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uin } // select CAD parameters - //! \TODO: [LR2021] the magic numbers for CAD are based on Semtech examples, this is probably suboptimal uint8_t num = symbolNum; if(num == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { num = 2; } - const uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 }; + // reference values ​​from the datasheet for 2 symbols + //! \TODO: [LR2021] allow CAD peak detection autoconfiguration + const uint8_t detPeakValues[8] = { 56, 56, 56, 58, 58, 60, 64, 68 }; uint8_t peak = detPeak; if(peak == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { peak = detPeakValues[this->spreadingFactor - 5]; } - uint8_t min = detMin; - if(min == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { - min = 10; - } + // in Fast CAD mode enable acceleration + uint8_t pnrDelta = fast ? RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_FAST : RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_STANDARD; uint8_t mode = exitMode; if(mode == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) { @@ -755,17 +754,13 @@ int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uin uint32_t timeout_raw = (float)timeout / 30.52f; - //! \TODO: [LR2021] The datasheet says this CAD is only based on RSSI, but the reference to the LoRa CAD is GetLoraRxStats ...? - (void)peak; - (void)min; - - // set CAD parameters - //! \TODO: [LR2021] add configurable exit mode and timeout - state = setCadParams(timeout_raw, num, mode, timeout_raw); + // set LoRa CAD parameters + // preamble only mode is intentionally disabled, as it is unreliable according to the datasheet + state = setLoRaCadParams(num, false, pnrDelta, mode, timeout_raw, peak); RADIOLIB_ASSERT(state); - // start CAD - return(setCad()); + // start LoraCAD + return(setLoRaCad()); } RadioLibTime_t LR2021::getTimeOnAir(size_t len) { diff --git a/src/modules/LR2021/LR2021.h b/src/modules/LR2021/LR2021.h index 4a90b57125..64343083cd 100644 --- a/src/modules/LR2021/LR2021.h +++ b/src/modules/LR2021/LR2021.h @@ -42,6 +42,13 @@ class LR2021: public LRxxxx { */ uint32_t irqDioNum = 5; + /*! + \brief Determines the type of Lora CAD to perform, either "standard" CAD + (same as is implem,ented LR11x0, SX126x and others), or a "fast" CAD if set to true. + If there is no signal to be detected, fast CAD should return faster than standard CAD. + */ + bool fastCad = false; + /*! \brief Custom operation modes for LR2021. Needed because LR2021 has several modems (sub-GHz, 2.4 GHz etc.) in one package @@ -718,7 +725,7 @@ class LR2021: public LRxxxx { bool findChip(void); int16_t config(uint8_t modem); int16_t setPacketMode(uint8_t mode, uint8_t len); - int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout); + int16_t startCad(uint8_t symbolNum, uint8_t detPeak, bool fast, uint8_t exitMode, RadioLibTime_t timeout); // chip control commands int16_t readRadioRxFifo(uint8_t* data, size_t len); diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 1d36e05433..39acf11b04 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -404,6 +404,10 @@ #define RADIOLIB_LR2021_LORA_SYNC_WORD_PRIVATE (0x12UL << 0) // 7 0 LoRa sync word: 0x12 (private networks) #define RADIOLIB_LR2021_LORA_SYNC_WORD_LORAWAN (0x34UL << 0) // 7 0 0x34 (LoRaWAN reserved) +// RADIOLIB_LR2021_CMD_SET_LORA_CAD_PARAMS +#define RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_STANDARD (0x00UL << 0) // 7 0 LoRa CAD speed: normal +#define RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_FAST (0x08UL << 0) // 7 0 fast CAD + // RADIOLIB_LR2021_CMD_SET_LORA_HOPPING #define RADIOLIB_LR2021_LORA_HOPPING_DISABLED (0x00UL << 6) // 7 6 LoRa intra-packet hopping: disabled #define RADIOLIB_LR2021_LORA_HOPPING_ENABLED (0x01UL << 6) // 7 6 enabled From 631e0910a220b6e69021b0a51bcc83e490b3237d Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 19 Mar 2026 17:30:25 +0000 Subject: [PATCH 1842/1848] [LR2021] Formatting fixup --- src/modules/LR2021/LR2021.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/modules/LR2021/LR2021.cpp b/src/modules/LR2021/LR2021.cpp index a84f490893..139b3acad9 100644 --- a/src/modules/LR2021/LR2021.cpp +++ b/src/modules/LR2021/LR2021.cpp @@ -1044,9 +1044,7 @@ uint8_t LR2021::randomByte() { } int16_t LR2021::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC){ - int16_t state; - state = this->getLoRaPacketStatus(cr, hasCRC, NULL, NULL, NULL, NULL); - return (state); + return(this->getLoRaPacketStatus(cr, hasCRC, NULL, NULL, NULL, NULL)); } #endif From ae33c4819e3d28910d9493f5bf9cc4799e1a4dc8 Mon Sep 17 00:00:00 2001 From: Olivier Ouellet Date: Fri, 20 Mar 2026 23:04:12 -0400 Subject: [PATCH 1843/1848] Check if board is using DWT before calling dwt_init() on STM32 --- src/hal/Arduino/ArduinoHal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/Arduino/ArduinoHal.cpp b/src/hal/Arduino/ArduinoHal.cpp index 04989bcfd3..c99d0df226 100644 --- a/src/hal/Arduino/ArduinoHal.cpp +++ b/src/hal/Arduino/ArduinoHal.cpp @@ -10,7 +10,7 @@ void ArduinoHal::init() { if(initInterface) { spiBegin(); } - #if defined(ARDUINO_ARCH_STM32) + #if defined(ARDUINO_ARCH_STM32) && defined(DWT_BASE) dwt_init(); #endif } From f2286dcbd44c86a9ff83c11bab9e45f35ca450c1 Mon Sep 17 00:00:00 2001 From: Galile0 Date: Sun, 22 Mar 2026 07:52:01 +0100 Subject: [PATCH 1844/1848] [SX127x] Slightly Update frequency ranges in SX127x modules (#1733) * Slightly Update frequency ranges in SX127x modules * Update frequency range limits for SX127x modules to accommodate real-world use cases --- src/modules/SX127x/SX1276.cpp | 6 +++++- src/modules/SX127x/SX1276.h | 2 +- src/modules/SX127x/SX1277.cpp | 6 +++++- src/modules/SX127x/SX1277.h | 2 +- src/modules/SX127x/SX1278.cpp | 6 +++++- src/modules/SX127x/SX1278.h | 2 +- src/modules/SX127x/SX1279.cpp | 6 +++++- src/modules/SX127x/SX1279.h | 2 +- 8 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 09c6afe447..9da2d19b57 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -69,8 +69,12 @@ int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1276::setFrequency(float freq) { + // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been + // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to + // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while + // adding a small margin below the 400 MHz practical limit. if(!(((freq >= 137.0f) && (freq <= 175.0f)) || - ((freq >= 410.0f) && (freq <= 525.0f)) || + ((freq >= 395.0f) && (freq <= 525.0f)) || ((freq >= 862.0f) && (freq <= 1020.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index be453470d2..402b8cd1ae 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -58,7 +58,7 @@ class SX1276: public SX1278 { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 410.0 to 525.0 MHz and 862.0 to 1020 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 395.0 to 525.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower) and 862.0 to 1020 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index e24988806d..aae1c7801b 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -69,8 +69,12 @@ int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1277::setFrequency(float freq) { + // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been + // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to + // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while + // adding a small margin below the 400 MHz practical limit. if(!(((freq >= 137.0f) && (freq <= 175.0f)) || - ((freq >= 410.0f) && (freq <= 525.0f)) || + ((freq >= 395.0f) && (freq <= 525.0f)) || ((freq >= 862.0f) && (freq <= 1020.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index 89c630ebb9..3c0c071d09 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -58,7 +58,7 @@ class SX1277: public SX1278 { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 410.0 to 525.0 MHz and 862.0 to 1020 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz, 395.0 to 525.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower) and 862.0 to 1020 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 8d6a3353a4..0605620b86 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -83,8 +83,12 @@ void SX1278::reset() { } int16_t SX1278::setFrequency(float freq) { + // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been + // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to + // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while + // adding a small margin below the 400 MHz practical limit. if(!(((freq >= 137.0f) && (freq <= 175.0f)) || - ((freq >= 410.0f) && (freq <= 525.0f)))) { + ((freq >= 395.0f) && (freq <= 525.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index e3882dc701..600283f477 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -155,7 +155,7 @@ class SX1278: public SX127x { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz and 410.0 to 525.0 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 175.0 MHz and 395.0 to 525.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower). \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 5f167c6831..e356f62b19 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -69,8 +69,12 @@ int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1279::setFrequency(float freq) { + // NOTE: The datasheet specifies Band 2 as 410-480 MHz, but the hardware has been + // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to + // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while + // adding a small margin below the 400 MHz practical limit. if(!(((freq >= 137.0f) && (freq <= 160.0f)) || - ((freq >= 410.0f) && (freq <= 480.0f)) || + ((freq >= 395.0f) && (freq <= 480.0f)) || ((freq >= 779.0f) && (freq <= 960.0f)))) { return(RADIOLIB_ERR_INVALID_FREQUENCY); } diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index b0cddf0191..467807f264 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -58,7 +58,7 @@ class SX1279: public SX1278 { // configuration methods /*! - \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 160.0 MHz, 410.0 to 480.0 MHz and 779.0 to 960 MHz. + \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 160.0 MHz, 395.0 to 480.0 MHz (datasheet minimum is 410.0 MHz, hardware works lower) and 779.0 to 960 MHz. \param freq Carrier frequency to be set in MHz. \returns \ref status_codes */ From 2ee81780aa9d9effa7df6803ac234cdc6f13bf81 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2026 12:41:22 +0000 Subject: [PATCH 1845/1848] [CC1101] Fix halt in blocking transmit --- src/modules/CC1101/CC1101.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 86da5ca933..115284cf44 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -311,6 +311,11 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { dataSent += bytesToWrite; } } + + // enable interrupt for the final part of the packet + if(len > RADIOLIB_CC1101_FIFO_SIZE) { + state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0); + } return(state); } From f9fcb6c1123a850365905aaccc23ea41b4913e74 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2026 12:55:38 +0000 Subject: [PATCH 1846/1848] [CC1101] Add timeout to Tx FIFO feeding loop (#1725) --- src/modules/CC1101/CC1101.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 115284cf44..ca0f062c0f 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -293,7 +293,10 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { SPIsendCommand(RADIOLIB_CC1101_CMD_TX); // keep feeding the FIFO until the packet is done - while (dataSent < len) { + // calculate timeout (5ms + 500 % of expected time-on-air) + RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5); + start = this->mod->hal->millis(); + while(dataSent < len) { uint8_t fifoBytes = 0; uint8_t prevFifobytes = 0; @@ -304,12 +307,18 @@ int16_t CC1101::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { prevFifobytes = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0); } while(fifoBytes != prevFifobytes); - //If there is room add more data to the FIFO + // if there is room, add more data to the FIFO if(fifoBytes < RADIOLIB_CC1101_FIFO_SIZE) { uint8_t bytesToWrite = RADIOLIB_MIN((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - fifoBytes), (uint8_t)(len - dataSent)); SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, const_cast(&data[dataSent]), bytesToWrite); dataSent += bytesToWrite; } + + // check a timeout - this really shouldn't happen, but some packets can be quite long + if(this->mod->hal->millis() - start > timeout) { + (void)finishTransmit(); + return(RADIOLIB_ERR_TX_TIMEOUT); + } } // enable interrupt for the final part of the packet From 49f3211066184f75be42d264c823783a7829fd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Tue, 24 Mar 2026 21:39:02 +0100 Subject: [PATCH 1847/1848] Update contributing guideliens to consider AI use (#1738) * Add AI use chapter to contributing guidelines * Add a note that failure to adhere to AI guidelines is grounds for rejection --- CONTRIBUTING.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4bf96194b6..71e69586a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,19 @@ Issues with generic titles (e.g. "not working", "lora", etc.) will be **CLOSED** 4. **Issues deserve some attention too.** Issues that are left for 2 weeks without response by the original author when asked for further information will be closed due to inactivity. This is to keep track of important issues, the author is encouraged to reopen the issue at a later date. +## AI Use + +**RadioLib was written by humans, for humans**. Its authors, contributors, maintainers and community members were not asked for permission or approval when billion-dollar companies decided to scrape our hard work for training data, to be sold back to the world at a profit. While we consider this approach to be bordering on violating our license, this seems to be the world we live in. Therefore, if you decide to contribute to RadioLib while using an AI-based tool, please follow the rules below. + +1. **Mark the slop** +The issue or pull request must be clearly marked as fully or partially AI-generated. If you don't do it, we'll do it for you by the means of a dedicated label - and then consider whether to process your input at all. Since people like that have not even bothered to read this statement, it would be unreasonable to expect they will read the code the machine generated and that is not code we want. +2. **Less is more** +If your AI has produced a novel-length wall of text to describe a miniscule change, we consider it somewhat rude to copy-paste that output into the issue/PR description. Not only are you ignoring the templates which are asking for generally useful info; this approach also has the added bonus of explaining our own codebase back to us, while trying to sound as simple as possible. In reality though, it sounds like a junior developer giving us a lecture on a project that is older then they are. So please, try to get the actual point across in your own, human-generated words. +3. **Discuss first** +It is usually not a great idea to hit us with a large, unsolicited pull request. Especially if it changes APIs or tries to work around something. It's a lot easier to discuss these things in advance and agree on an approach in an issue. Your AI can write the PR quickly; but then we need to spend our free time on reviewing something that we did not ask for. + +RadioLib maintainers reserve the right to reject your contribution if it is not following these rules without further explanation other than directing you to this guideline document. + ## Code style guidelines I like pretty code! Or at least, I like *consistent* code style. When creating pull requests, please follow these style guidelines, they're in place to keep high code readability. From 7971af87a2087e295586ec78ced73da3d6474765 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Mar 2026 09:26:02 +0100 Subject: [PATCH 1848/1848] [LR2021] Fix setPaConfig (#1740) --- src/modules/LR2021/LR2021_cmds_radio.cpp | 4 +++- src/modules/LR2021/LR2021_commands.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/LR2021/LR2021_cmds_radio.cpp b/src/modules/LR2021/LR2021_cmds_radio.cpp index f8394d5a7a..a953d1c80e 100644 --- a/src/modules/LR2021/LR2021_cmds_radio.cpp +++ b/src/modules/LR2021/LR2021_cmds_radio.cpp @@ -95,7 +95,9 @@ int16_t LR2021::selPa(uint8_t pa) { int16_t LR2021::setPaConfig(uint8_t pa, uint8_t paLfMode, uint8_t paLfDutyCycle, uint8_t paLfSlices, uint8_t paHfDutyCycle) { uint8_t buff[] = { - (uint8_t)(pa << 7), (uint8_t)(paLfMode & 0x03), (uint8_t)(paLfDutyCycle & 0xF0), (uint8_t)(paLfSlices & 0x0F), (uint8_t)(paHfDutyCycle & 0x1F), + (uint8_t)((pa << 7) | (paLfMode & 0x03)), + (uint8_t)(((paLfDutyCycle & 0x0F) << 4) | (paLfSlices & 0x0F)), + (uint8_t)((paHfDutyCycle & 0x1F)), }; return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_PA_CONFIG, true, buff, sizeof(buff))); } diff --git a/src/modules/LR2021/LR2021_commands.h b/src/modules/LR2021/LR2021_commands.h index 39acf11b04..34b7c4d6f4 100644 --- a/src/modules/LR2021/LR2021_commands.h +++ b/src/modules/LR2021/LR2021_commands.h @@ -345,7 +345,7 @@ // RADIOLIB_LR2021_CMD_SET_PA_CONFIG #define RADIOLIB_LR2021_PA_LF_MODE_FSM (0x00UL << 0) // 1 0 PA LF mode: full single-ended mode -#define RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED (0x06UL << 4) // 7 4 PA LF duty cycle: PA not used +#define RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED (0x06UL << 0) // 7 4 PA LF duty cycle: PA not used #define RADIOLIB_LR2021_PA_LF_SLICES_UNUSED (0x07UL << 0) // 3 0 PA LF slices: PA not used #define RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED (0x10UL << 0) // 4 0 PA HF duty cycle: PA not used

y7&o*>d_kxYUWx!}8}9W-j17w-`aE`kyike7*Xc zut2~!VJ|=M&AtkC%|{BHBo!2(GG*&UHjl~%@0n$bo>itzK?841+f|})+^!_vny|gm zjp^f9We!0Hhg*&_?PW8_2J&GP_5|}%ZZf_eSeW?mAU-T%`T7T*XbQKIwreS_IoLJU ztt8Y<_C;~tC{|gP2(pHwJDu(6o>7*DI(HQ=N8wrJ8eDoLRc#fYjKJuQB>rhwn>TiN-Wv5!@+#_XvCAq>- zurl$wnRbawL-cV@f_gyItgia%G3SvQw^d)F<%rZ>E8VD=P3ICniN? z2kvd>ouo9~%d0&w)PzDbIJTi*m^S&M%r!s&j&|O$`(o(lrcLz*>@PBIpW0gE^TK33 zxgctz$k)uT0AIztBzUA6RNCw6W-|^90MP9A^^G%<6i9cD*I7^}k{o{>S(k%gvQ-cTiS6@5^B~Z$% z{M5wIm&phD!&R`?P(?JKa9kAn)EuwNud|6s?)POQfKIkfjWT#A;|Hme1&S5nK*~V6do$i za2+uyTi5$rsMqkH3yK*fHFtG*-iCN*IgLi9@$J@W6iz;-|On5cAr~_L-mP>dsy2v3=I{zkCR2!wg z{fQNI8T7mX23=Nq6W(EGpiU1-NrD9)PKGE_<|>%Cze)YYXW9`$J6TJWo_0GkCxM$8 zI*@GCJ;Fx4+<#jtp2>Lf@hrr%8qXVe+VC95Q&sQOW!}H-P-}wfQ=RHMtYE;F^J58G zvbUK&b#p7ajH9u@k~-D3yLRvpp(G^O;*VxGx=w1LU$*8NF`HbOG!S=O^FP{(LDZ+1 z+tiVCG_EmP;f*u7qrpmE9&gSx01d$nfav-{YdqVS9q+Gb-K20Ql#zLwxQ!AQ=~L#>;tE}y6meGug3gzXZ(?A5#+^KqPB zas(X}6kPNyYTeWoK2cvs35S@M@R(xU)bYP1^*`9U$^F9#g@^lu4}yv;nv;0IZ|ZDe zCW9sNJRT*J$%3$;byM&nrE5nzHw-nFn%wn2*st%0BmE9_4V;o)qTK^t!n|D$`KIlw zL~d?(g*-WSUhJ}pXz;Ht?G>s##E_`)kTvTwna6yoTh| zT;n;t+R)Eh?MB$w{LZ}%>w}#j9L3AO>yX!MI{M8CiHFms4;pzn*35lFeSGrAJ|4YQ z`f)sdit#v!#zR{2LC^@-a$E^;!7e;XAPO>h_^~m%zUc#m?zhLtc~K8CN7@MYo|4c3 zFo3puZ7eG_^!wx@2X5XeW^)oF_#m6lOSL4ja|1BB4cbne{mVW@VeV}=C_$bz(16(U zCdcv0{3Hv*jT2jw!CZAC0h}cLi}DdUm}7CvxHQX~mkeKSuTc-dB6>DCa<>NfyIB8! zPOb*e22Ou;9D+TB^Sq9h?W(uG-)Bj3Z@U#aH|e$6CM)xY)pg{hy1hVHteGltSuMCw zGwtrYR7yq_-~yq|$yazIOF%cR$5VjEE?FYSI$ljZ$jdMExyOEC;%k-5{v8Ls?aMi zZ|f|FPUwFc*9hn&JXC@TmQ*dD8ulVMrA@xka7>E%ox43NfnUj{Xe`>??CJ)<-xY3;Sf;7xgZc-sH~k zzuyA>{w)ppMIhZ_0mRFx1as~^T2We;!#WISS@XsVa3`qjHabF=L%%`iM*Ej*MOE0z zMu%2uW=9lWJgbw@BcHL44&dTuJp;Af2wwbU(wOlvC$^(vkS|UZE+^~bC*slI(Gk{ZyCg*?^L4>+0RBD;n}#p zKPe_IhIt;wmVpwxz?Q~Jcf>_23U7Xvn|%(HZNBj576+YwJiGL9CY_D{Nq ztRkv?!W0-XuN{v%4i(1O_q$H1#h$Z#vCtIPSN!Nc(K{}!W%>#q*;U&mFUUJ9?;p<} z;m>r4@zqgSvstohU**C?zfD`wETwNe$RC{uvLhLQAC#kr|2<${ee@ydw$hO1B|+2R zh8%yl@hnCSmLCqru|DExAg3e1u^xKIy;AHld6@!0kFmwG9(u=NuPhmXOBC>4hr{lj zsy?!!e=mrdA;S`vUUVWu@mI0pcuNAWb`(T)96 zf@*5huFDw7as1F#tBOPW#JPn zA=l5*_jw!V`tNA${gX{N2#1ou>EER*ap~?P zjEtuP!;<@smhQ$d=Dw}TaFhDy$j~*vuI+ghJhNAzCxs^&PbwY)_re(0sq$m_mk+5Y zF;{HaDd5i7=tIdhE_fl6^COrf16wN78Hv#iRwxyp$n%Yur6 zSw81{xAOt7v()|EF?Nv#BV#&H$T=hQ^LD|ff2$HmfYyQgxfARxeN`4kwRkZA|7?Cw z0}o9Yc_qPFc07_m&=a&)zopq<(**OC1m8s#nzD%36TFxEnr44d6Oyka=wTm6N-!1$ z&!LXjnx6;m)nP3n_t0_MFwWv=KiwM{M426+EQ1p;mhIJp0~0Wg?a_k+6EL1N>cN2t z$Y8rDh++IuNXiZH<5^oTVbr?wvM1f*#v*)+lIAfr=)hK1mf}vkwPv!YKu$c!DjC2D zLFB8cbW8M^r_Ue=NCJ#DVm)>La;!6R*;wbr$HzK1KaBTZjdkWcGS-=jM}4Cg?4^ia z7q1E?#cWuL4+7`Y_ zT2}t1_Si_Dw5;$AZ4Mf;Oys9d&V|BCCn=bnTuCZsnNVbsyfyHL=6?Pu=AnYwr{g+G zyoz*pBz8S>QtZ|id&kd*Db^7+Zs7~9W6=mpDs+sHYYWSw?}t+VX05p;bgKW5wGM=J z(=3etR*T3o^^YP>AEe?6+;GZ%NX9D`~Wj|;ni+B=&a+y!^9{SCVqr;JVN{76I1 zL*36eFqtyjU$b}2Pf{jQdl36JOQl%$lD(s37(a2@cH9o_ow)4KaQDPz*+UPdDHE5u zpKm(kz%NUrlpPN(i;OT!qF`hq*w8EQZA_$h(_J+scS4_xUcs%>Ze=}2`b zb)mK9X8)Je&FR@g=pTWP<;zDT38Kk*1SqvlTIvHl)YytxF7()=i;v7B{M;qX8V!K)H1XJ1k<#pZtg za&f%C;Nz^;PKBf3&%;;K_U5+hG{t4!yFWXKgxLb3miL0fx#vYz!^9aAj1b> z@t$#DA3CHj>uS@7jlhLV@|Uni16?~@>A+^x#)4G96#(4@n2hY}?LBZJ%|S5?nyrdc zd&?KgOSg({BnAfpVph-zQU0&L8pydYM!SvsFw*x#c3I=4_bvzg=b#_~Y8Ubufod_v z5)J7N@D4YQAD~q{>x=?SyYGJkErL3h-lARXSxP&AQKU$jL6r^@2YKO^1L?|8|Fi=& zwKXf)W9bT4r27KCaz=P-ZVXtZH6YFa7a~_A^`|=~LR**pdmIXtlg5c$(Dw!J`_l6c z^e$ZS<7j{V!cqDq^!d~W(#4xVp+oGe+ju)8bz}SSPeQfxgh>a?6$1My)ta7k7btBw zXa>y)%m#H~)O}AvQPR?URo$;X?4uEOIZcXRWQ&RA*j^)^~w8)g2JNt`X?|1cBq2+B( z>xVxd_9`_(>|pPe(eE|>qZOSE8A?a7$^P^MHJujb`3P4GT0kNRAk*Tt5= zpx6bEs04VU%J=Wg*xJ>4{rT@*FI+!YOij5F&dh_ZXq+p2O;SZuW~1}_#w=H3@uOZ> zl*46oy9BF2%<;m^uPFJ4?ZZLVG{Go}C8eXZj)PKX>ro@za#HN9c%W>=`s7h5Eqgb; z9F&K5$mULYM3+2r(AYW;`;8;esN0cG45~M}m7BrSGAGAdz;T`8ux3e_8_kpA6tIJ{ zaDuYp#XpriuFF=(qGyp)_{T6swVC-LU@ZIpI!wgP>TcNvKTnHpE>1g8T2QnqFL|bG z4s*kwRFmXcgwwT6_{%V*NkTU!&tp&@u4r-NImv8bEO$(}bqN)cZGxxKl})#6F}LGXAC*C7A5koyb1W zrycys8_{H5o=8NXjs?7Xu=O@3s8Y<<{X0*!A8INnbj{gtBlhpu#n-vd_85t`* z-ejevD4RiU@HUlYS=mEM}*3`~}JM-n}>;UI2D5LYVh*h5GDE#Q&J{PS>MH#Ha0!`;M`;^}RTEIBc5)H?rekM* zSA{6r;>2z2eBe6t@AB(rtSOdDcl;J>9^EC`sHWvsIK3I;hZ)Y`oe#1;=rfn>G{f z28#g(>>m4hzvKKYK8sl(70Ap~GNFRT9--VBvgbR^WG|M1f(q^lNaNPWoriz=AEs~i z;cnfxqZedFrQDNyS*rowi90WO8pWja9Ao-w>}YZ4F>$aIntEa8u{rHQa>J3pD|dp4 zQ~=SPVR{amMw7!^@60-8Y0tYblPQG;MBA9!+)eze1Q|^SuV6~#; zi(|#8M&sZR=ye>Mi5e1OF6b51ogb(`rV3`UfhsbfPDq85&^d^!f-hXLN4mP~8UIoC z)!**E=9^XbNlUUDooF_IL7?kQN+y>rj)#s@H%*9=&#WI|k<33>=e}XOn3K|hmD2TX zONA}Y`jOx}2vYmJ5llfuvu`MaWN|6^xbd5vq!5G#`O!4@(C!B4c5(JIT12ZAo@A`{)0)({3Ind|wTd$`r%O-^l6G&z9Sw;6R-cB| zAn={}lGAxn+OrX{rztj7u>Vslm`kH6g(&to#afN_Lt4oqsifqh)J(BDdow>8mR(C$ zNSF?3FU20Bv{ivh+^AVuBUM&jl=e}yF6*e>%E9H|`Z@`ElhS^QZl%;)bz82$b}10J zD1AWD`zU(nZVlxBj$P7@9T%ko6dj~!zP=KqKPO7?4i0ZQh~7ofj^`?`^w7j?;^*?d z2!Syu58{<=CqaAx}ggR@%$vDD0hD{C)zp6SR&1iN*W5j>Uu!!7NPC&=O*B<$EU8jdm5U1?> z;o}-h)<8>E*K4-iD#q2+vX==}9HC3#Y+@Uf!n$avvTlV4Ux$Q~_Q;wQ2ZgU3$Bjk# zz)Sy8E(p=DD6i!%z1)reQSM>A+`FzS_j8K5y4;9|C z)z`q)<+}f`a^Kd=eMm2N!GDyyLvQaxSCzZ{KifMyQZA_u?w4(bg9f-KX7!W`yVolA zKYIGr;O{}>!Ld7))eRI7S#=zD&tSVE8p}MN59ZyDYq$lNFQ{a%ql^wQ-xk+Kg6oTH zja~`-PUSmV(%NzonV%x6p%nV_fi~$g4oyzO5n=n%g5x_N&kk$saXlY3Zh7Pl*UheG zzohr4j-2@Oq5nARa2%I7*v4zt5axOzWwK1v$8O|*jGao~vL;?NcJnCa>N&ysiD3~s z;h@3)iFTQ%MehGXJA?fJFaOdGck1i^xE2xnd2q>I5C^k3=&Q6iAhZN-?7Eh(VvDpD zAPjOmsPcnTl1-IkN@lQW^k!oA;(K^0*(PQ-LjTJ%WSA*2=r$0c400K?vYT_enZpgv zwFv49ClHR~W}@tqfT^4aObzPEDvJ4tVLKe%=~cwhWXbgEu$n6TTEFwXU1FmJg#Kv}5;fR_VMRom;&&=*@cFAnA*@WdO(47f}jc#amKna@EWMG#dV3QS=SW(%P z2Gn3NqGAggH*VCL_7j4p+C~jgsaC8QA6so30vm%a6{1zB!D2v!8Wba-NRs)!&&+Nf zd}#Z}@Adlea?PEGd+)ht&b{~CbKmD&m+bixFo`kjmqaDt!B}Z;PS#x$G&5fxtoDR~ zX7i{%bAiD9laY!vrS7OFKCzFaJyEU#KN)5757-a2azD_@b+RAORn9`P(k05BsFl0$ ze=XOK=|$N*Q*X1UQ!Dp;eKyHiHnLo!RxU7L{~Ns_m@1Xc^Vt_QdRw(}FJa*!19~e* zmiws&rmXy5%auHjqTH+W!Nk*~m3y^5lH|BYmb*_Y*ZsZa#%92(WMHKBO!W8|y*$(% zHU1}5IXTO%xO2T9ssTH8=wF8>tP15d6IYzv=mv|w$Go;lSoUoW%w0P8@qHNxdDru@CDDiIY!vYoO zVW+Sc(U)}JBx1YFK{iSTTym~cDc~Cj4oeif2dt9b5+viE=;QDX*Vh< za$j8CWSB~fE%ov7Wq3|0I?R4eFJl0^M(<|Aio~3fr}s2`$;6y8S07JkMloZ)&u8|F z*g+xe>OLn_3!43pP-&W)!Rj+MN>1-gi~iZ(g+qW?thVB#N(Rari{EmMrZxoP>k3-i zgV4Fdo^z)h3zTop zg!k?Ivde+=liag(Z9hj0X=SW(TpQGtNnx(GzF&7|jt7Q+C$QXRl<1x%|9z3~}4{?TrWZ!$u~I zc_jbC{62VyeMILsPA&Kyr812Pe&51ANH<3Cdz{Yi5&5A5{CX(=eWUWf4e!-j_U>;K z!Q62Mbs)9`#EkSb@+gzqFW@ivtTB`dZIN%V15weMa#S#<^h~L2vT^PwVr`Q9$6$2K zKI;Z9?^7GrS=D?%qV@Ki$VNU8PDWpZ_d_Kg=mLhP(2AKgAZsb_CO*&rG!Lf!41NKg z1I|-ujXuN&WIfe{=Kwh%&!c>x&jjR{m0!UJ{DAWmT4Bx(wDK;br1rUy8a2>kOk8Zz zh73IMB43pO1Y|ZxSMt5>Aj%NAj_;KdZ${K^%<^QI5qN$b50^5%Jnt{nx-eFWzqVuT zMU&p_0_q^S)}x+8CjpnBNK7;$t@)#IGh z+!P@XWYMqu}l^FiH5EiNU!|G73f7B8$5HTUzN>A&cEjDN@&Hd}DWw zsv%V`UmsN6&Q5q6$(c8_XRe;bB+aTU66#RCUJuH5;uP zudc|)S}xx}n*Ln&*YVu?s0`Vm*_B3QwA48V4x`WKS{3J9_AdQBjLy1uNL(R;a2&!Z ze}g2PuxkZ4EfqbY20{axJol=B_I}!_MKtpOqS|s={E&o<0tCw)^GMQMAa=Vjl$?w% zvLELhve_lzrqpGW+K)ySLVO{!DSWxzH<5`Hpv&@*E#djdB0kWL5f4Nx#*jj(l<0H7 zz8Lb+zPg*V>pl`h|&eH)0JPDWXpI%{4Tihp~@V>B1L$F?D)c zLeJF*!=hpyA8So?vq&Cahrxj_v15(yvI5^!Dl}UPVaSYj4hq{Sh6`C<;Ww0+`d#vI zgQL$>0SK9s$yU}>gt%HKBV3#vo+;EPHEic;%#6F^$AV{rMA zU8-C(Jf;8(Be{Y2f(Hu^a-#!-u!!cNf73<(ptH+~1Le=8)b?Uo&OZWF0R|>4@n1$t z__0s~5H9XNOZU$r zL(MJ)9j+&6&_+~pHau>0WSJZ%5&0sY|Dl~`oQMnj%6GII#m`jTCJ||UPq6PjPX6Uw zZp6trk)T6wR!4O6A=-WG;QE8__ON&WXDm3#Q(|>wS;9j6+*<)_aMvdwhIjeQ$UA$pjr+U|rp^pGbE zwW$5@J>&1aG4dw_RddF-H5%F9XCp(C;(}TyWVCj3ndi1#F_V9I5Stb>&X2Gz)429+ zdMZZJbLY3{S^wYZ**1cnm)M#S^h_P1=l<`c=W*Cs!!1tWbN#_;E_i2Gu%;(?S9>tr z7mR>qeO)Yox(AGeB)Y5bt!25X>=*RCj*0uz_T%uaH$9OWzELu~DHf*kPxHNDVMV^6 zc_PGUTwYF;)X9oi9XrfngC}#l@Qi;MA>H)jegC?zy+j z#4_uT{ib2^g4mP61qXir@cXZn)#1Qkno~#YnL{YQhMAEGH8(F$Yg2+^S8!^3FpCRH zoWy`>oRc}gJNB6256pTW=ijxn>-*ZptS*4^>Ch;N8YpdFlMe?0V$wK`N%p|62Ev;w zxwLegLQ)+Nq;bnT{b1RW7ctjVrP)iD+A8KG3AM|YJ40pZ4+;%AmsFgSzF->Ey1?X==cb8YVkeNyQgwF2W5s%7T{2b3Pza&s?Ga%V+fQoCEA9_6N& zun}lqJy32n=M`^?Dok}AuAyDrV+H#>o#N4AyY761jlW$V?*H7f_kh7H@8+^?HUV2e zmV$kscYbKzt8L!7I7wRIXfen4Wag8cmhTSbo^O7pDtBhx9tGBzghPs4#$5i~wVQ9- zDCg#Kxj$5L-QnCB4Y_hluBSCOPs*L1|!jqy^wQ@w^(tKI3n(mEvrd;D#P@FS)%vct=;T zdWg4q%kpP>o55Rf6f9B14c-7Lv~-mbc^2xwfs$kS=g4S>RKAisJ90h%+TpES{$zN{ z$(tlG>^*CEw}nH3?@BWPHYkQ8d((QFjQ}un;_Y2xbx)-Mz9sGA9X)y%!yDwkF^_Mo zf+i)4VFdwAm+-L$x)|@>syZ6ZQgOS}$f*9G+fa%&@b`~w1Aj@P4H~)U61lJWhslld z#&^50Gacq%PxB>deq_Sit7z~xl`)XQWvqfX@hA!f3^%SU>H(9xAHw+%RMf-S(i+0Y2jVA4ZbIK4{24G`OMu_7ZK-lf?;wL%MvJcV_ncS{)}Ic!yh7P`5zC#C;8o!?C{cx2F^E)scJtN_|0j(zHr-Dj(tKy+n0{p z1SqnRuMCYnC&5pu(TfoO!426`(vt<*f8Y?t+9hD56n6NdmCD%L{bTRoe=w*8pp4UA zQA8SKMJd-Yg_d)XHbbLyB3>5X5ie_1L8#+opyCU?teT;+yb}jaoiy5Obn)5C^Rw5S zk5c%z4UO%e=q%v>KB^GMXL=!z4Hd#W20LC-1;zIlm9+9^L!2X62r`D_(T?sj>`t67-^E)c7C900G~5! zK>wVYvs6IoFDa6%t=6sC8ujMCO8%qTikQ}@U0DP`Hye~|qn zcg3YswQY{wDq5>|V@*yskeuqLc^)*p+rSEv2}XCf)B6#=o{H#r^d+&$`?*Tl5gOh1 znU>-^RUn|+pnrQ*_)+{+TaA*9$yLQ#NIAvE5P6tZz(13x>(RP>K38tPJiWv&;4nlB zXR(inEQFHuRkaHSnNDun+ZXY(;zQI$B}k)vvz9tJlY_$1Ykg@)~e! z5$Va_P}PVJ!^Y&Mt`C2!wskw(u@c;E^gc95D<9fTc}(L;fyR@eCCD%jyQFcu4Na2^ zg$3mO?I0?fxP8{ZZgi#*Y|JG91H&*%GY&;Pf%O(vUHT_DU|?fJuoTObcasskldfFu z4{yO{LpIFYHAH|bw@!(EeOy~Kz?BNHYGv~@*xA|j+S5XSThEMmYEU*~)5*xL)t)ZG z(=SInHNrg@ws>~6_Vmg+#d~VRQ(oD8F0AwHPwDAVk8AZl5&6H+-^kI-FNOdK}xVS<~p1s>^f{&Kf4YQg}Tbu`=jfU&Pmsb7t~R>e3&$Fa%6Ou zT6;!a=dpZD!A2?QWm?XS#Gx}~yTs0(0i)x!Bq3!stM#Jh{lNnQ2nQ?JS|Z%hV|eYy zB{%wwn`L8jmGKG5_;|?p*c!>H7+Xqb(6$WRrr|&Wz-nE)D_BS!YMs_%|8Z-l6+oU& zYwW7>8+U!wfv8|9omLp=4-G1tf5o1lZWrkPYGlvL)Am%s=dPf!Cx~+uxm}(!!QI>d z0v+)Cjsu)BrL*_M!J5|=3Rc(pe0-~Qv!tB5-A}upE(FCtp^BU2y0>yupDw_4KqG{k z^y!}N8gT!$epu6hU;8R(7LQD41@35>*4YnZAEWbI`zz0%8QNb-*Y{WA)_#~*wGeAV z*8ZisEm7NBk#`%mGTF{4FehR&{1|;!e1>#An3R_Ki0)B;92!rHhx2oieYXLT(uW_T zAneV&H&oC+hEm!VZY>T^vLnA99}ed4{i1-4815WJ>hc>lnhTGBJBhvLa7%T_&cFwRpiF+I>hbEkcktC(`qmx1e)Ddh`Boplrq&tu zGxYKAP#Na3I6w4Q69(c5r!`|ZK7`AjFTiU`POmI`=}gfa8$t~#Wmv(ZJAS2d?u`u?q&QCIPnGaCDH4YZsz^Sce4trD|e5n}_!K8}b$ zb`1}q3juo*unU@yd=9)fK$o{`h!a9m=6wPUwU)GN4O|x%onZ?LfU&|b z4UD0M;Sos7&v4C>vwn#a;4@M_^d8l4J#&4r&Us~u> zRyw50G_Gin=iVlNheC_t955{`fT7oN!~S{BoA?Xc#NTJf4Jo`vEOz2XyK z(`gsu6Dj8MZctslkvkB9!p47Y12n<=f6x>>|3v+J*`qY_R0K-wVNPNe0mr{#_3 z*#YG-hW!iOfgN!ITv0hiG_Yq*;RX`*kir`)F|*ZrEN{>T~?Iw7R_4K?~RK=8a{ zIgAh^U9cD@@QB4KnUpLd!GaHP{tWE%aBH|+fk(@R%OhgX1do;N@*FpGw)C~T z_6e{5U|LRE(^dKF&2@EO%xCA-L+4@-k;SNljY+P`?(lAFp>>~i)}#9Y^wG+r0bLu( z0c=i-d`7T-3a(DfNTYe~Sn)1#MET=$*us?iXky(>#WtZpD+)|{^e76{ru-p2kdV>< zHs}SCG4Xy7}A*B|~^V7k|I{_*w6 zf~zvy?#Y&>)7?IbnFE-$t6oS?>iJ?-T6y*5rjmNsn!LHr`SqiCL^JWEs@p0dfj=dI zvI+?CXB9f=96YUkG?VWV4}g2X_Pjm?;UMmF7h2J_My+iU>U*R&(XP05Yp!%PRpcQ~ zF&cMVh52&*p*+c!(*&X@Ag8cGpj~Hu$9c9i+pd|lo7qQc6##+HQTaZ0x#(X#N2Fmomt!2z$Hk z*_l#%vtW=b$JhNuQ`@Ie%h3a%Tii}GV0Gg$tKN%AOb@f-kwFY6j!*U;!e8tXkNsp3 zw0-f3-+Qf}&_p^Ehjb*3;y%30r(xQ3w!1yXst!`ny=M;p1Rx7lLZ(O_o!qp z9A0O{`G#;e*#E2deuB;-ZX5JkK7mWjC`G{~Ir^~ShgdH9UKJlxaUe9qFbTW(om{Y{ zJ$P4_W)X)8rD&>C#_=W@#>Ot|x)0%<;aF;QIIR!Xm27rgYjMo9_(fZbnB#cD?D)A^ z67LL&`GKA!&oBD7o|eSf%Hy{qaKpK@Sb&DZlN$A49r7V}$!3(g?n4tk z4PuFe;jY;-hG}KkP!b!4u?(>Kb!pXHT38HAZVU6O2IN_Oa@(4dEkWkqv^H`U4|}fe zS02BYT}|UFO2ec$Wc^HptyU=%|h2j#FvJ)q*3eFRenI{FTm|#)V!AGo)GTm<347+Aw6a_a4(Pw zvk&)2EQ0|+qWe%8)>ZB1{AJ8*FXu~U`_`MvIq~lU{;`$C^F$ z26f%~e78B%pGLk?X1l9N@Cio7w+Zxhit!2Fg|XaxJ*{W<9J_N@aQ}^#GP8nRSqvJm z44F9raROWtx>=ji5n>QBV!_-?VzcUdHRE)BWR2}O7vM~oi_*0X)!!PNJx=U`{TA>X z#|PsbE#v*UW4Atl)#%#bN9ui^DhGFu>0U$CWn9Q)3e7R;*t%TdK98_gN7kV~(Jb_t zI@;xtY~d#(*V@qK17sqMuC?JDBA6S<8ni~uDaP1eZV1RG7s3o7=s=)>r<8Y*8t9`a zFDa2yHQ?7${9?_1Oi!1q07OuRa+o(8avgO~Q6`{D_@4~`9)dM=NpU&L2MmCR=no<{ z4gjZ-!mq~p0Fg>tM;nB3qcpW3!s^l zgDx1i%dNu9a$d+Pow+F@8?fiC;Q@Bo_}K=;q@i*^jCaXEzeKtCWomDO3^E^!KZ&du z=nj_@Qy(p7qYDhN)j@ptj*daXd>(<(|0^XV4W@(n%}eOLY~hVqw> z%CBR^G?ea$u<}G zZR~}V)W+Li(JacoPulW`%y9{wjfo2fZ?Mzj^<=SbJ*DB>)9tK_E=LeMGN0i~);W}K z%E)}_?8NWLH%x2lm#kfXU!Hscn@UM}cMdF;xsx<%pB+W*$U6J>vj#mUP&%wu$%^>e ze#aVib3ES=MrRn09zB-8qxZ(~=uzNYduSMl^u_V$kyCLzdi1OB1iLZ}lY(zGQybqg z_v7d;MvJM4rCet;!v>>HOFpe)>%y4pe_+G*^BCF0sKIsOfFTez$?naXrm{>5x*au1*g0oo zeJBcqcm*3B{o8}Zj2msFlQ+e@r~}k=q-xaQ_>oqkKo;|eAOOezm>^Ef({a<3Bi&{e z%r@C+tGfo4g&n%!w~N!e$Z2v9C+3pzTHCZ|lW4Vx)7#(#iVY;d&z>S$+>9_!$QH(z z3rgk||2Z~)<<(19BrRf;Wm`-prf8$lacx>?*_K77T8=4dF*@EjRfVf0Wm#MHPJ8y$ zR3-C?qUVf`1u4Q*s|ltGTnp7jSw@GPu?Pca9=GfXW!ZLZ=8VA}%GOb(A?)vEa~0`V zm75$7@ar5^)6xRtFnwnlysf>B4WD`BuO;_lWy`PGi%A=z2TC`q>|D$~MlCGlq{_t( z>A2!vQt)2#T%~f!xkj$7dh207bH}X@OZi%H6W{<8ZdJ^+D)q3!ye*LXEK3 z6A25MT7a_k8!PDs=U&29R{0)O4zur7H3arGODiK>?cG>yFZOU>D_efgrV{;9v(qzpM%nUIRkO3IatWKP z-9!`m4$AH&{A0cE%ADu)8Li3BupB)l6vN_tG}XjIAn8yN=+<>Wb9s-$`XB901r!oM9xM;0sq7dMNTlV-9GetR7g}{c3@md0 zo%#)vg^sl)3z`Kc0;%2S-PGHtSOMhpz7HxK4MOBiF3^*VnfsI7avaaEjGUvkL(~8}@qB=6o#Fuw27h?HDWxJzZSSl$iu* zeFJnq<#RzKt}@@gu!#FZp! z{-1RLO!0Q4){bYQe;}eT`Uy4BS20jc6w9}z0`9Eu;QuX^Ylh7YCdJXPXT86S!XIw~k&YG(fBY;y zmxe!nHI?wkkK$8k_~XZ-+cYW(fBZZLDgir=-bz#w{L%{N*ZwQCZV@;xT_98ZG^aAxUH2h5ojD{c9}ex{7ZetKJ|zDH8OiT#XT)vrT5 z`K4P!J3SrI!yV|zk9)SeU0lQz!{G(G<}oF|1qesxqCyas{VUUbtTzkw~`NJ=tphzIAKYXb&D z@o%Y{s>S^2BfHMX_g0U7?}?G`L9^(~o4SdzFtM!l$P4M4b=cyUT4Lu5j!>wD%7n0w zc<+1Dz$nq%==(5!Yaur{vy4r)wl4yEEcw?&-hvqebDW$j;y@Le?EyaI-vHzgDIH44 ze+oQ4oM-Ykcs~bZp5TeUf;U{Chv111^QUx3TK+R$q+l~gF1zB{B6D)wJkDh{ zXRbcIEwiaU+cqxSnUP(ZR#B7$_zXr3+e!B8~4}(G{~nN1n|t zvPQB8X^!%K22*LjzpL3nL;t60FVMvM3m|sF4hWsM`z&M)hbjoXckkI%!YT(0bQR-$ z$5a@vP}U-=E~(z+K^#w7StcBwUx0{KWXBeFd5)FsFFtM*cJIb+A{;`$m}RpONu$i+ zIV=Z7+g--B?Q43R$dshEAe?V< z6pdM)?(n{%##-g+;~9f5pXQg0GOx|DM zJFLpnS*4lHo4F}k#lA~Ru$t(PQbFngLVW)g{wP#h#RiSXyjfUWjtMj z)NY3FNIMgV{>n~gg7(kE!z-)W{%rq4ivi5RxQ4Zu@Y*b(h+5r6@FIusuKjii#! z^W8{GVD++<7aWJq0IsJr+t?#ysSNaeC5fD{Ny2*Ng>2=4?5e_9_M7L~IpFQEiYsLs zdrqT41n@kpqZ^Io1r<+VR|!Zwp!O12OYc2rb*v?n%19R582$pJVgb2`<#7Ol2Gi7` zmA9PKv)(k6HFDQkUyPW9tlk+22=f`TYBg$*QUE;lobR5{b8Z^S$=`Xl<1ZAao`#6v z?F6(Zki^e9d@(@+##9UJZx)5O9S3#5;?ewK#|*^H-hf@Cb|3qM#sZ1pl5h9N?_R(* z(_JWpAPHpyRtRt*7u*1KgKHMhXZ95ovX+9#TJGIG9UKX`AQz8{&k;5gaq;x(4iY}{ zu{b{Rms(}*gpa%_j*pCJw;Bi^S#;Kq{cK>!6X;0c)Y8dQG94=?yEA9qI{CuP^1C12 zh~a;Sj)3&uc-BXVSK+ew^_sK3ZlV~sYV=$D&(7Aq7r*sb{MHR;JG$r=B7HLt;HR|I z!+zBs+{^`=seO_`Y92ey#w+gMIbIk?4CO1hM*BFk=xBovHu?+ztAjq5 zXf5EzqEXKy+!krMrP{5obeEuDe$(8`l;EQimCz|Ew6vYcg;gAv)i zm_4bzb56*;#3h7+4~C>mE|)OQN(=Ra5irh@apt$DirZB7Ng6Z3E~8QjT4MF(?${Dc zbdQ0nm`@e=VlMc|)(n^3?_L7Uu5{4zt5e8~$n5Mxl#>%5L1t5^axq3oMSRrnzBJ_i zG0xicmJMRqta6vR?2gwBviPXdZBTaBc^^UZUG_*WR76ayo0)6m z6}GV*rvae<_5h(*A*H*lFh+Fv53tJE7p^S?&eppKuO2Xxd?X&|91F(cQ*Rr#WwzR84$R3aS|s^ zv~OPn257wD(#f%hxj=}Pmf9-3aZjGh(z$fId)k^cwu))w%v0?QUuHLRekchqLP@~H z8fP#J#PE=W&aKqdkk&18OvUr3bX|MIy_a@;``+m}|KZ+NLvfL-NVd)6xLKhIvGiFz z8U8Iyscc)yakqxdvGiMehE7w_+7WAL+KHgs`bLMsF%qYp@j|$&ll)oLK>+jGFNZfw zBK>M(6;s#G3GA)Q$505FcwT@a&?3;Tts*d+Kj0x+sbrZ_LD6$tgCwc@1^_fqQ-y$GW3 zB)wC&=|V+$M^%if<1kuCV*UTevzj=)r?V2@bWYt=x~I3N?s-aUd_wQ<8>aKy`G)0a zsI33~eGd$M-&H-DUn%Sy4NdnC$wTJBS=)qM1Gay@B7=QE0jmIm(Rr1i&EZ#1w|)n0 zNrw_``hJWF6}nt%`$=ZmOaWRd5wsv82bcQRm&; z@$b5R$E@%dNg?fX|F3-~i}J?h7AFJ|4O6xKlH=z%l|$1n_vaN;X*a)Q0I9k z-g&;ij@NLWv-L#NcOCb1j$OEW*2~t@Z;!b!9Nwpf&8lPkz(UKc*|7xOHIx@)>u`C<*D&FX7(LOJboc{z%BcQXfG!B+)6P^B(}s zfTSp-BS1iZSQ4`k=l7)A+ark=%VH6Zl^4d6wE)*s@j6Ajz&;z^LCh=|LNq^;YMQtK z73kN;L_MTM?Bv!ZBnu-vo}GuAF{8ugo-cre#=e0Cu?6sM_*4gvX+Ao4K-YCNSZE;- zV;eaOC$g{#Gu$R9sT?Q}>WXBB0XP{j%XII<0A-+ob|n9bYxPc8aHMsSe zo@9+?9wvs?F&fQeZQzgu%@H`E`YlAWm4BQ}LNI+ihphnI?n#owZ0yCra4jbRF)w(3 zO9&L&_Y`v%3EsyjkcuQum&G6A3Yig?LCljy&mw_;f=oh^D9hpuTy4PygKImA`VFkz zk~kAb>mbJ#m=?gH&4nqTvYR8mXsbR~8qDE$t9AaSDQG@67vtRF{|NdZ?cd>5gg&kN zT!A$RG(+F>S+-G1!Fst}#HVZ9u?YyifZZyI=iuuh>Pv_!7K98`6lh6yl?gV%fMc3m z!RUQxM?^(Ev1-UA0mYvw3Z~-=MdIkgQ;Md4Hf(! zm}){h1n)0&Ch08W>vbmSEaNw-{e43mYf$^8Mc7m(=0xsSd;OAlE(GNPFi93y3Px!! z6uY%Nmc^Qc+@4q_=@O!~AHu9Tj93{kfPa*QR}~llnHJI+1Bo<$BkCW}c);HT2_Dcy zknUC?1V=*VzFn60x8E+yTd9|ojjsH&p|a@ica`M`rID~cfHkRYG)>W!Fe#?GM6eRF z+LD5Pk{$tZ96lay@|(a)tILC%NWn@dULcFJgbeTfs6N?sBkngsK9gN{g6&P(r`w34 zHbed_uFdFR7=Nw>c@S~*+h~{&R=NbEj9c+Oz8HNDgc8E>IIWOwl3-k6o39JfO%e<# z!BwA;WFT@q=z*NmXTn=QSNp3pfw&H1m?jU`Yo886!2b-Njszo8sdh_}n1<>fg6U7= zdGvC?Ca_Gd>(PUn(YNM74$1d7zXOhvrSBQWH~0qc2#gj^A>Q$KKr}Tr@sM-H>M901 zkZKVi+Uee_!OtPqMXJFMjdjG1@EBrU5!O zS9A`B703{EaL9unvIrT9OVnj(J7h?gs3@+gAUSb~TCDarkU)8Tfa(m%(-IXyruL#< zFKlg^Jo(_7tnsG=ywId5a`Px&=<+o4dw9{ugBRYb*v1eD8OaN89_C+Sh4%^-=6aHs zs}L7Y5*=Er>068gcW%VD&}xWG*Xjq~y*H?JGGupXk8Ma`F$U9w+GQgCFJ&7QuwrDL zd=5Bl)cB9)w-ful0Yv7L#0*r0p3@+SV{z|#wYyIe^JQ^1Sc;1{1=$G-_=@kNATf3! zHh`mw0~ygvVRvICaXiiz@UGGd$b`6GhXOEyYVdaQh8SuB%_G!?F!3#V3ES9*Pd2g* z(M+1mz&AjAd&9)H=p`e_1u8T_?xX~{;P7`dOs{K*R(`Hd>qOAXU!9;ediDQAD_`_& zT6ue%R=$vEC3astg4W2A1g%k9f>t11|0i0#vvpc0fY!)m30nCj|BY6OWW#$t+t~0; zc}!CKTQzx0XA(Ac(lM515NB9KQy!U&kPQ)mHzA6XrQ1D@Ul8As@ zw$YDXJBc_Agl!)$ix){yyP8?S=q##H$R>OtJ)yA+_J|FUbJ1TVaWaxokEX98D98ry zEc92>Yz=$~;z&wjfh-m(;uJp~>HQVLh9RO3o&I)&G32nATHiOU#p-&?u)M+C`z?7p zH5ivSXZ#!TStGuoclHoBP7cxlK^=7F_i#g(H-yVT`$&UqrH>KGgrQ z)o`>WS_u5=Fg7bYLUShwFuE3rF0*1~otJ3Tf8;Cz$fJOwn2d!H1_| zIdF?-=kp_WiE%ud7K+{9Jg9I+PA5b=7jEhOe`fO6GR#_79B@qBOU+wkF3HcC6pn|@ ziqXo0Guf<%f4wTLfwP3UF;!f0wH9+G%$b>o(yH%aaV9v9KVDPO7N|Y_rt~D+(01~n zF|{}?4*_bL;ZQ*?*8U)OEu5_O2Q9^DMEjm;HRn#v@$lDJcXK!?7RT}02-io`s5RU? zD9i}cp}gKTh;iAaaC;ss-qU=lMPV8g?0-dXu)e~!Du!))PHi*ajKf2_6n5Jy#jOg5 zLkWa^!Ok)}`TNVwMsKB677gWMNgAR&`xPb+N2brvj!aj$y!>KWF$8|~6~IvG(QB=% z*pR|>P^^|WH$uU4-uiK#%Ts3M`@YDOgvYbX|olk^md9eNuE>u!DDrF(qaa~31&AUM)dv8y`WH-8u{Q@ zAT%foR`)yeHhu7k`+D5-9yo^Oh+nX~-(C5@8&WL&KHTKHj|IBURte+W`|keDi&AX- z(}lu{$Ulz-!e8s)j6~fJ!al8?OS26q6KpF1WP?rEDhmfE8NY=ITM(z}URJRf=cjQN z-XgYIOn>sUSdyM94qMFkmMIp?e1zm2W4W=_lKiJTTP(s;8^adsy_*$F%KYbWVlHP% zwQTnqUgtzxV>=F6u+Sn@N29=brC;^8+h8J@B*iXU+Hi^j#c0+OY&F}k6^FPLC-AEV zj(U%Vr9Q|75fDmuh9eKH?2M2kT@YDdl`@+J#!+Q)AUO+EkaMyMu_IbBkrOHPd zfOU5=ce;D4T#@=)DZE|PDhh9Ro>th7F7ZW`oknRFi=%41^Q@+*%3o;38tDM_y9>e3 z6*?ZByqPpSKjMQvMWRRo&;DLd5uQIUZ*BZoh~e167a>2{WD|M&RTkkZ;(4{exPYd_ z^J+nczsDEg;S+3KJYN?3%i%h|85wsT>U;d#^ls2|z~e&eL=<;3(}+`FPSO1lRgR+7 zbAtWZP@Sts)Op?LT$XRQF*ua(>Jj;tjn2m-U%5tWn`Qg{4|nZ7z)8{~`1n&79?R$f z;vsfi?jj6noD<`>9$f(7w5eCJ_XTs(sTm04x=Uy{`dFg#$WRC0=_Cd$FFv zju8TO{8_KQbML+n&D-N=1ziFfM)`)!i04gb^Ym1v0lp!3=vfoJUz<<5XfS3ip4sBD z;4YwZ;OQ~vD4P|}pT$qGVt}3jT*G)P`+q$JYXLM;^0FFT}B(hr@HTk=op5?>AJa0z*i5Zv~ND4J?BLexthiQF0 zvw^oE(C8ke?Pw5=AUg*;i;GH%l|@V>#cKBK@wfS-gZ@R>_1dS8`V5BJZ-3WM$N@yF z_n4ka$gUR3dxRiOOytdhTWGFfw-!~mTh9Y2+)t@tzn=@fG#^&62tcgR!M;6cB8P0uZ4v47T61<&KlYTY~RlJ$Dw>%exK#+yA{&>{uR?ZGj` zUUoV$z-?H>m1nx{T#X>M)Fb#us7IVs*$wg1YS>>;su2BOxT|wBdy1~mijCSqjSRz# z*UH9xVU&U_)Q$Z?9ESln#FC6mLs8Mpq8V+oJ>E}*5>KI#4Sj;lDE|wU{VA1`KN&ch z9X2{_BdFJxX^0#Zazy;8Ki1d)v4{2dV*xJaAd9_R%OjTHAgS`npm%}fJu3{Y@X3YW zT&yV|eWmgK#vvZhuCz17@X|rx4XJ%ac7blG9G*!sdU6Ao2V zn2^FMiovgNi?AiHfAu#$)k^&GM}KgYdEdiE-s0ezhXwh(DB5`!x~={GoHP$L0^YI^eauL62*m zI6dUTom*y3R+8ACzjNM!_X^T;Q{*J(yrnoipwZ86u%2gqJ@3Qs29DCa!@e}Lux!nT zoFRU6K=rL@Ohp>vi!5iHOKsD_k2CY~XK>Q`)AhN|ZO!uat6HS>&ObCO*Htx0>nAG&t(o6ppiFdg$4-#?g+HyKkWQ@fL?RTxtn z{lE5ArsHMC^aA7C#`vCLOg~~wPcgLxOvgox3I9FD)XrvVA7N^L$M_y(d=D_b2F7$g zWBN5?x{s;7n=#3Z&%@N_F}~ZG+MhGN=}c`d)8S@JZl-oEQ+qDck;9mB7@v!&oyK%z zGqshB=~|}tr;IPe)LzAO{Dd(rWqg-09Y1C|K=TwLwbsk{G8tbn(^1HDp!P`&d>uN* zF|{)ppM$9#%RuuqWiY;U#x$MroyYjjVW5xKicCie1LVHX${?6#M>1ndX5hJoxVjx? z%2jJ;YE4WB&%kxZXC&_?Xj0IKO(sSO&Gd)P9~x(pZ+6UcK><9gRz$w!q?M=Z4>{|b zm20mIODiYc6ArBe?5|?%0VR~>>qFulB_tsxf)e_XKXh@&aolNFLepwLQCpg;mtOc% z>9(myCT&wfbNwN&?+A)~e11Eil@;eS&2RPfAX||?RBSp3#KA79^SpsAG*l&4>kGxz}u&kklojXd$K)G*THksj}RU2TXS3|!u)gvR=Isx3(W_H!I*;oGhzzZm%B#QZLt zYn;pnicTn@Y}0F0$EMGe&^b6YI)pOb{dB&9bB&eI1^&=1-wUXtKk%F5N+`|uoa!!L zn$LB#ss-0B{S()*4KMlpp?RjK)#N7vKlwxnIeky!UV%SUXxc)RP5QSI`ho8;+{^Qa zJf_V^O!tR=*zt%~|Izu9uL-x@{!p&zx2hcdI$-!%35llPfRL{Oz9UK~({#Vq$h$w9 zFZ(v)-F$y&w(0-0#+DpbLX%8&XzYo=y@!<0MAN-mW8dgeLgP%eYAYI^jI_g41Kth> ziau0AHd8g~84T1MoFDdWKsAGbcmJh?rucrYa?-Mw>N(RoRTF`du(Zs1PqTlOze-v* z>DH>yvf3M|m0x$yZ!rA~We)}xbkFbeRcb}ozdygF_F9zuRp8J+l~8(Zg;sR-Kj&9< zT!RJ-25#N2geG?^2jPQ(SN6^CFu zo|6_i_88x+Ugvys#hP_Bx3N$V{nDcRsrr1FcR@}0*!zOB(=Hd?hAUZfhA@?DJ8AJm z$CF2yrX<$Wq!w#Hb$jDVBEYb;@4KfxXyJn9qMgpy7W-rU=Jb-RH*YGMS2Jb>f=;e{ z05RTHv;MY|dPR|J6bQi6UF>?TJUMRW=-g<&Q=4i>;_0<`f9ha zZmY!HkqqCGf2&vZq(r&Z)5Dqm4k8Ei}G2^SIQWv&hPth?=g-Nv1CeH;nm9Ymeq5 zft}R$HSm!bID}V*1~IB<|MaU zK!&H*3EDTJWPy@fNLP04N{oD=_J`>HkCfbt0TAeIpo=0Ux0nZ7pq(zH=oc`BQYs4$ z3*=gG9#oMpU<$?Zkvx#_d<4(nMEnhM(NEH-pHLA*t@mGaXb>(Y^M~RUPVwS2uRgkm zsFmbLjTBLe3#w2=g~vuz*gLX9@NlhLz1X(roFXTF2Q^F`bOHo#D`9$1E>jT5YvD}x zD-uyG1qDM6BZo3dnC`jaNfm12!n@ezNAXPHcuY)mpx2PFX${$xw*9EO9~SbQ%qIWd zBkHn~oRm>$wPdnIA0eA7Gtdff;XYB|ax!xeOvbJs3|0hMwEX;4j5wgO^QaCSc<9QK z4dcBF6L2}E9<)DLGkEc`T=n9|k#<>ZMf>nWj4Wg)XVhaJtuaL6@eiY_U~5kigs#`+ z^Ziqj7@?>%@42KyVu@?=_9b zGvpOADYx^vq@J~j+{GWL;sJG^=;Drgu-#&mxd{q4z9RjS*YBUlDHAcxm%XO~((U3y z+{7wwLWLvm_21-j$|N}5R!CD_#xOUb0U5@dUw_Df3~>B%@h#lMR=hfqfBknHULC>} zfzGZN+jXfBDT|7K9i|h}JJ3{{sawU+t1j31NZ2QYZ`+N)Z9;|90sG(v1C$Q@5aJcl)X zN(j%ZI1`SNCNbxyvhaA(leZY)Y0!o?G~*lFPG=PvPh}Myq-*@D@mpxt<5uEB)AYh_ zP>*>y#`xg^wZdi*98k}%N(x;ngi~zE_c-=V32gcSygQXtA^A^b?bh=+tJ{%j>U;L- zY6f6dPtvnX#MLUShZXjpK=3a@Xi0csljOsF**|3g?0oDyJ-C!&)1NLxNX|WUK^P6m zdY-iK$B6F6*o*R~;9$-6Ych6CQ6ORP*1IYRF+>NxVgo8DLj)RE%7TG*DI;e})7IQn zEz0Rx>fm(^yQZ|eGXhP6wSd&Qji6v6D9C3g#3^Xc&?tC*Bn8_v3NkqBc>?bT)OO*I z^QX)&(`rX4xXsv#1gzIKLmtq@%Ea^4{4$B-E7He!R zNxvkj?nw!|GQyP^>r&cRW+0|uw^Oi#N!*mAJ&Y44X>wO3L4TE*AIsWJoHKsu#JYpY zd6Oh0@)!_(GH_y0O2LLtRN%b1QL$R}UKADV5qESu2bp1c-E86c1svh=lL#M3B_@IEfQf2@Q>ypL{lhfKo?PcHjtJGo4nw3wH#XP4$ph&ZC#e?AyJZzumKaP)&_ zoM@eGlPa9aks~ZWlY(;bM_3WzuyMqD&uKBHMknupvX9$XQBmx;RTz)QPggJQ$KOi) zj^ei!$#`?e)Nzw64h5SR$r>gj=Dre!? zV)<>Bn{z394=uyRf2-cokHup+Gp?@1Q--f~n%zqJgZL3KHl#$ z`sdo@xoPrTyB=9pylIfVMJwffm0e2-fr}(X`3KbKahC64`SWPq1}_HFIZVU`DlRFz zcF@d+naLI7lQ+MmJ~>9PG+gqwnQvvLR7|qK>g?hKhEv`a-%#1*TEU&F*Y~mbx++O< zlV?0RgGx&}dzVJw4k9p%2=spkfu&mZ1%vFRI$iwWPCk$E%1lILBKz3rFI7`IQ;{`a zd`{(>xxZKhvoNv6YYThR!d`pJ0wcG8XD`;uxNwjy)DoLj_M&)UXLfqeV{E(GwdxYA`2t#+fhV6x63qFxwpP9r*P2+QSrm{gBFt*{Y@=wt@C-m^(COfWl}(39D;|cEHM7Gdav@2oNir zNGf2h0uCUUgHa>i^n=LDbZKpmM>O~>o;NF=*T^*0WoJ6F-RUAuD4n9+wGZWI|2eRW zF`ZSNC?gNQQv6N~=~wRzn3?W8H;396u4S8P2JpN!kVBI!G%Gfl3KQQPkR&D`v*PEf z=W_)2hPRbg2?u=8&<7IR2hcnU7T&~pK2n#x!ycpYxA?UI3`|2iVF)IN`kV37zvT-9 zW?OeD&hqf=L%|j79U2AC4&Rde(l}xW#SduD`Sj#kS-=zJZVX3>Dr{_<~1g|0mas8s)!t^{X!iMwo;Ap%lS6G zEq?j<72)?JWUUl`*Wg!;Up;;g;@6B{=gF+1@wYKd8`A5M_a6L&6_^E%-MRn9Ty}5i zz^-7v)l$}Ou*o~ps$*nolahSTq=tq|t$|J}MmF{uD$6vJ5u>VQI(Mm+ zy^3y#JJeksb{QqFf9+3VzDI0RWdqMHr8^~_a&gk!`JScs9}!WztCo;=?1*dQi>Bq6o6dBesl5C``}YV#hZev%5KNys*l zvrSmOqB!YQu0v){@8MwWlrn{tG6z%VBsuSbw!quTa%QrUImVx9@h>wg%PjJ;F`;Dw zw=9`ieo|oC^6KSu=-BmmS6UM&Fz2%I1l|+xo+EY!8~M9x~S7T3_`WW7Yg| zt4!q{zi<4VDR3|lD#l+Y-mS9Fkex!XJanUHb$`i?`3A8@y##T8)7anBgOVF3EiNru zJO9Rt#UF?pa3(q36xXZlqgu8t*WQ?aqj;NoVWDgg*x%|ogj17NET=q6@BdJ|No60P z+riHVJ&XGVCf|Ss%4NnjXML3)#vB%HuE;y#H`tVCcUCW9OUpe=ALlyCnJQCC)$6L` z_hZ8*YoKJT)XYTFRL|W0d_#+2;>HgKvnM)(Mg79KsyP$&R!vYWLPbWhSgx|`sKSl^ z7=(NXV4+##A`;19BuP%~R@LJ{Ny;WT*Z_l4ROC@EGfJ7sd2{QlrM6^AT5RMt8Miq9 z;@@OaHu0r%+X63)k#?jBD{!E}?jtDOBld@_XiW7gw#r~zzRFXbM9V3Ma&)DW?R`1% zZscEhx6ILh4_{?vs!D9@_|R{RYbxqPjmFTtapio8NAZr|_=mv;i;(WwbovnzMFs~ zZxw6j%OrFt`SI8QkVx$xSAqJ(7jVpj{+L84qRCv{%Ce+m7Dd4BWoq&6!}$d%h#dHw9!1PXj|+I>*~(2JH}45 zjh$fMU|2p`VD1XDQi3aYKv`J0!fHL!);1`#z8Y#{bScRzsmpdB zxkI|RSbJjb{51zxzI|_4ozuDEt#Puj#`^jd*1KovswttGc2qNW+g@4e0gZ?xqkWur z#8NWaH->3!?ZvCwN7EML&b4uQ5leH{)JBfW3bT@$-}QoGHHG5g5UoI7UO;LET%bzp zK4mIhV)6%~#kr&voV41@qL!@;{&wlOwsN(6-MBAxYQ>Ck`xm1TUieONSmevDMlmJ_ z6_!ImNSLKHnc%HX!R6TN6J78amqY0s)QL$d+jR}*y~Nc?8Nf>sM^$9ux{C$RV!Z}0}mbZ zLW}|7LcnAggy{uNSmYn4g$ebNMFM@`CuEioNZuL+x`n*a1H*AmY;d#}Ln(8M19_{M zeQp?6M@}{-De1pUTLgOi-ms2Fl6Qk^*eH{xnR`Sml=S^1EBfFtSxe)1 zJcEw0t1s{p3S>foTqsbWYYBxbsvv~Ot{)E5qtODJ2@Y&VupBI9OZa|s9jT$eHTT2A z$P;WlokFrzOcP7C4x>wO4}v#q9jD|u*loFm40Mzs)MGpsB0xz&9OoV69l_%ddxbt1Q0paQ6%EcM9nLD7 zQ!LDd9aNYV1XVtEqHgSjvS$s>X)ezq=9grY-4#X^V{Y8{q$~Li# zn+_kFE*y+xI3lVkP=46$18sxnS#X-Y8zA-46-?3Bj;pT^Kl^>{q#JV9g~$c z-Q^L~rwf$HaHyH;!0civi0vrwZH2(UAV60T8}>aWE&r!%1-|Af!wjfWrQ%-`b?N~6 z5aHU{G3Kb@w{96Lr~_G8Z0W%f%&8&ct03@*{hSH#WBqvt;FYvXf{(yjTA*6SDqurK zb)!G2AHaj-w;sWTU`KEw9EhRx&psi^4KJ7YYEPMuW*;=P&$@Eht5ew-6L;apPdtg<*oD$B|Ghf(Nzo7DHkD-30$eZTjQfxx@M8Vf~N?gK2D8XrCbG;Q4C zV`RrigfLJWn;3T6OSd(k^TRxyKj7(nk#v6lAM5oZm-~SCiJxt6efwC0TD7v#+N-{O zKphjds6idQaAPW()ld*MP!Qc)5Th%&9ev!7>qin*1@eU(BGAon2(DkLvL2aebM|*< z4HoC9Y|g@!FZmmt#l496SvB`o9U2C;F}_AN$P76l1{t5MXE41UFmz`3nJ<+PsTGI- zG@tyn$d0M!ruTykgrFFRJnv-+B9mf)@Y{{*7>#B+Og&tQL21)wI9!4{GF=uqJsC#V zYGv#=?m^emZE3!&LP>R~eb;_?O=7Ura4P?bXhi=mApOO|6{k9q&L+=*Vp9osqH6o+ z`pqosj~X_Rdd4&q+^*;pVX<5JgXllh^TxIQ{uR9e>}B41s~`WIm=H+oNd}>xvb~2U zHL{Chqj7)Hz~QO5z_gNZ^Km%l;>vy85AWsVoztv<*OuEvBP&FP5I+@2kgT6F7;-rk zy_s+Wp*C+kO4pTSU~0j$BxVI@3CUvwG`kDW7~jY1VZcmo$9kT8dwd{!^)-{6jTlRq zZLrx^RX`MsS&&{X11xM}nAMV=2;$2<`@4=!EGfDsO?3Wb z?)D}ih-7E`Ka;!tv`HNqHkq@B%!8@yt}KQ>J`+Q(*E7N_1p&PUzFh$@SZ3#hb$53U z`u~J+hJoj?f5O;<@2G-UTn|Sv1%aXNU!~E7u_dwGo&k1J^IK)L$WO-&JUu8G_uYn~ zZpp{Qk~yAQo#Cg7bT3I$ToO5qGYx_hL61<3P>5hh$U<--lp)k31UI=(HC=A^tv*hDw!VHPmpd*PQ(PgZh4>y2zwndS6MZ_G5EH!Q!_KtFp@riW~(NW5Lqe0<*2)euvsxt}ZMuct9v9 zG!@;P=k6&L&1ZNf`@7gmJFR_6p2*I+C1~zNT$+2Wn~Qx{mLZIrat_Gf$2zG zwnZJN(JZ07^o4~xm+=<0ZwkM38q<0=HM2*rmxU%Obq2W3W#^ZxA1F7_Hg%!Rz*y8~ zi^0pJwwMgEiVJSexdcv+9qPq!{$sZ<**0OJzcY8QFTY--A19sHI*IaBn~b={4F&f% z6g<#SP}op_Mm^Y2fXY79P+)C9n{FYC#kPHn;x+L=P3O+Orc3R_AWX09w_(9}1KJip z{%>Mj54~6-7z(p?N)J1xdqEHtqNk?StQpip&;nQf1%cS@_}zJTyb%0A7$wZfC#$9Y zv{4;+D4fl?k41;0|IzsL&N<{xSz5j$f`L~Mh&hjZ0GcY z>y~_#X8`inJ@k1M=C87{LCn7XT;!(RMwi>p4bFAEQ|=me0^p_ETGzFD`{1_Cn;ACI zzdpAyQcx>7!4L@!c?%_>)1rRBVxUdxLX&|ps?A1&mriZb8D#AIisNpZdNEhFq_}uV z*-BUF#)!3LS23~qSLNs? ze}R;3&s`Q!t5!N|4cqQwTJI!f>(meE47fVEkex3Wa5oI2HZumV29TRU*7BX(h_bVm z==Dpm{|epBW}B~K4)M>){o@2bNu)(0tZCgOm0kZEmm&*Y@S9JGJxjtx87VjCG|+)c zN%c7ejEvT&&r_dN<@Net-ul1Q=c_;0XV5=8VYEJ7JSEaUO7&SGMyMh|qLY9!n*nd=Stk=4Qu`8&_&a*7=A{Uv|Pb099Cg-bO!6-UMYqd z#*pGdZ6P|0^j#rF+(bJVVsc#zy>sj-+M3mXg|b(zw1%oX4o!lw<==;q4fu!*=F3U& z_1L_Ke)vbkuwMN45CAWwn@QD;;4{7zUtPc|{SuDF3QT@jmoVo=tfE*L7bcwM4~z62 z1P=MUx}H@+k8=zH)qFZ;qOdzWX*y!B3bK~D{bESwv2Vl*rbBb`8zJtl4sR&B^O$B3cB+!ie7dF zN?0EXmzub^z4pJs>@x-kYF=3F@ib^s0WpwV1EfYgA(1{B)7p0AK zY9rp58u2rjzVY#s=1!X=98zhMub>C-CH+Oeago^8#;KCJ#Y$q%634at>!!Wc8PJN# zLl?egdfF9ezz>#0s2*V%_|SXc^OllktLcF#IT_BBMVp=(Jbe@vuz{tFNAVnjhkED{}2w*M8V9~rq!=e#9CmCOhVBlT@q zqF%qksQ-5Et~>emOOjE6{##2DZq+1CWckCFD%Sm~U3VFJTH~A5Q62R2BzxNX3Ts3! zc;R_uqsaje*MN_B=z!zKh3hwjhGV=)_mrIg zwuVf|3(k`l3D$>HMGC9cpNGe)XGqmy%`7-o+9I^7uKko4>x~U^`nRhN(=5SZ^x2B? zUsKL%e-WcYqRz63UkUV9f~KOg+0oPQQ#3ys-1Pb-Xn{dCcL8H9e!n(t#tAL@4$>@O zu#*VTw|ic6&Lwa>F_w-duQ%B%{r}RXXn>nS1ZszSwjICq2ogOu`Ci1;K`ehsJgzEe zhHl*mo<=glh-O=HmI%9hJwXLLvgO)n^nn)L;9O4MBSku?ipJqq6&0sGK3{uMR5M0r z3Ee^nH(JfgQgtvu;D5pBC%`y_lv_+gSFZgRaww%^MsxURIGLh+W3LMgP%m<~ZPU*~ z#IC8m9Uk-(lt$;qGCr)on)!8sp{*dP88LN zxzy8M5FdSb$gu1(!+Bw@&+TS}nmp~tsLz}9MpA8U>(H7%qNklHCmOjA5dSVsk$S@Z z;@x53gRGvQj;ln}G(vVJV^*c)Q;h#;2vv{LN&2y^_|`@Li%cGruE=g>jzfm?m~1MwBVi=o$G+d06(CKY#-YA;Tr z&pbGy$&nN4>tMYZwcN=1=vYPGEQo52NfV=HL0-$40uIFIre6cHS+5Jxmtm!24T{_TTkSJDmxcR>f(IrEOfi5ZOTC;JgS9{0B=EU(tqx3L|hYm?~8ROv> z&x_&VOS(7ujPT4o7Rn67KS<(DsPb5%S=xmoTvDCjOmGu<=%OFKz_NL>j7kcoMM=JK zv-ln2-B@LOX*)>|I~3M+@wK1$?IO8fm41Q5HT7N6HV;M3VwYSM=nsz~M#r+&F-m;< zPsr|k=yC$(Gb=@PW&wZZl8zd$(@)TzzU0HO0uqb>4k5rVNx*+4zz4L~Zx3u{Gh3U) zZuDaxLe^2}vk(dqiV%tsN)en0^$2?qTnOC=)G^4w5i|&Tge-(SghGTegf_tRBTp56 zH3)k04MG_Le0%qr{Rhl!v)LQ+@}57ALS8QE#wvbp)>aO&)1$S$hgH~ee@GU+45mnX z!FQ;zctup;@%=g`tazF$^!KqAV;E7IP4rL94Ihi;?TA?E4JnIy2qU<(;wDhRAC2x1CUlxC3iarxL8l~NUDr@UMYd~ZV9Mrlvz z?_1OCUAw@eTT?+XNW|nb5^Jle21(jp=l{wGXavWuf!loVh(g(#t#j?X)4!eaZTDnD z_DMPMx5FJ%ywPp|P}5Jo-Lqz)-pk0~z* zHWiHNEf~ubgj9!Lsx5$9EY>{W&3k zPZjBpNp#VL(w<)R*b$Tm6O;%1FDNIdehVlkYEA21|2LGsG2_oD$NnmG$sC|Oc#aMz z-(`GQAG*YN9p%qcIH!x25Uhtd3dT4Jf+ehnZmee%?}^C^#Rj#qTpd6)x9>p;Yxry>IWknLXsuEHk?1(G{Dr8A$y7EP_ zTn!ics*~fZfW~#VmOIoT8((LVe-eRP@7Eca0|K|GhGM%|{q;o&t4nz|wg3cQtl!)1 zDeZBA{8hI{{kfFH=Cy}CRG78mzIJO)4?pClEhLg3bkl{>H``W`?ig@;)Srt;TuS?> z`m>#=KhL=791^W&v@+Oi?WKDOMd1pI-Z?fUTkfn{w{Z*`)?oChRfap1lgsLYoSQj^ zNj@bY4)OPy8bQS098U35oY;HkS#-C@j; zHSkKoNikp1u6yjld?i)C;^TJfJ$(kpMXas8<{)cGf-XS8f8icc7*3ViAxkCg_}mQ* z7mO;RJ?$7Jt0g~U7l%*jNhIFJ2id$87AR|1(#56Pm2WXPv9xye#d4njn49|C6&2`U zCPYlQrRIr?tco#C=nLGVZMb)QtsiTh=)>=D(?L>+jQq}Fq9_R#3dRTpAp*#qmwFOI zta7Co75ML3EfoaOg^4aB!~&ygEu8zXIT(wBF1EUIUmh=iQsiH9v*W85UPNa`m!~S} zA&Ci@4OE6O>#0;mL)jTS#Tb1Wl&r;BwRFq4?X%elj(m#tm-avQ%Gmp6}m?YsH<*DCULAiiEGeH}=D@V|eZ<)+^w zDb@a-v7n5b&8NG`BDMv2 z&6d7GuVl%7jPi$h^@$d`^~6au*Bpg0~|xGusIgm!!e?R`{WSrrZ6L}gW44>7OX7BUL9 zk(9GN(4nLpX{w#gLk<3{e`D^GpYz^s+DwXJ15SD73)#qgv53Upm@gjci3=pE`QhP_ zkv5;CCl9*~?@P#$jUZ=en9lH2n;-|9z78pO#j^I&cGfp+ook!jksn-Eykb?mb?$GK zer{}D7mAfWZvND;_QEw|&8KvN^aUfocCD3hQ2tpx38TNY`gclKt z@$STL8Gh~L8DTp@8@{PWfIZK_?4#y};PJkO%WLV~zn?0(gjs9gj*!r+V_DYZT+-hC zJ7zCOO%a&?pzR5+cxU%CJ7G`aZGzuKYw!eCWeW(mOboz@Opt;tU~*yM`eG}W8xipGpmOfp zO!8e6GckCEhDn}Ah1D|?gFYJLqvr-A?M&tElrcX@mmh4IsIue-GWjYj!9)Fw!a#X{ z%v8>%Y<}~txlu%ou_kDPkOn*TLoW^KaPik3M0NcZi;Ax-YFAwRqB(7A2sF!bH0u zTLn|`#8ul9bZE<%NodQ5i*8}{Y;a1Dv(Ro)tO}!0OYGeXjnAY8d2jhOHK;V`&N;UK?#025y4DyIHmJj5CPL+fin7;hBh#YCxDG*z(%W$Zt%-a_x|W3 zMo~=HPj|&SX4EptkJ6U?7nk17C?2M5pI>Chm#57K^RbH0eShBe1c%?eL#d3P2`X#G zFMA6Ny8mF(;1`*-2H%>Jz|RwPGLuo3O_z}-#3k@4VD#tFYyQ1KG!5K4DZ7zcB~YcI zTYsD3@D7`<)32(m7e5SV6z^l7Z`7|UO|Z~dJ?zHh(&RcEI1UtON=VE0Nx+h<&#C-O zw1x*-Xv&fnnUVk%QetlFUeUIHICtSW2{6h7xDX~A$Sy6Kbj!TZ&*iB3nkT&96j(MQ zeT>B~+PTJV^DZs6YAgf>sbPnY7oL5Z$`Z!TVp{So%ZK+dcEQqBx=jXY{{QA$i zLhn`4jz6FbA?k`@H?1Y8+MXcztr`-dNv#)DB^XoYmnInJ5;99(m6rgg^-1%h5@InK z#?bG1;2nNX4n<4wIoIJ=6Zj|p4Ze01{;3i8-0Sdb2>et32LJLX{NG047hZ>dn!x|< z-{7D3z=QIK7BQ96MON?R><(ttP;?Nqsm9Vh3H9~%+Ibiv0Fg$+N1Ef6F(RM+2ekM3 z!4fIWGWtb)^6Z7ZZeabJerJK5tu)F@P4ZP=+{F^kpY9{u_GH|qg~KZJujGaFhs7@f zov}3jFgEKu+>o_GJ!Vd!jwSW=P~r?ZhC?RZ3VS#=5BPgZVwIar9N`A`w)xOe%@*}j(+hj}0 zA_O-tw^)8*&cLNWGJ*e1CIn_Oe&ZwUcM9K3r7vGZk!NgE0@(+XI^2YWqaxRbC6M*@ z7@P@Y)8COgr6lNN^TMX-5-~=RN$&esk?Vzr-LDq&kGR((QtlHTKb}Si<|xjiGi4-(0v+$ft~d8ZY}L(e$r_34tThV8sr1vtPF0 zXWBxJyG4G&v|`^;FGf|(F~0NN}X*?n!XW%fVco zwjgKeDnd6Br zCGGqohMxW(?bJx^Ts&Bn0Q1k3c^+L;#H&~h+J~hcP{v5V{el0V1Mv|U8s>#gCJ&v1i$7@z3sH+tHL(h?JJgUz98t; zKI(?rGRkKVcE!mvC?mul(;4_x*yF=0>lZssFR8-1s2o@5WVWqs#nRV)W0kC5{cFzh z&8ju~%gS6HCig_jL+iF$jGKeP>R!l(Wnosn9h(_dzP&t$vfiC)s;0}U8Ar8Oe$^{g z<=Hq+MmXb$C}LnZ-aDd*7#MEijS|$FU-eb(WzV&b!sIR-KR==D zms@A{B)#nBOT=0y-TwLS*am()r50zpEu`|iaDfe}((PeV$Lsv_jsAS0GYF{U;za=Y5OPwp(0J6|2!y*bFaGN^tt=lob+-x%b4 zN8VNk%M8xBlC!VmFl86%;0i8zLW)i&8?PY;*Cs^i1ZIM~wuz@N(6S4tL{kwCKhrdM zgxcb*-?9H(?RhcKzyEprd70e2XHr5;8_Cat6(X%At*{^>G&K8sf8L$^Oi}kzgi$`h zG&YisCW-V*ze}eBHjpc8_!GEp8TN+Qe=VTjA<6AM{hc^M!FI5|ZErilXiMWHa`T1O zVi64O;+WRIh?rY3-ZTh$ge-(&1UrHYp&OweLDdBq1U*6)LLovCf_4+GFK9bja=F?! zJ0=Ro%DMb(jh!;=D%WI0fw+DC*GT^L0w&$!s zOQFN-;_>^+8Orfegoj3hI#5jY0a$ z@_I3-zmd~ll^f+*ZPGJ)TU#RsQ@4*op~x?w#tAFc{1Ryi_i=KE(&fz2}GxWnj} zYBa?%rYRVM)~EVR>zNaOFqP0OC6vZ@PYEi1%4ype!|LC<$Y3gt4)U$Zi|@7vWpU1O zN9<XK=8G#iCV2%tkTk#i^NToe z@f;ue-r|n0r$P(<)gP$uc7B^p7h>n8lqb9Q#5edyMsA5jd^3s9V0_}CCwIlr zKamxN+}(=xdyYFVUMG)=9ODCG%63d1mdGR%M1Cn@5scVVBVP!hi6WxFXyRji@p5lnu;e=Hf%<880$|oGTH7ay5 z!^p=U@5gOstXMz!>zO*XdM$-^ETD(`mY;W!=skf~m zlXUWkq4^9v5n&t3;DArojeTh09nW~L|1BBwJ#OJ`^JIDL?f>^n1>A0^;0AjJaNUbiR_I zVkm5t2q=sj0VGLlZe&8YATOiu8UO@_9Ebhaxj?e>+V7^nJ>sDc`N+;IX+c#y*?Gm2 zomV{BdBuBnUh$rtSC*$|9P*K!S5nS(_|*jd$$x`S9EBg*c_rmuhhIbBpZYiWxKa3# zombMr>+nw#_`m%de5?oF)8Ca_-E0PM;Gjl!Ui#8K@%5jQofjEb5fV0LBpk1N#cfs1 z?v+P;@_Ns+ZuH#Os;tF!w#>8LI-*hXPrIQlev#mY?6+{6H2s_hQDI#cc?5cNX~H4a zt0(I!*>45Vex6!@INCF=zNNa=v)LMVY(>@*$Um^tvdmqIM6%P;%n1L*212_yj*R2a zh!hq(t$26}16TZd2VN_EL7K^VV%AhUHOqB(0@-ezBik*xsk?i{+t2z+(lYm{xv%$C#XCCbavxK9Y8Ii}dAXdT=j6G*08A~R z_sfN^r_xSR`n6s%^|V|a_DntNH3!+pIEN14;H^(NaNQ)4+iBFDH4mn+}(tn56I~eqKNQ z%Q=$q+EfJ$&HF1Fy{Eg59k-P24YG^`wt~Da!LLphx~_0iolc#j0(GY){kJ+{T_P@ zO9=r}eRm$m_2R(j2@ghnc1EuE?g+?~*i&g*A67JwQ}&*-%s9D!lZ_9q_@LiEXMN+2 zIJIHm+((a(!N~y)_^uXs1cBKiade!jj??&z2`yAas2;X*>gX}iUdeKJ`UtkcFeqZ> zU4C(zDz8HaU`N8cubWD2nI;?x#eQlI;gsNBSNrlg*bl``W2ax8M$eKWgNL=%=i;XM zctxnftlWM!JatT}7kmQ~s}$mR0U16f;<{}d-q_}D?E^1W44w$K2e2o)?Sf=aWK}WA zw}E(JQZ%utBGzR!6~m;cLBTd?mtQo#^#q+l);gFJ1uOW!o+BnjF_Lt-rybEOLrjVy zn!;kUA3KM~ygS(?rtfK!Jj;|$(VYb3NpfU1k^Y`M^Ix5ZGIV#+@m{c+CglFKXZ5>b zW0Zl&GWt2P0Kz1J-t+?=Bpahx_(N!eoEd#U>^%DW4W@GfC9{NkMFbaHexOZ?drd90 zDf!-%>BjG9qwL<;$LH=^s7*b`Ch8`|z!>VQY4mQX4sV~&?&&X?bB+xuoxv(>kZyd@ zW|{l65jIJBi6CpwC(ZgBU6WqKwz#}5|Af-~?79qzY+I6E%{hAaxT4A=GH{53{UsGvxpv%5uo+!JNtG&hOM znyxC7?w8XZ7d5zlJH?4yB4ER-f_ojL6$+duIZB(#b4WJQStgZ6r_v{L zWW+7t;5Az_nTyuO(fmO%5<=yl#3&w88|ZFRv@GMF$d1uZdIlWDnqHrh10D;vN8!R@ zisu6L4s%eiS;d&gT)vQMh>1Asb=bRuAG_vr!U*KRZiQvKCqDxoB{w)kKlz#5hB3wX zZyM8v{{z9e`(hxN3VkeiO2B<E#EdNc6GpA(VJsti$ zVvE<%v9YHXU16-jCq$2*0YwA;=nhmrx1>l5gV-NVpQ~@}{(v zBIX7!RHqk-NUFkR2nu`y0DQ)mA{jk}guJyyB|AF!Cq?ZV+;c3{P(rqs@IJ-eq0(hD za5Psoo5sa}(LDczSZ1X;D~C-wl#-$;+bfz@GeS0Vna{f=fnKI1j*&qFMP4FtIso@ENw>*DO_Y4?DSVSuernWJ z453m0_-d2p%U(3f|0X4u-AH}}^sK6a@0b-Tz4H!9b_36@tXHgzbFEPE9AozP_(S&G z$_F0~u0wY2P<;vu-w{)2`Kl)T`}>88Ri}J*9;lHvg;W{xgkp!tf&L>ecwWMsA>Hr? za=)GzTp-X%E09-G)rFQ7H{})LOBHTFexrGzRz@dOMWkNelDznfa8vcTi=$>T@E!A~ z4CRlJ44=7B@z{+Fw|nwBSOZSb$sspSR+57&c)ap_e}I+0u}}MlxR^L!rCXLGo0g|9 zBt3j18*0zX?%AF2yRiYk#}WDvHX-am{>KqwA6MzKR4TpwR+WAa&W1T^IXk&Cx3amN z?lnIvA-H>maOg?KyspDsF<^d%{wHZp`)M&2uFQl(`7|yj$4cUrE)$yaXvt-FIz05u zjCTlzPQh6$7>*SfW9OTk%Y^iJ!TE&E`M559yea)|li{c?eWGCa(Ud+*a2A=IkCZ$A zqD#M3mktlKHiz@!*ze*Mw)6=?dV2rj1wP5HL4820SAUOXj7=9L<7QygKyv>w8 zNtYh3Gn^0%zsl|Vh8Y@Yg_&8+cw@~>i?j17W^v#|>)qNk1KK6eA-FwAlO}#Zz%sCM z=AqXXGDhd7G(&=H3T-s6kry&XehnM=sO(BI(lvM3VI_x2!D3z$CbncXS@<>9&wkdv zCJHtA#-_X&z9O>;yOMN^;OrzAoG8#KBzO5rM(C*LVhuWHr(Ot}I4xGz@-TBKSTI~7 zIG-6CLOTeY;M_z$i{a_J$ty`4kF*!ai}qQR@*}$eiR+~IwRrE4-k%}wqdj&zdFiP6 z;#fPnErUY0rN2YEE&bimZp-jOx9QUN!u_==eTUS4p9tyinKI+@9DM-^kdUVw`KUE+tPPBGQ7*v8;lu@CH+%l`unEz&uke!#`N8m^v`t}enR>_ zA$^yS{(+DVCsThF(my2Kmi`gxwiaD_t1kUxA$?E9ihYL}I*T+wSF_hr^A7rq%}_2k z->pSQwai4HRlFzlnS|AmK9k2Y#+of@7qFfM%99wD?F#%dgY;Ic)LYZVutV~@nhZK| zSZ4j?mv*fPEW^gNDQ}`sF}=xBGk$p!`aD57F%iDYr!{F~34p2Q$NcOJcA}7^L#avI zXvCp6W2Cw{H)Svrry+Ve&bFYWiUg+QHW3%JH09+RK_RZm_Jlx_`6-)uP14jR+*D)Z z*M#L*Kln+?xFf;alXXQbX;95b)?@yZb;VRq)-5xzsH2GdIXC4ik0zOt9DhNM#+va7 z$}|I76WJux%rtu1GEr!WAg`$O$_qfK`dZ|UCqR~Xf1JEW?pTUc(BnjbkfX;lcCH{- zzhtb*pO_dk9X>KG`~L~C@X|Zw#{J#KIk2>#t>xV~MA3cD&Yi38m`YXLM>^~mH}ZRw z(f-RV)I4dc$&cYPl#AKolCp|hn_9_QQ91HOXFx?R`Ji*;gYU=(9_W@ZR2I)IcU(wP zpJMoRn7Eqx$_~Dwmw$GEf94fjNa>l&Fl7z2!&P@>y6mu*@XdJE%QKZ>cB3C584ESz zbv6BAhhq4$GWU7LngbJMX1y-60TX5I$V8d>j*$7ODf6Gwh;w9qX3N~^@Jy7M&8(Lr z(^;G8a%9#RGaD_L?;0~-H)XzW%WN`czG2DSrOW(W$b3)8tQ9i13Yojfh|7GFjJV9V zFyb;l&}Dw8%iJzxZmUSx*Tr}ohv{nSj5QxyYF@#hlZKo$Q6@2j{8vhY?qSkiY0zPT zu8$D-8go;nF}KhicCN+kvhF+8lj{bFCIonf+pr50@$z;;q5&9g z%8F|)Z59DA)wE+wC^6iwx=>#6$e56js`Cstl$kV4d&ZlBDVgKGG2XQIxZ5V%P3EU< z=BJV_x=j4jHqY?rlCo}<1{^Z4_yd_&EFZ~y25HVn=7_%N$-4!|V6P82?c|Y+v%#V6A_auex6UXmdTSg8y&aM0ZSSyzTo1kd;Ih=@-Ar%ayR^FrfT`x#2)%tr=q+`G zBpOI@H__VfN|4PmOg_L!fExOD-pyrBGpJMt9C#@MJgm%xpyYs-kLh-Hm}S4b7es(H9$ZU;GVD-GooiTW{iLr)aWg%?{qOX=-KC}eOwZd0 zJ*!7Z&V7y4?8f~0_6R*U(AmFVW8ncj?@Pk3w4qG!D^G_Vs(6FY9oVDYSHh)4f*SFjO5P)POhD=lF6Apy^dY1Cl|HiF+|u{IGYS+%ZQARez2Xs-e*dGA zZ;UBkv6FmDj%J@SG@BIzaC&-~a9gpHxL%IFNFKZ49jfE4TM{k|Ku!aTmcw5o@-Ty< zUh0D|xh;d!eNEHehY`y%$BqjbxKTuY85}1rZf9v1fo`$)5zz&lPZ%zFTu)FGbqRYi z)w}N5YJ}+sdW1X#>?>oj$6&pDcfxx>H9d!4DA3MlAa_NMJg6I@se9n<@qlqDDmz^NNLIMM zOu|Y3(V#AdzbyJ{5AvsI`Tz85FT$5q%cng!D+g|&u?L%DynocwgY!|cgaDzIqGjKs z7;QiNL07DFp)VTG;hlp#2B$$={?Ri97o4Cnd89HvS~!OZ>Km;@G1|EsWmk>CSzxrA z$dmb|E8@{0u7jJxLbyTSCOLb&C}xlgTsBEB=p(ca#|I~nSJL$Pr0Jf#rRE`@W;4Sz zbNoq>WD-CCUt9yB?-xC-6bR+95qto;4Db8jbI;xnJQSX$sPFLHjc^7bv7XRLx6Vl! zoj79zo0ciGhluHhtH_dX6X}b@mpD!eCavl3u}e6KFQ;AKA(Hhv*r7A3<6_%i6med1 zTC|eRJB0WH$^w|@GjOPz@=5d|{6z0Kv|HE;zJhKb-$j3tH1*R%4*34<5*0EEe{g1$ zH04ukFpC?_K(bruWRj0Ch0^{2udx1xA4F9)*YbdCl=_3o@l<@b9XPd*;?-AsH0UrR zFbZpMFnX9)5TsQs?n}DkQw5Pt!RIJVqU87YwcjravHoodoY6_qr==k$OZ@~LsiaSk zx0_H+l_CEH5}pXoJIMW1T}+hFlz|I;B`Q2dz93J~^d2G4Jg)CK(MBGU;q0~LRLCJy zOKx8!jfiuiyr}=rq`CxoKLR>AlNqirML>U`Cm6H0em{3;e$xCt+;l=JKa);c(hn(B z9392r9$2p(xL&~8z(vJMM^!I>h4OHi6D07D9{2&qM)Q9_nQ~Llbzvt3B|XYnf%5Da z7oee2bWfPnqv~cd9*zdlX{3MJhd}DlN>-+3Qq>6o(QGV3&yhMVHcELwkhk?jtD}?! zvN$38oS5nb*|nifOzPe|-#pJOPzu+$n2~5)CSA4Xr z4u0(U(LqbIPvisZnMVv;IXZM42TeA9vLtIi8wBGWp{-pRma5JC-+`JLa77sslr5Kk^SN-Kr?VZ-Qg%wNQUE=>pT)bXQHjuRO!uJ*$0NicgdoHt=n-THJ_sxVTq75@r4u=B zH?sFF(QqhZ?k*;|gp46gqBBnBgs0=PqVc_NTpX3>rB5RF9Hx4)V>CLAMkB-NZh7(p zIDdFEL_EAba;#hed{oW>DqOSVnFK|@5R|-tf{x>+-2McXD1mhgL6vEg_S>7m{xi#G zCD=B=&ZdCL|B|IzCV{~h72Kt0UH=U%)&o{A1mO-R?MF9*NhN#QEH^xP8LfF#F69a7 zVk<`x&%!rw^C#d}#T&pH)N?GQg?r)u0$hC)Fb6#OQQFP_6?olEz$zh#{vX0uk+~i8 zl(d)|b z{P*)oJtsZu>F5%IIrV5z*tb)Z2YJF84IRWcL>s~;HHx1EPf=o)43_dW@jr>Jn7ko$ zq|Xv4qmu@GfEnVZugB84Pi#4Q651-Lr7O;yZ#gznPG^v(q&C$5xTg(aldxov!hXD7 zSjBGf)dnoWow&h7j#ax7^&J%DedjB_8?C-eOgec!>HC|jf9+L?Z-)w~V(urnVKD>z zSW??(;HrN)-_mx{2NR>jN56=5+>YQt*zvmb&A}RY=i7O-`qbLR%%fgxVACbBQbq9z zuS1>pV#k%q?3nxLWkE?ZsiL4f8jDpF^J2r5J8fzTy4}@+&PeeEmvtlRCP7VwWrhj* z{z0LD>SB9Nh)dsx-(X6(m5QA9j_y`UxP_Xbiv<1zfl7Lh3B_9YlbCeuJn3usfs=xh z67Hu2j7TRX|H~QA7NBqKB@9Wa`qVEH-rC5%#CK;G10C`XVF#`0|;3j9YIn?OX^T!(oq{l_H~9d?L_0QKpzX0uA(b;cvueJl7c z0BnRufMNZ;eWRS9af1Z5*ooua~<&=`T4FVROc=K(4v zK#0z61Jj$Jbft4Gi@aVmB{iHRc&yk3${5$ohe8b<+*By>yJXLawt?E3{ze%8DE7q; z?NzXFbR1cJu@z!lo@1a5eUG%d;{6-6RfZg~56BPK$2z4vgwJWR`8vq=!nk4zsh9Q< zFgSyT<)Sd3V&(oqmzQY)X23z+n=2!y#mV13skMkr{}Q9T&U#(nsD+VYK@Ackyq9p- z(E+$xqvGB(_@DIgdDKF_ZKM|1n~iRar2c6sCjIk<)IVEq^pDeh5@-1a6@e6oj zK)sS%rIwCRwwcekpmlb5q%} z_b(>Cuyc_p?mJTOoDgJxczwyH;eX6o^%n25JJmAz)*<~ay(>Ha{)oCSK0LKpb;l3$ zLlT*_Cu%wmT>bXsiNiho58g9AU#I+j@N7talKj-qZ(n-j{I#RZV@sb;kNLZC<`r@6 zP{}&M{Mw^z+^@rlr}u4r`&x`GgpRLGzdi!JD zCt}?pbLcl}f_&~Re|rAKI|uImw6WtzO!c>wzd33&(3$5k&E~WYbLwHHGq~5BGGLzD zCtT8{V-94@^Gs$##c6EzaGSP?H^fX@^LxIjZIY(#URA%K(hFQsP)v^DeNmOF&&pYQ zEGI4b%3#(UP1|HuccO|*9Hf+;~Kq1m9^7#j(NjK*{gGwFHcL(dQekbq2i?E<%xUD=D%MrTmOt^`NJ{R;wn{ExQdJ7Vj?_oPdfCND{!6}9U!}tBs#$qle(t4e^Qs$VKbG~3 zhO1JgB^N&gU+UcQ#Ht#z?RweEi%|NX%HFio{P2ykf7UEthO*B|WuN0tpD1lIKSavz zKDRdJTsO*I>M8qvPubhs&G(O#eL4pvqv=+Z-kk*FB`z(ws>i(WdfED2n&m~^@2Fy| zq}?%ScYC&2bYT?d+#8x>Kb(Fo>zGR4tLi?>o!*RM?MK)41y!erF2q@Es{PEj1>mZYxS|`vB8BNlvTV zv(~_jl$$mW<$lM_(QtcJSSv_!#?EW*&UUmI_}cqvU1H4bS-Uh@->K^Ns_H-G`uM%V z&Oh9ql7VOe*x03UcBtxiljKb$dvkW4bC0z7W0d_4`dR&bL+@2Qi{V2aK zZ63Ev!yQxAe;_3$c4qJFasR30y&8R^rf)6EJnmMdlh%%uxm&|EYBudeX-C|uBniWw z(i${bjT)5G;a2GhX7}!q%K1R!Y}9lH?M>Wy*iEJ0)HY8EhP@5&+<_9%k1nu{_cqGN=eBC<>olF(x}2JKN6M&scW(}e}BzMy0==?@BZ8B+dCyl2456PdPTc~?2>sw7*2Up*vNlQJJ*jG~h zoLiMf3W-Uqe?#-i>&~ql+MR!2T~770ZdEeri?kdJ-&d-fZ*pk(-aVVL>l)WS?N%A2 zVbb{gbNclf`xY*1vnD3$6=7|uo0155uaLD~^ZZJ?gR9@HNt^ph;&yF`?M7M8XjZQ- zdzRy>H2Djk&*`iwdE`cENPDWRg40)N_I~tyV_#5-^?GTT;Z{Fg_5znxrHP4rUMMlU ztJaQ|x4IOQR9QKfHn+Y?Q?khYeBx-!R$J>I*A%bdHkrAVn*3aIjvEvCveDM<{g8W5 zQ}__4w`#VxFK;wwj+C~1d46L|gdS-Rb6HkRr(wBZP9168@<;ay(n3&Z;p(lLzMabx z&2vUtxBM?LiTSzp_-+ZuSv93R7LbII)-7L}mUB~i%NsptG~eaUZ-g7%<&SCZ;j*S_ zVj}Jq;#g0^(&nVHDQbqFmo_gZ9Ky(0EU0@MqT)Y}%{Sc_-@&Ig^J%?&$^bu?SalFS z3AYBFm8CG3ONPDLW(6IrIn3xMEl8U~_8;lWRF>;<&DbrEQ-@8PsZLRMCrrM3`b_na zS@AKk{j)i!W`ySPbWJPR+ZSSWhsHJTdX2(hM&TsJ}m?Ig_-rUNq7i&Azm$$KP3KHI^GvV^iplQCY4%- zeHbw-yh`@wglRSS?8Hx8b~MrNq~P{m{N#=7&QKfQlB8?Mjf=f=M22z*GL#M2Yf=;u z*JIC2aR_>ZG6V|h4tyiOEaD63QHE?&4Zn-}QQ^w(B1EM8Z-bQzqRUXg8u)?;DJlMw z&2_)DHU167MSDd-0xAjiL%tZ%4>b*o<~}hG@`0m4%f`}Qkp^@z2iTTN;A^ARQ|^u;``Nl9N{>`^u-KXISAu5+c7MvX4Td`(k;r59Qz0e<B+5p*l$3dxITH*)n*Ll6$L;R! zg-)tBo2GvzNdz4kN{=aO^^=2a@GC)o+I}E^?bB%ejNtglX=Amk#TmiTTHD}^;3(~1 z#TgC*jyq7=Qp84TS4#g^Aog|$a@gQj1$H)-a*7p_@v4KUh&8st;fV>`MT)gR^gb%Y z(~kBn_VX1-|Ab44=33ebopMi%(2dVdvbQDl+a_v3 z?Uxb!B>f-u-UcqJD*qq9_s#=@+<_TXGzV+$6=AT!W-hjlF67LWL5u-mO2bxL?`%ux z)~*t)y6Fbk5S0~T4_a0OnVD;w(UXrgphH@?D{LET(jq;Gt-8pXsWIID``iH^s{QZx z`+EKVuh;+gdi{Gfa?iQvp2yEQ=kxqI2kMznP=xkkt(c*dw}ylDz$T`=6$40a4#cIT zGtB|&_|$X6U?MLzqMz5vobm}qn%gtIqSa^~X9zZ%)AaCnKtHX_oZetJcjcSuhe&FT z^{3_zef0Oqd~<&$4TdVBT8|)QGZ{9%^=~YyeEIhj2XITxt@W{C-% zA>R@ZP?nKpKdeiH7y(^JHYyYY74)x3jqGsq-c`Y1nGR~$Ly)P^jgflXQ1@;gAoUcJ z(irK7bt9pR9>bG7=|9!*&`iQRC$bAVOv*rvgN>npIAtyv!IH_H@$?9r=rSjP#cH#S zzyXs=PqjnkFAXnA$t&eX+gwBC)Ji$gNC7Bq;@Y9IIat@aKrPmXtg2H{Z5|hT@%>B& z+#3xmGu$}5j-2%#l)W9l#776Fnen?D&nxh&z^?|s)%b0|&)PUJZ9o2Az%L2UHvD>U z&QWg-OdEk;5`O*A9WVNw!Ff02{A$Sga}WokuHJxtv`a2Vn%*pl-IB9Un%2o=gK^Z! z>#5}C?}R1;AE=lxj(r;elNOxA{2c!bLS=|QPbm}1CjK3ywXeyrAS;jx8MBG^NJTu1^UeTAZAr`(ti*Ha>gGt=uvQ`PP6tQraM8*8Iw8^m8 zia8b-%36oamWfpIO*+INV5~{i@sw#|PGKfP*qmM!RUFcq(p#`E0TzOk#H#XC^nTJT zFO6?mK~Xc-9??EPRY7KaTcAke)lf5@R+|6`WhQu|FZ*uXmzm549{ype#wNoyF_43o zLKav=W#93q*jSvT7`bgCIzws(zxGXKNN2<*gY%XE|0^@hxW1csv{_1O@!>1=F{Uq2 zf&Q~FO1<=5%Utve#u>bn1n&H?Ut17(mzn`%-+XY-K6zYa_ODITwRn`a$D<9reYLK` zRK6_*i9OLsRyB82ytQguMcJ{@jm@8ITeYfn-Hf_-78jId>rpf58~Kh^*{0(@r!nU~ zX$oCK`sm}PVBULw7BI~=6{o78k_yWf43zZz=72-hn;bBun~J9}cw-7(`U_&^O~ z%BhaS+`~jxnk-6=NQX+Lsa4X=b<(5;>1VW$bWY$Vi<|@fLoZ9Ysa4#~b=;%|?q><5 z(@j~=KJ|V}G>s@uXuA=sGB`8njA=H4fUqMGnS{tEnQV9@;+d9@i8yu-7Z&OqLO2coK0q@VOUK!L0V@gfCurmiU2c&c`TPI2N#r? zGqyQYd5FY^iA2BY$)vks<~T1$x|-0CVQMYTXsiB`!hgY=wpkeKsy->5mjv4W9m>WC z*fufgI2EA!w(mPO!8~VG0c>m<2A~h@OkOo7ejrapE`^wMUWKit_BDTcD#3KWZBh^b znWo3Yk#;-(P3qz&W${IO)m1KKwJ5&9M+`>R}(B|Xp_q@Zj?4ZcZoEgx*O<`%x$@U2; z7a3C?|5v);W;2$}d8jO+-Hb&FGZks{oZp4b7JD)O^TRHC_kgJrQ+JlgN?S!sVRjVM zf?g&$=aGZ+dD<#lZ&@}=33{q{FK_BhdEp!zhs{(h=wU--|JwlFt$f=Y6Gk`};7sfd zEfhud1qLEMgRyikF)cSzCthN*5qSnZ{cxcA5nR4414#Hi@0$fPdDt<~`&V<@&VjQ{ z12}%DF3&bGi2{0ycbZ#ql)_t3lfnJo0FED=V<{P(NZQ{UX!$)f0^TE4L0`f@W3aZ+ z+XDyV&b~TO9YuA`+a`{u?QaZt$CK9G?xDK;jY?f{sOu~R|c{rifw>z z(-w%=8V0Jkbn}^jBleKR2)S!h-M|E^B|gXyv)&1BEnd)2$=^T<4xa6Rk z%0~S339Utg86uYgJELqwXGdnql}s;Z32LeAf5{VCmtB+V<5GiBl=dWE)co*8DK`NI zQCbAEB(?F}jc75IR*In=REduV%N)V?Lj`!wir1;eDl3g%UR^BvuRl?Y=h9Fnm5UU= zTxIsY|C_QrHxUI>?Mh!FUC7>!ZX&WX=GLD!wBFA_f7zZ#^71qq>-)gBa2D}7RLjwU z8*j`0_kewdQhoxK3uQvj4&a#NIl+GO01hMCMPLr+PMGOb7up6|X3E70jCQ45oXk`| zA!|!y>ql%fJKUP2?HORW>9`e}IkBB{b#u->Zd&9jrh;$dj>Yc~euwd^3j~$BGp$d$ zk(Yp{-_$Hk?3S$jKH2tfv-1=4ySyeji>da)FeQ*VV(QsS~}p%)3iNU2tx<^k+=Lcr$KmQA+kn<3kk#0+;0D#*19Cu$P`Ot_>4_ zSMCP~ki&E4ThH8zIWU`K%ty)_Ov`Q{M>k>Ko4JYYTv|70?c;7#R;LT=aSFd4{D@r1 z^X$O1b9lDA1DpxJb@)Yau4ajEmpDcm*DaYJhj8(rhSh5kaNKjf*Fu#hQ%gtY!(=WG z!QB0t$O!KrV6WFEP{r1G?`Wzt0VS-^_Bu(#xVVfGZ}936q!YOb2*8XLsmL*Fn8^J7 zZUDNFz@$E^`Kb6%Qt<2eb!=?1C${htnfp|3ZXJN3X|{?gY?leWaJ>>dom$d{$Q*Lj zK^eLepls6UihI^-!h6V?xfcOA32vAc+syIp90yn#gw5?3-#%rG1SXxgRROa2H~J$0 zX$~1|UzqJX<#s78*V?IO)qq%lD@_xDSC}~_LLU(0J+HK)xqE;Wsuy8wnDn5>3@f1# zP@w{1w80DWU1+eL+k-z+d9wz~IF%kpO_R4ekX110Ghb>8Inc+5nH1>1ZD9n*kn^>j3)W z2Zh#W!zsYW&F1dmAM-BnMfJU zmyz`-94bR#UvoQweSG&{V1K+QrTC;|O(6z7-p3{5guM#(Q~a|4`zZp)5%5n3PAYM? zo*}csnQ;Q7yv$VZknJ;M_$Yv&^vqt&AxsoU)q;f?ZDljR&4-S;Koh3gou`es zt-S%N`*VX=q8)bEYrSc)?!JMQ%$#P;A@eyuBjYh%W1)-eW_J+8Fpv(om4yOAML~K+ z>2!#ei|7IY$PUbfzd!}+Q95d)&zUcwcyUO zaP}C8g_pbNMl#-IuC%BhYF8Zt>~8=c<3HJZ_Tqj2Z$R%fn4!Nwwuti_Y@#lkLcvPv zpb8d@^o1|bLKU~-VV=o;kQP{K9uGRCdIcWoc?=;*mgAA}G!v3#DQz7G)wD)}NSeIX zai^Iy4eZ$H*GYzTT$lmbutj<4%VSVfD@qUgq(8EH`W2EZau0UA$W;HD?s$pO-c5Hr z#Z>#~jygsw(da>t526#=yPywm@V3)@{qwj+)MG$iJxC7_S5^YIvTGK!!Jm)Gg8ui| znaDz746o@u!b{6}?vM1MCgdI83B@`~tk`6*@Iw73Qzw1Q!=XVvd1Z<9at~T~d!u}j zfrVG-PCDZ(vNQF>WTu4vinM|furqKg_N+aMJ?l5~MBbeN*QT&Cu-@i#PxZNPsSDii zbDiW}|MV#aGYx^?HWIrm!9BXpeVyPQlM%(cGaKB~GO8M2Ipe;*&V7U6HrFYpGCtR7 zUtn3I+gay!HMq_+xc()&e_rY~@$N*Qd#vCVOWj<%d%Ea4CA!Y?u3p~N$GdS=!kYEp z#9+pCE~C`v9@p+pYImLIUEgZH*a>UaVPquUCc}_HYtKq%>dm*h#}vTJau6j15YVr`a;#3v6BllU5|KUZKW;%0)PM9z3mYTPTNh^VQ$DQ4%+*Z6Zt$ zuo|W_nwR%rnu_25QUp3E5$o0oNn%rpzkUxo&>c7oe<0s{Md&A=N3FyZe1goZfB!(l z$`ve*%vdn%_6)#eB;V}AH=jaPp8pFmbnPHTs|XRkZi0o_fY1+;9P)ZJ%tz?Il9Yh= z^&d|dXP+*MfoS?8l4p0pFtd5WMD{88aX>m^KT<;fjwG<8`R~DWB>#D`r1>ulS>EOE zB(|>kTfF((z4;qp2_@ujAy3ugY&I&Hq5m-{{MKOUQ5H^Z(4}zs%>q!sjcNcln#h zqUOH}E2#W;g#34f{MY#W&7siF(+vGI={qJF#&?*Ksgp3hV*Pu*`sY_Nx4IXV%#X!# zx*sJ=tC7QGX&)sY3@xpDH9XHhfS0#+XU4jp9%%b^fQ`EZLlR{*Zz6^yvb%au@dw|u z^$wtwzQDRm=ivDi#;+xzhxWkq740qhDi1k0xK{1)VYN>VcuqRFbJl1n)RCHwn8*G;vhfFL>a$33Nhpbx(A1=gYP zqCRhZvkz28RHSOnN>X*`EU9|-RaFB~id5}J{Adm8y;G_8gMlt$-}j(@If2WF86FOi zz`8rVs1ydUw`Qkl6xeky-BX1(+=JcqQ@-iR)aPlsCYm+B--CbYce*imiT_R+$FyV+ zLZ>fq_);I-v*P^uGkGO&50ZB`6K6$nRyA!S9h+0ddh725Jl=U*;xiL&1~FW^?%w0%N+Ke2U5Kh7X|F1<2)HoB3ENBa3&v#>d{pySDJLzvNwi z;$!FWuC09ReBSjsAA2Y7`ZFK<3*PkxNCDS2vfeDIC<5sQ`W<2t<8IiQ$MCVA`eHvR zjr}{EKg4#BjV{r>zcgb|?tAudr2{>LXrPyqQNa`fy-$nP{PA-f!tYv=aR+$fQ`TNj zE&wrQZNj6+*mf9-!`-WY>FFD-nm>F6O_immf7-N$;G*USlE7z!Yr9~#RCbyfG#(qn zGt$y#>G$nYd7pGY{V3_H|KY(C;fme6dj&ZZTo>AA4!|YBko9{zDUB0>j1-o)e;~;r z>-UdI!tMex^4tU~Hvfl8`WB?uDCxZ<9hssc`d*U2Vc@AIhVP5WVc@xU=rHg+LJkAZ za1!c~2SdS)~}hmy^T5^Lt|W{*d7D z3!Y`XXQ{@&6K2tMr0=jE73-^g^^1t@J250v%y2cg?g5GPK8}DQ`VmshESh0zMQ}$C z%tP;-a5giJBxVn^oeRU5Y}Pf#WSZF~yA|rnsT$ zdz!u>1-$jo-C39kvwPUHifGmU9?8Xp{2QfvL$>e!tO3OqHg6Eh55BI;Nx^7+t z=4HxSc(JFJY?mETcx)-55T7hZMM@M?@E_v6Mq@>Ui zRm#v+pk)|FWKuDWj=kpj~P9GFrUinW!sodAfi%JB!N1S;M`v zMmP(~Awm&nB`9r=5@(H$wC$ZWlAkq3oONAVT<@HqLn3THgop?ABZ^~sMM8O;m~<*F zF7$=5LNH=9B_OcOkWlg2)V#Zpw%;xD*>ra{4C{N-jI4TYB|VBv6r32jyt628Hj~H9 zr&D3y1tQRW&qxcbwYo*hK~Lplc>C=#o^hq#Lsrjzo9wEBlB?H9In)xQ`mDQ#*3uOI zBYSE1kGvKAC;F+bfx`XOEd8-5Q|^-tx#tlsNpJ}^8cBruU)qkS7 zUy~J&OPIb04EVe_tFKR5LVw*7B*y*oy!Kzp;L=-x;?evY0X|>F52yO_8I#E8D{Gst zW%<5*HJ=|X-bT5TcbXk#eEu*YKc?*nEGEe6;v(ep5j051XZig2OucnPUw&*~eq3L^ zp)cP^eDVw<%(cw8h~@uVgzG@=xNCj#T=vLgy$x4e#39es-gt&+m<%oa^}r7gan_@_ z;^6}hSVcE@romYcs2OmNVx#{*|Q5tlqy`{U_@dmci>e4!9A z5tlrDo+RG&RiEqYP{K}LDyNT-zI(ayAu0xLc`iHU@qe}(*G++P$sHo)2%Zb4JfY68 z7+B|YRb;Ah$B9yz|Ld^Gm0jzU=V3VIDFeFOvD?R$5vM$>2-$+WZUU$IbT{xRkMA;~ z65-o~!r>n}`YZZ!Q0N!Wh_nq(K8HCX9-C0&Aa zqmq7sq=(RwY?2^L_9{V39#hbg$1kHLTY#1**vNBU&t|V@wcy#nd!B%Ao(MvMg%dmh z!P5Zqc7+NhZj_#fTOY5dRzXV|Jg=8}>dDf9{`5f6qQSGK(evj9Po3y_&F6VR^gQYH zyj1FWL-ai5^Sms0-sC+m@}9N4=V{)vQ9(UiR1U78#CZ5IMO? z8TVy;=bcF1K*Fx_*Kl&MV$C*E>kz(k8Ab8`dH2;QivM+zBpt8&2PR9wQL67JI10&o zoa7NC<#$6!O8OYys-|N}KUme|c&56967o$#exi^+R>;3zWbb63;rAUf7nI%cGfhx1 zLfpgedkKuq^FFPx?=`|Z=l6Y}q;H1WfUKv%ubUr4c4u`#)&om;cK) zIDuX8zimVMU$((p(?M+AKX?~LZo+x<`TTMA28bP9e0~zEZqFa@X{P6du&{+MV0WZy zy!HF?m^%y8Vy(aG%g6OGK6HMB{n;?9wy4?>V31p)+=XkxNPyM6@qO~;lVR@3u>JjT zj>f_W<0!AOTiO$LkD?jwL0oUm+#lPymEGKmKJI}CPFVqc3-C}+HXZ+C_(+>2Hu~&= z;}_o~xFwT4pIWmrY>5W5uKG@@a(URI!(+=G6#Sl8q6iCbHf1jj=jju>moIrls*}|1 z5=AGI0VIAk@0SM|uSoZaRJ+L7pAVB;(4%5;+Np6B;vV!U_n=41{X@nT$TJl0iJn^+ zdS?f@3O&OFPfX+<K)gt9q%#O)5*%^>2cZhdB$cm()jz zEU|fdOvE7WGCquF&0|qNp6b`1JCZW$Kqb3XpU5l3+_IuO%sNg`rUEA1D;--t`jg}duc%= zGyX0js1kQ@EaQf-bvWr%52=dyi6G7zq$4EpO7>ANL%a1+LMs+gjW?Jr|D%ba0bSJR$=24iO zdAH5`C2oM0A}Xf*4=d}UsFdr7=TrOR{b`!K*hiMEm*%>b7oMbP7wKPj9t^(^GTk$% zA{SJfGJ$y%FoAI`XP-2G!?*cI*Ue3=ar(0Ct7F;i<>`DMmq0i+T!t@MXSSRpI{&5pHA}*3A~2XlSrG7e48|w0*9juT2crd%5!g|Js1n!&K~xLuNI}#H z2p=SB1u_#+JP64^U~;@p2yB@gU)BOboP}f1Y95ML{FaRg{m^?+gSXK=wuC%Eok^>Vvr`fu6ks zfFA$HB&IHU3sqY=W$g$qt3QWXz0X1OttMe_H{>_aR)9t&X&|38@Iz?~Z2m9P3zPam zDp=SEu>jIx17o)Wbm(d1!=|);LVs3b;bmwaLx~JD(p2!wyI{5%0sKH6R;1HjM&o0M`Lu|0bT&Chue{}<2WhtD zlnMF6#rzRAXSvM*u6jb-=6)Qg3i&ch$R9dQ^G6E#*YWvdBAD`>^k?5-R71qeLnJ{k z;s1w-mq7&h|5e&Wle>e^E?Y>~{{!t3iUaBxdZ?c;=;}$iK}=W^{{z}3H0H;&OHsc< zyZB>7;gz@FUtKlzc7ivXYboemh9JB$MP2?ecq)uxIoS(JrM* zdJ57J+U2(-Jw&^VA_=l$|3}d-p_>Tpl1cjh)3i(I+%BxxLS@A!kzzwD_FexK+C@WM zphh;|8`jMS}x(=QE3 zYQ>qTedl1s?k`ELKcZbi-Mg-)T|&o6lF%u?I)=&m0qt@Z$@>Y~ok|D$79W4EX`+McFfegEp)9jYlK{1<^~#t-V&6JFzxPwpWf z-NZLH;kO$${10Sidx$eH_b2^7WJ_rd^tUQ9vlH@FGBXX?TiEV{2mI^g;~|;Z07<}s z*O1KYl9E1(bVO!$o}`Bk_?Jk69Ps}~$;?7++aWUxk-q=5%q;W_Id5Z>1AaFtW*(B6 zh1QY#bx>v&s_$=mO8$||EL69P$jqK3?583A)S6w_%FO(=yP9f9fvaR@?kCZzTRnIV zzo>L?=p1&hiJZg!=Wq@KQ&5~m+skF;fWJ5N7|!9Jl9_29MU@(vTqZc$AGxMV&FV;% z?x*3;5l6e?e9^u@R%B-WYK-9;nVH{z&7tmph$KoZ>)547u>w_%KMDig^vuDbD zF_Ra^2S(EgBoBH}Ff7xzKCz$ot2bzEvhQJ%IZYSTQK}HnXc?`m| z)yMt^ax|O(O}zs+4R|XR5vBdyeeoD~YQVyD#1FHNhI2o@J0>xntn!g0LcC zKb{goYK{8SY{)t+v6@DiO~@uw4VjqsYNv+hv^XPWnaXh%l`q+`?A3BO=hF8!^5d6{ zsu}JZ9#b^>55fWL1i8jlho=+*;JVZM&<{9o4`mA;)y)tQgGCvfdsEF12E6keVATcy|@6vCUcKu;1}mR$z0G z)kud=)ou&Ew~db3vS5*cH53%AMR;=1Kc{Z4!=xFv(~sP|V|)XjynR&3n9UOw-M(nc zox6673ak&--4=s|U@5r2;gpM@PB*%?c2f1&IXn*x^;aq&v3LrlqC6@fGh?HqK-)mp-g{jx$hP>6=O8JMTu)dDMj&$6PaTxwQ+IDTOXoQ21{!Z}*S$ z{O|ubPxBMyLd`!e=ic|@JWcD5^W1xXoTu6J6M28TI?oBXfsdF}GUiehRTT)D((j9U zc*gY`CX0}Eswh+X9Z!uk@iE1)9GSCe0A)=49577*@njy7-i5sw6>Gri;6K_5hcnZ% zkoQacUGNXYr9}NFN8lBQI81oXA?0IXJA}W^jb=rptnZTyVt|TnI&%Ev+1K7Y&2(Zz z2@MAS*u!CFcO9$RAJ6Usi|Di6L2S%7nKvF{JR|@M-6r!Mir`Ehx_Dypk$QHxSWk%_ z$ljt{M`ifmThR}jzqZ52d(QT823?b4x$6B(xGSfu;ugYunNvPK#~^sLN9sxNDo>R4 zG^_i#H73i1Fa@U8QZ>~vO27J5Q%$LdGG&=sTQ12}FlW-?z=dcwYtE)HtM%bk>wz`J z*Wad?BX2C-NLAHSYj(-&ja4qHs*o-%R3l8gi>3?TL-*ONKiT&qw6XlBR-Kud4mJqf z8Zy&q{AH#y%D*alhEh@l%%^ExugS?1nQD&Wo|f&e${1kbD+n<|iG}nOqa~i6OPF)1 zmE03D60=F-Mj@v%jRkk<#w=$}8Ad6f2OBeK+D@vaSE1<~1FQQlqpS*0UNt4|qv!a; zt{RzT28Wt_3vsn57E+G-<9>NbrHs*Hl*^4^nah{ZKw7N5LJp1EWnT!pY{ziTs9kt- z6X{qceWM6TIQpirLqyUonpMWC`%|lQKe(iMS~AZJd>a=86TXc}2*#Ldn8C@vC|5a2 zhghASos$C9@4+4&pCwPo$hjdc4nb(aW^x-2vrK5_u7eExRL% zlq*l(FBRs=nXLPR&)^+xFr7b#^@z0Yp)mWcdUoa#GTfhpGbi>U6=cm=1VEZUjA^yW(s;SFzM?WsW$cmE}x)it-q z=M-X#WSPz=tJPtMTOGvn&|1MNX>g+mO80*iroS5y-UzY>OlL3!OW>6?vZ$y7H7FAh zxB5d;!{AoCQbS~`6=MR}jZ4lBRF3{i@KALgI+L!er=pE@g^?Lh)5}Ts$o_Sm9MH1_ zyp@^{-4RT1A4?c@>~h^L7iFr8oKrZD{(-**IHwliJh~UZAo6OF4&sM12`uDpX&7A5 z9;mzs*K#lgQtc;46Cmtw9SMEYSrxl4^>`10>|!$CA}|BI;^V)F8>xzwM(-OBvDv=- zC~rPfnoo)OT0~ne&8LqahtdOzr<3)vo_761p4nu|Vxu0%kpsx@Fz8nYOiPEL{*qjp zL)EFNIj@DePl&1zc*+d@3$muzUJ|^7cq>>FghxOZVPlsWEjGNLM$u1^lkLLs<4|lN(DB|yB>(GlGw4Pj z%uO1wTcLMc;R~?dH-cUd<@3-u@dY5*g_QjcoUHWAq&{r(q=8V7Z1>awH~C9{(t&(9 z#@P5+>EfEQ8?6ytCEP;vn`BbRX0LQ19{r!{5pB9qn>noRR=R4my75-3VqF;!yxJOb zRbdppi4-RL{J#N61U8}j+Yq2|MB!{RwbCmFI~NXX-Xoo32K?_LJOJ*Bx{XvreMO|! zwEqP0BGrg__*0l~#W>o&2?OYH%rz9!fZR-Y?W6xldbbOXpW6Tz{X zrc#!=>#U*s;i-<(4DN>m9k?GZ4A3|2M9m2D7f+Gp-1-t4G`^N+6w=tQL|f~iy< zUei;5;Z5T1zzKZJaFc@5H%lr;Vx0TT;s`a&Ztqp%{n?h?Oxw106lCg|# zeHBg@)GV*Lhxj5FILiG?c}^(|so*(3^o9(-mhdXlK+zA7exjFl_bVNPcsRj%yP74s zU1GW=)$#kn7hMo}(+PcA-CYR*ZK(V+mbKi)#+liG4q?lU8_Y0#6<=PB-EokdKbE^D zWL}(ZYK6gV@rENhW&>q^0q@t~eJJw&BBP5(?z6~!8o3_~=EmFCB4-`Fi=;2cUc76+ z@i5n8zu?l*5l0u946t!-^*}UDAGv@sB%k|y);10rMNn{9AZf!dYtBJom>H9*;$KKm)!&SUHg z2RLW==UKEX18E?p^gqc9&&ZVVqk!1^7jA9fF3G8e!S2I1r2T@dS-F$eg<-g)#dSxyv|-DLRslA9Q$~=E z9>V=bbt!RC8A*+xmkf1XvBA#u_Y2JizFFtrek`F;@fcsW1MS0f)_?ZBWMK^a)NAm- z8(nAnaT#S@r*lOnoUqAgc>U0Xc6`j)nQ#$3*Y1A%Sb{eUH= z?rh8j>g$(L?7TCcRcRiQ?H7rZ60S+7Q!qj!&hIsCXyVGZ0nA}7`mznbAbvThrwf10 z$1ykfEynY{Z3JEpHA|XqDXLG>9g(74oeY$AH7|TBZXDaRt^as$IMtIGi;w`j2z`<| zFM+==J3o-WnD+ zCezQ7Z)?^poA>C_)EO28OdtB*vc@rM!gz~Fr;$38YpeLhcP#UCLTiBAEz=jaBRd-+ zW1fn(hT3JzJWIUh2>HYKKa#n(Wk|&7f0065qwGkePm#x*c{rZtshpG63iGs@sh_1n zNUe7N<-N8C`;!Gt=-_+B@!8y~GQtYg9NXQ9fS~l}IXTHS^msevARV2-({ZCh?E+1HxX0w!8z?LLYeYZl~sk)Ui&#ZVE5O z_a8t#R`q;@L@{z7%07Kmsa`vH5iTnmd{}Uf&QPFYBv_Bl+z7ZDhKjS|ZJ2K|V+sAF zS3b_D(_3MNSIWgNUn96OW;O{;<}}KyjndhCS|Z8^AFH6GZ1ADr+}wJ6hK8&3QFUll zL95ohDp$?L%DC+vY`peMnbJ}VL_%Xg+>vUW!m;tzRqoghJ(JLg2(m)FhL2anVN?zk zO`poLuCf^1(A+mV5FJ?aKnLsvf@aE6C)7LWhsdby_sOZlEwul}jv;Bum+vGwomksi z{1jan1UQL_u0P1=e21AB$}%>Uj=nb`7)8f_hwoD}GHFX<=)BCo+yh@$d91(oXdY`> zflwNuCy!RgW0lkb%sHH7LLBp0O^&Bz&B7%!U0#=Y3YaOuZRy4-5?Nf<|I|@SqGm-0 z5R@)(ED&^r95gw3t8Y)!=h~qMvj5G)O}cso%i*m|XySWh?Yv|ZrD<6B=sBY<=6LSI zQOC8(nHuNp;I`RDx}D(D+7mLRdwWp#DH_pET47k54R1+^GO?_Kzn8|%2m5n>NrxrT z{zi_bxI@S447eJOoX6LZG5W#l#TZ=}qq{0H#&=|YF#+4^y14sI+hhFW>xfjiQ&Jz>GzeE(j4=r+z0&cTbZCH zgO?7=w0tj9tHmh-;hhm48lJ_W=dHMpT9YUzr^w&X=ZI&ip{+_C!aDBL6CEqubw{|9 z_5;S#%zluh#}d<28XbIRrN*v6tv2&2ESDoOhdr7;`R!>ItLvX|C5we zN`ehWJB-9Hb2LAMXcm*pGb{%!jOq}u7FxY*vp>A2{ve?Ny z4&%u@Dn9-mQohGpl9fEd9mGnurk`fu2nW+ZfiTs@TgDFK;RN|Kvw>fIZzdaw$pF(y z_|75ShdLxeCF$WVPDk$t2ae#tLu2oX<__48xRhE2met0hx@daxHhY@N{gs?*+|X^I z;q=jB#FhMSu&dyyYZcjH$Y5zDCIhhq@}H3p>UA6*UHehB(r=t4qBP7a#rPz4d0Vvo zfa?ep;W}0HZqg^L23wTKR@XI|*BjT<3%NV_g7n~h(etC1asKC_F!D?trAu7KQcHtN z1+Y>P_~ekROC0w2BZ-F#_q)j91>y(yE3hq~rtOmUK;g+H2Q{Zvo$5rD`;Oyb?D-Xa z+EGA~(r6Gq-@l1ggKAgwnoR~*^Fad}o2J*(P|Or@vozCipeZ;hCP;r+_YLfF={(w9 zbQ}tMp9BLIUAr{wz?ze94)sTq zKn?b1%us(ihWgXC$&jb?2lpFv^hNl#I7HqN>)<@Sy9oHjP(Mu+>81!Y@x!`PL`MY| zARQuw(J^$e2n>)rUVJw#&OHbB)c!Sx>wDh3&_wVELMXNk(up)g66R)eDF65~jWJz< zaZ~)HJT|Bbuu;O^{@kTS>JrRD??UzVg1OGkBX*2fx8SvcnxyqfC5sCCqZrY62r z9R(&vgPK0+I%1zoM;k8|>V!UZoL8-CSL?df(bN`W#d?}LW31?e6L;H!*|sXR+NWkI z*%nxDv(a3GTGQ2OLlpRK^)NVkNBKaFt>TOknGI@v4^J|R@fh2+%T}R0FPMg;_Usy& zBvE!LlFXr8Fn-p)X8aiDis zptm*9TNCKr66hr}y?I!TZa=#{rbK&K-xCXG`@LC#t}~SyT+;6<>Nl_3*QVQ0b;1Gz>60=Ok!h${P>yk6CJ?r$pnNe^-aA{F4ou4B z8M!WF~YJ)H9Wt zSU}m7F=F)8F59yB3SBwo1zjo8qS8p4S(TUp3?E}hvpGB_qktllQN&Q4He0bxx5Obt zrlD)Ltzu{zW?z{G?E`Yfg|Z5&%+^zGJ4C<&wuFmo%h76+M+R{0+`Z`D=Qi9qZ_8Hf z#9{2wW0(5BIdxLH*mmU2=%%R|f{I#9mBCNj;tS;!UFF}Ly3~L4*f6%DrW_L8M^`(S zmHlBwX%q$e85s6r%2ukQYTm3^N-s{g?PqM1jcT<8ZQttX;Ii^kC)Mm!2~Ik=-_`77 z+Vxa-EG5KHeR0(Gw*B$&$p#t#y9EpEXzD#($VU6nJMaMGQ_ zE(ks?iQWQS9)MCJc{LO=sM$vBL~K&HOt#6kK4)C7?c3g>a<7vWa9Un)^*LiN6cR)a zsrkfFXPzpW7WfSR`?y92&j{j37d~qT$uW92VIR<(VU+KJ?}7D=#ZWoM05y&8+>?x z=odINDQi_}nh2iQQ?B?jW+ZL16xA;2$bGw2u&DfHvc=;rkyG^>ybh0Msf>SaIHqST z`mKggDby-v>Vb5^8idmboLW;3r&yZ(OAc4+B!vW}l>knTj2uW%$>qN(UcXGwYD!W* zUb^6(RbH^gt?E>l+Xs{11n>9YS$s~e_^KwuGEYf{!@3!U8AWbF)7$OW? zF+{kC#se8*&zcMMgTq9Z16>uyATQYj$=)ql87Z|{n$RxYSP(KV_|(j_(M)ikuZ{M# z1mC@z$(}-$N)}N{>kc?4zaO8eW#i}5d6YkqikECw6{-MjNHn|XpAonaIGf0kEc);p zNQzth7%Z$xII4}ecuSip0=bBk4NMjjkbf1*iEt#67>)NF;2eqA1r!{rb z_3TX-E9p1e&^rWXdh?`|x`yG*jC2FvWIJRtrY;d&Hk-pGxa*!jIea0ymb;@-`VTi7WM?FXZ-v=H}Ke(;0!gq3^He$N@S$5?a~d+()Hbv`JnnVwiOiG z#!?$@IdmqFMmzL5tj0_o6LVX0J5RiD8mJkU7)p)MDMSF!%w6Bk-O$Y;U|=o7jh(8@ z;1dJW?qkGyr;}Je&uo`&?Ur);Bo8Cy@KQe0j9JLj(>#}#lRT5kEzYG-Ic+QT!(hq45Bl*%hsH{Z0CBsp=LOPTPuTmU5B>Vf?I4`YM!g9 zDtoMe=Co89*>GMUAO~kA2rv0 zW2kt{&{bnTTJtF18FgeyD!o$sc+4aA<j zd5vE$JR&alF7(YUomn-dj-1D!@h%p^N4AmRhvfLuH5^pGdx&_tNO&kpY_`s%b+3on zQ_gpf@x;lorb~V%K1w&X`!CKSeRFG&|2uO>BW|Q4=e9 z&qAO^X)JZ7vfHyrb5Lel&6}-(&E*Yw)H-Wz?YDJ#bd5E)mGCq3m}QBjd8*vbs12VD zu_CU>d2miaK;I|DEG%5^n#-jcqn8}0JhJ8>h{YrJ1K#i4DFq)?v({HFfkejiAIF_8iW=hW^w?t>}%G5X=b@O-EslOH+&Yxc5P_#m=58~a*e)I zOr20vq{-!{-dwxaa3E54M%_14Ai2n;mNpE7w-9t5-#>dEdN3vU{)aL+LbG*EDNMy! z2s9qyPOA?yx)J+T9RYnBEdBiVAOOQM*PJ@7<(8WCoXP8AkHjwdK;D!%9{r_EREc`C zE;lQ;CQux-{Vcc`J!Wjv(4(jg-Fl_RU|DqpMv{WLS=W|$;iN8>RXrQfO@VFzzF2=A zZU^tW+{eo-80fQ%cj8PC>;G^W*#oC<6S+E4Gr(u)hU5#vQHu2s6K1M%sp8=Ine0p} z%gjx@Or&1^(jpw;wl;t*sNZBT%-54K+$kPWJJ{UWlg)kb^eNVFpr0UhAIUhv9!Wf6 zy^1%e>{~*6l2hgY2P8>#T77}njf|}aS-$B(0L)6J6_Yt`znhK49&RH^}S8AY6n*CqO zU?n*n+PF?t#MF#Cz?JX^A!80cH`_FO!98mi z(xFS#W>!akJq9w0XzLZWD!~P(teGjzU6NWET@NMh9{HG{CDIayl(WRoP>AwNhv4GI zMcBjGI+jYunmihTHGqIt!8-sv^IHnF7i82kQzCmkweTQrY@i3n;s@&q{TyUJE^%UY zyT5X93t9>@VS+oKb}vU0tE=$(OEi)VRT55TO)<0(<-Hs!bOKDm>|PwAWOTGHDcN8s z8JC<8!)im158?YO+FO+PiuXbGs^cx=Vw_R&@B_S}5Ak?0cg2S2G*zY+BmjJ-q-jIy zq3@_1zKBU4G2-j-dW&FTQqr}Pg{UDt$`yTzPH8lZmq0q`=m!K4B4*(&TRLZkWoXjc zsXRF%sC7(5M(;($QND zrdG&)R^`zpc90rcUmm>Oh8PNbX$H=zG#|^^MEY%U`L`0su^-8}v*p30%~ z6zxPWNtI3_e&&J7P7T>BUk{JZRJ#p08CPc_%ylfdqt#deTGK4AZj9(w3tax`Xhq4m^cQ68 zZg#}x+!CX5rjuoOrVGjxRJ@ZNmAKzr6Qq{b$1DXeXS5UVsJrWPhEt5wS+HhtmH`r@ zxxL6T&kV>2vuz%;y~J6n%+xA*6~|omk2q*))854O1dK zJWhj1i`9B+!TkZ-x*!2YRGkx*yL6_uhRH2P-m~V@O6?B^;-G~^Em!g%HlM?*^~?}0 zod|loE82BLI#5VXz%+QTqmz!2X$MxHs6H&wW|G3LwUgU>COaiDIwRGpbL}rwxYIdI z*X_nlBSt!eJJW@~$-=m4-cWz*Z82Fhnd*yjEBr#tR5lX&J|x-E#doSE2eQ&s>?*pN zEU4>&0q-mE;Ej7!mJC~FAfjqTE`ydR+zR4BgDw%Q{eY3xcG-+3YHI1isG`K&^gGOb zKb#-3*ABw1h(7eSyt?%AjR7kME0F{#=giO=Yrc><_zHyrh?z1(!?y#)tc^y<62hq< zTMO{eMKA(I?xTVq-gqnE{kVLrv|5KnTU~3)v}8zPznQR0NWJCb5dldzFtK<}E<*PrdfxInH@~6#OYr@_sxY(%iG8qMDQHU5W_kXyxP7dbK(=MKDsbe4aL1vBBBO>Cmc0V z1JV~eIb|Ykb*9BlF!Sw*x;rhp5c+yhrNKeviRnz%bN+{AJ)7J5;Y1Cil#fDrk3Mdg zHBw%CUS82n0Pq?-1uP(PW<}Gft|^7&URqeWd<}t&lXlj#)!Pk5{Ntg@NX2QW*no~i zLALMF#|~AD=tx)QnP7X$zEEUBfZ$ETXJYTgf0T~hhgit{%?|xX=~MJEDobXU$7oIu z`1bZgc#6~ELvwtLH3p&9@$75qpPLX>*K5hdWWz0+g2Ze%e+_scB<#J@0nv~m775Oz z-h!-v_=zkgO|$WV)pwhCr^_{`OdjlyQNbwyHD3>pPE)&g12~|hpaWl`w~I1Hjf=`u zhjz;t96)NfytovJOunqxPl>1#3)_f~WS=u1S;bDf@?i(`QHZ>f*j0t1xwdQC`ffmQ{9?SM#P zR*ht&5$#e!w=}9#a~f#xK~<}5MLS%=yKCiQM!!1^$0RY$LAaS=I4cEsCT%i%n{2FB zb5!2yMKFnRYn!=|?OZ}PH;Um#D3W|uFLJ|IPl7fBZWKK(eE<{-HHUc3erQtq|B2eL z2mUE%(&qW#2|$qMl?RXF69jO zMa3*Fl?=~(O?&}o((aXVa{Tp5PxEM~*rA&ED51#=Hb@>5TA-x0z_tM7sMlXdG8j!H zgH*f*8412i+Bi6v9^Nx?zm>hNt2G!ruy%tbO(!(jFeIKE?qFET7F>0J7rFQiBY<4f z?mr=FYWy+{t6lu{s*~fdnJNg}viHc8;j<*?0R)EmJVUR1L>Xx1g9fmvjM>kb5S|^2xDfs$6TCeY<`r!LC&YvsK5%ulT<9*Va zW~r7n#H8_39XSrn^}O`rX@(l>q^NpEs)=e~ss*ZLDpi~;Z8F@&#xl|)d>g|z8!{Qc zKw$z(!K|zmk+shdj3XI7wU2uoG0G^dGg$Cu)UP>#TNC*NQ*;NW=#+Tv7so^|_lW7t ziKkx?xThl}-OtIaKJpmKlJVfizuX#4792I#2;7S^ULFxVXAJH&j%ghO(svzx0+)Kk|xsm}VNO$eI2 zLg^{|(>}h*JRSm77J1hx3vo(p!)8GRgA4OdFIPwA`7?%l(Z|)8sCxn#!Jip}UDznS zWBxMX%v7G29!rbGg5|OP3{o%Ob8Q{`35?ClJ=Xmf!yPYvf_VWX_>)P=s;}7Lk+l19 zn2+Kt)WY8h_bBWKq-Px}QCb%RKF~8==|(|%vXom#cHX*E4_9%|m}(OKFT&miE~+a3 zAHV0$0|VZH8NkT`ZSECehQMY9%fXlKCw6|2}un9(KR4zb`Ly@44rEKIfc!9zN&u zc|56LTrk#If%Zzb5+g-1`wl((e?XLBW`>t&XYjM5W=z6J_f3^E{#qfZ(*Y#>Z zr+epWsm|(&?TEisRwjQ zzsSXR?w07oAbsI~5c@xlS=t*^6kSidXBCX`LV`R^tr)1r@dWhcc+k0&9v-8HK@+|% z;@rhqGxEqn&M{jwx)5{=N3sHt$UJ?jzJ?J%@;JqXQ9QL=#gp1GU5sbj=pEE(hzP~^ z;AtPHG7!{Z;w1%+@F-2)~Q;D_`CayU@#bcE1 zHTP!(B`y@Qv=>Wsu*?e1ohfCwJ4K7*WT26{-%VC?3dj1NYUrRUDoPJzT&~(zaM*Qf z`2bEyUF;=FiE{odvEDMkLT53VjJr>fFGA`1Vw*rI_dMbc$5-2CM{C7VN{*gfo~*u9 z)$fu{EWs=bBNX@3fzXJ~jrn)F`tVwRE>@c1`-WrpTw06s1A4ed8uwR$E*xJYLZPGu zs;`Xozl^?ZxeS^|rij6YsK-Gns^($XAE8HA(wDs#$Fg1>#nZ?IJcZ+nm$GbaKX3sm z=Qx2^I{RqW0g)L#N_81Mw56A;jLoUr7j*0^2+in{v(4gs{jDlCM;5Y?sO2Yy@tFhKY@}SGedRux_mmi;X+rAm0iHB#OdT2lfQYE@eG2auKu1J*=f&s#bn8E6 zeL+_Ym8C~zU1#W3%g}FXHb(F3QQ3P`{ZH+!w;nJaXHvXguSd19`*V+p@g{gk=yANw zIqvRJZH_i^iUmqEoFi*!TW7qK_$RhUrDDGRgv8YO0@rc}uB*<3#xOu(_%c)$(%6eO zR}Ecp_NW>G*FX8KI_mPv$y)Mm( zNo;KzI2(hb5cYOY)q+;vZd@DMak=MQ{S{7~({XaU^_aoFYt>K)(Vm)?5fGt=A1-4Aah2(IYB2k{*2Gj7--KiS^B)7$hXPPv{#=F?9PzpZ%(SzrB# za5^9_oI855ql?Ksd#a=Go{?T&gOx56n!H$eH*tUIasEBdi#t-k4(qYKW^2lk0CU#ce{M|*RuEbD7oN9U*IHZ}F6=ohfi13Rx`hYr z?{r0y_eas!EI+=Qk6s&n1=_&>|4WG0QTGNp0Aq!~-x~6-he*O)a3$?Hx$+M3-Q4=6 z{m!v-^adqBc?M=GFGmDitm3%>$j=6gf=)$fXE2(NW-DAuxGT873;afRNYe& zE78;6jlCJXP{*!OPF^t#6<2JoMB+#UalQK!T*z0m{TI)T|3|r3{*QD7ZTqiyn*NXU zP5&i*Fw|A=RI$c___nADdlsSU4}K9JPKh>EGK_!E`=yau!NX`^u=3i626D8#!dH7y zbnJe=R7eb36V$B#&`NZVj8e_wC`NF}YyR-QotN7WSm6~XVcIqre|;l5yziG0W77wE=Bd*Ba2irq z(fHvOQuz4g+Al<1*~Lmd(HqQ&zbLJ9tc$Q7Mpq4kK6GtrKUOn4)>QBThr!4gJD}q` zSX|f=K@U@QJE?EvW~N4_lbXBx11%NyPVt8S9GC#GdYzro3h!Rky*z5+*&H0%1sgO_ z9Myn_z=6^?t+%My_%=CEA-u$Va$_tVfL_W4yK$R42WhRG znaGd7$gRLVZf@rM5%zuw_9nL@iNbcc9nlo_CVH2Ihnpp6JA$x34Z=o#z(#JsPQuO2 zoEpfK%3x0+_2msdP?IHDW^Z=GD2Z&R5+HI>45|@eg`*@ine{eO5gvSBB=pdKR2fJA z{TDbZ5mb%5DZzm*ub!$+-+(h+f-@-YgO2%sz=49OKZ{hd@Hc=>i4+b(O`)DYNaMyC z1afil^c0zWRws9E*eF&ux%Z5_5 z%%^F!f@>OhG;^@yrwXYS12LZ$v9`yO<@CLg3(%GBJ8{l5vY%p*Ryyqs)ot45AZM`2 z2VX5;iN$fmOS7TOkXW3FVa}0VG~wpTNBe0oRGTVkaYBA3?_y7aL7rL=GnHueA*VG- zRRFt{(ntjtek$!$(xA%rVLOf+ilHi`9*{on& zC#+L|A)PiW>6a*&#TI9zd{_J~1^-Nz0Smq*QagX0JSXz8=!phP;m9ceyI&+LrDVzs zG{Ce#8Z#2lZ*MuY%F`hH=U`<8Me)87R4kPkQmj#^@P1m8B9b#DU2U^_lNIAK6(gcE zmW8E`vsl^)eq3XGSc_cvu!>DG2-dXt`Eeh>i<*tHpZh`y8ik@1W$@Ot^yucug{1K+ z4%?4O&#oI_%w;%`3^f^9F5cc8Tj_;9p_ydUk6M&mG_Pr1;6=*xhr=;R!dZDQFK+Qz95t4WK#?I;lPZz1br0wWYk*XX5zN( zE~->{N)+olS*)j>3TC}tW%Gotv+1?zA&GH$D)O&?0~;4P)^%2=pq$Klk>t6irt{zkL6-{ zx9E=4oN6p9_3BPU<*Y60*`JAHM2AssRWI1SAM`B0PqasAas#u^4*f$QUr-XKs9Du9 zzv)ldr1udJ=-XG4liLeJlqa`S+Il9lWi1!F!POP!Y4yCb9Cm^`L~_Sw6sw2NThJ~@ z`A{VBG({H~!lekj%AUkHJ&Zy|V5!|E;w-d>qUl7tVm^UJMs6Ua=|flymELkMFyJg! zv=$9?bt&?HE)1_a#_IGD~2tZ3?^@KjLESWElmeX@ae z+~!FM2KCA9I1ZfE(&Ud2#1|ol=qm%X0TRS6kREm=+9F9w@pf9V1xg4{yh=R!zcids^xl-9|;Fzncsqyh&nD_)ZpZ;Od9 z%SvlcXwbt3Xl7~VtESs9#xQQbiM0|_vR5dMJe`tS|1%O3ZJ=^3Ds$;#&&YPQ>{`8R5gVB*#7+u%pMvW? zKg?c;1s{Kaa&sGP9DLxx#iwmbb4(hK7 zM(S9PU}_`l6?A9VZFz=?^^uB+(3Ztd6l+MXSr5*WdG@HiWg&^9UC%M>Z*)B!*A2_+ zhs>Ese}qhu(q*vjqFk6TtR;%FgTmbSeqL{Ts{Uo{P+y9ERUh^~)RdFesE~tlGaRAP zjY8Fz7arTl{dRFU_viv0>8HoHz1pC1g(T-|zC11bTT&7Y+n~*%qWf1(MUoebikq|XGJd4Px@45Lxz*ll#bt3J#ms%W7mY1 zN8Of~Ib5fO|1OZT_WaO?S7g5`*kdEXT7BR)XMX6nd$_x~TMS&eO>4C;iPS}1!f@&Q zLac1`7B095eW~|sZ+mB_cx>kt$Hh*{TC&zFz7VteM5Y_{Z^Jb#ty_a2Of4?54@N?# zTm$SGxlhnFLE37Gmiy}ts$w}=U=Si5&*#vzIeHgNld$>a&fI_h=nAE|A)xk z)-p#!-ls<_L#!Y~`NQQo0BBhhrFio_x|iUPIexvGv%14o<(`XWrJCn%JvGriSLK|e zb(}s3R*YbsDb2K;x%NHR3a5Q8h@Sd?w%j5aPNsNJaJCoS;YggYMw2BmwEPW zMWcslTxiTw$2O+DNAl_TsQpyr|16TVv?5Dqw=6W){!=_P5vLc{qrhUffaE|6J2cvV z0URSMG4k7@4C*3F(+7<0Ja){LbIU)wR=DCDTG8ijZHZMD&bX!=5I1Ys+JA|C-J@_V zMgEt9w!gc(9sd^^I}g#x9?q0t3}SyBamjDWo#Dtmi&uc>WBH` zV!VE8yzSnKN8KXdfp)ic$?G9dVrOH(lfH7jo=~46ln*8 z)71ZugLIyaZP2QjrMB-_L5F#kw#TYbwbxGuAEG_G;Yd2S^e*gI?M|mru|v!n5t;R8 z;%p2P$1qGhqxo`*&4vs8hsE-8L8wHGl}Bm2WKRnN>|x@T$=!C&DN{J@YP(Enw})F~ zAr^bYKEx(sxj68!7(LW2=EV7Tqhg30t=L0<1EY%F2aoaB*Pam1HC^lZN^FUUt9#OO zc->KzaC47_!iY}kfQH$J(m5sRhZiMGFWjEiZ%-$d5YbQM7~!4h4QkN>C;qA%mr zCZXoZ_c-X@TjpxGD8(*f3@@}O5#L(Nun}>FaJb-ykunC^O8A{GQ?6t0kMoxkF16*Y zliRl)GERDal&h@fRGh54`zihBtC>3eQRq8#PmTf>9Jdm=eZNwH37<1)Zv2**CjO|(ZO>0Z7Fs_jXM_kDriDw2On z`A%Yt;ydENJH!g(t&ss+O|ys*ifsqY8&VBg z@JYt!B!jiQbi6&9T`a_xRv3sy#X76dToK85K*)oG=jxg=)QnK&;kJSLMM`n zO#o3b+<8J|7X2XEME_rVoWC_VKR43(nMmj7TEM6zPf!TKJx)dAMhuysM|v%JR7#hn zLirCp|2jsVpZt7}J1*9|cJRg?=Xh;w@+fFll-O|aXM5c3lx_C2J+3S`H)fI4$e(If za}0Ke&~~iBgOC#{Ije=!7-AtU#Uj23=IJ%lu{8UwBK9~q0>RRpM@NFRG%G%kjV;X% z$9vehu+}-lRc_D4l6jivBCSIC9IbVxbFQlXJ#1vPPz+OBUr_vZY($>S7-M(k5H>c{ z5_wzsq)88_41Shq2n9i`2b$6#%iwta!P- zsGXVVO@`Us`LMfc%0=Z#u>tLD3$``54<0VqmvPDkI!BJ>vuTmE4>~4bq!=cK?g|V+ z9pTQ;mDmZ#Lmddznx)Cu^gwbr^>i`ym;0cQ%vz=rY<~`o=$shb38j5-q0({3=gVKd z%Ei-taH8YyY@qQ}Y^{!IoT$`=ve@SYFmGSRN}y{WzC)Hd0I&~`!?v=#q4 zz470{jEdz4sirH)?Y~0nTsb0|CezgoJ>q!sAU$o;Fc#lR>&k!bd%pkN_Z&}4^UCog z=9T~aDCX79tM*Mbodt|=Cv)ugR|^Fq+|FXNv2W@lS19FajMz4Wm5!Ti-*nV+zbQSOoTtfWpgE8p z?k_xe^jGHPR}B&NO@ky?>Jj;@h>DTgbcX-UOu(rb>a+ZV>;296-rq3$CRN93xpy|S zJ~y?Tlb6rs+?>KaSMB7K&bi@sF2p`J!jLTa6@R*g_POwJa!aiCopCiEgU{`VdygHk zV)`buy=i{%YOLM9=@RLoRT*G~-{^FWm-q`0`ad5vChLYSI>dG!r%Njxd{Bmu67n>> z@~9%07}YxVf+d2he*l|R2+q3coZ~oaoTzI#Z+=&tqj-Lqor_yi4t0fxN6@#4HU#-^QnxW z9w<7MGzYs<$AXZdqE8{_!#iFb}LHSLSxDIZ=o@@w=y|N=5MBB zqw;@p02{qWRCF9Ll5Io#!iC?APv@#?u46QDQ(XVP%Dr7}5Uc0rKizsNenBjVBJk}7 zL`OOrkfow03K<|Tz>z$b9Hp>BPiq$t zVxym+i=|6Re}Uqh${2ehGLGhjFhyboW8(2P{=ES^dtjbuQkMiE;_1`L3I*nUrD_ZA2lw1a$J0hPG~)w z#UkQoPBh(Y?zzGBPnRoPM0t(Y#}dcbl)o6xxx!Q_j zV+(1cZ4q2=?P?VG7V-vtZ|C3Q)U$=oCRA<$&oQy;#}+V@;u^PtlP4d+)I{>dF+SteVfaCD2tWXm}tRAep1jO zy`%-9rH@hqEJ6i`mB}MMek0bYjz0)KZTIKv7Q*bY%<-@?nBXs07QqEf@F87ZvrdUA z{4xEGdVB{BF7D&e`zGK5Z}IT*Q&ph_(EV^-Ufac9m!BBVcHYe_Aza)(Ef-n!z1Y}# zenZA{+f9~r?B3xn#uT^C$aCs5s^kc8lY2-O?N#Hk`XM}rr<#dfdT##K88eW3cFXqM zz}rm+P9CE?{+gpAIVOJGQSH^}&W3a`Ct^OToyh3F^X~01^qdat>o|Fg#L>o^Zv}TY z^YqZAX0DnnqNh{DskAp|cd>(_7qM!8O_MIi<{=bR;dMFIp@2x@C|cbJysMh`i-f07 zyCNap1eX_zP5okDxr}W+ADRL3PiQ@F%#bPs(MJYChrzhu(ppu4WEGwRogDqhQp$eF zE%y6Vh2_`kyH2FDCnnA-P2XkZ>A@t$AkA|S491K?_tk#$rDjaSAAG=xi1%tTLhn=^ z&{qlVFm!OAL-C{bZz3B3AE47UiueXrxl4=@p_tx*xx~$^{f6pKg_={f`=}ioLAV2h zyi0D4%{Vj)5+;_Avw#O@WHKXHq+J~A^p8I7cK3+}V#yNor>$Ph=fLgC-VBh9V{8(J z#>7~OwXg!$Q@Ai+f8?{BWU05ZeYBFBBcnkbrDU8J3%(a?-o-Jiub0$DF$tsNA+^hq z>*5sjeF2zB$|6P0hft&BPl;p)En7c=S5X;XQ9qR1P!cTfgwf~>+vOa2)BE%lWOuZb z;=Q1Y8udwYKbC6nxhk$xYen;$hcezcRPg#C*M>vjZ91Q}FJTu%&Vs;*^7aS!@kRDi z8KK%)uEXZb1#{Hb*~KoEv*gT_WO@GX2fYJcxc$f%+Kl&Sx5Hc^^w*~cPyPB(d`2qC zQ}4f1@J%33c~HsZ2+KbwIKmjKYsm8l?^*Bk)(Lyb{x0}o;ruEXUfX;Do5}@q&5)_5 zt%T#~=Y_myMtY7*g0h#tRM4I2?KhJW3hstv+(zfnGtyVvmth1`5lXhZHU3qMbxvBD zDdoZGri8Rglg$e%;0IChJ=MO#9IhFG%~3iRE62B52{D|s7PFp}on!pfh9TF4Ue_%n zu3MoB4Tb2O$RZZ%$aWXZK<3DOE}bgPAV9H6a6yYov4Xj@yiN;4-4-}FC*^z;6o8$) zw&I%ipvm@uru&eld#Ao<(V-n}M|SSm3cnOvH+grM@?X=my{~E8pnt7y?XM1LGHtKb zty!_2FI!Q?+;3a8%KNOT>~T$Hji$0xUp4>G<4e|*KAs8x9*fP)Y}@Q??=z;d_cfJk zG;MYIHE?8c=;I7zn77!KKd^mXTeII)gr4%t#P z$T82L1#(TU?V$(DYBc!)O=XIHhG4$jSLd1`BnH2>Em5Nn==axkobS_Q+x7=hR$PK% zc%|R8YE{`3jdwrI!Jp~d|M$c|Wuj?6Z83V0nS*a_+pnpdW}@#;^zHZJeS&HKJRn6& zf_VKJ(_K>efA{V0N(}6$Sobz>-2}X}D+2rxiWe_dR8BGNJ*Q99NKFR*vb$&w^XGku zNvLfmFiSlR%(fXCeTv?Yfwpw@p&EESuX4J{G)*J*H4vlPv}|WzVmxgrs)$-hqZ`PA zsLkHK#Hllc%DYU7!Cp4a(4ZIvYzE*ReW=2J$6JNh@7=_kV3Lrc!Kg4T-GkTL`cR4g z6Z7W2L?d2Ov}iQ&tXf6e9c=HLeTjGecf1_{yx|63^Q(RI+s?tawM{YU6HJN86d&4X zz#Pt>f!;77|4V%u2d&5o^9y}I2Lo$-(?pYgiYf69ipBg~A9|IUg-=-)XVNE{XrCm~ zFKEyL@?9p=bPA@j514Mi&-e-a|Gf$S>0iQ^S^?mOX28Y=m_Y$8?*pzI7!eP?aDV7Q{S-Z|Cd1F{(_sEF zhNv+59V+Fft(%xIJ)mYo9S=P?_?3R}IDMB$G2-2E(-DfY z-@J9x;A#EfSM*&R#fW!bnT}A5{mrXZ4Sua3JWbzCq6qQswCM;%*suKwz6rm;hc){q zzQ`cHA%22{ukrwz*nLFbeb96y(8E!LM*@`xP5UXry{=WOx)15QkI;8YiV*LP1ecG! zJ+rgB59qrO(RU0*he)fjew?yu)vBGJq*Q)js$64g`$*pgPZk@RPai}Dwr+Th zHh2AGAe^0D`HX({26)z5Rl5AkgBvEV!X8DZa^`Ho2oIlS(m8wE%lfjCI$5=ySu9)S zELoi4wv#$p?!3y%AFA!JwarZ_ffob2ELX_B>kvw8+heLMX_U#_GK5PZYaT#OFbPZb z@DB#sGB<^hoRlJA2}_F{ph%=MFqJi2&XDYG6=y(UD^}wGnWks$;V)o;fZ8y)2KW)Pf;@uIY8Y% zPCCC4{iOs9V>xoxQXW0yh{kQ_SE9u?$6t$l$}edufF;uOe}gbm2o&tXi-1*=N+|M1 zFuH5*MdqL=>gHL~PZ(}8^>Qf`$FOi&TpV&!Kk@+RF}p|R^bq7mchkw&qk$NtmSap}cr* z!V%|?gSkUs9R!lzBhK6seYqYff{$%vm_`Tu4v{Vjy6Za;` z7m&*?LoqvNoYayDq>a|LH#|OxIn*{qXuSxfF*`RdO_rU~Ewo;)#YwyM+Ao+<0R68KX&a^=TAl-Oe=m6AOi; zC{Af;_ou0h9YUVs4!hpUTk_=gJXt!i%)y6m@X&C+5|B#2{MuIaQBz z6a;Q(>orIOxYKpMq;V^q>sj|LO(2~gud}OU)hf2d8M1-()@j#dKEB93zbSh%;S|(s z7s`1s^}U)5eY)b*xx>fy^@Mi7(sj63(46%3Cp+g7b}m!1mT6i@xvNQ;PyCA0)mT(& zHsBUozwe|ry=XN%SK;(RbBwomS<76RFjsD}!Z_bDmyLbIzl{k-H&S)nsH+})EW76~ zdbb{Pz~^Gqs)No_mk_FX*hs}X@R-=HBB89KD+E()lGq21A!i-|!{$TsHC;}y{wSE< z;tBQF2a~ntZ}4Idd4`rW9{rhvReC;y&IVo8sE<{hGsIx8uiiW4hkXoJSS+#=Cve}V+Qhz>1iZc)aehtMJj*F zMYSwK%>!^)0tpkMV;ji{QT?0#pJdY^$5aaT~c6mKpZHc2?w#TCn0d~*a+Ma=-vi#w6C?7}7>VICOt6SB zF3)0^SHxTr#uXVVWR}Aq=|5bt&9kD$#f*ePwo|KbqbOrsKz$1+1y6k8&TmTmU z?Rs*WiUU-x0oG{ZxD#n%kexVV;Cl;o-#p29B5gXHyJ2GIsTCiSfY0i(%I5zT7B8rM zJR1|pA-My#v)&Vvs5s~+>Qvx%R=6p<0Y2@c>PMO$h>yA@e)5F)lw0Fx-WLA=yyHNt zM8E~EgTao=iHoLDRZ3c>$!>5r!OcP>47PKyv)5-%Z@d655-o@%0}Y?Xs1Q3VvM?vf-(Y6$QDpV=Q##1HsFZlg)`|~Z}qC|x{ z{n3y8@q3CQxSrTs7B8cUhx>T5Qk14Oy9B)0Hu47Tw4laqZ6w3x_qsLwA0e`2S=Lml zS6bQBUGz?)RJlWU;X|o*C36+$x$!H>!zE8IUBKCkRZ9Xj-!NO$>$$o-1PI!|1upH& z+qdv%)BWRxpIqDb4T2}33Rqw4op8^~Aap^LW4prM`aQ=4T^(Zc1$XCvo#O9Dy2-%I;6A8Mw0LYJ4%BG;AnmcLPlY(nQP=KZ6j zgKi>SZ2UxbeEP2~Ux3%L9t@^u$ko@8ZY9qraSxJ9^!{H-;Cn}qALxDj#Ps;&8TNma z^?Wk=ulrOlF6Nz#LZwgU@Xp>6IO)2y9Bdgi)h{AjC<4lmF{y_o_#Sv0w|_zGd!DKN z4rAwh&<7)R|9iMOv}!=Es)jBFBWD@KwwBpbsG9*+)cd_mz&kGR%D0Nm!bC25oFYu^ zWSDVG!XNWuG80}N=_CyEsF&kPI^Xln-Ig4_P`!);67NdBeD0s^d$#r`6TXp8Gk#qUF6 zGo`vl`vTvhZZmJzwWfmBH8WV(M{m^i&R|_>8#AT48hiP~A^r|@kKpNMdBa#;TTG~{ z;Cj~QTFttuM_jc-u9{xgGiMY7A=l+5M&6~2nY@gcCcmfWdBFvShs9MT@Xx|G2(3BX zPg?kA1-|lkYI*>zatw<@e9Z`7yLn;^98@Ng+tM+RAf1ST->v*ilYI^o6PVt3+Q+Z% z<)0B+Oe|k5RU{KU{h)tC*2Vi=g2kopV$D}DsEF?0_;~-~t)Oi!pJN7HB1yE7LPzq= zqzNQJO5*itvOF^9U|PuHVjnNK``{dNum7AVP)CP6Mf9MA$AdQ8U4qj!+3kvB=@8Px z*JLtv#80k#0pJ#%{}-PmCt3>D!s~$yPvJo%LJ*0YpIpwz!N;WF@v!`qV1K%s^GoPB zo$GVmKjbP{Chv9S7eC{6Iq5jx`zuH`5LJaEP5UX_K#|>3A_+Sdko7bLWEFKDbA(m_ z?D&Yk;`cTmR=+N~C*ccQb`!3$AqWzw?zvU$EQ9V1#ZeUg=Q9N zT%?j_mlU!z*k5YKK|KdvizHaRCVMmL@5c7i3s_33*1(i|=njG< z1F94`?T~^;-e$>U$}@>uJ?@mbq-2^qlXXtK?TjoR0WmXWmWg;RS1sG8^=VRB&7_Bg zVMd#f1XcUbJfw@U{?%(c&nXPc9It(@W=q+ym^5$Nd!`OPo;CV-QkW0&N9q6aa}|kw zsz}Z0s49~>dy*Wdw}rRebXI>N>BG+NB^suiuB)fE?^}CD0imXhZBkWyIlVzK^e&SH zho-I&-5z@2Gz9V#v(QrY}n%ETxw$mac3|dj|O^ixG-jA%t|ulNd7`D?2jVK1A;TJ&E#UB;N85lWmt%YgL{k-`Ao`1zC;Ty@ zDBwmF|7Wa<%{US`;hNgw;oB(3a$nn@o2Z5@N%KR$fvK5Y7;l34KTj9Hv8r}6c#P}FUugYvipgI^`vFw^W8JSYMXZefV>ok|sQZ5y8|lQ}VdE5j zpJ;3XKjuclcz=gz+;*y-gKN?sUCUY|*RoXF3@94M`yv{n+YBy=r9*G;$cLAKPXPwJ znVTu&9e)KJlf$7;3!TFP>Ymq`3u)!ELWYqo8wG z3?PEa-^FPy$d4@Jf}|& z&r|D7FyN_KEM8|{sfK5RnukOd!8Pm&nylCdrfcTMF3Q%dbb3z}*8H$ot5d4Vn^c8w zha^WFRvvk2D2GuZe2m)G0y}1Inlz@ikTNY9^ST!lVU3b((UpZny$xAA^p&Yys?L-{266Fq2RorCCgEL0(Z1S7@ER*$t zh|cPK4}ZVQLilhQhX9~OoP>EjUHdq)l^&})2SK+DUUmgFO->cytS0LXXNovBT$U`i z$e>?v4KCDYFtIYzU7C<0mvZ(qL2;X)P9faS}nZ zmt0(rg0YX};j|sA*jrHZ8eE$NPoEXXQT0$Q+o;;dXE!J?O_Z@7eX-Kc13z3}#1&i2;JA4M(pwO;uwDi_V1uE&w*YW7?A zJKtsIN6phsRwQ}ct<3bzg!6D*>;oVnrmz`=o4_S_!Q0AU6pbQxE5~|`t8Y4VOB${{ zFUH!kz86`~qRw+-lBaf9OsWL;1y+$IwP!>wmSeK8U{e`0>b;LYZ0=%X)dtM#+q!!- zHbG+~7bqL=8WcwBlU3xJhq6UgR7s$F+G?;y=^1#;fG;=2P|WR-R_2e%H+18ww+pT3 zV0KoRcg;!)KZjEn|1q(!7r%4MFXnJ^Kn7=Ss{;({ZNkv$V0Us|2TtbFR8_%fVnvPjWW&MeltDCa4%mVTP&;cKJF zRd>5{isqiWa)o?NV8ztkAj`Ol*he^dP`Q60XK+;quB|L^2QIs_mDSm@lEr*w9bcWz zy0aBN=WQ@Q{GH^Fd`yptg)YCKFp{H#LUWq=KIo{`lS3Y0gE7PdHJ7g&h{1_tkUu13 ztUJ)7RCh_`>|(ch%@!2c0C^%wp!*9t3Z}Yg60;lehEr5k7BEi-7*0CW5cJqYkH2zD?I3_m` zGjQlnLmbS;?&f3zOjiW_4RE@01^gujo}H{pSLL{_v%L=rG}~95a`>^e5>U<+^y3wd zT+NDPt~0rJVrpfE!oZJKR`_QeeIyO^Avxj~ED$cd*lxZAZM}ZdK>Mc1W#mq=z4HX+ z4`Q0!;IeYPPQl=`>>i_e$rSp%a$HbYlXErs;8n(9b*vXoGT2?cmOIF`ti4qi0$78`dzS)TkYVFIHc)S7|Huf7D{B2Z8 zzfEj>WMsS$VfS5!Uo=(E*Sd1x3D~U(x{<++2fGr4}NaY>eh1!O1E{SQ^9aA#w8`5@uzjf_UHjl9H=1YHOo0 zE~#ti&nAaAMHi`W`9TdG;Y%V8@tAf{cH!79Ja=m4!nzD_g+0%$t6muL_)@Tef2vRf zcEZVU6&d=+w0oGaz{PE?0#Ecwl@^wTR+-?FAsqVb6sW9F)6_LEW4sRCBpmG->nEf4 z<=`@br@IJet(Cayad~jPkEi_tpI9Z0^Ei(K+$&=Po}b!ltBp&$pG+SMw)f{zHk=F%|)I6v0z8!>kK|MBxwk zq6mw&&L8Ms7y-imx^sm7%{nJSudeeu`Zw!ra9l{=f_bb=0ljL!SNS8)0rNy!gso_c z4Oc#{Zd`3&;TM-4R~ep5@Y{x82EQfvZNRS=zZ(47a5dn55Z5p+wAY7u?~<%2SS8g- znnjzzwlX2xqJ*QY;uJ_!m=%$kG&w7R!IJ-3OSsom!Vik%UYe*3L-vayNq2mvPv@bU zmP!+Aanj@X!y>thKJon`Nuf74$1K}=E+lF4XZn1;S0qUimBa#>?{W#Lkha}BIdhKL}|C>n0 zOX**TI0kKFJ0~-nv9$Dy{3jxbpl`Aeajo^NZH~9_zv zZx@MNg3%?qTfZ+^>Mgu`g#U|3L`whG?iI^hhs!Fwgej23_1?nu z-|-va;)*6JKZOS1g@z_?;jFW~MCW2&} zbbmtRp@8^~bPq?aP(R!(-4BZVUXi>d-4DRu7HAz_6e)9=u8$bJH7%p8hpb2n;H>3ghl5cc+^;uq70Ur*WpsM7fa;lt3i9*6yQD$QV!?X7exe1MM=9$=5)y& z(-^CHfX&Ikn@>h-zsC8+9|t_jukfM!(H7J-NX6PCZ<__SK))|du&Cv%`lc+BodYYj zaUtz-!klqGld8V(3cg5^%&v}~rOkdT2hzw+HIt?YxvL+dNaZ+Yb9DULuVL`qvhSKY z?2Z*~HnEyD-XT;%)K*%JxV6l)y4+VA&SxhK3au9?jXOr)HhLJyDV<#jLevD?g4LGE zYDg{}HR56|_MIc~PBy{L8t7`DSp=4r@v%*Rq!iS5V)dL*oCrYo++0`Swm`vr8>!-^ zm&AiA$`_BKpB?k4V6r$Qiv`*1h-6~rb`V-Oc=+hKnx&wkMx9Aa$p0I_qhk_NI0VT# ztgpEb-6$vN`B^9*W)Po$$R(praB28I$TK6JI0M<_NFK`xBY8x~W0F`%s?)>A9!*lO%k6W* z5G5A27J^4F z%dzCi?0K^&={9GR|I5)|%Hl3zj95H692}e;Y{k-mKX%hY5YB%s8j}{T4OaVH)vT+k zi#7OE#l1-yR@2mjm)4mtkNDmaMz70RJ}-kc_H?+MvL z-r-xGnC4)|Ue}1SSB9{%?PplfiXKlwLl`Xw5nz^_PDr#V4tWACL1;DCWPLtG#kI~5 zssR9LXPVrIwmPoM3ae=x4-|Bi$qPYCa`jUYW;A@LCuC@VBzX_hLXGK`v9%OqU zwHrap@ITo+a%YOKC&ZUzV)b{@eh+pGoDkGJFNY0FJr<2Iz=iTc%cZgVd*y}Yk~7A? z=lLI$7q&y8g(CO=N?thfgS{t&RVP~iDtND1*I5=#)%8xWd#~yi#X7w|=zh4}?LDvi za58sjMZa=;WGH9$2z>wPqV%e27# z;BJrOq>O5-zl)?a0H#TbuW3@}R(R(NVf6--3$xoFP0ZG_ots2%wYw(-hLNR7meS;8 z4liSD!D9AD4f`{xS8BOvfAkK=7cw=AtmVM^n9&`7N4ckZ#VfxvEX!Dm<>9cUC&V&2 znPd-Pm>8FtAA^rxG{|W8{0p9He01&M6f2k6dqV7SNys~Ug)wCDGRtJc?9v4~!?OJ; zv*Ch7dW&Q6%TjKmkiNYR}LU%ofM;(v@9WVGyQqR}ut^+7M77D%w%WjkZ_Un*s;fdB2o!{Ue zk$1i+Ro&O-*DHSpp)Cl3S5gR&o9%8>#490gqVR&nHU6`5Wdn*U1)pA#$R(7Ykv|j}RLCr{%SO00ayTz2YECA;^9Xq2@3kV7LIsFokd!b7Tx8 zZNhNP3Ayq~x(^Og{}aJjG+nH&QFV+J|2_htK{DMr?9E#8F#Re}(1782b0jIEPq_mZ z-xx47(UkGz0h(eB)IVU@WoUH#POe(It;_)B`X)PluP3?my=rOhKv=Q?eo;qhDxedG z1UG4%;+O)HO+seqKT7VS$?#WuVJsfWO=Cz}*AZ7psCmrIg!~M++3Ct;g)R`H`%{SS z(U4T$sMTFiCd z2ld0|y~`y{qmYl}6}u2np*l$oo47)2sP61FN-v+Ha0bKSon`Y~tTK@ai_BPyhrsh~saZPI76ej^inF; zvX`s5U9N*tUz745;-!L1f8&_`Hw_U+^h@F3MOB8b;bO(Mtk2+a09;>wlSn?H;4kr) zB9K*cBWvw0dal7n3SR@x`V>R213vX`%F|15_MQV<8!N6jT-We?64wD-yKrs8RgbF@ zSH*9qM_MYL$&O5^_~ZP@X%(9vi@dAiqZN^NSL}T@a(cz#S0k+zr{9iDjc3!gpB6Jt zi~8Kv$#V5@#wjuDx|nfNMA!)Y#rZtrYkEG%U!2b~PSEo?{(`uKEe_7-_>1#7*jKxc zXLKAd_}g*UUym=}b-ZfF@wFcxZ~pK&;+?UdME+;Av-Nkbv9HaXzWkq8y&r7)*9WH_ z_7$d{)1F(fvHHHogTIRX^ZKnJ{p8`*k)PI><97d!oA=bhPs>NQe^L3i^62YNoqN5b zW6A5sYqLN7uJetKh(I$J_hizkcOr%#%*A}8U4U2W6e z<6={1Z|$FZ|Nf?jzkhP-;hHon_0}@M^4qY&`2q?RDMbbIllWr4PB%EUx>8*eDAt z8(|}Ttg@F4V_5-?9&t_qnF`)cC4;!Z+RA{oQq)4>2fD#__V#l2mf^E{?^gW?JK4vM zgBfr&ds}xv&)~2&?oM{xR9YO)BN=TqJBb<4)5lEYNnpoW8tU|oY@)#40W1xIzHwX% zvN0Rl@4c5cckt!IV) zX}*QK6({7B22^RSAL_WdM?!Gxl=nH011n7IlQjjdsrLsneIF=vz3Go0|qRljmF(er7dy z7jPSw1DL?2q5#cZr)}pQJ}wQ$NYI*M1Z@j{AGEMHtVQwE=0^U$$^bzHPHo4R-ST*g zOVi8WH^krP-Kk%1+|c9W@B5^~6IQi-vWV!4C;!y{La!@w$QA8LtlC=v4R)VP>zPr7 zFpDO^q-RVG&s7P0M%Y=#ZfjUl}*|8wJYj$ z-Hy6SRaHBGAK+ISsy@C4P(L|VxtIbi2?BjW6E?u|_ch!BM|Gj+^mt!KqcKUH88~@0u=HtjhCzPAo}twTlY4-r&Z(GsSn$^qn+#-eN70%e5wlD z3CQ{u3R%z62+*{#f`6|RH24wH+nzlbnp|fY% zywB?^U(i%;&~M#P_3r3v4QrS+8^X>GzDT=cu$4j{3?GARVoituzNU1L(IC$9D&}#f z?P(3ZFhDoFQ&l2W+V$orK0mUd(rxePJ=-*x7Hd|lDtnxHd_~y6AZzMgR@KdDXfL3N zFH}7QLd@3v7y6-53d7{_lo?FfvsDe#HGo_8SQU~`<+Axzh!zW=4Ug$dp3q>}K9m9v z{WDAtF%PAL1qRh7Z*i5E(F{s(y-Ta$3?lPRg{MwiU8F$eYCpKH1^ z^*vdmk7v%#XxDBNy z)0Y&m>H9Ijm#PK>rvHzx?*WUdO8>w24#VFI-a({vQ188&&XCw;rg9+AnGqC03os1% z>Nb~J{F812tBbm}%}^McZ3DI@q&2d;W_;USq^%6v-GRc8h637BDcX@XQ&Jj9Q%SkM z&$*zr`+c5Y&qL1rcg}m>bI$vI-uImIzMU=I=iMVE%_S%vQw4WWX7}IR$nFZ7tzEp& z$N5CQSv)*tG;wBgNwc`F!1=J0`-VGLEjG8^?F8M(-TD>z7@sxQ9;pV|%_Vgu-Ax=u zJxb;W+#WS^Yjxx(-=@}rNiu-LNaRptXG`;&btQEz>nQ2x66J9t)g1_?e4w0^43?6T zF-gkz9ze-;C0k2)Oo?BUk{iEqJJpg)FJ5o_V7z4h8$NKJ3qW#yC3V);?b%w3Gdda8 zN8HvSQnGcUI~T0Yv0C3F;}{v#(S&to&ldNZ!zgmyQ0fq59uky;6=cdBb4y?gCP)e| znK-GO?<`O5yT0`|sY8SPspUk#fMw?iZ@bgolGhP==1rtzaLosTY*v(S60DA+ z?#Lk|=Y<@U%rzP&Md}^yl8K%6UwKuShGp|gUT=79(BIk8c&~e~0c15k zO2`7sK@;k9n5AsjInOG)W8$Hh{1JRn)`3D$HvW=DDhVLKvh-hSc3A zc`Lbf8I67pDcuppQ;zp$yHovxWY|MlS=G+)4yx>3Wc7kD9Eq*s2dhqPy}onTU=>KK z^{(L^Kj+TS{0EZ9&q15;=r*X8`^e{kFKsI8=7HYSAxa`dQdTz^6GK71ki_()IoznND7b_9Fjl)bfN1s*GB~BiE1)9ppF(=vzI!) zcbkM;@ip4eX?BJ3R3w*eHpv-45hFv55t5VQJeQ?LN=l`0AaU09!9XIFI25TZ6tG{5 z;>ketAT_f@SOT`8p`adWw^__xV1qP3gCPnq{Tnl+Bf3PTIipFq1(c5s5J+M4MPsuK zgrZ;Y8VKw-Fs9@|VDmf88G*mM?Q$ka@JW zjKl^}$nezJc##ZW9Nq(6xxg*8QsH69+qwdfhdh7sWb5NyLfGGQ`k#3@M7NMIY?p{btHGU;=Qdko6&I|M zz`9g1UzltXCgm2{P+XB2B<3S`wkXQ_#Hz?D$QIBE{fbTkE1h?9xmu!!QIYd@oPs3> zpd-!nv)58Bk><#%oxe57R!lEcUm-6B)C2{d*@?k;G2>PHxXrw4NW+O<$9gGynpdcj;3%7tCB8fl~h#!!rf?v?t zkf10ZAJhm_r5GFz=IW}XA+CDCHFXLPo~f&fPb?+<(Mj<_WRTWP*D?h9bJs?gX z1~5E~@YOk&5RTCT0$iBN!1+(wOt1r50#y?9NCSkc4ML?}$QTx^gAD`1;)bdUd0OBP zlCyyeG)Oxe0Eb^E-71+e=Sa7rMNPsy6oqmIgsCv|B!$Co5Z-9!B!xeG>oqiOq`9G? zpjiQm1eL%Vz|T#>RB!}?47>^qk@1HS6M&ddwGjx#Z~>vK`a|$#$U+;cz$lRZ!PkT0 z`CMZ&2XgDoO@cLbUgS`ud9VdAlJxP5>hS+Y)n$+-l$1^R_PKovY#`ouP9+$(Gb9Yx zz6>R?VkVV!rhw;@`YVYCAhoR!g3`WnZ zvc>~kGlT-CmkHB5hj6b=m=5}!TW#Zz0A!a-xgSW@}Br%tFx%Q zh>FA}+)2o?k_&;aA^nH?Kq0=#rKG?w+=Z>6u!su$4B(c`lt7V9HA5in?sPNqZ6GZ8 z5Fsr1m|D?NE2x3+OKbtQ^Oi_K09Q!kS>!jEh9{9g)&%Ii<%U*6Ri0Tq50kTi_sw=U z7ofJoD}E?i-dxZOz}_Up!w_8N zbxUUzxZVaSv`9sc>OIn58q$lMVw!?USpk13h3&aw07#Qzu)%b$l`8Nr*Mk<~b4$cfog(;maBQ4NCgc>+IuDF3R z3GWoi@pBHjXsHr@q~yZj$ht>ITAIs8O86$iV~AW(7HmOe4BN1f*(gfcqFu;@Ttbt8 zjiCX^FjCi~~|iKQOQ7Ybk)JHfKp-h}TB?J{#-@-0hWb z2h4^4a?FtlP}?NupbfyX#K9>T7-0%{gx2tOwGj&eDQ<_6V}%N_TdAPCxf85|(T8f# zueVi)ukLXPzhq?3UL@J+pt17eBA1r4AAD2RHm>L?gDyMIq6gjdxGzCTI> z!fk!Wr3TLWOPg~G|i^HU|Gim<6RZrYU-sjRc<~ z5DyhKzRY`S2)+Zl+gc$c^ffdbEEcl+${~kA4JHQYgEAVMNib0`s4&-15P0bABRqs2 z0a@ThcZuZs($*_vulu=Y2o{)cnbh59^A>PaKPK=DUx5S_)Q=N#eFf_Zf?spa)r2ez zQHSa}k?$OFhPkb(#1AgwtvOK5eB_W_Fb;mTt^lz!h+0_$qKfj11*0e!K^*1=KDLUI zU6@K3`H0)9N@Z}=qgwto!c35!SQ}Z35m^WHaR=zm{T+dJXbGelc@49+PFlAfwnUpS z4J3Jf$9Z;381+1yX(i~(>WGnbYXB+$9>{o#cGs1xyJKujp>616QJzPp4+P#m!XYv` zRSpp!9V~B=lte)mz^P&OL59E+kx?To^4=~vBY5ZA95sQ1&zceDAt)3qzQiVB7A2A) z<`q?&?6kYD1%x$2@z2f{9iI|QF;xU*$zNW@l=Tz4(sT-z&5ud7KF zQ!zXjCn|6&fI9dv33>)Vx2U7+3?UX0MFR4?X$-yWhP?wyb3Kwo9F{;w!CEdCNC#>P za?s#PwDFj~Ex>a`Z6q~g4!|Tk&~_Chf{Bj5^Q0Dd6F*e#XPZ?N7CDBv#-?#s&D$_Z z8)`vD13u3J{tZBZEW#w_>&oGcK~vx&0A#wl~YLfA;~Cb|l42=I2k)cAW_U4fIp zYsp$?1Dy2LN^L?;Ujq^CS%|k{u94>ync*d@5t2X|kXA1GZ=p3`SnT_pa1cG1dyYqN zs=#S3Z}-)JpYQWy_;$Wq>A@ zOI&JdK}P6lbv9-p?ioggM5S>}!eZ)kzPp8U_DTS-4Q59_=fvBe)yCkP8XZ!klc7ManY#?Ra)IT>wg{2#SVkT4CBBVTGP0Q`{} z%2Nxr76hMAMccpJpqPxfCpaK=yawU||Khtp=eo=JhVouv#(`;9w{B`EXaI)mUWLkU z196}tw;x=Z0pfC(+3*|v+1CKFJSWK$(Bvs1x2as>k|hq?3fV+?37_GeMK$PD$7d2c z7>;Ie4KC|`X(!=WVm~lkt~v{X0B^6jdC+9D1_9pY5b)MeApCFzKI)=Xs2gtQ{yx8y zXoJ8fg)YJPR`x@j=uQdE&UB>Ips{l-PLLy&GB!?9cH_?W3);!P}yg!CwVHPki-y#8q!&AKw zoUqGx1B9b(5P*%U7V!OD0{#V5SFxK<#ctUxkuC5W;68>IKpeqtsEbmu8@x*;d}N6z z+)3}evhLBylE@Y)hvst70izU+r&@>##4&8NzgNg<7Qu}sA!m&2v3sDFOpF%EdEDKM z?E_dNW8`}EB>al78B41MbEXC?}8zvYHXH zim1wkR=YeG4muD7I{=+I_EPYD$6yydEVvh&s~ z&e}pkAKI@pzcc6`Z0T%pwo8BxFd9(-Jhe^~03ljOIuYOF%aI{CQLXM_!3e5}Qy+da zfZ0euXNXPs@8P`z;lcX}O~8J^?`)C+=nbq1lsSSiW@-Fk%+Cs~5>#bBWC~zspkE>m z{?o+4-&adKtkbU4?d$XR)pk|^wgP?D$jj>G`vE{JM>>cPtaKj*9B2Za2FDu|$+&(u|cq&lpXK(j)LqA}=D=kINx z8<%zaAt^vD3`P_JYTUz_7zgFou`qcG}j7-6yzW;eNc;U~Us;*9%MQ%#I-m z4hoZO!w*$}Z{mYIaR#^6<|0@Q{XiE@gC{H-DeO_^{%2qv5%c+~NzI+jW} z?+BqC3=Y&vFazq!K~jy7kEIsEGML-MyJ2-*=gEpt_kQ9K0Rsj=>*HK-2z`0)W}fh5JUlC8>+*D7l_*zg#-IK zlZbm8^*SHt;6FpTU>r}#Ef(ffZ@9emHz0SYOwM%t3J7Q!VeCxzAe8478geLFR#=##wx0IR|%zQ{)e4U&a?k2$iZD;m&3e7Bfgf^=OSR&D~f|Mh0LI z3{Xi$HIOpR86JS;atX?YEWeQn)B*0!BXh_?dR9``3xTehiI)O4Fc!H$25vY0M#8CN z6Ab5a32;1{$Yhk*P%gFcQa$H8%3+5~bHm}=FE_l>T)wrxxdBiDq!49LPR1XIb1G=3 zRHTr$p@qwASZxFEP)uWiR98@>z=c4jIXo8o2^WbY63`UJ&=CnxvB(clg|Qh>#q|ip zHN5t?Pxw^Fc{|;?>S_#M#OE#pzUDh?TQ!&KUhHh?tZgoVG)K7v%>mQBNro5d#0P_Z zNE^@zS&kcHQam>Ul43!VkX)1js6_bwjXMCS3Ka0AEf>>q6|Awra?fJ8oUqhQ1{V6i z6Yz=1XGq`0WQCH*5!jz+`M>}d$lyCOS_9u_XLc5Jl4XyF+-(@tHZpX<8{t`MUi4px^!X?*{~HXZue7&VmZTTqI&ppjyaMPz_eNp0qh$ zm(V&MIugV1X?KwVf`Q4L0GO~&R0!#n+ zeJ)w1%NOE?h1k9p*q)#B#X?@H0-q{2I9V>7UA|(^)$N5n!-5V*1rEq91o4Rq5Eue( zfPAQztG|L)fu@1L>Lzbj@4wDv!&Qp7>`SrDGhjp*q%{+d**0ssG~G|@ock|2|G25% z7E)u=R@lOvCGKLI#*t-n4{&U2T|5h=~4i|XCCecbAncdiUsmV$on(aMg!?}XJvumuHsx(*CrV4Aw<}|1C zQkhk|CXK|!w1yU@WQ{N^;SDy?8hK<%lQrtlO7Edf^;R6W z@OUoOSfi^}68fw$n^%@uC#+dd2()sA>vMB2#bQfyEWFb-ejF<*rpN`cVwGN z(4<4#RD$C7ZmY50QngDZ=+@1CKaxUp2L3j%5zsAnVR*+qCea}@^>4KL0(ewh7~!elzywY&nwm6C~V~6 z3(DKY^~H_##jn>FH`T`OV78dniYxL{$`;!ZS`U6iL{FE`E2ZBk?z0MxHPu$^XxdW0 zws%F_;^CBm0|UydH8@qF?lEO>d?b@%)YD)t+#>r;>q4}$${cFfpVAQn zFD-<=R~zg(gY)*miK{$;!4Wj<>YUuc6Uv=)$!Az9Ukt>6;zB9FK7 z9WRLjyb!lNLoM>Wvi3l9h$zRdNQSsuqCp&^3PC95U3T8n#@99RFP8DuzW;SM!v6%Z z|2eS}eV>i{=^8(^`C8Q9HY+?V4N?v7Zuo=4==Qwnrn0P#6u0LnLH>Xlp7)93!yR1K z@V_bMpTNy^kJi;JYNqw&v)-ol#4oXKbrdXNp>FFdZ{bF<{xD5~esaq^iS@ zPjD1+&a+(hcXR(i>-)3VZQmgZv~({gA#VElZQq?pknTY^XHF{MP5jG64_$tP)(;Ky zFQxX6TwFxHsE}uY{$lxd#1KPIl*u#uhO#c$uNd?e5&w z#PN{(wA&?0&P`;E3pQbeFbh4lBN=Ur1ZbKGujiK5V&V2w42+3u4=;M1*26lPI4s9O zxm-DAk|)`PNtT|G(W0NFre`m;%h=Q!KOn>(CoewZe};+@EdrQnl659wx=D^T3Hp=^ zCLzHj1KLbW=`jgYQ%;!#e0J;cztRYTDBl9cFE=5Df$RkRpHTKTk4?&`STY zSa=0HOcoJgjfH%8dq18_Zl4q__G6~3{Ep(H2O>2Q_PLEH3Pp#Pt;o+8rlnFvE8hpB zsfe-_#o;ws6(iK(1B=ufH7hE@n=JL%8Mth&dZTGYeR!{>t&Z9`cB3QjgnXv-iaP@0 zBz)L1&`dRqzd5{OAl!yCQ)+Z7C>C<6^s4P_@<{=K^+K*|4#q8G#75EU>WZdB-|;4# z;7p&elpW;7HYlcmhgLR_#i`PxRXetRrCBP)E&}K;mPaw4Kc(k-SW|y)Gs-(O1ZcgcRDS zW0FwHV_{89s6-Weorp+@jqD43+Kb5H(pvrIW_pbdXN@)_!uy6nejH7T9 z5dh0+UkQ=}Ae}rB0M0d=9A@6W;ZE0T+E>nv#cIYK(}p?iZz$2xWnI=aTovUwvdLxH z&lBG5}J4fVdpm@Oi&26^Fy}h?jD`*#2<-L zfH)E)h6ITVYOH?kcO{c_d6Bd|h3h}g@BZU3hKL2CGEWCw&7VDD%DWTGbr{5ph#y{tctQyeJy&9%TqrnbzB!cMGP}C51qtn<7jmxI>t{P2Py(Y9t zqjh1obc@bg%hzi{o-w=B{mrz`P@ z_L8AG^ffS^#(#SJ=fZ!Z_zyaEES4)1i+B`q0ZMl|msu!KwyR3sWktTE9QaO&qAU!T zWzBt;laAX`U$?^U=*KoVp92nn7AY579pAS#KZ7kNaJTqseOM#F@{jA+Qf>$5I&Ry! z*NP1-H$Q-kPr8*&?6xBI|X^~4}eB@+=?L7&>&B)Vw<;nK8pk1D_=aI-^A)&XG7hC!C z2?-(eG*a;JN2JXBR-S2X)^APKN8yCQLm{I+R1En>MH5`17A6 z#h6;Hpy2v;P|zey8TgQE`XJaOPx(~;JtIsT7N$On$X(nCw4>Xw$#tIgr6Vtf4nwN@ zgw5B_@%=nT|4DEG%|s{`%q)74l!XBEy#f@&EyKdC5MzksuS!i4Gtc8B=XWO~Tw1=& zBVrnMs~~#X;~|KgmJm`V3;oPMFEj8V;du;woD`NX@cRkRE5P$d-nbHxQyYYUxs&$Y z&k?yI^1&-MpF;N9KsjC|#MGV~kVR}>K%h0TJt)f4_S8fT3&KDv-`gsI?a)o2)Tb8S z%G+C^&Zjf2RyF+Q^eXVig-!+kHj_>z3|Cp_Dj^3>)>3Oja;Th)4qJothS$oRTD|9$y-S`Y`~cJ9xFZRK3jeDK!j|Mr53m5FcEp;yIfUXVd!R5vm+0t z<%-apl39Dc+1q-0GIMkp#d7SO>^wF)>g~5Luu)w!yV#A8k8*6cH!kRm3pnDW60cP5 zl^VPhA18@kMviZiZny6rzukk|BEG@>9`gD=g%RR6_f(y#5hfk7H3@M5H+F$rbJ&WVkR?)7 zE#iR==@osyE0LzMbgl<=?ng&+m-FE8|7|7^?+O-e&B3k}@A9+3@I1h^4H|If&MIm% zi$UUt@Y$kr@jQ+V&eOL<nJwjz@Wl9+j>T$KI@gIwfVU=Ie}fu{;W+%U>~ELaf~d~$UJ&4=mImQ zccbgdy_>_(BB{!Y9$gb!6)rNAbMq$Pw+3vrx$r{RexPcD=7=r;5v z_G#`oJlDud9pV zF3}-6yFAr!L6qarEl5o+%9Bh0!kBGxJn7vhlypXvZxw|}qI?Uv@f&ojfX%)@%*6tS z?Ppo1Ak6?->jgbuAb~5Mr-)b6v6?LEpi{6~?tnAO4EGEDEQ3i}EKEIsWx*2imMBcD z5yE`RRyjRAp~8ZM8^ z%Qc$B<#sKl|5f?FBlIO}HN{#gG=$ossnJp%&m#v{Aj}3JOK4JPbnxKh@7Yi`Jnn`xfty)4=iZ44PSFJwNE=EphlcyHTamDh)VmY>0))mWKu{>ezskJ>_%!<||*qnNX zr4Vj{V~)#K zIe6>C7+(itSB-yYMXX-+!%6nm43rogySl~RioDg@@vC@y>k?djJN9gvy)_qA3@O-( zi|u#y!Zbwh$Nunx`tXC3wFjp#r(;95m2JNRyI^ASg$X7hx=Fb8ZMs6>cIYC6VnMey zIl@*fOtuTLi}Pw_yD)_jCcf&9C~Xtsj0cWYW5Q%!q(y;ieHno%f{5Mw!FI3@!Y&}n#p`i^cLyNV-M7wNx|D?<;t7@?chi&Ny{2l_2?fo$U!?A~ki z>*Rt&>YS4kHg#1`^5erc8D4{ojE$4I%DsRjU4!JG!VGx|7}$N2SfPL z-F=ZHOnrpD<0%wnq)i7r2qrvBz0k4miU%GGh^_S7f5F4#LB*cHq_uaK+4j;^y5fXT zm+RuXVvpydr`#tdP-Ihh*?|q+<*oQPA;eMQah5dZmQ-N5IHMw4Oht5!pBN4lMK#{3 zU=B1!T!0q@z7TjTnQ+91G#>6F_%~tWqP<&^qV=9yO?wAoP0oJL*mH<|^%PUM%0 z=1)PxskA%#L=!_H&X{EOTFoBQ$D=skpOQECju891k1WnBCg)l;juNl4#8dp~Xz|f+ z*V>91Z9Zae(76R(M}a4@U`4X_yt4Ulc#koxie;I|svYdnTd0H`FYGNu_1;%C?Y^<< zTaU1Blj<+*Al1LJ!Pc!5dmk~JD*OEzLWQP+q4OE0hM`chr@Y5i(zCS$H56e_*IZtY z^XYMm^A;zk*pBkZ!O|vhy@D?MLTqbpbnwLCrjM^SeenF-dG$<46QlJucpDo$^?jrD zo!`D{t6@TMO4n2C_11c7PL9?b3)UuAFyS>!gsaNysq$2u7_I0C?hwkD$Ot86w=~Go#^Z+x?O!VXVdAN?f5;;>BZ&>T5JM92??|M> zA2B`qh*}bf`$SxPnT^VxSdE2^)|8lpzK8Xi2-Y4-tt@!(`H6SncUdT1vMA!-CwH)7 zD6^fRB5P{VGo)bVC#C|%ILQ=4tjY-8`H+M_KVyKL>>D1QKqZ*xP8VnXWqQJbxznd0 zit6-9Vbf!`1#j4ukd-=Bib0O%uK@X#^-6NnsF6-Mz53;R1WjP{qIJgWydc;Q{Lv^Q zK1UxBgcjKtb8tG(Qfp!gS-q2Tz8+cNEEVpcww4sF%Gc5ew{e*tFvPGCiNCMOrmEO* zdIZC1`zf6Dw;%X3is>N57-KB#(g}TLI)uzK3j!12L_0f(bhY1V}8+mlm%xn>9v5U3xJ|9B%JHhe{U31vqSkcz9KcZ6+6XuMyH z8j$F;hpr<}5D7?S|9@tkfb3vEa))QN4g zGhcx}sx@oWUay68-AD+7EY#WSLun_u!1#c#XgnaQsyolZ7eunRglo=+=y{{2k75ua zT~i|6i#QukD)#y*78YsLe-@_)a=)0uCQGCAL!>CIV5gyW)$IBu{qib&rcQ?OX#if`^mCK6GUu7s@)5U!?PpG> zO+X@$`t~<}xEf8efrS2`AjNA8nz?{ZCB%%?_G35@DhM5~)=AojIfZZ_9}Ea1iiORJ zrme)Wg{YR%mES9$+jIJJ{9o@I7@Imb=Oi1u@CS^!zX2z7pUq1Pi4d;JCvC@)`?X!j z)$+DZ`zz&O?EPohlk^}HQ3^Yf9r;2Z6T$XIQ|*r_;cQ|cjhVH77H)Tgtw`sB2bsT6 zN;bq<=vlibSab$9iyjf_9Yj{|E4GxLW#`U$3q+_&U@TZKJUfLnxEf2iieL{EQafS% z+Z2Vpn+z;EC68&1OQ$L?DdBl+2p{s~7{)>Dx6OF35r6y{#1g?@7XDng_TbNpKYadU zWLHEK*L119KS+ANU&HuDmQ&$LF_{lzVwU9pS~#azqS*%q&Gafl?(&*YHWxNqG_xcT zVcj1X0s6^YjliD&)eQ*1htHnEXZMrO;(J3#h{XVbPzR?YH;^S7K^C#MnK*;!K5|>{ zzr62^@QFenCs*5skHQdme$mTs2tA~v=TTBRDaqfWa#K^72w2wq*kIfFc{rQ8qx=gmZS?$|Y_`IxigAFKT%3i7p&ZD}j)XnU~r{~ga z6HSMyRzhj%j( zI{p00MsUzb8%jIUPMF$#7)-1t@U1TAKKdy#+rkg@jUrC2o29O>Y>Xi~;;;q3BU@=EJGKO?>$>R;Q|R`gc->>bj?QusQznBUrSUmEMW?!KEjX&)6c^D|sD4CL!kucprG?1G+UQD6>sN=`AP+l7RDL2r7V$+|1o z?DLs@Rax5D{d#|E|vvNLJpVKAY{$LZWHzVki=%oUR8V>R?Mq|m~i@KcGI zsZ>Pi;tLP{m1N>Bg_Q?i=$Yeqy7xj>DN8Lfhs}MS!Qv*%Mg5HWYIppfLz5<85hk5k zN;ozOw25BYjP!!;{Pbl>^H&i$ zO;FnTkbcd*8IR7h-t{_s+wDI`Yl*pZl%otL`#uJ;3iGard>0jiTyQMIhHg%ae73tr z7X{!>O}4@)URPciMpYfyS+F9k1W8*=W0#w zc5kOB)4Ru_sKPYrR_nTgEG_lqft?wPwIvnf#B}{fN;PEmx`W6?tjm%(duNj)=<}L* zvzFP-L{SlWdpse5ZXK&6_>YF5TuI_L(ih1%*oM7F*TNE}QVCYeJnH@feP#;~iPehD zo>KLjyFWI)J2&*Ag0Yg7m*9`eSe#c9^3IJBL%{Zb=_%5;Mw&?Ce(0&FcI`vd(g{fj zM^29ta1E7dpbv5us48uRR~bxWp`4=3YtkvsN^L%nU9u*WqO8sm&f%yoUO<0+Tg)?5 ziSM(VjI#ZVzM%Z}uJq{k$5mx@#&#ud+_0pGeur&zEbpY;1@BwDDRgmi{FhpmDKy)6 zGm8NUAc)7suohzYu~Cp>6xJX%oUg>YmOgopb|cx+6rClUpkX)}_iKNNYs>7)ZHh&= z?IOG#ng3L>(h<}T*<7@H72^hNsqz!^2ld0hIA(G4?|Kbsc$^e%NkcJ)^_focdwph^ zV%S&tm}1#CmLWH@^hehtzW0)TgO)8_abayMf#akPho5H#c0)dMR}YK~rN?BZU?86; zHROe-ok&MKKGW4|?PAJM+MY$V$#G;pq=C_YAdH5SC+o1~0@9E&#-6Bx6>doXlvA5q z&-CoOB@pI2$gw7Yiwe$tCFG2o7)}!q%&xlQaQDBwz7M^I3zk#6V&}e-ht#jc_lz`+ z@O_3B%klYgtX)PD4Z8AE(wjm&782@(iDg1;YD3~%VRalfR}JOkm#~#TO2%JW5FD+ zmKxnD)e*_SfGItsS7%^W7FJ_c8U@TsgQ@WD6^D%n=w*b3EL+uc=kzirVhW??c_ zCQs~q|H@&*f#78??mp4)$vxuW~l}d{~Zu z*Ua-_?9?@&c(1Ufapx|e_!gj>hhMu^PQuqgy&7|yBpZPaw_pAAOorP^o_1k=Mb3%#5-B3 zN55w3iNFx|F_yG2arP{JP87d6U1GdW(YuDRP^-Km_{gXIyYuBjynL@*rPuv zaPuQkC(6AM1D&aXSeom-J;>{#HM4$CM+5oWYOYa|F8>b;Bq`anQWG%i=(qjo8)F)? zk2&s*Wi^I0YN-#ygXfW`j95#(D;Z*>jpv-XNjJ%wcqSIs-fzO^7=|q|DG5=c@!ImB zhS;~2mzB^6DuFrmDh&3jZ2TtoTfz0PodkL z3aecMt(_$#v00C_A5`=JXPJ*FMjeSLia4>z1d1d^{lE&4IDf!H?Ijgw5}lBFI|{^( z-jCt0rIw<*VGwDxGjNk+tUV(qMPDgBkvFC-LHkwP7*0_=v>^v?t&Y8n5 zNt&S50>YA~o#ru~SH7mcQ+ZCw>gvoehGc4$!n_>+gZp}6Jx=J*U9n|`D`)%1GQ+Dx z!c%oJ8T*IaWK9cL4Svz25Ex5n{X{S}0+k)3(d<*0@a+MmD;inAy;Bh?R<_7Vtlpd= zv&-nGUj@}&2q`>k#+joSCzDplNih~VizfSq-QfHQCB7_tjm(BQHuzx7SATkt+ERT~ zLseDlt9DcqQKJ1+i60)_Tiq4?LXsJ4@2|dEir$FHY#|Mbsr(n{fEaOu@A~K?)qMAE zL+M)yOt4=U<$u5Cp9>K*H##aMMg6Am!>A38Phao02>=6G#FLv2U5c_kLm>;X%!hJS z8zL!2+lO0G{hvO2Y4aBcZ{d+uI@<7ICqhEEe>ZCRFe#=J7%B78XpTSY3w{5hq=63F z@L{qG-SvAqk@OV$DJJu~Q8d=wK0Hd0EsX041hK@Dgs>R=gukT`d1u|nDr`_ z_;X?Le-Dd)DlEPr3=xKHnV*gJGZtIs#ZkbH5cDvC6ut zwtjW;RGu3(=Aq)xM=g2CK7iR#`5pPHHHpRYHySf3pM2B)E*Yg*=B%txEiTaL?kH_P zGfFlD5H303Ps3bklbK;z%gFSN#Z^|UeDdnS*xO<34(sUl<0t78RA>K*=zTEhv7mO( zZ_op@?>M}%@Bn@ZtpM)-1TBh)uzVI?v+}m2hyej>(IWlOc6@@&4yLJ`5eD`pyn-ZJ zq@!;9@%cPN6Ee}jtDLT_eD)(28em))gGOQ}5lMX2)`hH1+Up8JxeqT4rw%40u+byu znHb97&FT2|r#}+!!yb^0@eKA@9N+iv|KsLFS?c`j9`mc-*kO50cX}cd%2Pcf%79lH z_Kvb?Yy=y{Mq)vlEa16ZkL-LF|LUo)Z_T*8Hv&0>XNR!i+bOCfEmhy(#jdu!d`b3< z>_oRE0O_B6(FUCi$KL`Cd_;+eSj#rgnw)Ym;CGum~qlQ^ct+wp!JT zYsAS$Ha9JereA&>zn5ZA;~~9|T&$vtTdhp1b!BJT+Fs$F0b#DFrA!p%5lJjNla&%P z(MWy4>ffDKbGBAmFQ?N>LdJgEE{~OkT(0d_gv(b`?^b4CR-bC;UB+gm@mIC;FQ>EE z21(MsX3o3ZE2Itx_l|$iCZuF8x-5Ewj9^iBA;k75jGStcEdz48D5tc^_x8$Z|Ixtr zNtf=miijN1$=+g}=m z{e%B))4l|eWJzP=GH+Md8I~nuHc;h^pV&bBS#`b>ogR^#LNC^xl~+LX7?`!CyJEFk zO1pD3`Le>d@pkV+qSru|5s+@ddXq6GOLwO9Sk2-J2onXO#)vgJ{G6r`2Z%+;93Abj z8K<6+PvlkpZgl(3lvle@FE zdqxc_D|eG7;eXrOYslS|?drqzWAAKh$CG_p4&v29FbV#h@Em{1THQ0{8L0m3$_nKzuE?USVSBbAOr1F$=#??wB{Yo<(5x z8m|KPf4xw#}$1+=vBq!8(sb}Qu?y|;QBk}>CN_!N$v(c75~rg z@Yc~TyoC(#q#pu&4PPdP6pNa|;s{$-e)twc4ZtT7=-S2|3>y&(eH;F&@Q3l*Cex(T z_7$tkaFxMP;i_Uu&;~~>vxUn_<+sQkb5lH1d@+&T5Zv~ew4nxx2klmE*-yqD^j$F? z%Ji@teztVnji3e6p^`Lbo@FwrJMK0L)=}Tp*86S7wwBdFbw z+<8B%F=a5F*#4h|tdyib4ExjJfUEp;v=E?jS0yIR1t`BzhAh6ef3M&?1mXXxn9Osd zhW+i2jE38YLjgW`_nA^v0V2YGv6m^%q}yweP4w!(Ulb&0rm+9}RPVdUacO(_^*s4? z`JvZKfA%{3srfsKEAnHuFl%F1h>J}r_Az^lKAU{QqJpb%Xl6{3X=;pqL7&;aDn?`} zaly3kRmD@`WQkbiw-#=|GVz8IWQ)f9#rj$3cjLJce&nSpE7TI%O_l50 z2_v?BmtcpVe^tZ=DHo>}h3*V*Zf=~O>Mqb_g-}|n)mm*Qsm5n{zWB)`K$~*+An#m= z>3|F8e0t^o8IV^F%d3!QyiG1*bd*qBbXZMV>Y7Cwi{+$Qx%8FHZr^+EJ-^uw2HE7_{U>jsr_iL4qrF*DA;?# z-$OgUcK0SeO?@xrGz2f<%HUY+yI}`g0t|!A-y1x4xKTBgcU2;#R)01 zuPzaV2Zx1KeWEd~SNI?CfU8X?B8u|n*f^WaMyLG-h%q5X{EI8>@9BEUv@)iX60Os4 z>-+8romPEr{>qr%408Qu_qPCs0R=z9=9xMjdS@9PEhLY^5d1%k>U8NnH7jGpEcMpB z37uYjV-sG<9)IP;O2c|_$%@`3tGdHCbq6l-(j{yYwl7(3TJqq)lK)|r6rD-Ner?`h z6PFbBE?G&yFp_?rydeUlF})K3zw|NTED+pzoaKyvH!}YD$h0^ll0^3TK9T;EfEeQv zI~&=OmO|5|zs99yiO5DSjZPI|&aWpoaJrL?v@GfSqT3pWv{=@DA2xkqTf@)ELwf>} z8=DfCJ|^32HS6X!8uG5ZO0l-%cZU}zgoMR2%*qhU62PMDH}JN<2F{^redSxo9tbuj z`BTNPWaR^NECCVlr-tuXGKOo%eW2re4C2hn{H0hY2&OZ_btQr}Fqy+Q+6ftHV8mF> zxXyW%-p+X zI+A<6HVd29Brelbo<0N*5zEGPJ1?@~Cj|bfCtZtnTOZKbmoqCu?JKd6uj1t11N0%b z#`{A}k!Inra)NF0{<>+Erq}B}imX=@lH!4A1A{D}vB~>DftNl`gs9Dr{a`5}Hw6%0 z8uKf>W-^G$)k@kUW6Cf2Id~D$o`UR|O&=p4CjSk42#mM=R1e(5I+cM#Gh-R-(7ahJ z!9e5XR={gun4SD<&`?3YsTQ>vW!t@Dg*T~p4*qxHR*a$9;62I#U%}Ka28-nMktaY( z<;g=d(S~PcipC_870SGLfqg+7z3~M+!~x7t4`J^J8=B=WUK0A+j3m|SJL$1hYZRT-9}>1-a@NCQ7b7?dhD z<-|L|7jK7aU!@a!`S3avDE%CHkuFsjo{9Hqv`=@*zko$%m{}+$UsM)P($4P^zEkKd zLX2=hv8`5;-*_Nv2JKUCoKx7}lZ9v6MlNsA<3JrU{u;;Vf(_RSXO2umJ0P=ehIaQ` z2HFry@B1sh5tmTy&%cEyt+@(4RayR22&`J1oN-tt(rXB5dFK_A7CUA2h*`SPlu2cU zEHW1`v$-TK9wu{&I9q4;o}+Wrt{Fhri0gIY0xFb6@;TjWf3(oT7YfQMAY~ICQELUvbf&5a>kDR4lZ~ z!HEvtu7L#eQYPOU6fP?CCUtdtY`o)~8rmMfA2m3JYhfLZuTDXCGTz|a#wdUl`c6U? zXnpNtmc4*1&ZhL}&im-o|HR#0HAxfbS?Y6!5{49d2KlY``+OJQ-~Y*fuflMshsWQc z7u5YqWIV^Wg+#TXi+z5Z-j7{eape2Ve<<%a>50kc7PAmQM!95Oa>;!Poyo8Gz*7>zm?IA_xj zVZ-Zdb9(xYvMg3x#pyW1`%BY?_D+$WPWqg*VdK|nUlQ5I_D*Mf{jT1Jn9PlDwFz{u z@YA(KEC-=Y&ja`E!{2N8^Zgm;|8S2&JGbGl5x+h7bK(zqjZU^k95~x^>@e|JVYt%A z$KY@>@_^pC6;=1VH5%VUc441W=sU=b_+A!Q$oOg?S1<+gW0JpC#5T_8rf(y+jMec2 z(Mi~`ft-d*3BxSztm-7%mx09SL3(Hl?f{?sh5QTKV=2k@+Ds}fT-tiOa_;8<@LTqf zci60?BEeC;Js`WEYYR(HqE3AaGE2avA;Ae|)f-Tp5;D zo`T1cjW1prw_<6>;S*Te2|p0qiX9R{i$d2C0>q@)c+)8TCCM1NlrbeCiz5;WWS;OZ z{Eh%gp-G`VkqPX*YCv&79&r@GE}cT33~@BY*d+zF19iGHjOC9o)7667-d7+y8aoSX19ebcSR;Y zqtG7^mc`dZU{gSHl|px@m-XS~a=SvmM=r6wAbvP58RsO>A3gLx$UWn!_6RaWfw{i+8ju(pD^?zaZ}< zr`%}Pga6U26XYQjuJEiv>&BatY*gsAgw(<`hHU5Hc*+L_6FD^S;WbR+qMxluqeI8u z<#I&hh4|43k|vSf;KDcY0~*7HJCbp^mR!CzENoWjA5@GIO~0d(5`Tk~yZ(ceH^{?K zzfxIzD8CKLmc}j*lb89mn2U7twh%ThCz*a=yv#=w`t*32uc&3xH_Dv;A7y&gGT%}R z7Z5n(F(q`5B0LBIKt4VC9sou++0B3zR{6$SExg)VT2H2jvD#2d->Uw~V<#YuCUz?; zKD%!*ydCtV&3FTj>*{cKM_yky?pz>u4Aq1FzFv43O6kdjf#;d!W!KIm6E8iH&Gd)w z;AYZB0)NT!b$dNFV2+;{?PtV#icTY@RC3XEY!|4%huoM; zZrETxM(16C3m(4P?}#s$wGEM25I}gz_aiH;y*{NwNADmKD=C`z@^35_okRXN%-?k`@p}koglpI7Ji<7Ln(q~Dn;-vPQYzo^3mdMBVr+a<2=;^;X<_Yk6BCCU z`+iA(Sclh_GRcpiRtOZ+ZL!+jejF{PJIDjxjsu1yOC26nR{OE*c@`R3Og~I0`-y_( zL6`Ss$dbC-tw%r`H%s-&04stoyh>IX`@ zpk%(`*Dh1oSgjp%NxRuEbX=#Wk=A6*7LH!WISP6Yxf0&Jo_q!qik;LU(6^8~Kk9k# z1kQ%}hf2h7(fbIx9{**|J5&-om7aaw#E1Mp=H3S&itFkdzB9WE3k=Glq6sva9YxWA z-CZ@JmAbnELV^m21`|`*g+)mCvo4EZAJQ&FjHWgvm`2lTpM_X!(xf#eO-y5&g#=7m z(noC?O`Ei6(^S(WB}Nnf!F<0nvkMDJn&*9=_x-+aV0Px7d+xdC{yX>HbI;tHu#A&L zjon{vm0GzYjR*@3E_Ga^Dqvo=)9_bj0~ z^h1?1XU|Nq>)Jl(->4nR5SnHQnN71=lla+Fw@3bN7IzEPOgg3dI;F)3z3@KSV{W9U9Ah{ip5ncSKa}<{^Hn)D zQ^_x`gV@0`<80R7L&KOM8csEzNA?Mkjtj`@*vQ02R$xoaj4aia>P*P6SY5@I52CP` zfe(>C`|C*d?RmH0J^7aU9Gz3cu(^gflRj&=Lc_-=&dZlfjXU3q9rS~T0o(!Hd0X~k zhI8yK$K@7M)|}h;2(*OVZ{Wzi{TSj@6JPJ}Zy%yD>nUOiBc0#NdCy?Yy@y&U7KIbp zIm5uU3;S<59B5isx-V+&?GPDjB%8r+_A!yo(-OyE>ZIZfy_jM;rK%CzIl1 zFd`yYjv3!i!HUmc(fzEPZp4x4=QJr;jN%@nNJs|Q{TsObl-Cy_kxJKx{-a%9U(Rh+P!B;{%l(j0`(BbEr<8gM9jlSsCg&QYd_L=p z{DD2in8CreO7}j#C*Uw>{!})ZOEJ~Gj{+7OayTI#pU%OG3I`UNgR-R*dYb{ru?wgt z9i3u3X>YQ4$MPOW_8CVew!Jf%F1*9f{2SkQ8`6KBACG zvB?S2WXb)17dl7CIAmplPmO}yuHBuuAHW``y)Ba&j9N2KX)e& z#OwRlzvuCPC+X7G1a=-et^XQ8{h4+1Ekb?T1iK@>(6QL*Smbehqt&s5>wJW085etu z-Vdvc=wZXitxmFA-?V90~Y@euAhg&f((zE=Ljc7_(0pv(6YZ&l{KhNcl$X+M~hpe$DtgpS9^RM6&2HA-?y;1I7;d zHC~9%DtR0&IIHGytW^g)4YYB|&v=KX?as%I+wpm+2ICaiLdRhy8K>4C*af2-S$rbO ze2z2z{n*wBX2JJNXD^s6CQw6`wr%=gKtfx-(9_SI+;bW9ioThHCi2~gyNN7 z`Z=vgZ+hc)E~Cd+T=-aE3`Ta9r>4>2afz!|=B*R!8{FAtK1hZ%R3HLlvRQL5?5&&|$6#(e?Hqv5|8XC%C>yxj9u;lBV!315_FUr|+G|3wKH z@o%X1R^?QUWge+i{IjVbMlxaynQ;HQ$|`4-cWg$DrtgcH80-IeCPw|gBz~$7`JOL| zS}CIxrLKHA!no?rT<$V+hN&spl-`so!eI$_%o}wym2GmML`DGRzzsUakn~jCVK!Ut z6c>xhCQB1GLLm3Naqjt}?&#H-w~Cuw9^luDWpy=f)V*@iDz0#B7R?Jqi^+VmXkN6~ zGH>yM`4o}6a&r*9JXLhNL+^8w%cB)OC{_`8(fFgQesjIoRU^6`9!HIcCQ|1a!!E0J zAv$MWomVu^oqtm_^H$Zk(ibB;id8&vFB<1wIL^JGNdcsehEk$deklBc&5M)WsmY2+ zQQYIg-#pIk0lHY`6szjR+J@@tF$^OK=2Q|#V7tcABoaMwlcT!9rJ}*#^6&f!-xL-f z@aKIMzBvq^!du3<=Z$mE4|AhblN-P(Ng=$ANeg9AcD19vl2YoZ_P8A7o5h0MRpBxj zPBC|7Zjrd^Rs}rb&MGV<;a%^pDybkEB^11*-s|u-)KftRV}dC5lvI&)tZne(3+LY#FcAS*s}`7+|{BzclmO>73J7gie}SjvML-@ zfftLT_3E1$s9N(v80B@fv%H~x2xX}7j{I@YRWUp+B*Ehqy>%j3r`sbst7_3AlF^#* zjUW6+^2+U~uXmLPL#q6GTuNmQ23N4dgR}ARdpEmX;RMEn2T3y`wFGZ^54qLY7^`wG zPA*65Q~y(I9QAjP0c>atcT&3?dzGV`5Fsrff||tdD34UJ+EojAP)@j>I>PvJe`kHY z`0v73x*YC*=Z~6F=TXIj3zcL%d+d&^JJ}t#;V!&WVZ7djYTPs`Ny-{L9`u1Fp1KAE zFR3c0x~#IU;Di2R(TiLW-JYsCaY?uzA&mNOY;ZNWMhPpSgZ}P16#AEhcWkJ3l~gxY zxl5`lP`%45%iJO=4MeJ_)TG5JK}zc5f3>`3kINAyzZQ$`>go~srTnGT2U7``yV6nbf>Q}#PK7wy zfJ}1NHM%^+g6J+$DuMD|R)^|e<}KNzxD8U8$ zkVu6c!hB0mo^2WL$(FogFMsuHNR#xj3De{I|_08KP(tJuOc}04U zaHb?5^=qu3yJl=3Twm>SxyACTdWW;xg&?ZiRU34&RO+Cp{ix(V*FM}eVx!}3R|ABe zm(WntX!;fEJ}~|i%c|?@U8yvZq5>%KHh3ta;PrX`3P*MQC<5p!;g!TA4BT~YSFOqx zTJ>m7sswB6igH(k%_^&_>b)glqqzFuaIPWv;;t#FsPmK{drRtSt2dX_)Rm7JrNFby zCDvDm=TV4vdXD;!=2^J^SLI(tSOTeF$^GvVI6gf{nn*mSiWJh(fPsfvgb=KY!3dRX zwKF(4g&SOkJDJ-(wm#(5ILZo}?A0`ipsGafqA)i`N+ON1Le&iQx5SPCYN$mhZVXUE z?u?A`5nRd_s^4fTH4e=1hz7X{*;AtyC7$q(W{u^pO~je2zM{n0Ks~E^Rk>WQbd$ww z4nh=dgO)MM0}Nvr6*Xa^?^Ob%(1Zlz;V=G~&BU8T1+TuY!fVUN{PW9D6&g4_NWmWc z8R4g-5`zQ`BSVY^Q7AubR?gsDp=-H@$jSGYHjSW?0cZVZ=kw3=kRbCM>*I?#0F2P~^xIJ}F)VnGdjTb`= zag-iriiikB^MzOQ6b8-I_qe~Z?<)S6=D@9anENAZP~2xV^k`*^xy4EmAB%)Pw}s=m zF2(=<%OBxOA`hmCAD1T0eA>p8<-1s^fYX>Yf{_+8Uja|^rrqC624YlanMm$AF1!fzfc{JWodZ;78938`uRIsKrk&=2>tuizA zfan;YScho>k;U|)v8tkqW(+iah7c#YU0+{UHa4}2Tq7xf{`E^lnj)vrA|0F1Hf_0? zVn(QGDlC%DBA7yu37_e!DflXX3^YcjzY2p@uJUjyl!E^Te|ObY)qW9sY;D%c%vFV= zZCO$7s+Efs$)b#HLizh;{z#;PGFtwsxGdR(%tr@b?{<~ZaMn>)iTvJxQ31*i<+%yt zmFjBI=_tEU2;IrMO8=;_;@;UW}q>s4j=7^@?>)FJ=LvyUeK+d3kNU62MjOrs68`2BR$m%Q`Hn zjS{AzJS?$*1oLMEKa^h~ys8Z~N`O0g(Txuk2C*@F0gH4B`zJ*u7RJnT^2}-DYBc+& z--!K9?ls-}w6Dczd3m^F3cG2|oZ0V9KR=jmFx?!0Bp3MolXP}$(`{pg2H0E1%}Exm z7htP<3(m&5NT<&F>;^I2Yn>;$r|-n7kz%t5J2SGGQ!UQZA`+UlLaZ=hkuA4ioug`F zN|Gf>hc7e#bV5qf9b*??6<}@~{Z6EFk}uY9?39;bYw}|kgt&o$z`%fa?FZLVHWoW_ z3es(T;0JW*yIOI#*XJ?#UNmge96R9km0pC=IJP`?yD#|t7Y6>c(fAC{hzJxRLv&kQQ| z!vmBsSmH!~6uDulZ`gqJob|%^`_h8|4zd6n^j>~2;zN8aLCegST2joum4*Q&CsX*G z2eATc{o77tbPk7HT`XCPz3Ij|bA6fkW(NBK!APUnkglQql=ClOb^7*9Q~pJSp{*1b zOKK6#nSKjQFE1{ZaJoY%Ws0o^>?ZyKE86ByP@W?`ihV$+%#JuIqm_bc`}2Rlpu!5M z`Mht1;h2(~fj{gN(@ba0r;JF6vWkfQ3G$|*YD2IFV@aTG(1b-;k`Y zd;$Cb;QfH>C}8k9@JGo?uWtZO`9xRoo09cH5dQW!I@%!oUBD@C!>@Mu4UU691X_f1 zEsTECNy+*F;H7wKe>}VtLw{DDI^DVt_cLkJ6?_438lw{YA;3cLX<=}}zlIxVYzE*V z{`V}HZhbdhg{J}@8e>)7JPJ<_gA@Leg(`k#7#*TpG;g{!5B_<8M-d=+9hk4;7YFgR zi&QsxC*i#`j7}c8m#F@gfQR_eE*^z@!{CHJ1Aauy7ea=!M7!A3gDr9-i9<4WvcYA?H*n_fe>-c2P^~^9vOub{`_SseiGoJ za`ys1Gh2nH03J&348TJ0^e{N#i&-ju4&b5kas$69SB2*T9xAV5z(Vl#VQ|8)UasO- z0v@X8yMf;x%zroFq4c@|3&ESi;0pdNDxGaXcF0X9&J~SoJ>^ zqysOObXu}j;%2zs20WB+#ahS++ys9&NQd6(`arM32LTVsrOcS=)-AZn|5_NG`4gvG z-M9&^gE4E!j}LZs&9lJg69Dq zsy_sOJ8`--1^0TuL*+>DCQ+qd33#~NzA#sXyT`#(Z&2Y)p)0g^y58b$$|F}EO9qXG}% zS69{Et*kQB3JH9|X%S9nN`$$E5^j8anJZVTvw6}`kF1-H=BUS2Q-^rTN(oB1F;Ocl zU>P0DZlm5b7TDkt6)pJ};g9DJ^ZMY30u}~{f!12W!-e<_e}>XdPi4K96bee#APwVK zTurk!s4v82NT8Yp;lbHg`6INLwQ}hQ;Sm3!i0()(zcaahG*Xmr?WPjqN*$lTO_?(? zSb>`~8zVK~->NM@_AC8I3r%4ntPuatxX0B`kBiomM$_9sL%gsVKDnXbQ5G>VB~_~? z>=g3y)G(p^3l)Ofi}|%`SEBM8))ojyUC2rM(rc6xl_Iq-45>@Vz=rs0bk~Qo$8O7C zE#~L06z@o`zmsY?>Cs5tK$dt^P#D)@x(}>i6F_*vmGTQrGOpO54tAlZ zcVpQLhG;O5Q?yytSRa64Tdfy`PRseZ%U7-{%o_1pF?RJ-;a7zAqN={qrKk`T`j`uh z@JsO#Q^Yi-w8}ANJ%K7$3H(dc<(JWh9OQY#pA>3X;u?=Yq)7)Ef)gn$J&>x%Lm3GT zUYQFv4(k zcI)y6w87=obxx((D9fM0N-^I5-&P)^m+*-?rCC)}hEr4gsa3)#fmSB54m3*e3rhR{ zJUvg<2G})t>g%geAR@*Vq!tI?p?d5tQMg~Jh-3hZnlr1Q_Vp^dU)SfVJ1bh3pS2iz z^TJzmSFc7E7d6}R#TB+?M3XL&BEU05zoW1*a<|?9NEvx)o3oB|S zyPeS%3wtW8cAz;xN0ExeRVu5vO4Q0vD19M_7)*MIpDMdT;B)yvi-;5^6n+GMS*3_E z&D|mQcz!;ge?=bXXoA_7T2?u(!G1pf@^e`1_hKK6-aP}lj?(7LR3DKXP zU)RPk5{kcSFr+Z_dH0v&Qyl*jd^P-d`tJJ1a$2cZujH_?6hWe6gE=0=Aph_(fxLx; z8BH*%Pjz)3CIvyI8u~}5+`V-TWvWV&bkasFRL?!PZzi&m{!mQ$k0^iiUp7qMR@50Sr$goE9!LNPpVDgVD(Uj0wy;p%lT zNq|Dk+Dd5+8O zvF*2BS!ez7{-^3I;uJpOOX*RkbQ)SO%ntG1D919#b2w<7Px3c*le;2D&M|Hhx> zF~qI6l7wBVA}vOoBhijf{A&4Hys9wNxhe50{Ex7#re`z>khhRe;qsg0f4Ezzfur&Z z!vPU=L!3otH&bO0v1X`9q<`PqC|vfx9U-XXAkb;qL6Pg(%`_BKUJ+^bxblE|G%?@{ z;a!-XA~13jgVSuaKl;-A2Xzb`X{rzw2y{YMw$fjY6v$VWPcXhO?f@JrV2IufKKu3Sq8rV_yvWc54@Q?|&$9>(L(xhjQ8dTW+d2pTi<_?Bt01 z4BQ;+%4IeB#KwiY`mtA@@vPwzSEUPnn+W>E~zJxd-I9 zKsO3BTp>p8aC;ra1SlCgEJfW+wo)*Nr*FFGRjk2kFUGH7HdIRZ5E6vE8i35c@e#}B zYJ40>;fNT5Dip$VPg!3MTCS-1FlPO?-1WKj-|8x-7fbLCtgu&7h>$%AzJq}sb$H5D zdL#bz)ru!+T*7s3g)V&O0^6Qh$@Q~H5ed6C7gS8H&{s^$Tpm*0l|fp4Ax?0q8(Q!3 z`brpns~WM) zb_b+sRG2LrWjs8`!|^@Aw0{Yz!a(rToze7-wl33y%f>jq(V~_4U;- zXhhc%)bAmM(2rI_?}JbD#C%8+a*f6JR@aBjp;^d2GK<HWoTnQ0!2bF3g^y?9f3_W09 zSytt)RESMmlYH1kb+#%kB{Qg+bZ=l^e@F2X-}e~Ufhf^R2nimj6|rQZPnlk<)ePw0CH6o zN`l7c*ZA}|)WS#x`YWV(T+XYJ5I$rY=?j!17%4|ZmXG=LLJ3f%em+0?1zs4h^a_zg zmi3Cb54t^@-HHOTjtqE^zhm-_aKbMKr4yNu(olPMZCxYTiO&xA59LP)M)kjGfoV}l zvN<4st1Hs#vBZERhZiLb4Y48+S{M+ip)9jO9APCQjHuHE(|OD%8z9y-pX$jKg`c!K5^)KR%rnTZ-b5>ic(YX3tN zM$zj=v~B4BkX}c9?MVB@xX_C(szF&05ve0Z-$aWcsb91j1AEG#gegcvb)yg=X-B2EY$J&*rGg>C1(EY zq1RjO%wt!!*B(h5y%7JN5o=LZ^zVeI6n3c>K~$Q zd3jjyL#-=AO`;F0sJj{M1XQ=`OL*aBN&JlWN5cVHDEHA`8t{P&K8m!=S1syQN{Ah6 z%IKD;is?lN7c=hQr;#uR+IzcQ@2~l&(}AjxnSeleZ19WK#w>V{j>& zQU7rrTabrkb+Fv4^`_-1L>7N;gc$7K$}xlvt};T1iaA-fOvo#5WgV>{G$MB~Vq2b7 z6p~@1Y>dYLe}}(d`Kx_uIRuh2k{IoT6+x$b@lE|~G;^!tjnQUIUvsNoN{%RB{2@m} zL&PtpAL^w>`|V(MGWFZ}GEW&1Xc(C$guF-UYp|cj?5 zE(R9(=G!i?CEeFrhO8N!99Zi6rfrzJ5?Ji}hV3d_)P1?-6870i=|0XW%B^ z9NYWcM}fJ%uiO5`(z-uv`M{dWy&IU}OSb);&FcO~%X`+DIEvs*%ipZixzhooPqYni z{y?eEVe4dN-H*0(S)Ht+dw!+dfv^{Y1-?)*9}YfjVEU?HAnRfxCQn z+kVcfx*uyfV69|L-G^JAw{GTM2>gfd+qPeGzX^QD_g&jd?4IryTaH+pxn}}iUxV#e ztg-vKmS?S-n5X+t%hT3+?y0~=pWAkj<#)HYJZLT8b_Q1a3T++S!-2KF+ibhon(iOA zJY+56_5{}Z?zHV?CEfqo@)PT~*zMgvYWcDC4(^e_I$yDEH@7X2VRTUy$zS=@br<-Tm&R<1Q*_bs#C%WT~(Ek3LDoQ7Go zbhaJt{7qDa;;cql7XLA+H(9Ar9+o{E{>8x`CSfD~u*){iKg>&cJwB-|-0pC^xAiN+ zyI&Yy%6zb0nJsJmBt?`ozzo0`9$fIGo=aVOQ#zCDGMysBEB~%PGkcb%{lJ)Sve5P zE^&jJNlSw8obKY|m8Y9NZZ*br7!6&<_(R4?BO6Mey>X==y$YH)Fi)S?^i$7hH zyV0*vGG*YUq+6M_e+HeA7)Z^;S+rN>3@%#YusbgHKIE`PGoJcxWd~KJMV>Te6E5}! z3@r3a4;FRhLgJ}nrM10u60``npv zrI{k$&6j1n%Qsttj{_oDX|-1Pn;OS?LM#-0)-`daHH27L>cg)j`XbM~i@j>oH9IB+ zG}u8*pEWbm`OD#gL6x$mG&2r(xeG@2?bA*O@|`u8p-d@NBdi7XV-INDYMg&m^(iU2hRFXj*#X4_I@um)5GaeaImHZ>o(ib_ik8{m9(|_Zx%b} zq>+x!Zr8TjHHG%jo{0IoZTbF-U3S)C=dwSO8P7`TgBbZ=ATcP*j^||CRk`3L`8_FX zBT7JI=`-B(DA|i<;76Kye@7Ra>NMcJHQCp`jeJ^NKB(FbbuzqnCHwH52EDj^#`opE zDXit39AinuM^aDw<{8`@jWLaZM#H!92}6tow5A!pM#`qmMBOs;e$SKg)H0&(MA1}` zk5i%E@eATbiIRYb@~Jlna$v^6$KymL#>Zx$=p;Y0`;*$wVk5#p1{ZbQ_mt+5joVw? zhcufXEPYy2)tUd1X5CXPpo!{k!-pPI9BoP(TT&j(*{JV4(0%x+!iv0g-17yGIihU2 zhS}JQPvA4Sq*ruCPJdjjgOiWSOT81Bbw?(%mQNCcWpbqXF9yE*AOgx{N#;k)=M60y#m}m&tk869%O()9DeEHYUlv|8v z<-YN6P zwY)f^VmXdI&9lOnKNcnnQvQs4&Bx^8SSBoZ!W~nZuxXknFr2V! zs-s`-3JfJIp1SdO@}a=Bgx^i=30zIMmS7KDNq8n<(UguHraLC5#J*}tiN|h{zazd@ z@Zcdv5>s0(FYoSoWhm(t?vDyDQ&M7)E{k?|ip8{GrzLau;wAQdTTD`G2FLXihUK{S z6bDwN=prl*~&l@p+OBU?CN);-KD{=L|vVqr%zj^D0`zj5O>DwE2&YMZN?TcEUyoVjXg z@MnGUmRXKNcHLGitOVZ4C24X!9lKzJ>rg1G$@?hew1-P z9tMAs7$v3#-iuGdJNB6E5uzCu07D2)@MLPZNc}dvOWJmIU6Lq-(n< z_i5PssZx(scTtYOu{=WCg>k2`EVAUila z#^TU{D>@qZ;}_-E46ok!4*x`wFhQEgcC;F4YvG(E-E%BG$&?Y;KS}sdcvV=NG`y9u zGmvx>SwcByJSXGOE}{1sR){bz<9i5$lhP{-UW<4uVaKqOR3$0al| zY`c$x;hv%+g+7uG!%3(p25hZ8`B^%*5+f3(R_Zk5S5B8kCk(bgMFO9CzyuyY= zH6HT{D)8~`^4s^utXw-ew&1jUbOFEhW@a3adw;?rQW-ACU*t0r z+0kcXjBm?Xds*L10`B;U@lU8QS$i1#j-+lph4wW0=yM4H-e%c%rl&LA#99MA-O>Fh z3tYzIvgOgU5G>q5%11PLNH`(k0fz0+14~5RZicOzcW7Qq<6Pv={dovgl^3HxoOf^u zzh}lCoO{{!Lu{7}5bO6*(3dD^)O7GEC|_ukWFaI8)Z2?K4*DNWO2l-Uq$R#P^0U+Ca=T6DvOrSjzA@{qMQz52kO)$ z(b_+k>eImIX~Zbm90TLkZKh)YQ48 zOztB}Ub-N4i|Nz356F?h7Yk`z&Vu48T=fv#($9`@?~w;G?^VI$udft5HN9*5u5v2~ z+G8}FFvj!7xcKgT@V4=otnfW0Hpus^DVpZ zm^m}V)p4^lk)8x0zcKJ_33Q5(4^3#_exwog@0??iG0IG*r{N52E%z}ocKTPc{yY6v z?lWTJi6k7lctyssS*uIy ztat`b?AQH3Q(P1dXLdUS>sZwT&mNA7;I}uy9 za(xOOqPda=PzXJvR-id8fu_D`CfHSV0YaM zr!;-(4iBE5=}XsckRODw6xp`v?b~R4yL~zdT=Yd~Pv#TX90}C?i)Xsm(Aa3*OuI7H zmZslpl?Wh}-Am{u#&De zd-RBLm=<{)T$@3bj2s4S!RpUmU8c}hCJcX)jqhAb$5B%1gk!c*_YThY9^F5GiNR=H zf;kGqjaEisFt{Ry-;|C2MNIt{F=gzh*H6h~hXu!TM>6A4l`N*djIHe&Hoi<4uMl$Y zn=>k!$cYAT=KWfuWR4Y9I402P)8)ebd*I3R&+`@SDQPkq~|r6 z4wz5jIECZa`L=$X3`LWoAg9Wq^v@HLvSZlB%W_lX+qda@ zWgJzCQ-ZlaUj=(OcJnBW_wLlL(BQ~}R%AmU5>PtCAx$`IepSr~B(W6z8izKAS3T+g zX4CRtu}Kc|0q)1$jvIXe=6rER5!1dX9991oN!k80dTv8$v~f`GorZ1xx2|QqM`YuM zYm&scO3Lx>sn?E!8BB!Jd`^cJFNLWQ>k9D9NzHZOVO)PLy?N0_ln}=3h<;-Vwo-81 zcCG6d@`Jms72AN)n&$JX4Y$U(@lzW0rZ)#?_07#MzpJ>7!>;v#*hw=H_Pe%j7=XY{R^Z5-%wcQO%sF z)W|30G_Lpea(~aO+=lAO#z$ox&gptWHg?Hv8Ww@!JgT@~?j@yAs7ffqS-?fB|7*+| zK-r{zO|-r`hgrp&L@T?ISzG-FeTG1f7CL4*9Vs5iY~JxT z?i0#yoLJU(Ba{x>;~&b#f65l)4E{KG2LHcr=L7A$BWc#lS*GbC2VENkdXIcl4+}g^ z_1B2{ivyz)Qzggsy8l4$#GNJ-?rr(xA^SUAo>su2FNsIz;~-IM-~yd)5PQZk&F;9) z*}eWA=5b8Ti6~B}oXJ6G(op7x6UH0Q7)8l{kT-sf=3kQWdb__GhgP&T%Hj#J)z4ZT ziC_=MTn6$)E55dK5=U3u#n8VvfNATS=esx&Lqz!#|1Z~^M+tG(tKRBff{+pQ9nFLzOv%C^HN zr1e63h}y_KNkNQ1zlzXLD4~@BvF-F#ZXE>=mypG5Z37Bh&|n^}45Ng#8>bMGs-kgj z$gASoB3R2?1bcA8RsBW`i(0Gf=o~A54}EI%`K9Jz**FZH9S|hRx0r@&%=gQn-tAe7 zfW!HOc{ubCM}lbCO%kTa+$qW^ocgeK=P<;4NMkpFl@|J6nzdl^o=L(&Q|aXX{R16_ z)<;?Uw!rcO8X6@okBk-nG?n|^Ylv=Pasa>UBF54^jB(uCxXv6|z!?`$jh}QJGW>|Mu&9J7UeH^$=v|jtx4C}iaW>|fd zGpvWvZjO9QwC)3r8}}O`bV0MHTa(bHno30LU@`VRz@8A9fE8iv-_d2oc@&cWl!cUa zRvf&*JATmPc;JNN`)3?G&O5%>+pps=ykJZ^aZpUPS^TGP`p5P2aLU(T3ECeo*)E;# zmwS%mwCdE!Qh#ypvpUJYn~po3W7NH-Q=!wcex+-9MV2}T)Ae(VInx&L7QH?<-eT9A zUjp>+!b5Y6t&TR`(>e+$br)y#>ZHz7b3V?CmsYVQ9a7%&lHV=my>O!Qwe|Kt9Zy|d z=&zDiX(WGxWd$o-#bG{S!4Y$-be0tnmKFNKykARsM+*JblE1RUUu*Guy8L&izOf|2 zvx1XWX**U$ENSiVZ}hB)w5*Eq_+5ggFz+{o{-&-~ksWz2b>s!?t9a)MP2mciXO-T$ zBFeHV+Mf5KJ+DVvp_NudOL^T=-pi7Ila%+0_hR&N}!m&-fq`2bG@7>b1mdm@zQ%AZ z9K_T}u+x=jxAg%c_4*}Ybt&I z{bfXciF|Bsd*Vl2F2O5)^Bw}*JEvt#yu}8tmnq~ri|uOi09hJ@;MGIYE@^01TBH!W zRrzKgRU7bXg3o&LoYYy28hpK^RNw^^ZivU;JMn`j?p>Q9p6|S)`S({o9+2a3q~Kig zH7CfalTXx%QvbB9?Yg8-S40RJseh3ZCHrGtVQ1p)1p|MNGfsli2Mq#eVIe;!as?Eb z)3{~UOulab=iqQFMgd#j21dpNyID|1j~)tC)saTA@xYRDYZQ#HnE?JCeIIJ zD~|mA9ycA4*5a({+7!37?_xV;sqaP$rA-!apZIcwQHsRD8+kPrNCh@5h~uaun68JFe)*{ z@F#l5Su7w=<*Sef?c)TlIPwpWMU~H(Xtnw1;FsU21W(!hyXP1Omx^(jKCX{oC;au@ z&ksj%4D$3Xf%}buM^fnm_X@qQEgbHCY8ayo$zKl?shV-W8o>!luDE$V%KPV4{2|GI zMaAKsB}haA!d~H?qIcte4hyR-cBU$YP^`ZssQPPsWSD!BoS3v?aM1Q`oo&}}!LDI5 zjydN@J*s5=euYfOaMC<(pYrSUc$XWld{bzUaJW`YjP%8G?1g~ctwOFY@XJaE~5B!9*E7q&-u8g z^R>MA-*yLOCnAIFm_X@!J@=(MbiAlbPx(y~$y*$Ls=kr$yz&PWoQD>e2!ZQ)9ioDi<|yeQ|& zC~2iu%F~}%1<4sLt&CPAXN)2_1C5+&;_~zFUcPl*9L-KW4t~T6(V8{c^zt z+2Ogo@q!$AMmP10&=~hu8+P= zAG<*x-?;5xA$VfY|EAzG@Y3+o%u>-RknZJ99PNu)p%A~0H1C1Y(HWZer?RpfstoQh zwbC?j z&uNJ;_`_a`Yc29U6Unc0s+2lV@KZV6QK+jnWwiUT7o2Zj;yW0<4z3AEJ^vK>r;U5$ zgYB*DyNzN>+^(;4_e9N^g}vGmCDCZipL?&gnx$_%cFeo*MLzqKeD=XhEvGmnlakNv zkcBmRCaguug-GHkp4&o`w-XB2=c}oZ&Qw$J*uiAIHK$>@hL}V#<`*ZgT_8W@BlND+ zlj(jWfH4m(Ia` z@Tp|$zVC}PpXMD}Rmoy2ld<@Z1C|}oY+aI_4>P`Q2mB9XoqYJ?rSf;N7Y}$) z!o6lNUX{DCzB&m0CFuvExZu;)IrN_Di*zQ6DPG}Ts6>Q8i~nwubX=TiWRgJ?&FC(0 zXz*6ZduXjGqn=}mV$XI?F06izHa~>AM=Byy1mhXPKpPXqUO3UZ^18xoz!|PHFp@#(WIMCyF+ADt8j=SUvmd1QMH28nYRAnt@Pqa zTmL4`jy^{*ag(tsvYuxg>i-Vw%(%#z;?mT6q0mWsG$7#wzDo#u%J@XQK55TEd#60> zppIDrNQr0)ESxWh7}1OE*qv~?ZFbVg3S82?*@GnZZ2r&o#5Zq3EQK?+mad`pRam|i zr|v1*&>35U?V3Q$hdegRv>qqKKYK5yXx$G2CQK?AmPPwPOsec!gTPy-E2>XMYie%n zxkY(nz@oCg9miSIA=>6En6G}wRelD>v7m*SxW%vOHEPm1X<3}mm36%)s3QulnPU>J zZ{N!!>_27mKN0p4w=OJfRGjVx%mAXZ5;dWk0o@!{t=hPesv^r8q?U2WmAGe&MysGZ ztF_@zX+?$*C* z>*^Ww`)Bz24efh$?XI1H$HnDcoKRo-wCH<*3!1%@KA$~{bsqZ6{9QT!PO{(jEn{CAGS=qdUg z|C)esd;aaV{Gz}*^KJ9F17^Sf8SCR@qSIA#u~?tK-}ae{>tA-<`x%wbGFdGj9UKKO zUQxA*2hTeql*g)^8_J2f@7Zb(E@)!kBUb& zNyw}hqPDdk&?6pzU=}v1uRuvJ>=KFZGOg>I0 z#Q&P{Yf+_}I=8iNJtw2B56tEk8LC3-$vUj)4SkBh`U0G%dvaKm4w@wY343I^!D820 z_=q06e&G`B$)~li$M)DGXfc*A6u2~!qonF4O{AsgQ-~1T%fnFyUd!&}P5JlcGw-uL zgYmb+=HCt5yS~AtQxp(imRC%S9W*h&lNl-!G72+U6j#v^pT;t@7ENmJ(^w5Fcnarv z=l-ygy&Ylv^|1K`guj(b35HK&!Yq%~&oLP$K67pvDMoYz={7`q_s(DctQ6k?ya$fWtY$(-HD z>@%YH8EnrPw$>IoxT|sCp@RPy7ADR9A=XL{K)Y}8zoF}t`~D`MEZuQ*U^{~K#&HQ) z?AthO@pDo|6ii;S_N$0(Kasb-C1Y-e?g`-DeKJ}b*&DR|oX5H~rQZ<6y{_rqEhku_ z+jh&yhU#H+HB!2dd+VZ_^^QA+_4}m=hMvJSY<9u#XWWUPpQX>F7QBTw%$#m8t{*nv z34{aOZ-WT>b|EsI+4u3Lt+wUcbVut~@A@R)V~_IKqkH_{E#xB$?GZiJDE)qYdlM^; zdv3$b{Q2|Wn=U3Uv;1A9>$d zy~Q2@%3Gm|R$dUr*0V_CKoob`7To<;Lu(&Hy7UK9_9V_*^nji}VV`)iR5&^il_m(9 ztTSvYN7GE9_cRV#kK#pkvUI}Hff!_R7OcQ}#I=@dbddI0^CcVgf~dsi>w;Au_4!U^ zL+VWQi6f?FtOjS4qL)n52yq$O;!QaniEGwv;xi|<{duI@RQgc^a!}9DEHfBmhRp)< zaFE*^%tH*{oMM#6&o=WOyP-IuGU2&~>G{(9()sgm!Y;_(w#zVw%Xui3&(R8HR{MPJ zF6tor1ZMtlsI<7qqlxX%2#pJ3gc-t=3TB<3vhhWn z_Z^jW4o+cAXdE+-Jblf;J%c03_3cr7mX`@nhodlIexd&%%(~8Pq$8Oxx4h*LCLVtb z=)7P^)1VQ3a7eg83S3!xK1%=O`8-3;lPSX58Q1Ty6z@%FOEW$`WPW_e{^%NRTCfmi zij!x?8I1de%=-ZEA>ArXLyX#u_S61|t{o zG_w8xStw``y^vLy7oYxQZ=WpOAh7Ib<+nXRn3#23b_y{&5|BD%-OoIE@mK-Lm;fOF zW^WKq3D=>JTJvBoqv6FUNrW=sInQ*|cou4Z-7Lo(-u~{VK4R;8GOH}=5DdaJLFb8$ zZ7;sJ@#dIxGnkpt_N?6Z7x_@EzRx0yPlnU= z5?v|*U7vggH7t_hq9kDTwh&2}q889(s)`d*P0@|jt`l>55n*@!>uWgHW} z^>=bpdz#P``5|*}*0~q#Y+EX){3L}x=@gEhL1|_omnLNQAn$aq0bMz!8?gm252Lw; zvZg*nxsG{;v6A!wytLP(Ot*OFUTz+-nksR<^yEGv#EpADOTl62w)K}qcKjBG5Ki&q zps91|#|7`xK+G~@Z~i=*A6d%xntQIPeTyA^%VY}y#g7X%fA(-0EZGuF+MMw(aejJ>Cmwqf%ZR0!ahJ?zYwgYm+1z43{)B6*A z*YxccUYiq_!mOFe%XdD%f`M?~S(>|%S;I&lLUT`JDkZi@ItaV@K;Tz+=P~qQ#5C_b z_{1LJhGrQfuw$aP?L(P;&B`Wp4#GmEKQ3^rH1JN`u_5cRW2Glvzwyl%hsJd!n5Rxa z)m=>y`1+=byLY$Y$-qBz|W{&oIHp>ShFBs(_X9hfWjrt|pC(y-=1itg*3 z3|f%SM;ANPwum1eV{q>GY^%Xod(B*X&Ax9j_vcTLgJiwxr2H?H{OSDL8e_#Za|OJY zaBl>?l~OSnORt$r0ngxmAA}e0?3fe--RPq%f32;tZEEYJXiwiU&(z2tZM*MhQMy^7 zZcmsDmLp&-g!%C)WhOtvSKMK?UMqH`Ps+~>SYEzbI?u5DX$`Fns>WwBYF|+DzlCwz zI~wq1y@nw6ee1Yi1mowve$B&2Nh~%aa@KRvi3=@xQRpM#KD@VcP@eU4oFqgP3i?Fn zZHHoFHBA>EBxie{M+J6OXmkF44CVzi%;2W5ik&%Jadx4c-=Mg_2BF-?!F*r zZQtiO{k65NoHH%TIg|6S*wV_P#%H5ojruQ{vx+IQ2dxXuBAD?nlWf{*xUE`n`H~ba3KxgF^ZWNy7qea;~*#|wf#WO{ur{s zFmsB*c=4+F;#K>;?{j5AhDekM+32;hAg=yFV|-LTj+fYL#>#e#iz5VW<9Q<{(nrb? zPDDbYx5e`K6($K<3&g2L7m2glQP*K@!6hcQH39eVo_Yqx|BUFprDBt|wR6h`RR zaqh-8Ok8?z;!=dlj@?{qgnrkw2;C`GDO5h3CV2M5>`rJ+(6#Ss!*cTdjX=%HW{BgT zB*Qgrn{W=j1#DQLi_M08W2%UOLRN!pNo6VZ={vJ#f-L!)$p0^pRD)Ds3i)UnEWBkr z{@7LY|FJ@vF7j8=iOEop!y$^^$U||w5Me>3ur54^u8t~2p%7V^7qR=v-H)_lN0Z}#3)yaM5 zW#R=xnEI<`FBtiZJAGbl=z<;VYHF-jnDjd# zUG&T<`TtQGCur<^q}?82u}Ag3ONkV;S=}Rq&EL2xEn~1JeL|jX_p9kaO(ysE1MSjg-TzJ*I5MCMFPlH}FlhS4`nUfTMRN~(|VzKxG z3zJe|Sqg*uV?)N9u9{PUozFcI#723h#kPGEp65cjIq@nJY08U92wK8AdFyAgRpn2$ z6K{KYIDyw?y-d7Ky=tBcl4abM5eDYXTw+R!J1T;K`I5i;sH7t{o=8#6`Hv16qpzBy z5oR;jILb!vIWQ5-Zb4IU@rqC`=~!VeO~UdOR@(AqSeb)kSYm0|g!9x_6F=O)u9#jv z2*Vpxf<2`(O_OI@=NLb}V*dDweg6!uB*d0=%533-F5^G1nEwfnRIWJakuHey0txle z#&@rn--XXCt}y7++R2>pF@^Eb8~-MkuJJjgDBFKsvCL%l$&scA+im-##=qU@%NI@7 zB0mmv!RaohB5Sq{AD{U%4K%Hb0M^mc9?`aKqLcyjv-anDay#KhrYTes{HB7_7s z)ymd(D$5-ZToyrRpJ70Ig2ot@DX$uIFL0sC3qgXcQl~ht^I6XfLo{jybQW4Z&+w|D z?eGYu(q}G$bzT%crN~NV>3j5=U8Rvn2em29SuZicu4_Ucw+AOA(2zPgYv1sW*5G^Z zgi$R4$_Npnv(K7=j$ha24Rwr++5Ov+wkG`@-}+m4*6QEkn-}MHPxc%gah^O9a!#AR@8FAd@AfD}HfiW7Ql@5sU=OD5A*!VoWB{cZy3!@wn!r`$#&iIL^b z;rpl9GCwe_Rc*nsxp84&pFHt!!RI&GH76( z87_hX&J3VPnlr;)L17R?w}KfMV2Yc=AW&8aidNJjm1)r~(nVL@&D6}wb;$&^#a(r~ zXj{8x=A|&v%)Bzc&vVWUqP3Ub_xpPNe*b(%59hg^=kh+!qR(nZsY42k zAq#@k-pR(|1?u7g=4I*czy5#Qnc)59!;eBU%@)na~VX{s%A)@4q=Q=wI zIts+)%`1LX*h=Km{wemoV;db$HmAaz4%=p@wdRUOVW^#4Zob>F$^CppNvFTuv!HoF zNq@X$?^v6ovDqz)q<5ItInzbusnFrRyiBnrSurcMpkzUFf4qGU*XW2Wfj0z8UEL8$ zrsG{pUvREW-_oIYX{D|}v0%Sl%4HmVsNSAV?dUlE5*Ww-6?{AZxOp*9ZCrP1uhU(L zO#KB&E{J5>WlnYvmyiVcIAr#M=137+JlmCU!{bif9xgo@gqzSTTXUpXSCU0D3HWtP zdqDNUVyBlvnz`kO;&WJB9onf0*C=*qykL%@NDiZZP~qxe;8NYi_Ffz^MTt0;`#jGg zR>|f4t0UfS)A8Fh+IC2xkvOV#tx5M{_FLsd**R3+X0rm*-m#5!&?2)H(q4;GslGWw z9>G9c{QXeQd}l$*=XtF^(0U1S=m8a-2&F65VdmMFFms*qd!+i~=M=JNlGT+yM$L{H zxJg*OUbD)xSVmuDwn-cj9uO>-N1A&$NAE>v{t2(3{?e!m20ajtFn^nzKIRzgE!300 zuJi8i+3VMHQgi%J(eV-D_Ucy{5Xr^oo%!9OB^RlnJZc>Wa{2dueXs!icF}zGIS+6P zYy0~z3NrQib>w@^@qRxEEb|X_CNNUHEcQs!7#J*NxLevSGZcxMi%AiDwz_j?qI?{@ ziKSzlUMgw&al3+;x@55WV@yH-5$QFM(68xY$}J^|hl;u-5lgNpCwj`gH!k&8`H+P)*u(@ zi@?WW+fT;~^AWcPNrC-w( zeN$6W^Zt8QuVlBZQM~k$#VeGI)u*lYwRnZuy~3xi7IXDI%Ae%q<#j!4HSNT&bDc7_Ew##~6E0Q-sFC3CUx5NJm zT8Tr;Y2c^!Pi`VTP>y;ywnvpM-bNS)xY&{nsj;L)Kx!aOBT@rBY52Zco+kSNzw96N z+1Wjo-Y`>dcv1c~xgr^@l`!Bbm*oc!g%!p7ro_# zI#qXsQGPE!yHxk#SUGe`Q+1ZKgTBh$vVtXNo;|zNtF3?e(axhjhYpKcy$BEju00Fa4J!@J}!G+nD{HYG}l0blaq`6TiiYN8FaRP!(QnU?ON3t|k)JFw05n-(X$F{YtB#!+J*cJswZZRzGo%pU5~x{#rjjNHpEB^|SfH`Lrv zjBCw0Ity+p?PV@gl&~>rWFybl<&1JjTEr6X%RN%YgZfLWh+9i){|bxeXra=2sSbKD z-a|7))1ZpkVpPn6x_Ux};s(cb^9d0TML@xx2;Z#jY%gz*kgT{kTCEf(FdyxK_0*j; zQ+G{}Hs$Mwn2%{hVEd42zm^|vRh18EZ9|4rPUhr!uz{9@`7?F0pXvJ%n8Feq8otm_ zL(>agKk}korY2IcFOhbpiizh%zxoqCV2}c9VLCxRho77^MtLoQ-X+JhTbPY6|vFAEOJF>C=`kgaPVHVhOySm7V()>H@Jax=hFp)94+|UQx-Hw|WLAL(^mI zDvB1t+U>3$pTX>X{2aJOy+zGZNe50(;MHJHx)0GL6Yl z@C;e;HD{zD0lGfDVj?vpDCDnA4B64f1dH}-XJs!`^Yc$I+w5u|=`#%M`Pxj_Eovh6 zVsNnuEWLaIufzF*5vQ@avzC`pm?iBqq+WH4OGHf<>o?`VdN z+e%2WCcYUyP^kN4N3&$f-g{&9uyft@{YZ_aXR6L48um(ghtu#olKk|Sw85M39-SUM#O`m`#;VpCP zJPE8vFsaAFh<%E8Mt4R>#tEZQX*34X{+dMzt{kv8eh}V^CQ_y6^E(|U`_coX;~R8w zidtUJlEsA86SB&)XuMi}zfRr=i{g6-VdeF(of(#_Xh=IWrme8jNX`bg!(=!Yp`E}f zbaIcTSVoheoyv(>Ih|W&bP7Sc{$cg4$E#~K8l9I zN<4SKK!+G6L|~rB&u36@JBh%cAz0ErzJoPN_~Jv$ju)fs_GHy#m3q(gT9d~p&*v-3 zPXv|PPLu{b&|qrrdSb%q4A#R-?%7nt6qRdNDDUlH32P)xUQEY=qT!2zY*Dw6pAr7d&D4fm!p8q!0>MP^k~DOJvp*jbOC zha9Jm+op+A>5Oz`4%CY9r(`LtkB6&gN0>ge8P>o_IdUBGfcY^xr_08AN8_B^qKQc*5au)v-v$lbZJp`& zmz9WLEM{Awc9qyQi$uf|n%7mHR$o?9yI;W?rLI&kz4Wu~-jB%n@g4fN%ZR-aq{yRaX3Dj|$B9{7LeKbLl~+r&QJv z70C2E+s5^M;)GbIehi~0o)Xyku?*JYY@q80yYdbDu9d(!Z;}Pfn$at3+n7qVft`1vEjyiXA3n8a|0+v6j_go&f>^tNP77agp z5UdB)doB!HOAa`LUvpdc^@8;&^`6ti)~O#j zTb=S@uO)AS^=0**pKd+7k-qcawlXApKa@eQ8BiC&Uf`=aUW&5@y0+mf<_D-3kHj=3 z9D&aA8fQW$+f}SAR;CZ+Ty&;sV2dv+$tTCYxX?cI)p=*c=5*h7wIV1v!y*WN4zq{{eQdv zH7>bF?teONGGqi9nHoRJ(gkM>Q==)tAj*k}Tw?F40zv-tJ6>E%&!m;7cQSHi5$BNK ztyKGLU^=3d>!;CEL415AX)qZ-mL4ftoFt&*(B(mq()ZjmsaJEB~k%;6o# z>!DQ|quZyB@=y4px5){m)kwTO zPs(yuI}60w*<sEP|B)U>`mw=@n zWTin6msnbqjXgv8j)7>Ogk8OhojK#ahm6n%8wz2txVOcbx{1!;QbH`)w_g+v+rQvVq1dn?$z!Ln_`hc|Hm){8}F!_5M{bkzq;FWH) zcwur{NFbf~kq0#Ud)xhGmhMGQ)z^o^)_pquB@fu@@7?V$>v;9ddmGnB4x7SgBzU6h z-t`bXKWy6J@7?S#v%gjZvrrR;O?Cd>Tm5C-uicgS{yP(0rcj=uT83ukIN?PZ14wrO z13B54M=Sv#@$LwhmWSBFB10sjNU3tv%6J&{SQD}q3>qU~j7*)!bmx)syqziUhDD~> z;v@6mlij6viHyBtGr}W77RCHn9tP+vWz8J{OmhHH&HC}Bm8T-Ow*oJMv2M~vPMG|B zm@eqJ2)uXd(0rHNo|To#!GuF=dAfl@j2026?85Svi;3)`i1Xu zkP1h^9ukHQ#Qw!;SHYr?#_$EoBPL0DXomk;b^4eLqxN3fV~OyErLHr4K@|z#9gp^5 z@0TwhgdDJZ#}GYO;fz@dod-HJMSA*O>r43^$#9Yg^r)geq}&W2_}un6*t?tsn~-VF z?*&OlSl|KcUSQ8(7HufK80}_ffjYq>V&8&&tcOT0UJ$M)J#3O_hD7|FyW>X3zm~!H zm(vLw!4J~#4qY@$bY|%Zvp7TX)yvKWi_Z9Zsm{b4Gn~2mfcEI!2iZe^7awE97hzWs zjFk;KwS%xa^buzB0F-a&;T*YJqCE%gqJ)iMIW7(sAj2drM>w{MT^@Ur>*nAzgj3Fe z?Q49ub`7>iiT7O|_mi;%B;Xc1xW#4~AS*B>_LV{K{7lp{Bu%j9_ z)cSXD_sGWvt?ekf=Pd^eeD3r%lCC2`%+?^{o&5RxrzVNydEb;v)oea2 zNl|m*&$aeC54AhOkG*lf$JB9b_*n~ZIOWWF!D$TRVD{O#moZwoln0&6DrdLK3ox;g zcb)Xs_oY*LVxav&v2yu9!y>s-&envtw7%(V=7K2EpwzFO9o%?1OIeO@J?`Af1=Dl{ zr+(=?x(JqEu!mw=l;eNUaq6I0U6H!=05o{%*Fer(^h3^mIumaUTV2HOVW111t*h0= zPw+A-WV}c^@9{CkDpi>ONZqQ#pM$@q@DBKE4}Y%S-!s}%Fjz=DHPCdM0!Tpq|j*5XuET?|`sf5v0w(2i8vx+Y{nJHh{e7bb>%G ziHS z=X$vNr@)GOJ(2rOt?-i@C$xE|EF~w_k>dk?5|K;MR&#M3`KgT++llg7nleV=)cRe5 zPOUCvh4M%sm>7I6T?}0gikyb4rm#PO!Wi1Be1a>VtjrGqUBjqDFg*BpKxtr61h-3f zjs>%o>>(JIdp4l|%$XR_uJJvz*023H0m`dG;%5mQQr68a2-?_PwBYnTqKKIM?i+9I zaqjb$MX0!_I5@yYoIEu31}h0A@aTnKUA=P8iYEdG2Y-}^iOR#N^>7+ro6qe2PAIe& zyPi0qVvi5R?RZwq{^fGM-&pPI1FAQjn(2OUF2FSA3%hpRz*M<^w6FO7n>ibuhF1o% z`~CEpei?9n0vso%%pT{>DNl^k!O3SWcNyWdvybmG^<2;Yag=z<(4yZuYaZ_^-zNnT z-L{YRJ)Ru^oJs=cOhB2A+tI|9wx>mt<@q;1Tf&M@-%MK~rU&qxzWHK>O#7!Hb%-@c ztuD6qOcg7WPUgHfWDF|}N;XV=|WR2$3m$MbW;!Z#ZFNRJ3op;&^orOv;Oka$A;fb}oH>$R4pEsNP<_;P|h5 zl+x2@mZpB|RBag2Zh+|gg(Z@^t1v%sB@wL{vq zV6u(LbD0Ru!<9v}fq?o*wQ5Ma3LNA!S?)*LhP2Os$zmqmWiqI7K!gi!N`6BH)(F)M zUyiF2hYU$xqI$3zJCypOUNA=7Umq$yp2KDXFSFGUb55ofS zr|N-JN7>-gW0yf;nQ)=0l$O<;P-nKOD?w~2y8z2P`N^`1WjXf^a><7mCg=Q>y48hV zaIZAFKr4(zA6>3krj4gg66xaf=8$)4gp(smE>N#ScDj}-mC&Zz6!I?pTS5!4F62G> zw}c-~qGJI<=NHcGfc(uxb-}2>enk*rEo0p^gDRLd0&4XZj@wSdHWYoQ4djhNw!k(o zYFE64uf>RdiIl5}%Na#&En%CRO8s0LrL3DP_Cj12X)Z3L(Y1u0b;s{4NcLc&3q707 zpI@mfISYPO?9CZEFQot8@7>lkD8U+7U!2LU5OMY~uv2X54JY(qVKn!tdgEtuIbEG& z|4eQS4PSDVD+vwmJzfgSU3%bT^MZNk!lHohm;MOHsKN7V*rK(5dVVk4 zT3Q1YurR*Zl}Ei^K=nIWIB%oteX4(#>esOC?b{(gfUi)LTA&g#kAan!6!emMl+y0#u+~31u{Q!q@?+ySY0-? zIjbr44=>l4dd4mYhs9T={(cSm^z3|3$ua%e>^<2G48?uad@S;;ra7Bz^<%pI2=lj# z?`?czVwCpFbBBL>9^$5s-UvRqw)<3W{OW!BqV_~@g4JQi`)OkKRBobkB4@NrG2d